summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIain Merrick <husky@google.com>2010-10-19 14:37:37 +0100
committerIain Merrick <husky@google.com>2010-10-19 14:37:37 +0100
commit3345a6884c488ff3a535c2c9acdd33d74b37e311 (patch)
tree7784b988ef1698cb6967ea1bdf07616237716c6c
parentefc8475837ec58186051f23bb03542620424f6ce (diff)
downloadexternal_chromium-3345a6884c488ff3a535c2c9acdd33d74b37e311.zip
external_chromium-3345a6884c488ff3a535c2c9acdd33d74b37e311.tar.gz
external_chromium-3345a6884c488ff3a535c2c9acdd33d74b37e311.tar.bz2
Merge Chromium at 7.0.540.0 : Initial merge by git
Not including third_party/icu as it contains huge data files that break Gerrit, and aren't actually used. Change-Id: I428a386e70f3b58cacd28677b8cfda282e891e15
-rw-r--r--AUTHORS5
-rw-r--r--app/sql/DEPS2
-rw-r--r--app/sql/connection.cc107
-rw-r--r--app/sql/connection.h13
-rw-r--r--app/sql/connection_unittest.cc6
-rw-r--r--app/sql/diagnostic_error_delegate.h9
-rw-r--r--app/sql/init_status.h1
-rw-r--r--app/sql/meta_table.h1
-rw-r--r--app/sql/statement.cc4
-rw-r--r--app/sql/statement.h1
-rw-r--r--app/sql/statement_unittest.cc2
-rw-r--r--app/sql/transaction.cc6
-rw-r--r--app/sql/transaction.h1
-rw-r--r--app/sql/transaction_unittest.cc2
-rw-r--r--base/DEPS3
-rw-r--r--base/allocator/allocator.gyp11
-rw-r--r--base/allocator/allocator.target.mk7
-rw-r--r--base/allocator/allocator_unittests.target.mk7
-rw-r--r--base/at_exit.h1
-rw-r--r--base/atomic_ref_count.h1
-rw-r--r--base/atomic_sequence_num.h1
-rw-r--r--base/atomicops.h1
-rw-r--r--base/atomicops_internals_arm_gcc.h1
-rw-r--r--base/atomicops_internals_x86_gcc.h1
-rw-r--r--base/atomicops_internals_x86_macosx.h1
-rw-r--r--base/atomicops_internals_x86_msvc.h1
-rw-r--r--base/auto_reset.h1
-rw-r--r--base/base.Makefile2
-rw-r--r--base/base.gyp39
-rw-r--r--base/base.gypi52
-rw-r--r--base/base.target.mk28
-rw-r--r--base/base64.h1
-rw-r--r--base/base_drag_source.h1
-rw-r--r--base/base_drop_target.h1
-rw-r--r--base/base_i18n.target.mk10
-rw-r--r--base/base_paths.h1
-rw-r--r--base/base_paths_mac.h1
-rw-r--r--base/base_paths_mac.mm63
-rw-r--r--base/base_paths_posix.cc10
-rw-r--r--base/base_paths_win.h1
-rw-r--r--base/base_switches.cc36
-rw-r--r--base/base_switches.h11
-rw-r--r--base/base_unittests.target.mk24
-rw-r--r--base/basictypes.h1
-rw-r--r--base/bits.h1
-rw-r--r--base/callback.h1
-rw-r--r--base/cancellation_flag.h1
-rw-r--r--base/chrome_application_mac.h1
-rw-r--r--base/cocoa_protocols_mac.h1
-rw-r--r--base/command_line.cc232
-rw-r--r--base/command_line.h124
-rw-r--r--base/command_line_unittest.cc54
-rw-r--r--base/compat_execinfo.h1
-rw-r--r--base/compiler_specific.h1
-rw-r--r--base/condition_variable.h1
-rw-r--r--base/condition_variable_unittest.cc112
-rw-r--r--base/cpu.h1
-rw-r--r--base/crypto/capi_util.h5
-rw-r--r--base/crypto/cssm_init.h4
-rw-r--r--base/crypto/encryptor.h1
-rw-r--r--base/crypto/encryptor_unittest.cc3
-rw-r--r--base/crypto/rsa_private_key.h51
-rw-r--r--base/crypto/rsa_private_key_mac.cc20
-rw-r--r--base/crypto/rsa_private_key_nss.cc114
-rw-r--r--base/crypto/rsa_private_key_win.cc20
-rw-r--r--base/crypto/scoped_capi_types.h1
-rw-r--r--base/crypto/scoped_nss_types.h1
-rw-r--r--base/crypto/signature_creator.h1
-rw-r--r--base/crypto/signature_verifier.h1
-rw-r--r--base/crypto/symmetric_key.h4
-rw-r--r--base/crypto/symmetric_key_mac.cc7
-rw-r--r--base/crypto/symmetric_key_unittest.cc9
-rw-r--r--base/crypto/symmetric_key_win.cc25
-rw-r--r--base/data/valgrind/base_unittests.gtest-drmemory_win32.txt4
-rw-r--r--base/data/valgrind/base_unittests.gtest-tsan_win32.txt3
-rw-r--r--base/data/valgrind/base_unittests.gtest.txt5
-rw-r--r--base/data/valgrind/base_unittests.gtest_mac.txt3
-rw-r--r--base/data_pack.cc1
-rw-r--r--base/data_pack.h3
-rw-r--r--base/debug_on_start.h1
-rw-r--r--base/debug_util.h4
-rw-r--r--base/debug_util_posix.cc36
-rw-r--r--base/dir_reader_fallback.h1
-rw-r--r--base/dir_reader_linux.h1
-rw-r--r--base/dir_reader_posix.h1
-rw-r--r--base/eintr_wrapper.h1
-rw-r--r--base/env_var.h44
-rw-r--r--base/env_var_unittest.cc38
-rw-r--r--base/environment.cc (renamed from base/env_var.cc)52
-rw-r--r--base/environment.h48
-rw-r--r--base/environment_unittest.cc85
-rw-r--r--base/event_recorder.h3
-rw-r--r--base/event_synthesis_gtk.cc90
-rw-r--r--base/event_synthesis_gtk.h36
-rw-r--r--base/event_trace_consumer_win.h1
-rw-r--r--base/event_trace_controller_win.h1
-rw-r--r--base/event_trace_provider_win.h1
-rw-r--r--base/field_trial.cc12
-rw-r--r--base/field_trial.h7
-rw-r--r--base/field_trial_unittest.cc53
-rw-r--r--base/file_descriptor_posix.h1
-rw-r--r--base/file_descriptor_shuffle.h1
-rw-r--r--base/file_path.cc164
-rw-r--r--base/file_path.h1
-rw-r--r--base/file_path_unittest.cc53
-rw-r--r--base/file_util.cc42
-rw-r--r--base/file_util.h94
-rw-r--r--base/file_util_deprecated.h8
-rw-r--r--base/file_util_mac.mm4
-rw-r--r--base/file_util_posix.cc23
-rw-r--r--base/file_util_proxy.cc799
-rw-r--r--base/file_util_proxy.h187
-rw-r--r--base/file_util_unittest.cc307
-rw-r--r--base/file_util_win.cc304
-rw-r--r--base/file_version_info.h1
-rw-r--r--base/file_version_info_mac.h5
-rw-r--r--base/file_version_info_mac.mm4
-rw-r--r--base/file_version_info_win.h5
-rw-r--r--base/fix_wp64.h1
-rw-r--r--base/float_util.h1
-rw-r--r--base/format_macros.h3
-rw-r--r--base/foundation_utils_mac.h1
-rw-r--r--base/global_descriptors_posix.h1
-rw-r--r--base/gtest_prod_util.h1
-rw-r--r--base/gtk_util.h1
-rw-r--r--base/hash_tables.h1
-rw-r--r--base/histogram.cc97
-rw-r--r--base/histogram.h41
-rw-r--r--base/histogram_unittest.cc1
-rw-r--r--base/hmac.h1
-rw-r--r--base/i18n/file_util_icu.h12
-rw-r--r--base/i18n/icu_encoding_detection.h1
-rw-r--r--base/i18n/icu_string_conversions.h1
-rw-r--r--base/i18n/icu_util.cc6
-rw-r--r--base/i18n/icu_util.h1
-rw-r--r--base/i18n/number_formatting.h5
-rw-r--r--base/i18n/rtl.cc10
-rw-r--r--base/i18n/rtl.h8
-rw-r--r--base/i18n/rtl_unittest.cc9
-rw-r--r--base/i18n/time_formatting.h1
-rw-r--r--base/i18n/word_iterator.h7
-rw-r--r--base/iat_patch.h1
-rw-r--r--base/id_map.h1
-rw-r--r--base/image_util.h1
-rw-r--r--base/json/json_reader.cc35
-rw-r--r--base/json/json_reader.h1
-rw-r--r--base/json/json_reader_unittest.cc44
-rw-r--r--base/json/json_writer.cc9
-rw-r--r--base/json/json_writer.h7
-rw-r--r--base/json/json_writer_unittest.cc18
-rw-r--r--base/json/string_escape.h1
-rw-r--r--base/keyboard_code_conversion_gtk.cc620
-rw-r--r--base/keyboard_code_conversion_gtk.h49
-rw-r--r--base/keyboard_codes.h16
-rw-r--r--base/keyboard_codes_posix.h209
-rw-r--r--base/keyboard_codes_win.h185
-rw-r--r--base/lazy_instance.cc11
-rw-r--r--base/lazy_instance.h5
-rw-r--r--base/leak_annotations.h1
-rw-r--r--base/leak_tracker.h1
-rw-r--r--base/linked_list.h10
-rw-r--r--base/linked_ptr.h1
-rw-r--r--base/linked_ptr_unittest.cc17
-rw-r--r--base/linux_util.cc22
-rw-r--r--base/linux_util.h12
-rw-r--r--base/lock.h5
-rw-r--r--base/lock_impl.h1
-rw-r--r--base/lock_impl_win.cc2
-rw-r--r--base/lock_unittest.cc213
-rw-r--r--base/logging.cc309
-rw-r--r--base/logging.h100
-rw-r--r--base/logging_win.cc1
-rw-r--r--base/logging_win.h1
-rw-r--r--base/mac_util.h29
-rw-r--r--base/mac_util.mm192
-rw-r--r--base/mac_util_unittest.mm17
-rw-r--r--base/mach_ipc_mac.h40
-rw-r--r--base/mach_ipc_mac.mm13
-rw-r--r--base/md5.h1
-rw-r--r--base/memory_debug.h1
-rw-r--r--base/message_loop.cc19
-rw-r--r--base/message_loop.h5
-rw-r--r--base/message_loop_proxy.cc19
-rw-r--r--base/message_loop_proxy.h8
-rw-r--r--base/message_loop_proxy_impl.h1
-rw-r--r--base/message_loop_unittest.cc16
-rw-r--r--base/message_pump.cc15
-rw-r--r--base/message_pump.h4
-rw-r--r--base/message_pump_default.h1
-rw-r--r--base/message_pump_glib.cc16
-rw-r--r--base/message_pump_glib.h17
-rw-r--r--base/message_pump_glib_unittest.cc3
-rw-r--r--base/message_pump_libevent.h1
-rw-r--r--base/message_pump_mac.h1
-rw-r--r--base/message_pump_win.cc1
-rw-r--r--base/message_pump_win.h1
-rw-r--r--base/mime_util.h1
-rw-r--r--base/mime_util_xdg.cc5
-rw-r--r--base/move.h1
-rw-r--r--base/multiprocess_test.h120
-rw-r--r--base/native_library.h1
-rw-r--r--base/native_library_linux.cc4
-rw-r--r--base/native_library_mac.mm3
-rw-r--r--base/native_library_win.cc2
-rw-r--r--base/no_windows2000_unittest.h1
-rw-r--r--base/non_thread_safe.cc8
-rw-r--r--base/non_thread_safe.h16
-rw-r--r--base/non_thread_safe_unittest.cc108
-rw-r--r--base/nsimage_cache_mac.h1
-rw-r--r--base/nss_util.cc75
-rw-r--r--base/nss_util.h8
-rw-r--r--base/nss_util_internal.h1
-rw-r--r--base/nullable_string16.h1
-rw-r--r--base/object_watcher.h1
-rw-r--r--base/observer_list.h1
-rw-r--r--base/observer_list_threadsafe.h21
-rw-r--r--base/observer_list_unittest.cc45
-rw-r--r--base/path_service.cc39
-rw-r--r--base/path_service.h5
-rw-r--r--base/pe_image.h1
-rw-r--r--base/perftimer.h1
-rw-r--r--base/pickle.h1
-rw-r--r--base/platform_file.h118
-rw-r--r--base/platform_file_posix.cc123
-rw-r--r--base/platform_file_unittest.cc318
-rw-r--r--base/platform_file_win.cc147
-rw-r--r--base/platform_thread.h1
-rw-r--r--base/platform_thread_mac.mm5
-rw-r--r--base/platform_thread_unittest.cc104
-rw-r--r--base/port.h1
-rw-r--r--base/process.h1
-rw-r--r--base/process_posix.cc1
-rw-r--r--base/process_util.h65
-rw-r--r--base/process_util_linux.cc89
-rw-r--r--base/process_util_mac.mm21
-rw-r--r--base/process_util_posix.cc154
-rw-r--r--base/process_util_unittest.cc188
-rw-r--r--base/process_util_unittest_mac.h1
-rw-r--r--base/process_util_win.cc88
-rw-r--r--base/profiler.cc1
-rw-r--r--base/profiler.h1
-rw-r--r--base/rand_util.cc12
-rw-r--r--base/rand_util.h10
-rw-r--r--base/rand_util_c.h1
-rw-r--r--base/rand_util_unittest.cc8
-rw-r--r--base/raw_scoped_refptr_mismatch_checker.h1
-rw-r--r--base/ref_counted.h6
-rw-r--r--base/ref_counted_memory.cc46
-rw-r--r--base/ref_counted_memory.h34
-rw-r--r--base/registry.cc233
-rw-r--r--base/registry.h152
-rw-r--r--base/registry_unittest.cc59
-rw-r--r--base/resource_util.h7
-rw-r--r--base/safe_strerror_posix.h1
-rw-r--r--base/scoped_aedesc.h47
-rw-r--r--base/scoped_bstr_win.h1
-rw-r--r--base/scoped_callback_factory.h133
-rw-r--r--base/scoped_cftyperef.h1
-rw-r--r--base/scoped_comptr_win.h1
-rw-r--r--base/scoped_handle.h1
-rw-r--r--base/scoped_handle_win.h1
-rw-r--r--base/scoped_native_library.h4
-rw-r--r--base/scoped_native_library_unittest.cc3
-rw-r--r--base/scoped_nsautorelease_pool.h1
-rw-r--r--base/scoped_nsdisable_screen_updates.h1
-rw-r--r--base/scoped_nsobject.h36
-rw-r--r--base/scoped_open_process.h1
-rw-r--r--base/scoped_ptr.h11
-rw-r--r--base/scoped_temp_dir.cc19
-rw-r--r--base/scoped_temp_dir.h9
-rw-r--r--base/scoped_temp_dir_unittest.cc2
-rw-r--r--base/scoped_variant_win.h7
-rw-r--r--base/scoped_vector.h30
-rw-r--r--base/setproctitle_linux.h1
-rw-r--r--base/sha1.h1
-rw-r--r--base/sha1_win.cc1
-rw-r--r--base/sha2.cc7
-rw-r--r--base/sha2.h5
-rw-r--r--base/sha2_unittest.cc19
-rw-r--r--base/shared_memory.h12
-rw-r--r--base/shared_memory_posix.cc42
-rw-r--r--base/shared_memory_unittest.cc26
-rw-r--r--base/shared_memory_win.cc16
-rw-r--r--base/simple_thread.cc3
-rw-r--r--base/simple_thread.h1
-rw-r--r--base/simple_thread_unittest.cc12
-rw-r--r--base/singleton.h1
-rw-r--r--base/singleton_objc.h1
-rw-r--r--base/spin_wait.h1
-rw-r--r--base/stack_container.h1
-rw-r--r--base/stats_counters.cc113
-rw-r--r--base/stats_counters.h99
-rw-r--r--base/stats_table.cc2
-rw-r--r--base/stats_table.h1
-rw-r--r--base/stats_table_unittest.cc51
-rw-r--r--base/stl_util-inl.h1
-rw-r--r--base/string16.cc1
-rw-r--r--base/string16.h1
-rw-r--r--base/string16_unittest.cc1
-rw-r--r--base/string_number_conversions.cc401
-rw-r--r--base/string_number_conversions.h93
-rw-r--r--base/string_number_conversions_unittest.cc339
-rw-r--r--base/string_piece.cc4
-rw-r--r--base/string_piece.h1
-rw-r--r--base/string_split.cc106
-rw-r--r--base/string_split.h57
-rw-r--r--base/string_split_unittest.cc133
-rw-r--r--base/string_tokenizer.h8
-rw-r--r--base/string_util.cc934
-rw-r--r--base/string_util.h189
-rw-r--r--base/string_util_posix.h1
-rw-r--r--base/string_util_unittest.cc762
-rw-r--r--base/string_util_win.h1
-rw-r--r--base/stringprintf.cc175
-rw-r--r--base/stringprintf.h56
-rw-r--r--base/stringprintf_unittest.cc152
-rw-r--r--base/symbolize.target.mk7
-rw-r--r--base/sync_socket.h1
-rw-r--r--base/sync_socket_posix.cc1
-rw-r--r--base/sync_socket_win.cc1
-rw-r--r--base/sys_info.h1
-rw-r--r--base/sys_info_chromeos.cc8
-rw-r--r--base/sys_info_win.cc5
-rw-r--r--base/sys_string_conversions.h1
-rw-r--r--base/task.h32
-rw-r--r--base/task_queue.cc (renamed from chrome/common/task_queue.cc)9
-rw-r--r--base/task_queue.h (renamed from chrome/common/task_queue.h)11
-rw-r--r--base/task_queue_unittest.cc147
-rw-r--r--base/template_util.h3
-rw-r--r--base/test/perf_test_suite.h12
-rw-r--r--base/test/run_all_unittests.cc4
-rw-r--r--base/test/test_file_util.h5
-rw-r--r--base/test/test_suite.h247
-rw-r--r--base/test_support_base.target.mk25
-rw-r--r--base/test_support_perf.target.mk7
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.c2
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.gyp4
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.target.mk7
-rw-r--r--base/third_party/icu/icu_utf.h34
-rw-r--r--base/thread.cc12
-rw-r--r--base/thread.h8
-rw-r--r--base/thread_checker.cc16
-rw-r--r--base/thread_checker.h53
-rw-r--r--base/thread_checker_unittest.cc107
-rw-r--r--base/thread_collision_warner.h1
-rw-r--r--base/thread_local.h1
-rw-r--r--base/thread_local_storage.h1
-rw-r--r--base/thread_unittest.cc1
-rw-r--r--base/time.cc26
-rw-r--r--base/time.h21
-rw-r--r--base/time_unittest.cc2
-rw-r--r--base/time_win.cc30
-rw-r--r--base/time_win_unittest.cc60
-rw-r--r--base/timer.h1
-rw-r--r--base/tools_sanity_unittest.cc9
-rw-r--r--base/trace_event.cc4
-rw-r--r--base/trace_event.h1
-rw-r--r--base/trace_event_win.cc3
-rw-r--r--base/trace_event_win.h1
-rw-r--r--base/trace_event_win_unittest.cc3
-rw-r--r--base/tracked.cc4
-rw-r--r--base/tracked.h1
-rw-r--r--base/tracked_objects.cc200
-rw-r--r--base/tracked_objects.h47
-rw-r--r--base/tuple.h265
-rw-r--r--base/unix_domain_socket_posix.cc6
-rw-r--r--base/unix_domain_socket_posix.h3
-rw-r--r--base/utf_offset_string_conversions.h1
-rw-r--r--base/utf_string_conversion_utils.h1
-rw-r--r--base/utf_string_conversions.cc23
-rw-r--r--base/utf_string_conversions.h15
-rw-r--r--base/utf_string_conversions_unittest.cc3
-rw-r--r--base/values.cc298
-rw-r--r--base/values.h139
-rw-r--r--base/values_unittest.cc433
-rw-r--r--base/version.cc15
-rw-r--r--base/version.h1
-rw-r--r--base/vlog.cc69
-rw-r--r--base/vlog.h51
-rw-r--r--base/vlog_unittest.cc105
-rw-r--r--base/waitable_event.h7
-rw-r--r--base/waitable_event_posix.cc9
-rw-r--r--base/waitable_event_watcher.h1
-rw-r--r--base/watchdog.cc5
-rw-r--r--base/watchdog.h6
-rw-r--r--base/watchdog_unittest.cc29
-rw-r--r--base/weak_ptr.h1
-rw-r--r--base/win_util.cc32
-rw-r--r--base/win_util.h21
-rw-r--r--base/win_util_unittest.cc4
-rw-r--r--base/wmi_util.h1
-rw-r--r--base/worker_pool.h1
-rw-r--r--base/worker_pool_linux.cc8
-rw-r--r--base/worker_pool_linux.h1
-rw-r--r--base/worker_pool_mac.h1
-rw-r--r--base/worker_pool_mac.mm6
-rw-r--r--base/xdg_mime.target.mk7
-rw-r--r--base/xdg_util.cc22
-rw-r--r--base/xdg_util.h11
-rw-r--r--base/xdg_util_unittest.cc34
-rw-r--r--build/All.target.mk2
-rw-r--r--build/all.gyp32
-rwxr-xr-xbuild/build-bisect.py4
-rw-r--r--build/common.gypi138
-rw-r--r--build/features_override.gypi16
-rw-r--r--build/linux/system.Makefile2
-rw-r--r--build/linux/system.gyp49
-rw-r--r--build/temp_gyp/googleurl.target.mk7
-rw-r--r--build/temp_gyp/googleurl_unittests.target.mk7
-rw-r--r--build/util/lastchange.target.mk2
-rw-r--r--build/whitespace_file.txt6
-rw-r--r--chrome/browser/DEPS1
-rw-r--r--chrome/browser/accessibility_events.cc58
-rw-r--r--chrome/browser/accessibility_events.h46
-rw-r--r--chrome/browser/accessibility_win_browsertest.cc528
-rw-r--r--chrome/browser/aeropeek_manager.cc2
-rw-r--r--chrome/browser/aeropeek_manager.h13
-rw-r--r--chrome/browser/alternate_nav_url_fetcher.cc12
-rw-r--r--chrome/browser/alternate_nav_url_fetcher.h5
-rw-r--r--chrome/browser/app_controller_cppsafe_mac.h1
-rw-r--r--chrome/browser/app_controller_mac.h7
-rw-r--r--chrome/browser/app_controller_mac.mm47
-rw-r--r--chrome/browser/app_icon_win.h1
-rw-r--r--chrome/browser/app_launched_animation.h1
-rw-r--r--chrome/browser/app_modal_dialog.cc33
-rw-r--r--chrome/browser/app_modal_dialog.h101
-rw-r--r--chrome/browser/app_modal_dialog_gtk.cc51
-rw-r--r--chrome/browser/app_modal_dialog_mac.mm24
-rw-r--r--chrome/browser/app_modal_dialog_queue.h1
-rw-r--r--chrome/browser/app_modal_dialog_win.cc29
-rw-r--r--chrome/browser/appcache/appcache_dispatcher_host.cc16
-rw-r--r--chrome/browser/appcache/appcache_dispatcher_host.h5
-rw-r--r--chrome/browser/appcache/appcache_frontend_proxy.cc6
-rw-r--r--chrome/browser/appcache/appcache_frontend_proxy.h5
-rw-r--r--chrome/browser/appcache/chrome_appcache_service.cc112
-rw-r--r--chrome/browser/appcache/chrome_appcache_service.h24
-rw-r--r--chrome/browser/appcache/view_appcache_internals_job_factory.h1
-rw-r--r--chrome/browser/autocomplete/autocomplete.cc146
-rw-r--r--chrome/browser/autocomplete/autocomplete.h13
-rw-r--r--chrome/browser/autocomplete/autocomplete_accessibility.h1
-rw-r--r--chrome/browser/autocomplete/autocomplete_browsertest.cc109
-rw-r--r--chrome/browser/autocomplete/autocomplete_classifier.h1
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.cc98
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.h44
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_unittest.cc9
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view.h12
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc94
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc48
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.h26
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.h7
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.mm30
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_win.cc120
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_win.h27
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_model.cc35
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_model.h6
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view.h11
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc93
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_gtk.h4
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_mac.h8
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_mac.mm70
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_mac_unittest.mm6
-rw-r--r--chrome/browser/autocomplete/autocomplete_unittest.cc17
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.cc22
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.h14
-rw-r--r--chrome/browser/autocomplete/history_contents_provider_unittest.cc10
-rw-r--r--chrome/browser/autocomplete/history_url_provider.cc248
-rw-r--r--chrome/browser/autocomplete/history_url_provider.h138
-rw-r--r--chrome/browser/autocomplete/history_url_provider_unittest.cc54
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc16
-rw-r--r--chrome/browser/autocomplete/keyword_provider.h9
-rw-r--r--chrome/browser/autocomplete/keyword_provider_unittest.cc12
-rw-r--r--chrome/browser/autocomplete/search_provider.cc115
-rw-r--r--chrome/browser/autocomplete/search_provider.h16
-rw-r--r--chrome/browser/autocomplete/search_provider_unittest.cc38
-rw-r--r--chrome/browser/autocomplete_history_manager.cc23
-rw-r--r--chrome/browser/autocomplete_history_manager.h3
-rw-r--r--chrome/browser/autocomplete_history_manager_unittest.cc4
-rw-r--r--chrome/browser/autofill/address.h1
-rw-r--r--chrome/browser/autofill/address_field.cc16
-rw-r--r--chrome/browser/autofill/address_field.h1
-rw-r--r--chrome/browser/autofill/address_field_unittest.cc7
-rw-r--r--chrome/browser/autofill/auto_fill_editor_gtk.cc226
-rw-r--r--chrome/browser/autofill/autofill_address_model_mac.h1
-rw-r--r--chrome/browser/autofill/autofill_address_model_mac_unittest.mm1
-rw-r--r--chrome/browser/autofill/autofill_address_sheet_controller_mac.h2
-rw-r--r--chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm1
-rw-r--r--chrome/browser/autofill/autofill_cc_infobar.h2
-rw-r--r--chrome/browser/autofill/autofill_cc_infobar_delegate.cc41
-rw-r--r--chrome/browser/autofill/autofill_cc_infobar_delegate.h18
-rw-r--r--chrome/browser/autofill/autofill_cc_infobar_win.cc39
-rw-r--r--chrome/browser/autofill/autofill_common_unittest.cc10
-rw-r--r--chrome/browser/autofill/autofill_common_unittest.h3
-rw-r--r--chrome/browser/autofill/autofill_credit_card_model_mac.h6
-rw-r--r--chrome/browser/autofill/autofill_credit_card_model_mac.mm9
-rw-r--r--chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm11
-rw-r--r--chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h14
-rw-r--r--chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm35
-rw-r--r--chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm1
-rw-r--r--chrome/browser/autofill/autofill_dialog.h1
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac.h78
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac.mm338
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm325
-rw-r--r--chrome/browser/autofill/autofill_dialog_gtk.cc14
-rw-r--r--chrome/browser/autofill/autofill_dialog_mac.mm7
-rw-r--r--chrome/browser/autofill/autofill_download.cc4
-rw-r--r--chrome/browser/autofill/autofill_download.h3
-rw-r--r--chrome/browser/autofill/autofill_download_unittest.cc3
-rw-r--r--chrome/browser/autofill/autofill_field.cc4
-rw-r--r--chrome/browser/autofill/autofill_field.h1
-rw-r--r--chrome/browser/autofill/autofill_field_unittest.cc1
-rw-r--r--chrome/browser/autofill/autofill_manager.cc317
-rw-r--r--chrome/browser/autofill/autofill_manager.h46
-rw-r--r--chrome/browser/autofill/autofill_manager_unittest.cc210
-rw-r--r--chrome/browser/autofill/autofill_profile.cc1
-rw-r--r--chrome/browser/autofill/autofill_profile.h1
-rw-r--r--chrome/browser/autofill/autofill_profile_unittest.cc3
-rw-r--r--chrome/browser/autofill/autofill_text_field_mac.h3
-rw-r--r--chrome/browser/autofill/autofill_text_field_mac.mm35
-rw-r--r--chrome/browser/autofill/autofill_type.cc3
-rw-r--r--chrome/browser/autofill/autofill_type.h4
-rw-r--r--chrome/browser/autofill/autofill_xml_parser.cc3
-rw-r--r--chrome/browser/autofill/autofill_xml_parser.h1
-rw-r--r--chrome/browser/autofill/billing_address.h1
-rw-r--r--chrome/browser/autofill/contact_info.cc1
-rw-r--r--chrome/browser/autofill/contact_info.h1
-rw-r--r--chrome/browser/autofill/contact_info_unittest.cc1
-rw-r--r--chrome/browser/autofill/credit_card.cc167
-rw-r--r--chrome/browser/autofill/credit_card.h19
-rw-r--r--chrome/browser/autofill/credit_card_field.cc8
-rw-r--r--chrome/browser/autofill/credit_card_field.h1
-rw-r--r--chrome/browser/autofill/credit_card_field_unittest.cc1
-rw-r--r--chrome/browser/autofill/credit_card_unittest.cc11
-rw-r--r--chrome/browser/autofill/fax_field.cc1
-rw-r--r--chrome/browser/autofill/fax_field.h1
-rw-r--r--chrome/browser/autofill/fax_field_unittest.cc1
-rw-r--r--chrome/browser/autofill/fax_number.h1
-rw-r--r--chrome/browser/autofill/field_types.h1
-rw-r--r--chrome/browser/autofill/form_field.cc17
-rw-r--r--chrome/browser/autofill/form_field.h1
-rw-r--r--chrome/browser/autofill/form_field_unittest.cc83
-rw-r--r--chrome/browser/autofill/form_group.h1
-rw-r--r--chrome/browser/autofill/form_structure.cc37
-rw-r--r--chrome/browser/autofill/form_structure.h6
-rw-r--r--chrome/browser/autofill/form_structure_unittest.cc254
-rw-r--r--chrome/browser/autofill/home_address.h1
-rw-r--r--chrome/browser/autofill/home_phone_number.h1
-rw-r--r--chrome/browser/autofill/name_field.cc9
-rw-r--r--chrome/browser/autofill/name_field.h1
-rw-r--r--chrome/browser/autofill/name_field_unittest.cc239
-rw-r--r--chrome/browser/autofill/personal_data_manager.cc214
-rw-r--r--chrome/browser/autofill/personal_data_manager.h31
-rw-r--r--chrome/browser/autofill/personal_data_manager_mac.mm22
-rw-r--r--chrome/browser/autofill/personal_data_manager_unittest.cc167
-rw-r--r--chrome/browser/autofill/phone_field.cc1
-rw-r--r--chrome/browser/autofill/phone_field.h1
-rw-r--r--chrome/browser/autofill/phone_field_unittest.cc1
-rw-r--r--chrome/browser/autofill/phone_number.h1
-rw-r--r--chrome/browser/autofill/phone_number_unittest.cc1
-rw-r--r--chrome/browser/autofill/select_control_handler.cc520
-rw-r--r--chrome/browser/autofill/select_control_handler.h31
-rw-r--r--chrome/browser/automation/automation_autocomplete_edit_tracker.h1
-rw-r--r--chrome/browser/automation/automation_browser_tracker.h1
-rw-r--r--chrome/browser/automation/automation_extension_function.cc7
-rw-r--r--chrome/browser/automation/automation_extension_function.h5
-rw-r--r--chrome/browser/automation/automation_extension_tracker.cc4
-rw-r--r--chrome/browser/automation/automation_extension_tracker.h7
-rw-r--r--chrome/browser/automation/automation_profile_impl.cc216
-rw-r--r--chrome/browser/automation/automation_profile_impl.h25
-rw-r--r--chrome/browser/automation/automation_provider.cc3304
-rw-r--r--chrome/browser/automation/automation_provider.h675
-rw-r--r--chrome/browser/automation/automation_provider_gtk.cc82
-rw-r--r--chrome/browser/automation/automation_provider_json.cc1
-rw-r--r--chrome/browser/automation/automation_provider_json.h11
-rw-r--r--chrome/browser/automation/automation_provider_list.h1
-rw-r--r--chrome/browser/automation/automation_provider_mac.mm85
-rw-r--r--chrome/browser/automation/automation_provider_observers.cc290
-rw-r--r--chrome/browser/automation/automation_provider_observers.h221
-rw-r--r--chrome/browser/automation/automation_provider_views.cc190
-rw-r--r--chrome/browser/automation/automation_provider_win.cc144
-rw-r--r--chrome/browser/automation/automation_resource_message_filter.cc219
-rw-r--r--chrome/browser/automation/automation_resource_message_filter.h39
-rw-r--r--chrome/browser/automation/automation_resource_routing_delegate.h1
-rw-r--r--chrome/browser/automation/automation_resource_tracker.cc8
-rw-r--r--chrome/browser/automation/automation_resource_tracker.h7
-rw-r--r--chrome/browser/automation/automation_tab_tracker.h73
-rw-r--r--chrome/browser/automation/automation_window_tracker.h21
-rw-r--r--chrome/browser/automation/chrome_frame_automation_provider.cc3
-rw-r--r--chrome/browser/automation/chrome_frame_automation_provider.h4
-rw-r--r--chrome/browser/automation/extension_automation_constants.cc26
-rw-r--r--chrome/browser/automation/extension_automation_constants.h27
-rw-r--r--chrome/browser/automation/extension_port_container.cc5
-rw-r--r--chrome/browser/automation/extension_port_container.h2
-rw-r--r--chrome/browser/automation/ui_controls.h16
-rw-r--r--chrome/browser/automation/ui_controls_linux.cc31
-rw-r--r--chrome/browser/automation/ui_controls_mac.mm274
-rw-r--r--chrome/browser/automation/ui_controls_win.cc29
-rw-r--r--chrome/browser/automation/url_request_automation_job.cc2
-rw-r--r--chrome/browser/automation/url_request_automation_job.h14
-rw-r--r--chrome/browser/back_forward_menu_model.cc5
-rw-r--r--chrome/browser/back_forward_menu_model.h1
-rw-r--r--chrome/browser/back_forward_menu_model_unittest.cc18
-rw-r--r--chrome/browser/background_contents_service.cc66
-rw-r--r--chrome/browser/background_contents_service.h31
-rw-r--r--chrome/browser/background_contents_service_unittest.cc14
-rw-r--r--chrome/browser/background_mode_manager.cc474
-rw-r--r--chrome/browser/background_mode_manager.h152
-rw-r--r--chrome/browser/background_mode_manager_unittest.cc117
-rw-r--r--chrome/browser/blocked_plugin_manager.cc91
-rw-r--r--chrome/browser/blocked_plugin_manager.h40
-rw-r--r--chrome/browser/blocked_popup_container.cc13
-rw-r--r--chrome/browser/blocked_popup_container.h19
-rw-r--r--chrome/browser/bookmarks/base_bookmark_model_observer.h1
-rw-r--r--chrome/browser/bookmarks/bookmark_codec.cc59
-rw-r--r--chrome/browser/bookmarks/bookmark_codec.h28
-rw-r--r--chrome/browser/bookmarks/bookmark_codec_unittest.cc54
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu_controller.cc2
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu_controller.h2
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc21
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.cc17
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.h15
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data_unittest.cc46
-rw-r--r--chrome/browser/bookmarks/bookmark_drop_info.cc3
-rw-r--r--chrome/browser/bookmarks/bookmark_drop_info.h3
-rw-r--r--chrome/browser/bookmarks/bookmark_editor.h14
-rw-r--r--chrome/browser/bookmarks/bookmark_folder_editor_controller.cc28
-rw-r--r--chrome/browser/bookmarks/bookmark_folder_editor_controller.h1
-rw-r--r--chrome/browser/bookmarks/bookmark_html_writer.cc10
-rw-r--r--chrome/browser/bookmarks/bookmark_html_writer.h4
-rw-r--r--chrome/browser/bookmarks/bookmark_html_writer_unittest.cc98
-rw-r--r--chrome/browser/bookmarks/bookmark_index.cc72
-rw-r--r--chrome/browser/bookmarks/bookmark_index.h47
-rw-r--r--chrome/browser/bookmarks/bookmark_index_unittest.cc112
-rw-r--r--chrome/browser/bookmarks/bookmark_model.cc78
-rw-r--r--chrome/browser/bookmarks/bookmark_model.h52
-rw-r--r--chrome/browser/bookmarks/bookmark_model_observer.h1
-rw-r--r--chrome/browser/bookmarks/bookmark_model_test_utils.cc2
-rw-r--r--chrome/browser/bookmarks/bookmark_model_test_utils.h1
-rw-r--r--chrome/browser/bookmarks/bookmark_model_unittest.cc146
-rw-r--r--chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h1
-rw-r--r--chrome/browser/bookmarks/bookmark_service.h32
-rw-r--r--chrome/browser/bookmarks/bookmark_storage.cc16
-rw-r--r--chrome/browser/bookmarks/bookmark_storage.h14
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc48
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.h18
-rw-r--r--chrome/browser/bookmarks/bookmark_utils_unittest.cc57
-rw-r--r--chrome/browser/bookmarks/recently_used_folders_combo_model.cc4
-rw-r--r--chrome/browser/bookmarks/recently_used_folders_combo_model.h12
-rw-r--r--chrome/browser/browser.cc1088
-rw-r--r--chrome/browser/browser.h251
-rw-r--r--chrome/browser/browser_about_handler.cc355
-rw-r--r--chrome/browser/browser_about_handler.h1
-rw-r--r--chrome/browser/browser_accessibility_manager_win.cc172
-rw-r--r--chrome/browser/browser_accessibility_manager_win.h39
-rw-r--r--chrome/browser/browser_accessibility_win.cc501
-rw-r--r--chrome/browser/browser_accessibility_win.h160
-rw-r--r--chrome/browser/browser_accessibility_win_unittest.cc168
-rw-r--r--chrome/browser/browser_browsertest.cc398
-rw-r--r--chrome/browser/browser_child_process_host.cc32
-rw-r--r--chrome/browser/browser_child_process_host.h1
-rw-r--r--chrome/browser/browser_commands_unittest.cc2
-rw-r--r--chrome/browser/browser_encoding_uitest.cc2
-rw-r--r--chrome/browser/browser_focus_uitest.cc346
-rw-r--r--chrome/browser/browser_init.cc254
-rw-r--r--chrome/browser/browser_init.h63
-rw-r--r--chrome/browser/browser_init_browsertest.cc24
-rw-r--r--chrome/browser/browser_keyevents_browsertest.cc584
-rw-r--r--chrome/browser/browser_list.cc28
-rw-r--r--chrome/browser/browser_list.h12
-rw-r--r--chrome/browser/browser_main.cc633
-rw-r--r--chrome/browser/browser_main.h73
-rw-r--r--chrome/browser/browser_main_gtk.cc35
-rw-r--r--chrome/browser/browser_main_gtk.h15
-rw-r--r--chrome/browser/browser_main_mac.mm143
-rw-r--r--chrome/browser/browser_main_posix.cc129
-rw-r--r--chrome/browser/browser_main_posix.h25
-rw-r--r--chrome/browser/browser_main_win.cc62
-rw-r--r--chrome/browser/browser_main_win.h4
-rw-r--r--chrome/browser/browser_process.cc1
-rw-r--r--chrome/browser/browser_process.h14
-rw-r--r--chrome/browser/browser_process_impl.cc306
-rw-r--r--chrome/browser/browser_process_impl.h213
-rw-r--r--chrome/browser/browser_process_sub_thread.h3
-rw-r--r--chrome/browser/browser_resources.grd23
-rw-r--r--chrome/browser/browser_shutdown.cc27
-rw-r--r--chrome/browser/browser_shutdown.h6
-rw-r--r--chrome/browser/browser_theme_pack.cc1037
-rw-r--r--chrome/browser/browser_theme_pack.h226
-rw-r--r--chrome/browser/browser_theme_pack_unittest.cc429
-rw-r--r--chrome/browser/browser_theme_provider.cc603
-rw-r--r--chrome/browser/browser_theme_provider.h275
-rw-r--r--chrome/browser/browser_theme_provider_gtk.cc73
-rw-r--r--chrome/browser/browser_theme_provider_mac.mm317
-rw-r--r--chrome/browser/browser_theme_provider_unittest.cc52
-rw-r--r--chrome/browser/browser_trial.h1
-rw-r--r--chrome/browser/browser_uitest.cc49
-rw-r--r--chrome/browser/browser_unittest.cc109
-rw-r--r--chrome/browser/browser_url_handler.cc2
-rw-r--r--chrome/browser/browser_url_handler.h2
-rw-r--r--chrome/browser/browser_window.h44
-rw-r--r--chrome/browser/browsing_data_appcache_helper.cc14
-rw-r--r--chrome/browser/browsing_data_appcache_helper.h6
-rw-r--r--chrome/browser/browsing_data_appcache_helper_unittest.cc26
-rw-r--r--chrome/browser/browsing_data_database_helper.cc7
-rw-r--r--chrome/browser/browsing_data_database_helper.h4
-rw-r--r--chrome/browser/browsing_data_database_helper_browsertest.cc3
-rw-r--r--chrome/browser/browsing_data_database_helper_unittest.cc34
-rw-r--r--chrome/browser/browsing_data_indexed_db_helper.cc217
-rw-r--r--chrome/browser/browsing_data_indexed_db_helper.h125
-rw-r--r--chrome/browser/browsing_data_indexed_db_helper_unittest.cc112
-rw-r--r--chrome/browser/browsing_data_local_storage_helper.cc7
-rw-r--r--chrome/browser/browsing_data_local_storage_helper.h5
-rw-r--r--chrome/browser/browsing_data_local_storage_helper_browsertest.cc33
-rw-r--r--chrome/browser/browsing_data_local_storage_helper_unittest.cc32
-rw-r--r--chrome/browser/browsing_data_remover.cc57
-rw-r--r--chrome/browser/browsing_data_remover.h18
-rw-r--r--chrome/browser/browsing_instance.cc11
-rw-r--r--chrome/browser/browsing_instance.h12
-rw-r--r--chrome/browser/bug_report_util.cc191
-rw-r--r--chrome/browser/bug_report_util.h11
-rw-r--r--chrome/browser/cancelable_request.cc28
-rw-r--r--chrome/browser/cancelable_request.h277
-rw-r--r--chrome/browser/cert_store.h2
-rw-r--r--chrome/browser/certificate_manager_model.cc111
-rw-r--r--chrome/browser/certificate_manager_model.h54
-rw-r--r--chrome/browser/certificate_viewer.h1
-rw-r--r--chrome/browser/character_encoding.cc1
-rw-r--r--chrome/browser/character_encoding.h1
-rw-r--r--chrome/browser/child_process_launcher.cc37
-rw-r--r--chrome/browser/child_process_launcher.h4
-rw-r--r--chrome/browser/child_process_security_policy.cc56
-rw-r--r--chrome/browser/child_process_security_policy.h25
-rw-r--r--chrome/browser/child_process_security_policy_browsertest.cc1
-rw-r--r--chrome/browser/child_process_security_policy_unittest.cc89
-rw-r--r--chrome/browser/chrome_blob_storage_context.cc22
-rw-r--r--chrome/browser/chrome_blob_storage_context.h46
-rw-r--r--chrome/browser/chrome_browser_application_mac.h1
-rw-r--r--chrome/browser/chrome_plugin_browsing_context.h2
-rw-r--r--chrome/browser/chrome_plugin_host.cc8
-rw-r--r--chrome/browser/chrome_plugin_host.h1
-rw-r--r--chrome/browser/chrome_plugin_unittest.cc10
-rw-r--r--chrome/browser/chrome_thread.cc8
-rw-r--r--chrome/browser/chrome_thread.h8
-rw-r--r--chrome/browser/chromeos/DEPS1
-rwxr-xr-xchrome/browser/chromeos/PRESUBMIT.py4
-rw-r--r--chrome/browser/chromeos/audio_handler.cc60
-rw-r--r--chrome/browser/chromeos/audio_handler.h10
-rw-r--r--chrome/browser/chromeos/boot_times_loader.cc26
-rw-r--r--chrome/browser/chromeos/boot_times_loader.h1
-rw-r--r--chrome/browser/chromeos/cros/cros_api.gyp0
-rw-r--r--chrome/browser/chromeos/cros/cros_in_process_browser_test.cc288
-rw-r--r--chrome/browser/chromeos/cros/cros_in_process_browser_test.h74
-rw-r--r--chrome/browser/chromeos/cros/cros_library.cc274
-rw-r--r--chrome/browser/chromeos/cros/cros_library.h107
-rw-r--r--chrome/browser/chromeos/cros/cros_library_loader.h1
-rw-r--r--chrome/browser/chromeos/cros/cryptohome_library.cc253
-rw-r--r--chrome/browser/chromeos/cros/cryptohome_library.h102
-rw-r--r--chrome/browser/chromeos/cros/input_method_library.cc907
-rw-r--r--chrome/browser/chromeos/cros/input_method_library.h138
-rw-r--r--chrome/browser/chromeos/cros/keyboard_library.cc148
-rw-r--r--chrome/browser/chromeos/cros/keyboard_library.h35
-rw-r--r--chrome/browser/chromeos/cros/login_library.cc230
-rw-r--r--chrome/browser/chromeos/cros/login_library.h82
-rw-r--r--chrome/browser/chromeos/cros/mock_cros_library.h1
-rw-r--r--chrome/browser/chromeos/cros/mock_cryptohome_library.h59
-rw-r--r--chrome/browser/chromeos/cros/mock_input_method_library.h5
-rw-r--r--chrome/browser/chromeos/cros/mock_keyboard_library.h7
-rw-r--r--chrome/browser/chromeos/cros/mock_library_loader.h1
-rw-r--r--chrome/browser/chromeos/cros/mock_login_library.h20
-rw-r--r--chrome/browser/chromeos/cros/mock_mount_library.h11
-rw-r--r--chrome/browser/chromeos/cros/mock_network_library.h6
-rw-r--r--chrome/browser/chromeos/cros/mock_power_library.h1
-rw-r--r--chrome/browser/chromeos/cros/mock_screen_lock_library.h1
-rw-r--r--chrome/browser/chromeos/cros/mock_speech_synthesis_library.h1
-rw-r--r--chrome/browser/chromeos/cros/mock_synaptics_library.h24
-rw-r--r--chrome/browser/chromeos/cros/mock_system_library.h3
-rw-r--r--chrome/browser/chromeos/cros/mock_update_library.h4
-rw-r--r--chrome/browser/chromeos/cros/mount_library.cc191
-rw-r--r--chrome/browser/chromeos/cros/mount_library.h50
-rw-r--r--chrome/browser/chromeos/cros/network_library.cc1225
-rw-r--r--chrome/browser/chromeos/cros/network_library.h283
-rw-r--r--chrome/browser/chromeos/cros/power_library.cc168
-rw-r--r--chrome/browser/chromeos/cros/power_library.h62
-rw-r--r--chrome/browser/chromeos/cros/screen_lock_library.cc245
-rw-r--r--chrome/browser/chromeos/cros/screen_lock_library.h45
-rw-r--r--chrome/browser/chromeos/cros/speech_synthesis_library.cc59
-rw-r--r--chrome/browser/chromeos/cros/speech_synthesis_library.h20
-rw-r--r--chrome/browser/chromeos/cros/synaptics_library.cc37
-rw-r--r--chrome/browser/chromeos/cros/synaptics_library.h55
-rw-r--r--chrome/browser/chromeos/cros/syslogs_library.cc71
-rw-r--r--chrome/browser/chromeos/cros/syslogs_library.h35
-rw-r--r--chrome/browser/chromeos/cros/system_library.cc147
-rw-r--r--chrome/browser/chromeos/cros/system_library.h27
-rw-r--r--chrome/browser/chromeos/cros/update_library.cc132
-rw-r--r--chrome/browser/chromeos/cros/update_library.h47
-rw-r--r--chrome/browser/chromeos/cros_settings.cc155
-rw-r--r--chrome/browser/chromeos/cros_settings.h68
-rw-r--r--chrome/browser/chromeos/cros_settings_names.cc11
-rw-r--r--chrome/browser/chromeos/cros_settings_names.h11
-rw-r--r--chrome/browser/chromeos/customization_document.cc60
-rw-r--r--chrome/browser/chromeos/customization_document.h46
-rw-r--r--chrome/browser/chromeos/customization_document_unittest.cc8
-rw-r--r--chrome/browser/chromeos/dom_ui/accounts_options_handler.cc67
-rw-r--r--chrome/browser/chromeos/dom_ui/accounts_options_handler.h16
-rw-r--r--chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc75
-rw-r--r--chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h28
-rw-r--r--chrome/browser/chromeos/dom_ui/labs_handler.cc40
-rw-r--r--chrome/browser/chromeos/dom_ui/labs_handler.h4
-rw-r--r--chrome/browser/chromeos/dom_ui/language_hangul_options_handler.cc21
-rw-r--r--chrome/browser/chromeos/dom_ui/language_hangul_options_handler.h5
-rw-r--r--chrome/browser/chromeos/dom_ui/language_options_handler.cc281
-rw-r--r--chrome/browser/chromeos/dom_ui/language_options_handler.h58
-rw-r--r--chrome/browser/chromeos/dom_ui/sync_options_handler.cc49
-rw-r--r--chrome/browser/chromeos/dom_ui/sync_options_handler.h23
-rw-r--r--chrome/browser/chromeos/dom_ui/system_options_handler.cc146
-rw-r--r--chrome/browser/chromeos/dom_ui/system_options_handler.h21
-rw-r--r--chrome/browser/chromeos/drop_shadow_label.h1
-rw-r--r--chrome/browser/chromeos/external_cookie_handler.h1
-rw-r--r--chrome/browser/chromeos/external_metrics.h1
-rw-r--r--chrome/browser/chromeos/external_protocol_dialog.cc4
-rw-r--r--chrome/browser/chromeos/external_protocol_dialog.h5
-rw-r--r--chrome/browser/chromeos/frame/browser_frame_chromeos.cc32
-rw-r--r--chrome/browser/chromeos/frame/browser_frame_chromeos.h1
-rw-r--r--chrome/browser/chromeos/frame/browser_view.cc134
-rw-r--r--chrome/browser/chromeos/frame/browser_view.h12
-rw-r--r--chrome/browser/chromeos/frame/normal_browser_frame_view.cc371
-rw-r--r--chrome/browser/chromeos/frame/normal_browser_frame_view.h92
-rw-r--r--chrome/browser/chromeos/frame/panel_browser_view.cc12
-rw-r--r--chrome/browser/chromeos/frame/panel_browser_view.h1
-rw-r--r--chrome/browser/chromeos/frame/panel_controller.cc98
-rw-r--r--chrome/browser/chromeos/frame/panel_controller.h5
-rw-r--r--chrome/browser/chromeos/google_update_chromeos.cc2
-rw-r--r--chrome/browser/chromeos/gview_request_interceptor.cc5
-rw-r--r--chrome/browser/chromeos/gview_request_interceptor.h1
-rw-r--r--chrome/browser/chromeos/gview_request_interceptor_unittest.cc79
-rw-r--r--chrome/browser/chromeos/input_method/candidate_window.cc539
-rw-r--r--chrome/browser/chromeos/input_method/candidate_window.gyp1
-rw-r--r--chrome/browser/chromeos/input_method/input_method_util.cc111
-rw-r--r--chrome/browser/chromeos/input_method/input_method_util.h32
-rw-r--r--chrome/browser/chromeos/input_method/input_method_util_unittest.cc85
-rw-r--r--chrome/browser/chromeos/language_preferences.h455
-rw-r--r--chrome/browser/chromeos/language_preferences_unittest.cc6
-rw-r--r--chrome/browser/chromeos/login/account_creation_view.cc2
-rw-r--r--chrome/browser/chromeos/login/account_creation_view.h1
-rw-r--r--chrome/browser/chromeos/login/account_screen.cc12
-rw-r--r--chrome/browser/chromeos/login/account_screen.h2
-rw-r--r--chrome/browser/chromeos/login/account_screen_browsertest.cc13
-rw-r--r--chrome/browser/chromeos/login/auth_response_handler.h1
-rw-r--r--chrome/browser/chromeos/login/authentication_notification_details.h1
-rw-r--r--chrome/browser/chromeos/login/authenticator.h21
-rw-r--r--chrome/browser/chromeos/login/background_view.cc282
-rw-r--r--chrome/browser/chromeos/login/background_view.h96
-rw-r--r--chrome/browser/chromeos/login/camera.cc5
-rw-r--r--chrome/browser/chromeos/login/camera.h1
-rw-r--r--chrome/browser/chromeos/login/captcha_view.h1
-rw-r--r--chrome/browser/chromeos/login/client_login_response_handler.h3
-rw-r--r--chrome/browser/chromeos/login/cookie_fetcher.cc1
-rw-r--r--chrome/browser/chromeos/login/cookie_fetcher.h1
-rw-r--r--chrome/browser/chromeos/login/cookie_fetcher_unittest.cc5
-rw-r--r--chrome/browser/chromeos/login/eula_view.cc382
-rw-r--r--chrome/browser/chromeos/login/eula_view.h104
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.cc337
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.h61
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.cc86
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.h22
-rw-r--r--chrome/browser/chromeos/login/google_authenticator_unittest.cc306
-rw-r--r--chrome/browser/chromeos/login/helper.cc11
-rw-r--r--chrome/browser/chromeos/login/helper.h22
-rw-r--r--chrome/browser/chromeos/login/image_decoder.h1
-rw-r--r--chrome/browser/chromeos/login/image_downloader.cc4
-rw-r--r--chrome/browser/chromeos/login/image_downloader.h1
-rw-r--r--chrome/browser/chromeos/login/issue_response_handler.cc5
-rw-r--r--chrome/browser/chromeos/login/issue_response_handler.h3
-rw-r--r--chrome/browser/chromeos/login/language_switch_menu.cc25
-rw-r--r--chrome/browser/chromeos/login/language_switch_menu.h6
-rw-r--r--chrome/browser/chromeos/login/login_browsertest.cc19
-rw-r--r--chrome/browser/chromeos/login/login_html_dialog.cc43
-rw-r--r--chrome/browser/chromeos/login/login_html_dialog.h10
-rw-r--r--chrome/browser/chromeos/login/login_screen.cc29
-rw-r--r--chrome/browser/chromeos/login/login_screen.h9
-rw-r--r--chrome/browser/chromeos/login/login_screen_browsertest.cc28
-rw-r--r--chrome/browser/chromeos/login/login_status_consumer.h78
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc160
-rw-r--r--chrome/browser/chromeos/login/login_utils.h15
-rw-r--r--chrome/browser/chromeos/login/message_bubble.cc43
-rw-r--r--chrome/browser/chromeos/login/message_bubble.h32
-rw-r--r--chrome/browser/chromeos/login/mock_auth_response_handler.h1
-rw-r--r--chrome/browser/chromeos/login/mock_authenticator.h13
-rw-r--r--chrome/browser/chromeos/login/mock_screen_observer.h1
-rw-r--r--chrome/browser/chromeos/login/mock_update_screen.h1
-rw-r--r--chrome/browser/chromeos/login/network_screen.cc301
-rw-r--r--chrome/browser/chromeos/login/network_screen.h94
-rw-r--r--chrome/browser/chromeos/login/network_screen_browsertest.cc553
-rw-r--r--chrome/browser/chromeos/login/network_screen_delegate.h14
-rw-r--r--chrome/browser/chromeos/login/network_selection_view.cc422
-rw-r--r--chrome/browser/chromeos/login/network_selection_view.h74
-rw-r--r--chrome/browser/chromeos/login/new_user_view.cc265
-rw-r--r--chrome/browser/chromeos/login/new_user_view.h59
-rw-r--r--chrome/browser/chromeos/login/owner_key_utils.cc285
-rw-r--r--chrome/browser/chromeos/login/owner_key_utils.h81
-rw-r--r--chrome/browser/chromeos/login/owner_key_utils_unittest.cc105
-rw-r--r--chrome/browser/chromeos/login/password_changed_view.cc9
-rw-r--r--chrome/browser/chromeos/login/password_changed_view.h2
-rw-r--r--chrome/browser/chromeos/login/registration_screen.cc17
-rw-r--r--chrome/browser/chromeos/login/registration_screen.h2
-rw-r--r--chrome/browser/chromeos/login/rounded_rect_painter.cc68
-rw-r--r--chrome/browser/chromeos/login/rounded_rect_painter.h8
-rw-r--r--chrome/browser/chromeos/login/screen_lock_view.cc24
-rw-r--r--chrome/browser/chromeos/login/screen_lock_view.h7
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc238
-rw-r--r--chrome/browser/chromeos/login/screen_locker.h30
-rw-r--r--chrome/browser/chromeos/login/screen_locker_browsertest.cc36
-rw-r--r--chrome/browser/chromeos/login/screen_locker_tester.cc11
-rw-r--r--chrome/browser/chromeos/login/screen_locker_tester.h3
-rw-r--r--chrome/browser/chromeos/login/screen_observer.h2
-rw-r--r--chrome/browser/chromeos/login/update_screen.cc211
-rw-r--r--chrome/browser/chromeos/login/update_screen.h51
-rw-r--r--chrome/browser/chromeos/login/update_view.cc156
-rw-r--r--chrome/browser/chromeos/login/update_view.h44
-rw-r--r--chrome/browser/chromeos/login/user_controller.cc322
-rw-r--r--chrome/browser/chromeos/login/user_controller.h54
-rw-r--r--chrome/browser/chromeos/login/user_image_downloader.cc21
-rw-r--r--chrome/browser/chromeos/login/user_image_downloader.h3
-rw-r--r--chrome/browser/chromeos/login/user_image_loader.h1
-rw-r--r--chrome/browser/chromeos/login/user_image_screen.cc12
-rw-r--r--chrome/browser/chromeos/login/user_image_screen.h3
-rw-r--r--chrome/browser/chromeos/login/user_image_view.cc269
-rw-r--r--chrome/browser/chromeos/login/user_image_view.h36
-rw-r--r--chrome/browser/chromeos/login/user_manager.cc80
-rw-r--r--chrome/browser/chromeos/login/user_manager.h31
-rw-r--r--chrome/browser/chromeos/login/user_view.cc223
-rw-r--r--chrome/browser/chromeos/login/user_view.h50
-rw-r--r--chrome/browser/chromeos/login/view_screen.h22
-rw-r--r--chrome/browser/chromeos/login/web_page_screen.h11
-rw-r--r--chrome/browser/chromeos/login/web_page_view.cc10
-rw-r--r--chrome/browser/chromeos/login/web_page_view.h1
-rw-r--r--chrome/browser/chromeos/login/wizard_controller.cc537
-rw-r--r--chrome/browser/chromeos/login/wizard_controller.h66
-rw-r--r--chrome/browser/chromeos/login/wizard_controller_browsertest.cc73
-rw-r--r--chrome/browser/chromeos/login/wizard_in_process_browser_test.h1
-rw-r--r--chrome/browser/chromeos/login/wizard_screen.h7
-rw-r--r--chrome/browser/chromeos/low_battery_observer.cc3
-rw-r--r--chrome/browser/chromeos/low_battery_observer.h1
-rw-r--r--chrome/browser/chromeos/mock_cros_settings.cc36
-rw-r--r--chrome/browser/chromeos/mock_cros_settings.h30
-rw-r--r--chrome/browser/chromeos/native_dialog_window.cc43
-rw-r--r--chrome/browser/chromeos/native_dialog_window.h1
-rw-r--r--chrome/browser/chromeos/network_list.cc2
-rw-r--r--chrome/browser/chromeos/network_list.h2
-rw-r--r--chrome/browser/chromeos/network_message_observer.cc107
-rw-r--r--chrome/browser/chromeos/network_message_observer.h17
-rw-r--r--chrome/browser/chromeos/network_state_notifier.h2
-rw-r--r--chrome/browser/chromeos/network_state_notifier_browsertest.cc14
-rw-r--r--chrome/browser/chromeos/notifications/balloon_collection_impl.cc20
-rw-r--r--chrome/browser/chromeos/notifications/balloon_collection_impl.h13
-rw-r--r--chrome/browser/chromeos/notifications/balloon_view.cc17
-rw-r--r--chrome/browser/chromeos/notifications/balloon_view.h10
-rw-r--r--chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc12
-rw-r--r--chrome/browser/chromeos/notifications/desktop_notifications_unittest.h1
-rw-r--r--chrome/browser/chromeos/notifications/notification_browsertest.cc93
-rw-r--r--chrome/browser/chromeos/notifications/notification_panel.cc2
-rw-r--r--chrome/browser/chromeos/notifications/notification_panel.h3
-rw-r--r--chrome/browser/chromeos/notifications/system_notification.cc24
-rw-r--r--chrome/browser/chromeos/notifications/system_notification.h7
-rw-r--r--chrome/browser/chromeos/notifications/system_notification_factory.cc3
-rw-r--r--chrome/browser/chromeos/notifications/system_notification_factory.h1
-rw-r--r--chrome/browser/chromeos/offline/offline_load_page.cc29
-rw-r--r--chrome/browser/chromeos/offline/offline_load_page.h1
-rw-r--r--chrome/browser/chromeos/offline/offline_load_page_unittest.cc2
-rw-r--r--chrome/browser/chromeos/offline/offline_load_service.cc6
-rw-r--r--chrome/browser/chromeos/offline/offline_load_service.h3
-rw-r--r--chrome/browser/chromeos/options/cellular_config_view.cc192
-rw-r--r--chrome/browser/chromeos/options/cellular_config_view.h33
-rw-r--r--chrome/browser/chromeos/options/internet_page_view.cc27
-rw-r--r--chrome/browser/chromeos/options/internet_page_view.h2
-rw-r--r--chrome/browser/chromeos/options/ip_config_view.cc1
-rw-r--r--chrome/browser/chromeos/options/ip_config_view.h1
-rw-r--r--chrome/browser/chromeos/options/language_chewing_config_view.cc62
-rw-r--r--chrome/browser/chromeos/options/language_chewing_config_view.h17
-rw-r--r--chrome/browser/chromeos/options/language_config_model.cc13
-rw-r--r--chrome/browser/chromeos/options/language_config_model.h11
-rw-r--r--chrome/browser/chromeos/options/language_config_model_unittest.cc8
-rw-r--r--chrome/browser/chromeos/options/language_config_util.h17
-rw-r--r--chrome/browser/chromeos/options/language_config_view.cc5
-rw-r--r--chrome/browser/chromeos/options/language_config_view.h2
-rw-r--r--chrome/browser/chromeos/options/language_hangul_config_view.cc19
-rw-r--r--chrome/browser/chromeos/options/language_hangul_config_view.h3
-rw-r--r--chrome/browser/chromeos/options/language_mozc_config_view.cc72
-rw-r--r--chrome/browser/chromeos/options/language_mozc_config_view.h10
-rw-r--r--chrome/browser/chromeos/options/language_pinyin_config_view.cc28
-rw-r--r--chrome/browser/chromeos/options/language_pinyin_config_view.h9
-rw-r--r--chrome/browser/chromeos/options/network_config_view.cc3
-rw-r--r--chrome/browser/chromeos/options/network_config_view.h4
-rw-r--r--chrome/browser/chromeos/options/options_window_view.cc9
-rw-r--r--chrome/browser/chromeos/options/options_window_view.h1
-rw-r--r--chrome/browser/chromeos/options/settings_page_view.cc3
-rw-r--r--chrome/browser/chromeos/options/settings_page_view.h3
-rw-r--r--chrome/browser/chromeos/options/system_page_view.cc173
-rw-r--r--chrome/browser/chromeos/options/system_page_view.h1
-rw-r--r--chrome/browser/chromeos/options/wifi_config_view.cc57
-rw-r--r--chrome/browser/chromeos/options/wifi_config_view.h10
-rw-r--r--chrome/browser/chromeos/options/wifi_config_view_browsertest.cc14
-rw-r--r--chrome/browser/chromeos/panels/panel_scroller.cc3
-rw-r--r--chrome/browser/chromeos/panels/panel_scroller.h7
-rw-r--r--chrome/browser/chromeos/panels/panel_scroller_container.h8
-rw-r--r--chrome/browser/chromeos/panels/panel_scroller_header.h14
-rw-r--r--chrome/browser/chromeos/pipe_reader.cc17
-rw-r--r--chrome/browser/chromeos/pipe_reader.h19
-rw-r--r--chrome/browser/chromeos/pipe_reader_unittest.cc5
-rw-r--r--chrome/browser/chromeos/preferences.cc407
-rw-r--r--chrome/browser/chromeos/preferences.h55
-rw-r--r--chrome/browser/chromeos/pulse_audio_mixer.cc273
-rw-r--r--chrome/browser/chromeos/pulse_audio_mixer.h72
-rw-r--r--chrome/browser/chromeos/status/clock_menu_button.cc25
-rw-r--r--chrome/browser/chromeos/status/clock_menu_button.h4
-rw-r--r--chrome/browser/chromeos/status/clock_menu_button_browsertest.cc18
-rw-r--r--chrome/browser/chromeos/status/feedback_menu_button.cc2
-rw-r--r--chrome/browser/chromeos/status/feedback_menu_button.h2
-rw-r--r--chrome/browser/chromeos/status/language_menu_button.cc105
-rw-r--r--chrome/browser/chromeos/status/language_menu_button.h13
-rw-r--r--chrome/browser/chromeos/status/language_menu_button_browsertest.cc4
-rw-r--r--chrome/browser/chromeos/status/language_menu_button_unittest.cc101
-rw-r--r--chrome/browser/chromeos/status/network_menu_button.cc508
-rw-r--r--chrome/browser/chromeos/status/network_menu_button.h103
-rw-r--r--chrome/browser/chromeos/status/power_menu_button.cc198
-rw-r--r--chrome/browser/chromeos/status/power_menu_button.h22
-rw-r--r--chrome/browser/chromeos/status/power_menu_button_browsertest.cc95
-rw-r--r--chrome/browser/chromeos/status/status_area_button.cc56
-rw-r--r--chrome/browser/chromeos/status/status_area_button.h16
-rw-r--r--chrome/browser/chromeos/status/status_area_host.h1
-rw-r--r--chrome/browser/chromeos/status/status_area_view.cc3
-rw-r--r--chrome/browser/chromeos/status/status_area_view.h1
-rw-r--r--chrome/browser/chromeos/system_key_event_listener.h1
-rw-r--r--chrome/browser/chromeos/tab_closeable_state_watcher.cc17
-rw-r--r--chrome/browser/chromeos/tab_closeable_state_watcher.h17
-rw-r--r--chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc16
-rw-r--r--chrome/browser/chromeos/testdata/services_manifest.json19
-rw-r--r--chrome/browser/chromeos/testdata/startup_manifest.json23
-rw-r--r--chrome/browser/chromeos/update_browsertest.cc6
-rw-r--r--chrome/browser/chromeos/update_observer.cc52
-rw-r--r--chrome/browser/chromeos/update_observer.h4
-rw-r--r--chrome/browser/chromeos/usb_mount_observer.cc10
-rw-r--r--chrome/browser/chromeos/usb_mount_observer.h3
-rw-r--r--chrome/browser/chromeos/usb_mount_observer_browsertest.cc2
-rw-r--r--chrome/browser/chromeos/version_loader.cc3
-rw-r--r--chrome/browser/chromeos/version_loader.h1
-rw-r--r--chrome/browser/chromeos/view_ids.h2
-rw-r--r--chrome/browser/chromeos/volume_bubble.cc2
-rw-r--r--chrome/browser/chromeos/volume_bubble.h2
-rw-r--r--chrome/browser/chromeos/volume_bubble_view.cc2
-rw-r--r--chrome/browser/chromeos/volume_bubble_view.h1
-rw-r--r--chrome/browser/chromeos/wm_ipc.cc2
-rw-r--r--chrome/browser/chromeos/wm_ipc.h1
-rw-r--r--chrome/browser/chromeos/wm_message_listener.h1
-rw-r--r--chrome/browser/chromeos/wm_overview_controller.cc1
-rw-r--r--chrome/browser/chromeos/wm_overview_controller.h1
-rw-r--r--chrome/browser/chromeos/wm_overview_fav_icon.cc2
-rw-r--r--chrome/browser/chromeos/wm_overview_fav_icon.h1
-rw-r--r--chrome/browser/chromeos/wm_overview_snapshot.h3
-rw-r--r--chrome/browser/chromeos/wm_overview_title.cc5
-rw-r--r--chrome/browser/chromeos/wm_overview_title.h1
-rw-r--r--chrome/browser/clipboard_dispatcher.h2
-rw-r--r--chrome/browser/clipboard_dispatcher_gtk.cc1
-rw-r--r--chrome/browser/clipboard_dispatcher_win.cc1
-rw-r--r--chrome/browser/cocoa/about_ipc_bridge.h1
-rw-r--r--chrome/browser/cocoa/about_ipc_controller.h1
-rw-r--r--chrome/browser/cocoa/about_ipc_controller.mm8
-rw-r--r--chrome/browser/cocoa/about_ipc_controller_unittest.mm8
-rw-r--r--chrome/browser/cocoa/about_ipc_dialog.h1
-rw-r--r--chrome/browser/cocoa/about_window_controller.h1
-rw-r--r--chrome/browser/cocoa/about_window_controller.mm20
-rw-r--r--chrome/browser/cocoa/about_window_controller_unittest.mm25
-rw-r--r--chrome/browser/cocoa/accelerators_cocoa.h1
-rw-r--r--chrome/browser/cocoa/accelerators_cocoa.mm1
-rw-r--r--chrome/browser/cocoa/accelerators_cocoa_unittest.mm3
-rw-r--r--chrome/browser/cocoa/animatable_image.h1
-rw-r--r--chrome/browser/cocoa/animatable_image.mm34
-rw-r--r--chrome/browser/cocoa/animatable_image_unittest.mm10
-rw-r--r--chrome/browser/cocoa/animatable_view.h1
-rw-r--r--chrome/browser/cocoa/authorization_util.h1
-rw-r--r--chrome/browser/cocoa/authorization_util.mm6
-rw-r--r--chrome/browser/cocoa/back_forward_menu_controller.h1
-rw-r--r--chrome/browser/cocoa/background_gradient_view.h1
-rw-r--r--chrome/browser/cocoa/background_gradient_view.mm2
-rw-r--r--chrome/browser/cocoa/background_tile_view.h1
-rw-r--r--chrome/browser/cocoa/base_bubble_controller.h2
-rw-r--r--chrome/browser/cocoa/base_view.h5
-rw-r--r--chrome/browser/cocoa/base_view.mm4
-rw-r--r--chrome/browser/cocoa/base_view_unittest.mm6
-rw-r--r--chrome/browser/cocoa/bookmark_all_tabs_controller.h4
-rw-r--r--chrome/browser/cocoa/bookmark_all_tabs_controller.mm6
-rw-r--r--chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm18
-rw-r--r--chrome/browser/cocoa/bookmark_bar_bridge.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm5
-rw-r--r--chrome/browser/cocoa/bookmark_bar_constants.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.h12
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.mm127
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller_unittest.mm333
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_button_cell.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_controller.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_controller.mm201
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm358
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_view.mm2
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm48
-rw-r--r--chrome/browser/cocoa/bookmark_bar_folder_window.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_state.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_toolbar_view.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_toolbar_view.mm2
-rw-r--r--chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm2
-rw-r--r--chrome/browser/cocoa/bookmark_bar_unittest_helper.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_view.h1
-rw-r--r--chrome/browser/cocoa/bookmark_bar_view.mm4
-rw-r--r--chrome/browser/cocoa/bookmark_bar_view_unittest.mm48
-rw-r--r--chrome/browser/cocoa/bookmark_bubble_controller.h3
-rw-r--r--chrome/browser/cocoa/bookmark_bubble_controller.mm60
-rw-r--r--chrome/browser/cocoa/bookmark_bubble_controller_unittest.mm147
-rw-r--r--chrome/browser/cocoa/bookmark_button.h36
-rw-r--r--chrome/browser/cocoa/bookmark_button.mm73
-rw-r--r--chrome/browser/cocoa/bookmark_button_cell.h1
-rw-r--r--chrome/browser/cocoa/bookmark_button_cell.mm8
-rw-r--r--chrome/browser/cocoa/bookmark_button_cell_unittest.mm7
-rw-r--r--chrome/browser/cocoa/bookmark_button_unittest.mm64
-rw-r--r--chrome/browser/cocoa/bookmark_editor_base_controller.h1
-rw-r--r--chrome/browser/cocoa/bookmark_editor_base_controller.mm4
-rw-r--r--chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm52
-rw-r--r--chrome/browser/cocoa/bookmark_editor_controller.h1
-rw-r--r--chrome/browser/cocoa/bookmark_editor_controller.mm5
-rw-r--r--chrome/browser/cocoa/bookmark_editor_controller_unittest.mm75
-rw-r--r--chrome/browser/cocoa/bookmark_folder_target.h1
-rw-r--r--chrome/browser/cocoa/bookmark_folder_target.mm20
-rw-r--r--chrome/browser/cocoa/bookmark_folder_target_unittest.mm1
-rw-r--r--chrome/browser/cocoa/bookmark_menu_bridge.h1
-rw-r--r--chrome/browser/cocoa/bookmark_menu_bridge.mm6
-rw-r--r--chrome/browser/cocoa/bookmark_menu_bridge_unittest.mm41
-rw-r--r--chrome/browser/cocoa/bookmark_menu_cocoa_controller.h1
-rw-r--r--chrome/browser/cocoa/bookmark_menu_cocoa_controller.mm13
-rw-r--r--chrome/browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm7
-rw-r--r--chrome/browser/cocoa/bookmark_model_observer_for_cocoa.h1
-rw-r--r--chrome/browser/cocoa/bookmark_model_observer_for_cocoa_unittest.mm5
-rw-r--r--chrome/browser/cocoa/bookmark_name_folder_controller.h1
-rw-r--r--chrome/browser/cocoa/bookmark_name_folder_controller.mm8
-rw-r--r--chrome/browser/cocoa/bookmark_name_folder_controller_unittest.mm20
-rw-r--r--chrome/browser/cocoa/bookmark_tree_browser_cell.h1
-rw-r--r--chrome/browser/cocoa/browser_accessibility.h25
-rw-r--r--chrome/browser/cocoa/browser_accessibility.mm152
-rw-r--r--chrome/browser/cocoa/browser_accessibility_delegate.h4
-rw-r--r--chrome/browser/cocoa/browser_accessibility_unittest.mm45
-rw-r--r--chrome/browser/cocoa/browser_command_executor.h1
-rw-r--r--chrome/browser/cocoa/browser_frame_view.mm73
-rw-r--r--chrome/browser/cocoa/browser_test_helper.h14
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.h9
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.mm61
-rw-r--r--chrome/browser/cocoa/browser_window_controller.h28
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm209
-rw-r--r--chrome/browser/cocoa/browser_window_controller_private.h1
-rw-r--r--chrome/browser/cocoa/browser_window_controller_private.mm37
-rw-r--r--chrome/browser/cocoa/browser_window_controller_unittest.mm46
-rw-r--r--chrome/browser/cocoa/browser_window_factory.mm4
-rw-r--r--chrome/browser/cocoa/bubble_view.mm2
-rw-r--r--chrome/browser/cocoa/bubble_view_unittest.mm5
-rw-r--r--chrome/browser/cocoa/bug_report_window_controller.h1
-rw-r--r--chrome/browser/cocoa/bug_report_window_controller.mm1
-rw-r--r--chrome/browser/cocoa/bug_report_window_controller_unittest.mm7
-rw-r--r--chrome/browser/cocoa/chrome_browser_window.h56
-rw-r--r--chrome/browser/cocoa/chrome_browser_window.mm347
-rw-r--r--chrome/browser/cocoa/chrome_browser_window_unittest.mm137
-rw-r--r--chrome/browser/cocoa/chrome_event_processing_window.h1
-rw-r--r--chrome/browser/cocoa/chrome_event_processing_window_unittest.mm13
-rw-r--r--chrome/browser/cocoa/clear_browsing_data_controller.h1
-rw-r--r--chrome/browser/cocoa/clear_browsing_data_controller.mm2
-rw-r--r--chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm2
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell.h1
-rw-r--r--chrome/browser/cocoa/cocoa_test_helper.h71
-rw-r--r--chrome/browser/cocoa/collected_cookies_mac.h12
-rw-r--r--chrome/browser/cocoa/collected_cookies_mac.mm213
-rw-r--r--chrome/browser/cocoa/collected_cookies_mac_unittest.mm1
-rw-r--r--chrome/browser/cocoa/command_observer_bridge.h1
-rw-r--r--chrome/browser/cocoa/constrained_window_mac.h11
-rw-r--r--chrome/browser/cocoa/constrained_window_mac.mm18
-rw-r--r--chrome/browser/cocoa/content_blocked_bubble_controller.h59
-rw-r--r--chrome/browser/cocoa/content_blocked_bubble_controller.mm412
-rw-r--r--chrome/browser/cocoa/content_blocked_bubble_controller_unittest.mm62
-rw-r--r--chrome/browser/cocoa/content_exceptions_window_controller.h2
-rw-r--r--chrome/browser/cocoa/content_exceptions_window_controller.mm7
-rw-r--r--chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm10
-rw-r--r--chrome/browser/cocoa/content_settings_dialog_controller.h29
-rw-r--r--chrome/browser/cocoa/content_settings_dialog_controller.mm90
-rw-r--r--chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm26
-rw-r--r--chrome/browser/cocoa/cookie_details.h61
-rw-r--r--chrome/browser/cocoa/cookie_details.mm107
-rw-r--r--chrome/browser/cocoa/cookie_details_unittest.mm106
-rw-r--r--chrome/browser/cocoa/cookie_details_view_controller.h2
-rw-r--r--chrome/browser/cocoa/cookie_details_view_controller.mm1
-rw-r--r--chrome/browser/cocoa/cookie_details_view_controller_unittest.mm1
-rw-r--r--chrome/browser/cocoa/cookie_prompt_window_controller.h66
-rw-r--r--chrome/browser/cocoa/cookie_prompt_window_controller.mm215
-rw-r--r--chrome/browser/cocoa/cookie_prompt_window_controller_unittest.mm240
-rw-r--r--chrome/browser/cocoa/cookie_tree_node.mm2
-rw-r--r--chrome/browser/cocoa/cookies_window_controller.h19
-rw-r--r--chrome/browser/cocoa/cookies_window_controller.mm40
-rw-r--r--chrome/browser/cocoa/cookies_window_controller_unittest.mm145
-rw-r--r--chrome/browser/cocoa/custom_home_pages_model.h32
-rw-r--r--chrome/browser/cocoa/custom_home_pages_model.mm40
-rw-r--r--chrome/browser/cocoa/custom_home_pages_model_unittest.mm85
-rw-r--r--chrome/browser/cocoa/delayedmenu_button.h1
-rw-r--r--chrome/browser/cocoa/download_item_cell.h1
-rw-r--r--chrome/browser/cocoa/download_item_cell.mm14
-rw-r--r--chrome/browser/cocoa/download_item_controller.mm24
-rw-r--r--chrome/browser/cocoa/download_item_mac.h1
-rw-r--r--chrome/browser/cocoa/download_shelf_controller.mm6
-rw-r--r--chrome/browser/cocoa/download_shelf_mac.h6
-rw-r--r--chrome/browser/cocoa/download_shelf_view.h1
-rw-r--r--chrome/browser/cocoa/download_shelf_view.mm2
-rw-r--r--chrome/browser/cocoa/download_started_animation_mac.mm26
-rw-r--r--chrome/browser/cocoa/download_util_mac.h10
-rw-r--r--chrome/browser/cocoa/download_util_mac_unittest.mm11
-rw-r--r--chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm12
-rw-r--r--chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm34
-rw-r--r--chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h1
-rw-r--r--chrome/browser/cocoa/event_utils.h1
-rw-r--r--chrome/browser/cocoa/extension_install_prompt.mm5
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_bridge.h1
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller.h1
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller.mm1
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm1
-rw-r--r--chrome/browser/cocoa/extension_view_mac.h1
-rw-r--r--chrome/browser/cocoa/extensions/browser_action_button.h10
-rw-r--r--chrome/browser/cocoa/extensions/browser_action_button.mm22
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_container_view.h1
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_container_view.mm27
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.h4
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.mm123
-rw-r--r--chrome/browser/cocoa/extensions/extension_action_context_menu.h1
-rw-r--r--chrome/browser/cocoa/extensions/extension_action_context_menu.mm28
-rw-r--r--chrome/browser/cocoa/extensions/extension_infobar_controller.h1
-rw-r--r--chrome/browser/cocoa/extensions/extension_infobar_controller.mm11
-rw-r--r--chrome/browser/cocoa/extensions/extension_install_prompt_controller.h3
-rw-r--r--chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm2
-rw-r--r--chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm23
-rw-r--r--chrome/browser/cocoa/extensions/extension_popup_controller.h1
-rw-r--r--chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm5
-rw-r--r--chrome/browser/cocoa/external_protocol_dialog.mm8
-rw-r--r--chrome/browser/cocoa/fast_resize_view.h1
-rw-r--r--chrome/browser/cocoa/file_metadata.h1
-rw-r--r--chrome/browser/cocoa/find_bar_bridge.h1
-rw-r--r--chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm13
-rw-r--r--chrome/browser/cocoa/find_bar_text_field.mm10
-rw-r--r--chrome/browser/cocoa/find_bar_text_field_cell.mm16
-rw-r--r--chrome/browser/cocoa/find_bar_view.h1
-rw-r--r--chrome/browser/cocoa/find_bar_view.mm11
-rw-r--r--chrome/browser/cocoa/find_pasteboard.h1
-rw-r--r--chrome/browser/cocoa/first_run_bubble_controller.mm22
-rw-r--r--chrome/browser/cocoa/first_run_dialog.h16
-rw-r--r--chrome/browser/cocoa/first_run_dialog.mm97
-rw-r--r--chrome/browser/cocoa/floating_bar_backing_view.h1
-rw-r--r--chrome/browser/cocoa/focus_tracker.mm4
-rw-r--r--chrome/browser/cocoa/font_language_settings_controller.h2
-rw-r--r--chrome/browser/cocoa/font_language_settings_controller.mm2
-rw-r--r--chrome/browser/cocoa/font_language_settings_controller_unittest.mm7
-rw-r--r--chrome/browser/cocoa/fullscreen_controller.h5
-rw-r--r--chrome/browser/cocoa/fullscreen_controller.mm13
-rw-r--r--chrome/browser/cocoa/fullscreen_window.h14
-rw-r--r--chrome/browser/cocoa/fullscreen_window.mm23
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.h39
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.mm331
-rw-r--r--chrome/browser/cocoa/gradient_button_cell_unittest.mm36
-rw-r--r--chrome/browser/cocoa/history_menu_bridge.h25
-rw-r--r--chrome/browser/cocoa/history_menu_bridge.mm20
-rw-r--r--chrome/browser/cocoa/history_menu_bridge_unittest.mm36
-rw-r--r--chrome/browser/cocoa/history_menu_cocoa_controller.h1
-rw-r--r--chrome/browser/cocoa/hover_close_button.h25
-rw-r--r--chrome/browser/cocoa/hover_close_button.mm78
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller.h6
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller.mm11
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h1
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller_unittest.mm6
-rw-r--r--chrome/browser/cocoa/hung_renderer_controller.h5
-rw-r--r--chrome/browser/cocoa/image_utils.h1
-rw-r--r--chrome/browser/cocoa/image_utils_unittest.mm6
-rw-r--r--chrome/browser/cocoa/import_progress_dialog.h1
-rw-r--r--chrome/browser/cocoa/import_progress_dialog.mm1
-rw-r--r--chrome/browser/cocoa/import_settings_dialog.h4
-rw-r--r--chrome/browser/cocoa/importer_lock_dialog.h1
-rw-r--r--chrome/browser/cocoa/info_bubble_view.h6
-rw-r--r--chrome/browser/cocoa/info_bubble_view.mm2
-rw-r--r--chrome/browser/cocoa/infobar.h1
-rw-r--r--chrome/browser/cocoa/infobar_container_controller.h26
-rw-r--r--chrome/browser/cocoa/infobar_container_controller.mm66
-rw-r--r--chrome/browser/cocoa/infobar_container_controller_unittest.mm6
-rw-r--r--chrome/browser/cocoa/infobar_controller.mm23
-rw-r--r--chrome/browser/cocoa/infobar_controller_unittest.mm8
-rw-r--r--chrome/browser/cocoa/infobar_gradient_view.h1
-rw-r--r--chrome/browser/cocoa/infobar_gradient_view.mm2
-rw-r--r--chrome/browser/cocoa/infobar_test_helper.h36
-rw-r--r--chrome/browser/cocoa/install_from_dmg.h1
-rw-r--r--chrome/browser/cocoa/install_from_dmg.mm1
-rw-r--r--chrome/browser/cocoa/keystone_glue.h1
-rw-r--r--chrome/browser/cocoa/keystone_glue.mm1
-rw-r--r--chrome/browser/cocoa/keystone_infobar.h1
-rw-r--r--chrome/browser/cocoa/keystone_infobar.mm16
-rw-r--r--chrome/browser/cocoa/keyword_editor_cocoa_controller.h7
-rw-r--r--chrome/browser/cocoa/keyword_editor_cocoa_controller.mm11
-rw-r--r--chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm2
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field.h4
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field.mm23
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm7
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm38
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm18
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm13
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h1
-rw-r--r--chrome/browser/cocoa/location_bar/bubble_decoration.h5
-rw-r--r--chrome/browser/cocoa/location_bar/bubble_decoration.mm66
-rw-r--r--chrome/browser/cocoa/location_bar/content_setting_decoration.h9
-rw-r--r--chrome/browser/cocoa/location_bar/content_setting_decoration.mm35
-rw-r--r--chrome/browser/cocoa/location_bar/ev_bubble_decoration.h12
-rw-r--r--chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm54
-rw-r--r--chrome/browser/cocoa/location_bar/image_decoration.h1
-rw-r--r--chrome/browser/cocoa/location_bar/image_decoration.mm5
-rw-r--r--chrome/browser/cocoa/location_bar/keyword_hint_decoration.h1
-rw-r--r--chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm68
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_decoration.h1
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_view_mac.h20
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_view_mac.mm63
-rw-r--r--chrome/browser/cocoa/location_bar/location_icon_decoration.h1
-rw-r--r--chrome/browser/cocoa/location_bar/page_action_decoration.h6
-rw-r--r--chrome/browser/cocoa/location_bar/page_action_decoration.mm81
-rw-r--r--chrome/browser/cocoa/location_bar/selected_keyword_decoration.h1
-rw-r--r--chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm4
-rw-r--r--chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm9
-rw-r--r--chrome/browser/cocoa/location_bar/star_decoration.h1
-rw-r--r--chrome/browser/cocoa/location_bar/star_decoration.mm7
-rw-r--r--chrome/browser/cocoa/menu_button.h1
-rw-r--r--chrome/browser/cocoa/menu_controller.h2
-rw-r--r--chrome/browser/cocoa/menu_controller.mm1
-rw-r--r--chrome/browser/cocoa/menu_controller_unittest.mm52
-rw-r--r--chrome/browser/cocoa/multi_key_equivalent_button.h1
-rw-r--r--chrome/browser/cocoa/notifications/balloon_controller.h10
-rw-r--r--chrome/browser/cocoa/notifications/balloon_controller.mm101
-rw-r--r--chrome/browser/cocoa/notifications/balloon_controller_unittest.mm38
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view.h1
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view.mm21
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view_bridge.h1
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view_bridge.mm2
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view_host_mac.h1
-rw-r--r--chrome/browser/cocoa/nsmenuitem_additions.h1
-rw-r--r--chrome/browser/cocoa/objc_method_swizzle.h1
-rw-r--r--chrome/browser/cocoa/objc_zombie.h1
-rw-r--r--chrome/browser/cocoa/page_info_window_controller.mm6
-rw-r--r--chrome/browser/cocoa/page_info_window_mac.h11
-rw-r--r--chrome/browser/cocoa/page_info_window_mac.mm75
-rw-r--r--chrome/browser/cocoa/page_info_window_mac_unittest.mm47
-rw-r--r--chrome/browser/cocoa/popup_blocked_animation_mac.mm43
-rw-r--r--chrome/browser/cocoa/preferences_window_controller.h45
-rw-r--r--chrome/browser/cocoa/preferences_window_controller.mm281
-rw-r--r--chrome/browser/cocoa/preferences_window_controller_unittest.mm20
-rw-r--r--chrome/browser/cocoa/reload_button.h1
-rw-r--r--chrome/browser/cocoa/reload_button.mm14
-rw-r--r--chrome/browser/cocoa/reload_button_unittest.mm11
-rw-r--r--chrome/browser/cocoa/repost_form_warning_mac.h1
-rw-r--r--chrome/browser/cocoa/restart_browser.h1
-rw-r--r--chrome/browser/cocoa/restart_browser.mm3
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper.h7
-rw-r--r--chrome/browser/cocoa/sad_tab_controller.h1
-rw-r--r--chrome/browser/cocoa/sad_tab_controller_unittest.mm2
-rw-r--r--chrome/browser/cocoa/sad_tab_view.h1
-rw-r--r--chrome/browser/cocoa/scoped_authorizationref.h1
-rw-r--r--chrome/browser/cocoa/search_engine_list_model.h1
-rw-r--r--chrome/browser/cocoa/search_engine_list_model.mm1
-rw-r--r--chrome/browser/cocoa/search_engine_list_model_unittest.mm3
-rw-r--r--chrome/browser/cocoa/shell_dialogs_mac.mm26
-rw-r--r--chrome/browser/cocoa/side_tab_strip_controller.mm8
-rw-r--r--chrome/browser/cocoa/simple_content_exceptions_window_controller.h12
-rw-r--r--chrome/browser/cocoa/simple_content_exceptions_window_controller.mm112
-rw-r--r--chrome/browser/cocoa/simple_content_exceptions_window_controller_unittest.mm44
-rw-r--r--chrome/browser/cocoa/ssl_client_certificate_selector.mm129
-rw-r--r--chrome/browser/cocoa/status_bubble_mac.h43
-rw-r--r--chrome/browser/cocoa/status_bubble_mac.mm201
-rw-r--r--chrome/browser/cocoa/status_bubble_mac_unittest.mm254
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.h5
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.mm5
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm1
-rw-r--r--chrome/browser/cocoa/status_icons/status_tray_mac.h3
-rw-r--r--chrome/browser/cocoa/status_icons/status_tray_mac.mm2
-rw-r--r--chrome/browser/cocoa/styled_text_field_cell.h9
-rw-r--r--chrome/browser/cocoa/styled_text_field_cell.mm63
-rw-r--r--chrome/browser/cocoa/tab_contents_controller.h31
-rw-r--r--chrome/browser/cocoa/tab_contents_controller.mm119
-rw-r--r--chrome/browser/cocoa/tab_controller.h1
-rw-r--r--chrome/browser/cocoa/tab_controller.mm2
-rw-r--r--chrome/browser/cocoa/tab_controller_target.h1
-rw-r--r--chrome/browser/cocoa/tab_controller_unittest.mm3
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.h37
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.mm139
-rw-r--r--chrome/browser/cocoa/tab_strip_controller_unittest.mm33
-rw-r--r--chrome/browser/cocoa/tab_strip_model_observer_bridge.h6
-rw-r--r--chrome/browser/cocoa/tab_strip_model_observer_bridge.mm7
-rw-r--r--chrome/browser/cocoa/tab_strip_view.h7
-rw-r--r--chrome/browser/cocoa/tab_strip_view.mm16
-rw-r--r--chrome/browser/cocoa/tab_view.h1
-rw-r--r--chrome/browser/cocoa/tab_view.mm17
-rw-r--r--chrome/browser/cocoa/tab_view_picker_table_unittest.mm17
-rw-r--r--chrome/browser/cocoa/tab_window_controller.h9
-rw-r--r--chrome/browser/cocoa/tab_window_controller.mm11
-rw-r--r--chrome/browser/cocoa/table_row_nsimage_cache.h25
-rw-r--r--chrome/browser/cocoa/table_row_nsimage_cache.mm1
-rw-r--r--chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm1
-rw-r--r--chrome/browser/cocoa/task_manager_mac.h33
-rw-r--r--chrome/browser/cocoa/task_manager_mac.mm208
-rw-r--r--chrome/browser/cocoa/task_manager_mac_unittest.mm105
-rw-r--r--chrome/browser/cocoa/test_event_utils.h9
-rw-r--r--chrome/browser/cocoa/theme_install_bubble_view.h1
-rw-r--r--chrome/browser/cocoa/themed_window.h1
-rw-r--r--chrome/browser/cocoa/throbber_view.h2
-rw-r--r--chrome/browser/cocoa/toolbar_controller.h8
-rw-r--r--chrome/browser/cocoa/toolbar_controller.mm74
-rw-r--r--chrome/browser/cocoa/toolbar_controller_unittest.mm7
-rw-r--r--chrome/browser/cocoa/toolbar_view.h1
-rw-r--r--chrome/browser/cocoa/translate/before_translate_infobar_controller.mm2
-rw-r--r--chrome/browser/cocoa/translate/translate_infobar_base.h14
-rw-r--r--chrome/browser/cocoa/translate/translate_infobar_base.mm50
-rw-r--r--chrome/browser/cocoa/translate/translate_infobar_unittest.mm20
-rw-r--r--chrome/browser/cocoa/translate/translate_message_infobar_controller.h3
-rw-r--r--chrome/browser/cocoa/translate/translate_message_infobar_controller.mm29
-rw-r--r--chrome/browser/cocoa/ui_localizer.h1
-rw-r--r--chrome/browser/cocoa/ui_localizer.mm1
-rw-r--r--chrome/browser/cocoa/url_drop_target.h4
-rw-r--r--chrome/browser/cocoa/url_drop_target.mm22
-rw-r--r--chrome/browser/cocoa/vertical_gradient_view.h1
-rw-r--r--chrome/browser/cocoa/view_id_util.h1
-rw-r--r--chrome/browser/cocoa/view_id_util_browsertest.mm27
-rw-r--r--chrome/browser/cocoa/view_resizer.h1
-rw-r--r--chrome/browser/cocoa/view_resizer_pong.h1
-rw-r--r--chrome/browser/cocoa/web_contents_drag_source.h7
-rw-r--r--chrome/browser/cocoa/web_contents_drag_source.mm1
-rw-r--r--chrome/browser/cocoa/web_drag_source.h1
-rw-r--r--chrome/browser/cocoa/web_drag_source.mm11
-rw-r--r--chrome/browser/cocoa/web_drop_target_unittest.mm1
-rw-r--r--chrome/browser/cocoa/window_size_autosaver.h16
-rw-r--r--chrome/browser/cocoa/window_size_autosaver.mm50
-rw-r--r--chrome/browser/cocoa/window_size_autosaver_unittest.mm76
-rw-r--r--chrome/browser/cocoa/wrench_menu_controller.h34
-rw-r--r--chrome/browser/cocoa/wrench_menu_controller.mm142
-rw-r--r--chrome/browser/cocoa/wrench_menu_controller_unittest.mm38
-rw-r--r--chrome/browser/collected_cookies_uitest.cc22
-rw-r--r--chrome/browser/command_updater.h1
-rw-r--r--chrome/browser/config_dir_policy_provider.cc75
-rw-r--r--chrome/browser/config_dir_policy_provider.h42
-rw-r--r--chrome/browser/config_dir_policy_provider_unittest.cc115
-rw-r--r--chrome/browser/configuration_policy_pref_store.cc312
-rw-r--r--chrome/browser/configuration_policy_pref_store.h100
-rw-r--r--chrome/browser/configuration_policy_pref_store_unittest.cc469
-rw-r--r--chrome/browser/configuration_policy_provider.cc71
-rw-r--r--chrome/browser/configuration_policy_provider.h50
-rw-r--r--chrome/browser/configuration_policy_provider_mac.cc78
-rw-r--r--chrome/browser/configuration_policy_provider_mac.h30
-rw-r--r--chrome/browser/configuration_policy_provider_mac_unittest.cc119
-rw-r--r--chrome/browser/configuration_policy_provider_win.cc137
-rw-r--r--chrome/browser/configuration_policy_provider_win.h39
-rw-r--r--chrome/browser/configuration_policy_provider_win_unittest.cc315
-rw-r--r--chrome/browser/configuration_policy_store.h54
-rw-r--r--chrome/browser/content_exceptions_table_model.cc16
-rw-r--r--chrome/browser/content_exceptions_table_model.h6
-rw-r--r--chrome/browser/content_exceptions_table_model_unittest.cc34
-rw-r--r--chrome/browser/content_setting_bubble_model.cc183
-rw-r--r--chrome/browser/content_setting_bubble_model.h12
-rw-r--r--chrome/browser/content_setting_bubble_model_unittest.cc29
-rw-r--r--chrome/browser/content_setting_combo_model.cc17
-rw-r--r--chrome/browser/content_setting_combo_model.h5
-rw-r--r--chrome/browser/content_setting_image_model.cc60
-rw-r--r--chrome/browser/content_setting_image_model.h3
-rw-r--r--chrome/browser/content_setting_image_model_unittest.cc41
-rw-r--r--chrome/browser/cookie_modal_dialog.cc148
-rw-r--r--chrome/browser/cookie_modal_dialog.h154
-rw-r--r--chrome/browser/cookie_modal_dialog_gtk.cc155
-rw-r--r--chrome/browser/cookie_modal_dialog_mac.mm48
-rw-r--r--chrome/browser/cookie_modal_dialog_uitest.cc65
-rw-r--r--chrome/browser/cookie_modal_dialog_views.cc41
-rw-r--r--chrome/browser/cookie_prompt_modal_dialog_delegate.h25
-rw-r--r--chrome/browser/cookies_tree_model.cc195
-rw-r--r--chrome/browser/cookies_tree_model.h232
-rw-r--r--chrome/browser/cookies_tree_model_unittest.cc230
-rw-r--r--chrome/browser/crash_handler_host_linux.cc138
-rw-r--r--chrome/browser/crash_handler_host_linux.h52
-rw-r--r--chrome/browser/crash_handler_host_linux_stub.cc14
-rw-r--r--chrome/browser/crash_recovery_browsertest.cc4
-rw-r--r--chrome/browser/cross_site_request_manager.h1
-rw-r--r--chrome/browser/custom_home_pages_table_model.cc62
-rw-r--r--chrome/browser/custom_home_pages_table_model.h30
-rw-r--r--chrome/browser/debugger/debugger_host.h1
-rw-r--r--chrome/browser/debugger/debugger_remote_service.cc100
-rw-r--r--chrome/browser/debugger/debugger_remote_service.h1
-rw-r--r--chrome/browser/debugger/debugger_wrapper.h5
-rw-r--r--chrome/browser/debugger/devtools_client_host.h1
-rw-r--r--chrome/browser/debugger/devtools_http_protocol_handler.cc312
-rw-r--r--chrome/browser/debugger/devtools_http_protocol_handler.h45
-rw-r--r--chrome/browser/debugger/devtools_manager.cc61
-rw-r--r--chrome/browser/debugger/devtools_manager.h23
-rw-r--r--chrome/browser/debugger/devtools_protocol_handler.h1
-rw-r--r--chrome/browser/debugger/devtools_remote.h1
-rw-r--r--chrome/browser/debugger/devtools_remote_listen_socket.cc5
-rw-r--r--chrome/browser/debugger/devtools_remote_listen_socket.h1
-rw-r--r--chrome/browser/debugger/devtools_remote_listen_socket_unittest.h4
-rw-r--r--chrome/browser/debugger/devtools_remote_message.cc7
-rw-r--r--chrome/browser/debugger/devtools_remote_message.h1
-rw-r--r--chrome/browser/debugger/devtools_remote_message_unittest.cc16
-rw-r--r--chrome/browser/debugger/devtools_remote_service.cc37
-rw-r--r--chrome/browser/debugger/devtools_remote_service.h16
-rw-r--r--chrome/browser/debugger/devtools_sanity_unittest.cc148
-rw-r--r--chrome/browser/debugger/devtools_toggle_action.h1
-rw-r--r--chrome/browser/debugger/devtools_window.cc74
-rw-r--r--chrome/browser/debugger/devtools_window.h14
-rw-r--r--chrome/browser/debugger/extension_ports_remote_service.cc97
-rw-r--r--chrome/browser/debugger/extension_ports_remote_service.h1
-rw-r--r--chrome/browser/debugger/inspectable_tab_proxy.cc28
-rw-r--r--chrome/browser/debugger/inspectable_tab_proxy.h4
-rw-r--r--chrome/browser/default_encoding_combo_model.cc14
-rw-r--r--chrome/browser/default_encoding_combo_model.h9
-rw-r--r--chrome/browser/defaults.cc11
-rw-r--r--chrome/browser/defaults.h10
-rw-r--r--chrome/browser/diagnostics/diagnostics_main.cc12
-rw-r--r--chrome/browser/diagnostics/diagnostics_main.h1
-rw-r--r--chrome/browser/diagnostics/diagnostics_model.h1
-rw-r--r--chrome/browser/diagnostics/diagnostics_test.h1
-rw-r--r--chrome/browser/diagnostics/recon_diagnostics.cc30
-rw-r--r--chrome/browser/diagnostics/recon_diagnostics.h4
-rw-r--r--chrome/browser/diagnostics/sqlite_diagnostics.cc10
-rw-r--r--chrome/browser/diagnostics/sqlite_diagnostics.h1
-rw-r--r--chrome/browser/dock_info.h1
-rw-r--r--chrome/browser/dock_info_mac.cc2
-rw-r--r--chrome/browser/dock_info_win.cc19
-rw-r--r--chrome/browser/dom_operation_notification_details.h1
-rw-r--r--chrome/browser/dom_ui/advanced_options_handler.cc423
-rw-r--r--chrome/browser/dom_ui/advanced_options_handler.h57
-rw-r--r--chrome/browser/dom_ui/advanced_options_utils_mac.h23
-rw-r--r--chrome/browser/dom_ui/advanced_options_utils_mac.mm19
-rw-r--r--chrome/browser/dom_ui/app_launcher_handler.cc195
-rw-r--r--chrome/browser/dom_ui/app_launcher_handler.h44
-rw-r--r--chrome/browser/dom_ui/bookmarks_ui.h1
-rw-r--r--chrome/browser/dom_ui/browser_options_handler.cc246
-rw-r--r--chrome/browser/dom_ui/browser_options_handler.h46
-rw-r--r--chrome/browser/dom_ui/chrome_url_data_manager.cc21
-rw-r--r--chrome/browser/dom_ui/chrome_url_data_manager.h24
-rw-r--r--chrome/browser/dom_ui/clear_browser_data_handler.cc112
-rw-r--r--chrome/browser/dom_ui/clear_browser_data_handler.h20
-rw-r--r--chrome/browser/dom_ui/content_settings_handler.cc540
-rw-r--r--chrome/browser/dom_ui/content_settings_handler.h32
-rw-r--r--chrome/browser/dom_ui/core_options_handler.cc246
-rw-r--r--chrome/browser/dom_ui/core_options_handler.h50
-rw-r--r--chrome/browser/dom_ui/devtools_ui.cc1
-rw-r--r--chrome/browser/dom_ui/devtools_ui.h1
-rw-r--r--chrome/browser/dom_ui/dom_ui.cc115
-rw-r--r--chrome/browser/dom_ui/dom_ui.h36
-rw-r--r--chrome/browser/dom_ui/dom_ui_factory.cc71
-rw-r--r--chrome/browser/dom_ui/dom_ui_factory.h9
-rw-r--r--chrome/browser/dom_ui/dom_ui_favicon_source.cc33
-rw-r--r--chrome/browser/dom_ui/dom_ui_favicon_source.h16
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source.cc8
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source.h6
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc3
-rw-r--r--chrome/browser/dom_ui/dom_ui_thumbnail_source.cc19
-rw-r--r--chrome/browser/dom_ui/dom_ui_thumbnail_source.h19
-rw-r--r--chrome/browser/dom_ui/dom_ui_unittest.cc6
-rw-r--r--chrome/browser/dom_ui/dom_ui_util.cc45
-rw-r--r--chrome/browser/dom_ui/dom_ui_util.h21
-rw-r--r--chrome/browser/dom_ui/downloads_dom_handler.cc69
-rw-r--r--chrome/browser/dom_ui/downloads_dom_handler.h29
-rw-r--r--chrome/browser/dom_ui/downloads_ui.cc64
-rw-r--r--chrome/browser/dom_ui/downloads_ui.h1
-rw-r--r--chrome/browser/dom_ui/file_browse_browsertest.cc8
-rw-r--r--chrome/browser/dom_ui/filebrowse_ui.cc672
-rw-r--r--chrome/browser/dom_ui/filebrowse_ui.h10
-rw-r--r--chrome/browser/dom_ui/fileicon_source.cc4
-rw-r--r--chrome/browser/dom_ui/fileicon_source.h3
-rw-r--r--chrome/browser/dom_ui/font_settings_handler.cc137
-rw-r--r--chrome/browser/dom_ui/font_settings_handler.h23
-rw-r--r--chrome/browser/dom_ui/history2_ui.cc180
-rw-r--r--chrome/browser/dom_ui/history2_ui.h12
-rw-r--r--chrome/browser/dom_ui/history_ui.cc172
-rw-r--r--chrome/browser/dom_ui/history_ui.h12
-rw-r--r--chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc14
-rw-r--r--chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h8
-rw-r--r--chrome/browser/dom_ui/html_dialog_tab_contents_delegate_unittest.cc12
-rw-r--r--chrome/browser/dom_ui/html_dialog_ui.cc7
-rw-r--r--chrome/browser/dom_ui/html_dialog_ui.h5
-rw-r--r--chrome/browser/dom_ui/mediaplayer_browsertest.cc11
-rw-r--r--chrome/browser/dom_ui/mediaplayer_ui.cc138
-rw-r--r--chrome/browser/dom_ui/mediaplayer_ui.h7
-rw-r--r--chrome/browser/dom_ui/most_visited_handler.cc309
-rw-r--r--chrome/browser/dom_ui/most_visited_handler.h46
-rw-r--r--chrome/browser/dom_ui/net_internals_ui.cc324
-rw-r--r--chrome/browser/dom_ui/net_internals_ui.h1
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.cc48
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.h7
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc235
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.h37
-rw-r--r--chrome/browser/dom_ui/new_tab_ui_uitest.cc81
-rw-r--r--chrome/browser/dom_ui/ntp_resource_cache.cc247
-rw-r--r--chrome/browser/dom_ui/ntp_resource_cache.h10
-rw-r--r--chrome/browser/dom_ui/options_ui.cc99
-rw-r--r--chrome/browser/dom_ui/options_ui.h11
-rw-r--r--chrome/browser/dom_ui/options_ui_uitest.cc17
-rw-r--r--chrome/browser/dom_ui/personal_options_handler.cc210
-rw-r--r--chrome/browser/dom_ui/personal_options_handler.h23
-rw-r--r--chrome/browser/dom_ui/plugins_ui.cc160
-rw-r--r--chrome/browser/dom_ui/plugins_ui.h1
-rw-r--r--chrome/browser/dom_ui/register_page_ui.cc251
-rw-r--r--chrome/browser/dom_ui/register_page_ui.h20
-rw-r--r--chrome/browser/dom_ui/remoting_ui.h1
-rw-r--r--chrome/browser/dom_ui/shared_resources_data_source.h1
-rw-r--r--chrome/browser/dom_ui/shown_sections_handler.cc68
-rw-r--r--chrome/browser/dom_ui/shown_sections_handler.h22
-rw-r--r--chrome/browser/dom_ui/shown_sections_handler_unittest.cc40
-rw-r--r--chrome/browser/dom_ui/slideshow_ui.cc87
-rw-r--r--chrome/browser/dom_ui/slideshow_ui.h6
-rw-r--r--chrome/browser/dom_ui/tips_handler.cc35
-rw-r--r--chrome/browser/dom_ui/tips_handler.h10
-rw-r--r--chrome/browser/download/download_exe.cc60
-rw-r--r--chrome/browser/download/download_file.cc184
-rw-r--r--chrome/browser/download/download_file.h67
-rw-r--r--chrome/browser/download/download_file_manager.cc362
-rw-r--r--chrome/browser/download/download_file_manager.h65
-rw-r--r--chrome/browser/download/download_item.cc298
-rw-r--r--chrome/browser/download/download_item.h101
-rw-r--r--chrome/browser/download/download_item_model.cc32
-rw-r--r--chrome/browser/download/download_item_model.h1
-rw-r--r--chrome/browser/download/download_manager.cc1002
-rw-r--r--chrome/browser/download/download_manager.h240
-rw-r--r--chrome/browser/download/download_manager_unittest.cc614
-rw-r--r--chrome/browser/download/download_request_infobar_delegate.cc10
-rw-r--r--chrome/browser/download/download_request_infobar_delegate.h5
-rw-r--r--chrome/browser/download/download_request_limiter.h1
-rw-r--r--chrome/browser/download/download_request_limiter_unittest.cc3
-rw-r--r--chrome/browser/download/download_shelf.cc19
-rw-r--r--chrome/browser/download/download_shelf.h9
-rw-r--r--chrome/browser/download/download_started_animation.h1
-rw-r--r--chrome/browser/download/download_types.h9
-rw-r--r--chrome/browser/download/download_uitest.cc101
-rw-r--r--chrome/browser/download/download_util.cc315
-rw-r--r--chrome/browser/download/download_util.h52
-rw-r--r--chrome/browser/download/drag_download_file.cc16
-rw-r--r--chrome/browser/download/drag_download_file.h2
-rw-r--r--chrome/browser/download/drag_download_util.cc5
-rw-r--r--chrome/browser/download/drag_download_util.h1
-rw-r--r--chrome/browser/download/save_file.cc100
-rw-r--r--chrome/browser/download/save_file.h48
-rw-r--r--chrome/browser/download/save_file_manager.cc6
-rw-r--r--chrome/browser/download/save_file_manager.h5
-rw-r--r--chrome/browser/download/save_item.h1
-rw-r--r--chrome/browser/download/save_package.cc116
-rw-r--r--chrome/browser/download/save_package.h14
-rw-r--r--chrome/browser/download/save_package_unittest.cc76
-rw-r--r--chrome/browser/download/save_page_browsertest.cc2
-rw-r--r--chrome/browser/download/save_types.h1
-rw-r--r--chrome/browser/dummy_configuration_policy_provider.h25
-rw-r--r--chrome/browser/encoding_menu_controller.cc2
-rw-r--r--chrome/browser/encoding_menu_controller.h4
-rw-r--r--chrome/browser/encoding_menu_controller_unittest.cc1
-rw-r--r--chrome/browser/errorpage_uitest.cc12
-rw-r--r--chrome/browser/extensions/app_background_page_apitest.cc5
-rw-r--r--chrome/browser/extensions/app_process_apitest.cc95
-rw-r--r--chrome/browser/extensions/autoupdate_interceptor.h1
-rw-r--r--chrome/browser/extensions/browser_action_apitest.cc4
-rw-r--r--chrome/browser/extensions/browser_action_test_util.h1
-rw-r--r--chrome/browser/extensions/browser_action_test_util_gtk.cc6
-rw-r--r--chrome/browser/extensions/browser_action_test_util_views.cc4
-rw-r--r--chrome/browser/extensions/content_script_all_frames_apitest.cc4
-rw-r--r--chrome/browser/extensions/content_script_extension_process_apitest.cc2
-rw-r--r--chrome/browser/extensions/convert_user_script.cc2
-rw-r--r--chrome/browser/extensions/convert_user_script.h1
-rw-r--r--chrome/browser/extensions/crashed_extension_infobar.cc19
-rw-r--r--chrome/browser/extensions/crashed_extension_infobar.h9
-rw-r--r--chrome/browser/extensions/cross_origin_xhr_apitest.cc2
-rw-r--r--chrome/browser/extensions/crx_installer.cc93
-rw-r--r--chrome/browser/extensions/crx_installer.h29
-rw-r--r--chrome/browser/extensions/execute_code_in_tab_function.cc13
-rw-r--r--chrome/browser/extensions/execute_code_in_tab_function.h13
-rw-r--r--chrome/browser/extensions/execute_script_apitest.cc4
-rw-r--r--chrome/browser/extensions/extension_accessibility_api.cc3
-rw-r--r--chrome/browser/extensions/extension_accessibility_api.h4
-rw-r--r--chrome/browser/extensions/extension_accessibility_api_constants.cc22
-rw-r--r--chrome/browser/extensions/extension_accessibility_api_constants.h23
-rw-r--r--chrome/browser/extensions/extension_apitest.cc90
-rw-r--r--chrome/browser/extensions/extension_apitest.h34
-rw-r--r--chrome/browser/extensions/extension_bookmark_helpers.cc8
-rw-r--r--chrome/browser/extensions/extension_bookmark_helpers.h19
-rw-r--r--chrome/browser/extensions/extension_bookmark_manager_api.cc138
-rw-r--r--chrome/browser/extensions/extension_bookmark_manager_api.h2
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module.cc56
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module.h5
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module_constants.cc30
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module_constants.h31
-rw-r--r--chrome/browser/extensions/extension_bookmarks_unittest.cc53
-rw-r--r--chrome/browser/extensions/extension_browser_actions_api.cc17
-rw-r--r--chrome/browser/extensions/extension_browser_actions_api.h9
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.cc31
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.h12
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc29
-rw-r--r--chrome/browser/extensions/extension_browsertest.h1
-rw-r--r--chrome/browser/extensions/extension_browsertests_misc.cc341
-rw-r--r--chrome/browser/extensions/extension_clipboard_api.cc6
-rw-r--r--chrome/browser/extensions/extension_clipboard_api.h4
-rw-r--r--chrome/browser/extensions/extension_clipboard_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_context_menu_api.cc34
-rw-r--r--chrome/browser/extensions/extension_context_menu_api.h6
-rw-r--r--chrome/browser/extensions/extension_context_menu_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_context_menu_browsertest.cc344
-rw-r--r--chrome/browser/extensions/extension_context_menu_model.cc8
-rw-r--r--chrome/browser/extensions/extension_context_menu_model.h6
-rw-r--r--chrome/browser/extensions/extension_cookies_api.cc39
-rw-r--r--chrome/browser/extensions/extension_cookies_api.h14
-rw-r--r--chrome/browser/extensions/extension_cookies_api_constants.cc30
-rw-r--r--chrome/browser/extensions/extension_cookies_api_constants.h31
-rw-r--r--chrome/browser/extensions/extension_cookies_helpers.cc23
-rw-r--r--chrome/browser/extensions/extension_cookies_helpers.h8
-rw-r--r--chrome/browser/extensions/extension_cookies_unittest.cc8
-rw-r--r--chrome/browser/extensions/extension_creator.h3
-rw-r--r--chrome/browser/extensions/extension_data_deleter.cc6
-rw-r--r--chrome/browser/extensions/extension_data_deleter.h15
-rw-r--r--chrome/browser/extensions/extension_devtools_bridge.cc19
-rw-r--r--chrome/browser/extensions/extension_devtools_bridge.h6
-rw-r--r--chrome/browser/extensions/extension_devtools_browsertest.cc3
-rw-r--r--chrome/browser/extensions/extension_devtools_browsertest.h6
-rw-r--r--chrome/browser/extensions/extension_devtools_browsertests.cc22
-rw-r--r--chrome/browser/extensions/extension_devtools_events.cc23
-rw-r--r--chrome/browser/extensions/extension_devtools_events.h1
-rw-r--r--chrome/browser/extensions/extension_devtools_manager.h4
-rw-r--r--chrome/browser/extensions/extension_disabled_infobar_delegate.cc18
-rw-r--r--chrome/browser/extensions/extension_disabled_infobar_delegate.h8
-rw-r--r--chrome/browser/extensions/extension_dom_ui.cc116
-rw-r--r--chrome/browser/extensions/extension_dom_ui.h26
-rw-r--r--chrome/browser/extensions/extension_error_reporter.h1
-rw-r--r--chrome/browser/extensions/extension_event_names.cc7
-rw-r--r--chrome/browser/extensions/extension_event_names.h12
-rw-r--r--chrome/browser/extensions/extension_function.cc5
-rw-r--r--chrome/browser/extensions/extension_function.h15
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc130
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.h17
-rw-r--r--chrome/browser/extensions/extension_history_api.cc32
-rw-r--r--chrome/browser/extensions/extension_history_api.h4
-rw-r--r--chrome/browser/extensions/extension_history_api_constants.cc38
-rw-r--r--chrome/browser/extensions/extension_history_api_constants.h39
-rw-r--r--chrome/browser/extensions/extension_history_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_host.cc244
-rw-r--r--chrome/browser/extensions/extension_host.h58
-rw-r--r--chrome/browser/extensions/extension_host_mac.h1
-rw-r--r--chrome/browser/extensions/extension_i18n_api.cc12
-rw-r--r--chrome/browser/extensions/extension_i18n_api.h1
-rw-r--r--chrome/browser/extensions/extension_icon_manager.cc40
-rw-r--r--chrome/browser/extensions/extension_icon_manager.h7
-rw-r--r--chrome/browser/extensions/extension_idle_api.cc9
-rw-r--r--chrome/browser/extensions/extension_idle_api.h1
-rw-r--r--chrome/browser/extensions/extension_idle_api_constants.cc10
-rw-r--r--chrome/browser/extensions/extension_idle_api_constants.h11
-rw-r--r--chrome/browser/extensions/extension_incognito_apitest.cc51
-rw-r--r--chrome/browser/extensions/extension_infobar_delegate.cc9
-rw-r--r--chrome/browser/extensions/extension_infobar_delegate.h12
-rw-r--r--chrome/browser/extensions/extension_infobar_module.cc6
-rw-r--r--chrome/browser/extensions/extension_infobar_module.h1
-rw-r--r--chrome/browser/extensions/extension_infobar_module_constants.cc4
-rw-r--r--chrome/browser/extensions/extension_infobar_module_constants.h5
-rw-r--r--chrome/browser/extensions/extension_install_ui.cc126
-rw-r--r--chrome/browser/extensions/extension_install_ui.h16
-rw-r--r--chrome/browser/extensions/extension_install_ui_browsertest.cc4
-rw-r--r--chrome/browser/extensions/extension_javascript_url_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_management_browsertest.cc67
-rw-r--r--chrome/browser/extensions/extension_menu_manager.cc79
-rw-r--r--chrome/browser/extensions/extension_menu_manager.h15
-rw-r--r--chrome/browser/extensions/extension_menu_manager_unittest.cc91
-rw-r--r--chrome/browser/extensions/extension_message_service.cc227
-rw-r--r--chrome/browser/extensions/extension_message_service.h116
-rw-r--r--chrome/browser/extensions/extension_messages_apitest.cc11
-rw-r--r--chrome/browser/extensions/extension_messages_unittest.cc150
-rw-r--r--chrome/browser/extensions/extension_metrics_module.cc11
-rw-r--r--chrome/browser/extensions/extension_metrics_module.h1
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.cc26
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.h1
-rw-r--r--chrome/browser/extensions/extension_omnibox_apitest.cc26
-rw-r--r--chrome/browser/extensions/extension_override_apitest.cc50
-rw-r--r--chrome/browser/extensions/extension_page_actions_module.cc50
-rw-r--r--chrome/browser/extensions/extension_page_actions_module.h1
-rw-r--r--chrome/browser/extensions/extension_page_actions_module_constants.cc12
-rw-r--r--chrome/browser/extensions/extension_page_actions_module_constants.h13
-rw-r--r--chrome/browser/extensions/extension_popup_api.cc49
-rw-r--r--chrome/browser/extensions/extension_popup_api.h8
-rw-r--r--chrome/browser/extensions/extension_popup_apitest.cc19
-rw-r--r--chrome/browser/extensions/extension_pref_store.cc214
-rw-r--r--chrome/browser/extensions/extension_pref_store.h81
-rw-r--r--chrome/browser/extensions/extension_pref_store_unittest.cc262
-rw-r--r--chrome/browser/extensions/extension_prefs.cc290
-rw-r--r--chrome/browser/extensions/extension_prefs.h56
-rw-r--r--chrome/browser/extensions/extension_prefs_unittest.cc15
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc198
-rw-r--r--chrome/browser/extensions/extension_process_manager.h48
-rw-r--r--chrome/browser/extensions/extension_process_manager_unittest.cc8
-rw-r--r--chrome/browser/extensions/extension_processes_api.cc2
-rw-r--r--chrome/browser/extensions/extension_processes_api.h1
-rw-r--r--chrome/browser/extensions/extension_processes_api_constants.cc2
-rw-r--r--chrome/browser/extensions/extension_processes_api_constants.h3
-rw-r--r--chrome/browser/extensions/extension_protocols.cc79
-rw-r--r--chrome/browser/extensions/extension_protocols.h1
-rw-r--r--chrome/browser/extensions/extension_rlz_apitest.cc15
-rw-r--r--chrome/browser/extensions/extension_rlz_module.cc20
-rw-r--r--chrome/browser/extensions/extension_rlz_module.h3
-rw-r--r--chrome/browser/extensions/extension_shelf_model.cc282
-rw-r--r--chrome/browser/extensions/extension_shelf_model.h167
-rw-r--r--chrome/browser/extensions/extension_shelf_model_browsertest.cc97
-rw-r--r--chrome/browser/extensions/extension_startup_browsertest.cc28
-rw-r--r--chrome/browser/extensions/extension_storage_apitest.cc9
-rw-r--r--chrome/browser/extensions/extension_tabs_apitest.cc45
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc40
-rw-r--r--chrome/browser/extensions/extension_tabs_module.h2
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.cc60
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.h61
-rw-r--r--chrome/browser/extensions/extension_test_api.cc15
-rw-r--r--chrome/browser/extensions/extension_test_api.h7
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.cc6
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.h8
-rw-r--r--chrome/browser/extensions/extension_toolstrip_api.cc176
-rw-r--r--chrome/browser/extensions/extension_toolstrip_api.h60
-rw-r--r--chrome/browser/extensions/extension_toolstrip_apitest.cc11
-rw-r--r--chrome/browser/extensions/extension_ui_unittest.cc8
-rw-r--r--chrome/browser/extensions/extension_uitest.cc6
-rw-r--r--chrome/browser/extensions/extension_updater.cc53
-rw-r--r--chrome/browser/extensions/extension_updater.h3
-rw-r--r--chrome/browser/extensions/extension_updater_unittest.cc61
-rw-r--r--chrome/browser/extensions/extension_websocket_apitest.cc10
-rw-r--r--chrome/browser/extensions/extensions_quota_service.h1
-rw-r--r--chrome/browser/extensions/extensions_service.cc1010
-rw-r--r--chrome/browser/extensions/extensions_service.h216
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc904
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.h3
-rw-r--r--chrome/browser/extensions/extensions_ui.cc454
-rw-r--r--chrome/browser/extensions/extensions_ui.h49
-rw-r--r--chrome/browser/extensions/external_extension_provider.h16
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.cc94
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.h2
-rw-r--r--chrome/browser/extensions/external_registry_extension_provider_win.cc9
-rw-r--r--chrome/browser/extensions/external_registry_extension_provider_win.h1
-rw-r--r--chrome/browser/extensions/file_reader.h1
-rw-r--r--chrome/browser/extensions/fragment_navigation_apitest.cc4
-rw-r--r--chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h4
-rw-r--r--chrome/browser/extensions/image_loading_tracker.h5
-rw-r--r--chrome/browser/extensions/image_loading_tracker_unittest.cc7
-rw-r--r--chrome/browser/extensions/isolated_world_apitest.cc2
-rw-r--r--chrome/browser/extensions/notifications_apitest.cc8
-rw-r--r--chrome/browser/extensions/pack_extension_job.cc42
-rw-r--r--chrome/browser/extensions/pack_extension_job.h14
-rw-r--r--chrome/browser/extensions/page_action_apitest.cc2
-rw-r--r--chrome/browser/extensions/permissions_apitest.cc20
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker.cc90
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker.h6
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc16
-rw-r--r--chrome/browser/extensions/stubs_apitest.cc6
-rw-r--r--chrome/browser/extensions/test_extension_prefs.cc5
-rw-r--r--chrome/browser/extensions/test_extension_prefs.h1
-rw-r--r--chrome/browser/extensions/theme_installed_infobar_delegate.cc14
-rw-r--r--chrome/browser/extensions/theme_installed_infobar_delegate.h5
-rw-r--r--chrome/browser/extensions/user_script_listener.cc4
-rw-r--r--chrome/browser/extensions/user_script_listener.h6
-rw-r--r--chrome/browser/extensions/user_script_master.cc7
-rw-r--r--chrome/browser/extensions/user_script_master.h5
-rw-r--r--chrome/browser/external_protocol_handler.cc48
-rw-r--r--chrome/browser/external_protocol_handler.h15
-rw-r--r--chrome/browser/external_tab_container_win.cc125
-rw-r--r--chrome/browser/external_tab_container_win.h44
-rw-r--r--chrome/browser/fav_icon_helper.cc4
-rw-r--r--chrome/browser/fav_icon_helper.h4
-rw-r--r--chrome/browser/favicon_service.cc3
-rw-r--r--chrome/browser/favicon_service.h3
-rw-r--r--chrome/browser/file_path_watcher.h70
-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_unittest.cc466
-rw-r--r--chrome/browser/file_path_watcher_win.cc243
-rw-r--r--chrome/browser/file_select_helper.cc242
-rw-r--r--chrome/browser/file_select_helper.h85
-rw-r--r--chrome/browser/file_watcher.h61
-rw-r--r--chrome/browser/file_watcher_inotify.cc319
-rw-r--r--chrome/browser/file_watcher_mac.cc157
-rw-r--r--chrome/browser/file_watcher_stub.cc19
-rw-r--r--chrome/browser/file_watcher_unittest.cc259
-rw-r--r--chrome/browser/file_watcher_win.cc111
-rw-r--r--chrome/browser/find_backend_unittest.cc3
-rw-r--r--chrome/browser/find_bar.h2
-rw-r--r--chrome/browser/find_bar_controller.h2
-rw-r--r--chrome/browser/find_bar_host_browsertest.cc174
-rw-r--r--chrome/browser/find_bar_state.h1
-rw-r--r--chrome/browser/find_notification_details.h1
-rw-r--r--chrome/browser/first_run.cc222
-rw-r--r--chrome/browser/first_run.h297
-rw-r--r--chrome/browser/first_run_browsertest.cc52
-rw-r--r--chrome/browser/first_run_gtk.cc177
-rw-r--r--chrome/browser/first_run_mac.mm158
-rw-r--r--chrome/browser/first_run_unittest.cc24
-rw-r--r--chrome/browser/first_run_win.cc1077
-rw-r--r--chrome/browser/fonts_languages_window.h1
-rw-r--r--chrome/browser/gears_integration.h1
-rw-r--r--chrome/browser/geolocation/access_token_store.cc12
-rw-r--r--chrome/browser/geolocation/access_token_store.h1
-rw-r--r--chrome/browser/geolocation/access_token_store_browsertest.cc2
-rw-r--r--chrome/browser/geolocation/device_data_provider.h60
-rw-r--r--chrome/browser/geolocation/empty_device_data_provider.cc8
-rw-r--r--chrome/browser/geolocation/empty_device_data_provider.h1
-rw-r--r--chrome/browser/geolocation/fake_access_token_store.h1
-rw-r--r--chrome/browser/geolocation/geolocation_browsertest.cc56
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_map.cc33
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_map.h2
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc7
-rw-r--r--chrome/browser/geolocation/geolocation_dispatcher_host.h1
-rw-r--r--chrome/browser/geolocation/geolocation_exceptions_table_model.h2
-rw-r--r--chrome/browser/geolocation/geolocation_exceptions_table_model_unittest.cc1
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context.cc76
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context.h3
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context_unittest.cc13
-rw-r--r--chrome/browser/geolocation/geolocation_prefs.h1
-rw-r--r--chrome/browser/geolocation/geolocation_settings_state.cc7
-rw-r--r--chrome/browser/geolocation/geolocation_settings_state.h3
-rw-r--r--chrome/browser/geolocation/geolocation_settings_state_unittest.cc1
-rw-r--r--chrome/browser/geolocation/gps_location_provider_linux.cc2
-rw-r--r--chrome/browser/geolocation/gps_location_provider_linux.h10
-rw-r--r--chrome/browser/geolocation/libgps_wrapper_linux.h1
-rw-r--r--chrome/browser/geolocation/location_arbitrator.cc12
-rw-r--r--chrome/browser/geolocation/location_arbitrator.h3
-rw-r--r--chrome/browser/geolocation/location_arbitrator_unittest.cc4
-rw-r--r--chrome/browser/geolocation/location_provider.cc5
-rw-r--r--chrome/browser/geolocation/location_provider.h11
-rw-r--r--chrome/browser/geolocation/mock_location_provider.h1
-rw-r--r--chrome/browser/geolocation/network_location_provider.cc60
-rw-r--r--chrome/browser/geolocation/network_location_provider.h9
-rw-r--r--chrome/browser/geolocation/network_location_provider_unittest.cc332
-rw-r--r--chrome/browser/geolocation/network_location_request.cc114
-rw-r--r--chrome/browser/geolocation/network_location_request.h5
-rw-r--r--chrome/browser/geolocation/osx_wifi.h1
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_chromeos.cc11
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_chromeos.h9
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_common.cc3
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_common.h2
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_common_unittest.cc5
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_common_win.h3
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_linux.cc3
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_linux.h1
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_mac.h1
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_win.h1
-rw-r--r--chrome/browser/global_keyboard_shortcuts_mac.h1
-rw-r--r--chrome/browser/google_service_auth_error.h99
-rw-r--r--chrome/browser/google_update.cc331
-rw-r--r--chrome/browser/google_update.h143
-rw-r--r--chrome/browser/google_update_settings_posix.cc85
-rw-r--r--chrome/browser/google_update_settings_unittest.cc35
-rw-r--r--chrome/browser/google_url_tracker.cc179
-rw-r--r--chrome/browser/google_url_tracker.h113
-rw-r--r--chrome/browser/google_url_tracker_unittest.cc35
-rw-r--r--chrome/browser/google_util.cc58
-rw-r--r--chrome/browser/google_util.h26
-rw-r--r--chrome/browser/gpu_process_host.cc170
-rw-r--r--chrome/browser/gpu_process_host.h27
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.cc7
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.h5
-rw-r--r--chrome/browser/gtk/about_chrome_dialog.cc22
-rw-r--r--chrome/browser/gtk/about_chrome_dialog.h1
-rw-r--r--chrome/browser/gtk/accelerators_gtk.cc1
-rw-r--r--chrome/browser/gtk/accelerators_gtk.h1
-rw-r--r--chrome/browser/gtk/accessibility_event_router_gtk.cc33
-rw-r--r--chrome/browser/gtk/accessibility_event_router_gtk.h7
-rw-r--r--chrome/browser/gtk/accessible_widget_helper_gtk.h1
-rw-r--r--chrome/browser/gtk/back_forward_button_gtk.cc31
-rw-r--r--chrome/browser/gtk/back_forward_button_gtk.h1
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.cc145
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.h30
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk_interactive_uitest.cc18
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk_unittest.cc28
-rw-r--r--chrome/browser/gtk/bookmark_bar_instructions_gtk.cc21
-rw-r--r--chrome/browser/gtk/bookmark_bar_instructions_gtk.h4
-rw-r--r--chrome/browser/gtk/bookmark_bubble_gtk.cc18
-rw-r--r--chrome/browser/gtk/bookmark_bubble_gtk.h1
-rw-r--r--chrome/browser/gtk/bookmark_editor_gtk.cc12
-rw-r--r--chrome/browser/gtk/bookmark_editor_gtk.h8
-rw-r--r--chrome/browser/gtk/bookmark_editor_gtk_unittest.cc51
-rw-r--r--chrome/browser/gtk/bookmark_menu_controller_gtk.cc9
-rw-r--r--chrome/browser/gtk/bookmark_menu_controller_gtk.h3
-rw-r--r--chrome/browser/gtk/bookmark_tree_model.cc15
-rw-r--r--chrome/browser/gtk/bookmark_tree_model.h9
-rw-r--r--chrome/browser/gtk/bookmark_utils_gtk.cc41
-rw-r--r--chrome/browser/gtk/bookmark_utils_gtk.h4
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.cc194
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.h37
-rw-r--r--chrome/browser/gtk/browser_titlebar.cc7
-rw-r--r--chrome/browser/gtk/browser_titlebar.h1
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc239
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.h49
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc154
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h21
-rw-r--r--chrome/browser/gtk/cairo_cached_surface.h1
-rw-r--r--chrome/browser/gtk/certificate_dialogs.h1
-rw-r--r--chrome/browser/gtk/certificate_manager.cc39
-rw-r--r--chrome/browser/gtk/certificate_manager.h1
-rw-r--r--chrome/browser/gtk/certificate_viewer.cc27
-rw-r--r--chrome/browser/gtk/certificate_viewer.h1
-rw-r--r--chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc47
-rw-r--r--chrome/browser/gtk/clear_browsing_data_dialog_gtk.h1
-rw-r--r--chrome/browser/gtk/collected_cookies_gtk.cc102
-rw-r--r--chrome/browser/gtk/collected_cookies_gtk.h6
-rw-r--r--chrome/browser/gtk/constrained_window_gtk.cc50
-rw-r--r--chrome/browser/gtk/constrained_window_gtk.h16
-rw-r--r--chrome/browser/gtk/content_setting_bubble_gtk.cc51
-rw-r--r--chrome/browser/gtk/content_setting_bubble_gtk.h6
-rw-r--r--chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc7
-rw-r--r--chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h6
-rw-r--r--chrome/browser/gtk/custom_button.cc155
-rw-r--r--chrome/browser/gtk/custom_button.h71
-rw-r--r--chrome/browser/gtk/custom_drag.h1
-rw-r--r--chrome/browser/gtk/dialogs_gtk.cc4
-rw-r--r--chrome/browser/gtk/download_in_progress_dialog_gtk.cc6
-rw-r--r--chrome/browser/gtk/download_in_progress_dialog_gtk.h4
-rw-r--r--chrome/browser/gtk/download_item_gtk.cc35
-rw-r--r--chrome/browser/gtk/download_item_gtk.h3
-rw-r--r--chrome/browser/gtk/download_shelf_gtk.h3
-rw-r--r--chrome/browser/gtk/edit_search_engine_dialog.cc16
-rw-r--r--chrome/browser/gtk/edit_search_engine_dialog.h7
-rw-r--r--chrome/browser/gtk/extension_infobar_gtk.cc11
-rw-r--r--chrome/browser/gtk/extension_infobar_gtk.h1
-rw-r--r--chrome/browser/gtk/extension_install_prompt2_gtk.cc11
-rw-r--r--chrome/browser/gtk/extension_install_prompt_gtk.cc45
-rw-r--r--chrome/browser/gtk/extension_installed_bubble_gtk.cc47
-rw-r--r--chrome/browser/gtk/extension_installed_bubble_gtk.h5
-rw-r--r--chrome/browser/gtk/extension_popup_gtk.h1
-rw-r--r--chrome/browser/gtk/extension_view_gtk.h1
-rw-r--r--chrome/browser/gtk/external_protocol_dialog_gtk.cc6
-rw-r--r--chrome/browser/gtk/external_protocol_dialog_gtk.h4
-rw-r--r--chrome/browser/gtk/find_bar_gtk.cc26
-rw-r--r--chrome/browser/gtk/find_bar_gtk.h11
-rw-r--r--chrome/browser/gtk/first_run_bubble.cc154
-rw-r--r--chrome/browser/gtk/first_run_bubble.h17
-rw-r--r--chrome/browser/gtk/first_run_dialog.cc404
-rw-r--r--chrome/browser/gtk/first_run_dialog.h56
-rw-r--r--chrome/browser/gtk/focus_store_gtk.cc34
-rw-r--r--chrome/browser/gtk/focus_store_gtk.h8
-rw-r--r--chrome/browser/gtk/fullscreen_exit_bubble_gtk.h3
-rw-r--r--chrome/browser/gtk/gconf_titlebar_listener.cc6
-rw-r--r--chrome/browser/gtk/gconf_titlebar_listener.h4
-rw-r--r--chrome/browser/gtk/gtk_chrome_button.h7
-rw-r--r--chrome/browser/gtk/gtk_chrome_cookie_view.cc64
-rw-r--r--chrome/browser/gtk/gtk_chrome_cookie_view.h14
-rw-r--r--chrome/browser/gtk/gtk_chrome_link_button.cc3
-rw-r--r--chrome/browser/gtk/gtk_chrome_link_button.h12
-rw-r--r--chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h1
-rw-r--r--chrome/browser/gtk/gtk_custom_menu.cc8
-rw-r--r--chrome/browser/gtk/gtk_custom_menu.h1
-rw-r--r--chrome/browser/gtk/gtk_custom_menu_item.cc49
-rw-r--r--chrome/browser/gtk/gtk_custom_menu_item.h14
-rw-r--r--chrome/browser/gtk/gtk_expanded_container.h1
-rw-r--r--chrome/browser/gtk/gtk_floating_container.cc6
-rw-r--r--chrome/browser/gtk/gtk_floating_container.h4
-rw-r--r--chrome/browser/gtk/gtk_theme_provider.cc140
-rw-r--r--chrome/browser/gtk/gtk_theme_provider.h29
-rw-r--r--chrome/browser/gtk/gtk_theme_provider_unittest.cc1
-rw-r--r--chrome/browser/gtk/gtk_tree.cc213
-rw-r--r--chrome/browser/gtk/gtk_tree.h56
-rw-r--r--chrome/browser/gtk/gtk_util.cc79
-rw-r--r--chrome/browser/gtk/gtk_util.h32
-rw-r--r--chrome/browser/gtk/hover_controller_gtk.h2
-rw-r--r--chrome/browser/gtk/html_dialog_gtk.cc23
-rw-r--r--chrome/browser/gtk/html_dialog_gtk.h7
-rw-r--r--chrome/browser/gtk/hung_renderer_dialog_gtk.cc7
-rw-r--r--chrome/browser/gtk/import_dialog_gtk.cc1
-rw-r--r--chrome/browser/gtk/import_dialog_gtk.h1
-rw-r--r--chrome/browser/gtk/import_lock_dialog_gtk.cc1
-rw-r--r--chrome/browser/gtk/import_lock_dialog_gtk.h1
-rw-r--r--chrome/browser/gtk/import_progress_dialog_gtk.cc1
-rw-r--r--chrome/browser/gtk/import_progress_dialog_gtk.h1
-rw-r--r--chrome/browser/gtk/info_bubble_gtk.cc14
-rw-r--r--chrome/browser/gtk/info_bubble_gtk.h2
-rw-r--r--chrome/browser/gtk/infobar_container_gtk.h4
-rw-r--r--chrome/browser/gtk/infobar_gtk.cc235
-rw-r--r--chrome/browser/gtk/infobar_gtk.h23
-rw-r--r--chrome/browser/gtk/keyword_editor_view.cc5
-rw-r--r--chrome/browser/gtk/keyword_editor_view.h9
-rw-r--r--chrome/browser/gtk/keyword_editor_view_unittest.cc26
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc93
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.h25
-rw-r--r--chrome/browser/gtk/menu_bar_helper.cc4
-rw-r--r--chrome/browser/gtk/menu_bar_helper.h3
-rw-r--r--chrome/browser/gtk/menu_gtk.cc197
-rw-r--r--chrome/browser/gtk/menu_gtk.h36
-rw-r--r--chrome/browser/gtk/meta_frames.h1
-rw-r--r--chrome/browser/gtk/nine_box.cc1
-rw-r--r--chrome/browser/gtk/nine_box.h1
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_gtk.cc43
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_gtk.h6
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_host_gtk.h1
-rw-r--r--chrome/browser/gtk/options/advanced_contents_gtk.cc210
-rw-r--r--chrome/browser/gtk/options/advanced_contents_gtk.h3
-rw-r--r--chrome/browser/gtk/options/advanced_page_gtk.h3
-rw-r--r--chrome/browser/gtk/options/content_exception_editor.cc2
-rw-r--r--chrome/browser/gtk/options/content_exception_editor.h4
-rw-r--r--chrome/browser/gtk/options/content_exceptions_window_gtk.h1
-rw-r--r--chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc1
-rw-r--r--chrome/browser/gtk/options/content_filter_page_gtk.cc36
-rw-r--r--chrome/browser/gtk/options/content_filter_page_gtk.h3
-rw-r--r--chrome/browser/gtk/options/content_page_gtk.cc129
-rw-r--r--chrome/browser/gtk/options/content_page_gtk.h12
-rw-r--r--chrome/browser/gtk/options/content_settings_window_gtk.cc2
-rw-r--r--chrome/browser/gtk/options/content_settings_window_gtk.h3
-rw-r--r--chrome/browser/gtk/options/cookie_filter_page_gtk.cc22
-rw-r--r--chrome/browser/gtk/options/cookie_filter_page_gtk.h6
-rw-r--r--chrome/browser/gtk/options/cookies_view.cc22
-rw-r--r--chrome/browser/gtk/options/cookies_view.h11
-rw-r--r--chrome/browser/gtk/options/cookies_view_unittest.cc117
-rw-r--r--chrome/browser/gtk/options/fonts_page_gtk.cc10
-rw-r--r--chrome/browser/gtk/options/fonts_page_gtk.h6
-rw-r--r--chrome/browser/gtk/options/general_page_gtk.cc47
-rw-r--r--chrome/browser/gtk/options/general_page_gtk.h11
-rw-r--r--chrome/browser/gtk/options/languages_page_gtk.cc10
-rw-r--r--chrome/browser/gtk/options/languages_page_gtk.h5
-rw-r--r--chrome/browser/gtk/options/languages_page_gtk_unittest.cc1
-rw-r--r--chrome/browser/gtk/options/managed_prefs_banner_gtk.cc3
-rw-r--r--chrome/browser/gtk/options/managed_prefs_banner_gtk.h7
-rw-r--r--chrome/browser/gtk/options/options_layout_gtk.h4
-rw-r--r--chrome/browser/gtk/options/options_window_gtk.cc8
-rw-r--r--chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc9
-rw-r--r--chrome/browser/gtk/options/passwords_exceptions_page_gtk.h3
-rw-r--r--chrome/browser/gtk/options/passwords_exceptions_window_gtk.h1
-rw-r--r--chrome/browser/gtk/options/passwords_page_gtk.cc102
-rw-r--r--chrome/browser/gtk/options/passwords_page_gtk.h20
-rw-r--r--chrome/browser/gtk/options/simple_content_exceptions_window.cc64
-rw-r--r--chrome/browser/gtk/options/simple_content_exceptions_window.h18
-rw-r--r--chrome/browser/gtk/options/url_picker_dialog_gtk.cc12
-rw-r--r--chrome/browser/gtk/options/url_picker_dialog_gtk.h1
-rw-r--r--chrome/browser/gtk/overflow_button.h3
-rw-r--r--chrome/browser/gtk/page_info_window_gtk.cc9
-rw-r--r--chrome/browser/gtk/process_singleton_dialog.h1
-rw-r--r--chrome/browser/gtk/reload_button_gtk.cc157
-rw-r--r--chrome/browser/gtk/reload_button_gtk.h5
-rw-r--r--chrome/browser/gtk/repost_form_warning_gtk.cc2
-rw-r--r--chrome/browser/gtk/repost_form_warning_gtk.h1
-rw-r--r--chrome/browser/gtk/rounded_window.cc2
-rw-r--r--chrome/browser/gtk/rounded_window.h1
-rw-r--r--chrome/browser/gtk/sad_tab_gtk.h5
-rw-r--r--chrome/browser/gtk/slide_animator_gtk.cc1
-rw-r--r--chrome/browser/gtk/slide_animator_gtk.h3
-rw-r--r--chrome/browser/gtk/ssl_client_certificate_selector.cc190
-rw-r--r--chrome/browser/gtk/status_bubble_gtk.cc8
-rw-r--r--chrome/browser/gtk/status_bubble_gtk.h9
-rw-r--r--chrome/browser/gtk/status_icons/status_icon_gtk.cc16
-rw-r--r--chrome/browser/gtk/status_icons/status_icon_gtk.h12
-rw-r--r--chrome/browser/gtk/status_icons/status_tray_gtk.cc2
-rw-r--r--chrome/browser/gtk/status_icons/status_tray_gtk.h3
-rw-r--r--chrome/browser/gtk/status_icons/status_tray_gtk_unittest.cc10
-rw-r--r--chrome/browser/gtk/tab_contents_container_gtk.cc3
-rw-r--r--chrome/browser/gtk/tab_contents_container_gtk.h4
-rw-r--r--chrome/browser/gtk/tab_contents_drag_source.cc27
-rw-r--r--chrome/browser/gtk/tab_contents_drag_source.h1
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc6
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h3
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_gtk.cc2
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_gtk.h1
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.cc5
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.h4
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.cc5
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.h4
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.cc32
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.h13
-rw-r--r--chrome/browser/gtk/tabstrip_origin_provider.h1
-rw-r--r--chrome/browser/gtk/task_manager_gtk.cc105
-rw-r--r--chrome/browser/gtk/task_manager_gtk.h20
-rw-r--r--chrome/browser/gtk/theme_install_bubble_view_gtk.h1
-rw-r--r--chrome/browser/gtk/translate/after_translate_infobar_gtk.h1
-rw-r--r--chrome/browser/gtk/translate/before_translate_infobar_gtk.h1
-rw-r--r--chrome/browser/gtk/translate/translate_infobar_base_gtk.cc9
-rw-r--r--chrome/browser/gtk/translate/translate_infobar_base_gtk.h3
-rw-r--r--chrome/browser/gtk/translate/translate_message_infobar_gtk.h1
-rw-r--r--chrome/browser/gtk/update_recommended_dialog.cc17
-rw-r--r--chrome/browser/gtk/update_recommended_dialog.h1
-rw-r--r--chrome/browser/gtk/view_id_util.cc3
-rw-r--r--chrome/browser/gtk/view_id_util.h1
-rw-r--r--chrome/browser/gtk/view_id_util_browsertest.cc8
-rw-r--r--chrome/browser/hang_monitor/hung_plugin_action.h1
-rw-r--r--chrome/browser/hang_monitor/hung_window_detector.h1
-rw-r--r--chrome/browser/history/archived_database.cc9
-rw-r--r--chrome/browser/history/archived_database.h1
-rw-r--r--chrome/browser/history/download_database.cc21
-rw-r--r--chrome/browser/history/download_database.h5
-rw-r--r--chrome/browser/history/download_types.h104
-rw-r--r--chrome/browser/history/expire_history_backend.cc12
-rw-r--r--chrome/browser/history/expire_history_backend.h2
-rw-r--r--chrome/browser/history/expire_history_backend_unittest.cc110
-rw-r--r--chrome/browser/history/history.cc72
-rw-r--r--chrome/browser/history/history.h42
-rw-r--r--chrome/browser/history/history_backend.cc79
-rw-r--r--chrome/browser/history/history_backend.h28
-rw-r--r--chrome/browser/history/history_backend_unittest.cc256
-rw-r--r--chrome/browser/history/history_database.cc40
-rw-r--r--chrome/browser/history/history_database.h10
-rw-r--r--chrome/browser/history/history_marshaling.h48
-rw-r--r--chrome/browser/history/history_notifications.h1
-rw-r--r--chrome/browser/history/history_publisher.h2
-rw-r--r--chrome/browser/history/history_publisher_win.cc6
-rw-r--r--chrome/browser/history/history_querying_unittest.cc16
-rw-r--r--chrome/browser/history/history_types.cc87
-rw-r--r--chrome/browser/history/history_types.h111
-rw-r--r--chrome/browser/history/history_unittest.cc78
-rw-r--r--chrome/browser/history/in_memory_database.h5
-rw-r--r--chrome/browser/history/in_memory_history_backend.cc17
-rw-r--r--chrome/browser/history/in_memory_history_backend.h7
-rw-r--r--chrome/browser/history/in_memory_url_index.cc487
-rw-r--r--chrome/browser/history/in_memory_url_index.h220
-rw-r--r--chrome/browser/history/in_memory_url_index_unittest.cc166
-rw-r--r--chrome/browser/history/multipart_uitest.cc24
-rw-r--r--chrome/browser/history/page_usage_data.h1
-rw-r--r--chrome/browser/history/query_parser.h1
-rw-r--r--chrome/browser/history/redirect_uitest.cc115
-rw-r--r--chrome/browser/history/snippet.cc3
-rw-r--r--chrome/browser/history/snippet.h1
-rw-r--r--chrome/browser/history/snippet_unittest.cc98
-rw-r--r--chrome/browser/history/starred_url_database.cc2
-rw-r--r--chrome/browser/history/starred_url_database.h1
-rw-r--r--chrome/browser/history/starred_url_database_unittest.cc1
-rw-r--r--chrome/browser/history/text_database.cc9
-rw-r--r--chrome/browser/history/text_database.h1
-rw-r--r--chrome/browser/history/text_database_manager.h3
-rw-r--r--chrome/browser/history/text_database_manager_unittest.cc16
-rw-r--r--chrome/browser/history/thumbnail_database.cc29
-rw-r--r--chrome/browser/history/thumbnail_database.h1
-rw-r--r--chrome/browser/history/thumbnail_database_unittest.cc21
-rw-r--r--chrome/browser/history/top_sites.cc536
-rw-r--r--chrome/browser/history/top_sites.h131
-rw-r--r--chrome/browser/history/top_sites_database.cc18
-rw-r--r--chrome/browser/history/top_sites_database.h25
-rw-r--r--chrome/browser/history/top_sites_unittest.cc482
-rw-r--r--chrome/browser/history/url_database.cc7
-rw-r--r--chrome/browser/history/url_database.h9
-rw-r--r--chrome/browser/history/url_database_unittest.cc18
-rw-r--r--chrome/browser/history/visit_database.cc78
-rw-r--r--chrome/browser/history/visit_database.h10
-rw-r--r--chrome/browser/history/visit_database_unittest.cc57
-rw-r--r--chrome/browser/history/visit_tracker.h1
-rw-r--r--chrome/browser/history/visitsegment_database.cc1
-rw-r--r--chrome/browser/history/visitsegment_database.h1
-rw-r--r--chrome/browser/host_content_settings_map.cc483
-rw-r--r--chrome/browser/host_content_settings_map.h127
-rw-r--r--chrome/browser/host_content_settings_map_unittest.cc248
-rw-r--r--chrome/browser/host_zoom_map.cc27
-rw-r--r--chrome/browser/host_zoom_map.h3
-rw-r--r--chrome/browser/host_zoom_map_unittest.cc27
-rw-r--r--chrome/browser/hung_renderer_dialog.h1
-rw-r--r--chrome/browser/icon_loader.cc5
-rw-r--r--chrome/browser/icon_loader.h7
-rw-r--r--chrome/browser/icon_manager.h5
-rw-r--r--chrome/browser/idbbindingutilities_browsertest.cc270
-rw-r--r--chrome/browser/idle.h1
-rw-r--r--chrome/browser/ime_input.h5
-rw-r--r--chrome/browser/importer/firefox2_importer.cc6
-rw-r--r--chrome/browser/importer/firefox2_importer.h1
-rw-r--r--chrome/browser/importer/firefox3_importer.cc39
-rw-r--r--chrome/browser/importer/firefox3_importer.h13
-rw-r--r--chrome/browser/importer/firefox_importer_unittest.cc1
-rw-r--r--chrome/browser/importer/firefox_importer_unittest_utils.h1
-rw-r--r--chrome/browser/importer/firefox_importer_unittest_utils_mac.cc10
-rw-r--r--chrome/browser/importer/firefox_importer_utils.cc106
-rw-r--r--chrome/browser/importer/firefox_importer_utils.h11
-rw-r--r--chrome/browser/importer/firefox_importer_utils_win.cc8
-rw-r--r--chrome/browser/importer/firefox_profile_lock.h3
-rw-r--r--chrome/browser/importer/firefox_proxy_settings.cc29
-rw-r--r--chrome/browser/importer/firefox_proxy_settings.h3
-rw-r--r--chrome/browser/importer/firefox_proxy_settings_unittest.cc46
-rw-r--r--chrome/browser/importer/ie_importer.cc17
-rw-r--r--chrome/browser/importer/ie_importer.h1
-rw-r--r--chrome/browser/importer/importer.cc41
-rw-r--r--chrome/browser/importer/importer.h10
-rw-r--r--chrome/browser/importer/importer_bridge.cc22
-rw-r--r--chrome/browser/importer/importer_bridge.h11
-rw-r--r--chrome/browser/importer/importer_data_types.h3
-rw-r--r--chrome/browser/importer/importer_list.cc7
-rw-r--r--chrome/browser/importer/importer_list.h1
-rw-r--r--chrome/browser/importer/importer_messages.h71
-rw-r--r--chrome/browser/importer/importer_messages_internal.h6
-rw-r--r--chrome/browser/importer/importer_unittest.cc17
-rw-r--r--chrome/browser/importer/mork_reader.cc9
-rw-r--r--chrome/browser/importer/mork_reader.h1
-rw-r--r--chrome/browser/importer/nss_decryptor.cc1
-rw-r--r--chrome/browser/importer/nss_decryptor.h1
-rw-r--r--chrome/browser/importer/nss_decryptor_mac.h8
-rw-r--r--chrome/browser/importer/nss_decryptor_mac.mm4
-rw-r--r--chrome/browser/importer/nss_decryptor_system_nss.h7
-rw-r--r--chrome/browser/importer/nss_decryptor_win.h1
-rw-r--r--chrome/browser/importer/profile_writer.cc20
-rw-r--r--chrome/browser/importer/profile_writer.h5
-rw-r--r--chrome/browser/importer/safari_importer.h1
-rw-r--r--chrome/browser/importer/safari_importer.mm3
-rw-r--r--chrome/browser/importer/safari_importer_unittest.mm1
-rw-r--r--chrome/browser/importer/toolbar_importer.cc12
-rw-r--r--chrome/browser/importer/toolbar_importer.h1
-rw-r--r--chrome/browser/importer/toolbar_importer_unittest.cc6
-rw-r--r--chrome/browser/in_process_webkit/browser_webkitclient_impl.cc38
-rw-r--r--chrome/browser/in_process_webkit/browser_webkitclient_impl.h17
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_area.cc18
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_area.h6
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_context.cc14
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_context.h4
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc7
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h9
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_namespace.h9
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_permission_request.cc65
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_permission_request.h64
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_uitest.cc43
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_callbacks.h52
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_context.cc70
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_context.h38
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc519
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h104
-rw-r--r--chrome/browser/in_process_webkit/webkit_context.cc14
-rw-r--r--chrome/browser/in_process_webkit/webkit_context.h10
-rw-r--r--chrome/browser/in_process_webkit/webkit_thread.h4
-rw-r--r--chrome/browser/input_window_dialog.h1
-rw-r--r--chrome/browser/input_window_dialog_gtk.cc81
-rw-r--r--chrome/browser/input_window_dialog_win.cc1
-rw-r--r--chrome/browser/intranet_redirect_detector.cc8
-rw-r--r--chrome/browser/intranet_redirect_detector.h2
-rw-r--r--chrome/browser/io_thread.cc158
-rw-r--r--chrome/browser/io_thread.h4
-rw-r--r--chrome/browser/jankometer.h1
-rw-r--r--chrome/browser/js_modal_dialog.cc15
-rw-r--r--chrome/browser/js_modal_dialog.h51
-rw-r--r--chrome/browser/js_modal_dialog_gtk.cc194
-rw-r--r--chrome/browser/js_modal_dialog_mac.mm202
-rw-r--r--chrome/browser/js_modal_dialog_win.cc32
-rw-r--r--chrome/browser/jsmessage_box_client.h8
-rw-r--r--chrome/browser/jumplist_win.cc12
-rw-r--r--chrome/browser/jumplist_win.h6
-rw-r--r--chrome/browser/keychain_mac.h1
-rw-r--r--chrome/browser/keychain_mock_mac.h1
-rw-r--r--chrome/browser/labs.cc270
-rw-r--r--chrome/browser/labs.h37
-rw-r--r--chrome/browser/language_combobox_model.cc15
-rw-r--r--chrome/browser/language_combobox_model.h9
-rw-r--r--chrome/browser/language_order_table_model.cc4
-rw-r--r--chrome/browser/language_order_table_model.h5
-rw-r--r--chrome/browser/load_from_memory_cache_details.h1
-rw-r--r--chrome/browser/load_notification_details.h1
-rw-r--r--chrome/browser/locale_tests_uitest.cc14
-rw-r--r--chrome/browser/location_bar.h8
-rw-r--r--chrome/browser/location_bar_util.h1
-rw-r--r--chrome/browser/login_model.h1
-rw-r--r--chrome/browser/login_prompt.cc7
-rw-r--r--chrome/browser/login_prompt.h1
-rw-r--r--chrome/browser/login_prompt_gtk.cc76
-rw-r--r--chrome/browser/login_prompt_mac.h1
-rw-r--r--chrome/browser/login_prompt_uitest.cc98
-rw-r--r--chrome/browser/login_prompt_win.cc7
-rw-r--r--chrome/browser/mach_broker_mac.cc158
-rw-r--r--chrome/browser/mach_broker_mac.h39
-rw-r--r--chrome/browser/mach_broker_mac_unittest.cc46
-rw-r--r--chrome/browser/managed_prefs_banner_base.cc81
-rw-r--r--chrome/browser/managed_prefs_banner_base.h54
-rw-r--r--chrome/browser/managed_prefs_banner_base_unittest.cc60
-rw-r--r--chrome/browser/media_uitest.cc83
-rw-r--r--chrome/browser/memory_details.cc5
-rw-r--r--chrome/browser/memory_details.h1
-rw-r--r--chrome/browser/memory_details_linux.cc2
-rw-r--r--chrome/browser/memory_details_mac.cc9
-rw-r--r--chrome/browser/memory_details_win.cc8
-rw-r--r--chrome/browser/memory_purger.h4
-rw-r--r--chrome/browser/message_box_handler.cc103
-rw-r--r--chrome/browser/message_box_handler.h6
-rw-r--r--chrome/browser/metrics/histogram_synchronizer.h1
-rw-r--r--chrome/browser/metrics/metric_event_duration_details.h1
-rw-r--r--chrome/browser/metrics/metrics_log.cc51
-rw-r--r--chrome/browser/metrics/metrics_log.h7
-rw-r--r--chrome/browser/metrics/metrics_response.cc4
-rw-r--r--chrome/browser/metrics/metrics_response.h1
-rw-r--r--chrome/browser/metrics/metrics_service.cc74
-rw-r--r--chrome/browser/metrics/metrics_service.h27
-rw-r--r--chrome/browser/metrics/metrics_service_uitest.cc12
-rw-r--r--chrome/browser/metrics/metrics_service_unittest.cc10
-rw-r--r--chrome/browser/metrics/user_metrics.h9
-rw-r--r--chrome/browser/mock_browsing_data_appcache_helper.cc4
-rw-r--r--chrome/browser/mock_browsing_data_appcache_helper.h3
-rw-r--r--chrome/browser/mock_browsing_data_database_helper.h2
-rw-r--r--chrome/browser/mock_browsing_data_indexed_db_helper.cc64
-rw-r--r--chrome/browser/mock_browsing_data_indexed_db_helper.h58
-rw-r--r--chrome/browser/mock_browsing_data_local_storage_helper.h3
-rw-r--r--chrome/browser/mock_configuration_policy_provider.h42
-rw-r--r--chrome/browser/mock_configuration_policy_store.h34
-rw-r--r--chrome/browser/mock_plugin_exceptions_table_model.cc17
-rw-r--r--chrome/browser/mock_plugin_exceptions_table_model.h29
-rw-r--r--chrome/browser/modal_html_dialog_delegate.cc1
-rw-r--r--chrome/browser/modal_html_dialog_delegate.h12
-rw-r--r--chrome/browser/nacl_host/nacl_broker_host_win.cc7
-rw-r--r--chrome/browser/nacl_host/nacl_broker_host_win.h1
-rw-r--r--chrome/browser/nacl_host/nacl_broker_service_win.h1
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc151
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.h11
-rw-r--r--chrome/browser/nacl_loader.sb11
-rw-r--r--chrome/browser/native_app_modal_dialog.h39
-rw-r--r--chrome/browser/net/browser_url_util.cc6
-rw-r--r--chrome/browser/net/browser_url_util.h3
-rw-r--r--chrome/browser/net/chrome_cookie_notification_details.h1
-rw-r--r--chrome/browser/net/chrome_cookie_policy.cc119
-rw-r--r--chrome/browser/net/chrome_cookie_policy.h7
-rw-r--r--chrome/browser/net/chrome_net_log.cc34
-rw-r--r--chrome/browser/net/chrome_net_log.h24
-rw-r--r--chrome/browser/net/chrome_network_delegate.cc2
-rw-r--r--chrome/browser/net/chrome_network_delegate.h3
-rw-r--r--chrome/browser/net/chrome_url_request_context.cc171
-rw-r--r--chrome/browser/net/chrome_url_request_context.h92
-rw-r--r--chrome/browser/net/chrome_url_request_context_unittest.cc42
-rw-r--r--chrome/browser/net/connect_interceptor.cc50
-rw-r--r--chrome/browser/net/connect_interceptor.h9
-rw-r--r--chrome/browser/net/connection_tester.cc10
-rw-r--r--chrome/browser/net/connection_tester.h1
-rw-r--r--chrome/browser/net/connection_tester_unittest.cc20
-rw-r--r--chrome/browser/net/cookie_policy_browsertest.cc18
-rw-r--r--chrome/browser/net/ftp_browsertest.cc11
-rw-r--r--chrome/browser/net/gaia/token_service.cc245
-rw-r--r--chrome/browser/net/gaia/token_service.h184
-rw-r--r--chrome/browser/net/load_timing_observer.cc57
-rw-r--r--chrome/browser/net/load_timing_observer.h10
-rw-r--r--chrome/browser/net/load_timing_observer_unittest.cc21
-rw-r--r--chrome/browser/net/metadata_url_request.h1
-rw-r--r--chrome/browser/net/passive_log_collector.cc55
-rw-r--r--chrome/browser/net/passive_log_collector.h33
-rw-r--r--chrome/browser/net/preconnect.cc164
-rw-r--r--chrome/browser/net/preconnect.h70
-rw-r--r--chrome/browser/net/predictor.cc314
-rw-r--r--chrome/browser/net/predictor.h85
-rw-r--r--chrome/browser/net/predictor_api.cc404
-rw-r--r--chrome/browser/net/predictor_api.h27
-rw-r--r--chrome/browser/net/predictor_unittest.cc218
-rw-r--r--chrome/browser/net/referrer.cc115
-rw-r--r--chrome/browser/net/referrer.h51
-rw-r--r--chrome/browser/net/resolve_proxy_msg_helper.h1
-rw-r--r--chrome/browser/net/resolve_proxy_msg_helper_unittest.cc9
-rw-r--r--chrome/browser/net/sdch_dictionary_fetcher.cc9
-rw-r--r--chrome/browser/net/sdch_dictionary_fetcher.h9
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store.cc34
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store.h11
-rw-r--r--chrome/browser/net/ssl_config_service_manager.h1
-rw-r--r--chrome/browser/net/ssl_config_service_manager_pref.cc7
-rw-r--r--chrome/browser/net/url_fixer_upper.cc8
-rw-r--r--chrome/browser/net/url_fixer_upper.h1
-rw-r--r--chrome/browser/net/url_info.cc147
-rw-r--r--chrome/browser/net/url_info.h45
-rw-r--r--chrome/browser/net/url_info_unittest.cc74
-rw-r--r--chrome/browser/net/url_request_failed_dns_job.h1
-rw-r--r--chrome/browser/net/url_request_mock_http_job.h1
-rw-r--r--chrome/browser/net/url_request_mock_link_doctor_job.cc2
-rw-r--r--chrome/browser/net/url_request_mock_link_doctor_job.h1
-rw-r--r--chrome/browser/net/url_request_mock_net_error_job.cc1
-rw-r--r--chrome/browser/net/url_request_mock_net_error_job.h1
-rw-r--r--chrome/browser/net/url_request_mock_util.h1
-rw-r--r--chrome/browser/net/url_request_slow_download_job.cc2
-rw-r--r--chrome/browser/net/url_request_slow_download_job.h1
-rw-r--r--chrome/browser/net/url_request_slow_http_job.cc3
-rw-r--r--chrome/browser/net/url_request_slow_http_job.h7
-rw-r--r--chrome/browser/net/url_request_tracking.h1
-rw-r--r--chrome/browser/net/view_http_cache_job_factory.cc25
-rw-r--r--chrome/browser/net/view_http_cache_job_factory.h1
-rw-r--r--chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc10
-rw-r--r--chrome/browser/net/websocket_experiment/websocket_experiment_runner.h1
-rw-r--r--chrome/browser/net/websocket_experiment/websocket_experiment_task.cc1
-rw-r--r--chrome/browser/net/websocket_experiment/websocket_experiment_task.h1
-rw-r--r--chrome/browser/notifications/balloon.cc4
-rw-r--r--chrome/browser/notifications/balloon.h8
-rw-r--r--chrome/browser/notifications/balloon_collection.cc3
-rw-r--r--chrome/browser/notifications/balloon_collection.h1
-rw-r--r--chrome/browser/notifications/balloon_collection_impl.h5
-rw-r--r--chrome/browser/notifications/balloon_collection_linux.cc4
-rw-r--r--chrome/browser/notifications/balloon_collection_mac.mm12
-rw-r--r--chrome/browser/notifications/balloon_collection_win.cc4
-rw-r--r--chrome/browser/notifications/balloon_host.cc38
-rw-r--r--chrome/browser/notifications/balloon_host.h29
-rw-r--r--chrome/browser/notifications/desktop_notification_service.cc68
-rw-r--r--chrome/browser/notifications/desktop_notification_service.h13
-rw-r--r--chrome/browser/notifications/desktop_notification_service_unittest.cc7
-rw-r--r--chrome/browser/notifications/desktop_notifications_unittest.cc39
-rw-r--r--chrome/browser/notifications/desktop_notifications_unittest.h2
-rw-r--r--chrome/browser/notifications/notification.h9
-rw-r--r--chrome/browser/notifications/notification_delegate.h11
-rw-r--r--chrome/browser/notifications/notification_exceptions_table_model.cc1
-rw-r--r--chrome/browser/notifications/notification_exceptions_table_model.h3
-rw-r--r--chrome/browser/notifications/notification_exceptions_table_model_unittest.cc1
-rw-r--r--chrome/browser/notifications/notification_object_proxy.cc9
-rw-r--r--chrome/browser/notifications/notification_object_proxy.h2
-rw-r--r--chrome/browser/notifications/notification_options_menu_model.cc3
-rw-r--r--chrome/browser/notifications/notification_options_menu_model.h1
-rw-r--r--chrome/browser/notifications/notification_test_util.h1
-rw-r--r--chrome/browser/notifications/notification_ui_manager.h1
-rw-r--r--chrome/browser/notifications/notifications_interactive_uitest.cc25
-rw-r--r--chrome/browser/notifications/notifications_prefs_cache.cc6
-rw-r--r--chrome/browser/notifications/notifications_prefs_cache.h1
-rw-r--r--chrome/browser/ntp_background_util.cc2
-rw-r--r--chrome/browser/ntp_background_util.h1
-rw-r--r--chrome/browser/omnibox_search_hint.cc17
-rw-r--r--chrome/browser/omnibox_search_hint.h4
-rw-r--r--chrome/browser/options_page_base.cc6
-rw-r--r--chrome/browser/options_page_base.h3
-rw-r--r--chrome/browser/options_util.cc17
-rw-r--r--chrome/browser/options_util.h1
-rw-r--r--chrome/browser/options_window.h1
-rw-r--r--chrome/browser/page_info_model.cc171
-rw-r--r--chrome/browser/page_info_model.h51
-rw-r--r--chrome/browser/page_info_window.h7
-rw-r--r--chrome/browser/page_state.cc111
-rw-r--r--chrome/browser/page_state.h62
-rw-r--r--chrome/browser/parsers/metadata_parser.h9
-rw-r--r--chrome/browser/parsers/metadata_parser_factory.h6
-rw-r--r--chrome/browser/parsers/metadata_parser_filebase.cc6
-rw-r--r--chrome/browser/parsers/metadata_parser_filebase.h6
-rw-r--r--chrome/browser/parsers/metadata_parser_filebase_unittest.cc5
-rw-r--r--chrome/browser/parsers/metadata_parser_jpeg.h1
-rw-r--r--chrome/browser/parsers/metadata_parser_jpeg_factory.cc6
-rw-r--r--chrome/browser/parsers/metadata_parser_jpeg_factory.h6
-rw-r--r--chrome/browser/parsers/metadata_parser_manager.h1
-rw-r--r--chrome/browser/password_manager/encryptor.h2
-rw-r--r--chrome/browser/password_manager/encryptor_password_mac.h1
-rw-r--r--chrome/browser/password_manager/ie7_password.cc3
-rw-r--r--chrome/browser/password_manager/ie7_password.h1
-rw-r--r--chrome/browser/password_manager/login_database.h1
-rw-r--r--chrome/browser/password_manager/login_database_posix.cc7
-rw-r--r--chrome/browser/password_manager/login_database_unittest.cc5
-rw-r--r--chrome/browser/password_manager/native_backend_gnome_x.cc7
-rw-r--r--chrome/browser/password_manager/native_backend_gnome_x.h3
-rw-r--r--chrome/browser/password_manager/native_backend_kwallet_x.cc36
-rw-r--r--chrome/browser/password_manager/native_backend_kwallet_x.h5
-rw-r--r--chrome/browser/password_manager/password_form_data.h1
-rw-r--r--chrome/browser/password_manager/password_form_manager.cc7
-rw-r--r--chrome/browser/password_manager/password_form_manager.h1
-rw-r--r--chrome/browser/password_manager/password_form_manager_unittest.cc56
-rw-r--r--chrome/browser/password_manager/password_manager.cc9
-rw-r--r--chrome/browser/password_manager/password_manager.h7
-rw-r--r--chrome/browser/password_manager/password_manager_delegate.h1
-rw-r--r--chrome/browser/password_manager/password_manager_unittest.cc11
-rw-r--r--chrome/browser/password_manager/password_store.cc3
-rw-r--r--chrome/browser/password_manager/password_store.h7
-rw-r--r--chrome/browser/password_manager/password_store_change.h1
-rw-r--r--chrome/browser/password_manager/password_store_default.cc2
-rw-r--r--chrome/browser/password_manager/password_store_default.h4
-rw-r--r--chrome/browser/password_manager/password_store_default_unittest.cc108
-rw-r--r--chrome/browser/password_manager/password_store_mac.h1
-rw-r--r--chrome/browser/password_manager/password_store_mac_internal.h1
-rw-r--r--chrome/browser/password_manager/password_store_win.cc1
-rw-r--r--chrome/browser/password_manager/password_store_win.h5
-rw-r--r--chrome/browser/password_manager/password_store_win_unittest.cc14
-rw-r--r--chrome/browser/password_manager/password_store_x.h1
-rw-r--r--chrome/browser/password_manager/password_store_x_unittest.cc18
-rw-r--r--chrome/browser/platform_util.h3
-rw-r--r--chrome/browser/platform_util_chromeos.cc15
-rw-r--r--chrome/browser/platform_util_common_linux.cc9
-rw-r--r--chrome/browser/platform_util_linux.cc1
-rw-r--r--chrome/browser/platform_util_mac.mm98
-rw-r--r--chrome/browser/platform_util_win.cc11
-rw-r--r--chrome/browser/plugin_download_helper.cc190
-rw-r--r--chrome/browser/plugin_download_helper.h80
-rw-r--r--chrome/browser/plugin_exceptions_table_model.cc191
-rw-r--r--chrome/browser/plugin_exceptions_table_model.h82
-rw-r--r--chrome/browser/plugin_exceptions_table_model_unittest.cc214
-rw-r--r--chrome/browser/plugin_installer.cc12
-rw-r--r--chrome/browser/plugin_installer.h7
-rw-r--r--chrome/browser/plugin_process_host.cc244
-rw-r--r--chrome/browser/plugin_process_host.h6
-rw-r--r--chrome/browser/plugin_service.cc49
-rw-r--r--chrome/browser/plugin_service.h24
-rw-r--r--chrome/browser/plugin_updater.cc234
-rw-r--r--chrome/browser/plugin_updater.h71
-rw-r--r--chrome/browser/popup_blocked_animation.h1
-rw-r--r--chrome/browser/popup_blocker_browsertest.cc44
-rw-r--r--chrome/browser/possible_url_model.cc37
-rw-r--r--chrome/browser/possible_url_model.h33
-rw-r--r--chrome/browser/power_save_blocker.h1
-rw-r--r--chrome/browser/power_save_blocker_stub.cc4
-rw-r--r--chrome/browser/pref_value_store.cc131
-rw-r--r--chrome/browser/pref_value_store.h129
-rw-r--r--chrome/browser/pref_value_store_unittest.cc430
-rw-r--r--chrome/browser/preferences_mac.h1
-rw-r--r--chrome/browser/preferences_mock_mac.cc1
-rw-r--r--chrome/browser/preferences_mock_mac.h1
-rw-r--r--chrome/browser/prefs/browser_prefs.cc (renamed from chrome/browser/browser_prefs.cc)28
-rw-r--r--chrome/browser/prefs/browser_prefs.h (renamed from chrome/browser/browser_prefs.h)7
-rw-r--r--chrome/browser/prefs/command_line_pref_store.cc (renamed from chrome/browser/command_line_pref_store.cc)3
-rw-r--r--chrome/browser/prefs/command_line_pref_store.h (renamed from chrome/browser/command_line_pref_store.h)11
-rw-r--r--chrome/browser/prefs/command_line_pref_store_unittest.cc (renamed from chrome/browser/command_line_pref_store_unittest.cc)26
-rw-r--r--chrome/browser/prefs/default_pref_store.cc21
-rw-r--r--chrome/browser/prefs/default_pref_store.h31
-rw-r--r--chrome/browser/prefs/dummy_pref_store.cc (renamed from chrome/browser/dummy_pref_store.cc)5
-rw-r--r--chrome/browser/prefs/dummy_pref_store.h (renamed from chrome/browser/dummy_pref_store.h)9
-rw-r--r--chrome/browser/prefs/pref_change_registrar.cc62
-rw-r--r--chrome/browser/prefs/pref_change_registrar.h57
-rw-r--r--chrome/browser/prefs/pref_change_registrar_unittest.cc121
-rw-r--r--chrome/browser/prefs/pref_member.cc (renamed from chrome/browser/pref_member.cc)20
-rw-r--r--chrome/browser/prefs/pref_member.h (renamed from chrome/browser/pref_member.h)42
-rw-r--r--chrome/browser/prefs/pref_member_unittest.cc (renamed from chrome/browser/pref_member_unittest.cc)17
-rw-r--r--chrome/browser/prefs/pref_notifier.cc139
-rw-r--r--chrome/browser/prefs/pref_notifier.h113
-rw-r--r--chrome/browser/prefs/pref_notifier_unittest.cc293
-rw-r--r--chrome/browser/prefs/pref_service.cc632
-rw-r--r--chrome/browser/prefs/pref_service.h277
-rw-r--r--chrome/browser/prefs/pref_service_uitest.cc (renamed from chrome/browser/pref_service_uitest.cc)15
-rw-r--r--chrome/browser/prefs/pref_service_unittest.cc (renamed from chrome/browser/pref_service_unittest.cc)83
-rw-r--r--chrome/browser/prefs/pref_set_observer.cc77
-rw-r--r--chrome/browser/prefs/pref_set_observer.h61
-rw-r--r--chrome/browser/prefs/pref_set_observer_unittest.cc89
-rw-r--r--chrome/browser/prefs/pref_value_store.cc342
-rw-r--r--chrome/browser/prefs/pref_value_store.h220
-rw-r--r--chrome/browser/prefs/pref_value_store_unittest.cc764
-rw-r--r--chrome/browser/prefs/scoped_pref_update.cc (renamed from chrome/browser/scoped_pref_update.cc)10
-rw-r--r--chrome/browser/prefs/scoped_pref_update.h (renamed from chrome/browser/scoped_pref_update.h)13
-rw-r--r--chrome/browser/prefs/session_startup_pref.cc (renamed from chrome/browser/session_startup_pref.cc)66
-rw-r--r--chrome/browser/prefs/session_startup_pref.h (renamed from chrome/browser/session_startup_pref.h)11
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc97
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_proxy_service.h31
-rw-r--r--chrome/browser/printing/print_dialog_cloud.cc73
-rw-r--r--chrome/browser/printing/print_dialog_cloud.h1
-rw-r--r--chrome/browser/printing/print_dialog_cloud_internal.h21
-rw-r--r--chrome/browser/printing/print_dialog_cloud_uitest.cc12
-rw-r--r--chrome/browser/printing/print_dialog_cloud_unittest.cc8
-rw-r--r--chrome/browser/printing/print_dialog_gtk.cc24
-rw-r--r--chrome/browser/printing/print_dialog_gtk.h14
-rw-r--r--chrome/browser/printing/print_job.h2
-rw-r--r--chrome/browser/printing/print_job_manager.h5
-rw-r--r--chrome/browser/printing/print_job_unittest.cc13
-rw-r--r--chrome/browser/printing/print_job_worker.cc50
-rw-r--r--chrome/browser/printing/print_job_worker.h10
-rw-r--r--chrome/browser/printing/print_job_worker_owner.h1
-rw-r--r--chrome/browser/printing/print_view_manager.cc9
-rw-r--r--chrome/browser/printing/print_view_manager.h5
-rw-r--r--chrome/browser/printing/printer_query.h1
-rw-r--r--chrome/browser/printing/printing_layout_uitest.cc44
-rw-r--r--chrome/browser/process_info_snapshot.h1
-rw-r--r--chrome/browser/process_info_snapshot_mac.cc4
-rw-r--r--chrome/browser/process_singleton.h17
-rw-r--r--chrome/browser/process_singleton_linux.cc248
-rw-r--r--chrome/browser/process_singleton_linux_uitest.cc130
-rw-r--r--chrome/browser/process_singleton_uitest.cc3
-rw-r--r--chrome/browser/process_singleton_win.cc7
-rw-r--r--chrome/browser/profile.cc1243
-rw-r--r--chrome/browser/profile.h266
-rw-r--r--chrome/browser/profile_impl.cc1322
-rw-r--r--chrome/browser/profile_impl.h258
-rw-r--r--chrome/browser/profile_import_process_host.cc29
-rw-r--r--chrome/browser/profile_import_process_host.h5
-rw-r--r--chrome/browser/profile_manager.cc13
-rw-r--r--chrome/browser/profile_manager.h54
-rw-r--r--chrome/browser/profile_manager_unittest.cc4
-rw-r--r--chrome/browser/remove_rows_table_model.h2
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_mac.cc66
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_mac.h30
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc98
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h61
-rw-r--r--chrome/browser/renderer_host/async_resource_handler.cc60
-rw-r--r--chrome/browser/renderer_host/async_resource_handler.h4
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.cc109
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.h21
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host_unittest.cc71
-rw-r--r--chrome/browser/renderer_host/audio_sync_reader.h7
-rw-r--r--chrome/browser/renderer_host/backing_store.h3
-rw-r--r--chrome/browser/renderer_host/backing_store_mac.h1
-rw-r--r--chrome/browser/renderer_host/backing_store_mac.mm1
-rw-r--r--chrome/browser/renderer_host/backing_store_manager.h1
-rw-r--r--chrome/browser/renderer_host/backing_store_proxy.h1
-rw-r--r--chrome/browser/renderer_host/backing_store_win.h1
-rw-r--r--chrome/browser/renderer_host/backing_store_x.cc13
-rw-r--r--chrome/browser/renderer_host/backing_store_x.h1
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc128
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h13
-rw-r--r--chrome/browser/renderer_host/buffered_resource_handler.cc12
-rw-r--r--chrome/browser/renderer_host/buffered_resource_handler.h1
-rw-r--r--chrome/browser/renderer_host/cross_site_resource_handler.cc6
-rw-r--r--chrome/browser/renderer_host/cross_site_resource_handler.h1
-rw-r--r--chrome/browser/renderer_host/database_dispatcher_host.cc25
-rw-r--r--chrome/browser/renderer_host/database_dispatcher_host.h1
-rw-r--r--chrome/browser/renderer_host/database_permission_request.cc90
-rw-r--r--chrome/browser/renderer_host/database_permission_request.h65
-rw-r--r--chrome/browser/renderer_host/download_resource_handler.cc31
-rw-r--r--chrome/browser/renderer_host/download_resource_handler.h10
-rw-r--r--chrome/browser/renderer_host/download_throttling_resource_handler.cc2
-rw-r--r--chrome/browser/renderer_host/download_throttling_resource_handler.h1
-rw-r--r--chrome/browser/renderer_host/global_request_id.h1
-rw-r--r--chrome/browser/renderer_host/gpu_view_host.h1
-rw-r--r--chrome/browser/renderer_host/gtk_im_context_wrapper.cc32
-rw-r--r--chrome/browser/renderer_host/gtk_im_context_wrapper.h16
-rw-r--r--chrome/browser/renderer_host/gtk_key_bindings_handler.h3
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.cc40
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.h30
-rw-r--r--chrome/browser/renderer_host/offline_resource_handler.h1
-rw-r--r--chrome/browser/renderer_host/render_process_host.h8
-rw-r--r--chrome/browser/renderer_host/render_sandbox_host_linux.cc49
-rw-r--r--chrome/browser/renderer_host/render_sandbox_host_linux.h1
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc333
-rw-r--r--chrome/browser/renderer_host/render_view_host.h91
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.cc18
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h165
-rw-r--r--chrome/browser/renderer_host/render_view_host_factory.cc6
-rw-r--r--chrome/browser/renderer_host/render_view_host_factory.h6
-rw-r--r--chrome/browser/renderer_host/render_view_host_notification_task.h16
-rw-r--r--chrome/browser/renderer_host/render_widget_helper.cc21
-rw-r--r--chrome/browser/renderer_host/render_widget_helper.h9
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc204
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h55
-rw-r--r--chrome/browser/renderer_host/render_widget_host_painting_observer.h7
-rw-r--r--chrome/browser/renderer_host/render_widget_host_unittest.cc6
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view.h29
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc265
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.h32
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.h51
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm741
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc105
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.h17
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc107
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.h37
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc6
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_request_info.h14
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc61
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc5
-rw-r--r--chrome/browser/renderer_host/resource_handler.h7
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc540
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h151
-rw-r--r--chrome/browser/renderer_host/resource_message_filter_gtk.cc1
-rw-r--r--chrome/browser/renderer_host/resource_message_filter_win.cc1
-rw-r--r--chrome/browser/renderer_host/resource_queue.h1
-rw-r--r--chrome/browser/renderer_host/resource_queue_unittest.cc1
-rw-r--r--chrome/browser/renderer_host/resource_request_details.h1
-rw-r--r--chrome/browser/renderer_host/safe_browsing_resource_handler.cc19
-rw-r--r--chrome/browser/renderer_host/safe_browsing_resource_handler.h2
-rw-r--r--chrome/browser/renderer_host/save_file_resource_handler.cc8
-rw-r--r--chrome/browser/renderer_host/save_file_resource_handler.h1
-rw-r--r--chrome/browser/renderer_host/site_instance.h2
-rw-r--r--chrome/browser/renderer_host/socket_stream_dispatcher_host.h1
-rw-r--r--chrome/browser/renderer_host/socket_stream_host.h7
-rw-r--r--chrome/browser/renderer_host/sync_resource_handler.cc29
-rw-r--r--chrome/browser/renderer_host/sync_resource_handler.h12
-rw-r--r--chrome/browser/renderer_host/test/render_view_host_manager_browsertest.cc40
-rw-r--r--chrome/browser/renderer_host/test/render_view_host_unittest.cc39
-rw-r--r--chrome/browser/renderer_host/test/site_instance_unittest.cc6
-rw-r--r--chrome/browser/renderer_host/test/test_backing_store.h1
-rw-r--r--chrome/browser/renderer_host/test/test_render_view_host.cc127
-rw-r--r--chrome/browser/renderer_host/test/test_render_view_host.h106
-rw-r--r--chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc1
-rw-r--r--chrome/browser/renderer_host/video_layer.h2
-rw-r--r--chrome/browser/renderer_host/video_layer_proxy.h1
-rw-r--r--chrome/browser/renderer_host/video_layer_x.h3
-rw-r--r--chrome/browser/renderer_host/web_cache_manager.cc2
-rw-r--r--chrome/browser/renderer_host/web_cache_manager.h4
-rw-r--r--chrome/browser/renderer_host/x509_user_cert_resource_handler.cc18
-rw-r--r--chrome/browser/renderer_host/x509_user_cert_resource_handler.h20
-rw-r--r--chrome/browser/renderer_preferences_util.cc6
-rw-r--r--chrome/browser/renderer_preferences_util.h1
-rw-r--r--chrome/browser/repost_form_warning_controller.h3
-rw-r--r--chrome/browser/repost_form_warning_uitest.cc30
-rw-r--r--chrome/browser/resources/about_memory.html303
-rw-r--r--chrome/browser/resources/about_memory_linux.html301
-rw-r--r--chrome/browser/resources/about_memory_mac.html301
-rw-r--r--chrome/browser/resources/about_sys.html186
-rw-r--r--chrome/browser/resources/amex.pngbin1316 -> 0 bytes
-rw-r--r--chrome/browser/resources/bookmark_manager/css/bmm.css36
-rw-r--r--chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js20
-rw-r--r--chrome/browser/resources/bookmark_manager/js/bmm/bookmark_tree.js2
-rw-r--r--chrome/browser/resources/bookmark_manager/main.html32
-rw-r--r--chrome/browser/resources/cc-generic.pngbin304 -> 0 bytes
-rw-r--r--chrome/browser/resources/chat_manager/background.html33
-rw-r--r--chrome/browser/resources/chat_manager/central_roster.html126
-rw-r--r--chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js6
-rw-r--r--chrome/browser/resources/chat_manager/js/chatbridgehook.js106
-rw-r--r--chrome/browser/resources/chat_manager/js/gmailbridgehook.js81
-rw-r--r--chrome/browser/resources/chat_manager/manifest.json15
-rw-r--r--chrome/browser/resources/diners.pngbin1018 -> 0 bytes
-rw-r--r--chrome/browser/resources/discover.pngbin933 -> 0 bytes
-rw-r--r--chrome/browser/resources/downloads.html29
-rw-r--r--chrome/browser/resources/extension_default_icon.pngbin3932 -> 0 bytes
-rw-r--r--chrome/browser/resources/extensions_infobar_mac.css4
-rw-r--r--chrome/browser/resources/extensions_toolstrip.css8
-rw-r--r--chrome/browser/resources/extensions_ui.html37
-rw-r--r--chrome/browser/resources/filebrowse.html280
-rw-r--r--chrome/browser/resources/history2.html249
-rw-r--r--chrome/browser/resources/host_registration_page.html61
-rw-r--r--chrome/browser/resources/incognito_tab.html8
-rw-r--r--chrome/browser/resources/jcb.pngbin1103 -> 0 bytes
-rw-r--r--chrome/browser/resources/mastercard.pngbin1250 -> 0 bytes
-rw-r--r--chrome/browser/resources/mediaplayer.html6
-rw-r--r--chrome/browser/resources/net_internals/dataview.js199
-rw-r--r--chrome/browser/resources/net_internals/index.html190
-rw-r--r--chrome/browser/resources/net_internals/loggrouper.js2
-rw-r--r--chrome/browser/resources/net_internals/logviewpainter.js182
-rw-r--r--chrome/browser/resources/net_internals/main.css53
-rw-r--r--chrome/browser/resources/net_internals/main.js210
-rw-r--r--chrome/browser/resources/net_internals/proxyview.js19
-rw-r--r--chrome/browser/resources/net_internals/requestsview.js207
-rw-r--r--chrome/browser/resources/net_internals/sourceentry.js169
-rw-r--r--chrome/browser/resources/net_internals/util.js167
-rw-r--r--chrome/browser/resources/new_new_tab.css319
-rw-r--r--chrome/browser/resources/new_new_tab.html168
-rw-r--r--chrome/browser/resources/new_new_tab.js735
-rw-r--r--chrome/browser/resources/new_tab_theme.css72
-rw-r--r--chrome/browser/resources/notification_1line.html1
-rw-r--r--chrome/browser/resources/notification_2line.html3
-rw-r--r--chrome/browser/resources/notification_icon.html2
-rw-r--r--chrome/browser/resources/ntp/apps.css90
-rw-r--r--chrome/browser/resources/ntp/apps.js333
-rw-r--r--chrome/browser/resources/ntp/most_visited.css30
-rw-r--r--chrome/browser/resources/ntp/most_visited.js86
-rw-r--r--chrome/browser/resources/ntp/util.js9
-rw-r--r--chrome/browser/resources/options.html302
-rw-r--r--chrome/browser/resources/options/advanced_options.html249
-rw-r--r--chrome/browser/resources/options/advanced_options.js241
-rw-r--r--chrome/browser/resources/options/browser_options.html68
-rw-r--r--chrome/browser/resources/options/browser_options.js337
-rw-r--r--chrome/browser/resources/options/browser_options_page.css21
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_add_user_overlay.html15
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_add_user_overlay.js60
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_options.html28
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_options.js116
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_options_page.css83
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_user_list.js146
-rw-r--r--chrome/browser/resources/options/chromeos_labs.html13
-rw-r--r--chrome/browser/resources/options/chromeos_language_hangul_options.html6
-rw-r--r--chrome/browser/resources/options/chromeos_language_hangul_options.js32
-rw-r--r--chrome/browser/resources/options/chromeos_language_options.css113
-rw-r--r--chrome/browser/resources/options/chromeos_language_options.html46
-rw-r--r--chrome/browser/resources/options/chromeos_system_options.html33
-rw-r--r--chrome/browser/resources/options/chromeos_system_options.js68
-rw-r--r--chrome/browser/resources/options/clear_browser_data_overlay.html61
-rw-r--r--chrome/browser/resources/options/clear_browser_data_overlay.js136
-rw-r--r--chrome/browser/resources/options/content_settings.html285
-rw-r--r--chrome/browser/resources/options/content_settings.js227
-rw-r--r--chrome/browser/resources/options/content_settings_page.css16
-rw-r--r--chrome/browser/resources/options/content_settings_ui.js54
-rw-r--r--chrome/browser/resources/options/font_settings_overlay.html3
-rw-r--r--chrome/browser/resources/options/font_settings_overlay.js31
-rw-r--r--chrome/browser/resources/options/options_page.css275
-rw-r--r--chrome/browser/resources/options/options_page.js394
-rw-r--r--chrome/browser/resources/options/personal_options.html93
-rw-r--r--chrome/browser/resources/options/personal_options.js149
-rw-r--r--chrome/browser/resources/options/pref_ui.js533
-rw-r--r--chrome/browser/resources/options/preferences.js283
-rw-r--r--chrome/browser/resources/options/sync_options.html19
-rw-r--r--chrome/browser/resources/playlist.html6
-rw-r--r--chrome/browser/resources/plugins.html46
-rw-r--r--chrome/browser/resources/shared/css/list.css1
-rw-r--r--chrome/browser/resources/shared/css/menu.css25
-rw-r--r--chrome/browser/resources/shared/js/cr.js42
-rw-r--r--chrome/browser/resources/shared/js/cr/ui.js12
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/array_data_model.js15
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/command.js12
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/context_menu_handler.js5
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/list.js28
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/list_selection_model.js313
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/list_selection_model_test.html2
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/menu_item.js11
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/position_util.js11
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/splitter.js6
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/tree.js4
-rw-r--r--chrome/browser/resources/shared/js/cr_test.html27
-rw-r--r--chrome/browser/resources/shared/js/media_common.js4
-rw-r--r--chrome/browser/resources/shared_resources.grd6
-rw-r--r--chrome/browser/resources/solo.pngbin751 -> 0 bytes
-rw-r--r--chrome/browser/resources/visa.pngbin993 -> 0 bytes
-rw-r--r--chrome/browser/resources_util.cc7
-rw-r--r--chrome/browser/resources_util.h7
-rw-r--r--chrome/browser/rlz/rlz.cc6
-rw-r--r--chrome/browser/rlz/rlz.h1
-rw-r--r--chrome/browser/safe_browsing/bloom_filter.cc15
-rw-r--r--chrome/browser/safe_browsing/bloom_filter.h13
-rw-r--r--chrome/browser/safe_browsing/bloom_filter_unittest.cc3
-rw-r--r--chrome/browser/safe_browsing/chunk_range.cc6
-rw-r--r--chrome/browser/safe_browsing/chunk_range.h1
-rw-r--r--chrome/browser/safe_browsing/filter_false_positive_perftest.cc36
-rw-r--r--chrome/browser/safe_browsing/protocol_manager.cc43
-rw-r--r--chrome/browser/safe_browsing/protocol_manager.h15
-rw-r--r--chrome/browser/safe_browsing/protocol_manager_unittest.cc27
-rw-r--r--chrome/browser/safe_browsing/protocol_parser.cc3
-rw-r--r--chrome/browser/safe_browsing/protocol_parser.h1
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.cc106
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.h6
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc3
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_browsertest.cc196
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database.cc670
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database.h182
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database_bloom.cc105
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database_bloom.h66
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database_unittest.cc510
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.cc85
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.h19
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store.cc32
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store.h13
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_file.cc209
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_file.h59
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc83
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_sqlite.h9
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_unittest.cc92
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h1
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_util.cc2
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_util.h2
-rw-r--r--chrome/browser/sanity_uitest.cc36
-rw-r--r--chrome/browser/search_engines/edit_search_engine_controller.cc19
-rw-r--r--chrome/browser/search_engines/edit_search_engine_controller.h17
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller.cc26
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller.h13
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller_unittest.cc129
-rw-r--r--chrome/browser/search_engines/template_url.cc165
-rw-r--r--chrome/browser/search_engines/template_url.h121
-rw-r--r--chrome/browser/search_engines/template_url_fetcher.h1
-rw-r--r--chrome/browser/search_engines/template_url_id.h11
-rw-r--r--chrome/browser/search_engines/template_url_model.cc701
-rw-r--r--chrome/browser/search_engines/template_url_model.h80
-rw-r--r--chrome/browser/search_engines/template_url_model_unittest.cc737
-rw-r--r--chrome/browser/search_engines/template_url_parser.cc13
-rw-r--r--chrome/browser/search_engines/template_url_parser.h4
-rw-r--r--chrome/browser/search_engines/template_url_prepopulate_data.cc463
-rw-r--r--chrome/browser/search_engines/template_url_prepopulate_data.h34
-rw-r--r--chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc8
-rw-r--r--chrome/browser/search_engines/template_url_table_model.cc37
-rw-r--r--chrome/browser/search_engines/template_url_table_model.h11
-rw-r--r--chrome/browser/search_engines/template_url_unittest.cc70
-rw-r--r--chrome/browser/search_engines/util.cc171
-rw-r--r--chrome/browser/search_engines/util.h25
-rw-r--r--chrome/browser/session_history_uitest.cc118
-rw-r--r--chrome/browser/sessions/base_session_service.h4
-rw-r--r--chrome/browser/sessions/session_backend.cc4
-rw-r--r--chrome/browser/sessions/session_backend.h10
-rw-r--r--chrome/browser/sessions/session_command.h1
-rw-r--r--chrome/browser/sessions/session_id.h1
-rw-r--r--chrome/browser/sessions/session_restore.cc43
-rw-r--r--chrome/browser/sessions/session_restore.h7
-rw-r--r--chrome/browser/sessions/session_restore_browsertest.cc10
-rw-r--r--chrome/browser/sessions/session_restore_uitest.cc100
-rw-r--r--chrome/browser/sessions/session_service.cc3
-rw-r--r--chrome/browser/sessions/session_service.h2
-rw-r--r--chrome/browser/sessions/session_service_test_helper.h1
-rw-r--r--chrome/browser/sessions/session_service_unittest.cc16
-rw-r--r--chrome/browser/sessions/session_types.cc66
-rw-r--r--chrome/browser/sessions/session_types.h40
-rw-r--r--chrome/browser/sessions/tab_restore_service.cc24
-rw-r--r--chrome/browser/sessions/tab_restore_service.h33
-rw-r--r--chrome/browser/sessions/tab_restore_service_unittest.cc484
-rw-r--r--chrome/browser/shell_dialogs.h10
-rw-r--r--chrome/browser/shell_integration.cc14
-rw-r--r--chrome/browser/shell_integration.h8
-rw-r--r--chrome/browser/shell_integration_linux.cc55
-rw-r--r--chrome/browser/shell_integration_unittest.cc39
-rw-r--r--chrome/browser/shell_integration_win.cc11
-rw-r--r--chrome/browser/spellcheck_host.cc17
-rw-r--r--chrome/browser/spellcheck_host.h1
-rw-r--r--chrome/browser/spellcheck_host_observer.h7
-rw-r--r--chrome/browser/spellchecker_platform_engine.h1
-rw-r--r--chrome/browser/spellchecker_platform_engine_unittest.cc1
-rw-r--r--chrome/browser/ssl/ssl_add_cert_handler.cc75
-rw-r--r--chrome/browser/ssl/ssl_add_cert_handler.h21
-rw-r--r--chrome/browser/ssl/ssl_add_cert_handler_mac.mm1
-rw-r--r--chrome/browser/ssl/ssl_blocking_page.cc43
-rw-r--r--chrome/browser/ssl/ssl_blocking_page.h4
-rw-r--r--chrome/browser/ssl/ssl_browser_tests.cc365
-rw-r--r--chrome/browser/ssl/ssl_cert_error_handler.h1
-rw-r--r--chrome/browser/ssl/ssl_client_auth_handler.h1
-rw-r--r--chrome/browser/ssl/ssl_error_handler.h1
-rw-r--r--chrome/browser/ssl/ssl_error_info.cc10
-rw-r--r--chrome/browser/ssl/ssl_error_info.h2
-rw-r--r--chrome/browser/ssl/ssl_host_state.h1
-rw-r--r--chrome/browser/ssl/ssl_manager.cc25
-rw-r--r--chrome/browser/ssl/ssl_manager.h29
-rw-r--r--chrome/browser/ssl/ssl_policy.cc8
-rw-r--r--chrome/browser/ssl/ssl_policy.h1
-rw-r--r--chrome/browser/ssl/ssl_policy_backend.cc109
-rw-r--r--chrome/browser/ssl/ssl_policy_backend.h51
-rw-r--r--chrome/browser/ssl/ssl_request_info.h1
-rw-r--r--chrome/browser/ssl_client_certificate_selector.h19
-rw-r--r--chrome/browser/status_bubble.h7
-rw-r--r--chrome/browser/status_icons/status_icon.cc18
-rw-r--r--chrome/browser/status_icons/status_icon.h36
-rw-r--r--chrome/browser/status_icons/status_icon_unittest.cc2
-rw-r--r--chrome/browser/status_icons/status_tray.cc26
-rw-r--r--chrome/browser/status_icons/status_tray.h36
-rw-r--r--chrome/browser/status_icons/status_tray_manager.cc56
-rw-r--r--chrome/browser/status_icons/status_tray_manager.h30
-rw-r--r--chrome/browser/status_icons/status_tray_unittest.cc40
-rw-r--r--chrome/browser/sync/abstract_profile_sync_service_test.h33
-rw-r--r--chrome/browser/sync/engine/all_status.cc78
-rw-r--r--chrome/browser/sync/engine/all_status.h14
-rw-r--r--chrome/browser/sync/engine/all_status_unittest.cc24
-rw-r--r--chrome/browser/sync/engine/apply_updates_command.cc1
-rw-r--r--chrome/browser/sync/engine/apply_updates_command.h2
-rw-r--r--chrome/browser/sync/engine/auth_watcher.cc351
-rw-r--r--chrome/browser/sync/engine/auth_watcher.h218
-rw-r--r--chrome/browser/sync/engine/auth_watcher_unittest.cc234
-rw-r--r--chrome/browser/sync/engine/authenticator.cc110
-rw-r--r--chrome/browser/sync/engine/authenticator.h104
-rw-r--r--chrome/browser/sync/engine/build_and_process_conflict_sets_command.cc11
-rw-r--r--chrome/browser/sync/engine/build_and_process_conflict_sets_command.h1
-rw-r--r--chrome/browser/sync/engine/build_commit_command.cc6
-rw-r--r--chrome/browser/sync/engine/build_commit_command.h1
-rw-r--r--chrome/browser/sync/engine/change_reorder_buffer.cc10
-rw-r--r--chrome/browser/sync/engine/change_reorder_buffer.h14
-rw-r--r--chrome/browser/sync/engine/cleanup_disabled_types_command.h1
-rw-r--r--chrome/browser/sync/engine/conflict_resolver.h1
-rw-r--r--chrome/browser/sync/engine/download_updates_command.cc5
-rw-r--r--chrome/browser/sync/engine/download_updates_command.h1
-rw-r--r--chrome/browser/sync/engine/get_commit_ids_command.cc1
-rw-r--r--chrome/browser/sync/engine/get_commit_ids_command.h2
-rw-r--r--chrome/browser/sync/engine/idle_query_linux.h1
-rw-r--r--chrome/browser/sync/engine/mock_model_safe_workers.h1
-rw-r--r--chrome/browser/sync/engine/model_changing_syncer_command.h1
-rw-r--r--chrome/browser/sync/engine/model_safe_worker.h2
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.cc20
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.h30
-rw-r--r--chrome/browser/sync/engine/net/syncapi_server_connection_manager.h5
-rw-r--r--chrome/browser/sync/engine/net/url_translator.cc3
-rw-r--r--chrome/browser/sync/engine/net/url_translator.h1
-rw-r--r--chrome/browser/sync/engine/post_commit_message_command.cc1
-rw-r--r--chrome/browser/sync/engine/post_commit_message_command.h2
-rw-r--r--chrome/browser/sync/engine/process_commit_response_command.h1
-rw-r--r--chrome/browser/sync/engine/process_updates_command.cc39
-rw-r--r--chrome/browser/sync/engine/process_updates_command.h1
-rw-r--r--chrome/browser/sync/engine/resolve_conflicts_command.h1
-rw-r--r--chrome/browser/sync/engine/store_timestamps_command.h1
-rw-r--r--chrome/browser/sync/engine/syncapi.cc736
-rw-r--r--chrome/browser/sync/engine/syncapi.h172
-rw-r--r--chrome/browser/sync/engine/syncapi_unittest.cc2
-rw-r--r--chrome/browser/sync/engine/syncer.cc52
-rw-r--r--chrome/browser/sync/engine/syncer.h13
-rw-r--r--chrome/browser/sync/engine/syncer_command.cc1
-rw-r--r--chrome/browser/sync/engine/syncer_command.h1
-rw-r--r--chrome/browser/sync/engine/syncer_end_command.cc1
-rw-r--r--chrome/browser/sync/engine/syncer_end_command.h1
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util.cc15
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util.h4
-rw-r--r--chrome/browser/sync/engine/syncer_proto_util_unittest.cc2
-rw-r--r--chrome/browser/sync/engine/syncer_thread.cc130
-rw-r--r--chrome/browser/sync/engine/syncer_thread.h52
-rw-r--r--chrome/browser/sync/engine/syncer_thread_unittest.cc114
-rw-r--r--chrome/browser/sync/engine/syncer_types.h13
-rw-r--r--chrome/browser/sync/engine/syncer_unittest.cc19
-rw-r--r--chrome/browser/sync/engine/syncer_util.cc1
-rw-r--r--chrome/browser/sync/engine/syncer_util.h2
-rw-r--r--chrome/browser/sync/engine/syncproto.h2
-rw-r--r--chrome/browser/sync/engine/update_applicator.cc3
-rw-r--r--chrome/browser/sync/engine/update_applicator.h7
-rw-r--r--chrome/browser/sync/engine/verify_updates_command.h1
-rw-r--r--chrome/browser/sync/glue/autofill_change_processor.cc131
-rw-r--r--chrome/browser/sync/glue/autofill_change_processor.h39
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller.h1
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator.cc14
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator.h11
-rw-r--r--chrome/browser/sync/glue/bookmark_change_processor.cc18
-rw-r--r--chrome/browser/sync/glue/bookmark_change_processor.h4
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.h1
-rw-r--r--chrome/browser/sync/glue/bookmark_model_associator.cc7
-rw-r--r--chrome/browser/sync/glue/bookmark_model_associator.h1
-rw-r--r--chrome/browser/sync/glue/change_processor.h8
-rw-r--r--chrome/browser/sync/glue/change_processor_mock.h1
-rw-r--r--chrome/browser/sync/glue/data_type_controller.h1
-rw-r--r--chrome/browser/sync/glue/data_type_controller_mock.h1
-rw-r--r--chrome/browser/sync/glue/data_type_manager.h1
-rw-r--r--chrome/browser/sync/glue/data_type_manager_impl.cc5
-rw-r--r--chrome/browser/sync/glue/data_type_manager_impl.h2
-rw-r--r--chrome/browser/sync/glue/data_type_manager_mock.h18
-rw-r--r--chrome/browser/sync/glue/database_model_worker.cc1
-rw-r--r--chrome/browser/sync/glue/database_model_worker.h7
-rw-r--r--chrome/browser/sync/glue/extension_change_processor.cc95
-rw-r--r--chrome/browser/sync/glue/extension_change_processor.h15
-rw-r--r--chrome/browser/sync/glue/extension_data.h1
-rw-r--r--chrome/browser/sync/glue/extension_data_type_controller.cc5
-rw-r--r--chrome/browser/sync/glue/extension_data_type_controller.h1
-rw-r--r--chrome/browser/sync/glue/extension_model_associator.cc397
-rw-r--r--chrome/browser/sync/glue/extension_model_associator.h68
-rw-r--r--chrome/browser/sync/glue/extension_util.cc33
-rw-r--r--chrome/browser/sync/glue/extension_util.h32
-rw-r--r--chrome/browser/sync/glue/extension_util_unittest.cc156
-rw-r--r--chrome/browser/sync/glue/history_model_worker.cc4
-rw-r--r--chrome/browser/sync/glue/history_model_worker.h9
-rw-r--r--chrome/browser/sync/glue/http_bridge.cc8
-rw-r--r--chrome/browser/sync/glue/http_bridge.h1
-rw-r--r--chrome/browser/sync/glue/http_bridge_unittest.cc35
-rw-r--r--chrome/browser/sync/glue/model_associator.h6
-rw-r--r--chrome/browser/sync/glue/model_associator_mock.h1
-rw-r--r--chrome/browser/sync/glue/password_change_processor.cc24
-rw-r--r--chrome/browser/sync/glue/password_change_processor.h4
-rw-r--r--chrome/browser/sync/glue/password_data_type_controller.h1
-rw-r--r--chrome/browser/sync/glue/password_model_associator.cc6
-rw-r--r--chrome/browser/sync/glue/password_model_associator.h3
-rw-r--r--chrome/browser/sync/glue/password_model_worker.cc2
-rw-r--r--chrome/browser/sync/glue/password_model_worker.h1
-rw-r--r--chrome/browser/sync/glue/preference_change_processor.cc77
-rw-r--r--chrome/browser/sync/glue/preference_change_processor.h14
-rw-r--r--chrome/browser/sync/glue/preference_data_type_controller.h1
-rw-r--r--chrome/browser/sync/glue/preference_model_associator.cc142
-rw-r--r--chrome/browser/sync/glue/preference_model_associator.h31
-rw-r--r--chrome/browser/sync/glue/preference_model_associator_unittest.cc54
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc305
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h180
-rw-r--r--chrome/browser/sync/glue/sync_backend_host_mock.h1
-rw-r--r--chrome/browser/sync/glue/synchronized_preferences.h71
-rw-r--r--chrome/browser/sync/glue/theme_change_processor.cc2
-rw-r--r--chrome/browser/sync/glue/theme_change_processor.h1
-rw-r--r--chrome/browser/sync/glue/theme_data_type_controller.h1
-rw-r--r--chrome/browser/sync/glue/theme_model_associator.cc2
-rw-r--r--chrome/browser/sync/glue/theme_model_associator.h1
-rw-r--r--chrome/browser/sync/glue/theme_util.cc12
-rw-r--r--chrome/browser/sync/glue/theme_util.h1
-rw-r--r--chrome/browser/sync/glue/typed_url_change_processor.cc1
-rw-r--r--chrome/browser/sync/glue/typed_url_change_processor.h3
-rw-r--r--chrome/browser/sync/glue/typed_url_data_type_controller.h8
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator.cc5
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator.h3
-rw-r--r--chrome/browser/sync/glue/ui_model_worker.h6
-rw-r--r--chrome/browser/sync/glue/ui_model_worker_unittest.cc1
-rw-r--r--chrome/browser/sync/notification_method.cc53
-rw-r--r--chrome/browser/sync/notification_method.h67
-rw-r--r--chrome/browser/sync/notifier/cache_invalidation_packet_handler.cc53
-rw-r--r--chrome/browser/sync/notifier/cache_invalidation_packet_handler.h17
-rw-r--r--chrome/browser/sync/notifier/chrome_invalidation_client.cc29
-rw-r--r--chrome/browser/sync/notifier/chrome_invalidation_client.h9
-rw-r--r--chrome/browser/sync/notifier/chrome_system_resources.h1
-rw-r--r--chrome/browser/sync/notifier/invalidation_util.h1
-rw-r--r--chrome/browser/sync/notifier/registration_manager.cc3
-rw-r--r--chrome/browser/sync/notifier/registration_manager.h1
-rw-r--r--chrome/browser/sync/notifier/registration_manager_unittest.cc1
-rw-r--r--chrome/browser/sync/notifier/server_notifier_thread.cc44
-rw-r--r--chrome/browser/sync/notifier/server_notifier_thread.h13
-rw-r--r--chrome/browser/sync/profile_sync_factory.h20
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.cc61
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.h14
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl_unittest.cc46
-rw-r--r--chrome/browser/sync/profile_sync_factory_mock.h11
-rw-r--r--chrome/browser/sync/profile_sync_service.cc535
-rw-r--r--chrome/browser/sync/profile_sync_service.h137
-rw-r--r--chrome/browser/sync/profile_sync_service_autofill_unittest.cc295
-rw-r--r--chrome/browser/sync/profile_sync_service_mock.h2
-rw-r--r--chrome/browser/sync/profile_sync_service_observer.h1
-rw-r--r--chrome/browser/sync/profile_sync_service_password_unittest.cc26
-rw-r--r--chrome/browser/sync/profile_sync_service_preference_unittest.cc126
-rw-r--r--chrome/browser/sync/profile_sync_service_startup_unittest.cc70
-rw-r--r--chrome/browser/sync/profile_sync_service_typed_url_unittest.cc27
-rw-r--r--chrome/browser/sync/profile_sync_service_unittest.cc136
-rw-r--r--chrome/browser/sync/profile_sync_test_util.h3
-rw-r--r--chrome/browser/sync/protocol/encryption.proto7
-rw-r--r--chrome/browser/sync/protocol/nigori_specifics.proto6
-rw-r--r--chrome/browser/sync/protocol/service_constants.h3
-rw-r--r--chrome/browser/sync/protocol/sync.proto66
-rw-r--r--chrome/browser/sync/protocol/sync_proto.gyp3
-rw-r--r--chrome/browser/sync/protocol/sync_proto.target.mk101
-rw-r--r--chrome/browser/sync/resources/about_sync.html6
-rw-r--r--chrome/browser/sync/resources/choose_datatypes.html68
-rw-r--r--chrome/browser/sync/resources/gaia_login.html66
-rw-r--r--chrome/browser/sync/resources/setup_done.html89
-rw-r--r--chrome/browser/sync/resources/setup_flow.html18
-rw-r--r--chrome/browser/sync/sessions/ordered_commit_set.cc2
-rw-r--r--chrome/browser/sync/sessions/ordered_commit_set.h1
-rw-r--r--chrome/browser/sync/sessions/session_state.h1
-rw-r--r--chrome/browser/sync/sessions/status_controller.cc10
-rw-r--r--chrome/browser/sync/sessions/status_controller.h1
-rw-r--r--chrome/browser/sync/sessions/sync_session.h4
-rw-r--r--chrome/browser/sync/sessions/sync_session_context.h19
-rw-r--r--chrome/browser/sync/sessions/sync_session_unittest.cc8
-rw-r--r--chrome/browser/sync/sync_constants.h1
-rw-r--r--chrome/browser/sync/sync_setup_flow.cc104
-rw-r--r--chrome/browser/sync/sync_setup_flow.h5
-rw-r--r--chrome/browser/sync/sync_setup_wizard.cc166
-rw-r--r--chrome/browser/sync/sync_setup_wizard.h1
-rw-r--r--chrome/browser/sync/sync_setup_wizard_unittest.cc43
-rw-r--r--chrome/browser/sync/sync_ui_util.cc18
-rw-r--r--chrome/browser/sync/sync_ui_util.h1
-rw-r--r--chrome/browser/sync/sync_ui_util_mac.h1
-rw-r--r--chrome/browser/sync/syncable/blob.h1
-rw-r--r--chrome/browser/sync/syncable/dir_open_result.h1
-rw-r--r--chrome/browser/sync/syncable/directory_backing_store.cc98
-rw-r--r--chrome/browser/sync/syncable/directory_backing_store.h11
-rw-r--r--chrome/browser/sync/syncable/directory_backing_store_unittest.cc13
-rw-r--r--chrome/browser/sync/syncable/directory_event.h1
-rw-r--r--chrome/browser/sync/syncable/directory_manager.cc11
-rw-r--r--chrome/browser/sync/syncable/directory_manager.h6
-rw-r--r--chrome/browser/sync/syncable/model_type.cc49
-rw-r--r--chrome/browser/sync/syncable/model_type.h7
-rw-r--r--chrome/browser/sync/syncable/path_name_cmp.h3
-rw-r--r--chrome/browser/sync/syncable/syncable-inl.h1
-rw-r--r--chrome/browser/sync/syncable/syncable.cc116
-rw-r--r--chrome/browser/sync/syncable/syncable.h16
-rw-r--r--chrome/browser/sync/syncable/syncable_changes_version.h1
-rw-r--r--chrome/browser/sync/syncable/syncable_columns.h1
-rw-r--r--chrome/browser/sync/syncable/syncable_id.cc7
-rw-r--r--chrome/browser/sync/syncable/syncable_id.h16
-rw-r--r--chrome/browser/sync/syncable/syncable_unittest.cc4
-rw-r--r--chrome/browser/sync/test_profile_sync_service.h157
-rw-r--r--chrome/browser/sync/tools/sync_listen_notifications.cc227
-rw-r--r--chrome/browser/sync/tools/sync_listen_notifications.target.mk10
-rw-r--r--chrome/browser/sync/unrecoverable_error_handler.h1
-rw-r--r--chrome/browser/sync/util/channel.h4
-rw-r--r--chrome/browser/sync/util/crypto_helpers.cc7
-rw-r--r--chrome/browser/sync/util/crypto_helpers.h5
-rw-r--r--chrome/browser/sync/util/cryptographer.cc114
-rw-r--r--chrome/browser/sync/util/cryptographer.h28
-rw-r--r--chrome/browser/sync/util/cryptographer_unittest.cc44
-rw-r--r--chrome/browser/sync/util/data_encryption.cc4
-rw-r--r--chrome/browser/sync/util/data_encryption.h5
-rw-r--r--chrome/browser/sync/util/dbgq.h1
-rw-r--r--chrome/browser/sync/util/extensions_activity_monitor.h4
-rw-r--r--chrome/browser/sync/util/extensions_activity_monitor_unittest.cc1
-rw-r--r--chrome/browser/sync/util/fast_dump.h22
-rw-r--r--chrome/browser/sync/util/nigori.cc40
-rw-r--r--chrome/browser/sync/util/nigori.h31
-rw-r--r--chrome/browser/sync/util/nigori_unittest.cc90
-rw-r--r--chrome/browser/sync/util/sync_types.h38
-rw-r--r--chrome/browser/sync/util/user_settings.cc5
-rw-r--r--chrome/browser/sync/util/user_settings.h8
-rw-r--r--chrome/browser/sync/util/user_settings_posix.cc1
-rw-r--r--chrome/browser/sync/util/user_settings_win.cc3
-rw-r--r--chrome/browser/tab_closeable_state_watcher.cc1
-rw-r--r--chrome/browser/tab_closeable_state_watcher.h1
-rw-r--r--chrome/browser/tab_contents/background_contents.cc68
-rw-r--r--chrome/browser/tab_contents/background_contents.h47
-rw-r--r--chrome/browser/tab_contents/constrained_window.h4
-rw-r--r--chrome/browser/tab_contents/infobar_delegate.cc12
-rw-r--r--chrome/browser/tab_contents/infobar_delegate.h32
-rw-r--r--chrome/browser/tab_contents/interstitial_page.cc96
-rw-r--r--chrome/browser/tab_contents/interstitial_page.h18
-rw-r--r--chrome/browser/tab_contents/language_state.cc9
-rw-r--r--chrome/browser/tab_contents/language_state.h6
-rw-r--r--chrome/browser/tab_contents/navigation_controller.cc187
-rw-r--r--chrome/browser/tab_contents/navigation_controller.h69
-rw-r--r--chrome/browser/tab_contents/navigation_controller_unittest.cc179
-rw-r--r--chrome/browser/tab_contents/navigation_entry.cc12
-rw-r--r--chrome/browser/tab_contents/navigation_entry.h2
-rw-r--r--chrome/browser/tab_contents/navigation_entry_unittest.cc3
-rw-r--r--chrome/browser/tab_contents/page_navigator.h4
-rw-r--r--chrome/browser/tab_contents/provisional_load_details.cc1
-rw-r--r--chrome/browser/tab_contents/provisional_load_details.h10
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu.cc132
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu.h7
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_gtk.h6
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_mac.h4
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_mac.mm31
-rw-r--r--chrome/browser/tab_contents/render_view_host_delegate_helper.cc33
-rw-r--r--chrome/browser/tab_contents/render_view_host_delegate_helper.h13
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager.cc20
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager.h6
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager_unittest.cc53
-rw-r--r--chrome/browser/tab_contents/security_style.h1
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc656
-rw-r--r--chrome/browser/tab_contents/tab_contents.h129
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.cc44
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.h68
-rw-r--r--chrome/browser/tab_contents/tab_contents_ssl_helper.cc204
-rw-r--r--chrome/browser/tab_contents/tab_contents_ssl_helper.h19
-rw-r--r--chrome/browser/tab_contents/tab_contents_view.cc52
-rw-r--r--chrome/browser/tab_contents/tab_contents_view.h20
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.cc99
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.h12
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_mac.h6
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_mac.mm7
-rw-r--r--chrome/browser/tab_contents/tab_specific_content_settings.cc152
-rw-r--r--chrome/browser/tab_contents/tab_specific_content_settings.h71
-rw-r--r--chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc65
-rw-r--r--chrome/browser/tab_contents/tab_util.h4
-rw-r--r--chrome/browser/tab_contents/test_tab_contents.cc48
-rw-r--r--chrome/browser/tab_contents/test_tab_contents.h22
-rw-r--r--chrome/browser/tab_contents/thumbnail_generator.h4
-rw-r--r--chrome/browser/tab_contents/view_source_uitest.cc35
-rw-r--r--chrome/browser/tab_contents/web_contents_unittest.cc151
-rw-r--r--chrome/browser/tab_contents/web_drag_dest_gtk.h7
-rw-r--r--chrome/browser/tab_contents/web_drag_source_win.h1
-rw-r--r--chrome/browser/tab_contents/web_drag_utils_win.h1
-rw-r--r--chrome/browser/tab_contents/web_drop_target_win.h1
-rw-r--r--chrome/browser/tab_menu_model.h3
-rw-r--r--chrome/browser/tab_menu_model_unittest.cc7
-rw-r--r--chrome/browser/tab_restore_uitest.cc56
-rw-r--r--chrome/browser/tabs/pinned_tab_codec.cc6
-rw-r--r--chrome/browser/tabs/pinned_tab_codec.h3
-rw-r--r--chrome/browser/tabs/pinned_tab_codec_unittest.cc2
-rw-r--r--chrome/browser/tabs/pinned_tab_service.h2
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc140
-rw-r--r--chrome/browser/tabs/tab_strip_model.h248
-rw-r--r--chrome/browser/tabs/tab_strip_model_order_controller.h1
-rw-r--r--chrome/browser/tabs/tab_strip_model_unittest.cc85
-rw-r--r--chrome/browser/task_manager.cc981
-rw-r--r--chrome/browser/task_manager.h412
-rw-r--r--chrome/browser/task_manager_browsertest.cc264
-rw-r--r--chrome/browser/task_manager_resource_providers.cc913
-rw-r--r--chrome/browser/task_manager_resource_providers.h395
-rw-r--r--chrome/browser/task_manager_unittest.cc109
-rw-r--r--chrome/browser/toolbar_model.cc15
-rw-r--r--chrome/browser/toolbar_model.h2
-rw-r--r--chrome/browser/translate/languages_menu_model.h2
-rw-r--r--chrome/browser/translate/options_menu_model.cc26
-rw-r--r--chrome/browser/translate/options_menu_model.h2
-rw-r--r--chrome/browser/translate/page_translated_details.h1
-rw-r--r--chrome/browser/translate/translate_infobar_delegate.cc32
-rw-r--r--chrome/browser/translate/translate_infobar_delegate.h2
-rw-r--r--chrome/browser/translate/translate_infobar_view.h1
-rw-r--r--chrome/browser/translate/translate_manager.cc48
-rw-r--r--chrome/browser/translate/translate_manager.h3
-rw-r--r--chrome/browser/translate/translate_manager_unittest.cc259
-rw-r--r--chrome/browser/translate/translate_prefs.cc58
-rw-r--r--chrome/browser/translate/translate_prefs.h19
-rw-r--r--chrome/browser/transport_security_persister.h1
-rw-r--r--chrome/browser/ui_thread_helpers.h32
-rw-r--r--chrome/browser/ui_thread_helpers_linux.cc18
-rw-r--r--chrome/browser/ui_thread_helpers_mac.mm59
-rw-r--r--chrome/browser/ui_thread_helpers_win.cc17
-rw-r--r--chrome/browser/unload_uitest.cc9
-rw-r--r--chrome/browser/upgrade_detector.cc43
-rw-r--r--chrome/browser/upgrade_detector.h1
-rw-r--r--chrome/browser/user_style_sheet_watcher.cc149
-rw-r--r--chrome/browser/user_style_sheet_watcher.h35
-rw-r--r--chrome/browser/userfeedback/proto/common.proto8
-rw-r--r--chrome/browser/userfeedback/proto/extension.proto3
-rw-r--r--chrome/browser/userfeedback/proto/web.proto1
-rw-r--r--chrome/browser/utility_process_host.cc59
-rw-r--r--chrome/browser/utility_process_host.h42
-rw-r--r--chrome/browser/view_ids.h10
-rwxr-xr-xchrome/browser/views/PRESUBMIT.py4
-rw-r--r--chrome/browser/views/about_chrome_view.cc102
-rw-r--r--chrome/browser/views/about_chrome_view.h14
-rw-r--r--chrome/browser/views/about_ipc_dialog.cc19
-rw-r--r--chrome/browser/views/about_ipc_dialog.h1
-rw-r--r--chrome/browser/views/accelerator_table_gtk.cc247
-rw-r--r--chrome/browser/views/accelerator_table_gtk.h5
-rw-r--r--chrome/browser/views/accessibility_event_router_views.cc181
-rw-r--r--chrome/browser/views/accessibility_event_router_views.h59
-rw-r--r--chrome/browser/views/accessibility_event_router_views_unittest.cc50
-rw-r--r--chrome/browser/views/accessible_toolbar_view.cc39
-rw-r--r--chrome/browser/views/accessible_toolbar_view.h7
-rw-r--r--chrome/browser/views/accessible_view_helper.cc12
-rw-r--r--chrome/browser/views/accessible_view_helper.h6
-rw-r--r--chrome/browser/views/app_launched_animation_win.cc6
-rw-r--r--chrome/browser/views/app_launcher.cc38
-rw-r--r--chrome/browser/views/app_launcher.h3
-rw-r--r--chrome/browser/views/appcache_info_view.cc2
-rw-r--r--chrome/browser/views/appcache_info_view.h1
-rw-r--r--chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc115
-rw-r--r--chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h9
-rw-r--r--chrome/browser/views/autocomplete/autocomplete_popup_gtk.h1
-rw-r--r--chrome/browser/views/autocomplete/autocomplete_popup_win.cc1
-rw-r--r--chrome/browser/views/autocomplete/autocomplete_popup_win.h1
-rw-r--r--chrome/browser/views/autofill_profiles_view_win.cc420
-rw-r--r--chrome/browser/views/autofill_profiles_view_win.h85
-rw-r--r--chrome/browser/views/bookmark_bar_instructions_view.cc17
-rw-r--r--chrome/browser/views/bookmark_bar_instructions_view.h10
-rw-r--r--chrome/browser/views/bookmark_bar_view.cc76
-rw-r--r--chrome/browser/views/bookmark_bar_view.h17
-rw-r--r--chrome/browser/views/bookmark_bar_view_test.cc67
-rw-r--r--chrome/browser/views/bookmark_bar_view_unittest.cc9
-rw-r--r--chrome/browser/views/bookmark_bubble_view.cc15
-rw-r--r--chrome/browser/views/bookmark_bubble_view.h7
-rw-r--r--chrome/browser/views/bookmark_context_menu.h4
-rw-r--r--chrome/browser/views/bookmark_context_menu_controller_views.cc3
-rw-r--r--chrome/browser/views/bookmark_context_menu_controller_views.h1
-rw-r--r--chrome/browser/views/bookmark_context_menu_test.cc21
-rw-r--r--chrome/browser/views/bookmark_editor_view.cc23
-rw-r--r--chrome/browser/views/bookmark_editor_view.h6
-rw-r--r--chrome/browser/views/bookmark_editor_view_unittest.cc73
-rw-r--r--chrome/browser/views/bookmark_menu_controller_views.cc16
-rw-r--r--chrome/browser/views/bookmark_menu_controller_views.h7
-rw-r--r--chrome/browser/views/browser_actions_container.cc1012
-rw-r--r--chrome/browser/views/browser_actions_container.h143
-rw-r--r--chrome/browser/views/browser_actions_container_browsertest.cc21
-rw-r--r--chrome/browser/views/browser_bubble.cc1
-rw-r--r--chrome/browser/views/browser_bubble.h1
-rw-r--r--chrome/browser/views/browser_bubble_gtk.cc19
-rw-r--r--chrome/browser/views/browser_bubble_win.cc27
-rw-r--r--chrome/browser/views/browser_dialogs.h4
-rw-r--r--chrome/browser/views/browser_views_accessibility_browsertest.cc1
-rw-r--r--chrome/browser/views/bubble_border.h1
-rw-r--r--chrome/browser/views/bug_report_view.cc627
-rw-r--r--chrome/browser/views/bug_report_view.h172
-rw-r--r--chrome/browser/views/chrome_views_delegate.cc48
-rw-r--r--chrome/browser/views/chrome_views_delegate.h12
-rw-r--r--chrome/browser/views/clear_browsing_data.cc79
-rw-r--r--chrome/browser/views/clear_browsing_data.h3
-rw-r--r--chrome/browser/views/collected_cookies_win.cc172
-rw-r--r--chrome/browser/views/collected_cookies_win.h8
-rw-r--r--chrome/browser/views/confirm_message_box_dialog.h1
-rw-r--r--chrome/browser/views/constrained_window_win.cc45
-rw-r--r--chrome/browser/views/constrained_window_win.h2
-rw-r--r--chrome/browser/views/content_blocked_bubble_contents.cc323
-rw-r--r--chrome/browser/views/content_blocked_bubble_contents.h101
-rw-r--r--chrome/browser/views/cookie_info_view.cc6
-rw-r--r--chrome/browser/views/cookie_info_view.h4
-rw-r--r--chrome/browser/views/cookie_prompt_view.cc298
-rw-r--r--chrome/browser/views/cookie_prompt_view.h122
-rw-r--r--chrome/browser/views/create_application_shortcut_view.cc3
-rw-r--r--chrome/browser/views/create_application_shortcut_view.h4
-rw-r--r--chrome/browser/views/database_info_view.h4
-rw-r--r--chrome/browser/views/database_open_info_view.cc2
-rw-r--r--chrome/browser/views/database_open_info_view.h1
-rw-r--r--chrome/browser/views/detachable_toolbar_view.cc39
-rw-r--r--chrome/browser/views/detachable_toolbar_view.h12
-rw-r--r--chrome/browser/views/dom_view.cc17
-rw-r--r--chrome/browser/views/dom_view.h3
-rw-r--r--chrome/browser/views/download_item_view.cc83
-rw-r--r--chrome/browser/views/download_item_view.h10
-rw-r--r--chrome/browser/views/download_shelf_view.cc44
-rw-r--r--chrome/browser/views/download_shelf_view.h27
-rw-r--r--chrome/browser/views/dropdown_bar_host.cc15
-rw-r--r--chrome/browser/views/dropdown_bar_host.h4
-rw-r--r--chrome/browser/views/dropdown_bar_view.h1
-rw-r--r--chrome/browser/views/edit_search_engine_dialog.cc13
-rw-r--r--chrome/browser/views/edit_search_engine_dialog.h1
-rw-r--r--chrome/browser/views/event_utils.h1
-rw-r--r--chrome/browser/views/extensions/browser_action_drag_data.cc1
-rw-r--r--chrome/browser/views/extensions/browser_action_drag_data.h1
-rw-r--r--chrome/browser/views/extensions/browser_action_drag_data_unittest.cc1
-rw-r--r--chrome/browser/views/extensions/browser_action_overflow_menu_controller.h1
-rw-r--r--chrome/browser/views/extensions/extension_install_prompt.cc121
-rw-r--r--chrome/browser/views/extensions/extension_install_prompt2.cc2
-rw-r--r--chrome/browser/views/extensions/extension_installed_bubble.cc2
-rw-r--r--chrome/browser/views/extensions/extension_installed_bubble.h1
-rw-r--r--chrome/browser/views/extensions/extension_popup.cc5
-rw-r--r--chrome/browser/views/extensions/extension_popup.h3
-rw-r--r--chrome/browser/views/extensions/extension_shelf.cc1107
-rw-r--r--chrome/browser/views/extensions/extension_shelf.h154
-rw-r--r--chrome/browser/views/extensions/extension_view.cc12
-rw-r--r--chrome/browser/views/extensions/extension_view.h8
-rw-r--r--chrome/browser/views/external_protocol_dialog.cc6
-rw-r--r--chrome/browser/views/external_protocol_dialog.h1
-rw-r--r--chrome/browser/views/find_bar_host.cc183
-rw-r--r--chrome/browser/views/find_bar_host.h10
-rw-r--r--chrome/browser/views/find_bar_host_interactive_uitest.cc144
-rw-r--r--chrome/browser/views/find_bar_host_uitest.cc10
-rw-r--r--chrome/browser/views/find_bar_view.cc112
-rw-r--r--chrome/browser/views/find_bar_view.h3
-rw-r--r--chrome/browser/views/first_run_bubble.cc22
-rw-r--r--chrome/browser/views/first_run_bubble.h3
-rw-r--r--chrome/browser/views/first_run_search_engine_view.cc114
-rw-r--r--chrome/browser/views/first_run_search_engine_view.h8
-rw-r--r--chrome/browser/views/frame/app_panel_browser_frame_view.cc8
-rw-r--r--chrome/browser/views/frame/app_panel_browser_frame_view.h2
-rw-r--r--chrome/browser/views/frame/browser_bubble_host.h1
-rw-r--r--chrome/browser/views/frame/browser_frame.h8
-rw-r--r--chrome/browser/views/frame/browser_frame_gtk.cc54
-rw-r--r--chrome/browser/views/frame/browser_frame_gtk.h4
-rw-r--r--chrome/browser/views/frame/browser_frame_win.cc53
-rw-r--r--chrome/browser/views/frame/browser_frame_win.h7
-rw-r--r--chrome/browser/views/frame/browser_non_client_frame_view.h9
-rw-r--r--chrome/browser/views/frame/browser_root_view.h1
-rw-r--r--chrome/browser/views/frame/browser_view.cc503
-rw-r--r--chrome/browser/views/frame/browser_view.h112
-rw-r--r--chrome/browser/views/frame/browser_view_layout.cc129
-rw-r--r--chrome/browser/views/frame/browser_view_layout.h29
-rw-r--r--chrome/browser/views/frame/glass_browser_frame_view.cc260
-rw-r--r--chrome/browser/views/frame/glass_browser_frame_view.h12
-rw-r--r--chrome/browser/views/frame/opaque_browser_frame_view.cc432
-rw-r--r--chrome/browser/views/frame/opaque_browser_frame_view.h38
-rw-r--r--chrome/browser/views/fullscreen_exit_bubble.cc8
-rw-r--r--chrome/browser/views/fullscreen_exit_bubble.h1
-rw-r--r--chrome/browser/views/generic_info_view.h1
-rw-r--r--chrome/browser/views/generic_info_view_unittest.cc1
-rw-r--r--chrome/browser/views/html_dialog_view.cc23
-rw-r--r--chrome/browser/views/html_dialog_view.h1
-rw-r--r--chrome/browser/views/hung_renderer_view.cc11
-rw-r--r--chrome/browser/views/importer_lock_view.cc2
-rw-r--r--chrome/browser/views/importer_lock_view.h1
-rw-r--r--chrome/browser/views/importer_view.cc6
-rw-r--r--chrome/browser/views/importer_view.h4
-rw-r--r--chrome/browser/views/importing_progress_view.cc4
-rw-r--r--chrome/browser/views/importing_progress_view.h1
-rw-r--r--chrome/browser/views/info_bubble.cc6
-rw-r--r--chrome/browser/views/info_bubble.h1
-rw-r--r--chrome/browser/views/infobars/after_translate_infobar.cc1
-rw-r--r--chrome/browser/views/infobars/after_translate_infobar.h9
-rw-r--r--chrome/browser/views/infobars/before_translate_infobar.cc1
-rw-r--r--chrome/browser/views/infobars/before_translate_infobar.h4
-rw-r--r--chrome/browser/views/infobars/extension_infobar.cc13
-rw-r--r--chrome/browser/views/infobars/extension_infobar.h3
-rw-r--r--chrome/browser/views/infobars/infobar_button_border.cc1
-rw-r--r--chrome/browser/views/infobars/infobar_button_border.h1
-rw-r--r--chrome/browser/views/infobars/infobar_container.cc7
-rw-r--r--chrome/browser/views/infobars/infobar_container.h4
-rw-r--r--chrome/browser/views/infobars/infobar_text_button.h1
-rw-r--r--chrome/browser/views/infobars/infobars.cc87
-rw-r--r--chrome/browser/views/infobars/infobars.h8
-rw-r--r--chrome/browser/views/infobars/translate_infobar_base.cc2
-rw-r--r--chrome/browser/views/infobars/translate_infobar_base.h1
-rw-r--r--chrome/browser/views/infobars/translate_message_infobar.h1
-rw-r--r--chrome/browser/views/jsmessage_box_dialog.cc118
-rw-r--r--chrome/browser/views/jsmessage_box_dialog.h62
-rw-r--r--chrome/browser/views/keyword_editor_view.cc13
-rw-r--r--chrome/browser/views/keyword_editor_view.h13
-rw-r--r--chrome/browser/views/list_background.h1
-rw-r--r--chrome/browser/views/local_storage_info_view.h4
-rw-r--r--chrome/browser/views/local_storage_set_item_info_view.cc2
-rw-r--r--chrome/browser/views/local_storage_set_item_info_view.h2
-rw-r--r--chrome/browser/views/location_bar/click_handler.h1
-rw-r--r--chrome/browser/views/location_bar/content_setting_image_view.cc2
-rw-r--r--chrome/browser/views/location_bar/content_setting_image_view.h1
-rw-r--r--chrome/browser/views/location_bar/ev_bubble_view.h1
-rw-r--r--chrome/browser/views/location_bar/icon_label_bubble_view.cc28
-rw-r--r--chrome/browser/views/location_bar/icon_label_bubble_view.h4
-rw-r--r--chrome/browser/views/location_bar/keyword_hint_view.h1
-rw-r--r--chrome/browser/views/location_bar/location_bar_view.cc469
-rw-r--r--chrome/browser/views/location_bar/location_bar_view.h103
-rw-r--r--chrome/browser/views/location_bar/location_icon_view.h1
-rw-r--r--chrome/browser/views/location_bar/page_action_image_view.cc81
-rw-r--r--chrome/browser/views/location_bar/page_action_image_view.h3
-rw-r--r--chrome/browser/views/location_bar/page_action_with_badge_view.cc6
-rw-r--r--chrome/browser/views/location_bar/page_action_with_badge_view.h3
-rw-r--r--chrome/browser/views/location_bar/selected_keyword_view.cc1
-rw-r--r--chrome/browser/views/location_bar/selected_keyword_view.h1
-rw-r--r--chrome/browser/views/location_bar/star_view.cc11
-rw-r--r--chrome/browser/views/location_bar/star_view.h3
-rw-r--r--chrome/browser/views/login_view.cc16
-rw-r--r--chrome/browser/views/login_view.h9
-rw-r--r--chrome/browser/views/modal_dialog_delegate.h5
-rw-r--r--chrome/browser/views/notifications/balloon_view.cc49
-rw-r--r--chrome/browser/views/notifications/balloon_view.h2
-rw-r--r--chrome/browser/views/notifications/balloon_view_host.h3
-rw-r--r--chrome/browser/views/options/advanced_contents_view.cc346
-rw-r--r--chrome/browser/views/options/advanced_contents_view.h1
-rw-r--r--chrome/browser/views/options/advanced_page_view.cc1
-rw-r--r--chrome/browser/views/options/advanced_page_view.h1
-rw-r--r--chrome/browser/views/options/content_exceptions_table_view.cc2
-rw-r--r--chrome/browser/views/options/content_exceptions_table_view.h1
-rw-r--r--chrome/browser/views/options/content_filter_page_view.cc67
-rw-r--r--chrome/browser/views/options/content_filter_page_view.h1
-rw-r--r--chrome/browser/views/options/content_page_view.cc32
-rw-r--r--chrome/browser/views/options/content_page_view.h6
-rw-r--r--chrome/browser/views/options/content_settings_window_view.cc3
-rw-r--r--chrome/browser/views/options/content_settings_window_view.h3
-rw-r--r--chrome/browser/views/options/cookie_filter_page_view.cc2
-rw-r--r--chrome/browser/views/options/cookie_filter_page_view.h5
-rw-r--r--chrome/browser/views/options/cookies_view.cc22
-rw-r--r--chrome/browser/views/options/cookies_view.h19
-rw-r--r--chrome/browser/views/options/exception_editor_view.h1
-rw-r--r--chrome/browser/views/options/exceptions_page_view.cc2
-rw-r--r--chrome/browser/views/options/exceptions_page_view.h1
-rw-r--r--chrome/browser/views/options/exceptions_view.h1
-rw-r--r--chrome/browser/views/options/fonts_languages_window_view.cc3
-rw-r--r--chrome/browser/views/options/fonts_languages_window_view.h1
-rw-r--r--chrome/browser/views/options/fonts_page_view.cc21
-rw-r--r--chrome/browser/views/options/fonts_page_view.h5
-rw-r--r--chrome/browser/views/options/general_page_view.cc73
-rw-r--r--chrome/browser/views/options/general_page_view.h8
-rw-r--r--chrome/browser/views/options/languages_page_view.cc12
-rw-r--r--chrome/browser/views/options/languages_page_view.h5
-rw-r--r--chrome/browser/views/options/managed_prefs_banner_view.cc3
-rw-r--r--chrome/browser/views/options/managed_prefs_banner_view.h5
-rw-r--r--chrome/browser/views/options/options_group_view.cc6
-rw-r--r--chrome/browser/views/options/options_group_view.h3
-rw-r--r--chrome/browser/views/options/options_page_view.cc7
-rw-r--r--chrome/browser/views/options/options_page_view.h4
-rw-r--r--chrome/browser/views/options/options_window_view.cc34
-rw-r--r--chrome/browser/views/options/passwords_exceptions_window_view.h1
-rw-r--r--chrome/browser/views/options/passwords_page_view.cc37
-rw-r--r--chrome/browser/views/options/passwords_page_view.h11
-rw-r--r--chrome/browser/views/options/plugin_filter_page_view.h1
-rw-r--r--chrome/browser/views/options/simple_content_exceptions_view.h1
-rw-r--r--chrome/browser/views/page_info_window_view.cc13
-rw-r--r--chrome/browser/views/pinned_contents_info_bubble.h1
-rw-r--r--chrome/browser/views/reload_button.cc27
-rw-r--r--chrome/browser/views/reload_button.h1
-rw-r--r--chrome/browser/views/repost_form_warning_view.h1
-rw-r--r--chrome/browser/views/restart_message_box.h1
-rw-r--r--chrome/browser/views/sad_tab_view.cc20
-rw-r--r--chrome/browser/views/sad_tab_view.h1
-rw-r--r--chrome/browser/views/select_file_dialog.cc24
-rw-r--r--chrome/browser/views/shell_dialogs_win.cc20
-rw-r--r--chrome/browser/views/shell_dialogs_win_unittest.cc100
-rw-r--r--chrome/browser/views/ssl_client_certificate_selector_win.cc26
-rw-r--r--chrome/browser/views/status_bubble_views.cc113
-rw-r--r--chrome/browser/views/status_bubble_views.h27
-rw-r--r--chrome/browser/views/status_icons/status_icon_win.cc31
-rw-r--r--chrome/browser/views/status_icons/status_icon_win.h18
-rw-r--r--chrome/browser/views/status_icons/status_tray_win.cc20
-rw-r--r--chrome/browser/views/status_icons/status_tray_win.h3
-rw-r--r--chrome/browser/views/status_icons/status_tray_win_unittest.cc17
-rw-r--r--chrome/browser/views/tab_contents/native_tab_contents_container.h3
-rw-r--r--chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc11
-rw-r--r--chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h3
-rw-r--r--chrome/browser/views/tab_contents/native_tab_contents_container_win.cc8
-rw-r--r--chrome/browser/views/tab_contents/native_tab_contents_container_win.h3
-rw-r--r--chrome/browser/views/tab_contents/render_view_context_menu_views.cc15
-rw-r--r--chrome/browser/views/tab_contents/render_view_context_menu_views.h5
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_container.cc7
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_container.h4
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_drag_win.cc16
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_drag_win.h1
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_gtk.cc11
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_gtk.h1
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_win.cc4
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_win.h1
-rw-r--r--chrome/browser/views/tab_icon_view.cc40
-rw-r--r--chrome/browser/views/tab_icon_view.h1
-rw-r--r--chrome/browser/views/tabs/base_tab.cc178
-rw-r--r--chrome/browser/views/tabs/base_tab.h27
-rw-r--r--chrome/browser/views/tabs/base_tab_strip.h1
-rw-r--r--chrome/browser/views/tabs/browser_tab_strip_controller.cc22
-rw-r--r--chrome/browser/views/tabs/browser_tab_strip_controller.h8
-rw-r--r--chrome/browser/views/tabs/dragged_tab_controller.cc52
-rw-r--r--chrome/browser/views/tabs/dragged_tab_controller.h7
-rw-r--r--chrome/browser/views/tabs/dragged_tab_view.cc3
-rw-r--r--chrome/browser/views/tabs/dragged_tab_view.h1
-rw-r--r--chrome/browser/views/tabs/native_view_photobooth.h1
-rw-r--r--chrome/browser/views/tabs/native_view_photobooth_gtk.h1
-rw-r--r--chrome/browser/views/tabs/native_view_photobooth_win.h1
-rw-r--r--chrome/browser/views/tabs/side_tab.cc2
-rw-r--r--chrome/browser/views/tabs/side_tab.h2
-rw-r--r--chrome/browser/views/tabs/side_tab_strip.h1
-rw-r--r--chrome/browser/views/tabs/tab.cc19
-rw-r--r--chrome/browser/views/tabs/tab.h3
-rw-r--r--chrome/browser/views/tabs/tab_controller.h1
-rw-r--r--chrome/browser/views/tabs/tab_dragging_test.cc22
-rw-r--r--chrome/browser/views/tabs/tab_renderer_data.h3
-rw-r--r--chrome/browser/views/tabs/tab_strip.cc133
-rw-r--r--chrome/browser/views/tabs/tab_strip.h38
-rw-r--r--chrome/browser/views/tabs/tab_strip_controller.h3
-rw-r--r--chrome/browser/views/task_manager_view.cc56
-rw-r--r--chrome/browser/views/theme_background.cc2
-rw-r--r--chrome/browser/views/theme_background.h1
-rw-r--r--chrome/browser/views/theme_helpers.h1
-rw-r--r--chrome/browser/views/theme_install_bubble_view.cc2
-rw-r--r--chrome/browser/views/theme_install_bubble_view.h2
-rw-r--r--chrome/browser/views/toolbar_view.cc217
-rw-r--r--chrome/browser/views/toolbar_view.h41
-rw-r--r--chrome/browser/views/unhandled_keyboard_event_handler.cc2
-rw-r--r--chrome/browser/views/unhandled_keyboard_event_handler.h1
-rw-r--r--chrome/browser/views/uninstall_view.cc8
-rw-r--r--chrome/browser/views/uninstall_view.h6
-rw-r--r--chrome/browser/views/update_recommended_message_box.cc2
-rw-r--r--chrome/browser/views/update_recommended_message_box.h1
-rw-r--r--chrome/browser/views/url_picker.cc16
-rw-r--r--chrome/browser/views/url_picker.h1
-rw-r--r--chrome/browser/views/user_data_dir_dialog.h1
-rw-r--r--chrome/browser/views/wrench_menu.cc43
-rw-r--r--chrome/browser/views/wrench_menu.h1
-rw-r--r--chrome/browser/visitedlink_event_listener.cc7
-rw-r--r--chrome/browser/visitedlink_event_listener.h5
-rw-r--r--chrome/browser/visitedlink_master.cc5
-rw-r--r--chrome/browser/visitedlink_master.h3
-rw-r--r--chrome/browser/visitedlink_unittest.cc20
-rw-r--r--chrome/browser/web_applications/web_app.cc21
-rw-r--r--chrome/browser/web_applications/web_app.h3
-rw-r--r--chrome/browser/web_applications/web_app_unittest.cc3
-rw-r--r--chrome/browser/web_resource/web_resource_service.cc205
-rw-r--r--chrome/browser/web_resource/web_resource_service.h60
-rw-r--r--chrome/browser/webdata/autofill_change.h1
-rw-r--r--chrome/browser/webdata/autofill_entry.h1
-rw-r--r--chrome/browser/webdata/web_data_service.cc125
-rw-r--r--chrome/browser/webdata/web_data_service.h43
-rw-r--r--chrome/browser/webdata/web_data_service_test_util.h3
-rw-r--r--chrome/browser/webdata/web_data_service_unittest.cc1
-rw-r--r--chrome/browser/webdata/web_database.cc345
-rw-r--r--chrome/browser/webdata/web_database.h39
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc905
-rw-r--r--chrome/browser/window_sizer.cc32
-rw-r--r--chrome/browser/window_sizer.h5
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.cc43
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.h8
-rw-r--r--chrome/browser/worker_host/worker_document_set.h1
-rw-r--r--chrome/browser/worker_host/worker_process_host.cc105
-rw-r--r--chrome/browser/worker_host/worker_process_host.h6
-rw-r--r--chrome/browser/worker_host/worker_service.h1
-rw-r--r--chrome/browser/wrench_menu_model.cc186
-rw-r--r--chrome/browser/wrench_menu_model.h48
-rw-r--r--chrome/browser/wrench_menu_model_unittest.cc56
-rw-r--r--chrome/browser/zygote_host_linux.cc71
-rw-r--r--chrome/browser/zygote_host_linux.h1
-rw-r--r--chrome/browser/zygote_main_linux.cc271
-rw-r--r--chrome/common/DEPS2
-rw-r--r--chrome/common/about_handler.cc2
-rw-r--r--chrome/common/about_handler.h6
-rw-r--r--chrome/common/app_mode_common_mac.h1
-rw-r--r--chrome/common/appcache/appcache_backend_proxy.cc5
-rw-r--r--chrome/common/appcache/appcache_backend_proxy.h4
-rw-r--r--chrome/common/appcache/appcache_dispatcher.cc6
-rw-r--r--chrome/common/appcache/appcache_dispatcher.h5
-rw-r--r--chrome/common/automation_constants.cc10
-rw-r--r--chrome/common/automation_constants.h11
-rw-r--r--chrome/common/bindings_policy.h1
-rw-r--r--chrome/common/child_process.cc69
-rw-r--r--chrome/common/child_process.h8
-rw-r--r--chrome/common/child_process_host.cc2
-rw-r--r--chrome/common/child_process_host.h16
-rw-r--r--chrome/common/child_process_info.cc46
-rw-r--r--chrome/common/child_process_info.h8
-rw-r--r--chrome/common/child_process_logging.h18
-rw-r--r--chrome/common/child_process_logging_linux.cc27
-rw-r--r--chrome/common/child_process_logging_mac.mm35
-rw-r--r--chrome/common/child_process_logging_win.cc39
-rw-r--r--chrome/common/child_thread.cc19
-rw-r--r--chrome/common/child_thread.h22
-rw-r--r--chrome/common/chrome_constants.cc10
-rw-r--r--chrome/common/chrome_constants.h7
-rw-r--r--chrome/common/chrome_counters.h1
-rw-r--r--chrome/common/chrome_descriptors.h1
-rw-r--r--chrome/common/chrome_paths.h1
-rw-r--r--chrome/common/chrome_paths_internal.h6
-rw-r--r--chrome/common/chrome_paths_linux.cc12
-rw-r--r--chrome/common/chrome_paths_win.cc1
-rw-r--r--chrome/common/chrome_plugin_api.h1
-rw-r--r--chrome/common/chrome_plugin_lib.cc8
-rw-r--r--chrome/common/chrome_plugin_lib.h3
-rw-r--r--chrome/common/chrome_plugin_util.cc9
-rw-r--r--chrome/common/chrome_plugin_util.h5
-rw-r--r--chrome/common/chrome_switches.cc317
-rw-r--r--chrome/common/chrome_switches.h93
-rw-r--r--chrome/common/chrome_version_info.cc105
-rw-r--r--chrome/common/chrome_version_info.h43
-rw-r--r--chrome/common/chrome_version_info_posix.h.version19
-rw-r--r--chrome/common/common.sb11
-rw-r--r--chrome/common/common_glue.cc10
-rw-r--r--chrome/common/common_param_traits.cc394
-rw-r--r--chrome/common/common_param_traits.h209
-rw-r--r--chrome/common/common_param_traits_unittest.cc30
-rw-r--r--chrome/common/content_settings.h1
-rw-r--r--chrome/common/content_settings_helper.h1
-rw-r--r--chrome/common/content_settings_types.h1
-rw-r--r--chrome/common/css_colors.h1
-rw-r--r--chrome/common/database_util.cc2
-rw-r--r--chrome/common/database_util.h1
-rw-r--r--chrome/common/db_message_filter.h1
-rw-r--r--chrome/common/debug_flags.cc5
-rw-r--r--chrome/common/debug_flags.h1
-rw-r--r--chrome/common/default_plugin.h1
-rw-r--r--chrome/common/deprecated/event_sys-inl.h2
-rw-r--r--chrome/common/deprecated/event_sys.h4
-rw-r--r--chrome/common/deprecated/event_sys_unittest.cc3
-rw-r--r--chrome/common/desktop_notifications/active_notification_tracker.cc10
-rw-r--r--chrome/common/desktop_notifications/active_notification_tracker.h5
-rw-r--r--chrome/common/devtools_messages.cc9
-rw-r--r--chrome/common/devtools_messages.h28
-rw-r--r--chrome/common/devtools_messages_internal.h32
-rw-r--r--chrome/common/dom_storage_common.h7
-rw-r--r--chrome/common/edit_command.h1
-rw-r--r--chrome/common/env_vars.h1
-rw-r--r--chrome/common/font_descriptor_mac.h5
-rw-r--r--chrome/common/font_loader_mac.h2
-rw-r--r--chrome/common/font_loader_mac.mm2
-rw-r--r--chrome/common/gears_api.h1
-rw-r--r--chrome/common/geoposition.h1
-rw-r--r--chrome/common/gpu_info.cc27
-rw-r--r--chrome/common/gpu_info.h22
-rw-r--r--chrome/common/gpu_info_unittest.cc3
-rw-r--r--chrome/common/gpu_messages.cc153
-rw-r--r--chrome/common/gpu_messages.h70
-rw-r--r--chrome/common/gpu_messages_internal.h166
-rw-r--r--chrome/common/gpu_messages_unittest.cc14
-rw-r--r--chrome/common/gpu_native_window_handle.h1
-rw-r--r--chrome/common/gpu_param_traits.h63
-rw-r--r--chrome/common/gpu_plugin.cc1
-rw-r--r--chrome/common/gpu_plugin.h1
-rw-r--r--chrome/common/gpu_video_common.cc231
-rw-r--r--chrome/common/gpu_video_common.h146
-rw-r--r--chrome/common/important_file_writer.cc18
-rw-r--r--chrome/common/important_file_writer.h3
-rw-r--r--chrome/common/indexed_db_key.cc17
-rw-r--r--chrome/common/indexed_db_key.h2
-rw-r--r--chrome/common/indexed_db_param_traits.cc96
-rw-r--r--chrome/common/indexed_db_param_traits.h40
-rw-r--r--chrome/common/ipc_test_sink.cc1
-rw-r--r--chrome/common/ipc_test_sink.h4
-rw-r--r--chrome/common/json_pref_store.cc5
-rw-r--r--chrome/common/json_pref_store.h1
-rw-r--r--chrome/common/json_pref_store_unittest.cc20
-rw-r--r--chrome/common/json_value_serializer.h1
-rw-r--r--chrome/common/json_value_serializer_unittest.cc54
-rw-r--r--chrome/common/jstemplate_builder.h1
-rw-r--r--chrome/common/libxml_utils.h1
-rw-r--r--chrome/common/logging_chrome.cc28
-rw-r--r--chrome/common/logging_chrome.h1
-rw-r--r--chrome/common/logging_chrome_uitest.cc17
-rw-r--r--chrome/common/mach_message_source_mac.h4
-rw-r--r--chrome/common/main_function_params.h2
-rw-r--r--chrome/common/message_router.cc6
-rw-r--r--chrome/common/message_router.h5
-rw-r--r--chrome/common/metrics_helpers.cc18
-rw-r--r--chrome/common/metrics_helpers.h3
-rw-r--r--chrome/common/mru_cache.h1
-rw-r--r--chrome/common/nacl_cmd_line.cc53
-rw-r--r--chrome/common/nacl_cmd_line.h3
-rw-r--r--chrome/common/nacl_messages.cc9
-rw-r--r--chrome/common/nacl_messages.h5
-rw-r--r--chrome/common/nacl_messages_internal.h6
-rw-r--r--chrome/common/nacl_types.h1
-rw-r--r--chrome/common/native_web_keyboard_event.h5
-rw-r--r--chrome/common/native_window_notification_source.h1
-rw-r--r--chrome/common/navigation_gesture.h1
-rw-r--r--chrome/common/navigation_types.h1
-rw-r--r--chrome/common/net/gaia/gaia_auth_consumer.h35
-rw-r--r--chrome/common/net/gaia/gaia_authenticator.h6
-rw-r--r--chrome/common/net/gaia/gaia_authenticator2.cc175
-rw-r--r--chrome/common/net/gaia/gaia_authenticator2.h54
-rw-r--r--chrome/common/net/gaia/gaia_authenticator2_unittest.cc132
-rw-r--r--chrome/common/net/gaia/gaia_authenticator2_unittest.h19
-rw-r--r--chrome/common/net/http_return.h1
-rw-r--r--chrome/common/net/net_resource_provider.cc26
-rw-r--r--chrome/common/net/net_resource_provider.h1
-rw-r--r--chrome/common/net/predictor_common.h1
-rw-r--r--chrome/common/net/socket_stream.h1
-rw-r--r--chrome/common/net/test_url_fetcher_factory.h3
-rw-r--r--chrome/common/net/url_fetcher.cc4
-rw-r--r--chrome/common/net/url_fetcher.h22
-rw-r--r--chrome/common/net/url_fetcher_protect.h8
-rw-r--r--chrome/common/net/url_fetcher_unittest.cc98
-rw-r--r--chrome/common/net/url_request_context_getter.h1
-rw-r--r--chrome/common/net/url_request_intercept_job.cc4
-rw-r--r--chrome/common/net/url_request_intercept_job.h1
-rw-r--r--chrome/common/notification_details.h1
-rw-r--r--chrome/common/notification_observer.h1
-rw-r--r--chrome/common/notification_observer_mock.h6
-rw-r--r--chrome/common/notification_registrar.h6
-rw-r--r--chrome/common/notification_service.cc10
-rw-r--r--chrome/common/notification_service.h2
-rw-r--r--chrome/common/notification_service_unittest.cc1
-rw-r--r--chrome/common/notification_source.h3
-rw-r--r--chrome/common/notification_type.h149
-rw-r--r--chrome/common/owned_widget_gtk.cc38
-rw-r--r--chrome/common/owned_widget_gtk.h89
-rw-r--r--chrome/common/page_transition_types.cc17
-rw-r--r--chrome/common/page_transition_types.h7
-rw-r--r--chrome/common/page_zoom.h3
-rw-r--r--chrome/common/pepper_plugin_registry.cc78
-rw-r--r--chrome/common/pepper_plugin_registry.h15
-rw-r--r--chrome/common/plugin_carbon_interpose_constants_mac.h1
-rw-r--r--chrome/common/plugin_group.cc289
-rw-r--r--chrome/common/plugin_group.h80
-rw-r--r--chrome/common/plugin_group_unittest.cc118
-rw-r--r--chrome/common/plugin_messages.cc308
-rw-r--r--chrome/common/plugin_messages.h277
-rw-r--r--chrome/common/plugin_messages_internal.h6
-rw-r--r--chrome/common/policy_constants.cc62
-rw-r--r--chrome/common/policy_constants.h61
-rw-r--r--chrome/common/pref_names.cc951
-rw-r--r--chrome/common/pref_names.h682
-rw-r--r--chrome/common/pref_store.h5
-rw-r--r--chrome/common/process_watcher.h3
-rw-r--r--chrome/common/process_watcher_unittest.cc9
-rw-r--r--chrome/common/process_watcher_win.cc6
-rw-r--r--chrome/common/property_bag.cc1
-rw-r--r--chrome/common/property_bag.h4
-rw-r--r--chrome/common/ref_counted_util.h1
-rw-r--r--chrome/common/render_messages.cc873
-rw-r--r--chrome/common/render_messages.h2935
-rw-r--r--chrome/common/render_messages_internal.h617
-rw-r--r--chrome/common/render_messages_params.cc1843
-rw-r--r--chrome/common/render_messages_params.h1275
-rw-r--r--chrome/common/render_messages_unittest.cc17
-rw-r--r--chrome/common/renderer_preferences.h1
-rw-r--r--chrome/common/resource_dispatcher.cc174
-rw-r--r--chrome/common/resource_dispatcher.h12
-rw-r--r--chrome/common/resource_dispatcher_unittest.cc43
-rw-r--r--chrome/common/resource_response.h1
-rw-r--r--chrome/common/result_codes.h1
-rw-r--r--chrome/common/sandbox_init_wrapper.h1
-rw-r--r--chrome/common/sandbox_init_wrapper_mac.cc18
-rw-r--r--chrome/common/sandbox_mac.h10
-rw-r--r--chrome/common/sandbox_mac.mm50
-rw-r--r--chrome/common/sandbox_mac_diraccess_unittest.mm13
-rw-r--r--chrome/common/sandbox_mac_fontloading_unittest.mm2
-rw-r--r--chrome/common/sandbox_mac_unittest_helper.h17
-rw-r--r--chrome/common/sandbox_mac_unittest_helper.mm8
-rw-r--r--chrome/common/sandbox_methods_linux.h1
-rw-r--r--chrome/common/sandbox_policy.cc98
-rw-r--r--chrome/common/sandbox_policy.h5
-rw-r--r--chrome/common/security_filter_peer.cc20
-rw-r--r--chrome/common/security_filter_peer.h11
-rw-r--r--chrome/common/serialized_script_value.cc15
-rw-r--r--chrome/common/serialized_script_value.h9
-rw-r--r--chrome/common/service_messages.cc9
-rw-r--r--chrome/common/service_messages.h14
-rw-r--r--chrome/common/service_messages_internal.h66
-rw-r--r--chrome/common/service_process_type.h17
-rw-r--r--chrome/common/service_process_util.cc97
-rw-r--r--chrome/common/service_process_util.h32
-rw-r--r--chrome/common/socket_stream_dispatcher.cc3
-rw-r--r--chrome/common/socket_stream_dispatcher.h17
-rw-r--r--chrome/common/spellcheck_common.cc4
-rw-r--r--chrome/common/spellcheck_common.h1
-rw-r--r--chrome/common/sqlite_compiled_statement.cc2
-rw-r--r--chrome/common/sqlite_compiled_statement.h1
-rw-r--r--chrome/common/sqlite_utils.cc1
-rw-r--r--chrome/common/sqlite_utils.h3
-rw-r--r--chrome/common/switch_utils.cc29
-rw-r--r--chrome/common/switch_utils.h22
-rw-r--r--chrome/common/switch_utils_unittest.cc46
-rw-r--r--chrome/common/thumbnail_score.h1
-rw-r--r--chrome/common/time_format.cc31
-rw-r--r--chrome/common/time_format.h15
-rw-r--r--chrome/common/time_format_unittest.cc46
-rw-r--r--chrome/common/translate_errors.h1
-rw-r--r--chrome/common/url_constants.cc68
-rw-r--r--chrome/common/url_constants.h74
-rw-r--r--chrome/common/utility_messages.cc16
-rw-r--r--chrome/common/utility_messages.h29
-rw-r--r--chrome/common/utility_messages_internal.h31
-rw-r--r--chrome/common/view_types.cc2
-rw-r--r--chrome/common/view_types.h5
-rw-r--r--chrome/common/visitedlink_common.cc8
-rw-r--r--chrome/common/visitedlink_common.h10
-rw-r--r--chrome/common/web_database_observer_impl.h2
-rw-r--r--chrome/common/web_resource/web_resource_unpacker.h7
-rw-r--r--chrome/common/webblobregistry_impl.cc40
-rw-r--r--chrome/common/webblobregistry_impl.h35
-rw-r--r--chrome/common/webkit_param_traits.cc177
-rw-r--r--chrome/common/webkit_param_traits.h310
-rw-r--r--chrome/common/webmessageportchannel_impl.h1
-rw-r--r--chrome/common/win_safe_util.cc24
-rw-r--r--chrome/common/win_safe_util.h1
-rw-r--r--chrome/common/window_container_type.h1
-rw-r--r--chrome/common/worker_messages.cc120
-rw-r--r--chrome/common/worker_messages.h82
-rw-r--r--chrome/common/worker_thread_ticker.h1
-rw-r--r--chrome/common/zip.cc1
-rw-r--r--chrome/common/zip.h7
-rw-r--r--googleurl/src/gurl.h2
-rw-r--r--googleurl/src/url_canon_etc.cc12
-rw-r--r--googleurl/src/url_canon_internal.h21
-rw-r--r--googleurl/src/url_canon_unittest.cc38
-rw-r--r--googleurl/src/url_parse.cc4
-rw-r--r--googleurl/src/url_test_utils.h7
-rw-r--r--net/base/address_family.h12
-rw-r--r--net/base/address_list.cc119
-rw-r--r--net/base/address_list.h51
-rw-r--r--net/base/address_list_net_log_param.cc2
-rw-r--r--net/base/address_list_net_log_param.h1
-rw-r--r--net/base/address_list_unittest.cc63
-rw-r--r--net/base/auth.cc28
-rw-r--r--net/base/auth.h23
-rw-r--r--net/base/bandwidth_metrics.h1
-rw-r--r--net/base/cache_type.h1
-rw-r--r--net/base/capturing_net_log.h3
-rw-r--r--net/base/cert_database.cc16
-rw-r--r--net/base/cert_database.h95
-rw-r--r--net/base/cert_database_nss.cc102
-rw-r--r--net/base/cert_database_nss_unittest.cc421
-rw-r--r--net/base/cert_status_flags.cc4
-rw-r--r--net/base/cert_status_flags.h3
-rw-r--r--net/base/cert_test_util.h4
-rw-r--r--net/base/cert_verifier.h1
-rw-r--r--net/base/cert_verify_result.h2
-rw-r--r--net/base/completion_callback.h1
-rw-r--r--net/base/connection_type_histograms.h1
-rw-r--r--net/base/cookie_monster.cc666
-rw-r--r--net/base/cookie_monster.h259
-rw-r--r--net/base/cookie_monster_perftest.cc158
-rw-r--r--net/base/cookie_monster_store_test.h147
-rw-r--r--net/base/cookie_monster_unittest.cc629
-rw-r--r--net/base/cookie_options.h1
-rw-r--r--net/base/cookie_policy.h1
-rw-r--r--net/base/cookie_store.h4
-rw-r--r--net/base/data_url.h1
-rw-r--r--net/base/dir_header.html2
-rw-r--r--net/base/directory_lister.cc109
-rw-r--r--net/base/directory_lister.h52
-rw-r--r--net/base/directory_lister_unittest.cc49
-rw-r--r--net/base/dns_reload_timer.cc91
-rw-r--r--net/base/dns_reload_timer.h22
-rw-r--r--net/base/dns_util.cc4
-rw-r--r--net/base/dns_util.h23
-rw-r--r--net/base/dns_util_unittest.cc25
-rw-r--r--net/base/dnsrr_resolver.cc417
-rw-r--r--net/base/dnsrr_resolver.h66
-rw-r--r--net/base/dnsrr_resolver_unittest.cc154
-rw-r--r--net/base/dnssec_chain_verifier.cc809
-rw-r--r--net/base/dnssec_chain_verifier.h110
-rw-r--r--net/base/dnssec_keyset.cc457
-rw-r--r--net/base/dnssec_keyset.h62
-rw-r--r--net/base/dnssec_unittest.cc694
-rw-r--r--net/base/escape.cc28
-rw-r--r--net/base/escape.h1
-rw-r--r--net/base/escape_unittest.cc3
-rw-r--r--net/base/ev_root_ca_metadata.cc3
-rw-r--r--net/base/ev_root_ca_metadata.h3
-rw-r--r--net/base/file_stream.h7
-rw-r--r--net/base/file_stream_posix.cc2
-rw-r--r--net/base/file_stream_unittest.cc5
-rw-r--r--net/base/file_stream_win.cc2
-rw-r--r--net/base/filter.cc10
-rw-r--r--net/base/filter.h5
-rw-r--r--net/base/filter_unittest.h1
-rw-r--r--net/base/forwarding_net_log.cc11
-rw-r--r--net/base/forwarding_net_log.h3
-rw-r--r--net/base/gzip_filter.h1
-rw-r--r--net/base/gzip_header.h1
-rw-r--r--net/base/host_cache.h7
-rw-r--r--net/base/host_cache_unittest.cc21
-rw-r--r--net/base/host_mapping_rules.cc35
-rw-r--r--net/base/host_mapping_rules.h19
-rw-r--r--net/base/host_mapping_rules_unittest.cc46
-rw-r--r--net/base/host_port_pair.cc25
-rw-r--r--net/base/host_port_pair.h50
-rw-r--r--net/base/host_resolver.cc15
-rw-r--r--net/base/host_resolver.h45
-rw-r--r--net/base/host_resolver_impl.cc342
-rw-r--r--net/base/host_resolver_impl.h40
-rw-r--r--net/base/host_resolver_impl_unittest.cc269
-rw-r--r--net/base/host_resolver_proc.cc163
-rw-r--r--net/base/host_resolver_proc.h3
-rw-r--r--net/base/https_prober.cc80
-rw-r--r--net/base/https_prober.h74
-rw-r--r--net/base/io_buffer.cc3
-rw-r--r--net/base/io_buffer.h13
-rw-r--r--net/base/keygen_handler.h17
-rw-r--r--net/base/keygen_handler_mac.cc31
-rw-r--r--net/base/keygen_handler_nss.cc2
-rw-r--r--net/base/keygen_handler_unittest.cc11
-rw-r--r--net/base/listen_socket.h1
-rw-r--r--net/base/listen_socket_unittest.cc161
-rw-r--r--net/base/listen_socket_unittest.h28
-rw-r--r--net/base/load_flags.h1
-rw-r--r--net/base/load_flags_list.h9
-rw-r--r--net/base/load_states.h1
-rw-r--r--net/base/mapped_host_resolver.cc8
-rw-r--r--net/base/mapped_host_resolver.h2
-rw-r--r--net/base/mapped_host_resolver_unittest.cc23
-rw-r--r--net/base/mime_sniffer.cc3
-rw-r--r--net/base/mime_sniffer.h1
-rw-r--r--net/base/mime_util.cc185
-rw-r--r--net/base/mime_util.h24
-rw-r--r--net/base/mock_host_resolver.cc67
-rw-r--r--net/base/mock_host_resolver.h8
-rw-r--r--net/base/net_error_list.h52
-rw-r--r--net/base/net_errors.h1
-rw-r--r--net/base/net_log.cc100
-rw-r--r--net/base/net_log.h41
-rw-r--r--net/base/net_log_event_type_list.h316
-rw-r--r--net/base/net_log_source_type_list.h4
-rw-r--r--net/base/net_log_unittest.h26
-rw-r--r--net/base/net_module.h1
-rw-r--r--net/base/net_test_constants.h18
-rw-r--r--net/base/net_test_suite.h3
-rw-r--r--net/base/net_util.cc643
-rw-r--r--net/base/net_util.h31
-rw-r--r--net/base/net_util_unittest.cc396
-rw-r--r--net/base/network_change_notifier.cc4
-rw-r--r--net/base/network_change_notifier.h1
-rw-r--r--net/base/network_change_notifier_linux.h1
-rw-r--r--net/base/network_change_notifier_mac.cc80
-rw-r--r--net/base/network_change_notifier_mac.h61
-rw-r--r--net/base/network_change_notifier_netlink_linux.cc36
-rw-r--r--net/base/network_change_notifier_netlink_linux.h1
-rw-r--r--net/base/network_change_notifier_win.h1
-rw-r--r--net/base/network_config_watcher_mac.cc92
-rw-r--r--net/base/network_config_watcher_mac.h67
-rw-r--r--net/base/nss_memio.c26
-rw-r--r--net/base/nss_memio.h9
-rw-r--r--net/base/pem_tokenizer.cc105
-rw-r--r--net/base/pem_tokenizer.h77
-rw-r--r--net/base/pem_tokenizer_unittest.cc169
-rw-r--r--net/base/platform_mime_util.h1
-rw-r--r--net/base/platform_mime_util_win.cc10
-rw-r--r--net/base/registry_controlled_domain.h1
-rw-r--r--net/base/request_priority.h3
-rw-r--r--net/base/run_all_unittests.cc2
-rw-r--r--net/base/scoped_cert_chain_context.h1
-rw-r--r--net/base/sdch_filter.h5
-rw-r--r--net/base/sdch_manager.cc14
-rw-r--r--net/base/sdch_manager.h7
-rw-r--r--net/base/ssl_cert_request_info.cc17
-rw-r--r--net/base/ssl_cert_request_info.h5
-rw-r--r--net/base/ssl_cipher_suite_names.cc3
-rw-r--r--net/base/ssl_cipher_suite_names.h1
-rw-r--r--net/base/ssl_client_auth_cache.h1
-rw-r--r--net/base/ssl_config_service.cc96
-rw-r--r--net/base/ssl_config_service.h90
-rw-r--r--net/base/ssl_config_service_defaults.cc20
-rw-r--r--net/base/ssl_config_service_defaults.h11
-rw-r--r--net/base/ssl_config_service_mac.cc4
-rw-r--r--net/base/ssl_config_service_mac.h1
-rw-r--r--net/base/ssl_config_service_mac_unittest.cc63
-rw-r--r--net/base/ssl_config_service_unittest.cc33
-rw-r--r--net/base/ssl_config_service_win.cc4
-rw-r--r--net/base/ssl_config_service_win.h3
-rw-r--r--net/base/ssl_config_service_win_unittest.cc63
-rw-r--r--net/base/ssl_connection_status_flags.h1
-rw-r--r--net/base/ssl_false_start_blacklist.cc34
-rw-r--r--net/base/ssl_false_start_blacklist.h98
-rw-r--r--net/base/ssl_false_start_blacklist.txt671
-rw-r--r--net/base/ssl_false_start_blacklist_process.cc266
-rw-r--r--net/base/ssl_false_start_blacklist_unittest.cc28
-rw-r--r--net/base/ssl_info.cc47
-rw-r--r--net/base/ssl_info.h26
-rw-r--r--net/base/ssl_non_sensitive_host_info.h56
-rw-r--r--net/base/static_cookie_policy.h1
-rw-r--r--net/base/telnet_server.cc284
-rw-r--r--net/base/telnet_server.h61
-rw-r--r--net/base/telnet_server_unittest.cc73
-rw-r--r--net/base/test_completion_callback.h1
-rw-r--r--net/base/transport_security_state.cc61
-rw-r--r--net/base/transport_security_state.h13
-rw-r--r--net/base/transport_security_state_unittest.cc33
-rw-r--r--net/base/upload_data.cc65
-rw-r--r--net/base/upload_data.h95
-rw-r--r--net/base/upload_data_stream.cc3
-rw-r--r--net/base/upload_data_stream.h4
-rw-r--r--net/base/upload_data_stream_unittest.cc7
-rw-r--r--net/base/winsock_init.h1
-rw-r--r--net/base/x509_cert_types.cc24
-rw-r--r--net/base/x509_cert_types.h19
-rw-r--r--net/base/x509_cert_types_mac.cc4
-rw-r--r--net/base/x509_certificate.cc91
-rw-r--r--net/base/x509_certificate.h46
-rw-r--r--net/base/x509_certificate_mac.cc104
-rw-r--r--net/base/x509_certificate_nss.cc132
-rw-r--r--net/base/x509_certificate_unittest.cc244
-rw-r--r--net/base/x509_certificate_win.cc69
-rw-r--r--net/crash_cache.target.mk10
-rw-r--r--net/data/heapcheck/net_unittests.gtest.txt18
-rw-r--r--net/data/proxy_resolver_v8_unittest/pac_library_unittest.js81
-rw-r--r--net/data/valgrind/net_unittests.gtest-memcheck.txt3
-rw-r--r--net/data/valgrind/net_unittests.gtest-tsan_mac.txt16
-rw-r--r--net/data/valgrind/net_unittests.gtest-tsan_win32.txt8
-rw-r--r--net/data/valgrind/net_unittests.gtest_mac.txt2
-rw-r--r--net/disk_cache/addr.h1
-rw-r--r--net/disk_cache/backend_impl.cc328
-rw-r--r--net/disk_cache/backend_impl.h62
-rw-r--r--net/disk_cache/backend_unittest.cc294
-rw-r--r--net/disk_cache/bitmap.h1
-rw-r--r--net/disk_cache/block_files.cc89
-rw-r--r--net/disk_cache/block_files.h22
-rw-r--r--net/disk_cache/block_files_unittest.cc49
-rw-r--r--net/disk_cache/cache_util.h5
-rw-r--r--net/disk_cache/cache_util_win.cc18
-rw-r--r--net/disk_cache/disk_cache.h1
-rw-r--r--net/disk_cache/disk_cache_test_base.cc48
-rw-r--r--net/disk_cache/disk_cache_test_base.h29
-rw-r--r--net/disk_cache/disk_cache_test_util.cc5
-rw-r--r--net/disk_cache/disk_cache_test_util.h9
-rw-r--r--net/disk_cache/disk_format.h1
-rw-r--r--net/disk_cache/entry_impl.cc597
-rw-r--r--net/disk_cache/entry_impl.h32
-rw-r--r--net/disk_cache/entry_unittest.cc1012
-rw-r--r--net/disk_cache/errors.h4
-rw-r--r--net/disk_cache/eviction.cc23
-rw-r--r--net/disk_cache/eviction.h9
-rw-r--r--net/disk_cache/experiments.h25
-rw-r--r--net/disk_cache/file.h11
-rw-r--r--net/disk_cache/file_block.h1
-rw-r--r--net/disk_cache/file_lock.h1
-rw-r--r--net/disk_cache/file_posix.cc35
-rw-r--r--net/disk_cache/file_win.cc44
-rw-r--r--net/disk_cache/hash.h1
-rw-r--r--net/disk_cache/histogram_macros.h4
-rw-r--r--net/disk_cache/in_flight_backend_io.cc83
-rw-r--r--net/disk_cache/in_flight_backend_io.h22
-rw-r--r--net/disk_cache/in_flight_io.cc14
-rw-r--r--net/disk_cache/in_flight_io.h12
-rw-r--r--net/disk_cache/mapped_file.h5
-rw-r--r--net/disk_cache/mem_backend_impl.h1
-rw-r--r--net/disk_cache/mem_entry_impl.cc10
-rw-r--r--net/disk_cache/mem_entry_impl.h1
-rw-r--r--net/disk_cache/mem_rankings.h1
-rw-r--r--net/disk_cache/rankings.cc14
-rw-r--r--net/disk_cache/rankings.h15
-rw-r--r--net/disk_cache/sparse_control.cc14
-rw-r--r--net/disk_cache/sparse_control.h1
-rw-r--r--net/disk_cache/stats.cc13
-rw-r--r--net/disk_cache/stats.h5
-rw-r--r--net/disk_cache/stats_histogram.h1
-rw-r--r--net/disk_cache/storage_block-inl.h1
-rw-r--r--net/disk_cache/storage_block.h3
-rw-r--r--net/disk_cache/stress_cache.cc34
-rw-r--r--net/disk_cache/trace.cc8
-rw-r--r--net/disk_cache/trace.h13
-rw-r--r--net/fetch_client.target.mk10
-rw-r--r--net/fetch_server.target.mk10
-rw-r--r--net/ftp/ftp_auth_cache.cc10
-rw-r--r--net/ftp/ftp_auth_cache.h21
-rw-r--r--net/ftp/ftp_auth_cache_unittest.cc74
-rw-r--r--net/ftp/ftp_ctrl_response_buffer.cc5
-rw-r--r--net/ftp/ftp_ctrl_response_buffer.h11
-rw-r--r--net/ftp/ftp_directory_listing_buffer.h7
-rw-r--r--net/ftp/ftp_directory_listing_buffer_unittest.cc19
-rw-r--r--net/ftp/ftp_directory_listing_parser.h7
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls.cc21
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls.h7
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls_unittest.cc13
-rw-r--r--net/ftp/ftp_directory_listing_parser_mlsd.cc16
-rw-r--r--net/ftp/ftp_directory_listing_parser_mlsd.h7
-rw-r--r--net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc6
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware.cc11
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware.h7
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware_unittest.cc6
-rw-r--r--net/ftp/ftp_directory_listing_parser_unittest.h10
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms.cc24
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms.h7
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms_unittest.cc10
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows.cc33
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows.h7
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows_unittest.cc17
-rw-r--r--net/ftp/ftp_network_layer.h8
-rw-r--r--net/ftp/ftp_network_session.h7
-rw-r--r--net/ftp/ftp_network_transaction.cc44
-rw-r--r--net/ftp/ftp_network_transaction.h14
-rw-r--r--net/ftp/ftp_network_transaction_unittest.cc57
-rw-r--r--net/ftp/ftp_request_info.h7
-rw-r--r--net/ftp/ftp_response_info.h7
-rw-r--r--net/ftp/ftp_server_type_histograms.h1
-rw-r--r--net/ftp/ftp_transaction.h12
-rw-r--r--net/ftp/ftp_transaction_factory.h7
-rw-r--r--net/ftp/ftp_util.cc29
-rw-r--r--net/ftp/ftp_util.h1
-rw-r--r--net/ftp/ftp_util_unittest.cc15
-rw-r--r--net/hresolv.target.mk10
-rw-r--r--net/http/des.h1
-rw-r--r--net/http/disk_cache_based_ssl_host_info.cc230
-rw-r--r--net/http/disk_cache_based_ssl_host_info.h92
-rw-r--r--net/http/http_alternate_protocols.cc43
-rw-r--r--net/http/http_alternate_protocols.h14
-rw-r--r--net/http/http_alternate_protocols_unittest.cc45
-rw-r--r--net/http/http_auth.cc56
-rw-r--r--net/http/http_auth.h55
-rw-r--r--net/http/http_auth_cache.cc39
-rw-r--r--net/http/http_auth_cache.h41
-rw-r--r--net/http/http_auth_cache_unittest.cc220
-rw-r--r--net/http/http_auth_controller.cc104
-rw-r--r--net/http/http_auth_controller.h34
-rw-r--r--net/http/http_auth_filter.cc4
-rw-r--r--net/http/http_auth_filter.h13
-rw-r--r--net/http/http_auth_filter_unittest.cc6
-rw-r--r--net/http/http_auth_filter_win.h5
-rw-r--r--net/http/http_auth_gssapi_posix.cc341
-rw-r--r--net/http/http_auth_gssapi_posix.h28
-rw-r--r--net/http/http_auth_gssapi_posix_unittest.cc123
-rw-r--r--net/http/http_auth_handler.cc7
-rw-r--r--net/http/http_auth_handler.h33
-rw-r--r--net/http/http_auth_handler_basic.cc26
-rw-r--r--net/http/http_auth_handler_basic.h13
-rw-r--r--net/http/http_auth_handler_basic_unittest.cc69
-rw-r--r--net/http/http_auth_handler_digest.cc78
-rw-r--r--net/http/http_auth_handler_digest.h40
-rw-r--r--net/http/http_auth_handler_digest_unittest.cc48
-rw-r--r--net/http/http_auth_handler_factory.cc56
-rw-r--r--net/http/http_auth_handler_factory.h32
-rw-r--r--net/http/http_auth_handler_factory_unittest.cc10
-rw-r--r--net/http/http_auth_handler_mock.cc31
-rw-r--r--net/http/http_auth_handler_mock.h27
-rw-r--r--net/http/http_auth_handler_negotiate.cc44
-rw-r--r--net/http/http_auth_handler_negotiate.h20
-rw-r--r--net/http/http_auth_handler_negotiate_unittest.cc24
-rw-r--r--net/http/http_auth_handler_ntlm.cc63
-rw-r--r--net/http/http_auth_handler_ntlm.h18
-rw-r--r--net/http/http_auth_handler_ntlm_portable.cc4
-rw-r--r--net/http/http_auth_handler_ntlm_win.cc5
-rw-r--r--net/http/http_auth_handler_unittest.cc6
-rw-r--r--net/http/http_auth_sspi_win.cc216
-rw-r--r--net/http/http_auth_sspi_win.h28
-rw-r--r--net/http/http_auth_sspi_win_unittest.cc102
-rw-r--r--net/http/http_auth_unittest.cc201
-rw-r--r--net/http/http_basic_stream.cc49
-rw-r--r--net/http/http_basic_stream.h32
-rw-r--r--net/http/http_byte_range.h1
-rw-r--r--net/http/http_cache.cc89
-rw-r--r--net/http/http_cache.h2
-rw-r--r--net/http/http_cache_transaction.cc30
-rw-r--r--net/http/http_cache_transaction.h17
-rw-r--r--net/http/http_cache_unittest.cc71
-rw-r--r--net/http/http_chunked_decoder.cc3
-rw-r--r--net/http/http_chunked_decoder.h1
-rw-r--r--net/http/http_net_log_params.h18
-rw-r--r--net/http/http_network_delegate.h1
-rw-r--r--net/http/http_network_layer.cc79
-rw-r--r--net/http/http_network_layer.h17
-rw-r--r--net/http/http_network_layer_unittest.cc12
-rw-r--r--net/http/http_network_session.cc145
-rw-r--r--net/http/http_network_session.h111
-rw-r--r--net/http/http_network_transaction.cc1295
-rw-r--r--net/http/http_network_transaction.h159
-rw-r--r--net/http/http_network_transaction_unittest.cc1606
-rw-r--r--net/http/http_proxy_client_socket.cc129
-rw-r--r--net/http/http_proxy_client_socket.h48
-rw-r--r--net/http/http_proxy_client_socket_pool.cc218
-rw-r--r--net/http/http_proxy_client_socket_pool.h107
-rw-r--r--net/http/http_proxy_client_socket_pool_unittest.cc214
-rw-r--r--net/http/http_request_headers.cc13
-rw-r--r--net/http/http_request_headers.h6
-rw-r--r--net/http/http_request_info.h16
-rw-r--r--net/http/http_response_body_drainer.cc126
-rw-r--r--net/http/http_response_body_drainer.h68
-rw-r--r--net/http/http_response_body_drainer_unittest.cc237
-rw-r--r--net/http/http_response_headers.cc28
-rw-r--r--net/http/http_response_headers.h15
-rw-r--r--net/http/http_response_info.cc38
-rw-r--r--net/http/http_response_info.h15
-rw-r--r--net/http/http_stream.h50
-rw-r--r--net/http/http_stream_factory.cc134
-rw-r--r--net/http/http_stream_factory.h109
-rw-r--r--net/http/http_stream_parser.cc85
-rw-r--r--net/http/http_stream_parser.h40
-rw-r--r--net/http/http_stream_request.cc994
-rw-r--r--net/http/http_stream_request.h218
-rw-r--r--net/http/http_transaction.h10
-rw-r--r--net/http/http_transaction_factory.h1
-rw-r--r--net/http/http_transaction_unittest.h15
-rw-r--r--net/http/http_util.cc14
-rw-r--r--net/http/http_util.h5
-rw-r--r--net/http/http_vary_data.h1
-rw-r--r--net/http/http_version.h1
-rw-r--r--net/http/md4.h1
-rw-r--r--net/http/mock_gssapi_library_posix.cc7
-rw-r--r--net/http/mock_gssapi_library_posix.h2
-rw-r--r--net/http/mock_sspi_library_win.cc10
-rw-r--r--net/http/mock_sspi_library_win.h1
-rw-r--r--net/http/partial_data.cc27
-rw-r--r--net/http/partial_data.h5
-rw-r--r--net/http/stream_factory.h149
-rw-r--r--net/http/url_security_manager.cc17
-rw-r--r--net/http/url_security_manager.h47
-rw-r--r--net/http/url_security_manager_posix.cc5
-rw-r--r--net/http/url_security_manager_unittest.cc46
-rw-r--r--net/http/url_security_manager_win.cc59
-rw-r--r--net/http_listen_socket.target.mk7
-rw-r--r--net/net.Makefile2
-rw-r--r--net/net.gyp157
-rw-r--r--net/net.target.mk17
-rw-r--r--net/net_base.target.mk52
-rw-r--r--net/net_perftests.target.mk14
-rw-r--r--net/net_resources.target.mk6
-rw-r--r--net/net_test_support.target.mk11
-rw-r--r--net/net_unittests.target.mk26
-rw-r--r--net/ocsp/nss_ocsp.cc14
-rw-r--r--net/ocsp/nss_ocsp.h1
-rw-r--r--net/proxy/init_proxy_resolver.cc71
-rw-r--r--net/proxy/init_proxy_resolver.h30
-rw-r--r--net/proxy/init_proxy_resolver_unittest.cc106
-rw-r--r--net/proxy/mock_proxy_resolver.h2
-rw-r--r--net/proxy/multi_threaded_proxy_resolver.cc3
-rw-r--r--net/proxy/multi_threaded_proxy_resolver.h2
-rw-r--r--net/proxy/multi_threaded_proxy_resolver_unittest.cc10
-rw-r--r--net/proxy/proxy_bypass_rules.cc19
-rw-r--r--net/proxy/proxy_bypass_rules.h5
-rw-r--r--net/proxy/proxy_bypass_rules_unittest.cc3
-rw-r--r--net/proxy/proxy_config.cc218
-rw-r--r--net/proxy/proxy_config.h48
-rw-r--r--net/proxy/proxy_config_service.h38
-rw-r--r--net/proxy/proxy_config_service_common_unittest.cc4
-rw-r--r--net/proxy/proxy_config_service_common_unittest.h16
-rw-r--r--net/proxy/proxy_config_service_fixed.h7
-rw-r--r--net/proxy/proxy_config_service_linux.cc108
-rw-r--r--net/proxy/proxy_config_service_linux.h53
-rw-r--r--net/proxy/proxy_config_service_linux_unittest.cc147
-rw-r--r--net/proxy/proxy_config_service_mac.cc120
-rw-r--r--net/proxy/proxy_config_service_mac.h65
-rw-r--r--net/proxy/proxy_config_service_win.cc127
-rw-r--r--net/proxy/proxy_config_service_win.h59
-rw-r--r--net/proxy/proxy_config_service_win_unittest.cc6
-rw-r--r--net/proxy/proxy_config_unittest.cc188
-rw-r--r--net/proxy/proxy_info.cc18
-rw-r--r--net/proxy/proxy_info.h20
-rw-r--r--net/proxy/proxy_list.h1
-rw-r--r--net/proxy/proxy_resolver.h1
-rw-r--r--net/proxy/proxy_resolver_js_bindings.cc14
-rw-r--r--net/proxy/proxy_resolver_js_bindings.h8
-rw-r--r--net/proxy/proxy_resolver_js_bindings_unittest.cc2
-rw-r--r--net/proxy/proxy_resolver_mac.h7
-rw-r--r--net/proxy/proxy_resolver_perftest.cc28
-rw-r--r--net/proxy/proxy_resolver_request_context.h1
-rw-r--r--net/proxy/proxy_resolver_script.h3
-rw-r--r--net/proxy/proxy_resolver_script_data.h1
-rw-r--r--net/proxy/proxy_resolver_v8.cc203
-rw-r--r--net/proxy/proxy_resolver_v8.h6
-rw-r--r--net/proxy/proxy_resolver_v8_unittest.cc5
-rw-r--r--net/proxy/proxy_resolver_winhttp.cc1
-rw-r--r--net/proxy/proxy_resolver_winhttp.h5
-rw-r--r--net/proxy/proxy_retry_info.h1
-rw-r--r--net/proxy/proxy_script_fetcher.h7
-rw-r--r--net/proxy/proxy_script_fetcher_unittest.cc81
-rw-r--r--net/proxy/proxy_server.cc78
-rw-r--r--net/proxy/proxy_server.h42
-rw-r--r--net/proxy/proxy_server_mac.cc4
-rw-r--r--net/proxy/proxy_server_unittest.cc104
-rw-r--r--net/proxy/proxy_service.cc409
-rw-r--r--net/proxy/proxy_service.h110
-rw-r--r--net/proxy/proxy_service_unittest.cc154
-rw-r--r--net/proxy/sync_host_resolver_bridge.h1
-rw-r--r--net/proxy/sync_host_resolver_bridge_unittest.cc2
-rw-r--r--net/run_testserver.target.mk10
-rw-r--r--net/server/http_listen_socket.cc91
-rw-r--r--net/server/http_listen_socket.h17
-rw-r--r--net/server/http_server_request_info.h3
-rw-r--r--net/socket/client_socket.cc101
-rw-r--r--net/socket/client_socket.h53
-rw-r--r--net/socket/client_socket_factory.cc12
-rw-r--r--net/socket/client_socket_factory.h10
-rw-r--r--net/socket/client_socket_handle.cc3
-rw-r--r--net/socket/client_socket_handle.h27
-rw-r--r--net/socket/client_socket_pool.h20
-rw-r--r--net/socket/client_socket_pool_base.cc452
-rw-r--r--net/socket/client_socket_pool_base.h194
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc1160
-rw-r--r--net/socket/client_socket_pool_histograms.cc33
-rw-r--r--net/socket/client_socket_pool_histograms.h13
-rw-r--r--net/socket/client_socket_pool_manager.cc327
-rw-r--r--net/socket/client_socket_pool_manager.h140
-rw-r--r--net/socket/socket.h31
-rw-r--r--net/socket/socket_test_util.cc485
-rw-r--r--net/socket/socket_test_util.h332
-rw-r--r--net/socket/socks5_client_socket.cc25
-rw-r--r--net/socket/socks5_client_socket.h6
-rw-r--r--net/socket/socks5_client_socket_unittest.cc4
-rw-r--r--net/socket/socks_client_socket.cc25
-rw-r--r--net/socket/socks_client_socket.h14
-rw-r--r--net/socket/socks_client_socket_pool.cc60
-rw-r--r--net/socket/socks_client_socket_pool.h40
-rw-r--r--net/socket/socks_client_socket_pool_unittest.cc110
-rw-r--r--net/socket/socks_client_socket_unittest.cc2
-rw-r--r--net/socket/ssl_client_socket.h39
-rw-r--r--net/socket/ssl_client_socket_mac.cc71
-rw-r--r--net/socket/ssl_client_socket_mac.h6
-rw-r--r--net/socket/ssl_client_socket_mac_factory.h1
-rw-r--r--net/socket/ssl_client_socket_nss.cc475
-rw-r--r--net/socket/ssl_client_socket_nss.h21
-rw-r--r--net/socket/ssl_client_socket_nss_factory.cc2
-rw-r--r--net/socket/ssl_client_socket_nss_factory.h1
-rw-r--r--net/socket/ssl_client_socket_pool.cc215
-rw-r--r--net/socket/ssl_client_socket_pool.h105
-rw-r--r--net/socket/ssl_client_socket_pool_unittest.cc375
-rw-r--r--net/socket/ssl_client_socket_unittest.cc257
-rw-r--r--net/socket/ssl_client_socket_win.cc104
-rw-r--r--net/socket/ssl_client_socket_win.h6
-rw-r--r--net/socket/tcp_client_socket.h1
-rw-r--r--net/socket/tcp_client_socket_libevent.cc45
-rw-r--r--net/socket/tcp_client_socket_libevent.h13
-rw-r--r--net/socket/tcp_client_socket_pool.cc46
-rw-r--r--net/socket/tcp_client_socket_pool.h26
-rw-r--r--net/socket/tcp_client_socket_pool_unittest.cc224
-rw-r--r--net/socket/tcp_client_socket_unittest.cc11
-rw-r--r--net/socket/tcp_client_socket_win.cc81
-rw-r--r--net/socket/tcp_client_socket_win.h14
-rw-r--r--net/socket/tcp_pinger.h140
-rw-r--r--net/socket/tcp_pinger_unittest.cc95
-rw-r--r--net/socket_stream/socket_stream.cc131
-rw-r--r--net/socket_stream/socket_stream.h13
-rw-r--r--net/socket_stream/socket_stream_job.h6
-rw-r--r--net/socket_stream/socket_stream_job_manager.h1
-rw-r--r--net/socket_stream/socket_stream_metrics.h5
-rw-r--r--net/socket_stream/socket_stream_unittest.cc20
-rw-r--r--net/spdy/spdy_bitmasks.h1
-rw-r--r--net/spdy/spdy_frame_builder.cc9
-rw-r--r--net/spdy/spdy_frame_builder.h12
-rw-r--r--net/spdy/spdy_framer.cc32
-rw-r--r--net/spdy/spdy_framer.h11
-rw-r--r--net/spdy/spdy_framer_test.cc54
-rw-r--r--net/spdy/spdy_http_stream.cc268
-rw-r--r--net/spdy/spdy_http_stream.h83
-rw-r--r--net/spdy/spdy_http_stream_unittest.cc139
-rw-r--r--net/spdy/spdy_http_utils.cc141
-rw-r--r--net/spdy/spdy_http_utils.h32
-rw-r--r--net/spdy/spdy_io_buffer.h1
-rw-r--r--net/spdy/spdy_network_transaction.cc335
-rw-r--r--net/spdy/spdy_network_transaction.h123
-rw-r--r--net/spdy/spdy_network_transaction_unittest.cc2902
-rw-r--r--net/spdy/spdy_protocol.h8
-rw-r--r--net/spdy/spdy_session.cc742
-rw-r--r--net/spdy/spdy_session.h131
-rw-r--r--net/spdy/spdy_session_pool.cc135
-rw-r--r--net/spdy/spdy_session_pool.h66
-rw-r--r--net/spdy/spdy_session_unittest.cc111
-rw-r--r--net/spdy/spdy_settings_storage.cc3
-rw-r--r--net/spdy/spdy_settings_storage.h2
-rw-r--r--net/spdy/spdy_stream.cc384
-rw-r--r--net/spdy/spdy_stream.h102
-rw-r--r--net/spdy/spdy_stream_unittest.cc26
-rw-r--r--net/spdy/spdy_test_util.cc402
-rw-r--r--net/spdy/spdy_test_util.h163
-rw-r--r--net/spdy/spdy_transaction_factory.h36
-rw-r--r--net/stress_cache.target.mk10
-rw-r--r--net/test/test_server.cc475
-rw-r--r--net/test/test_server.h146
-rw-r--r--net/third_party/mozilla_security_manager/nsKeygenHandler.cpp17
-rw-r--r--net/third_party/mozilla_security_manager/nsKeygenHandler.h4
-rw-r--r--net/third_party/nss/README.chromium10
-rw-r--r--net/third_party/nss/patches/falsestart.patch62
-rw-r--r--net/third_party/nss/ssl.gyp2
-rw-r--r--net/third_party/nss/ssl.target.mk9
-rw-r--r--net/third_party/nss/ssl/Makefile5
-rw-r--r--net/third_party/nss/ssl/ssl.def10
-rw-r--r--net/third_party/nss/ssl/ssl.h68
-rw-r--r--net/third_party/nss/ssl/ssl3con.c469
-rw-r--r--net/third_party/nss/ssl/ssl3ecc.c4
-rw-r--r--net/third_party/nss/ssl/ssl3ext.c23
-rw-r--r--net/third_party/nss/ssl/ssl3prot.h4
-rw-r--r--net/third_party/nss/ssl/sslauth.c9
-rw-r--r--net/third_party/nss/ssl/sslcon.c4
-rw-r--r--net/third_party/nss/ssl/sslerr.h6
-rw-r--r--net/third_party/nss/ssl/sslgathr.c32
-rw-r--r--net/third_party/nss/ssl/sslimpl.h77
-rw-r--r--net/third_party/nss/ssl/sslinfo.c10
-rw-r--r--net/third_party/nss/ssl/sslmutex.c6
-rw-r--r--net/third_party/nss/ssl/sslproto.h6
-rw-r--r--net/third_party/nss/ssl/sslreveal.c14
-rw-r--r--net/third_party/nss/ssl/sslsnce.c11
-rw-r--r--net/third_party/nss/ssl/sslsock.c22
-rw-r--r--net/third_party/nss/ssl/sslt.h16
-rw-r--r--net/tld_cleanup.target.mk7
-rw-r--r--net/tools/crash_cache/crash_cache.cc4
-rw-r--r--net/tools/dump_cache/cache_dumper.cc1
-rw-r--r--net/tools/dump_cache/cache_dumper.h1
-rw-r--r--net/tools/dump_cache/dump_cache.cc25
-rw-r--r--net/tools/dump_cache/dump_files.cc9
-rw-r--r--net/tools/dump_cache/upgrade.cc3
-rw-r--r--net/tools/dump_cache/url_to_filename_encoder.cc66
-rw-r--r--net/tools/dump_cache/url_to_filename_encoder.h169
-rw-r--r--net/tools/dump_cache/url_to_filename_encoder_unittest.cc193
-rw-r--r--net/tools/dump_cache/url_utilities.h64
-rw-r--r--net/tools/fetch/fetch_client.cc14
-rw-r--r--net/tools/fetch/http_listen_socket.cc12
-rw-r--r--net/tools/fetch/http_listen_socket.h1
-rw-r--r--net/tools/fetch/http_server.h2
-rw-r--r--net/tools/fetch/http_server_request_info.h1
-rw-r--r--net/tools/fetch/http_server_response_info.h27
-rw-r--r--net/tools/fetch/http_session.h1
-rw-r--r--net/tools/flip_server/balsa_enums.h1
-rw-r--r--net/tools/flip_server/balsa_frame.h1
-rw-r--r--net/tools/flip_server/balsa_headers.h1
-rw-r--r--net/tools/flip_server/balsa_headers_token_utils.h1
-rw-r--r--net/tools/flip_server/balsa_visitor_interface.h1
-rw-r--r--net/tools/flip_server/buffer_interface.h1
-rw-r--r--net/tools/flip_server/create_listener.h1
-rw-r--r--net/tools/flip_server/epoll_server.h4
-rw-r--r--net/tools/flip_server/flip_in_mem_edsm_server.cc5
-rw-r--r--net/tools/flip_server/http_message_constants.h1
-rw-r--r--net/tools/flip_server/loadtime_measurement.h1
-rw-r--r--net/tools/flip_server/other_defines.h5
-rw-r--r--net/tools/flip_server/ring_buffer.h1
-rw-r--r--net/tools/flip_server/simple_buffer.h1
-rw-r--r--net/tools/flip_server/split.h1
-rw-r--r--net/tools/flip_server/string_piece_utils.h3
-rw-r--r--net/tools/flip_server/url_to_filename_encoder.h127
-rw-r--r--net/tools/flip_server/url_utilities.h69
-rw-r--r--net/tools/hresolv/hresolv.cc55
-rw-r--r--net/tools/spdyshark/packet-spdy.h1
-rwxr-xr-xnet/tools/testserver/chromiumsync.py230
-rwxr-xr-xnet/tools/testserver/chromiumsync_test.py138
-rw-r--r--net/tools/testserver/run_testserver.cc43
-rw-r--r--net/tools/testserver/testserver.py169
-rw-r--r--net/tools/tld_cleanup/tld_cleanup.cc1
-rw-r--r--net/url_request/https_prober.cc6
-rw-r--r--net/url_request/https_prober.h4
-rw-r--r--net/url_request/url_request.cc55
-rw-r--r--net/url_request/url_request.h48
-rw-r--r--net/url_request/url_request_about_job.cc3
-rw-r--r--net/url_request/url_request_about_job.h3
-rw-r--r--net/url_request/url_request_context.cc26
-rw-r--r--net/url_request/url_request_context.h24
-rw-r--r--net/url_request/url_request_data_job.cc3
-rw-r--r--net/url_request/url_request_data_job.h3
-rw-r--r--net/url_request/url_request_error_job.h1
-rw-r--r--net/url_request/url_request_file_dir_job.cc22
-rw-r--r--net/url_request/url_request_file_dir_job.h4
-rw-r--r--net/url_request/url_request_file_job.cc14
-rw-r--r--net/url_request/url_request_file_job.h3
-rw-r--r--net/url_request/url_request_filter.h1
-rw-r--r--net/url_request/url_request_ftp_job.cc7
-rw-r--r--net/url_request/url_request_ftp_job.h12
-rw-r--r--net/url_request/url_request_http_job.cc17
-rw-r--r--net/url_request/url_request_http_job.h17
-rw-r--r--net/url_request/url_request_job.cc7
-rw-r--r--net/url_request/url_request_job.h6
-rw-r--r--net/url_request/url_request_job_manager.h1
-rw-r--r--net/url_request/url_request_job_metrics.h8
-rw-r--r--net/url_request/url_request_job_tracker.h1
-rw-r--r--net/url_request/url_request_netlog_params.cc8
-rw-r--r--net/url_request/url_request_netlog_params.h1
-rw-r--r--net/url_request/url_request_redirect_job.h1
-rw-r--r--net/url_request/url_request_simple_job.h1
-rw-r--r--net/url_request/url_request_status.h3
-rw-r--r--net/url_request/url_request_test_job.h1
-rw-r--r--net/url_request/url_request_unittest.cc679
-rw-r--r--net/url_request/url_request_unittest.h407
-rw-r--r--net/url_request/view_cache_helper.h1
-rw-r--r--net/websockets/websocket.cc1
-rw-r--r--net/websockets/websocket.h1
-rw-r--r--net/websockets/websocket_frame_handler.h1
-rw-r--r--net/websockets/websocket_handshake.cc9
-rw-r--r--net/websockets/websocket_handshake.h1
-rw-r--r--net/websockets/websocket_handshake_draft75.h1
-rw-r--r--net/websockets/websocket_handshake_handler.cc7
-rw-r--r--net/websockets/websocket_handshake_handler.h4
-rw-r--r--net/websockets/websocket_handshake_handler_unittest.cc1
-rw-r--r--net/websockets/websocket_handshake_unittest.cc10
-rw-r--r--net/websockets/websocket_job.cc13
-rw-r--r--net/websockets/websocket_job.h6
-rw-r--r--net/websockets/websocket_job_unittest.cc4
-rw-r--r--net/websockets/websocket_throttle.cc25
-rw-r--r--net/websockets/websocket_throttle.h1
-rw-r--r--sdch/sdch.target.mk7
-rw-r--r--testing/gmock.gyp2
-rw-r--r--testing/gmock.target.mk8
-rw-r--r--testing/gmock/Makefile.am51
-rw-r--r--testing/gmock/README390
-rw-r--r--testing/gmock/include/gmock/gmock-actions.h9
-rw-r--r--testing/gmock/include/gmock/gmock-generated-function-mockers.h22
-rw-r--r--testing/gmock/include/gmock/gmock-generated-function-mockers.h.pump2
-rw-r--r--testing/gmock/include/gmock/gmock-generated-matchers.h33
-rw-r--r--testing/gmock/include/gmock/gmock-generated-matchers.h.pump6
-rw-r--r--testing/gmock/include/gmock/gmock-matchers.h386
-rw-r--r--testing/gmock/include/gmock/gmock-more-actions.h12
-rw-r--r--testing/gmock/include/gmock/gmock-printers.h725
-rw-r--r--testing/gmock/include/gmock/gmock-spec-builders.h6
-rw-r--r--testing/gmock/include/gmock/gmock.h1
-rw-r--r--testing/gmock/include/gmock/internal/gmock-internal-utils.h296
-rw-r--r--testing/gmock/include/gmock/internal/gmock-port.h137
-rw-r--r--testing/gmock/make/Makefile29
-rwxr-xr-xtesting/gmock/run_tests.py1
-rwxr-xr-xtesting/gmock/scripts/gmock_doctor.py2
-rw-r--r--testing/gmock/scripts/test/Makefile57
-rw-r--r--testing/gmock/src/gmock-all.cc1
-rw-r--r--testing/gmock/src/gmock-printers.cc318
-rw-r--r--testing/gmock/test/gmock-actions_test.cc8
-rw-r--r--testing/gmock/test/gmock-generated-matchers_test.cc9
-rw-r--r--testing/gmock/test/gmock-internal-utils_test.cc311
-rw-r--r--testing/gmock/test/gmock-matchers_test.cc304
-rw-r--r--testing/gmock/test/gmock-nice-strict_test.cc2
-rw-r--r--testing/gmock/test/gmock-port_test.cc123
-rw-r--r--testing/gmock/test/gmock-printers_test.cc1118
-rw-r--r--testing/gmock/test/gmock-spec-builders_test.cc54
-rw-r--r--testing/gmock/test/gmock_all_test.cc1
-rwxr-xr-xtesting/gmock/test/gmock_output_test.py2
-rw-r--r--testing/gmock/test/gmock_output_test_golden.txt6
-rwxr-xr-xtesting/gmock/test/gmock_test_utils.py60
-rw-r--r--testing/gmockmain.target.mk7
-rw-r--r--testing/gtest.gyp19
-rw-r--r--testing/gtest.target.mk8
-rw-r--r--testing/gtest/CMakeLists.txt285
-rw-r--r--testing/gtest/Makefile.am57
-rw-r--r--testing/gtest/README528
-rw-r--r--testing/gtest/codegear/gtest.groupproj24
-rw-r--r--testing/gtest/codegear/gtest_unittest.cbproj16
-rw-r--r--testing/gtest/configure.ac1
-rw-r--r--testing/gtest/include/gtest/gtest.h37
-rw-r--r--testing/gtest/include/gtest/internal/gtest-internal.h340
-rw-r--r--testing/gtest/include/gtest/internal/gtest-param-util.h11
-rw-r--r--testing/gtest/include/gtest/internal/gtest-port.h137
-rw-r--r--testing/gtest/include/gtest/internal/gtest-string.h5
-rw-r--r--testing/gtest/make/Makefile10
-rw-r--r--testing/gtest/src/gtest-all.cc1
-rw-r--r--testing/gtest/src/gtest-death-test.cc9
-rw-r--r--testing/gtest/src/gtest-internal-inl.h12
-rw-r--r--testing/gtest/src/gtest.cc34
-rw-r--r--testing/gtest/src/gtest_main.cc2
-rw-r--r--testing/gtest/test/gtest-param-test_test.cc39
-rw-r--r--testing/gtest/test/gtest-port_test.cc116
-rw-r--r--testing/gtest/test/gtest_all_test.cc1
-rwxr-xr-xtesting/gtest/test/gtest_filter_unittest.py128
-rwxr-xr-xtesting/gtest/test/gtest_help_test.py17
-rw-r--r--testing/gtest/test/gtest_help_test_.cc4
-rwxr-xr-xtesting/gtest/test/gtest_output_test.py4
-rw-r--r--testing/gtest/test/gtest_output_test_.cc18
-rw-r--r--testing/gtest/test/gtest_output_test_golden_lin.txt22
-rw-r--r--testing/gtest/test/gtest_output_test_golden_win.txt21
-rwxr-xr-xtesting/gtest/test/gtest_test_utils.py10
-rw-r--r--testing/gtest/test/gtest_unittest.cc394
-rwxr-xr-xtesting/gtest/test/run_tests_util.py2
-rw-r--r--testing/gtestmain.target.mk7
-rw-r--r--third_party/libevent/libevent.target.mk7
-rw-r--r--third_party/libjingle/libjingle.gyp6
-rw-r--r--third_party/libjingle/libjingle.target.mk11
-rw-r--r--third_party/libjingle/libjingle_p2p.target.mk8
-rw-r--r--third_party/libjingle/overrides/talk/base/scoped_ptr.h7
-rw-r--r--third_party/libjingle/source/README131
-rw-r--r--third_party/libjingle/source/talk/base/asyncfile.h27
-rw-r--r--third_party/libjingle/source/talk/base/asynchttprequest.cc5
-rw-r--r--third_party/libjingle/source/talk/base/asynchttprequest.h3
-rw-r--r--third_party/libjingle/source/talk/base/asyncsocket.h42
-rw-r--r--third_party/libjingle/source/talk/base/asynctcpsocket.cc47
-rw-r--r--third_party/libjingle/source/talk/base/asynctcpsocket.h21
-rw-r--r--third_party/libjingle/source/talk/base/basictypes.h21
-rw-r--r--third_party/libjingle/source/talk/base/bytebuffer.cc55
-rw-r--r--third_party/libjingle/source/talk/base/bytebuffer.h12
-rw-r--r--third_party/libjingle/source/talk/base/byteorder.h52
-rw-r--r--third_party/libjingle/source/talk/base/common.h13
-rw-r--r--third_party/libjingle/source/talk/base/fileutils.h13
-rw-r--r--third_party/libjingle/source/talk/base/httpbase.cc17
-rw-r--r--third_party/libjingle/source/talk/base/httpcommon.cc4
-rw-r--r--third_party/libjingle/source/talk/base/httpcommon.h2
-rw-r--r--third_party/libjingle/source/talk/base/logging.h2
-rw-r--r--third_party/libjingle/source/talk/base/messagequeue.cc25
-rw-r--r--third_party/libjingle/source/talk/base/openssladapter.cc5
-rw-r--r--third_party/libjingle/source/talk/base/proxydetect.cc12
-rw-r--r--third_party/libjingle/source/talk/base/scoped_ptr.h19
-rw-r--r--third_party/libjingle/source/talk/base/signalthread.cc12
-rw-r--r--third_party/libjingle/source/talk/base/signalthread.h7
-rw-r--r--third_party/libjingle/source/talk/base/socketadapters.cc58
-rw-r--r--third_party/libjingle/source/talk/base/socketaddress.cc4
-rw-r--r--third_party/libjingle/source/talk/base/socketstream.h127
-rw-r--r--third_party/libjingle/source/talk/base/stream.cc71
-rw-r--r--third_party/libjingle/source/talk/base/stream.h75
-rw-r--r--third_party/libjingle/source/talk/base/task.cc10
-rw-r--r--third_party/libjingle/source/talk/base/taskparent.cc26
-rw-r--r--third_party/libjingle/source/talk/base/thread.cc98
-rw-r--r--third_party/libjingle/source/talk/base/thread.h30
-rw-r--r--third_party/libjingle/source/talk/base/unixfilesystem.cc17
-rw-r--r--third_party/libjingle/source/talk/base/unixfilesystem.h7
-rw-r--r--third_party/libjingle/source/talk/base/win32filesystem.cc108
-rw-r--r--third_party/libjingle/source/talk/base/win32filesystem.h6
-rw-r--r--third_party/libjingle/source/talk/examples/call/callclient.cc13
-rw-r--r--third_party/libjingle/source/talk/examples/login/xmppthread.cc18
-rw-r--r--third_party/libjingle/source/talk/libjingle.scons148
-rw-r--r--third_party/libjingle/source/talk/main.scons64
-rw-r--r--third_party/libjingle/source/talk/p2p/base/candidate.h2
-rw-r--r--third_party/libjingle/source/talk/p2p/base/constants.cc16
-rw-r--r--third_party/libjingle/source/talk/p2p/base/constants.h24
-rw-r--r--third_party/libjingle/source/talk/p2p/base/p2ptransport.cc19
-rw-r--r--third_party/libjingle/source/talk/p2p/base/p2ptransport.h12
-rw-r--r--third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc6
-rw-r--r--third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h2
-rw-r--r--third_party/libjingle/source/talk/p2p/base/parsing.cc15
-rw-r--r--third_party/libjingle/source/talk/p2p/base/parsing.h16
-rw-r--r--third_party/libjingle/source/talk/p2p/base/pseudotcp.cc94
-rw-r--r--third_party/libjingle/source/talk/p2p/base/pseudotcp.h56
-rw-r--r--third_party/libjingle/source/talk/p2p/base/rawtransport.cc10
-rw-r--r--third_party/libjingle/source/talk/p2p/base/rawtransport.h7
-rw-r--r--third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc6
-rw-r--r--third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h2
-rw-r--r--third_party/libjingle/source/talk/p2p/base/relayport.cc13
-rw-r--r--third_party/libjingle/source/talk/p2p/base/relayport.h4
-rw-r--r--third_party/libjingle/source/talk/p2p/base/session.cc99
-rw-r--r--third_party/libjingle/source/talk/p2p/base/session.h78
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessionclient.h53
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessiondescription.h67
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessionmanager.cc32
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessionmanager.h10
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessionmessages.cc264
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessionmessages.h94
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stun.cc28
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stunrequest.cc2
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stunrequest.h2
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transport.cc34
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transport.h14
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transportchannel.h8
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h4
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc4
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h2
-rw-r--r--third_party/libjingle/source/talk/session/phone/call.cc21
-rw-r--r--third_party/libjingle/source/talk/session/phone/channel.cc215
-rw-r--r--third_party/libjingle/source/talk/session/phone/channel.h93
-rw-r--r--third_party/libjingle/source/talk/session/phone/channelmanager.cc122
-rw-r--r--third_party/libjingle/source/talk/session/phone/channelmanager.h38
-rw-r--r--third_party/libjingle/source/talk/session/phone/codec.cc6
-rw-r--r--third_party/libjingle/source/talk/session/phone/codec.h99
-rw-r--r--third_party/libjingle/source/talk/session/phone/devicemanager.cc214
-rw-r--r--third_party/libjingle/source/talk/session/phone/devicemanager.h4
-rw-r--r--third_party/libjingle/source/talk/session/phone/filevideoengine.h6
-rw-r--r--third_party/libjingle/source/talk/session/phone/filevideomediachannel.h1
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediachannel.h84
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediaengine.h47
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediasessionclient.cc295
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediasessionclient.h158
-rw-r--r--third_party/libjingle/source/talk/session/phone/srtpfilter.cc24
-rw-r--r--third_party/libjingle/source/talk/session/phone/srtpfilter.h6
-rw-r--r--third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc133
-rw-r--r--third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.h20
-rw-r--r--third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.cc92
-rw-r--r--third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h48
-rw-r--r--third_party/libjingle/source/talk/site_scons/talk.py60
-rw-r--r--third_party/libjingle/source/talk/third_party/gipslite/Interface/GipsVoiceEngineLite.h132
-rw-r--r--third_party/libjingle/source/talk/third_party/gipslite/Interface/expiration.h6
-rw-r--r--third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.dllbin357376 -> 0 bytes
-rw-r--r--third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.libbin8148 -> 0 bytes
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/Makefile.am91
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/affine.c144
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/affine.h43
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.c640
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.h50
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/audiostream.c343
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/g711common.h171
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/hpuxsndcard.c301
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.c574
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.h81
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.c117
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.h130
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/ms.c342
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/ms.h81
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.c132
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.h65
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.c124
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.h64
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.c121
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.h64
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.c101
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.h61
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.c129
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.h64
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.c251
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.h74
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.c130
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.h66
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.c99
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.h63
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.c278
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.h87
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.c235
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.h90
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.c94
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.h75
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.c250
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.h67
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.c96
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.h61
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.c94
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.h61
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.c168
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.h73
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.c537
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.h201
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.c194
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.h72
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.c244
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.h84
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.c82
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.h60
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msossread.c148
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msossread.h77
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.c247
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.h78
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.c91
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.h60
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.c56
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.h49
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msread.c182
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msread.h80
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.c246
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.h81
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.c163
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.h80
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.c211
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.h85
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.c303
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.h64
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.c39
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.h80
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.c39
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.h80
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.c218
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.h69
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.c192
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.h66
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssync.c193
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mssync.h136
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.c114
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.h68
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.c152
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.h55
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.c161
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.h62
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msutils.h61
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.c530
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.h96
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.c94
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.h74
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.c121
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.h63
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/osscard.c495
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/osscard.h47
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/recvrtp.c109
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/ring_test.c63
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/rtpspeex.c38
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/sendrtp.c110
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.c204
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.h143
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test.c91
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_alaw.c90
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_gsm.c110
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_lpc10.c109
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_mulaw.c87
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_rtprecv.c100
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_speex.c38
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_truespeech.c91
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_v4l.c32
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/test_videostream.c44
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/videostream.c258
-rw-r--r--third_party/libjingle/source/talk/third_party/mediastreamer/waveheader.h111
-rw-r--r--third_party/modp_b64/README.chromium10
-rw-r--r--third_party/modp_b64/modp_b64.target.mk7
-rw-r--r--third_party/modp_b64/modp_b64_data.h8
-rw-r--r--webkit/glue/DEPS1
-rw-r--r--webkit/glue/context_menu.cc38
-rw-r--r--webkit/glue/context_menu.h31
-rw-r--r--webkit/glue/cpp_bound_class.cc4
-rw-r--r--webkit/glue/cpp_bound_class.h2
-rw-r--r--webkit/glue/cpp_variant.cc7
-rw-r--r--webkit/glue/devtools_message_data.cc30
-rw-r--r--webkit/glue/devtools_message_data.h25
-rw-r--r--webkit/glue/devtools_strings.grd1
-rw-r--r--webkit/glue/dom_operations.cc25
-rw-r--r--webkit/glue/dom_operations.h12
-rw-r--r--webkit/glue/dom_operations_unittest.cc1
-rw-r--r--webkit/glue/dom_serializer_unittest.cc9
-rw-r--r--webkit/glue/form_data.cc34
-rw-r--r--webkit/glue/form_data.h14
-rw-r--r--webkit/glue/form_field.cc3
-rw-r--r--webkit/glue/form_field.h1
-rw-r--r--webkit/glue/ftp_directory_listing_response_delegate.h2
-rw-r--r--webkit/glue/glue_serialize.cc27
-rw-r--r--webkit/glue/idb_bindings.cc69
-rw-r--r--webkit/glue/idb_bindings.h25
-rw-r--r--webkit/glue/inspector_strings.grd1
-rw-r--r--webkit/glue/media/buffered_data_source.cc4
-rw-r--r--webkit/glue/media/buffered_data_source.h9
-rw-r--r--webkit/glue/media/buffered_data_source_unittest.cc34
-rw-r--r--webkit/glue/media/media_resource_loader_bridge_factory.cc12
-rw-r--r--webkit/glue/media/media_resource_loader_bridge_factory.h5
-rw-r--r--webkit/glue/media/mock_media_resource_loader_bridge_factory.h8
-rw-r--r--webkit/glue/media/simple_data_source.cc7
-rw-r--r--webkit/glue/media/simple_data_source.h7
-rw-r--r--webkit/glue/media/simple_data_source_unittest.cc4
-rw-r--r--webkit/glue/media/video_renderer_impl.cc10
-rw-r--r--webkit/glue/media/video_renderer_impl.h2
-rw-r--r--webkit/glue/media/web_video_renderer.h16
-rw-r--r--webkit/glue/mimetype_unittest.cc7
-rw-r--r--webkit/glue/mock_resource_loader_bridge.h14
-rw-r--r--webkit/glue/multipart_response_delegate.cc11
-rw-r--r--webkit/glue/multipart_response_delegate_unittest.cc124
-rw-r--r--webkit/glue/password_form.cc36
-rw-r--r--webkit/glue/password_form.h32
-rw-r--r--webkit/glue/plugins/gtk_plugin_container_manager.cc16
-rw-r--r--webkit/glue/plugins/pepper_buffer.cc10
-rw-r--r--webkit/glue/plugins/pepper_buffer.h5
-rw-r--r--webkit/glue/plugins/pepper_device_context_2d.cc553
-rw-r--r--webkit/glue/plugins/pepper_device_context_2d.h175
-rw-r--r--webkit/glue/plugins/pepper_directory_reader.cc9
-rw-r--r--webkit/glue/plugins/pepper_directory_reader.h9
-rw-r--r--webkit/glue/plugins/pepper_event_conversion.cc293
-rw-r--r--webkit/glue/plugins/pepper_event_conversion.h18
-rw-r--r--webkit/glue/plugins/pepper_file_chooser.cc85
-rw-r--r--webkit/glue/plugins/pepper_file_chooser.h20
-rw-r--r--webkit/glue/plugins/pepper_file_io.cc258
-rw-r--r--webkit/glue/plugins/pepper_file_io.h40
-rw-r--r--webkit/glue/plugins/pepper_file_ref.cc42
-rw-r--r--webkit/glue/plugins/pepper_file_ref.h20
-rw-r--r--webkit/glue/plugins/pepper_file_system.cc222
-rw-r--r--webkit/glue/plugins/pepper_file_system.h9
-rw-r--r--webkit/glue/plugins/pepper_font.cc296
-rw-r--r--webkit/glue/plugins/pepper_font.h28
-rw-r--r--webkit/glue/plugins/pepper_image_data.cc25
-rw-r--r--webkit/glue/plugins/pepper_image_data.h11
-rw-r--r--webkit/glue/plugins/pepper_plugin_delegate.h154
-rw-r--r--webkit/glue/plugins/pepper_plugin_instance.cc303
-rw-r--r--webkit/glue/plugins/pepper_plugin_instance.h88
-rw-r--r--webkit/glue/plugins/pepper_plugin_module.cc215
-rw-r--r--webkit/glue/plugins/pepper_plugin_module.h37
-rw-r--r--webkit/glue/plugins/pepper_private.cc157
-rw-r--r--webkit/glue/plugins/pepper_private.h2
-rw-r--r--webkit/glue/plugins/pepper_resource.cc14
-rw-r--r--webkit/glue/plugins/pepper_resource.h43
-rw-r--r--webkit/glue/plugins/pepper_resource_tracker.cc21
-rw-r--r--webkit/glue/plugins/pepper_resource_tracker.h15
-rw-r--r--webkit/glue/plugins/pepper_scrollbar.cc34
-rw-r--r--webkit/glue/plugins/pepper_scrollbar.h10
-rw-r--r--webkit/glue/plugins/pepper_url_loader.cc95
-rw-r--r--webkit/glue/plugins/pepper_url_loader.h21
-rw-r--r--webkit/glue/plugins/pepper_url_request_info.cc46
-rw-r--r--webkit/glue/plugins/pepper_url_request_info.h9
-rw-r--r--webkit/glue/plugins/pepper_url_response_info.cc17
-rw-r--r--webkit/glue/plugins/pepper_url_response_info.h6
-rw-r--r--webkit/glue/plugins/pepper_var.cc984
-rw-r--r--webkit/glue/plugins/pepper_var.h245
-rw-r--r--webkit/glue/plugins/pepper_webplugin_impl.cc18
-rw-r--r--webkit/glue/plugins/pepper_widget.cc19
-rw-r--r--webkit/glue/plugins/pepper_widget.h8
-rw-r--r--webkit/glue/plugins/plugin_host.cc3
-rw-r--r--webkit/glue/plugins/plugin_instance.cc16
-rw-r--r--webkit/glue/plugins/plugin_instance.h1
-rw-r--r--webkit/glue/plugins/plugin_lib.cc20
-rw-r--r--webkit/glue/plugins/plugin_lib.h2
-rw-r--r--webkit/glue/plugins/plugin_lib_mac.mm3
-rw-r--r--webkit/glue/plugins/plugin_lib_posix.cc13
-rw-r--r--webkit/glue/plugins/plugin_lib_unittest.cc1
-rw-r--r--webkit/glue/plugins/plugin_lib_win.cc13
-rw-r--r--webkit/glue/plugins/plugin_list.cc22
-rw-r--r--webkit/glue/plugins/plugin_list_mac.mm8
-rw-r--r--webkit/glue/plugins/plugin_list_posix.cc26
-rw-r--r--webkit/glue/plugins/plugin_list_win.cc20
-rw-r--r--webkit/glue/plugins/plugin_stream.h15
-rw-r--r--webkit/glue/plugins/ppb_private.h94
-rw-r--r--webkit/glue/plugins/test/npapi_test.cc50
-rw-r--r--webkit/glue/plugins/test/plugin_arguments_test.cc5
-rw-r--r--webkit/glue/plugins/test/plugin_geturl_test.cc6
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc23
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.h3
-rw-r--r--webkit/glue/plugins/test/plugin_schedule_timer_test.h4
-rw-r--r--webkit/glue/plugins/test/plugin_test.h13
-rw-r--r--webkit/glue/plugins/test/plugin_test_factory.cc6
-rw-r--r--webkit/glue/plugins/test/plugin_thread_async_call_test.cc1
-rw-r--r--webkit/glue/plugins/test/plugin_thread_async_call_test.h15
-rw-r--r--webkit/glue/plugins/test/plugin_windowed_test.cc8
-rw-r--r--webkit/glue/plugins/test/plugin_windowless_test.cc7
-rw-r--r--webkit/glue/plugins/webplugin.cc3
-rw-r--r--webkit/glue/plugins/webplugin.h1
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.cc36
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h63
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_gtk.cc117
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_mac.mm73
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_win.cc21
-rw-r--r--webkit/glue/plugins/webplugin_impl.cc11
-rw-r--r--webkit/glue/plugins/webplugin_impl.h3
-rw-r--r--webkit/glue/plugins/webview_plugin.cc52
-rw-r--r--webkit/glue/plugins/webview_plugin.h27
-rw-r--r--webkit/glue/resource_fetcher.cc6
-rw-r--r--webkit/glue/resource_fetcher.h5
-rw-r--r--webkit/glue/resource_fetcher_unittest.cc28
-rw-r--r--webkit/glue/resource_loader_bridge.cc3
-rw-r--r--webkit/glue/resource_loader_bridge.h33
-rw-r--r--webkit/glue/resource_type.h1
-rw-r--r--webkit/glue/resources/webkit_strings_am.xtb13
-rw-r--r--webkit/glue/resources/webkit_strings_ar.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_bg.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_bn.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_ca.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_cs.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_da.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_de.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_el.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_en-GB.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_es-419.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_es.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_et.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_fi.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_fil.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_fr.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_gu.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_hi.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_hr.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_hu.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_id.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_it.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_iw.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_ja.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_kn.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_ko.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_lt.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_lv.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_ml.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_mr.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_nl.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_no.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_pl.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_pt-BR.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_pt-PT.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_ro.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_ru.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_sk.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_sl.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_sr.xtb31
-rw-r--r--webkit/glue/resources/webkit_strings_sv.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_sw.xtb17
-rw-r--r--webkit/glue/resources/webkit_strings_ta.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_te.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_th.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_tr.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_uk.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_vi.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_zh-CN.xtb27
-rw-r--r--webkit/glue/resources/webkit_strings_zh-TW.xtb27
-rw-r--r--webkit/glue/simple_webmimeregistry_impl.cc1
-rw-r--r--webkit/glue/unittest_test_server.h58
-rw-r--r--webkit/glue/user_agent.cc121
-rw-r--r--webkit/glue/user_agent.h28
-rw-r--r--webkit/glue/webaccessibility.cc77
-rw-r--r--webkit/glue/webaccessibility.h24
-rw-r--r--webkit/glue/webclipboard_impl.cc3
-rw-r--r--webkit/glue/webclipboard_impl.h2
-rw-r--r--webkit/glue/webcookie.cc43
-rw-r--r--webkit/glue/webcookie.h34
-rw-r--r--webkit/glue/webcursor.cc13
-rw-r--r--webkit/glue/webcursor.h3
-rw-r--r--webkit/glue/webcursor_gtk.cc18
-rw-r--r--webkit/glue/webcursor_unittest.cc36
-rw-r--r--webkit/glue/webdropdata.cc11
-rw-r--r--webkit/glue/webdropdata.h6
-rw-r--r--webkit/glue/webfileutilities_impl.cc (renamed from webkit/glue/webfilesystem_impl.cc)66
-rw-r--r--webkit/glue/webfileutilities_impl.h (renamed from webkit/glue/webfilesystem_impl.h)16
-rw-r--r--webkit/glue/webkit_glue.cc134
-rw-r--r--webkit/glue/webkit_glue.gypi92
-rw-r--r--webkit/glue/webkit_glue.h13
-rw-r--r--webkit/glue/webkit_resources.grd34
-rw-r--r--webkit/glue/webkit_strings.grd13
-rw-r--r--webkit/glue/webkitclient_impl.cc35
-rw-r--r--webkit/glue/webkitclient_impl.h3
-rw-r--r--webkit/glue/webmediaplayer_impl.cc50
-rw-r--r--webkit/glue/webmediaplayer_impl.h7
-rw-r--r--webkit/glue/webmenurunner_mac.mm10
-rw-r--r--webkit/glue/webpasswordautocompletelistener_impl.cc8
-rw-r--r--webkit/glue/webpasswordautocompletelistener_impl.h3
-rw-r--r--webkit/glue/webpasswordautocompletelistener_unittest.cc1
-rw-r--r--webkit/glue/webpreferences.cc9
-rw-r--r--webkit/glue/webpreferences.h8
-rw-r--r--webkit/glue/weburlloader_impl.cc37
-rw-r--r--webkit/glue/webvideoframe_impl.cc96
-rw-r--r--webkit/glue/webvideoframe_impl.h37
5076 files changed, 158984 insertions, 129636 deletions
diff --git a/AUTHORS b/AUTHORS
index a5a76f2..8a4a5b7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -80,3 +80,8 @@ Jared Wein <weinjared@gmail.com>
Mingmin Xie <melvinxie@gmail.com>
Michael Gilbert <floppymaster@gmail.com>
Giuseppe Iuculano <giuseppe@iuculano.it>
+litl LLC
+James Willcox <jwillcox@litl.com>
+Shreyas VA <v.a.shreyas@gmail.com>
+Steven Pennington <spenn@engr.uvic.ca>
+Jorge Villatoro <jorge@tomatocannon.com>
diff --git a/app/sql/DEPS b/app/sql/DEPS
index 7bfcce1..0f76c3a 100644
--- a/app/sql/DEPS
+++ b/app/sql/DEPS
@@ -1,3 +1,3 @@
include_rules = [
- "+third_party/sqlite/preprocessed",
+ "+third_party/sqlite",
]
diff --git a/app/sql/connection.cc b/app/sql/connection.cc
index ba40a11..1e0aa2c 100644
--- a/app/sql/connection.cc
+++ b/app/sql/connection.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.
@@ -11,11 +11,43 @@
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+<<<<<<< HEAD
#ifdef ANDROID
#include "sqlite3.h"
#else
#include "third_party/sqlite/preprocessed/sqlite3.h"
#endif
+=======
+#include "third_party/sqlite/sqlite3.h"
+
+namespace {
+
+// Spin for up to a second waiting for the lock to clear when setting
+// up the database.
+// TODO(shess): Better story on this. http://crbug.com/56559
+const base::TimeDelta kBusyTimeout = base::TimeDelta::FromSeconds(1);
+
+class ScopedBusyTimeout {
+ public:
+ explicit ScopedBusyTimeout(sqlite3* db)
+ : db_(db) {
+ }
+ ~ScopedBusyTimeout() {
+ sqlite3_busy_timeout(db_, 0);
+ }
+
+ int SetTimeout(base::TimeDelta timeout) {
+ DCHECK_LT(timeout.InMilliseconds(), INT_MAX);
+ return sqlite3_busy_timeout(db_,
+ static_cast<int>(timeout.InMilliseconds()));
+ }
+
+ private:
+ sqlite3* db_;
+};
+
+} // namespace
+>>>>>>> Chromium at release 7.0.540.0
namespace sql {
@@ -25,6 +57,12 @@ bool StatementID::operator<(const StatementID& other) const {
return strcmp(str_, other.str_) < 0;
}
+ErrorDelegate::ErrorDelegate() {
+}
+
+ErrorDelegate::~ErrorDelegate() {
+}
+
Connection::StatementRef::StatementRef()
: connection_(NULL),
stmt_(NULL) {
@@ -135,7 +173,7 @@ bool Connection::BeginTransaction() {
void Connection::RollbackTransaction() {
if (!transaction_nesting_) {
- NOTREACHED() << "Rolling back a nonexistant transaction";
+ NOTREACHED() << "Rolling back a nonexistent transaction";
return;
}
@@ -152,7 +190,7 @@ void Connection::RollbackTransaction() {
bool Connection::CommitTransaction() {
if (!transaction_nesting_) {
- NOTREACHED() << "Rolling back a nonexistant transaction";
+ NOTREACHED() << "Rolling back a nonexistent transaction";
return false;
}
transaction_nesting_--;
@@ -179,6 +217,15 @@ bool Connection::Execute(const char* sql) {
return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK;
}
+bool Connection::ExecuteWithTimeout(const char* sql, base::TimeDelta timeout) {
+ if (!db_)
+ return false;
+
+ ScopedBusyTimeout busy_timeout(db_);
+ busy_timeout.SetTimeout(timeout);
+ return sqlite3_exec(db_, sql, NULL, NULL, NULL) == SQLITE_OK;
+}
+
bool Connection::HasCachedStatement(const StatementID& id) const {
return statement_cache_.find(id) != statement_cache_.end();
}
@@ -271,6 +318,17 @@ int Connection::GetErrorCode() const {
return sqlite3_errcode(db_);
}
+int Connection::GetLastErrno() const {
+ if (!db_)
+ return -1;
+
+ int err = 0;
+ if (SQLITE_OK != sqlite3_file_control(db_, NULL, SQLITE_LAST_ERRNO, &err))
+ return -2;
+
+ return err;
+}
+
const char* Connection::GetErrorMessage() const {
if (!db_)
return "sql::Connection has no connection.";
@@ -290,19 +348,44 @@ bool Connection::OpenInternal(const std::string& file_name) {
return false;
}
- if (page_size_ != 0) {
- if (!Execute(StringPrintf("PRAGMA page_size=%d", page_size_).c_str()))
- NOTREACHED() << "Could not set page size";
+ // Enable extended result codes to provide more color on I/O errors.
+ // Not having extended result codes is not a fatal problem, as
+ // Chromium code does not attempt to handle I/O errors anyhow. The
+ // current implementation always returns SQLITE_OK, the DCHECK is to
+ // quickly notify someone if SQLite changes.
+ err = sqlite3_extended_result_codes(db_, 1);
+ DCHECK_EQ(err, SQLITE_OK) << "Could not enable extended result codes";
+
+ // If indicated, lock up the database before doing anything else, so
+ // that the following code doesn't have to deal with locking.
+ // TODO(shess): This code is brittle. Find the cases where code
+ // doesn't request |exclusive_locking_| and audit that it does the
+ // right thing with SQLITE_BUSY, and that it doesn't make
+ // assumptions about who might change things in the database.
+ // http://crbug.com/56559
+ if (exclusive_locking_) {
+ // TODO(shess): This should probably be a full CHECK(). Code
+ // which requests exclusive locking but doesn't get it is almost
+ // certain to be ill-tested.
+ if (!Execute("PRAGMA locking_mode=EXCLUSIVE"))
+ NOTREACHED() << "Could not set locking mode: " << GetErrorMessage();
}
- if (cache_size_ != 0) {
- if (!Execute(StringPrintf("PRAGMA cache_size=%d", cache_size_).c_str()))
- NOTREACHED() << "Could not set page size";
+ if (page_size_ != 0) {
+ // Enforce SQLite restrictions on |page_size_|.
+ DCHECK(!(page_size_ & (page_size_ - 1)))
+ << " page_size_ " << page_size_ << " is not a power of two.";
+ static const int kSqliteMaxPageSize = 32768; // from sqliteLimit.h
+ DCHECK_LE(page_size_, kSqliteMaxPageSize);
+ const std::string sql = StringPrintf("PRAGMA page_size=%d", page_size_);
+ if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
+ NOTREACHED() << "Could not set page size: " << GetErrorMessage();
}
- if (exclusive_locking_) {
- if (!Execute("PRAGMA locking_mode=EXCLUSIVE"))
- NOTREACHED() << "Could not set locking mode.";
+ if (cache_size_ != 0) {
+ const std::string sql = StringPrintf("PRAGMA cache_size=%d", cache_size_);
+ if (!ExecuteWithTimeout(sql.c_str(), kBusyTimeout))
+ NOTREACHED() << "Could not set cache size: " << GetErrorMessage();
}
return true;
diff --git a/app/sql/connection.h b/app/sql/connection.h
index 6927c89..0b685cc 100644
--- a/app/sql/connection.h
+++ b/app/sql/connection.h
@@ -4,6 +4,7 @@
#ifndef APP_SQL_CONNECTION_H_
#define APP_SQL_CONNECTION_H_
+#pragma once
#include <map>
#include <set>
@@ -11,6 +12,7 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
+#include "base/time.h"
class FilePath;
struct sqlite3;
@@ -76,6 +78,8 @@ class Connection;
// corruption, low-level IO errors or locking violations.
class ErrorDelegate : public base::RefCounted<ErrorDelegate> {
public:
+ ErrorDelegate();
+
// |error| is an sqlite result code as seen in sqlite\preprocessed\sqlite3.h
// |connection| is db connection where the error happened and |stmt| is
// our best guess at the statement that triggered the error. Do not store
@@ -92,7 +96,7 @@ class ErrorDelegate : public base::RefCounted<ErrorDelegate> {
protected:
friend class base::RefCounted<ErrorDelegate>;
- virtual ~ErrorDelegate() {}
+ virtual ~ErrorDelegate();
};
class Connection {
@@ -260,6 +264,10 @@ class Connection {
// Returns the error code associated with the last sqlite operation.
int GetErrorCode() const;
+ // Returns the errno associated with GetErrorCode(). See
+ // SQLITE_LAST_ERRNO in SQLite documentation.
+ int GetLastErrno() const;
+
// Returns a pointer to a statically allocated string associated with the
// last sqlite operation.
const char* GetErrorMessage() const;
@@ -334,6 +342,9 @@ class Connection {
// The return value is the error code reflected back to client code.
int OnSqliteError(int err, Statement* stmt);
+ // Like |Execute()|, but retries if the database is locked.
+ bool ExecuteWithTimeout(const char* sql, base::TimeDelta ms_timeout);
+
// The actual sqlite database. Will be NULL before Init has been called or if
// Init resulted in an error.
sqlite3* db_;
diff --git a/app/sql/connection_unittest.cc b/app/sql/connection_unittest.cc
index a36fca7..0a14a9a 100644
--- a/app/sql/connection_unittest.cc
+++ b/app/sql/connection_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.
@@ -8,7 +8,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
class SQLConnectionTest : public testing::Test {
public:
@@ -91,7 +91,7 @@ TEST_F(SQLConnectionTest, DoesStuffExist) {
EXPECT_FALSE(db().DoesColumnExist("foo", "bar"));
EXPECT_TRUE(db().DoesColumnExist("foo", "a"));
- // Testing for a column on a nonexistant table.
+ // Testing for a column on a nonexistent table.
EXPECT_FALSE(db().DoesColumnExist("bar", "b"));
}
diff --git a/app/sql/diagnostic_error_delegate.h b/app/sql/diagnostic_error_delegate.h
index 0b0cc65..1c2d6e9 100644
--- a/app/sql/diagnostic_error_delegate.h
+++ b/app/sql/diagnostic_error_delegate.h
@@ -4,6 +4,7 @@
#ifndef APP_SQL_DIAGNOSTIC_ERROR_DELEGATE_H_
#define APP_SQL_DIAGNOSTIC_ERROR_DELEGATE_H_
+#pragma once
#include "app/sql/connection.h"
#include "base/histogram.h"
@@ -26,14 +27,18 @@ class DiagnosticErrorDelegate : public ErrorDelegate {
virtual int OnError(int error, Connection* connection,
Statement* stmt) {
- NOTREACHED() << "sqlite error " << error << ": " <<
- connection->GetErrorMessage();
+ NOTREACHED() << "sqlite error " << error
+ << ", errno " << connection->GetLastErrno()
+ << ": " << connection->GetErrorMessage();
RecordErrorInHistogram(error);
return error;
}
private:
static void RecordErrorInHistogram(int error) {
+ // Trim off the extended error codes.
+ error &= 0xff;
+
// The histogram values from sqlite result codes go currently from 1 to
// 26 currently but 50 gives them room to grow.
UMA_HISTOGRAM_ENUMERATION(UniqueT::name(), error, 50);
diff --git a/app/sql/init_status.h b/app/sql/init_status.h
index ac70c7b..048c5e8 100644
--- a/app/sql/init_status.h
+++ b/app/sql/init_status.h
@@ -4,6 +4,7 @@
#ifndef APP_SQL_INIT_STATUS_H_
#define APP_SQL_INIT_STATUS_H_
+#pragma once
namespace sql {
diff --git a/app/sql/meta_table.h b/app/sql/meta_table.h
index 26ad079..4b06337 100644
--- a/app/sql/meta_table.h
+++ b/app/sql/meta_table.h
@@ -4,6 +4,7 @@
#ifndef APP_SQL_META_TABLE_H_
#define APP_SQL_META_TABLE_H_
+#pragma once
#include <string>
diff --git a/app/sql/statement.cc b/app/sql/statement.cc
index 4ac9c2e..3cff490 100644
--- a/app/sql/statement.cc
+++ b/app/sql/statement.cc
@@ -6,11 +6,15 @@
#include "base/logging.h"
#include "base/utf_string_conversions.h"
+<<<<<<< HEAD
#ifdef ANDROID
#include "sqlite3.h"
#else
#include "third_party/sqlite/preprocessed/sqlite3.h"
#endif
+=======
+#include "third_party/sqlite/sqlite3.h"
+>>>>>>> Chromium at release 7.0.540.0
namespace sql {
diff --git a/app/sql/statement.h b/app/sql/statement.h
index 0fbbfba..eaaac41 100644
--- a/app/sql/statement.h
+++ b/app/sql/statement.h
@@ -4,6 +4,7 @@
#ifndef APP_SQL_STATEMENT_H_
#define APP_SQL_STATEMENT_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/app/sql/statement_unittest.cc b/app/sql/statement_unittest.cc
index 90f421c..f9271a7 100644
--- a/app/sql/statement_unittest.cc
+++ b/app/sql/statement_unittest.cc
@@ -10,7 +10,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
class StatementErrorHandler : public sql::ErrorDelegate {
public:
diff --git a/app/sql/transaction.cc b/app/sql/transaction.cc
index 79a198b..10bcfb0 100644
--- a/app/sql/transaction.cc
+++ b/app/sql/transaction.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.
@@ -30,7 +30,7 @@ bool Transaction::Begin() {
void Transaction::Rollback() {
if (!is_open_) {
- NOTREACHED() << "Attempting to roll back a nonexistant transaction. "
+ NOTREACHED() << "Attempting to roll back a nonexistent transaction. "
<< "Did you remember to call Begin() and check its return?";
return;
}
@@ -40,7 +40,7 @@ void Transaction::Rollback() {
bool Transaction::Commit() {
if (!is_open_) {
- NOTREACHED() << "Attempting to commit a nonexistant transaction. "
+ NOTREACHED() << "Attempting to commit a nonexistent transaction. "
<< "Did you remember to call Begin() and check its return?";
return false;
}
diff --git a/app/sql/transaction.h b/app/sql/transaction.h
index 70741d1..c65ca8d 100644
--- a/app/sql/transaction.h
+++ b/app/sql/transaction.h
@@ -4,6 +4,7 @@
#ifndef APP_SQL_TRANSACTION_H_
#define APP_SQL_TRANSACTION_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/app/sql/transaction_unittest.cc b/app/sql/transaction_unittest.cc
index 55b77b9..9ca6bbd 100644
--- a/app/sql/transaction_unittest.cc
+++ b/app/sql/transaction_unittest.cc
@@ -9,7 +9,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
class SQLTransactionTest : public testing::Test {
public:
diff --git a/base/DEPS b/base/DEPS
index 24e3365..21793f6 100644
--- a/base/DEPS
+++ b/base/DEPS
@@ -5,9 +5,6 @@ include_rules = [
"+third_party/modp_b64",
"+third_party/tcmalloc",
- # Testing stuff shouldn't be used by the general base code.
- "-base/test",
-
# ICU dependendencies must be separate from the rest of base.
"-i18n",
]
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
index a1ad04d..64b1159 100644
--- a/base/allocator/allocator.gyp
+++ b/base/allocator/allocator.gyp
@@ -354,6 +354,17 @@
'<(tcmalloc_dir)/src/debugallocation.cc',
],
}],
+ [ 'linux_keep_shadow_stacks==1', {
+ 'sources': [
+ '<(tcmalloc_dir)/src/linux_shadow_stacks.cc',
+ '<(tcmalloc_dir)/src/linux_shadow_stacks.h',
+ '<(tcmalloc_dir)/src/stacktrace_shadow-inl.h',
+ ],
+ 'cflags': [
+ '-finstrument-functions',
+ '-DKEEP_SHADOW_STACKS',
+ ],
+ }],
[ 'linux_use_heapchecker==0', {
# Do not compile and link the heapchecker source.
'sources!': [
diff --git a/base/allocator/allocator.target.mk b/base/allocator/allocator.target.mk
index 3e69ed9..06a84d6 100644
--- a/base/allocator/allocator.target.mk
+++ b/base/allocator/allocator.target.mk
@@ -15,6 +15,7 @@ CFLAGS_Debug := -pthread \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
+ -pipe \
-fno-strict-aliasing \
-DNO_HEAP_CHECK \
-O0 \
@@ -47,6 +48,7 @@ CFLAGS_Release := -pthread \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
+ -pipe \
-fno-strict-aliasing \
-DNO_HEAP_CHECK \
-O2 \
@@ -132,11 +134,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/allocator/allocator_unittests.target.mk b/base/allocator/allocator_unittests.target.mk
index baa0471..32bfc87 100644
--- a/base/allocator/allocator_unittests.target.mk
+++ b/base/allocator/allocator_unittests.target.mk
@@ -18,6 +18,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -53,6 +54,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -107,14 +109,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/at_exit.h b/base/at_exit.h
index 082525e..fa0f277 100644
--- a/base/at_exit.h
+++ b/base/at_exit.h
@@ -4,6 +4,7 @@
#ifndef BASE_AT_EXIT_H_
#define BASE_AT_EXIT_H_
+#pragma once
#include <stack>
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
index 076a944..dff4b1f 100644
--- a/base/atomic_ref_count.h
+++ b/base/atomic_ref_count.h
@@ -10,6 +10,7 @@
#ifndef BASE_ATOMIC_REF_COUNT_H_
#define BASE_ATOMIC_REF_COUNT_H_
+#pragma once
#include "base/atomicops.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h
index 6bd51c6..11805a0 100644
--- a/base/atomic_sequence_num.h
+++ b/base/atomic_sequence_num.h
@@ -4,6 +4,7 @@
#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_
#define BASE_ATOMIC_SEQUENCE_NUM_H_
+#pragma once
#include "base/atomicops.h"
#include "base/basictypes.h"
diff --git a/base/atomicops.h b/base/atomicops.h
index e8de374..cf2f2bb 100644
--- a/base/atomicops.h
+++ b/base/atomicops.h
@@ -27,6 +27,7 @@
#ifndef BASE_ATOMICOPS_H_
#define BASE_ATOMICOPS_H_
+#pragma once
#include "base/basictypes.h"
#include "base/port.h"
diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h
index e838f1b..091b34d 100644
--- a/base/atomicops_internals_arm_gcc.h
+++ b/base/atomicops_internals_arm_gcc.h
@@ -8,6 +8,7 @@
#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
+#pragma once
namespace base {
namespace subtle {
diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h
index 002734b..08dc5aa 100644
--- a/base/atomicops_internals_x86_gcc.h
+++ b/base/atomicops_internals_x86_gcc.h
@@ -6,6 +6,7 @@
#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+#pragma once
// This struct is not part of the public API of this module; clients may not
// use it.
diff --git a/base/atomicops_internals_x86_macosx.h b/base/atomicops_internals_x86_macosx.h
index 9997da1..5de7df3 100644
--- a/base/atomicops_internals_x86_macosx.h
+++ b/base/atomicops_internals_x86_macosx.h
@@ -6,6 +6,7 @@
#ifndef BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
#define BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
+#pragma once
#include <libkern/OSAtomic.h>
diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h
index eacbb5e..1574528 100644
--- a/base/atomicops_internals_x86_msvc.h
+++ b/base/atomicops_internals_x86_msvc.h
@@ -6,6 +6,7 @@
#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#pragma once
#include <windows.h>
diff --git a/base/auto_reset.h b/base/auto_reset.h
index 3925abe..8638045 100644
--- a/base/auto_reset.h
+++ b/base/auto_reset.h
@@ -4,6 +4,7 @@
#ifndef BASE_AUTO_RESET_H_
#define BASE_AUTO_RESET_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/base.Makefile b/base/base.Makefile
index ee5a4c6..d4421bf 100644
--- a/base/base.Makefile
+++ b/base/base.Makefile
@@ -3,4 +3,4 @@
export builddir_name ?= /usr/local/google/src/chromium-merge/src/base/out
.PHONY: all
all:
- $(MAKE) -C .. symbolize xdg_mime base test_support_perf test_support_base base_i18n base_unittests
+ $(MAKE) -C .. xdg_mime symbolize base base_i18n test_support_perf test_support_base base_unittests
diff --git a/base/base.gyp b/base/base.gyp
index d2c9a68..3655bda 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -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.
@@ -31,6 +31,8 @@
'base',
],
'sources': [
+ 'i18n/char_iterator.cc',
+ 'i18n/char_iterator.h',
'i18n/file_util_icu.cc',
'i18n/file_util_icu.h',
'i18n/icu_encoding_detection.cc',
@@ -55,9 +57,7 @@
'msvs_guid': '27A30967-4BBA-48D1-8522-CDE95F7B1CEC',
'sources': [
# Infrastructure files.
- 'multiprocess_test.h',
'test/run_all_unittests.cc',
- 'test/test_suite.h',
# Tests.
'at_exit_unittest.cc',
@@ -70,13 +70,14 @@
'condition_variable_unittest.cc',
'crypto/encryptor_unittest.cc',
'crypto/rsa_private_key_unittest.cc',
+ 'crypto/rsa_private_key_nss_unittest.cc',
'crypto/signature_creator_unittest.cc',
'crypto/signature_verifier_unittest.cc',
'crypto/symmetric_key_unittest.cc',
'data_pack_unittest.cc',
'debug_util_unittest.cc',
'dir_reader_posix_unittest.cc',
- 'env_var_unittest.cc',
+ 'environment_unittest.cc',
'event_trace_consumer_win_unittest.cc',
'event_trace_controller_win_unittest.cc',
'event_trace_provider_win_unittest.cc',
@@ -89,6 +90,7 @@
'histogram_unittest.cc',
'hmac_unittest.cc',
'id_map_unittest.cc',
+ 'i18n/char_iterator_unittest.cc',
'i18n/file_util_icu_unittest.cc',
'i18n/icu_string_conversions_unittest.cc',
'i18n/rtl_unittest.cc',
@@ -100,21 +102,26 @@
'leak_tracker_unittest.cc',
'linked_list_unittest.cc',
'linked_ptr_unittest.cc',
+ 'lock_unittest.cc',
'mac_util_unittest.mm',
'message_loop_proxy_impl_unittest.cc',
'message_loop_unittest.cc',
'message_pump_glib_unittest.cc',
+ 'non_thread_safe_unittest.cc',
'object_watcher_unittest.cc',
'observer_list_unittest.cc',
'path_service_unittest.cc',
'pe_image_unittest.cc',
'pickle_unittest.cc',
+ 'platform_file_unittest.cc',
+ 'platform_thread_unittest.cc',
'pr_time_unittest.cc',
'process_util_unittest.cc',
'process_util_unittest_mac.h',
'process_util_unittest_mac.mm',
'rand_util_unittest.cc',
'ref_counted_unittest.cc',
+ 'registry_unittest.cc',
'scoped_bstr_win_unittest.cc',
'scoped_comptr_win_unittest.cc',
'scoped_native_library_unittest.cc',
@@ -128,13 +135,17 @@
'singleton_unittest.cc',
'stack_container_unittest.cc',
'stats_table_unittest.cc',
+ 'string_number_conversions_unittest.cc',
'string_piece_unittest.cc',
'string_split_unittest.cc',
'string_tokenizer_unittest.cc',
'string_util_unittest.cc',
+ 'stringprintf_unittest.cc',
'sys_info_unittest.cc',
'sys_string_conversions_mac_unittest.mm',
'sys_string_conversions_unittest.cc',
+ 'task_queue_unittest.cc',
+ 'thread_checker_unittest.cc',
'thread_collision_warner_unittest.cc',
'thread_local_storage_unittest.cc',
'thread_local_unittest.cc',
@@ -150,6 +161,7 @@
'utf_string_conversions_unittest.cc',
'values_unittest.cc',
'version_unittest.cc',
+ 'vlog_unittest.cc',
'waitable_event_unittest.cc',
'waitable_event_watcher_unittest.cc',
'watchdog_unittest.cc',
@@ -166,6 +178,7 @@
'dependencies': [
'base',
'base_i18n',
+ 'test_support_base',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
],
@@ -186,6 +199,7 @@
}, { # OS != "linux" and OS != "freebsd" and OS != "openbsd" and OS != "solaris"
'sources!': [
'message_pump_glib_unittest.cc',
+ 'crypto/rsa_private_key_nss_unittest.cc',
]
}],
# This is needed to trigger the dll copy step on windows.
@@ -205,6 +219,7 @@
'event_trace_provider_win_unittest.cc',
'object_watcher_unittest.cc',
'pe_image_unittest.cc',
+ 'registry_unittest.cc',
'scoped_bstr_win_unittest.cc',
'scoped_comptr_win_unittest.cc',
'scoped_variant_win_unittest.cc',
@@ -222,13 +237,29 @@
'type': '<(library)',
'dependencies': [
'base',
+ 'base_i18n',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'conditions': [
+ ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
+ 'dependencies': [
+ # test_suite initializes GTK.
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
],
'sources': [
+ 'test/multiprocess_test.cc',
+ 'test/multiprocess_test.h',
+ 'test/perf_test_suite.h',
'test/test_file_util.h',
'test/test_file_util_linux.cc',
'test/test_file_util_mac.cc',
'test/test_file_util_posix.cc',
'test/test_file_util_win.cc',
+ 'test/test_suite.cc',
+ 'test/test_suite.h',
],
},
{
diff --git a/base/base.gypi b/base/base.gypi
index ff05d2a..5450594 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -63,23 +63,24 @@
'dir_reader_fallback.h',
'dir_reader_linux.h',
'dir_reader_posix.h',
- 'env_var.cc',
- 'env_var.h',
+ 'environment.cc',
+ 'environment.h',
'event_trace_consumer_win.h',
'event_trace_controller_win.cc',
'event_trace_controller_win.h',
'event_trace_provider_win.cc',
'event_trace_provider_win.h',
- 'event_synthesis_gtk.cc',
- 'event_synthesis_gtk.h',
'file_path.cc',
'file_path.h',
'file_util.cc',
'file_util.h',
'file_util_deprecated.h',
+ 'file_util_linux.cc',
'file_util_mac.mm',
'file_util_posix.cc',
'file_util_win.cc',
+ 'file_util_proxy.cc',
+ 'file_util_proxy.h',
'file_version_info.h',
'file_version_info_mac.h',
'file_version_info_mac.mm',
@@ -99,6 +100,12 @@
'iat_patch.cc',
'iat_patch.h',
'id_map.h',
+ 'json/json_reader.cc',
+ 'json/json_reader.h',
+ 'json/json_writer.cc',
+ 'json/json_writer.h',
+ 'json/string_escape.cc',
+ 'json/string_escape.h',
'lazy_instance.cc',
'lazy_instance.h',
'leak_annotations.h',
@@ -121,9 +128,11 @@
'memory_debug.h',
'message_loop.cc',
'message_loop.h',
+ 'message_loop_proxy.cc',
'message_loop_proxy.h',
'message_loop_proxy_impl.cc',
'message_loop_proxy_impl.h',
+ 'message_pump.cc',
'message_pump.h',
'message_pump_default.cc',
'message_pump_default.h',
@@ -176,6 +185,7 @@
'raw_scoped_refptr_mismatch_checker.h',
'ref_counted.cc',
'ref_counted.h',
+ 'ref_counted_memory.cc',
'ref_counted_memory.h',
'registry.cc',
'registry.h',
@@ -183,8 +193,10 @@
'resource_util.h',
'safe_strerror_posix.cc',
'safe_strerror_posix.h',
+ 'scoped_aedesc.h',
'scoped_bstr_win.cc',
'scoped_bstr_win.h',
+ 'scoped_callback_factory.h',
'scoped_cftyperef.h',
'scoped_comptr_win.h',
'scoped_handle.h',
@@ -211,10 +223,13 @@
'singleton.h',
'spin_wait.h',
'stack_container.h',
+ 'stats_counters.cc',
'stats_counters.h',
'stats_table.cc',
'stats_table.h',
'stl_util-inl.h',
+ 'string_number_conversions.cc',
+ 'string_number_conversions.h',
'string_piece.cc',
'string_piece.h',
'string_split.cc',
@@ -223,6 +238,8 @@
'string_util.cc',
'string_util.h',
'string_util_win.h',
+ 'stringprintf.cc',
+ 'stringprintf.h',
'sys_info.h',
'sys_info_chromeos.cc',
'sys_info_freebsd.cc',
@@ -237,9 +254,13 @@
'sys_string_conversions_win.cc',
'task.cc',
'task.h',
+ 'task_queue.cc',
+ 'task_queue.h',
'template_util.h',
'thread.cc',
'thread.h',
+ 'thread_checker.cc',
+ 'thread_checker.h',
'thread_collision_warner.cc',
'thread_collision_warner.h',
'thread_local.h',
@@ -270,6 +291,8 @@
'utf_string_conversions.h',
'values.cc',
'values.h',
+ 'vlog.cc',
+ 'vlog.h',
'waitable_event.h',
'waitable_event_posix.cc',
'waitable_event_watcher.h',
@@ -327,6 +350,11 @@
],
},
],
+ [ 'OS != "mac"', {
+ 'sources!': [
+ 'scoped_aedesc.h'
+ ],
+ }],
# For now, just test the *BSD platforms enough to exclude them.
# Subsequent changes will include them further.
[ 'OS != "freebsd"', {
@@ -413,17 +441,6 @@
'hmac_win.cc',
'image_util.cc',
'image_util.h',
- 'json/json_reader.cc',
- 'json/json_reader.h',
- 'json/json_writer.cc',
- 'json/json_writer.h',
- 'json/string_escape.cc',
- 'json/string_escape.h',
- 'keyboard_code_conversion_gtk.cc',
- 'keyboard_code_conversion_gtk.h',
- 'keyboard_codes.h',
- 'keyboard_codes_win.h',
- 'keyboard_codes_posix.h',
'linux_util.cc',
'linux_util.h',
'md5.cc',
@@ -642,11 +659,6 @@
'cflags': [
'-fPIC',
],
- # Official builds set -gstabs, which fails when building with -fPIC.
- # It's useless on 64 bits anyways because breakpad doesn't work then.
- 'cflags!': [
- '-gstabs',
- ],
'direct_dependent_settings': {
'include_dirs': [
'..',
diff --git a/base/base.target.mk b/base/base.target.mk
index 2f152ce..566e074 100644
--- a/base/base.target.mk
+++ b/base/base.target.mk
@@ -20,6 +20,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -73,6 +74,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -124,21 +126,27 @@ OBJS := $(obj).target/$(TARGET)/base/third_party/dmg_fp/dtoa.o \
$(obj).target/$(TARGET)/base/condition_variable_posix.o \
$(obj).target/$(TARGET)/base/debug_util.o \
$(obj).target/$(TARGET)/base/debug_util_posix.o \
- $(obj).target/$(TARGET)/base/env_var.o \
- $(obj).target/$(TARGET)/base/event_synthesis_gtk.o \
+ $(obj).target/$(TARGET)/base/environment.o \
$(obj).target/$(TARGET)/base/file_path.o \
$(obj).target/$(TARGET)/base/file_util.o \
+ $(obj).target/$(TARGET)/base/file_util_linux.o \
$(obj).target/$(TARGET)/base/file_util_posix.o \
+ $(obj).target/$(TARGET)/base/file_util_proxy.o \
$(obj).target/$(TARGET)/base/global_descriptors_posix.o \
$(obj).target/$(TARGET)/base/gtk_util.o \
$(obj).target/$(TARGET)/base/histogram.o \
+ $(obj).target/$(TARGET)/base/json/json_reader.o \
+ $(obj).target/$(TARGET)/base/json/json_writer.o \
+ $(obj).target/$(TARGET)/base/json/string_escape.o \
$(obj).target/$(TARGET)/base/lazy_instance.o \
$(obj).target/$(TARGET)/base/lock.o \
$(obj).target/$(TARGET)/base/lock_impl_posix.o \
$(obj).target/$(TARGET)/base/logging.o \
$(obj).target/$(TARGET)/base/memory_debug.o \
$(obj).target/$(TARGET)/base/message_loop.o \
+ $(obj).target/$(TARGET)/base/message_loop_proxy.o \
$(obj).target/$(TARGET)/base/message_loop_proxy_impl.o \
+ $(obj).target/$(TARGET)/base/message_pump.o \
$(obj).target/$(TARGET)/base/message_pump_default.o \
$(obj).target/$(TARGET)/base/mime_util_xdg.o \
$(obj).target/$(TARGET)/base/native_library_linux.o \
@@ -156,20 +164,26 @@ OBJS := $(obj).target/$(TARGET)/base/third_party/dmg_fp/dtoa.o \
$(obj).target/$(TARGET)/base/rand_util.o \
$(obj).target/$(TARGET)/base/rand_util_posix.o \
$(obj).target/$(TARGET)/base/ref_counted.o \
+ $(obj).target/$(TARGET)/base/ref_counted_memory.o \
$(obj).target/$(TARGET)/base/safe_strerror_posix.o \
$(obj).target/$(TARGET)/base/scoped_temp_dir.o \
$(obj).target/$(TARGET)/base/sha1_portable.o \
$(obj).target/$(TARGET)/base/shared_memory_posix.o \
$(obj).target/$(TARGET)/base/simple_thread.o \
+ $(obj).target/$(TARGET)/base/stats_counters.o \
$(obj).target/$(TARGET)/base/stats_table.o \
+ $(obj).target/$(TARGET)/base/string_number_conversions.o \
$(obj).target/$(TARGET)/base/string_piece.o \
$(obj).target/$(TARGET)/base/string_split.o \
$(obj).target/$(TARGET)/base/string_util.o \
+ $(obj).target/$(TARGET)/base/stringprintf.o \
$(obj).target/$(TARGET)/base/sys_info_linux.o \
$(obj).target/$(TARGET)/base/sys_info_posix.o \
$(obj).target/$(TARGET)/base/sys_string_conversions_linux.o \
$(obj).target/$(TARGET)/base/task.o \
+ $(obj).target/$(TARGET)/base/task_queue.o \
$(obj).target/$(TARGET)/base/thread.o \
+ $(obj).target/$(TARGET)/base/thread_checker.o \
$(obj).target/$(TARGET)/base/thread_collision_warner.o \
$(obj).target/$(TARGET)/base/thread_local_posix.o \
$(obj).target/$(TARGET)/base/thread_local_storage_posix.o \
@@ -183,6 +197,7 @@ OBJS := $(obj).target/$(TARGET)/base/third_party/dmg_fp/dtoa.o \
$(obj).target/$(TARGET)/base/utf_string_conversion_utils.o \
$(obj).target/$(TARGET)/base/utf_string_conversions.o \
$(obj).target/$(TARGET)/base/values.o \
+ $(obj).target/$(TARGET)/base/vlog.o \
$(obj).target/$(TARGET)/base/waitable_event_posix.o \
$(obj).target/$(TARGET)/base/waitable_event_watcher_posix.o \
$(obj).target/$(TARGET)/base/watchdog.o \
@@ -203,10 +218,6 @@ OBJS := $(obj).target/$(TARGET)/base/third_party/dmg_fp/dtoa.o \
$(obj).target/$(TARGET)/base/field_trial.o \
$(obj).target/$(TARGET)/base/file_descriptor_shuffle.o \
$(obj).target/$(TARGET)/base/hmac_nss.o \
- $(obj).target/$(TARGET)/base/json/json_reader.o \
- $(obj).target/$(TARGET)/base/json/json_writer.o \
- $(obj).target/$(TARGET)/base/json/string_escape.o \
- $(obj).target/$(TARGET)/base/keyboard_code_conversion_gtk.o \
$(obj).target/$(TARGET)/base/linux_util.o \
$(obj).target/$(TARGET)/base/md5.o \
$(obj).target/$(TARGET)/base/message_pump_glib.o \
@@ -256,11 +267,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/base64.h b/base/base64.h
index d45a8a3..39cebfb 100644
--- a/base/base64.h
+++ b/base/base64.h
@@ -4,6 +4,7 @@
#ifndef BASE_BASE64_H__
#define BASE_BASE64_H__
+#pragma once
#include <string>
diff --git a/base/base_drag_source.h b/base/base_drag_source.h
index 0489038..c8fcc7e 100644
--- a/base/base_drag_source.h
+++ b/base/base_drag_source.h
@@ -4,6 +4,7 @@
#ifndef BASE_BASE_DRAG_SOURCE_H_
#define BASE_BASE_DRAG_SOURCE_H_
+#pragma once
#include <objidl.h>
diff --git a/base/base_drop_target.h b/base/base_drop_target.h
index 942c996..de66ce2 100644
--- a/base/base_drop_target.h
+++ b/base/base_drop_target.h
@@ -4,6 +4,7 @@
#ifndef BASE_BASE_DROP_TARGET_H_
#define BASE_BASE_DROP_TARGET_H_
+#pragma once
#include <objidl.h>
diff --git a/base/base_i18n.target.mk b/base/base_i18n.target.mk
index 5e771c2..1ceeabd 100644
--- a/base/base_i18n.target.mk
+++ b/base/base_i18n.target.mk
@@ -20,6 +20,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -69,6 +70,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -101,7 +103,8 @@ INCS_Release := -Ithird_party/icu/public/common \
-Ithird_party/icu/public/i18n \
-I.
-OBJS := $(obj).target/$(TARGET)/base/i18n/file_util_icu.o \
+OBJS := $(obj).target/$(TARGET)/base/i18n/char_iterator.o \
+ $(obj).target/$(TARGET)/base/i18n/file_util_icu.o \
$(obj).target/$(TARGET)/base/i18n/icu_encoding_detection.o \
$(obj).target/$(TARGET)/base/i18n/icu_string_conversions.o \
$(obj).target/$(TARGET)/base/i18n/icu_util.o \
@@ -135,11 +138,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/base_paths.h b/base/base_paths.h
index 6a8342e..0f9be04 100644
--- a/base/base_paths.h
+++ b/base/base_paths.h
@@ -4,6 +4,7 @@
#ifndef BASE_BASE_PATHS_H_
#define BASE_BASE_PATHS_H_
+#pragma once
// This file declares path keys for the base module. These can be used with
// the PathService to access various special directories and files.
diff --git a/base/base_paths_mac.h b/base/base_paths_mac.h
index ac75402..cb6fbd0 100644
--- a/base/base_paths_mac.h
+++ b/base/base_paths_mac.h
@@ -4,6 +4,7 @@
#ifndef BASE_BASE_PATHS_MAC_H_
#define BASE_BASE_PATHS_MAC_H_
+#pragma once
// This file declares Mac-specific path keys for the base module.
// These can be used with the PathService to access various special
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
index df9f362..793bece 100644
--- a/base/base_paths_mac.mm
+++ b/base/base_paths_mac.mm
@@ -7,6 +7,7 @@
#import <Cocoa/Cocoa.h>
#include <mach-o/dyld.h>
+#include "base/compiler_specific.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
@@ -14,48 +15,62 @@
#include "base/path_service.h"
#include "base/string_util.h"
+namespace {
+
+bool GetNSExecutablePath(FilePath* path) WARN_UNUSED_RESULT;
+
+bool GetNSExecutablePath(FilePath* path) {
+ DCHECK(path);
+ // Executable path can have relative references ("..") depending on
+ // how the app was launched.
+ uint32_t executable_length = 0;
+ _NSGetExecutablePath(NULL, &executable_length);
+ DCHECK_GE(executable_length, 1u);
+ std::string executable_path;
+ char* executable_path_c = WriteInto(&executable_path, executable_length);
+ int rv = _NSGetExecutablePath(executable_path_c, &executable_length);
+ DCHECK_EQ(rv, 0);
+ DCHECK(!executable_path.empty());
+ if ((rv != 0) || (executable_path.empty()))
+ return false;
+ *path = FilePath(executable_path);
+ return true;
+}
+
+} // namespace
+
namespace base {
bool PathProviderMac(int key, FilePath* result) {
- std::string cur;
switch (key) {
case base::FILE_EXE:
case base::FILE_MODULE: {
- // Executable path can have relative references ("..") depending on
- // how the app was launched.
- uint32_t executable_length = 0;
- _NSGetExecutablePath(NULL, &executable_length);
- DCHECK_GT(executable_length, 1u);
- char* executable = WriteInto(&cur, executable_length);
- int rv = _NSGetExecutablePath(executable, &executable_length);
- DCHECK_EQ(rv, 0);
- DCHECK(!cur.empty());
- break;
+ return GetNSExecutablePath(result);
}
case base::DIR_USER_CACHE:
return mac_util::GetUserDirectory(NSCachesDirectory, result);
case base::DIR_APP_DATA:
return mac_util::GetUserDirectory(NSApplicationSupportDirectory, result);
case base::DIR_SOURCE_ROOT: {
- PathService::Get(base::DIR_EXE, result);
- if (mac_util::AmIBundled()) {
- // The bundled app executables (Chromium, TestShell, etc) live five
- // levels down, eg:
- // src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium.
- *result = result->DirName().DirName().DirName().DirName().DirName();
- } else {
- // Unit tests execute two levels deep from the source root, eg:
- // src/xcodebuild/{Debug|Release}/base_unittests
- *result = result->DirName().DirName();
+ if (GetNSExecutablePath(result)) {
+ // Start with the executable's directory.
+ *result = result->DirName();
+ if (mac_util::AmIBundled()) {
+ // The bundled app executables (Chromium, TestShell, etc) live five
+ // levels down, eg:
+ // src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
+ *result = result->DirName().DirName().DirName().DirName().DirName();
+ } else {
+ // Unit tests execute two levels deep from the source root, eg:
+ // src/xcodebuild/{Debug|Release}/base_unittests
+ *result = result->DirName().DirName();
+ }
}
return true;
}
default:
return false;
}
-
- *result = FilePath(cur);
- return true;
}
} // namespace base
diff --git a/base/base_paths_posix.cc b/base/base_paths_posix.cc
index 3866010..8707c4c 100644
--- a/base/base_paths_posix.cc
+++ b/base/base_paths_posix.cc
@@ -12,7 +12,7 @@
#include <sys/sysctl.h>
#endif
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
@@ -61,9 +61,9 @@ bool PathProviderPosix(int key, FilePath* result) {
case base::DIR_SOURCE_ROOT: {
// Allow passing this in the environment, for more flexibility in build
// tree configurations (sub-project builds, gyp --output_dir, etc.)
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
std::string cr_source_root;
- if (env->GetEnv("CR_SOURCE_ROOT", &cr_source_root)) {
+ if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) {
path = FilePath(cr_source_root);
if (file_util::PathExists(path.Append("base/base_paths_posix.cc"))) {
*result = path;
@@ -104,11 +104,15 @@ bool PathProviderPosix(int key, FilePath* result) {
return false;
}
case base::DIR_USER_CACHE:
+<<<<<<< HEAD
#ifdef ANDROID
NOTREACHED();
return false;
#else
scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+=======
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+>>>>>>> Chromium at release 7.0.540.0
FilePath cache_dir(base::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
".cache"));
*result = cache_dir;
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
index 7cf0314..9e2db36 100644
--- a/base/base_paths_win.h
+++ b/base/base_paths_win.h
@@ -4,6 +4,7 @@
#ifndef BASE_BASE_PATHS_WIN_H__
#define BASE_BASE_PATHS_WIN_H__
+#pragma once
// This file declares windows-specific path keys for the base module.
// These can be used with the PathService to access various special
diff --git a/base/base_switches.cc b/base/base_switches.cc
index 2613623..49c6487 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.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.
@@ -11,27 +11,37 @@ namespace switches {
// seconds for the debugger to attach to itself. Then a break point will be hit.
const char kDebugOnStart[] = "debug-on-start";
-// Will wait for 60 seconds for a debugger to come to attach to the process.
-const char kWaitForDebugger[] = "wait-for-debugger";
-
-// Suppresses all error dialogs when present.
-const char kNoErrorDialogs[] = "noerrdialogs";
-
// Disables the crash reporting.
const char kDisableBreakpad[] = "disable-breakpad";
+// Enable DCHECKs in release mode.
+const char kEnableDCHECK[] = "enable-dcheck";
+
// Generates full memory crash dump.
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
-// The value of this switch determines whether the process is started as a
-// renderer or plugin host. If it's empty, it's the browser.
-const char kProcessType[] = "type";
-
-// Enable DCHECKs in release mode.
-const char kEnableDCHECK[] = "enable-dcheck";
+// Suppresses all error dialogs when present.
+const char kNoErrorDialogs[] = "noerrdialogs";
// Disable win_util::MessageBox. This is useful when running as part of
// scripts that do not have a user interface.
const char kNoMessageBox[] = "no-message-box";
+// When running certain tests that spawn child processes, this switch indicates
+// to the test framework that the current process is a child process.
+const char kTestChildProcess[] = "test-child-process";
+
+// Gives the default maximal active V-logging level; 0 is the default.
+// Normally positive values are used for V-logging levels.
+const char kV[] = "v";
+
+// Gives the per-module maximal V-logging levels to override the value
+// given by --v. E.g. "my_module=2,foo*=3" would change the logging
+// level for all code in source files "my_module.*" and "foo*.*"
+// ("-inl" suffixes are also disregarded for this matching).
+const char kVModule[] = "vmodule";
+
+// Will wait for 60 seconds for a debugger to come to attach to the process.
+const char kWaitForDebugger[] = "wait-for-debugger";
+
} // namespace switches
diff --git a/base/base_switches.h b/base/base_switches.h
index 4074043..56b6bc9 100644
--- a/base/base_switches.h
+++ b/base/base_switches.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.
@@ -6,17 +6,20 @@
#ifndef BASE_BASE_SWITCHES_H_
#define BASE_BASE_SWITCHES_H_
+#pragma once
namespace switches {
extern const char kDebugOnStart[];
-extern const char kWaitForDebugger[];
extern const char kDisableBreakpad[];
+extern const char kEnableDCHECK[];
extern const char kFullMemoryCrashReport[];
extern const char kNoErrorDialogs[];
-extern const char kProcessType[];
-extern const char kEnableDCHECK[];
extern const char kNoMessageBox[];
+extern const char kTestChildProcess[];
+extern const char kV[];
+extern const char kVModule[];
+extern const char kWaitForDebugger[];
} // namespace switches
diff --git a/base/base_unittests.target.mk b/base/base_unittests.target.mk
index dba329d..bccc717 100644
--- a/base/base_unittests.target.mk
+++ b/base/base_unittests.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -77,6 +78,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -126,13 +128,14 @@ OBJS := $(obj).target/$(TARGET)/base/test/run_all_unittests.o \
$(obj).target/$(TARGET)/base/condition_variable_unittest.o \
$(obj).target/$(TARGET)/base/crypto/encryptor_unittest.o \
$(obj).target/$(TARGET)/base/crypto/rsa_private_key_unittest.o \
+ $(obj).target/$(TARGET)/base/crypto/rsa_private_key_nss_unittest.o \
$(obj).target/$(TARGET)/base/crypto/signature_creator_unittest.o \
$(obj).target/$(TARGET)/base/crypto/signature_verifier_unittest.o \
$(obj).target/$(TARGET)/base/crypto/symmetric_key_unittest.o \
$(obj).target/$(TARGET)/base/data_pack_unittest.o \
$(obj).target/$(TARGET)/base/debug_util_unittest.o \
$(obj).target/$(TARGET)/base/dir_reader_posix_unittest.o \
- $(obj).target/$(TARGET)/base/env_var_unittest.o \
+ $(obj).target/$(TARGET)/base/environment_unittest.o \
$(obj).target/$(TARGET)/base/field_trial_unittest.o \
$(obj).target/$(TARGET)/base/file_descriptor_shuffle_unittest.o \
$(obj).target/$(TARGET)/base/file_path_unittest.o \
@@ -141,6 +144,7 @@ OBJS := $(obj).target/$(TARGET)/base/test/run_all_unittests.o \
$(obj).target/$(TARGET)/base/histogram_unittest.o \
$(obj).target/$(TARGET)/base/hmac_unittest.o \
$(obj).target/$(TARGET)/base/id_map_unittest.o \
+ $(obj).target/$(TARGET)/base/i18n/char_iterator_unittest.o \
$(obj).target/$(TARGET)/base/i18n/file_util_icu_unittest.o \
$(obj).target/$(TARGET)/base/i18n/icu_string_conversions_unittest.o \
$(obj).target/$(TARGET)/base/i18n/rtl_unittest.o \
@@ -152,12 +156,16 @@ OBJS := $(obj).target/$(TARGET)/base/test/run_all_unittests.o \
$(obj).target/$(TARGET)/base/leak_tracker_unittest.o \
$(obj).target/$(TARGET)/base/linked_list_unittest.o \
$(obj).target/$(TARGET)/base/linked_ptr_unittest.o \
+ $(obj).target/$(TARGET)/base/lock_unittest.o \
$(obj).target/$(TARGET)/base/message_loop_proxy_impl_unittest.o \
$(obj).target/$(TARGET)/base/message_loop_unittest.o \
$(obj).target/$(TARGET)/base/message_pump_glib_unittest.o \
+ $(obj).target/$(TARGET)/base/non_thread_safe_unittest.o \
$(obj).target/$(TARGET)/base/observer_list_unittest.o \
$(obj).target/$(TARGET)/base/path_service_unittest.o \
$(obj).target/$(TARGET)/base/pickle_unittest.o \
+ $(obj).target/$(TARGET)/base/platform_file_unittest.o \
+ $(obj).target/$(TARGET)/base/platform_thread_unittest.o \
$(obj).target/$(TARGET)/base/pr_time_unittest.o \
$(obj).target/$(TARGET)/base/process_util_unittest.o \
$(obj).target/$(TARGET)/base/rand_util_unittest.o \
@@ -172,12 +180,16 @@ OBJS := $(obj).target/$(TARGET)/base/test/run_all_unittests.o \
$(obj).target/$(TARGET)/base/singleton_unittest.o \
$(obj).target/$(TARGET)/base/stack_container_unittest.o \
$(obj).target/$(TARGET)/base/stats_table_unittest.o \
+ $(obj).target/$(TARGET)/base/string_number_conversions_unittest.o \
$(obj).target/$(TARGET)/base/string_piece_unittest.o \
$(obj).target/$(TARGET)/base/string_split_unittest.o \
$(obj).target/$(TARGET)/base/string_tokenizer_unittest.o \
$(obj).target/$(TARGET)/base/string_util_unittest.o \
+ $(obj).target/$(TARGET)/base/stringprintf_unittest.o \
$(obj).target/$(TARGET)/base/sys_info_unittest.o \
$(obj).target/$(TARGET)/base/sys_string_conversions_unittest.o \
+ $(obj).target/$(TARGET)/base/task_queue_unittest.o \
+ $(obj).target/$(TARGET)/base/thread_checker_unittest.o \
$(obj).target/$(TARGET)/base/thread_collision_warner_unittest.o \
$(obj).target/$(TARGET)/base/thread_local_storage_unittest.o \
$(obj).target/$(TARGET)/base/thread_local_unittest.o \
@@ -191,6 +203,7 @@ OBJS := $(obj).target/$(TARGET)/base/test/run_all_unittests.o \
$(obj).target/$(TARGET)/base/utf_string_conversions_unittest.o \
$(obj).target/$(TARGET)/base/values_unittest.o \
$(obj).target/$(TARGET)/base/version_unittest.o \
+ $(obj).target/$(TARGET)/base/vlog_unittest.o \
$(obj).target/$(TARGET)/base/waitable_event_unittest.o \
$(obj).target/$(TARGET)/base/waitable_event_watcher_unittest.o \
$(obj).target/$(TARGET)/base/watchdog_unittest.o \
@@ -202,7 +215,7 @@ OBJS := $(obj).target/$(TARGET)/base/test/run_all_unittests.o \
all_deps += $(OBJS)
# Make sure our dependencies are built before any of us.
-$(OBJS): | $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a xdisplaycheck $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a
+$(OBJS): | $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a xdisplaycheck $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
@@ -229,14 +242,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -269,7 +283,7 @@ LIBS := -lrt \
$(builddir)/base_unittests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/base_unittests: LIBS := $(LIBS)
$(builddir)/base_unittests: TOOLSET := $(TOOLSET)
-$(builddir)/base_unittests: $(OBJS) $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a FORCE_DO_CMD
+$(builddir)/base_unittests: $(OBJS) $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a FORCE_DO_CMD
$(call do_cmd,link)
all_deps += $(builddir)/base_unittests
diff --git a/base/basictypes.h b/base/basictypes.h
index 2fc5538..74c0460 100644
--- a/base/basictypes.h
+++ b/base/basictypes.h
@@ -4,6 +4,7 @@
#ifndef BASE_BASICTYPES_H_
#define BASE_BASICTYPES_H_
+#pragma once
#include <limits.h> // So we can set the bounds of our types
#include <stddef.h> // For size_t
diff --git a/base/bits.h b/base/bits.h
index b2209e8..75f9859 100644
--- a/base/bits.h
+++ b/base/bits.h
@@ -6,6 +6,7 @@
#ifndef BASE_BITS_H_
#define BASE_BITS_H_
+#pragma once
#include "base/basictypes.h"
#include "base/logging.h"
diff --git a/base/callback.h b/base/callback.h
index 17a1adc..7f2eb70 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -4,6 +4,7 @@
#ifndef BASE_CALLBACK_H_
#define BASE_CALLBACK_H_
+#pragma once
#include "base/tuple.h"
#include "base/raw_scoped_refptr_mismatch_checker.h"
diff --git a/base/cancellation_flag.h b/base/cancellation_flag.h
index b9c045d..98ca846 100644
--- a/base/cancellation_flag.h
+++ b/base/cancellation_flag.h
@@ -4,6 +4,7 @@
#ifndef BASE_CANCELLATION_FLAG_H_
#define BASE_CANCELLATION_FLAG_H_
+#pragma once
#include "base/atomicops.h"
#include "base/platform_thread.h"
diff --git a/base/chrome_application_mac.h b/base/chrome_application_mac.h
index 07fd433..3d620b4 100644
--- a/base/chrome_application_mac.h
+++ b/base/chrome_application_mac.h
@@ -4,6 +4,7 @@
#ifndef BASE_CHROME_APPLICATION_MAC_H_
#define BASE_CHROME_APPLICATION_MAC_H_
+#pragma once
#import <AppKit/AppKit.h>
diff --git a/base/cocoa_protocols_mac.h b/base/cocoa_protocols_mac.h
index 1ff2878..c7808de 100644
--- a/base/cocoa_protocols_mac.h
+++ b/base/cocoa_protocols_mac.h
@@ -4,6 +4,7 @@
#ifndef BASE_COCOA_PROTOCOLS_MAC_H_
#define BASE_COCOA_PROTOCOLS_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/base/command_line.cc b/base/command_line.cc
index c046125..a68c8f3 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -21,9 +21,10 @@
#include "base/file_path.h"
#include "base/logging.h"
#include "base/singleton.h"
-#include "base/string_piece.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
#if defined(OS_LINUX)
// Linux/glibc doesn't natively have setproctitle().
@@ -104,9 +105,17 @@ void CommandLine::ParseFromString(const std::wstring& command_line) {
LocalFree(args);
}
+// static
+CommandLine CommandLine::FromString(const std::wstring& command_line) {
+ CommandLine cmd;
+ cmd.ParseFromString(command_line);
+ return cmd;
+}
+
CommandLine::CommandLine(const FilePath& program) {
if (!program.empty()) {
program_ = program.value();
+ // TODO(evanm): proper quoting here.
command_line_string_ = L'"' + program.value() + L'"';
}
}
@@ -117,6 +126,14 @@ CommandLine::CommandLine(ArgumentsOnly args_only) {
argv_.push_back("");
}
+CommandLine::CommandLine(int argc, const char* const* argv) {
+ InitFromArgv(argc, argv);
+}
+
+CommandLine::CommandLine(const std::vector<std::string>& argv) {
+ InitFromArgv(argv);
+}
+
void CommandLine::InitFromArgv(int argc, const char* const* argv) {
for (int i = 0; i < argc; ++i)
argv_.push_back(argv[i]);
@@ -257,6 +274,12 @@ void CommandLine::Reset() {
current_process_commandline_ = NULL;
}
+// static
+CommandLine* CommandLine::ForCurrentProcess() {
+ DCHECK(current_process_commandline_);
+ return current_process_commandline_;
+}
+
bool CommandLine::HasSwitch(const std::string& switch_string) const {
std::string lowercased_switch(switch_string);
#if defined(OS_WIN)
@@ -265,7 +288,24 @@ bool CommandLine::HasSwitch(const std::string& switch_string) const {
return switches_.find(lowercased_switch) != switches_.end();
}
-std::wstring CommandLine::GetSwitchValue(
+#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 {
+ return WideToASCII(GetSwitchValue(switch_string));
+}
+
+FilePath CommandLine::GetSwitchValuePath(
+ const std::string& switch_string) const {
+ return FilePath(GetSwitchValueNative(switch_string));
+}
+
+CommandLine::StringType CommandLine::GetSwitchValueNative(
const std::string& switch_string) const {
std::string lowercased_switch(switch_string);
#if defined(OS_WIN)
@@ -276,14 +316,31 @@ std::wstring CommandLine::GetSwitchValue(
switches_.find(lowercased_switch);
if (result == switches_.end()) {
- return L"";
+ return CommandLine::StringType();
} else {
-#if defined(OS_WIN)
return result->second;
+ }
+}
+
+std::wstring CommandLine::GetSwitchValue(
+ const std::string& switch_string) const {
+ // TODO(evanm): deprecate.
+ CommandLine::StringType value = GetSwitchValueNative(switch_string);
+#if defined(OS_WIN)
+ return value;
#else
- return base::SysNativeMBToWide(result->second);
+ return base::SysNativeMBToWide(value);
#endif
- }
+}
+
+std::wstring CommandLine::GetSwitchValue(
+ const std::wstring& switch_string) const {
+ // TODO(evanm): deprecate.
+ return GetSwitchValue(WideToASCII(switch_string));
+}
+
+FilePath CommandLine::GetProgram() const {
+ return FilePath::FromWStringHack(program());
}
#if defined(OS_WIN)
@@ -303,69 +360,83 @@ std::string CommandLine::command_line_string() const {
}
#endif
-// static
-std::wstring CommandLine::PrefixedSwitchString(
- const std::string& switch_string) {
-#if defined(OS_WIN)
- return kSwitchPrefixes[0] + ASCIIToWide(switch_string);
-#else
- return ASCIIToWide(kSwitchPrefixes[0] + switch_string);
-#endif
-}
-
-// static
-std::wstring CommandLine::PrefixedSwitchStringWithValue(
- const std::string& switch_string, const std::wstring& value_string) {
- if (value_string.empty()) {
- return PrefixedSwitchString(switch_string);
- }
-
- return PrefixedSwitchString(switch_string +
-#if defined(OS_WIN)
- WideToASCII(kSwitchValueSeparator)
-#else
- kSwitchValueSeparator
-#endif
- ) + value_string;
-}
-
#if defined(OS_WIN)
void CommandLine::AppendSwitch(const std::string& switch_string) {
- std::wstring prefixed_switch_string = PrefixedSwitchString(switch_string);
command_line_string_.append(L" ");
- command_line_string_.append(prefixed_switch_string);
+ command_line_string_.append(kSwitchPrefixes[0] + ASCIIToWide(switch_string));
switches_[switch_string] = L"";
}
-void CommandLine::AppendSwitchWithValue(const std::string& switch_string,
- const std::wstring& value_string) {
- std::wstring value_string_edit;
+void CommandLine::AppendSwitchASCII(const std::string& switch_string,
+ const std::string& value_string) {
+ AppendSwitchNative(switch_string, ASCIIToWide(value_string));
+}
- // NOTE(jhughes): If the value contains a quotation mark at one
- // end but not both, you may get unusable output.
- if (!value_string.empty() &&
- (value_string.find(L" ") != std::wstring::npos) &&
- (value_string[0] != L'"') &&
- (value_string[value_string.length() - 1] != L'"')) {
- // need to provide quotes
- value_string_edit = StringPrintf(L"\"%ls\"", value_string.c_str());
- } else {
- value_string_edit = value_string;
+// Quote a string if necessary, such that CommandLineToArgvW() will
+// always process it as a single argument.
+static std::wstring WindowsStyleQuote(const std::wstring& arg) {
+ // We follow the quoting rules of CommandLineToArgvW.
+ // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+ if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
+ // No quoting necessary.
+ return arg;
}
+ std::wstring out;
+ out.push_back(L'"');
+ for (size_t i = 0; i < arg.size(); ++i) {
+ if (arg[i] == '\\') {
+ // Find the extent of this run of backslashes.
+ size_t start = i, end = start + 1;
+ for (; end < arg.size() && arg[end] == '\\'; ++end)
+ /* empty */;
+ size_t backslash_count = end - start;
+
+ // Backslashes are escapes only if the run is followed by a double quote.
+ // Since we also will end the string with a double quote, we escape for
+ // either a double quote or the end of the string.
+ if (end == arg.size() || arg[end] == '"') {
+ // To quote, we need to output 2x as many backslashes.
+ backslash_count *= 2;
+ }
+ for (size_t j = 0; j < backslash_count; ++j)
+ out.push_back('\\');
+
+ // Advance i to one before the end to balance i++ in loop.
+ i = end - 1;
+ } else if (arg[i] == '"') {
+ out.push_back('\\');
+ out.push_back('"');
+ } else {
+ out.push_back(arg[i]);
+ }
+ }
+ out.push_back('"');
+
+ return out;
+}
+
+void CommandLine::AppendSwitchNative(const std::string& switch_string,
+ const std::wstring& value) {
std::wstring combined_switch_string =
- PrefixedSwitchStringWithValue(switch_string, value_string_edit);
+ kSwitchPrefixes[0] + ASCIIToWide(switch_string);
+ if (!value.empty())
+ combined_switch_string += kSwitchValueSeparator + WindowsStyleQuote(value);
command_line_string_.append(L" ");
command_line_string_.append(combined_switch_string);
- switches_[switch_string] = value_string;
+ switches_[switch_string] = value;
+}
+
+void CommandLine::AppendArg(const std::string& value) {
+ DCHECK(IsStringUTF8(value));
+ AppendArgNative(UTF8ToWide(value));
}
-void CommandLine::AppendLooseValue(const std::wstring& value) {
- // TODO(evan): quoting?
+void CommandLine::AppendArgNative(const std::wstring& value) {
command_line_string_.append(L" ");
- command_line_string_.append(value);
+ command_line_string_.append(WindowsStyleQuote(value));
args_.push_back(value);
}
@@ -381,6 +452,8 @@ void CommandLine::AppendArguments(const CommandLine& other,
}
void CommandLine::PrependWrapper(const std::wstring& wrapper) {
+ if (wrapper.empty())
+ return;
// The wrapper may have embedded arguments (like "gdb --args"). In this case,
// we don't pretend to do anything fancy, we just split on spaces.
std::vector<std::wstring> wrapper_and_args;
@@ -395,17 +468,27 @@ void CommandLine::AppendSwitch(const std::string& switch_string) {
switches_[switch_string] = "";
}
-void CommandLine::AppendSwitchWithValue(const std::string& switch_string,
- const std::wstring& value_string) {
- std::string mb_value = base::SysWideToNativeMB(value_string);
+void CommandLine::AppendSwitchNative(const std::string& switch_string,
+ const std::string& value) {
+ std::string combined_switch_string = kSwitchPrefixes[0] + switch_string;
+ if (!value.empty())
+ combined_switch_string += kSwitchValueSeparator + value;
+ argv_.push_back(combined_switch_string);
+ switches_[switch_string] = value;
+}
- argv_.push_back(kSwitchPrefixes[0] + switch_string +
- kSwitchValueSeparator + mb_value);
- switches_[switch_string] = mb_value;
+void CommandLine::AppendSwitchASCII(const std::string& switch_string,
+ const std::string& value_string) {
+ AppendSwitchNative(switch_string, value_string);
}
-void CommandLine::AppendLooseValue(const std::wstring& value) {
- argv_.push_back(base::SysWideToNativeMB(value));
+void CommandLine::AppendArg(const std::string& value) {
+ AppendArgNative(value);
+}
+
+void CommandLine::AppendArgNative(const std::string& value) {
+ DCHECK(IsStringUTF8(value));
+ argv_.push_back(value);
}
void CommandLine::AppendArguments(const CommandLine& other,
@@ -421,10 +504,9 @@ void CommandLine::AppendArguments(const CommandLine& other,
switches_[i->first] = i->second;
}
-void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) {
+void CommandLine::PrependWrapper(const std::string& wrapper) {
// The wrapper may have embedded arguments (like "gdb --args"). In this case,
// we don't pretend to do anything fancy, we just split on spaces.
- const std::string wrapper = base::SysWideToNativeMB(wrapper_wide);
std::vector<std::string> wrapper_and_args;
SplitString(wrapper, ' ', &wrapper_and_args);
argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
@@ -432,6 +514,32 @@ void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) {
#endif
+void CommandLine::AppendArgPath(const FilePath& path) {
+ AppendArgNative(path.value());
+}
+
+void CommandLine::AppendSwitchPath(const std::string& switch_string,
+ const FilePath& path) {
+ AppendSwitchNative(switch_string, path.value());
+}
+
+void CommandLine::CopySwitchesFrom(const CommandLine& source,
+ const char* const switches[],
+ size_t count) {
+ for (size_t i = 0; i < count; ++i) {
+ if (source.HasSwitch(switches[i])) {
+ StringType value = source.GetSwitchValueNative(switches[i]);
+ AppendSwitchNative(switches[i], value);
+ }
+ }
+}
+
// private
CommandLine::CommandLine() {
}
+
+// static
+CommandLine* CommandLine::ForCurrentProcessMutable() {
+ DCHECK(current_process_commandline_);
+ return current_process_commandline_;
+}
diff --git a/base/command_line.h b/base/command_line.h
index 2c4f32d..ce10d65 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -15,6 +15,7 @@
#ifndef BASE_COMMAND_LINE_H_
#define BASE_COMMAND_LINE_H_
+#pragma once
#include "build/build_config.h"
@@ -23,10 +24,8 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/logging.h"
-#include "base/string_util.h"
+class FilePath;
class InProcessBrowserTest;
class CommandLine {
@@ -43,11 +42,7 @@ class CommandLine {
// Initialize by parsing the given command-line string.
// The program name is assumed to be the first item in the string.
void ParseFromString(const std::wstring& command_line);
- static CommandLine FromString(const std::wstring& command_line) {
- CommandLine cmd;
- cmd.ParseFromString(command_line);
- return cmd;
- }
+ static CommandLine FromString(const std::wstring& command_line);
#elif defined(OS_POSIX)
// The type of native command line arguments.
typedef std::string StringType;
@@ -56,12 +51,8 @@ class CommandLine {
void InitFromArgv(int argc, const char* const* argv);
void InitFromArgv(const std::vector<std::string>& argv);
- CommandLine(int argc, const char* const* argv) {
- InitFromArgv(argc, argv);
- }
- explicit CommandLine(const std::vector<std::string>& argv) {
- InitFromArgv(argv);
- }
+ CommandLine(int argc, const char* const* argv);
+ explicit CommandLine(const std::vector<std::string>& argv);
#endif
// Construct a new, empty command line.
@@ -87,44 +78,22 @@ class CommandLine {
// If Init is called only once, e.g. in main(), calling Reset() is not
// necessary.
static void Reset();
- // The same function snuck into this class under two different names;
- // this one remains for backwards compat with the older o3d build.
- static void Terminate() { Reset(); }
// Get the singleton CommandLine representing the current process's
// command line. Note: returned value is mutable, but not thread safe;
// only mutate if you know what you're doing!
- static CommandLine* ForCurrentProcess() {
- DCHECK(current_process_commandline_);
- return current_process_commandline_;
- }
+ static CommandLine* ForCurrentProcess();
// Returns true if this command line contains the given switch.
// (Switch names are case-insensitive.)
bool HasSwitch(const std::string& switch_string) const;
- // Deprecated version of the above.
- bool HasSwitch(const std::wstring& switch_string) const {
- return HasSwitch(WideToASCII(switch_string));
- }
-
// Returns the value associated with the given switch. If the
// switch has no value or isn't present, this method returns
// the empty string.
- // TODO(evanm): move these into command_line.cpp once we've fixed the
- // wstringness.
- std::string GetSwitchValueASCII(const std::string& switch_string) const {
- return WideToASCII(GetSwitchValue(switch_string));
- }
- FilePath GetSwitchValuePath(const std::string& switch_string) const {
- return FilePath::FromWStringHack(GetSwitchValue(switch_string));
- }
-
- // Deprecated versions of the above.
- std::wstring GetSwitchValue(const std::string& switch_string) const;
- std::wstring GetSwitchValue(const std::wstring& switch_string) const {
- return GetSwitchValue(WideToASCII(switch_string));
- }
+ std::string GetSwitchValueASCII(const std::string& switch_string) const;
+ FilePath GetSwitchValuePath(const std::string& switch_string) const;
+ StringType GetSwitchValueNative(const std::string& switch_string) const;
// Get the number of switches in this process.
size_t GetSwitchCount() const { return switches_.size(); }
@@ -133,7 +102,7 @@ class CommandLine {
typedef std::map<std::string, StringType> SwitchMap;
// Get a copy of all switches, along with their values
- SwitchMap GetSwitches() const {
+ const SwitchMap& GetSwitches() const {
return switches_;
}
@@ -156,48 +125,50 @@ class CommandLine {
#endif
// Returns the program part of the command line string (the first item).
- FilePath GetProgram() const {
- return FilePath::FromWStringHack(program());
- }
-
- // Returns the program part of the command line string (the first item).
- // Deprecated version of the above.
- std::wstring program() const;
-
- // Return a copy of the string prefixed with a switch prefix.
- // Used internally.
- static std::wstring PrefixedSwitchString(const std::string& switch_string);
-
- // Return a copy of the string prefixed with a switch prefix,
- // and appended with the given value. Used internally.
- static std::wstring PrefixedSwitchStringWithValue(
- const std::string& switch_string,
- const std::wstring& value_string);
+ FilePath GetProgram() const;
- // Appends the given switch string (preceded by a space and a switch
- // prefix) to the given string.
+ // Append a switch to the command line.
void AppendSwitch(const std::string& switch_string);
- // Appends the given switch string (preceded by a space and a switch
- // prefix) to the given string, with the given value attached.
- void AppendSwitchWithValue(const std::string& switch_string,
- const std::wstring& value_string);
- void AppendSwitchWithValue(const std::string& switch_string,
- const std::string& value_string) {
- AppendSwitchWithValue(switch_string, ASCIIToWide(value_string));
- }
-
- // Append a loose value to the command line.
- void AppendLooseValue(const std::wstring& value);
+ // Append a switch and value to the command line.
+ void AppendSwitchPath(const std::string& switch_string, const FilePath& path);
+ void AppendSwitchNative(const std::string& switch_string,
+ const StringType& value);
+ void AppendSwitchASCII(const std::string& switch_string,
+ const std::string& value);
+
+ // Append an argument to the command line.
+ // Note on quoting: the argument will be quoted properly such that it is
+ // interpreted as one argument to the target command.
+ // AppendArg is primarily for ASCII; non-ASCII input will be
+ // interpreted as UTF-8.
+ void AppendArg(const std::string& value);
+ void AppendArgPath(const FilePath& value);
+ void AppendArgNative(const StringType& value);
// Append the arguments from another command line to this one.
// If |include_program| is true, include |other|'s program as well.
void AppendArguments(const CommandLine& other,
bool include_program);
- // On POSIX systems it's common to run processes via a wrapper (like
- // "valgrind" or "gdb --args").
- void PrependWrapper(const std::wstring& wrapper);
+ // Insert a command before the current command. Common for debuggers,
+ // like "valgrind" or "gdb --args".
+ void PrependWrapper(const StringType& wrapper);
+
+ // Copy a set of switches (and their values, if any) from another command
+ // line. Commonly used when launching a subprocess.
+ 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.
+ std::wstring GetSwitchValue(const std::string& switch_string) const;
+ std::wstring GetSwitchValue(const std::wstring& switch_string) const;
+ std::wstring program() const;
+#if defined(OS_WIN)
+ // Deprecated on non-Windows.
+ bool HasSwitch(const std::wstring& switch_string) const;
+#endif
private:
friend class InProcessBrowserTest;
@@ -205,10 +176,7 @@ class CommandLine {
CommandLine();
// Used by InProcessBrowserTest.
- static CommandLine* ForCurrentProcessMutable() {
- DCHECK(current_process_commandline_);
- return current_process_commandline_;
- }
+ static CommandLine* ForCurrentProcessMutable();
// The singleton CommandLine instance representing the current process's
// command line.
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index 8f3c7c0..a34cf43 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.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,9 +7,19 @@
#include "base/command_line.h"
#include "base/basictypes.h"
-#include "base/string_util.h"
+#include "base/file_path.h"
+#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+// To test Windows quoting behavior, we use a string that has some backslashes
+// and quotes.
+// Consider the command-line argument: q\"bs1\bs2\\bs3q\\\"
+// Here it is with C-style escapes.
+#define TRICKY_QUOTED L"q\\\"bs1\\bs2\\\\bs3q\\\\\\\""
+// It should be parsed by Windows as: q"bs1\bs2\\bs3q\"
+// Here that is with C-style escapes.
+#define TRICKY L"q\"bs1\\bs2\\\\bs3q\\\""
+
TEST(CommandLineTest, CommandLineConstructor) {
#if defined(OS_WIN)
CommandLine cl = CommandLine::FromString(
@@ -17,6 +27,7 @@ TEST(CommandLineTest, CommandLineConstructor) {
L"--other-switches=\"--dog=canine --cat=feline\" "
L"-spaetzle=Crepe -=loosevalue flan "
L"--input-translation=\"45\"--output-rotation "
+ L"--quotes=" TRICKY_QUOTED L" "
L"-- -- --not-a-switch "
L"\"in the time of submarines...\"");
EXPECT_FALSE(cl.command_line_string().empty());
@@ -50,6 +61,9 @@ TEST(CommandLineTest, CommandLineConstructor) {
#endif
EXPECT_TRUE(cl.HasSwitch("other-switches"));
EXPECT_TRUE(cl.HasSwitch("input-translation"));
+#if defined(OS_WIN)
+ EXPECT_TRUE(cl.HasSwitch("quotes"));
+#endif
EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
@@ -58,6 +72,9 @@ TEST(CommandLineTest, CommandLineConstructor) {
EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
"other-switches"));
EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
+#if defined(OS_WIN)
+ EXPECT_EQ(TRICKY, cl.GetSwitchValueNative("quotes"));
+#endif
const std::vector<CommandLine::StringType>& args = cl.args();
ASSERT_EQ(5U, args.size());
@@ -100,24 +117,39 @@ TEST(CommandLineTest, EmptyString) {
TEST(CommandLineTest, AppendSwitches) {
std::string switch1 = "switch1";
std::string switch2 = "switch2";
- std::wstring value = L"value";
+ std::string value = "value";
std::string switch3 = "switch3";
- std::wstring value3 = L"a value with spaces";
+ std::string value3 = "a value with spaces";
std::string switch4 = "switch4";
- std::wstring value4 = L"\"a value with quotes\"";
+ std::string value4 = "\"a value with quotes\"";
+ std::string switch5 = "quotes";
+ std::string value5 = WideToUTF8(TRICKY);
CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
cl.AppendSwitch(switch1);
- cl.AppendSwitchWithValue(switch2, value);
- cl.AppendSwitchWithValue(switch3, value3);
- cl.AppendSwitchWithValue(switch4, value4);
+ cl.AppendSwitchASCII(switch2, value);
+ cl.AppendSwitchASCII(switch3, value3);
+ cl.AppendSwitchASCII(switch4, value4);
+ cl.AppendSwitchASCII(switch5, value5);
EXPECT_TRUE(cl.HasSwitch(switch1));
EXPECT_TRUE(cl.HasSwitch(switch2));
- EXPECT_EQ(value, cl.GetSwitchValue(switch2));
+ EXPECT_EQ(value, cl.GetSwitchValueASCII(switch2));
EXPECT_TRUE(cl.HasSwitch(switch3));
- EXPECT_EQ(value3, cl.GetSwitchValue(switch3));
+ EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3));
EXPECT_TRUE(cl.HasSwitch(switch4));
- EXPECT_EQ(value4, cl.GetSwitchValue(switch4));
+ EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4));
+ EXPECT_TRUE(cl.HasSwitch(switch5));
+ EXPECT_EQ(value5, cl.GetSwitchValueASCII(switch5));
+
+#if defined(OS_WIN)
+ EXPECT_EQ(L"\"Program\" "
+ L"--switch1 "
+ L"--switch2=value "
+ L"--switch3=\"a value with spaces\" "
+ L"--switch4=\"\\\"a value with quotes\\\"\" "
+ L"--quotes=\"" TRICKY_QUOTED L"\"",
+ cl.command_line_string());
+#endif
}
diff --git a/base/compat_execinfo.h b/base/compat_execinfo.h
index 13e4967..8ef7190 100644
--- a/base/compat_execinfo.h
+++ b/base/compat_execinfo.h
@@ -7,6 +7,7 @@
#ifndef BASE_COMPAT_EXECINFO_H_
#define BASE_COMPAT_EXECINFO_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 23b9f12..ce93998 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -4,6 +4,7 @@
#ifndef BASE_COMPILER_SPECIFIC_H_
#define BASE_COMPILER_SPECIFIC_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/condition_variable.h b/base/condition_variable.h
index da87bfc..4fe1892 100644
--- a/base/condition_variable.h
+++ b/base/condition_variable.h
@@ -64,6 +64,7 @@
#ifndef BASE_CONDITION_VARIABLE_H_
#define BASE_CONDITION_VARIABLE_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/condition_variable_unittest.cc b/base/condition_variable_unittest.cc
index 95756e0..67d1839 100644
--- a/base/condition_variable_unittest.cc
+++ b/base/condition_variable_unittest.cc
@@ -106,6 +106,11 @@ class WorkQueue : public PlatformThread::Delegate {
void SetTaskCount(int count);
void SetAllowHelp(bool allow);
+ // The following must be called without locking, and will spin wait until the
+ // threads are all in a wait state.
+ void SpinUntilAllThreadsAreWaiting();
+ void SpinUntilTaskCountLessThan(int task_count);
+
// Caller must acquire lock before calling.
void SetShutdown();
@@ -124,6 +129,7 @@ class WorkQueue : public PlatformThread::Delegate {
ConditionVariable no_more_tasks_; // Task count is zero.
const int thread_count_;
+ int waiting_thread_count_;
scoped_array<PlatformThreadHandle> thread_handles_;
std::vector<int> assignment_history_; // Number of assignment per worker.
std::vector<int> completion_history_; // Number of completions per worker.
@@ -184,8 +190,7 @@ TEST_F(ConditionVariableTest, TimeoutTest) {
}
// Test serial task servicing, as well as two parallel task servicing methods.
-// TODO(maruel): This test is flaky, see http://crbug.com/10607
-TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
+TEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
const int kThreadCount = 10;
WorkQueue queue(kThreadCount); // Start the threads.
@@ -199,10 +204,9 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
queue.all_threads_have_ids()->Wait();
}
- // Wait a bit more to allow threads to reach their wait state.
// If threads aren't in a wait state, they may start to gobble up tasks in
// parallel, short-circuiting (breaking) this test.
- PlatformThread::Sleep(100);
+ queue.SpinUntilAllThreadsAreWaiting();
{
// Since we have no tasks yet, all threads should be waiting by now.
@@ -224,7 +228,8 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
}
queue.work_is_available()->Signal(); // Start up one thread.
-
+ // Wait till we at least start to handle tasks (and we're not all waiting).
+ queue.SpinUntilTaskCountLessThan(kTaskCount);
{
// Wait until all 10 work tasks have at least been assigned.
@@ -244,14 +249,7 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
}
// Wait to be sure all tasks are done.
- while (1) {
- {
- AutoLock auto_lock(*queue.lock());
- if (kTaskCount == queue.GetNumberOfCompletedTasks())
- break;
- }
- PlatformThread::Sleep(30); // Wait a little.
- }
+ queue.SpinUntilAllThreadsAreWaiting();
{
// Check that all work was done by one thread id.
@@ -274,29 +272,20 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
}
queue.work_is_available()->Signal(); // But each worker can signal another.
+ // Wait till we at least start to handle tasks (and we're not all waiting).
+ queue.SpinUntilTaskCountLessThan(kTaskCount);
// Wait to allow the all workers to get done.
- while (1) {
- {
- AutoLock auto_lock(*queue.lock());
- if (kTaskCount == queue.GetNumberOfCompletedTasks())
- break;
- }
- PlatformThread::Sleep(30); // Wait a little.
- }
+ queue.SpinUntilAllThreadsAreWaiting();
{
// Wait until all work tasks have at least been assigned.
AutoLock auto_lock(*queue.lock());
while (queue.task_count())
queue.no_more_tasks()->Wait();
- // Since they can all run almost in parallel, there is no guarantee that all
- // tasks are finished, but we should have gotten here faster than it would
- // take to run all tasks serially.
- EXPECT_GT(queue.GetWorkTime().InMilliseconds() * (kTaskCount - 1),
- (base::Time::Now() - start_time).InMilliseconds());
// To avoid racy assumptions, we'll just assert that at least 2 threads
- // did work.
+ // did work. We know that the first worker should have gone to sleep, and
+ // hence a second worker should have gotten an assignment.
EXPECT_LE(2, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
@@ -307,8 +296,10 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
queue.SetAllowHelp(false);
}
queue.work_is_available()->Broadcast(); // Make them all try.
+ // Wait till we at least start to handle tasks (and we're not all waiting).
+ queue.SpinUntilTaskCountLessThan(3);
// Wait to allow the 3 workers to get done.
- PlatformThread::Sleep(45);
+ queue.SpinUntilAllThreadsAreWaiting();
{
AutoLock auto_lock(*queue.lock());
@@ -325,9 +316,11 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
queue.SetWorkTime(kThirtyMs);
queue.SetAllowHelp(true); // Allow (unnecessary) help requests.
}
- queue.work_is_available()->Broadcast(); // We already signal all threads.
+ queue.work_is_available()->Broadcast(); // Signal all threads.
+ // Wait till we at least start to handle tasks (and we're not all waiting).
+ queue.SpinUntilTaskCountLessThan(3);
// Wait to allow the 3 workers to get done.
- PlatformThread::Sleep(100);
+ queue.SpinUntilAllThreadsAreWaiting();
{
AutoLock auto_lock(*queue.lock());
@@ -340,40 +333,40 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
// Set up to make each task get help from another worker.
queue.ResetHistory();
- queue.SetTaskCount(20);
+ queue.SetTaskCount(20); // 2 tasks per thread.
queue.SetWorkTime(kThirtyMs);
queue.SetAllowHelp(true);
}
queue.work_is_available()->Signal(); // But each worker can signal another.
+ // Wait till we at least start to handle tasks (and we're not all waiting).
+ queue.SpinUntilTaskCountLessThan(20);
// Wait to allow the 10 workers to get done.
- PlatformThread::Sleep(100); // Should take about 60 ms.
+ queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms.
{
AutoLock auto_lock(*queue.lock());
EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
- EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread());
- EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread());
EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
// Same as last test, but with Broadcast().
queue.ResetHistory();
- queue.SetTaskCount(20); // 2 tasks per process.
+ queue.SetTaskCount(20); // 2 tasks per thread.
queue.SetWorkTime(kThirtyMs);
queue.SetAllowHelp(true);
}
queue.work_is_available()->Broadcast();
+ // Wait till we at least start to handle tasks (and we're not all waiting).
+ queue.SpinUntilTaskCountLessThan(20);
// Wait to allow the 10 workers to get done.
- PlatformThread::Sleep(100); // Should take about 60 ms.
+ queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms.
{
AutoLock auto_lock(*queue.lock());
EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
EXPECT_EQ(0, queue.task_count());
- EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread());
- EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread());
EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
queue.SetShutdown();
@@ -382,7 +375,6 @@ TEST_F(ConditionVariableTest, FLAKY_MultiThreadConsumerTest) {
SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
queue.ThreadSafeCheckShutdown(kThreadCount));
- PlatformThread::Sleep(10); // Be sure they're all shutdown.
}
TEST_F(ConditionVariableTest, LargeFastTaskTest) {
@@ -400,7 +392,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
}
// Wait a bit more to allow threads to reach their wait state.
- private_cv.TimedWait(kThirtyMs);
+ queue.SpinUntilAllThreadsAreWaiting();
{
// Since we have no tasks, all threads should be waiting by now.
@@ -427,11 +419,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
}
// Wait till the last of the tasks complete.
- // Don't bother to use locks: We may not get info in time... but we'll see it
- // eventually.
- SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
- 20 * kThreadCount ==
- queue.GetNumberOfCompletedTasks());
+ queue.SpinUntilAllThreadsAreWaiting();
{
// With Broadcast(), every thread should have participated.
@@ -459,11 +447,7 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
}
// Wait till the last of the tasks complete.
- // Don't bother to use locks: We may not get info in time... but we'll see it
- // eventually.
- SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
- 4 * kThreadCount ==
- queue.GetNumberOfCompletedTasks());
+ queue.SpinUntilAllThreadsAreWaiting();
{
// With Signal(), every thread should have participated.
@@ -482,7 +466,6 @@ TEST_F(ConditionVariableTest, LargeFastTaskTest) {
// Wait for shutdowns to complete.
SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
queue.ThreadSafeCheckShutdown(kThreadCount));
- PlatformThread::Sleep(10); // Be sure they're all shutdown.
}
//------------------------------------------------------------------------------
@@ -495,6 +478,7 @@ WorkQueue::WorkQueue(int thread_count)
all_threads_have_ids_(&lock_),
no_more_tasks_(&lock_),
thread_count_(thread_count),
+ waiting_thread_count_(0),
thread_handles_(new PlatformThreadHandle[thread_count]),
assignment_history_(thread_count),
completion_history_(thread_count),
@@ -525,6 +509,7 @@ WorkQueue::~WorkQueue() {
for (int i = 0; i < thread_count_; ++i) {
PlatformThread::Join(thread_handles_[i]);
}
+ EXPECT_EQ(0, waiting_thread_count_);
}
int WorkQueue::GetThreadId() {
@@ -670,6 +655,29 @@ void WorkQueue::SetShutdown() {
shutdown_ = true;
}
+void WorkQueue::SpinUntilAllThreadsAreWaiting() {
+ while (true) {
+ {
+ AutoLock auto_lock(lock_);
+ if (waiting_thread_count_ == thread_count_)
+ break;
+ }
+ PlatformThread::Sleep(30);
+ }
+}
+
+void WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
+ while (true) {
+ {
+ AutoLock auto_lock(lock_);
+ if (task_count_ < task_count)
+ break;
+ }
+ PlatformThread::Sleep(30);
+ }
+}
+
+
//------------------------------------------------------------------------------
// Define the standard worker task. Several tests will spin out many of these
// threads.
@@ -704,7 +712,9 @@ void WorkQueue::ThreadMain() {
{
AutoLock auto_lock(lock_);
while (0 == task_count() && !shutdown()) {
+ ++waiting_thread_count_;
work_is_available()->Wait();
+ --waiting_thread_count_;
}
if (shutdown()) {
// Ack the notification of a shutdown message back to the controller.
diff --git a/base/cpu.h b/base/cpu.h
index 15cc668..963da1a 100644
--- a/base/cpu.h
+++ b/base/cpu.h
@@ -4,6 +4,7 @@
#ifndef BASE_CPU_H_
#define BASE_CPU_H_
+#pragma once
#include <string>
diff --git a/base/crypto/capi_util.h b/base/crypto/capi_util.h
index 9f26403..8f89828 100644
--- a/base/crypto/capi_util.h
+++ b/base/crypto/capi_util.h
@@ -3,7 +3,8 @@
// found in the LICENSE file.
#ifndef BASE_CRYPTO_CAPI_UTIL_H_
-#define BASE_CRYPTO_CAPI_UTIl_H_
+#define BASE_CRYPTO_CAPI_UTIL_H_
+#pragma once
#include <windows.h>
#include <wincrypt.h>
@@ -28,4 +29,4 @@ BOOL CryptAcquireContextLocked(HCRYPTPROV* prov,
} // namespace base
-#endif // BASE_CRYPTO_CAPI_UTIl_H_
+#endif // BASE_CRYPTO_CAPI_UTIL_H_
diff --git a/base/crypto/cssm_init.h b/base/crypto/cssm_init.h
index b5ec03d..e457083 100644
--- a/base/crypto/cssm_init.h
+++ b/base/crypto/cssm_init.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef BASE_CRYPTO_CSSM_INIT_H_
#define BASE_CRYPTO_CSSM_INIT_H_
+#pragma once
#include <Security/cssm.h>
-#include "base/logging.h"
#include "base/scoped_ptr.h"
class Lock;
diff --git a/base/crypto/encryptor.h b/base/crypto/encryptor.h
index 5267549..f1d6f28 100644
--- a/base/crypto/encryptor.h
+++ b/base/crypto/encryptor.h
@@ -4,6 +4,7 @@
#ifndef BASE_CRYPTO_ENCRYPTOR_H_
#define BASE_CRYPTO_ENCRYPTOR_H_
+#pragma once
#include <string>
diff --git a/base/crypto/encryptor_unittest.cc b/base/crypto/encryptor_unittest.cc
index e6b8afb..bc66e55 100644
--- a/base/crypto/encryptor_unittest.cc
+++ b/base/crypto/encryptor_unittest.cc
@@ -39,8 +39,6 @@ TEST(EncryptorTest, EncryptDecrypt) {
// http://gladman.plushost.co.uk/oldsite/AES/index.php
// http://csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip
-// TODO(wtc): implement base::SymmetricKey::Import and enable this test on Mac.
-#if defined(USE_NSS) || defined(OS_WIN)
// NIST SP 800-38A test vector F.2.5 CBC-AES256.Encrypt.
TEST(EncryptorTest, EncryptAES256CBC) {
// From NIST SP 800-38a test cast F.2.5 CBC-AES256.Encrypt.
@@ -110,4 +108,3 @@ TEST(EncryptorTest, EncryptAES256CBC) {
EXPECT_EQ(plaintext, decypted);
}
-#endif // USE_NSS || OS_WIN
diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h
index 9c8bfd4..0349ade 100644
--- a/base/crypto/rsa_private_key.h
+++ b/base/crypto/rsa_private_key.h
@@ -4,6 +4,7 @@
#ifndef BASE_CRYPTO_RSA_PRIVATE_KEY_H_
#define BASE_CRYPTO_RSA_PRIVATE_KEY_H_
+#pragma once
#include "build/build_config.h"
@@ -23,6 +24,9 @@ struct SECKEYPublicKeyStr;
#if defined(OS_WIN)
#include "base/crypto/scoped_capi_types.h"
#endif
+#if defined(USE_NSS)
+#include "base/gtest_prod_util.h"
+#endif
namespace base {
@@ -161,12 +165,38 @@ class RSAPrivateKey {
// Create a new random instance. Can return NULL if initialization fails.
static RSAPrivateKey* Create(uint16 num_bits);
+ // Create a new random instance. Can return NULL if initialization fails.
+ // The created key is permanent and is not exportable in plaintext form.
+ //
+ // NOTE: Currently only available if USE_NSS is defined.
+ static RSAPrivateKey* CreateSensitive(uint16 num_bits);
+
// Create a new instance by importing an existing private key. The format is
// an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if
// initialization fails.
static RSAPrivateKey* CreateFromPrivateKeyInfo(
const std::vector<uint8>& input);
+ // Create a new instance by importing an existing private key. The format is
+ // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if
+ // initialization fails.
+ // The created key is permanent and is not exportable in plaintext form.
+ //
+ // NOTE: Currently only available if USE_NSS is defined.
+ static RSAPrivateKey* CreateSensitiveFromPrivateKeyInfo(
+ const std::vector<uint8>& input);
+
+ // Import an existing public key, and then search for the private
+ // half in the key database. The format of the public key blob is is
+ // an X509 SubjectPublicKeyInfo block. This can return NULL if
+ // initialization fails or the private key cannot be found. The
+ // caller takes ownership of the returned object, but nothing new is
+ // created in the key database.
+ //
+ // NOTE: Currently only available if USE_NSS is defined.
+ static RSAPrivateKey* FindFromPublicKeyInfo(
+ const std::vector<uint8>& input);
+
~RSAPrivateKey();
#if defined(USE_NSS)
@@ -185,10 +215,27 @@ class RSAPrivateKey {
bool ExportPublicKey(std::vector<uint8>* output);
private:
- // Constructor is private. Use Create() or CreateFromPrivateKeyInfo()
- // instead.
+#if defined(USE_NSS)
+ FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FindFromPublicKey);
+ FRIEND_TEST_ALL_PREFIXES(RSAPrivateKeyNSSTest, FailedFindFromPublicKey);
+#endif
+
+ // Constructor is private. Use one of the Create*() or Find*()
+ // methods above instead.
RSAPrivateKey();
+ // Shared helper for Create() and CreateSensitive().
+ // TODO(cmasone): consider replacing |permanent| and |sensitive| with a
+ // flags arg created by ORing together some enumerated values.
+ static RSAPrivateKey* CreateWithParams(uint16 num_bits,
+ bool permanent,
+ bool sensitive);
+
+ // Shared helper for CreateFromPrivateKeyInfo() and
+ // CreateSensitiveFromPrivateKeyInfo().
+ static RSAPrivateKey* CreateFromPrivateKeyInfoWithParams(
+ const std::vector<uint8>& input, bool permanent, bool sensitive);
+
#if defined(USE_NSS)
SECKEYPrivateKeyStr* key_;
SECKEYPublicKeyStr* public_key_;
diff --git a/base/crypto/rsa_private_key_mac.cc b/base/crypto/rsa_private_key_mac.cc
index 6dc6a42..e46e93e 100644
--- a/base/crypto/rsa_private_key_mac.cc
+++ b/base/crypto/rsa_private_key_mac.cc
@@ -49,6 +49,12 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
}
// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
const std::vector<uint8>& input) {
if (input.empty())
@@ -103,6 +109,20 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
return result.release();
}
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
+ const std::vector<uint8>& input) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
+ const std::vector<uint8>& input) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
RSAPrivateKey::RSAPrivateKey() {
memset(&key_, 0, sizeof(key_));
diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc
index 4fc0650..13e4f1f 100644
--- a/base/crypto/rsa_private_key_nss.cc
+++ b/base/crypto/rsa_private_key_nss.cc
@@ -13,6 +13,7 @@
#include "base/leak_annotations.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"
@@ -41,10 +42,14 @@ static bool ReadAttribute(SECKEYPrivateKey* key,
namespace base {
// static
-RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
+RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
+ bool permanent,
+ bool sensitive) {
+ base::EnsureNSSInit();
+
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
- PK11SlotInfo *slot = PK11_GetInternalSlot();
+ PK11SlotInfo *slot = GetDefaultNSSKeySlot();
if (!slot)
return NULL;
@@ -52,7 +57,7 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
param.keySizeInBits = num_bits;
param.pe = 65537L;
result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &param,
- &result->public_key_, PR_FALSE, PR_FALSE, NULL);
+ &result->public_key_, permanent, sensitive, NULL);
PK11_FreeSlot(slot);
if (!result->key_)
return NULL;
@@ -61,14 +66,30 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
}
// static
-RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
- const std::vector<uint8>& input) {
+RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
+ return CreateWithParams(num_bits,
+ PR_FALSE /* not permanent */,
+ PR_FALSE /* not sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
+ return CreateWithParams(num_bits,
+ PR_TRUE /* permanent */,
+ PR_TRUE /* sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
+ const std::vector<uint8>& input, bool permanent, bool sensitive) {
// This method currently leaks some memory.
// See http://crbug.com/34742.
ANNOTATE_SCOPED_MEMORY_LEAK;
+ base::EnsureNSSInit();
+
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
- PK11SlotInfo *slot = PK11_GetInternalSlot();
+ PK11SlotInfo *slot = GetDefaultNSSKeySlot();
if (!slot)
return NULL;
@@ -76,7 +97,7 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
der_private_key_info.data = const_cast<unsigned char*>(&input.front());
der_private_key_info.len = input.size();
SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot,
- &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE,
+ &der_private_key_info, NULL, NULL, permanent, sensitive,
KU_DIGITAL_SIGNATURE, &result->key_, NULL);
PK11_FreeSlot(slot);
if (rv != SECSuccess) {
@@ -93,6 +114,85 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
return result.release();
}
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
+ const std::vector<uint8>& input) {
+ return CreateFromPrivateKeyInfoWithParams(input,
+ PR_FALSE /* not permanent */,
+ PR_FALSE /* not sensitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
+ const std::vector<uint8>& input) {
+ return CreateFromPrivateKeyInfoWithParams(input,
+ PR_TRUE /* permanent */,
+ PR_TRUE /* seneitive */);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
+ const std::vector<uint8>& input) {
+ base::EnsureNSSInit();
+
+ scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
+
+ // First, decode and save the public key.
+ SECItem key_der;
+ key_der.type = siBuffer;
+ key_der.data = const_cast<unsigned char*>(&input[0]);
+ key_der.len = input.size();
+
+ CERTSubjectPublicKeyInfo *spki =
+ SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
+ if (!spki) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ result->public_key_ = SECKEY_ExtractPublicKey(spki);
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ if (!result->public_key_) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ // Now, look for the associated private key in the user's NSS DB. If it's
+ // not there, consider that an error.
+ PK11SlotInfo *slot = GetDefaultNSSKeySlot();
+ if (!slot) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ // Make sure the key is an RSA key. If not, that's an error
+ if (result->public_key_->keyType != rsaKey) {
+ PK11_FreeSlot(slot);
+ NOTREACHED();
+ return NULL;
+ }
+
+ SECItem *ck_id = PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus));
+ if (!ck_id) {
+ PK11_FreeSlot(slot);
+ NOTREACHED();
+ return NULL;
+ }
+
+ // Finally...Look for the key!
+ result->key_ = PK11_FindKeyByKeyID(slot, ck_id, NULL);
+
+ // Cleanup...
+ PK11_FreeSlot(slot);
+ SECITEM_FreeItem(ck_id, PR_TRUE);
+
+ // If we didn't find it, that's ok.
+ if (!result->key_)
+ return NULL;
+
+ return result.release();
+}
+
RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
EnsureNSSInit();
}
diff --git a/base/crypto/rsa_private_key_win.cc b/base/crypto/rsa_private_key_win.cc
index b02ef3c..5dd8cca 100644
--- a/base/crypto/rsa_private_key_win.cc
+++ b/base/crypto/rsa_private_key_win.cc
@@ -39,6 +39,12 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
}
// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
const std::vector<uint8>& input) {
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
@@ -103,6 +109,20 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
return result.release();
}
+// static
+RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
+ const std::vector<uint8>& input) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
+ const std::vector<uint8>& input) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
RSAPrivateKey::RSAPrivateKey() : provider_(NULL), key_(NULL) {}
RSAPrivateKey::~RSAPrivateKey() {}
diff --git a/base/crypto/scoped_capi_types.h b/base/crypto/scoped_capi_types.h
index bdb05c3..d6582a7 100644
--- a/base/crypto/scoped_capi_types.h
+++ b/base/crypto/scoped_capi_types.h
@@ -4,6 +4,7 @@
#ifndef BASE_CRYPTO_SCOPED_CAPI_TYPES_H_
#define BASE_CRYPTO_SCOPED_CAPI_TYPES_H_
+#pragma once
#include <windows.h>
#include <wincrypt.h>
diff --git a/base/crypto/scoped_nss_types.h b/base/crypto/scoped_nss_types.h
index c1c84c1..664251f 100644
--- a/base/crypto/scoped_nss_types.h
+++ b/base/crypto/scoped_nss_types.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_NSS_TYPES_H_
#define BASE_SCOPED_NSS_TYPES_H_
+#pragma once
#include <nss.h>
#include <pk11pub.h>
diff --git a/base/crypto/signature_creator.h b/base/crypto/signature_creator.h
index 0e11ec3..38e327b 100644
--- a/base/crypto/signature_creator.h
+++ b/base/crypto/signature_creator.h
@@ -4,6 +4,7 @@
#ifndef BASE_CRYPTO_SIGNATURE_CREATOR_H_
#define BASE_CRYPTO_SIGNATURE_CREATOR_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/crypto/signature_verifier.h b/base/crypto/signature_verifier.h
index 1ef08cf..4746edc 100644
--- a/base/crypto/signature_verifier.h
+++ b/base/crypto/signature_verifier.h
@@ -4,6 +4,7 @@
#ifndef BASE_CRYPTO_SIGNATURE_VERIFIER_H_
#define BASE_CRYPTO_SIGNATURE_VERIFIER_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/crypto/symmetric_key.h b/base/crypto/symmetric_key.h
index c1e6f97..d7259be 100644
--- a/base/crypto/symmetric_key.h
+++ b/base/crypto/symmetric_key.h
@@ -4,6 +4,7 @@
#ifndef BASE_CRYPTO_SYMMETRIC_KEY_H_
#define BASE_CRYPTO_SYMMETRIC_KEY_H_
+#pragma once
#include <string>
@@ -44,14 +45,11 @@ class SymmetricKey {
size_t iterations,
size_t key_size_in_bits);
-#if defined(USE_NSS) || defined(OS_WIN)
- // TODO(albertb): Port this method to mac.
// Imports a raw key. For this call to be successful, |raw_key| must have been
// generated by either GenerateRandomKey or DeriveKeyFromPassword, and
// must have been exported with GetRawKey. The caller owns the returned
// SymmetricKey.
static SymmetricKey* Import(Algorithm algorithm, const std::string& raw_key);
-#endif
#if defined(USE_NSS)
PK11SymKey* key() const { return key_.get(); }
diff --git a/base/crypto/symmetric_key_mac.cc b/base/crypto/symmetric_key_mac.cc
index 19c330d..574f9d2 100644
--- a/base/crypto/symmetric_key_mac.cc
+++ b/base/crypto/symmetric_key_mac.cc
@@ -10,7 +10,6 @@
#include "base/crypto/cssm_init.h"
#include "base/logging.h"
-#include "base/rand_util.h"
namespace {
@@ -134,6 +133,12 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
return derived_key;
}
+// static
+SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
+ const std::string& raw_key) {
+ return new SymmetricKey(raw_key.data(), raw_key.size() * 8);
+}
+
SymmetricKey::SymmetricKey(const void *key_data, size_t key_size_in_bits)
: key_(reinterpret_cast<const char*>(key_data),
key_size_in_bits / 8) {}
diff --git a/base/crypto/symmetric_key_unittest.cc b/base/crypto/symmetric_key_unittest.cc
index 341e45b..023179d 100644
--- a/base/crypto/symmetric_key_unittest.cc
+++ b/base/crypto/symmetric_key_unittest.cc
@@ -29,8 +29,6 @@ TEST(SymmetricKeyTest, GenerateRandomKey) {
EXPECT_NE(raw_key, raw_key2);
}
-// TODO(albertb): Port this test to Mac.
-#if defined(USE_NSS) || defined(OS_WIN)
TEST(SymmetricKeyTest, ImportGeneratedKey) {
scoped_ptr<base::SymmetricKey> key1(
base::SymmetricKey::GenerateRandomKey(base::SymmetricKey::AES, 256));
@@ -47,14 +45,12 @@ TEST(SymmetricKeyTest, ImportGeneratedKey) {
EXPECT_EQ(raw_key1, raw_key2);
}
-#endif // USE_NSS || OS_WIN
-// TODO(albertb): Port this test to Win and Mac.
-#if defined(USE_NSS)
TEST(SymmetricKeyTest, ImportDerivedKey) {
scoped_ptr<base::SymmetricKey> key1(
base::SymmetricKey::DeriveKeyFromPassword(base::SymmetricKey::HMAC_SHA1,
- "password", "salt", 1024, 160));
+ "password", "somesalt", 1024,
+ 160));
ASSERT_TRUE(NULL != key1.get());
std::string raw_key1;
EXPECT_TRUE(key1->GetRawKey(&raw_key1));
@@ -68,7 +64,6 @@ TEST(SymmetricKeyTest, ImportDerivedKey) {
EXPECT_EQ(raw_key1, raw_key2);
}
-#endif // USE_NSS
struct PBKDF2TestVector {
const char* password;
diff --git a/base/crypto/symmetric_key_win.cc b/base/crypto/symmetric_key_win.cc
index 7d2080c..76be8ad 100644
--- a/base/crypto/symmetric_key_win.cc
+++ b/base/crypto/symmetric_key_win.cc
@@ -455,19 +455,30 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
// static
SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
const std::string& raw_key) {
- // TODO(wtc): support HMAC.
- DCHECK_EQ(algorithm, AES);
+ DWORD provider_type = 0;
+ ALG_ID alg = 0;
+ switch (algorithm) {
+ case AES:
+ provider_type = PROV_RSA_AES;
+ alg = GetAESAlgIDForKeySize(raw_key.size() * 8);
+ break;
+ case HMAC_SHA1:
+ provider_type = PROV_RSA_FULL;
+ alg = CALG_HMAC;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ if (provider_type == 0 || alg == 0)
+ return NULL;
ScopedHCRYPTPROV provider;
BOOL ok = CryptAcquireContext(provider.receive(), NULL, NULL,
- PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
+ provider_type, CRYPT_VERIFYCONTEXT);
if (!ok)
return NULL;
- ALG_ID alg = GetAESAlgIDForKeySize(raw_key.size() * 8);
- if (alg == 0)
- return NULL;
-
ScopedHCRYPTKEY key;
if (!ImportRawKey(provider, alg, raw_key.data(), raw_key.size(), &key))
return NULL;
diff --git a/base/data/valgrind/base_unittests.gtest-drmemory_win32.txt b/base/data/valgrind/base_unittests.gtest-drmemory_win32.txt
index eaa0ced..1a9d52c 100644
--- a/base/data/valgrind/base_unittests.gtest-drmemory_win32.txt
+++ b/base/data/valgrind/base_unittests.gtest-drmemory_win32.txt
@@ -1,3 +1,7 @@
+# Dr. Memory crashes on some COM calls:
+# http://code.google.com/p/drmemory/issues/detail?id=21
+WMI*
+
# TODO(timurrrr) investigate the failures and enable these tests one-by-one.
RSA*
GmockTest.*
diff --git a/base/data/valgrind/base_unittests.gtest-tsan_win32.txt b/base/data/valgrind/base_unittests.gtest-tsan_win32.txt
index 4e237d5..0207c09 100644
--- a/base/data/valgrind/base_unittests.gtest-tsan_win32.txt
+++ b/base/data/valgrind/base_unittests.gtest-tsan_win32.txt
@@ -1,3 +1,6 @@
+# Occasionally fails under TSan, see http://crbug.com/54229
+ProcessUtilTest.CalcFreeMemory
+
# This file is copied from Valgrind-on-Wine filter
# TODO(timurrrr): include/investigate the listed tests one-by-one
EtwTraceControllerTest.EnableDisable
diff --git a/base/data/valgrind/base_unittests.gtest.txt b/base/data/valgrind/base_unittests.gtest.txt
index 8f7a32f..173defa 100644
--- a/base/data/valgrind/base_unittests.gtest.txt
+++ b/base/data/valgrind/base_unittests.gtest.txt
@@ -16,4 +16,7 @@ ClipboardTest.*
# These tests trigger a CHECK so they will leak memory. They don't test
# anything else, so just disable them on valgrind. Bug 28179.
-OutOfMemoryTest.*
+OutOfMemoryDeathTest.*
+
+# Flaky under Valgrind, see http://crbug.com/55517
+PlatformFile.TouchGetInfoPlatformFile
diff --git a/base/data/valgrind/base_unittests.gtest_mac.txt b/base/data/valgrind/base_unittests.gtest_mac.txt
index d78c20d..46fbf47 100644
--- a/base/data/valgrind/base_unittests.gtest_mac.txt
+++ b/base/data/valgrind/base_unittests.gtest_mac.txt
@@ -4,3 +4,6 @@ ConditionVariableTest.LargeFastTaskTest
# Fails on Valgrind/Mac due to missing syscall wrapper
# for the symlink() syscall. See http://crbug.com/44001
FileUtilTest.NormalizeFilePathSymlinks
+
+# Fails on Valgrind/Mac, see http://crbug.com/53196
+CancellationFlagTest.SetOnDifferentThreadDeathTest
diff --git a/base/data_pack.cc b/base/data_pack.cc
index 06f2308..c130031 100644
--- a/base/data_pack.cc
+++ b/base/data_pack.cc
@@ -8,6 +8,7 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/ref_counted_memory.h"
#include "base/string_piece.h"
// For details of the file layout, see
diff --git a/base/data_pack.h b/base/data_pack.h
index f3f8481..2836715 100644
--- a/base/data_pack.h
+++ b/base/data_pack.h
@@ -8,17 +8,18 @@
#ifndef BASE_DATA_PACK_H_
#define BASE_DATA_PACK_H_
+#pragma once
#include <map>
#include "base/basictypes.h"
-#include "base/ref_counted_memory.h"
#include "base/scoped_ptr.h"
namespace file_util {
class MemoryMappedFile;
}
class FilePath;
+class RefCountedStaticMemory;
namespace base {
diff --git a/base/debug_on_start.h b/base/debug_on_start.h
index e31e7eb..1774415 100644
--- a/base/debug_on_start.h
+++ b/base/debug_on_start.h
@@ -8,6 +8,7 @@
#ifndef BASE_DEBUG_ON_START_H_
#define BASE_DEBUG_ON_START_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/debug_util.h b/base/debug_util.h
index 303b4df..a7dba3a 100644
--- a/base/debug_util.h
+++ b/base/debug_util.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.
@@ -8,9 +8,9 @@
#ifndef BASE_DEBUG_UTIL_H_
#define BASE_DEBUG_UTIL_H_
+#pragma once
#include <iosfwd>
-#include <vector>
#include "base/basictypes.h"
diff --git a/base/debug_util_posix.cc b/base/debug_util_posix.cc
index 0070008..b0cb6e5 100644
--- a/base/debug_util_posix.cc
+++ b/base/debug_util_posix.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.
@@ -13,6 +13,9 @@
#include <sys/types.h>
#include <unistd.h>
+#include <string>
+#include <vector>
+
#if defined(__GLIBCXX__)
#include <cxxabi.h>
#endif
@@ -22,7 +25,6 @@
#endif
#include <iostream>
-#include <string>
#include "base/basictypes.h"
#include "base/compat_execinfo.h"
@@ -31,7 +33,7 @@
#include "base/safe_strerror_posix.h"
#include "base/scoped_ptr.h"
#include "base/string_piece.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
#if defined(USE_SYMBOLIZE)
#include "base/third_party/symbolize/symbolize.h"
@@ -47,6 +49,7 @@ const char kMangledSymbolPrefix[] = "_Z";
const char kSymbolCharacters[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+#if !defined(USE_SYMBOLIZE)
// Demangles C++ symbols in the given text. Example:
//
// "sconsbuild/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
@@ -92,12 +95,15 @@ void DemangleSymbols(std::string* text) {
#endif // defined(__GLIBCXX__)
}
+#endif // !defined(USE_SYMBOLIZE)
// Gets the backtrace as a vector of strings. If possible, resolve symbol
// names and attach these. Otherwise just use raw addresses. Returns true
-// if any symbol name is resolved.
+// if any symbol name is resolved. Returns false on error and *may* fill
+// in |error_message| if an error message is available.
bool GetBacktraceStrings(void **trace, int size,
- std::vector<std::string>* trace_strings) {
+ std::vector<std::string>* trace_strings,
+ std::string* error_message) {
bool symbolized = false;
#if defined(USE_SYMBOLIZE)
@@ -109,10 +115,11 @@ bool GetBacktraceStrings(void **trace, int size,
symbol, sizeof(symbol))) {
// Don't call DemangleSymbols() here as the symbol is demangled by
// google::Symbolize().
- trace_strings->push_back(StringPrintf("%s [%p]", symbol, trace[i]));
+ trace_strings->push_back(
+ base::StringPrintf("%s [%p]", symbol, trace[i]));
symbolized = true;
} else {
- trace_strings->push_back(StringPrintf("%p", trace[i]));
+ trace_strings->push_back(base::StringPrintf("%p", trace[i]));
}
}
#else
@@ -127,8 +134,10 @@ bool GetBacktraceStrings(void **trace, int size,
}
symbolized = true;
} else {
+ if (error_message)
+ *error_message = safe_strerror(errno);
for (int i = 0; i < size; ++i) {
- trace_strings->push_back(StringPrintf("%p", trace[i]));
+ trace_strings->push_back(base::StringPrintf("%p", trace[i]));
}
}
*/
@@ -288,7 +297,7 @@ void StackTrace::PrintBacktrace() {
#endif
fflush(stderr);
std::vector<std::string> trace_strings;
- GetBacktraceStrings(trace_, count_, &trace_strings);
+ GetBacktraceStrings(trace_, count_, &trace_strings, NULL);
for (size_t i = 0; i < trace_strings.size(); ++i) {
std::cerr << "\t" << trace_strings[i] << "\n";
}
@@ -304,11 +313,14 @@ void StackTrace::OutputToStream(std::ostream* os) {
#endif // ANDROID
#endif
std::vector<std::string> trace_strings;
- if (GetBacktraceStrings(trace_, count_, &trace_strings)) {
+ std::string error_message;
+ if (GetBacktraceStrings(trace_, count_, &trace_strings, &error_message)) {
(*os) << "Backtrace:\n";
} else {
- (*os) << "Unable get symbols for backtrace (" << safe_strerror(errno)
- << "). Dumping raw addresses in trace:\n";
+ if (!error_message.empty())
+ error_message = " (" + error_message + ")";
+ (*os) << "Unable to get symbols for backtrace" << error_message << ". "
+ << "Dumping raw addresses in trace:\n";
}
for (size_t i = 0; i < trace_strings.size(); ++i) {
diff --git a/base/dir_reader_fallback.h b/base/dir_reader_fallback.h
index c8f02e6..398f51b 100644
--- a/base/dir_reader_fallback.h
+++ b/base/dir_reader_fallback.h
@@ -4,6 +4,7 @@
#ifndef BASE_DIR_READER_FALLBACK_H_
#define BASE_DIR_READER_FALLBACK_H_
+#pragma once
namespace base {
diff --git a/base/dir_reader_linux.h b/base/dir_reader_linux.h
index 7fd534f..2b83334 100644
--- a/base/dir_reader_linux.h
+++ b/base/dir_reader_linux.h
@@ -4,6 +4,7 @@
#ifndef BASE_DIR_READER_LINUX_H_
#define BASE_DIR_READER_LINUX_H_
+#pragma once
#include <errno.h>
#include <fcntl.h>
diff --git a/base/dir_reader_posix.h b/base/dir_reader_posix.h
index 7f069b6..f591ae0 100644
--- a/base/dir_reader_posix.h
+++ b/base/dir_reader_posix.h
@@ -4,6 +4,7 @@
#ifndef BASE_DIR_READER_POSIX_H_
#define BASE_DIR_READER_POSIX_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/eintr_wrapper.h b/base/eintr_wrapper.h
index d2aee11..191c2a7 100644
--- a/base/eintr_wrapper.h
+++ b/base/eintr_wrapper.h
@@ -9,6 +9,7 @@
#ifndef BASE_EINTR_WRAPPER_H_
#define BASE_EINTR_WRAPPER_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/env_var.h b/base/env_var.h
deleted file mode 100644
index c0a45ca..0000000
--- a/base/env_var.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 BASE_ENV_VAR_H_
-#define BASE_ENV_VAR_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-
-namespace base {
-
-namespace env_vars {
-
-#if defined(OS_POSIX)
-extern const char kHome[];
-#endif
-
-} // namespace env_vars
-
-// These are used to derive mocks for unittests.
-class EnvVarGetter {
- public:
- virtual ~EnvVarGetter();
-
- // Gets an environment variable's value and stores it in |result|.
- // Returns false if the key is unset.
- virtual bool GetEnv(const char* variable_name, std::string* result) = 0;
-
- // Syntactic sugar for GetEnv(variable_name, NULL);
- virtual bool HasEnv(const char* variable_name);
-
- // Returns true on success, otherwise returns false.
- virtual bool SetEnv(const char* variable_name,
- const std::string& new_value) = 0;
-
- // Create an instance of EnvVarGetter
- static EnvVarGetter* Create();
-};
-
-} // namespace base
-
-#endif // BASE_ENV_VAR_H_
diff --git a/base/env_var_unittest.cc b/base/env_var_unittest.cc
deleted file mode 100644
index d80d997..0000000
--- a/base/env_var_unittest.cc
+++ /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.
-
-#include "base/env_var.h"
-#include "base/scoped_ptr.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-typedef PlatformTest EnvVarTest;
-
-TEST_F(EnvVarTest, GetEnvVar) {
- // Every setup should have non-empty PATH...
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- std::string env_value;
- EXPECT_TRUE(env->GetEnv("PATH", &env_value));
- EXPECT_NE(env_value, "");
-}
-
-TEST_F(EnvVarTest, HasEnvVar) {
- // Every setup should have PATH...
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- EXPECT_TRUE(env->HasEnv("PATH"));
-}
-
-TEST_F(EnvVarTest, SetEnvVar) {
- const char kFooUpper[] = "FOO";
- const char kFooLower[] = "foo";
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- EXPECT_TRUE(env->SetEnv(kFooUpper, kFooLower));
-
- // Now verify that the environment has the new variable.
- EXPECT_TRUE(env->HasEnv(kFooUpper));
-
- std::string var_value;
- EXPECT_TRUE(env->GetEnv(kFooUpper, &var_value));
- EXPECT_EQ(var_value, kFooLower);
-}
diff --git a/base/env_var.cc b/base/environment.cc
index d0eaa0c..9ccc078 100644
--- a/base/env_var.cc
+++ b/base/environment.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/env_var.h"
+#include "base/environment.h"
#if defined(OS_POSIX)
#include <stdlib.h>
@@ -19,10 +19,10 @@
namespace {
-class EnvVarGetterImpl : public base::EnvVarGetter {
+class EnvironmentImpl : public base::Environment {
public:
- virtual bool GetEnv(const char* variable_name, std::string* result) {
- if (GetEnvImpl(variable_name, result))
+ virtual bool GetVar(const char* variable_name, std::string* result) {
+ if (GetVarImpl(variable_name, result))
return true;
// Some commonly used variable names are uppercase while others
@@ -37,15 +37,19 @@ class EnvVarGetterImpl : public base::EnvVarGetter {
alternate_case_var = StringToLowerASCII(std::string(variable_name));
else
return false;
- return GetEnvImpl(alternate_case_var.c_str(), result);
+ return GetVarImpl(alternate_case_var.c_str(), result);
}
- virtual bool SetEnv(const char* variable_name, const std::string& new_value) {
- return SetEnvImpl(variable_name, new_value);
+ virtual bool SetVar(const char* variable_name, const std::string& new_value) {
+ return SetVarImpl(variable_name, new_value);
+ }
+
+ virtual bool UnSetVar(const char* variable_name) {
+ return UnSetVarImpl(variable_name);
}
private:
- bool GetEnvImpl(const char* variable_name, std::string* result) {
+ bool GetVarImpl(const char* variable_name, std::string* result) {
#if defined(OS_POSIX)
const char* env_value = getenv(variable_name);
if (!env_value)
@@ -71,14 +75,24 @@ class EnvVarGetterImpl : public base::EnvVarGetter {
#endif
}
- bool SetEnvImpl(const char* variable_name, const std::string& new_value) {
+ bool SetVarImpl(const char* variable_name, const std::string& new_value) {
+#if defined(OS_POSIX)
+ // On success, zero is returned.
+ return !setenv(variable_name, new_value.c_str(), 1);
+#elif defined(OS_WIN)
+ // On success, a nonzero value is returned.
+ return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(),
+ UTF8ToWide(new_value).c_str());
+#endif
+ }
+
+ bool UnSetVarImpl(const char* variable_name) {
#if defined(OS_POSIX)
// On success, zero is returned.
- return setenv(variable_name, new_value.c_str(), 1) == 0;
+ return !unsetenv(variable_name);
#elif defined(OS_WIN)
- // On success, a nonzero is returned.
- return ::SetEnvironmentVariable(ASCIIToWide(variable_name).c_str(),
- ASCIIToWide(new_value).c_str()) != 0;
+ // On success, a nonzero value is returned.
+ return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL);
#endif
}
};
@@ -97,15 +111,15 @@ const char kHome[] = "HOME";
} // namespace env_vars
-EnvVarGetter::~EnvVarGetter() {}
+Environment::~Environment() {}
-bool EnvVarGetter::HasEnv(const char* variable_name) {
- return GetEnv(variable_name, NULL);
+// static
+Environment* Environment::Create() {
+ return new EnvironmentImpl();
}
-// static
-EnvVarGetter* EnvVarGetter::Create() {
- return new EnvVarGetterImpl();
+bool Environment::HasVar(const char* variable_name) {
+ return GetVar(variable_name, NULL);
}
} // namespace base
diff --git a/base/environment.h b/base/environment.h
new file mode 100644
index 0000000..4c0691b
--- /dev/null
+++ b/base/environment.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 BASE_ENVIRONMENT_H_
+#define BASE_ENVIRONMENT_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+namespace env_vars {
+
+#if defined(OS_POSIX)
+extern const char kHome[];
+#endif
+
+} // namespace env_vars
+
+class Environment {
+ public:
+ virtual ~Environment();
+
+ // Static factory method that returns the implementation that provide the
+ // appropriate platform-specific instance.
+ static Environment* Create();
+
+ // Gets an environment variable's value and stores it in |result|.
+ // Returns false if the key is unset.
+ virtual bool GetVar(const char* variable_name, std::string* result) = 0;
+
+ // Syntactic sugar for GetVar(variable_name, NULL);
+ virtual bool HasVar(const char* variable_name);
+
+ // Returns true on success, otherwise returns false.
+ virtual bool SetVar(const char* variable_name,
+ const std::string& new_value) = 0;
+
+ // Returns true on success, otherwise returns false.
+ virtual bool UnSetVar(const char* variable_name) = 0;
+};
+
+} // namespace base
+
+#endif // BASE_ENVIRONMENT_H_
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc
new file mode 100644
index 0000000..d1ce503
--- /dev/null
+++ b/base/environment_unittest.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 "base/environment.h"
+#include "base/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest EnvironmentTest;
+
+TEST_F(EnvironmentTest, GetVar) {
+ // Every setup should have non-empty PATH...
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ std::string env_value;
+ EXPECT_TRUE(env->GetVar("PATH", &env_value));
+ EXPECT_NE(env_value, "");
+}
+
+TEST_F(EnvironmentTest, GetVarReverse) {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ const char* kFooUpper = "FOO";
+ const char* kFooLower = "foo";
+
+ // Set a variable in UPPER case.
+ EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+ // And then try to get this variable passing the lower case.
+ std::string env_value;
+ EXPECT_TRUE(env->GetVar(kFooLower, &env_value));
+
+ EXPECT_STREQ(env_value.c_str(), kFooLower);
+
+ EXPECT_TRUE(env->UnSetVar(kFooUpper));
+
+ const char* kBar = "bar";
+ // Now do the opposite, set the variable in the lower case.
+ EXPECT_TRUE(env->SetVar(kFooLower, kBar));
+
+ // And then try to get this variable passing the UPPER case.
+ EXPECT_TRUE(env->GetVar(kFooUpper, &env_value));
+
+ EXPECT_STREQ(env_value.c_str(), kBar);
+
+ EXPECT_TRUE(env->UnSetVar(kFooLower));
+}
+
+TEST_F(EnvironmentTest, HasVar) {
+ // Every setup should have PATH...
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ EXPECT_TRUE(env->HasVar("PATH"));
+}
+
+TEST_F(EnvironmentTest, SetVar) {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+
+ const char* kFooUpper = "FOO";
+ const char* kFooLower = "foo";
+ EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+ // Now verify that the environment has the new variable.
+ EXPECT_TRUE(env->HasVar(kFooUpper));
+
+ std::string var_value;
+ EXPECT_TRUE(env->GetVar(kFooUpper, &var_value));
+ EXPECT_EQ(var_value, kFooLower);
+}
+
+TEST_F(EnvironmentTest, UnSetVar) {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+
+ const char* kFooUpper = "FOO";
+ const char* kFooLower = "foo";
+ // First set some environment variable.
+ EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+ // Now verify that the environment has the new variable.
+ EXPECT_TRUE(env->HasVar(kFooUpper));
+
+ // Finally verify that the environment variable was erased.
+ EXPECT_TRUE(env->UnSetVar(kFooUpper));
+
+ // And check that the variable has been unset.
+ EXPECT_FALSE(env->HasVar(kFooUpper));
+}
diff --git a/base/event_recorder.h b/base/event_recorder.h
index df99428..04fbaa1 100644
--- a/base/event_recorder.h
+++ b/base/event_recorder.h
@@ -4,10 +4,11 @@
#ifndef BASE_EVENT_RECORDER_H_
#define BASE_EVENT_RECORDER_H_
+#pragma once
-#include <string>
#if defined(OS_WIN)
#include <windows.h>
+#include <stdio.h>
#endif
#include "base/basictypes.h"
diff --git a/base/event_synthesis_gtk.cc b/base/event_synthesis_gtk.cc
deleted file mode 100644
index 2055909..0000000
--- a/base/event_synthesis_gtk.cc
+++ /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.
-
-#include "base/event_synthesis_gtk.h"
-
-#include "base/keyboard_code_conversion_gtk.h"
-
-namespace base {
-
-GdkEvent* SynthesizeKeyEvent(GdkWindow* window,
- bool press, guint gdk_key, guint state) {
- GdkEvent* event = gdk_event_new(press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
-
- event->key.type = press ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
- event->key.window = window;
- if (window)
- g_object_ref(window);
- event->key.send_event = false;
-
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- event->key.time = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
-
- event->key.state = state;
- event->key.keyval = gdk_key;
-
- GdkKeymapKey* keys;
- gint n_keys;
- if (event->key.keyval != 0 &&
- gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(),
- event->key.keyval, &keys, &n_keys)) {
- event->key.hardware_keycode = keys[0].keycode;
- event->key.group = keys[0].group;
- g_free(keys);
- }
-
- return event;
-}
-
-void SynthesizeKeyPressEvents(GdkWindow* window,
- base::KeyboardCode key,
- bool control, bool shift, bool alt,
- std::vector<GdkEvent*>* events) {
- if (control)
- events->push_back(
- SynthesizeKeyEvent(window, true, GDK_Control_L, 0));
-
- if (shift) {
- events->push_back(SynthesizeKeyEvent(window, true, GDK_Shift_L,
- control ? GDK_CONTROL_MASK : 0));
- }
-
- if (alt) {
- guint state = (control ? GDK_CONTROL_MASK : 0) |
- (shift ? GDK_SHIFT_MASK : 0);
- events->push_back(
- SynthesizeKeyEvent(window, true, GDK_Alt_L, state));
- }
-
- // TODO(estade): handle other state flags besides control, shift, alt?
- // For example caps lock.
- guint state = (control ? GDK_CONTROL_MASK : 0) |
- (shift ? GDK_SHIFT_MASK : 0) |
- (alt ? GDK_MOD1_MASK : 0);
-
- guint gdk_key = base::GdkKeyCodeForWindowsKeyCode(key, shift);
- events->push_back(SynthesizeKeyEvent(window, true, gdk_key, state));
- events->push_back(SynthesizeKeyEvent(window, false, gdk_key, state));
-
- if (alt) {
- guint state = (control ? GDK_CONTROL_MASK : 0) |
- (shift ? GDK_SHIFT_MASK : 0) | GDK_MOD1_MASK;
- events->push_back(
- SynthesizeKeyEvent(window, false, GDK_Alt_L, state));
- }
-
- if (shift) {
- events->push_back(
- SynthesizeKeyEvent(window, false, GDK_Shift_L,
- (control ? GDK_CONTROL_MASK : 0) | GDK_SHIFT_MASK));
- }
-
- if (control) {
- events->push_back(
- SynthesizeKeyEvent(window, false, GDK_Control_L, GDK_CONTROL_MASK));
- }
-}
-
-} // namespace base
diff --git a/base/event_synthesis_gtk.h b/base/event_synthesis_gtk.h
deleted file mode 100644
index 11a540c..0000000
--- a/base/event_synthesis_gtk.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.
-//
-// This file declares routines for creating fake GDK events (at the moment,
-// only keyboard events). This is useful for a variety of testing purposes.
-// NOTE: This should not be used outside of testing.
-
-#ifndef BASE_EVENT_SYNTHESIS_GTK_
-#define BASE_EVENT_SYNTHESIS_GTK_
-
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <vector>
-
-#include "base/keyboard_codes.h"
-
-namespace base {
-
-// Creates and returns a key event. Passes ownership to the caller.
-GdkEvent* SynthesizeKeyEvent(GdkWindow* event_window,
- bool press,
- guint gdk_key,
- guint state);
-
-// Creates the proper sequence of key events for a key press + release.
-// Ownership of the events in the vector is passed to the caller.
-void SynthesizeKeyPressEvents(
- GdkWindow* window,
- base::KeyboardCode key,
- bool control, bool shift, bool alt,
- std::vector<GdkEvent*>* events);
-
-} // namespace base
-
-#endif // BASE_EVENT_SYNTHESIS_GTK_
diff --git a/base/event_trace_consumer_win.h b/base/event_trace_consumer_win.h
index 03db96f..de53ab2 100644
--- a/base/event_trace_consumer_win.h
+++ b/base/event_trace_consumer_win.h
@@ -5,6 +5,7 @@
// Declaration of a Windows event trace consumer base class.
#ifndef BASE_EVENT_TRACE_CONSUMER_WIN_H_
#define BASE_EVENT_TRACE_CONSUMER_WIN_H_
+#pragma once
#include <windows.h>
#include <wmistr.h>
diff --git a/base/event_trace_controller_win.h b/base/event_trace_controller_win.h
index 5267c86..5f66b97 100644
--- a/base/event_trace_controller_win.h
+++ b/base/event_trace_controller_win.h
@@ -19,6 +19,7 @@
// as well as potentially from multiple binary trace files.
#ifndef BASE_EVENT_TRACE_CONTROLLER_WIN_H_
#define BASE_EVENT_TRACE_CONTROLLER_WIN_H_
+#pragma once
#include <windows.h>
#include <wmistr.h>
diff --git a/base/event_trace_provider_win.h b/base/event_trace_provider_win.h
index 9668740..b0526b1 100644
--- a/base/event_trace_provider_win.h
+++ b/base/event_trace_provider_win.h
@@ -6,6 +6,7 @@
// Windows Event Tracing for logging transport and control.
#ifndef BASE_EVENT_TRACE_PROVIDER_WIN_H_
#define BASE_EVENT_TRACE_PROVIDER_WIN_H_
+#pragma once
#include <windows.h>
#include <wmistr.h>
diff --git a/base/field_trial.cc b/base/field_trial.cc
index 137c8c3..3575001 100644
--- a/base/field_trial.cc
+++ b/base/field_trial.cc
@@ -1,12 +1,12 @@
-// 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.
-
#include "base/field_trial.h"
+
#include "base/logging.h"
#include "base/rand_util.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
using base::TimeTicks;
@@ -19,6 +19,8 @@ const int FieldTrial::kAllRemainingProbability = -2;
// static
const char FieldTrialList::kPersistentStringSeparator('/');
+static const char kHistogramFieldTrialSeparator('_');
+
//------------------------------------------------------------------------------
// FieldTrial methods and members.
@@ -47,7 +49,7 @@ int FieldTrial::AppendGroup(const std::string& name,
// This is the group that crossed the random line, so we do the assignment.
group_ = next_group_number_;
if (name.empty())
- StringAppendF(&group_name_, "_%d", group_);
+ base::StringAppendF(&group_name_, "%d", group_);
else
group_name_ = name;
}
@@ -58,6 +60,7 @@ int FieldTrial::AppendGroup(const std::string& name,
std::string FieldTrial::MakeName(const std::string& name_prefix,
const std::string& trial_name) {
std::string big_string(name_prefix);
+ big_string.append(1, kHistogramFieldTrialSeparator);
return big_string.append(FieldTrialList::FindFullName(trial_name));
}
@@ -135,6 +138,7 @@ void FieldTrialList::StatesToString(std::string* output) {
if (!global_)
return;
DCHECK(output->empty());
+ AutoLock auto_lock(global_->lock_);
for (RegistrationList::iterator it = global_->registered_.begin();
it != global_->registered_.end(); ++it) {
const std::string name = it->first;
diff --git a/base/field_trial.h b/base/field_trial.h
index 1248e83..b1f0a07 100644
--- a/base/field_trial.h
+++ b/base/field_trial.h
@@ -34,8 +34,8 @@
// // process teardown, courtesy of their automatic registration in
// // FieldTrialList.
// scoped_refptr<FieldTrial> trial = new FieldTrial("MemoryExperiment", 1000);
-// int group1 = trial->AppendGroup("_high_mem", 20); // 2% in _high_mem group.
-// int group2 = trial->AppendGroup("_low_mem", 20); // 2% in _low_mem group.
+// int group1 = trial->AppendGroup("high_mem", 20); // 2% in high_mem group.
+// int group2 = trial->AppendGroup("low_mem", 20); // 2% in low_mem group.
// // Take action depending of which group we randomly land in.
// if (trial->group() == group1)
// SetPruningAlgorithm(kType1); // Sample setting of browser state.
@@ -61,6 +61,7 @@
#ifndef BASE_FIELD_TRIAL_H_
#define BASE_FIELD_TRIAL_H_
+#pragma once
#include <map>
#include <string>
@@ -124,7 +125,7 @@ class FieldTrial : public base::RefCounted<FieldTrial> {
// This is empty of the trial is not in the experiment.
const std::string name_;
- // The maximu sum of all probabilities supplied, which corresponds to 100%.
+ // The maximum sum of all probabilities supplied, which corresponds to 100%.
// This is the scaling factor used to adjust supplied probabilities.
Probability divisor_;
diff --git a/base/field_trial_unittest.cc b/base/field_trial_unittest.cc
index 671376d..54523dd 100644
--- a/base/field_trial_unittest.cc
+++ b/base/field_trial_unittest.cc
@@ -6,7 +6,7 @@
#include "base/field_trial.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
class FieldTrialTest : public testing::Test {
@@ -26,9 +26,9 @@ TEST_F(FieldTrialTest, Registration) {
EXPECT_FALSE(FieldTrialList::Find(name2));
FieldTrial* trial1 = new FieldTrial(name1, 10);
- EXPECT_EQ(trial1->group(), FieldTrial::kNotParticipating);
- EXPECT_EQ(trial1->name(), name1);
- EXPECT_EQ(trial1->group_name(), "");
+ EXPECT_EQ(FieldTrial::kNotParticipating, trial1->group());
+ EXPECT_EQ(name1, trial1->name());
+ EXPECT_EQ("", trial1->group_name());
trial1->AppendGroup("", 7);
@@ -36,9 +36,9 @@ TEST_F(FieldTrialTest, Registration) {
EXPECT_FALSE(FieldTrialList::Find(name2));
FieldTrial* trial2 = new FieldTrial(name2, 10);
- EXPECT_EQ(trial2->group(), FieldTrial::kNotParticipating);
- EXPECT_EQ(trial2->name(), name2);
- EXPECT_EQ(trial2->group_name(), "");
+ EXPECT_EQ(FieldTrial::kNotParticipating, trial2->group());
+ EXPECT_EQ(name2, trial2->name());
+ EXPECT_EQ("", trial2->group_name());
trial2->AppendGroup("a first group", 7);
@@ -56,16 +56,16 @@ TEST_F(FieldTrialTest, AbsoluteProbabilities) {
always_false[0] = i;
FieldTrial* trial_true = new FieldTrial(always_true, 10);
- const std::string winner = "_TheWinner";
+ const std::string winner = "TheWinner";
int winner_group = trial_true->AppendGroup(winner, 10);
- EXPECT_EQ(trial_true->group(), winner_group);
- EXPECT_EQ(trial_true->group_name(), winner);
+ EXPECT_EQ(winner_group, trial_true->group());
+ EXPECT_EQ(winner, trial_true->group_name());
FieldTrial* trial_false = new FieldTrial(always_false, 10);
int loser_group = trial_false->AppendGroup("ALoser", 0);
- EXPECT_NE(trial_false->group(), loser_group);
+ EXPECT_NE(loser_group, trial_false->group());
}
}
@@ -76,7 +76,7 @@ TEST_F(FieldTrialTest, RemainingProbability) {
scoped_refptr<FieldTrial> trial;
int counter = 0;
do {
- std::string name = StringPrintf("trial%d", ++counter);
+ std::string name = base::StringPrintf("trial%d", ++counter);
trial = new FieldTrial(name, 10);
trial->AppendGroup(loser, 5); // 50% chance of not being chosen.
} while (trial->group() != FieldTrial::kNotParticipating);
@@ -123,15 +123,15 @@ TEST_F(FieldTrialTest, OneWinner) {
int might_win = trial->AppendGroup("", 1);
if (trial->group() == might_win) {
- EXPECT_EQ(winner_index, -2);
+ EXPECT_EQ(-2, winner_index);
winner_index = might_win;
- StringAppendF(&winner_name, "_%d", might_win);
+ StringAppendF(&winner_name, "%d", might_win);
EXPECT_EQ(winner_name, trial->group_name());
}
}
EXPECT_GE(winner_index, 0);
EXPECT_EQ(trial->group(), winner_index);
- EXPECT_EQ(winner_name, trial->group_name());
+ EXPECT_EQ(trial->group_name(), winner_name);
}
TEST_F(FieldTrialTest, Save) {
@@ -139,15 +139,15 @@ TEST_F(FieldTrialTest, Save) {
FieldTrial* trial = new FieldTrial("Some name", 10);
// There is no winner yet, so no textual group name is associated with trial.
- EXPECT_EQ(trial->group_name(), "");
+ EXPECT_EQ("", trial->group_name());
FieldTrialList::StatesToString(&save_string);
- EXPECT_EQ(save_string, "");
+ EXPECT_EQ("", save_string);
save_string.clear();
// Create a winning group.
trial->AppendGroup("Winner", 10);
FieldTrialList::StatesToString(&save_string);
- EXPECT_EQ(save_string, "Some name/Winner/");
+ EXPECT_EQ("Some name/Winner/", save_string);
save_string.clear();
// Create a second trial and winning group.
@@ -156,7 +156,7 @@ TEST_F(FieldTrialTest, Save) {
FieldTrialList::StatesToString(&save_string);
// We assume names are alphabetized... though this is not critical.
- EXPECT_EQ(save_string, "Some name/Winner/xxx/yyyy/");
+ EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string);
}
TEST_F(FieldTrialTest, Restore) {
@@ -167,13 +167,13 @@ TEST_F(FieldTrialTest, Restore) {
FieldTrial* trial = FieldTrialList::Find("Some_name");
ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
- EXPECT_EQ(trial->group_name(), "Winner");
- EXPECT_EQ(trial->name(), "Some_name");
+ EXPECT_EQ("Winner", trial->group_name());
+ EXPECT_EQ("Some_name", trial->name());
trial = FieldTrialList::Find("xxx");
ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
- EXPECT_EQ(trial->group_name(), "yyyy");
- EXPECT_EQ(trial->name(), "xxx");
+ EXPECT_EQ("yyyy", trial->group_name());
+ EXPECT_EQ("xxx", trial->name());
}
TEST_F(FieldTrialTest, BogusRestore) {
@@ -196,3 +196,10 @@ TEST_F(FieldTrialTest, DuplicateRestore) {
// But it is an error to try to change to a different winner.
EXPECT_FALSE(FieldTrialList::StringAugmentsState("Some name/Loser/"));
}
+
+TEST_F(FieldTrialTest, MakeName) {
+ FieldTrial* trial = new FieldTrial("Field Trial", 10);
+ trial->AppendGroup("Winner", 10);
+ EXPECT_EQ("Histogram_Winner",
+ FieldTrial::MakeName("Histogram", "Field Trial"));
+}
diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h
index abc0789..6f46ab4 100644
--- a/base/file_descriptor_posix.h
+++ b/base/file_descriptor_posix.h
@@ -4,6 +4,7 @@
#ifndef BASE_FILE_DESCRIPTOR_POSIX_H_
#define BASE_FILE_DESCRIPTOR_POSIX_H_
+#pragma once
namespace base {
diff --git a/base/file_descriptor_shuffle.h b/base/file_descriptor_shuffle.h
index e1c93cd..a5c08e4 100644
--- a/base/file_descriptor_shuffle.h
+++ b/base/file_descriptor_shuffle.h
@@ -4,6 +4,7 @@
#ifndef BASE_FILE_DESCRIPTOR_SHUFFLE_H_
#define BASE_FILE_DESCRIPTOR_SHUFFLE_H_
+#pragma once
// This code exists to perform the shuffling of file descriptors which is
// commonly needed when forking subprocesses. The naive approve is very simple,
diff --git a/base/file_path.cc b/base/file_path.cc
index 1787a69..e330e3c 100644
--- a/base/file_path.cc
+++ b/base/file_path.cc
@@ -4,7 +4,9 @@
#include "base/file_path.h"
-#if defined(OS_MACOSX)
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
#include <CoreServices/CoreServices.h>
#endif
@@ -16,14 +18,12 @@
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
#if defined(OS_MACOSX)
#include "base/scoped_cftyperef.h"
#include "base/third_party/icu/icu_utf.h"
#endif
-#if defined(OS_WIN)
-#include "base/win_util.h"
-#endif
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
@@ -36,16 +36,18 @@ const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
+typedef FilePath::StringType StringType;
namespace {
+const char* kCommonDoubleExtensions[] = { "gz", "z", "bz2" };
+
// If this FilePath contains a drive letter specification, returns the
// position of the last character of the drive letter specification,
// otherwise returns npos. This can only be true on Windows, when a pathname
// begins with a letter followed by a colon. On other platforms, this always
// returns npos.
-FilePath::StringType::size_type FindDriveLetter(
- const FilePath::StringType& path) {
+StringType::size_type FindDriveLetter(const StringType& path) {
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
// This is dependent on an ASCII-based character set, but that's a
// reasonable assumption. iswalpha can be too inclusive here.
@@ -55,35 +57,33 @@ FilePath::StringType::size_type FindDriveLetter(
return 1;
}
#endif // FILE_PATH_USES_DRIVE_LETTERS
- return FilePath::StringType::npos;
+ return StringType::npos;
}
-
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
-bool EqualDriveLetterCaseInsensitive(const FilePath::StringType a,
- const FilePath::StringType b) {
+bool EqualDriveLetterCaseInsensitive(const StringType a,
+ const StringType b) {
size_t a_letter_pos = FindDriveLetter(a);
size_t b_letter_pos = FindDriveLetter(b);
- if ((a_letter_pos == FilePath::StringType::npos) ||
- (b_letter_pos == FilePath::StringType::npos))
+ if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
return a == b;
- FilePath::StringType a_letter(a.substr(0, a_letter_pos + 1));
- FilePath::StringType b_letter(b.substr(0, b_letter_pos + 1));
+ StringType a_letter(a.substr(0, a_letter_pos + 1));
+ StringType b_letter(b.substr(0, b_letter_pos + 1));
if (!StartsWith(a_letter, b_letter, false))
return false;
- FilePath::StringType a_rest(a.substr(a_letter_pos + 1));
- FilePath::StringType b_rest(b.substr(b_letter_pos + 1));
+ StringType a_rest(a.substr(a_letter_pos + 1));
+ StringType b_rest(b.substr(b_letter_pos + 1));
return a_rest == b_rest;
}
#endif // defined(FILE_PATH_USES_DRIVE_LETTERS)
-bool IsPathAbsolute(const FilePath::StringType& path) {
+bool IsPathAbsolute(const StringType& path) {
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
- FilePath::StringType::size_type letter = FindDriveLetter(path);
- if (letter != FilePath::StringType::npos) {
+ StringType::size_type letter = FindDriveLetter(path);
+ if (letter != StringType::npos) {
// Look for a separator right after the drive specification.
return path.length() > letter + 1 &&
FilePath::IsSeparator(path[letter + 1]);
@@ -97,8 +97,8 @@ bool IsPathAbsolute(const FilePath::StringType& path) {
#endif // FILE_PATH_USES_DRIVE_LETTERS
}
-bool AreAllSeparators(const FilePath::StringType& input) {
- for (FilePath::StringType::const_iterator it = input.begin();
+bool AreAllSeparators(const StringType& input) {
+ for (StringType::const_iterator it = input.begin();
it != input.end(); ++it) {
if (!FilePath::IsSeparator(*it))
return false;
@@ -107,6 +107,54 @@ bool AreAllSeparators(const FilePath::StringType& input) {
return true;
}
+// Find the position of the '.' that separates the extension from the rest
+// of the file name. The position is relative to BaseName(), not value().
+// This allows a second extension component of up to 4 characters when the
+// rightmost extension component is a common double extension (gz, bz2, Z).
+// For example, foo.tar.gz or foo.tar.Z would have extension components of
+// '.tar.gz' and '.tar.Z' respectively. Returns npos if it can't find an
+// extension.
+StringType::size_type ExtensionSeparatorPosition(const StringType& path) {
+ // Special case "." and ".."
+ if (path == FilePath::kCurrentDirectory || path == FilePath::kParentDirectory)
+ return StringType::npos;
+
+ const StringType::size_type last_dot =
+ path.rfind(FilePath::kExtensionSeparator);
+
+ // No extension, or the extension is the whole filename.
+ if (last_dot == StringType::npos || last_dot == 0U)
+ return last_dot;
+
+ // Special case .<extension1>.<extension2>, but only if the final extension
+ // is one of a few common double extensions.
+ StringType extension(path, last_dot + 1);
+ bool is_common_double_extension = false;
+ for (size_t i = 0; i < arraysize(kCommonDoubleExtensions); ++i) {
+ if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensions[i]))
+ is_common_double_extension = true;
+ }
+ if (!is_common_double_extension)
+ return last_dot;
+
+ // Check that <extension1> is 1-4 characters, otherwise fall back to
+ // <extension2>.
+ const StringType::size_type penultimate_dot =
+ path.rfind(FilePath::kExtensionSeparator, last_dot - 1);
+ const StringType::size_type last_separator =
+ path.find_last_of(FilePath::kSeparators, last_dot - 1,
+ arraysize(FilePath::kSeparators) - 1);
+ if (penultimate_dot != StringType::npos &&
+ (last_separator == StringType::npos ||
+ penultimate_dot > last_separator) &&
+ last_dot - penultimate_dot <= 5U &&
+ last_dot - penultimate_dot > 1U) {
+ return penultimate_dot;
+ }
+
+ return last_dot;
+}
+
} // namespace
FilePath::FilePath() {
@@ -136,8 +184,7 @@ bool FilePath::IsSeparator(CharType character) {
return false;
}
-void FilePath::GetComponents(std::vector<FilePath::StringType>* components)
- const {
+void FilePath::GetComponents(std::vector<StringType>* components) const {
DCHECK(components);
if (!components)
return;
@@ -145,7 +192,7 @@ void FilePath::GetComponents(std::vector<FilePath::StringType>* components)
if (value().empty())
return;
- std::vector<FilePath::StringType> ret_val;
+ std::vector<StringType> ret_val;
FilePath current = *this;
FilePath base;
@@ -165,12 +212,11 @@ void FilePath::GetComponents(std::vector<FilePath::StringType>* components)
// Capture drive letter, if any.
FilePath dir = current.DirName();
StringType::size_type letter = FindDriveLetter(dir.value());
- if (letter != FilePath::StringType::npos) {
- ret_val.push_back(FilePath::StringType(dir.value(), 0, letter + 1));
+ if (letter != StringType::npos) {
+ ret_val.push_back(StringType(dir.value(), 0, letter + 1));
}
- *components = std::vector<FilePath::StringType>(ret_val.rbegin(),
- ret_val.rend());
+ *components = std::vector<StringType>(ret_val.rbegin(), ret_val.rend());
}
bool FilePath::operator==(const FilePath& that) const {
@@ -195,8 +241,8 @@ bool FilePath::IsParent(const FilePath& child) const {
bool FilePath::AppendRelativePath(const FilePath& child,
FilePath* path) const {
- std::vector<FilePath::StringType> parent_components;
- std::vector<FilePath::StringType> child_components;
+ std::vector<StringType> parent_components;
+ std::vector<StringType> child_components;
GetComponents(&parent_components);
child.GetComponents(&child_components);
@@ -205,17 +251,17 @@ bool FilePath::AppendRelativePath(const FilePath& child,
if (parent_components.size() == 0)
return false;
- std::vector<FilePath::StringType>::const_iterator parent_comp =
+ std::vector<StringType>::const_iterator parent_comp =
parent_components.begin();
- std::vector<FilePath::StringType>::const_iterator child_comp =
+ std::vector<StringType>::const_iterator child_comp =
child_components.begin();
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
// Windows can access case sensitive filesystems, so component
// comparisions must be case sensitive, but drive letters are
// never case sensitive.
- if ((FindDriveLetter(*parent_comp) != FilePath::StringType::npos) &&
- (FindDriveLetter(*child_comp) != FilePath::StringType::npos)) {
+ if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
+ (FindDriveLetter(*child_comp) != StringType::npos)) {
if (!StartsWith(*parent_comp, *child_comp, false))
return false;
++parent_comp;
@@ -301,30 +347,24 @@ FilePath FilePath::BaseName() const {
return new_path;
}
-FilePath::StringType FilePath::Extension() const {
- // BaseName() calls StripTrailingSeparators, so cases like /foo.baz/// work.
- StringType base = BaseName().value();
-
- // Special case "." and ".."
- if (base == kCurrentDirectory || base == kParentDirectory)
+StringType FilePath::Extension() const {
+ FilePath base(BaseName());
+ const StringType::size_type dot = ExtensionSeparatorPosition(base.path_);
+ if (dot == StringType::npos)
return StringType();
- const StringType::size_type last_dot = base.rfind(kExtensionSeparator);
- if (last_dot == StringType::npos)
- return StringType();
- return StringType(base, last_dot);
+ return base.path_.substr(dot, StringType::npos);
}
FilePath FilePath::RemoveExtension() const {
- StringType ext = Extension();
- // It's important to check Extension() since that verifies that the
- // kExtensionSeparator actually appeared in the last path component.
- if (ext.empty())
- return FilePath(path_);
- // Since Extension() verified that the extension is in fact in the last path
- // component, this substr will effectively strip trailing separators.
- const StringType::size_type last_dot = path_.rfind(kExtensionSeparator);
- return FilePath(path_.substr(0, last_dot));
+ if (Extension().empty())
+ return *this;
+
+ const StringType::size_type dot = ExtensionSeparatorPosition(path_);
+ if (dot == StringType::npos)
+ return *this;
+
+ return FilePath(path_.substr(0, dot));
}
FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
@@ -355,7 +395,7 @@ FilePath FilePath::InsertBeforeExtensionASCII(const base::StringPiece& suffix)
const {
DCHECK(IsStringASCII(suffix));
#if defined(OS_WIN)
- return InsertBeforeExtension(ASCIIToWide(suffix));
+ return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string()));
#elif defined(OS_POSIX)
return InsertBeforeExtension(suffix.as_string());
#endif
@@ -390,7 +430,7 @@ FilePath FilePath::ReplaceExtension(const StringType& extension) const {
bool FilePath::MatchesExtension(const StringType& extension) const {
DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
- FilePath::StringType current_extension = Extension();
+ StringType current_extension = Extension();
if (current_extension.length() != extension.length())
return false;
@@ -439,7 +479,7 @@ FilePath FilePath::Append(const FilePath& component) const {
FilePath FilePath::AppendASCII(const base::StringPiece& component) const {
DCHECK(IsStringASCII(component));
#if defined(OS_WIN)
- return Append(ASCIIToWide(component));
+ return Append(ASCIIToUTF16(component.as_string()));
#elif defined(OS_POSIX)
return Append(component.as_string());
#endif
@@ -950,7 +990,7 @@ int FilePath::HFSFastUnicodeCompare(const StringType& string1,
}
}
-FilePath::StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
+StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
scoped_cftyperef<CFStringRef> cfstring(
CFStringCreateWithBytesNoCopy(
NULL,
@@ -1071,7 +1111,7 @@ FilePath FilePath::StripTrailingSeparators() const {
// static.
void FilePath::WriteStringTypeToPickle(Pickle* pickle,
- const FilePath::StringType& path) {
+ const StringType& path) {
#if defined(WCHAR_T_IS_UTF16)
pickle->WriteWString(path);
#elif defined(WCHAR_T_IS_UTF32)
@@ -1083,7 +1123,7 @@ void FilePath::WriteStringTypeToPickle(Pickle* pickle,
// static.
bool FilePath::ReadStringTypeFromPickle(Pickle* pickle, void** iter,
- FilePath::StringType* path) {
+ StringType* path) {
#if defined(WCHAR_T_IS_UTF16)
if (!pickle->ReadWString(iter, path))
return false;
@@ -1129,12 +1169,12 @@ void FilePath::StripTrailingSeparatorsInternal() {
}
bool FilePath::ReferencesParent() const {
- std::vector<FilePath::StringType> components;
+ std::vector<StringType> components;
GetComponents(&components);
- std::vector<FilePath::StringType>::const_iterator it = components.begin();
+ std::vector<StringType>::const_iterator it = components.begin();
for (; it != components.end(); ++it) {
- const FilePath::StringType& component = *it;
+ const StringType& component = *it;
if (component == kParentDirectory)
return true;
}
diff --git a/base/file_path.h b/base/file_path.h
index 6887cdc..01cd4a5 100644
--- a/base/file_path.h
+++ b/base/file_path.h
@@ -98,6 +98,7 @@
#ifndef BASE_FILE_PATH_H_
#define BASE_FILE_PATH_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/base/file_path_unittest.cc b/base/file_path_unittest.cc
index 828a642..6eb106b 100644
--- a/base/file_path_unittest.cc
+++ b/base/file_path_unittest.cc
@@ -1,11 +1,11 @@
-// 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 "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
-#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -307,7 +307,7 @@ TEST_F(FilePathTest, Append) {
// TODO(erikkay): It would be nice to have a unicode test append value to
// handle the case when AppendASCII is passed UTF8
#if defined(OS_WIN)
- std::string ascii = WideToASCII(leaf);
+ std::string ascii = WideToUTF8(leaf);
#elif defined(OS_POSIX)
std::string ascii = leaf;
#endif
@@ -698,16 +698,16 @@ TEST_F(FilePathTest, Extension) {
FilePath base_dir(FILE_PATH_LITERAL("base_dir"));
FilePath jpg = base_dir.Append(FILE_PATH_LITERAL("foo.jpg"));
- EXPECT_EQ(jpg.Extension(), FILE_PATH_LITERAL(".jpg"));
+ EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.Extension());
FilePath base = jpg.BaseName().RemoveExtension();
- EXPECT_EQ(base.value(), FILE_PATH_LITERAL("foo"));
+ EXPECT_EQ(FILE_PATH_LITERAL("foo"), base.value());
FilePath path_no_ext = base_dir.Append(base);
- EXPECT_EQ(jpg.RemoveExtension().value(), path_no_ext.value());
+ EXPECT_EQ(path_no_ext.value(), jpg.RemoveExtension().value());
EXPECT_EQ(path_no_ext.value(), path_no_ext.RemoveExtension().value());
- EXPECT_EQ(path_no_ext.Extension(), FILE_PATH_LITERAL(""));
+ EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.Extension());
}
TEST_F(FilePathTest, Extension2) {
@@ -730,6 +730,16 @@ TEST_F(FilePathTest, Extension2) {
{ FPL("/foo/bar/"), FPL("") },
{ FPL("/foo/bar./"), FPL(".") },
{ FPL("/foo/bar/baz.ext1.ext2"), FPL(".ext2") },
+ { FPL("/foo.tar.gz"), FPL(".tar.gz") },
+ { FPL("/foo.tar.Z"), FPL(".tar.Z") },
+ { FPL("/foo.tar.bz2"), FPL(".tar.bz2") },
+ { FPL("/subversion-1.6.12.zip"), FPL(".zip") },
+ { FPL("/foo.1234.gz"), FPL(".1234.gz") },
+ { FPL("/foo.12345.gz"), FPL(".gz") },
+ { FPL("/foo..gz"), FPL(".gz") },
+ { FPL("/foo.1234.tar.gz"), FPL(".tar.gz") },
+ { FPL("/foo.tar.tar.gz"), FPL(".tar.gz") },
+ { FPL("/foo.tar.gz.gz"), FPL(".gz.gz") },
{ FPL("."), FPL("") },
{ FPL(".."), FPL("") },
{ FPL("./foo"), FPL("") },
@@ -815,6 +825,34 @@ TEST_F(FilePathTest, InsertBeforeExtension) {
}
}
+TEST_F(FilePathTest, RemoveExtension) {
+ const struct UnaryTestData cases[] = {
+ { FPL(""), FPL("") },
+ { FPL("."), FPL(".") },
+ { FPL(".."), FPL("..") },
+ { FPL("foo.dll"), FPL("foo") },
+ { FPL("./foo.dll"), FPL("./foo") },
+ { FPL("foo..dll"), FPL("foo.") },
+ { FPL("foo"), FPL("foo") },
+ { FPL("foo."), FPL("foo") },
+ { FPL("foo.."), FPL("foo.") },
+ { FPL("foo.baz.dll"), FPL("foo.baz") },
+ { FPL("foo.tar.gz"), FPL("foo") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+ { FPL("C:\\foo.bar\\foo"), FPL("C:\\foo.bar\\foo") },
+ { FPL("C:\\foo.bar\\..\\\\"), FPL("C:\\foo.bar\\..\\\\") },
+#endif
+ { FPL("/foo.bar/foo"), FPL("/foo.bar/foo") },
+ { FPL("/foo.bar/..////"), FPL("/foo.bar/..////") },
+ };
+ for (unsigned int i = 0; i < arraysize(cases); ++i) {
+ FilePath path(cases[i].input);
+ FilePath removed = path.RemoveExtension();
+ EXPECT_EQ(cases[i].expected, removed.value()) << "i: " << i <<
+ ", path: " << path.value();
+ }
+}
+
TEST_F(FilePathTest, ReplaceExtension) {
const struct BinaryTestData cases[] = {
{ { FPL(""), FPL("") }, FPL("") },
@@ -823,6 +861,7 @@ TEST_F(FilePathTest, ReplaceExtension) {
{ { FPL(".."), FPL("txt") }, FPL("") },
{ { FPL("."), FPL("") }, FPL("") },
{ { FPL("foo.dll"), FPL("txt") }, FPL("foo.txt") },
+ { { FPL("./foo.dll"), FPL("txt") }, FPL("./foo.txt") },
{ { FPL("foo..dll"), FPL("txt") }, FPL("foo..txt") },
{ { FPL("foo.dll"), FPL(".txt") }, FPL("foo.txt") },
{ { FPL("foo"), FPL("txt") }, FPL("foo.txt") },
diff --git a/base/file_util.cc b/base/file_util.cc
index b611716..747232b 100644
--- a/base/file_util.cc
+++ b/base/file_util.cc
@@ -185,7 +185,7 @@ FILE* CreateAndOpenTemporaryFile(FilePath* path) {
}
bool GetFileSize(const FilePath& file_path, int64* file_size) {
- FileInfo info;
+ base::PlatformFileInfo info;
if (!GetFileInfo(file_path, &info))
return false;
*file_size = info.size;
@@ -200,6 +200,28 @@ bool IsDotDot(const FilePath& path) {
return FILE_PATH_LITERAL("..") == path.BaseName().value();
}
+bool TouchFile(const FilePath& path,
+ const base::Time& last_accessed,
+ const base::Time& last_modified) {
+ base::PlatformFile file =
+ base::CreatePlatformFile(path,
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_WRITE_ATTRIBUTES,
+ NULL, NULL);
+ if (file != base::kInvalidPlatformFileValue) {
+ bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
+ base::ClosePlatformFile(file);
+ return result;
+ }
+
+ return false;
+}
+
+bool SetLastModifiedTime(const FilePath& path,
+ const base::Time& last_modified) {
+ return TouchFile(path, last_modified, last_modified);
+}
+
bool CloseFile(FILE* file) {
if (file == NULL)
return true;
@@ -320,9 +342,9 @@ bool MemoryMappedFile::Initialize(const FilePath& file_name) {
}
bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
- file_ = base::CreatePlatformFile(file_name,
- base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
- NULL);
+ file_ = base::CreatePlatformFile(
+ file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+ NULL, NULL);
if (file_ == base::kInvalidPlatformFileValue) {
LOG(ERROR) << "Couldn't open " << file_name.value();
@@ -338,10 +360,6 @@ bool MemoryMappedFile::IsValid() {
// Deprecated functions ----------------------------------------------------
-bool ReadFileToString(const std::wstring& path, std::string* contents) {
- return ReadFileToString(FilePath::FromWStringHack(path), contents);
-}
-
bool AbsolutePath(std::wstring* path_str) {
FilePath path(FilePath::FromWStringHack(*path_str));
if (!AbsolutePath(&path))
@@ -394,14 +412,6 @@ FILE* OpenFile(const std::wstring& filename, const char* mode) {
int ReadFile(const std::wstring& filename, char* data, int size) {
return ReadFile(FilePath::FromWStringHack(filename), data, size);
}
-void UpOneDirectory(std::wstring* dir) {
- FilePath path = FilePath::FromWStringHack(*dir);
- FilePath directory = path.DirName();
- // If there is no separator, we will get back kCurrentDirectory.
- // In this case don't change |dir|.
- if (directory.value() != FilePath::kCurrentDirectory)
- *dir = directory.ToWStringHack();
-}
int WriteFile(const std::wstring& filename, const char* data, int size) {
return WriteFile(FilePath::FromWStringHack(filename), data, size);
}
diff --git a/base/file_util.h b/base/file_util.h
index 25d3783..cdc5175 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -7,6 +7,7 @@
#ifndef BASE_FILE_UTIL_H_
#define BASE_FILE_UTIL_H_
+#pragma once
#include "build/build_config.h"
@@ -34,7 +35,6 @@
#include "base/platform_file.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
-#include "base/time.h"
#if defined(OS_POSIX)
#include "base/eintr_wrapper.h"
@@ -238,6 +238,8 @@ bool CopyAndDeleteDirectory(const FilePath& from_path,
bool IsDirectoryEmpty(const FilePath& dir_path);
// Get the temporary directory provided by the system.
+// WARNING: DON'T USE THIS. If you want to create a temporary file, use one of
+// the functions below.
bool GetTempDir(FilePath* path);
// Get a temporary directory for shared memory files.
// Only useful on POSIX; redirects to GetTempDir() on Windows.
@@ -252,53 +254,37 @@ FilePath GetHomeDir();
// be empty and all handles closed after this function returns.
bool CreateTemporaryFile(FilePath* path);
+// Same as CreateTemporaryFile but the file is created in |dir|.
+bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file);
+
// Create and open a temporary file. File is opened for read/write.
// The full path is placed in |path|.
// Returns a handle to the opened file or NULL if an error occured.
FILE* CreateAndOpenTemporaryFile(FilePath* path);
// Like above but for shmem files. Only useful for POSIX.
FILE* CreateAndOpenTemporaryShmemFile(FilePath* path);
-
// Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|.
FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path);
-// Same as CreateTemporaryFile but the file is created in |dir|.
-bool CreateTemporaryFileInDir(const FilePath& dir,
- FilePath* temp_file);
+// Create a new directory. If prefix is provided, the new directory name is in
+// the format of prefixyyyy.
+// NOTE: prefix is ignored in the POSIX implementation.
+// If success, return true and output the full path of the directory created.
+bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+ FilePath* new_temp_path);
// Create a directory within another directory.
-// Extra characters will be appended to |name_tmpl| to ensure that the
+// Extra characters will be appended to |prefix| to ensure that the
// new directory does not have the same name as an existing directory.
-// If |loosen_permissions| is true, the new directory will be readable
-// and writable to all users on windows. It is ignored on other platforms.
-// |loosen_permissions| exists to allow debugging of crbug/35198, and will
-// be removed when the issue is understood.
bool CreateTemporaryDirInDir(const FilePath& base_dir,
const FilePath::StringType& prefix,
- bool loosen_permissions,
FilePath* new_dir);
-// Create a new directory under TempPath. If prefix is provided, the new
-// directory name is in the format of prefixyyyy.
-// NOTE: prefix is ignored in the POSIX implementation.
-// TODO(erikkay): is this OK?
-// If success, return true and output the full path of the directory created.
-bool CreateNewTempDirectory(const FilePath::StringType& prefix,
- FilePath* new_temp_path);
-
// Creates a directory, as well as creating any parent directories, if they
// don't exist. Returns 'true' on successful creation, or if the directory
// already exists. The directory is only readable by the current user.
bool CreateDirectory(const FilePath& full_path);
-#if defined(OS_WIN)
-// Added for debugging an issue where CreateDirectory() fails. LOG(*) does
-// not work, because the failure happens in a sandboxed process.
-// TODO(skerner): Remove once crbug/35198 is resolved.
-bool CreateDirectoryExtraLogging(const FilePath& full_path,
- std::ostream& error);
-#endif // defined (OS_WIN)
-
// Returns the file size. Returns true on success.
bool GetFileSize(const FilePath& file_path, int64* file_size);
@@ -316,25 +302,25 @@ bool IsDotDot(const FilePath& path);
// or if |real_path| would be longer than MAX_PATH characters.
bool NormalizeFilePath(const FilePath& path, FilePath* real_path);
-// Used to hold information about a given file path. See GetFileInfo below.
-struct FileInfo {
- // The size of the file in bytes. Undefined when is_directory is true.
- int64 size;
-
- // True if the file corresponds to a directory.
- bool is_directory;
-
- // The last modified time of a file.
- base::Time last_modified;
-
- // Add additional fields here as needed.
-};
+#if defined(OS_WIN)
+// Given an existing file in |path|, it returns in |real_path| the path
+// in the native NT format, of the form "\Device\HarddiskVolumeXX\..".
+// Returns false it it fails. Empty files cannot be resolved with this
+// function.
+bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path);
+#endif
// Returns information about the given file path.
-bool GetFileInfo(const FilePath& file_path, FileInfo* info);
+bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* info);
+
+// Sets the time of the last access and the time of the last modification.
+bool TouchFile(const FilePath& path,
+ const base::Time& last_accessed,
+ const base::Time& last_modified);
// Set the time of the last modification. Useful for unit tests.
-bool SetLastModifiedTime(const FilePath& file_path, base::Time last_modified);
+bool SetLastModifiedTime(const FilePath& path,
+ const base::Time& last_modified);
#if defined(OS_POSIX)
// Store inode number of |path| in |inode|. Return true on success.
@@ -613,9 +599,29 @@ inline bool MakeFileUnreadable(const FilePath& path) {
// is passed in. If it is 0 then the whole file is paged in. The step size
// which indicates the number of bytes to skip after every page touched is
// also passed in.
- bool PreReadImage(const wchar_t* file_path, size_t size_to_read,
- size_t step_size);
+bool PreReadImage(const wchar_t* file_path, size_t size_to_read,
+ size_t step_size);
#endif // OS_WIN
+
+#if defined(OS_LINUX)
+// Broad categories of file systems as returned by statfs() on Linux.
+enum FileSystemType {
+ FILE_SYSTEM_UNKNOWN, // statfs failed.
+ FILE_SYSTEM_0, // statfs.f_type == 0 means unknown, may indicate AFS.
+ FILE_SYSTEM_ORDINARY, // on-disk filesystem like ext2
+ FILE_SYSTEM_NFS,
+ FILE_SYSTEM_SMB,
+ FILE_SYSTEM_CODA,
+ FILE_SYSTEM_MEMORY, // in-memory file system
+ FILE_SYSTEM_OTHER, // any other value.
+ FILE_SYSTEM_TYPE_COUNT
+};
+
+// Attempts determine the FileSystemType for |path|.
+// Returns false if |path| doesn't exist.
+bool GetFileSystemType(const FilePath& path, FileSystemType* type);
+#endif
+
} // namespace file_util
// Deprecated functions have been moved to this separate header file,
diff --git a/base/file_util_deprecated.h b/base/file_util_deprecated.h
index efffe8f..45e60b7 100644
--- a/base/file_util_deprecated.h
+++ b/base/file_util_deprecated.h
@@ -12,6 +12,7 @@
#ifndef BASE_FILE_UTIL_DEPRECATED_H_
#define BASE_FILE_UTIL_DEPRECATED_H_
+#pragma once
#include "build/build_config.h"
@@ -26,9 +27,6 @@ namespace file_util {
FILE* OpenFile(const std::string& filename, const char* mode);
FILE* OpenFile(const std::wstring& filename, const char* mode);
-// Use FilePath::DirName instead.
-void UpOneDirectory(std::wstring* dir);
-
// Use FilePath::BaseName instead.
std::wstring GetFilenameFromPath(const std::wstring& path);
@@ -53,14 +51,10 @@ std::wstring GetFileExtensionFromPath(const std::wstring& path);
bool AbsolutePath(std::wstring* path);
-// Use FilePath::InsertBeforeExtension.
-void InsertBeforeExtension(FilePath* path, const FilePath::StringType& suffix);
-
// 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,
bool recursive);
-bool ReadFileToString(const std::wstring& path, std::string* contents);
int ReadFile(const std::wstring& filename, char* data, int size);
int WriteFile(const std::wstring& filename, const char* data, int size);
diff --git a/base/file_util_mac.mm b/base/file_util_mac.mm
index 7f81e8a..811799c 100644
--- a/base/file_util_mac.mm
+++ b/base/file_util_mac.mm
@@ -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,8 +7,8 @@
#import <Cocoa/Cocoa.h>
#include <copyfile.h>
+#include "base/basictypes.h"
#include "base/file_path.h"
-#include "base/logging.h"
#include "base/string_util.h"
namespace file_util {
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 08eed63..7315810 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -420,23 +420,17 @@ static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
// this should be OK since mkdtemp just replaces characters in place
char* buffer = const_cast<char*>(sub_dir_string.c_str());
char* dtemp = mkdtemp(buffer);
- if (!dtemp)
+ if (!dtemp) {
+ DPLOG(ERROR) << "mkdtemp";
return false;
+ }
*new_dir = FilePath(dtemp);
return true;
}
bool CreateTemporaryDirInDir(const FilePath& base_dir,
const FilePath::StringType& prefix,
- bool loosen_permissions,
FilePath* new_dir) {
- // To understand crbug/35198, the ability to call this
- // this function on windows while giving loose permissions
- // to the resulting directory has been temporarily added.
- // It should not be possible to call this function with
- // loosen_permissions == true on non-windows platforms.
- DCHECK(!loosen_permissions);
-
FilePath::StringType mkdtemp_template = prefix;
mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX"));
return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir);
@@ -480,23 +474,18 @@ bool CreateDirectory(const FilePath& full_path) {
return true;
}
-bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
+bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
stat_wrapper_t file_info;
if (CallStat(file_path.value().c_str(), &file_info) != 0)
return false;
results->is_directory = S_ISDIR(file_info.st_mode);
results->size = file_info.st_size;
results->last_modified = base::Time::FromTimeT(file_info.st_mtime);
+ results->last_accessed = base::Time::FromTimeT(file_info.st_atime);
+ results->creation_time = base::Time::FromTimeT(file_info.st_ctime);
return true;
}
-bool SetLastModifiedTime(const FilePath& file_path, base::Time last_modified) {
- struct timeval times[2];
- times[0] = last_modified.ToTimeVal();
- times[1] = last_modified.ToTimeVal();
- return (utimes(file_path.value().c_str(), times) == 0);
-}
-
bool GetInode(const FilePath& path, ino_t* inode) {
struct stat buffer;
int result = stat(path.value().c_str(), &buffer);
diff --git a/base/file_util_proxy.cc b/base/file_util_proxy.cc
new file mode 100644
index 0000000..7f7b03a
--- /dev/null
+++ b/base/file_util_proxy.cc
@@ -0,0 +1,799 @@
+// Copyright (c) 2010 The Chromium Authors. 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_proxy.h"
+
+#include "base/message_loop_proxy.h"
+
+// TODO(jianli): Move the code from anonymous namespace to base namespace so
+// that all of the base:: prefixes would be unnecessary.
+namespace {
+
+class MessageLoopRelay
+ : public base::RefCountedThreadSafe<MessageLoopRelay> {
+ public:
+ MessageLoopRelay()
+ : origin_message_loop_proxy_(
+ base::MessageLoopProxy::CreateForCurrentThread()),
+ error_code_(base::PLATFORM_FILE_OK) {
+ }
+
+ bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ const tracked_objects::Location& from_here) {
+ return message_loop_proxy->PostTask(
+ from_here,
+ NewRunnableMethod(this, &MessageLoopRelay::ProcessOnTargetThread));
+ }
+
+ protected:
+ friend class base::RefCountedThreadSafe<MessageLoopRelay>;
+ virtual ~MessageLoopRelay() {}
+
+ // Called to perform work on the FILE thread.
+ virtual void RunWork() = 0;
+
+ // Called to notify the callback on the origin thread.
+ virtual void RunCallback() = 0;
+
+ void set_error_code(base::PlatformFileError error_code) {
+ error_code_ = error_code;
+ }
+
+ base::PlatformFileError error_code() const {
+ return error_code_;
+ }
+
+ private:
+ void ProcessOnTargetThread() {
+ RunWork();
+ origin_message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &MessageLoopRelay::RunCallback));
+ }
+
+ scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
+ base::PlatformFileError error_code_;
+};
+
+class RelayCreateOrOpen : public MessageLoopRelay {
+ public:
+ RelayCreateOrOpen(
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ int file_flags,
+ base::FileUtilProxy::CreateOrOpenCallback* callback)
+ : message_loop_proxy_(message_loop_proxy),
+ file_path_(file_path),
+ file_flags_(file_flags),
+ callback_(callback),
+ file_handle_(base::kInvalidPlatformFileValue),
+ created_(false) {
+ DCHECK(callback);
+ }
+
+ protected:
+ virtual ~RelayCreateOrOpen() {
+ if (file_handle_ != base::kInvalidPlatformFileValue)
+ base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
+ }
+
+ virtual void RunWork() {
+ base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+ file_handle_ = base::CreatePlatformFile(file_path_, file_flags_,
+ &created_, &error_code);
+ set_error_code(error_code);
+ }
+
+ virtual void RunCallback() {
+ callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
+ created_);
+ delete callback_;
+ }
+
+ private:
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ FilePath file_path_;
+ int file_flags_;
+ base::FileUtilProxy::CreateOrOpenCallback* callback_;
+ base::PlatformFile file_handle_;
+ bool created_;
+};
+
+class RelayCreateTemporary : public MessageLoopRelay {
+ public:
+ RelayCreateTemporary(
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ base::FileUtilProxy::CreateTemporaryCallback* callback)
+ : message_loop_proxy_(message_loop_proxy),
+ callback_(callback),
+ file_handle_(base::kInvalidPlatformFileValue) {
+ DCHECK(callback);
+ }
+
+ protected:
+ virtual ~RelayCreateTemporary() {
+ if (file_handle_ != base::kInvalidPlatformFileValue)
+ base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
+ }
+
+ virtual void RunWork() {
+ // TODO(darin): file_util should have a variant of CreateTemporaryFile
+ // that returns a FilePath and a PlatformFile.
+ file_util::CreateTemporaryFile(&file_path_);
+
+ // Use a fixed set of flags that are appropriate for writing to a temporary
+ // file from the IO thread using a net::FileStream.
+ int file_flags =
+ base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_ASYNC |
+ base::PLATFORM_FILE_TEMPORARY;
+ base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+ file_handle_ = base::CreatePlatformFile(file_path_, file_flags,
+ NULL, &error_code);
+ set_error_code(error_code);
+ }
+
+ virtual void RunCallback() {
+ callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
+ file_path_);
+ delete callback_;
+ }
+
+ private:
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ base::FileUtilProxy::CreateTemporaryCallback* callback_;
+ base::PlatformFile file_handle_;
+ FilePath file_path_;
+};
+
+class RelayWithStatusCallback : public MessageLoopRelay {
+ public:
+ explicit RelayWithStatusCallback(
+ base::FileUtilProxy::StatusCallback* callback)
+ : callback_(callback) {
+ // It is OK for callback to be NULL.
+ }
+
+ protected:
+ virtual void RunCallback() {
+ // The caller may not have been interested in the result.
+ if (callback_) {
+ callback_->Run(error_code());
+ delete callback_;
+ }
+ }
+
+ private:
+ base::FileUtilProxy::StatusCallback* callback_;
+};
+
+class RelayClose : public RelayWithStatusCallback {
+ public:
+ RelayClose(base::PlatformFile file_handle,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_handle_(file_handle) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!base::ClosePlatformFile(file_handle_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ private:
+ base::PlatformFile file_handle_;
+};
+
+class RelayDelete : public RelayWithStatusCallback {
+ public:
+ RelayDelete(const FilePath& file_path,
+ bool recursive,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_path_(file_path),
+ recursive_(recursive) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!file_util::PathExists(file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ if (!file_util::Delete(file_path_, recursive_)) {
+ if (!recursive_ && !file_util::IsDirectoryEmpty(file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+ return;
+ }
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+ }
+
+ private:
+ FilePath file_path_;
+ bool recursive_;
+};
+
+class RelayCopy : public RelayWithStatusCallback {
+ public:
+ RelayCopy(const FilePath& src_file_path,
+ const FilePath& dest_file_path,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ src_file_path_(src_file_path),
+ dest_file_path_(dest_file_path) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ bool dest_path_exists = file_util::PathExists(dest_file_path_);
+ if (!dest_path_exists &&
+ !file_util::DirectoryExists(dest_file_path_.DirName())) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ // |src_file_path| exists and is a directory.
+ // |dest_file_path| exists and is a file.
+ if (file_util::DirectoryExists(src_file_path_) &&
+ dest_path_exists && !file_util::DirectoryExists(dest_file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY);
+ return;
+ }
+ if (file_util::ContainsPath(src_file_path_, dest_file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+ if (!file_util::CopyDirectory(src_file_path_, dest_file_path_,
+ true /* recursive */)) {
+ if (!file_util::PathExists(src_file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ if (src_file_path_.value() == dest_file_path_.value()) {
+ set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
+ return;
+ }
+ // Something else went wrong.
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+ }
+
+ private:
+ FilePath src_file_path_;
+ FilePath dest_file_path_;
+};
+
+class RelayMove : public RelayWithStatusCallback {
+ public:
+ RelayMove(const FilePath& src_file_path,
+ const FilePath& dest_file_path,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ src_file_path_(src_file_path),
+ dest_file_path_(dest_file_path) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ bool dest_path_exists = file_util::PathExists(dest_file_path_);
+ if (!dest_path_exists &&
+ !file_util::DirectoryExists(dest_file_path_.DirName())) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ // |src_file_path| exists and is a directory.
+ // |dest_file_path| exists and is a file.
+ if (file_util::DirectoryExists(src_file_path_) &&
+ dest_path_exists &&
+ !file_util::DirectoryExists(dest_file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
+ return;
+ }
+ if (file_util::ContainsPath(src_file_path_, dest_file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+ return;
+ }
+ if (!file_util::Move(src_file_path_, dest_file_path_)) {
+ if (!file_util::PathExists(src_file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ if (src_file_path_.value() == dest_file_path_.value()) {
+ set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
+ return;
+ }
+ // Something else went wrong.
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+ }
+
+ private:
+ FilePath src_file_path_;
+ FilePath dest_file_path_;
+};
+
+class RelayCreateDirectory : public RelayWithStatusCallback {
+ public:
+ RelayCreateDirectory(
+ const FilePath& file_path,
+ bool exclusive,
+ bool recursive,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_path_(file_path),
+ exclusive_(exclusive),
+ recursive_(recursive) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ bool path_exists = file_util::PathExists(file_path_);
+ // If parent dir of file doesn't exist.
+ if (!recursive_ && !file_util::PathExists(file_path_.DirName())) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ if (exclusive_ && path_exists) {
+ set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
+ return;
+ }
+ // If file exists at the path.
+ if (path_exists && !file_util::DirectoryExists(file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
+ return;
+ }
+ if (!file_util::CreateDirectory(file_path_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ private:
+ FilePath file_path_;
+ bool exclusive_;
+ bool recursive_;
+};
+
+class RelayReadDirectory : public MessageLoopRelay {
+ public:
+ RelayReadDirectory(const FilePath& file_path,
+ base::FileUtilProxy::ReadDirectoryCallback* callback)
+ : callback_(callback), file_path_(file_path) {
+ DCHECK(callback);
+ }
+
+ protected:
+ virtual void RunWork() {
+ // TODO(kkanetkar): Implement directory read in multiple chunks.
+ if (!file_util::DirectoryExists(file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+
+ file_util::FileEnumerator file_enum(
+ file_path_, false, static_cast<file_util::FileEnumerator::FILE_TYPE>(
+ file_util::FileEnumerator::FILES |
+ file_util::FileEnumerator::DIRECTORIES));
+ FilePath current;
+ while (!(current = file_enum.Next()).empty()) {
+ base::file_util_proxy::Entry entry;
+ file_util::FileEnumerator::FindInfo info;
+ file_enum.GetFindInfo(&info);
+ entry.is_directory = file_enum.IsDirectory(info);
+ // This will just give the entry's name instead of entire path
+ // if we use current.value().
+ entry.name = file_util::FileEnumerator::GetFilename(info).value();
+ entries_.push_back(entry);
+ }
+ }
+
+ virtual void RunCallback() {
+ callback_->Run(error_code(), entries_);
+ delete callback_;
+ }
+
+ private:
+ base::FileUtilProxy::ReadDirectoryCallback* callback_;
+ FilePath file_path_;
+ std::vector<base::file_util_proxy::Entry> entries_;
+};
+
+class RelayGetFileInfo : public MessageLoopRelay {
+ public:
+ RelayGetFileInfo(const FilePath& file_path,
+ base::FileUtilProxy::GetFileInfoCallback* callback)
+ : callback_(callback),
+ file_path_(file_path) {
+ DCHECK(callback);
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!file_util::PathExists(file_path_)) {
+ set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ if (!file_util::GetFileInfo(file_path_, &file_info_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ virtual void RunCallback() {
+ callback_->Run(error_code(), file_info_);
+ delete callback_;
+ }
+
+ private:
+ base::FileUtilProxy::GetFileInfoCallback* callback_;
+ FilePath file_path_;
+ base::PlatformFileInfo file_info_;
+};
+
+class RelayGetFileInfoFromPlatformFile : public MessageLoopRelay {
+ public:
+ RelayGetFileInfoFromPlatformFile(
+ base::PlatformFile file,
+ base::FileUtilProxy::GetFileInfoCallback* callback)
+ : callback_(callback),
+ file_(file) {
+ DCHECK(callback);
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!base::GetPlatformFileInfo(file_, &file_info_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ virtual void RunCallback() {
+ callback_->Run(error_code(), file_info_);
+ delete callback_;
+ }
+
+ private:
+ base::FileUtilProxy::GetFileInfoCallback* callback_;
+ base::PlatformFile file_;
+ base::PlatformFileInfo file_info_;
+};
+
+class RelayRead : public MessageLoopRelay {
+ public:
+ RelayRead(base::PlatformFile file,
+ int64 offset,
+ char* buffer,
+ int bytes_to_read,
+ base::FileUtilProxy::ReadWriteCallback* callback)
+ : file_(file),
+ offset_(offset),
+ buffer_(buffer),
+ bytes_to_read_(bytes_to_read),
+ callback_(callback),
+ bytes_read_(0) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_,
+ bytes_to_read_);
+ if (bytes_read_ < 0)
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ virtual void RunCallback() {
+ if (callback_) {
+ callback_->Run(error_code(), bytes_read_);
+ delete callback_;
+ }
+ }
+
+ private:
+ base::PlatformFile file_;
+ int64 offset_;
+ char* buffer_;
+ int bytes_to_read_;
+ base::FileUtilProxy::ReadWriteCallback* callback_;
+ int bytes_read_;
+};
+
+class RelayWrite : public MessageLoopRelay {
+ public:
+ RelayWrite(base::PlatformFile file,
+ long long offset,
+ const char* buffer,
+ int bytes_to_write,
+ base::FileUtilProxy::ReadWriteCallback* callback)
+ : file_(file),
+ offset_(offset),
+ buffer_(buffer),
+ bytes_to_write_(bytes_to_write),
+ callback_(callback) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_,
+ bytes_to_write_);
+ if (bytes_written_ < 0)
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ virtual void RunCallback() {
+ if (callback_) {
+ callback_->Run(error_code(), bytes_written_);
+ delete callback_;
+ }
+ }
+
+ private:
+ base::PlatformFile file_;
+ int64 offset_;
+ const char* buffer_;
+ int bytes_to_write_;
+ base::FileUtilProxy::ReadWriteCallback* callback_;
+ int bytes_written_;
+};
+
+class RelayTouch : public RelayWithStatusCallback {
+ public:
+ RelayTouch(base::PlatformFile file,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_(file),
+ last_access_time_(last_access_time),
+ last_modified_time_(last_modified_time) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!base::TouchPlatformFile(file_, last_access_time_, last_modified_time_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ private:
+ base::PlatformFile file_;
+ base::Time last_access_time_;
+ base::Time last_modified_time_;
+};
+
+class RelayTouchFilePath : public RelayWithStatusCallback {
+ public:
+ RelayTouchFilePath(const FilePath& file_path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_path_(file_path),
+ last_access_time_(last_access_time),
+ last_modified_time_(last_modified_time) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!file_util::TouchFile(
+ file_path_, last_access_time_, last_modified_time_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ private:
+ FilePath file_path_;
+ base::Time last_access_time_;
+ base::Time last_modified_time_;
+};
+
+class RelayTruncate : public RelayWithStatusCallback {
+ public:
+ RelayTruncate(base::PlatformFile file,
+ int64 length,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_(file),
+ length_(length) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!base::TruncatePlatformFile(file_, length_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ private:
+ base::PlatformFile file_;
+ int64 length_;
+};
+
+class RelayFlush : public RelayWithStatusCallback {
+ public:
+ RelayFlush(base::PlatformFile file,
+ base::FileUtilProxy::StatusCallback* callback)
+ : RelayWithStatusCallback(callback),
+ file_(file) {
+ }
+
+ protected:
+ virtual void RunWork() {
+ if (!base::FlushPlatformFile(file_))
+ set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
+ }
+
+ private:
+ base::PlatformFile file_;
+};
+
+bool Start(const tracked_objects::Location& from_here,
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ scoped_refptr<MessageLoopRelay> relay) {
+ return relay->Start(message_loop_proxy, from_here);
+}
+
+} // namespace
+
+namespace base {
+
+// static
+bool FileUtilProxy::CreateOrOpen(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path, int file_flags,
+ CreateOrOpenCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen(
+ message_loop_proxy, file_path, file_flags, callback));
+}
+
+// static
+bool FileUtilProxy::CreateTemporary(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ CreateTemporaryCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayCreateTemporary(message_loop_proxy, callback));
+}
+
+// static
+bool FileUtilProxy::CreateDirectory(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ bool exclusive,
+ bool recursive,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
+ file_path, exclusive, recursive, callback));
+}
+
+// static
+bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile file_handle,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayClose(file_handle, callback));
+}
+
+// static
+bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayDelete(file_path, false, callback));
+}
+
+// static
+bool FileUtilProxy::Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayCopy(src_file_path, dest_file_path, callback));
+}
+
+// static
+bool FileUtilProxy::Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayMove(src_file_path, dest_file_path, callback));
+}
+
+// static
+bool FileUtilProxy::ReadDirectory(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ ReadDirectoryCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(
+ file_path, callback));
+}
+
+// Retrieves the information about a file. It is invalid to pass NULL for the
+// callback.
+bool FileUtilProxy::GetFileInfo(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ GetFileInfoCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(
+ file_path, callback));
+}
+
+// static
+bool FileUtilProxy::RecursiveDelete(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayDelete(file_path, true, callback));
+}
+
+// static
+bool FileUtilProxy::GetFileInfoFromPlatformFile(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ PlatformFile file,
+ GetFileInfoCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayGetFileInfoFromPlatformFile(file, callback));
+}
+
+// static
+bool FileUtilProxy::Read(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ PlatformFile file,
+ int64 offset,
+ char* buffer,
+ int bytes_to_read,
+ ReadWriteCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayRead(file, offset, buffer, bytes_to_read, callback));
+}
+
+// static
+bool FileUtilProxy::Write(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ PlatformFile file,
+ int64 offset,
+ const char* buffer,
+ int bytes_to_write,
+ ReadWriteCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayWrite(file, offset, buffer, bytes_to_write, callback));
+}
+
+// static
+bool FileUtilProxy::Touch(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ PlatformFile file,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayTouch(file, last_access_time, last_modified_time,
+ callback));
+}
+
+// static
+bool FileUtilProxy::Touch(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayTouchFilePath(file_path, last_access_time,
+ last_modified_time, callback));
+}
+
+// static
+bool FileUtilProxy::Truncate(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ PlatformFile file,
+ long long length,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy,
+ new RelayTruncate(file, length, callback));
+}
+
+// static
+bool FileUtilProxy::Flush(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ PlatformFile file,
+ StatusCallback* callback) {
+ return Start(FROM_HERE, message_loop_proxy, new RelayFlush(file, callback));
+}
+
+} // namespace base
diff --git a/base/file_util_proxy.h b/base/file_util_proxy.h
new file mode 100644
index 0000000..081c11b
--- /dev/null
+++ b/base/file_util_proxy.h
@@ -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.
+
+#ifndef BASE_FILE_UTIL_PROXY_H_
+#define BASE_FILE_UTIL_PROXY_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/platform_file.h"
+#include "base/ref_counted.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace file_util_proxy {
+
+// Holds metadata for file or directory entry.
+struct Entry {
+ FilePath::StringType name;
+ bool is_directory;
+};
+
+} // namespace file_util_proxy
+
+class MessageLoopProxy;
+class Time;
+
+// This class provides asynchronous access to common file routines.
+class FileUtilProxy {
+ public:
+ // This callback is used by methods that report only an error code. It is
+ // valid to pass NULL as the callback parameter to any function that takes a
+ // StatusCallback, in which case the operation will complete silently.
+ typedef Callback1<base::PlatformFileError /* error code */
+ >::Type StatusCallback;
+
+ // Creates or opens a file with the given flags. It is invalid to pass NULL
+ // for the callback.
+ typedef Callback3<base::PlatformFileError /* error code */,
+ base::PassPlatformFile,
+ bool /* created */>::Type CreateOrOpenCallback;
+ static bool CreateOrOpen(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ int file_flags,
+ CreateOrOpenCallback* callback);
+
+ // Creates a temporary file for writing. The path and an open file handle
+ // are returned. It is invalid to pass NULL for the callback.
+ typedef Callback3<base::PlatformFileError /* error code */,
+ base::PassPlatformFile,
+ FilePath>::Type CreateTemporaryCallback;
+ static bool CreateTemporary(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ CreateTemporaryCallback* callback);
+
+ // Close the given file handle.
+ static bool Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile,
+ StatusCallback* callback);
+
+ // Retrieves the information about a file. It is invalid to pass NULL for the
+ // callback.
+ typedef Callback2<base::PlatformFileError /* error code */,
+ const base::PlatformFileInfo& /* file_info */
+ >::Type GetFileInfoCallback;
+ static bool GetFileInfo(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ GetFileInfoCallback* callback);
+
+ static bool GetFileInfoFromPlatformFile(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile file,
+ GetFileInfoCallback* callback);
+
+ typedef Callback2<base::PlatformFileError /* error code */,
+ const std::vector<base::file_util_proxy::Entry>&
+ >::Type ReadDirectoryCallback;
+ static bool ReadDirectory(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ ReadDirectoryCallback* callback);
+
+ // Copies a file or a directory from |src_file_path| to |dest_file_path|
+ // Error cases:
+ // If destination file doesn't exist or destination's parent
+ // doesn't exists.
+ // If source dir exists but destination path is an existing file.
+ // If source is a parent of destination.
+ // If source doesn't exists.
+ static bool Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path,
+ StatusCallback* callback);
+
+ // Creates directory at given path. It's an error to create
+ // if |exclusive| is true and dir already exists.
+ static bool CreateDirectory(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ bool exclusive,
+ bool recursive,
+ StatusCallback* callback);
+
+ // Deletes a file or empty directory.
+ static bool Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ StatusCallback* callback);
+
+ // Moves a file or a directory from src_file_path to dest_file_path.
+ // Error cases are similar to Copy method's error cases.
+ static bool Move(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& src_file_path,
+ const FilePath& dest_file_path,
+ StatusCallback* callback);
+
+ // Deletes a directory and all of its contents.
+ static bool RecursiveDelete(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ StatusCallback* callback);
+
+ // Reads from a file. On success, the file pointer is moved to position
+ // |offset + bytes_to_read| in the file. The callback can be NULL.
+ typedef Callback2<base::PlatformFileError /* error code */,
+ int /* bytes read/written */>::Type ReadWriteCallback;
+ static bool Read(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile file,
+ int64 offset,
+ char* buffer,
+ int bytes_to_read,
+ ReadWriteCallback* callback);
+
+ // Writes to a file. If |offset| is greater than the length of the file,
+ // |false| is returned. On success, the file pointer is moved to position
+ // |offset + bytes_to_write| in the file. If The callback can be NULL.
+ static bool Write(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile file,
+ int64 offset,
+ const char* buffer,
+ int bytes_to_write,
+ ReadWriteCallback* callback);
+
+ // Touches a file. The callback can be NULL.
+ static bool Touch(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile file,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ StatusCallback* callback);
+
+ // Touches a file. The callback can be NULL.
+ static bool Touch(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ const FilePath& file_path,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ StatusCallback* callback);
+
+ // Truncates a file to the given length. If |length| is greater than the
+ // current length of the file, the file will be extended with zeroes.
+ // The callback can be NULL.
+ static bool Truncate(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile file,
+ long long length,
+ StatusCallback* callback);
+
+ // Flushes a file. The callback can be NULL.
+ static bool Flush(
+ scoped_refptr<MessageLoopProxy> message_loop_proxy,
+ base::PlatformFile file,
+ StatusCallback* callback);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilProxy);
+};
+
+} // namespace base
+
+#endif // BASE_FILE_UTIL_PROXY_H_
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index 7860111..ca36b6a 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -18,10 +18,10 @@
#include "base/base_paths.h"
#include "base/file_path.h"
#include "base/file_util.h"
-#include "base/logging.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/scoped_handle.h"
+#include "base/scoped_temp_dir.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -120,23 +120,10 @@ class FileUtilTest : public PlatformTest {
protected:
virtual void SetUp() {
PlatformTest::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("FileUtilTest"));
-
- // Create a fresh, empty copy of this directory.
- file_util::Delete(test_dir_, true);
- file_util::CreateDirectory(test_dir_);
- }
- virtual void TearDown() {
- PlatformTest::TearDown();
- // Clean up test directory
- ASSERT_TRUE(file_util::Delete(test_dir_, true));
- ASSERT_FALSE(file_util::PathExists(test_dir_));
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
- // the path to temporary directory used to contain the test operations
- FilePath test_dir_;
+ ScopedTempDir temp_dir_;
};
// Collects all the results from the given file enumerator, and provides an
@@ -239,69 +226,6 @@ TEST_F(FileUtilTest, AppendToPath) {
}
#endif // defined(OS_WIN)
-
-static const struct InsertBeforeExtensionCase {
- const FilePath::CharType* path;
- const FilePath::CharType* suffix;
- const FilePath::CharType* result;
-} kInsertBeforeExtension[] = {
- {FPL(""), FPL(""), FPL("")},
- {FPL(""), FPL("txt"), FPL("txt")},
- {FPL("."), FPL("txt"), FPL("txt.")},
- {FPL("."), FPL(""), FPL(".")},
- {FPL("foo.dll"), FPL("txt"), FPL("footxt.dll")},
- {FPL("foo.dll"), FPL(".txt"), FPL("foo.txt.dll")},
- {FPL("foo"), FPL("txt"), FPL("footxt")},
- {FPL("foo"), FPL(".txt"), FPL("foo.txt")},
- {FPL("foo.baz.dll"), FPL("txt"), FPL("foo.baztxt.dll")},
- {FPL("foo.baz.dll"), FPL(".txt"), FPL("foo.baz.txt.dll")},
- {FPL("foo.dll"), FPL(""), FPL("foo.dll")},
- {FPL("foo.dll"), FPL("."), FPL("foo..dll")},
- {FPL("foo"), FPL(""), FPL("foo")},
- {FPL("foo"), FPL("."), FPL("foo.")},
- {FPL("foo.baz.dll"), FPL(""), FPL("foo.baz.dll")},
- {FPL("foo.baz.dll"), FPL("."), FPL("foo.baz..dll")},
-#if defined(OS_WIN)
- {FPL("\\"), FPL(""), FPL("\\")},
- {FPL("\\"), FPL("txt"), FPL("\\txt")},
- {FPL("\\."), FPL("txt"), FPL("\\txt.")},
- {FPL("\\."), FPL(""), FPL("\\.")},
- {FPL("C:\\bar\\foo.dll"), FPL("txt"), FPL("C:\\bar\\footxt.dll")},
- {FPL("C:\\bar.baz\\foodll"), FPL("txt"), FPL("C:\\bar.baz\\foodlltxt")},
- {FPL("C:\\bar.baz\\foo.dll"), FPL("txt"), FPL("C:\\bar.baz\\footxt.dll")},
- {FPL("C:\\bar.baz\\foo.dll.exe"), FPL("txt"),
- FPL("C:\\bar.baz\\foo.dlltxt.exe")},
- {FPL("C:\\bar.baz\\foo"), FPL(""), FPL("C:\\bar.baz\\foo")},
- {FPL("C:\\bar.baz\\foo.exe"), FPL(""), FPL("C:\\bar.baz\\foo.exe")},
- {FPL("C:\\bar.baz\\foo.dll.exe"), FPL(""), FPL("C:\\bar.baz\\foo.dll.exe")},
- {FPL("C:\\bar\\baz\\foo.exe"), FPL(" (1)"), FPL("C:\\bar\\baz\\foo (1).exe")},
-#elif defined(OS_POSIX)
- {FPL("/"), FPL(""), FPL("/")},
- {FPL("/"), FPL("txt"), FPL("/txt")},
- {FPL("/."), FPL("txt"), FPL("/txt.")},
- {FPL("/."), FPL(""), FPL("/.")},
- {FPL("/bar/foo.dll"), FPL("txt"), FPL("/bar/footxt.dll")},
- {FPL("/bar.baz/foodll"), FPL("txt"), FPL("/bar.baz/foodlltxt")},
- {FPL("/bar.baz/foo.dll"), FPL("txt"), FPL("/bar.baz/footxt.dll")},
- {FPL("/bar.baz/foo.dll.exe"), FPL("txt"), FPL("/bar.baz/foo.dlltxt.exe")},
- {FPL("/bar.baz/foo"), FPL(""), FPL("/bar.baz/foo")},
- {FPL("/bar.baz/foo.exe"), FPL(""), FPL("/bar.baz/foo.exe")},
- {FPL("/bar.baz/foo.dll.exe"), FPL(""), FPL("/bar.baz/foo.dll.exe")},
- {FPL("/bar/baz/foo.exe"), FPL(" (1)"), FPL("/bar/baz/foo (1).exe")},
-#endif
-};
-
-#if defined(OS_WIN)
-// This function has been deprecated on non-Windows.
-TEST_F(FileUtilTest, InsertBeforeExtensionTest) {
- for (unsigned int i = 0; i < arraysize(kInsertBeforeExtension); ++i) {
- FilePath path(kInsertBeforeExtension[i].path);
- file_util::InsertBeforeExtension(&path, kInsertBeforeExtension[i].suffix);
- EXPECT_EQ(kInsertBeforeExtension[i].result, path.value());
- }
-}
-#endif
-
static const struct filename_case {
const wchar_t* path;
const wchar_t* filename;
@@ -417,7 +341,8 @@ TEST_F(FileUtilTest, GetDirectoryFromPath) {
// Flaky, http://crbug.com/46246
TEST_F(FileUtilTest, FLAKY_CountFilesCreatedAfter) {
// Create old file (that we don't want to count)
- FilePath old_file_name = test_dir_.Append(FILE_PATH_LITERAL("Old File.txt"));
+ FilePath old_file_name =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Old File.txt"));
CreateTextFile(old_file_name, L"Just call me Mr. Creakybits");
// Age to perfection
@@ -431,30 +356,31 @@ TEST_F(FileUtilTest, FLAKY_CountFilesCreatedAfter) {
// Establish our cutoff time
base::Time now(base::Time::NowFromSystemTime());
- EXPECT_EQ(0, file_util::CountFilesCreatedAfter(test_dir_, now));
+ EXPECT_EQ(0, file_util::CountFilesCreatedAfter(temp_dir_.path(), now));
// Create a new file (that we do want to count)
- FilePath new_file_name = test_dir_.Append(FILE_PATH_LITERAL("New File.txt"));
+ FilePath new_file_name =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("New File.txt"));
CreateTextFile(new_file_name, L"Waaaaaaaaaaaaaah.");
// We should see only the new file.
- EXPECT_EQ(1, file_util::CountFilesCreatedAfter(test_dir_, now));
+ EXPECT_EQ(1, file_util::CountFilesCreatedAfter(temp_dir_.path(), now));
// Delete new file, we should see no files after cutoff now
EXPECT_TRUE(file_util::Delete(new_file_name, false));
- EXPECT_EQ(0, file_util::CountFilesCreatedAfter(test_dir_, now));
+ EXPECT_EQ(0, file_util::CountFilesCreatedAfter(temp_dir_.path(), now));
}
TEST_F(FileUtilTest, FileAndDirectorySize) {
// Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize
// should return 53 bytes.
- FilePath file_01 = test_dir_.Append(FPL("The file 01.txt"));
+ FilePath file_01 = temp_dir_.path().Append(FPL("The file 01.txt"));
CreateTextFile(file_01, L"12345678901234567890");
int64 size_f1 = 0;
ASSERT_TRUE(file_util::GetFileSize(file_01, &size_f1));
EXPECT_EQ(20ll, size_f1);
- FilePath subdir_path = test_dir_.Append(FPL("Level2"));
+ FilePath subdir_path = temp_dir_.path().Append(FPL("Level2"));
file_util::CreateDirectory(subdir_path);
FilePath file_02 = subdir_path.Append(FPL("The file 02.txt"));
@@ -469,21 +395,22 @@ TEST_F(FileUtilTest, FileAndDirectorySize) {
FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt"));
CreateTextFile(file_03, L"123");
- int64 computed_size = file_util::ComputeDirectorySize(test_dir_);
+ int64 computed_size = file_util::ComputeDirectorySize(temp_dir_.path());
EXPECT_EQ(size_f1 + size_f2 + 3, computed_size);
- computed_size = file_util::ComputeFilesSize(test_dir_, FPL("The file*"));
+ computed_size =
+ file_util::ComputeFilesSize(temp_dir_.path(), FPL("The file*"));
EXPECT_EQ(size_f1, computed_size);
- computed_size = file_util::ComputeFilesSize(test_dir_, FPL("bla*"));
+ computed_size = file_util::ComputeFilesSize(temp_dir_.path(), FPL("bla*"));
EXPECT_EQ(0, computed_size);
}
TEST_F(FileUtilTest, NormalizeFilePathBasic) {
// Create a directory under the test dir. Because we create it,
// we know it is not a link.
- FilePath file_a_path = test_dir_.Append(FPL("file_a"));
- FilePath dir_path = test_dir_.Append(FPL("dir"));
+ FilePath file_a_path = temp_dir_.path().Append(FPL("file_a"));
+ FilePath dir_path = temp_dir_.path().Append(FPL("dir"));
FilePath file_b_path = dir_path.Append(FPL("file_b"));
file_util::CreateDirectory(dir_path);
@@ -491,7 +418,7 @@ TEST_F(FileUtilTest, NormalizeFilePathBasic) {
ASSERT_FALSE(file_util::PathExists(file_a_path));
ASSERT_FALSE(file_util::NormalizeFilePath(file_a_path,
&normalized_file_a_path))
- << "NormalizeFilePath() should fail on nonexistant paths.";
+ << "NormalizeFilePath() should fail on nonexistent paths.";
CreateTextFile(file_a_path, bogus_content);
ASSERT_TRUE(file_util::PathExists(file_a_path));
@@ -515,7 +442,7 @@ TEST_F(FileUtilTest, NormalizeFilePathBasic) {
TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
// Build the following directory structure:
//
- // test_dir_
+ // temp_dir
// |-> base_a
// | |-> sub_a
// | |-> file.txt
@@ -523,11 +450,11 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
// | |-> sub_long
// | |-> deep.txt
// |-> base_b
- // |-> to_sub_a (reparse point to test_dir_\base_a\sub_a)
- // |-> to_base_b (reparse point to test_dir_\base_b)
- // |-> to_sub_long (reparse point to test_dir_\sub_a\long_name_\sub_long)
+ // |-> to_sub_a (reparse point to temp_dir\base_a\sub_a)
+ // |-> to_base_b (reparse point to temp_dir\base_b)
+ // |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long)
- FilePath base_a = test_dir_.Append(FPL("base_a"));
+ FilePath base_a = temp_dir_.path().Append(FPL("base_a"));
ASSERT_TRUE(file_util::CreateDirectory(base_a));
FilePath sub_a = base_a.Append(FPL("sub_a"));
@@ -562,7 +489,7 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
ASSERT_TRUE(file_util::CreateDirectory(sub_long));
CreateTextFile(deep_file, bogus_content);
- FilePath base_b = test_dir_.Append(FPL("base_b"));
+ FilePath base_b = temp_dir_.path().Append(FPL("base_b"));
ASSERT_TRUE(file_util::CreateDirectory(base_b));
FilePath to_sub_a = base_b.Append(FPL("to_sub_a"));
@@ -575,7 +502,7 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory.
NULL));
- ASSERT_NE(INVALID_HANDLE_VALUE, reparse_to_sub_a.Get());
+ ASSERT_TRUE(reparse_to_sub_a.IsValid());
ASSERT_TRUE(SetReparsePoint(reparse_to_sub_a, sub_a));
FilePath to_base_b = base_b.Append(FPL("to_base_b"));
@@ -588,7 +515,7 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory.
NULL));
- ASSERT_NE(INVALID_HANDLE_VALUE, reparse_to_base_b.Get());
+ ASSERT_TRUE(reparse_to_base_b.IsValid());
ASSERT_TRUE(SetReparsePoint(reparse_to_base_b, base_b));
FilePath to_sub_long = base_b.Append(FPL("to_sub_long"));
@@ -601,7 +528,7 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory.
NULL));
- ASSERT_NE(INVALID_HANDLE_VALUE, reparse_to_sub_long.Get());
+ ASSERT_TRUE(reparse_to_sub_long.IsValid());
ASSERT_TRUE(SetReparsePoint(reparse_to_sub_long, sub_long));
// Normalize a junction free path: base_a\sub_a\file.txt .
@@ -669,8 +596,8 @@ TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
FilePath normalized_path;
// Link one file to another.
- FilePath link_from = test_dir_.Append(FPL("from_file"));
- FilePath link_to = test_dir_.Append(FPL("to_file"));
+ FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+ FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
CreateTextFile(link_to, bogus_content);
ASSERT_TRUE(MakeSymlink(link_to, link_from))
@@ -683,8 +610,8 @@ TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
ASSERT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
// Link to a directory.
- link_from = test_dir_.Append(FPL("from_dir"));
- link_to = test_dir_.Append(FPL("to_dir"));
+ link_from = temp_dir_.path().Append(FPL("from_dir"));
+ link_to = temp_dir_.path().Append(FPL("to_dir"));
file_util::CreateDirectory(link_to);
ASSERT_TRUE(MakeSymlink(link_to, link_from))
@@ -694,8 +621,8 @@ TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
<< "Links to directories should return false.";
// Test that a loop in the links causes NormalizeFilePath() to return false.
- link_from = test_dir_.Append(FPL("link_a"));
- link_to = test_dir_.Append(FPL("link_b"));
+ link_from = temp_dir_.path().Append(FPL("link_a"));
+ link_to = temp_dir_.path().Append(FPL("link_b"));
ASSERT_TRUE(MakeSymlink(link_to, link_from))
<< "Failed to create loop symlink a.";
ASSERT_TRUE(MakeSymlink(link_from, link_to))
@@ -707,7 +634,7 @@ TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
#endif // defined(OS_POSIX)
TEST_F(FileUtilTest, DeleteNonExistent) {
- FilePath non_existent = test_dir_.AppendASCII("bogus_file_dne.foobar");
+ FilePath non_existent = temp_dir_.path().AppendASCII("bogus_file_dne.foobar");
ASSERT_FALSE(file_util::PathExists(non_existent));
EXPECT_TRUE(file_util::Delete(non_existent, false));
@@ -718,7 +645,7 @@ TEST_F(FileUtilTest, DeleteNonExistent) {
TEST_F(FileUtilTest, DeleteFile) {
// Create a file
- FilePath file_name = test_dir_.Append(FPL("Test DeleteFile 1.txt"));
+ FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 1.txt"));
CreateTextFile(file_name, bogus_content);
ASSERT_TRUE(file_util::PathExists(file_name));
@@ -727,7 +654,7 @@ TEST_F(FileUtilTest, DeleteFile) {
EXPECT_FALSE(file_util::PathExists(file_name));
// Test recursive case, create a new file
- file_name = test_dir_.Append(FPL("Test DeleteFile 2.txt"));
+ file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt"));
CreateTextFile(file_name, bogus_content);
ASSERT_TRUE(file_util::PathExists(file_name));
@@ -742,16 +669,16 @@ TEST_F(FileUtilTest, DeleteFile) {
// TODO(erikkay): see if anyone's actually using this feature of the API
TEST_F(FileUtilTest, DeleteWildCard) {
// Create a file and a directory
- FilePath file_name = test_dir_.Append(FPL("Test DeleteWildCard.txt"));
+ FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteWildCard.txt"));
CreateTextFile(file_name, bogus_content);
ASSERT_TRUE(file_util::PathExists(file_name));
- FilePath subdir_path = test_dir_.Append(FPL("DeleteWildCardDir"));
+ FilePath subdir_path = temp_dir_.path().Append(FPL("DeleteWildCardDir"));
file_util::CreateDirectory(subdir_path);
ASSERT_TRUE(file_util::PathExists(subdir_path));
// Create the wildcard path
- FilePath directory_contents = test_dir_;
+ FilePath directory_contents = temp_dir_.path();
directory_contents = directory_contents.Append(FPL("*"));
// Delete non-recursively and check that only the file is deleted
@@ -768,7 +695,8 @@ TEST_F(FileUtilTest, DeleteWildCard) {
// TODO(erikkay): see if anyone's actually using this feature of the API
TEST_F(FileUtilTest, DeleteNonExistantWildCard) {
// Create a file and a directory
- FilePath subdir_path = test_dir_.Append(FPL("DeleteNonExistantWildCard"));
+ FilePath subdir_path =
+ temp_dir_.path().Append(FPL("DeleteNonExistantWildCard"));
file_util::CreateDirectory(subdir_path);
ASSERT_TRUE(file_util::PathExists(subdir_path));
@@ -789,7 +717,7 @@ TEST_F(FileUtilTest, DeleteNonExistantWildCard) {
// Tests non-recursive Delete() for a directory.
TEST_F(FileUtilTest, DeleteDirNonRecursive) {
// Create a subdirectory and put a file and two directories inside.
- FilePath test_subdir = test_dir_.Append(FPL("DeleteDirNonRecursive"));
+ FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirNonRecursive"));
file_util::CreateDirectory(test_subdir);
ASSERT_TRUE(file_util::PathExists(test_subdir));
@@ -819,7 +747,7 @@ TEST_F(FileUtilTest, DeleteDirNonRecursive) {
// Tests recursive Delete() for a directory.
TEST_F(FileUtilTest, DeleteDirRecursive) {
// Create a subdirectory and put a file and two directories inside.
- FilePath test_subdir = test_dir_.Append(FPL("DeleteDirRecursive"));
+ FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirRecursive"));
file_util::CreateDirectory(test_subdir);
ASSERT_TRUE(file_util::PathExists(test_subdir));
@@ -849,13 +777,13 @@ TEST_F(FileUtilTest, DeleteDirRecursive) {
TEST_F(FileUtilTest, MoveFileNew) {
// Create a file
FilePath file_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
ASSERT_TRUE(file_util::PathExists(file_name_from));
- // The destination
- FilePath file_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+ // The destination.
+ FilePath file_name_to = temp_dir_.path().Append(
+ FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
ASSERT_FALSE(file_util::PathExists(file_name_to));
EXPECT_TRUE(file_util::Move(file_name_from, file_name_to));
@@ -868,13 +796,13 @@ TEST_F(FileUtilTest, MoveFileNew) {
TEST_F(FileUtilTest, MoveFileExists) {
// Create a file
FilePath file_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
ASSERT_TRUE(file_util::PathExists(file_name_from));
- // The destination name
- FilePath file_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+ // The destination name.
+ FilePath file_name_to = temp_dir_.path().Append(
+ FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
CreateTextFile(file_name_to, L"Old file content");
ASSERT_TRUE(file_util::PathExists(file_name_to));
@@ -889,13 +817,13 @@ TEST_F(FileUtilTest, MoveFileExists) {
TEST_F(FileUtilTest, MoveFileDirExists) {
// Create a file
FilePath file_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
ASSERT_TRUE(file_util::PathExists(file_name_from));
// The destination directory
FilePath dir_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Destination"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
file_util::CreateDirectory(dir_name_to);
ASSERT_TRUE(file_util::PathExists(dir_name_to));
@@ -906,7 +834,7 @@ TEST_F(FileUtilTest, MoveFileDirExists) {
TEST_F(FileUtilTest, MoveNew) {
// Create a directory
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -916,8 +844,9 @@ TEST_F(FileUtilTest, MoveNew) {
CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
ASSERT_TRUE(file_util::PathExists(file_name_from));
- // Move the directory
- FilePath dir_name_to = test_dir_.Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+ // Move the directory.
+ FilePath dir_name_to =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Move_To_Subdir"));
FilePath file_name_to =
dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
@@ -935,7 +864,7 @@ TEST_F(FileUtilTest, MoveNew) {
TEST_F(FileUtilTest, MoveExist) {
// Create a directory
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -947,7 +876,7 @@ TEST_F(FileUtilTest, MoveExist) {
// Move the directory
FilePath dir_name_exists =
- test_dir_.Append(FILE_PATH_LITERAL("Destination"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
FilePath dir_name_to =
dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir"));
@@ -970,7 +899,7 @@ TEST_F(FileUtilTest, MoveExist) {
TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
// Create a directory.
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -994,7 +923,7 @@ TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
// Copy the directory recursively.
FilePath dir_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
FilePath file_name_to =
dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
FilePath subdir_name_to =
@@ -1020,7 +949,7 @@ TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
// Create a directory.
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -1044,7 +973,7 @@ TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
// Copy the directory recursively.
FilePath dir_name_exists =
- test_dir_.Append(FILE_PATH_LITERAL("Destination"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
FilePath dir_name_to =
dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
@@ -1075,7 +1004,7 @@ TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
TEST_F(FileUtilTest, CopyDirectoryNew) {
// Create a directory.
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -1099,7 +1028,7 @@ TEST_F(FileUtilTest, CopyDirectoryNew) {
// Copy the directory not recursively.
FilePath dir_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
FilePath file_name_to =
dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
FilePath subdir_name_to =
@@ -1122,7 +1051,7 @@ TEST_F(FileUtilTest, CopyDirectoryNew) {
TEST_F(FileUtilTest, CopyDirectoryExists) {
// Create a directory.
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -1146,7 +1075,7 @@ TEST_F(FileUtilTest, CopyDirectoryExists) {
// Copy the directory not recursively.
FilePath dir_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
FilePath file_name_to =
dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
FilePath subdir_name_to =
@@ -1171,13 +1100,13 @@ TEST_F(FileUtilTest, CopyDirectoryExists) {
TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) {
// Create a file
FilePath file_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
ASSERT_TRUE(file_util::PathExists(file_name_from));
// The destination name
- FilePath file_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+ FilePath file_name_to = temp_dir_.path().Append(
+ FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
ASSERT_FALSE(file_util::PathExists(file_name_to));
EXPECT_TRUE(file_util::CopyDirectory(file_name_from, file_name_to, true));
@@ -1189,13 +1118,13 @@ TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) {
TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) {
// Create a file
FilePath file_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
ASSERT_TRUE(file_util::PathExists(file_name_from));
// The destination name
- FilePath file_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+ FilePath file_name_to = temp_dir_.path().Append(
+ FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
CreateTextFile(file_name_to, L"Old file content");
ASSERT_TRUE(file_util::PathExists(file_name_to));
@@ -1209,13 +1138,13 @@ TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) {
TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) {
// Create a file
FilePath file_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
ASSERT_TRUE(file_util::PathExists(file_name_from));
// The destination
FilePath dir_name_to =
- test_dir_.Append(FILE_PATH_LITERAL("Destination"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
file_util::CreateDirectory(dir_name_to);
ASSERT_TRUE(file_util::PathExists(dir_name_to));
FilePath file_name_to =
@@ -1230,7 +1159,7 @@ TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) {
TEST_F(FileUtilTest, CopyFile) {
// Create a directory
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -1267,7 +1196,7 @@ TEST_F(FileUtilTest, CopyFile) {
// TODO(erikkay): implement
#if defined(OS_WIN)
TEST_F(FileUtilTest, GetFileCreationLocalTime) {
- FilePath file_name = test_dir_.Append(L"Test File.txt");
+ FilePath file_name = temp_dir_.path().Append(L"Test File.txt");
SYSTEMTIME start_time;
GetLocalTime(&start_time);
@@ -1405,10 +1334,10 @@ TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) {
// We don't need equivalent functionality outside of Windows.
#if defined(OS_WIN)
TEST_F(FileUtilTest, ResolveShortcutTest) {
- FilePath target_file = test_dir_.Append(L"Target.txt");
+ FilePath target_file = temp_dir_.path().Append(L"Target.txt");
CreateTextFile(target_file, L"This is the target.");
- FilePath link_file = test_dir_.Append(L"Link.lnk");
+ FilePath link_file = temp_dir_.path().Append(L"Link.lnk");
HRESULT result;
IShellLink *shell = NULL;
@@ -1449,10 +1378,10 @@ TEST_F(FileUtilTest, ResolveShortcutTest) {
TEST_F(FileUtilTest, CreateShortcutTest) {
const wchar_t file_contents[] = L"This is another target.";
- FilePath target_file = test_dir_.Append(L"Target1.txt");
+ FilePath target_file = temp_dir_.path().Append(L"Target1.txt");
CreateTextFile(target_file, file_contents);
- FilePath link_file = test_dir_.Append(L"Link1.lnk");
+ FilePath link_file = temp_dir_.path().Append(L"Link1.lnk");
CoInitialize(NULL);
EXPECT_TRUE(file_util::CreateShortcutLink(target_file.value().c_str(),
@@ -1471,7 +1400,7 @@ TEST_F(FileUtilTest, CreateShortcutTest) {
TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) {
// Create a directory
FilePath dir_name_from =
- test_dir_.Append(FILE_PATH_LITERAL("CopyAndDelete_From_Subdir"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("CopyAndDelete_From_Subdir"));
file_util::CreateDirectory(dir_name_from);
ASSERT_TRUE(file_util::PathExists(dir_name_from));
@@ -1482,7 +1411,7 @@ TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) {
ASSERT_TRUE(file_util::PathExists(file_name_from));
// Move the directory by using CopyAndDeleteDirectory
- FilePath dir_name_to = test_dir_.Append(
+ FilePath dir_name_to = temp_dir_.path().Append(
FILE_PATH_LITERAL("CopyAndDelete_To_Subdir"));
FilePath file_name_to =
dir_name_to.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
@@ -1575,12 +1504,11 @@ TEST_F(FileUtilTest, CreateNewTempDirectoryTest) {
TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) {
FilePath new_dir;
ASSERT_TRUE(file_util::CreateTemporaryDirInDir(
- test_dir_,
+ temp_dir_.path(),
FILE_PATH_LITERAL("CreateNewTemporaryDirInDirTest"),
- false,
&new_dir));
EXPECT_TRUE(file_util::PathExists(new_dir));
- EXPECT_TRUE(test_dir_.IsParent(new_dir));
+ EXPECT_TRUE(temp_dir_.path().IsParent(new_dir));
EXPECT_TRUE(file_util::Delete(new_dir, false));
}
@@ -1592,7 +1520,7 @@ TEST_F(FileUtilTest, GetShmemTempDirTest) {
TEST_F(FileUtilTest, CreateDirectoryTest) {
FilePath test_root =
- test_dir_.Append(FILE_PATH_LITERAL("create_directory_test"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("create_directory_test"));
#if defined(OS_WIN)
FilePath test_path =
test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\"));
@@ -1648,7 +1576,7 @@ TEST_F(FileUtilTest, CreateDirectoryTest) {
TEST_F(FileUtilTest, DetectDirectoryTest) {
// Check a directory
FilePath test_root =
- test_dir_.Append(FILE_PATH_LITERAL("detect_directory_test"));
+ temp_dir_.path().Append(FILE_PATH_LITERAL("detect_directory_test"));
EXPECT_FALSE(file_util::PathExists(test_root));
EXPECT_TRUE(file_util::CreateDirectory(test_root));
EXPECT_TRUE(file_util::PathExists(test_root));
@@ -1668,23 +1596,23 @@ TEST_F(FileUtilTest, DetectDirectoryTest) {
TEST_F(FileUtilTest, FileEnumeratorTest) {
// Test an empty directory.
- file_util::FileEnumerator f0(test_dir_, true, FILES_AND_DIRECTORIES);
+ file_util::FileEnumerator f0(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
EXPECT_EQ(f0.Next().value(), FILE_PATH_LITERAL(""));
EXPECT_EQ(f0.Next().value(), FILE_PATH_LITERAL(""));
// Test an empty directory, non-recursively, including "..".
- file_util::FileEnumerator f0_dotdot(test_dir_, false,
+ file_util::FileEnumerator f0_dotdot(temp_dir_.path(), false,
static_cast<file_util::FileEnumerator::FILE_TYPE>(
FILES_AND_DIRECTORIES | file_util::FileEnumerator::INCLUDE_DOT_DOT));
- EXPECT_EQ(test_dir_.Append(FILE_PATH_LITERAL("..")).value(),
+ EXPECT_EQ(temp_dir_.path().Append(FILE_PATH_LITERAL("..")).value(),
f0_dotdot.Next().value());
EXPECT_EQ(FILE_PATH_LITERAL(""),
f0_dotdot.Next().value());
// create the directories
- FilePath dir1 = test_dir_.Append(FILE_PATH_LITERAL("dir1"));
+ FilePath dir1 = temp_dir_.path().Append(FILE_PATH_LITERAL("dir1"));
EXPECT_TRUE(file_util::CreateDirectory(dir1));
- FilePath dir2 = test_dir_.Append(FILE_PATH_LITERAL("dir2"));
+ FilePath dir2 = temp_dir_.path().Append(FILE_PATH_LITERAL("dir2"));
EXPECT_TRUE(file_util::CreateDirectory(dir2));
FilePath dir2inner = dir2.Append(FILE_PATH_LITERAL("inner"));
EXPECT_TRUE(file_util::CreateDirectory(dir2inner));
@@ -1694,16 +1622,16 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
CreateTextFile(dir2file, L"");
FilePath dir2innerfile = dir2inner.Append(FILE_PATH_LITERAL("innerfile.txt"));
CreateTextFile(dir2innerfile, L"");
- FilePath file1 = test_dir_.Append(FILE_PATH_LITERAL("file1.txt"));
+ FilePath file1 = temp_dir_.path().Append(FILE_PATH_LITERAL("file1.txt"));
CreateTextFile(file1, L"");
FilePath file2_rel =
dir2.Append(FilePath::kParentDirectory)
.Append(FILE_PATH_LITERAL("file2.txt"));
CreateTextFile(file2_rel, L"");
- FilePath file2_abs = test_dir_.Append(FILE_PATH_LITERAL("file2.txt"));
+ FilePath file2_abs = temp_dir_.path().Append(FILE_PATH_LITERAL("file2.txt"));
// Only enumerate files.
- file_util::FileEnumerator f1(test_dir_, true,
+ file_util::FileEnumerator f1(temp_dir_.path(), true,
file_util::FileEnumerator::FILES);
FindResultCollector c1(f1);
EXPECT_TRUE(c1.HasFile(file1));
@@ -1713,7 +1641,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
EXPECT_EQ(c1.size(), 4);
// Only enumerate directories.
- file_util::FileEnumerator f2(test_dir_, true,
+ file_util::FileEnumerator f2(temp_dir_.path(), true,
file_util::FileEnumerator::DIRECTORIES);
FindResultCollector c2(f2);
EXPECT_TRUE(c2.HasFile(dir1));
@@ -1723,7 +1651,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Only enumerate directories non-recursively.
file_util::FileEnumerator f2_non_recursive(
- test_dir_, false, file_util::FileEnumerator::DIRECTORIES);
+ temp_dir_.path(), false, file_util::FileEnumerator::DIRECTORIES);
FindResultCollector c2_non_recursive(f2_non_recursive);
EXPECT_TRUE(c2_non_recursive.HasFile(dir1));
EXPECT_TRUE(c2_non_recursive.HasFile(dir2));
@@ -1731,18 +1659,19 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Only enumerate directories, non-recursively, including "..".
file_util::FileEnumerator f2_dotdot(
- test_dir_, false,
+ temp_dir_.path(), false,
static_cast<file_util::FileEnumerator::FILE_TYPE>(
file_util::FileEnumerator::DIRECTORIES |
file_util::FileEnumerator::INCLUDE_DOT_DOT));
FindResultCollector c2_dotdot(f2_dotdot);
EXPECT_TRUE(c2_dotdot.HasFile(dir1));
EXPECT_TRUE(c2_dotdot.HasFile(dir2));
- EXPECT_TRUE(c2_dotdot.HasFile(test_dir_.Append(FILE_PATH_LITERAL(".."))));
+ EXPECT_TRUE(c2_dotdot.HasFile(
+ temp_dir_.path().Append(FILE_PATH_LITERAL(".."))));
EXPECT_EQ(c2_dotdot.size(), 3);
// Enumerate files and directories.
- file_util::FileEnumerator f3(test_dir_, true, FILES_AND_DIRECTORIES);
+ file_util::FileEnumerator f3(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
FindResultCollector c3(f3);
EXPECT_TRUE(c3.HasFile(dir1));
EXPECT_TRUE(c3.HasFile(dir2));
@@ -1754,7 +1683,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
EXPECT_EQ(c3.size(), 7);
// Non-recursive operation.
- file_util::FileEnumerator f4(test_dir_, false, FILES_AND_DIRECTORIES);
+ file_util::FileEnumerator f4(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
FindResultCollector c4(f4);
EXPECT_TRUE(c4.HasFile(dir2));
EXPECT_TRUE(c4.HasFile(dir2));
@@ -1763,7 +1692,7 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
EXPECT_EQ(c4.size(), 4);
// Enumerate with a pattern.
- file_util::FileEnumerator f5(test_dir_, true, FILES_AND_DIRECTORIES,
+ file_util::FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES,
FILE_PATH_LITERAL("dir*"));
FindResultCollector c5(f5);
EXPECT_TRUE(c5.HasFile(dir1));
@@ -1775,13 +1704,14 @@ TEST_F(FileUtilTest, FileEnumeratorTest) {
// Make sure the destructor closes the find handle while in the middle of a
// query to allow TearDown to delete the directory.
- file_util::FileEnumerator f6(test_dir_, true, FILES_AND_DIRECTORIES);
+ file_util::FileEnumerator f6(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
EXPECT_FALSE(f6.Next().value().empty()); // Should have found something
// (we don't care what).
}
TEST_F(FileUtilTest, Contains) {
- FilePath data_dir = test_dir_.Append(FILE_PATH_LITERAL("FilePathTest"));
+ FilePath data_dir =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
// Create a fresh, empty copy of this directory.
if (file_util::PathExists(data_dir)) {
@@ -1823,8 +1753,9 @@ TEST_F(FileUtilTest, Contains) {
#endif
}
-TEST_F(FileUtilTest, LastModified) {
- FilePath data_dir = test_dir_.Append(FILE_PATH_LITERAL("FilePathTest"));
+TEST_F(FileUtilTest, TouchFile) {
+ FilePath data_dir =
+ temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
// Create a fresh, empty copy of this directory.
if (file_util::PathExists(data_dir)) {
@@ -1836,19 +1767,29 @@ TEST_F(FileUtilTest, LastModified) {
std::string data("hello");
ASSERT_TRUE(file_util::WriteFile(foobar, data.c_str(), data.length()));
+ base::Time access_time;
+ // This timestamp is divisible by one day (in local timezone),
+ // to make it work on FAT too.
+ ASSERT_TRUE(base::Time::FromString(L"Wed, 16 Nov 1994, 00:00:00",
+ &access_time));
+
base::Time modification_time;
// Note that this timestamp is divisible by two (seconds) - FAT stores
// modification times with 2s resolution.
ASSERT_TRUE(base::Time::FromString(L"Tue, 15 Nov 1994, 12:45:26 GMT",
&modification_time));
- ASSERT_TRUE(file_util::SetLastModifiedTime(foobar, modification_time));
- file_util::FileInfo file_info;
+
+ ASSERT_TRUE(file_util::TouchFile(foobar, access_time, modification_time));
+ base::PlatformFileInfo file_info;
ASSERT_TRUE(file_util::GetFileInfo(foobar, &file_info));
- ASSERT_TRUE(file_info.last_modified == modification_time);
+ EXPECT_EQ(file_info.last_accessed.ToInternalValue(),
+ access_time.ToInternalValue());
+ EXPECT_EQ(file_info.last_modified.ToInternalValue(),
+ modification_time.ToInternalValue());
}
TEST_F(FileUtilTest, IsDirectoryEmpty) {
- FilePath empty_dir = test_dir_.Append(FILE_PATH_LITERAL("EmptyDir"));
+ FilePath empty_dir = temp_dir_.path().Append(FILE_PATH_LITERAL("EmptyDir"));
ASSERT_FALSE(file_util::PathExists(empty_dir));
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 26955f2..a376d0d 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -17,14 +17,19 @@
#include "base/pe_image.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_handle.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/win_util.h"
namespace file_util {
namespace {
+const DWORD kFileShareAll =
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
// Helper for NormalizeFilePath(), defined below.
bool DevicePathToDriveLetterPath(const FilePath& device_path,
FilePath* drive_letter_path) {
@@ -59,59 +64,10 @@ bool DevicePathToDriveLetterPath(const FilePath& device_path,
while(*drive_map_ptr++);
}
- // No drive matched. The path does not start with a device junction.
- *drive_letter_path = device_path;
- return true;
-}
-
-// Build a security descriptor with the weakest possible file permissions.
-bool InitLooseSecurityDescriptor(SECURITY_ATTRIBUTES *sa,
- SECURITY_DESCRIPTOR *sd) {
- DWORD last_error;
-
- if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
- last_error = GetLastError();
- LOG(ERROR) << "InitializeSecurityDescriptor failed: GetLastError() = "
- << last_error;
- return false;
- }
-
- if (!SetSecurityDescriptorDacl(sd,
- TRUE, // bDaclPresent: Add one to |sd|.
- NULL, // pDacl: NULL means allow all access.
- FALSE // bDaclDefaulted: Not defaulted.
- )) {
- last_error = GetLastError();
- LOG(ERROR) << "SetSecurityDescriptorDacl() failed: GetLastError() = "
- << last_error;
- return false;
- }
-
- if (!SetSecurityDescriptorGroup(sd,
- NULL, // pGroup: No no primary group.
- FALSE // bGroupDefaulted: Not defaulted.
- )) {
- last_error = GetLastError();
- LOG(ERROR) << "SetSecurityDescriptorGroup() failed: GetLastError() = "
- << last_error;
- return false;
- }
-
- if (!SetSecurityDescriptorSacl(sd,
- FALSE, // bSaclPresent: No SACL.
- NULL,
- FALSE
- )) {
- last_error = GetLastError();
- LOG(ERROR) << "SetSecurityDescriptorSacl() failed: GetLastError() = "
- << last_error;
- return false;
- }
-
- sa->nLength = sizeof(SECURITY_ATTRIBUTES);
- sa->lpSecurityDescriptor = sd;
- sa->bInheritHandle = TRUE;
- return true;
+ // No drive matched. The path does not start with a device junction
+ // that is mounted as a drive letter. This means there is no drive
+ // letter path to the volume that holds |device_path|, so fail.
+ return false;
}
} // namespace
@@ -171,7 +127,7 @@ bool Delete(const FilePath& path, bool recursive) {
if (!recursive) {
// If not recursing, then first check to see if |path| is a directory.
// If it is, then remove it with RemoveDirectory.
- FileInfo file_info;
+ base::PlatformFileInfo file_info;
if (GetFileInfo(path, &file_info) && file_info.is_directory)
return RemoveDirectory(path.value().c_str()) != 0;
@@ -335,8 +291,7 @@ bool PathExists(const FilePath& path) {
bool PathIsWritable(const FilePath& path) {
HANDLE dir =
- CreateFile(path.value().c_str(), FILE_ADD_FILE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (dir == INVALID_HANDLE_VALUE)
@@ -372,8 +327,7 @@ bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
bool GetFileCreationLocalTime(const std::wstring& filename,
LPSYSTEMTIME creation_time) {
ScopedHandle file_handle(
- CreateFile(filename.c_str(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ CreateFile(filename.c_str(), GENERIC_READ, kFileShareAll, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
}
@@ -601,19 +555,7 @@ bool CreateTemporaryFileInDir(const FilePath& dir,
bool CreateTemporaryDirInDir(const FilePath& base_dir,
const FilePath::StringType& prefix,
- bool loosen_permissions,
FilePath* new_dir) {
- SECURITY_ATTRIBUTES sa;
- SECURITY_DESCRIPTOR sd;
-
- LPSECURITY_ATTRIBUTES directory_security_attributes = NULL;
- if (loosen_permissions) {
- if (InitLooseSecurityDescriptor(&sa, &sd))
- directory_security_attributes = &sa;
- else
- LOG(ERROR) << "Failed to init security attributes, fall back to NULL.";
- }
-
FilePath path_to_create;
srand(static_cast<uint32>(time(NULL)));
@@ -623,13 +565,12 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
// the one exists, keep trying another path name until we reach some limit.
path_to_create = base_dir;
- std::wstring new_dir_name;
+ string16 new_dir_name;
new_dir_name.assign(prefix);
- new_dir_name.append(IntToWString(rand() % kint16max));
+ new_dir_name.append(base::IntToString16(rand() % kint16max));
path_to_create = path_to_create.Append(new_dir_name);
- if (::CreateDirectory(path_to_create.value().c_str(),
- directory_security_attributes))
+ if (::CreateDirectory(path_to_create.value().c_str(), NULL))
break;
count++;
}
@@ -639,7 +580,6 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
}
*new_dir = path_to_create;
-
return true;
}
@@ -649,38 +589,22 @@ bool CreateNewTempDirectory(const FilePath::StringType& prefix,
if (!GetTempDir(&system_temp_dir))
return false;
- return CreateTemporaryDirInDir(system_temp_dir,
- prefix,
- false,
- new_temp_path);
+ return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path);
}
bool CreateDirectory(const FilePath& full_path) {
- return file_util::CreateDirectoryExtraLogging(full_path, LOG(INFO));
-}
-
-// TODO(skerner): Extra logging has been added to understand crbug/35198 .
-// Remove it once we get a log from a user who can reproduce the issue.
-bool CreateDirectoryExtraLogging(const FilePath& full_path,
- std::ostream& log) {
- log << "Enter CreateDirectory: full_path = " << full_path.value()
- << std::endl;
// If the path exists, we've succeeded if it's a directory, failed otherwise.
const wchar_t* full_path_str = full_path.value().c_str();
DWORD fileattr = ::GetFileAttributes(full_path_str);
- log << "::GetFileAttributes() returned " << fileattr << std::endl;
- if (fileattr == INVALID_FILE_ATTRIBUTES) {
- DWORD fileattr_error = GetLastError();
- log << "::GetFileAttributes() failed. GetLastError() = "
- << fileattr_error << std::endl;
- } else {
+ if (fileattr != INVALID_FILE_ATTRIBUTES) {
if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
- log << "CreateDirectory(" << full_path_str << "), "
- << "directory already exists." << std::endl;
+ DLOG(INFO) << "CreateDirectory(" << full_path_str << "), "
+ << "directory already exists.";
return true;
} else {
- log << "CreateDirectory(" << full_path_str << "), "
- << "conflicts with existing file." << std::endl;
+ LOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
+ << "conflicts with existing file.";
+ return false;
}
}
@@ -691,54 +615,31 @@ bool CreateDirectoryExtraLogging(const FilePath& full_path,
// directories starting with the highest-level missing parent.
FilePath parent_path(full_path.DirName());
if (parent_path.value() == full_path.value()) {
- log << "Can't create directory: parent_path " << parent_path.value()
- << " should not equal full_path " << full_path.value()
- << std::endl;
return false;
}
if (!CreateDirectory(parent_path)) {
- log << "Failed to create one of the parent directories: "
- << parent_path.value() << std::endl;
+ DLOG(WARNING) << "Failed to create one of the parent directories.";
return false;
}
- log << "About to call ::CreateDirectory() with full_path_str = "
- << full_path_str << std::endl;
if (!::CreateDirectory(full_path_str, NULL)) {
DWORD error_code = ::GetLastError();
- log << "CreateDirectory() gave last error " << error_code << std::endl;
-
- DWORD fileattr = GetFileAttributes(full_path.value().c_str());
- if (fileattr == INVALID_FILE_ATTRIBUTES) {
- DWORD fileattr_error = ::GetLastError();
- log << "GetFileAttributes() failed, GetLastError() = "
- << fileattr_error << std::endl;
- } else {
- log << "GetFileAttributes() returned " << fileattr << std::endl;
- log << "Is the path a directory: "
- << ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) << std::endl;
- }
if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
// This error code doesn't indicate whether we were racing with someone
// creating the same directory, or a file with the same path, therefore
// we check.
- log << "Race condition? Directory already exists: "
- << full_path.value() << std::endl;
return true;
} else {
- DWORD dir_exists_error = ::GetLastError();
- log << "Failed to create directory " << full_path_str << std::endl;
- log << "GetLastError() for DirectoryExists() is "
- << dir_exists_error << std::endl;
+ LOG(WARNING) << "Failed to create directory " << full_path_str
+ << ", last error is " << error_code << ".";
return false;
}
} else {
- log << "::CreateDirectory() succeeded." << std::endl;
return true;
}
}
-bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
+bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
WIN32_FILE_ATTRIBUTE_DATA attr;
if (!GetFileAttributesEx(file_path.value().c_str(),
GetFileExInfoStandard, &attr)) {
@@ -753,20 +654,12 @@ bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
results->is_directory =
(attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
results->last_modified = base::Time::FromFileTime(attr.ftLastWriteTime);
+ results->last_accessed = base::Time::FromFileTime(attr.ftLastAccessTime);
+ results->creation_time = base::Time::FromFileTime(attr.ftCreationTime);
return true;
}
-bool SetLastModifiedTime(const FilePath& file_path, base::Time last_modified) {
- FILETIME timestamp(last_modified.ToFileTime());
- ScopedHandle file_handle(
- CreateFile(file_path.value().c_str(), FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
- BOOL ret = SetFileTime(file_handle.Get(), NULL, &timestamp, &timestamp);
- return ret != 0;
-}
-
FILE* OpenFile(const FilePath& filename, const char* mode) {
std::wstring w_mode = ASCIIToWide(std::string(mode));
return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
@@ -784,7 +677,7 @@ int ReadFile(const FilePath& filename, char* data, int size) {
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL));
- if (file == INVALID_HANDLE_VALUE)
+ if (!file)
return -1;
DWORD read;
@@ -802,7 +695,7 @@ int WriteFile(const FilePath& filename, const char* data, int size) {
CREATE_ALWAYS,
0,
NULL));
- if (file == INVALID_HANDLE_VALUE) {
+ if (!file) {
LOG(WARNING) << "CreateFile failed for path " << filename.value() <<
" error code=" << GetLastError() <<
" error text=" << win_util::FormatLastWin32Error();
@@ -1033,51 +926,52 @@ bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
}
bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
- ScopedHandle path_handle(
- ::CreateFile(path.value().c_str(),
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL));
- if (path_handle == INVALID_HANDLE_VALUE)
+ FilePath mapped_file;
+ if (!NormalizeToNativeFilePath(path, &mapped_file))
return false;
+ // NormalizeToNativeFilePath() will return a path that starts with
+ // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath()
+ // will find a drive letter which maps to the path's device, so
+ // that we return a path starting with a drive letter.
+ return DevicePathToDriveLetterPath(mapped_file, real_path);
+}
+bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
// In Vista, GetFinalPathNameByHandle() would give us the real path
// from a file handle. If we ever deprecate XP, consider changing the
// code below to a call to GetFinalPathNameByHandle(). The method this
// function uses is explained in the following msdn article:
// http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
- DWORD file_size_high = 0;
- DWORD file_size_low = ::GetFileSize(path_handle.Get(), &file_size_high);
- if (file_size_low == 0 && file_size_high == 0) {
- // It is not possible to map an empty file.
- LOG(ERROR) << "NormalizeFilePath failed: Empty file.";
+ ScopedHandle file_handle(
+ ::CreateFile(path.value().c_str(),
+ GENERIC_READ,
+ kFileShareAll,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL));
+ if (!file_handle)
return false;
- }
// Create a file mapping object. Can't easily use MemoryMappedFile, because
- // we only map the first byte, and need direct access to the handle.
+ // we only map the first byte, and need direct access to the handle. You can
+ // not map an empty file, this call fails in that case.
ScopedHandle file_map_handle(
- ::CreateFileMapping(path_handle.Get(),
+ ::CreateFileMapping(file_handle.Get(),
NULL,
PAGE_READONLY,
0,
1, // Just one byte. No need to look at the data.
NULL));
-
- if (file_map_handle == INVALID_HANDLE_VALUE)
+ if (!file_map_handle)
return false;
// Use a view of the file to get the path to the file.
- void* file_view = MapViewOfFile(
- file_map_handle.Get(), FILE_MAP_READ, 0, 0, 1);
+ void* file_view = MapViewOfFile(file_map_handle.Get(),
+ FILE_MAP_READ, 0, 0, 1);
if (!file_view)
return false;
- bool success = false;
-
// The expansion of |path| into a full path may make it longer.
// GetMappedFileName() will fail if the result is longer than MAX_PATH.
// Pad a bit to be safe. If kMaxPathLength is ever changed to be less
@@ -1086,42 +980,78 @@ bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
// path fit in |mapped_file_path|.
const int kMaxPathLength = MAX_PATH + 10;
wchar_t mapped_file_path[kMaxPathLength];
- if (::GetMappedFileName(GetCurrentProcess(),
- file_view,
- mapped_file_path,
- kMaxPathLength)) {
- // GetMappedFileName() will return a path that starts with
- // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath()
- // will find a drive letter which maps to the path's device, so
- // that we return a path starting with a drive letter.
- FilePath mapped_file(mapped_file_path);
- success = DevicePathToDriveLetterPath(mapped_file, real_path);
+ bool success = false;
+ HANDLE cp = GetCurrentProcess();
+ if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) {
+ *nt_path = FilePath(mapped_file_path);
+ success = true;
}
- UnmapViewOfFile(file_view);
+ ::UnmapViewOfFile(file_view);
return success;
}
bool PreReadImage(const wchar_t* file_path, size_t size_to_read,
size_t step_size) {
- HMODULE dll_module = LoadLibraryExW(
- file_path,
- NULL,
- LOAD_WITH_ALTERED_SEARCH_PATH | DONT_RESOLVE_DLL_REFERENCES);
+ if (win_util::GetWinVersion() > win_util::WINVERSION_XP) {
+ // Vista+ branch. On these OSes, the forced reads through the DLL actually
+ // slows warm starts. The solution is to sequentially read file contents
+ // with an optional cap on total amount to read.
+ ScopedHandle file(
+ CreateFile(file_path,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL));
- if (!dll_module)
- return false;
+ if (!file.IsValid())
+ return false;
- PEImage pe_image(dll_module);
- PIMAGE_NT_HEADERS nt_headers = pe_image.GetNTHeaders();
- size_t actual_size_to_read = size_to_read ? size_to_read :
- nt_headers->OptionalHeader.SizeOfImage;
- volatile uint8* touch = reinterpret_cast<uint8*>(dll_module);
- size_t offset = 0;
- while (offset < actual_size_to_read) {
- uint8 unused = *(touch + offset);
- offset += step_size;
+ // Default to 1MB sequential reads.
+ const DWORD actual_step_size = std::max(static_cast<DWORD>(step_size),
+ static_cast<DWORD>(1024*1024));
+ LPVOID buffer = ::VirtualAlloc(NULL,
+ actual_step_size,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+
+ if (buffer == NULL)
+ return false;
+
+ DWORD len;
+ size_t total_read = 0;
+ while (::ReadFile(file, buffer, actual_step_size, &len, NULL) &&
+ len > 0 &&
+ (size_to_read ? total_read < size_to_read : true)) {
+ total_read += static_cast<size_t>(len);
+ }
+ ::VirtualFree(buffer, 0, MEM_RELEASE);
+ } else {
+ // WinXP branch. Here, reading the DLL from disk doesn't do
+ // what we want so instead we pull the pages into memory by loading
+ // the DLL and touching pages at a stride.
+ HMODULE dll_module = ::LoadLibraryExW(
+ file_path,
+ NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH | DONT_RESOLVE_DLL_REFERENCES);
+
+ if (!dll_module)
+ return false;
+
+ PEImage pe_image(dll_module);
+ PIMAGE_NT_HEADERS nt_headers = pe_image.GetNTHeaders();
+ size_t actual_size_to_read = size_to_read ? size_to_read :
+ nt_headers->OptionalHeader.SizeOfImage;
+ volatile uint8* touch = reinterpret_cast<uint8*>(dll_module);
+ size_t offset = 0;
+ while (offset < actual_size_to_read) {
+ uint8 unused = *(touch + offset);
+ offset += step_size;
+ }
+ FreeLibrary(dll_module);
}
- FreeLibrary(dll_module);
+
return true;
}
diff --git a/base/file_version_info.h b/base/file_version_info.h
index 9ab7a0d..19407d2 100644
--- a/base/file_version_info.h
+++ b/base/file_version_info.h
@@ -4,6 +4,7 @@
#ifndef BASE_FILE_VERSION_INFO_H__
#define BASE_FILE_VERSION_INFO_H__
+#pragma once
#include <string>
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
index a523f54..d66c4e6 100644
--- a/base/file_version_info_mac.h
+++ b/base/file_version_info_mac.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef BASE_FILE_VERSION_INFO_MAC_H_
#define BASE_FILE_VERSION_INFO_MAC_H_
+#pragma once
#include <string>
@@ -17,8 +18,6 @@
class NSBundle;
#endif
-class FilePath;
-
// 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.
diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm
index 2218226..57be79a 100644
--- a/base/file_version_info_mac.mm
+++ b/base/file_version_info_mac.mm
@@ -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,8 +6,8 @@
#import <Cocoa/Cocoa.h>
+#include "base/basictypes.h"
#include "base/file_path.h"
-#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
diff --git a/base/file_version_info_win.h b/base/file_version_info_win.h
index ce173fe..3d60d69 100644
--- a/base/file_version_info_win.h
+++ b/base/file_version_info_win.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef BASE_FILE_VERSION_INFO_WIN_H_
#define BASE_FILE_VERSION_INFO_WIN_H_
+#pragma once
#include <string>
@@ -14,8 +15,6 @@
struct tagVS_FIXEDFILEINFO;
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
-class FilePath;
-
// 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.
diff --git a/base/fix_wp64.h b/base/fix_wp64.h
index 0c4c0bb..7e2f7c1 100644
--- a/base/fix_wp64.h
+++ b/base/fix_wp64.h
@@ -7,6 +7,7 @@
#ifndef BASE_FIX_WP64_H__
#define BASE_FIX_WP64_H__
+#pragma once
#include <windows.h>
diff --git a/base/float_util.h b/base/float_util.h
index a71b639..69334d0 100644
--- a/base/float_util.h
+++ b/base/float_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_FLOAT_UTIL_H_
#define BASE_FLOAT_UTIL_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/format_macros.h b/base/format_macros.h
index 9c9b950..3afad59 100644
--- a/base/format_macros.h
+++ b/base/format_macros.h
@@ -4,6 +4,7 @@
#ifndef BASE_FORMAT_MACROS_H_
#define BASE_FORMAT_MACROS_H_
+#pragma once
// This file defines the format macros for some integer types.
@@ -70,4 +71,4 @@
#endif
-#endif // !BASE_FORMAT_MACROS_H_
+#endif // BASE_FORMAT_MACROS_H_
diff --git a/base/foundation_utils_mac.h b/base/foundation_utils_mac.h
index 64ebeda..740a383 100644
--- a/base/foundation_utils_mac.h
+++ b/base/foundation_utils_mac.h
@@ -4,6 +4,7 @@
#ifndef BASE_FOUNDATION_UTILS_MAC_H_
#define BASE_FOUNDATION_UTILS_MAC_H_
+#pragma once
#include <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
diff --git a/base/global_descriptors_posix.h b/base/global_descriptors_posix.h
index f606a82..c37dae6 100644
--- a/base/global_descriptors_posix.h
+++ b/base/global_descriptors_posix.h
@@ -4,6 +4,7 @@
#ifndef BASE_GLOBAL_DESCRIPTORS_POSIX_H_
#define BASE_GLOBAL_DESCRIPTORS_POSIX_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/gtest_prod_util.h b/base/gtest_prod_util.h
index 0e8e61a..a54235a 100644
--- a/base/gtest_prod_util.h
+++ b/base/gtest_prod_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_GTEST_PROD_UTIL_H_
#define BASE_GTEST_PROD_UTIL_H_
+#pragma once
#include "testing/gtest/include/gtest/gtest_prod.h"
diff --git a/base/gtk_util.h b/base/gtk_util.h
index fc85db5..435780d 100644
--- a/base/gtk_util.h
+++ b/base/gtk_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_GTK_UTIL_H_
#define BASE_GTK_UTIL_H_
+#pragma once
#include <string>
diff --git a/base/hash_tables.h b/base/hash_tables.h
index 4835f29..5fbe466 100644
--- a/base/hash_tables.h
+++ b/base/hash_tables.h
@@ -20,6 +20,7 @@
#ifndef BASE_HASH_TABLES_H_
#define BASE_HASH_TABLES_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/histogram.cc b/base/histogram.cc
index 2206756..e045d81 100644
--- a/base/histogram.cc
+++ b/base/histogram.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.
@@ -10,12 +10,14 @@
#include "base/histogram.h"
#include <math.h>
+
+#include <algorithm>
#include <string>
#include "base/lock.h"
#include "base/logging.h"
#include "base/pickle.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
using base::TimeDelta;
@@ -84,6 +86,10 @@ Histogram::~Histogram() {
DCHECK(ValidateBucketRanges());
}
+bool Histogram::PrintEmptyBucket(size_t index) const {
+ return true;
+}
+
void Histogram::Add(int value) {
if (value >= kSampleType_MAX)
value = kSampleType_MAX - 1;
@@ -95,10 +101,18 @@ void Histogram::Add(int value) {
Accumulate(value, 1, index);
}
+void Histogram::AddBoolean(bool value) {
+ DCHECK(false);
+}
+
void Histogram::AddSampleSet(const SampleSet& sample) {
sample_.Add(sample);
}
+void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
+ DCHECK(false);
+}
+
// The following methods provide a graphical histogram display.
void Histogram::WriteHTMLGraph(std::string* output) const {
// TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
@@ -290,6 +304,20 @@ void Histogram::SnapshotSample(SampleSet* sample) const {
*sample = sample_;
}
+bool Histogram::HasConstructorArguments(Sample minimum, Sample maximum,
+ size_t bucket_count) {
+ return ((minimum == declared_min_) && (maximum == declared_max_) &&
+ (bucket_count == bucket_count_));
+}
+
+bool Histogram::HasConstructorTimeDeltaArguments(base::TimeDelta minimum,
+ base::TimeDelta maximum,
+ size_t bucket_count) {
+ return ((minimum.InMilliseconds() == declared_min_) &&
+ (maximum.InMilliseconds() == declared_max_) &&
+ (bucket_count == bucket_count_));
+}
+
//------------------------------------------------------------------------------
// Accessor methods
@@ -314,10 +342,10 @@ double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const {
void Histogram::WriteAsciiHeader(const SampleSet& snapshot,
Count sample_count,
std::string* output) const {
- StringAppendF(output,
- "Histogram: %s recorded %d samples",
- histogram_name().c_str(),
- sample_count);
+ base::StringAppendF(output,
+ "Histogram: %s recorded %d samples",
+ histogram_name().c_str(),
+ sample_count);
if (0 == sample_count) {
DCHECK_EQ(snapshot.sum(), 0);
} else {
@@ -326,12 +354,13 @@ void Histogram::WriteAsciiHeader(const SampleSet& snapshot,
- average * average;
double standard_deviation = sqrt(variance);
- StringAppendF(output,
- ", average = %.1f, standard deviation = %.1f",
- average, standard_deviation);
+ base::StringAppendF(output,
+ ", average = %.1f, standard deviation = %.1f",
+ average, standard_deviation);
}
if (flags_ & ~kHexRangePrintingFlag )
- StringAppendF(output, " (flags = 0x%x)", flags_ & ~kHexRangePrintingFlag);
+ base::StringAppendF(output, " (flags = 0x%x)",
+ flags_ & ~kHexRangePrintingFlag);
}
void Histogram::WriteAsciiBucketContext(const int64 past,
@@ -343,22 +372,22 @@ void Histogram::WriteAsciiBucketContext(const int64 past,
WriteAsciiBucketValue(current, scaled_sum, output);
if (0 < i) {
double percentage = past / scaled_sum;
- StringAppendF(output, " {%3.1f%%}", percentage);
+ base::StringAppendF(output, " {%3.1f%%}", percentage);
}
}
const std::string Histogram::GetAsciiBucketRange(size_t i) const {
std::string result;
if (kHexRangePrintingFlag & flags_)
- StringAppendF(&result, "%#x", ranges(i));
+ base::StringAppendF(&result, "%#x", ranges(i));
else
- StringAppendF(&result, "%d", ranges(i));
+ base::StringAppendF(&result, "%d", ranges(i));
return result;
}
void Histogram::WriteAsciiBucketValue(Count current, double scaled_sum,
std::string* output) const {
- StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
+ base::StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
}
void Histogram::WriteAsciiBucketGraph(double current_size, double max_size,
@@ -474,6 +503,9 @@ Histogram::SampleSet::SampleSet()
square_sum_(0) {
}
+Histogram::SampleSet::~SampleSet() {
+}
+
void Histogram::SampleSet::Resize(const Histogram& histogram) {
counts_.resize(histogram.bucket_count(), 0);
}
@@ -596,6 +628,9 @@ scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet(
bucket_count, flags);
}
+LinearHistogram::~LinearHistogram() {
+}
+
LinearHistogram::LinearHistogram(const std::string& name, Sample minimum,
Sample maximum, size_t bucket_count)
: Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) {
@@ -613,6 +648,10 @@ LinearHistogram::LinearHistogram(const std::string& name,
DCHECK(ValidateBucketRanges());
}
+Histogram::ClassType LinearHistogram::histogram_type() const {
+ return LINEAR_HISTOGRAM;
+}
+
void LinearHistogram::SetRangeDescriptions(
const DescriptionPair descriptions[]) {
for (int i =0; descriptions[i].description; ++i) {
@@ -671,6 +710,17 @@ scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name,
return histogram;
}
+Histogram::ClassType BooleanHistogram::histogram_type() const {
+ return BOOLEAN_HISTOGRAM;
+}
+
+void BooleanHistogram::AddBoolean(bool value) {
+ Add(value ? 1 : 0);
+}
+
+BooleanHistogram::BooleanHistogram(const std::string& name)
+ : LinearHistogram(name, 1, 2, 3) {
+}
//------------------------------------------------------------------------------
// CustomHistogram:
@@ -706,6 +756,10 @@ scoped_refptr<Histogram> CustomHistogram::FactoryGet(
return histogram;
}
+Histogram::ClassType CustomHistogram::histogram_type() const {
+ return CUSTOM_HISTOGRAM;
+}
+
CustomHistogram::CustomHistogram(const std::string& name,
const std::vector<int>& custom_ranges)
: Histogram(name, custom_ranges[1], custom_ranges.back(),
@@ -774,10 +828,9 @@ void StatisticsRecorder::Register(Histogram* histogram) {
return;
const std::string name = histogram->histogram_name();
AutoLock auto_lock(*lock_);
- DCHECK(histograms_->end() == histograms_->find(name));
-
- (*histograms_)[name] = histogram;
- return;
+ // Avoid overwriting a previous registration.
+ if (histograms_->end() == histograms_->find(name))
+ (*histograms_)[name] = histogram;
}
// static
@@ -809,10 +862,12 @@ void StatisticsRecorder::WriteGraph(const std::string& query,
std::string* output) {
if (!histograms_)
return;
- if (query.length())
- StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
- else
+ if (query.length()) {
+ base::StringAppendF(output, "Collections of histograms for %s\n",
+ query.c_str());
+ } else {
output->append("Collections of all histograms\n");
+ }
Histograms snapshot;
GetSnapshot(query, &snapshot);
diff --git a/base/histogram.h b/base/histogram.h
index b745026..0287d37 100644
--- a/base/histogram.h
+++ b/base/histogram.h
@@ -30,6 +30,7 @@
#ifndef BASE_HISTOGRAM_H_
#define BASE_HISTOGRAM_H_
+#pragma once
#include <map>
#include <string>
@@ -221,11 +222,6 @@ class Histogram;
class LinearHistogram;
class Pickle;
-namespace disk_cache {
- class StatsHistogram;
-}; // namespace disk_cache
-
-
class Histogram : public base::RefCountedThreadSafe<Histogram> {
public:
typedef int Sample; // Used for samples (and ranges of samples).
@@ -276,6 +272,8 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
class SampleSet {
public:
explicit SampleSet();
+ ~SampleSet();
+
// Adjust size of counts_ for use with given histogram.
void Resize(const Histogram& histogram);
void CheckSize(const Histogram& histogram) const;
@@ -318,7 +316,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
void Add(int value);
// This method is an interface, used only by BooleanHistogram.
- virtual void AddBoolean(bool value) { DCHECK(false); }
+ virtual void AddBoolean(bool value);
// Accept a TimeDelta to increment.
void AddTime(base::TimeDelta time) {
@@ -328,8 +326,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
void AddSampleSet(const SampleSet& sample);
// This method is an interface, used only by LinearHistogram.
- virtual void SetRangeDescriptions(const DescriptionPair descriptions[])
- { DCHECK(false); }
+ virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
// The following methods provide graphical histogram displays.
void WriteHTMLGraph(std::string* output) const;
@@ -372,17 +369,11 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
virtual void SnapshotSample(SampleSet* sample) const;
virtual bool HasConstructorArguments(Sample minimum, Sample maximum,
- size_t bucket_count) {
- return ((minimum == declared_min_) && (maximum == declared_max_) &&
- (bucket_count == bucket_count_));
- }
+ size_t bucket_count);
virtual bool HasConstructorTimeDeltaArguments(base::TimeDelta minimum,
- base::TimeDelta maximum, size_t bucket_count) {
- return ((minimum.InMilliseconds() == declared_min_) &&
- (maximum.InMilliseconds() == declared_max_) &&
- (bucket_count == bucket_count_));
- }
+ base::TimeDelta maximum,
+ size_t bucket_count);
protected:
friend class base::RefCountedThreadSafe<Histogram>;
@@ -394,7 +385,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
virtual ~Histogram();
// Method to override to skip the display of the i'th bucket if it's empty.
- virtual bool PrintEmptyBucket(size_t index) const { return true; }
+ virtual bool PrintEmptyBucket(size_t index) const;
//----------------------------------------------------------------------------
// Methods to override to create histogram with different bucket widths.
@@ -487,7 +478,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// buckets.
class LinearHistogram : public Histogram {
public:
- virtual ClassType histogram_type() const { return LINEAR_HISTOGRAM; }
+ virtual ClassType histogram_type() const;
// Store a list of number/text values for use in rendering the histogram.
// The last element in the array has a null in its "description" slot.
@@ -501,6 +492,8 @@ class LinearHistogram : public Histogram {
base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count,
Flags flags);
+ virtual ~LinearHistogram();
+
protected:
LinearHistogram(const std::string& name, Sample minimum,
Sample maximum, size_t bucket_count);
@@ -538,14 +531,12 @@ class BooleanHistogram : public LinearHistogram {
static scoped_refptr<Histogram> FactoryGet(const std::string& name,
Flags flags);
- virtual ClassType histogram_type() const { return BOOLEAN_HISTOGRAM; }
+ virtual ClassType histogram_type() const;
- virtual void AddBoolean(bool value) { Add(value ? 1 : 0); }
+ virtual void AddBoolean(bool value);
private:
- explicit BooleanHistogram(const std::string& name)
- : LinearHistogram(name, 1, 2, 3) {
- }
+ explicit BooleanHistogram(const std::string& name);
DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
};
@@ -555,7 +546,7 @@ class BooleanHistogram : public LinearHistogram {
// CustomHistogram is a histogram for a set of custom integers.
class CustomHistogram : public Histogram {
public:
- virtual ClassType histogram_type() const { return CUSTOM_HISTOGRAM; }
+ virtual ClassType histogram_type() const;
static scoped_refptr<Histogram> FactoryGet(const std::string& name,
const std::vector<int>& custom_ranges, Flags flags);
diff --git a/base/histogram_unittest.cc b/base/histogram_unittest.cc
index 56c733b..4637a5f 100644
--- a/base/histogram_unittest.cc
+++ b/base/histogram_unittest.cc
@@ -5,7 +5,6 @@
// Test of Histogram class
#include "base/histogram.h"
-#include "base/string_util.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/hmac.h b/base/hmac.h
index b915124..d467e1a 100644
--- a/base/hmac.h
+++ b/base/hmac.h
@@ -7,6 +7,7 @@
#ifndef BASE_HMAC_H_
#define BASE_HMAC_H_
+#pragma once
#include <string>
diff --git a/base/i18n/file_util_icu.h b/base/i18n/file_util_icu.h
index 54ddb08..a855eb3 100644
--- a/base/i18n/file_util_icu.h
+++ b/base/i18n/file_util_icu.h
@@ -1,16 +1,16 @@
-// 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.
-// File utilities that use the ICU library go in this file.
+#ifndef BASE_I18N_FILE_UTIL_ICU_H_
+#define BASE_I18N_FILE_UTIL_ICU_H_
+#pragma once
-#include <string>
+// File utilities that use the ICU library go in this file.
#include "base/file_path.h"
#include "base/string16.h"
-class FilePath;
-
namespace file_util {
// Returns true if file_name does not have any illegal character. The input
@@ -33,3 +33,5 @@ void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b);
} // namespace file_util
+
+#endif // BASE_I18N_FILE_UTIL_ICU_H_
diff --git a/base/i18n/icu_encoding_detection.h b/base/i18n/icu_encoding_detection.h
index 0d8e5d8..e7e6253 100644
--- a/base/i18n/icu_encoding_detection.h
+++ b/base/i18n/icu_encoding_detection.h
@@ -4,6 +4,7 @@
#ifndef BASE_I18N_ICU_ENCODING_DETECTION_H_
#define BASE_I18N_ICU_ENCODING_DETECTION_H_
+#pragma once
#include <string>
diff --git a/base/i18n/icu_string_conversions.h b/base/i18n/icu_string_conversions.h
index 79d7e02..1495cae 100644
--- a/base/i18n/icu_string_conversions.h
+++ b/base/i18n/icu_string_conversions.h
@@ -4,6 +4,7 @@
#ifndef BASE_I18N_ICU_STRING_CONVERSIONS_H_
#define BASE_I18N_ICU_STRING_CONVERSIONS_H_
+#pragma once
#include <string>
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index 066534c..d378a25 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -29,10 +29,8 @@
#if defined(OS_WIN)
#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_SHARED
-#elif defined(OS_MACOSX)
+#else
#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_STATIC
-#elif defined(OS_POSIX)
-#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_FILE
#endif
#endif // ICU_UTIL_DATA_IMPL
@@ -77,7 +75,7 @@ bool Initialize() {
udata_setCommonData(reinterpret_cast<void*>(addr), &err);
return err == U_ZERO_ERROR;
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
- // Mac bundles the ICU data in.
+ // Mac/Linux bundle the ICU data in.
return true;
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
// For now, expect the data file to be alongside the executable.
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
index 56eaa37..35c2e4f 100644
--- a/base/i18n/icu_util.h
+++ b/base/i18n/icu_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_I18N_ICU_UTIL_H_
#define BASE_I18N_ICU_UTIL_H_
+#pragma once
namespace icu_util {
diff --git a/base/i18n/number_formatting.h b/base/i18n/number_formatting.h
index 9fa2b18..f5ec083 100644
--- a/base/i18n/number_formatting.h
+++ b/base/i18n/number_formatting.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef BASE_I18N_NUMBER_FORMATTING_H_
#define BASE_I18N_NUMBER_FORMATTING_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "base/string16.h"
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
index 6c3d394..f5381a2 100644
--- a/base/i18n/rtl.cc
+++ b/base/i18n/rtl.cc
@@ -269,10 +269,12 @@ void WrapPathWithLTRFormatting(const FilePath& path,
rtl_safe_path->push_back(kPopDirectionalFormatting);
}
-std::wstring GetDisplayStringInLTRDirectionality(std::wstring* text) {
- if (IsRTL())
- WrapStringWithLTRFormatting(text);
- return *text;
+string16 GetDisplayStringInLTRDirectionality(const string16& text) {
+ if (!IsRTL())
+ return text;
+ string16 text_mutable(text);
+ WrapStringWithLTRFormatting(&text_mutable);
+ return text_mutable;
}
const string16 StripWrappingBidiControlCharacters(const string16& text) {
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
index 98a4e35..2fe932c 100644
--- a/base/i18n/rtl.h
+++ b/base/i18n/rtl.h
@@ -4,7 +4,9 @@
#ifndef BASE_I18N_RTL_H_
#define BASE_I18N_RTL_H_
+#pragma once
+#include "base/compiler_specific.h"
#include "base/string16.h"
#include "build/build_config.h"
@@ -134,14 +136,16 @@ void WrapPathWithLTRFormatting(const FilePath& path,
// string is wrapped with LRE (Left-To-Right Embedding) and PDF (Pop
// Directional Formatting) marks and returned. In LTR locale, the string itself
// is returned.
-std::wstring GetDisplayStringInLTRDirectionality(std::wstring* text);
+string16 GetDisplayStringInLTRDirectionality(const string16& text)
+ WARN_UNUSED_RESULT;
// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C)
// explicit bidi control characters from |text|, if there are any. Otherwise,
// return the text itself. Explicit bidi control characters display and have
// semantic effect. They can be deleted so they might not always appear in a
// pair.
-const string16 StripWrappingBidiControlCharacters(const string16& text);
+const string16 StripWrappingBidiControlCharacters(const string16& text)
+ WARN_UNUSED_RESULT;
} // namespace i18n
} // namespace base
diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc
index 62de290..061e140 100644
--- a/base/i18n/rtl_unittest.cc
+++ b/base/i18n/rtl_unittest.cc
@@ -217,13 +217,12 @@ TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) {
{ L"abc\x05d0\x05d1.jpg", L"\x202a"L"abc\x05d0\x05d1.jpg\x202c" },
};
for (unsigned int i = 0; i < arraysize(test_data); ++i) {
- std::wstring input = test_data[i].raw_filename;
- std::wstring expected =
- base::i18n::GetDisplayStringInLTRDirectionality(&input);
+ string16 input = WideToUTF16(test_data[i].raw_filename);
+ string16 expected = base::i18n::GetDisplayStringInLTRDirectionality(input);
if (base::i18n::IsRTL())
- EXPECT_EQ(test_data[i].display_string, expected);
+ EXPECT_EQ(expected, WideToUTF16(test_data[i].display_string));
else
- EXPECT_EQ(input, expected);
+ EXPECT_EQ(expected, input);
}
}
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
index dd623af..d78ae9b 100644
--- a/base/i18n/time_formatting.h
+++ b/base/i18n/time_formatting.h
@@ -7,6 +7,7 @@
#ifndef BASE_I18N_TIME_FORMATTING_H_
#define BASE_I18N_TIME_FORMATTING_H_
+#pragma once
#include <string>
diff --git a/base/i18n/word_iterator.h b/base/i18n/word_iterator.h
index aabafab..b9067c6 100644
--- a/base/i18n/word_iterator.h
+++ b/base/i18n/word_iterator.h
@@ -1,13 +1,14 @@
-// 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.
#ifndef BASE_I18N_WORD_ITERATOR_H_
#define BASE_I18N_WORD_ITERATOR_H_
+#pragma once
-#include <string>
#include <vector>
+#include "unicode/ubrk.h"
#include "unicode/uchar.h"
#include "base/basictypes.h"
@@ -68,7 +69,7 @@ class WordIterator {
private:
// ICU iterator.
- void* iter_;
+ UBreakIterator* iter_;
#if !defined(WCHAR_T_IS_UTF16)
std::vector<UChar> chars_;
#endif
diff --git a/base/iat_patch.h b/base/iat_patch.h
index 47d92ce..c2cbbcb 100644
--- a/base/iat_patch.h
+++ b/base/iat_patch.h
@@ -11,6 +11,7 @@
#ifndef BASE_IAT_PATCH_H__
#define BASE_IAT_PATCH_H__
+#pragma once
#include <windows.h>
#include "base/basictypes.h"
diff --git a/base/id_map.h b/base/id_map.h
index 00ef16a..9a41d74 100644
--- a/base/id_map.h
+++ b/base/id_map.h
@@ -4,6 +4,7 @@
#ifndef BASE_ID_MAP_H_
#define BASE_ID_MAP_H_
+#pragma once
#include <set>
diff --git a/base/image_util.h b/base/image_util.h
index 7e55358..ccdffc3 100644
--- a/base/image_util.h
+++ b/base/image_util.h
@@ -8,6 +8,7 @@
#ifndef BASE_IMAGE_UTIL_H_
#define BASE_IMAGE_UTIL_H_
+#pragma once
#include <windows.h>
#include <vector>
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index cf9ce02..391f58b 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.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,6 +7,7 @@
#include "base/float_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
@@ -19,18 +20,6 @@ static const int kStackLimit = 100;
namespace {
-inline int HexToInt(wchar_t c) {
- if ('0' <= c && c <= '9') {
- return c - '0';
- } else if ('A' <= c && c <= 'F') {
- return c - 'A' + 10;
- } else if ('a' <= c && c <= 'f') {
- return c - 'a' + 10;
- }
- NOTREACHED();
- return 0;
-}
-
// A helper method for ParseNumberToken. It reads an int from the end of
// token. The method returns false if there is no valid integer at the end of
// the token.
@@ -306,7 +295,7 @@ Value* JSONReader::BuildValue(bool is_root) {
return NULL;
// Convert the key into a wstring.
- std::wstring dict_key;
+ std::string dict_key;
bool success = dict_key_value->GetAsString(&dict_key);
DCHECK(success);
@@ -401,11 +390,11 @@ Value* JSONReader::DecodeNumber(const Token& token) {
const std::wstring num_string(token.begin, token.length);
int num_int;
- if (StringToInt(WideToUTF16Hack(num_string), &num_int))
+ if (StringToInt(WideToUTF8(num_string), &num_int))
return Value::CreateIntegerValue(num_int);
double num_double;
- if (StringToDouble(WideToUTF16Hack(num_string), &num_double) &&
+ if (StringToDouble(WideToUTF8(num_string), &num_double) &&
base::IsFinite(num_double))
return Value::CreateRealValue(num_double);
@@ -492,15 +481,15 @@ Value* JSONReader::DecodeString(const Token& token) {
break;
case 'x':
- decoded_str.push_back((HexToInt(*(token.begin + i + 1)) << 4) +
- HexToInt(*(token.begin + i + 2)));
+ decoded_str.push_back((HexDigitToInt(*(token.begin + i + 1)) << 4) +
+ HexDigitToInt(*(token.begin + i + 2)));
i += 2;
break;
case 'u':
- decoded_str.push_back((HexToInt(*(token.begin + i + 1)) << 12 ) +
- (HexToInt(*(token.begin + i + 2)) << 8) +
- (HexToInt(*(token.begin + i + 3)) << 4) +
- HexToInt(*(token.begin + i + 4)));
+ decoded_str.push_back((HexDigitToInt(*(token.begin + i + 1)) << 12 ) +
+ (HexDigitToInt(*(token.begin + i + 2)) << 8) +
+ (HexDigitToInt(*(token.begin + i + 3)) << 4) +
+ HexDigitToInt(*(token.begin + i + 4)));
i += 4;
break;
@@ -515,7 +504,7 @@ Value* JSONReader::DecodeString(const Token& token) {
decoded_str.push_back(c);
}
}
- return Value::CreateStringValue(decoded_str);
+ return Value::CreateStringValue(WideToUTF16Hack(decoded_str));
}
JSONReader::Token JSONReader::ParseToken() {
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index aa0c2a7..33bd8f2 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -30,6 +30,7 @@
#ifndef BASE_JSON_JSON_READER_H_
#define BASE_JSON_JSON_READER_H_
+#pragma once
#include <string>
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
index 71649df..c00c976 100644
--- a/base/json/json_reader_unittest.cc
+++ b/base/json/json_reader_unittest.cc
@@ -1,10 +1,12 @@
-// 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.
#include "testing/gtest/include/gtest/gtest.h"
#include "base/json/json_reader.h"
#include "base/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -168,9 +170,9 @@ TEST(JSONReaderTest, Reading) {
root.reset(JSONReader().JsonToValue("\"hello world\"", false, false));
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_STRING));
- std::wstring str_val;
+ std::string str_val;
ASSERT_TRUE(root->GetAsString(&str_val));
- ASSERT_EQ(L"hello world", str_val);
+ ASSERT_EQ("hello world", str_val);
// Empty string
root.reset(JSONReader().JsonToValue("\"\"", false, false));
@@ -178,7 +180,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root->IsType(Value::TYPE_STRING));
str_val.clear();
ASSERT_TRUE(root->GetAsString(&str_val));
- ASSERT_EQ(L"", str_val);
+ ASSERT_EQ("", str_val);
// Test basic string escapes
root.reset(JSONReader().JsonToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"",
@@ -187,7 +189,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root->IsType(Value::TYPE_STRING));
str_val.clear();
ASSERT_TRUE(root->GetAsString(&str_val));
- ASSERT_EQ(L" \"\\/\b\f\n\r\t\v", str_val);
+ ASSERT_EQ(" \"\\/\b\f\n\r\t\v", str_val);
// Test hex and unicode escapes including the null character.
root.reset(JSONReader().JsonToValue("\"\\x41\\x00\\u1234\"", false,
@@ -196,7 +198,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root->IsType(Value::TYPE_STRING));
str_val.clear();
ASSERT_TRUE(root->GetAsString(&str_val));
- ASSERT_EQ(std::wstring(L"A\0\x1234", 3), str_val);
+ ASSERT_EQ(std::wstring(L"A\0\x1234", 3), UTF8ToWide(str_val));
// Test invalid strings
root.reset(JSONReader().JsonToValue("\"no closing quote", false, false));
@@ -302,14 +304,14 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get());
real_val = 0.0;
- ASSERT_TRUE(dict_val->GetReal(L"number", &real_val));
+ ASSERT_TRUE(dict_val->GetReal("number", &real_val));
ASSERT_DOUBLE_EQ(9.87654321, real_val);
Value* null_val = NULL;
- ASSERT_TRUE(dict_val->Get(L"null", &null_val));
+ ASSERT_TRUE(dict_val->Get("null", &null_val));
ASSERT_TRUE(null_val->IsType(Value::TYPE_NULL));
str_val.clear();
- ASSERT_TRUE(dict_val->GetString(L"S", &str_val));
- ASSERT_EQ(L"str", str_val);
+ ASSERT_TRUE(dict_val->GetString("S", &str_val));
+ ASSERT_EQ("str", str_val);
root2.reset(JSONReader::Read(
"{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", true));
@@ -342,15 +344,15 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
dict_val = static_cast<DictionaryValue*>(root.get());
DictionaryValue* inner_dict = NULL;
- ASSERT_TRUE(dict_val->GetDictionary(L"inner", &inner_dict));
+ ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict));
ListValue* inner_array = NULL;
- ASSERT_TRUE(inner_dict->GetList(L"array", &inner_array));
+ ASSERT_TRUE(inner_dict->GetList("array", &inner_array));
ASSERT_EQ(1U, inner_array->GetSize());
bool_value = true;
- ASSERT_TRUE(dict_val->GetBoolean(L"false", &bool_value));
+ ASSERT_TRUE(dict_val->GetBoolean("false", &bool_value));
ASSERT_FALSE(bool_value);
inner_dict = NULL;
- ASSERT_TRUE(dict_val->GetDictionary(L"d", &inner_dict));
+ ASSERT_TRUE(dict_val->GetDictionary("d", &inner_dict));
root2.reset(JSONReader::Read(
"{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", true));
@@ -363,15 +365,15 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
dict_val = static_cast<DictionaryValue*>(root.get());
int integer_value = 0;
- EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion(L"a.b", &integer_value));
+ EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
EXPECT_EQ(3, integer_value);
- EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion(L"c", &integer_value));
+ EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value));
EXPECT_EQ(2, integer_value);
inner_dict = NULL;
- ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion(L"d.e.f",
+ ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion("d.e.f",
&inner_dict));
ASSERT_EQ(1U, inner_dict->size());
- EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion(L"g.h.i.j",
+ EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j",
&integer_value));
EXPECT_EQ(1, integer_value);
@@ -379,9 +381,9 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
dict_val = static_cast<DictionaryValue*>(root.get());
- EXPECT_TRUE(dict_val->GetInteger(L"a.b", &integer_value));
+ EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value));
EXPECT_EQ(2, integer_value);
- EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion(L"a.b", &integer_value));
+ EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
EXPECT_EQ(1, integer_value);
// Invalid, no closing brace
@@ -444,7 +446,7 @@ TEST(JSONReaderTest, Reading) {
ASSERT_TRUE(root->IsType(Value::TYPE_STRING));
str_val.clear();
ASSERT_TRUE(root->GetAsString(&str_val));
- ASSERT_EQ(L"\x7f51\x9875", str_val);
+ ASSERT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val));
// Test invalid utf8 encoded input
root.reset(JSONReader().JsonToValue("\"345\xb0\xa1\xb0\xa2\"",
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index ffdad76..dbf43ec 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.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,6 +7,7 @@
#include "base/json/string_escape.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "base/utf_string_conversions.h"
@@ -187,8 +188,10 @@ void JSONWriter::BuildJSONString(const Value* const node,
}
}
-void JSONWriter::AppendQuotedString(const std::wstring& str) {
- JsonDoubleQuote(WideToUTF16Hack(str), true, json_string_);
+void JSONWriter::AppendQuotedString(const std::string& str) {
+ // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we
+ // have to convert it to UTF-16. This round-trip is suboptimal.
+ JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_);
}
void JSONWriter::IndentLine(int depth) {
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
index 0ebee0a..eb17145 100644
--- a/base/json/json_writer.h
+++ b/base/json/json_writer.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef BASE_JSON_JSON_WRITER_H_
#define BASE_JSON_JSON_WRITER_H_
+#pragma once
#include <string>
@@ -44,8 +45,8 @@ class JSONWriter {
// json_string_ will contain the JSON.
void BuildJSONString(const Value* const node, int depth, bool escape);
- // Appends a quoted, escaped, version of str to json_string_.
- void AppendQuotedString(const std::wstring& str);
+ // Appends a quoted, escaped, version of (UTF-8) str to json_string_.
+ void AppendQuotedString(const std::string& str);
// Adds space to json_string_ for the indent level.
void IndentLine(int depth);
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
index e7d0f05..937d083 100644
--- a/base/json/json_writer_unittest.cc
+++ b/base/json/json_writer_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.
@@ -50,10 +50,10 @@ TEST(JSONWriterTest, Writing) {
// list list nesting, etc.
DictionaryValue root_dict;
ListValue* list = new ListValue;
- root_dict.Set(L"list", list);
+ root_dict.Set("list", list);
DictionaryValue* inner_dict = new DictionaryValue;
list->Append(inner_dict);
- inner_dict->SetInteger(L"inner int", 10);
+ inner_dict->SetInteger("inner int", 10);
ListValue* inner_list = new ListValue;
list->Append(inner_list);
list->Append(Value::CreateBooleanValue(true));
@@ -79,18 +79,18 @@ TEST(JSONWriterTest, Writing) {
// Test keys with periods
DictionaryValue period_dict;
- period_dict.SetWithoutPathExpansion(L"a.b", Value::CreateIntegerValue(3));
- period_dict.SetWithoutPathExpansion(L"c", Value::CreateIntegerValue(2));
+ period_dict.SetWithoutPathExpansion("a.b", Value::CreateIntegerValue(3));
+ period_dict.SetWithoutPathExpansion("c", Value::CreateIntegerValue(2));
DictionaryValue* period_dict2 = new DictionaryValue;
- period_dict2->SetWithoutPathExpansion(L"g.h.i.j",
+ period_dict2->SetWithoutPathExpansion("g.h.i.j",
Value::CreateIntegerValue(1));
- period_dict.SetWithoutPathExpansion(L"d.e.f", period_dict2);
+ period_dict.SetWithoutPathExpansion("d.e.f", period_dict2);
JSONWriter::Write(&period_dict, false, &output_js);
ASSERT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
DictionaryValue period_dict3;
- period_dict3.Set(L"a.b", Value::CreateIntegerValue(2));
- period_dict3.SetWithoutPathExpansion(L"a.b", Value::CreateIntegerValue(1));
+ period_dict3.Set("a.b", Value::CreateIntegerValue(2));
+ period_dict3.SetWithoutPathExpansion("a.b", Value::CreateIntegerValue(1));
JSONWriter::Write(&period_dict3, false, &output_js);
ASSERT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
}
diff --git a/base/json/string_escape.h b/base/json/string_escape.h
index 7c64c29..2d7206b 100644
--- a/base/json/string_escape.h
+++ b/base/json/string_escape.h
@@ -6,6 +6,7 @@
#ifndef BASE_JSON_STRING_ESCAPE_H_
#define BASE_JSON_STRING_ESCAPE_H_
+#pragma once
#include <string>
diff --git a/base/keyboard_code_conversion_gtk.cc b/base/keyboard_code_conversion_gtk.cc
deleted file mode 100644
index 91de891..0000000
--- a/base/keyboard_code_conversion_gtk.cc
+++ /dev/null
@@ -1,620 +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.
-
-/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
- * Copyright (C) 2008, 2009 Google Inc.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// WindowsKeyCodeForGdkKeyCode is copied from platform/gtk/KeyEventGtk.cpp
-
-#ifndef BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
-#define BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
-
-#include "base/keyboard_code_conversion_gtk.h"
-
-#include <gdk/gdkkeysyms.h>
-
-#include "base/keyboard_codes_posix.h"
-
-namespace base {
-
-base::KeyboardCode WindowsKeyCodeForGdkKeyCode(int keycode) {
- switch (keycode) {
- case GDK_KP_0:
- return VKEY_NUMPAD0; // (60) Numeric keypad 0 key
- case GDK_KP_1:
- return VKEY_NUMPAD1; // (61) Numeric keypad 1 key
- case GDK_KP_2:
- return VKEY_NUMPAD2; // (62) Numeric keypad 2 key
- case GDK_KP_3:
- return VKEY_NUMPAD3; // (63) Numeric keypad 3 key
- case GDK_KP_4:
- return VKEY_NUMPAD4; // (64) Numeric keypad 4 key
- case GDK_KP_5:
- return VKEY_NUMPAD5; // (65) Numeric keypad 5 key
- case GDK_KP_6:
- return VKEY_NUMPAD6; // (66) Numeric keypad 6 key
- case GDK_KP_7:
- return VKEY_NUMPAD7; // (67) Numeric keypad 7 key
- case GDK_KP_8:
- return VKEY_NUMPAD8; // (68) Numeric keypad 8 key
- case GDK_KP_9:
- return VKEY_NUMPAD9; // (69) Numeric keypad 9 key
- case GDK_KP_Multiply:
- return VKEY_MULTIPLY; // (6A) Multiply key
- case GDK_KP_Add:
- return VKEY_ADD; // (6B) Add key
- case GDK_KP_Subtract:
- return VKEY_SUBTRACT; // (6D) Subtract key
- case GDK_KP_Decimal:
- return VKEY_DECIMAL; // (6E) Decimal key
- case GDK_KP_Divide:
- return VKEY_DIVIDE; // (6F) Divide key
-
- case GDK_BackSpace:
- return VKEY_BACK; // (08) BACKSPACE key
- case GDK_ISO_Left_Tab:
- case GDK_3270_BackTab:
- case GDK_Tab:
- return VKEY_TAB; // (09) TAB key
- case GDK_Clear:
- return VKEY_CLEAR; // (0C) CLEAR key
- case GDK_ISO_Enter:
- case GDK_KP_Enter:
- case GDK_Return:
- return VKEY_RETURN; // (0D) Return key
- case GDK_Shift_L:
- case GDK_Shift_R:
- return VKEY_SHIFT; // (10) SHIFT key
- case GDK_Control_L:
- case GDK_Control_R:
- return VKEY_CONTROL; // (11) CTRL key
- case GDK_Menu:
- case GDK_Alt_L:
- case GDK_Alt_R:
- return VKEY_MENU; // (12) ALT key
-
- case GDK_Pause:
- return VKEY_PAUSE; // (13) PAUSE key
- case GDK_Caps_Lock:
- return VKEY_CAPITAL; // (14) CAPS LOCK key
- case GDK_Kana_Lock:
- case GDK_Kana_Shift:
- return VKEY_KANA; // (15) Input Method Editor (IME) Kana mode
- case GDK_Hangul:
- return VKEY_HANGUL; // VKEY_HANGUL (15) IME Hangul mode
- // VKEY_JUNJA (17) IME Junja mode
- // VKEY_FINAL (18) IME final mode
- case GDK_Hangul_Hanja:
- return VKEY_HANJA; // (19) IME Hanja mode
- case GDK_Kanji:
- return VKEY_KANJI; // (19) IME Kanji mode
- case GDK_Escape:
- return VKEY_ESCAPE; // (1B) ESC key
- // VKEY_CONVERT (1C) IME convert
- // VKEY_NONCONVERT (1D) IME nonconvert
- // VKEY_ACCEPT (1E) IME accept
- // VKEY_MODECHANGE (1F) IME mode change request
- case GDK_space:
- return VKEY_SPACE; // (20) SPACEBAR
- case GDK_Page_Up:
- return VKEY_PRIOR; // (21) PAGE UP key
- case GDK_Page_Down:
- return VKEY_NEXT; // (22) PAGE DOWN key
- case GDK_End:
- return VKEY_END; // (23) END key
- case GDK_Home:
- return VKEY_HOME; // (24) HOME key
- case GDK_Left:
- return VKEY_LEFT; // (25) LEFT ARROW key
- case GDK_Up:
- return VKEY_UP; // (26) UP ARROW key
- case GDK_Right:
- return VKEY_RIGHT; // (27) RIGHT ARROW key
- case GDK_Down:
- return VKEY_DOWN; // (28) DOWN ARROW key
- case GDK_Select:
- return VKEY_SELECT; // (29) SELECT key
- case GDK_Print:
- return VKEY_PRINT; // (2A) PRINT key
- case GDK_Execute:
- return VKEY_EXECUTE; // (2B) EXECUTE key
- // dunno on this
- // case GDK_PrintScreen:
- // return VKEY_SNAPSHOT; // (2C) PRINT SCREEN key
- case GDK_Insert:
- return VKEY_INSERT; // (2D) INS key
- case GDK_Delete:
- return VKEY_DELETE; // (2E) DEL key
- case GDK_Help:
- return VKEY_HELP; // (2F) HELP key
- case GDK_0:
- case GDK_parenright:
- return VKEY_0; // (30) 0) key
- case GDK_1:
- case GDK_exclam:
- return VKEY_1; // (31) 1 ! key
- case GDK_2:
- case GDK_at:
- return VKEY_2; // (32) 2 & key
- case GDK_3:
- case GDK_numbersign:
- return VKEY_3; // case '3': case '#';
- case GDK_4:
- case GDK_dollar: // (34) 4 key '$';
- return VKEY_4;
- case GDK_5:
- case GDK_percent:
- return VKEY_5; // (35) 5 key '%'
- case GDK_6:
- case GDK_asciicircum:
- return VKEY_6; // (36) 6 key '^'
- case GDK_7:
- case GDK_ampersand:
- return VKEY_7; // (37) 7 key case '&'
- case GDK_8:
- case GDK_asterisk:
- return VKEY_8; // (38) 8 key '*'
- case GDK_9:
- case GDK_parenleft:
- return VKEY_9; // (39) 9 key '('
- case GDK_a:
- case GDK_A:
- return VKEY_A; // (41) A key case 'a': case 'A': return 0x41;
- case GDK_b:
- case GDK_B:
- return VKEY_B; // (42) B key case 'b': case 'B': return 0x42;
- case GDK_c:
- case GDK_C:
- return VKEY_C; // (43) C key case 'c': case 'C': return 0x43;
- case GDK_d:
- case GDK_D:
- return VKEY_D; // (44) D key case 'd': case 'D': return 0x44;
- case GDK_e:
- case GDK_E:
- return VKEY_E; // (45) E key case 'e': case 'E': return 0x45;
- case GDK_f:
- case GDK_F:
- return VKEY_F; // (46) F key case 'f': case 'F': return 0x46;
- case GDK_g:
- case GDK_G:
- return VKEY_G; // (47) G key case 'g': case 'G': return 0x47;
- case GDK_h:
- case GDK_H:
- return VKEY_H; // (48) H key case 'h': case 'H': return 0x48;
- case GDK_i:
- case GDK_I:
- return VKEY_I; // (49) I key case 'i': case 'I': return 0x49;
- case GDK_j:
- case GDK_J:
- return VKEY_J; // (4A) J key case 'j': case 'J': return 0x4A;
- case GDK_k:
- case GDK_K:
- return VKEY_K; // (4B) K key case 'k': case 'K': return 0x4B;
- case GDK_l:
- case GDK_L:
- return VKEY_L; // (4C) L key case 'l': case 'L': return 0x4C;
- case GDK_m:
- case GDK_M:
- return VKEY_M; // (4D) M key case 'm': case 'M': return 0x4D;
- case GDK_n:
- case GDK_N:
- return VKEY_N; // (4E) N key case 'n': case 'N': return 0x4E;
- case GDK_o:
- case GDK_O:
- return VKEY_O; // (4F) O key case 'o': case 'O': return 0x4F;
- case GDK_p:
- case GDK_P:
- return VKEY_P; // (50) P key case 'p': case 'P': return 0x50;
- case GDK_q:
- case GDK_Q:
- return VKEY_Q; // (51) Q key case 'q': case 'Q': return 0x51;
- case GDK_r:
- case GDK_R:
- return VKEY_R; // (52) R key case 'r': case 'R': return 0x52;
- case GDK_s:
- case GDK_S:
- return VKEY_S; // (53) S key case 's': case 'S': return 0x53;
- case GDK_t:
- case GDK_T:
- return VKEY_T; // (54) T key case 't': case 'T': return 0x54;
- case GDK_u:
- case GDK_U:
- return VKEY_U; // (55) U key case 'u': case 'U': return 0x55;
- case GDK_v:
- case GDK_V:
- return VKEY_V; // (56) V key case 'v': case 'V': return 0x56;
- case GDK_w:
- case GDK_W:
- return VKEY_W; // (57) W key case 'w': case 'W': return 0x57;
- case GDK_x:
- case GDK_X:
- return VKEY_X; // (58) X key case 'x': case 'X': return 0x58;
- case GDK_y:
- case GDK_Y:
- return VKEY_Y; // (59) Y key case 'y': case 'Y': return 0x59;
- case GDK_z:
- case GDK_Z:
- return VKEY_Z; // (5A) Z key case 'z': case 'Z': return 0x5A;
- case GDK_Meta_L:
- case GDK_Super_L:
- return VKEY_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard)
- case GDK_Meta_R:
- case GDK_Super_R:
- return VKEY_RWIN; // (5C) Right Windows key (Natural keyboard)
- // VKEY_APPS (5D) Applications key (Natural keyboard)
- // VKEY_SLEEP (5F) Computer Sleep key
- // VKEY_SEPARATOR (6C) Separator key
- // VKEY_SUBTRACT (6D) Subtract key
- // VKEY_DECIMAL (6E) Decimal key
- // VKEY_DIVIDE (6F) Divide key
- // handled by key code above
-
- case GDK_Num_Lock:
- return VKEY_NUMLOCK; // (90) NUM LOCK key
-
- case GDK_Scroll_Lock:
- return VKEY_SCROLL; // (91) SCROLL LOCK key
-
- // VKEY_LSHIFT (A0) Left SHIFT key
- // VKEY_RSHIFT (A1) Right SHIFT key
- // VKEY_LCONTROL (A2) Left CONTROL key
- // VKEY_RCONTROL (A3) Right CONTROL key
- // VKEY_LMENU (A4) Left MENU key
- // VKEY_RMENU (A5) Right MENU key
- // VKEY_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key
- // VKEY_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key
- // VKEY_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key
- // VKEY_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key
- // VKEY_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key
- // VKEY_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key
- // VKEY_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key
- // VKEY_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key
- // VKEY_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key
- // VKEY_VOLUME_UP (AF) Windows 2000/XP: Volume Up key
- // VKEY_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key
- // VKEY_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key
- // VKEY_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key
- // VKEY_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key
- // VKEY_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key
- // VKEY_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key
- // VKEY_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key
- // VKEY_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key
-
- // VKEY_OEM_1 (BA) Used for miscellaneous characters; it can vary by
- // keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key
- case GDK_semicolon:
- case GDK_colon:
- return VKEY_OEM_1; // case ';': case ':': return 0xBA;
- // VKEY_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key
- case GDK_plus:
- case GDK_equal:
- return VKEY_OEM_PLUS; // case '=': case '+': return 0xBB;
- // VKEY_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ','
- // key
- case GDK_comma:
- case GDK_less:
- return VKEY_OEM_COMMA; // case ',': case '<': return 0xBC;
- // VKEY_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-'
- // key
- case GDK_minus:
- case GDK_underscore:
- return VKEY_OEM_MINUS; // case '-': case '_': return 0xBD;
- // VKEY_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.'
- // key
- case GDK_period:
- case GDK_greater:
- return VKEY_OEM_PERIOD; // case '.': case '>': return 0xBE;
- // VKEY_OEM_2 (BF) Used for miscellaneous characters; it can vary by
- // keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key
- case GDK_slash:
- case GDK_question:
- return VKEY_OEM_2; // case '/': case '?': return 0xBF;
- // VKEY_OEM_3 (C0) Used for miscellaneous characters; it can vary by
- // keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key
- case GDK_asciitilde:
- case GDK_quoteleft:
- return VKEY_OEM_3; // case '`': case '~': return 0xC0;
- // VKEY_OEM_4 (DB) Used for miscellaneous characters; it can vary by
- // keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key
- case GDK_bracketleft:
- case GDK_braceleft:
- return VKEY_OEM_4; // case '[': case '{': return 0xDB;
- // VKEY_OEM_5 (DC) Used for miscellaneous characters; it can vary by
- // keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key
- case GDK_backslash:
- case GDK_bar:
- return VKEY_OEM_5; // case '\\': case '|': return 0xDC;
- // VKEY_OEM_6 (DD) Used for miscellaneous characters; it can vary by
- // keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key
- case GDK_bracketright:
- case GDK_braceright:
- return VKEY_OEM_6; // case ']': case '}': return 0xDD;
- // VKEY_OEM_7 (DE) Used for miscellaneous characters; it can vary by
- // keyboard. Windows 2000/XP: For the US standard keyboard, the
- // 'single-quote/double-quote' key
- case GDK_quoteright:
- case GDK_quotedbl:
- return VKEY_OEM_7; // case '\'': case '"': return 0xDE;
- // VKEY_OEM_8 (DF) Used for miscellaneous characters; it can vary by
- // keyboard.
- // VKEY_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the
- // backslash key on the RT 102-key keyboard
- // VKEY_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP:
- // IME PROCESS key
- // VKEY_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if
- // they were keystrokes. The VKEY_PACKET key is the low word of a 32-bit
- // Virtual Key value used for non-keyboard input methods. For more
- // information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and
- // WM_KEYUP
- // VKEY_ATTN (F6) Attn key
- // VKEY_CRSEL (F7) CrSel key
- // VKEY_EXSEL (F8) ExSel key
- // VKEY_EREOF (F9) Erase EOF key
- // VKEY_PLAY (FA) Play key
- // VKEY_ZOOM (FB) Zoom key
- // VKEY_NONAME (FC) Reserved for future use
- // VKEY_PA1 (FD) PA1 key
- // VKEY_OEM_CLEAR (FE) Clear key
- case GDK_F1:
- case GDK_F2:
- case GDK_F3:
- case GDK_F4:
- case GDK_F5:
- case GDK_F6:
- case GDK_F7:
- case GDK_F8:
- case GDK_F9:
- case GDK_F10:
- case GDK_F11:
- case GDK_F12:
- case GDK_F13:
- case GDK_F14:
- case GDK_F15:
- case GDK_F16:
- case GDK_F17:
- case GDK_F18:
- case GDK_F19:
- case GDK_F20:
- case GDK_F21:
- case GDK_F22:
- case GDK_F23:
- case GDK_F24:
- return static_cast<base::KeyboardCode>(VKEY_F1 + (keycode - GDK_F1));
- default:
- return VKEY_UNKNOWN;
- }
-}
-
-// TODO(jcampan): this method might be incomplete.
-int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode, bool shift) {
- switch (keycode) {
- case VKEY_NUMPAD0:
- return GDK_KP_0;
- case VKEY_NUMPAD1:
- return GDK_KP_1;
- case VKEY_NUMPAD2:
- return GDK_KP_2;
- case VKEY_NUMPAD3:
- return GDK_KP_3;
- case VKEY_NUMPAD4:
- return GDK_KP_4;
- case VKEY_NUMPAD5:
- return GDK_KP_5;
- case VKEY_NUMPAD6:
- return GDK_KP_6;
- case VKEY_NUMPAD7:
- return GDK_KP_7;
- case VKEY_NUMPAD8:
- return GDK_KP_8;
- case VKEY_NUMPAD9:
- return GDK_KP_9;
- case VKEY_MULTIPLY:
- return GDK_KP_Multiply;
- case VKEY_ADD:
- return GDK_KP_Add;
- case VKEY_SUBTRACT:
- return GDK_KP_Subtract;
- case VKEY_DECIMAL:
- return GDK_KP_Decimal;
- case VKEY_DIVIDE:
- return GDK_KP_Divide;
-
- case VKEY_BACK:
- return GDK_BackSpace;
- case VKEY_TAB:
- return shift ? GDK_ISO_Left_Tab : GDK_Tab;
- case VKEY_CLEAR:
- return GDK_Clear;
- case VKEY_RETURN:
- return GDK_Return;
- case VKEY_SHIFT:
- return GDK_Shift_L;
- case VKEY_CONTROL:
- return GDK_Control_L;
- case VKEY_MENU:
- return GDK_Menu;
-
- case VKEY_PAUSE:
- return GDK_Pause;
- case VKEY_CAPITAL:
- return GDK_Caps_Lock;
- case VKEY_KANA:
- return GDK_Kana_Lock;
- case VKEY_HANJA:
- return GDK_Hangul_Hanja;
- case VKEY_ESCAPE:
- return GDK_Escape;
- case VKEY_SPACE:
- return GDK_space;
- case VKEY_PRIOR:
- return GDK_Page_Up;
- case VKEY_NEXT:
- return GDK_Page_Down;
- case VKEY_END:
- return GDK_End;
- case VKEY_HOME:
- return GDK_Home;
- case VKEY_LEFT:
- return GDK_Left;
- case VKEY_UP:
- return GDK_Up;
- case VKEY_RIGHT:
- return GDK_Right;
- case VKEY_DOWN:
- return GDK_Down;
- case VKEY_SELECT:
- return GDK_Select;
- case VKEY_PRINT:
- return GDK_Print;
- case VKEY_EXECUTE:
- return GDK_Execute;
- case VKEY_INSERT:
- return GDK_Insert;
- case VKEY_DELETE:
- return GDK_Delete;
- case VKEY_HELP:
- return GDK_Help;
- case VKEY_0:
- return shift ? GDK_parenright : GDK_0;
- case VKEY_1:
- return shift ? GDK_exclam : GDK_1;
- case VKEY_2:
- return shift ? GDK_at : GDK_2;
- case VKEY_3:
- return shift ? GDK_numbersign : GDK_3;
- case VKEY_4:
- return shift ? GDK_dollar : GDK_4;
- case VKEY_5:
- return shift ? GDK_percent : GDK_5;
- case VKEY_6:
- return shift ? GDK_asciicircum : GDK_6;
- case VKEY_7:
- return shift ? GDK_ampersand : GDK_7;
- case VKEY_8:
- return shift ? GDK_asterisk : GDK_8;
- case VKEY_9:
- return shift ? GDK_parenleft : GDK_9;
-
- case VKEY_A:
- case VKEY_B:
- case VKEY_C:
- case VKEY_D:
- case VKEY_E:
- case VKEY_F:
- case VKEY_G:
- case VKEY_H:
- case VKEY_I:
- case VKEY_J:
- case VKEY_K:
- case VKEY_L:
- case VKEY_M:
- case VKEY_N:
- case VKEY_O:
- case VKEY_P:
- case VKEY_Q:
- case VKEY_R:
- case VKEY_S:
- case VKEY_T:
- case VKEY_U:
- case VKEY_V:
- case VKEY_W:
- case VKEY_X:
- case VKEY_Y:
- case VKEY_Z:
- return (shift ? GDK_A : GDK_a) + (keycode - VKEY_A);
-
- case VKEY_LWIN:
- return GDK_Meta_L;
- case VKEY_RWIN:
- return GDK_Meta_R;
-
- case VKEY_NUMLOCK:
- return GDK_Num_Lock;
-
- case VKEY_SCROLL:
- return GDK_Scroll_Lock;
-
- case VKEY_OEM_1:
- return shift ? GDK_colon : GDK_semicolon;
- case VKEY_OEM_PLUS:
- return shift ? GDK_plus : GDK_equal;
- case VKEY_OEM_COMMA:
- return shift ? GDK_less : GDK_comma;
- case VKEY_OEM_MINUS:
- return shift ? GDK_underscore : GDK_minus;
- case VKEY_OEM_PERIOD:
- return shift ? GDK_greater : GDK_period;
- case VKEY_OEM_2:
- return shift ? GDK_question : GDK_slash;
- case VKEY_OEM_3:
- return shift ? GDK_asciitilde : GDK_quoteleft;
- case VKEY_OEM_4:
- return shift ? GDK_braceleft : GDK_bracketleft;
- case VKEY_OEM_5:
- return shift ? GDK_bar : GDK_backslash;
- case VKEY_OEM_6:
- return shift ? GDK_braceright : GDK_bracketright;
- case VKEY_OEM_7:
- return shift ? GDK_quotedbl : GDK_quoteright;
-
- case VKEY_F1:
- case VKEY_F2:
- case VKEY_F3:
- case VKEY_F4:
- case VKEY_F5:
- case VKEY_F6:
- case VKEY_F7:
- case VKEY_F8:
- case VKEY_F9:
- case VKEY_F10:
- case VKEY_F11:
- case VKEY_F12:
- case VKEY_F13:
- case VKEY_F14:
- case VKEY_F15:
- case VKEY_F16:
- case VKEY_F17:
- case VKEY_F18:
- case VKEY_F19:
- case VKEY_F20:
- case VKEY_F21:
- case VKEY_F22:
- case VKEY_F23:
- case VKEY_F24:
- return GDK_F1 + (keycode - VKEY_F1);
-
- default:
- return 0;
- }
-}
-
-} // namespace
-
-#endif // BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
diff --git a/base/keyboard_code_conversion_gtk.h b/base/keyboard_code_conversion_gtk.h
deleted file mode 100644
index 2ad6b12..0000000
--- a/base/keyboard_code_conversion_gtk.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.
-
-/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
- * Copyright (C) 2008, 2009 Google Inc.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// WindowsKeyCodeForGdkKeyCode is copied from platform/gtk/KeyEventGtk.cpp
-
-#ifndef BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
-#define BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
-
-#include "base/keyboard_codes_posix.h"
-
-namespace base {
-
-base::KeyboardCode WindowsKeyCodeForGdkKeyCode(int keycode);
-
-int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode, bool shift);
-
-} // namespace
-
-#endif // BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
diff --git a/base/keyboard_codes.h b/base/keyboard_codes.h
deleted file mode 100644
index 9a7f968..0000000
--- a/base/keyboard_codes.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.
-
-#ifndef BASE_KEYBOARD_CODES_H_
-#define BASE_KEYBOARD_CODES_H_
-
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include "base/keyboard_codes_win.h"
-#elif defined(USE_X11) || defined(OS_MACOSX)
-#include "base/keyboard_codes_posix.h"
-#endif
-
-#endif // BASE_KEYBOARD_CODES_H_
diff --git a/base/keyboard_codes_posix.h b/base/keyboard_codes_posix.h
deleted file mode 100644
index 9d870aa..0000000
--- a/base/keyboard_codes_posix.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.
-
-/*
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com. All rights reserved.
- * Copyright (C) 2008, 2009 Google Inc.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR
- * PROFITS, OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BASE_KEYBOARD_CODES_POSIX_H_
-#define BASE_KEYBOARD_CODES_POSIX_H_
-
-namespace base {
-
-typedef enum {
- VKEY_BACK = 0x08,
- VKEY_TAB = 0x09,
- VKEY_CLEAR = 0x0C,
- VKEY_RETURN = 0x0D,
- VKEY_SHIFT = 0x10,
- VKEY_CONTROL = 0x11,
- VKEY_MENU = 0x12,
- VKEY_PAUSE = 0x13,
- VKEY_CAPITAL = 0x14,
- VKEY_KANA = 0x15,
- VKEY_HANGUL = 0x15,
- VKEY_JUNJA = 0x17,
- VKEY_FINAL = 0x18,
- VKEY_HANJA = 0x19,
- VKEY_KANJI = 0x19,
- VKEY_ESCAPE = 0x1B,
- VKEY_CONVERT = 0x1C,
- VKEY_NONCONVERT = 0x1D,
- VKEY_ACCEPT = 0x1E,
- VKEY_MODECHANGE = 0x1F,
- VKEY_SPACE = 0x20,
- VKEY_PRIOR = 0x21,
- VKEY_NEXT = 0x22,
- VKEY_END = 0x23,
- VKEY_HOME = 0x24,
- VKEY_LEFT = 0x25,
- VKEY_UP = 0x26,
- VKEY_RIGHT = 0x27,
- VKEY_DOWN = 0x28,
- VKEY_SELECT = 0x29,
- VKEY_PRINT = 0x2A,
- VKEY_EXECUTE = 0x2B,
- VKEY_SNAPSHOT = 0x2C,
- VKEY_INSERT = 0x2D,
- VKEY_DELETE = 0x2E,
- VKEY_HELP = 0x2F,
- VKEY_0 = 0x30,
- VKEY_1 = 0x31,
- VKEY_2 = 0x32,
- VKEY_3 = 0x33,
- VKEY_4 = 0x34,
- VKEY_5 = 0x35,
- VKEY_6 = 0x36,
- VKEY_7 = 0x37,
- VKEY_8 = 0x38,
- VKEY_9 = 0x39,
- VKEY_A = 0x41,
- VKEY_B = 0x42,
- VKEY_C = 0x43,
- VKEY_D = 0x44,
- VKEY_E = 0x45,
- VKEY_F = 0x46,
- VKEY_G = 0x47,
- VKEY_H = 0x48,
- VKEY_I = 0x49,
- VKEY_J = 0x4A,
- VKEY_K = 0x4B,
- VKEY_L = 0x4C,
- VKEY_M = 0x4D,
- VKEY_N = 0x4E,
- VKEY_O = 0x4F,
- VKEY_P = 0x50,
- VKEY_Q = 0x51,
- VKEY_R = 0x52,
- VKEY_S = 0x53,
- VKEY_T = 0x54,
- VKEY_U = 0x55,
- VKEY_V = 0x56,
- VKEY_W = 0x57,
- VKEY_X = 0x58,
- VKEY_Y = 0x59,
- VKEY_Z = 0x5A,
- VKEY_LWIN = 0x5B,
- VKEY_COMMAND = VKEY_LWIN, // Provide the Mac name for convenience.
- VKEY_RWIN = 0x5C,
- VKEY_APPS = 0x5D,
- VKEY_SLEEP = 0x5F,
- VKEY_NUMPAD0 = 0x60,
- VKEY_NUMPAD1 = 0x61,
- VKEY_NUMPAD2 = 0x62,
- VKEY_NUMPAD3 = 0x63,
- VKEY_NUMPAD4 = 0x64,
- VKEY_NUMPAD5 = 0x65,
- VKEY_NUMPAD6 = 0x66,
- VKEY_NUMPAD7 = 0x67,
- VKEY_NUMPAD8 = 0x68,
- VKEY_NUMPAD9 = 0x69,
- VKEY_MULTIPLY = 0x6A,
- VKEY_ADD = 0x6B,
- VKEY_SEPARATOR = 0x6C,
- VKEY_SUBTRACT = 0x6D,
- VKEY_DECIMAL = 0x6E,
- VKEY_DIVIDE = 0x6F,
- VKEY_F1 = 0x70,
- VKEY_F2 = 0x71,
- VKEY_F3 = 0x72,
- VKEY_F4 = 0x73,
- VKEY_F5 = 0x74,
- VKEY_F6 = 0x75,
- VKEY_F7 = 0x76,
- VKEY_F8 = 0x77,
- VKEY_F9 = 0x78,
- VKEY_F10 = 0x79,
- VKEY_F11 = 0x7A,
- VKEY_F12 = 0x7B,
- VKEY_F13 = 0x7C,
- VKEY_F14 = 0x7D,
- VKEY_F15 = 0x7E,
- VKEY_F16 = 0x7F,
- VKEY_F17 = 0x80,
- VKEY_F18 = 0x81,
- VKEY_F19 = 0x82,
- VKEY_F20 = 0x83,
- VKEY_F21 = 0x84,
- VKEY_F22 = 0x85,
- VKEY_F23 = 0x86,
- VKEY_F24 = 0x87,
- VKEY_NUMLOCK = 0x90,
- VKEY_SCROLL = 0x91,
- VKEY_LSHIFT = 0xA0,
- VKEY_RSHIFT = 0xA1,
- VKEY_LCONTROL = 0xA2,
- VKEY_RCONTROL = 0xA3,
- VKEY_LMENU = 0xA4,
- VKEY_RMENU = 0xA5,
- VKEY_BROWSER_BACK = 0xA6,
- VKEY_BROWSER_FORWARD = 0xA7,
- VKEY_BROWSER_REFRESH = 0xA8,
- VKEY_BROWSER_STOP = 0xA9,
- VKEY_BROWSER_SEARCH = 0xAA,
- VKEY_BROWSER_FAVORITES = 0xAB,
- VKEY_BROWSER_HOME = 0xAC,
- VKEY_VOLUME_MUTE = 0xAD,
- VKEY_VOLUME_DOWN = 0xAE,
- VKEY_VOLUME_UP = 0xAF,
- VKEY_MEDIA_NEXT_TRACK = 0xB0,
- VKEY_MEDIA_PREV_TRACK = 0xB1,
- VKEY_MEDIA_STOP = 0xB2,
- VKEY_MEDIA_PLAY_PAUSE = 0xB3,
- VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
- VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
- VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
- VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
- VKEY_OEM_1 = 0xBA,
- VKEY_OEM_PLUS = 0xBB,
- VKEY_OEM_COMMA = 0xBC,
- VKEY_OEM_MINUS = 0xBD,
- VKEY_OEM_PERIOD = 0xBE,
- VKEY_OEM_2 = 0xBF,
- VKEY_OEM_3 = 0xC0,
- VKEY_OEM_4 = 0xDB,
- VKEY_OEM_5 = 0xDC,
- VKEY_OEM_6 = 0xDD,
- VKEY_OEM_7 = 0xDE,
- VKEY_OEM_8 = 0xDF,
- VKEY_OEM_102 = 0xE2,
- VKEY_PROCESSKEY = 0xE5,
- VKEY_PACKET = 0xE7,
- VKEY_ATTN = 0xF6,
- VKEY_CRSEL = 0xF7,
- VKEY_EXSEL = 0xF8,
- VKEY_EREOF = 0xF9,
- VKEY_PLAY = 0xFA,
- VKEY_ZOOM = 0xFB,
- VKEY_NONAME = 0xFC,
- VKEY_PA1 = 0xFD,
- VKEY_OEM_CLEAR = 0xFE,
- VKEY_UNKNOWN = 0
-} KeyboardCode;
-
-} // namespace views
-
-#endif // BASE_KEYBOARD_CODES_POSIX_H_
diff --git a/base/keyboard_codes_win.h b/base/keyboard_codes_win.h
deleted file mode 100644
index 7a2f0ef..0000000
--- a/base/keyboard_codes_win.h
+++ /dev/null
@@ -1,185 +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_KEYBOARD_CODES_WIN_H_
-#define BASE_KEYBOARD_CODES_WIN_H_
-
-#include <windows.h>
-
-namespace base {
-
-typedef enum {
- VKEY_BACK = VK_BACK,
- VKEY_TAB = VK_TAB,
- VKEY_CLEAR = VK_CLEAR,
- VKEY_RETURN = VK_RETURN,
- VKEY_SHIFT = VK_SHIFT,
- VKEY_CONTROL = VK_CONTROL,
- VKEY_MENU = VK_MENU, // a.k.a. ALT
- VKEY_PAUSE = VK_PAUSE,
- VKEY_CAPITAL = VK_CAPITAL,
- VKEY_KANA = VK_KANA,
- VKEY_HANGUL = VK_HANGUL,
- VKEY_JUNJA = VK_JUNJA,
- VKEY_FINAL = VK_FINAL,
- VKEY_HANJA = VK_HANJA,
- VKEY_KANJI = VK_KANJI,
- VKEY_ESCAPE = VK_ESCAPE,
- VKEY_CONVERT = VK_CONVERT,
- VKEY_NONCONVERT = VK_NONCONVERT,
- VKEY_ACCEPT = VK_ACCEPT,
- VKEY_MODECHANGE = VK_MODECHANGE,
- VKEY_SPACE = VK_SPACE,
- VKEY_PRIOR = VK_PRIOR,
- VKEY_NEXT = VK_NEXT,
- VKEY_END = VK_END,
- VKEY_HOME = VK_HOME,
- VKEY_LEFT = VK_LEFT,
- VKEY_UP = VK_UP,
- VKEY_RIGHT = VK_RIGHT,
- VKEY_DOWN = VK_DOWN,
- VKEY_SELECT = VK_SELECT,
- VKEY_PRINT = VK_PRINT,
- VKEY_EXECUTE = VK_EXECUTE,
- VKEY_SNAPSHOT = VK_SNAPSHOT,
- VKEY_INSERT = VK_INSERT,
- VKEY_DELETE = VK_DELETE,
- VKEY_HELP = VK_HELP,
- VKEY_0 = '0',
- VKEY_1 = '1',
- VKEY_2 = '2',
- VKEY_3 = '3',
- VKEY_4 = '4',
- VKEY_5 = '5',
- VKEY_6 = '6',
- VKEY_7 = '7',
- VKEY_8 = '8',
- VKEY_9 = '9',
- VKEY_A = 'A',
- VKEY_B = 'B',
- VKEY_C = 'C',
- VKEY_D = 'D',
- VKEY_E = 'E',
- VKEY_F = 'F',
- VKEY_G = 'G',
- VKEY_H = 'H',
- VKEY_I = 'I',
- VKEY_J = 'J',
- VKEY_K = 'K',
- VKEY_L = 'L',
- VKEY_M = 'M',
- VKEY_N = 'N',
- VKEY_O = 'O',
- VKEY_P = 'P',
- VKEY_Q = 'Q',
- VKEY_R = 'R',
- VKEY_S = 'S',
- VKEY_T = 'T',
- VKEY_U = 'U',
- VKEY_V = 'V',
- VKEY_W = 'W',
- VKEY_X = 'X',
- VKEY_Y = 'Y',
- VKEY_Z = 'Z',
- VKEY_LWIN = VK_LWIN,
- VKEY_COMMAND = VKEY_LWIN, // Provide the Mac name for convenience.
- VKEY_RWIN = VK_RWIN,
- VKEY_APPS = VK_APPS,
- VKEY_SLEEP = VK_SLEEP,
- VKEY_NUMPAD0 = VK_NUMPAD0,
- VKEY_NUMPAD1 = VK_NUMPAD1,
- VKEY_NUMPAD2 = VK_NUMPAD2,
- VKEY_NUMPAD3 = VK_NUMPAD3,
- VKEY_NUMPAD4 = VK_NUMPAD4,
- VKEY_NUMPAD5 = VK_NUMPAD5,
- VKEY_NUMPAD6 = VK_NUMPAD6,
- VKEY_NUMPAD7 = VK_NUMPAD7,
- VKEY_NUMPAD8 = VK_NUMPAD8,
- VKEY_NUMPAD9 = VK_NUMPAD9,
- VKEY_MULTIPLY = VK_MULTIPLY,
- VKEY_ADD = VK_ADD,
- VKEY_SEPARATOR = VK_SEPARATOR,
- VKEY_SUBTRACT = VK_SUBTRACT,
- VKEY_DECIMAL = VK_DECIMAL,
- VKEY_DIVIDE = VK_DIVIDE,
- VKEY_F1 = VK_F1,
- VKEY_F2 = VK_F2,
- VKEY_F3 = VK_F3,
- VKEY_F4 = VK_F4,
- VKEY_F5 = VK_F5,
- VKEY_F6 = VK_F6,
- VKEY_F7 = VK_F7,
- VKEY_F8 = VK_F8,
- VKEY_F9 = VK_F9,
- VKEY_F10 = VK_F10,
- VKEY_F11 = VK_F11,
- VKEY_F12 = VK_F12,
- VKEY_F13 = VK_F13,
- VKEY_F14 = VK_F14,
- VKEY_F15 = VK_F15,
- VKEY_F16 = VK_F16,
- VKEY_F17 = VK_F17,
- VKEY_F18 = VK_F18,
- VKEY_F19 = VK_F19,
- VKEY_F20 = VK_F20,
- VKEY_F21 = VK_F21,
- VKEY_F22 = VK_F22,
- VKEY_F23 = VK_F23,
- VKEY_F24 = VK_F24,
- VKEY_NUMLOCK = VK_NUMLOCK,
- VKEY_SCROLL = VK_SCROLL,
- VKEY_LSHIFT = VK_LSHIFT,
- VKEY_RSHIFT = VK_RSHIFT,
- VKEY_LCONTROL = VK_LCONTROL,
- VKEY_RCONTROL = VK_RCONTROL,
- VKEY_LMENU = VK_LMENU,
- VKEY_RMENU = VK_RMENU,
- VKEY_BROWSER_BACK = VK_BROWSER_BACK,
- VKEY_BROWSER_FORWARD = VK_BROWSER_FORWARD,
- VKEY_BROWSER_REFRESH = VK_BROWSER_REFRESH,
- VKEY_BROWSER_STOP = VK_BROWSER_STOP,
- VKEY_BROWSER_SEARCH = VK_BROWSER_SEARCH,
- VKEY_BROWSER_FAVORITES = VK_BROWSER_FAVORITES,
- VKEY_BROWSER_HOME = VK_BROWSER_HOME,
- VKEY_VOLUME_MUTE = VK_VOLUME_MUTE,
- VKEY_VOLUME_DOWN = VK_VOLUME_DOWN,
- VKEY_VOLUME_UP = VK_VOLUME_UP,
- VKEY_MEDIA_NEXT_TRACK = VK_MEDIA_NEXT_TRACK,
- VKEY_MEDIA_PREV_TRACK = VK_MEDIA_PREV_TRACK,
- VKEY_MEDIA_STOP = VK_MEDIA_STOP,
- VKEY_MEDIA_PLAY_PAUSE = VK_MEDIA_PLAY_PAUSE,
- VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
- VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
- VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
- VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
- VKEY_OEM_1 = VK_OEM_1,
- VKEY_OEM_PLUS = VK_OEM_PLUS,
- VKEY_OEM_COMMA = VK_OEM_COMMA,
- VKEY_OEM_MINUS = VK_OEM_MINUS,
- VKEY_OEM_PERIOD = VK_OEM_PERIOD,
- VKEY_OEM_2 = VK_OEM_2,
- VKEY_OEM_3 = VK_OEM_3,
- VKEY_OEM_4 = VK_OEM_4,
- VKEY_OEM_5 = VK_OEM_5,
- VKEY_OEM_6 = VK_OEM_6,
- VKEY_OEM_7 = VK_OEM_7,
- VKEY_OEM_8 = VK_OEM_8,
- VKEY_OEM_102 = VK_OEM_102,
- VKEY_PROCESSKEY = VK_PROCESSKEY,
- VKEY_PACKET = VK_PACKET,
- VKEY_ATTN = VK_ATTN,
- VKEY_CRSEL = VK_CRSEL,
- VKEY_EXSEL = VK_EXSEL,
- VKEY_EREOF = VK_EREOF,
- VKEY_PLAY = VK_PLAY,
- VKEY_ZOOM = VK_ZOOM,
- VKEY_NONAME = VK_NONAME,
- VKEY_PA1 = VK_PA1,
- VKEY_OEM_CLEAR = VK_OEM_CLEAR,
- VKEY_UNKNOWN = 0
-} KeyboardCode;
-
-} // namespace views
-
-#endif // BASE_KEYBOARD_CODES_WIN_H_
diff --git a/base/lazy_instance.cc b/base/lazy_instance.cc
index f98ba3f..957482c 100644
--- a/base/lazy_instance.cc
+++ b/base/lazy_instance.cc
@@ -36,19 +36,8 @@ void LazyInstanceHelper::CompleteInstance(void* instance, void (*dtor)(void*)) {
// Instance is created, go from CREATING to CREATED.
base::subtle::Release_Store(&state_, STATE_CREATED);
- // Allow reusing the LazyInstance (reset it to the initial state). This
- // makes possible calling all AtExit callbacks between tests. Assumes that
- // no other threads execute when AtExit callbacks are processed.
- base::AtExitManager::RegisterCallback(&LazyInstanceHelper::ResetState,
- this);
-
// Make sure that the lazily instantiated object will get destroyed at exit.
base::AtExitManager::RegisterCallback(dtor, instance);
}
-// static
-void LazyInstanceHelper::ResetState(void* helper) {
- reinterpret_cast<LazyInstanceHelper*>(helper)->state_ = STATE_EMPTY;
-}
-
} // namespace base
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index d639348..52a5124 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -34,6 +34,7 @@
#ifndef BASE_LAZY_INSTANCE_H_
#define BASE_LAZY_INSTANCE_H_
+#pragma once
#include "base/atomicops.h"
#include "base/basictypes.h"
@@ -80,10 +81,6 @@ class LazyInstanceHelper {
base::subtle::Atomic32 state_;
private:
- // Resets state of |helper| to STATE_EMPTY so that it can be reused.
- // Not thread safe.
- static void ResetState(void* helper);
-
DISALLOW_COPY_AND_ASSIGN(LazyInstanceHelper);
};
diff --git a/base/leak_annotations.h b/base/leak_annotations.h
index a402acf..dd8280b 100644
--- a/base/leak_annotations.h
+++ b/base/leak_annotations.h
@@ -4,6 +4,7 @@
#ifndef BASE_LEAK_ANNOTATIONS_H_
#define BASE_LEAK_ANNOTATIONS_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/leak_tracker.h b/base/leak_tracker.h
index 46e7b4a..dd85ff6 100644
--- a/base/leak_tracker.h
+++ b/base/leak_tracker.h
@@ -4,6 +4,7 @@
#ifndef BASE_LEAK_TRACKER_H_
#define BASE_LEAK_TRACKER_H_
+#pragma once
// Only enable leak tracking in debug builds.
#ifndef NDEBUG
diff --git a/base/linked_list.h b/base/linked_list.h
index 5b5184f..d91a1f8 100644
--- a/base/linked_list.h
+++ b/base/linked_list.h
@@ -4,6 +4,7 @@
#ifndef BASE_LINKED_LIST_H_
#define BASE_LINKED_LIST_H_
+#pragma once
// Simple LinkedList type. (See the Q&A section to understand how this
// differs from std::list).
@@ -125,6 +126,13 @@ class LinkNode {
return static_cast<T*>(this);
}
+ // Work around a Clang bug reported upstream:
+ // http://llvm.org/bugs/show_bug.cgi?id=7974
+ // TODO(evanm): remove this and its sole caller.
+ void set(LinkNode<T>* prev, LinkNode<T>* next) {
+ previous_ = prev; next_ = next;
+ }
+
private:
LinkNode<T>* previous_;
LinkNode<T>* next_;
@@ -136,7 +144,7 @@ class LinkedList {
// The "root" node is self-referential, and forms the basis of a circular
// list (root_.next() will point back to the start of the list,
// and root_->previous() wraps around to the end of the list).
- LinkedList() : root_(&root_, &root_) {}
+ LinkedList() { root_.set(&root_, &root_); }
// Appends |e| to the end of the linked list.
void Append(LinkNode<T>* e) {
diff --git a/base/linked_ptr.h b/base/linked_ptr.h
index d9e81b3..162798d 100644
--- a/base/linked_ptr.h
+++ b/base/linked_ptr.h
@@ -36,6 +36,7 @@
#ifndef BASE_LINKED_PTR_H_
#define BASE_LINKED_PTR_H_
+#pragma once
#include "base/logging.h" // for CHECK macros
diff --git a/base/linked_ptr_unittest.cc b/base/linked_ptr_unittest.cc
index f0b8989..e65b687 100644
--- a/base/linked_ptr_unittest.cc
+++ b/base/linked_ptr_unittest.cc
@@ -1,12 +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 <string>
#include "base/linked_ptr.h"
-
-#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -17,17 +16,17 @@ std::string history;
// Class which tracks allocation/deallocation
struct A {
- A(): mynum(num++) { history += StringPrintf("A%d ctor\n", mynum); }
- virtual ~A() { history += StringPrintf("A%d dtor\n", mynum); }
- virtual void Use() { history += StringPrintf("A%d use\n", mynum); }
+ A(): mynum(num++) { history += base::StringPrintf("A%d ctor\n", mynum); }
+ virtual ~A() { history += base::StringPrintf("A%d dtor\n", mynum); }
+ virtual void Use() { history += base::StringPrintf("A%d use\n", mynum); }
int mynum;
};
// Subclass
struct B: public A {
- B() { history += StringPrintf("B%d ctor\n", mynum); }
- ~B() { history += StringPrintf("B%d dtor\n", mynum); }
- virtual void Use() { history += StringPrintf("B%d use\n", mynum); }
+ B() { history += base::StringPrintf("B%d ctor\n", mynum); }
+ ~B() { history += base::StringPrintf("B%d dtor\n", mynum); }
+ virtual void Use() { history += base::StringPrintf("B%d use\n", mynum); }
};
} // namespace
diff --git a/base/linux_util.cc b/base/linux_util.cc
index dda6333..62931ce 100644
--- a/base/linux_util.cc
+++ b/base/linux_util.cc
@@ -10,14 +10,12 @@
#include <glib.h>
#include <stdlib.h>
#include <sys/stat.h>
-#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "base/command_line.h"
-#include "base/env_var.h"
#include "base/file_util.h"
#include "base/lock.h"
#include "base/path_service.h"
@@ -127,9 +125,12 @@ bool ProcPathGetInode(ino_t* inode_out, const char* path, bool log = false) {
namespace base {
+// Account for the terminating null character.
+static const int kDistroSize = 128 + 1;
+
// We use this static string to hold the Linux distro info. If we
// crash, the crash handler code will send this in the crash dump.
-std::string linux_distro =
+char g_linux_distro[kDistroSize] =
#if defined(OS_CHROMEOS)
"CrOS";
#else // if defined(OS_LINUX)
@@ -138,7 +139,7 @@ std::string linux_distro =
std::string GetLinuxDistro() {
#if defined(OS_CHROMEOS)
- return linux_distro;
+ return g_linux_distro;
#elif defined(OS_LINUX)
LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::Get();
LinuxDistroState state = distro_state_singleton->State();
@@ -155,25 +156,30 @@ std::string GetLinuxDistro() {
// lsb_release -d should return: Description:<tab>Distro Info
static const std::string field = "Description:\t";
if (output.compare(0, field.length(), field) == 0) {
- linux_distro = output.substr(field.length());
- TrimWhitespaceASCII(linux_distro, TRIM_ALL, &linux_distro);
+ SetLinuxDistro(output.substr(field.length()));
}
}
distro_state_singleton->CheckFinished();
- return linux_distro;
+ return g_linux_distro;
} else if (STATE_CHECK_STARTED == state) {
// If the distro check above is in progress in some other thread, we're
// not going to wait for the results.
return "Unknown";
} else {
// In STATE_CHECK_FINISHED, no more writing to |linux_distro|.
- return linux_distro;
+ return g_linux_distro;
}
#else
NOTIMPLEMENTED();
#endif
}
+void SetLinuxDistro(const std::string& distro) {
+ std::string trimmed_distro;
+ TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro);
+ base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
+}
+
bool FileDescriptorGetInode(ino_t* inode_out, int fd) {
DCHECK(inode_out);
diff --git a/base/linux_util.h b/base/linux_util.h
index a4ba9b6..0d2f20e 100644
--- a/base/linux_util.h
+++ b/base/linux_util.h
@@ -4,24 +4,28 @@
#ifndef BASE_LINUX_UTIL_H_
#define BASE_LINUX_UTIL_H_
+#pragma once
#include <stdint.h>
#include <sys/types.h>
#include <string>
-class FilePath;
-
namespace base {
-class EnvVarGetter;
-
static const char kFindInodeSwitch[] = "--find-inode";
+// This is declared here so the crash reporter can access the memory directly
+// in compromised context without going through the standard library.
+extern char g_linux_distro[];
+
// Get the Linux Distro if we can, or return "Unknown", similar to
// GetWinVersion() in base/win_util.h.
std::string GetLinuxDistro();
+// Set the Linux Distro string.
+void SetLinuxDistro(const std::string& distro);
+
// Return the inode number for the UNIX domain socket |fd|.
bool FileDescriptorGetInode(ino_t* inode_out, int fd);
diff --git a/base/lock.h b/base/lock.h
index 64b8f74..0ae4861 100644
--- a/base/lock.h
+++ b/base/lock.h
@@ -4,6 +4,7 @@
#ifndef BASE_LOCK_H_
#define BASE_LOCK_H_
+#pragma once
#include "base/lock_impl.h"
@@ -20,7 +21,9 @@ class Lock {
void Release() { lock_.Unlock(); }
// If the lock is not held, take it and return true. If the lock is already
- // held by another thread, immediately return false.
+ // held by another thread, immediately return false. This must not be called
+ // by a thread already holding the lock (what happens is undefined and an
+ // assertion may fail).
bool Try() { return lock_.Try(); }
// Null implementation if not debug.
diff --git a/base/lock_impl.h b/base/lock_impl.h
index 5e323a6..9a6a1a0 100644
--- a/base/lock_impl.h
+++ b/base/lock_impl.h
@@ -4,6 +4,7 @@
#ifndef BASE_LOCK_IMPL_H_
#define BASE_LOCK_IMPL_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/lock_impl_win.cc b/base/lock_impl_win.cc
index 14b76f8..8c03b61 100644
--- a/base/lock_impl_win.cc
+++ b/base/lock_impl_win.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/lock_impl.h"
-#include "base/logging.h"
LockImpl::LockImpl() {
// The second parameter is the spin count, for short-held locks it avoid the
@@ -29,4 +28,3 @@ void LockImpl::Lock() {
void LockImpl::Unlock() {
::LeaveCriticalSection(&os_lock_);
}
-
diff --git a/base/lock_unittest.cc b/base/lock_unittest.cc
new file mode 100644
index 0000000..cf99df9
--- /dev/null
+++ b/base/lock_unittest.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2010 The Chromium Authors. 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/lock.h"
+
+#include <stdlib.h>
+
+#include "base/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+typedef testing::Test LockTest;
+
+// Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
+
+class BasicLockTestThread : public PlatformThread::Delegate {
+ public:
+ BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
+
+ virtual void ThreadMain() {
+ for (int i = 0; i < 10; i++) {
+ lock_->Acquire();
+ acquired_++;
+ lock_->Release();
+ }
+ for (int i = 0; i < 10; i++) {
+ lock_->Acquire();
+ acquired_++;
+ PlatformThread::Sleep(rand() % 20);
+ lock_->Release();
+ }
+ for (int i = 0; i < 10; i++) {
+ if (lock_->Try()) {
+ acquired_++;
+ PlatformThread::Sleep(rand() % 20);
+ lock_->Release();
+ }
+ }
+ }
+
+ int acquired() const { return acquired_; }
+
+ private:
+ Lock* lock_;
+ int acquired_;
+
+ DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
+};
+
+TEST_F(LockTest, Basic) {
+ Lock lock;
+ BasicLockTestThread thread(&lock);
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+ int acquired = 0;
+ for (int i = 0; i < 5; i++) {
+ lock.Acquire();
+ acquired++;
+ lock.Release();
+ }
+ for (int i = 0; i < 10; i++) {
+ lock.Acquire();
+ acquired++;
+ PlatformThread::Sleep(rand() % 20);
+ lock.Release();
+ }
+ for (int i = 0; i < 10; i++) {
+ if (lock.Try()) {
+ acquired++;
+ PlatformThread::Sleep(rand() % 20);
+ lock.Release();
+ }
+ }
+ for (int i = 0; i < 5; i++) {
+ lock.Acquire();
+ acquired++;
+ PlatformThread::Sleep(rand() % 20);
+ lock.Release();
+ }
+
+ PlatformThread::Join(handle);
+
+ EXPECT_GE(acquired, 20);
+ EXPECT_GE(thread.acquired(), 20);
+}
+
+// Test that Try() works as expected -------------------------------------------
+
+class TryLockTestThread : public PlatformThread::Delegate {
+ public:
+ TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
+
+ virtual void ThreadMain() {
+ got_lock_ = lock_->Try();
+ if (got_lock_)
+ lock_->Release();
+ }
+
+ bool got_lock() const { return got_lock_; }
+
+ private:
+ Lock* lock_;
+ bool got_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
+};
+
+TEST_F(LockTest, TryLock) {
+ Lock lock;
+
+ ASSERT_TRUE(lock.Try());
+ // We now have the lock....
+
+ // This thread will not be able to get the lock.
+ {
+ TryLockTestThread thread(&lock);
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+ PlatformThread::Join(handle);
+
+ ASSERT_FALSE(thread.got_lock());
+ }
+
+ lock.Release();
+
+ // This thread will....
+ {
+ TryLockTestThread thread(&lock);
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+ PlatformThread::Join(handle);
+
+ ASSERT_TRUE(thread.got_lock());
+ // But it released it....
+ ASSERT_TRUE(lock.Try());
+ }
+
+ lock.Release();
+}
+
+// Tests that locks actually exclude -------------------------------------------
+
+class MutexLockTestThread : public PlatformThread::Delegate {
+ public:
+ MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
+
+ // Static helper which can also be called from the main thread.
+ static void DoStuff(Lock* lock, int* value) {
+ for (int i = 0; i < 40; i++) {
+ lock->Acquire();
+ int v = *value;
+ PlatformThread::Sleep(rand() % 10);
+ *value = v + 1;
+ lock->Release();
+ }
+ }
+
+ virtual void ThreadMain() {
+ DoStuff(lock_, value_);
+ }
+
+ private:
+ Lock* lock_;
+ int* value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
+};
+
+TEST_F(LockTest, MutexTwoThreads) {
+ Lock lock;
+ int value = 0;
+
+ MutexLockTestThread thread(&lock, &value);
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+ MutexLockTestThread::DoStuff(&lock, &value);
+
+ PlatformThread::Join(handle);
+
+ EXPECT_EQ(2 * 40, value);
+}
+
+TEST_F(LockTest, MutexFourThreads) {
+ Lock lock;
+ int value = 0;
+
+ MutexLockTestThread thread1(&lock, &value);
+ MutexLockTestThread thread2(&lock, &value);
+ MutexLockTestThread thread3(&lock, &value);
+ PlatformThreadHandle handle1 = kNullThreadHandle;
+ PlatformThreadHandle handle2 = kNullThreadHandle;
+ PlatformThreadHandle handle3 = kNullThreadHandle;
+
+ ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
+ ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
+ ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
+
+ MutexLockTestThread::DoStuff(&lock, &value);
+
+ PlatformThread::Join(handle1);
+ PlatformThread::Join(handle2);
+ PlatformThread::Join(handle3);
+
+ EXPECT_EQ(4 * 40, value);
+}
diff --git a/base/logging.cc b/base/logging.cc
index af1ab06..bfdff2d 100644
--- a/base/logging.cc
+++ b/base/logging.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.
@@ -25,6 +25,7 @@ typedef HANDLE MutexHandle;
#if defined(OS_POSIX)
#include <errno.h>
+#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -50,18 +51,18 @@ typedef pthread_mutex_t* MutexHandle;
#endif
#include "base/process_util.h"
#include "base/string_piece.h"
-#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "base/vlog.h"
namespace logging {
bool g_enable_dcheck = false;
+VlogInfo* g_vlog_info = NULL;
const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
"INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
int min_log_level = 0;
-LogLockingState lock_log_file = LOCK_LOG_FILE;
// The default set here for logging_destination will only be used if
// InitLogging is not called. On Windows, use a file next to the exe;
@@ -83,10 +84,8 @@ const int kAlwaysPrintErrorLevel = LOG_ERROR;
// will be lazily initialized to the default value when it is
// first needed.
#if defined(OS_WIN)
-typedef wchar_t PathChar;
typedef std::wstring PathString;
#else
-typedef char PathChar;
typedef std::string PathString;
#endif
PathString* log_file_name = NULL;
@@ -100,6 +99,9 @@ bool log_thread_id = false;
bool log_timestamp = true;
bool log_tickcount = false;
+// Should we pop up fatal debug messages in a dialog?
+bool show_error_dialogs = false;
+
// An assert handler override specified by the client to be called instead of
// the debug message dialog and process termination.
LogAssertHandlerFunction log_assert_handler = NULL;
@@ -109,19 +111,6 @@ LogReportHandlerFunction log_report_handler = NULL;
// A log message handler that gets notified of every log message we process.
LogMessageHandlerFunction log_message_handler = NULL;
-// The lock is used if log file locking is false. It helps us avoid problems
-// with multiple threads writing to the log file at the same time. Use
-// LockImpl directly instead of using Lock, because Lock makes logging calls.
-static LockImpl* log_lock = NULL;
-
-// When we don't use a lock, we are using a global mutex. We need to do this
-// because LockFileEx is not thread safe.
-#if defined(OS_WIN)
-MutexHandle log_mutex = NULL;
-#elif defined(OS_POSIX)
-pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
// Helper functions to wrap platform differences.
int32 CurrentProcessId() {
@@ -178,6 +167,126 @@ void DeleteFilePath(const PathString& log_name) {
#endif
}
+void GetDefaultLogFile(PathString default_log_file) {
+#if defined(OS_WIN)
+ // On Windows we use the same path as the exe.
+ wchar_t module_name[MAX_PATH];
+ GetModuleFileName(NULL, module_name, MAX_PATH);
+ default_log_file = module_name;
+ std::wstring::size_type last_backslash =
+ default_log_file.rfind('\\', default_log_file.size());
+ if (last_backslash != std::wstring::npos)
+ default_log_file.erase(last_backslash + 1);
+ default_log_file += L"debug.log";
+#elif defined(OS_POSIX)
+ // On other platforms we just use the current directory.
+ default_log_file = "debug.log";
+#endif
+}
+
+// This class acts as a wrapper for locking the logging files.
+// LoggingLock::Init() should be called from the main thread before any logging
+// is done. Then whenever logging, be sure to have a local LoggingLock
+// instance on the stack. This will ensure that the lock is unlocked upon
+// exiting the frame.
+// LoggingLocks can not be nested.
+class LoggingLock {
+ public:
+ LoggingLock() {
+ LockLogging();
+ }
+
+ ~LoggingLock() {
+ UnlockLogging();
+ }
+
+ static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
+ if (initialized)
+ return;
+ lock_log_file = lock_log;
+ if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+ if (!log_mutex) {
+ std::wstring safe_name;
+ if (new_log_file)
+ safe_name = new_log_file;
+ else
+ GetDefaultLogFile(safe_name);
+ // \ is not a legal character in mutex names so we replace \ with /
+ std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
+ std::wstring t(L"Global\\");
+ t.append(safe_name);
+ log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
+ }
+#endif
+ } else {
+ log_lock = new LockImpl();
+ }
+ initialized = true;
+ }
+
+ private:
+ static void LockLogging() {
+ if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+ ::WaitForSingleObject(log_mutex, INFINITE);
+ // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
+ // abort the process here. UI tests might be crashy sometimes,
+ // and aborting the test binary only makes the problem worse.
+ // We also don't use LOG macros because that might lead to an infinite
+ // loop. For more info see http://crbug.com/18028.
+#elif defined(OS_POSIX)
+ pthread_mutex_lock(&log_mutex);
+#endif
+ } else {
+ // use the lock
+ log_lock->Lock();
+ }
+ }
+
+ static void UnlockLogging() {
+ if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+ ReleaseMutex(log_mutex);
+#elif defined(OS_POSIX)
+ pthread_mutex_unlock(&log_mutex);
+#endif
+ } else {
+ log_lock->Unlock();
+ }
+ }
+
+ // The lock is used if log file locking is false. It helps us avoid problems
+ // with multiple threads writing to the log file at the same time. Use
+ // LockImpl directly instead of using Lock, because Lock makes logging calls.
+ static LockImpl* log_lock;
+
+ // When we don't use a lock, we are using a global mutex. We need to do this
+ // because LockFileEx is not thread safe.
+#if defined(OS_WIN)
+ static MutexHandle log_mutex;
+#elif defined(OS_POSIX)
+ static pthread_mutex_t log_mutex;
+#endif
+
+ static bool initialized;
+ static LogLockingState lock_log_file;
+};
+
+// static
+bool LoggingLock::initialized = false;
+// static
+LockImpl* LoggingLock::log_lock = NULL;
+// static
+LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
+
+#if defined(OS_WIN)
+// static
+MutexHandle LoggingLock::log_mutex = NULL;
+#elif defined(OS_POSIX)
+pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
// Called by logging functions to ensure that debug_file is initialized
// and can be used for writing. Returns false if the file could not be
// initialized. debug_file will be NULL in this case.
@@ -188,20 +297,8 @@ bool InitializeLogFileHandle() {
if (!log_file_name) {
// Nobody has called InitLogging to specify a debug log file, so here we
// initialize the log file name to a default.
-#if defined(OS_WIN)
- // On Windows we use the same path as the exe.
- wchar_t module_name[MAX_PATH];
- GetModuleFileName(NULL, module_name, MAX_PATH);
- log_file_name = new std::wstring(module_name);
- std::wstring::size_type last_backslash =
- log_file_name->rfind('\\', log_file_name->size());
- if (last_backslash != std::wstring::npos)
- log_file_name->erase(last_backslash + 1);
- *log_file_name += L"debug.log";
-#elif defined(OS_POSIX)
- // On other platforms we just use the current directory.
- log_file_name = new std::string("debug.log");
-#endif
+ log_file_name = new PathString();
+ GetDefaultLogFile(*log_file_name);
}
if (logging_destination == LOG_ONLY_TO_FILE ||
@@ -231,21 +328,25 @@ bool InitializeLogFileHandle() {
return true;
}
-void InitLogMutex() {
-#if defined(OS_WIN)
- if (!log_mutex) {
- // \ is not a legal character in mutex names so we replace \ with /
- std::wstring safe_name(*log_file_name);
- std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
- std::wstring t(L"Global\\");
- t.append(safe_name);
- log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
+void BaseInitLoggingImpl(const PathChar* new_log_file,
+ LoggingDestination logging_dest,
+ LogLockingState lock_log,
+ OldFileDeletionState delete_old) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ g_enable_dcheck =
+ command_line->HasSwitch(switches::kEnableDCHECK);
+ delete g_vlog_info;
+ g_vlog_info = NULL;
+ // Don't bother initializing g_vlog_info unless we use one of the
+ // vlog switches.
+ if (command_line->HasSwitch(switches::kV) ||
+ command_line->HasSwitch(switches::kVModule)) {
+ g_vlog_info =
+ new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
+ command_line->GetSwitchValueASCII(switches::kVModule));
}
-#elif defined(OS_POSIX)
- // statically initialized
-#endif
-}
+<<<<<<< HEAD
void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
LogLockingState lock_log, OldFileDeletionState delete_old) {
g_enable_dcheck =
@@ -254,6 +355,11 @@ void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
#else
CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
#endif // ANDROID
+=======
+ LoggingLock::Init(lock_log, new_log_file);
+
+ LoggingLock logging_lock;
+>>>>>>> Chromium at release 7.0.540.0
if (log_file) {
// calling InitLogging twice or after some log call has already opened the
@@ -262,7 +368,6 @@ void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
log_file = NULL;
}
- lock_log_file = lock_log;
logging_destination = logging_dest;
// ignore file options if logging is disabled or only to system
@@ -276,13 +381,8 @@ void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
if (delete_old == DELETE_OLD_LOG_FILE)
DeleteFilePath(*log_file_name);
- if (lock_log_file == LOCK_LOG_FILE) {
- InitLogMutex();
- } else if (!log_lock) {
- log_lock = new LockImpl();
- }
-
InitializeLogFileHandle();
+
}
void SetMinLogLevel(int level) {
@@ -293,6 +393,13 @@ int GetMinLogLevel() {
return min_log_level;
}
+int GetVlogLevelHelper(const char* file, size_t N) {
+ DCHECK_GT(N, 0U);
+ return g_vlog_info ?
+ g_vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
+ VlogInfo::kDefaultVlogLevel;
+}
+
void SetLogFilterPrefix(const char* filter) {
if (log_filter_prefix) {
delete log_filter_prefix;
@@ -311,6 +418,10 @@ void SetLogItems(bool enable_process_id, bool enable_thread_id,
log_tickcount = enable_tickcount;
}
+void SetShowErrorDialogs(bool enable_dialogs) {
+ show_error_dialogs = enable_dialogs;
+}
+
void SetLogAssertHandler(LogAssertHandlerFunction handler) {
log_assert_handler = handler;
}
@@ -330,6 +441,9 @@ void DisplayDebugMessageInDialog(const std::string& str) {
if (str.empty())
return;
+ if (!show_error_dialogs)
+ return;
+
#if defined(OS_WIN)
// For Windows programs, it's possible that the message loop is
// messed up on a fatal error, and creating a MessageBox will cause
@@ -363,7 +477,7 @@ void DisplayDebugMessageInDialog(const std::string& str) {
MessageBoxW(NULL, &cmdline[0], L"Fatal error",
MB_OK | MB_ICONHAND | MB_TOPMOST);
}
-#elif defined(USE_X11)
+#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
@@ -488,22 +602,9 @@ LogMessage::~LogMessage() {
logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
#if defined(OS_WIN)
OutputDebugStringA(str_newline.c_str());
- if (severity_ >= kAlwaysPrintErrorLevel) {
-#else
- {
#endif
- // TODO(erikkay): this interferes with the layout tests since it grabs
- // stderr and stdout and diffs them against known data. Our info and warn
- // logs add noise to that. Ideally, the layout tests would set the log
- // level to ignore anything below error. When that happens, we should
- // take this fprintf out of the #else so that Windows users can benefit
- // from the output when running tests from the command-line. In the
- // meantime, we leave this in for Mac and Linux, but until this is fixed
- // they won't be able to pass any layout tests that have info or warn
- // logs. See http://b/1343647
- fprintf(stderr, "%s", str_newline.c_str());
- fflush(stderr);
- }
+ fprintf(stderr, "%s", str_newline.c_str());
+ fflush(stderr);
} else if (severity_ >= kAlwaysPrintErrorLevel) {
// When we're only outputting to a log file, above a certain log level, we
// should still output to stderr so that we can better detect and diagnose
@@ -512,61 +613,31 @@ LogMessage::~LogMessage() {
fflush(stderr);
}
+ // We can have multiple threads and/or processes, so try to prevent them
+ // from clobbering each other's writes.
+ // If the client app did not call InitLogging, and the lock has not
+ // been created do it now. We do this on demand, but if two threads try
+ // to do this at the same time, there will be a race condition to create
+ // the lock. This is why InitLogging should be called from the main
+ // thread at the beginning of execution.
+ LoggingLock::Init(LOCK_LOG_FILE, NULL);
// write to log file
if (logging_destination != LOG_NONE &&
- logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
- InitializeLogFileHandle()) {
- // We can have multiple threads and/or processes, so try to prevent them
- // from clobbering each other's writes.
- if (lock_log_file == LOCK_LOG_FILE) {
- // Ensure that the mutex is initialized in case the client app did not
- // call InitLogging. This is not thread safe. See below.
- InitLogMutex();
-
-#if defined(OS_WIN)
- ::WaitForSingleObject(log_mutex, INFINITE);
- // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
- // abort the process here. UI tests might be crashy sometimes,
- // and aborting the test binary only makes the problem worse.
- // We also don't use LOG macros because that might lead to an infinite
- // loop. For more info see http://crbug.com/18028.
-#elif defined(OS_POSIX)
- pthread_mutex_lock(&log_mutex);
-#endif
- } else {
- // use the lock
- if (!log_lock) {
- // The client app did not call InitLogging, and so the lock has not
- // been created. We do this on demand, but if two threads try to do
- // this at the same time, there will be a race condition to create
- // the lock. This is why InitLogging should be called from the main
- // thread at the beginning of execution.
- log_lock = new LockImpl();
- }
- log_lock->Lock();
- }
-
+ logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG) {
+ LoggingLock logging_lock;
+ if (InitializeLogFileHandle()) {
#if defined(OS_WIN)
- SetFilePointer(log_file, 0, 0, SEEK_END);
- DWORD num_written;
- WriteFile(log_file,
- static_cast<const void*>(str_newline.c_str()),
- static_cast<DWORD>(str_newline.length()),
- &num_written,
- NULL);
+ SetFilePointer(log_file, 0, 0, SEEK_END);
+ DWORD num_written;
+ WriteFile(log_file,
+ static_cast<const void*>(str_newline.c_str()),
+ static_cast<DWORD>(str_newline.length()),
+ &num_written,
+ NULL);
#else
- fprintf(log_file, "%s", str_newline.c_str());
- fflush(log_file);
-#endif
-
- if (lock_log_file == LOCK_LOG_FILE) {
-#if defined(OS_WIN)
- ReleaseMutex(log_mutex);
-#elif defined(OS_POSIX)
- pthread_mutex_unlock(&log_mutex);
+ fprintf(log_file, "%s", str_newline.c_str());
+ fflush(log_file);
#endif
- } else {
- log_lock->Unlock();
}
}
@@ -690,6 +761,8 @@ ErrnoLogMessage::~ErrnoLogMessage() {
#endif // OS_WIN
void CloseLogFile() {
+ LoggingLock logging_lock;
+
if (!log_file)
return;
diff --git a/base/logging.h b/base/logging.h
index 0152e8c..6996f7b 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -4,6 +4,7 @@
#ifndef BASE_LOGGING_H_
#define BASE_LOGGING_H_
+#pragma once
#include <string>
#include <cstring>
@@ -73,6 +74,39 @@
//
// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
//
+// There are "verbose level" logging macros. They look like
+//
+// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module. For instance,
+// --vmodule=profile=2,icon_loader=1,browser_*=3 --v=0
+// will cause:
+// a. VLOG(2) and lower messages to be printed from profile.{h,cc}
+// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
+// c. VLOG(3) and lower messages to be printed from files prefixed with
+// "browser"
+// d. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character) wildcards.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished with just VLOG(2) << ...;
+// }
+//
+// There is also a VLOG_IF "verbose level" condition macro for sample
+// cases, when some extra computation and preparation for logs is not
+// needed.
+//
+// VLOG_IF(1, (size > 1024))
+// << "I'm printed when size is more than 1024 and when you run the "
+// "program with --v=1 or more";
+//
// We also override the standard 'assert' to use 'DLOG_ASSERT'.
//
// Lastly, there is:
@@ -125,6 +159,31 @@ enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
// Defaults to APPEND_TO_OLD_LOG_FILE.
enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
+// TODO(avi): do we want to do a unification of character types here?
+#if defined(OS_WIN)
+typedef wchar_t PathChar;
+#else
+typedef char PathChar;
+#endif
+
+// Define different names for the BaseInitLoggingImpl() function depending on
+// whether NDEBUG is defined or not so that we'll fail to link if someone tries
+// to compile logging.cc with NDEBUG but includes logging.h without defining it,
+// or vice versa.
+#if NDEBUG
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG
+#else
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG
+#endif
+
+// Implementation of the InitLogging() method declared below. We use a
+// more-specific name so we can #define it above without affecting other code
+// that has named stuff "InitLogging".
+void BaseInitLoggingImpl(const PathChar* log_file,
+ LoggingDestination logging_dest,
+ LogLockingState lock_log,
+ OldFileDeletionState delete_old);
+
// Sets the log file name and other global logging state. Calling this function
// is recommended, and is normally done at the beginning of application init.
// If you don't call it, all the flags will be initialized to their default
@@ -135,14 +194,12 @@ enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
// The default log file is initialized to "debug.log" in the application
// directory. You probably don't want this, especially since the program
// directory may not be writable on an enduser's system.
-#if defined(OS_WIN)
-void InitLogging(const wchar_t* log_file, LoggingDestination logging_dest,
- LogLockingState lock_log, OldFileDeletionState delete_old);
-#elif defined(OS_POSIX)
-// TODO(avi): do we want to do a unification of character types here?
-void InitLogging(const char* log_file, LoggingDestination logging_dest,
- LogLockingState lock_log, OldFileDeletionState delete_old);
-#endif
+inline void InitLogging(const PathChar* log_file,
+ LoggingDestination logging_dest,
+ LogLockingState lock_log,
+ OldFileDeletionState delete_old) {
+ BaseInitLoggingImpl(log_file, logging_dest, lock_log, delete_old);
+}
// Sets the log level. Anything at or above this level will be written to the
// log file/displayed to the user (if applicable). Anything below this level
@@ -153,6 +210,16 @@ void SetMinLogLevel(int level);
// Gets the current log level.
int GetMinLogLevel();
+// Gets the current vlog level for the given file (usually taken from
+// __FILE__).
+
+// Note that |N| is the size *with* the null terminator.
+int GetVlogLevelHelper(const char* file_start, size_t N);
+
+template <size_t N>
+int GetVlogLevel(const char (&file)[N]) {
+ return GetVlogLevelHelper(file, N);
+}
// Sets the log filter prefix. Any log message below LOG_ERROR severity that
// doesn't start with this prefix with be silently ignored. The filter defaults
// to NULL (everything is logged) if this function is not called. Messages
@@ -166,6 +233,11 @@ void SetLogFilterPrefix(const char* filter);
void SetLogItems(bool enable_process_id, bool enable_thread_id,
bool enable_timestamp, bool enable_tickcount);
+// Sets whether or not you'd like to see fatal debug messages popped up in
+// a dialog box or not.
+// Dialogs are not shown by default.
+void SetShowErrorDialogs(bool enable_dialogs);
+
// Sets the Log Assert Handler that will be used to notify of check failures.
// The default handler shows a dialog box and then terminate the process,
// however clients can use this function to override with their own handling
@@ -250,13 +322,25 @@ const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL;
// impossible to stream something like a string directly to an unnamed
// ostream. We employ a neat hack by calling the stream() member
// function of LogMessage which seems to avoid the problem.
+//
+// We can't do any caching tricks with VLOG_IS_ON() like the
+// google-glog version since it requires GCC extensions. This means
+// that using the v-logging functions in conjunction with --vmodule
+// may be slow.
+#define VLOG_IS_ON(verboselevel) \
+ (logging::GetVlogLevel(__FILE__) >= (verboselevel))
#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
#define SYSLOG(severity) LOG(severity)
+#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
+
+// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
#define LOG_IF(severity, condition) \
!(condition) ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define VLOG_IF(verboselevel, condition) \
+ LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
#ifdef ANDROID
#ifndef LOG_ASSERT
diff --git a/base/logging_win.cc b/base/logging_win.cc
index 2c2d6b0..f17cf34 100644
--- a/base/logging_win.cc
+++ b/base/logging_win.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/logging_win.h"
-#include "base/atomicops.h"
#include "base/singleton.h"
#include <initguid.h> // NOLINT
diff --git a/base/logging_win.h b/base/logging_win.h
index 42b02fe..f2e6e5a 100644
--- a/base/logging_win.h
+++ b/base/logging_win.h
@@ -4,6 +4,7 @@
#ifndef BASE_LOGGING_WIN_H_
#define BASE_LOGGING_WIN_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
diff --git a/base/mac_util.h b/base/mac_util.h
index bfe2079..4b8d636 100644
--- a/base/mac_util.h
+++ b/base/mac_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_MAC_UTIL_H_
#define BASE_MAC_UTIL_H_
+#pragma once
#include <Carbon/Carbon.h>
#include <string>
@@ -16,6 +17,7 @@ class FilePath;
@class NSWindow;
#else
class NSBundle;
+class NSImage;
class NSWindow;
#endif
@@ -140,6 +142,33 @@ CFTypeRef GetValueFromDictionary(CFDictionaryRef dict,
// Sets the process name as displayed in Activity Monitor to process_name.
void SetProcessName(CFStringRef process_name);
+// Converts a NSImage to a CGImageRef. Normally, the system frameworks can do
+// this fine, especially on 10.6. On 10.5, however, CGImage cannot handle
+// converting a PDF-backed NSImage into a CGImageRef. This function will
+// rasterize the PDF into a bitmap CGImage. The caller is responsible for
+// releasing the return value.
+CGImageRef CopyNSImageToCGImage(NSImage* image);
+
+// Checks if the current application is set as a Login Item, so it will launch
+// on Login. If a non-NULL pointer to is_hidden is passed, the Login Item also
+// is queried for the 'hide on launch' flag.
+bool CheckLoginItemStatus(bool* is_hidden);
+
+// Adds current application to the set of Login Items with specified "hide"
+// flag. This has the same effect as adding/removing the application in
+// SystemPreferences->Accounts->LoginItems or marking Application in the Dock
+// as "Options->Open on Login".
+// Does nothing if the application is already set up as Login Item with
+// specified hide flag.
+void AddToLoginItems(bool hide_on_startup);
+
+// Removes the current application from the list Of Login Items.
+void RemoveFromLoginItems();
+
+// Returns true if the current process was automatically launched as a
+// 'Login Item' with 'hide on startup' flag. Used to suppress opening windows.
+bool WasLaunchedAsHiddenLoginItem();
+
} // namespace mac_util
#endif // BASE_MAC_UTIL_H_
diff --git a/base/mac_util.mm b/base/mac_util.mm
index cd7a949..e017fe7 100644
--- a/base/mac_util.mm
+++ b/base/mac_util.mm
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_cftyperef.h"
+#include "base/scoped_nsobject.h"
#include "base/sys_string_conversions.h"
namespace {
@@ -49,6 +50,82 @@ void SetUIMode() {
SetSystemUIMode(desired_mode, desired_options);
}
+bool WasLaunchedAsLoginItem() {
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+
+ scoped_nsobject<const NSDictionary> process_info(
+ reinterpret_cast<const NSDictionary*>(
+ 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)));
+
+ // Check that creator process code is that of loginwindow.
+ BOOL result =
+ [[parent_info objectForKey:@"FileCreator"] isEqualToString:@"lgnw"];
+
+ return result == YES;
+}
+
+// Looks into Shared File Lists corresponding to Login Items for the item
+// representing the current application. If such an item is found, returns
+// retained reference to it. Caller is responsible for releasing the reference.
+LSSharedFileListItemRef GetLoginItemForApp() {
+ scoped_cftyperef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+ NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+ if (!login_items.get()) {
+ LOG(ERROR) << "Couldn't get a Login Items list.";
+ return NULL;
+ }
+
+ scoped_nsobject<const NSArray> login_items_array(
+ reinterpret_cast<const NSArray*>(
+ LSSharedFileListCopySnapshot(login_items, NULL)));
+
+ NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
+
+ for(NSUInteger i = 0; i < [login_items_array count]; ++i) {
+ LSSharedFileListItemRef item = reinterpret_cast<LSSharedFileListItemRef>(
+ [login_items_array objectAtIndex:i]);
+ CFURLRef item_url_ref = NULL;
+
+ if (LSSharedFileListItemResolve(item, 0, &item_url_ref, NULL) == noErr) {
+ scoped_cftyperef<CFURLRef> item_url(item_url_ref);
+ if (CFEqual(item_url, url)) {
+ CFRetain(item);
+ return item;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+#if !defined(MAC_OS_X_VERSION_10_6) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+// kLSSharedFileListLoginItemHidden is supported on
+// 10.5, but missing from the 10.5 headers.
+// http://openradar.appspot.com/6482251
+static NSString* kLSSharedFileListLoginItemHidden =
+ @"com.apple.loginitem.HideOnLaunch";
+#endif
+
+bool IsHiddenLoginItem(LSSharedFileListItemRef item) {
+ scoped_cftyperef<CFBooleanRef> hidden(reinterpret_cast<CFBooleanRef>(
+ LSSharedFileListItemCopyProperty(item,
+ reinterpret_cast<CFStringRef>(kLSSharedFileListLoginItemHidden))));
+
+ return hidden && hidden == kCFBooleanTrue;
+}
+
} // end namespace
namespace mac_util {
@@ -71,12 +148,15 @@ bool AmIBundled() {
ProcessSerialNumber psn = {0, kCurrentProcess};
FSRef fsref;
- if (GetProcessBundleLocation(&psn, &fsref) != noErr)
+ if (GetProcessBundleLocation(&psn, &fsref) != noErr) {
+ LOG(ERROR) << "GetProcessBundleLocation failed, returning false";
return false;
+ }
FSCatalogInfo info;
if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info,
NULL, NULL, NULL) != noErr) {
+ LOG(ERROR) << "FSGetCatalogInfo failed, returning false";
return false;
}
@@ -479,4 +559,114 @@ void SetProcessName(CFStringRef process_name) {
LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
}
+// Converts a NSImage to a CGImageRef. Normally, the system frameworks can do
+// this fine, especially on 10.6. On 10.5, however, CGImage cannot handle
+// converting a PDF-backed NSImage into a CGImageRef. This function will
+// rasterize the PDF into a bitmap CGImage. The caller is responsible for
+// releasing the return value.
+CGImageRef CopyNSImageToCGImage(NSImage* image) {
+ // This is based loosely on http://www.cocoadev.com/index.pl?CGImageRef .
+ NSSize size = [image size];
+ scoped_cftyperef<CGContextRef> context(
+ CGBitmapContextCreate(NULL, // Allow CG to allocate memory.
+ size.width,
+ size.height,
+ 8, // bitsPerComponent
+ 0, // bytesPerRow - CG will calculate by default.
+ [[NSColorSpace genericRGBColorSpace] CGColorSpace],
+ kCGBitmapByteOrder32Host |
+ kCGImageAlphaPremultipliedFirst));
+ if (!context.get())
+ return NULL;
+
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:
+ [NSGraphicsContext graphicsContextWithGraphicsPort:context.get()
+ flipped:NO]];
+ [image drawInRect:NSMakeRect(0,0, size.width, size.height)
+ fromRect:NSZeroRect
+ operation:NSCompositeCopy
+ fraction:1.0];
+ [NSGraphicsContext restoreGraphicsState];
+
+ return CGBitmapContextCreateImage(context);
+}
+
+bool CheckLoginItemStatus(bool* is_hidden) {
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (!item.get())
+ return false;
+
+ if (is_hidden)
+ *is_hidden = IsHiddenLoginItem(item);
+
+ return true;
+}
+
+void AddToLoginItems(bool hide_on_startup) {
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) {
+ return; // Already is a login item with required hide flag.
+ }
+
+ scoped_cftyperef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+ NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+ if (!login_items.get()) {
+ LOG(ERROR) << "Couldn't get a Login Items list.";
+ return;
+ }
+
+ // Remove the old item, it has wrong hide flag, we'll create a new one.
+ if (item.get()) {
+ LSSharedFileListItemRemove(login_items, item);
+ }
+
+ NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
+
+ BOOL hide = hide_on_startup ? YES : NO;
+ NSDictionary* properties =
+ [NSDictionary
+ dictionaryWithObject:[NSNumber numberWithBool:hide]
+ forKey:(NSString*)kLSSharedFileListLoginItemHidden];
+
+ scoped_cftyperef<LSSharedFileListItemRef> new_item;
+ new_item.reset(LSSharedFileListInsertItemURL(
+ login_items, kLSSharedFileListItemLast, NULL, NULL,
+ reinterpret_cast<CFURLRef>(url),
+ reinterpret_cast<CFDictionaryRef>(properties), NULL));
+
+ if (!new_item.get()) {
+ LOG(ERROR) << "Couldn't insert current app into Login Items list.";
+ }
+}
+
+void RemoveFromLoginItems() {
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (!item.get())
+ return;
+
+ scoped_cftyperef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+ NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+ if (!login_items.get()) {
+ LOG(ERROR) << "Couldn't get a Login Items list.";
+ return;
+ }
+
+ LSSharedFileListItemRemove(login_items, item);
+}
+
+bool WasLaunchedAsHiddenLoginItem() {
+ if (!WasLaunchedAsLoginItem())
+ return false;
+
+ scoped_cftyperef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+ if (!item.get()) {
+ LOG(ERROR) << "Process launched at Login but can't access Login Item List.";
+ return false;
+ }
+ return IsHiddenLoginItem(item);
+}
+
} // namespace mac_util
diff --git a/base/mac_util_unittest.mm b/base/mac_util_unittest.mm
index aebb731..f590ac1 100644
--- a/base/mac_util_unittest.mm
+++ b/base/mac_util_unittest.mm
@@ -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.
@@ -165,6 +165,21 @@ TEST_F(MacUtilTest, TestGetValueFromDictionary) {
dict, CFSTR("no-exist"), CFStringGetTypeID()));
}
+TEST_F(MacUtilTest, CopyNSImageToCGImage) {
+ scoped_nsobject<NSImage> nsImage(
+ [[NSImage alloc] initWithSize:NSMakeSize(20, 20)]);
+ [nsImage lockFocus];
+ [[NSColor redColor] set];
+ NSRect rect = NSZeroRect;
+ rect.size = [nsImage size];
+ NSRectFill(rect);
+ [nsImage unlockFocus];
+
+ scoped_cftyperef<CGImageRef> cgImage(
+ mac_util::CopyNSImageToCGImage(nsImage.get()));
+ EXPECT_TRUE(cgImage.get());
+}
+
} // namespace
} // namespace mac_util
diff --git a/base/mach_ipc_mac.h b/base/mach_ipc_mac.h
index 1e88279..d506a00 100644
--- a/base/mach_ipc_mac.h
+++ b/base/mach_ipc_mac.h
@@ -4,6 +4,7 @@
#ifndef BASE_MACH_IPC_MAC_H_
#define BASE_MACH_IPC_MAC_H_
+#pragma once
#include <mach/mach.h>
#include <mach/message.h>
@@ -19,7 +20,7 @@
//
// The three main classes of interest are
//
-// MachMessage: a wrapper for a mach message of the following form
+// MachMessage: a wrapper for a Mach message of the following form
// mach_msg_header_t
// mach_msg_body_t
// optional descriptors
@@ -29,10 +30,10 @@
// and are used instead of MachMessage which is an abstract base class
//
// ReceivePort:
-// Represents a mach port for which we have receive rights
+// Represents a Mach port for which we have receive rights
//
// MachPortSender:
-// Represents a mach port for which we have send rights
+// Represents a Mach port for which we have send rights
//
// Here's an example to receive a message on a server port:
//
@@ -113,12 +114,6 @@ class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
return disposition;
}
- // We're just a simple wrapper for mach_msg_port_descriptor_t
- // and have the same memory layout
- operator mach_msg_port_descriptor_t&() {
- return *this;
- }
-
// For convenience
operator mach_port_t() const {
return GetMachPort();
@@ -126,7 +121,7 @@ class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
};
//==============================================================================
-// MachMessage: a wrapper for a mach message
+// MachMessage: a wrapper for a Mach message
// (mach_msg_header_t, mach_msg_body_t, extra data)
//
// This considerably simplifies the construction of a message for sending
@@ -164,7 +159,7 @@ class MachMessage {
int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
- // Adds a descriptor (typically a mach port) to be translated
+ // Adds a descriptor (typically a Mach port) to be translated
// returns true if successful, otherwise not enough space
bool AddDescriptor(const MachMsgPortDescriptor &desc);
@@ -174,7 +169,7 @@ class MachMessage {
MachMsgPortDescriptor *GetDescriptor(int n);
- // Convenience method which gets the mach port described by the descriptor
+ // Convenience method which gets the Mach port described by the descriptor
mach_port_t GetTranslatedPort(int n);
// A simple message is one with no descriptors
@@ -211,7 +206,7 @@ class MachMessage {
int CalculateSize();
// Returns total storage size that this object can grow to, this is inclusive
- // of the mach header.
+ // of the Mach header.
size_t MaxSize() const { return storage_length_bytes_; }
protected:
@@ -241,7 +236,7 @@ class MachMessage {
//==============================================================================
// MachReceiveMessage and MachSendMessage are useful to separate the idea
-// of a mach message being sent and being received, and adds increased type
+// of a Mach message being sent and being received, and adds increased type
// safety:
// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
// MachPortSender::SendMessage() only accepts a MachSendMessage
@@ -270,26 +265,27 @@ class MachSendMessage : public MachMessage {
};
//==============================================================================
-// Represents a mach port for which we have receive rights
+// Represents a Mach port for which we have receive rights
class ReceivePort {
public:
- // Creates a new mach port for receiving messages and registers a name for it
+ // Creates a new Mach port for receiving messages and registers a name for it
explicit ReceivePort(const char *receive_port_name);
- // Given an already existing mach port, use it. We take ownership of the
+ // Given an already existing Mach port, use it. We take ownership of the
// port and deallocate it in our destructor.
explicit ReceivePort(mach_port_t receive_port);
- // Create a new mach port for receiving messages
+ // Create a new Mach port for receiving messages
ReceivePort();
~ReceivePort();
- // Waits on the mach port until message received or timeout
+ // Waits on the Mach port until message received or timeout. If |timeout| is
+ // MACH_MSG_TIMEOUT_NONE, this method waits forever.
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
mach_msg_timeout_t timeout);
- // The underlying mach port that we wrap
+ // The underlying Mach port that we wrap
mach_port_t GetPort() const { return port_; }
private:
@@ -300,14 +296,14 @@ class ReceivePort {
};
//==============================================================================
-// Represents a mach port for which we have send rights
+// Represents a Mach port for which we have send rights
class MachPortSender {
public:
// get a port with send rights corresponding to a named registered service
explicit MachPortSender(const char *receive_port_name);
- // Given an already existing mach port, use it. Does not take ownership of
+ // Given an already existing Mach port, use it. Does not take ownership of
// |send_port|.
explicit MachPortSender(mach_port_t send_port);
diff --git a/base/mach_ipc_mac.mm b/base/mach_ipc_mac.mm
index 973b66a..a0bfdc8 100644
--- a/base/mach_ipc_mac.mm
+++ b/base/mach_ipc_mac.mm
@@ -198,7 +198,12 @@ ReceivePort::ReceivePort(const char *receive_port_name) {
if (init_result_ != KERN_SUCCESS)
return;
- NSPort *ns_port = [NSMachPort portWithMachPort:port_];
+ // Without |NSMachPortDeallocateNone|, the NSMachPort seems to deallocate
+ // receive rights on port when it is eventually released. It is not necessary
+ // to deallocate any rights here as |port_| is fully deallocated in the
+ // ReceivePort destructor.
+ NSPort *ns_port = [NSMachPort portWithMachPort:port_
+ options:NSMachPortDeallocateNone];
NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
[[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
}
@@ -252,8 +257,12 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
out_message->Head()->msgh_reserved = 0;
out_message->Head()->msgh_id = 0;
+ mach_msg_option_t rcv_options = MACH_RCV_MSG;
+ if (timeout != MACH_MSG_TIMEOUT_NONE)
+ rcv_options |= MACH_RCV_TIMEOUT;
+
kern_return_t result = mach_msg(out_message->Head(),
- MACH_RCV_MSG | MACH_RCV_TIMEOUT,
+ rcv_options,
0,
out_message->MaxSize(),
port_,
diff --git a/base/md5.h b/base/md5.h
index 227e008..5ab6e32 100644
--- a/base/md5.h
+++ b/base/md5.h
@@ -4,6 +4,7 @@
#ifndef BASE_MD5_H_
#define BASE_MD5_H_
+#pragma once
#include <string>
diff --git a/base/memory_debug.h b/base/memory_debug.h
index 1963268..6d8c7f9 100644
--- a/base/memory_debug.h
+++ b/base/memory_debug.h
@@ -8,6 +8,7 @@
#ifndef BASE_MEMORY_DEBUG_H_
#define BASE_MEMORY_DEBUG_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 3728ef2..8ed0bfc 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -11,7 +11,6 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/message_pump_default.h"
-#include "base/string_util.h"
#include "base/thread_local.h"
#if defined(OS_MACOSX)
@@ -185,24 +184,26 @@ MessageLoop::~MessageLoop() {
lazy_tls_ptr.Pointer()->Set(NULL);
}
-void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
+void MessageLoop::AddDestructionObserver(
+ DestructionObserver* destruction_observer) {
DCHECK(this == current());
- destruction_observers_.AddObserver(obs);
+ destruction_observers_.AddObserver(destruction_observer);
}
-void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
+void MessageLoop::RemoveDestructionObserver(
+ DestructionObserver* destruction_observer) {
DCHECK(this == current());
- destruction_observers_.RemoveObserver(obs);
+ destruction_observers_.RemoveObserver(destruction_observer);
}
-void MessageLoop::AddTaskObserver(TaskObserver *obs) {
+void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
DCHECK_EQ(this, current());
- task_observers_.AddObserver(obs);
+ task_observers_.AddObserver(task_observer);
}
-void MessageLoop::RemoveTaskObserver(TaskObserver *obs) {
+void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
DCHECK_EQ(this, current());
- task_observers_.RemoveObserver(obs);
+ task_observers_.RemoveObserver(task_observer);
}
void MessageLoop::Run() {
diff --git a/base/message_loop.h b/base/message_loop.h
index ca6da55..2b7c7c8 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_LOOP_H_
#define BASE_MESSAGE_LOOP_H_
+#pragma once
#include <queue>
#include <string>
@@ -90,8 +91,10 @@ class MessageLoop : public base::MessagePump::Delegate {
//
class DestructionObserver {
public:
- virtual ~DestructionObserver();
virtual void WillDestroyCurrentMessageLoop() = 0;
+
+ protected:
+ virtual ~DestructionObserver();
};
// Add a DestructionObserver, which will start receiving notifications
diff --git a/base/message_loop_proxy.cc b/base/message_loop_proxy.cc
new file mode 100644
index 0000000..bc7088d
--- /dev/null
+++ b/base/message_loop_proxy.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.
+
+#include "base/message_loop_proxy.h"
+
+namespace base {
+
+MessageLoopProxy::MessageLoopProxy() {
+}
+
+MessageLoopProxy::~MessageLoopProxy() {
+}
+
+void MessageLoopProxy::OnDestruct() {
+ delete this;
+}
+
+} // namespace base
diff --git a/base/message_loop_proxy.h b/base/message_loop_proxy.h
index 10d5368..20e9e10 100644
--- a/base/message_loop_proxy.h
+++ b/base/message_loop_proxy.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_LOOP_PROXY_H_
#define BASE_MESSAGE_LOOP_PROXY_H_
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
@@ -56,13 +57,12 @@ class MessageLoopProxy
protected:
friend struct MessageLoopProxyTraits;
- virtual ~MessageLoopProxy() { }
+ MessageLoopProxy();
+ virtual ~MessageLoopProxy();
// Called when the proxy is about to be deleted. Subclasses can override this
// to provide deletion on specific threads.
- virtual void OnDestruct() {
- delete this;
- }
+ virtual void OnDestruct();
};
struct MessageLoopProxyTraits {
diff --git a/base/message_loop_proxy_impl.h b/base/message_loop_proxy_impl.h
index f895532..b93bb64 100644
--- a/base/message_loop_proxy_impl.h
+++ b/base/message_loop_proxy_impl.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_LOOP_PROXY_IMPL_H_
#define BASE_MESSAGE_LOOP_PROXY_IMPL_H_
+#pragma once
#include "base/lock.h"
#include "base/message_loop.h"
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index 719a01a..e21ac63 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_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 <vector>
+
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/message_loop.h"
@@ -839,8 +841,8 @@ class Recursive2Tasks : public Task {
for (;;) {
HWND button = FindWindowEx(window, NULL, L"Button", NULL);
if (button != NULL) {
- EXPECT_TRUE(0 == SendMessage(button, WM_LBUTTONDOWN, 0, 0));
- EXPECT_TRUE(0 == SendMessage(button, WM_LBUTTONUP, 0, 0));
+ EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
+ EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
break;
}
}
@@ -1379,6 +1381,7 @@ TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
// TODO(darin): MessageLoop does not support deleting all tasks in the
// destructor.
+// Fails, http://crbug.com/50272.
TEST(MessageLoopTest, FAILS_EnsureTaskDeletion) {
RunTest_EnsureTaskDeletion(MessageLoop::TYPE_DEFAULT);
RunTest_EnsureTaskDeletion(MessageLoop::TYPE_UI);
@@ -1387,6 +1390,7 @@ TEST(MessageLoopTest, FAILS_EnsureTaskDeletion) {
// TODO(darin): MessageLoop does not support deleting all tasks in the
// destructor.
+// Fails, http://crbug.com/50272.
TEST(MessageLoopTest, FAILS_EnsureTaskDeletion_Chain) {
RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_DEFAULT);
RunTest_EnsureTaskDeletion_Chain(MessageLoop::TYPE_UI);
@@ -1459,7 +1463,7 @@ TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) {
class DummyTask : public Task {
public:
- DummyTask(int num_tasks) : num_tasks_(num_tasks) {}
+ explicit DummyTask(int num_tasks) : num_tasks_(num_tasks) {}
virtual void Run() {
if (num_tasks_ > 1) {
@@ -1477,7 +1481,7 @@ class DummyTask : public Task {
class DummyTaskObserver : public MessageLoop::TaskObserver {
public:
- DummyTaskObserver(int num_tasks)
+ explicit DummyTaskObserver(int num_tasks)
: num_tasks_started_(0),
num_tasks_processed_(0),
num_tasks_(num_tasks) {}
@@ -1593,7 +1597,7 @@ TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) {
// pipe() is just the easiest way to do it.
int pipefds[2];
int err = pipe(pipefds);
- ASSERT_TRUE(err == 0);
+ ASSERT_EQ(0, err);
int fd = pipefds[1];
{
// Arrange for controller to live longer than message loop.
@@ -1618,7 +1622,7 @@ TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
// (Errors only showed up in valgrind.)
int pipefds[2];
int err = pipe(pipefds);
- ASSERT_TRUE(err == 0);
+ ASSERT_EQ(0, err);
int fd = pipefds[1];
{
// Arrange for message loop to live longer than controller.
diff --git a/base/message_pump.cc b/base/message_pump.cc
new file mode 100644
index 0000000..de7c517
--- /dev/null
+++ b/base/message_pump.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 "base/message_pump.h"
+
+namespace base {
+
+MessagePump::MessagePump() {
+}
+
+MessagePump::~MessagePump() {
+}
+
+} // namespace base
diff --git a/base/message_pump.h b/base/message_pump.h
index 9ae9e2c..f8a097d 100644
--- a/base/message_pump.h
+++ b/base/message_pump.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_PUMP_H_
#define BASE_MESSAGE_PUMP_H_
+#pragma once
#include "base/ref_counted.h"
@@ -39,7 +40,8 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
virtual bool DoIdleWork() = 0;
};
- virtual ~MessagePump() {}
+ MessagePump();
+ virtual ~MessagePump();
// The Run method is called to enter the message pump's run loop.
//
diff --git a/base/message_pump_default.h b/base/message_pump_default.h
index aa0dab9..0ac6cd4 100644
--- a/base/message_pump_default.h
+++ b/base/message_pump_default.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_PUMP_DEFAULT_H_
#define BASE_MESSAGE_PUMP_DEFAULT_H_
+#pragma once
#include "base/message_pump.h"
#include "base/time.h"
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc
index f027fdc..e85a712 100644
--- a/base/message_pump_glib.cc
+++ b/base/message_pump_glib.cc
@@ -124,6 +124,22 @@ GSourceFuncs WorkSourceFuncs = {
namespace base {
+struct MessagePumpForUI::RunState {
+ Delegate* delegate;
+ Dispatcher* dispatcher;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+
+ // This keeps the state of whether the pump got signaled that there was new
+ // work to be done. Since we eat the message on the wake up pipe as soon as
+ // we get it, we keep that state here to stay consistent.
+ bool has_work;
+};
+
MessagePumpForUI::MessagePumpForUI()
: state_(NULL),
context_(g_main_context_default()),
diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h
index d140dbf..f6d022a 100644
--- a/base/message_pump_glib.h
+++ b/base/message_pump_glib.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_PUMP_GLIB_H_
#define BASE_MESSAGE_PUMP_GLIB_H_
+#pragma once
#include "base/message_pump.h"
#include "base/observer_list.h"
@@ -81,21 +82,7 @@ class MessagePumpForUI : public MessagePump {
private:
// We may make recursive calls to Run, so we save state that needs to be
// separate between them in this structure type.
- struct RunState {
- Delegate* delegate;
- Dispatcher* dispatcher;
-
- // Used to flag that the current Run() invocation should return ASAP.
- bool should_quit;
-
- // Used to count how many Run() invocations are on the stack.
- int run_depth;
-
- // This keeps the state of whether the pump got signaled that there was new
- // work to be done. Since we eat the message on the wake up pipe as soon as
- // we get it, we keep that state here to stay consistent.
- bool has_work;
- };
+ struct RunState;
// Invoked from EventDispatcher. Notifies all observers we're about to
// process an event.
diff --git a/base/message_pump_glib_unittest.cc b/base/message_pump_glib_unittest.cc
index cb9a84f..72d2fbf 100644
--- a/base/message_pump_glib_unittest.cc
+++ b/base/message_pump_glib_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.
@@ -10,7 +10,6 @@
#include <algorithm>
#include <vector>
-#include "base/logging.h"
#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "base/ref_counted.h"
diff --git a/base/message_pump_libevent.h b/base/message_pump_libevent.h
index 6516128..f271612 100644
--- a/base/message_pump_libevent.h
+++ b/base/message_pump_libevent.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_PUMP_LIBEVENT_H_
#define BASE_MESSAGE_PUMP_LIBEVENT_H_
+#pragma once
#include "base/basictypes.h"
#include "base/message_pump.h"
diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h
index 3234000..59a7329 100644
--- a/base/message_pump_mac.h
+++ b/base/message_pump_mac.h
@@ -29,6 +29,7 @@
#ifndef BASE_MESSAGE_PUMP_MAC_H_
#define BASE_MESSAGE_PUMP_MAC_H_
+#pragma once
#include "base/message_pump.h"
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc
index 6fa3e7d..fc4b2e4 100644
--- a/base/message_pump_win.cc
+++ b/base/message_pump_win.cc
@@ -7,7 +7,6 @@
#include <math.h>
#include "base/histogram.h"
-#include "base/win_util.h"
using base::Time;
diff --git a/base/message_pump_win.h b/base/message_pump_win.h
index 9608187..d7d53cb 100644
--- a/base/message_pump_win.h
+++ b/base/message_pump_win.h
@@ -4,6 +4,7 @@
#ifndef BASE_MESSAGE_PUMP_WIN_H_
#define BASE_MESSAGE_PUMP_WIN_H_
+#pragma once
#include <windows.h>
diff --git a/base/mime_util.h b/base/mime_util.h
index 58cb630..6212b31 100644
--- a/base/mime_util.h
+++ b/base/mime_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_MIME_UTIL_H_
#define BASE_MIME_UTIL_H_
+#pragma once
#include <string>
diff --git a/base/mime_util_xdg.cc b/base/mime_util_xdg.cc
index d00a568..5dc4960 100644
--- a/base/mime_util_xdg.cc
+++ b/base/mime_util_xdg.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.
@@ -18,6 +18,7 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/third_party/xdg_mime/xdgmime.h"
@@ -272,7 +273,7 @@ bool IconTheme::LoadIndexTheme(const FilePath& file) {
std::string key, value;
std::vector<std::string> r;
- SplitStringDontTrim(entry, '=', &r);
+ base::SplitStringDontTrim(entry, '=', &r);
if (r.size() < 2)
continue;
diff --git a/base/move.h b/base/move.h
index eb66070..118eb0a 100644
--- a/base/move.h
+++ b/base/move.h
@@ -4,6 +4,7 @@
#ifndef BASE_MOVE_H_
#define BASE_MOVE_H_
+#pragma once
#include <algorithm>
diff --git a/base/multiprocess_test.h b/base/multiprocess_test.h
deleted file mode 100644
index 4fa5693..0000000
--- a/base/multiprocess_test.h
+++ /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.
-
-#ifndef BASE_MULTIPROCESS_TEST_H_
-#define BASE_MULTIPROCESS_TEST_H_
-
-#include "base/base_switches.h"
-#include "base/command_line.h"
-#include "base/process_util.h"
-#include "base/string_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/multiprocess_func_list.h"
-#include "testing/platform_test.h"
-
-#if defined(OS_POSIX)
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-// Command line switch to invoke a child process rather than
-// to run the normal test suite.
-static const char kRunClientProcess[] = "client";
-
-// A MultiProcessTest is a test class which makes it easier to
-// write a test which requires code running out of process.
-//
-// To create a multiprocess test simply follow these steps:
-//
-// 1) Derive your test from MultiProcessTest. Example:
-//
-// class MyTest : public MultiProcessTest {
-// };
-//
-// TEST_F(MyTest, TestCaseName) {
-// ...
-// }
-//
-// 2) Create a mainline function for the child processes and include
-// testing/multiprocess_func_list.h.
-// See the declaration of the MULTIPROCESS_TEST_MAIN macro
-// in that file for an example.
-// 3) Call SpawnChild(L"foo"), where "foo" is the name of
-// the function you wish to run in the child processes.
-// That's it!
-//
-class MultiProcessTest : public PlatformTest {
- protected:
- // Run a child process.
- // 'procname' is the name of a function which the child will
- // execute. It must be exported from this library in order to
- // run.
- //
- // Example signature:
- // extern "C" int __declspec(dllexport) FooBar() {
- // // do client work here
- // }
- //
- // Returns the handle to the child, or NULL on failure
- //
- // TODO(darin): re-enable this once we have base/debug_util.h
- // ProcessDebugFlags(&cl, DebugUtil::UNKNOWN, false);
- base::ProcessHandle SpawnChild(const std::wstring& procname) {
- return SpawnChild(procname, false);
- }
-
- base::ProcessHandle SpawnChild(const std::wstring& procname,
- bool debug_on_start) {
-#if defined(OS_WIN)
- return SpawnChildImpl(procname, debug_on_start);
-#elif defined(OS_POSIX)
- base::file_handle_mapping_vector empty_file_list;
- return SpawnChildImpl(procname, empty_file_list, debug_on_start);
-#endif
- }
-
-#if defined(OS_POSIX)
- base::ProcessHandle SpawnChild(
- const std::wstring& procname,
- const base::file_handle_mapping_vector& fds_to_map,
- bool debug_on_start) {
- return SpawnChildImpl(procname, fds_to_map, debug_on_start);
- }
-#endif
-
-protected:
- CommandLine MakeCmdLine(const std::wstring& procname, bool debug_on_start) {
- CommandLine cl(*CommandLine::ForCurrentProcess());
- cl.AppendSwitchWithValue(kRunClientProcess, procname);
- if (debug_on_start)
- cl.AppendSwitch(switches::kDebugOnStart);
- return cl;
- }
-
- private:
-#if defined(OS_WIN)
- base::ProcessHandle SpawnChildImpl(const std::wstring& procname,
- bool debug_on_start) {
- base::ProcessHandle handle = static_cast<base::ProcessHandle>(NULL);
- base::LaunchApp(MakeCmdLine(procname, debug_on_start),
- false, true, &handle);
- return handle;
- }
-
-#elif defined(OS_POSIX)
- // TODO(port): with the CommandLine refactoring, this code is very similar
- // to the Windows code. Investigate whether this can be made shorter.
- base::ProcessHandle SpawnChildImpl(
- const std::wstring& procname,
- const base::file_handle_mapping_vector& fds_to_map,
- bool debug_on_start) {
- base::ProcessHandle handle = base::kNullProcessHandle;
- base::LaunchApp(MakeCmdLine(procname, debug_on_start).argv(),
- fds_to_map, false, &handle);
- return handle;
- }
-#endif
-};
-
-#endif // BASE_MULTIPROCESS_TEST_H_
diff --git a/base/native_library.h b/base/native_library.h
index c37e3a4..2bb8497 100644
--- a/base/native_library.h
+++ b/base/native_library.h
@@ -4,6 +4,7 @@
#ifndef BASE_NATIVE_LIBRARY_H_
#define BASE_NATIVE_LIBRARY_H_
+#pragma once
// This file defines a cross-platform "NativeLibrary" type which represents
// a loadable module.
diff --git a/base/native_library_linux.cc b/base/native_library_linux.cc
index 99e32c6..b6d7aef 100644
--- a/base/native_library_linux.cc
+++ b/base/native_library_linux.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.
@@ -8,7 +8,7 @@
#include "base/file_path.h"
#include "base/logging.h"
-#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
namespace base {
diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm
index 8aaeeb1..d13a4b6 100644
--- a/base/native_library_mac.mm
+++ b/base/native_library_mac.mm
@@ -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.
@@ -11,6 +11,7 @@
#include "base/file_util.h"
#include "base/scoped_cftyperef.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
namespace base {
diff --git a/base/native_library_win.cc b/base/native_library_win.cc
index 1c7accf..94e4b63 100644
--- a/base/native_library_win.cc
+++ b/base/native_library_win.cc
@@ -7,7 +7,7 @@
#include <windows.h>
#include "base/file_util.h"
-#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
namespace base {
diff --git a/base/no_windows2000_unittest.h b/base/no_windows2000_unittest.h
index 5870925..4aae07d 100644
--- a/base/no_windows2000_unittest.h
+++ b/base/no_windows2000_unittest.h
@@ -4,6 +4,7 @@
#ifndef BASE_NO_WINDOWS2000_UNITTEST_H_
#define BASE_NO_WINDOWS2000_UNITTEST_H_
+#pragma once
#include "testing/gtest/include/gtest/gtest.h"
#include "base/win_util.h"
diff --git a/base/non_thread_safe.cc b/base/non_thread_safe.cc
index d8a91c6..6889101 100644
--- a/base/non_thread_safe.cc
+++ b/base/non_thread_safe.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,12 +9,8 @@
#include "base/logging.h"
-NonThreadSafe::NonThreadSafe()
- : valid_thread_id_(PlatformThread::CurrentId()) {
-}
-
bool NonThreadSafe::CalledOnValidThread() const {
- return valid_thread_id_ == PlatformThread::CurrentId();
+ return thread_checker_.CalledOnValidThread();
}
NonThreadSafe::~NonThreadSafe() {
diff --git a/base/non_thread_safe.h b/base/non_thread_safe.h
index 1da46aa..e435884 100644
--- a/base/non_thread_safe.h
+++ b/base/non_thread_safe.h
@@ -1,11 +1,13 @@
-// 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.
-#ifndef BASE_NON_THREAD_SAFE_H__
-#define BASE_NON_THREAD_SAFE_H__
+#ifndef BASE_NON_THREAD_SAFE_H_
+#define BASE_NON_THREAD_SAFE_H_
+#pragma once
#include "base/platform_thread.h"
+#include "base/thread_checker.h"
// A helper class used to help verify that methods of a class are
// called from the same thread. One can inherit from this class and use
@@ -28,25 +30,21 @@
#ifndef NDEBUG
class NonThreadSafe {
public:
- NonThreadSafe();
~NonThreadSafe();
bool CalledOnValidThread() const;
private:
- PlatformThreadId valid_thread_id_;
+ ThreadChecker thread_checker_;
};
#else
// Do nothing in release mode.
class NonThreadSafe {
public:
- NonThreadSafe() {}
- ~NonThreadSafe() {}
-
bool CalledOnValidThread() const {
return true;
}
};
#endif // NDEBUG
-#endif // BASE_NON_THREAD_SAFE_H__
+#endif // BASE_NON_THREAD_SAFE_H_
diff --git a/base/non_thread_safe_unittest.cc b/base/non_thread_safe_unittest.cc
new file mode 100644
index 0000000..0603987
--- /dev/null
+++ b/base/non_thread_safe_unittest.cc
@@ -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.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/non_thread_safe.h"
+#include "base/scoped_ptr.h"
+#include "base/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#ifndef NDEBUG
+
+// Simple class to exersice the basics of NonThreadSafe.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class NonThreadSafeClass : public NonThreadSafe {
+ public:
+ NonThreadSafeClass() {}
+
+ // Verifies that it was called on the same thread as the constructor.
+ void DoStuff() {
+ DCHECK(CalledOnValidThread());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
+};
+
+// Calls NonThreadSafeClass::DoStuff on another thread.
+class CallDoStuffOnThread : public base::SimpleThread {
+ public:
+ CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class)
+ : SimpleThread("call_do_stuff_on_thread"),
+ non_thread_safe_class_(non_thread_safe_class) {
+ }
+
+ virtual void Run() {
+ non_thread_safe_class_->DoStuff();
+ }
+
+ private:
+ NonThreadSafeClass* non_thread_safe_class_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
+};
+
+// Deletes NonThreadSafeClass on a different thread.
+class DeleteNonThreadSafeClassOnThread : public base::SimpleThread {
+ public:
+ DeleteNonThreadSafeClassOnThread(NonThreadSafeClass* non_thread_safe_class)
+ : SimpleThread("delete_non_thread_safe_class_on_thread"),
+ non_thread_safe_class_(non_thread_safe_class) {
+ }
+
+ virtual void Run() {
+ non_thread_safe_class_.reset();
+ }
+
+ private:
+ scoped_ptr<NonThreadSafeClass> non_thread_safe_class_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
+};
+
+TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
+ scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+ new NonThreadSafeClass);
+
+ // Verify that DoStuff doesn't assert.
+ non_thread_safe_class->DoStuff();
+
+ // Verify that the destructor doesn't assert.
+ non_thread_safe_class.reset();
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThread) {
+ ASSERT_DEBUG_DEATH({
+ scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+ new NonThreadSafeClass);
+
+ // Verify that DoStuff asserts when called on a different thread.
+ CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
+
+ call_on_thread.Start();
+ call_on_thread.Join();
+ }, "");
+}
+
+TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThread) {
+ ASSERT_DEBUG_DEATH({
+ scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+ new NonThreadSafeClass);
+
+ // Verify that the destructor asserts when called on a different thread.
+ DeleteNonThreadSafeClassOnThread delete_on_thread(
+ non_thread_safe_class.release());
+
+ delete_on_thread.Start();
+ delete_on_thread.Join();
+ }, "");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#endif // NDEBUG
diff --git a/base/nsimage_cache_mac.h b/base/nsimage_cache_mac.h
index ffa8dbb..b13eac9 100644
--- a/base/nsimage_cache_mac.h
+++ b/base/nsimage_cache_mac.h
@@ -4,6 +4,7 @@
#ifndef BASE_NSIMAGE_CACHE_MAC_H_
#define BASE_NSIMAGE_CACHE_MAC_H_
+#pragma once
#ifdef __OBJC__
@class NSImage;
diff --git a/base/nss_util.cc b/base/nss_util.cc
index cc61bdf..b144881 100644
--- a/base/nss_util.cc
+++ b/base/nss_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2008-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.
@@ -21,18 +21,20 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/singleton.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
// USE_NSS means we use NSS for everything crypto-related. If USE_NSS is not
// defined, such as on Mac and Windows, we use NSS for SSL only -- we don't
// use NSS for crypto or certificate verification, and we don't use the NSS
// certificate and key databases.
#if defined(USE_NSS)
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/lock.h"
#include "base/scoped_ptr.h"
#endif // defined(USE_NSS)
+namespace base {
+
namespace {
#if defined(USE_NSS)
@@ -80,10 +82,10 @@ void UseLocalCacheOfNSSDatabaseIfNFS(const FilePath& database_dir) {
struct statfs buf;
if (statfs(database_dir.value().c_str(), &buf) == 0) {
if (buf.f_type == NFS_SUPER_MAGIC) {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
const char* use_cache_env_var = "NSS_SDB_USE_CACHE";
- if (!env->HasEnv(use_cache_env_var))
- env->SetEnv(use_cache_env_var, "yes");
+ if (!env->HasVar(use_cache_env_var))
+ env->SetVar(use_cache_env_var, "yes");
}
}
#endif // defined(OS_LINUX)
@@ -127,6 +129,7 @@ class NSSInitSingleton {
public:
NSSInitSingleton()
: real_db_slot_(NULL),
+ test_db_slot_(NULL),
root_(NULL),
chromeos_user_logged_in_(false) {
base::EnsureNSPRInit();
@@ -218,6 +221,7 @@ class NSSInitSingleton {
PK11_FreeSlot(real_db_slot_);
real_db_slot_ = NULL;
}
+ CloseTestNSSDB();
if (root_) {
SECMOD_UnloadUserModule(root_);
SECMOD_DestroyModule(root_);
@@ -237,23 +241,30 @@ class NSSInitSingleton {
void OpenPersistentNSSDB() {
if (!chromeos_user_logged_in_) {
chromeos_user_logged_in_ = true;
-
- const std::string modspec =
- StringPrintf("configDir='%s' tokenDescription='Real NSS database'",
- GetDefaultConfigDirectory().value().c_str());
- real_db_slot_ = SECMOD_OpenUserDB(modspec.c_str());
- if (real_db_slot_ == NULL) {
- LOG(ERROR) << "Error opening persistent database (" << modspec
- << "): NSS error code " << PR_GetError();
- } else {
- if (PK11_NeedUserInit(real_db_slot_))
- PK11_InitPin(real_db_slot_, NULL, NULL);
- }
+ real_db_slot_ = OpenUserDB(GetDefaultConfigDirectory(),
+ "Real NSS database");
}
}
#endif // defined(OS_CHROMEOS)
+ bool OpenTestNSSDB(const FilePath& path, const char* description) {
+ test_db_slot_ = OpenUserDB(path, description);
+ return !!test_db_slot_;
+ }
+
+ void CloseTestNSSDB() {
+ if (test_db_slot_) {
+ SECStatus status = SECMOD_CloseUserDB(test_db_slot_);
+ if (status != SECSuccess)
+ LOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
+ PK11_FreeSlot(test_db_slot_);
+ test_db_slot_ = NULL;
+ }
+ }
+
PK11SlotInfo* GetDefaultKeySlot() {
+ if (test_db_slot_)
+ return PK11_ReferenceSlot(test_db_slot_);
if (real_db_slot_)
return PK11_ReferenceSlot(real_db_slot_);
return PK11_GetInternalKeySlot();
@@ -266,7 +277,25 @@ class NSSInitSingleton {
#endif // defined(USE_NSS)
private:
+ static PK11SlotInfo* OpenUserDB(const FilePath& path,
+ const char* description) {
+ const std::string modspec =
+ StringPrintf("configDir='sql:%s' tokenDescription='%s'",
+ path.value().c_str(), description);
+ PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
+ if (db_slot) {
+ if (PK11_NeedUserInit(db_slot))
+ PK11_InitPin(db_slot, NULL, NULL);
+ }
+ else {
+ LOG(ERROR) << "Error opening persistent database (" << modspec
+ << "): NSS error code " << PR_GetError();
+ }
+ return db_slot;
+ }
+
PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL.
+ PK11SlotInfo* test_db_slot_; // Overrides internal key slot and real_db_slot_
SECMODModule *root_;
bool chromeos_user_logged_in_;
#if defined(USE_NSS)
@@ -276,8 +305,6 @@ class NSSInitSingleton {
} // namespace
-namespace base {
-
void EnsureNSPRInit() {
Singleton<NSPRInitSingleton>::get();
}
@@ -287,6 +314,14 @@ void EnsureNSSInit() {
}
#if defined(USE_NSS)
+bool OpenTestNSSDB(const FilePath& path, const char* description) {
+ return Singleton<NSSInitSingleton>::get()->OpenTestNSSDB(path, description);
+}
+
+void CloseTestNSSDB() {
+ Singleton<NSSInitSingleton>::get()->CloseTestNSSDB();
+}
+
Lock* GetNSSWriteLock() {
return Singleton<NSSInitSingleton>::get()->write_lock();
}
diff --git a/base/nss_util.h b/base/nss_util.h
index 8de3537..15b624c 100644
--- a/base/nss_util.h
+++ b/base/nss_util.h
@@ -4,10 +4,12 @@
#ifndef BASE_NSS_UTIL_H_
#define BASE_NSS_UTIL_H_
+#pragma once
#include "base/basictypes.h"
#if defined(USE_NSS)
+class FilePath;
class Lock;
#endif // defined(USE_NSS)
@@ -38,6 +40,12 @@ void OpenPersistentNSSDB();
Time PRTimeToBaseTime(int64 prtime);
#if defined(USE_NSS)
+// Exposed for unittests only. |path| should be an existing directory under
+// which the DB files will be placed. |description| is a user-visible name for
+// the DB, as a utf8 string, which will be truncated at 32 bytes.
+bool OpenTestNSSDB(const FilePath& path, const char* description);
+void CloseTestNSSDB();
+
// NSS has a bug which can cause a deadlock or stall in some cases when writing
// to the certDB and keyDB. It also has a bug which causes concurrent key pair
// generations to scribble over each other. To work around this, we synchronize
diff --git a/base/nss_util_internal.h b/base/nss_util_internal.h
index b3ed33f..139740b 100644
--- a/base/nss_util_internal.h
+++ b/base/nss_util_internal.h
@@ -4,6 +4,7 @@
#ifndef BASE_NSS_SLOT_UTIL_H_
#define BASE_NSS_SLOT_UTIL_H_
+#pragma once
#include <secmodt.h>
diff --git a/base/nullable_string16.h b/base/nullable_string16.h
index 6f07183..0702549 100644
--- a/base/nullable_string16.h
+++ b/base/nullable_string16.h
@@ -4,6 +4,7 @@
#ifndef BASE_NULLABLE_STRING16_H_
#define BASE_NULLABLE_STRING16_H_
+#pragma once
#include "base/string16.h"
diff --git a/base/object_watcher.h b/base/object_watcher.h
index 0340de0..e05ceac 100644
--- a/base/object_watcher.h
+++ b/base/object_watcher.h
@@ -4,6 +4,7 @@
#ifndef BASE_OBJECT_WATCHER_H_
#define BASE_OBJECT_WATCHER_H_
+#pragma once
#include <windows.h>
diff --git a/base/observer_list.h b/base/observer_list.h
index 10c6775..ca4b3fd 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -4,6 +4,7 @@
#ifndef BASE_OBSERVER_LIST_H__
#define BASE_OBSERVER_LIST_H__
+#pragma once
#include <algorithm>
#include <limits>
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index f7dabef..d034e6c 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -4,10 +4,10 @@
#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
#define BASE_OBSERVER_LIST_THREADSAFE_H_
+#pragma once
#include <algorithm>
#include <map>
-#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
@@ -53,7 +53,12 @@ template <class ObserverType>
class ObserverListThreadSafe
: public base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> > {
public:
- ObserverListThreadSafe() {}
+ typedef typename ObserverList<ObserverType>::NotificationType
+ NotificationType;
+
+ ObserverListThreadSafe()
+ : type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
+ explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
~ObserverListThreadSafe() {
typename ObserversListMap::const_iterator it;
@@ -74,7 +79,7 @@ class ObserverListThreadSafe
{
AutoLock lock(list_lock_);
if (observer_lists_.find(loop) == observer_lists_.end())
- observer_lists_[loop] = new ObserverList<ObserverType>();
+ observer_lists_[loop] = new ObserverList<ObserverType>(type_);
list = observer_lists_[loop];
}
list->AddObserver(obs);
@@ -177,15 +182,16 @@ class ObserverListThreadSafe
// If there are no more observers on the list, we can now delete it.
if (list->size() == 0) {
-#ifndef NDEBUG
{
AutoLock lock(list_lock_);
- // Verify this list is no longer registered.
+ // Remove |list| if it's not already removed.
+ // This can happen if multiple observers got removed in a notification.
+ // See http://crbug.com/55725.
typename ObserversListMap::iterator it =
observer_lists_.find(MessageLoop::current());
- DCHECK(it == observer_lists_.end() || it->second != list);
+ if (it != observer_lists_.end() && it->second == list)
+ observer_lists_.erase(it);
}
-#endif
delete list;
}
}
@@ -195,6 +201,7 @@ class ObserverListThreadSafe
// These are marked mutable to facilitate having NotifyAll be const.
Lock list_lock_; // Protects the observer_lists_.
ObserversListMap observer_lists_;
+ const NotificationType type_;
DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
};
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
index 6982d3d..71c97d3 100644
--- a/base/observer_list_unittest.cc
+++ b/base/observer_list_unittest.cc
@@ -2,9 +2,12 @@
// 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/observer_list.h"
#include "base/observer_list_threadsafe.h"
+
+#include <vector>
+
+#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "base/ref_counted.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -224,6 +227,46 @@ TEST(ObserverListThreadSafeTest, BasicTest) {
EXPECT_EQ(d.total, -10);
}
+class FooRemover : public Foo {
+ public:
+ explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
+ virtual ~FooRemover() {}
+
+ void AddFooToRemove(Foo* foo) {
+ foos_.push_back(foo);
+ }
+
+ virtual void Observe(int x) {
+ std::vector<Foo*> tmp;
+ tmp.swap(foos_);
+ for (std::vector<Foo*>::iterator it = tmp.begin();
+ it != tmp.end(); ++it) {
+ list_->RemoveObserver(*it);
+ }
+ }
+
+ private:
+ const scoped_refptr<ObserverListThreadSafe<Foo> > list_;
+ std::vector<Foo*> foos_;
+};
+
+TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
+ MessageLoop loop;
+ scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+ new ObserverListThreadSafe<Foo>);
+
+ FooRemover a(observer_list);
+ Adder b(1);
+
+ observer_list->AddObserver(&a);
+ observer_list->AddObserver(&b);
+
+ a.AddFooToRemove(&a);
+ a.AddFooToRemove(&b);
+
+ observer_list->Notify(&Foo::Observe, 1);
+ loop.RunAllPending();
+}
// A test driver for a multi-threaded notification loop. Runs a number
// of observer threads, each of which constantly adds/removes itself
diff --git a/base/path_service.cc b/base/path_service.cc
index e363fe6..8660c42 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -16,7 +16,6 @@
#include "base/lock.h"
#include "base/logging.h"
#include "base/singleton.h"
-#include "base/string_util.h"
namespace base {
bool PathProvider(int key, FilePath* result);
@@ -32,7 +31,6 @@ namespace base {
namespace {
typedef base::hash_map<int, FilePath> PathMap;
-typedef base::hash_set<int> PathSet;
// We keep a linked list of providers. In a debug build we ensure that no two
// providers claim overlapping keys.
@@ -95,8 +93,8 @@ static Provider base_provider_posix = {
struct PathData {
Lock lock;
- PathMap cache; // Track mappings from path key to path value.
- PathSet overrides; // Track whether a path has been overridden.
+ PathMap cache; // Cache mappings from path key to path value.
+ PathMap overrides; // Track path overrides.
Provider* providers; // Linked list of path service providers.
PathData() {
@@ -142,6 +140,20 @@ bool PathService::GetFromCache(int key, FilePath* result) {
}
// static
+bool PathService::GetFromOverrides(int key, FilePath* result) {
+ PathData* path_data = GetPathData();
+ AutoLock scoped_lock(path_data->lock);
+
+ // check for an overriden version.
+ PathMap::const_iterator it = path_data->overrides.find(key);
+ if (it != path_data->overrides.end()) {
+ *result = it->second;
+ return true;
+ }
+ return false;
+}
+
+// static
void PathService::AddToCache(int key, const FilePath& path) {
PathData* path_data = GetPathData();
AutoLock scoped_lock(path_data->lock);
@@ -166,6 +178,9 @@ bool PathService::Get(int key, FilePath* result) {
if (GetFromCache(key, result))
return true;
+ if (GetFromOverrides(key, result))
+ return true;
+
FilePath path;
// search providers for the requested path
@@ -200,14 +215,6 @@ bool PathService::Get(int key, std::wstring* result) {
}
#endif
-bool PathService::IsOverridden(int key) {
- PathData* path_data = GetPathData();
- DCHECK(path_data);
-
- AutoLock scoped_lock(path_data->lock);
- return path_data->overrides.find(key) != path_data->overrides.end();
-}
-
bool PathService::Override(int key, const FilePath& path) {
PathData* path_data = GetPathData();
DCHECK(path_data);
@@ -229,8 +236,14 @@ bool PathService::Override(int key, const FilePath& path) {
return false;
AutoLock scoped_lock(path_data->lock);
+
+ // Clear the cache now. Some of its entries could have depended
+ // on the value we are overriding, and are now out of sync with reality.
+ path_data->cache.clear();
+
path_data->cache[key] = file_path;
- path_data->overrides.insert(key);
+ path_data->overrides[key] = file_path;
+
return true;
}
diff --git a/base/path_service.h b/base/path_service.h
index b0e51e4..4d99cdc 100644
--- a/base/path_service.h
+++ b/base/path_service.h
@@ -4,6 +4,7 @@
#ifndef BASE_PATH_SERVICE_H_
#define BASE_PATH_SERVICE_H_
+#pragma once
#include "build/build_config.h"
@@ -44,9 +45,6 @@ class PathService {
// over the lifetime of the app, so this method should be used with caution.
static bool Override(int key, const FilePath& path);
- // Return whether a path was overridden.
- static bool IsOverridden(int key);
-
// To extend the set of supported keys, you can register a path provider,
// which is just a function mirroring PathService::Get. The ProviderFunc
// returns false if it cannot provide a non-empty path for the given key.
@@ -64,6 +62,7 @@ class PathService {
int key_end);
private:
static bool GetFromCache(int key, FilePath* path);
+ static bool GetFromOverrides(int key, FilePath* path);
static void AddToCache(int key, const FilePath& path);
};
diff --git a/base/pe_image.h b/base/pe_image.h
index f2461d3..968d056 100644
--- a/base/pe_image.h
+++ b/base/pe_image.h
@@ -10,6 +10,7 @@
#ifndef BASE_PE_IMAGE_H_
#define BASE_PE_IMAGE_H_
+#pragma once
#include <windows.h>
#include <DelayIMP.h>
diff --git a/base/perftimer.h b/base/perftimer.h
index 1ac1a7d..dae6d61 100644
--- a/base/perftimer.h
+++ b/base/perftimer.h
@@ -4,6 +4,7 @@
#ifndef BASE_PERFTIMER_H_
#define BASE_PERFTIMER_H_
+#pragma once
#include <string>
diff --git a/base/pickle.h b/base/pickle.h
index fdfdb2b..c7aee67 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -4,6 +4,7 @@
#ifndef BASE_PICKLE_H__
#define BASE_PICKLE_H__
+#pragma once
#include <string>
diff --git a/base/platform_file.h b/base/platform_file.h
index 0dbf4e4..5024717 100644
--- a/base/platform_file.h
+++ b/base/platform_file.h
@@ -4,8 +4,11 @@
#ifndef BASE_PLATFORM_FILE_H_
#define BASE_PLATFORM_FILE_H_
+#pragma once
+#include "base/basictypes.h"
#include "build/build_config.h"
+#include "base/time.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
@@ -36,23 +39,130 @@ enum PlatformFileFlags {
PLATFORM_FILE_ASYNC = 256,
PLATFORM_FILE_TEMPORARY = 512, // Used on Windows only
PLATFORM_FILE_HIDDEN = 1024, // Used on Windows only
- PLATFORM_FILE_DELETE_ON_CLOSE = 2048
+ PLATFORM_FILE_DELETE_ON_CLOSE = 2048,
+ PLATFORM_FILE_TRUNCATE = 4096,
+ PLATFORM_FILE_WRITE_ATTRIBUTES = 8192 // Used on Windows only
+};
+
+// PLATFORM_FILE_ERROR_ACCESS_DENIED is returned when a call fails because of
+// a filesystem restriction. PLATFORM_FILE_ERROR_SECURITY is returned when a
+// browser policy doesn't allow the operation to be executed.
+enum PlatformFileError {
+ PLATFORM_FILE_OK = 0,
+ PLATFORM_FILE_ERROR_FAILED = -1,
+ PLATFORM_FILE_ERROR_IN_USE = -2,
+ PLATFORM_FILE_ERROR_EXISTS = -3,
+ PLATFORM_FILE_ERROR_NOT_FOUND = -4,
+ PLATFORM_FILE_ERROR_ACCESS_DENIED = -5,
+ PLATFORM_FILE_ERROR_TOO_MANY_OPENED = -6,
+ PLATFORM_FILE_ERROR_NO_MEMORY = -7,
+ PLATFORM_FILE_ERROR_NO_SPACE = -8,
+ PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9,
+ PLATFORM_FILE_ERROR_INVALID_OPERATION = -10,
+ PLATFORM_FILE_ERROR_SECURITY = -11,
+ PLATFORM_FILE_ERROR_ABORT = -12
+};
+
+// Used to hold information about a given file.
+// If you add more fields to this structure (platform-specific fields are OK),
+// make sure to update all functions that use it in file_util_{win|posix}.cc
+// too, and the ParamTraits<base::PlatformFileInfo> implementation in
+// chrome/common/common_param_traits.cc.
+struct PlatformFileInfo {
+ // The size of the file in bytes. Undefined when is_directory is true.
+ int64 size;
+
+ // True if the file corresponds to a directory.
+ bool is_directory;
+
+ // The last modified time of a file.
+ base::Time last_modified;
+
+ // The last accessed time of a file.
+ base::Time last_accessed;
+
+ // The creation time of a file.
+ base::Time creation_time;
};
// Creates or opens the given file. If PLATFORM_FILE_OPEN_ALWAYS is used, and
// |created| is provided, |created| will be set to true if the file was created
-// or to false in case the file was just opened.
+// or to false in case the file was just opened. |error_code| can be NULL.
PlatformFile CreatePlatformFile(const FilePath& name,
int flags,
- bool* created);
+ bool* created,
+ PlatformFileError* error_code);
// Deprecated.
PlatformFile CreatePlatformFile(const std::wstring& name,
int flags,
bool* created);
-// Closes a file handle
+// Closes a file handle. Returns |true| on success and |false| otherwise.
bool ClosePlatformFile(PlatformFile file);
+// Reads the given number of bytes (or until EOF is reached) starting with the
+// given offset. Returns the number of bytes read, or -1 on error.
+int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size);
+
+// Writes the given buffer into the file at the given offset, overwritting any
+// data that was previously there. Returns the number of bytes written, or -1
+// on error.
+int WritePlatformFile(PlatformFile file, int64 offset,
+ const char* data, int size);
+
+// Truncates the given file to the given length. If |length| is greater than
+// the current size of the file, the file is extended with zeros. If the file
+// doesn't exist, |false| is returned.
+bool TruncatePlatformFile(PlatformFile file, int64 length);
+
+// Flushes the buffers of the given file.
+bool FlushPlatformFile(PlatformFile file);
+
+// Touches the given file.
+bool TouchPlatformFile(PlatformFile file, const Time& last_access_time,
+ const Time& last_modified_time);
+
+// Returns some information for the given file.
+bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info);
+
+// Use this class to pass ownership of a PlatformFile to a receiver that may or
+// may not want to accept it. This class does not own the storage for the
+// PlatformFile.
+//
+// EXAMPLE:
+//
+// void MaybeProcessFile(PassPlatformFile pass_file) {
+// if (...) {
+// PlatformFile file = pass_file.ReleaseValue();
+// // Now, we are responsible for closing |file|.
+// }
+// }
+//
+// void OpenAndMaybeProcessFile(const FilePath& path) {
+// PlatformFile file = CreatePlatformFile(path, ...);
+// MaybeProcessFile(PassPlatformFile(&file));
+// if (file != kInvalidPlatformFileValue)
+// ClosePlatformFile(file);
+// }
+//
+class PassPlatformFile {
+ public:
+ explicit PassPlatformFile(PlatformFile* value) : value_(value) {
+ }
+
+ // Called to retrieve the PlatformFile stored in this object. The caller
+ // gains ownership of the PlatformFile and is now responsible for closing it.
+ // Any subsequent calls to this method will return an invalid PlatformFile.
+ PlatformFile ReleaseValue() {
+ PlatformFile temp = *value_;
+ *value_ = kInvalidPlatformFileValue;
+ return temp;
+ }
+
+ private:
+ PlatformFile* value_;
+};
+
} // namespace base
#endif // BASE_PLATFORM_FILE_H_
diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc
index 46039b9..4b744fe 100644
--- a/base/platform_file_posix.cc
+++ b/base/platform_file_posix.cc
@@ -8,15 +8,30 @@
#include <errno.h>
#include <sys/stat.h>
+#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
namespace base {
+#if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \
+ (defined(OS_MACOSX) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
+typedef struct stat stat_wrapper_t;
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+ return fstat(fd, sb);
+}
+#else
+typedef struct stat64 stat_wrapper_t;
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+ return fstat64(fd, sb);
+}
+#endif
+
// TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
PlatformFile CreatePlatformFile(const FilePath& name, int flags,
- bool* created) {
+ bool* created, PlatformFileError* error_code) {
int open_flags = 0;
if (flags & PLATFORM_FILE_CREATE)
open_flags = O_CREAT | O_EXCL;
@@ -30,6 +45,8 @@ PlatformFile CreatePlatformFile(const FilePath& name, int flags,
!(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
NOTREACHED();
errno = EOPNOTSUPP;
+ if (error_code)
+ *error_code = PLATFORM_FILE_ERROR_FAILED;
return kInvalidPlatformFileValue;
}
@@ -37,10 +54,16 @@ PlatformFile CreatePlatformFile(const FilePath& name, int flags,
open_flags |= O_RDWR;
} else if (flags & PLATFORM_FILE_WRITE) {
open_flags |= O_WRONLY;
- } else if (!(flags & PLATFORM_FILE_READ)) {
+ } else if (!(flags & PLATFORM_FILE_READ ||
+ flags & PLATFORM_FILE_WRITE_ATTRIBUTES)) {
NOTREACHED();
}
+ if (flags & PLATFORM_FILE_TRUNCATE) {
+ DCHECK(flags & PLATFORM_FILE_WRITE);
+ open_flags |= O_TRUNC;
+ }
+
DCHECK(O_RDONLY == 0);
int descriptor = open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR);
@@ -61,20 +84,112 @@ PlatformFile CreatePlatformFile(const FilePath& name, int flags,
}
}
+ if (created && (descriptor > 0) && (flags & PLATFORM_FILE_CREATE_ALWAYS))
+ *created = true;
+
if ((descriptor > 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
unlink(name.value().c_str());
}
+ if (error_code) {
+ if (descriptor >= 0)
+ *error_code = PLATFORM_FILE_OK;
+ else {
+ switch (errno) {
+ case EACCES:
+ case EISDIR:
+ case EROFS:
+ case EPERM:
+ *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
+ break;
+ case ETXTBSY:
+ *error_code = PLATFORM_FILE_ERROR_IN_USE;
+ break;
+ case EEXIST:
+ *error_code = PLATFORM_FILE_ERROR_EXISTS;
+ break;
+ case ENOENT:
+ *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
+ break;
+ case EMFILE:
+ *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
+ break;
+ case ENOMEM:
+ *error_code = PLATFORM_FILE_ERROR_NO_MEMORY;
+ break;
+ case ENOSPC:
+ *error_code = PLATFORM_FILE_ERROR_NO_SPACE;
+ break;
+ case ENOTDIR:
+ *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
+ break;
+ default:
+ *error_code = PLATFORM_FILE_ERROR_FAILED;
+ }
+ }
+ }
+
return descriptor;
}
PlatformFile CreatePlatformFile(const std::wstring& name, int flags,
bool* created) {
- return CreatePlatformFile(FilePath::FromWStringHack(name), flags, created);
+ return CreatePlatformFile(FilePath::FromWStringHack(name), flags,
+ created, NULL);
}
bool ClosePlatformFile(PlatformFile file) {
- return close(file);
+ return !close(file);
+}
+
+int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
+ if (file < 0)
+ return -1;
+
+ return HANDLE_EINTR(pread(file, data, size, offset));
+}
+
+int WritePlatformFile(PlatformFile file, int64 offset,
+ const char* data, int size) {
+ if (file < 0)
+ return -1;
+
+ return HANDLE_EINTR(pwrite(file, data, size, offset));
+}
+
+bool TruncatePlatformFile(PlatformFile file, int64 length) {
+ return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length)));
+}
+
+bool FlushPlatformFile(PlatformFile file) {
+ return !fsync(file);
+}
+
+bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
+ const base::Time& last_modified_time) {
+ if (file < 0)
+ return false;
+
+ timeval times[2];
+ times[0] = last_access_time.ToTimeVal();
+ times[1] = last_modified_time.ToTimeVal();
+ return !futimes(file, times);
+}
+
+bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
+ if (!info)
+ return false;
+
+ stat_wrapper_t file_info;
+ if (CallFstat(file, &file_info))
+ return false;
+
+ info->is_directory = S_ISDIR(file_info.st_mode);
+ info->size = file_info.st_size;
+ info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
+ info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
+ info->creation_time = base::Time::FromTimeT(file_info.st_ctime);
+ return true;
}
} // namespace base
diff --git a/base/platform_file_unittest.cc b/base/platform_file_unittest.cc
new file mode 100644
index 0000000..90fca1a
--- /dev/null
+++ b/base/platform_file_unittest.cc
@@ -0,0 +1,318 @@
+// Copyright (c) 2010 The Chromium Authors. 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/platform_file.h"
+#include "base/scoped_temp_dir.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Reads from a file the given number of bytes, or until EOF is reached.
+// Returns the number of bytes read.
+int ReadFully(base::PlatformFile file, int64 offset, char* data, int size) {
+ int total_bytes_read = 0;
+ int bytes_read;
+ while (total_bytes_read < size) {
+ bytes_read = base::ReadPlatformFile(
+ file, offset + total_bytes_read, &data[total_bytes_read],
+ size - total_bytes_read);
+
+ // If we reached EOF, bytes_read will be 0.
+ if (bytes_read == 0)
+ return total_bytes_read;
+
+ if ((bytes_read < 0) || (bytes_read > size - total_bytes_read))
+ return -1;
+
+ total_bytes_read += bytes_read;
+ }
+
+ return total_bytes_read;
+}
+
+// Writes the given number of bytes to a file.
+// Returns the number of bytes written.
+int WriteFully(base::PlatformFile file, int64 offset,
+ const char* data, int size) {
+ int total_bytes_written = 0;
+ int bytes_written;
+ while (total_bytes_written < size) {
+ bytes_written = base::WritePlatformFile(
+ file, offset + total_bytes_written, &data[total_bytes_written],
+ size - total_bytes_written);
+
+ if ((bytes_written == 0) && (size == 0))
+ return 0;
+
+ if ((bytes_written <= 0) || (bytes_written > size - total_bytes_written))
+ return -1;
+
+ total_bytes_written += bytes_written;
+ }
+
+ return total_bytes_written;
+}
+
+} // namespace
+
+TEST(PlatformFile, CreatePlatformFile) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
+
+ // Open a file that doesn't exist.
+ base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+ base::PlatformFile file = base::CreatePlatformFile(
+ file_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+ NULL, &error_code);
+ EXPECT_EQ(base::kInvalidPlatformFileValue, file);
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, error_code);
+
+ // Open or create a file.
+ bool created = false;
+ error_code = base::PLATFORM_FILE_OK;
+ file = base::CreatePlatformFile(
+ file_path, base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ,
+ &created, &error_code);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+ EXPECT_TRUE(created);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+ base::ClosePlatformFile(file);
+
+ // Open an existing file.
+ created = false;
+ file = base::CreatePlatformFile(
+ file_path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+ &created, &error_code);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+ EXPECT_FALSE(created);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+ base::ClosePlatformFile(file);
+
+ // Create a file that exists.
+ file = base::CreatePlatformFile(
+ file_path, base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
+ &created, &error_code);
+ EXPECT_EQ(base::kInvalidPlatformFileValue, file);
+ EXPECT_FALSE(created);
+ EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, error_code);
+
+ // Create or overwrite a file.
+ error_code = base::PLATFORM_FILE_OK;
+ file = base::CreatePlatformFile(
+ file_path, base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ,
+ &created, &error_code);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+ EXPECT_TRUE(created);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+ base::ClosePlatformFile(file);
+
+ // Create a delete-on-close file.
+ created = false;
+ file_path = temp_dir.path().AppendASCII("create_file_2");
+ file = base::CreatePlatformFile(
+ file_path,
+ base::PLATFORM_FILE_OPEN_ALWAYS |
+ base::PLATFORM_FILE_DELETE_ON_CLOSE |
+ base::PLATFORM_FILE_READ,
+ &created, &error_code);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+ EXPECT_TRUE(created);
+ EXPECT_EQ(base::PLATFORM_FILE_OK, error_code);
+
+ EXPECT_TRUE(base::ClosePlatformFile(file));
+ EXPECT_FALSE(file_util::PathExists(file_path));
+}
+
+TEST(PlatformFile, ReadWritePlatformFile) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath file_path = temp_dir.path().AppendASCII("read_write_file");
+ base::PlatformFile file = base::CreatePlatformFile(
+ file_path,
+ base::PLATFORM_FILE_CREATE |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE,
+ NULL, NULL);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+
+ char data_to_write[] = "test";
+ const int kTestDataSize = 4;
+
+ // Write 0 bytes to the file.
+ int bytes_written = WriteFully(file, 0, data_to_write, 0);
+ EXPECT_EQ(0, bytes_written);
+
+ // Write "test" to the file.
+ bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize);
+ EXPECT_EQ(kTestDataSize, bytes_written);
+
+ // Read from EOF.
+ char data_read_1[32];
+ int bytes_read = ReadFully(file, kTestDataSize, data_read_1, kTestDataSize);
+ EXPECT_EQ(0, bytes_read);
+
+ // Read from somewhere in the middle of the file.
+ const int kPartialReadOffset = 1;
+ bytes_read = ReadFully(file, kPartialReadOffset, data_read_1, kTestDataSize);
+ EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read);
+ for (int i = 0; i < bytes_read; i++)
+ EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]);
+
+ // Read 0 bytes.
+ bytes_read = ReadFully(file, 0, data_read_1, 0);
+ EXPECT_EQ(0, bytes_read);
+
+ // Read the entire file.
+ bytes_read = ReadFully(file, 0, data_read_1, kTestDataSize);
+ EXPECT_EQ(kTestDataSize, bytes_read);
+ for (int i = 0; i < bytes_read; i++)
+ EXPECT_EQ(data_to_write[i], data_read_1[i]);
+
+ // Write past the end of the file.
+ const int kOffsetBeyondEndOfFile = 10;
+ const int kPartialWriteLength = 2;
+ bytes_written = WriteFully(file, kOffsetBeyondEndOfFile,
+ data_to_write, kPartialWriteLength);
+ EXPECT_EQ(kPartialWriteLength, bytes_written);
+
+ // Make sure the file was extended.
+ int64 file_size = 0;
+ EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
+ EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size);
+
+ // Make sure the file was zero-padded.
+ char data_read_2[32];
+ bytes_read = ReadFully(file, 0, data_read_2, static_cast<int>(file_size));
+ EXPECT_EQ(file_size, bytes_read);
+ for (int i = 0; i < kTestDataSize; i++)
+ EXPECT_EQ(data_to_write[i], data_read_2[i]);
+ for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++)
+ EXPECT_EQ(0, data_read_2[i]);
+ for (int i = kOffsetBeyondEndOfFile; i < file_size; i++)
+ EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]);
+
+ // Close the file handle to allow the temp directory to be deleted.
+ base::ClosePlatformFile(file);
+}
+
+TEST(PlatformFile, TruncatePlatformFile) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath file_path = temp_dir.path().AppendASCII("truncate_file");
+ base::PlatformFile file = base::CreatePlatformFile(
+ file_path,
+ base::PLATFORM_FILE_CREATE |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE,
+ NULL, NULL);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+
+ // Write "test" to the file.
+ char data_to_write[] = "test";
+ int kTestDataSize = 4;
+ int bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize);
+ EXPECT_EQ(kTestDataSize, bytes_written);
+
+ // Extend the file.
+ const int kExtendedFileLength = 10;
+ int64 file_size = 0;
+ EXPECT_TRUE(base::TruncatePlatformFile(file, kExtendedFileLength));
+ EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
+ EXPECT_EQ(kExtendedFileLength, file_size);
+
+ // Make sure the file was zero-padded.
+ char data_read[32];
+ int bytes_read = ReadFully(file, 0, data_read, static_cast<int>(file_size));
+ EXPECT_EQ(file_size, bytes_read);
+ for (int i = 0; i < kTestDataSize; i++)
+ EXPECT_EQ(data_to_write[i], data_read[i]);
+ for (int i = kTestDataSize; i < file_size; i++)
+ EXPECT_EQ(0, data_read[i]);
+
+ // Truncate the file.
+ const int kTruncatedFileLength = 2;
+ EXPECT_TRUE(base::TruncatePlatformFile(file, kTruncatedFileLength));
+ EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size));
+ EXPECT_EQ(kTruncatedFileLength, file_size);
+
+ // Make sure the file was truncated.
+ bytes_read = ReadFully(file, 0, data_read, kTestDataSize);
+ EXPECT_EQ(file_size, bytes_read);
+ for (int i = 0; i < file_size; i++)
+ EXPECT_EQ(data_to_write[i], data_read[i]);
+
+ // Close the file handle to allow the temp directory to be deleted.
+ base::ClosePlatformFile(file);
+}
+
+TEST(PlatformFile, TouchGetInfoPlatformFile) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::PlatformFile file = base::CreatePlatformFile(
+ temp_dir.path().AppendASCII("touch_get_info_file"),
+ base::PLATFORM_FILE_CREATE |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_WRITE_ATTRIBUTES,
+ NULL, NULL);
+ EXPECT_NE(base::kInvalidPlatformFileValue, file);
+
+ // Get info for a newly created file.
+ base::PlatformFileInfo info;
+ EXPECT_TRUE(base::GetPlatformFileInfo(file, &info));
+
+ // Add 2 seconds to account for possible rounding errors on
+ // filesystems that use a 1s or 2s timestamp granularity.
+ base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2);
+ EXPECT_EQ(0, info.size);
+ EXPECT_FALSE(info.is_directory);
+ EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
+ EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
+ EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
+ base::Time creation_time = info.creation_time;
+
+ // Write "test" to the file.
+ char data[] = "test";
+ const int kTestDataSize = 4;
+ int bytes_written = WriteFully(file, 0, data, kTestDataSize);
+ EXPECT_EQ(kTestDataSize, bytes_written);
+
+ // Change the last_accessed and last_modified dates.
+ // It's best to add values that are multiples of 2 (in seconds)
+ // to the current last_accessed and last_modified times, because
+ // FATxx uses a 2s timestamp granularity.
+ base::Time new_last_accessed =
+ info.last_accessed + base::TimeDelta::FromSeconds(234);
+ base::Time new_last_modified =
+ info.last_modified + base::TimeDelta::FromMinutes(567);
+
+ EXPECT_TRUE(base::TouchPlatformFile(file, new_last_accessed,
+ new_last_modified));
+
+ // Make sure the file info was updated accordingly.
+ EXPECT_TRUE(base::GetPlatformFileInfo(file, &info));
+ EXPECT_EQ(info.size, kTestDataSize);
+ EXPECT_FALSE(info.is_directory);
+
+ // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
+#if defined(OS_POSIX)
+ EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec,
+ new_last_accessed.ToTimeVal().tv_sec);
+ EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec,
+ new_last_modified.ToTimeVal().tv_sec);
+#else
+ EXPECT_EQ(info.last_accessed.ToInternalValue(),
+ new_last_accessed.ToInternalValue());
+ EXPECT_EQ(info.last_modified.ToInternalValue(),
+ new_last_modified.ToInternalValue());
+#endif
+
+ EXPECT_EQ(info.creation_time.ToInternalValue(),
+ creation_time.ToInternalValue());
+
+ // Close the file handle to allow the temp directory to be deleted.
+ base::ClosePlatformFile(file);
+}
diff --git a/base/platform_file_win.cc b/base/platform_file_win.cc
index 1143487..63dfef9 100644
--- a/base/platform_file_win.cc
+++ b/base/platform_file_win.cc
@@ -11,7 +11,8 @@ namespace base {
PlatformFile CreatePlatformFile(const FilePath& name,
int flags,
- bool* created) {
+ bool* created,
+ PlatformFileError* error_code) {
DWORD disposition = 0;
if (flags & PLATFORM_FILE_OPEN)
@@ -32,6 +33,12 @@ PlatformFile CreatePlatformFile(const FilePath& name,
disposition = CREATE_ALWAYS;
}
+ if (flags & PLATFORM_FILE_TRUNCATE) {
+ DCHECK(!disposition);
+ DCHECK(flags & PLATFORM_FILE_WRITE);
+ disposition = TRUNCATE_EXISTING;
+ }
+
if (!disposition) {
NOTREACHED();
return NULL;
@@ -40,6 +47,8 @@ PlatformFile CreatePlatformFile(const FilePath& name,
DWORD access = (flags & PLATFORM_FILE_READ) ? GENERIC_READ : 0;
if (flags & PLATFORM_FILE_WRITE)
access |= GENERIC_WRITE;
+ if (flags & PLATFORM_FILE_WRITE_ATTRIBUTES)
+ access |= FILE_WRITE_ATTRIBUTES;
DWORD sharing = (flags & PLATFORM_FILE_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
if (!(flags & PLATFORM_FILE_EXCLUSIVE_WRITE))
@@ -58,9 +67,35 @@ PlatformFile CreatePlatformFile(const FilePath& name,
HANDLE file = CreateFile(name.value().c_str(), access, sharing, NULL,
disposition, create_flags, NULL);
- if ((flags & PLATFORM_FILE_OPEN_ALWAYS) && created &&
- INVALID_HANDLE_VALUE != file) {
- *created = (ERROR_ALREADY_EXISTS != GetLastError());
+ if (created && (INVALID_HANDLE_VALUE != file)) {
+ if (flags & PLATFORM_FILE_OPEN_ALWAYS)
+ *created = (ERROR_ALREADY_EXISTS != GetLastError());
+ else if (flags & PLATFORM_FILE_CREATE_ALWAYS)
+ *created = true;
+ }
+
+ if (error_code) {
+ if (file != kInvalidPlatformFileValue)
+ *error_code = PLATFORM_FILE_OK;
+ else {
+ DWORD last_error = GetLastError();
+ switch (last_error) {
+ case ERROR_SHARING_VIOLATION:
+ *error_code = PLATFORM_FILE_ERROR_IN_USE;
+ break;
+ case ERROR_FILE_EXISTS:
+ *error_code = PLATFORM_FILE_ERROR_EXISTS;
+ break;
+ case ERROR_FILE_NOT_FOUND:
+ *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
+ break;
+ case ERROR_ACCESS_DENIED:
+ *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
+ break;
+ default:
+ *error_code = PLATFORM_FILE_ERROR_FAILED;
+ }
+ }
}
return file;
@@ -68,11 +103,111 @@ PlatformFile CreatePlatformFile(const FilePath& name,
PlatformFile CreatePlatformFile(const std::wstring& name, int flags,
bool* created) {
- return CreatePlatformFile(FilePath::FromWStringHack(name), flags, created);
+ return CreatePlatformFile(FilePath::FromWStringHack(name), flags,
+ created, NULL);
}
bool ClosePlatformFile(PlatformFile file) {
- return (CloseHandle(file) == 0);
+ return (CloseHandle(file) != 0);
+}
+
+int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
+ if (file == kInvalidPlatformFileValue)
+ return -1;
+
+ LARGE_INTEGER offset_li;
+ offset_li.QuadPart = offset;
+
+ OVERLAPPED overlapped = {0};
+ overlapped.Offset = offset_li.LowPart;
+ overlapped.OffsetHigh = offset_li.HighPart;
+
+ DWORD bytes_read;
+ if (::ReadFile(file, data, size, &bytes_read, &overlapped) != 0)
+ return bytes_read;
+ else if (ERROR_HANDLE_EOF == GetLastError())
+ return 0;
+
+ return -1;
+}
+
+int WritePlatformFile(PlatformFile file, int64 offset,
+ const char* data, int size) {
+ if (file == kInvalidPlatformFileValue)
+ return -1;
+
+ LARGE_INTEGER offset_li;
+ offset_li.QuadPart = offset;
+
+ OVERLAPPED overlapped = {0};
+ overlapped.Offset = offset_li.LowPart;
+ overlapped.OffsetHigh = offset_li.HighPart;
+
+ DWORD bytes_written;
+ if (::WriteFile(file, data, size, &bytes_written, &overlapped) != 0)
+ return bytes_written;
+
+ return -1;
+}
+
+bool TruncatePlatformFile(PlatformFile file, int64 length) {
+ if (file == kInvalidPlatformFileValue)
+ return false;
+
+ // Get the current file pointer.
+ LARGE_INTEGER file_pointer;
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+ if (::SetFilePointerEx(file, zero, &file_pointer, FILE_CURRENT) == 0)
+ return false;
+
+ LARGE_INTEGER length_li;
+ length_li.QuadPart = length;
+ // If length > file size, SetFilePointerEx() should extend the file
+ // with zeroes on all Windows standard file systems (NTFS, FATxx).
+ if (!::SetFilePointerEx(file, length_li, NULL, FILE_BEGIN))
+ return false;
+
+ // Set the new file length and move the file pointer to its old position.
+ // This is consistent with ftruncate()'s behavior, even when the file
+ // pointer points to a location beyond the end of the file.
+ return ((::SetEndOfFile(file) != 0) &&
+ (::SetFilePointerEx(file, file_pointer, NULL, FILE_BEGIN) != 0));
+}
+
+bool FlushPlatformFile(PlatformFile file) {
+ return ((file != kInvalidPlatformFileValue) && ::FlushFileBuffers(file));
+}
+
+bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
+ const base::Time& last_modified_time) {
+ if (file == kInvalidPlatformFileValue)
+ return false;
+
+ FILETIME last_access_filetime = last_access_time.ToFileTime();
+ FILETIME last_modified_filetime = last_modified_time.ToFileTime();
+ return (::SetFileTime(file, NULL, &last_access_filetime,
+ &last_modified_filetime) != 0);
+}
+
+bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
+ if (!info)
+ return false;
+
+ BY_HANDLE_FILE_INFORMATION file_info;
+ if (GetFileInformationByHandle(file, &file_info) == 0)
+ return false;
+
+ LARGE_INTEGER size;
+ size.HighPart = file_info.nFileSizeHigh;
+ size.LowPart = file_info.nFileSizeLow;
+ info->size = size.QuadPart;
+ info->is_directory =
+ file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;
+ info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
+ info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
+ info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
+ return true;
}
} // namespace disk_cache
diff --git a/base/platform_thread.h b/base/platform_thread.h
index 4478519..e330422 100644
--- a/base/platform_thread.h
+++ b/base/platform_thread.h
@@ -8,6 +8,7 @@
#ifndef BASE_PLATFORM_THREAD_H_
#define BASE_PLATFORM_THREAD_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/platform_thread_mac.mm b/base/platform_thread_mac.mm
index 428e276..34afea7 100644
--- a/base/platform_thread_mac.mm
+++ b/base/platform_thread_mac.mm
@@ -62,6 +62,7 @@ void PlatformThread::SetName(const char* name) {
// hardcode it.
const int kMaxNameLength = 63;
std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
- if (dynamic_pthread_setname_np(shortened_name.c_str()) < 0)
- PLOG(ERROR) << "pthread_setname_np";
+ // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
+ // See http://crbug.com/47058
+ dynamic_pthread_setname_np(shortened_name.c_str());
}
diff --git a/base/platform_thread_unittest.cc b/base/platform_thread_unittest.cc
new file mode 100644
index 0000000..9875aa8
--- /dev/null
+++ b/base/platform_thread_unittest.cc
@@ -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.
+
+#include "base/platform_thread.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+typedef testing::Test PlatformThreadTest;
+
+// Trivial tests that thread runs and doesn't crash on create and join ---------
+
+class TrivialThread : public PlatformThread::Delegate {
+ public:
+ TrivialThread() : did_run_(false) {}
+
+ virtual void ThreadMain() {
+ did_run_ = true;
+ }
+
+ bool did_run() const { return did_run_; }
+
+ private:
+ bool did_run_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrivialThread);
+};
+
+TEST_F(PlatformThreadTest, Trivial) {
+ TrivialThread thread;
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_FALSE(thread.did_run());
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+ PlatformThread::Join(handle);
+ ASSERT_TRUE(thread.did_run());
+}
+
+TEST_F(PlatformThreadTest, TrivialTimesTen) {
+ TrivialThread thread[10];
+ PlatformThreadHandle handle[arraysize(thread)];
+
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_FALSE(thread[n].did_run());
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+ for (size_t n = 0; n < arraysize(thread); n++)
+ PlatformThread::Join(handle[n]);
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_TRUE(thread[n].did_run());
+}
+
+// Tests of basic thread functions ---------------------------------------------
+
+class FunctionTestThread : public TrivialThread {
+ public:
+ FunctionTestThread() : thread_id_(0) {}
+
+ virtual void ThreadMain() {
+ thread_id_ = PlatformThread::CurrentId();
+ PlatformThread::YieldCurrentThread();
+ PlatformThread::Sleep(50);
+
+ TrivialThread::ThreadMain();
+ }
+
+ PlatformThreadId thread_id() const { return thread_id_; }
+
+ private:
+ PlatformThreadId thread_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
+};
+
+TEST_F(PlatformThreadTest, Function) {
+ PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+ FunctionTestThread thread;
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_FALSE(thread.did_run());
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+ PlatformThread::Join(handle);
+ ASSERT_TRUE(thread.did_run());
+ EXPECT_NE(thread.thread_id(), main_thread_id);
+}
+
+TEST_F(PlatformThreadTest, FunctionTimesTen) {
+ PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+ FunctionTestThread thread[10];
+ PlatformThreadHandle handle[arraysize(thread)];
+
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_FALSE(thread[n].did_run());
+ for (size_t n = 0; n < arraysize(thread); n++)
+ ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+ for (size_t n = 0; n < arraysize(thread); n++)
+ PlatformThread::Join(handle[n]);
+ for (size_t n = 0; n < arraysize(thread); n++) {
+ ASSERT_TRUE(thread[n].did_run());
+ EXPECT_NE(thread[n].thread_id(), main_thread_id);
+ }
+}
diff --git a/base/port.h b/base/port.h
index af4e450..2e66057 100644
--- a/base/port.h
+++ b/base/port.h
@@ -4,6 +4,7 @@
#ifndef BASE_PORT_H_
#define BASE_PORT_H_
+#pragma once
#include <stdarg.h>
#include "build/build_config.h"
diff --git a/base/process.h b/base/process.h
index 096d1b3..32f5131 100644
--- a/base/process.h
+++ b/base/process.h
@@ -4,6 +4,7 @@
#ifndef BASE_PROCESS_H_
#define BASE_PROCESS_H_
+#pragma once
#include "base/basictypes.h"
#include "build/build_config.h"
diff --git a/base/process_posix.cc b/base/process_posix.cc
index 904884a..ee70e5a 100644
--- a/base/process_posix.cc
+++ b/base/process_posix.cc
@@ -9,6 +9,7 @@
#include <sys/resource.h>
#include "base/process_util.h"
+#include "base/logging.h"
namespace base {
diff --git a/base/process_util.h b/base/process_util.h
index 67501be..d7a36da 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -7,6 +7,7 @@
#ifndef BASE_PROCESS_UTIL_H_
#define BASE_PROCESS_UTIL_H_
+#pragma once
#include "base/basictypes.h"
@@ -32,9 +33,7 @@ typedef struct _malloc_zone_t malloc_zone_t;
#include <utility>
#include <vector>
-#include "base/command_line.h"
#include "base/file_descriptor_shuffle.h"
-#include "base/file_path.h"
#include "base/process.h"
#ifndef NAME_MAX // Solaris and some BSDs have no NAME_MAX
@@ -45,6 +44,9 @@ typedef struct _malloc_zone_t malloc_zone_t;
#endif
#endif
+class CommandLine;
+class FilePath;
+
namespace base {
#if defined(OS_WIN)
@@ -143,6 +145,18 @@ void CloseSuperfluousFds(const InjectiveMultimap& saved_map);
#endif
#if defined(OS_WIN)
+
+enum IntegrityLevel {
+ INTEGRITY_UNKNOWN,
+ LOW_INTEGRITY,
+ MEDIUM_INTEGRITY,
+ HIGH_INTEGRITY,
+};
+// Determine the integrity level of the specified process. Returns false
+// if the system does not support integrity levels (pre-Vista) or in the case
+// of an underlying system failure.
+bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level);
+
// Runs the given application name with the given command line. Normally, the
// first command line argument should be the path to the process, and don't
// forget to quote it.
@@ -160,6 +174,13 @@ void CloseSuperfluousFds(const InjectiveMultimap& saved_map);
bool LaunchApp(const std::wstring& cmdline,
bool wait, bool start_hidden, ProcessHandle* process_handle);
+// Same as LaunchApp, except allows the new process to inherit handles of the
+// parent process.
+bool LaunchAppWithHandleInheritance(const std::wstring& cmdline,
+ bool wait,
+ bool start_hidden,
+ ProcessHandle* process_handle);
+
// Runs the given application name with the given command line as if the user
// represented by |token| had launched it. The caveats about |cmdline| and
// |process_handle| explained for LaunchApp above apply as well.
@@ -174,10 +195,11 @@ bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
bool start_hidden, ProcessHandle* process_handle);
// Has the same behavior as LaunchAppAsUser, but offers the boolean option to
-// use an empty string for the desktop name.
+// use an empty string for the desktop name and a boolean for allowing the
+// child process to inherit handles from its parent.
bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
bool start_hidden, ProcessHandle* process_handle,
- bool empty_desktop_name);
+ bool empty_desktop_name, bool inherit_handles);
#elif defined(OS_POSIX)
@@ -204,6 +226,14 @@ bool LaunchApp(const std::vector<std::string>& argv,
const file_handle_mapping_vector& fds_to_remap,
bool wait, ProcessHandle* process_handle);
+// Similar to the above two methods, but starts the child process in a process
+// group of its own, instead of allowing it to inherit the parent's process
+// group. The pgid of the child process will be the same as its pid.
+bool LaunchAppInNewProcessGroup(const std::vector<std::string>& argv,
+ const environment_vector& environ,
+ const file_handle_mapping_vector& fds_to_remap,
+ bool wait, ProcessHandle* process_handle);
+
// AlterEnvironment returns a modified environment vector, constructed from the
// given environment and the list of changes given in |changes|. Each key in
// the environment is matched against the first element of the pairs. In the
@@ -213,18 +243,6 @@ bool LaunchApp(const std::vector<std::string>& argv,
// The returned array is allocated using new[] and must be freed by the caller.
char** AlterEnvironment(const environment_vector& changes,
const char* const* const env);
-
-#if defined(OS_MACOSX)
-// Similar to the above, but also returns the new process's task_t if
-// |task_handle| is not NULL. If |task_handle| is not NULL, the caller is
-// responsible for calling |mach_port_deallocate()| on the returned handle.
-bool LaunchAppAndGetTask(const std::vector<std::string>& argv,
- const environment_vector& environ,
- const file_handle_mapping_vector& fds_to_remap,
- bool wait,
- task_t* task_handle,
- ProcessHandle* process_handle);
-#endif // defined(OS_MACOSX)
#endif // defined(OS_POSIX)
// Executes the application specified by cl. This function delegates to one
@@ -252,9 +270,15 @@ class ProcessFilter {
// Returns true to indicate set-inclusion and false otherwise. This method
// should not have side-effects and should be idempotent.
virtual bool Includes(const ProcessEntry& entry) const = 0;
+<<<<<<< HEAD
#ifdef ANDROID
virtual ~ProcessFilter() {}
#endif
+=======
+
+ protected:
+ virtual ~ProcessFilter() {}
+>>>>>>> Chromium at release 7.0.540.0
};
// Returns the number of processes on the machine that are running from the
@@ -266,7 +290,7 @@ int GetProcessCount(const std::wstring& executable_name,
// Attempts to kill all the processes on the current machine that were launched
// from the given executable name, ending them with the given exit code. If
// filter is non-null, then only processes selected by the filter are killed.
-// Returns false if all processes were able to be killed off, false if at least
+// 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,
const ProcessFilter* filter);
@@ -276,6 +300,13 @@ bool KillProcesses(const std::wstring& executable_name, int exit_code,
// for the process to be actually terminated before returning.
// Returns true if this is successful, false otherwise.
bool KillProcess(ProcessHandle process, int exit_code, bool wait);
+
+#if defined(OS_POSIX)
+// Attempts to kill the process group identified by |process_group_id|. Returns
+// true on success.
+bool KillProcessGroup(ProcessHandle process_group_id);
+#endif
+
#if defined(OS_WIN)
bool KillProcessById(ProcessId process_id, int exit_code, bool wait);
#endif
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index d3d029e..43e1a5c 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -17,6 +17,8 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/sys_info.h"
@@ -32,7 +34,7 @@ enum ParsingState {
// spaces.
void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
FilePath stat_file("/proc");
- stat_file = stat_file.Append(IntToString(pid));
+ stat_file = stat_file.Append(base::IntToString(pid));
stat_file = stat_file.Append("stat");
std::string mem_stats;
if (!file_util::ReadFileToString(stat_file, &mem_stats))
@@ -46,7 +48,7 @@ namespace base {
ProcessId GetParentProcessId(ProcessHandle process) {
FilePath stat_file("/proc");
- stat_file = stat_file.Append(IntToString(process));
+ stat_file = stat_file.Append(base::IntToString(process));
stat_file = stat_file.Append("status");
std::string status;
if (!file_util::ReadFileToString(stat_file, &status))
@@ -64,7 +66,8 @@ ProcessId GetParentProcessId(ProcessHandle process) {
case KEY_VALUE:
DCHECK(!last_key_name.empty());
if (last_key_name == "PPid") {
- pid_t ppid = StringToInt(tokenizer.token());
+ int ppid;
+ base::StringToInt(tokenizer.token(), &ppid);
return ppid;
}
state = KEY_NAME;
@@ -77,7 +80,7 @@ ProcessId GetParentProcessId(ProcessHandle process) {
FilePath GetProcessExecutablePath(ProcessHandle process) {
FilePath stat_file("/proc");
- stat_file = stat_file.Append(IntToString(process));
+ 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));
@@ -205,8 +208,11 @@ size_t ProcessMetrics::GetPagefileUsage() const {
std::vector<std::string> proc_stats;
GetProcStats(process_, &proc_stats);
const size_t kVmSize = 22;
- if (proc_stats.size() > kVmSize)
- return static_cast<size_t>(StringToInt(proc_stats[kVmSize]));
+ if (proc_stats.size() > kVmSize) {
+ int vm_size;
+ base::StringToInt(proc_stats[kVmSize], &vm_size);
+ return static_cast<size_t>(vm_size);
+ }
return 0;
}
@@ -215,8 +221,11 @@ size_t ProcessMetrics::GetPeakPagefileUsage() const {
std::vector<std::string> proc_stats;
GetProcStats(process_, &proc_stats);
const size_t kVmPeak = 21;
- if (proc_stats.size() > kVmPeak)
- return static_cast<size_t>(StringToInt(proc_stats[kVmPeak]));
+ if (proc_stats.size() > kVmPeak) {
+ int vm_peak;
+ if (base::StringToInt(proc_stats[kVmPeak], &vm_peak))
+ return vm_peak;
+ }
return 0;
}
@@ -226,8 +235,9 @@ size_t ProcessMetrics::GetWorkingSetSize() const {
GetProcStats(process_, &proc_stats);
const size_t kVmRss = 23;
if (proc_stats.size() > kVmRss) {
- size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmRss]));
- return num_pages * getpagesize();
+ int num_pages;
+ if (base::StringToInt(proc_stats[kVmRss], &num_pages))
+ return static_cast<size_t>(num_pages) * getpagesize();
}
return 0;
}
@@ -238,8 +248,9 @@ size_t ProcessMetrics::GetPeakWorkingSetSize() const {
GetProcStats(process_, &proc_stats);
const size_t kVmHwm = 23;
if (proc_stats.size() > kVmHwm) {
- size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmHwm]));
- return num_pages * getpagesize();
+ int num_pages;
+ base::StringToInt(proc_stats[kVmHwm], &num_pages);
+ return static_cast<size_t>(num_pages) * getpagesize();
}
return 0;
}
@@ -265,7 +276,7 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
// See http://www.pixelbeat.org/scripts/ps_mem.py
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
FilePath stat_file =
- FilePath("/proc").Append(IntToString(process_)).Append("smaps");
+ FilePath("/proc").Append(base::IntToString(process_)).Append("smaps");
std::string smaps;
int private_kb = 0;
int pss_kb = 0;
@@ -288,10 +299,14 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
return false;
}
if (last_key_name.starts_with(private_prefix)) {
- private_kb += StringToInt(tokenizer.token());
+ int cur;
+ base::StringToInt(tokenizer.token(), &cur);
+ private_kb += cur;
} else if (last_key_name.starts_with(pss_prefix)) {
have_pss = true;
- pss_kb += StringToInt(tokenizer.token());
+ int cur;
+ base::StringToInt(tokenizer.token(), &cur);
+ pss_kb += cur;
}
state = KEY_NAME;
break;
@@ -305,7 +320,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
return false;
stat_file =
- FilePath("/proc").Append(IntToString(process_)).Append("statm");
+ FilePath("/proc").Append(base::IntToString(process_)).Append("statm");
std::string statm;
if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0)
return false;
@@ -314,8 +329,11 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
SplitString(statm, ' ', &statm_vec);
if (statm_vec.size() != 7)
return false; // Not the format we expect.
- private_kb = StringToInt(statm_vec[1]) - StringToInt(statm_vec[2]);
- private_kb *= page_size_kb;
+
+ int statm1, statm2;
+ base::StringToInt(statm_vec[1], &statm1);
+ base::StringToInt(statm_vec[2], &statm2);
+ private_kb = (statm1 - statm2) * page_size_kb;
}
ws_usage->priv = private_kb;
// Sharable is not calculated, as it does not provide interesting data.
@@ -332,7 +350,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
std::string proc_io_contents;
FilePath io_file("/proc");
- io_file = io_file.Append(IntToString(process_));
+ io_file = io_file.Append(base::IntToString(process_));
io_file = io_file.Append("io");
if (!file_util::ReadFileToString(io_file, &proc_io_contents))
return false;
@@ -352,13 +370,17 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
case KEY_VALUE:
DCHECK(!last_key_name.empty());
if (last_key_name == "syscr") {
- (*io_counters).ReadOperationCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).ReadOperationCount));
} else if (last_key_name == "syscw") {
- (*io_counters).WriteOperationCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).WriteOperationCount));
} else if (last_key_name == "rchar") {
- (*io_counters).ReadTransferCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).ReadTransferCount));
} else if (last_key_name == "wchar") {
- (*io_counters).WriteTransferCount = StringToInt64(tokenizer.token());
+ base::StringToInt64(tokenizer.token(),
+ reinterpret_cast<int64*>(&(*io_counters).WriteTransferCount));
}
state = KEY_NAME;
break;
@@ -384,7 +406,10 @@ int ParseProcStatCPU(const std::string& input) {
if (fields.size() < 13)
return -1; // Output not in the format we expect.
- return StringToInt(fields[11]) + StringToInt(fields[12]);
+ int fields11, fields12;
+ base::StringToInt(fields[11], &fields11);
+ base::StringToInt(fields[12], &fields12);
+ return fields11 + fields12;
}
// Get the total CPU of a single process. Return value is number of jiffies
@@ -498,13 +523,13 @@ size_t GetSystemCommitCharge() {
DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:");
DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:");
- size_t result_in_kb;
- result_in_kb = StringToInt(meminfo_fields[kMemTotalIndex]);
- result_in_kb -= StringToInt(meminfo_fields[kMemFreeIndex]);
- result_in_kb -= StringToInt(meminfo_fields[kMemBuffersIndex]);
- result_in_kb -= StringToInt(meminfo_fields[kMemCacheIndex]);
+ int mem_total, mem_free, mem_buffers, mem_cache;
+ base::StringToInt(meminfo_fields[kMemTotalIndex], &mem_total);
+ base::StringToInt(meminfo_fields[kMemFreeIndex], &mem_free);
+ base::StringToInt(meminfo_fields[kMemBuffersIndex], &mem_buffers);
+ base::StringToInt(meminfo_fields[kMemCacheIndex], &mem_cache);
- return result_in_kb;
+ return mem_total - mem_free - mem_buffers - mem_cache;
}
namespace {
@@ -613,13 +638,13 @@ bool AdjustOOMScore(ProcessId process, int score) {
return false;
FilePath oom_adj("/proc");
- oom_adj = oom_adj.Append(Int64ToString(process));
+ oom_adj = oom_adj.Append(base::Int64ToString(process));
oom_adj = oom_adj.AppendASCII("oom_adj");
if (!file_util::PathExists(oom_adj))
return false;
- std::string score_str = IntToString(score);
+ std::string score_str = base::IntToString(score);
return (static_cast<int>(score_str.length()) ==
file_util::WriteFile(oom_adj, score_str.c_str(), score_str.length()));
}
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 0bdc134..2ea59a0 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -17,6 +17,7 @@
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <sys/wait.h>
#include <new>
@@ -613,10 +614,17 @@ void EnableTerminationOnOutOfMemory() {
g_oom_killer_enabled = true;
- int32 os_major;
- int32 os_minor;
- int32 os_bugfix;
- SysInfo::OperatingSystemVersionNumbers(&os_major, &os_minor, &os_bugfix);
+ // Not SysInfo::OperatingSystemVersionNumbers as that calls through to Gestalt
+ // which ends up (on > 10.6) spawning threads.
+ struct utsname machine_info;
+ if (uname(&machine_info)) {
+ return;
+ }
+
+ // The string machine_info.release is the xnu/Darwin version number, "9.xxx"
+ // on Mac OS X 10.5, and "10.xxx" on Mac OS X 10.6. See
+ // http://en.wikipedia.org/wiki/Darwin_(operating_system) .
+ long darwin_version = strtol(machine_info.release, NULL, 10);
// === C malloc/calloc/valloc/realloc/posix_memalign ===
@@ -635,8 +643,7 @@ void EnableTerminationOnOutOfMemory() {
!g_old_memalign_purgeable) << "Old allocators unexpectedly non-null";
// See http://trac.webkit.org/changeset/53362/trunk/WebKitTools/DumpRenderTree/mac
- bool zone_allocators_protected =
- ((os_major == 10 && os_minor > 6) || os_major > 10);
+ bool zone_allocators_protected = darwin_version > 10;
ChromeMallocZone* default_zone =
reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
@@ -752,7 +759,7 @@ void EnableTerminationOnOutOfMemory() {
<< "Old allocators unexpectedly non-null";
bool cf_allocator_internals_known =
- (os_major == 10 && (os_minor == 5 || os_minor == 6));
+ darwin_version == 9 || darwin_version == 10;
if (cf_allocator_internals_known) {
ChromeCFAllocatorRef allocator = const_cast<ChromeCFAllocatorRef>(
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index cae70a5..31a8e9d 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -16,6 +16,7 @@
#include <limits>
#include <set>
+#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/debug_util.h"
#include "base/dir_reader_posix.h"
@@ -23,15 +24,14 @@
#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
-#include "base/rand_util.h"
#include "base/scoped_ptr.h"
+#include "base/stringprintf.h"
#include "base/time.h"
#include "base/waitable_event.h"
#if defined(OS_MACOSX)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
-#include "base/mach_ipc_mac.h"
#else
extern char** environ;
#endif
@@ -107,6 +107,15 @@ void StackDumpSignalHandler(int signal) {
_exit(1);
}
+void ResetChildSignalHandlersToDefaults() {
+ // The previous signal handlers are likely to be meaningless in the child's
+ // context so we reset them to the defaults for now. http://crbug.com/44953
+ // These signal handlers are setup in browser_main.cc:BrowserMain
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+}
+
} // anonymous namespace
ProcessId GetCurrentProcId() {
@@ -146,6 +155,8 @@ bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
DCHECK_GT(process_id, 1) << " tried to kill invalid process_id";
if (process_id <= 1)
return false;
+ static unsigned kMaxSleepMs = 1000;
+ unsigned sleep_ms = 4;
bool result = kill(process_id, SIGTERM) == 0;
@@ -169,7 +180,9 @@ bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
DPLOG(ERROR) << "Error waiting for process " << process_id;
}
- sleep(1);
+ usleep(sleep_ms * 1000);
+ if (sleep_ms < kMaxSleepMs)
+ sleep_ms *= 2;
}
if (!exited)
@@ -182,6 +195,13 @@ bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
return result;
}
+bool KillProcessGroup(ProcessHandle process_group_id) {
+ bool result = kill(-1 * process_group_id, SIGKILL) == 0;
+ if (!result)
+ PLOG(ERROR) << "Unable to terminate process group " << process_group_id;
+ return result;
+}
+
// A class to handle auto-closing of DIR*'s.
class ScopedDIRClose {
public:
@@ -286,75 +306,6 @@ void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
}
}
-#if defined(OS_MACOSX)
-static std::string MachErrorCode(kern_return_t err) {
- return StringPrintf("0x%x %s", err, mach_error_string(err));
-}
-
-// Forks the current process and returns the child's |task_t| in the parent
-// process.
-static pid_t fork_and_get_task(task_t* child_task) {
- const int kTimeoutMs = 100;
- kern_return_t err;
-
- // Put a random number into the channel name, so that a compromised renderer
- // can't pretend being the child that's forked off.
- std::string mach_connection_name = StringPrintf(
- "com.google.Chrome.samplingfork.%p.%d",
- child_task, base::RandInt(0, std::numeric_limits<int>::max()));
- ReceivePort parent_recv_port(mach_connection_name.c_str());
-
- // Error handling philosophy: If Mach IPC fails, don't touch |child_task| but
- // return a valid pid. If IPC fails in the child, the parent will have to wait
- // until kTimeoutMs is over. This is not optimal, but I've never seen it
- // happen, and stuff should still mostly work.
- pid_t pid = fork();
- switch (pid) {
- case -1:
- return pid;
- case 0: { // child
- MachSendMessage child_message(/* id= */0);
- if (!child_message.AddDescriptor(mach_task_self())) {
- LOG(ERROR) << "child AddDescriptor(mach_task_self()) failed.";
- return pid;
- }
-
- MachPortSender child_sender(mach_connection_name.c_str());
- err = child_sender.SendMessage(child_message, kTimeoutMs);
- if (err != KERN_SUCCESS) {
- LOG(ERROR) << "child SendMessage() failed: " << MachErrorCode(err);
- return pid;
- }
- break;
- }
- default: { // parent
- MachReceiveMessage child_message;
- err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
- if (err != KERN_SUCCESS) {
- LOG(ERROR) << "parent WaitForMessage() failed: " << MachErrorCode(err);
- return pid;
- }
-
- if (child_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
- LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
- return pid;
- }
- *child_task = child_message.GetTranslatedPort(0);
- break;
- }
- }
- return pid;
-}
-
-bool LaunchApp(const std::vector<std::string>& argv,
- const environment_vector& env_changes,
- const file_handle_mapping_vector& fds_to_remap,
- bool wait, ProcessHandle* process_handle) {
- return LaunchAppAndGetTask(
- argv, env_changes, fds_to_remap, wait, NULL, process_handle);
-}
-#endif // defined(OS_MACOSX)
-
char** AlterEnvironment(const environment_vector& changes,
const char* const* const env) {
unsigned count = 0;
@@ -476,19 +427,13 @@ char** AlterEnvironment(const environment_vector& changes,
return ret;
}
-#if defined(OS_MACOSX)
-bool LaunchAppAndGetTask(
-#else
-bool LaunchApp(
-#endif
+bool LaunchAppImpl(
const std::vector<std::string>& argv,
const environment_vector& env_changes,
const file_handle_mapping_vector& fds_to_remap,
bool wait,
-#if defined(OS_MACOSX)
- task_t* task_handle,
-#endif
- ProcessHandle* process_handle) {
+ ProcessHandle* process_handle,
+ bool start_new_process_group) {
pid_t pid;
InjectiveMultimap fd_shuffle1, fd_shuffle2;
fd_shuffle1.reserve(fds_to_remap.size());
@@ -496,35 +441,24 @@ bool LaunchApp(
scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ));
-#if defined(OS_MACOSX)
- if (task_handle == NULL) {
- pid = fork();
- } else {
- // On OS X, the task_t for a process is needed for several reasons. Sadly,
- // the function task_for_pid() requires privileges a normal user doesn't
- // have. Instead, a short-lived Mach IPC connection is opened between parent
- // and child, and the child sends its task_t to the parent at fork time.
- *task_handle = MACH_PORT_NULL;
- pid = fork_and_get_task(task_handle);
- }
-#else
pid = fork();
-#endif
if (pid < 0)
return false;
if (pid == 0) {
// Child process
+
+ if (start_new_process_group) {
+ // Instead of inheriting the process group ID of the parent, the child
+ // starts off a new process group with pgid equal to its process ID.
+ if (setpgid(0, 0) < 0)
+ return false;
+ }
#if defined(OS_MACOSX)
RestoreDefaultExceptionHandler();
#endif
- // The previous signal handlers are likely to be meaningless in the child's
- // context so we reset them to the defaults for now. http://crbug.com/44953
- // These signal handlers are setup in browser_main.cc:BrowserMain
- signal(SIGTERM, SIG_DFL);
- signal(SIGHUP, SIG_DFL);
- signal(SIGINT, SIG_DFL);
+ ResetChildSignalHandlersToDefaults();
#if 0
// When debugging it can be helpful to check that we really aren't making
@@ -579,6 +513,26 @@ bool LaunchApp(
return true;
}
+bool LaunchApp(
+ const std::vector<std::string>& argv,
+ const environment_vector& env_changes,
+ const file_handle_mapping_vector& fds_to_remap,
+ bool wait,
+ ProcessHandle* process_handle) {
+ return LaunchAppImpl(argv, env_changes, fds_to_remap,
+ wait, process_handle, false);
+}
+
+bool LaunchAppInNewProcessGroup(
+ const std::vector<std::string>& argv,
+ const environment_vector& env_changes,
+ const file_handle_mapping_vector& fds_to_remap,
+ bool wait,
+ ProcessHandle* process_handle) {
+ return LaunchAppImpl(argv, env_changes, fds_to_remap, wait,
+ process_handle, true);
+}
+
bool LaunchApp(const std::vector<std::string>& argv,
const file_handle_mapping_vector& fds_to_remap,
bool wait, ProcessHandle* process_handle) {
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index 481c759..e92459c 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_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.
@@ -9,12 +9,15 @@
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
-#include "base/multiprocess_test.h"
+#include "base/logging.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
+#include "base/test/multiprocess_test.h"
+#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
#if defined(OS_LINUX)
#include <errno.h>
@@ -61,7 +64,7 @@ void SignalChildren(const char* filename) {
} // namespace
-class ProcessUtilTest : public MultiProcessTest {
+class ProcessUtilTest : public base::MultiProcessTest {
#if defined(OS_POSIX)
public:
// Spawn a child process that counts how many file descriptors are open.
@@ -74,7 +77,7 @@ MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
}
TEST_F(ProcessUtilTest, SpawnChild) {
- base::ProcessHandle handle = this->SpawnChild(L"SimpleChildProcess");
+ base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
ASSERT_NE(base::kNullProcessHandle, handle);
EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000));
base::CloseProcessHandle(handle);
@@ -87,7 +90,7 @@ MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
TEST_F(ProcessUtilTest, KillSlowChild) {
remove("SlowChildProcess.die");
- base::ProcessHandle handle = this->SpawnChild(L"SlowChildProcess");
+ base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
ASSERT_NE(base::kNullProcessHandle, handle);
SignalChildren("SlowChildProcess.die");
EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000));
@@ -97,7 +100,7 @@ TEST_F(ProcessUtilTest, KillSlowChild) {
TEST_F(ProcessUtilTest, DidProcessCrash) {
remove("SlowChildProcess.die");
- base::ProcessHandle handle = this->SpawnChild(L"SlowChildProcess");
+ base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
ASSERT_NE(base::kNullProcessHandle, handle);
bool child_exited = true;
@@ -117,7 +120,7 @@ TEST_F(ProcessUtilTest, DidProcessCrash) {
// Note: a platform may not be willing or able to lower the priority of
// a process. The calls to SetProcessBackground should be noops then.
TEST_F(ProcessUtilTest, SetProcessBackgrounded) {
- base::ProcessHandle handle = this->SpawnChild(L"SimpleChildProcess");
+ base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
base::Process process(handle);
int old_priority = process.GetPriority();
process.SetProcessBackgrounded(true);
@@ -204,18 +207,16 @@ TEST_F(ProcessUtilTest, GetAppOutput) {
.Append(FILE_PATH_LITERAL("python.exe"));
CommandLine cmd_line(python_runtime);
- cmd_line.AppendLooseValue(L"-c");
- cmd_line.AppendLooseValue(L"\"import sys; sys.stdout.write('" +
- ASCIIToWide(message) + L"');\"");
+ cmd_line.AppendArg("-c");
+ cmd_line.AppendArg("import sys; sys.stdout.write('" + message + "');");
std::string output;
ASSERT_TRUE(base::GetAppOutput(cmd_line, &output));
EXPECT_EQ(message, output);
// Let's make sure stderr is ignored.
CommandLine other_cmd_line(python_runtime);
- other_cmd_line.AppendLooseValue(L"-c");
- other_cmd_line.AppendLooseValue(
- L"\"import sys; sys.stderr.write('Hello!');\"");
+ other_cmd_line.AppendArg("-c");
+ other_cmd_line.AppendArg("import sys; sys.stderr.write('Hello!');");
output.clear();
ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output));
EXPECT_EQ("", output);
@@ -225,7 +226,7 @@ TEST_F(ProcessUtilTest, LaunchAsUser) {
base::UserTokenHandle token;
ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
std::wstring cmdline =
- this->MakeCmdLine(L"SimpleChildProcess", false).command_line_string();
+ this->MakeCmdLine("SimpleChildProcess", false).command_line_string();
EXPECT_TRUE(base::LaunchAppAsUser(token, cmdline, false, NULL));
}
@@ -290,7 +291,7 @@ int ProcessUtilTest::CountOpenFDsInChild() {
base::file_handle_mapping_vector fd_mapping_vec;
fd_mapping_vec.push_back(std::pair<int, int>(fds[1], kChildPipe));
base::ProcessHandle handle = this->SpawnChild(
- L"ProcessUtilsLeakFDChildProcess", fd_mapping_vec, false);
+ "ProcessUtilsLeakFDChildProcess", fd_mapping_vec, false);
CHECK(handle);
int ret = HANDLE_EINTR(close(fds[1]));
DPCHECK(ret == 0);
@@ -555,9 +556,9 @@ int tc_set_new_mode(int mode);
}
#endif // defined(USE_TCMALLOC)
-class OutOfMemoryTest : public testing::Test {
+class OutOfMemoryDeathTest : public testing::Test {
public:
- OutOfMemoryTest()
+ OutOfMemoryDeathTest()
: value_(NULL),
// Make test size as large as possible minus a few pages so
// that alignment or other rounding doesn't make it wrap.
@@ -566,9 +567,6 @@ class OutOfMemoryTest : public testing::Test {
}
virtual void SetUp() {
- // Must call EnableTerminationOnOutOfMemory() because that is called from
- // chrome's main function and therefore hasn't been called yet.
- base::EnableTerminationOnOutOfMemory();
#if defined(USE_TCMALLOC)
tc_set_new_mode(1);
}
@@ -578,56 +576,92 @@ class OutOfMemoryTest : public testing::Test {
#endif // defined(USE_TCMALLOC)
}
+ void SetUpInDeathAssert() {
+ // Must call EnableTerminationOnOutOfMemory() because that is called from
+ // chrome's main function and therefore hasn't been called yet.
+ // Since this call may result in another thread being created and death
+ // tests shouldn't be started in a multithread environment, this call
+ // should be done inside of the ASSERT_DEATH.
+ base::EnableTerminationOnOutOfMemory();
+ }
+
void* value_;
size_t test_size_;
ssize_t signed_test_size_;
};
-TEST_F(OutOfMemoryTest, New) {
- ASSERT_DEATH(value_ = operator new(test_size_), "");
+TEST_F(OutOfMemoryDeathTest, New) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = operator new(test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, NewArray) {
- ASSERT_DEATH(value_ = new char[test_size_], "");
+TEST_F(OutOfMemoryDeathTest, NewArray) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = new char[test_size_];
+ }, "");
}
-TEST_F(OutOfMemoryTest, Malloc) {
- ASSERT_DEATH(value_ = malloc(test_size_), "");
+TEST_F(OutOfMemoryDeathTest, Malloc) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = malloc(test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, Realloc) {
- ASSERT_DEATH(value_ = realloc(NULL, test_size_), "");
+TEST_F(OutOfMemoryDeathTest, Realloc) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = realloc(NULL, test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, Calloc) {
- ASSERT_DEATH(value_ = calloc(1024, test_size_ / 1024L), "");
+TEST_F(OutOfMemoryDeathTest, Calloc) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = calloc(1024, test_size_ / 1024L);
+ }, "");
}
-TEST_F(OutOfMemoryTest, Valloc) {
- ASSERT_DEATH(value_ = valloc(test_size_), "");
+TEST_F(OutOfMemoryDeathTest, Valloc) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = valloc(test_size_);
+ }, "");
}
#if defined(OS_LINUX)
-TEST_F(OutOfMemoryTest, Pvalloc) {
- ASSERT_DEATH(value_ = pvalloc(test_size_), "");
+TEST_F(OutOfMemoryDeathTest, Pvalloc) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = pvalloc(test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, Memalign) {
- ASSERT_DEATH(value_ = memalign(4, test_size_), "");
+TEST_F(OutOfMemoryDeathTest, Memalign) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = memalign(4, test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, ViaSharedLibraries) {
+TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
// g_try_malloc is documented to return NULL on failure. (g_malloc is the
// 'safe' default that crashes if allocation fails). However, since we have
// hopefully overridden malloc, even g_try_malloc should fail. This tests
// that the run-time symbol resolution is overriding malloc for shared
// libraries as well as for our code.
- ASSERT_DEATH(value_ = g_try_malloc(test_size_), "");
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = g_try_malloc(test_size_);
+ }, "");
}
#endif // OS_LINUX
#if defined(OS_POSIX)
-TEST_F(OutOfMemoryTest, Posix_memalign) {
+TEST_F(OutOfMemoryDeathTest, Posix_memalign) {
typedef int (*memalign_t)(void **, size_t, size_t);
#if defined(OS_MACOSX)
// posix_memalign only exists on >= 10.6. Use dlsym to grab it at runtime
@@ -641,7 +675,10 @@ TEST_F(OutOfMemoryTest, Posix_memalign) {
// Grab the return value of posix_memalign to silence a compiler warning
// about unused return values. We don't actually care about the return
// value, since we're asserting death.
- ASSERT_DEATH(EXPECT_EQ(ENOMEM, memalign(&value_, 8, test_size_)), "");
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ EXPECT_EQ(ENOMEM, memalign(&value_, 8, test_size_));
+ }, "");
}
}
#endif // OS_POSIX
@@ -650,32 +687,43 @@ TEST_F(OutOfMemoryTest, Posix_memalign) {
// Purgeable zone tests (if it exists)
-TEST_F(OutOfMemoryTest, MallocPurgeable) {
+TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
malloc_zone_t* zone = base::GetPurgeableZone();
if (zone)
- ASSERT_DEATH(value_ = malloc_zone_malloc(zone, test_size_), "");
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = malloc_zone_malloc(zone, test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, ReallocPurgeable) {
+TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
malloc_zone_t* zone = base::GetPurgeableZone();
if (zone)
- ASSERT_DEATH(value_ = malloc_zone_realloc(zone, NULL, test_size_), "");
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = malloc_zone_realloc(zone, NULL, test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, CallocPurgeable) {
+TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
malloc_zone_t* zone = base::GetPurgeableZone();
if (zone)
- ASSERT_DEATH(value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L),
- "");
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
+ }, "");
}
-TEST_F(OutOfMemoryTest, VallocPurgeable) {
+TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
malloc_zone_t* zone = base::GetPurgeableZone();
if (zone)
- ASSERT_DEATH(value_ = malloc_zone_valloc(zone, test_size_), "");
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = malloc_zone_valloc(zone, test_size_);
+ }, "");
}
-TEST_F(OutOfMemoryTest, PosixMemalignPurgeable) {
+TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
malloc_zone_t* zone = base::GetPurgeableZone();
typedef void* (*zone_memalign_t)(malloc_zone_t*, size_t, size_t);
@@ -686,7 +734,10 @@ TEST_F(OutOfMemoryTest, PosixMemalignPurgeable) {
dlsym(RTLD_DEFAULT, "malloc_zone_memalign"));
if (zone && zone_memalign) {
- ASSERT_DEATH(value_ = zone_memalign(zone, 8, test_size_), "");
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ value_ = zone_memalign(zone, 8, test_size_);
+ }, "");
}
}
@@ -697,19 +748,28 @@ TEST_F(OutOfMemoryTest, PosixMemalignPurgeable) {
// it's likely that they'll fail because they would require a preposterous
// amount of (virtual) memory.
-TEST_F(OutOfMemoryTest, CFAllocatorSystemDefault) {
- ASSERT_DEATH(while ((value_ =
- base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}, "");
+TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ while ((value_ =
+ base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}
+ }, "");
}
-TEST_F(OutOfMemoryTest, CFAllocatorMalloc) {
- ASSERT_DEATH(while ((value_ =
- base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}, "");
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ while ((value_ =
+ base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}
+ }, "");
}
-TEST_F(OutOfMemoryTest, CFAllocatorMallocZone) {
- ASSERT_DEATH(while ((value_ =
- base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}, "");
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ while ((value_ =
+ base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}
+ }, "");
}
#if !defined(ARCH_CPU_64_BITS)
@@ -717,9 +777,11 @@ TEST_F(OutOfMemoryTest, CFAllocatorMallocZone) {
// See process_util_unittest_mac.mm for an explanation of why this test isn't
// run in the 64-bit environment.
-TEST_F(OutOfMemoryTest, PsychoticallyBigObjCObject) {
- ASSERT_DEATH(while ((value_ =
- base::AllocatePsychoticallyBigObjCObject())) {}, "");
+TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) {
+ ASSERT_DEATH({
+ SetUpInDeathAssert();
+ while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
+ }, "");
}
#endif // !ARCH_CPU_64_BITS
diff --git a/base/process_util_unittest_mac.h b/base/process_util_unittest_mac.h
index 7b4fe1c..60deb13 100644
--- a/base/process_util_unittest_mac.h
+++ b/base/process_util_unittest_mac.h
@@ -7,6 +7,7 @@
#ifndef BASE_PROCESS_UTIL_UNITTEST_MAC_H_
#define BASE_PROCESS_UTIL_UNITTEST_MAC_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/process_util_win.cc b/base/process_util_win.cc
index 2eb73ca..c5d7790 100644
--- a/base/process_util_win.cc
+++ b/base/process_util_win.cc
@@ -12,11 +12,13 @@
#include <ios>
+#include "base/command_line.h"
#include "base/debug_util.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/scoped_handle_win.h"
#include "base/scoped_ptr.h"
+#include "base/win_util.h"
// userenv.dll is required for CreateEnvironmentBlock().
#pragma comment(lib, "userenv.lib")
@@ -138,8 +140,60 @@ ProcessId GetProcId(ProcessHandle process) {
return 0;
}
-bool LaunchApp(const std::wstring& cmdline,
- bool wait, bool start_hidden, ProcessHandle* process_handle) {
+bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) {
+ if (!level)
+ return false;
+
+ if (win_util::GetWinVersion() < win_util::WINVERSION_VISTA)
+ return false;
+
+ HANDLE process_token;
+ if (!OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE,
+ &process_token))
+ return false;
+
+ ScopedHandle scoped_process_token(process_token);
+
+ DWORD token_info_length = 0;
+ if (GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
+ &token_info_length) ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return false;
+
+ scoped_array<char> token_label_bytes(new char[token_info_length]);
+ if (!token_label_bytes.get())
+ return false;
+
+ TOKEN_MANDATORY_LABEL* token_label =
+ reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
+ if (!token_label)
+ return false;
+
+ if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
+ token_info_length, &token_info_length))
+ return false;
+
+ DWORD integrity_level = *GetSidSubAuthority(token_label->Label.Sid,
+ (DWORD)(UCHAR)(*GetSidSubAuthorityCount(token_label->Label.Sid)-1));
+
+ if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID) {
+ *level = LOW_INTEGRITY;
+ } else if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
+ integrity_level < SECURITY_MANDATORY_HIGH_RID) {
+ *level = MEDIUM_INTEGRITY;
+ } else if (integrity_level >= SECURITY_MANDATORY_HIGH_RID) {
+ *level = HIGH_INTEGRITY;
+ } else {
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool LaunchAppImpl(const std::wstring& cmdline,
+ bool wait, bool start_hidden, bool inherit_handles,
+ ProcessHandle* process_handle) {
STARTUPINFO startup_info = {0};
startup_info.cb = sizeof(startup_info);
startup_info.dwFlags = STARTF_USESHOWWINDOW;
@@ -147,7 +201,7 @@ bool LaunchApp(const std::wstring& cmdline,
PROCESS_INFORMATION process_info;
if (!CreateProcess(NULL,
const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
- FALSE, 0, NULL, NULL,
+ inherit_handles, 0, NULL, NULL,
&startup_info, &process_info))
return false;
@@ -166,14 +220,26 @@ bool LaunchApp(const std::wstring& cmdline,
return true;
}
+bool LaunchApp(const std::wstring& cmdline,
+ bool wait, bool start_hidden, ProcessHandle* process_handle) {
+ return LaunchAppImpl(cmdline, wait, start_hidden, false, process_handle);
+}
+
+bool LaunchAppWithHandleInheritance(
+ const std::wstring& cmdline, bool wait, bool start_hidden,
+ ProcessHandle* process_handle) {
+ return LaunchAppImpl(cmdline, wait, start_hidden, true, process_handle);
+}
+
bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
bool start_hidden, ProcessHandle* process_handle) {
- return LaunchAppAsUser(token, cmdline, start_hidden, process_handle, false);
+ return LaunchAppAsUser(token, cmdline, start_hidden, process_handle,
+ false, false);
}
bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
bool start_hidden, ProcessHandle* process_handle,
- bool empty_desktop_name) {
+ bool empty_desktop_name, bool inherit_handles) {
STARTUPINFO startup_info = {0};
startup_info.cb = sizeof(startup_info);
if (empty_desktop_name)
@@ -191,7 +257,7 @@ bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
BOOL launched =
CreateProcessAsUser(token, NULL, const_cast<wchar_t*>(cmdline.c_str()),
- NULL, NULL, FALSE, flags, enviroment_block,
+ NULL, NULL, inherit_handles, flags, enviroment_block,
NULL, &startup_info, &process_info);
DestroyEnvironmentBlock(enviroment_block);
@@ -211,8 +277,8 @@ bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
bool LaunchApp(const CommandLine& cl,
bool wait, bool start_hidden, ProcessHandle* process_handle) {
- return LaunchApp(cl.command_line_string(), wait,
- start_hidden, process_handle);
+ return LaunchAppImpl(cl.command_line_string(), wait,
+ start_hidden, false, process_handle);
}
// Attempts to kill the process identified by the given process
@@ -700,13 +766,13 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
}
bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) const {
- const SIZE_T kTopAdress = 0x7F000000;
+ const SIZE_T kTopAddress = 0x7F000000;
const SIZE_T kMegabyte = 1024 * 1024;
SIZE_T accumulated = 0;
MEMORY_BASIC_INFORMATION largest = {0};
UINT_PTR scan = 0;
- while (scan < kTopAdress) {
+ while (scan < kTopAddress) {
MEMORY_BASIC_INFORMATION info;
if (!::VirtualQueryEx(process_, reinterpret_cast<void*>(scan),
&info, sizeof(info)))
@@ -714,7 +780,7 @@ bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) const {
if (info.State == MEM_FREE) {
accumulated += info.RegionSize;
UINT_PTR end = scan + info.RegionSize;
- if (info.RegionSize > (largest.RegionSize))
+ if (info.RegionSize > largest.RegionSize)
largest = info;
}
scan += info.RegionSize;
diff --git a/base/profiler.cc b/base/profiler.cc
index e291117..b66664b 100644
--- a/base/profiler.cc
+++ b/base/profiler.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/profiler.h"
-#include "base/string_util.h"
#if defined(USE_TCMALLOC) && defined(OS_LINUX)
#include "third_party/tcmalloc/chromium/src/google/profiler.h"
diff --git a/base/profiler.h b/base/profiler.h
index 4fd1117..ea8867a 100644
--- a/base/profiler.h
+++ b/base/profiler.h
@@ -8,6 +8,7 @@
#ifndef BASE_PROFILER_H__
#define BASE_PROFILER_H__
+#pragma once
#include "base/basictypes.h"
diff --git a/base/rand_util.cc b/base/rand_util.cc
index 8480c82..0576c94 100644
--- a/base/rand_util.cc
+++ b/base/rand_util.cc
@@ -1,4 +1,4 @@
-// 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.
@@ -16,9 +16,8 @@ namespace base {
int RandInt(int min, int max) {
DCHECK(min <= max);
- uint64 range = static_cast<int64>(max) - min + 1;
- uint64 number = base::RandUint64();
- int result = min + static_cast<int>(number % range);
+ uint64 range = static_cast<uint64>(max) - min + 1;
+ int result = min + static_cast<int>(base::RandGenerator(range));
DCHECK(result >= min && result <= max);
return result;
}
@@ -37,4 +36,9 @@ double RandDouble() {
return result;
}
+uint64 RandGenerator(uint64 max) {
+ DCHECK(max > 0);
+ return base::RandUint64() % max;
+}
+
} // namespace base
diff --git a/base/rand_util.h b/base/rand_util.h
index e6ffe9a..699fc7f 100644
--- a/base/rand_util.h
+++ b/base/rand_util.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef BASE_RAND_UTIL_H_
#define BASE_RAND_UTIL_H_
+#pragma once
#include "base/basictypes.h"
@@ -15,6 +16,13 @@ uint64 RandUint64();
// Returns a random number between min and max (inclusive). Thread-safe.
int RandInt(int min, int max);
+// Returns a random number in range [0, max). Thread-safe.
+//
+// Note that this can be used as an adapter for std::random_shuffle():
+// Given a pre-populated |std::vector<int> myvector|, shuffle it as
+// std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
+uint64 RandGenerator(uint64 max);
+
// Returns a random double in range [0, 1). Thread-safe.
double RandDouble();
diff --git a/base/rand_util_c.h b/base/rand_util_c.h
index 20e3082..63cf813 100644
--- a/base/rand_util_c.h
+++ b/base/rand_util_c.h
@@ -4,6 +4,7 @@
#ifndef BASE_RAND_UTIL_C_H_
#define BASE_RAND_UTIL_C_H_
+#pragma once
#ifdef __cplusplus
extern "C" {
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
index f56c0ec..cbc338a 100644
--- a/base/rand_util_unittest.cc
+++ b/base/rand_util_unittest.cc
@@ -27,3 +27,11 @@ TEST(RandUtilTest, RandDouble) {
EXPECT_GT(1.0, number);
EXPECT_LE(0.0, number);
}
+
+// Make sure that it is still appropriate to use RandGenerator in conjunction
+// with std::random_shuffle().
+TEST(RandUtilTest, RandGeneratorForRandomShuffle) {
+ EXPECT_EQ(base::RandGenerator(1), 0U);
+ EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(),
+ std::numeric_limits<int64>::max());
+}
diff --git a/base/raw_scoped_refptr_mismatch_checker.h b/base/raw_scoped_refptr_mismatch_checker.h
index 598710f..d2913e7 100644
--- a/base/raw_scoped_refptr_mismatch_checker.h
+++ b/base/raw_scoped_refptr_mismatch_checker.h
@@ -4,6 +4,7 @@
#ifndef BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
#define BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#pragma once
#include "base/ref_counted.h"
#include "base/tuple.h"
diff --git a/base/ref_counted.h b/base/ref_counted.h
index e8413d9..e2b2ed2 100644
--- a/base/ref_counted.h
+++ b/base/ref_counted.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef BASE_REF_COUNTED_H_
#define BASE_REF_COUNTED_H_
+#pragma once
#include "base/atomic_ref_count.h"
#include "base/thread_collision_warner.h"
@@ -109,7 +110,8 @@ struct DefaultRefCountedThreadSafeTraits {
// Delete through RefCountedThreadSafe to make child classes only need to be
// friend with RefCountedThreadSafe instead of this struct, which is an
// implementation detail.
- RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
+ RefCountedThreadSafe<T,
+ DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
}
};
diff --git a/base/ref_counted_memory.cc b/base/ref_counted_memory.cc
new file mode 100644
index 0000000..0a4a613
--- /dev/null
+++ b/base/ref_counted_memory.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 "base/ref_counted_memory.h"
+
+RefCountedMemory::RefCountedMemory() {
+}
+
+RefCountedMemory::~RefCountedMemory() {
+}
+
+const unsigned char* RefCountedStaticMemory::front() const {
+ return data_;
+}
+
+size_t RefCountedStaticMemory::size() const {
+ return length_;
+}
+
+RefCountedBytes* RefCountedBytes::TakeVector(
+ std::vector<unsigned char>* to_destroy) {
+ RefCountedBytes* bytes = new RefCountedBytes;
+ bytes->data.swap(*to_destroy);
+ return bytes;
+}
+
+RefCountedBytes::RefCountedBytes() {
+}
+
+RefCountedBytes::RefCountedBytes(const std::vector<unsigned char>& initializer)
+ : data(initializer) {
+}
+
+RefCountedBytes::~RefCountedBytes() {
+}
+
+const unsigned char* RefCountedBytes::front() const {
+ // STL will assert if we do front() on an empty vector, but calling code
+ // expects a NULL.
+ return size() ? &data.front() : NULL;
+}
+
+size_t RefCountedBytes::size() const {
+ return data.size();
+}
diff --git a/base/ref_counted_memory.h b/base/ref_counted_memory.h
index eae7984..08400ec 100644
--- a/base/ref_counted_memory.h
+++ b/base/ref_counted_memory.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef BASE_REF_COUNTED_MEMORY_H_
#define BASE_REF_COUNTED_MEMORY_H_
+#pragma once
#include <vector>
@@ -26,8 +27,8 @@ class RefCountedMemory : public base::RefCountedThreadSafe<RefCountedMemory> {
protected:
friend class base::RefCountedThreadSafe<RefCountedMemory>;
-
- virtual ~RefCountedMemory() {}
+ RefCountedMemory();
+ virtual ~RefCountedMemory();
};
// An implementation of RefCountedMemory, where the ref counting does not
@@ -39,8 +40,8 @@ class RefCountedStaticMemory : public RefCountedMemory {
RefCountedStaticMemory(const unsigned char* data, size_t length)
: data_(data), length_(length) {}
- virtual const unsigned char* front() const { return data_; }
- virtual size_t size() const { return length_; }
+ virtual const unsigned char* front() const;
+ virtual size_t size() const;
private:
const unsigned char* data_;
@@ -56,27 +57,22 @@ class RefCountedBytes : public RefCountedMemory {
// Constructs a RefCountedBytes object by performing a swap. (To non
// destructively build a RefCountedBytes, use the constructor that takes a
// vector.)
- static RefCountedBytes* TakeVector(std::vector<unsigned char>* to_destroy) {
- RefCountedBytes* bytes = new RefCountedBytes;
- bytes->data.swap(*to_destroy);
- return bytes;
- }
+ static RefCountedBytes* TakeVector(std::vector<unsigned char>* to_destroy);
- RefCountedBytes() {}
+ RefCountedBytes();
// Constructs a RefCountedBytes object by _copying_ from |initializer|.
- RefCountedBytes(const std::vector<unsigned char>& initializer)
- : data(initializer) {}
+ RefCountedBytes(const std::vector<unsigned char>& initializer);
- virtual const unsigned char* front() const {
- // STL will assert if we do front() on an empty vector, but calling code
- // expects a NULL.
- return size() ? &data.front() : NULL;
- }
- virtual size_t size() const { return data.size(); }
+ virtual const unsigned char* front() const;
+ virtual size_t size() const;
std::vector<unsigned char> data;
+ protected:
+ friend class base::RefCountedThreadSafe<RefCountedBytes>;
+ virtual ~RefCountedBytes();
+
private:
DISALLOW_COPY_AND_ASSIGN(RefCountedBytes);
};
diff --git a/base/registry.cc b/base/registry.cc
index bdd3089..f8e58b9 100644
--- a/base/registry.cc
+++ b/base/registry.cc
@@ -1,27 +1,17 @@
-// 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.
-// All Rights Reserved.
#include "base/registry.h"
-#include <assert.h>
#include <shlwapi.h>
-#include <windows.h>
-#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
-
-// local types (see the same declarations in the header file)
-#define tchar TCHAR
-#define CTP const tchar*
-#define tstr std::basic_string<tchar>
+#include "base/logging.h"
-//
-// RegistryValueIterator
-//
+#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
RegistryValueIterator::RegistryValueIterator(HKEY root_key,
- LPCTSTR folder_key) {
+ const wchar_t* folder_key) {
LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
@@ -47,19 +37,17 @@ RegistryValueIterator::~RegistryValueIterator() {
}
bool RegistryValueIterator::Valid() const {
- // true while the iterator is valid
return key_ != NULL && index_ >= 0;
}
void RegistryValueIterator::operator++() {
- // advance to the next entry in the folder
--index_;
Read();
}
bool RegistryValueIterator::Read() {
if (Valid()) {
- DWORD ncount = sizeof(name_)/sizeof(*name_);
+ DWORD ncount = arraysize(name_);
value_size_ = sizeof(value_);
LRESULT r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
reinterpret_cast<BYTE*>(value_), &value_size_);
@@ -74,7 +62,6 @@ bool RegistryValueIterator::Read() {
}
DWORD RegistryValueIterator::ValueCount() const {
-
DWORD count = 0;
HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
&count, NULL, NULL, NULL, NULL);
@@ -85,12 +72,8 @@ DWORD RegistryValueIterator::ValueCount() const {
return count;
}
-//
-// RegistryKeyIterator
-//
-
RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
- LPCTSTR folder_key) {
+ const wchar_t* folder_key) {
LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
@@ -116,19 +99,17 @@ RegistryKeyIterator::~RegistryKeyIterator() {
}
bool RegistryKeyIterator::Valid() const {
- // true while the iterator is valid
return key_ != NULL && index_ >= 0;
}
void RegistryKeyIterator::operator++() {
- // advance to the next entry in the folder
--index_;
Read();
}
bool RegistryKeyIterator::Read() {
if (Valid()) {
- DWORD ncount = sizeof(name_)/sizeof(*name_);
+ DWORD ncount = arraysize(name_);
FILETIME written;
LRESULT r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
NULL, &written);
@@ -141,7 +122,6 @@ bool RegistryKeyIterator::Read() {
}
DWORD RegistryKeyIterator::SubkeyCount() const {
-
DWORD count = 0;
HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
@@ -152,22 +132,28 @@ DWORD RegistryKeyIterator::SubkeyCount() const {
return count;
}
-//
-// RegKey
-//
+RegKey::RegKey()
+ : key_(NULL),
+ watch_event_(0) {
+}
-RegKey::RegKey(HKEY rootkey, const tchar* subkey, REGSAM access)
- : key_(NULL), watch_event_(0) {
+RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
+ : key_(NULL),
+ watch_event_(0) {
if (rootkey) {
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
- this->Create(rootkey, subkey, access);
+ Create(rootkey, subkey, access);
else
- this->Open(rootkey, subkey, access);
+ Open(rootkey, subkey, access);
} else {
- assert(!subkey);
+ DCHECK(!subkey);
}
}
+RegKey::~RegKey() {
+ Close();
+}
+
void RegKey::Close() {
StopWatching();
if (key_) {
@@ -176,25 +162,25 @@ void RegKey::Close() {
}
}
-bool RegKey::Create(HKEY rootkey, const tchar* subkey, REGSAM access) {
+bool RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DWORD disposition_value;
return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
}
-bool RegKey::CreateWithDisposition(HKEY rootkey, const tchar* subkey,
+bool RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access) {
- assert(rootkey && subkey && access && disposition);
- this->Close();
-
- LONG const result = RegCreateKeyEx(rootkey,
- subkey,
- 0,
- NULL,
- REG_OPTION_NON_VOLATILE,
- access,
- NULL,
- &key_,
- disposition );
+ DCHECK(rootkey && subkey && access && disposition);
+ Close();
+
+ LONG result = RegCreateKeyEx(rootkey,
+ subkey,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ access,
+ NULL,
+ &key_,
+ disposition);
if (result != ERROR_SUCCESS) {
key_ = NULL;
return false;
@@ -203,40 +189,37 @@ bool RegKey::CreateWithDisposition(HKEY rootkey, const tchar* subkey,
return true;
}
-bool RegKey::Open(HKEY rootkey, const tchar* subkey, REGSAM access) {
- assert(rootkey && subkey && access);
- this->Close();
+bool RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+ DCHECK(rootkey && subkey && access);
+ Close();
- LONG const result = RegOpenKeyEx(rootkey, subkey, 0,
- access, &key_ );
+ LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
return false;
}
-
return true;
}
-bool RegKey::CreateKey(const tchar* name, REGSAM access) {
- assert(name && access);
+bool RegKey::CreateKey(const wchar_t* name, REGSAM access) {
+ DCHECK(name && access);
HKEY subkey = NULL;
- LONG const result = RegCreateKeyEx(key_, name, 0, NULL,
- REG_OPTION_NON_VOLATILE,
- access, NULL, &subkey, NULL);
- this->Close();
+ LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
+ access, NULL, &subkey, NULL);
+ Close();
key_ = subkey;
return (result == ERROR_SUCCESS);
}
-bool RegKey::OpenKey(const tchar* name, REGSAM access) {
- assert(name && access);
+bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
+ DCHECK(name && access);
HKEY subkey = NULL;
- LONG const result = RegOpenKeyEx(key_, name, 0, access, &subkey);
+ LONG result = RegOpenKeyEx(key_, name, 0, access, &subkey);
- this->Close();
+ Close();
key_ = subkey;
return (result == ERROR_SUCCESS);
@@ -244,14 +227,14 @@ bool RegKey::OpenKey(const tchar* name, REGSAM access) {
DWORD RegKey::ValueCount() {
DWORD count = 0;
- HRESULT const result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
- NULL, &count, NULL, NULL, NULL, NULL);
+ HRESULT result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
+ NULL, &count, NULL, NULL, NULL, NULL);
return (result != ERROR_SUCCESS) ? 0 : count;
}
-bool RegKey::ReadName(int index, tstr* name) {
- tchar buf[256];
- DWORD bufsize = sizeof(buf)/sizeof(*buf);
+bool RegKey::ReadName(int index, std::wstring* name) {
+ wchar_t buf[256];
+ DWORD bufsize = arraysize(buf);
LRESULT r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL,
NULL, NULL);
if (r != ERROR_SUCCESS)
@@ -261,34 +244,35 @@ bool RegKey::ReadName(int index, tstr* name) {
return true;
}
-bool RegKey::ValueExists(const tchar* name) {
- if (!key_) return false;
- const HRESULT result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
+bool RegKey::ValueExists(const wchar_t* name) {
+ if (!key_)
+ return false;
+ HRESULT result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
return (result == ERROR_SUCCESS);
}
-bool RegKey::ReadValue(const tchar* name, void* data,
+bool RegKey::ReadValue(const wchar_t* name, void* data,
DWORD* dsize, DWORD* dtype) {
- if (!key_) return false;
- HRESULT const result = RegQueryValueEx(key_, name, 0, dtype,
- reinterpret_cast<LPBYTE>(data),
- dsize);
+ if (!key_)
+ return false;
+ HRESULT result = RegQueryValueEx(key_, name, 0, dtype,
+ reinterpret_cast<LPBYTE>(data), dsize);
return (result == ERROR_SUCCESS);
}
-bool RegKey::ReadValue(const tchar* name, tstr * value) {
- assert(value);
- static const size_t kMaxStringLength = 1024; // This is after expansion.
+bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) {
+ DCHECK(value);
+ const size_t kMaxStringLength = 1024; // This is after expansion.
// Use the one of the other forms of ReadValue if 1024 is too small for you.
- TCHAR raw_value[kMaxStringLength];
+ wchar_t raw_value[kMaxStringLength];
DWORD type = REG_SZ, size = sizeof(raw_value);
- if (this->ReadValue(name, raw_value, &size, &type)) {
+ if (ReadValue(name, raw_value, &size, &type)) {
if (type == REG_SZ) {
*value = raw_value;
} else if (type == REG_EXPAND_SZ) {
- TCHAR expanded[kMaxStringLength];
+ wchar_t expanded[kMaxStringLength];
size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
- // Success: returns the number of TCHARs copied
+ // Success: returns the number of wchar_t's copied
// Fail: buffer too small, returns the size required
// Fail: other, returns 0
if (size == 0 || size > kMaxStringLength)
@@ -304,12 +288,14 @@ bool RegKey::ReadValue(const tchar* name, tstr * value) {
return false;
}
-bool RegKey::ReadValueDW(const tchar* name, DWORD * value) {
- assert(value);
- DWORD type = REG_DWORD, size = sizeof(DWORD), result = 0;
- if (this->ReadValue(name, &result, &size, &type)
- && (type == REG_DWORD || type == REG_BINARY)
- && size == sizeof(DWORD)) {
+bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) {
+ DCHECK(value);
+ DWORD type = REG_DWORD;
+ DWORD size = sizeof(DWORD);
+ DWORD result = 0;
+ if (ReadValue(name, &result, &size, &type) &&
+ (type == REG_DWORD || type == REG_BINARY) &&
+ size == sizeof(DWORD)) {
*value = result;
return true;
}
@@ -317,13 +303,14 @@ bool RegKey::ReadValueDW(const tchar* name, DWORD * value) {
return false;
}
-bool RegKey::WriteValue(const tchar* name,
- const void * data,
- DWORD dsize,
- DWORD dtype) {
- assert(data);
- if (!key_) return false;
- HRESULT const result = RegSetValueEx(
+bool RegKey::WriteValue(const wchar_t* name, const void * data,
+ DWORD dsize, DWORD dtype) {
+ DCHECK(data);
+
+ if (!key_)
+ return false;
+
+ HRESULT result = RegSetValueEx(
key_,
name,
0,
@@ -333,25 +320,23 @@ bool RegKey::WriteValue(const tchar* name,
return (result == ERROR_SUCCESS);
}
-bool RegKey::WriteValue(const tchar * name, const tchar * value) {
- return this->WriteValue(name, value,
- static_cast<DWORD>(sizeof(*value) * (_tcslen(value) + 1)), REG_SZ);
+bool RegKey::WriteValue(const wchar_t * name, const wchar_t* value) {
+ return WriteValue(name, value,
+ static_cast<DWORD>(sizeof(*value) * (wcslen(value) + 1)), REG_SZ);
}
-bool RegKey::WriteValue(const tchar * name, DWORD value) {
- return this->WriteValue(name, &value,
- static_cast<DWORD>(sizeof(value)), REG_DWORD);
+bool RegKey::WriteValue(const wchar_t* name, DWORD value) {
+ return WriteValue(name, &value,
+ static_cast<DWORD>(sizeof(value)), REG_DWORD);
}
-bool RegKey::DeleteKey(const tchar * name) {
- if (!key_) return false;
- return (ERROR_SUCCESS == SHDeleteKey(key_, name));
+bool RegKey::DeleteKey(const wchar_t* name) {
+ return (!key_) ? false : (ERROR_SUCCESS == SHDeleteKey(key_, name));
}
-
-bool RegKey::DeleteValue(const tchar * value_name) {
- assert(value_name);
- HRESULT const result = RegDeleteValue(key_, value_name);
+bool RegKey::DeleteValue(const wchar_t* value_name) {
+ DCHECK(value_name);
+ HRESULT result = RegDeleteValue(key_, value_name);
return (result == ERROR_SUCCESS);
}
@@ -394,29 +379,3 @@ bool RegKey::HasChanged() {
}
return false;
}
-
-// Register a COM object with the most usual properties.
-bool RegisterCOMServer(const tchar* guid,
- const tchar* name,
- const tchar* path) {
- RegKey key(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_WRITE);
- key.CreateKey(guid, KEY_WRITE);
- key.WriteValue(NULL, name);
- key.CreateKey(_T("InprocServer32"), KEY_WRITE);
- key.WriteValue(NULL, path);
- key.WriteValue(_T("ThreadingModel"), _T("Apartment"));
- return true;
-}
-
-bool RegisterCOMServer(const tchar* guid, const tchar* name, HINSTANCE module) {
- tchar module_path[MAX_PATH];
- ::GetModuleFileName(module, module_path, MAX_PATH);
- _tcslwr_s(module_path, MAX_PATH);
- return RegisterCOMServer(guid, name, module_path);
-}
-
-bool UnregisterCOMServer(const tchar* guid) {
- RegKey key(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_WRITE);
- key.DeleteKey(guid);
- return true;
-}
diff --git a/base/registry.h b/base/registry.h
index 0babbc8..7584de0 100644
--- a/base/registry.h
+++ b/base/registry.h
@@ -1,79 +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.
-// All Rights Reserved.
#ifndef BASE_REGISTRY_H_
#define BASE_REGISTRY_H_
+#pragma once
#include <windows.h>
-#include <tchar.h>
-#include <shlwapi.h>
#include <string>
-// The shared file uses a bunch of header files that define types that we don't.
-// To avoid changing much code from the standard version, and also to avoid
-// polluting our namespace with extra types we don't want, we define these types
-// here with the preprocessor and undefine them at the end of the file.
-#define tchar TCHAR
-#define CTP const tchar*
-#define tstr std::basic_string<tchar>
+#include "base/basictypes.h"
-// RegKey
-// Utility class to read from and manipulate the registry.
+// Utility class to read, write and manipulate the Windows Registry.
// Registry vocabulary primer: a "key" is like a folder, in which there
-// are "values", which are <name,data> pairs, with an associated data type.
-
+// are "values", which are <name, data> pairs, with an associated data type.
class RegKey {
public:
- RegKey(HKEY rootkey = NULL, CTP subkey = NULL, REGSAM access = KEY_READ);
-
- ~RegKey() { Close(); }
+ RegKey();
+ RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+ ~RegKey();
- bool Create(HKEY rootkey, CTP subkey, REGSAM access = KEY_READ);
+ bool Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
- bool CreateWithDisposition(HKEY rootkey, CTP subkey, DWORD* disposition,
- REGSAM access = KEY_READ);
+ bool CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+ DWORD* disposition, REGSAM access);
- bool Open(HKEY rootkey, CTP subkey, REGSAM access = KEY_READ);
+ bool Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
- // Create a subkey (or open if exists).
- bool CreateKey(CTP name, REGSAM access);
+ // Creates a subkey or open it if it already exists.
+ bool CreateKey(const wchar_t* name, REGSAM access);
- // Open a subkey
- bool OpenKey(CTP name, REGSAM access);
+ // Opens a subkey
+ bool OpenKey(const wchar_t* name, REGSAM access);
- // all done, eh?
void Close();
- // Count of the number of value extant.
DWORD ValueCount();
- // Determine the Nth value's name.
- bool ReadName(int index, tstr* name);
+ // Determine the nth value's name.
+ bool ReadName(int index, std::wstring* name);
// True while the key is valid.
bool Valid() const { return key_ != NULL; }
- // Kill key and everything that liveth below it; please be careful out there.
- bool DeleteKey(CTP name);
+ // Kill a key and everything that live below it; please be careful when using
+ // it.
+ bool DeleteKey(const wchar_t* name);
+
+ // Deletes a single value within the key.
+ bool DeleteValue(const wchar_t* name);
- // Delete a single value within the key.
- bool DeleteValue(CTP name);
+ bool ValueExists(const wchar_t* name);
- bool ValueExists(CTP name);
- bool ReadValue(CTP name, void* data, DWORD* dsize, DWORD* dtype = NULL);
- bool ReadValue(CTP name, tstr* value);
- bool ReadValueDW(CTP name, DWORD* value); // Named to differ from tstr*
+ 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 WriteValue(CTP name, const void* data, DWORD dsize,
- DWORD dtype = REG_BINARY);
- bool WriteValue(CTP name, CTP value);
- bool WriteValue(CTP name, DWORD value);
+ bool WriteValue(const wchar_t* name, const void* data, DWORD dsize,
+ DWORD dtype);
+ bool WriteValue(const wchar_t* name, const wchar_t* value);
+ bool WriteValue(const wchar_t* name, DWORD value);
- // Start watching the key to see if any of its values have changed.
- // The key must have been opened with the KEY_NOTIFY access
- // privelege.
+ // 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.
bool StartWatching();
// If StartWatching hasn't been called, always returns false.
@@ -92,6 +81,8 @@ class RegKey {
private:
HKEY key_; // The registry key being iterated.
HANDLE watch_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegKey);
};
// Iterates the entries found in a particular folder on the registry.
@@ -100,78 +91,75 @@ class RegKey {
// adequate.
class RegistryValueIterator {
public:
- // Specify a key in construction.
- RegistryValueIterator(HKEY root_key, LPCTSTR folder_key);
+ RegistryValueIterator(HKEY root_key, const wchar_t* folder_key);
~RegistryValueIterator();
- DWORD ValueCount() const; // Count of the number of subkeys extant.
+ DWORD ValueCount() const;
- bool Valid() const; // True while the iterator is valid.
+ // True while the iterator is valid.
+ bool Valid() const;
- void operator++(); // Advance to the next entry in the folder.
+ // Advances to the next registry entry.
+ void operator++();
- // The pointers returned by these functions are statics owned by the
- // Name and Value functions.
- CTP Name() const { return name_; }
- CTP Value() const { return value_; }
+ const wchar_t* Name() const { return name_; }
+ const wchar_t* Value() const { return value_; }
DWORD ValueSize() const { return value_size_; }
DWORD Type() const { return type_; }
int Index() const { return index_; }
private:
- bool Read(); // Read in the current values.
+ // Read in the current values.
+ bool Read();
+
+ // The registry key being iterated.
+ HKEY key_;
- HKEY key_; // The registry key being iterated.
- int index_; // Current index of the iteration.
+ // Current index of the iteration.
+ int index_;
// Current values.
- TCHAR name_[MAX_PATH];
- TCHAR value_[MAX_PATH];
+ wchar_t name_[MAX_PATH];
+ wchar_t value_[MAX_PATH];
DWORD value_size_;
DWORD type_;
-};
+ DISALLOW_COPY_AND_ASSIGN(RegistryValueIterator);
+};
class RegistryKeyIterator {
public:
- // Specify a parent key in construction.
- RegistryKeyIterator(HKEY root_key, LPCTSTR folder_key);
+ RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key);
~RegistryKeyIterator();
- DWORD SubkeyCount() const; // Count of the number of subkeys extant.
+ DWORD SubkeyCount() const;
- bool Valid() const; // True while the iterator is valid.
+ // True while the iterator is valid.
+ bool Valid() const;
- void operator++(); // Advance to the next entry in the folder.
+ // Advances to the next entry in the folder.
+ void operator++();
- // The pointer returned by Name() is a static owned by the function.
- CTP Name() const { return name_; }
+ const wchar_t* Name() const { return name_; }
int Index() const { return index_; }
private:
- bool Read(); // Read in the current values.
+ // Read in the current values.
+ bool Read();
- HKEY key_; // The registry key being iterated.
- int index_; // Current index of the iteration.
+ // The registry key being iterated.
+ HKEY key_;
- // Current values.
- TCHAR name_[MAX_PATH];
-};
+ // Current index of the iteration.
+ int index_;
+ wchar_t name_[MAX_PATH];
-// Register a COM object with the most usual properties.
-bool RegisterCOMServer(const tchar* guid, const tchar* name,
- const tchar* modulepath);
-bool RegisterCOMServer(const tchar* guid, const tchar* name, HINSTANCE module);
-bool UnregisterCOMServer(const tchar* guid);
-
-// undo the local types defined above
-#undef tchar
-#undef CTP
-#undef tstr
+ DISALLOW_COPY_AND_ASSIGN(RegistryKeyIterator);
+};
#endif // BASE_REGISTRY_H_
diff --git a/base/registry_unittest.cc b/base/registry_unittest.cc
new file mode 100644
index 0000000..2618a75
--- /dev/null
+++ b/base/registry_unittest.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 "base/registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const wchar_t kRootKey[] = L"Base_Registry_Unittest";
+
+class RegistryTest : public testing::Test {
+ public:
+ RegistryTest() {}
+
+ protected:
+ virtual void SetUp() {
+ // Create a temporary key.
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+ key.DeleteKey(kRootKey);
+ ASSERT_FALSE(key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+ }
+
+ virtual void TearDown() {
+ // Clean up the temporary key.
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
+ ASSERT_TRUE(key.DeleteKey(kRootKey));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RegistryTest);
+};
+
+TEST_F(RegistryTest, ValueTest) {
+ RegKey key;
+
+ std::wstring foo_key(kRootKey);
+ foo_key += L"\\Foo";
+ ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+ {
+ ASSERT_TRUE(key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+ KEY_READ | KEY_SET_VALUE));
+
+ const wchar_t* kName = L"Bar";
+ const wchar_t* kValue = L"bar";
+ EXPECT_TRUE(key.WriteValue(kName, kValue));
+ EXPECT_TRUE(key.ValueExists(kName));
+ std::wstring out_value;
+ EXPECT_TRUE(key.ReadValue(kName, &out_value));
+ EXPECT_NE(out_value, L"");
+ EXPECT_STREQ(out_value.c_str(), kValue);
+ EXPECT_EQ(1U, key.ValueCount());
+ EXPECT_TRUE(key.DeleteValue(kName));
+ }
+}
+
+} // namespace
diff --git a/base/resource_util.h b/base/resource_util.h
index eb2276f..8a37f95 100644
--- a/base/resource_util.h
+++ b/base/resource_util.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.
@@ -7,18 +7,19 @@
#ifndef BASE_RESOURCE_UTIL_H__
#define BASE_RESOURCE_UTIL_H__
+#pragma once
#include <windows.h>
-#include <string>
#include "base/basictypes.h"
namespace base {
+
// Function for getting a data resource (BINDATA) from a dll. Some
// resources are optional, especially in unit tests, so this returns false
// but doesn't raise an error if the resource can't be loaded.
bool GetDataResourceFromModule(HMODULE module, int resource_id,
void** data, size_t* length);
-} // namespace
+} // namespace base
#endif // BASE_RESOURCE_UTIL_H__
diff --git a/base/safe_strerror_posix.h b/base/safe_strerror_posix.h
index ecf3a78..03c18c8 100644
--- a/base/safe_strerror_posix.h
+++ b/base/safe_strerror_posix.h
@@ -4,6 +4,7 @@
#ifndef BASE_SAFE_STRERROR_POSIX_H_
#define BASE_SAFE_STRERROR_POSIX_H_
+#pragma once
#include <string>
diff --git a/base/scoped_aedesc.h b/base/scoped_aedesc.h
new file mode 100644
index 0000000..9239887
--- /dev/null
+++ b/base/scoped_aedesc.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 BASE_SCOPED_AEDESC_H_
+#define BASE_SCOPED_AEDESC_H_
+#pragma once
+
+#import <CoreServices/CoreServices.h>
+
+#include "base/basictypes.h"
+
+// The scoped_aedesc is used to scope AppleEvent descriptors. On creation,
+// it will store a NULL descriptor. On destruction, it will dispose of the
+// descriptor.
+//
+// This class is parameterized for additional type safety checks. You can use
+// the generic AEDesc type by not providing a template parameter:
+// scoped_aedesc<> desc;
+template <typename AEDescType = AEDesc>
+class scoped_aedesc {
+ public:
+ scoped_aedesc() {
+ AECreateDesc(typeNull, NULL, 0, &desc_);
+ }
+
+ ~scoped_aedesc() {
+ AEDisposeDesc(&desc_);
+ }
+
+ // Used for in parameters.
+ operator const AEDescType*() {
+ return &desc_;
+ }
+
+ // Used for out parameters.
+ AEDescType* OutPointer() {
+ return &desc_;
+ }
+
+ private:
+ AEDescType desc_;
+
+ DISALLOW_COPY_AND_ASSIGN(scoped_aedesc);
+};
+
+#endif // BASE_SCOPED_AEDESC_H_
diff --git a/base/scoped_bstr_win.h b/base/scoped_bstr_win.h
index 04f27e1..42a9c21 100644
--- a/base/scoped_bstr_win.h
+++ b/base/scoped_bstr_win.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_BSTR_WIN_H_
#define BASE_SCOPED_BSTR_WIN_H_
+#pragma once
#include <windows.h>
#include <oleauto.h>
diff --git a/base/scoped_callback_factory.h b/base/scoped_callback_factory.h
new file mode 100644
index 0000000..a2fc1f0
--- /dev/null
+++ b/base/scoped_callback_factory.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ScopedCallbackFactory helps in cases where you wish to allocate a Callback
+// (see base/callback.h), but need to prevent any pending callbacks from
+// executing when your object gets destroyed.
+//
+// EXAMPLE:
+//
+// void GatherDataAsynchronously(Callback1<Data>::Type* callback);
+//
+// class MyClass {
+// public:
+// MyClass() : factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+// }
+//
+// void Process() {
+// GatherDataAsynchronously(factory_.NewCallback(&MyClass::GotData));
+// }
+//
+// private:
+// void GotData(const Data& data) {
+// ...
+// }
+//
+// base::ScopedCallbackFactory<MyClass> factory_;
+// };
+//
+// In the above example, the Process function calls GatherDataAsynchronously to
+// kick off some asynchronous processing that upon completion will notify a
+// callback. If in the meantime, the MyClass instance is destroyed, when the
+// callback runs, it will notice that the MyClass instance is dead, and it will
+// avoid calling the GotData method.
+
+#ifndef BASE_SCOPED_CALLBACK_FACTORY_H_
+#define BASE_SCOPED_CALLBACK_FACTORY_H_
+
+#include "base/callback.h"
+#include "base/weak_ptr.h"
+
+namespace base {
+
+template <class T>
+class ScopedCallbackFactory {
+ public:
+ explicit ScopedCallbackFactory(T* obj) : weak_factory_(obj) {
+ }
+
+ typename Callback0::Type* NewCallback(
+ void (T::*method)()) {
+ return new CallbackImpl<void (T::*)(), Tuple0 >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1>
+ typename Callback1<Arg1>::Type* NewCallback(
+ void (T::*method)(Arg1)) {
+ return new CallbackImpl<void (T::*)(Arg1), Tuple1<Arg1> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2>
+ typename Callback2<Arg1, Arg2>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2), Tuple2<Arg1, Arg2> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3>
+ typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2, Arg3)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3),
+ Tuple3<Arg1, Arg2, Arg3> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2, Arg3, Arg4)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3, Arg4),
+ Tuple4<Arg1, Arg2, Arg3, Arg4> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback(
+ void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) {
+ return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5),
+ Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(
+ weak_factory_.GetWeakPtr(), method);
+ }
+
+ void RevokeAll() { weak_factory_.InvalidateWeakPtrs(); }
+ bool HasPendingCallbacks() const { return weak_factory_.HasWeakPtrs(); }
+
+ private:
+ template <typename Method>
+ class CallbackStorage {
+ public:
+ CallbackStorage(const WeakPtr<T>& obj, Method meth)
+ : obj_(obj),
+ meth_(meth) {
+ }
+
+ protected:
+ WeakPtr<T> obj_;
+ Method meth_;
+ };
+
+ template <typename Method, typename Params>
+ class CallbackImpl : public CallbackStorage<Method>,
+ public CallbackRunner<Params> {
+ public:
+ CallbackImpl(const WeakPtr<T>& obj, Method meth)
+ : CallbackStorage<Method>(obj, meth) {
+ }
+ virtual void RunWithParams(const Params& params) {
+ // Use "this->" to force C++ to look inside our templatized base class;
+ // see Effective C++, 3rd Ed, item 43, p210 for details.
+ if (!this->obj_)
+ return;
+ DispatchToMethod(this->obj_.get(), this->meth_, params);
+ }
+ };
+
+ WeakPtrFactory<T> weak_factory_;
+};
+
+} // namespace base
+
+#endif // BASE_SCOPED_CALLBACK_FACTORY_H_
diff --git a/base/scoped_cftyperef.h b/base/scoped_cftyperef.h
index 908be24..4e41816 100644
--- a/base/scoped_cftyperef.h
+++ b/base/scoped_cftyperef.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_CFTYPEREF_H_
#define BASE_SCOPED_CFTYPEREF_H_
+#pragma once
#include <CoreFoundation/CoreFoundation.h>
#include "base/basictypes.h"
diff --git a/base/scoped_comptr_win.h b/base/scoped_comptr_win.h
index dbe2805..dd9b9fc 100644
--- a/base/scoped_comptr_win.h
+++ b/base/scoped_comptr_win.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_COMPTR_WIN_H_
#define BASE_SCOPED_COMPTR_WIN_H_
+#pragma once
#include <unknwn.h>
diff --git a/base/scoped_handle.h b/base/scoped_handle.h
index cc87e6a..43ee975 100644
--- a/base/scoped_handle.h
+++ b/base/scoped_handle.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_HANDLE_H_
#define BASE_SCOPED_HANDLE_H_
+#pragma once
#include <stdio.h>
diff --git a/base/scoped_handle_win.h b/base/scoped_handle_win.h
index 1f4cdbe..4011a18 100644
--- a/base/scoped_handle_win.h
+++ b/base/scoped_handle_win.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_HANDLE_WIN_H_
#define BASE_SCOPED_HANDLE_WIN_H_
+#pragma once
#include <windows.h>
diff --git a/base/scoped_native_library.h b/base/scoped_native_library.h
index 3227dba..bed5c39 100644
--- a/base/scoped_native_library.h
+++ b/base/scoped_native_library.h
@@ -4,10 +4,12 @@
#ifndef BASE_SCOPED_NATIVE_LIBRARY_H_
#define BASE_SCOPED_NATIVE_LIBRARY_H_
+#pragma once
-#include "base/file_path.h"
#include "base/native_library.h"
+class FilePath;
+
namespace base {
// A class which encapsulates a base::NativeLibrary object available only in a
diff --git a/base/scoped_native_library_unittest.cc b/base/scoped_native_library_unittest.cc
index 178e20d..567239d 100644
--- a/base/scoped_native_library_unittest.cc
+++ b/base/scoped_native_library_unittest.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "base/scoped_native_library.h"
+#if defined(OS_WIN)
+#include "base/file_path.h"
+#endif
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/scoped_nsautorelease_pool.h b/base/scoped_nsautorelease_pool.h
index 64bf9e7..9f428ac 100644
--- a/base/scoped_nsautorelease_pool.h
+++ b/base/scoped_nsautorelease_pool.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_NSAUTORELEASE_POOL_H_
#define BASE_SCOPED_NSAUTORELEASE_POOL_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/scoped_nsdisable_screen_updates.h b/base/scoped_nsdisable_screen_updates.h
index 964f1bc..5af6026 100644
--- a/base/scoped_nsdisable_screen_updates.h
+++ b/base/scoped_nsdisable_screen_updates.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_NSDISABLE_SCREEN_UPDATES_H_
#define BASE_SCOPED_NSDISABLE_SCREEN_UPDATES_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/base/scoped_nsobject.h b/base/scoped_nsobject.h
index bde2753..1b40ade 100644
--- a/base/scoped_nsobject.h
+++ b/base/scoped_nsobject.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_NSOBJECT_H_
#define BASE_SCOPED_NSOBJECT_H_
+#pragma once
#import <Foundation/Foundation.h>
#include "base/basictypes.h"
@@ -48,13 +49,8 @@ class scoped_nsobject {
object_ = object;
}
- bool operator==(NST* that) const {
- return object_ == that;
- }
-
- bool operator!=(NST* that) const {
- return object_ != that;
- }
+ bool operator==(NST* that) const { return object_ == that; }
+ bool operator!=(NST* that) const { return object_ != that; }
operator NST*() const {
return object_;
@@ -85,6 +81,23 @@ class scoped_nsobject {
DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
};
+// Free functions
+template <class C>
+void swap(scoped_nsobject<C>& p1, scoped_nsobject<C>& p2) {
+ p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C* p1, const scoped_nsobject<C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C* p1, const scoped_nsobject<C>& p2) {
+ return p1 != p2.get();
+}
+
+
// Specialization to make scoped_nsobject<id> work.
template<>
class scoped_nsobject<id> {
@@ -109,13 +122,8 @@ class scoped_nsobject<id> {
object_ = object;
}
- bool operator==(id that) const {
- return object_ == that;
- }
-
- bool operator!=(id that) const {
- return object_ != that;
- }
+ bool operator==(id that) const { return object_ == that; }
+ bool operator!=(id that) const { return object_ != that; }
operator id() const {
return object_;
diff --git a/base/scoped_open_process.h b/base/scoped_open_process.h
index 9badc76..641f8e5 100644
--- a/base/scoped_open_process.h
+++ b/base/scoped_open_process.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_OPEN_PROCESS_H_
#define BASE_SCOPED_OPEN_PROCESS_H_
+#pragma once
#include "base/process.h"
#include "base/process_util.h"
diff --git a/base/scoped_ptr.h b/base/scoped_ptr.h
index c716e77..88ee41b 100644
--- a/base/scoped_ptr.h
+++ b/base/scoped_ptr.h
@@ -4,7 +4,7 @@
// Scopers help you manage ownership of a pointer, helping you easily manage the
// a pointer within a scope, and automatically destroying the pointer at the
-// end of a scope. There are two main classes you will use, which coorespond
+// end of a scope. There are two main classes you will use, which correspond
// to the operators new/delete and new[]/delete[].
//
// Example usage (scoped_ptr):
@@ -19,7 +19,7 @@
// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed.
// foo->Method(); // Foo::Method() called.
// foo.get()->Method(); // Foo::Method() called.
-// SomeFunc(foo.release()); // SomeFunc takes owernship, foo no longer
+// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer
// // manages a pointer.
// foo.reset(new Foo("wee4")); // foo manages a pointer again.
// foo.reset(); // Foo("wee4") destroyed, foo no longer
@@ -35,6 +35,7 @@
#ifndef BASE_SCOPED_PTR_H_
#define BASE_SCOPED_PTR_H_
+#pragma once
// This is an implementation designed to match the anticipated future TR2
// implementation of the scoped_ptr class, and its closely-related brethren,
@@ -62,7 +63,7 @@ class scoped_ptr {
// The element type
typedef C element_type;
- // Constructor. Defaults to intializing with NULL.
+ // Constructor. Defaults to initializing with NULL.
// There is no way to create an uninitialized scoped_ptr.
// The input parameter must be allocated with new.
explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
@@ -275,7 +276,7 @@ class scoped_ptr_malloc {
// The element type
typedef C element_type;
- // Constructor. Defaults to intializing with NULL.
+ // Constructor. Defaults to initializing with NULL.
// There is no way to create an uninitialized scoped_ptr.
// The input parameter must be allocated with an allocator that matches the
// Free functor. For the default Free functor, this is malloc, calloc, or
@@ -317,7 +318,7 @@ class scoped_ptr_malloc {
// Comparison operators.
// These return whether a scoped_ptr_malloc and a plain pointer refer
// to the same object, not just to two different but equal objects.
- // For compatibility wwith the boost-derived implementation, these
+ // For compatibility with the boost-derived implementation, these
// take non-const arguments.
bool operator==(C* p) const {
return ptr_ == p;
diff --git a/base/scoped_temp_dir.cc b/base/scoped_temp_dir.cc
index 28f59bf..a510ddf 100644
--- a/base/scoped_temp_dir.cc
+++ b/base/scoped_temp_dir.cc
@@ -4,17 +4,14 @@
#include "base/scoped_temp_dir.h"
-#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
-#include "base/string_util.h"
ScopedTempDir::ScopedTempDir() {
}
ScopedTempDir::~ScopedTempDir() {
- if (!path_.empty() && !file_util::Delete(path_, true))
- LOG(ERROR) << "ScopedTempDir unable to delete " << path_.value();
+ Delete();
}
bool ScopedTempDir::CreateUniqueTempDir() {
@@ -27,19 +24,15 @@ bool ScopedTempDir::CreateUniqueTempDir() {
return true;
}
-bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path,
- bool loose_permissions) {
+bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path) {
// If |path| does not exist, create it.
- if (!file_util::CreateDirectory(base_path)) {
- LOG(ERROR) << "Failed to create base directory " << base_path.value();
+ if (!file_util::CreateDirectory(base_path))
return false;
- }
// Create a new, uniquely named directory under |base_path|.
if (!file_util::CreateTemporaryDirInDir(
base_path,
FILE_PATH_LITERAL("scoped_dir_"),
- loose_permissions,
&path_)) {
return false;
}
@@ -56,6 +49,12 @@ bool ScopedTempDir::Set(const FilePath& path) {
return true;
}
+void ScopedTempDir::Delete() {
+ if (!path_.empty() && !file_util::Delete(path_, true))
+ LOG(ERROR) << "ScopedTempDir unable to delete " << path_.value();
+ path_.clear();
+}
+
FilePath ScopedTempDir::Take() {
FilePath ret = path_;
path_ = FilePath();
diff --git a/base/scoped_temp_dir.h b/base/scoped_temp_dir.h
index a0708dc..66d52f6 100644
--- a/base/scoped_temp_dir.h
+++ b/base/scoped_temp_dir.h
@@ -4,6 +4,7 @@
#ifndef BASE_SCOPED_TEMP_DIR_H_
#define BASE_SCOPED_TEMP_DIR_H_
+#pragma once
// An object representing a temporary / scratch directory that should be cleaned
// up (recursively) when this object goes out of scope. Note that since
@@ -18,7 +19,7 @@ class ScopedTempDir {
// No directory is owned/created initially.
ScopedTempDir();
- // Recursively delete path_
+ // Recursively delete path.
~ScopedTempDir();
// Creates a unique directory in TempPath, and takes ownership of it.
@@ -26,13 +27,15 @@ class ScopedTempDir {
bool CreateUniqueTempDir();
// Creates a unique directory under a given path, and takes ownership of it.
- bool CreateUniqueTempDirUnderPath(const FilePath& path,
- bool loose_permissions);
+ bool CreateUniqueTempDirUnderPath(const FilePath& path);
// Takes ownership of directory at |path|, creating it if necessary.
// Don't call multiple times unless Take() has been called first.
bool Set(const FilePath& path);
+ // Deletes the temporary directory wrapped by this object.
+ void Delete();
+
// Caller takes ownership of the temporary directory so it won't be destroyed
// when this object goes out of scope.
FilePath Take();
diff --git a/base/scoped_temp_dir_unittest.cc b/base/scoped_temp_dir_unittest.cc
index e180119..4be0d07 100644
--- a/base/scoped_temp_dir_unittest.cc
+++ b/base/scoped_temp_dir_unittest.cc
@@ -65,7 +65,7 @@ TEST(ScopedTempDir, UniqueTempDirUnderPath) {
FilePath test_path;
{
ScopedTempDir dir;
- EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path, false));
+ EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path));
test_path = dir.path();
EXPECT_TRUE(file_util::DirectoryExists(test_path));
EXPECT_TRUE(base_path.IsParent(test_path));
diff --git a/base/scoped_variant_win.h b/base/scoped_variant_win.h
index 4436ca9..c712e50 100644
--- a/base/scoped_variant_win.h
+++ b/base/scoped_variant_win.h
@@ -1,15 +1,16 @@
-// 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.
#ifndef BASE_SCOPED_VARIANT_WIN_H_
#define BASE_SCOPED_VARIANT_WIN_H_
+#pragma once
#include <windows.h>
#include <oleauto.h>
-#include "base/basictypes.h" // needed to pick up OS_WIN
-#include "base/logging.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
// Scoped VARIANT class for automatically freeing a COM VARIANT at the
// end of a scope. Additionally provides a few functions to make the
diff --git a/base/scoped_vector.h b/base/scoped_vector.h
index c007ce4..ec152c9 100644
--- a/base/scoped_vector.h
+++ b/base/scoped_vector.h
@@ -4,10 +4,11 @@
#ifndef BASE_SCOPED_VECTOR_H_
#define BASE_SCOPED_VECTOR_H_
+#pragma once
#include <vector>
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "base/stl_util-inl.h"
// ScopedVector wraps a vector deleting the elements from its
@@ -26,7 +27,7 @@ class ScopedVector {
std::vector<T*>* operator->() { return &v; }
const std::vector<T*>* operator->() const { return &v; }
- T* operator[](size_t i) { return v[i]; }
+ T*& operator[](size_t i) { return v[i]; }
const T* operator[](size_t i) const { return v[i]; }
bool empty() const { return v.empty(); }
@@ -53,7 +54,32 @@ class ScopedVector {
}
void reset() { STLDeleteElements(&v); }
+ void resize(size_t new_size) { v.resize(new_size); }
+ // Lets the ScopedVector take ownership of |x|.
+ iterator insert(iterator position, T* x) {
+ return v.insert(position, x);
+ }
+
+ iterator erase(iterator position) {
+ delete *position;
+ return v.erase(position);
+ }
+
+ iterator erase(iterator first, iterator last) {
+ STLDeleteContainerPointers(first, last);
+ return v.erase(first, last);
+ }
+
+ // Like |erase()|, but doesn't delete the element at |position|.
+ iterator weak_erase(iterator position) {
+ return v.erase(position);
+ }
+
+ // Like |erase()|, but doesn't delete the elements in [first, last).
+ iterator weak_erase(iterator first, iterator last) {
+ return v.erase(first, last);
+ }
private:
std::vector<T*> v;
diff --git a/base/setproctitle_linux.h b/base/setproctitle_linux.h
index c1cf689..769338c 100644
--- a/base/setproctitle_linux.h
+++ b/base/setproctitle_linux.h
@@ -4,6 +4,7 @@
#ifndef BASE_SETPROCTITLE_LINUX_H_
#define BASE_SETPROCTITLE_LINUX_H_
+#pragma once
#ifdef __cplusplus
extern "C" {
diff --git a/base/sha1.h b/base/sha1.h
index bcc1ced..dd43686 100644
--- a/base/sha1.h
+++ b/base/sha1.h
@@ -4,6 +4,7 @@
#ifndef BASE_SHA1_H_
#define BASE_SHA1_H_
+#pragma once
#include <string>
diff --git a/base/sha1_win.cc b/base/sha1_win.cc
index b79ac38..0d0cf2c 100644
--- a/base/sha1_win.cc
+++ b/base/sha1_win.cc
@@ -8,7 +8,6 @@
#include <wincrypt.h>
#include "base/logging.h"
-#include "base/string_util.h"
namespace base {
diff --git a/base/sha2.cc b/base/sha2.cc
index b6d6d56..c0fd0ab 100644
--- a/base/sha2.cc
+++ b/base/sha2.cc
@@ -4,6 +4,7 @@
#include "base/sha2.h"
+#include "base/stl_util-inl.h"
#include "base/third_party/nss/blapi.h"
#include "base/third_party/nss/sha256.h"
@@ -19,4 +20,10 @@ void SHA256HashString(const std::string& str, void* output, size_t len) {
static_cast<unsigned int>(len));
}
+std::string SHA256HashString(const std::string& str) {
+ std::string output(SHA256_LENGTH, 0);
+ SHA256HashString(str, string_as_array(&output), output.size());
+ return output;
+}
+
} // namespace base
diff --git a/base/sha2.h b/base/sha2.h
index 5678dbf..19e41c3 100644
--- a/base/sha2.h
+++ b/base/sha2.h
@@ -4,6 +4,7 @@
#ifndef BASE_SHA2_H_
#define BASE_SHA2_H_
+#pragma once
#include <string>
@@ -22,6 +23,10 @@ enum {
// only 32 bytes (the full hash) are stored in the 'output' buffer.
void SHA256HashString(const std::string& str, void* output, size_t len);
+// Convenience version of the above that returns the result in a 32-byte
+// string.
+std::string SHA256HashString(const std::string& str);
+
} // namespace base
#endif // BASE_SHA2_H_
diff --git a/base/sha2_unittest.cc b/base/sha2_unittest.cc
index a6844dd..b0321e8 100644
--- a/base/sha2_unittest.cc
+++ b/base/sha2_unittest.cc
@@ -30,6 +30,25 @@ TEST(Sha256Test, Test1) {
EXPECT_EQ(expected1[i], static_cast<int>(output_truncated1[i]));
}
+TEST(Sha256Test, Test1_String) {
+ // Same as the above, but using the wrapper that returns a std::string.
+ // Example B.1 from FIPS 180-2: one-block message.
+ std::string input1 = "abc";
+ int expected1[] = { 0xba, 0x78, 0x16, 0xbf,
+ 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3,
+ 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61,
+ 0xf2, 0x00, 0x15, 0xad };
+
+ std::string output1 = base::SHA256HashString(input1);
+ ASSERT_EQ(base::SHA256_LENGTH, output1.size());
+ for (size_t i = 0; i < base::SHA256_LENGTH; i++)
+ EXPECT_EQ(expected1[i], static_cast<uint8>(output1[i]));
+}
+
TEST(Sha256Test, Test2) {
// Example B.2 from FIPS 180-2: multi-block message.
std::string input2 =
diff --git a/base/shared_memory.h b/base/shared_memory.h
index b6701f8..053026e 100644
--- a/base/shared_memory.h
+++ b/base/shared_memory.h
@@ -4,6 +4,7 @@
#ifndef BASE_SHARED_MEMORY_H_
#define BASE_SHARED_MEMORY_H_
+#pragma once
#include "build/build_config.h"
@@ -71,18 +72,18 @@ class SharedMemory {
// opens the existing shared memory and ignores the size parameter.
// If name is the empty string, use a unique name.
// Returns true on success, false on failure.
- bool Create(const std::wstring& name, bool read_only, bool open_existing,
+ bool Create(const std::string& name, bool read_only, bool open_existing,
uint32 size);
// Deletes resources associated with a shared memory segment based on name.
// Not all platforms require this call.
- bool Delete(const std::wstring& name);
+ bool Delete(const std::string& name);
// Opens a shared memory segment based on a name.
// If read_only is true, opens for read-only access.
// If name is the empty string, use a unique name.
// Returns true on success, false on failure.
- bool Open(const std::wstring& name, bool read_only);
+ bool Open(const std::string& name, bool read_only);
// Maps the shared memory into the caller's address space.
// Returns true on success, false otherwise. The memory address
@@ -160,10 +161,9 @@ class SharedMemory {
private:
#if defined(OS_POSIX)
- bool CreateOrOpen(const std::wstring &name, int posix_flags, uint32 size);
- bool FilePathForMemoryName(const std::wstring& memname, FilePath* path);
+ bool CreateOrOpen(const std::string& name, int posix_flags, uint32 size);
+ bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
void LockOrUnlockCommon(int function);
-
#endif
bool ShareToProcessCommon(ProcessHandle process,
SharedMemoryHandle* new_handle,
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc
index 009f91e..7283cbd 100644
--- a/base/shared_memory_posix.cc
+++ b/base/shared_memory_posix.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.
@@ -14,7 +14,7 @@
#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/safe_strerror_posix.h"
-#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
namespace base {
@@ -77,7 +77,7 @@ void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
close(handle.fd);
}
-bool SharedMemory::Create(const std::wstring &name, bool read_only,
+bool SharedMemory::Create(const std::string& name, bool read_only,
bool open_existing, uint32 size) {
read_only_ = read_only;
@@ -96,7 +96,7 @@ bool SharedMemory::Create(const std::wstring &name, bool read_only,
// Our current implementation of shmem is with mmap()ing of files.
// These files need to be deleted explicitly.
// In practice this call is only needed for unit tests.
-bool SharedMemory::Delete(const std::wstring& name) {
+bool SharedMemory::Delete(const std::string& name) {
FilePath path;
if (!FilePathForMemoryName(name, &path))
return false;
@@ -109,7 +109,7 @@ bool SharedMemory::Delete(const std::wstring& name) {
return true;
}
-bool SharedMemory::Open(const std::wstring &name, bool read_only) {
+bool SharedMemory::Open(const std::string& name, bool read_only) {
read_only_ = read_only;
int posix_flags = 0;
@@ -118,22 +118,21 @@ bool SharedMemory::Open(const std::wstring &name, bool read_only) {
return CreateOrOpen(name, posix_flags, 0);
}
-// For the given shmem named |memname|, return a filename to mmap()
+// For the given shmem named |mem_name|, return a filename to mmap()
// (and possibly create). Modifies |filename|. Return false on
// error, or true of we are happy.
-bool SharedMemory::FilePathForMemoryName(const std::wstring& memname,
+bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
FilePath* path) {
// mem_name will be used for a filename; make sure it doesn't
// contain anything which will confuse us.
- DCHECK(memname.find_first_of(L"/") == std::string::npos);
- DCHECK(memname.find_first_of(L"\0") == std::string::npos);
+ DCHECK(mem_name.find('/') == std::string::npos);
+ DCHECK(mem_name.find('\0') == std::string::npos);
FilePath temp_dir;
- if (file_util::GetShmemTempDir(&temp_dir) == false)
+ if (!file_util::GetShmemTempDir(&temp_dir))
return false;
- *path = temp_dir.AppendASCII("com.google.chrome.shmem." +
- WideToASCII(memname));
+ *path = temp_dir.AppendASCII("com.google.chrome.shmem." + mem_name);
return true;
}
@@ -143,7 +142,7 @@ bool SharedMemory::FilePathForMemoryName(const std::wstring& memname,
// we restart from a crash. (That isn't a new problem, but it is a problem.)
// In case we want to delete it later, it may be useful to save the value
// of mem_filename after FilePathForMemoryName().
-bool SharedMemory::CreateOrOpen(const std::wstring &name,
+bool SharedMemory::CreateOrOpen(const std::string& name,
int posix_flags, uint32 size) {
DCHECK(mapped_file_ == -1);
@@ -151,7 +150,7 @@ bool SharedMemory::CreateOrOpen(const std::wstring &name,
FILE *fp;
FilePath path;
- if (name == L"") {
+ if (name.empty()) {
// It doesn't make sense to have a read-only private piece of shmem
DCHECK(posix_flags & (O_RDWR | O_WRONLY));
@@ -162,7 +161,8 @@ bool SharedMemory::CreateOrOpen(const std::wstring &name,
// Deleting the file prevents anyone else from mapping it in
// (making it private), and prevents the need for cleanup (once
// the last fd is closed, it is truly freed).
- file_util::Delete(path, false);
+ if (fp)
+ file_util::Delete(path, false);
} else {
if (!FilePathForMemoryName(name, &path))
return false;
@@ -190,9 +190,15 @@ bool SharedMemory::CreateOrOpen(const std::wstring &name,
if (fp == NULL) {
if (posix_flags & O_CREAT) {
#if !defined(OS_MACOSX)
- PLOG(FATAL) << "Creating shared memory in " << path.value() << " failed. "
- << "This is frequently caused by incorrect permissions on "
- << "/dev/shm. Try 'sudo chmod 777 /dev/shm' to fix.";
+ PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+ FilePath dir = path.DirName();
+ if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
+ PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
+ if (dir.value() == "/dev/shm") {
+ LOG(FATAL) << "This is frequently caused by incorrect permissions on "
+ << "/dev/shm. Try 'sudo chmod 777 /dev/shm' to fix.";
+ }
+ }
#else
PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
#endif
diff --git a/base/shared_memory_unittest.cc b/base/shared_memory_unittest.cc
index 459b423..97287fa 100644
--- a/base/shared_memory_unittest.cc
+++ b/base/shared_memory_unittest.cc
@@ -3,12 +3,13 @@
// found in the LICENSE file.
#include "base/basictypes.h"
-#include "base/multiprocess_test.h"
#include "base/platform_thread.h"
#include "base/scoped_nsautorelease_pool.h"
#include "base/shared_memory.h"
#include "base/scoped_ptr.h"
+#include "base/test/multiprocess_test.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
static const int kNumThreads = 5;
static const int kNumTasks = 5;
@@ -54,13 +55,13 @@ class MultipleThreadMain : public PlatformThread::Delegate {
private:
int16 id_;
- static const wchar_t* const s_test_name_;
+ static const char* const s_test_name_;
DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
};
-const wchar_t* const MultipleThreadMain::s_test_name_ =
- L"SharedMemoryOpenThreadTest";
+const char* const MultipleThreadMain::s_test_name_ =
+ "SharedMemoryOpenThreadTest";
// TODO(port):
// This test requires the ability to pass file descriptors between processes.
@@ -81,7 +82,7 @@ class MultipleLockThread : public PlatformThread::Delegate {
SharedMemoryHandle handle = NULL;
{
SharedMemory memory1;
- EXPECT_TRUE(memory1.Create(L"SharedMemoryMultipleLockThreadTest",
+ EXPECT_TRUE(memory1.Create("SharedMemoryMultipleLockThreadTest",
false, true, kDataSize));
EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
// TODO(paulg): Implement this once we have a posix version of
@@ -116,7 +117,7 @@ class MultipleLockThread : public PlatformThread::Delegate {
TEST(SharedMemoryTest, OpenClose) {
const uint32 kDataSize = 1024;
- std::wstring test_name = L"SharedMemoryOpenCloseTest";
+ std::string test_name = "SharedMemoryOpenCloseTest";
// Open two handles to a memory segment, confirm that they are mapped
// separately yet point to the same space.
@@ -242,7 +243,7 @@ TEST(SharedMemoryTest, AnonymousPrivate) {
ASSERT_TRUE(pointers.get());
for (i = 0; i < count; i++) {
- rv = memories[i].Create(L"", false, true, kDataSize);
+ rv = memories[i].Create("", false, true, kDataSize);
EXPECT_TRUE(rv);
rv = memories[i].Map(kDataSize);
EXPECT_TRUE(rv);
@@ -271,13 +272,11 @@ TEST(SharedMemoryTest, AnonymousPrivate) {
for (int i = 0; i < count; i++) {
memories[i].Close();
}
-
}
-
// On POSIX it is especially important we test shmem across processes,
// not just across threads. But the test is enabled on all platforms.
-class SharedMemoryProcessTest : public MultiProcessTest {
+class SharedMemoryProcessTest : public base::MultiProcessTest {
public:
static void CleanUp() {
@@ -315,10 +314,10 @@ class SharedMemoryProcessTest : public MultiProcessTest {
}
private:
- static const wchar_t* const s_test_name_;
+ static const char* const s_test_name_;
};
-const wchar_t* const SharedMemoryProcessTest::s_test_name_ = L"MPMem";
+const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
TEST_F(SharedMemoryProcessTest, Tasks) {
@@ -326,7 +325,7 @@ TEST_F(SharedMemoryProcessTest, Tasks) {
base::ProcessHandle handles[kNumTasks];
for (int index = 0; index < kNumTasks; ++index) {
- handles[index] = SpawnChild(L"SharedMemoryTestMain");
+ handles[index] = SpawnChild("SharedMemoryTestMain", false);
}
int exit_code = 0;
@@ -342,5 +341,4 @@ MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
return SharedMemoryProcessTest::TaskTestMain();
}
-
} // namespace base
diff --git a/base/shared_memory_win.cc b/base/shared_memory_win.cc
index 7d3e4cd..f35ada1 100644
--- a/base/shared_memory_win.cc
+++ b/base/shared_memory_win.cc
@@ -5,7 +5,7 @@
#include "base/shared_memory.h"
#include "base/logging.h"
-#include "base/win_util.h"
+#include "base/utf_string_conversions.h"
namespace base {
@@ -61,7 +61,7 @@ void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
::CloseHandle(handle);
}
-bool SharedMemory::Create(const std::wstring &name, bool read_only,
+bool SharedMemory::Create(const std::string& name, bool read_only,
bool open_existing, uint32 size) {
DCHECK(mapped_file_ == NULL);
@@ -71,12 +71,12 @@ bool SharedMemory::Create(const std::wstring &name, bool read_only,
// To avoid client impact, we continue to retain the size as the
// actual requested size.
uint32 rounded_size = (size + 0xffff) & ~0xffff;
- name_ = name;
+ name_ = ASCIIToWide(name);
read_only_ = read_only;
mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
read_only_ ? PAGE_READONLY : PAGE_READWRITE, 0,
static_cast<DWORD>(rounded_size),
- name.empty() ? NULL : name.c_str());
+ name_.empty() ? NULL : name_.c_str());
if (!mapped_file_)
return false;
@@ -89,19 +89,19 @@ bool SharedMemory::Create(const std::wstring &name, bool read_only,
return true;
}
-bool SharedMemory::Delete(const std::wstring& name) {
+bool SharedMemory::Delete(const std::string& name) {
// intentionally empty -- there is nothing for us to do on Windows.
return true;
}
-bool SharedMemory::Open(const std::wstring &name, bool read_only) {
+bool SharedMemory::Open(const std::string& name, bool read_only) {
DCHECK(mapped_file_ == NULL);
- name_ = name;
+ name_ = ASCIIToWide(name);
read_only_ = read_only;
mapped_file_ = OpenFileMapping(
read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, false,
- name.empty() ? NULL : name.c_str());
+ name_.empty() ? NULL : name_.c_str());
if (mapped_file_ != NULL) {
// Note: size_ is not set in this case.
return true;
diff --git a/base/simple_thread.cc b/base/simple_thread.cc
index 6d531a2..bd97369 100644
--- a/base/simple_thread.cc
+++ b/base/simple_thread.cc
@@ -4,10 +4,9 @@
#include "base/simple_thread.h"
-#include "base/waitable_event.h"
#include "base/logging.h"
#include "base/platform_thread.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
namespace base {
diff --git a/base/simple_thread.h b/base/simple_thread.h
index 737b97d..40e568a 100644
--- a/base/simple_thread.h
+++ b/base/simple_thread.h
@@ -39,6 +39,7 @@
#ifndef BASE_SIMPLE_THREAD_H_
#define BASE_SIMPLE_THREAD_H_
+#pragma once
#include <string>
#include <queue>
diff --git a/base/simple_thread_unittest.cc b/base/simple_thread_unittest.cc
index 8bb267d..85995c2 100644
--- a/base/simple_thread_unittest.cc
+++ b/base/simple_thread_unittest.cc
@@ -1,11 +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 "base/atomic_sequence_num.h"
#include "base/lock.h"
#include "base/simple_thread.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -121,8 +121,8 @@ TEST(SimpleThreadTest, NamedWithOptions) {
thread.Start();
EXPECT_EQ(thread.name_prefix(), "event_waiter");
- EXPECT_EQ(thread.name(), std::string("event_waiter/") +
- IntToString(thread.tid()));
+ EXPECT_EQ(thread.name(),
+ std::string("event_waiter/") + base::IntToString(thread.tid()));
event.Wait();
EXPECT_TRUE(event.IsSignaled());
@@ -130,8 +130,8 @@ TEST(SimpleThreadTest, NamedWithOptions) {
// We keep the name and tid, even after the thread is gone.
EXPECT_EQ(thread.name_prefix(), "event_waiter");
- EXPECT_EQ(thread.name(), std::string("event_waiter/") +
- IntToString(thread.tid()));
+ EXPECT_EQ(thread.name(),
+ std::string("event_waiter/") + base::IntToString(thread.tid()));
}
TEST(SimpleThreadTest, ThreadPool) {
diff --git a/base/singleton.h b/base/singleton.h
index d891c74..ccb2c7d 100644
--- a/base/singleton.h
+++ b/base/singleton.h
@@ -4,6 +4,7 @@
#ifndef BASE_SINGLETON_H_
#define BASE_SINGLETON_H_
+#pragma once
#include "base/at_exit.h"
#include "base/atomicops.h"
diff --git a/base/singleton_objc.h b/base/singleton_objc.h
index 3ba5f1e..e28c8a5 100644
--- a/base/singleton_objc.h
+++ b/base/singleton_objc.h
@@ -29,6 +29,7 @@
#ifndef BASE_SINGLETON_OBJC_H_
#define BASE_SINGLETON_OBJC_H_
+#pragma once
#import <Foundation/Foundation.h>
#include "base/singleton.h"
diff --git a/base/spin_wait.h b/base/spin_wait.h
index b1e2045..34484d2 100644
--- a/base/spin_wait.h
+++ b/base/spin_wait.h
@@ -14,6 +14,7 @@
#ifndef BASE_SPIN_WAIT_H__
#define BASE_SPIN_WAIT_H__
+#pragma once
#include "base/platform_thread.h"
#include "base/time.h"
diff --git a/base/stack_container.h b/base/stack_container.h
index 7a2c23b..dc946db 100644
--- a/base/stack_container.h
+++ b/base/stack_container.h
@@ -4,6 +4,7 @@
#ifndef BASE_STACK_CONTAINER_H_
#define BASE_STACK_CONTAINER_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/base/stats_counters.cc b/base/stats_counters.cc
new file mode 100644
index 0000000..345e1d6
--- /dev/null
+++ b/base/stats_counters.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 "base/stats_counters.h"
+
+StatsCounter::StatsCounter(const std::string& name)
+ : counter_id_(-1) {
+ // We prepend the name with 'c:' to indicate that it is a counter.
+ name_ = "c:";
+ name_.append(name);
+}
+
+StatsCounter::~StatsCounter() {
+}
+
+void StatsCounter::Set(int value) {
+ int* loc = GetPtr();
+ if (loc)
+ *loc = value;
+}
+
+void StatsCounter::Add(int value) {
+ int* loc = GetPtr();
+ if (loc)
+ (*loc) += value;
+}
+
+StatsCounter::StatsCounter()
+ : counter_id_(-1) {
+}
+
+int* StatsCounter::GetPtr() {
+ StatsTable* table = StatsTable::current();
+ if (!table)
+ return NULL;
+
+ // If counter_id_ is -1, then we haven't looked it up yet.
+ if (counter_id_ == -1) {
+ counter_id_ = table->FindCounter(name_);
+ if (table->GetSlot() == 0) {
+ if (!table->RegisterThread("")) {
+ // There is no room for this thread. This thread
+ // cannot use counters.
+ counter_id_ = 0;
+ return NULL;
+ }
+ }
+ }
+
+ // If counter_id_ is > 0, then we have a valid counter.
+ if (counter_id_ > 0)
+ return table->GetLocation(counter_id_, table->GetSlot());
+
+ // counter_id_ was zero, which means the table is full.
+ return NULL;
+}
+
+
+StatsCounterTimer::StatsCounterTimer(const std::string& name) {
+ // we prepend the name with 't:' to indicate that it is a timer.
+ name_ = "t:";
+ name_.append(name);
+}
+
+StatsCounterTimer::~StatsCounterTimer() {
+}
+
+void StatsCounterTimer::Start() {
+ if (!Enabled())
+ return;
+ start_time_ = base::TimeTicks::Now();
+ stop_time_ = base::TimeTicks();
+}
+
+// Stop the timer and record the results.
+void StatsCounterTimer::Stop() {
+ if (!Enabled() || !Running())
+ return;
+ stop_time_ = base::TimeTicks::Now();
+ Record();
+}
+
+// Returns true if the timer is running.
+bool StatsCounterTimer::Running() {
+ return Enabled() && !start_time_.is_null() && stop_time_.is_null();
+}
+
+// Accept a TimeDelta to increment.
+void StatsCounterTimer::AddTime(base::TimeDelta time) {
+ Add(static_cast<int>(time.InMilliseconds()));
+}
+
+void StatsCounterTimer::Record() {
+ AddTime(stop_time_ - start_time_);
+}
+
+
+StatsRate::StatsRate(const char* name)
+ : StatsCounterTimer(name),
+ counter_(name),
+ largest_add_(std::string(" ").append(name).append("MAX").c_str()) {
+}
+
+StatsRate::~StatsRate() {
+}
+
+void StatsRate::Add(int value) {
+ counter_.Increment();
+ StatsCounterTimer::Add(value);
+ if (value > largest_add_.value())
+ largest_add_.Set(value);
+}
diff --git a/base/stats_counters.h b/base/stats_counters.h
index bb87e61..defb9ee 100644
--- a/base/stats_counters.h
+++ b/base/stats_counters.h
@@ -5,6 +5,7 @@
#ifndef BASE_STATS_COUNTERS_H__
#define BASE_STATS_COUNTERS_H__
+#pragma once
#include <string>
#include "base/stats_table.h"
@@ -74,31 +75,18 @@
class StatsCounter {
public:
// Create a StatsCounter object.
- explicit StatsCounter(const std::string& name)
- : counter_id_(-1) {
- // We prepend the name with 'c:' to indicate that it is a counter.
- name_ = "c:";
- name_.append(name);
- };
-
- virtual ~StatsCounter() {}
+ explicit StatsCounter(const std::string& name);
+ virtual ~StatsCounter();
// Sets the counter to a specific value.
- void Set(int value) {
- int* loc = GetPtr();
- if (loc) *loc = value;
- }
+ void Set(int value);
// Increments the counter.
void Increment() {
Add(1);
}
- virtual void Add(int value) {
- int* loc = GetPtr();
- if (loc)
- (*loc) += value;
- }
+ virtual void Add(int value);
// Decrements the counter.
void Decrement() {
@@ -122,36 +110,10 @@ class StatsCounter {
}
protected:
- StatsCounter()
- : counter_id_(-1) {
- }
+ StatsCounter();
// Returns the cached address of this counter location.
- int* GetPtr() {
- StatsTable* table = StatsTable::current();
- if (!table)
- return NULL;
-
- // If counter_id_ is -1, then we haven't looked it up yet.
- if (counter_id_ == -1) {
- counter_id_ = table->FindCounter(name_);
- if (table->GetSlot() == 0) {
- if (!table->RegisterThread("")) {
- // There is no room for this thread. This thread
- // cannot use counters.
- counter_id_ = 0;
- return NULL;
- }
- }
- }
-
- // If counter_id_ is > 0, then we have a valid counter.
- if (counter_id_ > 0)
- return table->GetLocation(counter_id_, table->GetSlot());
-
- // counter_id_ was zero, which means the table is full.
- return NULL;
- }
+ int* GetPtr();
std::string name_;
// The counter id in the table. We initialize to -1 (an invalid value)
@@ -167,43 +129,24 @@ class StatsCounter {
class StatsCounterTimer : protected StatsCounter {
public:
// Constructs and starts the timer.
- explicit StatsCounterTimer(const std::string& name) {
- // we prepend the name with 't:' to indicate that it is a timer.
- name_ = "t:";
- name_.append(name);
- }
+ explicit StatsCounterTimer(const std::string& name);
+ virtual ~StatsCounterTimer();
// Start the timer.
- void Start() {
- if (!Enabled())
- return;
- start_time_ = base::TimeTicks::Now();
- stop_time_ = base::TimeTicks();
- }
+ void Start();
// Stop the timer and record the results.
- void Stop() {
- if (!Enabled() || !Running())
- return;
- stop_time_ = base::TimeTicks::Now();
- Record();
- }
+ void Stop();
// Returns true if the timer is running.
- bool Running() {
- return Enabled() && !start_time_.is_null() && stop_time_.is_null();
- }
+ bool Running();
// Accept a TimeDelta to increment.
- virtual void AddTime(base::TimeDelta time) {
- Add(static_cast<int>(time.InMilliseconds()));
- }
+ virtual void AddTime(base::TimeDelta time);
protected:
// Compute the delta between start and stop, in milliseconds.
- void Record() {
- AddTime(stop_time_ - start_time_);
- }
+ void Record();
base::TimeTicks start_time_;
base::TimeTicks stop_time_;
@@ -215,18 +158,10 @@ class StatsCounterTimer : protected StatsCounter {
class StatsRate : public StatsCounterTimer {
public:
// Constructs and starts the timer.
- explicit StatsRate(const char* name)
- : StatsCounterTimer(name),
- counter_(name),
- largest_add_(std::string(" ").append(name).append("MAX").c_str()) {
- }
+ explicit StatsRate(const char* name);
+ virtual ~StatsRate();
- virtual void Add(int value) {
- counter_.Increment();
- StatsCounterTimer::Add(value);
- if (value > largest_add_.value())
- largest_add_.Set(value);
- }
+ virtual void Add(int value);
private:
StatsCounter counter_;
diff --git a/base/stats_table.cc b/base/stats_table.cc
index 971cc0f..7e96fea 100644
--- a/base/stats_table.cc
+++ b/base/stats_table.cc
@@ -178,7 +178,7 @@ StatsTablePrivate* StatsTablePrivate::New(const std::string& name,
return NULL;
#else
scoped_ptr<StatsTablePrivate> priv(new StatsTablePrivate());
- if (!priv->shared_memory_.Create(UTF8ToWide(name), false, true, size))
+ if (!priv->shared_memory_.Create(name, false, true, size))
return NULL;
if (!priv->shared_memory_.Map(size))
return NULL;
diff --git a/base/stats_table.h b/base/stats_table.h
index fd112fa..3522876 100644
--- a/base/stats_table.h
+++ b/base/stats_table.h
@@ -19,6 +19,7 @@
#ifndef BASE_STATS_TABLE_H__
#define BASE_STATS_TABLE_H__
+#pragma once
#include <string>
#include "base/basictypes.h"
diff --git a/base/stats_table_unittest.cc b/base/stats_table_unittest.cc
index 5c8e499..f926f29 100644
--- a/base/stats_table_unittest.cc
+++ b/base/stats_table_unittest.cc
@@ -7,12 +7,14 @@
#include <windows.h>
#endif
-#include "base/multiprocess_test.h"
#include "base/platform_thread.h"
#include "base/simple_thread.h"
#include "base/shared_memory.h"
#include "base/stats_table.h"
#include "base/stats_counters.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/test/multiprocess_test.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -21,9 +23,9 @@ namespace base {
class StatsTableTest : public MultiProcessTest {
public:
- void DeleteShmem(std::string name) {
+ void DeleteShmem(const std::string& name) {
base::SharedMemory mem;
- mem.Delete(UTF8ToWide(name));
+ mem.Delete(name);
}
};
@@ -73,7 +75,7 @@ const std::string kCounterDecrement = "CounterDecrement";
// decremented by even threads.
const std::string kCounterMixed = "CounterMixed";
// The number of thread loops that we will do.
-const int kThreadLoops = 1000;
+const int kThreadLoops = 100;
class StatsTableThread : public base::SimpleThread {
public:
@@ -188,7 +190,8 @@ MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
}
// Create a few processes and have them poke on their counters.
-TEST_F(StatsTableTest, MultipleProcesses) {
+// This test is slow and flaky http://crbug.com/10611
+TEST_F(StatsTableTest, FLAKY_MultipleProcesses) {
// Create a stats table.
const int kMaxProcs = 20;
const int kMaxCounter = 5;
@@ -204,7 +207,7 @@ TEST_F(StatsTableTest, MultipleProcesses) {
// Spawn the processes.
for (int16 index = 0; index < kMaxProcs; index++) {
- procs[index] = this->SpawnChild(L"StatsTableMultipleProcessMain");
+ procs[index] = this->SpawnChild("StatsTableMultipleProcessMain", false);
EXPECT_NE(base::kNullProcessHandle, procs[index]);
}
@@ -316,17 +319,21 @@ TEST_F(StatsTableTest, StatsCounterTimer) {
EXPECT_TRUE(bar.start_time().is_null());
EXPECT_TRUE(bar.stop_time().is_null());
+ const int kRunMs = 100;
+
// Do some timing.
bar.Start();
- PlatformThread::Sleep(500);
+ PlatformThread::Sleep(kRunMs);
bar.Stop();
- EXPECT_LE(500, table.GetCounterValue("t:bar"));
+ EXPECT_GT(table.GetCounterValue("t:bar"), 0);
+ EXPECT_LE(kRunMs, table.GetCounterValue("t:bar"));
// Verify that timing again is additive.
bar.Start();
- PlatformThread::Sleep(500);
+ PlatformThread::Sleep(kRunMs);
bar.Stop();
- EXPECT_LE(1000, table.GetCounterValue("t:bar"));
+ EXPECT_GT(table.GetCounterValue("t:bar"), 0);
+ EXPECT_LE(kRunMs * 2, table.GetCounterValue("t:bar"));
}
// Test some basic StatsRate operations
@@ -345,19 +352,21 @@ TEST_F(StatsTableTest, StatsRate) {
EXPECT_EQ(0, table.GetCounterValue("c:baz"));
EXPECT_EQ(0, table.GetCounterValue("t:baz"));
+ const int kRunMs = 100;
+
// Do some timing.
baz.Start();
- PlatformThread::Sleep(500);
+ PlatformThread::Sleep(kRunMs);
baz.Stop();
EXPECT_EQ(1, table.GetCounterValue("c:baz"));
- EXPECT_LE(500, table.GetCounterValue("t:baz"));
+ EXPECT_LE(kRunMs, table.GetCounterValue("t:baz"));
// Verify that timing again is additive.
baz.Start();
- PlatformThread::Sleep(500);
+ PlatformThread::Sleep(kRunMs);
baz.Stop();
EXPECT_EQ(2, table.GetCounterValue("c:baz"));
- EXPECT_LE(1000, table.GetCounterValue("t:baz"));
+ EXPECT_LE(kRunMs * 2, table.GetCounterValue("t:baz"));
}
// Test some basic StatsScope operations
@@ -378,24 +387,26 @@ TEST_F(StatsTableTest, StatsScope) {
EXPECT_EQ(0, table.GetCounterValue("t:bar"));
EXPECT_EQ(0, table.GetCounterValue("c:bar"));
+ const int kRunMs = 100;
+
// Try a scope.
{
StatsScope<StatsCounterTimer> timer(foo);
StatsScope<StatsRate> timer2(bar);
- PlatformThread::Sleep(500);
+ PlatformThread::Sleep(kRunMs);
}
- EXPECT_LE(500, table.GetCounterValue("t:foo"));
- EXPECT_LE(500, table.GetCounterValue("t:bar"));
+ EXPECT_LE(kRunMs, table.GetCounterValue("t:foo"));
+ EXPECT_LE(kRunMs, table.GetCounterValue("t:bar"));
EXPECT_EQ(1, table.GetCounterValue("c:bar"));
// Try a second scope.
{
StatsScope<StatsCounterTimer> timer(foo);
StatsScope<StatsRate> timer2(bar);
- PlatformThread::Sleep(500);
+ PlatformThread::Sleep(kRunMs);
}
- EXPECT_LE(1000, table.GetCounterValue("t:foo"));
- EXPECT_LE(1000, table.GetCounterValue("t:bar"));
+ EXPECT_LE(kRunMs * 2, table.GetCounterValue("t:foo"));
+ EXPECT_LE(kRunMs * 2, table.GetCounterValue("t:bar"));
EXPECT_EQ(2, table.GetCounterValue("c:bar"));
DeleteShmem(kTableName);
diff --git a/base/stl_util-inl.h b/base/stl_util-inl.h
index 4abc0d2..2161c59 100644
--- a/base/stl_util-inl.h
+++ b/base/stl_util-inl.h
@@ -7,6 +7,7 @@
#ifndef BASE_STL_UTIL_INL_H_
#define BASE_STL_UTIL_INL_H_
+#pragma once
#include <string.h> // for memcpy
#include <functional>
diff --git a/base/string16.cc b/base/string16.cc
index d1d0908..f7eaf7e 100644
--- a/base/string16.cc
+++ b/base/string16.cc
@@ -13,7 +13,6 @@
#elif defined(WCHAR_T_IS_UTF32)
-#include "base/string_util.h"
#include "base/utf_string_conversions.h"
namespace base {
diff --git a/base/string16.h b/base/string16.h
index 28cf3d8..78734fd 100644
--- a/base/string16.h
+++ b/base/string16.h
@@ -4,6 +4,7 @@
#ifndef BASE_STRING16_H_
#define BASE_STRING16_H_
+#pragma once
// WHAT:
// A version of std::basic_string that provides 2-byte characters even when
diff --git a/base/string16_unittest.cc b/base/string16_unittest.cc
index 69eed4b..06b3dca 100644
--- a/base/string16_unittest.cc
+++ b/base/string16_unittest.cc
@@ -5,6 +5,7 @@
#include <sstream>
#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(WCHAR_T_IS_UTF32)
diff --git a/base/string_number_conversions.cc b/base/string_number_conversions.cc
new file mode 100644
index 0000000..62599dd
--- /dev/null
+++ b/base/string_number_conversions.cc
@@ -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.
+
+#include "base/string_number_conversions.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "base/third_party/dmg_fp/dmg_fp.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT, typename UINT, bool NEG>
+struct IntToStringT {
+ // This is to avoid a compiler warning about unary minus on unsigned type.
+ // For example, say you had the following code:
+ // template <typename INT>
+ // INT abs(INT value) { return value < 0 ? -value : value; }
+ // Even though if INT is unsigned, it's impossible for value < 0, so the
+ // unary minus will never be taken, the compiler will still generate a
+ // warning. We do a little specialization dance...
+ template <typename INT2, typename UINT2, bool NEG2>
+ struct ToUnsignedT {};
+
+ template <typename INT2, typename UINT2>
+ struct ToUnsignedT<INT2, UINT2, false> {
+ static UINT2 ToUnsigned(INT2 value) {
+ return static_cast<UINT2>(value);
+ }
+ };
+
+ template <typename INT2, typename UINT2>
+ struct ToUnsignedT<INT2, UINT2, true> {
+ static UINT2 ToUnsigned(INT2 value) {
+ return static_cast<UINT2>(value < 0 ? -value : value);
+ }
+ };
+
+ // This set of templates is very similar to the above templates, but
+ // for testing whether an integer is negative.
+ template <typename INT2, bool NEG2>
+ struct TestNegT {};
+ template <typename INT2>
+ struct TestNegT<INT2, false> {
+ static bool TestNeg(INT2 value) {
+ // value is unsigned, and can never be negative.
+ return false;
+ }
+ };
+ template <typename INT2>
+ struct TestNegT<INT2, true> {
+ static bool TestNeg(INT2 value) {
+ return value < 0;
+ }
+ };
+
+ static STR IntToString(INT value) {
+ // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
+ // So round up to allocate 3 output characters per byte, plus 1 for '-'.
+ const int kOutputBufSize = 3 * sizeof(INT) + 1;
+
+ // Allocate the whole string right away, we will right back to front, and
+ // then return the substr of what we ended up using.
+ STR outbuf(kOutputBufSize, 0);
+
+ bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
+ // Even though is_neg will never be true when INT is parameterized as
+ // unsigned, even the presence of the unary operation causes a warning.
+ UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
+
+ for (typename STR::iterator it = outbuf.end();;) {
+ --it;
+ DCHECK(it != outbuf.begin());
+ *it = static_cast<typename STR::value_type>((res % 10) + '0');
+ res /= 10;
+
+ // We're done..
+ if (res == 0) {
+ if (is_neg) {
+ --it;
+ DCHECK(it != outbuf.begin());
+ *it = static_cast<typename STR::value_type>('-');
+ }
+ return STR(it, outbuf.end());
+ }
+ }
+ NOTREACHED();
+ return STR();
+ }
+};
+
+// Generalized string-to-number conversion.
+//
+// StringToNumberTraits should provide:
+// - a typedef for string_type, the STL string type used as input.
+// - a typedef for value_type, the target numeric type.
+// - a static function, convert_func, which dispatches to an appropriate
+// strtol-like function and returns type value_type.
+// - a static function, valid_func, which validates |input| and returns a bool
+// indicating whether it is in proper form. This is used to check for
+// conditions that convert_func tolerates but should result in
+// StringToNumber returning false. For strtol-like funtions, valid_func
+// should check for leading whitespace.
+template<typename StringToNumberTraits>
+bool StringToNumber(const typename StringToNumberTraits::string_type& input,
+ typename StringToNumberTraits::value_type* output) {
+ typedef StringToNumberTraits traits;
+
+ errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows.
+ typename traits::string_type::value_type* endptr = NULL;
+ typename traits::value_type value = traits::convert_func(input.c_str(),
+ &endptr);
+ *output = value;
+
+ // Cases to return false:
+ // - If errno is ERANGE, there was an overflow or underflow.
+ // - If the input string is empty, there was nothing to parse.
+ // - If endptr does not point to the end of the string, there are either
+ // characters remaining in the string after a parsed number, or the string
+ // does not begin with a parseable number. endptr is compared to the
+ // expected end given the string's stated length to correctly catch cases
+ // where the string contains embedded NUL characters.
+ // - valid_func determines that the input is not in preferred form.
+ return errno == 0 &&
+ !input.empty() &&
+ input.c_str() + input.length() == endptr &&
+ traits::valid_func(input);
+}
+
+static int strtoi(const char *nptr, char **endptr, int base) {
+ long res = strtol(nptr, endptr, base);
+#if __LP64__
+ // Long is 64-bits, we have to handle under/overflow ourselves.
+ if (res > kint32max) {
+ res = kint32max;
+ errno = ERANGE;
+ } else if (res < kint32min) {
+ res = kint32min;
+ errno = ERANGE;
+ }
+#endif
+ return static_cast<int>(res);
+}
+
+static unsigned int strtoui(const char *nptr, char **endptr, int base) {
+ unsigned long res = strtoul(nptr, endptr, base);
+#if __LP64__
+ // Long is 64-bits, we have to handle under/overflow ourselves. Test to see
+ // if the result can fit into 32-bits (as signed or unsigned).
+ if (static_cast<int>(static_cast<long>(res)) != static_cast<long>(res) &&
+ static_cast<unsigned int>(res) != res) {
+ res = kuint32max;
+ errno = ERANGE;
+ }
+#endif
+ return static_cast<unsigned int>(res);
+}
+
+class StringToIntTraits {
+ public:
+ typedef std::string string_type;
+ typedef int value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return strtoi(str, endptr, kBase);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class String16ToIntTraits {
+ public:
+ typedef string16 string_type;
+ typedef int value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#if defined(WCHAR_T_IS_UTF16)
+ return wcstol(str, endptr, kBase);
+#elif defined(WCHAR_T_IS_UTF32)
+ std::string ascii_string = UTF16ToUTF8(string16(str));
+ char* ascii_end = NULL;
+ value_type ret = strtoi(ascii_string.c_str(), &ascii_end, kBase);
+ if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
+ *endptr =
+ const_cast<string_type::value_type*>(str) + ascii_string.length();
+ }
+ return ret;
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !iswspace(str[0]);
+ }
+};
+
+class StringToInt64Traits {
+ public:
+ typedef std::string string_type;
+ typedef int64 value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#ifdef OS_WIN
+ return _strtoi64(str, endptr, kBase);
+#else // assume OS_POSIX
+ return strtoll(str, endptr, kBase);
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class String16ToInt64Traits {
+ public:
+ typedef string16 string_type;
+ typedef int64 value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#ifdef OS_WIN
+ return _wcstoi64(str, endptr, kBase);
+#else // assume OS_POSIX
+ std::string ascii_string = UTF16ToUTF8(string16(str));
+ char* ascii_end = NULL;
+ value_type ret = strtoll(ascii_string.c_str(), &ascii_end, kBase);
+ if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
+ *endptr =
+ const_cast<string_type::value_type*>(str) + ascii_string.length();
+ }
+ return ret;
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !iswspace(str[0]);
+ }
+};
+
+// For the HexString variants, use the unsigned variants like strtoul for
+// convert_func so that input like "0x80000000" doesn't result in an overflow.
+
+class HexStringToIntTraits {
+ public:
+ typedef std::string string_type;
+ typedef int value_type;
+ static const int kBase = 16;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return strtoui(str, endptr, kBase);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class StringToDoubleTraits {
+ public:
+ typedef std::string string_type;
+ typedef double value_type;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return dmg_fp::strtod(str, endptr);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+template<class CHAR>
+bool HexDigitToIntT(const CHAR digit, uint8* val) {
+ if (digit >= '0' && digit <= '9')
+ *val = digit - '0';
+ else if (digit >= 'a' && digit <= 'f')
+ *val = 10 + digit - 'a';
+ else if (digit >= 'A' && digit <= 'F')
+ *val = 10 + digit - 'A';
+ else
+ return false;
+ return true;
+}
+
+template<typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
+ DCHECK(output->size() == 0);
+ size_t count = input.size();
+ if (count == 0 || (count % 2) != 0)
+ return false;
+ for (uintptr_t i = 0; i < count / 2; ++i) {
+ uint8 msb = 0; // most significant 4 bits
+ uint8 lsb = 0; // least significant 4 bits
+ if (!HexDigitToIntT(input[i * 2], &msb) ||
+ !HexDigitToIntT(input[i * 2 + 1], &lsb))
+ return false;
+ output->push_back((msb << 4) | lsb);
+ }
+ return true;
+}
+
+} // namespace
+
+std::string IntToString(int value) {
+ return IntToStringT<std::string, int, unsigned int, true>::
+ IntToString(value);
+}
+
+string16 IntToString16(int value) {
+ return IntToStringT<string16, int, unsigned int, true>::
+ IntToString(value);
+}
+
+std::string UintToString(unsigned int value) {
+ return IntToStringT<std::string, unsigned int, unsigned int, false>::
+ IntToString(value);
+}
+
+string16 UintToString16(unsigned int value) {
+ return IntToStringT<string16, unsigned int, unsigned int, false>::
+ IntToString(value);
+}
+
+std::string Int64ToString(int64 value) {
+ return IntToStringT<std::string, int64, uint64, true>::
+ IntToString(value);
+}
+
+string16 Int64ToString16(int64 value) {
+ return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+}
+
+std::string Uint64ToString(uint64 value) {
+ return IntToStringT<std::string, uint64, uint64, false>::
+ IntToString(value);
+}
+
+string16 Uint64ToString16(uint64 value) {
+ return IntToStringT<string16, uint64, uint64, false>::
+ IntToString(value);
+}
+
+std::string DoubleToString(double value) {
+ // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+ char buffer[32];
+ dmg_fp::g_fmt(buffer, value);
+ return std::string(buffer);
+}
+
+bool StringToInt(const std::string& input, int* output) {
+ return StringToNumber<StringToIntTraits>(input, output);
+}
+
+bool StringToInt(const string16& input, int* output) {
+ return StringToNumber<String16ToIntTraits>(input, output);
+}
+
+bool StringToInt64(const std::string& input, int64* output) {
+ return StringToNumber<StringToInt64Traits>(input, output);
+}
+
+bool StringToInt64(const string16& input, int64* output) {
+ return StringToNumber<String16ToInt64Traits>(input, output);
+}
+
+bool StringToDouble(const std::string& input, double* output) {
+ return StringToNumber<StringToDoubleTraits>(input, output);
+}
+
+// Note: if you need to add String16ToDouble, first ask yourself if it's
+// really necessary. If it is, probably the best implementation here is to
+// convert to 8-bit and then use the 8-bit version.
+
+std::string HexEncode(const void* bytes, size_t size) {
+ static const char kHexChars[] = "0123456789ABCDEF";
+
+ // Each input byte creates two output hex characters.
+ std::string ret(size * 2, '\0');
+
+ for (size_t i = 0; i < size; ++i) {
+ char b = reinterpret_cast<const char*>(bytes)[i];
+ ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+ ret[(i * 2) + 1] = kHexChars[b & 0xf];
+ }
+ return ret;
+}
+
+bool HexStringToInt(const std::string& input, int* output) {
+ return StringToNumber<HexStringToIntTraits>(input, output);
+}
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+ return HexStringToBytesT(input, output);
+}
+
+} // namespace base
+
diff --git a/base/string_number_conversions.h b/base/string_number_conversions.h
new file mode 100644
index 0000000..4d89e86
--- /dev/null
+++ b/base/string_number_conversions.h
@@ -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.
+
+#ifndef BASE_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRING_NUMBER_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+// ----------------------------------------------------------------------------
+// IMPORTANT MESSAGE FROM YOUR SPONSOR
+//
+// This file contains no "wstring" variants. New code should use string16. If
+// you need to make old code work, use the UTF8 version and convert. Please do
+// not add wstring variants.
+//
+// Please do not add "convenience" functions for converting strings to integers
+// that return the value and ignore success/failure. That encourages people to
+// write code that doesn't properly handle the error conditions.
+// ----------------------------------------------------------------------------
+
+namespace base {
+
+// Number -> string conversions ------------------------------------------------
+
+std::string IntToString(int value);
+string16 IntToString16(int value);
+
+std::string UintToString(unsigned value);
+string16 UintToString16(unsigned value);
+
+std::string Int64ToString(int64 value);
+string16 Int64ToString16(int64 value);
+
+std::string Uint64ToString(uint64 value);
+string16 Uint64ToString16(uint64 value);
+
+// DoubleToString converts the double to a string format that ignores the
+// locale. If you want to use locale specific formatting, use ICU.
+std::string DoubleToString(double value);
+
+// String -> number conversions ------------------------------------------------
+
+// Perform a best-effort conversion of the input string to a numeric type,
+// setting |*output| to the result of the conversion. Returns true for
+// "perfect" conversions; returns false in the following cases:
+// - Overflow/underflow. |*output| will be set to the maximum value supported
+// by the data type.
+// - Trailing characters in the string after parsing the number. |*output|
+// will be set to the value of the number that was parsed.
+// - No characters parseable as a number at the beginning of the string.
+// |*output| will be set to 0.
+// - Empty string. |*output| will be set to 0.
+bool StringToInt(const std::string& input, int* output);
+bool StringToInt(const string16& input, int* output);
+bool StringToInt64(const std::string& input, int64* output);
+bool StringToInt64(const string16& input, int64* output);
+
+// For floating-point conversions, only conversions of input strings in decimal
+// form are defined to work. Behavior with strings representing floating-point
+// numbers in hexadecimal, and strings representing non-fininte values (such as
+// NaN and inf) is undefined. Otherwise, these behave the same as the integral
+// variants. This expects the input string to NOT be specific to the locale.
+// If your input is locale specific, use ICU to read the number.
+bool StringToDouble(const std::string& input, double* output);
+
+// Hex encoding ----------------------------------------------------------------
+
+// Returns a hex string representation of a binary buffer. The returned hex
+// string will be in upper case. This function does not check if |size| is
+// within reasonable limits since it's written with trusted data in mind. If
+// you suspect that the data you want to format might be large, the absolute
+// max size for |size| should be is
+// std::numeric_limits<size_t>::max() / 2
+std::string HexEncode(const void* bytes, size_t size);
+
+// Best effort conversion, see StringToInt above for restrictions.
+bool HexStringToInt(const std::string& input, int* output);
+
+// Similar to the previous functions, except that output is a vector of bytes.
+// |*output| will contain as many bytes as were successfully parsed prior to the
+// error. There is no overflow, but input.size() must be evenly divisible by 2.
+// Leading 0x or +/- are not allowed.
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output);
+
+} // namespace base
+
+#endif // BASE_STRING_NUMBER_CONVERSIONS_H_
+
diff --git a/base/string_number_conversions_unittest.cc b/base/string_number_conversions_unittest.cc
new file mode 100644
index 0000000..9ae7bdb
--- /dev/null
+++ b/base/string_number_conversions_unittest.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 <limits>
+#include <math.h> // For HUGE_VAL.
+
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+template <typename INT>
+struct IntToStringTest {
+ INT num;
+ const char* sexpected;
+ const char* uexpected;
+};
+
+} // namespace
+
+TEST(StringNumberConversionsTest, IntToString) {
+ static const IntToStringTest<int> int_tests[] = {
+ { 0, "0", "0" },
+ { -1, "-1", "4294967295" },
+ { std::numeric_limits<int>::max(), "2147483647", "2147483647" },
+ { std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
+ };
+ static const IntToStringTest<int64> int64_tests[] = {
+ { 0, "0", "0" },
+ { -1, "-1", "18446744073709551615" },
+ { std::numeric_limits<int64>::max(),
+ "9223372036854775807",
+ "9223372036854775807", },
+ { std::numeric_limits<int64>::min(),
+ "-9223372036854775808",
+ "9223372036854775808" },
+ };
+
+ for (size_t i = 0; i < arraysize(int_tests); ++i) {
+ const IntToStringTest<int>* test = &int_tests[i];
+ EXPECT_EQ(IntToString(test->num), test->sexpected);
+ EXPECT_EQ(IntToString16(test->num), UTF8ToUTF16(test->sexpected));
+ EXPECT_EQ(UintToString(test->num), test->uexpected);
+ EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected));
+ }
+ for (size_t i = 0; i < arraysize(int64_tests); ++i) {
+ const IntToStringTest<int64>* test = &int64_tests[i];
+ EXPECT_EQ(Int64ToString(test->num), test->sexpected);
+ EXPECT_EQ(Int64ToString16(test->num), UTF8ToUTF16(test->sexpected));
+ EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
+ EXPECT_EQ(Uint64ToString16(test->num), UTF8ToUTF16(test->uexpected));
+ }
+}
+
+TEST(StringNumberConversionsTest, Uint64ToString) {
+ static const struct {
+ uint64 input;
+ std::string output;
+ } cases[] = {
+ {0, "0"},
+ {42, "42"},
+ {INT_MAX, "2147483647"},
+ {kuint64max, "18446744073709551615"},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)
+ EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
+}
+
+TEST(StringNumberConversionsTest, StringToInt) {
+ static const struct {
+ std::string input;
+ int output;
+ bool success;
+ } cases[] = {
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", INT_MIN, true},
+ {"2147483647", INT_MAX, true},
+ {"", 0, false},
+ {" 42", 42, false},
+ {"42 ", 42, false},
+ {"\t\n\v\f\r 42", 42, false},
+ {"blah42", 0, false},
+ {"42blah", 42, false},
+ {"blah42blah", 0, false},
+ {"-273.15", -273, false},
+ {"+98.6", 98, false},
+ {"--123", 0, false},
+ {"++123", 0, false},
+ {"-+123", 0, false},
+ {"+-123", 0, false},
+ {"-", 0, false},
+ {"-2147483649", INT_MIN, false},
+ {"-99999999999", INT_MIN, false},
+ {"2147483648", INT_MAX, false},
+ {"99999999999", INT_MAX, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ int output;
+ EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
+ EXPECT_EQ(cases[i].output, output);
+
+ string16 utf16_input = UTF8ToUTF16(cases[i].input);
+ EXPECT_EQ(cases[i].success, StringToInt(utf16_input, &output));
+ EXPECT_EQ(cases[i].output, output);
+ }
+
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "6\06";
+ std::string input_string(input, arraysize(input) - 1);
+ int output;
+ EXPECT_FALSE(StringToInt(input_string, &output));
+ EXPECT_EQ(6, output);
+
+ string16 utf16_input = UTF8ToUTF16(input_string);
+ EXPECT_FALSE(StringToInt(utf16_input, &output));
+ EXPECT_EQ(6, output);
+}
+
+TEST(StringNumberConversionsTest, StringToInt64) {
+ static const struct {
+ std::string input;
+ int64 output;
+ bool success;
+ } cases[] = {
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", INT_MIN, true},
+ {"2147483647", INT_MAX, true},
+ {"-2147483649", GG_INT64_C(-2147483649), true},
+ {"-99999999999", GG_INT64_C(-99999999999), true},
+ {"2147483648", GG_INT64_C(2147483648), true},
+ {"99999999999", GG_INT64_C(99999999999), true},
+ {"9223372036854775807", kint64max, true},
+ {"-9223372036854775808", kint64min, true},
+ {"09", 9, true},
+ {"-09", -9, true},
+ {"", 0, false},
+ {" 42", 42, false},
+ {"42 ", 42, false},
+ {"\t\n\v\f\r 42", 42, false},
+ {"blah42", 0, false},
+ {"42blah", 42, false},
+ {"blah42blah", 0, false},
+ {"-273.15", -273, false},
+ {"+98.6", 98, false},
+ {"--123", 0, false},
+ {"++123", 0, false},
+ {"-+123", 0, false},
+ {"+-123", 0, false},
+ {"-", 0, false},
+ {"-9223372036854775809", kint64min, false},
+ {"-99999999999999999999", kint64min, false},
+ {"9223372036854775808", kint64max, false},
+ {"99999999999999999999", kint64max, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ int64 output;
+ EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
+ EXPECT_EQ(cases[i].output, output);
+
+ string16 utf16_input = UTF8ToUTF16(cases[i].input);
+ EXPECT_EQ(cases[i].success, StringToInt64(utf16_input, &output));
+ EXPECT_EQ(cases[i].output, output);
+ }
+
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "6\06";
+ std::string input_string(input, arraysize(input) - 1);
+ int64 output;
+ EXPECT_FALSE(StringToInt64(input_string, &output));
+ EXPECT_EQ(6, output);
+
+ string16 utf16_input = UTF8ToUTF16(input_string);
+ EXPECT_FALSE(StringToInt64(utf16_input, &output));
+ EXPECT_EQ(6, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt) {
+ static const struct {
+ std::string input;
+ int output;
+ bool success;
+ } cases[] = {
+ {"0", 0, true},
+ {"42", 66, true},
+ {"-42", -66, true},
+ {"+42", 66, true},
+ {"7fffffff", INT_MAX, true},
+ {"80000000", INT_MIN, true},
+ {"ffffffff", -1, true},
+ {"DeadBeef", 0xdeadbeef, true},
+ {"0x42", 66, true},
+ {"-0x42", -66, true},
+ {"+0x42", 66, true},
+ {"0x7fffffff", INT_MAX, true},
+ {"0x80000000", INT_MIN, true},
+ {"0xffffffff", -1, true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x0f", 15, true},
+ {"0f", 15, true},
+ {" 45", 0x45, false},
+ {"\t\n\v\f\r 0x45", 0x45, false},
+ {" 45", 0x45, false},
+ {"45 ", 0x45, false},
+ {"efgh", 0xef, false},
+ {"0xefgh", 0xef, false},
+ {"hgfe", 0, false},
+ {"100000000", -1, false}, // don't care about |output|, just |success|
+ {"-", 0, false},
+ {"", 0, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ int output;
+ EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output));
+ EXPECT_EQ(cases[i].output, output);
+ }
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "0xc0ffee\09";
+ std::string input_string(input, arraysize(input) - 1);
+ int output;
+ EXPECT_FALSE(HexStringToInt(input_string, &output));
+ EXPECT_EQ(0xc0ffee, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToBytes) {
+ static const struct {
+ const std::string input;
+ const char* output;
+ size_t output_len;
+ bool success;
+ } cases[] = {
+ {"0", "", 0, false}, // odd number of characters fails
+ {"00", "\0", 1, true},
+ {"42", "\x42", 1, true},
+ {"-42", "", 0, false}, // any non-hex value fails
+ {"+42", "", 0, false},
+ {"7fffffff", "\x7f\xff\xff\xff", 4, true},
+ {"80000000", "\x80\0\0\0", 4, true},
+ {"deadbeef", "\xde\xad\xbe\xef", 4, true},
+ {"DeadBeef", "\xde\xad\xbe\xef", 4, true},
+ {"0x42", "", 0, false}, // leading 0x fails (x is not hex)
+ {"0f", "\xf", 1, true},
+ {"45 ", "\x45", 1, false},
+ {"efgh", "\xef", 1, false},
+ {"", "", 0, false},
+ {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true},
+ {"0123456789ABCDEF012345",
+ "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true},
+ };
+
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ std::vector<uint8> output;
+ std::vector<uint8> compare;
+ EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
+ i << ": " << cases[i].input;
+ for (size_t j = 0; j < cases[i].output_len; ++j)
+ compare.push_back(static_cast<uint8>(cases[i].output[j]));
+ ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
+ EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
+ i << ": " << cases[i].input;
+ }
+}
+
+TEST(StringNumberConversionsTest, StringToDouble) {
+ static const struct {
+ std::string input;
+ double output;
+ bool success;
+ } cases[] = {
+ {"0", 0.0, true},
+ {"42", 42.0, true},
+ {"-42", -42.0, true},
+ {"123.45", 123.45, true},
+ {"-123.45", -123.45, true},
+ {"+123.45", 123.45, true},
+ {"2.99792458e8", 299792458.0, true},
+ {"149597870.691E+3", 149597870691.0, true},
+ {"6.", 6.0, true},
+ {"9e99999999999999999999", HUGE_VAL, false},
+ {"-9e99999999999999999999", -HUGE_VAL, false},
+ {"1e-2", 0.01, true},
+ {" 1e-2", 0.01, false},
+ {"1e-2 ", 0.01, false},
+ {"-1E-7", -0.0000001, true},
+ {"01e02", 100, true},
+ {"2.3e15", 2.3e15, true},
+ {"\t\n\v\f\r -123.45e2", -12345.0, false},
+ {"+123 e4", 123.0, false},
+ {"123e ", 123.0, false},
+ {"123e", 123.0, false},
+ {" 2.99", 2.99, false},
+ {"1e3.4", 1000.0, false},
+ {"nothing", 0.0, false},
+ {"-", 0.0, false},
+ {"+", 0.0, false},
+ {"", 0.0, false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ double output;
+ EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
+ EXPECT_DOUBLE_EQ(cases[i].output, output);
+ }
+
+ // One additional test to verify that conversion of numbers in strings with
+ // embedded NUL characters. The NUL and extra data after it should be
+ // interpreted as junk after the number.
+ const char input[] = "3.14\0159";
+ std::string input_string(input, arraysize(input) - 1);
+ double output;
+ EXPECT_FALSE(StringToDouble(input_string, &output));
+ EXPECT_DOUBLE_EQ(3.14, output);
+}
+
+TEST(StringNumberConversionsTest, HexEncode) {
+ std::string hex(HexEncode(NULL, 0));
+ EXPECT_EQ(hex.length(), 0U);
+ unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
+ hex = HexEncode(bytes, sizeof(bytes));
+ EXPECT_EQ(hex.compare("01FF02FE038081"), 0);
+}
+
+} // namespace base
diff --git a/base/string_piece.cc b/base/string_piece.cc
index 082e3c2..3ccb4f0 100644
--- a/base/string_piece.cc
+++ b/base/string_piece.cc
@@ -54,7 +54,7 @@ size_type StringPiece::find(char c, size_type pos) const {
return npos;
const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
- return result != ptr_ + length_ ? result - ptr_ : npos;
+ return result != ptr_ + length_ ? static_cast<size_t>(result - ptr_) : npos;
}
size_type StringPiece::rfind(const StringPiece& s, size_type pos) const {
@@ -66,7 +66,7 @@ size_type StringPiece::rfind(const StringPiece& s, size_type pos) const {
const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
- return result != last ? result - ptr_ : npos;
+ return result != last ? static_cast<size_t>(result - ptr_) : npos;
}
size_type StringPiece::rfind(char c, size_type pos) const {
diff --git a/base/string_piece.h b/base/string_piece.h
index 5b4bf40..70c0480 100644
--- a/base/string_piece.h
+++ b/base/string_piece.h
@@ -17,6 +17,7 @@
#ifndef BASE_STRING_PIECE_H_
#define BASE_STRING_PIECE_H_
+#pragma once
#include <algorithm>
#include <iosfwd>
diff --git a/base/string_split.cc b/base/string_split.cc
index 2b4deb5..ca97954 100644
--- a/base/string_split.cc
+++ b/base/string_split.cc
@@ -4,7 +4,56 @@
#include "base/string_split.h"
+#include "base/logging.h"
#include "base/string_util.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "base/utf_string_conversions.h"
+
+template<typename STR>
+static void SplitStringT(const STR& str,
+ const typename STR::value_type s,
+ bool trim_whitespace,
+ std::vector<STR>* r) {
+ size_t last = 0;
+ size_t i;
+ size_t c = str.size();
+ for (i = 0; i <= c; ++i) {
+ if (i == c || str[i] == s) {
+ size_t len = i - last;
+ STR tmp = str.substr(last, len);
+ if (trim_whitespace) {
+ STR t_tmp;
+ TrimWhitespace(tmp, TRIM_ALL, &t_tmp);
+ r->push_back(t_tmp);
+ } else {
+ r->push_back(tmp);
+ }
+ last = i + 1;
+ }
+ }
+}
+
+void SplitString(const std::wstring& str,
+ wchar_t c,
+ std::vector<std::wstring>* r) {
+ SplitStringT(str, c, true, r);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+void SplitString(const string16& str,
+ char16 c,
+ std::vector<string16>* r) {
+ DCHECK(CBU16_IS_SINGLE(c));
+ SplitStringT(str, c, true, r);
+}
+#endif
+
+void SplitString(const std::string& str,
+ char c,
+ std::vector<std::string>* r) {
+ DCHECK(c >= 0 && c < 0x7F);
+ SplitStringT(str, c, true, r);
+}
namespace base {
@@ -70,4 +119,61 @@ bool SplitStringIntoKeyValuePairs(
return success;
}
+template <typename STR>
+static void SplitStringUsingSubstrT(const STR& str,
+ const STR& s,
+ std::vector<STR>* r) {
+ typename STR::size_type begin_index = 0;
+ while (true) {
+ const typename STR::size_type end_index = str.find(s, begin_index);
+ if (end_index == STR::npos) {
+ const STR term = str.substr(begin_index);
+ STR tmp;
+ TrimWhitespace(term, TRIM_ALL, &tmp);
+ r->push_back(tmp);
+ return;
+ }
+ const STR term = str.substr(begin_index, end_index - begin_index);
+ STR tmp;
+ TrimWhitespace(term, TRIM_ALL, &tmp);
+ r->push_back(tmp);
+ begin_index = end_index + s.size();
+ }
+}
+
+void SplitStringUsingSubstr(const string16& str,
+ const string16& s,
+ std::vector<string16>* r) {
+ SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringUsingSubstr(const std::string& str,
+ const std::string& s,
+ std::vector<std::string>* r) {
+ SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringDontTrim(const std::wstring& str,
+ wchar_t c,
+ std::vector<std::wstring>* r) {
+ SplitStringT(str, c, false, r);
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+void SplitStringDontTrim(const string16& str,
+ char16 c,
+ std::vector<string16>* r) {
+ DCHECK(CBU16_IS_SINGLE(c));
+ SplitStringT(str, c, false, r);
+}
+#endif
+
+void SplitStringDontTrim(const std::string& str,
+ char c,
+ std::vector<std::string>* r) {
+ DCHECK(IsStringUTF8(str));
+ DCHECK(c >= 0 && c < 0x7F);
+ SplitStringT(str, c, false, r);
+}
+
} // namespace base
diff --git a/base/string_split.h b/base/string_split.h
index 3e7881f..c7cb5e7 100644
--- a/base/string_split.h
+++ b/base/string_split.h
@@ -4,11 +4,41 @@
#ifndef BASE_STRING_SPLIT_H_
#define BASE_STRING_SPLIT_H_
+#pragma once
#include <string>
#include <utility>
#include <vector>
+#include "base/string16.h"
+
+// TODO(tfarina): Move the following functions into the namespace and update the
+// callers.
+//-----------------------------------------------------------------------------
+
+// Splits |str| into a vector of strings delimited by |s|. Append the results
+// into |r| as they appear. If several instances of |s| are contiguous, or if
+// |str| begins with or ends with |s|, then an empty string is inserted.
+//
+// Every substring is trimmed of any leading or trailing white space.
+// Where wchar_t is char16 (i.e. Windows), |c| must be in BMP
+// (Basic Multilingual Plane). Elsewhere (Linux/Mac), wchar_t
+// should be a valid Unicode code point (32-bit).
+void SplitString(const std::wstring& str,
+ wchar_t c,
+ std::vector<std::wstring>* r);
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+void SplitString(const string16& str,
+ char16 c,
+ std::vector<string16>* r);
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+void SplitString(const std::string& str,
+ char c,
+ std::vector<std::string>* r);
+
namespace base {
bool SplitStringIntoKeyValues(
@@ -22,6 +52,33 @@ bool SplitStringIntoKeyValuePairs(
char key_value_pair_delimiter,
std::vector<std::pair<std::string, std::string> >* kv_pairs);
+// The same as SplitString, but use a substring delimiter instead of a char.
+void SplitStringUsingSubstr(const string16& str,
+ const string16& s,
+ std::vector<string16>* r);
+void SplitStringUsingSubstr(const std::string& str,
+ const std::string& s,
+ std::vector<std::string>* r);
+
+// The same as SplitString, but don't trim white space.
+// Where wchar_t is char16 (i.e. Windows), |c| must be in BMP
+// (Basic Multilingual Plane). Elsewhere (Linux/Mac), wchar_t
+// should be a valid Unicode code point (32-bit).
+void SplitStringDontTrim(const std::wstring& str,
+ wchar_t c,
+ std::vector<std::wstring>* r);
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+void SplitStringDontTrim(const string16& str,
+ char16 c,
+ std::vector<string16>* r);
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+void SplitStringDontTrim(const std::string& str,
+ char c,
+ std::vector<std::string>* r);
+
} // namespace base
#endif // BASE_STRING_SPLIT_H
diff --git a/base/string_split_unittest.cc b/base/string_split_unittest.cc
index 820f74b..d4042ad 100644
--- a/base/string_split_unittest.cc
+++ b/base/string_split_unittest.cc
@@ -3,8 +3,11 @@
// found in the LICENSE file.
#include "base/string_split.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using ::testing::ElementsAre;
+
namespace base {
class SplitStringIntoKeyValuesTest : public testing::Test {
@@ -129,4 +132,134 @@ TEST_F(SplitStringIntoKeyValuePairsTest, DelimiterInValue) {
EXPECT_EQ("value2", kv_pairs[1].second);
}
+TEST(SplitStringUsingSubstrTest, EmptyString) {
+ std::vector<std::string> results;
+ SplitStringUsingSubstr("", "DELIMITER", &results);
+ ASSERT_EQ(1u, results.size());
+ EXPECT_THAT(results, ElementsAre(""));
+}
+
+// Test for SplitString
+TEST(StringUtilTest, SplitString) {
+ std::vector<std::wstring> r;
+
+ SplitString(L"", L',', &r);
+ ASSERT_EQ(1U, r.size());
+ EXPECT_EQ(r[0], L"");
+ r.clear();
+
+ SplitString(L"a,b,c", L',', &r);
+ ASSERT_EQ(3U, r.size());
+ EXPECT_EQ(r[0], L"a");
+ EXPECT_EQ(r[1], L"b");
+ EXPECT_EQ(r[2], L"c");
+ r.clear();
+
+ SplitString(L"a, b, c", L',', &r);
+ ASSERT_EQ(3U, r.size());
+ EXPECT_EQ(r[0], L"a");
+ EXPECT_EQ(r[1], L"b");
+ EXPECT_EQ(r[2], L"c");
+ r.clear();
+
+ SplitString(L"a,,c", L',', &r);
+ ASSERT_EQ(3U, r.size());
+ EXPECT_EQ(r[0], L"a");
+ EXPECT_EQ(r[1], L"");
+ EXPECT_EQ(r[2], L"c");
+ r.clear();
+
+ SplitString(L"", L'*', &r);
+ ASSERT_EQ(1U, r.size());
+ EXPECT_EQ(r[0], L"");
+ r.clear();
+
+ SplitString(L"foo", L'*', &r);
+ ASSERT_EQ(1U, r.size());
+ EXPECT_EQ(r[0], L"foo");
+ r.clear();
+
+ SplitString(L"foo ,", L',', &r);
+ ASSERT_EQ(2U, r.size());
+ EXPECT_EQ(r[0], L"foo");
+ EXPECT_EQ(r[1], L"");
+ r.clear();
+
+ SplitString(L",", L',', &r);
+ ASSERT_EQ(2U, r.size());
+ EXPECT_EQ(r[0], L"");
+ EXPECT_EQ(r[1], L"");
+ r.clear();
+
+ SplitString(L"\t\ta\t", L'\t', &r);
+ ASSERT_EQ(4U, r.size());
+ EXPECT_EQ(r[0], L"");
+ EXPECT_EQ(r[1], L"");
+ EXPECT_EQ(r[2], L"a");
+ EXPECT_EQ(r[3], L"");
+ r.clear();
+
+ SplitString(L"\ta\t\nb\tcc", L'\n', &r);
+ ASSERT_EQ(2U, r.size());
+ EXPECT_EQ(r[0], L"a");
+ EXPECT_EQ(r[1], L"b\tcc");
+ r.clear();
+}
+
+TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) {
+ std::vector<std::string> results;
+ SplitStringUsingSubstr("alongwordwithnodelimiter", "DELIMITER", &results);
+ ASSERT_EQ(1u, results.size());
+ EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
+}
+
+TEST(SplitStringUsingSubstrTest, LeadingDelimitersSkipped) {
+ std::vector<std::string> results;
+ SplitStringUsingSubstr(
+ "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree",
+ "DELIMITER",
+ &results);
+ ASSERT_EQ(6u, results.size());
+ EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
+}
+
+TEST(SplitStringUsingSubstrTest, ConsecutiveDelimitersSkipped) {
+ std::vector<std::string> results;
+ SplitStringUsingSubstr(
+ "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
+ "DELIMITER",
+ &results);
+ ASSERT_EQ(7u, results.size());
+ EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
+}
+
+TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) {
+ std::vector<std::string> results;
+ SplitStringUsingSubstr(
+ "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
+ "DELIMITER",
+ &results);
+ ASSERT_EQ(7u, results.size());
+ EXPECT_THAT(
+ results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
+}
+
+TEST(StringSplitTest, StringSplitDontTrim) {
+ std::vector<std::wstring> r;
+
+ SplitStringDontTrim(L"\t\ta\t", L'\t', &r);
+ ASSERT_EQ(4U, r.size());
+ EXPECT_EQ(r[0], L"");
+ EXPECT_EQ(r[1], L"");
+ EXPECT_EQ(r[2], L"a");
+ EXPECT_EQ(r[3], L"");
+ r.clear();
+
+ SplitStringDontTrim(L"\ta\t\nb\tcc", L'\n', &r);
+ ASSERT_EQ(2U, r.size());
+ EXPECT_EQ(r[0], L"\ta\t");
+ EXPECT_EQ(r[1], L"b\tcc");
+ r.clear();
+}
+
} // namespace base
diff --git a/base/string_tokenizer.h b/base/string_tokenizer.h
index 3b8f8c3..a274fd1 100644
--- a/base/string_tokenizer.h
+++ b/base/string_tokenizer.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef BASE_STRING_TOKENIZER_H_
#define BASE_STRING_TOKENIZER_H_
+#pragma once
#include <algorithm>
#include <string>
@@ -160,6 +161,7 @@ class StringTokenizerT {
end_ = string_end;
delims_ = delims;
options_ = 0;
+ token_is_delim_ = false;
}
// Implementation of GetNext() for when we have no quote characters. We have
@@ -174,7 +176,7 @@ class StringTokenizerT {
++token_end_;
if (delims_.find(*token_begin_) == str::npos)
break;
- // else skip over delim
+ // else skip over delimiter.
}
while (token_end_ != end_ && delims_.find(*token_end_) == str::npos)
++token_end_;
@@ -196,7 +198,7 @@ class StringTokenizerT {
token_is_delim_ = true;
return true;
}
- // else skip over delim
+ // else skip over delimiter.
}
while (token_end_ != end_ && AdvanceOne(&state, *token_end_))
++token_end_;
diff --git a/base/string_util.cc b/base/string_util.cc
index b09c049..dcab1d4 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -25,6 +25,7 @@
#include "base/singleton.h"
#include "base/third_party/dmg_fp/dmg_fp.h"
#include "base/utf_string_conversion_utils.h"
+#include "base/utf_string_conversions.h"
#include "base/third_party/icu/icu_utf.h"
namespace {
@@ -58,239 +59,8 @@ static bool CompareParameter(const ReplacementOffset& elem1,
return elem1.parameter < elem2.parameter;
}
-// Generalized string-to-number conversion.
-//
-// StringToNumberTraits should provide:
-// - a typedef for string_type, the STL string type used as input.
-// - a typedef for value_type, the target numeric type.
-// - a static function, convert_func, which dispatches to an appropriate
-// strtol-like function and returns type value_type.
-// - a static function, valid_func, which validates |input| and returns a bool
-// indicating whether it is in proper form. This is used to check for
-// conditions that convert_func tolerates but should result in
-// StringToNumber returning false. For strtol-like funtions, valid_func
-// should check for leading whitespace.
-template<typename StringToNumberTraits>
-bool StringToNumber(const typename StringToNumberTraits::string_type& input,
- typename StringToNumberTraits::value_type* output) {
- typedef StringToNumberTraits traits;
-
- errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows.
- typename traits::string_type::value_type* endptr = NULL;
- typename traits::value_type value = traits::convert_func(input.c_str(),
- &endptr);
- *output = value;
-
- // Cases to return false:
- // - If errno is ERANGE, there was an overflow or underflow.
- // - If the input string is empty, there was nothing to parse.
- // - If endptr does not point to the end of the string, there are either
- // characters remaining in the string after a parsed number, or the string
- // does not begin with a parseable number. endptr is compared to the
- // expected end given the string's stated length to correctly catch cases
- // where the string contains embedded NUL characters.
- // - valid_func determines that the input is not in preferred form.
- return errno == 0 &&
- !input.empty() &&
- input.c_str() + input.length() == endptr &&
- traits::valid_func(input);
-}
-
-static int strtoi(const char *nptr, char **endptr, int base) {
- long res = strtol(nptr, endptr, base);
-#if __LP64__
- // Long is 64-bits, we have to handle under/overflow ourselves.
- if (res > kint32max) {
- res = kint32max;
- errno = ERANGE;
- } else if (res < kint32min) {
- res = kint32min;
- errno = ERANGE;
- }
-#endif
- return static_cast<int>(res);
-}
-
-static unsigned int strtoui(const char *nptr, char **endptr, int base) {
- unsigned long res = strtoul(nptr, endptr, base);
-#if __LP64__
- // Long is 64-bits, we have to handle under/overflow ourselves. Test to see
- // if the result can fit into 32-bits (as signed or unsigned).
- if (static_cast<int>(static_cast<long>(res)) != static_cast<long>(res) &&
- static_cast<unsigned int>(res) != res) {
- res = kuint32max;
- errno = ERANGE;
- }
-#endif
- return static_cast<unsigned int>(res);
-}
-
-class StringToIntTraits {
- public:
- typedef std::string string_type;
- typedef int value_type;
- static const int kBase = 10;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
- return strtoi(str, endptr, kBase);
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !isspace(str[0]);
- }
-};
-
-class String16ToIntTraits {
- public:
- typedef string16 string_type;
- typedef int value_type;
- static const int kBase = 10;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
-#if defined(WCHAR_T_IS_UTF16)
- return wcstol(str, endptr, kBase);
-#elif defined(WCHAR_T_IS_UTF32)
- std::string ascii_string = UTF16ToASCII(string16(str));
- char* ascii_end = NULL;
- value_type ret = strtoi(ascii_string.c_str(), &ascii_end, kBase);
- if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
- *endptr =
- const_cast<string_type::value_type*>(str) + ascii_string.length();
- }
- return ret;
-#endif
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !iswspace(str[0]);
- }
-};
-
-class StringToInt64Traits {
- public:
- typedef std::string string_type;
- typedef int64 value_type;
- static const int kBase = 10;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
-#ifdef OS_WIN
- return _strtoi64(str, endptr, kBase);
-#else // assume OS_POSIX
- return strtoll(str, endptr, kBase);
-#endif
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !isspace(str[0]);
- }
-};
-
-class String16ToInt64Traits {
- public:
- typedef string16 string_type;
- typedef int64 value_type;
- static const int kBase = 10;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
-#ifdef OS_WIN
- return _wcstoi64(str, endptr, kBase);
-#else // assume OS_POSIX
- std::string ascii_string = UTF16ToASCII(string16(str));
- char* ascii_end = NULL;
- value_type ret = strtoll(ascii_string.c_str(), &ascii_end, kBase);
- if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
- *endptr =
- const_cast<string_type::value_type*>(str) + ascii_string.length();
- }
- return ret;
-#endif
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !iswspace(str[0]);
- }
-};
-
-// For the HexString variants, use the unsigned variants like strtoul for
-// convert_func so that input like "0x80000000" doesn't result in an overflow.
-
-class HexStringToIntTraits {
- public:
- typedef std::string string_type;
- typedef int value_type;
- static const int kBase = 16;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
- return strtoui(str, endptr, kBase);
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !isspace(str[0]);
- }
-};
-
-class HexString16ToIntTraits {
- public:
- typedef string16 string_type;
- typedef int value_type;
- static const int kBase = 16;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
-#if defined(WCHAR_T_IS_UTF16)
- return wcstoul(str, endptr, kBase);
-#elif defined(WCHAR_T_IS_UTF32)
- std::string ascii_string = UTF16ToASCII(string16(str));
- char* ascii_end = NULL;
- value_type ret = strtoui(ascii_string.c_str(), &ascii_end, kBase);
- if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
- *endptr =
- const_cast<string_type::value_type*>(str) + ascii_string.length();
- }
- return ret;
-#endif
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !iswspace(str[0]);
- }
-};
-
-class StringToDoubleTraits {
- public:
- typedef std::string string_type;
- typedef double value_type;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
- return dmg_fp::strtod(str, endptr);
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !isspace(str[0]);
- }
-};
-
-class String16ToDoubleTraits {
- public:
- typedef string16 string_type;
- typedef double value_type;
- static inline value_type convert_func(const string_type::value_type* str,
- string_type::value_type** endptr) {
- // Because dmg_fp::strtod does not like char16, we convert it to ASCII.
- // In theory, this should be safe, but it's possible that 16-bit chars
- // might get ignored by accident causing something to be parsed when it
- // shouldn't.
- std::string ascii_string = UTF16ToASCII(string16(str));
- char* ascii_end = NULL;
- value_type ret = dmg_fp::strtod(ascii_string.c_str(), &ascii_end);
- if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
- // Put endptr at end of input string, so it's not recognized as an error.
- *endptr =
- const_cast<string_type::value_type*>(str) + ascii_string.length();
- }
-
- return ret;
- }
- static inline bool valid_func(const string_type& str) {
- return !str.empty() && !iswspace(str[0]);
- }
-};
-
} // namespace
-
namespace base {
bool IsWprintfFormatPortable(const wchar_t* format) {
@@ -328,7 +98,6 @@ bool IsWprintfFormatPortable(const wchar_t* format) {
return true;
}
-
} // namespace base
@@ -653,21 +422,11 @@ std::string WideToASCII(const std::wstring& wide) {
return std::string(wide.begin(), wide.end());
}
-std::wstring ASCIIToWide(const base::StringPiece& ascii) {
- DCHECK(IsStringASCII(ascii)) << ascii;
- return std::wstring(ascii.begin(), ascii.end());
-}
-
std::string UTF16ToASCII(const string16& utf16) {
DCHECK(IsStringASCII(utf16)) << utf16;
return std::string(utf16.begin(), utf16.end());
}
-string16 ASCIIToUTF16(const base::StringPiece& ascii) {
- DCHECK(IsStringASCII(ascii)) << ascii;
- return string16(ascii.begin(), ascii.end());
-}
-
// Latin1 is just the low range of Unicode, so we can copy directly to convert.
bool WideToLatin1(const std::wstring& wide, std::string* latin1) {
std::string output;
@@ -899,27 +658,27 @@ DataUnits GetByteDisplayUnits(int64 bytes) {
// TODO(mpcomplete): deal with locale
// Byte suffixes. This must match the DataUnits enum.
-static const wchar_t* const kByteStrings[] = {
- L"B",
- L"kB",
- L"MB",
- L"GB"
+static const char* const kByteStrings[] = {
+ "B",
+ "kB",
+ "MB",
+ "GB"
};
-static const wchar_t* const kSpeedStrings[] = {
- L"B/s",
- L"kB/s",
- L"MB/s",
- L"GB/s"
+static const char* const kSpeedStrings[] = {
+ "B/s",
+ "kB/s",
+ "MB/s",
+ "GB/s"
};
-std::wstring FormatBytesInternal(int64 bytes,
- DataUnits units,
- bool show_units,
- const wchar_t* const* suffix) {
+string16 FormatBytesInternal(int64 bytes,
+ DataUnits units,
+ bool show_units,
+ const char* const* suffix) {
if (bytes < 0) {
NOTREACHED() << "Negative bytes value";
- return std::wstring();
+ return string16();
}
DCHECK(units >= DATA_UNITS_BYTE && units <= DATA_UNITS_GIBIBYTE);
@@ -929,26 +688,26 @@ std::wstring FormatBytesInternal(int64 bytes,
for (int i = 0; i < units; ++i)
unit_amount /= 1024.0;
- wchar_t buf[64];
+ char buf[64];
if (bytes != 0 && units != DATA_UNITS_BYTE && unit_amount < 100)
- base::swprintf(buf, arraysize(buf), L"%.1lf", unit_amount);
+ base::snprintf(buf, arraysize(buf), "%.1lf", unit_amount);
else
- base::swprintf(buf, arraysize(buf), L"%.0lf", unit_amount);
+ base::snprintf(buf, arraysize(buf), "%.0lf", unit_amount);
- std::wstring ret(buf);
+ std::string ret(buf);
if (show_units) {
- ret += L" ";
+ ret += " ";
ret += suffix[units];
}
- return ret;
+ return ASCIIToUTF16(ret);
}
-std::wstring FormatBytes(int64 bytes, DataUnits units, bool show_units) {
+string16 FormatBytes(int64 bytes, DataUnits units, bool show_units) {
return FormatBytesInternal(bytes, units, show_units, kByteStrings);
}
-std::wstring FormatSpeed(int64 bytes, DataUnits units, bool show_units) {
+string16 FormatSpeed(int64 bytes, DataUnits units, bool show_units) {
return FormatBytesInternal(bytes, units, show_units, kSpeedStrings);
}
@@ -1004,395 +763,6 @@ void ReplaceSubstringsAfterOffset(std::string* str,
true); // replace all instances
}
-// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
-// is the size of the buffer. These return the number of characters in the
-// formatted string excluding the NUL terminator. If the buffer is not
-// large enough to accommodate the formatted string without truncation, they
-// return the number of characters that would be in the fully-formatted string
-// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
-inline int vsnprintfT(char* buffer,
- size_t buf_size,
- const char* format,
- va_list argptr) {
- return base::vsnprintf(buffer, buf_size, format, argptr);
-}
-
-inline int vsnprintfT(wchar_t* buffer,
- size_t buf_size,
- const wchar_t* format,
- va_list argptr) {
- return base::vswprintf(buffer, buf_size, format, argptr);
-}
-
-// Templatized backend for StringPrintF/StringAppendF. This does not finalize
-// the va_list, the caller is expected to do that.
-template <class StringType>
-static void StringAppendVT(StringType* dst,
- const typename StringType::value_type* format,
- va_list ap) {
- // First try with a small fixed size buffer.
- // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
- // and StringUtilTest.StringPrintfBounds.
- typename StringType::value_type stack_buf[1024];
-
- va_list ap_copy;
- GG_VA_COPY(ap_copy, ap);
-
-#if !defined(OS_WIN)
- errno = 0;
-#endif
- int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
- va_end(ap_copy);
-
- if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
- // It fit.
- dst->append(stack_buf, result);
- return;
- }
-
- // Repeatedly increase buffer size until it fits.
- int mem_length = arraysize(stack_buf);
- while (true) {
- if (result < 0) {
-#if !defined(OS_WIN)
- // On Windows, vsnprintfT always returns the number of characters in a
- // fully-formatted string, so if we reach this point, something else is
- // wrong and no amount of buffer-doubling is going to fix it.
- if (errno != 0 && errno != EOVERFLOW)
-#endif
- {
- // If an error other than overflow occurred, it's never going to work.
- DLOG(WARNING) << "Unable to printf the requested string due to error.";
- return;
- }
- // Try doubling the buffer size.
- mem_length *= 2;
- } else {
- // We need exactly "result + 1" characters.
- mem_length = result + 1;
- }
-
- if (mem_length > 32 * 1024 * 1024) {
- // That should be plenty, don't try anything larger. This protects
- // against huge allocations when using vsnprintfT implementations that
- // return -1 for reasons other than overflow without setting errno.
- DLOG(WARNING) << "Unable to printf the requested string due to size.";
- return;
- }
-
- std::vector<typename StringType::value_type> mem_buf(mem_length);
-
- // NOTE: You can only use a va_list once. Since we're in a while loop, we
- // need to make a new copy each time so we don't use up the original.
- GG_VA_COPY(ap_copy, ap);
- result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
- va_end(ap_copy);
-
- if ((result >= 0) && (result < mem_length)) {
- // It fit.
- dst->append(&mem_buf[0], result);
- return;
- }
- }
-}
-
-namespace {
-
-template <typename STR, typename INT, typename UINT, bool NEG>
-struct IntToStringT {
- // This is to avoid a compiler warning about unary minus on unsigned type.
- // For example, say you had the following code:
- // template <typename INT>
- // INT abs(INT value) { return value < 0 ? -value : value; }
- // Even though if INT is unsigned, it's impossible for value < 0, so the
- // unary minus will never be taken, the compiler will still generate a
- // warning. We do a little specialization dance...
- template <typename INT2, typename UINT2, bool NEG2>
- struct ToUnsignedT { };
-
- template <typename INT2, typename UINT2>
- struct ToUnsignedT<INT2, UINT2, false> {
- static UINT2 ToUnsigned(INT2 value) {
- return static_cast<UINT2>(value);
- }
- };
-
- template <typename INT2, typename UINT2>
- struct ToUnsignedT<INT2, UINT2, true> {
- static UINT2 ToUnsigned(INT2 value) {
- return static_cast<UINT2>(value < 0 ? -value : value);
- }
- };
-
- // This set of templates is very similar to the above templates, but
- // for testing whether an integer is negative.
- template <typename INT2, bool NEG2>
- struct TestNegT { };
- template <typename INT2>
- struct TestNegT<INT2, false> {
- static bool TestNeg(INT2 value) {
- // value is unsigned, and can never be negative.
- return false;
- }
- };
- template <typename INT2>
- struct TestNegT<INT2, true> {
- static bool TestNeg(INT2 value) {
- return value < 0;
- }
- };
-
- static STR IntToString(INT value) {
- // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
- // So round up to allocate 3 output characters per byte, plus 1 for '-'.
- const int kOutputBufSize = 3 * sizeof(INT) + 1;
-
- // Allocate the whole string right away, we will right back to front, and
- // then return the substr of what we ended up using.
- STR outbuf(kOutputBufSize, 0);
-
- bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
- // Even though is_neg will never be true when INT is parameterized as
- // unsigned, even the presence of the unary operation causes a warning.
- UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
-
- for (typename STR::iterator it = outbuf.end();;) {
- --it;
- DCHECK(it != outbuf.begin());
- *it = static_cast<typename STR::value_type>((res % 10) + '0');
- res /= 10;
-
- // We're done..
- if (res == 0) {
- if (is_neg) {
- --it;
- DCHECK(it != outbuf.begin());
- *it = static_cast<typename STR::value_type>('-');
- }
- return STR(it, outbuf.end());
- }
- }
- NOTREACHED();
- return STR();
- }
-};
-
-}
-
-std::string IntToString(int value) {
- return IntToStringT<std::string, int, unsigned int, true>::
- IntToString(value);
-}
-std::wstring IntToWString(int value) {
- return IntToStringT<std::wstring, int, unsigned int, true>::
- IntToString(value);
-}
-string16 IntToString16(int value) {
- return IntToStringT<string16, int, unsigned int, true>::
- IntToString(value);
-}
-std::string UintToString(unsigned int value) {
- return IntToStringT<std::string, unsigned int, unsigned int, false>::
- IntToString(value);
-}
-std::wstring UintToWString(unsigned int value) {
- return IntToStringT<std::wstring, unsigned int, unsigned int, false>::
- IntToString(value);
-}
-string16 UintToString16(unsigned int value) {
- return IntToStringT<string16, unsigned int, unsigned int, false>::
- IntToString(value);
-}
-std::string Int64ToString(int64 value) {
- return IntToStringT<std::string, int64, uint64, true>::
- IntToString(value);
-}
-std::wstring Int64ToWString(int64 value) {
- return IntToStringT<std::wstring, int64, uint64, true>::
- IntToString(value);
-}
-std::string Uint64ToString(uint64 value) {
- return IntToStringT<std::string, uint64, uint64, false>::
- IntToString(value);
-}
-std::wstring Uint64ToWString(uint64 value) {
- return IntToStringT<std::wstring, uint64, uint64, false>::
- IntToString(value);
-}
-
-std::string DoubleToString(double value) {
- // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
- char buffer[32];
- dmg_fp::g_fmt(buffer, value);
- return std::string(buffer);
-}
-
-std::wstring DoubleToWString(double value) {
- return ASCIIToWide(DoubleToString(value));
-}
-
-void StringAppendV(std::string* dst, const char* format, va_list ap) {
- StringAppendVT(dst, format, ap);
-}
-
-void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
- StringAppendVT(dst, format, ap);
-}
-
-std::string StringPrintf(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- std::string result;
- StringAppendV(&result, format, ap);
- va_end(ap);
- return result;
-}
-
-std::wstring StringPrintf(const wchar_t* format, ...) {
- va_list ap;
- va_start(ap, format);
- std::wstring result;
- StringAppendV(&result, format, ap);
- va_end(ap);
- return result;
-}
-
-std::string StringPrintV(const char* format, va_list ap) {
- std::string result;
- StringAppendV(&result, format, ap);
- return result;
-}
-
-const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- dst->clear();
- StringAppendV(dst, format, ap);
- va_end(ap);
- return *dst;
-}
-
-const std::wstring& SStringPrintf(std::wstring* dst,
- const wchar_t* format, ...) {
- va_list ap;
- va_start(ap, format);
- dst->clear();
- StringAppendV(dst, format, ap);
- va_end(ap);
- return *dst;
-}
-
-void StringAppendF(std::string* dst, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- StringAppendV(dst, format, ap);
- va_end(ap);
-}
-
-void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
- va_list ap;
- va_start(ap, format);
- StringAppendV(dst, format, ap);
- va_end(ap);
-}
-
-template<typename STR>
-static void SplitStringT(const STR& str,
- const typename STR::value_type s,
- bool trim_whitespace,
- std::vector<STR>* r) {
- size_t last = 0;
- size_t i;
- size_t c = str.size();
- for (i = 0; i <= c; ++i) {
- if (i == c || str[i] == s) {
- size_t len = i - last;
- STR tmp = str.substr(last, len);
- if (trim_whitespace) {
- STR t_tmp;
- TrimWhitespace(tmp, TRIM_ALL, &t_tmp);
- r->push_back(t_tmp);
- } else {
- r->push_back(tmp);
- }
- last = i + 1;
- }
- }
-}
-
-void SplitString(const std::wstring& str,
- wchar_t s,
- std::vector<std::wstring>* r) {
- SplitStringT(str, s, true, r);
-}
-
-#if !defined(WCHAR_T_IS_UTF16)
-void SplitString(const string16& str,
- char16 s,
- std::vector<string16>* r) {
- SplitStringT(str, s, true, r);
-}
-#endif
-
-void SplitString(const std::string& str,
- char s,
- std::vector<std::string>* r) {
- SplitStringT(str, s, true, r);
-}
-
-void SplitStringDontTrim(const std::wstring& str,
- wchar_t s,
- std::vector<std::wstring>* r) {
- SplitStringT(str, s, false, r);
-}
-
-#if !defined(WCHAR_T_IS_UTF16)
-void SplitStringDontTrim(const string16& str,
- char16 s,
- std::vector<string16>* r) {
- SplitStringT(str, s, false, r);
-}
-#endif
-
-void SplitStringDontTrim(const std::string& str,
- char s,
- std::vector<std::string>* r) {
- SplitStringT(str, s, false, r);
-}
-
-template <typename STR>
-static void SplitStringUsingSubstrT(const STR& str,
- const STR& s,
- std::vector<STR>* r) {
- typename STR::size_type begin_index = 0;
- while (true) {
- const typename STR::size_type end_index = str.find(s, begin_index);
- if (end_index == STR::npos) {
- const STR term = str.substr(begin_index);
- STR tmp;
- TrimWhitespace(term, TRIM_ALL, &tmp);
- r->push_back(tmp);
- return;
- }
- const STR term = str.substr(begin_index, end_index - begin_index);
- STR tmp;
- TrimWhitespace(term, TRIM_ALL, &tmp);
- r->push_back(tmp);
- begin_index = end_index + s.size();
- }
-}
-
-void SplitStringUsingSubstr(const string16& str,
- const string16& s,
- std::vector<string16>* r) {
- SplitStringUsingSubstrT(str, s, r);
-}
-
-void SplitStringUsingSubstr(const std::string& str,
- const std::string& s,
- std::vector<std::string>* r) {
- SplitStringUsingSubstrT(str, s, r);
-}
template<typename STR>
static size_t TokenizeT(const STR& str,
@@ -1552,7 +922,11 @@ OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
++i;
DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
if ('$' == *i) {
- formatted.push_back('$');
+ while (i != format_string.end() && '$' == *i) {
+ formatted.push_back('$');
+ ++i;
+ }
+ --i;
} else {
uintptr_t index = *i - '1';
if (offsets) {
@@ -1607,102 +981,116 @@ string16 ReplaceStringPlaceholders(const string16& format_string,
return result;
}
-template <class CHAR>
-static bool IsWildcard(CHAR character) {
+static bool IsWildcard(base_icu::UChar32 character) {
return character == '*' || character == '?';
}
// Move the strings pointers to the point where they start to differ.
-template <class CHAR>
-static void EatSameChars(const CHAR** pattern, const CHAR** string) {
- bool escaped = false;
- while (**pattern && **string) {
- if (!escaped && IsWildcard(**pattern)) {
+template <typename CHAR, typename NEXT>
+static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
+ const CHAR** string, const CHAR* string_end,
+ NEXT next) {
+ const CHAR* escape = NULL;
+ while (*pattern != pattern_end && *string != string_end) {
+ if (!escape && IsWildcard(**pattern)) {
// We don't want to match wildcard here, except if it's escaped.
return;
}
// Check if the escapement char is found. If so, skip it and move to the
// next character.
- if (!escaped && **pattern == L'\\') {
- escaped = true;
- (*pattern)++;
+ if (!escape && **pattern == '\\') {
+ escape = *pattern;
+ next(pattern, pattern_end);
continue;
}
// Check if the chars match, if so, increment the ptrs.
- if (**pattern == **string) {
- (*pattern)++;
- (*string)++;
+ const CHAR* pattern_next = *pattern;
+ const CHAR* string_next = *string;
+ base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
+ if (pattern_char == next(&string_next, string_end) &&
+ pattern_char != (base_icu::UChar32) CBU_SENTINEL) {
+ *pattern = pattern_next;
+ *string = string_next;
} else {
// Uh ho, it did not match, we are done. If the last char was an
// escapement, that means that it was an error to advance the ptr here,
// let's put it back where it was. This also mean that the MatchPattern
// function will return false because if we can't match an escape char
// here, then no one will.
- if (escaped) {
- (*pattern)--;
+ if (escape) {
+ *pattern = escape;
}
return;
}
- escaped = false;
+ escape = NULL;
}
}
-template <class CHAR>
-static void EatWildcard(const CHAR** pattern) {
- while (**pattern) {
+template <typename CHAR, typename NEXT>
+static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+ while (*pattern != end) {
if (!IsWildcard(**pattern))
return;
- (*pattern)++;
+ next(pattern, end);
}
}
-template <class CHAR>
-static bool MatchPatternT(const CHAR* eval, const CHAR* pattern, int depth) {
+template <typename CHAR, typename NEXT>
+static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
+ const CHAR* pattern, const CHAR* pattern_end,
+ int depth,
+ NEXT next) {
const int kMaxDepth = 16;
if (depth > kMaxDepth)
return false;
// Eat all the matching chars.
- EatSameChars(&pattern, &eval);
+ EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
// If the string is empty, then the pattern must be empty too, or contains
// only wildcards.
- if (*eval == 0) {
- EatWildcard(&pattern);
- if (*pattern)
- return false;
- return true;
+ if (eval == eval_end) {
+ EatWildcard(&pattern, pattern_end, next);
+ return pattern == pattern_end;
}
// Pattern is empty but not string, this is not a match.
- if (*pattern == 0)
+ if (pattern == pattern_end)
return false;
// If this is a question mark, then we need to compare the rest with
// the current string or the string with one character eaten.
+ const CHAR* next_pattern = pattern;
+ next(&next_pattern, pattern_end);
if (pattern[0] == '?') {
- if (MatchPatternT(eval, pattern + 1, depth + 1) ||
- MatchPatternT(eval + 1, pattern + 1, depth + 1))
+ if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+ depth + 1, next))
+ return true;
+ const CHAR* next_eval = eval;
+ next(&next_eval, eval_end);
+ if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
+ depth + 1, next))
return true;
}
// This is a *, try to match all the possible substrings with the remainder
// of the pattern.
if (pattern[0] == '*') {
- while (*eval) {
- if (MatchPatternT(eval, pattern + 1, depth + 1))
+ while (eval != eval_end) {
+ if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+ depth + 1, next))
return true;
eval++;
}
// We reached the end of the string, let see if the pattern contains only
// wildcards.
- if (*eval == 0) {
- EatWildcard(&pattern);
- if (*pattern)
+ if (eval == eval_end) {
+ EatWildcard(&pattern, pattern_end, next);
+ if (pattern != pattern_end)
return false;
return true;
}
@@ -1711,135 +1099,37 @@ static bool MatchPatternT(const CHAR* eval, const CHAR* pattern, int depth) {
return false;
}
-bool MatchPatternWide(const std::wstring& eval, const std::wstring& pattern) {
- return MatchPatternT(eval.c_str(), pattern.c_str(), 0);
-}
-
-bool MatchPatternASCII(const std::string& eval, const std::string& pattern) {
- DCHECK(IsStringASCII(eval) && IsStringASCII(pattern));
- return MatchPatternT(eval.c_str(), pattern.c_str(), 0);
-}
-
-bool StringToInt(const std::string& input, int* output) {
- return StringToNumber<StringToIntTraits>(input, output);
-}
-
-bool StringToInt(const string16& input, int* output) {
- return StringToNumber<String16ToIntTraits>(input, output);
-}
-
-bool StringToInt64(const std::string& input, int64* output) {
- return StringToNumber<StringToInt64Traits>(input, output);
-}
-
-bool StringToInt64(const string16& input, int64* output) {
- return StringToNumber<String16ToInt64Traits>(input, output);
-}
-
-bool HexStringToInt(const std::string& input, int* output) {
- return StringToNumber<HexStringToIntTraits>(input, output);
-}
-
-bool HexStringToInt(const string16& input, int* output) {
- return StringToNumber<HexString16ToIntTraits>(input, output);
-}
-
-namespace {
-
-template<class CHAR>
-bool HexDigitToIntT(const CHAR digit, uint8* val) {
- if (digit >= '0' && digit <= '9')
- *val = digit - '0';
- else if (digit >= 'a' && digit <= 'f')
- *val = 10 + digit - 'a';
- else if (digit >= 'A' && digit <= 'F')
- *val = 10 + digit - 'A';
- else
- return false;
- return true;
-}
-
-template<typename STR>
-bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
- DCHECK(output->size() == 0);
- size_t count = input.size();
- if (count == 0 || (count % 2) != 0)
- return false;
- for (uintptr_t i = 0; i < count / 2; ++i) {
- uint8 msb = 0; // most significant 4 bits
- uint8 lsb = 0; // least significant 4 bits
- if (!HexDigitToIntT(input[i * 2], &msb) ||
- !HexDigitToIntT(input[i * 2 + 1], &lsb))
- return false;
- output->push_back((msb << 4) | lsb);
+struct NextCharUTF8 {
+ base_icu::UChar32 operator()(const char** p, const char* end) {
+ base_icu::UChar32 c;
+ int offset = 0;
+ CBU8_NEXT(*p, offset, end - *p, c);
+ *p += offset;
+ return c;
}
- return true;
-}
-
-} // namespace
-
-bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
- return HexStringToBytesT(input, output);
-}
-
-bool HexStringToBytes(const string16& input, std::vector<uint8>* output) {
- return HexStringToBytesT(input, output);
-}
-
-int StringToInt(const std::string& value) {
- int result;
- StringToInt(value, &result);
- return result;
-}
-
-int StringToInt(const string16& value) {
- int result;
- StringToInt(value, &result);
- return result;
-}
-
-int64 StringToInt64(const std::string& value) {
- int64 result;
- StringToInt64(value, &result);
- return result;
-}
-
-int64 StringToInt64(const string16& value) {
- int64 result;
- StringToInt64(value, &result);
- return result;
-}
-
-int HexStringToInt(const std::string& value) {
- int result;
- HexStringToInt(value, &result);
- return result;
-}
-
-int HexStringToInt(const string16& value) {
- int result;
- HexStringToInt(value, &result);
- return result;
-}
-
-bool StringToDouble(const std::string& input, double* output) {
- return StringToNumber<StringToDoubleTraits>(input, output);
-}
+};
-bool StringToDouble(const string16& input, double* output) {
- return StringToNumber<String16ToDoubleTraits>(input, output);
-}
+struct NextCharUTF16 {
+ base_icu::UChar32 operator()(const char16** p, const char16* end) {
+ base_icu::UChar32 c;
+ int offset = 0;
+ CBU16_NEXT(*p, offset, end - *p, c);
+ *p += offset;
+ return c;
+ }
+};
-double StringToDouble(const std::string& value) {
- double result;
- StringToDouble(value, &result);
- return result;
+bool MatchPattern(const base::StringPiece& eval,
+ const base::StringPiece& pattern) {
+ return MatchPatternT(eval.data(), eval.data() + eval.size(),
+ pattern.data(), pattern.data() + pattern.size(),
+ 0, NextCharUTF8());
}
-double StringToDouble(const string16& value) {
- double result;
- StringToDouble(value, &result);
- return result;
+bool MatchPattern(const string16& eval, const string16& pattern) {
+ return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
+ pattern.c_str(), pattern.c_str() + pattern.size(),
+ 0, NextCharUTF16());
}
// The following code is compatible with the OpenBSD lcpy interface. See:
@@ -1909,17 +1199,3 @@ bool ElideString(const std::wstring& input, int max_len, std::wstring* output) {
return true;
}
-
-std::string HexEncode(const void* bytes, size_t size) {
- static const char kHexChars[] = "0123456789ABCDEF";
-
- // Each input byte creates two output hex characters.
- std::string ret(size * 2, '\0');
-
- for (size_t i = 0; i < size; ++i) {
- char b = reinterpret_cast<const char*>(bytes)[i];
- ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
- ret[(i * 2) + 1] = kHexChars[b & 0xf];
- }
- return ret;
-}
diff --git a/base/string_util.h b/base/string_util.h
index 11a9fd2..7079127 100644
--- a/base/string_util.h
+++ b/base/string_util.h
@@ -6,6 +6,7 @@
#ifndef BASE_STRING_UTIL_H_
#define BASE_STRING_UTIL_H_
+#pragma once
#include <stdarg.h> // va_list
@@ -17,6 +18,17 @@
#include "base/string16.h"
#include "base/string_piece.h" // For implicit conversions.
+// TODO(brettw) remove this dependency. Previously StringPrintf lived in this
+// file. We need to convert the callers over to using stringprintf.h instead
+// and then remove this.
+#include "base/stringprintf.h"
+
+#ifdef RLZ_WIN_LIB_RLZ_LIB_H_
+// TODO(tfarina): Fix the rlz library to include this instead and remove
+// this include.
+#include "base/string_split.h"
+#endif // RLZ_WIN_LIB_RLZ_LIB_H_
+
// Safe standard library wrappers for all platforms.
namespace base {
@@ -226,11 +238,10 @@ bool ContainsOnlyChars(const std::wstring& input,
bool ContainsOnlyChars(const string16& input, const string16& characters);
bool ContainsOnlyChars(const std::string& input, const std::string& characters);
-// These convert between ASCII (7-bit) and Wide/UTF16 strings.
+// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
+// beforehand.
std::string WideToASCII(const std::wstring& wide);
-std::wstring ASCIIToWide(const base::StringPiece& ascii);
std::string UTF16ToASCII(const string16& utf16);
-string16 ASCIIToUTF16(const base::StringPiece& ascii);
// Converts the given wide string to the corresponding Latin1. This will fail
// (return false) if any characters are more than 255.
@@ -363,6 +374,25 @@ inline bool IsAsciiDigit(Char c) {
return c >= '0' && c <= '9';
}
+template <typename Char>
+inline bool IsHexDigit(Char c) {
+ return (c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f');
+}
+
+template <typename Char>
+inline Char HexDigitToInt(Char c) {
+ DCHECK(IsHexDigit(c));
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return 0;
+}
+
// Returns true if it's a whitespace character.
inline bool IsWhitespace(wchar_t c) {
return wcschr(kWhitespaceWide, c) != NULL;
@@ -383,16 +413,16 @@ DataUnits GetByteDisplayUnits(int64 bytes);
// specified by 'units', with an optional unit suffix.
// Ex: FormatBytes(512, DATA_UNITS_KIBIBYTE, true) => "0.5 KB"
// Ex: FormatBytes(10*1024, DATA_UNITS_MEBIBYTE, false) => "0.1"
-std::wstring FormatBytes(int64 bytes, DataUnits units, bool show_units);
+string16 FormatBytes(int64 bytes, DataUnits units, bool show_units);
// As above, but with "/s" units.
// Ex: FormatSpeed(512, DATA_UNITS_KIBIBYTE, true) => "0.5 KB/s"
// Ex: FormatSpeed(10*1024, DATA_UNITS_MEBIBYTE, false) => "0.1"
-std::wstring FormatSpeed(int64 bytes, DataUnits units, bool show_units);
+string16 FormatSpeed(int64 bytes, DataUnits units, bool show_units);
// Return a number formated with separators in the user's locale way.
// Ex: FormatNumber(1234567) => 1,234,567
-std::wstring FormatNumber(int64 number);
+string16 FormatNumber(int64 number);
// Starting at |start_offset| (usually 0), replace the first instance of
// |find_this| with |replace_with|.
@@ -420,94 +450,6 @@ void ReplaceSubstringsAfterOffset(std::string* str,
const std::string& find_this,
const std::string& replace_with);
-// Specialized string-conversion functions.
-std::string IntToString(int value);
-std::wstring IntToWString(int value);
-string16 IntToString16(int value);
-std::string UintToString(unsigned int value);
-std::wstring UintToWString(unsigned int value);
-string16 UintToString16(unsigned int value);
-std::string Int64ToString(int64 value);
-std::wstring Int64ToWString(int64 value);
-std::string Uint64ToString(uint64 value);
-std::wstring Uint64ToWString(uint64 value);
-// The DoubleToString methods convert the double to a string format that
-// ignores the locale. If you want to use locale specific formatting, use ICU.
-std::string DoubleToString(double value);
-std::wstring DoubleToWString(double value);
-
-// Perform a best-effort conversion of the input string to a numeric type,
-// setting |*output| to the result of the conversion. Returns true for
-// "perfect" conversions; returns false in the following cases:
-// - Overflow/underflow. |*output| will be set to the maximum value supported
-// by the data type.
-// - Trailing characters in the string after parsing the number. |*output|
-// will be set to the value of the number that was parsed.
-// - No characters parseable as a number at the beginning of the string.
-// |*output| will be set to 0.
-// - Empty string. |*output| will be set to 0.
-bool StringToInt(const std::string& input, int* output);
-bool StringToInt(const string16& input, int* output);
-bool StringToInt64(const std::string& input, int64* output);
-bool StringToInt64(const string16& input, int64* output);
-bool HexStringToInt(const std::string& input, int* output);
-bool HexStringToInt(const string16& input, int* output);
-
-// Similar to the previous functions, except that output is a vector of bytes.
-// |*output| will contain as many bytes as were successfully parsed prior to the
-// error. There is no overflow, but input.size() must be evenly divisible by 2.
-// Leading 0x or +/- are not allowed.
-bool HexStringToBytes(const std::string& input, std::vector<uint8>* output);
-bool HexStringToBytes(const string16& input, std::vector<uint8>* output);
-
-// For floating-point conversions, only conversions of input strings in decimal
-// form are defined to work. Behavior with strings representing floating-point
-// numbers in hexadecimal, and strings representing non-fininte values (such as
-// NaN and inf) is undefined. Otherwise, these behave the same as the integral
-// variants. This expects the input string to NOT be specific to the locale.
-// If your input is locale specific, use ICU to read the number.
-bool StringToDouble(const std::string& input, double* output);
-bool StringToDouble(const string16& input, double* output);
-
-// Convenience forms of the above, when the caller is uninterested in the
-// boolean return value. These return only the |*output| value from the
-// above conversions: a best-effort conversion when possible, otherwise, 0.
-int StringToInt(const std::string& value);
-int StringToInt(const string16& value);
-int64 StringToInt64(const std::string& value);
-int64 StringToInt64(const string16& value);
-int HexStringToInt(const std::string& value);
-int HexStringToInt(const string16& value);
-double StringToDouble(const std::string& value);
-double StringToDouble(const string16& value);
-
-// Return a C++ string given printf-like input.
-std::string StringPrintf(const char* format, ...) PRINTF_FORMAT(1, 2);
-std::wstring StringPrintf(const wchar_t* format, ...) WPRINTF_FORMAT(1, 2);
-
-// Return a C++ string given vprintf-like input.
-std::string StringPrintV(const char* format, va_list ap) PRINTF_FORMAT(1, 0);
-
-// Store result into a supplied string and return it
-const std::string& SStringPrintf(std::string* dst, const char* format, ...)
- PRINTF_FORMAT(2, 3);
-const std::wstring& SStringPrintf(std::wstring* dst,
- const wchar_t* format, ...)
- WPRINTF_FORMAT(2, 3);
-
-// Append result to a supplied string
-void StringAppendF(std::string* dst, const char* format, ...)
- PRINTF_FORMAT(2, 3);
-void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
- WPRINTF_FORMAT(2, 3);
-
-// Lower-level routine that takes a va_list and appends to a specified
-// string. All other routines are just convenience wrappers around it.
-void StringAppendV(std::string* dst, const char* format, va_list ap)
- PRINTF_FORMAT(2, 0);
-void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap)
- WPRINTF_FORMAT(2, 0);
-
// This is mpcomplete's pattern for saving a string copy when dealing with
// a function that writes results into a wchar_t[] and wanting the result to
// end up in a std::wstring. It ensures that the std::wstring's internal
@@ -551,44 +493,6 @@ template<typename Char> struct CaseInsensitiveCompareASCII {
}
};
-// TODO(timsteele): Move these split string functions into their own API on
-// string_split.cc/.h files.
-//-----------------------------------------------------------------------------
-
-// Splits |str| into a vector of strings delimited by |s|. Append the results
-// into |r| as they appear. If several instances of |s| are contiguous, or if
-// |str| begins with or ends with |s|, then an empty string is inserted.
-//
-// Every substring is trimmed of any leading or trailing white space.
-void SplitString(const std::wstring& str,
- wchar_t s,
- std::vector<std::wstring>* r);
-void SplitString(const string16& str,
- char16 s,
- std::vector<string16>* r);
-void SplitString(const std::string& str,
- char s,
- std::vector<std::string>* r);
-
-// The same as SplitString, but don't trim white space.
-void SplitStringDontTrim(const std::wstring& str,
- wchar_t s,
- std::vector<std::wstring>* r);
-void SplitStringDontTrim(const string16& str,
- char16 s,
- std::vector<string16>* r);
-void SplitStringDontTrim(const std::string& str,
- char s,
- std::vector<std::string>* r);
-
-// The same as SplitString, but use a substring delimiter instead of a char.
-void SplitStringUsingSubstr(const string16& str,
- const string16& s,
- std::vector<string16>* r);
-void SplitStringUsingSubstr(const std::string& str,
- const std::string& s,
- std::vector<std::string>* r);
-
// Splits a string into its fields delimited by any of the characters in
// |delimiters|. Each field is added to the |tokens| vector. Returns the
// number of tokens found.
@@ -626,8 +530,9 @@ void SplitStringAlongWhitespace(const std::string& str,
std::vector<std::string>* result);
// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
-// Additionally, $$ is replaced by $. The offsets parameter here can
-// be NULL. This only allows you to use up to nine replacements.
+// Additionally, any number of consecutive '$' characters is replaced by that
+// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
+// NULL. This only allows you to use up to nine replacements.
string16 ReplaceStringPlaceholders(const string16& format_string,
const std::vector<string16>& subst,
std::vector<size_t>* offsets);
@@ -636,7 +541,7 @@ std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
const std::vector<std::string>& subst,
std::vector<size_t>* offsets);
-// Single-string shortcut for ReplaceStringHolders.
+// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
string16 ReplaceStringPlaceholders(const string16& format_string,
const string16& a,
size_t* offset);
@@ -653,17 +558,9 @@ bool ElideString(const std::wstring& input, int max_len, std::wstring* output);
// string can contain wildcards like * and ?
// The backslash character (\) is an escape character for * and ?
// We limit the patterns to having a max of 16 * or ? characters.
-bool MatchPatternWide(const std::wstring& string, const std::wstring& pattern);
-bool MatchPatternASCII(const std::string& string, const std::string& pattern);
-
-// Returns a hex string representation of a binary buffer.
-// The returned hex string will be in upper case.
-// This function does not check if |size| is within reasonable limits since
-// it's written with trusted data in mind.
-// If you suspect that the data you want to format might be large,
-// the absolute max size for |size| should be is
-// std::numeric_limits<size_t>::max() / 2
-std::string HexEncode(const void* bytes, size_t size);
+bool MatchPattern(const base::StringPiece& string,
+ const base::StringPiece& pattern);
+bool MatchPattern(const string16& string, const string16& pattern);
// Hack to convert any char-like type to its unsigned counterpart.
// For example, it will convert char, signed char and unsigned char to unsigned
diff --git a/base/string_util_posix.h b/base/string_util_posix.h
index 15a3792..f9f732b 100644
--- a/base/string_util_posix.h
+++ b/base/string_util_posix.h
@@ -4,6 +4,7 @@
#ifndef BASE_STRING_UTIL_POSIX_H_
#define BASE_STRING_UTIL_POSIX_H_
+#pragma once
#include <stdarg.h>
#include <stdio.h>
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
index 7afc0bd..8163ba0 100644
--- a/base/string_util_unittest.cc
+++ b/base/string_util_unittest.cc
@@ -414,6 +414,15 @@ TEST(StringUtilTest, IsStringUTF8) {
EXPECT_FALSE(IsStringUTF8("\xd9\xee\xe4\xee"));
// U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7
EXPECT_FALSE(IsStringUTF8("\xe3\xe5\xe9\xdC"));
+
+ // Check that we support Embedded Nulls. The first uses the canonical UTF-8
+ // representation, and the second uses a 2-byte sequence. The second version
+ // is invalid UTF-8 since UTF-8 states that the shortest encoding for a
+ // given codepoint must be used.
+ static const char kEmbeddedNull[] = "embedded\0null";
+ EXPECT_TRUE(IsStringUTF8(
+ std::string(kEmbeddedNull, sizeof(kEmbeddedNull))));
+ EXPECT_FALSE(IsStringUTF8("embedded\xc0\x80U+0000"));
}
TEST(StringUtilTest, ConvertASCII) {
@@ -530,8 +539,8 @@ TEST(StringUtilTest, FormatBytes) {
static const struct {
int64 bytes;
DataUnits units;
- const wchar_t* expected;
- const wchar_t* expected_with_units;
+ const char* expected;
+ const char* expected_with_units;
} cases[] = {
// Expected behavior: we show one post-decimal digit when we have
// under two pre-decimal digits, except in cases where it makes no
@@ -539,35 +548,35 @@ TEST(StringUtilTest, FormatBytes) {
// Since we switch units once we cross the 1000 mark, this keeps
// the display of file sizes or bytes consistently around three
// digits.
- {0, DATA_UNITS_BYTE, L"0", L"0 B"},
- {512, DATA_UNITS_BYTE, L"512", L"512 B"},
- {512, DATA_UNITS_KIBIBYTE, L"0.5", L"0.5 kB"},
- {1024*1024, DATA_UNITS_KIBIBYTE, L"1024", L"1024 kB"},
- {1024*1024, DATA_UNITS_MEBIBYTE, L"1.0", L"1.0 MB"},
- {1024*1024*1024, DATA_UNITS_GIBIBYTE, L"1.0", L"1.0 GB"},
- {10LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, L"10.0", L"10.0 GB"},
- {99LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, L"99.0", L"99.0 GB"},
- {105LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, L"105", L"105 GB"},
+ {0, DATA_UNITS_BYTE, "0", "0 B"},
+ {512, DATA_UNITS_BYTE, "512", "512 B"},
+ {512, DATA_UNITS_KIBIBYTE, "0.5", "0.5 kB"},
+ {1024*1024, DATA_UNITS_KIBIBYTE, "1024", "1024 kB"},
+ {1024*1024, DATA_UNITS_MEBIBYTE, "1.0", "1.0 MB"},
+ {1024*1024*1024, DATA_UNITS_GIBIBYTE, "1.0", "1.0 GB"},
+ {10LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "10.0", "10.0 GB"},
+ {99LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "99.0", "99.0 GB"},
+ {105LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "105", "105 GB"},
{105LL*1024*1024*1024 + 500LL*1024*1024, DATA_UNITS_GIBIBYTE,
- L"105", L"105 GB"},
- {~(1LL<<63), DATA_UNITS_GIBIBYTE, L"8589934592", L"8589934592 GB"},
+ "105", "105 GB"},
+ {~(1LL<<63), DATA_UNITS_GIBIBYTE, "8589934592", "8589934592 GB"},
- {99*1024 + 103, DATA_UNITS_KIBIBYTE, L"99.1", L"99.1 kB"},
- {1024*1024 + 103, DATA_UNITS_KIBIBYTE, L"1024", L"1024 kB"},
- {1024*1024 + 205 * 1024, DATA_UNITS_MEBIBYTE, L"1.2", L"1.2 MB"},
+ {99*1024 + 103, DATA_UNITS_KIBIBYTE, "99.1", "99.1 kB"},
+ {1024*1024 + 103, DATA_UNITS_KIBIBYTE, "1024", "1024 kB"},
+ {1024*1024 + 205 * 1024, DATA_UNITS_MEBIBYTE, "1.2", "1.2 MB"},
{1024*1024*1024 + (927 * 1024*1024), DATA_UNITS_GIBIBYTE,
- L"1.9", L"1.9 GB"},
- {10LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, L"10.0", L"10.0 GB"},
- {100LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, L"100", L"100 GB"},
+ "1.9", "1.9 GB"},
+ {10LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "10.0", "10.0 GB"},
+ {100LL*1024*1024*1024, DATA_UNITS_GIBIBYTE, "100", "100 GB"},
#ifdef NDEBUG
- {-1, DATA_UNITS_BYTE, L"", L""},
+ {-1, DATA_UNITS_BYTE, "", ""},
#endif
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(cases[i].expected,
+ EXPECT_EQ(ASCIIToUTF16(cases[i].expected),
FormatBytes(cases[i].bytes, cases[i].units, false));
- EXPECT_EQ(cases[i].expected_with_units,
+ EXPECT_EQ(ASCIIToUTF16(cases[i].expected_with_units),
FormatBytes(cases[i].bytes, cases[i].units, true));
}
}
@@ -633,363 +642,31 @@ TEST(StringUtilTest, ReplaceFirstSubstringAfterOffset) {
}
}
-namespace {
-
-template <typename INT>
-struct IntToStringTest {
- INT num;
- const char* sexpected;
- const char* uexpected;
-};
-
-} // namespace
-
-TEST(StringUtilTest, IntToString) {
- static const IntToStringTest<int> int_tests[] = {
- { 0, "0", "0" },
- { -1, "-1", "4294967295" },
- { std::numeric_limits<int>::max(), "2147483647", "2147483647" },
- { std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
- };
- static const IntToStringTest<int64> int64_tests[] = {
- { 0, "0", "0" },
- { -1, "-1", "18446744073709551615" },
- { std::numeric_limits<int64>::max(),
- "9223372036854775807",
- "9223372036854775807", },
- { std::numeric_limits<int64>::min(),
- "-9223372036854775808",
- "9223372036854775808" },
- };
-
- for (size_t i = 0; i < arraysize(int_tests); ++i) {
- const IntToStringTest<int>* test = &int_tests[i];
- EXPECT_EQ(IntToString(test->num), test->sexpected);
- EXPECT_EQ(IntToWString(test->num), UTF8ToWide(test->sexpected));
- EXPECT_EQ(UintToString(test->num), test->uexpected);
- EXPECT_EQ(UintToWString(test->num), UTF8ToWide(test->uexpected));
- }
- for (size_t i = 0; i < arraysize(int64_tests); ++i) {
- const IntToStringTest<int64>* test = &int64_tests[i];
- EXPECT_EQ(Int64ToString(test->num), test->sexpected);
- EXPECT_EQ(Int64ToWString(test->num), UTF8ToWide(test->sexpected));
- EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
- EXPECT_EQ(Uint64ToWString(test->num), UTF8ToWide(test->uexpected));
- }
-}
-
-TEST(StringUtilTest, Uint64ToString) {
- static const struct {
- uint64 input;
- std::string output;
- } cases[] = {
- {0, "0"},
- {42, "42"},
- {INT_MAX, "2147483647"},
- {kuint64max, "18446744073709551615"},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)
- EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
-}
-
-TEST(StringUtilTest, StringToInt) {
- static const struct {
- std::string input;
- int output;
- bool success;
- } cases[] = {
- {"0", 0, true},
- {"42", 42, true},
- {"-2147483648", INT_MIN, true},
- {"2147483647", INT_MAX, true},
- {"", 0, false},
- {" 42", 42, false},
- {"42 ", 42, false},
- {"\t\n\v\f\r 42", 42, false},
- {"blah42", 0, false},
- {"42blah", 42, false},
- {"blah42blah", 0, false},
- {"-273.15", -273, false},
- {"+98.6", 98, false},
- {"--123", 0, false},
- {"++123", 0, false},
- {"-+123", 0, false},
- {"+-123", 0, false},
- {"-", 0, false},
- {"-2147483649", INT_MIN, false},
- {"-99999999999", INT_MIN, false},
- {"2147483648", INT_MAX, false},
- {"99999999999", INT_MAX, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(cases[i].output, StringToInt(cases[i].input));
- int output;
- EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
- EXPECT_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].output, StringToInt(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, StringToInt(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_EQ(cases[i].output, output);
- }
-
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "6\06";
- std::string input_string(input, arraysize(input) - 1);
- int output;
- EXPECT_FALSE(StringToInt(input_string, &output));
- EXPECT_EQ(6, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(StringToInt(WideToUTF16Hack(wide_input), &output));
- EXPECT_EQ(6, output);
-}
-
-TEST(StringUtilTest, StringToInt64) {
- static const struct {
- std::string input;
- int64 output;
- bool success;
- } cases[] = {
- {"0", 0, true},
- {"42", 42, true},
- {"-2147483648", INT_MIN, true},
- {"2147483647", INT_MAX, true},
- {"-2147483649", GG_INT64_C(-2147483649), true},
- {"-99999999999", GG_INT64_C(-99999999999), true},
- {"2147483648", GG_INT64_C(2147483648), true},
- {"99999999999", GG_INT64_C(99999999999), true},
- {"9223372036854775807", kint64max, true},
- {"-9223372036854775808", kint64min, true},
- {"09", 9, true},
- {"-09", -9, true},
- {"", 0, false},
- {" 42", 42, false},
- {"42 ", 42, false},
- {"\t\n\v\f\r 42", 42, false},
- {"blah42", 0, false},
- {"42blah", 42, false},
- {"blah42blah", 0, false},
- {"-273.15", -273, false},
- {"+98.6", 98, false},
- {"--123", 0, false},
- {"++123", 0, false},
- {"-+123", 0, false},
- {"+-123", 0, false},
- {"-", 0, false},
- {"-9223372036854775809", kint64min, false},
- {"-99999999999999999999", kint64min, false},
- {"9223372036854775808", kint64max, false},
- {"99999999999999999999", kint64max, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(cases[i].output, StringToInt64(cases[i].input));
- int64 output;
- EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
- EXPECT_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].output, StringToInt64(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, StringToInt64(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_EQ(cases[i].output, output);
- }
-
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "6\06";
- std::string input_string(input, arraysize(input) - 1);
- int64 output;
- EXPECT_FALSE(StringToInt64(input_string, &output));
- EXPECT_EQ(6, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(StringToInt64(WideToUTF16Hack(wide_input), &output));
- EXPECT_EQ(6, output);
-}
-
-TEST(StringUtilTest, HexStringToInt) {
- static const struct {
- std::string input;
- int output;
- bool success;
- } cases[] = {
- {"0", 0, true},
- {"42", 66, true},
- {"-42", -66, true},
- {"+42", 66, true},
- {"7fffffff", INT_MAX, true},
- {"80000000", INT_MIN, true},
- {"ffffffff", -1, true},
- {"DeadBeef", 0xdeadbeef, true},
- {"0x42", 66, true},
- {"-0x42", -66, true},
- {"+0x42", 66, true},
- {"0x7fffffff", INT_MAX, true},
- {"0x80000000", INT_MIN, true},
- {"0xffffffff", -1, true},
- {"0XDeadBeef", 0xdeadbeef, true},
- {"0x0f", 15, true},
- {"0f", 15, true},
- {" 45", 0x45, false},
- {"\t\n\v\f\r 0x45", 0x45, false},
- {" 45", 0x45, false},
- {"45 ", 0x45, false},
- {"efgh", 0xef, false},
- {"0xefgh", 0xef, false},
- {"hgfe", 0, false},
- {"100000000", -1, false}, // don't care about |output|, just |success|
- {"-", 0, false},
- {"", 0, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_EQ(cases[i].output, HexStringToInt(cases[i].input));
- int output;
- EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output));
- EXPECT_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].output, HexStringToInt(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, HexStringToInt(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_EQ(cases[i].output, output);
- }
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "0xc0ffee\09";
- std::string input_string(input, arraysize(input) - 1);
- int output;
- EXPECT_FALSE(HexStringToInt(input_string, &output));
- EXPECT_EQ(0xc0ffee, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(HexStringToInt(WideToUTF16Hack(wide_input), &output));
- EXPECT_EQ(0xc0ffee, output);
-}
-
-TEST(StringUtilTest, HexStringToBytes) {
- static const struct {
- const std::string input;
- const char* output;
- size_t output_len;
- bool success;
- } cases[] = {
- {"0", "", 0, false}, // odd number of characters fails
- {"00", "\0", 1, true},
- {"42", "\x42", 1, true},
- {"-42", "", 0, false}, // any non-hex value fails
- {"+42", "", 0, false},
- {"7fffffff", "\x7f\xff\xff\xff", 4, true},
- {"80000000", "\x80\0\0\0", 4, true},
- {"deadbeef", "\xde\xad\xbe\xef", 4, true},
- {"DeadBeef", "\xde\xad\xbe\xef", 4, true},
- {"0x42", "", 0, false}, // leading 0x fails (x is not hex)
- {"0f", "\xf", 1, true},
- {"45 ", "\x45", 1, false},
- {"efgh", "\xef", 1, false},
- {"", "", 0, false},
- {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true},
- {"0123456789ABCDEF012345",
- "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true},
- };
-
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<uint8> output;
- std::vector<uint8> compare;
- EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
- i << ": " << cases[i].input;
- for (size_t j = 0; j < cases[i].output_len; ++j)
- compare.push_back(static_cast<uint8>(cases[i].output[j]));
- ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
- EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
- i << ": " << cases[i].input;
-
- output.clear();
- compare.clear();
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_EQ(cases[i].success,
- HexStringToBytes(WideToUTF16Hack(wide_input), &output)) <<
- i << ": " << cases[i].input;
- for (size_t j = 0; j < cases[i].output_len; ++j)
- compare.push_back(static_cast<uint8>(cases[i].output[j]));
- ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
- EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
- i << ": " << cases[i].input;
- }
-}
-
-TEST(StringUtilTest, StringToDouble) {
- static const struct {
- std::string input;
- double output;
- bool success;
- } cases[] = {
- {"0", 0.0, true},
- {"42", 42.0, true},
- {"-42", -42.0, true},
- {"123.45", 123.45, true},
- {"-123.45", -123.45, true},
- {"+123.45", 123.45, true},
- {"2.99792458e8", 299792458.0, true},
- {"149597870.691E+3", 149597870691.0, true},
- {"6.", 6.0, true},
- {"9e99999999999999999999", HUGE_VAL, false},
- {"-9e99999999999999999999", -HUGE_VAL, false},
- {"1e-2", 0.01, true},
- {" 1e-2", 0.01, false},
- {"1e-2 ", 0.01, false},
- {"-1E-7", -0.0000001, true},
- {"01e02", 100, true},
- {"2.3e15", 2.3e15, true},
- {"\t\n\v\f\r -123.45e2", -12345.0, false},
- {"+123 e4", 123.0, false},
- {"123e ", 123.0, false},
- {"123e", 123.0, false},
- {" 2.99", 2.99, false},
- {"1e3.4", 1000.0, false},
- {"nothing", 0.0, false},
- {"-", 0.0, false},
- {"+", 0.0, false},
- {"", 0.0, false},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- EXPECT_DOUBLE_EQ(cases[i].output, StringToDouble(cases[i].input));
- double output;
- EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
- EXPECT_DOUBLE_EQ(cases[i].output, output);
-
- std::wstring wide_input = ASCIIToWide(cases[i].input);
- EXPECT_DOUBLE_EQ(cases[i].output,
- StringToDouble(WideToUTF16Hack(wide_input)));
- EXPECT_EQ(cases[i].success, StringToDouble(WideToUTF16Hack(wide_input),
- &output));
- EXPECT_DOUBLE_EQ(cases[i].output, output);
- }
-
- // One additional test to verify that conversion of numbers in strings with
- // embedded NUL characters. The NUL and extra data after it should be
- // interpreted as junk after the number.
- const char input[] = "3.14\0159";
- std::string input_string(input, arraysize(input) - 1);
- double output;
- EXPECT_FALSE(StringToDouble(input_string, &output));
- EXPECT_DOUBLE_EQ(3.14, output);
-
- std::wstring wide_input = ASCIIToWide(input_string);
- EXPECT_FALSE(StringToDouble(WideToUTF16Hack(wide_input), &output));
- EXPECT_DOUBLE_EQ(3.14, output);
+TEST(StringUtilTest, HexDigitToInt) {
+ EXPECT_EQ(0, HexDigitToInt('0'));
+ EXPECT_EQ(1, HexDigitToInt('1'));
+ EXPECT_EQ(2, HexDigitToInt('2'));
+ EXPECT_EQ(3, HexDigitToInt('3'));
+ EXPECT_EQ(4, HexDigitToInt('4'));
+ EXPECT_EQ(5, HexDigitToInt('5'));
+ EXPECT_EQ(6, HexDigitToInt('6'));
+ EXPECT_EQ(7, HexDigitToInt('7'));
+ EXPECT_EQ(8, HexDigitToInt('8'));
+ EXPECT_EQ(9, HexDigitToInt('9'));
+ EXPECT_EQ(10, HexDigitToInt('A'));
+ EXPECT_EQ(11, HexDigitToInt('B'));
+ EXPECT_EQ(12, HexDigitToInt('C'));
+ EXPECT_EQ(13, HexDigitToInt('D'));
+ EXPECT_EQ(14, HexDigitToInt('E'));
+ EXPECT_EQ(15, HexDigitToInt('F'));
+
+ // Verify the lower case as well.
+ EXPECT_EQ(10, HexDigitToInt('a'));
+ EXPECT_EQ(11, HexDigitToInt('b'));
+ EXPECT_EQ(12, HexDigitToInt('c'));
+ EXPECT_EQ(13, HexDigitToInt('d'));
+ EXPECT_EQ(14, HexDigitToInt('e'));
+ EXPECT_EQ(15, HexDigitToInt('f'));
}
// This checks where we can use the assignment operator for a va_list. We need
@@ -1025,227 +702,6 @@ TEST(StringUtilTest, VAList) {
VariableArgsFunc("%d %d %s %lf", 45, 92, "This is interesting", 9.21);
}
-TEST(StringUtilTest, StringPrintfEmpty) {
- EXPECT_EQ("", StringPrintf("%s", ""));
-}
-
-TEST(StringUtilTest, StringPrintfMisc) {
- EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w'));
- EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w'));
-}
-
-TEST(StringUtilTest, StringAppendfEmptyString) {
- std::string value("Hello");
- StringAppendF(&value, "%s", "");
- EXPECT_EQ("Hello", value);
-
- std::wstring valuew(L"Hello");
- StringAppendF(&valuew, L"%ls", L"");
- EXPECT_EQ(L"Hello", valuew);
-}
-
-TEST(StringUtilTest, StringAppendfString) {
- std::string value("Hello");
- StringAppendF(&value, " %s", "World");
- EXPECT_EQ("Hello World", value);
-
- std::wstring valuew(L"Hello");
- StringAppendF(&valuew, L" %ls", L"World");
- EXPECT_EQ(L"Hello World", valuew);
-}
-
-TEST(StringUtilTest, StringAppendfInt) {
- std::string value("Hello");
- StringAppendF(&value, " %d", 123);
- EXPECT_EQ("Hello 123", value);
-
- std::wstring valuew(L"Hello");
- StringAppendF(&valuew, L" %d", 123);
- EXPECT_EQ(L"Hello 123", valuew);
-}
-
-// Make sure that lengths exactly around the initial buffer size are handled
-// correctly.
-TEST(StringUtilTest, StringPrintfBounds) {
- const int kSrcLen = 1026;
- char src[kSrcLen];
- for (size_t i = 0; i < arraysize(src); i++)
- src[i] = 'A';
-
- wchar_t srcw[kSrcLen];
- for (size_t i = 0; i < arraysize(srcw); i++)
- srcw[i] = 'A';
-
- for (int i = 1; i < 3; i++) {
- src[kSrcLen - i] = 0;
- std::string out;
- SStringPrintf(&out, "%s", src);
- EXPECT_STREQ(src, out.c_str());
-
- srcw[kSrcLen - i] = 0;
- std::wstring outw;
- SStringPrintf(&outw, L"%ls", srcw);
- EXPECT_STREQ(srcw, outw.c_str());
- }
-}
-
-// Test very large sprintfs that will cause the buffer to grow.
-TEST(StringUtilTest, Grow) {
- char src[1026];
- for (size_t i = 0; i < arraysize(src); i++)
- src[i] = 'A';
- src[1025] = 0;
-
- const char* fmt = "%sB%sB%sB%sB%sB%sB%s";
-
- std::string out;
- SStringPrintf(&out, fmt, src, src, src, src, src, src, src);
-
- const int kRefSize = 320000;
- char* ref = new char[kRefSize];
-#if defined(OS_WIN)
- sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src);
-#elif defined(OS_POSIX)
- snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src);
-#endif
-
- EXPECT_STREQ(ref, out.c_str());
- delete[] ref;
-}
-
-// A helper for the StringAppendV test that follows.
-// Just forwards its args to StringAppendV.
-static void StringAppendVTestHelper(std::string* out,
- const char* format,
- ...) PRINTF_FORMAT(2, 3);
-
-static void StringAppendVTestHelper(std::string* out, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- StringAppendV(out, format, ap);
- va_end(ap);
-}
-
-TEST(StringUtilTest, StringAppendV) {
- std::string out;
- StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
- EXPECT_EQ("1 foo bar", out);
-}
-
-// Test the boundary condition for the size of the string_util's
-// internal buffer.
-TEST(StringUtilTest, GrowBoundary) {
- const int string_util_buf_len = 1024;
- // Our buffer should be one larger than the size of StringAppendVT's stack
- // buffer.
- const int buf_len = string_util_buf_len + 1;
- char src[buf_len + 1]; // Need extra one for NULL-terminator.
- for (int i = 0; i < buf_len; ++i)
- src[i] = 'a';
- src[buf_len] = 0;
-
- std::string out;
- SStringPrintf(&out, "%s", src);
-
- EXPECT_STREQ(src, out.c_str());
-}
-
-// TODO(evanm): what's the proper cross-platform test here?
-#if defined(OS_WIN)
-// sprintf in Visual Studio fails when given U+FFFF. This tests that the
-// failure case is gracefuly handled.
-TEST(StringUtilTest, Invalid) {
- wchar_t invalid[2];
- invalid[0] = 0xffff;
- invalid[1] = 0;
-
- std::wstring out;
- SStringPrintf(&out, L"%ls", invalid);
- EXPECT_STREQ(L"", out.c_str());
-}
-#endif
-
-// Test for SplitString
-TEST(StringUtilTest, SplitString) {
- std::vector<std::wstring> r;
-
- SplitString(L"", L',', &r);
- ASSERT_EQ(1U, r.size());
- EXPECT_EQ(r[0], L"");
- r.clear();
-
- SplitString(L"a,b,c", L',', &r);
- ASSERT_EQ(3U, r.size());
- EXPECT_EQ(r[0], L"a");
- EXPECT_EQ(r[1], L"b");
- EXPECT_EQ(r[2], L"c");
- r.clear();
-
- SplitString(L"a, b, c", L',', &r);
- ASSERT_EQ(3U, r.size());
- EXPECT_EQ(r[0], L"a");
- EXPECT_EQ(r[1], L"b");
- EXPECT_EQ(r[2], L"c");
- r.clear();
-
- SplitString(L"a,,c", L',', &r);
- ASSERT_EQ(3U, r.size());
- EXPECT_EQ(r[0], L"a");
- EXPECT_EQ(r[1], L"");
- EXPECT_EQ(r[2], L"c");
- r.clear();
-
- SplitString(L"", L'*', &r);
- ASSERT_EQ(1U, r.size());
- EXPECT_EQ(r[0], L"");
- r.clear();
-
- SplitString(L"foo", L'*', &r);
- ASSERT_EQ(1U, r.size());
- EXPECT_EQ(r[0], L"foo");
- r.clear();
-
- SplitString(L"foo ,", L',', &r);
- ASSERT_EQ(2U, r.size());
- EXPECT_EQ(r[0], L"foo");
- EXPECT_EQ(r[1], L"");
- r.clear();
-
- SplitString(L",", L',', &r);
- ASSERT_EQ(2U, r.size());
- EXPECT_EQ(r[0], L"");
- EXPECT_EQ(r[1], L"");
- r.clear();
-
- SplitString(L"\t\ta\t", L'\t', &r);
- ASSERT_EQ(4U, r.size());
- EXPECT_EQ(r[0], L"");
- EXPECT_EQ(r[1], L"");
- EXPECT_EQ(r[2], L"a");
- EXPECT_EQ(r[3], L"");
- r.clear();
-
- SplitStringDontTrim(L"\t\ta\t", L'\t', &r);
- ASSERT_EQ(4U, r.size());
- EXPECT_EQ(r[0], L"");
- EXPECT_EQ(r[1], L"");
- EXPECT_EQ(r[2], L"a");
- EXPECT_EQ(r[3], L"");
- r.clear();
-
- SplitString(L"\ta\t\nb\tcc", L'\n', &r);
- ASSERT_EQ(2U, r.size());
- EXPECT_EQ(r[0], L"a");
- EXPECT_EQ(r[1], L"b\tcc");
- r.clear();
-
- SplitStringDontTrim(L"\ta\t\nb\tcc", L'\n', &r);
- ASSERT_EQ(2U, r.size());
- EXPECT_EQ(r[0], L"\ta\t");
- EXPECT_EQ(r[1], L"b\tcc");
- r.clear();
-}
-
// Test for Tokenize
template <typename STR>
void TokenizeTest() {
@@ -1485,6 +941,15 @@ TEST(StringUtilTest, StdStringReplaceStringPlaceholders) {
EXPECT_EQ(formatted, "9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii");
}
+TEST(StringUtilTest, ReplaceStringPlaceholdersConsecutiveDollarSigns) {
+ std::vector<std::string> subst;
+ subst.push_back("a");
+ subst.push_back("b");
+ subst.push_back("c");
+ EXPECT_EQ(ReplaceStringPlaceholders("$$1 $$$2 $$$$3", subst, NULL),
+ "$1 $$2 $$$3");
+}
+
TEST(StringUtilTest, SplitStringAlongWhitespace) {
struct TestData {
const std::wstring input;
@@ -1518,22 +983,36 @@ TEST(StringUtilTest, SplitStringAlongWhitespace) {
}
TEST(StringUtilTest, MatchPatternTest) {
- EXPECT_EQ(MatchPatternASCII("www.google.com", "*.com"), true);
- EXPECT_EQ(MatchPatternASCII("www.google.com", "*"), true);
- EXPECT_EQ(MatchPatternASCII("www.google.com", "www*.g*.org"), false);
- EXPECT_EQ(MatchPatternASCII("Hello", "H?l?o"), true);
- EXPECT_EQ(MatchPatternASCII("www.google.com", "http://*)"), false);
- EXPECT_EQ(MatchPatternASCII("www.msn.com", "*.COM"), false);
- EXPECT_EQ(MatchPatternASCII("Hello*1234", "He??o\\*1*"), true);
- EXPECT_EQ(MatchPatternASCII("", "*.*"), false);
- EXPECT_EQ(MatchPatternASCII("", "*"), true);
- EXPECT_EQ(MatchPatternASCII("", "?"), true);
- EXPECT_EQ(MatchPatternASCII("", ""), true);
- EXPECT_EQ(MatchPatternASCII("Hello", ""), false);
- EXPECT_EQ(MatchPatternASCII("Hello*", "Hello*"), true);
+ EXPECT_TRUE(MatchPattern("www.google.com", "*.com"));
+ EXPECT_TRUE(MatchPattern("www.google.com", "*"));
+ EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org"));
+ EXPECT_TRUE(MatchPattern("Hello", "H?l?o"));
+ EXPECT_FALSE(MatchPattern("www.google.com", "http://*)"));
+ EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM"));
+ EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*"));
+ EXPECT_FALSE(MatchPattern("", "*.*"));
+ EXPECT_TRUE(MatchPattern("", "*"));
+ EXPECT_TRUE(MatchPattern("", "?"));
+ EXPECT_TRUE(MatchPattern("", ""));
+ EXPECT_FALSE(MatchPattern("Hello", ""));
+ EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
// Stop after a certain recursion depth.
- EXPECT_EQ(MatchPatternASCII("12345678901234567890", "???????????????????*"),
- false);
+ EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
+
+ // Test UTF8 matching.
+ EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
+ EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?."));
+ EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*"));
+ // Invalid sequences should be handled as a single invalid character.
+ EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?"));
+ // If the pattern has invalid characters, it shouldn't match anything.
+ EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80"));
+
+ // Test UTF16 character matching.
+ EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"),
+ UTF8ToUTF16("*.com")));
+ EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"),
+ UTF8ToUTF16("He??o\\*1*")));
}
TEST(StringUtilTest, LcpyTest) {
@@ -1655,14 +1134,6 @@ TEST(StringUtilTest, ElideString) {
}
}
-TEST(StringUtilTest, HexEncode) {
- std::string hex(HexEncode(NULL, 0));
- EXPECT_EQ(hex.length(), 0U);
- unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
- hex = HexEncode(bytes, sizeof(bytes));
- EXPECT_EQ(hex.compare("01FF02FE038081"), 0);
-}
-
TEST(StringUtilTest, RemoveChars) {
const char* kRemoveChars = "-/+*";
std::string input = "A-+bc/d!*";
@@ -1692,49 +1163,4 @@ TEST(StringUtilTest, ContainsOnlyChars) {
EXPECT_FALSE(ContainsOnlyChars("123a", "4321"));
}
-TEST(SplitStringUsingSubstrTest, EmptyString) {
- std::vector<std::string> results;
- SplitStringUsingSubstr("", "DELIMITER", &results);
- ASSERT_EQ(1u, results.size());
- EXPECT_THAT(results, ElementsAre(""));
-}
-
-TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) {
- std::vector<std::string> results;
- SplitStringUsingSubstr("alongwordwithnodelimiter", "DELIMITER", &results);
- ASSERT_EQ(1u, results.size());
- EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
-}
-
-TEST(SplitStringUsingSubstrTest, LeadingDelimitersSkipped) {
- std::vector<std::string> results;
- SplitStringUsingSubstr(
- "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree",
- "DELIMITER",
- &results);
- ASSERT_EQ(6u, results.size());
- EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
-}
-
-TEST(SplitStringUsingSubstrTest, ConsecutiveDelimitersSkipped) {
- std::vector<std::string> results;
- SplitStringUsingSubstr(
- "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
- "DELIMITER",
- &results);
- ASSERT_EQ(7u, results.size());
- EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
-}
-
-TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) {
- std::vector<std::string> results;
- SplitStringUsingSubstr(
- "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
- "DELIMITER",
- &results);
- ASSERT_EQ(7u, results.size());
- EXPECT_THAT(
- results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
-}
-
} // namespace base
diff --git a/base/string_util_win.h b/base/string_util_win.h
index 124238c..8836f74 100644
--- a/base/string_util_win.h
+++ b/base/string_util_win.h
@@ -4,6 +4,7 @@
#ifndef BASE_STRING_UTIL_WIN_H_
#define BASE_STRING_UTIL_WIN_H_
+#pragma once
#include <stdarg.h>
#include <stdio.h>
diff --git a/base/stringprintf.cc b/base/stringprintf.cc
new file mode 100644
index 0000000..5607d39
--- /dev/null
+++ b/base/stringprintf.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 "base/stringprintf.h"
+
+#include <errno.h>
+
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
+// is the size of the buffer. These return the number of characters in the
+// formatted string excluding the NUL terminator. If the buffer is not
+// large enough to accommodate the formatted string without truncation, they
+// return the number of characters that would be in the fully-formatted string
+// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
+inline int vsnprintfT(char* buffer,
+ size_t buf_size,
+ const char* format,
+ va_list argptr) {
+ return base::vsnprintf(buffer, buf_size, format, argptr);
+}
+
+inline int vsnprintfT(wchar_t* buffer,
+ size_t buf_size,
+ const wchar_t* format,
+ va_list argptr) {
+ return base::vswprintf(buffer, buf_size, format, argptr);
+}
+
+// Templatized backend for StringPrintF/StringAppendF. This does not finalize
+// the va_list, the caller is expected to do that.
+template <class StringType>
+static void StringAppendVT(StringType* dst,
+ const typename StringType::value_type* format,
+ va_list ap) {
+ // First try with a small fixed size buffer.
+ // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
+ // and StringUtilTest.StringPrintfBounds.
+ typename StringType::value_type stack_buf[1024];
+
+ va_list ap_copy;
+ GG_VA_COPY(ap_copy, ap);
+
+#if !defined(OS_WIN)
+ errno = 0;
+#endif
+ int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
+ va_end(ap_copy);
+
+ if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
+ // It fit.
+ dst->append(stack_buf, result);
+ return;
+ }
+
+ // Repeatedly increase buffer size until it fits.
+ int mem_length = arraysize(stack_buf);
+ while (true) {
+ if (result < 0) {
+#if !defined(OS_WIN)
+ // On Windows, vsnprintfT always returns the number of characters in a
+ // fully-formatted string, so if we reach this point, something else is
+ // wrong and no amount of buffer-doubling is going to fix it.
+ if (errno != 0 && errno != EOVERFLOW)
+#endif
+ {
+ // If an error other than overflow occurred, it's never going to work.
+ DLOG(WARNING) << "Unable to printf the requested string due to error.";
+ return;
+ }
+ // Try doubling the buffer size.
+ mem_length *= 2;
+ } else {
+ // We need exactly "result + 1" characters.
+ mem_length = result + 1;
+ }
+
+ if (mem_length > 32 * 1024 * 1024) {
+ // That should be plenty, don't try anything larger. This protects
+ // against huge allocations when using vsnprintfT implementations that
+ // return -1 for reasons other than overflow without setting errno.
+ DLOG(WARNING) << "Unable to printf the requested string due to size.";
+ return;
+ }
+
+ std::vector<typename StringType::value_type> mem_buf(mem_length);
+
+ // NOTE: You can only use a va_list once. Since we're in a while loop, we
+ // need to make a new copy each time so we don't use up the original.
+ GG_VA_COPY(ap_copy, ap);
+ result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
+ va_end(ap_copy);
+
+ if ((result >= 0) && (result < mem_length)) {
+ // It fit.
+ dst->append(&mem_buf[0], result);
+ return;
+ }
+ }
+}
+
+} // namespace
+
+std::string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+std::wstring StringPrintf(const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::wstring result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+std::string StringPrintV(const char* format, va_list ap) {
+ std::string result;
+ StringAppendV(&result, format, ap);
+ return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+const std::wstring& SStringPrintf(std::wstring* dst,
+ const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+ StringAppendVT(dst, format, ap);
+}
+
+void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
+ StringAppendVT(dst, format, ap);
+}
+
+} // namespace base
diff --git a/base/stringprintf.h b/base/stringprintf.h
new file mode 100644
index 0000000..43d60d4
--- /dev/null
+++ b/base/stringprintf.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 BASE_STRINGPRINTF_H_
+#define BASE_STRINGPRINTF_H_
+
+#include <stdarg.h> // va_list
+
+#include <string>
+
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// Return a C++ string given printf-like input.
+std::string StringPrintf(const char* format, ...) PRINTF_FORMAT(1, 2);
+std::wstring StringPrintf(const wchar_t* format, ...) WPRINTF_FORMAT(1, 2);
+
+// Return a C++ string given vprintf-like input.
+std::string StringPrintV(const char* format, va_list ap) PRINTF_FORMAT(1, 0);
+
+// Store result into a supplied string and return it.
+const std::string& SStringPrintf(std::string* dst, const char* format, ...)
+ PRINTF_FORMAT(2, 3);
+const std::wstring& SStringPrintf(std::wstring* dst,
+ const wchar_t* format, ...)
+ WPRINTF_FORMAT(2, 3);
+
+// Append result to a supplied string.
+void StringAppendF(std::string* dst, const char* format, ...)
+ PRINTF_FORMAT(2, 3);
+void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
+ WPRINTF_FORMAT(2, 3);
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string. All other routines are just convenience wrappers around it.
+void StringAppendV(std::string* dst, const char* format, va_list ap)
+ PRINTF_FORMAT(2, 0);
+void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap)
+ WPRINTF_FORMAT(2, 0);
+
+} // namespace base
+
+// Don't require the namespace for legacy code. New code should use "base::" or
+// have its own using decl.
+//
+// TODO(brettw) remove these when calling code is converted.
+using base::StringPrintf;
+using base::StringPrintV;
+using base::SStringPrintf;
+using base::StringAppendV;
+using base::StringAppendF;
+using base::StringAppendV;
+
+#endif // BASE_STRINGPRINTF_H_
diff --git a/base/stringprintf_unittest.cc b/base/stringprintf_unittest.cc
new file mode 100644
index 0000000..ffb9c77
--- /dev/null
+++ b/base/stringprintf_unittest.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 "base/basictypes.h"
+#include "base/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// A helper for the StringAppendV test that follows.
+//
+// Just forwards its args to StringAppendV.
+static void StringAppendVTestHelper(std::string* out, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(out, format, ap);
+ va_end(ap);
+}
+
+} // namespace
+
+TEST(StringPrintfTest, StringPrintfEmpty) {
+ EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringPrintfTest, StringPrintfMisc) {
+ EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w'));
+ EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w'));
+}
+
+TEST(StringPrintfTest, StringAppendfEmptyString) {
+ std::string value("Hello");
+ StringAppendF(&value, "%s", "");
+ EXPECT_EQ("Hello", value);
+
+ std::wstring valuew(L"Hello");
+ StringAppendF(&valuew, L"%ls", L"");
+ EXPECT_EQ(L"Hello", valuew);
+}
+
+TEST(StringPrintfTest, StringAppendfString) {
+ std::string value("Hello");
+ StringAppendF(&value, " %s", "World");
+ EXPECT_EQ("Hello World", value);
+
+ std::wstring valuew(L"Hello");
+ StringAppendF(&valuew, L" %ls", L"World");
+ EXPECT_EQ(L"Hello World", valuew);
+}
+
+TEST(StringPrintfTest, StringAppendfInt) {
+ std::string value("Hello");
+ StringAppendF(&value, " %d", 123);
+ EXPECT_EQ("Hello 123", value);
+
+ std::wstring valuew(L"Hello");
+ StringAppendF(&valuew, L" %d", 123);
+ EXPECT_EQ(L"Hello 123", valuew);
+}
+
+// Make sure that lengths exactly around the initial buffer size are handled
+// correctly.
+TEST(StringPrintfTest, StringPrintfBounds) {
+ const int kSrcLen = 1026;
+ char src[kSrcLen];
+ for (size_t i = 0; i < arraysize(src); i++)
+ src[i] = 'A';
+
+ wchar_t srcw[kSrcLen];
+ for (size_t i = 0; i < arraysize(srcw); i++)
+ srcw[i] = 'A';
+
+ for (int i = 1; i < 3; i++) {
+ src[kSrcLen - i] = 0;
+ std::string out;
+ SStringPrintf(&out, "%s", src);
+ EXPECT_STREQ(src, out.c_str());
+
+ srcw[kSrcLen - i] = 0;
+ std::wstring outw;
+ SStringPrintf(&outw, L"%ls", srcw);
+ EXPECT_STREQ(srcw, outw.c_str());
+ }
+}
+
+// Test very large sprintfs that will cause the buffer to grow.
+TEST(StringPrintfTest, Grow) {
+ char src[1026];
+ for (size_t i = 0; i < arraysize(src); i++)
+ src[i] = 'A';
+ src[1025] = 0;
+
+ const char* fmt = "%sB%sB%sB%sB%sB%sB%s";
+
+ std::string out;
+ SStringPrintf(&out, fmt, src, src, src, src, src, src, src);
+
+ const int kRefSize = 320000;
+ char* ref = new char[kRefSize];
+#if defined(OS_WIN)
+ sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src);
+#elif defined(OS_POSIX)
+ snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src);
+#endif
+
+ EXPECT_STREQ(ref, out.c_str());
+ delete[] ref;
+}
+
+TEST(StringPrintfTest, StringAppendV) {
+ std::string out;
+ StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
+ EXPECT_EQ("1 foo bar", out);
+}
+
+// Test the boundary condition for the size of the string_util's
+// internal buffer.
+TEST(StringPrintfTest, GrowBoundary) {
+ const int string_util_buf_len = 1024;
+ // Our buffer should be one larger than the size of StringAppendVT's stack
+ // buffer.
+ const int buf_len = string_util_buf_len + 1;
+ char src[buf_len + 1]; // Need extra one for NULL-terminator.
+ for (int i = 0; i < buf_len; ++i)
+ src[i] = 'a';
+ src[buf_len] = 0;
+
+ std::string out;
+ SStringPrintf(&out, "%s", src);
+
+ EXPECT_STREQ(src, out.c_str());
+}
+
+// TODO(evanm): what's the proper cross-platform test here?
+#if defined(OS_WIN)
+// sprintf in Visual Studio fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled.
+TEST(StringPrintfTest, Invalid) {
+ wchar_t invalid[2];
+ invalid[0] = 0xffff;
+ invalid[1] = 0;
+
+ std::wstring out;
+ SStringPrintf(&out, L"%ls", invalid);
+ EXPECT_STREQ(L"", out.c_str());
+}
+#endif
+
+} // namespace base
diff --git a/base/symbolize.target.mk b/base/symbolize.target.mk
index b4bf650..affac99 100644
--- a/base/symbolize.target.mk
+++ b/base/symbolize.target.mk
@@ -16,6 +16,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-Wno-sign-compare \
-O0 \
@@ -46,6 +47,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-Wno-sign-compare \
-O2 \
@@ -91,11 +93,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/sync_socket.h b/base/sync_socket.h
index a44c445..1408b47 100644
--- a/base/sync_socket.h
+++ b/base/sync_socket.h
@@ -4,6 +4,7 @@
#ifndef BASE_SYNC_SOCKET_H_
#define BASE_SYNC_SOCKET_H_
+#pragma once
// A socket abstraction used for sending and receiving plain
// data. Because they are blocking, they can be used to perform
diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc
index d4a302e..c2020c2 100644
--- a/base/sync_socket_posix.cc
+++ b/base/sync_socket_posix.cc
@@ -11,7 +11,6 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include "base/atomicops.h"
#include "base/file_util.h"
#include "base/logging.h"
diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc
index 4e3c35f..1e4fb2f 100644
--- a/base/sync_socket_win.cc
+++ b/base/sync_socket_win.cc
@@ -7,7 +7,6 @@
#include <stdio.h>
#include <windows.h>
#include <sys/types.h>
-#include "base/atomicops.h"
#include "base/logging.h"
diff --git a/base/sys_info.h b/base/sys_info.h
index 1bb4eca..adfb250 100644
--- a/base/sys_info.h
+++ b/base/sys_info.h
@@ -4,6 +4,7 @@
#ifndef BASE_SYS_INFO_H_
#define BASE_SYS_INFO_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
index af204df..1cd9fb6 100644
--- a/base/sys_info_chromeos.cc
+++ b/base/sys_info_chromeos.cc
@@ -7,8 +7,8 @@
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
-#include "base/string_util.h"
namespace base {
@@ -54,12 +54,12 @@ void SysInfo::ParseLsbRelease(const std::string& lsb_release,
StringTokenizer tokenizer(version, ".");
for (int i = 0; i < 3 && tokenizer.GetNext(); i++) {
if (0 == i) {
- *major_version = StringToInt(tokenizer.token());
+ StringToInt(tokenizer.token(), major_version);
*minor_version = *bugfix_version = 0;
} else if (1 == i) {
- *minor_version = StringToInt(tokenizer.token());
+ StringToInt(tokenizer.token(), minor_version);
} else { // 2 == i
- *bugfix_version = StringToInt(tokenizer.token());
+ StringToInt(tokenizer.token(), bugfix_version);
}
}
}
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
index ed4d2fb..fa3ab43 100644
--- a/base/sys_info_win.cc
+++ b/base/sys_info_win.cc
@@ -9,7 +9,7 @@
#include "base/file_path.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
namespace base {
@@ -58,7 +58,8 @@ std::string SysInfo::OperatingSystemVersion() {
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&info);
- return StringPrintf("%lu.%lu", info.dwMajorVersion, info.dwMinorVersion);
+ return base::StringPrintf("%lu.%lu",
+ info.dwMajorVersion, info.dwMinorVersion);
}
// TODO: Implement OperatingSystemVersionComplete, which would include
diff --git a/base/sys_string_conversions.h b/base/sys_string_conversions.h
index edf4dd2..a96a687 100644
--- a/base/sys_string_conversions.h
+++ b/base/sys_string_conversions.h
@@ -4,6 +4,7 @@
#ifndef BASE_SYS_STRING_CONVERSIONS_H_
#define BASE_SYS_STRING_CONVERSIONS_H_
+#pragma once
// Provides system-dependent string type conversions for cases where it's
// necessary to not use ICU. Generally, you should not need this in Chrome,
diff --git a/base/task.h b/base/task.h
index 0cff589..e6ac33c 100644
--- a/base/task.h
+++ b/base/task.h
@@ -4,6 +4,7 @@
#ifndef BASE_TASK_H_
#define BASE_TASK_H_
+#pragma once
#include "base/non_thread_safe.h"
#include "base/raw_scoped_refptr_mismatch_checker.h"
@@ -106,30 +107,30 @@ class ScopedRunnableMethodFactory {
template <class Method, class A, class B, class C>
inline CancelableTask* NewRunnableMethod(Method method,
- const A& a,
- const B& b,
- const C& c) {
+ const A& a,
+ const B& b,
+ const C& c) {
return new RunnableMethod<Method, Tuple3<A, B, C> >(
weak_factory_.GetWeakPtr(), method, MakeTuple(a, b, c));
}
template <class Method, class A, class B, class C, class D>
inline CancelableTask* NewRunnableMethod(Method method,
- const A& a,
- const B& b,
- const C& c,
- const D& d) {
+ const A& a,
+ const B& b,
+ const C& c,
+ const D& d) {
return new RunnableMethod<Method, Tuple4<A, B, C, D> >(
weak_factory_.GetWeakPtr(), method, MakeTuple(a, b, c, d));
}
template <class Method, class A, class B, class C, class D, class E>
inline CancelableTask* NewRunnableMethod(Method method,
- const A& a,
- const B& b,
- const C& c,
- const D& d,
- const E& e) {
+ const A& a,
+ const B& b,
+ const C& c,
+ const D& d,
+ const E& e) {
return new RunnableMethod<Method, Tuple5<A, B, C, D, E> >(
weak_factory_.GetWeakPtr(), method, MakeTuple(a, b, c, d, e));
}
@@ -142,7 +143,8 @@ class ScopedRunnableMethodFactory {
template <class Method, class Params>
class RunnableMethod : public CancelableTask {
public:
- RunnableMethod(const base::WeakPtr<T>& obj, Method meth,
+ RunnableMethod(const base::WeakPtr<T>& obj,
+ Method meth,
const Params& params)
: obj_(obj),
meth_(meth),
@@ -186,6 +188,7 @@ class DeleteTask : public CancelableTask {
virtual void Cancel() {
obj_ = NULL;
}
+
private:
T* obj_;
};
@@ -203,6 +206,7 @@ class ReleaseTask : public CancelableTask {
virtual void Cancel() {
obj_ = NULL;
}
+
private:
T* obj_;
};
@@ -295,7 +299,7 @@ struct RunnableMethodTraits {
// want to call
// Param - the parameter(s) to the method, possibly packed as a Tuple
// A - the first parameter (if any) to the method
-// B - the second parameter (if any) to the mathod
+// B - the second parameter (if any) to the method
//
// Put these all together and you get an object that can call a method whose
// signature is:
diff --git a/chrome/common/task_queue.cc b/base/task_queue.cc
index 0d5aabb..e3c196b 100644
--- a/chrome/common/task_queue.cc
+++ b/base/task_queue.cc
@@ -1,9 +1,10 @@
-// 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/common/task_queue.h"
+#include "base/task_queue.h"
+#include "base/logging.h"
#include "base/stl_util-inl.h"
TaskQueue::TaskQueue() {
@@ -32,6 +33,8 @@ void TaskQueue::Run() {
}
void TaskQueue::Push(Task* task) {
+ DCHECK(task);
+
// Add the task to the back of the queue.
queue_.push_back(task);
}
@@ -41,6 +44,6 @@ void TaskQueue::Clear() {
STLDeleteElements(&queue_);
}
-bool TaskQueue::Empty() const {
+bool TaskQueue::IsEmpty() const {
return queue_.empty();
}
diff --git a/chrome/common/task_queue.h b/base/task_queue.h
index 9e1c817..5bfc777 100644
--- a/chrome/common/task_queue.h
+++ b/base/task_queue.h
@@ -1,9 +1,10 @@
-// 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.
-#ifndef CHROME_COMMON_TASK_QUEUE_H__
-#define CHROME_COMMON_TASK_QUEUE_H__
+#ifndef BASE_TASK_QUEUE_H_
+#define BASE_TASK_QUEUE_H_
+#pragma once
#include <deque>
@@ -32,11 +33,11 @@ class TaskQueue : public Task {
void Clear();
// Returns true if this queue contains no tasks.
- bool Empty() const;
+ bool IsEmpty() const;
private:
// The list of tasks we are waiting to run.
std::deque<Task*> queue_;
};
-#endif // CHROME_COMMON_TASK_QUEUE_H__
+#endif // BASE_TASK_QUEUE_H_
diff --git a/base/task_queue_unittest.cc b/base/task_queue_unittest.cc
new file mode 100644
index 0000000..90fc4cd
--- /dev/null
+++ b/base/task_queue_unittest.cc
@@ -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.
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "base/task_queue.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Sets bools according to whether Run or the destructor were called.
+class TrackCallsTask : public Task {
+ public:
+ TrackCallsTask(bool* ran, bool* deleted)
+ : ran_(ran),
+ deleted_(deleted) {
+ *ran_ = false;
+ *deleted_ = false;
+ }
+
+ virtual ~TrackCallsTask() {
+ *deleted_ = true;
+ }
+
+ virtual void Run() {
+ *ran_ = true;
+ }
+
+ private:
+ bool* ran_;
+ bool* deleted_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackCallsTask);
+};
+
+// Adds a given task to the queue when run.
+class TaskQueuerTask : public Task {
+ public:
+ TaskQueuerTask(TaskQueue* queue, Task* task_to_queue)
+ : queue_(queue),
+ task_to_queue_(task_to_queue) {
+ }
+
+ virtual void Run() {
+ queue_->Push(task_to_queue_);
+ }
+
+ private:
+ TaskQueue* queue_;
+ Task* task_to_queue_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskQueuerTask);
+};
+
+} // namespace
+
+TEST(TaskQueueTest, RunNoTasks) {
+ TaskQueue queue;
+ EXPECT_TRUE(queue.IsEmpty());
+
+ queue.Run();
+ EXPECT_TRUE(queue.IsEmpty());
+}
+
+TEST(TaskQueueTest, RunTasks) {
+ TaskQueue queue;
+
+ bool ran_task1 = false;
+ bool deleted_task1 = false;
+ queue.Push(new TrackCallsTask(&ran_task1, &deleted_task1));
+
+ bool ran_task2 = false;
+ bool deleted_task2 = false;
+ queue.Push(new TrackCallsTask(&ran_task2, &deleted_task2));
+
+ queue.Run();
+
+ EXPECT_TRUE(ran_task1);
+ EXPECT_TRUE(deleted_task1);
+ EXPECT_TRUE(ran_task2);
+ EXPECT_TRUE(deleted_task2);
+ EXPECT_TRUE(queue.IsEmpty());
+}
+
+TEST(TaskQueueTest, ClearTasks) {
+ TaskQueue queue;
+
+ bool ran_task1 = false;
+ bool deleted_task1 = false;
+ queue.Push(new TrackCallsTask(&ran_task1, &deleted_task1));
+
+ bool ran_task2 = false;
+ bool deleted_task2 = false;
+ queue.Push(new TrackCallsTask(&ran_task2, &deleted_task2));
+
+ queue.Clear();
+
+ EXPECT_TRUE(queue.IsEmpty());
+
+ queue.Run();
+
+ EXPECT_FALSE(ran_task1);
+ EXPECT_TRUE(deleted_task1);
+ EXPECT_FALSE(ran_task2);
+ EXPECT_TRUE(deleted_task2);
+ EXPECT_TRUE(queue.IsEmpty());
+}
+
+TEST(TaskQueueTest, OneTaskQueuesMore) {
+ TaskQueue main_queue;
+
+ // Build a task which will queue two more when run.
+ scoped_ptr<TaskQueue> nested_queue(new TaskQueue());
+ bool ran_task1 = false;
+ bool deleted_task1 = false;
+ nested_queue->Push(
+ new TaskQueuerTask(&main_queue,
+ new TrackCallsTask(&ran_task1, &deleted_task1)));
+ bool ran_task2 = false;
+ bool deleted_task2 = false;
+ nested_queue->Push(
+ new TaskQueuerTask(&main_queue,
+ new TrackCallsTask(&ran_task2, &deleted_task2)));
+
+ main_queue.Push(nested_queue.release());
+
+ // Run the task which pushes two more tasks.
+ main_queue.Run();
+
+ // None of the pushed tasks shoudl have run yet.
+ EXPECT_FALSE(ran_task1);
+ EXPECT_FALSE(deleted_task1);
+ EXPECT_FALSE(ran_task2);
+ EXPECT_FALSE(deleted_task2);
+ EXPECT_FALSE(main_queue.IsEmpty());
+
+ // Now run the nested tasks.
+ main_queue.Run();
+
+ EXPECT_TRUE(ran_task1);
+ EXPECT_TRUE(deleted_task1);
+ EXPECT_TRUE(ran_task2);
+ EXPECT_TRUE(deleted_task2);
+ EXPECT_TRUE(main_queue.IsEmpty());
+}
diff --git a/base/template_util.h b/base/template_util.h
index 69702f3..2cfe04c 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_TEMPLATE_UTIL_H_
#define BASE_TEMPLATE_UTIL_H_
+#pragma once
namespace base {
@@ -26,4 +27,4 @@ template <class T> struct is_pointer<T*> : true_type {};
} // namespace base
-#endif
+#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/base/test/perf_test_suite.h b/base/test/perf_test_suite.h
index 896659b..37abea6 100644
--- a/base/test/perf_test_suite.h
+++ b/base/test/perf_test_suite.h
@@ -4,14 +4,17 @@
#ifndef BASE_TEST_PERF_TEST_SUITE_H_
#define BASE_TEST_PERF_TEST_SUITE_H_
+#pragma once
#include "base/command_line.h"
#include "base/debug_util.h"
#include "base/file_path.h"
+#include "base/path_service.h"
#include "base/perftimer.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "base/test/test_suite.h"
+#include "testing/gtest/include/gtest/gtest.h"
class PerfTestSuite : public TestSuite {
public:
@@ -22,16 +25,13 @@ class PerfTestSuite : public TestSuite {
TestSuite::Initialize();
// Initialize the perf timer log
- FilePath log_path;
- std::wstring log_file =
- CommandLine::ForCurrentProcess()->GetSwitchValue("log-file");
- if (log_file.empty()) {
+ FilePath log_path =
+ CommandLine::ForCurrentProcess()->GetSwitchValuePath("log-file");
+ if (log_path.empty()) {
FilePath exe;
PathService::Get(base::FILE_EXE, &exe);
log_path = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
log_path = log_path.InsertBeforeExtension(FILE_PATH_LITERAL("_perf"));
- } else {
- log_path = FilePath::FromWStringHack(log_file);
}
ASSERT_TRUE(InitPerfLog(log_path));
diff --git a/base/test/run_all_unittests.cc b/base/test/run_all_unittests.cc
index 7b90358..8bfeb3b 100644
--- a/base/test/run_all_unittests.cc
+++ b/base/test/run_all_unittests.cc
@@ -5,7 +5,5 @@
#include "base/test/test_suite.h"
int main(int argc, char** argv) {
- TestSuite test_suite(argc, argv);
- test_suite.EnforceTestIsolation();
- return test_suite.Run();
+ return base::TestSuite(argc, argv).Run();
}
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
index fc1c4d5..362c525 100644
--- a/base/test/test_file_util.h
+++ b/base/test/test_file_util.h
@@ -1,14 +1,13 @@
-// 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.
#ifndef BASE_TEST_TEST_FILE_UTIL_H_
#define BASE_TEST_TEST_FILE_UTIL_H_
+#pragma once
// File utility functions used only by tests.
-#include <string>
-
class FilePath;
namespace file_util {
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
index ff6f131..2d4352b 100644
--- a/base/test/test_suite.h
+++ b/base/test/test_suite.h
@@ -1,264 +1,87 @@
-// 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.
#ifndef BASE_TEST_TEST_SUITE_H_
#define BASE_TEST_TEST_SUITE_H_
+#pragma once
// Defines a basic test suite framework for running gtest based tests. You can
// instantiate this class in your main function and call its Run method to run
// any gtest based tests that are linked into your executable.
-#include "base/at_exit.h"
-#include "base/base_paths.h"
-#include "base/debug_on_start.h"
-#include "base/debug_util.h"
-#include "base/i18n/icu_util.h"
-#include "base/multiprocess_test.h"
-#include "base/nss_util.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
-#include "base/scoped_nsautorelease_pool.h"
-#include "base/scoped_ptr.h"
-#include "base/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/multiprocess_func_list.h"
-
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-#include <gtk/gtk.h>
-#endif
-
-// A command-line flag that makes a test failure always result in a non-zero
-// process exit code.
-const char kStrictFailureHandling[] = "strict_failure_handling";
-
-// Match function used by the GetTestCount method.
-typedef bool (*TestMatch)(const testing::TestInfo&);
+#include <string>
-// By setting up a shadow AtExitManager, this test event listener ensures that
-// no state is carried between tests (like singletons, lazy instances, etc).
-// Of course it won't help if the code under test corrupts memory.
-class TestIsolationEnforcer : public testing::EmptyTestEventListener {
- public:
- virtual void OnTestStart(const testing::TestInfo& test_info) {
- ASSERT_FALSE(exit_manager_.get());
- exit_manager_.reset(new base::ShadowingAtExitManager());
- }
+#include "base/at_exit.h"
- virtual void OnTestEnd(const testing::TestInfo& test_info) {
- ASSERT_TRUE(exit_manager_.get());
- exit_manager_.reset();
- }
+namespace testing {
+class TestInfo;
+}
- private:
- scoped_ptr<base::ShadowingAtExitManager> exit_manager_;
-};
+namespace base {
class TestSuite {
public:
- TestSuite(int argc, char** argv) {
- base::EnableTerminationOnHeapCorruption();
- CommandLine::Init(argc, argv);
- testing::InitGoogleTest(&argc, argv);
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- g_thread_init(NULL);
- gtk_init_check(&argc, &argv);
-#endif // defined(OS_LINUX)
- // Don't add additional code to this constructor. Instead add it to
- // Initialize(). See bug 6436.
- }
+ // Match function used by the GetTestCount method.
+ typedef bool (*TestMatch)(const testing::TestInfo&);
- virtual ~TestSuite() {
- CommandLine::Reset();
- }
+ TestSuite(int argc, char** argv);
+ virtual ~TestSuite();
// Returns true if the test is marked as flaky.
- static bool IsMarkedFlaky(const testing::TestInfo& test) {
- return strncmp(test.name(), "FLAKY_", 6) == 0;
- }
+ static bool IsMarkedFlaky(const testing::TestInfo& test);
// Returns true if the test is marked as failing.
- static bool IsMarkedFailing(const testing::TestInfo& test) {
- return strncmp(test.name(), "FAILS_", 6) == 0;
- }
+ static bool IsMarkedFailing(const testing::TestInfo& test);
// Returns true if the test is marked as "MAYBE_".
// When using different prefixes depending on platform, we use MAYBE_ and
// preprocessor directives to replace MAYBE_ with the target prefix.
- static bool IsMarkedMaybe(const testing::TestInfo& test) {
- return strncmp(test.name(), "MAYBE_", 6) == 0;
- }
+ static bool IsMarkedMaybe(const testing::TestInfo& test);
// Returns true if the test failure should be ignored.
- static bool ShouldIgnoreFailure(const testing::TestInfo& test) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(kStrictFailureHandling))
- return false;
- return IsMarkedFlaky(test) || IsMarkedFailing(test);
- }
+ static bool ShouldIgnoreFailure(const testing::TestInfo& test);
// Returns true if the test failed and the failure shouldn't be ignored.
- static bool NonIgnoredFailures(const testing::TestInfo& test) {
- return test.should_run() && test.result()->Failed() &&
- !ShouldIgnoreFailure(test);
- }
+ static bool NonIgnoredFailures(const testing::TestInfo& test);
// Returns the number of tests where the match function returns true.
- int GetTestCount(TestMatch test_match) {
- testing::UnitTest* instance = testing::UnitTest::GetInstance();
- int count = 0;
-
- for (int i = 0; i < instance->total_test_case_count(); ++i) {
- const testing::TestCase& test_case = *instance->GetTestCase(i);
- for (int j = 0; j < test_case.total_test_count(); ++j) {
- if (test_match(*test_case.GetTestInfo(j))) {
- count++;
- }
- }
- }
-
- return count;
- }
-
- // TODO(phajdan.jr): Enforce isolation for all tests once it's stable.
- void EnforceTestIsolation() {
- testing::TestEventListeners& listeners =
- testing::UnitTest::GetInstance()->listeners();
- listeners.Append(new TestIsolationEnforcer);
- }
-
- void CatchMaybeTests() {
- testing::TestEventListeners& listeners =
- testing::UnitTest::GetInstance()->listeners();
- listeners.Append(new MaybeTestDisabler);
- }
-
- // Don't add additional code to this method. Instead add it to
- // Initialize(). See bug 6436.
- int Run() {
- base::ScopedNSAutoreleasePool scoped_pool;
-
- Initialize();
- std::wstring client_func =
- CommandLine::ForCurrentProcess()->GetSwitchValue(kRunClientProcess);
- // Check to see if we are being run as a client process.
- if (!client_func.empty()) {
- // Convert our function name to a usable string for GetProcAddress.
- std::string func_name(client_func.begin(), client_func.end());
-
- return multi_process_function_list::InvokeChildProcessTest(func_name);
- }
- int result = RUN_ALL_TESTS();
+ int GetTestCount(TestMatch test_match);
- // If there are failed tests, see if we should ignore the failures.
- if (result != 0 && GetTestCount(&TestSuite::NonIgnoredFailures) == 0)
- result = 0;
+ void CatchMaybeTests();
- // Display the number of flaky tests.
- int flaky_count = GetTestCount(&TestSuite::IsMarkedFlaky);
- if (flaky_count) {
- printf(" YOU HAVE %d FLAKY %s\n\n", flaky_count,
- flaky_count == 1 ? "TEST" : "TESTS");
- }
+ int Run();
- // Display the number of tests with ignored failures (FAILS).
- int failing_count = GetTestCount(&TestSuite::IsMarkedFailing);
- if (failing_count) {
- printf(" YOU HAVE %d %s with ignored failures (FAILS prefix)\n\n",
- failing_count, failing_count == 1 ? "test" : "tests");
- }
-
- // This MUST happen before Shutdown() since Shutdown() tears down
- // objects (such as NotificationService::current()) that Cocoa
- // objects use to remove themselves as observers.
- scoped_pool.Recycle();
-
- Shutdown();
-
- return result;
- }
+ // A command-line flag that makes a test failure always result in a non-zero
+ // process exit code.
+ static const char kStrictFailureHandling[];
protected:
- class MaybeTestDisabler : public testing::EmptyTestEventListener {
- public:
- virtual void OnTestStart(const testing::TestInfo& test_info) {
- ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info))
- << "Probably the OS #ifdefs don't include all of the necessary "
- "platforms.\nPlease ensure that no tests have the MAYBE_ prefix "
- "after the code is preprocessed.";
- }
- };
-
// By default fatal log messages (e.g. from DCHECKs) result in error dialogs
// which gum up buildbots. Use a minimalistic assert handler which just
// terminates the process.
- static void UnitTestAssertHandler(const std::string& str) {
- RAW_LOG(FATAL, str.c_str());
- }
+ static void UnitTestAssertHandler(const std::string& str);
// Disable crash dialogs so that it doesn't gum up the buildbot
- virtual void SuppressErrorDialogs() {
-#if defined(OS_WIN)
- UINT new_flags = SEM_FAILCRITICALERRORS |
- SEM_NOGPFAULTERRORBOX |
- SEM_NOOPENFILEERRORBOX;
-
- // Preserve existing error mode, as discussed at
- // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
- UINT existing_flags = SetErrorMode(new_flags);
- SetErrorMode(existing_flags | new_flags);
-#endif // defined(OS_WIN)
- }
+ virtual void SuppressErrorDialogs();
// Override these for custom initialization and shutdown handling. Use these
// instead of putting complex code in your constructor/destructor.
- virtual void Initialize() {
- // Initialize logging.
- FilePath exe;
- PathService::Get(base::FILE_EXE, &exe);
- FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
- logging::InitLogging(log_filename.value().c_str(),
- logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
- logging::LOCK_LOG_FILE,
- logging::DELETE_OLD_LOG_FILE);
- // We want process and thread IDs because we may have multiple processes.
- // Note: temporarily enabled timestamps in an effort to catch bug 6361.
- logging::SetLogItems(true, true, true, true);
-
- CHECK(base::EnableInProcessStackDumping());
-#if defined(OS_WIN)
- // Make sure we run with high resolution timer to minimize differences
- // between production code and test code.
- base::Time::EnableHighResolutionTimer(true);
-#endif // defined(OS_WIN)
-
- // In some cases, we do not want to see standard error dialogs.
- if (!DebugUtil::BeingDebugged() &&
- !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
- SuppressErrorDialogs();
- DebugUtil::SuppressDialogs();
- logging::SetLogAssertHandler(UnitTestAssertHandler);
- }
-
- icu_util::Initialize();
-
-#if defined(USE_NSS)
- // Trying to repeatedly initialize and cleanup NSS and NSPR may result in
- // a deadlock. Such repeated initialization will happen when using test
- // isolation. Prevent problems by initializing NSS here, so that the cleanup
- // will be done only on process exit.
- base::EnsureNSSInit();
-#endif // defined(USE_NSS)
-
- CatchMaybeTests();
- }
-
- virtual void Shutdown() {
- }
+ virtual void Initialize();
+ virtual void Shutdown();
// Make sure that we setup an AtExitManager so Singleton objects will be
// destroyed.
base::AtExitManager at_exit_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSuite);
};
+} // namespace base
+
+// TODO(brettw) remove this. This is a temporary hack to allow WebKit to compile
+// until we can update it to use "base::" (preventing a two-sided patch).
+using base::TestSuite;
+
#endif // BASE_TEST_TEST_SUITE_H_
diff --git a/base/test_support_base.target.mk b/base/test_support_base.target.mk
index 1edb2e1..18e068d 100644
--- a/base/test_support_base.target.mk
+++ b/base/test_support_base.target.mk
@@ -6,6 +6,8 @@ DEFS_Debug := '-DNO_HEAPCHECKER' \
'-DCHROMIUM_BUILD' \
'-DENABLE_REMOTING=1' \
'-DENABLE_GPU=1' \
+ '-DUNIT_TEST' \
+ '-DGTEST_HAS_RTTI=0' \
'-D__STDC_FORMAT_MACROS' \
'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
'-D_DEBUG'
@@ -19,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -45,12 +48,16 @@ CFLAGS_CC_Debug := -fno-rtti \
-fno-threadsafe-statics \
-fvisibility-inlines-hidden
-INCS_Debug := -I.
+INCS_Debug := -I. \
+ -Itesting/gmock/include \
+ -Itesting/gtest/include
DEFS_Release := '-DNO_HEAPCHECKER' \
'-DCHROMIUM_BUILD' \
'-DENABLE_REMOTING=1' \
'-DENABLE_GPU=1' \
+ '-DUNIT_TEST' \
+ '-DGTEST_HAS_RTTI=0' \
'-D__STDC_FORMAT_MACROS' \
'-DNDEBUG' \
'-DNVALGRIND' \
@@ -65,6 +72,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -93,10 +101,14 @@ CFLAGS_CC_Release := -fno-rtti \
-fno-threadsafe-statics \
-fvisibility-inlines-hidden
-INCS_Release := -I.
+INCS_Release := -I. \
+ -Itesting/gmock/include \
+ -Itesting/gtest/include
-OBJS := $(obj).target/$(TARGET)/base/test/test_file_util_linux.o \
- $(obj).target/$(TARGET)/base/test/test_file_util_posix.o
+OBJS := $(obj).target/$(TARGET)/base/test/multiprocess_test.o \
+ $(obj).target/$(TARGET)/base/test/test_file_util_linux.o \
+ $(obj).target/$(TARGET)/base/test/test_file_util_posix.o \
+ $(obj).target/$(TARGET)/base/test/test_suite.o
# Add to the list of files we specially track dependencies for.
all_deps += $(OBJS)
@@ -123,11 +135,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/test_support_perf.target.mk b/base/test_support_perf.target.mk
index 9329dd0..b18c953 100644
--- a/base/test_support_perf.target.mk
+++ b/base/test_support_perf.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -70,6 +71,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -129,11 +131,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.c b/base/third_party/dynamic_annotations/dynamic_annotations.c
index 5cfadb9..4bfc33b 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.c
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.c
@@ -141,7 +141,7 @@ static int GetRunningOnValgrind(void) {
/* value will remain "1" if res == 0 or res >= sizeof(value). The latter
* can happen only if the given value is long, in this case it can't be "0".
*/
- if (res > 0 && !strcmp(value, "0"))
+ if (res > 0 && strcmp(value, "0") != 0)
return 1;
#endif
return 0;
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.gyp b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
index 0cb4627..d1fa819 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.gyp
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
@@ -9,7 +9,7 @@
'type': '<(library)',
'msvs_guid': 'EF3AD1A1-5FA6-4B70-9CCC-F5AE4C6D0892',
'include_dirs': [
- '<(DEPTH)',
+ '../../../',
],
'sources': [
'dynamic_annotations.c',
@@ -29,7 +29,7 @@
# TODO(gregoryd): merge with dynamic_annotations when
# the win32/64 targets are merged.
'include_dirs': [
- '<(DEPTH)',
+ '../../../',
],
'sources': [
'dynamic_annotations.c',
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.target.mk b/base/third_party/dynamic_annotations/dynamic_annotations.target.mk
index b61f8af..7e74f64 100644
--- a/base/third_party/dynamic_annotations/dynamic_annotations.target.mk
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.target.mk
@@ -16,6 +16,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -45,6 +46,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -88,11 +90,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/third_party/icu/icu_utf.h b/base/third_party/icu/icu_utf.h
index 050a84b..43b4967 100644
--- a/base/third_party/icu/icu_utf.h
+++ b/base/third_party/icu/icu_utf.h
@@ -233,7 +233,7 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
}
// UTF-16 macros ---------------------------------------------------------------
-// from utf8.h
+// from utf16.h
/**
* Does this code unit alone encode a code point (BMP, not a surrogate)?
@@ -241,7 +241,7 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @return TRUE or FALSE
* @stable ICU 2.4
*/
-#define CBU16_IS_SINGLE(c) !U_IS_SURROGATE(c)
+#define CBU16_IS_SINGLE(c) !CBU_IS_SURROGATE(c)
/**
* Is this code unit a lead surrogate (U+d800..U+dbff)?
@@ -332,6 +332,36 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
#define CBU16_MAX_LENGTH 2
/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The offset may point to the lead surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the following trail surrogate as well.
+ * If the offset points to a trail surrogate or
+ * to a single, unpaired lead surrogate, then that itself
+ * will be returned as the code point.
+ *
+ * @param s const UChar * string
+ * @param i string offset, i<length
+ * @param length string length
+ * @param c output UChar32 variable
+ * @stable ICU 2.4
+ */
+#define CBU16_NEXT(s, i, length, c) { \
+ (c)=(s)[(i)++]; \
+ if(CBU16_IS_LEAD(c)) { \
+ uint16 __c2; \
+ if((i)<(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \
+ ++(i); \
+ (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \
+ } \
+ } \
+}
+
+/**
* Append a code point to a string, overwriting 1 or 2 code units.
* The offset points to the current end of the string contents
* and is advanced (post-increment).
diff --git a/base/thread.cc b/base/thread.cc
index 97f9599..41d78f0 100644
--- a/base/thread.cc
+++ b/base/thread.cc
@@ -5,7 +5,6 @@
#include "base/thread.h"
#include "base/lazy_instance.h"
-#include "base/string_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/thread_local.h"
#include "base/waitable_event.h"
@@ -36,7 +35,8 @@ struct Thread::StartupData {
};
Thread::Thread(const char* name)
- : stopping_(false),
+ : started_(false),
+ stopping_(false),
startup_data_(NULL),
thread_(0),
message_loop_(NULL),
@@ -85,13 +85,17 @@ bool Thread::StartWithOptions(const Options& options) {
if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
DLOG(ERROR) << "failed to create thread";
- startup_data_ = NULL; // Record that we failed to start.
+ startup_data_ = NULL;
return false;
}
// Wait for the thread to start and initialize message_loop_
startup_data.event.Wait();
+ // set it to NULL so we don't keep a pointer to some object on the stack.
+ startup_data_ = NULL;
+ started_ = true;
+
DCHECK(message_loop_);
return true;
}
@@ -113,7 +117,7 @@ void Thread::Stop() {
DCHECK(!message_loop_);
// The thread no longer needs to be joined.
- startup_data_ = NULL;
+ started_ = false;
stopping_ = false;
}
diff --git a/base/thread.h b/base/thread.h
index b5a87eb..cf8a69a 100644
--- a/base/thread.h
+++ b/base/thread.h
@@ -4,6 +4,7 @@
#ifndef BASE_THREAD_H_
#define BASE_THREAD_H_
+#pragma once
#include <string>
@@ -154,9 +155,10 @@ class Thread : PlatformThread::Delegate {
// PlatformThread::Delegate methods:
virtual void ThreadMain();
- // We piggy-back on the startup_data_ member to know if we successfully
- // started the thread. This way we know that we need to call Join.
- bool thread_was_started() const { return startup_data_ != NULL; }
+ bool thread_was_started() const { return started_; }
+
+ // Whether we successfully started the thread.
+ bool started_;
// If true, we're in the middle of stopping, and shouldn't access
// |message_loop_|. It may non-NULL and invalid.
diff --git a/base/thread_checker.cc b/base/thread_checker.cc
new file mode 100644
index 0000000..124b76c
--- /dev/null
+++ b/base/thread_checker.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 "base/thread_checker.h"
+
+// This code is only done in debug builds.
+#ifndef NDEBUG
+ThreadChecker::ThreadChecker() : valid_thread_id_(PlatformThread::CurrentId()) {
+}
+
+bool ThreadChecker::CalledOnValidThread() const {
+ return valid_thread_id_ == PlatformThread::CurrentId();
+}
+
+#endif // NDEBUG
diff --git a/base/thread_checker.h b/base/thread_checker.h
new file mode 100644
index 0000000..4e1d792
--- /dev/null
+++ b/base/thread_checker.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 BASE_THREAD_CHECKER_H_
+#define BASE_THREAD_CHECKER_H_
+#pragma once
+
+#include "base/platform_thread.h"
+
+// Before using this class, please consider using NonThreadSafe as it
+// makes it much easier to determine the nature of your class.
+//
+// A helper class used to help verify that some methods of a class are
+// called from the same thread. One can inherit from this class and use
+// CalledOnValidThread() to verify.
+//
+// Inheriting from class indicates that one must be careful when using the class
+// with multiple threads. However, it is up to the class document to indicate
+// how it can be used with threads.
+//
+// Example:
+// class MyClass : public ThreadChecker {
+// public:
+// void Foo() {
+// DCHECK(CalledOnValidThread());
+// ... (do stuff) ...
+// }
+// }
+//
+// In Release mode, CalledOnValidThread will always return true.
+//
+#ifndef NDEBUG
+class ThreadChecker {
+ public:
+ ThreadChecker();
+
+ bool CalledOnValidThread() const;
+
+ private:
+ const PlatformThreadId valid_thread_id_;
+};
+#else
+// Do nothing in release mode.
+class ThreadChecker {
+ public:
+ bool CalledOnValidThread() const {
+ return true;
+ }
+};
+#endif // NDEBUG
+
+#endif // BASE_THREAD_CHECKER_H_
diff --git a/base/thread_checker_unittest.cc b/base/thread_checker_unittest.cc
new file mode 100644
index 0000000..fe49e21
--- /dev/null
+++ b/base/thread_checker_unittest.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 "base/basictypes.h"
+#include "base/logging.h"
+#include "base/thread_checker.h"
+#include "base/scoped_ptr.h"
+#include "base/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#ifndef NDEBUG
+
+// Simple class to exersice the basics of ThreadChecker.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class ThreadCheckerClass : public ThreadChecker {
+ public:
+ ThreadCheckerClass() {}
+
+ // Verifies that it was called on the same thread as the constructor.
+ void DoStuff() {
+ DCHECK(CalledOnValidThread());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
+};
+
+// Calls ThreadCheckerClass::DoStuff on another thread.
+class CallDoStuffOnThread : public base::SimpleThread {
+ public:
+ CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
+ : SimpleThread("call_do_stuff_on_thread"),
+ thread_checker_class_(thread_checker_class) {
+ }
+
+ virtual void Run() {
+ thread_checker_class_->DoStuff();
+ }
+
+ private:
+ ThreadCheckerClass* thread_checker_class_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
+};
+
+// Deletes ThreadCheckerClass on a different thread.
+class DeleteThreadCheckerClassOnThread : public base::SimpleThread {
+ public:
+ DeleteThreadCheckerClassOnThread(ThreadCheckerClass* thread_checker_class)
+ : SimpleThread("delete_thread_checker_class_on_thread"),
+ thread_checker_class_(thread_checker_class) {
+ }
+
+ virtual void Run() {
+ thread_checker_class_.reset();
+ }
+
+ private:
+ scoped_ptr<ThreadCheckerClass> thread_checker_class_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
+};
+
+TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that DoStuff doesn't assert.
+ thread_checker_class->DoStuff();
+
+ // Verify that the destructor doesn't assert.
+ thread_checker_class.reset();
+}
+
+TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that the destructor doesn't assert
+ // when called on a different thread.
+ DeleteThreadCheckerClassOnThread delete_on_thread(
+ thread_checker_class.release());
+
+ delete_on_thread.Start();
+ delete_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThread) {
+ ASSERT_DEBUG_DEATH({
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // Verify that DoStuff asserts when called on a different thread.
+ CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+ call_on_thread.Start();
+ call_on_thread.Join();
+ }, "");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#endif // NDEBUG
diff --git a/base/thread_collision_warner.h b/base/thread_collision_warner.h
index 509ee5d..1e14d1a 100644
--- a/base/thread_collision_warner.h
+++ b/base/thread_collision_warner.h
@@ -4,6 +4,7 @@
#ifndef BASE_THREAD_COLLISION_WARNER_H_
#define BASE_THREAD_COLLISION_WARNER_H_
+#pragma once
#include <memory>
diff --git a/base/thread_local.h b/base/thread_local.h
index ec53da5..3227c83 100644
--- a/base/thread_local.h
+++ b/base/thread_local.h
@@ -47,6 +47,7 @@
#ifndef BASE_THREAD_LOCAL_H_
#define BASE_THREAD_LOCAL_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/thread_local_storage.h b/base/thread_local_storage.h
index 6e693a0..b37a53c 100644
--- a/base/thread_local_storage.h
+++ b/base/thread_local_storage.h
@@ -4,6 +4,7 @@
#ifndef BASE_THREAD_LOCAL_STORAGE_H_
#define BASE_THREAD_LOCAL_STORAGE_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/base/thread_unittest.cc b/base/thread_unittest.cc
index 696cfc2..1651a6a 100644
--- a/base/thread_unittest.cc
+++ b/base/thread_unittest.cc
@@ -8,7 +8,6 @@
#include "base/lock.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/base/time.cc b/base/time.cc
index 2c40d21..766f599 100644
--- a/base/time.cc
+++ b/base/time.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/time.h"
-#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/third_party/nspr/prtime.h"
@@ -67,6 +66,8 @@ time_t Time::ToTimeT() const {
// static
Time Time::FromDoubleT(double dt) {
+ if (dt == 0)
+ return Time(); // Preserve 0 so we can tell it doesn't exist.
return Time(static_cast<int64>((dt *
static_cast<double>(kMicrosecondsPerSecond)) +
kTimeTToMicrosecondsOffset));
@@ -79,6 +80,13 @@ double Time::ToDoubleT() const {
static_cast<double>(kMicrosecondsPerSecond));
}
+// static
+Time Time::UnixEpoch() {
+ Time time;
+ time.us_ = kTimeTToMicrosecondsOffset;
+ return time;
+}
+
Time Time::LocalMidnight() const {
Exploded exploded;
LocalExplode(&exploded);
@@ -105,4 +113,20 @@ bool Time::FromString(const wchar_t* time_string, Time* parsed_time) {
return true;
}
+// Time::Exploded -------------------------------------------------------------
+
+inline bool is_in_range(int value, int lo, int hi) {
+ return lo <= value && value <= hi;
+}
+
+bool Time::Exploded::HasValidValues() const {
+ return is_in_range(month, 1, 12) &&
+ is_in_range(day_of_week, 0, 6) &&
+ is_in_range(day_of_month, 1, 31) &&
+ is_in_range(hour, 0, 23) &&
+ is_in_range(minute, 0, 59) &&
+ is_in_range(second, 0, 60) &&
+ is_in_range(millisecond, 0, 999);
+}
+
} // namespace base
diff --git a/base/time.h b/base/time.h
index 98a711d..79e30b4 100644
--- a/base/time.h
+++ b/base/time.h
@@ -21,6 +21,7 @@
#ifndef BASE_TIME_H_
#define BASE_TIME_H_
+#pragma once
#include <time.h>
@@ -213,6 +214,11 @@ class Time {
int second; // Second within the current minute (0-59 plus leap
// seconds which may take it up to 60).
int millisecond; // Milliseconds within the current second (0-999)
+
+ // A cursory test for whether the data members are within their
+ // respective ranges. A 'true' return value does not guarantee the
+ // Exploded value can be successfully converted to a Time value.
+ bool HasValidValues() const;
};
// Contains the NULL time. Use Time::Now() to get the current time.
@@ -224,6 +230,9 @@ class Time {
return us_ == 0;
}
+ // Returns the time for epoch in Unix-like system (Jan 1, 1970).
+ static Time UnixEpoch();
+
// Returns the current time. Watch out, the system might adjust its clock
// in which case time will actually go backwards. We don't guarantee that
// times are increasing, or that two calls to Now() won't be the same.
@@ -243,6 +252,9 @@ class Time {
// Converts time to/from a double which is the number of seconds since epoch
// (Jan 1, 1970). Webkit uses this format to represent time.
+ // Because WebKit initializes double time value to 0 to indicate "not
+ // initialized", we map it to empty Time object that also means "not
+ // initialized".
static Time FromDoubleT(double dt);
double ToDoubleT() const;
@@ -453,6 +465,15 @@ class TimeTicks {
// SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
static TimeTicks HighResNow();
+#if defined(OS_WIN)
+ // Get the absolute value of QPC time drift. For testing.
+ static int64 GetQPCDriftMicroseconds();
+
+ // Returns true if the high resolution clock is working on this system.
+ // This is only for testing.
+ static bool IsHighResClockWorking();
+#endif
+
// Returns true if this object has not been initialized.
bool is_null() const {
return ticks_ == 0;
diff --git a/base/time_unittest.cc b/base/time_unittest.cc
index 2950d74..d383612 100644
--- a/base/time_unittest.cc
+++ b/base/time_unittest.cc
@@ -117,7 +117,7 @@ TEST(TimeTicks, Deltas) {
}
}
-TEST(TimeTicks, HighResNow) {
+TEST(TimeTicks, FLAKY_HighResNow) {
#if defined(OS_WIN)
Time::ActivateHighResolutionTimer(true);
#endif
diff --git a/base/time_win.cc b/base/time_win.cc
index d4da0f4..5d3ecd6 100644
--- a/base/time_win.cc
+++ b/base/time_win.cc
@@ -331,22 +331,20 @@ class HighResNowSingleton {
}
TimeDelta Now() {
- // Our maximum tolerance for QPC drifting.
- const int kMaxTimeDrift = 50 * Time::kMicrosecondsPerMillisecond;
-
- if (IsUsingHighResClock()) {
- int64 now = UnreliableNow();
-
- // Verify that QPC does not seem to drift.
- DCHECK(now - ReliableNow() - skew_ < kMaxTimeDrift);
-
- return TimeDelta::FromMicroseconds(now);
- }
+ if (IsUsingHighResClock())
+ return TimeDelta::FromMicroseconds(UnreliableNow());
// Just fallback to the slower clock.
return RolloverProtectedNow();
}
+ int64 GetQPCDriftMicroseconds() {
+ if (!IsUsingHighResClock())
+ return 0;
+
+ return abs((UnreliableNow() - ReliableNow()) - skew_);
+ }
+
private:
// Synchronize the QPC clock with GetSystemTimeAsFileTime.
void InitializeClock() {
@@ -398,3 +396,13 @@ TimeTicks TimeTicks::Now() {
TimeTicks TimeTicks::HighResNow() {
return TimeTicks() + Singleton<HighResNowSingleton>::get()->Now();
}
+
+// static
+int64 TimeTicks::GetQPCDriftMicroseconds() {
+ return Singleton<HighResNowSingleton>::get()->GetQPCDriftMicroseconds();
+}
+
+// static
+bool TimeTicks::IsHighResClockWorking() {
+ return Singleton<HighResNowSingleton>::get()->IsUsingHighResClock();
+} \ No newline at end of file
diff --git a/base/time_win_unittest.cc b/base/time_win_unittest.cc
index aa39478..4389e7a 100644
--- a/base/time_win_unittest.cc
+++ b/base/time_win_unittest.cc
@@ -6,6 +6,7 @@
#include <mmsystem.h>
#include <process.h>
+#include "base/platform_thread.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -107,27 +108,29 @@ TEST(TimeTicks, WinRollover) {
}
}
-// Flaky, http://crbug.com/42850.
-TEST(TimeTicks, FLAKY_SubMillisecondTimers) {
- // Loop for a bit getting timers quickly. We want to
- // see at least one case where we get a new sample in
- // less than one millisecond.
+TEST(TimeTicks, SubMillisecondTimers) {
+ // HighResNow doesn't work on some systems. Since the product still works
+ // even if it doesn't work, it makes this entire test questionable.
+ if (!TimeTicks::IsHighResClockWorking())
+ return;
+
+ const int kRetries = 1000;
bool saw_submillisecond_timer = false;
- int64 min_timer = 1000;
- TimeTicks last_time = TimeTicks::HighResNow();
+
+ // Run kRetries attempts to see a sub-millisecond timer.
for (int index = 0; index < 1000; index++) {
- TimeTicks now = TimeTicks::HighResNow();
- TimeDelta delta = now - last_time;
- if (delta.InMicroseconds() > 0 &&
- delta.InMicroseconds() < 1000) {
- if (min_timer > delta.InMicroseconds())
- min_timer = delta.InMicroseconds();
+ TimeTicks last_time = TimeTicks::HighResNow();
+ TimeDelta delta;
+ // Spin until the clock has detected a change.
+ do {
+ delta = TimeTicks::HighResNow() - last_time;
+ } while (delta.InMicroseconds() == 0);
+ if (delta.InMicroseconds() < 1000) {
saw_submillisecond_timer = true;
+ break;
}
- last_time = now;
}
EXPECT_TRUE(saw_submillisecond_timer);
- printf("Min timer is: %ldus\n", static_cast<long>(min_timer));
}
TEST(TimeTicks, TimeGetTimeCaps) {
@@ -203,3 +206,30 @@ TEST(TimeTicks, TimerPerformance) {
test_case++;
}
}
+
+TEST(TimeTicks, Drift) {
+ const int kIterations = 100;
+ int64 total_drift = 0;
+
+ for (int i = 0; i < kIterations; ++i) {
+ int64 drift_microseconds = TimeTicks::GetQPCDriftMicroseconds();
+
+ // Make sure the drift never exceeds our limit.
+ EXPECT_LT(drift_microseconds, 50000);
+
+ // Sleep for a few milliseconds (note that it means 1000 microseconds).
+ // If we check the drift too frequently, it's going to increase
+ // monotonically, making our measurement less realistic.
+ PlatformThread::Sleep((i % 2 == 0) ? 1 : 2);
+
+ total_drift += drift_microseconds;
+ }
+
+ // Sanity check. We expect some time drift to occur, especially across
+ // the number of iterations we do. However, if the QPC is disabled, this
+ // is not measuring anything (drift is zero in that case).
+ EXPECT_LT(0, total_drift);
+
+ printf("average time drift in microseconds: %lld\n",
+ total_drift / kIterations);
+}
diff --git a/base/timer.h b/base/timer.h
index a6d18bc..0de7c79 100644
--- a/base/timer.h
+++ b/base/timer.h
@@ -40,6 +40,7 @@
#ifndef BASE_TIMER_H_
#define BASE_TIMER_H_
+#pragma once
// IMPORTANT: If you change timer code, make sure that all tests (including
// disabled ones) from timer_unittests.cc pass locally. Some are disabled
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
index d4b27a5..ab2d197 100644
--- a/base/tools_sanity_unittest.cc
+++ b/base/tools_sanity_unittest.cc
@@ -35,6 +35,14 @@ TEST(ToolsSanityTest, MemoryLeak) {
leak[4] = 1; // Make sure the allocated memory is used.
}
+void ReadUninitializedValue(char *ptr) {
+ if (*ptr == '\0') {
+ (*ptr)++;
+ } else {
+ (*ptr)--;
+ }
+}
+
void ReadValueOutOfArrayBoundsLeft(char *ptr) {
LOG(INFO) << "Reading a byte out of bounds: " << ptr[-2];
}
@@ -54,6 +62,7 @@ void WriteValueOutOfArrayBoundsRight(char *ptr, size_t size) {
}
void MakeSomeErrors(char *ptr, size_t size) {
+ ReadUninitializedValue(ptr);
ReadValueOutOfArrayBoundsLeft(ptr);
ReadValueOutOfArrayBoundsRight(ptr, size);
WriteValueOutOfArrayBoundsLeft(ptr);
diff --git a/base/trace_event.cc b/base/trace_event.cc
index 56b18c2..fbb35f8 100644
--- a/base/trace_event.cc
+++ b/base/trace_event.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,7 +10,7 @@
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/time.h"
diff --git a/base/trace_event.h b/base/trace_event.h
index 775f628..e46e225 100644
--- a/base/trace_event.h
+++ b/base/trace_event.h
@@ -14,6 +14,7 @@
#ifndef BASE_TRACE_EVENT_H_
#define BASE_TRACE_EVENT_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/trace_event_win.cc b/base/trace_event_win.cc
index eae6782..7217283 100644
--- a/base/trace_event_win.cc
+++ b/base/trace_event_win.cc
@@ -3,8 +3,7 @@
// found in the LICENSE file.
#include "base/trace_event_win.h"
-#include "base/atomicops.h"
-#include "base/logging_win.h"
+#include "base/logging.h"
#include "base/singleton.h"
#include <initguid.h> // NOLINT
diff --git a/base/trace_event_win.h b/base/trace_event_win.h
index 14f768f..77ab3fb 100644
--- a/base/trace_event_win.h
+++ b/base/trace_event_win.h
@@ -5,6 +5,7 @@
// This file contains the Windows-specific declarations for trace_event.h.
#ifndef BASE_TRACE_EVENT_WIN_H_
#define BASE_TRACE_EVENT_WIN_H_
+#pragma once
#include <string>
#include "base/event_trace_provider_win.h"
diff --git a/base/trace_event_win_unittest.cc b/base/trace_event_win_unittest.cc
index 50769c5..7222d95 100644
--- a/base/trace_event_win_unittest.cc
+++ b/base/trace_event_win_unittest.cc
@@ -251,7 +251,8 @@ TEST_F(TraceEventTest, TraceLog) {
PlayLog();
}
-TEST_F(TraceEventTest, Macros) {
+// Marked flaky per http://crbug.com/52388
+TEST_F(TraceEventTest, FLAKY_Macros) {
ExpectPlayLog();
// The events should arrive in the same sequence as the expects.
diff --git a/base/tracked.cc b/base/tracked.cc
index a9d6ad7..8ae7447 100644
--- a/base/tracked.cc
+++ b/base/tracked.cc
@@ -4,7 +4,7 @@
#include "base/tracked.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/tracked_objects.h"
using base::TimeTicks;
@@ -28,7 +28,7 @@ Location::Location()
void Location::Write(bool display_filename, bool display_function_name,
std::string* output) const {
- StringAppendF(output, "%s[%d] ",
+ base::StringAppendF(output, "%s[%d] ",
display_filename ? file_name_ : "line",
line_number_);
diff --git a/base/tracked.h b/base/tracked.h
index af904c1..7af05ff 100644
--- a/base/tracked.h
+++ b/base/tracked.h
@@ -17,6 +17,7 @@
#ifndef BASE_TRACKED_H_
#define BASE_TRACKED_H_
+#pragma once
#include <string>
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 3085816..4831e4a 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.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,6 +9,7 @@
#include "base/format_macros.h"
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
using base::TimeDelta;
@@ -53,10 +54,12 @@ void DeathData::AddDeathData(const DeathData& other) {
void DeathData::Write(std::string* output) const {
if (!count_)
return;
- if (1 == count_)
- StringAppendF(output, "(1)Life in %dms ", AverageMsDuration());
- else
- StringAppendF(output, "(%d)Lives %dms/life ", count_, AverageMsDuration());
+ if (1 == count_) {
+ base::StringAppendF(output, "(1)Life in %dms ", AverageMsDuration());
+ } else {
+ base::StringAppendF(output, "(%d)Lives %dms/life ",
+ count_, AverageMsDuration());
+ }
}
void DeathData::Clear() {
@@ -88,6 +91,8 @@ ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
ThreadData::ThreadData() : next_(NULL), message_loop_(MessageLoop::current()) {}
+ThreadData::~ThreadData() {}
+
// static
ThreadData* ThreadData::current() {
if (!tls_index_.initialized())
@@ -336,6 +341,73 @@ void ThreadData::Reset() {
}
#ifdef OS_WIN
+// A class used to count down which is accessed by several threads. This is
+// used to make sure RunOnAllThreads() actually runs a task on the expected
+// count of threads.
+class ThreadData::ThreadSafeDownCounter {
+ public:
+ // Constructor sets the count, once and for all.
+ explicit ThreadSafeDownCounter(size_t count);
+
+ // Decrement the count, and return true if we hit zero. Also delete this
+ // instance automatically when we hit zero.
+ bool LastCaller();
+
+ private:
+ size_t remaining_count_;
+ Lock lock_; // protect access to remaining_count_.
+};
+
+ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count)
+ : remaining_count_(count) {
+ DCHECK_GT(remaining_count_, 0u);
+}
+
+bool ThreadData::ThreadSafeDownCounter::LastCaller() {
+ {
+ AutoLock lock(lock_);
+ if (--remaining_count_)
+ return false;
+ } // Release lock, so we can delete everything in this instance.
+ delete this;
+ return true;
+}
+
+// A Task class that runs a static method supplied, and checks to see if this
+// is the last tasks instance (on last thread) that will run the method.
+// IF this is the last run, then the supplied event is signalled.
+class ThreadData::RunTheStatic : public Task {
+ public:
+ typedef void (*FunctionPointer)();
+ RunTheStatic(FunctionPointer function,
+ HANDLE completion_handle,
+ ThreadSafeDownCounter* counter);
+ // Run the supplied static method, and optionally set the event.
+ void Run();
+
+ private:
+ FunctionPointer function_;
+ HANDLE completion_handle_;
+ // Make sure enough tasks are called before completion is signaled.
+ ThreadSafeDownCounter* counter_;
+
+ DISALLOW_COPY_AND_ASSIGN(RunTheStatic);
+};
+
+ThreadData::RunTheStatic::RunTheStatic(FunctionPointer function,
+ HANDLE completion_handle,
+ ThreadSafeDownCounter* counter)
+ : function_(function),
+ completion_handle_(completion_handle),
+ counter_(counter) {
+}
+
+void ThreadData::RunTheStatic::Run() {
+ function_();
+ if (counter_->LastCaller())
+ SetEvent(completion_handle_);
+}
+
// TODO(jar): This should use condition variables, and be cross platform.
void ThreadData::RunOnAllThreads(void (*function)()) {
ThreadData* list = first(); // Get existing list.
@@ -445,41 +517,6 @@ void ThreadData::ShutdownDisablingFurtherTracking() {
return;
}
-
-//------------------------------------------------------------------------------
-
-ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count)
- : remaining_count_(count) {
- DCHECK_GT(remaining_count_, 0u);
-}
-
-bool ThreadData::ThreadSafeDownCounter::LastCaller() {
- {
- AutoLock lock(lock_);
- if (--remaining_count_)
- return false;
- } // Release lock, so we can delete everything in this instance.
- delete this;
- return true;
-}
-
-//------------------------------------------------------------------------------
-#ifdef OS_WIN
-ThreadData::RunTheStatic::RunTheStatic(FunctionPointer function,
- HANDLE completion_handle,
- ThreadSafeDownCounter* counter)
- : function_(function),
- completion_handle_(completion_handle),
- counter_(counter) {
-}
-
-void ThreadData::RunTheStatic::Run() {
- function_();
- if (counter_->LastCaller())
- SetEvent(completion_handle_);
-}
-#endif
-
//------------------------------------------------------------------------------
// Individual 3-tuple of birth (place and thread) along with death thread, and
// the accumulated stats for instances (DeathData).
@@ -506,9 +543,9 @@ const std::string Snapshot::DeathThreadName() const {
void Snapshot::Write(std::string* output) const {
death_data_.Write(output);
- StringAppendF(output, "%s->%s ",
- birth_->birth_thread()->ThreadName().c_str(),
- death_thread_->ThreadName().c_str());
+ base::StringAppendF(output, "%s->%s ",
+ birth_->birth_thread()->ThreadName().c_str(),
+ death_thread_->ThreadName().c_str());
birth_->location().Write(true, true, output);
}
@@ -549,6 +586,9 @@ DataCollector::DataCollector() {
}
}
+DataCollector::~DataCollector() {
+}
+
void DataCollector::Append(const ThreadData& thread_data) {
// Get copy of data (which is done under ThreadData's lock).
ThreadData::BirthMap birth_map;
@@ -592,6 +632,13 @@ void DataCollector::AddListOfLivingObjects() {
//------------------------------------------------------------------------------
// Aggregation
+Aggregation::Aggregation()
+ : birth_count_(0) {
+}
+
+Aggregation::~Aggregation() {
+}
+
void Aggregation::AddDeathSnapshot(const Snapshot& snapshot) {
AddBirth(snapshot.birth());
death_threads_[snapshot.death_thread()]++;
@@ -616,33 +663,37 @@ void Aggregation::Write(std::string* output) const {
if (locations_.size() == 1) {
locations_.begin()->first.Write(true, true, output);
} else {
- StringAppendF(output, "%" PRIuS " Locations. ", locations_.size());
- if (birth_files_.size() > 1)
- StringAppendF(output, "%" PRIuS " Files. ", birth_files_.size());
- else
- StringAppendF(output, "All born in %s. ",
- birth_files_.begin()->first.c_str());
+ base::StringAppendF(output, "%" PRIuS " Locations. ", locations_.size());
+ if (birth_files_.size() > 1) {
+ base::StringAppendF(output, "%" PRIuS " Files. ", birth_files_.size());
+ } else {
+ base::StringAppendF(output, "All born in %s. ",
+ birth_files_.begin()->first.c_str());
+ }
}
- if (birth_threads_.size() > 1)
- StringAppendF(output, "%" PRIuS " BirthingThreads. ",
- birth_threads_.size());
- else
- StringAppendF(output, "All born on %s. ",
- birth_threads_.begin()->first->ThreadName().c_str());
+ if (birth_threads_.size() > 1) {
+ base::StringAppendF(output, "%" PRIuS " BirthingThreads. ",
+ birth_threads_.size());
+ } else {
+ base::StringAppendF(output, "All born on %s. ",
+ birth_threads_.begin()->first->ThreadName().c_str());
+ }
if (death_threads_.size() > 1) {
- StringAppendF(output, "%" PRIuS " DeathThreads. ", death_threads_.size());
+ base::StringAppendF(output, "%" PRIuS " DeathThreads. ",
+ death_threads_.size());
} else {
- if (death_threads_.begin()->first)
- StringAppendF(output, "All deleted on %s. ",
- death_threads_.begin()->first->ThreadName().c_str());
- else
+ if (death_threads_.begin()->first) {
+ base::StringAppendF(output, "All deleted on %s. ",
+ death_threads_.begin()->first->ThreadName().c_str());
+ } else {
output->append("All these objects are still alive.");
+ }
}
if (birth_count_ > 1)
- StringAppendF(output, "Births=%d ", birth_count_);
+ base::StringAppendF(output, "Births=%d ", birth_count_);
DeathData::Write(output);
}
@@ -937,23 +988,24 @@ bool Comparator::WriteSortGrouping(const Snapshot& sample,
bool wrote_data = false;
switch (selector_) {
case BIRTH_THREAD:
- StringAppendF(output, "All new on %s ",
- sample.birth_thread()->ThreadName().c_str());
+ base::StringAppendF(output, "All new on %s ",
+ sample.birth_thread()->ThreadName().c_str());
wrote_data = true;
break;
case DEATH_THREAD:
- if (sample.death_thread())
- StringAppendF(output, "All deleted on %s ",
- sample.DeathThreadName().c_str());
- else
+ if (sample.death_thread()) {
+ base::StringAppendF(output, "All deleted on %s ",
+ sample.DeathThreadName().c_str());
+ } else {
output->append("All still alive ");
+ }
wrote_data = true;
break;
case BIRTH_FILE:
- StringAppendF(output, "All born in %s ",
- sample.location().file_name());
+ base::StringAppendF(output, "All born in %s ",
+ sample.location().file_name());
break;
case BIRTH_FUNCTION:
@@ -976,11 +1028,11 @@ void Comparator::WriteSnapshot(const Snapshot& sample,
sample.death_data().Write(output);
if (!(combined_selectors_ & BIRTH_THREAD) ||
!(combined_selectors_ & DEATH_THREAD))
- StringAppendF(output, "%s->%s ",
- (combined_selectors_ & BIRTH_THREAD) ? "*" :
- sample.birth().birth_thread()->ThreadName().c_str(),
- (combined_selectors_ & DEATH_THREAD) ? "*" :
- sample.DeathThreadName().c_str());
+ base::StringAppendF(output, "%s->%s ",
+ (combined_selectors_ & BIRTH_THREAD) ? "*" :
+ sample.birth().birth_thread()->ThreadName().c_str(),
+ (combined_selectors_ & DEATH_THREAD) ? "*" :
+ sample.DeathThreadName().c_str());
sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE),
!(combined_selectors_ & BIRTH_FUNCTION),
output);
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 48e2b5a..b76a295 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -4,6 +4,7 @@
#ifndef BASE_TRACKED_OBJECTS_H_
#define BASE_TRACKED_OBJECTS_H_
+#pragma once
#include <map>
#include <string>
@@ -292,6 +293,7 @@ class DataCollector {
// Construct with a list of how many threads should contribute. This helps us
// determine (in the async case) when we are done with all contributions.
DataCollector();
+ ~DataCollector();
// Add all stats from the indicated thread into our arrays. This function is
// mutex protected, and *could* be called from any threads (although current
@@ -332,7 +334,8 @@ class DataCollector {
class Aggregation: public DeathData {
public:
- Aggregation() : birth_count_(0) {}
+ Aggregation();
+ ~Aggregation();
void AddDeathSnapshot(const Snapshot& snapshot);
void AddBirths(const Births& births);
@@ -468,6 +471,7 @@ class ThreadData {
typedef std::map<const Births*, DeathData> DeathMap;
ThreadData();
+ ~ThreadData();
// Using Thread Local Store, find the current instance for collecting data.
// If an instance does not exist, construct one (and remember it for use on
@@ -557,44 +561,9 @@ class ThreadData {
SHUTDOWN,
};
- // A class used to count down which is accessed by several threads. This is
- // used to make sure RunOnAllThreads() actually runs a task on the expected
- // count of threads.
- class ThreadSafeDownCounter {
- public:
- // Constructor sets the count, once and for all.
- explicit ThreadSafeDownCounter(size_t count);
-
- // Decrement the count, and return true if we hit zero. Also delete this
- // instance automatically when we hit zero.
- bool LastCaller();
-
- private:
- size_t remaining_count_;
- Lock lock_; // protect access to remaining_count_.
- };
-
-#ifdef OS_WIN
- // A Task class that runs a static method supplied, and checks to see if this
- // is the last tasks instance (on last thread) that will run the method.
- // IF this is the last run, then the supplied event is signalled.
- class RunTheStatic : public Task {
- public:
- typedef void (*FunctionPointer)();
- RunTheStatic(FunctionPointer function,
- HANDLE completion_handle,
- ThreadSafeDownCounter* counter);
- // Run the supplied static method, and optionally set the event.
- void Run();
-
- private:
- FunctionPointer function_;
- HANDLE completion_handle_;
- // Make sure enough tasks are called before completion is signaled.
- ThreadSafeDownCounter* counter_;
-
- DISALLOW_COPY_AND_ASSIGN(RunTheStatic);
- };
+#if defined(OS_WIN)
+ class ThreadSafeDownCounter;
+ class RunTheStatic;
#endif
// Each registered thread is called to set status_ to SHUTDOWN.
diff --git a/base/tuple.h b/base/tuple.h
index d17d9f5..b67d924 100644
--- a/base/tuple.h
+++ b/base/tuple.h
@@ -28,6 +28,7 @@
#ifndef BASE_TUPLE_H__
#define BASE_TUPLE_H__
+#pragma once
// Traits ----------------------------------------------------------------------
//
@@ -51,6 +52,9 @@ struct TupleTraits<P&> {
typedef P& ParamType;
};
+template <class P>
+struct TupleTypes { };
+
// Tuple -----------------------------------------------------------------------
//
// This set of classes is useful for bundling 0 or more heterogeneous data types
@@ -75,9 +79,6 @@ template <class A>
struct Tuple1 {
public:
typedef A TypeA;
- typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple;
- typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple;
- typedef Tuple1<typename TupleTraits<A>::ParamType> ParamTuple;
Tuple1() {}
explicit Tuple1(typename TupleTraits<A>::ParamType a) : a(a) {}
@@ -90,12 +91,6 @@ struct Tuple2 {
public:
typedef A TypeA;
typedef B TypeB;
- typedef Tuple2<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType> ValueTuple;
- typedef Tuple2<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType> RefTuple;
- typedef Tuple2<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType> ParamTuple;
Tuple2() {}
Tuple2(typename TupleTraits<A>::ParamType a,
@@ -113,15 +108,6 @@ struct Tuple3 {
typedef A TypeA;
typedef B TypeB;
typedef C TypeC;
- typedef Tuple3<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType> ValueTuple;
- typedef Tuple3<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType> RefTuple;
- typedef Tuple3<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType> ParamTuple;
Tuple3() {}
Tuple3(typename TupleTraits<A>::ParamType a,
@@ -142,18 +128,6 @@ struct Tuple4 {
typedef B TypeB;
typedef C TypeC;
typedef D TypeD;
- typedef Tuple4<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType> ValueTuple;
- typedef Tuple4<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType> RefTuple;
- typedef Tuple4<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType> ParamTuple;
Tuple4() {}
Tuple4(typename TupleTraits<A>::ParamType a,
@@ -177,21 +151,6 @@ struct Tuple5 {
typedef C TypeC;
typedef D TypeD;
typedef E TypeE;
- typedef Tuple5<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType> ValueTuple;
- typedef Tuple5<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType> RefTuple;
- typedef Tuple5<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType> ParamTuple;
Tuple5() {}
Tuple5(typename TupleTraits<A>::ParamType a,
@@ -218,24 +177,6 @@ struct Tuple6 {
typedef D TypeD;
typedef E TypeE;
typedef F TypeF;
- typedef Tuple6<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType,
- typename TupleTraits<F>::ValueType> ValueTuple;
- typedef Tuple6<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType,
- typename TupleTraits<F>::RefType> RefTuple;
- typedef Tuple6<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType,
- typename TupleTraits<F>::ParamType> ParamTuple;
Tuple6() {}
Tuple6(typename TupleTraits<A>::ParamType a,
@@ -265,27 +206,6 @@ struct Tuple7 {
typedef E TypeE;
typedef F TypeF;
typedef G TypeG;
- typedef Tuple7<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType,
- typename TupleTraits<F>::ValueType,
- typename TupleTraits<G>::ValueType> ValueTuple;
- typedef Tuple7<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType,
- typename TupleTraits<F>::RefType,
- typename TupleTraits<G>::RefType> RefTuple;
- typedef Tuple7<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType,
- typename TupleTraits<F>::ParamType,
- typename TupleTraits<G>::ParamType> ParamTuple;
Tuple7() {}
Tuple7(typename TupleTraits<A>::ParamType a,
@@ -319,30 +239,6 @@ struct Tuple8 {
typedef F TypeF;
typedef G TypeG;
typedef H TypeH;
- typedef Tuple8<typename TupleTraits<A>::ValueType,
- typename TupleTraits<B>::ValueType,
- typename TupleTraits<C>::ValueType,
- typename TupleTraits<D>::ValueType,
- typename TupleTraits<E>::ValueType,
- typename TupleTraits<F>::ValueType,
- typename TupleTraits<G>::ValueType,
- typename TupleTraits<H>::ValueType> ValueTuple;
- typedef Tuple8<typename TupleTraits<A>::RefType,
- typename TupleTraits<B>::RefType,
- typename TupleTraits<C>::RefType,
- typename TupleTraits<D>::RefType,
- typename TupleTraits<E>::RefType,
- typename TupleTraits<F>::RefType,
- typename TupleTraits<G>::RefType,
- typename TupleTraits<H>::RefType> RefTuple;
- typedef Tuple8<typename TupleTraits<A>::ParamType,
- typename TupleTraits<B>::ParamType,
- typename TupleTraits<C>::ParamType,
- typename TupleTraits<D>::ParamType,
- typename TupleTraits<E>::ParamType,
- typename TupleTraits<F>::ParamType,
- typename TupleTraits<G>::ParamType,
- typename TupleTraits<H>::ParamType> ParamTuple;
Tuple8() {}
Tuple8(typename TupleTraits<A>::ParamType a,
@@ -366,6 +262,159 @@ struct Tuple8 {
H h;
};
+// Tuple types ----------------------------------------------------------------
+//
+// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
+// definitions of class types the tuple takes as parameters.
+
+template <>
+struct TupleTypes< Tuple0 > {
+ typedef Tuple0 ValueTuple;
+ typedef Tuple0 RefTuple;
+ typedef Tuple0 ParamTuple;
+};
+
+template <class A>
+struct TupleTypes< Tuple1<A> > {
+ typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple;
+ typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple;
+ typedef Tuple1<typename TupleTraits<A>::ParamType> ParamTuple;
+};
+
+template <class A, class B>
+struct TupleTypes< Tuple2<A, B> > {
+ typedef Tuple2<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType> ValueTuple;
+typedef Tuple2<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType> RefTuple;
+ typedef Tuple2<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C>
+struct TupleTypes< Tuple3<A, B, C> > {
+ typedef Tuple3<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType> ValueTuple;
+typedef Tuple3<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType> RefTuple;
+ typedef Tuple3<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D>
+struct TupleTypes< Tuple4<A, B, C, D> > {
+ typedef Tuple4<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType> ValueTuple;
+typedef Tuple4<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType> RefTuple;
+ typedef Tuple4<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E>
+struct TupleTypes< Tuple5<A, B, C, D, E> > {
+ typedef Tuple5<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType> ValueTuple;
+typedef Tuple5<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType> RefTuple;
+ typedef Tuple5<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F>
+struct TupleTypes< Tuple6<A, B, C, D, E, F> > {
+ typedef Tuple6<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType,
+ typename TupleTraits<F>::ValueType> ValueTuple;
+typedef Tuple6<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType,
+ typename TupleTraits<F>::RefType> RefTuple;
+ typedef Tuple6<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType,
+ typename TupleTraits<F>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G>
+struct TupleTypes< Tuple7<A, B, C, D, E, F, G> > {
+ typedef Tuple7<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType,
+ typename TupleTraits<F>::ValueType,
+ typename TupleTraits<G>::ValueType> ValueTuple;
+typedef Tuple7<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType,
+ typename TupleTraits<F>::RefType,
+ typename TupleTraits<G>::RefType> RefTuple;
+ typedef Tuple7<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType,
+ typename TupleTraits<F>::ParamType,
+ typename TupleTraits<G>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G,
+ class H>
+struct TupleTypes< Tuple8<A, B, C, D, E, F, G, H> > {
+ typedef Tuple8<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType,
+ typename TupleTraits<F>::ValueType,
+ typename TupleTraits<G>::ValueType,
+ typename TupleTraits<H>::ValueType> ValueTuple;
+typedef Tuple8<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType,
+ typename TupleTraits<F>::RefType,
+ typename TupleTraits<G>::RefType,
+ typename TupleTraits<H>::RefType> RefTuple;
+ typedef Tuple8<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType,
+ typename TupleTraits<F>::ParamType,
+ typename TupleTraits<G>::ParamType,
+ typename TupleTraits<H>::ParamType> ParamTuple;
+};
+
// Tuple creators -------------------------------------------------------------
//
// Helper functions for constructing tuples while inferring the template
diff --git a/base/unix_domain_socket_posix.cc b/base/unix_domain_socket_posix.cc
index 08c41cf..73fa260 100644
--- a/base/unix_domain_socket_posix.cc
+++ b/base/unix_domain_socket_posix.cc
@@ -15,7 +15,8 @@
namespace base {
-bool SendMsg(int fd, const void* buf, size_t length, std::vector<int>& fds) {
+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};
@@ -26,11 +27,8 @@ bool SendMsg(int fd, const void* buf, size_t length, std::vector<int>& fds) {
if (fds.size()) {
const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
control_buffer = new char[control_len];
- if (!control_buffer)
- return false;
struct cmsghdr *cmsg;
-
msg.msg_control = control_buffer;
msg.msg_controllen = control_len;
cmsg = CMSG_FIRSTHDR(&msg);
diff --git a/base/unix_domain_socket_posix.h b/base/unix_domain_socket_posix.h
index ecf6cfb..51c821b 100644
--- a/base/unix_domain_socket_posix.h
+++ b/base/unix_domain_socket_posix.h
@@ -4,6 +4,7 @@
#ifndef BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
#define BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -16,7 +17,7 @@ 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,
- std::vector<int>& fds);
+ 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);
diff --git a/base/utf_offset_string_conversions.h b/base/utf_offset_string_conversions.h
index 0a1a682..b20e4b1 100644
--- a/base/utf_offset_string_conversions.h
+++ b/base/utf_offset_string_conversions.h
@@ -4,6 +4,7 @@
#ifndef BASE_UTF_OFFSET_STRING_CONVERSIONS_H_
#define BASE_UTF_OFFSET_STRING_CONVERSIONS_H_
+#pragma once
#include <string>
diff --git a/base/utf_string_conversion_utils.h b/base/utf_string_conversion_utils.h
index 0c02d82..a34c9ae 100644
--- a/base/utf_string_conversion_utils.h
+++ b/base/utf_string_conversion_utils.h
@@ -4,6 +4,7 @@
#ifndef BASE_UTF_STRING_CONVERSION_UTILS_H_
#define BASE_UTF_STRING_CONVERSION_UTILS_H_
+#pragma once
// This should only be used by the various UTF string conversion files.
diff --git a/base/utf_string_conversions.cc b/base/utf_string_conversions.cc
index d517e1b..41a70db 100644
--- a/base/utf_string_conversions.cc
+++ b/base/utf_string_conversions.cc
@@ -1,10 +1,11 @@
-// 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.
#include "base/utf_string_conversions.h"
#include "base/string_piece.h"
+#include "base/string_util.h"
#include "base/utf_string_conversion_utils.h"
using base::PrepareForUTF8Output;
@@ -173,3 +174,23 @@ std::string UTF16ToUTF8(const string16& utf16) {
}
#endif
+
+std::wstring ASCIIToWide(const char* ascii) {
+ DCHECK(IsStringASCII(ascii)) << ascii;
+ return std::wstring(ascii, &ascii[strlen(ascii)]);
+}
+
+std::wstring ASCIIToWide(const std::string& ascii) {
+ DCHECK(IsStringASCII(ascii)) << ascii;
+ return std::wstring(ascii.begin(), ascii.end());
+}
+
+string16 ASCIIToUTF16(const char* ascii) {
+ DCHECK(IsStringASCII(ascii)) << ascii;
+ return string16(ascii, &ascii[strlen(ascii)]);
+}
+
+string16 ASCIIToUTF16(const std::string& ascii) {
+ DCHECK(IsStringASCII(ascii)) << ascii;
+ return string16(ascii.begin(), ascii.end());
+}
diff --git a/base/utf_string_conversions.h b/base/utf_string_conversions.h
index 57a22e7..6c49b41 100644
--- a/base/utf_string_conversions.h
+++ b/base/utf_string_conversions.h
@@ -4,6 +4,7 @@
#ifndef BASE_UTF_STRING_CONVERSIONS_H_
#define BASE_UTF_STRING_CONVERSIONS_H_
+#pragma once
#include <string>
@@ -47,4 +48,18 @@ std::string UTF16ToUTF8(const string16& utf16);
# define UTF16ToWideHack UTF16ToWide
#endif
+// These convert an ASCII string, typically a hardcoded constant, to a
+// UTF16/Wide string.
+//
+// Note that this doesn't use StringPiece because it's very common to need
+// ASCIIToUTF16("foo"), and either we have to include it in this file, or
+// forward declare it and force all callers to include string_piece.h. Given
+// that string_piece brings in complicated stuff like <algorithm>, it's
+// easier to just duplicate these very simple definitions for the two calling
+// cases we actually use.
+std::wstring ASCIIToWide(const char* ascii);
+std::wstring ASCIIToWide(const std::string& ascii);
+string16 ASCIIToUTF16(const char* ascii);
+string16 ASCIIToUTF16(const std::string& ascii);
+
#endif // BASE_UTF_STRING_CONVERSIONS_H_
diff --git a/base/utf_string_conversions_unittest.cc b/base/utf_string_conversions_unittest.cc
index 01a4125..2687a55 100644
--- a/base/utf_string_conversions_unittest.cc
+++ b/base/utf_string_conversions_unittest.cc
@@ -1,9 +1,10 @@
-// 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.
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/values.cc b/base/values.cc
index eebd7eb..ce73cb1 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -90,12 +90,7 @@ Value* Value::CreateStringValue(const std::string& in_value) {
}
// static
-Value* Value::CreateStringValue(const std::wstring& in_value) {
- return new StringValue(in_value);
-}
-
-// static
-Value* Value::CreateStringValueFromUTF16(const string16& in_value) {
+Value* Value::CreateStringValue(const string16& in_value) {
return new StringValue(in_value);
}
@@ -104,27 +99,23 @@ BinaryValue* Value::CreateBinaryValue(char* buffer, size_t size) {
return BinaryValue::Create(buffer, size);
}
-bool Value::GetAsBoolean(bool* in_value) const {
- return false;
-}
-
-bool Value::GetAsInteger(int* in_value) const {
+bool Value::GetAsBoolean(bool* out_value) const {
return false;
}
-bool Value::GetAsReal(double* in_value) const {
+bool Value::GetAsInteger(int* out_value) const {
return false;
}
-bool Value::GetAsString(std::string* in_value) const {
+bool Value::GetAsReal(double* out_value) const {
return false;
}
-bool Value::GetAsString(std::wstring* in_value) const {
+bool Value::GetAsString(std::string* out_value) const {
return false;
}
-bool Value::GetAsUTF16(string16* out_value) const {
+bool Value::GetAsString(string16* out_value) const {
return false;
}
@@ -228,17 +219,10 @@ StringValue::StringValue(const std::string& in_value)
DCHECK(IsStringUTF8(in_value));
}
-StringValue::StringValue(const std::wstring& in_value)
- : Value(TYPE_STRING),
- value_(WideToUTF8(in_value)) {
-}
-
-#if !defined(WCHAR_T_IS_UTF16)
StringValue::StringValue(const string16& in_value)
: Value(TYPE_STRING),
value_(UTF16ToUTF8(in_value)) {
}
-#endif
StringValue::~StringValue() {
}
@@ -249,13 +233,7 @@ bool StringValue::GetAsString(std::string* out_value) const {
return true;
}
-bool StringValue::GetAsString(std::wstring* out_value) const {
- if (out_value)
- *out_value = UTF8ToWide(value_);
- return true;
-}
-
-bool StringValue::GetAsUTF16(string16* out_value) const {
+bool StringValue::GetAsString(string16* out_value) const {
if (out_value)
*out_value = UTF8ToUTF16(value_);
return true;
@@ -323,7 +301,7 @@ bool BinaryValue::Equals(const Value* other) const {
///////////////////// DictionaryValue ////////////////////
DictionaryValue::DictionaryValue()
- : Value(TYPE_DICTIONARY) {
+ : Value(TYPE_DICTIONARY) {
}
DictionaryValue::~DictionaryValue() {
@@ -353,7 +331,8 @@ bool DictionaryValue::Equals(const Value* other) const {
while (lhs_it != end_keys() && rhs_it != other_dict->end_keys()) {
Value* lhs;
Value* rhs;
- if (!GetWithoutPathExpansion(*lhs_it, &lhs) ||
+ if (*lhs_it != *rhs_it ||
+ !GetWithoutPathExpansion(*lhs_it, &lhs) ||
!other_dict->GetWithoutPathExpansion(*rhs_it, &rhs) ||
!lhs->Equals(rhs)) {
return false;
@@ -367,16 +346,13 @@ bool DictionaryValue::Equals(const Value* other) const {
return true;
}
-bool DictionaryValue::HasKey(const std::wstring& key) const {
+bool DictionaryValue::HasKey(const std::string& key) const {
+ DCHECK(IsStringUTF8(key));
ValueMap::const_iterator current_entry = dictionary_.find(key);
DCHECK((current_entry == dictionary_.end()) || current_entry->second);
return current_entry != dictionary_.end();
}
-bool DictionaryValue::HasKeyASCII(const std::string& key) const {
- return HasKey(ASCIIToWide(key));
-}
-
void DictionaryValue::Clear() {
ValueMap::iterator dict_iterator = dictionary_.begin();
while (dict_iterator != dictionary_.end()) {
@@ -387,16 +363,17 @@ void DictionaryValue::Clear() {
dictionary_.clear();
}
-void DictionaryValue::Set(const std::wstring& path, Value* in_value) {
+void DictionaryValue::Set(const std::string& path, Value* in_value) {
+ DCHECK(IsStringUTF8(path));
DCHECK(in_value);
- std::wstring current_path(path);
+ std::string current_path(path);
DictionaryValue* current_dictionary = this;
for (size_t delimiter_position = current_path.find('.');
- delimiter_position != std::wstring::npos;
+ delimiter_position != std::string::npos;
delimiter_position = current_path.find('.')) {
// Assume that we're indexing into a dictionary.
- std::wstring key(current_path, 0, delimiter_position);
+ std::string key(current_path, 0, delimiter_position);
DictionaryValue* child_dictionary = NULL;
if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
child_dictionary = new DictionaryValue;
@@ -410,34 +387,29 @@ void DictionaryValue::Set(const std::wstring& path, Value* in_value) {
current_dictionary->SetWithoutPathExpansion(current_path, in_value);
}
-void DictionaryValue::SetBoolean(const std::wstring& path, bool in_value) {
+void DictionaryValue::SetBoolean(const std::string& path, bool in_value) {
Set(path, CreateBooleanValue(in_value));
}
-void DictionaryValue::SetInteger(const std::wstring& path, int in_value) {
+void DictionaryValue::SetInteger(const std::string& path, int in_value) {
Set(path, CreateIntegerValue(in_value));
}
-void DictionaryValue::SetReal(const std::wstring& path, double in_value) {
+void DictionaryValue::SetReal(const std::string& path, double in_value) {
Set(path, CreateRealValue(in_value));
}
-void DictionaryValue::SetString(const std::wstring& path,
+void DictionaryValue::SetString(const std::string& path,
const std::string& in_value) {
Set(path, CreateStringValue(in_value));
}
-void DictionaryValue::SetString(const std::wstring& path,
- const std::wstring& in_value) {
+void DictionaryValue::SetString(const std::string& path,
+ const string16& in_value) {
Set(path, CreateStringValue(in_value));
}
-void DictionaryValue::SetStringFromUTF16(const std::wstring& path,
- const string16& in_value) {
- Set(path, CreateStringValueFromUTF16(in_value));
-}
-
-void DictionaryValue::SetWithoutPathExpansion(const std::wstring& key,
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
Value* in_value) {
// If there's an existing value here, we need to delete it, because
// we own all our children.
@@ -449,11 +421,12 @@ void DictionaryValue::SetWithoutPathExpansion(const std::wstring& key,
dictionary_[key] = in_value;
}
-bool DictionaryValue::Get(const std::wstring& path, Value** out_value) const {
- std::wstring current_path(path);
+bool DictionaryValue::Get(const std::string& path, Value** out_value) const {
+ DCHECK(IsStringUTF8(path));
+ std::string current_path(path);
const DictionaryValue* current_dictionary = this;
for (size_t delimiter_position = current_path.find('.');
- delimiter_position != std::wstring::npos;
+ delimiter_position != std::string::npos;
delimiter_position = current_path.find('.')) {
DictionaryValue* child_dictionary = NULL;
if (!current_dictionary->GetDictionary(
@@ -467,7 +440,7 @@ bool DictionaryValue::Get(const std::wstring& path, Value** out_value) const {
return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
}
-bool DictionaryValue::GetBoolean(const std::wstring& path,
+bool DictionaryValue::GetBoolean(const std::string& path,
bool* bool_value) const {
Value* value;
if (!Get(path, &value))
@@ -476,7 +449,7 @@ bool DictionaryValue::GetBoolean(const std::wstring& path,
return value->GetAsBoolean(bool_value);
}
-bool DictionaryValue::GetInteger(const std::wstring& path,
+bool DictionaryValue::GetInteger(const std::string& path,
int* out_value) const {
Value* value;
if (!Get(path, &value))
@@ -485,7 +458,7 @@ bool DictionaryValue::GetInteger(const std::wstring& path,
return value->GetAsInteger(out_value);
}
-bool DictionaryValue::GetReal(const std::wstring& path,
+bool DictionaryValue::GetReal(const std::string& path,
double* out_value) const {
Value* value;
if (!Get(path, &value))
@@ -495,26 +468,6 @@ bool DictionaryValue::GetReal(const std::wstring& path,
}
bool DictionaryValue::GetString(const std::string& path,
- string16* out_value) const {
- return GetStringAsUTF16(ASCIIToWide(path), out_value);
-}
-
-bool DictionaryValue::GetStringASCII(const std::string& path,
- std::string* out_value) const {
- std::string out;
- if (!GetString(ASCIIToWide(path), &out))
- return false;
-
- if (!IsStringASCII(out)) {
- NOTREACHED();
- return false;
- }
-
- out_value->assign(out);
- return true;
-}
-
-bool DictionaryValue::GetString(const std::wstring& path,
std::string* out_value) const {
Value* value;
if (!Get(path, &value))
@@ -523,8 +476,8 @@ bool DictionaryValue::GetString(const std::wstring& path,
return value->GetAsString(out_value);
}
-bool DictionaryValue::GetString(const std::wstring& path,
- std::wstring* out_value) const {
+bool DictionaryValue::GetString(const std::string& path,
+ string16* out_value) const {
Value* value;
if (!Get(path, &value))
return false;
@@ -532,16 +485,22 @@ bool DictionaryValue::GetString(const std::wstring& path,
return value->GetAsString(out_value);
}
-bool DictionaryValue::GetStringAsUTF16(const std::wstring& path,
- string16* out_value) const {
- Value* value;
- if (!Get(path, &value))
+bool DictionaryValue::GetStringASCII(const std::string& path,
+ std::string* out_value) const {
+ std::string out;
+ if (!GetString(path, &out))
+ return false;
+
+ if (!IsStringASCII(out)) {
+ NOTREACHED();
return false;
+ }
- return value->GetAsUTF16(out_value);
+ out_value->assign(out);
+ return true;
}
-bool DictionaryValue::GetBinary(const std::wstring& path,
+bool DictionaryValue::GetBinary(const std::string& path,
BinaryValue** out_value) const {
Value* value;
bool result = Get(path, &value);
@@ -554,7 +513,7 @@ bool DictionaryValue::GetBinary(const std::wstring& path,
return true;
}
-bool DictionaryValue::GetDictionary(const std::wstring& path,
+bool DictionaryValue::GetDictionary(const std::string& path,
DictionaryValue** out_value) const {
Value* value;
bool result = Get(path, &value);
@@ -567,7 +526,7 @@ bool DictionaryValue::GetDictionary(const std::wstring& path,
return true;
}
-bool DictionaryValue::GetList(const std::wstring& path,
+bool DictionaryValue::GetList(const std::string& path,
ListValue** out_value) const {
Value* value;
bool result = Get(path, &value);
@@ -580,8 +539,9 @@ bool DictionaryValue::GetList(const std::wstring& path,
return true;
}
-bool DictionaryValue::GetWithoutPathExpansion(const std::wstring& key,
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
Value** out_value) const {
+ DCHECK(IsStringUTF8(key));
ValueMap::const_iterator entry_iterator = dictionary_.find(key);
if (entry_iterator == dictionary_.end())
return false;
@@ -592,50 +552,40 @@ bool DictionaryValue::GetWithoutPathExpansion(const std::wstring& key,
return true;
}
-bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::wstring& path,
+bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key,
int* out_value) const {
Value* value;
- if (!GetWithoutPathExpansion(path, &value))
+ if (!GetWithoutPathExpansion(key, &value))
return false;
return value->GetAsInteger(out_value);
}
bool DictionaryValue::GetStringWithoutPathExpansion(
- const std::wstring& path,
+ const std::string& key,
std::string* out_value) const {
Value* value;
- if (!GetWithoutPathExpansion(path, &value))
+ if (!GetWithoutPathExpansion(key, &value))
return false;
return value->GetAsString(out_value);
}
bool DictionaryValue::GetStringWithoutPathExpansion(
- const std::wstring& path,
- std::wstring* out_value) const {
- Value* value;
- if (!GetWithoutPathExpansion(path, &value))
- return false;
-
- return value->GetAsString(out_value);
-}
-
-bool DictionaryValue::GetStringAsUTF16WithoutPathExpansion(
- const std::wstring& path,
+ const std::string& key,
string16* out_value) const {
Value* value;
- if (!GetWithoutPathExpansion(path, &value))
+ if (!GetWithoutPathExpansion(key, &value))
return false;
- return value->GetAsUTF16(out_value);
+ return value->GetAsString(out_value);
}
bool DictionaryValue::GetDictionaryWithoutPathExpansion(
- const std::wstring& path,
+ const std::string& key,
DictionaryValue** out_value) const {
Value* value;
- bool result = GetWithoutPathExpansion(path, &value);
+ bool result = GetWithoutPathExpansion(key, &value);
if (!result || !value->IsType(TYPE_DICTIONARY))
return false;
@@ -645,10 +595,10 @@ bool DictionaryValue::GetDictionaryWithoutPathExpansion(
return true;
}
-bool DictionaryValue::GetListWithoutPathExpansion(const std::wstring& path,
+bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key,
ListValue** out_value) const {
Value* value;
- bool result = GetWithoutPathExpansion(path, &value);
+ bool result = GetWithoutPathExpansion(key, &value);
if (!result || !value->IsType(TYPE_LIST))
return false;
@@ -658,11 +608,12 @@ bool DictionaryValue::GetListWithoutPathExpansion(const std::wstring& path,
return true;
}
-bool DictionaryValue::Remove(const std::wstring& path, Value** out_value) {
- std::wstring current_path(path);
+bool DictionaryValue::Remove(const std::string& path, Value** out_value) {
+ DCHECK(IsStringUTF8(path));
+ std::string current_path(path);
DictionaryValue* current_dictionary = this;
size_t delimiter_position = current_path.rfind('.');
- if (delimiter_position != std::wstring::npos) {
+ if (delimiter_position != std::string::npos) {
if (!GetDictionary(current_path.substr(0, delimiter_position),
&current_dictionary))
return false;
@@ -673,8 +624,9 @@ bool DictionaryValue::Remove(const std::wstring& path, Value** out_value) {
out_value);
}
-bool DictionaryValue::RemoveWithoutPathExpansion(const std::wstring& key,
+bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key,
Value** out_value) {
+ DCHECK(IsStringUTF8(key));
ValueMap::iterator entry_iterator = dictionary_.find(key);
if (entry_iterator == dictionary_.end())
return false;
@@ -713,6 +665,114 @@ 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) {
@@ -787,7 +847,7 @@ bool ListValue::GetString(size_t index, std::string* out_value) const {
return value->GetAsString(out_value);
}
-bool ListValue::GetString(size_t index, std::wstring* out_value) const {
+bool ListValue::GetString(size_t index, string16* out_value) const {
Value* value;
if (!Get(index, &value))
return false;
@@ -795,14 +855,6 @@ bool ListValue::GetString(size_t index, std::wstring* out_value) const {
return value->GetAsString(out_value);
}
-bool ListValue::GetStringAsUTF16(size_t index, string16* out_value) const {
- Value* value;
- if (!Get(index, &value))
- return false;
-
- return value->GetAsUTF16(out_value);
-}
-
bool ListValue::GetBinary(size_t index, BinaryValue** out_value) const {
Value* value;
bool result = Get(index, &value);
diff --git a/base/values.h b/base/values.h
index ea8a3ca..a70b0c8 100644
--- a/base/values.h
+++ b/base/values.h
@@ -2,24 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This file specifies a recursive data storage class called Value
-// intended for storing setting and other persistable data.
-// It includes the ability to specify (recursive) lists and dictionaries, so
-// it's fairly expressive. However, the API is optimized for the common case,
-// namely storing a hierarchical tree of simple values. Given a
-// DictionaryValue root, you can easily do things like:
+// This file specifies a recursive data storage class called Value intended for
+// storing setting and other persistable data. It includes the ability to
+// specify (recursive) lists and dictionaries, so it's fairly expressive.
+// However, the API is optimized for the common case, namely storing a
+// hierarchical tree of simple values. Given a DictionaryValue root, you can
+// easily do things like:
//
-// root->SetString(L"global.pages.homepage", L"http://goateleporter.com");
-// std::wstring homepage = L"http://google.com"; // default/fallback value
-// root->GetString(L"global.pages.homepage", &homepage);
+// root->SetString("global.pages.homepage", "http://goateleporter.com");
+// std::string homepage = "http://google.com"; // default/fallback value
+// root->GetString("global.pages.homepage", &homepage);
//
-// where "global" and "pages" are also DictionaryValues, and "homepage"
-// is a string setting. If some elements of the path didn't exist yet,
-// the SetString() method would create the missing elements and attach them
-// to root before attaching the homepage value.
+// where "global" and "pages" are also DictionaryValues, and "homepage" is a
+// string setting. If some elements of the path didn't exist yet, the
+// SetString() method would create the missing elements and attach them to root
+// before attaching the homepage value.
#ifndef BASE_VALUES_H_
#define BASE_VALUES_H_
+#pragma once
#include <iterator>
#include <map>
@@ -38,7 +39,7 @@ class DictionaryValue;
class ListValue;
typedef std::vector<Value*> ValueVector;
-typedef std::map<std::wstring, Value*> ValueMap;
+typedef std::map<std::string, Value*> ValueMap;
// The Value class is the base class for Values. A Value can be
// instantiated via the Create*Value() factory methods, or by directly
@@ -55,8 +56,7 @@ class Value {
static Value* CreateIntegerValue(int in_value);
static Value* CreateRealValue(double in_value);
static Value* CreateStringValue(const std::string& in_value);
- static Value* CreateStringValue(const std::wstring& in_value);
- static Value* CreateStringValueFromUTF16(const string16& in_value);
+ static Value* CreateStringValue(const string16& in_value);
// This one can return NULL if the input isn't valid. If the return value
// is non-null, the new object has taken ownership of the buffer pointer.
@@ -91,8 +91,7 @@ class Value {
virtual bool GetAsInteger(int* out_value) const;
virtual bool GetAsReal(double* out_value) const;
virtual bool GetAsString(std::string* out_value) const;
- virtual bool GetAsString(std::wstring* out_value) const;
- virtual bool GetAsUTF16(string16* out_value) const;
+ virtual bool GetAsString(string16* out_value) const;
// 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.
@@ -144,20 +143,14 @@ class StringValue : public Value {
// Initializes a StringValue with a UTF-8 narrow character string.
explicit StringValue(const std::string& in_value);
- // Initializes a StringValue with a wide character string.
- explicit StringValue(const std::wstring& in_value);
-
-#if !defined(WCHAR_T_IS_UTF16)
// Initializes a StringValue with a string16.
explicit StringValue(const string16& in_value);
-#endif
~StringValue();
// Subclassed methods
bool GetAsString(std::string* out_value) const;
- bool GetAsString(std::wstring* out_value) const;
- bool GetAsUTF16(string16* out_value) const;
+ bool GetAsString(string16* out_value) const;
Value* DeepCopy() const;
virtual bool Equals(const Value* other) const;
@@ -201,6 +194,9 @@ class BinaryValue: public Value {
DISALLOW_COPY_AND_ASSIGN(BinaryValue);
};
+// DictionaryValue provides a key-value dictionary with (optional) "path"
+// parsing for recursive access; see the comment at the top of the file. Keys
+// are |std::string|s and should be UTF-8 encoded.
class DictionaryValue : public Value {
public:
DictionaryValue();
@@ -211,10 +207,7 @@ class DictionaryValue : public Value {
virtual bool Equals(const Value* other) const;
// Returns true if the current dictionary has a value for the given key.
- bool HasKeyASCII(const std::string& key) const;
- // Deprecated version of the above. TODO: add a string16 version for Unicode.
- // http://code.google.com/p/chromium/issues/detail?id=23581
- bool HasKey(const std::wstring& key) const;
+ bool HasKey(const std::string& key) const;
// Returns the number of Values in this dictionary.
size_t size() const { return dictionary_.size(); }
@@ -234,20 +227,19 @@ class DictionaryValue : public Value {
// to the path in that location.
// Note that the dictionary takes ownership of the value referenced by
// |in_value|, and therefore |in_value| must be non-NULL.
- void Set(const std::wstring& path, Value* in_value);
+ void Set(const std::string& path, Value* in_value);
// Convenience forms of Set(). These methods will replace any existing
// value at that path, even if it has a different type.
- void SetBoolean(const std::wstring& path, bool in_value);
- void SetInteger(const std::wstring& path, int in_value);
- void SetReal(const std::wstring& path, double in_value);
- void SetString(const std::wstring& path, const std::string& in_value);
- void SetString(const std::wstring& path, const std::wstring& in_value);
- void SetStringFromUTF16(const std::wstring& path, const string16& in_value);
+ void SetBoolean(const std::string& path, bool in_value);
+ void SetInteger(const std::string& path, int in_value);
+ void SetReal(const std::string& path, double in_value);
+ void SetString(const std::string& path, const std::string& in_value);
+ void SetString(const std::string& path, const string16& in_value);
// Like Set(), but without special treatment of '.'. This allows e.g. URLs to
// be used as paths.
- void SetWithoutPathExpansion(const std::wstring& key, Value* in_value);
+ void SetWithoutPathExpansion(const std::string& key, Value* in_value);
// Gets the Value associated with the given path starting from this object.
// A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
@@ -256,41 +248,35 @@ class DictionaryValue : public Value {
// through the |out_value| parameter, and the function will return true.
// Otherwise, it will return false and |out_value| will be untouched.
// Note that the dictionary always owns the value that's returned.
- bool Get(const std::wstring& path, Value** out_value) const;
+ bool Get(const std::string& path, Value** out_value) const;
// These are convenience forms of Get(). The value will be retrieved
// and the return value will be true if the path is valid and the value at
// the end of the path can be returned in the form specified.
- bool GetBoolean(const std::wstring& path, bool* out_value) const;
- bool GetInteger(const std::wstring& path, int* out_value) const;
- bool GetReal(const std::wstring& path, double* out_value) const;
+ bool GetBoolean(const std::string& path, bool* out_value) const;
+ bool GetInteger(const std::string& path, int* out_value) const;
+ bool GetReal(const std::string& path, double* out_value) const;
+ bool GetString(const std::string& path, std::string* out_value) const;
bool GetString(const std::string& path, string16* out_value) const;
bool GetStringASCII(const std::string& path, std::string* out_value) const;
- // TODO: deprecate wstring accessors.
- // http://code.google.com/p/chromium/issues/detail?id=23581
- bool GetString(const std::wstring& path, std::string* out_value) const;
- bool GetString(const std::wstring& path, std::wstring* out_value) const;
- bool GetStringAsUTF16(const std::wstring& path, string16* out_value) const;
- bool GetBinary(const std::wstring& path, BinaryValue** out_value) const;
- bool GetDictionary(const std::wstring& path,
+ bool GetBinary(const std::string& path, BinaryValue** out_value) const;
+ bool GetDictionary(const std::string& path,
DictionaryValue** out_value) const;
- bool GetList(const std::wstring& path, ListValue** out_value) const;
+ bool GetList(const std::string& path, ListValue** out_value) const;
// Like Get(), but without special treatment of '.'. This allows e.g. URLs to
// be used as paths.
- bool GetWithoutPathExpansion(const std::wstring& key,
+ bool GetWithoutPathExpansion(const std::string& key,
Value** out_value) const;
- bool GetIntegerWithoutPathExpansion(const std::wstring& path,
+ bool GetIntegerWithoutPathExpansion(const std::string& key,
int* out_value) const;
- bool GetStringWithoutPathExpansion(const std::wstring& path,
+ bool GetStringWithoutPathExpansion(const std::string& key,
std::string* out_value) const;
- bool GetStringWithoutPathExpansion(const std::wstring& path,
- std::wstring* out_value) const;
- bool GetStringAsUTF16WithoutPathExpansion(const std::wstring& path,
- string16* out_value) const;
- bool GetDictionaryWithoutPathExpansion(const std::wstring& path,
+ bool GetStringWithoutPathExpansion(const std::string& key,
+ string16* out_value) const;
+ bool GetDictionaryWithoutPathExpansion(const std::string& key,
DictionaryValue** out_value) const;
- bool GetListWithoutPathExpansion(const std::wstring& path,
+ bool GetListWithoutPathExpansion(const std::string& key,
ListValue** out_value) const;
// Removes the Value with the specified path from this dictionary (or one
@@ -299,11 +285,11 @@ class DictionaryValue : public Value {
// passed out via out_value. If |out_value| is NULL, the removed value will
// be deleted. This method returns true if |path| is a valid path; otherwise
// it will return false and the DictionaryValue object will be unchanged.
- bool Remove(const std::wstring& path, Value** out_value);
+ bool Remove(const std::string& path, Value** out_value);
// Like Remove(), but without special treatment of '.'. This allows e.g. URLs
// to be used as paths.
- bool RemoveWithoutPathExpansion(const std::wstring& key, Value** out_value);
+ bool RemoveWithoutPathExpansion(const std::string& key, Value** out_value);
// Makes a copy of |this| but doesn't include empty dictionaries and lists in
// the copy. This never returns NULL, even if |this| itself is empty.
@@ -315,6 +301,16 @@ 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.
//
@@ -322,14 +318,14 @@ class DictionaryValue : public Value {
// THE NORMAL XXX() APIs. This makes sure things will work correctly if any
// keys have '.'s in them.
class key_iterator
- : private std::iterator<std::input_iterator_tag, const std::wstring> {
+ : private std::iterator<std::input_iterator_tag, const std::string> {
public:
explicit key_iterator(ValueMap::const_iterator itr) { itr_ = itr; }
key_iterator operator++() {
++itr_;
return *this;
}
- const std::wstring& operator*() { return itr_->first; }
+ const std::string& operator*() { return itr_->first; }
bool operator!=(const key_iterator& other) { return itr_ != other.itr_; }
bool operator==(const key_iterator& other) { return itr_ == other.itr_; }
@@ -341,6 +337,17 @@ 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);
@@ -384,8 +391,7 @@ class ListValue : public Value {
bool GetInteger(size_t index, int* out_value) const;
bool GetReal(size_t index, double* out_value) const;
bool GetString(size_t index, std::string* out_value) const;
- bool GetString(size_t index, std::wstring* out_value) const;
- bool GetStringAsUTF16(size_t index, string16* out_value) const;
+ bool GetString(size_t index, string16* out_value) const;
bool GetBinary(size_t index, BinaryValue** out_value) const;
bool GetDictionary(size_t index, DictionaryValue** out_value) const;
bool GetList(size_t index, ListValue** out_value) const;
@@ -412,6 +418,11 @@ class ListValue : public Value {
// Returns true if successful, or false if the index was out of range.
bool Insert(size_t index, Value* in_value);
+ // Swaps contents with the |other| list.
+ void Swap(ListValue* other) {
+ list_.swap(other->list_);
+ }
+
// Iteration
typedef ValueVector::iterator iterator;
typedef ValueVector::const_iterator const_iterator;
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 8aa8359..c1fb018 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -5,60 +5,78 @@
#include <limits>
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#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()));
+ }
};
-TEST(ValuesTest, Basic) {
+TEST_F(ValuesTest, Basic) {
// Test basic dictionary getting/setting
DictionaryValue settings;
- std::wstring homepage = L"http://google.com";
- ASSERT_FALSE(
- settings.GetString(L"global.homepage", &homepage));
- ASSERT_EQ(std::wstring(L"http://google.com"), homepage);
-
- ASSERT_FALSE(settings.Get(L"global", NULL));
- settings.Set(L"global", Value::CreateBooleanValue(true));
- ASSERT_TRUE(settings.Get(L"global", NULL));
- settings.SetString(L"global.homepage", L"http://scurvy.com");
- ASSERT_TRUE(settings.Get(L"global", NULL));
- homepage = L"http://google.com";
- ASSERT_TRUE(settings.GetString(L"global.homepage", &homepage));
- ASSERT_EQ(std::wstring(L"http://scurvy.com"), homepage);
+ std::string homepage = "http://google.com";
+ ASSERT_FALSE(settings.GetString("global.homepage", &homepage));
+ ASSERT_EQ(std::string("http://google.com"), homepage);
+
+ ASSERT_FALSE(settings.Get("global", NULL));
+ settings.Set("global", Value::CreateBooleanValue(true));
+ ASSERT_TRUE(settings.Get("global", NULL));
+ settings.SetString("global.homepage", "http://scurvy.com");
+ ASSERT_TRUE(settings.Get("global", NULL));
+ homepage = "http://google.com";
+ ASSERT_TRUE(settings.GetString("global.homepage", &homepage));
+ ASSERT_EQ(std::string("http://scurvy.com"), homepage);
// Test storing a dictionary in a list.
ListValue* toolbar_bookmarks;
ASSERT_FALSE(
- settings.GetList(L"global.toolbar.bookmarks", &toolbar_bookmarks));
+ settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
toolbar_bookmarks = new ListValue;
- settings.Set(L"global.toolbar.bookmarks", toolbar_bookmarks);
- ASSERT_TRUE(
- settings.GetList(L"global.toolbar.bookmarks", &toolbar_bookmarks));
+ settings.Set("global.toolbar.bookmarks", toolbar_bookmarks);
+ ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
DictionaryValue* new_bookmark = new DictionaryValue;
- new_bookmark->SetString(L"name", L"Froogle");
- new_bookmark->SetString(L"url", L"http://froogle.com");
+ new_bookmark->SetString("name", "Froogle");
+ new_bookmark->SetString("url", "http://froogle.com");
toolbar_bookmarks->Append(new_bookmark);
ListValue* bookmark_list;
- ASSERT_TRUE(settings.GetList(L"global.toolbar.bookmarks", &bookmark_list));
+ ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list));
DictionaryValue* bookmark;
ASSERT_EQ(1U, bookmark_list->GetSize());
ASSERT_TRUE(bookmark_list->GetDictionary(0, &bookmark));
- std::wstring bookmark_name = L"Unnamed";
- ASSERT_TRUE(bookmark->GetString(L"name", &bookmark_name));
- ASSERT_EQ(std::wstring(L"Froogle"), bookmark_name);
- std::wstring bookmark_url;
- ASSERT_TRUE(bookmark->GetString(L"url", &bookmark_url));
- ASSERT_EQ(std::wstring(L"http://froogle.com"), bookmark_url);
+ std::string bookmark_name = "Unnamed";
+ ASSERT_TRUE(bookmark->GetString("name", &bookmark_name));
+ ASSERT_EQ(std::string("Froogle"), bookmark_name);
+ std::string bookmark_url;
+ ASSERT_TRUE(bookmark->GetString("url", &bookmark_url));
+ ASSERT_EQ(std::string("http://froogle.com"), bookmark_url);
}
-TEST(ValuesTest, List) {
+TEST_F(ValuesTest, List) {
scoped_ptr<ListValue> mixed_list(new ListValue());
mixed_list->Set(0, Value::CreateBooleanValue(true));
mixed_list->Set(1, Value::CreateIntegerValue(42));
@@ -93,7 +111,7 @@ TEST(ValuesTest, List) {
ASSERT_EQ("foo", string_value);
}
-TEST(ValuesTest, BinaryValue) {
+TEST_F(ValuesTest, BinaryValue) {
char* buffer = NULL;
// Passing a null buffer pointer doesn't yield a BinaryValue
scoped_ptr<BinaryValue> binary(BinaryValue::Create(buffer, 0));
@@ -126,42 +144,27 @@ TEST(ValuesTest, BinaryValue) {
ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize()));
}
-TEST(ValuesTest, StringValue) {
+TEST_F(ValuesTest, StringValue) {
// Test overloaded CreateStringValue.
scoped_ptr<Value> narrow_value(Value::CreateStringValue("narrow"));
ASSERT_TRUE(narrow_value.get());
ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING));
- scoped_ptr<Value> wide_value(Value::CreateStringValue(L"wide"));
- ASSERT_TRUE(wide_value.get());
- ASSERT_TRUE(wide_value->IsType(Value::TYPE_STRING));
scoped_ptr<Value> utf16_value(
- Value::CreateStringValueFromUTF16(ASCIIToUTF16("utf16")));
+ Value::CreateStringValue(ASCIIToUTF16("utf16")));
ASSERT_TRUE(utf16_value.get());
ASSERT_TRUE(utf16_value->IsType(Value::TYPE_STRING));
// Test overloaded GetString.
std::string narrow = "http://google.com";
- std::wstring wide = L"http://google.com";
string16 utf16 = ASCIIToUTF16("http://google.com");
ASSERT_TRUE(narrow_value->GetAsString(&narrow));
- ASSERT_TRUE(narrow_value->GetAsString(&wide));
- ASSERT_TRUE(narrow_value->GetAsUTF16(&utf16));
+ ASSERT_TRUE(narrow_value->GetAsString(&utf16));
ASSERT_EQ(std::string("narrow"), narrow);
- ASSERT_EQ(std::wstring(L"narrow"), wide);
ASSERT_EQ(ASCIIToUTF16("narrow"), utf16);
- ASSERT_TRUE(wide_value->GetAsString(&narrow));
- ASSERT_TRUE(wide_value->GetAsString(&wide));
- ASSERT_TRUE(wide_value->GetAsUTF16(&utf16));
- ASSERT_EQ(std::string("wide"), narrow);
- ASSERT_EQ(std::wstring(L"wide"), wide);
- ASSERT_EQ(ASCIIToUTF16("wide"), utf16);
-
ASSERT_TRUE(utf16_value->GetAsString(&narrow));
- ASSERT_TRUE(utf16_value->GetAsString(&wide));
- ASSERT_TRUE(utf16_value->GetAsUTF16(&utf16));
+ ASSERT_TRUE(utf16_value->GetAsString(&utf16));
ASSERT_EQ(std::string("utf16"), narrow);
- ASSERT_EQ(std::wstring(L"utf16"), wide);
ASSERT_EQ(ASCIIToUTF16("utf16"), utf16);
}
@@ -187,7 +190,7 @@ class DeletionTestValue : public Value {
bool* deletion_flag_;
};
-TEST(ValuesTest, ListDeletion) {
+TEST_F(ValuesTest, ListDeletion) {
bool deletion_flag = true;
{
@@ -214,7 +217,7 @@ TEST(ValuesTest, ListDeletion) {
}
}
-TEST(ValuesTest, ListRemoval) {
+TEST_F(ValuesTest, ListRemoval) {
bool deletion_flag = true;
Value* removed_item = NULL;
@@ -255,8 +258,8 @@ TEST(ValuesTest, ListRemoval) {
}
}
-TEST(ValuesTest, DictionaryDeletion) {
- std::wstring key = L"test";
+TEST_F(ValuesTest, DictionaryDeletion) {
+ std::string key = "test";
bool deletion_flag = true;
{
@@ -283,8 +286,8 @@ TEST(ValuesTest, DictionaryDeletion) {
}
}
-TEST(ValuesTest, DictionaryRemoval) {
- std::wstring key = L"test";
+TEST_F(ValuesTest, DictionaryRemoval) {
+ std::string key = "test";
bool deletion_flag = true;
Value* removed_item = NULL;
@@ -293,7 +296,7 @@ TEST(ValuesTest, DictionaryRemoval) {
dict.Set(key, new DeletionTestValue(&deletion_flag));
EXPECT_FALSE(deletion_flag);
EXPECT_TRUE(dict.HasKey(key));
- EXPECT_FALSE(dict.Remove(L"absent key", &removed_item));
+ EXPECT_FALSE(dict.Remove("absent key", &removed_item));
EXPECT_TRUE(dict.Remove(key, &removed_item));
EXPECT_FALSE(dict.HasKey(key));
ASSERT_TRUE(removed_item);
@@ -314,57 +317,54 @@ TEST(ValuesTest, DictionaryRemoval) {
}
}
-TEST(ValuesTest, DictionaryWithoutPathExpansion) {
+TEST_F(ValuesTest, DictionaryWithoutPathExpansion) {
DictionaryValue dict;
- dict.Set(L"this.is.expanded", Value::CreateNullValue());
- dict.SetWithoutPathExpansion(L"this.isnt.expanded", Value::CreateNullValue());
+ dict.Set("this.is.expanded", Value::CreateNullValue());
+ dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue());
- EXPECT_FALSE(dict.HasKey(L"this.is.expanded"));
- EXPECT_TRUE(dict.HasKey(L"this"));
+ EXPECT_FALSE(dict.HasKey("this.is.expanded"));
+ EXPECT_TRUE(dict.HasKey("this"));
Value* value1;
- EXPECT_TRUE(dict.Get(L"this", &value1));
+ EXPECT_TRUE(dict.Get("this", &value1));
DictionaryValue* value2;
- ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion(L"this", &value2));
+ ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2));
EXPECT_EQ(value1, value2);
EXPECT_EQ(1U, value2->size());
- EXPECT_TRUE(dict.HasKey(L"this.isnt.expanded"));
+ EXPECT_TRUE(dict.HasKey("this.isnt.expanded"));
Value* value3;
- EXPECT_FALSE(dict.Get(L"this.isnt.expanded", &value3));
+ EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3));
Value* value4;
- ASSERT_TRUE(dict.GetWithoutPathExpansion(L"this.isnt.expanded", &value4));
+ ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4));
EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
}
-TEST(ValuesTest, DeepCopy) {
+TEST_F(ValuesTest, DeepCopy) {
DictionaryValue original_dict;
Value* original_null = Value::CreateNullValue();
- original_dict.Set(L"null", original_null);
+ original_dict.Set("null", original_null);
Value* original_bool = Value::CreateBooleanValue(true);
- original_dict.Set(L"bool", original_bool);
+ original_dict.Set("bool", original_bool);
Value* original_int = Value::CreateIntegerValue(42);
- original_dict.Set(L"int", original_int);
+ original_dict.Set("int", original_int);
Value* original_real = Value::CreateRealValue(3.14);
- original_dict.Set(L"real", original_real);
+ original_dict.Set("real", original_real);
Value* original_string = Value::CreateStringValue("hello");
- original_dict.Set(L"string", original_string);
- Value* original_wstring = Value::CreateStringValue(L"peek-a-boo");
- original_dict.Set(L"wstring", original_wstring);
- Value* original_utf16 =
- Value::CreateStringValueFromUTF16(ASCIIToUTF16("hello16"));
- original_dict.Set(L"utf16", original_utf16);
+ original_dict.Set("string", original_string);
+ Value* original_string16 = Value::CreateStringValue(ASCIIToUTF16("hello16"));
+ original_dict.Set("string16", original_string16);
char* original_buffer = new char[42];
memset(original_buffer, '!', 42);
BinaryValue* original_binary = Value::CreateBinaryValue(original_buffer, 42);
- original_dict.Set(L"binary", original_binary);
+ original_dict.Set("binary", original_binary);
ListValue* original_list = new ListValue();
Value* original_list_element_0 = Value::CreateIntegerValue(0);
original_list->Append(original_list_element_0);
Value* original_list_element_1 = Value::CreateIntegerValue(1);
original_list->Append(original_list_element_1);
- original_dict.Set(L"list", original_list);
+ original_dict.Set("list", original_list);
scoped_ptr<DictionaryValue> copy_dict(
static_cast<DictionaryValue*>(original_dict.DeepCopy()));
@@ -372,13 +372,13 @@ TEST(ValuesTest, DeepCopy) {
ASSERT_NE(copy_dict.get(), &original_dict);
Value* copy_null = NULL;
- ASSERT_TRUE(copy_dict->Get(L"null", &copy_null));
+ ASSERT_TRUE(copy_dict->Get("null", &copy_null));
ASSERT_TRUE(copy_null);
ASSERT_NE(copy_null, original_null);
ASSERT_TRUE(copy_null->IsType(Value::TYPE_NULL));
Value* copy_bool = NULL;
- ASSERT_TRUE(copy_dict->Get(L"bool", &copy_bool));
+ ASSERT_TRUE(copy_dict->Get("bool", &copy_bool));
ASSERT_TRUE(copy_bool);
ASSERT_NE(copy_bool, original_bool);
ASSERT_TRUE(copy_bool->IsType(Value::TYPE_BOOLEAN));
@@ -387,7 +387,7 @@ TEST(ValuesTest, DeepCopy) {
ASSERT_TRUE(copy_bool_value);
Value* copy_int = NULL;
- ASSERT_TRUE(copy_dict->Get(L"int", &copy_int));
+ ASSERT_TRUE(copy_dict->Get("int", &copy_int));
ASSERT_TRUE(copy_int);
ASSERT_NE(copy_int, original_int);
ASSERT_TRUE(copy_int->IsType(Value::TYPE_INTEGER));
@@ -396,7 +396,7 @@ TEST(ValuesTest, DeepCopy) {
ASSERT_EQ(42, copy_int_value);
Value* copy_real = NULL;
- ASSERT_TRUE(copy_dict->Get(L"real", &copy_real));
+ ASSERT_TRUE(copy_dict->Get("real", &copy_real));
ASSERT_TRUE(copy_real);
ASSERT_NE(copy_real, original_real);
ASSERT_TRUE(copy_real->IsType(Value::TYPE_REAL));
@@ -405,46 +405,29 @@ TEST(ValuesTest, DeepCopy) {
ASSERT_EQ(3.14, copy_real_value);
Value* copy_string = NULL;
- ASSERT_TRUE(copy_dict->Get(L"string", &copy_string));
+ ASSERT_TRUE(copy_dict->Get("string", &copy_string));
ASSERT_TRUE(copy_string);
ASSERT_NE(copy_string, original_string);
ASSERT_TRUE(copy_string->IsType(Value::TYPE_STRING));
std::string copy_string_value;
- std::wstring copy_wstring_value;
- string16 copy_utf16_value;
+ string16 copy_string16_value;
ASSERT_TRUE(copy_string->GetAsString(&copy_string_value));
- ASSERT_TRUE(copy_string->GetAsString(&copy_wstring_value));
- ASSERT_TRUE(copy_string->GetAsUTF16(&copy_utf16_value));
+ ASSERT_TRUE(copy_string->GetAsString(&copy_string16_value));
ASSERT_EQ(std::string("hello"), copy_string_value);
- ASSERT_EQ(std::wstring(L"hello"), copy_wstring_value);
- ASSERT_EQ(ASCIIToUTF16("hello"), copy_utf16_value);
-
- Value* copy_wstring = NULL;
- ASSERT_TRUE(copy_dict->Get(L"wstring", &copy_wstring));
- ASSERT_TRUE(copy_wstring);
- ASSERT_NE(copy_wstring, original_wstring);
- ASSERT_TRUE(copy_wstring->IsType(Value::TYPE_STRING));
- ASSERT_TRUE(copy_wstring->GetAsString(&copy_string_value));
- ASSERT_TRUE(copy_wstring->GetAsString(&copy_wstring_value));
- ASSERT_TRUE(copy_wstring->GetAsUTF16(&copy_utf16_value));
- ASSERT_EQ(std::string("peek-a-boo"), copy_string_value);
- ASSERT_EQ(std::wstring(L"peek-a-boo"), copy_wstring_value);
- ASSERT_EQ(ASCIIToUTF16("peek-a-boo"), copy_utf16_value);
-
- Value* copy_utf16 = NULL;
- ASSERT_TRUE(copy_dict->Get(L"utf16", &copy_utf16));
- ASSERT_TRUE(copy_utf16);
- ASSERT_NE(copy_utf16, original_utf16);
- ASSERT_TRUE(copy_utf16->IsType(Value::TYPE_STRING));
- ASSERT_TRUE(copy_utf16->GetAsString(&copy_string_value));
- ASSERT_TRUE(copy_utf16->GetAsString(&copy_wstring_value));
- ASSERT_TRUE(copy_utf16->GetAsUTF16(&copy_utf16_value));
+ ASSERT_EQ(ASCIIToUTF16("hello"), copy_string16_value);
+
+ Value* copy_string16 = NULL;
+ ASSERT_TRUE(copy_dict->Get("string16", &copy_string16));
+ ASSERT_TRUE(copy_string16);
+ ASSERT_NE(copy_string16, original_string16);
+ ASSERT_TRUE(copy_string16->IsType(Value::TYPE_STRING));
+ ASSERT_TRUE(copy_string16->GetAsString(&copy_string_value));
+ ASSERT_TRUE(copy_string16->GetAsString(&copy_string16_value));
ASSERT_EQ(std::string("hello16"), copy_string_value);
- ASSERT_EQ(std::wstring(L"hello16"), copy_wstring_value);
- ASSERT_EQ(ASCIIToUTF16("hello16"), copy_utf16_value);
+ ASSERT_EQ(ASCIIToUTF16("hello16"), copy_string16_value);
Value* copy_binary = NULL;
- ASSERT_TRUE(copy_dict->Get(L"binary", &copy_binary));
+ ASSERT_TRUE(copy_dict->Get("binary", &copy_binary));
ASSERT_TRUE(copy_binary);
ASSERT_NE(copy_binary, original_binary);
ASSERT_TRUE(copy_binary->IsType(Value::TYPE_BINARY));
@@ -457,7 +440,7 @@ TEST(ValuesTest, DeepCopy) {
original_binary->GetSize()));
Value* copy_value = NULL;
- ASSERT_TRUE(copy_dict->Get(L"list", &copy_value));
+ ASSERT_TRUE(copy_dict->Get("list", &copy_value));
ASSERT_TRUE(copy_value);
ASSERT_NE(copy_value, original_list);
ASSERT_TRUE(copy_value->IsType(Value::TYPE_LIST));
@@ -481,7 +464,7 @@ TEST(ValuesTest, DeepCopy) {
ASSERT_EQ(1, copy_list_element_1_value);
}
-TEST(ValuesTest, Equals) {
+TEST_F(ValuesTest, Equals) {
Value* null1 = Value::CreateNullValue();
Value* null2 = Value::CreateNullValue();
EXPECT_NE(null1, null2);
@@ -494,43 +477,50 @@ TEST(ValuesTest, Equals) {
delete boolean;
DictionaryValue dv;
- dv.SetBoolean(L"a", false);
- dv.SetInteger(L"b", 2);
- dv.SetReal(L"c", 2.5);
- dv.SetString(L"d1", "string");
- dv.SetString(L"d2", L"string");
- dv.Set(L"e", Value::CreateNullValue());
+ dv.SetBoolean("a", false);
+ dv.SetInteger("b", 2);
+ dv.SetReal("c", 2.5);
+ dv.SetString("d1", "string");
+ dv.SetString("d2", ASCIIToUTF16("http://google.com"));
+ dv.Set("e", Value::CreateNullValue());
- DictionaryValue* copy = static_cast<DictionaryValue*>(dv.DeepCopy());
- EXPECT_TRUE(dv.Equals(copy));
+ scoped_ptr<DictionaryValue> copy;
+ copy.reset(static_cast<DictionaryValue*>(dv.DeepCopy()));
+ EXPECT_TRUE(dv.Equals(copy.get()));
ListValue* list = new ListValue;
list->Append(Value::CreateNullValue());
list->Append(new DictionaryValue);
- dv.Set(L"f", list);
+ dv.Set("f", list);
- EXPECT_FALSE(dv.Equals(copy));
- copy->Set(L"f", list->DeepCopy());
- EXPECT_TRUE(dv.Equals(copy));
+ EXPECT_FALSE(dv.Equals(copy.get()));
+ copy->Set("f", list->DeepCopy());
+ EXPECT_TRUE(dv.Equals(copy.get()));
list->Append(Value::CreateBooleanValue(true));
- EXPECT_FALSE(dv.Equals(copy));
- delete copy;
+ EXPECT_FALSE(dv.Equals(copy.get()));
+
+ // Check if Equals detects differences in only the keys.
+ copy.reset(static_cast<DictionaryValue*>(dv.DeepCopy()));
+ EXPECT_TRUE(dv.Equals(copy.get()));
+ copy->Remove("a", NULL);
+ copy->SetBoolean("aa", false);
+ EXPECT_FALSE(dv.Equals(copy.get()));
}
-TEST(ValuesTest, RemoveEmptyChildren) {
+TEST_F(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<DictionaryValue> root(new DictionaryValue);
// Remove empty lists and dictionaries.
- root->Set(L"empty_dict", new DictionaryValue);
- root->Set(L"empty_list", new ListValue);
- root->SetWithoutPathExpansion(L"a.b.c.d.e", new DictionaryValue);
+ root->Set("empty_dict", new DictionaryValue);
+ root->Set("empty_list", new ListValue);
+ root->SetWithoutPathExpansion("a.b.c.d.e", new DictionaryValue);
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_TRUE(root->empty());
// Make sure we don't prune too much.
- root->SetBoolean(L"bool", true);
- root->Set(L"empty_dict", new DictionaryValue);
- root->SetString(L"empty_string", "");
+ root->SetBoolean("bool", true);
+ root->Set("empty_dict", new DictionaryValue);
+ root->SetString("empty_string", "");
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
@@ -541,21 +531,21 @@ TEST(ValuesTest, RemoveEmptyChildren) {
// Nested test cases. These should all reduce back to the bool and string
// set above.
{
- root->Set(L"a.b.c.d.e", new DictionaryValue);
+ root->Set("a.b.c.d.e", new DictionaryValue);
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
}
{
DictionaryValue* inner = new DictionaryValue;
- root->Set(L"dict_with_emtpy_children", inner);
- inner->Set(L"empty_dict", new DictionaryValue);
- inner->Set(L"empty_list", new ListValue);
+ root->Set("dict_with_emtpy_children", inner);
+ inner->Set("empty_dict", new DictionaryValue);
+ inner->Set("empty_list", new ListValue);
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
}
{
ListValue* inner = new ListValue;
- root->Set(L"list_with_empty_children", inner);
+ root->Set("list_with_empty_children", inner);
inner->Append(new DictionaryValue);
inner->Append(new ListValue);
root.reset(root->DeepCopyWithoutEmptyChildren());
@@ -565,13 +555,13 @@ TEST(ValuesTest, RemoveEmptyChildren) {
// Nested with siblings.
{
ListValue* inner = new ListValue;
- root->Set(L"list_with_empty_children", inner);
+ root->Set("list_with_empty_children", inner);
inner->Append(new DictionaryValue);
inner->Append(new ListValue);
DictionaryValue* inner2 = new DictionaryValue;
- root->Set(L"dict_with_empty_children", inner2);
- inner2->Set(L"empty_dict", new DictionaryValue);
- inner2->Set(L"empty_list", new ListValue);
+ root->Set("dict_with_empty_children", inner2);
+ inner2->Set("empty_dict", new DictionaryValue);
+ inner2->Set("empty_list", new ListValue);
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(2U, root->size());
}
@@ -579,61 +569,172 @@ TEST(ValuesTest, RemoveEmptyChildren) {
// Make sure nested values don't get pruned.
{
ListValue* inner = new ListValue;
- root->Set(L"list_with_empty_children", inner);
+ root->Set("list_with_empty_children", inner);
ListValue* inner2 = new ListValue;
inner->Append(new DictionaryValue);
inner->Append(inner2);
inner2->Append(Value::CreateStringValue("hello"));
root.reset(root->DeepCopyWithoutEmptyChildren());
EXPECT_EQ(3U, root->size());
- EXPECT_TRUE(root->GetList(L"list_with_empty_children", &inner));
+ EXPECT_TRUE(root->GetList("list_with_empty_children", &inner));
EXPECT_EQ(1U, inner->GetSize()); // Dictionary was pruned.
EXPECT_TRUE(inner->GetList(0, &inner2));
EXPECT_EQ(1U, inner2->GetSize());
}
}
-TEST(ValuesTest, MergeDictionary) {
+TEST_F(ValuesTest, MergeDictionary) {
scoped_ptr<DictionaryValue> base(new DictionaryValue);
- base->SetString(L"base_key", "base_key_value_base");
- base->SetString(L"collide_key", "collide_key_value_base");
+ base->SetString("base_key", "base_key_value_base");
+ base->SetString("collide_key", "collide_key_value_base");
DictionaryValue* base_sub_dict = new DictionaryValue;
- base_sub_dict->SetString(L"sub_base_key", "sub_base_key_value_base");
- base_sub_dict->SetString(L"sub_collide_key", "sub_collide_key_value_base");
- base->Set(L"sub_dict_key", base_sub_dict);
+ base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
+ base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
+ base->Set("sub_dict_key", base_sub_dict);
scoped_ptr<DictionaryValue> merge(new DictionaryValue);
- merge->SetString(L"merge_key", "merge_key_value_merge");
- merge->SetString(L"collide_key", "collide_key_value_merge");
+ merge->SetString("merge_key", "merge_key_value_merge");
+ merge->SetString("collide_key", "collide_key_value_merge");
DictionaryValue* merge_sub_dict = new DictionaryValue;
- merge_sub_dict->SetString(L"sub_merge_key", "sub_merge_key_value_merge");
- merge_sub_dict->SetString(L"sub_collide_key", "sub_collide_key_value_merge");
- merge->Set(L"sub_dict_key", merge_sub_dict);
+ merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
+ merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
+ merge->Set("sub_dict_key", merge_sub_dict);
base->MergeDictionary(merge.get());
EXPECT_EQ(4U, base->size());
std::string base_key_value;
- EXPECT_TRUE(base->GetString(L"base_key", &base_key_value));
+ EXPECT_TRUE(base->GetString("base_key", &base_key_value));
EXPECT_EQ("base_key_value_base", base_key_value); // Base value preserved.
std::string collide_key_value;
- EXPECT_TRUE(base->GetString(L"collide_key", &collide_key_value));
+ EXPECT_TRUE(base->GetString("collide_key", &collide_key_value));
EXPECT_EQ("collide_key_value_merge", collide_key_value); // Replaced.
std::string merge_key_value;
- EXPECT_TRUE(base->GetString(L"merge_key", &merge_key_value));
+ EXPECT_TRUE(base->GetString("merge_key", &merge_key_value));
EXPECT_EQ("merge_key_value_merge", merge_key_value); // Merged in.
DictionaryValue* res_sub_dict;
- EXPECT_TRUE(base->GetDictionary(L"sub_dict_key", &res_sub_dict));
+ EXPECT_TRUE(base->GetDictionary("sub_dict_key", &res_sub_dict));
EXPECT_EQ(3U, res_sub_dict->size());
std::string sub_base_key_value;
- EXPECT_TRUE(res_sub_dict->GetString(L"sub_base_key", &sub_base_key_value));
+ EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value));
EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved.
std::string sub_collide_key_value;
- EXPECT_TRUE(res_sub_dict->GetString(L"sub_collide_key",
+ EXPECT_TRUE(res_sub_dict->GetString("sub_collide_key",
&sub_collide_key_value));
EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced.
std::string sub_merge_key_value;
- EXPECT_TRUE(res_sub_dict->GetString(L"sub_merge_key", &sub_merge_key_value));
+ 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/version.cc b/base/version.cc
index 2271fcf..8a09142 100644
--- a/base/version.cc
+++ b/base/version.cc
@@ -1,17 +1,20 @@
-// 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.
#include "base/version.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
// static
Version* Version::GetVersionFromString(const std::wstring& version_str) {
if (!IsStringASCII(version_str))
return NULL;
- return GetVersionFromString(WideToASCII(version_str));
+ return GetVersionFromString(WideToUTF8(version_str));
}
// static
@@ -60,10 +63,10 @@ const std::string Version::GetString() const {
std::string version_str;
int count = components_.size();
for (int i = 0; i < count - 1; ++i) {
- version_str.append(IntToString(components_[i]));
+ version_str.append(base::IntToString(components_[i]));
version_str.append(".");
}
- version_str.append(IntToString(components_[count - 1]));
+ version_str.append(base::IntToString(components_[count - 1]));
return version_str;
}
@@ -76,7 +79,7 @@ bool Version::InitFromString(const std::string& version_str) {
for (std::vector<std::string>::iterator i = numbers.begin();
i != numbers.end(); ++i) {
int num;
- if (!StringToInt(*i, &num))
+ if (!base::StringToInt(*i, &num))
return false;
if (num < 0)
return false;
@@ -84,7 +87,7 @@ bool Version::InitFromString(const std::string& version_str) {
if (num > max)
return false;
// This throws out things like +3, or 032.
- if (IntToString(num) != *i)
+ if (base::IntToString(num) != *i)
return false;
uint16 component = static_cast<uint16>(num);
components_.push_back(component);
diff --git a/base/version.h b/base/version.h
index 776ebe6..99e6650 100644
--- a/base/version.h
+++ b/base/version.h
@@ -4,6 +4,7 @@
#ifndef BASE_VERSION_H_
#define BASE_VERSION_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/base/vlog.cc b/base/vlog.cc
new file mode 100644
index 0000000..d6c3eb7
--- /dev/null
+++ b/base/vlog.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 "base/vlog.h"
+
+#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+
+namespace logging {
+
+const int VlogInfo::kDefaultVlogLevel = 0;
+
+VlogInfo::VlogInfo(const std::string& v_switch,
+ const std::string& vmodule_switch)
+ : max_vlog_level_(kDefaultVlogLevel) {
+ typedef std::pair<std::string, std::string> KVPair;
+ if (!base::StringToInt(v_switch, &max_vlog_level_)) {
+ LOG(WARNING) << "Parsed v switch \""
+ << v_switch << "\" as " << max_vlog_level_;
+ }
+ std::vector<KVPair> kv_pairs;
+ if (!base::SplitStringIntoKeyValuePairs(
+ vmodule_switch, '=', ',', &kv_pairs)) {
+ LOG(WARNING) << "Could not fully parse vmodule switch \""
+ << vmodule_switch << "\"";
+ }
+ for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
+ it != kv_pairs.end(); ++it) {
+ int vlog_level = kDefaultVlogLevel;
+ if (!base::StringToInt(it->second, &vlog_level)) {
+ LOG(WARNING) << "Parsed vlog level for \""
+ << it->first << "=" << it->second
+ << "\" as " << vlog_level;
+ }
+ vmodule_levels_.push_back(std::make_pair(it->first, vlog_level));
+ }
+}
+
+int VlogInfo::GetVlogLevel(const base::StringPiece& file) {
+ if (!vmodule_levels_.empty()) {
+ base::StringPiece module(file);
+ base::StringPiece::size_type last_slash_pos =
+ module.find_last_of("\\/");
+ if (last_slash_pos != base::StringPiece::npos) {
+ module.remove_prefix(last_slash_pos + 1);
+ }
+ base::StringPiece::size_type extension_start = module.find('.');
+ module = module.substr(0, extension_start);
+ static const char kInlSuffix[] = "-inl";
+ static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
+ if (module.ends_with(kInlSuffix)) {
+ module.remove_suffix(kInlSuffixLen);
+ }
+ for (std::vector<VmodulePattern>::const_iterator it =
+ vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) {
+ // TODO(akalin): Use a less-heavyweight version of MatchPattern
+ // (we can pretty much assume we're dealing with ASCII).
+ if (MatchPattern(module, it->first)) {
+ return it->second;
+ }
+ }
+ }
+ return max_vlog_level_;
+}
+
+} // namespace
diff --git a/base/vlog.h b/base/vlog.h
new file mode 100644
index 0000000..faa62ec
--- /dev/null
+++ b/base/vlog.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 BASE_VLOG_H_
+#define BASE_VLOG_H_
+#pragma once
+
+#include <cstddef>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/string_piece.h"
+
+namespace logging {
+
+// A helper class containing all the settings for vlogging.
+class VlogInfo {
+ public:
+ // |v_switch| gives the default maximal active V-logging level; 0 is
+ // the default. Normally positive values are used for V-logging
+ // levels.
+ //
+ // |vmodule_switch| gives the per-module maximal V-logging levels to
+ // override the value given by |v_switch|.
+ // E.g. "my_module=2,foo*=3" would change the logging level for all
+ // code in source files "my_module.*" and "foo*.*" ("-inl" suffixes
+ // are also disregarded for this matching).
+ VlogInfo(const std::string& v_switch,
+ const std::string& vmodule_switch);
+
+ // Returns the vlog level for a given file (usually taken from
+ // __FILE__).
+ int GetVlogLevel(const base::StringPiece& file);
+
+ static const int kDefaultVlogLevel;
+
+ private:
+ typedef std::pair<std::string, int> VmodulePattern;
+
+ int max_vlog_level_;
+ std::vector<VmodulePattern> vmodule_levels_;
+
+ DISALLOW_COPY_AND_ASSIGN(VlogInfo);
+};
+
+} // namespace logging
+
+#endif // BASE_VLOG_H_
diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc
new file mode 100644
index 0000000..bb48724
--- /dev/null
+++ b/base/vlog_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 "base/vlog.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace logging {
+
+namespace {
+
+class VlogTest : public testing::Test {
+};
+
+TEST_F(VlogTest, NoVmodule) {
+ EXPECT_EQ(0, VlogInfo("", "").GetVlogLevel("test1"));
+ EXPECT_EQ(0, VlogInfo("0", "").GetVlogLevel("test2"));
+ EXPECT_EQ(0, VlogInfo("blah", "").GetVlogLevel("test3"));
+ EXPECT_EQ(0, VlogInfo("0blah1", "").GetVlogLevel("test4"));
+ EXPECT_EQ(1, VlogInfo("1", "").GetVlogLevel("test5"));
+ EXPECT_EQ(5, VlogInfo("5", "").GetVlogLevel("test6"));
+}
+
+TEST_F(VlogTest, Vmodule) {
+ const char kVSwitch[] = "-1";
+ const char kVModuleSwitch[] =
+ "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge=5";
+ VlogInfo vlog_info(kVSwitch, kVModuleSwitch);
+ EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc"));
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc"));
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm"));
+ EXPECT_EQ(-1, vlog_info.GetVlogLevel("D:\\path\\to what/bar_unittest.m"));
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h"));
+ EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h"));
+ EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux"));
+ EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.h"));
+}
+
+#define BENCHMARK(iters, elapsed, code) \
+ do { \
+ base::TimeTicks start = base::TimeTicks::Now(); \
+ for (int i = 0; i < iters; ++i) code; \
+ base::TimeTicks end = base::TimeTicks::Now(); \
+ elapsed = end - start; \
+ double cps = iters / elapsed.InSecondsF(); \
+ LOG(INFO) << cps << " cps (" << elapsed.InSecondsF() \
+ << "s elapsed)"; \
+ } while (0)
+
+double GetSlowdown(const base::TimeDelta& base,
+ const base::TimeDelta& elapsed) {
+ return elapsed.InSecondsF() / base.InSecondsF();
+}
+
+
+TEST_F(VlogTest, Perf) {
+ const char* kVlogs[] = {
+ "/path/to/foo.cc",
+ "C:\\path\\to\\bar.h",
+ "/path/to/not-matched.mm",
+ "C:\\path\\to\\baz-inl.mm",
+ "C:\\path\\to\\qux.mm",
+ "/path/to/quux.mm",
+ "/path/to/another-not-matched.mm",
+ };
+ const int kVlogCount = arraysize(kVlogs);
+
+ base::TimeDelta null_elapsed;
+ {
+ VlogInfo null_vlog_info("", "");
+ BENCHMARK(10000000, null_elapsed, {
+ EXPECT_NE(-1, null_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
+ });
+ }
+
+ {
+ VlogInfo small_vlog_info("0", "foo=1,bar=2,baz=3,qux=4,quux=5");
+ base::TimeDelta elapsed;
+ BENCHMARK(10000000, elapsed, {
+ EXPECT_NE(-1, small_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
+ });
+ LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
+ << "x";
+ }
+
+ {
+ VlogInfo pattern_vlog_info("0", "fo*=1,ba?=2,b*?z=3,*ux=4,?uux=5");
+ base::TimeDelta elapsed;
+ BENCHMARK(10000000, elapsed, {
+ EXPECT_NE(-1, pattern_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
+ });
+ LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
+ << "x";
+ }
+}
+
+#undef BENCHMARK
+
+} // namespace
+
+} // namespace logging
diff --git a/base/waitable_event.h b/base/waitable_event.h
index 8f5962f..081ad66 100644
--- a/base/waitable_event.h
+++ b/base/waitable_event.h
@@ -4,6 +4,7 @@
#ifndef BASE_WAITABLE_EVENT_H_
#define BASE_WAITABLE_EVENT_H_
+#pragma once
#include "base/basictypes.h"
@@ -143,10 +144,8 @@ class WaitableEvent {
struct WaitableEventKernel :
public RefCountedThreadSafe<WaitableEventKernel> {
public:
- WaitableEventKernel(bool manual_reset, bool initially_signaled)
- : manual_reset_(manual_reset),
- signaled_(initially_signaled) {
- }
+ WaitableEventKernel(bool manual_reset, bool initially_signaled);
+ virtual ~WaitableEventKernel();
bool Dequeue(Waiter* waiter, void* tag);
diff --git a/base/waitable_event_posix.cc b/base/waitable_event_posix.cc
index 793f635..adc521e 100644
--- a/base/waitable_event_posix.cc
+++ b/base/waitable_event_posix.cc
@@ -335,6 +335,15 @@ size_t WaitableEvent::EnqueueMany
// -----------------------------------------------------------------------------
// Private functions...
+WaitableEvent::WaitableEventKernel::WaitableEventKernel(bool manual_reset,
+ bool initially_signaled)
+ : manual_reset_(manual_reset),
+ signaled_(initially_signaled) {
+}
+
+WaitableEvent::WaitableEventKernel::~WaitableEventKernel() {
+}
+
// -----------------------------------------------------------------------------
// Wake all waiting waiters. Called with lock held.
// -----------------------------------------------------------------------------
diff --git a/base/waitable_event_watcher.h b/base/waitable_event_watcher.h
index c6309f4..b6f5e9e 100644
--- a/base/waitable_event_watcher.h
+++ b/base/waitable_event_watcher.h
@@ -4,6 +4,7 @@
#ifndef BASE_WAITABLE_EVENT_WATCHER_H_
#define BASE_WAITABLE_EVENT_WATCHER_H_
+#pragma once
#include "build/build_config.h"
diff --git a/base/watchdog.cc b/base/watchdog.cc
index d78ec0c..b20d9fa 100644
--- a/base/watchdog.cc
+++ b/base/watchdog.cc
@@ -5,6 +5,7 @@
#include "base/watchdog.h"
#include "base/compiler_specific.h"
+#include "base/logging.h"
#include "base/platform_thread.h"
using base::TimeDelta;
@@ -72,6 +73,10 @@ void Watchdog::Disarm() {
// will check its state and time, and act accordingly.
}
+void Watchdog::Alarm() {
+ DLOG(INFO) << "Watchdog alarmed for " << thread_watched_name_;
+}
+
//------------------------------------------------------------------------------
// Internal private methods that the watchdog thread uses.
diff --git a/base/watchdog.h b/base/watchdog.h
index fa60316..b4262d4 100644
--- a/base/watchdog.h
+++ b/base/watchdog.h
@@ -17,12 +17,12 @@
#ifndef BASE_WATCHDOG_H__
#define BASE_WATCHDOG_H__
+#pragma once
#include <string>
#include "base/condition_variable.h"
#include "base/lock.h"
-#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/time.h"
@@ -44,9 +44,7 @@ class Watchdog {
// Alarm is called if the time expires after an Arm() without someone calling
// Disarm(). This method can be overridden to create testable classes.
- virtual void Alarm() {
- DLOG(INFO) << "Watchdog alarmed for " << thread_watched_name_;
- }
+ virtual void Alarm();
// Reset static data to initial state. Useful for tests, to ensure
// they are independent.
diff --git a/base/watchdog_unittest.cc b/base/watchdog_unittest.cc
index f16c564..19dfe28 100644
--- a/base/watchdog_unittest.cc
+++ b/base/watchdog_unittest.cc
@@ -1,16 +1,19 @@
-// 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.
// Tests for Watchdog class.
+#include "base/watchdog.h"
+
+#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/spin_wait.h"
#include "base/time.h"
-#include "base/watchdog.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::TimeDelta;
+using base::TimeTicks;
namespace {
@@ -104,12 +107,26 @@ TEST_F(WatchdogTest, ConstructorDisabledTest) {
// Make sure Disarming will prevent firing, even after Arming.
TEST_F(WatchdogTest, DisarmTest) {
- WatchdogCounter watchdog(TimeDelta::FromSeconds(5), "Enabled3", true);
+ WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true);
+
+ TimeTicks start = TimeTicks::Now();
watchdog.Arm();
- PlatformThread::Sleep(100); // Don't sleep too long
+ PlatformThread::Sleep(100); // Sleep a bit, but not past the alarm point.
watchdog.Disarm();
- // Alarm should not fire.
- PlatformThread::Sleep(5500);
+ TimeTicks end = TimeTicks::Now();
+
+ if (end - start > TimeDelta::FromMilliseconds(500)) {
+ LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
+ << "timing-sensitive test suspicious. Aborting now.";
+ return;
+ }
+
+ // Alarm should not have fired before it was disarmed.
+ EXPECT_EQ(0, watchdog.alarm_counter());
+
+ // Sleep past the point where it would have fired if it wasn't disarmed,
+ // and verify that it didn't fire.
+ PlatformThread::Sleep(1000);
EXPECT_EQ(0, watchdog.alarm_counter());
// ...but even after disarming, we can still use the alarm...
diff --git a/base/weak_ptr.h b/base/weak_ptr.h
index 6dbc9e2..a4222f3 100644
--- a/base/weak_ptr.h
+++ b/base/weak_ptr.h
@@ -50,6 +50,7 @@
#ifndef BASE_WEAK_PTR_H_
#define BASE_WEAK_PTR_H_
+#pragma once
#include "base/logging.h"
#include "base/non_thread_safe.h"
diff --git a/base/win_util.cc b/base/win_util.cc
index 12cf241..b87e441 100644
--- a/base/win_util.cc
+++ b/base/win_util.cc
@@ -1,17 +1,20 @@
-// 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/win_util.h"
+#include <aclapi.h>
#include <propvarutil.h>
#include <sddl.h>
+#include <shlobj.h>
#include "base/logging.h"
#include "base/registry.h"
#include "base/scoped_handle.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
namespace win_util {
@@ -350,7 +353,8 @@ std::wstring GetClassName(HWND window) {
bool UserAccountControlIsEnabled() {
RegKey key(HKEY_LOCAL_MACHINE,
- L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System");
+ L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
+ KEY_READ);
DWORD uac_enabled;
if (!key.ReadValueDW(L"EnableLUA", &uac_enabled))
return true;
@@ -372,7 +376,7 @@ std::wstring FormatMessage(unsigned messageid) {
LocalFree(reinterpret_cast<HLOCAL>(string_buffer));
} else {
// The formating failed. simply convert the message value into a string.
- SStringPrintf(&formatted_string, L"message number %d", messageid);
+ base::SStringPrintf(&formatted_string, L"message number %d", messageid);
}
return formatted_string;
}
@@ -381,14 +385,6 @@ std::wstring FormatLastWin32Error() {
return FormatMessage(GetLastError());
}
-WORD KeyboardCodeToWin(base::KeyboardCode keycode) {
- return static_cast<WORD>(keycode);
-}
-
-base::KeyboardCode WinToKeyboardCode(WORD keycode) {
- return static_cast<base::KeyboardCode>(keycode);
-}
-
bool SetAppIdForPropertyStore(IPropertyStore* property_store,
const wchar_t* app_id) {
DCHECK(property_store);
@@ -411,6 +407,20 @@ bool SetAppIdForPropertyStore(IPropertyStore* property_store,
return SUCCEEDED(result);
}
+static const char16 kAutoRunKeyPath[] =
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
+
+bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+ const string16& command) {
+ RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+ return autorun_key.WriteValue(name.c_str(), command.c_str());
+}
+
+bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
+ RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+ return autorun_key.DeleteValue(name.c_str());
+}
+
} // namespace win_util
#ifdef _MSC_VER
diff --git a/base/win_util.h b/base/win_util.h
index 32dea21..01372bd 100644
--- a/base/win_util.h
+++ b/base/win_util.h
@@ -4,14 +4,17 @@
#ifndef BASE_WIN_UTIL_H__
#define BASE_WIN_UTIL_H__
+#pragma once
#include <windows.h>
-#include <aclapi.h>
-#include <shlobj.h>
#include <string>
-#include "base/keyboard_codes.h"
+#include "base/string16.h"
+
+struct IPropertyStore;
+struct _tagpropertykey;
+typedef _tagpropertykey PROPERTYKEY;
namespace win_util {
@@ -112,16 +115,20 @@ std::wstring FormatMessage(unsigned messageid);
// Uses the last Win32 error to generate a human readable message string.
std::wstring FormatLastWin32Error();
-// Methods to convert base::KeyboardCode/Windows virtual key type methods.
-WORD KeyboardCodeToWin(base::KeyboardCode keycode);
-base::KeyboardCode WinToKeyboardCode(WORD keycode);
-
// Sets the application id in given IPropertyStore. The function is intended
// for tagging application/chromium shortcut, browser window and jump list for
// Win7.
bool SetAppIdForPropertyStore(IPropertyStore* property_store,
const wchar_t* app_id);
+// Adds the specified |command| using the specified |name| to the AutoRun key.
+// |root_key| could be HKCU or HKLM or the root of any user hive.
+bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+ const string16& command);
+// Removes the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive.
+bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name);
+
} // namespace win_util
#endif // BASE_WIN_UTIL_H__
diff --git a/base/win_util_unittest.cc b/base/win_util_unittest.cc
index 39162a5..0ff1eca 100644
--- a/base/win_util_unittest.cc
+++ b/base/win_util_unittest.cc
@@ -4,10 +4,10 @@
#include <windows.h>
-#include "testing/gtest/include/gtest/gtest.h"
-#include "base/registry.h"
+#include "base/basictypes.h"
#include "base/string_util.h"
#include "base/win_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
// The test is somewhat silly, because the Vista bots some have UAC enabled
// and some have it disabled. At least we check that it does not crash.
diff --git a/base/wmi_util.h b/base/wmi_util.h
index 18585ae..7d4fed0 100644
--- a/base/wmi_util.h
+++ b/base/wmi_util.h
@@ -19,6 +19,7 @@
#ifndef BASE_WMI_UTIL_H__
#define BASE_WMI_UTIL_H__
+#pragma once
#include <string>
#include <wbemidl.h>
diff --git a/base/worker_pool.h b/base/worker_pool.h
index ef7d679..e0b75a9 100644
--- a/base/worker_pool.h
+++ b/base/worker_pool.h
@@ -4,6 +4,7 @@
#ifndef BASE_WORKER_POOL_H_
#define BASE_WORKER_POOL_H_
+#pragma once
#include "base/tracked.h"
diff --git a/base/worker_pool_linux.cc b/base/worker_pool_linux.cc
index b9c85b3..2aa1df2 100644
--- a/base/worker_pool_linux.cc
+++ b/base/worker_pool_linux.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,7 +9,7 @@
#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/ref_counted.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/task.h"
namespace {
@@ -66,8 +66,8 @@ class WorkerThread : public PlatformThread::Delegate {
};
void WorkerThread::ThreadMain() {
- const std::string name =
- StringPrintf("%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
+ const std::string name = base::StringPrintf(
+ "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
PlatformThread::SetName(name.c_str());
for (;;) {
diff --git a/base/worker_pool_linux.h b/base/worker_pool_linux.h
index a9cd894..e8c1931 100644
--- a/base/worker_pool_linux.h
+++ b/base/worker_pool_linux.h
@@ -23,6 +23,7 @@
#ifndef BASE_WORKER_POOL_LINUX_H_
#define BASE_WORKER_POOL_LINUX_H_
+#pragma once
#include <queue>
#include <string>
diff --git a/base/worker_pool_mac.h b/base/worker_pool_mac.h
index 7c67e45..85cab8b 100644
--- a/base/worker_pool_mac.h
+++ b/base/worker_pool_mac.h
@@ -4,6 +4,7 @@
#ifndef BASE_WORKER_POOL_MAC_H_
#define BASE_WORKER_POOL_MAC_H_
+#pragma once
#include "base/worker_pool.h"
diff --git a/base/worker_pool_mac.mm b/base/worker_pool_mac.mm
index 9a9076e..b9d4192 100644
--- a/base/worker_pool_mac.mm
+++ b/base/worker_pool_mac.mm
@@ -4,6 +4,7 @@
#include "base/worker_pool_mac.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/histogram.h"
#include "base/logging.h"
#import "base/scoped_nsautorelease_pool.h"
@@ -103,9 +104,12 @@ size_t outstanding_ = 0; // Operations posted but not completed.
}
- (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];
}
diff --git a/base/xdg_mime.target.mk b/base/xdg_mime.target.mk
index 6d39669..5f6d825 100644
--- a/base/xdg_mime.target.mk
+++ b/base/xdg_mime.target.mk
@@ -16,6 +16,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -45,6 +46,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -95,11 +97,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/base/xdg_util.cc b/base/xdg_util.cc
index 0ff6c47..017ae7a 100644
--- a/base/xdg_util.cc
+++ b/base/xdg_util.cc
@@ -4,22 +4,22 @@
#include "base/xdg_util.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h"
namespace base {
-FilePath GetXDGDirectory(EnvVarGetter* env, const char* env_name,
+FilePath GetXDGDirectory(Environment* env, const char* env_name,
const char* fallback_dir) {
std::string env_value;
- if (env->GetEnv(env_name, &env_value) && !env_value.empty())
+ if (env->GetVar(env_name, &env_value) && !env_value.empty())
return FilePath(env_value);
return file_util::GetHomeDir().Append(fallback_dir);
}
-FilePath GetXDGUserDirectory(EnvVarGetter* env, const char* dir_name,
+FilePath GetXDGUserDirectory(Environment* env, const char* dir_name,
const char* fallback_dir) {
char* xdg_dir = xdg_user_dir_lookup(dir_name);
if (xdg_dir) {
@@ -30,16 +30,16 @@ FilePath GetXDGUserDirectory(EnvVarGetter* env, const char* dir_name,
return file_util::GetHomeDir().Append(fallback_dir);
}
-DesktopEnvironment GetDesktopEnvironment(EnvVarGetter* env) {
+DesktopEnvironment GetDesktopEnvironment(Environment* env) {
std::string desktop_session;
- if (env->GetEnv("DESKTOP_SESSION", &desktop_session)) {
+ if (env->GetVar("DESKTOP_SESSION", &desktop_session)) {
if (desktop_session == "gnome") {
return DESKTOP_ENVIRONMENT_GNOME;
} else if (desktop_session == "kde4") {
return DESKTOP_ENVIRONMENT_KDE4;
} else if (desktop_session == "kde") {
// This may mean KDE4 on newer systems, so we have to check.
- if (env->HasEnv("KDE_SESSION_VERSION"))
+ if (env->HasVar("KDE_SESSION_VERSION"))
return DESKTOP_ENVIRONMENT_KDE4;
return DESKTOP_ENVIRONMENT_KDE3;
} else if (desktop_session.find("xfce") != std::string::npos) {
@@ -49,10 +49,10 @@ DesktopEnvironment GetDesktopEnvironment(EnvVarGetter* env) {
// Fall back on some older environment variables.
// Useful particularly in the DESKTOP_SESSION=default case.
- if (env->HasEnv("GNOME_DESKTOP_SESSION_ID")) {
+ if (env->HasVar("GNOME_DESKTOP_SESSION_ID")) {
return DESKTOP_ENVIRONMENT_GNOME;
- } else if (env->HasEnv("KDE_FULL_SESSION")) {
- if (env->HasEnv("KDE_SESSION_VERSION"))
+ } else if (env->HasVar("KDE_FULL_SESSION")) {
+ if (env->HasVar("KDE_SESSION_VERSION"))
return DESKTOP_ENVIRONMENT_KDE4;
return DESKTOP_ENVIRONMENT_KDE3;
}
@@ -76,7 +76,7 @@ const char* GetDesktopEnvironmentName(DesktopEnvironment env) {
return NULL;
}
-const char* GetDesktopEnvironmentName(EnvVarGetter* env) {
+const char* GetDesktopEnvironmentName(Environment* env) {
return GetDesktopEnvironmentName(GetDesktopEnvironment(env));
}
diff --git a/base/xdg_util.h b/base/xdg_util.h
index b69ce51..c0788c8 100644
--- a/base/xdg_util.h
+++ b/base/xdg_util.h
@@ -4,6 +4,7 @@
#ifndef BASE_XDG_UTIL_H_
#define BASE_XDG_UTIL_H_
+#pragma once
// XDG refers to http://en.wikipedia.org/wiki/Freedesktop.org .
// This file contains utilities found across free desktop
@@ -13,20 +14,20 @@ class FilePath;
namespace base {
-class EnvVarGetter;
+class Environment;
// Utility function for getting XDG directories.
// |env_name| is the name of an environment variable that we want to use to get
// a directory path. |fallback_dir| is the directory relative to $HOME that we
// use if |env_name| cannot be found or is empty. |fallback_dir| may be NULL.
// Examples of |env_name| are XDG_CONFIG_HOME and XDG_DATA_HOME.
-FilePath GetXDGDirectory(EnvVarGetter* env, const char* env_name,
+FilePath GetXDGDirectory(Environment* env, const char* env_name,
const char* fallback_dir);
// Wrapper around xdg_user_dir_lookup() from src/base/third_party/xdg-user-dirs
// This looks up "well known" user directories like the desktop and music
// folder. Examples of |dir_name| are DESKTOP and MUSIC.
-FilePath GetXDGUserDirectory(EnvVarGetter* env, const char* dir_name,
+FilePath GetXDGUserDirectory(Environment* env, const char* dir_name,
const char* fallback_dir);
enum DesktopEnvironment {
@@ -43,13 +44,13 @@ enum DesktopEnvironment {
// of which desktop environment we're using. We use this to know when
// to attempt to use preferences from the desktop environment --
// proxy settings, password manager, etc.
-DesktopEnvironment GetDesktopEnvironment(EnvVarGetter* env);
+DesktopEnvironment GetDesktopEnvironment(Environment* env);
// Return a string representation of the given desktop environment.
// May return NULL in the case of DESKTOP_ENVIRONMENT_OTHER.
const char* GetDesktopEnvironmentName(DesktopEnvironment env);
// Convenience wrapper that calls GetDesktopEnvironment() first.
-const char* GetDesktopEnvironmentName(EnvVarGetter* env);
+const char* GetDesktopEnvironmentName(Environment* env);
} // namespace base
diff --git a/base/xdg_util_unittest.cc b/base/xdg_util_unittest.cc
index b821921..c33fca5 100644
--- a/base/xdg_util_unittest.cc
+++ b/base/xdg_util_unittest.cc
@@ -4,11 +4,10 @@
#include "base/xdg_util.h"
+#include "base/environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "base/env_var.h"
-
using ::testing::_;
using ::testing::Return;
using ::testing::SetArgumentPointee;
@@ -16,10 +15,11 @@ using ::testing::StrEq;
namespace {
-class MockEnvVarGetter : public base::EnvVarGetter {
+class MockEnvironment : public base::Environment {
public:
- MOCK_METHOD2(GetEnv, bool(const char*, std::string* result));
- MOCK_METHOD2(SetEnv, bool(const char*, const std::string& new_value));
+ MOCK_METHOD2(GetVar, bool(const char*, std::string* result));
+ MOCK_METHOD2(SetVar, bool(const char*, const std::string& new_value));
+ MOCK_METHOD1(UnSetVar, bool(const char*));
};
const char* kGnome = "gnome";
@@ -30,9 +30,9 @@ const char* kXFCE = "xfce";
} // namespace
TEST(XDGUtilTest, GetDesktopEnvironmentGnome) {
- MockEnvVarGetter getter;
- EXPECT_CALL(getter, GetEnv(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetEnv(StrEq("DESKTOP_SESSION"), _))
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
.WillOnce(DoAll(SetArgumentPointee<1>(kGnome), Return(true)));
EXPECT_EQ(base::DESKTOP_ENVIRONMENT_GNOME,
@@ -40,9 +40,9 @@ TEST(XDGUtilTest, GetDesktopEnvironmentGnome) {
}
TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) {
- MockEnvVarGetter getter;
- EXPECT_CALL(getter, GetEnv(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetEnv(StrEq("DESKTOP_SESSION"), _))
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
.WillOnce(DoAll(SetArgumentPointee<1>(kKDE4), Return(true)));
EXPECT_EQ(base::DESKTOP_ENVIRONMENT_KDE4,
@@ -50,9 +50,9 @@ TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) {
}
TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) {
- MockEnvVarGetter getter;
- EXPECT_CALL(getter, GetEnv(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetEnv(StrEq("DESKTOP_SESSION"), _))
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
.WillOnce(DoAll(SetArgumentPointee<1>(kKDE), Return(true)));
EXPECT_EQ(base::DESKTOP_ENVIRONMENT_KDE3,
@@ -60,9 +60,9 @@ TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) {
}
TEST(XDGUtilTest, GetDesktopEnvironmentXFCE) {
- MockEnvVarGetter getter;
- EXPECT_CALL(getter, GetEnv(_, _)).WillRepeatedly(Return(false));
- EXPECT_CALL(getter, GetEnv(StrEq("DESKTOP_SESSION"), _))
+ MockEnvironment getter;
+ EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+ EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _))
.WillOnce(DoAll(SetArgumentPointee<1>(kXFCE), Return(true)));
EXPECT_EQ(base::DESKTOP_ENVIRONMENT_XFCE,
diff --git a/build/All.target.mk b/build/All.target.mk
index e826557..c7b452d 100644
--- a/build/All.target.mk
+++ b/build/All.target.mk
@@ -4,7 +4,7 @@ TOOLSET := target
TARGET := All
### Rules for final target.
$(obj).target/build/All.stamp: TOOLSET := $(TOOLSET)
-$(obj).target/build/All.stamp: app_unittests $(obj).target/app/app_strings.stamp $(obj).target/app/app_resources.stamp $(obj).target/app/libapp_base.a $(obj).target/app/app_unittest_strings.stamp $(obj).target/base/libbase_i18n.a base_unittests $(obj).target/base/libtest_support_base.a $(obj).target/base/libtest_support_perf.a $(obj).target/base/libbase.a $(obj).target/base/libsymbolize.a $(obj).target/base/libxdg_mime.a sync_listen_notifications $(obj).target/chrome/chrome_resources.stamp $(obj).target/chrome/chrome_strings.stamp $(obj).target/chrome/theme_resources.stamp $(obj).target/chrome/platform_locale_settings.stamp $(obj).target/chrome/chrome_extra_resources.stamp $(obj).target/chrome/default_extensions.stamp $(obj).target/chrome/libdebugger.a $(obj).target/chrome/libplugin.a $(obj).target/chrome/libutility.a $(obj).target/chrome/libprofile_import.a $(obj).target/chrome/libchrome_gpu.a $(obj).target/chrome/libworker.a $(obj).target/chrome/libsyncapi.a $(obj).target/chrome/libsync.a $(obj).target/chrome/libsync_notifier.a $(obj).target/chrome/libservice.a $(obj).target/chrome/libbrowser.a $(obj).target/chrome/component_extensions.stamp $(obj).target/chrome/userfeedback_proto.stamp $(obj).target/chrome/libcommon.a $(obj).target/chrome/libcommon_net.a chrome $(obj).target/chrome/libchrome_version_info.a $(obj).target/chrome/librenderer.a interactive_ui_tests $(obj).target/chrome/libtest_support_common.a $(obj).target/chrome/libtest_support_ui.a $(obj).target/chrome/libtest_support_unit.a automated_ui_tests ui_tests libnacl_security_tests.so nacl_sandbox_tests nacl_ui_tests unit_tests browser_tests startup_tests reliability_tests page_cycler_tests tab_switching_test memory_test url_fetch_test sync_unit_tests sync_integration_tests plugin_tests $(obj).target/chrome/libcommon_constants.a $(obj).target/chrome/libnacl.a convert_dict $(obj).target/chrome/libconvert_dict.a flush_cache $(obj).target/chrome/packed_extra_resources.stamp $(obj).target/chrome/linux_symbols.stamp $(obj).target/chrome/packed_resources.stamp $(obj).target/chrome/libinstaller_util.a perf_tests gfx_unittests $(obj).target/gfx/libgfx.a $(obj).target/gpu/libcommand_buffer_common.a $(obj).target/gpu/libgles2_cmd_helper.a $(obj).target/gpu/libgles2_implementation.a $(obj).target/gpu/libgles2_lib.a $(obj).target/gpu/libgles2_c_lib.a $(obj).target/gpu/libcommand_buffer_client.a $(obj).target/gpu/libcommand_buffer_service.a $(obj).target/gpu/libgpu_plugin.a gpu_unittests $(obj).target/gpu/libgles2_demo_lib.a $(obj).target/gpu/libpgl.a $(obj).target/gpu/demos/libgpu_demo_framework.a $(obj).target/gpu/demos/libgpu_demo_framework_exe.a hello_triangle_exe mip_map_2d_exe simple_texture_2d_exe simple_texture_cubemap_exe simple_vertex_shader_exe stencil_test_exe texture_wrap_exe ipc_tests $(obj).target/ipc/libipc.a $(obj).target/jingle/libnotifier.a notifier_unit_tests $(obj).target/media/libmedia.a media_unittests media_bench scaler_bench ffmpeg_tests wav_ola_test qt_faststart omx_test omx_unittests $(obj).target/media/libomx_wrapper.a player_x11 $(obj).target/net/libnet_base.a $(obj).target/net/libnet.a net_unittests net_perftests stress_cache tld_cleanup crash_cache run_testserver $(obj).target/net/libnet_test_support.a $(obj).target/net/net_resources.stamp fetch_client fetch_server $(obj).target/net/libhttp_listen_socket.a hresolv $(obj).target/net/third_party/nss/libssl.a $(obj).target/printing/libprinting.a printing_unittests $(obj).target/sdch/libsdch.a $(obj).target/skia/libskia.a $(obj).target/skia/libskia_opts.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgmockmain.a $(obj).target/testing/libgtest.a $(obj).target/testing/libgtestmain.a $(obj).target/third_party/cacheinvalidation/cacheinvalidation_proto.stamp $(obj).target/third_party/cacheinvalidation/libcacheinvalidation.a cacheinvalidation_unittests $(obj).target/third_party/cld/libcld.a codesighs maptsvdifftool nm2tsv $(obj).target/third_party/ffmpeg/libffmpeg.a libffmpegsumo.so $(obj).target/third_party/ffmpeg/assemble_ffmpeg_asm.stamp $(obj).target/third_party/ffmpeg/make_ffmpeg_asm_lib.stamp ffmpegsumo_nolink $(obj).target/third_party/icu/libicudata.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/libxml/libxml2.a $(obj).target/third_party/libxslt/libxslt.a $(obj).target/third_party/lzma_sdk/liblzma_sdk.a $(obj).target/third_party/mesa/libmesa.a libosmesa.so $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/third_party/npapi/npapi.stamp $(obj).target/third_party/ppapi/ppapi_c.stamp $(obj).target/third_party/ppapi/libppapi_cpp_objects.a $(obj).target/third_party/ppapi/libppapi_cpp.a libppapi_example.so libppapi_tests.so $(obj).target/third_party/ots/libots.a $(obj).target/third_party/sqlite/libsqlite3.a sqlite_shell $(obj).target/third_party/WebKit/WebKit/chromium/libwebkit.a $(obj).target/third_party/WebKit/WebKit/chromium/inspector_resources.stamp $(obj).target/third_party/WebKit/WebKit/chromium/devtools_html.stamp $(obj).target/third_party/WebKit/WebKit/chromium/concatenated_devtools_js.stamp webkit_unit_tests ImageDiff DumpRenderTree $(obj).target/third_party/zlib/libzlib.a $(obj).target/webkit/support/libappcache.a $(obj).target/webkit/support/libdatabase.a $(obj).target/webkit/support/webkit_resources.stamp $(obj).target/webkit/support/webkit_strings.stamp $(obj).target/webkit/support/libglue.a libnpapi_layout_test_plugin.so $(obj).target/webkit/support/copy_npapi_layout_test_plugin.stamp $(obj).target/webkit/support/libwebkit_support.a $(obj).target/webkit/pull_in_webkit_unit_tests.stamp $(obj).target/webkit/pull_in_DumpRenderTree.stamp $(obj).target/webkit/libtest_shell_common.a $(obj).target/webkit/test_shell_pak.stamp test_shell test_shell_tests $(obj).target/webkit/test_shell_resources.stamp $(obj).target/build/util/lastchange.stamp $(obj).target/build/temp_gyp/libgoogleurl.a googleurl_unittests $(obj).target/v8/tools/gyp/v8.stamp $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_nosnapshot.a $(obj).target/v8/tools/gyp/libv8_base.a v8_shell yasm $(obj).host/third_party/yasm/config_sources.stamp $(obj).host/third_party/yasm/generate_files.stamp $(obj).host/third_party/yasm/libgenperf_libs.a genstring genperf genmacro genversion re2c genmodule $(obj).target/breakpad/libbreakpad_client.a breakpad_unittests generate_test_dump $(obj).target/courgette/libcourgette_lib.a courgette courgette_minimal_tool courgette_unittests courgette_fuzz chrome_sandbox $(obj).target/sandbox/libsandbox.a gtk_clipboard_dump xdisplaycheck $(obj).target/third_party/libevent/libevent.a $(obj).target/remoting/libchromoting_plugin.a $(obj).target/remoting/libchromoting_base.a $(obj).target/remoting/libchromoting_host.a $(obj).target/remoting/libchromoting_client.a chromoting_simple_host chromoting_host_keygen $(obj).target/remoting/libchromoting_jingle_glue.a chromoting_jingle_test_client remoting_unittests chromoting_client_test_webserver chromoting_x11_client $(obj).target/chrome/libnacl_security_tests.so $(obj).target/third_party/ffmpeg/libffmpegsumo.so $(obj).target/third_party/ppapi/libppapi_example.so FORCE_DO_CMD
+$(obj).target/build/All.stamp: app_unittests $(obj).target/app/app_strings.stamp $(obj).target/app/app_resources.stamp $(obj).target/app/libapp_base.a $(obj).target/app/app_unittest_strings.stamp $(obj).target/base/libbase_i18n.a base_unittests $(obj).target/base/libtest_support_base.a $(obj).target/base/libtest_support_perf.a $(obj).target/base/libbase.a $(obj).target/base/libsymbolize.a $(obj).target/base/libxdg_mime.a sync_listen_notifications $(obj).target/chrome/chrome_resources.stamp $(obj).target/chrome/chrome_strings.stamp $(obj).target/chrome/theme_resources.stamp $(obj).target/chrome/platform_locale_settings.stamp $(obj).target/chrome/chrome_extra_resources.stamp $(obj).target/chrome/default_extensions.stamp $(obj).target/chrome/libdebugger.a $(obj).target/chrome/libplugin.a $(obj).target/chrome/libutility.a $(obj).target/chrome/libprofile_import.a $(obj).target/chrome/libchrome_gpu.a $(obj).target/chrome/libworker.a $(obj).target/chrome/libsyncapi.a $(obj).target/chrome/libsync.a $(obj).target/chrome/libsync_notifier.a $(obj).target/chrome/libservice.a $(obj).target/chrome/libbrowser.a $(obj).target/chrome/component_extensions.stamp $(obj).target/chrome/userfeedback_proto.stamp $(obj).target/chrome/libcommon.a $(obj).target/chrome/libcommon_net.a chrome $(obj).target/chrome/librenderer.a $(obj).target/chrome/safe_browsing_proto.stamp interactive_ui_tests $(obj).target/chrome/libtest_support_common.a $(obj).target/chrome/libtest_support_ui.a $(obj).target/chrome/libtest_support_unit.a automated_ui_tests ui_tests chromedriver libnacl_security_tests.so nacl_sandbox_tests nacl_ui_tests unit_tests browser_tests safe_browsing_tests startup_tests reliability_tests page_cycler_tests tab_switching_test memory_test url_fetch_test sync_unit_tests sync_integration_tests plugin_tests $(obj).target/chrome/libcommon_constants.a $(obj).target/chrome/libnacl.a convert_dict $(obj).target/chrome/libconvert_dict.a flush_cache $(obj).target/chrome/packed_extra_resources.stamp $(obj).target/chrome/linux_symbols.stamp $(obj).target/chrome/policy_templates.stamp $(obj).target/chrome/packed_resources.stamp $(obj).target/chrome/libinstaller_util.a perf_tests gfx_unittests $(obj).target/gfx/libgfx.a $(obj).target/gfx/gfx_resources.stamp $(obj).target/gpu/libcommand_buffer_common.a $(obj).target/gpu/libgles2_cmd_helper.a $(obj).target/gpu/libgles2_implementation.a $(obj).target/gpu/libgles2_lib.a $(obj).target/gpu/libgles2_c_lib.a $(obj).target/gpu/libcommand_buffer_client.a $(obj).target/gpu/libcommand_buffer_service.a $(obj).target/gpu/libgpu_plugin.a gpu_unittests $(obj).target/gpu/libgles2_demo_lib.a $(obj).target/gpu/libpgl.a $(obj).target/gpu/demos/libgpu_demo_framework.a $(obj).target/gpu/demos/libgpu_demo_framework_exe.a $(obj).target/gpu/demos/libgpu_demo_framework_ppapi.a hello_triangle_exe mip_map_2d_exe simple_texture_2d_exe simple_texture_cubemap_exe simple_vertex_shader_exe stencil_test_exe texture_wrap_exe ipc_tests $(obj).target/ipc/libipc.a $(obj).target/jingle/libnotifier.a notifier_unit_tests $(obj).target/media/libmedia.a ffmpeg_unittests media_unittests $(obj).target/media/libmedia_test_support.a media_bench scaler_bench ffmpeg_tests wav_ola_test qt_faststart omx_test omx_unittests $(obj).target/media/libomx_wrapper.a player_x11 $(obj).target/net/libnet_base.a $(obj).target/net/libnet.a net_unittests net_perftests stress_cache tld_cleanup crash_cache run_testserver $(obj).target/net/libnet_test_support.a $(obj).target/net/net_resources.stamp fetch_client fetch_server $(obj).target/net/libhttp_listen_socket.a hresolv dnssec_chain_verify $(obj).target/net/third_party/nss/libssl.a $(obj).target/printing/libprinting.a printing_unittests $(obj).target/sdch/libsdch.a $(obj).target/skia/libskia.a $(obj).target/skia/libskia_opts.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgmockmain.a $(obj).target/testing/libgtest.a $(obj).target/testing/libgtestmain.a $(obj).target/third_party/cacheinvalidation/cacheinvalidation_proto.stamp $(obj).target/third_party/cacheinvalidation/libcacheinvalidation.a cacheinvalidation_unittests $(obj).target/third_party/cld/libcld.a codesighs maptsvdifftool nm2tsv $(obj).target/third_party/ffmpeg/libffmpeg.a libffmpegsumo.so $(obj).target/third_party/ffmpeg/assemble_ffmpeg_asm.stamp $(obj).target/third_party/ffmpeg/make_ffmpeg_asm_lib.stamp ffmpegsumo_nolink $(obj).target/third_party/icu/libicudata.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/libxml/libxml2.a $(obj).target/third_party/libxslt/libxslt.a $(obj).target/third_party/lzma_sdk/liblzma_sdk.a $(obj).target/third_party/mesa/libmesa.a libosmesa.so $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/third_party/npapi/npapi.stamp $(obj).target/third_party/ppapi/ppapi_c.stamp $(obj).target/third_party/ppapi/libppapi_cpp_objects.a $(obj).target/third_party/ppapi/libppapi_cpp.a libppapi_example.so libppapi_tests.so $(obj).target/third_party/ots/libots.a $(obj).target/third_party/sqlite/libsqlite3.a sqlite_shell $(obj).target/third_party/WebKit/WebKit/chromium/libwebkit.a $(obj).target/third_party/WebKit/WebKit/chromium/inspector_resources.stamp $(obj).target/third_party/WebKit/WebKit/chromium/devtools_html.stamp $(obj).target/third_party/WebKit/WebKit/chromium/concatenated_devtools_js.stamp webkit_unit_tests ImageDiff DumpRenderTree $(obj).target/third_party/zlib/libzlib.a $(obj).target/webkit/support/libappcache.a $(obj).target/webkit/support/libblob.a $(obj).target/webkit/support/libfileapi.a $(obj).target/webkit/support/libdatabase.a $(obj).target/webkit/support/webkit_resources.stamp $(obj).target/webkit/support/webkit_strings.stamp $(obj).target/webkit/support/libwebkit_user_agent.a $(obj).target/webkit/support/libglue.a libnpapi_layout_test_plugin.so $(obj).target/webkit/support/copy_npapi_layout_test_plugin.stamp $(obj).target/webkit/support/libwebkit_support.a $(obj).target/webkit/pull_in_webkit_unit_tests.stamp $(obj).target/webkit/pull_in_DumpRenderTree.stamp $(obj).target/webkit/libtest_shell_common.a $(obj).target/webkit/test_shell_pak.stamp test_shell test_shell_tests $(obj).target/webkit/test_shell_resources.stamp $(obj).target/build/util/lastchange.stamp $(obj).target/build/temp_gyp/libgoogleurl.a googleurl_unittests $(obj).target/v8/tools/gyp/v8.stamp $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_nosnapshot.a $(obj).target/v8/tools/gyp/libv8_base.a v8_shell yasm $(obj).host/third_party/yasm/config_sources.stamp $(obj).host/third_party/yasm/generate_files.stamp $(obj).host/third_party/yasm/libgenperf_libs.a genstring genperf genmacro genversion re2c genmodule $(obj).target/breakpad/libbreakpad_client.a $(obj).target/breakpad/libbreakpad_processor_support.a breakpad_unittests generate_test_dump minidump-2-core $(obj).target/courgette/libcourgette_lib.a courgette courgette_minimal_tool courgette_unittests courgette_fuzz chrome_sandbox $(obj).target/sandbox/libsandbox.a gtk_clipboard_dump xdisplaycheck $(obj).target/third_party/libevent/libevent.a $(obj).target/remoting/libchromoting_plugin.a $(obj).target/remoting/libchromoting_base.a $(obj).target/remoting/libchromoting_host.a $(obj).target/remoting/libchromoting_client.a chromoting_simple_host chromoting_host_keygen $(obj).target/remoting/libchromoting_jingle_glue.a chromoting_jingle_test_client $(obj).target/remoting/libchromoting_protocol.a chromotocol_test_client remoting_unittests chromoting_client_test_webserver chromoting_x11_client $(obj).target/chrome/libnacl_security_tests.so $(obj).target/third_party/ffmpeg/libffmpegsumo.so $(obj).target/third_party/ppapi/libppapi_example.so FORCE_DO_CMD
$(call do_cmd,touch)
all_deps += $(obj).target/build/All.stamp
diff --git a/build/all.gyp b/build/all.gyp
index e762965..5348c74 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -107,6 +107,7 @@
'../gears/gears.gyp:*',
'../rlz/rlz.gyp:*',
'../sandbox/sandbox.gyp:*',
+ '../third_party/angle/src/build_angle.gyp:*',
'../third_party/bsdiff/bsdiff.gyp:*',
'../third_party/bspatch/bspatch.gyp:*',
'../third_party/gles2_book/gles2_book.gyp:*',
@@ -156,7 +157,11 @@
'dependencies': [
'../app/app.gyp:app_unittests',
'../chrome/chrome.gyp:browser_tests',
+ '../chrome/chrome.gyp:interactive_ui_tests',
'../chrome/chrome.gyp:nacl_ui_tests',
+ '../chrome/chrome.gyp:nacl_sandbox_tests',
+ '../chrome/chrome.gyp:safe_browsing_tests',
+ '../chrome/chrome.gyp:sync_integration_tests',
'../chrome/chrome.gyp:sync_unit_tests',
'../chrome/chrome.gyp:ui_tests',
'../chrome/chrome.gyp:unit_tests',
@@ -179,9 +184,12 @@
'../chrome/chrome.gyp:browser_tests',
'../chrome/chrome.gyp:memory_test',
'../chrome/chrome.gyp:nacl_ui_tests',
+ '../chrome/chrome.gyp:nacl_sandbox_tests',
'../chrome/chrome.gyp:page_cycler_tests',
'../chrome/chrome.gyp:plugin_tests',
+ '../chrome/chrome.gyp:safe_browsing_tests',
'../chrome/chrome.gyp:startup_tests',
+ '../chrome/chrome.gyp:sync_integration_tests',
'../chrome/chrome.gyp:sync_unit_tests',
'../chrome/chrome.gyp:tab_switching_test',
'../chrome/chrome.gyp:ui_tests',
@@ -213,6 +221,25 @@
'../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
],
},
+ {
+ 'target_name': 'chromium_builder_dbg_valgrind_mac',
+ 'type': 'none',
+ 'dependencies': [
+ '../app/app.gyp:app_unittests',
+ '../base/base.gyp:base_unittests',
+ 'temp_gyp/googleurl.gyp:googleurl_unittests',
+ '../ipc/ipc.gyp:ipc_tests',
+ '../media/media.gyp:media_unittests',
+ '../net/net.gyp:net_unittests',
+ '../printing/printing.gyp:printing_unittests',
+ '../remoting/remoting.gyp:remoting_unittests',
+ '../chrome/chrome.gyp:sync_unit_tests',
+ '../chrome/chrome.gyp:unit_tests',
+ '../chrome/chrome.gyp:ui_tests',
+ '../jingle/jingle.gyp:notifier_unit_tests',
+ '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+ ],
+ },
], # targets
}], # OS="mac"
['OS=="win"', {
@@ -230,10 +257,13 @@
'../chrome/chrome.gyp:memory_test',
'../chrome/chrome.gyp:mini_installer_test',
'../chrome/chrome.gyp:nacl_ui_tests',
+ '../chrome/chrome.gyp:nacl_sandbox_tests',
'../chrome/chrome.gyp:page_cycler_tests',
'../chrome/chrome.gyp:plugin_tests',
+ '../chrome/chrome.gyp:safe_browsing_tests',
'../chrome/chrome.gyp:selenium_tests',
'../chrome/chrome.gyp:startup_tests',
+ '../chrome/chrome.gyp:sync_integration_tests',
'../chrome/chrome.gyp:sync_unit_tests',
'../chrome/chrome.gyp:tab_switching_test',
'../chrome/chrome.gyp:ui_tests',
@@ -264,7 +294,6 @@
'../chrome_frame/chrome_frame.gyp:chrome_frame_tests',
'../chrome_frame/chrome_frame.gyp:chrome_frame_unittests',
'../chrome_frame/chrome_frame.gyp:npchrome_frame',
- '../third_party/angle/src/build_angle.gyp:*',
],
},
{
@@ -308,6 +337,7 @@
'../chrome/chrome.gyp:interactive_ui_tests',
'../chrome/chrome.gyp:memory_test',
'../chrome/chrome.gyp:page_cycler_tests',
+ '../chrome/chrome.gyp:safe_browsing_tests',
'../chrome/chrome.gyp:startup_tests',
'../chrome/chrome.gyp:sync_unit_tests',
'../chrome/chrome.gyp:tab_switching_test',
diff --git a/build/build-bisect.py b/build/build-bisect.py
index 64504bc..f44846a 100755
--- a/build/build-bisect.py
+++ b/build/build-bisect.py
@@ -97,7 +97,7 @@ def SetArchiveVars(archive):
BUILD_ARCHIVE_TYPE = archive
BUILD_ARCHIVE_DIR = 'chromium-rel-' + BUILD_ARCHIVE_TYPE
- if BUILD_ARCHIVE_TYPE in ('linux', 'linux-64'):
+ 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'
@@ -178,7 +178,7 @@ def main():
'Perform binary search on the snapshot builds.')
parser = optparse.OptionParser(usage=usage)
# Strangely, the default help output doesn't include the choice list.
- choices = ['mac', 'xp', 'linux', 'linux-64']
+ choices = ['mac', 'xp', 'linux', 'linux-64', 'linux-chromiumos']
parser.add_option('-a', '--archive',
choices = choices,
help = 'The buildbot archive to bisect [%s].' %
diff --git a/build/common.gypi b/build/common.gypi
index 3026274..1665600 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -61,6 +61,9 @@
# toolkit_views test below.
'chromeos%': '0',
+ # Disable touch support by default.
+ 'touchui%': 0,
+
# To do a shared build on linux we need to be able to choose between
# type static_library and shared_library. We default to doing a static
# build but you can override this with "gyp -Dlibrary=shared_library"
@@ -70,15 +73,26 @@
'library%': 'static_library',
},
- # Set default value of toolkit_views on for Windows and Chrome OS.
- # We set it at this level of nesting so the value is available for
+ # We set those at this level of nesting so the values are available for
# other conditionals below.
'conditions': [
- ['OS=="win" or chromeos==1', {
+ # Set default value of toolkit_views on for Windows, Chrome OS
+ # and the touch UI.
+ ['OS=="win" or chromeos==1 or touchui==1', {
'toolkit_views%': 1,
}, {
'toolkit_views%': 0,
}],
+
+ # A flag to enable or disable our compile-time dependency
+ # on gnome-keyring. If that dependency is disabled, no gnome-keyring
+ # support will be available. This option is useful
+ # for Linux distributions.
+ ['chromeos==1', {
+ 'use_gnome_keyring%': 0,
+ }, {
+ 'use_gnome_keyring%': 1,
+ }],
],
'host_arch%': '<(host_arch)',
@@ -87,15 +101,9 @@
# building on.
'target_arch%': '<(host_arch)',
- # We do want to build Chromium with Breakpad support in certain
- # situations. I.e. for Chrome bot.
- 'linux_chromium_breakpad%': 0,
- # And if we want to dump symbols.
- 'linux_chromium_dump_symbols%': 0,
- # Also see linux_strip_binary below.
-
- # Copy conditionally-set chromeos variable out one scope.
+ # Copy conditionally-set chromeos and touchui variables out one scope.
'chromeos%': '<(chromeos)',
+ 'touchui%': '<(touchui)',
# This variable tells WebCore.gyp and JavaScriptCore.gyp whether they are
# are built under a chromium full build (1) or a webkit.org chromium
@@ -145,7 +153,9 @@
'target_arch%': '<(target_arch)',
'host_arch%': '<(host_arch)',
'toolkit_views%': '<(toolkit_views)',
+ 'use_gnome_keyring%': '<(use_gnome_keyring)',
'chromeos%': '<(chromeos)',
+ 'touchui%': '<(touchui)',
'inside_chromium_build%': '<(inside_chromium_build)',
'fastbuild%': '<(fastbuild)',
'linux_fpic%': '<(linux_fpic)',
@@ -241,8 +251,20 @@
# Set this to true to enable SELinux support.
'selinux%': 0,
- # Strip the binary after dumping symbols.
+ # Set this to true when building with Clang.
+ # See http://code.google.com/p/chromium/wiki/Clang for details.
+ # TODO: eventually clang should behave identically to gcc, and this
+ # won't be necessary.
+ 'clang%': 0,
+
+ # Override whether we should use Breakpad on Linux. I.e. for Chrome bot.
+ 'linux_breakpad%': 0,
+ # And if we want to dump symbols for Breakpad-enabled builds.
+ 'linux_dump_symbols%': 0,
+ # And if we want to strip the binary after dumping symbols.
'linux_strip_binary%': 0,
+ # Strip the test binaries needed for Linux reliability tests.
+ 'linux_strip_reliability_tests%': 0,
# Enable TCMalloc.
'linux_use_tcmalloc%': 1,
@@ -253,6 +275,10 @@
# Disable TCMalloc's heapchecker.
'linux_use_heapchecker%': 0,
+ # Disable shadow stack keeping used by heapcheck to unwind the stacks
+ # better.
+ 'linux_keep_shadow_stacks%': 0,
+
# Set to 1 to turn on seccomp sandbox by default.
# (Note: this is ignored for official builds.)
'linux_use_seccomp_sandbox%': 0,
@@ -284,6 +310,9 @@
# whether to compile in the sources for the GPU plugin / process.
'enable_gpu%': 1,
+ # Use OpenSSL instead of NSS. Currently in developement.
+ 'use_openssl%': 0,
+
'conditions': [
['OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
# This will set gcc_version to XY if you are running gcc X.Y.*.
@@ -292,21 +321,13 @@
# Figure out the python architecture to decide if we build pyauto.
'python_arch%': '<!(<(DEPTH)/build/linux/python_arch.sh <(sysroot)/usr/lib/libpython<(python_ver).so.1.0)',
'conditions': [
- ['branding=="Chrome" or linux_chromium_breakpad==1', {
+ ['branding=="Chrome"', {
'linux_breakpad%': 1,
- }, {
- 'linux_breakpad%': 0,
}],
# All Chrome builds have breakpad symbols, but only process the
# symbols from official builds.
- # TODO(mmoss) dump_syms segfaults on x64. Enable once dump_syms and
- # crash server handle 64-bit symbols.
- ['linux_chromium_dump_symbols==1 or '
- '(branding=="Chrome" and buildtype=="Official" and '
- 'target_arch=="ia32")', {
+ ['(branding=="Chrome" and buildtype=="Official")', {
'linux_dump_symbols%': 1,
- }, {
- 'linux_dump_symbols%': 0,
}],
['toolkit_views==0', {
# GTK wants Title Case strings
@@ -349,7 +370,6 @@
['component=="shared_library"', {
'win_use_allocator_shim%': 0,
}],
-
['MSVS_VERSION=="2005"', {
'msvs_multi_core_compile%': 0,
},{
@@ -374,15 +394,12 @@
# so Cocoa is happy (http://crbug.com/20441).
'locales': [
'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en-GB',
- 'en-US', 'es-419', 'es', 'et', 'fi', 'fil', 'fr', 'gu', 'he',
+ 'en-US', 'es-419', 'es', 'et', 'fa', 'fi', 'fil', 'fr', 'gu', 'he',
'hi', 'hr', 'hu', 'id', 'it', 'ja', 'kn', 'ko', 'lt', 'lv',
'ml', 'mr', 'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru',
'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tr', 'uk',
'vi', 'zh-CN', 'zh-TW',
],
-
- # Disable touch support by default.
- 'touchui%': 0,
},
'target_defaults': {
'variables': {
@@ -524,6 +541,16 @@
}], # OS==win
], # conditions for coverage
}], # coverage!=0
+ ['OS=="win"', {
+ 'defines': [
+ '__STD_C',
+ '_CRT_SECURE_NO_DEPRECATE',
+ '_SCL_SECURE_NO_DEPRECATE',
+ ],
+ 'include_dirs': [
+ '<(DEPTH)/third_party/wtl/include',
+ ],
+ }], # OS==win
], # conditions for 'target_defaults'
'target_conditions': [
['chromium_code==0', {
@@ -830,6 +857,7 @@
# Don't export any symbols (for example, to plugins we dlopen()).
# Note: this is *required* to make some plugins work.
'-fvisibility=hidden',
+ '-pipe',
],
'cflags_cc': [
'-fno-rtti',
@@ -919,11 +947,6 @@
'cflags': [
'-O>(debug_optimize)',
'-g',
- # One can use '-gstabs' to enable building the debugging
- # information in STABS format for breakpad's dumpsyms.
- ],
- 'ldflags': [
- '-rdynamic', # Allows backtrace to resolve symbols.
],
},
'Release_Base': {
@@ -947,6 +970,12 @@
'-fdata-sections',
'-ffunction-sections',
],
+ 'ldflags': [
+ # Specifically tell the linker to perform optimizations.
+ # See http://lwn.net/Articles/192624/ .
+ '-Wl,-O1',
+ '-Wl,--as-needed',
+ ],
'conditions' : [
['no_gc_sections==0', {
'ldflags': [
@@ -1094,13 +1123,30 @@
],
}]]
}],
+ ['clang==1', {
+ 'cflags': [
+ # Don't warn about unused variables, due to a common pattern:
+ # scoped_deleter unused_variable(&thing_to_delete);
+ '-Wno-unused-variable',
+ # Clang spots more unused functions.
+ '-Wno-unused-function',
+ # gtest confuses clang.
+ '-Wno-bool-conversions',
+ # Don't die on dtoa code that uses a char as an array index.
+ '-Wno-char-subscripts',
+ ],
+ 'cflags!': [
+ # Clang doesn't seem to know know this flag.
+ '-mfpmath=sse',
+ ],
+ }],
['no_strict_aliasing==1', {
'cflags': [
'-fno-strict-aliasing',
],
}],
['linux_breakpad==1', {
- 'cflags': [ '-gstabs' ],
+ 'cflags': [ '-g' ],
'defines': ['USE_LINUX_BREAKPAD'],
}],
['linux_use_seccomp_sandbox==1 and buildtype!="Official"', {
@@ -1126,6 +1172,10 @@
['linux_use_heapchecker==0', {
'defines': ['NO_HEAPCHECKER'],
}],
+ ['linux_keep_shadow_stacks==1', {
+ 'defines': ['KEEP_SHADOW_STACKS'],
+ 'cflags': ['-finstrument-functions'],
+ }],
],
},
}],
@@ -1145,9 +1195,10 @@
['OS=="mac"', {
'target_defaults': {
'variables': {
- # This should be 'mac_real_dsym%', but there seems to be a bug
- # with % in variables that are intended to be set to different
- # values in different targets, like this one.
+ # These should be 'mac_real_dsym%' and 'mac_strip%', but there
+ # seems to be a bug with % in variables that are intended to be
+ # set to different values in different targets, like these two.
+ 'mac_strip': 1, # Strip debugging symbols from the target.
'mac_real_dsym': 0, # Fake .dSYMs are fine in most cases.
},
'mac_bundle': 0,
@@ -1186,6 +1237,13 @@
['chromium_mac_pch', {'GCC_PRECOMPILE_PREFIX_HEADER': 'YES'},
{'GCC_PRECOMPILE_PREFIX_HEADER': 'NO'}
],
+ ['clang==1', {
+ 'WARNING_CFLAGS': [
+ # Don't die on dtoa code that uses a char as an array index.
+ # This is required solely for base/third_party/dmg_fp/dtoa.cc.
+ '-Wno-char-subscripts',
+ ],
+ }],
],
},
'target_conditions': [
@@ -1195,7 +1253,8 @@
['_mac_bundle', {
'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
}],
- ['_type=="executable" or _type=="shared_library" or _type=="loadable_module"', {
+ ['(_type=="executable" or _type=="shared_library" or \
+ _type=="loadable_module") and mac_strip!=0', {
'target_conditions': [
['mac_real_dsym == 1', {
# To get a real .dSYM bundle produced by dsymutil, set the
@@ -1239,7 +1298,8 @@
], # postbuilds
}], # mac_real_dsym
], # target_conditions
- }], # _type=="executable" or _type=="shared_library" or _type=="loadable_module"
+ }], # (_type=="executable" or _type=="shared_library" or
+ # _type=="loadable_module") and mac_strip!=0
], # target_conditions
}, # target_defaults
}], # OS=="mac"
@@ -1265,7 +1325,6 @@
],
}],
],
-
'msvs_system_include_dirs': [
'<(DEPTH)/third_party/platformsdk_win7/files/Include',
'<(DEPTH)/third_party/directxsdk/files/Include',
@@ -1286,7 +1345,6 @@
[ 'msvs_multi_core_compile', {
'AdditionalOptions': ['/MP'],
}],
-
['component=="shared_library"', {
'ExceptionHandling': '1', # /EHsc
}, {
diff --git a/build/features_override.gypi b/build/features_override.gypi
index 2e19776..6c38efa 100644
--- a/build/features_override.gypi
+++ b/build/features_override.gypi
@@ -11,21 +11,25 @@
# but not listed below, it will revert to its hardcoded webkit value.
'feature_defines': [
'ENABLE_3D_CANVAS=1',
+ 'ENABLE_BLOB=1',
'ENABLE_BLOB_SLICE=1',
'ENABLE_CHANNEL_MESSAGING=1',
'ENABLE_DASHBOARD_SUPPORT=0',
'ENABLE_DATABASE=1',
'ENABLE_DATAGRID=0',
+ 'ENABLE_DEVICE_ORIENTATION=1',
'ENABLE_DIRECTORY_UPLOAD=1',
'ENABLE_DOM_STORAGE=1',
'ENABLE_EVENTSOURCE=1',
- 'ENABLE_FILE_READER=1',
+ 'ENABLE_FILE_SYSTEM=1',
'ENABLE_FILTERS=1',
'ENABLE_GEOLOCATION=1',
'ENABLE_ICONDATABASE=0',
'ENABLE_INDEXED_DATABASE=1',
+ 'ENABLE_INPUT_SPEECH=1',
'ENABLE_JAVASCRIPT_DEBUGGER=1',
'ENABLE_JSC_MULTIPLE_THREADS=0',
+ 'ENABLE_LINK_PREFETCH=1',
'ENABLE_METER_TAG=1',
'ENABLE_NOTIFICATIONS=1',
'ENABLE_OFFLINE_WEB_APPLICATIONS=1',
@@ -47,13 +51,14 @@
'ENABLE_WEB_SOCKETS=1',
'ENABLE_WEB_TIMING=1',
'ENABLE_WORKERS=1',
+ 'ENABLE_XHR_RESPONSE_BLOB=1',
'ENABLE_XPATH=1',
'ENABLE_XSLT=1',
],
# We have to nest variables inside variables so that they can be overridden
# through GYP_DEFINES.
'variables': {
- 'use_accelerated_compositing%': 0,
+ 'use_accelerated_compositing%': 1,
'enable_svg%': 1,
'enable_touch_events%': 1,
},
@@ -61,10 +66,11 @@
'enable_svg%': '<(enable_svg)',
'enable_touch_events%': '<(enable_touch_events)',
'conditions': [
- ['OS=="win" or OS=="linux" or use_accelerated_compositing==1', {
+ ['(OS=="win" or OS=="linux" or OS=="mac") and use_accelerated_compositing==1', {
'feature_defines': [
- 'WTF_USE_ACCELERATED_COMPOSITING=1',
- 'ENABLE_3D_RENDERING=1',
+ 'WTF_USE_ACCELERATED_COMPOSITING=1',
+ 'ENABLE_3D_RENDERING=1',
+ 'ENABLE_ACCELERATED_2D_CANVAS=1',
],
'use_accelerated_compositing': 1,
}],
diff --git a/build/linux/system.Makefile b/build/linux/system.Makefile
index 4eebf76..b93aff2 100644
--- a/build/linux/system.Makefile
+++ b/build/linux/system.Makefile
@@ -3,4 +3,4 @@
export builddir_name ?= /usr/local/google/src/chromium-merge/src/build/linux/out
.PHONY: all
all:
- $(MAKE) -C ../.. xext dbus-glib gtk gnome-keyring fontconfig x11 gconf gdk freetype2 gtkprint nss
+ $(MAKE) -C ../.. libresolv freetype2 xext dbus-glib gtkprint gtk fontconfig gdk gconf gnome-keyring x11 nss
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 876579a..ed88a0a 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -15,7 +15,7 @@
}],
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
'variables': {
- # We use our own copy of libssl, although we still need to link against
+ # We use our own copy of libssl3, although we still need to link against
# the rest of NSS.
'use_system_ssl%': 0,
},
@@ -81,7 +81,7 @@
],
'direct_dependent_settings': {
'cflags': [
- # We need for our local copies of the libssl headers to come
+ # We need for our local copies of the libssl3 headers to come
# first, otherwise the code will build, but will fallback to
# the set of features advertised in the system headers.
# Unfortunately, there's no include path that we can filter
@@ -102,7 +102,7 @@
'<!@(<(pkg-config) --libs-only-l nss | sed -e "s/-lssl3//")',
],
},
- }, {
+ }, {
'direct_dependent_settings': {
'cflags': [
'<!@(<(pkg-config) --cflags nss)',
@@ -119,7 +119,8 @@
'<!@(<(pkg-config) --libs-only-l nss)',
],
},
- }]]
+ }
+ ]]
}],
],
},
@@ -259,11 +260,14 @@
'target_name': 'gnome-keyring',
'type': 'settings',
'conditions': [
- ['chromeos==0', {
+ ['use_gnome_keyring==1', {
'direct_dependent_settings': {
'cflags': [
'<!@(<(pkg-config) --cflags gnome-keyring-1)',
],
+ 'defines': [
+ 'USE_GNOME_KEYRING',
+ ],
'conditions': [
['linux_link_gnome_keyring==0', {
'defines': ['DLOPEN_GNOME_KEYRING'],
@@ -308,6 +312,41 @@
],
},
},
+ {
+ 'target_name': 'libresolv',
+ 'type': 'settings',
+ 'link_settings': {
+ 'libraries': [
+ '-lresolv',
+ ],
+ },
+ },
+ {
+ 'target_name': 'openssl',
+ 'type': 'settings',
+ 'conditions': [
+ ['use_openssl==1', {
+ 'direct_dependent_settings': {
+ 'defines': [
+ # OpenSSL support is in development.
+ # eventually USE_OPENSSL and USE_NSS will be mutually exclusive.
+ # During the transitional period, a use_openssl=1 build still
+ # needs to define USE_NSS, so it is necessary to test the
+ # USE_OPENSSL macro before testing USE_NSS.
+ 'USE_OPENSSL',
+ ],
+ 'include_dirs': [
+ '<!@(<(pkg-config) --cflags openssl)',
+ ],
+ },
+ 'link_settings': {
+ 'libraries': [
+ '<!@(<(pkg-config) --libs-only-l openssl)',
+ ],
+ },
+ },],
+ ],
+ },
],
}
diff --git a/build/temp_gyp/googleurl.target.mk b/build/temp_gyp/googleurl.target.mk
index 8648a40..75d4bb1 100644
--- a/build/temp_gyp/googleurl.target.mk
+++ b/build/temp_gyp/googleurl.target.mk
@@ -20,6 +20,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -69,6 +70,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -143,11 +145,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/build/temp_gyp/googleurl_unittests.target.mk b/build/temp_gyp/googleurl_unittests.target.mk
index 0f023ed..e5dfba1 100644
--- a/build/temp_gyp/googleurl_unittests.target.mk
+++ b/build/temp_gyp/googleurl_unittests.target.mk
@@ -22,6 +22,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -59,6 +60,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -114,14 +116,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
diff --git a/build/util/lastchange.target.mk b/build/util/lastchange.target.mk
index 5a64d85..5aed5d9 100644
--- a/build/util/lastchange.target.mk
+++ b/build/util/lastchange.target.mk
@@ -34,6 +34,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -63,6 +64,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index e434d0c..aed7970 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -1,5 +1,9 @@
+Copyright (c) 2010 The Chromium Authors. All rights reserved.
+Use of this useless file is governed by a BSD-style license that can be
+found in the LICENSE file.
+
This file is used for making non-code changes to trigger buildbot cycles. Make
any modification below this line.
================================================================================
-Smash, smash, smash...
+This file needs more cowbell.
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 004846a..3aad30f 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -21,7 +21,6 @@ include_rules = [
"+libxml", # For search engine definition parsing.
"+media/audio", # Chrome's lightweight audio library.
"+media/base",
- "+third_party/cros",
"+third_party/expat",
"+third_party/gpsd",
"+third_party/sqlite",
diff --git a/chrome/browser/accessibility_events.cc b/chrome/browser/accessibility_events.cc
index 79d2af9..aade4b3 100644
--- a/chrome/browser/accessibility_events.cc
+++ b/chrome/browser/accessibility_events.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/accessibility_events.h"
+#include "base/values.h"
+
#include "chrome/browser/extensions/extension_accessibility_api_constants.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_service.h"
@@ -24,78 +26,96 @@ void SendAccessibilityNotification(
void AccessibilityControlInfo::SerializeToDict(DictionaryValue *dict) const {
dict->SetString(keys::kNameKey, name_);
+ dict->SetString(keys::kTypeKey, type());
}
-void AccessibilityWindowInfo::SerializeToDict(DictionaryValue *dict) const {
- AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeWindow);
+const char* AccessibilityWindowInfo::type() const {
+ return keys::kTypeWindow;
}
-void AccessibilityButtonInfo::SerializeToDict(DictionaryValue *dict) const {
- AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeButton);
+const char* AccessibilityButtonInfo::type() const {
+ return keys::kTypeButton;
}
-void AccessibilityLinkInfo::SerializeToDict(DictionaryValue *dict) const {
- AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeLink);
+const char* AccessibilityLinkInfo::type() const {
+ return keys::kTypeLink;
+}
+
+const char* AccessibilityRadioButtonInfo::type() const {
+ return keys::kTypeRadioButton;
}
void AccessibilityRadioButtonInfo::SerializeToDict(
DictionaryValue *dict) const {
AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeRadioButton);
dict->SetBoolean(keys::kCheckedKey, checked_);
dict->SetInteger(keys::kItemIndexKey, item_index_);
dict->SetInteger(keys::kItemCountKey, item_count_);
}
+const char* AccessibilityCheckboxInfo::type() const {
+ return keys::kTypeCheckbox;
+}
+
void AccessibilityCheckboxInfo::SerializeToDict(DictionaryValue *dict) const {
AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeCheckbox);
dict->SetBoolean(keys::kCheckedKey, checked_);
}
+const char* AccessibilityTabInfo::type() const {
+ return keys::kTypeTab;
+}
+
void AccessibilityTabInfo::SerializeToDict(DictionaryValue *dict) const {
AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeTab);
dict->SetInteger(keys::kItemIndexKey, tab_index_);
dict->SetInteger(keys::kItemCountKey, tab_count_);
}
+const char* AccessibilityComboBoxInfo::type() const {
+ return keys::kTypeComboBox;
+}
+
void AccessibilityComboBoxInfo::SerializeToDict(DictionaryValue *dict) const {
AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeComboBox);
dict->SetString(keys::kValueKey, value_);
dict->SetInteger(keys::kItemIndexKey, item_index_);
dict->SetInteger(keys::kItemCountKey, item_count_);
}
+const char* AccessibilityTextBoxInfo::type() const {
+ return keys::kTypeTextBox;
+}
+
void AccessibilityTextBoxInfo::SerializeToDict(DictionaryValue *dict) const {
AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeTextBox);
dict->SetString(keys::kValueKey, value_);
dict->SetBoolean(keys::kPasswordKey, password_);
dict->SetInteger(keys::kSelectionStartKey, selection_start_);
dict->SetInteger(keys::kSelectionEndKey, selection_end_);
}
+const char* AccessibilityListBoxInfo::type() const {
+ return keys::kTypeListBox;
+}
+
void AccessibilityListBoxInfo::SerializeToDict(DictionaryValue *dict) const {
AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeListBox);
dict->SetString(keys::kValueKey, value_);
dict->SetInteger(keys::kItemIndexKey, item_index_);
dict->SetInteger(keys::kItemCountKey, item_count_);
}
-void AccessibilityMenuInfo::SerializeToDict(DictionaryValue *dict) const {
- AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeMenu);
+const char* AccessibilityMenuInfo::type() const {
+ return keys::kTypeMenu;
+}
+
+const char* AccessibilityMenuItemInfo::type() const {
+ return keys::kTypeMenuItem;
}
void AccessibilityMenuItemInfo::SerializeToDict(DictionaryValue *dict) const {
AccessibilityControlInfo::SerializeToDict(dict);
- dict->SetString(keys::kTypeKey, keys::kTypeMenuItem);
dict->SetBoolean(keys::kHasSubmenuKey, has_submenu_);
dict->SetInteger(keys::kItemIndexKey, item_index_);
dict->SetInteger(keys::kItemCountKey, item_count_);
diff --git a/chrome/browser/accessibility_events.h b/chrome/browser/accessibility_events.h
index a1fe7ae..a0ef971 100644
--- a/chrome/browser/accessibility_events.h
+++ b/chrome/browser/accessibility_events.h
@@ -4,12 +4,12 @@
#ifndef CHROME_BROWSER_ACCESSIBILITY_EVENTS_H_
#define CHROME_BROWSER_ACCESSIBILITY_EVENTS_H_
+#pragma once
#include <string>
-#include "base/values.h"
-
class AccessibilityControlInfo;
+class DictionaryValue;
class NotificationType;
class Profile;
@@ -28,7 +28,11 @@ class AccessibilityControlInfo {
// Serialize this class as a DictionaryValue that can be converted to
// a JavaScript object.
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual void SerializeToDict(DictionaryValue* dict) const;
+
+ // Return the specific type of this control, which will be one of the
+ // string constants defined in extension_accessibility_api_constants.h.
+ virtual const char* type() const = 0;
Profile* profile() const { return profile_; }
@@ -53,7 +57,7 @@ class AccessibilityWindowInfo : public AccessibilityControlInfo {
AccessibilityWindowInfo(Profile* profile, std::string window_name)
: AccessibilityControlInfo(profile, window_name) { }
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
};
// Accessibility information about a push button passed to onControlFocused
@@ -63,7 +67,7 @@ class AccessibilityButtonInfo : public AccessibilityControlInfo {
AccessibilityButtonInfo(Profile* profile, std::string button_name)
: AccessibilityControlInfo(profile, button_name) { }
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
};
// Accessibility information about a hyperlink passed to onControlFocused
@@ -73,7 +77,7 @@ class AccessibilityLinkInfo : public AccessibilityControlInfo {
AccessibilityLinkInfo(Profile* profile, std::string link_name)
: AccessibilityControlInfo(profile, link_name) { }
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
};
// Accessibility information about a radio button passed to onControlFocused
@@ -91,7 +95,9 @@ class AccessibilityRadioButtonInfo : public AccessibilityControlInfo {
item_count_(item_count) {
}
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
+
+ virtual void SerializeToDict(DictionaryValue* dict) const;
void SetChecked(bool checked) { checked_ = checked; }
@@ -113,7 +119,9 @@ class AccessibilityCheckboxInfo : public AccessibilityControlInfo {
checked_(checked) {
}
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
+
+ virtual void SerializeToDict(DictionaryValue* dict) const;
void SetChecked(bool checked) { checked_ = checked; }
@@ -134,7 +142,9 @@ class AccessibilityTabInfo : public AccessibilityControlInfo {
tab_count_(tab_count) {
}
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
+
+ virtual void SerializeToDict(DictionaryValue* dict) const;
void SetTab(int tab_index, std::string tab_name) {
tab_index_ = tab_index;
@@ -162,7 +172,9 @@ class AccessibilityComboBoxInfo : public AccessibilityControlInfo {
item_count_(item_count) {
}
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
+
+ virtual void SerializeToDict(DictionaryValue* dict) const;
void SetValue(int item_index, std::string value) {
item_index_ = item_index;
@@ -192,7 +204,9 @@ class AccessibilityTextBoxInfo : public AccessibilityControlInfo {
selection_end_(0) {
}
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
+
+ virtual void SerializeToDict(DictionaryValue* dict) const;
void SetValue(std::string value, int selection_start, int selection_end) {
value_ = value;
@@ -222,7 +236,9 @@ class AccessibilityListBoxInfo : public AccessibilityControlInfo {
item_count_(item_count) {
}
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
+
+ virtual void SerializeToDict(DictionaryValue* dict) const;
void SetValue(int item_index, std::string value) {
item_index_ = item_index;
@@ -245,7 +261,7 @@ class AccessibilityMenuInfo : public AccessibilityControlInfo {
AccessibilityMenuInfo(Profile* profile, std::string menu_name)
: AccessibilityControlInfo(profile, menu_name) { }
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
};
// Accessibility information about a menu item; this class is used by
@@ -263,7 +279,9 @@ class AccessibilityMenuItemInfo : public AccessibilityControlInfo {
item_count_(item_count) {
}
- virtual void SerializeToDict(DictionaryValue *dict) const;
+ virtual const char* type() const;
+
+ virtual void SerializeToDict(DictionaryValue* dict) const;
private:
bool has_submenu_;
diff --git a/chrome/browser/accessibility_win_browsertest.cc b/chrome/browser/accessibility_win_browsertest.cc
index d946082..68abd21 100644
--- a/chrome/browser/accessibility_win_browsertest.cc
+++ b/chrome/browser/accessibility_win_browsertest.cc
@@ -5,61 +5,53 @@
#include <atlbase.h>
#include <vector>
-#include "base/file_path.h"
#include "base/scoped_comptr_win.h"
+#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view_win.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+#include "ia2_api_all.h" // Generated
+
+using std::auto_ptr;
+using std::vector;
+using std::wstring;
namespace {
class AccessibilityWinBrowserTest : public InProcessBrowserTest {
public:
- AccessibilityWinBrowserTest() : screenreader_running_(FALSE) {}
+ AccessibilityWinBrowserTest() {}
// InProcessBrowserTest
void SetUpInProcessBrowserTestFixture();
- void TearDownInProcessBrowserTestFixture();
protected:
- IAccessible* GetRenderWidgetHostViewClientAccessible();
-
- private:
- BOOL screenreader_running_;
+ IAccessible* GetRendererAccessible();
+ void ExecuteScript(wstring script);
};
void AccessibilityWinBrowserTest::SetUpInProcessBrowserTestFixture() {
- // This test assumes the windows system-wide SPI_SETSCREENREADER flag is
- // cleared.
- if (SystemParametersInfo(SPI_GETSCREENREADER, 0, &screenreader_running_, 0) &&
- screenreader_running_) {
- // Clear the SPI_SETSCREENREADER flag and notify active applications about
- // the setting change.
- ::SystemParametersInfo(SPI_SETSCREENREADER, FALSE, NULL, 0);
- ::SendNotifyMessage(
- HWND_BROADCAST, WM_SETTINGCHANGE, SPI_GETSCREENREADER, 0);
- }
-}
-
-void AccessibilityWinBrowserTest::TearDownInProcessBrowserTestFixture() {
- if (screenreader_running_) {
- // Restore the SPI_SETSCREENREADER flag and notify active applications about
- // the setting change.
- ::SystemParametersInfo(SPI_SETSCREENREADER, TRUE, NULL, 0);
- ::SendNotifyMessage(
- HWND_BROADCAST, WM_SETTINGCHANGE, SPI_GETSCREENREADER, 0);
- }
+ // If the mouse happens to be on the document then it will have the unexpected
+ // STATE_SYSTEM_HOTTRACKED state. Move it to a non-document location.
+ ui_controls::SendMouseMove(0, 0);
}
class AccessibleChecker {
public:
- AccessibleChecker(std::wstring expected_name, int32 expected_role);
- AccessibleChecker(std::wstring expected_name, std::wstring expected_role);
+ AccessibleChecker(
+ wstring expected_name,
+ int32 expected_role,
+ wstring expected_value);
+ AccessibleChecker(
+ wstring expected_name,
+ wstring expected_role,
+ wstring expected_value);
// Append an AccessibleChecker that verifies accessibility information for
// a child IAccessible. Order is important.
@@ -70,20 +62,34 @@ class AccessibleChecker {
// initialized with.
void CheckAccessible(IAccessible* accessible);
- typedef std::vector<AccessibleChecker*> AccessibleCheckerVector;
+ // Set the expected value for this AccessibleChecker.
+ void SetExpectedValue(wstring expected_value);
+
+ // Set the expected state for this AccessibleChecker.
+ void SetExpectedState(LONG expected_state);
private:
void CheckAccessibleName(IAccessible* accessible);
void CheckAccessibleRole(IAccessible* accessible);
+ void CheckAccessibleValue(IAccessible* accessible);
+ void CheckAccessibleState(IAccessible* accessible);
void CheckAccessibleChildren(IAccessible* accessible);
private:
+ typedef vector<AccessibleChecker*> AccessibleCheckerVector;
+
// Expected accessible name. Checked against IAccessible::get_accName.
- std::wstring name_;
+ wstring name_;
// Expected accessible role. Checked against IAccessible::get_accRole.
CComVariant role_;
+ // Expected accessible value. Checked against IAccessible::get_accValue.
+ wstring value_;
+
+ // Expected accessible state. Checked against IAccessible::get_accState.
+ LONG state_;
+
// Expected accessible children. Checked using IAccessible::get_accChildCount
// and ::AccessibleChildren.
AccessibleCheckerVector children_;
@@ -107,7 +113,7 @@ IAccessible* GetAccessibleFromResultVariant(IAccessible* parent, VARIANT *var) {
case VT_I4: {
CComPtr<IDispatch> dispatch;
HRESULT hr = parent->get_accChild(CreateI4Variant(V_I4(var)), &dispatch);
- EXPECT_EQ(hr, S_OK);
+ EXPECT_TRUE(SUCCEEDED(hr));
return CComQIPtr<IAccessible>(dispatch).Detach();
break;
}
@@ -116,14 +122,78 @@ IAccessible* GetAccessibleFromResultVariant(IAccessible* parent, VARIANT *var) {
return NULL;
}
+HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
+ // TODO(ctguil): For some reason querying the IAccessible2 interface from
+ // IAccessible fails.
+ ScopedComPtr<IServiceProvider> service_provider;
+ HRESULT hr = accessible->QueryInterface(service_provider.Receive());
+ if (FAILED(hr))
+ return hr;
+
+ hr = service_provider->QueryService(IID_IAccessible2, accessible2);
+ return hr;
+}
+
+// Sets result to true if the child is located in the parent's tree. An
+// exhustive search is perform here because we determine equality using
+// IAccessible2::get_uniqueID which is only supported by the child node.
+void AccessibleContainsAccessible(
+ IAccessible* parent, IAccessible2* child, bool* result) {
+ vector<ScopedComPtr<IAccessible>> accessible_list;
+ accessible_list.push_back(ScopedComPtr<IAccessible>(parent));
+
+ LONG unique_id;
+ HRESULT hr = child->get_uniqueID(&unique_id);
+ ASSERT_EQ(hr, S_OK);
+ *result = false;
+
+ while (accessible_list.size()) {
+ ScopedComPtr<IAccessible> accessible = accessible_list.back();
+ accessible_list.pop_back();
+
+ ScopedComPtr<IAccessible2> accessible2;
+ hr = QueryIAccessible2(accessible, accessible2.Receive());
+ if (SUCCEEDED(hr)) {
+ LONG child_id;
+ accessible2->get_uniqueID(&child_id);
+ if (child_id == unique_id) {
+ *result = true;
+ break;
+ }
+ }
+
+ LONG child_count;
+ hr = accessible->get_accChildCount(&child_count);
+ ASSERT_EQ(hr, S_OK);
+ if (child_count == 0)
+ continue;
+
+ auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
+ LONG obtained_count = 0;
+ hr = AccessibleChildren(
+ accessible, 0, child_count, child_array.get(), &obtained_count);
+ ASSERT_EQ(hr, S_OK);
+ ASSERT_EQ(child_count, obtained_count);
+
+ for (int index = 0; index < obtained_count; index++) {
+ ScopedComPtr<IAccessible> child_accessible(
+ GetAccessibleFromResultVariant(accessible, &child_array.get()[index]));
+ if (child_accessible.get())
+ accessible_list.push_back(ScopedComPtr<IAccessible>(child_accessible));
+ }
+ }
+}
+
// Retrieve the MSAA client accessibility object for the Render Widget Host View
// of the selected tab.
IAccessible*
-AccessibilityWinBrowserTest::GetRenderWidgetHostViewClientAccessible() {
+AccessibilityWinBrowserTest::GetRendererAccessible() {
HWND hwnd_render_widget_host_view =
browser()->GetSelectedTabContents()->GetRenderWidgetHostView()->
GetNativeView();
+ // By requesting an accessible chrome will believe a screen reader has been
+ // detected.
IAccessible* accessible;
HRESULT hr = AccessibleObjectFromWindow(
hwnd_render_widget_host_view, OBJID_CLIENT,
@@ -134,16 +204,25 @@ AccessibilityWinBrowserTest::GetRenderWidgetHostViewClientAccessible() {
return accessible;
}
+void AccessibilityWinBrowserTest::ExecuteScript(wstring script) {
+ browser()->GetSelectedTabContents()->render_view_host()->
+ ExecuteJavascriptInWebFrame(L"", script);
+}
+
AccessibleChecker::AccessibleChecker(
- std::wstring expected_name, int32 expected_role) :
+ wstring expected_name, int32 expected_role, wstring expected_value) :
name_(expected_name),
- role_(expected_role) {
+ role_(expected_role),
+ value_(expected_value),
+ state_(-1) {
}
AccessibleChecker::AccessibleChecker(
- std::wstring expected_name, std::wstring expected_role) :
+ wstring expected_name, wstring expected_role, wstring expected_value) :
name_(expected_name),
- role_(expected_role.c_str()) {
+ role_(expected_role.c_str()),
+ value_(expected_value),
+ state_(-1) {
}
void AccessibleChecker::AppendExpectedChild(
@@ -154,9 +233,19 @@ void AccessibleChecker::AppendExpectedChild(
void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
CheckAccessibleName(accessible);
CheckAccessibleRole(accessible);
+ CheckAccessibleValue(accessible);
+ CheckAccessibleState(accessible);
CheckAccessibleChildren(accessible);
}
+void AccessibleChecker::SetExpectedValue(wstring expected_value) {
+ value_ = expected_value;
+}
+
+void AccessibleChecker::SetExpectedState(LONG expected_state) {
+ state_ = expected_state;
+}
+
void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
CComBSTR name;
HRESULT hr =
@@ -168,9 +257,8 @@ void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
} else {
// Test that the correct string was returned.
EXPECT_EQ(hr, S_OK);
- EXPECT_EQ(CompareString(LOCALE_NEUTRAL, 0, name, SysStringLen(name),
- name_.c_str(), name_.length()),
- CSTR_EQUAL);
+ EXPECT_STREQ(name_.c_str(),
+ wstring(name.m_str, SysStringLen(name)).c_str());
}
}
@@ -178,8 +266,31 @@ void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
VARIANT var_role = {0};
HRESULT hr =
accessible->get_accRole(CreateI4Variant(CHILDID_SELF), &var_role);
+ ASSERT_EQ(hr, S_OK);
+ EXPECT_TRUE(role_ == var_role);
+}
+
+void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
+ CComBSTR value;
+ HRESULT hr =
+ accessible->get_accValue(CreateI4Variant(CHILDID_SELF), &value);
+ EXPECT_EQ(S_OK, hr);
+
+ // Test that the correct string was returned.
+ EXPECT_STREQ(value_.c_str(),
+ wstring(value.m_str, SysStringLen(value)).c_str());
+}
+
+void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
+ if (state_ < 0)
+ return;
+
+ VARIANT var_state = {0};
+ HRESULT hr =
+ accessible->get_accState(CreateI4Variant(CHILDID_SELF), &var_state);
EXPECT_EQ(hr, S_OK);
- ASSERT_TRUE(role_ == var_role);
+ ASSERT_EQ(VT_I4, V_VT(&var_state));
+ EXPECT_EQ(state_, V_I4(&var_state));
}
void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
@@ -188,7 +299,7 @@ void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
EXPECT_EQ(hr, S_OK);
ASSERT_EQ(child_count, children_.size());
- std::auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
+ auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
LONG obtained_count = 0;
hr = AccessibleChildren(parent, 0, child_count,
child_array.get(), &obtained_count);
@@ -201,29 +312,27 @@ void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
++child_checker, ++child) {
ScopedComPtr<IAccessible> child_accessible;
child_accessible.Attach(GetAccessibleFromResultVariant(parent, child));
+ ASSERT_TRUE(child_accessible.get());
(*child_checker)->CheckAccessible(child_accessible);
}
}
IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
TestRendererAccessibilityTree) {
- // By requesting an accessible chrome will believe a screen reader has been
- // detected.
- ScopedComPtr<IAccessible> document_accessible(
- GetRenderWidgetHostViewClientAccessible());
-
// The initial accessible returned should have state STATE_SYSTEM_BUSY while
// the accessibility tree is being requested from the renderer.
- VARIANT var_state;
- HRESULT hr = document_accessible->
- get_accState(CreateI4Variant(CHILDID_SELF), &var_state);
- EXPECT_EQ(hr, S_OK);
- EXPECT_EQ(V_VT(&var_state), VT_I4);
- EXPECT_EQ(V_I4(&var_state), STATE_SYSTEM_BUSY);
+ AccessibleChecker document1_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
+ document1_checker.SetExpectedState(
+ STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED |
+ STATE_SYSTEM_BUSY);
+ document1_checker.CheckAccessible(GetRendererAccessible());
- // Wait for the initial accessibility tree to load.
+ // Wait for the initial accessibility tree to load. Busy state should clear.
ui_test_utils::WaitForNotification(
NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+ document1_checker.SetExpectedState(
+ STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
+ document1_checker.CheckAccessible(GetRendererAccessible());
GURL tree_url(
"data:text/html,<html><head><title>Accessibility Win Test</title></head>"
@@ -233,25 +342,22 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
ui_test_utils::WaitForNotification(
NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
- document_accessible = GetRenderWidgetHostViewClientAccessible();
- ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
-
- AccessibleChecker button_checker(L"push", ROLE_SYSTEM_PUSHBUTTON);
- AccessibleChecker checkbox_checker(L"", ROLE_SYSTEM_CHECKBUTTON);
-
- AccessibleChecker grouping_checker(L"", L"div");
- grouping_checker.AppendExpectedChild(&button_checker);
- grouping_checker.AppendExpectedChild(&checkbox_checker);
-
- AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT);
- document_checker.AppendExpectedChild(&grouping_checker);
-
- // Check the accessible tree of the renderer.
- document_checker.CheckAccessible(document_accessible);
+ // Check the browser's copy of the renderer accessibility tree.
+ AccessibleChecker button_checker(L"push", ROLE_SYSTEM_PUSHBUTTON, L"push");
+ AccessibleChecker checkbox_checker(L"", ROLE_SYSTEM_CHECKBUTTON, L"");
+ AccessibleChecker body_checker(L"", L"body", L"");
+ AccessibleChecker document2_checker(
+ L"Accessibility Win Test", ROLE_SYSTEM_DOCUMENT, L"");
+ body_checker.AppendExpectedChild(&button_checker);
+ body_checker.AppendExpectedChild(&checkbox_checker);
+ document2_checker.AppendExpectedChild(&body_checker);
+ document2_checker.CheckAccessible(GetRendererAccessible());
// Check that document accessible has a parent accessible.
+ ScopedComPtr<IAccessible> document_accessible(GetRendererAccessible());
+ ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
ScopedComPtr<IDispatch> parent_dispatch;
- hr = document_accessible->get_accParent(parent_dispatch.Receive());
+ HRESULT hr = document_accessible->get_accParent(parent_dispatch.Receive());
EXPECT_EQ(hr, S_OK);
EXPECT_NE(parent_dispatch, reinterpret_cast<IDispatch*>(NULL));
@@ -262,13 +368,285 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
// Verify that the IAccessible reference still points to a valid object and
// that calls to its methods fail since the tree is no longer valid after
// the page navagation.
- // Todo(ctguil): Currently this is giving a false positive because E_FAIL is
- // returned when BrowserAccessibilityManager::RequestAccessibilityInfo fails
- // since the previous render view host connection is lost. Verify that
- // instances are actually marked as invalid once the browse side cache is
- // checked in.
CComBSTR name;
hr = document_accessible->get_accName(CreateI4Variant(CHILDID_SELF), &name);
ASSERT_EQ(E_FAIL, hr);
}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestNotificationActiveDescendantChanged) {
+ GURL tree_url("data:text/html,<ul tabindex='-1' role='radiogroup'><li id='li'"
+ ">li</li></ul>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ GetRendererAccessible();
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check the browser's copy of the renderer accessibility tree.
+ AccessibleChecker list_marker_checker(L"", ROLE_SYSTEM_LISTITEM, L"\x2022");
+ AccessibleChecker static_text_checker(L"", ROLE_SYSTEM_TEXT, L"li");
+ AccessibleChecker list_item_checker(L"", ROLE_SYSTEM_LISTITEM, L"");
+ list_item_checker.SetExpectedState(
+ STATE_SYSTEM_READONLY);
+ AccessibleChecker radio_group_checker(L"", ROLE_SYSTEM_GROUPING, L"");
+ radio_group_checker.SetExpectedState(
+ STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
+ AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
+ list_item_checker.AppendExpectedChild(&list_marker_checker);
+ list_item_checker.AppendExpectedChild(&static_text_checker);
+ radio_group_checker.AppendExpectedChild(&list_item_checker);
+ document_checker.AppendExpectedChild(&radio_group_checker);
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // Set focus to the radio group.
+ ExecuteScript(L"document.body.children[0].focus()");
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ radio_group_checker.SetExpectedState(
+ STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // Set the active descendant of the radio group
+ ExecuteScript(
+ L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ list_item_checker.SetExpectedState(
+ STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
+ radio_group_checker.SetExpectedState(
+ STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
+ document_checker.CheckAccessible(GetRendererAccessible());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestNotificationCheckedStateChanged) {
+ GURL tree_url("data:text/html,<body><input type='checkbox' /></body>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ GetRendererAccessible();
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check the browser's copy of the renderer accessibility tree.
+ AccessibleChecker checkbox_checker(L"", ROLE_SYSTEM_CHECKBUTTON, L"");
+ checkbox_checker.SetExpectedState(
+ STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
+ AccessibleChecker body_checker(L"", L"body", L"");
+ AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
+ body_checker.AppendExpectedChild(&checkbox_checker);
+ document_checker.AppendExpectedChild(&body_checker);
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // Check the checkbox.
+ ExecuteScript(L"document.body.children[0].checked=true");
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ checkbox_checker.SetExpectedState(
+ STATE_SYSTEM_CHECKED | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
+ document_checker.CheckAccessible(GetRendererAccessible());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestNotificationChildrenChanged) {
+ // The role attribute causes the node to be in the accessibility tree.
+ GURL tree_url(
+ "data:text/html,<body role=group></body>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ GetRendererAccessible();
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check the browser's copy of the renderer accessibility tree.
+ AccessibleChecker body_checker(L"", L"body", L"");
+ AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
+ document_checker.AppendExpectedChild(&body_checker);
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // Change the children of the document body.
+ ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ AccessibleChecker text_checker(L"", ROLE_SYSTEM_TEXT, L"new text");
+ body_checker.AppendExpectedChild(&text_checker);
+ document_checker.CheckAccessible(GetRendererAccessible());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestNotificationFocusChanged) {
+ // The role attribute causes the node to be in the accessibility tree.
+ GURL tree_url(
+ "data:text/html,<div role=group tabindex='-1'></div>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ GetRendererAccessible();
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check the browser's copy of the renderer accessibility tree.
+ AccessibleChecker div_checker(L"", L"div", L"");
+ div_checker.SetExpectedState(
+ STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_READONLY);
+ AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
+ document_checker.AppendExpectedChild(&div_checker);
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // Focus the div in the document
+ ExecuteScript(L"document.body.children[0].focus()");
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ div_checker.SetExpectedState(
+ STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // TODO(ctguil): The renderer should notify the browser when focus is cleared.
+ // Uncomment code below when fixed.
+ // Focus the document accessible. This will un-focus the current node.
+ // http://crbug.com/57045
+ ScopedComPtr<IAccessible> document_accessible(GetRendererAccessible());
+ ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
+ HRESULT hr = document_accessible->accSelect(
+ SELFLAG_TAKEFOCUS, CreateI4Variant(CHILDID_SELF));
+ ASSERT_EQ(hr, S_OK);
+ // ui_test_utils::WaitForNotification(
+ // NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ // div_checker.SetExpectedState(
+ // STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
+ // document_checker.CheckAccessible(GetRendererAccessible());
+}
+
+// http://crbug.com/46209
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ DISABLED_TestNotificationChildrenChanged2) {
+ // The role attribute causes the node to be in the accessibility tree.
+ GURL tree_url(
+ "data:text/html,<div role=group style='visibility: hidden'>text"
+ "</div>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ GetRendererAccessible();
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check the accessible tree of the browser.
+ AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // Change the children of the document body.
+ ExecuteScript(L"document.body.children[0].style.visibility='visible'");
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ AccessibleChecker static_text_checker(L"", ROLE_SYSTEM_TEXT, L"text");
+ AccessibleChecker div_checker(L"", L"div", L"");
+ document_checker.AppendExpectedChild(&div_checker);
+ div_checker.AppendExpectedChild(&static_text_checker);
+ document_checker.CheckAccessible(GetRendererAccessible());
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ TestNotificationValueChanged) {
+ GURL tree_url("data:text/html,<body><input type='text' value='old value'/>"
+ "</body>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ GetRendererAccessible();
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check the browser's copy of the renderer accessibility tree.
+ AccessibleChecker static_text_checker(L"", ROLE_SYSTEM_TEXT, L"old value");
+ AccessibleChecker text_field_div_checker(L"", L"div", L"");
+ AccessibleChecker text_field_checker(L"", ROLE_SYSTEM_TEXT, L"old value");
+ text_field_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
+ AccessibleChecker body_checker(L"", L"body", L"");
+ AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
+ text_field_div_checker.AppendExpectedChild(&static_text_checker);
+ text_field_checker.AppendExpectedChild(&text_field_div_checker);
+ body_checker.AppendExpectedChild(&text_field_checker);
+ document_checker.AppendExpectedChild(&body_checker);
+ document_checker.CheckAccessible(GetRendererAccessible());
+
+ // Set the value of the text control
+ ExecuteScript(L"document.body.children[0].value='new value'");
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Check that the accessibility tree of the browser has been updated.
+ text_field_checker.SetExpectedValue(L"new value");
+ static_text_checker.SetExpectedValue(L"new value");
+ document_checker.CheckAccessible(GetRendererAccessible());
+}
+
+// FAILS crbug.com/54220
+// This test verifies that browser-side cache of the renderer accessibility
+// tree is reachable from the browser's tree. Tools that analyze windows
+// accessibility trees like AccExplorer32 should be able to drill into the
+// cached renderer accessibility tree.
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ DISABLED_ContainsRendererAccessibilityTree) {
+ GURL tree_url("data:text/html,<body><input type='checkbox' /></body>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ GetRendererAccessible();
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Get the accessibility object for the browser window.
+ HWND browser_hwnd = browser()->window()->GetNativeHandle();
+ ScopedComPtr<IAccessible> browser_accessible;
+ HRESULT hr = AccessibleObjectFromWindow(
+ browser_hwnd,
+ OBJID_WINDOW,
+ IID_IAccessible,
+ reinterpret_cast<void**>(browser_accessible.Receive()));
+ ASSERT_EQ(S_OK, hr);
+
+ // Get the accessibility object for the renderer client document.
+ ScopedComPtr<IAccessible> document_accessible(GetRendererAccessible());
+ ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
+ ScopedComPtr<IAccessible2> document_accessible2;
+ hr = QueryIAccessible2(document_accessible, document_accessible2.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ // TODO(ctguil): Pointer comparison of retrieved IAccessible pointers dosen't
+ // seem to work for here. Perhaps make IAccessible2 available in views to make
+ // unique id comparison available.
+ bool found = false;
+ ScopedComPtr<IAccessible> parent = document_accessible;
+ while (parent.get()) {
+ ScopedComPtr<IDispatch> parent_dispatch;
+ hr = parent->get_accParent(parent_dispatch.Receive());
+ ASSERT_TRUE(SUCCEEDED(hr));
+ if (!parent_dispatch.get()) {
+ ASSERT_EQ(hr, S_FALSE);
+ break;
+ }
+
+ parent.Release();
+ hr = parent_dispatch.QueryInterface(parent.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ if (parent.get() == browser_accessible.get()) {
+ found = true;
+ break;
+ }
+ }
+
+ // If pointer comparison fails resort to the exhuasive search that can use
+ // IAccessible2::get_uniqueID for equality comparison.
+ if (!found) {
+ AccessibleContainsAccessible(
+ browser_accessible, document_accessible2, &found);
+ }
+
+ ASSERT_EQ(found, true);
+}
} // namespace.
diff --git a/chrome/browser/aeropeek_manager.cc b/chrome/browser/aeropeek_manager.cc
index ba0ca91..586fcab 100644
--- a/chrome/browser/aeropeek_manager.cc
+++ b/chrome/browser/aeropeek_manager.cc
@@ -12,6 +12,7 @@
#include "base/scoped_comptr_win.h"
#include "base/scoped_handle_win.h"
#include "base/scoped_native_library.h"
+#include "base/waitable_event.h"
#include "base/win_util.h"
#include "chrome/browser/app_icon_win.h"
#include "chrome/browser/browser_list.h"
@@ -23,6 +24,7 @@
#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/tabs/tab_strip_model.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/aeropeek_manager.h b/chrome/browser/aeropeek_manager.h
index 80d60db..3c2d0cb 100644
--- a/chrome/browser/aeropeek_manager.h
+++ b/chrome/browser/aeropeek_manager.h
@@ -4,19 +4,21 @@
#ifndef CHROME_BROWSER_AEROPEEK_MANAGER_H_
#define CHROME_BROWSER_AEROPEEK_MANAGER_H_
+#pragma once
+
+#include <windows.h>
#include <list>
-#include "base/waitable_event.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
#include "gfx/insets.h"
namespace gfx {
class Size;
}
-class TabContents;
class AeroPeekWindow;
class SkBitmap;
+class TabContents;
// A class which defines interfaces called from AeroPeekWindow.
// This class is used for dispatching an event received by a thumbnail window
@@ -45,6 +47,9 @@ class AeroPeekWindowDelegate {
virtual void GetContentInsets(gfx::Insets* insets) = 0;
virtual bool GetTabThumbnail(int tab_id, SkBitmap* thumbnail) = 0;
virtual bool GetTabPreview(int tab_id, SkBitmap* preview) = 0;
+
+ protected:
+ virtual ~AeroPeekWindowDelegate() {}
};
// A class that implements AeroPeek of Windows 7:
@@ -91,7 +96,7 @@ class AeroPeekManager : public TabStripModelObserver,
public AeroPeekWindowDelegate {
public:
explicit AeroPeekManager(HWND application_window);
- ~AeroPeekManager();
+ virtual ~AeroPeekManager();
// Sets the margins of the "user-perceived content area".
// (See comments of |content_insets_|).
diff --git a/chrome/browser/alternate_nav_url_fetcher.cc b/chrome/browser/alternate_nav_url_fetcher.cc
index ebe136e..4e329cd 100644
--- a/chrome/browser/alternate_nav_url_fetcher.cc
+++ b/chrome/browser/alternate_nav_url_fetcher.cc
@@ -95,16 +95,16 @@ void AlternateNavURLFetcher::OnURLFetchComplete(const URLFetcher* source,
ShowInfobarIfPossible();
}
-std::wstring AlternateNavURLFetcher::GetMessageTextWithOffset(
+string16 AlternateNavURLFetcher::GetMessageTextWithOffset(
size_t* link_offset) const {
- const std::wstring label = l10n_util::GetStringF(
- IDS_ALTERNATE_NAV_URL_VIEW_LABEL, std::wstring(), link_offset);
- DCHECK(*link_offset != std::wstring::npos);
+ const string16 label = l10n_util::GetStringFUTF16(
+ IDS_ALTERNATE_NAV_URL_VIEW_LABEL, string16(), link_offset);
+ DCHECK(*link_offset != string16::npos);
return label;
}
-std::wstring AlternateNavURLFetcher::GetLinkText() const {
- return UTF8ToWide(alternate_nav_url_.spec());
+string16 AlternateNavURLFetcher::GetLinkText() const {
+ return UTF8ToUTF16(alternate_nav_url_.spec());
}
SkBitmap* AlternateNavURLFetcher::GetIcon() const {
diff --git a/chrome/browser/alternate_nav_url_fetcher.h b/chrome/browser/alternate_nav_url_fetcher.h
index 2295617..e888d07 100644
--- a/chrome/browser/alternate_nav_url_fetcher.h
+++ b/chrome/browser/alternate_nav_url_fetcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_ALTERNATE_NAV_URL_FETCHER_H_
#define CHROME_BROWSER_ALTERNATE_NAV_URL_FETCHER_H_
+#pragma once
#include <string>
@@ -55,8 +56,8 @@ class AlternateNavURLFetcher : public NotificationObserver,
const std::string& data);
// LinkInfoBarDelegate
- virtual std::wstring GetMessageTextWithOffset(size_t* link_offset) const;
- virtual std::wstring GetLinkText() const;
+ virtual string16 GetMessageTextWithOffset(size_t* link_offset) const;
+ virtual string16 GetLinkText() const;
virtual SkBitmap* GetIcon() const;
virtual bool LinkClicked(WindowOpenDisposition disposition);
virtual void InfoBarClosed();
diff --git a/chrome/browser/app_controller_cppsafe_mac.h b/chrome/browser/app_controller_cppsafe_mac.h
index da2aefb..36df149 100644
--- a/chrome/browser/app_controller_cppsafe_mac.h
+++ b/chrome/browser/app_controller_cppsafe_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_APP_CONTROLLER_CPPSAFE_MAC_H_
#define CHROME_BROWSER_APP_CONTROLLER_CPPSAFE_MAC_H_
+#pragma once
// We declare this in a separate file that is safe for including in C++ code.
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h
index 4a33607..dc555e0 100644
--- a/chrome/browser/app_controller_mac.h
+++ b/chrome/browser/app_controller_mac.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_APP_CONTROLLER_MAC_H_
#define CHROME_BROWSER_APP_CONTROLLER_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#include <vector>
@@ -14,7 +15,6 @@
@class AboutWindowController;
class BookmarkMenuBridge;
class CommandUpdater;
-@class CrApplication;
class GURL;
class HistoryMenuBridge;
@class PreferencesWindowController;
@@ -49,6 +49,9 @@ class Profile;
// Outlet for the help menu so we can bless it so Cocoa adds the search item
// to it.
IBOutlet NSMenu* helpMenu_;
+
+ // Outlet for the tabpose menu item so we can hide it.
+ IBOutlet NSMenuItem* tabposeMenuItem_;
}
@property(readonly, nonatomic) BOOL startupComplete;
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 1ebff27..72a0b75 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -4,11 +4,14 @@
#import "chrome/browser/app_controller_mac.h"
+#include "app/l10n_util.h"
#include "app/l10n_util_mac.h"
#include "base/auto_reset.h"
#include "base/command_line.h"
+#include "base/file_path.h"
#include "base/mac_util.h"
#include "base/message_loop.h"
+#include "base/string_number_conversions.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
@@ -35,7 +38,7 @@
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/options_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -47,6 +50,7 @@
#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/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/net_util.h"
@@ -137,6 +141,7 @@ void RecordLastRunAppBundlePath() {
@interface AppController(Private)
- (void)initMenuState;
+- (void)registerServicesMenuTypesTo:(NSApplication*)app;
- (void)openUrls:(const std::vector<GURL>&)urls;
- (void)getUrl:(NSAppleEventDescriptor*)event
withReply:(NSAppleEventDescriptor*)reply;
@@ -241,7 +246,7 @@ void RecordLastRunAppBundlePath() {
// Initiate a shutdown (via BrowserList::CloseAllBrowsers()) if we aren't
// already shutting down.
if (!browser_shutdown::IsTryingToQuit())
- BrowserList::CloseAllBrowsers(true);
+ BrowserList::CloseAllBrowsers();
return num_browsers == 0 ? YES : NO;
}
@@ -480,6 +485,9 @@ void RecordLastRunAppBundlePath() {
// shim.
RecordLastRunAppBundlePath();
+ // Makes "Services" menu items available.
+ [self registerServicesMenuTypesTo:[notify object]];
+
startupComplete_ = YES;
// TODO(viettrungluu): This is very temporary, since this should be done "in"
@@ -489,6 +497,11 @@ void RecordLastRunAppBundlePath() {
[self openUrls:startupUrls_];
[self clearStartupUrls];
}
+
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ if (!parsed_command_line.HasSwitch(switches::kEnableExposeForTabs)) {
+ [tabposeMenuItem_ setHidden:YES];
+ }
}
// This is called after profiles have been loaded and preferences registered.
@@ -528,7 +541,7 @@ void RecordLastRunAppBundlePath() {
// Dialog text: warning and explanation.
warningText = l10n_util::GetNSStringF(
IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_WARNING, product_name,
- IntToString16(downloadCount));
+ base::IntToString16(downloadCount));
explanationText = l10n_util::GetNSStringF(
IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_EXPLANATION, product_name);
@@ -837,6 +850,23 @@ void RecordLastRunAppBundlePath() {
if (flag)
return YES;
+ // If launched as a hidden login item (due to installation of a persistent app
+ // or by the user, for example in System Preferenecs->Accounts->Login Items),
+ // allow session to be restored first time the user clicks on a Dock icon.
+ // Normally, it'd just open a new empty page.
+ {
+ static BOOL doneOnce = NO;
+ if (!doneOnce) {
+ doneOnce = YES;
+ if (mac_util::WasLaunchedAsHiddenLoginItem()) {
+ SessionService* sessionService =
+ [self defaultProfile]->GetSessionService();
+ if (sessionService &&
+ sessionService->RestoreIfNecessary(std::vector<GURL>()))
+ return NO;
+ }
+ }
+ }
// Otherwise open a new window.
{
AutoReset<bool> auto_reset_in_run(&g_is_opening_new_window, true);
@@ -869,6 +899,13 @@ void RecordLastRunAppBundlePath() {
menuState_->UpdateCommandEnabled(IDC_TASK_MANAGER, true);
}
+- (void)registerServicesMenuTypesTo:(NSApplication*)app {
+ // Note that RenderWidgetHostViewCocoa implements NSServicesRequests which
+ // handles requests from services.
+ NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil];
+ [app registerServicesMenuSendTypes:types returnTypes:types];
+}
+
- (Profile*)defaultProfile {
// TODO(jrg): Find a better way to get the "default" profile.
if (g_browser_process->profile_manager())
@@ -897,7 +934,7 @@ void RecordLastRunAppBundlePath() {
}
CommandLine dummy(CommandLine::ARGUMENTS_ONLY);
- BrowserInit::LaunchWithProfile launch(std::wstring(), dummy);
+ BrowserInit::LaunchWithProfile launch(FilePath(), dummy);
launch.OpenURLsInBrowser(browser, false, urls);
}
@@ -949,7 +986,7 @@ void RecordLastRunAppBundlePath() {
if (parsed_command_line.HasSwitch(switches::kEnableTabbedOptions)) {
if (Browser* browser = ActivateBrowser([self defaultProfile])) {
// Show options tab in the active browser window.
- browser->ShowOptionsTab();
+ browser->ShowOptionsTab(chrome::kDefaultOptionsSubPage);
} else {
// No browser window, so create one for the options tab.
Browser::OpenOptionsWindow([self defaultProfile]);
diff --git a/chrome/browser/app_icon_win.h b/chrome/browser/app_icon_win.h
index 5239cdf..02dc9b2 100644
--- a/chrome/browser/app_icon_win.h
+++ b/chrome/browser/app_icon_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_APP_ICON_WIN_H_
#define CHROME_BROWSER_APP_ICON_WIN_H_
+#pragma once
#include <windows.h>
diff --git a/chrome/browser/app_launched_animation.h b/chrome/browser/app_launched_animation.h
index b31a25d..278b228 100644
--- a/chrome/browser/app_launched_animation.h
+++ b/chrome/browser/app_launched_animation.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_APP_LAUNCHED_ANIMATION_H_
#define CHROME_BROWSER_APP_LAUNCHED_ANIMATION_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/app_modal_dialog.cc b/chrome/browser/app_modal_dialog.cc
index e8f306d..506d76f 100644
--- a/chrome/browser/app_modal_dialog.cc
+++ b/chrome/browser/app_modal_dialog.cc
@@ -5,20 +5,20 @@
#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)
-#if defined(OS_WIN) || defined(OS_LINUX)
- : dialog_(NULL),
-#elif defined(OS_MACOSX)
- :
-#endif
+ : skip_this_dialog_(false),
tab_contents_(tab_contents),
- title_(title),
- skip_this_dialog_(false) {
+ native_dialog_(NULL),
+ title_(title) {
+}
+
+AppModalDialog::~AppModalDialog() {
}
void AppModalDialog::ShowModalDialog() {
@@ -33,14 +33,21 @@ void AppModalDialog::ShowModalDialog() {
NotificationService::NoDetails());
}
-void AppModalDialog::Cleanup() {
- NotificationService::current()->Notify(
- NotificationType::APP_MODAL_DIALOG_CLOSED,
- 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
index 92ac494..708e86e 100644
--- a/chrome/browser/app_modal_dialog.h
+++ b/chrome/browser/app_modal_dialog.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_APP_MODAL_DIALOG_H_
#define CHROME_BROWSER_APP_MODAL_DIALOG_H_
+#pragma once
#include <string>
@@ -12,23 +13,8 @@
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-// Define NativeDialog type as platform specific dialog view.
-#if defined(OS_WIN)
-class ModalDialogDelegate;
-typedef ModalDialogDelegate* NativeDialog;
-#elif defined(OS_MACOSX)
-typedef void* NativeDialog;
-#elif defined(TOOLKIT_USES_GTK)
-typedef struct _GtkDialog GtkDialog;
-typedef struct _GtkWidget GtkWidget;
-typedef int gint;
-typedef GtkWidget* NativeDialog;
-#endif
-
+class NativeAppModalDialog;
class TabContents;
-namespace IPC {
-class Message;
-}
// A controller+model base class for modal dialogs.
class AppModalDialog {
@@ -39,74 +25,57 @@ class AppModalDialog {
AppModalDialog(TabContents* tab_contents, const std::wstring& title);
virtual ~AppModalDialog();
- // Called by the app modal window queue when it is time to show this window.
+ // Called by the AppModalDialogQueue to show this dialog.
void ShowModalDialog();
- // 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_; }
-
- /////////////////////////////////////////////////////////////////////////////
- // The following methods are platform specific and should be implemented in
- // the platform specific .cc files.
- // Create the platform specific NativeDialog and display it. When the
- // NativeDialog is closed, it should call OnAccept or OnCancel to notify the
- // renderer of the user's action. The NativeDialog is also expected to
- // delete the AppModalDialog associated with it.
- virtual void CreateAndShowDialog();
-
-#if defined(TOOLKIT_USES_GTK)
- virtual void HandleDialogResponse(GtkDialog* dialog, gint response_id) = 0;
- // Callback for dialog response calls, passes results to specialized
- // HandleDialogResponse() implementation.
- static void OnDialogResponse(GtkDialog* dialog, gint response_id,
- AppModalDialog* app_modal_dialog);
-#endif
-
- // Close the dialog if it is showing.
- virtual void CloseModalDialog();
-
- // Called by the app modal window queue to activate the window.
+ // 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() {
- return title_;
- }
+ std::wstring title() const { return title_; }
- // Helper methods used to query or control the dialog. This is used by
- // automation.
- virtual int GetDialogButtons() = 0;
- virtual void AcceptWindow() = 0;
- virtual void CancelWindow() = 0;
+ NativeAppModalDialog* native_dialog() const { return native_dialog_; }
- protected:
- // Cleans up the dialog class.
- virtual void Cleanup();
- // Creates the actual platform specific dialog view class.
- virtual NativeDialog CreateNativeDialog() = 0;
+ // Methods overridable by AppModalDialog subclasses:
- // A reference to the platform native dialog box.
-#if defined(OS_LINUX) || defined(OS_WIN)
- NativeDialog dialog_;
-#endif
+ // 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();
- // Parent tab contents.
- TabContents* tab_contents_;
+ // 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_; }
- // Information about the message box is held in the following variables.
- std::wstring title_;
+ 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_;
+
private:
+ // The toolkit-specific implementation of the app modal dialog box.
+ NativeAppModalDialog* native_dialog_;
+
+ // Information about the message box is held in the following variables.
+ std::wstring title_;
+
DISALLOW_COPY_AND_ASSIGN(AppModalDialog);
};
diff --git a/chrome/browser/app_modal_dialog_gtk.cc b/chrome/browser/app_modal_dialog_gtk.cc
deleted file mode 100644
index 2eb9185..0000000
--- a/chrome/browser/app_modal_dialog_gtk.cc
+++ /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.
-
-#include "chrome/browser/app_modal_dialog.h"
-
-#include <gtk/gtk.h>
-
-#include "app/l10n_util.h"
-#include "app/message_box_flags.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.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 "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-
-AppModalDialog::~AppModalDialog() {
-}
-
-void AppModalDialog::CreateAndShowDialog() {
-}
-
-// static
-void AppModalDialog::OnDialogResponse(GtkDialog* dialog, gint response_id,
- AppModalDialog* app_modal_dialog) {
- app_modal_dialog->HandleDialogResponse(dialog, response_id);
-}
-
-void AppModalDialog::ActivateModalDialog() {
- DCHECK(dialog_);
- gtk_window_present(GTK_WINDOW(dialog_));
-}
-
-void AppModalDialog::CloseModalDialog() {
- DCHECK(dialog_);
- HandleDialogResponse(GTK_DIALOG(dialog_), GTK_RESPONSE_DELETE_EVENT);
-}
-
-void AppModalDialog::AcceptWindow() {
- DCHECK(dialog_);
- HandleDialogResponse(GTK_DIALOG(dialog_), GTK_RESPONSE_OK);
-}
-
-void AppModalDialog::CancelWindow() {
- DCHECK(dialog_);
- HandleDialogResponse(GTK_DIALOG(dialog_), GTK_RESPONSE_CANCEL);
-}
diff --git a/chrome/browser/app_modal_dialog_mac.mm b/chrome/browser/app_modal_dialog_mac.mm
deleted file mode 100644
index 8d23387..0000000
--- a/chrome/browser/app_modal_dialog_mac.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 "chrome/browser/app_modal_dialog.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/logging.h"
-
-AppModalDialog::~AppModalDialog() {
-}
-
-void AppModalDialog::CreateAndShowDialog() {
- NOTIMPLEMENTED();
-}
-
-void AppModalDialog::ActivateModalDialog() {
- NOTIMPLEMENTED();
-}
-
-void AppModalDialog::CloseModalDialog() {
- NOTIMPLEMENTED();
-}
diff --git a/chrome/browser/app_modal_dialog_queue.h b/chrome/browser/app_modal_dialog_queue.h
index b9709b3..78d9142 100644
--- a/chrome/browser/app_modal_dialog_queue.h
+++ b/chrome/browser/app_modal_dialog_queue.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_APP_MODAL_DIALOG_QUEUE_H_
#define CHROME_BROWSER_APP_MODAL_DIALOG_QUEUE_H_
+#pragma once
#include <queue>
diff --git a/chrome/browser/app_modal_dialog_win.cc b/chrome/browser/app_modal_dialog_win.cc
deleted file mode 100644
index e48d986..0000000
--- a/chrome/browser/app_modal_dialog_win.cc
+++ /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 "chrome/browser/app_modal_dialog.h"
-
-#include "base/logging.h"
-#include "chrome/browser/views/jsmessage_box_dialog.h"
-#include "views/window/dialog_delegate.h"
-#include "views/window/window.h"
-
-AppModalDialog::~AppModalDialog() {
-}
-
-void AppModalDialog::CreateAndShowDialog() {
- dialog_ = CreateNativeDialog();
- DCHECK(dialog_->IsModal());
- dialog_->ShowModalDialog();
-}
-
-void AppModalDialog::ActivateModalDialog() {
- DCHECK(dialog_);
- dialog_->ActivateModalDialog();
-}
-
-void AppModalDialog::CloseModalDialog() {
- DCHECK(dialog_);
- dialog_->CloseModalDialog();
-}
diff --git a/chrome/browser/appcache/appcache_dispatcher_host.cc b/chrome/browser/appcache/appcache_dispatcher_host.cc
index b3a7bb0..e37784f 100644
--- a/chrome/browser/appcache/appcache_dispatcher_host.cc
+++ b/chrome/browser/appcache/appcache_dispatcher_host.cc
@@ -61,6 +61,7 @@ bool AppCacheDispatcherHost::OnMessageReceived(const IPC::Message& msg,
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_MESSAGE_HANDLER(AppCacheMsg_SelectCacheForWorker,
OnSelectCacheForWorker);
@@ -102,8 +103,7 @@ void AppCacheDispatcherHost::OnSelectCache(
ReceivedBadMessage(AppCacheMsg_SelectCache::ID);
}
} else {
- frontend_proxy_.OnCacheSelected(
- host_id, appcache::kNoCacheId, appcache::UNCACHED);
+ frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
}
}
@@ -115,8 +115,7 @@ void AppCacheDispatcherHost::OnSelectCacheForWorker(
ReceivedBadMessage(AppCacheMsg_SelectCacheForWorker::ID);
}
} else {
- frontend_proxy_.OnCacheSelected(
- host_id, appcache::kNoCacheId, appcache::UNCACHED);
+ frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
}
}
@@ -126,8 +125,7 @@ void AppCacheDispatcherHost::OnSelectCacheForSharedWorker(
if (!backend_impl_.SelectCacheForSharedWorker(host_id, appcache_id))
ReceivedBadMessage(AppCacheMsg_SelectCacheForSharedWorker::ID);
} else {
- frontend_proxy_.OnCacheSelected(
- host_id, appcache::kNoCacheId, appcache::UNCACHED);
+ frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
}
}
@@ -142,6 +140,12 @@ void AppCacheDispatcherHost::OnMarkAsForeignEntry(
}
}
+void AppCacheDispatcherHost::OnGetResourceList(
+ int host_id, std::vector<appcache::AppCacheResourceInfo>* params) {
+ if (appcache_service_.get())
+ backend_impl_.GetResourceList(host_id, params);
+}
+
void AppCacheDispatcherHost::OnGetStatus(int host_id,
IPC::Message* reply_msg) {
if (pending_reply_msg_.get()) {
diff --git a/chrome/browser/appcache/appcache_dispatcher_host.h b/chrome/browser/appcache/appcache_dispatcher_host.h
index 37ff02e..c54784c 100644
--- a/chrome/browser/appcache/appcache_dispatcher_host.h
+++ b/chrome/browser/appcache/appcache_dispatcher_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_APPCACHE_APPCACHE_DISPATCHER_HOST_H_
#define CHROME_BROWSER_APPCACHE_APPCACHE_DISPATCHER_HOST_H_
+#pragma once
#include <vector>
@@ -58,7 +59,9 @@ class AppCacheDispatcherHost {
void OnGetStatus(int host_id, IPC::Message* reply_msg);
void OnStartUpdate(int host_id, IPC::Message* reply_msg);
void OnSwapCache(int host_id, IPC::Message* reply_msg);
-
+ void OnGetResourceList(
+ int host_id,
+ std::vector<appcache::AppCacheResourceInfo>* resource_infos);
void GetStatusCallback(appcache::Status status, void* param);
void StartUpdateCallback(bool result, void* param);
void SwapCacheCallback(bool result, void* param);
diff --git a/chrome/browser/appcache/appcache_frontend_proxy.cc b/chrome/browser/appcache/appcache_frontend_proxy.cc
index 78ec85d..0a80424 100644
--- a/chrome/browser/appcache/appcache_frontend_proxy.cc
+++ b/chrome/browser/appcache/appcache_frontend_proxy.cc
@@ -6,9 +6,9 @@
#include "chrome/common/render_messages.h"
-void AppCacheFrontendProxy::OnCacheSelected(int host_id, int64 cache_id ,
- appcache::Status status) {
- sender_->Send(new AppCacheMsg_CacheSelected(host_id, cache_id, status));
+void AppCacheFrontendProxy::OnCacheSelected(
+ int host_id, const appcache::AppCacheInfo& info) {
+ sender_->Send(new AppCacheMsg_CacheSelected(host_id, info));
}
void AppCacheFrontendProxy::OnStatusChanged(const std::vector<int>& host_ids,
diff --git a/chrome/browser/appcache/appcache_frontend_proxy.h b/chrome/browser/appcache/appcache_frontend_proxy.h
index becbdee..2d3775c 100644
--- a/chrome/browser/appcache/appcache_frontend_proxy.h
+++ b/chrome/browser/appcache/appcache_frontend_proxy.h
@@ -4,7 +4,9 @@
#ifndef CHROME_BROWSER_APPCACHE_APPCACHE_FRONTEND_PROXY_H_
#define CHROME_BROWSER_APPCACHE_APPCACHE_FRONTEND_PROXY_H_
+#pragma once
+#include <string>
#include <vector>
#include "ipc/ipc_message.h"
@@ -18,8 +20,7 @@ class AppCacheFrontendProxy : public appcache::AppCacheFrontend {
IPC::Message::Sender* sender() const { return sender_; }
// AppCacheFrontend methods
- virtual void OnCacheSelected(int host_id, int64 cache_id ,
- appcache::Status);
+ virtual void OnCacheSelected(int host_id, const appcache::AppCacheInfo& info);
virtual void OnStatusChanged(const std::vector<int>& host_ids,
appcache::Status status);
virtual void OnEventRaised(const std::vector<int>& host_ids,
diff --git a/chrome/browser/appcache/chrome_appcache_service.cc b/chrome/browser/appcache/chrome_appcache_service.cc
index c2e41a0..58a398e 100644
--- a/chrome/browser/appcache/chrome_appcache_service.cc
+++ b/chrome/browser/appcache/chrome_appcache_service.cc
@@ -7,8 +7,6 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h"
-#include "chrome/browser/message_box_handler.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/notification_service.h"
@@ -17,54 +15,29 @@
static bool has_initialized_thread_ids;
-// ChromeAppCacheService cannot just subclass the delegate interface
-// because we may have several prompts pending.
-class ChromeAppCacheService::PromptDelegate
- : public CookiePromptModalDialogDelegate {
- public:
- PromptDelegate(ChromeAppCacheService* service,
- const GURL& manifest_url, net::CompletionCallback* callback)
- : service_(service), manifest_url_(manifest_url), callback_(callback) {
- }
-
- virtual void AllowSiteData(bool session_expire) {
- service_->DidPrompt(net::OK, manifest_url_, callback_);
- delete this;
- }
-
- virtual void BlockSiteData() {
- service_->DidPrompt(net::ERR_ACCESS_DENIED, manifest_url_, callback_);
- delete this;
- }
-
- private:
- scoped_refptr<ChromeAppCacheService> service_;
- GURL manifest_url_;
- net::CompletionCallback* callback_;
-};
-
// ----------------------------------------------------------------------------
-ChromeAppCacheService::ChromeAppCacheService(
- const FilePath& profile_path,
- ChromeURLRequestContext* request_context) {
+ChromeAppCacheService::ChromeAppCacheService() {
+}
+
+void ChromeAppCacheService::InitializeOnIOThread(
+ const FilePath& profile_path, bool is_incognito,
+ scoped_refptr<HostContentSettingsMap> content_settings_map) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- DCHECK(request_context);
if (!has_initialized_thread_ids) {
has_initialized_thread_ids = true;
appcache::AppCacheThread::Init(ChromeThread::DB, ChromeThread::IO);
}
- host_contents_settings_map_ = request_context->host_content_settings_map();
+ host_contents_settings_map_ = content_settings_map;
registrar_.Add(
this, NotificationType::PURGE_MEMORY, NotificationService::AllSources());
// Init our base class.
- Initialize(request_context->is_off_the_record() ?
- FilePath() : profile_path.Append(chrome::kAppCacheDirname),
- ChromeThread::GetMessageLoopProxyForThread(ChromeThread::CACHE));
- set_request_context(request_context);
+ Initialize(
+ is_incognito ? FilePath() : profile_path.Append(chrome::kAppCacheDirname),
+ ChromeThread::GetMessageLoopProxyForThread(ChromeThread::CACHE));
set_appcache_policy(this);
}
@@ -72,6 +45,19 @@ ChromeAppCacheService::~ChromeAppCacheService() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
}
+void ChromeAppCacheService::SetOriginQuotaInMemory(
+ const GURL& origin, int64 quota) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ if (storage())
+ storage()->SetOriginQuotaInMemory(origin, quota);
+}
+
+void ChromeAppCacheService::ResetOriginQuotaInMemory(const GURL& origin) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ if (storage())
+ storage()->ResetOriginQuotaInMemory(origin);
+}
+
// static
void ChromeAppCacheService::ClearLocalState(const FilePath& profile_path) {
file_util::Delete(profile_path.Append(chrome::kAppCacheDirname), true);
@@ -80,7 +66,7 @@ void ChromeAppCacheService::ClearLocalState(const FilePath& profile_path) {
bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
ContentSetting setting = host_contents_settings_map_->GetContentSetting(
- manifest_url, CONTENT_SETTINGS_TYPE_COOKIES);
+ manifest_url, CONTENT_SETTINGS_TYPE_COOKIES, "");
DCHECK(setting != CONTENT_SETTING_DEFAULT);
// We don't prompt for read access.
return setting != CONTENT_SETTING_BLOCK;
@@ -90,60 +76,12 @@ int ChromeAppCacheService::CanCreateAppCache(
const GURL& manifest_url, net::CompletionCallback* callback) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
ContentSetting setting = host_contents_settings_map_->GetContentSetting(
- manifest_url, CONTENT_SETTINGS_TYPE_COOKIES);
+ manifest_url, CONTENT_SETTINGS_TYPE_COOKIES, "");
DCHECK(setting != CONTENT_SETTING_DEFAULT);
- if (setting == CONTENT_SETTING_ASK) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &ChromeAppCacheService::DoPrompt,
- manifest_url, callback));
- return net::ERR_IO_PENDING;
- }
return (setting != CONTENT_SETTING_BLOCK) ? net::OK :
net::ERR_ACCESS_DENIED;
}
-void ChromeAppCacheService::DoPrompt(
- const GURL& manifest_url, net::CompletionCallback* callback) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-
- // The setting may have changed (due to the "remember" option)
- ContentSetting setting = host_contents_settings_map_->GetContentSetting(
- manifest_url, CONTENT_SETTINGS_TYPE_COOKIES);
- if (setting != CONTENT_SETTING_ASK) {
- int rv = (setting != CONTENT_SETTING_BLOCK) ? net::OK :
- net::ERR_ACCESS_DENIED;
- DidPrompt(rv, manifest_url, callback);
- return;
- }
-
- // Show the prompt on top of the current tab.
- Browser* browser = BrowserList::GetLastActive();
- if (!browser || !browser->GetSelectedTabContents()) {
- DidPrompt(net::ERR_ACCESS_DENIED, manifest_url, callback);
- return;
- }
-
- RunAppCachePrompt(browser->GetSelectedTabContents(),
- host_contents_settings_map_, manifest_url,
- new PromptDelegate(this, manifest_url, callback));
-}
-
-void ChromeAppCacheService::DidPrompt(
- int rv, const GURL& manifest_url, net::CompletionCallback* callback) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(this, &ChromeAppCacheService::CallCallback,
- rv, callback));
-}
-
-void ChromeAppCacheService::CallCallback(
- int rv, net::CompletionCallback* callback) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- callback->Run(rv);
-}
-
void ChromeAppCacheService::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/appcache/chrome_appcache_service.h b/chrome/browser/appcache/chrome_appcache_service.h
index 888b672..9c33c04 100644
--- a/chrome/browser/appcache/chrome_appcache_service.h
+++ b/chrome/browser/appcache/chrome_appcache_service.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_APPCACHE_CHROME_APPCACHE_SERVICE_H_
#define CHROME_BROWSER_APPCACHE_CHROME_APPCACHE_SERVICE_H_
+#pragma once
#include "base/ref_counted.h"
#include "chrome/browser/chrome_thread.h"
@@ -21,7 +22,7 @@ class FilePath;
// object, and those URLRequestContexts are refcounted independently of the
// owning profile.
//
-// All methods, including the ctor and dtor, are expected to be called on
+// All methods, except the ctor, are expected to be called on
// the IO thread (unless specifically called out in doc comments).
class ChromeAppCacheService
: public base::RefCountedThreadSafe<ChromeAppCacheService,
@@ -30,8 +31,16 @@ class ChromeAppCacheService
public appcache::AppCachePolicy,
public NotificationObserver {
public:
- ChromeAppCacheService(const FilePath& profile_path,
- ChromeURLRequestContext* request_context);
+ ChromeAppCacheService();
+
+ void InitializeOnIOThread(
+ const FilePath& profile_path, bool is_incognito,
+ scoped_refptr<HostContentSettingsMap> content_settings_map);
+
+ // Helpers used by the extension service to grant and revoke
+ // unlimited storage to app extensions.
+ void SetOriginQuotaInMemory(const GURL& origin, int64 quota);
+ void ResetOriginQuotaInMemory(const GURL& origin);
static void ClearLocalState(const FilePath& profile_path);
@@ -39,8 +48,6 @@ class ChromeAppCacheService
friend class ChromeThread;
friend class DeleteTask<ChromeAppCacheService>;
- class PromptDelegate;
-
virtual ~ChromeAppCacheService();
// AppCachePolicy overrides
@@ -48,13 +55,6 @@ class ChromeAppCacheService
virtual int CanCreateAppCache(const GURL& manifest_url,
net::CompletionCallback* callback);
- // The DoPrompt and DidPrrompt methods are called on the UI thread, and
- // the following CallCallback method is called on the IO thread.
- void DoPrompt(const GURL& manifest_url, net::CompletionCallback* callback);
- void DidPrompt(int rv, const GURL& manifest_url,
- net::CompletionCallback* callback);
- void CallCallback(int rv, net::CompletionCallback* callback);
-
// NotificationObserver override
virtual void Observe(NotificationType type,
const NotificationSource& source,
diff --git a/chrome/browser/appcache/view_appcache_internals_job_factory.h b/chrome/browser/appcache/view_appcache_internals_job_factory.h
index 50ee303..66ae0e2 100644
--- a/chrome/browser/appcache/view_appcache_internals_job_factory.h
+++ b/chrome/browser/appcache/view_appcache_internals_job_factory.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_APPCACHE_VIEW_APPCACHE_INTERNALS_JOB_FACTORY_H_
#define CHROME_BROWSER_APPCACHE_VIEW_APPCACHE_INTERNALS_JOB_FACTORY_H_
+#pragma once
class GURL;
class URLRequest;
diff --git a/chrome/browser/autocomplete/autocomplete.cc b/chrome/browser/autocomplete/autocomplete.cc
index d24e209..e69d413 100644
--- a/chrome/browser/autocomplete/autocomplete.cc
+++ b/chrome/browser/autocomplete/autocomplete.cc
@@ -8,8 +8,12 @@
#include "app/l10n_util.h"
#include "base/basictypes.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/browser/autocomplete/history_quick_provider.h"
#include "chrome/browser/autocomplete/history_url_provider.h"
#include "chrome/browser/autocomplete/history_contents_provider.h"
#include "chrome/browser/autocomplete/keyword_provider.h"
@@ -18,8 +22,9 @@
#include "chrome/browser/dom_ui/history_ui.h"
#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.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"
@@ -122,7 +127,9 @@ AutocompleteInput::Type AutocompleteInput::Parse(
*scheme = parsed_scheme;
if (parsed_scheme == L"file") {
- // A user might or might not type a scheme when entering a file URL.
+ // A user might or might not type a scheme when entering a file URL. In
+ // either case, |parsed_scheme| will tell us that this is a file URL, but
+ // |parts->scheme| might be empty, e.g. if the user typed "C:\foo".
return URL;
}
@@ -151,7 +158,8 @@ AutocompleteInput::Type AutocompleteInput::Parse(
// 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.
- switch (ExternalProtocolHandler::GetBlockState(parsed_scheme)) {
+ // TODO(viettrungluu): get rid of conversion.
+ switch (ExternalProtocolHandler::GetBlockState(WideToUTF8(parsed_scheme))) {
case ExternalProtocolHandler::DONT_BLOCK:
return URL;
@@ -232,26 +240,24 @@ AutocompleteInput::Type AutocompleteInput::Parse(
UNKNOWN : QUERY;
}
- // Presence of a port means this is likely a URL, if the port is really a port
- // number. If it's just garbage after a colon, this is a query.
+ // A port number is a good indicator that this is a URL. However, it might
+ // also be a query like "1.66:1" that looks kind of like an IP address and
+ // port number. So here we only check for "port numbers" that are illegal and
+ // thus mean this can't be navigated to (e.g. "1.2.3.4:garbage"), and we save
+ // handling legal port numbers until after the "IP address" determination
+ // below.
if (parts->port.is_nonempty()) {
int port;
- return (StringToInt(WideToUTF16(
- text.substr(parts->port.begin, parts->port.len)), &port) &&
- (port >= 0) && (port <= 65535)) ? URL : QUERY;
+ if (!base::StringToInt(WideToUTF8(
+ text.substr(parts->port.begin, parts->port.len)), &port) ||
+ (port < 0) || (port > 65535))
+ return QUERY;
}
- // Presence of a username could either indicate a URL or an email address
- // ("user@mail.com"). E-mail addresses are likely queries so we only open
- // this as a URL if the user explicitly typed a scheme.
- if (parts->username.is_nonempty() && parts->scheme.is_nonempty())
- return URL;
-
- // Presence of a password means this is likely a URL. Note that unless the
- // user has typed an explicit "http://" or similar, we'll probably think that
- // the username is some unknown scheme, and bail out in the scheme-handling
- // code above.
- if (parts->password.is_nonempty())
+ // Now that we've ruled out all schemes other than http or https and done a
+ // little more sanity checking, the presence of a scheme means this is likely
+ // a URL.
+ if (parts->scheme.is_nonempty())
return URL;
// See if the host is an IP address.
@@ -262,36 +268,48 @@ AutocompleteInput::Type AutocompleteInput::Parse(
// it, unless they explicitly typed a scheme. This is true even if the URL
// appears to have a path: "1.2/45" is more likely a search (for the answer
// to a math problem) than a URL.
- if ((host_info.num_ipv4_components == 4) || parts->scheme.is_nonempty())
+ if (host_info.num_ipv4_components == 4)
return URL;
return desired_tld.empty() ? UNKNOWN : REQUESTED_URL;
}
if (host_info.family == url_canon::CanonHostInfo::IPV6)
return URL;
+ // Now that we've ruled out invalid ports and queries that look like they have
+ // a port, the presence of a port means this is likely a URL.
+ if (parts->port.is_nonempty())
+ return URL;
+
+ // Presence of a password means this is likely a URL. Note that unless the
+ // user has typed an explicit "http://" or similar, we'll probably think that
+ // the username is some unknown scheme, and bail out in the scheme-handling
+ // code above.
+ if (parts->password.is_nonempty())
+ return URL;
+
// The host doesn't look like a number, so see if the user's given us a path.
if (parts->path.is_nonempty()) {
// Most inputs with paths are URLs, even ones without known registries (e.g.
- // intranet URLs). However, if the user didn't type a scheme, there's no
- // known registry, and the path has a space, this is more likely a query
- // with a slash in the first term (e.g. "ps/2 games") than a URL. We can
- // still open URLs with spaces in the path by escaping the space, and we
- // will still inline autocomplete them if users have typed them in the past,
- // but we default to searching since that's the common case.
- return (!parts->scheme.is_nonempty() && (registry_length == 0) &&
+ // intranet URLs). However, if there's no known registry and the path has
+ // a space, this is more likely a query with a slash in the first term
+ // (e.g. "ps/2 games") than a URL. We can still open URLs with spaces in
+ // the path by escaping the space, and we will still inline autocomplete
+ // them if users have typed them in the past, but we default to searching
+ // since that's the common case.
+ return ((registry_length == 0) &&
(text.substr(parts->path.begin, parts->path.len).find(' ') !=
std::wstring::npos)) ? UNKNOWN : URL;
}
- // If we reach here with a username, our input looks like "user@host"; this is
- // the case mentioned above, where we think this is more likely an email
- // address than an HTTP auth attempt, so search for it.
+ // If we reach here with a username, our input looks like "user@host".
+ // Because there is no scheme explicitly specified, we think this is more
+ // likely an email address than an HTTP auth attempt. Hence, we search by
+ // default and let users correct us on a case-by-case basis.
if (parts->username.is_nonempty())
return UNKNOWN;
- // We have a bare host string. See if it has a known TLD or the user typed a
- // scheme. If so, it's probably a URL.
- if (parts->scheme.is_nonempty() || (registry_length != 0))
+ // We have a bare host string. If it has a known TLD, it's probably a URL.
+ if (registry_length != 0)
return URL;
// No TLD that we know about. This could be:
@@ -630,14 +648,13 @@ void AutocompleteProvider::UpdateStarredStateOfMatches() {
std::wstring AutocompleteProvider::StringForURLDisplay(const GURL& url,
bool check_accept_lang,
bool trim_http) const {
- std::wstring languages = (check_accept_lang && profile_) ?
- UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)) :
- std::wstring();
- return net::FormatUrl(
+ std::string languages = (check_accept_lang && profile_) ?
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages) : std::string();
+ return UTF16ToWideHack(net::FormatUrl(
url,
languages,
net::kFormatUrlOmitAll & ~(trim_http ? 0 : net::kFormatUrlOmitHTTP),
- UnescapeRule::SPACES, NULL, NULL, NULL);
+ UnescapeRule::SPACES, NULL, NULL, NULL));
}
// AutocompleteResult ---------------------------------------------------------
@@ -701,7 +718,7 @@ void AutocompleteResult::SortAndCull(const AutocompleteInput& input) {
&AutocompleteMatch::DestinationsEqual),
matches_.end());
- // Find the top max_matches.
+ // Find the top |kMaxMatches| matches.
if (matches_.size() > kMaxMatches) {
std::partial_sort(matches_.begin(), matches_.begin() + kMaxMatches,
matches_.end(), &AutocompleteMatch::MoreRelevant);
@@ -728,6 +745,7 @@ void AutocompleteResult::SortAndCull(const AutocompleteInput& input) {
(input.type() == AutocompleteInput::REQUESTED_URL)) &&
(default_match_ != end()) &&
(default_match_->transition != PageTransition::TYPED) &&
+ (default_match_->transition != PageTransition::KEYWORD) &&
(input.canonicalized_url() != default_match_->destination_url))
alternate_nav_url_ = input.canonicalized_url();
}
@@ -755,7 +773,11 @@ AutocompleteController::AutocompleteController(Profile* profile)
have_committed_during_this_query_(false),
done_(true) {
providers_.push_back(new SearchProvider(this, profile));
- providers_.push_back(new HistoryURLProvider(this, profile));
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableInMemoryURLIndex))
+ providers_.push_back(new HistoryQuickProvider(this, profile));
+ else
+ providers_.push_back(new HistoryURLProvider(this, profile));
providers_.push_back(new KeywordProvider(this, profile));
history_contents_provider_ = new HistoryContentsProvider(this, profile);
providers_.push_back(history_contents_provider_);
@@ -812,9 +834,12 @@ void AutocompleteController::Start(const std::wstring& text,
// If we're interrupting an old query, and committing its result won't shrink
// the visible set (which would probably re-expand soon, thus looking very
// flickery), then go ahead and commit what we've got, in order to feel more
- // responsive when the user is typing rapidly.
+ // responsive when the user is typing rapidly. In this case it's important
+ // that we don't update the edit, as the user has already changed its contents
+ // and anything we might do with it (e.g. inline autocomplete) likely no
+ // longer applies.
if (!minimal_changes && !done_ && (latest_result_.size() >= result_.size()))
- CommitResult();
+ CommitResult(false);
// If the timer is already running, it could fire shortly after starting this
// query, when we're likely to only have the synchronous results back, thus
@@ -865,17 +890,20 @@ void AutocompleteController::DeleteMatch(const AutocompleteMatch& match) {
DCHECK(match.deletable);
match.provider->DeleteMatch(match); // This may synchronously call back to
// OnProviderUpdate().
- CommitResult(); // Ensure any new result gets committed immediately. If it
- // was committed already or hasn't been modified, this is
- // harmless.
+ CommitResult(true); // Ensure any new result gets committed immediately. If
+ // it was committed already or hasn't been modified, this
+ // is harmless.
+}
+
+void AutocompleteController::CommitIfQueryHasNeverBeenCommitted() {
+ if (!have_committed_during_this_query_)
+ CommitResult(true);
}
void AutocompleteController::OnProviderUpdate(bool updated_matches) {
CheckIfDone();
- if (updated_matches || done_) {
+ if (updated_matches || done_)
UpdateLatestResult(false);
- return;
- }
}
void AutocompleteController::UpdateLatestResult(bool is_synchronous_pass) {
@@ -916,15 +944,15 @@ void AutocompleteController::UpdateLatestResult(bool is_synchronous_pass) {
// last commit, to minimize flicker.
if (result_.empty() || (done_ && !have_committed_during_this_query_) ||
delay_interval_has_passed_)
- CommitResult();
+ CommitResult(true);
}
void AutocompleteController::DelayTimerFired() {
delay_interval_has_passed_ = true;
- CommitResult();
+ CommitResult(true);
}
-void AutocompleteController::CommitResult() {
+void AutocompleteController::CommitResult(bool notify_default_match) {
if (done_) {
update_delay_timer_.Stop();
delay_interval_has_passed_ = false;
@@ -942,13 +970,15 @@ void AutocompleteController::CommitResult() {
NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED,
Source<AutocompleteController>(this),
Details<const AutocompleteResult>(&result_));
- // This notification must be sent after the other so the popup has time to
- // update its state before the edit calls into it.
- // TODO(pkasting): Eliminate this ordering requirement.
- NotificationService::current()->Notify(
- NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED,
- Source<AutocompleteController>(this),
- Details<const AutocompleteResult>(&result_));
+ if (notify_default_match) {
+ // This notification must be sent after the other so the popup has time to
+ // update its state before the edit calls into it.
+ // TODO(pkasting): Eliminate this ordering requirement.
+ NotificationService::current()->Notify(
+ NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED,
+ Source<AutocompleteController>(this),
+ Details<const AutocompleteResult>(&result_));
+ }
if (!done_)
update_delay_timer_.Reset();
}
diff --git a/chrome/browser/autocomplete/autocomplete.h b/chrome/browser/autocomplete/autocomplete.h
index 9ddec43..440f9ec 100644
--- a/chrome/browser/autocomplete/autocomplete.h
+++ b/chrome/browser/autocomplete/autocomplete.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_H_
+#pragma once
#include <string>
#include <vector>
@@ -147,7 +148,6 @@ class AutocompleteProvider;
class AutocompleteResult;
class AutocompleteController;
class HistoryContentsProvider;
-class KeywordProvider;
class Profile;
class TemplateURL;
@@ -768,6 +768,10 @@ class AutocompleteController : public ACProviderListener {
// no query is running.
void DeleteMatch(const AutocompleteMatch& match);
+ // Commits the results for the current query if they've never been committed.
+ // This is used by the popup to ensure it's not showing an out-of-date query.
+ void CommitIfQueryHasNeverBeenCommitted();
+
// Getters
const AutocompleteInput& input() const { return input_; }
const AutocompleteResult& result() const { return result_; }
@@ -790,7 +794,12 @@ class AutocompleteController : public ACProviderListener {
void DelayTimerFired();
// Copies |latest_result_| to |result_| and notifies observers of updates.
- void CommitResult();
+ // |notify_default_match| should normally be true; if it's false, we don't
+ // send an AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED notification. This
+ // is a hack to avoid updating the edit with out-of-date data.
+ // TODO(pkasting): Don't hardcode assumptions about who listens to these
+ // notificiations.
+ void CommitResult(bool notify_default_match);
// Returns the matches from |provider| whose destination urls are not in
// |latest_result_|.
diff --git a/chrome/browser/autocomplete/autocomplete_accessibility.h b/chrome/browser/autocomplete/autocomplete_accessibility.h
index 48b938d..27bd356 100644
--- a/chrome/browser/autocomplete/autocomplete_accessibility.h
+++ b/chrome/browser/autocomplete/autocomplete_accessibility.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_ACCESSIBILITY_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_ACCESSIBILITY_H_
+#pragma once
#include <atlbase.h>
#include <atlcom.h>
diff --git a/chrome/browser/autocomplete/autocomplete_browsertest.cc b/chrome/browser/autocomplete/autocomplete_browsertest.cc
index 11a8bc9..5ef296b 100644
--- a/chrome/browser/autocomplete/autocomplete_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_browsertest.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 "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
@@ -12,6 +14,7 @@
#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/common/notification_type.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
@@ -26,6 +29,15 @@
#define MAYBE_Basic Basic
#endif
+// Autocomplete test is flaky on ChromeOS.
+// http://crbug.com/52928
+#if defined(OS_CHROMEOS)
+#define MAYBE_Autocomplete FLAKY_Autocomplete
+#else
+#define MAYBE_Autocomplete Autocomplete
+#endif
+
+
namespace {
std::wstring AutocompleteResultAsString(const AutocompleteResult& result) {
@@ -99,7 +111,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Basic) {
EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
}
-IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, Autocomplete) {
+IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Autocomplete) {
// The results depend on the history backend being loaded. Make sure it is
// loaded so that the autocomplete results are consistent.
WaitForHistoryBackendToLoad();
@@ -142,9 +154,11 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, TabAwayRevertSelect) {
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
location_bar->location_entry()->GetText());
location_bar->location_entry()->SetUserText(L"");
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(
GURL(chrome::kAboutBlankURL), GURL(), PageTransition::START_PAGE,
- -1, TabStripModel::ADD_SELECTED, NULL, std::string());
+ -1, TabStripModel::ADD_SELECTED, NULL, std::string(), &browser_used);
+ EXPECT_EQ(browser(), browser_used);
ui_test_utils::WaitForNavigation(
&browser()->GetSelectedTabContents()->controller());
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
@@ -154,3 +168,94 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, TabAwayRevertSelect) {
location_bar->location_entry()->GetText());
EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
}
+
+IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
+ LocationBar* location_bar = GetLocationBar();
+
+ // Focus search when omnibox is blank
+ {
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
+ location_bar->location_entry()->GetText());
+
+ location_bar->FocusSearch();
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
+
+ size_t selection_start, selection_end;
+ location_bar->location_entry()->GetSelectionBounds(&selection_start,
+ &selection_end);
+ EXPECT_EQ(1U, selection_start);
+ EXPECT_EQ(1U, selection_end);
+ }
+
+ // 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_EQ(L"foo", location_bar->location_entry()->GetText());
+
+ location_bar->FocusSearch();
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
+
+ size_t selection_start, selection_end;
+ location_bar->location_entry()->GetSelectionBounds(&selection_start,
+ &selection_end);
+ EXPECT_EQ(1U, selection_start);
+ EXPECT_EQ(1U, selection_end);
+ }
+
+ // Focus search when omnibox _is_ already in forced query mode, but no query
+ // has been typed.
+ {
+ location_bar->location_entry()->SetUserText(L"?");
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
+
+ location_bar->FocusSearch();
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
+
+ size_t selection_start, selection_end;
+ location_bar->location_entry()->GetSelectionBounds(&selection_start,
+ &selection_end);
+ EXPECT_EQ(1U, selection_start);
+ EXPECT_EQ(1U, selection_end);
+ }
+
+ // Focus search when omnibox _is_ already in forced query mode, and some query
+ // has been typed.
+ {
+ location_bar->location_entry()->SetUserText(L"?foo");
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(L"?foo", location_bar->location_entry()->GetText());
+
+ location_bar->FocusSearch();
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(L"?foo", location_bar->location_entry()->GetText());
+
+ size_t selection_start, selection_end;
+ location_bar->location_entry()->GetSelectionBounds(&selection_start,
+ &selection_end);
+ EXPECT_EQ(1U, std::min(selection_start, selection_end));
+ EXPECT_EQ(4U, std::max(selection_start, selection_end));
+ }
+
+ // 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_EQ(L" ?foo", location_bar->location_entry()->GetText());
+
+ location_bar->FocusSearch();
+ EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_EQ(L" ?foo", location_bar->location_entry()->GetText());
+
+ size_t selection_start, selection_end;
+ location_bar->location_entry()->GetSelectionBounds(&selection_start,
+ &selection_end);
+ EXPECT_EQ(4U, std::min(selection_start, selection_end));
+ EXPECT_EQ(7U, std::max(selection_start, selection_end));
+ }
+}
diff --git a/chrome/browser/autocomplete/autocomplete_classifier.h b/chrome/browser/autocomplete/autocomplete_classifier.h
index 3588c27..facdd34 100644
--- a/chrome/browser/autocomplete/autocomplete_classifier.h
+++ b/chrome/browser/autocomplete/autocomplete_classifier.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_CLASSIFIER_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_CLASSIFIER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc
index 03c8bff..49b687b 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit.cc
@@ -15,8 +15,10 @@
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/autocomplete/keyword_provider.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/extensions/extension_omnibox_api.h"
+#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/url_fixer_upper.h"
@@ -127,6 +129,12 @@ void AutocompleteEditModel::RestoreState(const State& state) {
}
}
+AutocompleteMatch AutocompleteEditModel::CurrentMatch() {
+ AutocompleteMatch match;
+ GetInfoForCurrentText(&match, NULL);
+ return match;
+}
+
bool AutocompleteEditModel::UpdatePermanentText(
const std::wstring& new_permanent_text) {
// When there's a new URL, and the user is not editing anything or the edit
@@ -154,14 +162,28 @@ void AutocompleteEditModel::GetDataForURLExport(GURL* url,
AutocompleteMatch match;
GetInfoForCurrentText(&match, NULL);
*url = match.destination_url;
- if (UTF8ToWide(url->possibly_invalid_spec()) == permanent_text_) {
+ if (*url == URLFixerUpper::FixupURL(WideToUTF8(permanent_text_),
+ std::string())) {
*title = controller_->GetTitle();
*favicon = controller_->GetFavIcon();
}
}
std::wstring AutocompleteEditModel::GetDesiredTLD() const {
- return (control_key_state_ == DOWN_WITHOUT_CHANGE) ?
+ // Tricky corner case: The user has typed "foo" and currently sees an inline
+ // autocomplete suggestion of "foo.net". He now presses ctrl-a (e.g. to
+ // select all, on Windows). If we treat the ctrl press as potentially for the
+ // sake of ctrl-enter, then we risk "www.foo.com" being promoted as the best
+ // match. This would make the autocompleted text disappear, leaving our user
+ // feeling very confused when the wrong text gets highlighted.
+ //
+ // Thus, we only treat the user as pressing ctrl-enter when the user presses
+ // ctrl without any fragile state built up in the omnibox:
+ // * the contents of the omnibox have not changed since the keypress,
+ // * there is no autocompleted text visible, and
+ // * the user is not typing a keyword query.
+ return (control_key_state_ == DOWN_WITHOUT_CHANGE &&
+ inline_autocomplete_text_.empty() && !KeywordIsSelected())?
std::wstring(L"com") : std::wstring();
}
@@ -259,9 +281,11 @@ void AutocompleteEditModel::Revert() {
}
void AutocompleteEditModel::StartAutocomplete(
+ bool has_selected_text,
bool prevent_inline_autocomplete) const {
popup_->StartAutocomplete(user_text_, GetDesiredTLD(),
prevent_inline_autocomplete || just_deleted_text_ ||
+ (has_selected_text && inline_autocomplete_text_.empty()) ||
(paste_state_ != NONE), keyword_ui_state_ == KEYWORD);
}
@@ -297,7 +321,8 @@ void AutocompleteEditModel::AcceptInput(WindowOpenDisposition disposition,
if (!match.destination_url.is_valid())
return;
- if (UTF8ToWide(match.destination_url.spec()) == permanent_text_) {
+ if (match.destination_url ==
+ URLFixerUpper::FixupURL(WideToUTF8(permanent_text_), std::string())) {
// When the user hit enter on the existing permanent URL, treat it like a
// reload for scoring purposes. We could detect this by just checking
// user_input_in_progress_, but it seems better to treat "edits" that end
@@ -312,6 +337,15 @@ void AutocompleteEditModel::AcceptInput(WindowOpenDisposition disposition,
match.transition = PageTransition::LINK;
}
+ if (match.type == AutocompleteMatch::SEARCH_WHAT_YOU_TYPED ||
+ match.type == AutocompleteMatch::SEARCH_HISTORY ||
+ match.type == AutocompleteMatch::SEARCH_SUGGEST) {
+ const TemplateURL* default_provider =
+ profile_->GetTemplateURLModel()->GetDefaultSearchProvider();
+ if (default_provider && default_provider->url() &&
+ default_provider->url()->HasGoogleBaseURLs())
+ GoogleURLTracker::GoogleURLSearchCommitted();
+ }
view_->OpenURL(match.destination_url, disposition, match.transition,
alternate_nav_url, AutocompletePopupModel::kNoMatch,
is_keyword_hint_ ? std::wstring() : keyword_);
@@ -369,6 +403,9 @@ void AutocompleteEditModel::OpenURL(const GURL& url,
// search engine, if applicable; see comments in template_url.h.
}
+#if defined(TOOLKIT_VIEWS)
+ controller_->OnAutocompleteWillAccept();
+#endif
if (disposition != NEW_BACKGROUND_TAB)
view_->RevertAll(); // Revert the box to its unedited state
controller_->OnAutocompleteAccept(url, disposition, transition,
@@ -411,6 +448,10 @@ const AutocompleteResult& AutocompleteEditModel::result() const {
void AutocompleteEditModel::OnSetFocus(bool control_down) {
has_focus_ = true;
control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP;
+ NotificationService::current()->Notify(
+ NotificationType::AUTOCOMPLETE_EDIT_FOCUSED,
+ Source<AutocompleteEditModel>(this),
+ NotificationService::NoDetails());
}
void AutocompleteEditModel::OnKillFocus() {
@@ -465,6 +506,8 @@ void AutocompleteEditModel::OnControlKeyChanged(bool pressed) {
// the input text.
InternalSetUserText(UserTextFromDisplayText(view_->GetText()));
has_temporary_text_ = false;
+ if (KeywordIsSelected())
+ AcceptKeyword();
}
if ((old_state != DOWN_WITH_CHANGE) && popup_->IsOpen()) {
// Autocomplete history provider results may change, so refresh the
@@ -581,6 +624,10 @@ bool AutocompleteEditModel::OnAfterPossibleChange(const std::wstring& new_text,
else if (text_differs)
paste_state_ = NONE;
+ // Modifying the selection counts as accepting the autocompleted text.
+ const bool user_text_changed =
+ text_differs || (selection_differs && !inline_autocomplete_text_.empty());
+
// If something has changed while the control key is down, prevent
// "ctrl-enter" until the control key is released. When we do this, we need
// to update the popup if it's open, since the desired_tld will have changed.
@@ -589,20 +636,23 @@ bool AutocompleteEditModel::OnAfterPossibleChange(const std::wstring& new_text,
control_key_state_ = DOWN_WITH_CHANGE;
if (!text_differs && !popup_->IsOpen())
return false; // Don't open the popup for no reason.
- } else if (!text_differs &&
- (inline_autocomplete_text_.empty() || !selection_differs)) {
+ } else if (!user_text_changed) {
return false;
}
- const bool had_keyword = (keyword_ui_state_ != NO_KEYWORD) &&
- !is_keyword_hint_ && !keyword_.empty();
+ const bool had_keyword = KeywordIsSelected();
- // Modifying the selection counts as accepting the autocompleted text.
- InternalSetUserText(UserTextFromDisplayText(new_text));
- has_temporary_text_ = false;
+ // If the user text has not changed, we do not want to change the model's
+ // state associated with the text. Otherwise, we can get surprising behavior
+ // where the autocompleted text unexpectedly reappears, e.g. crbug.com/55983
+ if (user_text_changed) {
+ InternalSetUserText(UserTextFromDisplayText(new_text));
+ has_temporary_text_ = false;
- // Track when the user has deleted text so we won't allow inline autocomplete.
- just_deleted_text_ = just_deleted_text;
+ // Track when the user has deleted text so we won't allow inline
+ // autocomplete.
+ just_deleted_text_ = just_deleted_text;
+ }
// Disable the fancy keyword UI if the user didn't already have a visible
// keyword and is not at the end of the edit. This prevents us from showing
@@ -626,6 +676,12 @@ bool AutocompleteEditModel::OnAfterPossibleChange(const std::wstring& new_text,
return true;
}
+void AutocompleteEditModel::PopupBoundsChangedTo(const gfx::Rect& bounds) {
+#if defined(TOOLKIT_VIEWS)
+ controller_->OnPopupBoundsChanged(bounds);
+#endif
+}
+
// Return true if the suggestion type warrants a TCP/IP preconnection.
// i.e., it is now highly likely that the user will select the related domain.
static bool IsPreconnectable(AutocompleteMatch::Type type) {
@@ -666,8 +722,8 @@ void AutocompleteEditModel::Observe(NotificationType type,
if (!match->destination_url.SchemeIs(chrome::kExtensionScheme)) {
// Warm up DNS Prefetch cache, or preconnect to a search service.
- chrome_browser_net::AnticipateUrl(match->destination_url,
- IsPreconnectable(match->type));
+ chrome_browser_net::AnticipateOmniboxUrl(match->destination_url,
+ IsPreconnectable(match->type));
}
// We could prefetch the alternate nav URL, if any, but because there
@@ -686,18 +742,20 @@ void AutocompleteEditModel::InternalSetUserText(const std::wstring& text) {
inline_autocomplete_text_.clear();
}
+bool AutocompleteEditModel::KeywordIsSelected() const {
+ return ((keyword_ui_state_ != NO_KEYWORD) && !is_keyword_hint_ &&
+ !keyword_.empty());
+}
+
std::wstring AutocompleteEditModel::DisplayTextFromUserText(
const std::wstring& text) const {
- return ((keyword_ui_state_ == NO_KEYWORD) || is_keyword_hint_ ||
- keyword_.empty()) ?
- text : KeywordProvider::SplitReplacementStringFromInput(text);
+ return KeywordIsSelected() ?
+ KeywordProvider::SplitReplacementStringFromInput(text) : text;
}
std::wstring AutocompleteEditModel::UserTextFromDisplayText(
const std::wstring& text) const {
- return ((keyword_ui_state_ == NO_KEYWORD) || is_keyword_hint_ ||
- keyword_.empty()) ?
- text : (keyword_ + L" " + text);
+ return KeywordIsSelected() ? (keyword_ + L" " + text) : text;
}
void AutocompleteEditModel::GetInfoForCurrentText(
diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h
index 1b9d03a..33420dd 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.h
+++ b/chrome/browser/autocomplete/autocomplete_edit.h
@@ -4,10 +4,13 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_H_
+#pragma once
#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/page_transition_types.h"
+#include "gfx/native_widget_types.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/window_open_disposition.h"
@@ -19,6 +22,10 @@ class AutocompleteEditController;
class AutocompleteEditModel;
class AutocompleteEditView;
+namespace gfx {
+class Rect;
+}
+
// TODO(pkasting): The names and contents of the classes in
// this file are temporary. I am in hack-and-slash mode right now.
// http://code.google.com/p/chromium/issues/detail?id=6772
@@ -26,6 +33,28 @@ class AutocompleteEditView;
// Embedders of an AutocompleteEdit widget must implement this class.
class AutocompleteEditController {
public:
+#if defined(TOOLKIT_VIEWS)
+ // Sent when the autocomplete popup is about to close.
+ virtual void OnAutocompleteWillClosePopup() = 0;
+
+ // Sent when the edit is losing focus. |view_gaining_focus| is the view
+ // gaining focus and may be null.
+ virtual void OnAutocompleteLosingFocus(
+ gfx::NativeView view_gaining_focus) = 0;
+
+ // Sent prior to OnAutoCompleteAccept and before the model has been reverted.
+ virtual void OnAutocompleteWillAccept() = 0;
+
+ // Commits the suggested text. |typed_text| is the current text showing in the
+ // autocomplete. Returns true if the text was committed.
+ virtual bool OnCommitSuggestedText(const std::wstring& typed_text) = 0;
+
+ // Invoked when the popup is going to change its bounds to |bounds|.
+ virtual void OnPopupBoundsChanged(const gfx::Rect& bounds) = 0;
+#else
+ // TODO: port.
+#endif
+
// When the user presses enter or selects a line with the mouse, this
// function will get called synchronously with the url to open and
// disposition and transition to use when opening it.
@@ -101,10 +130,8 @@ class AutocompleteEditModel : public NotificationObserver {
void SetPopupModel(AutocompletePopupModel* popup_model);
-#ifdef UNIT_TEST
// It should only be used by testing code.
AutocompletePopupModel* popup_model() const { return popup_; }
-#endif
// Invoked when the profile has changed.
void SetProfile(Profile* profile);
@@ -118,6 +145,10 @@ class AutocompleteEditModel : public NotificationObserver {
// Restores local state from the saved |state|.
void RestoreState(const State& state);
+ // Returns the match for the current text. If the user has not edited the text
+ // this is the match corresponding to the permanent text.
+ AutocompleteMatch CurrentMatch();
+
// Called when the user wants to export the entire current text as a URL.
// Sets the url, and if known, the title and favicon.
void GetDataForURLExport(GURL* url, std::wstring* title, SkBitmap* favicon);
@@ -174,7 +205,8 @@ class AutocompleteEditModel : public NotificationObserver {
void Revert();
// Directs the popup to start autocomplete.
- void StartAutocomplete(bool prevent_inline_autocomplete) const;
+ void StartAutocomplete(bool has_selected_text,
+ bool prevent_inline_autocomplete) const;
// Determines whether the user can "paste and go", given the specified text.
// This also updates the internal paste-and-go-related state variables as
@@ -287,6 +319,9 @@ class AutocompleteEditModel : public NotificationObserver {
bool just_deleted_text,
bool at_end_of_edit);
+ // Invoked when the popup is going to change its bounds to |bounds|.
+ void PopupBoundsChangedTo(const gfx::Rect& bounds);
+
private:
enum PasteState {
NONE, // Most recent edit was not a paste that replaced all text.
@@ -322,6 +357,9 @@ class AutocompleteEditModel : public NotificationObserver {
// Called whenever user_text_ should change.
void InternalSetUserText(const std::wstring& text);
+ // Returns true if a keyword is selected.
+ bool KeywordIsSelected() const;
+
// Conversion between user text and display text. User text is the text the
// user has input. Display text is the text being shown in the edit. The
// two are different if a keyword is selected.
diff --git a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
index bd48602..6451fa6 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
@@ -35,6 +35,8 @@ class TestingAutocompleteEditView : public AutocompleteEditView {
size_t caret_pos) {}
virtual void SetForcedQuery() {}
virtual bool IsSelectAll() { return false; }
+ virtual void GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end) {}
virtual void SelectAll(bool reversed) {}
virtual void RevertAll() {}
virtual void UpdatePopup() {}
@@ -59,6 +61,13 @@ class TestingAutocompleteEditView : public AutocompleteEditView {
class TestingAutocompleteEditController : public AutocompleteEditController {
public:
TestingAutocompleteEditController() {}
+ virtual void OnAutocompleteWillClosePopup() {}
+ virtual void OnAutocompleteLosingFocus(gfx::NativeView view_gaining_focus) {}
+ virtual void OnAutocompleteWillAccept() {}
+ virtual bool OnCommitSuggestedText(const std::wstring& typed_text) {
+ return false;
+ }
+ virtual void OnPopupBoundsChanged(const gfx::Rect& bounds) {}
virtual void OnAutocompleteAccept(const GURL& url,
WindowOpenDisposition disposition,
PageTransition::Type transition,
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view.h b/chrome/browser/autocomplete/autocomplete_edit_view.h
index 0d4c230..ce9a227 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view.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.
@@ -10,6 +10,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_H_
+#pragma once
#include <string>
@@ -81,7 +82,7 @@ class AutocompleteEditView {
// Sets the edit to forced query mode. Practically speaking, this means that
// if the edit is not in forced query mode, its text is set to "?" with the
// cursor at the end, and if the edit is in forced query mode (its first
- // character is '?'), the text after the '?' is selected.
+ // non-whitespace character is '?'), the text after the '?' is selected.
//
// In the future we should display the search engine UI for the default engine
// rather than '?'.
@@ -90,6 +91,13 @@ class AutocompleteEditView {
// Returns true if all text is selected or there is no text at all.
virtual bool IsSelectAll() = 0;
+ // Fills |start| and |end| with the indexes of the current selection's bounds.
+ // It is not guaranteed that |*start < *end|, as the selection can be
+ // directed. If there is no selection, |start| and |end| will both be equal
+ // to the current cursor position.
+ virtual void GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end) = 0;
+
// Selects all the text in the edit. Use this in place of SetSelAll() to
// avoid selecting the "phantom newline" at the end of the edit.
virtual void SelectAll(bool reversed) = 0;
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc b/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc
index e267f3c..16d0d56 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc
@@ -4,12 +4,9 @@
#include <stdio.h>
-#include "base/file_path.h"
-#include "base/keyboard_codes.h"
-#include "base/logging.h"
+#include "app/keyboard_codes.h"
#include "base/message_loop.h"
-#include "base/platform_thread.h"
-#include "base/ref_counted.h"
+#include "base/string16.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -18,7 +15,6 @@
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
-#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
@@ -43,24 +39,24 @@ namespace {
const char kSearchKeyword[] = "foo";
const wchar_t kSearchKeywordKeys[] = {
- base::VKEY_F, base::VKEY_O, base::VKEY_O, 0
+ app::VKEY_F, app::VKEY_O, app::VKEY_O, 0
};
const char kSearchURL[] = "http://www.foo.com/search?q={searchTerms}";
const char kSearchShortName[] = "foo";
const char kSearchText[] = "abc";
const wchar_t kSearchTextKeys[] = {
- base::VKEY_A, base::VKEY_B, base::VKEY_C, 0
+ app::VKEY_A, app::VKEY_B, app::VKEY_C, 0
};
const char kSearchTextURL[] = "http://www.foo.com/search?q=abc";
const char kSearchSingleChar[] = "z";
-const wchar_t kSearchSingleCharKeys[] = { base::VKEY_Z, 0 };
+const wchar_t kSearchSingleCharKeys[] = { app::VKEY_Z, 0 };
const char kSearchSingleCharURL[] = "http://www.foo.com/search?q=z";
const char kHistoryPageURL[] = "chrome://history/#q=abc";
const char kDesiredTLDHostname[] = "www.bar.com";
const wchar_t kDesiredTLDKeys[] = {
- base::VKEY_B, base::VKEY_A, base::VKEY_R, 0
+ app::VKEY_B, app::VKEY_A, app::VKEY_R, 0
};
// Hostnames that shall be blocked by host resolver.
@@ -106,13 +102,6 @@ class AutocompleteEditViewTest : public InProcessBrowserTest,
set_show_window(true);
}
- void GetNativeWindow(gfx::NativeWindow* native_window) {
- BrowserWindow* window = browser()->window();
- ASSERT_TRUE(window);
- *native_window = window->GetNativeHandle();
- ASSERT_TRUE(*native_window);
- }
-
void GetAutocompleteEditView(AutocompleteEditView** edit_view) {
BrowserWindow* window = browser()->window();
ASSERT_TRUE(window);
@@ -122,18 +111,15 @@ class AutocompleteEditViewTest : public InProcessBrowserTest,
ASSERT_TRUE(*edit_view);
}
- void SendKey(base::KeyboardCode key, bool control, bool shift, bool alt) {
- gfx::NativeWindow window = NULL;
- ASSERT_NO_FATAL_FAILURE(GetNativeWindow(&window));
- ui_controls::SendKeyPressNotifyWhenDone(window, key, control, shift, alt,
- false /* command */,
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ void SendKey(app::KeyboardCode key, bool control, bool shift, bool alt) {
+ ASSERT_TRUE(
+ ui_test_utils::SendKeyPressSync(
+ browser(), key, control, shift, alt, false /* command */));
}
void SendKeySequence(const wchar_t* keys) {
for (; *keys; ++keys)
- ASSERT_NO_FATAL_FAILURE(SendKey(static_cast<base::KeyboardCode>(*keys),
+ ASSERT_NO_FATAL_FAILURE(SendKey(static_cast<app::KeyboardCode>(*keys),
false, false, false));
}
@@ -233,10 +219,11 @@ class AutocompleteEditViewTest : public InProcessBrowserTest,
Time t = Time::Now() - TimeDelta::FromHours(i + 1);
history_service->AddPageWithDetails(url, UTF8ToUTF16(cur.title),
cur.visit_count,
- cur.typed_count, t, false);
+ cur.typed_count, t, false,
+ history::SOURCE_BROWSED);
history_service->SetPageContents(url, UTF8ToUTF16(cur.body));
if (cur.starred) {
- bookmark_model->SetURLStarred(url, std::wstring(), true);
+ bookmark_model->SetURLStarred(url, string16(), true);
}
}
}
@@ -268,19 +255,6 @@ class AutocompleteEditViewTest : public InProcessBrowserTest,
}
MessageLoopForUI::current()->Quit();
}
-
-#if defined(OS_WIN)
- virtual void CleanUpOnMainThread() {
- // A hack to avoid hitting issue http://crbug.com/18372 and
- // http://crbug.com/18373
- // Weird that it only happens on Windows.
- // TODO(suzhe): Remove this hack as soon as these bugs are fixed.
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- new MessageLoop::QuitTask(),
- 2000);
- ui_test_utils::RunMessageLoop();
- }
-#endif
};
// Test if ctrl-* accelerators are workable in omnibox.
@@ -299,25 +273,25 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, BrowserAccelerators) {
ASSERT_NO_FATAL_FAILURE(WaitForTabOpenOrClose(tab_count + 1));
// Select the first Tab.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_1, true, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_1, true, false, false));
ASSERT_EQ(0, browser()->selected_index());
browser()->FocusLocationBar();
// Select the second Tab.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_2, true, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_2, true, false, false));
ASSERT_EQ(1, browser()->selected_index());
browser()->FocusLocationBar();
// Close a Tab.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_W, true, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_W, true, false, false));
ASSERT_NO_FATAL_FAILURE(WaitForTabOpenOrClose(tab_count));
// Try ctrl-l to focus location bar.
edit_view->SetUserText(L"Hello world");
EXPECT_FALSE(edit_view->IsSelectAll());
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_L, true, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_L, true, false, false));
EXPECT_TRUE(edit_view->IsSelectAll());
}
@@ -334,17 +308,17 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, BackspaceInKeywordMode) {
ASSERT_EQ(kSearchKeyword, WideToUTF8(edit_view->model()->keyword()));
// Trigger keyword mode.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_TAB, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_TAB, false, false, false));
ASSERT_FALSE(edit_view->model()->is_keyword_hint());
ASSERT_EQ(kSearchKeyword, WideToUTF8(edit_view->model()->keyword()));
// Backspace without search text should bring back keyword hint mode.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_BACK, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_BACK, false, false, false));
ASSERT_TRUE(edit_view->model()->is_keyword_hint());
ASSERT_EQ(kSearchKeyword, WideToUTF8(edit_view->model()->keyword()));
// Trigger keyword mode again.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_TAB, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_TAB, false, false, false));
ASSERT_FALSE(edit_view->model()->is_keyword_hint());
ASSERT_EQ(kSearchKeyword, WideToUTF8(edit_view->model()->keyword()));
@@ -354,7 +328,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, BackspaceInKeywordMode) {
// Should stay in keyword mode while deleting search text by pressing
// backspace.
for (size_t i = 0; i < arraysize(kSearchText) - 1; ++i) {
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_BACK, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_BACK, false, false, false));
ASSERT_FALSE(edit_view->model()->is_keyword_hint());
ASSERT_EQ(kSearchKeyword, WideToUTF8(edit_view->model()->keyword()));
}
@@ -363,10 +337,10 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, BackspaceInKeywordMode) {
ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchTextKeys));
// Move cursor to the beginning of the search text.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_HOME, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_HOME, false, false, false));
// Backspace at the beginning of the search text shall turn off
// the keyword mode.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_BACK, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_BACK, false, false, false));
ASSERT_FALSE(edit_view->model()->is_keyword_hint());
ASSERT_EQ(std::string(), WideToUTF8(edit_view->model()->keyword()));
ASSERT_EQ(std::string(kSearchKeyword) + kSearchText,
@@ -386,11 +360,11 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, Escape) {
EXPECT_TRUE(edit_view->IsSelectAll());
// Delete all text in omnibox.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_BACK, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_BACK, false, false, false));
EXPECT_TRUE(edit_view->GetText().empty());
// Escape shall revert the text in omnibox.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_ESCAPE, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_ESCAPE, false, false, false));
EXPECT_EQ(old_text, edit_view->GetText());
EXPECT_TRUE(edit_view->IsSelectAll());
}
@@ -409,7 +383,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, DesiredTLD) {
ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
ASSERT_TRUE(popup_model->IsOpen());
// ctrl-Enter triggers desired_tld feature, thus www.bar.com shall be opened.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_RETURN, true, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_RETURN, true, false, false));
GURL url = browser()->GetSelectedTabContents()->GetURL();
EXPECT_STREQ(kDesiredTLDHostname, url.host().c_str());
@@ -426,7 +400,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, AltEnter) {
edit_view->SetUserText(ASCIIToWide(chrome::kChromeUIHistoryURL));
int tab_count = browser()->tab_count();
// alt-Enter opens a new tab.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_RETURN, false, false, true));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_RETURN, false, false, true));
ASSERT_NO_FATAL_FAILURE(WaitForTabOpenOrClose(tab_count + 1));
}
@@ -450,7 +424,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EnterToSearch) {
popup_model->result().default_match()->type);
// Open the default match.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_RETURN, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_RETURN, false, false, false));
GURL url = browser()->GetSelectedTabContents()->GetURL();
EXPECT_STREQ(kSearchTextURL, url.spec().c_str());
@@ -467,7 +441,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EnterToSearch) {
popup_model->result().default_match()->type);
// Open the default match.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_RETURN, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_RETURN, false, false, false));
url = browser()->GetSelectedTabContents()->GetURL();
EXPECT_STREQ(kSearchSingleCharURL, url.spec().c_str());
}
@@ -495,7 +469,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EnterToOpenHistoryPage) {
AutocompleteMatch::OPEN_HISTORY_PAGE)
break;
size_t old_selected_line = popup_model->selected_line();
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_DOWN, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_DOWN, false, false, false));
ASSERT_EQ(old_selected_line + 1, popup_model->selected_line());
if (popup_model->selected_line() == size - 1)
break;
@@ -506,7 +480,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EnterToOpenHistoryPage) {
popup_model->result().match_at(popup_model->selected_line()).type);
// Open the history page item.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_RETURN, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_RETURN, false, false, false));
GURL url = browser()->GetSelectedTabContents()->GetURL();
EXPECT_STREQ(kHistoryPageURL, url.spec().c_str());
}
@@ -536,7 +510,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EscapeToDefaultMatch) {
// Move to another line with different text.
size_t size = popup_model->result().size();
while (popup_model->selected_line() < size - 1) {
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_DOWN, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_DOWN, false, false, false));
ASSERT_NE(old_selected_line, popup_model->selected_line());
if (old_text != edit_view->GetText())
break;
@@ -545,7 +519,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteEditViewTest, EscapeToDefaultMatch) {
EXPECT_NE(old_text, edit_view->GetText());
// Escape shall revert back to the default match item.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_ESCAPE, false, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_ESCAPE, false, false, false));
EXPECT_EQ(old_text, edit_view->GetText());
EXPECT_EQ(old_selected_line, popup_model->selected_line());
}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
index 679d2f2..9eda29f 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
@@ -9,11 +9,10 @@
#include <algorithm>
-#include "app/clipboard/clipboard.h"
-#include "app/clipboard/scoped_clipboard_writer.h"
#include "app/l10n_util.h"
#include "base/gtk_util.h"
#include "base/logging.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
@@ -33,6 +32,7 @@
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
+#include "third_party/undoview/undo_view.h"
#if defined(TOOLKIT_VIEWS)
#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h"
@@ -217,7 +217,7 @@ void AutocompleteEditViewGtk::Init() {
tag_table_ = gtk_text_tag_table_new();
text_buffer_ = gtk_text_buffer_new(tag_table_);
g_object_set_data(G_OBJECT(text_buffer_), kAutocompleteEditViewGtkKey, this);
- text_view_ = gtk_text_view_new_with_buffer(text_buffer_);
+ text_view_ = gtk_undo_view_new(text_buffer_);
if (popup_window_mode_)
gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view_), false);
@@ -342,6 +342,18 @@ int AutocompleteEditViewGtk::TextWidth() {
horizontal_border_size;
}
+int AutocompleteEditViewGtk::WidthOfTextAfterCursor() {
+ // TODO(sky): implement this.
+ NOTIMPLEMENTED();
+ return TextWidth();
+}
+
+gfx::Font AutocompleteEditViewGtk::GetFont() {
+ GtkRcStyle* rc_style = gtk_widget_get_modifier_style(text_view_);
+ return gfx::Font((rc_style && rc_style->font_desc) ?
+ rc_style->font_desc : text_view_->style->font_desc);
+}
+
void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) {
DCHECK(tab);
// If any text has been selected, register it as the PRIMARY selection so it
@@ -420,6 +432,10 @@ int AutocompleteEditViewGtk::GetIcon() const {
toolbar_model_->GetIcon();
}
+void AutocompleteEditViewGtk::SetUserText(const std::wstring& text) {
+ SetUserText(text, text, true);
+}
+
void AutocompleteEditViewGtk::SetUserText(const std::wstring& text,
const std::wstring& display_text,
bool update_popup) {
@@ -439,11 +455,12 @@ void AutocompleteEditViewGtk::SetWindowTextAndCaretPos(const std::wstring& text,
void AutocompleteEditViewGtk::SetForcedQuery() {
const std::wstring current_text(GetText());
- if (current_text.empty() || (current_text[0] != '?')) {
+ const size_t start = current_text.find_first_not_of(kWhitespaceWide);
+ if (start == std::wstring::npos || (current_text[start] != '?')) {
SetUserText(L"?");
} else {
StartUpdatingHighlightedText();
- SetSelectedRange(CharRange(current_text.size(), 1));
+ SetSelectedRange(CharRange(current_text.size(), start + 1));
FinishUpdatingHighlightedText();
}
}
@@ -460,6 +477,13 @@ bool AutocompleteEditViewGtk::IsSelectAll() {
gtk_text_iter_equal(&end, &sel_end);
}
+void AutocompleteEditViewGtk::GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end) {
+ CharRange selection = GetSelection();
+ *start = static_cast<size_t>(selection.cp_min);
+ *end = static_cast<size_t>(selection.cp_max);
+}
+
void AutocompleteEditViewGtk::SelectAll(bool reversed) {
// SelectAll() is invoked as a side effect of other actions (e.g. switching
// tabs or hitting Escape) in autocomplete_edit.cc, so we don't update the
@@ -481,10 +505,16 @@ void AutocompleteEditViewGtk::UpdatePopup() {
// Don't inline autocomplete when the caret/selection isn't at the end of
// the text.
CharRange sel = GetSelection();
- model_->StartAutocomplete(std::max(sel.cp_max, sel.cp_min) < GetTextLength());
+ model_->StartAutocomplete(sel.cp_min != sel.cp_max,
+ std::max(sel.cp_max, sel.cp_min) < GetTextLength());
}
void AutocompleteEditViewGtk::ClosePopup() {
+#if defined(TOOLKIT_VIEWS)
+ if (popup_view_->GetModel()->IsOpen())
+ controller_->OnAutocompleteWillClosePopup();
+#endif
+
popup_view_->GetModel()->StopAutocomplete();
}
@@ -915,6 +945,12 @@ gboolean AutocompleteEditViewGtk::HandleViewFocusIn(GtkWidget* sender,
gboolean AutocompleteEditViewGtk::HandleViewFocusOut(GtkWidget* sender,
GdkEventFocus* event) {
+#if defined(TOOLKIT_VIEWS)
+ // This must be invoked before ClosePopup.
+ // TODO: figure out who is getting focus.
+ controller_->OnAutocompleteLosingFocus(NULL);
+#endif
+
// Close the popup.
ClosePopup();
// Tell the model to reset itself.
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
index 83aa77a..92c0f77 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -15,10 +16,10 @@
#include "base/scoped_ptr.h"
#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/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "chrome/common/page_transition_types.h"
#include "gfx/rect.h"
#include "webkit/glue/window_open_disposition.h"
@@ -28,6 +29,11 @@ class AutocompleteEditModel;
class AutocompletePopupView;
class Profile;
class TabContents;
+
+namespace gfx{
+class Font;
+}
+
namespace views {
class View;
}
@@ -69,10 +75,18 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
// Initialize, create the underlying widgets, etc.
void Init();
- // Returns the width, in pixels, needed to display the current text. The
- // returned value includes margins and borders.
+ // Returns the width in pixels needed to display the current text. The
+ // returned value includes margins.
int TextWidth();
+ // Returns the width in pixels needed to display the text from one character
+ // before the caret to the end of the string. See comments in
+ // LocationBarView::Layout as to why this uses -1.
+ int WidthOfTextAfterCursor();
+
+ // Returns the font.
+ gfx::Font GetFont();
+
// Implement the AutocompleteEditView interface.
virtual AutocompleteEditModel* model() { return model_.get(); }
virtual const AutocompleteEditModel* model() const { return model_.get(); }
@@ -93,9 +107,7 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
virtual bool IsEditingOrEmpty() const;
virtual int GetIcon() const;
- virtual void SetUserText(const std::wstring& text) {
- SetUserText(text, text, true);
- }
+ virtual void SetUserText(const std::wstring& text);
virtual void SetUserText(const std::wstring& text,
const std::wstring& display_text,
bool update_popup);
@@ -106,6 +118,8 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
virtual void SetForcedQuery();
virtual bool IsSelectAll();
+ virtual void GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end);
virtual void SelectAll(bool reversed);
virtual void RevertAll();
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
index ae9a900..a474ce0 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_MAC_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -48,9 +49,7 @@ class AutocompleteEditViewMac : public AutocompleteEditView,
virtual bool IsEditingOrEmpty() const;
virtual int GetIcon() const;
- virtual void SetUserText(const std::wstring& text) {
- SetUserText(text, text, true);
- }
+ virtual void SetUserText(const std::wstring& text);
virtual void SetUserText(const std::wstring& text,
const std::wstring& display_text,
bool update_popup);
@@ -61,6 +60,8 @@ class AutocompleteEditViewMac : public AutocompleteEditView,
virtual void SetForcedQuery();
virtual bool IsSelectAll();
+ virtual void GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end);
virtual void SelectAll(bool reversed);
virtual void RevertAll();
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
index 736525d..0c2646e 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
@@ -126,8 +126,8 @@ NSImage* AutocompleteEditViewMac::ImageForResource(int resource_id) {
switch(resource_id) {
// From the autocomplete popup, or the star icon at the RHS of the
// text field.
- case IDR_OMNIBOX_STAR: image_name = @"omnibox_star.pdf"; break;
- case IDR_OMNIBOX_STAR_LIT: image_name = @"omnibox_star_lit.pdf"; break;
+ case IDR_STAR: image_name = @"star.pdf"; break;
+ case IDR_STAR_LIT: image_name = @"star_lit.pdf"; break;
// Values from |AutocompleteMatch::TypeToIcon()|.
case IDR_OMNIBOX_SEARCH: image_name = @"omnibox_search.pdf"; break;
@@ -301,6 +301,10 @@ int AutocompleteEditViewMac::GetIcon() const {
toolbar_model_->GetIcon();
}
+void AutocompleteEditViewMac::SetUserText(const std::wstring& text) {
+ SetUserText(text, text, true);
+}
+
void AutocompleteEditViewMac::SetUserText(const std::wstring& text,
const std::wstring& display_text,
bool update_popup) {
@@ -348,10 +352,11 @@ void AutocompleteEditViewMac::SetForcedQuery() {
FocusLocation(true);
const std::wstring current_text(GetText());
- if (current_text.empty() || (current_text[0] != '?')) {
+ const size_t start = current_text.find_first_not_of(kWhitespaceWide);
+ if (start == std::wstring::npos || (current_text[start] != '?')) {
SetUserText(L"?");
} else {
- NSRange range = NSMakeRange(1, current_text.size() - 1);
+ NSRange range = NSMakeRange(start + 1, current_text.size() - start - 1);
[[field_ currentEditor] setSelectedRange:range];
}
}
@@ -363,6 +368,18 @@ bool AutocompleteEditViewMac::IsSelectAll() {
return NSEqualRanges(all_range, GetSelectedRange());
}
+void AutocompleteEditViewMac::GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end) {
+ if (![field_ currentEditor]) {
+ *start = *end = 0;
+ return;
+ }
+
+ const NSRange selected_range = GetSelectedRange();
+ *start = static_cast<size_t>(selected_range.location);
+ *end = static_cast<size_t>(NSMaxRange(selected_range));
+}
+
void AutocompleteEditViewMac::SelectAll(bool reversed) {
// TODO(shess): Figure out what |reversed| implies. The gtk version
// has it imply inverting the selection front to back, but I don't
@@ -407,7 +424,8 @@ void AutocompleteEditViewMac::UpdatePopup() {
prevent_inline_autocomplete = true;
}
- model_->StartAutocomplete(prevent_inline_autocomplete);
+ model_->StartAutocomplete([editor selectedRange].length != 0,
+ prevent_inline_autocomplete);
}
void AutocompleteEditViewMac::ClosePopup() {
@@ -920,5 +938,5 @@ std::wstring AutocompleteEditViewMac::GetClipboardText(Clipboard* clipboard) {
// static
NSFont* AutocompleteEditViewMac::GetFieldFont() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- return rb.GetFont(ResourceBundle::BaseFont).nativeFont();
+ return rb.GetFont(ResourceBundle::BaseFont).GetNativeFont();
}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
index 1182059..9660ecb 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
@@ -13,6 +13,7 @@
#include "app/clipboard/clipboard.h"
#include "app/clipboard/scoped_clipboard_writer.h"
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/l10n_util_win.h"
#include "app/os_exchange_data.h"
@@ -24,9 +25,9 @@
#include "base/basictypes.h"
#include "base/i18n/rtl.h"
#include "base/iat_patch.h"
-#include "base/keyboard_codes.h"
#include "base/lazy_instance.h"
#include "base/ref_counted.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/autocomplete/autocomplete_accessibility.h"
@@ -429,7 +430,7 @@ AutocompleteEditViewWin::AutocompleteEditViewWin(
Create(hwnd, 0, 0, 0, l10n_util::GetExtendedStyles());
SetReadOnly(popup_window_mode_);
- SetFont(font_.hfont());
+ SetFont(font_.GetNativeFont());
// NOTE: Do not use SetWordBreakProcEx() here, that is no longer supported as
// of Rich Edit 2.0 onward.
@@ -438,7 +439,7 @@ AutocompleteEditViewWin::AutocompleteEditViewWin(
// Get the metrics for the font.
HDC dc = ::GetDC(NULL);
- SelectObject(dc, font_.hfont());
+ SelectObject(dc, font_.GetNativeFont());
TEXTMETRIC tm = {0};
GetTextMetrics(dc, &tm);
const float kXHeightRatio = 0.7f; // The ratio of a font's x-height to its
@@ -446,12 +447,12 @@ AutocompleteEditViewWin::AutocompleteEditViewWin(
// provide a true value for a font's
// x-height in its text metrics, so we
// approximate.
- font_x_height_ = static_cast<int>((static_cast<float>(font_.baseline() -
+ font_x_height_ = static_cast<int>((static_cast<float>(font_.GetBaseline() -
tm.tmInternalLeading) * kXHeightRatio) + 0.5);
// The distance from the top of the field to the desired baseline of the
// rendered text.
const int kTextBaseline = popup_window_mode_ ? 15 : 18;
- font_y_adjustment_ = kTextBaseline - font_.baseline();
+ font_y_adjustment_ = kTextBaseline - font_.GetBaseline();
// Get the number of twips per pixel, which we need below to offset our text
// by the desired number of pixels.
@@ -495,6 +496,21 @@ AutocompleteEditViewWin::~AutocompleteEditViewWin() {
g_paint_patcher.Pointer()->DerefPatch();
}
+int AutocompleteEditViewWin::TextWidth() {
+ return WidthNeededToDisplay(GetText());
+}
+
+int AutocompleteEditViewWin::WidthOfTextAfterCursor() {
+ CHARRANGE selection;
+ GetSelection(selection);
+ const int start = std::max(0, static_cast<int>(selection.cpMax - 1));
+ return WidthNeededToDisplay(GetText().substr(start));
+ }
+
+gfx::Font AutocompleteEditViewWin::GetFont() {
+ return font_;
+}
+
void AutocompleteEditViewWin::SaveStateToTab(TabContents* tab) {
DCHECK(tab);
@@ -613,6 +629,10 @@ int AutocompleteEditViewWin::GetIcon() const {
toolbar_model_->GetIcon();
}
+void AutocompleteEditViewWin::SetUserText(const std::wstring& text) {
+ SetUserText(text, text, true);
+}
+
void AutocompleteEditViewWin::SetUserText(const std::wstring& text,
const std::wstring& display_text,
bool update_popup) {
@@ -633,10 +653,11 @@ void AutocompleteEditViewWin::SetWindowTextAndCaretPos(const std::wstring& text,
void AutocompleteEditViewWin::SetForcedQuery() {
const std::wstring current_text(GetText());
- if (current_text.empty() || (current_text[0] != '?'))
+ const size_t start = current_text.find_first_not_of(kWhitespaceWide);
+ if (start == std::wstring::npos || (current_text[start] != '?'))
SetUserText(L"?");
else
- SetSelection(current_text.length(), 1);
+ SetSelection(current_text.length(), start + 1);
}
bool AutocompleteEditViewWin::IsSelectAll() {
@@ -645,6 +666,14 @@ bool AutocompleteEditViewWin::IsSelectAll() {
return IsSelectAllForRange(selection);
}
+void AutocompleteEditViewWin::GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end) {
+ CHARRANGE selection;
+ GetSel(selection);
+ *start = static_cast<size_t>(selection.cpMin);
+ *end = static_cast<size_t>(selection.cpMax);
+}
+
void AutocompleteEditViewWin::SelectAll(bool reversed) {
if (reversed)
SetSelection(GetTextLength(), 0);
@@ -691,15 +720,21 @@ void AutocompleteEditViewWin::UpdatePopup() {
// * The user is trying to compose something in an IME
CHARRANGE sel;
GetSel(sel);
- model_->StartAutocomplete((sel.cpMax < GetTextLength()) || ime_composing);
+ model_->StartAutocomplete(sel.cpMax != sel.cpMin,
+ (sel.cpMax < GetTextLength()) || ime_composing);
}
void AutocompleteEditViewWin::ClosePopup() {
+ if (popup_view_->GetModel()->IsOpen())
+ controller_->OnAutocompleteWillClosePopup();
+
popup_view_->GetModel()->StopAutocomplete();
}
void AutocompleteEditViewWin::SetFocus() {
::SetFocus(m_hWnd);
+ parent_view_->
+ NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS, false);
}
IAccessible* AutocompleteEditViewWin::GetIAccessible() {
@@ -871,10 +906,10 @@ void AutocompleteEditViewWin::PasteAndGo(const std::wstring& text) {
bool AutocompleteEditViewWin::SkipDefaultKeyEventProcessing(
const views::KeyEvent& e) {
- base::KeyboardCode key = e.GetKeyCode();
+ app::KeyboardCode key = e.GetKeyCode();
// We don't process ALT + numpad digit as accelerators, they are used for
// entering special characters. We do translate alt-home.
- if (e.IsAltDown() && (key != base::VKEY_HOME) &&
+ if (e.IsAltDown() && (key != app::VKEY_HOME) &&
win_util::IsNumPadDigit(key, e.IsExtendedKey()))
return true;
@@ -886,28 +921,28 @@ bool AutocompleteEditViewWin::SkipDefaultKeyEventProcessing(
// accelerators (e.g., F5 for reload the page should work even when the
// Omnibox gets focused).
switch (key) {
- case base::VKEY_ESCAPE: {
+ case app::VKEY_ESCAPE: {
ScopedFreeze freeze(this, GetTextObjectModel());
return model_->OnEscapeKeyPressed();
}
- case base::VKEY_RETURN:
+ case app::VKEY_RETURN:
return true;
- case base::VKEY_UP:
- case base::VKEY_DOWN:
+ case app::VKEY_UP:
+ case app::VKEY_DOWN:
return !e.IsAltDown();
- case base::VKEY_DELETE:
- case base::VKEY_INSERT:
+ case app::VKEY_DELETE:
+ case app::VKEY_INSERT:
return !e.IsAltDown() && e.IsShiftDown() && !e.IsControlDown();
- case base::VKEY_X:
- case base::VKEY_V:
+ case app::VKEY_X:
+ case app::VKEY_V:
return !e.IsAltDown() && e.IsControlDown();
- case base::VKEY_BACK:
- case base::VKEY_OEM_PLUS:
+ case app::VKEY_BACK:
+ case app::VKEY_OEM_PLUS:
return true;
default:
@@ -1349,6 +1384,9 @@ void AutocompleteEditViewWin::OnKillFocus(HWND focus_wnd) {
return;
}
+ // This must be invoked before ClosePopup.
+ controller_->OnAutocompleteLosingFocus(focus_wnd);
+
// Close the popup.
ClosePopup();
@@ -1752,7 +1790,7 @@ void AutocompleteEditViewWin::HandleKeystroke(UINT message,
ScopedFreeze freeze(this, GetTextObjectModel());
OnBeforePossibleChange();
- if (key == base::VKEY_HOME || key == base::VKEY_END) {
+ if (key == app::VKEY_HOME || key == app::VKEY_END) {
// DefWindowProc() might reset the keyboard layout when it receives a
// keydown event for VKEY_HOME or VKEY_END. When the window was created
// with WS_EX_LAYOUTRTL and the current keyboard layout is not a RTL one,
@@ -1791,10 +1829,22 @@ bool AutocompleteEditViewWin::OnKeyDownOnlyWritable(TCHAR key,
// WM_SYSKEYDOWN, so we need to check (flags & KF_ALTDOWN) in various places
// in this function even with a WM_SYSKEYDOWN handler.
- // Update LocationBarView::SkipDefaultKeyEventProcessing() as well when you
- // add some key combinations here.
+ // If adding a new key that could possibly be an accelerator then you'll need
+ // to update LocationBarView::SkipDefaultKeyEventProcessing() as well.
int count = repeat_count;
switch (key) {
+ case VK_RIGHT:
+ // TODO(sky): figure out RTL.
+ if (base::i18n::IsRTL())
+ return false;
+ {
+ CHARRANGE selection;
+ GetSel(selection);
+ return (selection.cpMin == selection.cpMax) &&
+ (selection.cpMin == GetTextLength()) &&
+ controller_->OnCommitSuggestedText(GetText());
+ }
+
case VK_RETURN:
model_->AcceptInput((flags & KF_ALTDOWN) ?
NEW_FOREGROUND_TAB : CURRENT_TAB, false);
@@ -2147,10 +2197,10 @@ void AutocompleteEditViewWin::DrawSlashForInsecureScheme(
const int kAdditionalSpaceOutsideFont =
static_cast<int>(ceil(kStrokeWidthPixels * 1.5f));
const CRect scheme_rect(PosFromChar(insecure_scheme_component_.begin).x,
- font_top + font_.baseline() - font_x_height_ -
+ font_top + font_.GetBaseline() - font_x_height_ -
kAdditionalSpaceOutsideFont,
PosFromChar(insecure_scheme_component_.end()).x,
- font_top + font_.baseline() +
+ font_top + font_.GetBaseline() +
kAdditionalSpaceOutsideFont);
// Clip to the portion we care about and translate to canvas coordinates
@@ -2231,7 +2281,7 @@ void AutocompleteEditViewWin::DrawDropHighlight(
const CRect highlight_rect(highlight_x,
highlight_y,
highlight_x + 1,
- highlight_y + font_.height());
+ highlight_y + font_.GetHeight());
// Clip the highlight to the region being painted.
CRect clip_rect;
@@ -2428,7 +2478,7 @@ void AutocompleteEditViewWin::RepaintDropHighlight(int position) {
if ((position != -1) && (position <= GetTextLength())) {
const POINT min_loc(PosFromChar(position));
const RECT highlight_bounds = {min_loc.x - 1, font_y_adjustment_,
- min_loc.x + 2, font_.height() + font_y_adjustment_};
+ min_loc.x + 2, font_.GetHeight() + font_y_adjustment_};
InvalidateRect(&highlight_bounds, false);
}
}
@@ -2482,3 +2532,19 @@ void AutocompleteEditViewWin::TrackMousePosition(MouseButton button,
click_point_[button] = point;
}
}
+
+int AutocompleteEditViewWin::GetHorizontalMargin() {
+ RECT rect;
+ GetRect(&rect);
+ RECT client_rect;
+ GetClientRect(&client_rect);
+ return (rect.left - client_rect.left) + (client_rect.right - rect.right);
+}
+
+int AutocompleteEditViewWin::WidthNeededToDisplay(const std::wstring& text) {
+ // Use font_.GetStringWidth() instead of
+ // PosFromChar(location_entry_->GetTextLength()) because PosFromChar() is
+ // apparently buggy. In both LTR UI and RTL UI with left-to-right layout,
+ // PosFromChar(i) might return 0 when i is greater than 1.
+ return font_.GetStringWidth(text) + GetHorizontalMargin();
+}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h
index 8157706..c0abab6 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_WIN_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_WIN_H_
+#pragma once
#include <atlbase.h>
#include <atlapp.h>
@@ -24,7 +25,6 @@
#include "webkit/glue/window_open_disposition.h"
#include "views/controls/menu/menu_2.h"
-class AutocompletePopupModel;
class Profile;
class TabContents;
namespace views {
@@ -74,6 +74,18 @@ class AutocompleteEditViewWin
views::View* parent_view() const { return parent_view_; }
+ // Returns the width in pixels needed to display the current text. The
+ // returned value includes margins.
+ int TextWidth();
+
+ // Returns the width in pixels needed to display the text from one character
+ // before the caret to the end of the string. See comments in
+ // LocationBarView::Layout as to why this uses -1.
+ int WidthOfTextAfterCursor();
+
+ // Returns the font.
+ gfx::Font GetFont();
+
// Implement the AutocompleteEditView interface.
virtual AutocompleteEditModel* model() { return model_.get(); }
virtual const AutocompleteEditModel* model() const { return model_.get(); }
@@ -94,9 +106,7 @@ class AutocompleteEditViewWin
virtual bool IsEditingOrEmpty() const;
virtual int GetIcon() const;
- virtual void SetUserText(const std::wstring& text) {
- SetUserText(text, text, true);
- }
+ virtual void SetUserText(const std::wstring& text);
virtual void SetUserText(const std::wstring& text,
const std::wstring& display_text,
bool update_popup);
@@ -107,6 +117,8 @@ class AutocompleteEditViewWin
virtual void SetForcedQuery();
virtual bool IsSelectAll();
+ virtual void GetSelectionBounds(std::wstring::size_type* start,
+ std::wstring::size_type* end);
virtual void SelectAll(bool reversed);
virtual void RevertAll();
@@ -124,6 +136,7 @@ class AutocompleteEditViewWin
virtual bool OnAfterPossibleChange();
virtual gfx::NativeView GetNativeView() const;
virtual CommandUpdater* GetCommandUpdater();
+ int GetPopupMaxYCoordinate();
// Exposes custom IAccessible implementation to the overall MSAA hierarchy.
IAccessible* GetIAccessible();
@@ -383,6 +396,12 @@ class AutocompleteEditViewWin
void SelectAllIfNecessary(MouseButton button, const CPoint& point);
void TrackMousePosition(MouseButton button, const CPoint& point);
+ // Returns the sum of the left and right margins.
+ int GetHorizontalMargin();
+
+ // Returns the width in pixels needed to display |text|.
+ int WidthNeededToDisplay(const std::wstring& text);
+
scoped_ptr<AutocompleteEditModel> model_;
scoped_ptr<AutocompletePopupView> popup_view_;
diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.cc b/chrome/browser/autocomplete/autocomplete_popup_model.cc
index f4f7a82..7456ccd 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 "unicode/ubidi.h"
+
#include "base/string_util.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_popup_view.h"
@@ -12,7 +14,7 @@
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/notification_service.h"
-#include "third_party/icu/public/common/unicode/ubidi.h"
+#include "gfx/rect.h"
///////////////////////////////////////////////////////////////////////////////
// AutocompletePopupModel
@@ -82,14 +84,19 @@ void AutocompletePopupModel::SetHoveredLine(size_t line) {
void AutocompletePopupModel::SetSelectedLine(size_t line,
bool reset_to_default) {
+ // We should at least be dealing with the results of the current query. Note
+ // that even if |line| was valid on entry, this may make it invalid. We clamp
+ // it below.
+ controller_->CommitIfQueryHasNeverBeenCommitted();
+
const AutocompleteResult& result = controller_->result();
- CHECK(line < result.size());
if (result.empty())
return;
// Cancel the query so the matches don't change on the user.
controller_->Stop(false);
+ line = std::min(line, result.size() - 1);
const AutocompleteMatch& match = result.match_at(line);
if (reset_to_default) {
manually_selected_match_.Clear();
@@ -154,6 +161,10 @@ void AutocompletePopupModel::InfoForCurrentSelection(
DCHECK(match != NULL);
const AutocompleteResult* result;
if (!controller_->done()) {
+ // NOTE: Using latest_result() is important here since not only could it
+ // contain newer results than result() for the current query, it could even
+ // refer to an entirely different query (e.g. if the user is typing rapidly
+ // and the controller is purposefully delaying updates to avoid flicker).
result = &controller_->latest_result();
// It's technically possible for |result| to be empty if no provider returns
// a synchronous result but the query has not completed synchronously;
@@ -229,8 +240,8 @@ void AutocompletePopupModel::Move(int count) {
// Clamp the new line to [0, result_.count() - 1].
const size_t new_line = selected_line_ + count;
- SetSelectedLine((((count < 0) && (new_line >= selected_line_)) ?
- 0 : std::min(new_line, result.size() - 1)), false);
+ SetSelectedLine(((count < 0) && (new_line >= selected_line_)) ? 0 : new_line,
+ false);
}
void AutocompletePopupModel::TryDeletingCurrentItem() {
@@ -252,10 +263,12 @@ void AutocompletePopupModel::TryDeletingCurrentItem() {
const AutocompleteResult& result = controller_->result();
if (!result.empty()) {
// Move the selection to the next choice after the deleted one.
+ // SetSelectedLine() will clamp to take care of the case where we deleted
+ // the last item.
// TODO(pkasting): Eventually the controller should take care of this
// before notifying us, reducing flicker. At that point the check for
// deletability can move there too.
- SetSelectedLine(std::min(result.size() - 1, selected_line), false);
+ SetSelectedLine(selected_line, false);
}
}
}
@@ -268,8 +281,8 @@ void AutocompletePopupModel::Observe(NotificationType type,
const AutocompleteResult* result =
Details<const AutocompleteResult>(details).ptr();
- selected_line_ = (result->default_match() == result->end()) ?
- kNoMatch : (result->default_match() - result->begin());
+ selected_line_ = result->default_match() == result->end() ?
+ kNoMatch : static_cast<size_t>(result->default_match() - result->begin());
// There had better not be a nonempty result set with no default match.
CHECK((selected_line_ != kNoMatch) || result->empty());
// If we're going to trim the window size to no longer include the hovered
@@ -279,6 +292,12 @@ void AutocompletePopupModel::Observe(NotificationType type,
SetHoveredLine(kNoMatch);
view_->UpdatePopupAppearance();
+
+#if defined(TOOLKIT_VIEWS)
+ edit_model_->PopupBoundsChangedTo(view_->GetTargetBounds());
+#else
+ // TODO: port
+#endif
}
const SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch(
@@ -286,6 +305,6 @@ const SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch(
if (!match.template_url || !match.template_url->IsExtensionKeyword())
return NULL;
- return &profile_->GetExtensionsService()->GetOmniboxIcon(
+ return &profile_->GetExtensionsService()->GetOmniboxPopupIcon(
match.template_url->GetExtensionId());
}
diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.h b/chrome/browser/autocomplete/autocomplete_popup_model.h
index 8686bde..5a7fe92 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_model.h
+++ b/chrome/browser/autocomplete/autocomplete_popup_model.h
@@ -4,9 +4,11 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_MODEL_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_MODEL_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class AutocompleteEditModel;
@@ -39,6 +41,8 @@ class AutocompletePopupModel : public NotificationObserver {
// Returns true if the popup is currently open.
bool IsOpen() const;
+ AutocompletePopupView* view() const { return view_; }
+
// Returns the AutocompleteController used by this popup.
AutocompleteController* autocomplete_controller() const {
return controller_.get();
@@ -62,7 +66,7 @@ class AutocompletePopupModel : public NotificationObserver {
// Call to change the selected line. This will update all state and repaint
// the necessary parts of the window, as well as updating the edit with the
- // new temporary text. |line| should be within the range of valid lines.
+ // new temporary text. |line| will be clamped to the range of valid lines.
// |reset_to_default| is true when the selection is being reset back to the
// default match, and thus there is no temporary text (and no
// |manually_selected_match_|).
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view.h b/chrome/browser/autocomplete/autocomplete_popup_view.h
index 5674e4b..279d63d 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view.h
+++ b/chrome/browser/autocomplete/autocomplete_popup_view.h
@@ -10,6 +10,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_H_
+#pragma once
#include "build/build_config.h"
@@ -29,6 +30,13 @@ class AutocompletePopupView {
// mean opening or closing the window.
virtual void UpdatePopupAppearance() = 0;
+#if defined(TOOLKIT_VIEWS)
+ // Returns the target bounds for the popup. This returns the popup's current
+ // bounds when not animating, or the desired target bounds when animating.
+ // The return value is in screen coordinates.
+ virtual gfx::Rect GetTargetBounds() = 0;
+#endif
+
// Paint any pending updates.
virtual void PaintUpdatesNow() = 0;
@@ -40,6 +48,9 @@ class AutocompletePopupView {
// Returns the popup's model.
virtual AutocompletePopupModel* GetModel() = 0;
+
+ // Returns the max y coordinate of the popup in screen coordinates.
+ virtual int GetMaxYCoordinate() = 0;
};
#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_H_
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
index 8a6c24b..5923ec5 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
@@ -9,7 +9,6 @@
#include <algorithm>
#include <string>
-#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
@@ -58,10 +57,10 @@ const int kIconWidth = 17;
const int kIconTopPadding = 2;
// Space between the left edge (including the border) and the text.
-const int kIconLeftPadding = 5 + kBorderThickness;
+const int kIconLeftPadding = 3 + kBorderThickness;
// Space between the image and the text.
-const int kIconRightPadding = 7;
+const int kIconRightPadding = 5;
// Space between the left edge (including the border) and the text.
const int kIconAreaWidth =
@@ -75,11 +74,8 @@ const int kRightPadding = 3;
// the total width.
const float kContentWidthPercentage = 0.7;
-// How much to offset the popup from the bottom of the location bar in gtk mode.
-const int kGtkVerticalOffset = 3;
-
-// How much we shrink the popup on the left/right in gtk mode.
-const int kGtkHorizontalOffset = 1;
+// How much to offset the popup from the bottom of the location bar.
+const int kVerticalOffset = 3;
// UTF-8 Left-to-right embedding.
const char* kLRE = "\xe2\x80\xaa";
@@ -289,9 +285,9 @@ AutocompletePopupViewGtk::AutocompletePopupViewGtk(
// plumb a gfx::Font through. This is because popup windows have a
// different font size, although we could just derive that font here.
// For now, force the font size.
- gfx::Font font = gfx::Font::CreateFont(
- gfx::Font().FontName(), browser_defaults::kAutocompletePopupFontSize);
- PangoFontDescription* pfd = gfx::Font::PangoFontFromGfxFont(font);
+ gfx::Font font(gfx::Font().GetFontName(),
+ browser_defaults::kAutocompletePopupFontSize);
+ PangoFontDescription* pfd = font.GetNativeFont();
pango_layout_set_font_description(layout_, pfd);
pango_font_description_free(pfd);
@@ -370,6 +366,12 @@ AutocompletePopupModel* AutocompletePopupViewGtk::GetModel() {
return model_.get();
}
+int AutocompletePopupViewGtk::GetMaxYCoordinate() {
+ // TODO: implement if match preview pans out.
+ NOTIMPLEMENTED();
+ return 0;
+}
+
void AutocompletePopupViewGtk::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -378,28 +380,17 @@ void AutocompletePopupViewGtk::Observe(NotificationType type,
if (theme_provider_->UseGtkTheme()) {
border_color_ = theme_provider_->GetBorderColor();
- // Create a fake gtk table
- GtkWidget* fake_tree = gtk_entry_new();
- GtkStyle* style = gtk_rc_get_style(fake_tree);
+ gtk_util::GetTextColors(
+ &background_color_, &selected_background_color_,
+ &content_text_color_, &selected_content_text_color_);
- background_color_ = style->base[GTK_STATE_NORMAL];
- selected_background_color_ = style->base[GTK_STATE_SELECTED];
hovered_background_color_ = gtk_util::AverageColors(
background_color_, selected_background_color_);
-
- content_text_color_ = style->text[GTK_STATE_NORMAL];
- selected_content_text_color_ = style->text[GTK_STATE_SELECTED];
- url_text_color_ =
- NormalURLColor(style->text[GTK_STATE_NORMAL]);
- url_selected_text_color_ =
- SelectedURLColor(style->text[GTK_STATE_SELECTED],
- style->base[GTK_STATE_SELECTED]);
-
- description_text_color_ = style->text[GTK_STATE_NORMAL];
- description_selected_text_color_ = style->text[GTK_STATE_SELECTED];
-
- g_object_ref_sink(fake_tree);
- g_object_unref(fake_tree);
+ url_text_color_ = NormalURLColor(content_text_color_);
+ url_selected_text_color_ = SelectedURLColor(selected_content_text_color_,
+ selected_background_color_);
+ description_text_color_ = content_text_color_;
+ description_selected_text_color_ = selected_content_text_color_;
} else {
border_color_ = kBorderColor;
background_color_ = kBackgroundColor;
@@ -422,27 +413,12 @@ void AutocompletePopupViewGtk::Show(size_t num_results) {
gint origin_x, origin_y;
gdk_window_get_origin(location_bar_->window, &origin_x, &origin_y);
GtkAllocation allocation = location_bar_->allocation;
- int vertical_offset = 0;
- int horizontal_offset = 0;
- if (theme_provider_->UseGtkTheme()) {
- // Shrink the popup by 1 pixel on both sides in gtk mode. The darkest line
- // is usually one pixel in, and is almost always +/-1 pixel from this,
- // meaning the vertical offset will hide (hopefully) problems when this is
- // wrong.
- horizontal_offset = kGtkHorizontalOffset;
-
- // We offset the the popup from the bottom of the location bar in gtk
- // mode. The background color between the bottom of the location bar and
- // the popup helps hide the fact that we can't really reliably match what
- // the user would otherwise preceive as the left/right edges of the
- // location bar.
- vertical_offset = kGtkVerticalOffset;
- }
+ int horizontal_offset = 1;
gtk_window_move(GTK_WINDOW(window_),
origin_x + allocation.x - kBorderThickness + horizontal_offset,
origin_y + allocation.y + allocation.height - kBorderThickness - 1 +
- vertical_offset);
+ kVerticalOffset);
gtk_widget_set_size_request(window_,
allocation.width + (kBorderThickness * 2) - (horizontal_offset * 2),
(num_results * kHeightPerResult) + (kBorderThickness * 2));
@@ -587,17 +563,6 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget,
pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE);
- // An offset to align text in gtk mode. The hard coded constants in this file
- // are all created for the chrome-theme. In an effort to make this look good
- // on the majority of gtk themes, we shrink the popup by one pixel on each
- // side and push it downwards a bit so there's space between the drawn
- // location bar and the popup so we don't touch it (contrast with
- // chrome-theme where that's exactly what we want). Because of that, we need
- // to shift the content inside the popup by one pixel.
- int gtk_offset = 0;
- if (theme_provider_->UseGtkTheme())
- gtk_offset = kGtkHorizontalOffset;
-
for (size_t i = 0; i < result.size(); ++i) {
gfx::Rect line_rect = GetRectForLine(i, window_rect.width());
// Only repaint and layout damaged lines.
@@ -616,8 +581,8 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget,
line_rect.width(), line_rect.height());
}
- int icon_start_x = ltr ? (kIconLeftPadding - gtk_offset) :
- (line_rect.width() - kIconLeftPadding - kIconWidth + gtk_offset);
+ int icon_start_x = ltr ? kIconLeftPadding :
+ (line_rect.width() - kIconLeftPadding - kIconWidth);
// Draw the icon for this result.
DrawFullPixbuf(drawable, gc,
IconForMatch(match, is_selected),
@@ -652,8 +617,8 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget,
line_rect.y() + ((kHeightPerResult - actual_content_height) / 2));
gdk_draw_layout(drawable, gc,
- ltr ? (kIconAreaWidth - gtk_offset) :
- (text_width - actual_content_width + gtk_offset),
+ ltr ? kIconAreaWidth :
+ (text_width - actual_content_width),
content_y, layout_);
if (has_description) {
@@ -668,8 +633,8 @@ gboolean AutocompletePopupViewGtk::HandleExpose(GtkWidget* widget,
gint actual_description_width;
pango_layout_get_size(layout_, &actual_description_width, NULL);
gdk_draw_layout(drawable, gc, ltr ?
- (kIconAreaWidth - gtk_offset + actual_content_width) :
- (text_width - actual_content_width + gtk_offset -
+ (kIconAreaWidth + actual_content_width) :
+ (text_width - actual_content_width -
(actual_description_width / PANGO_SCALE)),
content_y, layout_);
}
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
index 2942489..cae3798 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include <map>
@@ -17,7 +18,7 @@
class AutocompleteEditModel;
class AutocompleteEditView;
-class AutocompleteMatch;
+struct AutocompleteMatch;
class AutocompletePopupModel;
class GtkThemeProvider;
class Profile;
@@ -39,6 +40,7 @@ class AutocompletePopupViewGtk : public AutocompletePopupView,
virtual void PaintUpdatesNow();
virtual void OnDragCanceled();
virtual AutocompletePopupModel* GetModel();
+ virtual int GetMaxYCoordinate();
// Overridden from NotificationObserver:
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac.h b/chrome/browser/autocomplete/autocomplete_popup_view_mac.h
index 7d1ec26..e0a27d5 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_mac.h
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_mac.h
@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_MAC_H_
#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#include <string>
-#include <map>
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
@@ -23,7 +23,6 @@ class AutocompleteEditModel;
class AutocompleteEditViewMac;
@class NSImage;
class Profile;
-class SkBitmap;
// Implements AutocompletePopupView using a raw NSWindow containing an
// NSTableView.
@@ -63,6 +62,9 @@ class AutocompletePopupViewMac : public AutocompletePopupView {
}
virtual void UpdatePopupAppearance();
+ // Set |line| to be selected.
+ void SetSelectedLine(size_t line);
+
// This is only called by model in SetSelectedLine() after updating
// everything. Popup should already be visible.
virtual void PaintUpdatesNow();
@@ -72,6 +74,8 @@ class AutocompletePopupViewMac : public AutocompletePopupView {
// Returns the popup's model.
virtual AutocompletePopupModel* GetModel();
+ virtual int GetMaxYCoordinate();
+
// Opens the URL corresponding to the given |row|. If |force_background| is
// true, forces the URL to open in a background tab. Otherwise, determines
// the proper window open disposition from the modifier flags on |[NSApp
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm b/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm
index 16105ad..c1efe82 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm
@@ -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 <cmath>
+
#include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h"
#include "app/resource_bundle.h"
@@ -26,7 +28,7 @@ const int kEditFontAdjust = -1;
// How much to adjust the cell sizing up from the default determined
// by the font.
-const int kCellHeightAdjust = 7.0;
+const int kCellHeightAdjust = 6.0;
// How to round off the popup's corners. Goal is to match star and go
// buttons.
@@ -40,17 +42,14 @@ const CGFloat kPopupFieldGap = 2.0;
const CGFloat kPopupAlpha = 240.0 / 255.0;
// How far to offset image column from the left.
-const CGFloat kImageXOffset = 2.0;
+const CGFloat kImageXOffset = 4.0;
// How far to offset the text column from the left.
-const CGFloat kTextXOffset = 25.0;
+const CGFloat kTextXOffset = 27.0;
// Animation duration when animating the popup window smaller.
const NSTimeInterval kShrinkAnimationDuration = 0.1;
-// A very short animation duration used to cancel running animations.
-const NSTimeInterval kCancelAnimationDuration = 0.00001;
-
// Maximum fraction of the popup width that can be used to display match
// contents.
const float kMaxContentsFraction = 0.7;
@@ -68,11 +67,6 @@ const CGFloat kFieldVisualInset = 1.0;
// borders.
const CGFloat kWindowBorderWidth = 1.0;
-// |AutocompleteButtonCell| and |AutocompleteTextFieldCell| draw their
-// text somewhat differently. The image needs to be adjusted slightly
-// downward to align with the text the same.
-const CGFloat kImageBaselineAdjust = 1.0;
-
// Background colors for different states of the popup elements.
NSColor* BackgroundColor() {
return [[NSColor controlBackgroundColor] colorWithAlphaComponent:kPopupAlpha];
@@ -109,7 +103,7 @@ NSMutableAttributedString* AutocompletePopupViewMac::DecorateMatchedString(
// Start out with a string using the default style info.
NSString* s = base::SysWideToNSString(matchString);
NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- font.nativeFont(), NSFontAttributeName,
+ font.GetNativeFont(), NSFontAttributeName,
textColor, NSForegroundColorAttributeName,
nil];
NSMutableAttributedString* as =
@@ -134,7 +128,7 @@ NSMutableAttributedString* AutocompletePopupViewMac::DecorateMatchedString(
if (0 != (i->style & ACMatchClassification::MATCH)) {
if (!boldFont) {
NSFontManager* fontManager = [NSFontManager sharedFontManager];
- boldFont = [fontManager convertFont:font.nativeFont()
+ boldFont = [fontManager convertFont:font.GetNativeFont()
toHaveTrait:NSBoldFontMask];
}
[as addAttribute:NSFontAttributeName value:boldFont range:range];
@@ -203,7 +197,7 @@ NSAttributedString* AutocompletePopupViewMac::MatchText(
NSDictionary* attributes =
[NSDictionary dictionaryWithObjectsAndKeys:
- font.nativeFont(), NSFontAttributeName,
+ font.GetNativeFont(), NSFontAttributeName,
ContentTextColor(), NSForegroundColorAttributeName,
nil];
NSString* rawEnDash = [NSString stringWithFormat:@" %C ", 0x2013];
@@ -344,16 +338,35 @@ void AutocompletePopupViewMac::PositionPopup(const CGFloat matrixHeight) {
// Otherwise, resize immediately.
bool animate = (NSHeight(popupFrame) < NSHeight(currentPopupFrame) &&
NSWidth(popupFrame) == NSWidth(currentPopupFrame));
- NSTimeInterval duration =
- (animate ? kShrinkAnimationDuration: kCancelAnimationDuration);
+
+ NSDictionary* savedAnimations = nil;
+ if (!animate) {
+ // In an ideal world, running a zero-length animation would cancel any
+ // running animations and set the new frame value immediately. In practice,
+ // zero-length animations are ignored entirely. Work around this AppKit bug
+ // by explicitly setting an NSNull animation for the "frame" key and then
+ // running the animation with a non-zero(!!) duration. This somehow
+ // convinces AppKit to do the right thing. Save off the current animations
+ // dictionary so it can be restored later.
+ savedAnimations = [[popup_ animations] copy];
+ [popup_ setAnimations:
+ [NSDictionary dictionaryWithObjectsAndKeys:[NSNull null],
+ @"frame", nil]];
+ }
[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];
+ [[NSAnimationContext currentContext] setDuration:kShrinkAnimationDuration];
[[popup_ animator] setFrame:popupFrame display:YES];
[NSAnimationContext endGrouping];
+ if (!animate) {
+ // Restore the original animations dictionary. This does not reinstate any
+ // previously running animations.
+ [popup_ setAnimations:savedAnimations];
+ }
+
if (!IsOpen())
[[field_ window] addChildWindow:popup_ ordered:NSWindowAbove];
}
@@ -392,8 +405,8 @@ void AutocompletePopupViewMac::UpdatePopupAppearance() {
// The popup's font is a slightly smaller version of the field's.
NSFont* fieldFont = AutocompleteEditViewMac::GetFieldFont();
const CGFloat resultFontSize = [fieldFont pointSize] + kEditFontAdjust;
- gfx::Font resultFont = gfx::Font::CreateFont(
- base::SysNSStringToWide([fieldFont fontName]), (int)resultFontSize);
+ gfx::Font resultFont(base::SysNSStringToWide([fieldFont fontName]),
+ static_cast<int>(resultFontSize));
AutocompleteMatrix* matrix = [popup_ contentView];
@@ -435,6 +448,10 @@ void AutocompletePopupViewMac::UpdatePopupAppearance() {
PositionPopup(rows * cellHeight);
}
+void AutocompletePopupViewMac::SetSelectedLine(size_t line) {
+ model_->SetSelectedLine(line, false);
+}
+
// This is only called by model in SetSelectedLine() after updating
// everything. Popup should already be visible.
void AutocompletePopupViewMac::PaintUpdatesNow() {
@@ -446,6 +463,12 @@ AutocompletePopupModel* AutocompletePopupViewMac::GetModel() {
return model_.get();
}
+int AutocompletePopupViewMac::GetMaxYCoordinate() {
+ // TODO: implement if match preview pans out.
+ NOTIMPLEMENTED();
+ return 0;
+}
+
void AutocompletePopupViewMac::OpenURLForRow(int row, bool force_background) {
DCHECK_GE(row, 0);
@@ -503,8 +526,8 @@ void AutocompletePopupViewMac::OpenURLForRow(int row, bool force_background) {
if (image) {
NSRect imageRect = cellFrame;
imageRect.size = [image size];
- imageRect.origin.y += kImageBaselineAdjust +
- floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2);
+ imageRect.origin.y +=
+ std::floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
imageRect.origin.x += kImageXOffset;
[image drawInRect:imageRect
fromRect:NSZeroRect // Entire image
@@ -515,7 +538,7 @@ void AutocompletePopupViewMac::OpenURLForRow(int row, bool force_background) {
// Adjust the title position to be lined up under the field's text.
NSAttributedString* title = [self attributedTitle];
- if (title) {
+ if (title && [title length]) {
NSRect titleRect = cellFrame;
titleRect.size.width -= kTextXOffset;
titleRect.origin.x += kTextXOffset;
@@ -654,7 +677,8 @@ void AutocompletePopupViewMac::OpenURLForRow(int row, bool force_background) {
NSInteger row, column;
if ([self getRow:&row column:&column forPoint:point]) {
DCHECK_EQ(column, 0);
- [self selectCellAtRow:row column:column];
+ DCHECK(popupView_);
+ popupView_->SetSelectedLine(row);
return YES;
}
return NO;
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac_unittest.mm b/chrome/browser/autocomplete/autocomplete_popup_view_mac_unittest.mm
index a715248..b6be8dc 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_mac_unittest.mm
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_mac_unittest.mm
@@ -24,7 +24,7 @@ class AutocompletePopupViewMacTest : public PlatformTest {
// These are here because there is no autorelease pool for the
// constructor.
color_ = [NSColor blackColor];
- font_ = gfx::Font::CreateFont(
+ font_ = gfx::Font(
base::SysNSStringToWide([[NSFont userFontOfSize:12] fontName]), 12);
}
@@ -427,7 +427,7 @@ TEST_F(AutocompletePopupViewMacTest, ElideString) {
const float kNarrow = 20.0;
NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:font_.nativeFont()
+ [NSDictionary dictionaryWithObject:font_.GetNativeFont()
forKey:NSFontAttributeName];
scoped_nsobject<NSMutableAttributedString> as(
[[NSMutableAttributedString alloc] initWithString:contents
@@ -476,7 +476,7 @@ TEST_F(AutocompletePopupViewMacTest, MatchTextElide) {
// Figure out the width of the contents.
NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:font_.nativeFont()
+ [NSDictionary dictionaryWithObject:font_.GetNativeFont()
forKey:NSFontAttributeName];
const float contentsWidth = [contents sizeWithAttributes:attributes].width;
diff --git a/chrome/browser/autocomplete/autocomplete_unittest.cc b/chrome/browser/autocomplete/autocomplete_unittest.cc
index 42963df..18abfb5 100644
--- a/chrome/browser/autocomplete/autocomplete_unittest.cc
+++ b/chrome/browser/autocomplete/autocomplete_unittest.cc
@@ -4,9 +4,11 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -77,7 +79,7 @@ void TestProvider::AddResults(int start_at, int num) {
AutocompleteMatch match(this, relevance_ - i, false,
AutocompleteMatch::URL_WHAT_YOU_TYPED);
- match.fill_into_edit = prefix_ + IntToWString(i);
+ match.fill_into_edit = prefix_ + UTF8ToWide(base::IntToString(i));
match.destination_url = GURL(WideToUTF8(match.fill_into_edit));
match.contents = match.fill_into_edit;
@@ -122,9 +124,6 @@ class AutocompleteProviderTest : public testing::Test,
void AutocompleteProviderTest::SetUp() {
registrar_.Add(this, NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED,
NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED,
- NotificationService::AllSources());
ResetController(false);
}
@@ -218,9 +217,9 @@ TEST(AutocompleteTest, InputType) {
{ L"foo.com", AutocompleteInput::URL },
{ L"-.com", AutocompleteInput::UNKNOWN },
{ L"foo/bar", AutocompleteInput::URL },
+ { L"foo;bar", AutocompleteInput::QUERY },
{ L"foo/bar baz", AutocompleteInput::UNKNOWN },
{ L"foo bar.com", AutocompleteInput::QUERY },
- { L"http://foo/bar baz", AutocompleteInput::URL },
{ L"foo bar", AutocompleteInput::QUERY },
{ L"foo+bar", AutocompleteInput::QUERY },
{ L"foo+bar.com", AutocompleteInput::UNKNOWN },
@@ -230,10 +229,14 @@ TEST(AutocompleteTest, InputType) {
{ 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"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"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
@@ -251,17 +254,21 @@ TEST(AutocompleteTest, InputType) {
{ L"http://foo.c", AutocompleteInput::URL },
{ L"http://foo.com", AutocompleteInput::URL },
{ L"http://foo_bar.com", AutocompleteInput::URL },
+ { L"http://foo/bar baz", AutocompleteInput::URL },
{ L"http://-.com", AutocompleteInput::UNKNOWN },
{ L"http://_foo_.com", AutocompleteInput::UNKNOWN },
{ L"http://foo.com:abc", AutocompleteInput::QUERY },
{ L"http://foo.com:123456", AutocompleteInput::QUERY },
+ { L"http://1.2.3.4:abc", AutocompleteInput::QUERY },
{ L"http:user@foo.com", AutocompleteInput::URL },
{ L"http://user@foo.com", AutocompleteInput::URL },
+ { L"http:user:pass@foo.com", AutocompleteInput::URL },
{ L"http://user:pass@foo.com", AutocompleteInput::URL },
{ L"http://1.2", AutocompleteInput::URL },
{ L"http://1.2/45", AutocompleteInput::URL },
{ L"http:ps/2 games", AutocompleteInput::URL },
{ L"http://ps/2 games", AutocompleteInput::URL },
+ { L"https://foo.com", AutocompleteInput::URL },
{ L"127.0.0.1", AutocompleteInput::URL },
{ L"127.0.1", AutocompleteInput::UNKNOWN },
{ L"127.0.1/", AutocompleteInput::UNKNOWN },
diff --git a/chrome/browser/autocomplete/history_contents_provider.cc b/chrome/browser/autocomplete/history_contents_provider.cc
index 947f0be..911f429 100644
--- a/chrome/browser/autocomplete/history_contents_provider.cc
+++ b/chrome/browser/autocomplete/history_contents_provider.cc
@@ -7,6 +7,7 @@
#include "base/callback.h"
#include "base/histogram.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/history/query_parser.h"
@@ -49,6 +50,18 @@ bool CompareMatchRelevance(const MatchReference& a, const MatchReference& b) {
using history::HistoryDatabase;
+HistoryContentsProvider::HistoryContentsProvider(ACProviderListener* listener,
+ Profile* profile)
+ : AutocompleteProvider(listener, profile, "HistoryContents"),
+ star_title_count_(0),
+ star_contents_count_(0),
+ title_count_(0),
+ contents_count_(0),
+ input_type_(AutocompleteInput::INVALID),
+ trim_http_(false),
+ have_results_(false) {
+}
+
void HistoryContentsProvider::Start(const AutocompleteInput& input,
bool minimal_changes) {
matches_.clear();
@@ -137,6 +150,9 @@ void HistoryContentsProvider::Stop() {
have_results_ = false;
}
+HistoryContentsProvider::~HistoryContentsProvider() {
+}
+
void HistoryContentsProvider::QueryComplete(HistoryService::Handle handle,
history::QueryResults* results) {
results_.AppendResultsBySwapping(results, true);
@@ -267,8 +283,8 @@ void HistoryContentsProvider::QueryBookmarks(const AutocompleteInput& input) {
TimeTicks start_time = TimeTicks::Now();
std::vector<bookmark_utils::TitleMatch> matches;
- bookmark_model->GetBookmarksWithTitlesMatching(input.text(), kMaxMatches,
- &matches);
+ bookmark_model->GetBookmarksWithTitlesMatching(WideToUTF16Hack(input.text()),
+ kMaxMatches, &matches);
for (size_t i = 0; i < matches.size(); ++i)
AddBookmarkTitleMatchToResults(matches[i]);
UMA_HISTOGRAM_TIMES("Omnibox.QueryBookmarksTime",
@@ -278,6 +294,6 @@ void HistoryContentsProvider::QueryBookmarks(const AutocompleteInput& input) {
void HistoryContentsProvider::AddBookmarkTitleMatchToResults(
const bookmark_utils::TitleMatch& match) {
history::URLResult url_result(match.node->GetURL(), match.match_positions);
- url_result.set_title(WideToUTF16(match.node->GetTitle()));
+ url_result.set_title(match.node->GetTitle());
results_.AppendURLBySwapping(&url_result);
}
diff --git a/chrome/browser/autocomplete/history_contents_provider.h b/chrome/browser/autocomplete/history_contents_provider.h
index c2148cc..31b75ec 100644
--- a/chrome/browser/autocomplete/history_contents_provider.h
+++ b/chrome/browser/autocomplete/history_contents_provider.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_HISTORY_CONTENTS_PROVIDER_H_
#define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_CONTENTS_PROVIDER_H_
+#pragma once
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/history/history.h"
@@ -21,16 +22,7 @@ struct TitleMatch;
// This is synchronous.
class HistoryContentsProvider : public AutocompleteProvider {
public:
- HistoryContentsProvider(ACProviderListener* listener, Profile* profile)
- : AutocompleteProvider(listener, profile, "HistoryContents"),
- star_title_count_(0),
- star_contents_count_(0),
- title_count_(0),
- contents_count_(0),
- input_type_(AutocompleteInput::INVALID),
- trim_http_(false),
- have_results_(false) {
- }
+ HistoryContentsProvider(ACProviderListener* listener, Profile* profile);
// As necessary asks the history service for the relevant results. When
// done SetResults is invoked.
@@ -49,7 +41,7 @@ class HistoryContentsProvider : public AutocompleteProvider {
static const size_t kMaxMatchCount = 50;
private:
- ~HistoryContentsProvider() {}
+ ~HistoryContentsProvider();
void QueryComplete(HistoryService::Handle handle,
history::QueryResults* results);
diff --git a/chrome/browser/autocomplete/history_contents_provider_unittest.cc b/chrome/browser/autocomplete/history_contents_provider_unittest.cc
index 2fd6e23..21e91fa 100644
--- a/chrome/browser/autocomplete/history_contents_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_contents_provider_unittest.cc
@@ -1,12 +1,14 @@
-// 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/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/history_contents_provider.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history.h"
#include "chrome/test/testing_profile.h"
@@ -71,7 +73,8 @@ class HistoryContentsProviderTest : public testing::Test,
Time t = Time::Now() - TimeDelta::FromDays(arraysize(test_entries) + i);
history_service->AddPage(url, t, id_scope, i, GURL(),
- PageTransition::LINK, history::RedirectList(), false);
+ PageTransition::LINK, history::RedirectList(),
+ history::SOURCE_BROWSED, false);
history_service->SetPageTitle(url, UTF8ToUTF16(test_entries[i].title));
history_service->SetPageContents(url, UTF8ToUTF16(test_entries[i].body));
}
@@ -155,7 +158,8 @@ TEST_F(HistoryContentsProviderTest, Bookmarks) {
// Add a bookmark.
GURL bookmark_url("http://www.google.com/4");
- profile()->GetBookmarkModel()->SetURLStarred(bookmark_url, L"bar", true);
+ profile()->GetBookmarkModel()->SetURLStarred(bookmark_url,
+ ASCIIToUTF16("bar"), true);
// Ask for synchronous. This should only get the bookmark.
AutocompleteInput sync_input(L"bar", std::wstring(), true, false, true);
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index bac2d1a..9dab45d 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "base/basictypes.h"
-#include "base/command_line.h"
#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/string_util.h"
@@ -16,9 +15,8 @@
#include "chrome/browser/history/history_backend.h"
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
@@ -29,6 +27,79 @@
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
+using history::Prefix;
+using history::Prefixes;
+using history::HistoryMatch;
+using history::HistoryMatches;
+
+namespace history {
+
+// Returns true if |url| is just a host (e.g. "http://www.google.com/") and
+// not some other subpage (e.g. "http://www.google.com/foo.html").
+bool IsHostOnly(const GURL& url) {
+ DCHECK(url.is_valid());
+ return (!url.has_path() || (url.path() == "/")) && !url.has_query() &&
+ !url.has_ref();
+}
+
+// Acts like the > operator for URLInfo classes.
+bool CompareHistoryMatch(const HistoryMatch& a, const HistoryMatch& b) {
+ // A URL that has been typed at all is better than one that has never been
+ // typed. (Note "!"s on each side)
+ if (!a.url_info.typed_count() != !b.url_info.typed_count())
+ return a.url_info.typed_count() > b.url_info.typed_count();
+
+ // Innermost matches (matches after any scheme or "www.") are better than
+ // non-innermost matches.
+ if (a.innermost_match != b.innermost_match)
+ return a.innermost_match;
+
+ // URLs that have been typed more often are better.
+ if (a.url_info.typed_count() != b.url_info.typed_count())
+ return a.url_info.typed_count() > b.url_info.typed_count();
+
+ // For URLs that have each been typed once, a host (alone) is better than a
+ // page inside.
+ if (a.url_info.typed_count() == 1) {
+ const bool a_is_host_only = history::IsHostOnly(a.url_info.url());
+ if (a_is_host_only != history::IsHostOnly(b.url_info.url()))
+ return a_is_host_only;
+ }
+
+ // URLs that have been visited more often are better.
+ if (a.url_info.visit_count() != b.url_info.visit_count())
+ return a.url_info.visit_count() > b.url_info.visit_count();
+
+ // URLs that have been visited more recently are better.
+ return a.url_info.last_visit() > b.url_info.last_visit();
+}
+
+// Given the user's |input| and a |match| created from it, reduce the
+// match's URL to just a host. If this host still matches the user input,
+// return it. Returns the empty string on failure.
+GURL ConvertToHostOnly(const HistoryMatch& match, const std::wstring& input) {
+ // See if we should try to do host-only suggestions for this URL. Nonstandard
+ // schemes means there's no authority section, so suggesting the host name
+ // is useless. File URLs are standard, but host suggestion is not useful for
+ // them either.
+ const GURL& url = match.url_info.url();
+ if (!url.is_valid() || !url.IsStandard() || url.SchemeIsFile())
+ return GURL();
+
+ // Transform to a host-only match. Bail if the host no longer matches the
+ // user input (e.g. because the user typed more than just a host).
+ GURL host = url.GetWithEmptyPath();
+ if ((host.spec().length() < (match.input_location + input.length())))
+ return GURL(); // User typing is longer than this host suggestion.
+
+ const std::wstring spec = UTF8ToWide(host.spec());
+ if (spec.compare(match.input_location, input.length(), input))
+ return GURL(); // User typing is no longer a prefix.
+
+ return host;
+}
+
+} // namespace history
HistoryURLProviderParams::HistoryURLProviderParams(
const AutocompleteInput& input,
@@ -42,6 +113,13 @@ HistoryURLProviderParams::HistoryURLProviderParams(
languages(languages) {
}
+HistoryURLProvider::HistoryURLProvider(ACProviderListener* listener,
+ Profile* profile)
+ : AutocompleteProvider(listener, profile, "HistoryURL"),
+ prefixes_(GetPrefixes()),
+ params_(NULL) {
+}
+
void HistoryURLProvider::Start(const AutocompleteInput& input,
bool minimal_changes) {
// NOTE: We could try hard to do less work in the |minimal_changes| case
@@ -151,30 +229,25 @@ void HistoryURLProvider::DoAutocomplete(history::HistoryBackend* backend,
URLRowVector url_matches;
HistoryMatches history_matches;
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableInMemoryURLIndex)) {
- // TODO(rohitrao): Fetch results from the index.
- } else {
- for (Prefixes::const_iterator i(prefixes_.begin()); i != prefixes_.end();
- ++i) {
- if (params->cancel)
- return; // Canceled in the middle of a query, give up.
- // We only need kMaxMatches results in the end, but before we get there we
- // need to promote lower-quality matches that are prefixes of
- // higher-quality matches, and remove lower-quality redirects. So we ask
- // for more results than we need, of every prefix type, in hopes this will
- // give us far more than enough to work with. CullRedirects() will then
- // reduce the list to the best kMaxMatches results.
- db->AutocompleteForPrefix(WideToUTF16(i->prefix + params->input.text()),
- kMaxMatches * 2, &url_matches);
- for (URLRowVector::const_iterator j(url_matches.begin());
- j != url_matches.end(); ++j) {
- const Prefix* best_prefix = BestPrefix(j->url(), std::wstring());
- DCHECK(best_prefix != NULL);
- history_matches.push_back(HistoryMatch(*j, i->prefix.length(),
- !i->num_components,
- i->num_components >= best_prefix->num_components));
- }
+ for (Prefixes::const_iterator i(prefixes_.begin()); i != prefixes_.end();
+ ++i) {
+ if (params->cancel)
+ return; // Canceled in the middle of a query, give up.
+ // We only need kMaxMatches results in the end, but before we get there we
+ // need to promote lower-quality matches that are prefixes of
+ // higher-quality matches, and remove lower-quality redirects. So we ask
+ // for more results than we need, of every prefix type, in hopes this will
+ // give us far more than enough to work with. CullRedirects() will then
+ // reduce the list to the best kMaxMatches results.
+ db->AutocompleteForPrefix(WideToUTF16(i->prefix + params->input.text()),
+ kMaxMatches * 2, &url_matches);
+ for (URLRowVector::const_iterator j(url_matches.begin());
+ j != url_matches.end(); ++j) {
+ const Prefix* best_prefix = BestPrefix(j->url(), std::wstring());
+ DCHECK(best_prefix != NULL);
+ history_matches.push_back(HistoryMatch(*j, i->prefix.length(),
+ !i->num_components,
+ i->num_components >= best_prefix->num_components));
}
}
@@ -325,13 +398,18 @@ bool HistoryURLProvider::FixupExactSuggestion(history::URLDatabase* db,
// * ...then just before pressing "ctrl" the best match we supplied was the
// what-you-typed match, so stick with it by promoting this.
history::URLRow info;
+ MatchType type = INLINE_AUTOCOMPLETE;
if (!db->GetRowForURL(match->destination_url, &info)) {
if (input.desired_tld().empty())
return false;
GURL destination_url(URLFixerUpper::FixupURL(WideToUTF8(input.text()),
std::string()));
- if (!db->GetRowForURL(destination_url, &info))
+ if (!db->GetRowForURL(destination_url, NULL))
return false;
+
+ // If we got here, then we hit the tricky corner case. Make sure that
+ // |info| corresponds to the right URL.
+ info = history::URLRow(match->destination_url);
} else {
// We have data for this match, use it.
match->deletable = true;
@@ -339,10 +417,20 @@ bool HistoryURLProvider::FixupExactSuggestion(history::URLDatabase* db,
AutocompleteMatch::ClassifyMatchInString(input.text(),
UTF16ToWide(info.title()),
ACMatchClassification::NONE, &match->description_class);
+ if (!info.typed_count()) {
+ // If we reach here, we must be in the second pass, and we must not have
+ // promoted this match as an exact match during the first pass. That
+ // means it will have been outscored by the "search what you typed match".
+ // We need to maintain that ordering in order to not make the destination
+ // for the user's typing change depending on when they hit enter. So
+ // lower the score here enough to let the search provider continue to
+ // outscore this match.
+ type = WHAT_YOU_TYPED;
+ }
}
// Promote as an exact match.
- match->relevance = CalculateRelevance(input.type(), INLINE_AUTOCOMPLETE, 0);
+ match->relevance = CalculateRelevance(input.type(), type, 0);
// Put it on the front of the HistoryMatches for redirect culling.
EnsureMatchPresent(info, std::wstring::npos, false, matches, true);
@@ -360,7 +448,7 @@ bool HistoryURLProvider::PromoteMatchForInlineAutocomplete(
// hand, we wouldn't want to immediately start autocompleting it.
if (!match.url_info.typed_count() ||
((match.url_info.typed_count() == 1) &&
- !IsHostOnly(match.url_info.url())))
+ !history::IsHostOnly(match.url_info.url())))
return false;
params->matches.push_back(HistoryMatchToACMatch(params, match,
@@ -454,47 +542,7 @@ size_t HistoryURLProvider::TrimHttpPrefix(std::wstring* url) {
}
// static
-bool HistoryURLProvider::IsHostOnly(const GURL& url) {
- DCHECK(url.is_valid());
- return (!url.has_path() || (url.path() == "/")) && !url.has_query() &&
- !url.has_ref();
-}
-
-// static
-bool HistoryURLProvider::CompareHistoryMatch(const HistoryMatch& a,
- const HistoryMatch& b) {
- // A URL that has been typed at all is better than one that has never been
- // typed. (Note "!"s on each side)
- if (!a.url_info.typed_count() != !b.url_info.typed_count())
- return a.url_info.typed_count() > b.url_info.typed_count();
-
- // Innermost matches (matches after any scheme or "www.") are better than
- // non-innermost matches.
- if (a.innermost_match != b.innermost_match)
- return a.innermost_match;
-
- // URLs that have been typed more often are better.
- if (a.url_info.typed_count() != b.url_info.typed_count())
- return a.url_info.typed_count() > b.url_info.typed_count();
-
- // For URLs that have each been typed once, a host (alone) is better than a
- // page inside.
- if (a.url_info.typed_count() == 1) {
- const bool a_is_host_only = IsHostOnly(a.url_info.url());
- if (a_is_host_only != IsHostOnly(b.url_info.url()))
- return a_is_host_only;
- }
-
- // URLs that have been visited more often are better.
- if (a.url_info.visit_count() != b.url_info.visit_count())
- return a.url_info.visit_count() > b.url_info.visit_count();
-
- // URLs that have been visited more recently are better.
- return a.url_info.last_visit() > b.url_info.last_visit();
-}
-
-// static
-HistoryURLProvider::Prefixes HistoryURLProvider::GetPrefixes() {
+history::Prefixes HistoryURLProvider::GetPrefixes() {
// We'll complete text following these prefixes.
// NOTE: There's no requirement that these be in any particular order.
Prefixes prefixes;
@@ -526,30 +574,6 @@ int HistoryURLProvider::CalculateRelevance(AutocompleteInput::Type input_type,
}
// static
-GURL HistoryURLProvider::ConvertToHostOnly(const HistoryMatch& match,
- const std::wstring& input) {
- // See if we should try to do host-only suggestions for this URL. Nonstandard
- // schemes means there's no authority section, so suggesting the host name
- // is useless. File URLs are standard, but host suggestion is not useful for
- // them either.
- const GURL& url = match.url_info.url();
- if (!url.is_valid() || !url.IsStandard() || url.SchemeIsFile())
- return GURL();
-
- // Transform to a host-only match. Bail if the host no longer matches the
- // user input (e.g. because the user typed more than just a host).
- GURL host = url.GetWithEmptyPath();
- if ((host.spec().length() < (match.input_location + input.length())))
- return GURL(); // User typing is longer than this host suggestion.
-
- const std::wstring spec = UTF8ToWide(host.spec());
- if (spec.compare(match.input_location, input.length(), input))
- return GURL(); // User typing is no longer a prefix.
-
- return host;
-}
-
-// static
void HistoryURLProvider::PromoteOrCreateShorterSuggestion(
history::URLDatabase* db,
const HistoryURLProviderParams& params,
@@ -563,7 +587,7 @@ void HistoryURLProvider::PromoteOrCreateShorterSuggestion(
// itself be added as a match. We can add the base iff it's not "effectively
// the same" as any "what you typed" match.
const HistoryMatch& match = matches->front();
- GURL search_base = ConvertToHostOnly(match, params.input.text());
+ GURL search_base = history::ConvertToHostOnly(match, params.input.text());
bool can_add_search_base_to_matches = !have_what_you_typed_match;
if (search_base.is_empty()) {
// Search from what the user typed when we couldn't reduce the best match
@@ -576,6 +600,9 @@ void HistoryURLProvider::PromoteOrCreateShorterSuggestion(
std::string new_match = match.url_info.url().possibly_invalid_spec().
substr(0, match.input_location + params.input.text().length());
search_base = GURL(new_match);
+ // TODO(mrossetti): There is a degenerate case where the following may
+ // cause a failure: http://www/~someword/fubar.html. Diagnose.
+ // See: http://crbug.com/50101
if (search_base.is_empty())
return; // Can't construct a valid URL from which to start a search.
} else if (!can_add_search_base_to_matches) {
@@ -722,7 +749,7 @@ void HistoryURLProvider::RunAutocompletePasses(
}
}
-const HistoryURLProvider::Prefix* HistoryURLProvider::BestPrefix(
+const history::Prefix* HistoryURLProvider::BestPrefix(
const GURL& url,
const std::wstring& prefix_suffix) const {
const Prefix* best_prefix = NULL;
@@ -742,7 +769,7 @@ const HistoryURLProvider::Prefix* HistoryURLProvider::BestPrefix(
void HistoryURLProvider::SortMatches(HistoryMatches* matches) const {
// Sort by quality, best first.
- std::sort(matches->begin(), matches->end(), &CompareHistoryMatch);
+ std::sort(matches->begin(), matches->end(), &history::CompareHistoryMatch);
// Remove duplicate matches (caused by the search string appearing in one of
// the prefixes as well as after it). Consider the following scenario:
@@ -775,15 +802,11 @@ void HistoryURLProvider::SortMatches(HistoryMatches* matches) const {
}
void HistoryURLProvider::CullPoorMatches(HistoryMatches* matches) const {
- static const int kLowQualityMatchTypedLimit = 1;
- static const int kLowQualityMatchVisitLimit = 3;
- static const int kLowQualityMatchAgeLimitInDays = 3;
- Time recent_threshold =
- Time::Now() - TimeDelta::FromDays(kLowQualityMatchAgeLimitInDays);
+ Time recent_threshold = history::AutocompleteAgeThreshold();
for (HistoryMatches::iterator i(matches->begin()); i != matches->end();) {
- const history::URLRow& url_info = i->url_info;
- if ((url_info.typed_count() <= kLowQualityMatchTypedLimit) &&
- (url_info.visit_count() <= kLowQualityMatchVisitLimit) &&
+ const history::URLRow& url_info(i->url_info);
+ if ((url_info.typed_count() <= history::kLowQualityMatchTypedLimit) &&
+ (url_info.visit_count() <= history::kLowQualityMatchVisitLimit) &&
(url_info.last_visit() < recent_threshold)) {
i = matches->erase(i);
} else {
@@ -864,23 +887,24 @@ AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch(
DCHECK(match.destination_url.is_valid());
size_t inline_autocomplete_offset =
history_match.input_location + params->input.text().length();
+ std::string languages = (match_type == WHAT_YOU_TYPED) ?
+ std::string() : WideToUTF8(params->languages);
const net::FormatUrlTypes format_types = net::kFormatUrlOmitAll &
~((params->trim_http && !history_match.match_in_scheme) ?
0 : net::kFormatUrlOmitHTTP);
match.fill_into_edit =
AutocompleteInput::FormattedStringWithEquivalentMeaning(info.url(),
- net::FormatUrl(info.url(), match_type == WHAT_YOU_TYPED ?
- std::wstring() : params->languages, format_types, UnescapeRule::SPACES,
- NULL, NULL, &inline_autocomplete_offset));
+ UTF16ToWideHack(net::FormatUrl(info.url(), languages, format_types,
+ UnescapeRule::SPACES, NULL, NULL,
+ &inline_autocomplete_offset)));
if (!params->input.prevent_inline_autocomplete())
match.inline_autocomplete_offset = inline_autocomplete_offset;
DCHECK((match.inline_autocomplete_offset == std::wstring::npos) ||
(match.inline_autocomplete_offset <= match.fill_into_edit.length()));
size_t match_start = history_match.input_location;
- match.contents = net::FormatUrl(info.url(),
- match_type == WHAT_YOU_TYPED ? std::wstring() : params->languages,
- format_types, UnescapeRule::SPACES, NULL, NULL, &match_start);
+ match.contents = UTF16ToWideHack(net::FormatUrl(info.url(), languages,
+ format_types, UnescapeRule::SPACES, NULL, NULL, &match_start));
if ((match_start != std::wstring::npos) &&
(inline_autocomplete_offset != std::wstring::npos) &&
(inline_autocomplete_offset != match_start)) {
diff --git a/chrome/browser/autocomplete/history_url_provider.h b/chrome/browser/autocomplete/history_url_provider.h
index e98d777..1a6c6f0 100644
--- a/chrome/browser/autocomplete/history_url_provider.h
+++ b/chrome/browser/autocomplete/history_url_provider.h
@@ -4,21 +4,21 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_
#define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_URL_PROVIDER_H_
-
-#include <vector>
-#include <deque>
+#pragma once
#include "chrome/browser/autocomplete/autocomplete.h"
-#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/autocomplete/history_provider_util.h"
-class HistoryService;
class MessageLoop;
class Profile;
namespace history {
+
class HistoryBackend;
-} // namespace history
+class URLDatabase;
+class URLRow;
+} // namespace history
// How history autocomplete works
// ==============================
@@ -133,21 +133,16 @@ struct HistoryURLProviderParams {
// anything on destruction.
class HistoryURLProvider : public AutocompleteProvider {
public:
- HistoryURLProvider(ACProviderListener* listener, Profile* profile)
- : AutocompleteProvider(listener, profile, "HistoryURL"),
- prefixes_(GetPrefixes()),
- params_(NULL) {
- }
+ HistoryURLProvider(ACProviderListener* listener, Profile* profile);
#ifdef UNIT_TEST
HistoryURLProvider(ACProviderListener* listener,
Profile* profile,
const std::wstring& languages)
- : AutocompleteProvider(listener, profile, "History"),
- prefixes_(GetPrefixes()),
- params_(NULL),
- languages_(languages) {
- }
+ : AutocompleteProvider(listener, profile, "History"),
+ prefixes_(GetPrefixes()),
+ params_(NULL),
+ languages_(languages) {}
#endif
// no destructor (see note above)
@@ -179,69 +174,6 @@ class HistoryURLProvider : public AutocompleteProvider {
private:
~HistoryURLProvider() {}
- struct Prefix {
- Prefix(std::wstring prefix, int num_components)
- : prefix(prefix),
- num_components(num_components) { }
-
- std::wstring prefix;
-
- // The number of "components" in the prefix. The scheme is a component,
- // and the initial "www." or "ftp." is a component. So "http://foo.com"
- // and "www.bar.com" each have one component, "ftp://ftp.ftp.com" has two,
- // and "mysite.com" has none. This is used to tell whether the user's
- // input is an innermost match or not. See comments in HistoryMatch.
- int num_components;
- };
- typedef std::vector<Prefix> Prefixes;
-
- // Used for intermediate history result operations.
- struct HistoryMatch {
- // Required for STL, we don't use this directly.
- HistoryMatch()
- : url_info(),
- input_location(std::wstring::npos),
- match_in_scheme(false),
- innermost_match(true) {
- }
-
- HistoryMatch(const history::URLRow& url_info,
- size_t input_location,
- bool match_in_scheme,
- bool innermost_match)
- : url_info(url_info),
- input_location(input_location),
- match_in_scheme(match_in_scheme),
- innermost_match(innermost_match) {
- }
-
- bool operator==(const GURL& url) const {
- return url_info.url() == url;
- }
-
- history::URLRow url_info;
-
- // The offset of the user's input within the URL.
- size_t input_location;
-
- // Whether this is a match in the scheme. This determines whether we'll go
- // ahead and show a scheme on the URL even if the user didn't type one.
- // If our best match was in the scheme, not showing the scheme is both
- // confusing and, for inline autocomplete of the fill_into_edit, dangerous.
- // (If the user types "h" and we match "http://foo/", we need to inline
- // autocomplete that, not "foo/", which won't show anything at all, and
- // will mislead the user into thinking the What You Typed match is what's
- // selected.)
- bool match_in_scheme;
-
- // A match after any scheme/"www.", if the user input could match at both
- // locations. If the user types "w", an innermost match ("website.com") is
- // better than a non-innermost match ("www.google.com"). If the user types
- // "x", no scheme in our prefix list (or "www.") begins with x, so all
- // matches are, vacuously, "innermost matches".
- bool innermost_match;
- };
- typedef std::deque<HistoryMatch> HistoryMatches;
enum MatchType {
NORMAL,
@@ -267,16 +199,8 @@ class HistoryURLProvider : public AutocompleteProvider {
// return 0.
static size_t TrimHttpPrefix(std::wstring* url);
- // Returns true if |url| is just a host (e.g. "http://www.google.com/") and
- // not some other subpage (e.g. "http://www.google.com/foo.html").
- static bool IsHostOnly(const GURL& url);
-
- // Acts like the > operator for URLInfo classes.
- static bool CompareHistoryMatch(const HistoryMatch& a,
- const HistoryMatch& b);
-
// Returns the set of prefixes to use for prefixes_.
- static Prefixes GetPrefixes();
+ static history::Prefixes GetPrefixes();
// Determines the relevance for some input, given its type and which match it
// is. If |match_type| is NORMAL, |match_number| is a number
@@ -289,7 +213,7 @@ class HistoryURLProvider : public AutocompleteProvider {
// Given the user's |input| and a |match| created from it, reduce the
// match's URL to just a host. If this host still matches the user input,
// return it. Returns the empty string on failure.
- static GURL ConvertToHostOnly(const HistoryMatch& match,
+ static GURL ConvertToHostOnly(const history::HistoryMatch& match,
const std::wstring& input);
// See if a shorter version of the best match should be created, and if so
@@ -304,7 +228,7 @@ class HistoryURLProvider : public AutocompleteProvider {
const HistoryURLProviderParams& params,
bool have_what_you_typed_match,
const AutocompleteMatch& what_you_typed_match,
- HistoryMatches* matches);
+ history::HistoryMatches* matches);
// Ensures that |matches| contains an entry for |info|, which may mean adding
// a new such entry (using |input_location| and |match_in_scheme|).
@@ -316,7 +240,7 @@ class HistoryURLProvider : public AutocompleteProvider {
static void EnsureMatchPresent(const history::URLRow& info,
std::wstring::size_type input_location,
bool match_in_scheme,
- HistoryMatches* matches,
+ history::HistoryMatches* matches,
bool promote);
// Helper function that actually launches the two autocomplete passes.
@@ -329,8 +253,8 @@ class HistoryURLProvider : public AutocompleteProvider {
// |prefix_suffix| (which may be empty) is appended to every attempted
// prefix. This is useful when you need to figure out the innermost match
// for some user input in a URL.
- const Prefix* BestPrefix(const GURL& text,
- const std::wstring& prefix_suffix) const;
+ const history::Prefix* BestPrefix(const GURL& text,
+ const std::wstring& prefix_suffix) const;
// Returns a match corresponding to exactly what the user has typed.
AutocompleteMatch SuggestExactInput(const AutocompleteInput& input,
@@ -345,25 +269,25 @@ class HistoryURLProvider : public AutocompleteProvider {
bool FixupExactSuggestion(history::URLDatabase* db,
const AutocompleteInput& input,
AutocompleteMatch* match,
- HistoryMatches* matches) const;
+ history::HistoryMatches* matches) const;
// Determines if |match| is suitable for inline autocomplete, and promotes it
// if so.
bool PromoteMatchForInlineAutocomplete(HistoryURLProviderParams* params,
- const HistoryMatch& match);
+ const history::HistoryMatch& match);
// Sorts the given list of matches.
- void SortMatches(HistoryMatches* matches) const;
+ void SortMatches(history::HistoryMatches* matches) const;
// Removes results that have been rarely typed or visited, and not any time
// recently. The exact parameters for this heuristic can be found in the
// function body.
- void CullPoorMatches(HistoryMatches* matches) const;
+ void CullPoorMatches(history::HistoryMatches* matches) const;
// Removes results that redirect to each other, leaving at most |max_results|
// results.
void CullRedirects(history::HistoryBackend* backend,
- HistoryMatches* matches,
+ history::HistoryMatches* matches,
size_t max_results) const;
// Helper function for CullRedirects, this removes all but the first
@@ -374,19 +298,19 @@ class HistoryURLProvider : public AutocompleteProvider {
// input identified by |source_index|. If |source_index| or an item before
// is removed, the next item will be shifted, and this allows the caller to
// pick up on the next one when this happens.
- size_t RemoveSubsequentMatchesOf(
- HistoryMatches* matches,
- size_t source_index,
- const std::vector<GURL>& remove) const;
+ size_t RemoveSubsequentMatchesOf(history::HistoryMatches* matches,
+ size_t source_index,
+ const std::vector<GURL>& remove) const;
// Converts a line from the database into an autocomplete match for display.
- AutocompleteMatch HistoryMatchToACMatch(HistoryURLProviderParams* params,
- const HistoryMatch& history_match,
- MatchType match_type,
- size_t match_number);
+ AutocompleteMatch HistoryMatchToACMatch(
+ HistoryURLProviderParams* params,
+ const history::HistoryMatch& history_match,
+ MatchType match_type,
+ size_t match_number);
// Prefixes to try appending to user input when looking for a match.
- const Prefixes prefixes_;
+ const history::Prefixes prefixes_;
// Params for the current query. The provider should not free this directly;
// instead, it is passed as a parameter through the history backend, and the
diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc
index 845d2e7..9a42592 100644
--- a/chrome/browser/autocomplete/history_url_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_url_provider_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.
@@ -6,6 +6,7 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/history_url_provider.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history.h"
@@ -23,10 +24,7 @@ struct TestURLInfo {
std::string title;
int visit_count;
int typed_count;
-};
-
-// Contents of the test database.
-static TestURLInfo test_db[] = {
+} test_db[] = {
{"http://www.google.com/", "Google", 3, 3},
// High-quality pages should get a host synthesized as a lower-quality match.
@@ -87,6 +85,11 @@ static TestURLInfo test_db[] = {
{"http://www.\xEA\xB5\x90\xEC\x9C\xA1.kr/", "Korean", 2, 2},
{"http://spaces.com/path%20with%20spaces/foo.html", "Spaces", 2, 2},
{"http://ms/c++%20style%20guide", "Style guide", 2, 2},
+
+ // URLs for testing ctrl-enter behavior.
+ {"http://binky/", "Intranet binky", 2, 2},
+ {"http://winky/", "Intranet winky", 2, 2},
+ {"http://www.winky.com/", "Internet winky", 5, 0},
};
class HistoryURLProviderTest : public testing::Test,
@@ -174,7 +177,8 @@ void HistoryURLProviderTest::FillData() {
const GURL current_url(cur.url);
history_service_->AddPageWithDetails(current_url, UTF8ToUTF16(cur.title),
cur.visit_count, cur.typed_count,
- visit_time, false);
+ visit_time, false,
+ history::SOURCE_BROWSED);
}
}
@@ -190,7 +194,8 @@ void HistoryURLProviderTest::RunTest(const std::wstring text,
MessageLoop::current()->Run();
matches_ = autocomplete_->matches();
- ASSERT_EQ(num_results, matches_.size()) << "Input text: " << text;
+ ASSERT_EQ(num_results, matches_.size()) << "Input text: " << text
+ << "\nTLD: \"" << desired_tld << "\"";
for (size_t i = 0; i < num_results; ++i)
EXPECT_EQ(expected_urls[i], matches_[i].destination_url.spec());
}
@@ -314,7 +319,8 @@ TEST_F(HistoryURLProviderTest, CullRedirects) {
history_service_->AddPageWithDetails(GURL(redirect[i].url),
UTF8ToUTF16("Title"),
redirect[i].count, redirect[i].count,
- Time::Now(), false);
+ Time::Now(), false,
+ history::SOURCE_BROWSED);
}
// Create a B->C->A redirect chain, but set the visit counts such that they
@@ -326,7 +332,8 @@ TEST_F(HistoryURLProviderTest, CullRedirects) {
redirects_to_a.push_back(GURL(redirect[2].url));
redirects_to_a.push_back(GURL(redirect[0].url));
history_service_->AddPage(GURL(redirect[0].url), NULL, 0, GURL(),
- PageTransition::TYPED, redirects_to_a, true);
+ PageTransition::TYPED, redirects_to_a,
+ history::SOURCE_BROWSED, true);
// Because all the results are part of a redirect chain with other results,
// all but the first one (A) should be culled. We should get the default
@@ -356,6 +363,35 @@ TEST_F(HistoryURLProviderTest, WhatYouTyped) {
const std::string results_3[] = {"https://wytmatch%20foo%20bar/"};
RunTest(L"https://wytmatch foo bar", std::wstring(), false, results_3,
arraysize(results_3));
+
+ // Test the corner case where a user has fully typed a previously visited
+ // intranet address and is now hitting ctrl-enter, which completes to a
+ // previously unvisted internet domain.
+ const std::string binky_results[] = {"http://binky/"};
+ const std::string binky_com_results[] = {
+ "http://www.binky.com/",
+ "http://binky/",
+ };
+ RunTest(L"binky", std::wstring(), false, binky_results,
+ arraysize(binky_results));
+ RunTest(L"binky", L"com", false, binky_com_results,
+ arraysize(binky_com_results));
+
+ // Test the related case where a user has fully typed a previously visited
+ // intranet address and is now hitting ctrl-enter, which completes to a
+ // previously visted internet domain.
+ const std::string winky_results[] = {
+ "http://winky/",
+ "http://www.winky.com/",
+ };
+ const std::string winky_com_results[] = {
+ "http://www.winky.com/",
+ "http://winky/",
+ };
+ RunTest(L"winky", std::wstring(), false, winky_results,
+ arraysize(winky_results));
+ RunTest(L"winky", L"com", false, winky_com_results,
+ arraysize(winky_com_results));
}
TEST_F(HistoryURLProviderTest, Fixup) {
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index 1e68de5..14ab4ff 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -24,7 +24,7 @@
// otherwise.
class KeywordProvider::ScopedEndExtensionKeywordMode {
public:
- ScopedEndExtensionKeywordMode(KeywordProvider* provider)
+ explicit ScopedEndExtensionKeywordMode(KeywordProvider* provider)
: provider_(provider) { }
~ScopedEndExtensionKeywordMode() {
if (provider_)
@@ -177,6 +177,9 @@ void KeywordProvider::Start(const AutocompleteInput& input,
// front of our vector.
if (keyword_matches.front() == keyword) {
const TemplateURL* template_url(model->GetTemplateURLForKeyword(keyword));
+ // TODO(pkasting): We should probably check that if the user explicitly
+ // typed a scheme, that scheme matches the one in |template_url|.
+
if (profile_ &&
!input.synchronous_only() && template_url->IsExtensionKeyword()) {
// If this extension keyword is disabled, make sure we don't add any
@@ -339,7 +342,7 @@ int KeywordProvider::CalculateRelevance(AutocompleteInput::Type type,
AutocompleteMatch KeywordProvider::CreateAutocompleteMatch(
TemplateURLModel* model,
- const std::wstring keyword,
+ const std::wstring& keyword,
const AutocompleteInput& input,
size_t prefix_length,
const std::wstring& remaining_input,
@@ -369,9 +372,12 @@ AutocompleteMatch KeywordProvider::CreateAutocompleteMatch(
if (!remaining_input.empty() || !keyword_complete || supports_replacement)
result.fill_into_edit.push_back(L' ');
result.fill_into_edit.append(remaining_input);
- if (!input.prevent_inline_autocomplete() &&
- (keyword_complete || remaining_input.empty()))
- result.inline_autocomplete_offset = input.text().length();
+ // If we wanted to set |result.inline_autocomplete_offset| correctly, we'd
+ // need CleanUserInputKeyword() to return the amount of adjustment it's made
+ // to the user's input. Because right now inexact keyword matches can't score
+ // more highly than a "what you typed" match from one of the other providers,
+ // we just don't bother to do this, and leave inline autocompletion off.
+ result.inline_autocomplete_offset = std::wstring::npos;
// Create destination URL and popup entry content by substituting user input
// into keyword templates.
diff --git a/chrome/browser/autocomplete/keyword_provider.h b/chrome/browser/autocomplete/keyword_provider.h
index ee9de7a..2d39836 100644
--- a/chrome/browser/autocomplete/keyword_provider.h
+++ b/chrome/browser/autocomplete/keyword_provider.h
@@ -14,10 +14,12 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_KEYWORD_PROVIDER_H_
#define CHROME_BROWSER_AUTOCOMPLETE_KEYWORD_PROVIDER_H_
+#pragma once
#include <string>
#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class Profile;
@@ -46,9 +48,8 @@ class TemplateURLModel;
// action "[keyword] %s". If the user has typed a (possibly partial) keyword
// but no search terms, the suggested result is shown greyed out, with
// "<enter term(s)>" as the substituted input, and does nothing when selected.
-class KeywordProvider :
- public AutocompleteProvider,
- public NotificationObserver {
+class KeywordProvider : public AutocompleteProvider,
+ public NotificationObserver {
public:
KeywordProvider(ACProviderListener* listener, Profile* profile);
// For testing.
@@ -112,7 +113,7 @@ class KeywordProvider :
// If |relevance| is negative, calculate a relevance based on heuristics.
AutocompleteMatch CreateAutocompleteMatch(
TemplateURLModel* model,
- const std::wstring keyword,
+ const std::wstring& keyword,
const AutocompleteInput& input,
size_t prefix_length,
const std::wstring& remaining_input,
diff --git a/chrome/browser/autocomplete/keyword_provider_unittest.cc b/chrome/browser/autocomplete/keyword_provider_unittest.cc
index 0578496..5583519 100644
--- a/chrome/browser/autocomplete/keyword_provider_unittest.cc
+++ b/chrome/browser/autocomplete/keyword_provider_unittest.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.
@@ -99,14 +99,17 @@ TEST_F(KeywordProviderTest, Edit) {
{L"aaaa foo", 1, {L"aaaa foo"}},
{L"www.aaaa foo", 1, {L"aaaa foo"}},
- // Clean up keyword input properly.
+ // Clean up keyword input properly. "http" and "https" are the only
+ // allowed schemes.
{L"www", 1, {L"www "}},
{L"www.", 0, {}},
{L"www.w w", 2, {L"www w", L"weasel w"}},
{L"http://www", 1, {L"www "}},
{L"http://www.", 0, {}},
{L"ftp: blah", 0, {}},
- {L"mailto:z", 1, {L"z "}},
+ {L"mailto:z", 0, {}},
+ {L"ftp://z", 0, {}},
+ {L"https://z", 1, {L"z "}},
};
RunTest<std::wstring>(edit_cases, arraysize(edit_cases),
@@ -165,7 +168,8 @@ TEST_F(KeywordProviderTest, Description) {
{L"z foo", 1, {L"(Keyword: z)"}},
{L"a foo", 3, {L"(Keyword: aa)", L"(Keyword: ab)",
L"(Keyword: aaaa)"}},
- {L"ftp://www.www w", 1, {L"(Keyword: www)"}},
+ {L"ftp://www.www w", 0, {}},
+ {L"http://www.ab w", 1, {L"(Keyword: ab)"}},
// Keyword should be returned regardless of query input.
{L"z", 1, {L"(Keyword: z)"}},
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index 08dc01c..a13ef3e 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -5,18 +5,20 @@
#include "chrome/browser/autocomplete/search_provider.h"
#include <algorithm>
+#include <cmath>
#include "app/l10n_util.h"
#include "base/callback.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/message_loop.h"
+#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/keyword_provider.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/google_util.h"
+#include "chrome/browser/google/google_util.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/json_value_serializer.h"
@@ -52,6 +54,14 @@ void SearchProvider::Providers::Set(const TemplateURL* default_provider,
cached_keyword_provider_ = *keyword_provider;
}
+SearchProvider::SearchProvider(ACProviderListener* listener, Profile* profile)
+ : AutocompleteProvider(listener, profile, "Search"),
+ have_history_results_(false),
+ history_request_pending_(false),
+ suggest_results_pending_(0),
+ have_suggest_results_(false) {
+}
+
void SearchProvider::Start(const AutocompleteInput& input,
bool minimal_changes) {
matches_.clear();
@@ -196,6 +206,9 @@ void SearchProvider::OnURLFetchComplete(const URLFetcher* source,
listener_->OnProviderUpdate(!suggest_results->empty());
}
+SearchProvider::~SearchProvider() {
+}
+
void SearchProvider::StartOrStopHistoryQuery(bool minimal_changes) {
// For the minimal_changes case, if we finished the previous query and still
// have its results, or are allowed to keep running it, just do that, rather
@@ -268,34 +281,44 @@ bool SearchProvider::IsQuerySuitableForSuggest() const {
!profile_->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled))
return false;
- // If the input type is URL, we take extra care so that private data in URL
+ // If the input type might be a URL, we take extra care so that private data
// isn't sent to the server.
- if (input_.type() == AutocompleteInput::URL) {
- // Don't query the server for URLs that aren't http/https/ftp. Sending
- // things like file: and data: is both a waste of time and a disclosure of
- // potentially private, local data.
- if ((input_.scheme() != L"http") && (input_.scheme() != L"https") &&
- (input_.scheme() != L"ftp"))
- return false;
- // Don't leak private data in URL
- const url_parse::Parsed& parts = input_.parts();
+ // FORCED_QUERY means the user is explicitly asking us to search for this, so
+ // we assume it isn't a URL and/or there isn't private data.
+ if (input_.type() == AutocompleteInput::FORCED_QUERY)
+ return true;
+
+ // Next we check the scheme. If this is UNKNOWN/REQUESTED_URL/URL with a
+ // scheme that isn't http/https/ftp, we shouldn't send it. Sending things
+ // like file: and data: is both a waste of time and a disclosure of
+ // potentially private, local data. Other "schemes" may actually be
+ // usernames, and we don't want to send passwords. If the scheme is OK, we
+ // still need to check other cases below. If this is QUERY, then the presence
+ // of these schemes means the user explicitly typed one, and thus this is
+ // probably a URL that's being entered and happens to currently be invalid --
+ // in which case we again want to run our checks below. Other QUERY cases are
+ // less likely to be URLs and thus we assume we're OK.
+ if ((input_.scheme() != L"http") && (input_.scheme() != L"https") &&
+ (input_.scheme() != L"ftp"))
+ return (input_.type() == AutocompleteInput::QUERY);
+
+ // Don't send URLs with usernames, queries or refs. Some of these are
+ // private, and the Suggest server is unlikely to have any useful results
+ // for any of them. Also don't send URLs with ports, as we may initially
+ // think that a username + password is a host + port (and we don't want to
+ // send usernames/passwords), and even if the port really is a port, the
+ // server is once again unlikely to have and useful results.
+ const url_parse::Parsed& parts = input_.parts();
+ if (parts.username.is_nonempty() || parts.port.is_nonempty() ||
+ parts.query.is_nonempty() || parts.ref.is_nonempty())
+ return false;
- // Don't send URLs with usernames, queries or refs. Some of these are
- // private, and the Suggest server is unlikely to have any useful results
- // for any of them.
- // Password is optional and may be omitted. Checking username is
- // sufficient.
- if (parts.username.is_nonempty() || parts.query.is_nonempty() ||
- parts.ref.is_nonempty())
- return false;
- // Don't send anything for https except hostname and port number.
- // Hostname and port number are OK because they are visible when TCP
- // connection is established and the Suggest server may provide some
- // useful completed URL.
- if (input_.scheme() == L"https" && parts.path.is_nonempty())
- return false;
- }
+ // Don't send anything for https except the hostname. Hostnames are OK
+ // because they are visible when the TCP connection is established, but the
+ // specific path may reveal private information.
+ if ((input_.scheme() == L"https") && parts.path.is_nonempty())
+ return false;
return true;
}
@@ -321,7 +344,7 @@ void SearchProvider::StopSuggest() {
have_suggest_results_ = false;
}
-void SearchProvider::ScheduleHistoryQuery(TemplateURL::IDType search_id,
+void SearchProvider::ScheduleHistoryQuery(TemplateURLID search_id,
const std::wstring& text) {
DCHECK(!text.empty());
HistoryService* const history_service =
@@ -386,10 +409,11 @@ bool SearchProvider::ParseSuggestResults(Value* root_val,
ListValue* root_list = static_cast<ListValue*>(root_val);
Value* query_val;
- std::wstring query_str;
+ string16 query_str;
Value* result_val;
if ((root_list->GetSize() < 2) || !root_list->Get(0, &query_val) ||
- !query_val->GetAsString(&query_str) || (query_str != input_text) ||
+ !query_val->GetAsString(&query_str) ||
+ (query_str != WideToUTF16Hack(input_text)) ||
!root_list->Get(1, &result_val) || !result_val->IsType(Value::TYPE_LIST))
return false;
@@ -417,7 +441,7 @@ bool SearchProvider::ParseSuggestResults(Value* root_val,
DictionaryValue* dict_val = static_cast<DictionaryValue*>(optional_val);
// Parse Google Suggest specific type extension.
- static const std::wstring kGoogleSuggestType(L"google:suggesttype");
+ static const std::string kGoogleSuggestType("google:suggesttype");
if (dict_val->HasKey(kGoogleSuggestType))
dict_val->GetList(kGoogleSuggestType, &type_list);
}
@@ -426,17 +450,23 @@ bool SearchProvider::ParseSuggestResults(Value* root_val,
ListValue* result_list = static_cast<ListValue*>(result_val);
for (size_t i = 0; i < result_list->GetSize(); ++i) {
Value* suggestion_val;
- std::wstring suggestion_str;
+ string16 suggestion_str;
if (!result_list->Get(i, &suggestion_val) ||
!suggestion_val->GetAsString(&suggestion_str))
return false;
+ // Google search may return empty suggestions for weird input characters,
+ // they make no sense at all and can cause problem in our code.
+ // See http://crbug.com/56214
+ if (!suggestion_str.length())
+ continue;
+
Value* type_val;
- std::wstring type_str;
+ std::string type_str;
if (type_list && type_list->Get(i, &type_val) &&
- type_val->GetAsString(&type_str) && (type_str == L"NAVIGATION")) {
+ type_val->GetAsString(&type_str) && (type_str == "NAVIGATION")) {
Value* site_val;
- std::wstring site_name;
+ string16 site_name;
NavigationResults& navigation_results =
is_keyword ? keyword_navigation_results_ :
default_navigation_results_;
@@ -445,16 +475,18 @@ bool SearchProvider::ParseSuggestResults(Value* root_val,
site_val->IsType(Value::TYPE_STRING) &&
site_val->GetAsString(&site_name)) {
// We can't blindly trust the URL coming from the server to be valid.
- GURL result_url(URLFixerUpper::FixupURL(WideToUTF8(suggestion_str),
+ GURL result_url(URLFixerUpper::FixupURL(UTF16ToUTF8(suggestion_str),
std::string()));
- if (result_url.is_valid())
- navigation_results.push_back(NavigationResult(result_url, site_name));
+ if (result_url.is_valid()) {
+ navigation_results.push_back(NavigationResult(result_url,
+ UTF16ToWideHack(site_name)));
+ }
}
} else {
// TODO(kochi): Currently we treat a calculator result as a query, but it
// is better to have better presentation for caluculator results.
if (suggest_results->size() < kMaxMatches)
- suggest_results->push_back(suggestion_str);
+ suggest_results->push_back(UTF16ToWideHack(suggestion_str));
}
}
@@ -587,7 +619,8 @@ int SearchProvider::CalculateRelevanceForHistory(const Time& time,
// points, while the relevance of a search two weeks ago is discounted about
// 450 points.
const double elapsed_time = std::max((Time::Now() - time).InSecondsF(), 0.);
- const int score_discount = static_cast<int>(6.5 * pow(elapsed_time, 0.3));
+ const int score_discount =
+ static_cast<int>(6.5 * std::pow(elapsed_time, 0.3));
// Don't let scores go below 0. Negative relevance scores are meaningful in
// a different way.
@@ -716,7 +749,7 @@ void SearchProvider::AddMatchToMap(const std::wstring& query_string,
// NOTE: Keep this ToLower() call in sync with url_database.cc.
const std::pair<MatchMap::iterator, bool> i = map->insert(
std::pair<std::wstring, AutocompleteMatch>(
- l10n_util::ToLower(query_string), match));
+ UTF16ToWide(l10n_util::ToLower(WideToUTF16(query_string))), match));
// NOTE: We purposefully do a direct relevance comparison here instead of
// using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added
// first" rather than "items alphabetically first" when the scores are equal.
diff --git a/chrome/browser/autocomplete/search_provider.h b/chrome/browser/autocomplete/search_provider.h
index f59dc26..73b70fe 100644
--- a/chrome/browser/autocomplete/search_provider.h
+++ b/chrome/browser/autocomplete/search_provider.h
@@ -14,6 +14,7 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
#define CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
+#pragma once
#include <map>
#include <string>
@@ -24,6 +25,7 @@
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_id.h"
#include "chrome/common/net/url_fetcher.h"
class Profile;
@@ -42,13 +44,7 @@ class Value;
class SearchProvider : public AutocompleteProvider,
public URLFetcher::Delegate {
public:
- SearchProvider(ACProviderListener* listener, Profile* profile)
- : AutocompleteProvider(listener, profile, "Search"),
- have_history_results_(false),
- history_request_pending_(false),
- suggest_results_pending_(0),
- have_suggest_results_(false) {
- }
+ SearchProvider(ACProviderListener* listener, Profile* profile);
#if defined(UNIT_TEST)
static void set_query_suggest_immediately(bool value) {
@@ -76,7 +72,7 @@ class SearchProvider : public AutocompleteProvider,
static const int kKeywordProviderURLFetcherID;
private:
- ~SearchProvider() {}
+ ~SearchProvider();
// Manages the providers (TemplateURLs) used by SearchProvider. Two providers
// may be used:
@@ -184,7 +180,7 @@ class SearchProvider : public AutocompleteProvider,
// Schedules a history query requesting past searches against the engine
// whose id is |search_id| and whose text starts with |text|.
- void ScheduleHistoryQuery(TemplateURL::IDType search_id,
+ void ScheduleHistoryQuery(TemplateURLID search_id,
const std::wstring& text);
// Called back by the history system to return searches that begin with the
@@ -282,7 +278,7 @@ class SearchProvider : public AutocompleteProvider,
// corresponds to the id of the search engine and is used in the callback to
// determine whether the request corresponds to the keyword of default
// provider.
- CancelableRequestConsumerTSimple<TemplateURL::IDType>
+ CancelableRequestConsumerTSimple<TemplateURLID>
history_request_consumer_;
// Searches in the user's history that begin with the input text.
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index b013db9..5d6c816 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_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.
@@ -100,7 +100,7 @@ void SearchProviderTest::SetUp() {
default_t_url_->SetSuggestionsURL("http://defaultturl2/{searchTerms}", 0, 0);
turl_model->Add(default_t_url_);
turl_model->SetDefaultSearchProvider(default_t_url_);
- TemplateURL::IDType default_provider_id = default_t_url_->id();
+ TemplateURLID default_provider_id = default_t_url_->id();
ASSERT_NE(0, default_provider_id);
// Add url1, with search term term1_.
@@ -109,7 +109,8 @@ void SearchProviderTest::SetUp() {
term1_url_ = GURL(default_t_url_->url()->ReplaceSearchTerms(
*default_t_url_, UTF16ToWide(term1_), 0, std::wstring()));
history->AddPageWithDetails(term1_url_, string16(), 1, 1,
- base::Time::Now(), false);
+ base::Time::Now(), false,
+ history::SOURCE_BROWSED);
history->SetKeywordSearchTermsForURL(term1_url_, default_t_url_->id(),
term1_);
@@ -126,7 +127,8 @@ void SearchProviderTest::SetUp() {
keyword_url_ = GURL(keyword_t_url_->url()->ReplaceSearchTerms(
*keyword_t_url_, UTF16ToWide(keyword_term_), 0, std::wstring()));
history->AddPageWithDetails(keyword_url_, string16(), 1, 1,
- base::Time::Now(), false);
+ base::Time::Now(), false,
+ history::SOURCE_BROWSED);
history->SetKeywordSearchTermsForURL(keyword_url_, keyword_t_url_->id(),
keyword_term_);
@@ -136,7 +138,6 @@ void SearchProviderTest::SetUp() {
}
void SearchProviderTest::OnProviderUpdate(bool updated_matches) {
- SearchProvider::set_query_suggest_immediately(false);
if (quit_when_done_ && provider_->done()) {
quit_when_done_ = false;
message_loop_.Quit();
@@ -269,3 +270,30 @@ TEST_F(SearchProviderTest, QueryKeywordProvider) {
EXPECT_EQ(keyword_t_url_->keyword() + L" " + UTF16ToWide(keyword_term_),
match.fill_into_edit);
}
+
+TEST_F(SearchProviderTest, DontSendPrivateDataToSuggest) {
+ // None of the following input strings should be sent to the suggest server,
+ // because they may contain private data.
+ const char* inputs[] = {
+ "username:password",
+ "http://username:password",
+ "https://username:password",
+ "username:password@hostname",
+ "http://username:password@hostname/",
+ "file://filename",
+ "data://data",
+ "unknownscheme:anything",
+ "http://hostname/?query=q",
+ "http://hostname/path#ref",
+ "https://hostname/path",
+ };
+
+ for (size_t i = 0; i < arraysize(inputs); ++i) {
+ QueryForInput(ASCIIToUTF16(inputs[i]));
+ // Make sure the default providers suggest service was not queried.
+ ASSERT_TRUE(test_factory_.GetFetcherByID(
+ SearchProvider::kDefaultProviderURLFetcherID) == NULL);
+ // Run till the history results complete.
+ RunTillProviderDone();
+ }
+}
diff --git a/chrome/browser/autocomplete_history_manager.cc b/chrome/browser/autocomplete_history_manager.cc
index dab9363..b2c4d3c 100644
--- a/chrome/browser/autocomplete_history_manager.cc
+++ b/chrome/browser/autocomplete_history_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,9 +7,10 @@
#include <vector>
#include "base/string16.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/credit_card.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -46,19 +47,21 @@ bool IsSSN(const string16& text) {
string16 group_string = number_string.substr(3, 2);
string16 serial_string = number_string.substr(5, 4);
- int area = StringToInt(area_string);
+ int area;
+ if (!base::StringToInt(area_string, &area))
+ return false;
if (area < 1 ||
area == 666 ||
(area > 733 && area < 750) ||
area > 772)
return false;
- int group = StringToInt(group_string);
- if (group == 0)
+ int group;
+ if (!base::StringToInt(group_string, &group) || group == 0)
return false;
- int serial = StringToInt(serial_string);
- if (serial == 0)
+ int serial;
+ if (!base::StringToInt(serial_string, &serial) || serial == 0)
return false;
return true;
@@ -147,6 +150,10 @@ void AutocompleteHistoryManager::StoreFormEntriesInWebDatabase(
if (profile_->IsOffTheRecord())
return;
+ // Don't save data that was submitted through JavaScript.
+ if (!form.user_submitted)
+ return;
+
// We put the following restriction on stored FormFields:
// - non-empty name
// - non-empty value
diff --git a/chrome/browser/autocomplete_history_manager.h b/chrome/browser/autocomplete_history_manager.h
index 4e87bd6..23493b3 100644
--- a/chrome/browser/autocomplete_history_manager.h
+++ b/chrome/browser/autocomplete_history_manager.h
@@ -4,8 +4,9 @@
#ifndef CHROME_BROWSER_AUTOCOMPLETE_HISTORY_MANAGER_H_
#define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_MANAGER_H_
+#pragma once
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/webdata/web_data_service.h"
diff --git a/chrome/browser/autocomplete_history_manager_unittest.cc b/chrome/browser/autocomplete_history_manager_unittest.cc
index 3ff2696..f60ccce 100644
--- a/chrome/browser/autocomplete_history_manager_unittest.cc
+++ b/chrome/browser/autocomplete_history_manager_unittest.cc
@@ -7,6 +7,7 @@
#include "base/ref_counted.h"
#include "base/string16.h"
#include "base/task.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete_history_manager.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/test/testing_profile.h"
@@ -50,6 +51,7 @@ TEST_F(AutocompleteHistoryManagerTest, CreditCardNumberValue) {
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
+ form.user_submitted = true;
// Valid Visa credit card number pulled from the paypal help site.
webkit_glue::FormField valid_cc(ASCIIToUTF16("Credit Card"),
@@ -72,6 +74,7 @@ TEST_F(AutocompleteHistoryManagerTest, NonCreditCardNumberValue) {
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
+ form.user_submitted = true;
// Invalid credit card number.
webkit_glue::FormField invalid_cc(ASCIIToUTF16("Credit Card"),
@@ -92,6 +95,7 @@ TEST_F(AutocompleteHistoryManagerTest, SSNValue) {
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
+ form.user_submitted = true;
webkit_glue::FormField ssn(ASCIIToUTF16("Social Security Number"),
ASCIIToUTF16("ssn"),
diff --git a/chrome/browser/autofill/address.h b/chrome/browser/autofill/address.h
index 80ba9fb..1f826ee 100644
--- a/chrome/browser/autofill/address.h
+++ b/chrome/browser/autofill/address.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_ADDRESS_H_
#define CHROME_BROWSER_AUTOFILL_ADDRESS_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/address_field.cc b/chrome/browser/autofill/address_field.cc
index 8ffb656..52e5193 100644
--- a/chrome/browser/autofill/address_field.cc
+++ b/chrome/browser/autofill/address_field.cc
@@ -8,6 +8,7 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
bool AddressField::GetFieldInfo(FieldTypeMap* field_type_map) const {
@@ -201,7 +202,7 @@ bool AddressField::ParseAddressLines(
return false;
} else {
pattern =
- ASCIIToUTF16("street|address line|address1|street_line1|addr1");
+ ASCIIToUTF16("address.?line|address1|addr1|street");
string16 label_pattern = ASCIIToUTF16("address");
if (!ParseText(iter, pattern, &address_field->address1_))
@@ -209,12 +210,6 @@ bool AddressField::ParseAddressLines(
return false;
}
- // Some pages (e.g. expedia_checkout.html) have an apartment or
- // suite number at this point. The occasional page (e.g.
- // Ticketmaster3.html) calls this a unit number. We ignore this
- // field since we can't fill it yet.
- ParseText(iter, ASCIIToUTF16("suite|unit"));
-
// Optionally parse more address lines, which may have empty labels.
// Some pages have 3 address lines (eg SharperImageModifyAccount.html)
// Some pages even have 4 address lines (e.g. uk/ShoesDirect2.html)!
@@ -224,7 +219,7 @@ bool AddressField::ParseAddressLines(
if (!ParseEmptyText(iter, &address_field->address2_))
ParseText(iter, pattern, &address_field->address2_);
} else {
- pattern = ASCIIToUTF16("address2|street|street_line2|addr2");
+ pattern = ASCIIToUTF16("address.?line2|address2|addr2|street|suite|unit");
string16 label_pattern = ASCIIToUTF16("address");
if (!ParseEmptyText(iter, &address_field->address2_))
if (!ParseText(iter, pattern, &address_field->address2_))
@@ -238,8 +233,9 @@ bool AddressField::ParseAddressLines(
kEcmlBillToAddress3, '|');
ParseText(iter, pattern);
} else {
- pattern = ASCIIToUTF16("line3");
- ParseLabelText(iter, pattern, NULL);
+ pattern = ASCIIToUTF16("address.?line3|address3|addr3|street|line3");
+ if (!ParseEmptyText(iter, NULL))
+ ParseText(iter, pattern, NULL);
}
}
diff --git a/chrome/browser/autofill/address_field.h b/chrome/browser/autofill/address_field.h
index 7629b45..6b93ead 100644
--- a/chrome/browser/autofill/address_field.h
+++ b/chrome/browser/autofill/address_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_ADDRESS_FIELD_H_
#define CHROME_BROWSER_AUTOFILL_ADDRESS_FIELD_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/address_field_unittest.cc b/chrome/browser/autofill/address_field_unittest.cc
index 2778ee3..5477b11 100644
--- a/chrome/browser/autofill/address_field_unittest.cc
+++ b/chrome/browser/autofill/address_field_unittest.cc
@@ -4,6 +4,7 @@
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/address_field.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
@@ -408,11 +409,9 @@ TEST_F(AddressFieldTest, ParseTwoLineAddressMissingLabel) {
ASSERT_TRUE(
field_type_map_.find(ASCIIToUTF16("addr1")) != field_type_map_.end());
EXPECT_EQ(ADDRESS_HOME_LINE1, field_type_map_[ASCIIToUTF16("addr1")]);
- ASSERT_FALSE(
+ ASSERT_TRUE(
field_type_map_.find(ASCIIToUTF16("addr2")) != field_type_map_.end());
- // The second line of the address should not match if |name| is set but
- // |label| is empty.
- EXPECT_NE(ADDRESS_HOME_LINE2, field_type_map_[ASCIIToUTF16("addr2")]);
+ EXPECT_EQ(ADDRESS_HOME_LINE2, field_type_map_[ASCIIToUTF16("addr2")]);
}
TEST_F(AddressFieldTest, ParseCompany) {
diff --git a/chrome/browser/autofill/auto_fill_editor_gtk.cc b/chrome/browser/autofill/auto_fill_editor_gtk.cc
index dda15c9..09442d7 100644
--- a/chrome/browser/autofill/auto_fill_editor_gtk.cc
+++ b/chrome/browser/autofill/auto_fill_editor_gtk.cc
@@ -13,6 +13,7 @@
#include "base/string_util.h"
#include "base/task.h"
#include "base/time.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/autofill/phone_number.h"
@@ -136,6 +137,17 @@ GtkWidget* TableBuilder::AddWidget(GtkWidget* widget, int col_span) {
return widget;
}
+// Returns true if the text contained in the entry |widget| is non-empty and
+// parses as a valid phone number.
+bool IsValidPhoneNumber(GtkWidget* widget) {
+ string16 text(GetEntryText(widget));
+ if (text.empty())
+ return true;
+
+ string16 number, city_code, country_code;
+ return PhoneNumber::ParsePhoneNumber(text, &number, &city_code,&country_code);
+}
+
// AutoFillProfileEditor -------------------------------------------------------
// Class responsible for editing or creating an AutoFillProfile.
@@ -148,10 +160,13 @@ class AutoFillProfileEditor {
private:
friend class DeleteTask<AutoFillProfileEditor>;
- ~AutoFillProfileEditor() {}
+ virtual ~AutoFillProfileEditor() {}
void Init();
+ // Registers for the text changed on all our text fields.
+ void RegisterForTextChanged();
+
// Sets the values of the various widgets to |profile|.
void SetWidgetValues(AutoFillProfile* profile);
@@ -172,10 +187,14 @@ class AutoFillProfileEditor {
// when not empty.
void SetPhoneSizeRequest(GtkWidget* widget);
+ // Updates the enabled state of the ok button.
+ void UpdateOkButton();
+
CHROMEGTK_CALLBACK_0(AutoFillProfileEditor, void, OnDestroy);
CHROMEG_CALLBACK_1(AutoFillProfileEditor, void, OnResponse, GtkDialog*, gint);
CHROMEG_CALLBACK_0(AutoFillProfileEditor, void, OnPhoneChanged, GtkEditable*);
CHROMEG_CALLBACK_0(AutoFillProfileEditor, void, OnFaxChanged, GtkEditable*);
+ CHROMEG_CALLBACK_0(AutoFillProfileEditor, void, OnFieldChanged, GtkEditable*);
// Are we creating a new profile?
const bool is_new_;
@@ -202,6 +221,7 @@ class AutoFillProfileEditor {
GtkWidget* fax_;
GtkWidget* fax_image_;
GtkWidget* email_;
+ GtkWidget* ok_button_;
DISALLOW_COPY_AND_ASSIGN(AutoFillProfileEditor);
};
@@ -219,6 +239,10 @@ AutoFillProfileEditor::AutoFillProfileEditor(
if (auto_fill_profile)
SetWidgetValues(auto_fill_profile);
+ RegisterForTextChanged();
+
+ UpdateOkButton();
+
gtk_util::ShowDialogWithLocalizedSize(
dialog_,
IDS_AUTOFILL_DIALOG_EDIT_ADDRESS_WIDTH_CHARS,
@@ -300,12 +324,16 @@ void AutoFillProfileEditor::Init() {
l10n_util::GetStringUTF8(caption_id).c_str(),
NULL,
static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
- GTK_STOCK_APPLY,
- GTK_RESPONSE_APPLY,
- GTK_STOCK_CANCEL,
- GTK_RESPONSE_CANCEL,
NULL);
+ ok_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_),
+ GTK_STOCK_APPLY,
+ GTK_RESPONSE_APPLY);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_APPLY);
+
+ gtk_dialog_add_button(GTK_DIALOG(dialog_), GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+
g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this);
@@ -313,6 +341,24 @@ void AutoFillProfileEditor::Init() {
main_table_builder.table(), TRUE, TRUE, 0);
}
+void AutoFillProfileEditor::RegisterForTextChanged() {
+ g_signal_connect(full_name_, "changed", G_CALLBACK(OnFieldChangedThunk),
+ this);
+ g_signal_connect(company_, "changed", G_CALLBACK(OnFieldChangedThunk),
+ this);
+ g_signal_connect(address_1_, "changed", G_CALLBACK(OnFieldChangedThunk),
+ this);
+ g_signal_connect(address_2_, "changed", G_CALLBACK(OnFieldChangedThunk),
+ this);
+ g_signal_connect(city_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(state_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(zip_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(country_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(email_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(phone_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(fax_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+}
+
void AutoFillProfileEditor::SetWidgetValues(AutoFillProfile* profile) {
SetEntryText(full_name_, profile, NAME_FULL);
SetEntryText(company_, profile, COMPANY_NAME);
@@ -418,6 +464,29 @@ void AutoFillProfileEditor::SetPhoneSizeRequest(GtkWidget* widget) {
gdk_pixbuf_get_height(buf));
}
+void AutoFillProfileEditor::UpdateOkButton() {
+ // Enable the ok button if at least one field is non-empty and the phone
+ // numbers are valid.
+ bool valid =
+ !GetEntryText(full_name_).empty() ||
+ !GetEntryText(company_).empty() ||
+ !GetEntryText(address_1_).empty() ||
+ !GetEntryText(address_2_).empty() ||
+ !GetEntryText(city_).empty() ||
+ !GetEntryText(state_).empty() ||
+ !GetEntryText(zip_).empty() ||
+ !GetEntryText(country_).empty() ||
+ !GetEntryText(email_).empty();
+ if (valid) {
+ valid = IsValidPhoneNumber(phone_) && IsValidPhoneNumber(fax_);
+ } else {
+ valid = IsValidPhoneNumber(phone_) && IsValidPhoneNumber(fax_) &&
+ (!GetEntryText(full_name_).empty() ||
+ !GetEntryText(company_).empty());
+ }
+ gtk_widget_set_sensitive(ok_button_, valid);
+}
+
void AutoFillProfileEditor::OnDestroy(GtkWidget* widget) {
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
@@ -442,6 +511,10 @@ void AutoFillProfileEditor::OnFaxChanged(GtkEditable* editable) {
UpdatePhoneImage(fax_, fax_image_);
}
+void AutoFillProfileEditor::OnFieldChanged(GtkEditable* editable) {
+ UpdateOkButton();
+}
+
// AutoFillCreditCardEditor ----------------------------------------------------
// Number of years shown in the expiration year combobox.
@@ -468,7 +541,7 @@ class AutoFillCreditCardEditor {
COL_COUNT
};
- ~AutoFillCreditCardEditor() {}
+ virtual ~AutoFillCreditCardEditor() {}
// Creates the GtkListStore used to show the billing addresses.
GtkListStore* CreateAddressStore();
@@ -476,14 +549,17 @@ class AutoFillCreditCardEditor {
// Creates the combobox used to show the billing addresses.
GtkWidget* CreateAddressWidget();
- // Creates the combobox for chosing the month.
+ // Creates the combobox for choosing the month.
GtkWidget* CreateMonthWidget();
- // Creates the combobox for chosing the year.
+ // Creates the combobox for choosing the year.
GtkWidget* CreateYearWidget();
void Init();
+ // Registers for the text changed on all our text fields.
+ void RegisterForTextChanged();
+
// Sets the values displayed in the various widgets from |profile|.
void SetWidgetValues(CreditCard* profile);
@@ -493,9 +569,18 @@ class AutoFillCreditCardEditor {
// Updates |card| with the values from the widgets.
void SetCreditCardValuesFromWidgets(CreditCard* card);
+ // Updates the enabled state of the ok button.
+ void UpdateOkButton();
+
CHROMEGTK_CALLBACK_0(AutoFillCreditCardEditor, void, OnDestroy);
CHROMEG_CALLBACK_1(AutoFillCreditCardEditor, void, OnResponse, GtkDialog*,
gint);
+ CHROMEG_CALLBACK_0(AutoFillCreditCardEditor, void, OnFieldChanged,
+ GtkEditable*);
+ CHROMEG_CALLBACK_2(AutoFillCreditCardEditor, void, OnDeleteTextFromNumber,
+ GtkEditable*, gint, gint);
+ CHROMEG_CALLBACK_3(AutoFillCreditCardEditor, void, OnInsertTextIntoNumber,
+ GtkEditable*, gchar*, gint, gint*);
// Are we creating a new credit card?
const bool is_new_;
@@ -511,12 +596,16 @@ class AutoFillCreditCardEditor {
// Initial year shown in expiration date year combobox.
int base_year_;
+ // Has the number_ field been edited by the user yet?
+ bool edited_number_;
+
GtkWidget* dialog_;
GtkWidget* name_;
GtkWidget* address_;
GtkWidget* number_;
GtkWidget* month_;
GtkWidget* year_;
+ GtkWidget* ok_button_;
GtkListStore* address_store_;
@@ -531,7 +620,8 @@ AutoFillCreditCardEditor::AutoFillCreditCardEditor(
credit_card_id_(credit_card ? credit_card->unique_id() : 0),
observer_(observer),
profile_(profile),
- base_year_(0) {
+ base_year_(0),
+ edited_number_(false) {
base::Time::Exploded exploded_time;
base::Time::Now().LocalExplode(&exploded_time);
base_year_ = exploded_time.year;
@@ -542,7 +632,7 @@ AutoFillCreditCardEditor::AutoFillCreditCardEditor(
SetWidgetValues(credit_card);
} else {
// We're creating a new credit card. Select a default billing address (if
- // there are any) and select Januay of next year.
+ // there are any) and select January of next year.
PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
if (!data_manager->profiles().empty())
gtk_combo_box_set_active(GTK_COMBO_BOX(address_), 0);
@@ -550,6 +640,10 @@ AutoFillCreditCardEditor::AutoFillCreditCardEditor(
gtk_combo_box_set_active(GTK_COMBO_BOX(year_), 1);
}
+ RegisterForTextChanged();
+
+ UpdateOkButton();
+
gtk_util::ShowDialogWithLocalizedSize(
dialog_,
IDS_AUTOFILL_DIALOG_EDIT_CCARD_WIDTH_CHARS,
@@ -568,6 +662,20 @@ GtkListStore* AutoFillCreditCardEditor::CreateAddressStore() {
for (std::vector<AutoFillProfile*>::const_iterator i =
data_manager->profiles().begin();
i != data_manager->profiles().end(); ++i) {
+ FieldTypeSet fields;
+ (*i)->GetAvailableFieldTypes(&fields);
+ if (fields.find(ADDRESS_HOME_LINE1) == fields.end() &&
+ fields.find(ADDRESS_HOME_LINE2) == fields.end() &&
+ fields.find(ADDRESS_HOME_APT_NUM) == fields.end() &&
+ fields.find(ADDRESS_HOME_CITY) == fields.end() &&
+ fields.find(ADDRESS_HOME_STATE) == fields.end() &&
+ fields.find(ADDRESS_HOME_ZIP) == fields.end() &&
+ fields.find(ADDRESS_HOME_COUNTRY) == fields.end()) {
+ // No address information in this profile; it's useless as a billing
+ // address.
+ continue;
+ }
+
gtk_list_store_append(store, &iter);
gtk_list_store_set(
store, &iter,
@@ -648,12 +756,16 @@ void AutoFillCreditCardEditor::Init() {
l10n_util::GetStringUTF8(caption_id).c_str(),
NULL,
static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
- GTK_STOCK_APPLY,
- GTK_RESPONSE_APPLY,
- GTK_STOCK_CANCEL,
- GTK_RESPONSE_CANCEL,
NULL);
+ ok_button_ = gtk_dialog_add_button(GTK_DIALOG(dialog_),
+ GTK_STOCK_APPLY,
+ GTK_RESPONSE_APPLY);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_APPLY);
+
+ gtk_dialog_add_button(GTK_DIALOG(dialog_), GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+
g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this);
@@ -661,6 +773,15 @@ void AutoFillCreditCardEditor::Init() {
main_table_builder.table(), TRUE, TRUE, 0);
}
+void AutoFillCreditCardEditor::RegisterForTextChanged() {
+ g_signal_connect(name_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(number_, "changed", G_CALLBACK(OnFieldChangedThunk), this);
+ g_signal_connect(number_, "delete-text",
+ G_CALLBACK(OnDeleteTextFromNumberThunk), this);
+ g_signal_connect(number_, "insert-text",
+ G_CALLBACK(OnInsertTextIntoNumberThunk), this);
+}
+
void AutoFillCreditCardEditor::SetWidgetValues(CreditCard* card) {
SetEntryText(name_, card, CREDIT_CARD_NAME);
@@ -668,25 +789,29 @@ void AutoFillCreditCardEditor::SetWidgetValues(CreditCard* card) {
for (std::vector<AutoFillProfile*>::const_iterator i =
data_manager->profiles().begin();
i != data_manager->profiles().end(); ++i) {
- if ((*i)->Label() == card->billing_address()) {
+ if ((*i)->unique_id() == card->billing_address_id()) {
int index = static_cast<int>(i - data_manager->profiles().begin());
gtk_combo_box_set_active(GTK_COMBO_BOX(address_), index);
break;
}
}
- SetEntryText(number_, card, CREDIT_CARD_NUMBER);
+ gtk_entry_set_text(GTK_ENTRY(number_),
+ UTF16ToUTF8(card->ObfuscatedNumber()).c_str());
- int month = StringToInt(
- UTF16ToUTF8(card->GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH))));
+ int month;
+ base::StringToInt(card->GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH)),
+ &month);
if (month >= 1 && month <= 12) {
gtk_combo_box_set_active(GTK_COMBO_BOX(month_), month - 1);
} else {
gtk_combo_box_set_active(GTK_COMBO_BOX(month_), 0);
}
- int year = StringToInt(UTF16ToUTF8(
- card->GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR))));
+ int year;
+ base::StringToInt(
+ card->GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR)),
+ &year);
if (year >= base_year_ && year < base_year_ + kNumYears)
gtk_combo_box_set_active(GTK_COMBO_BOX(year_), year - base_year_);
else
@@ -723,7 +848,7 @@ void AutoFillCreditCardEditor::ApplyEdits() {
card = &cards.back();
}
- // Update the credit card from what the user typedi n.
+ // Update the credit card from what the user typed in.
SetCreditCardValuesFromWidgets(card);
// And update the model.
@@ -736,7 +861,7 @@ void AutoFillCreditCardEditor::SetCreditCardValuesFromWidgets(
SetFormValue(name_, card, CREDIT_CARD_NAME);
- card->set_billing_address(string16());
+ card->set_billing_address_id(0);
int selected_address_index =
gtk_combo_box_get_active(GTK_COMBO_BOX(address_));
if (selected_address_index != -1) {
@@ -751,28 +876,36 @@ void AutoFillCreditCardEditor::SetCreditCardValuesFromWidgets(
data_manager->profiles().begin();
i != data_manager->profiles().end(); ++i) {
if ((*i)->unique_id() == id) {
- card->set_billing_address((*i)->Label());
+ card->set_billing_address_id(id);
break;
}
}
g_value_unset(&value);
}
- SetFormValue(number_, card, CREDIT_CARD_NUMBER);
+ if (edited_number_)
+ SetFormValue(number_, card, CREDIT_CARD_NUMBER);
int selected_month_index =
gtk_combo_box_get_active(GTK_COMBO_BOX(month_));
if (selected_month_index == -1)
selected_month_index = 0;
card->SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
- IntToString16(selected_month_index + 1));
+ base::IntToString16(selected_month_index + 1));
int selected_year_index =
gtk_combo_box_get_active(GTK_COMBO_BOX(year_));
if (selected_year_index == -1)
selected_year_index = 0;
card->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
- IntToString16(selected_year_index + base_year_));
+ base::IntToString16(selected_year_index + base_year_));
+}
+
+void AutoFillCreditCardEditor::UpdateOkButton() {
+ // Enable the ok button if at least one field is non-empty and the phone
+ // numbers are valid.
+ bool valid = !GetEntryText(name_).empty() || !GetEntryText(number_).empty();
+ gtk_widget_set_sensitive(ok_button_, valid);
}
void AutoFillCreditCardEditor::OnDestroy(GtkWidget* widget) {
@@ -791,6 +924,47 @@ void AutoFillCreditCardEditor::OnResponse(GtkDialog* dialog, gint response_id) {
}
}
+void AutoFillCreditCardEditor::OnFieldChanged(GtkEditable* editable) {
+ if (editable == GTK_EDITABLE(number_))
+ edited_number_ = true;
+ UpdateOkButton();
+}
+
+void AutoFillCreditCardEditor::OnDeleteTextFromNumber(GtkEditable* editable,
+ gint start,
+ gint end) {
+ if (!edited_number_) {
+ // The user hasn't deleted any text yet, so delete it all.
+ edited_number_ = true;
+ g_signal_stop_emission_by_name(editable, "delete-text");
+ gtk_entry_set_text(GTK_ENTRY(number_), "");
+ }
+}
+
+void AutoFillCreditCardEditor::OnInsertTextIntoNumber(GtkEditable* editable,
+ gchar* new_text,
+ gint new_text_length,
+ gint* position) {
+ if (!edited_number_) {
+ // This is the first edit to the number. If |editable| is not empty, reset
+ // the text so that any obfuscated text is removed.
+ edited_number_ = true;
+
+ if (GetEntryText(GTK_WIDGET(editable)).empty())
+ return;
+
+ g_signal_stop_emission_by_name(editable, "insert-text");
+
+ if (new_text_length < 0)
+ new_text_length = strlen(new_text);
+ gtk_entry_set_text(GTK_ENTRY(number_),
+ std::string(new_text, new_text_length).c_str());
+
+ // Sets the cursor after the last character in |editable|.
+ gtk_editable_set_position(editable, -1);
+ }
+}
+
} // namespace
void ShowAutoFillProfileEditor(gfx::NativeView parent,
diff --git a/chrome/browser/autofill/autofill_address_model_mac.h b/chrome/browser/autofill/autofill_address_model_mac.h
index b84408f..230db90 100644
--- a/chrome/browser/autofill/autofill_address_model_mac.h
+++ b/chrome/browser/autofill/autofill_address_model_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_MODEL_MAC_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_MODEL_MAC_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/autofill/autofill_address_model_mac_unittest.mm b/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
index ca517b0..adab6aa 100644
--- a/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
#import "chrome/browser/autofill/autofill_address_model_mac.h"
#include "chrome/browser/autofill/autofill_common_unittest.h"
#include "chrome/browser/autofill/autofill_profile.h"
diff --git a/chrome/browser/autofill/autofill_address_sheet_controller_mac.h b/chrome/browser/autofill/autofill_address_sheet_controller_mac.h
index 963d4ff..0df6016 100644
--- a/chrome/browser/autofill/autofill_address_sheet_controller_mac.h
+++ b/chrome/browser/autofill/autofill_address_sheet_controller_mac.h
@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_SHEET_CONTROLLER_MAC_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_SHEET_CONTROLLER_MAC_
+#pragma once
#import <Cocoa/Cocoa.h>
@class AutoFillAddressModel;
-@class AutoFillDialogController;
class AutoFillProfile;
// The sheet can be invoked in "Add" or "Edit" mode. This dictates the caption
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 f46425d..7c72255 100644
--- a/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/scoped_nsobject.h"
+#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"
diff --git a/chrome/browser/autofill/autofill_cc_infobar.h b/chrome/browser/autofill/autofill_cc_infobar.h
index 35aa92b..a850bad 100644
--- a/chrome/browser/autofill/autofill_cc_infobar.h
+++ b/chrome/browser/autofill/autofill_cc_infobar.h
@@ -4,9 +4,11 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_CC_INFOBAR_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_CC_INFOBAR_H_
+#pragma once
class InfoBar;
class ConfirmInfoBarDelegate;
+
InfoBar* CreateAutofillCcInfoBar(ConfirmInfoBarDelegate* delegate);
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_CC_INFOBAR_H_
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
index 36bde07..2dadc7d 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
@@ -6,10 +6,10 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/histogram.h"
#include "chrome/browser/autofill/autofill_cc_infobar.h"
#include "chrome/browser/autofill/autofill_manager.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/pref_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/tab_contents/tab_contents_delegate.h"
@@ -22,15 +22,7 @@
AutoFillCCInfoBarDelegate::AutoFillCCInfoBarDelegate(TabContents* tab_contents,
AutoFillManager* host)
: ConfirmInfoBarDelegate(tab_contents),
- browser_(NULL),
host_(host) {
- if (tab_contents) {
- // This is NULL for TestTabContents.
- if (tab_contents->delegate())
- browser_ = tab_contents->delegate()->GetBrowser();
-
- tab_contents->AddInfoBar(this);
- }
}
AutoFillCCInfoBarDelegate::~AutoFillCCInfoBarDelegate() {
@@ -49,13 +41,11 @@ void AutoFillCCInfoBarDelegate::InfoBarClosed() {
host_->OnInfoBarClosed(false);
host_ = NULL;
}
-
- // This will delete us.
- ConfirmInfoBarDelegate::InfoBarClosed();
+ delete this;
}
-std::wstring AutoFillCCInfoBarDelegate::GetMessageText() const {
- return l10n_util::GetString(IDS_AUTOFILL_CC_INFOBAR_TEXT);
+string16 AutoFillCCInfoBarDelegate::GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_INFOBAR_TEXT);
}
SkBitmap* AutoFillCCInfoBarDelegate::GetIcon() const {
@@ -67,19 +57,20 @@ int AutoFillCCInfoBarDelegate::GetButtons() const {
return BUTTON_OK | BUTTON_CANCEL;
}
-std::wstring AutoFillCCInfoBarDelegate::GetButtonLabel(
+string16 AutoFillCCInfoBarDelegate::GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const {
if (button == BUTTON_OK)
- return l10n_util::GetString(IDS_AUTOFILL_CC_INFOBAR_ACCEPT);
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_INFOBAR_ACCEPT);
else if (button == BUTTON_CANCEL)
- return l10n_util::GetString(IDS_AUTOFILL_CC_INFOBAR_DENY);
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_INFOBAR_DENY);
else
NOTREACHED();
- return std::wstring();
+ return string16();
}
bool AutoFillCCInfoBarDelegate::Accept() {
+ UMA_HISTOGRAM_COUNTS("AutoFill.CCInfoBarAccepted", 1);
if (host_) {
host_->OnInfoBarClosed(true);
host_ = NULL;
@@ -88,6 +79,7 @@ bool AutoFillCCInfoBarDelegate::Accept() {
}
bool AutoFillCCInfoBarDelegate::Cancel() {
+ UMA_HISTOGRAM_COUNTS("AutoFill.CCInfoBarDenied", 1);
if (host_) {
host_->OnInfoBarClosed(false);
host_ = NULL;
@@ -95,13 +87,13 @@ bool AutoFillCCInfoBarDelegate::Cancel() {
return true;
}
-std::wstring AutoFillCCInfoBarDelegate::GetLinkText() {
- return l10n_util::GetString(IDS_AUTOFILL_CC_LEARN_MORE);
+string16 AutoFillCCInfoBarDelegate::GetLinkText() {
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_LEARN_MORE);
}
bool AutoFillCCInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
- browser_->OpenURL(GURL(kAutoFillLearnMoreUrl), GURL(), NEW_FOREGROUND_TAB,
- PageTransition::TYPED);
+ host_->tab_contents()->OpenURL(GURL(kAutoFillLearnMoreUrl), GURL(),
+ NEW_FOREGROUND_TAB, PageTransition::TYPED);
return false;
}
@@ -111,3 +103,6 @@ InfoBar* AutoFillCCInfoBarDelegate::CreateInfoBar() {
}
#endif // defined(OS_WIN)
+InfoBarDelegate::Type AutoFillCCInfoBarDelegate::GetInfoBarType() {
+ return PAGE_ACTION_TYPE;
+}
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.h b/chrome/browser/autofill/autofill_cc_infobar_delegate.h
index 3b7a751..a02b4ca 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.h
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.h
@@ -4,13 +4,12 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_CC_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_CC_INFOBAR_DELEGATE_H_
+#pragma once
-#include <string>
-
+#include "base/string16.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
class AutoFillManager;
-class Browser;
class SkBitmap;
class TabContents;
@@ -25,14 +24,14 @@ class AutoFillCCInfoBarDelegate : public ConfirmInfoBarDelegate {
virtual bool ShouldExpire(
const NavigationController::LoadCommittedDetails& details) const;
virtual void InfoBarClosed();
- virtual std::wstring GetMessageText() const;
+ virtual string16 GetMessageText() const;
virtual SkBitmap* GetIcon() const;
virtual int GetButtons() const;
- virtual std::wstring GetButtonLabel(
+ virtual string16 GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const;
virtual bool Accept();
virtual bool Cancel();
- virtual std::wstring GetLinkText();
+ virtual string16 GetLinkText();
virtual bool LinkClicked(WindowOpenDisposition disposition);
#if defined(OS_WIN)
@@ -40,14 +39,9 @@ class AutoFillCCInfoBarDelegate : public ConfirmInfoBarDelegate {
virtual InfoBar* CreateInfoBar();
#endif // defined(OS_WIN)
- virtual Type GetInfoBarType() {
- return PAGE_ACTION_TYPE;
- }
+ virtual Type GetInfoBarType();
private:
- // The browser.
- Browser* browser_;
-
// The AutoFillManager that initiated this InfoBar.
AutoFillManager* host_;
diff --git a/chrome/browser/autofill/autofill_cc_infobar_win.cc b/chrome/browser/autofill/autofill_cc_infobar_win.cc
index f96e759..31a7c6a 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_win.cc
+++ b/chrome/browser/autofill/autofill_cc_infobar_win.cc
@@ -4,11 +4,10 @@
#include "chrome/browser/autofill/autofill_cc_infobar.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/views/event_utils.h"
-#include "chrome/browser/views/infobars/infobar_button_border.h"
#include "chrome/browser/views/infobars/infobars.h"
+#include "chrome/browser/views/infobars/infobar_text_button.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -43,15 +42,14 @@ class SaveCCInfoConfirmInfoBar : public AlertInfoBar,
private:
void Init();
- views::TextButton* CreateTextButton(const std::wstring& text);
ConfirmInfoBarDelegate* GetDelegate();
// The buttons are owned by InfoBar view from the moment they are added to its
// hierarchy (Init() called), but we still need pointers to them to process
// messages from them.
- views::TextButton* save_button_;
- views::TextButton* dont_save_button_;
+ InfoBarTextButton* save_button_;
+ InfoBarTextButton* dont_save_button_;
views::Link* link_;
bool initialized_;
@@ -62,10 +60,11 @@ SaveCCInfoConfirmInfoBar::SaveCCInfoConfirmInfoBar(
ConfirmInfoBarDelegate* delegate)
: AlertInfoBar(delegate),
initialized_(false) {
- save_button_ = CreateTextButton(delegate->GetButtonLabel(
- ConfirmInfoBarDelegate::BUTTON_OK));
- dont_save_button_ = CreateTextButton(delegate->GetButtonLabel(
- ConfirmInfoBarDelegate::BUTTON_CANCEL));
+ save_button_ = InfoBarTextButton::Create(this,
+ delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK));
+ dont_save_button_ = InfoBarTextButton::Create(this,
+ delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL));
+
// Set up the link.
link_ = new views::Link;
link_->SetText(delegate->GetLinkText());
@@ -163,27 +162,6 @@ void SaveCCInfoConfirmInfoBar::Init() {
AddChildView(link_);
}
-views::TextButton* SaveCCInfoConfirmInfoBar::CreateTextButton(
- const std::wstring& text) {
- views::TextButton* text_button = new views::TextButton(this, std::wstring());
- text_button->set_border(new InfoBarButtonBorder);
-
- // Set font colors for different states.
- text_button->SetEnabledColor(SK_ColorBLACK);
- text_button->SetHighlightColor(SK_ColorBLACK);
- text_button->SetHoverColor(SK_ColorBLACK);
- text_button->SetNormalHasBorder(true);
- text_button->SetShowHighlighted(true);
-
- // Set font then text, then size button to fit text.
- text_button->SetFont(ResourceBundle::GetSharedInstance().GetFont(
- ResourceBundle::MediumFont));
- text_button->SetText(text);
- text_button->ClearMaxTextSize();
- text_button->SizeToPreferredSize();
- return text_button;
-}
-
ConfirmInfoBarDelegate* SaveCCInfoConfirmInfoBar::GetDelegate() {
return delegate()->AsConfirmInfoBarDelegate();
}
@@ -192,4 +170,3 @@ InfoBar* CreateAutofillCcInfoBar(ConfirmInfoBarDelegate* delegate) {
DCHECK(delegate);
return new SaveCCInfoConfirmInfoBar(delegate);
}
-
diff --git a/chrome/browser/autofill/autofill_common_unittest.cc b/chrome/browser/autofill/autofill_common_unittest.cc
index b7997cc..bad2784 100644
--- a/chrome/browser/autofill/autofill_common_unittest.cc
+++ b/chrome/browser/autofill/autofill_common_unittest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/autofill/autofill_common_unittest.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "webkit/glue/form_field.h"
@@ -31,7 +32,9 @@ void SetProfileInfo(AutoFillProfile* profile,
const char* address1, const char* address2, const char* city,
const char* state, const char* zipcode, const char* country,
const char* phone, const char* fax) {
- profile->set_label(ASCIIToUTF16(label));
+ // TODO(jhawkins): Remove |label|.
+ if (label)
+ profile->set_label(ASCIIToUTF16(label));
check_and_set(profile, NAME_FIRST, first_name);
check_and_set(profile, NAME_MIDDLE, middle_name);
check_and_set(profile, NAME_LAST, last_name);
@@ -50,15 +53,14 @@ void SetProfileInfo(AutoFillProfile* profile,
void SetCreditCardInfo(CreditCard* credit_card,
const char* label, const char* name_on_card, const char* type,
const char* card_number, const char* expiration_month,
- const char* expiration_year, const char* billing_address) {
+ const char* expiration_year, int billing_address_id) {
credit_card->set_label(ASCIIToUTF16(label));
check_and_set(credit_card, CREDIT_CARD_NAME, name_on_card);
check_and_set(credit_card, CREDIT_CARD_TYPE, type);
check_and_set(credit_card, CREDIT_CARD_NUMBER, card_number);
check_and_set(credit_card, CREDIT_CARD_EXP_MONTH, expiration_month);
check_and_set(credit_card, CREDIT_CARD_EXP_4_DIGIT_YEAR, expiration_year);
- if (billing_address)
- credit_card->set_billing_address(ASCIIToUTF16(billing_address));
+ credit_card->set_billing_address_id(billing_address_id);
}
} // namespace autofill_unittest
diff --git a/chrome/browser/autofill/autofill_common_unittest.h b/chrome/browser/autofill/autofill_common_unittest.h
index fdb965f..a53bf84 100644
--- a/chrome/browser/autofill/autofill_common_unittest.h
+++ b/chrome/browser/autofill/autofill_common_unittest.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_COMMON_UNITTEST_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_COMMON_UNITTEST_H_
+#pragma once
class AutoFillProfile;
class CreditCard;
@@ -38,7 +39,7 @@ void SetProfileInfo(AutoFillProfile* profile,
void SetCreditCardInfo(CreditCard* credit_card,
const char* label, const char* name_on_card, const char* type,
const char* card_number, const char* expiration_month,
- const char* expiration_year, const char* billing_address);
+ const char* expiration_year, int billing_address_id);
} // namespace autofill_unittest
diff --git a/chrome/browser/autofill/autofill_credit_card_model_mac.h b/chrome/browser/autofill/autofill_credit_card_model_mac.h
index 3f1cb93..277ff55 100644
--- a/chrome/browser/autofill/autofill_credit_card_model_mac.h
+++ b/chrome/browser/autofill/autofill_credit_card_model_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_MODEL_MAC_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_MODEL_MAC_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -24,15 +25,14 @@ class CreditCard;
NSString* creditCardNumber_;
NSString* expirationMonth_;
NSString* expirationYear_;
- NSString* billingAddress_;
- NSString* shippingAddress_;
+ NSInteger billingAddressID_;
}
@property (nonatomic, copy) NSString* nameOnCard;
@property (nonatomic, copy) NSString* creditCardNumber;
@property (nonatomic, copy) NSString* expirationMonth;
@property (nonatomic, copy) NSString* expirationYear;
-@property (nonatomic, copy) NSString* billingAddress;
+@property (nonatomic) NSInteger billingAddressID;
// Designated initializer. Initializes the property strings to values retrieved
// from the |creditCard| object.
diff --git a/chrome/browser/autofill/autofill_credit_card_model_mac.mm b/chrome/browser/autofill/autofill_credit_card_model_mac.mm
index 26f0db9..5c49ab2 100644
--- a/chrome/browser/autofill/autofill_credit_card_model_mac.mm
+++ b/chrome/browser/autofill/autofill_credit_card_model_mac.mm
@@ -15,7 +15,7 @@
@synthesize creditCardNumber = creditCardNumber_;
@synthesize expirationMonth = expirationMonth_;
@synthesize expirationYear = expirationYear_;
-@synthesize billingAddress = billingAddress_;
+@synthesize billingAddressID = billingAddressID_;
- (id)initWithCreditCard:(const CreditCard&)creditCard {
if ((self = [super init])) {
@@ -27,8 +27,7 @@
creditCard.GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH)))];
[self setExpirationYear:SysUTF16ToNSString(
creditCard.GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR)))];
- [self setBillingAddress:SysUTF16ToNSString(
- creditCard.billing_address())];
+ [self setBillingAddressID:creditCard.billing_address_id()];
}
return self;
}
@@ -38,7 +37,6 @@
[creditCardNumber_ release];
[expirationMonth_ release];
[expirationYear_ release];
- [billingAddress_ release];
[super dealloc];
}
@@ -52,8 +50,7 @@
base::SysNSStringToUTF16([self expirationMonth]));
creditCard->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
base::SysNSStringToUTF16([self expirationYear]));
- creditCard->set_billing_address(
- base::SysNSStringToUTF16([self billingAddress]));
+ creditCard->set_billing_address_id([self billingAddressID]);
}
@end
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 642741c..6caab87 100644
--- a/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_common_unittest.h"
#import "chrome/browser/autofill/autofill_credit_card_model_mac.h"
#include "chrome/browser/autofill/credit_card.h"
@@ -26,7 +27,7 @@ TEST(AutoFillCreditCardModelTest, Basic) {
TEST(AutoFillCreditCardModelTest, InitializationFromCreditCard) {
CreditCard credit_card(string16(), 0);
autofill_unittest::SetCreditCardInfo(&credit_card, "Corporate",
- "John Dillinger", "Visa", "123456789012", "01", "2010", "Chicago");
+ "John Dillinger", "Visa", "123456789012", "01", "2010", 1);
scoped_nsobject<AutoFillCreditCardModel> model(
[[AutoFillCreditCardModel alloc] initWithCreditCard:credit_card]);
EXPECT_TRUE(model.get());
@@ -35,13 +36,13 @@ TEST(AutoFillCreditCardModelTest, InitializationFromCreditCard) {
EXPECT_TRUE([[model creditCardNumber] isEqualToString:@"123456789012"]);
EXPECT_TRUE([[model expirationMonth] isEqualToString:@"01"]);
EXPECT_TRUE([[model expirationYear] isEqualToString:@"2010"]);
- EXPECT_TRUE([[model billingAddress] isEqualToString:@"Chicago"]);
+ EXPECT_EQ(1, [model billingAddressID]);
}
TEST(AutoFillCreditCardModelTest, CopyModelToCreditCard) {
CreditCard credit_card(string16(), 0);
autofill_unittest::SetCreditCardInfo(&credit_card, "Corporate",
- "John Dillinger", "Visa", "123456789012", "01", "2010", "Chicago");
+ "John Dillinger", "Visa", "123456789012", "01", "2010", 1);
scoped_nsobject<AutoFillCreditCardModel> model(
[[AutoFillCreditCardModel alloc] initWithCreditCard:credit_card]);
EXPECT_TRUE(model.get());
@@ -50,7 +51,7 @@ TEST(AutoFillCreditCardModelTest, CopyModelToCreditCard) {
[model setCreditCardNumber:@"223456789012"];
[model setExpirationMonth:@"11"];
[model setExpirationYear:@"2011"];
- [model setBillingAddress:@"New York"];
+ [model setBillingAddressID:2];
[model copyModelToCreditCard:&credit_card];
@@ -63,7 +64,7 @@ TEST(AutoFillCreditCardModelTest, CopyModelToCreditCard) {
EXPECT_EQ(ASCIIToUTF16("2011"),
credit_card.GetFieldText(
AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR)));
- EXPECT_EQ(ASCIIToUTF16("New York"), credit_card.billing_address());
+ EXPECT_EQ(2, credit_card.billing_address_id());
}
} // namespace
diff --git a/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h
index 6fa281d..76fa2ad 100644
--- a/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h
+++ b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_SHEET_CONTROLLER_MAC_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_SHEET_CONTROLLER_MAC_
+#pragma once
#import <Cocoa/Cocoa.h>
+#include <vector>
@class AutoFillCreditCardModel;
@class AutoFillDialogController;
@@ -33,6 +35,10 @@ typedef NSInteger AutoFillCreditCardMode;
// "New credit card" or "Edit credit card" depending on context.
IBOutlet NSTextField* caption_;
+ // The credit card number field. This is here for unit testing purposes.
+ // The text of this field is obfuscated until edited.
+ IBOutlet NSTextField* creditCardNumberField_;
+
// The primary model for this controller. The model is instantiated
// from within |initWithCreditCard:|. We do not hold it as a scoped_nsobject
// because it is exposed as a KVO compliant property.
@@ -44,6 +50,9 @@ typedef NSInteger AutoFillCreditCardMode;
// of addresses change in the |parentController_|.
NSArray* billingAddressContents_;
+ // Array of IDs corresponding to the strings in |billingAddressContents_|.
+ std::vector<int> billingAddressIDs_;
+
// Contents of the expiration month and year popups. Strongly owned. We do
// not hold them as scoped_nsobjects because they are exposed as KVO compliant
// properties.
@@ -79,4 +88,9 @@ typedef NSInteger AutoFillCreditCardMode;
@end
+// Interface exposed for unit testing.
+@interface AutoFillCreditCardSheetController (ExposedForUnitTests)
+- (NSTextField*)creditCardNumberField;
+@end
+
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_SHEET_CONTROLLER_MAC_
diff --git a/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm
index 3a483c5..31fbff0 100644
--- a/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm
+++ b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm
@@ -12,6 +12,13 @@
#include "chrome/browser/autofill/credit_card.h"
#include "grit/generated_resources.h"
+// Interface exposed for unit testing.
+@implementation AutoFillCreditCardSheetController (ExposedForUnitTests)
+- (NSTextField*)creditCardNumberField {
+ return creditCardNumberField_;
+}
+@end
+
// Private methods for the |AutoFillCreditCardSheetController| class.
@interface AutoFillCreditCardSheetController (PrivateMethods)
- (void)buildBillingAddressContents;
@@ -91,12 +98,19 @@
// The model copies the popup values blindly. We need to clear the strings
// in the case that our special menus are in effect.
if ([billingAddressPopup_ indexOfSelectedItem] <= 0)
- [creditCardModel_ setBillingAddress:@""];
+ [creditCardModel_ setBillingAddressID:0];
if ([expirationMonthPopup_ indexOfSelectedItem] <= 0)
[creditCardModel_ setExpirationMonth:@""];
if ([expirationYearPopup_ indexOfSelectedItem] <= 0)
[creditCardModel_ setExpirationYear:@""];
+ // The view does not set the billing address directly. It relies on
+ // the controller to translate between popup index and the billing address
+ // ID. Note the -1 offset. This is due to the empty menu item in the popup.
+ if ([billingAddressPopup_ indexOfSelectedItem] > 0) {
+ [creditCardModel_ setBillingAddressID:
+ billingAddressIDs_[[billingAddressPopup_ indexOfSelectedItem]-1]];
+ }
[creditCardModel_ copyModelToCreditCard:creditCard];
}
@@ -108,17 +122,26 @@
IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS);
// Build the menu array and set it.
- NSArray* addressStrings = [parentController_ addressLabels];
+ NSArray* addressStrings = nil;
+ [parentController_ addressLabels:&addressStrings
+ addressIDs:&billingAddressIDs_];
NSArray* newArray = [[NSArray arrayWithObject:menuString]
arrayByAddingObjectsFromArray:addressStrings];
[self setBillingAddressContents:newArray];
- // If the addresses no longer contain our selected item, reset the selection.
- if ([addressStrings
- indexOfObject:[creditCardModel_ billingAddress]] == NSNotFound) {
- [creditCardModel_ setBillingAddress:menuString];
+ // If the addresses no longer contain our billing address then reset the
+ // selection.
+ int distance = std::distance(billingAddressIDs_.begin(),
+ std::find(billingAddressIDs_.begin(),
+ billingAddressIDs_.end(),
+ [creditCardModel_ billingAddressID]));
+ if (distance >= static_cast<int>(billingAddressIDs_.size())) {
+ [billingAddressPopup_ selectItemAtIndex:0];
+ } else {
+ [billingAddressPopup_ selectItemAtIndex:distance+1];
}
+
// Disable first item in menu. "Choose existing address" is a non-item.
[[billingAddressPopup_ itemAtIndex:0] setEnabled:NO];
}
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 a15b421..9058070 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
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/scoped_nsobject.h"
+#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"
diff --git a/chrome/browser/autofill/autofill_dialog.h b/chrome/browser/autofill/autofill_dialog.h
index d5f7b07..1c47c86 100644
--- a/chrome/browser/autofill/autofill_dialog.h
+++ b/chrome/browser/autofill/autofill_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_DIALOG_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_DIALOG_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.h b/chrome/browser/autofill/autofill_dialog_controller_mac.h
index 7a7faa7..cd5eec1 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac.h
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_DIALOG_CONTROLLER_MAC_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_DIALOG_CONTROLLER_MAC_
+#pragma once
#import <Cocoa/Cocoa.h>
#include <vector>
@@ -14,9 +15,11 @@
#include "chrome/browser/autofill/autofill_dialog.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
+#include "chrome/browser/prefs/pref_member.h"
namespace AutoFillDialogControllerInternal {
class PersonalDataManagerObserver;
+class PreferenceObserver;
} // AutoFillDialogControllerInternal
@class AutoFillAddressSheetController;
@@ -25,8 +28,8 @@ class PersonalDataManagerObserver;
class Profile;
@class WindowSizeAutosaver;
-// A window controller for managing the autofill options dialog.
-// Application modally presents a dialog allowing the user to store
+// A window controller for managing the AutoFill options dialog.
+// Modelessly presents a dialog allowing the user to store
// personal address and credit card information.
@interface AutoFillDialogController : NSWindowController <NSTableViewDelegate> {
@private
@@ -47,14 +50,6 @@ class Profile;
// Weak, not retained.
Profile* profile_;
- // Reference to input parameter.
- // Weak, not retained.
- AutoFillProfile* importedProfile_;
-
- // Reference to input parameter.
- // Weak, not retained.
- CreditCard* importedCreditCard_;
-
// Working list of input profiles.
std::vector<AutoFillProfile> profiles_;
@@ -62,10 +57,16 @@ class Profile;
std::vector<CreditCard> creditCards_;
// State of checkbox for enabling AutoFill in general.
- BOOL autoFillEnabled_;
+ BooleanPrefMember autoFillEnabled_;
+
+ // Whether AutoFill is controlled by configuration management.
+ BOOL autoFillManaged_;
+
+ // Whether AutoFill is managed and disabled.
+ BOOL autoFillManagedAndDisabled_;
// State of checkbox for enabling Mac Address Book integration.
- BOOL auxiliaryEnabled_;
+ BooleanPrefMember auxiliaryEnabled_;
// State for |itemIsSelected| property used in bindings for "Edit..." and
// "Remove" buttons.
@@ -89,6 +90,10 @@ class Profile;
// Manages PersonalDataManager loading.
scoped_ptr<AutoFillDialogControllerInternal::PersonalDataManagerObserver>
personalDataManagerObserver_;
+
+ // Watches for changes to the AutoFill enabled preference.
+ scoped_ptr<AutoFillDialogControllerInternal::PreferenceObserver>
+ preferenceObserver_;
}
// Property representing state of the AutoFill enabled preference. Checkbox is
@@ -96,6 +101,15 @@ class Profile;
// to this property.
@property (nonatomic) BOOL autoFillEnabled;
+// Property indicating whether AutoFill is under control of configuration
+// management. The enabled state of the AutoFill enabled checkbox is bound to
+// this property.
+@property (nonatomic) BOOL autoFillManaged;
+
+// Property that is true iff AutoFill is managed and disabled. The save button's
+// enabled state is bound to this property.
+@property (nonatomic) BOOL autoFillManagedAndDisabled;
+
// Property representing state of Address Book "me" card usage. Checkbox is
// bound to this in nib.
@property (nonatomic) BOOL auxiliaryEnabled;
@@ -108,26 +122,18 @@ class Profile;
// state of edit button is bound to this property.
@property (nonatomic) BOOL multipleSelected;
-// Main interface for displaying an application modal AutoFill dialog on screen.
+// Main interface for displaying a modeless AutoFill dialog on screen.
// This class method creates a new |AutoFillDialogController| and runs it as a
-// modal dialog. The controller autoreleases itself when the dialog is closed.
-// |observer| can be NULL, but if it is, then no notification is sent during
-// call to |save|. If |observer| is non-NULL then its |OnAutoFillDialogApply|
-// method is invoked during |save| with the new address and credit card
-// information.
+// modeless dialog. The controller autoreleases itself when the dialog is
+// closed. |observer| can be NULL, but if it is, then no notification is sent
+// during modifications to data. If |observer| is non-NULL then its
+// |OnAutoFillDialogApply| method is invoked with the new address and credit
+// card information.
// |profile| must be non-NULL.
// AutoFill profile and credit card data is initialized from the
// |PersonalDataManager| that is associated with the input |profile|.
-// If |importedProfile| or |importedCreditCard| parameters are supplied then
-// the |PersonalDataManager| data is ignored. Both may be NULL.
+ (void)showAutoFillDialogWithObserver:(AutoFillDialogObserver*)observer
- profile:(Profile*)profile
- importedProfile:(AutoFillProfile*)importedProfile
- importedCreditCard:(CreditCard*)importedCreditCard;
-
-// IBActions for the dialog buttons.
-- (IBAction)save:(id)sender;
-- (IBAction)cancel:(id)sender;
+ profile:(Profile*)profile;
// IBActions for adding new items.
- (IBAction)addNewAddress:(id)sender;
@@ -154,8 +160,11 @@ class Profile;
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView;
-// Returns an array of labels representing the addresses in the |profiles_|.
-- (NSArray*)addressLabels;
+// Creates an array of labels and populates a vector of corresponding IDs
+// representing the addresses and associated billing address IDs in the
+// |profiles_| member.
+// Only returns labels and IDs for which there exists address information.
+- (void)addressLabels:(NSArray**)labels addressIDs:(std::vector<int>*)ids;
@end
@@ -166,14 +175,11 @@ class Profile;
// Note: controller is autoreleased when |-closeDialog| is called.
+ (AutoFillDialogController*)controllerWithObserver:
(AutoFillDialogObserver*)observer
- profile:(Profile*)profile
- importedProfile:(AutoFillProfile*)importedProfile
- importedCreditCard:(CreditCard*)importedCreditCard;
+ profile:(Profile*)profile;
- (id)initWithObserver:(AutoFillDialogObserver*)observer
- profile:(Profile*)profile
- importedProfile:(AutoFillProfile*)importedProfile
- importedCreditCard:(CreditCard*)importedCreditCard;
+ profile:(Profile*)profile;
+- (void)runModelessDialog;
- (void)closeDialog;
- (AutoFillAddressSheetController*)addressSheetController;
- (AutoFillCreditCardSheetController*)creditCardSheetController;
@@ -182,6 +188,8 @@ class Profile;
- (void)addSelectedAddressAtIndex:(size_t)i;
- (void)addSelectedCreditCardAtIndex:(size_t)i;
- (BOOL)editButtonEnabled;
+- (std::vector<AutoFillProfile>&)profiles;
+- (std::vector<CreditCard>&)creditCards;
@end
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_DIALOG_CONTROLLER_MAC_
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.mm b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
index 594808b..26bd111 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac.mm
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
@@ -6,6 +6,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/mac_util.h"
+#include "base/singleton.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
@@ -16,8 +17,10 @@
#import "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/browser_process.h"
#import "chrome/browser/cocoa/window_size_autosaver.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/app_resources.h"
@@ -25,6 +28,10 @@
namespace {
+// Type for singleton object that contains the instance of the visible
+// dialog.
+typedef std::map<Profile*, AutoFillDialogController*> ProfileControllerMap;
+
// Update profile labels passed as |input|. When profile data changes as a
// result of adding new profiles, edititing existing profiles, or deleting a
// profile, then the list of profiles need to have their derived labels
@@ -79,12 +86,25 @@ void UpdateProfileLabels(std::vector<AutoFillProfile>* input) {
// Private interface.
@interface AutoFillDialogController (PrivateMethods)
+// Save profiles and credit card information after user modification.
+- (void)save;
+
// Asyncronous handler for when PersonalDataManager data loads. The
// personal data manager notifies the dialog with this method when the
// data loading is complete and ready to be used.
- (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles
creditCards:(const std::vector<CreditCard*>&)creditCards;
+// Asyncronous handler for when PersonalDataManager data changes. The
+// personal data manager notifies the dialog with this method when the
+// data has changed.
+- (void)onPersonalDataChanged:(const std::vector<AutoFillProfile*>&)profiles
+ creditCards:(const std::vector<CreditCard*>&)creditCards;
+
+// Called upon changes to AutoFill preferences that should be reflected in the
+// UI.
+- (void)preferenceDidChange:(const std::string&)preferenceName;
+
// Returns true if |row| is an index to a valid profile in |tableView_|, and
// false otherwise.
- (BOOL)isProfileRow:(NSInteger)row;
@@ -116,9 +136,6 @@ void UpdateProfileLabels(std::vector<AutoFillProfile>* input) {
// |creditCards_|.
- (NSInteger)rowFromCreditCardIndex:(size_t)row;
-// Invokes the modal dialog.
-- (void)runModalDialog;
-
@end
namespace AutoFillDialogControllerInternal {
@@ -142,6 +159,9 @@ class PersonalDataManagerObserver : public PersonalDataManager::Observer {
// Notifies the observer that the PersonalDataManager has finished loading.
virtual void OnPersonalDataLoaded();
+ // Notifies the observer that the PersonalDataManager data has changed.
+ virtual void OnPersonalDataChanged();
+
private:
// Utility method to remove |this| from |personal_data_manager_| as an
// observer.
@@ -176,37 +196,57 @@ void PersonalDataManagerObserver::RemoveObserver() {
}
}
-// The data is ready so display our data. Notify the dialog controller that
-// the data is ready. Once done we clear the observer.
+// The data has been loaded, notify the controller.
void PersonalDataManagerObserver::OnPersonalDataLoaded() {
- RemoveObserver();
[controller_ onPersonalDataLoaded:personal_data_manager_->web_profiles()
creditCards:personal_data_manager_->credit_cards()];
}
+// The data has changed, notify the controller.
+void PersonalDataManagerObserver::OnPersonalDataChanged() {
+ [controller_ onPersonalDataChanged:personal_data_manager_->web_profiles()
+ creditCards:personal_data_manager_->credit_cards()];
+}
+
+// Bridges preference changed notifications to the dialog controller.
+class PreferenceObserver : public NotificationObserver {
+ public:
+ explicit PreferenceObserver(AutoFillDialogController* controller)
+ : controller_(controller) {}
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED) {
+ const std::string* pref = Details<std::string>(details).ptr();
+ if (pref) {
+ [controller_ preferenceDidChange:*pref];
+ }
+ }
+ }
+
+ private:
+ AutoFillDialogController* controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreferenceObserver);
+};
+
} // namespace AutoFillDialogControllerInternal
@implementation AutoFillDialogController
-@synthesize autoFillEnabled = autoFillEnabled_;
-@synthesize auxiliaryEnabled = auxiliaryEnabled_;
+@synthesize autoFillManaged = autoFillManaged_;
+@synthesize autoFillManagedAndDisabled = autoFillManagedAndDisabled_;
@synthesize itemIsSelected = itemIsSelected_;
@synthesize multipleSelected = multipleSelected_;
+ (void)showAutoFillDialogWithObserver:(AutoFillDialogObserver*)observer
- profile:(Profile*)profile
- importedProfile:(AutoFillProfile*) importedProfile
- importedCreditCard:(CreditCard*) importedCreditCard {
+ profile:(Profile*)profile {
AutoFillDialogController* controller =
[AutoFillDialogController controllerWithObserver:observer
- profile:profile
- importedProfile:importedProfile
- importedCreditCard:importedCreditCard];
-
- // Only run modal dialog if it is not already being shown.
- if (![controller isWindowLoaded]) {
- [controller runModalDialog];
- }
+ profile:profile];
+ [controller runModelessDialog];
}
- (void)awakeFromNib {
@@ -218,15 +258,14 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
// |personalDataManager| data is loaded, we can proceed with the contents.
[self onPersonalDataLoaded:personal_data_manager->web_profiles()
creditCards:personal_data_manager->credit_cards()];
- } else {
- // |personalDataManager| data is NOT loaded, so we load it here, installing
- // our observer.
- personalDataManagerObserver_.reset(
- new AutoFillDialogControllerInternal::PersonalDataManagerObserver(
- self, personal_data_manager, profile_));
- personal_data_manager->SetObserver(personalDataManagerObserver_.get());
}
+ // Register as listener to listen to subsequent data change notifications.
+ personalDataManagerObserver_.reset(
+ new AutoFillDialogControllerInternal::PersonalDataManagerObserver(
+ self, personal_data_manager, profile_));
+ personal_data_manager->SetObserver(personalDataManagerObserver_.get());
+
// Explicitly load the data in the table before window displays to avoid
// nasty flicker as tables update.
[tableView_ reloadData];
@@ -241,24 +280,13 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
[tableView_ setDataSource:nil];
[tableView_ setDelegate:nil];
[self autorelease];
-}
-// Called when the user clicks the save button.
-- (IBAction)save:(id)sender {
- // If we have an |observer_| then communicate the changes back.
- if (observer_) {
- profile_->GetPrefs()->SetBoolean(prefs::kAutoFillEnabled, autoFillEnabled_);
- profile_->GetPrefs()->SetBoolean(prefs::kAutoFillAuxiliaryProfilesEnabled,
- auxiliaryEnabled_);
- observer_->OnAutoFillDialogApply(&profiles_, &creditCards_);
+ // Remove ourself from the map.
+ ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
+ ProfileControllerMap::iterator it = map->find(profile_);
+ if (it != map->end()) {
+ map->erase(it);
}
- [self closeDialog];
-}
-
-// Called when the user clicks the cancel button. All we need to do is stop
-// the modal session.
-- (IBAction)cancel:(id)sender {
- [self closeDialog];
}
// Invokes the "Add" sheet for address information. If user saves then the new
@@ -321,9 +349,9 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
if (!newAddress.IsEmpty()) {
profiles_.push_back(newAddress);
- // Refresh the view based on new data.
- UpdateProfileLabels(&profiles_);
- [tableView_ reloadData];
+ // Saving will save to the PDM and the table will refresh when PDM sends
+ // notification that the underlying model has changed.
+ [self save];
// Update the selection to the newly added item.
NSInteger row = [self rowFromProfileIndex:profiles_.size() - 1];
@@ -348,8 +376,9 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
if (!newCreditCard.IsEmpty()) {
creditCards_.push_back(newCreditCard);
- // Refresh the view based on new data.
- [tableView_ reloadData];
+ // Saving will save to the PDM and the table will refresh when PDM sends
+ // notification that the underlying model has changed.
+ [self save];
// Update the selection to the newly added item.
NSInteger row = [self rowFromCreditCardIndex:creditCards_.size() - 1];
@@ -395,8 +424,9 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
[tableView_ deselectAll:self];
}
- UpdateProfileLabels(&profiles_);
- [tableView_ reloadData];
+ // Saving will save to the PDM and the table will refresh when PDM sends
+ // notification that the underlying model has changed.
+ [self save];
}
// Edits the selected item, either address or credit card depending on the item
@@ -466,8 +496,9 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
std::mem_fun_ref(&AutoFillProfile::IsEmpty)),
profiles_.end());
- UpdateProfileLabels(&profiles_);
- [tableView_ reloadData];
+ // Saving will save to the PDM and the table will refresh when PDM sends
+ // notification that the underlying model has changed.
+ [self save];
}
[sheet orderOut:self];
addressSheetController.reset(nil);
@@ -490,7 +521,10 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
creditCards_.begin(), creditCards_.end(),
std::mem_fun_ref(&CreditCard::IsEmpty)),
creditCards_.end());
- [tableView_ reloadData];
+
+ // Saving will save to the PDM and the table will refresh when PDM sends
+ // notification that the underlying model has changed.
+ [self save];
}
[sheet orderOut:self];
creditCardSheetController.reset(nil);
@@ -505,7 +539,7 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
// NSTableView Delegate method.
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row {
- return ![self tableView:tableView isGroupRow:row];
+ return [self isProfileRow:row] || [self isCreditCardRow:row];
}
// NSTableView Delegate method.
@@ -585,45 +619,88 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
return 0;
}
-- (NSArray*)addressLabels {
+- (void)addressLabels:(NSArray**)labels addressIDs:(std::vector<int>*)ids {
NSUInteger capacity = profiles_.size();
NSMutableArray* array = [NSMutableArray arrayWithCapacity:capacity];
+ ids->clear();
std::vector<AutoFillProfile>::iterator i;
for (i = profiles_.begin(); i != profiles_.end(); ++i) {
+ FieldTypeSet fields;
+ i->GetAvailableFieldTypes(&fields);
+ if (fields.find(ADDRESS_HOME_LINE1) == fields.end() &&
+ fields.find(ADDRESS_HOME_LINE2) == fields.end() &&
+ fields.find(ADDRESS_HOME_APT_NUM) == fields.end() &&
+ fields.find(ADDRESS_HOME_CITY) == fields.end() &&
+ fields.find(ADDRESS_HOME_STATE) == fields.end() &&
+ fields.find(ADDRESS_HOME_ZIP) == fields.end() &&
+ fields.find(ADDRESS_HOME_COUNTRY) == fields.end()) {
+ // No address information in this profile; it's useless as a billing
+ // address.
+ continue;
+ }
[array addObject:SysUTF16ToNSString(i->Label())];
+ ids->push_back(i->unique_id());
}
- return array;
+ *labels = array;
+}
+
+// Accessor for |autoFillEnabled| preference state. Note: a checkbox in Nib
+// is bound to this via KVO.
+- (BOOL)autoFillEnabled {
+ return autoFillEnabled_.GetValue();
+}
+
+// Setter for |autoFillEnabled| preference state.
+- (void)setAutoFillEnabled:(BOOL)value {
+ autoFillEnabled_.SetValueIfNotManaged(value ? true : false);
+}
+
+// Accessor for |auxiliaryEnabled| preference state. Note: a checkbox in Nib
+// is bound to this via KVO.
+- (BOOL)auxiliaryEnabled {
+ return auxiliaryEnabled_.GetValue();
+}
+
+// Setter for |auxiliaryEnabled| preference state.
+- (void)setAuxiliaryEnabled:(BOOL)value {
+ if ([self autoFillEnabled])
+ auxiliaryEnabled_.SetValueIfNotManaged(value ? true : false);
}
@end
@implementation AutoFillDialogController (ExposedForUnitTests)
-+ (AutoFillDialogController*)controllerWithObserver:
- (AutoFillDialogObserver*)observer
- profile:(Profile*)profile
- importedProfile:(AutoFillProfile*)importedProfile
- importedCreditCard:(CreditCard*)importedCreditCard {
++ (AutoFillDialogController*)
+ controllerWithObserver:(AutoFillDialogObserver*)observer
+ profile:(Profile*)profile {
+ profile = profile->GetOriginalProfile();
+
+ ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
+ DCHECK(map != NULL);
+ ProfileControllerMap::iterator it = map->find(profile);
+ if (it == map->end()) {
+ // We should have exactly 1 or 0 entry in the map, no more. That is,
+ // only one profile can have the AutoFill dialog up at a time.
+ DCHECK_EQ(map->size(), 0U);
// Deallocation is done upon window close. See |windowWillClose:|.
AutoFillDialogController* controller =
- [[self alloc] initWithObserver:observer
- profile:profile
- importedProfile:importedProfile
- importedCreditCard:importedCreditCard];
- return controller;
+ [[self alloc] initWithObserver:observer profile:profile];
+ it = map->insert(std::make_pair(profile, controller)).first;
+ }
+
+ return it->second;
}
// This is the designated initializer for this class.
-// |profiles| are non-retained immutable list of autofill profiles.
+// |profiles| are non-retained immutable list of AutoFill profiles.
// |creditCards| are non-retained immutable list of credit card info.
- (id)initWithObserver:(AutoFillDialogObserver*)observer
- profile:(Profile*)profile
- importedProfile:(AutoFillProfile*)importedProfile
- importedCreditCard:(CreditCard*)importedCreditCard {
+ profile:(Profile*)profile {
DCHECK(profile);
// Use initWithWindowNibPath: instead of initWithWindowNibName: so we
// can override it in a unit test.
@@ -634,16 +711,26 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
// Initialize member variables based on input.
observer_ = observer;
profile_ = profile;
- importedProfile_ = importedProfile;
- importedCreditCard_ = importedCreditCard;
- // Use property here to trigger KVO binding.
- [self setAutoFillEnabled:profile_->GetPrefs()->GetBoolean(
- prefs::kAutoFillEnabled)];
+ // Initialize the preference observer and watch kAutoFillEnabled.
+ preferenceObserver_.reset(
+ new AutoFillDialogControllerInternal::PreferenceObserver(self));
+ autoFillEnabled_.Init(prefs::kAutoFillEnabled, profile_->GetPrefs(),
+ preferenceObserver_.get());
+
+ // Call |preferenceDidChange| in order to initialize UI state of the
+ // checkbox.
+ [self preferenceDidChange:prefs::kAutoFillEnabled];
- // Use property here to trigger KVO binding.
- [self setAuxiliaryEnabled:profile_->GetPrefs()->GetBoolean(
- prefs::kAutoFillAuxiliaryProfilesEnabled)];
+ // Initialize the preference observer and watch
+ // kAutoFillAuxiliaryProfilesEnabled.
+ auxiliaryEnabled_.Init(prefs::kAutoFillAuxiliaryProfilesEnabled,
+ profile_->GetPrefs(),
+ preferenceObserver_.get());
+
+ // Call |preferenceDidChange| in order to initialize UI state of the
+ // checkbox.
+ [self preferenceDidChange:prefs::kAutoFillAuxiliaryProfilesEnabled];
// Do not use [NSMutableArray array] here; we need predictable destruction
// which will be prevented by having a reference held by an autorelease
@@ -652,10 +739,22 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
return self;
}
+// Run modeless.
+- (void)runModelessDialog {
+ // Use stored window geometry if it exists.
+ if (g_browser_process && g_browser_process->local_state()) {
+ sizeSaver_.reset([[WindowSizeAutosaver alloc]
+ initWithWindow:[self window]
+ prefService:g_browser_process->local_state()
+ path:prefs::kAutoFillDialogPlacement]);
+ }
+
+ [self showWindow:nil];
+}
+
// Close the dialog.
- (void)closeDialog {
- [[self window] close];
- [NSApp stopModal];
+ [[self window] performClose:self];
}
- (AutoFillAddressSheetController*)addressSheetController {
@@ -694,48 +793,69 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
return [editButton_ isEnabled];
}
+- (std::vector<AutoFillProfile>&)profiles {
+ return profiles_;
+}
+
+- (std::vector<CreditCard>&)creditCards {
+ return creditCards_;
+}
+
@end
@implementation AutoFillDialogController (PrivateMethods)
-// Run application modal.
-- (void)runModalDialog {
- // Use stored window geometry if it exists.
- if (g_browser_process && g_browser_process->local_state()) {
- sizeSaver_.reset([[WindowSizeAutosaver alloc]
- initWithWindow:[self window]
- prefService:g_browser_process->local_state()
- path:prefs::kAutoFillDialogPlacement
- state:kSaveWindowPos]);
- }
+// Called when the user modifies the profiles or credit card information.
+- (void)save {
+ // If we have an |observer_| then communicate the changes back, unless
+ // AutoFill has been disabled through policy in the mean time.
+ if (observer_ && !autoFillManagedAndDisabled_) {
+ // Make a working copy of profiles. |OnAutoFillDialogApply| can mutate
+ // |profiles_|.
+ std::vector<AutoFillProfile> profiles = profiles_;
- [NSApp runModalForWindow:[self window]];
+ // Make a working copy of credit cards. |OnAutoFillDialogApply| can mutate
+ // |creditCards_|.
+ std::vector<CreditCard> creditCards = creditCards_;
+
+ observer_->OnAutoFillDialogApply(&profiles, &creditCards);
+ }
}
- (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles
creditCards:(const std::vector<CreditCard*>&)creditCards {
- if (importedProfile_) {
- profiles_.push_back(*importedProfile_);
- }
+ [self onPersonalDataChanged:profiles creditCards:creditCards];
+}
- if (importedCreditCard_) {
- creditCards_.push_back(*importedCreditCard_);
- }
+- (void)onPersonalDataChanged:(const std::vector<AutoFillProfile*>&)profiles
+ creditCards:(const std::vector<CreditCard*>&)creditCards {
+ // Make local copy of |profiles|.
+ profiles_.clear();
+ for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
+ iter != profiles.end(); ++iter)
+ profiles_.push_back(**iter);
- // If we're not using imported data then use the data fetch from the web db.
- if (!importedProfile_ && !importedCreditCard_) {
- // Make local copy of |profiles|.
- for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
- iter != profiles.end(); ++iter)
- profiles_.push_back(**iter);
-
- // Make local copy of |creditCards|.
- for (std::vector<CreditCard*>::const_iterator iter = creditCards.begin();
- iter != creditCards.end(); ++iter)
- creditCards_.push_back(**iter);
- }
+ // Make local copy of |creditCards|.
+ creditCards_.clear();
+ for (std::vector<CreditCard*>::const_iterator iter = creditCards.begin();
+ iter != creditCards.end(); ++iter)
+ creditCards_.push_back(**iter);
UpdateProfileLabels(&profiles_);
+ [tableView_ reloadData];
+}
+
+- (void)preferenceDidChange:(const std::string&)preferenceName {
+ if (preferenceName == prefs::kAutoFillEnabled) {
+ [self setAutoFillEnabled:autoFillEnabled_.GetValue()];
+ [self setAutoFillManaged:autoFillEnabled_.IsManaged()];
+ [self setAutoFillManagedAndDisabled:
+ autoFillEnabled_.IsManaged() && !autoFillEnabled_.GetValue()];
+ } else if (preferenceName == prefs::kAutoFillAuxiliaryProfilesEnabled) {
+ [self setAuxiliaryEnabled:auxiliaryEnabled_.GetValue()];
+ } else {
+ NOTREACHED();
+ }
}
- (BOOL)isProfileRow:(NSInteger)row {
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
index 96276e4..e8c7dab 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "base/ref_counted.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.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"
@@ -12,9 +14,10 @@
#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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -148,11 +151,8 @@ class AutoFillDialogControllerTest : public CocoaTest {
void LoadDialog() {
controller_ = [AutoFillDialogController
- controllerWithObserver:&observer_
- profile:helper_.profile()
- importedProfile:imported_profile_
- importedCreditCard:imported_credit_card_];
- [controller_ window];
+ controllerWithObserver:&observer_ profile:helper_.profile()];
+ [controller_ runModelessDialog];
}
std::vector<AutoFillProfile*>& profiles() {
@@ -172,69 +172,36 @@ class AutoFillDialogControllerTest : public CocoaTest {
DISALLOW_COPY_AND_ASSIGN(AutoFillDialogControllerTest);
};
-TEST_F(AutoFillDialogControllerTest, SaveButtonInformsObserver) {
+TEST_F(AutoFillDialogControllerTest, CloseButtonDoesNotInformObserver) {
LoadDialog();
- [controller_ save:nil];
- ASSERT_TRUE(observer_.hit_);
-}
-
-TEST_F(AutoFillDialogControllerTest, CancelButtonDoesNotInformObserver) {
- LoadDialog();
- [controller_ cancel:nil];
+ [controller_ closeDialog];
ASSERT_FALSE(observer_.hit_);
}
-TEST_F(AutoFillDialogControllerTest, NoEditsGiveBackOriginalProfile) {
+TEST_F(AutoFillDialogControllerTest, NoEditsDoNotChangeObserverProfiles) {
AutoFillProfile profile;
profiles().push_back(&profile);
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
-
- // Sizes should match.
- ASSERT_EQ(observer_.profiles_.size(), profiles().size());
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
- // Contents should match.
- size_t i = 0;
- size_t count = profiles().size();
- for (i = 0; i < count; i++)
- ASSERT_EQ(observer_.profiles_[i], *profiles()[i]);
-
- // Contents should not match a different profile.
- AutoFillProfile different_profile;
- different_profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("joe"));
- for (i = 0; i < count; i++)
- ASSERT_NE(observer_.profiles_[i], different_profile);
+ // Observer should not have profiles.
+ ASSERT_EQ(0UL, observer_.profiles_.size());
}
-TEST_F(AutoFillDialogControllerTest, NoEditsGiveBackOriginalCreditCard) {
+TEST_F(AutoFillDialogControllerTest, NoEditsDoNotChangeObserverCreditCards) {
CreditCard credit_card(ASCIIToUTF16("myCC"), 345);
credit_cards().push_back(&credit_card);
LoadDialog();
- [controller_ save:nil];
-
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ [controller_ closeDialog];
- // Sizes should match.
- ASSERT_EQ(observer_.credit_cards_.size(), credit_cards().size());
-
- // Contents should match. With the exception of the |unique_id|.
- size_t i = 0;
- size_t count = credit_cards().size();
- for (i = 0; i < count; i++) {
- credit_cards()[i]->set_unique_id(observer_.credit_cards_[i].unique_id());
- ASSERT_EQ(observer_.credit_cards_[i], *credit_cards()[i]);
- }
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
- // Contents should not match a different profile.
- CreditCard different_credit_card(ASCIIToUTF16("different"), 0);
- different_credit_card.SetInfo(
- AutoFillType(CREDIT_CARD_NUMBER), ASCIIToUTF16("1234"));
- for (i = 0; i < count; i++)
- ASSERT_NE(observer_.credit_cards_[i], different_credit_card);
+ // Observer should not have credit cards.
+ ASSERT_EQ(0UL, observer_.credit_cards_.size());
}
TEST_F(AutoFillDialogControllerTest, AutoFillDataMutation) {
@@ -243,20 +210,20 @@ TEST_F(AutoFillDialogControllerTest, AutoFillDataMutation) {
profile.SetInfo(AutoFillType(NAME_MIDDLE), ASCIIToUTF16("C"));
profile.SetInfo(AutoFillType(NAME_LAST), ASCIIToUTF16("Smith"));
profile.SetInfo(AutoFillType(EMAIL_ADDRESS),
- ASCIIToUTF16("john@chromium.org"));
+ ASCIIToUTF16("john@chromium.org"));
profile.SetInfo(AutoFillType(COMPANY_NAME), ASCIIToUTF16("Google Inc."));
profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
ASCIIToUTF16("1122 Mountain View Road"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2), ASCIIToUTF16("Suite #1"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_CITY),
- ASCIIToUTF16("Mountain View"));
+ ASCIIToUTF16("Mountain View"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_STATE), ASCIIToUTF16("CA"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_ZIP), ASCIIToUTF16("94111"));
profile.SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), ASCIIToUTF16("USA"));
- profile.SetInfo(
- AutoFillType(PHONE_HOME_WHOLE_NUMBER), ASCIIToUTF16("014155552258"));
- profile.SetInfo(
- AutoFillType(PHONE_FAX_WHOLE_NUMBER), ASCIIToUTF16("024087172258"));
+ profile.SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER),
+ ASCIIToUTF16("014155552258"));
+ profile.SetInfo(AutoFillType(PHONE_FAX_WHOLE_NUMBER),
+ ASCIIToUTF16("024087172258"));
profiles().push_back(&profile);
LoadDialog();
@@ -278,7 +245,7 @@ TEST_F(AutoFillDialogControllerTest, AutoFillDataMutation) {
EXPECT_TRUE([[am faxWholeNumber] isEqualToString:@"024087172258"]);
[sheet save:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
ASSERT_TRUE(observer_.hit_);
ASSERT_TRUE(observer_.profiles_.size() == 1);
@@ -293,11 +260,12 @@ TEST_F(AutoFillDialogControllerTest, AutoFillDataMutation) {
TEST_F(AutoFillDialogControllerTest, CreditCardDataMutation) {
CreditCard credit_card(ASCIIToUTF16("myCC"), 345);
credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("DCH"));
- credit_card.SetInfo(
- AutoFillType(CREDIT_CARD_NUMBER), ASCIIToUTF16("1234 5678 9101 1121"));
+ credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER),
+ ASCIIToUTF16("1234 5678 9101 1121"));
credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), ASCIIToUTF16("01"));
- credit_card.SetInfo(
- AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), ASCIIToUTF16("2012"));
+ credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
+ ASCIIToUTF16("2012"));
+ credit_card.set_billing_address_id(0);
credit_cards().push_back(&credit_card);
LoadDialog();
@@ -313,12 +281,18 @@ TEST_F(AutoFillDialogControllerTest, CreditCardDataMutation) {
EXPECT_TRUE([[cm expirationMonth] isEqualToString:@"01"]);
EXPECT_TRUE([[cm expirationYear] isEqualToString:@"2012"]);
+ // Check that user-visible text is obfuscated.
+ NSTextField* numberField = [sheet creditCardNumberField];
+ ASSERT_TRUE(numberField != nil);
+ EXPECT_TRUE([[numberField stringValue] isEqualToString:@"************1121"]);
+
[sheet save:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
ASSERT_TRUE(observer_.hit_);
ASSERT_TRUE(observer_.credit_cards_.size() == 1);
+ // Don't compare unique ids.
credit_cards()[0]->set_unique_id(observer_.credit_cards_[0].unique_id());
ASSERT_EQ(observer_.credit_cards_[0], *credit_cards()[0]);
}
@@ -331,23 +305,23 @@ TEST_F(AutoFillDialogControllerTest, TwoProfiles) {
profile2.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Bob"));
profiles().push_back(&profile2);
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// Sizes should match. And should be 2.
- ASSERT_EQ(observer_.profiles_.size(), profiles().size());
- ASSERT_EQ(observer_.profiles_.size(), 2UL);
+ ASSERT_EQ([controller_ profiles].size(), profiles().size());
+ ASSERT_EQ([controller_ profiles].size(), 2UL);
// Contents should match. With the exception of the |unique_id|.
for (size_t i = 0, count = profiles().size(); i < count; i++) {
- profiles()[i]->set_unique_id(observer_.profiles_[i].unique_id());
+ profiles()[i]->set_unique_id([controller_ profiles][i].unique_id());
// Do not compare labels. Label is a derived field.
- observer_.profiles_[i].set_label(string16());
+ [controller_ profiles][i].set_label(string16());
profiles()[i]->set_label(string16());
- ASSERT_EQ(observer_.profiles_[i], *profiles()[i]);
+ ASSERT_EQ([controller_ profiles][i], *profiles()[i]);
}
}
@@ -359,19 +333,19 @@ TEST_F(AutoFillDialogControllerTest, TwoCreditCards) {
credit_card2.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Bob"));
credit_cards().push_back(&credit_card2);
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// Sizes should match. And should be 2.
- ASSERT_EQ(observer_.credit_cards_.size(), credit_cards().size());
- ASSERT_EQ(observer_.credit_cards_.size(), 2UL);
+ ASSERT_EQ([controller_ creditCards].size(), credit_cards().size());
+ ASSERT_EQ([controller_ creditCards].size(), 2UL);
// Contents should match. With the exception of the |unique_id|.
for (size_t i = 0, count = credit_cards().size(); i < count; i++) {
- credit_cards()[i]->set_unique_id(observer_.credit_cards_[i].unique_id());
- ASSERT_EQ(observer_.credit_cards_[i], *credit_cards()[i]);
+ credit_cards()[i]->set_unique_id([controller_ creditCards][i].unique_id());
+ ASSERT_EQ([controller_ creditCards][i], *credit_cards()[i]);
}
}
@@ -387,7 +361,7 @@ TEST_F(AutoFillDialogControllerTest, AddNewProfile) {
ASSERT_TRUE(model != nil);
[model setFullName:@"Don"];
[sheet save:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
ASSERT_TRUE(observer_.hit_);
@@ -416,7 +390,7 @@ TEST_F(AutoFillDialogControllerTest, AddNewCreditCard) {
ASSERT_TRUE(model != nil);
[model setNameOnCard:@"Don"];
[sheet save:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
ASSERT_TRUE(observer_.hit_);
@@ -428,6 +402,7 @@ TEST_F(AutoFillDialogControllerTest, AddNewCreditCard) {
// New credit card should match. Don't compare labels.
CreditCard new_credit_card;
new_credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Don"));
+ new_credit_card.set_billing_address_id(0);
observer_.credit_cards_[1].set_label(string16());
ASSERT_EQ(observer_.credit_cards_[1], new_credit_card);
}
@@ -441,18 +416,13 @@ TEST_F(AutoFillDialogControllerTest, AddNewEmptyProfile) {
AutoFillAddressSheetController* sheet = [controller_ addressSheetController];
ASSERT_TRUE(sheet != nil);
[sheet save:nil];
- [controller_ save:nil];
-
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ [controller_ closeDialog];
- // Sizes should be same. Empty profile should not be saved.
- ASSERT_EQ(observer_.profiles_.size(), profiles().size());
- ASSERT_EQ(observer_.profiles_.size(), 1UL);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
- // Profile should match original.
- observer_.profiles_[0].set_label(string16());
- ASSERT_EQ(observer_.profiles_[0], profile);
+ // Empty profile should not be saved.
+ ASSERT_EQ(0UL, observer_.profiles_.size());
}
TEST_F(AutoFillDialogControllerTest, AddNewEmptyCreditCard) {
@@ -465,18 +435,13 @@ TEST_F(AutoFillDialogControllerTest, AddNewEmptyCreditCard) {
[controller_ creditCardSheetController];
ASSERT_TRUE(sheet != nil);
[sheet save:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
-
- // Sizes should be same. Empty credit card should not be saved.
- ASSERT_EQ(observer_.credit_cards_.size(), credit_cards().size());
- ASSERT_EQ(observer_.credit_cards_.size(), 1UL);
+ ASSERT_FALSE(observer_.hit_);
- // Credit card should match original.
- observer_.credit_cards_[0].set_label(string16());
- ASSERT_EQ(observer_.credit_cards_[0], credit_card);
+ // Empty credit card should not be saved.
+ ASSERT_EQ(0UL, observer_.credit_cards_.size());
}
TEST_F(AutoFillDialogControllerTest, DeleteProfile) {
@@ -486,7 +451,7 @@ TEST_F(AutoFillDialogControllerTest, DeleteProfile) {
LoadDialog();
[controller_ selectAddressAtIndex:0];
[controller_ deleteSelection:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
ASSERT_TRUE(observer_.hit_);
@@ -503,7 +468,7 @@ TEST_F(AutoFillDialogControllerTest, DeleteCreditCard) {
LoadDialog();
[controller_ selectCreditCardAtIndex:0];
[controller_ deleteSelection:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
ASSERT_TRUE(observer_.hit_);
@@ -523,7 +488,7 @@ TEST_F(AutoFillDialogControllerTest, TwoProfilesDeleteOne) {
LoadDialog();
[controller_ selectAddressAtIndex:1];
[controller_ deleteSelection:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
ASSERT_TRUE(observer_.hit_);
@@ -551,7 +516,7 @@ TEST_F(AutoFillDialogControllerTest, TwoCreditCardsDeleteOne) {
LoadDialog();
[controller_ selectCreditCardAtIndex:1];
[controller_ deleteSelection:nil];
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
ASSERT_TRUE(observer_.hit_);
@@ -587,7 +552,7 @@ TEST_F(AutoFillDialogControllerTest, DeleteMultiple) {
[controller_ deleteSelection:nil];
[controller_ selectAddressAtIndex:0];
ASSERT_TRUE([controller_ editButtonEnabled]);
- [controller_ save:nil];
+ [controller_ closeDialog];
// Should hit our observer.
ASSERT_TRUE(observer_.hit_);
@@ -616,10 +581,10 @@ TEST_F(AutoFillDialogControllerTest, DeleteMultiple) {
// Auxilliary profiles are enabled by default.
TEST_F(AutoFillDialogControllerTest, AuxiliaryProfilesTrue) {
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// Auxiliary profiles setting should be unchanged.
ASSERT_TRUE(helper_.profile()->GetPrefs()->GetBoolean(
@@ -630,10 +595,10 @@ TEST_F(AutoFillDialogControllerTest, AuxiliaryProfilesFalse) {
helper_.profile()->GetPrefs()->SetBoolean(
prefs::kAutoFillAuxiliaryProfilesEnabled, false);
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// Auxiliary profiles setting should be unchanged.
ASSERT_FALSE(helper_.profile()->GetPrefs()->GetBoolean(
@@ -645,10 +610,10 @@ TEST_F(AutoFillDialogControllerTest, AuxiliaryProfilesChanged) {
prefs::kAutoFillAuxiliaryProfilesEnabled, false);
LoadDialog();
[controller_ setAuxiliaryEnabled:YES];
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// Auxiliary profiles setting should be unchanged.
ASSERT_TRUE(helper_.profile()->GetPrefs()->GetBoolean(
@@ -662,70 +627,37 @@ TEST_F(AutoFillDialogControllerTest, WaitForDataToLoad) {
credit_cards().push_back(&credit_card);
helper_.test_profile_->test_manager_->test_data_is_loaded_ = false;
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// Sizes should match.
- ASSERT_EQ(observer_.profiles_.size(), profiles().size());
- ASSERT_EQ(observer_.credit_cards_.size(), credit_cards().size());
+ ASSERT_EQ([controller_ profiles].size(), profiles().size());
+ ASSERT_EQ([controller_ creditCards].size(), credit_cards().size());
// Contents should match.
size_t i = 0;
size_t count = profiles().size();
for (i = 0; i < count; i++) {
// Do not compare labels. Label is a derived field.
- observer_.profiles_[i].set_label(string16());
+ [controller_ profiles][i].set_label(string16());
profiles()[i]->set_label(string16());
- ASSERT_EQ(observer_.profiles_[i], *profiles()[i]);
+ ASSERT_EQ([controller_ profiles][i], *profiles()[i]);
}
count = credit_cards().size();
for (i = 0; i < count; i++) {
- ASSERT_EQ(observer_.credit_cards_[i], *credit_cards()[i]);
+ ASSERT_EQ([controller_ creditCards][i], *credit_cards()[i]);
}
}
-TEST_F(AutoFillDialogControllerTest, ImportedParameters) {
- AutoFillProfile profile(ASCIIToUTF16("Home"), 0);
- imported_profile_ = &profile;
- CreditCard credit_card(ASCIIToUTF16("Mastercard"), 0);
- imported_credit_card_ = &credit_card;
-
- // Note: when the |imported_*| parameters are supplied the dialog should
- // ignore any profile and credit card information in the
- // |PersonalDataManager|.
- AutoFillProfile profile_ignored(ASCIIToUTF16("Work"), 0);
- profiles().push_back(&profile_ignored);
- CreditCard credit_card_ignored(ASCIIToUTF16("Visa"), 0);
- credit_cards().push_back(&credit_card_ignored);
-
- LoadDialog();
- [controller_ save:nil];
-
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
-
- // Sizes should match.
- ASSERT_EQ(1UL, observer_.profiles_.size());
- ASSERT_EQ(1UL, observer_.credit_cards_.size());
-
- // Do not compare labels. Label is a derived field.
- observer_.profiles_[0].set_label(string16());
- profile.set_label(string16());
-
- // Contents should match.
- ASSERT_EQ(observer_.profiles_[0], profile);
- ASSERT_EQ(observer_.credit_cards_[0], credit_card);
-}
-
// AutoFill is enabled by default.
TEST_F(AutoFillDialogControllerTest, AutoFillEnabledTrue) {
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// AutoFill enabled setting should be unchanged.
ASSERT_TRUE(helper_.profile()->GetPrefs()->GetBoolean(
@@ -735,10 +667,10 @@ TEST_F(AutoFillDialogControllerTest, AutoFillEnabledTrue) {
TEST_F(AutoFillDialogControllerTest, AutoFillEnabledFalse) {
helper_.profile()->GetPrefs()->SetBoolean(prefs::kAutoFillEnabled, false);
LoadDialog();
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// AutoFill enabled setting should be unchanged.
ASSERT_FALSE(helper_.profile()->GetPrefs()->GetBoolean(
@@ -750,14 +682,77 @@ TEST_F(AutoFillDialogControllerTest, AutoFillEnabledChanged) {
prefs::kAutoFillAuxiliaryProfilesEnabled, false);
LoadDialog();
[controller_ setAutoFillEnabled:YES];
- [controller_ save:nil];
+ [controller_ closeDialog];
- // Should hit our observer.
- ASSERT_TRUE(observer_.hit_);
+ // Should not hit our observer.
+ ASSERT_FALSE(observer_.hit_);
// Auxiliary profiles setting should be unchanged.
ASSERT_TRUE(helper_.profile()->GetPrefs()->GetBoolean(
prefs::kAutoFillEnabled));
}
+TEST_F(AutoFillDialogControllerTest, PolicyRefresh) {
+ LoadDialog();
+ ASSERT_FALSE([controller_ autoFillManaged]);
+
+ // Disable AutoFill through configuration policy.
+ helper_.profile()->GetTestingPrefService()->SetManagedPref(
+ prefs::kAutoFillEnabled, Value::CreateBooleanValue(false));
+ ASSERT_TRUE([controller_ autoFillManaged]);
+ ASSERT_FALSE([controller_ autoFillEnabled]);
+
+ // Enabling through policy should switch to enabled but not editable.
+ helper_.profile()->GetTestingPrefService()->SetManagedPref(
+ prefs::kAutoFillEnabled, Value::CreateBooleanValue(true));
+ ASSERT_TRUE([controller_ autoFillManaged]);
+ ASSERT_TRUE([controller_ autoFillEnabled]);
+
+ [controller_ closeDialog];
+}
+
+TEST_F(AutoFillDialogControllerTest, PolicyDisabledAndSave) {
+ // Disable AutoFill through configuration policy.
+ helper_.profile()->GetTestingPrefService()->SetManagedPref(
+ prefs::kAutoFillEnabled, Value::CreateBooleanValue(false));
+ helper_.profile()->GetPrefs()->SetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled, false);
+ LoadDialog();
+
+ // Save should be disabled.
+ ASSERT_TRUE([controller_ autoFillManagedAndDisabled]);
+
+ [controller_ setAuxiliaryEnabled:YES];
+ [controller_ closeDialog];
+
+ // Observer should not have been called.
+ ASSERT_FALSE(observer_.hit_);
+
+ // Auxiliary profiles setting should be unchanged.
+ ASSERT_FALSE(helper_.profile()->GetPrefs()->GetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled));
+}
+
+TEST_F(AutoFillDialogControllerTest, PolicyEnabledAndSave) {
+ // Enable AutoFill through configuration policy.
+ helper_.profile()->GetTestingPrefService()->SetManagedPref(
+ prefs::kAutoFillEnabled, Value::CreateBooleanValue(true));
+ helper_.profile()->GetPrefs()->SetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled, false);
+ LoadDialog();
+
+ // Save should be enabled.
+ ASSERT_FALSE([controller_ autoFillManagedAndDisabled]);
+
+ [controller_ setAuxiliaryEnabled:YES];
+ [controller_ closeDialog];
+
+ // Observer should not have been notified.
+ ASSERT_FALSE(observer_.hit_);
+
+ // Auxiliary profiles setting should have been saved.
+ ASSERT_TRUE(helper_.profile()->GetPrefs()->GetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled));
+}
+
} // namespace
diff --git a/chrome/browser/autofill/autofill_dialog_gtk.cc b/chrome/browser/autofill/autofill_dialog_gtk.cc
index ec8a1fe..1e6a12b 100644
--- a/chrome/browser/autofill/autofill_dialog_gtk.cc
+++ b/chrome/browser/autofill/autofill_dialog_gtk.cc
@@ -27,8 +27,8 @@
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_member.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer.h"
@@ -234,7 +234,7 @@ void AutoFillDialog::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
- const std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ const std::string* pref_name = Details<std::string>(details).ptr();
if (!pref_name || *pref_name == prefs::kAutoFillEnabled) {
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(form_autofill_enable_check_),
@@ -273,7 +273,7 @@ void AutoFillDialog::OnAutoFillCheckToggled(GtkWidget* widget) {
UserMetrics::RecordAction(UserMetricsAction("Options_FormAutofill_Disable"),
profile_);
}
- enable_form_autofill_.SetValue(enabled);
+ enable_form_autofill_.SetValueIfNotManaged(enabled);
profile_->GetPrefs()->ScheduleSavePersistentPrefs();
UpdateWidgetState();
}
@@ -376,7 +376,7 @@ void AutoFillDialog::LoadAutoFillData() {
return;
}
- // Rebuild the underyling store.
+ // Rebuild the underlying store.
gtk_list_store_clear(list_store_);
GtkTreeIter iter;
@@ -442,7 +442,7 @@ void AutoFillDialog::LoadAutoFillData() {
void AutoFillDialog::InitializeWidgets() {
dialog_ = gtk_dialog_new_with_buttons(
- l10n_util::GetStringUTF8(IDS_AUTOFILL_OPTIONS).c_str(),
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_OPTIONS_TITLE).c_str(),
// AutoFill dialog is shared between all browser windows.
NULL,
// Non-modal.
@@ -546,6 +546,8 @@ void AutoFillDialog::InitializeWidgets() {
}
void AutoFillDialog::UpdateWidgetState() {
+ gtk_widget_set_sensitive(form_autofill_enable_check_,
+ !enable_form_autofill_.IsManaged());
if (!personal_data_->IsDataLoaded() || !enable_form_autofill_.GetValue()) {
gtk_widget_set_sensitive(add_address_button_, FALSE);
gtk_widget_set_sensitive(add_credit_card_button_, FALSE);
diff --git a/chrome/browser/autofill/autofill_dialog_mac.mm b/chrome/browser/autofill/autofill_dialog_mac.mm
index 4e65ac4..f97bad9 100644
--- a/chrome/browser/autofill/autofill_dialog_mac.mm
+++ b/chrome/browser/autofill/autofill_dialog_mac.mm
@@ -4,7 +4,7 @@
#import "chrome/browser/autofill/autofill_dialog_controller_mac.h"
#include "chrome/browser/autofill/autofill_dialog.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
@@ -13,10 +13,7 @@
void ShowAutoFillDialog(gfx::NativeView parent,
AutoFillDialogObserver* observer,
Profile* profile) {
- // TODO: get rid of imported profile and credit card.
[AutoFillDialogController
showAutoFillDialogWithObserver:observer
- profile:profile
- importedProfile:NULL
- importedCreditCard:NULL];
+ profile:profile];
}
diff --git a/chrome/browser/autofill/autofill_download.cc b/chrome/browser/autofill/autofill_download.cc
index 8407d80..73ee70a 100644
--- a/chrome/browser/autofill/autofill_download.cc
+++ b/chrome/browser/autofill/autofill_download.cc
@@ -10,7 +10,7 @@
#include "base/rand_util.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/autofill/autofill_xml_parser.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "net/http/http_response_headers.h"
@@ -175,7 +175,7 @@ bool AutoFillDownloadManager::StartRequest(
URLFetcher::POST,
this);
url_fetchers_[fetcher] = request_data;
- fetcher->set_automatcally_retry_on_5xx(false);
+ fetcher->set_automatically_retry_on_5xx(false);
fetcher->set_request_context(Profile::GetDefaultRequestContext());
fetcher->set_upload_data("text/plain", form_xml);
fetcher->Start();
diff --git a/chrome/browser/autofill/autofill_download.h b/chrome/browser/autofill/autofill_download.h
index 34b2554..2befb00 100644
--- a/chrome/browser/autofill/autofill_download.h
+++ b/chrome/browser/autofill/autofill_download.h
@@ -4,14 +4,13 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_DOWNLOAD_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_DOWNLOAD_H_
+#pragma once
#include <map>
#include <vector>
#include <string>
-#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
-#include "base/string16.h"
#include "base/time.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/field_types.h"
diff --git a/chrome/browser/autofill/autofill_download_unittest.cc b/chrome/browser/autofill/autofill_download_unittest.cc
index 3074ecd..baecd97 100644
--- a/chrome/browser/autofill/autofill_download_unittest.cc
+++ b/chrome/browser/autofill/autofill_download_unittest.cc
@@ -5,6 +5,7 @@
#include <list>
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_download.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
#include "chrome/test/testing_profile.h"
@@ -147,7 +148,7 @@ TEST(AutoFillDownloadTest, QueryAndUploadTest) {
ASCIIToUTF16("text"),
0));
form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("city"),
- ASCIIToUTF16("address2"),
+ ASCIIToUTF16("city"),
string16(),
ASCIIToUTF16("text"),
0));
diff --git a/chrome/browser/autofill/autofill_field.cc b/chrome/browser/autofill/autofill_field.cc
index 3ba943a..9503f7c 100644
--- a/chrome/browser/autofill/autofill_field.cc
+++ b/chrome/browser/autofill/autofill_field.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "base/sha1.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
namespace {
@@ -20,7 +20,7 @@ static std::string Hash32Bit(const std::string& str) {
((hash_bin[2] & 0xFF) << 8) |
(hash_bin[3] & 0xFF);
- return UintToString(hash32);
+ return base::UintToString(hash32);
}
} // namespace
diff --git a/chrome/browser/autofill/autofill_field.h b/chrome/browser/autofill/autofill_field.h
index 7411fc2..e0fe324 100644
--- a/chrome/browser/autofill/autofill_field.h
+++ b/chrome/browser/autofill/autofill_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/autofill/autofill_field_unittest.cc b/chrome/browser/autofill/autofill_field_unittest.cc
index 48d29ec..712ddf8 100644
--- a/chrome/browser/autofill/autofill_field_unittest.cc
+++ b/chrome/browser/autofill/autofill_field_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/field_types.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index bbb6b5d..9d94997 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -4,16 +4,24 @@
#include "chrome/browser/autofill/autofill_manager.h"
+#include <limits>
#include <string>
#include "base/basictypes.h"
#include "base/string16.h"
+<<<<<<< HEAD
#include "chrome/browser/autofill/autofill_dialog.h"
#ifndef ANDROID
#include "chrome/browser/autofill/autofill_cc_infobar_delegate.h"
#endif
+=======
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/autofill_cc_infobar_delegate.h"
+#include "chrome/browser/autofill/autofill_dialog.h"
+>>>>>>> Chromium at release 7.0.540.0
#include "chrome/browser/autofill/form_structure.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/autofill/select_control_handler.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#ifndef ANDROID
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -45,36 +53,54 @@ const int kAutoFillPhoneNumberPrefixCount = 3;
const int kAutoFillPhoneNumberSuffixOffset = 3;
const int kAutoFillPhoneNumberSuffixCount = 4;
-const string16::value_type kLabelSeparator[] = {';',' ',0};
+const string16::value_type kCreditCardPrefix[] = {'*',0};
+const string16::value_type kLabelSeparator[] = {';',' ','*',0};
+
+// Combines the |label| string with the last four digits of the credit card
+// |cc|. If one, the other, or both are empty strings we omit the separator.
+string16 CombineLabelAndCreditCard(const string16& label,
+ const CreditCard* cc) {
+ if (label.empty())
+ return kCreditCardPrefix + cc->LastFourDigits();
+ else if (cc->LastFourDigits().empty())
+ return label;
+ else
+ return label + kLabelSeparator + cc->LastFourDigits();
+}
// Removes duplicate elements whilst preserving original order of |elements| and
// |unique_ids|.
void RemoveDuplicateElements(
std::vector<string16>* elements, std::vector<int>* unique_ids) {
- std::vector<string16> copy;
+ DCHECK_EQ(elements->size(), unique_ids->size());
+
+ std::vector<string16> elements_copy;
+ std::vector<int> unique_ids_copy;
for (size_t i = 0; i < elements->size(); ++i) {
const string16& element = (*elements)[i];
bool unique = true;
- for (std::vector<string16>::const_iterator copy_iter = copy.begin();
- copy_iter != copy.end(); ++copy_iter) {
+ for (std::vector<string16>::const_iterator copy_iter
+ = elements_copy.begin();
+ copy_iter != elements_copy.end(); ++copy_iter) {
if (element == *copy_iter) {
unique = false;
break;
}
}
- if (unique)
- copy.push_back(element);
- else
- unique_ids->erase(unique_ids->begin() + i);
+ if (unique) {
+ elements_copy.push_back(element);
+ unique_ids_copy.push_back((*unique_ids)[i]);
+ }
}
- elements->assign(copy.begin(), copy.end());
+ elements->assign(elements_copy.begin(), elements_copy.end());
+ unique_ids->assign(unique_ids_copy.begin(), unique_ids_copy.end());
}
bool FormIsHTTPS(FormStructure* form) {
- return form->ConvertToFormData().origin.SchemeIs(chrome::kHttpsScheme);
+ return form->source_url().SchemeIs(chrome::kHttpsScheme);
}
} // namespace
@@ -86,7 +112,9 @@ const char* kAutoFillLearnMoreUrl =
AutoFillManager::AutoFillManager(TabContents* tab_contents)
: tab_contents_(tab_contents),
personal_data_(NULL),
- download_manager_(tab_contents_->profile()) {
+ download_manager_(tab_contents_->profile()),
+ disable_download_manager_requests_(false),
+ cc_infobar_(NULL) {
DCHECK(tab_contents);
// |personal_data_| is NULL when using TestTabContents.
@@ -125,6 +153,10 @@ void AutoFillManager::FormSubmitted(const FormData& form) {
if (tab_contents_->profile()->IsOffTheRecord())
return;
+ // Don't save data that was submitted through JavaScript.
+ if (!form.user_submitted)
+ return;
+
// Grab a copy of the form data.
upload_form_structure_.reset(new FormStructure(form));
@@ -141,11 +173,6 @@ void AutoFillManager::FormsSeen(const std::vector<FormData>& forms) {
if (!IsAutoFillEnabled())
return;
- // No profiles or credit cards, no need to parse the forms.
- if (personal_data_->profiles().empty() &&
- personal_data_->credit_cards().empty())
- return;
-
ParseForms(forms);
}
@@ -175,7 +202,7 @@ bool AutoFillManager::GetAutoFillSuggestions(int query_id,
AutoFillField* autofill_field = NULL;
for (std::vector<FormStructure*>::iterator form_iter =
form_structures_.begin();
- form_iter != form_structures_.end(); ++form_iter) {
+ form_iter != form_structures_.end() && !autofill_field; ++form_iter) {
form = *form_iter;
// Don't send suggestions for forms that aren't auto-fillable.
@@ -196,11 +223,12 @@ bool AutoFillManager::GetAutoFillSuggestions(int query_id,
}
}
- if (autofill_field == NULL)
+ if (!autofill_field)
return false;
std::vector<string16> values;
std::vector<string16> labels;
+ std::vector<string16> icons;
std::vector<int> unique_ids;
AutoFillType type(autofill_field->type());
@@ -209,15 +237,17 @@ bool AutoFillManager::GetAutoFillSuggestions(int query_id,
bool handle_billing = FormIsHTTPS(form);
if (type.group() == AutoFillType::CREDIT_CARD)
- GetCreditCardSuggestions(form, field, type, &values, &labels, &unique_ids);
+ GetCreditCardSuggestions(
+ form, field, type, &values, &labels, &icons, &unique_ids);
else if (type.group() == AutoFillType::ADDRESS_BILLING)
GetBillingProfileSuggestions(
- form, field, type, &values, &labels, &unique_ids);
+ form, field, type, &values, &labels, &icons, &unique_ids);
else
- GetProfileSuggestions(
- form, field, type, handle_billing, &values, &labels, &unique_ids);
+ GetProfileSuggestions(form, field, type, handle_billing,
+ &values, &labels, &icons, &unique_ids);
DCHECK_EQ(values.size(), labels.size());
+ DCHECK_EQ(values.size(), icons.size());
DCHECK_EQ(values.size(), unique_ids.size());
// No suggestions.
@@ -231,20 +261,21 @@ bool AutoFillManager::GetAutoFillSuggestions(int query_id,
if (form_autofilled) {
RemoveDuplicateElements(&values, &unique_ids);
labels.resize(values.size());
+ icons.resize(values.size());
- for (size_t i = 0; i < labels.size(); ++i)
+ for (size_t i = 0; i < labels.size(); ++i) {
labels[i] = string16();
+ icons[i] = string16();
+ }
}
- host->AutoFillSuggestionsReturned(query_id, values, labels, unique_ids);
+ host->AutoFillSuggestionsReturned(
+ query_id, values, labels, icons, unique_ids);
return true;
}
-// TODO(jhawkins): Remove the |value| parameter.
bool AutoFillManager::FillAutoFillFormData(int query_id,
const FormData& form,
- const string16& value,
- const string16& label,
int unique_id) {
if (!IsAutoFillEnabled())
return false;
@@ -283,39 +314,29 @@ bool AutoFillManager::FillAutoFillFormData(int query_id,
if (!form_structure->autofill_count())
return false;
- // |cc_digits| will contain the last four digits of a credit card number only
- // if the form has billing fields.
- string16 cc_digits;
-
- // If the form has billing fields, |label| will contain at least one "; "
- // followed by the last four digits of a credit card number.
- if (form_structure->HasBillingFields()) {
- // We must search for the last "; " as it's possible the profile label
- // proper can contain this sequence of characters.
- size_t index = label.find_last_of(kLabelSeparator);
- if (index != string16::npos) {
- size_t cc_index = index + 1;
- cc_digits = label.substr(cc_index);
- }
- }
+ // Unpack the |unique_id| into component parts.
+ int cc_id = 0;
+ int profile_id = 0;
+ UnpackIDs(unique_id, &cc_id, &profile_id);
- // Find the profile that matches the |unique_id|.
+ // Find the profile that matches the |profile_id|, if one is specified.
const AutoFillProfile* profile = NULL;
- for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
- iter != profiles.end(); ++iter) {
- if ((*iter)->unique_id() == unique_id) {
- profile = *iter;
+ if (profile_id != 0) {
+ for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
+ iter != profiles.end(); ++iter) {
+ if ((*iter)->unique_id() == profile_id) {
+ profile = *iter;
+ break;
+ }
}
}
- // Don't look for a matching credit card if we fully-matched the profile using
- // the entire label.
+ // Find the credit card that matches the |cc_id|, if one is specified.
const CreditCard* credit_card = NULL;
- if (!cc_digits.empty()) {
- // Find the credit card that matches the |cc_label|.
+ if (cc_id != 0) {
for (std::vector<CreditCard*>::const_iterator iter = credit_cards.begin();
iter != credit_cards.end(); ++iter) {
- if ((*iter)->LastFourDigits() == cc_digits) {
+ if ((*iter)->unique_id() == cc_id) {
credit_card = *iter;
break;
}
@@ -351,8 +372,7 @@ bool AutoFillManager::FillAutoFillFormData(int query_id,
AutoFillType autofill_type(field->type());
if (credit_card &&
autofill_type.group() == AutoFillType::CREDIT_CARD) {
- result.fields[i].set_value(
- credit_card->GetFieldText(autofill_type));
+ FillCreditCardFormField(credit_card, autofill_type, &result.fields[j]);
} else if (credit_card &&
autofill_type.group() == AutoFillType::ADDRESS_BILLING) {
FillBillingFormField(credit_card, autofill_type, &result.fields[j]);
@@ -364,6 +384,7 @@ bool AutoFillManager::FillAutoFillFormData(int query_id,
// proceed to the next |result| field, and the next |form_structure|.
++i;
}
+ autofilled_forms_signatures_.push_front(form_structure->FormSignature());
host->AutoFillFormDataFilled(query_id, result);
return true;
@@ -444,20 +465,47 @@ void AutoFillManager::HandleSubmit() {
CreditCard* credit_card;
personal_data_->GetImportedFormData(&profile, &credit_card);
+<<<<<<< HEAD
if (credit_card) {
#ifndef ANDROID
cc_infobar_.reset(new AutoFillCCInfoBarDelegate(tab_contents_, this));
#endif
} else {
+=======
+ if (!credit_card) {
+>>>>>>> Chromium at release 7.0.540.0
UploadFormData();
+ return;
+ }
+
+ // Show an infobar to offer to save the credit card info.
+ if (tab_contents_) {
+ tab_contents_->AddInfoBar(new AutoFillCCInfoBarDelegate(tab_contents_,
+ this));
}
}
void AutoFillManager::UploadFormData() {
- // TODO(georgey): enable upload request when we make sure that our data is in
- // line with toolbar data:
- // download_manager_.StartUploadRequest(upload_form_structure_,
- // form_is_autofilled);
+ if (!disable_download_manager_requests_ && upload_form_structure_.get()) {
+ bool was_autofilled = false;
+ // Check if the form among last 3 forms that were auto-filled.
+ // Clear older signatures.
+ std::list<std::string>::iterator it;
+ int total_form_checked = 0;
+ for (it = autofilled_forms_signatures_.begin();
+ it != autofilled_forms_signatures_.end() && total_form_checked < 3;
+ ++it, ++total_form_checked) {
+ if (*it == upload_form_structure_->FormSignature())
+ was_autofilled = true;
+ }
+ // Remove outdated form signatures.
+ if (total_form_checked == 3 && it != autofilled_forms_signatures_.end()) {
+ autofilled_forms_signatures_.erase(it,
+ autofilled_forms_signatures_.end());
+ }
+ download_manager_.StartUploadRequest(*(upload_form_structure_.get()),
+ was_autofilled);
+ }
}
void AutoFillManager::OnInfoBarClosed(bool should_save) {
@@ -469,14 +517,18 @@ void AutoFillManager::OnInfoBarClosed(bool should_save) {
AutoFillManager::AutoFillManager()
: tab_contents_(NULL),
personal_data_(NULL),
- download_manager_(NULL) {
+ download_manager_(NULL),
+ disable_download_manager_requests_(false),
+ cc_infobar_(NULL) {
}
AutoFillManager::AutoFillManager(TabContents* tab_contents,
PersonalDataManager* personal_data)
: tab_contents_(tab_contents),
personal_data_(personal_data),
- download_manager_(NULL) {
+ download_manager_(NULL),
+ disable_download_manager_requests_(false),
+ cc_infobar_(NULL) {
DCHECK(tab_contents);
}
@@ -486,6 +538,7 @@ void AutoFillManager::GetProfileSuggestions(FormStructure* form,
bool include_cc_labels,
std::vector<string16>* values,
std::vector<string16>* labels,
+ std::vector<string16>* icons,
std::vector<int>* unique_ids) {
const std::vector<AutoFillProfile*>& profiles = personal_data_->profiles();
std::vector<AutoFillProfile*> matched_profiles;
@@ -500,19 +553,22 @@ void AutoFillManager::GetProfileSuggestions(FormStructure* form,
StartsWith(profile_field_value, field.value(), false)) {
matched_profiles.push_back(profile);
values->push_back(profile_field_value);
- unique_ids->push_back(profile->unique_id());
+ unique_ids->push_back(PackIDs(0, profile->unique_id()));
}
}
AutoFillProfile::CreateInferredLabels(&matched_profiles, labels, 0,
type.field_type());
- if (!include_cc_labels || !form->HasBillingFields() || !FormIsHTTPS(form))
+ if (!include_cc_labels || !form->HasBillingFields() || !FormIsHTTPS(form)) {
+ icons->resize(values->size()); // No CC, so no icons.
return;
+ }
size_t i = 0;
std::vector<string16> expanded_values;
std::vector<string16> expanded_labels;
+ std::vector<int> expanded_ids;
for (std::vector<AutoFillProfile*>::const_iterator iter =
matched_profiles.begin(); iter != matched_profiles.end();
++iter, ++i) {
@@ -521,14 +577,16 @@ void AutoFillManager::GetProfileSuggestions(FormStructure* form,
personal_data_->credit_cards().begin();
cc != personal_data_->credit_cards().end(); ++cc) {
expanded_values.push_back((*values)[i]);
- string16 label = (*labels)[i] + kLabelSeparator +
- (*cc)->LastFourDigits();
+ string16 label = CombineLabelAndCreditCard((*labels)[i], *cc);
expanded_labels.push_back(label);
- unique_ids->push_back(profile->unique_id());
+ icons->push_back((*cc)->type());
+ expanded_ids.push_back(PackIDs((*cc)->unique_id(), profile->unique_id()));
}
}
+
expanded_labels.swap(*labels);
expanded_values.swap(*values);
+ expanded_ids.swap(*unique_ids);
}
void AutoFillManager::GetBillingProfileSuggestions(
@@ -537,24 +595,27 @@ void AutoFillManager::GetBillingProfileSuggestions(
AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels,
+ std::vector<string16>* icons,
std::vector<int>* unique_ids) {
- std::vector<CreditCard*> matching_creditcards;
- std::vector<AutoFillProfile*> matching_profiles;
- std::vector<string16> cc_values;
- std::vector<string16> cc_labels;
// If the form is non-HTTPS, no CC suggestions are provided; however, give the
// user the option of filling the billing address fields with regular address
// data.
if (!FormIsHTTPS(form)) {
- GetProfileSuggestions(form, field, type, false, values, labels, unique_ids);
+ GetProfileSuggestions(
+ form, field, type, false, values, icons, labels, unique_ids);
return;
}
+ std::vector<CreditCard*> matching_creditcards;
+ std::vector<AutoFillProfile*> matching_profiles;
+
+ // Collect matching pairs of credit cards and related profiles, where profile
+ // field value matches form field value.
for (std::vector<CreditCard*>::const_iterator cc =
personal_data_->credit_cards().begin();
cc != personal_data_->credit_cards().end(); ++cc) {
- string16 label = (*cc)->billing_address();
+ int billing_address_id = (*cc)->billing_address_id();
AutoFillProfile* billing_profile = NULL;
// The value of the stored data for this field type in the |profile|.
@@ -566,7 +627,7 @@ void AutoFillManager::GetBillingProfileSuggestions(
AutoFillProfile* profile = *iter;
// This assumes that labels are unique.
- if (profile->Label() == label &&
+ if (profile->unique_id() == billing_address_id &&
!profile->GetFieldText(type).empty() &&
StartsWith(profile->GetFieldText(type), field.value(), false)) {
billing_profile = profile;
@@ -577,17 +638,27 @@ void AutoFillManager::GetBillingProfileSuggestions(
if (!billing_profile)
continue;
- for (std::vector<AutoFillProfile*>::const_iterator iter =
- personal_data_->profiles().begin();
- iter != personal_data_->profiles().end(); ++iter) {
- values->push_back(billing_profile->GetFieldText(type));
+ matching_creditcards.push_back(*cc);
+ matching_profiles.push_back(billing_profile);
+ }
- string16 label = (*iter)->Label() +
- ASCIIToUTF16("; ") +
- (*cc)->LastFourDigits();
- labels->push_back(label);
- unique_ids->push_back((*iter)->unique_id());
- }
+ std::vector<string16> inferred_labels;
+ AutoFillProfile::CreateInferredLabels(&matching_profiles, &inferred_labels, 0,
+ type.field_type());
+
+ DCHECK_EQ(matching_profiles.size(), matching_creditcards.size());
+ DCHECK_EQ(matching_profiles.size(), inferred_labels.size());
+
+ // Process the matching pairs into suggested |values|, |labels|, and
+ // |unique_ids|.
+ for (size_t i = 0; i < matching_profiles.size(); ++i) {
+ values->push_back(matching_profiles[i]->GetFieldText(type));
+ string16 label = CombineLabelAndCreditCard(inferred_labels[i],
+ matching_creditcards[i]);
+ labels->push_back(label);
+ icons->push_back(matching_creditcards[i]->type());
+ unique_ids->push_back(PackIDs(matching_creditcards[i]->unique_id(),
+ matching_profiles[i]->unique_id()));
}
}
@@ -596,6 +667,7 @@ void AutoFillManager::GetCreditCardSuggestions(FormStructure* form,
AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels,
+ std::vector<string16>* icons,
std::vector<int>* unique_ids) {
// Don't return CC suggestions for non-HTTPS pages.
if (!FormIsHTTPS(form))
@@ -607,8 +679,7 @@ void AutoFillManager::GetCreditCardSuggestions(FormStructure* form,
CreditCard* credit_card = *iter;
// The value of the stored data for this field type in the |credit_card|.
- string16 creditcard_field_value =
- credit_card->GetFieldText(type);
+ string16 creditcard_field_value = credit_card->GetFieldText(type);
if (!creditcard_field_value.empty() &&
StartsWith(creditcard_field_value, field.value(), false)) {
if (type.field_type() == CREDIT_CARD_NUMBER)
@@ -616,19 +687,28 @@ void AutoFillManager::GetCreditCardSuggestions(FormStructure* form,
if (!form->HasNonBillingFields()) {
values->push_back(creditcard_field_value);
- labels->push_back(credit_card->Label());
- unique_ids->push_back(credit_card->unique_id());
+ labels->push_back(CombineLabelAndCreditCard(string16(), credit_card));
+ icons->push_back(credit_card->type());
+ unique_ids->push_back(PackIDs(credit_card->unique_id(), 0));
} else {
- for (std::vector<AutoFillProfile*>::const_iterator iter =
- personal_data_->profiles().begin();
- iter != personal_data_->profiles().end(); ++iter) {
+ const std::vector<AutoFillProfile*>& profiles
+ = personal_data_->profiles();
+ std::vector<string16> inferred_labels;
+ AutoFillProfile::CreateInferredLabels(&profiles,
+ &inferred_labels,
+ 0,
+ type.field_type());
+ DCHECK_EQ(profiles.size(), inferred_labels.size());
+
+ for (size_t i = 0; i < profiles.size(); ++i) {
values->push_back(creditcard_field_value);
- string16 label = (*iter)->Label() +
- ASCIIToUTF16("; ") +
- credit_card->LastFourDigits();
+ string16 label = CombineLabelAndCreditCard(inferred_labels[i],
+ credit_card);
labels->push_back(label);
- unique_ids->push_back((*iter)->unique_id());
+ icons->push_back(credit_card->type());
+ unique_ids->push_back(
+ PackIDs(credit_card->unique_id(), profiles[i]->unique_id()));
}
}
}
@@ -642,13 +722,13 @@ void AutoFillManager::FillBillingFormField(const CreditCard* credit_card,
DCHECK(type.group() == AutoFillType::ADDRESS_BILLING);
DCHECK(field);
- string16 billing_address = credit_card->billing_address();
- if (!billing_address.empty()) {
+ int billing_address_id = credit_card->billing_address_id();
+ if (billing_address_id != 0) {
AutoFillProfile* profile = NULL;
const std::vector<AutoFillProfile*>& profiles = personal_data_->profiles();
for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
iter != profiles.end(); ++iter) {
- if ((*iter)->Label() == billing_address) {
+ if ((*iter)->unique_id() == billing_address_id) {
profile = *iter;
break;
}
@@ -660,6 +740,18 @@ void AutoFillManager::FillBillingFormField(const CreditCard* credit_card,
}
}
+void AutoFillManager::FillCreditCardFormField(const CreditCard* credit_card,
+ AutoFillType type,
+ webkit_glue::FormField* field) {
+ DCHECK(credit_card);
+ DCHECK(field);
+
+ if (field->form_control_type() == ASCIIToUTF16("select-one"))
+ autofill::FillSelectControl(credit_card, type, field);
+ else
+ field->set_value(credit_card->GetFieldText(type));
+}
+
void AutoFillManager::FillFormField(const AutoFillProfile* profile,
AutoFillType type,
webkit_glue::FormField* field) {
@@ -670,7 +762,7 @@ void AutoFillManager::FillFormField(const AutoFillProfile* profile,
FillPhoneNumberField(profile, field);
} else {
if (field->form_control_type() == ASCIIToUTF16("select-one"))
- FillSelectOneField(profile, type, field);
+ autofill::FillSelectControl(profile, type, field);
else
field->set_value(profile->GetFieldText(type));
}
@@ -728,15 +820,36 @@ void AutoFillManager::ParseForms(
for (std::vector<FormData>::const_iterator iter =
forms.begin();
iter != forms.end(); ++iter) {
- FormStructure* form_structure = new FormStructure(*iter);
+ scoped_ptr<FormStructure> form_structure(new FormStructure(*iter));
if (!form_structure->ShouldBeParsed())
continue;
- DeterminePossibleFieldTypes(form_structure);
- form_structures_.push_back(form_structure);
+ DeterminePossibleFieldTypes(form_structure.get());
+ form_structures_.push_back(form_structure.release());
}
// If none of the forms were parsed, no use querying the server.
- if (!form_structures_.empty())
+ if (!form_structures_.empty() && !disable_download_manager_requests_)
download_manager_.StartQueryRequest(form_structures_);
}
+
+// When sending IDs (across processes) to the renderer we pack credit card and
+// profile IDs into a single integer. Credit card IDs are sent in the high
+// word and profile IDs are sent in the low word.
+// static
+int AutoFillManager::PackIDs(int cc_id, int profile_id) {
+ DCHECK(cc_id <= std::numeric_limits<unsigned short>::max());
+ DCHECK(profile_id <= std::numeric_limits<unsigned short>::max());
+
+ return cc_id << std::numeric_limits<unsigned short>::digits | profile_id;
+}
+
+// When receiving IDs (across processes) from the renderer we unpack credit card
+// and profile IDs from a single integer. Credit card IDs are stored in the
+// high word and profile IDs are stored in the low word.
+// static
+void AutoFillManager::UnpackIDs(int id, int* cc_id, int* profile_id) {
+ *cc_id = id >> std::numeric_limits<unsigned short>::digits &
+ std::numeric_limits<unsigned short>::max();
+ *profile_id = id & std::numeric_limits<unsigned short>::max();
+}
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index bc499fa..69e3523 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -4,10 +4,13 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_MANAGER_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_MANAGER_H_
+#pragma once
#include <vector>
#include <string>
+#include <list>
+#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
#include "chrome/browser/autofill/autofill_dialog.h"
@@ -51,6 +54,9 @@ class AutoFillManager :
// Registers our Enable/Disable AutoFill pref.
static void RegisterUserPrefs(PrefService* prefs);
+ // Returns the TabContents hosting this AutoFillManager.
+ TabContents* tab_contents() const { return tab_contents_; }
+
// RenderViewHostDelegate::AutoFill implementation:
virtual void FormSubmitted(const webkit_glue::FormData& form);
virtual void FormsSeen(const std::vector<webkit_glue::FormData>& forms);
@@ -59,8 +65,6 @@ class AutoFillManager :
const webkit_glue::FormField& field);
virtual bool FillAutoFillFormData(int query_id,
const webkit_glue::FormData& form,
- const string16& value,
- const string16& label,
int unique_id);
virtual void ShowAutoFillDialog();
@@ -97,6 +101,7 @@ class AutoFillManager :
AutoFillManager();
AutoFillManager(TabContents* tab_contents,
PersonalDataManager* personal_data);
+
void set_personal_data_manager(PersonalDataManager* personal_data) {
personal_data_ = personal_data;
}
@@ -105,7 +110,7 @@ class AutoFillManager :
// Returns a list of values from the stored profiles that match |type| and the
// value of |field| and returns the labels of the matching profiles. |labels|
// is filled with the Profile label and possibly the last four digits of a
- // corresponding credit card: 'Home; 1258' - Home is the Profile label and
+ // corresponding credit card: 'Home; *1258' - Home is the Profile label and
// 1258 is the last four digits of the credit card. If |include_cc_labels| is
// true, check for billing fields and append CC digits to the labels;
// otherwise, regular profiles are returned for billing address fields.
@@ -115,6 +120,7 @@ class AutoFillManager :
bool include_cc_labels,
std::vector<string16>* values,
std::vector<string16>* labels,
+ std::vector<string16>* icons,
std::vector<int>* unique_ids);
// Same as GetProfileSuggestions, but the list of stored profiles is limited
@@ -124,6 +130,7 @@ class AutoFillManager :
AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels,
+ std::vector<string16>* icons,
std::vector<int>* unique_ids);
// Returns a list of values from the stored credit cards that match |type| and
@@ -133,6 +140,7 @@ class AutoFillManager :
AutoFillType type,
std::vector<string16>* values,
std::vector<string16>* labels,
+ std::vector<string16>* icons,
std::vector<int>* unique_ids);
// Set |field| argument's value based on |type| and contents of the
@@ -143,6 +151,12 @@ class AutoFillManager :
AutoFillType type,
webkit_glue::FormField* field);
+ // Set |field| argument's value based on |type| and contents of the
+ // |credit_card|.
+ void FillCreditCardFormField(const CreditCard* credit_card,
+ AutoFillType type,
+ webkit_glue::FormField* field);
+
// Set |field| argument's value based on |type| and contents of the |profile|.
void FillFormField(const AutoFillProfile* profile,
AutoFillType type,
@@ -163,6 +177,16 @@ class AutoFillManager :
// Parses the forms using heuristic matching and querying the AutoFill server.
void ParseForms(const std::vector<webkit_glue::FormData>& forms);
+ // Methods for packing and unpacking credit card and profile IDs for sending
+ // and receiving to and from the renderer process.
+ static int PackIDs(int cc_id, int profile_id);
+ static void UnpackIDs(int id, int* cc_id, int* profile_id);
+
+ // 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;
+ }
+
// The TabContents hosting this AutoFillManager.
// Weak reference.
// May not be NULL.
@@ -174,9 +198,15 @@ class AutoFillManager :
// May be NULL. NULL indicates OTR.
PersonalDataManager* personal_data_;
+ std::list<std::string> autofilled_forms_signatures_;
// Handles queries and uploads to AutoFill servers.
AutoFillDownloadManager download_manager_;
+ // Should be set to true in AutoFillManagerTest and other tests, false in
+ // AutoFillDownloadManagerTest and in non-test environment. Is false by
+ // default.
+ bool disable_download_manager_requests_;
+
// Our copy of the form data.
ScopedVector<FormStructure> form_structures_;
@@ -185,8 +215,18 @@ class AutoFillManager :
#ifndef ANDROID
// The InfoBar that asks for permission to store credit card information.
+<<<<<<< HEAD
scoped_ptr<AutoFillCCInfoBarDelegate> cc_infobar_;
#endif
+=======
+ // Deletes itself when closed.
+ AutoFillCCInfoBarDelegate* cc_infobar_;
+
+ friend class TestAutoFillManager;
+ FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillCreditCardForm);
+ FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillNonBillingFormSemicolon);
+ FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillBillFormSemicolon);
+>>>>>>> Chromium at release 7.0.540.0
DISALLOW_COPY_AND_ASSIGN(AutoFillManager);
};
diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc
index a9a915d..c84d482 100644
--- a/chrome/browser/autofill/autofill_manager_unittest.cc
+++ b/chrome/browser/autofill/autofill_manager_unittest.cc
@@ -9,12 +9,13 @@
#include "base/scoped_vector.h"
#include "base/string16.h"
#include "base/tuple.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_common_unittest.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/autofill/personal_data_manager.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
@@ -28,9 +29,8 @@
using webkit_glue::FormData;
-namespace {
-
-typedef Tuple4<int,
+typedef Tuple5<int,
+ std::vector<string16>,
std::vector<string16>,
std::vector<string16>,
std::vector<int> > AutoFillParam;
@@ -44,6 +44,7 @@ class TestPersonalDataManager : public PersonalDataManager {
virtual void InitializeIfNeeded() {}
virtual void SaveImportedFormData() {}
+ virtual bool IsDataLoaded() const { return true; }
AutoFillProfile* GetLabeledProfile(const char* label) {
for (std::vector<AutoFillProfile *>::iterator it = web_profiles_.begin();
@@ -87,18 +88,18 @@ class TestPersonalDataManager : public PersonalDataManager {
CreditCard* credit_card = new CreditCard;
autofill_unittest::SetCreditCardInfo(credit_card, "First", "Elvis Presley",
"Visa", "1234567890123456", "04",
- "2012", "Home");
+ "2012", 1);
credit_card->set_unique_id(4);
credit_cards->push_back(credit_card);
credit_card = new CreditCard;
autofill_unittest::SetCreditCardInfo(credit_card, "Second", "Buddy Holly",
"Mastercard", "0987654321098765", "10",
- "2014", "");
+ "2014", 2);
credit_card->set_unique_id(5);
credit_cards->push_back(credit_card);
credit_card = new CreditCard;
autofill_unittest::SetCreditCardInfo(credit_card, "Empty", "", "", "", "",
- "", "");
+ "", 3);
credit_card->set_unique_id(6);
credit_cards->push_back(credit_card);
}
@@ -108,10 +109,14 @@ class TestPersonalDataManager : public PersonalDataManager {
class TestAutoFillManager : public AutoFillManager {
public:
- explicit TestAutoFillManager(TabContents* tab_contents)
+ TestAutoFillManager(TabContents* tab_contents,
+ TestPersonalDataManager* personal_manager)
: AutoFillManager(tab_contents, NULL) {
- test_personal_data_ = new TestPersonalDataManager();
- set_personal_data_manager(test_personal_data_.get());
+ test_personal_data_ = personal_manager;
+ set_personal_data_manager(personal_manager);
+ // Download manager requests are disabled for purposes of this unit-test.
+ // These request are tested in autofill_download_unittest.cc.
+ set_disable_download_manager_requests(true);
}
virtual bool IsAutoFillEnabled() const { return true; }
@@ -125,7 +130,7 @@ class TestAutoFillManager : public AutoFillManager {
}
private:
- scoped_refptr<TestPersonalDataManager> test_personal_data_;
+ TestPersonalDataManager* test_personal_data_;
DISALLOW_COPY_AND_ASSIGN(TestAutoFillManager);
};
@@ -135,6 +140,7 @@ void CreateTestFormData(FormData* form) {
form->method = ASCIIToUTF16("POST");
form->origin = GURL("http://myform.com/form.html");
form->action = GURL("http://myform.com/submit.html");
+ form->user_submitted = true;
webkit_glue::FormField field;
autofill_unittest::CreateTestFormField(
@@ -177,6 +183,7 @@ void CreateTestFormDataBilling(FormData* form) {
form->method = ASCIIToUTF16("POST");
form->origin = GURL("https://myform.com/form.html");
form->action = GURL("https://myform.com/submit.html");
+ form->user_submitted = true;
webkit_glue::FormField field;
autofill_unittest::CreateTestFormField(
@@ -229,10 +236,18 @@ void CreateTestFormDataBilling(FormData* form) {
class AutoFillManagerTest : public RenderViewHostTestHarness {
public:
AutoFillManagerTest() {}
+ virtual ~AutoFillManagerTest() {
+ // 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();
- autofill_manager_.reset(new TestAutoFillManager(contents()));
+ test_personal_data_ = new TestPersonalDataManager();
+ autofill_manager_.reset(new TestAutoFillManager(contents(),
+ test_personal_data_.get()));
}
Profile* profile() { return contents()->profile(); }
@@ -274,6 +289,7 @@ class AutoFillManagerTest : public RenderViewHostTestHarness {
protected:
scoped_ptr<TestAutoFillManager> autofill_manager_;
+ scoped_refptr<TestPersonalDataManager> test_personal_data_;
private:
DISALLOW_COPY_AND_ASSIGN(AutoFillManagerTest);
@@ -387,12 +403,12 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsEmptyValue) {
EXPECT_EQ(ASCIIToUTF16("************8765"), values[4]);
EXPECT_EQ(ASCIIToUTF16("************8765"), values[5]);
ASSERT_EQ(6U, labels.size());
- EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
- EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
- EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
- EXPECT_EQ(ASCIIToUTF16("Home; 8765"), labels[3]);
- EXPECT_EQ(ASCIIToUTF16("Work; 8765"), labels[4]);
- EXPECT_EQ(ASCIIToUTF16("Empty; 8765"), labels[5]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("*3456"), labels[2]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *8765"), labels[3]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *8765"), labels[4]);
+ EXPECT_EQ(ASCIIToUTF16("*8765"), labels[5]);
}
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
@@ -428,9 +444,9 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
EXPECT_EQ(ASCIIToUTF16("************3456"), values[1]);
EXPECT_EQ(ASCIIToUTF16("************3456"), values[2]);
ASSERT_EQ(3U, labels.size());
- EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
- EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
- EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("*3456"), labels[2]);
}
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
@@ -469,12 +485,12 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[4]);
EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[5]);
ASSERT_EQ(6U, labels.size());
- EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
- EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
- EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
- EXPECT_EQ(ASCIIToUTF16("Home; 8765"), labels[3]);
- EXPECT_EQ(ASCIIToUTF16("Work; 8765"), labels[4]);
- EXPECT_EQ(ASCIIToUTF16("Empty; 8765"), labels[5]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("*3456"), labels[2]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *8765"), labels[3]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *8765"), labels[4]);
+ EXPECT_EQ(ASCIIToUTF16("*8765"), labels[5]);
}
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsSemicolon) {
@@ -524,14 +540,14 @@ TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsSemicolon) {
EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[6]);
EXPECT_EQ(ASCIIToUTF16("Buddy Holly"), values[7]);
ASSERT_EQ(8U, labels.size());
- EXPECT_EQ(ASCIIToUTF16("Home; 3456"), labels[0]);
- EXPECT_EQ(ASCIIToUTF16("Work; 3456"), labels[1]);
- EXPECT_EQ(ASCIIToUTF16("Empty; 3456"), labels[2]);
- EXPECT_EQ(ASCIIToUTF16("Home; 8765; 3456"), labels[3]);
- EXPECT_EQ(ASCIIToUTF16("Home; 8765"), labels[4]);
- EXPECT_EQ(ASCIIToUTF16("Work; 8765"), labels[5]);
- EXPECT_EQ(ASCIIToUTF16("Empty; 8765"), labels[6]);
- EXPECT_EQ(ASCIIToUTF16("Home; 8765; 8765"), labels[7]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *3456"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("*3456"), labels[2]);
+ EXPECT_EQ(ASCIIToUTF16("Joe Ely; *3456"), labels[3]);
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *8765"), labels[4]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *8765"), labels[5]);
+ EXPECT_EQ(ASCIIToUTF16("*8765"), labels[6]);
+ EXPECT_EQ(ASCIIToUTF16("Joe Ely; *8765"), labels[7]);
}
TEST_F(AutoFillManagerTest, GetCreditCardSuggestionsNonHTTPS) {
@@ -646,28 +662,33 @@ TEST_F(AutoFillManagerTest, GetFieldSuggestionsForAutocompleteOnly) {
// The page ID sent to the AutoFillManager from the RenderView, used to send
// an IPC message back to the renderer.
const int kPageID = 1;
- const int kAlternatePageID = 0;
webkit_glue::FormField field;
autofill_unittest::CreateTestFormField(
- "First Name", "firstname", "", "text", &field);
- EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, true, field));
+ "Some Field", "somefield", "", "text", &field);
+ EXPECT_FALSE(autofill_manager_->GetAutoFillSuggestions(kPageID, true, field));
// No suggestions provided, so send an empty vector as the results.
// This triggers the combined message send.
// In this case, we're simulating a cancel of Autocomplete with a different
// page ID and an empty vector of suggestions.
- rvh()->AutocompleteSuggestionsReturned(kAlternatePageID,
- std::vector<string16>());
+ std::vector<string16> suggestions;
+ suggestions.push_back(ASCIIToUTF16("one"));
+ suggestions.push_back(ASCIIToUTF16("two"));
+ rvh()->AutocompleteSuggestionsReturned(kPageID, suggestions);
// Test that we sent the right message to the renderer.
int page_id = 0;
std::vector<string16> values;
std::vector<string16> labels;
EXPECT_TRUE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
- EXPECT_EQ(kAlternatePageID, page_id);
- ASSERT_EQ(0U, values.size());
- ASSERT_EQ(0U, labels.size());
+ EXPECT_EQ(kPageID, page_id);
+ ASSERT_EQ(2U, values.size());
+ ASSERT_EQ(2U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("one"), values[0]);
+ EXPECT_EQ(string16(), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("two"), values[1]);
+ EXPECT_EQ(string16(), labels[1]);
}
TEST_F(AutoFillManagerTest, GetFieldSuggestionsWithDuplicateValues) {
@@ -712,6 +733,42 @@ TEST_F(AutoFillManagerTest, GetFieldSuggestionsWithDuplicateValues) {
EXPECT_EQ(string16(), labels[1]);
}
+TEST_F(AutoFillManagerTest, GetBillingSuggestionsAddress1) {
+ FormData form;
+ CreateTestFormDataBilling(&form);
+
+ // Set up our FormStructures.
+ std::vector<FormData> forms;
+ forms.push_back(form);
+ autofill_manager_->FormsSeen(forms);
+
+ // The page ID sent to the AutoFillManager from the RenderView, used to send
+ // an IPC message back to the renderer.
+ const int kPageID = 1;
+
+ webkit_glue::FormField field;
+ autofill_unittest::CreateTestFormField(
+ "Address Line 1", "billingAddr1", "", "text", &field);
+ EXPECT_TRUE(autofill_manager_->GetAutoFillSuggestions(kPageID, false, field));
+
+ // No suggestions provided, so send an empty vector as the results.
+ // This triggers the combined message send.
+ rvh()->AutocompleteSuggestionsReturned(kPageID, std::vector<string16>());
+
+ // Test that we sent the right message to the renderer.
+ int page_id = 0;
+ std::vector<string16> values;
+ std::vector<string16> labels;
+ EXPECT_TRUE(GetAutoFillSuggestionsMessage(&page_id, &values, &labels));
+ EXPECT_EQ(kPageID, page_id);
+ ASSERT_EQ(2U, values.size());
+ EXPECT_EQ(ASCIIToUTF16("3734 Elvis Presley Blvd."), values[0]);
+ EXPECT_EQ(ASCIIToUTF16("123 Apple St."), values[1]);
+ ASSERT_EQ(2U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("Elvis Aaron Presley; *3456"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Charles Hardin Holley; *8765"), labels[1]);
+}
+
TEST_F(AutoFillManagerTest, FillCreditCardForm) {
FormData form;
CreateTestFormDataBilling(&form);
@@ -724,12 +781,8 @@ TEST_F(AutoFillManagerTest, FillCreditCardForm) {
// The page ID sent to the AutoFillManager from the RenderView, used to send
// an IPC message back to the renderer.
const int kPageID = 1;
- EXPECT_TRUE(
- autofill_manager_->FillAutoFillFormData(kPageID,
- form,
- string16(),
- ASCIIToUTF16("Home; 3456"),
- 1));
+ EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(
+ kPageID, form, AutoFillManager::PackIDs(4, 1)));
int page_id = 0;
FormData results;
@@ -797,7 +850,7 @@ TEST_F(AutoFillManagerTest, FillNonBillingFormSemicolon) {
"916 16th St.", "Apt. 6", "Lubbock",
"Texas", "79401", "USA",
"12345678901", "");
- profile->set_unique_id(6);
+ profile->set_unique_id(7);
autofill_manager_->AddProfile(profile);
FormData form;
@@ -811,12 +864,8 @@ TEST_F(AutoFillManagerTest, FillNonBillingFormSemicolon) {
// The page ID sent to the AutoFillManager from the RenderView, used to send
// an IPC message back to the renderer.
const int kPageID = 1;
- EXPECT_TRUE(
- autofill_manager_->FillAutoFillFormData(kPageID,
- form,
- string16(),
- ASCIIToUTF16("Home; 8765"),
- 6));
+ EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(
+ kPageID, form, AutoFillManager::PackIDs(4, 7)));
int page_id = 0;
FormData results;
@@ -871,7 +920,7 @@ TEST_F(AutoFillManagerTest, FillBillFormSemicolon) {
"916 16th St.", "Apt. 6", "Lubbock",
"Texas", "79401", "USA",
"12345678901", "");
- profile->set_unique_id(6);
+ profile->set_unique_id(7);
autofill_manager_->AddProfile(profile);
FormData form;
@@ -886,7 +935,7 @@ TEST_F(AutoFillManagerTest, FillBillFormSemicolon) {
// an IPC message back to the renderer.
const int kPageID = 1;
EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(
- kPageID, form, string16(), ASCIIToUTF16("Home; 8765; 3456"), 6));
+ kPageID, form, AutoFillManager::PackIDs(4, 7)));
int page_id = 0;
FormData results;
@@ -953,6 +1002,7 @@ TEST_F(AutoFillManagerTest, FillPhoneNumber) {
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://myform.com/phone_form.html");
form.action = GURL("http://myform.com/phone_submit.html");
+ form.user_submitted = true;
webkit_glue::FormField field;
@@ -998,8 +1048,6 @@ TEST_F(AutoFillManagerTest, FillPhoneNumber) {
EXPECT_TRUE(
autofill_manager_->FillAutoFillFormData(page_id,
form,
- ASCIIToUTF16(test_data),
- ASCIIToUTF16("Work"),
work_profile->unique_id()));
page_id = 0;
FormData results;
@@ -1024,6 +1072,7 @@ TEST_F(AutoFillManagerTest, FormChangesRemoveField) {
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
+ form.user_submitted = true;
webkit_glue::FormField field;
autofill_unittest::CreateTestFormField(
@@ -1054,11 +1103,7 @@ TEST_F(AutoFillManagerTest, FormChangesRemoveField) {
// The page ID sent to the AutoFillManager from the RenderView, used to send
// an IPC message back to the renderer.
const int kPageID = 1;
- EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(kPageID,
- form,
- ASCIIToUTF16("Elvis"),
- ASCIIToUTF16("Home"),
- 1));
+ EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(kPageID, form, 1));
int page_id = 0;
FormData results;
@@ -1067,6 +1112,7 @@ TEST_F(AutoFillManagerTest, FormChangesRemoveField) {
EXPECT_EQ(ASCIIToUTF16("POST"), results.method);
EXPECT_EQ(GURL("http://myform.com/form.html"), results.origin);
EXPECT_EQ(GURL("http://myform.com/submit.html"), results.action);
+ EXPECT_TRUE(results.user_submitted);
ASSERT_EQ(4U, results.fields.size());
autofill_unittest::CreateTestFormField(
@@ -1089,6 +1135,7 @@ TEST_F(AutoFillManagerTest, FormChangesAddField) {
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
+ form.user_submitted = true;
webkit_glue::FormField field;
autofill_unittest::CreateTestFormField(
@@ -1119,11 +1166,7 @@ TEST_F(AutoFillManagerTest, FormChangesAddField) {
// The page ID sent to the AutoFillManager from the RenderView, used to send
// an IPC message back to the renderer.
const int kPageID = 1;
- EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(kPageID,
- form,
- ASCIIToUTF16("Elvis"),
- ASCIIToUTF16("Home"),
- 1));
+ EXPECT_TRUE(autofill_manager_->FillAutoFillFormData(kPageID, form, 1));
int page_id = 0;
FormData results;
@@ -1132,6 +1175,7 @@ TEST_F(AutoFillManagerTest, FormChangesAddField) {
EXPECT_EQ(ASCIIToUTF16("POST"), results.method);
EXPECT_EQ(GURL("http://myform.com/form.html"), results.origin);
EXPECT_EQ(GURL("http://myform.com/submit.html"), results.action);
+ EXPECT_TRUE(results.user_submitted);
ASSERT_EQ(5U, results.fields.size());
autofill_unittest::CreateTestFormField(
@@ -1157,6 +1201,7 @@ TEST_F(AutoFillManagerTest, HiddenFields) {
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://myform.com/form.html");
form.action = GURL("http://myform.com/submit.html");
+ form.user_submitted = true;
webkit_glue::FormField field;
autofill_unittest::CreateTestFormField(
@@ -1181,4 +1226,27 @@ TEST_F(AutoFillManagerTest, HiddenFields) {
// fields. Need to query the PDM.
}
-} // namespace
+// Checks that resetting the auxiliary profile enabled preference does the right
+// thing on all platforms.
+TEST_F(AutoFillManagerTest, AuxiliaryProfilesReset) {
+#if defined(OS_MACOSX)
+ // Auxiliary profiles is implemented on Mac only. It enables Mac Address
+ // Book integration.
+ ASSERT_TRUE(profile()->GetPrefs()->GetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled));
+ profile()->GetPrefs()->SetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled, false);
+ profile()->GetPrefs()->ClearPref(prefs::kAutoFillAuxiliaryProfilesEnabled);
+ ASSERT_TRUE(profile()->GetPrefs()->GetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled));
+#else
+ ASSERT_FALSE(profile()->GetPrefs()->GetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled));
+ profile()->GetPrefs()->SetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled, true);
+ profile()->GetPrefs()->ClearPref(prefs::kAutoFillAuxiliaryProfilesEnabled);
+ ASSERT_FALSE(profile()->GetPrefs()->GetBoolean(
+ prefs::kAutoFillAuxiliaryProfilesEnabled));
+#endif
+}
+
diff --git a/chrome/browser/autofill/autofill_profile.cc b/chrome/browser/autofill/autofill_profile.cc
index 2b64f0f..414aa93 100644
--- a/chrome/browser/autofill/autofill_profile.cc
+++ b/chrome/browser/autofill/autofill_profile.cc
@@ -484,7 +484,6 @@ string16 AutoFillProfile::ConstructInferredLabel(
return label;
}
-
// 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 17e8528..676bc77 100644
--- a/chrome/browser/autofill/autofill_profile.h
+++ b/chrome/browser/autofill/autofill_profile.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_PROFILE_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_PROFILE_H_
+#pragma once
#include <map>
#include <vector>
diff --git a/chrome/browser/autofill/autofill_profile_unittest.cc b/chrome/browser/autofill/autofill_profile_unittest.cc
index 2a0a6e8..81dadb5 100644
--- a/chrome/browser/autofill/autofill_profile_unittest.cc
+++ b/chrome/browser/autofill/autofill_profile_unittest.cc
@@ -2,11 +2,11 @@
// 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/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_common_unittest.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "grit/generated_resources.h"
@@ -368,4 +368,3 @@ TEST(AutoFillProfileTest, MergeWith) {
}
} // namespace
-
diff --git a/chrome/browser/autofill/autofill_text_field_mac.h b/chrome/browser/autofill/autofill_text_field_mac.h
index a774aca..385c59f 100644
--- a/chrome/browser/autofill/autofill_text_field_mac.h
+++ b/chrome/browser/autofill/autofill_text_field_mac.h
@@ -4,13 +4,12 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_TEXT_FIELD_MAC_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_TEXT_FIELD_MAC_
+#pragma once
#import <Cocoa/Cocoa.h>
#import "base/scoped_nsobject.h"
-#define AUTOFILL_CC_TAG 22
-
// Subclass of NSTextField with special abilities:
// - automatically scrolls containing NSScrollView to visually reveal itself
// on focus
diff --git a/chrome/browser/autofill/autofill_text_field_mac.mm b/chrome/browser/autofill/autofill_text_field_mac.mm
index ff5b1a0..5db2ffb 100644
--- a/chrome/browser/autofill/autofill_text_field_mac.mm
+++ b/chrome/browser/autofill/autofill_text_field_mac.mm
@@ -10,28 +10,30 @@
@implementation AutoFillTextField
- (void)awakeFromNib {
- if ([self tag] == AUTOFILL_CC_TAG)
+ // Fields tagged with this value in the nib file will be treated as credit
+ // card number fields.
+ const int kAutoFillCreditCardTag = 22;
+
+ if ([self tag] == kAutoFillCreditCardTag) {
isCreditCardField_ = YES;
-}
-// Override NSResponder method for when the text field may gain focus. We
-// call |scrollRectToVisible| to ensure that this text field is visible within
-// the scrolling area.
-- (BOOL)becomeFirstResponder {
- // Vertical inset is negative to indicate "outset". Provides some visual
- // space above and below when tabbing between fields.
- const CGFloat kVerticalInset = -40.0;
- BOOL becoming = [super becomeFirstResponder];
- if (becoming) {
- [self scrollRectToVisible:NSInsetRect([self bounds], 0.0, kVerticalInset)];
+ // KVO bindings initialize fields prior to |awakeFromNib|. In the credit
+ // card field case we need to re-initialize the value to the obfuscated
+ // version.
+ [self setObjectValue:[self objectValue]];
}
- return becoming;
}
-- (void)setObjectValue:(id)object {
- if (isCreditCardField_ && [object isKindOfClass:[NSString class]]) {
+- (void)setObjectValue:(id<NSCopying>)anObject {
+ // -[NSControl setObjectValue:] says that the passed-in object has type
+ // |id<NSCopying>|, 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.
+ NSObject<NSCopying>* object = static_cast<NSObject<NSCopying>*>(anObject);
+ if (isCreditCardField_ &&
+ [object isKindOfClass:[NSString class]]) {
// Obfuscate the number.
- NSString* string = object;
+ NSString* string = static_cast<NSString*>(object);
CreditCard card;
card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER),
base::SysNSStringToUTF16(string));
@@ -51,6 +53,7 @@
// fetched if it is changed, and since we force selection, that should clear
// the obfuscation. Nevertheless, we'll be paranoid here since we don't want
// the obfuscating ***s to end up in the database.
+ NOTREACHED();
return obfuscatedValue_.get();
} else {
return [super objectValue];
diff --git a/chrome/browser/autofill/autofill_type.cc b/chrome/browser/autofill/autofill_type.cc
index 030b12c..2fd8cf2 100644
--- a/chrome/browser/autofill/autofill_type.cc
+++ b/chrome/browser/autofill/autofill_type.cc
@@ -1,11 +1,10 @@
-// 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.
#include "chrome/browser/autofill/autofill_type.h"
#include "base/basictypes.h"
-#include "base/logging.h"
namespace {
diff --git a/chrome/browser/autofill/autofill_type.h b/chrome/browser/autofill/autofill_type.h
index 0fc692a..2091153 100644
--- a/chrome/browser/autofill/autofill_type.h
+++ b/chrome/browser/autofill/autofill_type.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_TYPE_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_TYPE_H_
+#pragma once
#include <map>
#include <set>
-#include <string>
#include "base/string16.h"
#include "chrome/browser/autofill/field_types.h"
diff --git a/chrome/browser/autofill/autofill_xml_parser.cc b/chrome/browser/autofill/autofill_xml_parser.cc
index 0142799..4577c38 100644
--- a/chrome/browser/autofill/autofill_xml_parser.cc
+++ b/chrome/browser/autofill/autofill_xml_parser.cc
@@ -93,7 +93,8 @@ int AutoFillQueryXmlParser::GetIntValue(buzz::XmlParseContext* context,
AutoFillUploadXmlParser::AutoFillUploadXmlParser(double* positive_upload_rate,
double* negative_upload_rate)
- : positive_upload_rate_(positive_upload_rate),
+ : succeeded_(false),
+ positive_upload_rate_(positive_upload_rate),
negative_upload_rate_(negative_upload_rate) {
DCHECK(positive_upload_rate_);
DCHECK(negative_upload_rate_);
diff --git a/chrome/browser/autofill/autofill_xml_parser.h b/chrome/browser/autofill/autofill_xml_parser.h
index 02cb31e..9a58011 100644
--- a/chrome/browser/autofill/autofill_xml_parser.h
+++ b/chrome/browser/autofill/autofill_xml_parser.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_XML_PARSER_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_XML_PARSER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/billing_address.h b/chrome/browser/autofill/billing_address.h
index 79cd90e..4e9f762 100644
--- a/chrome/browser/autofill/billing_address.h
+++ b/chrome/browser/autofill/billing_address.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_BILLING_ADDRESS_H_
#define CHROME_BROWSER_AUTOFILL_BILLING_ADDRESS_H_
+#pragma once
#include "chrome/browser/autofill/address.h"
#include "chrome/browser/autofill/field_types.h"
diff --git a/chrome/browser/autofill/contact_info.cc b/chrome/browser/autofill/contact_info.cc
index 0709a24..f38f049 100644
--- a/chrome/browser/autofill/contact_info.cc
+++ b/chrome/browser/autofill/contact_info.cc
@@ -6,6 +6,7 @@
#include "base/basictypes.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"
diff --git a/chrome/browser/autofill/contact_info.h b/chrome/browser/autofill/contact_info.h
index a2aa6cb..97c3119 100644
--- a/chrome/browser/autofill/contact_info.h
+++ b/chrome/browser/autofill/contact_info.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_CONTACT_INFO_H_
#define CHROME_BROWSER_AUTOFILL_CONTACT_INFO_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/contact_info_unittest.cc b/chrome/browser/autofill/contact_info_unittest.cc
index 139c242..0ce9cec 100644
--- a/chrome/browser/autofill/contact_info_unittest.cc
+++ b/chrome/browser/autofill/contact_info_unittest.cc
@@ -6,6 +6,7 @@
#include "base/basictypes.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/autofill/credit_card.cc b/chrome/browser/autofill/credit_card.cc
index efc4d64..50861a3 100644
--- a/chrome/browser/autofill/credit_card.cc
+++ b/chrome/browser/autofill/credit_card.cc
@@ -4,13 +4,20 @@
#include "chrome/browser/autofill/credit_card.h"
+<<<<<<< HEAD
#ifndef ANDROID
// FIXME: Need l10n on Android?
+=======
+#include <string>
+
+>>>>>>> Chromium at release 7.0.540.0
#include "app/l10n_util.h"
#endif
#include "base/basictypes.h"
#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"
@@ -18,10 +25,12 @@
#include "grit/generated_resources.h"
#endif
-static const string16 kCreditCardSeparators = ASCIIToUTF16(" -");
-static const char* kCreditCardObfuscationString = "************";
+namespace {
+
+const string16::value_type kCreditCardSeparators[] = {' ','-',0};
+const char* kCreditCardObfuscationString = "************";
-static const AutoFillFieldType kAutoFillCreditCardTypes[] = {
+const AutoFillFieldType kAutoFillCreditCardTypes[] = {
CREDIT_CARD_NAME,
CREDIT_CARD_NUMBER,
CREDIT_CARD_TYPE,
@@ -29,13 +38,107 @@ static const AutoFillFieldType kAutoFillCreditCardTypes[] = {
CREDIT_CARD_EXP_4_DIGIT_YEAR,
};
-static const int kAutoFillCreditCardLength =
- arraysize(kAutoFillCreditCardTypes);
+const int kAutoFillCreditCardLength = arraysize(kAutoFillCreditCardTypes);
+
+// These values must match the values in WebKitClientImpl in webkit/glue. We
+// send these strings to WK, which then asks WebKitClientImpl to load the image
+// data.
+const char* kAmericanExpressCard = "americanExpressCC";
+const char* kDinersCard = "dinersCC";
+const char* kDiscoverCard = "discoverCC";
+const char* kGenericCard = "genericCC";
+const char* kJCBCard = "jcbCC";
+const char* kMasterCard = "masterCardCC";
+const char* kSoloCard = "soloCC";
+const char* kVisaCard = "visaCC";
+
+std::string GetCreditCardType(const string16& number) {
+ // Credit card number specifications taken from:
+ // http://en.wikipedia.org/wiki/Credit_card_numbers and
+ // http://www.beachnet.com/~hstiles/cardtype.html
+ // Card Type Prefix(es) Length
+ // ---------------------------------------------------------------
+ // Visa 4 13,16
+ // American Express 34,37 15
+ // Diners Club 300-305,2014,2149,36, 14,15
+ // Discover Card 6011,65 16
+ // JCB 3 16
+ // JCB 2131,1800 15
+ // MasterCard 51-55 16
+ // Solo (debit card) 6334,6767 16,18,19
+
+ // We need at least 4 digits to work with.
+ if (number.length() < 4)
+ return kGenericCard;
+
+ int first_four_digits = 0;
+ if (!base::StringToInt(number.substr(0, 4), &first_four_digits))
+ return kGenericCard;
+
+ int first_three_digits = first_four_digits / 10;
+ int first_two_digits = first_three_digits / 10;
+ int first_digit = first_two_digits / 10;
+
+ switch (number.length()) {
+ case 13:
+ if (first_digit == 4)
+ return kVisaCard;
+
+ break;
+ case 14:
+ if (first_three_digits >= 300 && first_three_digits <=305)
+ return kDinersCard;
+
+ if (first_digit == 36)
+ return kDinersCard;
+
+ break;
+ case 15:
+ if (first_two_digits == 34 || first_two_digits == 37)
+ return kAmericanExpressCard;
+
+ if (first_four_digits == 2131 || first_four_digits == 1800)
+ return kJCBCard;
+
+ if (first_four_digits == 2014 || first_four_digits == 2149)
+ return kDinersCard;
+
+ break;
+ case 16:
+ if (first_four_digits == 6011 || first_two_digits == 65)
+ return kDiscoverCard;
+
+ if (first_four_digits == 6334 || first_four_digits == 6767)
+ return kSoloCard;
+
+ if (first_two_digits >= 51 && first_two_digits <= 55)
+ return kMasterCard;
+
+ if (first_digit == 3)
+ return kJCBCard;
+
+ if (first_digit == 4)
+ return kVisaCard;
+
+ break;
+ case 18:
+ case 19:
+ if (first_four_digits == 6334 || first_four_digits == 6767)
+ return kSoloCard;
+
+ break;
+ }
+
+ return kGenericCard;
+}
+
+} // namespace
CreditCard::CreditCard(const string16& label, int unique_id)
: expiration_month_(0),
expiration_year_(0),
label_(label),
+ billing_address_id_(0),
unique_id_(unique_id) {
}
@@ -46,6 +149,7 @@ CreditCard::CreditCard(const CreditCard& card) : FormGroup() {
CreditCard::CreditCard()
: expiration_month_(0),
expiration_year_(0),
+ billing_address_id_(0),
unique_id_(0) {
}
@@ -69,9 +173,6 @@ void CreditCard::GetPossibleFieldTypes(const string16& text,
if (Is4DigitExpirationYear(text))
possible_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
-
- if (IsCardType(text))
- possible_types->insert(CREDIT_CARD_TYPE);
}
void CreditCard::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
@@ -89,9 +190,6 @@ void CreditCard::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
if (!Expiration4DigitYearAsString().empty())
available_types->insert(CREDIT_CARD_EXP_4_DIGIT_YEAR);
- if (!type().empty())
- available_types->insert(CREDIT_CARD_TYPE);
-
if (!number().empty())
available_types->insert(CREDIT_CARD_NUMBER);
}
@@ -162,7 +260,8 @@ string16 CreditCard::GetFieldText(const AutoFillType& type) const {
}
case CREDIT_CARD_TYPE:
- return this->type();
+ // We don't handle this case.
+ return string16();
case CREDIT_CARD_NUMBER:
return number();
@@ -206,7 +305,7 @@ void CreditCard::SetInfo(const AutoFillType& type, const string16& value) {
break;
case CREDIT_CARD_TYPE:
- set_type(value);
+ // We determine the type based on the number.
break;
case CREDIT_CARD_NUMBER: {
@@ -215,6 +314,7 @@ void CreditCard::SetInfo(const AutoFillType& type, const string16& value) {
break;
}
set_number(value);
+ set_type(ASCIIToUTF16(GetCreditCardType(number())));
// Update last four digits as well.
if (value.length() > 4)
set_last_four_digits(value.substr(value.length() - 4));
@@ -286,7 +386,7 @@ void CreditCard::operator=(const CreditCard& source) {
expiration_month_ = source.expiration_month_;
expiration_year_ = source.expiration_year_;
label_ = source.label_;
- billing_address_ = source.billing_address_;
+ billing_address_id_ = source.billing_address_id_;
unique_id_ = source.unique_id_;
}
@@ -302,7 +402,7 @@ bool CreditCard::operator==(const CreditCard& creditcard) const {
if (label_ != creditcard.label_ ||
unique_id_ != creditcard.unique_id_ ||
- billing_address_ != creditcard.billing_address_) {
+ billing_address_id_ != creditcard.billing_address_id_) {
return false;
}
@@ -323,7 +423,7 @@ bool CreditCard::operator!=(const CreditCard& creditcard) const {
// static
bool CreditCard::IsCreditCardNumber(const string16& text) {
string16 number;
- RemoveChars(text, kCreditCardSeparators.c_str(), &number);
+ RemoveChars(text, kCreditCardSeparators, &number);
int sum = 0;
bool odd = false;
@@ -348,7 +448,7 @@ bool CreditCard::IsCreditCardNumber(const string16& text) {
bool CreditCard::IsEmpty() const {
FieldTypeSet types;
GetAvailableFieldTypes(&types);
- return types.empty() && billing_address().empty();
+ return types.empty() && billing_address_id_ == 0;
}
@@ -356,7 +456,7 @@ string16 CreditCard::ExpirationMonthAsString() const {
if (expiration_month_ == 0)
return string16();
- string16 month = IntToString16(expiration_month_);
+ string16 month = base::IntToString16(expiration_month_);
if (expiration_month_ >= 10)
return month;
@@ -369,14 +469,14 @@ string16 CreditCard::Expiration4DigitYearAsString() const {
if (expiration_year_ == 0)
return string16();
- return IntToString16(Expiration4DigitYear());
+ return base::IntToString16(Expiration4DigitYear());
}
string16 CreditCard::Expiration2DigitYearAsString() const {
if (expiration_year_ == 0)
return string16();
- return IntToString16(Expiration2DigitYear());
+ return base::IntToString16(Expiration2DigitYear());
}
void CreditCard::SetExpirationMonthFromString(const string16& text) {
@@ -428,18 +528,21 @@ bool CreditCard::FindInfoMatchesHelper(const AutoFillFieldType& field_type,
string16 exp_month(ExpirationMonthAsString());
if (StartsWith(exp_month, info, true))
*match = exp_month;
+ break;
}
case CREDIT_CARD_EXP_2_DIGIT_YEAR: {
string16 exp_year(Expiration2DigitYearAsString());
if (StartsWith(exp_year, info, true))
*match = exp_year;
+ break;
}
case CREDIT_CARD_EXP_4_DIGIT_YEAR: {
string16 exp_year(Expiration4DigitYearAsString());
if (StartsWith(exp_year, info, true))
*match = exp_year;
+ break;
}
case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR: {
@@ -447,6 +550,7 @@ bool CreditCard::FindInfoMatchesHelper(const AutoFillFieldType& field_type,
Expiration2DigitYearAsString());
if (StartsWith(exp_date, info, true))
*match = exp_date;
+ break;
}
case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR: {
@@ -454,13 +558,12 @@ bool CreditCard::FindInfoMatchesHelper(const AutoFillFieldType& field_type,
Expiration4DigitYearAsString());
if (StartsWith(exp_date, info, true))
*match = exp_date;
+ break;
}
- case CREDIT_CARD_TYPE: {
- string16 card_type(this->type());
- if (StartsWith(card_type, info, true))
- *match = card_type;
- }
+ case CREDIT_CARD_TYPE:
+ // We don't handle this case.
+ break;
case CREDIT_CARD_VERIFICATION_CODE:
NOTREACHED();
@@ -478,7 +581,7 @@ bool CreditCard::IsNameOnCard(const string16& text) const {
bool CreditCard::IsExpirationMonth(const string16& text) const {
int month;
- if (!StringToInt(text, &month))
+ if (!base::StringToInt(text, &month))
return false;
return expiration_month_ == month;
@@ -486,7 +589,7 @@ bool CreditCard::IsExpirationMonth(const string16& text) const {
bool CreditCard::Is2DigitExpirationYear(const string16& text) const {
int year;
- if (!StringToInt(text, &year))
+ if (!base::StringToInt(text, &year))
return false;
return year < 100 && (expiration_year_ % 100) == year;
@@ -494,19 +597,15 @@ bool CreditCard::Is2DigitExpirationYear(const string16& text) const {
bool CreditCard::Is4DigitExpirationYear(const string16& text) const {
int year;
- if (!StringToInt(text, &year))
+ if (!base::StringToInt(text, &year))
return false;
return expiration_year_ == year;
}
-bool CreditCard::IsCardType(const string16& text) const {
- return StringToLowerASCII(text) == StringToLowerASCII(type_);
-}
-
bool CreditCard::ConvertDate(const string16& date, int* num) const {
if (!date.empty()) {
- bool converted = StringToInt(date, num);
+ bool converted = base::StringToInt(date, num);
DCHECK(converted);
if (!converted)
return false;
@@ -525,7 +624,7 @@ std::ostream& operator<<(std::ostream& os, const CreditCard& creditcard) {
<< " "
<< creditcard.unique_id()
<< " "
- << UTF16ToUTF8(creditcard.billing_address())
+ << creditcard.billing_address_id()
<< " "
<< UTF16ToUTF8(creditcard.GetFieldText(AutoFillType(CREDIT_CARD_NAME)))
<< " "
diff --git a/chrome/browser/autofill/credit_card.h b/chrome/browser/autofill/credit_card.h
index 85d104f..e078ab1 100644
--- a/chrome/browser/autofill/credit_card.h
+++ b/chrome/browser/autofill/credit_card.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_CREDIT_CARD_H_
#define CHROME_BROWSER_AUTOFILL_CREDIT_CARD_H_
+#pragma once
#include <vector>
@@ -38,12 +39,13 @@ class CreditCard : public FormGroup {
// The last four digits of the credit card number.
string16 LastFourDigits() const;
- const string16& billing_address() const { return billing_address_; }
+ const string16& type() const { return type_; }
+ int billing_address_id() const { return billing_address_id_; }
int unique_id() const { return unique_id_; }
// The caller should verify that the corresponding AutoFillProfile exists.
- void set_billing_address(const string16& address) {
- billing_address_ = address;
+ void set_billing_address_id(int address_id) {
+ billing_address_id_ = address_id;
}
void set_unique_id(int id) { unique_id_ = id; }
@@ -78,7 +80,6 @@ class CreditCard : public FormGroup {
const string16& number() const { return number_; }
const string16& name_on_card() const { return name_on_card_; }
- const string16& type() const { return type_; }
const string16& last_four_digits() const { return last_four_digits_; }
int expiration_month() const { return expiration_month_; }
int expiration_year() const { return expiration_year_; }
@@ -118,10 +119,6 @@ class CreditCard : public FormGroup {
// year.
bool Is4DigitExpirationYear(const string16& text) const;
- // Returns true if |text| matches the type of the card. The comparison is
- // case-insensitive.
- bool IsCardType(const string16& text) const;
-
// Converts |date| to an integer form. Returns true if the conversion
// succeeded.
bool ConvertDate(const string16& date, int* num) const;
@@ -140,9 +137,9 @@ class CreditCard : public FormGroup {
// This is the display name of the card set by the user, e.g., Amazon Visa.
string16 label_;
- // The billing address. This is the label of the AutoFillProfile that contains
- // the corresponding billing address.
- string16 billing_address_;
+ // The billing address. This is the unique ID of the AutoFillProfile that
+ // contains the corresponding billing address.
+ int billing_address_id_;
// The unique ID of this credit card.
int unique_id_;
diff --git a/chrome/browser/autofill/credit_card_field.cc b/chrome/browser/autofill/credit_card_field.cc
index 770cff4..7bf8db6 100644
--- a/chrome/browser/autofill/credit_card_field.cc
+++ b/chrome/browser/autofill/credit_card_field.cc
@@ -6,6 +6,7 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
bool CreditCardField::GetFieldInfo(FieldTypeMap* field_type_map) const {
@@ -18,11 +19,12 @@ bool CreditCardField::GetFieldInfo(FieldTypeMap* field_type_map) const {
// initial.
if (cardholder_last_ == NULL) {
// Add() will check if cardholder_ is != NULL.
- Add(field_type_map, cardholder_, AutoFillType(CREDIT_CARD_NAME));
+ ok = ok && Add(field_type_map, cardholder_, AutoFillType(CREDIT_CARD_NAME));
+ DCHECK(ok);
}
- Add(field_type_map, type_, AutoFillType(CREDIT_CARD_TYPE));
-
+ ok = ok && Add(field_type_map, type_, AutoFillType(CREDIT_CARD_TYPE));
+ DCHECK(ok);
ok = ok && Add(field_type_map, expiration_month_,
AutoFillType(CREDIT_CARD_EXP_MONTH));
DCHECK(ok);
diff --git a/chrome/browser/autofill/credit_card_field.h b/chrome/browser/autofill/credit_card_field.h
index bd128d3..68cc0db 100644
--- a/chrome/browser/autofill/credit_card_field.h
+++ b/chrome/browser/autofill/credit_card_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_CREDIT_CARD_FIELD_H_
#define CHROME_BROWSER_AUTOFILL_CREDIT_CARD_FIELD_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/credit_card_field_unittest.cc b/chrome/browser/autofill/credit_card_field_unittest.cc
index d674bc5..c333032 100644
--- a/chrome/browser/autofill/credit_card_field_unittest.cc
+++ b/chrome/browser/autofill/credit_card_field_unittest.cc
@@ -4,6 +4,7 @@
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/credit_card_field.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
diff --git a/chrome/browser/autofill/credit_card_unittest.cc b/chrome/browser/autofill/credit_card_unittest.cc
index 5912872..1c7f8ba 100644
--- a/chrome/browser/autofill/credit_card_unittest.cc
+++ b/chrome/browser/autofill/credit_card_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_common_unittest.h"
#include "chrome/browser/autofill/credit_card.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,7 +24,7 @@ TEST(CreditCardTest, PreviewSummaryAndObfuscatedNumberStrings) {
// Case 00: Empty credit card with empty strings.
CreditCard credit_card00(string16(), 0);
autofill_unittest::SetCreditCardInfo(&credit_card00, "Corporate",
- "John Dillinger", "Visa", "", "", "", "Chicago");
+ "John Dillinger", "Visa", "", "", "", 1);
string16 summary00 = credit_card00.PreviewSummary();
EXPECT_EQ(string16(), summary00);
string16 obfuscated00 = credit_card00.ObfuscatedNumber();
@@ -32,7 +33,7 @@ TEST(CreditCardTest, PreviewSummaryAndObfuscatedNumberStrings) {
// Case 1: No credit card number.
CreditCard credit_card1(string16(), 0);
autofill_unittest::SetCreditCardInfo(&credit_card1, "Corporate",
- "John Dillinger", "Visa", "", "01", "2010", "Chicago");
+ "John Dillinger", "Visa", "", "01", "2010", 1);
string16 summary1 = credit_card1.PreviewSummary();
EXPECT_EQ(string16(), summary1);
string16 obfuscated1 = credit_card1.ObfuscatedNumber();
@@ -41,7 +42,7 @@ TEST(CreditCardTest, PreviewSummaryAndObfuscatedNumberStrings) {
// Case 2: No month.
CreditCard credit_card2(string16(), 0);
autofill_unittest::SetCreditCardInfo(&credit_card2, "Corporate",
- "John Dillinger", "Visa", "123456789012", "", "2010", "Chicago");
+ "John Dillinger", "Visa", "123456789012", "", "2010", 1);
string16 summary2 = credit_card2.PreviewSummary();
EXPECT_EQ(string16(ASCIIToUTF16("************9012")), summary2);
string16 obfuscated2 = credit_card2.ObfuscatedNumber();
@@ -50,7 +51,7 @@ TEST(CreditCardTest, PreviewSummaryAndObfuscatedNumberStrings) {
// Case 3: No year.
CreditCard credit_card3(string16(), 0);
autofill_unittest::SetCreditCardInfo(&credit_card3, "Corporate",
- "John Dillinger", "Visa", "123456789012", "01", "", "Chicago");
+ "John Dillinger", "Visa", "123456789012", "01", "", 1);
string16 summary3 = credit_card3.PreviewSummary();
EXPECT_EQ(string16(ASCIIToUTF16("************9012")), summary3);
string16 obfuscated3 = credit_card3.ObfuscatedNumber();
@@ -59,7 +60,7 @@ TEST(CreditCardTest, PreviewSummaryAndObfuscatedNumberStrings) {
// Case 4: Have everything.
CreditCard credit_card4(string16(), 0);
autofill_unittest::SetCreditCardInfo(&credit_card4, "Corporate",
- "John Dillinger", "Visa", "123456789012", "01", "2010", "Chicago");
+ "John Dillinger", "Visa", "123456789012", "01", "2010", 1);
string16 summary4 = credit_card4.PreviewSummary();
EXPECT_EQ(string16(ASCIIToUTF16("************9012, Exp: 01/2010")), summary4);
string16 obfuscated4 = credit_card4.ObfuscatedNumber();
diff --git a/chrome/browser/autofill/fax_field.cc b/chrome/browser/autofill/fax_field.cc
index f935a6d..80e25cb 100644
--- a/chrome/browser/autofill/fax_field.cc
+++ b/chrome/browser/autofill/fax_field.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
// static
diff --git a/chrome/browser/autofill/fax_field.h b/chrome/browser/autofill/fax_field.h
index b5c1eed..e954ee1 100644
--- a/chrome/browser/autofill/fax_field.h
+++ b/chrome/browser/autofill/fax_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_FAX_FIELD_H_
#define CHROME_BROWSER_AUTOFILL_FAX_FIELD_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/fax_field_unittest.cc b/chrome/browser/autofill/fax_field_unittest.cc
index 258f8d0..0ba21c0 100644
--- a/chrome/browser/autofill/fax_field_unittest.cc
+++ b/chrome/browser/autofill/fax_field_unittest.cc
@@ -4,6 +4,7 @@
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/fax_field.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
diff --git a/chrome/browser/autofill/fax_number.h b/chrome/browser/autofill/fax_number.h
index 5ebd11e..864746f 100644
--- a/chrome/browser/autofill/fax_number.h
+++ b/chrome/browser/autofill/fax_number.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_FAX_NUMBER_H_
#define CHROME_BROWSER_AUTOFILL_FAX_NUMBER_H_
+#pragma once
#include "chrome/browser/autofill/phone_number.h"
diff --git a/chrome/browser/autofill/field_types.h b/chrome/browser/autofill/field_types.h
index 934fa45..ab03192 100644
--- a/chrome/browser/autofill/field_types.h
+++ b/chrome/browser/autofill/field_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_
#define CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/autofill/form_field.cc b/chrome/browser/autofill/form_field.cc
index b68c77d..24b45ed 100644
--- a/chrome/browser/autofill/form_field.cc
+++ b/chrome/browser/autofill/form_field.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/autofill/form_field.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/address_field.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/credit_card_field.h"
@@ -66,6 +67,12 @@ namespace {
// The name of the hidden form control element.
const char* const kControlTypeHidden = "hidden";
+// The name of the radio form control element.
+const char* const kControlTypeRadio = "radio";
+
+// The name of the checkbox form control element.
+const char* const kControlTypeCheckBox = "checkbox";
+
} // namespace
class EmailField : public FormField {
@@ -184,7 +191,7 @@ bool FormField::ParseText(std::vector<AutoFillField*>::const_iterator* iter,
bool FormField::ParseEmptyText(
std::vector<AutoFillField*>::const_iterator* iter,
AutoFillField** dest) {
- return ParseLabelAndName(iter, ASCIIToUTF16("^$"), dest);
+ return ParseLabelText(iter, ASCIIToUTF16("^$"), dest);
}
// static
@@ -270,9 +277,13 @@ FormFieldSet::FormFieldSet(FormStructure* fields) {
// Parse fields.
std::vector<AutoFillField*>::const_iterator field = fields->begin();
while (field != fields->end() && *field != NULL) {
- // Don't parse hidden fields.
+ // Don't parse hidden fields or radio or checkbox controls.
if (LowerCaseEqualsASCII((*field)->form_control_type(),
- kControlTypeHidden)) {
+ kControlTypeHidden) ||
+ LowerCaseEqualsASCII((*field)->form_control_type(),
+ kControlTypeRadio) ||
+ LowerCaseEqualsASCII((*field)->form_control_type(),
+ kControlTypeCheckBox)) {
field++;
continue;
}
diff --git a/chrome/browser/autofill/form_field.h b/chrome/browser/autofill/form_field.h
index 7c9547c..cf57350 100644
--- a/chrome/browser/autofill/form_field.h
+++ b/chrome/browser/autofill/form_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_FORM_FIELD_H_
#define CHROME_BROWSER_AUTOFILL_FORM_FIELD_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/form_field_unittest.cc b/chrome/browser/autofill/form_field_unittest.cc
new file mode 100644
index 0000000..965fa70
--- /dev/null
+++ b/chrome/browser/autofill/form_field_unittest.cc
@@ -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.
+
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/form_field.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(FormFieldTest, Match) {
+ AutoFillField field;
+
+ // Empty strings match.
+ EXPECT_TRUE(FormField::Match(&field, string16(), true));
+
+ // Empty pattern matches non-empty string.
+ field.set_label(ASCIIToUTF16("a"));
+ EXPECT_TRUE(FormField::Match(&field, string16(), true));
+
+ // Strictly empty pattern matches empty string.
+ field.set_label(ASCIIToUTF16(""));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^$"), true));
+
+ // Strictly empty pattern does not match non-empty string.
+ field.set_label(ASCIIToUTF16("a"));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^$"), true));
+
+ // Non-empty pattern doesn't match empty string.
+ field.set_label(string16());
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("a"), true));
+
+ // Beginning of line.
+ field.set_label(ASCIIToUTF16("head_tail"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^head"), true));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^tail"), true));
+
+ // End of line.
+ field.set_label(ASCIIToUTF16("head_tail"));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("head$"), true));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("tail$"), true));
+
+ // Exact.
+ field.set_label(ASCIIToUTF16("head_tail"));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^head$"), true));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("^tail$"), true));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("^head_tail$"), true));
+
+ // Escaped dots.
+ field.set_label(ASCIIToUTF16("m.i."));
+ // Note: This pattern is misleading as the "." characters are wild cards.
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m.i."), true));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."), true));
+ field.set_label(ASCIIToUTF16("mXiX"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("m.i."), true));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("m\\.i\\."), true));
+
+ // Repetition.
+ field.set_label(ASCIIToUTF16("headtail"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"), true));
+ field.set_label(ASCIIToUTF16("headXtail"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"), true));
+ field.set_label(ASCIIToUTF16("headXXXtail"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.*tail"), true));
+ field.set_label(ASCIIToUTF16("headtail"));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("head.+tail"), true));
+ field.set_label(ASCIIToUTF16("headXtail"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.+tail"), true));
+ field.set_label(ASCIIToUTF16("headXXXtail"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head.+tail"), true));
+
+ // Alternation.
+ field.set_label(ASCIIToUTF16("head_tail"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head|other"), true));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("tail|other"), true));
+ EXPECT_FALSE(FormField::Match(&field, ASCIIToUTF16("bad|good"), true));
+
+ // Case sensitivity.
+ field.set_label(ASCIIToUTF16("xxxHeAd_tAiLxxx"));
+ EXPECT_TRUE(FormField::Match(&field, ASCIIToUTF16("head_tail"), true));
+}
+
+} // namespace
diff --git a/chrome/browser/autofill/form_group.h b/chrome/browser/autofill/form_group.h
index c742b91..4a61c1a 100644
--- a/chrome/browser/autofill/form_group.h
+++ b/chrome/browser/autofill/form_group.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_FORM_GROUP_H_
#define CHROME_BROWSER_AUTOFILL_FORM_GROUP_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
index 2d0d76f..93fd2d7 100644
--- a/chrome/browser/autofill/form_structure.cc
+++ b/chrome/browser/autofill/form_structure.cc
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/sha1.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_xml_parser.h"
#include "chrome/browser/autofill/field_types.h"
@@ -62,7 +62,7 @@ static std::string Hash64Bit(const std::string& str) {
(((static_cast<uint64>(hash_bin[6])) & 0xFF) << 8) |
((static_cast<uint64>(hash_bin[7])) & 0xFF);
- return Uint64ToString(hash64);
+ return base::Uint64ToString(hash64);
}
} // namespace
@@ -71,6 +71,9 @@ FormStructure::FormStructure(const FormData& form)
: form_name_(form.name),
source_url_(form.origin),
target_url_(form.action),
+ has_credit_card_field_(false),
+ has_autofillable_field_(false),
+ has_password_fields_(false),
autofill_count_(0) {
// Copy the form fields.
std::vector<webkit_glue::FormField>::const_iterator field;
@@ -89,7 +92,8 @@ FormStructure::FormStructure(const FormData& form)
}
// Generate a unique name for this field by appending a counter to the name.
- string16 unique_name = field->name() + IntToString16(fields_.size() + 1);
+ string16 unique_name = field->name() +
+ base::IntToString16(fields_.size() + 1);
fields_.push_back(new AutoFillField(*field, unique_name));
}
@@ -333,27 +337,6 @@ size_t FormStructure::field_count() const {
return (field_size == 0) ? 0 : field_size - 1;
}
-FormData FormStructure::ConvertToFormData() const {
- FormData form;
- form.name = form_name_;
- form.origin = source_url_;
- form.action = target_url_;
-
- if (method_ == GET)
- form.method = ASCIIToUTF16("GET");
- else if (method_ == POST)
- form.method = ASCIIToUTF16("POST");
- else
- NOTREACHED();
-
- for (std::vector<AutoFillField*>::const_iterator iter = fields_.begin();
- iter != fields_.end() && *iter; ++iter) {
- form.fields.push_back(static_cast<webkit_glue::FormField>(**iter));
- }
-
- return form;
-}
-
bool FormStructure::operator==(const FormData& form) const {
// TODO(jhawkins): Is this enough to differentiate a form?
if (form_name_ == form.name &&
@@ -381,9 +364,7 @@ void FormStructure::GetHeuristicAutoFillTypes() {
for (size_t index = 0; index < field_count(); index++) {
AutoFillField* field = fields_[index];
- // TODO(dhollowa): Defensive check for crash happening in the field.
- // See http://crbug.com/42211
- CHECK(field);
+ DCHECK(field);
FieldTypeMap::iterator iter = field_type_map.find(field->unique_name());
AutoFillFieldType heuristic_auto_fill_type;
@@ -432,7 +413,7 @@ bool FormStructure::EncodeFormRequest(
field_element->SetAttr(buzz::QName(kAttributeSignature),
field->FieldSignature());
field_element->SetAttr(buzz::QName(kAttributeAutoFillType),
- IntToString(*type));
+ base::IntToString(*type));
encompassing_xml_element->AddElement(field_element);
}
} else {
diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h
index 8ce5a18..bb583dc 100644
--- a/chrome/browser/autofill/form_structure.h
+++ b/chrome/browser/autofill/form_structure.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_
#define CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_
+#pragma once
#include <string>
#include <vector>
@@ -92,9 +93,6 @@ class FormStructure {
// Returns the number of fields that are able to be autofilled.
size_t autofill_count() const { return autofill_count_; }
- // Converts this object to a FormData object.
- webkit_glue::FormData ConvertToFormData() const;
-
// Used for iterating over the fields.
std::vector<AutoFillField*>::const_iterator begin() const {
return fields_.begin();
@@ -103,6 +101,8 @@ class FormStructure {
return fields_.end();
}
+ const GURL& source_url() const { return source_url_; }
+
bool operator==(const webkit_glue::FormData& form) const;
bool operator!=(const webkit_glue::FormData& form) const;
diff --git a/chrome/browser/autofill/form_structure_unittest.cc b/chrome/browser/autofill/form_structure_unittest.cc
index 7b8848f..0eea0a6 100644
--- a/chrome/browser/autofill/form_structure_unittest.cc
+++ b/chrome/browser/autofill/form_structure_unittest.cc
@@ -90,33 +90,13 @@ TEST(FormStructureTest, AutoFillCount) {
EXPECT_EQ(1U, form_structure.autofill_count());
}
-TEST(FormStructureTest, ConvertToFormData) {
+TEST(FormStructureTest, SourceURL) {
FormData form;
+ form.origin = GURL("http://www.foo.com/");
form.method = ASCIIToUTF16("post");
- form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("username"),
- ASCIIToUTF16("username"),
- string16(),
- ASCIIToUTF16("text"),
- 0));
- form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("password"),
- ASCIIToUTF16("password"),
- string16(),
- ASCIIToUTF16("password"),
- 0));
- form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("state"),
- ASCIIToUTF16("state"),
- string16(),
- ASCIIToUTF16("select"),
- 0));
- form.fields.push_back(webkit_glue::FormField(string16(),
- ASCIIToUTF16("Submit"),
- string16(),
- ASCIIToUTF16("submit"),
- 0));
FormStructure form_structure(form);
- FormData converted = form_structure.ConvertToFormData();
- EXPECT_EQ(form, converted);
+ EXPECT_EQ(form.origin, form_structure.source_url());
}
TEST(FormStructureTest, HasAutoFillableValues) {
@@ -420,7 +400,8 @@ TEST(FormStructureTest, HeuristicsSample8) {
// Zip.
EXPECT_EQ(ADDRESS_BILLING_ZIP, form_structure->field(6)->heuristic_type());
// Country.
- EXPECT_EQ(ADDRESS_BILLING_COUNTRY, form_structure->field(7)->heuristic_type());
+ EXPECT_EQ(ADDRESS_BILLING_COUNTRY,
+ form_structure->field(7)->heuristic_type());
// Phone.
EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER,
form_structure->field(8)->heuristic_type());
@@ -740,6 +721,141 @@ TEST(FormStructureTest, ThreeAddressLines) {
EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(3)->heuristic_type());
}
+// This test verifies that "addressLine1" and "addressLine2" matches heuristics.
+// This occured in https://www.gorillaclothing.com/. http://crbug.com/52126.
+TEST(FormStructureTest, BillingAndShippingAddresses) {
+ scoped_ptr<FormStructure> form_structure;
+ FormData form;
+
+ form.method = ASCIIToUTF16("post");
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Address Line1"),
+ ASCIIToUTF16("shipping.address.addressLine1"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Address Line2"),
+ ASCIIToUTF16("shipping.address.addressLine2"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Address Line1"),
+ ASCIIToUTF16("billing.address.addressLine1"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Address Line2"),
+ ASCIIToUTF16("billing.address.addressLine2"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form_structure.reset(new FormStructure(form));
+ EXPECT_TRUE(form_structure->IsAutoFillable());
+ ASSERT_EQ(4U, form_structure->field_count());
+ ASSERT_EQ(4U, form_structure->autofill_count());
+
+ // Address Line 1.
+ EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type());
+ // Address Line 2.
+ EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type());
+ // Address Line 1.
+ EXPECT_EQ(ADDRESS_BILLING_LINE1, form_structure->field(2)->heuristic_type());
+ // Address Line 2.
+ EXPECT_EQ(ADDRESS_BILLING_LINE2, form_structure->field(3)->heuristic_type());
+}
+
+
+// This example comes from expedia.com where they use a "Suite" label to
+// indicate a suite or apartment number. We interpret this as address line 2.
+// And the following "Street address second line" we interpret as address line
+// 3 and discard.
+// See http://crbug.com/48197 for details.
+TEST(FormStructureTest, ThreeAddressLinesExpedia) {
+ scoped_ptr<FormStructure> form_structure;
+ FormData form;
+
+ form.method = ASCIIToUTF16("post");
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Street:"),
+ ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads1"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Suite or Apt:"),
+ ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adap"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Street address second line"),
+ ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_ads2"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("City:"),
+ ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adct"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form_structure.reset(new FormStructure(form));
+ EXPECT_TRUE(form_structure->IsAutoFillable());
+ ASSERT_EQ(4U, form_structure->field_count());
+ ASSERT_EQ(3U, form_structure->autofill_count());
+
+ // Address Line 1.
+ EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type());
+ // Suite / Apt.
+ EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type());
+ // Address Line 3.
+ EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(2)->heuristic_type());
+ // City.
+ EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(3)->heuristic_type());
+}
+
+// This example comes from ebay.com where the word "suite" appears in the label
+// and the name "address2" clearly indicates that this is the address line 2.
+// See http://crbug.com/48197 for details.
+TEST(FormStructureTest, TwoAddressLinesEbay) {
+ scoped_ptr<FormStructure> form_structure;
+ FormData form;
+
+ form.method = ASCIIToUTF16("post");
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Address Line1"),
+ ASCIIToUTF16("address1"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("Floor number, suite number, etc"),
+ ASCIIToUTF16("address2"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(
+ webkit_glue::FormField(ASCIIToUTF16("City"),
+ ASCIIToUTF16("city"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form_structure.reset(new FormStructure(form));
+ EXPECT_TRUE(form_structure->IsAutoFillable());
+ ASSERT_EQ(3U, form_structure->field_count());
+ ASSERT_EQ(3U, form_structure->autofill_count());
+
+ // Address Line 1.
+ EXPECT_EQ(ADDRESS_HOME_LINE1, form_structure->field(0)->heuristic_type());
+ // Address Line 2.
+ EXPECT_EQ(ADDRESS_HOME_LINE2, form_structure->field(1)->heuristic_type());
+ // City.
+ EXPECT_EQ(ADDRESS_HOME_CITY, form_structure->field(2)->heuristic_type());
+}
+
TEST(FormStructureTest, HeuristicsStateWithProvince) {
scoped_ptr<FormStructure> form_structure;
FormData form;
@@ -851,15 +967,13 @@ TEST(FormStructureTest, HeuristicsWithBilling) {
form_structure.reset(new FormStructure(form));
EXPECT_TRUE(form_structure->IsAutoFillable());
ASSERT_EQ(11U, form_structure->field_count());
- ASSERT_EQ(10U, form_structure->autofill_count());
+ ASSERT_EQ(11U, form_structure->autofill_count());
EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type());
EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type());
EXPECT_EQ(COMPANY_NAME, form_structure->field(2)->heuristic_type());
EXPECT_EQ(ADDRESS_BILLING_LINE1, form_structure->field(3)->heuristic_type());
- // Note: We'd expect this to match ADDRESS_BILLING_LINE2, but due to toolbar
- // heuristics for other pages we skip fields with label including "suite".
- EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(4)->heuristic_type());
+ EXPECT_EQ(ADDRESS_BILLING_LINE2, form_structure->field(4)->heuristic_type());
EXPECT_EQ(ADDRESS_BILLING_CITY, form_structure->field(5)->heuristic_type());
EXPECT_EQ(ADDRESS_BILLING_STATE, form_structure->field(6)->heuristic_type());
EXPECT_EQ(ADDRESS_BILLING_COUNTRY,
@@ -916,4 +1030,88 @@ TEST(FormStructureTest, ThreePartPhoneNumber) {
EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(3)->heuristic_type());
}
+TEST(FormStructureTest, MatchSpecificInputTypes) {
+ scoped_ptr<FormStructure> form_structure;
+ FormData form;
+ form.method = ASCIIToUTF16("post");
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("First Name"),
+ ASCIIToUTF16("firstname"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Last Name"),
+ ASCIIToUTF16("lastname"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("EMail"),
+ ASCIIToUTF16("email"),
+ string16(),
+ ASCIIToUTF16("email"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Phone"),
+ ASCIIToUTF16("phone"),
+ string16(),
+ ASCIIToUTF16("number"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Country"),
+ ASCIIToUTF16("country"),
+ string16(),
+ ASCIIToUTF16("select-one"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Fax"),
+ ASCIIToUTF16("fax"),
+ string16(),
+ ASCIIToUTF16("tel"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("Address"),
+ ASCIIToUTF16("address"),
+ string16(),
+ ASCIIToUTF16("radio"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("City"),
+ ASCIIToUTF16("city"),
+ string16(),
+ ASCIIToUTF16("checkbox"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(ASCIIToUTF16("State"),
+ ASCIIToUTF16("state"),
+ string16(),
+ ASCIIToUTF16("hidden"),
+ 0));
+ form.fields.push_back(webkit_glue::FormField(string16(),
+ ASCIIToUTF16("Submit"),
+ string16(),
+ ASCIIToUTF16("submit"),
+ 0));
+ form_structure.reset(new FormStructure(form));
+ EXPECT_TRUE(form_structure->IsAutoFillable());
+
+ // Expect the correct number of fields.
+ ASSERT_EQ(10U, form_structure->field_count());
+ ASSERT_EQ(6U, form_structure->autofill_count());
+
+ // First name.
+ EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type());
+ // Last name.
+ EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type());
+ // Email.
+ EXPECT_EQ(EMAIL_ADDRESS, form_structure->field(2)->heuristic_type());
+ // Phone.
+ EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER,
+ form_structure->field(3)->heuristic_type());
+ // Country.
+ EXPECT_EQ(ADDRESS_HOME_COUNTRY, form_structure->field(4)->heuristic_type());
+ // Fax.
+ EXPECT_EQ(PHONE_FAX_WHOLE_NUMBER, form_structure->field(5)->heuristic_type());
+ // Address. Invalid input type.
+ EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(6)->heuristic_type());
+ // City. Invalid input type.
+ EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(7)->heuristic_type());
+ // State. Invalid input type.
+ EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(8)->heuristic_type());
+ // Submit. Invalid input type.
+ EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(9)->heuristic_type());
+}
+
} // namespace
diff --git a/chrome/browser/autofill/home_address.h b/chrome/browser/autofill/home_address.h
index bf51dc5..ced2922 100644
--- a/chrome/browser/autofill/home_address.h
+++ b/chrome/browser/autofill/home_address.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_HOME_ADDRESS_H_
#define CHROME_BROWSER_AUTOFILL_HOME_ADDRESS_H_
+#pragma once
#include "chrome/browser/autofill/address.h"
#include "chrome/browser/autofill/field_types.h"
diff --git a/chrome/browser/autofill/home_phone_number.h b/chrome/browser/autofill/home_phone_number.h
index d4051c9..e2aba0a 100644
--- a/chrome/browser/autofill/home_phone_number.h
+++ b/chrome/browser/autofill/home_phone_number.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_HOME_PHONE_NUMBER_H_
#define CHROME_BROWSER_AUTOFILL_HOME_PHONE_NUMBER_H_
+#pragma once
#include "chrome/browser/autofill/phone_number.h"
diff --git a/chrome/browser/autofill/name_field.cc b/chrome/browser/autofill/name_field.cc
index c11a018..8163d7a 100644
--- a/chrome/browser/autofill/name_field.cc
+++ b/chrome/browser/autofill/name_field.cc
@@ -6,6 +6,7 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_type.h"
NameField* NameField::Parse(std::vector<AutoFillField*>::const_iterator* iter,
@@ -76,7 +77,7 @@ FirstLastNameField* FirstLastNameField::Parse2(
// American-style).
// The ".*first$" matches fields ending in "first" (example in sample8.html).
string16 match =
- ASCIIToUTF16("first *name|first_name|initials|fname|.*first$");
+ ASCIIToUTF16("first *name|first_name|initials|fname|first$");
if (!ParseText(&q, match, &v->first_name_))
return NULL;
@@ -85,16 +86,16 @@ FirstLastNameField* FirstLastNameField::Parse2(
// as both (the label text is "MI" and the element name is
// "txtmiddlename"); such a field probably actually represents a
// middle initial.
- match = ASCIIToUTF16("^mi$|middle initial|middleinitial|m.i.");
+ match = ASCIIToUTF16("middle *initial|middle_initial|m\\.i\\.|mi$");
if (ParseText(&q, match, &v->middle_name_)) {
v->middle_initial_ = true;
} else {
- match = ASCIIToUTF16("middle *name|mname");
+ match = ASCIIToUTF16("middle *name|middle_name|mname|middle$");
ParseText(&q, match, &v->middle_name_);
}
// The ".*last$" matches fields ending in "last" (example in sample8.html).
- match = ASCIIToUTF16("last *name|last_name|lname|surname|.*last$");
+ match = ASCIIToUTF16("last *name|last_name|lname|surname|last$");
if (!ParseText(&q, match, &v->last_name_))
return NULL;
diff --git a/chrome/browser/autofill/name_field.h b/chrome/browser/autofill/name_field.h
index 5d6e4e5..7b16e77 100644
--- a/chrome/browser/autofill/name_field.h
+++ b/chrome/browser/autofill/name_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_NAME_FIELD_H_
#define CHROME_BROWSER_AUTOFILL_NAME_FIELD_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/name_field_unittest.cc b/chrome/browser/autofill/name_field_unittest.cc
index 11e453e..03cbec3 100644
--- a/chrome/browser/autofill/name_field_unittest.cc
+++ b/chrome/browser/autofill/name_field_unittest.cc
@@ -4,6 +4,7 @@
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/name_field.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -195,4 +196,242 @@ TEST_F(NameFieldTest, FirstLastMiddleWithSpaces) {
EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
}
+TEST_F(NameFieldTest, FirstLastEmpty) {
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("first_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name1")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(string16(),
+ ASCIIToUTF16("last_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name2")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, false));
+ ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
+ ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
+ EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
+ EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name2")]);
+}
+
+TEST_F(NameFieldTest, FirstMiddleLastEmpty) {
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(ASCIIToUTF16("Name"),
+ ASCIIToUTF16("first_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name1")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(string16(),
+ ASCIIToUTF16("middle_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name2")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(string16(),
+ ASCIIToUTF16("last_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name3")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, false));
+ ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
+ ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
+ EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
+ EXPECT_EQ(NAME_MIDDLE_INITIAL, field_type_map_[ASCIIToUTF16("name2")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
+ EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+}
+
+TEST_F(NameFieldTest, MiddleInitial) {
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(ASCIIToUTF16("First Name"),
+ ASCIIToUTF16("first_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name1")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(ASCIIToUTF16("MI"),
+ ASCIIToUTF16("middle_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name2")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(ASCIIToUTF16("Last Name"),
+ ASCIIToUTF16("last_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name3")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, false));
+ ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
+ ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
+ EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
+ EXPECT_EQ(NAME_MIDDLE_INITIAL, field_type_map_[ASCIIToUTF16("name2")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
+ EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+}
+
+TEST_F(NameFieldTest, MiddleInitialNoLastName) {
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(ASCIIToUTF16("First Name"),
+ ASCIIToUTF16("first_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name1")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(ASCIIToUTF16("MI"),
+ ASCIIToUTF16("middle_name"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name2")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, false));
+ ASSERT_EQ(static_cast<NameField*>(NULL), field_.get());
+}
+
+// This case is from the dell.com checkout page. The middle initial "mi" string
+// came at the end following other descriptive text. http://crbug.com/45123.
+TEST_F(NameFieldTest, MiddleInitialAtEnd) {
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(string16(),
+ ASCIIToUTF16("XXXnameXXXfirst"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name1")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(string16(),
+ ASCIIToUTF16("XXXnameXXXmi"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name2")));
+ list_.push_back(
+ new AutoFillField(webkit_glue::FormField(string16(),
+ ASCIIToUTF16("XXXnameXXXlast"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name3")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, false));
+ ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
+ ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
+ EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
+ EXPECT_EQ(NAME_MIDDLE_INITIAL, field_type_map_[ASCIIToUTF16("name2")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
+ EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+}
+
+TEST_F(NameFieldTest, ECMLNoName) {
+ list_.push_back(new AutoFillField(
+ webkit_glue::FormField(ASCIIToUTF16("Company"),
+ ASCIIToUTF16("ecom_shipto_postal_company"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("field1")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, true));
+ ASSERT_EQ(static_cast<NameField*>(NULL), field_.get());
+}
+
+TEST_F(NameFieldTest, ECMLMiddleInitialNoLastName) {
+ list_.push_back(new AutoFillField(
+ webkit_glue::FormField(ASCIIToUTF16("First Name"),
+ ASCIIToUTF16("ecom_shipto_postal_name_first"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name1")));
+ list_.push_back(new AutoFillField(
+ webkit_glue::FormField(ASCIIToUTF16("Middle"),
+ ASCIIToUTF16("ecom_shipto_postal_name_middle"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name2")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, true));
+ ASSERT_EQ(static_cast<NameField*>(NULL), field_.get());
+}
+
+TEST_F(NameFieldTest, ECMLFirstMiddleLast) {
+ list_.push_back(new AutoFillField(
+ webkit_glue::FormField(string16(),
+ ASCIIToUTF16("ecom_shipto_postal_name_first"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name1")));
+ list_.push_back(new AutoFillField(
+ webkit_glue::FormField(string16(),
+ ASCIIToUTF16("ecom_shipto_postal_name_middle"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name2")));
+ list_.push_back(new AutoFillField(
+ webkit_glue::FormField(string16(),
+ ASCIIToUTF16("ecom_shipto_postal_name_last"),
+ string16(),
+ ASCIIToUTF16("text"),
+ 0),
+ ASCIIToUTF16("name3")));
+ list_.push_back(NULL);
+ iter_ = list_.begin();
+ field_.reset(NameField::Parse(&iter_, true));
+ ASSERT_NE(static_cast<NameField*>(NULL), field_.get());
+ ASSERT_TRUE(field_->GetFieldInfo(&field_type_map_));
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
+ EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
+ EXPECT_EQ(NAME_MIDDLE, field_type_map_[ASCIIToUTF16("name2")]);
+ ASSERT_TRUE(
+ field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
+ EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+}
+
} // namespace
diff --git a/chrome/browser/autofill/personal_data_manager.cc b/chrome/browser/autofill/personal_data_manager.cc
index b15526e..c282bea 100644
--- a/chrome/browser/autofill/personal_data_manager.cc
+++ b/chrome/browser/autofill/personal_data_manager.cc
@@ -8,6 +8,7 @@
#include <iterator>
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/autofill_field.h"
@@ -16,7 +17,7 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
namespace {
@@ -27,6 +28,33 @@ const int kMinImportSize = 3;
const char kUnlabeled[] = "Unlabeled";
+template<typename T>
+class FormGroupIDMatchesFunctor {
+ public:
+ explicit FormGroupIDMatchesFunctor(int id) : id_(id) {}
+
+ bool operator()(const T& form_group) {
+ return form_group.unique_id() == id_;
+ }
+
+ private:
+ int id_;
+};
+
+template<typename T>
+class DereferenceFunctor {
+ public:
+ template<typename T_Iterator>
+ const T& operator()(const T_Iterator& iterator) {
+ return *iterator;
+ }
+};
+
+template<typename T>
+T* address_of(T& v) {
+ return &v;
+}
+
} // namespace
PersonalDataManager::~PersonalDataManager() {
@@ -82,7 +110,7 @@ void PersonalDataManager::OnAutoFillDialogApply(
}
void PersonalDataManager::SetObserver(PersonalDataManager::Observer* observer) {
- // TODO: RemoveObserver is for compatability with old code, it should be
+ // TODO: RemoveObserver is for compatibility with old code, it should be
// nuked.
observers_.RemoveObserver(observer);
observers_.AddObserver(observer);
@@ -229,9 +257,12 @@ void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) {
std::mem_fun_ref(&AutoFillProfile::IsEmpty)),
profiles->end());
+<<<<<<< HEAD
SetUniqueProfileLabels(profiles);
#ifndef ANDROID
+=======
+>>>>>>> Chromium at release 7.0.540.0
WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
if (!wds)
return;
@@ -276,6 +307,15 @@ void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) {
}
}
+ // Ensure that profile labels are up to date. Currently, sync relies on
+ // labels to identify a profile.
+ // TODO(dhollowa): We need to deprecate labels and update the way sync
+ // identifies profiles.
+ std::vector<AutoFillProfile*> profile_pointers(profiles->size());
+ std::transform(profiles->begin(), profiles->end(), profile_pointers.begin(),
+ address_of<AutoFillProfile>);
+ AutoFillProfile::AdjustInferredLabels(&profile_pointers);
+
// Add the new profiles to the web database.
for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
iter != profiles->end(); ++iter) {
@@ -283,11 +323,8 @@ void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) {
// unique ID. This also means we need to add this profile to the web
// database.
if (iter->unique_id() == 0) {
- iter->set_unique_id(CreateNextUniqueID(&unique_ids_));
+ iter->set_unique_id(CreateNextUniqueIDFor(&unique_profile_ids_));
wds->AddAutoFillProfile(*iter);
-
- // Update the list of unique profile IDs.
- unique_profile_ids_.insert(iter->unique_id());
}
}
#endif
@@ -368,11 +405,8 @@ void PersonalDataManager::SetCreditCards(
// unique ID. This also means we need to add this credit card to the web
// database.
if (iter->unique_id() == 0) {
- iter->set_unique_id(CreateNextUniqueID(&unique_ids_));
+ iter->set_unique_id(CreateNextUniqueIDFor(&unique_creditcard_ids_));
wds->AddCreditCard(*iter);
-
- // Update the list of unique credit card IDs.
- unique_creditcard_ids_.insert(iter->unique_id());
}
}
#endif
@@ -386,6 +420,125 @@ void PersonalDataManager::SetCreditCards(
FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataChanged());
}
+// TODO(jhawkins): Refactor SetProfiles so this isn't so hacky.
+void PersonalDataManager::AddProfile(const AutoFillProfile& profile) {
+ // Set to true if |profile| is merged into the profile list.
+ bool merged = false;
+
+ // Don't save a web profile if the data in the profile is a subset of an
+ // auxiliary profile.
+ for (std::vector<AutoFillProfile*>::const_iterator iter =
+ auxiliary_profiles_.begin();
+ iter != auxiliary_profiles_.end(); ++iter) {
+ if (profile.IsSubsetOf(**iter))
+ return;
+ }
+
+ std::vector<AutoFillProfile> profiles;
+ for (std::vector<AutoFillProfile*>::const_iterator iter =
+ web_profiles_.begin();
+ iter != web_profiles_.end(); ++iter) {
+ if (profile.IsSubsetOf(**iter)) {
+ // In this case, the existing profile already contains all of the data
+ // in |profile|, so consider the profiles already merged.
+ merged = true;
+ } else if ((*iter)->IntersectionOfTypesHasEqualValues(profile)) {
+ // |profile| contains all of the data in this profile, plus
+ // more.
+ merged = true;
+ (*iter)->MergeWith(profile);
+ }
+
+ profiles.push_back(**iter);
+ }
+
+ if (!merged)
+ profiles.push_back(profile);
+
+ SetProfiles(&profiles);
+}
+
+void PersonalDataManager::UpdateProfile(const AutoFillProfile& profile) {
+ WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
+ if (!wds)
+ return;
+
+ // Update the cached profile.
+ for (std::vector<AutoFillProfile*>::iterator iter = web_profiles_->begin();
+ iter != web_profiles_->end(); ++iter) {
+ if ((*iter)->unique_id() == profile.unique_id()) {
+ delete *iter;
+ *iter = new AutoFillProfile(profile);
+ break;
+ }
+ }
+
+ wds->UpdateAutoFillProfile(profile);
+ FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataChanged());
+}
+
+void PersonalDataManager::RemoveProfile(int unique_id) {
+ // TODO(jhawkins): Refactor SetProfiles so this isn't so hacky.
+ std::vector<AutoFillProfile> profiles(web_profiles_.size());
+ std::transform(web_profiles_.begin(), web_profiles_.end(),
+ profiles.begin(),
+ DereferenceFunctor<AutoFillProfile>());
+
+ // Remove the profile that matches |unique_id|.
+ profiles.erase(
+ std::remove_if(profiles.begin(), profiles.end(),
+ FormGroupIDMatchesFunctor<AutoFillProfile>(unique_id)),
+ profiles.end());
+
+ SetProfiles(&profiles);
+}
+
+// TODO(jhawkins): Refactor SetCreditCards so this isn't so hacky.
+void PersonalDataManager::AddCreditCard(const CreditCard& credit_card) {
+ std::vector<CreditCard> credit_cards(credit_cards_.size());
+ std::transform(credit_cards_.begin(), credit_cards_.end(),
+ credit_cards.begin(),
+ DereferenceFunctor<CreditCard>());
+
+ credit_cards.push_back(credit_card);
+ SetCreditCards(&credit_cards);
+}
+
+void PersonalDataManager::UpdateCreditCard(const CreditCard& credit_card) {
+ WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
+ if (!wds)
+ return;
+
+ // Update the cached credit card.
+ for (std::vector<CreditCard*>::iterator iter = credit_cards_->begin();
+ iter != credit_cards_->end(); ++iter) {
+ if ((*iter)->unique_id() == credit_card.unique_id()) {
+ delete *iter;
+ *iter = new CreditCard(credit_card);
+ break;
+ }
+ }
+
+ wds->UpdateCreditCard(credit_card);
+ FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataChanged());
+}
+
+void PersonalDataManager::RemoveCreditCard(int unique_id) {
+ // TODO(jhawkins): Refactor SetCreditCards so this isn't so hacky.
+ std::vector<CreditCard> credit_cards(credit_cards_.size());
+ std::transform(credit_cards_.begin(), credit_cards_.end(),
+ credit_cards.begin(),
+ DereferenceFunctor<CreditCard>());
+
+ // Remove the credit card that matches |unique_id|.
+ credit_cards.erase(
+ std::remove_if(credit_cards.begin(), credit_cards.end(),
+ FormGroupIDMatchesFunctor<CreditCard>(unique_id)),
+ credit_cards.end());
+
+ SetCreditCards(&credit_cards);
+}
+
void PersonalDataManager::GetPossibleFieldTypes(const string16& text,
FieldTypeSet* possible_types) {
string16 clean_info = StringToLowerASCII(CollapseWhitespace(text, false));
@@ -467,9 +620,7 @@ AutoFillProfile* PersonalDataManager::CreateNewEmptyAutoFillProfileForDBThread(
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
AutoLock lock(unique_ids_lock_);
AutoFillProfile* p = new AutoFillProfile(label,
- CreateNextUniqueID(&unique_ids_));
- // Also update the unique profile IDs.
- unique_profile_ids_.insert(p->unique_id());
+ CreateNextUniqueIDFor(&unique_profile_ids_));
return p;
#endif
}
@@ -492,7 +643,7 @@ void PersonalDataManager::Init(Profile* profile) {
LoadCreditCards();
}
-int PersonalDataManager::CreateNextUniqueID(std::set<int>* unique_ids) {
+int PersonalDataManager::CreateNextUniqueIDFor(std::set<int>* id_set) {
// Profile IDs MUST start at 1 to allow 0 as an error value when reading
// the ID from the WebDB (see LoadData()).
#ifdef ANDROID
@@ -500,9 +651,10 @@ int PersonalDataManager::CreateNextUniqueID(std::set<int>* unique_ids) {
#else
unique_ids_lock_.AssertAcquired();
int id = 1;
- while (unique_ids->count(id) != 0)
+ while (unique_ids_.count(id) != 0)
++id;
- unique_ids->insert(id);
+ unique_ids_.insert(id);
+ id_set->insert(id);
return id;
#endif
}
@@ -566,6 +718,7 @@ void PersonalDataManager::ReceiveLoadedProfiles(WebDataService::Handle h,
for (std::vector<AutoFillProfile*>::iterator iter = profiles.begin();
iter != profiles.end(); ++iter) {
unique_profile_ids_.insert((*iter)->unique_id());
+ unique_ids_.insert((*iter)->unique_id());
web_profiles_.push_back(*iter);
}
#endif
@@ -588,6 +741,7 @@ void PersonalDataManager::ReceiveLoadedCreditCards(
for (std::vector<CreditCard*>::iterator iter = credit_cards.begin();
iter != credit_cards.end(); ++iter) {
unique_creditcard_ids_.insert((*iter)->unique_id());
+ unique_ids_.insert((*iter)->unique_id());
credit_cards_.push_back(*iter);
}
#endif
@@ -609,28 +763,6 @@ void PersonalDataManager::CancelPendingQuery(WebDataService::Handle* handle) {
#endif
}
-void PersonalDataManager::SetUniqueProfileLabels(
- std::vector<AutoFillProfile>* profiles) {
- std::map<string16, std::vector<AutoFillProfile*> > label_map;
- for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
- iter != profiles->end(); ++iter) {
- label_map[iter->Label()].push_back(&(*iter));
- }
-
- for (std::map<string16, std::vector<AutoFillProfile*> >::iterator iter =
- label_map.begin();
- iter != label_map.end(); ++iter) {
- // Start at the second element because the first label should not be
- // renamed. The appended label number starts at 2, because the first label
- // has an implicit index of 1.
- for (size_t i = 1; i < iter->second.size(); ++i) {
- string16 newlabel = iter->second[i]->Label() +
- UintToString16(static_cast<unsigned int>(i + 1));
- iter->second[i]->set_label(newlabel);
- }
- }
-}
-
void PersonalDataManager::SetUniqueCreditCardLabels(
std::vector<CreditCard>* credit_cards) {
std::map<string16, std::vector<CreditCard*> > label_map;
@@ -647,7 +779,7 @@ void PersonalDataManager::SetUniqueCreditCardLabels(
// has an implicit index of 1.
for (size_t i = 1; i < iter->second.size(); ++i) {
string16 newlabel = iter->second[i]->Label() +
- UintToString16(static_cast<unsigned int>(i + 1));
+ base::UintToString16(static_cast<unsigned int>(i + 1));
iter->second[i]->set_label(newlabel);
}
}
@@ -664,6 +796,7 @@ void PersonalDataManager::SaveImportedProfile() {
if (!imported_profile_.get())
return;
+<<<<<<< HEAD
// Set to true if |imported_profile_| is merged into the profile list.
bool merged = false;
@@ -702,6 +835,9 @@ void PersonalDataManager::SaveImportedProfile() {
SetProfiles(&profiles);
#endif
+=======
+ AddProfile(*imported_profile_);
+>>>>>>> Chromium at release 7.0.540.0
}
// TODO(jhawkins): Refactor and merge this with SaveImportedProfile.
diff --git a/chrome/browser/autofill/personal_data_manager.h b/chrome/browser/autofill/personal_data_manager.h
index 7b4d0f3..008cb2b 100644
--- a/chrome/browser/autofill/personal_data_manager.h
+++ b/chrome/browser/autofill/personal_data_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_PERSONAL_DATA_MANAGER_H_
#define CHROME_BROWSER_AUTOFILL_PERSONAL_DATA_MANAGER_H_
+#pragma once
#include <set>
#include <vector>
@@ -99,6 +100,24 @@ class PersonalDataManager
// ID of newly-added profiles.
void SetCreditCards(std::vector<CreditCard>* credit_cards);
+ // Adds |profile| to the web database.
+ void AddProfile(const AutoFillProfile& profile);
+
+ // Updates |profile| which already exists in the web database.
+ void UpdateProfile(const AutoFillProfile& profile);
+
+ // Removes the profile represented by |unique_id|.
+ void RemoveProfile(int unique_id);
+
+ // Adds |credit_card| to the web database.
+ void AddCreditCard(const CreditCard& credit_card);
+
+ // Updates |credit_card| which already exists in the web database.
+ void UpdateCreditCard(const CreditCard& credit_card);
+
+ // Removes the credit card represented by |unique_id|.
+ void RemoveCreditCard(int unique_id);
+
// Gets the possible field types for the given text, determined by matching
// the text with all known personal information and returning matching types.
void GetPossibleFieldTypes(const string16& text,
@@ -166,8 +185,11 @@ class PersonalDataManager
// Returns the profile of the tab contents.
Profile* profile();
- // This will create and reserve a new unique ID for a profile.
- int CreateNextUniqueID(std::set<int>* unique_ids);
+ // This will create and reserve a new unique ID for the id pool |id_set|.
+ // The |id_set| is typically |unique_profile_ids_| or
+ // |unique_creditcard_ids_|. The global pool |unique_ids_| is used to ensure
+ // uniqueness of ids across all pools. The new (next) unique id is returned.
+ int CreateNextUniqueIDFor(std::set<int>* id_set);
// Loads the saved profiles from the web database.
virtual void LoadProfiles();
@@ -196,7 +218,6 @@ class PersonalDataManager
// to the end of non-unique labels.
// TODO(jhawkins): Create a new interface for labeled entities and turn these
// two methods into one.
- void SetUniqueProfileLabels(std::vector<AutoFillProfile>* profiles);
void SetUniqueCreditCardLabels(std::vector<CreditCard>* credit_cards);
// Saves |imported_profile_| to the WebDB if it exists.
@@ -216,6 +237,10 @@ class PersonalDataManager
// profile ID.
std::set<int> unique_profile_ids_;
+ // The set of already created unique profile IDs for auxiliary profiles, used
+ // to create a new unique auxiliary profile ID.
+ std::set<int> unique_auxiliary_profile_ids_;
+
// The set of already created unique credit card IDs, used to create a new
// unique credit card ID.
std::set<int> unique_creditcard_ids_;
diff --git a/chrome/browser/autofill/personal_data_manager_mac.mm b/chrome/browser/autofill/personal_data_manager_mac.mm
index ff199af..b2bf60d 100644
--- a/chrome/browser/autofill/personal_data_manager_mac.mm
+++ b/chrome/browser/autofill/personal_data_manager_mac.mm
@@ -250,6 +250,28 @@ void AuxiliaryProfilesImpl::GetAddressBookPhoneNumbers(
// Populate |auxiliary_profiles_| with the Address Book data.
void PersonalDataManager::LoadAuxiliaryProfiles() {
+ AutoLock lock(unique_ids_lock_);
+
+ // Before loading new auxiliary profiles remove the unique ids from the
+ // id pools. The |GetAddressBookMeCard()| call below clears the
+ // |auxiliary_profiles_|.
+ unique_auxiliary_profile_ids_.clear();
+ for (ScopedVector<AutoFillProfile>::iterator iter
+ = auxiliary_profiles_.begin();
+ iter != auxiliary_profiles_.end(); ++iter) {
+ if ((*iter)->unique_id() != 0) {
+ unique_ids_.erase((*iter)->unique_id());
+ }
+ }
+
AuxiliaryProfilesImpl impl(&auxiliary_profiles_);
impl.GetAddressBookMeCard();
+
+ // For newly fetched auxiliary profiles, ensure that we have unique ids set.
+ for (ScopedVector<AutoFillProfile>::iterator iter
+ = auxiliary_profiles_.begin();
+ iter != auxiliary_profiles_.end(); ++iter) {
+ (*iter)->set_unique_id(
+ CreateNextUniqueIDFor(&unique_auxiliary_profile_ids_));
+ }
}
diff --git a/chrome/browser/autofill/personal_data_manager_unittest.cc b/chrome/browser/autofill/personal_data_manager_unittest.cc
index b60ef41..1709421 100644
--- a/chrome/browser/autofill/personal_data_manager_unittest.cc
+++ b/chrome/browser/autofill/personal_data_manager_unittest.cc
@@ -6,12 +6,13 @@
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_common_unittest.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer_mock.h"
@@ -82,8 +83,8 @@ class PersonalDataManagerTest : public testing::Test {
AutoFillProfile* MakeProfile() {
AutoLock lock(personal_data_->unique_ids_lock_);
return new AutoFillProfile(string16(),
- personal_data_->CreateNextUniqueID(
- &personal_data_->unique_profile_ids_));
+ personal_data_->CreateNextUniqueIDFor(
+ &personal_data_->unique_profile_ids_));
}
MessageLoopForUI message_loop_;
@@ -132,8 +133,11 @@ TEST_F(PersonalDataManagerTest, SetProfiles) {
// The PersonalDataManager will update the unique IDs when saving the
// profiles, so we have to update the expectations.
+ // Same for labels.
profile0.set_unique_id(update[0].unique_id());
profile1.set_unique_id(update[1].unique_id());
+ profile0.set_label(update[0].Label());
+ profile1.set_label(update[1].Label());
const std::vector<AutoFillProfile*>& results1 = personal_data_->profiles();
ASSERT_EQ(2U, results1.size());
@@ -151,7 +155,10 @@ TEST_F(PersonalDataManagerTest, SetProfiles) {
personal_data_->SetProfiles(&update);
// Set the expected unique ID for profile2.
+ // Same for labels.
+ profile0.set_label(update[0].Label());
profile2.set_unique_id(update[1].unique_id());
+ profile2.set_label(update[1].Label());
// AutoFillProfile IDs are re-used, so the third profile to be added will have
// a unique ID that matches the old unique ID of the removed profile1, even
@@ -178,7 +185,9 @@ TEST_F(PersonalDataManagerTest, SetProfiles) {
// Verify that we've loaded the profiles from the web database.
const std::vector<AutoFillProfile*>& results3 = personal_data_->profiles();
ASSERT_EQ(2U, results3.size());
+ profile0.set_label(results3.at(0)->Label());
EXPECT_EQ(profile0, *results3.at(0));
+ profile2.set_label(results3.at(1)->Label());
EXPECT_EQ(profile2, *results3.at(1));
}
@@ -186,15 +195,15 @@ TEST_F(PersonalDataManagerTest, SetProfiles) {
TEST_F(PersonalDataManagerTest, SetCreditCards) {
CreditCard creditcard0(string16(), 0);
autofill_unittest::SetCreditCardInfo(&creditcard0, "Corporate",
- "John Dillinger", "Visa", "123456789012", "01", "2010", "Chicago");
+ "John Dillinger", "Visa", "123456789012", "01", "2010", 1);
CreditCard creditcard1(string16(), 0);
autofill_unittest::SetCreditCardInfo(&creditcard1, "Personal",
- "Bonnie Parker", "Mastercard", "098765432109", "12", "2012", "Dallas");
+ "Bonnie Parker", "Mastercard", "098765432109", "12", "2012", 2);
CreditCard creditcard2(string16(), 0);
autofill_unittest::SetCreditCardInfo(&creditcard2, "Savings", "Clyde Barrow",
- "American Express", "777666888555", "04", "2015", "Home");
+ "American Express", "777666888555", "04", "2015", 3);
// This will verify that the web database has been loaded and the notification
// sent out.
@@ -212,8 +221,11 @@ TEST_F(PersonalDataManagerTest, SetCreditCards) {
// The PersonalDataManager will update the unique IDs when saving the
// credit cards, so we have to update the expectations.
+ // Same for labels.
creditcard0.set_unique_id(update[0].unique_id());
creditcard1.set_unique_id(update[1].unique_id());
+ creditcard0.set_label(update[0].Label());
+ creditcard1.set_label(update[1].Label());
const std::vector<CreditCard*>& results1 = personal_data_->credit_cards();
ASSERT_EQ(2U, results1.size());
@@ -231,7 +243,9 @@ TEST_F(PersonalDataManagerTest, SetCreditCards) {
personal_data_->SetCreditCards(&update);
// Set the expected unique ID for creditcard2.
+ // Same for labels.
creditcard2.set_unique_id(update[1].unique_id());
+ creditcard2.set_label(update[1].Label());
// CreditCard IDs are re-used, so the third credit card to be added will have
// a unique ID that matches the old unique ID of the removed creditcard1, even
@@ -277,11 +291,11 @@ TEST_F(PersonalDataManagerTest, SetProfilesAndCreditCards) {
CreditCard creditcard0(string16(), 0);
autofill_unittest::SetCreditCardInfo(&creditcard0, "Corporate",
- "John Dillinger", "Visa", "123456789012", "01", "2010", "Chicago");
+ "John Dillinger", "Visa", "123456789012", "01", "2010", 1);
CreditCard creditcard1(string16(), 0);
autofill_unittest::SetCreditCardInfo(&creditcard1, "Personal",
- "Bonnie Parker", "Mastercard", "098765432109", "12", "2012", "Dallas");
+ "Bonnie Parker", "Mastercard", "098765432109", "12", "2012", 2);
// This will verify that the web database has been loaded and the notification
// sent out.
@@ -300,8 +314,11 @@ TEST_F(PersonalDataManagerTest, SetProfilesAndCreditCards) {
// The PersonalDataManager will update the unique IDs when saving the
// profiles, so we have to update the expectations.
+ // Same for labels.
profile0.set_unique_id(update[0].unique_id());
profile1.set_unique_id(update[1].unique_id());
+ profile0.set_label(update[0].Label());
+ profile1.set_label(update[1].Label());
const std::vector<AutoFillProfile*>& results1 = personal_data_->profiles();
ASSERT_EQ(2U, results1.size());
@@ -316,8 +333,11 @@ TEST_F(PersonalDataManagerTest, SetProfilesAndCreditCards) {
// The PersonalDataManager will update the unique IDs when saving the
// credit cards, so we have to update the expectations.
+ // Same for labels.
creditcard0.set_unique_id(update_cc[0].unique_id());
creditcard1.set_unique_id(update_cc[1].unique_id());
+ creditcard0.set_label(update_cc[0].Label());
+ creditcard1.set_label(update_cc[1].Label());
const std::vector<CreditCard*>& results2 = personal_data_->credit_cards();
ASSERT_EQ(2U, results2.size());
@@ -334,6 +354,55 @@ TEST_F(PersonalDataManagerTest, SetProfilesAndCreditCards) {
EXPECT_EQ(4U, ids.size());
}
+// Test care for 50047. Makes sure that unique_ids_ is populated correctly on
+// load.
+TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) {
+ AutoFillProfile profile0(string16(), 0);
+ autofill_unittest::SetProfileInfo(&profile0,
+ "", "y", "", "", "", "", "", "", "", "", "", "", "", "");
+
+ // This will verify that the web database has been loaded and the notification
+ // sent out.
+ EXPECT_CALL(personal_data_observer_,
+ OnPersonalDataLoaded()).WillRepeatedly(QuitUIMessageLoop());
+
+ // The message loop will exit when the mock observer is notified.
+ MessageLoop::current()->Run();
+
+ // Add the profile0 to the db.
+ std::vector<AutoFillProfile> update;
+ update.push_back(profile0);
+ personal_data_->SetProfiles(&update);
+
+ // Reset the PersonalDataManager. This recreates PersonalDataManager, which
+ // should populate unique_ids_.
+ ResetPersonalDataManager();
+
+ // The message loop will exit when the PersonalDataLoadedObserver is notified.
+ MessageLoop::current()->Run();
+
+ // Verify that we've loaded the profiles from the web database.
+ const std::vector<AutoFillProfile*>& results2 = personal_data_->profiles();
+ ASSERT_EQ(1U, results2.size());
+
+ // Add a new profile.
+ AutoFillProfile profile1(string16(), 0);
+ autofill_unittest::SetProfileInfo(&profile1,
+ "", "y", "", "", "", "", "", "", "", "", "", "", "", "");
+ update.clear();
+ update.push_back(*results2[0]);
+ update.push_back(profile1);
+ personal_data_->SetProfiles(&update);
+
+ // Make sure the two profiles have different ids (and neither equal to 0,
+ // which is an invalid id).
+ const std::vector<AutoFillProfile*>& results3 = personal_data_->profiles();
+ ASSERT_EQ(2U, results3.size());
+ EXPECT_NE(results3[0]->unique_id(), results3[1]->unique_id());
+ EXPECT_NE(0, results3[0]->unique_id());
+ EXPECT_NE(0, results3[1]->unique_id());
+}
+
TEST_F(PersonalDataManagerTest, SetEmptyProfile) {
AutoFillProfile profile0(string16(), 0);
autofill_unittest::SetProfileInfo(&profile0,
@@ -377,7 +446,7 @@ TEST_F(PersonalDataManagerTest, SetEmptyProfile) {
TEST_F(PersonalDataManagerTest, SetEmptyCreditCard) {
CreditCard creditcard0(string16(), 0);
autofill_unittest::SetCreditCardInfo(&creditcard0,
- "", "", "", "", "", "", "");
+ "", "", "", "", "", "", 0);
// This will verify that the web database has been loaded and the notification
// sent out.
@@ -440,6 +509,8 @@ TEST_F(PersonalDataManagerTest, Refresh) {
profile0.set_unique_id(update[0].unique_id());
profile1.set_unique_id(update[1].unique_id());
+ profile0.set_label(update[0].Label());
+ profile1.set_label(update[1].Label());
// Wait for the refresh.
EXPECT_CALL(personal_data_observer_,
@@ -525,63 +596,16 @@ TEST_F(PersonalDataManagerTest, ImportFormData) {
MessageLoop::current()->Run();
- AutoFillProfile expected(ASCIIToUTF16("Unlabeled"), 1);
- autofill_unittest::SetProfileInfo(&expected, "Unlabeled", "George", NULL,
+ AutoFillProfile expected(string16(), 1);
+ autofill_unittest::SetProfileInfo(&expected, NULL, "George", NULL,
"Washington", "theprez@gmail.com", NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL);
const std::vector<AutoFillProfile*>& results = personal_data_->profiles();
ASSERT_EQ(1U, results.size());
+ expected.set_label(results[0]->Label());
EXPECT_EQ(expected, *results[0]);
}
-TEST_F(PersonalDataManagerTest, SetUniqueProfileLabels) {
- AutoFillProfile profile0(ASCIIToUTF16("Home"), 0);
- profile0.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("John"));
- AutoFillProfile profile1(ASCIIToUTF16("Home"), 0);
- profile1.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Paul"));
- AutoFillProfile profile2(ASCIIToUTF16("Home"), 0);
- profile2.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Ringo"));
- AutoFillProfile profile3(ASCIIToUTF16("NotHome"), 0);
- profile3.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Other"));
- AutoFillProfile profile4(ASCIIToUTF16("Work"), 0);
- profile4.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Ozzy"));
- AutoFillProfile profile5(ASCIIToUTF16("Work"), 0);
- profile5.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Dio"));
-
- // This will verify that the web database has been loaded and the notification
- // sent out.
- EXPECT_CALL(personal_data_observer_,
- OnPersonalDataLoaded()).WillOnce(QuitUIMessageLoop());
-
- // The message loop will exit when the mock observer is notified.
- MessageLoop::current()->Run();
-
- // Add the test profiles to the database.
- std::vector<AutoFillProfile> update;
- update.push_back(profile0);
- update.push_back(profile1);
- update.push_back(profile2);
- update.push_back(profile3);
- update.push_back(profile4);
- update.push_back(profile5);
- personal_data_->SetProfiles(&update);
-
- // And wait for the refresh.
- EXPECT_CALL(personal_data_observer_,
- OnPersonalDataLoaded()).WillOnce(QuitUIMessageLoop());
-
- MessageLoop::current()->Run();
-
- const std::vector<AutoFillProfile*>& results = personal_data_->profiles();
- ASSERT_EQ(6U, results.size());
- EXPECT_EQ(ASCIIToUTF16("Home"), results[0]->Label());
- EXPECT_EQ(ASCIIToUTF16("Home2"), results[1]->Label());
- EXPECT_EQ(ASCIIToUTF16("Home3"), results[2]->Label());
- EXPECT_EQ(ASCIIToUTF16("NotHome"), results[3]->Label());
- EXPECT_EQ(ASCIIToUTF16("Work"), results[4]->Label());
- EXPECT_EQ(ASCIIToUTF16("Work2"), results[5]->Label());
-}
-
TEST_F(PersonalDataManagerTest, SetUniqueCreditCardLabels) {
CreditCard credit_card0(ASCIIToUTF16("Home"), 0);
credit_card0.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("John"));
@@ -651,12 +675,13 @@ TEST_F(PersonalDataManagerTest, AggregateProfileData) {
MessageLoop::current()->Run();
scoped_ptr<AutoFillProfile> expected(
- new AutoFillProfile(ASCIIToUTF16("Unlabeled"), 1));
- autofill_unittest::SetProfileInfo(expected.get(), "Unlabeled", "George", NULL,
+ new AutoFillProfile(string16(), 1));
+ autofill_unittest::SetProfileInfo(expected.get(), NULL, "George", NULL,
"Washington", "theprez@gmail.com", NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL);
const std::vector<AutoFillProfile*>& results = personal_data_->profiles();
ASSERT_EQ(1U, results.size());
+ expected->set_label(results[0]->Label());
EXPECT_EQ(*expected, *results[0]);
// Now create a completely different profile.
@@ -685,16 +710,18 @@ TEST_F(PersonalDataManagerTest, AggregateProfileData) {
const std::vector<AutoFillProfile*>& results2 = personal_data_->profiles();
ASSERT_EQ(2U, results2.size());
- expected.reset(new AutoFillProfile(ASCIIToUTF16("Unlabeled"), 1));
- autofill_unittest::SetProfileInfo(expected.get(), "Unlabeled", "George", NULL,
+ expected.reset(new AutoFillProfile(string16(), 1));
+ autofill_unittest::SetProfileInfo(expected.get(), NULL, "George", NULL,
"Washington", "theprez@gmail.com", NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL);
+ expected->set_label(results2[0]->Label());
EXPECT_EQ(*expected, *results2[0]);
- expected.reset(new AutoFillProfile(ASCIIToUTF16("Unlabeled2"), 2));
- autofill_unittest::SetProfileInfo(expected.get(), "Unlabeled2", "John", NULL,
+ expected.reset(new AutoFillProfile(string16(), 2));
+ autofill_unittest::SetProfileInfo(expected.get(), NULL, "John", NULL,
"Adams", "second@gmail.com", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL);
+ expected->set_label(results2[1]->Label());
EXPECT_EQ(*expected, *results2[1]);
// Submit a form with new data for the first profile.
@@ -732,15 +759,17 @@ TEST_F(PersonalDataManagerTest, AggregateProfileData) {
const std::vector<AutoFillProfile*>& results3 = personal_data_->profiles();
ASSERT_EQ(2U, results3.size());
- expected.reset(new AutoFillProfile(ASCIIToUTF16("Unlabeled"), 1));
- autofill_unittest::SetProfileInfo(expected.get(), "Unlabeled", "George", NULL,
+ expected.reset(new AutoFillProfile(string16(), 1));
+ autofill_unittest::SetProfileInfo(expected.get(), NULL, "George", NULL,
"Washington", "theprez@gmail.com", NULL, "190 High Street", NULL,
"Philadelphia", "Pennsylvania", "19106", NULL, NULL, NULL);
+ expected->set_label(results3[0]->Label());
EXPECT_EQ(*expected, *results3[0]);
- expected.reset(new AutoFillProfile(ASCIIToUTF16("Unlabeled2"), 2));
- autofill_unittest::SetProfileInfo(expected.get(), "Unlabeled2", "John", NULL,
+ expected.reset(new AutoFillProfile(string16(), 2));
+ autofill_unittest::SetProfileInfo(expected.get(), NULL, "John", NULL,
"Adams", "second@gmail.com", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL);
+ expected->set_label(results3[1]->Label());
EXPECT_EQ(*expected, *results3[1]);
}
diff --git a/chrome/browser/autofill/phone_field.cc b/chrome/browser/autofill/phone_field.cc
index 16df07f..e063587 100644
--- a/chrome/browser/autofill/phone_field.cc
+++ b/chrome/browser/autofill/phone_field.cc
@@ -8,6 +8,7 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
// static
diff --git a/chrome/browser/autofill/phone_field.h b/chrome/browser/autofill/phone_field.h
index 6a3c934..2642a5c 100644
--- a/chrome/browser/autofill/phone_field.h
+++ b/chrome/browser/autofill/phone_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_PHONE_FIELD_H_
#define CHROME_BROWSER_AUTOFILL_PHONE_FIELD_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/phone_field_unittest.cc b/chrome/browser/autofill/phone_field_unittest.cc
index e27f09e..ce0ae48 100644
--- a/chrome/browser/autofill/phone_field_unittest.cc
+++ b/chrome/browser/autofill/phone_field_unittest.cc
@@ -4,6 +4,7 @@
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/phone_field.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
diff --git a/chrome/browser/autofill/phone_number.h b/chrome/browser/autofill/phone_number.h
index f9dad65..ef1bafc 100644
--- a/chrome/browser/autofill/phone_number.h
+++ b/chrome/browser/autofill/phone_number.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOFILL_PHONE_NUMBER_H_
#define CHROME_BROWSER_AUTOFILL_PHONE_NUMBER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/autofill/phone_number_unittest.cc b/chrome/browser/autofill/phone_number_unittest.cc
index be61665..bcb37f2 100644
--- a/chrome/browser/autofill/phone_number_unittest.cc
+++ b/chrome/browser/autofill/phone_number_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/utf_string_conversions.h"
#include "chrome/browser/autofill/home_phone_number.h"
#include "chrome/browser/autofill/phone_number.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/autofill/select_control_handler.cc b/chrome/browser/autofill/select_control_handler.cc
new file mode 100644
index 0000000..cbf5292
--- /dev/null
+++ b/chrome/browser/autofill/select_control_handler.cc
@@ -0,0 +1,520 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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/select_control_handler.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/form_group.h"
+#include "webkit/glue/form_field.h"
+
+namespace {
+
+// TODO(jhawkins): Add more states/provinces. See http://crbug.com/45039.
+
+class State {
+ public:
+ const char* name;
+ const char* abbreviation;
+
+ static const State all_states[];
+
+ static string16 Abbreviation(const string16& name);
+ static string16 FullName(const string16& abbreviation);
+};
+
+const State State::all_states[] = {
+ { "alabama", "al" },
+ { "alaska", "ak" },
+ { "arizona", "az" },
+ { "arkansas", "ar" },
+ { "california", "ca" },
+ { "colorado", "co" },
+ { "connecticut", "ct" },
+ { "delaware", "de" },
+ { "district of columbia", "dc" },
+ { "florida", "fl" },
+ { "georgia", "ga" },
+ { "hawaii", "hi" },
+ { "idaho", "id" },
+ { "illinois", "il" },
+ { "indiana", "in" },
+ { "iowa", "ia" },
+ { "kansas", "ks" },
+ { "kentucky", "ky" },
+ { "louisiana", "la" },
+ { "maine", "me" },
+ { "maryland", "md" },
+ { "massachusetts", "ma" },
+ { "michigan", "mi" },
+ { "minnesota", "mv" },
+ { "mississippi", "ms" },
+ { "missouri", "mo" },
+ { "montana", "mt" },
+ { "nebraska", "ne" },
+ { "nevada", "nv" },
+ { "new hampshire", "nh" },
+ { "new jersey", "nj" },
+ { "new mexico", "nm" },
+ { "new york", "ny" },
+ { "north carolina", "nc" },
+ { "north dakota", "nd" },
+ { "ohio", "oh" },
+ { "oklahoma", "ok" },
+ { "oregon", "or" },
+ { "pennsylvania", "pa" },
+ { "puerto rico", "pr" },
+ { "rhode island", "ri" },
+ { "south carolina", "sc" },
+ { "south dakota", "sd" },
+ { "tennessee", "tn" },
+ { "texas", "tx" },
+ { "utah", "ut" },
+ { "vermont", "vt" },
+ { "virginia", "va" },
+ { "washington", "wa" },
+ { "west Virginia", "wv" },
+ { "wisconsin", "wi" },
+ { "wyoming", "wy" },
+ { NULL, NULL }
+};
+
+string16 State::Abbreviation(const string16& name) {
+ for (const State *s = all_states ; s->name ; ++s)
+ if (LowerCaseEqualsASCII(name, s->name))
+ return ASCIIToUTF16(s->abbreviation);
+ return string16();
+}
+
+string16 State::FullName(const string16& abbreviation) {
+ for (const State *s = all_states ; s->name ; ++s)
+ if (LowerCaseEqualsASCII(abbreviation, s->abbreviation))
+ return ASCIIToUTF16(s->name);
+ return string16();
+}
+
+// Holds valid country names, their 2 letter abbreviation, and maps from
+// the former to the latter
+class Country {
+ public:
+ const char* name;
+ const char* abbreviation;
+
+ static const Country all_countries[];
+
+ static string16 Abbreviation(const string16 &name);
+ static string16 FullName(const string16& abbreviation);
+};
+
+// A list of all English country names and code elements. ISO 3166.
+const Country Country::all_countries[] = {
+ { "united states", "us" },
+ { "afghanistan", "af" },
+ { "aland islands", "ax" },
+ { "albania", "al" },
+ { "algeria", "dz" },
+ { "american samoa", "as" },
+ { "andorra", "ad" },
+ { "angola", "ao" },
+ { "anguilla", "ai" },
+ { "antarctica", "aq" },
+ { "antigua and barbuda", "ag" },
+ { "argentina", "ar" },
+ { "armenia", "am" },
+ { "aruba", "aw" },
+ { "australia", "au" },
+ { "austria", "at" },
+ { "azerbaijan", "az" },
+ { "bahamas", "bs" },
+ { "bahrain", "bh" },
+ { "bangladesh", "bd" },
+ { "barbados", "bb" },
+ { "belarus", "by" },
+ { "belgium", "be" },
+ { "belize", "bz" },
+ { "benin", "bj" },
+ { "bermuda", "bm" },
+ { "bhutan", "bt" },
+ { "bolivia", "bo" },
+ { "bosnia and herzegovina", "ba" },
+ { "botswana", "bw" },
+ { "bouvet island", "bv" },
+ { "brazil", "br" },
+ { "british indian ocean territory", "io" },
+ { "brunei darussalam", "bn" },
+ { "bulgaria", "bg" },
+ { "burkina faso", "bf" },
+ { "burundi", "bi" },
+ { "cambodia", "kh" },
+ { "cameroon", "cm" },
+ { "canada", "ca" },
+ { "cape verde", "cv" },
+ { "cayman islands", "ky" },
+ { "central african republic", "cf" },
+ { "chad", "td" },
+ { "chile", "cl" },
+ { "china", "cn" },
+ { "christmas island", "cx" },
+ { "cocos (keeling) islands", "cc" },
+ { "colombia", "co" },
+ { "comoros", "km" },
+ { "congo", "cg" },
+ { "congo (dem. rep.)", "cd" },
+ { "cook islands", "ck" },
+ { "costa rica", "cr" },
+ { "cote d'ivoire", "ci" },
+ { "croatia", "hr" },
+ { "cuba", "cu" },
+ { "cyprus", "cy" },
+ { "czech republic", "cz" },
+ { "denmark", "dk" },
+ { "djibouti", "dj" },
+ { "dominica", "dm" },
+ { "dominican republic", "do" },
+ { "ecuador", "ec" },
+ { "egypt", "eg" },
+ { "el salvador", "sv" },
+ { "equatorial guinea", "gq" },
+ { "eritrea", "er" },
+ { "estonia", "ee" },
+ { "ethiopia", "et" },
+ { "falkland islands (malvinas)", "fk" },
+ { "faroe islands", "fo" },
+ { "fiji", "fj" },
+ { "finland", "fi" },
+ { "france", "fr" },
+ { "french guiana", "gf" },
+ { "french polynesia", "pf" },
+ { "gabon", "ga" },
+ { "gambia", "gm" },
+ { "georgia", "ge" },
+ { "germany", "de" },
+ { "ghana", "gh" },
+ { "gibraltar", "gi" },
+ { "greece", "gr" },
+ { "greenland", "gl" },
+ { "grenada", "gd" },
+ { "guadeloupe", "gp" },
+ { "guam", "gu" },
+ { "guatemala", "gt" },
+ { "guernsey", "cg" },
+ { "guinea", "gn" },
+ { "guinea-bissau", "gw" },
+ { "guyana", "gy" },
+ { "haiti", "ht" },
+ { "heard island and mcdonald islands", "hm" },
+ { "holy see (vatica city state)", "va" },
+ { "honduras", "hn" },
+ { "hong kong", "hk" },
+ { "hungary", "hu" },
+ { "iceland", "is" },
+ { "india", "in" },
+ { "indonesia", "id" },
+ { "iran", "ir" },
+ { "iraq", "iq" },
+ { "ireland", "ie" },
+ { "isle of man", "im" },
+ { "israel", "il" },
+ { "italy", "it" },
+ { "ivory coast", "ci" },
+ { "jamaica", "jm" },
+ { "japan", "jp" },
+ { "jersey", "je" },
+ { "jordan", "jo" },
+ { "kazakhstan", "kz" },
+ { "kenya", "ke" },
+ { "kiribati", "ki" },
+ { "korea (north)", "kp" },
+ { "korea (south)", "kr" },
+ { "kuwait", "kw" },
+ { "kyrgyzstan", "kg" },
+ { "laos", "la" },
+ { "latvia", "lv" },
+ { "lebanon", "lb" },
+ { "lesotho", "ls" },
+ { "liberia", "lr" },
+ { "libya", "ly" },
+ { "liechtenstein", "li" },
+ { "lithuania", "lt" },
+ { "luxembourg", "lu" },
+ { "macao", "mo" },
+ { "macedonia", "mk" },
+ { "madagascar", "mg" },
+ { "malawi", "mw" },
+ { "malaysia", "my" },
+ { "maldives", "mv" },
+ { "mali", "ml" },
+ { "malta", "mt" },
+ { "marshall islands", "mh" },
+ { "martinique", "mq" },
+ { "mauritania", "mr" },
+ { "mauritius", "mu" },
+ { "mayotte", "yt" },
+ { "mexico", "mx" },
+ { "micronesia", "fm" },
+ { "moldova", "md" },
+ { "monaco", "mc" },
+ { "mongolia", "mn" },
+ { "montserrat", "ms" },
+ { "morocco", "ma" },
+ { "mozambique", "mz" },
+ { "myanmar", "mm" },
+ { "namibia", "na" },
+ { "nepal", "np" },
+ { "netherlands", "nl" },
+ { "netherlands antilles", "an" },
+ { "new caledonia", "nc" },
+ { "new zealand", "nz" },
+ { "nicaragua", "ni" },
+ { "niger", "ne" },
+ { "nigeria", "ng" },
+ { "niue", "nu" },
+ { "norfolk island", "nf" },
+ { "northern mariana islands", "mp" },
+ { "norway", "no" },
+ { "oman", "om" },
+ { "pakistan", "pk" },
+ { "palau", "pw" },
+ { "palestine", "ps" },
+ { "panama", "pa" },
+ { "papua new guinea", "pg" },
+ { "paraguay", "py" },
+ { "peru", "pe" },
+ { "philippines", "ph" },
+ { "pitcairn", "pn" },
+ { "poland", "pl" },
+ { "portugal", "pt" },
+ { "puerto rico", "pr" },
+ { "qatar", "qa" },
+ { "reunion", "re" },
+ { "romania", "ro" },
+ { "russia", "ru" },
+ { "rwanda", "rw" },
+ { "saint helena", "sh" },
+ { "saint kitts and nevis", "kn" },
+ { "saint lucia", "lc" },
+ { "saint pierre and miquelon", "pm" },
+ { "saint vincent and the grenadines", "vc" },
+ { "samoa", "ws" },
+ { "san marino", "sm" },
+ { "sao tome and principe", "st" },
+ { "saudi arabia", "sa" },
+ { "senegal", "sn" },
+ { "serbia and montenegro", "cs" },
+ { "seychelles", "sc" },
+ { "sierra leone", "sl" },
+ { "singapore", "sg" },
+ { "slovakia", "sk" },
+ { "slovenia", "si" },
+ { "solomon islands", "sb" },
+ { "somalia", "so" },
+ { "south africa", "za" },
+ { "south georgia and the south sandwich islands", "gs" },
+ { "spain", "es" },
+ { "sri lanka", "lk" },
+ { "sudan", "sd" },
+ { "suriname", "sr" },
+ { "svalbard and jan mayen", "sj" },
+ { "swaziland", "sz" },
+ { "sweden", "se" },
+ { "switzerland", "ch" },
+ { "syria", "sy" },
+ { "taiwan", "tw" },
+ { "tajikistan", "tj" },
+ { "tanzania", "tz" },
+ { "thailand", "th" },
+ { "timor-leste", "tl" },
+ { "togo", "tg" },
+ { "tokelau", "tk" },
+ { "tonga", "to" },
+ { "trinidad and tobago", "tt" },
+ { "tunisia", "tn" },
+ { "turkey", "tr" },
+ { "turkmenistan", "tm" },
+ { "turks and caicos islands", "tc" },
+ { "tuvalu", "tv" },
+ { "uganda", "ug" },
+ { "ukraine", "ua" },
+ { "united arab emirates", "ae" },
+ { "united kingdom", "gb" },
+ { "u.s. minor outlying islands", "um" },
+ { "uruguay", "uy" },
+ { "uzbekistan", "uz" },
+ { "vanuatu", "vu" },
+ { "venezuela", "ve" },
+ { "vietnam", "vn" },
+ { "virgin islands, british", "vg" },
+ { "virgin islands, u.s.", "vi" },
+ { "wallis and futuna", "wf" },
+ { "western sahara", "eh" },
+ { "yemen", "ye" },
+ { "zambia", "zm" },
+ { "zimbabwe", "zw" },
+ { NULL, NULL }
+};
+
+string16 Country::Abbreviation(const string16& name) {
+ for (const Country *s = all_countries ; s->name ; ++s)
+ if (LowerCaseEqualsASCII(name, s->name))
+ return ASCIIToUTF16(s->abbreviation);
+ return string16();
+}
+
+string16 Country::FullName(const string16& abbreviation) {
+ for (const Country *s = all_countries ; s->name ; ++s)
+ if (LowerCaseEqualsASCII(abbreviation, s->abbreviation))
+ return ASCIIToUTF16(s->name);
+ return string16();
+}
+
+const char* const kMonthsAbbreviated[] = {
+ NULL, // Padding so index 1 = month 1 = January.
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+};
+
+const char* const kMonthsFull[] = {
+ NULL, // Padding so index 1 = month 1 = January.
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December",
+};
+
+// Returns true if the value was successfully set, meaning |value| was found in
+// the list of select options in |field|.
+bool SetSelectControlValue(const string16& value,
+ webkit_glue::FormField* field) {
+ string16 value_lowercase = StringToLowerASCII(value);
+
+ for (std::vector<string16>::const_iterator iter =
+ field->option_strings().begin();
+ iter != field->option_strings().end(); ++iter) {
+ if (value_lowercase == StringToLowerASCII(*iter)) {
+ field->set_value(*iter);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool FillStateSelectControl(const string16& value,
+ webkit_glue::FormField* field) {
+ if (value.empty())
+ return false;
+
+ string16 abbrev, full;
+ if (value.size() < 4U) {
+ abbrev = value;
+ full = State::FullName(value);
+ } else {
+ abbrev = State::Abbreviation(value);
+ full = value;
+ }
+
+ // Try the abbreviation name first.
+ if (!abbrev.empty() && SetSelectControlValue(abbrev, field))
+ return true;
+
+ if (full.empty())
+ return false;
+
+ return SetSelectControlValue(full, field);
+}
+
+bool FillCountrySelectControl(const string16& value,
+ webkit_glue::FormField* field) {
+ if (value.empty())
+ return false;
+
+ string16 abbrev, full;
+ if (value.size() < 4U) {
+ abbrev = value;
+ full = Country::FullName(value);
+ } else {
+ abbrev = Country::Abbreviation(value);
+ full = value;
+ }
+
+ // Try the abbreviation name first.
+ if (!abbrev.empty() && SetSelectControlValue(abbrev, field))
+ return true;
+
+ if (full.empty())
+ return false;
+
+ return SetSelectControlValue(full, field);
+}
+
+bool FillExpirationMonthSelectControl(const string16& value,
+ webkit_glue::FormField* field) {
+ if (value.empty())
+ return false;
+
+ if (SetSelectControlValue(value, field))
+ return true;
+
+ int index = 0;
+ if (!base::StringToInt(value, &index) ||
+ index <= 0 ||
+ static_cast<size_t>(index) >= arraysize(kMonthsFull))
+ return false;
+
+ bool filled =
+ SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) ||
+ SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field);
+ return filled;
+}
+
+} // namespace
+
+namespace autofill {
+
+void FillSelectControl(const FormGroup* form_group,
+ AutoFillType type,
+ webkit_glue::FormField* field) {
+ DCHECK(form_group);
+ DCHECK(field);
+ DCHECK(field->form_control_type() == ASCIIToUTF16("select-one"));
+
+ string16 value;
+ string16 field_text = form_group->GetFieldText(type);
+ for (size_t i = 0; i < field->option_strings().size(); ++i) {
+ if (form_group->GetFieldText(type) == field->option_strings()[i]) {
+ // An exact match, use it.
+ value = form_group->GetFieldText(type);
+ break;
+ }
+
+ if (StringToLowerASCII(field->option_strings()[i]) ==
+ StringToLowerASCII(field_text)) {
+ // A match, but not in the same case. Save it in case an exact match is
+ // not found.
+ value = field->option_strings()[i];
+ }
+ }
+
+ if (!value.empty()) {
+ field->set_value(value);
+ return;
+ }
+
+ if (type.field_type() == ADDRESS_HOME_STATE ||
+ type.field_type() == ADDRESS_BILLING_STATE) {
+ FillStateSelectControl(field_text, field);
+ } else if (type.field_type() == ADDRESS_HOME_COUNTRY ||
+ type.field_type() == ADDRESS_BILLING_COUNTRY) {
+ FillCountrySelectControl(field_text, field);
+ } else if (type.field_type() == CREDIT_CARD_EXP_MONTH) {
+ FillExpirationMonthSelectControl(field_text, field);
+ }
+
+ return;
+}
+
+} // namespace autofill
diff --git a/chrome/browser/autofill/select_control_handler.h b/chrome/browser/autofill/select_control_handler.h
new file mode 100644
index 0000000..723600a
--- /dev/null
+++ b/chrome/browser/autofill/select_control_handler.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_AUTOFILL_SELECT_CONTROL_HANDLER_H_
+#define CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_
+#pragma once
+
+#include "chrome/browser/autofill/autofill_type.h"
+
+class FormGroup;
+
+namespace webkit_glue {
+class FormField;
+} // namespace webkit_glue
+
+namespace autofill {
+
+// TODO(jhawkins): This definitely needs tests.
+
+// Fills a select-one control with the appropriate value from |form_group|.
+// Finds the matching value for field types that we know contain different
+// variations of a value, e.g., (tx, TX, Texas) or credit card expiration
+// months, e.g., (04, April).
+void FillSelectControl(const FormGroup* form_group,
+ AutoFillType type,
+ webkit_glue::FormField* field);
+
+} // namespace autofill
+
+#endif // CHROME_BROWSER_AUTOFILL_SELECT_CONTROL_HANDLER_H_
diff --git a/chrome/browser/automation/automation_autocomplete_edit_tracker.h b/chrome/browser/automation/automation_autocomplete_edit_tracker.h
index 3f741f3..2394b89 100644
--- a/chrome/browser/automation/automation_autocomplete_edit_tracker.h
+++ b/chrome/browser/automation/automation_autocomplete_edit_tracker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_AUTOCOMPLETE_EDIT_TRACKER_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_AUTOCOMPLETE_EDIT_TRACKER_H_
+#pragma once
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/automation/automation_resource_tracker.h"
diff --git a/chrome/browser/automation/automation_browser_tracker.h b/chrome/browser/automation/automation_browser_tracker.h
index aa6d034..a58cd1f 100644
--- a/chrome/browser/automation/automation_browser_tracker.h
+++ b/chrome/browser/automation/automation_browser_tracker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_BROWSER_TRACKER_H__
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_BROWSER_TRACKER_H__
+#pragma once
#include "chrome/browser/automation/automation_resource_tracker.h"
#include "chrome/browser/browser.h"
diff --git a/chrome/browser/automation/automation_extension_function.cc b/chrome/browser/automation/automation_extension_function.cc
index c58e45c..2e72c6b 100644
--- a/chrome/browser/automation/automation_extension_function.cc
+++ b/chrome/browser/automation/automation_extension_function.cc
@@ -8,6 +8,7 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/values.h"
#include "chrome/browser/automation/extension_automation_constants.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -19,6 +20,9 @@ TabContents* AutomationExtensionFunction::api_handler_tab_ = NULL;
AutomationExtensionFunction::PendingFunctionsMap
AutomationExtensionFunction::pending_functions_;
+AutomationExtensionFunction::AutomationExtensionFunction() {
+}
+
void AutomationExtensionFunction::SetArgs(const ListValue* args) {
// Need to JSON-encode for sending over the wire to the automation user.
base::JSONWriter::Write(args, false, &args_);
@@ -163,3 +167,6 @@ bool AutomationExtensionFunction::InterceptMessageFromExternalHost(
return false;
}
+
+AutomationExtensionFunction::~AutomationExtensionFunction() {
+}
diff --git a/chrome/browser/automation/automation_extension_function.h b/chrome/browser/automation/automation_extension_function.h
index 5e15e9e..275d3c9 100644
--- a/chrome/browser/automation/automation_extension_function.h
+++ b/chrome/browser/automation/automation_extension_function.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_EXTENSION_FUNCTION_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_EXTENSION_FUNCTION_H_
+#pragma once
#include <map>
#include <string>
@@ -20,7 +21,7 @@ class TabContents;
// automation interface, so that extensions can be tested using UITests.
class AutomationExtensionFunction : public AsyncExtensionFunction {
public:
- AutomationExtensionFunction() { }
+ AutomationExtensionFunction();
// ExtensionFunction implementation.
virtual void SetArgs(const ListValue* args);
@@ -58,7 +59,7 @@ class AutomationExtensionFunction : public AsyncExtensionFunction {
const std::string& target);
private:
- ~AutomationExtensionFunction() {}
+ ~AutomationExtensionFunction();
// Weak reference, lifetime managed by the ExternalTabContainer instance
// owning the TabContents in question.
diff --git a/chrome/browser/automation/automation_extension_tracker.cc b/chrome/browser/automation/automation_extension_tracker.cc
index 8f09e1f..cd816d3 100644
--- a/chrome/browser/automation/automation_extension_tracker.cc
+++ b/chrome/browser/automation/automation_extension_tracker.cc
@@ -20,6 +20,10 @@ AutomationExtensionTracker::AutomationExtensionTracker(
AutomationExtensionTracker::~AutomationExtensionTracker() {
}
+void AutomationExtensionTracker::AddObserver(Extension* resource) {}
+
+void AutomationExtensionTracker::RemoveObserver(Extension* resource) {}
+
void AutomationExtensionTracker::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/automation/automation_extension_tracker.h b/chrome/browser/automation/automation_extension_tracker.h
index e55a2eb..c1b7ed7 100644
--- a/chrome/browser/automation/automation_extension_tracker.h
+++ b/chrome/browser/automation/automation_extension_tracker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_EXTENSION_TRACKER_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_EXTENSION_TRACKER_H_
+#pragma once
#include "chrome/browser/automation/automation_resource_tracker.h"
@@ -13,7 +14,7 @@ class Extension;
class AutomationExtensionTracker
: public AutomationResourceTracker<Extension*> {
public:
- AutomationExtensionTracker(IPC::Message::Sender* automation);
+ explicit AutomationExtensionTracker(IPC::Message::Sender* automation);
virtual ~AutomationExtensionTracker();
@@ -22,10 +23,10 @@ class AutomationExtensionTracker
// extension, is the one who sends the notification about extension
// uninstalls. Instead of using this method, one observer is added for all
// extensions in the constructor.
- virtual void AddObserver(Extension* resource) {}
+ virtual void AddObserver(Extension* resource);
// See related comment above as to why this method is empty.
- virtual void RemoveObserver(Extension* resource) {}
+ virtual void RemoveObserver(Extension* resource);
// Overriding AutomationResourceTracker Observe. AutomationResourceTracker's
// Observe expects the NotificationSource to be the object that is closing.
diff --git a/chrome/browser/automation/automation_profile_impl.cc b/chrome/browser/automation/automation_profile_impl.cc
deleted file mode 100644
index 751019a..0000000
--- a/chrome/browser/automation/automation_profile_impl.cc
+++ /dev/null
@@ -1,216 +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/automation/automation_profile_impl.h"
-
-#include <map>
-
-#include "chrome/browser/automation/automation_resource_message_filter.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/profile.h"
-#include "net/base/net_errors.h"
-#include "net/url_request/url_request_context.h"
-#include "chrome/test/automation/automation_messages.h"
-
-namespace AutomationRequestContext {
-
-// A special Request context for automation. Substitute a few things
-// like cookie store, proxy settings etc to handle them differently
-// for automation.
-class AutomationURLRequestContext : public ChromeURLRequestContext {
- public:
- AutomationURLRequestContext(ChromeURLRequestContext* original_context,
- net::CookieStore* automation_cookie_store,
- net::CookiePolicy* automation_cookie_policy)
- : ChromeURLRequestContext(original_context),
- // We must hold a reference to |original_context|, since many
- // of the dependencies that ChromeURLRequestContext(original_context)
- // copied are scoped to |original_context|.
- original_context_(original_context) {
- cookie_policy_ = automation_cookie_policy;
- cookie_store_ = automation_cookie_store;
- }
-
- virtual bool IsExternal() const {
- return true;
- }
-
- private:
- virtual ~AutomationURLRequestContext() {
- // Clear out members before calling base class dtor since we don't
- // own any of them.
-
- // Clear URLRequestContext members.
- host_resolver_ = NULL;
- proxy_service_ = NULL;
- http_transaction_factory_ = NULL;
- ftp_transaction_factory_ = NULL;
- cookie_store_ = NULL;
- transport_security_state_ = NULL;
- }
-
- scoped_refptr<ChromeURLRequestContext> original_context_;
- DISALLOW_COPY_AND_ASSIGN(AutomationURLRequestContext);
-};
-
-// CookieStore specialization to have automation specific
-// behavior for cookies.
-class AutomationCookieStore : public net::CookieStore {
- public:
- AutomationCookieStore(net::CookieStore* original_cookie_store,
- AutomationResourceMessageFilter* automation_client,
- int tab_handle)
- : original_cookie_store_(original_cookie_store),
- automation_client_(automation_client),
- tab_handle_(tab_handle) {
- }
-
- virtual ~AutomationCookieStore() {
- DLOG(INFO) << "In " << __FUNCTION__;
- }
-
- // CookieStore implementation.
- virtual bool SetCookieWithOptions(const GURL& url,
- const std::string& cookie_line,
- const net::CookieOptions& options) {
- // The cookie_string_ is available only once, i.e. once it is read by
- // it is invalidated.
- cookie_string_ = cookie_line;
- return true;
- }
-
- virtual std::string GetCookiesWithOptions(const GURL& url,
- const net::CookieOptions& options) {
- return cookie_string_;
- }
-
- virtual void DeleteCookie(const GURL& url,
- const std::string& cookie_name) {
- NOTREACHED() << "Should not get called for an automation profile";
- }
-
- virtual net::CookieMonster* GetCookieMonster() {
- NOTREACHED() << "Should not get called for an automation profile";
- return NULL;
- }
-
- protected:
- void SendIPCMessageOnIOThread(IPC::Message* m) {
- if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- automation_client_->Send(m);
- } else {
- Task* task = NewRunnableMethod(this,
- &AutomationCookieStore::SendIPCMessageOnIOThread, m);
- ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, task);
- }
- }
-
- net::CookieStore* original_cookie_store_;
- scoped_refptr<AutomationResourceMessageFilter> automation_client_;
- int tab_handle_;
- std::string cookie_string_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AutomationCookieStore);
-};
-
-// CookiePolicy specialization for automation specific cookie policies.
-class AutomationCookiePolicy : public net::CookiePolicy {
- public:
- AutomationCookiePolicy(AutomationResourceMessageFilter* automation_client,
- int tab_handle, net::CookieStore* cookie_store)
- : automation_client_(automation_client),
- tab_handle_(tab_handle),
- cookie_store_(cookie_store) {}
-
- virtual int CanGetCookies(const GURL& url,
- const GURL& first_party_for_cookies,
- net::CompletionCallback* callback) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-
- if (automation_client_.get()) {
- automation_client_->GetCookiesForUrl(tab_handle_, url, callback,
- cookie_store_.get());
- return net::ERR_IO_PENDING;
- }
- return net::ERR_ACCESS_DENIED;
- }
-
- virtual int CanSetCookie(const GURL& url,
- const GURL& first_party_for_cookies,
- const std::string& cookie_line,
- net::CompletionCallback* callback) {
- if (automation_client_.get()) {
- automation_client_->Send(new AutomationMsg_SetCookieAsync(0,
- tab_handle_, url, cookie_line));
- }
- return net::ERR_ACCESS_DENIED;
- }
-
- private:
- scoped_refptr<AutomationResourceMessageFilter> automation_client_;
- int tab_handle_;
- scoped_refptr<net::CookieStore> cookie_store_;
-
- DISALLOW_COPY_AND_ASSIGN(AutomationCookiePolicy);
-};
-
-class Factory : public ChromeURLRequestContextFactory {
- public:
- Factory(ChromeURLRequestContextGetter* original_context_getter,
- Profile* profile,
- AutomationResourceMessageFilter* automation_client,
- int tab_handle)
- : ChromeURLRequestContextFactory(profile),
- original_context_getter_(original_context_getter),
- automation_client_(automation_client),
- tab_handle_(tab_handle) {
- }
-
- virtual ChromeURLRequestContext* Create() {
- ChromeURLRequestContext* original_context =
- original_context_getter_->GetIOContext();
-
- // Create an automation cookie store.
- scoped_refptr<net::CookieStore> automation_cookie_store =
- new AutomationCookieStore(original_context->cookie_store(),
- automation_client_,
- tab_handle_);
-
- // Create an automation cookie policy.
- AutomationCookiePolicy* automation_cookie_policy =
- new AutomationCookiePolicy(automation_client_,
- tab_handle_,
- automation_cookie_store);
-
- return new AutomationURLRequestContext(original_context,
- automation_cookie_store,
- automation_cookie_policy);
- }
-
- private:
- scoped_refptr<ChromeURLRequestContextGetter> original_context_getter_;
- scoped_refptr<AutomationResourceMessageFilter> automation_client_;
- int tab_handle_;
-};
-
-ChromeURLRequestContextGetter* CreateAutomationURLRequestContextForTab(
- int tab_handle,
- Profile* profile,
- AutomationResourceMessageFilter* automation_client) {
- ChromeURLRequestContextGetter* original_context =
- static_cast<ChromeURLRequestContextGetter*>(
- profile->GetRequestContext());
-
- ChromeURLRequestContextGetter* request_context =
- new ChromeURLRequestContextGetter(
- NULL, // Don't register an observer on PrefService.
- new Factory(original_context, profile, automation_client,
- tab_handle));
- return request_context;
-}
-
-} // namespace AutomationRequestContext
-
diff --git a/chrome/browser/automation/automation_profile_impl.h b/chrome/browser/automation/automation_profile_impl.h
deleted file mode 100644
index 5bfba8e..0000000
--- a/chrome/browser/automation/automation_profile_impl.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 CHROME_BROWSER_AUTOMATION_AUTOMATION_PROFILE_IMPL_H_
-#define CHROME_BROWSER_AUTOMATION_AUTOMATION_PROFILE_IMPL_H_
-
-#include "ipc/ipc_message.h"
-
-class Profile;
-class ChromeURLRequestContextGetter;
-class AutomationResourceMessageFilter;
-
-namespace AutomationRequestContext {
-
-// Returns the URL request context to be used by HTTP requests handled over
-// the automation channel.
-ChromeURLRequestContextGetter* CreateAutomationURLRequestContextForTab(
- int tab_handle,
- Profile* profile,
- AutomationResourceMessageFilter* automation_client);
-
-}
-
-#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROFILE_IMPL_H_
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 6c66931..a7a59ad 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -6,15 +6,12 @@
#include <set>
-#include "app/l10n_util.h"
#include "app/message_box_flags.h"
#include "base/callback.h"
#include "base/file_path.h"
-#include "base/file_version_info.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/json/string_escape.h"
-#include "base/keyboard_codes.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
@@ -22,6 +19,8 @@
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
+#include "base/trace_event.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/waitable_event.h"
@@ -32,7 +31,6 @@
#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_extension_tracker.h"
-#include "chrome/browser/automation/automation_provider_json.h"
#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/automation/automation_provider_observers.h"
#include "chrome/browser/automation/automation_resource_message_filter.h"
@@ -74,7 +72,7 @@
#include "chrome/browser/login_prompt.h"
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
@@ -82,6 +80,7 @@
#include "chrome/browser/ssl/ssl_manager.h"
#include "chrome/browser/ssl/ssl_blocking_page.h"
#include "chrome/browser/tab_contents/infobar_delegate.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/translate/translate_infobar_delegate.h"
@@ -112,57 +111,11 @@
using base::Time;
-class AutomationInterstitialPage : public InterstitialPage {
- public:
- AutomationInterstitialPage(TabContents* tab,
- const GURL& url,
- const std::string& contents)
- : InterstitialPage(tab, true, url),
- contents_(contents) {
- }
-
- virtual std::string GetHTMLContents() { return contents_; }
-
- private:
- std::string contents_;
-
- DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
-};
-
-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);
- }
-
- private:
- int flags_;
-
- DISALLOW_COPY_AND_ASSIGN(ClickTask);
-};
-
AutomationProvider::AutomationProvider(Profile* profile)
- : redirect_query_(0),
- profile_(profile),
- reply_message_(NULL),
- popup_menu_waiter_(NULL) {
+ : profile_(profile),
+ reply_message_(NULL) {
+ TRACE_EVENT_BEGIN("AutomationProvider::AutomationProvider", 0, "");
+
browser_tracker_.reset(new AutomationBrowserTracker(this));
extension_tracker_.reset(new AutomationExtensionTracker(this));
tab_tracker_.reset(new AutomationTabTracker(this));
@@ -175,6 +128,8 @@ AutomationProvider::AutomationProvider(Profile* profile)
extension_test_result_observer_.reset(
new ExtensionTestResultNotificationObserver(this));
g_browser_process->AddRefModule();
+
+ TRACE_EVENT_END("AutomationProvider::AutomationProvider", 0, "");
}
AutomationProvider::~AutomationProvider() {
@@ -195,20 +150,20 @@ AutomationProvider::~AutomationProvider() {
}
void AutomationProvider::ConnectToChannel(const std::string& channel_id) {
+ TRACE_EVENT_BEGIN("AutomationProvider::ConnectToChannel", 0, "");
+
automation_resource_message_filter_ = new AutomationResourceMessageFilter;
channel_.reset(
new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this,
automation_resource_message_filter_,
g_browser_process->io_thread()->message_loop(),
true, g_browser_process->shutdown_event()));
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- std::string version_string;
- if (version_info != NULL) {
- version_string = WideToASCII(version_info->file_version());
- }
+ chrome::VersionInfo version_info;
// Send a hello message with our current automation protocol version.
- channel_->Send(new AutomationMsg_Hello(0, version_string.c_str()));
+ channel_->Send(new AutomationMsg_Hello(0, version_info.Version().c_str()));
+
+ TRACE_EVENT_END("AutomationProvider::ConnectToChannel", 0, "");
}
void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
@@ -301,6 +256,42 @@ int AutomationProvider::AddExtension(Extension* extension) {
return extension_tracker_->Add(extension);
}
+// TODO(phajdan.jr): move to TestingAutomationProvider.
+DictionaryValue* AutomationProvider::GetDictionaryFromDownloadItem(
+ const DownloadItem* download) {
+ std::map<DownloadItem::DownloadState, std::string> state_to_string;
+ state_to_string[DownloadItem::IN_PROGRESS] = std::string("IN_PROGRESS");
+ state_to_string[DownloadItem::CANCELLED] = std::string("CANCELLED");
+ state_to_string[DownloadItem::REMOVING] = std::string("REMOVING");
+ state_to_string[DownloadItem::COMPLETE] = std::string("COMPLETE");
+
+ std::map<DownloadItem::SafetyState, std::string> safety_state_to_string;
+ safety_state_to_string[DownloadItem::SAFE] = std::string("SAFE");
+ safety_state_to_string[DownloadItem::DANGEROUS] = std::string("DANGEROUS");
+ safety_state_to_string[DownloadItem::DANGEROUS_BUT_VALIDATED] =
+ std::string("DANGEROUS_BUT_VALIDATED");
+
+ DictionaryValue* dl_item_value = new DictionaryValue;
+ dl_item_value->SetInteger("id", static_cast<int>(download->id()));
+ dl_item_value->SetString("url", download->url().spec());
+ dl_item_value->SetString("referrer_url", download->referrer_url().spec());
+ dl_item_value->SetString("file_name", download->GetFileName().value());
+ dl_item_value->SetString("full_path", download->full_path().value());
+ dl_item_value->SetBoolean("is_paused", download->is_paused());
+ dl_item_value->SetBoolean("open_when_complete",
+ download->open_when_complete());
+ dl_item_value->SetBoolean("is_extension_install",
+ download->is_extension_install());
+ dl_item_value->SetBoolean("is_temporary", download->is_temporary());
+ dl_item_value->SetBoolean("is_otr", download->is_otr()); // off-the-record
+ dl_item_value->SetString("state", state_to_string[download->state()]);
+ dl_item_value->SetString("safety_state",
+ safety_state_to_string[download->safety_state()]);
+ dl_item_value->SetInteger("PercentComplete", download->PercentComplete());
+
+ return dl_item_value;
+}
+
Extension* AutomationProvider::GetExtension(int extension_handle) {
return extension_tracker_->GetResource(extension_handle);
}
@@ -326,192 +317,24 @@ Extension* AutomationProvider::GetDisabledExtension(int extension_handle) {
void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
- IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequestAsync,
- CloseBrowserAsync)
- IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab)
- IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetCookie, SetCookie)
- 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)
- IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuth, NeedsAuth)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RedirectsFrom,
- GetRedirectsFrom)
- IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount)
- IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
- GetNormalBrowserWindowCount)
- IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetBrowserLocale, GetBrowserLocale)
- IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindow,
- GetLastActiveBrowserWindow)
- IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindow, GetActiveWindow)
- IPC_MESSAGE_HANDLER(AutomationMsg_FindNormalBrowserWindow,
- FindNormalBrowserWindow)
- IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActive, IsWindowActive)
- IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow)
- IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowMaximized, IsWindowMaximized)
- IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync,
- ExecuteBrowserCommandAsync)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand,
- ExecuteBrowserCommand)
- IPC_MESSAGE_HANDLER(AutomationMsg_TerminateSession, TerminateSession)
- IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBounds, WindowGetViewBounds)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetWindowBounds, GetWindowBounds)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowBounds, SetWindowBounds)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisible, SetWindowVisible)
- IPC_MESSAGE_HANDLER(AutomationMsg_WindowClick, WindowSimulateClick)
- IPC_MESSAGE_HANDLER(AutomationMsg_WindowMouseMove, WindowSimulateMouseMove)
- IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPress, WindowSimulateKeyPress)
#if !defined(OS_MACOSX)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag,
WindowSimulateDrag)
#endif // !defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(AutomationMsg_TabCount, GetTabCount)
- IPC_MESSAGE_HANDLER(AutomationMsg_Type, GetType)
- IPC_MESSAGE_HANDLER(AutomationMsg_Tab, GetTab)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_TabHWND, GetTabHWND)
#endif // defined(OS_WIN)
- IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessID, GetTabProcessID)
- IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle)
- IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex)
- IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL)
- IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibility, GetShelfVisibility)
- IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreen, IsFullscreen)
- IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreenBubbleVisible,
- GetFullscreenBubbleVisibility)
IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
- IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAccelerator, ApplyAccelerator)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation,
- ExecuteJavascript)
- IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCount,
- GetConstrainedWindowCount)
- IPC_MESSAGE_HANDLER(AutomationMsg_FindInPage, HandleFindInPageRequest)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewID, GetFocusedViewID)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InspectElement,
- HandleInspectElementRequest)
- IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectory, GetDownloadDirectory)
IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindow,
- OpenNewBrowserWindow)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindowOfType,
- OpenNewBrowserWindowOfType)
- IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser)
- IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowser,
- GetAutocompleteEditForBrowser)
- IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindow, GetBrowserForWindow)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ShowInterstitialPage,
- ShowInterstitialPage)
- IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPage,
- HideInterstitialPage)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabToBeRestored,
- WaitForTabToBeRestored)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState, GetSecurityState)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType, GetPageType)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetMetricEventDuration,
- GetMetricEventDuration)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ActionOnSSLBlockingPage,
- ActionOnSSLBlockingPage)
- IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
- IPC_MESSAGE_HANDLER(AutomationMsg_IsMenuCommandEnabled,
- IsMenuCommandEnabled)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_PrintNow, PrintNow)
IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync)
- IPC_MESSAGE_HANDLER(AutomationMsg_SavePage, SavePage)
- IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetText,
- GetAutocompleteEditText)
- IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetText,
- SetAutocompleteEditText)
- IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgress,
- AutocompleteEditIsQueryInProgress)
- IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatches,
- AutocompleteEditGetMatches)
- IPC_MESSAGE_HANDLER(AutomationMsg_OpenFindInPage,
- HandleOpenFindInPageRequest)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest)
- IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibility,
- GetFindWindowVisibility)
- IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowLocation,
- HandleFindWindowLocationRequest)
- IPC_MESSAGE_HANDLER(AutomationMsg_BookmarkBarVisibility,
- GetBookmarkBarVisibility)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetBookmarksAsJSON,
- GetBookmarksAsJSON)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForBookmarkModelToLoad,
- WaitForBookmarkModelToLoad)
- IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkGroup,
- AddBookmarkGroup)
- IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkURL,
- AddBookmarkURL)
- IPC_MESSAGE_HANDLER(AutomationMsg_ReparentBookmark,
- ReparentBookmark)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkTitle,
- SetBookmarkTitle)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkURL,
- SetBookmarkURL)
- IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBookmark,
- RemoveBookmark)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SendJSONRequest,
- SendJSONRequest)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetInfoBarCount, GetInfoBarCount)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ClickInfoBarAccept,
- ClickInfoBarAccept)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetLastNavigationTime,
- GetLastNavigationTime)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForNavigation,
- WaitForNavigation)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetIntPreference, SetIntPreference)
- IPC_MESSAGE_HANDLER(AutomationMsg_ShowingAppModalDialog,
- GetShowingAppModalDialog)
- IPC_MESSAGE_HANDLER(AutomationMsg_ClickAppModalDialogButton,
- ClickAppModalDialogButton)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetStringPreference, SetStringPreference)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetBooleanPreference,
- GetBooleanPreference)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetBooleanPreference,
- SetBooleanPreference)
- IPC_MESSAGE_HANDLER(AutomationMsg_GetPageCurrentEncoding,
- GetPageCurrentEncoding)
IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding)
- IPC_MESSAGE_HANDLER(AutomationMsg_SavePackageShouldPromptUser,
- SavePackageShouldPromptUser)
- IPC_MESSAGE_HANDLER(AutomationMsg_WindowTitle, GetWindowTitle)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetShelfVisibility, SetShelfVisibility)
- IPC_MESSAGE_HANDLER(AutomationMsg_BlockedPopupCount, GetBlockedPopupCount)
IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll)
IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut)
IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy)
IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste)
IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync)
IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(
- AutomationMsg_WaitForBrowserWindowCountToBecome,
- WaitForBrowserWindowCountToBecome)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(
- AutomationMsg_WaitForAppModalDialogToBeShown,
- WaitForAppModalDialogToBeShown)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(
- AutomationMsg_GoBackBlockUntilNavigationsComplete,
- GoBackBlockUntilNavigationsComplete)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(
- AutomationMsg_GoForwardBlockUntilNavigationsComplete,
- GoForwardBlockUntilNavigationsComplete)
IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InstallExtension,
InstallExtension)
@@ -537,20 +360,8 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
MoveExtensionBrowserAction)
IPC_MESSAGE_HANDLER(AutomationMsg_GetExtensionProperty,
GetExtensionProperty)
- IPC_MESSAGE_HANDLER(AutomationMsg_ShutdownSessionService,
- ShutdownSessionService)
IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetContentSetting, SetContentSetting)
IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData)
- IPC_MESSAGE_HANDLER(AutomationMsg_ResetToDefaultTheme, ResetToDefaultTheme)
-#if defined(TOOLKIT_VIEWS)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForFocusedViewIDToChange,
- WaitForFocusedViewIDToChange)
- IPC_MESSAGE_HANDLER(AutomationMsg_StartTrackingPopupMenus,
- StartTrackingPopupMenus)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForPopupMenuToOpen,
- WaitForPopupMenuToOpen)
-#endif // defined(TOOLKIT_VIEWS)
#if defined(OS_WIN)
// These are for use with external tabs.
IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
@@ -570,399 +381,29 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
OnMessageFromExternalHost)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved)
- IPC_MESSAGE_HANDLER(AutomationMsg_RunUnloadHandlers, OnRunUnloadHandlers)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers,
+ OnRunUnloadHandlers)
+ IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel)
#endif // defined(OS_WIN)
#if defined(OS_CHROMEOS)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoginWithUserAndPass,
LoginWithUserAndPass)
#endif // defined(OS_CHROMEOS)
+ IPC_MESSAGE_UNHANDLED(OnUnhandledMessage())
IPC_END_MESSAGE_MAP()
}
-void AutomationProvider::ActivateTab(int handle, int at_index, int* status) {
- *status = -1;
- if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (at_index >= 0 && at_index < browser->tab_count()) {
- browser->SelectTabContentsAt(at_index, true);
- *status = 0;
- }
- }
-}
-
-void AutomationProvider::AppendTab(int handle, const GURL& url,
- IPC::Message* reply_message) {
- int append_tab_response = -1; // -1 is the error code
- NotificationObserver* observer = NULL;
-
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- observer = AddTabStripObserver(browser, reply_message);
- TabContents* tab_contents = browser->AddTabWithURL(
- url, GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED,
- NULL, std::string());
- if (tab_contents) {
- append_tab_response =
- GetIndexForNavigationController(&tab_contents->controller(), browser);
- }
- }
-
- if (append_tab_response < 0) {
- // The append tab failed. Remove the TabStripObserver
- if (observer) {
- RemoveTabStripObserver(observer);
- delete observer;
- }
-
- AutomationMsg_AppendTab::WriteReplyParams(reply_message,
- append_tab_response);
- Send(reply_message);
- }
-}
-
-void AutomationProvider::NavigateToURL(int handle, const GURL& url,
- IPC::Message* reply_message) {
- NavigateToURLBlockUntilNavigationsComplete(handle, url, 1, reply_message);
-}
-
-void AutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
- int handle, const GURL& url, int number_of_navigations,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
-
- // Simulate what a user would do. Activate the tab and then navigate.
- // We could allow navigating in a background tab in future.
- Browser* browser = FindAndActivateTab(tab);
-
- if (browser) {
- AddNavigationStatusListener(tab, reply_message, number_of_navigations,
- false);
-
- // TODO(darin): avoid conversion to GURL
- browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
- return;
- }
- }
-
- AutomationMsg_NavigateToURL::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
-void AutomationProvider::NavigationAsync(int handle,
- const GURL& url,
- bool* status) {
- NavigationAsyncWithDisposition(handle, url, CURRENT_TAB, status);
-}
-
-void AutomationProvider::NavigationAsyncWithDisposition(
- int handle,
- const GURL& url,
- WindowOpenDisposition disposition,
- bool* status) {
- *status = false;
-
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
-
- // Simulate what a user would do. Activate the tab and then navigate.
- // We could allow navigating in a background tab in future.
- Browser* browser = FindAndActivateTab(tab);
-
- if (browser) {
- // Don't add any listener unless a callback mechanism is desired.
- // TODO(vibhor): Do this if such a requirement arises in future.
- browser->OpenURL(url, GURL(), disposition, PageTransition::TYPED);
- *status = true;
- }
- }
-}
-
-void AutomationProvider::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 AutomationProvider::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 AutomationProvider::Reload(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_RELOAD)) {
- AddNavigationStatusListener(tab, reply_message, 1, false);
- browser->Reload(CURRENT_TAB);
- return;
- }
- }
-
- AutomationMsg_Reload::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
-void AutomationProvider::SetAuth(int tab_handle,
- const std::wstring& username,
- const std::wstring& password,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(tab_handle)) {
- NavigationController* tab = tab_tracker_->GetResource(tab_handle);
- LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
-
- if (iter != login_handler_map_.end()) {
- // If auth is needed again after this, assume login has failed. This is
- // not strictly correct, because a navigation can require both proxy and
- // server auth, but it should be OK for now.
- LoginHandler* handler = iter->second;
- AddNavigationStatusListener(tab, reply_message, 1, false);
- handler->SetAuth(username, password);
- return;
- }
- }
-
- AutomationMsg_SetAuth::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
- Send(reply_message);
-}
-
-void AutomationProvider::CancelAuth(int tab_handle,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(tab_handle)) {
- NavigationController* tab = tab_tracker_->GetResource(tab_handle);
- LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
-
- if (iter != login_handler_map_.end()) {
- // If auth is needed again after this, something is screwy.
- LoginHandler* handler = iter->second;
- AddNavigationStatusListener(tab, reply_message, 1, false);
- handler->CancelAuth();
- return;
- }
- }
-
- AutomationMsg_CancelAuth::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
- Send(reply_message);
-}
-
-void AutomationProvider::NeedsAuth(int tab_handle, bool* needs_auth) {
- *needs_auth = false;
-
- if (tab_tracker_->ContainsHandle(tab_handle)) {
- NavigationController* tab = tab_tracker_->GetResource(tab_handle);
- LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
-
- if (iter != login_handler_map_.end()) {
- // The LoginHandler will be in our map IFF the tab needs auth.
- *needs_auth = true;
- }
- }
-}
-
-void AutomationProvider::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)) {
- NavigationController* tab = tab_tracker_->GetResource(tab_handle);
- HistoryService* history_service =
- tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
-
- DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
- "has no history service";
- if (history_service) {
- DCHECK(reply_message_ == NULL);
- reply_message_ = reply_message;
- // Schedule a history query for redirects. The response will be sent
- // asynchronously from the callback the history system uses to notify us
- // that it's done: OnRedirectQueryComplete.
- redirect_query_ = history_service->QueryRedirectsFrom(
- source_url, &consumer_,
- NewCallback(this, &AutomationProvider::OnRedirectQueryComplete));
- return; // Response will be sent when query completes.
- }
- }
-
- // Send failure response.
- std::vector<GURL> empty;
- AutomationMsg_RedirectsFrom::WriteReplyParams(reply_message, false, empty);
- Send(reply_message);
-}
-
-void AutomationProvider::GetActiveTabIndex(int handle, int* active_tab_index) {
- *active_tab_index = -1; // -1 is the error code
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- *active_tab_index = browser->selected_index();
- }
-}
-
-void AutomationProvider::GetBrowserLocale(string16* locale) {
- DCHECK(g_browser_process);
- *locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale());
-}
-
-void AutomationProvider::GetBrowserWindowCount(int* window_count) {
- *window_count = static_cast<int>(BrowserList::size());
-}
-
-void AutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
- *window_count = static_cast<int>(
- BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL));
-}
-
-void AutomationProvider::GetShowingAppModalDialog(bool* showing_dialog,
- int* dialog_button) {
- AppModalDialog* dialog_delegate =
- Singleton<AppModalDialogQueue>()->active_dialog();
- *showing_dialog = (dialog_delegate != NULL);
- if (*showing_dialog)
- *dialog_button = dialog_delegate->GetDialogButtons();
- else
- *dialog_button = MessageBoxFlags::DIALOGBUTTON_NONE;
-}
-
-void AutomationProvider::ClickAppModalDialogButton(int button, bool* success) {
- *success = false;
-
- AppModalDialog* dialog_delegate =
- Singleton<AppModalDialogQueue>()->active_dialog();
- if (dialog_delegate &&
- (dialog_delegate->GetDialogButtons() & button) == button) {
- if ((button & MessageBoxFlags::DIALOGBUTTON_OK) ==
- MessageBoxFlags::DIALOGBUTTON_OK) {
- dialog_delegate->AcceptWindow();
- *success = true;
- }
- if ((button & MessageBoxFlags::DIALOGBUTTON_CANCEL) ==
- MessageBoxFlags::DIALOGBUTTON_CANCEL) {
- DCHECK(!*success) << "invalid param, OK and CANCEL specified";
- dialog_delegate->CancelWindow();
- *success = true;
- }
- }
-}
-
-void AutomationProvider::ShutdownSessionService(int handle, bool* result) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- browser->profile()->ShutdownSessionService();
- *result = true;
- } else {
- *result = false;
- }
-}
-
-void AutomationProvider::GetBrowserWindow(int index, int* handle) {
- *handle = 0;
- if (index >= 0) {
- BrowserList::const_iterator iter = BrowserList::begin();
- for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index) {}
- if (iter != BrowserList::end()) {
- *handle = browser_tracker_->Add(*iter);
- }
- }
-}
-
-void AutomationProvider::FindNormalBrowserWindow(int* handle) {
- *handle = 0;
- Browser* browser = BrowserList::FindBrowserWithType(profile_,
- Browser::TYPE_NORMAL,
- false);
- if (browser)
- *handle = browser_tracker_->Add(browser);
-}
-
-void AutomationProvider::GetLastActiveBrowserWindow(int* handle) {
- *handle = 0;
- Browser* browser = BrowserList::GetLastActive();
- if (browser)
- *handle = browser_tracker_->Add(browser);
-}
-
-#if defined(OS_POSIX)
-// TODO(estade): use this implementation for all platforms?
-void AutomationProvider::GetActiveWindow(int* handle) {
- gfx::NativeWindow window =
- BrowserList::GetLastActive()->window()->GetNativeHandle();
- *handle = window_tracker_->Add(window);
-}
-#endif
-
-void AutomationProvider::ExecuteBrowserCommandAsync(int handle, int command,
- bool* success) {
- *success = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser->command_updater()->SupportsCommand(command) &&
- browser->command_updater()->IsCommandEnabled(command)) {
- browser->ExecuteCommand(command);
- *success = true;
- }
- }
-}
-
-void AutomationProvider::ExecuteBrowserCommand(
- int handle, int command, IPC::Message* reply_message) {
- // List of commands which just finish synchronously and don't require
- // setting up an observer.
- static const int kSynchronousCommands[] = {
- IDC_HOME,
- IDC_SELECT_NEXT_TAB,
- IDC_SELECT_PREVIOUS_TAB,
- IDC_SHOW_BOOKMARK_MANAGER,
- };
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser->command_updater()->SupportsCommand(command) &&
- browser->command_updater()->IsCommandEnabled(command)) {
- // First check if we can handle the command without using an observer.
- for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
- if (command == kSynchronousCommands[i]) {
- browser->ExecuteCommand(command);
- AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message,
- true);
- Send(reply_message);
- return;
- }
- }
-
- // Use an observer if we have one, otherwise fail.
- if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
- this, browser, command, reply_message)) {
- browser->ExecuteCommand(command);
- return;
- }
- }
- }
- AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false);
- Send(reply_message);
+void AutomationProvider::OnUnhandledMessage() {
+ // We should not hang here. Print a message to indicate what's going on,
+ // and disconnect the channel to notify the caller about the error
+ // in a way it can't ignore, and make any further attempts to send
+ // messages fail fast.
+ LOG(ERROR) << "AutomationProvider received a message it can't handle. "
+ << "Please make sure that you use switches::kTestingChannelID "
+ << "for test code (TestingAutomationProvider), and "
+ << "switches::kAutomationClientChannelID for everything else "
+ << "(like ChromeFrame). Closing the automation channel.";
+ channel_->Close();
}
// This task just adds another task to the event queue. This is useful if
@@ -983,111 +424,6 @@ class InvokeTaskLaterTask : public Task {
DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask);
};
-void AutomationProvider::WindowSimulateClick(const IPC::Message& message,
- int handle,
- const gfx::Point& click,
- int flags) {
- if (window_tracker_->ContainsHandle(handle)) {
- ui_controls::SendMouseMoveNotifyWhenDone(click.x(), click.y(),
- new ClickTask(flags));
- }
-}
-
-void AutomationProvider::WindowSimulateMouseMove(const IPC::Message& message,
- int handle,
- const gfx::Point& location) {
- if (window_tracker_->ContainsHandle(handle))
- ui_controls::SendMouseMove(location.x(), location.y());
-}
-
-void AutomationProvider::WindowSimulateKeyPress(const IPC::Message& message,
- int handle,
- int key,
- int flags) {
- if (!window_tracker_->ContainsHandle(handle))
- return;
-
- gfx::NativeWindow window = window_tracker_->GetResource(handle);
- // The key event is sent to whatever window is active.
- ui_controls::SendKeyPress(window, static_cast<base::KeyboardCode>(key),
- ((flags & views::Event::EF_CONTROL_DOWN) ==
- views::Event::EF_CONTROL_DOWN),
- ((flags & views::Event::EF_SHIFT_DOWN) ==
- views::Event::EF_SHIFT_DOWN),
- ((flags & views::Event::EF_ALT_DOWN) ==
- views::Event::EF_ALT_DOWN),
- ((flags & views::Event::EF_COMMAND_DOWN) ==
- views::Event::EF_COMMAND_DOWN));
-}
-
-void AutomationProvider::IsWindowActive(int handle, bool* success,
- bool* is_active) {
- if (window_tracker_->ContainsHandle(handle)) {
- *is_active =
- platform_util::IsWindowActive(window_tracker_->GetResource(handle));
- *success = true;
- } else {
- *success = false;
- *is_active = false;
- }
-}
-
-void AutomationProvider::GetTabCount(int handle, int* tab_count) {
- *tab_count = -1; // -1 is the error code
-
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- *tab_count = browser->tab_count();
- }
-}
-
-void AutomationProvider::GetType(int handle, int* type_as_int) {
- *type_as_int = -1; // -1 is the error code
-
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- *type_as_int = static_cast<int>(browser->type());
- }
-}
-
-void AutomationProvider::GetTab(int win_handle, int tab_index,
- int* tab_handle) {
- *tab_handle = 0;
- if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
- Browser* browser = browser_tracker_->GetResource(win_handle);
- if (tab_index < browser->tab_count()) {
- TabContents* tab_contents =
- browser->GetTabContentsAt(tab_index);
- *tab_handle = tab_tracker_->Add(&tab_contents->controller());
- }
- }
-}
-
-void AutomationProvider::GetTabTitle(int handle, int* title_string_size,
- std::wstring* title) {
- *title_string_size = -1; // -1 is the error code
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- NavigationEntry* entry = tab->GetActiveEntry();
- if (entry != NULL) {
- *title = UTF16ToWideHack(entry->title());
- } else {
- *title = std::wstring();
- }
- *title_string_size = static_cast<int>(title->size());
- }
-}
-
-void AutomationProvider::GetTabIndex(int handle, int* tabstrip_index) {
- *tabstrip_index = -1; // -1 is the error code
-
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- Browser* browser = Browser::GetBrowserForController(tab, NULL);
- *tabstrip_index = browser->tabstrip_model()->GetIndexOfController(tab);
- }
-}
-
void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
if (window_tracker_->ContainsHandle(handle)) {
window_tracker_->Remove(window_tracker_->GetResource(handle));
@@ -1099,29 +435,6 @@ void AutomationProvider::OnChannelError() {
AutomationProviderList::GetInstance()->RemoveProvider(this);
}
-// TODO(brettw) change this to accept GURLs when history supports it
-void AutomationProvider::OnRedirectQueryComplete(
- HistoryService::Handle request_handle,
- GURL from_url,
- bool success,
- history::RedirectList* redirects) {
- DCHECK(request_handle == redirect_query_);
- DCHECK(reply_message_ != NULL);
-
- std::vector<GURL> redirects_gurl;
- reply_message_->WriteBool(success);
- if (success) {
- for (size_t i = 0; i < redirects->size(); i++)
- redirects_gurl.push_back(redirects->at(i));
- }
-
- IPC::ParamTraits<std::vector<GURL> >::Write(reply_message_, redirects_gurl);
-
- Send(reply_message_);
- redirect_query_ = 0;
- reply_message_ = NULL;
-}
-
bool AutomationProvider::Send(IPC::Message* msg) {
DCHECK(channel_.get());
return channel_->Send(msg);
@@ -1137,316 +450,6 @@ Browser* AutomationProvider::FindAndActivateTab(
return browser;
}
-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(
- const GURL& url,
- URLRequestContextGetter* context_getter) {
- std::string cookies;
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- CHECK(ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- new GetCookiesTask(url, context_getter, &event, &cookies)));
- event.Wait();
- return cookies;
-}
-
-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(
- const GURL& url,
- const std::string& value,
- URLRequestContextGetter* context_getter) {
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- bool rv = false;
- CHECK(ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- new SetCookieTask(url, value, context_getter, &event, &rv)));
- event.Wait();
- return rv;
-}
-
-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);
-};
-
-} // namespace
-
-void AutomationProvider::GetCookies(const GURL& url, int handle,
- int* value_size,
- 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().
- scoped_refptr<URLRequestContextGetter> request_context =
- tab->tab_contents()->request_context();
- if (!request_context.get())
- request_context = tab->profile()->GetRequestContext();
-
- *value = GetCookiesForURL(url, request_context.get());
- *value_size = static_cast<int>(value->size());
- }
-}
-
-void AutomationProvider::SetCookie(const GURL& url,
- const std::string value,
- int handle,
- int* response_value) {
- *response_value = -1;
-
- if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
-
- scoped_refptr<URLRequestContextGetter> request_context =
- tab->tab_contents()->request_context();
- if (!request_context.get())
- request_context = tab->profile()->GetRequestContext();
-
- if (SetCookieForURL(url, value, request_context.get()))
- *response_value = 1;
- }
-}
-
-void AutomationProvider::DeleteCookie(const GURL& url,
- const std::string& cookie_name,
- int handle, bool* success) {
- *success = false;
- if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- new DeleteCookieTask(url, cookie_name,
- tab->profile()->GetRequestContext()));
- *success = true;
- }
-}
-
-void AutomationProvider::ShowCollectedCookiesDialog(
- int handle, bool* success) {
- *success = false;
- if (tab_tracker_->ContainsHandle(handle)) {
- TabContents* tab_contents =
- tab_tracker_->GetResource(handle)->tab_contents();
- tab_contents->delegate()->ShowCollectedCookiesDialog(tab_contents);
- *success = true;
- }
-}
-
-void AutomationProvider::GetTabURL(int handle, bool* success, GURL* url) {
- *success = false;
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- // Return what the user would see in the location bar.
- *url = tab->GetActiveEntry()->virtual_url();
- *success = true;
- }
-}
-
-void AutomationProvider::GetTabProcessID(int handle, int* process_id) {
- *process_id = -1;
-
- if (tab_tracker_->ContainsHandle(handle)) {
- *process_id = 0;
- TabContents* tab_contents =
- tab_tracker_->GetResource(handle)->tab_contents();
- RenderProcessHost* rph = tab_contents->GetRenderProcessHost();
- if (rph)
- *process_id = base::GetProcId(rph->GetHandle());
- }
-}
-
-void AutomationProvider::ApplyAccelerator(int handle, int id) {
- NOTREACHED() << "This function has been deprecated. "
- << "Please use ExecuteBrowserCommandAsync instead.";
-}
-
-void AutomationProvider::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;
- 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) {
- AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string());
- Send(reply_message);
- }
-}
-
-void AutomationProvider::GetShelfVisibility(int handle, bool* visible) {
- *visible = false;
-
- if (browser_tracker_->ContainsHandle(handle)) {
-#if defined(OS_CHROMEOS)
- // Chromium OS shows FileBrowse ui rather than download shelf. So we
- // enumerate all browsers and look for a chrome://filebrowse... pop up.
- for (BrowserList::const_iterator it = BrowserList::begin();
- it != BrowserList::end(); ++it) {
- if ((*it)->type() == Browser::TYPE_POPUP) {
- const GURL& url =
- (*it)->GetTabContentsAt((*it)->selected_index())->GetURL();
-
- if (url.SchemeIs(chrome::kChromeUIScheme) &&
- url.host() == chrome::kChromeUIFileBrowseHost) {
- *visible = true;
- break;
- }
- }
- }
-#else
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- *visible = browser->window()->IsDownloadShelfVisible();
- }
-#endif
- }
-}
-
-void AutomationProvider::SetShelfVisibility(int handle, bool visible) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- if (visible)
- browser->window()->GetDownloadShelf()->Show();
- else
- browser->window()->GetDownloadShelf()->Close();
- }
- }
-}
-
-void AutomationProvider::IsFullscreen(int handle, bool* visible) {
- *visible = false;
-
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser)
- *visible = browser->window()->IsFullscreen();
- }
-}
-
-void AutomationProvider::GetFullscreenBubbleVisibility(int handle,
- bool* visible) {
- *visible = false;
-
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser)
- *visible = browser->window()->IsFullscreenBubbleVisible();
- }
-}
-
-void AutomationProvider::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());
- }
- }
-}
-
-void AutomationProvider::HandleFindInPageRequest(
- int handle, const std::wstring& find_request,
- int forward, int match_case, int* active_ordinal, int* matches_found) {
- NOTREACHED() << "This function has been deprecated."
- << "Please use HandleFindRequest instead.";
- *matches_found = -1;
- return;
-}
-
void AutomationProvider::HandleFindRequest(
int handle,
const AutomationMsg_Find_Params& params,
@@ -1471,1522 +474,6 @@ void AutomationProvider::HandleFindRequest(
params.find_next);
}
-void AutomationProvider::HandleOpenFindInPageRequest(
- const IPC::Message& message, int handle) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- browser->FindInPage(false, false);
- }
-}
-
-void AutomationProvider::GetFindWindowVisibility(int handle, bool* visible) {
- *visible = false;
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- FindBarTesting* find_bar =
- browser->GetFindBarController()->find_bar()->GetFindBarTesting();
- find_bar->GetFindBarWindowInfo(NULL, visible);
- }
-}
-
-void AutomationProvider::HandleFindWindowLocationRequest(int handle, int* x,
- int* y) {
- gfx::Point position(0, 0);
- bool visible = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- FindBarTesting* find_bar =
- browser->GetFindBarController()->find_bar()->GetFindBarTesting();
- find_bar->GetFindBarWindowInfo(&position, &visible);
- }
-
- *x = position.x();
- *y = position.y();
-}
-
-// Bookmark bar visibility is based on the pref (e.g. is it in the toolbar).
-// Presence in the NTP is NOT considered visible by this call.
-void AutomationProvider::GetBookmarkBarVisibility(int handle,
- bool* visible,
- bool* animating) {
- *visible = false;
- *animating = false;
-
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
-#if 0 // defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
- // TODO(jrg): Was removed in rev43789 for perf. Need to investigate.
-
- // IsBookmarkBarVisible() line looks correct but is not
- // consistent across platforms. Specifically, on Mac/Linux, it
- // returns false if the bar is hidden in a pref (even if visible
- // on the NTP). On ChromeOS, it returned true if on NTP
- // independent of the pref. Making the code more consistent
- // caused a perf bot regression on Windows (which shares views).
- // See http://crbug.com/40225
- *visible = browser->profile()->GetPrefs()->GetBoolean(
- prefs::kShowBookmarkBar);
-#else
- *visible = browser->window()->IsBookmarkBarVisible();
-#endif
- *animating = browser->window()->IsBookmarkBarAnimating();
- }
- }
-}
-
-void AutomationProvider::GetBookmarksAsJSON(int handle,
- std::string* bookmarks_as_json,
- bool *success) {
- *success = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- if (!browser->profile()->GetBookmarkModel()->IsLoaded()) {
- return;
- }
- scoped_refptr<BookmarkStorage> storage = new BookmarkStorage(
- browser->profile(),
- browser->profile()->GetBookmarkModel());
- *success = storage->SerializeData(bookmarks_as_json);
- }
- }
-}
-
-void AutomationProvider::WaitForBookmarkModelToLoad(
- int handle,
- IPC::Message* reply_message) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- BookmarkModel* model = browser->profile()->GetBookmarkModel();
- if (model->IsLoaded()) {
- AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
- reply_message, true);
- Send(reply_message);
- } else {
- // The observer will delete itself when done.
- new AutomationProviderBookmarkModelObserver(this, reply_message,
- model);
- }
- }
-}
-
-void AutomationProvider::AddBookmarkGroup(int handle,
- int64 parent_id, int index,
- std::wstring title,
- bool* success) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- BookmarkModel* model = browser->profile()->GetBookmarkModel();
- if (!model->IsLoaded()) {
- *success = false;
- return;
- }
- const BookmarkNode* parent = model->GetNodeByID(parent_id);
- DCHECK(parent);
- if (parent) {
- const BookmarkNode* child = model->AddGroup(parent, index,
- WideToUTF16(title));
- DCHECK(child);
- if (child)
- *success = true;
- }
- }
- }
- *success = false;
-}
-
-void AutomationProvider::AddBookmarkURL(int handle,
- int64 parent_id, int index,
- std::wstring title, const GURL& url,
- bool* success) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- BookmarkModel* model = browser->profile()->GetBookmarkModel();
- if (!model->IsLoaded()) {
- *success = false;
- return;
- }
- const BookmarkNode* parent = model->GetNodeByID(parent_id);
- DCHECK(parent);
- if (parent) {
- const BookmarkNode* child = model->AddURL(parent, index,
- WideToUTF16(title), url);
- DCHECK(child);
- if (child)
- *success = true;
- }
- }
- }
- *success = false;
-}
-
-void AutomationProvider::ReparentBookmark(int handle,
- int64 id, int64 new_parent_id,
- int index,
- bool* success) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- BookmarkModel* model = browser->profile()->GetBookmarkModel();
- if (!model->IsLoaded()) {
- *success = false;
- return;
- }
- const BookmarkNode* node = model->GetNodeByID(id);
- DCHECK(node);
- const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id);
- DCHECK(new_parent);
- if (node && new_parent) {
- model->Move(node, new_parent, index);
- *success = true;
- }
- }
- }
- *success = false;
-}
-
-void AutomationProvider::SetBookmarkTitle(int handle,
- int64 id, std::wstring title,
- bool* success) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- BookmarkModel* model = browser->profile()->GetBookmarkModel();
- if (!model->IsLoaded()) {
- *success = false;
- return;
- }
- const BookmarkNode* node = model->GetNodeByID(id);
- DCHECK(node);
- if (node) {
- model->SetTitle(node, WideToUTF16(title));
- *success = true;
- }
- }
- }
- *success = false;
-}
-
-void AutomationProvider::SetBookmarkURL(int handle,
- int64 id, const GURL& url,
- bool* success) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- BookmarkModel* model = browser->profile()->GetBookmarkModel();
- if (!model->IsLoaded()) {
- *success = false;
- return;
- }
- const BookmarkNode* node = model->GetNodeByID(id);
- DCHECK(node);
- if (node) {
- model->SetURL(node, url);
- *success = true;
- }
- }
- }
- *success = false;
-}
-
-void AutomationProvider::RemoveBookmark(int handle,
- int64 id,
- bool* success) {
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- if (browser) {
- BookmarkModel* model = browser->profile()->GetBookmarkModel();
- if (!model->IsLoaded()) {
- *success = false;
- return;
- }
- const BookmarkNode* node = model->GetNodeByID(id);
- DCHECK(node);
- if (node) {
- const BookmarkNode* parent = node->GetParent();
- DCHECK(parent);
- model->Remove(parent, parent->IndexOfChild(node));
- *success = true;
- }
- }
- }
- *success = false;
-}
-
-// Sample json input: { "command": "SetWindowDimensions",
-// "x": 20, # optional
-// "y": 20, # optional
-// "width": 800, # optional
-// "height": 600 } # optional
-void AutomationProvider::SetWindowDimensions(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- gfx::Rect rect = browser->window()->GetRestoredBounds();
- int x, y, width, height;
- if (args->GetInteger(L"x", &x))
- rect.set_x(x);
- if (args->GetInteger(L"y", &y))
- rect.set_y(y);
- if (args->GetInteger(L"width", &width))
- rect.set_width(width);
- if (args->GetInteger(L"height", &height))
- rect.set_height(height);
- browser->window()->SetBounds(rect);
- AutomationJSONReply(this, reply_message).SendSuccess(NULL);
-}
-
-ListValue* AutomationProvider::GetInfobarsInfo(TabContents* tc) {
- // Each infobar may have different properties depending on the type.
- ListValue* infobars = new ListValue;
- for (int infobar_index = 0;
- infobar_index < tc->infobar_delegate_count();
- ++infobar_index) {
- DictionaryValue* infobar_item = new DictionaryValue;
- InfoBarDelegate* infobar = tc->GetInfoBarDelegateAt(infobar_index);
- if (infobar->AsConfirmInfoBarDelegate()) {
- // Also covers ThemeInstalledInfoBarDelegate and
- // CrashedExtensionInfoBarDelegate.
- infobar_item->SetString(L"type", "confirm_infobar");
- ConfirmInfoBarDelegate* confirm_infobar =
- infobar->AsConfirmInfoBarDelegate();
- infobar_item->SetString(L"text", confirm_infobar->GetMessageText());
- infobar_item->SetString(L"link_text", confirm_infobar->GetLinkText());
- ListValue* buttons_list = new ListValue;
- int buttons = confirm_infobar->GetButtons();
- if (ConfirmInfoBarDelegate::BUTTON_OK & buttons) {
- StringValue* button_label = new StringValue(
- confirm_infobar->GetButtonLabel(
- ConfirmInfoBarDelegate::BUTTON_OK));
- buttons_list->Append(button_label);
- }
- if (ConfirmInfoBarDelegate::BUTTON_CANCEL & buttons) {
- StringValue* button_label = new StringValue(
- confirm_infobar->GetButtonLabel(
- ConfirmInfoBarDelegate::BUTTON_CANCEL));
- buttons_list->Append(button_label);
- }
- infobar_item->Set(L"buttons", buttons_list);
- } else if (infobar->AsAlertInfoBarDelegate()) {
- infobar_item->SetString(L"type", "alert_infobar");
- AlertInfoBarDelegate* alert_infobar =
- infobar->AsAlertInfoBarDelegate();
- infobar_item->SetString(L"text", alert_infobar->GetMessageText());
- } else if (infobar->AsLinkInfoBarDelegate()) {
- infobar_item->SetString(L"type", "link_infobar");
- LinkInfoBarDelegate* link_infobar = infobar->AsLinkInfoBarDelegate();
- infobar_item->SetString(L"link_text", link_infobar->GetLinkText());
- } else if (infobar->AsTranslateInfoBarDelegate()) {
- infobar_item->SetString(L"type", "translate_infobar");
- TranslateInfoBarDelegate* translate_infobar =
- infobar->AsTranslateInfoBarDelegate();
- infobar_item->SetString(L"original_lang_code",
- translate_infobar->GetOriginalLanguageCode());
- infobar_item->SetString(L"target_lang_code",
- translate_infobar->GetTargetLanguageCode());
- } else if (infobar->AsExtensionInfoBarDelegate()) {
- infobar_item->SetString(L"type", "extension_infobar");
- } else {
- infobar_item->SetString(L"type", "unknown_infobar");
- }
- infobars->Append(infobar_item);
- }
- return infobars;
-}
-
-// Sample json input: { "command": "WaitForInfobarCount",
-// "count": COUNT,
-// "tab_index": INDEX }
-// Sample output: {}
-void AutomationProvider::WaitForInfobarCount(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- int tab_index;
- int count;
- if (!args->GetInteger(L"count", &count) || count < 0 ||
- !args->GetInteger(L"tab_index", &tab_index) || tab_index < 0) {
- AutomationJSONReply(this, reply_message).SendError(
- "Missing or invalid args: 'count', 'tab_index'.");
- return;
- }
-
- TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
- // Observer deletes itself.
- new WaitForInfobarCountObserver(this, reply_message, tab_contents, count);
-}
-
-namespace {
-
-// Task to get info about BrowserChildProcessHost. Must run on IO thread to
-// honor the semantics of BrowserChildProcessHost.
-// Used by AutomationProvider::GetBrowserInfo().
-class GetChildProcessHostInfoTask : public Task {
- public:
- GetChildProcessHostInfoTask(base::WaitableEvent* event,
- ListValue* child_processes)
- : event_(event),
- child_processes_(child_processes) {}
-
- virtual void Run() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
- // Only add processes which are already started,
- // since we need their handle.
- if ((*iter)->handle() == base::kNullProcessHandle) {
- continue;
- }
- ChildProcessInfo* info = *iter;
- DictionaryValue* item = new DictionaryValue;
- item->SetString(L"name", info->name());
- item->SetString(L"type",
- ChildProcessInfo::GetTypeNameInEnglish(info->type()));
- item->SetInteger(L"pid", base::GetProcId(info->handle()));
- child_processes_->Append(item);
- }
- event_->Signal();
- }
-
- private:
- base::WaitableEvent* const event_; // weak
- ListValue* child_processes_;
-
- DISALLOW_COPY_AND_ASSIGN(GetChildProcessHostInfoTask);
-};
-
-} // namespace
-
-// Sample json input: { "command": "GetBrowserInfo" }
-// Refer to GetBrowserInfo() in chrome/test/pyautolib/pyauto.py for
-// sample json output.
-void AutomationProvider::GetBrowserInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- DictionaryValue* properties = new DictionaryValue;
- properties->SetString(L"ChromeVersion", chrome::kChromeVersion);
- properties->SetString(L"BrowserProcessExecutableName",
- chrome::kBrowserProcessExecutableName);
- properties->SetString(L"HelperProcessExecutableName",
- chrome::kHelperProcessExecutableName);
- properties->SetString(L"BrowserProcessExecutablePath",
- chrome::kBrowserProcessExecutablePath);
- properties->SetString(L"HelperProcessExecutablePath",
- chrome::kHelperProcessExecutablePath);
- properties->SetString(L"command_line_string",
- CommandLine::ForCurrentProcess()->command_line_string());
-
- std::string branding;
-#if defined(GOOGLE_CHROME_BUILD)
- branding = "Google Chrome";
-#elif defined(CHROMIUM_BUILD)
- branding = "Chromium";
-#else
- branding = "Unknown Branding";
-#endif
- properties->SetString(L"branding", branding);
-
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
- return_value->Set(L"properties", properties);
-
- return_value->SetInteger(L"browser_pid", base::GetCurrentProcId());
- // Add info about all windows in a list of dictionaries, one dictionary
- // item per window.
- ListValue* windows = new ListValue;
- int windex = 0;
- for (BrowserList::const_iterator it = BrowserList::begin();
- it != BrowserList::end();
- ++it, ++windex) {
- DictionaryValue* browser_item = new DictionaryValue;
- browser = *it;
- browser_item->SetInteger(L"index", windex);
- // Window properties
- gfx::Rect rect = browser->window()->GetRestoredBounds();
- browser_item->SetInteger(L"x", rect.x());
- browser_item->SetInteger(L"y", rect.y());
- browser_item->SetInteger(L"width", rect.width());
- browser_item->SetInteger(L"height", rect.height());
- browser_item->SetBoolean(L"fullscreen",
- browser->window()->IsFullscreen());
- browser_item->SetInteger(L"selected_tab", browser->selected_index());
- browser_item->SetBoolean(L"incognito",
- browser->profile()->IsOffTheRecord());
- // For each window, add info about all tabs in a list of dictionaries,
- // one dictionary item per tab.
- ListValue* tabs = new ListValue;
- for (int i = 0; i < browser->tab_count(); ++i) {
- TabContents* tc = browser->GetTabContentsAt(i);
- DictionaryValue* tab = new DictionaryValue;
- tab->SetInteger(L"index", i);
- tab->SetString(L"url", tc->GetURL().spec());
- tab->SetInteger(L"renderer_pid",
- base::GetProcId(tc->GetRenderProcessHost()->GetHandle()));
- tab->Set(L"infobars", GetInfobarsInfo(tc));
- tabs->Append(tab);
- }
- browser_item->Set(L"tabs", tabs);
-
- windows->Append(browser_item);
- }
- return_value->Set(L"windows", windows);
-
- return_value->SetString(L"child_process_path",
- ChildProcessHost::GetChildPath(true).value());
- // Child processes are the processes for plugins and other workers.
- // Add all child processes in a list of dictionaries, one dictionary item
- // per child process.
- ListValue* child_processes = new ListValue;
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- CHECK(ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- new GetChildProcessHostInfoTask(&event, child_processes)));
- event.Wait();
- return_value->Set(L"child_processes", child_processes);
-
- // Add all extension processes in a list of dictionaries, one dictionary
- // item per extension process.
- ListValue* extension_processes = new ListValue;
- ProfileManager* profile_manager = g_browser_process->profile_manager();
- for (ProfileManager::const_iterator it = profile_manager->begin();
- it != profile_manager->end(); ++it) {
- ExtensionProcessManager* process_manager =
- (*it)->GetExtensionProcessManager();
- ExtensionProcessManager::const_iterator jt;
- for (jt = process_manager->begin(); jt != process_manager->end(); ++jt) {
- ExtensionHost* ex_host = *jt;
- // Don't add dead extension processes.
- if (!ex_host->IsRenderViewLive())
- continue;
- DictionaryValue* item = new DictionaryValue;
- item->SetString(L"name", ex_host->extension()->name());
- item->SetInteger(
- L"pid",
- base::GetProcId(ex_host->render_process_host()->GetHandle()));
- extension_processes->Append(item);
- }
- }
- return_value->Set(L"extension_processes", extension_processes);
- AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
-}
-
-// Sample json input: { "command": "GetHistoryInfo",
-// "search_text": "some text" }
-// Refer chrome/test/pyautolib/history_info.py for sample json output.
-void AutomationProvider::GetHistoryInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- consumer_.CancelAllRequests();
-
- string16 search_text;
- args->GetString("search_text", &search_text);
-
- // Fetch history.
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- history::QueryOptions options;
- // The observer owns itself. It deletes itself after it fetches history.
- AutomationProviderHistoryObserver* history_observer =
- new AutomationProviderHistoryObserver(this, reply_message);
- hs->QueryHistory(
- search_text,
- options,
- &consumer_,
- NewCallback(history_observer,
- &AutomationProviderHistoryObserver::HistoryQueryComplete));
-}
-
-// Sample json input: { "command": "AddHistoryItem",
-// "item": { "URL": "http://www.google.com",
-// "title": "Google", # optional
-// "time": 12345 # optional (time_t)
-// } }
-// Refer chrome/test/pyautolib/pyauto.py for details on input.
-void AutomationProvider::AddHistoryItem(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- DictionaryValue* item = NULL;
- args->GetDictionary(L"item", &item);
- string16 url_text;
- string16 title;
- base::Time time = base::Time::Now();
- AutomationJSONReply reply(this, reply_message);
-
- if (!item->GetString("url", &url_text)) {
- reply.SendError("bad args (no URL in dict?)");
- return;
- }
- GURL gurl(url_text);
- item->GetString("title", &title); // Don't care if it fails.
- int it;
- double dt;
- if (item->GetInteger(L"time", &it))
- time = base::Time::FromTimeT(it);
- else if (item->GetReal(L"time", &dt))
- time = base::Time::FromDoubleT(dt);
-
- // Ideas for "dummy" values (e.g. id_scope) came from
- // chrome/browser/autocomplete/history_contents_provider_unittest.cc
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- const void* id_scope = reinterpret_cast<void*>(1);
- hs->AddPage(gurl, time,
- id_scope,
- 0,
- GURL(),
- PageTransition::LINK,
- history::RedirectList(),
- false);
- if (title.length())
- hs->SetPageTitle(gurl, title);
- reply.SendSuccess(NULL);
-}
-
-// Sample json input: { "command": "GetDownloadsInfo" }
-// Refer chrome/test/pyautolib/download_info.py for sample json output.
-void AutomationProvider::GetDownloadsInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- AutomationProviderDownloadManagerObserver observer;
- std::vector<DownloadItem*> downloads;
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
- AutomationJSONReply reply(this, reply_message);
-
- if (!profile_->HasCreatedDownloadManager()) {
- reply.SendError("no download manager");
- return;
- }
- // Use DownloadManager's GetDownloads() method and not GetCurrentDownloads()
- // since that would be transient; a download might enter and empty out
- // the current download queue too soon to be noticed.
- profile_->GetDownloadManager()->GetDownloads(&observer, L"");
- downloads = observer.Downloads();
-
- std::map<DownloadItem::DownloadState, std::string> state_to_string;
- state_to_string[DownloadItem::IN_PROGRESS] = std::string("IN_PROGRESS");
- state_to_string[DownloadItem::CANCELLED] = std::string("CANCELLED");
- state_to_string[DownloadItem::REMOVING] = std::string("REMOVING");
- state_to_string[DownloadItem::COMPLETE] = std::string("COMPLETE");
-
- std::map<DownloadItem::SafetyState, std::string> safety_state_to_string;
- safety_state_to_string[DownloadItem::SAFE] = std::string("SAFE");
- safety_state_to_string[DownloadItem::DANGEROUS] = std::string("DANGEROUS");
- safety_state_to_string[DownloadItem::DANGEROUS_BUT_VALIDATED] =
- std::string("DANGEROUS_BUT_VALIDATED");
-
- ListValue* list_of_downloads = new ListValue;
- for (std::vector<DownloadItem*>::iterator it = downloads.begin();
- it != downloads.end();
- it++) { // Fill info about each download item.
- DictionaryValue* dl_item_value = new DictionaryValue;
- dl_item_value->SetInteger(L"id", static_cast<int>((*it)->id()));
- dl_item_value->SetString(L"url", (*it)->url().spec());
- dl_item_value->SetString(L"referrer_url", (*it)->referrer_url().spec());
- dl_item_value->SetString(L"file_name", (*it)->file_name().value());
- dl_item_value->SetString(L"full_path", (*it)->full_path().value());
- dl_item_value->SetBoolean(L"is_paused", (*it)->is_paused());
- dl_item_value->SetBoolean(L"open_when_complete",
- (*it)->open_when_complete());
- dl_item_value->SetBoolean(L"is_extension_install",
- (*it)->is_extension_install());
- dl_item_value->SetBoolean(L"is_temporary", (*it)->is_temporary());
- dl_item_value->SetBoolean(L"is_otr", (*it)->is_otr()); // off-the-record
- dl_item_value->SetString(L"state", state_to_string[(*it)->state()]);
- dl_item_value->SetString(L"safety_state",
- safety_state_to_string[(*it)->safety_state()]);
- dl_item_value->SetInteger(L"PercentComplete", (*it)->PercentComplete());
- list_of_downloads->Append(dl_item_value);
- }
- return_value->Set(L"downloads", list_of_downloads);
-
- reply.SendSuccess(return_value.get());
- // All value objects allocated above are owned by |return_value|
- // and get freed by it.
-}
-
-void AutomationProvider::WaitForDownloadsToComplete(
- Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- AutomationProviderDownloadManagerObserver observer;
- std::vector<DownloadItem*> downloads;
- AutomationJSONReply reply(this, reply_message);
-
- // Look for a quick return.
- if (!profile_->HasCreatedDownloadManager()) {
- reply.SendSuccess(NULL); // No download manager.
- return;
- }
- profile_->GetDownloadManager()->GetCurrentDownloads(&observer, FilePath());
- downloads = observer.Downloads();
- if (downloads.size() == 0) {
- reply.SendSuccess(NULL);
- return;
- }
-
- // The observer owns itself. When the last observed item pings, it
- // deletes itself.
- AutomationProviderDownloadItemObserver* item_observer =
- new AutomationProviderDownloadItemObserver(
- this, reply_message, downloads.size());
- for (std::vector<DownloadItem*>::iterator i = downloads.begin();
- i != downloads.end();
- i++) {
- (*i)->AddObserver(item_observer);
- }
-}
-
-// Sample json input: { "command": "GetPrefsInfo" }
-// Refer chrome/test/pyautolib/prefs_info.py for sample json output.
-void AutomationProvider::GetPrefsInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- const PrefService::PreferenceSet& prefs =
- profile_->GetPrefs()->preference_set();
- DictionaryValue* items = new DictionaryValue;
- for (PrefService::PreferenceSet::const_iterator it = prefs.begin();
- it != prefs.end(); ++it) {
- items->Set((*it)->name(), (*it)->GetValue()->DeepCopy());
- }
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
- return_value->Set(L"prefs", items); // return_value owns items.
- AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
-}
-
-// Sample json input: { "command": "SetPrefs", "path": path, "value": value }
-void AutomationProvider::SetPrefs(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- std::wstring path;
- Value* val;
- AutomationJSONReply reply(this, reply_message);
- if (args->GetString(L"path", &path) && args->Get(L"value", &val)) {
- PrefService* pref_service = profile_->GetPrefs();
- const PrefService::Preference* pref =
- pref_service->FindPreference(path.c_str());
- if (!pref) { // Not a registered pref.
- reply.SendError("pref not registered.");
- return;
- } else if (pref->IsManaged()) { // Do not attempt to change a managed pref.
- reply.SendError("pref is managed. cannot be changed.");
- return;
- } else { // Set the pref.
- pref_service->Set(path.c_str(), *val);
- }
- } else {
- reply.SendError("no pref path or value given.");
- return;
- }
-
- reply.SendSuccess(NULL);
-}
-
-// Sample json input: { "command": "GetOmniboxInfo" }
-// Refer chrome/test/pyautolib/omnibox_info.py for sample json output.
-void AutomationProvider::GetOmniboxInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
-
- LocationBar* loc_bar = browser->window()->GetLocationBar();
- AutocompleteEditView* edit_view = loc_bar->location_entry();
- AutocompleteEditModel* model = edit_view->model();
-
- // Fill up matches.
- ListValue* matches = new ListValue;
- const AutocompleteResult& result = model->result();
- for (AutocompleteResult::const_iterator i = result.begin();
- i != result.end(); ++i) {
- const AutocompleteMatch& match = *i;
- DictionaryValue* item = new DictionaryValue; // owned by return_value
- item->SetString(L"type", AutocompleteMatch::TypeToString(match.type));
- item->SetBoolean(L"starred", match.starred);
- item->SetString(L"destination_url", match.destination_url.spec());
- item->SetString(L"contents", match.contents);
- item->SetString(L"description", match.description);
- matches->Append(item);
- }
- return_value->Set(L"matches", matches);
-
- // Fill up other properties.
- DictionaryValue* properties = new DictionaryValue; // owned by return_value
- properties->SetBoolean(L"has_focus", model->has_focus());
- properties->SetBoolean(L"query_in_progress", model->query_in_progress());
- properties->SetString(L"keyword", model->keyword());
- properties->SetString(L"text", edit_view->GetText());
- return_value->Set(L"properties", properties);
-
- AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
-}
-
-// Sample json input: { "command": "SetOmniboxText",
-// "text": "goog" }
-void AutomationProvider::SetOmniboxText(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- std::wstring text;
- AutomationJSONReply reply(this, reply_message);
- if (!args->GetString(L"text", &text)) {
- reply.SendError("text missing");
- return;
- }
- browser->FocusLocationBar();
- LocationBar* loc_bar = browser->window()->GetLocationBar();
- AutocompleteEditView* edit_view = loc_bar->location_entry();
- edit_view->model()->OnSetFocus(false);
- edit_view->SetUserText(text);
- reply.SendSuccess(NULL);
-}
-
-// Sample json input: { "command": "OmniboxMovePopupSelection",
-// "count": 1 }
-// Negative count implies up, positive implies down. Count values will be
-// capped by the size of the popup list.
-void AutomationProvider::OmniboxMovePopupSelection(
- Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- int count;
- AutomationJSONReply reply(this, reply_message);
- if (!args->GetInteger(L"count", &count)) {
- reply.SendError("count missing");
- return;
- }
- LocationBar* loc_bar = browser->window()->GetLocationBar();
- AutocompleteEditModel* model = loc_bar->location_entry()->model();
- model->OnUpOrDownKeyPressed(count);
- reply.SendSuccess(NULL);
-}
-
-// Sample json input: { "command": "OmniboxAcceptInput" }
-void AutomationProvider::OmniboxAcceptInput(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- NavigationController& controller =
- browser->GetSelectedTabContents()->controller();
- // Setup observer to wait until the selected item loads.
- NotificationObserver* observer =
- new OmniboxAcceptNotificationObserver(&controller, this, reply_message);
- notification_observer_list_.AddObserver(observer);
-
- browser->window()->GetLocationBar()->AcceptInput();
-}
-
-// Sample json input: { "command": "GetInitialLoadTimes" }
-// Refer to InitialLoadObserver::GetTimingInformation() for sample output.
-void AutomationProvider::GetInitialLoadTimes(
- Browser*,
- DictionaryValue*,
- IPC::Message* reply_message) {
- scoped_ptr<DictionaryValue> return_value(
- initial_load_observer_->GetTimingInformation());
-
- std::string json_return;
- base::JSONWriter::Write(return_value.get(), false, &json_return);
- AutomationMsg_SendJSONRequest::WriteReplyParams(
- reply_message, json_return, true);
- Send(reply_message);
-}
-
-// Sample json input: { "command": "GetPluginsInfo" }
-// Refer chrome/test/pyautolib/plugins_info.py for sample json output.
-void AutomationProvider::GetPluginsInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
- ListValue* items = new ListValue;
- for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
- it != plugins.end();
- ++it) {
- DictionaryValue* item = new DictionaryValue;
- item->SetStringFromUTF16(L"name", it->name);
- item->SetString(L"path", it->path.value());
- item->SetStringFromUTF16(L"version", it->version);
- item->SetStringFromUTF16(L"desc", it->desc);
- item->SetBoolean(L"enabled", it->enabled);
- // Add info about mime types.
- ListValue* mime_types = new ListValue();
- for (std::vector<WebPluginMimeType>::const_iterator type_it =
- it->mime_types.begin();
- type_it != it->mime_types.end();
- ++type_it) {
- DictionaryValue* mime_type = new DictionaryValue();
- mime_type->SetString(L"mimeType", type_it->mime_type);
- mime_type->SetStringFromUTF16(L"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(L"fileExtensions", file_extensions);
-
- mime_types->Append(mime_type);
- }
- item->Set(L"mimeTypes", mime_types);
- items->Append(item);
- }
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
- return_value->Set(L"plugins", items); // return_value owns items.
-
- AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
-}
-
-// Sample json input:
-// { "command": "EnablePlugin",
-// "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
-void AutomationProvider::EnablePlugin(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- FilePath::StringType path;
- AutomationJSONReply reply(this, reply_message);
- if (!args->GetString(L"path", &path)) {
- reply.SendError("path not specified.");
- return;
- } else if (!NPAPI::PluginList::Singleton()->EnablePlugin(FilePath(path))) {
- reply.SendError(StringPrintf("Could not enable plugin for path %s.",
- path.c_str()));
- return;
- }
- reply.SendSuccess(NULL);
-}
-
-// Sample json input:
-// { "command": "DisablePlugin",
-// "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
-void AutomationProvider::DisablePlugin(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- FilePath::StringType path;
- AutomationJSONReply reply(this, reply_message);
- if (!args->GetString(L"path", &path)) {
- reply.SendError("path not specified.");
- return;
- } else if (!NPAPI::PluginList::Singleton()->DisablePlugin(FilePath(path))) {
- reply.SendError(StringPrintf("Could not disable plugin for path %s.",
- path.c_str()));
- return;
- }
- reply.SendSuccess(NULL);
-}
-
-// Sample json input:
-// { "command": "SaveTabContents",
-// "tab_index": 0,
-// "filename": <a full pathname> }
-// Sample json output:
-// {}
-void AutomationProvider::SaveTabContents(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- int tab_index = 0;
- FilePath::StringType filename;
- FilePath::StringType parent_directory;
- TabContents* tab_contents = NULL;
-
- if (!args->GetInteger(L"tab_index", &tab_index) ||
- !args->GetString(L"filename", &filename)) {
- AutomationJSONReply(this, reply_message).SendError(
- "tab_index or filename param missing");
- return;
- } else {
- tab_contents = browser->GetTabContentsAt(tab_index);
- if (!tab_contents) {
- AutomationJSONReply(this, reply_message).SendError(
- "no tab at tab_index");
- return;
- }
- }
- // We're doing a SAVE_AS_ONLY_HTML so the the directory path isn't
- // used. Nevertheless, SavePackage requires it be valid. Sigh.
- parent_directory = FilePath(filename).DirName().value();
- if (!tab_contents->SavePage(FilePath(filename), FilePath(parent_directory),
- SavePackage::SAVE_AS_ONLY_HTML)) {
- AutomationJSONReply(this, reply_message).SendError(
- "Could not initiate SavePage");
- return;
- }
- // The observer will delete itself when done.
- new SavePackageNotificationObserver(tab_contents->save_package(),
- this, reply_message);
-}
-
-// Refer to ImportSettings() in chrome/test/pyautolib/pyauto.py for sample
-// json input.
-// Sample json output: "{}"
-void AutomationProvider::ImportSettings(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- // Map from the json string passed over to the import item masks.
- std::map<std::string, ImportItem> string_to_import_item;
- string_to_import_item["HISTORY"] = importer::HISTORY;
- string_to_import_item["FAVORITES"] = importer::FAVORITES;
- string_to_import_item["COOKIES"] = importer::COOKIES;
- string_to_import_item["PASSWORDS"] = importer::PASSWORDS;
- string_to_import_item["SEARCH_ENGINES"] = importer::SEARCH_ENGINES;
- string_to_import_item["HOME_PAGE"] = importer::HOME_PAGE;
- string_to_import_item["ALL"] = importer::ALL;
-
- std::wstring browser_name;
- int import_items = 0;
- ListValue* import_items_list = NULL;
- bool first_run;
-
- if (!args->GetString(L"import_from", &browser_name) ||
- !args->GetBoolean(L"first_run", &first_run) ||
- !args->GetList(L"import_items", &import_items_list)) {
- AutomationJSONReply(this, reply_message).SendError(
- "Incorrect type for one or more of the arguments.");
- return;
- }
-
- int num_items = import_items_list->GetSize();
- for (int i = 0; i < num_items; i++) {
- std::string item;
- import_items_list->GetString(i, &item);
- // If the provided string is not part of the map, error out.
- if (!ContainsKey(string_to_import_item, item)) {
- AutomationJSONReply(this, reply_message).SendError(
- "Invalid item string found in import_items.");
- return;
- }
- 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++) {
- std::wstring name = 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;
- }
-
- 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);
-}
-
-// See AddSavedPassword() in chrome/test/functional/pyauto.py for sample json
-// input.
-// Sample json output: { "password_added": true }
-void AutomationProvider::AddSavedPassword(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- string16 username;
- string16 password;
- base::Time time = base::Time::Now();
- AutomationJSONReply reply(this, reply_message);
-
- if (!args->GetStringAsUTF16(L"password", &password) ||
- !args->GetStringAsUTF16(L"username", &username)) {
- reply.SendError("Username and password must be strings.");
- return;
- }
-
- // If the time is specified, change time to the specified time.
- int it;
- double dt;
- if (args->GetInteger(L"time", &it))
- time = base::Time::FromTimeT(it);
- else if (args->GetReal(L"time", &dt))
- time = base::Time::FromDoubleT(dt);
-
- webkit_glue::PasswordForm new_password;
- new_password.username_value = username;
- new_password.password_value = password;
- new_password.date_created = time;
-
- Profile* profile = browser->profile();
- // Use IMPLICIT_ACCESS since new passwords aren't added off the record.
- PasswordStore* password_store =
- profile->GetPasswordStore(Profile::IMPLICIT_ACCESS);
-
- // Set the return based on whether setting the password succeeded.
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
-
- // It will be null if it's accessed in an incognito window.
- if (password_store != NULL) {
- password_store->AddLogin(new_password);
- return_value->SetBoolean(L"password_added", true);
- } else {
- return_value->SetBoolean(L"password_added", false);
- }
-
- reply.SendSuccess(return_value.get());
-}
-
-// Sample json input: { "command": "GetSavedPasswords" }
-// Refer to GetSavedPasswords() in chrome/test/pyautolib/pyauto.py for sample
-// json output.
-void AutomationProvider::GetSavedPasswords(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- Profile* profile = browser->profile();
- // Use EXPLICIT_ACCESS since saved passwords can be retreived off the record.
- PasswordStore* password_store =
- profile->GetPasswordStore(Profile::EXPLICIT_ACCESS);
- password_store->GetAutofillableLogins(
- new AutomationProviderGetPasswordsObserver(this, reply_message));
- // Observer deletes itself after returning.
-}
-
-// Refer to ClearBrowsingData() in chrome/test/pyautolib/pyauto.py for sample
-// json input.
-// Sample json output: {}
-void AutomationProvider::ClearBrowsingData(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- std::map<std::string, BrowsingDataRemover::TimePeriod> string_to_time_period;
- string_to_time_period["LAST_HOUR"] = BrowsingDataRemover::LAST_HOUR;
- string_to_time_period["LAST_DAY"] = BrowsingDataRemover::LAST_DAY;
- string_to_time_period["LAST_WEEK"] = BrowsingDataRemover::LAST_WEEK;
- string_to_time_period["FOUR_WEEKS"] = BrowsingDataRemover::FOUR_WEEKS;
- string_to_time_period["EVERYTHING"] = BrowsingDataRemover::EVERYTHING;
-
- std::map<std::string, int> string_to_mask_value;
- string_to_mask_value["HISTORY"] = BrowsingDataRemover::REMOVE_HISTORY;
- string_to_mask_value["DOWNLOADS"] = BrowsingDataRemover::REMOVE_DOWNLOADS;
- string_to_mask_value["COOKIES"] = BrowsingDataRemover::REMOVE_COOKIES;
- string_to_mask_value["PASSWORDS"] = BrowsingDataRemover::REMOVE_PASSWORDS;
- string_to_mask_value["FORM_DATA"] = BrowsingDataRemover::REMOVE_FORM_DATA;
- string_to_mask_value["CACHE"] = BrowsingDataRemover::REMOVE_CACHE;
-
- std::string time_period;
- ListValue* to_remove;
- if (!args->GetString(L"time_period", &time_period) ||
- !args->GetList(L"to_remove", &to_remove)) {
- AutomationJSONReply(this, reply_message).SendError(
- "time_period must be a string and to_remove a list.");
- return;
- }
-
- int remove_mask = 0;
- int num_removals = to_remove->GetSize();
- for (int i = 0; i < num_removals; i++) {
- std::string removal;
- to_remove->GetString(i, &removal);
- // If the provided string is not part of the map, then error out.
- if (!ContainsKey(string_to_mask_value, removal)) {
- AutomationJSONReply(this, reply_message).SendError(
- "Invalid browsing data string found in to_remove.");
- return;
- }
- remove_mask |= string_to_mask_value[removal];
- }
-
- if (!ContainsKey(string_to_time_period, time_period)) {
- AutomationJSONReply(this, reply_message).SendError(
- "Invalid string for time_period.");
- return;
- }
-
- BrowsingDataRemover* remover = new BrowsingDataRemover(
- profile(), string_to_time_period[time_period], base::Time());
-
- remover->AddObserver(
- new AutomationProviderBrowsingDataObserver(this, reply_message));
- remover->Remove(remove_mask);
- // BrowsingDataRemover deletes itself using DeleteTask.
- // The observer also deletes itself after sending the reply.
-}
-
-// Sample json input: { "command": "GetThemeInfo" }
-// Refer GetThemeInfo() in chrome/test/pyautolib/pyauto.py for sample output.
-void AutomationProvider::GetThemeInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
- Extension* theme = browser->profile()->GetTheme();
- if (theme) {
- return_value->SetString(L"name", theme->name());
- return_value->Set(L"images", theme->GetThemeImages()->DeepCopy());
- return_value->Set(L"colors", theme->GetThemeColors()->DeepCopy());
- return_value->Set(L"tints", theme->GetThemeTints()->DeepCopy());
- }
- AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
-}
-
-// Sample json input:
-// { "command": "GetAutoFillProfile" }
-// Refer to GetAutoFillProfile() in chrome/test/pyautolib/pyauto.py for sample
-// json output.
-void AutomationProvider::GetAutoFillProfile(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- // Get the AutoFillProfiles currently in the database.
- int tab_index = 0;
- args->GetInteger(L"tab_index", &tab_index);
- TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
- AutomationJSONReply reply(this, reply_message);
-
- if (tab_contents) {
- PersonalDataManager* pdm = tab_contents->profile()->GetOriginalProfile()
- ->GetPersonalDataManager();
- if (pdm) {
- std::vector<AutoFillProfile*> autofill_profiles = pdm->profiles();
- std::vector<CreditCard*> credit_cards = pdm->credit_cards();
-
- ListValue* profiles = GetListFromAutoFillProfiles(autofill_profiles);
- ListValue* cards = GetListFromCreditCards(credit_cards);
-
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
-
- return_value->Set(L"profiles", profiles);
- return_value->Set(L"credit_cards", cards);
- reply.SendSuccess(return_value.get());
- } else {
- reply.SendError("No PersonalDataManager.");
- return;
- }
- } else {
- reply.SendError("No tab at that index.");
- return;
- }
-}
-
-// Refer to FillAutoFillProfile() in chrome/test/pyautolib/pyauto.py for sample
-// json input.
-// Sample json output: {}
-void AutomationProvider::FillAutoFillProfile(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message) {
- AutomationJSONReply reply(this, reply_message);
- ListValue* profiles = NULL;
- ListValue* cards = NULL;
- args->GetList(L"profiles", &profiles);
- args->GetList(L"credit_cards", &cards);
- std::string error_mesg;
-
- std::vector<AutoFillProfile> autofill_profiles;
- std::vector<CreditCard> credit_cards;
- // Create an AutoFillProfile for each of the dictionary profiles.
- if (profiles) {
- autofill_profiles = GetAutoFillProfilesFromList(*profiles, &error_mesg);
- }
- // Create a CreditCard for each of the dictionary values.
- if (cards) {
- credit_cards = GetCreditCardsFromList(*cards, &error_mesg);
- }
- if (!error_mesg.empty()) {
- reply.SendError(error_mesg);
- return;
- }
-
- // Save the AutoFillProfiles.
- int tab_index = 0;
- args->GetInteger(L"tab_index", &tab_index);
- TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
-
- if (tab_contents) {
- PersonalDataManager* pdm = tab_contents->profile()
- ->GetPersonalDataManager();
- if (pdm) {
- pdm->OnAutoFillDialogApply(profiles? &autofill_profiles : NULL,
- cards? &credit_cards : NULL);
- } else {
- reply.SendError("No PersonalDataManager.");
- return;
- }
- } else {
- reply.SendError("No tab at that index.");
- return;
- }
- reply.SendSuccess(NULL);
-}
-
-/* static */
-ListValue* AutomationProvider::GetListFromAutoFillProfiles(
- std::vector<AutoFillProfile*> autofill_profiles) {
- ListValue* profiles = new ListValue;
-
- std::map<AutoFillFieldType, std::wstring> autofill_type_to_string
- = GetAutoFillFieldToStringMap();
-
- // For each AutoFillProfile, transform it to a dictionary object to return.
- for (std::vector<AutoFillProfile*>::iterator it = autofill_profiles.begin();
- it != autofill_profiles.end(); ++it) {
- AutoFillProfile* profile = *it;
- DictionaryValue* profile_info = new DictionaryValue;
- profile_info->SetStringFromUTF16(L"label", profile->Label());
- // For each of the types, if it has a value, add it to the dictionary.
- for (std::map<AutoFillFieldType, std::wstring>::iterator
- type_it = autofill_type_to_string.begin();
- type_it != autofill_type_to_string.end(); ++type_it) {
- string16 value = profile->GetFieldText(AutoFillType(type_it->first));
- if (value.length()) { // If there was something stored for that value.
- profile_info->SetStringFromUTF16(type_it->second, value);
- }
- }
- profiles->Append(profile_info);
- }
- return profiles;
-}
-
-/* static */
-ListValue* AutomationProvider::GetListFromCreditCards(
- std::vector<CreditCard*> credit_cards) {
- ListValue* cards = new ListValue;
-
- std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string =
- GetCreditCardFieldToStringMap();
-
- // For each AutoFillProfile, transform it to a dictionary object to return.
- for (std::vector<CreditCard*>::iterator it = credit_cards.begin();
- it != credit_cards.end(); ++it) {
- CreditCard* card = *it;
- DictionaryValue* card_info = new DictionaryValue;
- card_info->SetStringFromUTF16(L"label", card->Label());
- // For each of the types, if it has a value, add it to the dictionary.
- for (std::map<AutoFillFieldType, std::wstring>::iterator type_it =
- credit_card_type_to_string.begin();
- type_it != credit_card_type_to_string.end(); ++type_it) {
- string16 value = card->GetFieldText(AutoFillType(type_it->first));
- // If there was something stored for that value.
- if (value.length()) {
- card_info->SetStringFromUTF16(type_it->second, value);
- }
- }
- cards->Append(card_info);
- }
- return cards;
-}
-
-/* static */
-std::vector<AutoFillProfile> AutomationProvider::GetAutoFillProfilesFromList(
- const ListValue& profiles, std::string* error_message) {
- std::vector<AutoFillProfile> autofill_profiles;
- DictionaryValue* profile_info = NULL;
- string16 profile_label;
- string16 current_value;
-
- std::map<AutoFillFieldType, std::wstring> autofill_type_to_string =
- GetAutoFillFieldToStringMap();
-
- int num_profiles = profiles.GetSize();
- for (int i = 0; i < num_profiles; i++) {
- profiles.GetDictionary(i, &profile_info);
- profile_info->GetString("label", &profile_label);
- // Choose an id of 0 so that a unique id will be created.
- AutoFillProfile profile(profile_label, 0);
- // Loop through the possible profile types and add those provided.
- for (std::map<AutoFillFieldType, std::wstring>::iterator type_it =
- autofill_type_to_string.begin();
- type_it != autofill_type_to_string.end(); ++type_it) {
- if (profile_info->HasKey(type_it->second)) {
- if (profile_info->GetStringAsUTF16(type_it->second, &current_value)) {
- profile.SetInfo(AutoFillType(type_it->first), current_value);
- } else {
- *error_message= "All values must be strings";
- break;
- }
- }
- }
- autofill_profiles.push_back(profile);
- }
- return autofill_profiles;
-}
-
-/* static */
-std::vector<CreditCard> AutomationProvider::GetCreditCardsFromList(
- const ListValue& cards, std::string* error_message) {
- std::vector<CreditCard> credit_cards;
- DictionaryValue* card_info = NULL;
- string16 card_label;
- string16 current_value;
-
- std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string =
- GetCreditCardFieldToStringMap();
-
- int num_credit_cards = cards.GetSize();
- for (int i = 0; i < num_credit_cards; i++) {
- cards.GetDictionary(i, &card_info);
- card_info->GetString("label", &card_label);
- CreditCard card(card_label, 0);
- // Loop through the possible credit card fields and add those provided.
- for (std::map<AutoFillFieldType, std::wstring>::iterator type_it =
- credit_card_type_to_string.begin();
- type_it != credit_card_type_to_string.end(); ++type_it) {
- if (card_info->HasKey(type_it->second)) {
- if (card_info->GetStringAsUTF16(type_it->second, &current_value)) {
- card.SetInfo(AutoFillType(type_it->first), current_value);
- } else {
- *error_message= "All values must be strings";
- break;
- }
- }
- }
- credit_cards.push_back(card);
- }
- return credit_cards;
-}
-
-/* static */
-std::map<AutoFillFieldType, std::wstring>
- AutomationProvider::GetAutoFillFieldToStringMap() {
- std::map<AutoFillFieldType, std::wstring> autofill_type_to_string;
- autofill_type_to_string[NAME_FIRST] = L"NAME_FIRST";
- autofill_type_to_string[NAME_MIDDLE] = L"NAME_MIDDLE";
- autofill_type_to_string[NAME_LAST] = L"NAME_LAST";
- autofill_type_to_string[COMPANY_NAME] = L"COMPANY_NAME";
- autofill_type_to_string[EMAIL_ADDRESS] = L"EMAIL_ADDRESS";
- autofill_type_to_string[ADDRESS_HOME_LINE1] = L"ADDRESS_HOME_LINE1";
- autofill_type_to_string[ADDRESS_HOME_LINE2] = L"ADDRESS_HOME_LINE2";
- autofill_type_to_string[ADDRESS_HOME_CITY] = L"ADDRESS_HOME_CITY";
- autofill_type_to_string[ADDRESS_HOME_STATE] = L"ADDRESS_HOME_STATE";
- autofill_type_to_string[ADDRESS_HOME_ZIP] = L"ADDRESS_HOME_ZIP";
- autofill_type_to_string[ADDRESS_HOME_COUNTRY] = L"ADDRESS_HOME_COUNTRY";
- autofill_type_to_string[PHONE_HOME_NUMBER] = L"PHONE_HOME_NUMBER";
- autofill_type_to_string[PHONE_FAX_NUMBER] = L"PHONE_FAX_NUMBER";
- autofill_type_to_string[NAME_FIRST] = L"NAME_FIRST";
- return autofill_type_to_string;
-}
-
-/* static */
-std::map<AutoFillFieldType, std::wstring>
- AutomationProvider::GetCreditCardFieldToStringMap() {
- std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string;
- credit_card_type_to_string[CREDIT_CARD_NAME] = L"CREDIT_CARD_NAME";
- credit_card_type_to_string[CREDIT_CARD_NUMBER] = L"CREDIT_CARD_NUMBER";
- credit_card_type_to_string[CREDIT_CARD_TYPE] = L"CREDIT_CARD_TYPE";
- credit_card_type_to_string[CREDIT_CARD_EXP_MONTH] = L"CREDIT_CARD_EXP_MONTH";
- credit_card_type_to_string[CREDIT_CARD_EXP_4_DIGIT_YEAR] =
- L"CREDIT_CARD_EXP_4_DIGIT_YEAR";
- return credit_card_type_to_string;
-}
-
-void AutomationProvider::SendJSONRequest(int handle,
- std::string json_request,
- IPC::Message* reply_message) {
- Browser* browser = NULL;
- scoped_ptr<Value> values;
-
- // Basic error checking.
- if (browser_tracker_->ContainsHandle(handle)) {
- browser = browser_tracker_->GetResource(handle);
- }
- if (!browser) {
- AutomationJSONReply(this, reply_message).SendError("no browser object");
- return;
- }
- base::JSONReader reader;
- std::string error;
- values.reset(reader.ReadAndReturnError(json_request, true, NULL, &error));
- if (!error.empty()) {
- AutomationJSONReply(this, reply_message).SendError(error);
- return;
- }
-
- // Make sure input is a dict with a string command.
- std::string command;
- DictionaryValue* dict_value = NULL;
- if (values->GetType() != Value::TYPE_DICTIONARY) {
- AutomationJSONReply(this, reply_message).SendError("not a dict");
- return;
- }
- // Ownership remains with "values" variable.
- dict_value = static_cast<DictionaryValue*>(values.get());
- if (!dict_value->GetStringASCII(std::string("command"), &command)) {
- AutomationJSONReply(this, reply_message).SendError(
- "no command key in dict or not a string command");
- return;
- }
-
- // Map json commands to their handlers.
- std::map<std::string, JsonHandler> handler_map;
- handler_map["DisablePlugin"] = &AutomationProvider::DisablePlugin;
- handler_map["EnablePlugin"] = &AutomationProvider::EnablePlugin;
- handler_map["GetPluginsInfo"] = &AutomationProvider::GetPluginsInfo;
-
- handler_map["GetBrowserInfo"] = &AutomationProvider::GetBrowserInfo;
-
- handler_map["WaitForInfobarCount"] = &AutomationProvider::WaitForInfobarCount;
-
- handler_map["GetHistoryInfo"] = &AutomationProvider::GetHistoryInfo;
- handler_map["AddHistoryItem"] = &AutomationProvider::AddHistoryItem;
-
- handler_map["GetOmniboxInfo"] = &AutomationProvider::GetOmniboxInfo;
- handler_map["SetOmniboxText"] = &AutomationProvider::SetOmniboxText;
- handler_map["OmniboxAcceptInput"] = &AutomationProvider::OmniboxAcceptInput;
- handler_map["OmniboxMovePopupSelection"] =
- &AutomationProvider::OmniboxMovePopupSelection;
-
- handler_map["GetPrefsInfo"] = &AutomationProvider::GetPrefsInfo;
- handler_map["SetPrefs"] = &AutomationProvider::SetPrefs;
-
- handler_map["SetWindowDimensions"] = &AutomationProvider::SetWindowDimensions;
-
- handler_map["GetDownloadsInfo"] = &AutomationProvider::GetDownloadsInfo;
- handler_map["WaitForAllDownloadsToComplete"] =
- &AutomationProvider::WaitForDownloadsToComplete;
-
- handler_map["GetInitialLoadTimes"] = &AutomationProvider::GetInitialLoadTimes;
-
- handler_map["SaveTabContents"] = &AutomationProvider::SaveTabContents;
-
- handler_map["ImportSettings"] = &AutomationProvider::ImportSettings;
-
- handler_map["AddSavedPassword"] = &AutomationProvider::AddSavedPassword;
- handler_map["GetSavedPasswords"] = &AutomationProvider::GetSavedPasswords;
-
- handler_map["ClearBrowsingData"] = &AutomationProvider::ClearBrowsingData;
-
- // SetTheme() implemented using InstallExtension().
- handler_map["GetThemeInfo"] = &AutomationProvider::GetThemeInfo;
-
- handler_map["GetAutoFillProfile"] = &AutomationProvider::GetAutoFillProfile;
- handler_map["FillAutoFillProfile"] = &AutomationProvider::FillAutoFillProfile;
-
- if (handler_map.find(std::string(command)) != handler_map.end()) {
- (this->*handler_map[command])(browser, dict_value, reply_message);
- } else {
- std::string error_string = "Unknown command. Options: ";
- for (std::map<std::string, JsonHandler>::const_iterator it =
- handler_map.begin(); it != handler_map.end(); ++it) {
- error_string += it->first + ", ";
- }
- AutomationJSONReply(this, reply_message).SendError(error_string);
- }
-}
-
-void AutomationProvider::HandleInspectElementRequest(
- int handle, int x, int y, IPC::Message* reply_message) {
- TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
- if (tab_contents) {
- DCHECK(reply_message_ == NULL);
- reply_message_ = reply_message;
-
- DevToolsManager::GetInstance()->InspectElement(
- tab_contents->render_view_host(), x, y);
- } else {
- AutomationMsg_InspectElement::WriteReplyParams(reply_message, -1);
- Send(reply_message);
- }
-}
-
-void AutomationProvider::ReceivedInspectElementResponse(int num_resources) {
- if (reply_message_) {
- AutomationMsg_InspectElement::WriteReplyParams(reply_message_,
- num_resources);
- Send(reply_message_);
- reply_message_ = NULL;
- }
-}
-
class SetProxyConfigTask : public Task {
public:
SetProxyConfigTask(URLRequestContextGetter* request_context_getter,
@@ -3067,336 +554,6 @@ void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) {
new SetProxyConfigTask(context_getter, new_proxy_config));
}
-void AutomationProvider::GetDownloadDirectory(
- int handle, FilePath* download_directory) {
- DLOG(INFO) << "Handling download directory request";
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- DownloadManager* dlm = tab->profile()->GetDownloadManager();
- DCHECK(dlm);
- *download_directory = dlm->download_path();
- }
-}
-
-void AutomationProvider::OpenNewBrowserWindow(bool show,
- IPC::Message* reply_message) {
- OpenNewBrowserWindowOfType(static_cast<int>(Browser::TYPE_NORMAL), show,
- reply_message);
-}
-
-void AutomationProvider::OpenNewBrowserWindowOfType(
- int type, bool show, IPC::Message* reply_message) {
- new BrowserOpenedNotificationObserver(this, reply_message);
- // We may have no current browser windows open so don't rely on
- // asking an existing browser to execute the IDC_NEWWINDOW command
- Browser* browser = new Browser(static_cast<Browser::Type>(type), profile_);
- browser->CreateBrowserWindow();
- browser->AddBlankTab(true);
- if (show)
- browser->window()->Show();
-}
-
-void AutomationProvider::GetWindowForBrowser(int browser_handle,
- bool* success,
- int* handle) {
- *success = false;
- *handle = 0;
-
- if (browser_tracker_->ContainsHandle(browser_handle)) {
- Browser* browser = browser_tracker_->GetResource(browser_handle);
- gfx::NativeWindow win = browser->window()->GetNativeHandle();
- // Add() returns the existing handle for the resource if any.
- *handle = window_tracker_->Add(win);
- *success = true;
- }
-}
-
-void AutomationProvider::GetAutocompleteEditForBrowser(
- int browser_handle,
- bool* success,
- int* autocomplete_edit_handle) {
- *success = false;
- *autocomplete_edit_handle = 0;
-
- if (browser_tracker_->ContainsHandle(browser_handle)) {
- Browser* browser = browser_tracker_->GetResource(browser_handle);
- LocationBar* loc_bar = browser->window()->GetLocationBar();
- AutocompleteEditView* edit_view = loc_bar->location_entry();
- // Add() returns the existing handle for the resource if any.
- *autocomplete_edit_handle = autocomplete_edit_tracker_->Add(edit_view);
- *success = true;
- }
-}
-
-void AutomationProvider::ShowInterstitialPage(int tab_handle,
- const std::string& html_text,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(tab_handle)) {
- NavigationController* controller = tab_tracker_->GetResource(tab_handle);
- TabContents* tab_contents = controller->tab_contents();
-
- AddNavigationStatusListener(controller, reply_message, 1, false);
- AutomationInterstitialPage* interstitial =
- new AutomationInterstitialPage(tab_contents,
- GURL("about:interstitial"),
- html_text);
- interstitial->Show();
- return;
- }
-
- AutomationMsg_ShowInterstitialPage::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
-void AutomationProvider::HideInterstitialPage(int tab_handle,
- bool* success) {
- *success = false;
- TabContents* tab_contents = GetTabContentsForHandle(tab_handle, NULL);
- if (tab_contents && tab_contents->interstitial_page()) {
- tab_contents->interstitial_page()->DontProceed();
- *success = true;
- }
-}
-
-void AutomationProvider::CloseTab(int tab_handle,
- bool wait_until_closed,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(tab_handle)) {
- NavigationController* controller = tab_tracker_->GetResource(tab_handle);
- int index;
- Browser* browser = Browser::GetBrowserForController(controller, &index);
- DCHECK(browser);
- new TabClosedNotificationObserver(this, wait_until_closed, reply_message);
- browser->CloseContents(controller->tab_contents());
- return;
- }
-
- AutomationMsg_CloseTab::WriteReplyParams(reply_message, false);
- Send(reply_message);
-}
-
-void AutomationProvider::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();
- }
-}
-
-void AutomationProvider::CloseBrowserAsync(int browser_handle) {
- if (browser_tracker_->ContainsHandle(browser_handle)) {
- Browser* browser = browser_tracker_->GetResource(browser_handle);
- browser->window()->Close();
- } else {
- NOTREACHED();
- }
-}
-
-void AutomationProvider::WaitForTabToBeRestored(int tab_handle,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(tab_handle)) {
- NavigationController* tab = tab_tracker_->GetResource(tab_handle);
- restore_tracker_.reset(
- new NavigationControllerRestoredObserver(this, tab, reply_message));
- }
-}
-
-void AutomationProvider::GetSecurityState(int handle, bool* success,
- SecurityStyle* security_style,
- int* ssl_cert_status,
- int* insecure_content_status) {
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- NavigationEntry* entry = tab->GetActiveEntry();
- *success = true;
- *security_style = entry->ssl().security_style();
- *ssl_cert_status = entry->ssl().cert_status();
- *insecure_content_status = entry->ssl().content_status();
- } else {
- *success = false;
- *security_style = SECURITY_STYLE_UNKNOWN;
- *ssl_cert_status = 0;
- *insecure_content_status = 0;
- }
-}
-
-void AutomationProvider::GetPageType(int handle, bool* success,
- NavigationEntry::PageType* page_type) {
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- NavigationEntry* entry = tab->GetActiveEntry();
- *page_type = entry->page_type();
- *success = true;
- // In order to return the proper result when an interstitial is shown and
- // no navigation entry were created for it we need to ask the TabContents.
- if (*page_type == NavigationEntry::NORMAL_PAGE &&
- tab->tab_contents()->showing_interstitial_page())
- *page_type = NavigationEntry::INTERSTITIAL_PAGE;
- } else {
- *success = false;
- *page_type = NavigationEntry::NORMAL_PAGE;
- }
-}
-
-void AutomationProvider::GetMetricEventDuration(const std::string& event_name,
- int* duration_ms) {
- *duration_ms = metric_event_duration_observer_->GetEventDurationMs(
- event_name);
-}
-
-void AutomationProvider::ActionOnSSLBlockingPage(int handle, bool proceed,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- NavigationEntry* entry = tab->GetActiveEntry();
- if (entry->page_type() == NavigationEntry::INTERSTITIAL_PAGE) {
- TabContents* tab_contents = tab->tab_contents();
- InterstitialPage* ssl_blocking_page =
- InterstitialPage::GetInterstitialPage(tab_contents);
- if (ssl_blocking_page) {
- if (proceed) {
- AddNavigationStatusListener(tab, reply_message, 1, false);
- ssl_blocking_page->Proceed();
- return;
- }
- ssl_blocking_page->DontProceed();
- AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS);
- Send(reply_message);
- return;
- }
- }
- }
- // We failed.
- AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
-void AutomationProvider::BringBrowserToFront(int browser_handle,
- bool* success) {
- if (browser_tracker_->ContainsHandle(browser_handle)) {
- Browser* browser = browser_tracker_->GetResource(browser_handle);
- browser->window()->Activate();
- *success = true;
- } else {
- *success = false;
- }
-}
-
-void AutomationProvider::IsMenuCommandEnabled(int browser_handle,
- int message_num,
- bool* menu_item_enabled) {
- 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;
- }
-}
-
-void AutomationProvider::PrintNow(int tab_handle,
- IPC::Message* reply_message) {
- NavigationController* tab = NULL;
- TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab);
- if (tab_contents) {
- FindAndActivateTab(tab);
- notification_observer_list_.AddObserver(
- new DocumentPrintedNotificationObserver(this, reply_message));
- if (tab_contents->PrintNow())
- return;
- }
- AutomationMsg_PrintNow::WriteReplyParams(reply_message, false);
- Send(reply_message);
-}
-
-void AutomationProvider::SavePage(int tab_handle,
- const FilePath& file_name,
- const FilePath& dir_path,
- int type,
- bool* success) {
- if (!tab_tracker_->ContainsHandle(tab_handle)) {
- *success = false;
- return;
- }
-
- 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;
-}
-
-void AutomationProvider::GetAutocompleteEditText(int autocomplete_edit_handle,
- bool* success,
- std::wstring* text) {
- *success = false;
- if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
- *text = autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
- GetText();
- *success = true;
- }
-}
-
-void AutomationProvider::SetAutocompleteEditText(int autocomplete_edit_handle,
- const std::wstring& text,
- bool* success) {
- *success = false;
- if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
- autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
- SetUserText(text);
- *success = true;
- }
-}
-
-void AutomationProvider::AutocompleteEditGetMatches(
- int autocomplete_edit_handle,
- bool* success,
- std::vector<AutocompleteMatchData>* matches) {
- *success = false;
- if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
- const AutocompleteResult& result = autocomplete_edit_tracker_->
- GetResource(autocomplete_edit_handle)->model()->result();
- for (AutocompleteResult::const_iterator i = result.begin();
- i != result.end(); ++i)
- matches->push_back(AutocompleteMatchData(*i));
- *success = true;
- }
-}
-
-void AutomationProvider::AutocompleteEditIsQueryInProgress(
- int autocomplete_edit_handle,
- bool* success,
- bool* query_in_progress) {
- *success = false;
- *query_in_progress = false;
- if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
- *query_in_progress = autocomplete_edit_tracker_->
- GetResource(autocomplete_edit_handle)->model()->query_in_progress();
- *success = true;
- }
-}
-
-#if !defined(OS_MACOSX)
-
-#endif // !defined(OS_MACOSX)
-
TabContents* AutomationProvider::GetTabContentsForHandle(
int handle, NavigationController** tab) {
if (tab_tracker_->ContainsHandle(handle)) {
@@ -3408,179 +565,6 @@ TabContents* AutomationProvider::GetTabContentsForHandle(
return NULL;
}
-TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
- : AutomationProvider(profile) {
- BrowserList::AddObserver(this);
- registrar_.Add(this, NotificationType::SESSION_END,
- NotificationService::AllSources());
-}
-
-TestingAutomationProvider::~TestingAutomationProvider() {
- BrowserList::RemoveObserver(this);
-}
-
-void TestingAutomationProvider::OnChannelError() {
- BrowserList::CloseAllBrowsersAndExit();
- AutomationProvider::OnChannelError();
-}
-
-void TestingAutomationProvider::OnBrowserAdded(const Browser* browser) {
-}
-
-void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
- // For backwards compatibility with the testing automation interface, we
- // want the automation provider (and hence the process) to go away when the
- // last browser goes away.
- if (BrowserList::size() == 1 && !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kKeepAliveForTest)) {
- // If you change this, update Observer for NotificationType::SESSION_END
- // below.
- MessageLoop::current()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
- }
-}
-
-void TestingAutomationProvider::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NotificationType::SESSION_END);
- // OnBrowserRemoving 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 OnBrowserRemoving.
- Release();
-}
-
-void TestingAutomationProvider::OnRemoveProvider() {
- AutomationProviderList::GetInstance()->RemoveProvider(this);
-}
-
-void AutomationProvider::GetInfoBarCount(int handle, int* count) {
- *count = -1; // -1 means error.
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* nav_controller = tab_tracker_->GetResource(handle);
- if (nav_controller)
- *count = nav_controller->tab_contents()->infobar_delegate_count();
- }
-}
-
-void AutomationProvider::ClickInfoBarAccept(int handle,
- int info_bar_index,
- bool wait_for_navigation,
- IPC::Message* reply_message) {
- bool success = false;
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* nav_controller = tab_tracker_->GetResource(handle);
- if (nav_controller) {
- int count = nav_controller->tab_contents()->infobar_delegate_count();
- if (info_bar_index >= 0 && info_bar_index < count) {
- if (wait_for_navigation) {
- AddNavigationStatusListener(nav_controller, reply_message, 1, false);
- }
- InfoBarDelegate* delegate =
- nav_controller->tab_contents()->GetInfoBarDelegateAt(
- info_bar_index);
- if (delegate->AsConfirmInfoBarDelegate())
- delegate->AsConfirmInfoBarDelegate()->Accept();
- success = true;
- }
- }
- }
-
- // This "!wait_for_navigation || !success condition" logic looks suspicious.
- // It will send a failure message when success is true but
- // |wait_for_navigation| is false.
- // TODO(phajdan.jr): investgate whether the reply param (currently
- // AUTOMATION_MSG_NAVIGATION_ERROR) should depend on success.
- if (!wait_for_navigation || !success)
- AutomationMsg_ClickInfoBarAccept::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
-}
-
-void AutomationProvider::GetLastNavigationTime(int handle,
- int64* last_navigation_time) {
- Time time = tab_tracker_->GetLastNavigationTime(handle);
- *last_navigation_time = time.ToInternalValue();
-}
-
-void AutomationProvider::WaitForNavigation(int handle,
- int64 last_navigation_time,
- IPC::Message* reply_message) {
- NavigationController* controller = tab_tracker_->GetResource(handle);
- Time time = tab_tracker_->GetLastNavigationTime(handle);
-
- if (time.ToInternalValue() > last_navigation_time || !controller) {
- AutomationMsg_WaitForNavigation::WriteReplyParams(reply_message,
- controller == NULL ? AUTOMATION_MSG_NAVIGATION_ERROR :
- AUTOMATION_MSG_NAVIGATION_SUCCESS);
- Send(reply_message);
- return;
- }
-
- AddNavigationStatusListener(controller, reply_message, 1, true);
-}
-
-void AutomationProvider::SetIntPreference(int handle,
- const std::wstring& name,
- int value,
- bool* success) {
- *success = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- browser->profile()->GetPrefs()->SetInteger(name.c_str(), value);
- *success = true;
- }
-}
-
-void AutomationProvider::SetStringPreference(int handle,
- const std::wstring& name,
- const std::string& value,
- bool* success) {
- *success = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- browser->profile()->GetPrefs()->SetString(name.c_str(), value);
- *success = true;
- }
-}
-
-void AutomationProvider::GetBooleanPreference(int handle,
- const std::wstring& name,
- bool* success,
- bool* value) {
- *success = false;
- *value = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- *value = browser->profile()->GetPrefs()->GetBoolean(name.c_str());
- *success = true;
- }
-}
-
-void AutomationProvider::SetBooleanPreference(int handle,
- const std::wstring& name,
- bool value,
- bool* success) {
- *success = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- browser->profile()->GetPrefs()->SetBoolean(name.c_str(), value);
- *success = true;
- }
-}
-
-// Gets the current used encoding name of the page in the specified tab.
-void AutomationProvider::GetPageCurrentEncoding(
- int tab_handle, std::string* current_encoding) {
- if (tab_tracker_->ContainsHandle(tab_handle)) {
- NavigationController* nav = tab_tracker_->GetResource(tab_handle);
- Browser* browser = FindAndActivateTab(nav);
- DCHECK(browser);
-
- if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU))
- *current_encoding = nav->tab_contents()->encoding();
- }
-}
-
// Gets the current used encoding name of the page in the specified tab.
void AutomationProvider::OverrideEncoding(int tab_handle,
const std::string& encoding_name,
@@ -3617,29 +601,6 @@ void AutomationProvider::OverrideEncoding(int tab_handle,
}
}
-void AutomationProvider::SavePackageShouldPromptUser(bool should_prompt) {
- SavePackage::SetShouldPromptUser(should_prompt);
-}
-
-void AutomationProvider::GetBlockedPopupCount(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) {
- BlockedPopupContainer* container =
- tab_contents->blocked_popup_container();
- if (container) {
- *count = static_cast<int>(container->GetBlockedPopupCount());
- } else {
- // If we don't have a container, we don't have any blocked popups to
- // contain!
- *count = 0;
- }
- }
- }
-}
-
void AutomationProvider::SelectAll(int tab_handle) {
RenderViewHost* view = GetViewForTab(tab_handle);
if (!view) {
@@ -3737,68 +698,6 @@ void AutomationProvider::RemoveBrowsingData(int remove_mask) {
// BrowsingDataRemover deletes itself.
}
-void AutomationProvider::WaitForBrowserWindowCountToBecome(
- int target_count, IPC::Message* reply_message) {
- if (static_cast<int>(BrowserList::size()) == target_count) {
- AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
- reply_message, true);
- Send(reply_message);
- return;
- }
-
- // Set up an observer (it will delete itself).
- new BrowserCountChangeNotificationObserver(target_count, this, reply_message);
-}
-
-void AutomationProvider::WaitForAppModalDialogToBeShown(
- IPC::Message* reply_message) {
- if (Singleton<AppModalDialogQueue>()->HasActiveDialog()) {
- AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams(
- reply_message, true);
- Send(reply_message);
- return;
- }
-
- // Set up an observer (it will delete itself).
- new AppModalDialogShownObserver(this, reply_message);
-}
-
-void AutomationProvider::GoBackBlockUntilNavigationsComplete(
- int handle, int number_of_navigations, 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, number_of_navigations,
- false);
- browser->GoBack(CURRENT_TAB);
- return;
- }
- }
-
- AutomationMsg_GoBackBlockUntilNavigationsComplete::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
-void AutomationProvider::GoForwardBlockUntilNavigationsComplete(
- int handle, int number_of_navigations, 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, number_of_navigations,
- false);
- browser->GoForward(CURRENT_TAB);
- return;
- }
- }
-
- AutomationMsg_GoForwardBlockUntilNavigationsComplete::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
@@ -3820,28 +719,6 @@ RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) {
return NULL;
}
-void AutomationProvider::GetBrowserForWindow(int window_handle,
- bool* success,
- int* browser_handle) {
- *success = false;
- *browser_handle = 0;
-
- gfx::NativeWindow window = window_tracker_->GetResource(window_handle);
- if (!window)
- return;
-
- BrowserList::const_iterator iter = BrowserList::begin();
- for (;iter != BrowserList::end(); ++iter) {
- gfx::NativeWindow this_window = (*iter)->window()->GetNativeHandle();
- if (window == this_window) {
- // Add() returns the existing handle for the resource if any.
- *browser_handle = browser_tracker_->Add(*iter);
- *success = true;
- return;
- }
- }
-}
-
void AutomationProvider::InstallExtension(const FilePath& crx_path,
IPC::Message* reply_message) {
ExtensionsService* service = profile_->GetExtensionsService();
@@ -4069,7 +946,7 @@ void AutomationProvider::GetExtensionProperty(
}
index++;
}
- *value = IntToString(found_index);
+ *value = base::IntToString(found_index);
*success = true;
}
break;
@@ -4086,48 +963,3 @@ void AutomationProvider::SaveAsAsync(int tab_handle) {
if (tab_contents)
tab_contents->OnSavePage();
}
-
-void AutomationProvider::SetContentSetting(
- int handle,
- const std::string& host,
- ContentSettingsType content_type,
- ContentSetting setting,
- bool* success) {
- *success = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- HostContentSettingsMap* map =
- browser->profile()->GetHostContentSettingsMap();
- if (host.empty()) {
- map->SetDefaultContentSetting(content_type, setting);
- } else {
- map->SetContentSetting(HostContentSettingsMap::Pattern(host),
- content_type, setting);
- }
- *success = true;
- }
-}
-
-#if !defined(TOOLKIT_VIEWS)
-void AutomationProvider::GetFocusedViewID(int handle, int* view_id) {
- NOTIMPLEMENTED();
-};
-
-void AutomationProvider::WaitForFocusedViewIDToChange(
- int handle, int previous_view_id, IPC::Message* reply_message) {
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::StartTrackingPopupMenus(
- int browser_handle, bool* success) {
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::WaitForPopupMenuToOpen(IPC::Message* reply_message) {
- NOTIMPLEMENTED();
-}
-#endif // !defined(TOOLKIT_VIEWS)
-
-void AutomationProvider::ResetToDefaultTheme() {
- profile_->ClearTheme();
-}
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index f166771..838fcd6 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -10,23 +10,25 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_H_
+#pragma once
#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/observer_list.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/autofill/field_types.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/history/history.h"
+#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/content_settings.h"
-#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/test/automation/automation_constants.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_channel.h"
#if defined(OS_WIN)
+#include "gfx/native_widget_types.h"
#include "views/event.h"
#endif // defined(OS_WIN)
@@ -46,16 +48,24 @@ class AutomationExtensionTracker;
class AutomationResourceMessageFilter;
class AutomationTabTracker;
class AutomationWindowTracker;
+class Browser;
class CreditCard;
class DictionaryValue;
+class DownloadItem;
class Extension;
class ExtensionPortContainer;
class ExtensionTestResultNotificationObserver;
class ExternalTabContainer;
+class FilePath;
+class InitialLoadObserver;
+class ListValue;
class LoginHandler;
class MetricEventDurationObserver;
-class InitialLoadObserver;
+class NavigationController;
class NavigationControllerRestoredObserver;
+class Profile;
+class RenderViewHost;
+class TabContents;
struct AutocompleteMatchData;
namespace gfx {
@@ -129,9 +139,6 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
virtual void OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelError();
- // Received response from inspector controller
- void ReceivedInspectElementResponse(int num_resources);
-
IPC::Message* reply_message_release() {
IPC::Message* reply_message = reply_message_;
reply_message_ = NULL;
@@ -148,138 +155,66 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
bool AddExternalTab(ExternalTabContainer* external_tab);
#endif
+ // Get the DictionaryValue equivalent for a download item. Caller owns the
+ // DictionaryValue.
+ DictionaryValue* GetDictionaryFromDownloadItem(const DownloadItem* download);
+
protected:
friend class base::RefCounted<AutomationProvider>;
- friend class PopupMenuWaiter;
virtual ~AutomationProvider();
+ // Helper function to find the browser window that contains a given
+ // NavigationController and activate that tab.
+ // Returns the Browser if found.
+ Browser* FindAndActivateTab(NavigationController* contents);
+
+ // Convert a tab handle into a TabContents. If |tab| is non-NULL a pointer
+ // to the tab is also returned. Returns NULL in case of failure or if the tab
+ // is not of the TabContents type.
+ TabContents* GetTabContentsForHandle(int handle, NavigationController** tab);
+
+ scoped_ptr<AutomationAutocompleteEditTracker> autocomplete_edit_tracker_;
+ scoped_ptr<AutomationBrowserTracker> browser_tracker_;
+ scoped_ptr<InitialLoadObserver> initial_load_observer_;
+ scoped_ptr<MetricEventDurationObserver> metric_event_duration_observer_;
+ scoped_ptr<NavigationControllerRestoredObserver> restore_tracker_;
+ scoped_ptr<AutomationTabTracker> tab_tracker_;
+ scoped_ptr<AutomationWindowTracker> window_tracker_;
+
+ typedef ObserverList<NotificationObserver> NotificationObserverList;
+ NotificationObserverList notification_observer_list_;
+
+ typedef std::map<NavigationController*, LoginHandler*> LoginHandlerMap;
+ LoginHandlerMap login_handler_map_;
+
+ Profile* profile_;
+
+ // A pointer to reply message used when we do asynchronous processing in the
+ // message handler.
+ // TODO(phajdan.jr): Remove |reply_message_|, it is error-prone.
+ IPC::Message* reply_message_;
+
+ // Consumer for asynchronous history queries.
+ CancelableRequestConsumer consumer_;
+
private:
+ void OnUnhandledMessage();
+
// IPC Message callbacks.
- void CloseBrowser(int handle, IPC::Message* reply_message);
- void CloseBrowserAsync(int browser_handle);
- void ActivateTab(int handle, int at_index, int* status);
- void AppendTab(int handle, const GURL& url, IPC::Message* reply_message);
- void CloseTab(int tab_handle, bool wait_until_closed,
- IPC::Message* reply_message);
-
- void GetActiveTabIndex(int handle, int* active_tab_index);
- void GetCookies(const GURL& url, int handle, int* value_size,
- std::string* value);
- void SetCookie(const GURL& url,
- const std::string value,
- int handle,
- int* response_value);
- void DeleteCookie(const GURL& url, const std::string& cookie_name,
- int handle, bool* success);
- void ShowCollectedCookiesDialog(int handle, bool* success);
- void GetBrowserWindowCount(int* window_count);
- void GetBrowserLocale(string16* locale);
- void GetNormalBrowserWindowCount(int* window_count);
- void GetShowingAppModalDialog(bool* showing_dialog, int* dialog_button);
- void ClickAppModalDialogButton(int button, bool* success);
- void ShutdownSessionService(int handle, bool* result);
- // Be aware that the browser window returned might be of non TYPE_NORMAL
- // or in incognito mode.
- void GetBrowserWindow(int index, int* handle);
- void FindNormalBrowserWindow(int* handle);
- void GetLastActiveBrowserWindow(int* handle);
- void GetActiveWindow(int* handle);
- void ExecuteBrowserCommandAsync(int handle, int command, bool* success);
- void ExecuteBrowserCommand(int handle, int command,
- IPC::Message* reply_message);
- void TerminateSession(int handle, bool* success);
- void WindowGetViewBounds(int handle, int view_id, bool screen_coordinates,
- bool* success, gfx::Rect* bounds);
void WindowSimulateDrag(int handle,
std::vector<gfx::Point> drag_path,
int flags,
bool press_escape_en_route,
IPC::Message* reply_message);
- void WindowSimulateClick(const IPC::Message& message,
- int handle,
- const gfx::Point& click,
- int flags);
- void WindowSimulateMouseMove(const IPC::Message& message,
- int handle,
- const gfx::Point& location);
- void WindowSimulateKeyPress(const IPC::Message& message,
- int handle,
- int key,
- int flags);
- void GetWindowBounds(int handle, gfx::Rect* bounds, bool* result);
- void SetWindowBounds(int handle, const gfx::Rect& bounds, bool* result);
- void SetWindowVisible(int handle, bool visible, bool* result);
- void IsWindowActive(int handle, bool* success, bool* is_active);
- void ActivateWindow(int handle);
- void IsWindowMaximized(int handle, bool* is_maximized, bool* success);
-
- void GetTabCount(int handle, int* tab_count);
- void GetType(int handle, int* type_as_int);
- void GetTab(int win_handle, int tab_index, int* tab_handle);
+
#if defined(OS_WIN)
// TODO(port): Replace HWND.
void GetTabHWND(int handle, HWND* tab_hwnd);
#endif // defined(OS_WIN)
- void GetTabProcessID(int handle, int* process_id);
- void GetTabTitle(int handle, int* title_string_size, std::wstring* title);
- void GetTabIndex(int handle, int* tabstrip_index);
- void GetTabURL(int handle, bool* success, GURL* url);
void HandleUnused(const IPC::Message& message, int handle);
- 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);
- void NavigationAsync(int handle, const GURL& url, bool* status);
- void NavigationAsyncWithDisposition(int handle,
- 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);
- void CancelAuth(int tab_handle, IPC::Message* reply_message);
- void NeedsAuth(int tab_handle, bool* needs_auth);
- void GetRedirectsFrom(int tab_handle,
- const GURL& source_url,
- IPC::Message* reply_message);
- void ExecuteJavascript(int handle,
- const std::wstring& frame_xpath,
- const std::wstring& script,
- IPC::Message* reply_message);
- void GetShelfVisibility(int handle, bool* visible);
- void SetShelfVisibility(int handle, bool visible);
void SetFilteredInet(const IPC::Message& message, bool enabled);
void GetFilteredInetHitCount(int* hit_count);
void SetProxyConfig(const std::string& new_proxy_config);
- void IsFullscreen(int handle, bool* is_fullscreen);
- void GetFullscreenBubbleVisibility(int handle, bool* is_visible);
- void SetContentSetting(int handle,
- const std::string& host,
- ContentSettingsType content_type,
- ContentSetting setting,
- bool* success);
-
- void GetFocusedViewID(int handle, int* view_id);
-
- // Helper function to find the browser window that contains a given
- // NavigationController and activate that tab.
- // Returns the Browser if found.
- Browser* FindAndActivateTab(NavigationController* contents);
-
- // Deprecated.
- void ApplyAccelerator(int handle, int id);
-
- void GetConstrainedWindowCount(int handle, int* count);
-
- // This function has been deprecated, please use HandleFindRequest.
- void HandleFindInPageRequest(int handle,
- const std::wstring& find_request,
- int forward,
- int match_case,
- int* active_ordinal,
- int* matches_found);
// Responds to the FindInPage request, retrieves the search query parameters,
// launches an observer to listen for results and issues a StartFind request.
@@ -287,281 +222,6 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
const AutomationMsg_Find_Params& params,
IPC::Message* reply_message);
- // Responds to requests to open the FindInPage window.
- void HandleOpenFindInPageRequest(const IPC::Message& message,
- int handle);
-
- // Get the visibility state of the Find window.
- void GetFindWindowVisibility(int handle, bool* visible);
-
- // Responds to requests to find the location of the Find window.
- void HandleFindWindowLocationRequest(int handle, int* x, int* y);
-
- // Get the visibility state of the Bookmark bar.
- void GetBookmarkBarVisibility(int handle, bool* visible, bool* animating);
-
- // Get the bookmarks as a JSON string.
- void GetBookmarksAsJSON(int handle, std::string* bookmarks_as_json,
- bool *success);
-
- // Wait for the bookmark model to load.
- void WaitForBookmarkModelToLoad(int handle, IPC::Message* reply_message);
-
- // Set |loaded| to true if the bookmark model has loaded, else false.
- void BookmarkModelHasLoaded(int handle, bool* loaded);
-
- // Editing, modification, and removal of bookmarks.
- // Bookmarks are referenced by id.
- void AddBookmarkGroup(int handle,
- int64 parent_id, int index, std::wstring title,
- bool* success);
- void AddBookmarkURL(int handle,
- int64 parent_id, int index,
- std::wstring title, const GURL& url,
- bool* success);
- void ReparentBookmark(int handle,
- int64 id, int64 new_parent_id, int index,
- bool* success);
- void SetBookmarkTitle(int handle,
- int64 id, std::wstring title,
- bool* success);
- void SetBookmarkURL(int handle,
- int64 id, const GURL& url,
- bool* success);
- void RemoveBookmark(int handle,
- int64 id,
- bool* success);
-
- // Set window dimensions.
- // Uses the JSON interface for input/output.
- void SetWindowDimensions(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about infobars in the given TabContents object.
- // This includes info about the type of infobars, the message text,
- // buttons, etc.
- // Caller owns the returned object.
- ListValue* GetInfobarsInfo(TabContents* tc);
-
- // Wait for infobar count in a given tab to become a certain value.
- // Uses the JSON interface for input/output.
- void WaitForInfobarCount(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about the chromium/chrome in use.
- // This includes things like version, executable name, executable path.
- // Uses the JSON interface for input/output.
- void GetBrowserInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about downloads. This includes only ones that have been
- // registered by the history system.
- // Uses the JSON interface for input/output.
- void GetDownloadsInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Wait for all downloads to complete.
- // Uses the JSON interface for input/output.
- void WaitForDownloadsToComplete(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about history.
- // Uses the JSON interface for input/output.
- void GetHistoryInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Add an item to the history service.
- // Uses the JSON interface for input/output.
- void AddHistoryItem(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about preferences.
- // Uses the JSON interface for input/output.
- void GetPrefsInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Set prefs.
- // Uses the JSON interface for input/output.
- void SetPrefs(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Return load times of initial tabs.
- // Uses the JSON interface for input/output.
- // Only includes tabs from command line arguments or session restore.
- // See declaration of InitialLoadObserver in automation_provider_observers.h
- // for example response.
- void GetInitialLoadTimes(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about plugins.
- // Uses the JSON interface for input/output.
- void GetPluginsInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Enable a plugin.
- // Uses the JSON interface for input/output.
- void EnablePlugin(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Disable a plugin.
- // Uses the JSON interface for input/output.
- void DisablePlugin(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about omnibox.
- // Contains data about the matches (url, content, description)
- // in the omnibox popup, the text in the omnibox.
- // Uses the JSON interface for input/output.
- void GetOmniboxInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Set text in the omnibox. This sets focus to the omnibox.
- // Uses the JSON interface for input/output.
- void SetOmniboxText(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Move omnibox popup selection up or down.
- // Uses the JSON interface for input/output.
- void OmniboxMovePopupSelection(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Accept the current string of text in the omnibox.
- // This is equivalent to clicking or hiting enter on a popup selection.
- // Blocks until the page loads.
- // Uses the JSON interface for input/output.
- void OmniboxAcceptInput(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,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Import the given settings from the given browser.
- // Uses the JSON interface for input/output.
- void ImportSettings(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Add a new username-password combination to the saved passwords.
- // Uses the JSON interface for input/output.
- void AddSavedPassword(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Return the saved username/password combinations.
- // Uses the JSON interface for input/output.
- void GetSavedPasswords(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Clear the specified browsing data. This call provides similar
- // functionality to RemoveBrowsingData but is synchronous.
- // Uses the JSON interface for input/output.
- void ClearBrowsingData(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get info about theme.
- // Uses the JSON interface for input/output.
- void GetThemeInfo(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Get the profiles that are currently saved to the DB.
- // Uses the JSON interface for input/output.
- void GetAutoFillProfile(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Fill in an AutoFillProfile with the given profile information.
- // Uses the JSON interface for input/output.
- void FillAutoFillProfile(Browser* browser,
- DictionaryValue* args,
- IPC::Message* reply_message);
-
- // Translate DictionaryValues of autofill profiles and credit cards to the
- // data structure used in the browser.
- // Args:
- // profiles/cards: the ListValue of profiles/credit cards to translate.
- // error_message: a pointer to the return string in case of error.
- static std::vector<AutoFillProfile> GetAutoFillProfilesFromList(
- const ListValue& profiles, std::string* error_message);
- static std::vector<CreditCard> GetCreditCardsFromList(
- const ListValue& cards, std::string* error_message);
-
- // The opposite of the above: translates from the internal data structure
- // for profiles and credit cards to a ListValue of DictionaryValues. The
- // caller owns the returned object.
- static ListValue* GetListFromAutoFillProfiles(
- std::vector<AutoFillProfile*> autofill_profiles);
- static ListValue* GetListFromCreditCards(
- std::vector<CreditCard*> credit_cards);
-
- // Return the map from the internal data representation to the string value
- // of auto fill fields and credit card fields.
- static std::map<AutoFillFieldType, std::wstring>
- GetAutoFillFieldToStringMap();
- static std::map<AutoFillFieldType, std::wstring>
- GetCreditCardFieldToStringMap();
-
- // Generic pattern for pyautolib
- // Uses the JSON interface for input/output.
- void SendJSONRequest(int handle,
- std::string json_request,
- IPC::Message* reply_message);
-
- // Method ptr for json handlers.
- // Uses the JSON interface for input/output.
- typedef void (AutomationProvider::*JsonHandler)(Browser* browser,
- DictionaryValue*,
- IPC::Message*);
-
- // Responds to InspectElement request
- void HandleInspectElementRequest(int handle,
- int x,
- int y,
- IPC::Message* reply_message);
-
- void GetDownloadDirectory(int handle, FilePath* download_directory);
-
- // Retrieves a Browser from a Window and vice-versa.
- void GetWindowForBrowser(int window_handle, bool* success, int* handle);
- void GetBrowserForWindow(int window_handle, bool* success,
- int* browser_handle);
-
- void GetAutocompleteEditForBrowser(int browser_handle, bool* success,
- int* autocomplete_edit_handle);
-
- // 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);
-
- void ShowInterstitialPage(int tab_handle,
- const std::string& html_text,
- IPC::Message* reply_message);
- void HideInterstitialPage(int tab_handle, bool* success);
-
void OnSetPageFontSize(int tab_handle, int font_size);
// See browsing_data_remover.h for explanation of bitmap fields.
@@ -605,139 +265,20 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
bool* success,
std::string* value);
-
- // See comment in AutomationMsg_WaitForTabToBeRestored.
- void WaitForTabToBeRestored(int tab_handle, IPC::Message* reply_message);
-
- // Gets the security state for the tab associated to the specified |handle|.
- void GetSecurityState(int handle, bool* success,
- SecurityStyle* security_style, int* ssl_cert_status,
- int* insecure_content_status);
-
- // Gets the page type for the tab associated to the specified |handle|.
- void GetPageType(int handle, bool* success,
- NavigationEntry::PageType* page_type);
-
- // Gets the duration in ms of the last event matching |event_name|.
- // |duration_ms| is -1 if the event hasn't occurred yet.
- void GetMetricEventDuration(const std::string& event_name, int* duration_ms);
-
- // Simulates an action on the SSL blocking page at the tab specified by
- // |handle|. If |proceed| is true, it is equivalent to the user pressing the
- // 'Proceed' button, if false the 'Get me out of there button'.
- // Not that this fails if the tab is not displaying a SSL blocking page.
- void ActionOnSSLBlockingPage(int handle,
- bool proceed,
- IPC::Message* reply_message);
-
- // Brings the browser window to the front and activates it.
- void BringBrowserToFront(int browser_handle, bool* success);
-
- // Checks to see if a command on the browser's CommandController is enabled.
- void IsMenuCommandEnabled(int browser_handle,
- int message_num,
- bool* menu_item_enabled);
-
- // Prints the current tab immediately.
- void PrintNow(int tab_handle, IPC::Message* reply_message);
-
// Asynchronous request for printing the current tab.
void PrintAsync(int tab_handle);
- // Save the current web page.
- void SavePage(int tab_handle,
- const FilePath& file_name,
- const FilePath& dir_path,
- int type,
- bool* success);
-
- // Retrieves the visible text from the autocomplete edit.
- void GetAutocompleteEditText(int autocomplete_edit_handle,
- bool* success, std::wstring* text);
-
- // Sets the visible text from the autocomplete edit.
- void SetAutocompleteEditText(int autocomplete_edit_handle,
- const std::wstring& text,
- bool* success);
-
- // Retrieves if a query to an autocomplete provider is in progress.
- void AutocompleteEditIsQueryInProgress(int autocomplete_edit_handle,
- bool* success,
- bool* query_in_progress);
-
- // Retrieves the individual autocomplete matches displayed by the popup.
- void AutocompleteEditGetMatches(int autocomplete_edit_handle,
- bool* success,
- std::vector<AutocompleteMatchData>* matches);
-
-
- // Retrieves the number of info-bars currently showing in |count|.
- void GetInfoBarCount(int handle, int* count);
-
- // Causes a click on the "accept" button of the info-bar at |info_bar_index|.
- // If |wait_for_navigation| is true, it sends the reply after a navigation has
- // occurred.
- void ClickInfoBarAccept(int handle, int info_bar_index,
- bool wait_for_navigation,
- IPC::Message* reply_message);
-
- // Retrieves the last time a navigation occurred for the tab.
- void GetLastNavigationTime(int handle, int64* last_navigation_time);
-
- // Waits for a new navigation in the tab if none has happened since
- // |last_navigation_time|.
- void WaitForNavigation(int handle,
- int64 last_navigation_time,
- IPC::Message* reply_message);
-
- // Sets the int value for preference with name |name|.
- void SetIntPreference(int handle,
- const std::wstring& name,
- int value,
- bool* success);
-
- // Sets the string value for preference with name |name|.
- void SetStringPreference(int handle,
- const std::wstring& name,
- const std::string& value,
- bool* success);
-
- // Gets the bool value for preference with name |name|.
- void GetBooleanPreference(int handle,
- const std::wstring& name,
- bool* success,
- bool* value);
-
- // Sets the bool value for preference with name |name|.
- void SetBooleanPreference(int handle,
- const std::wstring& name,
- bool value,
- bool* success);
-
- // Resets to the default theme.
- void ResetToDefaultTheme();
-
- // Gets the current used encoding name of the page in the specified tab.
- void GetPageCurrentEncoding(int tab_handle, std::string* current_encoding);
-
// Uses the specified encoding to override the encoding of the page in the
// specified tab.
void OverrideEncoding(int tab_handle,
const std::string& encoding_name,
bool* success);
- void SavePackageShouldPromptUser(bool should_prompt);
-
// Enables extension automation (for e.g. UITests).
void SetEnableExtensionAutomation(
int tab_handle,
const std::vector<std::string>& functions_enabled);
- void GetWindowTitle(int handle, string16* text);
-
- // Returns the number of blocked popups in the tab |handle|.
- void GetBlockedPopupCount(int handle, int* count);
-
// Selects all contents on the page.
void SelectAll(int tab_handle);
@@ -750,24 +291,6 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
void StopAsync(int tab_handle);
void SaveAsAsync(int tab_handle);
- void WaitForBrowserWindowCountToBecome(int target_count,
- IPC::Message* reply_message);
-
- void WaitForAppModalDialogToBeShown(IPC::Message* reply_message);
-
- void GoBackBlockUntilNavigationsComplete(int handle,
- int number_of_navigations,
- IPC::Message* reply_message);
-
- void GoForwardBlockUntilNavigationsComplete(int handle,
- int number_of_navigations,
- IPC::Message* reply_message);
-
- // Convert a tab handle into a TabContents. If |tab| is non-NULL a pointer
- // to the tab is also returned. Returns NULL in case of failure or if the tab
- // is not of the TabContents type.
- TabContents* GetTabContentsForHandle(int handle, NavigationController** tab);
-
#if defined(OS_CHROMEOS)
// Logs in through the Chrome OS Login Wizard with given |username| and
// password. Returns true via |reply_message| on success.
@@ -776,13 +299,6 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
IPC::Message* reply_message);
#endif
- // Callback for history redirect queries.
- virtual void OnRedirectQueryComplete(
- HistoryService::Handle request_handle,
- GURL from_url,
- bool success,
- history::RedirectList* redirects);
-
// Returns the associated view for the tab handle passed in.
// Returns NULL on failure.
RenderViewHost* GetViewForTab(int tab_handle);
@@ -799,19 +315,6 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
// the associated extension is disabled. Returns NULL otherwise.
Extension* GetDisabledExtension(int extension_handle);
- // Block until the focused view ID changes to something other than
- // previous_view_id.
- void WaitForFocusedViewIDToChange(int handle,
- int previous_view_id,
- IPC::Message* reply_message);
-
- // Start tracking popup menus. Must be called before executing the
- // command that might open the popup menu; then call WaitForPopupMenuToOpen.
- void StartTrackingPopupMenus(int browser_handle, bool* success);
-
- // Wait until a popup menu has opened.
- void WaitForPopupMenuToOpen(IPC::Message* reply_message);
-
// Method called by the popup menu tracker when a popup menu is opened.
void NotifyPopupMenuOpened();
@@ -864,90 +367,28 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
void OnBrowserMoved(int handle);
- void OnRunUnloadHandlers(int handle, gfx::NativeWindow notification_window,
- int notification_message);
+ void OnRunUnloadHandlers(int handle, IPC::Message* reply_message);
+
+ void OnSetZoomLevel(int handle, int zoom_level);
ExternalTabContainer* GetExternalTabForHandle(int handle);
#endif // defined(OS_WIN)
- typedef ObserverList<NotificationObserver> NotificationObserverList;
- typedef std::map<NavigationController*, LoginHandler*> LoginHandlerMap;
typedef std::map<int, ExtensionPortContainer*> PortContainerMap;
scoped_ptr<IPC::ChannelProxy> channel_;
- scoped_ptr<InitialLoadObserver> initial_load_observer_;
scoped_ptr<NotificationObserver> new_tab_ui_load_observer_;
scoped_ptr<NotificationObserver> find_in_page_observer_;
scoped_ptr<NotificationObserver> dom_operation_observer_;
scoped_ptr<NotificationObserver> dom_inspector_observer_;
scoped_ptr<ExtensionTestResultNotificationObserver>
extension_test_result_observer_;
- scoped_ptr<MetricEventDurationObserver> metric_event_duration_observer_;
- scoped_ptr<AutomationBrowserTracker> browser_tracker_;
scoped_ptr<AutomationExtensionTracker> extension_tracker_;
- scoped_ptr<AutomationTabTracker> tab_tracker_;
- scoped_ptr<AutomationWindowTracker> window_tracker_;
- scoped_ptr<AutomationAutocompleteEditTracker> autocomplete_edit_tracker_;
- scoped_ptr<NavigationControllerRestoredObserver> restore_tracker_;
- LoginHandlerMap login_handler_map_;
PortContainerMap port_containers_;
- NotificationObserverList notification_observer_list_;
scoped_refptr<AutomationResourceMessageFilter>
automation_resource_message_filter_;
- // Handle for an in-process redirect query. We expect only one redirect query
- // at a time (we should have only one caller, and it will block while waiting
- // for the results) so there is only one handle. When non-0, indicates a
- // query in progress.
- HistoryService::Handle redirect_query_;
-
- // Consumer for asynchronous history queries.
- CancelableRequestConsumer consumer_;
-
- Profile* profile_;
-
- IPC::Message* reply_message_;
-
- // Keep track of whether a popup menu has been opened since the last time
- // that StartTrackingPopupMenus has been called.
- bool popup_menu_opened_;
-
- // A temporary object that receives a notification when a popup menu opens.
- PopupMenuWaiter* popup_menu_waiter_;
-
DISALLOW_COPY_AND_ASSIGN(AutomationProvider);
};
-// When life started, the AutomationProvider class was a singleton and was meant
-// only for UI tests. It had specific behavior (like for example, when the
-// channel was shut down. it closed all open Browsers). The new
-// AutomationProvider serves other purposes than just UI testing. This class is
-// meant to provide the OLD functionality for backward compatibility
-class TestingAutomationProvider : public AutomationProvider,
- public BrowserList::Observer,
- public NotificationObserver {
- public:
- explicit TestingAutomationProvider(Profile* profile);
-
- // BrowserList::Observer implementation
- // Called immediately after a browser is added to the list
- virtual void OnBrowserAdded(const Browser* browser);
- // Called immediately before a browser is removed from the list
- virtual void OnBrowserRemoving(const Browser* browser);
-
- // IPC implementations
- virtual void OnChannelError();
-
- private:
- virtual ~TestingAutomationProvider();
-
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- void OnRemoveProvider(); // Called via PostTask
-
- NotificationRegistrar registrar_;
-};
-
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_H_
diff --git a/chrome/browser/automation/automation_provider_gtk.cc b/chrome/browser/automation/automation_provider_gtk.cc
index 8b391ee..37c4fb8 100644
--- a/chrome/browser/automation/automation_provider_gtk.cc
+++ b/chrome/browser/automation/automation_provider_gtk.cc
@@ -6,6 +6,7 @@
#include <gtk/gtk.h>
+#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_window_tracker.h"
@@ -16,70 +17,6 @@
#include "gfx/point.h"
#include "gfx/rect.h"
-void AutomationProvider::SetWindowBounds(int handle, const gfx::Rect& bounds,
- bool* success) {
- *success = false;
- GtkWindow* window = window_tracker_->GetResource(handle);
- if (window) {
- gtk_window_move(window, bounds.x(), bounds.height());
- gtk_window_resize(window, bounds.width(), bounds.height());
- *success = true;
- }
-}
-
-void AutomationProvider::SetWindowVisible(int handle, bool visible,
- bool* result) {
- *result = false;
- GtkWindow* window = window_tracker_->GetResource(handle);
- if (window) {
- if (visible) {
- gtk_window_present(window);
- } else {
- gtk_widget_hide(GTK_WIDGET(window));
- }
- *result = true;
- }
-}
-
-#if !defined(TOOLKIT_VIEWS)
-void AutomationProvider::WindowGetViewBounds(int handle, int view_id,
- bool screen_coordinates,
- bool* success,
- gfx::Rect* bounds) {
- *success = false;
-
- GtkWindow* window = window_tracker_->GetResource(handle);
- if (window) {
- GtkWidget* widget = ViewIDUtil::GetWidget(GTK_WIDGET(window),
- static_cast<ViewID>(view_id));
- if (!widget)
- return;
- *success = true;
- *bounds = gfx::Rect(widget->allocation.width, widget->allocation.height);
- gint x, y;
- if (screen_coordinates) {
- gfx::Point point = gtk_util::GetWidgetScreenPosition(widget);
- x = point.x();
- y = point.y();
- } else {
- gtk_widget_translate_coordinates(widget, GTK_WIDGET(window),
- 0, 0, &x, &y);
- }
- bounds->set_origin(gfx::Point(x, y));
- }
-}
-#endif
-
-void AutomationProvider::ActivateWindow(int handle) {
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::IsWindowMaximized(int handle, bool* is_maximized,
- bool* success) {
- *success = false;
- NOTIMPLEMENTED();
-}
-
void AutomationProvider::PrintAsync(int tab_handle) {
NOTIMPLEMENTED();
}
@@ -202,20 +139,3 @@ void AutomationProvider::WindowSimulateDrag(int handle,
Send(reply_message);
}
}
-
-void AutomationProvider::TerminateSession(int handle, bool* success) {
- *success = false;
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::GetWindowBounds(int handle, gfx::Rect* bounds,
- bool* result) {
- *result = false;
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::GetWindowTitle(int handle, string16* text) {
- gfx::NativeWindow window = window_tracker_->GetResource(handle);
- const gchar* title = gtk_window_get_title(window);
- text->assign(UTF8ToUTF16(title));
-}
diff --git a/chrome/browser/automation/automation_provider_json.cc b/chrome/browser/automation/automation_provider_json.cc
index 05f3a1b..2ffbeaa 100644
--- a/chrome/browser/automation/automation_provider_json.cc
+++ b/chrome/browser/automation/automation_provider_json.cc
@@ -6,6 +6,7 @@
#include "base/json/json_writer.h"
#include "base/json/string_escape.h"
+#include "chrome/browser/automation/automation_provider.h"
#include "chrome/test/automation/automation_messages.h"
namespace {
diff --git a/chrome/browser/automation/automation_provider_json.h b/chrome/browser/automation/automation_provider_json.h
index a203c58..26b8581 100644
--- a/chrome/browser/automation/automation_provider_json.h
+++ b/chrome/browser/automation/automation_provider_json.h
@@ -6,12 +6,16 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_JSON_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_JSON_H_
+#pragma once
#include <string>
-#include "base/values.h"
-#include "ipc/ipc_message.h"
-#include "chrome/browser/automation/automation_provider.h"
+class Value;
+class AutomationProvider;
+
+namespace IPC {
+class Message;
+}
// Helper to ensure we always send a reply message for JSON automation requests.
class AutomationJSONReply {
@@ -37,4 +41,3 @@ class AutomationJSONReply {
};
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_JSON_H_
-
diff --git a/chrome/browser/automation/automation_provider_list.h b/chrome/browser/automation/automation_provider_list.h
index 058dc34..47145fa 100644
--- a/chrome/browser/automation/automation_provider_list.h
+++ b/chrome/browser/automation/automation_provider_list.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_LIST_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_LIST_H_
+#pragma once
#include <vector>
#include "base/basictypes.h"
diff --git a/chrome/browser/automation/automation_provider_mac.mm b/chrome/browser/automation/automation_provider_mac.mm
index ed55d2d..99c1bdb 100644
--- a/chrome/browser/automation/automation_provider_mac.mm
+++ b/chrome/browser/automation/automation_provider_mac.mm
@@ -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.
@@ -12,62 +12,13 @@
#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/test/automation/automation_messages.h"
#include "gfx/point.h"
#include "gfx/rect.h"
#include "grit/generated_resources.h"
-void AutomationProvider::SetWindowBounds(int handle, const gfx::Rect& bounds,
- bool* success) {
- *success = false;
- NSWindow* window = window_tracker_->GetResource(handle);
- if (window) {
- NSRect new_bounds = NSRectFromCGRect(bounds.ToCGRect());
-
- if ([[NSScreen screens] count] > 0) {
- new_bounds.origin.y =
- [[[NSScreen screens] objectAtIndex:0] frame].size.height -
- new_bounds.origin.y - new_bounds.size.height;
- }
-
- [window setFrame:new_bounds display:NO];
- *success = true;
- }
-}
-
-void AutomationProvider::SetWindowVisible(int handle, bool visible,
- bool* result) {
- *result = false;
- NSWindow* window = window_tracker_->GetResource(handle);
- if (window) {
- if (visible) {
- [window orderFront:nil];
- } else {
- [window orderOut:nil];
- }
- *result = true;
- }
-}
-
-void AutomationProvider::WindowGetViewBounds(int handle, int view_id,
- bool screen_coordinates,
- bool* success,
- gfx::Rect* bounds) {
- // AutomationProxyVisibleTest claims that this is used only by Chrome Views
- // which we don't use on the Mac. Is this true?
-
- *success = false;
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::ActivateWindow(int handle) { NOTIMPLEMENTED(); }
-
-void AutomationProvider::IsWindowMaximized(int handle, bool* is_maximized,
- bool* success) {
- *success = false;
- NOTIMPLEMENTED();
-}
-
void AutomationProvider::PrintAsync(int tab_handle) {
NOTIMPLEMENTED();
}
@@ -82,33 +33,3 @@ void AutomationProvider::WindowSimulateDrag(int handle,
Send(reply_message);
}
-void AutomationProvider::TerminateSession(int handle, bool* success) {
- *success = false;
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::GetWindowBounds(int handle, gfx::Rect* bounds,
- bool* result) {
- *result = false;
- NOTIMPLEMENTED();
-}
-
-void AutomationProvider::GetWindowTitle(int handle, string16* text) {
- gfx::NativeWindow window = window_tracker_->GetResource(handle);
- NSString* title = nil;
- if ([[window delegate] isKindOfClass:[TabWindowController class]]) {
- TabWindowController* delegate =
- reinterpret_cast<TabWindowController*>([window delegate]);
- title = [delegate selectedTabTitle];
- } else {
- title = [window title];
- }
- // If we don't yet have a title, use "Untitled".
- if (![title length]) {
- text->assign(WideToUTF16(l10n_util::GetString(
- IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED)));
- return;
- }
-
- text->assign(base::SysNSStringToUTF16(title));
-}
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc
index f731309..6628cf1 100644
--- a/chrome/browser/automation/automation_provider_observers.cc
+++ b/chrome/browser/automation/automation_provider_observers.cc
@@ -11,6 +11,8 @@
#include "chrome/browser/automation/automation_provider.h"
#include "chrome/browser/automation/automation_provider_json.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/save_package.h"
@@ -21,8 +23,11 @@
#include "chrome/browser/metrics/metric_event_duration_details.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/translate/page_translated_details.h"
+#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/automation/automation_constants.h"
@@ -98,17 +103,17 @@ DictionaryValue* InitialLoadObserver::GetTimingInformation() const {
DictionaryValue* item = new DictionaryValue;
base::TimeDelta delta_start = it->second.start_time() - init_time_;
- item->SetReal(L"load_start_ms", delta_start.InMillisecondsF());
+ item->SetReal("load_start_ms", delta_start.InMillisecondsF());
if (it->second.stop_time().is_null()) {
- item->Set(L"load_stop_ms", Value::CreateNullValue());
+ item->Set("load_stop_ms", Value::CreateNullValue());
} else {
base::TimeDelta delta_stop = it->second.stop_time() - init_time_;
- item->SetReal(L"load_stop_ms", delta_stop.InMillisecondsF());
+ item->SetReal("load_stop_ms", delta_stop.InMillisecondsF());
}
items->Append(item);
}
DictionaryValue* return_value = new DictionaryValue;
- return_value->Set(L"tabs", items);
+ return_value->Set("tabs", items);
return return_value;
}
@@ -338,6 +343,49 @@ void TabClosedNotificationObserver::set_for_browser_command(
for_browser_command_ = for_browser_command;
}
+TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation,
+ Browser* browser,
+ IPC::Message* reply_message,
+ int target_tab_count)
+ : automation_(automation),
+ reply_message_(reply_message),
+ tab_strip_model_(browser->tabstrip_model()),
+ target_tab_count_(target_tab_count) {
+ tab_strip_model_->AddObserver(this);
+ CheckTabCount();
+}
+
+TabCountChangeObserver::~TabCountChangeObserver() {
+ tab_strip_model_->RemoveObserver(this);
+}
+
+void TabCountChangeObserver::TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground) {
+ CheckTabCount();
+}
+
+void TabCountChangeObserver::TabClosingAt(TabContents* contents, int index) {
+ CheckTabCount();
+}
+
+void TabCountChangeObserver::TabStripModelDeleted() {
+ AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_,
+ false);
+ automation_->Send(reply_message_);
+ delete this;
+}
+
+void TabCountChangeObserver::CheckTabCount() {
+ if (tab_strip_model_->count() != target_tab_count_)
+ return;
+
+ AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_,
+ true);
+ automation_->Send(reply_message_);
+ delete this;
+}
+
bool DidExtensionHostsStopLoading(ExtensionProcessManager* manager) {
for (ExtensionProcessManager::const_iterator iter = manager->begin();
iter != manager->end(); ++iter) {
@@ -758,6 +806,7 @@ void ExecuteBrowserCommandObserver::Observe(
ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver(
AutomationProvider* automation, IPC::Message* reply_message)
: automation_(automation),
+ notification_type_(NotificationType::ALL),
reply_message_(reply_message) {
}
@@ -928,6 +977,117 @@ void MetricEventDurationObserver::Observe(NotificationType type,
metric_event_duration->duration_ms;
}
+PageTranslatedObserver::PageTranslatedObserver(AutomationProvider* automation,
+ IPC::Message* reply_message,
+ TabContents* tab_contents)
+ : automation_(automation),
+ reply_message_(reply_message) {
+ registrar_.Add(this, NotificationType::PAGE_TRANSLATED,
+ Source<TabContents>(tab_contents));
+}
+
+void PageTranslatedObserver::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::PAGE_TRANSLATED);
+ AutomationJSONReply reply(automation_, reply_message_);
+
+ PageTranslatedDetails* translated_details =
+ Details<PageTranslatedDetails>(details).ptr();
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->SetBoolean(
+ "translation_success",
+ translated_details->error_type == TranslateErrors::NONE);
+ reply.SendSuccess(return_value.get());
+ delete this;
+}
+
+TabLanguageDeterminedObserver::TabLanguageDeterminedObserver(
+ AutomationProvider* automation, IPC::Message* reply_message,
+ TabContents* tab_contents, TranslateInfoBarDelegate* translate_bar)
+ : automation_(automation),
+ reply_message_(reply_message),
+ tab_contents_(tab_contents),
+ translate_bar_(translate_bar) {
+ registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
+ Source<TabContents>(tab_contents));
+}
+
+void TabLanguageDeterminedObserver::Observe(
+ NotificationType type, const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED);
+
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->SetBoolean("page_translated",
+ tab_contents_->language_state().IsPageTranslated());
+ return_value->SetBoolean(
+ "can_translate_page", TranslatePrefs::CanTranslate(
+ automation_->profile()->GetPrefs(),
+ tab_contents_->language_state().original_language(),
+ tab_contents_->GetURL()));
+ return_value->SetString(
+ "original_language",
+ tab_contents_->language_state().original_language());
+ if (translate_bar_) {
+ DictionaryValue* bar_info = new DictionaryValue;
+ std::map<TranslateInfoBarDelegate::Type, std::string> type_to_string;
+ type_to_string[TranslateInfoBarDelegate::BEFORE_TRANSLATE] =
+ "BEFORE_TRANSLATE";
+ type_to_string[TranslateInfoBarDelegate::TRANSLATING] =
+ "TRANSLATING";
+ type_to_string[TranslateInfoBarDelegate::AFTER_TRANSLATE] =
+ "AFTER_TRANSLATE";
+ type_to_string[TranslateInfoBarDelegate::TRANSLATION_ERROR] =
+ "TRANSLATION_ERROR";
+
+ bar_info->SetBoolean("always_translate_lang_button_showing",
+ translate_bar_->ShouldShowAlwaysTranslateButton());
+ bar_info->SetBoolean("never_translate_lang_button_showing",
+ translate_bar_->ShouldShowNeverTranslateButton());
+ bar_info->SetString("bar_state", type_to_string[translate_bar_->type()]);
+ bar_info->SetString("target_lang_code",
+ translate_bar_->GetTargetLanguageCode());
+ bar_info->SetString("original_lang_code",
+ translate_bar_->GetOriginalLanguageCode());
+ return_value->Set("translate_bar", bar_info);
+ }
+ AutomationJSONReply(automation_, reply_message_)
+ .SendSuccess(return_value.get());
+ delete this;
+}
+
+InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation,
+ IPC::Message* reply_message,
+ TabContents* tab_contents,
+ int target_count)
+ : automation_(automation),
+ reply_message_(reply_message),
+ tab_contents_(tab_contents),
+ target_count_(target_count) {
+ Source<TabContents> source(tab_contents);
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source);
+ CheckCount();
+}
+
+void InfoBarCountObserver::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED ||
+ type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED);
+ CheckCount();
+}
+
+void InfoBarCountObserver::CheckCount() {
+ if (tab_contents_->infobar_delegate_count() != target_count_)
+ return;
+
+ AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, true);
+ automation_->Send(reply_message_);
+ delete this;
+}
+
#if defined(OS_CHROMEOS)
LoginManagerObserver::LoginManagerObserver(
AutomationProvider* automation,
@@ -951,7 +1111,8 @@ void LoginManagerObserver::Observe(NotificationType type,
}
#endif
-AutomationProviderBookmarkModelObserver::AutomationProviderBookmarkModelObserver(
+AutomationProviderBookmarkModelObserver::
+AutomationProviderBookmarkModelObserver(
AutomationProvider* provider,
IPC::Message* reply_message,
BookmarkModel* model) {
@@ -961,7 +1122,8 @@ AutomationProviderBookmarkModelObserver::AutomationProviderBookmarkModelObserver
model_->AddObserver(this);
}
-AutomationProviderBookmarkModelObserver::~AutomationProviderBookmarkModelObserver() {
+AutomationProviderBookmarkModelObserver::
+~AutomationProviderBookmarkModelObserver() {
model_->RemoveObserver(this);
}
@@ -981,6 +1143,49 @@ void AutomationProviderDownloadItemObserver::OnDownloadFileCompleted(
}
}
+void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated(
+ DownloadItem* download) {
+ // If this observer is watching for open, only send the reply if the download
+ // has been auto-opened.
+ if (wait_for_open_ && !download->auto_opened())
+ return;
+
+ download->RemoveObserver(this);
+ scoped_ptr<DictionaryValue> return_value(
+ provider_->GetDictionaryFromDownloadItem(download));
+ AutomationJSONReply(provider_, reply_message_).SendSuccess(
+ return_value.get());
+ delete this;
+}
+
+void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened(
+ DownloadItem* download) {
+ download->RemoveObserver(this);
+ scoped_ptr<DictionaryValue> return_value(
+ provider_->GetDictionaryFromDownloadItem(download));
+ AutomationJSONReply(provider_, reply_message_).SendSuccess(
+ return_value.get());
+ delete this;
+}
+
+void AutomationProviderDownloadModelChangedObserver::ModelChanged() {
+ AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL);
+ download_manager_->RemoveObserver(this);
+ delete this;
+}
+
+void AutomationProviderSearchEngineObserver::OnTemplateURLModelChanged() {
+ TemplateURLModel* url_model = provider_->profile()->GetTemplateURLModel();
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->Set("search_engines",
+ provider_->ExtractSearchEngineInfo(url_model));
+
+ url_model->RemoveObserver(this);
+ AutomationJSONReply(provider_, reply_message_).SendSuccess(
+ return_value.get());
+ delete this;
+}
+
void AutomationProviderHistoryObserver::HistoryQueryComplete(
HistoryService::Handle request_handle,
history::QueryResults* results) {
@@ -990,18 +1195,18 @@ void AutomationProviderHistoryObserver::HistoryQueryComplete(
for (size_t i = 0; i < results->size(); ++i) {
DictionaryValue* page_value = new DictionaryValue;
history::URLResult const &page = (*results)[i];
- page_value->SetStringFromUTF16(L"title", page.title());
- page_value->SetString(L"url", page.url().spec());
- page_value->SetReal(L"time",
+ page_value->SetString("title", page.title());
+ page_value->SetString("url", page.url().spec());
+ page_value->SetReal("time",
static_cast<double>(page.visit_time().ToDoubleT()));
- page_value->SetStringFromUTF16(L"snippet", page.snippet().text());
+ page_value->SetString("snippet", page.snippet().text());
page_value->SetBoolean(
- L"starred",
+ "starred",
provider_->profile()->GetBookmarkModel()->IsBookmarked(page.url()));
history_list->Append(page_value);
}
- return_value->Set(L"history", history_list);
+ return_value->Set("history", history_list);
// Return history info.
AutomationJSONReply reply(provider_, reply_message_);
reply.SendSuccess(return_value.get());
@@ -1023,17 +1228,24 @@ void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone(
result.begin(); it != result.end(); ++it) {
DictionaryValue* password_val = new DictionaryValue;
webkit_glue::PasswordForm* password_form = *it;
- password_val->SetStringFromUTF16(L"username",
- password_form->username_value);
- password_val->SetStringFromUTF16(L"password",
- password_form->password_value);
+ password_val->SetString("username_value", password_form->username_value);
+ password_val->SetString("password_value", password_form->password_value);
+ password_val->SetString("signon_realm", password_form->signon_realm);
password_val->SetReal(
- L"time", static_cast<double>(
- password_form->date_created.ToDoubleT()));
+ "time", static_cast<double>(password_form->date_created.ToDoubleT()));
+ password_val->SetString("origin_url", password_form->origin.spec());
+ password_val->SetString("username_element",
+ password_form->username_element);
+ password_val->SetString("password_element",
+ password_form->password_element);
+ password_val->SetString("submit_element",
+ password_form->submit_element);
+ password_val->SetString("action_target", password_form->action.spec());
+ password_val->SetBoolean("blacklist", password_form->blacklisted_by_user);
passwords->Append(password_val);
}
- return_value->Set(L"passwords", passwords);
+ return_value->Set("passwords", passwords);
AutomationJSONReply(provider_, reply_message_).SendSuccess(
return_value.get());
delete this;
@@ -1097,38 +1309,24 @@ void SavePackageNotificationObserver::Observe(
}
}
-WaitForInfobarCountObserver::WaitForInfobarCountObserver(
+AutocompleteEditFocusedObserver::AutocompleteEditFocusedObserver(
AutomationProvider* automation,
- IPC::Message* reply_message,
- TabContents* tab_contents,
- int count)
- : automation_(automation),
- reply_message_(reply_message),
- tab_contents_(tab_contents),
- count_(count) {
- if (tab_contents->infobar_delegate_count() == count) {
- ConditionMet();
- return;
- }
- registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED,
- Source<TabContents>(tab_contents_));
- registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
- Source<TabContents>(tab_contents_));
+ AutocompleteEditModel* autocomplete_edit,
+ IPC::Message* reply_message)
+ : automation_(automation),
+ reply_message_(reply_message),
+ autocomplete_edit_model_(autocomplete_edit) {
+ Source<AutocompleteEditModel> source(autocomplete_edit);
+ registrar_.Add(this, NotificationType::AUTOCOMPLETE_EDIT_FOCUSED, source);
}
-void WaitForInfobarCountObserver::Observe(
+void AutocompleteEditFocusedObserver::Observe(
NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED ||
- type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED);
- if (tab_contents_->infobar_delegate_count() == count_) {
- ConditionMet();
- }
-}
-
-void WaitForInfobarCountObserver::ConditionMet() {
- registrar_.RemoveAll();
- AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL);
+ DCHECK(type == NotificationType::AUTOCOMPLETE_EDIT_FOCUSED);
+ AutomationMsg_WaitForAutocompleteEditFocus::WriteReplyParams(
+ reply_message_, true);
+ automation_->Send(reply_message_);
delete this;
}
diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h
index 732d1fd..e03f8a3 100644
--- a/chrome/browser/automation/automation_provider_observers.h
+++ b/chrome/browser/automation/automation_provider_observers.h
@@ -1,27 +1,32 @@
-// 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.
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_OBSERVERS_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_OBSERVERS_H_
+#pragma once
#include <deque>
#include <map>
#include <set>
+#include "chrome/browser/automation/testing_automation_provider.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
#include "chrome/browser/browsing_data_remover.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/history/history.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/automation/automation_messages.h"
+class AutocompleteEditModel;
class AutomationProvider;
class Browser;
class Extension;
@@ -29,6 +34,7 @@ class ExtensionProcessManager;
class NavigationController;
class SavePackage;
class TabContents;
+class TranslateInfoBarDelegate;
namespace IPC {
class Message;
@@ -188,6 +194,37 @@ class TabClosedNotificationObserver : public TabStripNotificationObserver {
DISALLOW_COPY_AND_ASSIGN(TabClosedNotificationObserver);
};
+// Notifies when the tab count reaches the target number.
+class TabCountChangeObserver : public TabStripModelObserver {
+ public:
+ TabCountChangeObserver(AutomationProvider* automation,
+ Browser* browser,
+ IPC::Message* reply_message,
+ int target_tab_count);
+ // Implementation of TabStripModelObserver.
+ virtual void TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground);
+ virtual void TabClosingAt(TabContents* contents, int index);
+ virtual void TabStripModelDeleted();
+
+ private:
+ ~TabCountChangeObserver();
+
+ // Checks if the current tab count matches our target, and if so,
+ // sends the reply message and deletes self.
+ void CheckTabCount();
+
+ AutomationProvider* automation_;
+ IPC::Message* reply_message_;
+
+ TabStripModel* tab_strip_model_;
+
+ const int target_tab_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabCountChangeObserver);
+};
+
// Observes when an extension has finished installing or possible install
// errors. This does not guarantee that the extension is ready for use.
class ExtensionInstallNotificationObserver : public NotificationObserver {
@@ -486,6 +523,74 @@ class MetricEventDurationObserver : public NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(MetricEventDurationObserver);
};
+class PageTranslatedObserver : public NotificationObserver {
+ public:
+ PageTranslatedObserver(AutomationProvider* automation,
+ IPC::Message* reply_message,
+ TabContents* tab_contents);
+
+ // NotificationObserver interface.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ NotificationRegistrar registrar_;
+ scoped_refptr<AutomationProvider> automation_;
+ IPC::Message* reply_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(PageTranslatedObserver);
+};
+
+class TabLanguageDeterminedObserver : public NotificationObserver {
+ public:
+ TabLanguageDeterminedObserver(AutomationProvider* automation,
+ IPC::Message* reply_message,
+ TabContents* tab_contents,
+ TranslateInfoBarDelegate* translate_bar);
+
+ // NotificationObserver interface.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ NotificationRegistrar registrar_;
+ AutomationProvider* automation_;
+ IPC::Message* reply_message_;
+ TabContents* tab_contents_;
+ TranslateInfoBarDelegate* translate_bar_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabLanguageDeterminedObserver);
+};
+
+class InfoBarCountObserver : public NotificationObserver {
+ public:
+ InfoBarCountObserver(AutomationProvider* automation,
+ IPC::Message* reply_message,
+ TabContents* tab_contents,
+ int target_count);
+
+ // NotificationObserver interface.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Checks whether the infobar count matches our target, and if so
+ // sends the reply message and deletes itself.
+ void CheckCount();
+
+ NotificationRegistrar registrar_;
+ AutomationProvider* automation_;
+ IPC::Message* reply_message_;
+ TabContents* tab_contents_;
+
+ const int target_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(InfoBarCountObserver);
+};
+
#if defined(OS_CHROMEOS)
// Collects LOGIN_AUTHENTICATION notifications and returns
// whether authentication succeeded to the automation provider.
@@ -553,27 +658,6 @@ class AutomationProviderBookmarkModelObserver : BookmarkModelObserver {
DISALLOW_COPY_AND_ASSIGN(AutomationProviderBookmarkModelObserver);
};
-// When asked for pending downloads, the DownloadManager places
-// results in a DownloadManager::Observer.
-class AutomationProviderDownloadManagerObserver
- : public DownloadManager::Observer {
- public:
- AutomationProviderDownloadManagerObserver() : DownloadManager::Observer() {}
- virtual ~AutomationProviderDownloadManagerObserver() {}
- virtual void ModelChanged() {}
- virtual void SetDownloads(std::vector<DownloadItem*>& downloads) {
- downloads_ = downloads;
- }
- std::vector<DownloadItem*> Downloads() {
- return downloads_;
- }
- private:
- std::vector<DownloadItem*> downloads_;
-
- DISALLOW_COPY_AND_ASSIGN(AutomationProviderDownloadManagerObserver);
-};
-
-
// Allows the automation provider to wait for all downloads to finish.
class AutomationProviderDownloadItemObserver : public DownloadItem::Observer {
public:
@@ -599,6 +683,74 @@ class AutomationProviderDownloadItemObserver : public DownloadItem::Observer {
DISALLOW_COPY_AND_ASSIGN(AutomationProviderDownloadItemObserver);
};
+// Allows the automation provider to wait until the download has been updated
+// or opened.
+class AutomationProviderDownloadUpdatedObserver
+ : public DownloadItem::Observer {
+ public:
+ AutomationProviderDownloadUpdatedObserver(
+ AutomationProvider* provider,
+ IPC::Message* reply_message,
+ bool wait_for_open)
+ : provider_(provider),
+ reply_message_(reply_message),
+ wait_for_open_(wait_for_open) {}
+
+ virtual void OnDownloadUpdated(DownloadItem* download);
+ virtual void OnDownloadOpened(DownloadItem* download);
+ virtual void OnDownloadFileCompleted(DownloadItem* download) { }
+
+ private:
+ AutomationProvider* provider_;
+ IPC::Message* reply_message_;
+ bool wait_for_open_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomationProviderDownloadUpdatedObserver);
+};
+
+// Allows the automation provider to wait until the download model has changed
+// (because a new download has been added or removed).
+class AutomationProviderDownloadModelChangedObserver
+ : public DownloadManager::Observer {
+ public:
+ AutomationProviderDownloadModelChangedObserver(
+ AutomationProvider* provider,
+ IPC::Message* reply_message,
+ DownloadManager* download_manager)
+ : provider_(provider),
+ reply_message_(reply_message),
+ download_manager_(download_manager) {}
+
+ virtual void ModelChanged();
+
+ private:
+ AutomationProvider* provider_;
+ IPC::Message* reply_message_;
+ DownloadManager* download_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomationProviderDownloadModelChangedObserver);
+};
+
+// Allows automation provider to wait until TemplateURLModel has loaded
+// before looking up/returning search engine info.
+class AutomationProviderSearchEngineObserver
+ : public TemplateURLModelObserver {
+ public:
+ AutomationProviderSearchEngineObserver(
+ TestingAutomationProvider* provider,
+ IPC::Message* reply_message)
+ : provider_(provider),
+ reply_message_(reply_message) {}
+
+ void OnTemplateURLModelChanged();
+
+ private:
+ TestingAutomationProvider* provider_;
+ IPC::Message* reply_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomationProviderSearchEngineObserver);
+};
+
// Allows the automation provider to wait for history queries to finish.
class AutomationProviderHistoryObserver {
public:
@@ -636,8 +788,8 @@ class AutomationProviderImportSettingsObserver
};
// Allows automation provider to wait for getting passwords to finish.
-class AutomationProviderGetPasswordsObserver :
- public PasswordStoreConsumer {
+class AutomationProviderGetPasswordsObserver
+ : public PasswordStoreConsumer {
public:
AutomationProviderGetPasswordsObserver(
AutomationProvider* provider,
@@ -711,28 +863,25 @@ class SavePackageNotificationObserver : public NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(SavePackageNotificationObserver);
};
-// Allows the automation provider to wait for a given number of infobars.
-class WaitForInfobarCountObserver : public NotificationObserver {
+// Allows automation provider to wait until the autocomplete edit
+// has received focus
+class AutocompleteEditFocusedObserver : public NotificationObserver {
public:
- WaitForInfobarCountObserver(AutomationProvider* automation,
- IPC::Message* reply_message,
- TabContents* tab_contents,
- int count);
+ AutocompleteEditFocusedObserver(AutomationProvider* automation,
+ AutocompleteEditModel* autocomplete_edit,
+ IPC::Message* reply_message);
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
private:
- void ConditionMet();
-
NotificationRegistrar registrar_;
AutomationProvider* automation_;
IPC::Message* reply_message_;
- TabContents* tab_contents_;
- int count_;
+ AutocompleteEditModel* autocomplete_edit_model_;
- DISALLOW_COPY_AND_ASSIGN(WaitForInfobarCountObserver);
+ DISALLOW_COPY_AND_ASSIGN(AutocompleteEditFocusedObserver);
};
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_OBSERVERS_H_
diff --git a/chrome/browser/automation/automation_provider_views.cc b/chrome/browser/automation/automation_provider_views.cc
deleted file mode 100644
index f130079..0000000
--- a/chrome/browser/automation/automation_provider_views.cc
+++ /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.
-
-#include "chrome/browser/automation/automation_provider.h"
-
-#include "chrome/browser/automation/automation_browser_tracker.h"
-#include "chrome/browser/automation/automation_window_tracker.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/toolbar_view.h"
-#include "chrome/test/automation/automation_messages.h"
-#include "gfx/point.h"
-#include "views/controls/menu/menu_wrapper.h"
-#include "views/focus/focus_manager.h"
-#include "views/view.h"
-#include "views/widget/root_view.h"
-#include "views/widget/widget.h"
-
-void AutomationProvider::WindowGetViewBounds(int handle, int view_id,
- bool screen_coordinates,
- bool* success,
- gfx::Rect* bounds) {
- *success = false;
-
- if (window_tracker_->ContainsHandle(handle)) {
- gfx::NativeWindow window = window_tracker_->GetResource(handle);
- views::RootView* root_view = views::Widget::FindRootView(window);
- if (root_view) {
- views::View* view = root_view->GetViewByID(view_id);
- if (view) {
- *success = true;
- gfx::Point point;
- if (screen_coordinates)
- views::View::ConvertPointToScreen(view, &point);
- else
- views::View::ConvertPointToView(view, root_view, &point);
- *bounds = view->GetLocalBounds(false);
- bounds->set_origin(point);
- }
- }
- }
-}
-
-void AutomationProvider::GetFocusedViewID(int handle, int* view_id) {
- *view_id = -1;
- if (window_tracker_->ContainsHandle(handle)) {
- gfx::NativeWindow window = window_tracker_->GetResource(handle);
- views::FocusManager* focus_manager =
- views::FocusManager::GetFocusManagerForNativeWindow(window);
- DCHECK(focus_manager);
- views::View* focused_view = focus_manager->GetFocusedView();
- if (focused_view)
- *view_id = focused_view->GetID();
- }
-}
-
-// Helper class that waits until the focus has changed to a view other
-// than the one with the provided view id.
-class ViewFocusChangeWaiter : public views::FocusChangeListener {
- public:
- ViewFocusChangeWaiter(views::FocusManager* focus_manager,
- int previous_view_id,
- AutomationProvider* automation,
- IPC::Message* reply_message)
- : focus_manager_(focus_manager),
- previous_view_id_(previous_view_id),
- automation_(automation),
- reply_message_(reply_message),
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
- focus_manager_->AddFocusChangeListener(this);
- // Call the focus change notification once in case the focus has
- // already changed.
- FocusWillChange(NULL, focus_manager_->GetFocusedView());
- }
-
- ~ViewFocusChangeWaiter() {
- focus_manager_->RemoveFocusChangeListener(this);
- }
-
- // Inherited from FocusChangeListener
- virtual void FocusWillChange(views::View* focused_before,
- views::View* focused_now) {
- // This listener is called before focus actually changes. Post a task
- // that will get run after focus changes.
- MessageLoop::current()->PostTask(
- FROM_HERE,
- method_factory_.NewRunnableMethod(
- &ViewFocusChangeWaiter::FocusChanged,
- focused_before,
- focused_now));
- }
-
- private:
- void FocusChanged(views::View* focused_before,
- views::View* focused_now) {
- if (focused_now && focused_now->GetID() != previous_view_id_) {
- AutomationMsg_WaitForFocusedViewIDToChange::WriteReplyParams(
- reply_message_, true, focused_now->GetID());
-
- automation_->Send(reply_message_);
- delete this;
- }
- }
-
- views::FocusManager* focus_manager_;
- int previous_view_id_;
- AutomationProvider* automation_;
- IPC::Message* reply_message_;
- ScopedRunnableMethodFactory<ViewFocusChangeWaiter> method_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ViewFocusChangeWaiter);
-};
-
-void AutomationProvider::WaitForFocusedViewIDToChange(
- int handle, int previous_view_id, IPC::Message* reply_message) {
- if (!window_tracker_->ContainsHandle(handle))
- return;
- gfx::NativeWindow window = window_tracker_->GetResource(handle);
- views::FocusManager* focus_manager =
- views::FocusManager::GetFocusManagerForNativeWindow(window);
-
- // The waiter will respond to the IPC and delete itself when done.
- new ViewFocusChangeWaiter(focus_manager,
- previous_view_id,
- this,
- reply_message);
-}
-
-class PopupMenuWaiter : public views::MenuListener {
- public:
- PopupMenuWaiter(ToolbarView* toolbar_view,
- AutomationProvider* automation)
- : toolbar_view_(toolbar_view),
- automation_(automation),
- reply_message_(NULL) {
- toolbar_view_->AddMenuListener(this);
- }
-
- // Implementation of views::MenuListener
- virtual void OnMenuOpened() {
- toolbar_view_->RemoveMenuListener(this);
- automation_->popup_menu_opened_ = true;
- automation_->popup_menu_waiter_ = NULL;
- if (reply_message_) {
- AutomationMsg_WaitForPopupMenuToOpen::WriteReplyParams(
- reply_message_, true);
- automation_->Send(reply_message_);
- }
- delete this;
- }
-
- void set_reply_message(IPC::Message* reply_message) {
- reply_message_ = reply_message;
- }
-
- private:
- ToolbarView* toolbar_view_;
- AutomationProvider* automation_;
- IPC::Message* reply_message_;
-
- DISALLOW_COPY_AND_ASSIGN(PopupMenuWaiter);
-};
-
-void AutomationProvider::StartTrackingPopupMenus(
- int browser_handle, bool* success) {
- if (browser_tracker_->ContainsHandle(browser_handle)) {
- Browser* browser = browser_tracker_->GetResource(browser_handle);
- BrowserView* browser_view = reinterpret_cast<BrowserView*>(
- browser->window());
- ToolbarView* toolbar_view = browser_view->GetToolbarView();
- popup_menu_opened_ = false;
- popup_menu_waiter_ = new PopupMenuWaiter(toolbar_view, this);
- *success = true;
- }
-}
-
-void AutomationProvider::WaitForPopupMenuToOpen(IPC::Message* reply_message) {
- // See if the menu already opened and return true if so.
- if (popup_menu_opened_) {
- AutomationMsg_WaitForPopupMenuToOpen::WriteReplyParams(
- reply_message, true);
- Send(reply_message);
- return;
- }
-
- // Otherwise, register this reply message with the waiter,
- // which will handle responding to this IPC when the popup
- // menu opens.
- popup_menu_waiter_->set_reply_message(reply_message);
-}
diff --git a/chrome/browser/automation/automation_provider_win.cc b/chrome/browser/automation/automation_provider_win.cc
index 51959bd..98ee218 100644
--- a/chrome/browser/automation/automation_provider_win.cc
+++ b/chrome/browser/automation/automation_provider_win.cc
@@ -1,11 +1,13 @@
-// 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.
#include "chrome/browser/automation/automation_provider.h"
+#include "app/keyboard_codes.h"
#include "base/json/json_reader.h"
-#include "base/keyboard_codes.h"
+#include "base/trace_event.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_extension_function.h"
#include "chrome/browser/automation/automation_tab_tracker.h"
@@ -20,7 +22,9 @@
#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"
+#include "chrome/common/page_zoom.h"
#include "chrome/test/automation/automation_messages.h"
+#include "views/focus/accelerator_handler.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_win.h"
#include "views/window/window.h"
@@ -70,22 +74,6 @@ BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM l_param) {
return TRUE;
}
-void AutomationProvider::GetActiveWindow(int* handle) {
- HWND window = GetForegroundWindow();
-
- // Let's make sure this window belongs to our process.
- if (EnumThreadWindows(::GetCurrentThreadId(),
- EnumThreadWndProc,
- reinterpret_cast<LPARAM>(window))) {
- // We enumerated all the windows and did not find the foreground window,
- // it is not our window, ignore it.
- *handle = 0;
- return;
- }
-
- *handle = window_tracker_->Add(window);
-}
-
// This task enqueues a mouse event on the event loop, so that the view
// that it's being sent to can do the requisite post-processing.
class MouseEventTask : public Task {
@@ -212,15 +200,23 @@ void AutomationProvider::WindowSimulateDrag(int handle,
MoveMouse(end);
if (press_escape_en_route) {
- // Press Escape.
- ui_controls::SendKeyPress(window, base::VKEY_ESCAPE,
- ((flags & views::Event::EF_CONTROL_DOWN)
- == views::Event::EF_CONTROL_DOWN),
- ((flags & views::Event::EF_SHIFT_DOWN) ==
- views::Event::EF_SHIFT_DOWN),
- ((flags & views::Event::EF_ALT_DOWN) ==
- views::Event::EF_ALT_DOWN),
- false);
+ // Press Escape, making sure we wait until chrome processes the escape.
+ // TODO(phajdan.jr): make this use ui_test_utils::SendKeyPressSync.
+ ui_controls::SendKeyPressNotifyWhenDone(
+ window, app::VKEY_ESCAPE,
+ ((flags & views::Event::EF_CONTROL_DOWN) ==
+ views::Event::EF_CONTROL_DOWN),
+ ((flags & views::Event::EF_SHIFT_DOWN) ==
+ views::Event::EF_SHIFT_DOWN),
+ ((flags & views::Event::EF_ALT_DOWN) == views::Event::EF_ALT_DOWN),
+ false,
+ new MessageLoop::QuitTask());
+ MessageLoopForUI* loop = MessageLoopForUI::current();
+ bool did_allow_task_nesting = loop->NestableTasksAllowed();
+ loop->SetNestableTasksAllowed(true);
+ views::AcceleratorHandler handler;
+ loop->Run(&handler);
+ loop->SetNestableTasksAllowed(did_allow_task_nesting);
}
SendMessage(top_level_hwnd, up_message, wparam_flags,
MAKELPARAM(end.x, end.y));
@@ -233,60 +229,6 @@ void AutomationProvider::WindowSimulateDrag(int handle,
}
}
-void AutomationProvider::GetWindowBounds(int handle, gfx::Rect* bounds,
- bool* success) {
- *success = false;
- HWND hwnd = window_tracker_->GetResource(handle);
- if (hwnd) {
- *success = true;
- WINDOWPLACEMENT window_placement;
- GetWindowPlacement(hwnd, &window_placement);
- *bounds = window_placement.rcNormalPosition;
- }
-}
-
-void AutomationProvider::SetWindowBounds(int handle, const gfx::Rect& bounds,
- bool* success) {
- *success = false;
- if (window_tracker_->ContainsHandle(handle)) {
- HWND hwnd = window_tracker_->GetResource(handle);
- if (::MoveWindow(hwnd, bounds.x(), bounds.y(), bounds.width(),
- bounds.height(), true)) {
- *success = true;
- }
- }
-}
-
-void AutomationProvider::SetWindowVisible(int handle, bool visible,
- bool* result) {
- if (window_tracker_->ContainsHandle(handle)) {
- HWND hwnd = window_tracker_->GetResource(handle);
- ::ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
- *result = true;
- } else {
- *result = false;
- }
-}
-
-void AutomationProvider::ActivateWindow(int handle) {
- if (window_tracker_->ContainsHandle(handle)) {
- ::SetActiveWindow(window_tracker_->GetResource(handle));
- }
-}
-
-void AutomationProvider::IsWindowMaximized(int handle, bool* is_maximized,
- bool* success) {
- *success = false;
-
- HWND hwnd = window_tracker_->GetResource(handle);
- if (hwnd) {
- *success = true;
- WINDOWPLACEMENT window_placement;
- GetWindowPlacement(hwnd, &window_placement);
- *is_maximized = (window_placement.showCmd == SW_MAXIMIZE);
- }
-}
-
void AutomationProvider::GetTabHWND(int handle, HWND* tab_hwnd) {
*tab_hwnd = NULL;
@@ -300,6 +242,8 @@ void AutomationProvider::CreateExternalTab(
const IPC::ExternalTabSettings& settings,
gfx::NativeWindow* tab_container_window, gfx::NativeWindow* tab_window,
int* tab_handle) {
+ TRACE_EVENT_BEGIN("AutomationProvider::CreateExternalTab", 0, "");
+
*tab_handle = 0;
*tab_container_window = NULL;
*tab_window = NULL;
@@ -324,6 +268,8 @@ void AutomationProvider::CreateExternalTab(
} else {
external_tab_container->Uninitialize();
}
+
+ TRACE_EVENT_END("AutomationProvider::CreateExternalTab", 0, "");
}
bool AutomationProvider::AddExternalTab(ExternalTabContainer* external_tab) {
@@ -432,6 +378,8 @@ void AutomationProvider::ConnectExternalTab(
gfx::NativeWindow* tab_container_window,
gfx::NativeWindow* tab_window,
int* tab_handle) {
+ TRACE_EVENT_BEGIN("AutomationProvider::ConnectExternalTab", 0, "");
+
*tab_handle = 0;
*tab_container_window = NULL;
*tab_window = NULL;
@@ -454,16 +402,8 @@ void AutomationProvider::ConnectExternalTab(
} else {
external_tab_container->Uninitialize();
}
-}
-
-void AutomationProvider::TerminateSession(int handle, bool* success) {
- *success = false;
- if (browser_tracker_->ContainsHandle(handle)) {
- Browser* browser = browser_tracker_->GetResource(handle);
- HWND window = browser->window()->GetNativeHandle();
- *success = (::PostMessageW(window, WM_ENDSESSION, 0, 0) == TRUE);
- }
+ TRACE_EVENT_END("AutomationProvider::ConnectExternalTab", 0, "");
}
void AutomationProvider::SetEnableExtensionAutomation(
@@ -491,14 +431,6 @@ void AutomationProvider::OnBrowserMoved(int tab_handle) {
}
}
-void AutomationProvider::GetWindowTitle(int handle, string16* text) {
- gfx::NativeWindow window = window_tracker_->GetResource(handle);
- std::wstring result;
- int length = ::GetWindowTextLength(window) + 1;
- ::GetWindowText(window, WriteInto(&result, length), length);
- text->assign(WideToUTF16(result));
-}
-
void AutomationProvider::OnMessageFromExternalHost(int handle,
const std::string& message,
const std::string& origin,
@@ -564,7 +496,7 @@ bool AutomationProvider::InterceptBrowserEventMessageFromExternalHost(
if (profile()->GetExtensionMessageService()) {
profile()->GetExtensionMessageService()->DispatchEventToRenderers(
- event_name, json_args, profile()->IsOffTheRecord(), GURL());
+ event_name, json_args, profile(), GURL());
}
return true;
@@ -595,11 +527,19 @@ void AutomationProvider::NavigateExternalTabAtIndex(
}
void AutomationProvider::OnRunUnloadHandlers(
- int handle, gfx::NativeWindow notification_window,
- int notification_message) {
+ int handle, IPC::Message* reply_message) {
ExternalTabContainer* external_tab = GetExternalTabForHandle(handle);
if (external_tab) {
- external_tab->RunUnloadHandlers(notification_window, notification_message);
+ external_tab->RunUnloadHandlers(reply_message);
}
}
+void AutomationProvider::OnSetZoomLevel(int handle, int zoom_level) {
+ if (tab_tracker_->ContainsHandle(handle)) {
+ NavigationController* tab = tab_tracker_->GetResource(handle);
+ if (tab->tab_contents() && tab->tab_contents()->render_view_host()) {
+ tab->tab_contents()->render_view_host()->Zoom(
+ static_cast<PageZoom::Function>(zoom_level));
+ }
+ }
+}
diff --git a/chrome/browser/automation/automation_resource_message_filter.cc b/chrome/browser/automation/automation_resource_message_filter.cc
index 68fc346..c9237c8 100644
--- a/chrome/browser/automation/automation_resource_message_filter.cc
+++ b/chrome/browser/automation/automation_resource_message_filter.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.
@@ -13,21 +13,83 @@
#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/common/chrome_paths.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/test/automation/automation_messages.h"
#include "googleurl/src/gurl.h"
-#include "net/base/cookie_store.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_filter.h"
-AutomationResourceMessageFilter::RenderViewMap
- AutomationResourceMessageFilter::filtered_render_views_;
+base::LazyInstance<AutomationResourceMessageFilter::RenderViewMap>
+ AutomationResourceMessageFilter::filtered_render_views_(
+ base::LINKER_INITIALIZED);
+
+base::LazyInstance<AutomationResourceMessageFilter::CompletionCallbackMap>
+ AutomationResourceMessageFilter::completion_callback_map_(
+ base::LINKER_INITIALIZED);
int AutomationResourceMessageFilter::unique_request_id_ = 1;
+int AutomationResourceMessageFilter::next_completion_callback_id_ = 0;
+
+// CookieStore specialization to enable fetching and setting cookies over the
+// automation channel. This cookie store is transient i.e. it maintains cookies
+// for the duration of the current request to set or get cookies from the
+// renderer.
+class AutomationCookieStore : public net::CookieStore {
+ public:
+ AutomationCookieStore(AutomationResourceMessageFilter* automation_client,
+ int tab_handle)
+ : automation_client_(automation_client),
+ tab_handle_(tab_handle) {
+ }
+
+ virtual ~AutomationCookieStore() {
+ DLOG(INFO) << "In " << __FUNCTION__;
+ }
+
+ // CookieStore implementation.
+ virtual bool SetCookieWithOptions(const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options) {
+ // The cookie_string_ is available only once, i.e. once it is read by
+ // it is invalidated.
+ cookie_string_ = cookie_line;
+ return true;
+ }
+
+ virtual std::string GetCookiesWithOptions(const GURL& url,
+ const net::CookieOptions& options) {
+ return cookie_string_;
+ }
+
+ virtual void DeleteCookie(const GURL& url,
+ const std::string& cookie_name) {
+ NOTREACHED() << "Should not get called for an automation profile";
+ }
+
+ virtual net::CookieMonster* GetCookieMonster() {
+ NOTREACHED() << "Should not get called for an automation profile";
+ return NULL;
+ }
+
+ protected:
+ scoped_refptr<AutomationResourceMessageFilter> automation_client_;
+ int tab_handle_;
+ std::string cookie_string_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutomationCookieStore);
+};
+
AutomationResourceMessageFilter::AutomationResourceMessageFilter()
: channel_(NULL) {
+ // Ensure that an instance of the callback map is created.
+ completion_callback_map_.Get();
+ // Ensure that an instance of the render view map is created.
+ filtered_render_views_.Get();
+
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableFunction(
@@ -58,11 +120,11 @@ void AutomationResourceMessageFilter::OnChannelClosing() {
// Only erase RenderViews which are associated with this
// AutomationResourceMessageFilter instance.
- RenderViewMap::iterator index = filtered_render_views_.begin();
- while (index != filtered_render_views_.end()) {
+ RenderViewMap::iterator index = filtered_render_views_.Get().begin();
+ while (index != filtered_render_views_.Get().end()) {
const AutomationDetails& details = (*index).second;
if (details.filter.get() == this) {
- filtered_render_views_.erase(index++);
+ filtered_render_views_.Get().erase(index++);
} else {
index++;
}
@@ -147,7 +209,6 @@ void AutomationResourceMessageFilter::UnRegisterRequest(
DCHECK(ContainsKey(pending_request_map_, job->id()));
pending_request_map_.erase(job->id());
} else {
- DCHECK(ContainsKey(request_map_, job->id()));
request_map_.erase(job->id());
}
}
@@ -198,24 +259,32 @@ void AutomationResourceMessageFilter::RegisterRenderViewInIOThread(
int renderer_pid, int renderer_id,
int tab_handle, AutomationResourceMessageFilter* filter,
bool pending_view) {
+ RendererId renderer_key(renderer_pid, renderer_id);
+
+ scoped_refptr<net::CookieStore> cookie_store =
+ new AutomationCookieStore(filter, tab_handle);
+
RenderViewMap::iterator automation_details_iter(
- filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));
- if (automation_details_iter != filtered_render_views_.end()) {
+ filtered_render_views_.Get().find(renderer_key));
+ if (automation_details_iter != filtered_render_views_.Get().end()) {
DCHECK(automation_details_iter->second.ref_count > 0);
automation_details_iter->second.ref_count++;
} else {
- filtered_render_views_[RendererId(renderer_pid, renderer_id)] =
+ filtered_render_views_.Get()[renderer_key] =
AutomationDetails(tab_handle, filter, pending_view);
}
+
+ filtered_render_views_.Get()[renderer_key].set_cookie_store(cookie_store);
}
// static
void AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread(
int renderer_pid, int renderer_id) {
RenderViewMap::iterator automation_details_iter(
- filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));
+ filtered_render_views_.Get().find(RendererId(renderer_pid,
+ renderer_id)));
- if (automation_details_iter == filtered_render_views_.end()) {
+ if (automation_details_iter == filtered_render_views_.Get().end()) {
LOG(INFO) << "UnRegisterRenderViewInIOThread: already unregistered";
return;
}
@@ -223,7 +292,7 @@ void AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread(
automation_details_iter->second.ref_count--;
if (automation_details_iter->second.ref_count <= 0) {
- filtered_render_views_.erase(RendererId(renderer_pid, renderer_id));
+ filtered_render_views_.Get().erase(RendererId(renderer_pid, renderer_id));
}
}
@@ -233,10 +302,12 @@ bool AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread(
AutomationResourceMessageFilter* filter) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ RendererId renderer_key(renderer_pid, renderer_id);
+
RenderViewMap::iterator automation_details_iter(
- filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));
+ filtered_render_views_.Get().find(renderer_key));
- if (automation_details_iter == filtered_render_views_.end()) {
+ if (automation_details_iter == filtered_render_views_.Get().end()) {
NOTREACHED() << "Failed to find pending view for renderer pid:"
<< renderer_pid
<< ", render view id:"
@@ -246,13 +317,18 @@ bool AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread(
DCHECK(automation_details_iter->second.is_pending_render_view);
+ scoped_refptr<net::CookieStore> cookie_store =
+ new AutomationCookieStore(filter, tab_handle);
+
AutomationResourceMessageFilter* old_filter =
automation_details_iter->second.filter;
DCHECK(old_filter != NULL);
- filtered_render_views_[RendererId(renderer_pid, renderer_id)] =
+ filtered_render_views_.Get()[renderer_key] =
AutomationDetails(tab_handle, filter, false);
+ filtered_render_views_.Get()[renderer_key].set_cookie_store(cookie_store);
+
ResumeJobsForPendingView(tab_handle, old_filter, filter);
return true;
}
@@ -260,9 +336,9 @@ bool AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread(
bool AutomationResourceMessageFilter::LookupRegisteredRenderView(
int renderer_pid, int renderer_id, AutomationDetails* details) {
bool found = false;
- RenderViewMap::iterator it = filtered_render_views_.find(RendererId(
+ RenderViewMap::iterator it = filtered_render_views_.Get().find(RendererId(
renderer_pid, renderer_id));
- if (it != filtered_render_views_.end()) {
+ if (it != filtered_render_views_.Get().end()) {
found = true;
if (details)
*details = it->second;
@@ -318,54 +394,115 @@ void AutomationResourceMessageFilter::OnRecordHistograms(
}
}
-void AutomationResourceMessageFilter::GetCookiesForUrl(
- int tab_handle, const GURL& url, net::CompletionCallback* callback,
- net::CookieStore* cookie_store) {
- DCHECK(callback != NULL);
- DCHECK(cookie_store != NULL);
+bool AutomationResourceMessageFilter::GetCookiesForUrl(
+ const GURL& url, net::CompletionCallback* callback) {
+ GetCookiesCompletion* get_cookies_callback =
+ static_cast<GetCookiesCompletion*>(callback);
+
+ RendererId renderer_key(get_cookies_callback->render_process_id(),
+ get_cookies_callback->render_view_id());
+
+ RenderViewMap::iterator automation_details_iter(
+ filtered_render_views_.Get().find(renderer_key));
+
+ if (automation_details_iter == filtered_render_views_.Get().end()) {
+ return false;
+ }
+
+ DCHECK(automation_details_iter->second.filter != NULL);
+ DCHECK(automation_details_iter->second.cookie_store_.get() != NULL);
int completion_callback_id = GetNextCompletionCallbackId();
- DCHECK(!ContainsKey(completion_callback_map_, completion_callback_id));
+ DCHECK(!ContainsKey(completion_callback_map_.Get(), completion_callback_id));
CookieCompletionInfo cookie_info;
cookie_info.completion_callback = callback;
- cookie_info.cookie_store = cookie_store;
+ cookie_info.cookie_store = automation_details_iter->second.cookie_store_;
+
+ completion_callback_map_.Get()[completion_callback_id] = cookie_info;
- completion_callback_map_[completion_callback_id] = cookie_info;
+ DCHECK(automation_details_iter->second.filter != NULL);
- Send(new AutomationMsg_GetCookiesFromHost(0, tab_handle, url,
- completion_callback_id));
+ if (automation_details_iter->second.filter) {
+ automation_details_iter->second.filter->Send(
+ new AutomationMsg_GetCookiesFromHost(
+ 0, automation_details_iter->second.tab_handle, url,
+ completion_callback_id));
+ }
+ return true;
}
void AutomationResourceMessageFilter::OnGetCookiesHostResponse(
int tab_handle, bool success, const GURL& url, const std::string& cookies,
int cookie_id) {
CompletionCallbackMap::iterator index =
- completion_callback_map_.find(cookie_id);
- if (index != completion_callback_map_.end()) {
+ completion_callback_map_.Get().find(cookie_id);
+ if (index != completion_callback_map_.Get().end()) {
net::CompletionCallback* callback = index->second.completion_callback;
+
scoped_refptr<net::CookieStore> cookie_store = index->second.cookie_store;
DCHECK(callback != NULL);
DCHECK(cookie_store.get() != NULL);
- completion_callback_map_.erase(index);
-
- // Set the cookie in the cookie store so that the callback can read it.
- cookie_store->SetCookieWithOptions(url, cookies, net::CookieOptions());
-
- Tuple1<int> params;
- params.a = success ? net::OK : net::ERR_ACCESS_DENIED;
- callback->RunWithParams(params);
+ completion_callback_map_.Get().erase(index);
- // The cookie for this URL is only valid until it is read by the callback.
- cookie_store->SetCookieWithOptions(url, "", net::CookieOptions());
+ OnGetCookiesHostResponseInternal(tab_handle, success, url, cookies,
+ callback, cookie_store.get());
} else {
NOTREACHED() << "Received invalid completion callback id:"
<< cookie_id;
}
}
+void AutomationResourceMessageFilter::OnGetCookiesHostResponseInternal(
+ int tab_handle, bool success, const GURL& url, const std::string& cookies,
+ net::CompletionCallback* callback, net::CookieStore* cookie_store) {
+ DCHECK(callback);
+ DCHECK(cookie_store);
+
+ GetCookiesCompletion* get_cookies_callback =
+ static_cast<GetCookiesCompletion*>(callback);
+
+ get_cookies_callback->set_cookie_store(cookie_store);
+
+ // Set the cookie in the cookie store so that the callback can read it.
+ cookie_store->SetCookieWithOptions(url, cookies, net::CookieOptions());
+
+ Tuple1<int> params;
+ params.a = success ? net::OK : net::ERR_ACCESS_DENIED;
+ callback->RunWithParams(params);
+
+ // The cookie for this URL is only valid until it is read by the callback.
+ cookie_store->SetCookieWithOptions(url, "", net::CookieOptions());
+}
+
+bool AutomationResourceMessageFilter::SetCookiesForUrl(
+ const GURL& url, const std::string& cookie_line,
+ net::CompletionCallback* callback) {
+ SetCookieCompletion* set_cookies_callback =
+ static_cast<SetCookieCompletion*>(callback);
+
+ RenderViewMap::iterator automation_details_iter(
+ filtered_render_views_.Get().find(RendererId(
+ set_cookies_callback->render_process_id(),
+ set_cookies_callback->render_view_id())));
+
+ if (automation_details_iter == filtered_render_views_.Get().end()) {
+ return false;
+ }
+
+ DCHECK(automation_details_iter->second.filter != NULL);
+
+ 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));
+ }
+
+ return true;
+}
+
// static
void AutomationResourceMessageFilter::ResumeJobsForPendingView(
int tab_handle,
diff --git a/chrome/browser/automation/automation_resource_message_filter.h b/chrome/browser/automation/automation_resource_message_filter.h
index 55b9bf2..c245f28 100644
--- a/chrome/browser/automation/automation_resource_message_filter.h
+++ b/chrome/browser/automation/automation_resource_message_filter.h
@@ -4,14 +4,17 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_MESSAGE_FILTER_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_MESSAGE_FILTER_H_
+#pragma once
#include <map>
#include "base/atomicops.h"
+#include "base/lazy_instance.h"
#include "base/lock.h"
#include "base/platform_thread.h"
#include "ipc/ipc_channel_proxy.h"
#include "net/base/completion_callback.h"
+#include "net/base/cookie_store.h"
class URLRequestAutomationJob;
class GURL;
@@ -39,12 +42,23 @@ class AutomationResourceMessageFilter
is_pending_render_view(pending_view) {
}
+ void set_cookie_store(net::CookieStore* cookie_store) {
+ cookie_store_ = cookie_store;
+ }
+
+ net::CookieStore* cookie_store() {
+ return cookie_store_.get();
+ }
+
int tab_handle;
int ref_count;
scoped_refptr<AutomationResourceMessageFilter> filter;
// Indicates whether network requests issued by this render view need to
// be executed later.
bool is_pending_render_view;
+
+ // The cookie store associated with this render view.
+ scoped_refptr<net::CookieStore> cookie_store_;
};
// Create the filter.
@@ -99,9 +113,13 @@ class AutomationResourceMessageFilter
// Retrieves cookies for the url passed in from the external host. The
// callback passed in is notified on success or failure asynchronously.
- void GetCookiesForUrl(int tab_handle, const GURL& url,
- net::CompletionCallback* callback,
- net::CookieStore* cookie_store);
+ // Returns true on success.
+ static bool GetCookiesForUrl(const GURL& url,
+ net::CompletionCallback* callback);
+
+ // Sets cookies on the URL in the external host. Returns true on success.
+ static bool SetCookiesForUrl(const GURL& url, const std::string& cookie_line,
+ net::CompletionCallback* callback);
// This function gets invoked when we receive a response from the external
// host for the cookie request sent in GetCookiesForUrl above. It sets the
@@ -126,6 +144,13 @@ class AutomationResourceMessageFilter
int renderer_pid, int renderer_id, int tab_handle,
AutomationResourceMessageFilter* filter);
+ // Helper function to execute the GetCookies completion callback with the
+ // response for the GetCookies request from the renderer.
+ static void OnGetCookiesHostResponseInternal(
+ int tab_handle, bool success, const GURL& url,
+ const std::string& cookies, net::CompletionCallback* callback,
+ net::CookieStore* cookie_store);
+
private:
void OnSetFilteredInet(bool enable);
void OnGetFilteredInetHitCount(int* hit_count);
@@ -138,7 +163,7 @@ class AutomationResourceMessageFilter
AutomationResourceMessageFilter* old_filter,
AutomationResourceMessageFilter* new_filter);
- int GetNextCompletionCallbackId() {
+ static int GetNextCompletionCallbackId() {
return ++next_completion_callback_id_;
}
@@ -174,7 +199,7 @@ class AutomationResourceMessageFilter
RequestMap pending_request_map_;
// Map of render views interested in diverting url requests over automation.
- static RenderViewMap filtered_render_views_;
+ static base::LazyInstance<RenderViewMap> filtered_render_views_;
// Contains information used for completing the request to read cookies from
// the host coming in from the renderer.
@@ -189,11 +214,11 @@ class AutomationResourceMessageFilter
// cookies from the host and is removed when we receive a response from the
// host. Please see the OnGetCookiesHostResponse function.
typedef std::map<int, CookieCompletionInfo> CompletionCallbackMap;
- CompletionCallbackMap completion_callback_map_;
+ static base::LazyInstance<CompletionCallbackMap> completion_callback_map_;
// Contains the id of the next completion callback. This is passed to the the
// external host as a cookie referring to the completion callback.
- int next_completion_callback_id_;
+ static int next_completion_callback_id_;
DISALLOW_COPY_AND_ASSIGN(AutomationResourceMessageFilter);
};
diff --git a/chrome/browser/automation/automation_resource_routing_delegate.h b/chrome/browser/automation/automation_resource_routing_delegate.h
index 2438e4d..7f67a99 100644
--- a/chrome/browser/automation/automation_resource_routing_delegate.h
+++ b/chrome/browser/automation/automation_resource_routing_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_ROUTING_DELEGATE_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_ROUTING_DELEGATE_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/automation/automation_resource_tracker.cc b/chrome/browser/automation/automation_resource_tracker.cc
index de20ba1..c233b41 100644
--- a/chrome/browser/automation/automation_resource_tracker.cc
+++ b/chrome/browser/automation/automation_resource_tracker.cc
@@ -7,6 +7,14 @@
#include "chrome/common/notification_service.h"
#include "chrome/test/automation/automation_messages.h"
+AutomationResourceTrackerImpl::AutomationResourceTrackerImpl(
+ IPC::Message::Sender* sender)
+ : sender_(sender) {
+}
+
+AutomationResourceTrackerImpl::~AutomationResourceTrackerImpl() {
+}
+
int AutomationResourceTrackerImpl::AddImpl(void* resource) {
if (ContainsResourceImpl(resource))
return resource_to_handle_[resource];
diff --git a/chrome/browser/automation/automation_resource_tracker.h b/chrome/browser/automation/automation_resource_tracker.h
index 58703e7..671f72b 100644
--- a/chrome/browser/automation/automation_resource_tracker.h
+++ b/chrome/browser/automation/automation_resource_tracker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_TRACKER_H__
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_RESOURCE_TRACKER_H__
+#pragma once
#include <map>
@@ -31,10 +32,8 @@ struct AutomationResourceTraits<T*> {
// of AutomationResourceTracker to live in a .cc file.
class AutomationResourceTrackerImpl {
public:
- explicit AutomationResourceTrackerImpl(IPC::Message::Sender* sender)
- : sender_(sender) {}
-
- virtual ~AutomationResourceTrackerImpl() {}
+ explicit AutomationResourceTrackerImpl(IPC::Message::Sender* sender);
+ virtual ~AutomationResourceTrackerImpl();
// These need to be implemented in AutomationResourceTracker,
// since it needs to call the subclass's type-specific notification
diff --git a/chrome/browser/automation/automation_tab_tracker.h b/chrome/browser/automation/automation_tab_tracker.h
index 02b40be..e894f0d 100644
--- a/chrome/browser/automation/automation_tab_tracker.h
+++ b/chrome/browser/automation/automation_tab_tracker.h
@@ -4,83 +4,30 @@
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_TAB_TRACKER_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_TAB_TRACKER_H_
+#pragma once
#include <map>
#include "base/time.h"
#include "chrome/browser/automation/automation_resource_tracker.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_type.h"
+
+class NavigationController;
+class NotificationType;
class AutomationTabTracker
: public AutomationResourceTracker<NavigationController*> {
public:
- explicit AutomationTabTracker(IPC::Message::Sender* automation)
- : AutomationResourceTracker<NavigationController*>(automation) {}
-
- virtual ~AutomationTabTracker() {
- }
-
- virtual void AddObserver(NavigationController* resource) {
- // This tab could either be a regular tab or an external tab
- // Register for both notifications.
- registrar_.Add(this, NotificationType::TAB_CLOSING,
- Source<NavigationController>(resource));
- registrar_.Add(this, NotificationType::EXTERNAL_TAB_CLOSED,
- Source<NavigationController>(resource));
- // We also want to know about navigations so we can keep track of the last
- // navigation time.
- registrar_.Add(this, NotificationType::LOAD_STOP,
- Source<NavigationController>(resource));
- }
+ explicit AutomationTabTracker(IPC::Message::Sender* automation);
+ virtual ~AutomationTabTracker();
- virtual void RemoveObserver(NavigationController* resource) {
- registrar_.Remove(this, NotificationType::TAB_CLOSING,
- Source<NavigationController>(resource));
- registrar_.Remove(this, NotificationType::EXTERNAL_TAB_CLOSED,
- Source<NavigationController>(resource));
- registrar_.Remove(this, NotificationType::LOAD_STOP,
- Source<NavigationController>(resource));
- }
+ virtual void AddObserver(NavigationController* resource);
+ virtual void RemoveObserver(NavigationController* resource);
virtual void Observe(NotificationType type,
const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::LOAD_STOP:
- last_navigation_times_[Source<NavigationController>(source).ptr()] =
- base::Time::Now();
- return;
- case NotificationType::EXTERNAL_TAB_CLOSED:
- case NotificationType::TAB_CLOSING:
- {
- std::map<NavigationController*, base::Time>::iterator iter =
- last_navigation_times_.find(
- Source<NavigationController>(source).ptr());
- if (iter != last_navigation_times_.end())
- last_navigation_times_.erase(iter);
- }
- break;
- default:
- NOTREACHED();
- }
- AutomationResourceTracker<NavigationController*>::Observe(type, source,
- details);
- }
+ const NotificationDetails& details);
- base::Time GetLastNavigationTime(int handle) {
- if (ContainsHandle(handle)) {
- NavigationController* controller = GetResource(handle);
- if (controller) {
- std::map<NavigationController*, base::Time>::const_iterator iter =
- last_navigation_times_.find(controller);
- if (iter != last_navigation_times_.end())
- return iter->second;
- }
- }
- return base::Time();
- }
+ base::Time GetLastNavigationTime(int handle);
private:
// Last time a navigation occurred.
diff --git a/chrome/browser/automation/automation_window_tracker.h b/chrome/browser/automation/automation_window_tracker.h
index 02cfeea..7483f1d 100644
--- a/chrome/browser/automation/automation_window_tracker.h
+++ b/chrome/browser/automation/automation_window_tracker.h
@@ -1,32 +1,23 @@
-// 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.
#ifndef CHROME_BROWSER_AUTOMATION_AUTOMATION_WINDOW_TRACKER_H_
#define CHROME_BROWSER_AUTOMATION_AUTOMATION_WINDOW_TRACKER_H_
+#pragma once
#include "build/build_config.h"
#include "chrome/browser/automation/automation_resource_tracker.h"
-#include "chrome/common/native_window_notification_source.h"
#include "gfx/native_widget_types.h"
class AutomationWindowTracker
: public AutomationResourceTracker<gfx::NativeWindow> {
public:
- explicit AutomationWindowTracker(IPC::Message::Sender* automation)
- : AutomationResourceTracker<gfx::NativeWindow>(automation) { }
- virtual ~AutomationWindowTracker() {
- }
+ explicit AutomationWindowTracker(IPC::Message::Sender* automation);
+ virtual ~AutomationWindowTracker();
- virtual void AddObserver(gfx::NativeWindow resource) {
- registrar_.Add(this, NotificationType::WINDOW_CLOSED,
- Source<gfx::NativeWindow>(resource));
- }
-
- virtual void RemoveObserver(gfx::NativeWindow resource) {
- registrar_.Remove(this, NotificationType::WINDOW_CLOSED,
- Source<gfx::NativeWindow>(resource));
- }
+ virtual void AddObserver(gfx::NativeWindow resource);
+ virtual void RemoveObserver(gfx::NativeWindow resource);
};
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_WINDOW_TRACKER_H_
diff --git a/chrome/browser/automation/chrome_frame_automation_provider.cc b/chrome/browser/automation/chrome_frame_automation_provider.cc
index 52f8ded..b3ea659 100644
--- a/chrome/browser/automation/chrome_frame_automation_provider.cc
+++ b/chrome/browser/automation/chrome_frame_automation_provider.cc
@@ -65,7 +65,8 @@ bool ChromeFrameAutomationProvider::IsValidMessage(uint32 type) {
case AutomationMsg_SaveAsAsync::ID:
case AutomationMsg_RemoveBrowsingData::ID:
case AutomationMsg_OverrideEncoding::ID:
- case AutomationMsg_RunUnloadHandlers::ID: {
+ case AutomationMsg_RunUnloadHandlers::ID:
+ case AutomationMsg_SetZoomLevel::ID: {
is_valid_message = true;
break;
}
diff --git a/chrome/browser/automation/chrome_frame_automation_provider.h b/chrome/browser/automation/chrome_frame_automation_provider.h
index 0ab6a8f..fad6bd8 100644
--- a/chrome/browser/automation/chrome_frame_automation_provider.h
+++ b/chrome/browser/automation/chrome_frame_automation_provider.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.
@@ -10,9 +10,9 @@
#ifndef CHROME_BROWSER_AUTOMATION_CHROME_FRAME_AUTOMATION_PROVIDER_H_
#define CHROME_BROWSER_AUTOMATION_CHROME_FRAME_AUTOMATION_PROVIDER_H_
+#pragma once
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/automation/automation_provider.h"
class Profile;
diff --git a/chrome/browser/automation/extension_automation_constants.cc b/chrome/browser/automation/extension_automation_constants.cc
index c513945..c4e6fce 100644
--- a/chrome/browser/automation/extension_automation_constants.cc
+++ b/chrome/browser/automation/extension_automation_constants.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,22 +7,22 @@
namespace extension_automation_constants {
const char kAutomationOrigin[] = "__priv_xtapi";
-const wchar_t kAutomationRequestIdKey[] = L"rqid";
+const char kAutomationRequestIdKey[] = "rqid";
-const wchar_t kAutomationHasCallbackKey[] = L"hascb";
-const wchar_t kAutomationErrorKey[] = L"err";
-const wchar_t kAutomationNameKey[] = L"name";
-const wchar_t kAutomationArgsKey[] = L"args";
-const wchar_t kAutomationResponseKey[] = L"res";
+const char kAutomationHasCallbackKey[] = "hascb";
+const char kAutomationErrorKey[] = "err";
+const char kAutomationNameKey[] = "name";
+const char kAutomationArgsKey[] = "args";
+const char kAutomationResponseKey[] = "res";
const char kAutomationRequestTarget[] = "__priv_xtreq";
const char kAutomationResponseTarget[] = "__priv_xtres";
-const wchar_t kAutomationConnectionIdKey[] = L"connid";
-const wchar_t kAutomationMessageDataKey[] = L"data";
-const wchar_t kAutomationExtensionIdKey[] = L"extid";
-const wchar_t kAutomationPortIdKey[] = L"portid";
-const wchar_t kAutomationChannelNameKey[] = L"chname";
-const wchar_t kAutomationTabJsonKey[] = L"tab";
+const char kAutomationConnectionIdKey[] = "connid";
+const char kAutomationMessageDataKey[] = "data";
+const char kAutomationExtensionIdKey[] = "extid";
+const char kAutomationPortIdKey[] = "portid";
+const char kAutomationChannelNameKey[] = "chname";
+const char kAutomationTabJsonKey[] = "tab";
const char kAutomationPortRequestTarget[] = "__priv_prtreq";
const char kAutomationPortResponseTarget[] = "__priv_prtres";
diff --git a/chrome/browser/automation/extension_automation_constants.h b/chrome/browser/automation/extension_automation_constants.h
index 8c29293..dea4d2d 100644
--- a/chrome/browser/automation/extension_automation_constants.h
+++ b/chrome/browser/automation/extension_automation_constants.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,32 +6,33 @@
#ifndef CHROME_BROWSER_AUTOMATION_EXTENSION_AUTOMATION_CONSTANTS_H_
#define CHROME_BROWSER_AUTOMATION_EXTENSION_AUTOMATION_CONSTANTS_H_
+#pragma once
namespace extension_automation_constants {
// All extension automation related messages will have this origin.
extern const char kAutomationOrigin[];
// Key used for all extension automation request types.
-extern const wchar_t kAutomationRequestIdKey[];
+extern const char kAutomationRequestIdKey[];
// Keys used for API communications
-extern const wchar_t kAutomationHasCallbackKey[];
-extern const wchar_t kAutomationErrorKey[]; // not present implies success
-extern const wchar_t kAutomationNameKey[];
-extern const wchar_t kAutomationArgsKey[];
-extern const wchar_t kAutomationResponseKey[];
+extern const char kAutomationHasCallbackKey[];
+extern const char kAutomationErrorKey[]; // not present implies success
+extern const char kAutomationNameKey[];
+extern const char kAutomationArgsKey[];
+extern const char kAutomationResponseKey[];
// All external API requests have this target.
extern const char kAutomationRequestTarget[];
// All API responses should have this target.
extern const char kAutomationResponseTarget[];
// Keys used for port communications
-extern const wchar_t kAutomationConnectionIdKey[];
-extern const wchar_t kAutomationMessageDataKey[];
-extern const wchar_t kAutomationExtensionIdKey[];
-extern const wchar_t kAutomationPortIdKey[];
-extern const wchar_t kAutomationChannelNameKey[];
-extern const wchar_t kAutomationTabJsonKey[];
+extern const char kAutomationConnectionIdKey[];
+extern const char kAutomationMessageDataKey[];
+extern const char kAutomationExtensionIdKey[];
+extern const char kAutomationPortIdKey[];
+extern const char kAutomationChannelNameKey[];
+extern const char kAutomationTabJsonKey[];
// All external port message requests should have this target.
extern const char kAutomationPortRequestTarget[];
diff --git a/chrome/browser/automation/extension_port_container.cc b/chrome/browser/automation/extension_port_container.cc
index e93f42c..2c80844 100644
--- a/chrome/browser/automation/extension_port_container.cc
+++ b/chrome/browser/automation/extension_port_container.cc
@@ -36,11 +36,6 @@ ExtensionPortContainer::~ExtensionPortContainer() {
if (port_id_ != -1)
service_->CloseChannel(port_id_);
-
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PORT_DELETED_DEBUG,
- Source<IPC::Message::Sender>(this),
- NotificationService::NoDetails());
}
bool ExtensionPortContainer::PostResponseToExternalPort(
diff --git a/chrome/browser/automation/extension_port_container.h b/chrome/browser/automation/extension_port_container.h
index 8fd8299..1325303 100644
--- a/chrome/browser/automation/extension_port_container.h
+++ b/chrome/browser/automation/extension_port_container.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_AUTOMATION_EXTENSION_PORT_CONTAINER_H_
#define CHROME_BROWSER_AUTOMATION_EXTENSION_PORT_CONTAINER_H_
+#pragma once
#include <string>
@@ -15,7 +16,6 @@ class AutomationProvider;
class ExtensionMessageService;
class GURL;
class ListValue;
-class MessageLoop;
class RenderViewHost;
// This class represents an external port to an extension, opened
diff --git a/chrome/browser/automation/ui_controls.h b/chrome/browser/automation/ui_controls.h
index b0a2675..3664567 100644
--- a/chrome/browser/automation/ui_controls.h
+++ b/chrome/browser/automation/ui_controls.h
@@ -1,21 +1,20 @@
-// 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.
#ifndef CHROME_BROWSER_AUTOMATION_UI_CONTROLS_H_
#define CHROME_BROWSER_AUTOMATION_UI_CONTROLS_H_
+#pragma once
#include "build/build_config.h"
-#include <string>
-
#if defined(OS_WIN)
#include <wtypes.h>
#endif
+#include "app/keyboard_codes.h"
#include "gfx/native_widget_types.h"
#include "gfx/point.h"
-#include "base/keyboard_codes.h"
#if defined(TOOLKIT_VIEWS)
namespace views {
@@ -43,14 +42,17 @@ namespace ui_controls {
// these functions, so passing NULL is ok.
// Send a key press with/without modifier keys.
+//
+// If you're writing a test chances are you want the variant in ui_test_utils.
+// See it for details.
bool SendKeyPress(gfx::NativeWindow window,
- base::KeyboardCode key,
+ app::KeyboardCode key,
bool control,
bool shift,
bool alt,
bool command);
bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
- base::KeyboardCode key,
+ app::KeyboardCode key,
bool control,
bool shift,
bool alt,
@@ -89,7 +91,7 @@ void MoveMouseToCenterAndPress(
#elif defined(TOOLKIT_GTK)
GtkWidget* widget,
#elif defined(OS_MACOSX)
- NSWindow* window,
+ NSView* view,
#endif
MouseButton button,
int state,
diff --git a/chrome/browser/automation/ui_controls_linux.cc b/chrome/browser/automation/ui_controls_linux.cc
index c9dca78..a2dd0ae 100644
--- a/chrome/browser/automation/ui_controls_linux.cc
+++ b/chrome/browser/automation/ui_controls_linux.cc
@@ -7,11 +7,11 @@
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
+#include "app/event_synthesis_gtk.h"
#include "gfx/rect.h"
-#include "base/event_synthesis_gtk.h"
-#include "base/keyboard_code_conversion_gtk.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "chrome/browser/automation/ui_controls_internal.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/test/automation/automation_constants.h"
@@ -62,27 +62,6 @@ class EventWaiter : public MessageLoopForUI::Observer {
int count_;
};
-class ClickTask : public Task {
- public:
- ClickTask(ui_controls::MouseButton button, int state, Task* followup)
- : button_(button), state_(state), followup_(followup) {
- }
-
- virtual ~ClickTask() {}
-
- virtual void Run() {
- if (followup_)
- ui_controls::SendMouseEventsNotifyWhenDone(button_, state_, followup_);
- else
- ui_controls::SendMouseEvents(button_, state_);
- }
-
- private:
- ui_controls::MouseButton button_;
- int state_;
- Task* followup_;
-};
-
void FakeAMouseMotionEvent(gint x, gint y) {
GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY);
@@ -117,7 +96,7 @@ void FakeAMouseMotionEvent(gint x, gint y) {
namespace ui_controls {
bool SendKeyPress(gfx::NativeWindow window,
- base::KeyboardCode key,
+ app::KeyboardCode key,
bool control, bool shift, bool alt, bool command) {
DCHECK(command == false); // No command key on Linux
GdkWindow* event_window = NULL;
@@ -145,7 +124,7 @@ bool SendKeyPress(gfx::NativeWindow window,
}
std::vector<GdkEvent*> events;
- base::SynthesizeKeyPressEvents(event_window, key, control, shift, alt,
+ app::SynthesizeKeyPressEvents(event_window, key, control, shift, alt,
&events);
for (std::vector<GdkEvent*>::iterator iter = events.begin();
iter != events.end(); ++iter) {
@@ -158,7 +137,7 @@ bool SendKeyPress(gfx::NativeWindow window,
}
bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
- base::KeyboardCode key,
+ app::KeyboardCode key,
bool control, bool shift,
bool alt, bool command,
Task* task) {
diff --git a/chrome/browser/automation/ui_controls_mac.mm b/chrome/browser/automation/ui_controls_mac.mm
index 715135c..5edfa5d 100644
--- a/chrome/browser/automation/ui_controls_mac.mm
+++ b/chrome/browser/automation/ui_controls_mac.mm
@@ -6,8 +6,11 @@
#import <Cocoa/Cocoa.h>
#include <mach/mach_time.h>
+#include <vector>
+#include "app/keyboard_code_conversion_mac.h"
#include "base/message_loop.h"
+#include "chrome/browser/automation/ui_controls_internal.h"
#include "chrome/browser/chrome_thread.h"
// Implementation details: We use [NSApplication sendEvent:] instead
@@ -22,6 +25,23 @@
// into the event queue. (I can post other kinds of tasks but can't
// guarantee their order with regards to events).
+// But [NSApplication sendEvent:] causes a problem when sending mouse click
+// events. Because in order to handle mouse drag, when processing a mouse
+// click event, the application may want to retrieve the next event
+// synchronously by calling NSApplication's nextEventMatchingMask method.
+// In this case, [NSApplication sendEvent:] causes deadlock.
+// So we need to use [NSApplication postEvent:atStart:] for mouse click
+// events. In order to notify the caller correctly after all events has been
+// processed, we setup a task to watch for the event queue time to time and
+// notify the caller as soon as there is no event in the queue.
+//
+// TODO(suzhe):
+// 1. Investigate why using [NSApplication postEvent:atStart:] for keyboard
+// events causes BrowserKeyEventsTest.CommandKeyEvents to fail.
+// See http://crbug.com/49270
+// 2. On OSX 10.6, [NSEvent addLocalMonitorForEventsMatchingMask:handler:] may
+// be used, so that we don't need to poll the event queue time to time.
+
namespace {
// From
@@ -53,13 +73,155 @@ NSTimeInterval TimeIntervalSinceSystemStartup() {
return UpTimeInNanoseconds() / 1000000000.0;
}
+// Creates and returns an autoreleased key event.
+NSEvent* SynthesizeKeyEvent(NSWindow* window,
+ bool keyDown,
+ app::KeyboardCode keycode,
+ NSUInteger flags) {
+ unichar character;
+ unichar characterIgnoringModifiers;
+ int macKeycode = app::MacKeyCodeForWindowsKeyCode(
+ keycode, flags, &character, &characterIgnoringModifiers);
+
+ if (macKeycode < 0)
+ return nil;
+
+ NSString* charactersIgnoringModifiers =
+ [[[NSString alloc] initWithCharacters:&characterIgnoringModifiers
+ length:1]
+ autorelease];
+ NSString* characters =
+ [[[NSString alloc] initWithCharacters:&character length:1] autorelease];
+
+ NSEventType type = (keyDown ? NSKeyDown : NSKeyUp);
+
+ // Modifier keys generate NSFlagsChanged event rather than
+ // NSKeyDown/NSKeyUp events.
+ if (keycode == app::VKEY_CONTROL || keycode == app::VKEY_SHIFT ||
+ keycode == app::VKEY_MENU || keycode == app::VKEY_COMMAND)
+ type = NSFlagsChanged;
+
+ // For events other than mouse moved, [event locationInWindow] is
+ // UNDEFINED if the event is not NSMouseMoved. Thus, the (0,0)
+ // location should be fine.
+ NSEvent* event =
+ [NSEvent keyEventWithType:type
+ location:NSMakePoint(0, 0)
+ modifierFlags:flags
+ timestamp:TimeIntervalSinceSystemStartup()
+ windowNumber:[window windowNumber]
+ context:nil
+ characters:characters
+ charactersIgnoringModifiers:charactersIgnoringModifiers
+ isARepeat:NO
+ keyCode:(unsigned short)macKeycode];
+
+ return event;
+}
+
+// Creates the proper sequence of autoreleased key events for a key down + up.
+void SynthesizeKeyEventsSequence(NSWindow* window,
+ app::KeyboardCode keycode,
+ bool control,
+ bool shift,
+ bool alt,
+ bool command,
+ std::vector<NSEvent*>* events) {
+ NSEvent* event = nil;
+ NSUInteger flags = 0;
+ if (control) {
+ flags |= NSControlKeyMask;
+ event = SynthesizeKeyEvent(window, true, app::VKEY_CONTROL, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (shift) {
+ flags |= NSShiftKeyMask;
+ event = SynthesizeKeyEvent(window, true, app::VKEY_SHIFT, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (alt) {
+ flags |= NSAlternateKeyMask;
+ event = SynthesizeKeyEvent(window, true, app::VKEY_MENU, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (command) {
+ flags |= NSCommandKeyMask;
+ event = SynthesizeKeyEvent(window, true, app::VKEY_COMMAND, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+
+ event = SynthesizeKeyEvent(window, true, keycode, flags);
+ DCHECK(event);
+ events->push_back(event);
+ event = SynthesizeKeyEvent(window, false, keycode, flags);
+ DCHECK(event);
+ events->push_back(event);
+
+ if (command) {
+ flags &= ~NSCommandKeyMask;
+ event = SynthesizeKeyEvent(window, false, app::VKEY_COMMAND, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (alt) {
+ flags &= ~NSAlternateKeyMask;
+ event = SynthesizeKeyEvent(window, false, app::VKEY_MENU, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (shift) {
+ flags &= ~NSShiftKeyMask;
+ event = SynthesizeKeyEvent(window, false, app::VKEY_SHIFT, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (control) {
+ flags &= ~NSControlKeyMask;
+ event = SynthesizeKeyEvent(window, false, app::VKEY_CONTROL, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+}
+
+// A task class to watch for the event queue. The specific task will be fired
+// when there is no more event in the queue.
+class EventQueueWatcher : public Task {
+ public:
+ EventQueueWatcher(Task* task) : task_(task) {}
+
+ virtual ~EventQueueWatcher() {}
+
+ virtual void Run() {
+ NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue:NO];
+ // If there is still event in the queue, then we need to check again.
+ if (event)
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task_));
+ else
+ MessageLoop::current()->PostTask(FROM_HERE, task_);
+ }
+
+ private:
+ Task* task_;
+};
+
+// Stores the current mouse location on the screen. So that we can use it
+// when firing keyboard and mouse click events.
+NSPoint g_mouse_location = { 0, 0 };
+
} // anonymous namespace
namespace ui_controls {
bool SendKeyPress(gfx::NativeWindow window,
- base::KeyboardCode key,
+ app::KeyboardCode key,
bool control,
bool shift,
bool alt,
@@ -71,65 +233,31 @@ bool SendKeyPress(gfx::NativeWindow window,
// Win and Linux implement a SendKeyPress() this as a
// SendKeyPressAndRelease(), so we should as well (despite the name).
-//
-// TODO(jrg): handle "characters" better (e.g. apply shift?)
bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
- base::KeyboardCode key,
+ app::KeyboardCode key,
bool control,
bool shift,
bool alt,
bool command,
Task* task) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- NSUInteger flags = 0;
- if (control)
- flags |= NSControlKeyMask;
- if (shift)
- flags |= NSShiftKeyMask;
- if (alt)
- flags |= NSAlternateKeyMask;
- if (command)
- flags |= NSCommandKeyMask;
- unsigned char keycode = key;
- NSString* charactersIgnoringModifiers = [[[NSString alloc]
- initWithBytes:&keycode
- length:1
- encoding:NSUTF8StringEncoding]
- autorelease];
- NSString* characters = charactersIgnoringModifiers;
- // For events other than mouse moved, [event locationInWindow] is
- // UNDEFINED if the event is not NSMouseMoved. Thus, the (0,0)
- // locaiton should be fine.
- // First a key down...
- NSEvent* event =
- [NSEvent keyEventWithType:NSKeyDown
- location:NSMakePoint(0,0)
- modifierFlags:flags
- timestamp:TimeIntervalSinceSystemStartup()
- windowNumber:[window windowNumber]
- context:nil
- characters:characters
- charactersIgnoringModifiers:charactersIgnoringModifiers
- isARepeat:NO
- keyCode:key];
- [[NSApplication sharedApplication] sendEvent:event];
- // Then a key up.
- event =
- [NSEvent keyEventWithType:NSKeyUp
- location:NSMakePoint(0,0)
- modifierFlags:flags
- timestamp:TimeIntervalSinceSystemStartup()
- windowNumber:[window windowNumber]
- context:nil
- characters:characters
- charactersIgnoringModifiers:charactersIgnoringModifiers
- isARepeat:NO
- keyCode:key];
- [[NSApplication sharedApplication] sendEvent:event];
+ std::vector<NSEvent*> events;
+ SynthesizeKeyEventsSequence(
+ window, key, control, shift, alt, command, &events);
+
+ // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes
+ // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270
+ // But using [NSApplication sendEvent:] should be safe for keyboard events,
+ // because until now, no code wants to retrieve the next event when handling
+ // a keyboard event.
+ for (std::vector<NSEvent*>::iterator iter = events.begin();
+ iter != events.end(); ++iter)
+ [[NSApplication sharedApplication] sendEvent:*iter];
if (task)
- MessageLoop::current()->PostTask(FROM_HERE, task);
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task));
+
return true;
}
@@ -144,7 +272,8 @@ bool SendMouseMove(long x, long y) {
bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) {
NSWindow* window = [[NSApplication sharedApplication] keyWindow];
CGFloat screenHeight = [[NSScreen mainScreen] frame].size.height;
- NSPoint pointInWindow = NSMakePoint(x, screenHeight - y); // flip!
+ g_mouse_location = NSMakePoint(x, screenHeight - y); // flip!
+ NSPoint pointInWindow = g_mouse_location;
if (window)
pointInWindow = [window convertScreenToBase:pointInWindow];
NSTimeInterval timestamp = TimeIntervalSinceSystemStartup();
@@ -160,8 +289,10 @@ bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) {
clickCount:0
pressure:0.0];
[[NSApplication sharedApplication] postEvent:event atStart:NO];
+
if (task)
- MessageLoop::current()->PostTask(FROM_HERE, task);
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task));
+
return true;
}
@@ -176,7 +307,6 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) {
return (SendMouseEventsNotifyWhenDone(type, DOWN, NULL) &&
SendMouseEventsNotifyWhenDone(type, UP, task));
}
-
NSEventType etype = 0;
if (type == LEFT) {
if (state == UP) {
@@ -200,8 +330,7 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) {
return false;
}
NSWindow* window = [[NSApplication sharedApplication] keyWindow];
- NSPoint location = [NSEvent mouseLocation];
- NSPoint pointInWindow = location;
+ NSPoint pointInWindow = g_mouse_location;
if (window)
pointInWindow = [window convertScreenToBase:pointInWindow];
@@ -213,11 +342,13 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) {
windowNumber:[window windowNumber]
context:nil
eventNumber:0
- clickCount:0
- pressure:0.0];
- [[NSApplication sharedApplication] sendEvent:event];
+ clickCount:1
+ pressure:(state == DOWN ? 1.0 : 0.0 )];
+ [[NSApplication sharedApplication] postEvent:event atStart:NO];
+
if (task)
- MessageLoop::current()->PostTask(FROM_HERE, task);
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task));
+
return true;
}
@@ -225,18 +356,27 @@ bool SendMouseClick(MouseButton type) {
return SendMouseEventsNotifyWhenDone(type, UP|DOWN, NULL);
}
-// This appears to only be used by a function in test/ui_test_utils.h:
-// ui_test_utils::ClickOnView(). That is not implemented on Mac, so
-// we don't need to implement MoveMouseToCenterAndPress(). I've
-// suggested an implementation of ClickOnView() which would call Cocoa
-// directly and not need this indirection, so this may not be needed,
-// ever.
void MoveMouseToCenterAndPress(
- NSWindow* window,
+ NSView* view,
MouseButton button,
int state,
Task* task) {
- NOTIMPLEMENTED();
+ DCHECK(view);
+ NSWindow* window = [view window];
+ DCHECK(window);
+ NSScreen* screen = [window screen];
+ DCHECK(screen);
+
+ // Converts the center position of the view into the coordinates accepted
+ // by SendMouseMoveNotifyWhenDone() method.
+ NSRect bounds = [view bounds];
+ NSPoint center = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
+ center = [view convertPoint:center toView:nil];
+ center = [window convertBaseToScreen:center];
+ center = NSMakePoint(center.x, [screen frame].size.height - center.y);
+
+ SendMouseMoveNotifyWhenDone(center.x, center.y,
+ new ClickTask(button, state, task));
}
} // ui_controls
diff --git a/chrome/browser/automation/ui_controls_win.cc b/chrome/browser/automation/ui_controls_win.cc
index 50bb88f..fdd1732 100644
--- a/chrome/browser/automation/ui_controls_win.cc
+++ b/chrome/browser/automation/ui_controls_win.cc
@@ -4,7 +4,8 @@
#include "chrome/browser/automation/ui_controls.h"
-#include "base/keyboard_codes.h"
+#include "app/keyboard_code_conversion_win.h"
+#include "app/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/win_util.h"
@@ -137,10 +138,10 @@ void InputDispatcher::NotifyTask() {
// Populate the INPUT structure with the appropriate keyboard event
// parameters required by SendInput
-bool FillKeyboardInput(base::KeyboardCode key, INPUT* input, bool key_up) {
+bool FillKeyboardInput(app::KeyboardCode key, INPUT* input, bool key_up) {
memset(input, 0, sizeof(INPUT));
input->type = INPUT_KEYBOARD;
- input->ki.wVk = win_util::KeyboardCodeToWin(key);
+ input->ki.wVk = app::WindowsKeyCodeForKeyboardCode(key);
input->ki.dwFlags = key_up ? KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP :
KEYEVENTF_EXTENDEDKEY;
@@ -148,7 +149,7 @@ bool FillKeyboardInput(base::KeyboardCode key, INPUT* input, bool key_up) {
}
// Send a key event (up/down)
-bool SendKeyEvent(base::KeyboardCode key, bool up) {
+bool SendKeyEvent(app::KeyboardCode key, bool up) {
INPUT input = { 0 };
if (!FillKeyboardInput(key, &input, up))
@@ -160,7 +161,7 @@ bool SendKeyEvent(base::KeyboardCode key, bool up) {
return true;
}
-bool SendKeyPressImpl(base::KeyboardCode key,
+bool SendKeyPressImpl(app::KeyboardCode key,
bool control, bool shift, bool alt,
Task* task) {
scoped_refptr<InputDispatcher> dispatcher(
@@ -171,7 +172,7 @@ bool SendKeyPressImpl(base::KeyboardCode key,
// exists, send the key event directly there.
HWND popup_menu = ::FindWindow(L"#32768", 0);
if (popup_menu != NULL && popup_menu == ::GetTopWindow(NULL)) {
- WPARAM w_param = win_util::KeyboardCodeToWin(key);
+ WPARAM w_param = app::WindowsKeyCodeForKeyboardCode(key);
LPARAM l_param = 0;
::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param);
::SendMessage(popup_menu, WM_KEYUP, w_param, l_param);
@@ -185,19 +186,19 @@ bool SendKeyPressImpl(base::KeyboardCode key,
UINT i = 0;
if (control) {
- if (!FillKeyboardInput(base::VKEY_CONTROL, &input[i], false))
+ if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], false))
return false;
i++;
}
if (shift) {
- if (!FillKeyboardInput(base::VKEY_SHIFT, &input[i], false))
+ if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], false))
return false;
i++;
}
if (alt) {
- if (!FillKeyboardInput(base::VKEY_MENU, &input[i], false))
+ if (!FillKeyboardInput(app::VKEY_MENU, &input[i], false))
return false;
i++;
}
@@ -211,19 +212,19 @@ bool SendKeyPressImpl(base::KeyboardCode key,
i++;
if (alt) {
- if (!FillKeyboardInput(base::VKEY_MENU, &input[i], true))
+ if (!FillKeyboardInput(app::VKEY_MENU, &input[i], true))
return false;
i++;
}
if (shift) {
- if (!FillKeyboardInput(base::VKEY_SHIFT, &input[i], true))
+ if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], true))
return false;
i++;
}
if (control) {
- if (!FillKeyboardInput(base::VKEY_CONTROL, &input[i], true))
+ if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], true))
return false;
i++;
}
@@ -322,14 +323,14 @@ bool SendMouseEventsImpl(MouseButton type, int state, Task* task) {
// public functions -----------------------------------------------------------
-bool SendKeyPress(gfx::NativeWindow window, base::KeyboardCode key,
+bool SendKeyPress(gfx::NativeWindow window, app::KeyboardCode key,
bool control, bool shift, bool alt, bool command) {
DCHECK(command == false); // No command key on Windows
return SendKeyPressImpl(key, control, shift, alt, NULL);
}
bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
- base::KeyboardCode key,
+ app::KeyboardCode key,
bool control, bool shift, bool alt,
bool command,
Task* task) {
diff --git a/chrome/browser/automation/url_request_automation_job.cc b/chrome/browser/automation/url_request_automation_job.cc
index 6cdfdbf..8e96e7a 100644
--- a/chrome/browser/automation/url_request_automation_job.cc
+++ b/chrome/browser/automation/url_request_automation_job.cc
@@ -15,6 +15,7 @@
#include "net/base/cookie_monster.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request_context.h"
@@ -48,6 +49,7 @@ URLRequest::ProtocolFactory* URLRequestAutomationJob::old_https_factory_
URLRequestAutomationJob::URLRequestAutomationJob(URLRequest* request, int tab,
int request_id, AutomationResourceMessageFilter* filter, bool is_pending)
: URLRequestJob(request),
+ id_(0),
tab_(tab),
message_filter_(filter),
pending_buf_size_(0),
diff --git a/chrome/browser/automation/url_request_automation_job.h b/chrome/browser/automation/url_request_automation_job.h
index b8c7442..5ce9553 100644
--- a/chrome/browser/automation/url_request_automation_job.h
+++ b/chrome/browser/automation/url_request_automation_job.h
@@ -1,25 +1,27 @@
-// 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.
// This class simulates what wininet does when a dns lookup fails.
#ifndef CHROME_BROWSER_AUTOMATION_URL_REQUEST_AUTOMATION_JOB_H_
#define CHROME_BROWSER_AUTOMATION_URL_REQUEST_AUTOMATION_JOB_H_
+#pragma once
-#include <vector>
-
-#include "chrome/browser/automation/automation_resource_message_filter.h"
#include "chrome/common/ref_counted_util.h"
-#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
class AutomationResourceMessageFilter;
+namespace net {
+class HttpResponseHeaders;
+class HttpResponseInfo;
+}
+
namespace IPC {
class Message;
struct AutomationURLResponse;
-};
+}
// URLRequestJob implementation that loads the resources using
// automation.
diff --git a/chrome/browser/back_forward_menu_model.cc b/chrome/browser/back_forward_menu_model.cc
index 5a164e7..fb18da8 100644
--- a/chrome/browser/back_forward_menu_model.cc
+++ b/chrome/browser/back_forward_menu_model.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.
@@ -8,6 +8,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
@@ -368,7 +369,7 @@ std::string BackForwardMenuModel::BuildActionName(
metric_string += action;
if (index != -1) {
// +1 is for historical reasons (indices used to start at 1).
- metric_string += IntToString(index + 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
index 2315a41..4f838fd 100644
--- a/chrome/browser/back_forward_menu_model.h
+++ b/chrome/browser/back_forward_menu_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_H_
#define CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/back_forward_menu_model_unittest.cc b/chrome/browser/back_forward_menu_model_unittest.cc
index 99c2af5..f6d2ea7 100644
--- a/chrome/browser/back_forward_menu_model_unittest.cc
+++ b/chrome/browser/back_forward_menu_model_unittest.cc
@@ -1,18 +1,18 @@
-// 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.
#include "chrome/browser/back_forward_menu_model.h"
-#include "base/file_path.h"
-#include "base/file_util.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"
@@ -40,27 +40,23 @@ class BackFwdMenuModelTest : public RenderViewHostTestHarness {
// will be pending after we ask to navigate there).
void NavigateToOffset(int offset) {
controller().GoToOffset(offset);
- const NavigationEntry* entry = controller().pending_entry();
- rvh()->SendNavigate(entry->page_id(), entry->url());
+ contents()->CommitPendingNavigation();
}
// Same as NavigateToOffset but goes to an absolute index.
void NavigateToIndex(int index) {
controller().GoToIndex(index);
- const NavigationEntry* entry = controller().pending_entry();
- rvh()->SendNavigate(entry->page_id(), entry->url());
+ contents()->CommitPendingNavigation();
}
// Goes back/forward and commits the load.
void GoBack() {
controller().GoBack();
- const NavigationEntry* entry = controller().pending_entry();
- rvh()->SendNavigate(entry->page_id(), entry->url());
+ contents()->CommitPendingNavigation();
}
void GoForward() {
controller().GoForward();
- const NavigationEntry* entry = controller().pending_entry();
- rvh()->SendNavigate(entry->page_id(), entry->url());
+ contents()->CommitPendingNavigation();
}
};
diff --git a/chrome/browser/background_contents_service.cc b/chrome/browser/background_contents_service.cc
index c10d9d2..e50572c 100644
--- a/chrome/browser/background_contents_service.cc
+++ b/chrome/browser/background_contents_service.cc
@@ -9,13 +9,14 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
-#include "chrome/browser/tab_contents/background_contents.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
@@ -34,17 +35,16 @@
// <appid_2>: { "url": <url2>, "name": <frame_name> },
// ... etc ...
// }
-const wchar_t kUrlKey[] = L"url";
-const wchar_t kFrameNameKey[] = L"name";
+const char kUrlKey[] = "url";
+const char kFrameNameKey[] = "name";
BackgroundContentsService::BackgroundContentsService(
Profile* profile, const CommandLine* command_line)
- : prefs_(NULL),
- always_keep_alive_(command_line->HasSwitch(switches::kKeepAliveForTest)) {
+ : prefs_(NULL) {
// Don't load/store preferences if the proper switch is not enabled, or if
// the parent profile is off the record.
if (!profile->IsOffTheRecord() &&
- command_line->HasSwitch(switches::kRestoreBackgroundContents))
+ !command_line->HasSwitch(switches::kDisableRestoreBackgroundContents))
prefs_ = profile->GetPrefs();
// Listen for events to tell us when to load/unload persisted background
@@ -84,14 +84,6 @@ void BackgroundContentsService::StartObserving(Profile* profile) {
// BackgroundContents.
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
Source<Profile>(profile));
-
- if (always_keep_alive_ && !profile->IsOffTheRecord()) {
- // For testing, keep the browser process alive until there is an explicit
- // shutdown.
- registrar_.Add(this, NotificationType::APP_TERMINATING,
- NotificationService::AllSources());
- BrowserList::StartKeepAlive();
- }
}
void BackgroundContentsService::Observe(NotificationType type,
@@ -120,11 +112,6 @@ void BackgroundContentsService::Observe(NotificationType type,
ShutdownAssociatedBackgroundContents(
ASCIIToUTF16(Details<Extension>(details)->id()));
break;
- case NotificationType::APP_TERMINATING:
- // Performing an explicit shutdown, so allow the browser process to exit.
- DCHECK(always_keep_alive_);
- BrowserList::EndKeepAlive();
- break;
default:
NOTREACHED();
break;
@@ -147,11 +134,11 @@ void BackgroundContentsService::LoadBackgroundContentsFromPrefs(
string16 frame_name;
std::string url;
dict->GetString(kUrlKey, &url);
- dict->GetStringAsUTF16(kFrameNameKey, &frame_name);
+ dict->GetString(kFrameNameKey, &frame_name);
CreateBackgroundContents(profile,
GURL(url),
frame_name,
- WideToUTF16(*it));
+ UTF8ToUTF16(*it));
}
}
@@ -184,7 +171,9 @@ void BackgroundContentsService::CreateBackgroundContents(
}
BackgroundContents* contents = new BackgroundContents(
- SiteInstance::CreateSiteInstanceForURL(profile, url), MSG_ROUTING_NONE);
+ SiteInstance::CreateSiteInstanceForURL(profile, url),
+ MSG_ROUTING_NONE,
+ this);
// TODO(atwilson): Change this to send a BACKGROUND_CONTENTS_CREATED
// notification when we have a listener outside of BackgroundContentsService.
@@ -196,7 +185,7 @@ void BackgroundContentsService::CreateBackgroundContents(
RenderViewHost* render_view_host = contents->render_view_host();
// TODO(atwilson): Create RenderViews asynchronously to avoid increasing
// startup latency (http://crbug.com/47236).
- render_view_host->CreateRenderView(profile->GetRequestContext(), frame_name);
+ render_view_host->CreateRenderView(frame_name);
render_view_host->NavigateToURL(url);
}
@@ -214,14 +203,14 @@ void BackgroundContentsService::RegisterBackgroundContents(
prefs::kRegisteredBackgroundContents);
const string16& appid = GetParentApplicationId(background_contents);
DictionaryValue* current;
- if (pref->GetDictionaryWithoutPathExpansion(UTF16ToWide(appid), &current))
+ if (pref->GetDictionaryWithoutPathExpansion(UTF16ToUTF8(appid), &current))
return;
// No entry for this application yet, so add one.
DictionaryValue* dict = new DictionaryValue();
dict->SetString(kUrlKey, background_contents->GetURL().spec());
- dict->SetStringFromUTF16(kFrameNameKey, contents_map_[appid].frame_name);
- pref->SetWithoutPathExpansion(UTF16ToWide(appid), dict);
+ dict->SetString(kFrameNameKey, contents_map_[appid].frame_name);
+ pref->SetWithoutPathExpansion(UTF16ToUTF8(appid), dict);
prefs_->ScheduleSavePersistentPrefs();
}
@@ -233,7 +222,7 @@ void BackgroundContentsService::UnregisterBackgroundContents(
const string16 appid = GetParentApplicationId(background_contents);
DictionaryValue* pref = prefs_->GetMutableDictionary(
prefs::kRegisteredBackgroundContents);
- pref->RemoveWithoutPathExpansion(UTF16ToWide(appid), NULL);
+ pref->RemoveWithoutPathExpansion(UTF16ToUTF8(appid), NULL);
prefs_->ScheduleSavePersistentPrefs();
}
@@ -249,11 +238,6 @@ void BackgroundContentsService::ShutdownAssociatedBackgroundContents(
void BackgroundContentsService::BackgroundContentsOpened(
BackgroundContentsOpenedDetails* details) {
- // If this is the first BackgroundContents loaded, kick ourselves into
- // persistent mode.
- if (contents_map_.empty())
- BrowserList::StartKeepAlive();
-
// Add the passed object to our list. Should not already be tracked.
DCHECK(!IsTracked(details->contents));
DCHECK(!details->application_id.empty());
@@ -274,10 +258,6 @@ void BackgroundContentsService::BackgroundContentsShutdown(
DCHECK(IsTracked(background_contents));
string16 appid = GetParentApplicationId(background_contents);
contents_map_.erase(appid);
- // If we have no more BackgroundContents active, then stop keeping the browser
- // process alive.
- if (contents_map_.empty())
- BrowserList::EndKeepAlive();
}
BackgroundContents* BackgroundContentsService::GetAppBackgroundContents(
@@ -300,3 +280,15 @@ const string16& BackgroundContentsService::GetParentApplicationId(
void BackgroundContentsService::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(prefs::kRegisteredBackgroundContents);
}
+
+void BackgroundContentsService::AddTabContents(
+ TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {
+ Browser* browser = BrowserList::GetLastActiveWithProfile(
+ new_contents->profile());
+ if (!browser)
+ return;
+ browser->AddTabContents(new_contents, disposition, initial_pos, user_gesture);
+}
diff --git a/chrome/browser/background_contents_service.h b/chrome/browser/background_contents_service.h
index 73d9944..e9d7df0 100644
--- a/chrome/browser/background_contents_service.h
+++ b/chrome/browser/background_contents_service.h
@@ -4,18 +4,28 @@
#ifndef CHROME_BROWSER_BACKGROUND_CONTENTS_SERVICE_H_
#define CHROME_BROWSER_BACKGROUND_CONTENTS_SERVICE_H_
+#pragma once
#include <map>
+#include "base/gtest_prod_util.h"
+#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
+#include "chrome/common/window_container_type.h"
#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
+#include "webkit/glue/window_open_disposition.h"
class BackgroundContents;
class CommandLine;
class PrefService;
class Profile;
+class TabContents;
+
+namespace gfx {
+class Rect;
+}
+
struct BackgroundContentsOpenedDetails;
// BackgroundContentsService is owned by the profile, and is responsible for
@@ -26,7 +36,8 @@ struct BackgroundContentsOpenedDetails;
// It is also responsible for tracking the association between
// BackgroundContents and their parent app, and shutting them down when the
// parent app is unloaded.
-class BackgroundContentsService : private NotificationObserver {
+class BackgroundContentsService : private NotificationObserver,
+ public BackgroundContents::Delegate {
public:
BackgroundContentsService(Profile* profile, const CommandLine* command_line);
virtual ~BackgroundContentsService();
@@ -37,10 +48,18 @@ class BackgroundContentsService : private NotificationObserver {
static void RegisterUserPrefs(PrefService* prefs);
+ // BackgroundContents::Delegate implementation.
+ virtual void AddTabContents(TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture);
+
private:
friend class BackgroundContentsServiceTest;
- FRIEND_TEST(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy);
- FRIEND_TEST(BackgroundContentsServiceTest, TestApplicationIDLinkage);
+ FRIEND_TEST_ALL_PREFIXES(BackgroundContentsServiceTest,
+ BackgroundContentsCreateDestroy);
+ FRIEND_TEST_ALL_PREFIXES(BackgroundContentsServiceTest,
+ TestApplicationIDLinkage);
// Registers for various notifications.
void StartObserving(Profile* profile);
@@ -108,10 +127,6 @@ class BackgroundContentsService : private NotificationObserver {
typedef std::map<string16, BackgroundContentsInfo> BackgroundContentsMap;
BackgroundContentsMap contents_map_;
- // If true, should always keep the browser process alive regardless of whether
- // there are any BackgroundContents (used for manual/automated testing).
- bool always_keep_alive_;
-
DISALLOW_COPY_AND_ASSIGN(BackgroundContentsService);
};
diff --git a/chrome/browser/background_contents_service_unittest.cc b/chrome/browser/background_contents_service_unittest.cc
index 6383e2f..84c78ac 100644
--- a/chrome/browser/background_contents_service_unittest.cc
+++ b/chrome/browser/background_contents_service_unittest.cc
@@ -9,7 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -25,7 +25,6 @@ class BackgroundContentsServiceTest : public testing::Test {
~BackgroundContentsServiceTest() {}
void SetUp() {
command_line_.reset(new CommandLine(CommandLine::ARGUMENTS_ONLY));
- command_line_->AppendSwitch(switches::kRestoreBackgroundContents);
}
DictionaryValue* GetPrefs(Profile* profile) {
@@ -36,11 +35,11 @@ class BackgroundContentsServiceTest : public testing::Test {
// Returns the stored pref URL for the passed app id.
std::string GetPrefURLForApp(Profile* profile, const string16& appid) {
DictionaryValue* pref = GetPrefs(profile);
- EXPECT_TRUE(pref->HasKey(UTF16ToWide(appid)));
+ EXPECT_TRUE(pref->HasKey(UTF16ToUTF8(appid)));
DictionaryValue* value;
- pref->GetDictionaryWithoutPathExpansion(UTF16ToWide(appid), &value);
+ pref->GetDictionaryWithoutPathExpansion(UTF16ToUTF8(appid), &value);
std::string url;
- value->GetString(L"url", &url);
+ value->GetString("url", &url);
return url;
}
@@ -68,7 +67,7 @@ class MockBackgroundContents : public BackgroundContents {
Details<BackgroundContentsOpenedDetails>(&details));
}
- virtual const void Navigate(GURL url) {
+ virtual void Navigate(GURL url) {
url_ = url;
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
@@ -115,12 +114,9 @@ TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) {
BackgroundContentsService service(&profile, command_line_.get());
MockBackgroundContents* contents = new MockBackgroundContents(&profile);
EXPECT_FALSE(service.IsTracked(contents));
- EXPECT_FALSE(BrowserList::WillKeepAlive());
contents->SendOpenedNotification();
- EXPECT_TRUE(BrowserList::WillKeepAlive());
EXPECT_TRUE(service.IsTracked(contents));
delete contents;
- EXPECT_FALSE(BrowserList::WillKeepAlive());
EXPECT_FALSE(service.IsTracked(contents));
}
diff --git a/chrome/browser/background_mode_manager.cc b/chrome/browser/background_mode_manager.cc
new file mode 100644
index 0000000..b0110a1
--- /dev/null
+++ b/chrome/browser/background_mode_manager.cc
@@ -0,0 +1,474 @@
+// Copyright (c) 2010 The Chromium Authors. 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 "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 "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/background_mode_manager.h"
+#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/shell_integration.h"
+#include "chrome/browser/status_icons/status_icon.h"
+#include "chrome/browser/status_icons/status_tray.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#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/task.h"
+#include "base/utf_string_conversions.h"
+#include "base/xdg_util.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/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(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ FilePath result =
+ base::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.";
+ return;
+ }
+ std::string wrapper_script;
+ if (!environment->GetVar("CHROME_WRAPPER", &wrapper_script)) {
+ LOG(WARNING) << "Failed to register launch on login.";
+ return;
+ }
+ std::string autostart_file_contents =
+ "[Desktop Entry]\n"
+ "Type=Application\n"
+ "Terminal=false\n"
+ "Exec=" + wrapper_script + "\n"
+ "Name=" + version_info->Name() + "\n";
+ if (file_util::WriteFile(autostart_file, autostart_file_contents.c_str(),
+ autostart_file_contents.length()))
+ LOG(WARNING) << "Failed to register launch on login.";
+ }
+};
+#endif // defined(OS_LINUX)
+
+BackgroundModeManager::BackgroundModeManager(Profile* profile,
+ CommandLine* command_line)
+ : profile_(profile),
+ background_app_count_(0),
+ in_background_mode_(false),
+ status_tray_(NULL),
+ status_icon_(NULL) {
+ // If background mode is disabled, just exit - don't listen for
+ // any notifications.
+ if (!command_line->HasSwitch(switches::kEnableBackgroundMode))
+ return;
+
+ // If the -keep-alive-for-test flag is passed, then always keep chrome running
+ // in the background until the user explicitly terminates it, by acting as if
+ // we loaded a background app.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKeepAliveForTest))
+ OnBackgroundAppLoaded();
+
+ // When an extension is installed, make sure launch on startup is properly
+ // set if appropriate. Likewise, turn off launch on startup when the last
+ // background app is uninstalled.
+ registrar_.Add(this, NotificationType::EXTENSION_INSTALLED,
+ Source<Profile>(profile));
+ registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
+ Source<Profile>(profile));
+ // Listen for when extensions are loaded/unloaded so we can track the
+ // number of background apps.
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ Source<Profile>(profile));
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
+ Source<Profile>(profile));
+
+ // Check for the presence of background apps after all extensions have been
+ // loaded, to handle the case where an extension has been manually removed
+ // while Chrome was not running.
+ registrar_.Add(this, NotificationType::EXTENSIONS_READY,
+ Source<Profile>(profile));
+
+ // Listen for the application shutting down so we can decrement our KeepAlive
+ // count.
+ registrar_.Add(this, NotificationType::APP_TERMINATING,
+ NotificationService::AllSources());
+
+ // Listen for changes to the background mode preference.
+ pref_registrar_.Init(profile_->GetPrefs());
+ pref_registrar_.Add(prefs::kBackgroundModeEnabled, this);
+}
+
+BackgroundModeManager::~BackgroundModeManager() {
+ // We're going away, so exit background mode (does nothing if we aren't in
+ // background mode currently). This is primarily needed for unit tests,
+ // because in an actual running system we'd get an APP_TERMINATING
+ // notification before being destroyed.
+ EndBackgroundMode();
+}
+
+bool BackgroundModeManager::IsBackgroundModeEnabled() {
+ return profile_->GetPrefs()->GetBoolean(prefs::kBackgroundModeEnabled);
+}
+
+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) {
+ switch (type.value) {
+ case NotificationType::EXTENSIONS_READY:
+ // On a Mac, we use 'login items' mechanism which has user-facing UI so we
+ // don't want to stomp on user choice every time we start and load
+ // registered extensions.
+#if !defined(OS_MACOSX)
+ EnableLaunchOnStartup(IsBackgroundModeEnabled() &&
+ background_app_count_ > 0);
+#endif
+ break;
+ case NotificationType::EXTENSION_LOADED:
+ if (IsBackgroundApp(Details<Extension>(details).ptr()))
+ OnBackgroundAppLoaded();
+ break;
+ case NotificationType::EXTENSION_UNLOADED:
+ if (IsBackgroundApp(Details<Extension>(details).ptr()))
+ OnBackgroundAppUnloaded();
+ break;
+ case NotificationType::EXTENSION_INSTALLED:
+ if (IsBackgroundApp(Details<Extension>(details).ptr()))
+ OnBackgroundAppInstalled();
+ break;
+ case NotificationType::EXTENSION_UNINSTALLED:
+ if (IsBackgroundApp(Details<Extension>(details).ptr()))
+ OnBackgroundAppUninstalled();
+ break;
+ case NotificationType::APP_TERMINATING:
+ // Performing an explicit shutdown, so exit background mode (does nothing
+ // if we aren't in background mode currently).
+ EndBackgroundMode();
+ // Shutting down, so don't listen for any more notifications so we don't
+ // try to re-enter/exit background mode again.
+ registrar_.RemoveAll();
+ break;
+ case NotificationType::PREF_CHANGED:
+ DCHECK(0 == Details<std::string>(details).ptr()->compare(
+ prefs::kBackgroundModeEnabled));
+ OnBackgroundModePrefChanged();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+bool BackgroundModeManager::IsBackgroundApp(Extension* extension) {
+ return extension->HasApiPermission(Extension::kBackgroundPermission);
+}
+
+
+void BackgroundModeManager::OnBackgroundModePrefChanged() {
+ // Background mode has been enabled/disabled in preferences, so update our
+ // state accordingly.
+ if (IsBackgroundModeEnabled() && !in_background_mode_ &&
+ background_app_count_ > 0) {
+ // We should be in background mode, but we're not, so switch to background
+ // mode.
+ EnableLaunchOnStartup(true);
+ StartBackgroundMode();
+ }
+ if (!IsBackgroundModeEnabled() && in_background_mode_) {
+ // We're in background mode, but we shouldn't be any longer.
+ EnableLaunchOnStartup(false);
+ EndBackgroundMode();
+ }
+}
+
+void BackgroundModeManager::OnBackgroundAppLoaded() {
+ // When a background app loads, increment our count and also enable
+ // KeepAlive mode if the preference is set.
+ background_app_count_++;
+ if (background_app_count_ == 1 && IsBackgroundModeEnabled())
+ StartBackgroundMode();
+}
+
+void BackgroundModeManager::StartBackgroundMode() {
+ // Don't bother putting ourselves in background mode if we're already there.
+ if (in_background_mode_)
+ return;
+
+ // Mark ourselves as running in background mode.
+ in_background_mode_ = true;
+
+ // Put ourselves in KeepAlive mode and create a status tray icon.
+ BrowserList::StartKeepAlive();
+
+ // Display a status icon to exit Chrome.
+ CreateStatusTrayIcon();
+}
+
+void BackgroundModeManager::OnBackgroundAppUnloaded() {
+ // When a background app unloads, decrement our count and also end
+ // KeepAlive mode if appropriate.
+ background_app_count_--;
+ DCHECK(background_app_count_ >= 0);
+ if (background_app_count_ == 0 && IsBackgroundModeEnabled())
+ EndBackgroundMode();
+}
+
+void BackgroundModeManager::EndBackgroundMode() {
+ if (!in_background_mode_)
+ return;
+ in_background_mode_ = false;
+
+ // End KeepAlive mode and blow away our status tray icon.
+ BrowserList::EndKeepAlive();
+ RemoveStatusTrayIcon();
+}
+
+void BackgroundModeManager::OnBackgroundAppInstalled() {
+ // We're installing a background app. If this is the first background app
+ // being installed, make sure we are set to launch on startup.
+ if (IsBackgroundModeEnabled() && background_app_count_ == 0)
+ EnableLaunchOnStartup(true);
+}
+
+void BackgroundModeManager::OnBackgroundAppUninstalled() {
+ // When uninstalling a background app, disable launch on startup if it's the
+ // last one.
+ if (IsBackgroundModeEnabled() && background_app_count_ == 1)
+ 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)
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ new EnableLaunchOnStartupTask());
+ else
+ ChromeThread::PostTask(ChromeThread::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;
+ RegKey read_key(kBackgroundModeRegistryRootKey,
+ kBackgroundModeRegistrySubkey, KEY_READ);
+ RegKey write_key(kBackgroundModeRegistryRootKey,
+ kBackgroundModeRegistrySubkey, KEY_WRITE);
+ if (should_launch) {
+ FilePath executable;
+ if (!PathService::Get(base::FILE_EXE, &executable))
+ return;
+ if (read_key.ValueExists(key_name)) {
+ std::wstring current_value;
+ if (read_key.ReadValue(key_name, &current_value) &&
+ (current_value == executable.value()))
+ return;
+ }
+ if (!write_key.WriteValue(key_name, executable.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.
+#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
+ if (!status_tray_)
+ status_tray_ = profile_->GetStatusTray();
+#endif
+
+ // If the platform doesn't support status icons, or we've already created
+ // our status icon, just return.
+ if (!status_tray_ || status_icon_)
+ return;
+ status_icon_ = status_tray_->CreateStatusIcon();
+ if (!status_icon_)
+ return;
+
+ // Set the image and add ourselves as a click observer on it
+ SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_STATUS_TRAY_ICON);
+ status_icon_->SetImage(*bitmap);
+ status_icon_->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+
+ // Create a context menu item for Chrome.
+ menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(this);
+ menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+
+#if defined(TOOLKIT_GTK)
+ string16 preferences = gtk_util::GetStockPreferencesMenuLabel();
+ if (preferences.empty())
+ menu->AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
+ else
+ menu->AddItem(IDC_OPTIONS, preferences);
+#else
+ menu->AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
+#endif
+ menu->AddSeparator();
+ menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
+ status_icon_->SetContextMenu(menu);
+}
+
+bool BackgroundModeManager::IsCommandIdChecked(int command_id) const {
+ return false;
+}
+
+bool BackgroundModeManager::IsCommandIdEnabled(int command_id) const {
+ // For now, we do not support disabled items.
+ return true;
+}
+
+bool BackgroundModeManager::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ // No accelerators for status icon context menus.
+ return false;
+}
+
+void BackgroundModeManager::RemoveStatusTrayIcon() {
+ if (status_icon_)
+ status_tray_->RemoveStatusIcon(status_icon_);
+ status_icon_ = NULL;
+}
+
+
+void BackgroundModeManager::ExecuteCommand(int item) {
+ switch (item) {
+ case IDC_EXIT:
+ UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
+ BrowserList::CloseAllBrowsersAndExit();
+ break;
+ case IDC_ABOUT:
+ GetBrowserWindow()->OpenAboutChromeDialog();
+ break;
+ case IDC_OPTIONS:
+ GetBrowserWindow()->OpenOptionsDialog();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+Browser* BackgroundModeManager::GetBrowserWindow() {
+ Browser* browser = BrowserList::GetLastActive();
+ if (!browser) {
+ Browser::OpenEmptyWindow(profile_);
+ browser = BrowserList::GetLastActive();
+ }
+ return browser;
+}
+
+// static
+void BackgroundModeManager::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterBooleanPref(prefs::kBackgroundModeEnabled, true);
+ prefs->RegisterBooleanPref(prefs::kLaunchOnStartupResetAllowed, false);
+}
diff --git a/chrome/browser/background_mode_manager.h b/chrome/browser/background_mode_manager.h
new file mode 100644
index 0000000..52f37da
--- /dev/null
+++ b/chrome/browser/background_mode_manager.h
@@ -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.
+
+#ifndef CHROME_BROWSER_BACKGROUND_MODE_MANAGER_H_
+#define CHROME_BROWSER_BACKGROUND_MODE_MANAGER_H_
+#pragma once
+
+#include "app/menus/simple_menu_model.h"
+#include "base/gtest_prod_util.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/status_icons/status_icon.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class Browser;
+class Extension;
+class PrefService;
+class Profile;
+class StatusIcon;
+class StatusTray;
+
+// BackgroundModeManager is responsible for switching Chrome into and out of
+// "background mode" and for providing UI for the user to exit Chrome when there
+// are no open browser windows.
+//
+// Chrome enters background mode whenever there is an application with the
+// "background" permission installed and the appropriate user preference is
+// set (kBackgroundModeEnabled). This class monitors the set of installed/loaded
+// extensions to ensure that Chrome enters/exits background mode at the
+// appropriate time.
+//
+// When Chrome is in background mode, it will continue running even after the
+// last browser window is closed, until the user explicitly exits the app.
+// Additionally, when in background mode, Chrome will launch on OS login with
+// no open windows to allow apps with the "background" permission to run in the
+// background.
+class BackgroundModeManager
+ : private NotificationObserver,
+ private menus::SimpleMenuModel::Delegate {
+ public:
+ BackgroundModeManager(Profile* profile, CommandLine* command_line);
+ virtual ~BackgroundModeManager();
+
+ static void RegisterUserPrefs(PrefService* prefs);
+ private:
+ friend class TestBackgroundModeManager;
+ friend class BackgroundModeManagerTest;
+ FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
+ BackgroundAppLoadUnload);
+ FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
+ BackgroundAppInstallUninstall);
+ FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
+ BackgroundPrefDisabled);
+ FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
+ BackgroundPrefDynamicDisable);
+ FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
+ BackgroundPrefDynamicEnable);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // SimpleMenuModel::Delegate implementation.
+ 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);
+
+ // Called when an extension is loaded to manage count of background apps.
+ void OnBackgroundAppLoaded();
+
+ // Called when an extension is unloaded to manage count of background apps.
+ void OnBackgroundAppUnloaded();
+
+ // Invoked when an extension is installed so we can ensure that
+ // launch-on-startup is enabled if appropriate.
+ void OnBackgroundAppInstalled();
+
+ // Invoked when an extension is uninstalled so we can ensure that
+ // launch-on-startup is disabled if appropriate.
+ void OnBackgroundAppUninstalled();
+
+ // Invoked when the kBackgroundModeEnabled preference has changed.
+ void OnBackgroundModePrefChanged();
+
+ // Returns true if the passed extension is a background app.
+ bool IsBackgroundApp(Extension* extension);
+
+ // Returns true if the background mode preference is enabled
+ bool IsBackgroundModeEnabled();
+
+ // 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);
+
+ // Invoked to put Chrome in KeepAlive mode - chrome runs in the background
+ // and has a status bar icon.
+ void StartBackgroundMode();
+
+ // Invoked to take Chrome out of KeepAlive mode - chrome stops running in
+ // the background and removes its status bar icon.
+ void EndBackgroundMode();
+
+ // Create a status tray icon to allow the user to shutdown Chrome when running
+ // in background mode. Virtual to enable testing.
+ virtual void CreateStatusTrayIcon();
+
+ // Removes the status tray icon because we are exiting background mode.
+ // Virtual to enable testing.
+ virtual void RemoveStatusTrayIcon();
+
+ // Returns a browser window, or creates one if none are open. Used by
+ // operations (like displaying the preferences dialog) that require a Browser
+ // window.
+ Browser* GetBrowserWindow();
+
+ NotificationRegistrar registrar_;
+
+ // The parent profile for this object.
+ Profile* profile_;
+
+ // The number of background apps currently loaded.
+ int background_app_count_;
+
+ // Set to true when we are running in background mode. Allows us to track our
+ // current background state so we can take the appropriate action when the
+ // user disables/enables background mode via preferences.
+ bool in_background_mode_;
+
+ // Reference to our status tray (owned by our parent profile). If null, the
+ // platform doesn't support status icons.
+ StatusTray* status_tray_;
+
+ // Reference to our status icon (if any) - owned by the StatusTray.
+ StatusIcon* status_icon_;
+
+ // Ensure observed preferences are properly cleaned up.
+ PrefChangeRegistrar pref_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundModeManager);
+};
+
+#endif // CHROME_BROWSER_BACKGROUND_MODE_MANAGER_H_
diff --git a/chrome/browser/background_mode_manager_unittest.cc b/chrome/browser/background_mode_manager_unittest.cc
new file mode 100644
index 0000000..075db81
--- /dev/null
+++ b/chrome/browser/background_mode_manager_unittest.cc
@@ -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.
+
+#include "base/command_line.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/background_mode_manager.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::InSequence;
+
+class BackgroundModeManagerTest : public testing::Test {
+ public:
+ BackgroundModeManagerTest() {}
+ ~BackgroundModeManagerTest() {}
+ void SetUp() {
+ command_line_.reset(new CommandLine(CommandLine::ARGUMENTS_ONLY));
+ command_line_->AppendSwitch(switches::kEnableBackgroundMode);
+ }
+ scoped_ptr<CommandLine> command_line_;
+};
+
+class TestBackgroundModeManager : public BackgroundModeManager {
+ public:
+ TestBackgroundModeManager(Profile* profile, CommandLine* cl)
+ : BackgroundModeManager(profile, cl) {
+ }
+ MOCK_METHOD1(EnableLaunchOnStartup, void(bool));
+ MOCK_METHOD0(CreateStatusTrayIcon, void());
+ MOCK_METHOD0(RemoveStatusTrayIcon, void());
+};
+
+TEST_F(BackgroundModeManagerTest, BackgroundAppLoadUnload) {
+ InSequence s;
+ TestingProfile profile;
+ TestBackgroundModeManager manager(&profile, command_line_.get());
+ EXPECT_CALL(manager, CreateStatusTrayIcon());
+ EXPECT_CALL(manager, RemoveStatusTrayIcon());
+ EXPECT_FALSE(BrowserList::WillKeepAlive());
+ // Call to AppLoaded() will cause the status tray to be created, then call to
+ // unloaded will result in call to remove the icon.
+ manager.OnBackgroundAppLoaded();
+ EXPECT_TRUE(BrowserList::WillKeepAlive());
+ manager.OnBackgroundAppUnloaded();
+ EXPECT_FALSE(BrowserList::WillKeepAlive());
+}
+
+TEST_F(BackgroundModeManagerTest, BackgroundAppInstallUninstall) {
+ InSequence s;
+ TestingProfile profile;
+ TestBackgroundModeManager manager(&profile, command_line_.get());
+ // Call to AppInstalled() will cause chrome to be set to launch on startup,
+ // and call to AppUninstalling() set chrome to not launch on startup.
+ EXPECT_CALL(manager, EnableLaunchOnStartup(true));
+ EXPECT_CALL(manager, CreateStatusTrayIcon());
+ EXPECT_CALL(manager, EnableLaunchOnStartup(false));
+ EXPECT_CALL(manager, RemoveStatusTrayIcon());
+ manager.OnBackgroundAppInstalled();
+ manager.OnBackgroundAppLoaded();
+ manager.OnBackgroundAppUninstalled();
+ manager.OnBackgroundAppUnloaded();
+}
+
+TEST_F(BackgroundModeManagerTest, BackgroundPrefDisabled) {
+ InSequence s;
+ TestingProfile profile;
+ profile.GetPrefs()->SetBoolean(prefs::kBackgroundModeEnabled, false);
+ TestBackgroundModeManager manager(&profile, command_line_.get());
+ // Should not change launch on startup status when installing/uninstalling
+ // if background mode is disabled.
+ EXPECT_CALL(manager, EnableLaunchOnStartup(true)).Times(0);
+ EXPECT_CALL(manager, CreateStatusTrayIcon()).Times(0);
+ manager.OnBackgroundAppInstalled();
+ manager.OnBackgroundAppLoaded();
+ EXPECT_FALSE(BrowserList::WillKeepAlive());
+ manager.OnBackgroundAppUninstalled();
+ manager.OnBackgroundAppUnloaded();
+}
+
+TEST_F(BackgroundModeManagerTest, BackgroundPrefDynamicDisable) {
+ InSequence s;
+ TestingProfile profile;
+ TestBackgroundModeManager manager(&profile, command_line_.get());
+ EXPECT_CALL(manager, EnableLaunchOnStartup(true));
+ EXPECT_CALL(manager, CreateStatusTrayIcon());
+ EXPECT_CALL(manager, EnableLaunchOnStartup(false));
+ EXPECT_CALL(manager, RemoveStatusTrayIcon());
+ manager.OnBackgroundAppInstalled();
+ manager.OnBackgroundAppLoaded();
+ EXPECT_TRUE(BrowserList::WillKeepAlive());
+ // Disable status on the fly.
+ profile.GetPrefs()->SetBoolean(prefs::kBackgroundModeEnabled, false);
+ // Manually notify background mode manager that pref has changed
+ manager.OnBackgroundModePrefChanged();
+ EXPECT_FALSE(BrowserList::WillKeepAlive());
+}
+
+TEST_F(BackgroundModeManagerTest, BackgroundPrefDynamicEnable) {
+ InSequence s;
+ TestingProfile profile;
+ TestBackgroundModeManager manager(&profile, command_line_.get());
+ profile.GetPrefs()->SetBoolean(prefs::kBackgroundModeEnabled, false);
+ EXPECT_CALL(manager, EnableLaunchOnStartup(true));
+ EXPECT_CALL(manager, CreateStatusTrayIcon());
+ manager.OnBackgroundAppInstalled();
+ manager.OnBackgroundAppLoaded();
+ EXPECT_FALSE(BrowserList::WillKeepAlive());
+ // Enable status on the fly.
+ profile.GetPrefs()->SetBoolean(prefs::kBackgroundModeEnabled, true);
+ EXPECT_TRUE(BrowserList::WillKeepAlive());
+}
diff --git a/chrome/browser/blocked_plugin_manager.cc b/chrome/browser/blocked_plugin_manager.cc
new file mode 100644
index 0000000..2da3653
--- /dev/null
+++ b/chrome/browser/blocked_plugin_manager.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/blocked_plugin_manager.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/metrics/user_metrics.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/common/chrome_switches.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+BlockedPluginManager::BlockedPluginManager(TabContents* tab_contents)
+ : ConfirmInfoBarDelegate(tab_contents),
+ tab_contents_(tab_contents) { }
+
+void BlockedPluginManager::OnNonSandboxedPluginBlocked(
+ const std::string& plugin,
+ const string16& name) {
+ plugin_ = plugin;
+ name_ = name;
+ UserMetrics::RecordAction(UserMetricsAction("ClickToPlay_InfobarShown"));
+ tab_contents_->AddInfoBar(this);
+}
+
+void BlockedPluginManager::OnBlockedPluginLoaded() {
+ tab_contents_->RemoveInfoBar(this);
+}
+
+int BlockedPluginManager::GetButtons() const {
+ int buttons = BUTTON_OK;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings))
+ buttons |= BUTTON_CANCEL;
+ return buttons;
+}
+
+string16 BlockedPluginManager::GetButtonLabel(InfoBarButton button) const {
+ if (button == BUTTON_OK)
+ return l10n_util::GetStringUTF16(IDS_PLUGIN_LOAD_SHORT);
+ if (button == BUTTON_CANCEL)
+ return l10n_util::GetStringUTF16(IDS_BLOCKED_PLUGINS_UNBLOCK_SHORT);
+ return ConfirmInfoBarDelegate::GetButtonLabel(button);
+}
+
+string16 BlockedPluginManager::GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED_PROMPT, name_);
+}
+
+string16 BlockedPluginManager::GetLinkText() {
+ return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
+}
+
+SkBitmap* BlockedPluginManager::GetIcon() const {
+ return ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_INFOBAR_PLUGIN_INSTALL);
+}
+
+bool BlockedPluginManager::Accept() {
+ UserMetrics::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Infobar"));
+ tab_contents_->render_view_host()->LoadBlockedPlugins();
+ return true;
+}
+
+bool BlockedPluginManager::Cancel() {
+ DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings));
+ UserMetrics::RecordAction(UserMetricsAction("ClickToPlay_AllowAlways"));
+ tab_contents_->profile()->GetHostContentSettingsMap()->AddExceptionForURL(
+ tab_contents_->GetURL(), CONTENT_SETTINGS_TYPE_PLUGINS, plugin_,
+ CONTENT_SETTING_ALLOW);
+ tab_contents_->render_view_host()->LoadBlockedPlugins();
+ return true;
+}
+
+void BlockedPluginManager::InfoBarDismissed() {
+ UserMetrics::RecordAction(UserMetricsAction("ClickToPlay_Dismiss_Infobar"));
+}
+
+bool BlockedPluginManager::LinkClicked(WindowOpenDisposition disposition) {
+ // TODO(bauerb): Navigate to a help page explaining why we blocked the plugin,
+ // once we have one.
+ return false;
+}
diff --git a/chrome/browser/blocked_plugin_manager.h b/chrome/browser/blocked_plugin_manager.h
new file mode 100644
index 0000000..fcabdb2
--- /dev/null
+++ b/chrome/browser/blocked_plugin_manager.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_BLOCKED_PLUGIN_MANAGER_H_
+#define CHROME_BROWSER_BLOCKED_PLUGIN_MANAGER_H_
+
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/tab_contents/infobar_delegate.h"
+
+class TabContents;
+
+class BlockedPluginManager : public RenderViewHostDelegate::BlockedPlugin,
+ public ConfirmInfoBarDelegate {
+ public:
+ explicit BlockedPluginManager(TabContents* tab_contents);
+
+ virtual void OnNonSandboxedPluginBlocked(const std::string& plugin,
+ const string16& name);
+ virtual void OnBlockedPluginLoaded();
+
+ // ConfirmInfoBarDelegate methods
+ virtual int GetButtons() const;
+ virtual string16 GetButtonLabel(InfoBarButton button) const;
+ virtual string16 GetMessageText() const;
+ virtual string16 GetLinkText();
+ virtual SkBitmap* GetIcon() const;
+ virtual bool Accept();
+ virtual bool Cancel();
+ virtual void InfoBarDismissed();
+ virtual bool LinkClicked(WindowOpenDisposition disposition);
+
+ private:
+ // Owns us.
+ TabContents* tab_contents_;
+ string16 name_;
+ std::string plugin_;
+};
+
+#endif // CHROME_BROWSER_BLOCKED_PLUGIN_MANAGER_H_
diff --git a/chrome/browser/blocked_popup_container.cc b/chrome/browser/blocked_popup_container.cc
index ae52604..d349314 100644
--- a/chrome/browser/blocked_popup_container.cc
+++ b/chrome/browser/blocked_popup_container.cc
@@ -5,10 +5,21 @@
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "gfx/rect.h"
// static
const size_t BlockedPopupContainer::kImpossibleNumberOfPopups = 30;
+struct BlockedPopupContainer::BlockedPopup {
+ BlockedPopup(TabContents* tab_contents,
+ const gfx::Rect& bounds)
+ : tab_contents(tab_contents), bounds(bounds) {
+ }
+
+ TabContents* tab_contents;
+ gfx::Rect bounds;
+};
+
BlockedPopupContainer::BlockedPopupContainer(TabContents* owner)
: owner_(owner) {
}
@@ -110,7 +121,7 @@ void BlockedPopupContainer::MoveContents(TabContents* source,
}
}
-bool BlockedPopupContainer::IsPopup(TabContents* source) {
+bool BlockedPopupContainer::IsPopup(const TabContents* source) const {
return true;
}
diff --git a/chrome/browser/blocked_popup_container.h b/chrome/browser/blocked_popup_container.h
index 1cbc0f2..8fbd31a 100644
--- a/chrome/browser/blocked_popup_container.h
+++ b/chrome/browser/blocked_popup_container.h
@@ -9,6 +9,9 @@
#ifndef CHROME_BROWSER_BLOCKED_POPUP_CONTAINER_H_
#define CHROME_BROWSER_BLOCKED_POPUP_CONTAINER_H_
+#pragma once
+
+#include <vector>
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -57,8 +60,10 @@ class BlockedPopupContainer : public TabContentsDelegate {
const gfx::Rect& initial_position,
bool user_gesture);
- // Ignore activation requests from the TabContents we're blocking.
+ // Ignore activation/deactivation requests from the TabContents we're
+ // blocking.
virtual void ActivateContents(TabContents* contents) {}
+ virtual void DeactivateContents(TabContents* contents) {}
// Ignored; BlockedPopupContainer doesn't display a throbber.
virtual void LoadingStateChanged(TabContents* source) {}
@@ -70,7 +75,7 @@ class BlockedPopupContainer : public TabContentsDelegate {
virtual void MoveContents(TabContents* source, const gfx::Rect& new_bounds);
// Always returns true.
- virtual bool IsPopup(TabContents* source);
+ virtual bool IsPopup(const TabContents* source) const;
// Returns our |owner_|.
virtual TabContents* GetConstrainingContents(TabContents* source);
@@ -90,15 +95,7 @@ class BlockedPopupContainer : public TabContentsDelegate {
static const size_t kImpossibleNumberOfPopups;
protected:
- struct BlockedPopup {
- BlockedPopup(TabContents* tab_contents,
- const gfx::Rect& bounds)
- : tab_contents(tab_contents), bounds(bounds) {
- }
-
- TabContents* tab_contents;
- gfx::Rect bounds;
- };
+ struct BlockedPopup;
typedef std::vector<BlockedPopup> BlockedPopups;
private:
diff --git a/chrome/browser/bookmarks/base_bookmark_model_observer.h b/chrome/browser/bookmarks/base_bookmark_model_observer.h
index 8018b72..5a306aa 100644
--- a/chrome/browser/bookmarks/base_bookmark_model_observer.h
+++ b/chrome/browser/bookmarks/base_bookmark_model_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BASE_BOOKMARK_MODEL_OBSERVER_H_
#define CHROME_BROWSER_BOOKMARKS_BASE_BOOKMARK_MODEL_OBSERVER_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
diff --git a/chrome/browser/bookmarks/bookmark_codec.cc b/chrome/browser/bookmarks/bookmark_codec.cc
index e64c365..a4f0461 100644
--- a/chrome/browser/bookmarks/bookmark_codec.cc
+++ b/chrome/browser/bookmarks/bookmark_codec.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,6 +7,7 @@
#include <algorithm>
#include "app/l10n_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -15,18 +16,18 @@
using base::Time;
-const wchar_t* BookmarkCodec::kRootsKey = L"roots";
-const wchar_t* BookmarkCodec::kRootFolderNameKey = L"bookmark_bar";
-const wchar_t* BookmarkCodec::kOtherBookmarkFolderNameKey = L"other";
-const wchar_t* BookmarkCodec::kVersionKey = L"version";
-const wchar_t* BookmarkCodec::kChecksumKey = L"checksum";
-const wchar_t* BookmarkCodec::kIdKey = L"id";
-const wchar_t* BookmarkCodec::kTypeKey = L"type";
-const wchar_t* BookmarkCodec::kNameKey = L"name";
-const wchar_t* BookmarkCodec::kDateAddedKey = L"date_added";
-const wchar_t* BookmarkCodec::kURLKey = L"url";
-const wchar_t* BookmarkCodec::kDateModifiedKey = L"date_modified";
-const wchar_t* BookmarkCodec::kChildrenKey = L"children";
+const char* BookmarkCodec::kRootsKey = "roots";
+const char* BookmarkCodec::kRootFolderNameKey = "bookmark_bar";
+const char* BookmarkCodec::kOtherBookmarkFolderNameKey = "other";
+const char* BookmarkCodec::kVersionKey = "version";
+const char* BookmarkCodec::kChecksumKey = "checksum";
+const char* BookmarkCodec::kIdKey = "id";
+const char* BookmarkCodec::kTypeKey = "type";
+const char* BookmarkCodec::kNameKey = "name";
+const char* BookmarkCodec::kDateAddedKey = "date_added";
+const char* BookmarkCodec::kURLKey = "url";
+const char* BookmarkCodec::kDateModifiedKey = "date_modified";
+const char* BookmarkCodec::kChildrenKey = "children";
const char* BookmarkCodec::kTypeURL = "url";
const char* BookmarkCodec::kTypeFolder = "folder";
@@ -84,12 +85,12 @@ bool BookmarkCodec::Decode(BookmarkNode* bb_node,
Value* BookmarkCodec::EncodeNode(const BookmarkNode* node) {
DictionaryValue* value = new DictionaryValue();
- std::string id = Int64ToString(node->id());
+ std::string id = base::Int64ToString(node->id());
value->SetString(kIdKey, id);
- const string16& title = node->GetTitleAsString16();
- value->SetStringFromUTF16(kNameKey, title);
+ const string16& title = node->GetTitle();
+ value->SetString(kNameKey, title);
value->SetString(kDateAddedKey,
- Int64ToString(node->date_added().ToInternalValue()));
+ base::Int64ToString(node->date_added().ToInternalValue()));
if (node->type() == BookmarkNode::URL) {
value->SetString(kTypeKey, kTypeURL);
std::string url = node->GetURL().possibly_invalid_spec();
@@ -98,7 +99,7 @@ Value* BookmarkCodec::EncodeNode(const BookmarkNode* node) {
} else {
value->SetString(kTypeKey, kTypeFolder);
value->SetString(kDateModifiedKey,
- Int64ToString(node->date_group_modified().
+ base::Int64ToString(node->date_group_modified().
ToInternalValue()));
UpdateChecksumWithFolderNode(id, title);
@@ -156,9 +157,9 @@ bool BookmarkCodec::DecodeHelper(BookmarkNode* bb_node,
// the file.
bb_node->set_type(BookmarkNode::BOOKMARK_BAR);
other_folder_node->set_type(BookmarkNode::OTHER_NODE);
- bb_node->SetTitle(l10n_util::GetString(IDS_BOOMARK_BAR_FOLDER_NAME));
+ bb_node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_FOLDER_NAME));
other_folder_node->SetTitle(
- l10n_util::GetString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME));
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME));
return true;
}
@@ -192,7 +193,7 @@ bool BookmarkCodec::DecodeNode(const DictionaryValue& value,
int64 id = 0;
if (ids_valid_) {
if (!value.GetString(kIdKey, &id_string) ||
- !StringToInt64(id_string, &id) ||
+ !base::StringToInt64(id_string, &id) ||
ids_.count(id) != 0) {
ids_valid_ = false;
} else {
@@ -203,13 +204,14 @@ bool BookmarkCodec::DecodeNode(const DictionaryValue& value,
maximum_id_ = std::max(maximum_id_, id);
string16 title;
- value.GetStringAsUTF16(kNameKey, &title);
+ value.GetString(kNameKey, &title);
std::string date_added_string;
if (!value.GetString(kDateAddedKey, &date_added_string))
- date_added_string = Int64ToString(Time::Now().ToInternalValue());
- base::Time date_added = base::Time::FromInternalValue(
- StringToInt64(date_added_string));
+ date_added_string = base::Int64ToString(Time::Now().ToInternalValue());
+ int64 internal_time;
+ base::StringToInt64(date_added_string, &internal_time);
+ base::Time date_added = base::Time::FromInternalValue(internal_time);
#if !defined(OS_WIN)
// We changed the epoch for dates on Mac & Linux from 1970 to the Windows
// one of 1601. We assume any number we encounter from before 1970 is using
@@ -249,7 +251,7 @@ bool BookmarkCodec::DecodeNode(const DictionaryValue& value,
} else {
std::string last_modified_date;
if (!value.GetString(kDateModifiedKey, &last_modified_date))
- last_modified_date = Int64ToString(Time::Now().ToInternalValue());
+ last_modified_date = base::Int64ToString(Time::Now().ToInternalValue());
Value* child_values;
if (!value.Get(kChildrenKey, &child_values))
@@ -266,8 +268,9 @@ bool BookmarkCodec::DecodeNode(const DictionaryValue& value,
}
node->set_type(BookmarkNode::FOLDER);
- node->set_date_group_modified(Time::FromInternalValue(
- StringToInt64(last_modified_date)));
+ int64 internal_time;
+ base::StringToInt64(last_modified_date, &internal_time);
+ node->set_date_group_modified(Time::FromInternalValue(internal_time));
if (parent)
parent->Add(parent->GetChildCount(), node);
diff --git a/chrome/browser/bookmarks/bookmark_codec.h b/chrome/browser/bookmarks/bookmark_codec.h
index f1df31c..94c9213 100644
--- a/chrome/browser/bookmarks/bookmark_codec.h
+++ b/chrome/browser/bookmarks/bookmark_codec.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,12 +8,12 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_CODEC_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_CODEC_H_
+#pragma once
#include <set>
#include <string>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
#include "base/md5.h"
#include "base/string16.h"
@@ -72,18 +72,18 @@ class BookmarkCodec {
bool ids_reassigned() const { return ids_reassigned_; }
// Names of the various keys written to the Value.
- static const wchar_t* kRootsKey;
- static const wchar_t* kRootFolderNameKey;
- static const wchar_t* kOtherBookmarkFolderNameKey;
- static const wchar_t* kVersionKey;
- static const wchar_t* kChecksumKey;
- static const wchar_t* kIdKey;
- static const wchar_t* kTypeKey;
- static const wchar_t* kNameKey;
- static const wchar_t* kDateAddedKey;
- static const wchar_t* kURLKey;
- static const wchar_t* kDateModifiedKey;
- static const wchar_t* kChildrenKey;
+ static const char* kRootsKey;
+ static const char* kRootFolderNameKey;
+ static const char* kOtherBookmarkFolderNameKey;
+ static const char* kVersionKey;
+ static const char* kChecksumKey;
+ static const char* kIdKey;
+ static const char* kTypeKey;
+ static const char* kNameKey;
+ static const char* kDateAddedKey;
+ static const char* kURLKey;
+ static const char* kDateModifiedKey;
+ static const char* kChildrenKey;
// Possible values for kTypeKey.
static const char* kTypeURL;
diff --git a/chrome/browser/bookmarks/bookmark_codec_unittest.cc b/chrome/browser/bookmarks/bookmark_codec_unittest.cc
index 8272270..905b55a 100644
--- a/chrome/browser/bookmarks/bookmark_codec_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_codec_unittest.cc
@@ -1,9 +1,10 @@
-// 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.
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -13,16 +14,16 @@
namespace {
-const wchar_t kUrl1Title[] = L"url1";
-const wchar_t kUrl1Url[] = L"http://www.url1.com";
-const wchar_t kUrl2Title[] = L"url2";
-const wchar_t kUrl2Url[] = L"http://www.url2.com";
-const wchar_t kUrl3Title[] = L"url3";
-const wchar_t kUrl3Url[] = L"http://www.url3.com";
-const wchar_t kUrl4Title[] = L"url4";
-const wchar_t kUrl4Url[] = L"http://www.url4.com";
-const wchar_t kGroup1Title[] = L"group1";
-const wchar_t kGroup2Title[] = L"group2";
+const char kUrl1Title[] = "url1";
+const char kUrl1Url[] = "http://www.url1.com";
+const char kUrl2Title[] = "url2";
+const char kUrl2Url[] = "http://www.url2.com";
+const char kUrl3Title[] = "url3";
+const char kUrl3Url[] = "http://www.url3.com";
+const char kUrl4Title[] = "url4";
+const char kUrl4Url[] = "http://www.url4.com";
+const char kGroup1Title[] = "group1";
+const char kGroup2Title[] = "group2";
// Helper to get a mutable bookmark node.
static BookmarkNode* AsMutable(const BookmarkNode* node) {
@@ -37,22 +38,23 @@ class BookmarkCodecTest : public testing::Test {
BookmarkModel* CreateTestModel1() {
scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
- model->AddURL(bookmark_bar, 0, kUrl1Title, GURL(kUrl1Url));
+ model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
return model.release();
}
BookmarkModel* CreateTestModel2() {
scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
- model->AddURL(bookmark_bar, 0, kUrl1Title, GURL(kUrl1Url));
- model->AddURL(bookmark_bar, 1, kUrl2Title, GURL(kUrl2Url));
+ model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
+ model->AddURL(bookmark_bar, 1, ASCIIToUTF16(kUrl2Title), GURL(kUrl2Url));
return model.release();
}
BookmarkModel* CreateTestModel3() {
scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
- model->AddURL(bookmark_bar, 0, kUrl1Title, GURL(kUrl1Url));
- const BookmarkNode* group1 = model->AddGroup(bookmark_bar, 1, kGroup1Title);
- model->AddURL(group1, 0, kUrl2Title, GURL(kUrl2Url));
+ model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
+ const BookmarkNode* group1 = model->AddGroup(bookmark_bar, 1,
+ ASCIIToUTF16(kGroup1Title));
+ model->AddURL(group1, 0, ASCIIToUTF16(kUrl2Title), GURL(kUrl2Url));
return model.release();
}
@@ -200,9 +202,9 @@ TEST_F(BookmarkCodecTest, ChecksumManualEditTest) {
// Change something in the encoded value before decoding it.
DictionaryValue* child1_value;
GetBookmarksBarChildValue(value.get(), 0, &child1_value);
- std::wstring title;
+ std::string title;
ASSERT_TRUE(child1_value->GetString(BookmarkCodec::kNameKey, &title));
- child1_value->SetString(BookmarkCodec::kNameKey, title + L"1");
+ child1_value->SetString(BookmarkCodec::kNameKey, title + "1");
std::string dec_checksum;
scoped_ptr<BookmarkModel> decoded_model1(DecodeHelper(
@@ -244,8 +246,10 @@ TEST_F(BookmarkCodecTest, ChecksumManualEditIDsTest) {
// add a few extra nodes to bookmark model and make sure IDs are still uniuqe.
const BookmarkNode* bb_node = decoded_model->GetBookmarkBarNode();
- decoded_model->AddURL(bb_node, 0, L"new url1", GURL(L"http://newurl1.com"));
- decoded_model->AddURL(bb_node, 0, L"new url2", GURL(L"http://newurl2.com"));
+ decoded_model->AddURL(bb_node, 0, ASCIIToUTF16("new url1"),
+ GURL("http://newurl1.com"));
+ decoded_model->AddURL(bb_node, 0, ASCIIToUTF16("new url2"),
+ GURL("http://newurl2.com"));
ExpectIDsUnique(decoded_model.get());
}
@@ -266,10 +270,12 @@ TEST_F(BookmarkCodecTest, PersistIDsTest) {
// ID persistence is working properly.
const BookmarkNode* bookmark_bar = decoded_model.GetBookmarkBarNode();
decoded_model.AddURL(
- bookmark_bar, bookmark_bar->GetChildCount(), kUrl3Title, GURL(kUrl3Url));
+ bookmark_bar, bookmark_bar->GetChildCount(), ASCIIToUTF16(kUrl3Title),
+ GURL(kUrl3Url));
const BookmarkNode* group2_node = decoded_model.AddGroup(
- bookmark_bar, bookmark_bar->GetChildCount(), kGroup2Title);
- decoded_model.AddURL(group2_node, 0, kUrl4Title, GURL(kUrl4Url));
+ bookmark_bar, bookmark_bar->GetChildCount(), ASCIIToUTF16(kGroup2Title));
+ decoded_model.AddURL(group2_node, 0, ASCIIToUTF16(kUrl4Title),
+ GURL(kUrl4Url));
BookmarkCodec encoder2;
scoped_ptr<Value> model_value2(encoder2.Encode(&decoded_model));
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_controller.cc b/chrome/browser/bookmarks/bookmark_context_menu_controller.cc
index 96f5b1d..bc6ef28 100644
--- a/chrome/browser/bookmarks/bookmark_context_menu_controller.cc
+++ b/chrome/browser/bookmarks/bookmark_context_menu_controller.cc
@@ -13,7 +13,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_controller.h b/chrome/browser/bookmarks/bookmark_context_menu_controller.h
index 5169c63..76ffaa4 100644
--- a/chrome/browser/bookmarks/bookmark_context_menu_controller.h
+++ b/chrome/browser/bookmarks/bookmark_context_menu_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_CONTEXT_MENU_CONTROLLER_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_CONTEXT_MENU_CONTROLLER_H_
+#pragma once
#include <vector>
@@ -12,7 +13,6 @@
#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
#include "gfx/native_widget_types.h"
-class Browser;
class PageNavigator;
class Profile;
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc b/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc
index 26dd65e..8ef7362 100644
--- a/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc
@@ -3,11 +3,12 @@
// found in the LICENSE file.
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.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/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/common/pref_names.h"
@@ -86,18 +87,18 @@ class BookmarkContextMenuControllerTest : public testing::Test {
void AddTestData() {
std::string test_base = "file:///c:/tmp/";
- model_->AddURL(model_->GetBookmarkBarNode(), 0, L"a",
+ model_->AddURL(model_->GetBookmarkBarNode(), 0, ASCIIToUTF16("a"),
GURL(test_base + "a"));
const BookmarkNode* f1 =
- model_->AddGroup(model_->GetBookmarkBarNode(), 1, L"F1");
- model_->AddURL(f1, 0, L"f1a", GURL(test_base + "f1a"));
- const BookmarkNode* f11 = model_->AddGroup(f1, 1, L"F11");
- model_->AddURL(f11, 0, L"f11a", GURL(test_base + "f11a"));
- model_->AddGroup(model_->GetBookmarkBarNode(), 2, L"F2");
- model_->AddGroup(model_->GetBookmarkBarNode(), 3, L"F3");
+ model_->AddGroup(model_->GetBookmarkBarNode(), 1, ASCIIToUTF16("F1"));
+ model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
+ const BookmarkNode* f11 = model_->AddGroup(f1, 1, ASCIIToUTF16("F11"));
+ model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 2, ASCIIToUTF16("F2"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 3, ASCIIToUTF16("F3"));
const BookmarkNode* f4 =
- model_->AddGroup(model_->GetBookmarkBarNode(), 4, L"F4");
- model_->AddURL(f4, 0, L"f4a", GURL(test_base + "f4a"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 4, ASCIIToUTF16("F4"));
+ model_->AddURL(f4, 0, ASCIIToUTF16("f4a"), GURL(test_base + "f4a"));
}
};
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.cc b/chrome/browser/bookmarks/bookmark_drag_data.cc
index b691abf..44ab58e 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.cc
+++ b/chrome/browser/bookmarks/bookmark_drag_data.cc
@@ -8,6 +8,7 @@
#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"
#if defined(OS_MACOSX)
#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
@@ -20,15 +21,21 @@
const char* BookmarkDragData::kClipboardFormatString =
"chromium/x-bookmark-entries";
+BookmarkDragData::Element::Element() : is_url(false), id_(0) {
+}
+
BookmarkDragData::Element::Element(const BookmarkNode* node)
: is_url(node->is_url()),
url(node->GetURL()),
- title(node->GetTitleAsString16()),
+ title(node->GetTitle()),
id_(node->id()) {
for (int i = 0; i < node->GetChildCount(); ++i)
children.push_back(Element(node->GetChild(i)));
}
+BookmarkDragData::Element::~Element() {
+}
+
void BookmarkDragData::Element::WriteToPickle(Pickle* pickle) const {
pickle->WriteBool(is_url);
pickle->WriteString(url.spec());
@@ -83,6 +90,9 @@ OSExchangeData::CustomFormat BookmarkDragData::GetBookmarkCustomFormat() {
}
#endif
+BookmarkDragData::BookmarkDragData() {
+}
+
BookmarkDragData::BookmarkDragData(const BookmarkNode* node) {
elements.push_back(Element(node));
}
@@ -92,6 +102,9 @@ BookmarkDragData::BookmarkDragData(
ReadFromVector(nodes);
}
+BookmarkDragData::~BookmarkDragData() {
+}
+
bool BookmarkDragData::ReadFromVector(
const std::vector<const BookmarkNode*>& nodes) {
Clear();
@@ -207,7 +220,7 @@ void BookmarkDragData::Write(Profile* profile, OSExchangeData* data) const {
// clipboard.
if (elements.size() == 1 && elements[0].is_url) {
if (elements[0].url.SchemeIs(chrome::kJavaScriptScheme)) {
- data->SetString(ASCIIToWide(elements[0].url.spec()));
+ data->SetString(UTF8ToWide(elements[0].url.spec()));
} else {
data->SetURL(elements[0].url, UTF16ToWide(elements[0].title));
}
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.h b/chrome/browser/bookmarks/bookmark_drag_data.h
index b4b65da..d9e52e2 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.h
+++ b/chrome/browser/bookmarks/bookmark_drag_data.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_H_
+#pragma once
-#include <string>
#include <vector>
#include "base/file_path.h"
@@ -16,9 +16,7 @@
#include "app/os_exchange_data.h"
#endif
-class BookmarkModel;
class BookmarkNode;
-class OSExchangeData;
class Pickle;
class Profile;
@@ -46,9 +44,9 @@ class Profile;
struct BookmarkDragData {
// Element represents a single node.
struct Element {
+ Element();
explicit Element(const BookmarkNode* node);
-
- Element() : is_url(false), id_(0) {}
+ ~Element();
// If true, this element represents a URL.
bool is_url;
@@ -76,7 +74,7 @@ struct BookmarkDragData {
int64 id_;
};
- BookmarkDragData() { }
+ BookmarkDragData();
#if defined(TOOLKIT_VIEWS)
static OSExchangeData::CustomFormat GetBookmarkCustomFormat();
@@ -86,6 +84,8 @@ struct BookmarkDragData {
explicit BookmarkDragData(const BookmarkNode* node);
explicit BookmarkDragData(const std::vector<const BookmarkNode*>& nodes);
+ ~BookmarkDragData();
+
// Reads bookmarks from the given vector.
bool ReadFromVector(const std::vector<const BookmarkNode*>& nodes);
@@ -96,7 +96,8 @@ struct BookmarkDragData {
void WriteToClipboard(Profile* profile) const;
// Reads bookmarks from the general copy/paste clipboard. Prefers data
- // written via WriteToClipboard but will also attempt to read a plain bookmark.
+ // written via WriteToClipboard but will also attempt to read a plain
+ // bookmark.
bool ReadFromClipboard();
#if defined(OS_MACOSX)
// Reads bookmarks that are being dragged from the drag and drop
diff --git a/chrome/browser/bookmarks/bookmark_drag_data_unittest.cc b/chrome/browser/bookmarks/bookmark_drag_data_unittest.cc
index 55fc3b5..434a537 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_drag_data_unittest.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,6 +6,8 @@
#include "app/os_exchange_data_provider_win.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
@@ -62,8 +64,8 @@ TEST_F(BookmarkDragDataTest, JustURL) {
EXPECT_TRUE(drag_data.is_valid());
ASSERT_EQ(1, drag_data.elements.size());
EXPECT_TRUE(drag_data.elements[0].is_url);
- EXPECT_TRUE(drag_data.elements[0].url == url);
- EXPECT_TRUE(drag_data.elements[0].title == title);
+ EXPECT_EQ(url, drag_data.elements[0].url);
+ EXPECT_EQ(title, drag_data.elements[0].title);
EXPECT_EQ(0, drag_data.elements[0].children.size());
}
@@ -76,14 +78,14 @@ TEST_F(BookmarkDragDataTest, URL) {
BookmarkModel* model = profile.GetBookmarkModel();
const BookmarkNode* root = model->GetBookmarkBarNode();
GURL url(GURL("http://foo.com"));
- const std::wstring title(L"blah");
+ const string16 title(ASCIIToUTF16("blah"));
const BookmarkNode* node = model->AddURL(root, 0, title, url);
BookmarkDragData drag_data(node);
EXPECT_TRUE(drag_data.is_valid());
ASSERT_EQ(1, drag_data.elements.size());
EXPECT_TRUE(drag_data.elements[0].is_url);
- EXPECT_TRUE(drag_data.elements[0].url == url);
- EXPECT_EQ(title, drag_data.elements[0].title);
+ EXPECT_EQ(url, drag_data.elements[0].url);
+ EXPECT_EQ(title, WideToUTF16Hack(drag_data.elements[0].title));
OSExchangeData data;
drag_data.Write(&profile, &data);
@@ -94,19 +96,19 @@ TEST_F(BookmarkDragDataTest, URL) {
EXPECT_TRUE(read_data.is_valid());
ASSERT_EQ(1, read_data.elements.size());
EXPECT_TRUE(read_data.elements[0].is_url);
- EXPECT_TRUE(read_data.elements[0].url == url);
+ EXPECT_EQ(url, read_data.elements[0].url);
EXPECT_EQ(title, read_data.elements[0].title);
EXPECT_TRUE(read_data.GetFirstNode(&profile) == node);
// Make sure asking for the node with a different profile returns NULL.
- TestingProfile profile2(1);
+ TestingProfile profile2;
EXPECT_TRUE(read_data.GetFirstNode(&profile2) == NULL);
// Writing should also put the URL and title on the clipboard.
GURL read_url;
std::wstring read_title;
EXPECT_TRUE(data2.GetURLAndTitle(&read_url, &read_title));
- EXPECT_TRUE(read_url == url);
+ EXPECT_EQ(url, read_url);
EXPECT_EQ(title, read_title);
}
@@ -118,14 +120,14 @@ TEST_F(BookmarkDragDataTest, Group) {
profile.SetID(L"id");
BookmarkModel* model = profile.GetBookmarkModel();
const BookmarkNode* root = model->GetBookmarkBarNode();
- const BookmarkNode* g1 = model->AddGroup(root, 0, L"g1");
- const BookmarkNode* g11 = model->AddGroup(g1, 0, L"g11");
- const BookmarkNode* g12 = model->AddGroup(g1, 0, L"g12");
+ const BookmarkNode* g1 = model->AddGroup(root, 0, ASCIIToUTF16("g1"));
+ const BookmarkNode* g11 = model->AddGroup(g1, 0, ASCIIToUTF16("g11"));
+ const BookmarkNode* g12 = model->AddGroup(g1, 0, ASCIIToUTF16("g12"));
BookmarkDragData drag_data(g12);
EXPECT_TRUE(drag_data.is_valid());
ASSERT_EQ(1, drag_data.elements.size());
- EXPECT_EQ(g12->GetTitle(), drag_data.elements[0].title);
+ EXPECT_EQ(g12->GetTitle(), WideToUTF16Hack(drag_data.elements[0].title));
EXPECT_FALSE(drag_data.elements[0].is_url);
OSExchangeData data;
@@ -137,7 +139,7 @@ TEST_F(BookmarkDragDataTest, Group) {
EXPECT_TRUE(read_data.Read(data2));
EXPECT_TRUE(read_data.is_valid());
ASSERT_EQ(1, read_data.elements.size());
- EXPECT_EQ(g12->GetTitle(), read_data.elements[0].title);
+ EXPECT_EQ(g12->GetTitle(), WideToUTF16Hack(read_data.elements[0].title));
EXPECT_FALSE(read_data.elements[0].is_url);
// We should get back the same node when asking for the same profile.
@@ -145,7 +147,7 @@ TEST_F(BookmarkDragDataTest, Group) {
EXPECT_TRUE(g12 == r_g12);
// A different profile should return NULL for the node.
- TestingProfile profile2(1);
+ TestingProfile profile2;
EXPECT_TRUE(read_data.GetFirstNode(&profile2) == NULL);
}
@@ -157,10 +159,10 @@ TEST_F(BookmarkDragDataTest, GroupWithChild) {
profile.BlockUntilBookmarkModelLoaded();
BookmarkModel* model = profile.GetBookmarkModel();
const BookmarkNode* root = model->GetBookmarkBarNode();
- const BookmarkNode* group = model->AddGroup(root, 0, L"g1");
+ const BookmarkNode* group = model->AddGroup(root, 0, ASCIIToUTF16("g1"));
GURL url(GURL("http://foo.com"));
- const std::wstring title(L"blah2");
+ const string16 title(ASCIIToUTF16("blah2"));
model->AddURL(group, 0, title, url);
@@ -179,8 +181,8 @@ TEST_F(BookmarkDragDataTest, GroupWithChild) {
read_data.elements[0].children[0];
EXPECT_TRUE(read_child.is_url);
- EXPECT_EQ(title, read_child.title);
- EXPECT_TRUE(url == read_child.url);
+ EXPECT_EQ(title, WideToUTF16Hack(read_child.title));
+ EXPECT_EQ(url, read_child.url);
EXPECT_TRUE(read_child.is_url);
// And make sure we get the node back.
@@ -196,10 +198,10 @@ TEST_F(BookmarkDragDataTest, MultipleNodes) {
profile.BlockUntilBookmarkModelLoaded();
BookmarkModel* model = profile.GetBookmarkModel();
const BookmarkNode* root = model->GetBookmarkBarNode();
- const BookmarkNode* group = model->AddGroup(root, 0, L"g1");
+ const BookmarkNode* group = model->AddGroup(root, 0, ASCIIToUTF16("g1"));
GURL url(GURL("http://foo.com"));
- const std::wstring title(L"blah2");
+ const string16 title(ASCIIToUTF16("blah2"));
const BookmarkNode* url_node = model->AddURL(group, 0, title, url);
@@ -226,7 +228,7 @@ TEST_F(BookmarkDragDataTest, MultipleNodes) {
const BookmarkDragData::Element& read_url = read_data.elements[1];
EXPECT_TRUE(read_url.is_url);
- EXPECT_EQ(title, read_url.title);
+ EXPECT_EQ(title, WideToUTF16Hack(read_url.title));
EXPECT_EQ(0, read_url.children.size());
// And make sure we get the node back.
diff --git a/chrome/browser/bookmarks/bookmark_drop_info.cc b/chrome/browser/bookmarks/bookmark_drop_info.cc
index e6032b5..9a6106d 100644
--- a/chrome/browser/bookmarks/bookmark_drop_info.cc
+++ b/chrome/browser/bookmarks/bookmark_drop_info.cc
@@ -22,6 +22,9 @@ BookmarkDropInfo::BookmarkDropInfo(gfx::NativeWindow wnd, int top_margin)
scroll_up_(false) {
}
+BookmarkDropInfo::~BookmarkDropInfo() {
+}
+
void BookmarkDropInfo::Update(const views::DropTargetEvent& event) {
source_operations_ = event.GetSourceOperations();
is_control_down_ = event.IsControlDown();
diff --git a/chrome/browser/bookmarks/bookmark_drop_info.h b/chrome/browser/bookmarks/bookmark_drop_info.h
index e09cf9c..358a0f5 100644
--- a/chrome/browser/bookmarks/bookmark_drop_info.h
+++ b/chrome/browser/bookmarks/bookmark_drop_info.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_DROP_INFO_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_DROP_INFO_H_
+#pragma once
#include "base/basictypes.h"
#include "base/timer.h"
@@ -21,7 +22,7 @@ class DropTargetEvent;
class BookmarkDropInfo {
public:
BookmarkDropInfo(gfx::NativeWindow hwnd, int top_margin);
- virtual ~BookmarkDropInfo() {}
+ virtual ~BookmarkDropInfo();
// Invoke this from OnDragUpdated. It resets source_operations,
// is_control_down, last_y and updates the autoscroll timer as necessary.
diff --git a/chrome/browser/bookmarks/bookmark_editor.h b/chrome/browser/bookmarks/bookmark_editor.h
index a1dbcf8..63d3ccf 100644
--- a/chrome/browser/bookmarks/bookmark_editor.h
+++ b/chrome/browser/bookmarks/bookmark_editor.h
@@ -4,11 +4,12 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_EDITOR_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_EDITOR_H_
+#pragma once
-#include <string>
#include <utility>
#include <vector>
+#include "base/string16.h"
#include "gfx/native_widget_types.h"
class BookmarkNode;
@@ -42,12 +43,9 @@ class BookmarkEditor {
NEW_FOLDER
};
- EditDetails() : type(NEW_URL), existing_node(NULL) {}
-
- explicit EditDetails(const BookmarkNode* node)
- : type(EXISTING_NODE),
- existing_node(node) {
- }
+ EditDetails();
+ explicit EditDetails(const BookmarkNode* node);
+ ~EditDetails();
// See description of enum value for details.
Type type;
@@ -57,7 +55,7 @@ class BookmarkEditor {
// If type == NEW_FOLDER, this is the urls/title pairs to add to the
// folder.
- std::vector<std::pair<GURL, std::wstring> > urls;
+ std::vector<std::pair<GURL, string16> > urls;
};
// Shows the bookmark editor. The bookmark editor allows editing an
diff --git a/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc b/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc
index 4966c7c..22a7352 100644
--- a/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc
+++ b/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc
@@ -5,6 +5,8 @@
#include "chrome/browser/bookmarks/bookmark_folder_editor_controller.h"
#include "app/l10n_util.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/profile.h"
#include "grit/generated_resources.h"
@@ -39,16 +41,20 @@ BookmarkFolderEditorController::BookmarkFolderEditorController(
details_(details) {
DCHECK(IsNew() || node);
- std::wstring title = IsNew() ?
- l10n_util::GetString(IDS_BOOMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW) :
- l10n_util::GetString(IDS_BOOMARK_FOLDER_EDITOR_WINDOW_TITLE);
- std::wstring label =
- l10n_util::GetString(IDS_BOOMARK_BAR_EDIT_FOLDER_LABEL);
- std::wstring contents = IsNew() ?
- l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME) :
- UTF16ToWide(node_->GetTitleAsString16());
+ string16 title = IsNew() ?
+ l10n_util::GetStringUTF16(IDS_BOOMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW) :
+ l10n_util::GetStringUTF16(IDS_BOOMARK_FOLDER_EDITOR_WINDOW_TITLE);
+ string16 label =
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_EDIT_FOLDER_LABEL);
+ string16 contents = IsNew() ?
+ l10n_util::GetStringUTF16(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME) :
+ node_->GetTitle();
- dialog_ = InputWindowDialog::Create(wnd, title, label, contents, this);
+ dialog_ = InputWindowDialog::Create(wnd,
+ UTF16ToWideHack(title),
+ UTF16ToWideHack(label),
+ UTF16ToWideHack(contents),
+ this);
model_->AddObserver(this);
}
@@ -62,9 +68,9 @@ bool BookmarkFolderEditorController::IsValid(const std::wstring& text) {
void BookmarkFolderEditorController::InputAccepted(const std::wstring& text) {
if (IsNew())
- model_->AddGroup(node_, index_, text);
+ model_->AddGroup(node_, index_, WideToUTF16Hack(text));
else
- model_->SetTitle(node_, text);
+ model_->SetTitle(node_, WideToUTF16Hack(text));
}
void BookmarkFolderEditorController::InputCanceled() {
diff --git a/chrome/browser/bookmarks/bookmark_folder_editor_controller.h b/chrome/browser/bookmarks/bookmark_folder_editor_controller.h
index e3951a4..922cf57 100644
--- a/chrome/browser/bookmarks/bookmark_folder_editor_controller.h
+++ b/chrome/browser/bookmarks/bookmark_folder_editor_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_FOLDER_EDITOR_CONTROLLER_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_FOLDER_EDITOR_CONTROLLER_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.cc b/chrome/browser/bookmarks/bookmark_html_writer.cc
index d3df9b4..8631c1a 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer.cc
@@ -11,8 +11,9 @@
#include "base/message_loop.h"
#include "base/platform_file.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
+#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
@@ -218,9 +219,10 @@ class Writer : public Task {
// Converts a time string written to the JSON codec into a time_t string
// (used by bookmarks.html) and writes it.
bool WriteTime(const std::string& time_string) {
- base::Time time = base::Time::FromInternalValue(
- StringToInt64(time_string));
- return Write(Int64ToString(time.ToTimeT()));
+ int64 internal_value;
+ base::StringToInt64(time_string, &internal_value);
+ return Write(base::Int64ToString(
+ base::Time::FromInternalValue(internal_value).ToTimeT()));
}
// Writes the node and all its children, returning true on success.
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.h b/chrome/browser/bookmarks/bookmark_html_writer.h
index 58da351..a3aefe7 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer.h
+++ b/chrome/browser/bookmarks/bookmark_html_writer.h
@@ -4,20 +4,18 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_HTML_WRITER_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_HTML_WRITER_H_
+#pragma once
#include <list>
#include <map>
#include <string>
#include "base/ref_counted.h"
-#include "base/values.h"
#include "chrome/browser/history/history.h"
#include "chrome/common/notification_registrar.h"
#include "net/base/file_stream.h"
-class BookmarkModel;
class BookmarkNode;
-class DictionaryValue;
class FilePath;
class GURL;
class Profile;
diff --git a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
index 042f3aa..5789449 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
@@ -8,8 +8,10 @@
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
+#include "base/string16.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/i18n/time_formatting.h"
#include "chrome/browser/bookmarks/bookmark_html_writer.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -51,40 +53,41 @@ class BookmarkHTMLWriterTest : public testing::Test {
}
// Converts a BookmarkEntry to a string suitable for assertion testing.
- std::wstring BookmarkEntryToString(
+ string16 BookmarkEntryToString(
const ProfileWriter::BookmarkEntry& entry) {
- std::wstring result;
- result.append(L"on_toolbar=");
+ string16 result;
+ result.append(ASCIIToUTF16("on_toolbar="));
if (entry.in_toolbar)
- result.append(L"false");
+ result.append(ASCIIToUTF16("false"));
else
- result.append(L"true");
+ result.append(ASCIIToUTF16("true"));
- result.append(L" url=" + UTF8ToWide(entry.url.spec()));
+ result.append(ASCIIToUTF16(" url=") + UTF8ToUTF16(entry.url.spec()));
- result.append(L" path=");
+ result.append(ASCIIToUTF16(" path="));
for (size_t i = 0; i < entry.path.size(); ++i) {
if (i != 0)
- result.append(L"/");
- result.append(entry.path[i]);
+ result.append(ASCIIToUTF16("/"));
+ result.append(WideToUTF16Hack(entry.path[i]));
}
- result.append(L" title=");
- result.append(entry.title);
+ result.append(ASCIIToUTF16(" title="));
+ result.append(WideToUTF16Hack(entry.title));
- result.append(L" time=");
- result.append(base::TimeFormatFriendlyDateAndTime(entry.creation_time));
+ result.append(ASCIIToUTF16(" time="));
+ result.append(WideToUTF16Hack(
+ base::TimeFormatFriendlyDateAndTime(entry.creation_time)));
return result;
}
// Creates a set of bookmark values to a string for assertion testing.
- std::wstring BookmarkValuesToString(bool on_toolbar,
- const GURL& url,
- const std::wstring& title,
- base::Time creation_time,
- const std::wstring& f1,
- const std::wstring& f2,
- const std::wstring& f3) {
+ string16 BookmarkValuesToString(bool on_toolbar,
+ const GURL& url,
+ const string16& title,
+ base::Time creation_time,
+ const string16& f1,
+ const string16& f2,
+ const string16& f3) {
ProfileWriter::BookmarkEntry entry;
entry.in_toolbar = on_toolbar;
entry.url = url;
@@ -92,14 +95,14 @@ class BookmarkHTMLWriterTest : public testing::Test {
// to the importer.
entry.path.push_back(L"x");
if (!f1.empty()) {
- entry.path.push_back(f1);
+ entry.path.push_back(UTF16ToWideHack(f1));
if (!f2.empty()) {
- entry.path.push_back(f2);
+ entry.path.push_back(UTF16ToWideHack(f2));
if (!f3.empty())
- entry.path.push_back(f3);
+ entry.path.push_back(UTF16ToWideHack(f3));
}
}
- entry.title = title;
+ entry.title = UTF16ToWideHack(title);
entry.creation_time = creation_time;
return BookmarkEntryToString(entry);
}
@@ -107,11 +110,11 @@ class BookmarkHTMLWriterTest : public testing::Test {
void AssertBookmarkEntryEquals(const ProfileWriter::BookmarkEntry& entry,
bool on_toolbar,
const GURL& url,
- const std::wstring& title,
+ const string16& title,
base::Time creation_time,
- const std::wstring& f1,
- const std::wstring& f2,
- const std::wstring& f3) {
+ const string16& f1,
+ const string16& f2,
+ const string16& f3) {
EXPECT_EQ(BookmarkValuesToString(on_toolbar, url, title, creation_time,
f1, f2, f3),
BookmarkEntryToString(entry));
@@ -171,19 +174,19 @@ TEST_F(BookmarkHTMLWriterTest, Test) {
// F3
// F4
// url1
- std::wstring f1_title = L"F\"&;<1\"";
- std::wstring f2_title = L"F2";
- std::wstring f3_title = L"F 3";
- std::wstring f4_title = L"F4";
- std::wstring url1_title = L"url 1";
- std::wstring url2_title = L"url&2";
- std::wstring url3_title = L"url\"3";
- std::wstring url4_title = L"url\"&;";
+ string16 f1_title = ASCIIToUTF16("F\"&;<1\"");
+ string16 f2_title = ASCIIToUTF16("F2");
+ string16 f3_title = ASCIIToUTF16("F 3");
+ string16 f4_title = ASCIIToUTF16("F4");
+ string16 url1_title = ASCIIToUTF16("url 1");
+ string16 url2_title = ASCIIToUTF16("url&2");
+ string16 url3_title = ASCIIToUTF16("url\"3");
+ string16 url4_title = ASCIIToUTF16("url\"&;");
GURL url1("http://url1");
GURL url1_favicon("http://url1/icon.ico");
GURL url2("http://url2");
GURL url3("http://url3");
- GURL url4("http://\"&;\"");
+ GURL url4("javascript:alert(\"Hello!\");");
base::Time t1(base::Time::Now());
base::Time t2(t1 + base::TimeDelta::FromHours(1));
base::Time t3(t1 + base::TimeDelta::FromHours(1));
@@ -191,7 +194,8 @@ TEST_F(BookmarkHTMLWriterTest, Test) {
const BookmarkNode* f1 = model->AddGroup(
model->GetBookmarkBarNode(), 0, f1_title);
model->AddURLWithCreationTime(f1, 0, url1_title, url1, t1);
- profile.GetHistoryService(Profile::EXPLICIT_ACCESS)->AddPage(url1);
+ profile.GetHistoryService(Profile::EXPLICIT_ACCESS)->AddPage(url1,
+ history::SOURCE_BROWSED);
profile.GetFaviconService(Profile::EXPLICIT_ACCESS)->SetFavicon(url1,
url1_favicon,
icon_data);
@@ -243,22 +247,20 @@ TEST_F(BookmarkHTMLWriterTest, Test) {
// Verify we got back what we wrote.
ASSERT_EQ(7U, parsed_bookmarks.size());
// Windows and ChromeOS builds use Sentence case.
- std::wstring bookmark_folder_name =
- l10n_util::GetString(IDS_BOOMARK_BAR_FOLDER_NAME);
+ string16 bookmark_folder_name =
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_FOLDER_NAME);
AssertBookmarkEntryEquals(parsed_bookmarks[0], false, url1, url1_title, t1,
- bookmark_folder_name, f1_title, std::wstring());
+ bookmark_folder_name, f1_title, string16());
AssertBookmarkEntryEquals(parsed_bookmarks[1], false, url2, url2_title, t2,
bookmark_folder_name, f1_title, f2_title);
AssertBookmarkEntryEquals(parsed_bookmarks[2], false, url3, url3_title, t3,
- bookmark_folder_name, std::wstring(),
- std::wstring());
+ bookmark_folder_name, string16(), string16());
AssertBookmarkEntryEquals(parsed_bookmarks[3], false, url4, url4_title, t4,
- bookmark_folder_name, std::wstring(),
- std::wstring());
+ bookmark_folder_name, string16(), string16());
AssertBookmarkEntryEquals(parsed_bookmarks[4], false, url1, url1_title, t1,
- std::wstring(), std::wstring(), std::wstring());
+ string16(), string16(), string16());
AssertBookmarkEntryEquals(parsed_bookmarks[5], false, url2, url2_title, t2,
- std::wstring(), std::wstring(), std::wstring());
+ string16(), string16(), string16());
AssertBookmarkEntryEquals(parsed_bookmarks[6], false, url1, url1_title, t1,
- f3_title, f4_title, std::wstring());
+ f3_title, f4_title, string16());
}
diff --git a/chrome/browser/bookmarks/bookmark_index.cc b/chrome/browser/bookmarks/bookmark_index.cc
index 161058e..b1c1ab3 100644
--- a/chrome/browser/bookmarks/bookmark_index.cc
+++ b/chrome/browser/bookmarks/bookmark_index.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.
@@ -6,14 +6,41 @@
#include <algorithm>
#include <iterator>
+#include <list>
#include "app/l10n_util.h"
+#include "base/string16.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#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"
+// 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
+// query as well as the set of nodes that contain those terms in their titles.
+struct BookmarkIndex::Match {
+ // List of terms matching the query.
+ std::list<Index::const_iterator> terms;
+
+ // The set of nodes matching the terms. As an optimization this is empty
+ // when we match only one term, and is filled in when we get more than one
+ // term. We can do this as when we have only one matching term we know
+ // the set of matching nodes is terms.front()->second.
+ //
+ // Use nodes_begin() and nodes_end() to get an iterator over the set as
+ // it handles the necessary switching between nodes and terms.front().
+ NodeSet nodes;
+
+ // Returns an iterator to the beginning of the matching nodes. See
+ // description of nodes for why this should be used over nodes.begin().
+ NodeSet::const_iterator nodes_begin() const;
+
+ // Returns an iterator to the beginning of the matching nodes. See
+ // description of nodes for why this should be used over nodes.end().
+ NodeSet::const_iterator nodes_end() const;
+};
+
BookmarkIndex::NodeSet::const_iterator
BookmarkIndex::Match::nodes_begin() const {
return nodes.empty() ? terms.front()->second.begin() : nodes.begin();
@@ -23,10 +50,16 @@ BookmarkIndex::NodeSet::const_iterator BookmarkIndex::Match::nodes_end() const {
return nodes.empty() ? terms.front()->second.end() : nodes.end();
}
+BookmarkIndex::BookmarkIndex(Profile* profile) : profile_(profile) {
+}
+
+BookmarkIndex::~BookmarkIndex() {
+}
+
void BookmarkIndex::Add(const BookmarkNode* node) {
if (!node->is_url())
return;
- std::vector<std::wstring> terms = ExtractQueryWords(node->GetTitle());
+ std::vector<string16> terms = ExtractQueryWords(node->GetTitle());
for (size_t i = 0; i < terms.size(); ++i)
RegisterNode(terms[i], node);
}
@@ -35,16 +68,16 @@ void BookmarkIndex::Remove(const BookmarkNode* node) {
if (!node->is_url())
return;
- std::vector<std::wstring> terms = ExtractQueryWords(node->GetTitle());
+ std::vector<string16> terms = ExtractQueryWords(node->GetTitle());
for (size_t i = 0; i < terms.size(); ++i)
UnregisterNode(terms[i], node);
}
void BookmarkIndex::GetBookmarksWithTitlesMatching(
- const std::wstring& query,
+ const string16& query,
size_t max_count,
std::vector<bookmark_utils::TitleMatch>* results) {
- std::vector<std::wstring> terms = ExtractQueryWords(query);
+ std::vector<string16> terms = ExtractQueryWords(query);
if (terms.empty())
return;
@@ -62,7 +95,7 @@ void BookmarkIndex::GetBookmarksWithTitlesMatching(
// matches and so this shouldn't be performance critical.
QueryParser parser;
ScopedVector<QueryNode> query_nodes;
- parser.ParseQuery(WideToUTF16(query), &query_nodes.get());
+ parser.ParseQuery(query, &query_nodes.get());
// The highest typed counts should be at the beginning of the results vector
// so that the best matches will always be included in the results. The loop
@@ -115,21 +148,21 @@ void BookmarkIndex::AddMatchToResults(
// of QueryParser may filter it out. For example, the query
// ["thi"] will match the bookmark titled [Thinking], but since
// ["thi"] is quoted we don't want to do a prefix match.
- if (parser->DoesQueryMatch(WideToUTF16(node->GetTitle()), query_nodes,
+ if (parser->DoesQueryMatch(node->GetTitle(), query_nodes,
&(title_match.match_positions))) {
title_match.node = node;
results->push_back(title_match);
}
}
-bool BookmarkIndex::GetBookmarksWithTitleMatchingTerm(const std::wstring& term,
+bool BookmarkIndex::GetBookmarksWithTitleMatchingTerm(const string16& term,
bool first_term,
Matches* matches) {
Index::const_iterator i = index_.lower_bound(term);
if (i == index_.end())
return false;
- if (!QueryParser::IsWordLongEnoughForPrefixSearch(WideToUTF16(term))) {
+ if (!QueryParser::IsWordLongEnoughForPrefixSearch(term)) {
// Term is too short for prefix match, compare using exact match.
if (i->first != term)
return false; // No bookmarks with this term.
@@ -204,28 +237,17 @@ void BookmarkIndex::CombineMatches(const Index::const_iterator& index_i,
}
}
-std::vector<std::wstring> BookmarkIndex::ExtractQueryWords(
- const std::wstring& query) {
+std::vector<string16> BookmarkIndex::ExtractQueryWords(const string16& query) {
std::vector<string16> terms;
if (query.empty())
- return std::vector<std::wstring>();
+ return std::vector<string16>();
QueryParser parser;
// TODO: use ICU normalization.
- parser.ExtractQueryWords(l10n_util::ToLower(WideToUTF16(query)), &terms);
-
- // TODO(brettw) just remove this and return |terms| when this is converted
- // to string16.
-#if defined(WCHAR_T_IS_UTF32)
- std::vector<std::wstring> wterms;
- for (size_t i = 0; i < terms.size(); i++)
- wterms.push_back(UTF16ToWide(terms[i]));
- return wterms;
-#else
+ parser.ExtractQueryWords(l10n_util::ToLower(query), &terms);
return terms;
-#endif
}
-void BookmarkIndex::RegisterNode(const std::wstring& term,
+void BookmarkIndex::RegisterNode(const string16& term,
const BookmarkNode* node) {
if (std::find(index_[term].begin(), index_[term].end(), node) !=
index_[term].end()) {
@@ -235,7 +257,7 @@ void BookmarkIndex::RegisterNode(const std::wstring& term,
index_[term].insert(node);
}
-void BookmarkIndex::UnregisterNode(const std::wstring& term,
+void BookmarkIndex::UnregisterNode(const string16& term,
const BookmarkNode* node) {
Index::iterator i = index_.find(term);
if (i == index_.end()) {
diff --git a/chrome/browser/bookmarks/bookmark_index.h b/chrome/browser/bookmarks/bookmark_index.h
index 0fa1a58..d6ea15a 100644
--- a/chrome/browser/bookmarks/bookmark_index.h
+++ b/chrome/browser/bookmarks/bookmark_index.h
@@ -1,17 +1,17 @@
-// 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.
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_INDEX_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_INDEX_H_
+#pragma once
-#include <list>
#include <map>
#include <set>
-#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/string16.h"
class BookmarkNode;
class Profile;
@@ -36,7 +36,8 @@ class URLDatabase;
class BookmarkIndex {
public:
- explicit BookmarkIndex(Profile* profile) : profile_(profile) {}
+ explicit BookmarkIndex(Profile* profile);
+ ~BookmarkIndex();
// Invoked when a bookmark has been added to the model.
void Add(const BookmarkNode* node);
@@ -46,39 +47,15 @@ class BookmarkIndex {
// Returns up to |max_count| of bookmarks containing the text |query|.
void GetBookmarksWithTitlesMatching(
- const std::wstring& query,
+ const string16& query,
size_t max_count,
std::vector<bookmark_utils::TitleMatch>* results);
private:
typedef std::set<const BookmarkNode*> NodeSet;
- typedef std::map<std::wstring, NodeSet> Index;
-
- // 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
- // query as well as the set of nodes that contain those terms in their titles.
- struct Match {
- // List of terms matching the query.
- std::list<Index::const_iterator> terms;
-
- // The set of nodes matching the terms. As an optimization this is empty
- // when we match only one term, and is filled in when we get more than one
- // term. We can do this as when we have only one matching term we know
- // the set of matching nodes is terms.front()->second.
- //
- // Use nodes_begin() and nodes_end() to get an iterator over the set as
- // it handles the necessary switching between nodes and terms.front().
- NodeSet nodes;
-
- // Returns an iterator to the beginning of the matching nodes. See
- // description of nodes for why this should be used over nodes.begin().
- NodeSet::const_iterator nodes_begin() const;
-
- // Returns an iterator to the beginning of the matching nodes. See
- // description of nodes for why this should be used over nodes.end().
- NodeSet::const_iterator nodes_end() const;
- };
+ typedef std::map<string16, NodeSet> Index;
+ struct Match;
typedef std::vector<Match> Matches;
// Pairs BookmarkNodes and the number of times the nodes' URLs were typed.
@@ -115,7 +92,7 @@ class BookmarkIndex {
// Populates |matches| for the specified term. If |first_term| is true, this
// is the first term in the query. Returns true if there is at least one node
// matching the term.
- bool GetBookmarksWithTitleMatchingTerm(const std::wstring& term,
+ bool GetBookmarksWithTitleMatchingTerm(const string16& term,
bool first_term,
Matches* matches);
@@ -141,13 +118,13 @@ class BookmarkIndex {
Matches* result);
// Returns the set of query words from |query|.
- std::vector<std::wstring> ExtractQueryWords(const std::wstring& query);
+ std::vector<string16> ExtractQueryWords(const string16& query);
// Adds |node| to |index_|.
- void RegisterNode(const std::wstring& term, const BookmarkNode* node);
+ void RegisterNode(const string16& term, const BookmarkNode* node);
// Removes |node| from |index_|.
- void UnregisterNode(const std::wstring& term, const BookmarkNode* node);
+ void UnregisterNode(const string16& term, const BookmarkNode* node);
Index index_;
diff --git a/chrome/browser/bookmarks/bookmark_index_unittest.cc b/chrome/browser/bookmarks/bookmark_index_unittest.cc
index 6225bc7..94a2e16 100644
--- a/chrome/browser/bookmarks/bookmark_index_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_index_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.
@@ -6,7 +6,10 @@
#include <vector>
#include "base/message_loop.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_index.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
@@ -21,37 +24,38 @@ class BookmarkIndexTest : public testing::Test {
public:
BookmarkIndexTest() : model_(new BookmarkModel(NULL)) {}
- void AddBookmarksWithTitles(const wchar_t** titles, size_t count) {
- std::vector<std::wstring> title_vector;
+ void AddBookmarksWithTitles(const char** titles, size_t count) {
+ std::vector<std::string> title_vector;
for (size_t i = 0; i < count; ++i)
title_vector.push_back(titles[i]);
AddBookmarksWithTitles(title_vector);
}
- void AddBookmarksWithTitles(const std::vector<std::wstring>& titles) {
+ void AddBookmarksWithTitles(const std::vector<std::string>& titles) {
GURL url("about:blank");
for (size_t i = 0; i < titles.size(); ++i)
- model_->AddURL(model_->other_node(), static_cast<int>(i), titles[i], url);
+ model_->AddURL(model_->other_node(), static_cast<int>(i),
+ ASCIIToUTF16(titles[i]), url);
}
- void ExpectMatches(const std::wstring& query,
- const wchar_t** expected_titles,
+ void ExpectMatches(const std::string& query,
+ const char** expected_titles,
size_t expected_count) {
- std::vector<std::wstring> title_vector;
+ std::vector<std::string> title_vector;
for (size_t i = 0; i < expected_count; ++i)
title_vector.push_back(expected_titles[i]);
ExpectMatches(query, title_vector);
}
- void ExpectMatches(const std::wstring& query,
- const std::vector<std::wstring> expected_titles) {
+ void ExpectMatches(const std::string& query,
+ const std::vector<std::string> expected_titles) {
std::vector<bookmark_utils::TitleMatch> matches;
- model_->GetBookmarksWithTitlesMatching(query, 1000, &matches);
+ model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16(query), 1000, &matches);
ASSERT_EQ(expected_titles.size(), matches.size());
for (size_t i = 0; i < expected_titles.size(); ++i) {
bool found = false;
for (size_t j = 0; j < matches.size(); ++j) {
- if (std::wstring(expected_titles[i]) == matches[j].node->GetTitle()) {
+ if (ASCIIToUTF16(expected_titles[i]) == matches[j].node->GetTitle()) {
matches.erase(matches.begin() + j);
found = true;
break;
@@ -64,21 +68,24 @@ class BookmarkIndexTest : public testing::Test {
void ExtractMatchPositions(const std::string& string,
Snippet::MatchPositions* matches) {
std::vector<std::string> match_strings;
- SplitString(string, L':', &match_strings);
+ SplitString(string, ':', &match_strings);
for (size_t i = 0; i < match_strings.size(); ++i) {
std::vector<std::string> chunks;
SplitString(match_strings[i], ',', &chunks);
ASSERT_EQ(2U, chunks.size());
matches->push_back(Snippet::MatchPosition());
- matches->back().first = StringToInt(chunks[0]);
- matches->back().second = StringToInt(chunks[1]);
+ int chunks0, chunks1;
+ base::StringToInt(chunks[0], &chunks0);
+ base::StringToInt(chunks[1], &chunks1);
+ matches->back().first = chunks0;
+ matches->back().second = chunks1;
}
}
- void ExpectMatchPositions(const std::wstring& query,
+ void ExpectMatchPositions(const std::string& query,
const Snippet::MatchPositions& expected_positions) {
std::vector<bookmark_utils::TitleMatch> matches;
- model_->GetBookmarksWithTitlesMatching(query, 1000, &matches);
+ model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16(query), 1000, &matches);
ASSERT_EQ(1U, matches.size());
const bookmark_utils::TitleMatch& match = matches[0];
ASSERT_EQ(expected_positions.size(), match.match_positions.size());
@@ -99,41 +106,41 @@ class BookmarkIndexTest : public testing::Test {
// all query paths.
TEST_F(BookmarkIndexTest, Tests) {
struct TestData {
- const std::wstring input;
- const std::wstring query;
- const std::wstring expected;
+ const std::string input;
+ const std::string query;
+ const std::string expected;
} data[] = {
// Trivial test case of only one term, exact match.
- { L"a;b", L"A", L"a" },
+ { "a;b", "A", "a" },
// Prefix match, one term.
- { L"abcd;abc;b", L"abc", L"abcd;abc" },
+ { "abcd;abc;b", "abc", "abcd;abc" },
// Prefix match, multiple terms.
- { L"abcd cdef;abcd;abcd cdefg", L"abc cde", L"abcd cdef;abcd cdefg"},
+ { "abcd cdef;abcd;abcd cdefg", "abc cde", "abcd cdef;abcd cdefg"},
// Exact and prefix match.
- { L"ab cdef;abcd;abcd cdefg", L"ab cdef", L"ab cdef"},
+ { "ab cdef;abcd;abcd cdefg", "ab cdef", "ab cdef"},
// Exact and prefix match.
- { L"ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
- L"ab cde ghi",
- L"ab cdef ghij"},
+ { "ab cdef ghij;ab;cde;cdef;ghi;cdef ab;ghij ab",
+ "ab cde ghi",
+ "ab cdef ghij"},
// Title with term multiple times.
- { L"ab ab", L"ab", L"ab ab"},
+ { "ab ab", "ab", "ab ab"},
// Make sure quotes don't do a prefix match.
- { L"think", L"\"thi\"", L""},
+ { "think", "\"thi\"", ""},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
- std::vector<std::wstring> titles;
- SplitString(data[i].input, L';', &titles);
+ std::vector<std::string> titles;
+ SplitString(data[i].input, ';', &titles);
AddBookmarksWithTitles(titles);
- std::vector<std::wstring> expected;
+ std::vector<std::string> expected;
if (!data[i].expected.empty())
- SplitString(data[i].expected, L';', &expected);
+ SplitString(data[i].expected, ';', &expected);
ExpectMatches(data[i].query, expected);
@@ -144,17 +151,17 @@ TEST_F(BookmarkIndexTest, Tests) {
// Makes sure match positions are updated appropriately.
TEST_F(BookmarkIndexTest, MatchPositions) {
struct TestData {
- const std::wstring title;
- const std::wstring query;
+ const std::string title;
+ const std::string query;
const std::string expected;
} data[] = {
// Trivial test case of only one term, exact match.
- { L"a", L"A", "0,1" },
- { L"foo bar", L"bar", "4,7" },
- { L"fooey bark", L"bar foo", "0,3:6,9"},
+ { "a", "A", "0,1" },
+ { "foo bar", "bar", "4,7" },
+ { "fooey bark", "bar foo", "0,3:6,9"},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
- std::vector<std::wstring> titles;
+ std::vector<std::string> titles;
titles.push_back(data[i].title);
AddBookmarksWithTitles(titles);
@@ -168,43 +175,44 @@ TEST_F(BookmarkIndexTest, MatchPositions) {
// Makes sure index is updated when a node is removed.
TEST_F(BookmarkIndexTest, Remove) {
- const wchar_t* input[] = { L"a", L"b" };
+ const char* input[] = { "a", "b" };
AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));
// Remove the node and make sure we don't get back any results.
model_->Remove(model_->other_node(), 0);
- ExpectMatches(L"A", NULL, 0U);
+ ExpectMatches("A", NULL, 0U);
}
// Makes sure index is updated when a node's title is changed.
TEST_F(BookmarkIndexTest, ChangeTitle) {
- const wchar_t* input[] = { L"a", L"b" };
+ const char* input[] = { "a", "b" };
AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));
// Remove the node and make sure we don't get back any results.
- const wchar_t* expected[] = { L"blah" };
- model_->SetTitle(model_->other_node()->GetChild(0), L"blah");
- ExpectMatches(L"BlAh", expected, ARRAYSIZE_UNSAFE(expected));
+ const char* expected[] = { "blah" };
+ model_->SetTitle(model_->other_node()->GetChild(0), ASCIIToUTF16("blah"));
+ ExpectMatches("BlAh", expected, ARRAYSIZE_UNSAFE(expected));
}
// Makes sure no more than max queries is returned.
TEST_F(BookmarkIndexTest, HonorMax) {
- const wchar_t* input[] = { L"abcd", L"abcde" };
+ const char* input[] = { "abcd", "abcde" };
AddBookmarksWithTitles(input, ARRAYSIZE_UNSAFE(input));
std::vector<bookmark_utils::TitleMatch> matches;
- model_->GetBookmarksWithTitlesMatching(L"ABc", 1, &matches);
+ model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16("ABc"), 1, &matches);
EXPECT_EQ(1U, matches.size());
}
// Makes sure if the lower case string of a bookmark title is more characters
// than the upper case string no match positions are returned.
TEST_F(BookmarkIndexTest, EmptyMatchOnMultiwideLowercaseString) {
- const BookmarkNode* n1 = model_->AddURL(model_->other_node(), 0, L"\u0130 i",
+ const BookmarkNode* n1 = model_->AddURL(model_->other_node(), 0,
+ WideToUTF16(L"\u0130 i"),
GURL("http://www.google.com"));
std::vector<bookmark_utils::TitleMatch> matches;
- model_->GetBookmarksWithTitlesMatching(L"i", 100, &matches);
+ model_->GetBookmarksWithTitlesMatching(ASCIIToUTF16("i"), 100, &matches);
ASSERT_EQ(1U, matches.size());
EXPECT_TRUE(matches[0].node == n1);
EXPECT_TRUE(matches[0].match_positions.empty());
@@ -248,7 +256,7 @@ TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
// Populate the InMemoryDatabase....
url_db->AddURL(info);
// Populate the BookmarkIndex.
- model->AddURL(model->other_node(), i, UTF8ToWide(data[i].title),
+ model->AddURL(model->other_node(), i, UTF8ToUTF16(data[i].title),
data[i].url);
}
@@ -271,7 +279,7 @@ TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
// Populate match nodes.
std::vector<bookmark_utils::TitleMatch> matches;
- model->GetBookmarksWithTitlesMatching(L"google", 4, &matches);
+ model->GetBookmarksWithTitlesMatching(ASCIIToUTF16("google"), 4, &matches);
// The resulting order should be:
// 1. Google (google.com) 100
@@ -286,7 +294,7 @@ TEST_F(BookmarkIndexTest, GetResultsSortedByTypedCount) {
matches.clear();
// Select top two matches.
- model->GetBookmarksWithTitlesMatching(L"google", 2, &matches);
+ model->GetBookmarksWithTitlesMatching(ASCIIToUTF16("google"), 2, &matches);
EXPECT_EQ(2, static_cast<int>(matches.size()));
EXPECT_EQ(data[0].url, matches[0].node->GetURL());
diff --git a/chrome/browser/bookmarks/bookmark_model.cc b/chrome/browser/bookmarks/bookmark_model.cc
index a5c87bf..606c205 100644
--- a/chrome/browser/bookmarks/bookmark_model.cc
+++ b/chrome/browser/bookmarks/bookmark_model.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.
@@ -14,7 +14,7 @@
#include "chrome/browser/bookmarks/bookmark_storage.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_notifications.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_service.h"
#include "gfx/codec/png_codec.h"
@@ -43,6 +43,9 @@ BookmarkNode::BookmarkNode(int64 id, const GURL& url)
Initialize(id);
}
+BookmarkNode::~BookmarkNode() {
+}
+
void BookmarkNode::Initialize(int64 id) {
id_ = id;
loaded_favicon_ = false;
@@ -94,8 +97,9 @@ class SortComparator : public std::binary_function<const BookmarkNode*,
// Types are the same, compare the names.
if (!collator_)
return n1->GetTitle() < n2->GetTitle();
- return l10n_util::CompareStringWithCollator(collator_, n1->GetTitle(),
- n2->GetTitle()) == UCOL_LESS;
+ return l10n_util::CompareStringWithCollator(collator_,
+ UTF16ToWideHack(n1->GetTitle()), UTF16ToWideHack(n2->GetTitle())) ==
+ UCOL_LESS;
}
// Types differ, sort such that folders come first.
return n1->is_folder();
@@ -241,18 +245,12 @@ const SkBitmap& BookmarkModel::GetFavIcon(const BookmarkNode* node) {
return node->favicon();
}
-#if !defined(WCHAR_T_IS_UTF16)
-void BookmarkModel::SetTitle(const BookmarkNode* node,
- const std::wstring& title) {
- SetTitle(node, WideToUTF16(title));
-}
-#endif
void BookmarkModel::SetTitle(const BookmarkNode* node, const string16& title) {
if (!node) {
NOTREACHED();
return;
}
- if (node->GetTitleAsString16() == title)
+ if (node->GetTitle() == title)
return;
if (node == bookmark_bar_node_ || node == other_node_) {
@@ -348,6 +346,11 @@ void BookmarkModel::GetBookmarks(std::vector<GURL>* urls) {
}
}
+bool BookmarkModel::HasBookmarks() {
+ AutoLock url_lock(url_lock_);
+ return !nodes_ordered_by_url_set_.empty();
+}
+
bool BookmarkModel::IsBookmarked(const GURL& url) {
AutoLock url_lock(url_lock_);
return IsBookmarkedNoLock(url);
@@ -358,13 +361,6 @@ const BookmarkNode* BookmarkModel::GetNodeByID(int64 id) {
return GetNodeByID(&root_, id);
}
-#if !defined(WCHAR_T_IS_UTF16)
-const BookmarkNode* BookmarkModel::AddGroup(const BookmarkNode* parent,
- int index,
- const std::wstring& title) {
- return AddGroup(parent, index, WideToUTF16(title));
-}
-#endif
const BookmarkNode* BookmarkModel::AddGroup(const BookmarkNode* parent,
int index,
const string16& title) {
@@ -383,14 +379,6 @@ const BookmarkNode* BookmarkModel::AddGroup(const BookmarkNode* parent,
return AddNode(AsMutable(parent), index, new_node, false);
}
-#if !defined(WCHAR_T_IS_UTF16)
-const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
- int index,
- const std::wstring& title,
- const GURL& url) {
- return AddURL(parent, index, WideToUTF16(title), url);
-}
-#endif
const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
int index,
const string16& title,
@@ -398,17 +386,6 @@ const BookmarkNode* BookmarkModel::AddURL(const BookmarkNode* parent,
return AddURLWithCreationTime(parent, index, title, url, Time::Now());
}
-#if !defined(WCHAR_T_IS_UTF16)
-const BookmarkNode* BookmarkModel::AddURLWithCreationTime(
- const BookmarkNode* parent,
- int index,
- const std::wstring& title,
- const GURL& url,
- const Time& creation_time) {
- return AddURLWithCreationTime(parent, index, WideToUTF16(title),
- url, creation_time);
-}
-#endif
const BookmarkNode* BookmarkModel::AddURLWithCreationTime(
const BookmarkNode* parent,
int index,
@@ -464,13 +441,6 @@ void BookmarkModel::SortChildren(const BookmarkNode* parent) {
BookmarkNodeChildrenReordered(this, parent));
}
-#if !defined(WCHAR_T_IS_UTF16)
-void BookmarkModel::SetURLStarred(const GURL& url,
- const std::wstring& title,
- bool is_starred) {
- SetURLStarred(url, WideToUTF16(title), is_starred);
-}
-#endif
void BookmarkModel::SetURLStarred(const GURL& url,
const string16& title,
bool is_starred) {
@@ -506,14 +476,6 @@ void BookmarkModel::ResetDateGroupModified(const BookmarkNode* node) {
SetDateGroupModified(node, Time());
}
-#if !defined(WCHAR_T_IS_UTF16)
-void BookmarkModel::GetBookmarksWithTitlesMatching(
- const std::wstring& text,
- size_t max_count,
- std::vector<bookmark_utils::TitleMatch>* matches) {
- GetBookmarksWithTitlesMatching(WideToUTF16(text), max_count, matches);
-}
-#endif
void BookmarkModel::GetBookmarksWithTitlesMatching(
const string16& text,
size_t max_count,
@@ -521,7 +483,7 @@ void BookmarkModel::GetBookmarksWithTitlesMatching(
if (!loaded_)
return;
- index_->GetBookmarksWithTitlesMatching(UTF16ToWide(text), max_count, matches);
+ index_->GetBookmarksWithTitlesMatching(text, max_count, matches);
}
void BookmarkModel::ClearStore() {
@@ -751,10 +713,12 @@ BookmarkNode* BookmarkModel::CreateRootNodeFromStarredEntry(
entry.type == history::StarredEntry::OTHER);
BookmarkNode* node = new BookmarkNode(generate_next_node_id(), GURL());
node->Reset(entry);
- if (entry.type == history::StarredEntry::BOOKMARK_BAR)
- node->SetTitle(l10n_util::GetString(IDS_BOOMARK_BAR_FOLDER_NAME));
- else
- node->SetTitle(l10n_util::GetString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME));
+ if (entry.type == history::StarredEntry::BOOKMARK_BAR) {
+ node->SetTitle(l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_FOLDER_NAME));
+ } else {
+ node->SetTitle(
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME));
+ }
return node;
}
diff --git a/chrome/browser/bookmarks/bookmark_model.h b/chrome/browser/bookmarks/bookmark_model.h
index 6e238bc..015de94 100644
--- a/chrome/browser/bookmarks/bookmark_model.h
+++ b/chrome/browser/bookmarks/bookmark_model.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_H_
+#pragma once
#include "build/build_config.h"
@@ -26,8 +27,6 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
-class BookmarkCodec;
-class BookmarkEditorView;
class BookmarkIndex;
class BookmarkLoadDetails;
class BookmarkModel;
@@ -57,7 +56,7 @@ class BookmarkNode : public TreeNode<BookmarkNode> {
explicit BookmarkNode(const GURL& url);
// Creates a new node with the specified url and id.
BookmarkNode(int64 id, const GURL& url);
- virtual ~BookmarkNode() {}
+ virtual ~BookmarkNode();
// Returns the URL.
const GURL& GetURL() const { return url_; }
@@ -231,11 +230,7 @@ class BookmarkModel : public NotificationObserver, public BookmarkService {
// loaded it is loaded and the observer of the model notified when done.
const SkBitmap& GetFavIcon(const BookmarkNode* node);
- // TODO(munjal): Remove wstring overload once all code is moved to string16.
// Sets the title of the specified node.
-#if !defined(WCHAR_T_IS_UTF16)
- void SetTitle(const BookmarkNode* node, const std::wstring& title);
-#endif
void SetTitle(const BookmarkNode* node, const string16& title);
// Sets the URL of the specified bookmark node.
@@ -254,6 +249,10 @@ class BookmarkModel : public NotificationObserver, public BookmarkService {
// Returns all the bookmarked urls. This method is thread safe.
virtual void GetBookmarks(std::vector<GURL>* urls);
+ // Returns true if there are bookmarks, otherwise returns false. This method
+ // is thread safe.
+ bool HasBookmarks();
+
// Returns true if there is a bookmark for the specified URL. This method is
// thread safe. See BookmarkService for more details on this.
virtual bool IsBookmarked(const GURL& url);
@@ -266,39 +265,18 @@ class BookmarkModel : public NotificationObserver, public BookmarkService {
// the specified id.
const BookmarkNode* GetNodeByID(int64 id);
- // TODO(munjal): Remove wstring overload once all code is moved to string16.
// Adds a new group node at the specified position.
-#if !defined(WCHAR_T_IS_UTF16)
- const BookmarkNode* AddGroup(const BookmarkNode* parent,
- int index,
- const std::wstring& title);
-#endif
const BookmarkNode* AddGroup(const BookmarkNode* parent,
int index,
const string16& title);
- // TODO(munjal): Remove wstring overload once all code is moved to string16.
// Adds a url at the specified position.
-#if !defined(WCHAR_T_IS_UTF16)
- const BookmarkNode* AddURL(const BookmarkNode* parent,
- int index,
- const std::wstring& title,
- const GURL& url);
-#endif
const BookmarkNode* AddURL(const BookmarkNode* parent,
int index,
const string16& title,
const GURL& url);
- // TODO(munjal): Remove wstring overload once all code is moved to string16.
// Adds a url with a specific creation date.
-#if !defined(WCHAR_T_IS_UTF16)
- const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent,
- int index,
- const std::wstring& title,
- const GURL& url,
- const base::Time& creation_time);
-#endif
const BookmarkNode* AddURLWithCreationTime(const BookmarkNode* parent,
int index,
const string16& title,
@@ -309,15 +287,9 @@ class BookmarkModel : public NotificationObserver, public BookmarkService {
// BookmarkNodeChildrenReordered method.
void SortChildren(const BookmarkNode* parent);
- // TODO(munjal): Remove wstring overload once all code is moved to string16.
// This is the convenience that makes sure the url is starred or not starred.
// If is_starred is false, all bookmarks for URL are removed. If is_starred is
// true and there are no bookmarks for url, a bookmark is created.
-#if !defined(WCHAR_T_IS_UTF16)
- void SetURLStarred(const GURL& url,
- const std::wstring& title,
- bool is_starred);
-#endif
void SetURLStarred(const GURL& url,
const string16& title,
bool is_starred);
@@ -330,13 +302,6 @@ class BookmarkModel : public NotificationObserver, public BookmarkService {
// combobox of most recently modified groups.
void ResetDateGroupModified(const BookmarkNode* node);
- // TODO(munjal): Remove wstring overload once all code is moved to string16.
-#if !defined(WCHAR_T_IS_UTF16)
- void GetBookmarksWithTitlesMatching(
- const std::wstring& text,
- size_t max_count,
- std::vector<bookmark_utils::TitleMatch>* matches);
-#endif
void GetBookmarksWithTitlesMatching(
const string16& text,
size_t max_count,
@@ -367,6 +332,9 @@ class BookmarkModel : public NotificationObserver, public BookmarkService {
// Returns whether the bookmarks file changed externally.
bool file_changed() const { return file_changed_; }
+ // Returns the next node ID.
+ int64 next_node_id() const { return next_node_id_; }
+
private:
// Used to order BookmarkNodes by URL.
class NodeURLComparator {
diff --git a/chrome/browser/bookmarks/bookmark_model_observer.h b/chrome/browser/bookmarks/bookmark_model_observer.h
index 7cc50dc..a9819af 100644
--- a/chrome/browser/bookmarks/bookmark_model_observer.h
+++ b/chrome/browser/bookmarks/bookmark_model_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_H_
+#pragma once
class BookmarkModel;
class BookmarkNode;
diff --git a/chrome/browser/bookmarks/bookmark_model_test_utils.cc b/chrome/browser/bookmarks/bookmark_model_test_utils.cc
index e563a3f..e5b2a70 100644
--- a/chrome/browser/bookmarks/bookmark_model_test_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_model_test_utils.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.
diff --git a/chrome/browser/bookmarks/bookmark_model_test_utils.h b/chrome/browser/bookmarks/bookmark_model_test_utils.h
index e942bd6..c8b794a 100644
--- a/chrome/browser/bookmarks/bookmark_model_test_utils.h
+++ b/chrome/browser/bookmarks/bookmark_model_test_utils.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_TEST_UTILS_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MODEL_TEST_UTILS_H_
+#pragma once
class BookmarkModel;
class BookmarkNode;
diff --git a/chrome/browser/bookmarks/bookmark_model_unittest.cc b/chrome/browser/bookmarks/bookmark_model_unittest.cc
index 9d85f1f..0bf7534 100644
--- a/chrome/browser/bookmarks/bookmark_model_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_model_unittest.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,8 +6,14 @@
#include "app/tree_node_iterator.h"
#include "app/tree_node_model.h"
+#include "base/base_paths.h"
+#include "base/file_util.h"
#include "base/hash_tables.h"
+#include "base/path_service.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
@@ -172,7 +178,7 @@ TEST_F(BookmarkModelTest, InitialState) {
TEST_F(BookmarkModelTest, AddURL) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring title(L"foo");
+ const string16 title(ASCIIToUTF16("foo"));
const GURL url("http://foo.com");
const BookmarkNode* new_node = model.AddURL(root, 0, title, url);
@@ -191,7 +197,7 @@ TEST_F(BookmarkModelTest, AddURL) {
TEST_F(BookmarkModelTest, AddGroup) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring title(L"foo");
+ const string16 title(ASCIIToUTF16("foo"));
const BookmarkNode* new_node = model.AddGroup(root, 0, title);
AssertObserverCount(1, 0, 0, 0, 0);
@@ -213,7 +219,7 @@ TEST_F(BookmarkModelTest, AddGroup) {
TEST_F(BookmarkModelTest, RemoveURL) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring title(L"foo");
+ const string16 title(ASCIIToUTF16("foo"));
const GURL url("http://foo.com");
model.AddURL(root, 0, title, url);
ClearCounts();
@@ -229,12 +235,12 @@ TEST_F(BookmarkModelTest, RemoveURL) {
TEST_F(BookmarkModelTest, RemoveGroup) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- const BookmarkNode* group = model.AddGroup(root, 0, L"foo");
+ const BookmarkNode* group = model.AddGroup(root, 0, ASCIIToUTF16("foo"));
ClearCounts();
// Add a URL as a child.
- const std::wstring title(L"foo");
+ const string16 title(ASCIIToUTF16("foo"));
const GURL url("http://foo.com");
model.AddURL(group, 0, title, url);
@@ -252,13 +258,13 @@ TEST_F(BookmarkModelTest, RemoveGroup) {
TEST_F(BookmarkModelTest, SetTitle) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- std::wstring title(L"foo");
+ string16 title(ASCIIToUTF16("foo"));
const GURL url("http://foo.com");
const BookmarkNode* node = model.AddURL(root, 0, title, url);
ClearCounts();
- title = L"foo2";
+ title = ASCIIToUTF16("foo2");
model.SetTitle(node, title);
AssertObserverCount(0, 0, 0, 1, 0);
observer_details.AssertEquals(node, NULL, -1, -1);
@@ -267,7 +273,7 @@ TEST_F(BookmarkModelTest, SetTitle) {
TEST_F(BookmarkModelTest, SetURL) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring title(L"foo");
+ const string16 title(ASCIIToUTF16("foo"));
GURL url("http://foo.com");
const BookmarkNode* node = model.AddURL(root, 0, title, url);
@@ -282,10 +288,10 @@ TEST_F(BookmarkModelTest, SetURL) {
TEST_F(BookmarkModelTest, Move) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- std::wstring title(L"foo");
+ const string16 title(ASCIIToUTF16("foo"));
const GURL url("http://foo.com");
const BookmarkNode* node = model.AddURL(root, 0, title, url);
- const BookmarkNode* group1 = model.AddGroup(root, 0, L"foo");
+ const BookmarkNode* group1 = model.AddGroup(root, 0, ASCIIToUTF16("foo"));
ClearCounts();
model.Move(node, group1, 0);
@@ -309,11 +315,11 @@ TEST_F(BookmarkModelTest, Move) {
TEST_F(BookmarkModelTest, Copy) {
const BookmarkNode* root = model.GetBookmarkBarNode();
- static const std::wstring model_string(L"a 1:[ b c ] d 2:[ e f g ] h ");
+ static const std::string model_string("a 1:[ b c ] d 2:[ e f g ] h ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Copy 'd' to be after '1:b': URL item from bar to folder.
@@ -321,43 +327,43 @@ TEST_F(BookmarkModelTest, Copy) {
const BookmarkNode* destination = root->GetChild(1);
model.Copy(nodeToCopy, destination, 1);
actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(L"a 1:[ b d c ] d 2:[ e f g ] h ", actualModelString);
+ EXPECT_EQ("a 1:[ b d c ] d 2:[ e f g ] h ", actualModelString);
// Copy '1:d' to be after 'a': URL item from folder to bar.
const BookmarkNode* group = root->GetChild(1);
nodeToCopy = group->GetChild(1);
model.Copy(nodeToCopy, root, 1);
actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(L"a d 1:[ b d c ] d 2:[ e f g ] h ", actualModelString);
+ EXPECT_EQ("a d 1:[ b d c ] d 2:[ e f g ] h ", actualModelString);
// Copy '1' to be after '2:e': Folder from bar to folder.
nodeToCopy = root->GetChild(2);
destination = root->GetChild(4);
model.Copy(nodeToCopy, destination, 1);
actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(L"a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ", actualModelString);
+ EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ", actualModelString);
// Copy '2:1' to be after '2:f': Folder within same folder.
group = root->GetChild(4);
nodeToCopy = group->GetChild(1);
model.Copy(nodeToCopy, group, 3);
actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(L"a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ",
+ EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ",
actualModelString);
// Copy first 'd' to be after 'h': URL item within the bar.
nodeToCopy = root->GetChild(1);
model.Copy(nodeToCopy, root, 6);
actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(L"a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
+ EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
actualModelString);
// Copy '2' to be after 'a': Folder within the bar.
nodeToCopy = root->GetChild(4);
model.Copy(nodeToCopy, root, 1);
actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(L"a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] "
- L"d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
+ EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] "
+ "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
actualModelString);
}
@@ -365,7 +371,7 @@ TEST_F(BookmarkModelTest, Copy) {
TEST_F(BookmarkModelTest, ParentForNewNodes) {
ASSERT_EQ(model.GetBookmarkBarNode(), model.GetParentForNewNodes());
- const std::wstring title(L"foo");
+ const string16 title(ASCIIToUTF16("foo"));
const GURL url("http://foo.com");
model.AddURL(model.other_node(), 0, title, url);
@@ -375,9 +381,10 @@ TEST_F(BookmarkModelTest, ParentForNewNodes) {
// Make sure recently modified stays in sync when adding a URL.
TEST_F(BookmarkModelTest, MostRecentlyModifiedGroups) {
// Add a group.
- const BookmarkNode* group = model.AddGroup(model.other_node(), 0, L"foo");
+ const BookmarkNode* group = model.AddGroup(model.other_node(), 0,
+ ASCIIToUTF16("foo"));
// Add a URL to it.
- model.AddURL(group, 0, L"blah", GURL("http://foo.com"));
+ model.AddURL(group, 0, ASCIIToUTF16("blah"), GURL("http://foo.com"));
// Make sure group is in the most recently modified.
std::vector<const BookmarkNode*> most_recent_groups =
@@ -401,19 +408,19 @@ TEST_F(BookmarkModelTest, MostRecentlyAddedEntries) {
Time base_time = Time::Now();
BookmarkNode* n1 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
0,
- L"blah",
+ ASCIIToUTF16("blah"),
GURL("http://foo.com/0")));
BookmarkNode* n2 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
1,
- L"blah",
+ ASCIIToUTF16("blah"),
GURL("http://foo.com/1")));
BookmarkNode* n3 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
2,
- L"blah",
+ ASCIIToUTF16("blah"),
GURL("http://foo.com/2")));
BookmarkNode* n4 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
3,
- L"blah",
+ ASCIIToUTF16("blah"),
GURL("http://foo.com/3")));
n1->set_date_added(base_time + TimeDelta::FromDays(4));
n2->set_date_added(base_time + TimeDelta::FromDays(3));
@@ -445,9 +452,9 @@ TEST_F(BookmarkModelTest, GetMostRecentlyAddedNodeForURL) {
Time base_time = Time::Now();
const GURL url("http://foo.com/0");
BookmarkNode* n1 = AsMutable(model.AddURL(
- model.GetBookmarkBarNode(), 0, L"blah", url));
+ model.GetBookmarkBarNode(), 0, ASCIIToUTF16("blah"), url));
BookmarkNode* n2 = AsMutable(model.AddURL(
- model.GetBookmarkBarNode(), 1, L"blah", url));
+ model.GetBookmarkBarNode(), 1, ASCIIToUTF16("blah"), url));
n1->set_date_added(base_time + TimeDelta::FromDays(4));
n2->set_date_added(base_time + TimeDelta::FromDays(3));
@@ -462,8 +469,8 @@ TEST_F(BookmarkModelTest, GetMostRecentlyAddedNodeForURL) {
// Makes sure GetBookmarks removes duplicates.
TEST_F(BookmarkModelTest, GetBookmarksWithDups) {
const GURL url("http://foo.com/0");
- model.AddURL(model.GetBookmarkBarNode(), 0, L"blah", url);
- model.AddURL(model.GetBookmarkBarNode(), 1, L"blah", url);
+ model.AddURL(model.GetBookmarkBarNode(), 0, ASCIIToUTF16("blah"), url);
+ model.AddURL(model.GetBookmarkBarNode(), 1, ASCIIToUTF16("blah"), url);
std::vector<GURL> urls;
model.GetBookmarks(&urls);
@@ -471,6 +478,13 @@ TEST_F(BookmarkModelTest, GetBookmarksWithDups) {
ASSERT_TRUE(urls[0] == url);
}
+TEST_F(BookmarkModelTest, HasBookmarks) {
+ const GURL url("http://foo.com/");
+ model.AddURL(model.GetBookmarkBarNode(), 0, ASCIIToUTF16("bar"), url);
+
+ EXPECT_TRUE(model.HasBookmarks());
+}
+
namespace {
// NotificationObserver implementation used in verifying we've received the
@@ -509,7 +523,7 @@ TEST_F(BookmarkModelTest, NotifyURLsStarred) {
StarredListener listener;
const GURL url("http://foo.com/0");
const BookmarkNode* n1 = model.AddURL(
- model.GetBookmarkBarNode(), 0, L"blah", url);
+ model.GetBookmarkBarNode(), 0, ASCIIToUTF16("blah"), url);
// Starred notification should be sent.
EXPECT_EQ(1, listener.notification_count_);
@@ -522,7 +536,7 @@ TEST_F(BookmarkModelTest, NotifyURLsStarred) {
// Add another bookmark for the same URL. This should not send any
// notification.
const BookmarkNode* n2 = model.AddURL(
- model.GetBookmarkBarNode(), 1, L"blah", url);
+ model.GetBookmarkBarNode(), 1, ASCIIToUTF16("blah"), url);
EXPECT_EQ(0, listener.notification_count_);
@@ -553,24 +567,24 @@ typedef TreeNodeWithValue<BookmarkNode::Type> TestNode;
// Does the work of PopulateNodeFromString. index gives the index of the current
// element in description to process.
-static void PopulateNodeImpl(const std::vector<std::wstring>& description,
+static void PopulateNodeImpl(const std::vector<std::string>& description,
size_t* index,
TestNode* parent) {
while (*index < description.size()) {
- const std::wstring& element = description[*index];
+ const std::string& element = description[*index];
(*index)++;
- if (element == L"[") {
+ if (element == "[") {
// Create a new group and recurse to add all the children.
// Groups are given a unique named by way of an ever increasing integer
// value. The groups need not have a name, but one is assigned to help
// in debugging.
static int next_group_id = 1;
TestNode* new_node =
- new TestNode(IntToWString(next_group_id++),
+ new TestNode(base::IntToString16(next_group_id++),
BookmarkNode::FOLDER);
parent->Add(parent->GetChildCount(), new_node);
PopulateNodeImpl(description, index, new_node);
- } else if (element == L"]") {
+ } else if (element == "]") {
// End the current group.
return;
} else {
@@ -581,7 +595,7 @@ static void PopulateNodeImpl(const std::vector<std::wstring>& description,
DCHECK(element.find('[') == std::string::npos);
DCHECK(element.find(']') == std::string::npos);
parent->Add(parent->GetChildCount(),
- new TestNode(element, BookmarkNode::URL));
+ new TestNode(UTF8ToUTF16(element), BookmarkNode::URL));
}
}
}
@@ -603,9 +617,9 @@ static void PopulateNodeImpl(const std::vector<std::wstring>& description,
//
// NOTE: each name must be unique, and groups are assigned a unique title by way
// of an increasing integer.
-static void PopulateNodeFromString(const std::wstring& description,
+static void PopulateNodeFromString(const std::string& description,
TestNode* parent) {
- std::vector<std::wstring> elements;
+ std::vector<std::string> elements;
size_t index = 0;
SplitStringAlongWhitespace(description, &elements);
PopulateNodeImpl(elements, &index, parent);
@@ -623,7 +637,7 @@ static void PopulateBookmarkNode(TestNode* parent,
PopulateBookmarkNode(child, model, new_bb_node);
} else {
model->AddURL(bb_node, i, child->GetTitle(),
- GURL("http://" + WideToASCII(child->GetTitle())));
+ GURL("http://" + UTF16ToASCII(child->GetTitle())));
}
}
}
@@ -738,17 +752,17 @@ class BookmarkModelTestWithProfile : public testing::Test,
TEST_F(BookmarkModelTestWithProfile, CreateAndRestore) {
struct TestData {
// Structure of the children of the bookmark bar model node.
- const std::wstring bbn_contents;
+ const std::string bbn_contents;
// Structure of the children of the other node.
- const std::wstring other_contents;
+ const std::string other_contents;
} data[] = {
// See PopulateNodeFromString for a description of these strings.
- { L"", L"" },
- { L"a", L"b" },
- { L"a [ b ]", L"" },
- { L"", L"[ b ] a [ c [ d e [ f ] ] ]" },
- { L"a [ b ]", L"" },
- { L"a b c [ d e [ f ] ]", L"g h i [ j k [ l ] ]"},
+ { "", "" },
+ { "a", "b" },
+ { "a [ b ]", "" },
+ { "", "[ b ] a [ c [ d e [ f ] ] ]" },
+ { "a [ b ]", "" },
+ { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
// Recreate the profile. We need to reset with NULL first so that the last
@@ -803,29 +817,29 @@ class BookmarkModelTestWithProfile2 : public BookmarkModelTestWithProfile {
const BookmarkNode* child = bbn->GetChild(0);
ASSERT_EQ(BookmarkNode::URL, child->type());
- ASSERT_EQ(L"Google", child->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("Google"), child->GetTitle());
ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com"));
child = bbn->GetChild(1);
ASSERT_TRUE(child->is_folder());
- ASSERT_EQ(L"F1", child->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F1"), child->GetTitle());
ASSERT_EQ(2, child->GetChildCount());
const BookmarkNode* parent = child;
child = parent->GetChild(0);
ASSERT_EQ(BookmarkNode::URL, child->type());
- ASSERT_EQ(L"Google Advertising", child->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("Google Advertising"), child->GetTitle());
ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com/intl/en/ads/"));
child = parent->GetChild(1);
ASSERT_TRUE(child->is_folder());
- ASSERT_EQ(L"F11", child->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F11"), child->GetTitle());
ASSERT_EQ(1, child->GetChildCount());
parent = child;
child = parent->GetChild(0);
ASSERT_EQ(BookmarkNode::URL, child->type());
- ASSERT_EQ(L"Google Business Solutions", child->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("Google Business Solutions"), child->GetTitle());
ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com/services/"));
parent = bb_model_->other_node();
@@ -833,12 +847,12 @@ class BookmarkModelTestWithProfile2 : public BookmarkModelTestWithProfile {
child = parent->GetChild(0);
ASSERT_TRUE(child->is_folder());
- ASSERT_EQ(L"OF1", child->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("OF1"), child->GetTitle());
ASSERT_EQ(0, child->GetChildCount());
child = parent->GetChild(1);
ASSERT_EQ(BookmarkNode::URL, child->type());
- ASSERT_EQ(L"About Google", child->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("About Google"), child->GetTitle());
ASSERT_TRUE(child->GetURL() ==
GURL("http://www.google.com/intl/en/about.html"));
@@ -935,11 +949,11 @@ TEST_F(BookmarkModelTestWithProfile2, RemoveNotification) {
// Add a URL.
GURL url("http://www.google.com");
- bb_model_->SetURLStarred(url, std::wstring(), true);
+ bb_model_->SetURLStarred(url, string16(), true);
profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->AddPage(
url, NULL, 1, GURL(), PageTransition::TYPED,
- history::RedirectList(), false);
+ history::RedirectList(), history::SOURCE_BROWSED, false);
// This won't actually delete the URL, rather it'll empty out the visits.
// This triggers blocking on the BookmarkModel.
@@ -950,15 +964,15 @@ TEST_F(BookmarkModelTest, Sort) {
// Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'.
// 'C' and 'a' are folders.
TestNode bbn;
- PopulateNodeFromString(L"B [ a ] d [ a ]", &bbn);
+ PopulateNodeFromString("B [ a ] d [ a ]", &bbn);
const BookmarkNode* parent = model.GetBookmarkBarNode();
PopulateBookmarkNode(&bbn, &model, parent);
BookmarkNode* child1 = AsMutable(parent->GetChild(1));
- child1->SetTitle(L"a");
+ child1->SetTitle(ASCIIToUTF16("a"));
delete child1->Remove(0);
BookmarkNode* child3 = AsMutable(parent->GetChild(3));
- child3->SetTitle(L"C");
+ child3->SetTitle(ASCIIToUTF16("C"));
delete child3->Remove(0);
ClearCounts();
@@ -971,8 +985,8 @@ TEST_F(BookmarkModelTest, Sort) {
// Make sure the order matches (remember, 'a' and 'C' are folders and
// come first).
- EXPECT_TRUE(parent->GetChild(0)->GetTitle() == L"a");
- EXPECT_TRUE(parent->GetChild(1)->GetTitle() == L"C");
- EXPECT_TRUE(parent->GetChild(2)->GetTitle() == L"B");
- EXPECT_TRUE(parent->GetChild(3)->GetTitle() == L"d");
+ EXPECT_EQ(parent->GetChild(0)->GetTitle(), ASCIIToUTF16("a"));
+ EXPECT_EQ(parent->GetChild(1)->GetTitle(), ASCIIToUTF16("C"));
+ EXPECT_EQ(parent->GetChild(2)->GetTitle(), ASCIIToUTF16("B"));
+ EXPECT_EQ(parent->GetChild(3)->GetTitle(), ASCIIToUTF16("d"));
}
diff --git a/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h b/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h
index 00cf6d7..6f26d7b 100644
--- a/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h
+++ b/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_PASTEBOARD_HELPER_MAC_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_PASTEBOARD_HELPER_MAC_H_
+#pragma once
#include "base/file_path.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
diff --git a/chrome/browser/bookmarks/bookmark_service.h b/chrome/browser/bookmarks/bookmark_service.h
index baa898b..1515dd9 100644
--- a/chrome/browser/bookmarks/bookmark_service.h
+++ b/chrome/browser/bookmarks/bookmark_service.h
@@ -1,34 +1,10 @@
-// Copyright 2009, 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.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_SERVICE_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_SERVICE_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/bookmarks/bookmark_storage.cc b/chrome/browser/bookmarks/bookmark_storage.cc
index 365ba37..6cfe003 100644
--- a/chrome/browser/bookmarks/bookmark_storage.cc
+++ b/chrome/browser/bookmarks/bookmark_storage.cc
@@ -125,6 +125,22 @@ class BookmarkStorage::LoadTask : public Task {
DISALLOW_COPY_AND_ASSIGN(LoadTask);
};
+// BookmarkLoadDetails ---------------------------------------------------------
+
+BookmarkLoadDetails::BookmarkLoadDetails(BookmarkNode* bb_node,
+ BookmarkNode* other_folder_node,
+ BookmarkIndex* index,
+ int64 max_id)
+ : bb_node_(bb_node),
+ other_folder_node_(other_folder_node),
+ index_(index),
+ max_id_(max_id),
+ ids_reassigned_(false) {
+}
+
+BookmarkLoadDetails::~BookmarkLoadDetails() {
+}
+
// BookmarkStorage -------------------------------------------------------------
BookmarkStorage::BookmarkStorage(Profile* profile, BookmarkModel* model)
diff --git a/chrome/browser/bookmarks/bookmark_storage.h b/chrome/browser/bookmarks/bookmark_storage.h
index 4182dc4..541b063 100644
--- a/chrome/browser/bookmarks/bookmark_storage.h
+++ b/chrome/browser/bookmarks/bookmark_storage.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_STORAGE_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_STORAGE_H_
+#pragma once
#include "base/file_path.h"
#include "base/ref_counted.h"
@@ -16,8 +17,6 @@
class BookmarkModel;
class BookmarkNode;
class Profile;
-class Task;
-class Value;
// BookmarkLoadDetails is used by BookmarkStorage when loading bookmarks.
// BookmarkModel creates a BookmarkLoadDetails and passes it (including
@@ -32,13 +31,8 @@ class BookmarkLoadDetails {
BookmarkLoadDetails(BookmarkNode* bb_node,
BookmarkNode* other_folder_node,
BookmarkIndex* index,
- int64 max_id)
- : bb_node_(bb_node),
- other_folder_node_(other_folder_node),
- index_(index),
- max_id_(max_id),
- ids_reassigned_(false) {
- }
+ int64 max_id);
+ ~BookmarkLoadDetails();
BookmarkNode* bb_node() { return bb_node_.get(); }
BookmarkNode* release_bb_node() { return bb_node_.release(); }
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index 211c4e6..9576721 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -4,15 +4,15 @@
#include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "app/clipboard/clipboard.h"
#include "app/drag_drop_types.h"
#include "app/l10n_util.h"
#include "app/tree_node_iterator.h"
#include "base/basictypes.h"
#include "base/file_path.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/string16.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#if defined(OS_MACOSX)
@@ -24,7 +24,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/history/query_parser.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -42,7 +42,6 @@
#include "views/widget/root_view.h"
#include "views/widget/widget.h"
#elif defined(TOOLKIT_GTK)
-#include "app/gtk_util.h"
#include "chrome/browser/gtk/custom_drag.h"
#endif
@@ -167,7 +166,7 @@ bool ShouldOpenAll(gfx::NativeWindow parent,
string16 message = l10n_util::GetStringFUTF16(
IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
- IntToString16(descendant_count));
+ base::IntToString16(descendant_count));
string16 title = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
return platform_util::SimpleYesNoBox(parent, title, message);
}
@@ -182,7 +181,7 @@ bool MoreRecentlyModified(const BookmarkNode* n1, const BookmarkNode* n2) {
bool DoesBookmarkTextContainWords(const string16& text,
const std::vector<string16>& words) {
for (size_t i = 0; i < words.size(); ++i) {
- if (text.find(words[i]) == std::wstring::npos)
+ if (text.find(words[i]) == string16::npos)
return false;
}
return true;
@@ -192,16 +191,15 @@ bool DoesBookmarkTextContainWords(const string16& text,
// |languages| argument is user's accept-language setting to decode IDN.
bool DoesBookmarkContainWords(const BookmarkNode* node,
const std::vector<string16>& words,
- const std::wstring& languages) {
+ const std::string& languages) {
return
DoesBookmarkTextContainWords(
- l10n_util::ToLower(WideToUTF16(node->GetTitle())), words) ||
+ l10n_util::ToLower(node->GetTitle()), words) ||
DoesBookmarkTextContainWords(
l10n_util::ToLower(UTF8ToUTF16(node->GetURL().spec())), words) ||
- DoesBookmarkTextContainWords(l10n_util::ToLower(WideToUTF16(
- net::FormatUrl(
- node->GetURL(), languages, net::kFormatUrlOmitNothing,
- UnescapeRule::NORMAL, NULL, NULL, NULL))), words);
+ DoesBookmarkTextContainWords(l10n_util::ToLower(
+ net::FormatUrl(node->GetURL(), languages, net::kFormatUrlOmitNothing,
+ UnescapeRule::NORMAL, NULL, NULL, NULL)), words);
}
} // namespace
@@ -503,13 +501,13 @@ bool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2) {
}
void GetBookmarksContainingText(BookmarkModel* model,
- const std::wstring& text,
+ const string16& text,
size_t max_count,
- const std::wstring& languages,
+ const std::string& languages,
std::vector<const BookmarkNode*>* nodes) {
std::vector<string16> words;
QueryParser parser;
- parser.ExtractQueryWords(l10n_util::ToLower(WideToUTF16(text)), &words);
+ parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
if (words.empty())
return;
@@ -525,11 +523,11 @@ void GetBookmarksContainingText(BookmarkModel* model,
}
bool DoesBookmarkContainText(const BookmarkNode* node,
- const std::wstring& text,
- const std::wstring& languages) {
+ const string16& text,
+ const std::string& languages) {
std::vector<string16> words;
QueryParser parser;
- parser.ExtractQueryWords(l10n_util::ToLower(WideToUTF16(text)), &words);
+ parser.ExtractQueryWords(l10n_util::ToLower(text), &words);
if (words.empty())
return false;
@@ -538,7 +536,7 @@ bool DoesBookmarkContainText(const BookmarkNode* node,
static const BookmarkNode* CreateNewNode(BookmarkModel* model,
const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
- const std::wstring& new_title, const GURL& new_url) {
+ const string16& new_title, const GURL& new_url) {
const BookmarkNode* node;
if (details.type == BookmarkEditor::EditDetails::NEW_URL) {
node = model->AddURL(parent, parent->GetChildCount(), new_title, new_url);
@@ -559,7 +557,7 @@ static const BookmarkNode* CreateNewNode(BookmarkModel* model,
const BookmarkNode* ApplyEditsWithNoGroupChange(BookmarkModel* model,
const BookmarkNode* parent, const BookmarkEditor::EditDetails& details,
- const std::wstring& new_title, const GURL& new_url) {
+ const string16& new_title, const GURL& new_url) {
if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
return CreateNewNode(model, parent, details, new_title, new_url);
@@ -577,7 +575,7 @@ const BookmarkNode* ApplyEditsWithNoGroupChange(BookmarkModel* model,
const BookmarkNode* ApplyEditsWithPossibleGroupChange(BookmarkModel* model,
const BookmarkNode* new_parent, const BookmarkEditor::EditDetails& details,
- const std::wstring& new_title, const GURL& new_url) {
+ const string16& new_title, const GURL& new_url) {
if (details.type == BookmarkEditor::EditDetails::NEW_URL ||
details.type == BookmarkEditor::EditDetails::NEW_FOLDER) {
return CreateNewNode(model, new_parent, details, new_title, new_url);
@@ -618,15 +616,15 @@ void RegisterUserPrefs(PrefService* prefs) {
void GetURLAndTitleToBookmark(TabContents* tab_contents,
GURL* url,
- std::wstring* title) {
+ string16* title) {
*url = tab_contents->GetURL();
- *title = UTF16ToWideHack(tab_contents->GetTitle());
+ *title = tab_contents->GetTitle();
}
void GetURLsForOpenTabs(Browser* browser,
- std::vector<std::pair<GURL, std::wstring> >* urls) {
+ std::vector<std::pair<GURL, string16> >* urls) {
for (int i = 0; i < browser->tab_count(); ++i) {
- std::pair<GURL, std::wstring> entry;
+ std::pair<GURL, string16> entry;
GetURLAndTitleToBookmark(browser->GetTabContentsAt(i), &(entry.first),
&(entry.second));
urls->push_back(entry);
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 37ee96c..9fccbad 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_
#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_
+#pragma once
#include <string>
#include <vector>
+#include "base/string16.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/history/snippet.h"
@@ -145,16 +147,16 @@ bool MoreRecentlyAdded(const BookmarkNode* n1, const BookmarkNode* n2);
// the text |text|. |languages| is user's accept-language setting to decode
// IDN.
void GetBookmarksContainingText(BookmarkModel* model,
- const std::wstring& text,
+ const string16& text,
size_t max_count,
- const std::wstring& languages,
+ const std::string& languages,
std::vector<const BookmarkNode*>* nodes);
// Returns true if |node|'s url or title contains the string |text|.
// |languages| is user's accept-language setting to decode IDN.
bool DoesBookmarkContainText(const BookmarkNode* node,
- const std::wstring& text,
- const std::wstring& languages);
+ const string16& text,
+ const std::string& languages);
// Modifies a bookmark node (assuming that there's no magic that needs to be
// done regarding moving from one folder to another). If a new node is
@@ -164,7 +166,7 @@ const BookmarkNode* ApplyEditsWithNoGroupChange(
BookmarkModel* model,
const BookmarkNode* parent,
const BookmarkEditor::EditDetails& details,
- const std::wstring& new_title,
+ const string16& new_title,
const GURL& new_url);
// Modifies a bookmark node assuming that the parent of the node may have
@@ -175,7 +177,7 @@ const BookmarkNode* ApplyEditsWithPossibleGroupChange(
BookmarkModel* model,
const BookmarkNode* new_parent,
const BookmarkEditor::EditDetails& details,
- const std::wstring& new_title,
+ const string16& new_title,
const GURL& new_url);
// Toggles whether the bookmark bar is shown only on the new tab page or on
@@ -188,12 +190,12 @@ void RegisterUserPrefs(PrefService* prefs);
// Fills in the URL and title for a bookmark of |tab_contents|.
void GetURLAndTitleToBookmark(TabContents* tab_contents,
GURL* url,
- std::wstring* title);
+ string16* title);
// Returns, by reference in |urls|, the url and title pairs for each open
// tab in browser.
void GetURLsForOpenTabs(Browser* browser,
- std::vector<std::pair<GURL, std::wstring> >* urls);
+ std::vector<std::pair<GURL, string16> >* urls);
// Returns the parent for newly created folders/bookmarks. If |selection| has
// one element and it is a folder, |selection[0]| is returned, otherwise
diff --git a/chrome/browser/bookmarks/bookmark_utils_unittest.cc b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
index 384a55e..f27ef8b 100644
--- a/chrome/browser/bookmarks/bookmark_utils_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_utils_unittest.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 "app/clipboard/scoped_clipboard_writer.h"
#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"
@@ -16,83 +17,84 @@ typedef testing::Test BookmarkUtilsTest;
TEST_F(BookmarkUtilsTest, GetBookmarksContainingText) {
BookmarkModel model(NULL);
const BookmarkNode* n1 =
- model.AddURL(model.other_node(), 0, L"foo bar",
+ model.AddURL(model.other_node(), 0, ASCIIToUTF16("foo bar"),
GURL("http://www.google.com"));
const BookmarkNode* n2 =
- model.AddURL(model.other_node(), 0, L"baz buz",
+ model.AddURL(model.other_node(), 0, ASCIIToUTF16("baz buz"),
GURL("http://www.cnn.com"));
- model.AddGroup(model.other_node(), 0, L"foo");
+ model.AddGroup(model.other_node(), 0, ASCIIToUTF16("foo"));
std::vector<const BookmarkNode*> nodes;
bookmark_utils::GetBookmarksContainingText(
- &model, L"foo", 100, std::wstring(), &nodes);
+ &model, ASCIIToUTF16("foo"), 100, std::string(), &nodes);
ASSERT_EQ(1U, nodes.size());
EXPECT_TRUE(nodes[0] == n1);
EXPECT_TRUE(bookmark_utils::DoesBookmarkContainText(
- n1, L"foo", std::wstring()));
+ n1, ASCIIToUTF16("foo"), std::string()));
nodes.clear();
bookmark_utils::GetBookmarksContainingText(
- &model, L"cnn", 100, std::wstring(), &nodes);
+ &model, ASCIIToUTF16("cnn"), 100, std::string(), &nodes);
ASSERT_EQ(1U, nodes.size());
EXPECT_TRUE(nodes[0] == n2);
EXPECT_TRUE(bookmark_utils::DoesBookmarkContainText(
- n2, L"cnn", std::wstring()));
+ n2, ASCIIToUTF16("cnn"), std::string()));
nodes.clear();
bookmark_utils::GetBookmarksContainingText(
- &model, L"foo bar", 100, std::wstring(), &nodes);
+ &model, ASCIIToUTF16("foo bar"), 100, std::string(), &nodes);
ASSERT_EQ(1U, nodes.size());
EXPECT_TRUE(nodes[0] == n1);
EXPECT_TRUE(bookmark_utils::DoesBookmarkContainText(
- n1, L"foo bar", std::wstring()));
+ n1, ASCIIToUTF16("foo bar"), std::string()));
nodes.clear();
}
TEST_F(BookmarkUtilsTest, DoesBookmarkContainText) {
BookmarkModel model(NULL);
- const BookmarkNode* node = model.AddURL(model.other_node(), 0, L"foo bar",
+ const BookmarkNode* node = model.AddURL(model.other_node(), 0,
+ ASCIIToUTF16("foo bar"),
GURL("http://www.google.com"));
// Matches to the title.
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"ar", std::wstring()));
+ node, ASCIIToUTF16("ar"), std::string()));
// Matches to the URL
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"www", std::wstring()));
+ node, ASCIIToUTF16("www"), std::string()));
// No match.
ASSERT_FALSE(bookmark_utils::DoesBookmarkContainText(
- node, L"cnn", std::wstring()));
+ node, ASCIIToUTF16("cnn"), std::string()));
// Tests for a Japanese IDN.
- const wchar_t* kDecodedIdn = L"\x30B0\x30FC\x30B0\x30EB";
- node = model.AddURL(model.other_node(), 0, L"foo bar",
+ const string16 kDecodedIdn = WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB");
+ node = model.AddURL(model.other_node(), 0, ASCIIToUTF16("foo bar"),
GURL("http://xn--qcka1pmc.jp"));
// Unicode query doesn't match if languages have no "ja".
ASSERT_FALSE(bookmark_utils::DoesBookmarkContainText(
- node, kDecodedIdn, L"en"));
+ node, kDecodedIdn, "en"));
// Unicode query matches if languages have "ja".
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, kDecodedIdn, L"ja"));
+ node, kDecodedIdn, "ja"));
// Punycode query also matches as ever.
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"qcka1pmc", L"ja"));
+ node, ASCIIToUTF16("qcka1pmc"), "ja"));
// Tests with various lower/upper case characters.
- node = model.AddURL(model.other_node(), 0, L"FOO bar",
+ node = model.AddURL(model.other_node(), 0, ASCIIToUTF16("FOO bar"),
GURL("http://www.google.com/search?q=ABC"));
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"foo", std::wstring()));
+ node, ASCIIToUTF16("foo"), std::string()));
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"Foo", std::wstring()));
+ node, ASCIIToUTF16("Foo"), std::string()));
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"FOO", std::wstring()));
+ node, ASCIIToUTF16("FOO"), std::string()));
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"google abc", std::wstring()));
+ node, ASCIIToUTF16("google abc"), std::string()));
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"google ABC", std::wstring()));
+ node, ASCIIToUTF16("google ABC"), std::string()));
ASSERT_TRUE(bookmark_utils::DoesBookmarkContainText(
- node, L"http://www.google.com/search?q=A", std::wstring()));
+ node, ASCIIToUTF16("http://www.google.com/search?q=A"), std::string()));
}
#if !defined(OS_MACOSX)
@@ -101,7 +103,8 @@ TEST_F(BookmarkUtilsTest, CopyPaste) {
MessageLoopForUI loop;
BookmarkModel model(NULL);
- const BookmarkNode* node = model.AddURL(model.other_node(), 0, L"foo bar",
+ const BookmarkNode* node = model.AddURL(model.other_node(), 0,
+ ASCIIToUTF16("foo bar"),
GURL("http://www.google.com"));
// Copy a node to the clipboard.
diff --git a/chrome/browser/bookmarks/recently_used_folders_combo_model.cc b/chrome/browser/bookmarks/recently_used_folders_combo_model.cc
index cd6bfc1..e6309f4 100644
--- a/chrome/browser/bookmarks/recently_used_folders_combo_model.cc
+++ b/chrome/browser/bookmarks/recently_used_folders_combo_model.cc
@@ -53,9 +53,9 @@ int RecentlyUsedFoldersComboModel::GetItemCount() {
return static_cast<int>(nodes_.size() + 1);
}
-std::wstring RecentlyUsedFoldersComboModel::GetItemAt(int index) {
+string16 RecentlyUsedFoldersComboModel::GetItemAt(int index) {
if (index == static_cast<int>(nodes_.size()))
- return l10n_util::GetString(IDS_BOOMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
+ return l10n_util::GetStringUTF16(IDS_BOOMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
return nodes_[index]->GetTitle();
}
diff --git a/chrome/browser/bookmarks/recently_used_folders_combo_model.h b/chrome/browser/bookmarks/recently_used_folders_combo_model.h
index 2a8dac0..adf36a9 100644
--- a/chrome/browser/bookmarks/recently_used_folders_combo_model.h
+++ b/chrome/browser/bookmarks/recently_used_folders_combo_model.h
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_RECENTLY_FOLDERS_COMBO_MODEL_H_
-#define CHROME_BROWSER_RECENTLY_FOLDERS_COMBO_MODEL_H_
+#ifndef CHROME_BROWSER_BOOKMARKS_RECENTLY_USED_FOLDERS_COMBO_MODEL_H_
+#define CHROME_BROWSER_BOOKMARKS_RECENTLY_USED_FOLDERS_COMBO_MODEL_H_
+#pragma once
#include <vector>
#include "app/combobox_model.h"
+#include "base/string16.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
// Model for the combobox showing the list of folders to choose from. The
@@ -19,9 +21,9 @@ class RecentlyUsedFoldersComboModel : public ComboboxModel {
// Overridden from ComboboxModel:
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
- // Returns the node at the specified index.
+ // Returns the node at the specified |index|.
const BookmarkNode* GetNodeAt(int index);
// Returns the index of the original parent folder.
@@ -37,4 +39,4 @@ class RecentlyUsedFoldersComboModel : public ComboboxModel {
DISALLOW_COPY_AND_ASSIGN(RecentlyUsedFoldersComboModel);
};
-#endif // CHROME_BROWSER_RECENTLY_FOLDERS_COMBO_MODEL_H_
+#endif // CHROME_BROWSER_BOOKMARKS_RECENTLY_USED_FOLDERS_COMBO_MODEL_H_
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index c07538f..13bfbc1 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -16,11 +16,11 @@
#include "app/l10n_util.h"
#include "base/base_paths.h"
#include "base/command_line.h"
-#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "gfx/point.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/autofill/autofill_manager.h"
@@ -36,6 +36,7 @@
#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/content_settings_handler.h"
#include "chrome/browser/dom_ui/filebrowse_ui.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_item_model.h"
@@ -45,14 +46,15 @@
#include "chrome/browser/extensions/crashed_extension_infobar.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
-#include "chrome/browser/extensions/extension_shelf_model.h"
+#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/first_run.h"
-#include "chrome/browser/google_url_tracker.h"
-#include "chrome/browser/google_util.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/location_bar.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -60,22 +62,27 @@
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/options_window.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.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/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/service/service_process_control_manager.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"
#include "chrome/browser/tab_contents/interstitial_page.h"
+#include "chrome/browser/tab_contents/match_preview.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_menu_model.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/window_sizer.h"
@@ -96,6 +103,10 @@
#include "net/url_request/url_request_context.h"
#include "webkit/glue/window_open_disposition.h"
+#if defined(ENABLE_REMOTING)
+#include "chrome/browser/remoting/remoting_setup_flow.h"
+#endif
+
#if defined(OS_WIN)
#include "app/win_util.h"
#include "chrome/browser/browser_child_process_host.h"
@@ -103,7 +114,7 @@
#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.h"
+#include "chrome/browser/task_manager/task_manager.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/app_launcher.h"
#include "chrome/browser/views/location_bar/location_bar_view.h"
@@ -114,6 +125,9 @@
#endif
#if defined(OS_CHROMEOS)
+#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"
#include "chrome/browser/views/app_launcher.h"
#endif
@@ -131,6 +145,8 @@ static const std::string kBrokenPageUrl =
"http://www.google.com/support/chrome/bin/request.py?contact_type="
"broken_website&format=inproduct&p.page_title=$1&p.page_url=$2";
+static const std::string kHashMark = "#";
+
///////////////////////////////////////////////////////////////////////////////
namespace {
@@ -158,24 +174,6 @@ bool CompareURLsIgnoreRef(const GURL& url, const GURL& other) {
return url_no_ref == other_no_ref;
}
-// Return true if a browser is an app window or panel hosting
-// extension |extension_app|, and running under |profile|.
-bool BrowserHostsExtensionApp(Browser* browser,
- Profile* profile,
- Extension* extension_app) {
- if (browser->profile() != profile)
- return false;
-
- if (browser->type() != Browser::TYPE_EXTENSION_APP &&
- browser->type() != Browser::TYPE_APP_PANEL)
- return false;
-
- if (browser->extension_app() != extension_app)
- return false;
-
- return true;
-}
-
} // namespace
///////////////////////////////////////////////////////////////////////////////
@@ -185,7 +183,8 @@ Browser::Browser(Type type, Profile* profile)
: type_(type),
profile_(profile),
window_(NULL),
- tabstrip_model_(this, profile),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ tab_handler_(TabHandler::CreateTabHandler(this))),
command_updater_(this),
toolbar_model_(this),
chrome_updater_factory_(this),
@@ -198,8 +197,6 @@ Browser::Browser(Type type, Profile* profile)
last_blocked_command_disposition_(CURRENT_TAB),
pending_web_app_action_(NONE),
extension_app_(NULL) {
- tabstrip_model_.AddObserver(this);
-
registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
@@ -242,13 +239,14 @@ Browser::Browser(Type type, Profile* profile)
if (profile_->GetProfileSyncService())
profile_->GetProfileSyncService()->AddObserver(this);
+
+ if (type == TYPE_NORMAL && MatchPreview::IsEnabled() &&
+ !profile->IsOffTheRecord()) {
+ match_preview_.reset(new MatchPreview(this));
+ }
}
Browser::~Browser() {
- // The tab strip should not have any significant tabs at this point.
- DCHECK(!tabstrip_model_.HasNonPhantomTabs());
- tabstrip_model_.RemoveObserver(this);
-
if (profile_->GetProfileSyncService())
profile_->GetProfileSyncService()->RemoveObserver(this);
@@ -301,22 +299,31 @@ Browser* Browser::Create(Profile* profile) {
// static
Browser* Browser::CreateForPopup(Profile* profile) {
- Browser* browser = new Browser(TYPE_POPUP, profile);
+ Browser* browser = CreateForType(TYPE_POPUP, profile);
+ return browser;
+}
+
+// static
+Browser* Browser::CreateForType(Type type, Profile* profile) {
+ Browser* browser = new Browser(type, profile);
browser->CreateBrowserWindow();
return browser;
}
// static
-Browser* Browser::CreateForApp(const std::wstring& app_name,
+Browser* Browser::CreateForApp(const std::string& app_name,
Extension* extension,
Profile* profile,
bool is_panel) {
Browser::Type type = TYPE_APP;
- if (is_panel)
- type = TYPE_APP_PANEL;
- else if (extension)
+ if (is_panel) {
+ // 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;
@@ -345,9 +352,6 @@ Browser* Browser::CreateForDevTools(Profile* profile) {
void Browser::CreateBrowserWindow() {
DCHECK(!window_);
- if (SupportsWindowFeature(FEATURE_EXTENSIONSHELF))
- extension_shelf_model_.reset(new ExtensionShelfModel(this));
-
window_ = BrowserWindow::CreateBrowserWindow(this);
#if defined(OS_WIN)
@@ -355,7 +359,7 @@ void Browser::CreateBrowserWindow() {
// name. See http://crbug.com/7028.
win_util::SetAppIdForWindow(
type_ & TYPE_APP ?
- ShellIntegration::GetAppId(app_name_, profile_->GetPath()) :
+ ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) :
ShellIntegration::GetChromiumAppId(profile_->GetPath()),
window()->GetNativeHandle());
#endif
@@ -371,15 +375,15 @@ void Browser::CreateBrowserWindow() {
return;
if (local_state->FindPreference(prefs::kShouldShowFirstRunBubble) &&
local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
- FirstRun::BubbleType bubble_type = FirstRun::LARGEBUBBLE;
+ FirstRun::BubbleType bubble_type = FirstRun::LARGE_BUBBLE;
if (local_state->
FindPreference(prefs::kShouldUseOEMFirstRunBubble) &&
local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble)) {
- bubble_type = FirstRun::OEMBUBBLE;
+ bubble_type = FirstRun::OEM_BUBBLE;
} else if (local_state->
FindPreference(prefs::kShouldUseMinimalFirstRunBubble) &&
local_state->GetBoolean(prefs::kShouldUseMinimalFirstRunBubble)) {
- bubble_type = FirstRun::MINIMALBUBBLE;
+ bubble_type = FirstRun::MINIMAL_BUBBLE;
}
// Reset the preference so we don't show the bubble for subsequent windows.
local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
@@ -441,48 +445,11 @@ void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
// TODO(eroman): should we have referrer here?
browser->AddTabWithURL(
url, GURL(), PageTransition::LINK, -1, TabStripModel::ADD_SELECTED, NULL,
- std::string());
+ std::string(), &browser);
browser->window()->Show();
}
// static
-Browser* Browser::FindAppWindowOrPanel(Profile* profile,
- Extension* extension_app) {
- // Test the focused browser first.
- Browser* browser = BrowserList::GetLastActive();
- if (browser && BrowserHostsExtensionApp(browser, profile, extension_app))
- return browser;
-
- BrowserList::const_iterator browser_all;
- for (browser_all = BrowserList::begin();
- browser_all != BrowserList::end();
- ++browser_all) {
- if (BrowserHostsExtensionApp(*browser_all, profile, extension_app))
- return *browser_all;
- }
- return NULL;
-}
-
-// static
-TabContents* Browser::FindAppTab(Browser* browser, Extension* extension_app) {
- if (browser->type() != Browser::TYPE_NORMAL)
- return NULL;
-
- for (int tab_idx = 0; tab_idx < browser->tab_count(); ++tab_idx) {
- TabContents* tab_contents = browser->GetTabContentsAt(tab_idx);
- if (!tab_contents)
- continue;
-
- if (tab_contents->extension_app() != extension_app)
- continue;
-
- return tab_contents;
- }
-
- return NULL;
-}
-
-// static
// TODO(erikkay): There are multiple reasons why this could fail. Should
// this function return an error reason as well so that callers can show
// reasonable errors?
@@ -502,50 +469,27 @@ TabContents* Browser::OpenApplication(Profile* profile,
}
// static
-TabContents* Browser::OpenApplication(Profile* profile,
- Extension* extension,
- Extension::LaunchContainer container) {
+TabContents* Browser::OpenApplication(
+ Profile* profile,
+ Extension* extension,
+ extension_misc::LaunchContainer container) {
TabContents* tab = NULL;
- // If the app is loaded in an existing window or panel, focus it.
- Browser* browser = FindAppWindowOrPanel(profile, extension);
- if (browser) {
- browser->window()->Show();
- return browser->GetSelectedTabContents();
- }
-
- // If an app is loaded in an app tab in the focused browser, select it.
- browser = BrowserList::GetLastActive();
- if (browser && browser->profile() == profile) {
- tab = Browser::FindAppTab(browser, extension);
- if (tab) {
- int tab_idx = browser->tabstrip_model()->GetIndexOfTabContents(tab);
- DCHECK(tab_idx != TabStripModel::kNoTab);
- browser->SelectTabContentsAt(tab_idx, false);
- return tab;
- }
- }
-
// The app is not yet open. Load it.
switch (container) {
- case Extension::LAUNCH_WINDOW:
- case Extension::LAUNCH_PANEL:
+ case extension_misc::LAUNCH_WINDOW:
+ case extension_misc::LAUNCH_PANEL:
tab = Browser::OpenApplicationWindow(profile, extension, container,
- GURL());
+ GURL(), NULL);
break;
- case Extension::LAUNCH_TAB: {
- tab = Browser::OpenApplicationTab(profile, extension);
+ case extension_misc::LAUNCH_TAB: {
+ tab = Browser::OpenApplicationTab(profile, extension, NULL);
break;
}
default:
NOTREACHED();
break;
}
- if (tab) {
- Browser* browser = tab->delegate()->GetBrowser();
- if (browser && extension && extension->launch_fullscreen())
- browser->window()->SetFullscreen(true);
- }
return tab;
}
@@ -553,8 +497,9 @@ TabContents* Browser::OpenApplication(Profile* profile,
TabContents* Browser::OpenApplicationWindow(
Profile* profile,
Extension* extension,
- Extension::LaunchContainer container,
- const GURL& url_input) {
+ extension_misc::LaunchContainer container,
+ const GURL& url_input,
+ Browser** browser) {
GURL url;
if (!url_input.is_empty()) {
if (extension)
@@ -566,19 +511,19 @@ TabContents* Browser::OpenApplicationWindow(
}
// TODO(erikkay) this can't be correct for extensions
- std::wstring app_name = web_app::GenerateApplicationNameFromURL(url);
+ std::string app_name = web_app::GenerateApplicationNameFromURL(url);
RegisterAppPrefs(app_name);
- bool as_panel = extension && (container == Extension::LAUNCH_PANEL);
- Browser* browser = Browser::CreateForApp(app_name, extension, profile,
- as_panel);
- TabContents* tab_contents = browser->AddTabWithURL(
+ bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL);
+ Browser* local_browser = Browser::CreateForApp(app_name, extension, profile,
+ as_panel);
+ TabContents* tab_contents = local_browser->AddTabWithURL(
url, GURL(), PageTransition::START_PAGE, -1, TabStripModel::ADD_SELECTED,
- NULL, std::string());
+ NULL, std::string(), &local_browser);
tab_contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
tab_contents->render_view_host()->SyncRendererPrefs();
- browser->window()->Show();
+ local_browser->window()->Show();
// TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
// focus explicitly.
@@ -591,33 +536,48 @@ TabContents* Browser::OpenApplicationWindow(
// OnDidGetApplicationInfo, which calls
// web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as
// pending web app action.
- browser->pending_web_app_action_ = UPDATE_SHORTCUT;
+ local_browser->pending_web_app_action_ = UPDATE_SHORTCUT;
}
+ if (browser)
+ *browser = local_browser;
+
return tab_contents;
}
// static
TabContents* Browser::OpenApplicationWindow(Profile* profile,
- GURL& url) {
- return OpenApplicationWindow(profile, NULL, Extension::LAUNCH_WINDOW, url);
+ GURL& url, Browser** browser) {
+ return OpenApplicationWindow(profile, NULL, extension_misc::LAUNCH_WINDOW,
+ url, browser);
}
// static
TabContents* Browser::OpenApplicationTab(Profile* profile,
- Extension* extension) {
- Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
- if (!browser || browser->type() != Browser::TYPE_NORMAL)
- return NULL;
+ Extension* extension,
+ Browser** browser) {
+ Browser* local_browser = BrowserList::GetLastActiveWithProfile(profile);
+ TabContents* tab_contents = NULL;
+ if (!local_browser || local_browser->type() != Browser::TYPE_NORMAL)
+ return tab_contents;
+
+ // Check the prefs for overridden mode.
+ ExtensionsService* extensions_service = profile->GetExtensionsService();
+ DCHECK(extensions_service);
+
+ ExtensionPrefs::LaunchType launch_type =
+ extensions_service->extension_prefs()->GetLaunchType(extension->id());
+ int add_type = TabStripModel::ADD_SELECTED;
+ if (launch_type == ExtensionPrefs::LAUNCH_PINNED)
+ add_type |= TabStripModel::ADD_PINNED;
+
+ // TODO(erikkay): START_PAGE doesn't seem like the right transition in all
+ // cases.
+ tab_contents = local_browser->AddTabWithURL(extension->GetFullLaunchURL(),
+ GURL(), PageTransition::START_PAGE, -1, add_type, NULL, "", browser);
+ if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN)
+ local_browser->window()->SetFullscreen(true);
- // TODO(erikkay): This doesn't seem like the right transition in all cases.
- PageTransition::Type transition = PageTransition::START_PAGE;
- GURL url = extension->GetFullLaunchURL();
- TabContents* tab_contents =
- browser->CreateTabContentsForURL(url, GURL(), profile,
- transition, false, NULL);
- tab_contents->SetExtensionApp(extension);
- browser->AddTab(tab_contents, transition);
return tab_contents;
}
@@ -652,7 +612,7 @@ void Browser::OpenHelpWindow(Profile* profile) {
void Browser::OpenOptionsWindow(Profile* profile) {
Browser* browser = Browser::Create(profile);
- browser->ShowOptionsTab();
+ browser->ShowOptionsTab(chrome::kDefaultOptionsSubPage);
browser->window()->Show();
}
#endif
@@ -668,10 +628,10 @@ void Browser::OpenExtensionsWindow(Profile* profile) {
///////////////////////////////////////////////////////////////////////////////
// Browser, State Storage and Retrieval for UI:
-std::wstring Browser::GetWindowPlacementKey() const {
- std::wstring name(prefs::kBrowserWindowPlacement);
+std::string Browser::GetWindowPlacementKey() const {
+ std::string name(prefs::kBrowserWindowPlacement);
if (!app_name_.empty()) {
- name.append(L"_");
+ name.append("_");
name.append(app_name_);
}
return name;
@@ -741,7 +701,8 @@ SkBitmap Browser::GetCurrentPageIcon() const {
}
string16 Browser::GetWindowTitleForCurrentTab() const {
- TabContents* contents = tabstrip_model_.GetSelectedTabContents();
+ TabContents* contents =
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents();
string16 title;
// |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
@@ -770,8 +731,7 @@ string16 Browser::GetWindowTitleForCurrentTab() const {
void Browser::FormatTitleForDisplay(string16* title) {
size_t current_index = 0;
size_t match_index;
- while ((match_index = title->find(L'\n', current_index)) !=
- std::wstring::npos) {
+ while ((match_index = title->find(L'\n', current_index)) != string16::npos) {
title->replace(match_index, 1, string16());
current_index = match_index;
}
@@ -836,6 +796,9 @@ void Browser::OnWindowClosing() {
Source<Browser>(this),
Details<bool>(&exiting));
+ // Shutdown all IPC channels to service processes.
+ ServiceProcessControlManager::instance()->Shutdown();
+
CloseAllTabs();
}
@@ -859,11 +822,43 @@ void Browser::InProgressDownloadResponse(bool cancel_downloads) {
}
////////////////////////////////////////////////////////////////////////////////
+// Browser, TabStripModel pass-thrus:
+
+int Browser::tab_count() const {
+ return tab_handler_->GetTabStripModel()->count();
+}
+
+int Browser::selected_index() const {
+ return tab_handler_->GetTabStripModel()->selected_index();
+}
+
+int Browser::GetIndexOfController(
+ const NavigationController* controller) const {
+ return tab_handler_->GetTabStripModel()->GetIndexOfController(controller);
+}
+
+TabContents* Browser::GetTabContentsAt(int index) const {
+ return tab_handler_->GetTabStripModel()->GetTabContentsAt(index);
+}
+
+TabContents* Browser::GetSelectedTabContents() const {
+ return tab_handler_->GetTabStripModel()->GetSelectedTabContents();
+}
+
+void Browser::SelectTabContentsAt(int index, bool user_gesture) {
+ tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, user_gesture);
+}
+
+void Browser::CloseAllTabs() {
+ tab_handler_->GetTabStripModel()->CloseAllTabs();
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Browser, Tab adding/showing functions:
int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
- return (tabstrip_model_.insertion_policy() == TabStripModel::INSERT_AFTER) ?
- tab_count() : relative_index;
+ return (tab_handler_->GetTabStripModel()->insertion_policy() ==
+ TabStripModel::INSERT_AFTER) ? tab_count() : relative_index;
}
TabContents* Browser::AddTabWithURL(const GURL& url,
@@ -872,7 +867,8 @@ TabContents* Browser::AddTabWithURL(const GURL& url,
int index,
int add_types,
SiteInstance* instance,
- const std::string& extension_app_id) {
+ const std::string& extension_app_id,
+ Browser** browser_used) {
TabContents* contents = NULL;
if (CanSupportWindowFeature(FEATURE_TABSTRIP) || tabstrip_model()->empty()) {
GURL url_to_load = url;
@@ -881,7 +877,8 @@ TabContents* Browser::AddTabWithURL(const GURL& url,
contents = CreateTabContentsForURL(url_to_load, referrer, profile_,
transition, false, instance);
contents->SetExtensionAppById(extension_app_id);
- tabstrip_model_.AddTabContents(contents, index, transition, add_types);
+ tab_handler_->GetTabStripModel()->AddTabContents(contents, index,
+ transition, add_types);
// TODO(sky): figure out why this is needed. Without it we seem to get
// failures in startup tests.
// By default, content believes it is not hidden. When adding contents
@@ -890,6 +887,9 @@ TabContents* Browser::AddTabWithURL(const GURL& url,
// TabStripModel::AddTabContents invokes HideContents if not foreground.
contents->WasHidden();
}
+
+ if (browser_used)
+ *browser_used = this;
} else {
// We're in an app window or a popup window. Find an existing browser to
// open this URL in, creating one if none exists.
@@ -898,15 +898,18 @@ TabContents* Browser::AddTabWithURL(const GURL& url,
if (!b)
b = Browser::Create(profile_);
contents = b->AddTabWithURL(url, referrer, transition, index, add_types,
- instance, extension_app_id);
+ instance, extension_app_id, &b);
b->window()->Show();
+
+ if (browser_used)
+ *browser_used = b;
}
return contents;
}
TabContents* Browser::AddTab(TabContents* tab_contents,
PageTransition::Type type) {
- tabstrip_model_.AddTabContents(
+ tab_handler_->GetTabStripModel()->AddTabContents(
tab_contents, -1, type, TabStripModel::ADD_SELECTED);
return tab_contents;
}
@@ -942,20 +945,23 @@ TabContents* Browser::AddRestoredTab(
const std::string& extension_app_id,
bool select,
bool pin,
- bool from_last_session) {
- TabContents* new_tab = new TabContents(profile(), NULL,
- MSG_ROUTING_NONE, tabstrip_model_.GetSelectedTabContents());
+ bool from_last_session,
+ SessionStorageNamespace* session_storage_namespace) {
+ TabContents* new_tab = new TabContents(
+ profile(), NULL, MSG_ROUTING_NONE,
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents(),
+ session_storage_namespace);
new_tab->SetExtensionAppById(extension_app_id);
new_tab->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
bool really_pin =
(pin && tab_index == tabstrip_model()->IndexOfFirstNonMiniTab());
- tabstrip_model_.InsertTabContentsAt(
+ tab_handler_->GetTabStripModel()->InsertTabContentsAt(
tab_index, new_tab,
select ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE);
if (really_pin)
- tabstrip_model_.SetTabPinned(tab_index, true);
+ tab_handler_->GetTabStripModel()->SetTabPinned(tab_index, true);
if (select) {
window_->Activate();
} else {
@@ -980,15 +986,18 @@ void Browser::ReplaceRestoredTab(
const std::vector<TabNavigation>& navigations,
int selected_navigation,
bool from_last_session,
- const std::string& extension_app_id) {
+ const std::string& extension_app_id,
+ SessionStorageNamespace* session_storage_namespace) {
TabContents* replacement = new TabContents(profile(), NULL,
- MSG_ROUTING_NONE, tabstrip_model_.GetSelectedTabContents());
+ MSG_ROUTING_NONE,
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents(),
+ session_storage_namespace);
replacement->SetExtensionAppById(extension_app_id);
replacement->controller().RestoreFromState(navigations, selected_navigation,
from_last_session);
- tabstrip_model_.ReplaceNavigationControllerAt(
- tabstrip_model_.selected_index(),
+ tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt(
+ tab_handler_->GetTabStripModel()->selected_index(),
&replacement->controller());
}
@@ -1016,18 +1025,19 @@ void Browser::ShowSingletonTab(const GURL& url) {
&reverse_on_redirect);
// See if we already have a tab with the given URL and select it if so.
- for (int i = 0; i < tabstrip_model_.count(); i++) {
- TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
+ TabStripModel* model = tab_handler_->GetTabStripModel();
+ for (int i = 0; i < model->count(); i++) {
+ TabContents* tc = model->GetTabContentsAt(i);
if (CompareURLsIgnoreRef(tc->GetURL(), url) ||
CompareURLsIgnoreRef(tc->GetURL(), rewritten_url)) {
- tabstrip_model_.SelectTabContentsAt(i, false);
+ model->SelectTabContentsAt(i, false);
return;
}
}
// Otherwise, just create a new tab.
AddTabWithURL(url, GURL(), PageTransition::AUTO_BOOKMARK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(), NULL);
}
void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
@@ -1065,10 +1075,18 @@ void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
// Show various bits of UI
command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui);
- command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, show_main_ui);
+ command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR,
+ browser_defaults::bookmarks_enabled && show_main_ui);
command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS,
show_main_ui && profile_->IsSyncAccessible());
+
+#if defined(ENABLE_REMOTING)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableRemoting)) {
+ command_updater_.UpdateCommandEnabled(IDC_REMOTING_SETUP, show_main_ui);
+ }
+#endif
+
command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
@@ -1102,7 +1120,7 @@ TabContents* Browser::GetOrCloneTabForDisposition(
TabContents* current_tab = GetSelectedTabContents();
if (ShouldOpenNewTabForWindowDisposition(disposition)) {
current_tab = current_tab->Clone();
- tabstrip_model_.AddTabContents(
+ tab_handler_->GetTabStripModel()->AddTabContents(
current_tab, -1, PageTransition::LINK,
disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED :
TabStripModel::ADD_NONE);
@@ -1111,7 +1129,7 @@ TabContents* Browser::GetOrCloneTabForDisposition(
}
void Browser::UpdateTabStripModelInsertionPolicy() {
- tabstrip_model_.SetInsertionPolicy(UseVerticalTabs() ?
+ tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ?
TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
}
@@ -1130,7 +1148,7 @@ bool Browser::SupportsWindowFeatureImpl(WindowFeature feature,
window_->IsFullscreen();
#endif
- unsigned int features = FEATURE_INFOBAR;
+ unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR;
#if !defined(OS_CHROMEOS)
// Chrome OS opens a FileBrowse pop up instead of using download shelf.
@@ -1140,7 +1158,6 @@ bool Browser::SupportsWindowFeatureImpl(WindowFeature feature,
if (type() == TYPE_NORMAL) {
features |= FEATURE_BOOKMARKBAR;
- features |= FEATURE_EXTENSIONSHELF;
}
if (!hide_ui_for_fullscreen) {
@@ -1229,36 +1246,10 @@ void Browser::OpenCurrentURL() {
LocationBar* location_bar = window_->GetLocationBar();
WindowOpenDisposition open_disposition =
location_bar->GetWindowOpenDisposition();
- GURL url(WideToUTF8(location_bar->GetInputString()));
-
- if (open_disposition == CURRENT_TAB) {
- TabContents* selected_contents = GetSelectedTabContents();
- Extension* extension = profile()->GetExtensionsService()
- ->GetExtensionByWebExtent(url);
-
- if (extension && selected_contents &&
- selected_contents->GetURL().GetOrigin() ==
- GURL(chrome::kChromeUINewTabURL).GetOrigin()) {
- // If the |url| is within an app's web extent and it was typed into the
- // omnibox of an NTP page, interpret as an app launch and close the NTP
- // tab.
- Browser::OpenApplication(profile(), extension,
- extension->launch_container());
- CloseTabContents(selected_contents);
- return;
- }
+ if (OpenMatchPreview(open_disposition))
+ return;
- if (selected_contents) {
- // For the purposes of changing the window open disposition, the referrer
- // is the current tab's URL.
- open_disposition = AdjustWindowOpenDispositionForTab(
- IsPinned(selected_contents),
- url,
- selected_contents->GetURL(),
- location_bar->GetPageTransition(),
- open_disposition);
- }
- }
+ GURL url(WideToUTF8(location_bar->GetInputString()));
// Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
// inherit the opener. In some cases the tabstrip will determine the group
@@ -1323,8 +1314,8 @@ void Browser::CloseTab() {
UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"),
profile_);
if (CanCloseTab()) {
- tabstrip_model_.CloseTabContentsAt(
- tabstrip_model_.selected_index(),
+ tab_handler_->GetTabStripModel()->CloseTabContentsAt(
+ tab_handler_->GetTabStripModel()->selected_index(),
TabStripModel::CLOSE_USER_GESTURE |
TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
}
@@ -1332,35 +1323,49 @@ void Browser::CloseTab() {
void Browser::SelectNextTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_);
- tabstrip_model_.SelectNextTab();
+ tab_handler_->GetTabStripModel()->SelectNextTab();
}
void Browser::SelectPreviousTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_);
- tabstrip_model_.SelectPreviousTab();
+ tab_handler_->GetTabStripModel()->SelectPreviousTab();
+}
+
+void Browser::OpenTabpose() {
+#if defined(OS_MACOSX)
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExposeForTabs)) {
+ return;
+ }
+
+ UserMetrics::RecordAction(UserMetricsAction("OpenTabpose"), profile_);
+ window()->OpenTabpose();
+#else
+ NOTREACHED();
+#endif
}
void Browser::MoveTabNext() {
UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_);
- tabstrip_model_.MoveTabNext();
+ tab_handler_->GetTabStripModel()->MoveTabNext();
}
void Browser::MoveTabPrevious() {
UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_);
- tabstrip_model_.MoveTabPrevious();
+ tab_handler_->GetTabStripModel()->MoveTabPrevious();
}
void Browser::SelectNumberedTab(int index) {
if (index < tab_count()) {
UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"),
profile_);
- tabstrip_model_.SelectTabContentsAt(index, true);
+ tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, true);
}
}
void Browser::SelectLastTab() {
UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_);
- tabstrip_model_.SelectLastTab();
+ tab_handler_->GetTabStripModel()->SelectLastTab();
}
void Browser::DuplicateTab() {
@@ -1388,14 +1393,15 @@ void Browser::WriteCurrentURLToClipboard() {
chrome_browser_net::WriteURLToClipboard(
contents->GetURL(),
- UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)),
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
g_browser_process->clipboard());
}
void Browser::ConvertPopupToTabbedBrowser() {
UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_);
- int tab_strip_index = tabstrip_model_.selected_index();
- TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
+ int tab_strip_index = tab_handler_->GetTabStripModel()->selected_index();
+ TabContents* contents =
+ tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index);
Browser* browser = Browser::Create(profile_);
browser->tabstrip_model()->AppendTabContents(contents, true);
browser->window()->Show();
@@ -1427,6 +1433,11 @@ void Browser::Search() {
CloseTab();
return;
}
+
+ // Exit fullscreen to show omnibox.
+ if (window_->IsFullscreen())
+ ToggleFullscreenMode();
+
// Otherwise just open it.
NewTab();
}
@@ -1434,6 +1445,13 @@ void Browser::Search() {
void Browser::Exit() {
UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
+#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
BrowserList::CloseAllBrowsersAndExit();
}
@@ -1445,7 +1463,7 @@ void Browser::BookmarkCurrentPage() {
return; // Ignore requests until bookmarks are loaded.
GURL url;
- std::wstring title;
+ string16 title;
bookmark_utils::GetURLAndTitleToBookmark(GetSelectedTabContents(), &url,
&title);
bool was_bookmarked = model->IsBookmarked(url);
@@ -1682,15 +1700,8 @@ void Browser::OpenTaskManager() {
}
void Browser::OpenBugReportDialog() {
-#if defined(OS_CHROMEOS)
UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
window_->ShowReportBugDialog();
-#else
- TabContents* contents = GetSelectedTabContents();
- if (!contents)
- return;
- ShowBrokenPageTab(contents);
-#endif
}
void Browser::ToggleBookmarkBar() {
@@ -1698,12 +1709,6 @@ void Browser::ToggleBookmarkBar() {
window_->ToggleBookmarkBar();
}
-void Browser::ToggleExtensionShelf() {
- UserMetrics::RecordAction(UserMetricsAction("ToggleExtensionShelf"),
- profile_);
- window_->ToggleExtensionShelf();
-}
-
void Browser::OpenBookmarkManager() {
UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_);
ShowBookmarkManagerTab();
@@ -1765,30 +1770,65 @@ void Browser::ShowBrokenPageTab(TabContents* contents) {
ShowSingletonTab(GURL(report_page_url));
}
-void Browser::ShowOptionsTab() {
- UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_);
- ShowSingletonTab(GURL(chrome::kChromeUIOptionsURL));
+void Browser::ShowOptionsTab(const std::string& sub_page) {
+ GURL url(chrome::kChromeUISettingsURL + sub_page);
+
+ // See if there is already an options tab open that we can use.
+ TabStripModel* model = tab_handler_->GetTabStripModel();
+ for (int i = 0; i < model->count(); i++) {
+ TabContents* tc = model->GetTabContentsAt(i);
+ const GURL& tab_url = tc->GetURL();
+
+ if (tab_url.scheme() == url.scheme() && tab_url.host() == url.host()) {
+ // We found an existing options tab, load the URL in this tab. (Note:
+ // this may cause us to unnecessarily reload the same page. We can't
+ // really detect that unless the options page is permitted to change the
+ // URL in the address bar, but security policy doesn't allow that.
+ OpenURLAtIndex(tc, url, GURL(), CURRENT_TAB, PageTransition::GENERATED,
+ -1, -1);
+ model->SelectTabContentsAt(i, false);
+ return;
+ }
+ }
+
+ // No options tab found, so create a new one.
+ AddTabWithURL(url, GURL(), PageTransition::AUTO_BOOKMARK, -1,
+ TabStripModel::ADD_SELECTED, NULL, std::string(), NULL);
}
void Browser::OpenClearBrowsingDataDialog() {
UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"),
profile_);
- window_->ShowClearBrowsingDataDialog();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ ShowOptionsTab(
+ chrome::kAdvancedOptionsSubPage + kHashMark +
+ chrome::kClearBrowserDataSubPage);
+ } else {
+ window_->ShowClearBrowsingDataDialog();
+ }
}
void Browser::OpenOptionsDialog() {
+ UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_);
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableTabbedOptions)) {
- ShowOptionsTab();
+ ShowOptionsTab(chrome::kDefaultOptionsSubPage);
} else {
- UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_);
ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
}
}
void Browser::OpenKeywordEditor() {
UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_);
- window_->ShowSearchEnginesDialog();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ ShowOptionsTab(
+ chrome::kBrowserOptionsSubPage + kHashMark +
+ chrome::kSearchEnginesOptionsSubPage);
+ } else {
+ window_->ShowSearchEnginesDialog();
+ }
}
void Browser::OpenPasswordManager() {
@@ -1797,7 +1837,14 @@ void Browser::OpenPasswordManager() {
void Browser::OpenImportSettingsDialog() {
UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
- window_->ShowImportDialog();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ ShowOptionsTab(
+ chrome::kPersonalOptionsSubPage + kHashMark +
+ chrome::kImportDataSubPage);
+ } else {
+ window_->ShowImportDialog();
+ }
}
void Browser::OpenSyncMyBookmarksDialog() {
@@ -1805,9 +1852,19 @@ void Browser::OpenSyncMyBookmarksDialog() {
profile_, ProfileSyncService::START_FROM_WRENCH);
}
+#if defined(ENABLE_REMOTING)
+void Browser::OpenRemotingSetupDialog() {
+ RemotingSetupFlow::OpenDialog(profile_);
+}
+#endif
+
void Browser::OpenAboutChromeDialog() {
UserMetrics::RecordAction(UserMetricsAction("AboutChrome"), profile_);
+#if defined(OS_CHROMEOS)
+ ShowSingletonTab(GURL(chrome::kChromeUIAboutURL));
+#else
window_->ShowAboutChromeDialog();
+#endif
}
void Browser::OpenUpdateChromeDialog() {
@@ -1818,7 +1875,7 @@ void Browser::OpenUpdateChromeDialog() {
void Browser::OpenHelpTab() {
GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kHelpContentUrl));
AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(), NULL);
}
void Browser::OpenThemeGalleryTabAndActivate() {
@@ -1839,17 +1896,50 @@ void Browser::OpenAutoFillHelpTabAndActivate() {
window_->Activate();
}
+void Browser::OpenSearchEngineOptionsDialog() {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ OpenKeywordEditor();
+ } else {
+ ShowOptionsWindow(OPTIONS_PAGE_GENERAL, OPTIONS_GROUP_DEFAULT_SEARCH,
+ profile_);
+ }
+}
+
#if defined(OS_CHROMEOS)
void Browser::OpenSystemOptionsDialog() {
UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"),
profile_);
- ShowOptionsWindow(OPTIONS_PAGE_SYSTEM, OPTIONS_GROUP_NONE, profile_);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ ShowOptionsTab(chrome::kSystemOptionsSubPage);
+ } else {
+ ShowOptionsWindow(OPTIONS_PAGE_SYSTEM, OPTIONS_GROUP_NONE,
+ profile_);
+ }
}
void Browser::OpenInternetOptionsDialog() {
UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"),
profile_);
- ShowOptionsWindow(OPTIONS_PAGE_INTERNET, OPTIONS_GROUP_NONE, profile_);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ ShowOptionsTab(chrome::kInternetOptionsSubPage);
+ } else {
+ ShowOptionsWindow(OPTIONS_PAGE_INTERNET, OPTIONS_GROUP_DEFAULT_SEARCH,
+ profile_);
+ }
+}
+
+void Browser::OpenLanguageOptionsDialog() {
+ UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"),
+ profile_);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ ShowOptionsTab(chrome::kLanguageOptionsSubPage);
+ } else {
+ chromeos::LanguageConfigView::Show(profile_, NULL);
+ }
}
#endif
@@ -1879,6 +1969,7 @@ void Browser::RegisterPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1);
prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement);
+ prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1);
}
// static
@@ -1910,13 +2001,30 @@ void Browser::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true);
- prefs->RegisterBooleanPref(prefs::kShowExtensionShelf, true);
prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true);
prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true);
prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true);
prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false);
prefs->RegisterBooleanPref(prefs::kEnableTranslate, true);
- prefs->RegisterIntegerPref(prefs::kNTPPromoViewsRemaining, 5);
+ prefs->RegisterBooleanPref(prefs::kRemotingHasSetupCompleted, false);
+ prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string());
+}
+
+// static
+bool Browser::RunUnloadEventsHelper(TabContents* contents) {
+ // If the TabContents is not connected yet, then there's no unload
+ // handler we can fire even if the TabContents has an unload listener.
+ // One case where we hit this is in a tab that has an infinite loop
+ // before load.
+ if (TabHasUnloadListener(contents)) {
+ // If the page has unload listeners, then we tell the renderer to fire
+ // them. Once they have fired, we'll get a message back saying whether
+ // to proceed closing the page or not, which sends us back to this method
+ // with the HasUnloadListener bit cleared.
+ contents->render_view_host()->FirePageBeforeUnload(false);
+ return true;
+ }
+ return false;
}
// static
@@ -1924,7 +2032,8 @@ Browser* Browser::GetBrowserForController(
const NavigationController* controller, int* index_result) {
BrowserList::const_iterator it;
for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
- int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
+ int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController(
+ controller);
if (index != TabStripModel::kNoTab) {
if (index_result)
*index_result = index;
@@ -1979,6 +2088,7 @@ void Browser::ExecuteCommandWithDisposition(
case IDC_CLOSE_TAB: CloseTab(); break;
case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
+ case IDC_TABPOSE: OpenTabpose(); break;
case IDC_MOVE_TAB_NEXT: MoveTabNext(); break;
case IDC_MOVE_TAB_PREVIOUS: MoveTabPrevious(); break;
case IDC_SELECT_TAB_0:
@@ -2089,7 +2199,6 @@ void Browser::ExecuteCommandWithDisposition(
case IDC_REPORT_BUG: OpenBugReportDialog(); break;
case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
- case IDC_SHOW_EXTENSION_SHELF: ToggleExtensionShelf(); break;
case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
case IDC_SHOW_APP_MENU: ShowAppMenu(); break;
@@ -2097,21 +2206,21 @@ void Browser::ExecuteCommandWithDisposition(
case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
case IDC_MANAGE_EXTENSIONS: ShowExtensionsTab(); break;
case IDC_SYNC_BOOKMARKS: OpenSyncMyBookmarksDialog(); break;
+#if defined(ENABLE_REMOTING)
+ case IDC_REMOTING_SETUP: OpenRemotingSetupDialog(); break;
+#endif
case IDC_OPTIONS: OpenOptionsDialog(); break;
case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
- case IDC_ABOUT:
- if (Singleton<UpgradeDetector>::get()->notify_upgrade())
- OpenUpdateChromeDialog();
- else
- OpenAboutChromeDialog();
- break;
+ case IDC_ABOUT: OpenAboutChromeDialog(); break;
+ case IDC_UPGRADE_DIALOG: OpenUpdateChromeDialog(); break;
case IDC_HELP_PAGE: OpenHelpTab(); break;
#if defined(OS_CHROMEOS)
case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break;
case IDC_INTERNET_OPTIONS: OpenInternetOptionsDialog(); break;
+ case IDC_LANGUAGE_OPTIONS: OpenLanguageOptionsDialog(); break;
#endif
default:
@@ -2129,6 +2238,7 @@ bool Browser::IsReservedCommand(int command_id) {
command_id == IDC_RESTORE_TAB ||
command_id == IDC_SELECT_NEXT_TAB ||
command_id == IDC_SELECT_PREVIOUS_TAB ||
+ command_id == IDC_TABPOSE ||
command_id == IDC_EXIT ||
command_id == IDC_SEARCH;
}
@@ -2148,6 +2258,14 @@ int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) {
}
///////////////////////////////////////////////////////////////////////////////
+// Browser, PageNavigator implementation:
+void Browser::OpenURL(const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {
+ OpenURLFromTab(NULL, url, referrer, disposition, transition);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Browser, CommandUpdater::CommandUpdaterDelegate implementation:
void Browser::ExecuteCommand(int id) {
@@ -2155,6 +2273,17 @@ void Browser::ExecuteCommand(int id) {
}
///////////////////////////////////////////////////////////////////////////////
+// Browser, TabHandlerDelegate implementation:
+
+Profile* Browser::GetProfile() const {
+ return profile();
+}
+
+Browser* Browser::AsBrowser() {
+ return this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Browser, TabStripModelDelegate implementation:
TabContents* Browser::AddBlankTab(bool foreground) {
@@ -2169,18 +2298,18 @@ TabContents* Browser::AddBlankTabAt(int index, bool foreground) {
TabContents* tab_contents = AddTabWithURL(
GURL(chrome::kChromeUINewTabURL), GURL(), PageTransition::TYPED, index,
foreground ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE, NULL,
- std::string());
+ std::string(), NULL);
tab_contents->set_new_tab_start_time(new_tab_start_time);
return tab_contents;
}
Browser* Browser::CreateNewStripWithContents(TabContents* detached_contents,
const gfx::Rect& window_bounds,
- const DockInfo& dock_info) {
+ const DockInfo& dock_info,
+ bool maximize) {
DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP));
gfx::Rect new_window_bounds = window_bounds;
- bool maximize = false;
if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
dock_info.AdjustOtherWindowBounds();
@@ -2210,7 +2339,8 @@ void Browser::ContinueDraggingDetachedTab(TabContents* contents,
}
int Browser::GetDragActions() const {
- return TAB_TEAROFF_ACTION | (tab_count() > 1 ? TAB_MOVE_ACTION : 0);
+ return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ?
+ TabStripModelDelegate::TAB_MOVE_ACTION : 0);
}
TabContents* Browser::CreateTabContentsForURL(
@@ -2218,7 +2348,8 @@ TabContents* Browser::CreateTabContentsForURL(
PageTransition::Type transition, bool defer_load,
SiteInstance* instance) const {
TabContents* contents = new TabContents(profile, instance,
- MSG_ROUTING_NONE, tabstrip_model_.GetSelectedTabContents());
+ MSG_ROUTING_NONE,
+ tab_handler_->GetTabStripModel()->GetSelectedTabContents(), NULL);
if (!defer_load) {
// Load the initial URL before adding the new tab contents to the tab strip
@@ -2244,11 +2375,13 @@ void Browser::DuplicateContentsAt(int index) {
// If this is a tabbed browser, just create a duplicate tab inside the same
// window next to the tab being duplicated.
new_contents = contents->Clone();
- pinned = tabstrip_model_.IsTabPinned(index);
+ pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index);
int add_types = TabStripModel::ADD_SELECTED |
TabStripModel::ADD_INHERIT_GROUP |
(pinned ? TabStripModel::ADD_PINNED : 0);
- tabstrip_model_.InsertTabContentsAt(index + 1, new_contents, add_types);
+ tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
+ new_contents,
+ add_types);
} else {
Browser* browser = NULL;
if (type_ & TYPE_APP) {
@@ -2320,7 +2453,7 @@ bool Browser::CanReloadContents(TabContents* source) const {
bool Browser::CanCloseContentsAt(int index) {
if (!CanCloseTab())
return false;
- if (tabstrip_model_.count() > 1)
+ if (tab_handler_->GetTabStripModel()->count() > 1)
return true;
// We are closing the last tab for this browser. Make sure to check for
// in-progress downloads.
@@ -2359,6 +2492,13 @@ void Browser::ToggleUseVerticalTabs() {
UseVerticalTabsChanged();
}
+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();
+}
+
///////////////////////////////////////////////////////////////////////////////
// Browser, TabStripModelObserver implementation:
@@ -2395,6 +2535,9 @@ void Browser::TabDetachedAt(TabContents* contents, int index) {
}
void Browser::TabDeselectedAt(TabContents* contents, int index) {
+ if (match_preview())
+ match_preview()->DestroyPreviewContents();
+
// Save what the user's currently typing, so it can be restored when we
// switch back to this tab.
window_->GetLocationBar()->SaveStateToContents(contents);
@@ -2425,7 +2568,8 @@ void Browser::TabSelectedAt(TabContents* old_contents,
status_bubble->Hide();
// Show the loading state (if any).
- status_bubble->SetStatus(GetSelectedTabContents()->GetStatusText());
+ status_bubble->SetStatus(WideToUTF16Hack(
+ GetSelectedTabContents()->GetStatusText()));
}
if (HasFindBarController()) {
@@ -2437,9 +2581,9 @@ void Browser::TabSelectedAt(TabContents* old_contents,
// exist, the change will be picked up by sessions when created.
if (profile_->HasSessionService()) {
SessionService* session_service = profile_->GetSessionService();
- if (session_service && !tabstrip_model_.closing_all()) {
+ if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) {
session_service->SetSelectedTabInWindow(
- session_id(), tabstrip_model_.selected_index());
+ session_id(), tab_handler_->GetTabStripModel()->selected_index());
}
}
}
@@ -2456,7 +2600,7 @@ void Browser::TabReplacedAt(TabContents* old_contents,
TabContents* new_contents, int index) {
TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE);
TabInsertedAt(new_contents, index,
- (index == tabstrip_model_.selected_index()));
+ (index == tab_handler_->GetTabStripModel()->selected_index()));
int entry_count = new_contents->controller().entry_count();
if (entry_count > 0) {
@@ -2475,7 +2619,7 @@ void Browser::TabPinnedStateChanged(TabContents* contents, int index) {
session_service->SetPinnedState(
session_id(),
GetTabContentsAt(index)->controller().session_id(),
- tabstrip_model_.IsTabPinned(index));
+ tab_handler_->GetTabStripModel()->IsTabPinned(index));
}
}
@@ -2493,14 +2637,6 @@ void Browser::TabStripEmpty() {
}
///////////////////////////////////////////////////////////////////////////////
-// Browser, PageNavigator implementation:
-void Browser::OpenURL(const GURL& url, const GURL& referrer,
- WindowOpenDisposition disposition,
- PageTransition::Type transition) {
- OpenURLFromTab(NULL, url, referrer, disposition, transition);
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Browser, TabContentsDelegate implementation:
void Browser::OpenURLFromTab(TabContents* source,
@@ -2536,7 +2672,8 @@ void Browser::AddNewContents(TabContents* source,
// If this is a window with no tabstrip, we can only have one tab so we need
// to process this in tabbed browser window.
if (!CanSupportWindowFeature(FEATURE_TABSTRIP) &&
- tabstrip_model_.count() > 0 && disposition != NEW_WINDOW &&
+ tab_handler_->GetTabStripModel()->count() > 0 &&
+ disposition != NEW_WINDOW &&
disposition != NEW_POPUP) {
Browser* b = GetOrCreateTabbedBrowser(profile_);
DCHECK(b);
@@ -2562,7 +2699,7 @@ void Browser::AddNewContents(TabContents* source,
initial_pos, user_gesture);
browser->window()->Show();
} else if (disposition != SUPPRESS_OPEN) {
- tabstrip_model_.AddTabContents(
+ tab_handler_->GetTabStripModel()->AddTabContents(
new_contents, -1, PageTransition::LINK,
disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED :
TabStripModel::ADD_NONE);
@@ -2570,19 +2707,29 @@ void Browser::AddNewContents(TabContents* source,
}
void Browser::ActivateContents(TabContents* contents) {
- tabstrip_model_.SelectTabContentsAt(
- tabstrip_model_.GetIndexOfTabContents(contents), false);
+ tab_handler_->GetTabStripModel()->SelectTabContentsAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents), false);
window_->Activate();
}
+void Browser::DeactivateContents(TabContents* contents) {
+ window_->Deactivate();
+}
+
void Browser::LoadingStateChanged(TabContents* source) {
- window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
+ window_->UpdateLoadingAnimations(
+ tab_handler_->GetTabStripModel()->TabsAreLoading());
window_->UpdateTitleBar();
if (source == GetSelectedTabContents()) {
UpdateReloadStopState(source->is_loading(), false);
- if (GetStatusBubble())
- GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
+ if (GetStatusBubble()) {
+ GetStatusBubble()->SetStatus(WideToUTF16(
+ GetSelectedTabContents()->GetStatusText()));
+ }
+
+ if (source->is_loading())
+ UpdateZoomCommandsForTabState();
if (!source->is_loading() &&
pending_web_app_action_ == UPDATE_SHORTCUT) {
@@ -2610,12 +2757,12 @@ void Browser::CloseContents(TabContents* source) {
return;
}
- int index = tabstrip_model_.GetIndexOfTabContents(source);
+ int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source);
if (index == TabStripModel::kNoTab) {
NOTREACHED() << "CloseContents called for tab not in our strip";
return;
}
- tabstrip_model_.CloseTabContentsAt(
+ tab_handler_->GetTabStripModel()->CloseTabContentsAt(
index,
TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
}
@@ -2629,12 +2776,12 @@ void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
}
void Browser::DetachContents(TabContents* source) {
- int index = tabstrip_model_.GetIndexOfTabContents(source);
+ int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source);
if (index >= 0)
- tabstrip_model_.DetachTabContentsAt(index);
+ tab_handler_->GetTabStripModel()->DetachTabContentsAt(index);
}
-bool Browser::IsPopup(TabContents* source) {
+bool Browser::IsPopup(const TabContents* source) const {
// A non-tabbed BROWSER is an unconstrained popup.
return !!(type() & TYPE_POPUP);
}
@@ -2646,10 +2793,6 @@ void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
}
}
-void Browser::ExtensionShelfSizeChanged() {
- window_->SelectedTabExtensionShelfSizeChanged();
-}
-
void Browser::URLStarredChanged(TabContents* source, bool starred) {
if (source == GetSelectedTabContents())
window_->SetStarredState(starred);
@@ -2663,7 +2806,7 @@ void Browser::ContentsMouseEvent(
if (source == GetSelectedTabContents()) {
GetStatusBubble()->MouseMoved(location, !motion);
if (!motion)
- GetStatusBubble()->SetURL(GURL(), std::wstring());
+ GetStatusBubble()->SetURL(GURL(), string16());
}
}
@@ -2674,7 +2817,7 @@ void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
if (source == GetSelectedTabContents()) {
PrefService* prefs = profile_->GetPrefs();
GetStatusBubble()->SetURL(
- url, UTF8ToWide(prefs->GetString(prefs::kAcceptLanguages)));
+ url, UTF8ToUTF16(prefs->GetString(prefs::kAcceptLanguages)));
}
}
@@ -2688,7 +2831,9 @@ bool Browser::UseVerticalTabs() const {
}
void Browser::ContentsZoomChange(bool zoom_in) {
- ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
+ int command_id = zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS;
+ if (command_updater_.IsCommandEnabled(command_id))
+ ExecuteCommand(command_id);
}
void Browser::OnContentSettingsChange(TabContents* source) {
@@ -2723,7 +2868,7 @@ bool Browser::IsApplication() const {
void Browser::ConvertContentsToApplication(TabContents* contents) {
const GURL& url = contents->controller().GetActiveEntry()->url();
- std::wstring app_name = web_app::GenerateApplicationNameFromURL(url);
+ std::string app_name = web_app::GenerateApplicationNameFromURL(url);
RegisterAppPrefs(app_name);
DetachContents(contents);
@@ -2799,7 +2944,7 @@ int Browser::GetExtraRenderViewHeight() const {
return window_->GetExtraRenderViewHeight();
}
-void Browser::OnStartDownload(DownloadItem* download) {
+void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) {
if (!window())
return;
@@ -2837,6 +2982,12 @@ void Browser::OnStartDownload(DownloadItem* download) {
DownloadStartedAnimation::Show(current_tab);
}
#endif
+
+ // If the download occurs in a new tab, close it
+ if (tab->controller().IsInitialNavigation() &&
+ GetConstrainingContents(tab) == tab && tab_count() > 1) {
+ CloseContents(tab);
+ }
}
void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url,
@@ -2865,15 +3016,25 @@ void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) {
}
void Browser::ShowContentSettingsWindow(ContentSettingsType content_type) {
- window()->ShowContentSettingsWindow(content_type,
- profile_->GetOriginalProfile());
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ ShowOptionsTab(
+ chrome::kContentSettingsSubPage + kHashMark +
+ ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type));
+ } else {
+ window()->ShowContentSettingsWindow(content_type,
+ profile_->GetOriginalProfile());
+ }
}
void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) {
window()->ShowCollectedCookiesDialog(tab_contents);
}
-bool Browser::ShouldAddNavigationsToHistory() const {
+bool Browser::ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type) {
// Don't update history if running as app.
return !IsApplication();
}
@@ -2905,8 +3066,9 @@ void Browser::OnDidGetApplicationInfo(TabContents* tab_contents,
pending_web_app_action_ = NONE;
}
-Browser* Browser::GetBrowser() {
- return this;
+void Browser::ContentTypeChanged(TabContents* source) {
+ if (source == GetSelectedTabContents())
+ UpdateZoomCommandsForTabState();
}
///////////////////////////////////////////////////////////////////////////////
@@ -2953,13 +3115,14 @@ void Browser::Observe(NotificationType type,
case NotificationType::EXTENSION_UPDATE_DISABLED: {
// Show the UI if the extension was disabled for escalated permissions.
Profile* profile = Source<Profile>(source).ptr();
- DCHECK_EQ(profile_, profile);
- ExtensionsService* service = profile->GetExtensionsService();
- DCHECK(service);
- Extension* extension = Details<Extension>(details).ptr();
- if (service->extension_prefs()->DidExtensionEscalatePermissions(
- extension->id()))
- ShowExtensionDisabledUI(service, profile_, extension);
+ if (profile_->IsSameProfile(profile)) {
+ ExtensionsService* service = profile->GetExtensionsService();
+ DCHECK(service);
+ Extension* extension = Details<Extension>(details).ptr();
+ if (service->extension_prefs()->DidExtensionEscalatePermissions(
+ extension->id()))
+ ShowExtensionDisabledUI(service, profile_, extension);
+ }
break;
}
@@ -2969,12 +3132,12 @@ void Browser::Observe(NotificationType type,
// Close any tabs from the unloaded extension.
Extension* extension = Details<Extension>(details).ptr();
- for (int i = 0; i < tabstrip_model_.count(); i++) {
- TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
+ TabStripModel* model = tab_handler_->GetTabStripModel();
+ for (int i = model->count() - 1; i >= 0; --i) {
+ TabContents* tc = model->GetTabContentsAt(i);
if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
tc->GetURL().host() == extension->id()) {
CloseTabContents(tc);
- return;
}
}
@@ -3049,7 +3212,7 @@ void Browser::Observe(NotificationType type,
}
case NotificationType::PREF_CHANGED: {
- if (*(Details<std::wstring>(details).ptr()) == prefs::kUseVerticalTabs)
+ if (*(Details<std::string>(details).ptr()) == prefs::kUseVerticalTabs)
UseVerticalTabsChanged();
else
NOTREACHED();
@@ -3078,6 +3241,40 @@ void Browser::OnStateChanged() {
}
///////////////////////////////////////////////////////////////////////////////
+// Browser, MatchPreviewDelegate implementation:
+
+void Browser::ShowMatchPreview() {
+ DCHECK(match_preview_->tab_contents() == GetSelectedTabContents());
+ window_->ShowMatchPreview();
+}
+
+void Browser::HideMatchPreview() {
+ window_->HideMatchPreview();
+}
+
+void Browser::CommitMatchPreview(TabContents* preview_contents) {
+ TabContents* tab_contents = match_preview_->tab_contents();
+ int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(
+ tab_contents);
+ DCHECK_NE(-1, index);
+ preview_contents->controller().CopyStateFromAndPrune(
+ tab_contents->controller());
+ // TabStripModel takes ownership of preview_contents.
+ tab_handler_->GetTabStripModel()->ReplaceTabContentsAt(
+ index,
+ preview_contents,
+ TabStripModelObserver::REPLACE_MATCH_PREVIEW);
+}
+
+void Browser::SetSuggestedText(const string16& text) {
+ window()->GetLocationBar()->SetSuggestedText(text);
+}
+
+gfx::Rect Browser::GetMatchPreviewBounds() {
+ return window()->GetMatchPreviewBounds();
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Browser, Command and state updating (private):
void Browser::InitCommandState() {
@@ -3097,7 +3294,6 @@ void Browser::InitCommandState() {
command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, false);
- command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, true);
command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, true);
@@ -3162,8 +3358,8 @@ void Browser::InitCommandState() {
command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT, true);
command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
- command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
- command_updater_.UpdateCommandEnabled(IDC_SHOW_EXTENSION_SHELF, true);
+ command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER,
+ browser_defaults::bookmarks_enabled);
command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true);
@@ -3188,6 +3384,8 @@ void Browser::InitCommandState() {
command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
// Window management commands
+ command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN,
+ type() != TYPE_APP_PANEL);
command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
normal_window);
@@ -3202,9 +3400,13 @@ void Browser::InitCommandState() {
command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
+#if defined(OS_MACOSX)
+ command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window);
+#endif
// Page-related commands
- command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE, normal_window);
+ command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE,
+ browser_defaults::bookmarks_enabled && normal_window);
// Clipboard commands
command_updater_.UpdateCommandEnabled(IDC_COPY_URL, non_devtools_window);
@@ -3221,6 +3423,10 @@ void Browser::InitCommandState() {
// Show various bits of UI
command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window);
+ // The upgrade entry should always be enabled. Whether it is visible is a
+ // separate matter determined on menu show.
+ command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
+
// Initialize other commands whose state changes based on fullscreen mode.
UpdateCommandsForFullscreenMode(false);
}
@@ -3251,7 +3457,7 @@ void Browser::UpdateCommandsForTabState() {
// Page-related commands
window_->SetStarredState(current_tab->is_starred());
command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS,
- CanBookmarkAllTabs());
+ browser_defaults::bookmarks_enabled && CanBookmarkAllTabs());
command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
current_tab->controller().CanViewSource());
// Instead of using GetURL here, we use url() (which is the "real" url of the
@@ -3262,11 +3468,16 @@ void Browser::UpdateCommandsForTabState() {
bool is_savable_url =
SavePackage::IsSavableURL(active_entry ? active_entry->url() : GURL());
command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE, is_savable_url);
- command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU, is_savable_url &&
- SavePackage::IsSavableContents(current_tab->contents_mime_type()));
command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION,
current_tab->ShouldDisplayURL() && current_tab->GetURL().is_valid());
+ // Changing the encoding is not possible on Chrome-internal webpages.
+ bool is_chrome_internal = (active_entry ?
+ active_entry->url().SchemeIs(chrome::kChromeUIScheme) : false);
+ command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
+ !is_chrome_internal && SavePackage::IsSavableContents(
+ current_tab->contents_mime_type()));
+
// Show various bits of UI
// TODO(pinkerton): Disable app-mode in the model until we implement it
// on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
@@ -3274,6 +3485,15 @@ void Browser::UpdateCommandsForTabState() {
command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
web_app::IsValidUrl(current_tab->GetURL()));
#endif
+ UpdateZoomCommandsForTabState();
+}
+
+void Browser::UpdateZoomCommandsForTabState() {
+ // Disable zoom commands for PDF content.
+ bool enable_zoom = !GetSelectedTabContents()->is_displaying_pdf_content();
+ command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, enable_zoom);
+ command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, enable_zoom);
+ command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, enable_zoom);
}
void Browser::UpdateReloadStopState(bool is_loading, bool force) {
@@ -3306,8 +3526,9 @@ void Browser::ScheduleUIUpdate(const TabContents* source,
// Update the loading state synchronously. This is so the throbber will
// immediately start/stop, which gives a more snappy feel. We want to do
// this for any tab so they start & stop quickly.
- tabstrip_model_.UpdateTabContentsStateAt(
- tabstrip_model_.GetIndexOfController(&source->controller()),
+ tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfController(
+ &source->controller()),
TabStripModelObserver::LOADING_ONLY);
// The status bubble needs to be updated during INVALIDATE_LOAD too, but
// we do that asynchronously by not stripping INVALIDATE_LOAD from
@@ -3319,16 +3540,15 @@ void Browser::ScheduleUIUpdate(const TabContents* source,
// we need to process the update synchronously. This state only matters for
// the TabStripModel, so we notify the TabStripModel now and notify others
// asynchronously.
- tabstrip_model_.UpdateTabContentsStateAt(
- tabstrip_model_.GetIndexOfController(&source->controller()),
+ tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfController(
+ &source->controller()),
TabStripModelObserver::TITLE_NOT_LOADING);
}
- if (changed_flags & TabContents::INVALIDATE_BOOKMARK_BAR ||
- changed_flags & TabContents::INVALIDATE_EXTENSION_SHELF) {
+ if (changed_flags & TabContents::INVALIDATE_BOOKMARK_BAR) {
window()->ShelfVisibilityChanged();
- changed_flags &= ~(TabContents::INVALIDATE_BOOKMARK_BAR |
- TabContents::INVALIDATE_EXTENSION_SHELF);
+ changed_flags &= ~TabContents::INVALIDATE_BOOKMARK_BAR;
}
// If the only updates were synchronously handled above, we're done.
@@ -3382,7 +3602,7 @@ void Browser::ProcessPendingUIUpdates() {
// Updating the URL happens synchronously in ScheduleUIUpdate.
if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble())
- GetStatusBubble()->SetStatus(contents->GetStatusText());
+ GetStatusBubble()->SetStatus(WideToUTF16(contents->GetStatusText()));
if (flags & (TabContents::INVALIDATE_TAB |
TabContents::INVALIDATE_TITLE)) {
@@ -3398,8 +3618,8 @@ void Browser::ProcessPendingUIUpdates() {
// Updates that don't depend upon the selected state go here.
if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) {
- tabstrip_model_.UpdateTabContentsStateAt(
- tabstrip_model_.GetIndexOfTabContents(contents),
+ tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
+ tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents),
TabStripModelObserver::ALL);
}
@@ -3444,9 +3664,10 @@ void Browser::SyncHistoryWithTabs(int index) {
if (contents) {
session_service->SetTabIndexInWindow(
session_id(), contents->controller().session_id(), i);
- session_service->SetPinnedState(session_id(),
- contents->controller().session_id(),
- tabstrip_model_.IsTabPinned(i));
+ session_service->SetPinnedState(
+ session_id(),
+ contents->controller().session_id(),
+ tab_handler_->GetTabStripModel()->IsTabPinned(i));
}
}
}
@@ -3559,14 +3780,20 @@ bool Browser::CanCloseWithInProgressDownloads() {
bool normal_downloads_are_present = false;
bool incognito_downloads_are_present = false;
// If there are no download in-progress, our job is done.
- DownloadManager* download_manager = profile_->GetDownloadManager();
+ 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()) {
// Browser is incognito and so download_manager if present is for incognito
// downloads.
incognito_downloads_are_present =
(download_manager && download_manager->in_progress_count() != 0);
// Check original profile.
- download_manager = profile_->GetOriginalProfile()->GetDownloadManager();
+ if (profile_->GetOriginalProfile()->HasCreatedDownloadManager())
+ download_manager = profile_->GetOriginalProfile()->GetDownloadManager();
}
normal_downloads_are_present =
@@ -3629,121 +3856,19 @@ bool Browser::CanCloseWithInProgressDownloads() {
// Browser, Assorted utility functions (private):
// static
+Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) {
+ return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL,
+ match_incognito);
+}
+
+// static
Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) {
- Browser* browser = BrowserList::FindBrowserWithType(profile, TYPE_NORMAL,
- false);
+ Browser* browser = GetTabbedBrowser(profile, false);
if (!browser)
browser = Browser::Create(profile);
return browser;
}
-bool Browser::HandleCrossAppNavigation(TabContents* source,
- const GURL& url,
- const GURL& referrer,
- WindowOpenDisposition* disposition,
- PageTransition::Type transition) {
- // Can be null in unit tests.
- ExtensionsService* service = profile_->GetExtensionsService();
- if (!service)
- return false;
-
- // Can be null, e.g., when executed in a browser with no tabs.
- if (!source)
- return false;
-
- // Get the source extension, if any.
- Extension* source_extension = source->extension_app();
- if (!source_extension)
- source_extension = extension_app_;
-
- // Get the destination URL's extension, if any.
- Extension* destination_extension = service->GetExtensionByURL(url);
- if (!destination_extension)
- destination_extension = service->GetExtensionByWebExtent(url);
-
- // If they are the same, nothing to do.
- if (source_extension == destination_extension)
- return false;
-
- // If there is a source extension and the new URL is part of its browse
- // extent, also do nothing.
- if (source_extension && source_extension->browse_extent().ContainsURL(url))
- return false;
-
- if (destination_extension) {
- // Search for an existing app window for this app.
- for (BrowserList::const_iterator iter = BrowserList::begin();
- iter != BrowserList::end(); ++iter) {
- // Found an app window, open the URL there.
- if ((*iter)->extension_app() == destination_extension) {
- (*iter)->OpenURL(url, referrer, NEW_FOREGROUND_TAB, transition);
- (*iter)->window()->Show();
- return true;
- }
- }
-
- // If the extension wants to be opened in a window, but there is no
- // existing window, create one, then open the URL there.
- if (destination_extension->launch_container() ==
- Extension::LAUNCH_WINDOW) {
- Browser::OpenApplicationWindow(profile_, destination_extension,
- Extension::LAUNCH_WINDOW, url);
- return true;
- }
- }
-
- // Otherwise, we are opening a normal web page.
- //
- // If our source tab is in an app window, we don't want to open the tab
- // there. Find a normal browser to open it in.
- if (extension_app_) {
- Browser* browser = GetOrCreateTabbedBrowser(profile_);
- browser->OpenURL(url, referrer, NEW_FOREGROUND_TAB, transition);
- browser->window()->Show();
- return true;
- }
-
- // If our source tab is an app tab, don't allow normal web content to
- // overwrite it.
- if (source->extension_app() && *disposition == CURRENT_TAB)
- *disposition = NEW_FOREGROUND_TAB;
-
- return false;
-}
-
-// static
-WindowOpenDisposition Browser::AdjustWindowOpenDispositionForTab(
- bool is_pinned,
- const GURL& url,
- const GURL& referrer,
- PageTransition::Type transition,
- WindowOpenDisposition original_disposition) {
- if (!is_pinned ||
- original_disposition != CURRENT_TAB ||
- (transition != PageTransition::AUTO_BOOKMARK &&
- transition != PageTransition::LINK &&
- transition != PageTransition::TYPED)) {
- return original_disposition;
- }
-
- bool url_is_http_or_https =
- url.SchemeIs(chrome::kHttpScheme) ||
- url.SchemeIs(chrome::kHttpsScheme);
- bool referrer_is_http_or_https =
- referrer.SchemeIs(chrome::kHttpScheme) ||
- referrer.SchemeIs(chrome::kHttpsScheme);
- bool scheme_matches =
- (url.scheme() == referrer.scheme()) ||
- (url_is_http_or_https && referrer_is_http_or_https);
-
- // If the host and scheme are the same, then we allow the link to open in
- // the current tab, to make the page feel more web-appy.
- if (url.host() == referrer.host() && scheme_matches)
- return original_disposition;
-
- return NEW_FOREGROUND_TAB;
-}
-
void Browser::OpenURLAtIndex(TabContents* source,
const GURL& url,
const GURL& referrer,
@@ -3771,24 +3896,6 @@ void Browser::OpenURLAtIndex(TabContents* source,
delegate->OnUserGesture();
}
- disposition = AdjustWindowOpenDispositionForTab(
- current_tab && IsPinned(current_tab),
- url,
- referrer,
- transition,
- disposition);
-
- if (HandleCrossAppNavigation(current_tab, url, referrer, &disposition,
- transition)) {
- // If the source tab was brand new, we can be left with an empty tab which
- // looks ugly. Close it. It is still kinda ugly to have a tab flash visible
- // for a second, then disappear. But I think it is better than having a
- // dead tab just hang around.
- if (source->controller().entry_count() == 0)
- CloseTabContents(source);
- return;
- }
-
// If the URL is part of the same web site, then load it in the same
// SiteInstance (and thus the same process). This is an optimization to
// reduce process overhead; it is not necessary for compatibility. (That is,
@@ -3841,10 +3948,11 @@ void Browser::OpenURLAtIndex(TabContents* source,
Browser* browser = Browser::Create(profile_);
new_contents = browser->AddTabWithURL(
url, referrer, transition, index,
- TabStripModel::ADD_SELECTED | add_types, instance, std::string());
+ TabStripModel::ADD_SELECTED | add_types, instance, std::string(),
+ &browser);
browser->window()->Show();
} else if ((disposition == CURRENT_TAB) && current_tab) {
- tabstrip_model_.TabNavigating(current_tab, transition);
+ tab_handler_->GetTabStripModel()->TabNavigating(current_tab, transition);
bool user_initiated = (PageTransition::StripQualifier(transition) ==
PageTransition::AUTO_BOOKMARK);
@@ -3876,7 +3984,7 @@ void Browser::OpenURLAtIndex(TabContents* source,
if (disposition != NEW_BACKGROUND_TAB)
add_types |= TabStripModel::ADD_SELECTED;
new_contents = AddTabWithURL(url, referrer, transition, index, add_types,
- instance, std::string());
+ instance, std::string(), NULL);
}
if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost &&
@@ -3890,8 +3998,14 @@ void Browser::OpenURLAtIndex(TabContents* source,
void Browser::BuildPopupWindow(TabContents* source,
TabContents* new_contents,
const gfx::Rect& initial_pos) {
+ Browser::Type browser_type;
+ if ((type_ & TYPE_APP) || // New app popup
+ (source && source->is_app())) // App is creating a popup
+ browser_type = TYPE_APP_POPUP;
+ else
+ browser_type = TYPE_POPUP;
BuildPopupWindowHelper(source, new_contents, initial_pos,
- (type_ & TYPE_APP) ? TYPE_APP_POPUP : TYPE_POPUP,
+ browser_type,
profile_, false);
}
@@ -3958,27 +4072,29 @@ void Browser::TabDetachedAtImpl(TabContents* contents, int index,
// Save what the user's currently typed.
window_->GetLocationBar()->SaveStateToContents(contents);
- if (!tabstrip_model_.closing_all())
+ if (!tab_handler_->GetTabStripModel()->closing_all())
SyncHistoryWithTabs(0);
}
contents->set_delegate(NULL);
RemoveScheduledUpdatesFor(contents);
- if (find_bar_controller_.get() && index == tabstrip_model_.selected_index())
+ if (find_bar_controller_.get() &&
+ index == tab_handler_->GetTabStripModel()->selected_index()) {
find_bar_controller_->ChangeTabContents(NULL);
+ }
registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
Source<TabContents>(contents));
}
// static
-void Browser::RegisterAppPrefs(const std::wstring& app_name) {
+void Browser::RegisterAppPrefs(const std::string& app_name) {
// A set of apps that we've already started.
- static std::set<std::wstring>* g_app_names = NULL;
+ static std::set<std::string>* g_app_names = NULL;
if (!g_app_names)
- g_app_names = new std::set<std::wstring>;
+ g_app_names = new std::set<std::string>;
// Only register once for each app name.
if (g_app_names->find(app_name) != g_app_names->end())
@@ -3986,8 +4102,8 @@ void Browser::RegisterAppPrefs(const std::wstring& app_name) {
g_app_names->insert(app_name);
// We need to register the window position pref.
- std::wstring window_pref(prefs::kBrowserWindowPlacement);
- window_pref.append(L"_");
+ std::string window_pref(prefs::kBrowserWindowPlacement);
+ window_pref.append("_");
window_pref.append(app_name);
PrefService* prefs = g_browser_process->local_state();
DCHECK(prefs);
@@ -3995,23 +4111,6 @@ void Browser::RegisterAppPrefs(const std::wstring& app_name) {
prefs->RegisterDictionaryPref(window_pref.c_str());
}
-// static
-bool Browser::RunUnloadEventsHelper(TabContents* contents) {
- // If the TabContents is not connected yet, then there's no unload
- // handler we can fire even if the TabContents has an unload listener.
- // One case where we hit this is in a tab that has an infinite loop
- // before load.
- if (TabHasUnloadListener(contents)) {
- // If the page has unload listeners, then we tell the renderer to fire
- // them. Once they have fired, we'll get a message back saying whether
- // to proceed closing the page or not, which sends us back to this method
- // with the HasUnloadListener bit cleared.
- contents->render_view_host()->FirePageBeforeUnload(false);
- return true;
- }
- return false;
-}
-
void Browser::TabRestoreServiceChanged(TabRestoreService* service) {
command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
!service->entries().empty());
@@ -4026,11 +4125,30 @@ void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) {
tab_restore_service_ = NULL;
}
-bool Browser::IsPinned(TabContents* source) {
- int index = tabstrip_model_.GetIndexOfTabContents(source);
- if (index == TabStripModel::kNoTab) {
- NOTREACHED() << "IsPinned called for tab not in our strip";
+bool Browser::OpenMatchPreview(WindowOpenDisposition disposition) {
+ if (!match_preview() || !match_preview()->is_active())
return false;
+
+ if (disposition == CURRENT_TAB) {
+ match_preview()->CommitCurrentPreview(MatchPreview::COMMIT_PRESSED_ENTER);
+ return true;
}
- return tabstrip_model_.IsTabPinned(index);
+ if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) {
+ HideMatchPreview();
+ TabContents* preview_contents = match_preview()->ReleasePreviewContents(
+ MatchPreview::COMMIT_PRESSED_ENTER);
+ preview_contents->controller().PruneAllButActive();
+ tab_handler_->GetTabStripModel()->AddTabContents(
+ preview_contents,
+ -1,
+ match_preview()->last_transition_type(),
+ disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED :
+ TabStripModel::ADD_NONE);
+ return true;
+ }
+ // The omnibox currently doesn't use other dispositions, so we don't attempt
+ // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add
+ // support for the new disposition.
+ NOTREACHED();
+ return false;
}
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 6aa3f77..695d353 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -4,56 +4,62 @@
#ifndef CHROME_BROWSER_BROWSER_H_
#define CHROME_BROWSER_BROWSER_H_
+#pragma once
#include <map>
#include <set>
+#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/task.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.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/browser/shell_dialogs.h"
#include "chrome/browser/sync/profile_sync_service_observer.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/tabs/tab_handler.h"
+#include "chrome/browser/tabs/tab_strip_model_delegate.h" // TODO(beng): remove
+#include "chrome/browser/tabs/tab_strip_model_observer.h" // TODO(beng): remove
+#include "chrome/browser/tab_contents/match_preview_delegate.h"
#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/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/page_zoom.h"
#include "gfx/rect.h"
class BrowserWindow;
-class DebuggerWindow;
class Extension;
-class ExtensionShelfModel;
class FindBarController;
-class GoButton;
-class LocationBar;
+class MatchPreview;
class PrefService;
class Profile;
+class SessionStorageNamespace;
class SkBitmap;
class StatusBubble;
class TabNavigation;
+class TabStripModel;
namespace gfx {
class Point;
}
-class Browser : public TabStripModelDelegate,
- public TabStripModelObserver,
+class Browser : public TabHandlerDelegate,
public TabContentsDelegate,
public PageNavigator,
public CommandUpdater::CommandUpdaterDelegate,
public NotificationObserver,
public SelectFileDialog::Listener,
- public TabRestoreService::Observer,
- public ProfileSyncServiceObserver {
+ public TabRestoreServiceObserver,
+ public ProfileSyncServiceObserver,
+ public MatchPreviewDelegate {
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
@@ -65,12 +71,16 @@ class Browser : public TabStripModelDelegate,
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.
+ // 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,
+
+ // TODO(skerner): crbug/56776: Until the panel UI is complete on all
+ // platforms, apps that set app.launch.container = "panel" have type
+ // APP_POPUP.
TYPE_APP_PANEL = TYPE_APP | 32,
TYPE_ANY = TYPE_NORMAL |
TYPE_POPUP |
@@ -89,8 +99,8 @@ class Browser : public TabStripModelDelegate,
FEATURE_LOCATIONBAR = 8,
FEATURE_BOOKMARKBAR = 16,
FEATURE_INFOBAR = 32,
- FEATURE_DOWNLOADSHELF = 64,
- FEATURE_EXTENSIONSHELF = 128
+ FEATURE_SIDEBAR = 64,
+ FEATURE_DOWNLOADSHELF = 128
};
// Maximized state on creation.
@@ -121,11 +131,14 @@ class Browser : public TabStripModelDelegate,
// Like Create, but creates a tabstrip-less popup window.
static Browser* CreateForPopup(Profile* profile);
+ // Like Create, but creates a browser of the specified type.
+ static Browser* CreateForType(Type type, Profile* profile);
+
// 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.
- static Browser* CreateForApp(const std::wstring& app_name,
+ static Browser* CreateForApp(const std::string& app_name,
Extension* extension,
Profile* profile,
bool is_panel);
@@ -160,6 +173,10 @@ class Browser : public TabStripModelDelegate,
Profile* profile() const { return profile_; }
const std::vector<std::wstring>& user_data_dir_profiles() const;
+ // Returns the MatchPreview or NULL if there is no MatchPreview for this
+ // Browser.
+ MatchPreview* match_preview() const { return match_preview_.get(); }
+
#if defined(UNIT_TEST)
// Sets the BrowserWindow. This is intended for testing and generally not
// useful outside of testing. Use CreateBrowserWindow outside of testing, or
@@ -174,9 +191,6 @@ class Browser : public TabStripModelDelegate,
ToolbarModel* toolbar_model() { return &toolbar_model_; }
const SessionID& session_id() const { return session_id_; }
CommandUpdater* command_updater() { return &command_updater_; }
- ExtensionShelfModel* extension_shelf_model() {
- return extension_shelf_model_.get();
- }
// Get the FindBarController for this browser, creating it if it does not
// yet exist.
@@ -202,13 +216,6 @@ class Browser : public TabStripModelDelegate,
// |profile|, that session is re-used.
static void OpenURLOffTheRecord(Profile* profile, const GURL& url);
- // Finds an app tab running a given app in a browser.
- static TabContents* FindAppTab(Browser* browser, Extension* extension_app);
-
- // Finds a browser running an app as an app window or panel.
- static Browser* FindAppWindowOrPanel(Profile* profile,
- Extension* extension_app);
-
// Open an application specified by |app_id| in the appropriate launch
// container. Returns NULL if the app_id is invalid or if ExtensionsService
// isn't ready/available.
@@ -217,29 +224,39 @@ class Browser : public TabStripModelDelegate,
// Open |extension| in |container|. Returns the TabContents* that was created
// or NULL.
- static TabContents* OpenApplication(Profile* profile,
- Extension* extension,
- Extension::LaunchContainer container);
+ static TabContents* OpenApplication(
+ Profile* profile,
+ Extension* extension,
+ extension_misc::LaunchContainer container);
// Opens a new application window for the specified url. If |as_panel|
// is true, the application will be opened as a Browser::Type::APP_PANEL in
// app panel window, otherwise it will be opened as as either
// Browser::Type::APP a.k.a. "thin frame" (if |extension| is NULL) or
// Browser::Type::EXTENSION_APP (if |extension| is non-NULL).
+ // Returns the browser hosting for the TabContents via optional parameter,
+ // |browser|.
static TabContents* OpenApplicationWindow(
Profile* profile,
Extension* extension,
- Extension::LaunchContainer container,
- const GURL& url);
+ extension_misc::LaunchContainer container,
+ const GURL& url,
+ Browser** browser);
// Open an application for |extension| in a new application window or panel.
+ // Returns the browser hosting the TabContents via optional parameter,
+ // |browser|.
static TabContents* OpenApplicationWindow(Profile* profile,
- GURL& url);
+ GURL& url,
+ Browser** browser);
// Open an application for |extension| in a new application tab. Returns
// NULL if there are no appropriate existing browser windows for |profile|.
+ // Returns the browser hosting the TabContents via optional parameter,
+ // |browser|.
static TabContents* OpenApplicationTab(Profile* profile,
- Extension* extension);
+ Extension* extension,
+ Browser** browser);
// Opens a new window and opens the bookmark manager.
static void OpenBookmarkManagerWindow(Profile* profile);
@@ -260,7 +277,7 @@ class Browser : public TabStripModelDelegate,
// State Storage and Retrieval for UI ///////////////////////////////////////
// Save and restore the window position.
- std::wstring GetWindowPlacementKey() const;
+ std::string GetWindowPlacementKey() const;
bool ShouldSaveWindowPlacement() const;
void SaveWindowPlacement(const gfx::Rect& bounds, bool maximized);
gfx::Rect GetSavedWindowBounds() const;
@@ -280,6 +297,10 @@ class Browser : public TabStripModelDelegate,
// Gives beforeunload handlers the chance to cancel the close.
bool ShouldCloseWindow();
+ bool IsAttemptingToCloseBrowser() const {
+ return is_attempting_to_close_browser_;
+ }
+
// Invoked when the window containing us is closing. Performs the necessary
// cleanup.
void OnWindowClosing();
@@ -295,26 +316,17 @@ class Browser : public TabStripModelDelegate,
// TabStripModel pass-thrus /////////////////////////////////////////////////
TabStripModel* tabstrip_model() const {
- return const_cast<TabStripModel*>(&tabstrip_model_);
+ // TODO(beng): remove this accessor. It violates google style.
+ return tab_handler_->GetTabStripModel();
}
- int tab_count() const { return tabstrip_model_.count(); }
- int selected_index() const { return tabstrip_model_.selected_index(); }
- int GetIndexOfController(const NavigationController* controller) const {
- return tabstrip_model_.GetIndexOfController(controller);
- }
- TabContents* GetTabContentsAt(int index) const {
- return tabstrip_model_.GetTabContentsAt(index);
- }
- TabContents* GetSelectedTabContents() const {
- return tabstrip_model_.GetSelectedTabContents();
- }
- void SelectTabContentsAt(int index, bool user_gesture) {
- tabstrip_model_.SelectTabContentsAt(index, user_gesture);
- }
- void CloseAllTabs() {
- tabstrip_model_.CloseAllTabs();
- }
+ int tab_count() const;
+ int selected_index() const;
+ int GetIndexOfController(const NavigationController* controller) const;
+ TabContents* GetTabContentsAt(int index) const;
+ TabContents* GetSelectedTabContents() const;
+ void SelectTabContentsAt(int index, bool user_gesture);
+ void CloseAllTabs();
// Tab adding/showing functions /////////////////////////////////////////////
@@ -328,13 +340,17 @@ class Browser : public TabStripModelDelegate,
// values defined by TabStripModel::AddTabTypes; see it for details. If
// |instance| is not null, its process will be used to render the tab. If
// |extension_app_id| is non-empty the new tab is an app tab.
+ // The returned tab may be hosted in a different browser. |browser_used|
+ // will be assigned the browser that satisfied the add tab request.
+ // |browser_used| may be passed
TabContents* AddTabWithURL(const GURL& url,
const GURL& referrer,
PageTransition::Type transition,
int index,
int add_types,
SiteInstance* instance,
- const std::string& extension_app_id);
+ const std::string& extension_app_id,
+ Browser** browser_used);
// Add a new tab, given a TabContents. A TabContents appropriate to
// display the last committed entry is created and returned.
@@ -354,7 +370,8 @@ class Browser : public TabStripModelDelegate,
const std::string& extension_app_id,
bool select,
bool pin,
- bool from_last_session);
+ bool from_last_session,
+ SessionStorageNamespace* storage_namespace);
// Creates a new tab with the already-created TabContents 'new_contents'.
// The window for the added contents will be reparented correctly when this
// method returns. If |disposition| is NEW_POPUP, |pos| should hold the
@@ -379,17 +396,14 @@ class Browser : public TabStripModelDelegate,
// part of an animation.
void ToolbarSizeChanged(bool is_animating);
- // Notification that the extension shelf has changed size (as a result of
- // becoming detached or attached).
- void ExtensionShelfSizeChanged();
-
// Replaces the state of the currently selected tab with the session
// history restored from the SessionRestore system.
void ReplaceRestoredTab(
const std::vector<TabNavigation>& navigations,
int selected_navigation,
bool from_last_session,
- const std::string& extension_app_id);
+ const std::string& extension_app_id,
+ SessionStorageNamespace* session_storage_namespace);
// Navigate to an index in the tab history, opening a new tab depending on the
// disposition.
@@ -432,6 +446,7 @@ class Browser : public TabStripModelDelegate,
void CloseTab();
void SelectNextTab();
void SelectPreviousTab();
+ void OpenTabpose();
void MoveTabNext();
void MoveTabPrevious();
void SelectNumberedTab(int index);
@@ -502,7 +517,6 @@ class Browser : public TabStripModelDelegate,
void OpenBugReportDialog();
void ToggleBookmarkBar();
- void ToggleExtensionShelf();
void OpenBookmarkManager();
void ShowAppMenu();
@@ -511,12 +525,15 @@ class Browser : public TabStripModelDelegate,
void ShowDownloadsTab();
void ShowExtensionsTab();
void ShowBrokenPageTab(TabContents* contents);
- void ShowOptionsTab();
+ void ShowOptionsTab(const std::string& sub_page);
void OpenClearBrowsingDataDialog();
void OpenOptionsDialog();
void OpenKeywordEditor();
void OpenPasswordManager();
void OpenSyncMyBookmarksDialog();
+#if defined(ENABLE_REMOTING)
+ void OpenRemotingSetupDialog();
+#endif
void OpenImportSettingsDialog();
void OpenAboutChromeDialog();
void OpenUpdateChromeDialog();
@@ -525,9 +542,11 @@ class Browser : public TabStripModelDelegate,
void OpenThemeGalleryTabAndActivate();
void OpenAutoFillHelpTabAndActivate();
void OpenPrivacyDashboardTabAndActivate();
+ void OpenSearchEngineOptionsDialog();
#if defined(OS_CHROMEOS)
- void OpenSystemOptionsDialog();
void OpenInternetOptionsDialog();
+ void OpenLanguageOptionsDialog();
+ void OpenSystemOptionsDialog();
#endif
virtual void UpdateDownloadShelfVisibility(bool visible);
@@ -548,6 +567,9 @@ class Browser : public TabStripModelDelegate,
static void RegisterPrefs(PrefService* prefs);
static void RegisterUserPrefs(PrefService* prefs);
+ // Helper function to run unload listeners on a TabContents.
+ static bool RunUnloadEventsHelper(TabContents* contents);
+
// Returns the Browser which contains the tab with the given
// NavigationController, also filling in |index| (if valid) with the tab's
// index in the tab strip.
@@ -557,6 +579,9 @@ class Browser : public TabStripModelDelegate,
const NavigationController* controller, int* index);
// Retrieve the last active tabbed browser with a profile matching |profile|.
+ static Browser* GetTabbedBrowser(Profile* profile, bool match_incognito);
+
+ // Retrieve the last active tabbed browser with a profile matching |profile|.
// Creates a new Browser if none are available.
static Browser* GetOrCreateTabbedBrowser(Profile* profile);
@@ -589,7 +614,7 @@ class Browser : public TabStripModelDelegate,
// Interface implementations ////////////////////////////////////////////////
- // Overridden from PageNavigator
+ // Overridden from PageNavigator:
virtual void OpenURL(const GURL& url, const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition);
@@ -597,38 +622,21 @@ class Browser : public TabStripModelDelegate,
// Overridden from CommandUpdater::CommandUpdaterDelegate:
virtual void ExecuteCommand(int id);
- // Helper function to run unload listeners on a TabContents.
- static bool RunUnloadEventsHelper(TabContents* contents);
-
- // TabRestoreService::Observer ///////////////////////////////////////////////
+ // Overridden from TabRestoreServiceObserver:
virtual void TabRestoreServiceChanged(TabRestoreService* service);
virtual void TabRestoreServiceDestroyed(TabRestoreService* service);
- private:
- FRIEND_TEST_ALL_PREFIXES(BrowserTest, PinnedTabDisposition);
- FRIEND_TEST_ALL_PREFIXES(BrowserTest, NoTabsInPopups);
-
- // Used to describe why a tab is being detached. This is used by
- // TabDetachedAtImpl.
- enum DetachType {
- // Result of TabDetachedAt.
- DETACH_TYPE_DETACH,
-
- // Result of TabReplacedAt.
- DETACH_TYPE_REPLACE,
-
- // Result of the tab strip not having any significant tabs.
- DETACH_TYPE_EMPTY
- };
-
- bool IsPinned(TabContents* source);
+ // Overridden from TabHandlerDelegate:
+ virtual Profile* GetProfile() const;
+ virtual Browser* AsBrowser();
// Overridden from TabStripModelDelegate:
virtual TabContents* AddBlankTab(bool foreground);
virtual TabContents* AddBlankTabAt(int index, bool foreground);
virtual Browser* CreateNewStripWithContents(TabContents* detached_contents,
const gfx::Rect& window_bounds,
- const DockInfo& dock_info);
+ const DockInfo& dock_info,
+ bool maximize);
virtual void ContinueDraggingDetachedTab(TabContents* contents,
const gfx::Rect& window_bounds,
const gfx::Rect& tab_bounds);
@@ -653,6 +661,7 @@ class Browser : public TabStripModelDelegate,
virtual void ToggleUseVerticalTabs();
virtual bool CanRestoreTab();
virtual void RestoreTab();
+ virtual bool LargeIconsPermitted() const;
// Overridden from TabStripModelObserver:
virtual void TabInsertedAt(TabContents* contents,
@@ -674,6 +683,22 @@ class Browser : public TabStripModelDelegate,
virtual void TabPinnedStateChanged(TabContents* contents, int index);
virtual void TabStripEmpty();
+ private:
+ FRIEND_TEST_ALL_PREFIXES(BrowserTest, NoTabsInPopups);
+
+ // Used to describe why a tab is being detached. This is used by
+ // TabDetachedAtImpl.
+ enum DetachType {
+ // Result of TabDetachedAt.
+ DETACH_TYPE_DETACH,
+
+ // Result of TabReplacedAt.
+ DETACH_TYPE_REPLACE,
+
+ // Result of the tab strip not having any significant tabs.
+ DETACH_TYPE_EMPTY
+ };
+
// Overridden from TabContentsDelegate:
virtual void OpenURLFromTab(TabContents* source,
const GURL& url,
@@ -688,11 +713,12 @@ class Browser : public TabStripModelDelegate,
const gfx::Rect& initial_pos,
bool user_gesture);
virtual void ActivateContents(TabContents* contents);
+ virtual void DeactivateContents(TabContents* contents);
virtual void LoadingStateChanged(TabContents* source);
virtual void CloseContents(TabContents* source);
virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
virtual void DetachContents(TabContents* source);
- virtual bool IsPopup(TabContents* source);
+ virtual bool IsPopup(const TabContents* source) const;
virtual bool CanReloadContents(TabContents* source) const;
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating);
virtual void URLStarredChanged(TabContents* source, bool starred);
@@ -716,7 +742,7 @@ class Browser : public TabStripModelDelegate,
virtual void SetFocusToLocationBar(bool select_all);
virtual void RenderWidgetShowing();
virtual int GetExtraRenderViewHeight() const;
- virtual void OnStartDownload(DownloadItem* download);
+ virtual void OnStartDownload(DownloadItem* download, TabContents* tab);
virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
Profile* profile);
virtual void ShowPageInfo(Profile* profile,
@@ -729,10 +755,12 @@ class Browser : public TabStripModelDelegate,
virtual void ShowRepostFormWarningDialog(TabContents* tab_contents);
virtual void ShowContentSettingsWindow(ContentSettingsType content_type);
virtual void ShowCollectedCookiesDialog(TabContents* tab_contents);
- virtual bool ShouldAddNavigationsToHistory() const;
+ virtual bool ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type);
virtual void OnDidGetApplicationInfo(TabContents* tab_contents,
int32 page_id);
- virtual Browser* GetBrowser();
+ virtual void ContentTypeChanged(TabContents* source);
// Overridden from SelectFileDialog::Listener:
virtual void FileSelected(const FilePath& path, int index, void* params);
@@ -745,6 +773,13 @@ class Browser : public TabStripModelDelegate,
// Overridden from ProfileSyncServiceObserver:
virtual void OnStateChanged();
+ // Overriden from MatchPreviewDelegate:
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
+ virtual void CommitMatchPreview(TabContents* preview_contents);
+ virtual void SetSuggestedText(const string16& text);
+ virtual gfx::Rect GetMatchPreviewBounds();
+
// Command and state updating ///////////////////////////////////////////////
// Initialize state for all browser commands.
@@ -753,6 +788,9 @@ class Browser : public TabStripModelDelegate,
// Update commands whose state depends on the tab's state.
void UpdateCommandsForTabState();
+ // Update zoom commands based on the tab's state
+ void UpdateZoomCommandsForTabState();
+
// Ask the Reload/Stop button to change its icon, and update the Stop command
// state. |is_loading| is true if the current TabContents is loading.
// |force| is true if the button should change its icon immediately.
@@ -787,6 +825,7 @@ class Browser : public TabStripModelDelegate,
// TODO(beng): remove, and provide AutomationProvider a better way to access
// the LocationBarView's edit.
friend class AutomationProvider;
+ friend class TestingAutomationProvider;
// Returns the StatusBubble from the current toolbar. It is possible for
// this to return NULL if called before the toolbar has initialized.
@@ -890,9 +929,9 @@ class Browser : public TabStripModelDelegate,
// Create a preference dictionary for the provided application name. This is
// done only once per application name / per session.
- static void RegisterAppPrefs(const std::wstring& app_name);
+ static void RegisterAppPrefs(const std::string& app_name);
- // Shared code between Reload() and ReloadAll().
+ // Shared code between Reload() and ReloadIgnoringCache().
void ReloadInternal(WindowOpenDisposition disposition, bool ignore_cache);
// Return true if the window dispositions means opening a new tab.
@@ -926,16 +965,9 @@ class Browser : public TabStripModelDelegate,
// cancel closing of window.
bool IsClosingPermitted();
- // Calculate a new window open disposition for a navigation. The return
- // value will usually be |original_disposition|, but for some pinned tab cases
- // we change it to NEW_FOREGROUND_TAB so that the pinned tab feels more
- // permanent.
- static WindowOpenDisposition AdjustWindowOpenDispositionForTab(
- bool is_pinned,
- const GURL& url,
- const GURL& referrer,
- PageTransition::Type transition,
- WindowOpenDisposition original_disposition);
+ // Commits the current match preview, returning true on success. This is
+ // intended for use from OpenCurrentURL.
+ bool OpenMatchPreview(WindowOpenDisposition disposition);
// Data members /////////////////////////////////////////////////////////////
@@ -950,15 +982,15 @@ class Browser : public TabStripModelDelegate,
// This Browser's window.
BrowserWindow* window_;
- // This Browser's TabStripModel.
- TabStripModel tabstrip_model_;
+ // This Browser's current TabHandler.
+ scoped_ptr<TabHandler> tab_handler_;
// The CommandUpdater that manages the browser window commands.
CommandUpdater command_updater_;
// An optional application name which is used to retrieve and save window
// positions.
- std::wstring app_name_;
+ std::string app_name_;
// Unique identifier of this browser for session restore. This id is only
// unique within the current session, and is not guaranteed to be unique
@@ -968,9 +1000,6 @@ class Browser : public TabStripModelDelegate,
// The model for the toolbar view.
ToolbarModel toolbar_model_;
- // The model for the extension shelf.
- scoped_ptr<ExtensionShelfModel> extension_shelf_model_;
-
// UI update coalescing and handling ////////////////////////////////////////
typedef std::map<const TabContents*, int> UpdateMap;
@@ -1065,6 +1094,8 @@ class Browser : public TabStripModelDelegate,
// and we install ourselves as an observer.
TabRestoreService* tab_restore_service_;
+ scoped_ptr<MatchPreview> match_preview_;
+
DISALLOW_COPY_AND_ASSIGN(Browser);
};
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 14e748f..69ad244 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -11,27 +11,31 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "base/file_version_info.h"
+#include "base/command_line.h"
#include "base/histogram.h"
#include "base/i18n/number_formatting.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/stats_table.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/tracked_objects.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
-#include "chrome/browser/google_service_auth_error.h"
+#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/gpu_process_host_ui_shim.h"
+#include "chrome/browser/labs.h"
#include "chrome/browser/memory_details.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
@@ -40,7 +44,9 @@
#include "chrome/common/about_handler.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/gpu_info.h"
#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
@@ -92,7 +98,9 @@ const char kAppCacheInternalsPath[] = "appcache-internals";
const char kCreditsPath[] = "credits";
const char kCachePath[] = "view-http-cache";
const char kDnsPath[] = "dns";
+const char kGpuPath[] = "gpu";
const char kHistogramsPath[] = "histograms";
+const char kLabsPath[] = "labs";
const char kMemoryRedirectPath[] = "memory-redirect";
const char kMemoryPath[] = "memory";
const char kStatsPath[] = "stats";
@@ -114,7 +122,6 @@ const char kSandboxPath[] = "sandbox";
#if defined(OS_CHROMEOS)
const char kNetworkPath[] = "network";
const char kOSCreditsPath[] = "os-credits";
-const char kSysPath[] = "system";
#endif
// Add path here to be included in about:about
@@ -123,7 +130,9 @@ const char *kAllAboutPaths[] = {
kCachePath,
kCreditsPath,
kDnsPath,
+ kGpuPath,
kHistogramsPath,
+ kLabsPath,
kMemoryPath,
kNetInternalsPath,
kPluginsPath,
@@ -140,7 +149,6 @@ const char *kAllAboutPaths[] = {
#if defined(OS_CHROMEOS)
kNetworkPath,
kOSCreditsPath,
- kSysPath,
#endif
};
@@ -247,19 +255,23 @@ std::string AboutAbout() {
html.append("<html><head><title>About Pages</title></head><body>\n");
html.append("<h2>List of About pages</h2><ul>\n");
for (size_t i = 0; i < arraysize(kAllAboutPaths); i++) {
- if (kAllAboutPaths[i] == kNetInternalsPath ||
- kAllAboutPaths[i] == kPluginsPath ||
+ if (kAllAboutPaths[i] == kLabsPath && !about_labs::IsEnabled())
+ continue;
+ if (kAllAboutPaths[i] == kAppCacheInternalsPath ||
kAllAboutPaths[i] == kCachePath ||
- kAllAboutPaths[i] == kAppCacheInternalsPath)
+ kAllAboutPaths[i] == kLabsPath ||
+ kAllAboutPaths[i] == kNetInternalsPath ||
+ kAllAboutPaths[i] == kPluginsPath) {
html.append("<li><a href='chrome://");
- else
+ } else {
html.append("<li><a href='chrome://about/");
+ }
html.append(kAllAboutPaths[i]);
html.append("/'>about:");
html.append(kAllAboutPaths[i]);
html.append("</a>\n");
}
- const char *debug[] = { "crash", "hang", "shorthang" };
+ const char *debug[] = { "crash", "hang", "shorthang", "gpucrash", "gpuhang" };
html.append("</ul><h2>For Debug</h2>");
html.append("</ul><p>The following pages are for debugging purposes only. "
"Because they crash or hang the renderer, they're not linked "
@@ -278,7 +290,7 @@ std::string AboutAbout() {
#if defined(OS_CHROMEOS)
std::string AboutNetwork(const std::string& query) {
int refresh;
- StringToInt(query, &refresh);
+ base::StringToInt(query, &refresh);
return chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
GetHtmlInfo(refresh);
}
@@ -418,15 +430,15 @@ std::string AboutStats() {
// We maintain two lists - one for counters and one for timers.
// Timers actually get stored on both lists.
ListValue* counters;
- if (!root.GetList(L"counters", &counters)) {
+ if (!root.GetList("counters", &counters)) {
counters = new ListValue();
- root.Set(L"counters", counters);
+ root.Set("counters", counters);
}
ListValue* timers;
- if (!root.GetList(L"timers", &timers)) {
+ if (!root.GetList("timers", &timers)) {
timers = new ListValue();
- root.Set(L"timers", timers);
+ root.Set("timers", timers);
}
// NOTE: Counters start at index 1.
@@ -450,9 +462,8 @@ std::string AboutStats() {
scan_index < counters->GetSize(); scan_index++) {
DictionaryValue* dictionary;
if (counters->GetDictionary(scan_index, &dictionary)) {
- std::wstring scan_name;
- if (dictionary->GetString(L"name", &scan_name) &&
- WideToASCII(scan_name) == name) {
+ std::string scan_name;
+ if (dictionary->GetString("name", &scan_name) && scan_name == name) {
counter = dictionary;
}
} else {
@@ -462,7 +473,7 @@ std::string AboutStats() {
if (counter == NULL) {
counter = new DictionaryValue();
- counter->SetString(L"name", ASCIIToWide(name));
+ counter->SetString("name", name);
counters->Append(counter);
}
@@ -472,11 +483,11 @@ std::string AboutStats() {
int new_value = table->GetRowValue(index);
int prior_value = 0;
int delta = 0;
- if (counter->GetInteger(L"value", &prior_value)) {
+ if (counter->GetInteger("value", &prior_value)) {
delta = new_value - prior_value;
}
- counter->SetInteger(L"value", new_value);
- counter->SetInteger(L"delta", delta);
+ counter->SetInteger("value", new_value);
+ counter->SetInteger("delta", delta);
}
break;
case 'm':
@@ -487,7 +498,7 @@ std::string AboutStats() {
case 't':
{
int time = table->GetRowValue(index);
- counter->SetInteger(L"time", time);
+ counter->SetInteger("time", time);
// Store this on the timers list as well.
timers->Append(counter);
@@ -600,13 +611,9 @@ std::string AboutSandbox() {
#endif
std::string AboutVersion(DictionaryValue* localized_strings) {
- localized_strings->SetString(L"title",
- l10n_util::GetString(IDS_ABOUT_VERSION_TITLE));
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- if (version_info == NULL) {
- DLOG(ERROR) << "Unable to create FileVersionInfo object";
- return std::string();
- }
+ localized_strings->SetString("title",
+ l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_TITLE));
+ chrome::VersionInfo version_info;
std::string webkit_version = webkit_glue::GetWebKitVersion();
#ifdef CHROME_V8
@@ -617,42 +624,42 @@ std::string AboutVersion(DictionaryValue* localized_strings) {
std::string js_engine = "JavaScriptCore";
#endif
- localized_strings->SetString(L"name",
- l10n_util::GetString(IDS_PRODUCT_NAME));
- localized_strings->SetString(L"version", version_info->file_version());
- std::wstring mod = UTF16ToWide(platform_util::GetVersionStringModifier());
- localized_strings->SetString(L"version_modifier", mod);
- localized_strings->SetString(L"js_engine", js_engine);
- localized_strings->SetString(L"js_version", js_version);
- localized_strings->SetString(L"webkit_version", webkit_version);
- localized_strings->SetString(L"company",
- l10n_util::GetString(IDS_ABOUT_VERSION_COMPANY_NAME));
- localized_strings->SetString(L"copyright",
- l10n_util::GetString(IDS_ABOUT_VERSION_COPYRIGHT));
- localized_strings->SetString(L"cl", version_info->last_change());
- if (version_info->is_official_build()) {
- localized_strings->SetString(L"official",
- l10n_util::GetString(IDS_ABOUT_VERSION_OFFICIAL));
- } else {
- localized_strings->SetString(L"official",
- l10n_util::GetString(IDS_ABOUT_VERSION_UNOFFICIAL));
- }
- localized_strings->SetString(L"user_agent_name",
- l10n_util::GetString(IDS_ABOUT_VERSION_USER_AGENT));
- localized_strings->SetString(L"useragent", webkit_glue::GetUserAgent(GURL()));
- localized_strings->SetString(L"command_line_name",
- l10n_util::GetString(IDS_ABOUT_VERSION_COMMAND_LINE));
+ localized_strings->SetString("name",
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ localized_strings->SetString("version", version_info.Version());
+ localized_strings->SetString("version_modifier",
+ platform_util::GetVersionStringModifier());
+ localized_strings->SetString("js_engine", js_engine);
+ localized_strings->SetString("js_version", js_version);
+ localized_strings->SetString("webkit_version", webkit_version);
+ localized_strings->SetString("company",
+ l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMPANY_NAME));
+ localized_strings->SetString("copyright",
+ l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COPYRIGHT));
+ localized_strings->SetString("cl", version_info.LastChange());
+ localized_strings->SetString("official",
+ l10n_util::GetStringUTF16(
+ version_info.IsOfficialBuild() ?
+ IDS_ABOUT_VERSION_OFFICIAL
+ : IDS_ABOUT_VERSION_UNOFFICIAL));
+ localized_strings->SetString("user_agent_name",
+ l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_USER_AGENT));
+ localized_strings->SetString("useragent", webkit_glue::GetUserAgent(GURL()));
+ localized_strings->SetString("command_line_name",
+ l10n_util::GetStringUTF16(IDS_ABOUT_VERSION_COMMAND_LINE));
#if defined(OS_WIN)
- localized_strings->SetString(L"command_line",
- CommandLine::ForCurrentProcess()->command_line_string());
+ localized_strings->SetString("command_line",
+ WideToUTF16(CommandLine::ForCurrentProcess()->command_line_string()));
#elif defined(OS_POSIX)
std::string command_line = "";
typedef std::vector<std::string> ArgvList;
const ArgvList& argv = CommandLine::ForCurrentProcess()->argv();
for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++)
command_line += " " + *iter;
- localized_strings->SetString(L"command_line", command_line);
+ // TODO(viettrungluu): |command_line| could really have any encoding, whereas
+ // below we assumes it's UTF-8.
+ localized_strings->SetString("command_line", command_line);
#endif
base::StringPiece version_html(
@@ -663,33 +670,36 @@ std::string AboutVersion(DictionaryValue* localized_strings) {
version_html, localized_strings, "t" /* template root node id */);
}
-static void AddBoolSyncDetail(ListValue* details, const std::wstring& stat_name,
+static void AddBoolSyncDetail(ListValue* details, const std::string& stat_name,
bool stat_value) {
DictionaryValue* val = new DictionaryValue;
- val->SetString(L"stat_name", stat_name);
- val->SetBoolean(L"stat_value", stat_value);
+ val->SetString("stat_name", stat_name);
+ val->SetBoolean("stat_value", stat_value);
details->Append(val);
}
-static void AddIntSyncDetail(ListValue* details, const std::wstring& stat_name,
+static void AddIntSyncDetail(ListValue* details, const std::string& stat_name,
int64 stat_value) {
DictionaryValue* val = new DictionaryValue;
- val->SetString(L"stat_name", stat_name);
- val->SetString(L"stat_value", UTF16ToWide(base::FormatNumber(stat_value)));
+ val->SetString("stat_name", stat_name);
+ val->SetString("stat_value", base::FormatNumber(stat_value));
details->Append(val);
}
-static std::wstring MakeSyncAuthErrorText(
+static std::string MakeSyncAuthErrorText(
const GoogleServiceAuthError::State& state) {
switch (state) {
case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
- return L"INVALID_GAIA_CREDENTIALS";
+ case GoogleServiceAuthError::ACCOUNT_DELETED:
+ case GoogleServiceAuthError::ACCOUNT_DISABLED:
+ case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
+ return "INVALID_GAIA_CREDENTIALS";
case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
- return L"USER_NOT_SIGNED_UP";
+ return "USER_NOT_SIGNED_UP";
case GoogleServiceAuthError::CONNECTION_FAILED:
- return L"CONNECTION_FAILED";
+ return "CONNECTION_FAILED";
default:
- return std::wstring();
+ return std::string();
}
}
@@ -703,68 +713,68 @@ std::string AboutSync() {
DictionaryValue strings;
if (!service || !service->HasSyncSetupCompleted()) {
- strings.SetString(L"summary", L"SYNC DISABLED");
+ strings.SetString("summary", "SYNC DISABLED");
} else {
SyncManager::Status full_status(service->QueryDetailedSyncStatus());
- strings.SetString(L"summary",
+ strings.SetString("service_url", service->sync_service_url().spec());
+ strings.SetString("summary",
ProfileSyncService::BuildSyncStatusSummaryText(
full_status.summary));
- strings.Set(L"authenticated",
+ strings.Set("authenticated",
new FundamentalValue(full_status.authenticated));
- strings.SetString(L"auth_problem",
+ strings.SetString("auth_problem",
MakeSyncAuthErrorText(service->GetAuthError().state()));
- strings.SetString(L"time_since_sync", service->GetLastSyncedTimeString());
+ strings.SetString("time_since_sync", service->GetLastSyncedTimeString());
ListValue* details = new ListValue();
- strings.Set(L"details", details);
- AddBoolSyncDetail(details, L"Server Up", full_status.server_up);
- AddBoolSyncDetail(details, L"Server Reachable",
+ strings.Set("details", details);
+ AddBoolSyncDetail(details, "Server Up", full_status.server_up);
+ AddBoolSyncDetail(details, "Server Reachable",
full_status.server_reachable);
- AddBoolSyncDetail(details, L"Server Broken", full_status.server_broken);
- AddBoolSyncDetail(details, L"Notifications Enabled",
+ AddBoolSyncDetail(details, "Server Broken", full_status.server_broken);
+ AddBoolSyncDetail(details, "Notifications Enabled",
full_status.notifications_enabled);
- AddIntSyncDetail(details, L"Notifications Received",
+ AddIntSyncDetail(details, "Notifications Received",
full_status.notifications_received);
- AddIntSyncDetail(details, L"Notifications Sent",
+ AddIntSyncDetail(details, "Notifications Sent",
full_status.notifications_sent);
- AddIntSyncDetail(details, L"Unsynced Count", full_status.unsynced_count);
- AddIntSyncDetail(details, L"Conflicting Count",
+ AddIntSyncDetail(details, "Unsynced Count", full_status.unsynced_count);
+ AddIntSyncDetail(details, "Conflicting Count",
full_status.conflicting_count);
- AddBoolSyncDetail(details, L"Syncing", full_status.syncing);
- AddBoolSyncDetail(details, L"Initial Sync Ended",
+ AddBoolSyncDetail(details, "Syncing", full_status.syncing);
+ AddBoolSyncDetail(details, "Initial Sync Ended",
full_status.initial_sync_ended);
- AddBoolSyncDetail(details, L"Syncer Stuck", full_status.syncer_stuck);
- AddIntSyncDetail(details, L"Updates Available",
+ AddBoolSyncDetail(details, "Syncer Stuck", full_status.syncer_stuck);
+ AddIntSyncDetail(details, "Updates Available",
full_status.updates_available);
- AddIntSyncDetail(details, L"Updates Received",
- full_status.updates_received);
- AddBoolSyncDetail(details, L"Disk Full", full_status.disk_full);
- AddBoolSyncDetail(details, L"Invalid Store", full_status.invalid_store);
- AddIntSyncDetail(details, L"Max Consecutive Errors",
+ AddIntSyncDetail(details, "Updates Received", full_status.updates_received);
+ AddBoolSyncDetail(details, "Disk Full", full_status.disk_full);
+ AddBoolSyncDetail(details, "Invalid Store", full_status.invalid_store);
+ AddIntSyncDetail(details, "Max Consecutive Errors",
full_status.max_consecutive_errors);
if (service->unrecoverable_error_detected()) {
- strings.Set(L"unrecoverable_error_detected", new FundamentalValue(true));
- strings.SetString(L"unrecoverable_error_message",
+ strings.Set("unrecoverable_error_detected", new FundamentalValue(true));
+ strings.SetString("unrecoverable_error_message",
service->unrecoverable_error_message());
tracked_objects::Location loc(service->unrecoverable_error_location());
std::string location_str;
loc.Write(true, true, &location_str);
- strings.SetString(L"unrecoverable_error_location", location_str);
+ strings.SetString("unrecoverable_error_location", location_str);
}
browser_sync::ModelSafeRoutingInfo routes;
service->backend()->GetModelSafeRoutingInfo(&routes);
ListValue* routing_info = new ListValue();
- strings.Set(L"routing_info", routing_info);
+ strings.Set("routing_info", routing_info);
browser_sync::ModelSafeRoutingInfo::const_iterator it = routes.begin();
for (; it != routes.end(); ++it) {
DictionaryValue* val = new DictionaryValue;
- val->SetString(L"model_type", ModelTypeToString(it->first));
- val->SetString(L"group", ModelSafeGroupToString(it->second));
+ val->SetString("model_type", ModelTypeToString(it->first));
+ val->SetString("group", ModelSafeGroupToString(it->second));
routing_info->Append(val);
}
}
@@ -773,38 +783,50 @@ std::string AboutSync() {
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_ABOUT_SYNC_HTML));
- return jstemplate_builder::GetTemplateHtml(
+ return jstemplate_builder::GetTemplatesHtml(
sync_html, &strings , "t" /* template root node id */);
}
-#if defined(OS_CHROMEOS)
-std::string AboutSys() {
- DictionaryValue strings;
- chromeos::SyslogsLibrary* syslogs_lib =
- chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
- scoped_ptr<chromeos::LogDictionaryType> sys_info_;
- if (syslogs_lib)
- sys_info_.reset(syslogs_lib->GetSyslogs(new FilePath()));
- if (sys_info_.get()) {
- ListValue* details = new ListValue();
- strings.Set(L"details", details);
- chromeos::LogDictionaryType::iterator it;
-
- for (it = sys_info_.get()->begin(); it != sys_info_.get()->end(); ++it) {
- DictionaryValue* val = new DictionaryValue;
- val->SetString(L"stat_name", (*it).first);
- val->SetString(L"stat_value", (*it).second);
- details->Append(val);
- }
- }
- static const base::StringPiece sys_html(
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_ABOUT_SYS_HTML));
+std::string VersionNumberToString(uint32 value) {
+ int hi = (value >> 8) & 0xff;
+ int low = value & 0xff;
+ return base::IntToString(hi) + "." + base::IntToString(low);
+}
+
+std::string AboutGpu() {
+ GPUInfo gpu_info = GpuProcessHost::Get()->gpu_info();
- return jstemplate_builder::GetTemplateHtml(
- sys_html, &strings , "t" /* template root node id */);
+ std::string html;
+ if (!gpu_info.initialized()) {
+ GpuProcessHostUIShim::Get()->CollectGraphicsInfoAsynchronously();
+ // If it's not initialized yet, let the user know and reload the page
+ html.append("<html><head><title>About GPU</title></head>\n");
+ html.append("<body onload=\"setTimeout('window.location.reload(true)',");
+ html.append("2000)\">\n");
+ html.append("<h2>GPU Information</h2>\n");
+ html.append("<p>Retrieving GPU information . . .</p>\n");
+ html.append("</body></html> ");
+ } else {
+ html.append("<html><head><title>About GPU</title></head><body>\n");
+ html.append("<h2>GPU Information</h2><ul>\n");
+ html.append("<li><strong>Vendor ID:</strong> ");
+ html.append(base::IntToString(gpu_info.vendor_id()));
+ html.append("<li><strong>Device ID:</strong> ");
+ html.append(base::IntToString(gpu_info.device_id()));
+ html.append("<li><strong>Driver Version:</strong> ");
+ html.append(WideToASCII(gpu_info.driver_version()).c_str());
+ html.append("<li><strong>Pixel Shader Version:</strong> ");
+ html.append(VersionNumberToString(
+ gpu_info.pixel_shader_version()).c_str());
+ html.append("<li><strong>Vertex Shader Version:</strong> ");
+ html.append(VersionNumberToString(
+ gpu_info.vertex_shader_version()).c_str());
+ html.append("<li><strong>GL Version:</strong> ");
+ html.append(VersionNumberToString(gpu_info.gl_version()).c_str());
+ html.append("</ul></body></html> ");
+ }
+ return html;
}
-#endif
// AboutSource -----------------------------------------------------------------
@@ -890,10 +912,8 @@ void AboutSource::StartDataRequest(const std::string& path_raw,
#endif
} else if (path == kSyncPath) {
response = AboutSync();
-#if defined(OS_CHROMEOS)
- } else if (path == kSysPath) {
- response = AboutSys();
-#endif
+ } else if (path == kGpuPath) {
+ response = AboutGpu();
}
FinishDataRequest(response, request_id);
@@ -917,16 +937,16 @@ void AboutMemoryHandler::BindProcessMetrics(DictionaryValue* data,
DCHECK(data && info);
// Bind metrics to dictionary.
- data->SetInteger(L"ws_priv", static_cast<int>(info->working_set.priv));
- data->SetInteger(L"ws_shareable",
+ data->SetInteger("ws_priv", static_cast<int>(info->working_set.priv));
+ data->SetInteger("ws_shareable",
static_cast<int>(info->working_set.shareable));
- data->SetInteger(L"ws_shared", static_cast<int>(info->working_set.shared));
- data->SetInteger(L"comm_priv", static_cast<int>(info->committed.priv));
- data->SetInteger(L"comm_map", static_cast<int>(info->committed.mapped));
- data->SetInteger(L"comm_image", static_cast<int>(info->committed.image));
- data->SetInteger(L"pid", info->pid);
- data->SetString(L"version", info->version);
- data->SetInteger(L"processes", info->num_processes);
+ data->SetInteger("ws_shared", static_cast<int>(info->working_set.shared));
+ data->SetInteger("comm_priv", static_cast<int>(info->committed.priv));
+ 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->SetInteger("processes", info->num_processes);
}
// Helper for AboutMemory to append memory usage information for all
@@ -940,14 +960,14 @@ void AboutMemoryHandler::AppendProcess(ListValue* child_data,
child_data->Append(child);
BindProcessMetrics(child, info);
- std::wstring child_label(ChildProcessInfo::GetTypeNameInEnglish(info->type));
+ std::string child_label(ChildProcessInfo::GetTypeNameInEnglish(info->type));
if (info->is_diagnostics)
- child_label.append(L" (diagnostics)");
- child->SetString(L"child_name", child_label);
+ child_label.append(" (diagnostics)");
+ child->SetString("child_name", child_label);
ListValue* titles = new ListValue();
- child->Set(L"titles", titles);
+ child->Set("titles", titles);
for (size_t i = 0; i < info->titles.size(); ++i)
- titles->Append(new StringValue(info->titles[i]));
+ titles->Append(new StringValue(WideToUTF16Hack(info->titles[i])));
}
@@ -955,7 +975,7 @@ void AboutMemoryHandler::OnDetailsAvailable() {
// the root of the JSON hierarchy for about:memory jstemplate
DictionaryValue root;
ListValue* browsers = new ListValue();
- root.Set(L"browsers", browsers);
+ root.Set("browsers", browsers);
const std::vector<ProcessData>& browser_processes = processes();
@@ -986,7 +1006,8 @@ void AboutMemoryHandler::OnDetailsAvailable() {
}
DictionaryValue* browser_data = new DictionaryValue();
browsers->Append(browser_data);
- browser_data->SetString(L"name", browser_processes[index].name);
+ browser_data->SetString("name",
+ WideToUTF16Hack(browser_processes[index].name));
BindProcessMetrics(browser_data, &aggregate);
@@ -995,23 +1016,26 @@ void AboutMemoryHandler::OnDetailsAvailable() {
log_string.append(L", ");
log_string.append(browser_processes[index].name);
log_string.append(L", ");
- log_string.append(Int64ToWString(aggregate.working_set.priv));
+ log_string.append(UTF8ToWide(
+ base::Int64ToString(aggregate.working_set.priv)));
log_string.append(L", ");
- log_string.append(Int64ToWString(aggregate.working_set.shared));
+ log_string.append(UTF8ToWide(
+ base::Int64ToString(aggregate.working_set.shared)));
log_string.append(L", ");
- log_string.append(Int64ToWString(aggregate.working_set.shareable));
+ log_string.append(UTF8ToWide(
+ base::Int64ToString(aggregate.working_set.shareable)));
}
if (log_string.length() > 0)
LOG(INFO) << "memory: " << log_string;
// Set the browser & renderer detailed process data.
DictionaryValue* browser_data = new DictionaryValue();
- root.Set(L"browzr_data", browser_data);
+ root.Set("browzr_data", browser_data);
ListValue* child_data = new ListValue();
- root.Set(L"child_data", child_data);
+ root.Set("child_data", child_data);
ProcessData process = browser_processes[0]; // Chrome is the first browser.
- root.SetString(L"current_browser_name", process.name);
+ root.SetString("current_browser_name", WideToUTF16Hack(process.name));
for (size_t index = 0; index < process.processes.size(); index++) {
if (process.processes[index].type == ChildProcessInfo::BROWSER_PROCESS)
@@ -1020,7 +1044,7 @@ void AboutMemoryHandler::OnDetailsAvailable() {
AppendProcess(child_data, &process.processes[index]);
}
- root.SetBoolean(L"show_other_browsers",
+ root.SetBoolean("show_other_browsers",
browser_defaults::kShowOtherBrowsersInAboutMemory);
// Get about_memory.html
@@ -1050,10 +1074,10 @@ void ChromeOSAboutVersionHandler::OnVersion(
chromeos::VersionLoader::Handle handle,
std::string version) {
DictionaryValue localized_strings;
- localized_strings.SetString(L"os_name",
- l10n_util::GetString(IDS_PRODUCT_OS_NAME));
- localized_strings.SetString(L"os_version", UTF8ToWide(version));
- localized_strings.SetBoolean(L"is_chrome_os", true);
+ localized_strings.SetString("os_name",
+ l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME));
+ localized_strings.SetString("os_version", version);
+ localized_strings.SetBoolean("is_chrome_os", true);
source_->FinishDataRequest(AboutVersion(&localized_strings), request_id_);
// CancelableRequestProvider isn't happy when it's deleted and servicing a
@@ -1101,6 +1125,15 @@ bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) {
return true;
}
+ if (about_labs::IsEnabled()) {
+ // Rewrite about:labs and about:vaporware to chrome://labs/.
+ if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutLabsURL) ||
+ LowerCaseEqualsASCII(url->spec(), chrome::kAboutVaporwareURL)) {
+ *url = GURL(chrome::kChromeUILabsURL);
+ return true;
+ }
+ }
+
// Rewrite about:net-internals/* URLs to chrome://net-internals/*
if (StartsWithAboutSpecifier(*url, chrome::kAboutNetInternalsURL)) {
*url = RemapAboutURL(chrome::kNetworkViewInternalsURL, *url);
@@ -1127,6 +1160,16 @@ bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) {
return true;
}
+ // Handle URLs to wreck the gpu process.
+ if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuCrashURL)) {
+ GpuProcessHost::SendAboutGpuCrash();
+ return true;
+ }
+ if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuHangURL)) {
+ GpuProcessHost::SendAboutGpuHang();
+ return true;
+ }
+
// There are a few about: URLs that we hand over to the renderer. If the
// renderer wants them, don't do any rewriting.
if (chrome_about_handler::WillHandle(*url))
diff --git a/chrome/browser/browser_about_handler.h b/chrome/browser/browser_about_handler.h
index 56125ca..de8f1bf 100644
--- a/chrome/browser/browser_about_handler.h
+++ b/chrome/browser/browser_about_handler.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_BROWSER_ABOUT_HANDLER_H_
#define CHROME_BROWSER_BROWSER_ABOUT_HANDLER_H_
+#pragma once
#include <map>
#include <string>
diff --git a/chrome/browser/browser_accessibility_manager_win.cc b/chrome/browser/browser_accessibility_manager_win.cc
index eddb1c3..7f8b268 100644
--- a/chrome/browser/browser_accessibility_manager_win.cc
+++ b/chrome/browser/browser_accessibility_manager_win.cc
@@ -4,11 +4,11 @@
#include "chrome/browser/browser_accessibility_manager_win.h"
-#include "base/scoped_comptr_win.h"
#include "chrome/browser/browser_accessibility_win.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
using webkit_glue::WebAccessibility;
@@ -40,7 +40,7 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
parent_hwnd_, OBJID_WINDOW, IID_IAccessible,
reinterpret_cast<void **>(&window_iaccessible_));
DCHECK(SUCCEEDED(hr));
- root_ = CreateAccessibilityTree(NULL, src, 0);
+ root_ = CreateAccessibilityTree(NULL, GetNextChildID(), src, 0);
if (!focus_)
focus_ = root_;
}
@@ -58,6 +58,10 @@ BrowserAccessibility* BrowserAccessibilityManager::GetRoot() {
return root_;
}
+void BrowserAccessibilityManager::Remove(LONG child_id) {
+ child_id_map_.erase(child_id);
+}
+
BrowserAccessibility* BrowserAccessibilityManager::GetFromChildID(
LONG child_id) {
base::hash_map<LONG, BrowserAccessibility*>::iterator iter =
@@ -96,46 +100,168 @@ void BrowserAccessibilityManager::DoDefaultAction(
delegate_->AccessibilityDoDefaultAction(node.renderer_id());
}
-void BrowserAccessibilityManager::OnAccessibilityFocusChange(int renderer_id) {
+void BrowserAccessibilityManager::OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) {
+ for (uint32 index = 0; index < params.size(); index++) {
+ const ViewHostMsg_AccessibilityNotification_Params& param = params[index];
+
+ switch (param.notification_type) {
+ case ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_CHECK_STATE_CHANGED:
+ OnAccessibilityObjectStateChange(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_CHILDREN_CHANGED:
+ OnAccessibilityObjectChildrenChange(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_FOCUS_CHANGED:
+ OnAccessibilityObjectFocusChange(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_LOAD_COMPLETE:
+ OnAccessibilityObjectLoadComplete(param.acc_obj);
+ break;
+ case ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_VALUE_CHANGED:
+ OnAccessibilityObjectValueChange(param.acc_obj);
+ break;
+ default:
+ DCHECK(0);
+ break;
+ }
+ }
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::UpdateTree(
+ const webkit_glue::WebAccessibility& acc_obj) {
base::hash_map<int, LONG>::iterator iter =
- renderer_id_to_child_id_map_.find(renderer_id);
+ renderer_id_to_child_id_map_.find(acc_obj.id);
if (iter == renderer_id_to_child_id_map_.end())
- return;
+ return NULL;
LONG child_id = iter->second;
- base::hash_map<LONG, BrowserAccessibility*>::iterator uniq_iter =
- child_id_map_.find(child_id);
- if (uniq_iter != child_id_map_.end())
- focus_ = uniq_iter->second;
- ::NotifyWinEvent(EVENT_OBJECT_FOCUS, parent_hwnd_, OBJID_CLIENT, child_id);
+ BrowserAccessibility* old_browser_acc = GetFromChildID(child_id);
+ if (!old_browser_acc)
+ return NULL;
+
+ if (old_browser_acc->GetChildCount() == 0 && acc_obj.children.size() == 0) {
+ // Reinitialize the BrowserAccessibility if there are no children to update.
+ old_browser_acc->Initialize(
+ this,
+ old_browser_acc->GetParent(),
+ child_id,
+ old_browser_acc->index_in_parent(),
+ acc_obj);
+
+ return old_browser_acc;
+ } else {
+ BrowserAccessibility* new_browser_acc = CreateAccessibilityTree(
+ old_browser_acc->GetParent(),
+ child_id,
+ acc_obj,
+ old_browser_acc->index_in_parent());
+
+ if (old_browser_acc->GetParent()) {
+ old_browser_acc->GetParent()->ReplaceChild(
+ old_browser_acc,
+ new_browser_acc);
+ } else {
+ DCHECK_EQ(old_browser_acc, root_);
+ root_ = new_browser_acc;
+ }
+ old_browser_acc->InactivateTree();
+ old_browser_acc->Release();
+ child_id_map_[child_id] = new_browser_acc;
+
+ return new_browser_acc;
+ }
}
void BrowserAccessibilityManager::OnAccessibilityObjectStateChange(
- int renderer_id) {
- base::hash_map<int, LONG>::iterator iter =
- renderer_id_to_child_id_map_.find(renderer_id);
- if (iter == renderer_id_to_child_id_map_.end())
+ const webkit_glue::WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj);
+ if (!new_browser_acc)
return;
- LONG child_id = iter->second;
- ::NotifyWinEvent(EVENT_OBJECT_FOCUS, parent_hwnd_, OBJID_CLIENT, child_id);
+ LONG child_id = new_browser_acc->child_id();
+ NotifyWinEvent(
+ EVENT_OBJECT_STATECHANGE, parent_hwnd_, OBJID_CLIENT, child_id);
}
-BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree(
- BrowserAccessibility* parent,
- const webkit_glue::WebAccessibility& src,
- int index_in_parent) {
- BrowserAccessibility* instance = factory_->Create();
+void BrowserAccessibilityManager::OnAccessibilityObjectChildrenChange(
+ const webkit_glue::WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj);
+ if (!new_browser_acc)
+ return;
+
+ LONG child_id;
+ if (root_ != new_browser_acc) {
+ child_id = new_browser_acc->GetParent()->child_id();
+ } else {
+ child_id = CHILDID_SELF;
+ }
+ NotifyWinEvent(EVENT_OBJECT_REORDER, parent_hwnd_, OBJID_CLIENT, child_id);
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectFocusChange(
+ const webkit_glue::WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj);
+ if (!new_browser_acc)
+ return;
+
+ focus_ = new_browser_acc;
+ LONG child_id = new_browser_acc->child_id();
+ NotifyWinEvent(EVENT_OBJECT_FOCUS, parent_hwnd_, OBJID_CLIENT, child_id);
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectLoadComplete(
+ const webkit_glue::WebAccessibility& acc_obj) {
+ root_->InactivateTree();
+ root_->Release();
+ focus_ = NULL;
+
+ root_ = CreateAccessibilityTree(NULL, GetNextChildID(), acc_obj, 0);
+ if (!focus_)
+ focus_ = root_;
+
+ LONG root_id = root_->child_id();
+ NotifyWinEvent(EVENT_OBJECT_FOCUS, parent_hwnd_, OBJID_CLIENT, root_id);
+ NotifyWinEvent(
+ IA2_EVENT_DOCUMENT_LOAD_COMPLETE, parent_hwnd_, OBJID_CLIENT, root_id);
+}
+
+void BrowserAccessibilityManager::OnAccessibilityObjectValueChange(
+ const webkit_glue::WebAccessibility& acc_obj) {
+ BrowserAccessibility* new_browser_acc = UpdateTree(acc_obj);
+ if (!new_browser_acc)
+ return;
+
+ LONG child_id = new_browser_acc->child_id();
+ NotifyWinEvent(
+ EVENT_OBJECT_VALUECHANGE, parent_hwnd_, OBJID_CLIENT, child_id);
+}
+
+LONG BrowserAccessibilityManager::GetNextChildID() {
// Get the next child ID, and wrap around when we get near the end
// of a 32-bit integer range. It's okay to wrap around; we just want
// to avoid it as long as possible because clients may cache the ID of
// an object for a while to determine if they've seen it before.
- LONG child_id = next_child_id_;
next_child_id_--;
if (next_child_id_ == -2000000000)
next_child_id_ = -1;
+ return next_child_id_;
+}
+
+BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree(
+ BrowserAccessibility* parent,
+ int child_id,
+ const webkit_glue::WebAccessibility& src,
+ int index_in_parent) {
+ BrowserAccessibility* instance = factory_->Create();
+
instance->Initialize(this, parent, child_id, index_in_parent, src);
child_id_map_[child_id] = instance;
renderer_id_to_child_id_map_[src.id] = child_id;
@@ -143,7 +269,7 @@ BrowserAccessibility* BrowserAccessibilityManager::CreateAccessibilityTree(
focus_ = instance;
for (int i = 0; i < static_cast<int>(src.children.size()); ++i) {
BrowserAccessibility* child = CreateAccessibilityTree(
- instance, src.children[i], i);
+ instance, GetNextChildID(), src.children[i], i);
instance->AddChild(child);
}
diff --git a/chrome/browser/browser_accessibility_manager_win.h b/chrome/browser/browser_accessibility_manager_win.h
index afae99c..429c66f 100644
--- a/chrome/browser/browser_accessibility_manager_win.h
+++ b/chrome/browser/browser_accessibility_manager_win.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
#define CHROME_BROWSER_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
+#pragma once
#include <atlbase.h>
#include <atlcom.h>
#include <oleacc.h>
-#include <map>
+#include <hash_map>
+#include <vector>
#include "base/hash_tables.h"
#include "base/scoped_comptr_win.h"
@@ -17,8 +19,7 @@
#include "webkit/glue/webaccessibility.h"
class BrowserAccessibility;
-class RenderProcessHost;
-class RenderWidgetHost;
+struct ViewHostMsg_AccessibilityNotification_Params;
class BrowserAccessibilityFactory {
public:
@@ -51,6 +52,9 @@ class BrowserAccessibilityManager {
// Return a pointer to the root of the tree, does not make a new reference.
BrowserAccessibility* GetRoot();
+ // Removes the BrowserAccessibility child_id from the manager.
+ void Remove(LONG child_id);
+
// Return a pointer to the object corresponding to the given child_id,
// does not make a new reference.
BrowserAccessibility* GetFromChildID(LONG child_id);
@@ -72,16 +76,37 @@ class BrowserAccessibilityManager {
// Tell the renderer to do the default action for this node.
void DoDefaultAction(const BrowserAccessibility& node);
- // Called when the renderer process has notified us of a focus or state
- // change. Send a notification to MSAA clients of the change.
- void OnAccessibilityFocusChange(int acc_obj_id);
- void OnAccessibilityObjectStateChange(int acc_obj_id);
+ // Called when the renderer process has notified us of about tree changes.
+ // Send a notification to MSAA clients of the change.
+ void OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params);
private:
+ // Update the accessibility tree with an updated WebAccessibility tree or
+ // subtree received from the renderer process. Returns the updated node or
+ // NULL if no node was updated.
+ BrowserAccessibility* UpdateTree(
+ const webkit_glue::WebAccessibility& acc_obj);
+
+ void OnAccessibilityObjectStateChange(
+ const webkit_glue::WebAccessibility& acc_obj);
+ void OnAccessibilityObjectChildrenChange(
+ const webkit_glue::WebAccessibility& acc_obj);
+ void OnAccessibilityObjectFocusChange(
+ const webkit_glue::WebAccessibility& acc_obj);
+ void OnAccessibilityObjectLoadComplete(
+ const webkit_glue::WebAccessibility& acc_obj);
+ void OnAccessibilityObjectValueChange(
+ const webkit_glue::WebAccessibility& acc_obj);
+
+ // Returns the next MSAA child id.
+ static LONG GetNextChildID();
+
// Recursively build a tree of BrowserAccessibility objects from
// the WebAccessibility tree received from the renderer process.
BrowserAccessibility* CreateAccessibilityTree(
BrowserAccessibility* parent,
+ int child_id,
const webkit_glue::WebAccessibility& src,
int index_in_parent);
diff --git a/chrome/browser/browser_accessibility_win.cc b/chrome/browser/browser_accessibility_win.cc
index aed9bbc..61fe5cf 100644
--- a/chrome/browser/browser_accessibility_win.cc
+++ b/chrome/browser/browser_accessibility_win.cc
@@ -5,7 +5,10 @@
#include "chrome/browser/browser_accessibility_win.h"
#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_accessibility_manager_win.h"
+#include "net/base/escape.h"
using webkit_glue::WebAccessibility;
@@ -28,6 +31,8 @@ void BrowserAccessibility::Initialize(
LONG child_id,
LONG index_in_parent,
const webkit_glue::WebAccessibility& src) {
+ DCHECK_EQ(children_.size(), 0U);
+
manager_ = manager;
parent_ = parent;
child_id_ = child_id;
@@ -37,9 +42,16 @@ void BrowserAccessibility::Initialize(
name_ = src.name;
value_ = src.value;
attributes_ = src.attributes;
+ html_attributes_ = src.html_attributes;
location_ = src.location;
InitRoleAndState(src.role, src.state);
+ // Expose headings levels to NVDA with the "level" object attribute.
+ if (src.role == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 &&
+ IsAsciiDigit(role_name_[1])) {
+ html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1)));
+ }
+
// If this object doesn't have a name but it does have a description,
// use the description as its name - because some screen readers only
// announce the name.
@@ -55,6 +67,9 @@ void BrowserAccessibility::AddChild(BrowserAccessibility* child) {
}
void BrowserAccessibility::InactivateTree() {
+ if (!instance_active_)
+ return;
+
// Mark this object as inactive, so calls to all COM methods will return
// failure.
instance_active_ = false;
@@ -70,6 +85,7 @@ void BrowserAccessibility::InactivateTree() {
(*iter)->Release();
}
children_.clear();
+ manager_->Remove(child_id_);
}
bool BrowserAccessibility::IsDescendantOf(BrowserAccessibility* ancestor) {
@@ -82,6 +98,14 @@ bool BrowserAccessibility::IsDescendantOf(BrowserAccessibility* ancestor) {
return false;
}
+BrowserAccessibility* BrowserAccessibility::GetParent() {
+ return parent_;
+}
+
+uint32 BrowserAccessibility::GetChildCount() {
+ return children_.size();
+}
+
BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
if (parent_ && index_in_parent_ > 0)
return parent_->children_[index_in_parent_ - 1];
@@ -91,6 +115,7 @@ BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
if (parent_ &&
+ index_in_parent_ >= 0 &&
index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) {
return parent_->children_[index_in_parent_ + 1];
}
@@ -98,6 +123,14 @@ BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
return NULL;
}
+void BrowserAccessibility::ReplaceChild(
+ const BrowserAccessibility* old_acc, BrowserAccessibility* new_acc) {
+ DCHECK_EQ(children_[old_acc->index_in_parent_], old_acc);
+
+ old_acc = children_[old_acc->index_in_parent_];
+ children_[old_acc->index_in_parent_] = new_acc;
+}
+
BrowserAccessibility* BrowserAccessibility::NewReference() {
AddRef();
return this;
@@ -249,17 +282,8 @@ STDMETHODIMP BrowserAccessibility::get_accDefaultAction(VARIANT var_id,
if (!target)
return E_INVALIDARG;
- string16 action;
- if (!target->GetAttribute(WebAccessibility::ATTR_SHORTCUT, &action))
- return S_FALSE;
-
- if (action.empty())
- return S_FALSE;
-
- *def_action = SysAllocString(action.c_str());
-
- DCHECK(*def_action);
- return S_OK;
+ return target->GetAttributeAsBstr(
+ WebAccessibility::ATTR_SHORTCUT, def_action);
}
STDMETHODIMP BrowserAccessibility::get_accDescription(VARIANT var_id,
@@ -274,17 +298,7 @@ STDMETHODIMP BrowserAccessibility::get_accDescription(VARIANT var_id,
if (!target)
return E_INVALIDARG;
- string16 description;
- if (!target->GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &description))
- return S_FALSE;
-
- if (description.empty())
- return S_FALSE;
-
- *desc = SysAllocString(description.c_str());
-
- DCHECK(*desc);
- return S_OK;
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc);
}
STDMETHODIMP BrowserAccessibility::get_accFocus(VARIANT* focus_child) {
@@ -319,17 +333,7 @@ STDMETHODIMP BrowserAccessibility::get_accHelp(VARIANT var_id, BSTR* help) {
if (!target)
return E_INVALIDARG;
- string16 help_str;
- if (!target->GetAttribute(WebAccessibility::ATTR_HELP, &help_str))
- return S_FALSE;
-
- if (help_str.empty())
- return S_FALSE;
-
- *help = SysAllocString(help_str.c_str());
-
- DCHECK(*help);
- return S_OK;
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_HELP, help);
}
STDMETHODIMP BrowserAccessibility::get_accKeyboardShortcut(VARIANT var_id,
@@ -344,17 +348,7 @@ STDMETHODIMP BrowserAccessibility::get_accKeyboardShortcut(VARIANT var_id,
if (!target)
return E_INVALIDARG;
- string16 shortcut;
- if (!target->GetAttribute(WebAccessibility::ATTR_SHORTCUT, &shortcut))
- return S_FALSE;
-
- if (shortcut.empty())
- return S_FALSE;
-
- *acc_key = SysAllocString(shortcut.c_str());
-
- DCHECK(*acc_key);
- return S_OK;
+ return target->GetAttributeAsBstr(WebAccessibility::ATTR_SHORTCUT, acc_key);
}
STDMETHODIMP BrowserAccessibility::get_accName(VARIANT var_id, BSTR* name) {
@@ -502,7 +496,23 @@ STDMETHODIMP BrowserAccessibility::get_attributes(BSTR* attributes) {
if (!attributes)
return E_INVALIDARG;
- return S_FALSE;
+ // Follow Firefox's convention, which is to return a set of key-value pairs
+ // separated by semicolons, with a colon between the key and the value.
+ string16 str;
+ for (unsigned int i = 0; i < html_attributes_.size(); i++) {
+ if (i != 0)
+ str += L';';
+ str += Escape(html_attributes_[i].first);
+ str += L':';
+ str += Escape(html_attributes_[i].second);
+ }
+
+ if (str.empty())
+ return S_FALSE;
+
+ *attributes = SysAllocString(str.c_str());
+ DCHECK(*attributes);
+ return S_OK;
}
STDMETHODIMP BrowserAccessibility::get_states(AccessibleStates* states) {
@@ -561,17 +571,7 @@ STDMETHODIMP BrowserAccessibility::get_description(BSTR* desc) {
if (!desc)
return E_INVALIDARG;
- string16 description;
- if (!GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &description))
- return S_FALSE;
-
- if (description.empty())
- return S_FALSE;
-
- *desc = SysAllocString(description.c_str());
-
- DCHECK(*desc);
- return S_OK;
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc);
}
STDMETHODIMP BrowserAccessibility::get_imagePosition(
@@ -643,17 +643,342 @@ STDMETHODIMP BrowserAccessibility::get_text(
if (end_offset > len)
end_offset = len;
- *text = SysAllocString(
- name_.substr(start_offset, end_offset - start_offset).c_str());
+ string16 substr = name_.substr(start_offset, end_offset - start_offset);
+ if (substr.empty())
+ return S_FALSE;
+
+ *text = SysAllocString(substr.c_str());
+ DCHECK(*text);
return S_OK;
}
STDMETHODIMP BrowserAccessibility::get_caretOffset(long* offset) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!offset)
+ return E_INVALIDARG;
+
*offset = 0;
return S_OK;
}
//
+// ISimpleDOMDocument methods.
+//
+
+STDMETHODIMP BrowserAccessibility::get_URL(BSTR* url) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!url)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_URL, url);
+}
+
+STDMETHODIMP BrowserAccessibility::get_title(BSTR* title) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!title)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_TITLE, title);
+}
+
+STDMETHODIMP BrowserAccessibility::get_mimeType(BSTR* mime_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!mime_type)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_MIMETYPE, mime_type);
+}
+
+STDMETHODIMP BrowserAccessibility::get_docType(BSTR* doc_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!doc_type)
+ return E_INVALIDARG;
+
+ return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_DOCTYPE, doc_type);
+}
+
+//
+// ISimpleDOMNode methods.
+//
+
+STDMETHODIMP BrowserAccessibility::get_nodeInfo(
+ BSTR* node_name,
+ short* name_space_id,
+ BSTR* node_value,
+ unsigned int* num_children,
+ unsigned int* unique_id,
+ unsigned short* node_type) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node_name || !name_space_id || !node_value || !num_children ||
+ !unique_id || !node_type) {
+ return E_INVALIDARG;
+ }
+
+ string16 tag;
+ if (GetAttribute(WebAccessibility::ATTR_HTML_TAG, &tag))
+ *node_name = SysAllocString(tag.c_str());
+ else
+ *node_name = NULL;
+
+ *name_space_id = 0;
+ *node_value = SysAllocString(value_.c_str());
+ *num_children = children_.size();
+ *unique_id = child_id_;
+
+ if (role_ == ROLE_SYSTEM_DOCUMENT) {
+ *node_type = NODETYPE_DOCUMENT;
+ } else if (role_ == ROLE_SYSTEM_TEXT &&
+ ((ia2_state_ & IA2_STATE_EDITABLE) == 0)) {
+ *node_type = NODETYPE_TEXT;
+ } else {
+ *node_type = NODETYPE_ELEMENT;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibility::get_attributes(
+ unsigned short max_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values,
+ unsigned short* num_attribs) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attrib_names || !name_space_id || !attrib_values || !num_attribs)
+ return E_INVALIDARG;
+
+ *num_attribs = max_attribs;
+ if (*num_attribs > html_attributes_.size())
+ *num_attribs = html_attributes_.size();
+
+ for (unsigned short i = 0; i < *num_attribs; ++i) {
+ attrib_names[i] = SysAllocString(html_attributes_[i].first.c_str());
+ name_space_id[i] = 0;
+ attrib_values[i] = SysAllocString(html_attributes_[i].second.c_str());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibility::get_attributesForNames(
+ unsigned short num_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!attrib_names || !name_space_id || !attrib_values)
+ return E_INVALIDARG;
+
+ for (unsigned short i = 0; i < num_attribs; ++i) {
+ name_space_id[i] = 0;
+ bool found = false;
+ string16 name = (LPCWSTR)attrib_names[i];
+ for (unsigned int j = 0; j < html_attributes_.size(); ++j) {
+ if (html_attributes_[j].first == name) {
+ attrib_values[i] = SysAllocString(html_attributes_[j].second.c_str());
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ attrib_values[i] = NULL;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibility::get_computedStyle(
+ unsigned short max_style_properties,
+ boolean use_alternate_view,
+ BSTR *style_properties,
+ BSTR *style_values,
+ unsigned short *num_style_properties) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!style_properties || !style_values)
+ return E_INVALIDARG;
+
+ // We only cache a single style property for now: DISPLAY
+
+ if (max_style_properties == 0 ||
+ !HasAttribute(WebAccessibility::ATTR_DISPLAY)) {
+ *num_style_properties = 0;
+ return S_OK;
+ }
+
+ string16 display;
+ GetAttribute(WebAccessibility::ATTR_DISPLAY, &display);
+ *num_style_properties = 1;
+ style_properties[0] = SysAllocString(L"display");
+ style_values[0] = SysAllocString(display.c_str());
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibility::get_computedStyleForProperties(
+ unsigned short num_style_properties,
+ boolean use_alternate_view,
+ BSTR* style_properties,
+ BSTR* style_values) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!style_properties || !style_values)
+ return E_INVALIDARG;
+
+ // We only cache a single style property for now: DISPLAY
+
+ for (unsigned short i = 0; i < num_style_properties; i++) {
+ string16 name = (LPCWSTR)style_properties[i];
+ StringToLowerASCII(&name);
+ if (name == L"display") {
+ string16 display;
+ GetAttribute(WebAccessibility::ATTR_DISPLAY, &display);
+ style_values[i] = SysAllocString(display.c_str());
+ } else {
+ style_values[i] = NULL;
+ }
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibility::scrollTo(boolean placeTopLeft) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP BrowserAccessibility::get_parentNode(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ *node = parent_->NewReference();
+ return S_OK;
+}
+
+STDMETHODIMP BrowserAccessibility::get_firstChild(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (children_.size()) {
+ *node = children_[0]->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibility::get_lastChild(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (children_.size()) {
+ *node = children_[children_.size() - 1]->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibility::get_previousSibling(
+ ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (parent_ && index_in_parent_ > 0) {
+ *node = parent_->children_[index_in_parent_ - 1]->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibility::get_nextSibling(ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (parent_ &&
+ index_in_parent_ >= 0 &&
+ index_in_parent_ < static_cast<int>(parent_->children_.size()) - 1) {
+ *node = parent_->children_[index_in_parent_ + 1]->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+STDMETHODIMP BrowserAccessibility::get_childAt(
+ unsigned int child_index,
+ ISimpleDOMNode** node) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!node)
+ return E_INVALIDARG;
+
+ if (child_index < children_.size()) {
+ *node = children_[child_index]->NewReference();
+ return S_OK;
+ } else {
+ *node = NULL;
+ return S_FALSE;
+ }
+}
+
+//
+// ISimpleDOMText methods.
+//
+
+STDMETHODIMP BrowserAccessibility::get_domText(BSTR* dom_text) {
+ if (!instance_active_)
+ return E_FAIL;
+
+ if (!dom_text)
+ return E_INVALIDARG;
+
+ if (name_.empty())
+ return S_FALSE;
+
+ *dom_text = SysAllocString(name_.c_str());
+ DCHECK(*dom_text);
+ return S_OK;
+}
+
+//
// IServiceProvider methods.
//
@@ -662,8 +987,15 @@ STDMETHODIMP BrowserAccessibility::QueryService(
if (!instance_active_)
return E_FAIL;
- if (guidService == IID_IAccessible || guidService == IID_IAccessible2)
+ if (guidService == IID_IAccessible ||
+ guidService == IID_IAccessible2 ||
+ guidService == IID_IAccessibleImage ||
+ guidService == IID_IAccessibleText ||
+ guidService == IID_ISimpleDOMDocument ||
+ guidService == IID_ISimpleDOMNode ||
+ guidService == IID_ISimpleDOMText) {
return QueryInterface(riid, object);
+ }
*object = NULL;
return E_FAIL;
@@ -688,6 +1020,11 @@ HRESULT WINAPI BrowserAccessibility::InternalQueryInterface(
*object = NULL;
return E_NOINTERFACE;
}
+ } else if (iid == IID_ISimpleDOMDocument) {
+ if (role_ != ROLE_SYSTEM_DOCUMENT) {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
}
return CComObjectRootBase::InternalQueryInterface(
@@ -728,6 +1065,26 @@ bool BrowserAccessibility::GetAttribute(
return false;
}
+HRESULT BrowserAccessibility::GetAttributeAsBstr(
+ WebAccessibility::Attribute attribute, BSTR* value_bstr) {
+ string16 str;
+
+ if (!GetAttribute(attribute, &str))
+ return S_FALSE;
+
+ if (str.empty())
+ return S_FALSE;
+
+ *value_bstr = SysAllocString(str.c_str());
+ DCHECK(*value_bstr);
+
+ return S_OK;
+}
+
+string16 BrowserAccessibility::Escape(string16 str) {
+ return UTF8ToUTF16(EscapeNonASCII(UTF16ToUTF8(str)));
+}
+
void BrowserAccessibility::InitRoleAndState(LONG web_role,
LONG web_state) {
state_ = 0;
@@ -735,26 +1092,41 @@ void BrowserAccessibility::InitRoleAndState(LONG web_role,
if ((web_state >> WebAccessibility::STATE_CHECKED) & 1)
state_ |= STATE_SYSTEM_CHECKED;
+ if ((web_state >> WebAccessibility::STATE_COLLAPSED) & 1)
+ state_ |= STATE_SYSTEM_COLLAPSED;
+ if ((web_state >> WebAccessibility::STATE_EXPANDED) & 1)
+ state_ |= STATE_SYSTEM_EXPANDED;
if ((web_state >> WebAccessibility::STATE_FOCUSABLE) & 1)
state_ |= STATE_SYSTEM_FOCUSABLE;
+ if ((web_state >> WebAccessibility::STATE_HASPOPUP) & 1)
+ state_ |= STATE_SYSTEM_HASPOPUP;
if ((web_state >> WebAccessibility::STATE_HOTTRACKED) & 1)
state_ |= STATE_SYSTEM_HOTTRACKED;
if ((web_state >> WebAccessibility::STATE_INDETERMINATE) & 1)
state_ |= STATE_SYSTEM_INDETERMINATE;
+ if ((web_state >> WebAccessibility::STATE_INVISIBLE) & 1)
+ state_ |= STATE_SYSTEM_INVISIBLE;
if ((web_state >> WebAccessibility::STATE_LINKED) & 1)
state_ |= STATE_SYSTEM_LINKED;
if ((web_state >> WebAccessibility::STATE_MULTISELECTABLE) & 1)
state_ |= STATE_SYSTEM_MULTISELECTABLE;
+ // TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect.
if ((web_state >> WebAccessibility::STATE_OFFSCREEN) & 1)
state_ |= STATE_SYSTEM_OFFSCREEN;
if ((web_state >> WebAccessibility::STATE_PRESSED) & 1)
state_ |= STATE_SYSTEM_PRESSED;
if ((web_state >> WebAccessibility::STATE_PROTECTED) & 1)
state_ |= STATE_SYSTEM_PROTECTED;
+ if ((web_state >> WebAccessibility::STATE_SELECTABLE) & 1)
+ state_ |= STATE_SYSTEM_SELECTABLE;
+ if ((web_state >> WebAccessibility::STATE_SELECTED) & 1)
+ state_ |= STATE_SYSTEM_SELECTED;
if ((web_state >> WebAccessibility::STATE_READONLY) & 1)
state_ |= STATE_SYSTEM_READONLY;
if ((web_state >> WebAccessibility::STATE_TRAVERSED) & 1)
state_ |= STATE_SYSTEM_TRAVERSED;
+ if ((web_state >> WebAccessibility::STATE_BUSY) & 1)
+ state_ |= STATE_SYSTEM_BUSY;
if ((web_state >> WebAccessibility::STATE_UNAVAILABLE) & 1)
state_ |= STATE_SYSTEM_UNAVAILABLE;
@@ -795,7 +1167,7 @@ void BrowserAccessibility::InitRoleAndState(LONG web_role,
role_ = ROLE_SYSTEM_COMBOBOX;
break;
case WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION:
- role_name_ = L"dd";
+ GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_);
ia2_role_ = IA2_ROLE_PARAGRAPH;
break;
case WebAccessibility::ROLE_DEFINITION_LIST_TERM:
@@ -819,19 +1191,20 @@ void BrowserAccessibility::InitRoleAndState(LONG web_role,
role_ = ROLE_SYSTEM_TABLE;
break;
case WebAccessibility::ROLE_GROUP:
- role_name_ = L"div";
+ GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_);
+ if (role_name_.empty())
+ role_name_ = L"div";
ia2_role_ = IA2_ROLE_SECTION;
break;
case WebAccessibility::ROLE_HEADING:
- // TODO(dmazzoni): support all heading levels
- role_name_ = L"h1";
+ GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_);
ia2_role_ = IA2_ROLE_HEADING;
break;
case WebAccessibility::ROLE_IMAGE:
role_ = ROLE_SYSTEM_GRAPHIC;
break;
case WebAccessibility::ROLE_IMAGE_MAP:
- role_name_ = L"map";
+ GetAttribute(WebAccessibility::ATTR_HTML_TAG, &role_name_);
ia2_role_ = IA2_ROLE_IMAGE_MAP;
break;
case WebAccessibility::ROLE_IMAGE_MAP_LINK:
diff --git a/chrome/browser/browser_accessibility_win.h b/chrome/browser/browser_accessibility_win.h
index 08edb2b..76cb59d 100644
--- a/chrome/browser/browser_accessibility_win.h
+++ b/chrome/browser/browser_accessibility_win.h
@@ -4,16 +4,20 @@
#ifndef CHROME_BROWSER_BROWSER_ACCESSIBILITY_WIN_H_
#define CHROME_BROWSER_BROWSER_ACCESSIBILITY_WIN_H_
+#pragma once
#include <atlbase.h>
#include <atlcom.h>
#include <oleacc.h>
+#include <map>
#include <vector>
-#include "base/scoped_comptr_win.h"
#include "chrome/browser/browser_accessibility_manager_win.h"
#include "ia2_api_all.h" // Generated
+#include "ISimpleDOMDocument.h" // Generated
+#include "ISimpleDOMNode.h" // Generated
+#include "ISimpleDOMText.h" // Generated
#include "webkit/glue/webaccessibility.h"
using webkit_glue::WebAccessibility;
@@ -33,7 +37,10 @@ class ATL_NO_VTABLE BrowserAccessibility
&LIBID_IAccessible2Lib>,
public IAccessibleImage,
public IAccessibleText,
- public IServiceProvider {
+ public IServiceProvider,
+ public ISimpleDOMDocument,
+ public ISimpleDOMNode,
+ public ISimpleDOMText {
public:
BEGIN_COM_MAP(BrowserAccessibility)
COM_INTERFACE_ENTRY2(IDispatch, IAccessible2)
@@ -42,6 +49,9 @@ class ATL_NO_VTABLE BrowserAccessibility
COM_INTERFACE_ENTRY(IAccessibleImage)
COM_INTERFACE_ENTRY(IAccessibleText)
COM_INTERFACE_ENTRY(IServiceProvider)
+ COM_INTERFACE_ENTRY(ISimpleDOMDocument)
+ COM_INTERFACE_ENTRY(ISimpleDOMNode)
+ COM_INTERFACE_ENTRY(ISimpleDOMText)
END_COM_MAP()
BrowserAccessibility();
@@ -66,6 +76,13 @@ class ATL_NO_VTABLE BrowserAccessibility
// Return true if this object is equal to or a descendant of |ancestor|.
bool IsDescendantOf(BrowserAccessibility* ancestor);
+ // Returns the parent of this object, or NULL if it's the BrowserAccessibility
+ // root.
+ BrowserAccessibility* GetParent();
+
+ // Returns the number of children of this BrowserAccessibility object.
+ uint32 GetChildCount();
+
// Return the previous sibling of this object, or NULL if it's the first
// child of its parent.
BrowserAccessibility* GetPreviousSibling();
@@ -74,9 +91,15 @@ class ATL_NO_VTABLE BrowserAccessibility
// of its parent.
BrowserAccessibility* GetNextSibling();
+ // Replace a child BrowserAccessibility object. Used when updating the
+ // accessibility tree.
+ void ReplaceChild(
+ const BrowserAccessibility* old_acc, BrowserAccessibility* new_acc);
+
// Accessors
LONG child_id() const { return child_id_; }
int32 renderer_id() const { return renderer_id_; }
+ LONG index_in_parent() const { return index_in_parent_; }
// Add one to the reference count and return the same object. Always
// use this method when returning a BrowserAccessibility object as
@@ -324,6 +347,129 @@ class ATL_NO_VTABLE BrowserAccessibility
}
//
+ // ISimpleDOMDocument methods.
+ //
+
+ STDMETHODIMP get_URL(BSTR* url);
+
+ STDMETHODIMP get_title(BSTR* title);
+
+ STDMETHODIMP get_mimeType(BSTR* mime_type);
+
+ STDMETHODIMP get_docType(BSTR* doc_type);
+
+ STDMETHODIMP get_nameSpaceURIForID(
+ short name_space_id, BSTR *name_space_uri) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP put_alternateViewMediaTypes(
+ BSTR *comma_separated_media_types) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // ISimpleDOMNode methods.
+ //
+
+ STDMETHODIMP get_nodeInfo(
+ BSTR* node_name,
+ short* name_space_id,
+ BSTR* node_value,
+ unsigned int* num_children,
+ unsigned int* unique_id,
+ unsigned short* node_type);
+
+ STDMETHODIMP get_attributes(
+ unsigned short max_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values,
+ unsigned short* num_attribs);
+
+ STDMETHODIMP get_attributesForNames(
+ unsigned short num_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values);
+
+ STDMETHODIMP get_computedStyle(
+ unsigned short max_style_properties,
+ boolean use_alternate_view,
+ BSTR *style_properties,
+ BSTR *style_values,
+ unsigned short *num_style_properties);
+
+ STDMETHODIMP get_computedStyleForProperties(
+ unsigned short num_style_properties,
+ boolean use_alternate_view,
+ BSTR* style_properties,
+ BSTR* style_values);
+
+ STDMETHODIMP scrollTo(boolean placeTopLeft);
+
+ STDMETHODIMP get_parentNode(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_firstChild(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_lastChild(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_previousSibling(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_nextSibling(ISimpleDOMNode** node);
+
+ STDMETHODIMP get_childAt(
+ unsigned int child_index,
+ ISimpleDOMNode** node);
+
+ STDMETHODIMP get_innerHTML(BSTR* innerHTML) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_localInterface(void** local_interface) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_language(BSTR* language) {
+ return E_NOTIMPL;
+ }
+
+ //
+ // ISimpleDOMText methods.
+ //
+
+ STDMETHODIMP get_domText(BSTR* dom_text);
+
+ STDMETHODIMP get_clippedSubstringBounds(
+ unsigned int start_index,
+ unsigned int end_index,
+ int* x,
+ int* y,
+ int* width,
+ int* height) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_unclippedSubstringBounds(
+ unsigned int start_index,
+ unsigned int end_index,
+ int* x,
+ int* y,
+ int* width,
+ int* height) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP scrollToSubstring(
+ unsigned int start_index,
+ unsigned int end_index) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP get_fontFamily(BSTR *font_family) {
+ return E_NOTIMPL;
+ }
+
+ //
// IServiceProvider methods.
//
@@ -358,6 +504,15 @@ class ATL_NO_VTABLE BrowserAccessibility
// returns true if found.
bool GetAttribute(WebAccessibility::Attribute attribute, string16* value);
+ // Retrieve the string value of an attribute from the attribute map and
+ // if found and nonempty, allocate a new BSTR (with SysAllocString)
+ // and return S_OK. If not found or empty, return S_FALSE.
+ HRESULT GetAttributeAsBstr(
+ WebAccessibility::Attribute attribute, BSTR* value_bstr);
+
+ // Escape a string like it would be escaped for a URL or HTML form.
+ string16 Escape(string16 str);
+
// The manager of this tree of accessibility objects; needed for
// global operations like focus tracking.
BrowserAccessibilityManager* manager_;
@@ -378,6 +533,7 @@ class ATL_NO_VTABLE BrowserAccessibility
string16 name_;
string16 value_;
std::map<int32, string16> attributes_;
+ std::vector<std::pair<string16, string16> > html_attributes_;
LONG role_;
LONG state_;
diff --git a/chrome/browser/browser_accessibility_win_unittest.cc b/chrome/browser/browser_accessibility_win_unittest.cc
index 6d85671..f093153 100644
--- a/chrome/browser/browser_accessibility_win_unittest.cc
+++ b/chrome/browser/browser_accessibility_win_unittest.cc
@@ -3,8 +3,10 @@
// found in the LICENSE file.
#include "base/scoped_ptr.h"
+#include "base/scoped_comptr_win.h"
#include "chrome/browser/browser_accessibility_manager_win.h"
#include "chrome/browser/browser_accessibility_win.h"
+#include "chrome/common/render_messages_params.h"
#include "testing/gtest/include/gtest/gtest.h"
using webkit_glue::WebAccessibility;
@@ -32,15 +34,35 @@ class CountedBrowserAccessibilityFactory : public BrowserAccessibilityFactory {
}
};
+VARIANT CreateI4Variant(LONG value) {
+ VARIANT variant = {0};
+
+ V_VT(&variant) = VT_I4;
+ V_I4(&variant) = value;
+
+ return variant;
+}
+
+class BrowserAccessibilityTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // ATL needs a pointer to a COM module.
+ static CComModule module;
+ _pAtlModule = &module;
+
+ // Make sure COM is initialized for this thread; it's safe to call twice.
+ ::CoInitialize(NULL);
+ }
+
+ virtual void TearDown()
+ {
+ ::CoUninitialize();
+ }
+};
+
// Test that BrowserAccessibilityManager correctly releases the tree of
// BrowserAccessibility instances upon delete.
-TEST(BrowserAccessibilityTest, TestNoLeaks) {
- // ATL needs a pointer to a COM module.
- CComModule module;
- _pAtlModule = &module;
- // Make sure COM is initialized for this thread; it's safe to call twice.
- ::CoInitialize(NULL);
-
+TEST_F(BrowserAccessibilityTest, TestNoLeaks) {
// Create WebAccessibility objects for a simple document tree,
// representing the accessibility information used to initialize
// BrowserAccessibilityManager.
@@ -109,3 +131,135 @@ TEST(BrowserAccessibilityTest, TestNoLeaks) {
child1_iaccessible->Release();
ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
}
+
+TEST_F(BrowserAccessibilityTest, TestChildrenChange) {
+ // Create WebAccessibility objects for a simple document tree,
+ // representing the accessibility information used to initialize
+ // BrowserAccessibilityManager.
+ WebAccessibility text;
+ text.id = 2;
+ text.role = WebAccessibility::ROLE_STATIC_TEXT;
+ text.value = L"old text";
+ text.state = 0;
+
+ WebAccessibility root;
+ root.id = 1;
+ root.name = L"Document";
+ root.role = WebAccessibility::ROLE_DOCUMENT;
+ root.state = 0;
+ root.children.push_back(text);
+
+ // Construct a BrowserAccessibilityManager with this WebAccessibility tree
+ // and a factory for an instance-counting BrowserAccessibility.
+ CountedBrowserAccessibility::global_obj_count_ = 0;
+ BrowserAccessibilityManager* manager =
+ new BrowserAccessibilityManager(
+ GetDesktopWindow(), root, NULL,
+ new CountedBrowserAccessibilityFactory());
+
+ // Query for the text IAccessible and verify that it returns "old text" as its
+ // value.
+ ScopedComPtr<IDispatch> text_dispatch;
+ HRESULT hr = manager->GetRoot()->get_accChild(CreateI4Variant(1),
+ text_dispatch.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ ScopedComPtr<IAccessible> text_accessible;
+ hr = text_dispatch.QueryInterface(text_accessible.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ CComBSTR value;
+ hr = text_accessible->get_accValue(CreateI4Variant(CHILDID_SELF), &value);
+ ASSERT_EQ(S_OK, hr);
+ EXPECT_STREQ(L"old text", value.m_str);
+
+ text_dispatch.Release();
+ text_accessible.Release();
+
+ // Notify the BrowserAccessibilityManager that the text child has changed.
+ text.value = L"new text";
+ ViewHostMsg_AccessibilityNotification_Params param;
+ param.notification_type =
+ ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_CHILDREN_CHANGED;
+ param.acc_obj = text;
+ std::vector<ViewHostMsg_AccessibilityNotification_Params> notifications;
+ notifications.push_back(param);
+ manager->OnAccessibilityNotifications(notifications);
+
+ // Query for the text IAccessible and verify that it now returns "new text"
+ // as its value.
+ hr = manager->GetRoot()->get_accChild(
+ CreateI4Variant(1),
+ text_dispatch.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ hr = text_dispatch.QueryInterface(text_accessible.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ hr = text_accessible->get_accValue(CreateI4Variant(CHILDID_SELF), &value);
+ ASSERT_EQ(S_OK, hr);
+ EXPECT_STREQ(L"new text", value.m_str);
+
+ text_dispatch.Release();
+ text_accessible.Release();
+
+ // Delete the manager and test that all BrowserAccessibility instances are
+ // deleted.
+ delete manager;
+ ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
+}
+
+TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) {
+ // Create WebAccessibility objects for a simple document tree,
+ // representing the accessibility information used to initialize
+ // BrowserAccessibilityManager.
+ WebAccessibility text;
+ text.id = 3;
+ text.role = WebAccessibility::ROLE_STATIC_TEXT;
+ text.state = 0;
+
+ WebAccessibility div;
+ div.id = 2;
+ div.role = WebAccessibility::ROLE_GROUP;
+ div.state = 0;
+
+ div.children.push_back(text);
+ text.id = 4;
+ div.children.push_back(text);
+
+ WebAccessibility root;
+ root.id = 1;
+ root.role = WebAccessibility::ROLE_DOCUMENT;
+ root.state = 0;
+ root.children.push_back(div);
+
+ // Construct a BrowserAccessibilityManager with this WebAccessibility tree
+ // and a factory for an instance-counting BrowserAccessibility and ensure
+ // that exactly 4 instances were created. Note that the manager takes
+ // ownership of the factory.
+ CountedBrowserAccessibility::global_obj_count_ = 0;
+ BrowserAccessibilityManager* manager =
+ new BrowserAccessibilityManager(
+ GetDesktopWindow(), root, NULL,
+ new CountedBrowserAccessibilityFactory());
+ ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
+
+ // Notify the BrowserAccessibilityManager that the div node and its children
+ // were removed and ensure that only one BrowserAccessibility instance exists.
+ root.children.clear();
+ ViewHostMsg_AccessibilityNotification_Params param;
+ param.notification_type =
+ ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_CHILDREN_CHANGED;
+ param.acc_obj = root;
+ std::vector<ViewHostMsg_AccessibilityNotification_Params> notifications;
+ notifications.push_back(param);
+ manager->OnAccessibilityNotifications(notifications);
+ ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_);
+
+ // Delete the manager and test that all BrowserAccessibility instances are
+ // deleted.
+ delete manager;
+ ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
+}
diff --git a/chrome/browser/browser_browsertest.cc b/chrome/browser/browser_browsertest.cc
index 0525058..1bd9a14 100644
--- a/chrome/browser/browser_browsertest.cc
+++ b/chrome/browser/browser_browsertest.cc
@@ -6,9 +6,9 @@
#include "app/l10n_util.h"
#include "base/compiler_specific.h"
-#include "base/i18n/rtl.h"
#include "base/file_path.h"
#include "base/sys_info.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/app_modal_dialog.h"
#include "chrome/browser/browser.h"
@@ -20,11 +20,13 @@
#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/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tabs/pinned_tab_codec.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/pinned_tab_codec.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
@@ -34,6 +36,11 @@
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/mock_host_resolver.h"
+#include "net/test/test_server.h"
+
+#if defined(OS_WIN)
+#include "base/i18n/rtl.h"
+#endif
namespace {
@@ -48,7 +55,7 @@ const std::wstring OPEN_NEW_BEFOREUNLOAD_PAGE =
const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
const FilePath::CharType* kTitle2File = FILE_PATH_LITERAL("title2.html");
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
// Given a page title, returns the expected window caption string.
std::wstring WindowCaptionFromPageTitle(std::wstring page_title) {
@@ -98,10 +105,9 @@ class BrowserTest : public ExtensionBrowserTest {
// Used by phantom tab tests. Creates two tabs, pins the first and makes it
// a phantom tab (by closing it).
void PhantomTabTest() {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
host_resolver()->AddRule("www.example.com", "127.0.0.1");
- GURL url(server->TestServerPage("empty.html"));
+ GURL url(test_server()->GetURL("empty.html"));
TabStripModel* model = browser()->tabstrip_model();
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
@@ -111,7 +117,7 @@ class BrowserTest : public ExtensionBrowserTest {
ui_test_utils::NavigateToURL(browser(), url);
TabContents* app_contents = new TabContents(browser()->profile(), NULL,
- MSG_ROUTING_NONE, NULL);
+ MSG_ROUTING_NONE, NULL, NULL);
app_contents->SetExtensionApp(extension_app);
model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE);
@@ -130,13 +136,6 @@ class BrowserTest : public ExtensionBrowserTest {
}
protected:
- virtual void SetUpCommandLine(CommandLine* command_line) {
- ExtensionBrowserTest::SetUpCommandLine(command_line);
-
- // Needed for phantom tab tests.
- command_line->AppendSwitch(switches::kEnableApps);
- }
-
// In RTL locales wrap the page title with RTL embedding characters so that it
// matches the value returned by GetWindowTitle().
std::wstring LocaleWindowCaptionFromPageTitle(
@@ -207,8 +206,11 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_JavascriptAlertActivatesTab) {
GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
FilePath(kTitle1File)));
ui_test_utils::NavigateToURL(browser(), url);
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, 0,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
EXPECT_EQ(2, browser()->tab_count());
EXPECT_EQ(0, browser()->selected_index());
TabContents* second_tab = browser()->GetTabContentsAt(1);
@@ -233,8 +235,11 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, ThirtyFourTabs) {
// There is one initial tab.
for (int ix = 0; ix != 33; ++ix) {
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, 0,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
}
EXPECT_EQ(34, browser()->tab_count());
@@ -265,7 +270,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, ReloadThenCancelBeforeUnload) {
ExecuteJavascriptInWebFrame(L"", L"onbeforeunload=null;");
}
-// Crashy on mac. http://crbug.com/40150
+// Crashy on mac. http://crbug.com/38522
#if defined(OS_MACOSX)
#define MAYBE_SingleBeforeUnloadAfterWindowClose \
DISABLED_SingleBeforeUnloadAfterWindowClose
@@ -286,12 +291,12 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_SingleBeforeUnloadAfterWindowClose) {
browser()->GetTabContentsAt(0)->render_view_host()->
ExecuteJavascriptInWebFrame(L"", L"w.close(); alert('bar');");
AppModalDialog* alert = ui_test_utils::WaitForAppModalDialog();
- alert->AcceptWindow();
+ alert->native_dialog()->AcceptAppModalDialog();
alert = ui_test_utils::WaitForAppModalDialog();
EXPECT_FALSE(static_cast<JavaScriptAppModalDialog*>(alert)->
is_before_unload_dialog());
- alert->AcceptWindow();
+ alert->native_dialog()->AcceptAppModalDialog();
}
// Test that get_process_idle_time() returns reasonable values when compared
@@ -329,10 +334,8 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFile) {
IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttp) {
CommandUpdater* command_updater = browser()->command_updater();
- scoped_refptr<HTTPTestServer> http_server(
- HTTPTestServer::CreateServer(kDocRoot, NULL));
- ASSERT_TRUE(NULL != http_server.get());
- GURL http_url(http_server->TestServerPage(""));
+ ASSERT_TRUE(test_server()->Start());
+ GURL http_url(test_server()->GetURL(""));
ASSERT_TRUE(http_url.SchemeIs(chrome::kHttpScheme));
ui_test_utils::NavigateToURL(browser(), http_url);
EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
@@ -341,10 +344,9 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttp) {
IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttps) {
CommandUpdater* command_updater = browser()->command_updater();
- scoped_refptr<HTTPSTestServer> https_server(
- HTTPSTestServer::CreateGoodServer(kDocRoot));
- ASSERT_TRUE(NULL != https_server.get());
- GURL https_url(https_server->TestServerPage("/"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+ GURL https_url(test_server.GetURL("/"));
ASSERT_TRUE(https_url.SchemeIs(chrome::kHttpsScheme));
ui_test_utils::NavigateToURL(browser(), https_url);
EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
@@ -353,10 +355,9 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutHttps) {
IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutFtp) {
CommandUpdater* command_updater = browser()->command_updater();
- scoped_refptr<FTPTestServer> ftp_server(
- FTPTestServer::CreateServer(kDocRoot));
- ASSERT_TRUE(NULL != ftp_server.get());
- GURL ftp_url(ftp_server->TestServerPage(""));
+ net::TestServer test_server(net::TestServer::TYPE_FTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+ GURL ftp_url(test_server.GetURL(""));
ASSERT_TRUE(ftp_url.SchemeIs(chrome::kFtpScheme));
ui_test_utils::NavigateToURL(browser(), ftp_url);
EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_CREATE_SHORTCUTS));
@@ -387,12 +388,9 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, CommandCreateAppShortcutInvalid) {
// Test RenderView correctly send back favicon url for web page that redirects
// to an anchor in javascript body.onload handler.
IN_PROC_BROWSER_TEST_F(BrowserTest, FaviconOfOnloadRedirectToAnchorPage) {
- static const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server(
- HTTPTestServer::CreateServer(kDocRoot, NULL));
- ASSERT_TRUE(NULL != server.get());
- GURL url(server->TestServerPage("files/onload_redirect_to_anchor.html"));
- GURL expected_favicon_url(server->TestServerPage("files/test.png"));
+ ASSERT_TRUE(test_server()->Start());
+ GURL url(test_server()->GetURL("files/onload_redirect_to_anchor.html"));
+ GURL expected_favicon_url(test_server()->GetURL("files/test.png"));
ui_test_utils::NavigateToURL(browser(), url);
@@ -452,10 +450,9 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, RevivePhantomTab) {
// Makes sure TabClosing is sent when uninstalling an extension that is an app
// tab.
IN_PROC_BROWSER_TEST_F(BrowserTest, TabClosingWhenRemovingExtension) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
host_resolver()->AddRule("www.example.com", "127.0.0.1");
- GURL url(server->TestServerPage("empty.html"));
+ GURL url(test_server()->GetURL("empty.html"));
TabStripModel* model = browser()->tabstrip_model();
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
@@ -465,7 +462,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, TabClosingWhenRemovingExtension) {
ui_test_utils::NavigateToURL(browser(), url);
TabContents* app_contents = new TabContents(browser()->profile(), NULL,
- MSG_ROUTING_NONE, NULL);
+ MSG_ROUTING_NONE, NULL, NULL);
app_contents->SetExtensionApp(extension_app);
model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE);
@@ -508,10 +505,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, AppTabRemovedWhenExtensionUninstalled) {
#endif
// Tests that the CLD (Compact Language Detection) works properly.
IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) {
- static const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server(
- HTTPTestServer::CreateServer(kDocRoot, NULL));
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server()->Start());
TabContents* current_tab = browser()->GetSelectedTabContents();
@@ -521,7 +515,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) {
en_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED,
current_tab);
ui_test_utils::NavigateToURL(
- browser(), GURL(server->TestServerPage("files/english_page.html")));
+ 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;
@@ -535,7 +529,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) {
fr_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED,
current_tab);
ui_test_utils::NavigateToURL(
- browser(), GURL(server->TestServerPage("files/french_page.html")));
+ 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();
@@ -553,18 +547,17 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) {
#endif
// Makes sure pinned tabs are restored correctly on start.
IN_PROC_BROWSER_TEST_F(BrowserTest, RestorePinnedTabs) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// Add an pinned app tab.
host_resolver()->AddRule("www.example.com", "127.0.0.1");
- GURL url(server->TestServerPage("empty.html"));
+ GURL url(test_server()->GetURL("empty.html"));
TabStripModel* model = browser()->tabstrip_model();
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
Extension* extension_app = GetExtension();
ui_test_utils::NavigateToURL(browser(), url);
TabContents* app_contents = new TabContents(browser()->profile(), NULL,
- MSG_ROUTING_NONE, NULL);
+ MSG_ROUTING_NONE, NULL, NULL);
app_contents->SetExtensionApp(extension_app);
model->AddTabContents(app_contents, 0, 0, TabStripModel::ADD_NONE);
model->SetTabPinned(0, true);
@@ -583,7 +576,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, RestorePinnedTabs) {
// Simulate launching again.
CommandLine dummy(CommandLine::ARGUMENTS_ONLY);
- BrowserInit::LaunchWithProfile launch(std::wstring(), dummy);
+ BrowserInit::LaunchWithProfile launch(FilePath(), dummy);
launch.profile_ = browser()->profile();
launch.ProcessStartupURLs(std::vector<GURL>());
@@ -616,297 +609,6 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, RestorePinnedTabs) {
}
#endif // !defined(OS_CHROMEOS)
-class BrowserAppRefocusTest : public ExtensionBrowserTest {
- public:
- BrowserAppRefocusTest(): server_(NULL),
- extension_app_(NULL),
- profile_(NULL) {}
-
- protected:
- virtual void SetUpCommandLine(CommandLine* command_line) {
- ExtensionBrowserTest::SetUpCommandLine(command_line);
- command_line->AppendSwitch(switches::kEnableApps);
- }
-
- // Common setup for all tests. Can't use SetUpInProcessBrowserTestFixture
- // because starting the http server crashes if called from that function.
- // The IO thread is not set up at that point.
- virtual void SetUpExtensionApp() {
- // The web URL of the example app we load has a host of
- // www.example.com .
- server_ = StartHTTPServer();
- ASSERT_TRUE(server_);
- host_resolver()->AddRule("www.example.com", "127.0.0.1");
-
- profile_ = browser()->profile();
- ASSERT_TRUE(profile_);
-
- ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/")));
-
- // Save a pointer to the loaded extension in |extension_app_|.
- const ExtensionList* extensions =
- profile_->GetExtensionsService()->extensions();
-
- for (size_t i = 0; i < extensions->size(); ++i) {
- if ((*extensions)[i]->name() == "App Test")
- extension_app_ =(*extensions)[i];
- }
- ASSERT_TRUE(extension_app_) << "App Test extension not loaded.";
- }
-
- // Given a tab, wait for navigation in the tab, then test that it is
- // selected. If this function returns false, an error was logged.
- bool WaitForTab(TabContents* tab) WARN_UNUSED_RESULT {
- if (!tab) {
- LOG(ERROR) << "|tab| should not be NULL.";
- return false;
- }
- ui_test_utils::WaitForNavigation(&(tab->controller()));
- if (tab != browser()->GetSelectedTabContents()) {
- LOG(ERROR) << "Tab was not selected.";
- return false;
- }
- return true;
- }
-
- HTTPTestServer* server_;
- Extension* extension_app_;
- Profile* profile_;
-};
-
-#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(TOOLKIT_VIEWS))
-
-#define MAYBE_OpenTab OpenTab
-#define MAYBE_OpenPanel OpenPanel
-#define MAYBE_OpenWindow OpenWindow
-#define MAYBE_WindowBeforeTab WindowBeforeTab
-#define MAYBE_PanelBeforeTab PanelBeforeTab
-#define MAYBE_TabInFocusedWindow TabInFocusedWindow
-
-#else
-
-// Crashes on mac involving app panels: http://crbug.com/42865
-
-// Tests fail on Chrome OS: http://crbug.com/43061
-
-#define MAYBE_OpenTab DISABLED_OpenTab
-#define MAYBE_OpenPanel DISABLED_OpenPanel
-#define MAYBE_OpenWindow DISABLED_OpenWindow
-#define MAYBE_WindowBeforeTab DISABLED_WindowBeforeTab
-#define MAYBE_PanelBeforeTab DISABLED_PanelBeforeTab
-#define MAYBE_TabInFocusedWindow DISABLED_TabInFocusedWindow
-
-#endif
-
-// Test that launching an app refocuses a tab already hosting the app.
-IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_OpenTab) {
- SetUpExtensionApp();
-
- ASSERT_EQ(1, browser()->tab_count());
- ASSERT_EQ(NULL, Browser::FindAppTab(browser(), extension_app_));
-
- // Open a tab with the app.
- TabContents* tab = Browser::OpenApplicationTab(profile_, extension_app_);
- ASSERT_TRUE(WaitForTab(tab));
- ASSERT_EQ(2, browser()->tab_count());
-
- int app_tab_index = browser()->selected_index();
- ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab.";
- ASSERT_EQ(browser()->GetTabContentsAt(0),
- Browser::FindAppTab(browser(), extension_app_));
-
- // Open the same app. The existing tab should stay focused.
- tab = Browser::OpenApplication(profile_, extension_app_->id());
-
- // No need to wait for navigation, because the tab already exists,
- // and no navigation should take place.
- ASSERT_TRUE(tab != NULL);
- ASSERT_EQ(2, browser()->tab_count());
- ASSERT_EQ(app_tab_index, browser()->selected_index());
-
- // Focus the other tab, and reopen the app. The existing tab should
- // be refocused.
- browser()->SelectTabContentsAt(1, false);
- Browser::OpenApplication(profile_, extension_app_->id());
-
- tab = Browser::OpenApplication(profile_, extension_app_->id());
- ASSERT_TRUE(tab != NULL);
-
- ASSERT_EQ(2, browser()->tab_count());
- ASSERT_EQ(app_tab_index, browser()->selected_index());
-
- // Open a second browser window, and open the app in a tab.
- Browser* second_browser = CreateBrowser(profile_);
- second_browser->window()->Show();
-
- ASSERT_EQ(NULL, Browser::FindAppTab(second_browser, extension_app_)) <<
- "Browser::FindAppTab() should not find an app tab in the second " <<
- "window, beacuse it has not been added yet.";
-
- Browser::OpenApplication(profile_, extension_app_, Extension::LAUNCH_TAB);
- ASSERT_EQ(2, second_browser->tab_count()) <<
- "Expect the app to open in a tab under |second_browser|.";
- int second_app_tab_index = second_browser->selected_index();
- ASSERT_EQ(0, second_app_tab_index) <<
- "Second app tab should be the left most tab.";
- ASSERT_EQ(second_browser->GetTabContentsAt(0),
- Browser::FindAppTab(second_browser, extension_app_)) <<
- "Browser::FindAppTab() should look at the focused window.";
-}
-
-// Test that launching an app refocuses a panel running the app.
-IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_OpenPanel) {
- SetUpExtensionApp();
-
- ASSERT_EQ(1, browser()->tab_count());
- ASSERT_EQ(NULL, Browser::FindAppWindowOrPanel(profile_, extension_app_));
-
- // Open the app in a panel.
- Browser::OpenApplicationWindow(profile_, extension_app_,
- Extension::LAUNCH_PANEL, GURL());
- Browser* app_panel = BrowserList::GetLastActive();
- ASSERT_TRUE(app_panel);
- ASSERT_NE(app_panel, browser()) << "New browser should have opened.";
- ASSERT_EQ(app_panel, BrowserList::GetLastActive());
- ASSERT_EQ(app_panel,
- Browser::FindAppWindowOrPanel(profile_, extension_app_));
-
- // Focus the initial browser.
- browser()->window()->Show();
- ASSERT_EQ(browser(), BrowserList::GetLastActive());
-
- // Open the app.
- Browser::OpenApplication(profile_, extension_app_->id());
-
- // Focus should move to the panel.
- ASSERT_EQ(app_panel, BrowserList::GetLastActive());
- ASSERT_EQ(app_panel,
- Browser::FindAppWindowOrPanel(profile_, extension_app_));
-
- // No new tab should have been created in the initial browser.
- ASSERT_EQ(1, browser()->tab_count());
-}
-
-// Test that launching an app refocuses a window running the app.
-IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_OpenWindow) {
- SetUpExtensionApp();
-
- ASSERT_EQ(1, browser()->tab_count());
- ASSERT_EQ(NULL, Browser::FindAppWindowOrPanel(profile_, extension_app_));
-
- // Open a window with the app.
- Browser::OpenApplicationWindow(profile_, extension_app_,
- Extension::LAUNCH_WINDOW, GURL());
- Browser* app_window = BrowserList::GetLastActive();
- ASSERT_TRUE(app_window);
- ASSERT_NE(app_window, browser()) << "New browser should have opened.";
-
- // Focus the initial browser.
- browser()->window()->Show();
- ASSERT_EQ(browser(), BrowserList::GetLastActive());
-
- // Open the app.
- Browser::OpenApplication(profile_, extension_app_->id());
-
- // Focus should move to the window.
- ASSERT_EQ(app_window, BrowserList::GetLastActive());
- ASSERT_EQ(app_window,
- Browser::FindAppWindowOrPanel(profile_, extension_app_));
- // No new tab should have been created in the initial browser.
- ASSERT_EQ(1, browser()->tab_count());
-}
-
-// Test that if an app is opened while running in a window and a tab,
-// the window is focused.
-IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_WindowBeforeTab) {
- SetUpExtensionApp();
-
- ASSERT_EQ(1, browser()->tab_count());
-
- // Open a tab with the app.
- Browser::OpenApplicationTab(profile_, extension_app_);
- ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
- ASSERT_EQ(2, browser()->tab_count());
- int app_tab_index = browser()->selected_index();
- ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab.";
-
- // Open a window with the app.
- Browser::OpenApplicationWindow(profile_, extension_app_,
- Extension::LAUNCH_WINDOW, GURL());
- Browser* app_window = BrowserList::GetLastActive();
- ASSERT_TRUE(app_window);
- ASSERT_NE(app_window, browser()) << "New browser should have opened.";
-
- // Focus the initial browser.
- browser()->window()->Show();
-
- // Open the app. Focus should move to the window.
- Browser::OpenApplication(profile_, extension_app_->id());
- ASSERT_EQ(app_window, BrowserList::GetLastActive());
-}
-
-// Test that if an app is opened while running in a panel and a tab,
-// the panel is focused.
-IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_PanelBeforeTab) {
- SetUpExtensionApp();
-
- ASSERT_EQ(1, browser()->tab_count());
-
- // Open a tab with the app.
- TabContents* tab = Browser::OpenApplicationTab(profile_, extension_app_);
- ASSERT_TRUE(WaitForTab(tab));
- ASSERT_EQ(2, browser()->tab_count());
- int app_tab_index = browser()->selected_index();
- ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab.";
-
- // Open a panel with the app.
- Browser::OpenApplicationWindow(profile_, extension_app_,
- Extension::LAUNCH_PANEL, GURL());
- Browser* app_panel = BrowserList::GetLastActive();
- ASSERT_TRUE(app_panel);
- ASSERT_NE(app_panel, browser()) << "New browser should have opened.";
-
- // Focus the initial browser.
- browser()->window()->Show();
-
- // Open the app. Focus should move to the panel.
- Browser::OpenApplication(profile_, extension_app_->id());
- ASSERT_EQ(app_panel, BrowserList::GetLastActive());
-}
-
-// Test that if multiple tabs host an app, and that app is opened,
-// the tab in the current window gets focus.
-IN_PROC_BROWSER_TEST_F(BrowserAppRefocusTest, MAYBE_TabInFocusedWindow) {
- SetUpExtensionApp();
-
- ASSERT_EQ(1, browser()->tab_count());
-
- Browser::OpenApplicationTab(profile_, extension_app_);
- ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
- ASSERT_EQ(2, browser()->tab_count());
- int app_tab_index = browser()->selected_index();
- ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab.";
-
- // Open a new browser window, add an app tab.
- Browser* extra_browser = CreateBrowser(profile_);
- ASSERT_EQ(extra_browser, BrowserList::GetLastActive());
-
- Browser::OpenApplicationTab(profile_, extension_app_);
- ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(extra_browser));
- ASSERT_EQ(2, extra_browser->tab_count());
- app_tab_index = extra_browser->selected_index();
- ASSERT_EQ(0, app_tab_index) << "App tab should be the left most tab";
-
- // Open the app. Focus should move to the panel.
- Browser::OpenApplication(profile_, extension_app_->id());
- ASSERT_EQ(extra_browser, BrowserList::GetLastActive());
- ASSERT_EQ(2, extra_browser->tab_count());
-
- browser()->window()->Show();
- Browser::OpenApplication(profile_, extension_app_->id());
- ASSERT_EQ(browser(), BrowserList::GetLastActive());
- ASSERT_EQ(2, browser()->tab_count());
-}
// TODO(ben): this test was never enabled. It has bit-rotted since being added.
// It originally lived in browser_unittest.cc, but has been moved here to make
@@ -939,9 +641,11 @@ IN_PROC_BROWSER_TEST_F(BrowserTest2, NoTabsInPopups) {
EXPECT_EQ(1, popup_browser->tab_count());
// Now try opening another tab in the popup browser.
+ Browser* browser_used = NULL;
popup_browser->AddTabWithURL(
GURL(chrome::kAboutBlankURL), GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(), &browser_used);
+ EXPECT_EQ(popup_browser, browser_used);
// The popup should still only have one tab.
EXPECT_EQ(1, popup_browser->tab_count());
@@ -958,7 +662,8 @@ IN_PROC_BROWSER_TEST_F(BrowserTest2, NoTabsInPopups) {
// Now try opening another tab in the app browser.
app_browser->AddTabWithURL(
GURL(chrome::kAboutBlankURL), GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(), &browser_used);
+ EXPECT_EQ(app_browser, browser_used);
// The popup should still only have one tab.
EXPECT_EQ(1, app_browser->tab_count());
@@ -975,7 +680,8 @@ IN_PROC_BROWSER_TEST_F(BrowserTest2, NoTabsInPopups) {
// Now try opening another tab in the app popup browser.
app_popup_browser->AddTabWithURL(
GURL(chrome::kAboutBlankURL), GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(), &browser_used);
+ EXPECT_EQ(app_popup_browser, browser_used);
// The popup should still only have one tab.
EXPECT_EQ(1, app_popup_browser->tab_count());
diff --git a/chrome/browser/browser_child_process_host.cc b/chrome/browser/browser_child_process_host.cc
index d700475..36f8411 100644
--- a/chrome/browser/browser_child_process_host.cc
+++ b/chrome/browser/browser_child_process_host.cc
@@ -13,14 +13,16 @@
#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
-#include "base/waitable_event.h"
+#include "chrome/app/breakpad_mac.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/env_vars.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/plugin_messages.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/google_update_settings.h"
@@ -29,16 +31,6 @@
#include "base/linux_util.h"
#endif // OS_LINUX
-#if defined(OS_POSIX)
-// This is defined in chrome/browser/google_update_settings_posix.cc. It's the
-// static string containing the user's unique GUID. We send this in the crash
-// report.
-namespace google_update {
-extern std::string posix_guid;
-} // namespace google_update
-#endif // OS_POSIX
-
-
namespace {
typedef std::list<BrowserChildProcessHost*> ChildProcessList;
@@ -86,17 +78,15 @@ BrowserChildProcessHost::~BrowserChildProcessHost() {
void BrowserChildProcessHost::SetCrashReporterCommandLine(
CommandLine* command_line) {
#if defined(USE_LINUX_BREAKPAD)
- const bool unattended = (getenv(env_vars::kHeadless) != NULL);
- if (unattended || GoogleUpdateSettings::GetCollectStatsConsent()) {
- command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
- ASCIIToWide(google_update::posix_guid +
- "," +
- base::GetLinuxDistro()));
+ if (IsCrashReporterEnabled()) {
+ command_line->AppendSwitchASCII(switches::kEnableCrashReporter,
+ child_process_logging::GetClientId() + "," + base::GetLinuxDistro());
}
#elif defined(OS_MACOSX)
- if (GoogleUpdateSettings::GetCollectStatsConsent())
- command_line->AppendSwitchWithValue(switches::kEnableCrashReporter,
- ASCIIToWide(google_update::posix_guid));
+ if (IsCrashReporterEnabled()) {
+ command_line->AppendSwitchASCII(switches::kEnableCrashReporter,
+ child_process_logging::GetClientId());
+ }
#endif // OS_MACOSX
}
diff --git a/chrome/browser/browser_child_process_host.h b/chrome/browser/browser_child_process_host.h
index 20a8f6b..cf30973 100644
--- a/chrome/browser/browser_child_process_host.h
+++ b/chrome/browser/browser_child_process_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BROWSER_CHILD_PROCESS_HOST_H_
#define CHROME_BROWSER_BROWSER_CHILD_PROCESS_HOST_H_
+#pragma once
#include <list>
diff --git a/chrome/browser/browser_commands_unittest.cc b/chrome/browser/browser_commands_unittest.cc
index 3ed2adc..81bd0f5 100644
--- a/chrome/browser/browser_commands_unittest.cc
+++ b/chrome/browser/browser_commands_unittest.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/chrome_thread.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/common/url_constants.h"
#include "chrome/test/browser_with_test_window_test.h"
#include "chrome/test/testing_profile.h"
@@ -79,7 +80,6 @@ TEST_F(BrowserCommandsTest, DuplicateTab) {
}
TEST_F(BrowserCommandsTest, BookmarkCurrentPage) {
- ChromeThread ui_loop(ChromeThread::UI, MessageLoop::current());
ChromeThread file_loop(ChromeThread::FILE, MessageLoop::current());
// We use profile() here, since it's a TestingProfile.
profile()->CreateBookmarkModel(true);
diff --git a/chrome/browser/browser_encoding_uitest.cc b/chrome/browser/browser_encoding_uitest.cc
index b6c7496..1b52a3d 100644
--- a/chrome/browser/browser_encoding_uitest.cc
+++ b/chrome/browser/browser_encoding_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.
#include <string>
diff --git a/chrome/browser/browser_focus_uitest.cc b/chrome/browser/browser_focus_uitest.cc
index 1dad0de..90a3b19 100644
--- a/chrome/browser/browser_focus_uitest.cc
+++ b/chrome/browser/browser_focus_uitest.cc
@@ -4,10 +4,12 @@
#include "build/build_config.h"
+#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/message_loop.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/automation/ui_controls.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -15,13 +17,18 @@
#include "chrome/browser/tab_contents/interstitial_page.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/view_ids.h"
#include "chrome/common/chrome_paths.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) || defined(OS_WIN)
#include "views/focus/focus_manager.h"
#include "views/view.h"
#include "views/window/window.h"
+#endif
#if defined(TOOLKIT_VIEWS)
#include "chrome/browser/views/frame/browser_view.h"
@@ -34,12 +41,18 @@
#endif
#if defined(OS_LINUX)
-// For some reason we hit an external DNS lookup in this test in Linux but not
-// on Windows. TODO(estade): investigate.
-#define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial
+#define MAYBE_FocusTraversal FocusTraversal
+#define MAYBE_FocusTraversalOnInterstitial FocusTraversalOnInterstitial
// TODO(jcampan): http://crbug.com/23683
#define MAYBE_TabsRememberFocusFindInPage FAILS_TabsRememberFocusFindInPage
-#else
+#elif defined(OS_MACOSX)
+// TODO(suzhe): http://crbug.com/49738 (following two tests)
+#define MAYBE_FocusTraversal FAILS_FocusTraversal
+#define MAYBE_FocusTraversalOnInterstitial FAILS_FocusTraversalOnInterstitial
+// TODO(suzhe): http://crbug.com/49737
+#define MAYBE_TabsRememberFocusFindInPage FAILS_TabsRememberFocusFindInPage
+#elif defined(OS_WIN)
+#define MAYBE_FocusTraversal FocusTraversal
#define MAYBE_FocusTraversalOnInterstitial FocusTraversalOnInterstitial
#define MAYBE_TabsRememberFocusFindInPage TabsRememberFocusFindInPage
#endif
@@ -69,38 +82,12 @@ class BrowserFocusTest : public InProcessBrowserTest {
void ClickOnView(ViewID vid) {
ui_test_utils::ClickOnView(browser(), vid);
}
-
- static void HideNativeWindow(gfx::NativeWindow window) {
-#if defined(OS_WIN)
- // TODO(jcampan): retrieve the WidgetWin and show/hide on it instead of
- // using Windows API.
- ::ShowWindow(window, SW_HIDE);
-#elif defined(TOOLKIT_USES_GTK)
- gtk_widget_hide(GTK_WIDGET(window));
-#else
- NOTIMPLEMENTED();
-#endif
- }
-
- static void ShowNativeWindow(gfx::NativeWindow window) {
-#if defined(OS_WIN)
- // TODO(jcampan): retrieve the WidgetWin and show/hide on it instead of
- // using Windows API.
- ::ShowWindow(window, SW_SHOW);
-#elif defined(TOOLKIT_USES_GTK)
- gtk_widget_hide(GTK_WIDGET(window));
-#else
- NOTIMPLEMENTED();
-#endif
- }
};
class TestInterstitialPage : public InterstitialPage {
public:
TestInterstitialPage(TabContents* tab, bool new_navigation, const GURL& url)
- : InterstitialPage(tab, new_navigation, url),
- waiting_for_dom_response_(false),
- waiting_for_focus_change_(false) {
+ : InterstitialPage(tab, new_navigation, url) {
FilePath file_path;
bool r = PathService::Get(chrome::DIR_TEST_DATA, &file_path);
EXPECT_TRUE(r);
@@ -114,63 +101,31 @@ class TestInterstitialPage : public InterstitialPage {
return html_contents_;
}
- virtual void DomOperationResponse(const std::string& json_string,
- int automation_id) {
- if (waiting_for_dom_response_) {
- dom_response_ = json_string;
- waiting_for_dom_response_ = false;
- MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- return;
- }
- InterstitialPage::DomOperationResponse(json_string, automation_id);
- }
-
- std::string GetFocusedElement() {
- std::wstring script = L"window.domAutomationController.setAutomationId(0);"
- L"window.domAutomationController.send(getFocusedElement());";
-
- render_view_host()->ExecuteJavascriptInWebFrame(L"", script);
- DCHECK(!waiting_for_dom_response_);
- waiting_for_dom_response_ = true;
- ui_test_utils::RunMessageLoop();
- // Remove the JSON extra quotes.
- if (dom_response_.size() >= 2 && dom_response_[0] == '"' &&
- dom_response_[dom_response_.size() - 1] == '"') {
- dom_response_ = dom_response_.substr(1, dom_response_.size() - 2);
- }
- return dom_response_;
+ // Exposing render_view_host() to be public; it is declared as protected in
+ // the superclass.
+ virtual RenderViewHost* render_view_host() {
+ return InterstitialPage::render_view_host();
}
bool HasFocus() {
return render_view_host()->view()->HasFocus();
}
- void WaitForFocusChange() {
- waiting_for_focus_change_ = true;
- ui_test_utils::RunMessageLoop();
- }
-
protected:
virtual void FocusedNodeChanged() {
- if (!waiting_for_focus_change_)
- return;
-
- waiting_for_focus_change_= false;
- MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ NotificationService::current()->Notify(
+ NotificationType::FOCUS_CHANGED_IN_PAGE,
+ Source<RenderViewHost>(render_view_host()),
+ NotificationService::NoDetails());
}
private:
std::string html_contents_;
-
- bool waiting_for_dom_response_;
- bool waiting_for_focus_change_;
- std::string dom_response_;
};
-} // namespace
-
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, ClickingMovesFocus) {
-#if defined(USE_X11)
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+#if defined(USE_X11) || defined(OS_MACOSX)
// 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,
@@ -189,10 +144,11 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, ClickingMovesFocus) {
}
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
gfx::NativeWindow window = browser()->window()->GetNativeHandle();
@@ -200,15 +156,15 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) {
// The focus should be on the Tab contents.
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
// Now hide the window, show it again, the focus should not have changed.
- HideNativeWindow(window);
- ShowNativeWindow(window);
+ ui_test_utils::HideNativeWindow(window);
+ ui_test_utils::ShowAndFocusNativeWindow(window);
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
browser()->FocusLocationBar();
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// Hide the window, show it again, the focus should not have changed.
- HideNativeWindow(window);
- ShowNativeWindow(window);
+ ui_test_utils::HideNativeWindow(window);
+ ui_test_utils::ShowAndFocusNativeWindow(window);
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// The rest of this test does not make sense on Linux because the behavior
@@ -252,16 +208,20 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) {
// Tabs remember focus.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
// Create several tabs.
for (int i = 0; i < 4; ++i) {
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
}
// Alternate focus for the tab.
@@ -294,7 +254,6 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) {
ASSERT_TRUE(IsViewFocused(vid));
}
- gfx::NativeWindow window = browser()->window()->GetNativeHandle();
browser()->SelectTabContentsAt(0, true);
// Try the above, but with ctrl+tab. Since tab normally changes focus,
// this has regressed in the past. Loop through several times to be sure.
@@ -303,10 +262,8 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) {
VIEW_ID_LOCATION_BAR;
ASSERT_TRUE(IsViewFocused(vid));
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_TAB, true,
- false, false, false,
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_TAB, true, false, false, false));
}
// As above, but with ctrl+shift+tab.
@@ -316,20 +273,19 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) {
VIEW_ID_LOCATION_BAR;
ASSERT_TRUE(IsViewFocused(vid));
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_TAB, true,
- true, false, false,
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_TAB, true, true, false, false));
}
}
}
// Tabs remember focus with find-in-page box.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
browser()->Find();
@@ -341,8 +297,11 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) {
browser()->FocusLocationBar();
// Create a 2nd tab.
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
// Focus should be on the recently opened tab page.
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
@@ -364,10 +323,11 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) {
// Background window does not steal focus.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
// Open a new browser window.
@@ -393,9 +353,13 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) {
#elif defined(OS_WIN)
focused_browser = browser();
unfocused_browser = browser2;
+#elif defined(OS_MACOSX)
+ // On Mac, the newly created window always gets the focus.
+ focused_browser = browser2;
+ unfocused_browser = browser();
#endif
- GURL steal_focus_url = server->TestServerPage(kStealFocusPage);
+ GURL steal_focus_url = test_server()->GetURL(kStealFocusPage);
ui_test_utils::NavigateToURL(unfocused_browser, steal_focus_url);
// Activate the first browser.
@@ -415,10 +379,11 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) {
// Page cannot steal focus when focus is on location bar.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// Open the page that steals focus.
- GURL url = server->TestServerPage(kStealFocusPage);
+ GURL url = test_server()->GetURL(kStealFocusPage);
ui_test_utils::NavigateToURL(browser(), url);
browser()->FocusLocationBar();
@@ -435,11 +400,12 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
// focus has changed in the page. The notification in the renderer may change
// at which point this test would fail (see comment in
// RenderWidget::didFocus()).
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) {
- HTTPTestServer* server = StartHTTPServer();
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page.
- GURL url = server->TestServerPage(kTypicalPage);
+ GURL url = test_server()->GetURL(kTypicalPage);
ui_test_utils::NavigateToURL(browser(), url);
browser()->FocusLocationBar();
@@ -451,8 +417,6 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) {
"gmapLink"
};
- gfx::NativeWindow window = browser()->window()->GetNativeHandle();
-
// Test forward focus traversal.
for (int i = 0; i < 3; ++i) {
SCOPED_TRACE(StringPrintf("outer loop: %d", i));
@@ -471,16 +435,22 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) {
&actual));
ASSERT_STREQ(kExpElementIDs[j], actual.c_str());
- ASSERT_TRUE(ui_controls::SendKeyPress(window, base::VKEY_TAB,
- false, false, false, false));
-
+ NotificationType::Type notification_type;
+ NotificationSource notification_source =
+ NotificationService::AllSources();
if (j < arraysize(kExpElementIDs) - 1) {
- ui_test_utils::WaitForFocusChange(browser()->GetSelectedTabContents()->
- render_view_host());
+ notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE;
+ notification_source = Source<RenderViewHost>(
+ browser()->GetSelectedTabContents()->render_view_host());
} else {
// On the last tab key press, the focus returns to the browser.
- ui_test_utils::WaitForFocusInBrowser(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,
+ notification_type, notification_source));
}
// At this point the renderer has sent us a message asking to advance the
@@ -496,19 +466,26 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) {
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// Now let's press shift-tab to move the focus in reverse.
- for (size_t j = 0; j < 7; ++j) {
+ for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) {
SCOPED_TRACE(StringPrintf("inner loop: %" PRIuS, j));
- ASSERT_TRUE(ui_controls::SendKeyPress(window, base::VKEY_TAB,
- false, true, false, false));
+ NotificationType::Type notification_type;
+ NotificationSource notification_source =
+ NotificationService::AllSources();
if (j < arraysize(kExpElementIDs) - 1) {
- ui_test_utils::WaitForFocusChange(browser()->GetSelectedTabContents()->
- render_view_host());
+ notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE;
+ notification_source = Source<RenderViewHost>(
+ browser()->GetSelectedTabContents()->render_view_host());
} else {
// On the last tab key press, the focus returns to the browser.
- ui_test_utils::WaitForFocusInBrowser(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,
+ 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(
@@ -528,10 +505,11 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) {
// Focus traversal while an interstitial is showing.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
// Focus should be on the page.
@@ -557,8 +535,6 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
"gmapLink"
};
- gfx::NativeWindow window = browser()->window()->GetNativeHandle();
-
// Test forward focus traversal.
for (int i = 0; i < 2; ++i) {
// Location bar should be focused.
@@ -567,18 +543,29 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
// Now let's press tab to move the focus.
for (size_t j = 0; j < 7; ++j) {
// Let's make sure the focus is on the expected element in the page.
- std::string actual = interstitial_page->GetFocusedElement();
+ std::string actual;
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ interstitial_page->render_view_host(), L"",
+ L"window.domAutomationController.send(getFocusedElement());",
+ &actual));
ASSERT_STREQ(kExpElementIDs[j], actual.c_str());
- ASSERT_TRUE(ui_controls::SendKeyPress(window, base::VKEY_TAB,
- false, false, false, false));
-
+ NotificationType::Type notification_type;
+ NotificationSource notification_source =
+ NotificationService::AllSources();
if (j < arraysize(kExpElementIDs) - 1) {
- interstitial_page->WaitForFocusChange();
+ notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE;
+ notification_source = Source<RenderViewHost>(
+ interstitial_page->render_view_host());
} else {
// On the last tab key press, the focus returns to the browser.
- ui_test_utils::WaitForFocusInBrowser(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,
+ notification_type, notification_source));
}
// At this point the renderer has sent us a message asking to advance the
@@ -594,18 +581,29 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
// Now let's press shift-tab to move the focus in reverse.
for (size_t j = 0; j < 7; ++j) {
- ASSERT_TRUE(ui_controls::SendKeyPress(window, base::VKEY_TAB,
- false, true, false, false));
-
+ NotificationType::Type notification_type;
+ NotificationSource notification_source =
+ NotificationService::AllSources();
if (j < arraysize(kExpElementIDs) - 1) {
- interstitial_page->WaitForFocusChange();
+ notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE;
+ notification_source = Source<RenderViewHost>(
+ interstitial_page->render_view_host());
} else {
// On the last tab key press, the focus returns to the browser.
- ui_test_utils::WaitForFocusInBrowser(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,
+ notification_type, notification_source));
+
// Let's make sure the focus is on the expected element in the page.
- std::string actual = interstitial_page->GetFocusedElement();
+ std::string actual;
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ interstitial_page->render_view_host(), L"",
+ L"window.domAutomationController.send(getFocusedElement());",
+ &actual));
ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str());
}
@@ -618,10 +616,11 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
// Focus stays on page with interstitials.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
// Page should have focus.
@@ -653,19 +652,22 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) {
// Make sure Find box can request focus, even when it is already open.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// Open some page (any page that doesn't steal focus).
- GURL url = server->TestServerPage(kTypicalPage);
+ GURL url = test_server()->GetURL(kTypicalPage);
ui_test_utils::NavigateToURL(browser(), url);
- gfx::NativeWindow window = browser()->window()->GetNativeHandle();
-
+#if defined(OS_MACOSX)
+ // Press Cmd+F, which will make the Find box open and request focus.
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_F, false, false, false, true));
+#else
// Press Ctrl+F, which will make the Find box open and request focus.
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true,
- false, false, false,
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_F, true, false, false, false));
+#endif
// Ideally, we wouldn't sleep here and instead would intercept the
// RenderViewHostDelegate::HandleKeyboardEvent() callback. To do that, we
@@ -682,10 +684,13 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// Now press Ctrl+F again and focus should move to the Find box.
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true,
- false, false, false,
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+#if defined(OS_MACOSX)
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_F, false, false, false, true));
+#else
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_F, true, false, false, false));
+#endif
ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
// Set focus to the page.
@@ -693,10 +698,13 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
// Now press Ctrl+F again and focus should move to the Find box.
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true, false,
- false, false,
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+#if defined(OS_MACOSX)
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_F, false, false, false, true));
+#else
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_F, true, false, false, false));
+#endif
// See remark above on why we wait.
MessageLoop::current()->PostDelayedTask(
@@ -707,12 +715,13 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
// Makes sure the focus is in the right location when opening the different
// types of tabs.
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabInitialFocus) {
+// Flaky, http://crbug.com/50763.
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FLAKY_TabInitialFocus) {
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+
// Open the history tab, focus should be on the tab contents.
browser()->ShowHistoryTab();
-
ui_test_utils::RunAllPendingInMessageLoop();
-
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
// Open the new tab, focus should be on the location bar.
@@ -726,17 +735,18 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabInitialFocus) {
// Open about:blank, focus should be on the location bar.
browser()->AddTabWithURL(GURL("about:blank"), GURL(), PageTransition::LINK,
-1, TabStripModel::ADD_SELECTED, NULL,
- std::string());
+ std::string(),
+ NULL);
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
}
// Tests that focus goes where expected when using reload.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// Open the new tab, reload.
browser()->NewTab();
-
ui_test_utils::RunAllPendingInMessageLoop();
browser()->Reload(CURRENT_TAB);
@@ -745,26 +755,38 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// Open a regular page, focus the location bar, reload.
- ui_test_utils::NavigateToURL(browser(), server->TestServerPage(kSimplePage));
+ ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(kSimplePage));
browser()->FocusLocationBar();
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
browser()->Reload(CURRENT_TAB);
ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
+
// Focus should now be on the tab contents.
browser()->ShowDownloadsTab();
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
}
+#if (defined(OS_CHROMEOS) || defined(OS_LINUX)) && !defined(NDEBUG)
+// Hangy, http://crbug.com/50025.
+#define MAYBE_FocusOnReloadCrashedTab DISABLED_FocusOnReloadCrashedTab
+#else
+#define MAYBE_FocusOnReloadCrashedTab FocusOnReloadCrashedTab
+#endif
+
// Tests that focus goes where expected when using reload on a crashed tab.
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReloadCrashedTab) {
- HTTPTestServer* server = StartHTTPServer();
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusOnReloadCrashedTab) {
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_TRUE(test_server()->Start());
// Open a regular page, crash, reload.
- ui_test_utils::NavigateToURL(browser(), server->TestServerPage(kSimplePage));
+ ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(kSimplePage));
ui_test_utils::CrashTab(browser()->GetSelectedTabContents());
browser()->Reload(CURRENT_TAB);
ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
+
// Focus should now be on the tab contents.
browser()->ShowDownloadsTab();
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
}
+
+} // namespace
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc
index e5b15e2..f7f01a4 100644
--- a/chrome/browser/browser_init.cc
+++ b/chrome/browser/browser_init.cc
@@ -8,13 +8,18 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/event_recorder.h"
+#include "base/file_path.h"
#include "base/histogram.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/automation_provider.h"
+#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/automation/chrome_frame_automation_provider.h"
+#include "chrome/browser/automation/testing_automation_provider.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
@@ -23,24 +28,27 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_creator.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/first_run.h"
+#include "chrome/browser/extensions/pack_extension_job.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/pref_service.h"
+#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/renderer_host/render_process_host.h"
+#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/session_startup_pref.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/shell_integration.h"
-#include "chrome/browser/status_icons/status_tray_manager.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/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/pinned_tab_codec.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -127,8 +135,8 @@ class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate {
delete this;
}
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetString(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT);
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT);
}
virtual SkBitmap* GetIcon() const {
@@ -140,10 +148,10 @@ class DefaultBrowserInfoBarDelegate : public ConfirmInfoBarDelegate {
return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
}
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
return button == BUTTON_OK ?
- l10n_util::GetString(IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL) :
- l10n_util::GetString(IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL);
+ l10n_util::GetStringUTF16(IDS_SET_AS_DEFAULT_INFOBAR_BUTTON_LABEL) :
+ l10n_util::GetStringUTF16(IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL);
}
virtual bool NeedElevation(InfoBarButton button) const {
@@ -243,16 +251,16 @@ class SessionCrashedInfoBarDelegate : public ConfirmInfoBarDelegate {
virtual void InfoBarClosed() {
delete this;
}
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetString(IDS_SESSION_CRASHED_VIEW_MESSAGE);
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_MESSAGE);
}
virtual SkBitmap* GetIcon() const {
return ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_INFOBAR_RESTORE_SESSION);
}
virtual int GetButtons() const { return BUTTON_OK; }
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
- return l10n_util::GetString(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON);
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
+ return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON);
}
virtual bool Accept() {
// Restore the session.
@@ -310,9 +318,9 @@ LaunchMode GetLaunchShortcutKind() {
// The windows quick launch path is not localized.
if (shortcut.find(L"\\Quick Launch\\") != std::wstring::npos)
return LM_SHORTCUT_QUICKLAUNCH;
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
std::string appdata_path;
- env->GetEnv("USERPROFILE", &appdata_path);
+ env->GetVar("USERPROFILE", &appdata_path);
if (!appdata_path.empty() &&
shortcut.find(ASCIIToWide(appdata_path)) != std::wstring::npos)
return LM_SHORTCUT_DESKTOP;
@@ -341,20 +349,6 @@ GURL GetWelcomePageURL() {
return GURL(welcome_url);
}
-void ShowPackExtensionMessage(const std::wstring caption,
- const std::wstring message) {
-#if defined(OS_WIN)
- win_util::MessageBox(NULL, message, caption, MB_OK | MB_SETFOREGROUND);
-#else
- // Just send caption & text to stdout on mac & linux.
- std::string out_text = WideToASCII(caption);
- out_text.append("\n\n");
- out_text.append(WideToASCII(message));
- out_text.append("\n");
- printf("%s", out_text.c_str());
-#endif
-}
-
void UrlsToTabs(const std::vector<GURL>& urls,
std::vector<BrowserInit::LaunchWithProfile::Tab>* tabs) {
for (size_t i = 0; i < urls.size(); ++i) {
@@ -372,20 +366,14 @@ bool BrowserInit::InProcessStartup() {
return in_startup;
}
-bool BrowserInit::LaunchBrowser(
- const CommandLine& command_line, Profile* profile,
- const std::wstring& cur_dir, bool process_startup,
- int* return_code) {
+bool BrowserInit::LaunchBrowser(const CommandLine& command_line,
+ Profile* profile,
+ const FilePath& cur_dir,
+ bool process_startup,
+ int* return_code) {
in_startup = process_startup;
DCHECK(profile);
-#if defined(OS_WIN)
- // Disable the DPI-virtualization mode of Windows Vista or later because it
- // causes some problems when using system messages (such as WM_NCHITTEST and
- // WM_GETTITLEBARINFOEX) on a custom frame.
- win_util::CallSetProcessDPIAware();
-#endif
-
// Continue with the off-the-record profile from here on if --incognito
if (command_line.HasSwitch(switches::kIncognito))
profile = profile->GetOffTheRecordProfile();
@@ -450,34 +438,13 @@ bool BrowserInit::LaunchBrowser(
chromeos::SystemKeyEventListener::instance();
}
#endif
-
- if (command_line.HasSwitch(switches::kRestoreBackgroundContents) ||
- command_line.HasSwitch(switches::kKeepAliveForTest)) {
- // Create status icons
- StatusTrayManager* tray = g_browser_process->status_tray_manager();
- if (tray)
- tray->Init(profile);
- }
- return true;
-}
-
-#if defined(OS_CHROMEOS)
-bool BrowserInit::ApplyServicesCustomization(
- const chromeos::ServicesCustomizationDocument* customization) {
- GURL welcome_url(customization->initial_start_page_url());
- DCHECK(welcome_url.is_valid()) << welcome_url;
- if (welcome_url.is_valid()) {
- AddFirstRunTab(welcome_url);
- }
- // TODO(denisromanov): Add extensions and web apps customization here.
return true;
}
-#endif
// LaunchWithProfile ----------------------------------------------------------
BrowserInit::LaunchWithProfile::LaunchWithProfile(
- const std::wstring& cur_dir,
+ const FilePath& cur_dir,
const CommandLine& command_line)
: cur_dir_(cur_dir),
command_line_(command_line),
@@ -486,7 +453,7 @@ BrowserInit::LaunchWithProfile::LaunchWithProfile(
}
BrowserInit::LaunchWithProfile::LaunchWithProfile(
- const std::wstring& cur_dir,
+ const FilePath& cur_dir,
const CommandLine& command_line,
BrowserInit* browser_init)
: cur_dir_(cur_dir),
@@ -495,6 +462,9 @@ BrowserInit::LaunchWithProfile::LaunchWithProfile(
browser_init_(browser_init) {
}
+BrowserInit::LaunchWithProfile::~LaunchWithProfile() {
+}
+
bool BrowserInit::LaunchWithProfile::Launch(Profile* profile,
bool process_startup) {
DCHECK(profile);
@@ -511,16 +481,16 @@ bool BrowserInit::LaunchWithProfile::Launch(Profile* profile,
if (command_line_.HasSwitch(switches::kRemoteShellPort)) {
std::string port_str =
command_line_.GetSwitchValueASCII(switches::kRemoteShellPort);
- int64 port = StringToInt64(port_str);
- if (port > 0 && port < 65535)
+ int64 port;
+ if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535)
g_browser_process->InitDebuggerWrapper(static_cast<int>(port), false);
else
DLOG(WARNING) << "Invalid remote shell port number " << port;
} else if (command_line_.HasSwitch(switches::kRemoteDebuggingPort)) {
std::string port_str =
command_line_.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
- int64 port = StringToInt64(port_str);
- if (port > 0 && port < 65535)
+ int64 port;
+ if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535)
g_browser_process->InitDebuggerWrapper(static_cast<int>(port), true);
else
DLOG(WARNING) << "Invalid http debugger port number " << port;
@@ -603,7 +573,7 @@ bool BrowserInit::LaunchWithProfile::IsAppLaunch(std::string* app_url,
*app_url = command_line_.GetSwitchValueASCII(switches::kApp);
return true;
}
- if (command_line_.HasSwitch(switches::kEnableApps) &&
+ if (!command_line_.HasSwitch(switches::kDisableApps) &&
command_line_.HasSwitch(switches::kAppId)) {
if (app_id)
*app_id = command_line_.GetSwitchValueASCII(switches::kAppId);
@@ -643,7 +613,7 @@ bool BrowserInit::LaunchWithProfile::OpenApplicationWindow(Profile* profile) {
ChildProcessSecurityPolicy::GetInstance();
if (policy->IsWebSafeScheme(url.scheme()) ||
url.SchemeIs(chrome::kFileScheme)) {
- Browser::OpenApplicationWindow(profile, url);
+ Browser::OpenApplicationWindow(profile, url, NULL);
return true;
}
}
@@ -653,6 +623,17 @@ bool BrowserInit::LaunchWithProfile::OpenApplicationWindow(Profile* profile) {
void BrowserInit::LaunchWithProfile::ProcessLaunchURLs(
bool process_startup,
const std::vector<GURL>& urls_to_open) {
+ // If we're starting up in "background mode" (no open browser window) then
+ // don't open any browser windows.
+ if (process_startup && command_line_.HasSwitch(switches::kNoStartupWindow)) {
+ BrowserList::StartKeepAlive();
+ // Keep the app alive while the system initializes, then allow it to
+ // shutdown if no other module wants to keep it running.
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableFunction(BrowserList::EndKeepAlive));
+ return;
+ }
+
if (process_startup && ProcessStartupURLs(urls_to_open)) {
// ProcessStartupURLs processed the urls, nothing else to do.
return;
@@ -778,7 +759,7 @@ Browser* BrowserInit::LaunchWithProfile::OpenTabsInBrowser(
TabContents* tab = browser->AddTabWithURL(
tabs[i].url, GURL(), PageTransition::START_PAGE, index, add_types, NULL,
- tabs[i].app_id);
+ tabs[i].app_id, NULL);
if (profile_ && first_tab && process_startup) {
AddCrashedInfoBarIfNecessary(tab);
@@ -830,8 +811,8 @@ void BrowserInit::LaunchWithProfile::AddBadFlagsInfoBarIfNecessary(
if (bad_flag) {
tab->AddInfoBar(new SimpleAlertInfoBarDelegate(tab,
- l10n_util::GetStringF(IDS_BAD_FLAGS_WARNING_MESSAGE,
- L"--" + ASCIIToWide(bad_flag)),
+ l10n_util::GetStringFUTF16(IDS_BAD_FLAGS_WARNING_MESSAGE,
+ UTF8ToUTF16(std::string("--") + bad_flag)),
NULL, false));
}
}
@@ -839,7 +820,6 @@ void BrowserInit::LaunchWithProfile::AddBadFlagsInfoBarIfNecessary(
std::vector<GURL> BrowserInit::LaunchWithProfile::GetURLsFromCommandLine(
Profile* profile) {
std::vector<GURL> urls;
- FilePath cur_dir = FilePath::FromWStringHack(cur_dir_);
const std::vector<CommandLine::StringType>& params = command_line_.args();
for (size_t i = 0; i < params.size(); ++i) {
@@ -850,7 +830,7 @@ std::vector<GURL> BrowserInit::LaunchWithProfile::GetURLsFromCommandLine(
profile->GetTemplateURLModel()->GetDefaultSearchProvider();
if (!default_provider || !default_provider->url()) {
// No search provider available. Just treat this as regular URL.
- urls.push_back(URLFixerUpper::FixupRelativeFile(cur_dir, param));
+ urls.push_back(URLFixerUpper::FixupRelativeFile(cur_dir_, param));
continue;
}
const TemplateURLRef* search_url = default_provider->url();
@@ -861,7 +841,7 @@ std::vector<GURL> BrowserInit::LaunchWithProfile::GetURLsFromCommandLine(
TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring())));
} else {
// This will create a file URL or a regular URL.
- GURL url(URLFixerUpper::FixupRelativeFile(cur_dir, param));
+ GURL url(URLFixerUpper::FixupRelativeFile(cur_dir_, param));
// Exclude dangerous schemes.
if (url.is_valid()) {
ChildProcessSecurityPolicy *policy =
@@ -929,8 +909,56 @@ void BrowserInit::LaunchWithProfile::CheckDefaultBrowser(Profile* profile) {
ChromeThread::FILE, FROM_HERE, new CheckDefaultBrowserTask());
}
+class PackExtensionLogger : public PackExtensionJob::Client {
+ public:
+ PackExtensionLogger() {}
+ virtual void OnPackSuccess(const FilePath& crx_path,
+ const FilePath& output_private_key_path);
+ virtual void OnPackFailure(const std::string& error_message);
+
+ private:
+ void ShowPackExtensionMessage(const std::wstring& caption,
+ const std::wstring& message);
+
+ DISALLOW_COPY_AND_ASSIGN(PackExtensionLogger);
+};
+
+void PackExtensionLogger::OnPackSuccess(const FilePath& crx_path,
+ const FilePath& output_private_key_path)
+{
+ ShowPackExtensionMessage(L"Extension Packaging Success",
+ PackExtensionJob::StandardSuccessMessage(
+ crx_path, output_private_key_path));
+}
+
+void PackExtensionLogger::OnPackFailure(const std::string& error_message) {
+ ShowPackExtensionMessage(L"Extension Packaging Error",
+ UTF8ToWide(error_message));
+}
+
+void PackExtensionLogger::ShowPackExtensionMessage(const std::wstring& caption,
+ const std::wstring& message)
+{
+#if defined(OS_WIN)
+ win_util::MessageBox(NULL, message, caption, MB_OK | MB_SETFOREGROUND);
+#else
+ // Just send caption & text to stdout on mac & linux.
+ std::string out_text = WideToASCII(caption);
+ out_text.append("\n\n");
+ out_text.append(WideToASCII(message));
+ out_text.append("\n");
+ printf("%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 BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
- const std::wstring& cur_dir,
+ const FilePath& cur_dir,
bool process_startup,
Profile* profile,
int* return_code,
@@ -949,10 +977,12 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
// If there are any extra parameters, we expect each one to generate a
// new tab; if there are none then we get one homepage tab.
int expected_tab_count = 1;
- if (command_line.HasSwitch(switches::kRestoreLastSession)) {
+ if (command_line.HasSwitch(switches::kNoStartupWindow)) {
+ expected_tab_count = 0;
+ } else if (command_line.HasSwitch(switches::kRestoreLastSession)) {
std::string restore_session_value(
command_line.GetSwitchValueASCII(switches::kRestoreLastSession));
- StringToInt(restore_session_value, &expected_tab_count);
+ base::StringToInt(restore_session_value, &expected_tab_count);
} else {
expected_tab_count =
std::max(1, static_cast<int>(command_line.args().size()));
@@ -973,44 +1003,21 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
switches::kPackExtensionKey);
}
- // Output Paths.
- FilePath output(src_dir.DirName().Append(src_dir.BaseName().value()));
- FilePath crx_path(output);
- crx_path = crx_path.ReplaceExtension(chrome::kExtensionFileExtension);
- FilePath output_private_key_path;
- if (private_key_path.empty()) {
- output_private_key_path = FilePath(output);
- output_private_key_path =
- output_private_key_path.ReplaceExtension(FILE_PATH_LITERAL("pem"));
- }
+ // 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();
- // TODO(port): Creation & running is removed from mac & linux because
- // ExtensionCreator depends on base/crypto/rsa_private_key and
- // base/crypto/signature_creator, both of which only have windows
- // implementations.
- scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
- if (creator->Run(src_dir, crx_path, private_key_path,
- output_private_key_path)) {
- std::wstring message;
- if (private_key_path.value().empty()) {
- message = StringPrintf(
- L"Created the following files:\n\n"
- L"Extension: %ls\n"
- L"Key File: %ls\n\n"
- L"Keep your key file in a safe place. You will need it to create "
- L"new versions of your extension.",
- crx_path.ToWStringHack().c_str(),
- output_private_key_path.ToWStringHack().c_str());
- } else {
- message = StringPrintf(L"Created the extension:\n\n%ls",
- crx_path.ToWStringHack().c_str());
- }
- ShowPackExtensionMessage(L"Extension Packaging Success", message);
- } else {
- ShowPackExtensionMessage(L"Extension Packaging Error",
- UTF8ToWide(creator->error_message()));
- return false;
- }
return false;
}
}
@@ -1036,16 +1043,25 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line,
}
}
+ // If we have been invoked to display a desktop notification on behalf of
+ // the service process, we do not want to open any browser windows.
+ if (command_line.HasSwitch(switches::kNotifyCloudPrintTokenExpired)) {
+ silent_launch = true;
+ profile->GetCloudPrintProxyService()->ShowTokenExpiredNotification();
+ }
+
if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
- std::wstring allowed_ports =
- command_line.GetSwitchValue(switches::kExplicitlyAllowedPorts);
+ std::string allowed_ports =
+ command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
net::SetExplicitlyAllowedPorts(allowed_ports);
}
#if defined(OS_CHROMEOS)
// The browser will be launched after the user logs in.
- if (command_line.HasSwitch(switches::kLoginManager))
+ if (command_line.HasSwitch(switches::kLoginManager) ||
+ command_line.HasSwitch(switches::kLoginPassword)) {
silent_launch = true;
+ }
#endif
// If we don't want to launch a new browser window or tab (in the case
diff --git a/chrome/browser/browser_init.h b/chrome/browser/browser_init.h
index 3aa9b70..4676cfe 100644
--- a/chrome/browser/browser_init.h
+++ b/chrome/browser/browser_init.h
@@ -1,28 +1,24 @@
-// 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.
#ifndef CHROME_BROWSER_BROWSER_INIT_H_
#define CHROME_BROWSER_BROWSER_INIT_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/file_path.h"
#include "base/gtest_prod_util.h"
#include "googleurl/src/gurl.h"
class Browser;
class CommandLine;
class GURL;
-class PrefService;
class Profile;
class TabContents;
-#if defined(OS_CHROMEOS)
-namespace chromeos {
-class ServicesCustomizationDocument;
-}
-#endif
// class containing helpers for BrowserMain to spin up a new instance and
// initialize the profile.
@@ -39,22 +35,21 @@ class BrowserInit {
// This function is equivalent to ProcessCommandLine but should only be
// called during actual process startup.
- bool Start(const CommandLine& cmd_line, const std::wstring& cur_dir,
+ bool Start(const CommandLine& cmd_line, const FilePath& cur_dir,
Profile* profile, int* return_code) {
return ProcessCmdLineImpl(cmd_line, cur_dir, true, profile, return_code,
this);
}
- // This function performs command-line handling and is invoked when
- // process starts as well as when we get a start request from another
- // process (via the WM_COPYDATA message). |command_line| holds the command
- // line we need to process - either from this process or from some other one
- // (if |process_startup| is true and we are being called from
- // ProcessSingleton::OnCopyData).
+ // This function performs command-line handling and is invoked when process
+ // starts as well as when we get a start request from another process (via the
+ // WM_COPYDATA message). |command_line| holds the command line we need to
+ // process - either from this process or from some other one (if
+ // |process_startup| is true and we are being called from
+ // ProcessSingleton::OnCopyData).
static bool ProcessCommandLine(const CommandLine& cmd_line,
- const std::wstring& cur_dir,
- bool process_startup, Profile* profile,
- int* return_code) {
+ const FilePath& cur_dir, bool process_startup,
+ Profile* profile, int* return_code) {
return ProcessCmdLineImpl(cmd_line, cur_dir, process_startup, profile,
return_code, NULL);
}
@@ -67,22 +62,14 @@ class BrowserInit {
// Returns true if the browser is coming up.
static bool InProcessStartup();
- // Launches a browser window associated with |profile|. |command_line|
- // should be the command line passed to this process. |cur_dir| can be
- // the null string, which implies that the directory of the executable.
- // should be used. |process_startup| indicates whether this is the
- // first browser.
+ // Launches a browser window associated with |profile|. |command_line| should
+ // be the command line passed to this process. |cur_dir| can be empty, which
+ // implies that the directory of the executable should be used.
+ // |process_startup| indicates whether this is the first browser.
bool LaunchBrowser(const CommandLine& command_line, Profile* profile,
- const std::wstring& cur_dir, bool process_startup,
+ const FilePath& cur_dir, bool process_startup,
int* return_code);
-#if defined(OS_CHROMEOS)
- // Processes the OEM services customization document and modifies browser
- // settings like initial startup page, web apps and extentions.
- bool ApplyServicesCustomization(
- const chromeos::ServicesCustomizationDocument* customization);
-#endif
-
// LaunchWithProfile ---------------------------------------------------------
//
// Assists launching the application and appending the initial tabs for a
@@ -112,12 +99,10 @@ class BrowserInit {
// and thus no access to distribution-specific first-run behaviors. The
// second one is always called when the browser starts even if it is not
// the first run.
- LaunchWithProfile(const std::wstring& cur_dir,
- const CommandLine& command_line);
- LaunchWithProfile(const std::wstring& cur_dir,
- const CommandLine& command_line,
+ LaunchWithProfile(const FilePath& cur_dir, const CommandLine& command_line);
+ LaunchWithProfile(const FilePath& cur_dir, const CommandLine& command_line,
BrowserInit* browser_init);
- ~LaunchWithProfile() { }
+ ~LaunchWithProfile();
// Creates the necessary windows for startup. Returns true on success,
// false on failure. process_startup is true if Chrome is just
@@ -193,7 +178,7 @@ class BrowserInit {
// previously instructed not to do so) and warns the user if it is not.
void CheckDefaultBrowser(Profile* profile);
- std::wstring cur_dir_;
+ const FilePath cur_dir_;
const CommandLine& command_line_;
Profile* profile_;
BrowserInit* browser_init_;
@@ -202,9 +187,9 @@ class BrowserInit {
private:
static bool ProcessCmdLineImpl(const CommandLine& command_line,
- const std::wstring& cur_dir,
- bool process_startup, Profile* profile,
- int* return_code, BrowserInit* browser_init);
+ const FilePath& cur_dir, bool process_startup,
+ Profile* profile, int* return_code,
+ BrowserInit* browser_init);
// Additional tabs to open during first run.
std::vector<GURL> first_run_tabs_;
diff --git a/chrome/browser/browser_init_browsertest.cc b/chrome/browser/browser_init_browsertest.cc
index 8d130fc..f5ad83c 100644
--- a/chrome/browser/browser_init_browsertest.cc
+++ b/chrome/browser/browser_init_browsertest.cc
@@ -1,7 +1,10 @@
-// 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.
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_init.h"
#include "chrome/browser/browser_list.h"
@@ -31,8 +34,7 @@ class OpenURLsPopupObserver : public BrowserList::Observer {
// Test that when there is a popup as the active browser any requests to
// BrowserInit::LaunchWithProfile::OpenURLsInBrowser don't crash because
// there's no explicit profile given.
-// Flaky, http://crbug.com/42318.
-IN_PROC_BROWSER_TEST_F(BrowserInitTest, FLAKY_OpenURLsPopup) {
+IN_PROC_BROWSER_TEST_F(BrowserInitTest, OpenURLsPopup) {
std::vector<GURL> urls;
urls.push_back(GURL("http://localhost"));
@@ -49,7 +51,7 @@ IN_PROC_BROWSER_TEST_F(BrowserInitTest, FLAKY_OpenURLsPopup) {
ASSERT_EQ(popup, observer.added_browser_);
CommandLine dummy(CommandLine::ARGUMENTS_ONLY);
- BrowserInit::LaunchWithProfile launch(std::wstring(), dummy);
+ BrowserInit::LaunchWithProfile launch(FilePath(), dummy);
// This should create a new window, but re-use the profile from |popup|. If
// it used a NULL or invalid profile, it would crash.
launch.OpenURLsInBrowser(popup, false, urls);
@@ -63,16 +65,16 @@ IN_PROC_BROWSER_TEST_F(BrowserInitTest, FLAKY_OpenURLsPopup) {
// to start on most BuildBot runs and I don't want to add longer delays to
// the test. I'll circle back and make this work properly when i get a chance.
IN_PROC_BROWSER_TEST_F(BrowserInitTest, FLAKY_BlockBadURLs) {
- const std::wstring testurlstr(L"http://localhost/");
- const GURL testurl(WideToUTF16Hack(testurlstr));
+ const char* testurlstr = "http://localhost/";
+ const GURL testurl(testurlstr);
CommandLine cmdline(CommandLine::ARGUMENTS_ONLY);
- cmdline.AppendLooseValue(testurlstr);
- cmdline.AppendLooseValue(std::wstring(L"javascript:alert('boo')"));
- cmdline.AppendLooseValue(testurlstr);
- cmdline.AppendLooseValue(std::wstring(L"view-source:http://localhost/"));
+ cmdline.AppendArg(testurlstr);
+ cmdline.AppendArg("javascript:alert('boo')");
+ cmdline.AppendArg(testurlstr);
+ cmdline.AppendArg("view-source:http://localhost/");
// This will pick up the current browser instance.
- BrowserInit::LaunchWithProfile launch(std::wstring(), cmdline);
+ BrowserInit::LaunchWithProfile launch(FilePath(), cmdline);
launch.Launch(browser()->profile(), false);
// Give the browser a chance to start first. FIXME(jschuh)
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc
index 0b6e8fb..6e55f3e 100644
--- a/chrome/browser/browser_keyevents_browsertest.cc
+++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -4,16 +4,14 @@
#include "build/build_config.h"
+#include "app/keyboard_codes.h"
#include "base/basictypes.h"
-#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
@@ -24,6 +22,7 @@
#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"
namespace {
@@ -41,8 +40,11 @@ const wchar_t kSetFocusedElementJS[] =
const wchar_t kGetTextBoxValueJS[] =
L"window.domAutomationController.send("
L"document.getElementById('%ls').value);";
+const wchar_t kSetTextBoxValueJS[] =
+ L"window.domAutomationController.send("
+ L"document.getElementById('%ls').value = '%ls');";
const wchar_t kStartTestJS[] =
- L"window.domAutomationController.send(startTest());";
+ L"window.domAutomationController.send(startTest(%d));";
// Maximum lenght of the result array in KeyEventTestData structure.
const size_t kMaxResultLength = 10;
@@ -51,18 +53,19 @@ const size_t kMaxResultLength = 10;
// Each keyboard event may generate multiple result strings representing
// the result of keydown, keypress, keyup and textInput events.
// For keydown, keypress and keyup events, the format of the result string is:
-// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey>
+// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
// where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
-// <ctrlKey>, <shiftKey> and <altKey> are boolean value indicating the state of
-// corresponding modifier key.
+// <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
+// the state of corresponding modifier key.
// For textInput event, the format is: T <text>, where <text> is the text to be
// input.
// Please refer to chrome/test/data/keyevents_test.html for details.
struct KeyEventTestData {
- base::KeyboardCode key;
+ app::KeyboardCode key;
bool ctrl;
bool shift;
bool alt;
+ bool command;
bool suppress_keydown;
bool suppress_keypress;
@@ -124,23 +127,6 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
EnableDOMAutomation();
}
- void GetNativeWindow(gfx::NativeWindow* native_window) {
- BrowserWindow* window = browser()->window();
- ASSERT_TRUE(window);
- *native_window = window->GetNativeHandle();
- ASSERT_TRUE(*native_window);
- }
-
- void SendKey(base::KeyboardCode key, bool control, bool shift, bool alt) {
- gfx::NativeWindow window = NULL;
- ASSERT_NO_FATAL_FAILURE(GetNativeWindow(&window));
- EXPECT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
- window, key, control, shift, alt,
- false /* command, */,
- new MessageLoop::QuitTask()));
- ui_test_utils::RunMessageLoop();
- }
-
bool IsViewFocused(ViewID vid) {
return ui_test_utils::IsViewFocused(browser(), vid);
}
@@ -238,12 +224,24 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
ASSERT_EQ(WideToUTF8(value), actual);
}
- void StartTest(int tab_index) {
+ void SetTextBoxValue(int tab_index, const wchar_t* id,
+ const wchar_t* value) {
+ ASSERT_LT(tab_index, browser()->tab_count());
+ std::string actual;
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetTabContentsAt(tab_index)->render_view_host(),
+ L"",
+ StringPrintf(kSetTextBoxValueJS, id, value),
+ &actual));
+ ASSERT_EQ(WideToUTF8(value), actual);
+ }
+
+ void StartTest(int tab_index, int result_length) {
ASSERT_LT(tab_index, browser()->tab_count());
bool actual;
ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
browser()->GetTabContentsAt(tab_index)->render_view_host(),
- L"", kStartTestJS, &actual));
+ L"", StringPrintf(kStartTestJS, result_length), &actual));
ASSERT_TRUE(actual);
}
@@ -253,18 +251,19 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
// Inform our testing web page that we are about to start testing a key
// event.
- ASSERT_NO_FATAL_FAILURE(StartTest(tab_index));
+ ASSERT_NO_FATAL_FAILURE(StartTest(tab_index, test.result_length));
ASSERT_NO_FATAL_FAILURE(SuppressEvents(
tab_index, test.suppress_keydown, test.suppress_keypress,
test.suppress_keyup, test.suppress_textinput));
// We need to create a finish observer before sending the key event,
// because the test finished message might be arrived before returning
- // from the SendKey() method.
+ // from the SendKeyPressSync() method.
TestFinishObserver finish_observer(
browser()->GetTabContentsAt(tab_index)->render_view_host());
- ASSERT_NO_FATAL_FAILURE(SendKey(test.key, test.ctrl, test.shift, test.alt));
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), test.key, test.ctrl, test.shift, test.alt, test.command));
ASSERT_TRUE(finish_observer.WaitForFinish());
ASSERT_NO_FATAL_FAILURE(CheckResult(
tab_index, test.result_length, test.result));
@@ -272,10 +271,10 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
std::string GetTestDataDescription(const KeyEventTestData& data) {
std::string desc = StringPrintf(
- " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d\n"
+ " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d, command:%d\n"
" Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n"
" Expected results(%d):\n",
- data.key, data.ctrl, data.shift, data.alt,
+ data.key, data.ctrl, data.shift, data.alt, data.command,
data.suppress_keydown, data.suppress_keypress, data.suppress_keyup,
data.suppress_textinput, data.result_length);
for (int i = 0; i < data.result_length; ++i) {
@@ -287,72 +286,70 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
}
};
-} // namespace
-
-// Flaky since r51395. See crbug.com/48671.
-IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FLAKY_NormalKeyEvents) {
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, NormalKeyEvents) {
static const KeyEventTestData kTestNoInput[] = {
// a
- { base::VKEY_A, false, false, false,
+ { app::VKEY_A, false, false, false, false,
false, false, false, false, 3,
- { "D 65 0 false false false",
- "P 97 97 false false false",
- "U 65 0 false false false" } },
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
+ "U 65 0 false false false false" } },
// shift-a
- { base::VKEY_A, false, true, false,
+ { app::VKEY_A, false, true, false, false,
false, false, false, false, 5,
- { "D 16 0 false true false",
- "D 65 0 false true false",
- "P 65 65 false true false",
- "U 65 0 false true false",
- "U 16 0 false true false" } },
+ { "D 16 0 false true false false",
+ "D 65 0 false true false false",
+ "P 65 65 false true false false",
+ "U 65 0 false true false false",
+ "U 16 0 false true false false" } },
// a, suppress keydown
- { base::VKEY_A, false, false, false,
+ { app::VKEY_A, false, false, false, false,
true, false, false, false, 2,
- { "D 65 0 false false false",
- "U 65 0 false false false" } },
+ { "D 65 0 false false false false",
+ "U 65 0 false false false false" } },
};
static const KeyEventTestData kTestWithInput[] = {
// a
- { base::VKEY_A, false, false, false,
+ { app::VKEY_A, false, false, false, false,
false, false, false, false, 4,
- { "D 65 0 false false false",
- "P 97 97 false false false",
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
"T a",
- "U 65 0 false false false" } },
+ "U 65 0 false false false false" } },
// shift-a
- { base::VKEY_A, false, true, false,
+ { app::VKEY_A, false, true, false, false,
false, false, false, false, 6,
- { "D 16 0 false true false",
- "D 65 0 false true false",
- "P 65 65 false true false",
+ { "D 16 0 false true false false",
+ "D 65 0 false true false false",
+ "P 65 65 false true false false",
"T A",
- "U 65 0 false true false",
- "U 16 0 false true false" } },
+ "U 65 0 false true false false",
+ "U 16 0 false true false false" } },
// a, suppress keydown
- { base::VKEY_A, false, false, false,
+ { app::VKEY_A, false, false, false, false,
true, false, false, false, 2,
- { "D 65 0 false false false",
- "U 65 0 false false false" } },
+ { "D 65 0 false false false false",
+ "U 65 0 false false false false" } },
// a, suppress keypress
- { base::VKEY_A, false, false, false,
+ { app::VKEY_A, false, false, false, false,
false, true, false, false, 3,
- { "D 65 0 false false false",
- "P 97 97 false false false",
- "U 65 0 false false false" } },
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
+ "U 65 0 false false false false" } },
// a, suppress textInput
- { base::VKEY_A, false, false, false,
+ { app::VKEY_A, false, false, false, false,
false, false, false, true, 4,
- { "D 65 0 false false false",
- "P 97 97 false false false",
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
"T a",
- "U 65 0 false false false" } },
+ "U 65 0 false false false false" } },
};
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(test_server()->Start());
- GURL url = server->TestServerPage(kTestingPage);
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -365,68 +362,79 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FLAKY_NormalKeyEvents) {
<< GetTestDataDescription(kTestNoInput[i]);
}
+ // Input in normal text box.
ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
- << "kTestWithInput[" << i << "] failed:\n"
+ << "kTestWithInput[" << i << "] in text box failed:\n"
<< GetTestDataDescription(kTestWithInput[i]);
}
-
EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA"));
+
+ // Input in password box.
+ ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"B"));
+ for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
+ << "kTestWithInput[" << i << "] in password box failed:\n"
+ << GetTestDataDescription(kTestWithInput[i]);
+ }
+ EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"B", L"aA"));
}
+#if defined(OS_WIN) || defined(OS_LINUX)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
static const KeyEventTestData kTestCtrlF = {
- base::VKEY_F, true, false, false,
+ app::VKEY_F, true, false, false, false,
false, false, false, false, 2,
- { "D 17 0 true false false",
- "D 70 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 70 0 true false false false" }
};
static const KeyEventTestData kTestCtrlFSuppressKeyDown = {
- base::VKEY_F, true, false, false,
+ app::VKEY_F, true, false, false, false,
true, false, false, false, 4,
- { "D 17 0 true false false",
- "D 70 0 true false false",
- "U 70 0 true false false",
- "U 17 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 70 0 true false false false",
+ "U 70 0 true false false false",
+ "U 17 0 true false false false" }
};
// Ctrl+Z doesn't bind to any accelerators, which then should generate a
// keypress event with charCode=26.
static const KeyEventTestData kTestCtrlZ = {
- base::VKEY_Z, true, false, false,
+ app::VKEY_Z, true, false, false, false,
false, false, false, false, 5,
- { "D 17 0 true false false",
- "D 90 0 true false false",
- "P 26 26 true false false",
- "U 90 0 true false false",
- "U 17 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 90 0 true false false false",
+ "P 26 26 true false false false",
+ "U 90 0 true false false false",
+ "U 17 0 true false false false" }
};
static const KeyEventTestData kTestCtrlZSuppressKeyDown = {
- base::VKEY_Z, true, false, false,
+ app::VKEY_Z, true, false, false, false,
true, false, false, false, 4,
- { "D 17 0 true false false",
- "D 90 0 true false false",
- "U 90 0 true false false",
- "U 17 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 90 0 true false false false",
+ "U 90 0 true false false false",
+ "U 17 0 true false false false" }
};
// Ctrl+Enter shall generate a keypress event with charCode=10 (LF).
static const KeyEventTestData kTestCtrlEnter = {
- base::VKEY_RETURN, true, false, false,
+ app::VKEY_RETURN, true, false, false, false,
false, false, false, false, 5,
- { "D 17 0 true false false",
- "D 13 0 true false false",
- "P 10 10 true false false",
- "U 13 0 true false false",
- "U 17 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 13 0 true false false false",
+ "P 10 10 true false false false",
+ "U 13 0 true false false false",
+ "U 17 0 true false false false" }
};
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(test_server()->Start());
- GURL url = server->TestServerPage(kTestingPage);
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
@@ -438,7 +446,8 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
// Press Escape to close the Find box and move the focus back to the web page.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_ESCAPE, false, false, false));
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_ESCAPE, false, false, false, false));
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
// Press Ctrl+F with keydown suppressed shall not open the find box.
@@ -449,52 +458,131 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZSuppressKeyDown));
EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlEnter));
}
+#elif defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CommandKeyEvents) {
+ static const KeyEventTestData kTestCmdF = {
+ app::VKEY_F, false, false, false, true,
+ false, false, false, false, 2,
+ { "D 91 0 false false false true",
+ "D 70 0 false false false true" }
+ };
+
+ // On Mac we don't send key up events when command modifier is down.
+ static const KeyEventTestData kTestCmdFSuppressKeyDown = {
+ app::VKEY_F, false, false, false, true,
+ true, false, false, false, 3,
+ { "D 91 0 false false false true",
+ "D 70 0 false false false true",
+ "U 91 0 false false false true" }
+ };
+
+ ASSERT_TRUE(test_server()->Start());
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ int tab_index = browser()->selected_index();
+ // Press Cmd+F, which will make the Find box open and request focus.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdF));
+ EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
+
+ // Press Escape to close the Find box and move the focus back to the web page.
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_ESCAPE, false, false, false, false));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ // Press Cmd+F with keydown suppressed shall not open the find box.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdFSuppressKeyDown));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+}
+#endif
-#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
-// See http://crbug.com/40037 for details.
-#define MAYBE_AccessKeys DISABLED_AccessKeys
+#if defined(OS_WIN)
+// Tests may fail on windows: http://crbug.com/55713
+#define MAYBE_AccessKeys FLAKY_AccessKeys
#else
#define MAYBE_AccessKeys AccessKeys
#endif
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
- static const KeyEventTestData kTestAltA = {
- base::VKEY_A, false, false, true,
+#if defined(OS_MACOSX)
+ // On Mac, access keys use ctrl+alt modifiers.
+ static const KeyEventTestData kTestAccessA = {
+ app::VKEY_A, true, false, true, false,
+ false, false, false, false, 6,
+ { "D 17 0 true false false false",
+ "D 18 0 true false true false",
+ "D 65 0 true false true false",
+ "U 65 0 true false true false",
+ "U 18 0 true false true false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestAccessDSuppress = {
+ app::VKEY_D, true, false, true, false,
+ true, true, true, false, 6,
+ { "D 17 0 true false false false",
+ "D 18 0 true false true false",
+ "D 68 0 true false true false",
+ "U 68 0 true false true false",
+ "U 18 0 true false true false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestAccess1 = {
+ app::VKEY_1, true, false, true, false,
+ false, false, false, false, 6,
+ { "D 17 0 true false false false",
+ "D 18 0 true false true false",
+ "D 49 0 true false true false",
+ "U 49 0 true false true false",
+ "U 18 0 true false true false",
+ "U 17 0 true false false false" }
+ };
+#else
+ static const KeyEventTestData kTestAccessA = {
+ app::VKEY_A, false, false, true, false,
false, false, false, false, 4,
- { "D 18 0 false false true",
- "D 65 0 false false true",
- "U 65 0 false false true",
- "U 18 0 false false true" }
+ { "D 18 0 false false true false",
+ "D 65 0 false false true false",
+ "U 65 0 false false true false",
+ "U 18 0 false false true false" }
};
- static const KeyEventTestData kTestAltD = {
- base::VKEY_D, false, false, true,
+ static const KeyEventTestData kTestAccessD = {
+ app::VKEY_D, false, false, true, false,
false, false, false, false, 2,
- { "D 18 0 false false true",
- "D 68 0 false false true" }
+ { "D 18 0 false false true false",
+ "D 68 0 false false true false" }
};
- static const KeyEventTestData kTestAltDSuppress = {
- base::VKEY_D, false, false, true,
+ static const KeyEventTestData kTestAccessDSuppress = {
+ app::VKEY_D, false, false, true, false,
true, true, true, false, 4,
- { "D 18 0 false false true",
- "D 68 0 false false true",
- "U 68 0 false false true",
- "U 18 0 false false true" }
+ { "D 18 0 false false true false",
+ "D 68 0 false false true false",
+ "U 68 0 false false true false",
+ "U 18 0 false false true false" }
};
- static const KeyEventTestData kTestAlt1 = {
- base::VKEY_1, false, false, true,
+ static const KeyEventTestData kTestAccess1 = {
+ app::VKEY_1, false, false, true, false,
false, false, false, false, 4,
- { "D 18 0 false false true",
- "D 49 0 false false true",
- "U 49 0 false false true",
- "U 18 0 false false true" }
+ { "D 18 0 false false true false",
+ "D 49 0 false false true false",
+ "U 49 0 false false true false",
+ "U 18 0 false false true false" }
};
+#endif
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(test_server()->Start());
- GURL url = server->TestServerPage(kTestingPage);
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
ui_test_utils::RunAllPendingInMessageLoop();
@@ -505,15 +593,22 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
// Make sure no element is focused.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
// Alt+A should focus the element with accesskey = "A".
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltA));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessA));
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"A"));
// Blur the focused element.
EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
// Make sure no element is focused.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
+
+#if !defined(OS_MACOSX)
// Alt+D should move the focus to the location entry.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltD));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessD));
+
+ // TODO(isherman): This is an experimental change to help diagnose
+ // http://crbug.com/55713
+ ui_test_utils::RunAllPendingInMessageLoop();
+
EXPECT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// No element should be focused, as Alt+D was handled by the browser.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
@@ -524,11 +619,13 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
// Make sure no element is focused.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
+#endif
+
// If the keydown event is suppressed, then Alt+D should be handled as an
// accesskey rather than an accelerator key. Activation of an accesskey is not
// a part of the default action of the key event, so it should not be
// suppressed at all.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltDSuppress));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessDSuppress));
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"D"));
@@ -536,30 +633,38 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
// Make sure no element is focused.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAlt1));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccess1));
#if defined(TOOLKIT_GTK)
// On GTK, alt-0..9 are assigned as tab selection accelerators, so they can
// not be used as accesskeys.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
-#elif defined(OS_WIN)
+#else
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1"));
#endif
}
-IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, ReservedAccelerators) {
- HTTPTestServer* server = StartHTTPServer();
+#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) {
+ ASSERT_TRUE(test_server()->Start());
- GURL url = server->TestServerPage(kTestingPage);
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
static const KeyEventTestData kTestCtrlT = {
- base::VKEY_T, true, false, false,
+ app::VKEY_T, true, false, false, false,
true, false, false, false, 1,
- { "D 17 0 true false false" }
+ { "D 17 0 true false false false" }
};
ASSERT_EQ(1, browser()->tab_count());
@@ -576,46 +681,70 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, ReservedAccelerators) {
// Reserved accelerators can't be suppressed.
ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
// Press Ctrl+W, which will close the tab.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_W, true, false, false));
+ 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 = {
+ 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 = {
- base::VKEY_T, true, false, false,
+ app::VKEY_T, true, false, false, false,
false, false, false, false, 2,
- { "D 17 0 true false false",
- "D 84 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 84 0 true false false false" }
};
static const KeyEventTestData kTestCtrlPageDown = {
- base::VKEY_NEXT, true, false, false,
+ app::VKEY_NEXT, true, false, false, false,
true, false, false, false, 1,
- { "D 17 0 true false false" }
+ { "D 17 0 true false false false" }
};
static const KeyEventTestData kTestCtrlTab = {
- base::VKEY_TAB, true, false, false,
+ app::VKEY_TAB, true, false, false, false,
true, false, false, false, 1,
- { "D 17 0 true false false" }
+ { "D 17 0 true false false false" }
};
static const KeyEventTestData kTestCtrlTBlocked = {
- base::VKEY_T, true, false, false,
+ app::VKEY_T, true, false, false, false,
true, false, false, false, 4,
- { "D 17 0 true false false",
- "D 84 0 true false false",
- "U 84 0 true false false",
- "U 17 0 true false false" }
+ { "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" }
};
static const KeyEventTestData kTestCtrlWBlocked = {
- base::VKEY_W, true, false, false,
+ app::VKEY_W, true, false, false, false,
true, false, false, false, 4,
- { "D 17 0 true false false",
- "D 87 0 true false false",
- "U 87 0 true false false",
- "U 17 0 true false false" }
+ { "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_EQ(1, browser()->tab_count());
@@ -647,7 +776,144 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, ReservedAccelerators) {
// Ctrl+F4 to close the tab.
ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_F4, true, false, false));
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_F4, true, false, false, false));
ASSERT_EQ(1, browser()->tab_count());
#endif
}
+
+#if defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) {
+ static const KeyEventTestData kTestCtrlA = {
+ app::VKEY_A, true, false, false, false,
+ false, false, false, false, 4,
+ { "D 17 0 true false false false",
+ "D 65 0 true false false false",
+ "U 65 0 true false false false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestCtrlF = {
+ app::VKEY_F, true, false, false, false,
+ false, false, false, false, 4,
+ { "D 17 0 true false false false",
+ "D 70 0 true false false false",
+ "U 70 0 true false false false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestCtrlK = {
+ app::VKEY_K, true, false, false, false,
+ false, false, false, false, 4,
+ { "D 17 0 true false false false",
+ "D 75 0 true false false false",
+ "U 75 0 true false false false",
+ "U 17 0 true false false false" }
+ };
+
+ ASSERT_TRUE(test_server()->Start());
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ int tab_index = browser()->selected_index();
+ ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
+ ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index, L"A", L"Hello"));
+ // Move the caret to the beginning of the line.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlA));
+ // Forward one character
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
+ // Delete to the end of the line.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlK));
+ EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"H"));
+}
+#endif
+
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, PageUpDownKeys) {
+ static const KeyEventTestData kTestPageUp = {
+ app::VKEY_PRIOR, false, false, false, false,
+ false, false, false, false, 2,
+ { "D 33 0 false false false false",
+ "U 33 0 false false false false" }
+ };
+
+ static const KeyEventTestData kTestPageDown = {
+ app::VKEY_NEXT, false, false, false, false,
+ false, false, false, false, 2,
+ { "D 34 0 false false false false",
+ "U 34 0 false false false false" }
+ };
+
+ ASSERT_TRUE(test_server()->Start());
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ int tab_index = browser()->selected_index();
+ ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageUp));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageDown));
+ EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L""));
+}
+
+#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FocusMenuBarByAltKey) {
+ static const KeyEventTestData kTestAltKey = {
+ app::VKEY_MENU, false, false, false, false,
+ false, false, false, false, 2,
+ { "D 18 0 false false true false",
+ "U 18 0 false false true false" }
+ };
+
+ static const KeyEventTestData kTestAltKeySuppress = {
+ app::VKEY_MENU, false, false, false, false,
+ true, false, false, false, 2,
+ { "D 18 0 false false true false",
+ "U 18 0 false false true false" }
+ };
+
+ static const KeyEventTestData kTestCtrlAltKey = {
+ app::VKEY_MENU, true, false, false, false,
+ false, false, false, false, 4,
+ { "D 17 0 true false false false",
+ "D 18 0 true false true false",
+ "U 18 0 true false true false",
+ "U 17 0 true false false false" }
+ };
+
+ ASSERT_TRUE(test_server()->Start());
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ GURL url = test_server()->GetURL(kTestingPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ int tab_index = browser()->selected_index();
+ // Press and release Alt key to focus wrench menu button.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKey));
+ EXPECT_TRUE(IsViewFocused(VIEW_ID_APP_MENU));
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ // Alt key can be suppressed.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKeySuppress));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ // Ctrl+Alt should have no effect.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlAltKey));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+}
+#endif
+
+} // namespace
diff --git a/chrome/browser/browser_list.cc b/chrome/browser/browser_list.cc
index ed0991a..31e09cc 100644
--- a/chrome/browser/browser_list.cc
+++ b/chrome/browser/browser_list.cc
@@ -201,7 +201,10 @@ void BrowserList::RemoveBrowser(Browser* browser) {
(browser_shutdown::IsTryingToQuit() ||
g_browser_process->IsShuttingDown())) {
// Last browser has just closed, and this is a user-initiated quit or there
- // is no module keeping the app alive, so send out our notification.
+ // is no module keeping the app alive, so send out our notification. No need
+ // to call ProfileManager::ShutdownSessionServices() as part of the
+ // shutdown, because Browser::WindowClosing() already makes sure that the
+ // SessionService is created and notified.
NotificationService::current()->Notify(NotificationType::APP_TERMINATING,
NotificationService::AllSources(),
NotificationService::NoDetails());
@@ -220,7 +223,15 @@ void BrowserList::RemoveObserver(BrowserList::Observer* observer) {
}
// static
-void BrowserList::CloseAllBrowsers(bool use_post) {
+void BrowserList::CloseAllBrowsers() {
+ bool session_ending =
+ browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
+ bool use_post = !session_ending;
+ bool force_exit = false;
+#if defined(USE_X11)
+ if (session_ending)
+ force_exit = true;
+#endif
// Tell everyone that we are shutting down.
browser_shutdown::SetTryingToQuit(true);
@@ -230,7 +241,7 @@ void BrowserList::CloseAllBrowsers(bool use_post) {
// 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 (browsers_.empty()) {
+ if (force_exit || browsers_.empty()) {
NotificationService::current()->Notify(NotificationType::APP_TERMINATING,
NotificationService::AllSources(),
NotificationService::NoDetails());
@@ -273,10 +284,10 @@ void BrowserList::CloseAllBrowsersAndExit() {
#if !defined(OS_MACOSX)
// On most platforms, closing all windows causes the application to exit.
- CloseAllBrowsers(true);
+ CloseAllBrowsers();
#else
// On the Mac, the application continues to run once all windows are closed.
- // Terminate will result in a CloseAllBrowsers(true) call, and once (and if)
+ // Terminate will result in a CloseAllBrowsers() call, and once (and if)
// that is done, will cause the application to exit cleanly.
chrome_browser_application_mac::Terminate();
#endif
@@ -300,8 +311,7 @@ void BrowserList::WindowsSessionEnding() {
// Write important data first.
g_browser_process->EndSession();
- // Close all the browsers.
- BrowserList::CloseAllBrowsers(false);
+ BrowserList::CloseAllBrowsers();
// Send out notification. This is used during testing so that the test harness
// can properly shutdown before we exit.
@@ -317,6 +327,8 @@ void BrowserList::WindowsSessionEnding() {
// At this point the message loop is still running yet we've shut everything
// down. If any messages are processed we'll likely crash. Exit now.
ExitProcess(ResultCodes::NORMAL_EXIT);
+#elif defined(OS_LINUX)
+ _exit(ResultCodes::NORMAL_EXIT);
#else
NOTIMPLEMENTED();
#endif
@@ -355,7 +367,7 @@ void BrowserList::EndKeepAlive() {
// (MessageLoop::current() == null).
if (browsers_.empty() && !browser_shutdown::IsTryingToQuit() &&
MessageLoop::current())
- CloseAllBrowsers(true);
+ CloseAllBrowsers();
}
}
diff --git a/chrome/browser/browser_list.h b/chrome/browser/browser_list.h
index 9c477c0..dcde7fb 100644
--- a/chrome/browser/browser_list.h
+++ b/chrome/browser/browser_list.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BROWSER_LIST_H_
#define CHROME_BROWSER_BROWSER_LIST_H_
+#pragma once
#include <vector>
@@ -95,18 +96,17 @@ class BrowserList {
// 2. An update exe is present in the install folder.
static bool CanRestartForUpdate();
- // Closes all browsers. If use_post is true the windows are closed by way of
- // posting a WM_CLOSE message, otherwise the windows are closed directly. In
- // almost all cases you'll want to use true, the one exception is ending
- // the session. use_post should only be false when invoked from end session.
- static void CloseAllBrowsers(bool use_post);
-
// 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
// additionally exit the application.
static void CloseAllBrowsersAndExit();
+ // Closes all browsers. If the session is ending the windows are closed
+ // directly. Otherwise the windows are closed by way of posting a WM_CLOSE
+ // message.
+ static void CloseAllBrowsers();
+
// Begins shutdown of the application when the Windows session is ending.
static void WindowsSessionEnding();
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 2e39277..d711778 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -12,24 +12,30 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/system_monitor.h"
+#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/field_trial.h"
+#include "base/file_path.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/scoped_nsautorelease_pool.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/time.h"
+#include "base/trace_event.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_main_win.h"
#include "chrome/browser/browser_init.h"
-#include "chrome/browser/browser_prefs.h"
+#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/browser/browser_shutdown.h"
@@ -37,36 +43,44 @@
#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/first_run.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/jankometer.h"
+#include "chrome/browser/labs.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/metrics/metrics_service.h"
+#include "chrome/browser/net/blob_url_request_job_factory.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/metadata_url_request.h"
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
#include "chrome/browser/net/websocket_experiment/websocket_experiment_runner.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/pref_value_store.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/browser/process_singleton.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.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"
+#include "chrome/browser/service/service_process_control.h"
+#include "chrome/browser/service/service_process_control_manager.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/translate/translate_manager.h"
#include "chrome/common/child_process.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/env_vars.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/logging_chrome.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/net/net_resource_provider.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/result_codes.h"
+#include "chrome/common/service_process_type.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/master_preferences.h"
#include "grit/app_locale_settings.h"
@@ -76,9 +90,9 @@
#include "net/base/net_module.h"
#include "net/base/network_change_notifier.h"
#include "net/http/http_network_layer.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_network_transaction.h"
+#include "net/http/http_stream_factory.h"
#include "net/socket/client_socket_pool_base.h"
+#include "net/socket/client_socket_pool_manager.h"
#include "net/spdy/spdy_session_pool.h"
#if defined(USE_LINUX_BREAKPAD)
@@ -87,6 +101,7 @@
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "chrome/browser/browser_main_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#endif
@@ -106,23 +121,19 @@
#include "app/l10n_util_win.h"
#include "app/win_util.h"
-#include "base/registry.h"
-#include "base/win_util.h"
-#include "chrome/browser/browser.h"
#include "chrome/browser/browser_trial.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/rlz/rlz.h"
#include "chrome/browser/views/user_data_dir_dialog.h"
-#include "chrome/common/env_vars.h"
#include "chrome/common/sandbox_policy.h"
#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"
-#include "net/socket/ssl_client_socket_nss_factory.h"
#include "printing/printed_document.h"
#include "sandbox/src/sandbox.h"
#endif // defined(OS_WIN)
@@ -130,11 +141,6 @@
#if defined(OS_MACOSX)
#include <Security/Security.h>
#include "chrome/browser/cocoa/install_from_dmg.h"
-#include "net/socket/ssl_client_socket_mac_factory.h"
-#endif
-
-#if defined(OS_MACOSX) || defined(OS_WIN)
-#include "base/nss_util.h"
#endif
#if defined(TOOLKIT_VIEWS)
@@ -147,6 +153,8 @@
#include "chrome/browser/chromeos/cros/screen_lock_library.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/external_metrics.h"
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/views/browser_dialogs.h"
@@ -159,15 +167,30 @@ BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters)
parsed_command_line_(parameters.command_line_) {
}
-// BrowserMainParts: EarlyInitialization() and related -------------------------
+BrowserMainParts::~BrowserMainParts() {
+}
+
+// BrowserMainParts: |EarlyInitialization()| and related -----------------------
void BrowserMainParts::EarlyInitialization() {
PreEarlyInitialization();
+ // Note: make sure to call ConnectionFieldTrial() before
+ // ProxyConnectionsFieldTrial().
ConnectionFieldTrial();
SocketTimeoutFieldTrial();
+ ProxyConnectionsFieldTrial();
SpdyFieldTrial();
- InitializeSSL(); // TODO(viettrungluu): move to platform-specific method(s)
+ PrefetchFieldTrial();
+ ConnectBackupJobsFieldTrial();
+ InitializeSSL();
+
+ if (parsed_command_line().HasSwitch(switches::kEnableDNSSECCerts))
+ net::SSLConfigService::EnableDNSSEC();
+ if (parsed_command_line().HasSwitch(switches::kDisableSSLFalseStart))
+ net::SSLConfigService::DisableFalseStart();
+ if (parsed_command_line().HasSwitch(switches::kAllowSSLMITMProxies))
+ net::SSLConfigService::AllowMITMProxies();
PostEarlyInitialization();
}
@@ -179,30 +202,39 @@ void BrowserMainParts::EarlyInitialization() {
// on browsing. Too large a value might cause us to run into SYN flood detection
// mechanisms.
void BrowserMainParts::ConnectionFieldTrial() {
- const FieldTrial::Probability kConnDivisor = 100;
- const FieldTrial::Probability kConn16 = 10; // 10% probability
- const FieldTrial::Probability kRemainingConn = 30; // 30% probability
-
- scoped_refptr<FieldTrial> conn_trial =
- new FieldTrial("ConnCountImpact", kConnDivisor);
-
- const int conn_16 = conn_trial->AppendGroup("_conn_count_16", kConn16);
- const int conn_4 = conn_trial->AppendGroup("_conn_count_4", kRemainingConn);
- const int conn_8 = conn_trial->AppendGroup("_conn_count_8", kRemainingConn);
- const int conn_6 = conn_trial->AppendGroup("_conn_count_6",
+ const FieldTrial::Probability kConnectDivisor = 100;
+ const FieldTrial::Probability kConnectProbability = 1; // 1% probability
+
+ scoped_refptr<FieldTrial> connect_trial =
+ new FieldTrial("ConnCountImpact", kConnectDivisor);
+
+ const int connect_5 = connect_trial->AppendGroup("conn_count_5",
+ kConnectProbability);
+ const int connect_7 = connect_trial->AppendGroup("conn_count_7",
+ kConnectProbability);
+ const int connect_8 = connect_trial->AppendGroup("conn_count_8",
+ kConnectProbability);
+ const int connect_9 = connect_trial->AppendGroup("conn_count_9",
+ kConnectProbability);
+ // This (6) is the current default value. Having this group declared here
+ // makes it straightforward to modify |kConnectProbability| such that the same
+ // probability value will be assigned to all the other groups, while
+ // preserving the remainder of the of probability space to the default value.
+ const int connect_6 = connect_trial->AppendGroup("conn_count_6",
FieldTrial::kAllRemainingProbability);
- const int conn_trial_grp = conn_trial->group();
-
- if (conn_trial_grp == conn_4) {
- net::HttpNetworkSession::set_max_sockets_per_group(4);
- } else if (conn_trial_grp == conn_6) {
- // This (6) is the current default value.
- net::HttpNetworkSession::set_max_sockets_per_group(6);
- } else if (conn_trial_grp == conn_8) {
- net::HttpNetworkSession::set_max_sockets_per_group(8);
- } else if (conn_trial_grp == conn_16) {
- net::HttpNetworkSession::set_max_sockets_per_group(16);
+ const int connect_trial_group = connect_trial->group();
+
+ if (connect_trial_group == connect_5) {
+ net::ClientSocketPoolManager::set_max_sockets_per_group(5);
+ } else if (connect_trial_group == connect_6) {
+ net::ClientSocketPoolManager::set_max_sockets_per_group(6);
+ } else if (connect_trial_group == connect_7) {
+ net::ClientSocketPoolManager::set_max_sockets_per_group(7);
+ } else if (connect_trial_group == connect_8) {
+ net::ClientSocketPoolManager::set_max_sockets_per_group(8);
+ } else if (connect_trial_group == connect_9) {
+ net::ClientSocketPoolManager::set_max_sockets_per_group(9);
} else {
NOTREACHED();
}
@@ -214,38 +246,80 @@ void BrowserMainParts::ConnectionFieldTrial() {
// result in more ERR_CONNECT_RESETs, requiring one RTT to receive the RST
// packet and possibly another RTT to re-establish the connection.
void BrowserMainParts::SocketTimeoutFieldTrial() {
- const FieldTrial::Probability kIdleSktToDivisor = 100; // Idle socket timeout
- const FieldTrial::Probability kSktToProb = 25; // 25% probability
+ const FieldTrial::Probability kIdleSocketTimeoutDivisor = 100;
+ // 1% probability for all experimental settings.
+ const FieldTrial::Probability kSocketTimeoutProbability = 1;
scoped_refptr<FieldTrial> socket_timeout_trial =
- new FieldTrial("IdleSktToImpact", kIdleSktToDivisor);
+ new FieldTrial("IdleSktToImpact", kIdleSocketTimeoutDivisor);
const int socket_timeout_5 =
- socket_timeout_trial->AppendGroup("_idle_timeout_5", kSktToProb);
+ socket_timeout_trial->AppendGroup("idle_timeout_5",
+ kSocketTimeoutProbability);
const int socket_timeout_10 =
- socket_timeout_trial->AppendGroup("_idle_timeout_10", kSktToProb);
+ socket_timeout_trial->AppendGroup("idle_timeout_10",
+ kSocketTimeoutProbability);
const int socket_timeout_20 =
- socket_timeout_trial->AppendGroup("_idle_timeout_20", kSktToProb);
+ socket_timeout_trial->AppendGroup("idle_timeout_20",
+ kSocketTimeoutProbability);
const int socket_timeout_60 =
- socket_timeout_trial->AppendGroup("_idle_timeout_60",
+ socket_timeout_trial->AppendGroup("idle_timeout_60",
FieldTrial::kAllRemainingProbability);
- const int idle_to_trial_grp = socket_timeout_trial->group();
+ const int idle_to_trial_group = socket_timeout_trial->group();
- if (idle_to_trial_grp == socket_timeout_5) {
+ if (idle_to_trial_group == socket_timeout_5) {
net::ClientSocketPool::set_unused_idle_socket_timeout(5);
- } else if (idle_to_trial_grp == socket_timeout_10) {
- // This (10 seconds) is the current default value.
+ } else if (idle_to_trial_group == socket_timeout_10) {
net::ClientSocketPool::set_unused_idle_socket_timeout(10);
- } else if (idle_to_trial_grp == socket_timeout_20) {
+ } else if (idle_to_trial_group == socket_timeout_20) {
net::ClientSocketPool::set_unused_idle_socket_timeout(20);
- } else if (idle_to_trial_grp == socket_timeout_60) {
+ } else if (idle_to_trial_group == socket_timeout_60) {
net::ClientSocketPool::set_unused_idle_socket_timeout(60);
} else {
NOTREACHED();
}
}
+void BrowserMainParts::ProxyConnectionsFieldTrial() {
+ const FieldTrial::Probability kProxyConnectionsDivisor = 100;
+ // 25% probability
+ const FieldTrial::Probability kProxyConnectionProbability = 1;
+
+ scoped_refptr<FieldTrial> proxy_connection_trial =
+ new FieldTrial("ProxyConnectionImpact", kProxyConnectionsDivisor);
+
+ // The number of max sockets per group cannot be greater than the max number
+ // of sockets per proxy server. We tried using 8, and it can easily
+ // lead to total browser stalls.
+ const int proxy_connections_16 =
+ proxy_connection_trial->AppendGroup("proxy_connections_16",
+ kProxyConnectionProbability);
+ const int proxy_connections_64 =
+ proxy_connection_trial->AppendGroup("proxy_connections_64",
+ kProxyConnectionProbability);
+
+ // This (32 connections per proxy server) is the current default value.
+ // Declaring it here allows us to easily re-assign the probability space while
+ // maintaining that the default group always has the remainder of the "share",
+ // which allows for cleaner and quicker changes down the line if needed.
+ const int proxy_connections_32 =
+ proxy_connection_trial->AppendGroup("proxy_connections_32",
+ FieldTrial::kAllRemainingProbability);
+
+ const int proxy_connections_trial_group = proxy_connection_trial->group();
+
+ if (proxy_connections_trial_group == proxy_connections_16) {
+ net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(16);
+ } else if (proxy_connections_trial_group == proxy_connections_32) {
+ net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(32);
+ } else if (proxy_connections_trial_group == proxy_connections_64) {
+ net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(64);
+ } else {
+ NOTREACHED();
+ }
+}
+
// When --use-spdy not set, users will be in A/B test for spdy.
// group A (npn_with_spdy): this means npn and spdy are enabled. In case server
// supports spdy, browser will use spdy.
@@ -261,25 +335,14 @@ void BrowserMainParts::SpdyFieldTrial() {
net::HttpNetworkLayer::EnableSpdy(spdy_mode);
} else {
const FieldTrial::Probability kSpdyDivisor = 1000;
- // To enable 100% npn_with_spdy, set npnhttp_probability = 0 and set
- // npnspdy_probability = FieldTrial::kAllRemainingProbability.
- // To collect stats, make sure that FieldTrial are distributed among
- // all the three groups:
- // npn_with_spdy : 50%, npn_with_http : 25%, default (no npn, no spdy): 25%.
- // a. npn_with_spdy and default: these are used to collect stats for
- // alternate protocol with spdy vs. no alternate protocol case.
- // b. npn_with_spdy and npn_with_http: these are used to collect stats for
- // https vs. https over spdy case.
- FieldTrial::Probability npnhttp_probability = 250;
- FieldTrial::Probability npnspdy_probability = 500;
+ FieldTrial::Probability npnhttp_probability = 10; // 1% to preclude SPDY.
scoped_refptr<FieldTrial> trial =
new FieldTrial("SpdyImpact", kSpdyDivisor);
// npn with only http support, no spdy.
- int npn_http_grp =
- trial->AppendGroup("_npn_with_http", npnhttp_probability);
+ int npn_http_grp = trial->AppendGroup("npn_with_http", npnhttp_probability);
// npn with spdy support.
- int npn_spdy_grp =
- trial->AppendGroup("_npn_with_spdy", npnspdy_probability);
+ int npn_spdy_grp = trial->AppendGroup("npn_with_spdy",
+ FieldTrial::kAllRemainingProbability);
int trial_grp = trial->group();
if (trial_grp == npn_http_grp) {
is_spdy_trial = true;
@@ -293,29 +356,81 @@ void BrowserMainParts::SpdyFieldTrial() {
}
}
-// TODO(viettrungluu): move to platform-specific methods
-void BrowserMainParts::InitializeSSL() {
- // Use NSS for SSL by default.
-#if defined(OS_MACOSX)
- // The default client socket factory uses NSS for SSL by default on Mac.
- if (parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
- net::ClientSocketFactory::SetSSLClientSocketFactory(
- net::SSLClientSocketMacFactory);
+// If neither --enable-content-prefetch or --disable-content-prefetch
+// is set, users will not be in an A/B test for prefetching.
+void BrowserMainParts::PrefetchFieldTrial() {
+ if (parsed_command_line().HasSwitch(switches::kEnableContentPrefetch))
+ ResourceDispatcherHost::set_is_prefetch_enabled(true);
+ else if (parsed_command_line().HasSwitch(switches::kDisableContentPrefetch)) {
+ ResourceDispatcherHost::set_is_prefetch_enabled(false);
} else {
- // We want to be sure to init NSPR on the main thread.
- base::EnsureNSPRInit();
+ const FieldTrial::Probability kPrefetchDivisor = 100;
+ const FieldTrial::Probability no_prefetch_probability = 50;
+ scoped_refptr<FieldTrial> trial =
+ new FieldTrial("Prefetch", kPrefetchDivisor);
+ trial->AppendGroup("ContentPrefetchDisabled", no_prefetch_probability);
+ const int yes_prefetch_grp =
+ trial->AppendGroup("ContentPrefetchEnabled",
+ FieldTrial::kAllRemainingProbability);
+ const int trial_grp = trial->group();
+ ResourceDispatcherHost::set_is_prefetch_enabled(
+ trial_grp == yes_prefetch_grp);
}
-#elif defined(OS_WIN)
- // Because of a build system issue (http://crbug.com/43461), the default
- // client socket factory uses SChannel (the system SSL library) for SSL by
- // default on Windows.
- if (!parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
- net::ClientSocketFactory::SetSSLClientSocketFactory(
- net::SSLClientSocketNSSFactory);
- // We want to be sure to init NSPR on the main thread.
- base::EnsureNSPRInit();
+}
+
+// If neither --enable-connect-backup-jobs or --disable-connect-backup-jobs is
+// specified, run an A/B test for automatically establishing backup TCP
+// connections when a certain timeout value is exceeded.
+void BrowserMainParts::ConnectBackupJobsFieldTrial() {
+ if (parsed_command_line().HasSwitch(switches::kEnableConnectBackupJobs)) {
+ net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
+ true);
+ } else if (parsed_command_line().HasSwitch(
+ switches::kDisableConnectBackupJobs)) {
+ net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
+ false);
+ } else {
+ const FieldTrial::Probability kConnectBackupJobsDivisor = 100;
+ // 50% probability.
+ const FieldTrial::Probability kConnectBackupJobsProbability = 1; // 1%.
+ scoped_refptr<FieldTrial> trial = new FieldTrial("ConnnectBackupJobs",
+ kConnectBackupJobsDivisor);
+ trial->AppendGroup("ConnectBackupJobsDisabled",
+ kConnectBackupJobsProbability);
+ const int connect_backup_jobs_enabled =
+ trial->AppendGroup("ConnectBackupJobsEnabled",
+ FieldTrial::kAllRemainingProbability);
+ const int trial_group = trial->group();
+ net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
+ trial_group == connect_backup_jobs_enabled);
}
-#endif
+}
+
+// BrowserMainParts: |MainMessageLoopStart()| and related ----------------------
+
+void BrowserMainParts::MainMessageLoopStart() {
+ PreMainMessageLoopStart();
+
+ main_message_loop_.reset(new MessageLoop(MessageLoop::TYPE_UI));
+
+ // TODO(viettrungluu): should these really go before setting the thread name?
+ system_monitor_.reset(new SystemMonitor);
+ hi_res_timer_manager_.reset(new HighResolutionTimerManager);
+ network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
+
+ InitializeMainThread();
+
+ PostMainMessageLoopStart();
+}
+
+void BrowserMainParts::InitializeMainThread() {
+ const char* kThreadName = "CrBrowserMain";
+ PlatformThread::SetName(kThreadName);
+ main_message_loop().set_thread_name(kThreadName);
+
+ // Register the main thread by instantiating it, but don't call any methods.
+ main_thread_.reset(new ChromeThread(ChromeThread::UI,
+ MessageLoop::current()));
}
// -----------------------------------------------------------------------------
@@ -347,6 +462,8 @@ void HandleTestParameters(const CommandLine& command_line) {
}
void RunUIMessageLoop(BrowserProcess* browser_process) {
+ TRACE_EVENT_BEGIN("BrowserMain:MESSAGE_LOOP", 0, "");
+
#if defined(TOOLKIT_VIEWS)
views::AcceleratorHandler accelerator_handler;
MessageLoopForUI::current()->Run(&accelerator_handler);
@@ -355,6 +472,8 @@ void RunUIMessageLoop(BrowserProcess* browser_process) {
#elif defined(OS_POSIX)
MessageLoopForUI::current()->Run();
#endif
+
+ TRACE_EVENT_END("BrowserMain:MESSAGE_LOOP", 0, "");
}
void AddFirstRunNewTabs(BrowserInit* browser_init,
@@ -386,27 +505,18 @@ void InitializeNetworkOptions(const CommandLine& parsed_command_line) {
net::CookieMonster::EnableFileScheme();
}
- if (parsed_command_line.HasSwitch(switches::kFixedHttpPort)) {
- net::HttpNetworkSession::set_fixed_http_port(StringToInt(
- parsed_command_line.GetSwitchValueASCII(switches::kFixedHttpPort)));
- }
-
- if (parsed_command_line.HasSwitch(switches::kFixedHttpsPort)) {
- net::HttpNetworkSession::set_fixed_https_port(StringToInt(
- parsed_command_line.GetSwitchValueASCII(switches::kFixedHttpsPort)));
- }
-
if (parsed_command_line.HasSwitch(switches::kIgnoreCertificateErrors))
- net::HttpNetworkTransaction::IgnoreCertificateErrors(true);
+ net::HttpStreamFactory::set_ignore_certificate_errors(true);
if (parsed_command_line.HasSwitch(switches::kHostRules))
- net::HttpNetworkTransaction::SetHostMappingRules(
+ net::HttpStreamFactory::SetHostMappingRules(
parsed_command_line.GetSwitchValueASCII(switches::kHostRules));
if (parsed_command_line.HasSwitch(switches::kMaxSpdySessionsPerDomain)) {
- int value = StringToInt(
- parsed_command_line.GetSwitchValueASCII(
- switches::kMaxSpdySessionsPerDomain));
+ int value;
+ base::StringToInt(parsed_command_line.GetSwitchValueASCII(
+ switches::kMaxSpdySessionsPerDomain),
+ &value);
net::SpdySessionPool::set_max_sessions_per_domain(value);
}
}
@@ -468,7 +578,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));
+ PrefService::CreatePrefService(parent_profile, NULL));
parent_local_state->RegisterStringPref(prefs::kApplicationLocale,
std::string());
// Right now, we only inherit the locale setting from the parent profile.
@@ -567,8 +677,8 @@ Profile* CreateProfile(const MainFunctionParams& parameters,
// TODO(tc): It would be nice to remove the flag we don't want, but that
// sounds risky if we parse differently than CommandLineToArgvW.
CommandLine new_command_line = parameters.command_line_;
- new_command_line.AppendSwitchWithValue(switches::kUserDataDir,
- new_user_data_dir.ToWStringHack());
+ new_command_line.AppendSwitchPath(switches::kUserDataDir,
+ new_user_data_dir);
base::LaunchApp(new_command_line, false, false, NULL);
}
#else
@@ -589,9 +699,27 @@ void AdjustUIFont(LOGFONT* logfont) {
}
int GetMinimumFontSize() {
- return StringToInt(l10n_util::GetString(IDS_MINIMUM_UI_FONT_SIZE).c_str());
+ int min_font_size;
+ base::StringToInt(l10n_util::GetStringUTF16(IDS_MINIMUM_UI_FONT_SIZE),
+ &min_font_size);
+ return min_font_size;
}
+#elif defined(OS_CHROMEOS)
+// Changes the UI font if non-default font name is specified in
+// IDS_UI_FONT_FAMILY_CROS. This is necessary as the default font
+// specified in /etc/gtk-2.0/gtrkc may not work well for some languages
+// For instance, ChromeDroidSans does not work well for Japanese users,
+// since Chinese glyphs are used for Kanji characters.
+void MaybeChangeUIFont() {
+ const std::string font_name =
+ l10n_util::GetStringUTF8(IDS_UI_FONT_FAMILY_CROS);
+ // The font name should not be empty here, but just in case.
+ if (font_name == "default" || font_name.empty()) {
+ return;
+ }
+ gtk_util::SetGtkFont(font_name);
+}
#endif
#if defined(TOOLKIT_GTK)
@@ -608,8 +736,8 @@ void InitializeToolkit() {
views::ViewsDelegate::views_delegate = new ChromeViewsDelegate;
#if defined(OS_WIN)
- gfx::Font::adjust_font_callback = &AdjustUIFont;
- gfx::Font::get_minimum_font_size_callback = &GetMinimumFontSize;
+ gfx::PlatformFontWin::adjust_font_callback = &AdjustUIFont;
+ gfx::PlatformFontWin::get_minimum_font_size_callback = &GetMinimumFontSize;
// Init common control sex.
INITCOMMONCONTROLSEX config;
@@ -625,6 +753,34 @@ void InitializeToolkit() {
#if defined(OS_CHROMEOS)
+// Class is used to login using passed username and password.
+// The instance will be deleted upon success or failure.
+class StubLogin : public chromeos::LoginStatusConsumer {
+ public:
+ explicit StubLogin(std::string username, std::string password) {
+ authenticator_ = chromeos::LoginUtils::Get()->CreateAuthenticator(this);
+ authenticator_.get()->AuthenticateToLogin(
+ g_browser_process->profile_manager()->GetDefaultProfile(),
+ username,
+ password,
+ std::string(),
+ std::string());
+ }
+
+ void OnLoginFailure(const chromeos::LoginFailure& error) {
+ LOG(ERROR) << "Login Failure: " << error.GetErrorString();
+ delete this;
+ }
+
+ void OnLoginSuccess(const std::string& username,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ chromeos::LoginUtils::Get()->CompleteLogin(username, credentials);
+ delete this;
+ }
+
+ scoped_refptr<chromeos::Authenticator> authenticator_;
+};
+
void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) {
if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
std::string first_screen =
@@ -638,49 +794,28 @@ void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) {
if (size_arg.size()) {
std::vector<std::string> dimensions;
SplitString(size_arg, ',', &dimensions);
- if (dimensions.size() == 2)
- size.SetSize(StringToInt(dimensions[0]), StringToInt(dimensions[1]));
+ if (dimensions.size() == 2) {
+ int width, height;
+ if (base::StringToInt(dimensions[0], &width) &&
+ base::StringToInt(dimensions[1], &height))
+ size.SetSize(width, height);
+ }
}
browser::ShowLoginWizard(first_screen, size);
+ } else if (parsed_command_line.HasSwitch(switches::kLoginUser) &&
+ parsed_command_line.HasSwitch(switches::kLoginPassword)) {
+ new StubLogin(
+ parsed_command_line.GetSwitchValueASCII(switches::kLoginUser),
+ parsed_command_line.GetSwitchValueASCII(switches::kLoginPassword));
}
}
-bool OptionallyApplyServicesCustomizationFromCommandLine(
- const CommandLine& parsed_command_line,
- BrowserInit* browser_init) {
- // For Chrome OS, we may need to fetch OEM partner's services customization
- // manifest and apply the customizations. This happens on the very first run
- // or if startup manifest is passed on the command line.
- scoped_ptr<chromeos::ServicesCustomizationDocument> customization;
- customization.reset(new chromeos::ServicesCustomizationDocument());
- bool manifest_loaded = false;
- if (parsed_command_line.HasSwitch(switches::kServicesManifest)) {
- // Load manifest from file specified by command line switch.
- FilePath manifest_path =
- parsed_command_line.GetSwitchValuePath(switches::kServicesManifest);
- manifest_loaded = customization->LoadManifestFromFile(manifest_path);
- DCHECK(manifest_loaded) << manifest_path.value();
- }
- // If manifest was loaded successfully, apply the customizations.
- if (manifest_loaded) {
- browser_init->ApplyServicesCustomization(customization.get());
- }
- return manifest_loaded;
-}
-
#else
void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line) {
// Dummy empty function for non-ChromeOS builds to avoid extra ifdefs below.
}
-bool OptionallyApplyServicesCustomizationFromCommandLine(
- const CommandLine& parsed_command_line,
- BrowserInit* browser_init) {
- // Dummy empty function for non-ChromeOS builds to avoid extra ifdefs below.
- return false;
-}
-
#endif // defined(OS_CHROMEOS)
#if defined(OS_MACOSX)
@@ -692,6 +827,12 @@ OSStatus KeychainCallback(SecKeychainEvent keychain_event,
} // namespace
+#if defined(OS_CHROMEOS)
+// Allows authenticator to be invoked without adding refcounting. The instances
+// will delete themselves upon completion.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(StubLogin);
+#endif
+
#if defined(OS_WIN)
#define DLLEXPORT __declspec(dllexport)
@@ -701,49 +842,49 @@ DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded();
}
DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
+ // Need an instance of AtExitManager to handle singleton creations and
+ // deletions. We need this new instance because, the old instance created
+ // in ChromeMain() got destructed when the function returned.
+ base::AtExitManager exit_manager;
Upgrade::RelaunchChromeBrowserWithNewCommandLineIfNeeded();
}
#endif
// Main routine for running as the Browser process.
int BrowserMain(const MainFunctionParams& parameters) {
+ TRACE_EVENT_BEGIN("BrowserMain", 0, "");
scoped_ptr<BrowserMainParts>
parts(BrowserMainParts::CreateBrowserMainParts(parameters));
parts->EarlyInitialization();
+ parts->MainMessageLoopStart();
- // TODO(viettrungluu): put the remainder into BrowserMainParts
- const CommandLine& parsed_command_line = parameters.command_line_;
- base::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_;
-
- // WARNING: If we get a WM_ENDSESSION objects created on the stack here
+ // WARNING: If we get a WM_ENDSESSION, objects created on the stack here
// are NOT deleted. If you need something to run during WM_ENDSESSION add it
// to browser_shutdown::Shutdown or BrowserProcess::EndSession.
- // TODO(beng, brettw): someday, break this out into sub functions with well
- // defined roles (e.g. pre/post-profile startup, etc).
-
- // Do platform-specific things (such as finishing initializing Cocoa)
- // prior to instantiating the message loop. This could be turned into a
- // broadcast notification.
- WillInitializeMainMessageLoop(parameters);
-
- MessageLoop main_message_loop(MessageLoop::TYPE_UI);
-
- SystemMonitor system_monitor;
- HighResolutionTimerManager hi_res_timer_manager;
- scoped_ptr<net::NetworkChangeNotifier> network_change_notifier(
- net::NetworkChangeNotifier::Create());
-
- const char* kThreadName = "CrBrowserMain";
- PlatformThread::SetName(kThreadName);
- main_message_loop.set_thread_name(kThreadName);
+ // !!!!!!!!!! READ ME !!!!!!!!!!
+ // I (viettrungluu) am in the process of refactoring |BrowserMain()|. If you
+ // need to add something above this comment, read the documentation in
+ // browser_main.h. If you need to add something below, please do the
+ // following:
+ // - Figure out where you should add your code. Do NOT just pick a random
+ // location "which works".
+ // - Document the dependencies apart from compile-time-checkable ones. What
+ // must happen before your new code is executed? Does your new code need to
+ // run before something else? Are there performance reasons for executing
+ // your code at that point?
+ // - If you need to create a (persistent) object, heap allocate it and keep a
+ // |scoped_ptr| to it rather than allocating it on the stack. Otherwise
+ // I'll have to convert your code when I refactor.
+ // - Unless your new code is just a couple of lines, factor it out into a
+ // function with a well-defined purpose. Do NOT just add it inline in
+ // |BrowserMain()|.
+ // Thanks!
- // Register the main thread by instantiating it, but don't call any methods.
- ChromeThread main_thread(ChromeThread::UI, MessageLoop::current());
-
- // TODO(viettrungluu): temporary while I refactor BrowserMain()
- parts->TemporaryPosix_1();
+ // TODO(viettrungluu): put the remainder into BrowserMainParts
+ const CommandLine& parsed_command_line = parameters.command_line_;
+ base::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_;
FilePath user_data_dir;
#if defined(OS_WIN)
@@ -783,23 +924,39 @@ int BrowserMain(const MainFunctionParams& parameters) {
// tabs.
g_browser_process->tab_closeable_state_watcher();
-#if defined(USE_LINUX_BREAKPAD)
- // Needs to be called after we have chrome::DIR_USER_DATA and
- // g_browser_process.
- g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
- new GetLinuxDistroTask());
- InitCrashReporter();
-#endif
-
// The broker service initialization needs to run early because it will
// initialize the sandbox broker, which requires the process to swap its
// window station. During this time all the UI will be broken. This has to
// run before threads and windows are created.
InitializeBrokerServices(parameters, parsed_command_line);
+ // Initialize histogram statistics gathering system.
+ StatisticsRecorder statistics;
+
PrefService* local_state = InitializeLocalState(parsed_command_line,
is_first_run);
+#if defined(USE_LINUX_BREAKPAD)
+ // Needs to be called after we have chrome::DIR_USER_DATA and
+ // g_browser_process.
+ g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
+ new GetLinuxDistroTask());
+
+ // Check whether we should initialize the crash reporter. It may be disabled
+ // through configuration policy or user preference. The kHeadless environment
+ // variable overrides the decision, but only if the crash service is under
+ // control of the user.
+ const PrefService::Preference* metrics_reporting_enabled =
+ local_state->FindPreference(prefs::kMetricsReportingEnabled);
+ CHECK(metrics_reporting_enabled);
+ bool breakpad_enabled =
+ local_state->GetBoolean(prefs::kMetricsReportingEnabled);
+ if (!breakpad_enabled && metrics_reporting_enabled->IsUserModifiable())
+ breakpad_enabled = getenv(env_vars::kHeadless) != NULL;
+ if (breakpad_enabled)
+ InitCrashReporter();
+#endif
+
InitializeToolkit(); // Must happen before we try to display any UI.
// If we're running tests (ui_task is non-null), then the ResourceBundle
@@ -807,16 +964,16 @@ int BrowserMain(const MainFunctionParams& parameters) {
if (parameters.ui_task) {
g_browser_process->SetApplicationLocale("en-US");
} else {
- // Mac starts it earlier in WillInitializeMainMessageLoop (because
- // it is needed when loading the MainMenu.nib and the language doesn't
- // depend on anything since it comes from Cocoa.
+ // Mac starts it earlier in |PreMainMessageLoopStart()| (because it is
+ // needed when loading the MainMenu.nib and the language doesn't depend on
+ // anything since it comes from Cocoa.
#if defined(OS_MACOSX)
g_browser_process->SetApplicationLocale(l10n_util::GetLocaleOverride());
#else
// On a POSIX OS other than ChromeOS, the parameter that is passed to the
// method InitSharedInstance is ignored.
std::string app_locale = ResourceBundle::InitSharedInstance(
- ASCIIToWide(local_state->GetString(prefs::kApplicationLocale)));
+ local_state->GetString(prefs::kApplicationLocale));
g_browser_process->SetApplicationLocale(app_locale);
FilePath resources_pack_path;
@@ -825,7 +982,10 @@ int BrowserMain(const MainFunctionParams& parameters) {
#endif // !defined(OS_MACOSX)
}
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
+ // gdk_pixbuf_loader_write always fails on chromeos device.
+ // Disabling for chromeos as well because chromeos is not using them.
+ // http://crosbug.com/4996 .
gtk_util::SetDefaultWindowIcon();
#endif
@@ -833,8 +993,9 @@ int BrowserMain(const MainFunctionParams& parameters) {
parsed_command_line.GetSwitchValueASCII(switches::kTryChromeAgain);
if (!try_chrome.empty()) {
#if defined(OS_WIN)
- Upgrade::TryResult answer =
- Upgrade::ShowTryChromeDialog(StringToInt(try_chrome));
+ int try_chrome_int;
+ base::StringToInt(try_chrome, &try_chrome_int);
+ Upgrade::TryResult answer = Upgrade::ShowTryChromeDialog(try_chrome_int);
if (answer == Upgrade::TD_NOT_NOW)
return ResultCodes::NORMAL_EXIT_CANCEL;
if (answer == Upgrade::TD_UNINSTALL_CHROME)
@@ -871,9 +1032,6 @@ int BrowserMain(const MainFunctionParams& parameters) {
InitializeNetworkOptions(parsed_command_line);
- // Initialize histogram statistics gathering system.
- StatisticsRecorder statistics;
-
// Initialize histogram synchronizer system. This is a singleton and is used
// for posting tasks via NewRunnableMethod. Its deleted when it goes out of
// scope. Even though NewRunnableMethod does AddRef and Release, the object
@@ -909,6 +1067,9 @@ int BrowserMain(const MainFunctionParams& parameters) {
#if defined(OS_CHROMEOS)
// Now that the file thread exists we can record our stats.
chromeos::BootTimesLoader::Get()->RecordChromeMainStats();
+ // Change the UI font if necessary. This has to be done after
+ // InitSharedInstance() is called, as it depends on resource data.
+ MaybeChangeUIFont();
#endif
// Record last shutdown time into a histogram.
@@ -979,6 +1140,10 @@ int BrowserMain(const MainFunctionParams& parameters) {
// Profile creation ----------------------------------------------------------
#if defined(OS_CHROMEOS)
+ // Stub out chromeos implementations.
+ if (parsed_command_line.HasSwitch(switches::kStubCros))
+ chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
+
// Initialize the screen locker now so that it can receive
// LOGIN_USER_CHANGED notification from UserManager.
chromeos::ScreenLocker::InitClass();
@@ -987,14 +1152,36 @@ int BrowserMain(const MainFunctionParams& parameters) {
// notification it needs to track the logged in user.
g_browser_process->profile_manager()->GetDefaultProfile();
- if (parsed_command_line.HasSwitch(switches::kLoginUser)) {
+ // There are two use cases for kLoginUser:
+ // 1) if passed in tandem with kLoginPassword, to drive a "StubLogin"
+ // 2) if passed alone, to signal that the indicated user has already
+ // logged in and we should behave accordingly.
+ // This handles case 2.
+ if (parsed_command_line.HasSwitch(switches::kLoginUser) &&
+ !parsed_command_line.HasSwitch(switches::kLoginPassword)) {
std::string username =
parsed_command_line.GetSwitchValueASCII(switches::kLoginUser);
LOG(INFO) << "Relaunching browser for user: " << username;
chromeos::UserManager::Get()->UserLoggedIn(username);
+
+ // Redirect logs.
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ // The default profile will have been changed because the ProfileManager
+ // will process the notification that the UserManager sends out.
+
+ logging::RedirectChromeLogging(
+ user_data_dir.Append(profile_manager->GetCurrentProfileDir()),
+ *(CommandLine::ForCurrentProcess()),
+ logging::DELETE_OLD_LOG_FILE);
}
#endif
+#if defined(USE_X11)
+ SetBrowserX11ErrorHandlers();
+#endif
+
Profile* profile = CreateProfile(parameters, user_data_dir);
if (!profile)
return ResultCodes::NORMAL_EXIT;
@@ -1004,6 +1191,9 @@ int BrowserMain(const MainFunctionParams& parameters) {
PrefService* user_prefs = profile->GetPrefs();
DCHECK(user_prefs);
+ // Convert active labs into switches. Modifies the current command line.
+ about_labs::ConvertLabsToSwitches(profile, CommandLine::ForCurrentProcess());
+
// Tests should be able to tune login manager before showing it.
// Thus only show login manager in normal (non-testing) mode.
if (!parameters.ui_task) {
@@ -1013,7 +1203,8 @@ int BrowserMain(const MainFunctionParams& parameters) {
#if !defined(OS_MACOSX)
// Importing other browser settings is done in a browser-like process
// that exits when this task has finished.
- // TODO(port): Port to Mac
+ // TODO(port): Port the Mac's IPC-based implementation to other platforms to
+ // replace this implementation. http://crbug.com/22142
if (parsed_command_line.HasSwitch(switches::kImport) ||
parsed_command_line.HasSwitch(switches::kImportFromFile)) {
return FirstRun::ImportNow(profile, parsed_command_line);
@@ -1058,25 +1249,14 @@ int BrowserMain(const MainFunctionParams& parameters) {
// touches reads preferences.
if (is_first_run) {
if (!first_run_ui_bypass) {
-#if defined(OS_WIN)
FirstRun::AutoImport(profile,
master_prefs.homepage_defined,
master_prefs.do_import_items,
master_prefs.dont_import_items,
master_prefs.run_search_engine_experiment,
master_prefs.randomize_search_engine_experiment,
+ master_prefs.make_chrome_default,
&process_singleton);
-#else
- if (!OpenFirstRunDialog(profile,
- master_prefs.homepage_defined,
- master_prefs.do_import_items,
- master_prefs.dont_import_items,
- master_prefs.run_search_engine_experiment,
- master_prefs.randomize_search_engine_experiment,
- &process_singleton)) {
- return ResultCodes::NORMAL_EXIT;
- }
-#endif
#if defined(OS_POSIX)
// On Windows, the download is tagged with enable/disable stats so there
// is no need for this code.
@@ -1100,20 +1280,26 @@ int BrowserMain(const MainFunctionParams& parameters) {
// pre-resolution, as well as TCP/IP connection pre-warming.
// This also registers an observer to discard data when closing incognito
// mode.
+ bool preconnect_enabled = true; // Default status (easy to change!).
+ if (parsed_command_line.HasSwitch(switches::kDisablePreconnect))
+ preconnect_enabled = false;
+ else if (parsed_command_line.HasSwitch(switches::kEnablePreconnect))
+ preconnect_enabled = true;
chrome_browser_net::PredictorInit dns_prefetch(
user_prefs,
local_state,
- parsed_command_line.HasSwitch(switches::kEnablePreconnect),
- parsed_command_line.HasSwitch(switches::kPreconnectDespiteProxy));
+ preconnect_enabled);
#if defined(OS_WIN)
win_util::ScopedCOMInitializer com_initializer;
+#if defined(GOOGLE_CHROME_BUILD)
// Init the RLZ library. This just binds the dll and schedules a task on the
// file thread to be run sometime later. If this is the first run we record
// the installation event.
RLZTracker::InitRlzDelayed(is_first_run, master_prefs.ping_delay);
#endif
+#endif
// Configure the network module so it has access to resources.
net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
@@ -1123,12 +1309,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
RegisterURLRequestChromeJob();
RegisterExtensionProtocols();
RegisterMetadataURLRequestHandler();
-
- // If path to partner services customization document was passed on command
- // line, apply the customizations (Chrome OS only).
- // TODO(denisromanov): Remove this when not needed for testing.
- OptionallyApplyServicesCustomizationFromCommandLine(parsed_command_line,
- &browser_init);
+ RegisterBlobURLRequestJobFactory();
// In unittest mode, this will do nothing. In normal mode, this will create
// the global GoogleURLTracker and IntranetRedirectDetector instances, which
@@ -1163,9 +1344,9 @@ int BrowserMain(const MainFunctionParams& parameters) {
sdch_supported_domain =
parsed_command_line.GetSwitchValueASCII(switches::kSdchFilter);
} else {
- sdch_trial->AppendGroup("_global_disable_sdch",
+ sdch_trial->AppendGroup("global_disable_sdch",
kSDCH_DISABLE_PROBABILITY);
- int sdch_enabled = sdch_trial->AppendGroup("_global_enable_sdch",
+ int sdch_enabled = sdch_trial->AppendGroup("global_enable_sdch",
FieldTrial::kAllRemainingProbability);
if (sdch_enabled != sdch_trial->group())
sdch_supported_domain = "never_enabled_sdch_for_any_domain";
@@ -1180,8 +1361,9 @@ int BrowserMain(const MainFunctionParams& parameters) {
#if defined(OS_WIN) && !defined(GOOGLE_CHROME_BUILD)
if (parsed_command_line.HasSwitch(switches::kDebugPrint)) {
- printing::PrintedDocument::set_debug_dump_path(
- parsed_command_line.GetSwitchValue(switches::kDebugPrint));
+ FilePath path =
+ parsed_command_line.GetSwitchValuePath(switches::kDebugPrint);
+ printing::PrintedDocument::set_debug_dump_path(path);
}
#endif
@@ -1215,6 +1397,19 @@ int BrowserMain(const MainFunctionParams& parameters) {
ChildProcess::WaitForDebugger(L"Browser");
}
+ // If remoting or cloud print proxy is enabled and setup has been completed
+ // we start the service process here.
+ // The prerequisite for running the service process is that we have IO, UI
+ // and PROCESS_LAUNCHER threads up and running.
+ // 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, kServiceProcessRemoting);
+ control->Launch(NULL);
+ }
+ }
+
int result_code = ResultCodes::NORMAL_EXIT;
if (parameters.ui_task) {
// We are in test mode. Run one task and enter the main message loop.
@@ -1225,7 +1420,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
} else {
// We are in regular browser boot sequence. Open initial stabs and enter
// the main message loop.
- if (browser_init.Start(parsed_command_line, std::wstring(), profile,
+ if (browser_init.Start(parsed_command_line, FilePath(), profile,
&result_code)) {
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
// Initialize autoupdate timer. Timer callback costs basically nothing
@@ -1265,8 +1460,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
if (master_prefs.run_search_engine_experiment) {
UMA_HISTOGRAM_ENUMERATION(
"Chrome.SearchSelectExperiment",
- TemplateURLPrepopulateData::GetSearchEngineType(
- default_search_engine),
+ default_search_engine->search_engine_type(),
TemplateURLPrepopulateData::SEARCH_ENGINE_MAX);
// If the selection has been randomized, also record the winner by slot.
if (master_prefs.randomize_search_engine_experiment) {
@@ -1278,8 +1472,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
experiment_type.push_back('1' + engine_pos);
UMA_HISTOGRAM_ENUMERATION(
experiment_type,
- TemplateURLPrepopulateData::GetSearchEngineType(
- default_search_engine),
+ default_search_engine->search_engine_type(),
TemplateURLPrepopulateData::SEARCH_ENGINE_MAX);
} else {
NOTREACHED() << "Invalid search engine selection slot.";
@@ -1288,8 +1481,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
} else {
UMA_HISTOGRAM_ENUMERATION(
"Chrome.SearchSelectExempt",
- TemplateURLPrepopulateData::GetSearchEngineType(
- default_search_engine),
+ default_search_engine->search_engine_type(),
TemplateURLPrepopulateData::SEARCH_ENGINE_MAX);
}
}
@@ -1306,5 +1498,6 @@ int BrowserMain(const MainFunctionParams& parameters) {
ignore_result(browser_process.release());
browser_shutdown::Shutdown();
+ TRACE_EVENT_END("BrowserMain", 0, 0);
return result_code;
}
diff --git a/chrome/browser/browser_main.h b/chrome/browser/browser_main.h
index 2403e28..0648e52 100644
--- a/chrome/browser/browser_main.h
+++ b/chrome/browser/browser_main.h
@@ -4,14 +4,24 @@
#ifndef CHROME_BROWSER_BROWSER_MAIN_H_
#define CHROME_BROWSER_BROWSER_MAIN_H_
+#pragma once
#include "base/basictypes.h"
#include "base/field_trial.h"
+#include "base/scoped_ptr.h"
#include "base/tracked_objects.h"
+class ChromeThread;
class CommandLine;
+class HighResolutionTimerManager;
struct MainFunctionParams;
+class MessageLoop;
class MetricsService;
+class SystemMonitor;
+
+namespace net {
+class NetworkChangeNotifier;
+}
// BrowserMainParts:
// This class contains different "stages" to be executed in |BrowserMain()|,
@@ -33,7 +43,27 @@ class MetricsService;
// - EarlyInitialization: things which should be done as soon as possible on
// program start (such as setting up signal handlers) and things to be done
// at some generic time before the start of the main message loop.
+// - MainMessageLoopStart: things beginning with the start of the main message
+// loop and ending with initialization of the main thread; platform-specific
+// things which should be done immediately before the start of the main
+// message loop should go in |PreMainMessageLoopStart()|.
// - (more to come)
+//
+// How to add stuff (to existing parts):
+// - Figure out when your new code should be executed. What must happen
+// before/after your code is executed? Are there performance reasons for
+// running your code at a particular time? Document these things!
+// - Split out any platform-specific bits. Please avoid #ifdefs it at all
+// possible. You have two choices for platform-specific code: (1) Execute it
+// from one of the platform-specific |Pre/Post...()| methods; do this if the
+// code is unique to a platform type. Or (2) execute it from one of the
+// "parts" (e.g., |EarlyInitialization()|) and provide platform-specific
+// implementations of your code (in a virtual method); do this if you need to
+// provide different implementations across most/all platforms.
+// - Unless your new code is just one or two lines, put it into a separate
+// method with a well-defined purpose. (Likewise, if you're adding to an
+// existing chunk which makes it longer than one or two lines, please move
+// the code out into a separate method.)
class BrowserMainParts {
public:
// This static method is to be implemented by each platform and should
@@ -41,14 +71,11 @@ class BrowserMainParts {
static BrowserMainParts* CreateBrowserMainParts(
const MainFunctionParams& parameters);
+ virtual ~BrowserMainParts();
+
// Parts to be called by |BrowserMain()|.
void EarlyInitialization();
-
- // TODO(viettrungluu): This currently contains (POSIX) initialization done
- // later than "EarlyInitialization()" but dependent on it. Once the
- // refactoring includes that later stage, this should be put in some more
- // generic platform-dependent method.
- virtual void TemporaryPosix_1() {}
+ void MainMessageLoopStart();
protected:
explicit BrowserMainParts(const MainFunctionParams& parameters);
@@ -60,13 +87,18 @@ class BrowserMainParts {
const CommandLine& parsed_command_line() const {
return parsed_command_line_;
}
+ MessageLoop& main_message_loop() const {
+ return *main_message_loop_;
+ }
- private:
// Methods to be overridden to provide platform-specific code; these
// correspond to the "parts" above.
virtual void PreEarlyInitialization() {}
virtual void PostEarlyInitialization() {}
+ virtual void PreMainMessageLoopStart() {}
+ virtual void PostMainMessageLoopStart() {}
+ private:
// Methods for |EarlyInitialization()| ---------------------------------------
// A/B test for the maximum number of persistent connections per host.
@@ -75,11 +107,25 @@ class BrowserMainParts {
// A/B test for determining a value for unused socket timeout.
void SocketTimeoutFieldTrial();
+ // A/B test for the maximum number of connections per proxy server.
+ void ProxyConnectionsFieldTrial();
+
// A/B test for spdy when --use-spdy not set.
void SpdyFieldTrial();
+ // A/B test for prefetching with --(enable|disable)-prefetch not set.
+ void PrefetchFieldTrial();
+
+ // A/B test for automatically establishing a backup TCP connection when a
+ // specified timeout value is reached.
+ void ConnectBackupJobsFieldTrial();
+
// Used to initialize NSPR where appropriate.
- void InitializeSSL();
+ virtual void InitializeSSL() = 0;
+
+ // Methods for |MainMessageLoopStart()| --------------------------------------
+
+ void InitializeMainThread();
// Members initialized on construction ---------------------------------------
@@ -96,14 +142,17 @@ class BrowserMainParts {
// Statistical testing infrastructure for the entire browser.
FieldTrialList field_trial_;
+ // Members initialized in |MainMessageLoopStart()| ---------------------------
+ scoped_ptr<MessageLoop> main_message_loop_;
+ scoped_ptr<SystemMonitor> system_monitor_;
+ scoped_ptr<HighResolutionTimerManager> hi_res_timer_manager_;
+ scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+ scoped_ptr<ChromeThread> main_thread_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
};
-// Perform platform-specific work that needs to be done before the main
-// message loop is created, initialized, and entered.
-void WillInitializeMainMessageLoop(const MainFunctionParams& parameters);
-
// Perform platform-specific work that needs to be done after the main event
// loop has ended.
void DidEndMainMessageLoop();
diff --git a/chrome/browser/browser_main_gtk.cc b/chrome/browser/browser_main_gtk.cc
index c64d573..9f98f35 100644
--- a/chrome/browser/browser_main_gtk.cc
+++ b/chrome/browser/browser_main_gtk.cc
@@ -4,8 +4,12 @@
#include "chrome/browser/browser_main.h"
+#include "app/x11_util.h"
+#include "app/x11_util_internal.h"
#include "base/command_line.h"
#include "base/debug_util.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_main_gtk.h"
#include "chrome/browser/browser_main_win.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/common/result_codes.h"
@@ -14,9 +18,30 @@
#include "chrome/app/breakpad_linux.h"
#endif
-void WillInitializeMainMessageLoop(const MainFunctionParams& parameters) {
+namespace {
+
+// Indicates that we're currently responding to an IO error (by shutting down).
+bool g_in_x11_io_error_handler = false;
+
+int BrowserX11ErrorHandler(Display* d, XErrorEvent* error) {
+ if (!g_in_x11_io_error_handler)
+ LOG(ERROR) << x11_util::GetErrorEventDescription(d, error);
+ return 0;
+}
+
+int BrowserX11IOErrorHandler(Display* d) {
+ // If there's an IO error it likely means the X server has gone away
+ if (!g_in_x11_io_error_handler) {
+ g_in_x11_io_error_handler = true;
+ LOG(ERROR) << "X IO Error detected";
+ BrowserList::WindowsSessionEnding();
+ }
+
+ return 0;
}
+} // namespace
+
void DidEndMainMessageLoop() {
}
@@ -49,3 +74,11 @@ bool CheckMachineLevelInstall() {
void PrepareRestartOnCrashEnviroment(const CommandLine &parsed_command_line) {
}
+
+void SetBrowserX11ErrorHandlers() {
+ // Set up error handlers to make sure profile gets written if X server
+ // goes away.
+ x11_util::SetX11ErrorHandlers(
+ BrowserX11ErrorHandler,
+ BrowserX11IOErrorHandler);
+}
diff --git a/chrome/browser/browser_main_gtk.h b/chrome/browser/browser_main_gtk.h
new file mode 100644
index 0000000..234ff7a
--- /dev/null
+++ b/chrome/browser/browser_main_gtk.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.
+
+// Contains functions used by BrowserMain() that are gtk-specific.
+
+#ifndef CHROME_BROWSER_BROWSER_MAIN_GTK_H_
+#define CHROME_BROWSER_BROWSER_MAIN_GTK_H_
+#pragma once
+
+// Installs the X11 error handlers for the browser process. This will
+// allow us to exit cleanly if X exits before us.
+void SetBrowserX11ErrorHandlers();
+
+#endif // CHROME_BROWSER_BROWSER_MAIN_GTK_H_
diff --git a/chrome/browser/browser_main_mac.mm b/chrome/browser/browser_main_mac.mm
index 34cca50..a00c47b 100644
--- a/chrome/browser/browser_main_mac.mm
+++ b/chrome/browser/browser_main_mac.mm
@@ -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_main.h"
+#include "chrome/browser/browser_main_posix.h"
#import <Cocoa/Cocoa.h>
@@ -13,6 +13,7 @@
#include "base/debug_util.h"
#include "base/file_path.h"
#include "base/mac_util.h"
+#include "base/nss_util.h"
#include "base/path_service.h"
#include "base/scoped_nsobject.h"
#include "chrome/app/breakpad_mac.h"
@@ -22,57 +23,11 @@
#import "chrome/browser/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"
-
-// Tell Cooca to finish its initalization, which we want to do manually
-// instead of calling NSApplicationMain(). The primary reason is that NSAM()
-// never returns, which would leave all the objects currently on the stack
-// in scoped_ptrs hanging and never cleaned up. We then load the main nib
-// directly. The main event loop is run from common code using the
-// MessageLoop API, which works out ok for us because it's a wrapper around
-// CFRunLoop.
-void WillInitializeMainMessageLoop(const MainFunctionParams& parameters) {
- // Initialize NSApplication using the custom subclass.
- [BrowserCrApplication sharedApplication];
-
- // If ui_task is not NULL, the app is actually a browser_test, so startup is
- // handled outside of BrowserMain (which is what called this).
- if (!parameters.ui_task) {
- // The browser process only wants to support the language Cocoa will use, so
- // force the app locale to be overriden with that value.
- l10n_util::OverrideLocaleWithCocoaLocale();
-
- // Before we load the nib, we need to start up the resource bundle so we
- // have the strings avaiable for localization.
- std::wstring pref_locale;
- // TODO(markusheintz): Read preference pref::kApplicationLocale in order to
- // enforce the application locale.
- ResourceBundle::InitSharedInstance(pref_locale);
-
- FilePath resources_pack_path;
- PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
- ResourceBundle::AddDataPackToSharedInstance(resources_pack_path);
- }
-
- // Now load the nib (from the right bundle).
- scoped_nsobject<NSNib>
- nib([[NSNib alloc] initWithNibNamed:@"MainMenu"
- bundle:mac_util::MainAppBundle()]);
- [nib instantiateNibWithOwner:NSApp topLevelObjects:nil];
- // Make sure the app controller has been created.
- DCHECK([NSApp delegate]);
-
- // This is a no-op if the KeystoneRegistration framework is not present.
- // The framework is only distributed with branded Google Chrome builds.
- [[KeystoneGlue defaultKeystoneGlue] registerWithKeystone];
-
- // Prevent Cocoa from turning command-line arguments into
- // |-application:openFiles:|, since we already handle them directly.
- [[NSUserDefaults standardUserDefaults]
- setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
-}
+#include "net/socket/ssl_client_socket_mac_factory.h"
void DidEndMainMessageLoop() {
AppController* appController = [NSApp delegate];
@@ -104,3 +59,93 @@ bool CheckMachineLevelInstall() {
void PrepareRestartOnCrashEnviroment(const CommandLine& parsed_command_line) {
}
+
+// BrowserMainPartsMac ---------------------------------------------------------
+
+class BrowserMainPartsMac : public BrowserMainPartsPosix {
+ public:
+ explicit BrowserMainPartsMac(const MainFunctionParams& parameters)
+ : BrowserMainPartsPosix(parameters) {}
+
+ protected:
+ virtual void PreEarlyInitialization() {
+ BrowserMainPartsPosix::PreEarlyInitialization();
+
+ if (mac_util::WasLaunchedAsHiddenLoginItem()) {
+ CommandLine* singleton_command_line = CommandLine::ForCurrentProcess();
+ singleton_command_line->AppendSwitch(switches::kNoStartupWindow);
+ }
+ }
+
+ virtual void PreMainMessageLoopStart() {
+ BrowserMainPartsPosix::PreMainMessageLoopStart();
+
+ // Tell Cooca to finish its initalization, which we want to do manually
+ // instead of calling NSApplicationMain(). The primary reason is that NSAM()
+ // never returns, which would leave all the objects currently on the stack
+ // in scoped_ptrs hanging and never cleaned up. We then load the main nib
+ // directly. The main event loop is run from common code using the
+ // MessageLoop API, which works out ok for us because it's a wrapper around
+ // CFRunLoop.
+
+ // Initialize NSApplication using the custom subclass.
+ [BrowserCrApplication sharedApplication];
+
+ // If ui_task is not NULL, the app is actually a browser_test, so startup is
+ // handled outside of BrowserMain (which is what called this).
+ if (!parameters().ui_task) {
+ // The browser process only wants to support the language Cocoa will use,
+ // so force the app locale to be overriden with that value.
+ l10n_util::OverrideLocaleWithCocoaLocale();
+
+ // Before we load the nib, we need to start up the resource bundle so we
+ // have the strings avaiable for localization.
+ std::string pref_locale;
+ // TODO(markusheintz): Read preference pref::kApplicationLocale in order
+ // to enforce the application locale.
+ ResourceBundle::InitSharedInstance(pref_locale);
+
+ FilePath resources_pack_path;
+ PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
+ ResourceBundle::AddDataPackToSharedInstance(resources_pack_path);
+ }
+
+ // Now load the nib (from the right bundle).
+ scoped_nsobject<NSNib>
+ nib([[NSNib alloc] initWithNibNamed:@"MainMenu"
+ bundle:mac_util::MainAppBundle()]);
+ // TODO(viettrungluu): crbug.com/20504 - This currently leaks, so if you
+ // change this, you'll probably need to change the Valgrind suppression.
+ [nib instantiateNibWithOwner:NSApp topLevelObjects:nil];
+ // Make sure the app controller has been created.
+ DCHECK([NSApp delegate]);
+
+ // This is a no-op if the KeystoneRegistration framework is not present.
+ // The framework is only distributed with branded Google Chrome builds.
+ [[KeystoneGlue defaultKeystoneGlue] registerWithKeystone];
+
+ // Prevent Cocoa from turning command-line arguments into
+ // |-application:openFiles:|, since we already handle them directly.
+ [[NSUserDefaults standardUserDefaults]
+ setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
+ }
+
+ private:
+ virtual void InitializeSSL() {
+ // Use NSS for SSL by default.
+ // The default client socket factory uses NSS for SSL by default on Mac.
+ if (parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
+ net::ClientSocketFactory::SetSSLClientSocketFactory(
+ net::SSLClientSocketMacFactory);
+ } else {
+ // We want to be sure to init NSPR on the main thread.
+ base::EnsureNSPRInit();
+ }
+ }
+};
+
+// static
+BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
+ const MainFunctionParams& parameters) {
+ return new BrowserMainPartsMac(parameters);
+}
diff --git a/chrome/browser/browser_main_posix.cc b/chrome/browser/browser_main_posix.cc
index d85a93f..e6675f6 100644
--- a/chrome/browser/browser_main_posix.cc
+++ b/chrome/browser/browser_main_posix.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 "chrome/browser/browser_main_posix.h"
+
#include <errno.h>
#include <signal.h>
#include <sys/resource.h>
@@ -9,9 +11,8 @@
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_main.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_switches.h"
@@ -87,6 +88,8 @@ ShutdownDetector::ShutdownDetector(int shutdown_fd)
}
void ShutdownDetector::ThreadMain() {
+ PlatformThread::SetName("CrShutdownDetector");
+
int signal;
size_t bytes_read = 0;
ssize_t ret;
@@ -153,76 +156,74 @@ void SetFileDescriptorLimit(unsigned int max_descriptors) {
// BrowserMainPartsPosix -------------------------------------------------------
-class BrowserMainPartsPosix : public BrowserMainParts {
- public:
- explicit BrowserMainPartsPosix(const MainFunctionParams& parameters)
- : BrowserMainParts(parameters) {}
+void BrowserMainPartsPosix::PreEarlyInitialization() {
+ // We need to accept SIGCHLD, even though our handler is a no-op because
+ // otherwise we cannot wait on children. (According to POSIX 2001.)
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIGCHLDHandler;
+ CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
- virtual void TemporaryPosix_1() {
- int pipefd[2];
- int ret = pipe(pipefd);
- if (ret < 0) {
- PLOG(DFATAL) << "Failed to create pipe";
- } else {
- g_shutdown_pipe_read_fd = pipefd[0];
- g_shutdown_pipe_write_fd = pipefd[1];
- const size_t kShutdownDetectorThreadStackSize = 4096;
- if (!PlatformThread::CreateNonJoinable(
- kShutdownDetectorThreadStackSize,
- new ShutdownDetector(g_shutdown_pipe_read_fd))) {
- LOG(DFATAL) << "Failed to create shutdown detector task.";
- }
- }
- }
+ // If adding to this list of signal handlers, note the new signal probably
+ // needs to be reset in child processes. See
+ // base/process_util_posix.cc:LaunchApp
- private:
- virtual void PreEarlyInitialization() {
- // We need to accept SIGCHLD, even though our handler is a no-op because
- // otherwise we cannot wait on children. (According to POSIX 2001.)
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIGCHLDHandler;
- CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
-
- // If adding to this list of signal handlers, note the new signal probably
- // needs to be reset in child processes. See
- // base/process_util_posix.cc:LaunchApp
-
- // We need to handle SIGTERM, because that is how many POSIX-based distros
- // ask processes to quit gracefully at shutdown time.
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIGTERMHandler;
- CHECK(sigaction(SIGTERM, &action, NULL) == 0);
- // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
- // the browser process is being debugged, GDB will catch the SIGINT first.
- action.sa_handler = SIGINTHandler;
- CHECK(sigaction(SIGINT, &action, NULL) == 0);
- // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
- // distros send SIGHUP, SIGTERM, and then SIGKILL.
- action.sa_handler = SIGHUPHandler;
- CHECK(sigaction(SIGHUP, &action, NULL) == 0);
-
- const std::string fd_limit_string =
- parsed_command_line().GetSwitchValueASCII(
- switches::kFileDescriptorLimit);
- int fd_limit = 0;
- if (!fd_limit_string.empty()) {
- StringToInt(fd_limit_string, &fd_limit);
- }
+ // We need to handle SIGTERM, because that is how many POSIX-based distros ask
+ // processes to quit gracefully at shutdown time.
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIGTERMHandler;
+ CHECK(sigaction(SIGTERM, &action, NULL) == 0);
+ // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
+ // the browser process is being debugged, GDB will catch the SIGINT first.
+ action.sa_handler = SIGINTHandler;
+ CHECK(sigaction(SIGINT, &action, NULL) == 0);
+ // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
+ // distros send SIGHUP, SIGTERM, and then SIGKILL.
+ action.sa_handler = SIGHUPHandler;
+ CHECK(sigaction(SIGHUP, &action, NULL) == 0);
+
+ const std::string fd_limit_string =
+ parsed_command_line().GetSwitchValueASCII(
+ switches::kFileDescriptorLimit);
+ int fd_limit = 0;
+ if (!fd_limit_string.empty()) {
+ base::StringToInt(fd_limit_string, &fd_limit);
+ }
#if defined(OS_MACOSX)
- // We use quite a few file descriptors for our IPC, and the default limit on
- // the Mac is low (256), so bump it up if there is no explicit override.
- if (fd_limit == 0) {
- fd_limit = 1024;
- }
+ // We use quite a few file descriptors for our IPC, and the default limit on
+ // the Mac is low (256), so bump it up if there is no explicit override.
+ if (fd_limit == 0) {
+ fd_limit = 1024;
+ }
#endif // OS_MACOSX
- if (fd_limit > 0)
- SetFileDescriptorLimit(fd_limit);
+ if (fd_limit > 0)
+ SetFileDescriptorLimit(fd_limit);
+}
+
+void BrowserMainPartsPosix::PostMainMessageLoopStart() {
+ int pipefd[2];
+ int ret = pipe(pipefd);
+ if (ret < 0) {
+ PLOG(DFATAL) << "Failed to create pipe";
+ } else {
+ g_shutdown_pipe_read_fd = pipefd[0];
+ g_shutdown_pipe_write_fd = pipefd[1];
+ const size_t kShutdownDetectorThreadStackSize = 4096;
+ // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so
+ // if you change this, you'll probably need to change the suppression.
+ if (!PlatformThread::CreateNonJoinable(
+ kShutdownDetectorThreadStackSize,
+ new ShutdownDetector(g_shutdown_pipe_read_fd))) {
+ LOG(DFATAL) << "Failed to create shutdown detector task.";
+ }
}
-};
+}
+// Mac further subclasses BrowserMainPartsPosix
+#if !defined(OS_MACOSX)
// static
BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
const MainFunctionParams& parameters) {
return new BrowserMainPartsPosix(parameters);
}
+#endif // !defined(OS_MACOSX)
diff --git a/chrome/browser/browser_main_posix.h b/chrome/browser/browser_main_posix.h
new file mode 100644
index 0000000..817565a
--- /dev/null
+++ b/chrome/browser/browser_main_posix.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_BROWSER_MAIN_POSIX_H_
+#define CHROME_BROWSER_BROWSER_MAIN_POSIX_H_
+
+#include "chrome/browser/browser_main.h"
+
+class BrowserMainPartsPosix : public BrowserMainParts {
+ public:
+ explicit BrowserMainPartsPosix(const MainFunctionParams& parameters)
+ : BrowserMainParts(parameters) {}
+
+ protected:
+ virtual void PreEarlyInitialization();
+ virtual void PostMainMessageLoopStart();
+
+ private:
+#if !defined(OS_MACOSX)
+ virtual void InitializeSSL() {}
+#endif
+};
+
+#endif // CHROME_BROWSER_BROWSER_MAIN_POSIX_H_
diff --git a/chrome/browser/browser_main_win.cc b/chrome/browser/browser_main_win.cc
index 588a76c..8911307 100644
--- a/chrome/browser/browser_main_win.cc
+++ b/chrome/browser/browser_main_win.cc
@@ -11,14 +11,17 @@
#include <algorithm>
#include "app/l10n_util.h"
-#include "app/message_box_flags.h"
#include "app/win_util.h"
#include "base/command_line.h"
+#include "base/environment.h"
#include "base/i18n/rtl.h"
+#include "base/nss_util.h"
#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
#include "base/win_util.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/first_run.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/views/uninstall_view.h"
#include "chrome/common/chrome_switches.h"
@@ -30,13 +33,10 @@
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/winsock_init.h"
+#include "net/socket/ssl_client_socket_nss_factory.h"
#include "views/focus/accelerator_handler.h"
#include "views/window/window.h"
-void WillInitializeMainMessageLoop(const MainFunctionParams& parameters) {
- OleInitialize(NULL);
-}
-
void DidEndMainMessageLoop() {
OleUninitialize();
}
@@ -111,13 +111,12 @@ int DoUninstallTasks(bool chrome_still_running) {
// chrome executable's lifetime.
void PrepareRestartOnCrashEnviroment(const CommandLine &parsed_command_line) {
// Clear this var so child processes don't show the dialog by default.
- ::SetEnvironmentVariableW(ASCIIToWide(env_vars::kShowRestart).c_str(), NULL);
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ env->UnSetVar(env_vars::kShowRestart);
// For non-interactive tests we don't restart on crash.
- if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(),
- NULL, 0)) {
+ if (env->HasVar(env_vars::kHeadless))
return;
- }
// If the known command-line test options are used we don't create the
// environment block which means we don't get the restart dialog.
@@ -129,18 +128,17 @@ void PrepareRestartOnCrashEnviroment(const CommandLine &parsed_command_line) {
// The encoding we use for the info is "title|context|direction" where
// direction is either env_vars::kRtlLocale or env_vars::kLtrLocale depending
// on the current locale.
- std::wstring dlg_strings;
- dlg_strings.append(l10n_util::GetString(IDS_CRASH_RECOVERY_TITLE));
- dlg_strings.append(L"|");
- dlg_strings.append(l10n_util::GetString(IDS_CRASH_RECOVERY_CONTENT));
- dlg_strings.append(L"|");
- if (base::i18n::IsRTL())
- dlg_strings.append(ASCIIToWide(env_vars::kRtlLocale));
- else
- dlg_strings.append(ASCIIToWide(env_vars::kLtrLocale));
-
- ::SetEnvironmentVariableW(ASCIIToWide(env_vars::kRestartInfo).c_str(),
- dlg_strings.c_str());
+ string16 dlg_strings(l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_TITLE));
+ dlg_strings.push_back('|');
+ string16 adjusted_string(
+ l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_CONTENT));
+ base::i18n::AdjustStringForLocaleDirection(adjusted_string, &adjusted_string);
+ dlg_strings.append(adjusted_string);
+ dlg_strings.push_back('|');
+ dlg_strings.append(ASCIIToUTF16(
+ base::i18n::IsRTL() ? env_vars::kRtlLocale : env_vars::kLtrLocale));
+
+ env->SetVar(env_vars::kRestartInfo, UTF16ToUTF8(dlg_strings));
}
// This method handles the --hide-icons and --show-icons command line options
@@ -211,11 +209,29 @@ class BrowserMainPartsWin : public BrowserMainParts {
explicit BrowserMainPartsWin(const MainFunctionParams& parameters)
: BrowserMainParts(parameters) {}
- private:
+ protected:
virtual void PreEarlyInitialization() {
// Initialize Winsock.
net::EnsureWinsockInit();
}
+
+ virtual void PreMainMessageLoopStart() {
+ OleInitialize(NULL);
+ }
+
+ private:
+ virtual void InitializeSSL() {
+ // Use NSS for SSL by default.
+ // Because of a build system issue (http://crbug.com/43461), the default
+ // client socket factory uses SChannel (the system SSL library) for SSL by
+ // default on Windows.
+ if (!parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
+ net::ClientSocketFactory::SetSSLClientSocketFactory(
+ net::SSLClientSocketNSSFactory);
+ // We want to be sure to init NSPR on the main thread.
+ base::EnsureNSPRInit();
+ }
+ }
};
// static
diff --git a/chrome/browser/browser_main_win.h b/chrome/browser/browser_main_win.h
index 66fbc26..7d4bcf5 100644
--- a/chrome/browser/browser_main_win.h
+++ b/chrome/browser/browser_main_win.h
@@ -1,4 +1,4 @@
-// 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.
@@ -6,9 +6,9 @@
#ifndef CHROME_BROWSER_BROWSER_MAIN_WIN_H_
#define CHROME_BROWSER_BROWSER_MAIN_WIN_H_
+#pragma once
class CommandLine;
-class MetricsService;
// Handle uninstallation when given the appropriate the command-line switch.
// If |chrome_still_running| is true a modal dialog will be shown asking the
diff --git a/chrome/browser/browser_process.cc b/chrome/browser/browser_process.cc
index d1e7c28..5f52499 100644
--- a/chrome/browser/browser_process.cc
+++ b/chrome/browser/browser_process.cc
@@ -12,4 +12,3 @@ DownloadRequestLimiter* BrowserProcess::download_request_limiter() {
ResourceDispatcherHost* rdh = resource_dispatcher_host();
return rdh ? rdh->download_request_limiter() : NULL;
}
-
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index a85c6c6..e417f2d 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -9,6 +9,7 @@
#ifndef CHROME_BROWSER_BROWSER_PROCESS_H_
#define CHROME_BROWSER_BROWSER_PROCESS_H_
+#pragma once
#include <string>
#include <vector>
@@ -20,6 +21,7 @@ class AutomationProviderList;
class Clipboard;
class DevToolsManager;
class DownloadRequestLimiter;
+class DownloadStatusUpdater;
class GoogleURLTracker;
class IntranetRedirectDetector;
class IconManager;
@@ -28,11 +30,9 @@ class NotificationUIManager;
class PrefService;
class ProfileManager;
class ResourceDispatcherHost;
-class StatusTrayManager;
-class SuspendController;
+class SidebarManager;
class TabCloseableStateWatcher;
class ThumbnailGenerator;
-class WebAppInstallerService;
namespace base {
class Thread;
@@ -65,22 +65,19 @@ class BrowserProcess {
virtual ProfileManager* profile_manager() = 0;
virtual PrefService* local_state() = 0;
virtual DevToolsManager* devtools_manager() = 0;
+ virtual SidebarManager* sidebar_manager() = 0;
virtual Clipboard* clipboard() = 0;
// Returns the manager for desktop notifications.
virtual NotificationUIManager* notification_ui_manager() = 0;
- // Returns the status tray manager (provides APIs for manipulating status
- // icons).
- virtual StatusTrayManager* status_tray_manager() = 0;
-
// Returns the thread that we perform I/O coordination on (network requests,
// communication with renderers, etc.
// NOTE: You should ONLY use this to pass to IPC or other objects which must
// need a MessageLoop*. If you just want to post a task, use
// ChromeThread::PostTask (or other variants) as they take care of checking
// that a thread is still alive, race conditions, lifetime differences etc.
- // If you still must use this, need to check the return value for NULL.
+ // If you still must use this check the return value for NULL.
virtual IOThread* io_thread() = 0;
// Returns the thread that we perform random file operations on. For code
@@ -128,6 +125,7 @@ class BrowserProcess {
virtual void SetApplicationLocale(const std::string& locale) = 0;
DownloadRequestLimiter* download_request_limiter();
+ virtual DownloadStatusUpdater* download_status_updater() = 0;
// Returns an event that is signaled when the browser shutdown.
virtual base::WaitableEvent* shutdown_event() = 0;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 2fac31a..88b41a9 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -11,9 +11,11 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/task.h"
#include "base/thread.h"
#include "base/waitable_event.h"
#include "chrome/browser/appcache/chrome_appcache_service.h"
+#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_main.h"
@@ -24,8 +26,8 @@
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/download/download_file_manager.h"
#include "chrome/browser/download/save_file_manager.h"
-#include "chrome/browser/first_run.h"
-#include "chrome/browser/google_url_tracker.h"
+#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/intranet_redirect_detector.h"
@@ -36,13 +38,14 @@
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/pref_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/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/safe_browsing_service.h"
-#include "chrome/browser/status_icons/status_tray_manager.h"
+#include "chrome/browser/sidebar/sidebar_manager.h"
#include "chrome/browser/tab_closeable_state_watcher.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
@@ -53,6 +56,7 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
+#include "chrome/common/switch_utils.h"
#include "chrome/installer/util/google_update_constants.h"
#include "ipc/ipc_logging.h"
#include "webkit/database/database_tracker.h"
@@ -72,6 +76,13 @@
static const int kUpdateCheckIntervalHours = 6;
#endif
+#if defined(USE_X11)
+// How long to wait for the File thread to complete during EndSession, on
+// Linux. We have a timeout here because we're unable to run the UI messageloop
+// and there's some deadlock risk. Our only option is to exit anyway.
+static const int kEndSessionTimeoutSeconds = 10;
+#endif
+
BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
: created_resource_dispatcher_host_(false),
created_metrics_service_(false),
@@ -85,6 +96,7 @@ BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
created_icon_manager_(false),
created_debugger_wrapper_(false),
created_devtools_manager_(false),
+ created_sidebar_manager_(false),
created_notification_ui_manager_(false),
module_ref_count_(0),
did_start_(false),
@@ -132,6 +144,11 @@ BrowserProcessImpl::~BrowserProcessImpl() {
google_url_tracker_.reset();
intranet_redirect_detector_.reset();
+ // Need to clear the desktop notification balloons before the io_thread_ and
+ // before the profiles, since if there are any still showing we will access
+ // those things during teardown.
+ notification_ui_manager_.reset();
+
// Need to clear profiles (download managers) before the io_thread_.
profile_manager_.reset();
@@ -208,10 +225,16 @@ BrowserProcessImpl::~BrowserProcessImpl() {
g_browser_process = NULL;
}
+#if defined(OS_WIN)
// Send a QuitTask to the given MessageLoop.
static void PostQuit(MessageLoop* message_loop) {
message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
+#elif defined(USE_X11)
+static void Signal(base::WaitableEvent* event) {
+ event->Signal();
+}
+#endif
unsigned int BrowserProcessImpl::AddRefModule() {
DCHECK(CalledOnValidThread());
@@ -233,9 +256,9 @@ unsigned int BrowserProcessImpl::ReleaseModule() {
}
void BrowserProcessImpl::EndSession() {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(USE_X11)
// Notify we are going away.
- ::SetEvent(shutdown_event_->handle());
+ shutdown_event_->Signal();
#endif
// Mark all the profiles as clean.
@@ -257,9 +280,149 @@ void BrowserProcessImpl::EndSession() {
// We must write that the profile and metrics service shutdown cleanly,
// otherwise on startup we'll think we crashed. So we block until done and
// then proceed with normal shutdown.
- g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
+#if defined(USE_X11)
+ // Can't run a local loop on linux. Instead create a waitable event.
+ base::WaitableEvent done_writing(false, false);
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(Signal, &done_writing));
+ done_writing.TimedWait(
+ base::TimeDelta::FromSeconds(kEndSessionTimeoutSeconds));
+#elif defined(OS_WIN)
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
NewRunnableFunction(PostQuit, MessageLoop::current()));
MessageLoop::current()->Run();
+#else
+ NOTIMPLEMENTED();
+#endif
+}
+
+ResourceDispatcherHost* BrowserProcessImpl::resource_dispatcher_host() {
+ DCHECK(CalledOnValidThread());
+ if (!created_resource_dispatcher_host_)
+ CreateResourceDispatcherHost();
+ return resource_dispatcher_host_.get();
+}
+
+MetricsService* BrowserProcessImpl::metrics_service() {
+ DCHECK(CalledOnValidThread());
+ if (!created_metrics_service_)
+ CreateMetricsService();
+ return metrics_service_.get();
+}
+
+IOThread* BrowserProcessImpl::io_thread() {
+ DCHECK(CalledOnValidThread());
+ if (!created_io_thread_)
+ CreateIOThread();
+ return io_thread_.get();
+}
+
+base::Thread* BrowserProcessImpl::file_thread() {
+ DCHECK(CalledOnValidThread());
+ if (!created_file_thread_)
+ CreateFileThread();
+ return file_thread_.get();
+}
+
+base::Thread* BrowserProcessImpl::db_thread() {
+ DCHECK(CalledOnValidThread());
+ if (!created_db_thread_)
+ CreateDBThread();
+ return db_thread_.get();
+}
+
+base::Thread* BrowserProcessImpl::process_launcher_thread() {
+ DCHECK(CalledOnValidThread());
+ if (!created_process_launcher_thread_)
+ CreateProcessLauncherThread();
+ return process_launcher_thread_.get();
+}
+
+base::Thread* BrowserProcessImpl::cache_thread() {
+ DCHECK(CalledOnValidThread());
+ if (!created_cache_thread_)
+ CreateCacheThread();
+ return cache_thread_.get();
+}
+
+#if defined(USE_X11)
+base::Thread* BrowserProcessImpl::background_x11_thread() {
+ DCHECK(CalledOnValidThread());
+ // The BACKGROUND_X11 thread is created when the IO thread is created.
+ if (!created_io_thread_)
+ CreateIOThread();
+ return background_x11_thread_.get();
+}
+#endif
+
+ProfileManager* BrowserProcessImpl::profile_manager() {
+ DCHECK(CalledOnValidThread());
+ if (!created_profile_manager_)
+ CreateProfileManager();
+ return profile_manager_.get();
+}
+
+PrefService* BrowserProcessImpl::local_state() {
+ DCHECK(CalledOnValidThread());
+ if (!created_local_state_)
+ CreateLocalState();
+ return local_state_.get();
+}
+
+DevToolsManager* BrowserProcessImpl::devtools_manager() {
+ DCHECK(CalledOnValidThread());
+ if (!created_devtools_manager_)
+ CreateDevToolsManager();
+ return devtools_manager_.get();
+}
+
+SidebarManager* BrowserProcessImpl::sidebar_manager() {
+ DCHECK(CalledOnValidThread());
+ if (!created_sidebar_manager_)
+ CreateSidebarManager();
+ return sidebar_manager_.get();
+}
+
+Clipboard* BrowserProcessImpl::clipboard() {
+ DCHECK(CalledOnValidThread());
+ return clipboard_.get();
+}
+
+NotificationUIManager* BrowserProcessImpl::notification_ui_manager() {
+ DCHECK(CalledOnValidThread());
+ if (!created_notification_ui_manager_)
+ CreateNotificationUIManager();
+ return notification_ui_manager_.get();
+}
+
+IconManager* BrowserProcessImpl::icon_manager() {
+ DCHECK(CalledOnValidThread());
+ if (!created_icon_manager_)
+ CreateIconManager();
+ return icon_manager_.get();
+}
+
+ThumbnailGenerator* BrowserProcessImpl::GetThumbnailGenerator() {
+ return &thumbnail_generator_;
+}
+
+AutomationProviderList* BrowserProcessImpl::InitAutomationProviderList() {
+ DCHECK(CalledOnValidThread());
+ if (automation_provider_list_.get() == NULL) {
+ automation_provider_list_.reset(AutomationProviderList::GetInstance());
+ }
+ return automation_provider_list_.get();
+}
+
+void BrowserProcessImpl::InitDebuggerWrapper(int port, bool useHttp) {
+ DCHECK(CalledOnValidThread());
+ if (!created_debugger_wrapper_)
+ CreateDebuggerWrapper(port, useHttp);
+}
+
+bool BrowserProcessImpl::IsShuttingDown() {
+ DCHECK(CalledOnValidThread());
+ return did_start_ && 0 == module_ref_count_;
}
printing::PrintJobManager* BrowserProcessImpl::print_job_manager() {
@@ -271,6 +434,64 @@ printing::PrintJobManager* BrowserProcessImpl::print_job_manager() {
return print_job_manager_.get();
}
+GoogleURLTracker* BrowserProcessImpl::google_url_tracker() {
+ DCHECK(CalledOnValidThread());
+ if (!google_url_tracker_.get())
+ CreateGoogleURLTracker();
+ return google_url_tracker_.get();
+}
+
+IntranetRedirectDetector* BrowserProcessImpl::intranet_redirect_detector() {
+ DCHECK(CalledOnValidThread());
+ if (!intranet_redirect_detector_.get())
+ CreateIntranetRedirectDetector();
+ return intranet_redirect_detector_.get();
+}
+
+const std::string& BrowserProcessImpl::GetApplicationLocale() {
+ DCHECK(!locale_.empty());
+ return locale_;
+}
+
+void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {
+ locale_ = locale;
+ extension_l10n_util::SetProcessLocale(locale);
+}
+
+DownloadStatusUpdater* BrowserProcessImpl::download_status_updater() {
+ return &download_status_updater_;
+}
+
+base::WaitableEvent* BrowserProcessImpl::shutdown_event() {
+ return shutdown_event_.get();
+}
+
+TabCloseableStateWatcher* BrowserProcessImpl::tab_closeable_state_watcher() {
+ DCHECK(CalledOnValidThread());
+ if (!tab_closeable_state_watcher_.get())
+ CreateTabCloseableStateWatcher();
+ return tab_closeable_state_watcher_.get();
+}
+
+void BrowserProcessImpl::CheckForInspectorFiles() {
+ file_thread()->message_loop()->PostTask
+ (FROM_HERE,
+ NewRunnableMethod(this, &BrowserProcessImpl::DoInspectorFilesCheck));
+}
+
+#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
+void BrowserProcessImpl::StartAutoupdateTimer() {
+ autoupdate_timer_.Start(
+ base::TimeDelta::FromHours(kUpdateCheckIntervalHours),
+ this,
+ &BrowserProcessImpl::OnAutoupdateTimer);
+}
+#endif
+
+bool BrowserProcessImpl::have_inspector_files() const {
+ return have_inspector_files_;
+}
+
void BrowserProcessImpl::ClearLocalState(const FilePath& profile_path) {
SQLitePersistentCookieStore::ClearLocalState(profile_path.Append(
chrome::kCookieFilename));
@@ -415,8 +636,15 @@ void BrowserProcessImpl::CreateLocalState() {
FilePath local_state_path;
PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
- local_state_.reset(PrefService::CreatePrefService(local_state_path));
- }
+ local_state_.reset(PrefService::CreatePrefService(local_state_path, NULL));
+
+ // Make sure the the plugin updater gets notifications of changes
+ // in the plugin blacklist.
+ local_state_->RegisterListPref(prefs::kPluginsPluginsBlacklist);
+ plugin_state_change_registrar_.Init(local_state_.get());
+ plugin_state_change_registrar_.Add(prefs::kPluginsPluginsBlacklist,
+ PluginUpdater::GetPluginUpdater());
+}
void BrowserProcessImpl::CreateIconManager() {
DCHECK(!created_icon_manager_ && icon_manager_.get() == NULL);
@@ -437,6 +665,12 @@ void BrowserProcessImpl::CreateDevToolsManager() {
devtools_manager_ = new DevToolsManager();
}
+void BrowserProcessImpl::CreateSidebarManager() {
+ DCHECK(sidebar_manager_.get() == NULL);
+ created_sidebar_manager_ = true;
+ sidebar_manager_ = new SidebarManager();
+}
+
void BrowserProcessImpl::CreateGoogleURLTracker() {
DCHECK(google_url_tracker_.get() == NULL);
scoped_ptr<GoogleURLTracker> google_url_tracker(new GoogleURLTracker);
@@ -456,16 +690,6 @@ void BrowserProcessImpl::CreateNotificationUIManager() {
created_notification_ui_manager_ = true;
}
-void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {
- locale_ = locale;
- extension_l10n_util::SetProcessLocale(locale);
-}
-
-void BrowserProcessImpl::CreateStatusTrayManager() {
- DCHECK(status_tray_manager_.get() == NULL);
- status_tray_manager_.reset(new StatusTrayManager());
-}
-
void BrowserProcessImpl::CreateTabCloseableStateWatcher() {
DCHECK(tab_closeable_state_watcher_.get() == NULL);
tab_closeable_state_watcher_.reset(TabCloseableStateWatcher::Create());
@@ -475,21 +699,6 @@ void BrowserProcessImpl::CreateTabCloseableStateWatcher() {
// which don't do any management.
DISABLE_RUNNABLE_METHOD_REFCOUNT(BrowserProcessImpl);
-void BrowserProcessImpl::CheckForInspectorFiles() {
- file_thread()->message_loop()->PostTask
- (FROM_HERE,
- NewRunnableMethod(this, &BrowserProcessImpl::DoInspectorFilesCheck));
-}
-
-#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
-void BrowserProcessImpl::StartAutoupdateTimer() {
- autoupdate_timer_.Start(
- base::TimeDelta::FromHours(kUpdateCheckIntervalHours),
- this,
- &BrowserProcessImpl::OnAutoupdateTimer);
-}
-#endif
-
#if defined(IPC_MESSAGE_LOG_ENABLED)
void BrowserProcessImpl::SetIPCLoggingEnabled(bool enable) {
@@ -547,20 +756,13 @@ void BrowserProcessImpl::DoInspectorFilesCheck() {
bool BrowserProcessImpl::CanAutorestartForUpdate() const {
// Check if browser is in the background and if it needs to be restarted to
// apply a pending update.
- return BrowserList::size() == 0 && !BrowserList::WillKeepAlive() &&
+ return BrowserList::size() == 0 && BrowserList::WillKeepAlive() &&
Upgrade::IsUpdatePendingRestart();
}
-// Switches enumerated here will be removed when a background instance of
-// Chrome restarts itself. If your key is designed to only be used once,
-// or if it does not make sense when restarting a background instance to
-// pick up an automatic update, be sure to add it to this list.
-const char* const kSwitchesToRemoveOnAutorestart[] = {
- switches::kApp,
- switches::kFirstRun,
- switches::kImport,
- switches::kImportFromFile,
- switches::kMakeDefaultBrowser
+// Switches to add when auto-restarting Chrome.
+const char* const kSwitchesToAddOnAutorestart[] = {
+ switches::kNoStartupWindow
};
void BrowserProcessImpl::RestartPersistentInstance() {
@@ -570,10 +772,7 @@ void BrowserProcessImpl::RestartPersistentInstance() {
std::map<std::string, CommandLine::StringType> switches =
old_cl->GetSwitches();
- // Remove the keys that we shouldn't pass through during restart.
- for (size_t i = 0; i < arraysize(kSwitchesToRemoveOnAutorestart); i++) {
- switches.erase(kSwitchesToRemoveOnAutorestart[i]);
- }
+ switches::RemoveSwitchesForAutostart(&switches);
// Append the rest of the switches (along with their values, if any)
// to the new command line
@@ -581,14 +780,17 @@ void BrowserProcessImpl::RestartPersistentInstance() {
switches.begin(); i != switches.end(); ++i) {
CommandLine::StringType switch_value = i->second;
if (switch_value.length() > 0) {
- new_cl->AppendSwitchWithValue(i->first, i->second);
+ new_cl->AppendSwitchNative(i->first, i->second);
} else {
new_cl->AppendSwitch(i->first);
}
}
- if (!new_cl->HasSwitch(switches::kRestoreBackgroundContents))
- new_cl->AppendSwitch(switches::kRestoreBackgroundContents);
+ // Ensure that our desired switches are set on the new process.
+ for (size_t i = 0; i < arraysize(kSwitchesToAddOnAutorestart); ++i) {
+ if (!new_cl->HasSwitch(kSwitchesToAddOnAutorestart[i]))
+ new_cl->AppendSwitch(kSwitchesToAddOnAutorestart[i]);
+ }
DLOG(WARNING) << "Shutting down current instance of the browser.";
BrowserList::CloseAllBrowsersAndExit();
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 25ddb4e..898a1b9 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -9,6 +9,7 @@
#ifndef CHROME_BROWSER_BROWSER_PROCESS_IMPL_H_
#define CHROME_BROWSER_BROWSER_PROCESS_IMPL_H_
+#pragma once
#include <string>
@@ -17,8 +18,9 @@
#include "base/non_thread_safe.h"
#include "base/timer.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/browser_process.h"
+#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 "ipc/ipc_message.h"
@@ -36,181 +38,44 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
virtual void EndSession();
- virtual ResourceDispatcherHost* resource_dispatcher_host() {
- DCHECK(CalledOnValidThread());
- if (!created_resource_dispatcher_host_)
- CreateResourceDispatcherHost();
- return resource_dispatcher_host_.get();
- }
-
- virtual MetricsService* metrics_service() {
- DCHECK(CalledOnValidThread());
- if (!created_metrics_service_)
- CreateMetricsService();
- return metrics_service_.get();
- }
-
- virtual IOThread* io_thread() {
- DCHECK(CalledOnValidThread());
- if (!created_io_thread_)
- CreateIOThread();
- return io_thread_.get();
- }
-
- virtual base::Thread* file_thread() {
- DCHECK(CalledOnValidThread());
- if (!created_file_thread_)
- CreateFileThread();
- return file_thread_.get();
- }
-
- virtual base::Thread* db_thread() {
- DCHECK(CalledOnValidThread());
- if (!created_db_thread_)
- CreateDBThread();
- return db_thread_.get();
- }
-
- virtual base::Thread* process_launcher_thread() {
- DCHECK(CalledOnValidThread());
- if (!created_process_launcher_thread_)
- CreateProcessLauncherThread();
- return process_launcher_thread_.get();
- }
-
- virtual base::Thread* cache_thread() {
- DCHECK(CalledOnValidThread());
- if (!created_cache_thread_)
- CreateCacheThread();
- return cache_thread_.get();
- }
-
+ virtual ResourceDispatcherHost* resource_dispatcher_host();
+ virtual MetricsService* metrics_service();
+ virtual IOThread* io_thread();
+ virtual base::Thread* file_thread();
+ virtual base::Thread* db_thread();
+ virtual base::Thread* process_launcher_thread();
+ virtual base::Thread* cache_thread();
#if defined(USE_X11)
- virtual base::Thread* background_x11_thread() {
- DCHECK(CalledOnValidThread());
- // The BACKGROUND_X11 thread is created when the IO thread is created.
- if (!created_io_thread_)
- CreateIOThread();
- return background_x11_thread_.get();
- }
+ virtual base::Thread* background_x11_thread();
#endif
-
- virtual ProfileManager* profile_manager() {
- DCHECK(CalledOnValidThread());
- if (!created_profile_manager_)
- CreateProfileManager();
- return profile_manager_.get();
- }
-
- virtual PrefService* local_state() {
- DCHECK(CalledOnValidThread());
- if (!created_local_state_)
- CreateLocalState();
- return local_state_.get();
- }
-
- virtual DevToolsManager* devtools_manager() {
- DCHECK(CalledOnValidThread());
- if (!created_devtools_manager_)
- CreateDevToolsManager();
- return devtools_manager_.get();
- }
-
- virtual Clipboard* clipboard() {
- DCHECK(CalledOnValidThread());
- return clipboard_.get();
- }
-
- virtual NotificationUIManager* notification_ui_manager() {
- DCHECK(CalledOnValidThread());
- if (!created_notification_ui_manager_)
- CreateNotificationUIManager();
- return notification_ui_manager_.get();
- }
-
- virtual StatusTrayManager* status_tray_manager() {
- DCHECK(CalledOnValidThread());
- if (!status_tray_manager_.get())
- CreateStatusTrayManager();
- return status_tray_manager_.get();
- }
-
- virtual IconManager* icon_manager() {
- DCHECK(CalledOnValidThread());
- if (!created_icon_manager_)
- CreateIconManager();
- return icon_manager_.get();
- }
-
- virtual ThumbnailGenerator* GetThumbnailGenerator() {
- return &thumbnail_generator_;
- }
-
- virtual AutomationProviderList* InitAutomationProviderList() {
- DCHECK(CalledOnValidThread());
- if (automation_provider_list_.get() == NULL) {
- automation_provider_list_.reset(AutomationProviderList::GetInstance());
- }
- return automation_provider_list_.get();
- }
-
- virtual void InitDebuggerWrapper(int port, bool useHttp) {
- DCHECK(CalledOnValidThread());
- if (!created_debugger_wrapper_)
- CreateDebuggerWrapper(port, useHttp);
- }
-
+ virtual ProfileManager* profile_manager();
+ virtual PrefService* local_state();
+ virtual DevToolsManager* devtools_manager();
+ virtual SidebarManager* sidebar_manager();
+ virtual Clipboard* clipboard();
+ virtual NotificationUIManager* notification_ui_manager();
+ virtual IconManager* icon_manager();
+ virtual ThumbnailGenerator* GetThumbnailGenerator();
+ virtual AutomationProviderList* InitAutomationProviderList();
+ virtual void InitDebuggerWrapper(int port, bool useHttp);
virtual unsigned int AddRefModule();
-
virtual unsigned int ReleaseModule();
-
- virtual bool IsShuttingDown() {
- DCHECK(CalledOnValidThread());
- return did_start_ && 0 == module_ref_count_;
- }
-
+ virtual bool IsShuttingDown();
virtual printing::PrintJobManager* print_job_manager();
-
- virtual GoogleURLTracker* google_url_tracker() {
- DCHECK(CalledOnValidThread());
- if (!google_url_tracker_.get())
- CreateGoogleURLTracker();
- return google_url_tracker_.get();
- }
-
- virtual IntranetRedirectDetector* intranet_redirect_detector() {
- DCHECK(CalledOnValidThread());
- if (!intranet_redirect_detector_.get())
- CreateIntranetRedirectDetector();
- return intranet_redirect_detector_.get();
- }
-
- virtual const std::string& GetApplicationLocale() {
- DCHECK(!locale_.empty());
- return locale_;
- }
+ virtual GoogleURLTracker* google_url_tracker();
+ virtual IntranetRedirectDetector* intranet_redirect_detector();
+ virtual const std::string& GetApplicationLocale();
virtual void SetApplicationLocale(const std::string& locale);
-
- virtual base::WaitableEvent* shutdown_event() {
- return shutdown_event_.get();
- }
-
- virtual TabCloseableStateWatcher* tab_closeable_state_watcher() {
- DCHECK(CalledOnValidThread());
- if (!tab_closeable_state_watcher_.get())
- CreateTabCloseableStateWatcher();
- return tab_closeable_state_watcher_.get();
- }
-
+ virtual DownloadStatusUpdater* download_status_updater();
+ virtual base::WaitableEvent* shutdown_event();
+ virtual TabCloseableStateWatcher* tab_closeable_state_watcher();
virtual void CheckForInspectorFiles();
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
void StartAutoupdateTimer();
#endif
- virtual bool have_inspector_files() const {
- return have_inspector_files_;
- }
+ virtual bool have_inspector_files() const;
#if defined(IPC_MESSAGE_LOG_ENABLED)
virtual void SetIPCLoggingEnabled(bool enable);
@@ -239,6 +104,7 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
void CreateIconManager();
void CreateDebuggerWrapper(int port, bool useHttp);
void CreateDevToolsManager();
+ void CreateSidebarManager();
void CreateGoogleURLTracker();
void CreateIntranetRedirectDetector();
void CreateNotificationUIManager();
@@ -289,15 +155,15 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
bool created_devtools_manager_;
scoped_refptr<DevToolsManager> devtools_manager_;
+ bool created_sidebar_manager_;
+ scoped_refptr<SidebarManager> sidebar_manager_;
+
scoped_ptr<Clipboard> clipboard_;
// Manager for desktop notification UI.
bool created_notification_ui_manager_;
scoped_ptr<NotificationUIManager> notification_ui_manager_;
- // Manager for status tray.
- scoped_ptr<StatusTrayManager> status_tray_manager_;
-
scoped_ptr<AutomationProviderList> automation_provider_list_;
scoped_ptr<GoogleURLTracker> google_url_tracker_;
@@ -318,10 +184,15 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
bool checked_for_new_frames_;
bool using_new_frames_;
- // This service just sits around and makes thumanails for tabs. It does
- // nothing in the cosntructor so we don't have to worry about lazy init.
+ // This service just sits around and makes thumbnails for tabs. It does
+ // nothing in the constructor so we don't have to worry about lazy init.
ThumbnailGenerator thumbnail_generator_;
+ // Download status updates (like a changing application icon on dock/taskbar)
+ // are global per-application. DownloadStatusUpdater does no work in the ctor
+ // so we don't have to worry about lazy initialization.
+ DownloadStatusUpdater download_status_updater_;
+
// An event that notifies when we are shutting-down.
scoped_ptr<base::WaitableEvent> shutdown_event_;
@@ -331,6 +202,10 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
// Our best estimate about the existence of the inspector directory.
bool have_inspector_files_;
+ // Ensures that the observer of plugin disable/enable state
+ // notifications are properly added and removed.
+ PrefChangeRegistrar plugin_state_change_registrar_;
+
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
base::RepeatingTimer<BrowserProcessImpl> autoupdate_timer_;
diff --git a/chrome/browser/browser_process_sub_thread.h b/chrome/browser/browser_process_sub_thread.h
index c16997b..72f8372 100644
--- a/chrome/browser/browser_process_sub_thread.h
+++ b/chrome/browser/browser_process_sub_thread.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BROWSER_PROCESS_SUB_THREAD_H_
#define CHROME_BROWSER_BROWSER_PROCESS_SUB_THREAD_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/chrome_thread.h"
@@ -37,4 +38,4 @@ class BrowserProcessSubThread : public ChromeThread {
DISALLOW_COPY_AND_ASSIGN(BrowserProcessSubThread);
};
-#endif // CHROME_BROWSER_BROWSER_PROCESS_SUB_THREAD_H_
+#endif // CHROME_BROWSER_BROWSER_PROCESS_SUB_THREAD_H_
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 7463d03..d369ddb 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This comment is only here because changes to resources are not picked up
-without changes to the corresponding grd file. eadee -->
+without changes to the corresponding grd file. test -->
<grit latest_public_release="0" current_release="1">
<outputs>
<output filename="grit/browser_resources.h" type="rc_header">
@@ -28,20 +28,20 @@ without changes to the corresponding grd file. eadee -->
<include name="IDR_CREDITS_HTML" file="resources\about_credits.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_DOCS_APP_MANIFEST" file="resources\docs_app\manifest.json" type="BINDATA" />
<include name="IDR_DOWNLOADS_HTML" file="resources\downloads.html" flattenhtml="true" type="BINDATA" />
- <include name="IDR_EXTENSION_DEFAULT_ICON" file="resources\extension_default_icon.png" type="BINDATA" />
<if expr="os == 'darwin'">
<include name="IDR_EXTENSIONS_INFOBAR_CSS" file="resources\extensions_infobar_mac.css" flattenhtml="true" type="BINDATA" />
</if>
<if expr="os != 'darwin'">
<include name="IDR_EXTENSIONS_INFOBAR_CSS" file="resources\extensions_infobar.css" flattenhtml="true" type="BINDATA" />
</if>
- <include name="IDR_EXTENSIONS_TOOLSTRIP_THEME_CSS" file="resources\extensions_toolstrip.css" flattenhtml="true" type="BINDATA" />
<include name="IDR_EXTENSIONS_UI_HTML" file="resources\extensions_ui.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_GAIA_LOGIN_HTML" file="sync\resources\gaia_login.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_GMAIL_APP_MANIFEST" file="resources\gmail_app\manifest.json" 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_LABS_HTML" file="resources\labs.html" flattenhtml="true" 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" />
<include name="IDR_NEW_TAB_THEME_CSS" file="resources\new_tab_theme.css" flattenhtml="true" type="BINDATA" />
@@ -58,25 +58,24 @@ without changes to the corresponding grd file. eadee -->
<include name="IDR_SYNC_CHOOSE_DATATYPES_HTML" file="sync\resources\choose_datatypes.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_SETUP_DONE_HTML" file="sync\resources\setup_done.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_SETUP_FLOW_HTML" file="sync\resources\setup_flow.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_REMOTING_SETUP_FLOW_HTML" file="remoting\resources\remoting_setup_flow.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_REMOTING_SETUP_DONE_HTML" file="remoting\resources\remoting_setup_done.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_TRANSLATE_JS" file="resources\translate.js" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_AMEX" file="resources\amex.png" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_GENERIC" file="resources\cc-generic.png" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_DINERS" file="resources\diners.png" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_DISCOVER" file="resources\discover.png" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_JCB" file="resources\jcb.png" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_MASTERCARD" file="resources\mastercard.png" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_SOLO" file="resources\solo.png" type="BINDATA" />
- <include name="IDR_AUTOFILL_CC_VISA" file="resources\visa.png" type="BINDATA" />
-
+ <include name="IDR_BUGREPORT_HTML" file="resources\bug_report.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_BUGREPORT_HTML_INVALID" file="resources\bug_report_invalid.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_WEBSTORE_MANIFEST" file="resources\webstore_app\manifest.json" type="BINDATA" />
<if expr="pp_ifdef('chromeos')">
<include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_FILEBROWSE_HTML" file="resources\filebrowse.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_HOST_REGISTRATION_PAGE_HTML" file="resources\host_registration_page.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_IMAGEBURNER_HTML" file="resources\imageburner.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_MEDIAPLAYER_HTML" file="resources\mediaplayer.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_MEDIAPLAYERPLAYLIST_HTML" file="resources\playlist.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_MOBILE_SETUP_PAGE_HTML" file="resources\mobile_setup.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_OFFLINE_LOAD_HTML" file="resources\offline_load.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_OS_CREDITS_HTML" file="resources\about_os_credits.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SLIDESHOW_HTML" file="resources\slideshow.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_TALK_APP_MANIFEST" file="resources\chat_manager\manifest.json" type="BINDATA" />
</if>
</includes>
</release>
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index e8b668b..9231470 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -7,24 +7,25 @@
#include <string>
#include "app/resource_bundle.h"
+#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/path_service.h"
#include "base/process_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
-#include "base/waitable_event.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
-#include "chrome/browser/first_run.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/jankometer.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/plugin_process_host.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.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"
@@ -32,6 +33,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/chrome_plugin_lib.h"
+#include "chrome/common/switch_utils.h"
#include "net/predictor_api.h"
#if defined(OS_WIN)
@@ -138,7 +140,7 @@ void Shutdown() {
prefs->SavePersistentPrefs();
-#if defined(OS_WIN)
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
// Cleanup any statics created by RLZ. Must be done before NotificationService
// is destroyed.
RLZTracker::CleanupRlz();
@@ -175,12 +177,14 @@ void Shutdown() {
scoped_ptr<CommandLine> new_cl(new CommandLine(old_cl.GetProgram()));
std::map<std::string, CommandLine::StringType> switches =
old_cl.GetSwitches();
+ // Remove the switches that shouldn't persist across restart.
+ switches::RemoveSwitchesForAutostart(&switches);
// Append the old switches to the new command line.
for (std::map<std::string, CommandLine::StringType>::const_iterator i =
switches.begin(); i != switches.end(); ++i) {
CommandLine::StringType switch_value = i->second;
if (!switch_value.empty())
- new_cl->AppendSwitchWithValue(i->first, i->second);
+ new_cl->AppendSwitchNative(i->first, i->second);
else
new_cl->AppendSwitch(i->first);
}
@@ -207,7 +211,8 @@ void Shutdown() {
// and then write it to a file to be read at startup.
// We can't use prefs since all services are shutdown at this point.
TimeDelta shutdown_delta = Time::Now() - shutdown_started_;
- std::string shutdown_ms = Int64ToString(shutdown_delta.InMilliseconds());
+ std::string shutdown_ms =
+ base::Int64ToString(shutdown_delta.InMilliseconds());
int len = static_cast<int>(shutdown_ms.length()) + 1;
FilePath shutdown_ms_file = GetShutdownMsPath();
file_util::WriteFile(shutdown_ms_file, shutdown_ms.c_str(), len);
@@ -226,7 +231,7 @@ void ReadLastShutdownFile(
std::string shutdown_ms_str;
int64 shutdown_ms = 0;
if (file_util::ReadFileToString(shutdown_ms_file, &shutdown_ms_str))
- shutdown_ms = StringToInt64(shutdown_ms_str);
+ base::StringToInt64(shutdown_ms_str, &shutdown_ms);
file_util::Delete(shutdown_ms_file, false);
if (type == NOT_VALID || shutdown_ms == 0 || num_procs == 0)
@@ -287,4 +292,12 @@ bool IsTryingToQuit() {
return g_trying_to_quit;
}
+bool ShuttingDownWithoutClosingBrowsers() {
+#if defined(USE_X11)
+ if (GetShutdownType() == browser_shutdown::END_SESSION)
+ return true;
+#endif
+ return false;
+}
+
} // namespace browser_shutdown
diff --git a/chrome/browser/browser_shutdown.h b/chrome/browser/browser_shutdown.h
index c782f36..0df2919 100644
--- a/chrome/browser/browser_shutdown.h
+++ b/chrome/browser/browser_shutdown.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BROWSER_SHUTDOWN_H__
#define CHROME_BROWSER_BROWSER_SHUTDOWN_H__
+#pragma once
class PrefService;
@@ -65,6 +66,11 @@ void SetTryingToQuit(bool quitting);
// General accessor.
bool IsTryingToQuit();
+// This is true on X during an END_SESSION, when we can no longer depend
+// on the X server to be running. As a result we don't explicitly close the
+// browser windows, which can lead to conditions which would fail checks.
+bool ShuttingDownWithoutClosingBrowsers();
+
} // namespace browser_shutdown
#endif // CHROME_BROWSER_BROWSER_SHUTDOWN_H__
diff --git a/chrome/browser/browser_theme_pack.cc b/chrome/browser/browser_theme_pack.cc
deleted file mode 100644
index 7e1dc8e..0000000
--- a/chrome/browser/browser_theme_pack.cc
+++ /dev/null
@@ -1,1037 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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_theme_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/utf_string_conversions.h"
-#include "chrome/browser/browser_theme_provider.h"
-#include "chrome/browser/chrome_thread.h"
-#include "gfx/codec/png_codec.h"
-#include "gfx/skbitmap_operations.h"
-#include "grit/app_resources.h"
-#include "grit/theme_resources.h"
-#include "net/base/file_stream.h"
-#include "net/base/net_errors.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-
-namespace {
-
-// Version number of the current theme pack. We just throw out and rebuild
-// theme packs that aren't int-equal to this.
-const int kThemePackVersion = 13;
-
-// IDs that are in the DataPack won't clash with the positive integer
-// int32_t. kHeaderID should always have the maximum value because we want the
-// "header" to be written last. That way we can detect whether the pack was
-// successfully written and ignore and regenerate if it was only partially
-// written (i.e. chrome crashed on a different thread while writing the pack).
-const int kHeaderID = UINT_MAX - 1;
-const int kTintsID = UINT_MAX - 2;
-const int kColorsID = UINT_MAX - 3;
-const int kDisplayPropertiesID = UINT_MAX - 4;
-const int kSourceImagesID = UINT_MAX - 5;
-
-// Static size of the tint/color/display property arrays that are mmapped.
-const int kTintArraySize = 6;
-const int kColorArraySize = 19;
-const int kDisplayPropertySize = 3;
-
-// The sum of kFrameBorderThickness and kNonClientRestoredExtraThickness from
-// OpaqueBrowserFrameView.
-const int kRestoredTabVerticalOffset = 15;
-
-// Persistent constants for the main images that we need. These have the same
-// names as their IDR_* counterparts but these values will always stay the
-// same.
-const int PRS_THEME_FRAME = 1;
-const int PRS_THEME_FRAME_INACTIVE = 2;
-const int PRS_THEME_FRAME_INCOGNITO = 3;
-const int PRS_THEME_FRAME_INCOGNITO_INACTIVE = 4;
-const int PRS_THEME_TOOLBAR = 5;
-const int PRS_THEME_TAB_BACKGROUND = 6;
-const int PRS_THEME_TAB_BACKGROUND_INCOGNITO = 7;
-const int PRS_THEME_TAB_BACKGROUND_V = 8;
-const int PRS_THEME_NTP_BACKGROUND = 9;
-const int PRS_THEME_FRAME_OVERLAY = 10;
-const int PRS_THEME_FRAME_OVERLAY_INACTIVE = 11;
-const int PRS_THEME_BUTTON_BACKGROUND = 12;
-const int PRS_THEME_NTP_ATTRIBUTION = 13;
-const int PRS_THEME_WINDOW_CONTROL_BACKGROUND = 14;
-
-struct PersistingImagesTable {
- // A non-changing integer ID meant to be saved in theme packs. This ID must
- // not change between versions of chrome.
- int persistent_id;
-
- // The IDR that depends on the whims of GRIT and therefore changes whenever
- // someone adds a new resource.
- int idr_id;
-
- // String to check for when parsing theme manifests or NULL if this isn't
- // supposed to be changeable by the user.
- const char* key;
-};
-
-// IDR_* resource names change whenever new resources are added; use persistent
-// IDs when storing to a cached pack.
-PersistingImagesTable kPersistingImages[] = {
- { PRS_THEME_FRAME, IDR_THEME_FRAME,
- "theme_frame" },
- { PRS_THEME_FRAME_INACTIVE, IDR_THEME_FRAME_INACTIVE,
- "theme_frame_inactive" },
- { PRS_THEME_FRAME_INCOGNITO, IDR_THEME_FRAME_INCOGNITO,
- "theme_frame_incognito" },
- { PRS_THEME_FRAME_INCOGNITO_INACTIVE, IDR_THEME_FRAME_INCOGNITO_INACTIVE,
- "theme_frame_incognito_inactive" },
- { PRS_THEME_TOOLBAR, IDR_THEME_TOOLBAR,
- "theme_toolbar" },
- { PRS_THEME_TAB_BACKGROUND, IDR_THEME_TAB_BACKGROUND,
- "theme_tab_background" },
- { PRS_THEME_TAB_BACKGROUND_INCOGNITO, IDR_THEME_TAB_BACKGROUND_INCOGNITO,
- "theme_tab_background_incognito" },
- { PRS_THEME_TAB_BACKGROUND_V, IDR_THEME_TAB_BACKGROUND_V,
- "theme_tab_background_v"},
- { PRS_THEME_NTP_BACKGROUND, IDR_THEME_NTP_BACKGROUND,
- "theme_ntp_background" },
- { PRS_THEME_FRAME_OVERLAY, IDR_THEME_FRAME_OVERLAY,
- "theme_frame_overlay" },
- { PRS_THEME_FRAME_OVERLAY_INACTIVE, IDR_THEME_FRAME_OVERLAY_INACTIVE,
- "theme_frame_overlay_inactive" },
- { PRS_THEME_BUTTON_BACKGROUND, IDR_THEME_BUTTON_BACKGROUND,
- "theme_button_background" },
- { PRS_THEME_NTP_ATTRIBUTION, IDR_THEME_NTP_ATTRIBUTION,
- "theme_ntp_attribution" },
- { PRS_THEME_WINDOW_CONTROL_BACKGROUND, IDR_THEME_WINDOW_CONTROL_BACKGROUND,
- "theme_window_control_background"},
-
- // The rest of these entries have no key because they can't be overridden
- // from the json manifest.
- { 15, IDR_BACK, NULL },
- { 16, IDR_BACK_D, NULL },
- { 17, IDR_BACK_H, NULL },
- { 18, IDR_BACK_P, NULL },
- { 19, IDR_FORWARD, NULL },
- { 20, IDR_FORWARD_D, NULL },
- { 21, IDR_FORWARD_H, NULL },
- { 22, IDR_FORWARD_P, NULL },
- { 23, IDR_HOME, NULL },
- { 24, IDR_HOME_H, NULL },
- { 25, IDR_HOME_P, NULL },
- { 26, IDR_RELOAD, NULL },
- { 27, IDR_RELOAD_H, NULL },
- { 28, IDR_RELOAD_P, NULL },
- { 29, IDR_STOP, NULL },
- { 30, IDR_STOP_H, NULL },
- { 31, IDR_STOP_P, NULL },
- { 32, IDR_LOCATIONBG_C, NULL },
- { 33, IDR_LOCATIONBG_L, NULL },
- { 34, IDR_LOCATIONBG_R, NULL },
- { 35, IDR_TOOLS, NULL },
- { 36, IDR_MENU_DROPARROW, NULL },
- { 37, IDR_THROBBER, NULL },
- { 38, IDR_THROBBER_WAITING, NULL },
- { 39, IDR_THROBBER_LIGHT, NULL },
-};
-
-int GetPersistentIDByName(const std::string& key) {
- for (size_t i = 0; i < arraysize(kPersistingImages); ++i) {
- if (kPersistingImages[i].key != NULL &&
- base::strcasecmp(key.c_str(), kPersistingImages[i].key) == 0) {
- return kPersistingImages[i].persistent_id;
- }
- }
-
- return -1;
-}
-
-int GetPersistentIDByIDR(int idr) {
- for (size_t i = 0; i < arraysize(kPersistingImages); ++i) {
- if (kPersistingImages[i].idr_id == idr) {
- return kPersistingImages[i].persistent_id;
- }
- }
-
- return -1;
-}
-
-struct StringToIntTable {
- const char* key;
- int id;
-};
-
-// Strings used by themes to identify tints in the JSON.
-StringToIntTable kTintTable[] = {
- { "buttons", BrowserThemeProvider::TINT_BUTTONS },
- { "frame", BrowserThemeProvider::TINT_FRAME },
- { "frame_inactive", BrowserThemeProvider::TINT_FRAME_INACTIVE },
- { "frame_incognito", BrowserThemeProvider::TINT_FRAME_INCOGNITO },
- { "frame_incognito_inactive",
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE },
- { "background_tab", BrowserThemeProvider::TINT_BACKGROUND_TAB },
- { NULL, 0 }
-};
-
-// Strings used by themes to identify colors in the JSON.
-StringToIntTable kColorTable[] = {
- { "frame", BrowserThemeProvider::COLOR_FRAME },
- { "frame_inactive", BrowserThemeProvider::COLOR_FRAME_INACTIVE },
- { "frame_incognito", BrowserThemeProvider::COLOR_FRAME_INCOGNITO },
- { "frame_incognito_inactive",
- BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE },
- { "toolbar", BrowserThemeProvider::COLOR_TOOLBAR },
- { "tab_text", BrowserThemeProvider::COLOR_TAB_TEXT },
- { "tab_background_text", BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT },
- { "bookmark_text", BrowserThemeProvider::COLOR_BOOKMARK_TEXT },
- { "ntp_background", BrowserThemeProvider::COLOR_NTP_BACKGROUND },
- { "ntp_text", BrowserThemeProvider::COLOR_NTP_TEXT },
- { "ntp_link", BrowserThemeProvider::COLOR_NTP_LINK },
- { "ntp_link_underline", BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE },
- { "ntp_header", BrowserThemeProvider::COLOR_NTP_HEADER },
- { "ntp_section", BrowserThemeProvider::COLOR_NTP_SECTION },
- { "ntp_section_text", BrowserThemeProvider::COLOR_NTP_SECTION_TEXT },
- { "ntp_section_link", BrowserThemeProvider::COLOR_NTP_SECTION_LINK },
- { "ntp_section_link_underline",
- BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE },
- { "control_background", BrowserThemeProvider::COLOR_CONTROL_BACKGROUND },
- { "button_background", BrowserThemeProvider::COLOR_BUTTON_BACKGROUND },
- { NULL, 0 }
-};
-
-// Strings used by themes to identify display properties keys in JSON.
-StringToIntTable kDisplayProperties[] = {
- { "ntp_background_alignment",
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT },
- { "ntp_background_repeat", BrowserThemeProvider::NTP_BACKGROUND_TILING },
- { "ntp_logo_alternate", BrowserThemeProvider::NTP_LOGO_ALTERNATE },
- { NULL, 0 }
-};
-
-// Strings used by the tiling values in JSON.
-StringToIntTable kTilingStrings[] = {
- { "no-repeat", BrowserThemeProvider::NO_REPEAT },
- { "repeat-x", BrowserThemeProvider::REPEAT_X },
- { "repeat-y", BrowserThemeProvider::REPEAT_Y },
- { "repeat", BrowserThemeProvider::REPEAT },
- { NULL, 0 }
-};
-
-int GetIntForString(const std::string& key, StringToIntTable* table) {
- for (int i = 0; table[i].key != NULL; ++i) {
- if (base::strcasecmp(key.c_str(), table[i].key) == 0) {
- return table[i].id;
- }
- }
-
- return -1;
-}
-
-struct IntToIntTable {
- int key;
- int value;
-};
-
-// Mapping used in GenerateFrameImages() to associate frame images with the
-// tint ID that should maybe be applied to it.
-IntToIntTable kFrameTintMap[] = {
- { PRS_THEME_FRAME, BrowserThemeProvider::TINT_FRAME },
- { PRS_THEME_FRAME_INACTIVE, BrowserThemeProvider::TINT_FRAME_INACTIVE },
- { PRS_THEME_FRAME_OVERLAY, BrowserThemeProvider::TINT_FRAME },
- { PRS_THEME_FRAME_OVERLAY_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INACTIVE },
- { PRS_THEME_FRAME_INCOGNITO, BrowserThemeProvider::TINT_FRAME_INCOGNITO },
- { PRS_THEME_FRAME_INCOGNITO_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE }
-};
-
-// Mapping used in GenerateTabBackgroundImages() to associate what frame image
-// goes with which tab background.
-IntToIntTable kTabBackgroundMap[] = {
- { PRS_THEME_TAB_BACKGROUND, PRS_THEME_FRAME },
- { PRS_THEME_TAB_BACKGROUND_INCOGNITO, PRS_THEME_FRAME_INCOGNITO }
-};
-
-// A list of images that don't need tinting or any other modification and can
-// be byte-copied directly into the finished DataPack. This should contain the
-// persistent IDs for all themeable image IDs that aren't in kFrameTintMap or
-// kTabBackgroundMap.
-const int kPreloadIDs[] = {
- PRS_THEME_TOOLBAR,
- PRS_THEME_NTP_BACKGROUND,
- PRS_THEME_BUTTON_BACKGROUND,
- PRS_THEME_NTP_ATTRIBUTION,
- PRS_THEME_WINDOW_CONTROL_BACKGROUND
-};
-
-// Returns a piece of memory with the contents of the file |path|.
-RefCountedMemory* ReadFileData(const FilePath& path) {
- if (!path.empty()) {
- net::FileStream file;
- int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
- if (file.Open(path, flags) == net::OK) {
- int64 avail = file.Available();
- if (avail > 0 && avail < INT_MAX) {
- size_t size = static_cast<size_t>(avail);
- std::vector<unsigned char> raw_data;
- raw_data.resize(size);
- char* data = reinterpret_cast<char*>(&(raw_data.front()));
- if (file.ReadUntilComplete(data, size) == avail)
- return RefCountedBytes::TakeVector(&raw_data);
- }
- }
- }
-
- return NULL;
-}
-
-// Does error checking for invalid incoming data while trying to read an
-// floating point value.
-bool ValidRealValue(ListValue* tint_list, int index, double* out) {
- if (tint_list->GetReal(index, out))
- return true;
-
- int value = 0;
- if (tint_list->GetInteger(index, &value)) {
- *out = value;
- return true;
- }
-
- return false;
-}
-
-} // namespace
-
-BrowserThemePack::~BrowserThemePack() {
- if (!data_pack_.get()) {
- delete header_;
- delete [] tints_;
- delete [] colors_;
- delete [] display_properties_;
- delete [] source_images_;
- }
-
- STLDeleteValues(&prepared_images_);
- STLDeleteValues(&loaded_images_);
-}
-
-// static
-BrowserThemePack* BrowserThemePack::BuildFromExtension(Extension* extension) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- DCHECK(extension);
- DCHECK(extension->is_theme());
-
- BrowserThemePack* pack = new BrowserThemePack;
- pack->BuildHeader(extension);
- pack->BuildTintsFromJSON(extension->GetThemeTints());
- pack->BuildColorsFromJSON(extension->GetThemeColors());
- pack->BuildDisplayPropertiesFromJSON(extension->GetThemeDisplayProperties());
-
- // Builds the images. (Image building is dependent on tints).
- FilePathMap file_paths;
- pack->ParseImageNamesFromJSON(extension->GetThemeImages(),
- extension->path(),
- &file_paths);
- pack->BuildSourceImagesArray(file_paths);
-
- if (!pack->LoadRawBitmapsTo(file_paths, &pack->prepared_images_))
- return NULL;
-
- pack->GenerateFrameImages(&pack->prepared_images_);
-
-#if !defined(OS_MACOSX)
- // OSX uses its own special buttons that are PDFs that do odd sorts of vector
- // graphics tricks. Other platforms use bitmaps and we must pre-tint them.
- pack->GenerateTintedButtons(
- pack->GetTintInternal(BrowserThemeProvider::TINT_BUTTONS),
- &pack->prepared_images_);
-#endif
-
- pack->GenerateTabBackgroundImages(&pack->prepared_images_);
-
- // The BrowserThemePack is now in a consistent state.
- return pack;
-}
-
-// static
-scoped_refptr<BrowserThemePack> BrowserThemePack::BuildFromDataPack(
- FilePath path, const std::string& expected_id) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- scoped_refptr<BrowserThemePack> pack = new BrowserThemePack;
- pack->data_pack_.reset(new base::DataPack);
-
- if (!pack->data_pack_->Load(path)) {
- LOG(ERROR) << "Failed to load theme data pack.";
- return NULL;
- }
-
- base::StringPiece pointer;
- if (!pack->data_pack_->GetStringPiece(kHeaderID, &pointer))
- return NULL;
- pack->header_ = reinterpret_cast<BrowserThemePackHeader*>(const_cast<char*>(
- pointer.data()));
-
- if (pack->header_->version != kThemePackVersion) {
- DLOG(ERROR) << "BuildFromDataPack failure! Version mismatch!";
- return NULL;
- }
- // TODO(erg): Check endianess once DataPack works on the other endian.
- std::string theme_id(reinterpret_cast<char*>(pack->header_->theme_id),
- Extension::kIdSize);
- std::string truncated_id = expected_id.substr(0, Extension::kIdSize);
- if (theme_id != truncated_id) {
- DLOG(ERROR) << "Wrong id: " << theme_id << " vs " << expected_id;
- return NULL;
- }
-
- if (!pack->data_pack_->GetStringPiece(kTintsID, &pointer))
- return NULL;
- pack->tints_ = reinterpret_cast<TintEntry*>(const_cast<char*>(
- pointer.data()));
-
- if (!pack->data_pack_->GetStringPiece(kColorsID, &pointer))
- return NULL;
- pack->colors_ =
- reinterpret_cast<ColorPair*>(const_cast<char*>(pointer.data()));
-
- if (!pack->data_pack_->GetStringPiece(kDisplayPropertiesID, &pointer))
- return NULL;
- pack->display_properties_ = reinterpret_cast<DisplayPropertyPair*>(
- const_cast<char*>(pointer.data()));
-
- if (!pack->data_pack_->GetStringPiece(kSourceImagesID, &pointer))
- return NULL;
- pack->source_images_ = reinterpret_cast<int*>(
- const_cast<char*>(pointer.data()));
-
- return pack;
-}
-
-bool BrowserThemePack::WriteToDisk(FilePath path) const {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- // Add resources for each of the property arrays.
- RawDataForWriting resources;
- resources[kHeaderID] = base::StringPiece(
- reinterpret_cast<const char*>(header_), sizeof(BrowserThemePackHeader));
- resources[kTintsID] = base::StringPiece(
- reinterpret_cast<const char*>(tints_), sizeof(TintEntry[kTintArraySize]));
- resources[kColorsID] = base::StringPiece(
- reinterpret_cast<const char*>(colors_),
- sizeof(ColorPair[kColorArraySize]));
- resources[kDisplayPropertiesID] = base::StringPiece(
- reinterpret_cast<const char*>(display_properties_),
- sizeof(DisplayPropertyPair[kDisplayPropertySize]));
-
- int source_count = 1;
- int* end = source_images_;
- for (; *end != -1 ; end++)
- source_count++;
- resources[kSourceImagesID] = base::StringPiece(
- reinterpret_cast<const char*>(source_images_),
- source_count * sizeof(*source_images_));
-
- AddRawImagesTo(image_memory_, &resources);
-
- RawImages reencoded_images;
- RepackImages(prepared_images_, &reencoded_images);
- AddRawImagesTo(reencoded_images, &resources);
-
- return base::DataPack::WritePack(path, resources);
-}
-
-bool BrowserThemePack::GetTint(int id, color_utils::HSL* hsl) const {
- if (tints_) {
- for (int i = 0; i < kTintArraySize; ++i) {
- if (tints_[i].id == id) {
- hsl->h = tints_[i].h;
- hsl->s = tints_[i].s;
- hsl->l = tints_[i].l;
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool BrowserThemePack::GetColor(int id, SkColor* color) const {
- if (colors_) {
- for (int i = 0; i < kColorArraySize; ++i) {
- if (colors_[i].id == id) {
- *color = colors_[i].color;
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool BrowserThemePack::GetDisplayProperty(int id, int* result) const {
- if (display_properties_) {
- for (int i = 0; i < kDisplayPropertySize; ++i) {
- if (display_properties_[i].id == id) {
- *result = display_properties_[i].property;
- return true;
- }
- }
- }
-
- return false;
-}
-
-SkBitmap* BrowserThemePack::GetBitmapNamed(int idr_id) const {
- int prs_id = GetPersistentIDByIDR(idr_id);
- if (prs_id == -1)
- return NULL;
-
- // Check our cache of prepared images, first.
- ImageCache::const_iterator image_iter = prepared_images_.find(prs_id);
- if (image_iter != prepared_images_.end())
- return image_iter->second;
-
- // Check if we've already loaded this image.
- image_iter = loaded_images_.find(prs_id);
- if (image_iter != loaded_images_.end())
- return image_iter->second;
-
- scoped_refptr<RefCountedMemory> memory;
- if (data_pack_.get()) {
- memory = data_pack_->GetStaticMemory(prs_id);
- } else {
- RawImages::const_iterator it = image_memory_.find(prs_id);
- if (it != image_memory_.end()) {
- memory = it->second;
- }
- }
-
- if (memory.get()) {
- // Decode the PNG.
- SkBitmap bitmap;
- if (!gfx::PNGCodec::Decode(memory->front(), memory->size(),
- &bitmap)) {
- NOTREACHED() << "Unable to decode theme image resource " << idr_id
- << " from saved DataPack.";
- return NULL;
- }
-
- SkBitmap* ret = new SkBitmap(bitmap);
- loaded_images_[prs_id] = ret;
-
- return ret;
- }
-
- return NULL;
-}
-
-RefCountedMemory* BrowserThemePack::GetRawData(int idr_id) const {
- RefCountedMemory* memory = NULL;
- int prs_id = GetPersistentIDByIDR(idr_id);
-
- if (prs_id != -1) {
- if (data_pack_.get()) {
- memory = data_pack_->GetStaticMemory(prs_id);
- } else {
- RawImages::const_iterator it = image_memory_.find(prs_id);
- if (it != image_memory_.end()) {
- memory = it->second;
- }
- }
- }
-
- return memory;
-}
-
-bool BrowserThemePack::HasCustomImage(int idr_id) const {
- int prs_id = GetPersistentIDByIDR(idr_id);
- if (prs_id == -1)
- return false;
-
- int* img = source_images_;
- for (; *img != -1; ++img) {
- if (*img == prs_id)
- return true;
- }
-
- return false;
-}
-
-// private:
-
-BrowserThemePack::BrowserThemePack()
- : header_(NULL),
- tints_(NULL),
- colors_(NULL),
- display_properties_(NULL),
- source_images_(NULL) {
-}
-
-void BrowserThemePack::BuildHeader(Extension* extension) {
- header_ = new BrowserThemePackHeader;
- header_->version = kThemePackVersion;
-
- // TODO(erg): Need to make this endian safe on other computers. Prerequisite
- // is that base::DataPack removes this same check.
-#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
- header_->little_endian = 1;
-
- const std::string& id = extension->id();
- memcpy(header_->theme_id, id.c_str(), Extension::kIdSize);
-}
-
-void BrowserThemePack::BuildTintsFromJSON(DictionaryValue* tints_value) {
- tints_ = new TintEntry[kTintArraySize];
- for (int i = 0; i < kTintArraySize; ++i) {
- tints_[i].id = -1;
- tints_[i].h = -1;
- tints_[i].s = -1;
- tints_[i].l = -1;
- }
-
- if (!tints_value)
- return;
-
- // Parse the incoming data from |tints_value| into an intermediary structure.
- std::map<int, color_utils::HSL> temp_tints;
- for (DictionaryValue::key_iterator iter(tints_value->begin_keys());
- iter != tints_value->end_keys(); ++iter) {
- ListValue* tint_list;
- if (tints_value->GetList(*iter, &tint_list) &&
- (tint_list->GetSize() == 3)) {
- color_utils::HSL hsl = { -1, -1, -1 };
-
- if (ValidRealValue(tint_list, 0, &hsl.h) &&
- ValidRealValue(tint_list, 1, &hsl.s) &&
- ValidRealValue(tint_list, 2, &hsl.l)) {
- int id = GetIntForString(WideToUTF8(*iter), kTintTable);
- if (id != -1) {
- temp_tints[id] = hsl;
- }
- }
- }
- }
-
- // Copy data from the intermediary data structure to the array.
- int count = 0;
- for (std::map<int, color_utils::HSL>::const_iterator it =
- temp_tints.begin(); it != temp_tints.end() && count < kTintArraySize;
- ++it, ++count) {
- tints_[count].id = it->first;
- tints_[count].h = it->second.h;
- tints_[count].s = it->second.s;
- tints_[count].l = it->second.l;
- }
-}
-
-void BrowserThemePack::BuildColorsFromJSON(DictionaryValue* colors_value) {
- colors_ = new ColorPair[kColorArraySize];
- for (int i = 0; i < kColorArraySize; ++i) {
- colors_[i].id = -1;
- colors_[i].color = SkColorSetRGB(0, 0, 0);
- }
-
- std::map<int, SkColor> temp_colors;
- if (colors_value)
- ReadColorsFromJSON(colors_value, &temp_colors);
- GenerateMissingColors(&temp_colors);
-
- // Copy data from the intermediary data structure to the array.
- int count = 0;
- for (std::map<int, SkColor>::const_iterator it = temp_colors.begin();
- it != temp_colors.end() && count < kColorArraySize; ++it, ++count) {
- colors_[count].id = it->first;
- colors_[count].color = it->second;
- }
-}
-
-void BrowserThemePack::ReadColorsFromJSON(
- DictionaryValue* colors_value,
- std::map<int, SkColor>* temp_colors) {
- // Parse the incoming data from |colors_value| into an intermediary structure.
- for (DictionaryValue::key_iterator iter(colors_value->begin_keys());
- iter != colors_value->end_keys(); ++iter) {
- ListValue* color_list;
- if (colors_value->GetList(*iter, &color_list) &&
- ((color_list->GetSize() == 3) || (color_list->GetSize() == 4))) {
- SkColor color = SK_ColorWHITE;
- int r, g, b;
- if (color_list->GetInteger(0, &r) &&
- color_list->GetInteger(1, &g) &&
- color_list->GetInteger(2, &b)) {
- if (color_list->GetSize() == 4) {
- double alpha;
- int alpha_int;
- if (color_list->GetReal(3, &alpha)) {
- color = SkColorSetARGB(static_cast<int>(alpha * 255), r, g, b);
- } else if (color_list->GetInteger(3, &alpha_int) &&
- (alpha_int == 0 || alpha_int == 1)) {
- color = SkColorSetARGB(alpha_int ? 255 : 0, r, g, b);
- } else {
- // Invalid entry for part 4.
- continue;
- }
- } else {
- color = SkColorSetRGB(r, g, b);
- }
-
- int id = GetIntForString(WideToUTF8(*iter), kColorTable);
- if (id != -1) {
- (*temp_colors)[id] = color;
- }
- }
- }
- }
-}
-
-void BrowserThemePack::GenerateMissingColors(
- std::map<int, SkColor>* colors) {
- // Generate link colors, if missing. (See GetColor()).
- if (!colors->count(BrowserThemeProvider::COLOR_NTP_HEADER) &&
- colors->count(BrowserThemeProvider::COLOR_NTP_SECTION)) {
- (*colors)[BrowserThemeProvider::COLOR_NTP_HEADER] =
- (*colors)[BrowserThemeProvider::COLOR_NTP_SECTION];
- }
-
- if (!colors->count(BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE) &&
- colors->count(BrowserThemeProvider::COLOR_NTP_SECTION_LINK)) {
- SkColor color_section_link =
- (*colors)[BrowserThemeProvider::COLOR_NTP_SECTION_LINK];
- (*colors)[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
- SkColorSetA(color_section_link, SkColorGetA(color_section_link) / 3);
- }
-
- if (!colors->count(BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE) &&
- colors->count(BrowserThemeProvider::COLOR_NTP_LINK)) {
- SkColor color_link = (*colors)[BrowserThemeProvider::COLOR_NTP_LINK];
- (*colors)[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] =
- SkColorSetA(color_link, SkColorGetA(color_link) / 3);
- }
-
- // Generate frame colors, if missing. (See GenerateFrameColors()).
- SkColor frame;
- std::map<int, SkColor>::const_iterator it =
- colors->find(BrowserThemeProvider::COLOR_FRAME);
- if (it != colors->end()) {
- frame = it->second;
- } else {
- frame = BrowserThemeProvider::GetDefaultColor(
- BrowserThemeProvider::COLOR_FRAME);
- }
-
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME] =
- HSLShift(frame, GetTintInternal(BrowserThemeProvider::TINT_FRAME));
- }
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME_INACTIVE)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME_INACTIVE] =
- HSLShift(frame, GetTintInternal(
- BrowserThemeProvider::TINT_FRAME_INACTIVE));
- }
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME_INCOGNITO)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME_INCOGNITO] =
- HSLShift(frame, GetTintInternal(
- BrowserThemeProvider::TINT_FRAME_INCOGNITO));
- }
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE] =
- HSLShift(frame, GetTintInternal(
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE));
- }
-}
-
-void BrowserThemePack::BuildDisplayPropertiesFromJSON(
- DictionaryValue* display_properties_value) {
- display_properties_ = new DisplayPropertyPair[kDisplayPropertySize];
- for (int i = 0; i < kDisplayPropertySize; ++i) {
- display_properties_[i].id = -1;
- display_properties_[i].property = 0;
- }
-
- if (!display_properties_value)
- return;
-
- std::map<int, int> temp_properties;
- for (DictionaryValue::key_iterator iter(
- display_properties_value->begin_keys());
- iter != display_properties_value->end_keys(); ++iter) {
- int property_id = GetIntForString(WideToUTF8(*iter), kDisplayProperties);
- switch (property_id) {
- case BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT: {
- std::string val;
- if (display_properties_value->GetString(*iter, &val)) {
- temp_properties[BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT] =
- BrowserThemeProvider::StringToAlignment(val);
- }
- break;
- }
- case BrowserThemeProvider::NTP_BACKGROUND_TILING: {
- std::string val;
- if (display_properties_value->GetString(*iter, &val)) {
- temp_properties[BrowserThemeProvider::NTP_BACKGROUND_TILING] =
- GetIntForString(val, kTilingStrings);
- }
- break;
- }
- case BrowserThemeProvider::NTP_LOGO_ALTERNATE: {
- int val = 0;
- if (display_properties_value->GetInteger(*iter, &val))
- temp_properties[BrowserThemeProvider::NTP_LOGO_ALTERNATE] = val;
- break;
- }
- }
- }
-
- // Copy data from the intermediary data structure to the array.
- int count = 0;
- for (std::map<int, int>::const_iterator it = temp_properties.begin();
- it != temp_properties.end() && count < kDisplayPropertySize;
- ++it, ++count) {
- display_properties_[count].id = it->first;
- display_properties_[count].property = it->second;
- }
-}
-
-void BrowserThemePack::ParseImageNamesFromJSON(
- DictionaryValue* images_value,
- FilePath images_path,
- FilePathMap* file_paths) const {
- if (!images_value)
- return;
-
- for (DictionaryValue::key_iterator iter(images_value->begin_keys());
- iter != images_value->end_keys(); ++iter) {
- std::string val;
- if (images_value->GetString(*iter, &val)) {
- int id = GetPersistentIDByName(WideToUTF8(*iter));
- if (id != -1)
- (*file_paths)[id] = images_path.AppendASCII(val);
- }
- }
-}
-
-void BrowserThemePack::BuildSourceImagesArray(const FilePathMap& file_paths) {
- std::vector<int> ids;
- for (FilePathMap::const_iterator it = file_paths.begin();
- it != file_paths.end(); ++it) {
- ids.push_back(it->first);
- }
-
- source_images_ = new int[ids.size() + 1];
- std::copy(ids.begin(), ids.end(), source_images_);
- source_images_[ids.size()] = -1;
-}
-
-bool BrowserThemePack::LoadRawBitmapsTo(
- const FilePathMap& file_paths,
- ImageCache* raw_bitmaps) {
- for (FilePathMap::const_iterator it = file_paths.begin();
- it != file_paths.end(); ++it) {
- scoped_refptr<RefCountedMemory> raw_data(ReadFileData(it->second));
- if (!raw_data.get()) {
- LOG(ERROR) << "Could not load theme image";
- return false;
- }
-
- int id = it->first;
-
- // Some images need to go directly into |image_memory_|. No modification is
- // necessary or desirable.
- bool is_copyable = false;
- for (size_t i = 0; i < arraysize(kPreloadIDs); ++i) {
- if (kPreloadIDs[i] == id) {
- is_copyable = true;
- break;
- }
- }
-
- if (is_copyable) {
- image_memory_[id] = raw_data;
- } else if (raw_data.get() && raw_data->size()) {
- // Decode the PNG.
- SkBitmap bitmap;
- if (gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
- &bitmap)) {
- (*raw_bitmaps)[it->first] = new SkBitmap(bitmap);
- } else {
- NOTREACHED() << "Unable to decode theme image resource " << it->first;
- }
- }
- }
-
- return true;
-}
-
-void BrowserThemePack::GenerateFrameImages(ImageCache* bitmaps) const {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-
- // Create all the output bitmaps in a separate cache and move them back into
- // the input bitmaps because there can be name collisions.
- ImageCache temp_output;
-
- for (size_t i = 0; i < arraysize(kFrameTintMap); ++i) {
- int prs_id = kFrameTintMap[i].key;
- scoped_ptr<SkBitmap> frame;
- // If there's no frame image provided for the specified id, then load
- // the default provided frame. If that's not provided, skip this whole
- // thing and just use the default images.
- int prs_base_id;
-
- if (prs_id == PRS_THEME_FRAME_INCOGNITO_INACTIVE) {
- prs_base_id = bitmaps->count(PRS_THEME_FRAME_INCOGNITO) ?
- PRS_THEME_FRAME_INCOGNITO : PRS_THEME_FRAME;
- } else if (prs_id == PRS_THEME_FRAME_OVERLAY_INACTIVE) {
- prs_base_id = PRS_THEME_FRAME_OVERLAY;
- } else if (prs_id == PRS_THEME_FRAME_INACTIVE) {
- prs_base_id = PRS_THEME_FRAME;
- } else if (prs_id == PRS_THEME_FRAME_INCOGNITO &&
- !bitmaps->count(PRS_THEME_FRAME_INCOGNITO)) {
- prs_base_id = PRS_THEME_FRAME;
- } else {
- prs_base_id = prs_id;
- }
-
- if (bitmaps->count(prs_id)) {
- frame.reset(new SkBitmap(*(*bitmaps)[prs_id]));
- } else if (prs_base_id != prs_id && bitmaps->count(prs_base_id)) {
- frame.reset(new SkBitmap(*(*bitmaps)[prs_base_id]));
- } else if (prs_base_id == PRS_THEME_FRAME_OVERLAY &&
- bitmaps->count(PRS_THEME_FRAME)) {
- // If there is no theme overlay, don't tint the default frame,
- // because it will overwrite the custom frame image when we cache and
- // reload from disk.
- frame.reset(NULL);
- } else {
- // If the theme doesn't specify an image, then apply the tint to
- // the default frame.
- frame.reset(new SkBitmap(*rb.GetBitmapNamed(IDR_THEME_FRAME)));
- }
-
- if (frame.get()) {
- temp_output[prs_id] = new SkBitmap(
- SkBitmapOperations::CreateHSLShiftedBitmap(
- *frame, GetTintInternal(kFrameTintMap[i].value)));
- }
- }
-
- MergeImageCaches(temp_output, bitmaps);
-}
-
-void BrowserThemePack::GenerateTintedButtons(
- color_utils::HSL button_tint,
- ImageCache* processed_bitmaps) const {
- if (button_tint.h != -1 || button_tint.s != -1 || button_tint.l != -1) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- const std::set<int>& idr_ids =
- BrowserThemeProvider::GetTintableToolbarButtons();
- for (std::set<int>::const_iterator it = idr_ids.begin();
- it != idr_ids.end(); ++it) {
- int prs_id = GetPersistentIDByIDR(*it);
- DCHECK(prs_id > 0);
-
- // Fetch the image by IDR...
- scoped_ptr<SkBitmap> button(new SkBitmap(*rb.GetBitmapNamed(*it)));
-
- // but save a version with the persistent ID.
- (*processed_bitmaps)[prs_id] = new SkBitmap(
- SkBitmapOperations::CreateHSLShiftedBitmap(*button, button_tint));
- }
- }
-}
-
-void BrowserThemePack::GenerateTabBackgroundImages(ImageCache* bitmaps) const {
- ImageCache temp_output;
- for (size_t i = 0; i < arraysize(kTabBackgroundMap); ++i) {
- int prs_id = kTabBackgroundMap[i].key;
- int prs_base_id = kTabBackgroundMap[i].value;
-
- // We only need to generate the background tab images if we were provided
- // with a PRS_THEME_FRAME.
- ImageCache::const_iterator it = bitmaps->find(prs_base_id);
- if (it != bitmaps->end()) {
- SkBitmap bg_tint = SkBitmapOperations::CreateHSLShiftedBitmap(
- *(it->second), GetTintInternal(
- BrowserThemeProvider::TINT_BACKGROUND_TAB));
- int vertical_offset = bitmaps->count(prs_id)
- ? kRestoredTabVerticalOffset : 0;
- SkBitmap* bg_tab = new SkBitmap(SkBitmapOperations::CreateTiledBitmap(
- bg_tint, 0, vertical_offset, bg_tint.width(), bg_tint.height()));
-
- // If they've provided a custom image, overlay it.
- ImageCache::const_iterator overlay_it = bitmaps->find(prs_id);
- if (overlay_it != bitmaps->end()) {
- SkBitmap* overlay = overlay_it->second;
- SkCanvas canvas(*bg_tab);
- for (int x = 0; x < bg_tab->width(); x += overlay->width())
- canvas.drawBitmap(*overlay, static_cast<SkScalar>(x), 0, NULL);
- }
-
- temp_output[prs_id] = bg_tab;
- }
- }
-
- MergeImageCaches(temp_output, bitmaps);
-}
-
-void BrowserThemePack::RepackImages(const ImageCache& images,
- RawImages* reencoded_images) const {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- for (ImageCache::const_iterator it = images.begin();
- it != images.end(); ++it) {
- std::vector<unsigned char> image_data;
- if (!gfx::PNGCodec::EncodeBGRASkBitmap(*(it->second), false, &image_data)) {
- NOTREACHED() << "Image file for resource " << it->first
- << " could not be encoded.";
- } else {
- (*reencoded_images)[it->first] = RefCountedBytes::TakeVector(&image_data);
- }
- }
-}
-
-void BrowserThemePack::MergeImageCaches(
- const ImageCache& source, ImageCache* destination) const {
-
- for (ImageCache::const_iterator it = source.begin(); it != source.end();
- ++it) {
- ImageCache::const_iterator bitmap_it = destination->find(it->first);
- if (bitmap_it != destination->end())
- delete bitmap_it->second;
-
- (*destination)[it->first] = it->second;
- }
-}
-
-void BrowserThemePack::AddRawImagesTo(const RawImages& images,
- RawDataForWriting* out) const {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- for (RawImages::const_iterator it = images.begin(); it != images.end();
- ++it) {
- (*out)[it->first] = base::StringPiece(
- reinterpret_cast<const char*>(it->second->front()), it->second->size());
- }
-}
-
-color_utils::HSL BrowserThemePack::GetTintInternal(int id) const {
- if (tints_) {
- for (int i = 0; i < kTintArraySize; ++i) {
- if (tints_[i].id == id) {
- color_utils::HSL hsl;
- hsl.h = tints_[i].h;
- hsl.s = tints_[i].s;
- hsl.l = tints_[i].l;
- return hsl;
- }
- }
- }
-
- return BrowserThemeProvider::GetDefaultTint(id);
-}
diff --git a/chrome/browser/browser_theme_pack.h b/chrome/browser/browser_theme_pack.h
deleted file mode 100644
index 9160ba6..0000000
--- a/chrome/browser/browser_theme_pack.h
+++ /dev/null
@@ -1,226 +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_BROWSER_THEME_PACK_H_
-#define CHROME_BROWSER_BROWSER_THEME_PACK_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "base/ref_counted.h"
-#include "gfx/color_utils.h"
-#include "chrome/common/extensions/extension.h"
-
-class BrowserThemeProviderTest;
-namespace base {
-class DataPack;
-}
-class DictionaryValue;
-class FilePath;
-class RefCountedMemory;
-
-// An optimized representation of a theme, backed by a mmapped DataPack.
-//
-// The idea is to pre-process all images (tinting, compositing, etc) at theme
-// install time, save all the PNG-ified data into an mmappable file so we don't
-// suffer multiple file system access times, therefore solving two of the
-// problems with the previous implementation.
-//
-// A note on const-ness. All public, non-static methods are const. We do this
-// because once we've constructed a BrowserThemePack through the
-// BuildFromExtension() interface, we WriteToDisk() on a thread other than the
-// UI thread that consumes a BrowserThemePack. There is no locking; thread
-// safety between the writing thread and the UI thread is ensured by having the
-// data be immutable.
-class BrowserThemePack : public base::RefCountedThreadSafe<BrowserThemePack> {
- public:
- ~BrowserThemePack();
-
- // Builds the theme pack from all data from |extension|. This is often done
- // on a separate thread as it takes so long. This can fail and return NULL in
- // the case where the theme has invalid data.
- static BrowserThemePack* BuildFromExtension(Extension* extension);
-
- // Builds the theme pack from a previously performed WriteToDisk(). This
- // operation should be relatively fast, as it should be an mmap() and some
- // pointer swizzling. Returns NULL on any error attempting to read |path|.
- static scoped_refptr<BrowserThemePack> BuildFromDataPack(
- FilePath path, const std::string& expected_id);
-
- // Builds a data pack on disk at |path| for future quick loading by
- // BuildFromDataPack(). Often (but not always) called from the file thread;
- // implementation should be threadsafe because neither thread will write to
- // |image_memory_| and the worker thread will keep a reference to prevent
- // destruction.
- bool WriteToDisk(FilePath path) const;
-
- // If this theme specifies data for the corresponding |id|, return true and
- // write the corresponding value to the output parameter. These functions
- // don't return the default data. These methods should only be called from
- // the UI thread. (But this isn't enforced because of unit tests).
- bool GetTint(int id, color_utils::HSL* hsl) const;
- bool GetColor(int id, SkColor* color) const;
- bool GetDisplayProperty(int id, int* result) const;
-
- // Returns a bitmap if we have a custom image for |id|, otherwise NULL. Note
- // that this is separate from HasCustomImage() which returns whether a custom
- // image |id| was included in the unprocessed theme and is used as a proxy
- // for making layout decisions in the interface.
- SkBitmap* GetBitmapNamed(int id) const;
-
- // Returns the raw PNG encoded data for IDR_THEME_NTP_*. This method is only
- // supposed to work for the NTP attribution and background resources.
- RefCountedMemory* GetRawData(int id) const;
-
- // Whether this theme provides an image for |id|.
- bool HasCustomImage(int id) const;
-
- private:
- friend class BrowserThemePackTest;
-
- // Cached images. We cache all retrieved and generated bitmaps and keep
- // track of the pointers. We own these and will delete them when we're done
- // using them.
- typedef std::map<int, SkBitmap*> ImageCache;
-
- // The raw PNG memory associated with a certain id.
- typedef std::map<int, scoped_refptr<RefCountedMemory> > RawImages;
-
- // The type passed to base::DataPack::WritePack.
- typedef std::map<uint32, base::StringPiece> RawDataForWriting;
-
- // An association between an id and the FilePath that has the image data.
- typedef std::map<int, FilePath> FilePathMap;
-
- // Default. Everything is empty.
- BrowserThemePack();
-
- // Builds a header ready to write to disk.
- void BuildHeader(Extension* extension);
-
- // Transforms the JSON tint values into their final versions in the |tints_|
- // array.
- void BuildTintsFromJSON(DictionaryValue* tints_value);
-
- // Transforms the JSON color values into their final versions in the
- // |colors_| array and also fills in unspecified colors based on tint values.
- void BuildColorsFromJSON(DictionaryValue* color_value);
-
- // Implementation details of BuildColorsFromJSON().
- void ReadColorsFromJSON(DictionaryValue* colors_value,
- std::map<int, SkColor>* temp_colors);
- void GenerateMissingColors(std::map<int, SkColor>* temp_colors);
-
- // Transforms the JSON display properties into |display_properties_|.
- void BuildDisplayPropertiesFromJSON(DictionaryValue* display_value);
-
- // Parses the image names out of an extension.
- void ParseImageNamesFromJSON(DictionaryValue* images_value,
- FilePath images_path,
- FilePathMap* file_paths) const;
-
- // Creates the data for |source_images_| from |file_paths|.
- void BuildSourceImagesArray(const FilePathMap& file_paths);
-
- // Loads the unmodified bitmaps packed in the extension to SkBitmaps. Returns
- // true if all images loaded.
- bool LoadRawBitmapsTo(const FilePathMap& file_paths,
- ImageCache* raw_bitmaps);
-
- // Creates tinted and composited frame images. Source and destination is
- // |bitmaps|.
- void GenerateFrameImages(ImageCache* bitmaps) const;
-
- // Generates button images tinted with |button_tint| and places them in
- // processed_bitmaps.
- void GenerateTintedButtons(color_utils::HSL button_tint,
- ImageCache* processed_bitmaps) const;
-
- // Generates the semi-transparent tab background images, putting the results
- // in |bitmaps|. Must be called after GenerateFrameImages().
- void GenerateTabBackgroundImages(ImageCache* bitmaps) const;
-
- // Takes all the SkBitmaps in |images|, encodes them as PNGs and places
- // them in |reencoded_images|.
- void RepackImages(const ImageCache& images,
- RawImages* reencoded_images) const;
-
- // Takes all images in |source| and puts them in |destination|, freeing any
- // image already in |destination| that |source| would overwrite.
- void MergeImageCaches(const ImageCache& source,
- ImageCache* destination) const;
-
- // Changes the RefCountedMemory based |images| into StringPiece data in |out|.
- void AddRawImagesTo(const RawImages& images, RawDataForWriting* out) const;
-
- // Retrieves the tint OR the default tint. Unlike the public interface, we
- // always need to return a reasonable tint here, instead of partially
- // querying if the tint exists.
- color_utils::HSL GetTintInternal(int id) const;
-
- // Data pack, if we have one.
- scoped_ptr<base::DataPack> data_pack_;
-
- // All structs written to disk need to be packed; no alignment tricks here,
- // please.
-#pragma pack(push,1)
- // Header that is written to disk.
- struct BrowserThemePackHeader {
- // Numeric version to make sure we're compatible in the future.
- int32 version;
-
- // 1 if little_endian. 0 if big_endian. On mismatch, abort load.
- int32 little_endian;
-
- // theme_id without NULL terminator.
- uint8 theme_id[16];
- } *header_;
-
- // The remaining structs represent individual entries in an array. For the
- // following three structs, BrowserThemePack will either allocate an array or
- // will point directly to mmapped data.
- struct TintEntry {
- int32 id;
- double h;
- double s;
- double l;
- } *tints_;
-
- struct ColorPair {
- int32 id;
- SkColor color;
- } *colors_;
-
- struct DisplayPropertyPair {
- int32 id;
- int32 property;
- } *display_properties_;
-
- // A list of included source images. A pointer to a -1 terminated array of
- // our persistent IDs.
- int* source_images_;
-#pragma pack(pop)
-
- // References to raw PNG data. This map isn't touched when |data_pack_| is
- // non-NULL; |image_memory_| is only filled during BuildFromExtension(). Any
- // image data that needs to be written to the DataPack during WriteToDisk()
- // needs to be in |image_memory_|.
- RawImages image_memory_;
-
- // An immutable cache of images generated in BuildFromExtension(). When this
- // BrowserThemePack is generated from BuildFromDataPack(), this cache is
- // empty. We separate the images from the images loaded from disk so that
- // WriteToDisk()'s implementation doesn't need locks. There should be no IDs
- // in |image_memory_| that are in |prepared_images_| or vice versa.
- ImageCache prepared_images_;
-
- // Loaded images. These are loaded from |image_memory_| or the |data_pack_|.
- mutable ImageCache loaded_images_;
-
- DISALLOW_COPY_AND_ASSIGN(BrowserThemePack);
-};
-
-#endif // CHROME_BROWSER_BROWSER_THEME_PACK_H_
diff --git a/chrome/browser/browser_theme_pack_unittest.cc b/chrome/browser/browser_theme_pack_unittest.cc
deleted file mode 100644
index 001476c..0000000
--- a/chrome/browser/browser_theme_pack_unittest.cc
+++ /dev/null
@@ -1,429 +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/browser_theme_pack.h"
-
-#include "app/theme_provider.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_temp_dir.h"
-#include "base/values.h"
-#include "chrome/browser/browser_theme_provider.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/json_value_serializer.h"
-#include "gfx/color_utils.h"
-#include "grit/theme_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class BrowserThemePackTest : public ::testing::Test {
- public:
- BrowserThemePackTest()
- : message_loop(),
- fake_ui_thread(ChromeThread::UI, &message_loop),
- fake_file_thread(ChromeThread::FILE, &message_loop),
- theme_pack_(new BrowserThemePack) {
- }
-
- // Transformation for link underline colors.
- SkColor BuildThirdOpacity(SkColor color_link) {
- return SkColorSetA(color_link, SkColorGetA(color_link) / 3);
- }
-
- void GenerateDefaultFrameColor(std::map<int, SkColor>* colors,
- int color, int tint) {
- (*colors)[color] = HSLShift(
- BrowserThemeProvider::GetDefaultColor(
- BrowserThemeProvider::COLOR_FRAME),
- BrowserThemeProvider::GetDefaultTint(tint));
- }
-
- // Returns a mapping from each COLOR_* constant to the default value for this
- // constant. Callers get this map, and then modify expected values and then
- // run the resulting thing through VerifyColorMap().
- std::map<int, SkColor> GetDefaultColorMap() {
- std::map<int, SkColor> colors;
- for (int i = BrowserThemeProvider::COLOR_FRAME;
- i <= BrowserThemeProvider::COLOR_BUTTON_BACKGROUND; ++i) {
- colors[i] = BrowserThemeProvider::GetDefaultColor(i);
- }
-
- GenerateDefaultFrameColor(&colors, BrowserThemeProvider::COLOR_FRAME,
- BrowserThemeProvider::TINT_FRAME);
- GenerateDefaultFrameColor(&colors,
- BrowserThemeProvider::COLOR_FRAME_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INACTIVE);
- GenerateDefaultFrameColor(&colors,
- BrowserThemeProvider::COLOR_FRAME_INCOGNITO,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO);
- GenerateDefaultFrameColor(
- &colors,
- BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE);
-
- return colors;
- }
-
- void VerifyColorMap(const std::map<int, SkColor>& color_map) {
- for (std::map<int, SkColor>::const_iterator it = color_map.begin();
- it != color_map.end(); ++it) {
- SkColor color = BrowserThemeProvider::GetDefaultColor(it->first);
- theme_pack_->GetColor(it->first, &color);
- EXPECT_EQ(it->second, color) << "Color id = " << it->first;
- }
- }
-
- void LoadColorJSON(const std::string& json) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- LoadColorDictionary(static_cast<DictionaryValue*>(value.get()));
- }
-
- void LoadColorDictionary(DictionaryValue* value) {
- theme_pack_->BuildColorsFromJSON(value);
- }
-
- void LoadTintJSON(const std::string& json) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- LoadTintDictionary(static_cast<DictionaryValue*>(value.get()));
- }
-
- void LoadTintDictionary(DictionaryValue* value) {
- theme_pack_->BuildTintsFromJSON(value);
- }
-
- void LoadDisplayPropertiesJSON(const std::string& json) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- LoadDisplayPropertiesDictionary(static_cast<DictionaryValue*>(value.get()));
- }
-
- void LoadDisplayPropertiesDictionary(DictionaryValue* value) {
- theme_pack_->BuildDisplayPropertiesFromJSON(value);
- }
-
- void ParseImageNamesJSON(const std::string& json,
- std::map<int, FilePath>* out_file_paths) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- ParseImageNamesDictionary(static_cast<DictionaryValue*>(value.get()),
- out_file_paths);
- }
-
- void ParseImageNamesDictionary(DictionaryValue* value,
- std::map<int, FilePath>* out_file_paths) {
- theme_pack_->ParseImageNamesFromJSON(value, FilePath(), out_file_paths);
-
- // Build the source image list for HasCustomImage().
- theme_pack_->BuildSourceImagesArray(*out_file_paths);
- }
-
- bool LoadRawBitmapsTo(const std::map<int, FilePath>& out_file_paths) {
- return theme_pack_->LoadRawBitmapsTo(out_file_paths,
- &theme_pack_->prepared_images_);
- }
-
- FilePath GetStarGazingPath() {
- FilePath test_path;
- if (!PathService::Get(chrome::DIR_TEST_DATA, &test_path)) {
- NOTREACHED();
- return test_path;
- }
-
- test_path = test_path.AppendASCII("profiles");
- test_path = test_path.AppendASCII("complex_theme");
- test_path = test_path.AppendASCII("Default");
- test_path = test_path.AppendASCII("Extensions");
- test_path = test_path.AppendASCII("mblmlcbknbnfebdfjnolmcapmdofhmme");
- test_path = test_path.AppendASCII("1.1");
- return FilePath(test_path);
- }
-
- // Verifies the data in star gazing. We do this multiple times for different
- // BrowserThemePack objects to make sure it works in generated and mmapped
- // mode correctly.
- void VerifyStarGazing(BrowserThemePack* pack) {
- // First check that values we know exist, exist.
- SkColor color;
- EXPECT_TRUE(pack->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
- &color));
- EXPECT_EQ(SK_ColorBLACK, color);
-
- EXPECT_TRUE(pack->GetColor(BrowserThemeProvider::COLOR_NTP_BACKGROUND,
- &color));
- EXPECT_EQ(SkColorSetRGB(57, 137, 194), color);
-
- color_utils::HSL expected = { 0.6, 0.553, 0.5 };
- color_utils::HSL actual;
- EXPECT_TRUE(pack->GetTint(BrowserThemeProvider::TINT_BUTTONS, &actual));
- EXPECT_DOUBLE_EQ(expected.h, actual.h);
- EXPECT_DOUBLE_EQ(expected.s, actual.s);
- EXPECT_DOUBLE_EQ(expected.l, actual.l);
-
- int val;
- EXPECT_TRUE(pack->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, &val));
- EXPECT_EQ(BrowserThemeProvider::ALIGN_TOP, val);
-
- // The stargazing theme defines the following images:
- EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND));
- EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME));
- EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_NTP_BACKGROUND));
- EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND));
- EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TOOLBAR));
- EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND));
-
- // Here are a few images that we shouldn't expect because even though
- // they're included in the theme pack, they were autogenerated and
- // therefore shouldn't show up when calling HasCustomImage().
- EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INACTIVE));
- EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
- EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO_INACTIVE));
- EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_INCOGNITO));
-
- // Make sure we don't have phantom data.
- EXPECT_FALSE(pack->GetColor(BrowserThemeProvider::COLOR_CONTROL_BACKGROUND,
- &color));
- EXPECT_FALSE(pack->GetTint(BrowserThemeProvider::TINT_FRAME, &actual));
- }
-
- MessageLoop message_loop;
- ChromeThread fake_ui_thread;
- ChromeThread fake_file_thread;
-
- scoped_refptr<BrowserThemePack> theme_pack_;
-};
-
-
-TEST_F(BrowserThemePackTest, DeriveUnderlineLinkColor) {
- // If we specify a link color, but don't specify the underline color, the
- // theme provider should create one.
- std::string color_json = "{ \"ntp_link\": [128, 128, 128],"
- " \"ntp_section_link\": [128, 128, 128] }";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor link_color = SkColorSetRGB(128, 128, 128);
- colors[BrowserThemeProvider::COLOR_NTP_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] =
- BuildThirdOpacity(link_color);
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
- BuildThirdOpacity(link_color);
-
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, ProvideUnderlineLinkColor) {
- // If we specify the underline color, it shouldn't try to generate one.
- std::string color_json = "{ \"ntp_link\": [128, 128, 128],"
- " \"ntp_link_underline\": [255, 255, 255],"
- " \"ntp_section_link\": [128, 128, 128],"
- " \"ntp_section_link_underline\": [255, 255, 255]"
- "}";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor link_color = SkColorSetRGB(128, 128, 128);
- SkColor underline_color = SkColorSetRGB(255, 255, 255);
- colors[BrowserThemeProvider::COLOR_NTP_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] = underline_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
- underline_color;
-
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, UseSectionColorAsNTPHeader) {
- std::string color_json = "{ \"ntp_section\": [190, 190, 190] }";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor ntp_color = SkColorSetRGB(190, 190, 190);
- colors[BrowserThemeProvider::COLOR_NTP_HEADER] = ntp_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION] = ntp_color;
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, ProvideNtpHeaderColor) {
- std::string color_json = "{ \"ntp_header\": [120, 120, 120], "
- " \"ntp_section\": [190, 190, 190] }";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor ntp_header = SkColorSetRGB(120, 120, 120);
- SkColor ntp_section = SkColorSetRGB(190, 190, 190);
- colors[BrowserThemeProvider::COLOR_NTP_HEADER] = ntp_header;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION] = ntp_section;
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, CanReadTints) {
- std::string tint_json = "{ \"buttons\": [ 0.5, 0.5, 0.5 ] }";
- LoadTintJSON(tint_json);
-
- color_utils::HSL expected = { 0.5, 0.5, 0.5 };
- color_utils::HSL actual = { -1, -1, -1 };
- EXPECT_TRUE(theme_pack_->GetTint(
- BrowserThemeProvider::TINT_BUTTONS, &actual));
- EXPECT_DOUBLE_EQ(expected.h, actual.h);
- EXPECT_DOUBLE_EQ(expected.s, actual.s);
- EXPECT_DOUBLE_EQ(expected.l, actual.l);
-}
-
-TEST_F(BrowserThemePackTest, CanReadDisplayProperties) {
- std::string json = "{ \"ntp_background_alignment\": \"bottom\", "
- " \"ntp_background_repeat\": \"repeat-x\", "
- " \"ntp_logo_alternate\": 0 }";
- LoadDisplayPropertiesJSON(json);
-
- int out_val;
- EXPECT_TRUE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, &out_val));
- EXPECT_EQ(BrowserThemeProvider::ALIGN_BOTTOM, out_val);
-
- EXPECT_TRUE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_TILING, &out_val));
- EXPECT_EQ(BrowserThemeProvider::REPEAT_X, out_val);
-
- EXPECT_TRUE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_LOGO_ALTERNATE, &out_val));
- EXPECT_EQ(0, out_val);
-}
-
-TEST_F(BrowserThemePackTest, CanParsePaths) {
- std::string path_json = "{ \"theme_button_background\": \"one\", "
- " \"theme_toolbar\": \"two\" }";
- std::map<int, FilePath> out_file_paths;
- ParseImageNamesJSON(path_json, &out_file_paths);
-
- EXPECT_EQ(2u, out_file_paths.size());
- // "12" and "5" are internal constants to BrowserThemePack and are
- // PRS_THEME_BUTTON_BACKGROUND and PRS_THEME_TOOLBAR, but they are
- // implementation details that shouldn't be exported.
- EXPECT_TRUE(FilePath(FILE_PATH_LITERAL("one")) == out_file_paths[12]);
- EXPECT_TRUE(FilePath(FILE_PATH_LITERAL("two")) == out_file_paths[5]);
-}
-
-TEST_F(BrowserThemePackTest, InvalidPathNames) {
- std::string path_json = "{ \"wrong\": [1], "
- " \"theme_button_background\": \"one\", "
- " \"not_a_thing\": \"blah\" }";
- std::map<int, FilePath> out_file_paths;
- ParseImageNamesJSON(path_json, &out_file_paths);
-
- // We should have only parsed one valid path out of that mess above.
- EXPECT_EQ(1u, out_file_paths.size());
-}
-
-TEST_F(BrowserThemePackTest, InvalidColors) {
- std::string invalid_color = "{ \"toolbar\": [\"dog\", \"cat\", [12]], "
- " \"sound\": \"woof\" }";
- LoadColorJSON(invalid_color);
- std::map<int, SkColor> colors = GetDefaultColorMap();
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, InvalidTints) {
- std::string invalid_tints = "{ \"buttons\": [ \"dog\", \"cat\", [\"x\"]], "
- " \"invalid\": \"entry\" }";
- LoadTintJSON(invalid_tints);
-
- // We shouldn't have a buttons tint, as it was invalid.
- color_utils::HSL actual = { -1, -1, -1 };
- EXPECT_FALSE(theme_pack_->GetTint(BrowserThemeProvider::TINT_BUTTONS,
- &actual));
-}
-
-TEST_F(BrowserThemePackTest, InvalidDisplayProperties) {
- std::string invalid_properties = "{ \"ntp_background_alignment\": [15], "
- " \"junk\": [15.3] }";
- LoadDisplayPropertiesJSON(invalid_properties);
-
- int out_val;
- EXPECT_FALSE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, &out_val));
-}
-
-// These three tests should just not cause a segmentation fault.
-TEST_F(BrowserThemePackTest, NullPaths) {
- std::map<int, FilePath> out_file_paths;
- ParseImageNamesDictionary(NULL, &out_file_paths);
-}
-
-TEST_F(BrowserThemePackTest, NullTints) {
- LoadTintDictionary(NULL);
-}
-
-TEST_F(BrowserThemePackTest, NullColors) {
- LoadColorDictionary(NULL);
-}
-
-TEST_F(BrowserThemePackTest, NullDisplayProperties) {
- LoadDisplayPropertiesDictionary(NULL);
-}
-
-TEST_F(BrowserThemePackTest, TestHasCustomImage) {
- // HasCustomImage should only return true for images that exist in the
- // extension and not for autogenerated images.
- std::string images = "{ \"theme_frame\": \"one\" }";
- std::map<int, FilePath> out_file_paths;
- ParseImageNamesJSON(images, &out_file_paths);
-
- EXPECT_TRUE(theme_pack_->HasCustomImage(IDR_THEME_FRAME));
- EXPECT_FALSE(theme_pack_->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
-}
-
-TEST_F(BrowserThemePackTest, TestNonExistantImages) {
- std::string images = "{ \"theme_frame\": \"does_not_exist\" }";
- std::map<int, FilePath> out_file_paths;
- ParseImageNamesJSON(images, &out_file_paths);
-
- EXPECT_FALSE(LoadRawBitmapsTo(out_file_paths));
-}
-
-// TODO(erg): This test should actually test more of the built resources from
-// the extension data, but for now, exists so valgrind can test some of the
-// tricky memory stuff that BrowserThemePack does.
-TEST_F(BrowserThemePackTest, CanBuildAndReadPack) {
- ScopedTempDir dir;
- ASSERT_TRUE(dir.CreateUniqueTempDir());
- FilePath file = dir.path().Append(FILE_PATH_LITERAL("data.pak"));
-
- // Part 1: Build the pack from an extension.
- {
- FilePath star_gazing_path = GetStarGazingPath();
- Extension extension(star_gazing_path);
-
- FilePath manifest_path =
- star_gazing_path.AppendASCII("manifest.json");
- std::string error;
- JSONFileValueSerializer serializer(manifest_path);
- scoped_ptr<DictionaryValue> valid_value(
- static_cast<DictionaryValue*>(serializer.Deserialize(NULL, &error)));
- EXPECT_EQ("", error);
- ASSERT_TRUE(valid_value.get());
- ASSERT_TRUE(extension.InitFromValue(*valid_value, true, &error));
- ASSERT_EQ("", error);
-
- scoped_refptr<BrowserThemePack> pack =
- BrowserThemePack::BuildFromExtension(&extension);
- ASSERT_TRUE(pack.get());
- ASSERT_TRUE(pack->WriteToDisk(file));
- VerifyStarGazing(pack.get());
- }
-
- // Part 2: Try to read back the data pack that we just wrote to disk.
- {
- scoped_refptr<BrowserThemePack> pack =
- BrowserThemePack::BuildFromDataPack(
- file, "mblmlcbknbnfebdfjnolmcapmdofhmme");
- ASSERT_TRUE(pack.get());
- VerifyStarGazing(pack.get());
- }
-}
diff --git a/chrome/browser/browser_theme_provider.cc b/chrome/browser/browser_theme_provider.cc
deleted file mode 100644
index aa19232..0000000
--- a/chrome/browser/browser_theme_provider.cc
+++ /dev/null
@@ -1,603 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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_theme_provider.h"
-
-#include "app/resource_bundle.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_theme_pack.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
-#include "grit/app_resources.h"
-#include "grit/theme_resources.h"
-
-#if defined(OS_WIN)
-#include "app/win_util.h"
-#endif
-
-// Strings used in alignment properties.
-const char* BrowserThemeProvider::kAlignmentTop = "top";
-const char* BrowserThemeProvider::kAlignmentBottom = "bottom";
-const char* BrowserThemeProvider::kAlignmentLeft = "left";
-const char* BrowserThemeProvider::kAlignmentRight = "right";
-
-// Strings used in background tiling repetition properties.
-const char* BrowserThemeProvider::kTilingNoRepeat = "no-repeat";
-const char* BrowserThemeProvider::kTilingRepeatX = "repeat-x";
-const char* BrowserThemeProvider::kTilingRepeatY = "repeat-y";
-const char* BrowserThemeProvider::kTilingRepeat = "repeat";
-
-// Saved default values.
-const char* BrowserThemeProvider::kDefaultThemeID = "";
-
-namespace {
-
-SkColor TintForUnderline(SkColor input) {
- return SkColorSetA(input, SkColorGetA(input) / 3);
-}
-
-// Default colors.
-const SkColor kDefaultColorFrame = SkColorSetRGB(66, 116, 201);
-const SkColor kDefaultColorFrameInactive = SkColorSetRGB(161, 182, 228);
-const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139);
-const SkColor kDefaultColorFrameIncognitoInactive =
- SkColorSetRGB(126, 139, 156);
-#if defined(OS_MACOSX)
-const SkColor kDefaultColorToolbar = SkColorSetRGB(230, 230, 230);
-#else
-const SkColor kDefaultColorToolbar = SkColorSetRGB(223, 223, 223);
-#endif
-const SkColor kDefaultColorTabText = SK_ColorBLACK;
-#if defined(OS_MACOSX)
-const SkColor kDefaultColorBackgroundTabText = SK_ColorBLACK;
-const SkColor kDefaultColorBookmarkText = SK_ColorBLACK;
-#else
-const SkColor kDefaultColorBackgroundTabText = SkColorSetRGB(64, 64, 64);
-const SkColor kDefaultColorBookmarkText = SkColorSetRGB(18, 50, 114);
-#endif
-#if defined(OS_WIN)
-const SkColor kDefaultColorNTPBackground =
- color_utils::GetSysSkColor(COLOR_WINDOW);
-const SkColor kDefaultColorNTPText =
- color_utils::GetSysSkColor(COLOR_WINDOWTEXT);
-const SkColor kDefaultColorNTPLink =
- color_utils::GetSysSkColor(COLOR_HOTLIGHT);
-#else
-// TODO(beng): source from theme provider.
-const SkColor kDefaultColorNTPBackground = SK_ColorWHITE;
-const SkColor kDefaultColorNTPText = SK_ColorBLACK;
-const SkColor kDefaultColorNTPLink = SkColorSetRGB(6, 55, 116);
-#endif
-const SkColor kDefaultColorNTPHeader = SkColorSetRGB(75, 140, 220);
-const SkColor kDefaultColorNTPSection = SkColorSetRGB(229, 239, 254);
-const SkColor kDefaultColorNTPSectionText = SK_ColorBLACK;
-const SkColor kDefaultColorNTPSectionLink = SkColorSetRGB(6, 55, 116);
-const SkColor kDefaultColorControlBackground = SkColorSetARGB(0, 0, 0, 0);
-const SkColor kDefaultColorButtonBackground = SkColorSetARGB(0, 0, 0, 0);
-#if defined(OS_MACOSX)
-const SkColor kDefaultColorToolbarButtonStroke = SkColorSetARGB(75, 81, 81, 81);
-const SkColor kDefaultColorToolbarButtonStrokeInactive =
- SkColorSetARGB(75, 99, 99, 99);
-const SkColor kDefaultColorToolbarStroke = SkColorSetRGB(103, 103, 103);
-const SkColor kDefaultColorToolbarStrokeInactive = SkColorSetRGB(123, 123, 123);
-#endif
-
-// Default tints.
-const color_utils::HSL kDefaultTintButtons = { -1, -1, -1 };
-const color_utils::HSL kDefaultTintFrame = { -1, -1, -1 };
-const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75f };
-const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f };
-const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f };
-const color_utils::HSL kDefaultTintBackgroundTab = { -1, 0.5, 0.75 };
-
-// Default display properties.
-const int kDefaultDisplayPropertyNTPAlignment =
- BrowserThemeProvider::ALIGN_BOTTOM;
-const int kDefaultDisplayPropertyNTPTiling =
- BrowserThemeProvider::NO_REPEAT;
-const int kDefaultDisplayPropertyNTPInverseLogo = 0;
-
-// The sum of kFrameBorderThickness and kNonClientRestoredExtraThickness from
-// OpaqueBrowserFrameView.
-const int kRestoredTabVerticalOffset = 15;
-
-// The image resources we will allow people to theme.
-const int kThemeableImages[] = {
- IDR_THEME_FRAME,
- IDR_THEME_FRAME_INACTIVE,
- IDR_THEME_FRAME_INCOGNITO,
- IDR_THEME_FRAME_INCOGNITO_INACTIVE,
- IDR_THEME_TOOLBAR,
- IDR_THEME_TAB_BACKGROUND,
- IDR_THEME_TAB_BACKGROUND_INCOGNITO,
- IDR_THEME_TAB_BACKGROUND_V,
- IDR_THEME_NTP_BACKGROUND,
- IDR_THEME_FRAME_OVERLAY,
- IDR_THEME_FRAME_OVERLAY_INACTIVE,
- IDR_THEME_BUTTON_BACKGROUND,
- IDR_THEME_NTP_ATTRIBUTION,
- IDR_THEME_WINDOW_CONTROL_BACKGROUND
-};
-
-bool HasThemeableImage(int themeable_image_id) {
- static std::set<int> themeable_images;
- if (themeable_images.empty()) {
- themeable_images.insert(
- kThemeableImages, kThemeableImages + arraysize(kThemeableImages));
- }
- return themeable_images.count(themeable_image_id) > 0;
-}
-
-// The image resources that will be tinted by the 'button' tint value.
-// If you change this list, you must increment the version number in
-// browser_theme_pack.cc, and you should assign persistent IDs to the
-// data table at the start of said file or else tinted versions of
-// these resources will not be created.
-const int kToolbarButtonIDs[] = {
- IDR_BACK, IDR_BACK_D, IDR_BACK_H, IDR_BACK_P,
- IDR_FORWARD, IDR_FORWARD_D, IDR_FORWARD_H, IDR_FORWARD_P,
- IDR_HOME, IDR_HOME_H, IDR_HOME_P,
- IDR_RELOAD, IDR_RELOAD_H, IDR_RELOAD_P,
- IDR_STOP, IDR_STOP_H, IDR_STOP_P,
- IDR_LOCATIONBG_C, IDR_LOCATIONBG_L, IDR_LOCATIONBG_R,
- IDR_TOOLS,
- IDR_MENU_DROPARROW,
- IDR_THROBBER, IDR_THROBBER_WAITING, IDR_THROBBER_LIGHT,
-};
-
-// Writes the theme pack to disk on a separate thread.
-class WritePackToDiskTask : public Task {
- public:
- WritePackToDiskTask(BrowserThemePack* pack, const FilePath& path)
- : theme_pack_(pack), pack_path_(path) {}
-
- virtual void Run() {
- if (!theme_pack_->WriteToDisk(pack_path_)) {
- NOTREACHED() << "Could not write theme pack to disk";
- }
- }
-
- private:
- scoped_refptr<BrowserThemePack> theme_pack_;
- FilePath pack_path_;
-};
-
-} // namespace
-
-bool BrowserThemeProvider::IsThemeableImage(int resource_id) {
- return HasThemeableImage(resource_id);
-}
-
-BrowserThemeProvider::BrowserThemeProvider()
- : rb_(ResourceBundle::GetSharedInstance()),
- profile_(NULL),
- number_of_infobars_(0) {
- // Initialize the themeable image map so we can use it on other threads.
- HasThemeableImage(0);
-}
-
-BrowserThemeProvider::~BrowserThemeProvider() {
- FreePlatformCaches();
-
- RemoveUnusedThemes();
-}
-
-void BrowserThemeProvider::Init(Profile* profile) {
- DCHECK(CalledOnValidThread());
- profile_ = profile;
-
- LoadThemePrefs();
-}
-
-SkBitmap* BrowserThemeProvider::GetBitmapNamed(int id) const {
- DCHECK(CalledOnValidThread());
-
- SkBitmap* bitmap = NULL;
-
- if (theme_pack_.get())
- bitmap = theme_pack_->GetBitmapNamed(id);
-
- if (!bitmap)
- bitmap = rb_.GetBitmapNamed(id);
-
- return bitmap;
-}
-
-SkColor BrowserThemeProvider::GetColor(int id) const {
- DCHECK(CalledOnValidThread());
-
- SkColor color;
- if (theme_pack_.get() && theme_pack_->GetColor(id, &color))
- return color;
-
- return GetDefaultColor(id);
-}
-
-bool BrowserThemeProvider::GetDisplayProperty(int id, int* result) const {
- if (theme_pack_.get())
- return theme_pack_->GetDisplayProperty(id, result);
-
- return GetDefaultDisplayProperty(id, result);
-}
-
-bool BrowserThemeProvider::ShouldUseNativeFrame() const {
- if (HasCustomImage(IDR_THEME_FRAME))
- return false;
-#if defined(OS_WIN)
- return win_util::ShouldUseVistaFrame();
-#else
- return false;
-#endif
-}
-
-bool BrowserThemeProvider::HasCustomImage(int id) const {
- if (!HasThemeableImage(id))
- return false;
-
- if (theme_pack_)
- return theme_pack_->HasCustomImage(id);
-
- return false;
-}
-
-RefCountedMemory* BrowserThemeProvider::GetRawData(int id) const {
- // Check to see whether we should substitute some images.
- int ntp_alternate;
- GetDisplayProperty(NTP_LOGO_ALTERNATE, &ntp_alternate);
- if (id == IDR_PRODUCT_LOGO && ntp_alternate != 0)
- id = IDR_PRODUCT_LOGO_WHITE;
-
- RefCountedMemory* data = NULL;
- if (theme_pack_.get())
- data = theme_pack_->GetRawData(id);
- if (!data)
- data = rb_.LoadDataResourceBytes(id);
-
- return data;
-}
-
-void BrowserThemeProvider::SetTheme(Extension* extension) {
- // Clear our image cache.
- FreePlatformCaches();
-
- DCHECK(extension);
- DCHECK(extension->is_theme());
-
- BuildFromExtension(extension);
- SaveThemeID(extension->id());
-
- NotifyThemeChanged(extension);
- UserMetrics::RecordAction(UserMetricsAction("Themes_Installed"), profile_);
-}
-
-void BrowserThemeProvider::RemoveUnusedThemes() {
- if (!profile_)
- return;
- ExtensionsService* service = profile_->GetExtensionsService();
- if (!service)
- return;
- std::string current_theme = GetThemeID();
- std::vector<std::string> remove_list;
- const ExtensionList* extensions = service->extensions();
- for (ExtensionList::const_iterator it = extensions->begin();
- it != extensions->end(); ++it) {
- if ((*it)->is_theme() && (*it)->id() != current_theme) {
- remove_list.push_back((*it)->id());
- }
- }
- for (size_t i = 0; i < remove_list.size(); ++i)
- service->UninstallExtension(remove_list[i], false);
-}
-
-void BrowserThemeProvider::UseDefaultTheme() {
- ClearAllThemeData();
- NotifyThemeChanged(NULL);
- UserMetrics::RecordAction(UserMetricsAction("Themes_Reset"), profile_);
-}
-
-bool BrowserThemeProvider::UsingDefaultTheme() {
- return GetThemeID() == BrowserThemeProvider::kDefaultThemeID;
-}
-
-std::string BrowserThemeProvider::GetThemeID() const {
- return profile_->GetPrefs()->GetString(prefs::kCurrentThemeID);
-}
-
-// static
-std::string BrowserThemeProvider::AlignmentToString(int alignment) {
- // Convert from an AlignmentProperty back into a string.
- std::string vertical_string;
- std::string horizontal_string;
-
- if (alignment & BrowserThemeProvider::ALIGN_TOP)
- vertical_string = kAlignmentTop;
- else if (alignment & BrowserThemeProvider::ALIGN_BOTTOM)
- vertical_string = kAlignmentBottom;
-
- if (alignment & BrowserThemeProvider::ALIGN_LEFT)
- horizontal_string = kAlignmentLeft;
- else if (alignment & BrowserThemeProvider::ALIGN_RIGHT)
- horizontal_string = kAlignmentRight;
-
- if (vertical_string.empty())
- return horizontal_string;
- if (horizontal_string.empty())
- return vertical_string;
- return vertical_string + " " + horizontal_string;
-}
-
-// static
-int BrowserThemeProvider::StringToAlignment(const std::string& alignment) {
- std::vector<std::wstring> split;
- SplitStringAlongWhitespace(UTF8ToWide(alignment), &split);
-
- int alignment_mask = 0;
- for (std::vector<std::wstring>::iterator alignments(split.begin());
- alignments != split.end(); ++alignments) {
- std::string comp = WideToUTF8(*alignments);
- const char* component = comp.c_str();
-
- if (base::strcasecmp(component, kAlignmentTop) == 0)
- alignment_mask |= BrowserThemeProvider::ALIGN_TOP;
- else if (base::strcasecmp(component, kAlignmentBottom) == 0)
- alignment_mask |= BrowserThemeProvider::ALIGN_BOTTOM;
-
- if (base::strcasecmp(component, kAlignmentLeft) == 0)
- alignment_mask |= BrowserThemeProvider::ALIGN_LEFT;
- else if (base::strcasecmp(component, kAlignmentRight) == 0)
- alignment_mask |= BrowserThemeProvider::ALIGN_RIGHT;
- }
- return alignment_mask;
-}
-
-// static
-std::string BrowserThemeProvider::TilingToString(int tiling) {
- // Convert from a TilingProperty back into a string.
- if (tiling == BrowserThemeProvider::REPEAT_X)
- return kTilingRepeatX;
- if (tiling == BrowserThemeProvider::REPEAT_Y)
- return kTilingRepeatY;
- if (tiling == BrowserThemeProvider::REPEAT)
- return kTilingRepeat;
- return kTilingNoRepeat;
-}
-
-// static
-int BrowserThemeProvider::StringToTiling(const std::string& tiling) {
- const char* component = tiling.c_str();
-
- if (base::strcasecmp(component, kTilingRepeatX) == 0)
- return BrowserThemeProvider::REPEAT_X;
- if (base::strcasecmp(component, kTilingRepeatY) == 0)
- return BrowserThemeProvider::REPEAT_Y;
- if (base::strcasecmp(component, kTilingRepeat) == 0)
- return BrowserThemeProvider::REPEAT;
- // NO_REPEAT is the default choice.
- return BrowserThemeProvider::NO_REPEAT;
-}
-
-// static
-color_utils::HSL BrowserThemeProvider::GetDefaultTint(int id) {
- switch (id) {
- case TINT_FRAME:
- return kDefaultTintFrame;
- case TINT_FRAME_INACTIVE:
- return kDefaultTintFrameInactive;
- case TINT_FRAME_INCOGNITO:
- return kDefaultTintFrameIncognito;
- case TINT_FRAME_INCOGNITO_INACTIVE:
- return kDefaultTintFrameIncognitoInactive;
- case TINT_BUTTONS:
- return kDefaultTintButtons;
- case TINT_BACKGROUND_TAB:
- return kDefaultTintBackgroundTab;
- default:
- color_utils::HSL result = {-1, -1, -1};
- return result;
- }
-}
-
-// static
-SkColor BrowserThemeProvider::GetDefaultColor(int id) {
- switch (id) {
- case COLOR_FRAME:
- return kDefaultColorFrame;
- case COLOR_FRAME_INACTIVE:
- return kDefaultColorFrameInactive;
- case COLOR_FRAME_INCOGNITO:
- return kDefaultColorFrameIncognito;
- case COLOR_FRAME_INCOGNITO_INACTIVE:
- return kDefaultColorFrameIncognitoInactive;
- case COLOR_TOOLBAR:
- return kDefaultColorToolbar;
- case COLOR_TAB_TEXT:
- return kDefaultColorTabText;
- case COLOR_BACKGROUND_TAB_TEXT:
- return kDefaultColorBackgroundTabText;
- case COLOR_BOOKMARK_TEXT:
- return kDefaultColorBookmarkText;
- case COLOR_NTP_BACKGROUND:
- return kDefaultColorNTPBackground;
- case COLOR_NTP_TEXT:
- return kDefaultColorNTPText;
- case COLOR_NTP_LINK:
- return kDefaultColorNTPLink;
- case COLOR_NTP_LINK_UNDERLINE:
- return TintForUnderline(kDefaultColorNTPLink);
- case COLOR_NTP_HEADER:
- return kDefaultColorNTPHeader;
- case COLOR_NTP_SECTION:
- return kDefaultColorNTPSection;
- case COLOR_NTP_SECTION_TEXT:
- return kDefaultColorNTPSectionText;
- case COLOR_NTP_SECTION_LINK:
- return kDefaultColorNTPSectionLink;
- case COLOR_NTP_SECTION_LINK_UNDERLINE:
- return TintForUnderline(kDefaultColorNTPSectionLink);
- case COLOR_CONTROL_BACKGROUND:
- return kDefaultColorControlBackground;
- case COLOR_BUTTON_BACKGROUND:
- return kDefaultColorButtonBackground;
-#if defined(OS_MACOSX)
- case COLOR_TOOLBAR_BUTTON_STROKE:
- return kDefaultColorToolbarButtonStroke;
- case COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE:
- return kDefaultColorToolbarButtonStrokeInactive;
- case COLOR_TOOLBAR_STROKE:
- return kDefaultColorToolbarStroke;
- case COLOR_TOOLBAR_STROKE_INACTIVE:
- return kDefaultColorToolbarStrokeInactive;
-#endif
- default:
- // Return a debugging red color.
- return 0xffff0000;
- }
-}
-
-// static
-bool BrowserThemeProvider::GetDefaultDisplayProperty(int id, int* result) {
- switch (id) {
- case NTP_BACKGROUND_ALIGNMENT:
- *result = kDefaultDisplayPropertyNTPAlignment;
- return true;
- case NTP_BACKGROUND_TILING:
- *result = kDefaultDisplayPropertyNTPTiling;
- return true;
- case NTP_LOGO_ALTERNATE:
- *result = kDefaultDisplayPropertyNTPInverseLogo;
- return true;
- }
-
- return false;
-}
-
-// static
-const std::set<int>& BrowserThemeProvider::GetTintableToolbarButtons() {
- static std::set<int> button_set;
- if (button_set.empty()) {
- button_set = std::set<int>(
- kToolbarButtonIDs,
- kToolbarButtonIDs + arraysize(kToolbarButtonIDs));
- }
-
- return button_set;
-}
-
-color_utils::HSL BrowserThemeProvider::GetTint(int id) const {
- DCHECK(CalledOnValidThread());
-
- color_utils::HSL hsl;
- if (theme_pack_.get() && theme_pack_->GetTint(id, &hsl))
- return hsl;
-
- return GetDefaultTint(id);
-}
-
-void BrowserThemeProvider::ClearAllThemeData() {
- // Clear our image cache.
- FreePlatformCaches();
- theme_pack_ = NULL;
-
- profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename);
- SaveThemeID(kDefaultThemeID);
-}
-
-void BrowserThemeProvider::LoadThemePrefs() {
- PrefService* prefs = profile_->GetPrefs();
-
- std::string current_id = GetThemeID();
- if (current_id != kDefaultThemeID) {
- bool loaded_pack = false;
-
- // If we don't have a file pack, we're updating from an old version.
- FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename);
- if (path != FilePath()) {
- theme_pack_ = BrowserThemePack::BuildFromDataPack(path, current_id);
- loaded_pack = theme_pack_.get() != NULL;
- }
-
- if (loaded_pack) {
- UserMetrics::RecordAction(UserMetricsAction("Themes.Loaded"), profile_);
- } else {
- // TODO(erg): We need to pop up a dialog informing the user that their
- // theme is being migrated.
- ExtensionsService* service = profile_->GetExtensionsService();
- if (service) {
- Extension* extension = service->GetExtensionById(current_id, false);
- if (extension) {
- DLOG(ERROR) << "Migrating theme";
- BuildFromExtension(extension);
- UserMetrics::RecordAction(UserMetricsAction("Themes.Migrated"),
- profile_);
- } else {
- DLOG(ERROR) << "Theme is mysteriously gone.";
- ClearAllThemeData();
- UserMetrics::RecordAction(UserMetricsAction("Themes.Gone"), profile_);
- }
- }
- }
- }
-}
-
-void BrowserThemeProvider::NotifyThemeChanged(Extension* extension) {
- LOG(INFO) << "Sending BROWSER_THEME_CHANGED";
- // Redraw!
- NotificationService* service = NotificationService::current();
- service->Notify(NotificationType::BROWSER_THEME_CHANGED,
- Source<BrowserThemeProvider>(this),
- Details<Extension>(extension));
-#if defined(OS_MACOSX)
- NotifyPlatformThemeChanged();
-#endif // OS_MACOSX
-}
-
-#if defined(OS_WIN)
-void BrowserThemeProvider::FreePlatformCaches() {
- // Views (Skia) has no platform image cache to clear.
-}
-#endif
-
-void BrowserThemeProvider::SavePackName(const FilePath& pack_path) {
- profile_->GetPrefs()->SetFilePath(
- prefs::kCurrentThemePackFilename, pack_path);
-}
-
-void BrowserThemeProvider::SaveThemeID(const std::string& id) {
- profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, id);
-}
-
-void BrowserThemeProvider::BuildFromExtension(Extension* extension) {
- scoped_refptr<BrowserThemePack> pack =
- BrowserThemePack::BuildFromExtension(extension);
- if (!pack.get()) {
- // TODO(erg): We've failed to install the theme; perhaps we should tell the
- // user? http://crbug.com/34780
- LOG(ERROR) << "Could not load theme.";
- return;
- }
-
- // Write the packed file to disk.
- FilePath pack_path = extension->path().Append(chrome::kThemePackFilename);
- ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
- new WritePackToDiskTask(pack, pack_path));
-
- SavePackName(pack_path);
- theme_pack_ = pack;
-}
-
-void BrowserThemeProvider::OnInfobarDisplayed() {
- number_of_infobars_++;
-}
-
-void BrowserThemeProvider::OnInfobarDestroyed() {
- number_of_infobars_--;
-
- if (number_of_infobars_ == 0)
- RemoveUnusedThemes();
-}
diff --git a/chrome/browser/browser_theme_provider.h b/chrome/browser/browser_theme_provider.h
deleted file mode 100644
index 0cb4b15..0000000
--- a/chrome/browser/browser_theme_provider.h
+++ /dev/null
@@ -1,275 +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_BROWSER_THEME_PROVIDER_H_
-#define CHROME_BROWSER_BROWSER_THEME_PROVIDER_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "app/theme_provider.h"
-#include "base/non_thread_safe.h"
-#include "base/ref_counted.h"
-
-namespace color_utils {
- struct HSL;
-}
-
-class BrowserThemePack;
-class BrowserThemeProviderTest;
-class DictionaryValue;
-class Extension;
-class FilePath;
-class PrefService;
-class Profile;
-class ResourceBundle;
-
-#ifdef __OBJC__
-@class NSString;
-// Sent whenever the browser theme changes. Object => NSValue wrapping the
-// BrowserThemeProvider that changed.
-extern "C" NSString* const kBrowserThemeDidChangeNotification;
-#endif // __OBJC__
-
-class BrowserThemeProvider : public NonThreadSafe,
- public ThemeProvider {
- public:
- // Public constants used in BrowserThemeProvider and its subclasses:
-
- // Strings used in alignment properties.
- static const char* kAlignmentTop;
- static const char* kAlignmentBottom;
- static const char* kAlignmentLeft;
- static const char* kAlignmentRight;
-
- // Strings used in tiling properties.
- static const char* kTilingNoRepeat;
- static const char* kTilingRepeatX;
- static const char* kTilingRepeatY;
- static const char* kTilingRepeat;
-
- static const char* kDefaultThemeID;
-
- // Returns true if the image is themeable. Safe to call on any thread.
- static bool IsThemeableImage(int resource_id);
-
- BrowserThemeProvider();
- virtual ~BrowserThemeProvider();
-
- enum {
- COLOR_FRAME,
- COLOR_FRAME_INACTIVE,
- COLOR_FRAME_INCOGNITO,
- COLOR_FRAME_INCOGNITO_INACTIVE,
- COLOR_TOOLBAR,
- COLOR_TAB_TEXT,
- COLOR_BACKGROUND_TAB_TEXT,
- COLOR_BOOKMARK_TEXT,
- COLOR_NTP_BACKGROUND,
- COLOR_NTP_TEXT,
- COLOR_NTP_LINK,
- COLOR_NTP_LINK_UNDERLINE,
- COLOR_NTP_HEADER,
- COLOR_NTP_SECTION,
- COLOR_NTP_SECTION_TEXT,
- COLOR_NTP_SECTION_LINK,
- COLOR_NTP_SECTION_LINK_UNDERLINE,
- COLOR_CONTROL_BACKGROUND,
- COLOR_BUTTON_BACKGROUND,
- TINT_BUTTONS,
- TINT_FRAME,
- TINT_FRAME_INACTIVE,
- TINT_FRAME_INCOGNITO,
- TINT_FRAME_INCOGNITO_INACTIVE,
- TINT_BACKGROUND_TAB,
- NTP_BACKGROUND_ALIGNMENT,
- NTP_BACKGROUND_TILING,
- NTP_LOGO_ALTERNATE
-#if defined(OS_MACOSX)
- ,
- COLOR_TOOLBAR_STROKE = 1000,
- COLOR_TOOLBAR_STROKE_INACTIVE,
- COLOR_TOOLBAR_BUTTON_STROKE,
- COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
- GRADIENT_FRAME_INCOGNITO,
- GRADIENT_FRAME_INCOGNITO_INACTIVE,
- GRADIENT_TOOLBAR,
- GRADIENT_TOOLBAR_INACTIVE,
- GRADIENT_TOOLBAR_BUTTON,
- GRADIENT_TOOLBAR_BUTTON_INACTIVE,
- GRADIENT_TOOLBAR_BUTTON_PRESSED,
- GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE
-#endif // OS_MACOSX
- };
-
- // A bitfield mask for alignments.
- typedef enum {
- ALIGN_CENTER = 0x0,
- ALIGN_LEFT = 0x1,
- ALIGN_TOP = 0x2,
- ALIGN_RIGHT = 0x4,
- ALIGN_BOTTOM = 0x8,
- } AlignmentMasks;
-
- // Background tiling choices.
- typedef enum {
- NO_REPEAT = 0,
- REPEAT_X = 1,
- REPEAT_Y = 2,
- REPEAT = 3
- } Tiling;
-
- // ThemeProvider implementation.
- virtual void Init(Profile* profile);
- virtual SkBitmap* GetBitmapNamed(int id) const;
- virtual SkColor GetColor(int id) const;
- virtual bool GetDisplayProperty(int id, int* result) const;
- virtual bool ShouldUseNativeFrame() const;
- virtual bool HasCustomImage(int id) const;
- virtual RefCountedMemory* GetRawData(int id) const;
-#if defined(OS_LINUX)
- // GdkPixbufs returned by GetPixbufNamed and GetRTLEnabledPixbufNamed are
- // shared instances owned by the theme provider and should not be freed.
- virtual GdkPixbuf* GetPixbufNamed(int id) const;
- virtual GdkPixbuf* GetRTLEnabledPixbufNamed(int id) const;
-#elif defined(OS_MACOSX)
- 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;
-#endif
-
- // Set the current theme to the theme defined in |extension|.
- virtual void SetTheme(Extension* extension);
-
- // Reset the theme to default.
- virtual void UseDefaultTheme();
-
- // Set the current theme to the native theme. On some platforms, the native
- // theme is the default theme.
- virtual void SetNativeTheme() { UseDefaultTheme(); }
-
- // Whether we're using the chrome default theme. Virtual so linux can check
- // if we're using the GTK theme.
- virtual bool UsingDefaultTheme();
-
- // Gets the id of the last installed theme. (The theme may have been further
- // locally customized.)
- std::string GetThemeID() const;
-
- // This class needs to keep track of the number of theme infobars so that we
- // clean up unused themes.
- void OnInfobarDisplayed();
-
- // Decrements the number of theme infobars. If the last infobar has been
- // destroyed, uninstalls all themes that aren't the currently selected.
- void OnInfobarDestroyed();
-
- // Convert a bitfield alignment into a string like "top left". Public so that
- // it can be used to generate CSS values. Takes a bitfield of AlignmentMasks.
- static std::string AlignmentToString(int alignment);
-
- // Parse alignments from something like "top left" into a bitfield of
- // AlignmentMasks
- static int StringToAlignment(const std::string& alignment);
-
- // Convert a tiling value into a string like "no-repeat". Public
- // so that it can be used to generate CSS values. Takes a Tiling.
- static std::string TilingToString(int tiling);
-
- // Parse tiling values from something like "no-repeat" into a Tiling value.
- static int StringToTiling(const std::string& tiling);
-
- // Returns the default tint for the given tint |id| TINT_* enum value.
- static color_utils::HSL GetDefaultTint(int id);
-
- // Returns the default color for the given color |id| COLOR_* enum value.
- static SkColor GetDefaultColor(int id);
-
- // Returns true and sets |result| to the requested default property, if |id|
- // is valid.
- static bool GetDefaultDisplayProperty(int id, int* result);
-
- // Returns the set of IDR_* resources that should be tinted.
- static const std::set<int>& GetTintableToolbarButtons();
-
- // Save the images to be written to disk, mapping file path to id.
- typedef std::map<FilePath, int> ImagesDiskCache;
-
- protected:
- // Get the specified tint - |id| is one of the TINT_* enum values.
- color_utils::HSL GetTint(int id) const;
-
- // Clears all the override fields and saves the dictionary.
- virtual void ClearAllThemeData();
-
- // Load theme data from preferences.
- virtual void LoadThemePrefs();
-
- // Let all the browser views know that themes have changed.
- // extension is NULL iff the theme is being set to the
- // default/system theme.
- virtual void NotifyThemeChanged(Extension* extension);
-
-#if defined(OS_MACOSX)
- // Let all the browser views know that themes have changed in a platform way.
- virtual void NotifyPlatformThemeChanged();
-#endif // OS_MACOSX
-
- // Clears the platform-specific caches. Do not call directly; it's called
- // from ClearCaches().
- virtual void FreePlatformCaches();
-
- Profile* profile() { return profile_; }
-
- private:
- friend class BrowserThemeProviderTest;
-
- // Saves the filename of the cached theme pack.
- void SavePackName(const FilePath& pack_path);
-
- // Save the id of the last theme installed.
- void SaveThemeID(const std::string& id);
-
- // Implementation of SetTheme() (and the fallback from LoadThemePrefs() in
- // case we don't have a theme pack).
- void BuildFromExtension(Extension* extension);
-
- // Remove preference values for themes that are no longer in use.
- void RemoveUnusedThemes();
-
-#if defined(OS_LINUX)
- // Loads an image and flips it horizontally if |rtl_enabled| is true.
- GdkPixbuf* GetPixbufImpl(int id, bool rtl_enabled) const;
-#endif
-
-#if defined(OS_LINUX)
- typedef std::map<int, GdkPixbuf*> GdkPixbufMap;
- mutable GdkPixbufMap gdk_pixbufs_;
-#elif defined(OS_MACOSX)
- typedef std::map<int, NSImage*> NSImageMap;
- mutable NSImageMap nsimage_cache_;
-
- // The bool member of the pair is whether the color is a default color.
- typedef std::map<int, std::pair<NSColor*, bool> > NSColorMap;
- mutable NSColorMap nscolor_cache_;
-
- typedef std::map<int, NSGradient*> NSGradientMap;
- mutable NSGradientMap nsgradient_cache_;
-#endif
-
- ResourceBundle& rb_;
- Profile* profile_;
-
- scoped_refptr<BrowserThemePack> theme_pack_;
-
- // The number of infobars currently displayed.
- int number_of_infobars_;
-
- DISALLOW_COPY_AND_ASSIGN(BrowserThemeProvider);
-};
-
-#endif // CHROME_BROWSER_BROWSER_THEME_PROVIDER_H_
diff --git a/chrome/browser/browser_theme_provider_gtk.cc b/chrome/browser/browser_theme_provider_gtk.cc
deleted file mode 100644
index 8052086..0000000
--- a/chrome/browser/browser_theme_provider_gtk.cc
+++ /dev/null
@@ -1,73 +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/browser_theme_provider.h"
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-
-#include "base/i18n/rtl.h"
-#include "base/logging.h"
-#include "gfx/gtk_util.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-GdkPixbuf* BrowserThemeProvider::GetPixbufNamed(int id) const {
- return GetPixbufImpl(id, false);
-}
-
-GdkPixbuf* BrowserThemeProvider::GetRTLEnabledPixbufNamed(int id) const {
- return GetPixbufImpl(id, true);
-}
-
-GdkPixbuf* BrowserThemeProvider::GetPixbufImpl(int id, bool rtl_enabled) const {
- DCHECK(CalledOnValidThread());
- // Use the negative |resource_id| for the key for BIDI-aware images.
- int key = rtl_enabled ? -id : id;
-
- // Check to see if we already have the pixbuf in the cache.
- GdkPixbufMap::const_iterator pixbufs_iter = gdk_pixbufs_.find(key);
- if (pixbufs_iter != gdk_pixbufs_.end())
- return pixbufs_iter->second;
-
- SkBitmap* bitmap = GetBitmapNamed(id);
- GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
-
- // We loaded successfully. Cache the pixbuf.
- if (pixbuf) {
- if (base::i18n::IsRTL() && rtl_enabled) {
- GdkPixbuf* original_pixbuf = pixbuf;
- pixbuf = gdk_pixbuf_flip(pixbuf, TRUE);
- g_object_unref(original_pixbuf);
- }
-
- gdk_pixbufs_[key] = pixbuf;
- return pixbuf;
- }
-
- // We failed to retrieve the bitmap, show a debugging red square.
- LOG(WARNING) << "Unable to load GdkPixbuf with id " << id;
- NOTREACHED(); // Want to assert in debug mode.
-
- static GdkPixbuf* empty_bitmap = NULL;
- if (!empty_bitmap) {
- // The placeholder bitmap is bright red so people notice the problem.
- // This bitmap will be leaked, but this code should never be hit.
- scoped_ptr<SkBitmap> skia_bitmap(new SkBitmap());
- skia_bitmap->setConfig(SkBitmap::kARGB_8888_Config, 32, 32);
- skia_bitmap->allocPixels();
- skia_bitmap->eraseARGB(255, 255, 0, 0);
- empty_bitmap = gfx::GdkPixbufFromSkBitmap(skia_bitmap.get());
- }
- return empty_bitmap;
-}
-
-void BrowserThemeProvider::FreePlatformCaches() {
- DCHECK(CalledOnValidThread());
-
- // Free GdkPixbufs.
- for (GdkPixbufMap::iterator i = gdk_pixbufs_.begin();
- i != gdk_pixbufs_.end(); i++) {
- g_object_unref(i->second);
- }
- gdk_pixbufs_.clear();
-}
diff --git a/chrome/browser/browser_theme_provider_mac.mm b/chrome/browser/browser_theme_provider_mac.mm
deleted file mode 100644
index edac255..0000000
--- a/chrome/browser/browser_theme_provider_mac.mm
+++ /dev/null
@@ -1,317 +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/browser_theme_provider.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/logging.h"
-#include "chrome/browser/browser_theme_pack.h"
-#include "gfx/color_utils.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-
-NSString* const kBrowserThemeDidChangeNotification =
- @"BrowserThemeDidChangeNotification";
-
-namespace {
-
-void HSLToHSB(const color_utils::HSL& hsl, CGFloat* h, CGFloat* s, CGFloat* b) {
- SkColor color = color_utils::HSLToSkColor(hsl, 255); // alpha doesn't matter
- SkScalar hsv[3];
- SkColorToHSV(color, hsv);
-
- *h = SkScalarToDouble(hsv[0]) / 360.0;
- *s = SkScalarToDouble(hsv[1]);
- *b = SkScalarToDouble(hsv[2]);
-}
-
-}
-
-NSImage* BrowserThemeProvider::GetNSImageNamed(int id,
- bool allow_default) const {
- DCHECK(CalledOnValidThread());
-
- if (!allow_default && !HasCustomImage(id))
- return nil;
-
- // Check to see if we already have the image in the cache.
- NSImageMap::const_iterator nsimage_iter = nsimage_cache_.find(id);
- if (nsimage_iter != nsimage_cache_.end())
- return nsimage_iter->second;
-
- // Why don't we load the file directly into the image instead of the whole
- // SkBitmap > native conversion?
- // - For consistency with other platforms.
- // - To get the generated tinted images.
- SkBitmap* bitmap = GetBitmapNamed(id);
- NSImage* nsimage = gfx::SkBitmapToNSImage(*bitmap);
-
- // We loaded successfully. Cache the image.
- if (nsimage) {
- nsimage_cache_[id] = [nsimage retain];
- return nsimage;
- }
-
- // We failed to retrieve the bitmap, show a debugging red square.
- LOG(WARNING) << "Unable to load NSImage with id " << id;
- NOTREACHED(); // Want to assert in debug mode.
-
- static NSImage* empty_image = NULL;
- if (!empty_image) {
- // The placeholder image is bright red so people notice the problem. This
- // image will be leaked, but this code should never be hit.
- NSRect image_rect = NSMakeRect(0, 0, 32, 32);
- empty_image = [[NSImage alloc] initWithSize:image_rect.size];
- [empty_image lockFocus];
- [[NSColor redColor] set];
- NSRectFill(image_rect);
- [empty_image unlockFocus];
- }
-
- return empty_image;
-}
-
-NSColor* BrowserThemeProvider::GetNSImageColorNamed(int id,
- bool allow_default) const {
- DCHECK(CalledOnValidThread());
-
- // Check to see if we already have the color in the cache.
- NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
- if (nscolor_iter != nscolor_cache_.end()) {
- bool cached_is_default = nscolor_iter->second.second;
- if (!cached_is_default || allow_default)
- return nscolor_iter->second.first;
- }
-
- NSImage* image = GetNSImageNamed(id, allow_default);
- if (!image)
- return nil;
- NSColor* image_color = [NSColor colorWithPatternImage:image];
-
- // We loaded successfully. Cache the color.
- if (image_color) {
- nscolor_cache_[id] = std::make_pair([image_color retain],
- !HasCustomImage(id));
- }
-
- return image_color;
-}
-
-NSColor* BrowserThemeProvider::GetNSColor(int id,
- bool allow_default) const {
- DCHECK(CalledOnValidThread());
-
- // Check to see if we already have the color in the cache.
- NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
- if (nscolor_iter != nscolor_cache_.end()) {
- bool cached_is_default = nscolor_iter->second.second;
- if (!cached_is_default || allow_default)
- return nscolor_iter->second.first;
- }
-
- bool is_default = false;
- SkColor sk_color;
- if (theme_pack_.get() && theme_pack_->GetColor(id, &sk_color)) {
- is_default = false;
- } else {
- is_default = true;
- sk_color = GetDefaultColor(id);
- }
-
- if (is_default && !allow_default)
- return nil;
-
- NSColor* color = [NSColor
- colorWithCalibratedRed:SkColorGetR(sk_color)/255.0
- green:SkColorGetG(sk_color)/255.0
- blue:SkColorGetB(sk_color)/255.0
- alpha:SkColorGetA(sk_color)/255.0];
-
- // We loaded successfully. Cache the color.
- if (color)
- nscolor_cache_[id] = std::make_pair([color retain], is_default);
-
- return color;
-}
-
-NSColor* BrowserThemeProvider::GetNSColorTint(int id,
- bool allow_default) const {
- DCHECK(CalledOnValidThread());
-
- // Check to see if we already have the color in the cache.
- NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
- if (nscolor_iter != nscolor_cache_.end()) {
- bool cached_is_default = nscolor_iter->second.second;
- if (!cached_is_default || allow_default)
- return nscolor_iter->second.first;
- }
-
- bool is_default = false;
- color_utils::HSL tint;
- if (theme_pack_.get() && theme_pack_->GetTint(id, &tint)) {
- is_default = false;
- } else {
- is_default = true;
- tint = GetDefaultTint(id);
- }
-
- if (is_default && !allow_default)
- return nil;
-
- NSColor* tint_color = nil;
- if (tint.h == -1 && tint.s == -1 && tint.l == -1) {
- tint_color = [NSColor blackColor];
- } else {
- CGFloat hue, saturation, brightness;
- HSLToHSB(tint, &hue, &saturation, &brightness);
-
- tint_color = [NSColor colorWithCalibratedHue:hue
- saturation:saturation
- brightness:brightness
- alpha:1.0];
- }
-
- // We loaded successfully. Cache the color.
- if (tint_color)
- nscolor_cache_[id] = std::make_pair([tint_color retain], is_default);
-
- return tint_color;
-}
-
-NSGradient* BrowserThemeProvider::GetNSGradient(int id) const {
- DCHECK(CalledOnValidThread());
-
- // Check to see if we already have the gradient in the cache.
- NSGradientMap::const_iterator nsgradient_iter = nsgradient_cache_.find(id);
- if (nsgradient_iter != nsgradient_cache_.end())
- return nsgradient_iter->second;
-
- NSGradient* gradient = nil;
-
- // Note that we are not leaking when we assign a retained object to
- // |gradient|; in all cases we cache it before we return.
- switch (id) {
- case GRADIENT_FRAME_INCOGNITO:
- case GRADIENT_FRAME_INCOGNITO_INACTIVE: {
- // TODO(avi): can we simplify this?
- BOOL active = id == GRADIENT_FRAME_INCOGNITO;
- NSColor* base_color = [NSColor colorWithCalibratedRed:83/255.0
- green:108.0/255.0
- blue:140/255.0
- alpha:1.0];
-
- NSColor *start_color =
- [base_color gtm_colorAdjustedFor:GTMColorationBaseMidtone
- faded:!active];
- NSColor *end_color =
- [base_color gtm_colorAdjustedFor:GTMColorationBaseShadow
- faded:!active];
-
- if (!active) {
- start_color = [start_color gtm_colorByAdjustingLuminance:0.1
- saturation:0.5];
- end_color = [end_color gtm_colorByAdjustingLuminance:0.1
- saturation:0.5];
- }
-
- gradient = [[NSGradient alloc] initWithStartingColor:start_color
- endingColor:end_color];
- break;
- }
-
- case GRADIENT_TOOLBAR:
- case GRADIENT_TOOLBAR_INACTIVE: {
- NSColor* base_color = [NSColor colorWithCalibratedWhite:0.2 alpha:1.0];
- BOOL faded = (id == GRADIENT_TOOLBAR_INACTIVE ) ||
- (id == GRADIENT_TOOLBAR_BUTTON_INACTIVE);
- NSColor* start_color =
- [base_color gtm_colorAdjustedFor:GTMColorationLightHighlight
- faded:faded];
- NSColor* mid_color =
- [base_color gtm_colorAdjustedFor:GTMColorationLightMidtone
- faded:faded];
- NSColor* end_color =
- [base_color gtm_colorAdjustedFor:GTMColorationLightShadow
- faded:faded];
- NSColor* glow_color =
- [base_color gtm_colorAdjustedFor:GTMColorationLightPenumbra
- faded:faded];
-
- gradient =
- [[NSGradient alloc] initWithColorsAndLocations:start_color, 0.0,
- mid_color, 0.25,
- end_color, 0.5,
- glow_color, 0.75,
- nil];
- break;
- }
-
- case GRADIENT_TOOLBAR_BUTTON:
- case GRADIENT_TOOLBAR_BUTTON_INACTIVE: {
- NSColor* start_color = [NSColor colorWithCalibratedWhite:1.0 alpha:0.0];
- NSColor* end_color = [NSColor colorWithCalibratedWhite:1.0 alpha:0.3];
- gradient = [[NSGradient alloc] initWithStartingColor:start_color
- endingColor:end_color];
- break;
- }
- case GRADIENT_TOOLBAR_BUTTON_PRESSED:
- case GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE: {
- NSColor* base_color = [NSColor colorWithCalibratedWhite:0.5 alpha:1.0];
- BOOL faded = id == GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE;
- NSColor* start_color =
- [base_color gtm_colorAdjustedFor:GTMColorationBaseShadow
- faded:faded];
- NSColor* end_color =
- [base_color gtm_colorAdjustedFor:GTMColorationBaseMidtone
- faded:faded];
-
- gradient = [[NSGradient alloc] initWithStartingColor:start_color
- endingColor:end_color];
- break;
- }
- default:
- LOG(WARNING) << "Gradient request with unknown id " << id;
- NOTREACHED(); // Want to assert in debug mode.
- break;
- }
-
- // We loaded successfully. Cache the gradient.
- if (gradient)
- nsgradient_cache_[id] = gradient; // created retained
-
- return gradient;
-}
-
-// Let all the browser views know that themes have changed in a platform way.
-void BrowserThemeProvider::NotifyPlatformThemeChanged() {
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter postNotificationName:kBrowserThemeDidChangeNotification
- object:[NSValue valueWithPointer:this]];
-}
-
-void BrowserThemeProvider::FreePlatformCaches() {
- DCHECK(CalledOnValidThread());
-
- // Free images.
- for (NSImageMap::iterator i = nsimage_cache_.begin();
- i != nsimage_cache_.end(); i++) {
- [i->second release];
- }
- nsimage_cache_.clear();
-
- // Free colors.
- for (NSColorMap::iterator i = nscolor_cache_.begin();
- i != nscolor_cache_.end(); i++) {
- [i->second.first release];
- }
- nscolor_cache_.clear();
-
- // Free gradients.
- for (NSGradientMap::iterator i = nsgradient_cache_.begin();
- i != nsgradient_cache_.end(); i++) {
- [i->second release];
- }
- nsgradient_cache_.clear();
-}
diff --git a/chrome/browser/browser_theme_provider_unittest.cc b/chrome/browser/browser_theme_provider_unittest.cc
deleted file mode 100644
index 533c7af..0000000
--- a/chrome/browser/browser_theme_provider_unittest.cc
+++ /dev/null
@@ -1,52 +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/browser_theme_provider.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "base/values.h"
-#include "base/json/json_reader.h"
-
-TEST(BrowserThemeProviderTest, AlignmentConversion) {
- // Verify that we get out what we put in.
- std::string top_left = "top left";
- int alignment = BrowserThemeProvider::StringToAlignment(top_left);
- EXPECT_EQ(BrowserThemeProvider::ALIGN_TOP | BrowserThemeProvider::ALIGN_LEFT,
- alignment);
- EXPECT_EQ(top_left, BrowserThemeProvider::AlignmentToString(alignment));
-
- alignment = BrowserThemeProvider::StringToAlignment("top");
- EXPECT_EQ(BrowserThemeProvider::ALIGN_TOP, alignment);
- EXPECT_EQ("top", BrowserThemeProvider::AlignmentToString(alignment));
-
- alignment = BrowserThemeProvider::StringToAlignment("left");
- EXPECT_EQ(BrowserThemeProvider::ALIGN_LEFT, alignment);
- EXPECT_EQ("left", BrowserThemeProvider::AlignmentToString(alignment));
-
- alignment = BrowserThemeProvider::StringToAlignment("right");
- EXPECT_EQ(BrowserThemeProvider::ALIGN_RIGHT, alignment);
- EXPECT_EQ("right", BrowserThemeProvider::AlignmentToString(alignment));
-
- alignment = BrowserThemeProvider::StringToAlignment("righttopbottom");
- EXPECT_EQ(BrowserThemeProvider::ALIGN_CENTER, alignment);
- EXPECT_EQ("", BrowserThemeProvider::AlignmentToString(alignment));
-}
-
-TEST(BrowserThemeProviderTest, AlignmentConversionInput) {
- // Verify that we output in an expected format.
- int alignment = BrowserThemeProvider::StringToAlignment("right bottom");
- EXPECT_EQ("bottom right", BrowserThemeProvider::AlignmentToString(alignment));
-
- // Verify that bad strings don't cause explosions.
- alignment = BrowserThemeProvider::StringToAlignment("new zealand");
- EXPECT_EQ("", BrowserThemeProvider::AlignmentToString(alignment));
-
- // Verify that bad strings don't cause explosions.
- alignment = BrowserThemeProvider::StringToAlignment("new zealand top");
- EXPECT_EQ("top", BrowserThemeProvider::AlignmentToString(alignment));
-
- // Verify that bad strings don't cause explosions.
- alignment = BrowserThemeProvider::StringToAlignment("new zealandtop");
- EXPECT_EQ("", BrowserThemeProvider::AlignmentToString(alignment));
-}
diff --git a/chrome/browser/browser_trial.h b/chrome/browser/browser_trial.h
index f878a14..9af5a27 100644
--- a/chrome/browser/browser_trial.h
+++ b/chrome/browser/browser_trial.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_BROWSER_TRIAL_H_
#define CHROME_BROWSER_BROWSER_TRIAL_H_
+#pragma once
#include "base/field_trial.h"
diff --git a/chrome/browser/browser_uitest.cc b/chrome/browser/browser_uitest.cc
index 2058b18..8ec30a2 100644
--- a/chrome/browser/browser_uitest.cc
+++ b/chrome/browser/browser_uitest.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/base_paths.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/path_service.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/test/test_file_util.h"
@@ -22,7 +24,7 @@
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "net/base/net_util.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
namespace {
@@ -85,10 +87,10 @@ TEST_F(BrowserTest, NullOpenerRedirectForksProcess) {
if (in_process_renderer())
return;
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
+
FilePath test_file(test_data_directory_);
scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
ASSERT_TRUE(window.get());
@@ -136,10 +138,10 @@ TEST_F(BrowserTest, MAYBE_OtherRedirectsDontForkProcess) {
if (in_process_renderer())
return;
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
+
FilePath test_file(test_data_directory_);
scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
ASSERT_TRUE(window.get());
@@ -277,8 +279,7 @@ public:
file_util::Delete(tmp_profile_, true);
file_util::CreateDirectory(tmp_profile_);
- launch_arguments_.AppendSwitchWithValue(switches::kUserDataDir,
- tmp_profile_.ToWStringHack());
+ launch_arguments_.AppendSwitchPath(switches::kUserDataDir, tmp_profile_);
}
bool LaunchAppWithProfile() {
@@ -311,8 +312,7 @@ class AppModeTest : public UITest {
test_file = test_file.AppendASCII("title1.html");
GURL test_file_url(net::FilePathToFileURL(test_file));
- launch_arguments_.AppendSwitchWithValue(switches::kApp,
- test_file_url.spec());
+ launch_arguments_.AppendSwitchASCII(switches::kApp, test_file_url.spec());
}
};
@@ -355,4 +355,27 @@ TEST_F(RunInBackgroundTest, RunInBackgroundBasicTest) {
EXPECT_EQ(1, window_count);
}
+// Tests to ensure that the browser continues running in the background after
+// the last window closes.
+class NoStartupWindowTest : public UITest {
+ public:
+ NoStartupWindowTest() {
+ launch_arguments_.AppendSwitch(switches::kNoStartupWindow);
+ launch_arguments_.AppendSwitch(switches::kKeepAliveForTest);
+ }
+};
+
+TEST_F(NoStartupWindowTest, NoStartupWindowBasicTest) {
+ // No browser window should be started by default.
+ int window_count;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ EXPECT_EQ(0, window_count);
+
+ // Starting a browser window should work just fine.
+ ASSERT_TRUE(IsBrowserRunning());
+ ASSERT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_NORMAL, true));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ EXPECT_EQ(1, window_count);
+}
+
} // namespace
diff --git a/chrome/browser/browser_unittest.cc b/chrome/browser/browser_unittest.cc
deleted file mode 100644
index e6a530e..0000000
--- a/chrome/browser/browser_unittest.cc
+++ /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.
-
-#include "chrome/browser/browser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const struct NavigationScenario {
- bool pinned;
- const char* url;
- const char* referrer;
- PageTransition::Type transition;
- WindowOpenDisposition original_disposition;
- WindowOpenDisposition result_disposition;
-} kNavigationScenarios[] = {
- // Disposition changes to new foreground.
- { true,
- "http://www.example.com",
- "http://www.google.com",
- PageTransition::LINK,
- CURRENT_TAB,
- NEW_FOREGROUND_TAB },
- // Also works with AUTO_BOOKMARK.
- { true,
- "http://www.example.com",
- "http://www.google.com",
- PageTransition::AUTO_BOOKMARK,
- CURRENT_TAB,
- NEW_FOREGROUND_TAB },
- // Also works with TYPED.
- { true,
- "http://www.example.com",
- "http://www.google.com",
- PageTransition::TYPED,
- CURRENT_TAB,
- NEW_FOREGROUND_TAB },
- // Also happens if the schemes differ.
- { true,
- "ftp://www.example.com",
- "http://www.example.com",
- PageTransition::LINK,
- CURRENT_TAB,
- NEW_FOREGROUND_TAB },
- // Don't choke on an empty referrer.
- { true,
- "ftp://www.example.com",
- "",
- PageTransition::LINK,
- CURRENT_TAB,
- NEW_FOREGROUND_TAB },
- // Unpinned tab - no change.
- { false,
- "http://www.example.com",
- "http://www.google.com",
- PageTransition::LINK,
- CURRENT_TAB,
- CURRENT_TAB },
- // Original disposition is not CURRENT_TAB - no change.
- { true,
- "http://www.example.com",
- "http://www.google.com",
- PageTransition::LINK,
- NEW_BACKGROUND_TAB,
- NEW_BACKGROUND_TAB },
- // Other PageTransition type - no change.
- { true,
- "http://www.example.com",
- "http://www.google.com",
- PageTransition::RELOAD,
- CURRENT_TAB,
- CURRENT_TAB },
- // Same domain and scheme - no change.
- { true,
- "http://www.google.com/reader",
- "http://www.google.com",
- PageTransition::LINK,
- CURRENT_TAB,
- CURRENT_TAB },
- // Switching between http and https - no change.
- { true,
- "https://www.example.com",
- "http://www.example.com",
- PageTransition::LINK,
- CURRENT_TAB,
- CURRENT_TAB },
- // Switching between https and http - no change.
- { true,
- "http://www.example.com",
- "https://www.example.com",
- PageTransition::LINK,
- CURRENT_TAB,
- CURRENT_TAB },
-};
-
-} // namespace
-
-TEST(BrowserTest, PinnedTabDisposition) {
- for (size_t i = 0; i < arraysize(kNavigationScenarios); ++i) {
- EXPECT_EQ(kNavigationScenarios[i].result_disposition,
- Browser::AdjustWindowOpenDispositionForTab(
- kNavigationScenarios[i].pinned,
- GURL(kNavigationScenarios[i].url),
- GURL(kNavigationScenarios[i].referrer),
- kNavigationScenarios[i].transition,
- kNavigationScenarios[i].original_disposition)) << i;
- }
-}
diff --git a/chrome/browser/browser_url_handler.cc b/chrome/browser/browser_url_handler.cc
index b209e04..6707606 100644
--- a/chrome/browser/browser_url_handler.cc
+++ b/chrome/browser/browser_url_handler.cc
@@ -60,7 +60,7 @@ static bool ReverseViewSource(GURL* url, Profile* profile) {
// Handles rewriting DOM UI URLs.
static bool HandleDOMUI(GURL* url, Profile* profile) {
- if (!DOMUIFactory::UseDOMUIForURL(*url))
+ if (!DOMUIFactory::UseDOMUIForURL(profile, *url))
return false;
// Special case the new tab page. In older versions of Chrome, the new tab
diff --git a/chrome/browser/browser_url_handler.h b/chrome/browser/browser_url_handler.h
index e8b8a97..b2e0982 100644
--- a/chrome/browser/browser_url_handler.h
+++ b/chrome/browser/browser_url_handler.h
@@ -11,6 +11,7 @@
#ifndef CHROME_BROWSER_BROWSER_URL_HANDLER_H_
#define CHROME_BROWSER_BROWSER_URL_HANDLER_H_
+#pragma once
#include <vector>
#include <utility>
@@ -43,6 +44,7 @@ class BrowserURLHandler {
// RewriteURLIfNecessary is called.
static void InitURLHandlers();
+ private:
// The list of known URLHandlers, optionally with reverse-rewriters.
typedef std::pair<URLHandler, URLHandler> HandlerPair;
static std::vector<HandlerPair> url_handlers_;
diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h
index d4e679e..4ff6d5e 100644
--- a/chrome/browser/browser_window.h
+++ b/chrome/browser/browser_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BROWSER_WINDOW_H_
#define CHROME_BROWSER_BROWSER_WINDOW_H_
+#pragma once
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/content_settings_types.h"
@@ -19,7 +20,6 @@ class LocationBar;
class Profile;
class StatusBubble;
class TabContents;
-class TabContentsContainer;
class TemplateURL;
#if !defined(OS_MACOSX)
class ToolbarView;
@@ -60,6 +60,10 @@ class BrowserWindow {
// state if necessary.
virtual void Activate() = 0;
+ // Deactivates the window, making the next window in the Z order the active
+ // window.
+ virtual void Deactivate() = 0;
+
// Returns true if the window is currently the active/focused window.
virtual bool IsActive() const = 0;
@@ -83,17 +87,14 @@ class BrowserWindow {
// BrowserView.
virtual void SelectedTabToolbarSizeChanged(bool is_animating) = 0;
- // Notification for the Extension Shelf changing its size.
- virtual void SelectedTabExtensionShelfSizeChanged() = 0;
-
// Inform the frame that the selected tab favicon or title has changed. Some
// frames may need to refresh their title bar.
virtual void UpdateTitleBar() = 0;
- // Invoked when the visibility of the bookmark bar or extension shelf changes.
- // NOTE: this is NOT sent when the user toggles the visibility of one of
- // these shelves, but rather when the user transitions from a page that forces
- // the shelves to be visibile to one that doesn't have them visible (or
+ // Invoked when the visibility of the bookmark bar.
+ // NOTE: this is NOT sent when the user toggles the visibility of this,
+ // but rather when the user transitions from a page that forces
+ // it to be visibile to one that doesn't have it visible (or
// vice-versa).
// TODO(sky): see about routing visibility pref changing through here too.
virtual void ShelfVisibilityChanged() = 0;
@@ -186,9 +187,6 @@ class BrowserWindow {
// Shows or hides the bookmark bar depending on its current visibility.
virtual void ToggleBookmarkBar() = 0;
- // Shows or hides the extension shelf depending on its current visibility.
- virtual void ToggleExtensionShelf() = 0;
-
// Shows the About Chrome dialog box.
virtual views::Window* ShowAboutChromeDialog() = 0;
@@ -309,6 +307,22 @@ class BrowserWindow {
// Switches between available tabstrip display modes.
virtual void ToggleTabStripMode() = 0;
+#if defined(OS_MACOSX)
+ // Opens the tabpose view.
+ virtual void OpenTabpose() = 0;
+#endif
+
+ // Invoked when the match preview's tab contents should be shown.
+ virtual void ShowMatchPreview() = 0;
+
+ // Invoked when the match preview's tab contents should be hidden.
+ virtual void HideMatchPreview() = 0;
+
+ // Returns the desired bounds for match preview in screen coordinates. Note
+ // that if match preview isn't currently visible this returns the bounds the
+ // match preview would be placed at.
+ virtual gfx::Rect GetMatchPreviewBounds() = 0;
+
// Construct a BrowserWindow implementation for the specified |browser|.
static BrowserWindow* CreateBrowserWindow(Browser* browser);
@@ -320,7 +334,7 @@ class BrowserWindow {
friend class BrowserView;
virtual void DestroyBrowser() = 0;
- ~BrowserWindow() {}
+ virtual ~BrowserWindow() {}
};
#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
@@ -346,9 +360,15 @@ class BrowserWindowTesting {
// Returns the TabContentsContainer.
virtual views::View* GetTabContentsContainerView() const = 0;
+ // Returns the TabContentsContainer.
+ virtual views::View* GetSidebarContainerView() const = 0;
+
// Returns the ToolbarView.
virtual ToolbarView* GetToolbarView() const = 0;
#endif
+
+ protected:
+ virtual ~BrowserWindowTesting() {}
};
#endif // CHROME_BROWSER_BROWSER_WINDOW_H_
diff --git a/chrome/browser/browsing_data_appcache_helper.cc b/chrome/browser/browsing_data_appcache_helper.cc
index 3ce7106..f898318 100644
--- a/chrome/browser/browsing_data_appcache_helper.cc
+++ b/chrome/browser/browsing_data_appcache_helper.cc
@@ -118,19 +118,21 @@ void CannedBrowsingDataAppCacheHelper::AddAppCache(const GURL& manifest_url) {
return;
}
- appcache_infos_.push_back(
- appcache::AppCacheInfo(manifest_url,
- 0,
- base::Time(),
- base::Time(),
- base::Time()));
+ appcache::AppCacheInfo info;
+ info.manifest_url = manifest_url;
+ appcache_infos_.push_back(info);
}
void CannedBrowsingDataAppCacheHelper::Reset() {
info_collection_->infos_by_origin.clear();
}
+bool CannedBrowsingDataAppCacheHelper::empty() const {
+ return info_collection_->infos_by_origin.empty();
+}
+
void CannedBrowsingDataAppCacheHelper::StartFetching(
Callback0::Type* completion_callback) {
completion_callback->Run();
+ delete completion_callback;
}
diff --git a/chrome/browser/browsing_data_appcache_helper.h b/chrome/browser/browsing_data_appcache_helper.h
index d7da4a6..58d92af 100644
--- a/chrome/browser/browsing_data_appcache_helper.h
+++ b/chrome/browser/browsing_data_appcache_helper.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_BROWSING_DATA_APPCACHE_HELPER_H_
#define CHROME_BROWSER_BROWSING_DATA_APPCACHE_HELPER_H_
-
-#include <string>
+#pragma once
#include "base/scoped_ptr.h"
#include "base/task.h"
@@ -64,6 +63,9 @@ class CannedBrowsingDataAppCacheHelper : public BrowsingDataAppCacheHelper {
// Clears the list of canned caches.
void Reset();
+ // True if no appcaches are currently stored.
+ bool empty() const;
+
// BrowsingDataAppCacheHelper methods.
virtual void StartFetching(Callback0::Type* completion_callback);
virtual void CancelNotification() {}
diff --git a/chrome/browser/browsing_data_appcache_helper_unittest.cc b/chrome/browser/browsing_data_appcache_helper_unittest.cc
index e5631b1..8373485 100644
--- a/chrome/browser/browsing_data_appcache_helper_unittest.cc
+++ b/chrome/browser/browsing_data_appcache_helper_unittest.cc
@@ -9,7 +9,7 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-class TestCompletionCallback : public CallbackRunner<Tuple0> {
+class TestCompletionCallback {
public:
TestCompletionCallback()
: have_result_(false) {
@@ -17,9 +17,10 @@ class TestCompletionCallback : public CallbackRunner<Tuple0> {
bool have_result() const { return have_result_; }
- virtual void RunWithParams(const Tuple0& params) {
+ void callback() {
have_result_ = true;
}
+
private:
bool have_result_;
};
@@ -40,7 +41,8 @@ TEST(CannedBrowsingDataAppCacheHelperTest, SetInfo) {
helper->AddAppCache(manifest3);
TestCompletionCallback callback;
- helper->StartFetching(&callback);
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
ASSERT_TRUE(callback.have_result());
std::map<GURL, appcache::AppCacheInfoVector>& collection =
@@ -71,7 +73,8 @@ TEST(CannedBrowsingDataAppCacheHelperTest, Unique) {
helper->AddAppCache(manifest);
TestCompletionCallback callback;
- helper->StartFetching(&callback);
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
ASSERT_TRUE(callback.have_result());
std::map<GURL, appcache::AppCacheInfoVector>& collection =
@@ -82,3 +85,18 @@ TEST(CannedBrowsingDataAppCacheHelperTest, Unique) {
ASSERT_EQ(1u, collection[manifest.GetOrigin()].size());
EXPECT_EQ(manifest, collection[manifest.GetOrigin()].at(0).manifest_url);
}
+
+TEST(CannedBrowsingDataAppCacheHelperTest, Empty) {
+ TestingProfile profile;
+
+ GURL manifest("http://example.com/manifest.xml");
+
+ scoped_refptr<CannedBrowsingDataAppCacheHelper> helper =
+ new CannedBrowsingDataAppCacheHelper(&profile);
+
+ ASSERT_TRUE(helper->empty());
+ helper->AddAppCache(manifest);
+ ASSERT_FALSE(helper->empty());
+ helper->Reset();
+ ASSERT_TRUE(helper->empty());
+}
diff --git a/chrome/browser/browsing_data_database_helper.cc b/chrome/browser/browsing_data_database_helper.cc
index 11e5e6b..c407bc8 100644
--- a/chrome/browser/browsing_data_database_helper.cc
+++ b/chrome/browser/browsing_data_database_helper.cc
@@ -70,7 +70,7 @@ void BrowsingDataDatabaseHelper::FetchDatabaseInfoInFileThread() {
for (std::vector<string16>::const_iterator db = databases.begin();
db != databases.end(); ++db) {
FilePath file_path = tracker_->GetFullDBFilePath(ori->GetOrigin(), *db);
- file_util::FileInfo file_info;
+ base::PlatformFileInfo file_info;
if (file_util::GetFileInfo(file_path, &file_info)) {
database_info_.push_back(DatabaseInfo(
web_security_origin.host().utf8(),
@@ -147,7 +147,12 @@ void CannedBrowsingDataDatabaseHelper::Reset() {
database_info_.clear();
}
+bool CannedBrowsingDataDatabaseHelper::empty() const {
+ return database_info_.empty();
+}
+
void CannedBrowsingDataDatabaseHelper::StartFetching(
Callback1<const std::vector<DatabaseInfo>& >::Type* callback) {
callback->Run(database_info_);
+ delete callback;
}
diff --git a/chrome/browser/browsing_data_database_helper.h b/chrome/browser/browsing_data_database_helper.h
index 6020e9d..26210a7 100644
--- a/chrome/browser/browsing_data_database_helper.h
+++ b/chrome/browser/browsing_data_database_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BROWSING_DATA_DATABASE_HELPER_H_
#define CHROME_BROWSER_BROWSING_DATA_DATABASE_HELPER_H_
+#pragma once
#include <string>
#include <vector>
@@ -127,6 +128,9 @@ class CannedBrowsingDataDatabaseHelper : public BrowsingDataDatabaseHelper {
// Clear the list of canned databases.
void Reset();
+ // True if no databases are currently stored.
+ bool empty() const;
+
// BrowsingDataDatabaseHelper methods.
virtual void StartFetching(
Callback1<const std::vector<DatabaseInfo>& >::Type* callback);
diff --git a/chrome/browser/browsing_data_database_helper_browsertest.cc b/chrome/browser/browsing_data_database_helper_browsertest.cc
index 19c7c20..081d5a0 100644
--- a/chrome/browser/browsing_data_database_helper_browsertest.cc
+++ b/chrome/browser/browsing_data_database_helper_browsertest.cc
@@ -2,7 +2,10 @@
// 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/utf_string_conversions.h"
#include "chrome/browser/browsing_data_database_helper.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/testing_profile.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/browsing_data_database_helper_unittest.cc b/chrome/browser/browsing_data_database_helper_unittest.cc
index b5368c4..c8f1c18 100644
--- a/chrome/browser/browsing_data_database_helper_unittest.cc
+++ b/chrome/browser/browsing_data_database_helper_unittest.cc
@@ -4,13 +4,12 @@
#include "chrome/browser/browsing_data_database_helper.h"
+#include "base/file_util.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-class TestCompletionCallback
- : public CallbackRunner<Tuple1<
- const std::vector<BrowsingDataDatabaseHelper::DatabaseInfo>& > > {
+class TestCompletionCallback {
public:
TestCompletionCallback()
: have_result_(false) {
@@ -22,11 +21,10 @@ class TestCompletionCallback
return result_;
}
- virtual void RunWithParams(
- const Tuple1<const std::vector<
- BrowsingDataDatabaseHelper::DatabaseInfo>& >& params) {
+ void callback(const std::vector<
+ BrowsingDataDatabaseHelper::DatabaseInfo>& info) {
have_result_ = true;
- result_ = params.a;
+ result_ = info;
}
private:
@@ -55,7 +53,8 @@ TEST(CannedBrowsingDataDatabaseTest, AddDatabase) {
helper->AddDatabase(origin2, db3, "");
TestCompletionCallback callback;
- helper->StartFetching(&callback);
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
ASSERT_TRUE(callback.have_result());
std::vector<BrowsingDataDatabaseHelper::DatabaseInfo> result =
@@ -83,7 +82,8 @@ TEST(CannedBrowsingDataDatabaseTest, Unique) {
helper->AddDatabase(origin, db, "");
TestCompletionCallback callback;
- helper->StartFetching(&callback);
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
ASSERT_TRUE(callback.have_result());
std::vector<BrowsingDataDatabaseHelper::DatabaseInfo> result =
@@ -93,3 +93,19 @@ TEST(CannedBrowsingDataDatabaseTest, Unique) {
EXPECT_STREQ(origin_str, result[0].origin_identifier.c_str());
EXPECT_STREQ(db, result[0].database_name.c_str());
}
+
+TEST(CannedBrowsingDataDatabaseTest, Empty) {
+ TestingProfile profile;
+
+ const GURL origin("http://host1:1/");
+ const char db[] = "db1";
+
+ scoped_refptr<CannedBrowsingDataDatabaseHelper> helper =
+ new CannedBrowsingDataDatabaseHelper(&profile);
+
+ ASSERT_TRUE(helper->empty());
+ helper->AddDatabase(origin, db, "");
+ ASSERT_FALSE(helper->empty());
+ helper->Reset();
+ ASSERT_TRUE(helper->empty());
+}
diff --git a/chrome/browser/browsing_data_indexed_db_helper.cc b/chrome/browser/browsing_data_indexed_db_helper.cc
new file mode 100644
index 0000000..c1202a9
--- /dev/null
+++ b/chrome/browser/browsing_data_indexed_db_helper.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/browsing_data_indexed_db_helper.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/browser/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"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebSecurityOrigin;
+
+namespace {
+
+class BrowsingDataIndexedDBHelperImpl : public BrowsingDataIndexedDBHelper {
+ public:
+ explicit BrowsingDataIndexedDBHelperImpl(Profile* profile);
+
+ virtual void StartFetching(
+ Callback1<const std::vector<IndexedDBInfo>& >::Type* callback);
+ virtual void CancelNotification();
+ virtual void DeleteIndexedDBFile(const FilePath& file_path);
+
+ private:
+ virtual ~BrowsingDataIndexedDBHelperImpl();
+
+ // Enumerates all indexed database files in the WEBKIT thread.
+ void FetchIndexedDBInfoInWebKitThread();
+ // Notifies the completion callback in the UI thread.
+ void NotifyInUIThread();
+ // Delete a single indexed database file in the WEBKIT thread.
+ void DeleteIndexedDBFileInWebKitThread(const FilePath& file_path);
+
+ Profile* profile_;
+
+ // This only mutates in the WEBKIT thread.
+ std::vector<IndexedDBInfo> indexed_db_info_;
+
+ // This only mutates on the UI thread.
+ scoped_ptr<Callback1<const std::vector<IndexedDBInfo>& >::Type >
+ completion_callback_;
+ // Indicates whether or not we're currently fetching information:
+ // it's true when StartFetching() is called in the UI thread, and it's reset
+ // after we notified the callback in the UI thread.
+ // This only mutates on the UI thread.
+ bool is_fetching_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowsingDataIndexedDBHelperImpl);
+};
+
+BrowsingDataIndexedDBHelperImpl::BrowsingDataIndexedDBHelperImpl(
+ Profile* profile)
+ : profile_(profile),
+ completion_callback_(NULL),
+ is_fetching_(false) {
+ DCHECK(profile_);
+}
+
+BrowsingDataIndexedDBHelperImpl::~BrowsingDataIndexedDBHelperImpl() {
+}
+
+void BrowsingDataIndexedDBHelperImpl::StartFetching(
+ Callback1<const std::vector<IndexedDBInfo>& >::Type* callback) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(!is_fetching_);
+ DCHECK(callback);
+ is_fetching_ = true;
+ completion_callback_.reset(callback);
+ ChromeThread::PostTask(
+ ChromeThread::WEBKIT, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread));
+}
+
+void BrowsingDataIndexedDBHelperImpl::CancelNotification() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ completion_callback_.reset(NULL);
+}
+
+void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBFile(
+ const FilePath& file_path) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ ChromeThread::PostTask(
+ ChromeThread::WEBKIT, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &BrowsingDataIndexedDBHelperImpl::
+ DeleteIndexedDBFileInWebKitThread,
+ file_path));
+}
+
+void BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ file_util::FileEnumerator file_enumerator(
+ profile_->GetWebKitContext()->data_path().Append(
+ IndexedDBContext::kIndexedDBDirectory),
+ false, file_util::FileEnumerator::FILES);
+ for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
+ file_path = file_enumerator.Next()) {
+ if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) {
+ std::string name;
+ WebSecurityOrigin web_security_origin;
+ if (!IndexedDBContext::SplitIndexedDBFileName(
+ file_path, &name, &web_security_origin)) {
+ // Could not parse file name.
+ continue;
+ }
+ if (EqualsASCII(web_security_origin.protocol(),
+ chrome::kExtensionScheme)) {
+ // Extension state is not considered browsing data.
+ continue;
+ }
+ base::PlatformFileInfo file_info;
+ bool ret = file_util::GetFileInfo(file_path, &file_info);
+ if (ret) {
+ indexed_db_info_.push_back(IndexedDBInfo(
+ web_security_origin.protocol().utf8(),
+ web_security_origin.host().utf8(),
+ web_security_origin.port(),
+ web_security_origin.databaseIdentifier().utf8(),
+ web_security_origin.toString().utf8(),
+ name,
+ file_path,
+ file_info.size,
+ file_info.last_modified));
+ }
+ }
+ }
+
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &BrowsingDataIndexedDBHelperImpl::NotifyInUIThread));
+}
+
+void BrowsingDataIndexedDBHelperImpl::NotifyInUIThread() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(is_fetching_);
+ // Note: completion_callback_ mutates only in the UI thread, so it's safe to
+ // test it here.
+ if (completion_callback_ != NULL) {
+ completion_callback_->Run(indexed_db_info_);
+ completion_callback_.reset();
+ }
+ is_fetching_ = false;
+}
+
+void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBFileInWebKitThread(
+ const FilePath& file_path) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ // TODO(jochen): implement this once it's possible to delete indexed DBs.
+}
+
+} // namespace
+
+// static
+BrowsingDataIndexedDBHelper* BrowsingDataIndexedDBHelper::Create(
+ Profile* profile) {
+ return new BrowsingDataIndexedDBHelperImpl(profile);
+}
+
+CannedBrowsingDataIndexedDBHelper::CannedBrowsingDataIndexedDBHelper(
+ Profile* profile)
+ : profile_(profile) {
+ DCHECK(profile);
+}
+
+void CannedBrowsingDataIndexedDBHelper::AddIndexedDB(
+ const GURL& origin, const string16& name, const string16& description) {
+ WebSecurityOrigin web_security_origin =
+ WebSecurityOrigin::createFromString(
+ UTF8ToUTF16(origin.spec()));
+ std::string security_origin(web_security_origin.toString().utf8());
+
+ for (std::vector<IndexedDBInfo>::iterator
+ indexed_db = indexed_db_info_.begin();
+ indexed_db != indexed_db_info_.end(); ++indexed_db) {
+ if (indexed_db->origin == security_origin)
+ return;
+ }
+
+ indexed_db_info_.push_back(IndexedDBInfo(
+ web_security_origin.protocol().utf8(),
+ web_security_origin.host().utf8(),
+ web_security_origin.port(),
+ web_security_origin.databaseIdentifier().utf8(),
+ security_origin,
+ UTF16ToUTF8(name),
+ profile_->GetWebKitContext()->indexed_db_context()->
+ GetIndexedDBFilePath(name, web_security_origin),
+ 0,
+ base::Time()));
+}
+
+void CannedBrowsingDataIndexedDBHelper::Reset() {
+ indexed_db_info_.clear();
+}
+
+bool CannedBrowsingDataIndexedDBHelper::empty() const {
+ return indexed_db_info_.empty();
+}
+
+void CannedBrowsingDataIndexedDBHelper::StartFetching(
+ Callback1<const std::vector<IndexedDBInfo>& >::Type* callback) {
+ callback->Run(indexed_db_info_);
+ delete callback;
+}
diff --git a/chrome/browser/browsing_data_indexed_db_helper.h b/chrome/browser/browsing_data_indexed_db_helper.h
new file mode 100644
index 0000000..c3704ec
--- /dev/null
+++ b/chrome/browser/browsing_data_indexed_db_helper.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_BROWSER_BROWSING_DATA_INDEXED_DB_HELPER_H_
+#define CHROME_BROWSER_BROWSING_DATA_INDEXED_DB_HELPER_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/ref_counted.h"
+#include "base/time.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+
+class Profile;
+
+// BrowsingDataIndexedDBHelper is an interface for classes dealing with
+// aggregating and deleting browsing data stored in indexed databases. A
+// client of this class need to call StartFetching from the UI thread to
+// initiate the flow, and it'll be notified by the callback in its UI thread at
+// some later point. The client must call CancelNotification() if it's
+// destroyed before the callback is notified.
+class BrowsingDataIndexedDBHelper
+ : public base::RefCountedThreadSafe<BrowsingDataIndexedDBHelper> {
+ public:
+ // Contains detailed information about an indexed database.
+ struct IndexedDBInfo {
+ IndexedDBInfo(
+ const std::string& protocol,
+ const std::string& host,
+ unsigned short port,
+ const std::string& database_identifier,
+ const std::string& origin,
+ const std::string& database_name,
+ const FilePath& file_path,
+ int64 size,
+ base::Time last_modified)
+ : protocol(protocol),
+ host(host),
+ port(port),
+ database_identifier(database_identifier),
+ origin(origin),
+ database_name(database_name),
+ file_path(file_path),
+ size(size),
+ last_modified(last_modified) {
+ }
+
+ bool IsFileSchemeData() {
+ return protocol == chrome::kFileScheme;
+ }
+
+ std::string protocol;
+ std::string host;
+ unsigned short port;
+ std::string database_identifier;
+ std::string origin;
+ std::string database_name;
+ FilePath file_path;
+ int64 size;
+ base::Time last_modified;
+ };
+
+ // Create a BrowsingDataIndexedDBHelper instance for the indexed databases
+ // stored in |profile|'s user data directory.
+ static BrowsingDataIndexedDBHelper* Create(Profile* profile);
+
+ // Starts the fetching process, which will notify its completion via
+ // callback.
+ // This must be called only in the UI thread.
+ virtual void StartFetching(
+ Callback1<const std::vector<IndexedDBInfo>& >::Type* callback) = 0;
+ // Cancels the notification callback (i.e., the window that created it no
+ // longer exists).
+ // This must be called only in the UI thread.
+ virtual void CancelNotification() = 0;
+ // Requests a single indexed database file to be deleted in the WEBKIT thread.
+ virtual void DeleteIndexedDBFile(const FilePath& file_path) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<BrowsingDataIndexedDBHelper>;
+ virtual ~BrowsingDataIndexedDBHelper() {}
+};
+
+// This class is an implementation of BrowsingDataIndexedDBHelper that does
+// not fetch its information from the indexed database tracker, but gets them
+// passed as a parameter.
+class CannedBrowsingDataIndexedDBHelper
+ : public BrowsingDataIndexedDBHelper {
+ public:
+ explicit CannedBrowsingDataIndexedDBHelper(Profile* profile);
+
+ // Add a indexed database to the set of canned indexed databases that is
+ // returned by this helper.
+ void AddIndexedDB(const GURL& origin,
+ const string16& name,
+ const string16& description);
+
+ // Clear the list of canned indexed databases.
+ void Reset();
+
+ // True if no indexed databases are currently stored.
+ bool empty() const;
+
+ // BrowsingDataIndexedDBHelper methods.
+ virtual void StartFetching(
+ Callback1<const std::vector<IndexedDBInfo>& >::Type* callback);
+ virtual void CancelNotification() {}
+ virtual void DeleteIndexedDBFile(const FilePath& file_path) {}
+
+ private:
+ virtual ~CannedBrowsingDataIndexedDBHelper() {}
+
+ Profile* profile_;
+
+ std::vector<IndexedDBInfo> indexed_db_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(CannedBrowsingDataIndexedDBHelper);
+};
+
+#endif // CHROME_BROWSER_BROWSING_DATA_INDEXED_DB_HELPER_H_
diff --git a/chrome/browser/browsing_data_indexed_db_helper_unittest.cc b/chrome/browser/browsing_data_indexed_db_helper_unittest.cc
new file mode 100644
index 0000000..0cf0f0a
--- /dev/null
+++ b/chrome/browser/browsing_data_indexed_db_helper_unittest.cc
@@ -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 "testing/gtest/include/gtest/gtest.h"
+
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browsing_data_indexed_db_helper.h"
+#include "chrome/test/testing_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"
+
+namespace {
+
+class TestCompletionCallback {
+ public:
+ TestCompletionCallback() : has_result_(false) {}
+
+ bool has_result() const { return has_result_; }
+
+ const std::vector<BrowsingDataIndexedDBHelper::IndexedDBInfo>& result() {
+ return result_;
+ }
+
+ void callback(
+ const std::vector<BrowsingDataIndexedDBHelper::IndexedDBInfo>& info) {
+ has_result_ = true;
+ result_ = info;
+ }
+
+ private:
+ bool has_result_;
+ std::vector<BrowsingDataIndexedDBHelper::IndexedDBInfo> result_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCompletionCallback);
+};
+
+TEST(CannedBrowsingDataIndexedDBHelperTest, AddIndexedDB) {
+ TestingProfile profile;
+
+ const GURL origin1("http://host1:1/");
+ const GURL origin2("http://host2:1/");
+ const string16 name(ASCIIToUTF16("name"));
+ const string16 description(ASCIIToUTF16("description"));
+ const FilePath::CharType file1[] =
+ FILE_PATH_LITERAL("http_host1_1@name.indexeddb");
+ const FilePath::CharType file2[] =
+ FILE_PATH_LITERAL("http_host2_1@name.indexeddb");
+
+ scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
+ new CannedBrowsingDataIndexedDBHelper(&profile));
+ helper->AddIndexedDB(origin1, name, description);
+ helper->AddIndexedDB(origin2, name, description);
+
+ TestCompletionCallback callback;
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
+ ASSERT_TRUE(callback.has_result());
+
+ std::vector<BrowsingDataIndexedDBHelper::IndexedDBInfo> result =
+ callback.result();
+
+ ASSERT_EQ(2U, result.size());
+ EXPECT_EQ(FilePath(file1).value(), result[0].file_path.BaseName().value());
+ EXPECT_EQ(FilePath(file2).value(), result[1].file_path.BaseName().value());
+}
+
+TEST(CannedBrowsingDataIndexedDBHelperTest, Unique) {
+ TestingProfile profile;
+
+ const GURL origin("http://host1:1/");
+ const string16 name(ASCIIToUTF16("name"));
+ const string16 description(ASCIIToUTF16("description"));
+ const FilePath::CharType file[] =
+ FILE_PATH_LITERAL("http_host1_1@name.indexeddb");
+
+ scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
+ new CannedBrowsingDataIndexedDBHelper(&profile));
+ helper->AddIndexedDB(origin, name, description);
+ helper->AddIndexedDB(origin, name, description);
+
+ TestCompletionCallback callback;
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
+ ASSERT_TRUE(callback.has_result());
+
+ std::vector<BrowsingDataIndexedDBHelper::IndexedDBInfo> result =
+ callback.result();
+
+ ASSERT_EQ(1U, result.size());
+ EXPECT_EQ(FilePath(file).value(), result[0].file_path.BaseName().value());
+}
+
+TEST(CannedBrowsingDataIndexedDBHelperTest, Empty) {
+ TestingProfile profile;
+
+ const GURL origin("http://host1:1/");
+ const string16 name(ASCIIToUTF16("name"));
+ const string16 description(ASCIIToUTF16("description"));
+
+ scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
+ new CannedBrowsingDataIndexedDBHelper(&profile));
+
+ ASSERT_TRUE(helper->empty());
+ helper->AddIndexedDB(origin, name, description);
+ ASSERT_FALSE(helper->empty());
+ helper->Reset();
+ ASSERT_TRUE(helper->empty());
+}
+
+} // namespace
diff --git a/chrome/browser/browsing_data_local_storage_helper.cc b/chrome/browser/browsing_data_local_storage_helper.cc
index 2193305..1f94c03 100644
--- a/chrome/browser/browsing_data_local_storage_helper.cc
+++ b/chrome/browser/browsing_data_local_storage_helper.cc
@@ -76,7 +76,7 @@ void BrowsingDataLocalStorageHelper::FetchLocalStorageInfoInWebKitThread() {
// Extension state is not considered browsing data.
continue;
}
- file_util::FileInfo file_info;
+ base::PlatformFileInfo file_info;
bool ret = file_util::GetFileInfo(file_path, &file_info);
if (ret) {
local_storage_info_.push_back(LocalStorageInfo(
@@ -152,7 +152,12 @@ void CannedBrowsingDataLocalStorageHelper::Reset() {
local_storage_info_.clear();
}
+bool CannedBrowsingDataLocalStorageHelper::empty() const {
+ return local_storage_info_.empty();
+}
+
void CannedBrowsingDataLocalStorageHelper::StartFetching(
Callback1<const std::vector<LocalStorageInfo>& >::Type* callback) {
callback->Run(local_storage_info_);
+ delete callback;
}
diff --git a/chrome/browser/browsing_data_local_storage_helper.h b/chrome/browser/browsing_data_local_storage_helper.h
index 5d71423..1f61070 100644
--- a/chrome/browser/browsing_data_local_storage_helper.h
+++ b/chrome/browser/browsing_data_local_storage_helper.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_BROWSING_DATA_LOCAL_STORAGE_HELPER_H_
#define CHROME_BROWSER_BROWSING_DATA_LOCAL_STORAGE_HELPER_H_
+#pragma once
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/file_path.h"
@@ -120,6 +122,9 @@ class CannedBrowsingDataLocalStorageHelper
// Clear the list of canned local storages.
void Reset();
+ // True if no local storages are currently stored.
+ bool empty() const;
+
// BrowsingDataLocalStorageHelper methods.
virtual void StartFetching(
Callback1<const std::vector<LocalStorageInfo>& >::Type* callback);
diff --git a/chrome/browser/browsing_data_local_storage_helper_browsertest.cc b/chrome/browser/browsing_data_local_storage_helper_browsertest.cc
index e98c5f1..68b105d 100644
--- a/chrome/browser/browsing_data_local_storage_helper_browsertest.cc
+++ b/chrome/browser/browsing_data_local_storage_helper_browsertest.cc
@@ -7,12 +7,14 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/ref_counted.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/in_process_webkit/webkit_thread.h"
#include "chrome/browser/browsing_data_local_storage_helper.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"
#include "testing/gtest/include/gtest/gtest.h"
@@ -103,40 +105,15 @@ IN_PROC_BROWSER_TEST_F(BrowsingDataLocalStorageHelperTest, CallbackCompletes) {
ui_test_utils::RunMessageLoop();
}
-class WaitForWebKitThread
- : public base::RefCountedThreadSafe<WaitForWebKitThread> {
- public:
- void QuitUiMessageLoopAfterWebKitThreadNotified() {
- ChromeThread::PostTask(ChromeThread::WEBKIT,
- FROM_HERE,
- NewRunnableMethod(
- this, &WaitForWebKitThread::RunInWebKitThread));
- }
-
- private:
- void RunInWebKitThread() {
- ChromeThread::PostTask(ChromeThread::UI,
- FROM_HERE,
- NewRunnableMethod(
- this, &WaitForWebKitThread::RunInUiThread));
- }
-
- void RunInUiThread() {
- MessageLoop::current()->Quit();
- }
-};
-
IN_PROC_BROWSER_TEST_F(BrowsingDataLocalStorageHelperTest, DeleteSingleFile) {
scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_helper(
new BrowsingDataLocalStorageHelper(&testing_profile_));
CreateLocalStorageFilesForTest();
local_storage_helper->DeleteLocalStorageFile(
GetLocalStoragePathForTestingProfile().Append(FilePath(kTestFile0)));
- scoped_refptr<WaitForWebKitThread> wait_for_webkit_thread(
- new WaitForWebKitThread);
- wait_for_webkit_thread->QuitUiMessageLoopAfterWebKitThreadNotified();
- // Blocks until WaitForWebKitThread is notified.
- ui_test_utils::RunMessageLoop();
+ scoped_refptr<ThreadTestHelper> wait_for_webkit_thread(
+ new ThreadTestHelper(ChromeThread::WEBKIT));
+ ASSERT_TRUE(wait_for_webkit_thread->Run());
// Ensure the file has been deleted.
file_util::FileEnumerator file_enumerator(
GetLocalStoragePathForTestingProfile(),
diff --git a/chrome/browser/browsing_data_local_storage_helper_unittest.cc b/chrome/browser/browsing_data_local_storage_helper_unittest.cc
index 37c3555..fe110c3 100644
--- a/chrome/browser/browsing_data_local_storage_helper_unittest.cc
+++ b/chrome/browser/browsing_data_local_storage_helper_unittest.cc
@@ -8,9 +8,7 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-class TestCompletionCallback
- : public CallbackRunner<Tuple1<const std::vector<
- BrowsingDataLocalStorageHelper::LocalStorageInfo>& > > {
+class TestCompletionCallback {
public:
TestCompletionCallback()
: have_result_(false) {
@@ -23,11 +21,10 @@ class TestCompletionCallback
return result_;
}
- virtual void RunWithParams(
- const Tuple1<const std::vector<
- BrowsingDataLocalStorageHelper::LocalStorageInfo>& >& params) {
+ void callback(const std::vector<
+ BrowsingDataLocalStorageHelper::LocalStorageInfo>& info) {
have_result_ = true;
- result_ = params.a;
+ result_ = info;
}
private:
@@ -54,7 +51,8 @@ TEST(CannedBrowsingDataLocalStorageTest, AddLocalStorage) {
helper->AddLocalStorage(origin2);
TestCompletionCallback callback;
- helper->StartFetching(&callback);
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
ASSERT_TRUE(callback.have_result());
std::vector<BrowsingDataLocalStorageHelper::LocalStorageInfo> result =
@@ -78,7 +76,8 @@ TEST(CannedBrowsingDataLocalStorageTest, Unique) {
helper->AddLocalStorage(origin);
TestCompletionCallback callback;
- helper->StartFetching(&callback);
+ helper->StartFetching(
+ NewCallback(&callback, &TestCompletionCallback::callback));
ASSERT_TRUE(callback.have_result());
std::vector<BrowsingDataLocalStorageHelper::LocalStorageInfo> result =
@@ -87,3 +86,18 @@ TEST(CannedBrowsingDataLocalStorageTest, Unique) {
ASSERT_EQ(1u, result.size());
EXPECT_EQ(FilePath(file).value(), result[0].file_path.BaseName().value());
}
+
+TEST(CannedBrowsingDataLocalStorageTest, Empty) {
+ TestingProfile profile;
+
+ const GURL origin("http://host1:1/");
+
+ scoped_refptr<CannedBrowsingDataLocalStorageHelper> helper =
+ new CannedBrowsingDataLocalStorageHelper(&profile);
+
+ ASSERT_TRUE(helper->empty());
+ helper->AddLocalStorage(origin);
+ ASSERT_FALSE(helper->empty());
+ helper->Reset();
+ ASSERT_TRUE(helper->empty());
+}
diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc
index 329149b..8413b9e 100644
--- a/chrome/browser/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data_remover.cc
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/profile.h"
@@ -30,6 +31,7 @@
#include "net/http/http_cache.h"
#include "net/url_request/url_request_context.h"
#include "webkit/database/database_tracker.h"
+#include "webkit/database/database_util.h"
// Done so that we can use PostTask on BrowsingDataRemovers and not have
// BrowsingDataRemover implement RefCounted.
@@ -95,6 +97,25 @@ void BrowsingDataRemover::Remove(int remove_mask) {
DCHECK(!removing_);
removing_ = true;
+ std::vector<GURL> origin_whitelist;
+ ExtensionsService* extensions_service = profile_->GetExtensionsService();
+ if (extensions_service && extensions_service->HasInstalledExtensions()) {
+ std::map<GURL, int> whitelist_map =
+ extensions_service->protected_storage_map();
+ for (std::map<GURL, int>::const_iterator iter = whitelist_map.begin();
+ iter != whitelist_map.end(); ++iter) {
+ origin_whitelist.push_back(iter->first);
+ }
+ }
+
+ std::vector<string16> webkit_db_whitelist;
+ for (size_t i = 0; i < origin_whitelist.size(); ++i) {
+ webkit_db_whitelist.push_back(
+ webkit_database::DatabaseUtil::GetOriginIdentifier(
+ origin_whitelist[i]));
+ }
+
+
if (remove_mask & REMOVE_HISTORY) {
HistoryService* history_service =
profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
@@ -153,7 +174,7 @@ void BrowsingDataRemover::Remove(int remove_mask) {
// REMOVE_COOKIES is actually "cookies and other site data" so we make sure
// to remove other data such local databases, STS state, etc.
profile_->GetWebKitContext()->DeleteDataModifiedSince(
- delete_begin_, chrome::kExtensionScheme);
+ delete_begin_, chrome::kExtensionScheme, webkit_db_whitelist);
database_tracker_ = profile_->GetDatabaseTracker();
if (database_tracker_.get()) {
@@ -163,7 +184,8 @@ void BrowsingDataRemover::Remove(int remove_mask) {
NewRunnableMethod(
this,
&BrowsingDataRemover::ClearDatabasesOnFILEThread,
- delete_begin_));
+ delete_begin_,
+ webkit_db_whitelist));
}
ChromeThread::PostTask(
@@ -179,7 +201,8 @@ void BrowsingDataRemover::Remove(int remove_mask) {
NewRunnableMethod(
this,
&BrowsingDataRemover::ClearAppCacheOnIOThread,
- delete_begin_)); // we assume end time == now
+ delete_begin_, // we assume end time == now
+ origin_whitelist));
}
if (remove_mask & REMOVE_PASSWORDS) {
@@ -188,7 +211,8 @@ void BrowsingDataRemover::Remove(int remove_mask) {
PasswordStore* password_store =
profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS);
- password_store->RemoveLoginsCreatedBetween(delete_begin_, delete_end_);
+ if (password_store)
+ password_store->RemoveLoginsCreatedBetween(delete_begin_, delete_end_);
}
if (remove_mask & REMOVE_FORM_DATA) {
@@ -197,8 +221,10 @@ void BrowsingDataRemover::Remove(int remove_mask) {
WebDataService* web_data_service =
profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
- web_data_service->RemoveFormElementsAddedBetween(delete_begin_,
- delete_end_);
+ if (web_data_service) {
+ web_data_service->RemoveFormElementsAddedBetween(delete_begin_,
+ delete_end_);
+ }
}
if (remove_mask & REMOVE_CACHE) {
@@ -378,12 +404,13 @@ void BrowsingDataRemover::OnClearedDatabases(int rv) {
NotifyAndDeleteIfDone();
}
-void BrowsingDataRemover::ClearDatabasesOnFILEThread(base::Time delete_begin) {
+void BrowsingDataRemover::ClearDatabasesOnFILEThread(base::Time delete_begin,
+ const std::vector<string16>& webkit_db_whitelist) {
// This function should be called on the FILE thread.
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
int rv = database_tracker_->DeleteDataModifiedSince(
- delete_begin, &database_cleared_callback_);
+ delete_begin, webkit_db_whitelist, &database_cleared_callback_);
if (rv != net::ERR_IO_PENDING)
OnClearedDatabases(rv);
}
@@ -396,14 +423,17 @@ void BrowsingDataRemover::OnClearedAppCache() {
DCHECK(result);
return;
}
+ appcache_whitelist_.clear();
waiting_for_clear_appcache_ = false;
NotifyAndDeleteIfDone();
}
-void BrowsingDataRemover::ClearAppCacheOnIOThread(base::Time delete_begin) {
+void BrowsingDataRemover::ClearAppCacheOnIOThread(base::Time delete_begin,
+ const std::vector<GURL>& origin_whitelist) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
DCHECK(waiting_for_clear_appcache_);
+ appcache_whitelist_ = origin_whitelist;
appcache_info_ = new appcache::AppCacheInfoCollection;
GetAppCacheService()->GetAllAppCacheInfo(
appcache_info_, &appcache_got_info_callback_);
@@ -417,6 +447,15 @@ 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)
+ found_in_whitelist = true;
+ }
+ if (found_in_whitelist)
+ continue;
+
for (AppCacheInfoVector::const_iterator info = origin->second.begin();
info != origin->second.end(); ++info) {
if (info->creation_time > delete_begin_) {
diff --git a/chrome/browser/browsing_data_remover.h b/chrome/browser/browsing_data_remover.h
index 5034e88..a160198 100644
--- a/chrome/browser/browsing_data_remover.h
+++ b/chrome/browser/browsing_data_remover.h
@@ -4,9 +4,12 @@
#ifndef CHROME_BROWSER_BROWSING_DATA_REMOVER_H_
#define CHROME_BROWSER_BROWSING_DATA_REMOVER_H_
+#pragma once
+
+#include <vector>
#include "base/observer_list.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
#include "base/time.h"
#include "chrome/browser/appcache/chrome_appcache_service.h"
#include "chrome/browser/cancelable_request.h"
@@ -115,15 +118,19 @@ class BrowsingDataRemover : public NotificationObserver {
// NotifyAndDeleteIfDone.
void OnClearedDatabases(int rv);
- // Invoked on the FILE thread to delete HTML5 databases.
- void ClearDatabasesOnFILEThread(base::Time delete_begin);
+ // Invoked on the FILE thread to delete HTML5 databases. Ignores any within
+ // the |webkit_db_whitelist|.
+ void ClearDatabasesOnFILEThread(base::Time delete_begin,
+ const std::vector<string16>& webkit_db_whitelist);
// Callback when the appcache has been cleared. Invokes
// NotifyAndDeleteIfDone.
void OnClearedAppCache();
- // Invoked on the IO thread to delete from the AppCache.
- void ClearAppCacheOnIOThread(base::Time delete_begin);
+ // Invoked on the IO thread to delete from the AppCache, ignoring data from
+ // any origins within the |origin_whitelist|.
+ void ClearAppCacheOnIOThread(base::Time delete_begin,
+ const std::vector<GURL>& origin_whitelist);
// Lower level helpers.
void OnGotAppCacheInfo(int rv);
@@ -165,6 +172,7 @@ class BrowsingDataRemover : public NotificationObserver {
net::CompletionCallbackImpl<BrowsingDataRemover> appcache_deleted_callback_;
scoped_refptr<appcache::AppCacheInfoCollection> appcache_info_;
scoped_refptr<URLRequestContextGetter> request_context_getter_;
+ std::vector<GURL> appcache_whitelist_;
int appcaches_to_be_deleted_count_;
// Used to delete data from the HTTP caches.
diff --git a/chrome/browser/browsing_instance.cc b/chrome/browser/browsing_instance.cc
index 41a3abc..ec433b7 100644
--- a/chrome/browser/browsing_instance.cc
+++ b/chrome/browser/browsing_instance.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/browsing_instance.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/common/chrome_switches.h"
@@ -14,6 +15,10 @@
BrowsingInstance::ProfileSiteInstanceMap
BrowsingInstance::profile_site_instance_map_;
+BrowsingInstance::BrowsingInstance(Profile* profile)
+ : profile_(profile) {
+}
+
bool BrowsingInstance::ShouldUseProcessPerSite(const GURL& url) {
// Returns true if we should use the process-per-site model. This will be
// the case if the --process-per-site switch is specified, or in
@@ -123,3 +128,9 @@ void BrowsingInstance::UnregisterSiteInstance(SiteInstance* site_instance) {
map->erase(i);
}
}
+
+BrowsingInstance::~BrowsingInstance() {
+ // We should only be deleted when all of the SiteInstances that refer to
+ // us are gone.
+ DCHECK(site_instance_map_.empty());
+}
diff --git a/chrome/browser/browsing_instance.h b/chrome/browser/browsing_instance.h
index e44f747..fa4ce49 100644
--- a/chrome/browser/browsing_instance.h
+++ b/chrome/browser/browsing_instance.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_BROWSING_INSTANCE_H_
#define CHROME_BROWSER_BROWSING_INSTANCE_H_
+#pragma once
#include "base/hash_tables.h"
-#include "base/logging.h"
#include "base/ref_counted.h"
#include "chrome/browser/profile.h"
@@ -55,9 +55,7 @@ class SiteInstance;
class BrowsingInstance : public base::RefCounted<BrowsingInstance> {
public:
// Create a new BrowsingInstance.
- explicit BrowsingInstance(Profile* profile)
- : profile_(profile) {
- }
+ explicit BrowsingInstance(Profile* profile);
// Returns whether the process-per-site model is in use (globally or just for
// the given url), in which case we should ensure there is only one
@@ -91,11 +89,7 @@ class BrowsingInstance : public base::RefCounted<BrowsingInstance> {
friend class base::RefCounted<BrowsingInstance>;
// Virtual to allow tests to extend it.
- virtual ~BrowsingInstance() {
- // We should only be deleted when all of the SiteInstances that refer to
- // us are gone.
- DCHECK(site_instance_map_.empty());
- }
+ virtual ~BrowsingInstance();
private:
// Map of site to SiteInstance, to ensure we only have one SiteInstance per
diff --git a/chrome/browser/bug_report_util.cc b/chrome/browser/bug_report_util.cc
index 3f51fe7..6571d95 100644
--- a/chrome/browser/bug_report_util.cc
+++ b/chrome/browser/bug_report_util.cc
@@ -4,21 +4,34 @@
#include "chrome/browser/bug_report_util.h"
+#include <sstream>
+#include <string>
+
#include "app/l10n_util.h"
+#include "base/command_line.h"
#include "base/file_version_info.h"
+#include "base/file_util.h"
+#include "base/singleton.h"
+#include "base/string_util.h"
#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/safe_browsing/safe_browsing_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/url_fetcher.h"
#include "googleurl/src/gurl.h"
+#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
#include "net/url_request/url_request_status.h"
#include "unicode/locid.h"
-#include <string>
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/notifications/system_notification.h"
+#endif
namespace {
@@ -28,27 +41,60 @@ const char kReportPhishingUrl[] =
"http://www.google.com/safebrowsing/report_phish/";
// URL to post bug reports to.
-const char* const kBugReportPostUrl =
+static char const kBugReportPostUrl[] =
"https://www.google.com/tools/feedback/chrome/__submit";
-const char* const kProtBufMimeType = "application/x-protobuf";
-const char* const kPngMimeType = "image/png";
+static char const kProtBufMimeType[] = "application/x-protobuf";
+static char const kPngMimeType[] = "image/png";
// Tags we use in product specific data
-const char* const kPageTitleTag = "PAGE TITLE";
-const char* const kProblemTypeIdTag = "PROBLEM TYPE ID";
-const char* const kProblemTypeTag = "PROBLEM TYPE";
-const char* const kChromeVersionTag = "CHROME VERSION";
-const char* const kOsVersionTag = "OS VERSION";
+static char const kPageTitleTag[] = "PAGE TITLE";
+static char const kProblemTypeIdTag[] = "PROBLEM TYPE ID";
+static char const kProblemTypeTag[] = "PROBLEM TYPE";
+static char const kChromeVersionTag[] = "CHROME VERSION";
+static char const kOsVersionTag[] = "OS VERSION";
+
+static char const kNotificationId[] = "feedback.chromeos";
+
+static int const kHttpPostSuccessNoContent = 204;
+static int const kHttpPostFailNoConnection = -1;
+static int const kHttpPostFailClientError = 400;
+static int const kHttpPostFailServerError = 500;
+
+} // namespace
-} // namespace
+#if defined(OS_CHROMEOS)
+class FeedbackNotification {
+ public:
+ // Previous notification cleanup is handled by scoped_ptr.
+ // Note: notification will show only on one profile at a time.
+ void Show(Profile* profile, const string16& message, bool urgent) {
+ notification_.reset(
+ new chromeos::SystemNotification(profile, kNotificationId,
+ IDR_STATUSBAR_FEEDBACK,
+ l10n_util::GetStringUTF16(
+ IDS_BUGREPORT_NOTIFICATION_TITLE)));
+ notification_->Show(message, urgent, false);
+ }
+
+ private:
+ FeedbackNotification() {}
+ friend struct DefaultSingletonTraits<FeedbackNotification>;
+
+ scoped_ptr<chromeos::SystemNotification> notification_;
+ DISALLOW_COPY_AND_ASSIGN(FeedbackNotification);
+};
+#endif
// Simple URLFetcher::Delegate to clean up URLFetcher on completion.
class BugReportUtil::PostCleanup : public URLFetcher::Delegate {
public:
+#if defined(OS_CHROMEOS)
+ explicit PostCleanup(Profile* profile);
+#else
PostCleanup();
-
+#endif
// Overridden from URLFetcher::Delegate.
virtual void OnURLFetchComplete(const URLFetcher* source,
const GURL& url,
@@ -56,11 +102,22 @@ class BugReportUtil::PostCleanup : public URLFetcher::Delegate {
int response_code,
const ResponseCookies& cookies,
const std::string& data);
+
+ protected:
+ virtual ~PostCleanup() {}
+
private:
+ Profile* profile_;
+
DISALLOW_COPY_AND_ASSIGN(PostCleanup);
};
-BugReportUtil::PostCleanup::PostCleanup() {
+#if defined(OS_CHROMEOS)
+ BugReportUtil::PostCleanup::PostCleanup(Profile* profile)
+ : profile_(profile) {
+#else
+ BugReportUtil::PostCleanup::PostCleanup() {
+#endif
}
void BugReportUtil::PostCleanup::OnURLFetchComplete(
@@ -70,10 +127,38 @@ void BugReportUtil::PostCleanup::OnURLFetchComplete(
int response_code,
const ResponseCookies& cookies,
const std::string& data) {
- // if not 204, something went wrong
- if (response_code != 204)
- LOG(WARNING) << "Submission to feedback server failed. Response code: " <<
- response_code << std::endl;
+
+ std::stringstream error_stream;
+ if (response_code == kHttpPostSuccessNoContent) {
+ error_stream << "Success";
+ } else if (response_code == kHttpPostFailNoConnection) {
+ error_stream << "No connection to server.";
+ } else if ((response_code > kHttpPostFailClientError) &&
+ (response_code < kHttpPostFailServerError)) {
+ error_stream << "Client error: HTTP response code " << response_code;
+ } else if (response_code > kHttpPostFailServerError) {
+ error_stream << "Server error: HTTP response code " << response_code;
+ } else {
+ error_stream << "Unknown error: HTTP response code " << response_code;
+ }
+
+ LOG(WARNING) << "Submission to feedback server (" << url <<
+ ") status: " << error_stream.str() << std::endl;
+
+#if defined(OS_CHROMEOS)
+ // Show the notification to the user; this notification will stay active till
+ // either the user closes it, or we display another notification.
+ if (response_code == kHttpPostSuccessNoContent) {
+ Singleton<FeedbackNotification>()->Show(profile_, l10n_util::GetStringUTF16(
+ IDS_BUGREPORT_FEEDBACK_STATUS_SUCCESS), false);
+ } else {
+ Singleton<FeedbackNotification>()->Show(profile_,
+ l10n_util::GetStringFUTF16(IDS_BUGREPORT_FEEDBACK_STATUS_FAIL,
+ ASCIIToUTF16(error_stream.str())),
+ true);
+ }
+#endif
+
// Delete the URLFetcher.
delete source;
// And then delete ourselves.
@@ -108,9 +193,20 @@ void BugReportUtil::SetOSVersion(std::string *os_version) {
}
// static
+std::string BugReportUtil::feedback_server_("");
+
+// static
+void BugReportUtil::SetFeedbackServer(const std::string& server) {
+ feedback_server_ = server;
+}
+
+
+// static
void BugReportUtil::AddFeedbackData(
userfeedback::ExternalExtensionSubmit* feedback_data,
const std::string& key, const std::string& value) {
+ // We have no reason to log any empty values - gives us no data
+ if (value == "") return;
// Create log_value object and add it to the web_data object
userfeedback::ProductSpecificData log_value;
log_value.set_key(key);
@@ -124,19 +220,25 @@ void BugReportUtil::SendReport(Profile* profile,
const std::string& page_title_text,
int problem_type,
const std::string& page_url_text,
- const std::string& user_email_text,
const std::string& description,
const char* png_data,
int png_data_length,
int png_width,
#if defined(OS_CHROMEOS)
int png_height,
- const std::string& problem_type_text,
+ const std::string& user_email_text,
const chromeos::LogDictionaryType* const sys_info) {
#else
int png_height) {
#endif
- GURL post_url(kBugReportPostUrl);
+ GURL post_url;
+
+ if (CommandLine::ForCurrentProcess()->
+ HasSwitch(switches::kFeedbackServer))
+ post_url = GURL(CommandLine::ForCurrentProcess()->
+ GetSwitchValueASCII(switches::kFeedbackServer));
+ else
+ post_url = GURL(kBugReportPostUrl);
// Create google feedback protocol buffer objects
userfeedback::ExternalExtensionSubmit feedback_data;
@@ -156,39 +258,30 @@ void BugReportUtil::SendReport(Profile* profile,
AddFeedbackData(&feedback_data, std::string(kPageTitleTag),
page_title_text);
- AddFeedbackData(&feedback_data, std::string(kProblemTypeIdTag),
- StringPrintf("%d\r\n", problem_type));
-
#if defined(OS_CHROMEOS)
- AddFeedbackData(&feedback_data, std::string(kProblemTypeTag),
- problem_type_text);
-#endif
-
// Add the user e-mail to the feedback object
common_data->set_user_email(user_email_text);
+#endif
// Add the description to the feedback object
common_data->set_description(description);
// Add the language
std::string chrome_locale = g_browser_process->GetApplicationLocale();
- common_data->set_source_descripton_language(chrome_locale);
+ common_data->set_source_description_language(chrome_locale);
// Set the url
web_data->set_url(page_url_text);
// Add the Chrome version
- std::string chrome_version;
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- if (version_info.get()) {
- chrome_version = WideToUTF8(version_info->product_name()) + " - " +
- WideToUTF8(version_info->file_version()) +
- " (" + WideToUTF8(version_info->last_change()) + ")";
- }
-
- if (!chrome_version.empty())
+ chrome::VersionInfo version_info;
+ if (version_info.is_valid()) {
+ std::string chrome_version = version_info.Name() + " - " +
+ version_info.Version() +
+ " (" + version_info.LastChange() + ")";
AddFeedbackData(&feedback_data, std::string(kChromeVersionTag),
chrome_version);
+ }
// Add OS version (eg, for WinXP SP2: "5.1.2600 Service Pack 2").
std::string os_version = "";
@@ -218,9 +311,33 @@ void BugReportUtil::SendReport(Profile* profile,
*(feedback_data.mutable_screenshot()) = screenshot;
}
+ // Set our Chrome specific data
+ userfeedback::ChromeData chrome_data;
+#if defined(OS_CHROMEOS)
+ chrome_data.set_chrome_platform(
+ userfeedback::ChromeData_ChromePlatform_CHROME_OS);
+ userfeedback::ChromeOsData chrome_os_data;
+ chrome_os_data.set_category(
+ (userfeedback::ChromeOsData_ChromeOsCategory) problem_type);
+ *(chrome_data.mutable_chrome_os_data()) = chrome_os_data;
+#else
+ chrome_data.set_chrome_platform(
+ userfeedback::ChromeData_ChromePlatform_CHROME_BROWSER);
+ userfeedback::ChromeBrowserData chrome_browser_data;
+ chrome_browser_data.set_category(
+ (userfeedback::ChromeBrowserData_ChromeBrowserCategory) problem_type);
+ *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data;
+#endif
+
+ *(feedback_data.mutable_chrome_data()) = chrome_data;
+
// We have the body of our POST, so send it off to the server.
URLFetcher* fetcher = new URLFetcher(post_url, URLFetcher::POST,
- new BugReportUtil::PostCleanup);
+#if defined(OS_CHROMEOS)
+ new BugReportUtil::PostCleanup(profile));
+#else
+ new BugReportUtil::PostCleanup());
+#endif
fetcher->set_request_context(profile->GetRequestContext());
std::string post_body;
diff --git a/chrome/browser/bug_report_util.h b/chrome/browser/bug_report_util.h
index b7a6580..e11a22c 100644
--- a/chrome/browser/bug_report_util.h
+++ b/chrome/browser/bug_report_util.h
@@ -4,16 +4,15 @@
#ifndef CHROME_BROWSER_BUG_REPORT_UTIL_H_
#define CHROME_BROWSER_BUG_REPORT_UTIL_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/basictypes.h"
#if defined(OS_MACOSX)
#include "base/mac_util.h"
#include "base/sys_info.h"
#endif
-#include "base/scoped_ptr.h"
#include "chrome/browser/userfeedback/proto/common.pb.h"
#include "chrome/browser/userfeedback/proto/extension.pb.h"
#include "chrome/browser/userfeedback/proto/math.pb.h"
@@ -64,19 +63,21 @@ class BugReportUtil {
// all the call sites or making it a wrapper around another util.
static void SetOSVersion(std::string *os_version);
+ // This sets the address of the feedback server to be used by SendReport
+ static void SetFeedbackServer(const std::string& server);
+
// Generates bug report data.
static void SendReport(Profile* profile,
const std::string& page_title_text,
int problem_type,
const std::string& page_url_text,
- const std::string& user_email_text,
const std::string& description,
const char* png_data,
int png_data_length,
int png_width,
#if defined(OS_CHROMEOS)
int png_height,
- const std::string& problem_type_text,
+ const std::string& user_email_text,
const chromeos::LogDictionaryType* const sys_info);
#else
int png_height);
@@ -94,6 +95,8 @@ class BugReportUtil {
userfeedback::ExternalExtensionSubmit* feedback_data,
const std::string& key, const std::string& value);
+ static std::string feedback_server_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(BugReportUtil);
};
diff --git a/chrome/browser/cancelable_request.cc b/chrome/browser/cancelable_request.cc
index 85ab51a..4ed58f8 100644
--- a/chrome/browser/cancelable_request.cc
+++ b/chrome/browser/cancelable_request.cc
@@ -76,3 +76,31 @@ void CancelableRequestProvider::RequestCompleted(Handle handle) {
// Notify the consumer that the request is gone
consumer->OnRequestRemoved(this, handle);
}
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+// Emit our most common CancelableRequestConsumer.
+template class CancelableRequestConsumerTSimple<int>;
+
+// And the most common subclass of it.
+template class CancelableRequestConsumerT<int, 0>;
+#endif
+
+CancelableRequestBase::CancelableRequestBase()
+ : provider_(NULL),
+ consumer_(NULL),
+ handle_(0) {
+ callback_thread_ = MessageLoop::current();
+}
+
+CancelableRequestBase::~CancelableRequestBase() {
+}
+
+void CancelableRequestBase::Init(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle,
+ CancelableRequestConsumerBase* consumer) {
+ DCHECK(handle_ == 0 && provider_ == NULL && consumer_ == NULL);
+ provider_ = provider;
+ consumer_ = consumer;
+ handle_ = handle;
+}
diff --git a/chrome/browser/cancelable_request.h b/chrome/browser/cancelable_request.h
index 0e31f25..3ad7261 100644
--- a/chrome/browser/cancelable_request.h
+++ b/chrome/browser/cancelable_request.h
@@ -85,6 +85,7 @@
#ifndef CHROME_BROWSER_CANCELABLE_REQUEST_H__
#define CHROME_BROWSER_CANCELABLE_REQUEST_H__
+#pragma once
#include <map>
#include <vector>
@@ -98,6 +99,7 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
+#include "build/build_config.h"
class CancelableRequestBase;
class CancelableRequestConsumerBase;
@@ -175,6 +177,7 @@ class CancelableRequestProvider {
// Base class used to notify of new requests.
class CancelableRequestConsumerBase {
protected:
+ friend class CancelableRequestBase;
friend class CancelableRequestProvider;
virtual ~CancelableRequestConsumerBase() {
@@ -190,6 +193,14 @@ class CancelableRequestConsumerBase {
// given request, and by the provider when a request is canceled.
virtual void OnRequestRemoved(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) = 0;
+
+ // Sent to provider before executing a callback.
+ virtual void WillExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) = 0;
+
+ // Sent after executing a callback.
+ virtual void DidExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) = 0;
};
// Template for clients to use. It allows them to associate random "client
@@ -199,67 +210,48 @@ class CancelableRequestConsumerBase {
template<class T>
class CancelableRequestConsumerTSimple : public CancelableRequestConsumerBase {
public:
- CancelableRequestConsumerTSimple() {
- }
+ CancelableRequestConsumerTSimple();
// Cancel any outstanding requests so that we do not get called back after we
// are destroyed. As these requests are removed, the providers will call us
// back on OnRequestRemoved, which will then update the list. To iterate
// successfully while the list is changing out from under us, we make a copy.
- virtual ~CancelableRequestConsumerTSimple() {
- CancelAllRequests();
- }
+ virtual ~CancelableRequestConsumerTSimple();
// Associates some random data with a specified request. The request MUST be
// outstanding, or it will assert. This is intended to be called immediately
// after a request is issued.
void SetClientData(CancelableRequestProvider* p,
CancelableRequestProvider::Handle h,
- T client_data) {
- PendingRequest request(p, h);
- DCHECK(pending_requests_.find(request) != pending_requests_.end());
- pending_requests_[request] = client_data;
- }
+ T client_data);
// Retrieves previously associated data for a specified request. The request
// MUST be outstanding, or it will assert. This is intended to be called
// during processing of a callback to retrieve extra data.
T GetClientData(CancelableRequestProvider* p,
- CancelableRequestProvider::Handle h) {
- PendingRequest request(p, h);
- DCHECK(pending_requests_.find(request) != pending_requests_.end());
- return pending_requests_[request];
- }
+ CancelableRequestProvider::Handle h);
+
+ // Returns the data associated with the current request being processed. This
+ // is only valid during the time a callback is being processed.
+ T GetClientDataForCurrentRequest();
// Returns true if there are any pending requests.
- bool HasPendingRequests() const {
- return !pending_requests_.empty();
- }
+ bool HasPendingRequests() const;
// Returns the number of pending requests.
- size_t PendingRequestCount() const {
- return pending_requests_.size();
- }
+ size_t PendingRequestCount() const;
// Cancels all requests outstanding.
- void CancelAllRequests() {
- PendingRequestList copied_requests(pending_requests_);
- for (typename PendingRequestList::iterator i = copied_requests.begin();
- i != copied_requests.end(); ++i)
- i->first.provider->CancelRequest(i->first.handle);
- copied_requests.clear();
-
- // That should have cleared all the pending items.
- DCHECK(pending_requests_.empty());
- }
+ void CancelAllRequests();
+
+ // Returns the handle for the first request that has the specified client data
+ // (in |handle|). Returns true if there is a request for the specified client
+ // data, false otherwise.
+ bool GetFirstHandleForClientData(T client_data,
+ CancelableRequestProvider::Handle* handle);
// Gets the client data for all pending requests.
- void GetAllClientData(std::vector<T>* data) {
- DCHECK(data);
- for (typename PendingRequestList::iterator i = pending_requests_.begin();
- i != pending_requests_.end(); ++i)
- data->push_back(i->second);
- }
+ void GetAllClientData(std::vector<T>* data);
protected:
struct PendingRequest {
@@ -268,6 +260,8 @@ class CancelableRequestConsumerTSimple : public CancelableRequestConsumerBase {
: provider(p), handle(h) {
}
+ PendingRequest() : provider(NULL), handle(0) {}
+
// Comparison operator for stl.
bool operator<(const PendingRequest& other) const {
if (provider != other.provider)
@@ -275,53 +269,198 @@ class CancelableRequestConsumerTSimple : public CancelableRequestConsumerBase {
return handle < other.handle;
}
+ bool is_valid() const { return provider != NULL; }
+
CancelableRequestProvider* provider;
CancelableRequestProvider::Handle handle;
};
typedef std::map<PendingRequest, T> PendingRequestList;
- virtual T get_initial_t() const {
- return 0;
- }
+ virtual T get_initial_t() const;
virtual void OnRequestAdded(CancelableRequestProvider* provider,
- CancelableRequestProvider::Handle handle) {
- DCHECK(pending_requests_.find(PendingRequest(provider, handle)) ==
- pending_requests_.end());
- pending_requests_[PendingRequest(provider, handle)] = get_initial_t();
- }
+ CancelableRequestProvider::Handle handle);
virtual void OnRequestRemoved(CancelableRequestProvider* provider,
- CancelableRequestProvider::Handle handle) {
- typename PendingRequestList::iterator i =
- pending_requests_.find(PendingRequest(provider, handle));
- if (i == pending_requests_.end()) {
- NOTREACHED() << "Got a complete notification for a nonexistant request";
- return;
- }
+ CancelableRequestProvider::Handle handle);
- pending_requests_.erase(i);
- }
+ virtual void WillExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle);
+
+ virtual void DidExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle);
// Lists all outstanding requests.
PendingRequestList pending_requests_;
+
+ // This is valid while processing a request and is used to identify the
+ // provider/handle of request.
+ PendingRequest current_request_;
};
+template<class T>
+CancelableRequestConsumerTSimple<T>::CancelableRequestConsumerTSimple() {
+}
+
+template<class T>
+CancelableRequestConsumerTSimple<T>::~CancelableRequestConsumerTSimple() {
+ CancelAllRequests();
+}
+
+template<class T>
+void CancelableRequestConsumerTSimple<T>::SetClientData(
+ CancelableRequestProvider* p,
+ CancelableRequestProvider::Handle h,
+ T client_data) {
+ PendingRequest request(p, h);
+ DCHECK(pending_requests_.find(request) != pending_requests_.end());
+ pending_requests_[request] = client_data;
+}
+
+template<class T>
+T CancelableRequestConsumerTSimple<T>::GetClientData(
+ CancelableRequestProvider* p,
+ CancelableRequestProvider::Handle h) {
+ PendingRequest request(p, h);
+ DCHECK(pending_requests_.find(request) != pending_requests_.end());
+ return pending_requests_[request];
+}
+
+template<class T>
+T CancelableRequestConsumerTSimple<T>::GetClientDataForCurrentRequest() {
+ DCHECK(current_request_.is_valid());
+ return GetClientData(current_request_.provider, current_request_.handle);
+}
+
+template<class T>
+bool CancelableRequestConsumerTSimple<T>::HasPendingRequests() const {
+ return !pending_requests_.empty();
+}
+
+template<class T>
+size_t CancelableRequestConsumerTSimple<T>::PendingRequestCount() const {
+ return pending_requests_.size();
+}
+
+template<class T>
+void CancelableRequestConsumerTSimple<T>::CancelAllRequests() {
+ PendingRequestList copied_requests(pending_requests_);
+ for (typename PendingRequestList::iterator i = copied_requests.begin();
+ i != copied_requests.end(); ++i)
+ i->first.provider->CancelRequest(i->first.handle);
+ copied_requests.clear();
+
+ // That should have cleared all the pending items.
+ DCHECK(pending_requests_.empty());
+}
+
+template<class T>
+bool CancelableRequestConsumerTSimple<T>::GetFirstHandleForClientData(
+ T client_data,
+ CancelableRequestProvider::Handle* handle) {
+ for (typename PendingRequestList::const_iterator i =
+ pending_requests_.begin(); i != pending_requests_.end(); ++i) {
+ if (i->second == client_data) {
+ *handle = i->first.handle;
+ return true;
+ }
+ }
+ *handle = 0;
+ return false;
+}
+
+template<class T>
+void CancelableRequestConsumerTSimple<T>::GetAllClientData(
+ std::vector<T>* data) {
+ DCHECK(data);
+ for (typename PendingRequestList::iterator i = pending_requests_.begin();
+ i != pending_requests_.end(); ++i)
+ data->push_back(i->second);
+}
+
+template<class T>
+T CancelableRequestConsumerTSimple<T>::get_initial_t() const {
+ return 0;
+}
+
+template<class T>
+void CancelableRequestConsumerTSimple<T>::OnRequestAdded(
+ CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {
+ DCHECK(pending_requests_.find(PendingRequest(provider, handle)) ==
+ pending_requests_.end());
+ pending_requests_[PendingRequest(provider, handle)] = get_initial_t();
+}
+
+template<class T>
+void CancelableRequestConsumerTSimple<T>::OnRequestRemoved(
+ CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {
+ typename PendingRequestList::iterator i =
+ pending_requests_.find(PendingRequest(provider, handle));
+ if (i == pending_requests_.end()) {
+ NOTREACHED() << "Got a complete notification for a nonexistent request";
+ return;
+ }
+
+ pending_requests_.erase(i);
+}
+
+template<class T>
+void CancelableRequestConsumerTSimple<T>::WillExecute(
+ CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {
+ current_request_ = PendingRequest(provider, handle);
+}
+
+template<class T>
+void CancelableRequestConsumerTSimple<T>::DidExecute(
+ CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {
+ current_request_ = PendingRequest();
+}
+
// See CancelableRequestConsumerTSimple. The default value for T
// is given in |initial_t|.
template<class T, T initial_t>
class CancelableRequestConsumerT : public CancelableRequestConsumerTSimple<T> {
+ public:
+ CancelableRequestConsumerT();
+ virtual ~CancelableRequestConsumerT();
+
protected:
- virtual T get_initial_t() const {
- return initial_t;
- }
+ virtual T get_initial_t() const;
};
+template<class T, T initial_t>
+CancelableRequestConsumerT<T, initial_t>::CancelableRequestConsumerT() {
+}
+
+template<class T, T initial_t>
+CancelableRequestConsumerT<T, initial_t>::~CancelableRequestConsumerT() {
+}
+
+template<class T, T initial_t>
+T CancelableRequestConsumerT<T, initial_t>::get_initial_t() const {
+ return initial_t;
+}
+
// Some clients may not want to store data. Rather than do some complicated
// thing with virtual functions to allow some consumers to store extra data and
// some not to, we just define a default one that stores some dummy data.
typedef CancelableRequestConsumerT<int, 0> CancelableRequestConsumer;
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+// The vast majority of CancelableRequestConsumers are instantiated on <int>,
+// so prevent that template from being expanded in normal code.
+extern template class CancelableRequestConsumerTSimple<int>;
+
+// We'll also want to extern-template the most common, typedef-ed
+// CancelableRequestConsumerT.
+extern template class CancelableRequestConsumerT<int, 0>;
+#endif
+
// CancelableRequest ----------------------------------------------------------
//
// The request object that is used by a CancelableRequestProvider to send
@@ -369,12 +508,7 @@ class CancelableRequestBase
//
// In addition, not all of the information (for example, the handle) is known
// at construction time.
- CancelableRequestBase()
- : provider_(NULL),
- consumer_(NULL),
- handle_(0) {
- callback_thread_ = MessageLoop::current();
- }
+ CancelableRequestBase();
CancelableRequestConsumerBase* consumer() const {
return consumer_;
@@ -396,23 +530,24 @@ class CancelableRequestBase
protected:
friend class base::RefCountedThreadSafe<CancelableRequestBase>;
- virtual ~CancelableRequestBase() {}
+ virtual ~CancelableRequestBase();
// Initializes the object with the particulars from the provider. It may only
// be called once (it is called by the provider, which is a friend).
void Init(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle,
- CancelableRequestConsumerBase* consumer) {
- DCHECK(handle_ == 0 && provider_ == NULL && consumer_ == NULL);
- provider_ = provider;
- consumer_ = consumer;
- handle_ = handle;
- }
+ CancelableRequestConsumerBase* consumer);
// Tells the provider that the request is complete, which then tells the
// consumer.
void NotifyCompleted() const {
provider_->RequestCompleted(handle());
+ consumer_->DidExecute(provider_, handle_);
+ }
+
+ // Cover method for CancelableRequestConsumerBase::WillExecute.
+ void WillExecute() {
+ consumer_->WillExecute(provider_, handle_);
}
// The message loop that this request was created on. The callback will
@@ -520,6 +655,8 @@ class CancelableRequest : public CancelableRequestBase {
// request has been completed. This must be called on the callback_thread_.
void ExecuteCallback(const TupleType& param) {
if (!canceled_.IsSet()) {
+ WillExecute();
+
// Execute the callback.
callback_->RunWithParams(param);
diff --git a/chrome/browser/cert_store.h b/chrome/browser/cert_store.h
index 0b19540..fc17501 100644
--- a/chrome/browser/cert_store.h
+++ b/chrome/browser/cert_store.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_CERT_STORE_H_
#define CHROME_BROWSER_CERT_STORE_H_
+#pragma once
#include <map>
#include "base/lock.h"
#include "base/singleton.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "net/base/x509_certificate.h"
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
new file mode 100644
index 0000000..170bc7a
--- /dev/null
+++ b/chrome/browser/certificate_manager_model.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/certificate_manager_model.h"
+
+#include <cert.h>
+
+#include "base/i18n/time_formatting.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
+#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
+#include "net/base/x509_certificate.h"
+
+// TODO(mattm): Try to make this use only X509Certificate stuff rather than NSS
+// functions in some places. (Not very important at this time since this is only
+// used w/NSS anyway.)
+
+// PSM = Mozilla's Personal Security Manager.
+namespace psm = mozilla_security_manager;
+
+namespace {
+
+// Convert a char* return value from NSS into a std::string and free the NSS
+// memory. If the arg is NULL, an empty string will be returned instead.
+std::string Stringize(char* nss_text) {
+ std::string s;
+ if (nss_text) {
+ s = nss_text;
+ PORT_Free(nss_text);
+ }
+ return s;
+}
+
+std::string GetCertNameOrNickname(CERTCertificate* os_cert) {
+ std::string name = psm::ProcessIDN(
+ Stringize(CERT_GetCommonName(&os_cert->subject)));
+ if (name.empty() && os_cert->nickname) {
+ name = os_cert->nickname;
+ // Hack copied from mozilla: Cut off text before first :, which seems to
+ // just be the token name.
+ size_t colon_pos = name.find(':');
+ if (colon_pos != std::string::npos)
+ name = name.substr(colon_pos + 1);
+ }
+ return name;
+}
+
+} // namespace
+
+CertificateManagerModel::CertificateManagerModel() {
+}
+
+CertificateManagerModel::~CertificateManagerModel() {
+}
+
+void CertificateManagerModel::Refresh() {
+ cert_db_.ListCerts(&cert_list_);
+}
+
+void CertificateManagerModel::FilterAndBuildOrgGroupingMap(
+ net::CertType filter_type,
+ CertificateManagerModel::OrgGroupingMap* map) const {
+ for (net::CertificateList::const_iterator i = cert_list_.begin();
+ i != cert_list_.end(); ++i) {
+ net::X509Certificate* cert = i->get();
+ net::CertType type = psm::GetCertType(cert->os_cert_handle());
+ if (type != filter_type)
+ continue;
+
+ std::string org;
+ if (!cert->subject().organization_names.empty())
+ org = cert->subject().organization_names[0];
+ if (org.empty())
+ org = cert->subject().GetDisplayName();
+
+ (*map)[org].push_back(cert);
+ }
+}
+
+string16 CertificateManagerModel::GetColumnText(
+ const net::X509Certificate& cert,
+ Column column) const {
+ string16 rv;
+ switch (column) {
+ case COL_SUBJECT_NAME:
+ rv = UTF8ToUTF16(GetCertNameOrNickname(cert.os_cert_handle()));
+ break;
+ case COL_CERTIFICATE_STORE:
+ rv = UTF8ToUTF16(psm::GetCertTokenName(cert.os_cert_handle()));
+ break;
+ case COL_SERIAL_NUMBER:
+ rv = ASCIIToUTF16(Stringize(CERT_Hexify(
+ &cert.os_cert_handle()->serialNumber, PR_TRUE)));
+ break;
+ case COL_EXPIRES_ON:
+ if (!cert.valid_expiry().is_null()) {
+ rv = WideToUTF16Hack(
+ base::TimeFormatShortDateNumeric(cert.valid_expiry()));
+ }
+ break;
+ case COL_EMAIL_ADDRESS:
+ if (cert.os_cert_handle()->emailAddr)
+ rv = UTF8ToUTF16(cert.os_cert_handle()->emailAddr);
+ break;
+ default:
+ NOTREACHED();
+ }
+ return rv;
+}
diff --git a/chrome/browser/certificate_manager_model.h b/chrome/browser/certificate_manager_model.h
new file mode 100644
index 0000000..ce45d3a
--- /dev/null
+++ b/chrome/browser/certificate_manager_model.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_CERTIFICATE_MANAGER_MODEL_H_
+#define CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
+
+#include <map>
+#include <string>
+
+#include "base/ref_counted.h"
+#include "base/string16.h"
+#include "net/base/cert_database.h"
+
+// CertificateManagerModel provides the data to be displayed in the certificate
+// manager dialog, and processes changes from the view.
+class CertificateManagerModel {
+ public:
+ // Map from the subject organization name to the list of certs from that
+ // organization. If a cert does not have an organization name, the
+ // subject's CertPrincipal::GetDisplayName() value is used instead.
+ typedef std::map<std::string, net::CertificateList> OrgGroupingMap;
+
+ // Enumeration of the possible columns in the certificate manager tree view.
+ enum Column {
+ COL_SUBJECT_NAME,
+ COL_CERTIFICATE_STORE,
+ COL_SERIAL_NUMBER,
+ COL_EXPIRES_ON,
+ COL_EMAIL_ADDRESS,
+ };
+
+ CertificateManagerModel();
+ ~CertificateManagerModel();
+
+ // Refresh the list of certs. Following this call, the view should call
+ // FilterAndBuildOrgGroupingMap as necessary to refresh its tree views.
+ void Refresh();
+
+ // Fill |map| with the certificates matching |filter_type|.
+ void FilterAndBuildOrgGroupingMap(net::CertType filter_type,
+ OrgGroupingMap* map) const;
+
+ // Get the data to be displayed in |column| for the given |cert|.
+ string16 GetColumnText(const net::X509Certificate& cert, Column column) const;
+
+ private:
+ net::CertDatabase cert_db_;
+ net::CertificateList cert_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertificateManagerModel);
+};
+
+#endif // CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_
diff --git a/chrome/browser/certificate_viewer.h b/chrome/browser/certificate_viewer.h
index e0ba0c7..3d2d8c5 100644
--- a/chrome/browser/certificate_viewer.h
+++ b/chrome/browser/certificate_viewer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CERTIFICATE_VIEWER_H_
#define CHROME_BROWSER_CERTIFICATE_VIEWER_H_
+#pragma once
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/character_encoding.cc b/chrome/browser/character_encoding.cc
index 1e05017..8e24b02 100644
--- a/chrome/browser/character_encoding.cc
+++ b/chrome/browser/character_encoding.cc
@@ -13,6 +13,7 @@
#include "base/scoped_ptr.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "grit/generated_resources.h"
#include "unicode/ucnv.h"
diff --git a/chrome/browser/character_encoding.h b/chrome/browser/character_encoding.h
index 6f59381..ae1a6f1 100644
--- a/chrome/browser/character_encoding.h
+++ b/chrome/browser/character_encoding.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHARACTER_ENCODING_H_
#define CHROME_BROWSER_CHARACTER_ENCODING_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/child_process_launcher.cc b/chrome/browser/child_process_launcher.cc
index 60215d5..ad464c1 100644
--- a/chrome/browser/child_process_launcher.cc
+++ b/chrome/browser/child_process_launcher.cc
@@ -7,6 +7,7 @@
#include <utility> // For std::pair.
#include "base/command_line.h"
+#include "base/lock.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
@@ -17,6 +18,7 @@
#include "chrome/common/result_codes.h"
#if defined(OS_WIN)
+#include "base/file_path.h"
#include "chrome/common/sandbox_policy.h"
#elif defined(OS_LINUX)
#include "base/singleton.h"
@@ -160,20 +162,29 @@ class ChildProcessLauncher::Context
}
#endif // defined(OS_LINUX)
- // Actually launch the app.
- bool launched;
+ bool launched = false;
#if defined(OS_MACOSX)
- task_t child_task;
- launched = base::LaunchAppAndGetTask(
- cmd_line->argv(), env, fds_to_map, false, &child_task, &handle);
- if (launched && child_task != MACH_PORT_NULL) {
- MachBroker::instance()->RegisterPid(
- handle,
- MachBroker::MachInfo().SetTask(child_task));
- }
-#else
- launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map,
- /* wait= */false, &handle);
+ // It is possible for the child process to die immediately after
+ // launching. To prevent leaking MachBroker map entries in this case,
+ // lock around all of LaunchApp(). If the child dies, the death
+ // notification will be processed by the MachBroker after the call to
+ // AddPlaceholderForPid(), enabling proper cleanup.
+ { // begin scope for AutoLock
+ MachBroker* broker = MachBroker::instance();
+ AutoLock lock(broker->GetLock());
+
+ // This call to |PrepareForFork()| will start the MachBroker listener
+ // thread, if it is not already running. Therefore the browser process
+ // will be listening for Mach IPC before LaunchApp() is called.
+ broker->PrepareForFork();
+#endif
+ // Actually launch the app.
+ launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map,
+ /* wait= */false, &handle);
+#if defined(OS_MACOSX)
+ if (launched)
+ broker->AddPlaceholderForPid(handle);
+ } // end scope for AutoLock
#endif
if (!launched)
handle = base::kNullProcessHandle;
diff --git a/chrome/browser/child_process_launcher.h b/chrome/browser/child_process_launcher.h
index ce1c04d..95fb6ea 100644
--- a/chrome/browser/child_process_launcher.h
+++ b/chrome/browser/child_process_launcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHILD_PROCESS_LAUNCHER_H_
#define CHROME_BROWSER_CHILD_PROCESS_LAUNCHER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/process_util.h"
@@ -21,6 +22,9 @@ class ChildProcessLauncher {
// Will be called on the thread that the ChildProcessLauncher was
// constructed on.
virtual void OnProcessLaunched() = 0;
+
+ protected:
+ virtual ~Client() {}
};
// Launches the process asynchronously, calling the client when the result is
diff --git a/chrome/browser/child_process_security_policy.cc b/chrome/browser/child_process_security_policy.cc
index 723483d..5068e57 100644
--- a/chrome/browser/child_process_security_policy.cc
+++ b/chrome/browser/child_process_security_policy.cc
@@ -6,6 +6,7 @@
#include "base/file_path.h"
#include "base/logging.h"
+#include "base/platform_file.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/common/bindings_policy.h"
@@ -13,6 +14,12 @@
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request.h"
+const int kReadFilePermissions =
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_EXCLUSIVE_READ |
+ base::PLATFORM_FILE_ASYNC;
+
// The SecurityState class is used to maintain per-renderer security state
// information.
class ChildProcessSecurityPolicy::SecurityState {
@@ -34,9 +41,9 @@ class ChildProcessSecurityPolicy::SecurityState {
scheme_policy_[scheme] = false;
}
- // Grant permission to upload the specified file to the web.
- void GrantUploadFile(const FilePath& file) {
- uploadable_files_.insert(file);
+ // Grant certain permissions to a file.
+ void GrantPermissionsForFile(const FilePath& file, int permissions) {
+ file_permissions_[file.StripTrailingSeparators()] |= permissions;
}
void GrantBindings(int bindings) {
@@ -62,10 +69,18 @@ class ChildProcessSecurityPolicy::SecurityState {
return judgment->second;
}
- // Determine whether permission has been granted to upload file.
- // Files that have not been granted default to being denied.
- bool CanUploadFile(const FilePath& file) {
- return uploadable_files_.find(file) != uploadable_files_.end();
+ // Determine if the certain permissions have been granted to a file.
+ bool HasPermissionsForFile(const FilePath& file, int permissions) {
+ FilePath current_path = file.StripTrailingSeparators();
+ FilePath last_path;
+ while (current_path != last_path) {
+ if (file_permissions_.find(current_path) != file_permissions_.end())
+ return (file_permissions_[current_path] & permissions) == permissions;
+ last_path = current_path;
+ current_path = current_path.DirName();
+ }
+
+ return false;
}
bool has_dom_ui_bindings() const {
@@ -82,7 +97,7 @@ class ChildProcessSecurityPolicy::SecurityState {
private:
typedef std::map<std::string, bool> SchemeMap;
- typedef std::set<FilePath> FileSet;
+ typedef std::map<FilePath, int> FileMap; // bit-set of PlatformFileFlags
// Maps URL schemes to whether permission has been granted or revoked:
// |true| means the scheme has been granted.
@@ -92,7 +107,7 @@ class ChildProcessSecurityPolicy::SecurityState {
SchemeMap scheme_policy_;
// The set of files the renderer is permited to upload to the web.
- FileSet uploadable_files_;
+ FileMap file_permissions_;
int enabled_bindings_;
@@ -109,6 +124,7 @@ ChildProcessSecurityPolicy::ChildProcessSecurityPolicy() {
RegisterWebSafeScheme(chrome::kDataScheme);
RegisterWebSafeScheme("feed");
RegisterWebSafeScheme(chrome::kExtensionScheme);
+ RegisterWebSafeScheme(chrome::kBlobScheme);
// We know about the following psuedo schemes and treat them specially.
RegisterPseudoScheme(chrome::kAboutScheme);
@@ -214,15 +230,20 @@ void ChildProcessSecurityPolicy::GrantRequestURL(
}
}
-void ChildProcessSecurityPolicy::GrantUploadFile(int renderer_id,
- const FilePath& file) {
+void ChildProcessSecurityPolicy::GrantReadFile(int renderer_id,
+ const FilePath& file) {
+ GrantPermissionsForFile(renderer_id, file, kReadFilePermissions);
+}
+
+void ChildProcessSecurityPolicy::GrantPermissionsForFile(
+ int renderer_id, const FilePath& file, int permissions) {
AutoLock lock(lock_);
SecurityStateMap::iterator state = security_state_.find(renderer_id);
if (state == security_state_.end())
return;
- state->second->GrantUploadFile(file);
+ state->second->GrantPermissionsForFile(file, permissions);
}
void ChildProcessSecurityPolicy::GrantScheme(int renderer_id,
@@ -335,15 +356,20 @@ bool ChildProcessSecurityPolicy::CanRequestURL(
}
}
-bool ChildProcessSecurityPolicy::CanUploadFile(int renderer_id,
- const FilePath& file) {
+bool ChildProcessSecurityPolicy::CanReadFile(int renderer_id,
+ const FilePath& file) {
+ return HasPermissionsForFile(renderer_id, file, kReadFilePermissions);
+}
+
+bool ChildProcessSecurityPolicy::HasPermissionsForFile(
+ int renderer_id, const FilePath& file, int permissions) {
AutoLock lock(lock_);
SecurityStateMap::iterator state = security_state_.find(renderer_id);
if (state == security_state_.end())
return false;
- return state->second->CanUploadFile(file);
+ return state->second->HasPermissionsForFile(file, permissions);
}
bool ChildProcessSecurityPolicy::HasDOMUIBindings(int renderer_id) {
diff --git a/chrome/browser/child_process_security_policy.h b/chrome/browser/child_process_security_policy.h
index c6d162f..6ae4f30 100644
--- a/chrome/browser/child_process_security_policy.h
+++ b/chrome/browser/child_process_security_policy.h
@@ -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.
#ifndef CHROME_BROWSER_CHILD_PROCESS_SECURITY_POLICY_H_
#define CHROME_BROWSER_CHILD_PROCESS_SECURITY_POLICY_H_
-#include <string>
+#pragma once
+
#include <map>
#include <set>
+#include <string>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
@@ -67,7 +69,13 @@ class ChildProcessSecurityPolicy {
// 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 GrantUploadFile(int renderer_id, const FilePath& file);
+ void GrantReadFile(int renderer_id, const FilePath& file);
+
+ // Grants certain permissions to a file. |permissions| must be a bit-set of
+ // base::PlatformFileFlags.
+ void GrantPermissionsForFile(int renderer_id,
+ const FilePath& file,
+ int permissions);
// Grants the renderer process the capability to access URLs of the provided
// scheme.
@@ -98,7 +106,13 @@ class ChildProcessSecurityPolicy {
// 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
// capability to upload the requested file.
- bool CanUploadFile(int renderer_id, const FilePath& file);
+ bool CanReadFile(int renderer_id, const FilePath& file);
+
+ // Determins if certain permissions were granted for a file. |permissions|
+ // must be a bit-set of base::PlatformFileFlags.
+ bool HasPermissionsForFile(int renderer_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
@@ -115,7 +129,8 @@ class ChildProcessSecurityPolicy {
private:
friend class ChildProcessSecurityPolicyInProcessBrowserTest;
- FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyInProcessBrowserTest, NoLeak);
+ FRIEND_TEST_ALL_PREFIXES(ChildProcessSecurityPolicyInProcessBrowserTest,
+ NoLeak);
class SecurityState;
diff --git a/chrome/browser/child_process_security_policy_browsertest.cc b/chrome/browser/child_process_security_policy_browsertest.cc
index 41ec56a..336ba24 100644
--- a/chrome/browser/child_process_security_policy_browsertest.cc
+++ b/chrome/browser/child_process_security_policy_browsertest.cc
@@ -6,6 +6,7 @@
#include "base/basictypes.h"
#include "base/file_path.h"
+#include "base/process_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/child_process_security_policy.h"
diff --git a/chrome/browser/child_process_security_policy_unittest.cc b/chrome/browser/child_process_security_policy_unittest.cc
index 46279c7..949265d 100644
--- a/chrome/browser/child_process_security_policy_unittest.cc
+++ b/chrome/browser/child_process_security_policy_unittest.cc
@@ -6,6 +6,7 @@
#include "base/basictypes.h"
#include "base/file_path.h"
+#include "base/platform_file.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/common/url_constants.h"
#include "net/url_request/url_request.h"
@@ -185,30 +186,98 @@ TEST_F(ChildProcessSecurityPolicyTest, ViewSource) {
p->Remove(kRendererID);
}
-TEST_F(ChildProcessSecurityPolicyTest, CanUploadFiles) {
+TEST_F(ChildProcessSecurityPolicyTest, CanReadFiles) {
ChildProcessSecurityPolicy* p = ChildProcessSecurityPolicy::GetInstance();
p->Add(kRendererID);
- EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ EXPECT_FALSE(p->CanReadFile(kRendererID,
FilePath(FILE_PATH_LITERAL("/etc/passwd"))));
- p->GrantUploadFile(kRendererID, FilePath(FILE_PATH_LITERAL("/etc/passwd")));
- EXPECT_TRUE(p->CanUploadFile(kRendererID,
+ p->GrantReadFile(kRendererID, FilePath(FILE_PATH_LITERAL("/etc/passwd")));
+ EXPECT_TRUE(p->CanReadFile(kRendererID,
FilePath(FILE_PATH_LITERAL("/etc/passwd"))));
- EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ EXPECT_FALSE(p->CanReadFile(kRendererID,
FilePath(FILE_PATH_LITERAL("/etc/shadow"))));
p->Remove(kRendererID);
p->Add(kRendererID);
- EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ EXPECT_FALSE(p->CanReadFile(kRendererID,
FilePath(FILE_PATH_LITERAL("/etc/passwd"))));
- EXPECT_FALSE(p->CanUploadFile(kRendererID,
+ EXPECT_FALSE(p->CanReadFile(kRendererID,
FilePath(FILE_PATH_LITERAL("/etc/shadow"))));
p->Remove(kRendererID);
}
+TEST_F(ChildProcessSecurityPolicyTest, FilePermissions) {
+ ChildProcessSecurityPolicy* p = ChildProcessSecurityPolicy::GetInstance();
+
+ // Grant permissions for a file.
+ p->Add(kRendererID);
+ FilePath file = FilePath(FILE_PATH_LITERAL("/etc/passwd"));
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN));
+
+ p->GrantPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_TRUNCATE);
+ EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_TRUNCATE));
+ EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ));
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_CREATE));
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_CREATE |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_TRUNCATE));
+ p->Remove(kRendererID);
+
+ // Grant permissions for the directory the file is in.
+ p->Add(kRendererID);
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN));
+ p->GrantPermissionsForFile(kRendererID, FilePath(FILE_PATH_LITERAL("/etc")),
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ);
+ EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN));
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE));
+ p->Remove(kRendererID);
+
+ // Grant permissions for the directory the file is in (with trailing '/').
+ p->Add(kRendererID);
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN));
+ p->GrantPermissionsForFile(kRendererID, FilePath(FILE_PATH_LITERAL("/etc/")),
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ);
+ EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN));
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE));
+
+ // Grant permissions for the file (should overwrite the permissions granted
+ // for the directory).
+ p->GrantPermissionsForFile(kRendererID, file, base::PLATFORM_FILE_TEMPORARY);
+ EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_OPEN));
+ EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, file,
+ base::PLATFORM_FILE_TEMPORARY));
+ p->Remove(kRendererID);
+}
+
TEST_F(ChildProcessSecurityPolicyTest, CanServiceInspectElement) {
ChildProcessSecurityPolicy* p = ChildProcessSecurityPolicy::GetInstance();
@@ -248,11 +317,11 @@ TEST_F(ChildProcessSecurityPolicyTest, RemoveRace) {
p->Add(kRendererID);
p->GrantRequestURL(kRendererID, url);
- p->GrantUploadFile(kRendererID, file);
+ p->GrantReadFile(kRendererID, file);
p->GrantDOMUIBindings(kRendererID);
EXPECT_TRUE(p->CanRequestURL(kRendererID, url));
- EXPECT_TRUE(p->CanUploadFile(kRendererID, file));
+ EXPECT_TRUE(p->CanReadFile(kRendererID, file));
EXPECT_TRUE(p->HasDOMUIBindings(kRendererID));
p->Remove(kRendererID);
@@ -263,6 +332,6 @@ TEST_F(ChildProcessSecurityPolicyTest, RemoveRace) {
// In this case, we default to secure behavior.
EXPECT_FALSE(p->CanRequestURL(kRendererID, url));
- EXPECT_FALSE(p->CanUploadFile(kRendererID, file));
+ EXPECT_FALSE(p->CanReadFile(kRendererID, file));
EXPECT_FALSE(p->HasDOMUIBindings(kRendererID));
}
diff --git a/chrome/browser/chrome_blob_storage_context.cc b/chrome/browser/chrome_blob_storage_context.cc
new file mode 100644
index 0000000..c59ce0b
--- /dev/null
+++ b/chrome/browser/chrome_blob_storage_context.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/chrome_blob_storage_context.h"
+
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "webkit/blob/blob_storage_controller.h"
+
+using webkit_blob::BlobStorageController;
+
+ChromeBlobStorageContext::ChromeBlobStorageContext() {
+}
+
+void ChromeBlobStorageContext::InitializeOnIOThread() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ controller_.reset(new BlobStorageController());
+}
+
+ChromeBlobStorageContext::~ChromeBlobStorageContext() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+}
diff --git a/chrome/browser/chrome_blob_storage_context.h b/chrome/browser/chrome_blob_storage_context.h
new file mode 100644
index 0000000..f4e39a6
--- /dev/null
+++ b/chrome/browser/chrome_blob_storage_context.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_CHROME_BLOB_STORAGE_CONTEXT_H_
+#define CHROME_BROWSER_CHROME_BLOB_STORAGE_CONTEXT_H_
+#pragma once
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chrome_thread.h"
+
+class GURL;
+
+namespace webkit_blob {
+class BlobStorageController;
+}
+
+// A context class that keeps track of BlobStorageController used by the chrome.
+// There is an instance associated with each Profile. There could be multiple
+// URLRequestContexts in the same profile that refers to the same instance.
+//
+// All methods, except the ctor, are expected to be called on
+// the IO thread (unless specifically called out in doc comments).
+class ChromeBlobStorageContext
+ : public base::RefCountedThreadSafe<ChromeBlobStorageContext,
+ ChromeThread::DeleteOnIOThread> {
+ public:
+ ChromeBlobStorageContext();
+
+ void InitializeOnIOThread();
+
+ webkit_blob::BlobStorageController* controller() const {
+ return controller_.get();
+ }
+
+ private:
+ friend class ChromeThread;
+ friend class DeleteTask<ChromeBlobStorageContext>;
+
+ virtual ~ChromeBlobStorageContext();
+
+ scoped_ptr<webkit_blob::BlobStorageController> controller_;
+};
+
+#endif // CHROME_BROWSER_CHROME_BLOB_STORAGE_CONTEXT_H_
diff --git a/chrome/browser/chrome_browser_application_mac.h b/chrome/browser/chrome_browser_application_mac.h
index 67b4230..e599c63 100644
--- a/chrome/browser/chrome_browser_application_mac.h
+++ b/chrome/browser/chrome_browser_application_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROME_BROWSER_APPLICATION_MAC_H_
#define CHROME_BROWSER_CHROME_BROWSER_APPLICATION_MAC_H_
+#pragma once
#ifdef __OBJC__
diff --git a/chrome/browser/chrome_plugin_browsing_context.h b/chrome/browser/chrome_plugin_browsing_context.h
index 16499e8..ef31262 100644
--- a/chrome/browser/chrome_plugin_browsing_context.h
+++ b/chrome/browser/chrome_plugin_browsing_context.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_CHROME_PLUGIN_BROWSING_CONTEXT_H_
#define CHROME_BROWSER_CHROME_PLUGIN_BROWSING_CONTEXT_H_
+#pragma once
#include <map>
#include "base/id_map.h"
#include "chrome/common/chrome_plugin_api.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class URLRequestContext;
diff --git a/chrome/browser/chrome_plugin_host.cc b/chrome/browser/chrome_plugin_host.cc
index dc06c09..0789957 100644
--- a/chrome/browser/chrome_plugin_host.cc
+++ b/chrome/browser/chrome_plugin_host.cc
@@ -16,8 +16,8 @@
#include "base/perftimer.h"
#include "base/singleton.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chrome_plugin_browsing_context.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
@@ -305,7 +305,7 @@ class ModelessHtmlDialogDelegate : public HtmlDialogUIDelegate {
main_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
this, &ModelessHtmlDialogDelegate::Show));
}
- ~ModelessHtmlDialogDelegate() {
+ virtual ~ModelessHtmlDialogDelegate() {
DCHECK(ChromePluginLib::IsPluginThread());
}
@@ -472,8 +472,8 @@ int STDCALL CPB_GetBrowsingContextInfo(
PluginService* service = PluginService::GetInstance();
if (!service)
return CPERR_FAILURE;
- const std::wstring& wretval = service->GetUILocale();
- *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, WideToUTF8(wretval));
+ const std::string& retval = service->GetUILocale();
+ *static_cast<char**>(buf) = CPB_StringDup(CPB_Alloc, retval);
return CPERR_SUCCESS;
}
}
diff --git a/chrome/browser/chrome_plugin_host.h b/chrome/browser/chrome_plugin_host.h
index 2fd37a4..13a7736 100644
--- a/chrome/browser/chrome_plugin_host.h
+++ b/chrome/browser/chrome_plugin_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROME_PLUGIN_HOST_H__
#define CHROME_BROWSER_CHROME_PLUGIN_HOST_H__
+#pragma once
#include "chrome/common/chrome_plugin_api.h"
diff --git a/chrome/browser/chrome_plugin_unittest.cc b/chrome/browser/chrome_plugin_unittest.cc
index 3116a2f..3c5495c 100644
--- a/chrome/browser/chrome_plugin_unittest.cc
+++ b/chrome/browser/chrome_plugin_unittest.cc
@@ -17,11 +17,12 @@
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
const char kPluginFilename[] = "test_chrome_plugin.dll";
const int kResponseBufferSize = 4096;
@@ -278,11 +279,10 @@ TEST_F(ChromePluginTest, CanMakeGETRequestAsync) {
// Tests that the plugin can issue a POST request.
TEST_F(ChromePluginTest, CanMakePOSTRequest) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
- GURL url = server->TestServerPage("echo");
+ GURL url = test_server.GetURL("echo");
EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request("POST", url));
diff --git a/chrome/browser/chrome_thread.cc b/chrome/browser/chrome_thread.cc
index 984d188..dc3febd 100644
--- a/chrome/browser/chrome_thread.cc
+++ b/chrome/browser/chrome_thread.cc
@@ -119,6 +119,14 @@ bool ChromeThread::CurrentlyOn(ID identifier) {
}
// static
+bool ChromeThread::IsMessageLoopValid(ID identifier) {
+ AutoLock lock(lock_);
+ DCHECK(identifier >= 0 && identifier < ID_COUNT);
+ return chrome_threads_[identifier] &&
+ chrome_threads_[identifier]->message_loop();
+}
+
+// static
bool ChromeThread::PostTask(ID identifier,
const tracked_objects::Location& from_here,
Task* task) {
diff --git a/chrome/browser/chrome_thread.h b/chrome/browser/chrome_thread.h
index 5dbedfa..4bb9387 100644
--- a/chrome/browser/chrome_thread.h
+++ b/chrome/browser/chrome_thread.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROME_THREAD_H_
#define CHROME_BROWSER_CHROME_THREAD_H_
+#pragma once
#include "base/lock.h"
#include "base/task.h"
@@ -129,6 +130,11 @@ class ChromeThread : public base::Thread {
// thread.
static bool CurrentlyOn(ID identifier);
+ // Callable on any thread. Returns whether the threads message loop is valid.
+ // If this returns false it means the thread is in the process of shutting
+ // down.
+ static bool IsMessageLoopValid(ID identifier);
+
// If the current message loop is one of the known threads, returns true and
// sets identifier to its ID. Otherwise returns false.
static bool GetCurrentThreadIdentifier(ID* identifier);
@@ -164,7 +170,7 @@ class ChromeThread : public base::Thread {
//
// ...
// private:
- // friend class ChromeThread;
+ // friend struct ChromeThread::DeleteOnThread<ChromeThread::IO>;
// friend class DeleteTask<Foo>;
//
// ~Foo();
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index 29b7aa6..b12714a 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -1,4 +1,3 @@
include_rules = [
- "+third_party/cros",
"+cros",
]
diff --git a/chrome/browser/chromeos/PRESUBMIT.py b/chrome/browser/chromeos/PRESUBMIT.py
index 5762625..430c0f6 100755
--- a/chrome/browser/chromeos/PRESUBMIT.py
+++ b/chrome/browser/chromeos/PRESUBMIT.py
@@ -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,4 +9,4 @@ for more details on the presubmit API built into gcl.
"""
def GetPreferredTrySlaves():
- return ['linux_chromeos']
+ return ['linux_view', 'linux_chromeos']
diff --git a/chrome/browser/chromeos/audio_handler.cc b/chrome/browser/chromeos/audio_handler.cc
index f3157ee..f069b18 100644
--- a/chrome/browser/chromeos/audio_handler.cc
+++ b/chrome/browser/chromeos/audio_handler.cc
@@ -21,6 +21,8 @@ const double kMaxVolumeDb = 6.0;
// A value of less than one adjusts quieter volumes in larger steps (giving
// finer resolution in the higher volumes).
const double kVolumeBias = 0.5;
+// If a connection is lost, we try again this many times
+const int kMaxReconnectTries = 4;
} // namespace
@@ -28,11 +30,9 @@ const double kVolumeBias = 0.5;
// handles the volume level logic.
// TODO(davej): Serialize volume/mute for next startup?
-// TODO(davej): Should we try to regain a connection if for some reason all was
-// initialized fine, but later IsValid() returned false? Maybe N retries?
-double AudioHandler::GetVolumePercent() const {
- if (!SanityCheck())
+double AudioHandler::GetVolumePercent() {
+ if (!VerifyMixerConnection())
return 0;
return VolumeDbToPercent(mixer_->GetVolumeDb());
@@ -41,7 +41,7 @@ double AudioHandler::GetVolumePercent() const {
// Set volume using our internal 0-100% range. Notice 0% is a special case of
// silence, so we set the mixer volume to kSilenceDb instead of kMinVolumeDb.
void AudioHandler::SetVolumePercent(double volume_percent) {
- if (!SanityCheck())
+ if (!VerifyMixerConnection())
return;
DCHECK(volume_percent >= 0.0);
@@ -55,7 +55,7 @@ void AudioHandler::SetVolumePercent(double volume_percent) {
}
void AudioHandler::AdjustVolumeByPercent(double adjust_by_percent) {
- if (!SanityCheck())
+ if (!VerifyMixerConnection())
return;
DLOG(INFO) << "Adjusting Volume by " << adjust_by_percent << " percent";
@@ -79,15 +79,15 @@ void AudioHandler::AdjustVolumeByPercent(double adjust_by_percent) {
mixer_->SetVolumeDb(new_volume);
}
-bool AudioHandler::IsMute() const {
- if (!SanityCheck())
+bool AudioHandler::IsMute() {
+ if (!VerifyMixerConnection())
return false;
return mixer_->IsMute();
}
void AudioHandler::SetMute(bool do_mute) {
- if (!SanityCheck())
+ if (!VerifyMixerConnection())
return;
DLOG(INFO) << "Setting Mute to " << do_mute;
@@ -101,7 +101,8 @@ void AudioHandler::OnMixerInitialized(bool success) {
}
AudioHandler::AudioHandler()
- : connected_(false) {
+ : connected_(false),
+ reconnect_tries_(0) {
mixer_.reset(new PulseAudioMixer());
if (!mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized))) {
LOG(ERROR) << "Unable to connect to PulseAudio";
@@ -109,22 +110,39 @@ AudioHandler::AudioHandler()
}
AudioHandler::~AudioHandler() {
+ mixer_.reset();
};
-inline bool AudioHandler::SanityCheck() const {
- if (!mixer_->IsValid()) {
+bool AudioHandler::VerifyMixerConnection() {
+ PulseAudioMixer::State mixer_state = mixer_->CheckState();
+ if (mixer_state == PulseAudioMixer::READY)
+ return true;
+ if (connected_) {
+ // Something happened and the mixer is no longer valid after having been
+ // initialized earlier.
+ connected_ = false;
+ LOG(ERROR) << "Lost connection to PulseAudio";
+ } else {
+ LOG(ERROR) << "Mixer not valid";
+ }
+
+ if ((mixer_state == PulseAudioMixer::INITIALIZING) ||
+ (mixer_state == PulseAudioMixer::SHUTTING_DOWN))
+ return false;
+
+ if (reconnect_tries_ < kMaxReconnectTries) {
+ reconnect_tries_++;
+ LOG(INFO) << "Re-connecting to PulseAudio attempt " << reconnect_tries_
+ << "/" << kMaxReconnectTries;
+ mixer_.reset(new PulseAudioMixer());
+ connected_ = mixer_->InitSync();
if (connected_) {
- // Something happened and the mixer is no longer valid after having been
- // initialized earlier.
- // TODO(davej): Try to reconnect now?
- connected_ = false;
- LOG(ERROR) << "Lost connection to PulseAudio";
- } else {
- LOG(ERROR) << "Mixer not valid";
+ reconnect_tries_ = 0;
+ return true;
}
- return false;
+ LOG(ERROR) << "Unable to re-connect to PulseAudio";
}
- return true;
+ return false;
}
// VolumeDbToPercent() and PercentToVolumeDb() conversion functions allow us
diff --git a/chrome/browser/chromeos/audio_handler.h b/chrome/browser/chromeos/audio_handler.h
index 7e443a6..67addcb 100644
--- a/chrome/browser/chromeos/audio_handler.h
+++ b/chrome/browser/chromeos/audio_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_AUDIO_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_AUDIO_HANDLER_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "base/singleton.h"
@@ -22,7 +23,7 @@ class AudioHandler {
// Volume may go above 100% if another process changes PulseAudio's volume.
// Returns default of 0 on error. This function will block until the volume
// is retrieved or fails. Blocking call.
- double GetVolumePercent() const;
+ double GetVolumePercent();
// Set volume level from 0-100%. Volumes above 100% are OK and boost volume,
// although clipping will occur more at higher volumes. Volume gets quieter
@@ -36,7 +37,7 @@ class AudioHandler {
// Just returns true if mute, false if not or an error occurred.
// Blocking call.
- bool IsMute() const;
+ bool IsMute();
// Mutes all audio. Non-blocking call.
void SetMute(bool do_mute);
@@ -50,14 +51,15 @@ class AudioHandler {
AudioHandler();
virtual ~AudioHandler();
- inline bool SanityCheck() const;
+ bool VerifyMixerConnection();
// Conversion between our internal scaling (0-100%) and decibels.
static double VolumeDbToPercent(double volume_db);
static double PercentToVolumeDb(double volume_percent);
scoped_ptr<PulseAudioMixer> mixer_;
- mutable bool connected_; // Mutable for sanity checking only
+ bool connected_;
+ int reconnect_tries_;
DISALLOW_COPY_AND_ASSIGN(AudioHandler);
};
diff --git a/chrome/browser/chromeos/boot_times_loader.cc b/chrome/browser/chromeos/boot_times_loader.cc
index acdadce..c6b2628 100644
--- a/chrome/browser/chromeos/boot_times_loader.cc
+++ b/chrome/browser/chromeos/boot_times_loader.cc
@@ -13,7 +13,9 @@
#include "base/message_loop.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"
#include "base/thread.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
@@ -96,7 +98,7 @@ static bool GetTime(const std::string& log, double* value) {
size_t chars_left =
space_index != std::string::npos ? space_index : std::string::npos;
std::string value_string = contents.substr(0, chars_left);
- return StringToDouble(value_string, value);
+ return base::StringToDouble(value_string, value);
}
return false;
}
@@ -134,16 +136,16 @@ static void SendBootTimesToUMA(const BootTimesLoader::BootTimes& boot_times) {
// Stores the boot times to a file in /tmp to indicate that the
// times for the most recent boot event have been reported
// already. The file will be deleted at system shutdown/reboot.
- std::string boot_times_text = StringPrintf("total: %.2f\n"
- "firmware: %.2f\n"
- "kernel: %.2f\n"
- "system: %.2f\n"
- "chrome: %.2f\n",
- boot_times.total,
- boot_times.firmware,
- boot_times.pre_startup,
- boot_times.system,
- boot_times.chrome);
+ std::string boot_times_text = base::StringPrintf("total: %.2f\n"
+ "firmware: %.2f\n"
+ "kernel: %.2f\n"
+ "system: %.2f\n"
+ "chrome: %.2f\n",
+ boot_times.total,
+ boot_times.firmware,
+ boot_times.pre_startup,
+ boot_times.system,
+ boot_times.chrome);
file_util::WriteFile(sent, boot_times_text.data(), boot_times_text.size());
DCHECK(file_util::PathExists(sent));
}
@@ -219,7 +221,7 @@ static void WriteLoginTimes(
base::Time chrome_first_render) {
const FilePath log_path(kLogPath);
std::string output =
- StringPrintf("total: %.2f\nauth: %.2f\nlogin: %.2f\n",
+ base::StringPrintf("total: %.2f\nauth: %.2f\nlogin: %.2f\n",
(chrome_first_render - login_attempt).InSecondsF(),
(login_success - login_attempt).InSecondsF(),
(chrome_first_render - login_success).InSecondsF());
diff --git a/chrome/browser/chromeos/boot_times_loader.h b/chrome/browser/chromeos/boot_times_loader.h
index 143e425..95dd394 100644
--- a/chrome/browser/chromeos/boot_times_loader.h
+++ b/chrome/browser/chromeos/boot_times_loader.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_BOOT_TIMES_LOADER_H_
#define CHROME_BROWSER_CHROMEOS_BOOT_TIMES_LOADER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/cros/cros_api.gyp b/chrome/browser/chromeos/cros/cros_api.gyp
deleted file mode 100644
index e69de29..0000000
--- a/chrome/browser/chromeos/cros/cros_api.gyp
+++ /dev/null
diff --git a/chrome/browser/chromeos/cros/cros_in_process_browser_test.cc b/chrome/browser/chromeos/cros/cros_in_process_browser_test.cc
index 58055b5..ad88ae9 100644
--- a/chrome/browser/chromeos/cros/cros_in_process_browser_test.cc
+++ b/chrome/browser/chromeos/cros/cros_in_process_browser_test.cc
@@ -3,299 +3,19 @@
// found in the LICENSE file.
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
-
-#include "base/message_loop.h"
-#include "base/ref_counted.h"
-#include "base/time.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
-#include "chrome/browser/chromeos/cros/mock_keyboard_library.h"
-#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
-#include "chrome/browser/chromeos/cros/mock_library_loader.h"
-#include "chrome/browser/chromeos/cros/mock_network_library.h"
-#include "chrome/browser/chromeos/cros/mock_power_library.h"
-#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
-#include "chrome/browser/chromeos/cros/mock_synaptics_library.h"
-#include "chrome/browser/chromeos/cros/mock_system_library.h"
-#include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/login/wizard_screen.h"
#include "chrome/test/in_process_browser_test.h"
-#include "chrome/test/ui_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gmock/include/gmock/gmock.h"
namespace chromeos {
-using ::testing::AnyNumber;
-using ::testing::InvokeWithoutArgs;
-using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::StrictMock;
-using ::testing::_;
-
-CrosInProcessBrowserTest::CrosInProcessBrowserTest()
- : loader_(NULL),
- mock_cryptohome_library_(NULL),
- mock_keyboard_library_(NULL),
- mock_input_method_library_(NULL),
- mock_network_library_(NULL),
- mock_power_library_(NULL),
- mock_screen_lock_library_(NULL),
- mock_synaptics_library_(NULL),
- mock_system_library_(NULL) {}
-
-CrosInProcessBrowserTest::~CrosInProcessBrowserTest() {
-}
-
-chromeos::CrosLibrary::TestApi* CrosInProcessBrowserTest::test_api() {
- return chromeos::CrosLibrary::Get()->GetTestApi();
-}
-
-void CrosInProcessBrowserTest::InitStatusAreaMocks() {
- InitMockKeyboardLibrary();
- InitMockInputMethodLibrary();
- InitMockNetworkLibrary();
- InitMockPowerLibrary();
- InitMockSynapticsLibrary();
- InitMockSystemLibrary();
-}
-
-void CrosInProcessBrowserTest::InitMockLibraryLoader() {
- if (loader_)
- return;
- loader_ = new StrictMock<MockLibraryLoader>();
- EXPECT_CALL(*loader_, Load(_))
- .Times(AnyNumber())
- .WillRepeatedly(Return(true));
- test_api()->SetLibraryLoader(loader_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockCryptohomeLibrary() {
- InitMockLibraryLoader();
- if (mock_cryptohome_library_)
- return;
- mock_cryptohome_library_ = new StrictMock<MockCryptohomeLibrary>();
- test_api()->SetCryptohomeLibrary(mock_cryptohome_library_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockKeyboardLibrary() {
- InitMockLibraryLoader();
- if (mock_keyboard_library_)
- return;
- mock_keyboard_library_ = new StrictMock<MockKeyboardLibrary>();
- test_api()->SetKeyboardLibrary(mock_keyboard_library_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockInputMethodLibrary() {
- InitMockLibraryLoader();
- if (mock_input_method_library_)
- return;
- mock_input_method_library_ = new StrictMock<MockInputMethodLibrary>();
- test_api()->SetInputMethodLibrary(mock_input_method_library_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockNetworkLibrary() {
- InitMockLibraryLoader();
- if (mock_network_library_)
- return;
- mock_network_library_ = new StrictMock<MockNetworkLibrary>();
- test_api()->SetNetworkLibrary(mock_network_library_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockPowerLibrary() {
- InitMockLibraryLoader();
- if (mock_power_library_)
- return;
- mock_power_library_ = new StrictMock<MockPowerLibrary>();
- test_api()->SetPowerLibrary(mock_power_library_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockScreenLockLibrary() {
- InitMockLibraryLoader();
- if (mock_screen_lock_library_)
- return;
- mock_screen_lock_library_ = new StrictMock<MockScreenLockLibrary>();
- test_api()->SetScreenLockLibrary(mock_screen_lock_library_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockSynapticsLibrary() {
- InitMockLibraryLoader();
- if (mock_synaptics_library_)
- return;
- mock_synaptics_library_ = new StrictMock<MockSynapticsLibrary>();
- test_api()->SetSynapticsLibrary(mock_synaptics_library_, true);
-}
-
-void CrosInProcessBrowserTest::InitMockSystemLibrary() {
- InitMockLibraryLoader();
- if (mock_system_library_)
- return;
- mock_system_library_ = new StrictMock<MockSystemLibrary>();
- test_api()->SetSystemLibrary(mock_system_library_, true);
-}
-
-void CrosInProcessBrowserTest::SetStatusAreaMocksExpectations() {
- SetKeyboardLibraryStatusAreaExpectations();
- SetInputMethodLibraryStatusAreaExpectations();
- SetNetworkLibraryStatusAreaExpectations();
- SetPowerLibraryStatusAreaExpectations();
- SetSynapticsLibraryExpectations();
- SetSystemLibraryStatusAreaExpectations();
-}
-
-void CrosInProcessBrowserTest::SetKeyboardLibraryStatusAreaExpectations() {
- EXPECT_CALL(*mock_keyboard_library_, GetCurrentKeyboardLayoutName())
- .Times(AnyNumber())
- .WillRepeatedly((Return("us")))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_keyboard_library_, SetCurrentKeyboardLayoutByName(_))
- .Times(AnyNumber())
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_keyboard_library_, SetKeyboardLayoutPerWindow(_))
- .Times(AnyNumber())
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_keyboard_library_, GetKeyboardLayoutPerWindow(_))
- .Times(AnyNumber())
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
-}
-
-void CrosInProcessBrowserTest::SetInputMethodLibraryStatusAreaExpectations() {
- EXPECT_CALL(*mock_input_method_library_, AddObserver(_))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_input_method_library_, GetActiveInputMethods())
- .Times(AnyNumber())
- .WillRepeatedly(InvokeWithoutArgs(CreateFallbackInputMethodDescriptors))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_input_method_library_, GetSupportedInputMethods())
- .Times(AnyNumber())
- .WillRepeatedly(InvokeWithoutArgs(CreateFallbackInputMethodDescriptors))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_input_method_library_, current_ime_properties())
- .Times(1)
- .WillOnce((ReturnRef(ime_properties_)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_input_method_library_, SetImeConfig(_, _, _))
- .Times(AnyNumber())
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_input_method_library_, RemoveObserver(_))
- .Times(1)
- .RetiresOnSaturation();
-}
-
-void CrosInProcessBrowserTest::SetNetworkLibraryStatusAreaExpectations() {
- EXPECT_CALL(*mock_network_library_, AddObserver(_))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, wifi_connecting())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, wifi_connected())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, cellular_connecting())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, cellular_connected())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, ethernet_connected())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, Connected())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, Connecting())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, RemoveObserver(_))
- .Times(1)
- .RetiresOnSaturation();
-}
-void CrosInProcessBrowserTest::SetPowerLibraryStatusAreaExpectations() {
- EXPECT_CALL(*mock_power_library_, AddObserver(_))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_power_library_, battery_fully_charged())
- .Times(3)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_power_library_, battery_is_present())
- .Times(1)
- .WillOnce((Return(true)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_power_library_, battery_percentage())
- .Times(2)
- .WillRepeatedly((Return(42.0)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_power_library_, line_power_on())
- .Times(4)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_power_library_, battery_time_to_empty())
- .Times(1)
- .WillOnce((Return(base::TimeDelta::FromMinutes(42))))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_power_library_, RemoveObserver(_))
- .Times(1)
- .RetiresOnSaturation();
+CrosInProcessBrowserTest::CrosInProcessBrowserTest() {
+ cros_mock_.reset(new CrosMock());
}
-void CrosInProcessBrowserTest::SetSystemLibraryStatusAreaExpectations() {
- EXPECT_CALL(*mock_system_library_, AddObserver(_))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_system_library_, RemoveObserver(_))
- .Times(1)
- .RetiresOnSaturation();
-}
-
-void CrosInProcessBrowserTest::SetSynapticsLibraryExpectations() {
- EXPECT_CALL(*mock_synaptics_library_, SetBoolParameter(_, _))
- .Times(AnyNumber());
- EXPECT_CALL(*mock_synaptics_library_, SetRangeParameter(_, _))
- .Times(AnyNumber());
-}
-
-void CrosInProcessBrowserTest::SetSystemLibraryExpectations() {
- EXPECT_CALL(*mock_system_library_, GetTimezone())
- .Times(AnyNumber());
- EXPECT_CALL(*mock_system_library_, SetTimezone(_))
- .Times(AnyNumber());
+CrosInProcessBrowserTest::~CrosInProcessBrowserTest() {
}
void CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture() {
- // Prevent bogus gMock leak check from firing.
- if (loader_)
- test_api()->SetLibraryLoader(NULL, false);
- if (mock_cryptohome_library_)
- test_api()->SetCryptohomeLibrary(NULL, false);
- if (mock_keyboard_library_)
- test_api()->SetKeyboardLibrary(NULL, false);
- if (mock_input_method_library_)
- test_api()->SetInputMethodLibrary(NULL, false);
- if (mock_network_library_)
- test_api()->SetNetworkLibrary(NULL, false);
- if (mock_power_library_)
- test_api()->SetPowerLibrary(NULL, false);
- if (mock_screen_lock_library_)
- test_api()->SetScreenLockLibrary(NULL, false);
- if (mock_synaptics_library_)
- test_api()->SetSynapticsLibrary(NULL, false);
- if (mock_system_library_)
- test_api()->SetSystemLibrary(NULL, false);
+ cros_mock_->TearDownMocks();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/cros_in_process_browser_test.h b/chrome/browser/chromeos/cros/cros_in_process_browser_test.h
index 52e11db..b4e9a2e 100644
--- a/chrome/browser/chromeos/cros/cros_in_process_browser_test.h
+++ b/chrome/browser/chromeos/cros/cros_in_process_browser_test.h
@@ -4,32 +4,19 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_CROS_IN_PROCESS_BROWSER_TEST_H_
#define CHROME_BROWSER_CHROMEOS_CROS_CROS_IN_PROCESS_BROWSER_TEST_H_
+#pragma once
#include "base/scoped_ptr.h"
-#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/cros_mock.h"
#include "chrome/test/in_process_browser_test.h"
-#include "cros/chromeos_input_method.h"
namespace chromeos {
-class MockCryptohomeLibrary;
-class MockKeyboardLibrary;
-class MockInputMethodLibrary;
-class MockLibraryLoader;
-class MockNetworkLibrary;
-class MockPowerLibrary;
-class MockScreenLockLibrary;
-class MockScreenLockLibrary;
-class MockSynapticsLibrary;
-class MockSystemLibrary;
-
// Base class for Chromium OS tests wanting to bring up a browser in the
// unit test process and mock some parts of CrosLibrary. Once you mock part of
// CrosLibrary it will be considered as successfully loaded and libraries
-// that compose CrosLibrary will be created. The issue here is that you do
-// need to specify minimum set of mocks for you test to succeed.
-// CrosInProcessBrowserTest defines minimum set of mocks that is used
-// by status area elements (network, input language, power).
+// that compose CrosLibrary will be created. Use CrosMock to specify minimum
+// set of mocks for you test to succeed.
// See comments for InProcessBrowserTest base class too.
class CrosInProcessBrowserTest : public InProcessBrowserTest {
public:
@@ -37,62 +24,11 @@ class CrosInProcessBrowserTest : public InProcessBrowserTest {
virtual ~CrosInProcessBrowserTest();
protected:
- // This method setups basic mocks that are used by status area items:
- // LibraryLoader, Language, Network, Power, Synaptics libraries.
- // Add call to this method at the beginning of your
- // SetUpInProcessBrowserTestFixture.
- void InitStatusAreaMocks();
-
- // Initialization of CrosLibrary mock loader. If you intend calling
- // separate init methods for mocks call this one first.
- void InitMockLibraryLoader();
-
- // Initialization of mocks.
- void InitMockCryptohomeLibrary();
- void InitMockKeyboardLibrary();
- void InitMockInputMethodLibrary();
- void InitMockNetworkLibrary();
- void InitMockPowerLibrary();
- void InitMockScreenLockLibrary();
- void InitMockSynapticsLibrary();
- void InitMockSystemLibrary();
-
- // This method setups corresponding expectations for basic mocks that
- // are used by status area items.
- // Make sure that InitStatusAreaMocks was called before.
- // Add call to this method in your SetUpInProcessBrowserTestFixture.
- // They are all configured with RetiresOnSaturation().
- // Once such expectation is used it won't block expectations you've defined.
- void SetStatusAreaMocksExpectations();
-
- // Methods to setup minimal mocks expectations for status area.
- void SetKeyboardLibraryStatusAreaExpectations();
- void SetInputMethodLibraryStatusAreaExpectations();
- void SetNetworkLibraryStatusAreaExpectations();
- void SetPowerLibraryStatusAreaExpectations();
- void SetSystemLibraryStatusAreaExpectations();
- void SetSynapticsLibraryExpectations();
- void SetSystemLibraryExpectations();
+ scoped_ptr<CrosMock> cros_mock_;
// Overriden for things you would normally override TearDown for.
virtual void TearDownInProcessBrowserTestFixture();
- // TestApi gives access to CrosLibrary private members.
- chromeos::CrosLibrary::TestApi* test_api();
-
- // Mocks, destroyed by CrosLibrary class.
- MockLibraryLoader* loader_;
- MockCryptohomeLibrary* mock_cryptohome_library_;
- MockKeyboardLibrary* mock_keyboard_library_;
- MockInputMethodLibrary* mock_input_method_library_;
- MockNetworkLibrary* mock_network_library_;
- MockPowerLibrary* mock_power_library_;
- MockScreenLockLibrary* mock_screen_lock_library_;
- MockSynapticsLibrary* mock_synaptics_library_;
- MockSystemLibrary* mock_system_library_;
-
- ImePropertyList ime_properties_;
-
private:
DISALLOW_COPY_AND_ASSIGN(CrosInProcessBrowserTest);
};
diff --git a/chrome/browser/chromeos/cros/cros_library.cc b/chrome/browser/chromeos/cros/cros_library.cc
index a9e469d..9065304 100644
--- a/chrome/browser/chromeos/cros/cros_library.cc
+++ b/chrome/browser/chromeos/cros/cros_library.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/cros/cros_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"
#include "chrome/browser/chromeos/cros/input_method_library.h"
@@ -14,77 +15,24 @@
#include "chrome/browser/chromeos/cros/power_library.h"
#include "chrome/browser/chromeos/cros/screen_lock_library.h"
#include "chrome/browser/chromeos/cros/speech_synthesis_library.h"
-#include "chrome/browser/chromeos/cros/synaptics_library.h"
#include "chrome/browser/chromeos/cros/syslogs_library.h"
#include "chrome/browser/chromeos/cros/system_library.h"
+#include "chrome/browser/chromeos/cros/touchpad_library.h"
#include "chrome/browser/chromeos/cros/update_library.h"
namespace chromeos {
CrosLibrary::CrosLibrary() : library_loader_(NULL),
- crypto_lib_(NULL),
- keyboard_lib_(NULL),
- input_method_lib_(NULL),
- login_lib_(NULL),
- mount_lib_(NULL),
- network_lib_(NULL),
- power_lib_(NULL),
- screen_lock_lib_(NULL),
- speech_synthesis_lib_(NULL),
- synaptics_lib_(NULL),
- syslogs_lib_(NULL),
- system_lib_(NULL),
- update_lib_(NULL),
- own_library_loader_(true),
- own_cryptohome_lib_(true),
- own_keyboard_lib_(true),
- own_input_method_lib_(true),
- own_login_lib_(true),
- own_mount_lib_(true),
- own_network_lib_(true),
- own_power_lib_(true),
- own_screen_lock_lib_(true),
- own_speech_synthesis_lib_(true),
- own_synaptics_lib_(true),
- own_syslogs_lib_(true),
- own_system_lib_(true),
- own_update_lib_(true),
+ own_library_loader_(false),
+ use_stub_impl_(false),
loaded_(false),
load_error_(false),
test_api_(NULL) {
-
}
CrosLibrary::~CrosLibrary() {
if (own_library_loader_)
delete library_loader_;
- if (own_cryptohome_lib_)
- delete crypto_lib_;
- if (own_keyboard_lib_)
- delete keyboard_lib_;
- if (own_input_method_lib_)
- delete input_method_lib_;
- if (own_login_lib_)
- delete login_lib_;
- if (own_mount_lib_)
- delete mount_lib_;
- if (own_network_lib_)
- delete network_lib_;
- if (own_power_lib_)
- delete power_lib_;
- if (own_screen_lock_lib_)
- delete screen_lock_lib_;
- if (own_speech_synthesis_lib_)
- delete speech_synthesis_lib_;
- if (own_synaptics_lib_)
- delete synaptics_lib_;
- if (own_syslogs_lib_)
- delete syslogs_lib_;
- if (own_system_lib_)
- delete system_lib_;
- if (own_update_lib_)
- delete update_lib_;
- delete test_api_;
}
// static
@@ -92,88 +40,71 @@ CrosLibrary* CrosLibrary::Get() {
return Singleton<CrosLibrary>::get();
}
+BurnLibrary* CrosLibrary::GetBurnLibrary() {
+ return burn_lib_.GetDefaultImpl(use_stub_impl_);
+}
+
CryptohomeLibrary* CrosLibrary::GetCryptohomeLibrary() {
- if (!crypto_lib_)
- crypto_lib_ = new CryptohomeLibraryImpl();
- return crypto_lib_;
+ return crypto_lib_.GetDefaultImpl(use_stub_impl_);
}
KeyboardLibrary* CrosLibrary::GetKeyboardLibrary() {
- if (!keyboard_lib_)
- keyboard_lib_ = new KeyboardLibraryImpl();
- return keyboard_lib_;
+ return keyboard_lib_.GetDefaultImpl(use_stub_impl_);
}
InputMethodLibrary* CrosLibrary::GetInputMethodLibrary() {
- if (!input_method_lib_)
- input_method_lib_ = new InputMethodLibraryImpl();
- return input_method_lib_;
+ return input_method_lib_.GetDefaultImpl(use_stub_impl_);
}
LoginLibrary* CrosLibrary::GetLoginLibrary() {
- if (!login_lib_)
- login_lib_ = new LoginLibraryImpl();
- return login_lib_;
+ return login_lib_.GetDefaultImpl(use_stub_impl_);
}
MountLibrary* CrosLibrary::GetMountLibrary() {
- if (!mount_lib_)
- mount_lib_ = new MountLibraryImpl();
- return mount_lib_;
+ return mount_lib_.GetDefaultImpl(use_stub_impl_);
}
NetworkLibrary* CrosLibrary::GetNetworkLibrary() {
- if (!network_lib_)
- network_lib_ = new NetworkLibraryImpl();
- return network_lib_;
+ return network_lib_.GetDefaultImpl(use_stub_impl_);
}
PowerLibrary* CrosLibrary::GetPowerLibrary() {
- if (!power_lib_)
- power_lib_ = new PowerLibraryImpl();
- return power_lib_;
+ return power_lib_.GetDefaultImpl(use_stub_impl_);
}
ScreenLockLibrary* CrosLibrary::GetScreenLockLibrary() {
- if (!screen_lock_lib_)
- screen_lock_lib_ = new ScreenLockLibraryImpl();
- return screen_lock_lib_;
+ return screen_lock_lib_.GetDefaultImpl(use_stub_impl_);
}
SpeechSynthesisLibrary* CrosLibrary::GetSpeechSynthesisLibrary() {
- if (!speech_synthesis_lib_)
- speech_synthesis_lib_ = new SpeechSynthesisLibraryImpl();
- return speech_synthesis_lib_;
-}
-
-SynapticsLibrary* CrosLibrary::GetSynapticsLibrary() {
- if (!synaptics_lib_)
- synaptics_lib_ = new SynapticsLibraryImpl();
- return synaptics_lib_;
+ return speech_synthesis_lib_.GetDefaultImpl(use_stub_impl_);
}
SyslogsLibrary* CrosLibrary::GetSyslogsLibrary() {
- if (!syslogs_lib_)
- syslogs_lib_ = new SyslogsLibraryImpl();
- return syslogs_lib_;
+ return syslogs_lib_.GetDefaultImpl(use_stub_impl_);
}
SystemLibrary* CrosLibrary::GetSystemLibrary() {
- if (!system_lib_)
- system_lib_ = new SystemLibraryImpl();
- return system_lib_;
+ return system_lib_.GetDefaultImpl(use_stub_impl_);
+}
+
+TouchpadLibrary* CrosLibrary::GetTouchpadLibrary() {
+ return touchpad_lib_.GetDefaultImpl(use_stub_impl_);
}
UpdateLibrary* CrosLibrary::GetUpdateLibrary() {
- if (!update_lib_)
- update_lib_ = new UpdateLibraryImpl();
- return update_lib_;
+ return update_lib_.GetDefaultImpl(use_stub_impl_);
}
bool CrosLibrary::EnsureLoaded() {
+ if (use_stub_impl_)
+ return true;
+
if (!loaded_ && !load_error_) {
- if (!library_loader_)
+ if (!library_loader_) {
library_loader_ = new CrosLibraryLoader();
+ own_library_loader_ = true;
+ }
loaded_ = library_loader_->Load(&load_error_string_);
load_error_ = !loaded_;
}
@@ -181,9 +112,17 @@ bool CrosLibrary::EnsureLoaded() {
}
CrosLibrary::TestApi* CrosLibrary::GetTestApi() {
- if (!test_api_)
- test_api_ = new TestApi(this);
- return test_api_;
+ if (!test_api_.get())
+ test_api_.reset(new TestApi(this));
+ return test_api_.get();
+}
+
+void CrosLibrary::TestApi::SetUseStubImpl() {
+ library_->use_stub_impl_ = true;
+}
+
+void CrosLibrary::TestApi::ResetUseStubImpl() {
+ library_->use_stub_impl_ = false;
}
void CrosLibrary::TestApi::SetLibraryLoader(LibraryLoader* loader, bool own) {
@@ -199,105 +138,74 @@ void CrosLibrary::TestApi::SetLibraryLoader(LibraryLoader* loader, bool own) {
library_->load_error_ = false;
}
-void CrosLibrary::TestApi::SetCryptohomeLibrary(CryptohomeLibrary* library,
- bool own) {
- if (library_->own_cryptohome_lib_)
- delete library_->crypto_lib_;
- library_->own_cryptohome_lib_ = own;
- library_->crypto_lib_ = library;
+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) {
- if (library_->own_keyboard_lib_)
- delete library_->keyboard_lib_;
- library_->own_keyboard_lib_ = own;
- library_->keyboard_lib_ = library;
+void CrosLibrary::TestApi::SetKeyboardLibrary(
+ KeyboardLibrary* library, bool own) {
+ library_->keyboard_lib_.SetImpl(library, own);
}
-void CrosLibrary::TestApi::SetInputMethodLibrary(InputMethodLibrary* library,
- bool own) {
- if (library_->own_input_method_lib_)
- delete library_->input_method_lib_;
- library_->own_input_method_lib_ = own;
- library_->input_method_lib_ = library;
+void CrosLibrary::TestApi::SetInputMethodLibrary(
+ InputMethodLibrary* library, bool own) {
+ library_->input_method_lib_.SetImpl(library, own);
}
-void CrosLibrary::TestApi::SetLoginLibrary(LoginLibrary* library, bool own) {
- if (library_->own_login_lib_)
- delete library_->login_lib_;
- library_->own_login_lib_ = own;
- library_->login_lib_ = library;
+void CrosLibrary::TestApi::SetLoginLibrary(
+ LoginLibrary* library, bool own) {
+ library_->login_lib_.SetImpl(library, own);
}
-void CrosLibrary::TestApi::SetMountLibrary(MountLibrary* library, bool own) {
- if (library_->own_mount_lib_)
- delete library_->mount_lib_;
- library_->own_mount_lib_ = own;
- library_->mount_lib_ = library;
+void CrosLibrary::TestApi::SetMountLibrary(
+ MountLibrary* library, bool own) {
+ library_->mount_lib_.SetImpl(library, own);
}
-void CrosLibrary::TestApi::SetNetworkLibrary(NetworkLibrary* library,
- bool own) {
- if (library_->own_network_lib_)
- delete library_->network_lib_;
- library_->own_network_lib_ = own;
- library_->network_lib_ = library;
+void CrosLibrary::TestApi::SetNetworkLibrary(
+ NetworkLibrary* library, bool own) {
+ library_->network_lib_.SetImpl(library, own);
}
-void CrosLibrary::TestApi::SetPowerLibrary(PowerLibrary* library, bool own) {
- if (library_->own_power_lib_)
- delete library_->power_lib_;
- library_->own_power_lib_ = own;
- library_->power_lib_ = library;
+void CrosLibrary::TestApi::SetPowerLibrary(
+ PowerLibrary* library, bool own) {
+ library_->power_lib_.SetImpl(library, own);
}
-void CrosLibrary::TestApi::SetScreenLockLibrary(ScreenLockLibrary* library,
- bool own) {
- if (library_->own_screen_lock_lib_)
- delete library_->screen_lock_lib_;
- library_->own_screen_lock_lib_ = own;
- library_->screen_lock_lib_ = library;
+void CrosLibrary::TestApi::SetScreenLockLibrary(
+ ScreenLockLibrary* library, bool own) {
+ library_->screen_lock_lib_.SetImpl(library, own);
}
void CrosLibrary::TestApi::SetSpeechSynthesisLibrary(
SpeechSynthesisLibrary* library, bool own) {
- if (library_->own_speech_synthesis_lib_)
- delete library_->speech_synthesis_lib_;
- library_->own_speech_synthesis_lib_ = own;
- library_->speech_synthesis_lib_ = library;
-}
-
-void CrosLibrary::TestApi::SetSynapticsLibrary(SynapticsLibrary* library,
- bool own) {
- if (library_->own_synaptics_lib_)
- delete library_->synaptics_lib_;
- library_->own_synaptics_lib_ = own;
- library_->synaptics_lib_ = library;
-}
-
-void CrosLibrary::TestApi::SetSyslogsLibrary(SyslogsLibrary* library,
- bool own) {
- if (library_->syslogs_lib_)
- delete library_->syslogs_lib_;
- library_->own_syslogs_lib_ = own;
- library_->syslogs_lib_ = library;
-}
-
-void CrosLibrary::TestApi::SetSystemLibrary(SystemLibrary* library,
- bool own) {
- if (library_->system_lib_)
- delete library_->system_lib_;
- library_->own_system_lib_ = own;
- library_->system_lib_ = library;
-}
-
-void CrosLibrary::TestApi::SetUpdateLibrary(UpdateLibrary* library,
- bool own) {
- if (library_->update_lib_)
- delete library_->update_lib_;
- library_->own_update_lib_ = own;
- library_->update_lib_ = library;
+ 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);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/cros_library.h b/chrome/browser/chromeos/cros/cros_library.h
index b08254a..6695acf 100644
--- a/chrome/browser/chromeos/cros/cros_library.h
+++ b/chrome/browser/chromeos/cros/cros_library.h
@@ -4,13 +4,15 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_CROS_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_CROS_LIBRARY_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
#include "base/singleton.h"
-
namespace chromeos {
+class BurnLibrary;
class CryptohomeLibrary;
class KeyboardLibrary;
class InputMethodLibrary;
@@ -21,9 +23,9 @@ class NetworkLibrary;
class PowerLibrary;
class ScreenLockLibrary;
class SpeechSynthesisLibrary;
-class SynapticsLibrary;
class SyslogsLibrary;
class SystemLibrary;
+class TouchpadLibrary;
class UpdateLibrary;
// This class handles access to sub-parts of ChromeOS library. it provides
@@ -31,16 +33,23 @@ class UpdateLibrary;
// be mocked for testing.
class CrosLibrary {
public:
-
// This class provides access to internal members of CrosLibrary class for
// purpose of testing (i.e. replacement of members' implementation with
// mock objects).
class TestApi {
public:
+ // 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 SetBurnLibrary(BurnLibrary* library, bool own);
// Setter for CryptohomeLibrary.
void SetCryptohomeLibrary(CryptohomeLibrary* library, bool own);
// Setter for KeyboardLibrary
@@ -59,12 +68,12 @@ class CrosLibrary {
void SetScreenLockLibrary(ScreenLockLibrary* library, bool own);
// Setter for SpeechSynthesisLibrary.
void SetSpeechSynthesisLibrary(SpeechSynthesisLibrary* library, bool own);
- // Setter for SynapticsLibrary.
- void SetSynapticsLibrary(SynapticsLibrary* 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);
@@ -77,6 +86,9 @@ class CrosLibrary {
// This gets the CrosLibrary.
static CrosLibrary* Get();
+ // Getter for BurnLibrary.
+ BurnLibrary* GetBurnLibrary();
+
// Getter for CryptohomeLibrary.
CryptohomeLibrary* GetCryptohomeLibrary();
@@ -104,15 +116,15 @@ class CrosLibrary {
// This gets the singleton SpeechSynthesisLibrary.
SpeechSynthesisLibrary* GetSpeechSynthesisLibrary();
- // This gets the singleton SynapticsLibrary.
- SynapticsLibrary* GetSynapticsLibrary();
-
// 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();
@@ -136,42 +148,67 @@ class CrosLibrary {
virtual ~CrosLibrary();
LibraryLoader* library_loader_;
- CryptohomeLibrary* crypto_lib_;
- KeyboardLibrary* keyboard_lib_;
- InputMethodLibrary* input_method_lib_;
- LoginLibrary* login_lib_;
- MountLibrary* mount_lib_;
- NetworkLibrary* network_lib_;
- PowerLibrary* power_lib_;
- ScreenLockLibrary* screen_lock_lib_;
- SpeechSynthesisLibrary* speech_synthesis_lib_;
- SynapticsLibrary* synaptics_lib_;
- SyslogsLibrary* syslogs_lib_;
- SystemLibrary* system_lib_;
- UpdateLibrary* update_lib_;
bool own_library_loader_;
- bool own_cryptohome_lib_;
- bool own_keyboard_lib_;
- bool own_input_method_lib_;
- bool own_login_lib_;
- bool own_mount_lib_;
- bool own_network_lib_;
- bool own_power_lib_;
- bool own_screen_lock_lib_;
- bool own_speech_synthesis_lib_;
- bool own_synaptics_lib_;
- bool own_syslogs_lib_;
- bool own_system_lib_;
- bool own_update_lib_;
+ // This template supports the creation, setting and optional deletion of
+ // the cros libraries.
+ template <class L>
+ class Library {
+ public:
+ Library() : library_(NULL), own_(true) {}
+
+ ~Library() {
+ if (own_)
+ delete library_;
+ }
+
+ L* GetDefaultImpl(bool use_stub_impl) {
+ if (!library_) {
+ own_ = true;
+ library_ = L::GetImpl(use_stub_impl);
+ }
+ return library_;
+ }
+
+ void SetImpl(L* library, bool own) {
+ if (library != library_) {
+ if (own_)
+ delete library_;
+ library_ = library;
+ own_ = own;
+ }
+ }
+
+ private:
+ L* library_;
+ bool own_;
+ };
+
+ Library<BurnLibrary> burn_lib_;
+ Library<CryptohomeLibrary> crypto_lib_;
+ Library<KeyboardLibrary> keyboard_lib_;
+ Library<InputMethodLibrary> input_method_lib_;
+ Library<LoginLibrary> login_lib_;
+ Library<MountLibrary> mount_lib_;
+ Library<NetworkLibrary> network_lib_;
+ Library<PowerLibrary> power_lib_;
+ Library<ScreenLockLibrary> screen_lock_lib_;
+ Library<SpeechSynthesisLibrary> speech_synthesis_lib_;
+ Library<SyslogsLibrary> syslogs_lib_;
+ Library<SystemLibrary> system_lib_;
+ Library<TouchpadLibrary> touchpad_lib_;
+ Library<UpdateLibrary> update_lib_;
+
+ // Stub implementations of the libraries should be used.
+ bool use_stub_impl_;
// True if libcros was successfully loaded.
bool loaded_;
// True if the last load attempt had an error.
bool load_error_;
// Contains the error string from the last load attempt.
std::string load_error_string_;
- TestApi* test_api_;
+ scoped_ptr<TestApi> test_api_;
DISALLOW_COPY_AND_ASSIGN(CrosLibrary);
};
diff --git a/chrome/browser/chromeos/cros/cros_library_loader.h b/chrome/browser/chromeos/cros/cros_library_loader.h
index c326ab6..3ee1679 100644
--- a/chrome/browser/chromeos/cros/cros_library_loader.h
+++ b/chrome/browser/chromeos/cros/cros_library_loader.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_CROS_LIBRARY_LOADER_H_
#define CHROME_BROWSER_CHROMEOS_CROS_CROS_LIBRARY_LOADER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/cros/cryptohome_library.cc b/chrome/browser/chromeos/cros/cryptohome_library.cc
index 6ac8432..cd75a85 100644
--- a/chrome/browser/chromeos/cros/cryptohome_library.cc
+++ b/chrome/browser/chromeos/cros/cryptohome_library.cc
@@ -4,46 +4,239 @@
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
+#include "base/hash_tables.h"
#include "base/message_loop.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
namespace chromeos {
-bool CryptohomeLibraryImpl::CheckKey(const std::string& user_email,
- const std::string& passhash) {
- return chromeos::CryptohomeCheckKey(user_email.c_str(), passhash.c_str());
-}
+// This class handles the interaction with the ChromeOS cryptohome library APIs.
+class CryptohomeLibraryImpl : public CryptohomeLibrary {
+ public:
+ CryptohomeLibraryImpl() {
+ if (CrosLibrary::Get()->EnsureLoaded())
+ Init();
+ }
+ virtual ~CryptohomeLibraryImpl() {}
-bool CryptohomeLibraryImpl::MigrateKey(const std::string& user_email,
- const std::string& old_hash,
- const std::string& new_hash) {
- return chromeos::CryptohomeMigrateKey(user_email.c_str(),
- old_hash.c_str(),
- new_hash.c_str());
-}
+ bool CheckKey(const std::string& user_email, const std::string& passhash) {
+ return chromeos::CryptohomeCheckKey(user_email.c_str(), passhash.c_str());
+ }
-bool CryptohomeLibraryImpl::Remove(const std::string& user_email) {
- return chromeos::CryptohomeRemove(user_email.c_str());
-}
+ bool AsyncCheckKey(const std::string& user_email,
+ const std::string& passhash,
+ Delegate* d) {
+ return CacheCallback(
+ chromeos::CryptohomeAsyncCheckKey(user_email.c_str(), passhash.c_str()),
+ d,
+ "Couldn't initiate async check of user's key.");
+ }
-bool CryptohomeLibraryImpl::Mount(const std::string& user_email,
- const std::string& passhash,
- int* error_code) {
- return chromeos::CryptohomeMountAllowFail(user_email.c_str(),
- passhash.c_str(),
- error_code);
-}
+ bool MigrateKey(const std::string& user_email,
+ const std::string& old_hash,
+ const std::string& new_hash) {
+ return chromeos::CryptohomeMigrateKey(user_email.c_str(),
+ old_hash.c_str(),
+ new_hash.c_str());
+ }
-bool CryptohomeLibraryImpl::MountForBwsi(int* error_code) {
- return chromeos::CryptohomeMountGuest(error_code);
-}
+ bool AsyncMigrateKey(const std::string& user_email,
+ const std::string& old_hash,
+ const std::string& new_hash,
+ Delegate* d) {
+ return CacheCallback(
+ chromeos::CryptohomeAsyncMigrateKey(user_email.c_str(),
+ old_hash.c_str(),
+ new_hash.c_str()),
+ d,
+ "Couldn't initiate aync migration of user's key");
+ }
-bool CryptohomeLibraryImpl::IsMounted() {
- return chromeos::CryptohomeIsMounted();
-}
+ bool Mount(const std::string& user_email,
+ const std::string& passhash,
+ int* error_code) {
+ return chromeos::CryptohomeMountAllowFail(user_email.c_str(),
+ passhash.c_str(),
+ error_code);
+ }
+
+ bool AsyncMount(const std::string& user_email,
+ const std::string& passhash,
+ const bool create_if_missing,
+ Delegate* d) {
+ return CacheCallback(
+ chromeos::CryptohomeAsyncMount(user_email.c_str(),
+ passhash.c_str(),
+ create_if_missing,
+ "",
+ std::vector<std::string>()),
+ d,
+ "Couldn't initiate async mount of cryptohome.");
+ }
+
+ bool MountForBwsi(int* error_code) {
+ return chromeos::CryptohomeMountGuest(error_code);
+ }
+
+ bool AsyncMountForBwsi(Delegate* d) {
+ return CacheCallback(chromeos::CryptohomeAsyncMountGuest(),
+ d,
+ "Couldn't initiate async mount of cryptohome.");
+ }
+
+ bool Remove(const std::string& user_email) {
+ return chromeos::CryptohomeRemove(user_email.c_str());
+ }
+
+ bool AsyncRemove(const std::string& user_email, Delegate* d) {
+ return CacheCallback(
+ chromeos::CryptohomeAsyncRemove(user_email.c_str()),
+ d,
+ "Couldn't initiate async removal of cryptohome.");
+ }
+
+ bool IsMounted() {
+ return chromeos::CryptohomeIsMounted();
+ }
+
+ CryptohomeBlob GetSystemSalt() {
+ return chromeos::CryptohomeGetSystemSalt();
+ }
+
+ private:
+ static void Handler(const chromeos::CryptohomeAsyncCallStatus& event,
+ void* cryptohome_library) {
+ CryptohomeLibraryImpl* library =
+ reinterpret_cast<CryptohomeLibraryImpl*>(cryptohome_library);
+ library->Dispatch(event);
+ }
+
+ void Init() {
+ cryptohome_connection_ = chromeos::CryptohomeMonitorSession(&Handler, this);
+ }
+
+ void Dispatch(const chromeos::CryptohomeAsyncCallStatus& event) {
+ callback_map_[event.async_id]->OnComplete(event.return_status,
+ event.return_code);
+ callback_map_[event.async_id] = NULL;
+ }
+
+ bool CacheCallback(int async_id,
+ Delegate* d,
+ const char* error) {
+ if (async_id == 0) {
+ LOG(ERROR) << error;
+ return false;
+ }
+ callback_map_[async_id] = d;
+ return true;
+ }
+
+ typedef base::hash_map<int, Delegate*> CallbackMap;
+ mutable CallbackMap callback_map_;
+
+ void* cryptohome_connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl);
+};
+
+class CryptohomeLibraryStubImpl : public CryptohomeLibrary {
+ public:
+ CryptohomeLibraryStubImpl() {}
+ virtual ~CryptohomeLibraryStubImpl() {}
+
+ bool CheckKey(const std::string& user_email, const std::string& passhash) {
+ return true;
+ }
+
+ bool AsyncCheckKey(const std::string& user_email,
+ const std::string& passhash,
+ Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+
+ bool MigrateKey(const std::string& user_email,
+ const std::string& old_hash,
+ const std::string& new_hash) {
+ return true;
+ }
+
+ bool AsyncMigrateKey(const std::string& user_email,
+ const std::string& old_hash,
+ const std::string& new_hash,
+ Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+
+ bool Remove(const std::string& user_email) {
+ return true;
+ }
+
+ bool AsyncRemove(const std::string& user_email, Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+
+ bool Mount(const std::string& user_email,
+ const std::string& passhash,
+ int* error_code) {
+ return true;
+ }
+
+ bool AsyncMount(const std::string& user_email,
+ const std::string& passhash,
+ const bool create_if_missing,
+ Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+
+ bool MountForBwsi(int* error_code) {
+ return true;
+ }
+
+ bool AsyncMountForBwsi(Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+
+ bool IsMounted() {
+ return true;
+ }
+
+ CryptohomeBlob GetSystemSalt() {
+ CryptohomeBlob salt = CryptohomeBlob();
+ salt.push_back(0);
+ salt.push_back(0);
+ return salt;
+ }
+
+ private:
+ static void DoStubCallback(Delegate* callback) {
+ callback->OnComplete(true, kCryptohomeMountErrorNone);
+ }
+ DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryStubImpl);
+};
-CryptohomeBlob CryptohomeLibraryImpl::GetSystemSalt() {
- return chromeos::CryptohomeGetSystemSalt();
+// static
+CryptohomeLibrary* CryptohomeLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new CryptohomeLibraryStubImpl();
+ else
+ return new CryptohomeLibraryImpl();
}
-} // namespace chromeos
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/cryptohome_library.h b/chrome/browser/chromeos/cros/cryptohome_library.h
index 6e91d30..9a72761 100644
--- a/chrome/browser/chromeos/cros/cryptohome_library.h
+++ b/chrome/browser/chromeos/cros/cryptohome_library.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_CRYPTOHOME_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_CRYPTOHOME_LIBRARY_H_
+#pragma once
#include <string>
#include "base/singleton.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
#include "cros/chromeos_cryptohome.h"
namespace chromeos {
@@ -16,68 +18,90 @@ namespace chromeos {
// APIs.
class CryptohomeLibrary {
public:
- virtual ~CryptohomeLibrary() {}
-
- // Asks cryptohomed to try to find the cryptohome for |user_email| and then
- // mount it using |passhash| to unlock the key.
- virtual bool Mount(const std::string& user_email,
- const std::string& passhash,
- int* error_code) = 0;
+ class Delegate {
+ public:
+ // This will be called back on the UI thread. Consult |return_code| for
+ // further information beyond mere success or failure.
+ virtual void OnComplete(bool success, int return_code) = 0;
+ };
- // Asks cryptohomed to mount a tmpfs for BWSI mode.
- virtual bool MountForBwsi(int* error_code) = 0;
+ virtual ~CryptohomeLibrary() {}
// Asks cryptohomed to try to find the cryptohome for |user_email| and then
// use |passhash| to unlock the key.
virtual bool CheckKey(const std::string& user_email,
const std::string& passhash) = 0;
+ // Asks cryptohomed to asynchronously try to find the cryptohome for
+ // |user_email| and then use |passhash| to unlock the key.
+ // Returns true if the attempt is successfully initiated.
+ // d->OnComplete() will be called with status info on completion.
+ virtual bool AsyncCheckKey(const std::string& user_email,
+ const std::string& passhash,
+ Delegate* callback) = 0;
+
// Asks cryptohomed to try to find the cryptohome for |user_email| and then
// change from using |old_hash| to lock the key to using |new_hash|.
virtual bool MigrateKey(const std::string& user_email,
const std::string& old_hash,
const std::string& new_hash) = 0;
- // Asks cryptohomed to try to find the cryptohome for |user_email| and then
- // nuke it.
- virtual bool Remove(const std::string& user_email) = 0;
-
- // Asks cryptohomed if a drive is currently mounted.
- virtual bool IsMounted() = 0;
-
- // Asks cryptohomed for the system salt.
- virtual CryptohomeBlob GetSystemSalt() = 0;
-
-};
+ // Asks cryptohomed to asynchronously try to find the cryptohome for
+ // |user_email| and then change from using |old_hash| to lock the
+ // key to using |new_hash|.
+ // Returns true if the attempt is successfully initiated.
+ // d->OnComplete() will be called with status info on completion.
+ virtual bool AsyncMigrateKey(const std::string& user_email,
+ const std::string& old_hash,
+ const std::string& new_hash,
+ Delegate* callback) = 0;
-// This class handles the interaction with the ChromeOS cryptohome library APIs.
-class CryptohomeLibraryImpl : public CryptohomeLibrary {
- public:
- CryptohomeLibraryImpl() {}
- virtual ~CryptohomeLibraryImpl() {}
-
- // CryptohomeLibrary overrides.
+ // Asks cryptohomed to try to find the cryptohome for |user_email| and then
+ // mount it using |passhash| to unlock the key.
virtual bool Mount(const std::string& user_email,
const std::string& passhash,
- int* error_code);
+ int* error_code) = 0;
- virtual bool MountForBwsi(int* error_code);
+ // Asks cryptohomed to asynchronously try to find the cryptohome for
+ // |user_email| and then mount it using |passhash| to unlock the key.
+ // |create_if_missing| controls whether or not we ask cryptohomed to
+ // create a new home dir if one does not yet exist for |user_email|.
+ // Returns true if the attempt is successfully initiated.
+ // d->OnComplete() will be called with status info on completion.
+ // If |create_if_missing| is false, and no cryptohome exists for |user_email|,
+ // we'll get d->OnComplete(false, kCryptohomeMountErrorUserDoesNotExist).
+ // Otherwise, we expect the normal range of return codes.
+ virtual bool AsyncMount(const std::string& user_email,
+ const std::string& passhash,
+ const bool create_if_missing,
+ Delegate* callback) = 0;
- virtual bool CheckKey(const std::string& user_email,
- const std::string& passhash);
+ // Asks cryptohomed to mount a tmpfs for BWSI mode.
+ virtual bool MountForBwsi(int* error_code) = 0;
- virtual bool MigrateKey(const std::string& user_email,
- const std::string& old_hash,
- const std::string& new_hash);
+ // Asks cryptohomed to asynchronously to mount a tmpfs for BWSI mode.
+ // Returns true if the attempt is successfully initiated.
+ // d->OnComplete() will be called with status info on completion.
+ virtual bool AsyncMountForBwsi(Delegate* callback) = 0;
+
+ // Asks cryptohomed to try to find the cryptohome for |user_email| and then
+ // nuke it.
+ virtual bool Remove(const std::string& user_email) = 0;
- virtual bool Remove(const std::string& user_email);
+ // Asks cryptohomed to asynchronously try to find the cryptohome for
+ // |user_email| and then nuke it.
+ virtual bool AsyncRemove(const std::string& user_email,
+ Delegate* callback) = 0;
- virtual bool IsMounted();
+ // Asks cryptohomed if a drive is currently mounted.
+ virtual bool IsMounted() = 0;
- virtual CryptohomeBlob GetSystemSalt();
+ // Asks cryptohomed for the system salt.
+ virtual CryptohomeBlob GetSystemSalt() = 0;
- private:
- DISALLOW_COPY_AND_ASSIGN(CryptohomeLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static CryptohomeLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/input_method_library.cc b/chrome/browser/chromeos/cros/input_method_library.cc
index 260e507..933700b 100644
--- a/chrome/browser/chromeos/cros/input_method_library.cc
+++ b/chrome/browser/chromeos/cros/input_method_library.cc
@@ -4,20 +4,27 @@
#include "chrome/browser/chromeos/cros/input_method_library.h"
+#include <glib.h>
+#include <signal.h>
+
+#include "unicode/uloc.h"
+
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.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/language_preferences.h"
-#include "third_party/icu/public/common/unicode/uloc.h"
-
-// Allows InvokeLater without adding refcounting. This class is a Singleton and
-// won't be deleted until it's last InvokeLater is run.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::InputMethodLibraryImpl);
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
namespace {
+const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon";
+const char kCandidateWindowPath[] = "/opt/google/chrome/candidate_window";
// Finds a property which has |new_prop.key| from |prop_list|, and replaces the
// property with |new_prop|. Returns true if such a property is found.
@@ -37,265 +44,737 @@ bool FindAndUpdateProperty(const chromeos::ImeProperty& new_prop,
return false;
}
-// The default keyboard layout.
-const char kDefaultKeyboardLayout[] = "us";
-
} // namespace
namespace chromeos {
-InputMethodLibraryImpl::InputMethodLibraryImpl()
- : input_method_status_connection_(NULL),
- previous_input_method_("", "", "", ""),
- current_input_method_("", "", "", "") {
- scoped_ptr<InputMethodDescriptors> input_method_descriptors(
- CreateFallbackInputMethodDescriptors());
- current_input_method_ = input_method_descriptors->at(0);
-}
-
-InputMethodLibraryImpl::~InputMethodLibraryImpl() {
- if (input_method_status_connection_) {
- chromeos::DisconnectInputMethodStatus(input_method_status_connection_);
+class InputMethodLibraryImpl : public InputMethodLibrary,
+ public NotificationObserver {
+ public:
+ InputMethodLibraryImpl()
+ : input_method_status_connection_(NULL),
+ previous_input_method_("", "", "", ""),
+ current_input_method_("", "", "", ""),
+ should_launch_ime_(false),
+ ime_connected_(false),
+ defer_ime_startup_(false),
+ should_change_input_method_(false),
+ ibus_daemon_process_id_(0),
+ candidate_window_process_id_(0),
+ failure_count_(0) {
+ scoped_ptr<InputMethodDescriptors> input_method_descriptors(
+ CreateFallbackInputMethodDescriptors());
+ current_input_method_ = input_method_descriptors->at(0);
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ current_input_method_id_ = chromeos::GetHardwareKeyboardLayoutName();
+ }
+ // Observe APP_EXITING to stop input method processes gracefully.
+ // Note that even if we fail to stop input method processes from
+ // Chrome in case of a sudden crash, we have a way to do it from an
+ // upstart script. See crosbug.com/6515 and crosbug.com/6995 for
+ // details.
+ notification_registrar_.Add(this, NotificationType::APP_EXITING,
+ NotificationService::AllSources());
}
-}
-InputMethodLibraryImpl::Observer::~Observer() {
-}
+ ~InputMethodLibraryImpl() {
+ }
-void InputMethodLibraryImpl::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
-void InputMethodLibraryImpl::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
-chromeos::InputMethodDescriptors*
-InputMethodLibraryImpl::GetActiveInputMethods() {
- chromeos::InputMethodDescriptors* result = NULL;
- // The connection does not need to be alive, but it does need to be created.
- if (EnsureLoadedAndStarted()) {
- result = chromeos::GetActiveInputMethods(input_method_status_connection_);
+ InputMethodDescriptors* GetActiveInputMethods() {
+ chromeos::InputMethodDescriptors* result = NULL;
+ // The connection does not need to be alive, but it does need to be created.
+ if (EnsureLoadedAndStarted()) {
+ result = chromeos::GetActiveInputMethods(input_method_status_connection_);
+ }
+ if (!result || result->empty()) {
+ result = CreateFallbackInputMethodDescriptors();
+ }
+ return result;
}
- if (!result || result->empty()) {
- result = CreateFallbackInputMethodDescriptors();
+
+ size_t GetNumActiveInputMethods() {
+ scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
+ return input_methods->size();
}
- return result;
-}
-size_t InputMethodLibraryImpl::GetNumActiveInputMethods() {
- scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
- return input_methods->size();
-}
+ InputMethodDescriptors* GetSupportedInputMethods() {
+ InputMethodDescriptors* result = NULL;
+ // The connection does not need to be alive, but it does need to be created.
+ if (EnsureLoadedAndStarted()) {
+ result = chromeos::GetSupportedInputMethods(
+ input_method_status_connection_);
+ }
+ if (!result || result->empty()) {
+ result = CreateFallbackInputMethodDescriptors();
+ }
+ return result;
+ }
-chromeos::InputMethodDescriptors*
-InputMethodLibraryImpl::GetSupportedInputMethods() {
- chromeos::InputMethodDescriptors* result = NULL;
- // The connection does not need to be alive, but it does need to be created.
- if (EnsureLoadedAndStarted()) {
- result = chromeos::GetSupportedInputMethods(
- input_method_status_connection_);
+ void ChangeInputMethod(const std::string& input_method_id) {
+ current_input_method_id_ = input_method_id;
+ if (EnsureLoadedAndStarted()) {
+ if (input_method_id != chromeos::GetHardwareKeyboardLayoutName()) {
+ StartInputMethodProcesses();
+ }
+ chromeos::ChangeInputMethod(
+ input_method_status_connection_, input_method_id.c_str());
+ }
}
- if (!result || result->empty()) {
- result = CreateFallbackInputMethodDescriptors();
+
+ void SetImePropertyActivated(const std::string& key, bool activated) {
+ DCHECK(!key.empty());
+ if (EnsureLoadedAndStarted()) {
+ chromeos::SetImePropertyActivated(
+ input_method_status_connection_, key.c_str(), activated);
+ }
}
- return result;
-}
-void InputMethodLibraryImpl::ChangeInputMethod(
- const std::string& input_method_id) {
- if (EnsureLoadedAndStarted()) {
- chromeos::ChangeInputMethod(
- input_method_status_connection_, input_method_id.c_str());
+ bool InputMethodIsActivated(const std::string& input_method_id) {
+ scoped_ptr<InputMethodDescriptors> active_input_method_descriptors(
+ CrosLibrary::Get()->GetInputMethodLibrary()->GetActiveInputMethods());
+ for (size_t i = 0; i < active_input_method_descriptors->size(); ++i) {
+ if (active_input_method_descriptors->at(i).id == input_method_id) {
+ return true;
+ }
+ }
+ return false;
}
-}
-void InputMethodLibraryImpl::SetImePropertyActivated(const std::string& key,
- bool activated) {
- DCHECK(!key.empty());
- if (EnsureLoadedAndStarted()) {
- chromeos::SetImePropertyActivated(
- input_method_status_connection_, key.c_str(), activated);
+ bool GetImeConfig(const char* section, const char* config_name,
+ ImeConfigValue* out_value) {
+ bool success = false;
+ if (EnsureLoadedAndStarted()) {
+ success = chromeos::GetImeConfig(input_method_status_connection_,
+ section, config_name, out_value);
+ }
+ return success;
}
-}
-bool InputMethodLibraryImpl::InputMethodIsActivated(
- const std::string& input_method_id) {
- scoped_ptr<InputMethodDescriptors> active_input_method_descriptors(
- CrosLibrary::Get()->GetInputMethodLibrary()->GetActiveInputMethods());
- for (size_t i = 0; i < active_input_method_descriptors->size(); ++i) {
- if (active_input_method_descriptors->at(i).id == input_method_id) {
- return true;
+ bool SetImeConfig(const char* section, const char* config_name,
+ const ImeConfigValue& value) {
+ MaybeStartOrStopInputMethodProcesses(section, config_name, value);
+
+ const ConfigKeyType key = std::make_pair(section, config_name);
+ current_config_values_[key] = value;
+ if (ime_connected_) {
+ pending_config_requests_[key] = value;
+ FlushImeConfig();
}
+ return pending_config_requests_.empty();
}
- return false;
-}
-bool InputMethodLibraryImpl::GetImeConfig(
- const char* section, const char* config_name, ImeConfigValue* out_value) {
- bool success = false;
- if (EnsureLoadedAndStarted()) {
- success = chromeos::GetImeConfig(
- input_method_status_connection_, section, config_name, out_value);
+ virtual const InputMethodDescriptor& previous_input_method() const {
+ return previous_input_method_;
+ }
+ virtual const InputMethodDescriptor& current_input_method() const {
+ return current_input_method_;
}
- return success;
-}
-bool InputMethodLibraryImpl::SetImeConfig(
- const char* section, const char* config_name, const ImeConfigValue& value) {
- const ConfigKeyType key = std::make_pair(section, config_name);
- pending_config_requests_.erase(key);
- pending_config_requests_.insert(std::make_pair(key, value));
- current_config_values_[key] = value;
- FlushImeConfig();
- return pending_config_requests_.empty();
-}
+ virtual const ImePropertyList& current_ime_properties() const {
+ return current_ime_properties_;
+ }
-void InputMethodLibraryImpl::FlushImeConfig() {
- bool active_input_methods_are_changed = false;
- if (EnsureLoadedAndStarted()) {
- InputMethodConfigRequests::iterator iter = pending_config_requests_.begin();
- while (iter != pending_config_requests_.end()) {
- const std::string& section = iter->first.first;
- const std::string& config_name = iter->first.second;
- const ImeConfigValue& value = iter->second;
- if (chromeos::SetImeConfig(input_method_status_connection_,
- section.c_str(), config_name.c_str(), value)) {
- // Successfully sent. Remove the command and proceed to the next one.
- pending_config_requests_.erase(iter++);
- // Check if it's a change in active input methods.
- if (config_name == kPreloadEnginesConfigName) {
- active_input_methods_are_changed = true;
+ private:
+ // Starts or stops the input method processes based on the current state.
+ void MaybeStartOrStopInputMethodProcesses(
+ const char* section,
+ const char* config_name,
+ const ImeConfigValue& value) {
+ if (!strcmp(language_prefs::kGeneralSectionName, section) &&
+ !strcmp(language_prefs::kPreloadEnginesConfigName, config_name)) {
+ if (EnsureLoadedAndStarted()) {
+ // If there are no input methods other than one for the hardware
+ // keyboard, we'll stop the input method processes.
+ if (value.type == ImeConfigValue::kValueTypeStringList &&
+ value.string_list_value.size() == 1 &&
+ value.string_list_value[0] ==
+ chromeos::GetHardwareKeyboardLayoutName()) {
+ StopInputMethodProcesses();
+ } else if (!defer_ime_startup_) {
+ StartInputMethodProcesses();
+ }
+ chromeos::SetActiveInputMethods(input_method_status_connection_, value);
+ }
+ }
+ }
+
+ // Flushes the input method config data. The config data is queued up in
+ // |pending_config_requests_| until the config backend (ibus-memconf)
+ // starts. Since there is no good way to get notified when the config
+ // backend starts, we use a timer to periodically attempt to send the
+ // config data to the config backend.
+ void FlushImeConfig() {
+ bool active_input_methods_are_changed = false;
+ bool completed = false;
+ if (EnsureLoadedAndStarted()) {
+ InputMethodConfigRequests::iterator iter =
+ pending_config_requests_.begin();
+ while (iter != pending_config_requests_.end()) {
+ const std::string& section = iter->first.first;
+ const std::string& config_name = iter->first.second;
+ const ImeConfigValue& value = iter->second;
+ if (chromeos::SetImeConfig(input_method_status_connection_,
+ section.c_str(),
+ config_name.c_str(),
+ value)) {
+ // Check if it's a change in active input methods.
+ if (config_name == language_prefs::kPreloadEnginesConfigName) {
+ active_input_methods_are_changed = true;
+ }
+ // Successfully sent. Remove the command and proceed to the next one.
+ pending_config_requests_.erase(iter++);
+ } else {
+ // If SetImeConfig() fails, subsequent calls will likely fail.
+ break;
+ }
+ }
+ if (pending_config_requests_.empty()) {
+ // Calls to ChangeInputMethod() will fail if the input method has not
+ // yet been added to preload_engines. As such, the call is deferred
+ // until after all config values have been sent to the IME process.
+ if (should_change_input_method_) {
+ if (chromeos::ChangeInputMethod(input_method_status_connection_,
+ current_input_method_id_.c_str())) {
+ should_change_input_method_ = false;
+ completed = true;
+ active_input_methods_are_changed = true;
+ }
+ } else {
+ completed = true;
}
- } else {
- LOG(ERROR) << "chromeos::SetImeConfig failed. Will retry later: "
- << section << "/" << config_name;
- ++iter; // Do not remove the command.
}
}
- if (pending_config_requests_.empty()) {
+
+ if (completed) {
timer_.Stop(); // no-op if it's not running.
+ } else {
+ // Flush is not completed. Start a timer if it's not yet running.
+ if (!timer_.IsRunning()) {
+ static const int64 kTimerIntervalInMsec = 100;
+ failure_count_ = 0;
+ timer_.Start(base::TimeDelta::FromMilliseconds(kTimerIntervalInMsec),
+ this, &InputMethodLibraryImpl::FlushImeConfig);
+ } else {
+ // The timer is already running. We'll give up if it reaches the
+ // max retry count.
+ static const int kMaxRetries = 15;
+ ++failure_count_;
+ if (failure_count_ > kMaxRetries) {
+ LOG(ERROR) << "FlushImeConfig: Max retries exceeded. "
+ << "current_input_method_id: " << current_input_method_id_
+ << " pending_config_requests.size: "
+ << pending_config_requests_.size();
+ timer_.Stop();
+ }
+ }
}
- } else {
- if (!timer_.IsRunning()) {
- static const int64 kTimerIntervalInSec = 1;
- timer_.Start(base::TimeDelta::FromSeconds(kTimerIntervalInSec), this,
- &InputMethodLibraryImpl::FlushImeConfig);
+ if (active_input_methods_are_changed) {
+ FOR_EACH_OBSERVER(Observer, observers_, ActiveInputMethodsChanged(this));
}
}
- if (active_input_methods_are_changed) {
- FOR_EACH_OBSERVER(Observer, observers_, ActiveInputMethodsChanged(this));
+
+ static void InputMethodChangedHandler(
+ void* object,
+ const chromeos::InputMethodDescriptor& current_input_method) {
+ // The handler is called when the input method method change is
+ // notified via a DBus connection. Since the DBus notificatiosn are
+ // handled in the UI thread, we can assume that this functionalways
+ // runs on the UI thread, but just in case.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ LOG(ERROR) << "Not on UI thread";
+ return;
+ }
+
+ InputMethodLibraryImpl* input_method_library =
+ static_cast<InputMethodLibraryImpl*>(object);
+ input_method_library->ChangeCurrentInputMethod(current_input_method);
}
-}
-// static
-void InputMethodLibraryImpl::InputMethodChangedHandler(
- void* object, const chromeos::InputMethodDescriptor& current_input_method) {
- InputMethodLibraryImpl* input_method_library =
- static_cast<InputMethodLibraryImpl*>(object);
- input_method_library->UpdateCurrentInputMethod(current_input_method);
-}
+ static void RegisterPropertiesHandler(
+ void* object, const ImePropertyList& prop_list) {
+ // See comments in InputMethodChangedHandler.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ LOG(ERROR) << "Not on UI thread";
+ return;
+ }
-// static
-void InputMethodLibraryImpl::RegisterPropertiesHandler(
- void* object, const ImePropertyList& prop_list) {
- InputMethodLibraryImpl* input_method_library =
- static_cast<InputMethodLibraryImpl*>(object);
- input_method_library->RegisterProperties(prop_list);
-}
+ InputMethodLibraryImpl* input_method_library =
+ static_cast<InputMethodLibraryImpl*>(object);
+ input_method_library->RegisterProperties(prop_list);
+ }
-// static
-void InputMethodLibraryImpl::UpdatePropertyHandler(
- void* object, const ImePropertyList& prop_list) {
- InputMethodLibraryImpl* input_method_library =
- static_cast<InputMethodLibraryImpl*>(object);
- input_method_library->UpdateProperty(prop_list);
-}
+ static void UpdatePropertyHandler(
+ void* object, const ImePropertyList& prop_list) {
+ // See comments in InputMethodChangedHandler.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ LOG(ERROR) << "Not on UI thread";
+ return;
+ }
-// static
-void InputMethodLibraryImpl::ConnectionChangeHandler(void* object,
- bool connected) {
- InputMethodLibraryImpl* input_method_library =
- static_cast<InputMethodLibraryImpl*>(object);
- if (connected) {
- input_method_library->pending_config_requests_.insert(
- input_method_library->current_config_values_.begin(),
- input_method_library->current_config_values_.end());
- input_method_library->FlushImeConfig();
+ InputMethodLibraryImpl* input_method_library =
+ static_cast<InputMethodLibraryImpl*>(object);
+ input_method_library->UpdateProperty(prop_list);
}
-}
-bool InputMethodLibraryImpl::EnsureStarted() {
- if (!input_method_status_connection_) {
- input_method_status_connection_ = chromeos::MonitorInputMethodStatus(
- this,
- &InputMethodChangedHandler,
- &RegisterPropertiesHandler,
- &UpdatePropertyHandler,
- &ConnectionChangeHandler);
+ static void ConnectionChangeHandler(void* object, bool connected) {
+ // See comments in InputMethodChangedHandler.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ LOG(ERROR) << "Not on UI thread";
+ return;
+ }
+
+ InputMethodLibraryImpl* input_method_library =
+ static_cast<InputMethodLibraryImpl*>(object);
+ input_method_library->ime_connected_ = connected;
+ if (connected) {
+ input_method_library->pending_config_requests_.clear();
+ input_method_library->pending_config_requests_.insert(
+ input_method_library->current_config_values_.begin(),
+ input_method_library->current_config_values_.end());
+ input_method_library->should_change_input_method_ = true;
+ input_method_library->FlushImeConfig();
+ } else {
+ // Stop attempting to resend config data, since it will continue to fail.
+ input_method_library->timer_.Stop(); // no-op if it's not running.
+ }
}
- return true;
-}
-bool InputMethodLibraryImpl::EnsureLoadedAndStarted() {
- return CrosLibrary::Get()->EnsureLoaded() &&
- EnsureStarted();
-}
+ bool EnsureStarted() {
+ if (!input_method_status_connection_) {
+ input_method_status_connection_ = chromeos::MonitorInputMethodStatus(
+ this,
+ &InputMethodChangedHandler,
+ &RegisterPropertiesHandler,
+ &UpdatePropertyHandler,
+ &ConnectionChangeHandler);
+ }
+ return true;
+ }
-void InputMethodLibraryImpl::UpdateCurrentInputMethod(
- const chromeos::InputMethodDescriptor& new_input_method) {
- // Make sure we run on UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- DLOG(INFO) << "UpdateCurrentInputMethod (Background thread)";
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- // NewRunnableMethod() copies |new_input_method| by value.
- NewRunnableMethod(
- this, &InputMethodLibraryImpl::UpdateCurrentInputMethod,
- new_input_method));
- return;
- }
-
- DLOG(INFO) << "UpdateCurrentInputMethod (UI thread)";
- // Change the keyboard layout to a preferred layout for the input method.
- CrosLibrary::Get()->GetKeyboardLibrary()->SetCurrentKeyboardLayoutByName(
- new_input_method.keyboard_layout);
-
- if (current_input_method_.id != new_input_method.id) {
- previous_input_method_ = current_input_method_;
- current_input_method_ = new_input_method;
- }
- FOR_EACH_OBSERVER(Observer, observers_, InputMethodChanged(this));
-}
+ bool EnsureLoadedAndStarted() {
+ return CrosLibrary::Get()->EnsureLoaded() &&
+ EnsureStarted();
+ }
+
+ void ChangeCurrentInputMethod(const InputMethodDescriptor& new_input_method) {
+ // Change the keyboard layout to a preferred layout for the input method.
+ CrosLibrary::Get()->GetKeyboardLibrary()->SetCurrentKeyboardLayoutByName(
+ new_input_method.keyboard_layout);
-void InputMethodLibraryImpl::RegisterProperties(
- const ImePropertyList& prop_list) {
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &InputMethodLibraryImpl::RegisterProperties, prop_list));
- return;
+ if (current_input_method_.id != new_input_method.id) {
+ previous_input_method_ = current_input_method_;
+ current_input_method_ = new_input_method;
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, InputMethodChanged(this));
}
- // |prop_list| might be empty. This means "clear all properties."
- current_ime_properties_ = prop_list;
- FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
-}
+ 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() {
+ should_launch_ime_ = true;
+ MaybeLaunchInputMethodProcesses();
+ }
+
+ void UpdateProperty(const ImePropertyList& prop_list) {
+ 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
+ // line. On success, returns true and stores the process ID in
+ // |process_id|. Otherwise, returns false, and the contents of
+ // |process_id| is untouched. OnImeShutdown will be called when the
+ // process terminates.
+ bool LaunchInputMethodProcess(const std::string& command_line,
+ int* process_id) {
+ GError *error = NULL;
+ gchar **argv = NULL;
+ gint argc = NULL;
+ // TODO(zork): export "LD_PRELOAD=/usr/lib/libcrash.so"
+ if (!g_shell_parse_argv(command_line.c_str(), &argc, &argv, &error)) {
+ LOG(ERROR) << "Could not parse command: " << error->message;
+ g_error_free(error);
+ return false;
+ }
+
+ int pid = 0;
+ const GSpawnFlags kFlags = G_SPAWN_DO_NOT_REAP_CHILD;
+ const gboolean result = g_spawn_async(NULL, argv, NULL,
+ kFlags, NULL, NULL,
+ &pid, &error);
+ g_strfreev(argv);
+ if (!result) {
+ LOG(ERROR) << "Could not launch: " << command_line << ": "
+ << error->message;
+ g_error_free(error);
+ return false;
+ }
+ g_child_watch_add(pid, reinterpret_cast<GChildWatchFunc>(OnImeShutdown),
+ this);
+
+ *process_id = pid;
+ return true;
+ }
+
+ // Launches input method processes if these are not yet running.
+ void MaybeLaunchInputMethodProcesses() {
+ if (!should_launch_ime_) {
+ return;
+ }
+
+ if (ibus_daemon_process_id_ == 0) {
+ // TODO(zork): Send output to /var/log/ibus.log
+ const std::string ibus_daemon_command_line =
+ StringPrintf("%s --panel=disable --cache=none --restart --replace",
+ kIBusDaemonPath);
+ if (!LaunchInputMethodProcess(ibus_daemon_command_line,
+ &ibus_daemon_process_id_)) {
+ // On failure, we should not attempt to launch candidate_window.
+ return;
+ }
+ }
+
+ if (candidate_window_process_id_ == 0) {
+ // Pass the UI language info to candidate_window via --lang flag.
+ const std::string candidate_window_command_line =
+ StringPrintf("%s --lang=%s", kCandidateWindowPath,
+ g_browser_process->GetApplicationLocale().c_str());
+ if (!LaunchInputMethodProcess(candidate_window_command_line,
+ &candidate_window_process_id_)) {
+ // Return here just in case we add more code below.
+ return;
+ }
+ }
+ }
+
+ static void OnImeShutdown(int pid,
+ int status,
+ InputMethodLibraryImpl* library) {
+ g_spawn_close_pid(pid);
+ if (library->ibus_daemon_process_id_ == pid) {
+ library->ibus_daemon_process_id_ = 0;
+ } else if (library->candidate_window_process_id_ == pid) {
+ library->candidate_window_process_id_ = 0;
+ }
+
+ // Restart input method processes if needed.
+ library->MaybeLaunchInputMethodProcesses();
+ }
+
+ void StopInputMethodProcesses() {
+ should_launch_ime_ = false;
+ if (ibus_daemon_process_id_) {
+ const std::string xkb_engine_name =
+ chromeos::GetHardwareKeyboardLayoutName();
+ // We should not use chromeos::ChangeInputMethod() here since without the
+ // ibus-daemon process, ChangeCurrentInputMethod() callback function which
+ // actually changes the XKB layout will not be called.
+ CrosLibrary::Get()->GetKeyboardLibrary()->SetCurrentKeyboardLayoutByName(
+ chromeos::input_method::GetKeyboardLayoutName(xkb_engine_name));
+ kill(ibus_daemon_process_id_, SIGTERM);
+ ibus_daemon_process_id_ = 0;
+ }
+ if (candidate_window_process_id_) {
+ kill(candidate_window_process_id_, SIGTERM);
+ candidate_window_process_id_ = 0;
+ }
+ }
+
+ void SetDeferImeStartup(bool defer) {
+ LOG(INFO) << "Setting DeferImeStartup to " << defer;
+ defer_ime_startup_ = defer;
+ }
+
+ // NotificationObserver implementation:
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ // Stop the input processes on browser shutdown.
+ if (type.value == NotificationType::APP_EXITING) {
+ StopInputMethodProcesses();
+ }
+ }
+
+ // A reference to the language api, to allow callbacks when the input method
+ // status changes.
+ InputMethodStatusConnection* input_method_status_connection_;
+ ObserverList<Observer> observers_;
+
+ // The input method which was/is selected.
+ InputMethodDescriptor previous_input_method_;
+ InputMethodDescriptor current_input_method_;
+
+ // The input method properties which the current input method uses. The list
+ // might be empty when no input method is used.
+ ImePropertyList current_ime_properties_;
+
+ typedef std::pair<std::string, std::string> ConfigKeyType;
+ typedef std::map<ConfigKeyType, ImeConfigValue> InputMethodConfigRequests;
+ // SetImeConfig requests that are not yet completed.
+ // Use a map to queue config requests, so we only send the last request for
+ // the same config key (i.e. we'll discard ealier requests for the same
+ // config key). As we discard old requests for the same config key, the order
+ // of requests doesn't matter, so it's safe to use a map.
+ InputMethodConfigRequests pending_config_requests_;
+
+ // Values that have been set via SetImeConfig(). We keep a copy available to
+ // resend if the ime restarts and loses its state.
+ InputMethodConfigRequests current_config_values_;
+
+ // A timer for retrying to send |pendning_config_commands_| to the input
+ // method config daemon.
+ base::OneShotTimer<InputMethodLibraryImpl> timer_;
+
+ // This is used to register this object to APP_EXITING notification.
+ NotificationRegistrar notification_registrar_;
+
+ // True if we should launch the input method processes.
+ bool should_launch_ime_;
+ // True if the connection to the IBus daemon is alive.
+ bool ime_connected_;
+ // If true, we'll defer the startup until a non-default method is
+ // activated.
+ bool defer_ime_startup_;
+ // The ID of the current input method (ex. "mozc").
+ std::string current_input_method_id_;
+ // True if we should change the input method once the queue of the
+ // pending config requests becomes empty.
+ bool should_change_input_method_;
+
+ // The process id of the IBus daemon. 0 if it's not running. The process
+ // ID 0 is not used in Linux, hence it's safe to use 0 for this purpose.
+ int ibus_daemon_process_id_;
+ // The process id of the candidate window. 0 if it's not running.
+ int candidate_window_process_id_;
+ // The failure count of config flush attempts.
+ int failure_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodLibraryImpl);
+};
+
+InputMethodLibraryImpl::Observer::~Observer() {}
+
+class InputMethodLibraryStubImpl : public InputMethodLibrary {
+ public:
+ InputMethodLibraryStubImpl()
+ : previous_input_method_("", "", "", ""),
+ current_input_method_("", "", "", "") {
+ }
+
+ ~InputMethodLibraryStubImpl() {}
+ void AddObserver(Observer* observer) {}
+ void RemoveObserver(Observer* observer) {}
+
+ InputMethodDescriptors* GetActiveInputMethods() {
+ return CreateRealisticInputMethodDescriptors();
+ }
+
+
+ size_t GetNumActiveInputMethods() {
+ scoped_ptr<InputMethodDescriptors> descriptors(
+ CreateRealisticInputMethodDescriptors());
+ return descriptors->size();
+ }
+
+ InputMethodDescriptors* GetSupportedInputMethods() {
+ return CreateRealisticInputMethodDescriptors();
+ }
+
+ void ChangeInputMethod(const std::string& input_method_id) {}
+ void SetImePropertyActivated(const std::string& key, bool activated) {}
-void InputMethodLibraryImpl::UpdateProperty(const ImePropertyList& prop_list) {
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &InputMethodLibraryImpl::UpdateProperty, prop_list));
- return;
+ bool InputMethodIsActivated(const std::string& input_method_id) {
+ return true;
}
- for (size_t i = 0; i < prop_list.size(); ++i) {
- FindAndUpdateProperty(prop_list[i], &current_ime_properties_);
+ bool GetImeConfig(const char* section,
+ const char* config_name,
+ ImeConfigValue* out_value) {
+ return false;
}
- FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
+
+ bool SetImeConfig(const char* section,
+ const char* config_name,
+ const ImeConfigValue& value) {
+ return false;
+ }
+
+ virtual const InputMethodDescriptor& previous_input_method() const {
+ return previous_input_method_;
+ }
+
+ virtual const InputMethodDescriptor& current_input_method() const {
+ return current_input_method_;
+ }
+
+ virtual const ImePropertyList& current_ime_properties() const {
+ return current_ime_properties_;
+ }
+
+ virtual void StartInputMethodProcesses() {}
+ virtual void StopInputMethodProcesses() {}
+ virtual void SetDeferImeStartup(bool defer) {}
+
+ private:
+ // Creates realistic input method descriptors that can be used for
+ // testing Chrome OS version of chrome on regular Linux desktops.
+ InputMethodDescriptors* CreateRealisticInputMethodDescriptors() {
+ InputMethodDescriptors* descriptions = new InputMethodDescriptors;
+ // The list is created from output of gen_engines.py in libcros.
+ descriptions->push_back(InputMethodDescriptor(
+ "chewing", "Chewing", "us", "zh_TW"));
+ descriptions->push_back(InputMethodDescriptor(
+ "hangul", "Korean", "us", "ko"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:fa:isiri", "isiri (m17n)", "us", "fa"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:he:kbd", "kbd (m17n)", "us", "he"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:ar:kbd", "kbd (m17n)", "us", "ar"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:hi:itrans", "itrans (m17n)", "us", "hi"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:vi:vni", "vni (m17n)", "us", "vi"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:vi:viqr", "viqr (m17n)", "us", "vi"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:vi:tcvn", "tcvn (m17n)", "us", "vi"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:vi:telex", "telex (m17n)", "us", "vi"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:zh:cangjie", "cangjie (m17n)", "us", "zh"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:zh:quick", "quick (m17n)", "us", "zh"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:th:tis820", "tis820 (m17n)", "us", "th"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:th:kesmanee", "kesmanee (m17n)", "us", "th"));
+ descriptions->push_back(InputMethodDescriptor(
+ "m17n:th:pattachote", "pattachote (m17n)", "us", "th"));
+ descriptions->push_back(InputMethodDescriptor(
+ "mozc-jp", "Mozc (Japanese keyboard layout)", "jp", "ja"));
+ descriptions->push_back(InputMethodDescriptor(
+ "mozc", "Mozc (US keyboard layout)", "us", "ja"));
+ descriptions->push_back(InputMethodDescriptor(
+ "mozc-dv", "Mozc (US Dvorak keyboard layout)", "us(dvorak)", "ja"));
+ descriptions->push_back(InputMethodDescriptor(
+ "pinyin", "Pinyin", "us", "zh"));
+ descriptions->push_back(InputMethodDescriptor(
+ "bopomofo", "Bopomofo", "us", "zh"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:us::eng", "USA", "us", "eng"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:us:dvorak:eng", "USA - Dvorak", "us(dvorak)", "eng"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:be::ger", "Belgium", "be", "ger"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:be::nld", "Belgium", "be", "nld"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:be::fra", "Belgium", "be", "fra"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:br::por", "Brazil", "br", "por"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:bg::bul", "Bulgaria", "bg", "bul"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ca::fra", "Canada", "ca", "fra"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ca:eng:eng", "Canada - English", "ca(eng)", "eng"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:hr::scr", "Croatia", "hr", "scr"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:cz::cze", "Czechia", "cz", "cze"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:dk::dan", "Denmark", "dk", "dan"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:nl::nld", "Netherlands", "nl", "nld"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ee::est", "Estonia", "ee", "est"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:fi::fin", "Finland", "fi", "fin"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:fr::fra", "France", "fr", "fra"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:de::ger", "Germany", "de", "ger"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:gr::gre", "Greece", "gr", "gre"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:hu::hun", "Hungary", "hu", "hun"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:it::ita", "Italy", "it", "ita"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:jp::jpn", "Japan", "jp", "jpn"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:lt::lit", "Lithuania", "lt", "lit"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:lv::lav", "Latvia", "lv", "lav"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:no::nor", "Norway", "no", "nor"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:pl::pol", "Poland", "pl", "pol"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:pt::por", "Portugal", "pt", "por"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ro::rum", "Romania", "ro", "rum"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ru::rus", "Russia", "ru", "rus"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:rs::srp", "Serbia", "rs", "srp"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:si::slv", "Slovenia", "si", "slv"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:sk::slo", "Slovakia", "sk", "slo"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:es::spa", "Spain", "es", "spa"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:es:cat:cat",
+ "Spain - Catalan variant with middle-dot L", "es(cat)", "cat"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:se::swe", "Sweden", "se", "swe"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ch::ger", "Switzerland", "ch", "ger"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ch:fr:fra", "Switzerland - French", "ch(fr)", "fra"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:tr::tur", "Turkey", "tr", "tur"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:ua::ukr", "Ukraine", "ua", "ukr"));
+ descriptions->push_back(InputMethodDescriptor(
+ "xkb:gb:extd:eng", "United Kingdom - Extended - Winkeys", "gb(extd)",
+ "eng"));
+ return descriptions;
+ }
+
+ InputMethodDescriptor previous_input_method_;
+ InputMethodDescriptor current_input_method_;
+ ImePropertyList current_ime_properties_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodLibraryStubImpl);
+};
+
+// static
+InputMethodLibrary* InputMethodLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new InputMethodLibraryStubImpl();
+ else
+ return new InputMethodLibraryImpl();
}
} // namespace chromeos
+
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::InputMethodLibraryImpl);
diff --git a/chrome/browser/chromeos/cros/input_method_library.h b/chrome/browser/chromeos/cros/input_method_library.h
index e92b311..2ae4b85 100644
--- a/chrome/browser/chromeos/cros/input_method_library.h
+++ b/chrome/browser/chromeos/cros/input_method_library.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_INPUT_METHOD_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_INPUT_METHOD_LIBRARY_H_
+#pragma once
-#include <map>
#include <string>
#include <utility>
@@ -18,18 +18,27 @@ namespace chromeos {
// This class handles the interaction with the ChromeOS language library APIs.
// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: InputMethodLibrary::Get()
+// library class like this:
+// chromeos::CrosLibrary::Get()->GetInputMethodLibrary()
class InputMethodLibrary {
public:
class Observer {
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;
+
+ // Called when the active input methods are changed.
virtual void ActiveInputMethodsChanged(InputMethodLibrary* obj) = 0;
};
virtual ~InputMethodLibrary() {}
+ // Adds an observer to receive notifications of input method related
+ // changes as desribed in the Observer class above.
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
@@ -76,124 +85,31 @@ class InputMethodLibrary {
// the request and returns false.
// You can specify |section| and |config_name| arguments in the same way
// as GetImeConfig() above.
+ // Notice: This function might call the Observer::ActiveInputMethodsChanged()
+ // callback function immediately, before returning from the SetImeConfig
+ // function. See also http://crosbug.com/5217.
virtual bool SetImeConfig(const char* section,
const char* config_name,
const ImeConfigValue& value) = 0;
+ // Sets the IME state to enabled, and launches its processes if needed.
+ virtual void StartInputMethodProcesses() = 0;
+
+ // Disables the IME, and kills the processes if they are running.
+ virtual void StopInputMethodProcesses() = 0;
+
+ // Controls whether the IME process is started when preload engines are
+ // specificed, or defered until a non-default method is activated.
+ virtual void SetDeferImeStartup(bool defer) = 0;
+
virtual const InputMethodDescriptor& previous_input_method() const = 0;
virtual const InputMethodDescriptor& current_input_method() const = 0;
virtual const ImePropertyList& current_ime_properties() const = 0;
-};
-// This class handles the interaction with the ChromeOS language library APIs.
-// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: InputMethodLibrary::Get()
-class InputMethodLibraryImpl : public InputMethodLibrary {
- public:
- InputMethodLibraryImpl();
- virtual ~InputMethodLibraryImpl();
-
- // InputMethodLibrary overrides.
- virtual void AddObserver(Observer* observer);
- virtual void RemoveObserver(Observer* observer);
- virtual InputMethodDescriptors* GetActiveInputMethods();
- virtual size_t GetNumActiveInputMethods();
- virtual InputMethodDescriptors* GetSupportedInputMethods();
- virtual void ChangeInputMethod(const std::string& input_method_id);
- virtual void SetImePropertyActivated(const std::string& key,
- bool activated);
- virtual bool InputMethodIsActivated(const std::string& input_method_id);
- virtual bool GetImeConfig(
- const char* section, const char* config_name, ImeConfigValue* out_value);
- virtual bool SetImeConfig(const char* section,
- const char* config_name,
- const ImeConfigValue& value);
-
- virtual const InputMethodDescriptor& previous_input_method() const {
- return previous_input_method_;
- }
- virtual const InputMethodDescriptor& current_input_method() const {
- return current_input_method_;
- }
-
- virtual const ImePropertyList& current_ime_properties() const {
- return current_ime_properties_;
- }
-
- private:
- // This method is called when there's a change in input method status.
- static void InputMethodChangedHandler(
- void* object, const InputMethodDescriptor& current_input_method);
-
- // This method is called when an input method sends "RegisterProperties"
- // signal.
- static void RegisterPropertiesHandler(
- void* object, const ImePropertyList& prop_list);
-
- // This method is called when an input method sends "UpdateProperty" signal.
- static void UpdatePropertyHandler(
- void* object, const ImePropertyList& prop_list);
-
- // This method is called when bus connects or disconnects.
- static void ConnectionChangeHandler(void* object, bool connected);
-
- // Ensures that the monitoring of input method changes is started. Starts
- // the monitoring if necessary. Returns true if the monitoring has been
- // successfully started.
- bool EnsureStarted();
-
- // Ensures that the cros library is loaded and the the monitoring is
- // started. Loads the cros library and starts the monitoring if
- // necessary. Returns true if the two conditions are both met.
- bool EnsureLoadedAndStarted();
-
- // Called by the handler to update the input method status.
- // This will notify all the Observers.
- void UpdateCurrentInputMethod(
- const InputMethodDescriptor& current_input_method);
-
- // Called by the handler to register input method properties.
- void RegisterProperties(const ImePropertyList& prop_list);
-
- // Called by the handler to update input method properties.
- void UpdateProperty(const ImePropertyList& prop_list);
-
- // Tries to send all pending SetImeConfig requests to the input method config
- // daemon.
- void FlushImeConfig();
-
- // A reference to the language api, to allow callbacks when the input method
- // status changes.
- InputMethodStatusConnection* input_method_status_connection_;
- ObserverList<Observer> observers_;
-
- // The input method which was/is selected.
- InputMethodDescriptor previous_input_method_;
- InputMethodDescriptor current_input_method_;
-
- // The input method properties which the current input method uses. The list
- // might be empty when no input method is used.
- ImePropertyList current_ime_properties_;
-
- typedef std::pair<std::string, std::string> ConfigKeyType;
- typedef std::map<ConfigKeyType, ImeConfigValue> InputMethodConfigRequests;
- // SetImeConfig requests that are not yet completed.
- // Use a map to queue config requests, so we only send the last request for
- // the same config key (i.e. we'll discard ealier requests for the same
- // config key). As we discard old requests for the same config key, the order
- // of requests doesn't matter, so it's safe to use a map.
- InputMethodConfigRequests pending_config_requests_;
-
- // Values that have been set via SetImeConfig(). We keep a copy available to
- // resend if the ime restarts and loses its state.
- InputMethodConfigRequests current_config_values_;
-
- // A timer for retrying to send |pendning_config_commands_| to the input
- // method config daemon.
- base::OneShotTimer<InputMethodLibraryImpl> timer_;
-
- DISALLOW_COPY_AND_ASSIGN(InputMethodLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static InputMethodLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/keyboard_library.cc b/chrome/browser/chromeos/cros/keyboard_library.cc
index ff7a3b1..c7728c1 100644
--- a/chrome/browser/chromeos/cros/keyboard_library.cc
+++ b/chrome/browser/chromeos/cros/keyboard_library.cc
@@ -9,34 +9,140 @@
namespace chromeos {
-std::string KeyboardLibraryImpl::GetCurrentKeyboardLayoutName() const {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- return chromeos::GetCurrentKeyboardLayoutName();
+class KeyboardLibraryImpl : public KeyboardLibrary {
+ public:
+ KeyboardLibraryImpl() {}
+ virtual ~KeyboardLibraryImpl() {}
+
+ std::string GetHardwareKeyboardLayoutName() const {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::GetHardwareKeyboardLayoutName();
+ }
+ return "";
}
- return "";
-}
-bool KeyboardLibraryImpl::SetCurrentKeyboardLayoutByName(
- const std::string& layout_name) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- return chromeos::SetCurrentKeyboardLayoutByName(layout_name);
+ std::string GetCurrentKeyboardLayoutName() const {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::GetCurrentKeyboardLayoutName();
+ }
+ return "";
}
- return false;
-}
-bool KeyboardLibraryImpl::GetKeyboardLayoutPerWindow(
- bool* is_per_window) const {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- return chromeos::GetKeyboardLayoutPerWindow(is_per_window);
+ bool SetCurrentKeyboardLayoutByName(const std::string& layout_name) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::SetCurrentKeyboardLayoutByName(layout_name);
+ }
+ return false;
}
- return false;
-}
-bool KeyboardLibraryImpl::SetKeyboardLayoutPerWindow(bool is_per_window) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- return chromeos::SetKeyboardLayoutPerWindow(is_per_window);
+ bool RemapModifierKeys(const ModifierMap& modifier_map) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::RemapModifierKeys(modifier_map);
+ }
+ return false;
+ }
+
+ bool GetKeyboardLayoutPerWindow(bool* is_per_window) const {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::GetKeyboardLayoutPerWindow(is_per_window);
+ }
+ return false;
+ }
+
+ bool SetKeyboardLayoutPerWindow(bool is_per_window) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::SetKeyboardLayoutPerWindow(is_per_window);
+ }
+ return false;
+ }
+
+ bool GetAutoRepeatEnabled(bool* enabled) const {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::GetAutoRepeatEnabled(enabled);
+ }
+ return false;
+ }
+
+ bool SetAutoRepeatEnabled(bool enabled) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::SetAutoRepeatEnabled(enabled);
+ }
+ return false;
+ }
+
+ bool GetAutoRepeatRate(AutoRepeatRate* out_rate) const {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::GetAutoRepeatRate(out_rate);
+ }
+ return false;
+ }
+
+ bool SetAutoRepeatRate(const AutoRepeatRate& rate) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ return chromeos::SetAutoRepeatRate(rate);
+ }
+ return false;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeyboardLibraryImpl);
+};
+
+class KeyboardLibraryStubImpl : public KeyboardLibrary {
+ public:
+ KeyboardLibraryStubImpl() {}
+ virtual ~KeyboardLibraryStubImpl() {}
+
+ std::string GetHardwareKeyboardLayoutName() const {
+ return "xkb:us::eng";
}
- return false;
+
+ std::string GetCurrentKeyboardLayoutName() const {
+ return "";
+ }
+
+ bool SetCurrentKeyboardLayoutByName(const std::string& layout_name) {
+ return false;
+ }
+
+ bool RemapModifierKeys(const ModifierMap& modifier_map) {
+ return false;
+ }
+
+ bool GetKeyboardLayoutPerWindow(bool* is_per_window) const {
+ return false;
+ }
+
+ bool SetKeyboardLayoutPerWindow(bool is_per_window) {
+ return false;
+ }
+
+ bool GetAutoRepeatEnabled(bool* enabled) const {
+ return false;
+ }
+
+ bool SetAutoRepeatEnabled(bool enabled) {
+ return false;
+ }
+
+ bool GetAutoRepeatRate(AutoRepeatRate* out_rate) const {
+ return false;
+ }
+
+ bool SetAutoRepeatRate(const AutoRepeatRate& rate) {
+ return false;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(KeyboardLibraryStubImpl);
+};
+
+// static
+KeyboardLibrary* KeyboardLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new KeyboardLibraryStubImpl();
+ else
+ return new KeyboardLibraryImpl();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/keyboard_library.h b/chrome/browser/chromeos/cros/keyboard_library.h
index 17e1b42..b5f0deb 100644
--- a/chrome/browser/chromeos/cros/keyboard_library.h
+++ b/chrome/browser/chromeos/cros/keyboard_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_KEYBOARD_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_KEYBOARD_LIBRARY_H_
+#pragma once
#include "cros/chromeos_keyboard.h"
@@ -18,6 +19,9 @@ class KeyboardLibrary {
public:
virtual ~KeyboardLibrary() {}
+ // Returns the hardware layout name like "xkb:us::eng". On error, returns "".
+ virtual std::string GetHardwareKeyboardLayoutName() const = 0;
+
// Returns the current layout name like "us". On error, returns "".
virtual std::string GetCurrentKeyboardLayoutName() const = 0;
@@ -26,6 +30,9 @@ class KeyboardLibrary {
virtual bool SetCurrentKeyboardLayoutByName(
const std::string& layout_name) = 0;
+ // Remaps modifier keys. Returns true on success.
+ virtual bool RemapModifierKeys(const ModifierMap& modifier_map) = 0;
+
// Gets whehter we have separate keyboard layout per window, or not. The
// result is stored in |is_per_window|. Returns true on success.
virtual bool GetKeyboardLayoutPerWindow(bool* is_per_window) const = 0;
@@ -34,21 +41,25 @@ class KeyboardLibrary {
// is given, the same keyboard layout will be shared for all applications.
// Returns true on success.
virtual bool SetKeyboardLayoutPerWindow(bool is_per_window) = 0;
-};
-class KeyboardLibraryImpl : public KeyboardLibrary {
- public:
- KeyboardLibraryImpl() {}
- virtual ~KeyboardLibraryImpl() {}
+ // Gets the current auto-repeat mode of the keyboard. The result is stored in
+ // |enabled|. Returns true on success.
+ virtual bool GetAutoRepeatEnabled(bool* enabled) const = 0;
+
+ // Turns on and off the auto-repeat of the keyboard. Returns true on success.
+ virtual bool SetAutoRepeatEnabled(bool enabled) = 0;
+
+ // Gets the current auto-repeat rate of the keyboard. The result is stored in
+ // |out_rate|. Returns true on success.
+ virtual bool GetAutoRepeatRate(AutoRepeatRate* out_rate) const = 0;
- // KeyboardLibrary overrides.
- virtual std::string GetCurrentKeyboardLayoutName() const;
- virtual bool SetCurrentKeyboardLayoutByName(const std::string& layout_name);
- virtual bool GetKeyboardLayoutPerWindow(bool* is_per_window) const;
- virtual bool SetKeyboardLayoutPerWindow(bool is_per_window);
+ // Sets the auto-repeat rate of the keyboard, initial delay in ms, and repeat
+ // interval in ms. Returns true on success.
+ virtual bool SetAutoRepeatRate(const AutoRepeatRate& rate) = 0;
- private:
- DISALLOW_COPY_AND_ASSIGN(KeyboardLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static KeyboardLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/login_library.cc b/chrome/browser/chromeos/cros/login_library.cc
index efd8536..4b57d44 100644
--- a/chrome/browser/chromeos/cros/login_library.cc
+++ b/chrome/browser/chromeos/cros/login_library.cc
@@ -10,19 +10,227 @@
namespace chromeos {
-bool LoginLibraryImpl::EmitLoginPromptReady() {
- return chromeos::EmitLoginPromptReady();
-}
+class LoginLibraryImpl : public LoginLibrary {
+ public:
+ LoginLibraryImpl()
+ : set_owner_key_callback_(NULL),
+ whitelist_op_callback_(NULL),
+ property_op_callback_(NULL) {
+ if (CrosLibrary::Get()->EnsureLoaded())
+ Init();
+ }
+ virtual ~LoginLibraryImpl() {
+ if (session_connection_) {
+ chromeos::DisconnectSession(session_connection_);
+ }
+ }
-bool LoginLibraryImpl::StartSession(const std::string& user_email,
- const std::string& unique_id /* unused */) {
- // only pass unique_id through once we use it for something.
- return chromeos::StartSession(user_email.c_str(), "");
-}
+ bool EmitLoginPromptReady() {
+ return chromeos::EmitLoginPromptReady();
+ }
+
+ bool CheckWhitelist(const std::string& email,
+ std::vector<uint8>* OUT_signature) {
+ return chromeos::CheckWhitelist(email.c_str(), OUT_signature);
+ }
+
+ bool RetrieveProperty(const std::string& name,
+ std::string* OUT_value,
+ std::vector<uint8>* OUT_signature) {
+ return chromeos::RetrieveProperty(name.c_str(), OUT_value, OUT_signature);
+ }
+
+ bool SetOwnerKeyAsync(const std::vector<uint8>& public_key_der,
+ Delegate* callback) {
+ DCHECK(callback) << "must provide a callback to SetOwnerKeyAsync()";
+ if (set_owner_key_callback_)
+ return false;
+ set_owner_key_callback_ = callback;
+ return chromeos::SetOwnerKey(public_key_der);
+ }
+
+ bool StorePropertyAsync(const std::string& name,
+ const std::string& value,
+ const std::vector<uint8>& signature,
+ Delegate* callback) {
+ DCHECK(callback) << "must provide a callback to StorePropertyAsync()";
+ if (property_op_callback_)
+ return false;
+ property_op_callback_ = callback;
+ return chromeos::StoreProperty(name.c_str(), value.c_str(), signature);
+ }
+
+ bool UnwhitelistAsync(const std::string& email,
+ const std::vector<uint8>& signature,
+ Delegate* callback) {
+ DCHECK(callback) << "must provide a callback to UnwhitelistAsync()";
+ if (whitelist_op_callback_)
+ return false;
+ whitelist_op_callback_ = callback;
+ return chromeos::Unwhitelist(email.c_str(), signature);
+ }
+
+ bool WhitelistAsync(const std::string& email,
+ const std::vector<uint8>& signature,
+ Delegate* callback) {
+ DCHECK(callback) << "must provide a callback to WhitelistAsync()";
+ if (whitelist_op_callback_)
+ return false;
+ whitelist_op_callback_ = callback;
+ return chromeos::Whitelist(email.c_str(), signature);
+ }
+
+ bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
+ return chromeos::EnumerateWhitelisted(whitelisted);
+ }
+
+ bool StartSession(const std::string& user_email,
+ const std::string& unique_id /* unused */) {
+ // only pass unique_id through once we use it for something.
+ return chromeos::StartSession(user_email.c_str(), "");
+ }
+
+ bool StopSession(const std::string& unique_id /* unused */) {
+ // only pass unique_id through once we use it for something.
+ return chromeos::StopSession("");
+ }
+
+ bool RestartJob(int pid, const std::string& command_line) {
+ return chromeos::RestartJob(pid, command_line.c_str());
+ }
+
+ private:
+ static void Handler(void* object, const OwnershipEvent& event) {
+ LoginLibraryImpl* self = static_cast<LoginLibraryImpl*>(object);
+ switch (event) {
+ case SetKeySuccess:
+ self->CompleteSetOwnerKey(true);
+ break;
+ case SetKeyFailure:
+ self->CompleteSetOwnerKey(false);
+ break;
+ case WhitelistOpSuccess:
+ self->CompleteWhitelistOp(true);
+ break;
+ case WhitelistOpFailure:
+ self->CompleteWhitelistOp(false);
+ break;
+ case PropertyOpSuccess:
+ self->CompletePropertyOp(true);
+ break;
+ case PropertyOpFailure:
+ self->CompletePropertyOp(false);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ void Init() {
+ session_connection_ = chromeos::MonitorSession(&Handler, this);
+ }
+
+ void CompleteSetOwnerKey(bool result) {
+ CHECK(set_owner_key_callback_) << "CompleteSetOwnerKey() called without "
+ "a registered callback!";
+ set_owner_key_callback_->OnComplete(result);
+ set_owner_key_callback_ = NULL;
+ }
+
+ void CompleteWhitelistOp(bool result) {
+ CHECK(whitelist_op_callback_);
+ whitelist_op_callback_->OnComplete(result);
+ whitelist_op_callback_ = NULL;
+ }
+
+ void CompletePropertyOp(bool result) {
+ CHECK(property_op_callback_);
+ property_op_callback_->OnComplete(result);
+ property_op_callback_ = NULL;
+ }
+
+ chromeos::SessionConnection session_connection_;
+
+ Delegate* set_owner_key_callback_;
+ Delegate* whitelist_op_callback_;
+ Delegate* property_op_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginLibraryImpl);
+};
+
+class LoginLibraryStubImpl : public LoginLibrary {
+ public:
+ LoginLibraryStubImpl() {}
+ virtual ~LoginLibraryStubImpl() {}
+
+ bool EmitLoginPromptReady() { return true; }
+ bool CheckWhitelist(const std::string& email,
+ std::vector<uint8>* OUT_signature) {
+ OUT_signature->assign(2, 0);
+ return true;
+ }
+ bool RetrieveProperty(const std::string& name,
+ std::string* OUT_value,
+ std::vector<uint8>* OUT_signature) {
+ OUT_value->assign("stub");
+ OUT_signature->assign(2, 0);
+ return true;
+ }
+ bool SetOwnerKeyAsync(const std::vector<uint8>& public_key_der,
+ Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+ bool StorePropertyAsync(const std::string& name,
+ const std::string& value,
+ const std::vector<uint8>& signature,
+ Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+ bool UnwhitelistAsync(const std::string& email,
+ const std::vector<uint8>& signature,
+ Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+ bool WhitelistAsync(const std::string& email,
+ const std::vector<uint8>& signature,
+ Delegate* callback) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&DoStubCallback, callback));
+ return true;
+ }
+ bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) {
+ return true;
+ }
+ bool StartSession(const std::string& user_email,
+ 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; }
+
+ private:
+ static void DoStubCallback(Delegate* callback) {
+ callback->OnComplete(true);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(LoginLibraryStubImpl);
+};
-bool LoginLibraryImpl::StopSession(const std::string& unique_id /* unused */) {
- // only pass unique_id through once we use it for something.
- return chromeos::StopSession("");
+// static
+LoginLibrary* LoginLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new LoginLibraryStubImpl();
+ else
+ return new LoginLibraryImpl();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/login_library.h b/chrome/browser/chromeos/cros/login_library.h
index 3e8936f..fc9b11a 100644
--- a/chrome/browser/chromeos/cros/login_library.h
+++ b/chrome/browser/chromeos/cros/login_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_LOGIN_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_LOGIN_LIBRARY_H_
+#pragma once
#include <string>
@@ -15,10 +16,72 @@ namespace chromeos {
// This interface defines the interaction with the ChromeOS login library APIs.
class LoginLibrary {
public:
+ class Delegate {
+ public:
+ virtual void OnComplete(bool value) = 0;
+ };
+
virtual ~LoginLibrary() {}
// Requests that the Upstart signal login-prompt-ready be emitted.
virtual bool EmitLoginPromptReady() = 0;
+ // Check whether or not |email| is present on the whitelist.
+ // If so, we return true and store the signature passed when |email| was
+ // whitelisted in |OUT_signature|.
+ // If not, we return false and don't touch the output parameter.
+ virtual bool CheckWhitelist(const std::string& email,
+ std::vector<uint8>* OUT_signature) = 0;
+
+ // Fetch the value associated with |name|, if its present.
+ // If so, we return true, store the info in |OUT_value|, and store the
+ // signature passed when the property was initially stored in |OUT_signature|.
+ // If not, we return false and don't touch the output parameters.
+ virtual bool RetrieveProperty(const std::string& name,
+ std::string* OUT_value,
+ std::vector<uint8>* OUT_signature) = 0;
+
+ // Attempts to asynchronously set the provided public key as the
+ // Owner's public key for this device. |public_key_der| should be a
+ // DER-encoded PKCS11 SubjectPublicKeyInfo structure.
+ // Returns true if the attempt was successfully started.
+ // callback->Run() will be called when the operation is complete.
+ virtual bool SetOwnerKeyAsync(const std::vector<uint8>& public_key_der,
+ Delegate* callback) = 0;
+
+ // Attempts to issue a signed async request to store |name|=|value|.
+ // |signature| must by a SHA1 with RSA encryption signature over the string
+ // "name=value" with the owner's private key.
+ // Returns true if the attempt was successfully started.
+ // callback->Run() will be called when the operation is complete.
+ virtual bool StorePropertyAsync(const std::string& name,
+ const std::string& value,
+ const std::vector<uint8>& signature,
+ Delegate* callback) = 0;
+
+ // Attempts to issue a signed async request to whitelist |email|.
+ // |signature| must by a SHA1 with RSA encryption signature over |email|
+ // with the owner's private key.
+ // Returns true if the attempt was successfully started.
+ // callback->Run() will be called when the operation is complete.
+ virtual bool WhitelistAsync(const std::string& email,
+ const std::vector<uint8>& signature,
+ Delegate* callback) = 0;
+
+ // Attempts to issue a signed async request to remove |email| from the
+ // whitelist of users allowed to log in to this machine.
+ // |signature| must by a SHA1 with RSA encryption signature over |email|
+ // with the owner's private key.
+ // Returns true if the attempt was successfully started.
+ // callback->Run() will be called when the operation is complete.
+ virtual bool UnwhitelistAsync(const std::string& email,
+ const std::vector<uint8>& signature,
+ Delegate* callback) = 0;
+
+ // Retrieves the user white list. Note the call is for display purpose only.
+ // To determine if an email is white listed, you MUST use CheckWhitelist.
+ // Returns true if the request is successfully dispatched.
+ virtual bool EnumerateWhitelisted(std::vector<std::string>* whitelisted) = 0;
+
// Tells the session manager to start a logged-in session for the user
// |user_email|. |unique_id| is meant to be used when we have a non-human-
// readable unique identifier by which we distinguish users (to deal with
@@ -31,22 +94,13 @@ class LoginLibrary {
// This will tell the session manager to terminate the session for the user
// indicated by |unique_id|.
virtual bool StopSession(const std::string& unique_id /* unused */) = 0;
-};
-// This class handles the interaction with the ChromeOS login library APIs.
-class LoginLibraryImpl : public LoginLibrary {
- public:
- LoginLibraryImpl() {}
- virtual ~LoginLibraryImpl() {}
-
- // LoginLibrary overrides.
- virtual bool EmitLoginPromptReady();
- virtual bool StartSession(const std::string& user_email,
- const std::string& unique_id /* unused */);
- virtual bool StopSession(const std::string& unique_id /* unused */);
+ // Restarts the job with specified command line string.
+ virtual bool RestartJob(int pid, const std::string& command_line) = 0;
- private:
- DISALLOW_COPY_AND_ASSIGN(LoginLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static LoginLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/mock_cros_library.h b/chrome/browser/chromeos/cros/mock_cros_library.h
index f66cc67..19434fe 100644
--- a/chrome/browser/chromeos/cros/mock_cros_library.h
+++ b/chrome/browser/chromeos/cros/mock_cros_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_CROS_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_CROS_LIBRARY_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/cros/mock_cryptohome_library.h b/chrome/browser/chromeos/cros/mock_cryptohome_library.h
index 664f88a..c579418 100644
--- a/chrome/browser/chromeos/cros/mock_cryptohome_library.h
+++ b/chrome/browser/chromeos/cros/mock_cryptohome_library.h
@@ -4,30 +4,79 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_CRYPTOHOME_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_CRYPTOHOME_LIBRARY_H_
+#pragma once
#include <string>
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "testing/gmock/include/gmock/gmock.h"
+using ::testing::Invoke;
+using ::testing::WithArgs;
+using ::testing::_;
+
namespace chromeos {
class MockCryptohomeLibrary : public CryptohomeLibrary {
public:
- MockCryptohomeLibrary() {}
+ MockCryptohomeLibrary() {
+ ON_CALL(*this, AsyncCheckKey(_, _, _))
+ .WillByDefault(
+ WithArgs<2>(Invoke(this, &MockCryptohomeLibrary::DoCallback)));
+ ON_CALL(*this, AsyncMigrateKey(_, _, _, _))
+ .WillByDefault(
+ WithArgs<3>(Invoke(this, &MockCryptohomeLibrary::DoCallback)));
+ ON_CALL(*this, AsyncMount(_, _, _, _))
+ .WillByDefault(
+ WithArgs<3>(Invoke(this, &MockCryptohomeLibrary::DoCallback)));
+ ON_CALL(*this, AsyncMountForBwsi(_))
+ .WillByDefault(
+ WithArgs<0>(Invoke(this, &MockCryptohomeLibrary::DoCallback)));
+ ON_CALL(*this, AsyncRemove(_, _))
+ .WillByDefault(
+ WithArgs<1>(Invoke(this, &MockCryptohomeLibrary::DoCallback)));
+ }
virtual ~MockCryptohomeLibrary() {}
- MOCK_METHOD3(Mount, bool(const std::string& user_email,
- const std::string& passhash,
- int* error_code));
- MOCK_METHOD1(MountForBwsi, bool(int*));
MOCK_METHOD2(CheckKey, bool(const std::string& user_email,
const std::string& passhash));
+ MOCK_METHOD3(AsyncCheckKey, bool(const std::string& user_email,
+ const std::string& passhash,
+ Delegate* callback));
MOCK_METHOD3(MigrateKey, bool(const std::string& user_email,
const std::string& old_hash,
const std::string& new_hash));
+ MOCK_METHOD4(AsyncMigrateKey, bool(const std::string& user_email,
+ const std::string& old_hash,
+ const std::string& new_hash,
+ Delegate* callback));
+ MOCK_METHOD3(Mount, bool(const std::string& user_email,
+ const std::string& passhash,
+ int* error_code));
+ MOCK_METHOD4(AsyncMount, bool(const std::string& user_email,
+ const std::string& passhash,
+ const bool create_if_missing,
+ Delegate* callback));
+ MOCK_METHOD1(MountForBwsi, bool(int*));
+ MOCK_METHOD1(AsyncMountForBwsi, bool(Delegate* callback));
MOCK_METHOD1(Remove, bool(const std::string& user_email));
+ MOCK_METHOD2(AsyncRemove, bool(const std::string& user_email, Delegate* d));
MOCK_METHOD0(IsMounted, bool(void));
MOCK_METHOD0(GetSystemSalt, CryptohomeBlob(void));
+
+ void SetAsyncBehavior(bool outcome, int code) {
+ outcome_ = outcome;
+ code_ = code;
+ }
+
+ bool DoCallback(Delegate* d) {
+ d->OnComplete(outcome_, code_);
+ return true;
+ }
+
+ private:
+ bool outcome_;
+ int code_;
+ DISALLOW_COPY_AND_ASSIGN(MockCryptohomeLibrary);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/mock_input_method_library.h b/chrome/browser/chromeos/cros/mock_input_method_library.h
index ccd0387..4cbd1c8 100644
--- a/chrome/browser/chromeos/cros/mock_input_method_library.h
+++ b/chrome/browser/chromeos/cros/mock_input_method_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_INPUT_METHOD_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_INPUT_METHOD_LIBRARY_H_
+#pragma once
#include <string>
@@ -32,9 +33,11 @@ class MockInputMethodLibrary : public InputMethodLibrary {
MOCK_CONST_METHOD0(previous_input_method, const InputMethodDescriptor&(void));
MOCK_CONST_METHOD0(current_input_method, const InputMethodDescriptor&(void));
MOCK_CONST_METHOD0(current_ime_properties, const ImePropertyList&(void));
+ MOCK_METHOD0(StartInputMethodProcesses, void(void));
+ MOCK_METHOD0(StopInputMethodProcesses, void(void));
+ MOCK_METHOD1(SetDeferImeStartup, void(bool));
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_CROS_MOCK_INPUT_METHOD_LIBRARY_H_
-
diff --git a/chrome/browser/chromeos/cros/mock_keyboard_library.h b/chrome/browser/chromeos/cros/mock_keyboard_library.h
index 67bcdce..f36d74f 100644
--- a/chrome/browser/chromeos/cros/mock_keyboard_library.h
+++ b/chrome/browser/chromeos/cros/mock_keyboard_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_KEYBOARD_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_KEYBOARD_LIBRARY_H_
+#pragma once
#include <string>
@@ -17,10 +18,16 @@ class MockKeyboardLibrary : public KeyboardLibrary {
MockKeyboardLibrary() {}
virtual ~MockKeyboardLibrary() {}
+ MOCK_CONST_METHOD0(GetHardwareKeyboardLayoutName, std::string(void));
MOCK_CONST_METHOD0(GetCurrentKeyboardLayoutName, std::string(void));
MOCK_METHOD1(SetCurrentKeyboardLayoutByName, bool(const std::string&));
+ MOCK_METHOD1(RemapModifierKeys, bool(const ModifierMap&));
MOCK_CONST_METHOD1(GetKeyboardLayoutPerWindow, bool(bool*));
MOCK_METHOD1(SetKeyboardLayoutPerWindow, bool(bool));
+ MOCK_CONST_METHOD1(GetAutoRepeatEnabled, bool(bool*));
+ MOCK_METHOD1(SetAutoRepeatEnabled, bool(bool));
+ MOCK_CONST_METHOD1(GetAutoRepeatRate, bool(AutoRepeatRate*));
+ MOCK_METHOD1(SetAutoRepeatRate, bool(const AutoRepeatRate&));
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/mock_library_loader.h b/chrome/browser/chromeos/cros/mock_library_loader.h
index 5863a54..1e4a440 100644
--- a/chrome/browser/chromeos/cros/mock_library_loader.h
+++ b/chrome/browser/chromeos/cros/mock_library_loader.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_LIBRARY_LOADER_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_LIBRARY_LOADER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/cros/mock_login_library.h b/chrome/browser/chromeos/cros/mock_login_library.h
index 51096bf..43a77b4 100644
--- a/chrome/browser/chromeos/cros/mock_login_library.h
+++ b/chrome/browser/chromeos/cros/mock_login_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_LOGIN_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_LOGIN_LIBRARY_H_
+#pragma once
#include <string>
@@ -16,13 +17,28 @@ class MockLoginLibrary : public LoginLibrary {
public:
MockLoginLibrary() {}
virtual ~MockLoginLibrary() {}
+ MOCK_METHOD2(CheckWhitelist, bool(const std::string&, std::vector<uint8>*));
MOCK_METHOD0(EmitLoginPromptReady, bool(void));
+ MOCK_METHOD1(EnumerateWhitelisted, bool(std::vector<std::string>*));
+ MOCK_METHOD3(RetrieveProperty, bool(const std::string&,
+ std::string*,
+ std::vector<uint8>*));
+ MOCK_METHOD2(SetOwnerKeyAsync, bool(const std::vector<uint8>&, Delegate*));
+ MOCK_METHOD4(StorePropertyAsync, bool(const std::string&,
+ const std::string&,
+ const std::vector<uint8>&,
+ Delegate*));
+ MOCK_METHOD3(UnwhitelistAsync, bool(const std::string&,
+ const std::vector<uint8>&,
+ Delegate*));
+ MOCK_METHOD3(WhitelistAsync, bool(const std::string&,
+ const std::vector<uint8>&,
+ Delegate*));
MOCK_METHOD2(StartSession, bool(const std::string&, const std::string&));
- MOCK_METHOD1(StartSession, bool(const std::string&));
MOCK_METHOD1(StopSession, bool(const std::string&));
+ MOCK_METHOD2(RestartJob, bool(int, const std::string&));
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_CROS_MOCK_LOGIN_LIBRARY_H_
-
diff --git a/chrome/browser/chromeos/cros/mock_mount_library.h b/chrome/browser/chromeos/cros/mock_mount_library.h
index e0309ea..32a52c2 100644
--- a/chrome/browser/chromeos/cros/mock_mount_library.h
+++ b/chrome/browser/chromeos/cros/mock_mount_library.h
@@ -1,25 +1,22 @@
-// 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.
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_MOUNT_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_MOUNT_LIBRARY_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/observer_list.h"
#include "base/time.h"
-#include "cros/chromeos_mount.h"
#include "chrome/browser/chromeos/cros/mount_library.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "cros/chromeos_mount.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
-// This class handles the interaction with the ChromeOS mount library APIs.
-// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: MountLibrary::Get().
class MockMountLibrary : public MountLibrary {
public:
MockMountLibrary();
diff --git a/chrome/browser/chromeos/cros/mock_network_library.h b/chrome/browser/chromeos/cros/mock_network_library.h
index ee87358..823cd5b 100644
--- a/chrome/browser/chromeos/cros/mock_network_library.h
+++ b/chrome/browser/chromeos/cros/mock_network_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_NETWORK_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_NETWORK_LIBRARY_H_
+#pragma once
#include <string>
@@ -49,9 +50,6 @@ class MockNetworkLibrary : public NetworkLibrary {
MOCK_METHOD0(RequestWifiScan, void(void));
MOCK_METHOD0(UpdateSystemInfo, void(void));
MOCK_METHOD1(GetWifiAccessPoints, bool(WifiAccessPointVector*));
- MOCK_METHOD0(ConnectToPreferredNetworkIfAvailable, bool(void));
- MOCK_METHOD0(PreferredNetworkConnected, bool(void));
- MOCK_METHOD0(PreferredNetworkFailed, bool(void));
MOCK_METHOD4(ConnectToWifiNetwork, void(WifiNetwork,
const std::string&,
const std::string&,
@@ -65,7 +63,7 @@ class MockNetworkLibrary : public NetworkLibrary {
MOCK_METHOD1(DisconnectFromWirelessNetwork, void(const WirelessNetwork&));
MOCK_METHOD1(SaveCellularNetwork, void(const CellularNetwork&));
MOCK_METHOD1(SaveWifiNetwork, void(const WifiNetwork&));
- MOCK_METHOD1(ForgetWirelessNetwork, void(const WirelessNetwork&));
+ MOCK_METHOD1(ForgetWirelessNetwork, void(const std::string&));
MOCK_CONST_METHOD0(ethernet_available, bool(void));
MOCK_CONST_METHOD0(wifi_available, bool(void));
diff --git a/chrome/browser/chromeos/cros/mock_power_library.h b/chrome/browser/chromeos/cros/mock_power_library.h
index 4b57538..fae5521 100644
--- a/chrome/browser/chromeos/cros/mock_power_library.h
+++ b/chrome/browser/chromeos/cros/mock_power_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_POWER_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_POWER_LIBRARY_H_
+#pragma once
#include "chrome/browser/chromeos/cros/power_library.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/chromeos/cros/mock_screen_lock_library.h b/chrome/browser/chromeos/cros/mock_screen_lock_library.h
index 9022ce6..9b1c01c 100644
--- a/chrome/browser/chromeos/cros/mock_screen_lock_library.h
+++ b/chrome/browser/chromeos/cros/mock_screen_lock_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_SCREEN_LOCK_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_SCREEN_LOCK_LIBRARY_H_
+#pragma once
#include "chrome/browser/chromeos/cros/screen_lock_library.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/chromeos/cros/mock_speech_synthesis_library.h b/chrome/browser/chromeos/cros/mock_speech_synthesis_library.h
index 08cf883..dcf1926 100644
--- a/chrome/browser/chromeos/cros/mock_speech_synthesis_library.h
+++ b/chrome/browser/chromeos/cros/mock_speech_synthesis_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_SPEECH_SYNTHESIS_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_SPEECH_SYNTHESIS_LIBRARY_H_
+#pragma once
#include "chrome/browser/chromeos/cros/speech_synthesis_library.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/chromeos/cros/mock_synaptics_library.h b/chrome/browser/chromeos/cros/mock_synaptics_library.h
deleted file mode 100644
index be5efb0..0000000
--- a/chrome/browser/chromeos/cros/mock_synaptics_library.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_CHROMEOS_CROS_MOCK_SYNAPTICS_LIBRARY_H_
-#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_SYNAPTICS_LIBRARY_H_
-
-#include "chrome/browser/chromeos/cros/synaptics_library.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace chromeos {
-
-class MockSynapticsLibrary : public SynapticsLibrary {
- public:
- MockSynapticsLibrary() {}
- virtual ~MockSynapticsLibrary() {}
- MOCK_METHOD2(SetBoolParameter, void(SynapticsParameter, bool));
- MOCK_METHOD2(SetRangeParameter, void(SynapticsParameter, int));
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_CROS_MOCK_SYNAPTICS_LIBRARY_H_
-
diff --git a/chrome/browser/chromeos/cros/mock_system_library.h b/chrome/browser/chromeos/cros/mock_system_library.h
index bbb8006..a851238 100644
--- a/chrome/browser/chromeos/cros/mock_system_library.h
+++ b/chrome/browser/chromeos/cros/mock_system_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_SYSTEM_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_SYSTEM_LIBRARY_H_
+#pragma once
#include "chrome/browser/chromeos/cros/system_library.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -18,9 +19,9 @@ class MockSystemLibrary : public SystemLibrary {
MOCK_METHOD1(RemoveObserver, void(Observer*));
MOCK_METHOD0(GetTimezone, const icu::TimeZone&());
MOCK_METHOD1(SetTimezone, void(const icu::TimeZone*));
+ MOCK_METHOD2(GetMachineStatistic, bool(const std::string&, std::string*));
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_CROS_MOCK_SYSTEM_LIBRARY_H_
-
diff --git a/chrome/browser/chromeos/cros/mock_update_library.h b/chrome/browser/chromeos/cros/mock_update_library.h
index 4e1e7f6..d4f14cb 100644
--- a/chrome/browser/chromeos/cros/mock_update_library.h
+++ b/chrome/browser/chromeos/cros/mock_update_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOCK_UPDATE_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOCK_UPDATE_LIBRARY_H_
+#pragma once
#include "base/observer_list.h"
#include "chrome/browser/chromeos/cros/update_library.h"
@@ -17,7 +18,8 @@ class MockUpdateLibrary : public UpdateLibrary {
virtual ~MockUpdateLibrary() {}
MOCK_METHOD1(AddObserver, void(Observer*)); // NOLINT
MOCK_METHOD1(RemoveObserver, void(Observer*)); // NOLINT
-
+ MOCK_METHOD0(CheckForUpdate, bool(void));
+ MOCK_METHOD0(RebootAfterUpdate, bool(void));
MOCK_CONST_METHOD0(status, const Status&(void));
private:
diff --git a/chrome/browser/chromeos/cros/mount_library.cc b/chrome/browser/chromeos/cros/mount_library.cc
index e99edf2..16cec4a 100644
--- a/chrome/browser/chromeos/cros/mount_library.cc
+++ b/chrome/browser/chromeos/cros/mount_library.cc
@@ -9,97 +9,140 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-// Allows InvokeLater without adding refcounting. This class is a Singleton and
-// won't be deleted until it's last InvokeLater is run.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::MountLibraryImpl);
-
namespace chromeos {
-void MountLibraryImpl::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
+class MountLibraryImpl : public MountLibrary {
+ public:
+ MountLibraryImpl() : mount_status_connection_(NULL) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ Init();
+ } else {
+ LOG(ERROR) << "Cros Library has not been loaded";
+ }
+ }
-void MountLibraryImpl::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
+ ~MountLibraryImpl() {
+ if (mount_status_connection_) {
+ DisconnectMountStatus(mount_status_connection_);
+ }
+ }
-bool MountLibraryImpl::MountPath(const char* device_path) {
- return MountDevicePath(device_path);
-}
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
-void MountLibraryImpl::ParseDisks(const MountStatus& status) {
- disks_.clear();
- for (int i = 0; i < status.size; i++) {
- std::string path;
- std::string mountpath;
- std::string systempath;
- bool parent;
- bool hasmedia;
- if (status.disks[i].path != NULL) {
- path = status.disks[i].path;
- }
- if (status.disks[i].mountpath != NULL) {
- mountpath = status.disks[i].mountpath;
- }
- if (status.disks[i].systempath != NULL) {
- systempath = status.disks[i].systempath;
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
+
+ bool MountPath(const char* device_path) {
+ return MountDevicePath(device_path);
+ }
+
+ const DiskVector& disks() const { return disks_; }
+
+ private:
+ void ParseDisks(const MountStatus& status) {
+ disks_.clear();
+ for (int i = 0; i < status.size; i++) {
+ std::string path;
+ std::string mountpath;
+ std::string systempath;
+ bool parent;
+ bool hasmedia;
+ if (status.disks[i].path != NULL) {
+ path = status.disks[i].path;
+ }
+ if (status.disks[i].mountpath != NULL) {
+ mountpath = status.disks[i].mountpath;
+ }
+ if (status.disks[i].systempath != NULL) {
+ systempath = status.disks[i].systempath;
+ }
+ parent = status.disks[i].isparent;
+ hasmedia = status.disks[i].hasmedia;
+ disks_.push_back(Disk(path,
+ mountpath,
+ systempath,
+ parent,
+ hasmedia));
}
- parent = status.disks[i].isparent;
- hasmedia = status.disks[i].hasmedia;
- disks_.push_back(Disk(path,
- mountpath,
- systempath,
- parent,
- hasmedia));
}
-}
-MountLibraryImpl::MountLibraryImpl() : mount_status_connection_(NULL) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- Init();
- } else {
- LOG(ERROR) << "Cros Library has not been loaded";
+ static void MountStatusChangedHandler(void* object,
+ const MountStatus& status,
+ MountEventType evt,
+ const char* path) {
+ MountLibraryImpl* mount = static_cast<MountLibraryImpl*>(object);
+ std::string devicepath = path;
+ mount->ParseDisks(status);
+ mount->UpdateMountStatus(status, evt, devicepath);
}
-}
-MountLibraryImpl::~MountLibraryImpl() {
- if (mount_status_connection_) {
- DisconnectMountStatus(mount_status_connection_);
+ void Init() {
+ // Getting the monitor status so that the daemon starts up.
+ MountStatus* mount = RetrieveMountInformation();
+ if (!mount) {
+ LOG(ERROR) << "Failed to retrieve mount information";
+ return;
+ }
+ ParseDisks(*mount);
+ FreeMountStatus(mount);
+
+ mount_status_connection_ = MonitorMountStatus(
+ &MountStatusChangedHandler, this);
}
-}
-// static
-void MountLibraryImpl::MountStatusChangedHandler(void* object,
- const MountStatus& status,
- MountEventType evt,
- const char* path) {
- MountLibraryImpl* mount = static_cast<MountLibraryImpl*>(object);
- std::string devicepath = path;
- mount->ParseDisks(status);
- mount->UpdateMountStatus(status, evt, devicepath);
-}
+ void UpdateMountStatus(const MountStatus& status,
+ MountEventType evt,
+ const std::string& path) {
+ // Make sure we run on UI thread.
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-void MountLibraryImpl::Init() {
- // Getting the monitor status so that the daemon starts up.
- MountStatus* mount = RetrieveMountInformation();
- if (!mount) {
- LOG(ERROR) << "Failed to retrieve mount information";
- return;
+ FOR_EACH_OBSERVER(
+ Observer, observers_, MountChanged(this, evt, path));
}
- ParseDisks(*mount);
- FreeMountStatus(mount);
+ ObserverList<Observer> observers_;
- mount_status_connection_ = MonitorMountStatus(
- &MountStatusChangedHandler, this);
-}
+ // A reference to the mount api, to allow callbacks when the mount
+ // status changes.
+ MountStatusConnection mount_status_connection_;
+
+ // The list of disks found.
+ DiskVector disks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl);
+};
-void MountLibraryImpl::UpdateMountStatus(const MountStatus& status,
- MountEventType evt,
- const std::string& path) {
- // Make sure we run on UI thread.
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+class MountLibraryStubImpl : public MountLibrary {
+ public:
+ MountLibraryStubImpl() {}
+ virtual ~MountLibraryStubImpl() {}
- FOR_EACH_OBSERVER(Observer, observers_, MountChanged(this, evt, path));
+ // MountLibrary overrides.
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual const DiskVector& disks() const { return disks_; }
+ virtual bool MountPath(const char* device_path) { return false; }
+
+ private:
+ // The list of disks found.
+ DiskVector disks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MountLibraryStubImpl);
+};
+
+// static
+MountLibrary* MountLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new MountLibraryStubImpl();
+ else
+ return new MountLibraryImpl();
}
} // namespace chromeos
+
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::MountLibraryImpl);
+
diff --git a/chrome/browser/chromeos/cros/mount_library.h b/chrome/browser/chromeos/cros/mount_library.h
index 3fd772a..f54ba53 100644
--- a/chrome/browser/chromeos/cros/mount_library.h
+++ b/chrome/browser/chromeos/cros/mount_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_MOUNT_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_MOUNT_LIBRARY_H_
+#pragma once
#include <string>
#include <vector>
@@ -17,7 +18,7 @@ namespace chromeos {
// This class handles the interaction with the ChromeOS mount library APIs.
// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: MountLibrary::Get().
+// library class like this: chromeos::CrosLibrary::Get()->GetMountLibrary()
class MountLibrary {
public:
// Used to house an instance of each found mount device.
@@ -58,51 +59,10 @@ class MountLibrary {
virtual void RemoveObserver(Observer* observer) = 0;
virtual const DiskVector& disks() const = 0;
virtual bool MountPath(const char* device_path) = 0;
-};
-
-// This class handles the interaction with the ChromeOS mount library APIs.
-// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: MountLibrary::Get().
-class MountLibraryImpl : public MountLibrary {
- public:
- MountLibraryImpl();
- virtual ~MountLibraryImpl();
-
- // MountLibrary overrides.
- virtual void AddObserver(Observer* observer);
- virtual void RemoveObserver(Observer* observer);
- virtual const DiskVector& disks() const { return disks_; }
- virtual bool MountPath(const char* device_path);
- private:
- void ParseDisks(const MountStatus& status);
-
- // This method is called when there's a change in mount status.
- // This method is called the UI Thread.
- static void MountStatusChangedHandler(void* object,
- const MountStatus& status,
- MountEventType evt,
- const char* path);
-
- // This methods starts the monitoring of mount changes.
- // It should be called on the UI Thread.
- void Init();
-
- // Called by the handler to update the mount status.
- // This will notify all the Observers.
- void UpdateMountStatus(const MountStatus& status,
- MountEventType evt,
- const std::string& path);
-
- ObserverList<Observer> observers_;
-
- // A reference to the mount api, to allow callbacks when the mount
- // status changes.
- MountStatusConnection mount_status_connection_;
-
- // The list of disks found.
- DiskVector disks_;
- DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static MountLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc
index 7538111..2258a36 100644
--- a/chrome/browser/chromeos/cros/network_library.cc
+++ b/chrome/browser/chromeos/cros/network_library.cc
@@ -6,21 +6,14 @@
#include <algorithm>
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "net/url_request/url_request_job.h"
-
-// Allows InvokeLater without adding refcounting. This class is a Singleton and
-// won't be deleted until it's last InvokeLater is run.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::NetworkLibraryImpl);
namespace chromeos {
-static const std::string kGoogleWifi = "Google";
-static const std::string kGoogleAWifi = "Google-A";
-
// Helper function to wrap Html with <th> tag.
static std::string WrapWithTH(std::string text) {
return "<th>" + text + "</th>";
@@ -51,17 +44,18 @@ static std::string ToHtmlTableRow(Network* network) {
if (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR) {
WirelessNetwork* wireless = static_cast<WirelessNetwork*>(network);
str += WrapWithTD(wireless->name()) +
- WrapWithTD(IntToString(wireless->auto_connect())) +
- WrapWithTD(IntToString(wireless->strength()));
+ WrapWithTD(base::IntToString(wireless->auto_connect())) +
+ WrapWithTD(base::IntToString(wireless->strength()));
if (network->type() == TYPE_WIFI) {
WifiNetwork* wifi = static_cast<WifiNetwork*>(network);
str += WrapWithTD(wifi->GetEncryptionString()) +
- WrapWithTD(wifi->passphrase()) + WrapWithTD(wifi->identity()) +
- WrapWithTD(wifi->cert_path());
+ WrapWithTD(std::string(wifi->passphrase().length(), '*')) +
+ WrapWithTD(wifi->identity()) + WrapWithTD(wifi->cert_path());
}
}
str += WrapWithTD(network->GetStateString()) +
- WrapWithTD(network->GetErrorString()) + WrapWithTD(network->ip_address());
+ WrapWithTD(network->failed() ? network->GetErrorString() : "") +
+ WrapWithTD(network->ip_address());
return str;
}
@@ -123,7 +117,7 @@ std::string Network::GetStateString() {
std::string Network::GetErrorString() {
switch (error_) {
case ERROR_UNKNOWN:
- break;
+ return "Unknown Error";
case ERROR_OUT_OF_RANGE:
return "Out Of Range";
case ERROR_PIN_MISSING:
@@ -132,6 +126,10 @@ std::string Network::GetErrorString() {
return "DHCP Failed";
case ERROR_CONNECT_FAILED:
return "Connect Failed";
+ case ERROR_BAD_PASSPHRASE:
+ return "Bad Passphrase";
+ case ERROR_BAD_WEPKEY:
+ return "Bad WEP Key";
}
return "";
}
@@ -144,6 +142,7 @@ void WirelessNetwork::Clear() {
name_.clear();
strength_ = 0;
auto_connect_ = false;
+ favorite_ = false;
}
void WirelessNetwork::ConfigureFromService(const ServiceInfo& service) {
@@ -151,17 +150,27 @@ void WirelessNetwork::ConfigureFromService(const ServiceInfo& service) {
name_ = service.name;
strength_ = service.strength;
auto_connect_ = service.auto_connect;
+ favorite_ = service.favorite;
}
////////////////////////////////////////////////////////////////////////////////
// CellularNetwork
+
+bool CellularNetwork::StartActivation() const {
+ // TODO(ers, jglasgow): Kick of device activation process.
+ return true;
+}
+
void CellularNetwork::Clear() {
WirelessNetwork::Clear();
}
void CellularNetwork::ConfigureFromService(const ServiceInfo& service) {
WirelessNetwork::ConfigureFromService(service);
+ activation_state_ = service.activation_state;
+ // TODO(ers): Set other cellular properties here once they get added
+ // to ServiceInfo.
}
////////////////////////////////////////////////////////////////////////////////
@@ -203,622 +212,786 @@ std::string WifiNetwork::GetEncryptionString() {
////////////////////////////////////////////////////////////////////////////////
// NetworkLibrary
-// static
-const int NetworkLibraryImpl::kNetworkTrafficeTimerSecs = 1;
-
-NetworkLibraryImpl::NetworkLibraryImpl()
- : traffic_type_(0),
- network_status_connection_(NULL),
- available_devices_(0),
- enabled_devices_(0),
- connected_devices_(0),
- offline_mode_(false) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- Init();
- }
- g_url_request_job_tracker.AddObserver(this);
-}
+class NetworkLibraryImpl : public NetworkLibrary {
+ public:
+ NetworkLibraryImpl()
+ : network_status_connection_(NULL),
+ available_devices_(0),
+ enabled_devices_(0),
+ connected_devices_(0),
+ offline_mode_(false) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ Init();
+ } else {
+ InitTestData();
+ }
+ }
-NetworkLibraryImpl::~NetworkLibraryImpl() {
- if (network_status_connection_) {
- DisconnectMonitorNetwork(network_status_connection_);
+ ~NetworkLibraryImpl() {
+ if (network_status_connection_) {
+ DisconnectMonitorNetwork(network_status_connection_);
+ }
}
- g_url_request_job_tracker.RemoveObserver(this);
-}
-////////////////////////////////////////////////////////////////////////////////
-// NetworkLibraryImpl, URLRequestJobTracker::JobObserver implementation:
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
-void NetworkLibraryImpl::OnJobAdded(URLRequestJob* job) {
- CheckNetworkTraffic(false);
-}
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
-void NetworkLibraryImpl::OnJobRemoved(URLRequestJob* job) {
- CheckNetworkTraffic(false);
-}
+ virtual const EthernetNetwork& ethernet_network() const { return ethernet_; }
+ virtual bool ethernet_connecting() const { return ethernet_.connecting(); }
+ virtual bool ethernet_connected() const { return ethernet_.connected(); }
-void NetworkLibraryImpl::OnJobDone(URLRequestJob* job,
- const URLRequestStatus& status) {
- CheckNetworkTraffic(false);
-}
+ virtual const std::string& wifi_name() const { return wifi_.name(); }
+ virtual bool wifi_connecting() const { return wifi_.connecting(); }
+ virtual bool wifi_connected() const { return wifi_.connected(); }
+ virtual int wifi_strength() const { return wifi_.strength(); }
-void NetworkLibraryImpl::OnJobRedirect(URLRequestJob* job, const GURL& location,
- int status_code) {
- CheckNetworkTraffic(false);
-}
+ virtual const std::string& cellular_name() const { return cellular_.name(); }
+ virtual bool cellular_connecting() const { return cellular_.connecting(); }
+ virtual bool cellular_connected() const { return cellular_.connected(); }
+ virtual int cellular_strength() const { return cellular_.strength(); }
-void NetworkLibraryImpl::OnBytesRead(URLRequestJob* job, const char* buf,
- int byte_count) {
- CheckNetworkTraffic(true);
-}
+ bool Connected() const {
+ return ethernet_connected() || wifi_connected() || cellular_connected();
+ }
-void NetworkLibraryImpl::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
+ bool Connecting() const {
+ return ethernet_connecting() || wifi_connecting() || cellular_connecting();
+ }
-void NetworkLibraryImpl::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
+ const std::string& IPAddress() const {
+ // Returns highest priority IP address.
+ if (ethernet_connected())
+ return ethernet_.ip_address();
+ if (wifi_connected())
+ return wifi_.ip_address();
+ if (cellular_connected())
+ return cellular_.ip_address();
+ return ethernet_.ip_address();
+ }
-////////////////////////////////////////////////////////////////////////////////
+ virtual const WifiNetworkVector& wifi_networks() const {
+ return wifi_networks_;
+ }
-bool NetworkLibraryImpl::FindWifiNetworkByPath(
- const std::string& path, WifiNetwork* result) const {
- const WifiNetwork* wifi =
- GetWirelessNetworkByPath(wifi_networks_, path);
- if (wifi) {
- if (result)
- *result = *wifi;
- return true;
+ virtual const WifiNetworkVector& remembered_wifi_networks() const {
+ return remembered_wifi_networks_;
}
- return false;
-}
-bool NetworkLibraryImpl::FindCellularNetworkByPath(
- const std::string& path, CellularNetwork* result) const {
- const CellularNetwork* cellular =
- GetWirelessNetworkByPath(cellular_networks_, path);
- if (cellular) {
- if (result)
- *result = *cellular;
- return true;
+ virtual const CellularNetworkVector& cellular_networks() const {
+ return cellular_networks_;
}
- return false;
-}
-void NetworkLibraryImpl::RequestWifiScan() {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- RequestScan(TYPE_WIFI);
+ virtual const CellularNetworkVector& remembered_cellular_networks() const {
+ return remembered_cellular_networks_;
}
-}
-bool NetworkLibraryImpl::GetWifiAccessPoints(WifiAccessPointVector* result) {
- if (!CrosLibrary::Get()->EnsureLoaded())
- return false;
- DeviceNetworkList* network_list = GetDeviceNetworkList();
- if (network_list == NULL)
+ /////////////////////////////////////////////////////////////////////////////
+
+ bool FindWifiNetworkByPath(
+ const std::string& path, WifiNetwork* result) const {
+ const WifiNetwork* wifi =
+ GetWirelessNetworkByPath(wifi_networks_, path);
+ if (wifi) {
+ if (result)
+ *result = *wifi;
+ return true;
+ }
return false;
- result->clear();
- result->reserve(network_list->network_size);
- const base::Time now = base::Time::Now();
- for (size_t i = 0; i < network_list->network_size; ++i) {
- DCHECK(network_list->networks[i].address);
- DCHECK(network_list->networks[i].name);
- WifiAccessPoint ap;
- ap.mac_address = network_list->networks[i].address;
- ap.name = network_list->networks[i].name;
- ap.timestamp = now -
- base::TimeDelta::FromSeconds(network_list->networks[i].age_seconds);
- ap.signal_strength = network_list->networks[i].strength;
- ap.channel = network_list->networks[i].channel;
- result->push_back(ap);
- }
- FreeDeviceNetworkList(network_list);
- return true;
-}
+ }
-bool NetworkLibraryImpl::ConnectToPreferredNetworkIfAvailable() {
- // TODO(chocobo): Add the concept of preferred network to libcros.
- // So that we don't have to hard-code Google-A here.
- if (CrosLibrary::Get()->EnsureLoaded()) {
- LOG(INFO) << "Attempting to auto-connect to Google wifi.";
- // First force a refresh of the system info.
- UpdateSystemInfo();
+ bool FindCellularNetworkByPath(
+ const std::string& path, CellularNetwork* result) const {
+ const CellularNetwork* cellular =
+ GetWirelessNetworkByPath(cellular_networks_, path);
+ if (cellular) {
+ if (result)
+ *result = *cellular;
+ return true;
+ }
+ return false;
+ }
- // If ethernet is connected, then don't bother.
- if (ethernet_connected()) {
- LOG(INFO) << "Ethernet connected, so don't need Google wifi.";
- return false;
+ void RequestWifiScan() {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ RequestScan(TYPE_WIFI);
}
+ }
- WifiNetwork* wifi = GetPreferredNetwork();
- if (!wifi) {
- LOG(INFO) << "Google-A/Google wifi not found or set to not auto-connect.";
+ bool GetWifiAccessPoints(WifiAccessPointVector* result) {
+ if (!CrosLibrary::Get()->EnsureLoaded())
+ return false;
+ DeviceNetworkList* network_list = GetDeviceNetworkList();
+ if (network_list == NULL)
return false;
+ result->clear();
+ result->reserve(network_list->network_size);
+ const base::Time now = base::Time::Now();
+ for (size_t i = 0; i < network_list->network_size; ++i) {
+ DCHECK(network_list->networks[i].address);
+ DCHECK(network_list->networks[i].name);
+ WifiAccessPoint ap;
+ ap.mac_address = network_list->networks[i].address;
+ ap.name = network_list->networks[i].name;
+ ap.timestamp = now -
+ base::TimeDelta::FromSeconds(network_list->networks[i].age_seconds);
+ ap.signal_strength = network_list->networks[i].strength;
+ ap.channel = network_list->networks[i].channel;
+ result->push_back(ap);
}
+ FreeDeviceNetworkList(network_list);
+ return true;
+ }
- // Save the wifi path, so we know which one we want to auto-connect to.
- const std::string wifi_path = wifi->service_path();
-
- // It takes some time for the enterprise daemon to start up and populate the
- // certificate and identity. So we wait at most 3 seconds here. And every
- // 100ms, we refetch the system info and check the cert and identify on the
- // wifi. The enterprise daemon takes between 0.4 to 0.9 seconds to setup.
- bool setup = false;
- for (int i = 0; i < 30; i++) {
- // Update the system and refetch the network.
- UpdateSystemInfo();
- wifi = GetWirelessNetworkByPath(wifi_networks_, wifi_path);
- // See if identity and certpath are available.
- if (wifi && !wifi->identity().empty() && !wifi->cert_path().empty()) {
- LOG(INFO) << "Google wifi set up after " << (i*0.1) << " seconds.";
- setup = true;
- break;
+ void ConnectToWifiNetwork(WifiNetwork network,
+ const std::string& password,
+ const std::string& identity,
+ const std::string& certpath) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ if (ConnectToNetworkWithCertInfo(network.service_path().c_str(),
+ password.empty() ? NULL : password.c_str(),
+ identity.empty() ? NULL : identity.c_str(),
+ certpath.empty() ? NULL : certpath.c_str())) {
+ // Update local cache and notify listeners.
+ WifiNetwork* wifi = GetWirelessNetworkByPath(
+ wifi_networks_, network.service_path());
+ if (wifi) {
+ wifi->set_passphrase(password);
+ wifi->set_identity(identity);
+ wifi->set_cert_path(certpath);
+ wifi->set_connecting(true);
+ wifi_ = *wifi;
+ }
+ NotifyNetworkChanged();
}
- PlatformThread::Sleep(100);
}
+ }
- if (!setup) {
- LOG(INFO) << "Google wifi not set up after 3 seconds.";
- return false;
+ void ConnectToWifiNetwork(const std::string& ssid,
+ const std::string& password,
+ const std::string& identity,
+ const std::string& certpath,
+ bool auto_connect) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ // First create a service from hidden network.
+ ServiceInfo* service = GetWifiService(ssid.c_str(),
+ SECURITY_UNKNOWN);
+ if (service) {
+ // Set auto-connect.
+ SetAutoConnect(service->service_path, auto_connect);
+ // Now connect to that service.
+ ConnectToNetworkWithCertInfo(service->service_path,
+ password.empty() ? NULL : password.c_str(),
+ identity.empty() ? NULL : identity.c_str(),
+ certpath.empty() ? NULL : certpath.c_str());
+
+ // Clean up ServiceInfo object.
+ FreeServiceInfo(service);
+ } else {
+ LOG(WARNING) << "Cannot find hidden network: " << ssid;
+ // TODO(chocobo): Show error message.
+ }
}
+ }
- // Now that we have a setup Google wifi, we can connect to it.
- ConnectToNetwork(wifi_path.c_str(), NULL);
- return true;
+ void ConnectToCellularNetwork(CellularNetwork network) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ if (ConnectToNetwork(network.service_path().c_str(), NULL)) {
+ // Update local cache and notify listeners.
+ CellularNetwork* cellular = GetWirelessNetworkByPath(
+ cellular_networks_, network.service_path());
+ if (cellular) {
+ cellular->set_connecting(true);
+ cellular_ = *cellular;
+ }
+ NotifyNetworkChanged();
+ }
+ }
}
- return false;
-}
-bool NetworkLibraryImpl::PreferredNetworkConnected() {
- WifiNetwork* wifi = GetPreferredNetwork();
- return wifi && wifi->connected();
-}
+ void DisconnectFromWirelessNetwork(const WirelessNetwork& network) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ if (DisconnectFromNetwork(network.service_path().c_str())) {
+ // Update local cache and notify listeners.
+ if (network.type() == TYPE_WIFI) {
+ WifiNetwork* wifi = GetWirelessNetworkByPath(
+ wifi_networks_, network.service_path());
+ if (wifi) {
+ wifi->set_connected(false);
+ wifi_ = WifiNetwork();
+ }
+ } else if (network.type() == TYPE_CELLULAR) {
+ CellularNetwork* cellular = GetWirelessNetworkByPath(
+ cellular_networks_, network.service_path());
+ if (cellular) {
+ cellular->set_connected(false);
+ cellular_ = CellularNetwork();
+ }
+ }
+ NotifyNetworkChanged();
+ }
+ }
+ }
-bool NetworkLibraryImpl::PreferredNetworkFailed() {
- WifiNetwork* wifi = GetPreferredNetwork();
- return !wifi || wifi->failed();
-}
+ void SaveCellularNetwork(const CellularNetwork& network) {
+ // Update the wifi network in the local cache.
+ CellularNetwork* cellular = GetWirelessNetworkByPath(
+ cellular_networks_, network.service_path());
+ if (cellular)
+ *cellular = network;
-void NetworkLibraryImpl::ConnectToWifiNetwork(WifiNetwork network,
- const std::string& password,
- const std::string& identity,
- const std::string& certpath) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- ConnectToNetworkWithCertInfo(network.service_path().c_str(),
- password.empty() ? NULL : password.c_str(),
- identity.empty() ? NULL : identity.c_str(),
- certpath.empty() ? NULL : certpath.c_str());
+ // Update the cellular network with libcros.
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ SetAutoConnect(network.service_path().c_str(), network.auto_connect());
+ }
}
-}
-void NetworkLibraryImpl::ConnectToWifiNetwork(const std::string& ssid,
- const std::string& password,
- const std::string& identity,
- const std::string& certpath,
- bool auto_connect) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- // First create a service from hidden network.
- ServiceInfo* service = GetWifiService(ssid.c_str(),
- SECURITY_UNKNOWN);
- if (service) {
- // Set auto-connect.
- SetAutoConnect(service->service_path, auto_connect);
- // Now connect to that service.
- ConnectToNetworkWithCertInfo(service->service_path,
- password.empty() ? NULL : password.c_str(),
- identity.empty() ? NULL : identity.c_str(),
- certpath.empty() ? NULL : certpath.c_str());
-
- // Clean up ServiceInfo object.
- FreeServiceInfo(service);
- } else {
- LOG(WARNING) << "Cannot find hidden network: " << ssid;
- // TODO(chocobo): Show error message.
+ void SaveWifiNetwork(const WifiNetwork& network) {
+ // Update the wifi network in the local cache.
+ WifiNetwork* wifi = GetWirelessNetworkByPath(
+ wifi_networks_, network.service_path());
+ if (wifi)
+ *wifi = network;
+
+ // Update the wifi network with libcros.
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ SetPassphrase(
+ network.service_path().c_str(), network.passphrase().c_str());
+ SetIdentity(network.service_path().c_str(), network.identity().c_str());
+ SetCertPath(network.service_path().c_str(), network.cert_path().c_str());
+ SetAutoConnect(network.service_path().c_str(), network.auto_connect());
}
}
-}
-void NetworkLibraryImpl::ConnectToCellularNetwork(CellularNetwork network) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- ConnectToNetwork(network.service_path().c_str(), NULL);
+ void ForgetWirelessNetwork(const std::string& service_path) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ if (DeleteRememberedService(service_path.c_str())) {
+ // Update local cache and notify listeners.
+ std::remove_if(remembered_wifi_networks_.begin(),
+ remembered_wifi_networks_.end(),
+ WirelessNetwork::ServicePathEq(service_path));
+ std::remove_if(remembered_cellular_networks_.begin(),
+ remembered_cellular_networks_.end(),
+ WirelessNetwork::ServicePathEq(service_path));
+ NotifyNetworkChanged();
+ }
+ }
}
-}
-void NetworkLibraryImpl::DisconnectFromWirelessNetwork(
- const WirelessNetwork& network) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- DisconnectFromNetwork(network.service_path().c_str());
+ virtual bool ethernet_available() const {
+ return available_devices_ & (1 << TYPE_ETHERNET);
+ }
+ virtual bool wifi_available() const {
+ return available_devices_ & (1 << TYPE_WIFI);
+ }
+ virtual bool cellular_available() const {
+ return available_devices_ & (1 << TYPE_CELLULAR);
}
-}
-
-void NetworkLibraryImpl::SaveCellularNetwork(const CellularNetwork& network) {
- // Update the wifi network in the local cache.
- CellularNetwork* cellular = GetWirelessNetworkByPath(cellular_networks_,
- network.service_path());
- if (cellular)
- *cellular = network;
- // Update the cellular network with libcros.
- if (CrosLibrary::Get()->EnsureLoaded()) {
- SetAutoConnect(network.service_path().c_str(), network.auto_connect());
+ virtual bool ethernet_enabled() const {
+ return enabled_devices_ & (1 << TYPE_ETHERNET);
+ }
+ virtual bool wifi_enabled() const {
+ return enabled_devices_ & (1 << TYPE_WIFI);
+ }
+ virtual bool cellular_enabled() const {
+ return enabled_devices_ & (1 << TYPE_CELLULAR);
}
-}
-void NetworkLibraryImpl::SaveWifiNetwork(const WifiNetwork& network) {
- // Update the wifi network in the local cache.
- WifiNetwork* wifi = GetWirelessNetworkByPath(wifi_networks_,
- network.service_path());
- if (wifi)
- *wifi = network;
+ virtual bool offline_mode() const { return offline_mode_; }
- // Update the wifi network with libcros.
- if (CrosLibrary::Get()->EnsureLoaded()) {
- SetPassphrase(network.service_path().c_str(), network.passphrase().c_str());
- SetIdentity(network.service_path().c_str(), network.identity().c_str());
- SetCertPath(network.service_path().c_str(), network.cert_path().c_str());
- SetAutoConnect(network.service_path().c_str(), network.auto_connect());
+ void EnableEthernetNetworkDevice(bool enable) {
+ EnableNetworkDeviceType(TYPE_ETHERNET, enable);
}
-}
-void NetworkLibraryImpl::ForgetWirelessNetwork(const WirelessNetwork& network) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- DeleteRememberedService(network.service_path().c_str());
+ void EnableWifiNetworkDevice(bool enable) {
+ EnableNetworkDeviceType(TYPE_WIFI, enable);
}
-}
-
-void NetworkLibraryImpl::EnableEthernetNetworkDevice(bool enable) {
- EnableNetworkDeviceType(TYPE_ETHERNET, enable);
-}
-
-void NetworkLibraryImpl::EnableWifiNetworkDevice(bool enable) {
- EnableNetworkDeviceType(TYPE_WIFI, enable);
-}
-void NetworkLibraryImpl::EnableCellularNetworkDevice(bool enable) {
- EnableNetworkDeviceType(TYPE_CELLULAR, enable);
-}
+ void EnableCellularNetworkDevice(bool enable) {
+ EnableNetworkDeviceType(TYPE_CELLULAR, enable);
+ }
-void NetworkLibraryImpl::EnableOfflineMode(bool enable) {
- if (!CrosLibrary::Get()->EnsureLoaded())
- return;
+ void EnableOfflineMode(bool enable) {
+ if (!CrosLibrary::Get()->EnsureLoaded())
+ return;
- // If network device is already enabled/disabled, then don't do anything.
- if (enable && offline_mode_) {
- LOG(INFO) << "Trying to enable offline mode when it's already enabled. ";
- return;
- }
- if (!enable && !offline_mode_) {
- LOG(INFO) << "Trying to disable offline mode when it's already disabled. ";
- return;
- }
+ // If network device is already enabled/disabled, then don't do anything.
+ if (enable && offline_mode_) {
+ LOG(INFO) << "Trying to enable offline mode when it's already enabled. ";
+ return;
+ }
+ if (!enable && !offline_mode_) {
+ LOG(INFO) <<
+ "Trying to disable offline mode when it's already disabled. ";
+ return;
+ }
- if (SetOfflineMode(enable)) {
- offline_mode_ = enable;
+ if (SetOfflineMode(enable)) {
+ offline_mode_ = enable;
+ }
}
-}
-NetworkIPConfigVector NetworkLibraryImpl::GetIPConfigs(
- const std::string& device_path) {
- NetworkIPConfigVector ipconfig_vector;
- if (!device_path.empty()) {
- IPConfigStatus* ipconfig_status = ListIPConfigs(device_path.c_str());
- if (ipconfig_status) {
- for (int i = 0; i < ipconfig_status->size; i++) {
- IPConfig ipconfig = ipconfig_status->ips[i];
- ipconfig_vector.push_back(
- NetworkIPConfig(device_path, ipconfig.type, ipconfig.address,
- ipconfig.netmask, ipconfig.gateway,
- ipconfig.name_servers));
+ NetworkIPConfigVector GetIPConfigs(const std::string& device_path) {
+ NetworkIPConfigVector ipconfig_vector;
+ if (!device_path.empty()) {
+ IPConfigStatus* ipconfig_status = ListIPConfigs(device_path.c_str());
+ if (ipconfig_status) {
+ for (int i = 0; i < ipconfig_status->size; i++) {
+ IPConfig ipconfig = ipconfig_status->ips[i];
+ ipconfig_vector.push_back(
+ NetworkIPConfig(device_path, ipconfig.type, ipconfig.address,
+ ipconfig.netmask, ipconfig.gateway,
+ ipconfig.name_servers));
+ }
+ FreeIPConfigStatus(ipconfig_status);
+ // Sort the list of ip configs by type.
+ std::sort(ipconfig_vector.begin(), ipconfig_vector.end());
}
- FreeIPConfigStatus(ipconfig_status);
- // Sort the list of ip configs by type.
- std::sort(ipconfig_vector.begin(), ipconfig_vector.end());
}
- }
- return ipconfig_vector;
-}
+ return ipconfig_vector;
+ }
+
+ std::string GetHtmlInfo(int refresh) {
+ std::string output;
+ output.append("<html><head><title>About Network</title>");
+ if (refresh > 0)
+ output.append("<meta http-equiv=\"refresh\" content=\"" +
+ base::IntToString(refresh) + "\"/>");
+ output.append("</head><body>");
+ if (refresh > 0) {
+ output.append("(Auto-refreshing page every " +
+ base::IntToString(refresh) + "s)");
+ } else {
+ output.append("(To auto-refresh this page: about:network/&lt;secs&gt;)");
+ }
-std::string NetworkLibraryImpl::GetHtmlInfo(int refresh) {
- std::string output;
- output.append("<html><head><title>About Network</title>");
- if (refresh > 0)
- output.append("<meta http-equiv=\"refresh\" content=\"" +
- IntToString(refresh) + "\"/>");
- output.append("</head><body>");
- if (refresh > 0)
- output.append("(Auto-refreshing page every " + IntToString(refresh) + "s)");
- else
- output.append("(To auto-refresh this page: about:network/&lt;secs&gt;)");
+ output.append("<h3>Ethernet:</h3><table border=1>");
+ if (ethernet_enabled()) {
+ output.append("<tr>" + ToHtmlTableHeader(&ethernet_) + "</tr>");
+ output.append("<tr>" + ToHtmlTableRow(&ethernet_) + "</tr>");
+ }
- output.append("<h3>Ethernet:</h3><table border=1>");
- output.append("<tr>" + ToHtmlTableHeader(&ethernet_) + "</tr>");
- output.append("<tr>" + ToHtmlTableRow(&ethernet_) + "</tr>");
+ output.append("</table><h3>Wifi:</h3><table border=1>");
+ for (size_t i = 0; i < wifi_networks_.size(); ++i) {
+ if (i == 0)
+ output.append("<tr>" + ToHtmlTableHeader(&wifi_networks_[i]) + "</tr>");
+ output.append("<tr>" + ToHtmlTableRow(&wifi_networks_[i]) + "</tr>");
+ }
- output.append("</table><h3>Wifi:</h3><table border=1>");
- for (size_t i = 0; i < wifi_networks_.size(); ++i) {
- if (i == 0)
- output.append("<tr>" + ToHtmlTableHeader(&wifi_networks_[i]) + "</tr>");
- output.append("<tr>" + ToHtmlTableRow(&wifi_networks_[i]) + "</tr>");
- }
+ output.append("</table><h3>Cellular:</h3><table border=1>");
+ for (size_t i = 0; i < cellular_networks_.size(); ++i) {
+ if (i == 0)
+ output.append("<tr>" + ToHtmlTableHeader(&cellular_networks_[i]) +
+ "</tr>");
+ output.append("<tr>" + ToHtmlTableRow(&cellular_networks_[i]) + "</tr>");
+ }
- output.append("</table><h3>Cellular:</h3><table border=1>");
- for (size_t i = 0; i < cellular_networks_.size(); ++i) {
- if (i == 0)
- output.append("<tr>" + ToHtmlTableHeader(&cellular_networks_[i]) +
+ output.append("</table><h3>Remembered Wifi:</h3><table border=1>");
+ for (size_t i = 0; i < remembered_wifi_networks_.size(); ++i) {
+ if (i == 0)
+ output.append(
+ "<tr>" + ToHtmlTableHeader(&remembered_wifi_networks_[i]) +
+ "</tr>");
+ output.append("<tr>" + ToHtmlTableRow(&remembered_wifi_networks_[i]) +
"</tr>");
- output.append("<tr>" + ToHtmlTableRow(&cellular_networks_[i]) + "</tr>");
- }
+ }
- output.append("</table><h3>Remembered Wifi:</h3><table border=1>");
- for (size_t i = 0; i < remembered_wifi_networks_.size(); ++i) {
- if (i == 0)
- output.append("<tr>" + ToHtmlTableHeader(&remembered_wifi_networks_[i]) +
+ output.append("</table><h3>Remembered Cellular:</h3><table border=1>");
+ for (size_t i = 0; i < remembered_cellular_networks_.size(); ++i) {
+ if (i == 0)
+ output.append("<tr>" +
+ ToHtmlTableHeader(&remembered_cellular_networks_[i]) + "</tr>");
+ output.append("<tr>" + ToHtmlTableRow(&remembered_cellular_networks_[i]) +
"</tr>");
- output.append("<tr>" + ToHtmlTableRow(&remembered_wifi_networks_[i]) +
- "</tr>");
- }
+ }
- output.append("</table><h3>Remembered Cellular:</h3><table border=1>");
- for (size_t i = 0; i < remembered_cellular_networks_.size(); ++i) {
- if (i == 0)
- output.append("<tr>" +
- ToHtmlTableHeader(&remembered_cellular_networks_[i]) + "</tr>");
- output.append("<tr>" + ToHtmlTableRow(&remembered_cellular_networks_[i]) +
- "</tr>");
+ output.append("</table></body></html>");
+ return output;
}
- output.append("</table></body></html>");
- return output;
-}
-
-// static
-void NetworkLibraryImpl::NetworkStatusChangedHandler(void* object) {
- NetworkLibraryImpl* network = static_cast<NetworkLibraryImpl*>(object);
- DCHECK(network);
- network->UpdateNetworkStatus();
-}
+ private:
+ static void NetworkStatusChangedHandler(void* object) {
+ NetworkLibraryImpl* network = static_cast<NetworkLibraryImpl*>(object);
+ DCHECK(network);
+ network->UpdateNetworkStatus();
+ }
-// static
-void NetworkLibraryImpl::ParseSystem(SystemInfo* system,
- EthernetNetwork* ethernet,
- WifiNetworkVector* wifi_networks,
- CellularNetworkVector* cellular_networks,
- WifiNetworkVector* remembered_wifi_networks,
- CellularNetworkVector* remembered_cellular_networks) {
- DLOG(INFO) << "ParseSystem:";
- ethernet->Clear();
- for (int i = 0; i < system->service_size; i++) {
- const ServiceInfo& service = system->services[i];
- DLOG(INFO) << " (" << service.type <<
- ") " << service.name <<
- " mode=" << service.mode <<
- " state=" << service.state <<
- " sec=" << service.security <<
- " req=" << service.passphrase_required <<
- " pass=" << service.passphrase <<
- " id=" << service.identity <<
- " certpath=" << service.cert_path <<
- " str=" << service.strength <<
- " fav=" << service.favorite <<
- " auto=" << service.auto_connect <<
- " error=" << service.error;
- // Once a connected ethernet service is found, disregard other ethernet
- // services that are also found
- if (service.type == TYPE_ETHERNET && !(ethernet->connected()))
- ethernet->ConfigureFromService(service);
- else if (service.type == TYPE_WIFI)
- wifi_networks->push_back(WifiNetwork(service));
- else if (service.type == TYPE_CELLULAR)
- cellular_networks->push_back(CellularNetwork(service));
- }
- DLOG(INFO) << "Remembered networks:";
- for (int i = 0; i < system->remembered_service_size; i++) {
- const ServiceInfo& service = system->remembered_services[i];
- // Only serices marked as auto_connect are considered remembered networks.
- // TODO(chocobo): Don't add to remembered service if currently available.
- if (service.auto_connect) {
+ static void ParseSystem(SystemInfo* system,
+ EthernetNetwork* ethernet,
+ WifiNetworkVector* wifi_networks,
+ CellularNetworkVector* cellular_networks,
+ WifiNetworkVector* remembered_wifi_networks,
+ CellularNetworkVector* remembered_cellular_networks) {
+ DLOG(INFO) << "ParseSystem:";
+ ethernet->Clear();
+ for (int i = 0; i < system->service_size; i++) {
+ const ServiceInfo service = *system->GetServiceInfo(i);
DLOG(INFO) << " (" << service.type <<
") " << service.name <<
" mode=" << service.mode <<
+ " state=" << service.state <<
" sec=" << service.security <<
+ " req=" << service.passphrase_required <<
" pass=" << service.passphrase <<
" id=" << service.identity <<
" certpath=" << service.cert_path <<
- " auto=" << service.auto_connect;
- if (service.type == TYPE_WIFI)
- remembered_wifi_networks->push_back(WifiNetwork(service));
+ " str=" << service.strength <<
+ " fav=" << service.favorite <<
+ " auto=" << service.auto_connect <<
+ " error=" << service.error;
+ // Once a connected ethernet service is found, disregard other ethernet
+ // services that are also found
+ if (service.type == TYPE_ETHERNET && !(ethernet->connected()))
+ ethernet->ConfigureFromService(service);
+ else if (service.type == TYPE_WIFI)
+ wifi_networks->push_back(WifiNetwork(service));
else if (service.type == TYPE_CELLULAR)
- remembered_cellular_networks->push_back(CellularNetwork(service));
+ cellular_networks->push_back(CellularNetwork(service));
+ }
+ DLOG(INFO) << "Remembered networks:";
+ for (int i = 0; i < system->remembered_service_size; i++) {
+ const ServiceInfo& service = *system->GetRememberedServiceInfo(i);
+ // Only serices marked as auto_connect are considered remembered networks.
+ // TODO(chocobo): Don't add to remembered service if currently available.
+ if (service.auto_connect) {
+ DLOG(INFO) << " (" << service.type <<
+ ") " << service.name <<
+ " mode=" << service.mode <<
+ " sec=" << service.security <<
+ " pass=" << service.passphrase <<
+ " id=" << service.identity <<
+ " certpath=" << service.cert_path <<
+ " auto=" << service.auto_connect;
+ if (service.type == TYPE_WIFI)
+ remembered_wifi_networks->push_back(WifiNetwork(service));
+ else if (service.type == TYPE_CELLULAR)
+ remembered_cellular_networks->push_back(CellularNetwork(service));
+ }
}
}
-}
-
-void NetworkLibraryImpl::Init() {
- // First, get the currently available networks. This data is cached
- // on the connman side, so the call should be quick.
- LOG(INFO) << "Getting initial CrOS network info.";
- UpdateSystemInfo();
- LOG(INFO) << "Registering for network status updates.";
- // Now, register to receive updates on network status.
- network_status_connection_ = MonitorNetwork(&NetworkStatusChangedHandler,
- this);
-}
+ void Init() {
+ // First, get the currently available networks. This data is cached
+ // on the connman side, so the call should be quick.
+ LOG(INFO) << "Getting initial CrOS network info.";
+ UpdateSystemInfo();
-void NetworkLibraryImpl::UpdateSystemInfo() {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- UpdateNetworkStatus();
+ LOG(INFO) << "Registering for network status updates.";
+ // Now, register to receive updates on network status.
+ network_status_connection_ = MonitorNetwork(&NetworkStatusChangedHandler,
+ this);
+ }
+
+ void InitTestData() {
+ ethernet_.Clear();
+ ethernet_.set_connected(true);
+
+ wifi_networks_.clear();
+ WifiNetwork wifi1 = WifiNetwork();
+ wifi1.set_service_path("fw1");
+ wifi1.set_name("Fake Wifi 1");
+ wifi1.set_strength(90);
+ wifi1.set_connected(false);
+ wifi1.set_encryption(SECURITY_NONE);
+ wifi_networks_.push_back(wifi1);
+
+ WifiNetwork wifi2 = WifiNetwork();
+ wifi2.set_service_path("fw2");
+ wifi2.set_name("Fake Wifi 2");
+ wifi2.set_strength(70);
+ wifi2.set_connected(true);
+ wifi2.set_encryption(SECURITY_WEP);
+ wifi_networks_.push_back(wifi2);
+
+ WifiNetwork wifi3 = WifiNetwork();
+ wifi3.set_service_path("fw3");
+ wifi3.set_name("Fake Wifi 3");
+ wifi3.set_strength(50);
+ wifi3.set_connected(false);
+ wifi3.set_encryption(SECURITY_WEP);
+ wifi_networks_.push_back(wifi3);
+
+ wifi_ = wifi2;
+
+ cellular_networks_.clear();
+
+ cellular_networks_.clear();
+ CellularNetwork cellular1 = CellularNetwork();
+ cellular1.set_service_path("fc1");
+ cellular1.set_name("Fake Cellular 1");
+ cellular1.set_strength(90);
+ cellular1.set_connected(false);
+ cellular_networks_.push_back(cellular1);
+
+ CellularNetwork cellular2 = CellularNetwork();
+ cellular2.set_service_path("fc2");
+ cellular2.set_name("Fake Cellular 2");
+ cellular2.set_strength(70);
+ cellular2.set_connected(true);
+ cellular_networks_.push_back(cellular2);
+
+ CellularNetwork cellular3 = CellularNetwork();
+ cellular3.set_service_path("fc3");
+ cellular3.set_name("Fake Cellular 3");
+ cellular3.set_strength(50);
+ cellular3.set_connected(false);
+ cellular_networks_.push_back(cellular3);
+
+ cellular_ = cellular2;
+
+ remembered_wifi_networks_.clear();
+ remembered_wifi_networks_.push_back(wifi2);
+
+ remembered_cellular_networks_.clear();
+ remembered_cellular_networks_.push_back(cellular2);
+
+ int devices = (1 << TYPE_ETHERNET) | (1 << TYPE_WIFI) |
+ (1 << TYPE_CELLULAR);
+ available_devices_ = devices;
+ enabled_devices_ = devices;
+ connected_devices_ = devices;
+ offline_mode_ = false;
+ }
+
+ void UpdateSystemInfo() {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ UpdateNetworkStatus();
+ }
}
-}
-
-WifiNetwork* NetworkLibraryImpl::GetPreferredNetwork() {
- // First look for Google-A then look for Google.
- // Only care if set to auto-connect.
- WifiNetwork* wifi = GetWifiNetworkByName(kGoogleAWifi);
- // If wifi found and set to not auto-connect, then ignore it.
- if (wifi && !wifi->auto_connect())
- wifi = NULL;
-
- if (!wifi) {
- wifi = GetWifiNetworkByName(kGoogleWifi);
- // If wifi found and set to not auto-connect, then ignore it.
- if (wifi && !wifi->auto_connect())
- wifi = NULL;
- }
- return wifi;
-}
-WifiNetwork* NetworkLibraryImpl::GetWifiNetworkByName(const std::string& name) {
- for (size_t i = 0; i < wifi_networks_.size(); ++i) {
- if (wifi_networks_[i].name().compare(name) == 0) {
- return &wifi_networks_[i];
+ WifiNetwork* GetWifiNetworkByName(const std::string& name) {
+ for (size_t i = 0; i < wifi_networks_.size(); ++i) {
+ if (wifi_networks_[i].name().compare(name) == 0) {
+ return &wifi_networks_[i];
+ }
}
+ return NULL;
}
- return NULL;
-}
-
-template<typename T> T* NetworkLibraryImpl::GetWirelessNetworkByPath(
- std::vector<T>& networks, const std::string& path) {
- typedef typename std::vector<T>::iterator iter_t;
- iter_t iter = std::find_if(networks.begin(), networks.end(),
- WirelessNetwork::ServicePathEq(path));
- return (iter != networks.end()) ? &(*iter) : NULL;
-}
-// const version
-template<typename T> const T* NetworkLibraryImpl::GetWirelessNetworkByPath(
- const std::vector<T>& networks, const std::string& path) const {
- typedef typename std::vector<T>::const_iterator iter_t;
- iter_t iter = std::find_if(networks.begin(), networks.end(),
- WirelessNetwork::ServicePathEq(path));
- return (iter != networks.end()) ? &(*iter) : NULL;
-}
-
-void NetworkLibraryImpl::EnableNetworkDeviceType(ConnectionType device,
- bool enable) {
- if (!CrosLibrary::Get()->EnsureLoaded())
- return;
-
- // If network device is already enabled/disabled, then don't do anything.
- if (enable && (enabled_devices_ & (1 << device))) {
- LOG(WARNING) << "Trying to enable a device that's already enabled: "
- << device;
- return;
+ template<typename T> T* GetWirelessNetworkByPath(
+ std::vector<T>& networks, const std::string& path) {
+ typedef typename std::vector<T>::iterator iter_t;
+ iter_t iter = std::find_if(networks.begin(), networks.end(),
+ WirelessNetwork::ServicePathEq(path));
+ return (iter != networks.end()) ? &(*iter) : NULL;
}
- if (!enable && !(enabled_devices_ & (1 << device))) {
- LOG(WARNING) << "Trying to disable a device that's already disabled: "
- << device;
- return;
- }
-
- EnableNetworkDevice(device, enable);
-}
-void NetworkLibraryImpl::UpdateNetworkStatus() {
- // Make sure we run on UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &NetworkLibraryImpl::UpdateNetworkStatus));
- return;
+ // const version
+ template<typename T> const T* GetWirelessNetworkByPath(
+ const std::vector<T>& networks, const std::string& path) const {
+ typedef typename std::vector<T>::const_iterator iter_t;
+ iter_t iter = std::find_if(networks.begin(), networks.end(),
+ WirelessNetwork::ServicePathEq(path));
+ return (iter != networks.end()) ? &(*iter) : NULL;
}
- SystemInfo* system = GetSystemInfo();
- if (!system)
- return;
-
- wifi_networks_.clear();
- cellular_networks_.clear();
- remembered_wifi_networks_.clear();
- remembered_cellular_networks_.clear();
- ParseSystem(system, &ethernet_, &wifi_networks_, &cellular_networks_,
- &remembered_wifi_networks_, &remembered_cellular_networks_);
+ void EnableNetworkDeviceType(ConnectionType device, bool enable) {
+ if (!CrosLibrary::Get()->EnsureLoaded())
+ return;
- wifi_ = WifiNetwork();
- for (size_t i = 0; i < wifi_networks_.size(); i++) {
- if (wifi_networks_[i].connecting_or_connected()) {
- wifi_ = wifi_networks_[i];
- break; // There is only one connected or connecting wifi network.
+ // If network device is already enabled/disabled, then don't do anything.
+ if (enable && (enabled_devices_ & (1 << device))) {
+ LOG(WARNING) << "Trying to enable a device that's already enabled: "
+ << device;
+ return;
}
- }
- cellular_ = CellularNetwork();
- for (size_t i = 0; i < cellular_networks_.size(); i++) {
- if (cellular_networks_[i].connecting_or_connected()) {
- cellular_ = cellular_networks_[i];
- break; // There is only one connected or connecting cellular network.
+ if (!enable && !(enabled_devices_ & (1 << device))) {
+ LOG(WARNING) << "Trying to disable a device that's already disabled: "
+ << device;
+ return;
}
+
+ EnableNetworkDevice(device, enable);
}
- available_devices_ = system->available_technologies;
- enabled_devices_ = system->enabled_technologies;
- connected_devices_ = system->connected_technologies;
- offline_mode_ = system->offline_mode;
+ void NotifyNetworkChanged() {
+ FOR_EACH_OBSERVER(Observer, observers_, NetworkChanged(this));
+ }
- FOR_EACH_OBSERVER(Observer, observers_, NetworkChanged(this));
- FreeSystemInfo(system);
-}
+ void UpdateNetworkStatus() {
+ // Make sure we run on UI thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &NetworkLibraryImpl::UpdateNetworkStatus));
+ return;
+ }
-void NetworkLibraryImpl::CheckNetworkTraffic(bool download) {
- // If we already have a pending upload and download notification, then
- // shortcut and return.
- if (traffic_type_ == (Observer::TRAFFIC_DOWNLOAD | Observer::TRAFFIC_UPLOAD))
- return;
- // Figure out if we are uploading and/or downloading. We are downloading
- // if download == true. We are uploading if we have upload progress.
- if (download)
- traffic_type_ |= Observer::TRAFFIC_DOWNLOAD;
- if ((traffic_type_ & Observer::TRAFFIC_UPLOAD) == 0) {
- URLRequestJobTracker::JobIterator it;
- for (it = g_url_request_job_tracker.begin();
- it != g_url_request_job_tracker.end();
- ++it) {
- URLRequestJob* job = *it;
- if (job->GetUploadProgress() > 0) {
- traffic_type_ |= Observer::TRAFFIC_UPLOAD;
- break;
+ SystemInfo* system = GetSystemInfo();
+ if (!system)
+ return;
+
+ wifi_networks_.clear();
+ cellular_networks_.clear();
+ remembered_wifi_networks_.clear();
+ remembered_cellular_networks_.clear();
+ ParseSystem(system, &ethernet_, &wifi_networks_, &cellular_networks_,
+ &remembered_wifi_networks_, &remembered_cellular_networks_);
+
+ wifi_ = WifiNetwork();
+ for (size_t i = 0; i < wifi_networks_.size(); i++) {
+ if (wifi_networks_[i].connecting_or_connected()) {
+ wifi_ = wifi_networks_[i];
+ break; // There is only one connected or connecting wifi network.
+ }
+ }
+ cellular_ = CellularNetwork();
+ for (size_t i = 0; i < cellular_networks_.size(); i++) {
+ if (cellular_networks_[i].connecting_or_connected()) {
+ cellular_ = cellular_networks_[i];
+ break; // There is only one connected or connecting cellular network.
}
}
- }
- // If we have new traffic data to send out and the timer is not currently
- // running, then start a new timer.
- if (traffic_type_ && !timer_.IsRunning()) {
- timer_.Start(base::TimeDelta::FromSeconds(kNetworkTrafficeTimerSecs), this,
- &NetworkLibraryImpl::NetworkTrafficTimerFired);
- }
-}
-void NetworkLibraryImpl:: NetworkTrafficTimerFired() {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &NetworkLibraryImpl::NotifyNetworkTraffic,
- traffic_type_));
- // Reset traffic type so that we don't send the same data next time.
- traffic_type_ = 0;
-}
+ available_devices_ = system->available_technologies;
+ enabled_devices_ = system->enabled_technologies;
+ connected_devices_ = system->connected_technologies;
+ offline_mode_ = system->offline_mode;
-void NetworkLibraryImpl::NotifyNetworkTraffic(int traffic_type) {
- FOR_EACH_OBSERVER(Observer, observers_, NetworkTraffic(this, traffic_type));
-}
+ NotifyNetworkChanged();
+ FreeSystemInfo(system);
+ }
-bool NetworkLibraryImpl::Connected() const {
- return ethernet_connected() || wifi_connected() || cellular_connected();
-}
+ ObserverList<Observer> observers_;
-bool NetworkLibraryImpl::Connecting() const {
- return ethernet_connecting() || wifi_connecting() || cellular_connecting();
-}
+ // The network status connection for monitoring network status changes.
+ MonitorNetworkConnection network_status_connection_;
-const std::string& NetworkLibraryImpl::IPAddress() const {
- // Returns highest priority IP address.
- if (ethernet_connected())
- return ethernet_.ip_address();
- if (wifi_connected())
- return wifi_.ip_address();
- if (cellular_connected())
- return cellular_.ip_address();
- return ethernet_.ip_address();
+ // The ethernet network.
+ EthernetNetwork ethernet_;
+
+ // The list of available wifi networks.
+ WifiNetworkVector wifi_networks_;
+
+ // The current connected (or connecting) wifi network.
+ WifiNetwork wifi_;
+
+ // The remembered wifi networks.
+ WifiNetworkVector remembered_wifi_networks_;
+
+ // The list of available cellular networks.
+ CellularNetworkVector cellular_networks_;
+
+ // The current connected (or connecting) cellular network.
+ CellularNetwork cellular_;
+
+ // The remembered cellular networks.
+ CellularNetworkVector remembered_cellular_networks_;
+
+ // The current available network devices. Bitwise flag of ConnectionTypes.
+ int available_devices_;
+
+ // The current enabled network devices. Bitwise flag of ConnectionTypes.
+ int enabled_devices_;
+
+ // The current connected network devices. Bitwise flag of ConnectionTypes.
+ int connected_devices_;
+
+ bool offline_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkLibraryImpl);
+};
+
+class NetworkLibraryStubImpl : public NetworkLibrary {
+ public:
+ NetworkLibraryStubImpl() : ip_address_("1.1.1.1") {}
+ ~NetworkLibraryStubImpl() {}
+ void AddObserver(Observer* observer) {}
+ void RemoveObserver(Observer* observer) {}
+ virtual const EthernetNetwork& ethernet_network() const {
+ return ethernet_;
+ }
+ virtual bool ethernet_connecting() const { return false; }
+ virtual bool ethernet_connected() const { return true; }
+ virtual const std::string& wifi_name() const { return EmptyString(); }
+ virtual bool wifi_connecting() const { return false; }
+ virtual bool wifi_connected() const { return false; }
+ virtual int wifi_strength() const { return 0; }
+
+ virtual const std::string& cellular_name() const { return EmptyString(); }
+ virtual bool cellular_connecting() const { return false; }
+ virtual bool cellular_connected() const { return false; }
+ virtual int cellular_strength() const { return false; }
+
+ bool Connected() const { return true; }
+ bool Connecting() const { return false; }
+ const std::string& IPAddress() const { return ip_address_; }
+ virtual const WifiNetworkVector& wifi_networks() const {
+ return wifi_networks_;
+ }
+ virtual const WifiNetworkVector& remembered_wifi_networks() const {
+ return wifi_networks_;
+ }
+ virtual const CellularNetworkVector& cellular_networks() const {
+ return cellular_networks_;
+ }
+ virtual const CellularNetworkVector& remembered_cellular_networks() const {
+ return cellular_networks_;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+
+ bool FindWifiNetworkByPath(
+ const std::string& path, WifiNetwork* result) const { return false; }
+ bool FindCellularNetworkByPath(
+ const std::string& path, CellularNetwork* result) const { return false; }
+ void RequestWifiScan() {}
+ bool GetWifiAccessPoints(WifiAccessPointVector* result) { return false; }
+
+ void ConnectToWifiNetwork(WifiNetwork network,
+ const std::string& password,
+ const std::string& identity,
+ const std::string& certpath) {}
+ void ConnectToWifiNetwork(const std::string& ssid,
+ const std::string& password,
+ const std::string& identity,
+ const std::string& certpath,
+ bool auto_connect) {}
+ void ConnectToCellularNetwork(CellularNetwork network) {}
+ void DisconnectFromWirelessNetwork(const WirelessNetwork& network) {}
+ void SaveCellularNetwork(const CellularNetwork& network) {}
+ void SaveWifiNetwork(const WifiNetwork& network) {}
+ void ForgetWirelessNetwork(const std::string& service_path) {}
+ virtual bool ethernet_available() const { return true; }
+ virtual bool wifi_available() const { return false; }
+ virtual bool cellular_available() const { return false; }
+ virtual bool ethernet_enabled() const { return true; }
+ virtual bool wifi_enabled() const { return false; }
+ virtual bool cellular_enabled() const { return false; }
+ virtual bool offline_mode() const { return false; }
+ void EnableEthernetNetworkDevice(bool enable) {}
+ void EnableWifiNetworkDevice(bool enable) {}
+ void EnableCellularNetworkDevice(bool enable) {}
+ void EnableOfflineMode(bool enable) {}
+ NetworkIPConfigVector GetIPConfigs(const std::string& device_path) {
+ return NetworkIPConfigVector();
+ }
+ std::string GetHtmlInfo(int refresh) { return std::string(); }
+ void UpdateSystemInfo() {}
+
+ private:
+ std::string ip_address_;
+ EthernetNetwork ethernet_;
+ WifiNetworkVector wifi_networks_;
+ CellularNetworkVector cellular_networks_;
+};
+
+// static
+NetworkLibrary* NetworkLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new NetworkLibraryStubImpl();
+ else
+ return new NetworkLibraryImpl();
}
} // namespace chromeos
+
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::NetworkLibraryImpl);
diff --git a/chrome/browser/chromeos/cros/network_library.h b/chrome/browser/chromeos/cros/network_library.h
index 9521a41..c10cc01 100644
--- a/chrome/browser/chromeos/cros/network_library.h
+++ b/chrome/browser/chromeos/cros/network_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_NETWORK_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_NETWORK_LIBRARY_H_
+#pragma once
#include <string>
#include <vector>
@@ -11,9 +12,7 @@
#include "base/observer_list.h"
#include "base/platform_thread.h"
#include "base/singleton.h"
-#include "base/string16.h"
#include "base/timer.h"
-#include "net/url_request/url_request_job_tracker.h"
#include "cros/chromeos_network.h"
namespace chromeos {
@@ -31,6 +30,8 @@ class Network {
bool failed() const { return state_ == STATE_FAILURE; }
ConnectionError error() const { return error_; }
+ void set_service_path(const std::string& service_path) {
+ service_path_ = service_path; }
void set_connecting(bool connecting) { state_ = (connecting ?
STATE_ASSOCIATION : STATE_IDLE); }
void set_connected(bool connected) { state_ = (connected ?
@@ -89,9 +90,12 @@ class WirelessNetwork : public Network {
const std::string& name() const { return name_; }
int strength() const { return strength_; }
bool auto_connect() const { return auto_connect_; }
+ bool favorite() const { return favorite_; }
void set_name(const std::string& name) { name_ = name; }
+ void set_strength(int strength) { strength_ = strength; }
void set_auto_connect(bool auto_connect) { auto_connect_ = auto_connect; }
+ void set_favorite(bool favorite) { favorite_ = favorite; }
// Network overrides.
virtual void Clear();
@@ -101,11 +105,13 @@ class WirelessNetwork : public Network {
WirelessNetwork()
: Network(),
strength_(0),
- auto_connect_(false) {}
+ auto_connect_(false),
+ favorite_(false) {}
std::string name_;
int strength_;
bool auto_connect_;
+ bool favorite_;
};
class CellularNetwork : public WirelessNetwork {
@@ -115,10 +121,29 @@ class CellularNetwork : public WirelessNetwork {
: WirelessNetwork() {
ConfigureFromService(service);
}
+ // Starts device activation process. Returns false if the device state does
+ // not permit activation.
+ bool StartActivation() const;
+ const ActivationState activation_state() const { return activation_state_; }
+ const std::string& payment_url() const { return payment_url_; }
+ const std::string& meid() const { return meid_; }
+ const std::string& imei() const { return imei_; }
+ const std::string& imsi() const { return imsi_; }
+ const std::string& esn() const { return esn_; }
+ const std::string& mdn() const { return mdn_; }
// WirelessNetwork overrides.
virtual void Clear();
virtual void ConfigureFromService(const ServiceInfo& service);
+
+ protected:
+ ActivationState activation_state_;
+ std::string payment_url_;
+ std::string meid_;
+ std::string imei_;
+ std::string imsi_;
+ std::string esn_;
+ std::string mdn_;
};
class WifiNetwork : public WirelessNetwork {
@@ -221,22 +246,15 @@ struct NetworkIPConfig {
};
typedef std::vector<NetworkIPConfig> NetworkIPConfigVector;
+// This class handles the interaction with the ChromeOS network library APIs.
+// Classes can add themselves as observers. Users can get an instance of the
+// library like this: chromeos::CrosLibrary::Get()->GetNetworkLibrary()
class NetworkLibrary {
public:
class Observer {
public:
- // A bitfield mask for traffic types.
- enum TrafficTypes {
- TRAFFIC_DOWNLOAD = 0x1,
- TRAFFIC_UPLOAD = 0x2,
- } TrafficTypeMasks;
-
// Called when the network has changed. (wifi networks, and ethernet)
virtual void NetworkChanged(NetworkLibrary* obj) = 0;
-
- // Called when network traffic has been detected.
- // Takes a bitfield of TrafficTypeMasks.
- virtual void NetworkTraffic(NetworkLibrary* obj, int traffic_type) = 0;
};
virtual ~NetworkLibrary() {}
@@ -301,18 +319,6 @@ class NetworkLibrary {
// Force an update of the system info.
virtual void UpdateSystemInfo() = 0;
- // Attempt to connect to the preferred network if available and it is set up.
- // This call will return true if connection is started.
- // If the preferred network is not available or not setup, returns false.
- // Note: For dogfood purposes, we hardcode the preferred network to Google-A.
- virtual bool ConnectToPreferredNetworkIfAvailable() = 0;
-
- // Returns true if we are currently connected to the preferred network.
- virtual bool PreferredNetworkConnected() = 0;
-
- // Returns true if we failed to connect to the preferred network.
- virtual bool PreferredNetworkFailed() = 0;
-
// Connect to the specified wireless network with password.
virtual void ConnectToWifiNetwork(WifiNetwork network,
const std::string& password,
@@ -338,7 +344,7 @@ class NetworkLibrary {
virtual void SaveWifiNetwork(const WifiNetwork& network) = 0;
// Forget the passed in wireless (either cellular or wifi) network.
- virtual void ForgetWirelessNetwork(const WirelessNetwork& network) = 0;
+ virtual void ForgetWirelessNetwork(const std::string& service_path) = 0;
virtual bool ethernet_available() const = 0;
virtual bool wifi_available() const = 0;
@@ -369,229 +375,10 @@ class NetworkLibrary {
// Fetches debug network info for display in about:network.
// The page will have a meta refresh of |refresh| seconds if |refresh| > 0.
virtual std::string GetHtmlInfo(int refresh) = 0;
-};
-
-// This class handles the interaction with the ChromeOS network library APIs.
-// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: NetworkLibrary::Get()
-class NetworkLibraryImpl : public NetworkLibrary,
- public URLRequestJobTracker::JobObserver {
- public:
- NetworkLibraryImpl();
- virtual ~NetworkLibraryImpl();
-
- // URLRequestJobTracker::JobObserver methods (called on the IO thread):
- virtual void OnJobAdded(URLRequestJob* job);
- virtual void OnJobRemoved(URLRequestJob* job);
- virtual void OnJobDone(URLRequestJob* job, const URLRequestStatus& status);
- virtual void OnJobRedirect(URLRequestJob* job, const GURL& location,
- int status_code);
- virtual void OnBytesRead(URLRequestJob* job, const char* buf, int byte_count);
-
- // NetworkLibrary overrides.
- virtual void AddObserver(Observer* observer);
- virtual void RemoveObserver(Observer* observer);
-
- virtual const EthernetNetwork& ethernet_network() const { return ethernet_; }
- virtual bool ethernet_connecting() const { return ethernet_.connecting(); }
- virtual bool ethernet_connected() const { return ethernet_.connected(); }
-
- virtual const std::string& wifi_name() const { return wifi_.name(); }
- virtual bool wifi_connecting() const { return wifi_.connecting(); }
- virtual bool wifi_connected() const { return wifi_.connected(); }
- virtual int wifi_strength() const { return wifi_.strength(); }
-
- virtual const std::string& cellular_name() const { return cellular_.name(); }
- virtual bool cellular_connecting() const { return cellular_.connecting(); }
- virtual bool cellular_connected() const { return cellular_.connected(); }
- virtual int cellular_strength() const { return cellular_.strength(); }
-
- virtual bool Connected() const;
- virtual bool Connecting() const;
- virtual const std::string& IPAddress() const;
-
- virtual const WifiNetworkVector& wifi_networks() const {
- return wifi_networks_;
- }
-
- virtual const WifiNetworkVector& remembered_wifi_networks() const {
- return remembered_wifi_networks_;
- }
-
- virtual const CellularNetworkVector& cellular_networks() const {
- return cellular_networks_;
- }
-
- virtual const CellularNetworkVector& remembered_cellular_networks() const {
- return remembered_cellular_networks_;
- }
-
- virtual bool FindWifiNetworkByPath(const std::string& path,
- WifiNetwork* network) const;
- virtual bool FindCellularNetworkByPath(const std::string& path,
- CellularNetwork* network) const;
-
- virtual void RequestWifiScan();
- virtual bool GetWifiAccessPoints(WifiAccessPointVector* result);
- virtual bool ConnectToPreferredNetworkIfAvailable();
- virtual bool PreferredNetworkConnected();
- virtual bool PreferredNetworkFailed();
- virtual void ConnectToWifiNetwork(WifiNetwork network,
- const std::string& password,
- const std::string& identity,
- const std::string& certpath);
- virtual void ConnectToWifiNetwork(const std::string& ssid,
- const std::string& password,
- const std::string& identity,
- const std::string& certpath,
- bool auto_connect);
- virtual void ConnectToCellularNetwork(CellularNetwork network);
- virtual void DisconnectFromWirelessNetwork(const WirelessNetwork& network);
- virtual void SaveCellularNetwork(const CellularNetwork& network);
- virtual void SaveWifiNetwork(const WifiNetwork& network);
- virtual void ForgetWirelessNetwork(const WirelessNetwork& network);
-
- virtual bool ethernet_available() const {
- return available_devices_ & (1 << TYPE_ETHERNET);
- }
- virtual bool wifi_available() const {
- return available_devices_ & (1 << TYPE_WIFI);
- }
- virtual bool cellular_available() const {
- return available_devices_ & (1 << TYPE_CELLULAR);
- }
-
- virtual bool ethernet_enabled() const {
- return enabled_devices_ & (1 << TYPE_ETHERNET);
- }
- virtual bool wifi_enabled() const {
- return enabled_devices_ & (1 << TYPE_WIFI);
- }
- virtual bool cellular_enabled() const {
- return enabled_devices_ & (1 << TYPE_CELLULAR);
- }
-
- virtual bool offline_mode() const { return offline_mode_; }
-
- virtual void EnableEthernetNetworkDevice(bool enable);
- virtual void EnableWifiNetworkDevice(bool enable);
- virtual void EnableCellularNetworkDevice(bool enable);
- virtual void EnableOfflineMode(bool enable);
- virtual NetworkIPConfigVector GetIPConfigs(const std::string& device_path);
- virtual std::string GetHtmlInfo(int refresh);
-
- virtual void UpdateSystemInfo();
-
- private:
-
- // This method is called when there's a change in network status.
- // This method is called on a background thread.
- static void NetworkStatusChangedHandler(void* object);
-
- // This parses SystemInfo into:
- // - an EthernetNetwork
- // - a WifiNetworkVector of wifi networks
- // - a CellularNetworkVector of cellular networks.
- // - a WifiNetworkVector of remembered wifi networks
- // - a CellularNetworkVector of remembered cellular networks.
- static void ParseSystem(SystemInfo* system,
- EthernetNetwork* ethernet,
- WifiNetworkVector* wifi_networks,
- CellularNetworkVector* ceullular_networks,
- WifiNetworkVector* remembered_wifi_networks,
- CellularNetworkVector* remembered_ceullular_networks);
-
- // This methods loads the initial list of networks on startup and starts the
- // monitoring of network changes.
- void Init();
-
- // Returns the preferred wifi network.
- WifiNetwork* GetPreferredNetwork();
-
- // Gets the WifiNetwork with the given name. Returns NULL if not found.
- // Only used by GetPreferredNetwork() to lookup "Google" and "GoogleA" (hack)
- WifiNetwork* GetWifiNetworkByName(const std::string& name);
-
- // Gets the WirelessNetwork (WifiNetwork or CellularNetwork) by path
- template<typename T>
- T* GetWirelessNetworkByPath(std::vector<T>& networks,
- const std::string& path);
- template<typename T>
- const T* GetWirelessNetworkByPath(const std::vector<T>& networks,
- const std::string& path) const;
-
- // Enables/disables the specified network device.
- void EnableNetworkDeviceType(ConnectionType device, bool enable);
-
- // Update the cached network status.
- // This will notify all the Observers.
- void UpdateNetworkStatus();
-
- // Checks network traffic to see if there is any uploading.
- // If there is download traffic, then true is passed in for download.
- // If there is network traffic then start timer that invokes
- // NetworkTrafficTimerFired.
- void CheckNetworkTraffic(bool download);
-
- // Called when the timer fires and we need to send out NetworkTraffic
- // notifications.
- void NetworkTrafficTimerFired();
-
- // This is a helper method to notify the observers on the UI thread.
- void NotifyNetworkTraffic(int traffic_type);
-
- // This will notify all obeservers on the UI thread.
- void NotifyObservers();
-
- ObserverList<Observer> observers_;
-
- // The amount of time to wait between each NetworkTraffic notifications.
- static const int kNetworkTrafficeTimerSecs;
-
- // Timer for sending NetworkTraffic notification every
- // kNetworkTrafficeTimerSecs seconds.
- base::OneShotTimer<NetworkLibraryImpl> timer_;
-
- // The current traffic type that will be sent out for the next NetworkTraffic
- // notification. This is a bitfield of TrafficTypeMasks.
- int traffic_type_;
-
- // The network status connection for monitoring network status changes.
- MonitorNetworkConnection network_status_connection_;
-
- // The ethernet network.
- EthernetNetwork ethernet_;
-
- // The list of available wifi networks.
- WifiNetworkVector wifi_networks_;
-
- // The current connected (or connecting) wifi network.
- WifiNetwork wifi_;
-
- // The remembered wifi networks.
- WifiNetworkVector remembered_wifi_networks_;
-
- // The list of available cellular networks.
- CellularNetworkVector cellular_networks_;
-
- // The current connected (or connecting) cellular network.
- CellularNetwork cellular_;
-
- // The remembered cellular networks.
- CellularNetworkVector remembered_cellular_networks_;
-
- // The current available network devices. Bitwise flag of ConnectionTypes.
- int available_devices_;
-
- // The current enabled network devices. Bitwise flag of ConnectionTypes.
- int enabled_devices_;
-
- // The current connected network devices. Bitwise flag of ConnectionTypes.
- int connected_devices_;
-
- bool offline_mode_;
- DISALLOW_COPY_AND_ASSIGN(NetworkLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static NetworkLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/power_library.cc b/chrome/browser/chromeos/cros/power_library.cc
index 42978aa..220cd4e 100644
--- a/chrome/browser/chromeos/cros/power_library.cc
+++ b/chrome/browser/chromeos/cros/power_library.cc
@@ -9,87 +9,129 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-// Allows InvokeLater without adding refcounting. This class is a Singleton and
-// won't be deleted until it's last InvokeLater is run.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::PowerLibraryImpl);
-
namespace chromeos {
-PowerLibraryImpl::PowerLibraryImpl()
- : power_status_connection_(NULL),
- status_(chromeos::PowerStatus()) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- Init();
+class PowerLibraryImpl : public PowerLibrary {
+ public:
+ PowerLibraryImpl()
+ : power_status_connection_(NULL),
+ status_(chromeos::PowerStatus()) {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ Init();
+ }
}
-}
-PowerLibraryImpl::~PowerLibraryImpl() {
- if (power_status_connection_) {
- chromeos::DisconnectPowerStatus(power_status_connection_);
+ ~PowerLibraryImpl() {
+ if (power_status_connection_) {
+ chromeos::DisconnectPowerStatus(power_status_connection_);
+ }
}
-}
-void PowerLibraryImpl::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
-void PowerLibraryImpl::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
-bool PowerLibraryImpl::line_power_on() const {
- return status_.line_power_on;
-}
+ bool line_power_on() const {
+ return status_.line_power_on;
+ }
-bool PowerLibraryImpl::battery_is_present() const {
- return status_.battery_is_present;
-}
+ bool battery_is_present() const {
+ return status_.battery_is_present;
+ }
-bool PowerLibraryImpl::battery_fully_charged() const {
- return status_.battery_state == chromeos::BATTERY_STATE_FULLY_CHARGED;
-}
+ bool battery_fully_charged() const {
+ return status_.battery_state == chromeos::BATTERY_STATE_FULLY_CHARGED;
+ }
-double PowerLibraryImpl::battery_percentage() const {
- return status_.battery_percentage;
-}
+ double battery_percentage() const {
+ return status_.battery_percentage;
+ }
-base::TimeDelta PowerLibraryImpl::battery_time_to_empty() const {
- return base::TimeDelta::FromSeconds(status_.battery_time_to_empty);
-}
+ base::TimeDelta battery_time_to_empty() const {
+ return base::TimeDelta::FromSeconds(status_.battery_time_to_empty);
+ }
-base::TimeDelta PowerLibraryImpl::battery_time_to_full() const {
- return base::TimeDelta::FromSeconds(status_.battery_time_to_full);
-}
+ base::TimeDelta battery_time_to_full() const {
+ return base::TimeDelta::FromSeconds(status_.battery_time_to_full);
+ }
-// static
-void PowerLibraryImpl::PowerStatusChangedHandler(void* object,
- const chromeos::PowerStatus& status) {
- PowerLibraryImpl* power = static_cast<PowerLibraryImpl*>(object);
- power->UpdatePowerStatus(status);
-}
+ private:
+ static void PowerStatusChangedHandler(void* object,
+ const chromeos::PowerStatus& status) {
+ PowerLibraryImpl* power = static_cast<PowerLibraryImpl*>(object);
+ power->UpdatePowerStatus(status);
+ }
-void PowerLibraryImpl::Init() {
- power_status_connection_ = chromeos::MonitorPowerStatus(
- &PowerStatusChangedHandler, this);
-}
+ void Init() {
+ power_status_connection_ = chromeos::MonitorPowerStatus(
+ &PowerStatusChangedHandler, this);
+ }
-void PowerLibraryImpl::UpdatePowerStatus(const chromeos::PowerStatus& status) {
- // Make sure we run on UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &PowerLibraryImpl::UpdatePowerStatus, status));
- return;
+ void UpdatePowerStatus(const chromeos::PowerStatus& status) {
+ // Make sure we run on UI thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &PowerLibraryImpl::UpdatePowerStatus, status));
+ return;
+ }
+
+ DLOG(INFO) << "Power" <<
+ " lpo=" << status.line_power_on <<
+ " sta=" << status.battery_state <<
+ " per=" << status.battery_percentage <<
+ " tte=" << status.battery_time_to_empty <<
+ " ttf=" << status.battery_time_to_full;
+ status_ = status;
+ FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(this));
}
- DLOG(INFO) << "Power" <<
- " lpo=" << status.line_power_on <<
- " sta=" << status.battery_state <<
- " per=" << status.battery_percentage <<
- " tte=" << status.battery_time_to_empty <<
- " ttf=" << status.battery_time_to_full;
- status_ = status;
- FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(this));
+ ObserverList<Observer> observers_;
+
+ // A reference to the battery power api, to allow callbacks when the battery
+ // status changes.
+ chromeos::PowerStatusConnection power_status_connection_;
+
+ // The latest power status.
+ chromeos::PowerStatus status_;
+
+ DISALLOW_COPY_AND_ASSIGN(PowerLibraryImpl);
+};
+
+class PowerLibraryStubImpl : public PowerLibrary {
+ public:
+ PowerLibraryStubImpl() {}
+ ~PowerLibraryStubImpl() {}
+ void AddObserver(Observer* observer) {}
+ void RemoveObserver(Observer* observer) {}
+ bool line_power_on() const { return false; }
+ bool battery_is_present() const { return false; }
+ bool battery_fully_charged() const { return false; }
+ double battery_percentage() const { return false; }
+ base::TimeDelta battery_time_to_empty() const {
+ return base::TimeDelta::FromSeconds(0);
+ }
+ base::TimeDelta battery_time_to_full() const {
+ return base::TimeDelta::FromSeconds(0);
+ }
+};
+
+// static
+PowerLibrary* PowerLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new PowerLibraryStubImpl();
+ else
+ return new PowerLibraryImpl();
}
} // namespace chromeos
+
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::PowerLibraryImpl);
+
diff --git a/chrome/browser/chromeos/cros/power_library.h b/chrome/browser/chromeos/cros/power_library.h
index 76ab81a..10e6df4 100644
--- a/chrome/browser/chromeos/cros/power_library.h
+++ b/chrome/browser/chromeos/cros/power_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_POWER_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_POWER_LIBRARY_H_
+#pragma once
#include "base/observer_list.h"
#include "base/singleton.h"
@@ -14,7 +15,7 @@ namespace chromeos {
// This interface defines interaction with the ChromeOS power library APIs.
// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: PowerLibrary::Get()
+// library class like this: chromeos::CrosLibrary::Get()->GetPowerLibrary()
class PowerLibrary {
public:
class Observer {
@@ -41,63 +42,10 @@ class PowerLibrary {
// The amount of time until battery is full.
virtual base::TimeDelta battery_time_to_full() const = 0;
-};
-
-
-// This class handles the interaction with the ChromeOS power library APIs.
-// Classes can add themselves as observers. Users can get an instance of this
-// library class like this: PowerLibrary::Get()
-class PowerLibraryImpl : public PowerLibrary {
- public:
- PowerLibraryImpl();
- virtual ~PowerLibraryImpl();
-
- // PowerLibrary overrides.
- virtual void AddObserver(Observer* observer);
- virtual void RemoveObserver(Observer* observer);
-
- // Whether or not the line power is connected.
- virtual bool line_power_on() const;
-
- // Whether or not the battery is fully charged..
- virtual bool battery_fully_charged() const;
-
- // The percentage (0-100) of remaining battery.
- virtual double battery_percentage() const;
-
- // Whether there is a battery present.
- virtual bool battery_is_present() const;
-
- // The amount of time until battery is empty.
- virtual base::TimeDelta battery_time_to_empty() const;
-
- // The amount of time until battery is full.
- virtual base::TimeDelta battery_time_to_full() const;
-
- private:
-
- // This method is called when there's a change in power status.
- // This method is called on a background thread.
- static void PowerStatusChangedHandler(void* object,
- const chromeos::PowerStatus& status);
-
- // This methods starts the monitoring of power changes.
- void Init();
-
- // Called by the handler to update the power status.
- // This will notify all the Observers.
- void UpdatePowerStatus(const chromeos::PowerStatus& status);
-
- ObserverList<Observer> observers_;
-
- // A reference to the battery power api, to allow callbacks when the battery
- // status changes.
- chromeos::PowerStatusConnection power_status_connection_;
-
- // The latest power status.
- chromeos::PowerStatus status_;
- DISALLOW_COPY_AND_ASSIGN(PowerLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static PowerLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/screen_lock_library.cc b/chrome/browser/chromeos/cros/screen_lock_library.cc
index 731ec43..0115683 100644
--- a/chrome/browser/chromeos/cros/screen_lock_library.cc
+++ b/chrome/browser/chromeos/cros/screen_lock_library.cc
@@ -9,135 +9,170 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-// Allows InvokeLater without adding refcounting. This class is a Singleton and
-// won't be deleted until it's last InvokeLater is run.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::ScreenLockLibraryImpl);
-
namespace chromeos {
-ScreenLockLibraryImpl::ScreenLockLibraryImpl() {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- Init();
+// This class handles the interaction with the ChromeOS screen lock APIs.
+class ScreenLockLibraryImpl : public ScreenLockLibrary {
+ public:
+ ScreenLockLibraryImpl() {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ Init();
+ }
}
-}
-ScreenLockLibraryImpl::~ScreenLockLibraryImpl() {
- if (screen_lock_connection_) {
- chromeos::DisconnectScreenLock(screen_lock_connection_);
+ ~ScreenLockLibraryImpl() {
+ if (screen_lock_connection_) {
+ chromeos::DisconnectScreenLock(screen_lock_connection_);
+ }
}
-}
-void ScreenLockLibraryImpl::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
-void ScreenLockLibraryImpl::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
-void ScreenLockLibraryImpl::NotifyScreenLockRequested() {
- // Make sure we run on IO thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(this,
- &ScreenLockLibraryImpl::NotifyScreenLockRequested));
- return;
+ void NotifyScreenLockRequested() {
+ // Make sure we run on IO thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &ScreenLockLibraryImpl::NotifyScreenLockRequested));
+ return;
+ }
+ chromeos::NotifyScreenLockRequested();
}
- chromeos::NotifyScreenLockRequested();
-}
-void ScreenLockLibraryImpl::NotifyScreenLockCompleted() {
- // Make sure we run on IO thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(this,
- &ScreenLockLibraryImpl::NotifyScreenLockCompleted));
- return;
+ void NotifyScreenLockCompleted() {
+ // Make sure we run on IO thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &ScreenLockLibraryImpl::NotifyScreenLockCompleted));
+ return;
+ }
+ chromeos::NotifyScreenLockCompleted();
}
- chromeos::NotifyScreenLockCompleted();
-}
-void ScreenLockLibraryImpl::NotifyScreenUnlockRequested() {
- // Make sure we run on IO thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(this,
- &ScreenLockLibraryImpl::NotifyScreenUnlockRequested));
- return;
+ void NotifyScreenUnlockRequested() {
+ // Make sure we run on IO thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &ScreenLockLibraryImpl::NotifyScreenUnlockRequested));
+ return;
+ }
+ chromeos::NotifyScreenUnlockRequested();
}
- chromeos::NotifyScreenUnlockRequested();
-}
-void ScreenLockLibraryImpl::NotifyScreenUnlockCompleted() {
- // Make sure we run on IO thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(this,
- &ScreenLockLibraryImpl::NotifyScreenUnlockCompleted));
- return;
+ void NotifyScreenUnlockCompleted() {
+ // Make sure we run on IO thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &ScreenLockLibraryImpl::NotifyScreenUnlockCompleted));
+ return;
+ }
+ chromeos::NotifyScreenUnlockCompleted();
}
- chromeos::NotifyScreenUnlockCompleted();
-}
-void ScreenLockLibraryImpl::Init() {
- screen_lock_connection_ = chromeos::MonitorScreenLock(
- &ScreenLockedHandler, this);
-}
+ private:
+ void Init() {
+ screen_lock_connection_ = chromeos::MonitorScreenLock(
+ &ScreenLockedHandler, this);
+ }
-void ScreenLockLibraryImpl::LockScreen() {
- // Make sure we run on UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &ScreenLockLibraryImpl::LockScreen));
- return;
+ void LockScreen() {
+ // Make sure we run on UI thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &ScreenLockLibraryImpl::LockScreen));
+ return;
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, LockScreen(this));
}
- FOR_EACH_OBSERVER(Observer, observers_, LockScreen(this));
-}
-void ScreenLockLibraryImpl::UnlockScreen() {
- // Make sure we run on UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &ScreenLockLibraryImpl::UnlockScreen));
- return;
+ void UnlockScreen() {
+ // Make sure we run on UI thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &ScreenLockLibraryImpl::UnlockScreen));
+ return;
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, UnlockScreen(this));
}
- FOR_EACH_OBSERVER(Observer, observers_, UnlockScreen(this));
-}
-void ScreenLockLibraryImpl::UnlockScreenFailed() {
- // Make sure we run on UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &ScreenLockLibraryImpl::UnlockScreenFailed));
- return;
+ void UnlockScreenFailed() {
+ // Make sure we run on UI thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &ScreenLockLibraryImpl::UnlockScreenFailed));
+ return;
+ }
+ FOR_EACH_OBSERVER(Observer, observers_, UnlockScreenFailed(this));
}
- FOR_EACH_OBSERVER(Observer, observers_, UnlockScreenFailed(this));
-}
-// static
-void ScreenLockLibraryImpl::ScreenLockedHandler(void* object,
- ScreenLockEvent event) {
- ScreenLockLibraryImpl* self = static_cast<ScreenLockLibraryImpl*>(object);
- switch (event) {
- case chromeos::LockScreen:
- self->LockScreen();
- break;
- case chromeos::UnlockScreen:
- self->UnlockScreen();
- break;
- case chromeos::UnlockScreenFailed:
- self->UnlockScreenFailed();
- break;
- default:
- NOTREACHED();
+ static void ScreenLockedHandler(void* object, ScreenLockEvent event) {
+ ScreenLockLibraryImpl* self = static_cast<ScreenLockLibraryImpl*>(object);
+ switch (event) {
+ case chromeos::LockScreen:
+ self->LockScreen();
+ break;
+ case chromeos::UnlockScreen:
+ self->UnlockScreen();
+ break;
+ case chromeos::UnlockScreenFailed:
+ self->UnlockScreenFailed();
+ break;
+ default:
+ NOTREACHED();
+ }
}
+
+ ObserverList<Observer> observers_;
+
+ // A reference to the screen lock api
+ chromeos::ScreenLockConnection screen_lock_connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLockLibraryImpl);
+};
+
+class ScreenLockLibraryStubImpl : public ScreenLockLibrary {
+ public:
+ ScreenLockLibraryStubImpl() {}
+ ~ScreenLockLibraryStubImpl() {}
+ void AddObserver(Observer* observer) {}
+ void RemoveObserver(Observer* observer) {}
+ void NotifyScreenLockRequested() {}
+ void NotifyScreenLockCompleted() {}
+ void NotifyScreenUnlockRequested() {}
+ void NotifyScreenUnlockCompleted() {}
+};
+
+// static
+ScreenLockLibrary* ScreenLockLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new ScreenLockLibraryStubImpl();
+ else
+ return new ScreenLockLibraryImpl();
}
} // namespace chromeos
+
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::ScreenLockLibraryImpl);
+
diff --git a/chrome/browser/chromeos/cros/screen_lock_library.h b/chrome/browser/chromeos/cros/screen_lock_library.h
index 829d156..251c6f4 100644
--- a/chrome/browser/chromeos/cros/screen_lock_library.h
+++ b/chrome/browser/chromeos/cros/screen_lock_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_SCREEN_LOCK_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_SCREEN_LOCK_LIBRARY_H_
+#pragma once
#include "base/observer_list.h"
#include "cros/chromeos_screen_lock.h"
@@ -34,48 +35,10 @@ class ScreenLockLibrary {
virtual void NotifyScreenUnlockRequested() = 0;
// Notifies PowerManager that screen is unlocked.
virtual void NotifyScreenUnlockCompleted() = 0;
-};
-
-// This class handles the interaction with the ChromeOS screen lock APIs.
-class ScreenLockLibraryImpl : public ScreenLockLibrary {
- public:
- ScreenLockLibraryImpl();
- virtual ~ScreenLockLibraryImpl();
-
- // ScreenLockLibrary implementations:
- virtual void AddObserver(Observer* observer);
- virtual void RemoveObserver(Observer* observer);
- virtual void NotifyScreenLockRequested();
- virtual void NotifyScreenLockCompleted();
- virtual void NotifyScreenUnlockRequested();
- virtual void NotifyScreenUnlockCompleted();
-
- private:
- // This method is called when PowerManager requests to lock the screen.
- // This method is called on a background thread.
- static void ScreenLockedHandler(void* object, ScreenLockEvent event);
-
- // This methods starts the monitoring of screen lock request.
- void Init();
-
- // Called by the handler to notify the screen lock request from
- // SessionManager.
- void LockScreen();
-
- // Called by the handler to notify the screen unlock request from
- // SessionManager.
- void UnlockScreen();
-
- // Called by the handler to notify the screen unlock request has been
- // failed.
- void UnlockScreenFailed();
-
- ObserverList<Observer> observers_;
-
- // A reference to the screen lock api
- chromeos::ScreenLockConnection screen_lock_connection_;
- DISALLOW_COPY_AND_ASSIGN(ScreenLockLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static ScreenLockLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/speech_synthesis_library.cc b/chrome/browser/chromeos/cros/speech_synthesis_library.cc
index 10194ee..0325c1f 100644
--- a/chrome/browser/chromeos/cros/speech_synthesis_library.cc
+++ b/chrome/browser/chromeos/cros/speech_synthesis_library.cc
@@ -11,24 +11,55 @@
namespace chromeos {
-bool SpeechSynthesisLibraryImpl::Speak(const char* text) {
- return chromeos::Speak(text);
-}
+class SpeechSynthesisLibraryImpl : public SpeechSynthesisLibrary {
+ public:
+ SpeechSynthesisLibraryImpl() {}
+ virtual ~SpeechSynthesisLibraryImpl() {}
-bool SpeechSynthesisLibraryImpl::SetSpeakProperties(const char* props) {
- return chromeos::SetSpeakProperties(props);
-}
+ bool Speak(const char* text) {
+ return chromeos::Speak(text);
+ }
-bool SpeechSynthesisLibraryImpl::StopSpeaking() {
- return chromeos::StopSpeaking();
-}
+ bool SetSpeakProperties(const char* props) {
+ return chromeos::SetSpeakProperties(props);
+ }
-bool SpeechSynthesisLibraryImpl::IsSpeaking() {
- return chromeos::IsSpeaking();
-}
+ bool StopSpeaking() {
+ return chromeos::StopSpeaking();
+ }
+
+ bool IsSpeaking() {
+ return chromeos::IsSpeaking();
+ }
+
+ void InitTts(InitStatusCallback callback) {
+ chromeos::InitTts(callback);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpeechSynthesisLibraryImpl);
+};
+
+class SpeechSynthesisLibraryStubImpl : public SpeechSynthesisLibrary {
+ public:
+ SpeechSynthesisLibraryStubImpl() {}
+ virtual ~SpeechSynthesisLibraryStubImpl() {}
+ bool Speak(const char* text) { return true; }
+ bool SetSpeakProperties(const char* props) { return true; }
+ bool StopSpeaking() { return true; }
+ bool IsSpeaking() { return false; }
+ void InitTts(InitStatusCallback callback) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpeechSynthesisLibraryStubImpl);
+};
-void SpeechSynthesisLibraryImpl::InitTts(InitStatusCallback callback) {
- chromeos::InitTts(callback);
+// static
+SpeechSynthesisLibrary* SpeechSynthesisLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new SpeechSynthesisLibraryStubImpl();
+ else
+ return new SpeechSynthesisLibraryImpl();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/speech_synthesis_library.h b/chrome/browser/chromeos/cros/speech_synthesis_library.h
index 10f2c11..5ba97d1 100644
--- a/chrome/browser/chromeos/cros/speech_synthesis_library.h
+++ b/chrome/browser/chromeos/cros/speech_synthesis_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_SPEECH_SYNTHESIS_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_SPEECH_SYNTHESIS_LIBRARY_H_
+#pragma once
#include "base/singleton.h"
@@ -26,23 +27,10 @@ class SpeechSynthesisLibrary {
// Starts the speech synthesis service and indicates through a callback if
// it started successfully.
virtual void InitTts(InitStatusCallback) = 0;
-};
-// This class handles the interaction with the ChromeOS login library APIs.
-class SpeechSynthesisLibraryImpl : public SpeechSynthesisLibrary {
- public:
- SpeechSynthesisLibraryImpl() {}
- virtual ~SpeechSynthesisLibraryImpl() {}
-
- // SpeechSynthesisLibrary overrides.
- virtual bool Speak(const char* text);
- virtual bool SetSpeakProperties(const char* props);
- virtual bool StopSpeaking();
- virtual bool IsSpeaking();
- virtual void InitTts(InitStatusCallback);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SpeechSynthesisLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static SpeechSynthesisLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/synaptics_library.cc b/chrome/browser/chromeos/cros/synaptics_library.cc
deleted file mode 100644
index 462be76..0000000
--- a/chrome/browser/chromeos/cros/synaptics_library.cc
+++ /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.
-
-#include "chrome/browser/chromeos/cros/synaptics_library.h"
-
-#include "base/message_loop.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/chromeos/cros/cros_library.h"
-
-namespace chromeos {
-
-void SynapticsLibraryImpl::SetBoolParameter(SynapticsParameter param,
- bool value) {
- SetParameter(param, value ? 1 : 0);
-}
-
-void SynapticsLibraryImpl::SetRangeParameter(SynapticsParameter param,
- int value) {
- if (value < 1)
- value = 1;
- if (value > 10)
- value = 10;
- SetParameter(param, value);
-}
-
-void SynapticsLibraryImpl::SetParameter(SynapticsParameter param, int value) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- // This calls SetSynapticsParameter in the cros library which is
- // potentially time consuming. So we run this on the FILE thread.
- ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
- NewRunnableFunction(&SetSynapticsParameter, param, value));
- }
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/synaptics_library.h b/chrome/browser/chromeos/cros/synaptics_library.h
deleted file mode 100644
index 3dfd69f..0000000
--- a/chrome/browser/chromeos/cros/synaptics_library.h
+++ /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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_CROS_SYNAPTICS_LIBRARY_H_
-#define CHROME_BROWSER_CHROMEOS_CROS_SYNAPTICS_LIBRARY_H_
-
-#include "base/singleton.h"
-#include "cros/chromeos_synaptics.h"
-
-namespace chromeos {
-
-// This interface defines interaction with the ChromeOS synaptics library APIs.
-// Users can get an instance of this library class like this:
-// SynapticsLibrary::Get()
-// For a list of SynapticsPrameters, see chromeos_synaptics.h
-// in third_party/cros or /usr/include/cros
-class SynapticsLibrary {
- public:
- virtual ~SynapticsLibrary() {}
- // Sets a boolean parameter. The actual call will be run on the FILE thread.
- virtual void SetBoolParameter(SynapticsParameter param, bool value) = 0;
-
- // Sets a range parameter. The actual call will be run on the FILE thread.
- // Value should be between 1 and 10 inclusive.
- virtual void SetRangeParameter(SynapticsParameter param, int value) = 0;
-};
-
-
-// This class handles the interaction with the ChromeOS synaptics library APIs.
-// Users can get an instance of this library class like this:
-// SynapticsLibrary::Get()
-// For a list of SynapticsPrameters, see chromeos_synaptics.h
-// in third_party/cros or /usr/include/cros
-class SynapticsLibraryImpl : public SynapticsLibrary {
- public:
- SynapticsLibraryImpl() {}
- virtual ~SynapticsLibraryImpl() {}
-
- // SynapticsLibrary overrides.
- virtual void SetBoolParameter(SynapticsParameter param, bool value);
- virtual void SetRangeParameter(SynapticsParameter param, int value);
-
- private:
-
- // This helper methods calls into the libcros library to set the parameter.
- // This call is run on the FILE thread.
- void SetParameter(SynapticsParameter param, int value);
-
- DISALLOW_COPY_AND_ASSIGN(SynapticsLibraryImpl);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_CROS_SYNAPTICS_LIBRARY_H_
diff --git a/chrome/browser/chromeos/cros/syslogs_library.cc b/chrome/browser/chromeos/cros/syslogs_library.cc
index 365e9fe..9fed176 100644
--- a/chrome/browser/chromeos/cros/syslogs_library.cc
+++ b/chrome/browser/chromeos/cros/syslogs_library.cc
@@ -10,11 +10,74 @@
namespace chromeos {
-LogDictionaryType* SyslogsLibraryImpl::GetSyslogs(FilePath* tmpfilename) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- return chromeos::GetSystemLogs(tmpfilename);
+class SyslogsLibraryImpl : public SyslogsLibrary {
+ public:
+ SyslogsLibraryImpl() {}
+ virtual ~SyslogsLibraryImpl() {}
+
+ virtual Handle RequestSyslogs(FilePath* tmpfilename,
+ CancelableRequestConsumerBase* consumer,
+ ReadCompleteCallback* callback) {
+ // Register the callback request.
+ scoped_refptr<CancelableRequest<ReadCompleteCallback> > request(
+ new CancelableRequest<ReadCompleteCallback>(callback));
+ AddRequest(request, consumer);
+
+ // Schedule a task on the FILE thread which will then trigger a request
+ // callback on the calling thread (e.g. UI) when complete.
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &SyslogsLibraryImpl::ReadSyslogs, request, tmpfilename));
+
+ return request->handle();
+ }
+
+ private:
+ // Called from FILE thread.
+ void ReadSyslogs(
+ scoped_refptr<CancelableRequest<ReadCompleteCallback> > request,
+ FilePath* tmpfilename) {
+ if (request->canceled())
+ return;
+
+ LogDictionaryType* logs = NULL;
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ logs = chromeos::GetSystemLogs(tmpfilename);
+ }
+
+ // Will call the callback on the calling thread.
+ request->ForwardResult(Tuple1<LogDictionaryType*>(logs));
}
- return NULL;
+
+ DISALLOW_COPY_AND_ASSIGN(SyslogsLibraryImpl);
+};
+
+class SyslogsLibraryStubImpl : public SyslogsLibrary {
+ public:
+ SyslogsLibraryStubImpl() {}
+ virtual ~SyslogsLibraryStubImpl() {}
+
+ virtual Handle RequestSyslogs(FilePath* tmpfilename,
+ CancelableRequestConsumerBase* consumer,
+ ReadCompleteCallback* callback) {
+ if (callback)
+ callback->Run(Tuple1<LogDictionaryType*>(NULL));
+
+ return 0;
+ }
+};
+
+// static
+SyslogsLibrary* SyslogsLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new SyslogsLibraryStubImpl();
+ else
+ return new SyslogsLibraryImpl();
}
} // namespace chromeos
+
+// Allows InvokeLater without adding refcounting. SyslogsLibraryImpl is a
+// Singleton and won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::SyslogsLibraryImpl);
diff --git a/chrome/browser/chromeos/cros/syslogs_library.h b/chrome/browser/chromeos/cros/syslogs_library.h
index e29824c..56a07f7 100644
--- a/chrome/browser/chromeos/cros/syslogs_library.h
+++ b/chrome/browser/chromeos/cros/syslogs_library.h
@@ -4,33 +4,36 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_SYSLOGS_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_SYSLOGS_LIBRARY_H_
+#pragma once
#include "base/singleton.h"
+#include "chrome/browser/cancelable_request.h"
#include "cros/chromeos_syslogs.h"
+class CancelableRequestConsumerBase;
+
namespace chromeos {
// This interface defines interaction with the ChromeOS syslogs APIs.
-class SyslogsLibrary {
+class SyslogsLibrary : public CancelableRequestProvider {
public:
+ typedef Callback1<LogDictionaryType*>::Type ReadCompleteCallback;
+
SyslogsLibrary() {}
virtual ~SyslogsLibrary() {}
- // System logs gathered for userfeedback
- virtual LogDictionaryType* GetSyslogs(FilePath* tmpfilename) = 0;
-};
-
-
-// This class handles the interaction with the ChromeOS syslogs APIs.
-class SyslogsLibraryImpl : public SyslogsLibrary {
- public:
- SyslogsLibraryImpl() {}
- virtual ~SyslogsLibraryImpl() {}
-
- virtual LogDictionaryType* GetSyslogs(FilePath* tmpfilename);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SyslogsLibraryImpl);
+ // Request system logs. Read happens on the FILE thread and callback is
+ // called on the thread this is called from (via ForwardResult).
+ // Logs are owned by callback function (use delete when done with them).
+ // Returns the request handle. Call CancelRequest(Handle) to cancel
+ // the request before the callback gets called.
+ virtual Handle RequestSyslogs(FilePath* tmpfilename,
+ CancelableRequestConsumerBase* consumer,
+ ReadCompleteCallback* callback) = 0;
+
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static SyslogsLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/system_library.cc b/chrome/browser/chromeos/cros/system_library.cc
index 7f528d1..b14e38e 100644
--- a/chrome/browser/chromeos/cros/system_library.cc
+++ b/chrome/browser/chromeos/cros/system_library.cc
@@ -4,52 +4,129 @@
#include "chrome/browser/chromeos/cros/system_library.h"
+#include <map>
+
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
namespace chromeos {
-SystemLibraryImpl::SystemLibraryImpl() {
- std::string id = "US/Pacific";
- if (CrosLibrary::Get()->EnsureLoaded()) {
- std::string timezone_id = chromeos::GetTimezoneID();
- if (timezone_id.empty()) {
- LOG(ERROR) << "Got an empty string for timezone, default to " << id;
- } else {
- id = timezone_id;
+class SystemLibraryImpl : public SystemLibrary {
+ public:
+ typedef std::map<std::string, std::string> StringMap;
+
+ SystemLibraryImpl() {
+ // Get Statistics
+ UpdateMachineStatistics();
+ // Get Timezone
+ std::string id = "US/Pacific";
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ std::string timezone_id = chromeos::GetTimezoneID();
+ if (timezone_id.empty()) {
+ LOG(ERROR) << "Got an empty string for timezone, default to " << id;
+ } else {
+ id = timezone_id;
+ }
}
+ icu::TimeZone* timezone =
+ icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(id));
+ timezone_.reset(timezone);
+ icu::TimeZone::setDefault(*timezone);
+ LOG(INFO) << "Timezone is " << id;
}
- icu::TimeZone* timezone =
- icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(id));
- timezone_.reset(timezone);
- icu::TimeZone::setDefault(*timezone);
- LOG(INFO) << "Timezone is " << id;
-}
-void SystemLibraryImpl::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
-void SystemLibraryImpl::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
-const icu::TimeZone& SystemLibraryImpl::GetTimezone() {
- return *timezone_.get();
-}
+ const icu::TimeZone& GetTimezone() {
+ return *timezone_.get();
+ }
+
+ void SetTimezone(const icu::TimeZone* timezone) {
+ timezone_.reset(timezone->clone());
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ icu::UnicodeString unicode;
+ timezone->getID(unicode);
+ std::string id;
+ UTF16ToUTF8(unicode.getBuffer(), unicode.length(), &id);
+ LOG(INFO) << "Setting timezone to " << id;
+ chromeos::SetTimezoneID(id);
+ }
+ icu::TimeZone::setDefault(*timezone);
+ FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(*timezone));
+ }
+
+ bool GetMachineStatistic(const std::string& name, std::string* result) {
+ StringMap::iterator iter = machine_info_.find(name);
+ if (iter != machine_info_.end()) {
+ *result = iter->second;
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ void UpdateMachineStatistics() {
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ chromeos::MachineInfo* machine_info = chromeos::GetMachineInfo();
+ if (!machine_info) {
+ LOG(ERROR) << "Error calling chromeos::GetMachineInfo().";
+ return;
+ }
+ // Get Name Value pairs.
+ for (int i = 0; i<machine_info->name_value_size; ++i) {
+ const chromeos::MachineInfo::NVPair& nv = machine_info->name_values[i];
+ machine_info_[nv.name] = nv.value;
+ }
+ chromeos::FreeMachineInfo(machine_info);
+ }
+ }
+
+ scoped_ptr<icu::TimeZone> timezone_;
+ ObserverList<Observer> observers_;
+ StringMap machine_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemLibraryImpl);
+};
+
+class SystemLibraryStubImpl : public SystemLibrary {
+ public:
+ SystemLibraryStubImpl() {
+ std::string id = "US/Pacific";
+ icu::TimeZone* timezone =
+ icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(id));
+ timezone_.reset(timezone);
+ }
+ ~SystemLibraryStubImpl() {}
+
+ void AddObserver(Observer* observer) {}
+ void RemoveObserver(Observer* observer) {}
+ const icu::TimeZone& GetTimezone() {
+ return *timezone_.get();
+ }
+ void SetTimezone(const icu::TimeZone* timezone) {}
+
+ bool GetMachineStatistic(const std::string& name, std::string* result) {
+ *result = "Stub Statistic:" + name;
+ return true;
+ }
+
+ private:
+ scoped_ptr<icu::TimeZone> timezone_;
+ DISALLOW_COPY_AND_ASSIGN(SystemLibraryStubImpl);
+};
-void SystemLibraryImpl::SetTimezone(const icu::TimeZone* timezone) {
- timezone_.reset(timezone->clone());
- if (CrosLibrary::Get()->EnsureLoaded()) {
- icu::UnicodeString unicode;
- timezone->getID(unicode);
- std::string id;
- UTF16ToUTF8(unicode.getBuffer(), unicode.length(), &id);
- LOG(INFO) << "Setting timezone to " << id;
- chromeos::SetTimezoneID(id);
- }
- icu::TimeZone::setDefault(*timezone);
- FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(*timezone));
+// static
+SystemLibrary* SystemLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new SystemLibraryStubImpl();
+ else
+ return new SystemLibraryImpl();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/system_library.h b/chrome/browser/chromeos/cros/system_library.h
index b33eb3d..9cf6640 100644
--- a/chrome/browser/chromeos/cros/system_library.h
+++ b/chrome/browser/chromeos/cros/system_library.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_SYSTEM_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_SYSTEM_LIBRARY_H_
+#pragma once
#include "base/observer_list.h"
-#include "base/scoped_ptr.h"
#include "base/singleton.h"
#include "cros/chromeos_system.h"
#include "unicode/timezone.h"
@@ -32,26 +32,15 @@ class SystemLibrary {
// Sets the current timezone. |timezone| must be non-null.
virtual void SetTimezone(const icu::TimeZone* timezone) = 0;
-};
-
-// This class handles the interaction with the ChromeOS syslogs APIs.
-class SystemLibraryImpl : public SystemLibrary {
- public:
- SystemLibraryImpl();
- virtual ~SystemLibraryImpl() {}
-
- // NetworkLibrary overrides.
- virtual void AddObserver(Observer* observer);
- virtual void RemoveObserver(Observer* observer);
-
- virtual const icu::TimeZone& GetTimezone();
- virtual void SetTimezone(const icu::TimeZone*);
- private:
- scoped_ptr<icu::TimeZone> timezone_;
- ObserverList<Observer> observers_;
+ // Retrieve the named machine statistic (e.g. "hardware_class").
+ // This does not update the statistcs (i.e. does not call into libcros).
+ virtual bool GetMachineStatistic(const std::string& name,
+ std::string* result) = 0;
- DISALLOW_COPY_AND_ASSIGN(SystemLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static SystemLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/update_library.cc b/chrome/browser/chromeos/cros/update_library.cc
index 0ea5f2c..26a11ef 100644
--- a/chrome/browser/chromeos/cros/update_library.cc
+++ b/chrome/browser/chromeos/cros/update_library.cc
@@ -9,60 +9,114 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-// Allows InvokeLater without adding refcounting. This class is a Singleton and
-// won't be deleted until it's last InvokeLater is run.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::UpdateLibraryImpl);
-
namespace chromeos {
-UpdateLibraryImpl::UpdateLibraryImpl()
+class UpdateLibraryImpl : public UpdateLibrary {
+ public:
+ UpdateLibraryImpl()
: status_connection_(NULL) {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- Init();
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ Init();
+ }
}
-}
-UpdateLibraryImpl::~UpdateLibraryImpl() {
- if (status_connection_) {
- DisconnectUpdateProgress(status_connection_);
+ ~UpdateLibraryImpl() {
+ if (status_connection_) {
+ DisconnectUpdateProgress(status_connection_);
+ }
}
-}
-void UpdateLibraryImpl::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
-void UpdateLibraryImpl::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
-const UpdateLibrary::Status& UpdateLibraryImpl::status() const {
- return status_;
-}
+ bool CheckForUpdate() {
+ if (!CrosLibrary::Get()->EnsureLoaded())
+ return false;
-// static
-void UpdateLibraryImpl::ChangedHandler(void* object,
- const UpdateProgress& status) {
- UpdateLibraryImpl* power = static_cast<UpdateLibraryImpl*>(object);
- power->UpdateStatus(Status(status));
-}
+ return InitiateUpdateCheck();
+ }
-void UpdateLibraryImpl::Init() {
- status_connection_ = MonitorUpdateStatus(&ChangedHandler, this);
-}
+ bool RebootAfterUpdate() {
+ if (!CrosLibrary::Get()->EnsureLoaded())
+ return false;
+
+ return RebootIfUpdated();
+ }
+
+ const UpdateLibrary::Status& status() const {
+ return status_;
+ }
-void UpdateLibraryImpl::UpdateStatus(const Status& status) {
- // Make sure we run on UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &UpdateLibraryImpl::UpdateStatus, status));
- return;
+ private:
+ static void ChangedHandler(void* object,
+ const UpdateProgress& status) {
+ UpdateLibraryImpl* updater = static_cast<UpdateLibraryImpl*>(object);
+ updater->UpdateStatus(Status(status));
}
- status_ = status;
- FOR_EACH_OBSERVER(Observer, observers_, Changed(this));
+ void Init() {
+ status_connection_ = MonitorUpdateStatus(&ChangedHandler, this);
+ }
+
+ void UpdateStatus(const Status& status) {
+ // Make sure we run on UI thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &UpdateLibraryImpl::UpdateStatus, status));
+ return;
+ }
+
+ status_ = status;
+ FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(this));
+ }
+
+ ObserverList<Observer> observers_;
+
+ // A reference to the update api, to allow callbacks when the update
+ // status changes.
+ UpdateStatusConnection status_connection_;
+
+ // The latest power status.
+ Status status_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateLibraryImpl);
+};
+
+class UpdateLibraryStubImpl : public UpdateLibrary {
+ public:
+ UpdateLibraryStubImpl() {}
+ ~UpdateLibraryStubImpl() {}
+ void AddObserver(Observer* observer) {}
+ void RemoveObserver(Observer* observer) {}
+ bool CheckForUpdate() { return false; }
+ bool RebootAfterUpdate() { return false; }
+ const UpdateLibrary::Status& status() const {
+ return status_;
+ }
+
+ private:
+ Status status_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateLibraryStubImpl);
+};
+
+// static
+UpdateLibrary* UpdateLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new UpdateLibraryStubImpl();
+ else
+ return new UpdateLibraryImpl();
}
} // namespace chromeos
+// Allows InvokeLater without adding refcounting. This class is a Singleton and
+// won't be deleted until it's last InvokeLater is run.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::UpdateLibraryImpl);
+
diff --git a/chrome/browser/chromeos/cros/update_library.h b/chrome/browser/chromeos/cros/update_library.h
index c57e7bd..7b95815 100644
--- a/chrome/browser/chromeos/cros/update_library.h
+++ b/chrome/browser/chromeos/cros/update_library.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_UPDATE_LIBRARY_H_
#define CHROME_BROWSER_CHROMEOS_CROS_UPDATE_LIBRARY_H_
+#pragma once
#include <string>
@@ -52,50 +53,26 @@ class UpdateLibrary {
class Observer {
public:
virtual ~Observer() { }
- virtual void Changed(UpdateLibrary* obj) = 0;
+ virtual void UpdateStatusChanged(UpdateLibrary* library) = 0;
};
+// static UpdateLibrary* GetStubImplementation();
+
virtual ~UpdateLibrary() {}
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
- virtual const Status& status() const = 0;
-};
-
-class UpdateLibraryImpl : public UpdateLibrary {
- public:
- UpdateLibraryImpl();
- virtual ~UpdateLibraryImpl();
-
- // UpdateLibrary overrides.
- virtual void AddObserver(Observer* observer);
- virtual void RemoveObserver(Observer* observer);
-
- virtual const Status& status() const;
+ // Initiates update check and returns true if check was initiated.
+ virtual bool CheckForUpdate() = 0;
- private:
+ // Reboots if update has been performed.
+ virtual bool RebootAfterUpdate() = 0;
- // This method is called when there's a change in status.
- // This method is called on a background thread.
- static void ChangedHandler(void* object, const UpdateProgress& status);
-
- // This methods starts the monitoring of power changes.
- void Init();
-
- // Called by the handler to update the power status.
- // This will notify all the Observers.
- void UpdateStatus(const Status& status);
-
- ObserverList<Observer> observers_;
-
- // A reference to the update api, to allow callbacks when the update
- // status changes.
- UpdateStatusConnection status_connection_;
-
- // The latest power status.
- Status status_;
+ virtual const Status& status() const = 0;
- DISALLOW_COPY_AND_ASSIGN(UpdateLibraryImpl);
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static UpdateLibrary* GetImpl(bool stub);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros_settings.cc b/chrome/browser/chromeos/cros_settings.cc
index 852ad9d..a0e1297 100644
--- a/chrome/browser/chromeos/cros_settings.cc
+++ b/chrome/browser/chromeos/cros_settings.cc
@@ -6,38 +6,63 @@
#include "base/singleton.h"
#include "base/string_util.h"
-#include "chrome/browser/chromeos/mock_cros_settings.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/cros_settings_provider.h"
+#include "chrome/browser/chromeos/cros_settings_provider_user.h"
+#include "chrome/common/notification_service.h"
namespace chromeos {
CrosSettings* CrosSettings::Get() {
// TODO(xiyaun): Use real stuff when underlying libcros is ready.
- return Singleton<MockCrosSettings>::get();
+ return Singleton<CrosSettings>::get();
}
-bool CrosSettings::IsCrosSettings(const std::wstring& path) {
- return StartsWith(path, kCrosSettingsPrefix, true);
+bool CrosSettings::IsCrosSettings(const std::string& path) {
+ return StartsWithASCII(path, kCrosSettingsPrefix, true);
}
-void CrosSettings::SetBoolean(const std::wstring& path, bool in_value) {
+void CrosSettings::FireObservers(const char* path) {
+ DCHECK(CalledOnValidThread());
+ std::string path_str(path);
+ SettingsObserverMap::iterator observer_iterator =
+ settings_observers_.find(path_str);
+ if (observer_iterator == settings_observers_.end())
+ return;
+
+ NotificationObserverList::Iterator it(*(observer_iterator->second));
+ NotificationObserver* observer;
+ while ((observer = it.GetNext()) != NULL) {
+ observer->Observe(NotificationType::SYSTEM_SETTING_CHANGED,
+ Source<CrosSettings>(this),
+ Details<std::string>(&path_str));
+ }
+}
+
+void CrosSettings::SetBoolean(const std::string& path, bool in_value) {
+ DCHECK(CalledOnValidThread());
Set(path, Value::CreateBooleanValue(in_value));
}
-void CrosSettings::SetInteger(const std::wstring& path, int in_value) {
+void CrosSettings::SetInteger(const std::string& path, int in_value) {
+ DCHECK(CalledOnValidThread());
Set(path, Value::CreateIntegerValue(in_value));
}
-void CrosSettings::SetReal(const std::wstring& path, double in_value) {
+void CrosSettings::SetReal(const std::string& path, double in_value) {
+ DCHECK(CalledOnValidThread());
Set(path, Value::CreateRealValue(in_value));
}
-void CrosSettings::SetString(const std::wstring& path,
+void CrosSettings::SetString(const std::string& path,
const std::string& in_value) {
+ DCHECK(CalledOnValidThread());
Set(path, Value::CreateStringValue(in_value));
}
-bool CrosSettings::GetBoolean(const std::wstring& path,
+bool CrosSettings::GetBoolean(const std::string& path,
bool* bool_value) const {
+ DCHECK(CalledOnValidThread());
Value* value;
if (!Get(path, &value))
return false;
@@ -45,8 +70,105 @@ bool CrosSettings::GetBoolean(const std::wstring& path,
return value->GetAsBoolean(bool_value);
}
-bool CrosSettings::GetInteger(const std::wstring& path,
+bool CrosSettings::AddSettingsProvider(CrosSettingsProvider* provider) {
+ DCHECK(CalledOnValidThread());
+ providers_.push_back(provider);
+ return true;
+}
+
+bool CrosSettings::RemoveSettingsProvider(CrosSettingsProvider* provider) {
+ DCHECK(CalledOnValidThread());
+ std::vector<CrosSettingsProvider*>::iterator it =
+ std::find(providers_.begin(), providers_.end(), provider);
+ if (it != providers_.end()) {
+ providers_.erase(it);
+ return true;
+ }
+ return false;
+}
+
+void CrosSettings::AddSettingsObserver(const char* path,
+ NotificationObserver* obs) {
+ DCHECK(path);
+ DCHECK(obs);
+ DCHECK(CalledOnValidThread());
+
+ if (!GetProvider(std::string(path))) {
+ NOTREACHED() << "Trying to add an observer for an unregistered setting: "
+ << path;
+ return;
+ }
+
+ // Get the settings observer list associated with the path.
+ NotificationObserverList* observer_list = NULL;
+ SettingsObserverMap::iterator observer_iterator =
+ settings_observers_.find(path);
+ if (observer_iterator == settings_observers_.end()) {
+ observer_list = new NotificationObserverList;
+ settings_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 CrosSettings::RemoveSettingsObserver(const char* path,
+ NotificationObserver* obs) {
+ DCHECK(CalledOnValidThread());
+
+ SettingsObserverMap::iterator observer_iterator =
+ settings_observers_.find(path);
+ if (observer_iterator == settings_observers_.end()) {
+ return;
+ }
+
+ NotificationObserverList* observer_list = observer_iterator->second;
+ observer_list->RemoveObserver(obs);
+}
+
+CrosSettingsProvider* CrosSettings::GetProvider(
+ const std::string& path) const {
+ for (size_t i = 0; i < providers_.size(); ++i) {
+ if (providers_[i]->HandlesSetting(path)){
+ return providers_[i];
+ }
+ }
+ return NULL;
+}
+
+void CrosSettings::Set(const std::string& path, Value* in_value) {
+ DCHECK(CalledOnValidThread());
+ CrosSettingsProvider* provider;
+ provider = GetProvider(path);
+ if (provider) {
+ provider->Set(path, in_value);
+ }
+}
+
+bool CrosSettings::Get(const std::string& path, Value** out_value) const {
+ DCHECK(CalledOnValidThread());
+ CrosSettingsProvider* provider;
+ provider = GetProvider(path);
+ if (provider) {
+ return provider->Get(path, out_value);
+ }
+ return false;
+}
+
+bool CrosSettings::GetInteger(const std::string& path,
int* out_value) const {
+ DCHECK(CalledOnValidThread());
Value* value;
if (!Get(path, &value))
return false;
@@ -54,8 +176,9 @@ bool CrosSettings::GetInteger(const std::wstring& path,
return value->GetAsInteger(out_value);
}
-bool CrosSettings::GetReal(const std::wstring& path,
+bool CrosSettings::GetReal(const std::string& path,
double* out_value) const {
+ DCHECK(CalledOnValidThread());
Value* value;
if (!Get(path, &value))
return false;
@@ -63,8 +186,9 @@ bool CrosSettings::GetReal(const std::wstring& path,
return value->GetAsReal(out_value);
}
-bool CrosSettings::GetString(const std::wstring& path,
+bool CrosSettings::GetString(const std::string& path,
std::string* out_value) const {
+ DCHECK(CalledOnValidThread());
Value* value;
if (!Get(path, &value))
return false;
@@ -72,4 +196,11 @@ bool CrosSettings::GetString(const std::wstring& path,
return value->GetAsString(out_value);
}
+CrosSettings::CrosSettings() {
+}
+
+CrosSettings::~CrosSettings() {
+ DCHECK(!providers_.size());
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros_settings.h b/chrome/browser/chromeos/cros_settings.h
index cfe4ec8..226ec08 100644
--- a/chrome/browser/chromeos/cros_settings.h
+++ b/chrome/browser/chromeos/cros_settings.h
@@ -4,45 +4,85 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_SETTINGS_H_
#define CHROME_BROWSER_CHROMEOS_CROS_SETTINGS_H_
+#pragma once
#include <string>
-#include "base/values.h"
+#include <vector>
+#include "base/hash_tables.h"
+#include "base/non_thread_safe.h"
+#include "base/observer_list.h"
+#include "base/singleton.h"
#include "chrome/browser/chromeos/cros_settings_names.h"
+#include "chrome/common/notification_observer.h"
+
+class Value;
namespace chromeos {
+class CrosSettingsProvider;
+
// A class manages per-device/global settings.
-class CrosSettings {
+class CrosSettings : public NonThreadSafe {
public:
// Class factory.
static CrosSettings* Get();
// Helper function to test if given path is a value cros settings name.
- static bool IsCrosSettings(const std::wstring& path);
+ static bool IsCrosSettings(const std::string& path);
// Sets |in_value| to given |path| in cros settings.
// Note that this takes ownership of |in_value|.
- virtual void Set(const std::wstring& path, Value* in_value) = 0;
+ void Set(const std::string& path, Value* in_value);
+
+ // Fires system setting change notification.
+ void FireObservers(const char* path);
// Gets settings value of given |path| to |out_value|.
- // Note that |out_value| is still owned by this class.
- virtual bool Get(const std::wstring& path, Value** out_value) const = 0;
+ // Note that the caller owns |out_value| returned.
+ bool Get(const std::string& path, Value** out_value) const;
// Convenience forms of Set(). These methods will replace any existing
// value at that path, even if it has a different type.
- void SetBoolean(const std::wstring& path, bool in_value);
- void SetInteger(const std::wstring& path, int in_value);
- void SetReal(const std::wstring& path, double in_value);
- void SetString(const std::wstring& path, const std::string& in_value);
+ void SetBoolean(const std::string& path, bool in_value);
+ void SetInteger(const std::string& path, int in_value);
+ void SetReal(const std::string& path, double in_value);
+ void SetString(const std::string& path, const std::string& in_value);
// These are convenience forms of Get(). The value will be retrieved
// and the return value will be true if the path is valid and the value at
// the end of the path can be returned in the form specified.
- bool GetBoolean(const std::wstring& path, bool* out_value) const;
- bool GetInteger(const std::wstring& path, int* out_value) const;
- bool GetReal(const std::wstring& path, double* out_value) const;
- bool GetString(const std::wstring& path, std::string* out_value) const;
+ bool GetBoolean(const std::string& path, bool* out_value) const;
+ bool GetInteger(const std::string& path, int* out_value) const;
+ bool GetReal(const std::string& path, double* out_value) const;
+ bool GetString(const std::string& path, std::string* out_value) const;
+
+ // adding/removing of providers
+ bool AddSettingsProvider(CrosSettingsProvider* provider);
+ bool RemoveSettingsProvider(CrosSettingsProvider* provider);
+
+ // If the pref at the given path changes, we call the observer's Observe
+ // method with PREF_CHANGED.
+ void AddSettingsObserver(const char* path, NotificationObserver* obs);
+ void RemoveSettingsObserver(const char* path, NotificationObserver* obs);
+
+ private:
+ // List of ChromeOS system settings providers.
+ std::vector<CrosSettingsProvider*> providers_;
+
+ // A map from settings names to a list of observers. Observers get fired in
+ // the order they are added.
+ typedef ObserverList<NotificationObserver> NotificationObserverList;
+ typedef base::hash_map<std::string, NotificationObserverList*>
+ SettingsObserverMap;
+ SettingsObserverMap settings_observers_;
+
+ CrosSettings();
+ ~CrosSettings();
+ CrosSettingsProvider* GetProvider(const std::string& path) const;
+ friend struct DefaultSingletonTraits<CrosSettings>;
+
+ DISALLOW_COPY_AND_ASSIGN(CrosSettings);
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros_settings_names.cc b/chrome/browser/chromeos/cros_settings_names.cc
index 84fbf7e..1624726 100644
--- a/chrome/browser/chromeos/cros_settings_names.cc
+++ b/chrome/browser/chromeos/cros_settings_names.cc
@@ -6,10 +6,13 @@
namespace chromeos {
-const wchar_t kCrosSettingsPrefix[] = L"cros.";
+const char kCrosSettingsPrefix[] = "cros.";
-const wchar_t kAccountsPrefAllowBWSI[] = L"cros.accounts.allowBWSI";
-const wchar_t kAccountsPrefAllowGuest[] = L"cros.accounts.allowGuest";
-const wchar_t kAccountsPrefUsers[] = L"cros.accounts.users";
+const char kAccountsPrefAllowBWSI[] = "cros.accounts.allowBWSI";
+const char kAccountsPrefAllowGuest[] = "cros.accounts.allowGuest";
+const char kAccountsPrefShowUserNamesOnSignIn[]
+ = "cros.accounts.showUserNamesOnSignIn";
+const char kAccountsPrefUsers[] = "cros.accounts.users";
+const char kSystemTimezone[] = "cros.system.timezone";
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros_settings_names.h b/chrome/browser/chromeos/cros_settings_names.h
index ce99258..6f2bb5a 100644
--- a/chrome/browser/chromeos/cros_settings_names.h
+++ b/chrome/browser/chromeos/cros_settings_names.h
@@ -4,15 +4,18 @@
#ifndef CHROME_BROWSER_CHROMEOS_CROS_SETTINGS_NAMES_H_
#define CHROME_BROWSER_CHROMEOS_CROS_SETTINGS_NAMES_H_
+#pragma once
namespace chromeos {
-extern const wchar_t kCrosSettingsPrefix[];
+extern const char kCrosSettingsPrefix[];
-extern const wchar_t kAccountsPrefAllowBWSI[];
-extern const wchar_t kAccountsPrefAllowGuest[];
-extern const wchar_t kAccountsPrefUsers[];
+extern const char kAccountsPrefAllowBWSI[];
+extern const char kAccountsPrefAllowGuest[];
+extern const char kAccountsPrefShowUserNamesOnSignIn[];
+extern const char kAccountsPrefUsers[];
+extern const char kSystemTimezone[];
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_CROS_SETTINGS_NAMES_H_
diff --git a/chrome/browser/chromeos/customization_document.cc b/chrome/browser/chromeos/customization_document.cc
index 19410ec..b9a4f34 100644
--- a/chrome/browser/chromeos/customization_document.cc
+++ b/chrome/browser/chromeos/customization_document.cc
@@ -6,33 +6,32 @@
#include <string>
-#include "base/file_path.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
// Manifest attributes names.
namespace {
-const wchar_t kVersionAttr[] = L"version";
-const wchar_t kProductSkuAttr[] = L"product_sku";
-const wchar_t kInitialLocaleAttr[] = L"initial_locale";
-const wchar_t kInitialTimezoneAttr[] = L"initial_timezone";
-const wchar_t kBackgroundColorAttr[] = L"background_color";
-const wchar_t kRegistrationUrlAttr[] = L"registration_url";
-const wchar_t kSetupContentAttr[] = L"setup_content";
-const wchar_t kContentLocaleAttr[] = L"content_locale";
-const wchar_t kHelpPageAttr[] = L"help_page";
-const wchar_t kEulaPageAttr[] = L"eula_page";
-const wchar_t kAppMenuAttr[] = L"app_menu";
-const wchar_t kInitialStartPageAttr[] = L"initial_start_page";
-const wchar_t kSectionTitleAttr[] = L"section_title";
-const wchar_t kWebAppsAttr[] = L"web_apps";
-const wchar_t kSupportPageAttr[] = L"support_page";
-const wchar_t kExtensionsAttr[] = L"extensions";
+const char kVersionAttr[] = "version";
+const char kProductSkuAttr[] = "product_sku";
+const char kInitialLocaleAttr[] = "initial_locale";
+const char kInitialTimezoneAttr[] = "initial_timezone";
+const char kBackgroundColorAttr[] = "background_color";
+const char kRegistrationUrlAttr[] = "registration_url";
+const char kSetupContentAttr[] = "setup_content";
+const char kContentLocaleAttr[] = "content_locale";
+const char kHelpPageAttr[] = "help_page";
+const char kEulaPageAttr[] = "eula_page";
+const char kAppMenuAttr[] = "app_menu";
+const char kInitialStartPageAttr[] = "initial_start_page";
+const char kSectionTitleAttr[] = "section_title";
+const char kWebAppsAttr[] = "web_apps";
+const char kSupportPageAttr[] = "support_page";
+const char kExtensionsAttr[] = "extensions";
const char kAcceptedManifestVersion[] = "1.0";
@@ -72,6 +71,16 @@ bool CustomizationDocument::ParseFromJsonValue(const DictionaryValue* root) {
// StartupCustomizationDocument implementation.
+bool StartupCustomizationDocument::LoadManifestFromFile(
+ const FilePath& manifest_path) {
+ if (CustomizationDocument::LoadManifestFromFile(manifest_path)) {
+ manifest_path_ = manifest_path;
+ return true;
+ } else {
+ return false;
+ }
+}
+
bool StartupCustomizationDocument::ParseFromJsonValue(
const DictionaryValue* root) {
if (!CustomizationDocument::ParseFromJsonValue(root))
@@ -93,8 +102,9 @@ bool StartupCustomizationDocument::ParseFromJsonValue(
root->GetString(kBackgroundColorAttr, &background_color_string);
if (!background_color_string.empty()) {
if (background_color_string[0] == '#') {
- background_color_ = static_cast<SkColor>(
- 0xff000000 | HexStringToInt(background_color_string.substr(1)));
+ int background_int;
+ base::HexStringToInt(background_color_string.substr(1), &background_int);
+ background_color_ = static_cast<SkColor>(0xff000000 | background_int);
} else {
// Literal color constants are not supported yet.
return false;
@@ -128,14 +138,14 @@ bool StartupCustomizationDocument::ParseFromJsonValue(
return true;
}
-const StartupCustomizationDocument::SetupContent*
- StartupCustomizationDocument::GetSetupContent(
- const std::string& locale) const {
+FilePath StartupCustomizationDocument::GetSetupPagePath(
+ const std::string& locale, std::string SetupContent::* page_path) const {
SetupContentMap::const_iterator content_iter = setup_content_.find(locale);
if (content_iter != setup_content_.end()) {
- return &content_iter->second;
+ return manifest_path_.DirName().Append(content_iter->second.*page_path);
+ } else {
+ return FilePath();
}
- return NULL;
}
// ServicesCustomizationDocument implementation.
diff --git a/chrome/browser/chromeos/customization_document.h b/chrome/browser/chromeos/customization_document.h
index 169adb9..ffdd74f 100644
--- a/chrome/browser/chromeos/customization_document.h
+++ b/chrome/browser/chromeos/customization_document.h
@@ -4,18 +4,18 @@
#ifndef CHROME_BROWSER_CHROMEOS_CUSTOMIZATION_DOCUMENT_H_
#define CHROME_BROWSER_CHROMEOS_CUSTOMIZATION_DOCUMENT_H_
+#pragma once
#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
+#include "base/file_path.h"
#include "third_party/skia/include/core/SkColor.h"
class DictionaryValue;
class ListValue;
-class FilePath;
namespace chromeos {
@@ -35,6 +35,7 @@ class CustomizationDocument {
// Parses manifest's attributes from the JSON dictionary value.
virtual bool ParseFromJsonValue(const DictionaryValue* root);
+ private:
// Manifest version string.
std::string version_;
@@ -45,6 +46,20 @@ class CustomizationDocument {
class StartupCustomizationDocument : public CustomizationDocument {
public:
+ StartupCustomizationDocument() {}
+
+ virtual bool LoadManifestFromFile(const FilePath& manifest_path);
+
+ const std::string& product_sku() const { return product_sku_; }
+ const std::string& initial_locale() const { return initial_locale_; }
+ const std::string& initial_timezone() const { return initial_timezone_; }
+ SkColor background_color() const { return background_color_; }
+ const std::string& registration_url() const { return registration_url_; }
+
+ FilePath GetHelpPagePath(const std::string& locale) const;
+ FilePath GetEULAPagePath(const std::string& locale) const;
+
+ private:
struct SetupContent {
SetupContent() {}
SetupContent(const std::string& help_page_path,
@@ -60,18 +75,9 @@ class StartupCustomizationDocument : public CustomizationDocument {
typedef std::map<std::string, SetupContent> SetupContentMap;
- StartupCustomizationDocument() {}
-
- const std::string& product_sku() const { return product_sku_; }
- const std::string& initial_locale() const { return initial_locale_; }
- const std::string& initial_timezone() const { return initial_timezone_; }
- SkColor background_color() const { return background_color_; }
- const std::string& registration_url() const { return registration_url_; }
-
- const SetupContent* GetSetupContent(const std::string& locale) const;
-
- protected:
virtual bool ParseFromJsonValue(const DictionaryValue* root);
+ FilePath GetSetupPagePath(const std::string& locale,
+ std::string SetupContent::* page_path) const;
// Product SKU.
std::string product_sku_;
@@ -91,9 +97,21 @@ class StartupCustomizationDocument : public CustomizationDocument {
// Setup content for different locales.
SetupContentMap setup_content_;
+ // Copy of manifest full path.
+ FilePath manifest_path_;
+
DISALLOW_COPY_AND_ASSIGN(StartupCustomizationDocument);
};
+inline FilePath StartupCustomizationDocument::GetHelpPagePath(
+ const std::string& locale) const {
+ return GetSetupPagePath(locale, &SetupContent::help_page_path);
+}
+inline FilePath StartupCustomizationDocument::GetEULAPagePath(
+ const std::string& locale) const {
+ return GetSetupPagePath(locale, &SetupContent::eula_page_path);
+}
+
// OEM services customization document class.
class ServicesCustomizationDocument : public CustomizationDocument {
@@ -114,7 +132,7 @@ class ServicesCustomizationDocument : public CustomizationDocument {
const StringList& web_apps() const { return web_apps_; }
const StringList& extensions() const { return extensions_; }
- protected:
+ private:
virtual bool ParseFromJsonValue(const DictionaryValue* root);
bool ParseStringListFromJsonValue(const ListValue* list_value,
diff --git a/chrome/browser/chromeos/customization_document_unittest.cc b/chrome/browser/chromeos/customization_document_unittest.cc
index 41c2cee..a19e63a 100644
--- a/chrome/browser/chromeos/customization_document_unittest.cc
+++ b/chrome/browser/chromeos/customization_document_unittest.cc
@@ -104,13 +104,13 @@ TEST_F(StartupCustomizationDocumentTest, LoadGoodManifestFromString) {
EXPECT_EQ(customization_.background_color(),
SkColorSetRGB(0x88, 0x00, 0x88));
EXPECT_EQ(customization_.registration_url(), "http://www.google.com");
- EXPECT_EQ(customization_.GetSetupContent("en_US")->help_page_path,
+ EXPECT_EQ(customization_.GetHelpPagePath("en_US").value(),
"setup_content/en_US/help.html");
- EXPECT_EQ(customization_.GetSetupContent("en_US")->eula_page_path,
+ EXPECT_EQ(customization_.GetEULAPagePath("en_US").value(),
"setup_content/en_US/eula.html");
- EXPECT_EQ(customization_.GetSetupContent("ru")->help_page_path,
+ EXPECT_EQ(customization_.GetHelpPagePath("ru").value(),
"setup_content/ru/help.html");
- EXPECT_EQ(customization_.GetSetupContent("ru")->eula_page_path,
+ EXPECT_EQ(customization_.GetEULAPagePath("ru").value(),
"setup_content/ru/eula.html");
}
diff --git a/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc b/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc
index 9ca1730..249419a 100644
--- a/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc
@@ -7,40 +7,73 @@
#include "app/l10n_util.h"
#include "base/json/json_reader.h"
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/chromeos/cros_settings_provider_user.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
#include "grit/generated_resources.h"
namespace chromeos {
-AccountsOptionsHandler::AccountsOptionsHandler() {
+AccountsOptionsHandler::AccountsOptionsHandler()
+ : CrosOptionsPageUIHandler(new UserCrosSettingsProvider()) {
}
AccountsOptionsHandler::~AccountsOptionsHandler() {
}
+void AccountsOptionsHandler::RegisterMessages() {
+ DCHECK(dom_ui_);
+ dom_ui_->RegisterMessageCallback("whitelistUser",
+ NewCallback(this, &AccountsOptionsHandler::WhitelistUser));
+ dom_ui_->RegisterMessageCallback("unwhitelistUser",
+ NewCallback(this, &AccountsOptionsHandler::UnwhitelistUser));
+}
+
void AccountsOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"accountsPage", l10n_util::GetString(
+ localized_strings->SetString("accountsPage", l10n_util::GetStringUTF16(
IDS_OPTIONS_ACCOUNTS_TAB_LABEL));
- localized_strings->SetString(L"allow_BWSI", l10n_util::GetString(
+ localized_strings->SetString("allow_BWSI", l10n_util::GetStringUTF16(
IDS_OPTIONS_ACCOUNTS_ALLOW_BWSI_DESCRIPTION));
- localized_strings->SetString(L"allow_guest",l10n_util::GetString(
+ localized_strings->SetString("allow_guest",l10n_util::GetStringUTF16(
IDS_OPTIONS_ACCOUNTS_ALLOW_GUEST_DESCRIPTION));
- localized_strings->SetString(L"user_list_title",l10n_util::GetString(
- IDS_OPTIONS_ACCOUNTS_USER_LIST_TITLE));
- localized_strings->SetString(L"add_user",l10n_util::GetString(
- IDS_OPTIONS_ACCOUNTS_ADD_USER));
- localized_strings->SetString(L"remove_user",l10n_util::GetString(
- IDS_OPTIONS_ACCOUNTS_REMOVE_USER));
- localized_strings->SetString(L"add_user_email",l10n_util::GetString(
- IDS_OPTIONS_ACCOUNTS_EMAIL_LABEL));
-
- localized_strings->SetString(L"ok_label",l10n_util::GetString(
- IDS_OK));
- localized_strings->SetString(L"cancel_label",l10n_util::GetString(
- IDS_CANCEL));
+ 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(
+ IDS_OPTIONS_ACCOUNTS_USERNAME_EDIT_HINT));
+ localized_strings->SetString("username_format",l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ACCOUNTS_USERNAME_FORMAT));
+ localized_strings->SetString("add_users",l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ACCOUNTS_ADD_USERS));
+
+ localized_strings->SetString("current_user_is_owner",
+ UserManager::Get()->current_user_is_owner() ?
+ ASCIIToUTF16("true") : ASCIIToUTF16("false"));
+}
+
+UserCrosSettingsProvider* AccountsOptionsHandler::users_settings() const {
+ return static_cast<UserCrosSettingsProvider*>(settings_provider_.get());
+}
+
+void AccountsOptionsHandler::WhitelistUser(const ListValue* args) {
+ std::string email;
+ if (!args->GetString(0, &email)) {
+ return;
+ }
+
+ users_settings()->WhitelistUser(email);
+}
+
+void AccountsOptionsHandler::UnwhitelistUser(const ListValue* args) {
+ std::string email;
+ if (!args->GetString(0, &email)) {
+ return;
+ }
+
+ users_settings()->UnwhitelistUser(email);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/accounts_options_handler.h b/chrome/browser/chromeos/dom_ui/accounts_options_handler.h
index 0de8000..a43ec50 100644
--- a/chrome/browser/chromeos/dom_ui/accounts_options_handler.h
+++ b/chrome/browser/chromeos/dom_ui/accounts_options_handler.h
@@ -4,21 +4,33 @@
#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_ACCOUNTS_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_DOM_UI_ACCOUNTS_OPTIONS_HANDLER_H_
+#pragma once
-#include "chrome/browser/dom_ui/options_ui.h"
+#include "chrome/browser/chromeos/dom_ui/cros_options_page_ui_handler.h"
namespace chromeos {
+class UserCrosSettingsProvider;
+
// ChromeOS accounts options page handler.
-class AccountsOptionsHandler : public OptionsPageUIHandler {
+class AccountsOptionsHandler : public CrosOptionsPageUIHandler {
public:
AccountsOptionsHandler();
virtual ~AccountsOptionsHandler();
+ // DOMMessageHandler implementation.
+ virtual void RegisterMessages();
+
// OptionsUIHandler implementation:
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
private:
+ UserCrosSettingsProvider* users_settings() const;
+
+ // Javascript callbacks to whitelist/unwhitelist user.
+ void WhitelistUser(const ListValue* args);
+ void UnwhitelistUser(const ListValue* args);
+
DISALLOW_COPY_AND_ASSIGN(AccountsOptionsHandler);
};
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 889a85d..d76e33d 100644
--- a/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc
@@ -5,33 +5,42 @@
#include "chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h"
#include "base/json/json_reader.h"
-#include "base/string_util.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"
namespace chromeos {
-Value* CoreChromeOSOptionsHandler::FetchPref(const std::wstring& pref_name) {
+CoreChromeOSOptionsHandler::CoreChromeOSOptionsHandler()
+ : handling_change_(false) {
+}
+
+Value* CoreChromeOSOptionsHandler::FetchPref(const std::string& pref_name) {
if (!CrosSettings::IsCrosSettings(pref_name))
return ::CoreOptionsHandler::FetchPref(pref_name);
Value* pref_value = NULL;
CrosSettings::Get()->Get(pref_name, &pref_value);
- return pref_value ? pref_value->DeepCopy() : Value::CreateNullValue();
+ return pref_value ? pref_value : Value::CreateNullValue();
}
-void CoreChromeOSOptionsHandler::ObservePref(const std::wstring& pref_name) {
+void CoreChromeOSOptionsHandler::ObservePref(const std::string& pref_name) {
if (!CrosSettings::IsCrosSettings(pref_name))
return ::CoreOptionsHandler::ObservePref(pref_name);
// TODO(xiyuan): Change this when CrosSettings supports observers.
+ CrosSettings::Get()->AddSettingsObserver(pref_name.c_str(), this);
}
-void CoreChromeOSOptionsHandler::SetPref(const std::wstring& pref_name,
+void CoreChromeOSOptionsHandler::SetPref(const std::string& pref_name,
Value::ValueType pref_type,
- const std::string& value_string) {
+ const std::string& value_string,
+ const std::string& metric) {
if (!CrosSettings::IsCrosSettings(pref_name))
- return ::CoreOptionsHandler::SetPref(pref_name, pref_type, value_string);
-
+ return ::CoreOptionsHandler::SetPref(pref_name, pref_type, value_string,
+ metric);
+ handling_change_ = true;
CrosSettings* cros_settings = CrosSettings::Get();
switch (pref_type) {
case Value::TYPE_BOOLEAN:
@@ -39,7 +48,7 @@ void CoreChromeOSOptionsHandler::SetPref(const std::wstring& pref_name,
break;
case Value::TYPE_INTEGER:
int int_value;
- if (StringToInt(value_string, &int_value))
+ if (base::StringToInt(value_string, &int_value))
cros_settings->SetInteger(pref_name, int_value);
break;
case Value::TYPE_STRING:
@@ -55,6 +64,54 @@ void CoreChromeOSOptionsHandler::SetPref(const std::wstring& pref_name,
break;
}
}
+ handling_change_ = false;
+
+ ProcessUserMetric(pref_type, value_string, metric);
+}
+
+void CoreChromeOSOptionsHandler::StopObservingPref(const std::string& path) {
+ // Unregister this instance from observing prefs of chrome os settings.
+ if (CrosSettings::IsCrosSettings(path))
+ CrosSettings::Get()->RemoveSettingsObserver(path.c_str(), this);
+ else // Call base class to handle regular preferences.
+ ::CoreOptionsHandler::StopObservingPref(path);
+}
+
+void CoreChromeOSOptionsHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ // Ignore the notification if this instance had caused it.
+ if (handling_change_)
+ return;
+ if (type == NotificationType::SYSTEM_SETTING_CHANGED) {
+ NotifySettingsChanged(Details<std::string>(details).ptr());
+ return;
+ }
+ ::CoreOptionsHandler::Observe(type, source, details);
+}
+
+void CoreChromeOSOptionsHandler::NotifySettingsChanged(
+ const std::string* setting_name) {
+ DCHECK(dom_ui_);
+ DCHECK(CrosSettings::Get()->IsCrosSettings(*setting_name));
+ Value* value = NULL;
+ if (!CrosSettings::Get()->Get(*setting_name, &value)) {
+ NOTREACHED();
+ if (value)
+ delete value;
+ return;
+ }
+ for (PreferenceCallbackMap::const_iterator iter =
+ pref_callback_map_.find(*setting_name);
+ iter != pref_callback_map_.end(); ++iter) {
+ const std::wstring& callback_function = iter->second;
+ ListValue result_value;
+ result_value.Append(Value::CreateStringValue(setting_name->c_str()));
+ result_value.Append(value->DeepCopy());
+ dom_ui_->CallJavascriptFunction(callback_function, result_value);
+ }
+ if (value)
+ delete value;
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h b/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h
index 0c4dc5c..d3b63f5 100644
--- a/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h
+++ b/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_CORE_CHROMEOS_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_DOM_UI_CORE_CHROMEOS_OPTIONS_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/core_options_handler.h"
@@ -12,15 +13,30 @@ namespace chromeos {
// CoreChromeOSOptionsHandler handles ChromeOS settings.
class CoreChromeOSOptionsHandler : public ::CoreOptionsHandler {
public:
+ CoreChromeOSOptionsHandler();
protected:
- // ::CoreOptionsHandler Implementation
- virtual Value* FetchPref(const std::wstring& pref_name);
- virtual void ObservePref(const std::wstring& pref_name);
- virtual void SetPref(const std::wstring& pref_name,
+ // ::CoreOptionsHandler overrides
+ virtual Value* FetchPref(const std::string& pref_name);
+ virtual void ObservePref(const std::string& pref_name);
+ virtual void SetPref(const std::string& pref_name,
Value::ValueType pref_type,
- const std::string& value_string);
-
+ const std::string& value_string,
+ const std::string& metric);
+ virtual void StopObservingPref(const std::string& path);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Notifies registered JS callbacks on ChromeOS setting change.
+ void NotifySettingsChanged(const std::string* setting_name);
+
+ // Keeps the track of change caused by the handler to make sure
+ // it does not signal itself again.
+ bool handling_change_;
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/labs_handler.cc b/chrome/browser/chromeos/dom_ui/labs_handler.cc
index d6ecee0..7f45611 100644
--- a/chrome/browser/chromeos/dom_ui/labs_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/labs_handler.cc
@@ -5,20 +5,8 @@
#include "chrome/browser/chromeos/dom_ui/labs_handler.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/i18n/time_formatting.h"
-#include "base/stl_util-inl.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/common/notification_service.h"
-#include "grit/browser_resources.h"
-#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "grit/theme_resources.h"
LabsHandler::LabsHandler() {
}
@@ -30,15 +18,21 @@ void LabsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
// Labs page - ChromeOS
- localized_strings->SetString(L"labsPage",
- l10n_util::GetString(IDS_OPTIONS_LABS_TAB_LABEL));
- localized_strings->SetString(L"mediaplayer_title",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_MEDIAPLAYER));
- localized_strings->SetString(L"mediaplayer",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_MEDIAPLAYER_DESCRIPTION));
-
- localized_strings->SetString(L"advanced_file_title",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_ADVANCEDFS));
- localized_strings->SetString(L"advanced_filesystem",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_ADVANCEDFS_DESCRIPTION));
+ localized_strings->SetString("labsPage",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_LABS_TAB_LABEL));
+
+ localized_strings->SetString("mediaplayer_title",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_MEDIAPLAYER));
+ localized_strings->SetString("mediaplayer",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_MEDIAPLAYER_DESCRIPTION));
+
+ localized_strings->SetString("advanced_file_title",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_ADVANCEDFS));
+ localized_strings->SetString("advanced_filesystem",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_ADVANCEDFS_DESCRIPTION));
+
+ localized_strings->SetString("talk_title",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_TALK));
+ localized_strings->SetString("talk",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_TALK_DESCRIPTION));
}
diff --git a/chrome/browser/chromeos/dom_ui/labs_handler.h b/chrome/browser/chromeos/dom_ui/labs_handler.h
index 5c217bb..3fc1121 100644
--- a/chrome/browser/chromeos/dom_ui/labs_handler.h
+++ b/chrome/browser/chromeos/dom_ui/labs_handler.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LABS_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_DOM_UI_LABS_HANDLER_H_
-
-#include <string>
+#pragma once
#include "chrome/browser/dom_ui/options_ui.h"
@@ -19,7 +18,6 @@ class LabsHandler : public OptionsPageUIHandler {
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
private:
-
DISALLOW_COPY_AND_ASSIGN(LabsHandler);
};
diff --git a/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.cc b/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.cc
index 150ae15..46a8e2d 100644
--- a/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.cc
@@ -5,10 +5,13 @@
#include "chrome/browser/chromeos/dom_ui/language_hangul_options_handler.h"
#include "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "grit/generated_resources.h"
+namespace chromeos {
+
LanguageHangulOptionsHandler::LanguageHangulOptionsHandler() {
}
@@ -19,21 +22,23 @@ void LanguageHangulOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
// Language Hangul page - ChromeOS
- localized_strings->SetString(L"keyboard_layout",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_KEYBOARD_LAYOUT_TEXT));
+ localized_strings->SetString("hangul_keyboard_layout",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_KEYBOARD_LAYOUT_TEXT));
- localized_strings->Set(L"keyboardLayoutList", GetKeyboardLayoutList());
+ localized_strings->Set("HangulkeyboardLayoutList", GetKeyboardLayoutList());
}
ListValue* LanguageHangulOptionsHandler::GetKeyboardLayoutList() {
ListValue* keyboard_layout_list = new ListValue();
- for (size_t i = 0; i < arraysize(chromeos::kHangulKeyboardNameIDPairs); ++i) {
+ for (size_t i = 0; i < language_prefs::kNumHangulKeyboardNameIDPairs; ++i) {
ListValue* option = new ListValue();
- option->Append(Value::CreateStringValue(ASCIIToWide(
- chromeos::kHangulKeyboardNameIDPairs[i].keyboard_id)));
- option->Append(Value::CreateStringValue(l10n_util::GetString(
- chromeos::kHangulKeyboardNameIDPairs[i].message_id)));
+ option->Append(Value::CreateStringValue(
+ language_prefs::kHangulKeyboardNameIDPairs[i].keyboard_id));
+ option->Append(Value::CreateStringValue(l10n_util::GetStringUTF16(
+ language_prefs::kHangulKeyboardNameIDPairs[i].message_id)));
keyboard_layout_list->Append(option);
}
return keyboard_layout_list;
}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.h b/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.h
index 1872fbc..cedfb05 100644
--- a/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.h
+++ b/chrome/browser/chromeos/dom_ui/language_hangul_options_handler.h
@@ -4,12 +4,15 @@
#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LANGUAGE_HANGUL_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_DOM_UI_LANGUAGE_HANGUL_OPTIONS_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/options_ui.h"
class DictionaryValue;
class ListValue;
+namespace chromeos {
+
// Hangul options page UI handler.
class LanguageHangulOptionsHandler : public OptionsPageUIHandler {
public:
@@ -26,4 +29,6 @@ class LanguageHangulOptionsHandler : public OptionsPageUIHandler {
DISALLOW_COPY_AND_ASSIGN(LanguageHangulOptionsHandler);
};
+} // namespace chromeos
+
#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LANGUAGE_HANGUL_OPTIONS_HANDLER_H_
diff --git a/chrome/browser/chromeos/dom_ui/language_options_handler.cc b/chrome/browser/chromeos/dom_ui/language_options_handler.cc
index c78cccc..594f8b1 100644
--- a/chrome/browser/chromeos/dom_ui/language_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/language_options_handler.cc
@@ -4,12 +4,29 @@
#include "chrome/browser/chromeos/dom_ui/language_options_handler.h"
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/browser.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/input_method/input_method_util.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+namespace chromeos {
+
LanguageOptionsHandler::LanguageOptionsHandler() {
}
@@ -19,26 +36,248 @@ LanguageOptionsHandler::~LanguageOptionsHandler() {
void LanguageOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"languagePage",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_DIALOG_TITLE));
- localized_strings->SetString(L"add_button",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_BUTTON));
- localized_strings->SetString(L"configure",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE));
- localized_strings->SetString(L"input_method",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD));
- localized_strings->SetString(L"languages",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_LANGUAGES));
- localized_strings->SetString(L"remove_button",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_REMOVE_BUTTON));
- localized_strings->SetString(L"others",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_OTHERS));
- localized_strings->SetString(L"is_displayed_in_this_language",
- l10n_util::GetStringF(
+ localized_strings->SetString("languagePage",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_DIALOG_TITLE));
+ localized_strings->SetString("add_button",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_BUTTON));
+ localized_strings->SetString("configure",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE));
+ localized_strings->SetString("input_method",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD));
+ localized_strings->SetString("languages",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_LANGUAGES));
+ localized_strings->SetString("please_add_another_input_method",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_INPUT_METHOD));
+ localized_strings->SetString("please_add_another_language",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_LANGUAGE));
+ localized_strings->SetString("ok_button", l10n_util::GetStringUTF16(IDS_OK));
+ localized_strings->SetString("remove_button",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_REMOVE_BUTTON));
+ localized_strings->SetString("restart_button",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_RESTART_BUTTON));
+ localized_strings->SetString("add_language_instructions",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_LANGUAGE_INSTRUCTIONS));
+ localized_strings->SetString("input_method_instructions",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_INSTRUCTIONS));
+ localized_strings->SetString("switch_input_methods_hint",
+ l10n_util::GetStringFUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT,
+ ASCIIToUTF16("alt+shift")));
+ localized_strings->SetString("select_previous_input_method_hint",
+ l10n_util::GetStringFUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT,
+ ASCIIToUTF16("ctrl+space")));
+ localized_strings->SetString("cannot_be_displayed_in_this_language",
+ l10n_util::GetStringFUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_CANNOT_BE_DISPLAYED_IN_THIS_LANGUAGE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME)));
+ localized_strings->SetString("is_displayed_in_this_language",
+ l10n_util::GetStringFUTF16(
IDS_OPTIONS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE,
- l10n_util::GetString(IDS_PRODUCT_OS_NAME)));
- localized_strings->SetString(L"display_in_this_language",
- l10n_util::GetStringF(
+ l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME)));
+ localized_strings->SetString("display_in_this_language",
+ l10n_util::GetStringFUTF16(
IDS_OPTIONS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE,
- l10n_util::GetString(IDS_PRODUCT_OS_NAME)));
+ l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME)));
+ localized_strings->SetString("restart_required",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_RESTART_REQUIRED));
+ localized_strings->SetString("this_language_is_currently_in_use",
+ l10n_util::GetStringFUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_THIS_LANGUAGE_IS_CURRENTLY_IN_USE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME)));
+
+ // GetSupportedInputMethods() never return NULL.
+ scoped_ptr<InputMethodDescriptors> descriptors(
+ CrosLibrary::Get()->GetInputMethodLibrary()->GetSupportedInputMethods());
+
+ // The followigns are resources, rather than local strings.
+ localized_strings->SetString("currentUiLanguageCode",
+ g_browser_process->GetApplicationLocale());
+ localized_strings->Set("inputMethodList", GetInputMethodList(*descriptors));
+ localized_strings->Set("languageList", GetLanguageList(*descriptors));
+ localized_strings->Set("uiLanguageCodeSet", GetUiLanguageCodeSet());
+}
+
+void LanguageOptionsHandler::RegisterMessages() {
+ DCHECK(dom_ui_);
+ dom_ui_->RegisterMessageCallback("inputMethodDisable",
+ NewCallback(this, &LanguageOptionsHandler::InputMethodDisableCallback));
+ dom_ui_->RegisterMessageCallback("inputMethodEnable",
+ NewCallback(this, &LanguageOptionsHandler::InputMethodEnableCallback));
+ dom_ui_->RegisterMessageCallback("inputMethodOptionsOpen",
+ NewCallback(this,
+ &LanguageOptionsHandler::InputMethodOptionsOpenCallback));
+ dom_ui_->RegisterMessageCallback("languageOptionsOpen",
+ NewCallback(this, &LanguageOptionsHandler::LanguageOptionsOpenCallback));
+ dom_ui_->RegisterMessageCallback("uiLanguageChange",
+ NewCallback(this, &LanguageOptionsHandler::UiLanguageChangeCallback));
+ dom_ui_->RegisterMessageCallback("uiLanguageRestart",
+ NewCallback(this, &LanguageOptionsHandler::RestartCallback));
}
+
+ListValue* LanguageOptionsHandler::GetInputMethodList(
+ const InputMethodDescriptors& descriptors) {
+ ListValue* input_method_list = new ListValue();
+
+ for (size_t i = 0; i < descriptors.size(); ++i) {
+ const InputMethodDescriptor& descriptor = descriptors[i];
+ const std::string language_code =
+ input_method::GetLanguageCodeFromDescriptor(descriptor);
+ const std::string display_name =
+ input_method::GetInputMethodDisplayNameFromId(descriptor.id);
+
+ DictionaryValue* dictionary = new DictionaryValue();
+ dictionary->SetString("id", descriptor.id);
+ dictionary->SetString("displayName", display_name);
+
+ // One input method can be associated with multiple languages, hence
+ // we use a dictionary here.
+ DictionaryValue* language_codes = new DictionaryValue();
+ language_codes->SetBoolean(language_code, true);
+ // Check kExtraLanguages to see if there are languages associated with
+ // this input method. If these are present, add these.
+ for (size_t j = 0; j < arraysize(input_method::kExtraLanguages); ++j) {
+ const std::string extra_input_method_id =
+ input_method::kExtraLanguages[j].input_method_id;
+ const std::string extra_language_code =
+ input_method::kExtraLanguages[j].language_code;
+ if (extra_input_method_id == descriptor.id) {
+ language_codes->SetBoolean(extra_language_code, true);
+ }
+ }
+ dictionary->Set("languageCodeSet", language_codes);
+
+ input_method_list->Append(dictionary);
+ }
+
+ return input_method_list;
+}
+
+ListValue* LanguageOptionsHandler::GetLanguageList(
+ const InputMethodDescriptors& descriptors) {
+ std::set<std::string> language_codes;
+ // Collect the language codes from the supported input methods.
+ for (size_t i = 0; i < descriptors.size(); ++i) {
+ const InputMethodDescriptor& descriptor = descriptors[i];
+ const std::string language_code =
+ input_method::GetLanguageCodeFromDescriptor(descriptor);
+ language_codes.insert(language_code);
+ }
+ // Collect the language codes from kExtraLanguages.
+ for (size_t i = 0; i < arraysize(input_method::kExtraLanguages); ++i) {
+ const char* language_code =
+ input_method::kExtraLanguages[i].language_code;
+ language_codes.insert(language_code);
+ }
+
+ // Map of display name -> {language code, native_display_name}.
+ // In theory, we should be able to create a map that is sorted by
+ // display names using ICU comparator, but doing it is hard, thus we'll
+ // use an auxiliary vector to achieve the same result.
+ typedef std::pair<std::string, std::wstring> LanguagePair;
+ typedef std::map<std::wstring, LanguagePair> LanguageMap;
+ LanguageMap language_map;
+ // The auxiliary vector mentioned above.
+ std::vector<std::wstring> display_names;
+
+ // Build the list of display names, and build the language map.
+ for (std::set<std::string>::const_iterator iter = language_codes.begin();
+ iter != language_codes.end(); ++iter) {
+ const std::wstring display_name =
+ input_method::GetLanguageDisplayNameFromCode(*iter);
+ const std::wstring native_display_name =
+ input_method::GetLanguageNativeDisplayNameFromCode(*iter);
+ display_names.push_back(display_name);
+ language_map[display_name] =
+ std::make_pair(*iter, native_display_name);
+ }
+ DCHECK_EQ(display_names.size(), language_map.size());
+
+ // Sort display names using locale specific sorter.
+ l10n_util::SortStrings(g_browser_process->GetApplicationLocale(),
+ &display_names);
+
+ // Build the language list from the language map.
+ ListValue* language_list = new ListValue();
+ for (size_t i = 0; i < display_names.size(); ++i) {
+ const LanguagePair& pair = language_map[display_names[i]];
+ DictionaryValue* dictionary = new DictionaryValue();
+ dictionary->SetString("code", pair.first);
+ dictionary->SetString("displayName", WideToUTF16Hack(display_names[i]));
+ dictionary->SetString("nativeDisplayName", WideToUTF16Hack(pair.second));
+ language_list->Append(dictionary);
+ }
+
+ return language_list;
+}
+
+DictionaryValue* LanguageOptionsHandler::GetUiLanguageCodeSet() {
+ DictionaryValue* dictionary = new DictionaryValue();
+ const std::vector<std::string>& available_locales =
+ l10n_util::GetAvailableLocales();
+ for (size_t i = 0; i < available_locales.size(); ++i) {
+ dictionary->SetBoolean(available_locales[i], true);
+ }
+ return dictionary;
+}
+
+void LanguageOptionsHandler::InputMethodDisableCallback(
+ const ListValue* args) {
+ const std::string input_method_id = WideToASCII(ExtractStringValue(args));
+ const std::string action = StringPrintf(
+ "LanguageOptions_DisableInputMethod_%s", input_method_id.c_str());
+ UserMetrics::RecordComputedAction(action);
+}
+
+void LanguageOptionsHandler::InputMethodEnableCallback(
+ const ListValue* args) {
+ const std::string input_method_id = WideToASCII(ExtractStringValue(args));
+ const std::string action = StringPrintf(
+ "LanguageOptions_EnableInputMethod_%s", input_method_id.c_str());
+ UserMetrics::RecordComputedAction(action);
+}
+
+void LanguageOptionsHandler::InputMethodOptionsOpenCallback(
+ const ListValue* args) {
+ const std::string input_method_id = WideToASCII(ExtractStringValue(args));
+ const std::string action = StringPrintf(
+ "InputMethodOptions_Open_%s", input_method_id.c_str());
+ UserMetrics::RecordComputedAction(action);
+}
+
+void LanguageOptionsHandler::LanguageOptionsOpenCallback(
+ const ListValue* args) {
+ UserMetrics::RecordAction(UserMetricsAction("LanguageOptions_Open"));
+}
+
+void LanguageOptionsHandler::UiLanguageChangeCallback(
+ const ListValue* args) {
+ const std::string language_code = WideToASCII(ExtractStringValue(args));
+ CHECK(!language_code.empty());
+ const std::string action = StringPrintf(
+ "LanguageOptions_UiLanguageChange_%s", language_code.c_str());
+ UserMetrics::RecordComputedAction(action);
+
+ PrefService* prefs = g_browser_process->local_state();
+ prefs->SetString(prefs::kApplicationLocale, language_code);
+ prefs->SavePersistentPrefs();
+ dom_ui_->CallJavascriptFunction(
+ L"options.LanguageOptions.uiLanguageSaved");
+}
+
+void LanguageOptionsHandler::RestartCallback(const ListValue* args) {
+ UserMetrics::RecordAction(UserMetricsAction("LanguageOptions_Restart"));
+
+ Browser* browser = Browser::GetBrowserForController(
+ &dom_ui_->tab_contents()->controller(), NULL);
+ // TODO(kochi): For ChromiumOS, just exiting means browser restart.
+ // Implement browser restart for Chromium Win/Linux/Mac.
+ if (browser)
+ browser->ExecuteCommand(IDC_EXIT);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/language_options_handler.h b/chrome/browser/chromeos/dom_ui/language_options_handler.h
index da17a41..79ab685 100644
--- a/chrome/browser/chromeos/dom_ui/language_options_handler.h
+++ b/chrome/browser/chromeos/dom_ui/language_options_handler.h
@@ -4,10 +4,15 @@
#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LANGUAGE_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_DOM_UI_LANGUAGE_OPTIONS_HANDLER_H_
+#pragma once
+#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/dom_ui/options_ui.h"
class DictionaryValue;
+class ListValue;
+
+namespace chromeos {
// ChromeOS language options page UI handler.
class LanguageOptionsHandler : public OptionsPageUIHandler {
@@ -18,8 +23,61 @@ class LanguageOptionsHandler : public OptionsPageUIHandler {
// OptionsUIHandler implementation.
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+ // DOMMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // The following static methods are public for ease of testing.
+
+ // Gets the list of input methods from the given input descriptors.
+ // The return value will look like:
+ // [{'id': 'pinyin', 'displayName': 'Pinyin',
+ // 'languageCodeSet': {'zh-CW': true}}, ...]
+ //
+ // Note that true in languageCodeSet does not mean anything. We just use
+ // the dictionary as a set.
+ static ListValue* GetInputMethodList(
+ const InputMethodDescriptors& descriptors);
+
+ // Gets the list of languages from the given input descriptors.
+ // The return value will look like:
+ // [{'code': 'fi', 'displayName': 'Finnish', 'nativeDisplayName': 'suomi'},
+ // ...]
+ static ListValue* GetLanguageList(const InputMethodDescriptors& descriptors);
+
+ // Gets the set of language codes that can be used as UI language.
+ // The return value will look like:
+ // {'en-US': true, 'fi': true, 'fr': true, ...}
+ //
+ // Note that true in languageCodeSet does not mean anything. We just use
+ // the dictionary as a set.
+ static DictionaryValue* GetUiLanguageCodeSet();
+
private:
+ // Called when the input method is disabled.
+ // |args| will contain the input method ID as string (ex. "mozc").
+ void InputMethodDisableCallback(const ListValue* args);
+
+ // Called when the input method is enabled.
+ // |args| will contain the input method ID as string (ex. "mozc").
+ void InputMethodEnableCallback(const ListValue* args);
+
+ // Called when the input method options page is opened.
+ // |args| will contain the input method ID as string (ex. "mozc").
+ void InputMethodOptionsOpenCallback(const ListValue* args);
+
+ // Called when the language options is opened.
+ void LanguageOptionsOpenCallback(const ListValue* args);
+
+ // Called when the UI language is changed.
+ // |args| will contain the language code as string (ex. "fr").
+ void UiLanguageChangeCallback(const ListValue* args);
+
+ // Called when the restart button is clicked.
+ void RestartCallback(const ListValue* args);
+
DISALLOW_COPY_AND_ASSIGN(LanguageOptionsHandler);
};
+} // namespace
+
#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LANGUAGE_OPTIONS_HANDLER_H_
diff --git a/chrome/browser/chromeos/dom_ui/sync_options_handler.cc b/chrome/browser/chromeos/dom_ui/sync_options_handler.cc
deleted file mode 100644
index 073b8d4..0000000
--- a/chrome/browser/chromeos/dom_ui/sync_options_handler.cc
+++ /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 "chrome/browser/chromeos/dom_ui/sync_options_handler.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/i18n/time_formatting.h"
-#include "base/stl_util-inl.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/common/notification_service.h"
-#include "grit/browser_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "grit/theme_resources.h"
-
-SyncOptionsHandler::SyncOptionsHandler() {}
-
-SyncOptionsHandler::~SyncOptionsHandler() {}
-
-void SyncOptionsHandler::GetLocalizedValues(
- DictionaryValue* localized_strings) {
- DCHECK(localized_strings);
- // Sync page - ChromeOS
- localized_strings->SetString(L"syncPage",
- l10n_util::GetString(IDS_SYNC_NTP_SYNC_SECTION_TITLE));
- localized_strings->SetString(L"sync_title",
- l10n_util::GetString(IDS_CUSTOMIZE_SYNC_DESCRIPTION));
- localized_strings->SetString(L"syncsettings",
- l10n_util::GetString(IDS_SYNC_DATATYPE_PREFERENCES));
- localized_strings->SetString(L"syncbookmarks",
- l10n_util::GetString(IDS_SYNC_DATATYPE_BOOKMARKS));
- localized_strings->SetString(L"synctypedurls",
- l10n_util::GetString(IDS_SYNC_DATATYPE_TYPED_URLS));
- localized_strings->SetString(L"syncpasswords",
- l10n_util::GetString(IDS_SYNC_DATATYPE_PASSWORDS));
- localized_strings->SetString(L"syncextensions",
- l10n_util::GetString(IDS_SYNC_DATATYPE_EXTENSIONS));
- localized_strings->SetString(L"syncautofill",
- l10n_util::GetString(IDS_SYNC_DATATYPE_AUTOFILL));
- localized_strings->SetString(L"syncthemes",
- l10n_util::GetString(IDS_SYNC_DATATYPE_THEMES));
-}
diff --git a/chrome/browser/chromeos/dom_ui/sync_options_handler.h b/chrome/browser/chromeos/dom_ui/sync_options_handler.h
deleted file mode 100644
index a58c583..0000000
--- a/chrome/browser/chromeos/dom_ui/sync_options_handler.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 CHROME_BROWSER_CHROMEOS_DOM_UI_SYNC_OPTIONS_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_DOM_UI_SYNC_OPTIONS_HANDLER_H_
-
-#include "chrome/browser/dom_ui/options_ui.h"
-
-// ChromeOS system options page UI handler.
-class SyncOptionsHandler : public OptionsPageUIHandler {
- public:
- SyncOptionsHandler();
- virtual ~SyncOptionsHandler();
-
- // OptionsUIHandler implementation.
- virtual void GetLocalizedValues(DictionaryValue* localized_strings);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SyncOptionsHandler);
-};
-
-#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_SYNC_OPTIONS_HANDLER_H_
diff --git a/chrome/browser/chromeos/dom_ui/system_options_handler.cc b/chrome/browser/chromeos/dom_ui/system_options_handler.cc
index b280526..d47c82c 100644
--- a/chrome/browser/chromeos/dom_ui/system_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/system_options_handler.cc
@@ -4,15 +4,16 @@
#include "chrome/browser/chromeos/dom_ui/system_options_handler.h"
+#include <string>
+
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/callback.h"
-#include "base/i18n/time_formatting.h"
-#include "base/stl_util-inl.h"
-#include "base/time.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#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"
@@ -20,124 +21,49 @@
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
-static const char* kTimeZonesUtf8[] = {
- "Pacific/Samoa",
- "US/Hawaii",
- "US/Alaska",
- "US/Pacific",
- "US/Mountain",
- "US/Central",
- "US/Eastern",
- "America/Santiago",
- "America/Sao_Paulo",
- "Atlantic/South_Georgia",
- "Atlantic/Cape_Verde",
- "Europe/London",
- "Europe/Rome",
- "Europe/Helsinki",
- "Europe/Moscow",
- "Asia/Dubai",
- "Asia/Karachi",
- "Asia/Dhaka",
- "Asia/Bangkok",
- "Asia/Hong_Kong",
- "Asia/Tokyo",
- "Australia/Sydney",
- "Asia/Magadan",
- "Pacific/Auckland" };
-
-SystemOptionsHandler::SystemOptionsHandler() {
- // TODO(chocobo): For now, add all the GMT timezones.
- // We may eventually want to use icu::TimeZone::createEnumeration()
- // to list all the timezones and pick the ones we want to show.
- // NOTE: This currently does not handle daylight savings properly
- // b/c this is just a manually selected list of timezones that
- // happen to span the GMT-11 to GMT+12 Today. When daylight savings
- // kick in, this list might have more than one timezone in the same
- // GMT bucket.
- for (size_t i = 0; i < arraysize(kTimeZonesUtf8); i++) {
- timezones_.push_back(icu::TimeZone::createTimeZone(
- icu::UnicodeString::fromUTF8(kTimeZonesUtf8[i])));
- }
+SystemOptionsHandler::SystemOptionsHandler()
+ : chromeos::CrosOptionsPageUIHandler(
+ new chromeos::SystemSettingsProvider()) {
}
SystemOptionsHandler::~SystemOptionsHandler() {
- STLDeleteElements(&timezones_);
}
void SystemOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
// System page - ChromeOS
- localized_strings->SetString(L"systemPage",
- l10n_util::GetString(IDS_OPTIONS_SYSTEM_TAB_LABEL));
- localized_strings->SetString(L"datetime_title",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME));
- localized_strings->SetString(L"timezone",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION));
+ localized_strings->SetString("systemPage",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SYSTEM_TAB_LABEL));
+ localized_strings->SetString("datetime_title",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME));
+ localized_strings->SetString("timezone",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION));
- localized_strings->SetString(L"touchpad",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_TOUCHPAD));
- localized_strings->SetString(L"enable_tap_to_click",
- l10n_util::GetString(
+ localized_strings->SetString("touchpad",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_TOUCHPAD));
+ localized_strings->SetString("enable_tap_to_click",
+ l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_TAP_TO_CLICK_ENABLED_DESCRIPTION));
- localized_strings->SetString(L"enable_vert_edge_scroll",
- l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_VERT_EDGE_SCROLL_ENABLED_DESCRIPTION));
- localized_strings->SetString(L"sensitivity",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SENSITIVITY_DESCRIPTION));
- localized_strings->SetString(L"speed_factor",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SPEED_FACTOR_DESCRIPTION));
-
- localized_strings->SetString(L"language",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE));
- localized_strings->SetString(L"language_customize",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE));
+ localized_strings->SetString("sensitivity",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SENSITIVITY_DESCRIPTION));
- localized_strings->SetString(L"accessibility_title",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY));
- localized_strings->SetString(L"accessibility",
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DESCRIPTION));
-
- localized_strings->Set(L"timezoneList", GetTimezoneList());
-}
+ localized_strings->SetString("language",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE));
+ localized_strings->SetString("language_customize",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE));
+ localized_strings->SetString("modifier_keys_customize",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_MODIFIER_KEYS_CUSTOMIZE));
-ListValue* SystemOptionsHandler::GetTimezoneList() {
- ListValue* timezoneList = new ListValue();
- for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin();
- iter != timezones_.end(); ++iter) {
- const icu::TimeZone* timezone = *iter;
- ListValue* option = new ListValue();
- option->Append(Value::CreateStringValue(GetTimezoneID(timezone)));
- option->Append(Value::CreateStringValue(GetTimezoneName(timezone)));
- timezoneList->Append(option);
- }
- return timezoneList;
-}
-
-std::wstring SystemOptionsHandler::GetTimezoneName(
- const icu::TimeZone* timezone) {
- DCHECK(timezone);
- icu::UnicodeString name;
- timezone->getDisplayName(name);
- std::wstring output;
- UTF16ToWide(name.getBuffer(), name.length(), &output);
- int hour_offset = timezone->getRawOffset() / 3600000;
- const wchar_t* format;
- if (hour_offset == 0)
- format = L"(GMT) ";
- else
- format = L"(GMT%+d) ";
-
- return StringPrintf(format, hour_offset) + output;
-}
+ localized_strings->SetString("accessibility_title",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY));
+ localized_strings->SetString("accessibility",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DESCRIPTION));
-std::wstring SystemOptionsHandler::GetTimezoneID(
- const icu::TimeZone* timezone) {
- DCHECK(timezone);
- icu::UnicodeString id;
- timezone->getID(id);
- std::wstring output;
- UTF16ToWide(id.getBuffer(), id.length(), &output);
- return output;
+ localized_strings->Set("timezoneList",
+ reinterpret_cast<chromeos::SystemSettingsProvider*>(
+ settings_provider_.get())->GetTimezoneList());
}
diff --git a/chrome/browser/chromeos/dom_ui/system_options_handler.h b/chrome/browser/chromeos/dom_ui/system_options_handler.h
index c21d5b0..5d96050 100644
--- a/chrome/browser/chromeos/dom_ui/system_options_handler.h
+++ b/chrome/browser/chromeos/dom_ui/system_options_handler.h
@@ -4,15 +4,14 @@
#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_SYSTEM_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_DOM_UI_SYSTEM_OPTIONS_HANDLER_H_
+#pragma once
-#include <string>
-#include <vector>
+#include "chrome/browser/chromeos/dom_ui/cros_options_page_ui_handler.h"
-#include "chrome/browser/dom_ui/options_ui.h"
-#include "third_party/icu/public/i18n/unicode/timezone.h"
+class DictionaryValue;
// ChromeOS system options page UI handler.
-class SystemOptionsHandler : public OptionsPageUIHandler {
+class SystemOptionsHandler : public chromeos::CrosOptionsPageUIHandler {
public:
SystemOptionsHandler();
virtual ~SystemOptionsHandler();
@@ -21,18 +20,6 @@ class SystemOptionsHandler : public OptionsPageUIHandler {
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
private:
- // Creates the map of timezones used by the options page.
- ListValue* GetTimezoneList();
-
- // Gets timezone name.
- std::wstring GetTimezoneName(const icu::TimeZone* timezone);
-
- // Gets timezone ID which is also used as timezone pref value.
- std::wstring GetTimezoneID(const icu::TimeZone* timezone);
-
- // Timezones.
- std::vector<icu::TimeZone*> timezones_;
-
DISALLOW_COPY_AND_ASSIGN(SystemOptionsHandler);
};
diff --git a/chrome/browser/chromeos/drop_shadow_label.h b/chrome/browser/chromeos/drop_shadow_label.h
index 21ed7eb..5848160 100644
--- a/chrome/browser/chromeos/drop_shadow_label.h
+++ b/chrome/browser/chromeos/drop_shadow_label.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_DROP_SHADOW_LABEL_H_
#define CHROME_BROWSER_CHROMEOS_DROP_SHADOW_LABEL_H_
+#pragma once
#include "gfx/font.h"
#include "views/controls/label.h"
diff --git a/chrome/browser/chromeos/external_cookie_handler.h b/chrome/browser/chromeos/external_cookie_handler.h
index aef3367..b422ace 100644
--- a/chrome/browser/chromeos/external_cookie_handler.h
+++ b/chrome/browser/chromeos/external_cookie_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_EXTERNAL_COOKIE_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_EXTERNAL_COOKIE_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/external_metrics.h b/chrome/browser/chromeos/external_metrics.h
index 0af3dad..eac8c64 100644
--- a/chrome/browser/chromeos/external_metrics.h
+++ b/chrome/browser/chromeos/external_metrics.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_EXTERNAL_METRICS_H_
#define CHROME_BROWSER_CHROMEOS_EXTERNAL_METRICS_H_
+#pragma once
#include "base/basictypes.h"
#include "base/compiler_specific.h"
diff --git a/chrome/browser/chromeos/external_protocol_dialog.cc b/chrome/browser/chromeos/external_protocol_dialog.cc
index 5aeb8a9..2c53a29 100644
--- a/chrome/browser/chromeos/external_protocol_dialog.cc
+++ b/chrome/browser/chromeos/external_protocol_dialog.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.
@@ -82,7 +82,7 @@ views::View* ExternalProtocolDialog::GetContentsView() {
ExternalProtocolDialog::ExternalProtocolDialog(TabContents* tab_contents,
const GURL& url)
: creation_time_(base::TimeTicks::Now()),
- scheme_(UTF8ToWide(url.scheme())) {
+ scheme_(url.scheme()) {
const int kMaxUrlWithoutSchemeSize = 256;
std::wstring elided_url_without_scheme;
ElideString(ASCIIToWide(url.possibly_invalid_spec()),
diff --git a/chrome/browser/chromeos/external_protocol_dialog.h b/chrome/browser/chromeos/external_protocol_dialog.h
index 71ca656..84f7955 100644
--- a/chrome/browser/chromeos/external_protocol_dialog.h
+++ b/chrome/browser/chromeos/external_protocol_dialog.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_CHROMEOS_EXTERNAL_PROTOCOL_DIALOG_H_
#define CHROME_BROWSER_CHROMEOS_EXTERNAL_PROTOCOL_DIALOG_H_
+#pragma once
#include "base/time.h"
#include "views/window/dialog_delegate.h"
@@ -43,7 +44,7 @@ class ExternalProtocolDialog : public views::DialogDelegate {
base::TimeTicks creation_time_;
// The scheme of the url.
- std::wstring scheme_;
+ std::string scheme_;
DISALLOW_COPY_AND_ASSIGN(ExternalProtocolDialog);
};
diff --git a/chrome/browser/chromeos/frame/browser_frame_chromeos.cc b/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
index c0ca464..c946924 100644
--- a/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
+++ b/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
@@ -4,8 +4,11 @@
#include "chrome/browser/chromeos/frame/browser_frame_chromeos.h"
-#include "chrome/browser/chromeos/frame/normal_browser_frame_view.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/common/chrome_switches.h"
// static (Factory method.)
BrowserFrame* BrowserFrame::Create(BrowserView* browser_view,
@@ -27,21 +30,28 @@ BrowserFrameChromeos::~BrowserFrameChromeos() {
}
void BrowserFrameChromeos::Init() {
- // Excludes a browser intance that requires icon/title. This is typically true
- // for dev tools and javascript console.
- // TODO(oshima): handle app panels. This currently uses the default
- // implementation, which opens Chrome's app panel instead of
- // ChromeOS's panel.
- if (!IsPanel() &&
- !browser_view()->ShouldShowWindowIcon() &&
- !browser_view()->ShouldShowWindowTitle()) {
- set_browser_frame_view(new NormalBrowserFrameView(this, browser_view()));
+ // NOTE: This logic supersedes the logic in BrowserFrameGtk::Init()
+ // by always setting browser_frame_view_.
+ if (IsPanel()) {
+ // ChromeOS Panels should always use PopupNonClientFrameView.
+ set_browser_frame_view(new PopupNonClientFrameView());
+ } else {
+ // Default FrameView.
+ set_browser_frame_view(new OpaqueBrowserFrameView(this, browser_view()));
}
+
BrowserFrameGtk::Init();
+
+ if (!IsPanel()) {
+ // On chromeos we want windows to always render as active.
+ GetNonClientView()->DisableInactiveRendering(true);
+ }
}
bool BrowserFrameChromeos::IsMaximized() const {
- return !IsPanel() || WindowGtk::IsMaximized();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeosFrame))
+ return WindowGtk::IsMaximized();
+ return !IsFullscreen() && (!IsPanel() || WindowGtk::IsMaximized());
}
bool BrowserFrameChromeos::IsPanel() const {
diff --git a/chrome/browser/chromeos/frame/browser_frame_chromeos.h b/chrome/browser/chromeos/frame/browser_frame_chromeos.h
index b776591..4863047 100644
--- a/chrome/browser/chromeos/frame/browser_frame_chromeos.h
+++ b/chrome/browser/chromeos/frame/browser_frame_chromeos.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_FRAME_BROWSER_FRAME_CHROMEOS_H_
#define CHROME_BROWSER_CHROMEOS_FRAME_BROWSER_FRAME_CHROMEOS_H_
+#pragma once
#include "chrome/browser/views/frame/browser_frame_gtk.h"
diff --git a/chrome/browser/chromeos/frame/browser_view.cc b/chrome/browser/chromeos/frame/browser_view.cc
index 25ecefd..8ffbe2e 100644
--- a/chrome/browser/chromeos/frame/browser_view.cc
+++ b/chrome/browser/chromeos/frame/browser_view.cc
@@ -12,11 +12,10 @@
#include "base/command_line.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chromeos/frame/panel_browser_view.h"
-#include "chrome/browser/chromeos/options/language_config_view.h"
-#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/status/language_menu_button.h"
#include "chrome/browser/chromeos/status/network_menu_button.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
+#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/view_ids.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/views/app_launcher.h"
@@ -28,12 +27,11 @@
#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 "cros/chromeos_wm_ipc_enums.h"
#include "views/controls/button/button.h"
#include "views/controls/button/image_button.h"
-#include "views/controls/image_view.h"
#include "views/controls/menu/menu_2.h"
#include "views/screen.h"
#include "views/widget/root_view.h"
@@ -42,15 +40,6 @@
namespace {
-// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the
-// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
-// user).
-const int kOTRBottomSpacing = 2;
-
-// There are 2 px on each side of the OTR avatar (between the frame border and
-// it on the left, and between it and the tabstrip on the right).
-const int kOTRSideSpacing = 2;
-
// Amount to offset the toolbar by when vertical tabs are enabled.
const int kVerticalTabStripToolbarOffset = 2;
@@ -83,9 +72,6 @@ class BrowserViewLayout : public ::BrowserViewLayout {
case VIEW_ID_STATUS_AREA:
status_area_ = static_cast<chromeos::StatusAreaView*>(view);
break;
- case VIEW_ID_OTR_AVATAR:
- otr_avatar_icon_ = view;
- break;
}
}
@@ -95,21 +81,20 @@ class BrowserViewLayout : public ::BrowserViewLayout {
virtual int LayoutTabStrip() {
if (browser_view_->IsFullscreen() || !browser_view_->IsTabStripVisible()) {
status_area_->SetVisible(false);
- otr_avatar_icon_->SetVisible(false);
tabstrip_->SetVisible(false);
tabstrip_->SetBounds(0, 0, 0, 0);
return 0;
- } else {
- gfx::Rect layout_bounds =
- browser_view_->frame()->GetBoundsForTabStrip(tabstrip_);
- gfx::Point tabstrip_origin = layout_bounds.origin();
- views::View::ConvertPointToView(browser_view_->GetParent(), browser_view_,
- &tabstrip_origin);
- layout_bounds.set_origin(tabstrip_origin);
- if (browser_view_->UseVerticalTabs())
- return LayoutTitlebarComponentsWithVerticalTabs(layout_bounds);
- return LayoutTitlebarComponents(layout_bounds);
}
+
+ gfx::Rect tabstrip_bounds(
+ browser_view_->frame()->GetBoundsForTabStrip(tabstrip_));
+ gfx::Point tabstrip_origin = tabstrip_bounds.origin();
+ views::View::ConvertPointToView(browser_view_->GetParent(), browser_view_,
+ &tabstrip_origin);
+ tabstrip_bounds.set_origin(tabstrip_origin);
+ return browser_view_->UseVerticalTabs() ?
+ LayoutTitlebarComponentsWithVerticalTabs(tabstrip_bounds) :
+ LayoutTitlebarComponents(tabstrip_bounds);
}
virtual int LayoutToolbar(int top) {
@@ -154,33 +139,20 @@ class BrowserViewLayout : public ::BrowserViewLayout {
return false;
}
- // Positions the titlebar, toolbar, tabstrip, tabstrip and otr icon. This is
+ // Positions the titlebar, toolbar and tabstrip. This is
// used when side tabs are enabled.
int LayoutTitlebarComponentsWithVerticalTabs(const gfx::Rect& bounds) {
if (bounds.IsEmpty())
return 0;
tabstrip_->SetVisible(true);
- otr_avatar_icon_->SetVisible(browser_view_->ShouldShowOffTheRecordAvatar());
status_area_->SetVisible(true);
gfx::Size status_size = status_area_->GetPreferredSize();
int status_height = status_size.height();
- // Layout the otr icon.
int status_x = bounds.x();
- if (!otr_avatar_icon_->IsVisible()) {
- otr_avatar_icon_->SetBounds(0, 0, 0, 0);
- } else {
- gfx::Size otr_size = otr_avatar_icon_->GetPreferredSize();
-
- status_height = std::max(status_height, otr_size.height());
- int y = bounds.bottom() - status_height;
- otr_avatar_icon_->SetBounds(status_x, y, otr_size.width(), status_height);
- status_x += otr_size.width();
- }
-
- // Layout the status area after the otr icon.
+ // Layout the status area.
status_area_->SetBounds(status_x, bounds.bottom() - status_height,
status_size.width(), status_height);
@@ -211,66 +183,33 @@ class BrowserViewLayout : public ::BrowserViewLayout {
return bounds.y() + toolbar_height;
}
- // Layouts components in the title bar area (given by
- // |bounds|). These include the main menu, the otr avatar icon (in
- // incognito window), the tabstrip and the the status area.
+ // Lays out tabstrip and status area in the title bar area (given by
+ // |bounds|).
int LayoutTitlebarComponents(const gfx::Rect& bounds) {
- if (bounds.IsEmpty()) {
+ if (bounds.IsEmpty())
return 0;
- }
+
tabstrip_->SetVisible(true);
- otr_avatar_icon_->SetVisible(browser_view_->ShouldShowOffTheRecordAvatar());
status_area_->SetVisible(true);
- int bottom = bounds.bottom();
-
// Layout status area after tab strip.
gfx::Size status_size = status_area_->GetPreferredSize();
- status_area_->SetBounds(bounds.x() + bounds.width() - status_size.width(),
- bounds.y(), status_size.width(),
- status_size.height());
- LayoutOTRAvatar(bounds);
-
- int curx = bounds.x();
- int remaining_width = std::max(
- 0, // In case there is no space left.
- otr_avatar_icon_->bounds().x() - curx);
-
- tabstrip_->SetBounds(curx, bounds.y(), remaining_width, bounds.height());
-
- gfx::Rect toolbar_bounds = browser_view_->GetToolbarBounds();
- tabstrip_->SetBackgroundOffset(
- gfx::Point(curx - toolbar_bounds.x(), bounds.y()));
- return bottom;
- }
-
- // Layouts OTR avatar within the given |bounds|.
- void LayoutOTRAvatar(const gfx::Rect& bounds) {
- gfx::Rect status_bounds = status_area_->bounds();
- if (!otr_avatar_icon_->IsVisible()) {
- otr_avatar_icon_->SetBounds(status_bounds.x(), status_bounds.y(), 0, 0);
- } else {
- gfx::Size preferred_size = otr_avatar_icon_->GetPreferredSize();
-
- int y = bounds.bottom() - preferred_size.height() - kOTRBottomSpacing;
- int x = status_bounds.x() - kOTRSideSpacing - preferred_size.width();
- otr_avatar_icon_->SetBounds(x, y, preferred_size.width(),
- preferred_size.height());
- }
+ status_area_->SetBounds(bounds.right() - status_size.width(), bounds.y(),
+ status_size.width(), status_size.height());
+ tabstrip_->SetBounds(bounds.x(), bounds.y(),
+ std::max(0, status_area_->bounds().x() - bounds.x()),
+ bounds.height());
+ return bounds.bottom();
}
-
chromeos::StatusAreaView* status_area_;
- views::View* otr_avatar_icon_;
DISALLOW_COPY_AND_ASSIGN(BrowserViewLayout);
};
BrowserView::BrowserView(Browser* browser)
: ::BrowserView(browser),
- status_area_(NULL),
- force_maximized_window_(false),
- otr_avatar_icon_(new views::ImageView()) {
+ status_area_(NULL) {
}
BrowserView::~BrowserView() {
@@ -294,10 +233,6 @@ void BrowserView::Init() {
BrowserFrameGtk* gtk_frame = static_cast<BrowserFrameGtk*>(frame());
gtk_frame->GetNonClientView()->SetContextMenuController(this);
- otr_avatar_icon_->SetImage(GetOTRAvatarIcon());
- otr_avatar_icon_->SetID(VIEW_ID_OTR_AVATAR);
- AddChildView(otr_avatar_icon_);
-
// Make sure the window is set to the right type.
std::vector<int> params;
params.push_back(browser()->tab_count());
@@ -333,11 +268,6 @@ views::LayoutManager* BrowserView::CreateLayoutManager() const {
return new BrowserViewLayout();
}
-void BrowserView::InitTabStrip(TabStripModel* tab_strip_model) {
- ::BrowserView::InitTabStrip(tab_strip_model);
- UpdateOTRBackground();
-}
-
void BrowserView::ChildPreferredSizeChanged(View* child) {
Layout();
SchedulePaint();
@@ -394,8 +324,7 @@ void BrowserView::OpenButtonOptions(const views::View* button_view) const {
if (button_view == status_area_->network_view()) {
browser()->OpenInternetOptionsDialog();
} else if (button_view == status_area_->language_view()) {
- LanguageConfigView::Show(GetProfile(),
- frame()->GetWindow()->GetNativeWindow());
+ browser()->OpenLanguageOptionsDialog();
} else {
browser()->OpenSystemOptionsDialog();
}
@@ -432,20 +361,15 @@ void BrowserView::InitSystemMenu() {
system_menu_menu_.reset(new views::Menu2(system_menu_contents_.get()));
}
-void BrowserView::UpdateOTRBackground() {
- if (UseVerticalTabs())
- otr_avatar_icon_->set_background(new ThemeBackground(this));
- else
- otr_avatar_icon_->set_background(NULL);
-}
-
} // namespace chromeos
// static
BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
// Create a browser view for chromeos.
BrowserView* view;
- if (browser->type() & Browser::TYPE_POPUP)
+ if ((browser->type() == Browser::TYPE_POPUP) ||
+ (browser->type() == Browser::TYPE_APP_POPUP) ||
+ (browser->type() == Browser::TYPE_APP_PANEL))
view = new chromeos::PanelBrowserView(browser);
else
view = new chromeos::BrowserView(browser);
diff --git a/chrome/browser/chromeos/frame/browser_view.h b/chrome/browser/chromeos/frame/browser_view.h
index 0e9f40b..3c81c12 100644
--- a/chrome/browser/chromeos/frame/browser_view.h
+++ b/chrome/browser/chromeos/frame/browser_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_FRAME_BROWSER_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_FRAME_BROWSER_VIEW_H_
+#pragma once
#include <vector>
@@ -49,7 +50,6 @@ class BrowserView : public ::BrowserView,
virtual void Show();
virtual void FocusChromeOSStatus();
virtual views::LayoutManager* CreateLayoutManager() const;
- virtual void InitTabStrip(TabStripModel* tab_strip_model);
virtual void ChildPreferredSizeChanged(View* child);
virtual bool GetSavedWindowBounds(gfx::Rect* bounds) const;
@@ -75,10 +75,6 @@ class BrowserView : public ::BrowserView,
private:
void InitSystemMenu();
- // Updates the background of the otr icon. The background differs for vertical
- // tabs.
- void UpdateOTRBackground();
-
// Status Area view.
StatusAreaView* status_area_;
@@ -86,12 +82,6 @@ class BrowserView : public ::BrowserView,
scoped_ptr<menus::SimpleMenuModel> system_menu_contents_;
scoped_ptr<views::Menu2> system_menu_menu_;
- // A flag to specify if the browser window should be maximized.
- bool force_maximized_window_;
-
- // Off the record icon.
- views::ImageView* otr_avatar_icon_;
-
DISALLOW_COPY_AND_ASSIGN(BrowserView);
};
diff --git a/chrome/browser/chromeos/frame/normal_browser_frame_view.cc b/chrome/browser/chromeos/frame/normal_browser_frame_view.cc
deleted file mode 100644
index 84c4614..0000000
--- a/chrome/browser/chromeos/frame/normal_browser_frame_view.cc
+++ /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.
-
-#include "chrome/browser/chromeos/frame/normal_browser_frame_view.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "app/theme_provider.h"
-#include "app/x11_util.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "chrome/browser/browser_theme_provider.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/views/frame/browser_frame.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/tabs/tab_strip.h"
-#include "chrome/common/chrome_switches.h"
-#include "gfx/canvas.h"
-#include "gfx/font.h"
-#include "gfx/path.h"
-#include "grit/app_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "views/controls/button/image_button.h"
-#include "views/controls/image_view.h"
-#include "views/window/hit_test.h"
-#include "views/widget/root_view.h"
-#include "views/window/window.h"
-#include "views/window/window_resources.h"
-
-namespace {
-
-// The frame border is usually 0 as chromeos has no border. The border
-// can be enabled (4px fixed) with the command line option
-// "--chromeos-frame" so that one can resize the window on dev machine.
-const int kFrameBorderThicknessForDev = 4;
-
-// While resize areas on Windows are normally the same size as the window
-// borders, our top area is shrunk by 1 px to make it easier to move the window
-// around with our thinner top grabbable strip. (Incidentally, our side and
-// bottom resize areas don't match the frame border thickness either -- they
-// span the whole nonclient area, so there's no "dead zone" for the mouse.)
-const int kTopResizeAdjust = 1;
-
-// In the window corners, the resize areas don't actually expand bigger, but the
-// 16 px at the end of each edge triggers diagonal resizing.
-const int kResizeAreaCornerSize = 16;
-
-// The icon is inset 2 px from the left frame border.
-const int kIconLeftSpacing = 2;
-
-// The top 1 px of the tabstrip is shadow; in maximized mode we push this off
-// the top of the screen so the tabs appear flush against the screen edge.
-const int kTabstripTopShadowThickness = 1;
-
-const int kCustomFrameBackgroundVerticalOffset = 15;
-
-} // namespace
-
-namespace chromeos {
-
-///////////////////////////////////////////////////////////////////////////////
-// NormalBrowserFrameView, public:
-
-NormalBrowserFrameView::NormalBrowserFrameView(BrowserFrame* frame,
- BrowserView* browser_view)
- : BrowserNonClientFrameView(),
- frame_(frame),
- browser_view_(browser_view) {
- // Normal window does not have the window title/icon.
- DCHECK(!browser_view_->ShouldShowWindowIcon());
- DCHECK(!browser_view_->ShouldShowWindowTitle());
- DCHECK(!frame_->GetWindow()->GetDelegate()->ShouldShowWindowTitle());
- DCHECK(!frame_->GetWindow()->GetDelegate()->ShouldShowWindowIcon());
-}
-
-NormalBrowserFrameView::~NormalBrowserFrameView() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NormalBrowserFrameView, BrowserNonClientFrameView implementation:
-
-gfx::Rect NormalBrowserFrameView::GetBoundsForTabStrip(
- BaseTabStrip* tabstrip) const {
- int border_thickness = FrameBorderThickness();
- if (browser_view_->UseVerticalTabs()) {
- // BrowserViewLayout adjusts the height/width based on the status area and
- // otr icon.
- gfx::Size ps = tabstrip->GetPreferredSize();
- return gfx::Rect(border_thickness, NonClientTopBorderHeight(),
- ps.width(), browser_view_->height());
- }
- return gfx::Rect(border_thickness, NonClientTopBorderHeight(),
- std::max(0, width() - (2 * border_thickness)),
- tabstrip->GetPreferredHeight());
-}
-
-void NormalBrowserFrameView::UpdateThrobber(bool running) {
- // No window icon.
-}
-
-gfx::Size NormalBrowserFrameView::GetMinimumSize() {
- gfx::Size min_size(browser_view_->GetMinimumSize());
- int border_thickness = FrameBorderThickness();
- min_size.Enlarge(2 * border_thickness,
- NonClientTopBorderHeight() + border_thickness);
-
- int min_titlebar_width = (2 * border_thickness) + kIconLeftSpacing;
- min_size.set_width(std::max(min_size.width(), min_titlebar_width));
- return min_size;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NormalBrowserFrameView, views::NonClientFrameView implementation:
-
-gfx::Rect NormalBrowserFrameView::GetBoundsForClientView() const {
- return client_view_bounds_;
-}
-
-bool NormalBrowserFrameView::AlwaysUseNativeFrame() const {
- return frame_->AlwaysUseNativeFrame();
-}
-
-gfx::Rect NormalBrowserFrameView::GetWindowBoundsForClientBounds(
- const gfx::Rect& client_bounds) const {
- int top_height = NonClientTopBorderHeight();
- int border_thickness = FrameBorderThickness();
- return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
- std::max(0, client_bounds.y() - top_height),
- client_bounds.width() + (2 * border_thickness),
- client_bounds.height() + top_height + border_thickness);
-}
-
-int NormalBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
- if (!bounds().Contains(point))
- return HTNOWHERE;
- int frame_component =
- frame_->GetWindow()->GetClientView()->NonClientHitTest(point);
- if (frame_component != HTNOWHERE)
- return frame_component;
- int border_thickness = FrameBorderThickness();
- int window_component = GetHTComponentForFrame(point,
- std::max(0, border_thickness - kTopResizeAdjust), border_thickness,
- kResizeAreaCornerSize, kResizeAreaCornerSize,
- frame_->GetWindow()->GetDelegate()->CanResize());
- // Fall back to the caption if no other component matches.
- return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
-}
-
-void NormalBrowserFrameView::GetWindowMask(const gfx::Size& size,
- gfx::Path* window_mask) {
- DCHECK(window_mask);
- // Always maximized.
-}
-
-void NormalBrowserFrameView::EnableClose(bool enable) {
- // No close button
-}
-
-void NormalBrowserFrameView::ResetWindowControls() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NormalBrowserFrameView, views::View overrides:
-
-void NormalBrowserFrameView::Paint(gfx::Canvas* canvas) {
- views::Window* window = frame_->GetWindow();
- if (window->IsFullscreen())
- return; // Nothing is visible, so don't bother to paint.
-
- PaintMaximizedFrameBorder(canvas);
- PaintToolbarBackground(canvas);
-}
-
-void NormalBrowserFrameView::Layout() {
- int top_height = NonClientTopBorderHeight();
- int border_thickness = FrameBorderThickness();
- client_view_bounds_ = gfx::Rect(border_thickness, top_height,
- std::max(0, width() - (2 * border_thickness)),
- std::max(0, height() - top_height - border_thickness));
-}
-
-bool NormalBrowserFrameView::HitTest(const gfx::Point& l) const {
- // If the point is outside the bounds of the client area, claim it.
- if (NonClientFrameView::HitTest(l))
- return true;
-
- // Otherwise claim it only if it's in a non-tab portion of the tabstrip.
- bool vertical_tabs = browser_view_->UseVerticalTabs();
- const gfx::Rect& tabstrip_bounds = browser_view_->tabstrip()->bounds();
- if ((!vertical_tabs && l.y() > tabstrip_bounds.bottom()) ||
- (vertical_tabs && (l.x() > tabstrip_bounds.right() ||
- l.y() > tabstrip_bounds.bottom()))) {
- return false;
- }
-
- // We convert from our parent's coordinates since we assume we fill its bounds
- // completely. We need to do this since we're not a parent of the tabstrip,
- // meaning ConvertPointToView would otherwise return something bogus.
- gfx::Point browser_view_point(l);
- View::ConvertPointToView(GetParent(), browser_view_, &browser_view_point);
- return browser_view_->IsPositionInWindowCaption(browser_view_point);
-}
-
-void NormalBrowserFrameView::ViewHierarchyChanged(bool is_add,
- views::View* parent,
- views::View* child) {
- if (is_add && child == this) {
- // The Accessibility glue looks for the product name on these two views to
- // determine if this is in fact a Chrome window.
- GetRootView()->SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME));
- }
-}
-
-bool NormalBrowserFrameView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_TITLEBAR;
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NormalBrowserFrameView, TabIconView::TabContentsProvider implementation:
-
-bool NormalBrowserFrameView::ShouldTabIconViewAnimate() const {
- // This function is queried during the creation of the window as the
- // TabIconView we host is initialized, so we need to NULL check the selected
- // TabContents because in this condition there is not yet a selected tab.
- TabContents* current_tab = browser_view_->GetSelectedTabContents();
- return current_tab ? current_tab->is_loading() : false;
-}
-
-SkBitmap NormalBrowserFrameView::GetFavIconForTabIconView() {
- return frame_->GetWindow()->GetDelegate()->GetWindowIcon();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NormalBrowserFrameView, private:
-
-int NormalBrowserFrameView::FrameBorderThickness() const {
- static int border_thickness_ =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeosFrame) ?
- kFrameBorderThicknessForDev : 0;
- return border_thickness_;
-}
-
-int NormalBrowserFrameView::NonClientTopBorderHeight() const {
- return std::max(0, FrameBorderThickness() -
- (browser_view_->IsTabStripVisible() ? kTabstripTopShadowThickness : 0));
-}
-
-void NormalBrowserFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
- ThemeProvider* tp = GetThemeProvider();
- views::Window* window = frame_->GetWindow();
-
- // Window frame mode and color
- SkBitmap* theme_frame;
- int y = 0;
- // Never theme app and popup windows.
- if (!browser_view_->IsBrowserTypeNormal()) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- theme_frame = rb.GetBitmapNamed(ShouldPaintAsActive() ?
- IDR_FRAME : IDR_FRAME_INACTIVE);
- } else if (!browser_view_->IsOffTheRecord()) {
- theme_frame = tp->GetBitmapNamed(ShouldPaintAsActive() ?
- IDR_THEME_FRAME : IDR_THEME_FRAME_INACTIVE);
- // TODO(oshima): gtk based CHROMEOS is using non custom frame
- // mode which does this adjustment. This should be removed
- // once it's fully migrated to views. -1 is due to the layout
- // difference between views and gtk and will be removed.
- // See http://crbug.com/28580.
- y = -kCustomFrameBackgroundVerticalOffset - 1;
- } else {
- theme_frame = tp->GetBitmapNamed(ShouldPaintAsActive() ?
- IDR_THEME_FRAME_INCOGNITO: IDR_THEME_FRAME_INCOGNITO_INACTIVE);
- y = -kCustomFrameBackgroundVerticalOffset - 1;
- }
- // Draw the theme frame.
- canvas->TileImageInt(*theme_frame, 0, y, width(), theme_frame->height());
-
- // Draw the theme frame overlay
- if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
- browser_view_->IsBrowserTypeNormal()) {
- SkBitmap* theme_overlay = tp->GetBitmapNamed(ShouldPaintAsActive() ?
- IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE);
- canvas->DrawBitmapInt(*theme_overlay, 0, 0);
- }
-
- if (!browser_view_->IsToolbarVisible()) {
- // There's no toolbar to edge the frame border, so we need to draw a bottom
- // edge. The graphic we use for this has a built in client edge, so we clip
- // it off the bottom.
- SkBitmap* top_center =
- tp->GetBitmapNamed(IDR_APP_TOP_CENTER);
- int edge_height = top_center->height() - kClientEdgeThickness;
- canvas->TileImageInt(*top_center, 0,
- window->GetClientView()->y() - edge_height, width(), edge_height);
- }
-}
-
-void NormalBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
- if (!browser_view_->IsToolbarVisible())
- return;
-
- gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds());
- if (toolbar_bounds.IsEmpty())
- return;
-
- ThemeProvider* tp = GetThemeProvider();
- gfx::Point toolbar_origin(toolbar_bounds.origin());
- View::ConvertPointToView(frame_->GetWindow()->GetClientView(),
- this, &toolbar_origin);
- toolbar_bounds.set_origin(toolbar_origin);
-
- // Gross hack: We split the toolbar images into two pieces, since sometimes
- // (popup mode) the toolbar isn't tall enough to show the whole image. The
- // split happens between the top shadow section and the bottom gradient
- // section so that we never break the gradient.
- int split_point = kFrameShadowThickness * 2;
- int bottom_y = toolbar_bounds.y() + split_point;
- SkBitmap* toolbar_left =
- tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER);
- int bottom_edge_height =
- std::min(toolbar_left->height(), toolbar_bounds.height()) - split_point;
-
- SkColor theme_toolbar_color =
- tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
- canvas->FillRectInt(theme_toolbar_color, toolbar_bounds.x(), bottom_y,
- toolbar_bounds.width(), bottom_edge_height);
-
- int strip_height = browser_view_->GetTabStripHeight();
- SkBitmap* theme_toolbar = tp->GetBitmapNamed(IDR_THEME_TOOLBAR);
-
- canvas->TileImageInt(*theme_toolbar,
- toolbar_bounds.x() - kClientEdgeThickness,
- strip_height - kFrameShadowThickness,
- toolbar_bounds.x() - kClientEdgeThickness, bottom_y,
- toolbar_bounds.width() + (2 * kClientEdgeThickness),
- theme_toolbar->height());
-
- canvas->DrawBitmapInt(*toolbar_left, 0, 0, toolbar_left->width(), split_point,
- toolbar_bounds.x() - toolbar_left->width(), toolbar_bounds.y(),
- toolbar_left->width(), split_point, false);
- canvas->DrawBitmapInt(*toolbar_left, 0,
- toolbar_left->height() - bottom_edge_height, toolbar_left->width(),
- bottom_edge_height, toolbar_bounds.x() - toolbar_left->width(), bottom_y,
- toolbar_left->width(), bottom_edge_height, false);
-
- SkBitmap* toolbar_center =
- tp->GetBitmapNamed(IDR_CONTENT_TOP_CENTER);
- canvas->TileImageInt(*toolbar_center, 0, 0, toolbar_bounds.x(),
- toolbar_bounds.y(), toolbar_bounds.width(), split_point);
-
- SkBitmap* toolbar_right = tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER);
- canvas->DrawBitmapInt(*toolbar_right, 0, 0, toolbar_right->width(),
- split_point, toolbar_bounds.right(), toolbar_bounds.y(),
- toolbar_right->width(), split_point, false);
- canvas->DrawBitmapInt(*toolbar_right, 0,
- toolbar_right->height() - bottom_edge_height, toolbar_right->width(),
- bottom_edge_height, toolbar_bounds.right(), bottom_y,
- toolbar_right->width(), bottom_edge_height, false);
-
- // Draw the content/toolbar separator.
- canvas->DrawLineInt(ResourceBundle::toolbar_separator_color,
- toolbar_bounds.x(), toolbar_bounds.bottom() - 1,
- toolbar_bounds.right() - 1, toolbar_bounds.bottom() - 1);
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/frame/normal_browser_frame_view.h b/chrome/browser/chromeos/frame/normal_browser_frame_view.h
deleted file mode 100644
index 5de45dc..0000000
--- a/chrome/browser/chromeos/frame/normal_browser_frame_view.h
+++ /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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_FRAME_NORMAL_BROWSER_FRAME_VIEW_H_
-#define CHROME_BROWSER_CHROMEOS_FRAME_NORMAL_BROWSER_FRAME_VIEW_H_
-
-#include "chrome/browser/views/frame/browser_frame.h"
-#include "chrome/browser/views/frame/browser_non_client_frame_view.h"
-#include "chrome/browser/views/tab_icon_view.h"
-#include "views/controls/button/button.h"
-#include "views/window/non_client_view.h"
-
-class BaseTabStrip;
-class BrowserView;
-namespace gfx {
-class Font;
-}
-class TabContents;
-namespace views {
-class ImageButton;
-class ImageView;
-}
-
-namespace chromeos {
-
-class NormalBrowserFrameView : public BrowserNonClientFrameView,
- public TabIconView::TabIconViewModel {
- public:
- // Constructs a non-client view for an BrowserFrame.
- NormalBrowserFrameView(BrowserFrame* frame, BrowserView* browser_view);
- virtual ~NormalBrowserFrameView();
-
- // Overridden from BrowserNonClientFrameView:
- virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const;
- virtual void UpdateThrobber(bool running);
- virtual gfx::Size GetMinimumSize();
-
- protected:
- // Overridden from views::NonClientFrameView:
- virtual gfx::Rect GetBoundsForClientView() const;
- virtual bool AlwaysUseNativeFrame() const;
- virtual gfx::Rect GetWindowBoundsForClientBounds(
- const gfx::Rect& client_bounds) const;
- virtual int NonClientHitTest(const gfx::Point& point);
- virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask);
- virtual void EnableClose(bool enable);
- virtual void ResetWindowControls();
-
- // Overridden from views::View:
- virtual void Paint(gfx::Canvas* canvas);
- virtual void Layout();
- virtual bool HitTest(const gfx::Point& l) const;
- virtual void ViewHierarchyChanged(bool is_add,
- views::View* parent,
- views::View* child);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
-
- // Overridden from TabIconView::TabIconViewModel:
- virtual bool ShouldTabIconViewAnimate() const;
- virtual SkBitmap GetFavIconForTabIconView();
-
- private:
- // Returns the thickness of the border that makes up the window frame edges.
- // This does not include any client edge.
- int FrameBorderThickness() const;
-
- // Returns the height of the entire nonclient top border, including the window
- // frame, any title area, and any connected client edge.
- int NonClientTopBorderHeight() const;
-
- // Paint various sub-components of this view. The *FrameBorder() functions
- // also paint the background of the titlebar area, since the top frame border
- // and titlebar background are a contiguous component.
- void PaintMaximizedFrameBorder(gfx::Canvas* canvas);
- void PaintToolbarBackground(gfx::Canvas* canvas);
-
- // The frame that hosts this view.
- BrowserFrame* frame_;
-
- // The BrowserView hosted within this View.
- BrowserView* browser_view_;
-
- // The bounds of the ClientView.
- gfx::Rect client_view_bounds_;
-
- DISALLOW_COPY_AND_ASSIGN(NormalBrowserFrameView);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_FRAME_NORMAL_BROWSER_FRAME_VIEW_H_
diff --git a/chrome/browser/chromeos/frame/panel_browser_view.cc b/chrome/browser/chromeos/frame/panel_browser_view.cc
index 0d72579..b52f035 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 "third_party/cros/chromeos_wm_ipc_enums.h"
+#include "cros/chromeos_wm_ipc_enums.h"
#include "views/window/window.h"
namespace chromeos {
@@ -36,10 +36,12 @@ void PanelBrowserView::Init() {
}
void PanelBrowserView::Show() {
- panel_controller_.reset(new PanelController(this, GetNativeHandle()));
- panel_controller_->Init(
- true /* focus when opened */, bounds(), creator_xid_,
- WM_IPC_PANEL_USER_RESIZE_HORIZONTALLY_AND_VERTICALLY);
+ if (panel_controller_.get() == NULL) {
+ panel_controller_.reset(new PanelController(this, GetNativeHandle()));
+ panel_controller_->Init(
+ true /* focus when opened */, bounds(), creator_xid_,
+ WM_IPC_PANEL_USER_RESIZE_HORIZONTALLY_AND_VERTICALLY);
+ }
BrowserView::Show();
}
diff --git a/chrome/browser/chromeos/frame/panel_browser_view.h b/chrome/browser/chromeos/frame/panel_browser_view.h
index c3d7ec3..337245f 100644
--- a/chrome/browser/chromeos/frame/panel_browser_view.h
+++ b/chrome/browser/chromeos/frame/panel_browser_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_FRAME_PANEL_BROWSER_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_FRAME_PANEL_BROWSER_VIEW_H_
+#pragma once
#include "app/x11_util.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/chromeos/frame/panel_controller.cc b/chrome/browser/chromeos/frame/panel_controller.cc
index 621f63a..2f3f7eb 100644
--- a/chrome/browser/chromeos/frame/panel_controller.cc
+++ b/chrome/browser/chromeos/frame/panel_controller.cc
@@ -8,20 +8,25 @@
#include "app/resource_bundle.h"
#include "base/logging.h"
-#include "base/singleton.h"
#include "base/scoped_ptr.h"
+#include "base/singleton.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/chromeos/wm_ipc.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 "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"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/event.h"
+#include "views/painter.h"
#include "views/view.h"
#include "views/widget/widget_gtk.h"
#include "views/window/window.h"
@@ -39,20 +44,43 @@ static gfx::Font* inactive_font = NULL;
namespace {
-const int kTitleWidth = 200;
-const int kTitleHeight = 20;
+const int kTitleHeight = 24;
const int kTitleIconSize = 16;
-const int kTitleWidthPad = 2;
-const int kTitleHeightPad = 1;
-const int kButtonPad = 4;
-
-const SkColor kActiveGradientStart = 0xffebeff9;
-const SkColor kActiveGradientEnd = 0xffb3c4f6;
-const SkColor kInactiveGradientStart = 0xfff2f2f2;
-const SkColor kInactiveGradientEnd = 0xfff2f2f2;
-const SkColor kActiveColor = SK_ColorBLACK;
-const SkColor kInactiveColor = 0xff333333;
-const SkColor kCloseButtonColor = SK_ColorBLACK;
+const int kTitleWidthPad = 4;
+const int kTitleHeightPad = 4;
+const int kTitleCornerRadius = 4;
+const int kTitleCloseButtonPad = 6;
+const SkColor kTitleActiveGradientStart = SK_ColorWHITE;
+const SkColor kTitleActiveGradientEnd = 0xffe7edf1;
+const SkColor kTitleActiveColor = SK_ColorBLACK;
+const SkColor kTitleInactiveColor = SK_ColorBLACK;
+const SkColor kTitleCloseButtonColor = SK_ColorBLACK;
+
+// Used to draw the background of the panel title window.
+class TitleBackgroundPainter : public views::Painter {
+ virtual void Paint(int w, int h, gfx::Canvas* canvas) {
+ SkRect rect = {0, 0, w, h};
+ SkPath path;
+ SkScalar corners[] = {
+ kTitleCornerRadius, kTitleCornerRadius,
+ kTitleCornerRadius, kTitleCornerRadius,
+ 0, 0,
+ 0, 0
+ };
+ path.addRoundRect(rect, corners);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ SkPoint p[2] = {{0, 0}, {0, h}};
+ SkColor colors[2] = {kTitleActiveGradientStart, kTitleActiveGradientEnd};
+ SkShader* s = SkGradientShader::CreateLinear(
+ p, colors, NULL, 2, SkShader::kClamp_TileMode, NULL);
+ paint.setShader(s);
+ // Need to unref shader, otherwise never deleted.
+ s->unref();
+ canvas->AsCanvasSkia()->drawPath(path, paint);
+ }
+};
static bool resources_initialized;
static void InitializeResources() {
@@ -62,8 +90,10 @@ static void InitializeResources() {
resources_initialized = true;
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- inactive_font = new gfx::Font(rb.GetFont(ResourceBundle::BaseFont));
- active_font = new gfx::Font(inactive_font->DeriveFont(0, gfx::Font::BOLD));
+ gfx::Font base_font = rb.GetFont(ResourceBundle::BaseFont);
+ // Title fonts are the same for active and inactive.
+ inactive_font = new gfx::Font(base_font.DeriveFont(0, gfx::Font::BOLD));
+ active_font = inactive_font;
close_button_n = rb.GetBitmapNamed(IDR_TAB_CLOSE);
close_button_m = rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK);
close_button_h = rb.GetBitmapNamed(IDR_TAB_CLOSE_H);
@@ -92,10 +122,10 @@ void PanelController::Init(bool initial_focus,
const gfx::Rect& window_bounds,
XID creator_xid,
WmIpcPanelUserResizeType resize_type) {
- gfx::Rect title_bounds(
- 0, 0, window_bounds.width(), kTitleHeight);
+ gfx::Rect title_bounds(0, 0, window_bounds.width(), kTitleHeight);
title_window_ = new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
+ title_window_->MakeTransparent();
title_window_->Init(NULL, title_bounds);
gtk_widget_set_size_request(title_window_->GetNativeView(),
title_bounds.width(), title_bounds.height());
@@ -285,13 +315,14 @@ void PanelController::OnCloseButtonPressed() {
PanelController::TitleContentView::TitleContentView(
PanelController* panel_controller)
: panel_controller_(panel_controller) {
+ LOG(INFO) << "panel: c " << this;
InitializeResources();
close_button_ = new views::ImageButton(this);
close_button_->SetImage(views::CustomButton::BS_NORMAL, close_button_n);
close_button_->SetImage(views::CustomButton::BS_HOT, close_button_h);
close_button_->SetImage(views::CustomButton::BS_PUSHED, close_button_p);
close_button_->SetBackground(
- kCloseButtonColor, close_button_n, close_button_m);
+ kTitleCloseButtonColor, close_button_n, close_button_m);
AddChildView(close_button_);
title_icon_ = new views::ImageView();
@@ -300,12 +331,15 @@ PanelController::TitleContentView::TitleContentView(
title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
AddChildView(title_label_);
- // Default to inactive
+ set_background(
+ views::Background::CreateBackgroundPainter(
+ true, new TitleBackgroundPainter()));
OnFocusOut();
}
void PanelController::TitleContentView::Layout() {
- int close_button_x = bounds().width() - (close_button_width + kButtonPad);
+ int close_button_x = bounds().width() -
+ (close_button_width + kTitleCloseButtonPad);
close_button_->SetBounds(
close_button_x,
(bounds().height() - close_button_height) / 2,
@@ -313,15 +347,15 @@ void PanelController::TitleContentView::Layout() {
close_button_height);
title_icon_->SetBounds(
kTitleWidthPad,
- kTitleHeightPad * 2,
+ kTitleHeightPad,
kTitleIconSize,
kTitleIconSize);
int title_x = kTitleWidthPad * 2 + kTitleIconSize;
title_label_->SetBounds(
title_x,
- kTitleHeightPad,
- close_button_x - (title_x + kButtonPad),
- bounds().height() - kTitleHeightPad);
+ 0,
+ close_button_x - (title_x + kTitleCloseButtonPad),
+ bounds().height());
}
bool PanelController::TitleContentView::OnMousePressed(
@@ -343,18 +377,14 @@ bool PanelController::TitleContentView::OnMouseDragged(
}
void PanelController::TitleContentView::OnFocusIn() {
- set_background(views::Background::CreateVerticalGradientBackground(
- kActiveGradientStart, kActiveGradientEnd));
- title_label_->SetColor(kActiveColor);
+ title_label_->SetColor(kTitleActiveColor);
title_label_->SetFont(*active_font);
Layout();
SchedulePaint();
}
void PanelController::TitleContentView::OnFocusOut() {
- set_background(views::Background::CreateVerticalGradientBackground(
- kInactiveGradientStart, kInactiveGradientEnd));
- title_label_->SetColor(kInactiveColor);
+ title_label_->SetColor(kTitleInactiveColor);
title_label_->SetFont(*inactive_font);
Layout();
SchedulePaint();
@@ -370,4 +400,8 @@ void PanelController::TitleContentView::ButtonPressed(
panel_controller_->OnCloseButtonPressed();
}
+PanelController::TitleContentView::~TitleContentView() {
+ LOG(INFO) << "panel: delete " << this;
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/frame/panel_controller.h b/chrome/browser/chromeos/frame/panel_controller.h
index 32be295..5d4920f 100644
--- a/chrome/browser/chromeos/frame/panel_controller.h
+++ b/chrome/browser/chromeos/frame/panel_controller.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_FRAME_PANEL_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_FRAME_PANEL_CONTROLLER_H_
+#pragma once
#include <gtk/gtk.h>
#include "app/x11_util.h"
+#include "cros/chromeos_wm_ipc_enums.h"
#include "views/controls/button/button.h"
-#include "third_party/cros/chromeos_wm_ipc_enums.h"
class BrowserView;
class SkBitmap;
@@ -73,7 +74,7 @@ class PanelController {
public views::ButtonListener {
public:
explicit TitleContentView(PanelController* panelController);
- virtual ~TitleContentView() {}
+ virtual ~TitleContentView();
virtual void Layout();
virtual bool OnMousePressed(const views::MouseEvent& event);
virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
diff --git a/chrome/browser/chromeos/google_update_chromeos.cc b/chrome/browser/chromeos/google_update_chromeos.cc
index a7b2cc3..c1bf0ba 100644
--- a/chrome/browser/chromeos/google_update_chromeos.cc
+++ b/chrome/browser/chromeos/google_update_chromeos.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/google_update.h"
+#include "chrome/browser/google/google_update.h"
#include "base/message_loop.h"
#include "base/path_service.h"
diff --git a/chrome/browser/chromeos/gview_request_interceptor.cc b/chrome/browser/chromeos/gview_request_interceptor.cc
index dba4d9d..1d2b9cc 100644
--- a/chrome/browser/chromeos/gview_request_interceptor.cc
+++ b/chrome/browser/chromeos/gview_request_interceptor.cc
@@ -6,13 +6,14 @@
#include "base/file_path.h"
#include "base/path_service.h"
+#include "base/singleton.h"
#include "chrome/common/chrome_paths.h"
+#include "googleurl/src/gurl.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
-#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_redirect_job.h"
-#include "googleurl/src/gurl.h"
#include "webkit/glue/plugins/plugin_list.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/gview_request_interceptor.h b/chrome/browser/chromeos/gview_request_interceptor.h
index dcb5f20..adbbd25 100644
--- a/chrome/browser/chromeos/gview_request_interceptor.h
+++ b/chrome/browser/chromeos/gview_request_interceptor.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_GVIEW_REQUEST_INTERCEPTOR_H__
#define CHROME_BROWSER_CHROMEOS_GVIEW_REQUEST_INTERCEPTOR_H__
+#pragma once
#include <string>
#include "base/hash_tables.h"
diff --git a/chrome/browser/chromeos/gview_request_interceptor_unittest.cc b/chrome/browser/chromeos/gview_request_interceptor_unittest.cc
index 1cc28b9..7ba3b5d 100644
--- a/chrome/browser/chromeos/gview_request_interceptor_unittest.cc
+++ b/chrome/browser/chromeos/gview_request_interceptor_unittest.cc
@@ -5,12 +5,15 @@
#include <string>
#include "base/message_loop.h"
#include "chrome/browser/chromeos/gview_request_interceptor.h"
+#include "chrome/browser/plugin_service.h"
+#include "chrome/common/chrome_paths.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/plugins/plugin_list.h"
namespace chromeos {
@@ -49,6 +52,7 @@ class GViewRequestInterceptorTest : public testing::Test {
URLRequest::RegisterProtocolFactory("http",
&GViewRequestInterceptorTest::Factory);
interceptor_ = GViewRequestInterceptor::GetGViewRequestInterceptor();
+ ASSERT_TRUE(PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path_));
}
virtual void TearDown() {
@@ -61,10 +65,44 @@ class GViewRequestInterceptorTest : public testing::Test {
return new GViewURLRequestTestJob(request);
}
+ void RegisterPDFPlugin() {
+ 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();
+ }
+
+ void UnregisterPDFPlugin() {
+ NPAPI::PluginList::Singleton()->UnregisterInternalPlugin(pdf_path_);
+ NPAPI::PluginList::Singleton()->RefreshPlugins();
+ }
+
+ void SetPDFPluginLoadedState(bool want_loaded, bool* out_is_enabled) {
+ WebPluginInfo info;
+ bool is_loaded =
+ NPAPI::PluginList::Singleton()->GetPluginInfoByPath(pdf_path_, &info);
+ if (is_loaded && !want_loaded) {
+ UnregisterPDFPlugin();
+ is_loaded =
+ 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);
+ }
+ EXPECT_EQ(want_loaded, is_loaded);
+ *out_is_enabled = info.enabled;
+ }
+
protected:
MessageLoopForIO message_loop_;
TestDelegate test_delegate_;
URLRequest::Interceptor* interceptor_;
+ FilePath pdf_path_;
};
TEST_F(GViewRequestInterceptorTest, DoNotInterceptHtml) {
@@ -84,7 +122,46 @@ TEST_F(GViewRequestInterceptorTest, DoNotInterceptDownload) {
EXPECT_EQ(GURL("http://foo.com/file.pdf"), request.url());
}
-TEST_F(GViewRequestInterceptorTest, InterceptPdf) {
+TEST_F(GViewRequestInterceptorTest, DoNotInterceptPdfWhenEnabled) {
+ bool enabled;
+ SetPDFPluginLoadedState(true, &enabled);
+
+ if (!enabled) {
+ bool pdf_plugin_enabled =
+ NPAPI::PluginList::Singleton()->EnablePlugin(pdf_path_);
+ EXPECT_TRUE(pdf_plugin_enabled);
+ }
+
+ URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
+ request.Start();
+ MessageLoop::current()->Run();
+ EXPECT_EQ(0, test_delegate_.received_redirect_count());
+ EXPECT_EQ(GURL("http://foo.com/file.pdf"), request.url());
+}
+
+TEST_F(GViewRequestInterceptorTest, InterceptPdfWhenDisabled) {
+ bool enabled;
+ SetPDFPluginLoadedState(true, &enabled);
+
+ if (enabled) {
+ bool pdf_plugin_disabled =
+ NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path_);
+ EXPECT_TRUE(pdf_plugin_disabled);
+ }
+
+ URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
+ request.Start();
+ MessageLoop::current()->Run();
+ EXPECT_EQ(1, test_delegate_.received_redirect_count());
+ EXPECT_EQ(
+ GURL("http://docs.google.com/gview?url=http%3A//foo.com/file.pdf"),
+ request.url());
+}
+
+TEST_F(GViewRequestInterceptorTest, InterceptPdfWithNoPlugin) {
+ bool enabled;
+ SetPDFPluginLoadedState(false, &enabled);
+
URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
request.Start();
MessageLoop::current()->Run();
diff --git a/chrome/browser/chromeos/input_method/candidate_window.cc b/chrome/browser/chromeos/input_method/candidate_window.cc
index 2e95a20..3444f53 100644
--- a/chrome/browser/chromeos/input_method/candidate_window.cc
+++ b/chrome/browser/chromeos/input_method/candidate_window.cc
@@ -11,23 +11,26 @@
#include <vector>
#include "app/app_paths.h"
+#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/at_exit.h"
#include "base/command_line.h"
-#include "base/file_path.h"
#include "base/logging.h"
#include "base/observer_list.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library_loader.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
-#include "gfx/canvas.h"
-#include "gfx/font.h"
#include "cros/chromeos_cros_api.h"
#include "cros/chromeos_input_method_ui.h"
+#include "gfx/canvas.h"
+#include "gfx/font.h"
+#include "grit/app_locale_settings.h"
#include "views/controls/label.h"
#include "views/controls/textfield/textfield.h"
#include "views/event.h"
@@ -54,6 +57,11 @@ const SkColor kFooterTopColor = SkColorSetRGB(0xff, 0xff, 0xff);
const SkColor kFooterBottomColor = SkColorSetRGB(0xee, 0xee, 0xee);
const SkColor kShortcutColor = SkColorSetRGB(0x61, 0x61, 0x61);
const SkColor kDisabledShortcutColor = SkColorSetRGB(0xcc, 0xcc, 0xcc);
+const SkColor kAnnotationColor = SkColorSetRGB(0x88, 0x88, 0x88);
+
+// We'll use a bigger font size, so Chinese characters are more readable
+// in the candidate window.
+const int kFontSizeDelta = 2; // Two size bigger.
// The minimum width of candidate labels in the vertical candidate
// window. We use this value to prevent the candidate window from being
@@ -64,6 +72,29 @@ const int kMinCandidateLabelWidth = 100;
// too wide when one of candidates are long.
const int kMaxCandidateLabelWidth = 500;
+// VerticalCandidateLabel is used for rendering candidate text in
+// the vertical candidate window.
+class VerticalCandidateLabel : public views::Label {
+ virtual ~VerticalCandidateLabel() {}
+
+ // Returns the preferred size, but guarantees that the width has at
+ // least kMinCandidateLabelWidth pixels.
+ virtual gfx::Size GetPreferredSize() {
+ gfx::Size size = Label::GetPreferredSize();
+ // Hack. +2 is needed to prevent labels from getting elided like
+ // "abc..." in some cases. TODO(satorux): Figure out why it's
+ // necessary.
+ size.set_width(size.width() + 2);
+ if (size.width() < kMinCandidateLabelWidth) {
+ size.set_width(kMinCandidateLabelWidth);
+ }
+ if (size.width() > kMaxCandidateLabelWidth) {
+ size.set_width(kMaxCandidateLabelWidth);
+ }
+ return size;
+ }
+};
+
// Wraps the given view with some padding, and returns it.
views::View* WrapWithPadding(views::View* view, const gfx::Insets& insets) {
views::View* wrapper = new views::View;
@@ -83,6 +114,193 @@ views::View* WrapWithPadding(views::View* view, const gfx::Insets& insets) {
return wrapper;
}
+// Creates shortcut text from the given index and the orientation.
+std::wstring CreateShortcutText(int index,
+ chromeos::InputMethodLookupTable::Orientation orientation) {
+ // Choose the character used for the shortcut label.
+ const wchar_t kShortcutCharacters[] = L"1234567890ABCDEF";
+ // The default character should not be used but just in case.
+ wchar_t shortcut_character = L'?';
+ // -1 to exclude the null character at the end.
+ if (index < static_cast<int>(arraysize(kShortcutCharacters) - 1)) {
+ shortcut_character = kShortcutCharacters[index];
+ }
+
+ std::wstring shortcut_text;
+ if (orientation == chromeos::InputMethodLookupTable::kVertical) {
+ shortcut_text = base::StringPrintf(L"%lc", shortcut_character);
+ } else {
+ shortcut_text = base::StringPrintf(L"%lc.", shortcut_character);
+ }
+
+ return shortcut_text;
+}
+
+// Creates the shortcut label, and returns it (never returns NULL).
+// The label text is not set in this function.
+views::Label* CreateShortcutLabel(
+ chromeos::InputMethodLookupTable::Orientation orientation) {
+ // Create the shortcut label. The label will be owned by
+ // |wrapped_shortcut_label|, hence it's deleted when
+ // |wrapped_shortcut_label| is deleted.
+ views::Label* shortcut_label = new views::Label;
+
+ if (orientation == chromeos::InputMethodLookupTable::kVertical) {
+ shortcut_label->SetFont(
+ shortcut_label->font().DeriveFont(kFontSizeDelta, gfx::Font::BOLD));
+ } else {
+ shortcut_label->SetFont(
+ shortcut_label->font().DeriveFont(kFontSizeDelta));
+ }
+ // TODO(satorux): Maybe we need to use language specific fonts for
+ // candidate_label, like Chinese font for Chinese input method?
+ shortcut_label->SetColor(kShortcutColor);
+
+ return shortcut_label;
+}
+
+// Wraps the shortcut label, then decorates wrapped shortcut label
+// and returns it (never returns NULL).
+// The label text is not set in this function.
+views::View* CreateWrappedShortcutLabel(views::Label* shortcut_label,
+ chromeos::InputMethodLookupTable::Orientation orientation) {
+ // Wrap it with padding.
+ const gfx::Insets kVerticalShortcutLabelInsets(1, 6, 1, 6);
+ const gfx::Insets kHorizontalShortcutLabelInsets(1, 3, 1, 0);
+ const gfx::Insets insets =
+ (orientation == chromeos::InputMethodLookupTable::kVertical ?
+ kVerticalShortcutLabelInsets :
+ kHorizontalShortcutLabelInsets);
+ views::View* wrapped_shortcut_label =
+ WrapWithPadding(shortcut_label, insets);
+
+ // Add decoration based on the orientation.
+ if (orientation == chromeos::InputMethodLookupTable::kVertical) {
+ // Set the background color.
+ wrapped_shortcut_label->set_background(
+ views::Background::CreateSolidBackground(
+ kShortcutBackgroundColor));
+ }
+
+ return wrapped_shortcut_label;
+}
+
+// Creates the candidate label, and returns it (never returns NULL).
+// The label text is not set in this function.
+views::Label* CreateCandidateLabel(
+ chromeos::InputMethodLookupTable::Orientation orientation) {
+ views::Label* candidate_label = NULL;
+
+ // Create the candidate label. The label will be added to |this| as a
+ // child view, hence it's deleted when |this| is deleted.
+ if (orientation == chromeos::InputMethodLookupTable::kVertical) {
+ candidate_label = new VerticalCandidateLabel;
+ } else {
+ candidate_label = new views::Label;
+ }
+
+ // Change the font size.
+ candidate_label->SetFont(
+ candidate_label->font().DeriveFont(kFontSizeDelta));
+ candidate_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+
+ return candidate_label;
+}
+
+// Creates the annotation label, and return it (never returns NULL).
+// The label text is not set in this function.
+views::Label* CreateAnnotationLabel(
+ chromeos::InputMethodLookupTable::Orientation orientation) {
+ // Create the annotation label.
+ views::Label* annotation_label = new views::Label;
+
+ // Change the font size and color.
+ annotation_label->SetFont(
+ annotation_label->font().DeriveFont(kFontSizeDelta));
+ annotation_label->SetColor(kAnnotationColor);
+ annotation_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+
+ return annotation_label;
+}
+
+// Computes shortcut column width.
+int ComputeShortcutColumnWidth(
+ const chromeos::InputMethodLookupTable& lookup_table) {
+ int shortcut_column_width = 0;
+ // Create the shortcut label. The label will be owned by
+ // |wrapped_shortcut_label|, hence it's deleted when
+ // |wrapped_shortcut_label| is deleted.
+ views::Label* shortcut_label = CreateShortcutLabel(lookup_table.orientation);
+ scoped_ptr<views::View> wrapped_shortcut_label(
+ CreateWrappedShortcutLabel(shortcut_label, lookup_table.orientation));
+
+ // Compute the max width in shortcut labels.
+ // We'll create temporary shortcut labels, and choose the largest width.
+ for (int i = 0; i < lookup_table.page_size; ++i) {
+ shortcut_label->SetText(
+ CreateShortcutText(i, lookup_table.orientation));
+ shortcut_column_width =
+ std::max(shortcut_column_width,
+ wrapped_shortcut_label->GetPreferredSize().width());
+ }
+
+ return shortcut_column_width;
+}
+
+// Computes candidate column width.
+int ComputeCandidateColumnWidth(
+ const chromeos::InputMethodLookupTable& lookup_table) {
+ int candidate_column_width = 0;
+ scoped_ptr<views::Label> candidate_label(
+ 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 size_t start_from = current_page_index * lookup_table.page_size;
+
+ // Compute the max width in candidate labels.
+ // We'll create temporary candidate labels, and choose the largest width.
+ for (size_t i = 0; i < lookup_table.candidates.size(); ++i) {
+ const size_t index = start_from + i;
+
+ candidate_label->SetText(
+ UTF8ToWide(lookup_table.candidates[index]));
+ candidate_column_width =
+ std::max(candidate_column_width,
+ candidate_label->GetPreferredSize().width());
+ }
+
+ return candidate_column_width;
+}
+
+// Computes annotation column width.
+int ComputeAnnotationColumnWidth(
+ const chromeos::InputMethodLookupTable& lookup_table) {
+ int annotation_column_width = 0;
+ scoped_ptr<views::Label> annotation_label(
+ 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 size_t start_from = current_page_index * lookup_table.page_size;
+
+ // Compute max width in annotation labels.
+ // We'll create temporary annotation labels, and choose the largest width.
+ for (size_t i = 0; i < lookup_table.annotations.size(); ++i) {
+ const size_t index = start_from + i;
+
+ annotation_label->SetText(
+ UTF8ToWide(lookup_table.annotations[index]));
+ annotation_column_width =
+ std::max(annotation_column_width,
+ annotation_label->GetPreferredSize().width());
+ }
+
+ return annotation_column_width;
+}
+
} // namespace
namespace chromeos {
@@ -163,8 +381,7 @@ class CandidateWindowView : public views::View {
private:
// Initializes the candidate views if needed.
void MaybeInitializeCandidateViews(
- int num_views,
- InputMethodLookupTable::Orientation orientation);
+ const InputMethodLookupTable& lookup_table);
// Creates the footer area, where we show status information.
// For instance, we show a cursor position like 2/19.
@@ -216,6 +433,11 @@ class CandidateWindowView : public views::View {
views::Label* header_label_;
// The footer label is shown in the footer area.
views::Label* footer_label_;
+
+ // Current columns width in |candidate_area_|.
+ int previous_shortcut_column_width_;
+ int previous_candidate_column_width_;
+ int previous_annotation_column_width_;
};
// CandidateRow renderes a row of a candidate.
@@ -225,7 +447,11 @@ class CandidateView : public views::View {
int index_in_page,
InputMethodLookupTable::Orientation orientation);
virtual ~CandidateView() {}
- void Init();
+ // Initializes the candidate view with the given column widths.
+ // A width of 0 means that the column is resizable.
+ void Init(int shortcut_column_width,
+ int candidate_column_width,
+ int annotation_column_width);
// Sets candidate text to the given text.
void SetCandidateText(const std::wstring& text);
@@ -233,8 +459,8 @@ class CandidateView : public views::View {
// Sets shortcut text to the given text.
void SetShortcutText(const std::wstring& text);
- // Sets shortcut text from the given integer.
- void SetShortcutTextFromInt(int index);
+ // Sets annotation text to the given text.
+ void SetAnnotationText(const std::wstring& text);
// Selects the candidate row. Changes the appearance to make it look
// like a selected candidate.
@@ -278,29 +504,8 @@ class CandidateView : public views::View {
views::Label* shortcut_label_;
// The candidate label renders candidates.
views::Label* candidate_label_;
-};
-
-// VerticalCandidateLabel is used for rendering candidate text in
-// the vertical candidate window.
-class VerticalCandidateLabel : public views::Label {
- virtual ~VerticalCandidateLabel() {}
-
- // Returns the preferred size, but guarantees that the width has at
- // least kMinCandidateLabelWidth pixels.
- virtual gfx::Size GetPreferredSize() {
- gfx::Size size = Label::GetPreferredSize();
- // Hack. +2 is needed to prevent labels from getting elided like
- // "abc..." in some cases. TODO(satorux): Figure out why it's
- // necessary.
- size.set_width(size.width() + 2);
- if (size.width() < kMinCandidateLabelWidth) {
- size.set_width(kMinCandidateLabelWidth);
- }
- if (size.width() > kMaxCandidateLabelWidth) {
- size.set_width(kMaxCandidateLabelWidth);
- }
- return size;
- }
+ // The annotation label renders annotations.
+ views::Label* annotation_label_;
};
// CandidateWindowController controls the CandidateWindow.
@@ -308,12 +513,12 @@ class CandidateWindowController : public CandidateWindowView::Observer {
public:
CandidateWindowController();
virtual ~CandidateWindowController();
- void Init();
+ bool Init();
// Returns the work area of the monitor nearest the candidate window.
gfx::Rect GetMonitorWorkAreaNearestWindow();
- // Moves the candidate window per the the given cursor location, and the
+ // Moves the candidate window per the given cursor location, and the
// horizontal offset.
void MoveCandidateWindow(const gfx::Rect& cursor_location,
int horizontal_offset);
@@ -359,6 +564,10 @@ class CandidateWindowController : public CandidateWindowView::Observer {
static void OnUpdateLookupTable(void* input_method_library,
const InputMethodLookupTable& lookup_table);
+ // This function is called by libcros when ibus connects or disconnects.
+ // |input_method_library| is a void pointer to this object.
+ static void OnConnectionChange(void* input_method_library, bool connected);
+
// The connection is used for communicating with input method UI logic
// in libcros.
InputMethodUiStatusConnection* ui_status_connection_;
@@ -382,83 +591,57 @@ CandidateView::CandidateView(
orientation_(orientation),
parent_candidate_window_(parent_candidate_window),
shortcut_label_(NULL),
- candidate_label_(NULL) {
+ candidate_label_(NULL),
+ annotation_label_(NULL) {
}
-void CandidateView::Init() {
+void CandidateView::Init(int shortcut_column_width,
+ int candidate_column_width,
+ int annotation_column_width) {
views::GridLayout* layout = new views::GridLayout(this);
SetLayoutManager(layout); // |this| owns |layout|.
- // Create the shortcut label. The label will eventually be part of the
- // tree of |this| via |wrapped_shortcut_label|, hence it's deleted when
- // |this| is deleted.
- shortcut_label_ = new views::Label();
-
- // Wrap it with padding.
- const gfx::Insets kVerticalShortcutLabelInsets(1, 6, 1, 6);
- const gfx::Insets kHorizontalShortcutLabelInsets(1, 3, 1, 0);
- const gfx::Insets insets =
- (orientation_ == InputMethodLookupTable::kVertical ?
- kVerticalShortcutLabelInsets :
- kHorizontalShortcutLabelInsets);
+ // Create Labels.
+ shortcut_label_ = CreateShortcutLabel(orientation_);
views::View* wrapped_shortcut_label =
- WrapWithPadding(shortcut_label_, insets);
- // We'll use a bigger font size, so Chinese characters are more readable
- // in the candidate window.
- const int kFontSizeDelta = 2; // Two size bigger.
- // Make the font bold, and change the size.
- if (orientation_ == InputMethodLookupTable::kVertical) {
- shortcut_label_->SetFont(
- shortcut_label_->font().DeriveFont(kFontSizeDelta, gfx::Font::BOLD));
- } else {
- shortcut_label_->SetFont(
- shortcut_label_->font().DeriveFont(kFontSizeDelta));
- }
- // TODO(satorux): Maybe we need to use language specific fonts for
- // candidate_label, like Chinese font for Chinese input method?
+ CreateWrappedShortcutLabel(shortcut_label_, orientation_);
+ candidate_label_ = CreateCandidateLabel(orientation_);
+ annotation_label_ = CreateAnnotationLabel(orientation_);
- // Add decoration based on the orientation.
- if (orientation_ == InputMethodLookupTable::kVertical) {
- // Set the background color.
- wrapped_shortcut_label->set_background(
- views::Background::CreateSolidBackground(
- kShortcutBackgroundColor));
- }
- shortcut_label_->SetColor(kShortcutColor);
+ // Initialize the column set with three columns.
+ views::ColumnSet* column_set = layout->AddColumnSet(0);
- // Create the candidate label. The label will be added to |this| as a
- // child view, hence it's deleted when |this| is deleted.
- if (orientation_ == InputMethodLookupTable::kVertical) {
- candidate_label_ = new VerticalCandidateLabel;
- } else {
- candidate_label_ = new views::Label;
- }
- // Change the font size.
- candidate_label_->SetFont(
- candidate_label_->font().DeriveFont(kFontSizeDelta));
+ // If orientation is vertical, each column width is fixed.
+ // Otherwise the width is resizable.
+ const views::GridLayout::SizeType column_type =
+ orientation_ == InputMethodLookupTable::kVertical ?
+ views::GridLayout::FIXED : views::GridLayout::USE_PREF;
- candidate_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ const int padding_column_width =
+ orientation_ == InputMethodLookupTable::kVertical ? 4 : 6;
- // Initialize the column set with two columns.
- views::ColumnSet* column_set = layout->AddColumnSet(0);
+ // Set shortcut column type and width.
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
- 0, views::GridLayout::USE_PREF, 0, 0);
- if (orientation_ == InputMethodLookupTable::kVertical) {
- column_set->AddPaddingColumn(0, 4);
- }
+ 0, column_type, shortcut_column_width, 0);
+ column_set->AddPaddingColumn(0, padding_column_width);
+
+ // Set candidate column type and width.
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
- 0, views::GridLayout::USE_PREF, 0, 0);
- if (orientation_ == InputMethodLookupTable::kVertical) {
- column_set->AddPaddingColumn(0, 4);
- } else {
- column_set->AddPaddingColumn(0, 6);
- }
+ 0, column_type, candidate_column_width, 0);
+ column_set->AddPaddingColumn(0, padding_column_width);
- // Add the shortcut label and the candidate label.
+ // Set annotation column type and width.
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
+ 0, column_type, annotation_column_width, 0);
+ column_set->AddPaddingColumn(0, padding_column_width);
+
+ // Add the shortcut label, the candidate label, and annotation label.
layout->StartRow(0, 0);
- // |wrapped_shortcut_label| and |candidate_label_| will be owned by |this|.
+ // |wrapped_shortcut_label|, |candidate_label_|, and |annotation_label_|
+ // will be owned by |this|.
layout->AddView(wrapped_shortcut_label);
layout->AddView(candidate_label_);
+ layout->AddView(annotation_label_);
}
void CandidateView::SetCandidateText(const std::wstring& text) {
@@ -469,19 +652,8 @@ void CandidateView::SetShortcutText(const std::wstring& text) {
shortcut_label_->SetText(text);
}
-void CandidateView::SetShortcutTextFromInt(int index) {
- // Choose the character used for the shortcut label.
- const wchar_t kShortcutCharacters[] = L"1234567890ABCDEF";
- // The default character should not be used but just in case.
- wchar_t shortcut_character = L'?';
- if (index < static_cast<int>(arraysize(kShortcutCharacters) - 1)) {
- shortcut_character = kShortcutCharacters[index];
- }
- if (orientation_ == InputMethodLookupTable::kVertical) {
- shortcut_label_->SetText(StringPrintf(L"%lc", shortcut_character));
- } else {
- shortcut_label_->SetText(StringPrintf(L"%lc.", shortcut_character));
- }
+void CandidateView::SetAnnotationText(const std::wstring& text) {
+ annotation_label_->SetText(text);
}
void CandidateView::Select() {
@@ -539,7 +711,10 @@ CandidateWindowView::CandidateWindowView(
footer_area_(NULL),
header_area_(NULL),
header_label_(NULL),
- footer_label_(NULL) {
+ footer_label_(NULL),
+ previous_shortcut_column_width_(0),
+ previous_candidate_column_width_(0),
+ previous_annotation_column_width_(0) {
}
void CandidateWindowView::Init() {
@@ -613,8 +788,11 @@ void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) {
void CandidateWindowView::UpdateCandidates(
const InputMethodLookupTable& lookup_table) {
// Initialize candidate views if necessary.
- MaybeInitializeCandidateViews(lookup_table.page_size,
- lookup_table.orientation);
+ 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.
@@ -642,16 +820,21 @@ void CandidateWindowView::UpdateCandidates(
// (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->SetShortcutTextFromInt(i);
+ candidate_view->SetShortcutText(
+ CreateShortcutText(i, lookup_table_.orientation));
}
// Set the candidate text.
- if (candidate_index < lookup_table_.candidates.size()) {
+ 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);
}
}
@@ -663,15 +846,39 @@ void CandidateWindowView::UpdateCandidates(
}
void CandidateWindowView::MaybeInitializeCandidateViews(
- int num_views,
- InputMethodLookupTable::Orientation orientation) {
- // If the requested number of views matches the number of current views,
- // just reuse these.
- if (num_views == static_cast<int>(candidate_views_.size()) &&
- orientation == lookup_table_.orientation) {
+ const InputMethodLookupTable& lookup_table) {
+ const InputMethodLookupTable::Orientation orientation =
+ lookup_table.orientation;
+ const int page_size = lookup_table.page_size;
+
+ // Current column width.
+ int shortcut_column_width = 0;
+ int candidate_column_width = 0;
+ int annotation_column_width = 0;
+
+ // If orientation is horizontal, don't need to compute width,
+ // because each label is left aligned.
+ if (orientation == InputMethodLookupTable::kVertical) {
+ shortcut_column_width = ComputeShortcutColumnWidth(lookup_table);
+ candidate_column_width = ComputeCandidateColumnWidth(lookup_table);
+ annotation_column_width = ComputeAnnotationColumnWidth(lookup_table);
+ }
+
+ // If the requested number of views matches the number of current views, and
+ // previous and current column width are same, just reuse these.
+ if (static_cast<int>(candidate_views_.size()) == page_size &&
+ lookup_table_.orientation == orientation &&
+ previous_shortcut_column_width_ == shortcut_column_width &&
+ previous_candidate_column_width_ == candidate_column_width &&
+ previous_annotation_column_width_ == annotation_column_width) {
return;
}
+ // Update the previous column widths.
+ previous_shortcut_column_width_ = shortcut_column_width;
+ previous_candidate_column_width_ = candidate_column_width;
+ previous_annotation_column_width_ = annotation_column_width;
+
// Clear the existing candidate_views if any.
for (size_t i = 0; i < candidate_views_.size(); ++i) {
candidate_area_->RemoveChildView(candidate_views_[i]);
@@ -688,7 +895,7 @@ void CandidateWindowView::MaybeInitializeCandidateViews(
views::GridLayout::FILL,
0, views::GridLayout::USE_PREF, 0, 0);
} else {
- for (int i = 0; i < num_views; ++i) {
+ for (int i = 0; i < page_size; ++i) {
column_set->AddColumn(views::GridLayout::FILL,
views::GridLayout::FILL,
0, views::GridLayout::USE_PREF, 0, 0);
@@ -709,16 +916,27 @@ void CandidateWindowView::MaybeInitializeCandidateViews(
if (orientation == InputMethodLookupTable::kHorizontal) {
layout->StartRow(0, 0);
}
- for (int i = 0; i < num_views; ++i) {
+
+ for (int i = 0; i < page_size; ++i) {
CandidateView* candidate_row = new CandidateView(this, i, orientation);
- candidate_row->Init();
+ candidate_row->Init(shortcut_column_width,
+ candidate_column_width,
+ annotation_column_width);
candidate_views_.push_back(candidate_row);
if (orientation == InputMethodLookupTable::kVertical) {
layout->StartRow(0, 0);
}
- // |candidate_row| will be owned by candidate_area_|.
+ // |candidate_row| will be owned by |candidate_area_|.
layout->AddView(candidate_row);
}
+
+ // 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().
+ // 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);
}
views::View* CandidateWindowView::CreateHeaderArea() {
@@ -858,7 +1076,7 @@ int CandidateWindowView::GetHorizontalOffset() {
}
-void CandidateWindowController::Init() {
+bool CandidateWindowController::Init() {
// Initialize the input method UI status connection.
InputMethodUiStatusMonitorFunctions functions;
functions.hide_auxiliary_text =
@@ -872,11 +1090,17 @@ void CandidateWindowController::Init() {
functions.update_lookup_table =
&CandidateWindowController::OnUpdateLookupTable;
ui_status_connection_ = MonitorInputMethodUiStatus(functions, this);
- CHECK(ui_status_connection_)
- << "MonitorInputMethodUiStatus() failed.";
+ if (!ui_status_connection_) {
+ LOG(ERROR) << "MonitorInputMethodUiStatus() failed.";
+ return false;
+ }
+ MonitorInputMethodConnection(ui_status_connection_,
+ &CandidateWindowController::OnConnectionChange);
// Create the candidate window view.
CreateView();
+
+ return true;
}
void CandidateWindowController::CreateView() {
@@ -978,6 +1202,16 @@ void CandidateWindowController::OnSetCursorLocation(
CandidateWindowController* controller =
static_cast<CandidateWindowController*>(input_method_library);
+ // 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 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";
+ return;
+ }
+
// Remember the cursor location.
controller->set_cursor_location(gfx::Rect(x, y, width, height));
// Move the window per the cursor location.
@@ -1032,6 +1266,15 @@ void CandidateWindowController::OnCandidateCommitted(int index,
NotifyCandidateClicked(ui_status_connection_, index, button, flags);
}
+void CandidateWindowController::OnConnectionChange(
+ void* input_method_library,
+ bool connected) {
+ if (!connected) {
+ MessageLoopForUI::current()->PostTask(FROM_HERE,
+ new MessageLoop::QuitTask());
+ }
+}
+
} // namespace chromeos
int main(int argc, char** argv) {
@@ -1045,30 +1288,26 @@ int main(int argc, char** argv) {
base::EnableTerminationOnHeapCorruption();
app::RegisterPathProvider();
CommandLine::Init(argc, argv);
- // TODO(markusheintz): The command line switch --Lang is now processed
- // by the CommandLinePrefStore and mapped to the preference
- // prefs::kApplicationLocale. This preferences can be read through the
- // PrefService. l10n_util::GetApplicationLocale() which is called by the
- // ResourceBundle code now ignores the --Lang flag.
- // In order to support the --Lang flag here the preference
- // prefs::kApplicationLocale must be read and passed instead of L"en-US".
- ResourceBundle::InitSharedInstance(L"en-US");
-
- // Write logs to a file for debugging, if --logtofile=FILE_NAME is given.
+
+ // Check if the UI language code is passed from the command line,
+ // otherwise, default to "en-US".
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- std::string log_file_name =
- command_line.GetSwitchValueASCII(switches::kChromeosLogToFile);
- if (!log_file_name.empty()) {
- logging::SetMinLogLevel(logging::LOG_INFO);
- logging::InitLogging(log_file_name.c_str(),
- logging::LOG_ONLY_TO_FILE,
- logging::DONT_LOCK_LOG_FILE,
- logging::DELETE_OLD_LOG_FILE);
- // Redirect stderr to log_file_name. This is neeed to capture the
- // logging from libcros.so.
- if (!freopen(log_file_name.c_str(), "a", stderr)) {
- LOG(INFO) << "Failed to redirect stderr to " << log_file_name.c_str();
- }
+ std::string ui_language_code =
+ command_line.GetSwitchValueASCII(switches::kCandidateWindowLang);
+ if (ui_language_code.empty()) {
+ ui_language_code = "en-US";
+ }
+ ResourceBundle::InitSharedInstance(ui_language_code);
+
+ // Change the UI font if needed.
+ const std::string font_name =
+ l10n_util::GetStringUTF8(IDS_UI_FONT_FAMILY_CROS);
+ // The font name should not be empty here, but just in case.
+ if (font_name != "default" && !font_name.empty()) {
+ // Don't use gtk_util::SetGtkFont() in chrome/browser/gtk not to
+ // introduce a dependency to it.
+ g_object_set(gtk_settings_get_default(),
+ "gtk-font-name", font_name.c_str(), NULL);
}
// Load libcros.
@@ -1083,7 +1322,9 @@ int main(int argc, char** argv) {
// Create the candidate window controller.
chromeos::CandidateWindowController controller;
- controller.Init();
+ if (!controller.Init()) {
+ return 1;
+ }
// Start the main loop.
views::AcceleratorHandler accelerator_handler;
diff --git a/chrome/browser/chromeos/input_method/candidate_window.gyp b/chrome/browser/chromeos/input_method/candidate_window.gyp
index e2f3ced..0d3b446 100644
--- a/chrome/browser/chromeos/input_method/candidate_window.gyp
+++ b/chrome/browser/chromeos/input_method/candidate_window.gyp
@@ -11,6 +11,7 @@
'target_name': 'candidate_window',
'type': 'executable',
'dependencies': [
+ '../../../../app/app.gyp:app_strings',
'../../../../base/base.gyp:base',
'../../../../build/linux/system.gyp:gtk',
'../../../../build/linux/system.gyp:x11',
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc
index abb94c2..3d981f1 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -8,12 +8,15 @@
#include <map>
#include <utility>
+#include "unicode/uloc.h"
+
#include "app/l10n_util.h"
#include "app/l10n_util_collator.h"
#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
@@ -22,21 +25,17 @@
#include "chrome/browser/chromeos/cros/keyboard_library.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "grit/generated_resources.h"
-#include "third_party/icu/public/common/unicode/uloc.h"
namespace {
// Map from language code to associated input method IDs, etc.
typedef std::multimap<std::string, std::string> LanguageCodeToIdsMap;
struct IdMaps {
- LanguageCodeToIdsMap* language_code_to_ids;
- std::map<std::string, std::string>* id_to_language_code;
- std::map<std::string, std::string>* id_to_display_name;
+ scoped_ptr<LanguageCodeToIdsMap> language_code_to_ids;
+ scoped_ptr<std::map<std::string, std::string> > id_to_language_code;
+ scoped_ptr<std::map<std::string, std::string> > id_to_display_name;
- private:
- IdMaps() : language_code_to_ids(NULL),
- id_to_language_code(NULL),
- id_to_display_name(NULL) {
+ void ReloadMaps() {
chromeos::InputMethodLibrary* library =
chromeos::CrosLibrary::Get()->GetInputMethodLibrary();
scoped_ptr<chromeos::InputMethodDescriptors> supported_input_methods(
@@ -46,9 +45,9 @@ struct IdMaps {
// TODO(yusukes): Handle this error in nicer way.
}
- language_code_to_ids = new LanguageCodeToIdsMap;
- id_to_language_code = new std::map<std::string, std::string>;
- id_to_display_name = new std::map<std::string, std::string>;
+ language_code_to_ids->clear();
+ id_to_language_code->clear();
+ id_to_display_name->clear();
// Build the id to descriptor map for handling kExtraLanguages later.
typedef std::map<std::string,
@@ -81,6 +80,13 @@ struct IdMaps {
}
}
+ private:
+ IdMaps() : language_code_to_ids(new LanguageCodeToIdsMap),
+ id_to_language_code(new std::map<std::string, std::string>),
+ id_to_display_name(new std::map<std::string, std::string>) {
+ ReloadMaps();
+ }
+
void AddInputMethodToMaps(
const std::string& language_code,
const chromeos::InputMethodDescriptor& input_method) {
@@ -153,10 +159,6 @@ const struct EnglishToResouceId {
IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_VIETNAMESE_VIQR_INPUT_METHOD },
{ "vni (m17n)",
IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_VIETNAMESE_VNI_INPUT_METHOD },
- { "latn-post (m17n)",
- IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_LATIN_POST_INPUT_METHOD },
- { "latn-pre (m17n)",
- IDS_OPTIONS_SETTINGS_LANGUAGES_M17N_LATIN_PRE_INPUT_METHOD },
{ "Bopomofo", IDS_OPTIONS_SETTINGS_LANGUAGES_BOPOMOFO_INPUT_METHOD },
{ "Chewing", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_INPUT_METHOD },
{ "Pinyin", IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_INPUT_METHOD },
@@ -190,15 +192,20 @@ const struct EnglishToResouceId {
{ "USA - Dvorak", IDS_STATUSBAR_LAYOUT_USA_DVORAK },
{ "Romania", IDS_STATUSBAR_LAYOUT_ROMANIA },
{ "USA", IDS_STATUSBAR_LAYOUT_USA },
+ { "USA - International (AltGr dead keys)",
+ IDS_STATUSBAR_LAYOUT_USA_INTERNATIONAL },
{ "Lithuania", IDS_STATUSBAR_LAYOUT_LITHUANIA },
{ "United Kingdom - Extended - Winkeys",
IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM },
{ "Slovakia", IDS_STATUSBAR_LAYOUT_SLOVAKIA },
{ "Russia", IDS_STATUSBAR_LAYOUT_RUSSIA },
+ { "Russia - Phonetic", IDS_STATUSBAR_LAYOUT_RUSSIA_PHONETIC },
{ "Greece", IDS_STATUSBAR_LAYOUT_GREECE },
{ "Belgium", IDS_STATUSBAR_LAYOUT_BELGIUM },
{ "Bulgaria", IDS_STATUSBAR_LAYOUT_BULGARIA },
+ { "Bulgaria - Traditional phonetic", IDS_STATUSBAR_LAYOUT_BULGARIA_PHONETIC },
{ "Switzerland", IDS_STATUSBAR_LAYOUT_SWITZERLAND },
+ { "Switzerland - French", IDS_STATUSBAR_LAYOUT_SWITZERLAND_FRENCH },
{ "Turkey", IDS_STATUSBAR_LAYOUT_TURKEY },
{ "Portugal", IDS_STATUSBAR_LAYOUT_PORTUGAL },
{ "Spain", IDS_STATUSBAR_LAYOUT_SPAIN },
@@ -211,6 +218,11 @@ const struct EnglishToResouceId {
{ "Sweden", IDS_STATUSBAR_LAYOUT_SWEDEN },
{ "Netherlands", IDS_STATUSBAR_LAYOUT_NETHERLANDS },
{ "Latvia", IDS_STATUSBAR_LAYOUT_LATVIA },
+ { "Canada", IDS_STATUSBAR_LAYOUT_CANADA },
+ { "Canada - English", IDS_STATUSBAR_LAYOUT_CANADA_ENGLISH },
+ { "Israel", IDS_STATUSBAR_LAYOUT_ISRAEL },
+ { "Korea, Republic of - 101/104 key Compatible",
+ IDS_STATUSBAR_LAYOUT_KOREA_104 },
};
const size_t kNumEntries = arraysize(kEnglishToResourceIdArray);
@@ -231,20 +243,6 @@ const char* kIso639VariantMapping[][2] = {
{"slo", "slk"},
};
-// The list defines pairs of language code and the default input method
-// id. The list is used for reordering input method ids.
-//
-// TODO(satorux): We may need to handle secondary, and ternary input
-// methods, rather than handling the default input method only.
-const struct LanguageDefaultInputMethodId {
- const char* language_code;
- const char* input_method_id;
-} kLanguageDefaultInputMethodIds[] = {
- { "en-US", "xkb:us::eng", }, // US - English
- { "fr", "xkb:fr::fra", }, // France - French
- { "de", "xkb:de::ger", }, // Germany - German
-};
-
// The comparator is used for sorting language codes by their
// corresponding language names, using the ICU collator.
struct CompareLanguageCodesByLanguageName
@@ -264,6 +262,7 @@ struct CompareLanguageCodesByLanguageName
return l10n_util::StringComparator<std::wstring>(collator_)(key1, key2);
}
+ private:
icu::Collator* collator_;
};
@@ -293,6 +292,7 @@ struct CompareInputMethodIdsByLanguageName
return comparator_(language_code_1, language_code_2);
}
+ private:
const CompareLanguageCodesByLanguageName comparator_;
const std::map<std::string, std::string>& id_to_language_code_map_;
};
@@ -444,16 +444,6 @@ std::string GetLanguageCodeFromDescriptor(
return language_code;
}
-std::wstring MaybeRewriteLanguageName(const std::wstring& language_name) {
- // "t" is used as the language code for input methods that don't fall
- // under any other languages.
- if (language_name == L"t") {
- return l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_LANGUAGES_OTHERS);
- }
- return language_name;
-}
-
std::string GetLanguageCodeFromInputMethodId(
const std::string& input_method_id) {
// The code should be compatible with one of codes used for UI languages,
@@ -490,10 +480,14 @@ std::wstring GetLanguageDisplayNameFromCode(const std::string& language_code) {
if (!g_browser_process) {
return L"";
}
- return MaybeRewriteLanguageName(UTF16ToWide(
- l10n_util::GetDisplayNameForLocale(
- language_code, g_browser_process->GetApplicationLocale(),
- true)));
+ return UTF16ToWide(l10n_util::GetDisplayNameForLocale(
+ language_code, g_browser_process->GetApplicationLocale(), true));
+}
+
+std::wstring GetLanguageNativeDisplayNameFromCode(
+ const std::string& language_code) {
+ return UTF16ToWide(l10n_util::GetDisplayNameForLocale(
+ language_code, language_code, true));
}
void SortLanguageCodesByNames(std::vector<std::string>* language_codes) {
@@ -536,24 +530,6 @@ void SortInputMethodIdsByNamesInternal(
collator.get(), id_to_language_code_map));
}
-void ReorderInputMethodIdsForLanguageCode(
- const std::string& language_code,
- std::vector<std::string>* input_method_ids) {
- for (size_t i = 0; i < arraysize(kLanguageDefaultInputMethodIds); ++i) {
- if (language_code == kLanguageDefaultInputMethodIds[i].language_code) {
- std::vector<std::string>::iterator iter =
- std::find(input_method_ids->begin(), input_method_ids->end(),
- kLanguageDefaultInputMethodIds[i].input_method_id);
- // If it's not on the top of |input_method_id|, swap it with the top one.
- if (iter != input_method_ids->end() &&
- iter != input_method_ids->begin()) {
- std::swap(*input_method_ids->begin(), *iter);
- }
- break; // Don't have to check other language codes.
- }
- }
-}
-
bool GetInputMethodIdsFromLanguageCode(
const std::string& normalized_language_code,
InputMethodType type,
@@ -594,9 +570,11 @@ void EnableInputMethods(const std::string& language_code, InputMethodType type,
std::vector<std::string> input_method_ids;
GetInputMethodIdsFromLanguageCode(language_code, type, &input_method_ids);
+ std::string keyboard = CrosLibrary::Get()->GetKeyboardLibrary()->
+ GetHardwareKeyboardLayoutName();
if (std::count(input_method_ids.begin(), input_method_ids.end(),
- kHardwareKeyboardLayout) == 0) {
- input_method_ids.push_back(kHardwareKeyboardLayout);
+ keyboard) == 0) {
+ input_method_ids.push_back(keyboard);
}
// First, sort the vector by input method id, then by its display name.
std::sort(input_method_ids.begin(), input_method_ids.end());
@@ -607,11 +585,16 @@ void EnableInputMethods(const std::string& language_code, InputMethodType type,
value.type = ImeConfigValue::kValueTypeStringList;
value.string_list_value = input_method_ids;
InputMethodLibrary* library = CrosLibrary::Get()->GetInputMethodLibrary();
- library->SetImeConfig(kGeneralSectionName, kPreloadEnginesConfigName, value);
+ library->SetImeConfig(language_prefs::kGeneralSectionName,
+ language_prefs::kPreloadEnginesConfigName, value);
if (!initial_input_method_id.empty()) {
library->ChangeInputMethod(initial_input_method_id);
}
}
+void OnLocaleChanged() {
+ Singleton<IdMaps>::get()->ReloadMaps();
+}
+
} // namespace input_method
} // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/input_method_util.h b/chrome/browser/chromeos/input_method/input_method_util.h
index 72d86ea..f97a792 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.h
+++ b/chrome/browser/chromeos/input_method/input_method_util.h
@@ -4,7 +4,9 @@
#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_UTIL_H_
#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_UTIL_H_
+#pragma once
+#include <map>
#include <string>
#include <vector>
@@ -14,8 +16,8 @@
namespace chromeos {
namespace input_method {
-// The list of language that do not have associated input methods. For
-// these languages, we associate input methods here.
+// The list of language that do not have associated input methods in IBus.
+// For these languages, we associate input methods here.
const struct ExtraLanguage {
const char* language_code;
const char* input_method_id;
@@ -74,12 +76,6 @@ std::string GetLanguageCodeFromDescriptor(
// "pinyin" => ""
std::string GetKeyboardLayoutName(const std::string& input_method_id);
-// Rewrites the language name and returns the modified version if
-// necessary. Otherwise, returns the given language name as is.
-// In particular, this rewrites the special language name used for input
-// methods that don't fall under any other languages.
-std::wstring MaybeRewriteLanguageName(const std::wstring& language_name);
-
// Converts an input method ID to a language code of the IME. Returns "Eng"
// when |input_method_id| is unknown.
// Example: "hangul" => "ko"
@@ -95,10 +91,17 @@ std::string GetInputMethodDisplayNameFromId(const std::string& input_method_id);
// Converts a language code to a language display name, using the
// current application locale. MaybeRewriteLanguageName() is called
// internally.
-// Examples: "fr" => "French"
+// Examples: "fi" => "Finnish"
// "en-US" => "English (United States)"
std::wstring GetLanguageDisplayNameFromCode(const std::string& language_code);
+// Converts a language code to a language native display name.
+// MaybeRewriteLanguageName() is called internally.
+// Examples: "fi" => "suomi" (rather than Finnish)
+// "en-US" => "English (United States)"
+std::wstring GetLanguageNativeDisplayNameFromCode(
+ const std::string& language_code);
+
// Sorts the given language codes by their corresponding language names,
// using the unicode string comparator. Uses unstable sorting.
void SortLanguageCodesByNames(std::vector<std::string>* language_codes);
@@ -107,15 +110,6 @@ void SortLanguageCodesByNames(std::vector<std::string>* language_codes);
// using the unicode string comparator. Uses stable sorting.
void SortInputMethodIdsByNames(std::vector<std::string>* input_method_ids);
-// Reorders the given input method ids for the language code. For
-// example, if |language_codes| is "fr" and |input_method_ids| contains
-// ["xkb:be::fra", and "xkb:fr::fra"], the list is reordered to
-// ["xkb:fr::fra", and "xkb:be::fra"], so that French keyboard layout
-// comes before Belgian keyboard layout.
-void ReorderInputMethodIdsForLanguageCode(
- const std::string& language_code,
- std::vector<std::string>* input_method_ids);
-
enum InputMethodType {
kKeyboardLayoutsOnly,
kAllInputMethods,
@@ -156,6 +150,8 @@ bool GetInputMethodIdsFromLanguageCodeInternal(
InputMethodType type,
std::vector<std::string>* out_input_method_ids);
+void OnLocaleChanged();
+
} // namespace input_method
} // namespace chromeos
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 b4a3c95..f228d11 100644
--- a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
@@ -34,6 +34,9 @@ TEST(InputMethodUtilTest, NormalizeLanguageCode) {
// TODO(yusukes): test all language codes that IBus provides.
EXPECT_EQ("ja", NormalizeLanguageCode("ja"));
EXPECT_EQ("ja", NormalizeLanguageCode("jpn"));
+ // In the past "t" had a meaning of "other language" for some m17n latin
+ // input methods for testing purpose, but it is no longer used. We test "t"
+ // here as just an "unknown" language.
EXPECT_EQ("t", NormalizeLanguageCode("t"));
EXPECT_EQ("zh-CN", NormalizeLanguageCode("zh-CN"));
EXPECT_EQ("zh-CN", NormalizeLanguageCode("zh_CN"));
@@ -74,12 +77,6 @@ TEST(InputMethodUtilTest, GetLanguageCodeFromDescriptor) {
InputMethodDescriptor("xkb:uk::eng", "United Kingdom", "us", "eng")));
}
-TEST(InputMethodUtilTest, MaybeRewriteLanguageName) {
- EXPECT_EQ(L"English", MaybeRewriteLanguageName(L"English"));
- EXPECT_EQ(l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_OTHERS),
- MaybeRewriteLanguageName(L"t"));
-}
-
TEST(InputMethodUtilTest, GetKeyboardLayoutName) {
// Unsupported cases
EXPECT_EQ("", GetKeyboardLayoutName("UNSUPPORTED_ID"));
@@ -88,8 +85,6 @@ TEST(InputMethodUtilTest, GetKeyboardLayoutName) {
EXPECT_EQ("", GetKeyboardLayoutName("mozc"));
EXPECT_EQ("", GetKeyboardLayoutName("mozc-jp"));
EXPECT_EQ("", GetKeyboardLayoutName("pinyin"));
- EXPECT_EQ("", GetKeyboardLayoutName("m17n:t:latn-pre"));
- EXPECT_EQ("", GetKeyboardLayoutName("m17n:t:latn-post"));
EXPECT_EQ("", GetKeyboardLayoutName("m17n:ar:kbd"));
EXPECT_EQ("", GetKeyboardLayoutName("m17n:he:kbd"));
EXPECT_EQ("", GetKeyboardLayoutName("m17n:hi:itrans"));
@@ -142,10 +137,11 @@ TEST(InputMethodUtilTest, GetKeyboardLayoutName) {
}
TEST(InputMethodUtilTest, GetLanguageDisplayNameFromCode) {
- EXPECT_EQ(L"French", GetLanguageDisplayNameFromCode("fr"));
- // MaybeRewriteLanguageName() should be applied.
- EXPECT_EQ(l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_OTHERS),
- GetLanguageDisplayNameFromCode("t"));
+ EXPECT_EQ(L"Finnish", GetLanguageDisplayNameFromCode("fi"));
+}
+
+TEST(InputMethodUtilTest, GetLanguageNativeDisplayNameFromCode) {
+ EXPECT_EQ(L"suomi", GetLanguageNativeDisplayNameFromCode("fi"));
}
TEST(InputMethodUtilTest, SortLanguageCodesByNames) {
@@ -155,6 +151,7 @@ TEST(InputMethodUtilTest, SortLanguageCodesByNames) {
language_codes.push_back("ja");
language_codes.push_back("fr");
+ // For "t", see the comment in NormalizeLanguageCode test.
language_codes.push_back("t");
SortLanguageCodesByNames(&language_codes);
ASSERT_EQ(3U, language_codes.size());
@@ -178,7 +175,6 @@ TEST(LanguageConfigModelTest, SortInputMethodIdsByNamesInternal) {
id_to_language_code_map.insert(std::make_pair("mozc-jp", "ja"));
id_to_language_code_map.insert(std::make_pair("xkb:jp::jpn", "ja"));
id_to_language_code_map.insert(std::make_pair("xkb:fr::fra", "fr"));
- id_to_language_code_map.insert(std::make_pair("m17n:latn-pre", "t"));
std::vector<std::string> input_method_ids;
// Check if this function can handle an empty list.
@@ -187,87 +183,30 @@ TEST(LanguageConfigModelTest, SortInputMethodIdsByNamesInternal) {
input_method_ids.push_back("mozc"); // Japanese
input_method_ids.push_back("xkb:fr::fra"); // French
- input_method_ids.push_back("m17n:latn-pre"); // Others
SortInputMethodIdsByNamesInternal(id_to_language_code_map,
&input_method_ids);
- ASSERT_EQ(3U, input_method_ids.size());
+ ASSERT_EQ(2U, input_method_ids.size());
ASSERT_EQ("xkb:fr::fra", input_method_ids[0]); // French
ASSERT_EQ("mozc", input_method_ids[1]); // Japanese
- ASSERT_EQ("m17n:latn-pre", input_method_ids[2]); // Others
// Add a duplicate entry and see if it works.
// Note that SortInputMethodIdsByNamesInternal uses std::stable_sort.
input_method_ids.push_back("xkb:jp::jpn"); // also Japanese
SortInputMethodIdsByNamesInternal(id_to_language_code_map,
&input_method_ids);
- ASSERT_EQ(4U, input_method_ids.size());
+ ASSERT_EQ(3U, input_method_ids.size());
ASSERT_EQ("xkb:fr::fra", input_method_ids[0]); // French
ASSERT_EQ("mozc", input_method_ids[1]); // Japanese
ASSERT_EQ("xkb:jp::jpn", input_method_ids[2]); // Japanese
- ASSERT_EQ("m17n:latn-pre", input_method_ids[3]); // Others
input_method_ids.push_back("mozc-jp"); // also Japanese
SortInputMethodIdsByNamesInternal(id_to_language_code_map,
&input_method_ids);
- ASSERT_EQ(5U, input_method_ids.size());
+ ASSERT_EQ(4U, input_method_ids.size());
ASSERT_EQ("xkb:fr::fra", input_method_ids[0]); // French
ASSERT_EQ("mozc", input_method_ids[1]); // Japanese
ASSERT_EQ("xkb:jp::jpn", input_method_ids[2]); // Japanese
ASSERT_EQ("mozc-jp", input_method_ids[3]); // Japanese
- ASSERT_EQ("m17n:latn-pre", input_method_ids[4]); // Others
-}
-
-TEST(InputMethodUtilTest, ReorderInputMethodIdsForLanguageCode_DE) {
- std::vector<std::string> input_method_ids;
- input_method_ids.push_back("xkb:ch::ger"); // Switzerland - German
- input_method_ids.push_back("xkb:de::ger"); // Germany - German
- ReorderInputMethodIdsForLanguageCode("de", &input_method_ids);
- // The list should be reordered.
- ASSERT_EQ(2U, input_method_ids.size());
- EXPECT_EQ("xkb:de::ger", input_method_ids[0]);
- EXPECT_EQ("xkb:ch::ger", input_method_ids[1]);
-}
-
-TEST(InputMethodUtilTest, ReorderInputMethodIdsForLanguageCode_FR) {
- std::vector<std::string> input_method_ids;
- input_method_ids.push_back("xkb:be::fra"); // Belgium - French
- input_method_ids.push_back("xkb:fr::fra"); // France - French
- ReorderInputMethodIdsForLanguageCode("fr", &input_method_ids);
- // The list should be reordered.
- ASSERT_EQ(2U, input_method_ids.size());
- EXPECT_EQ("xkb:fr::fra", input_method_ids[0]);
- EXPECT_EQ("xkb:be::fra", input_method_ids[1]);
-}
-
-TEST(InputMethodUtilTest, ReorderInputMethodIdsForLanguageCode_EN_US) {
- std::vector<std::string> input_method_ids;
- input_method_ids.push_back("xkb:us:dvorak:eng"); // US - Dvorak - English
- input_method_ids.push_back("xkb:us::eng"); // US - English
- ReorderInputMethodIdsForLanguageCode("en-US", &input_method_ids);
- // The list should be reordered.
- ASSERT_EQ(2U, input_method_ids.size());
- EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
- EXPECT_EQ("xkb:us:dvorak:eng", input_method_ids[1]);
-}
-
-TEST(InputMethodUtilTest, ReorderInputMethodIdsForLanguageCode_FI) {
- std::vector<std::string> input_method_ids;
- input_method_ids.push_back("xkb:fi::fin"); // Finland - Finnish
- ReorderInputMethodIdsForLanguageCode("fi", &input_method_ids);
- // There is no rule for reordering for Finnish.
- ASSERT_EQ(1U, input_method_ids.size());
- EXPECT_EQ("xkb:fi::fin", input_method_ids[0]);
-}
-
-TEST(InputMethodUtilTest, ReorderInputMethodIdsForLanguageCode_Noop) {
- std::vector<std::string> input_method_ids;
- input_method_ids.push_back("xkb:fr::fra"); // France - French
- input_method_ids.push_back("xkb:be::fra"); // Belgium - French
- // If the list is already sorted, nothing should happen.
- ReorderInputMethodIdsForLanguageCode("fr", &input_method_ids);
- ASSERT_EQ(2U, input_method_ids.size());
- EXPECT_EQ("xkb:fr::fra", input_method_ids[0]);
- EXPECT_EQ("xkb:be::fra", input_method_ids[1]);
}
TEST(LanguageConfigModelTest, GetInputMethodIdsForLanguageCode) {
diff --git a/chrome/browser/chromeos/language_preferences.h b/chrome/browser/chromeos/language_preferences.h
index 34ab1ec..2dfb95e 100644
--- a/chrome/browser/chromeos/language_preferences.h
+++ b/chrome/browser/chromeos/language_preferences.h
@@ -4,17 +4,20 @@
#ifndef CHROME_BROWSER_CHROMEOS_LANGUAGE_PREFERENCES_H_
#define CHROME_BROWSER_CHROMEOS_LANGUAGE_PREFERENCES_H_
+#pragma once
-#include "base/basictypes.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
+#include <stddef.h> // For size_t
-// Section and config names for the IBus configuration daemon.
+// This file defines types and declare variables used in "Languages and
+// Input" settings in Chromium OS.
namespace chromeos {
+namespace language_prefs {
+// The struct is used for preferences consisting of multiple choices, like
+// punctuation types used in Japanese input method.
template <typename DataType>
struct LanguageMultipleChoicePreference {
- const wchar_t* pref_name; // Chrome preference name.
+ const char* pref_name; // Chrome preference name.
DataType default_pref_value;
const char* ibus_config_name;
// Currently we have 10 combobox items at most.
@@ -26,15 +29,19 @@ struct LanguageMultipleChoicePreference {
int label_message_id; // Resource grd ID for the label.
};
+// The struct is used for preferences of boolean values, like switches to
+// enable or disable particular features.
struct LanguageBooleanPrefs {
- const wchar_t* pref_name; // Chrome preference name.
+ const char* pref_name; // Chrome preference name.
bool default_pref_value;
const char* ibus_config_name;
int message_id;
};
+// The struct is used for preferences of integer range values, like the
+// key repeat rate.
struct LanguageIntegerRangePreference {
- const wchar_t* pref_name; // Chrome preference name.
+ const char* pref_name; // Chrome preference name.
int default_pref_value;
int min_pref_value;
int max_pref_value;
@@ -42,371 +49,121 @@ struct LanguageIntegerRangePreference {
int message_id;
};
+// ---------------------------------------------------------------------------
// For ibus-daemon
-const char kGeneralSectionName[] = "general";
-const char kHotKeySectionName[] = "general/hotkey";
-const char kPreloadEnginesConfigName[] = "preload_engines";
-const char kNextEngineInMenuConfigName[] = "next_engine_in_menu";
-const char kPreviousEngineConfigName[] = "previous_engine";
-
-// TODO(yusukes): Check if the "Kana/Eisu" key in the Japanese keyboard for
-// Chrome OS actually generates Zenkaku_Hankaku when the keyboard gets ready.
-
-// ibus-daemon accepts up to 5 next-engine hot-keys.
-const char kHotkeyNextEngineInMenu[] =
- "Shift+Alt+Release+Shift_L,Shift+Alt+Release+Meta_L,Control+Shift+space,"
- "Zenkaku_Hankaku";
-// TODO(suzhe): Add more key bindings?
-const char kHotkeyPreviousEngine[] = "Control+space";
-
-// For Simplified Chinese input method (ibus-chewing)
-const char kChewingSectionName[] = "engine/Chewing";
-
-// We have to sync the |ibus_config_name|s with those in
-// ibus-chewing/files/src/Config.cc.
-const LanguageBooleanPrefs kChewingBooleanPrefs[] = {
- { prefs::kLanguageChewingAutoShiftCur, false, "autoShiftCur",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_AUTO_SHIFT_CUR},
- { prefs::kLanguageChewingAddPhraseDirection, false, "addPhraseDirection",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_ADD_PHRASE_DIRECTION},
- { prefs::kLanguageChewingEasySymbolInput, true, "easySymbolInput",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_EASY_SYMBOL_INPUT},
- { prefs::kLanguageChewingEscCleanAllBuf, false, "escCleanAllBuf",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_ESC_CLEAN_ALL_BUF},
- { prefs::kLanguageChewingForceLowercaseEnglish, false,
- "forceLowercaseEnglish",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_FORCE_LOWER_CASE_ENGLISH},
- { prefs::kLanguageChewingPlainZhuyin, false, "plainZhuyin",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_PLAIN_ZHUYIN},
- { prefs::kLanguageChewingPhraseChoiceRearward, true, "phraseChoiceRearward",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_PHRASE_CHOICE_REARWARD},
- { prefs::kLanguageChewingSpaceAsSelection, true, "spaceAsSelection",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_SPACE_AS_SELECTION},
-};
-const size_t kNumChewingBooleanPrefs = ARRAYSIZE_UNSAFE(kChewingBooleanPrefs);
-
-const LanguageIntegerRangePreference kChewingIntegerPrefs[] = {
- { prefs::kLanguageChewingMaxChiSymbolLen, 20, 8, 40, "maxChiSymbolLen",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_MAX_CHI_SYMBOL_LEN},
- { prefs::kLanguageChewingCandPerPage, 10, 8, 10, "candPerPage",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTING_CAND_PER_PAGE},
-};
-const size_t kNumChewingIntegerPrefs = ARRAYSIZE_UNSAFE(kChewingIntegerPrefs);
-
-const LanguageMultipleChoicePreference<const char*>
- kChewingMultipleChoicePrefs[] = {
- { prefs::kLanguageChewingKeyboardType,
- "default",
- "KBType",
- {{ "default",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_DEFAULT },
- { "hsu", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_HSU },
- { "ibm", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_IBM },
- { "gin_yieh",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_GIN_YIEH },
- { "eten", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_ETEN },
- { "eten26", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_ETEN26 },
- { "dvorak", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_DVORAK },
- { "dvorak_hsu",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_DVORAK_HSU },
- { "dachen_26",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_DACHEN_26 },
- { "hanyu", IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE_HANYU }},
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_KEYBOARD_TYPE,
- },
- { prefs::kLanguageChewingSelKeys,
- "1234567890",
- "selKeys",
- {{ "1234567890",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_1234567890 },
- { "asdfghjkl;",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_ASDFGHJKLS },
- { "asdfzxcv89",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_ASDFZXCV89 },
- { "asdfjkl789",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_ASDFJKL789 },
- { "aoeu;qjkix",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_AOEUSQJKIX },
- { "aoeuhtnsid",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_AOEUHTNSID },
- { "aoeuidhtns",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_AOEUIDHTNS },
- { "1234qweras",
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS_1234QWERAS }},
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SEL_KEYS,
- },
-};
-const size_t kNumChewingMultipleChoicePrefs =
- arraysize(kChewingMultipleChoicePrefs);
-
-const LanguageMultipleChoicePreference<int> kChewingHsuSelKeyType = {
- prefs::kLanguageChewingHsuSelKeyType,
- 1,
- "hsuSelKeyType",
- {{ 1, IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_HSU_SEL_KEY_TYPE_1 },
- { 2, IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_HSU_SEL_KEY_TYPE_2 }},
- IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_HSU_SEL_KEY_TYPE,
-};
-
+// ---------------------------------------------------------------------------
+extern const char kGeneralSectionName[];
+extern const char kHotKeySectionName[];
+extern const char kPreloadEnginesConfigName[];
+extern const char kNextEngineInMenuConfigName[];
+extern const char kPreviousEngineConfigName[];
+extern const char kHotkeyNextEngineInMenu[];
+extern const char kHotkeyPreviousEngine[];
+
+// ---------------------------------------------------------------------------
+// For Traditional Chinese input method (ibus-chewing)
+// ---------------------------------------------------------------------------
+extern const char kChewingSectionName[];
+
+extern const LanguageBooleanPrefs kChewingBooleanPrefs[];
+// This is not ideal, but we should hard-code the number here as the value
+// is referenced in other header files as array sizes. We have a
+// COMPILE_ASSERT in .cc to ensure that the number is correct.
+const size_t kNumChewingBooleanPrefs = 8;
+
+extern const LanguageIntegerRangePreference kChewingIntegerPrefs[];
+// See comments at kNumChewingBooleanPrefs for why we hard-code this here.
+const size_t kNumChewingIntegerPrefs = 2;
+const int kChewingMaxChiSymbolLenIndex = 0;
+const int kChewingCandPerPageIndex = 1;
+
+extern const LanguageMultipleChoicePreference<const char*>
+ kChewingMultipleChoicePrefs[];
+// See comments at kNumChewingBooleanPrefs for why we hard-code this here.
+const size_t kNumChewingMultipleChoicePrefs = 2;
+
+extern const LanguageMultipleChoicePreference<int> kChewingHsuSelKeyType;
+
+// ---------------------------------------------------------------------------
// For Korean input method (ibus-hangul)
-const char kHangulSectionName[] = "engine/Hangul";
-const char kHangulKeyboardConfigName[] = "HangulKeyboard";
-const char kHangulHanjaKeysConfigName[] = "HanjaKeys";
-// We add Control+Alt+9 in addition to the two default keys since Hanja key
-// might not be available on the Chrome OS keyboard and F9 key is reserved by
-// the window manager.
-// TODO: Hanja keys are not configurable yet (and we're not sure if it should.)
-const char kHangulHanjaKeys[] = "F9,Hangul_Hanja,Control+Alt+9";
+// ---------------------------------------------------------------------------
+extern const char kHangulSectionName[];
+extern const char kHangulKeyboardConfigName[];
+extern const char kHangulHanjaKeysConfigName[];
+extern const char kHangulHanjaKeys[];
-const struct HangulKeyboardNameIDPair {
+struct HangulKeyboardNameIDPair {
int message_id;
const char* keyboard_id;
-} kHangulKeyboardNameIDPairs[] = {
- // We have to sync the |keyboard_id|s with those in
- // ibus-hangul/files/setup/main.py.
- { IDS_OPTIONS_SETTINGS_LANGUAGES_HANGUL_SETTINGS_KEYBOARD_2_SET, "2" },
- { IDS_OPTIONS_SETTINGS_LANGUAGES_HANGUL_SETTINGS_KEYBOARD_3_SET_FINAL,
- "3f" },
- { IDS_OPTIONS_SETTINGS_LANGUAGES_HANGUL_SETTINGS_KEYBOARD_3_SET_390, "39" },
- { IDS_OPTIONS_SETTINGS_LANGUAGES_HANGUL_SETTINGS_KEYBOARD_3_SET_NO_SHIFT,
- "3s" },
- // We don't support "Sebeolsik 2 set" keyboard.
};
+extern const HangulKeyboardNameIDPair kHangulKeyboardNameIDPairs[];
+// See comments at kNumChewingBooleanPrefs for why we hard-code this here.
+const size_t kNumHangulKeyboardNameIDPairs = 4;
+
+// ---------------------------------------------------------------------------
// For Simplified Chinese input method (ibus-pinyin)
-const char kPinyinSectionName[] = "engine/Pinyin";
+// ---------------------------------------------------------------------------
+extern const char kPinyinSectionName[];
-// We have to sync the |ibus_config_name|s with those in
-// ibus-pinyin/files/src/Config.cc.
-const LanguageBooleanPrefs kPinyinBooleanPrefs[] = {
- { prefs::kLanguagePinyinCorrectPinyin, true, "CorrectPinyin",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_CORRECT_PINYIN },
- { prefs::kLanguagePinyinFuzzyPinyin, false, "FuzzyPinyin",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_FUZZY_PINYIN },
- { prefs::kLanguagePinyinShiftSelectCandidate, false, "ShiftSelectCandidate",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_SHIFT_SELECT_PINYIN },
- { prefs::kLanguagePinyinMinusEqualPage, true, "MinusEqualPage",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_MINUS_EQUAL_PAGE },
- { prefs::kLanguagePinyinCommaPeriodPage, true, "CommaPeriodPage",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_COMMA_PERIOD_PAGE },
- { prefs::kLanguagePinyinAutoCommit, false, "AutoCommit",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_AUTO_COMMIT },
- { prefs::kLanguagePinyinDoublePinyin, false, "DoublePinyin",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_DOUBLE_PINYIN },
- { prefs::kLanguagePinyinInitChinese, true, "InitChinese",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_INIT_CHINESE },
- { prefs::kLanguagePinyinInitFull, false, "InitFull",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_INIT_FULL },
- { prefs::kLanguagePinyinInitFullPunct, true, "InitFullPunct",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_INIT_FULL_PUNCT },
- { prefs::kLanguagePinyinInitSimplifiedChinese, true, "InitSimplifiedChinese",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_INIT_SIMPLIFIED_CHINESE },
- { prefs::kLanguagePinyinTradCandidate, false, "TradCandidate",
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTING_TRAD_CANDIDATE },
- // TODO(yusukes): Support PINYIN_{INCOMPLETE,CORRECT,FUZZY}_... prefs (32
- // additional boolean prefs.)
-};
-const size_t kNumPinyinBooleanPrefs = ARRAYSIZE_UNSAFE(kPinyinBooleanPrefs);
-// TODO(yusukes): Support HalfWidthPuncts and IncompletePinyin prefs if needed.
+extern const LanguageBooleanPrefs kPinyinBooleanPrefs[];
+// See comments at kNumChewingBooleanPrefs for why we hard-code this here.
+const size_t kNumPinyinBooleanPrefs = 11;
-const LanguageMultipleChoicePreference<int> kPinyinDoublePinyinSchema = {
- prefs::kLanguagePinyinDoublePinyinSchema,
- 0,
- "DoublePinyinSchema",
- {{ 0, IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_DOUBLE_SCHEMA_MSPY},
- { 1, IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_DOUBLE_SCHEMA_ZRM},
- { 2, IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_DOUBLE_SCHEMA_ABC},
- { 3, IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_DOUBLE_SCHEMA_ZGPY},
- { 4, IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_DOUBLE_SCHEMA_PYJJ}},
- IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_DOUBLE_SCHEMA,
-};
+extern const LanguageMultipleChoicePreference<int> kPinyinDoublePinyinSchema;
-const struct {
- const wchar_t* pref_name; // Chrome preference name.
+struct PinyinIntegerPref {
+ const char* pref_name; // Chrome preference name.
int default_pref_value;
const char* ibus_config_name;
// TODO(yusukes): Add message_id if needed.
-} kPinyinIntegerPrefs[] = {
- // TODO(yusukes): the type of lookup_table_page_size on ibus should be uint.
- { prefs::kLanguagePinyinLookupTablePageSize, 5, "LookupTablePageSize" },
-};
-const size_t kNumPinyinIntegerPrefs = ARRAYSIZE_UNSAFE(kPinyinIntegerPrefs);
-
-// For Japanese input method (ibus-mozc)
-const char kMozcSectionName[] = "engine/Mozc";
-
-#define IDS_MOZC(suffix) \
- IDS_OPTIONS_SETTINGS_LANGUAGES_MOZC_##suffix
-
-const LanguageBooleanPrefs kMozcBooleanPrefs[] = {
- { prefs::kLanguageMozcIncognitoMode,
- false,
- "incognito_mode",
- IDS_MOZC(INCOGNITO_MODE)
- },
- { prefs::kLanguageMozcUseAutoImeTurnOff,
- true,
- "use_auto_ime_turn_off",
- IDS_MOZC(USE_AUTO_IME_TURN_OFF)
- },
- { prefs::kLanguageMozcUseDateConversion,
- true,
- "use_date_conversion",
- IDS_MOZC(USE_DATE_CONVERSION)
- },
- { prefs::kLanguageMozcUseSingleKanjiConversion,
- true,
- "use_single_kanji_conversion",
- IDS_MOZC(USE_SINGLE_KANJI_CONVERSION)
- },
- { prefs::kLanguageMozcUseSymbolConversion,
- true,
- "use_symbol_conversion",
- IDS_MOZC(USE_SYMBOL_CONVERSION)
- },
- { prefs::kLanguageMozcUseNumberConversion,
- true,
- "use_number_conversion",
- IDS_MOZC(USE_NUMBER_CONVERSION)
- },
- { prefs::kLanguageMozcUseHistorySuggest,
- true,
- "use_history_suggest",
- IDS_MOZC(USE_HISTORY_SUGGEST)
- },
- { prefs::kLanguageMozcUseDictionarySuggest,
- true,
- "use_dictionary_suggest",
- IDS_MOZC(USE_DICTIONARY_SUGGEST)
- },
};
-const size_t kNumMozcBooleanPrefs = ARRAYSIZE_UNSAFE(kMozcBooleanPrefs);
-const LanguageMultipleChoicePreference<const char*>
- kMozcMultipleChoicePrefs[] = {
- { prefs::kLanguageMozcPreeditMethod,
- "ROMAN",
- "preedit_method",
- {{ "ROMAN", IDS_MOZC(PREEDIT_METHOD_ROMAN) },
- { "KANA", IDS_MOZC(PREEDIT_METHOD_KANA) }},
- IDS_MOZC(PREEDIT_METHOD),
- },
- { prefs::kLanguageMozcSessionKeymap,
- "MSIME",
- "session_keymap",
- {{ "ATOK", IDS_MOZC(SESSION_KEYMAP_ATOK) },
- { "MSIME", IDS_MOZC(SESSION_KEYMAP_MSIME) },
- { "KOTOERI", IDS_MOZC(SESSION_KEYMAP_KOTOERI) }},
- // TODO: Support "CUSTOM" keymap.
- IDS_MOZC(SESSION_KEYMAP),
- },
- { prefs::kLanguageMozcPunctuationMethod,
- "KUTEN_TOUTEN",
- "punctuation_method",
- {{ "KUTEN_TOUTEN",
- IDS_MOZC(PUNCTUATION_METHOD_KUTEN_TOUTEN) },
- { "COMMA_PERIOD",
- IDS_MOZC(PUNCTUATION_METHOD_COMMA_PERIOD) },
- { "KUTEN_PERIOD",
- IDS_MOZC(PUNCTUATION_METHOD_KUTEN_PERIOD) },
- { "COMMA_TOUTEN",
- IDS_MOZC(PUNCTUATION_METHOD_COMMA_TOUTEN) }},
- IDS_MOZC(PUNCTUATION_METHOD),
- },
- { prefs::kLanguageMozcSymbolMethod,
- "CORNER_BRACKET_MIDDLE_DOT",
- "symbol_method",
- {{ "CORNER_BRACKET_MIDDLE_DOT",
- IDS_MOZC(SYMBOL_METHOD_CORNER_BRACKET_MIDDLE_DOT) },
- { "SQUARE_BRACKET_SLASH",
- IDS_MOZC(SYMBOL_METHOD_SQUARE_BRACKET_SLASH) },
- { "CORNER_BRACKET_SLASH",
- IDS_MOZC(SYMBOL_METHOD_CORNER_BRACKET_SLASH) },
- { "SQUARE_BRACKET_MIDDLE_DOT",
- IDS_MOZC(SYMBOL_METHOD_SQUARE_BRACKET_MIDDLE_DOT) }},
- IDS_MOZC(SYMBOL_METHOD),
- },
- { prefs::kLanguageMozcSpaceCharacterForm,
- "FUNDAMENTAL_INPUT_MODE",
- "space_character_form",
- {{ "FUNDAMENTAL_INPUT_MODE",
- IDS_MOZC(SPACE_CHARACTER_FORM_FUNDAMENTAL_INPUT_MODE) },
- { "FUNDAMENTAL_FULL_WIDTH",
- IDS_MOZC(SPACE_CHARACTER_FORM_FUNDAMENTAL_FULL_WIDTH) },
- { "FUNDAMENTAL_HALF_WIDTH",
- IDS_MOZC(SPACE_CHARACTER_FORM_FUNDAMENTAL_HALF_WIDTH) }},
- IDS_MOZC(SPACE_CHARACTER_FORM),
- },
- { prefs::kLanguageMozcHistoryLearningLevel,
- "DEFAULT_HISTORY",
- "history_learning_level",
- {{ "DEFAULT_HISTORY",
- IDS_MOZC(HISTORY_LEARNING_LEVEL_DEFAULT_HISTORY) },
- { "READ_ONLY",
- IDS_MOZC(HISTORY_LEARNING_LEVEL_READ_ONLY) },
- { "NO_HISTORY",
- IDS_MOZC(HISTORY_LEARNING_LEVEL_NO_HISTORY) }},
- IDS_MOZC(HISTORY_LEARNING_LEVEL),
- },
- // TODO(mazda): Uncomment this block once the candidate window in Chrome OS
- // supports changing shortcut labels.
- // { prefs::kLanguageMozcSelectionShortcut,
- // "SHORTCUT_123456789",
- // "selection_shortcut",
- // {{ "NO_SHORTCUT",
- // IDS_MOZC(SELECTION_SHORTCUT_NO_SHORTCUT) },
- // { "SHORTCUT_123456789",
- // IDS_MOZC(SELECTION_SHORTCUT_SHORTCUT_123456789) },
- // { "SHORTCUT_ASDFGHJKL",
- // IDS_MOZC(SELECTION_SHORTCUT_SHORTCUT_ASDFGHJKL) }},
- // IDS_MOZC(SELECTION_SHORTCUT),
- // },
- { prefs::kLanguageMozcShiftKeyModeSwitch,
- "ASCII_INPUT_MODE",
- "shift_key_mode_switch",
- {{ "OFF",
- IDS_MOZC(SHIFT_KEY_MODE_SWITCH_OFF) },
- { "ASCII_INPUT_MODE",
- IDS_MOZC(SHIFT_KEY_MODE_SWITCH_ASCII_INPUT_MODE) },
- { "KATAKANA_INPUT_MODE",
- IDS_MOZC(SHIFT_KEY_MODE_SWITCH_KATAKANA_INPUT_MODE) }},
- IDS_MOZC(SHIFT_KEY_MODE_SWITCH),
- },
- { prefs::kLanguageMozcNumpadCharacterForm,
- "NUMPAD_HALF_WIDTH",
- "numpad_character_form",
- {{ "NUMPAD_INPUT_MODE",
- IDS_MOZC(NUMPAD_CHARACTER_FORM_NUMPAD_INPUT_MODE) },
- { "NUMPAD_FULL_WIDTH",
- IDS_MOZC(NUMPAD_CHARACTER_FORM_NUMPAD_FULL_WIDTH) },
- { "NUMPAD_HALF_WIDTH",
- IDS_MOZC(NUMPAD_CHARACTER_FORM_NUMPAD_HALF_WIDTH) },
- { "NUMPAD_DIRECT_INPUT",
- IDS_MOZC(NUMPAD_CHARACTER_FORM_NUMPAD_DIRECT_INPUT) }},
- IDS_MOZC(NUMPAD_CHARACTER_FORM),
- },
-};
-const size_t kNumMozcMultipleChoicePrefs = arraysize(kMozcMultipleChoicePrefs);
+extern const PinyinIntegerPref kPinyinIntegerPrefs[];
+const size_t kNumPinyinIntegerPrefs = 1;
-const LanguageIntegerRangePreference kMozcIntegerPrefs[] = {
- { prefs::kLanguageMozcSuggestionsSize, 3, 1, 9, "suggestions_size",
- IDS_MOZC(SUGGESTIONS_SIZE)},
+// ---------------------------------------------------------------------------
+// For Japanese input method (ibus-mozc)
+// ---------------------------------------------------------------------------
+extern const char kMozcSectionName[];
+
+extern const LanguageBooleanPrefs kMozcBooleanPrefs[];
+// See comments at kNumChewingBooleanPrefs for why we hard-code this here.
+const size_t kNumMozcBooleanPrefs = 8;
+
+extern const LanguageMultipleChoicePreference<const char*>
+ kMozcMultipleChoicePrefs[];
+// See comments at kNumChewingBooleanPrefs for why we hard-code this here.
+const size_t kNumMozcMultipleChoicePrefs = 8;
+
+extern const LanguageIntegerRangePreference kMozcIntegerPrefs[];
+// See comments at kNumChewingBooleanPrefs for why we hard-code this here.
+const size_t kNumMozcIntegerPrefs = 1;
+
+// ---------------------------------------------------------------------------
+// For keyboard stuff
+// ---------------------------------------------------------------------------
+// TODO(yusukes): Temporary solution for View version of modifier key remapper.
+// Remove RemapType and kXkbModifierMultipleChoicePrefs when we finish to
+// migrate to DOMUI.
+enum RemapType {
+ kNoRemap = 0,
+ kSwapCtrlAndAlt = 1,
+ kSwapSearchAndCtrl = 2,
};
-const size_t kNumMozcIntegerPrefs = ARRAYSIZE_UNSAFE(kMozcIntegerPrefs);
-
-#undef IDS_MOZC
+extern const LanguageMultipleChoicePreference<int>
+ kXkbModifierMultipleChoicePrefs;
-// For Traditional Chinese input methods (ibus-pinyin-bopomofo and ibus-chewing)
-// TODO(yusukes): Add constants for Traditional Chinese input methods.
+// A delay between the first and the start of the rest.
+extern const int kXkbAutoRepeatDelayInMs;
+// An interval between the repeated keys.
+extern const int kXkbAutoRepeatIntervalInMs;
// A string Chrome preference (Local State) of the preferred keyboard layout in
// the login screen.
-const wchar_t kPreferredKeyboardLayout[] = L"PreferredKeyboardLayout";
-
-// A input method name that corresponds the hardware keyboard layout.
-// TODO(yusukes): just assuming US qwerty keyboard is not always correct.
-const char kHardwareKeyboardLayout[] = "xkb:us::eng";
+extern const char kPreferredKeyboardLayout[];
+} // language_prefs
} // chromeos
#endif // CHROME_BROWSER_CHROMEOS_LANGUAGE_PREFERENCES_H_
diff --git a/chrome/browser/chromeos/language_preferences_unittest.cc b/chrome/browser/chromeos/language_preferences_unittest.cc
index 49c5472..2383a28 100644
--- a/chrome/browser/chromeos/language_preferences_unittest.cc
+++ b/chrome/browser/chromeos/language_preferences_unittest.cc
@@ -10,6 +10,7 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
+namespace language_prefs {
namespace {
@@ -101,6 +102,8 @@ TEST(LanguagePreferencesTest, TestDefaultValuesOfMultipleChoicePrefs) {
EXPECT_TRUE(CheckDefaultValueOfMultipleChoicePrefs(
kChewingMultipleChoicePrefs, kNumChewingMultipleChoicePrefs));
EXPECT_TRUE(CheckDefaultValueOfMultipleChoicePrefs(
+ &kXkbModifierMultipleChoicePrefs, 1));
+ EXPECT_TRUE(CheckDefaultValueOfMultipleChoicePrefs(
&kChewingHsuSelKeyType, 1));
EXPECT_TRUE(CheckDefaultValueOfMultipleChoicePrefs(
&kPinyinDoublePinyinSchema, 1));
@@ -114,6 +117,8 @@ TEST(LanguagePreferencesTest, TestDuplicationOfMultipleChoicePrefs) {
EXPECT_TRUE(CheckDuplicationOfMultipleChoicePrefs(
kChewingMultipleChoicePrefs, kNumChewingMultipleChoicePrefs));
EXPECT_TRUE(CheckDuplicationOfMultipleChoicePrefs(
+ &kXkbModifierMultipleChoicePrefs, 1));
+ EXPECT_TRUE(CheckDuplicationOfMultipleChoicePrefs(
&kChewingHsuSelKeyType, 1));
EXPECT_TRUE(CheckDuplicationOfMultipleChoicePrefs(
&kPinyinDoublePinyinSchema, 1));
@@ -129,4 +134,5 @@ TEST(LanguagePreferencesTest, TestDefaultValuesOfIntegerRangePrefs) {
kMozcIntegerPrefs, kNumMozcIntegerPrefs));
}
+} // namespace language_prefs
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/account_creation_view.cc b/chrome/browser/chromeos/login/account_creation_view.cc
index 054e966..82ff793 100644
--- a/chrome/browser/chromeos/login/account_creation_view.cc
+++ b/chrome/browser/chromeos/login/account_creation_view.cc
@@ -61,8 +61,6 @@ class AccountCreationTabContents : public WizardWebPageViewTabContents,
virtual bool FillAutoFillFormData(int query_id,
const webkit_glue::FormData& form,
- const string16& name,
- const string16& label,
int unique_id) {
return false;
}
diff --git a/chrome/browser/chromeos/login/account_creation_view.h b/chrome/browser/chromeos/login/account_creation_view.h
index 11aa14d..40bbe31 100644
--- a/chrome/browser/chromeos/login/account_creation_view.h
+++ b/chrome/browser/chromeos/login/account_creation_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_ACCOUNT_CREATION_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_ACCOUNT_CREATION_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/account_screen.cc b/chrome/browser/chromeos/login/account_screen.cc
index b9ad26d..d7298fc 100644
--- a/chrome/browser/chromeos/login/account_screen.cc
+++ b/chrome/browser/chromeos/login/account_screen.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/login/account_screen.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/login/account_creation_view.h"
@@ -14,6 +15,7 @@
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
+#include "views/widget/widget_gtk.h"
namespace chromeos {
@@ -128,6 +130,12 @@ void AccountScreen::NavigationStateChanged(const TabContents* source,
}
}
+void AccountScreen::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
+ views::Widget* widget = view()->GetWidget();
+ if (widget && event.os_event && !event.skip_in_browser)
+ static_cast<views::WidgetGtk*>(widget)->HandleKeyboardEvent(event.os_event);
+}
+
///////////////////////////////////////////////////////////////////////////////
// AccountScreen, WebPageDelegate implementation:
void AccountScreen::OnPageLoaded() {
@@ -137,9 +145,7 @@ void AccountScreen::OnPageLoaded() {
if (g_browser_process) {
const std::string locale = g_browser_process->GetApplicationLocale();
input_method::EnableInputMethods(
- locale, input_method::kKeyboardLayoutsOnly, "");
- // TODO(yusukes,suzhe): Change the 2nd argument to kAllInputMethods when
- // crosbug.com/2670 is fixed.
+ locale, input_method::kAllInputMethods, "");
}
view()->ShowPageContent();
}
diff --git a/chrome/browser/chromeos/login/account_screen.h b/chrome/browser/chromeos/login/account_screen.h
index ec9173c..8d3ca4f 100644
--- a/chrome/browser/chromeos/login/account_screen.h
+++ b/chrome/browser/chromeos/login/account_screen.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_ACCOUNT_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_ACCOUNT_SCREEN_H_
+#pragma once
#include <string>
@@ -52,6 +53,7 @@ class AccountScreen : public ViewScreen<AccountCreationView>,
virtual void NavigationStateChanged(const TabContents* source,
unsigned changed_flags);
virtual void LoadingStateChanged(TabContents* source);
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
// WebPageScreen implementation:
virtual void CloseScreen(ScreenObserver::ExitCodes code);
diff --git a/chrome/browser/chromeos/login/account_screen_browsertest.cc b/chrome/browser/chromeos/login/account_screen_browsertest.cc
index 5f39335..eec150d 100644
--- a/chrome/browser/chromeos/login/account_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/account_screen_browsertest.cc
@@ -5,13 +5,14 @@
#include <string>
#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/login/account_screen.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h"
-#include "chrome/browser/chrome_thread.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+#include "net/test/test_server.h"
#include "net/url_request/url_request_about_job.h"
#include "net/url_request/url_request_filter.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -27,9 +28,8 @@ class AccountScreenTest : public WizardInProcessBrowserTest {
protected:
// Overridden from WizardInProcessBrowserTest:
virtual void SetUpWizard() {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server != NULL);
- GURL new_account_page_url(server->TestServerPage("files/new_account.html"));
+ ASSERT_TRUE(test_server()->Start());
+ GURL new_account_page_url(test_server()->GetURL("files/new_account.html"));
AccountScreen::set_new_account_page_url(new_account_page_url);
AccountScreen::set_check_for_https(false);
}
@@ -41,8 +41,7 @@ class AccountScreenTest : public WizardInProcessBrowserTest {
// A basic test. It does not care how things evolve after the URL is
// loaded. Thus no message loop is started. Just check that initial
// status is expected.
-// This test is flaky. See http://crbug.com/49004 .
-IN_PROC_BROWSER_TEST_F(AccountScreenTest, FLAKY_TestBasic) {
+IN_PROC_BROWSER_TEST_F(AccountScreenTest, TestBasic) {
ASSERT_TRUE(controller());
EXPECT_EQ(controller()->GetAccountScreen(), controller()->current_screen());
}
@@ -69,7 +68,7 @@ static URLRequestJob* InspectorHook(URLRequest* request,
return new URLRequestAboutJob(request);
}
-IN_PROC_BROWSER_TEST_F(AccountScreenTest, FLAKY_TestSchemeInspector) {
+IN_PROC_BROWSER_TEST_F(AccountScreenTest, TestSchemeInspector) {
ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
chrome::kCrosScheme);
URLRequestFilter::GetInstance()->AddHostnameHandler(chrome::kCrosScheme,
diff --git a/chrome/browser/chromeos/login/auth_response_handler.h b/chrome/browser/chromeos/login/auth_response_handler.h
index 826baeb..9be1a5e 100644
--- a/chrome/browser/chromeos/login/auth_response_handler.h
+++ b/chrome/browser/chromeos/login/auth_response_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_AUTH_RESPONSE_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_AUTH_RESPONSE_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/authentication_notification_details.h b/chrome/browser/chromeos/login/authentication_notification_details.h
index 4ad9f0d..2b14419 100644
--- a/chrome/browser/chromeos/login/authentication_notification_details.h
+++ b/chrome/browser/chromeos/login/authentication_notification_details.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_AUTHENTICATION_NOTIFICATION_DETAILS_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_AUTHENTICATION_NOTIFICATION_DETAILS_H_
+#pragma once
// A class to hold the parameters we get back from an authentication attempt
// through the login manager
diff --git a/chrome/browser/chromeos/login/authenticator.h b/chrome/browser/chromeos/login/authenticator.h
index bc0bdca..5fba9c3 100644
--- a/chrome/browser/chromeos/login/authenticator.h
+++ b/chrome/browser/chromeos/login/authenticator.h
@@ -4,12 +4,10 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_AUTHENTICATOR_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_AUTHENTICATOR_H_
+#pragma once
-#include <vector>
-
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "base/ref_counted.h"
-#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
@@ -25,10 +23,8 @@ namespace chromeos {
// consumer_->OnPasswordChangeDetected() on the UI thread.
class Authenticator : public base::RefCountedThreadSafe<Authenticator> {
public:
- explicit Authenticator(LoginStatusConsumer* consumer)
- : consumer_(consumer) {
- }
- virtual ~Authenticator() {}
+ explicit Authenticator(LoginStatusConsumer* consumer);
+ virtual ~Authenticator();
// Given a |username| and |password|, this method attempts to authenticate
// to login.
@@ -55,7 +51,7 @@ class Authenticator : public base::RefCountedThreadSafe<Authenticator> {
// and also call back to the login UI.
virtual void OnLoginSuccess(
const GaiaAuthConsumer::ClientLoginResult& credentials) = 0;
- virtual void OnLoginFailure(const std::string& data) = 0;
+ virtual void OnLoginFailure(const LoginFailure& error) = 0;
// Call these methods on the UI thread.
// If a password logs the user in online, but cannot be used to
@@ -75,6 +71,13 @@ class Authenticator : public base::RefCountedThreadSafe<Authenticator> {
virtual void ResyncEncryptedData(
const GaiaAuthConsumer::ClientLoginResult& credentials) = 0;
+ // Perform basic canonicalization of |email_address|, taking into account
+ // that gmail does not consider '.' or caps inside a username to matter.
+ // It also ignores everything after a '+'.
+ // For example, c.masone+abc@gmail.com == cMaSone@gmail.com, per
+ // http://mail.google.com/support/bin/answer.py?hl=en&ctx=mail&answer=10313#
+ static std::string Canonicalize(const std::string& email_address);
+
protected:
LoginStatusConsumer* consumer_;
diff --git a/chrome/browser/chromeos/login/background_view.cc b/chrome/browser/chromeos/login/background_view.cc
index 3d9f954..199f92f 100644
--- a/chrome/browser/chromeos/login/background_view.cc
+++ b/chrome/browser/chromeos/login/background_view.cc
@@ -4,21 +4,33 @@
#include "chrome/browser/chromeos/login/background_view.h"
+#include <string>
+#include <vector>
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/x11_util.h"
+#include "base/string16.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/oobe_progress_bar.h"
+#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/status/clock_menu_button.h"
#include "chrome/browser/chromeos/status/feedback_menu_button.h"
#include "chrome/browser/chromeos/status/language_menu_button.h"
#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/views/dom_view.h"
#include "cros/chromeos_wm_ipc_enums.h"
+#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "views/controls/button/text_button.h"
#include "views/controls/label.h"
#include "views/screen.h"
#include "views/widget/widget_gtk.h"
@@ -30,22 +42,35 @@
using views::WidgetGtk;
-namespace chromeos {
+namespace {
-BackgroundView::BackgroundView()
- : status_area_(NULL),
- os_version_label_(NULL),
- boot_times_label_(NULL),
- did_paint_(false) {
- views::Painter* painter = CreateBackgroundPainter();
- set_background(views::Background::CreateBackgroundPainter(true, painter));
- InitStatusArea();
- InitInfoLabels();
-}
+// The same as TextButton but switches cursor to hand cursor when mouse
+// is over the button.
+class TextButtonWithHandCursorOver : public views::TextButton {
+ public:
+ TextButtonWithHandCursorOver(views::ButtonListener* listener,
+ const std::wstring& text)
+ : views::TextButton(listener, text) {
+ }
+
+ virtual ~TextButtonWithHandCursorOver() {}
+
+ virtual gfx::NativeCursor GetCursorForPoint(
+ views::Event::EventType event_type,
+ const gfx::Point& p) {
+ if (!IsEnabled()) {
+ return NULL;
+ }
+ return gdk_cursor_new(GDK_HAND2);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextButtonWithHandCursorOver);
+};
+// This gets rid of the ugly X default cursor.
static void ResetXCursor() {
// TODO(sky): nuke this once new window manager is in place.
- // This gets rid of the ugly X default cursor.
Display* display = x11_util::GetXDisplay();
Cursor cursor = XCreateFontCursor(display, XC_left_ptr);
XID root_window = x11_util::GetX11RootWindow();
@@ -54,15 +79,54 @@ static void ResetXCursor() {
XChangeWindowAttributes(display, root_window, CWCursor, &attr);
}
+} // namespace
+
+namespace chromeos {
+
+///////////////////////////////////////////////////////////////////////////////
+// BackgroundView public:
+
+BackgroundView::BackgroundView()
+ : status_area_(NULL),
+ os_version_label_(NULL),
+ boot_times_label_(NULL),
+ progress_bar_(NULL),
+ go_incognito_button_(NULL),
+ did_paint_(false),
+ delegate_(NULL),
+ background_area_(NULL) {
+}
+
+void BackgroundView::Init(const GURL& background_url) {
+ views::Painter* painter = CreateBackgroundPainter();
+ set_background(views::Background::CreateBackgroundPainter(true, painter));
+ InitStatusArea();
+ InitInfoLabels();
+ if (!background_url.is_empty()) {
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ background_area_ = new DOMView();
+ AddChildView(background_area_);
+ background_area_->Init(profile, NULL);
+ background_area_->SetVisible(false);
+ background_area_->LoadURL(background_url);
+ }
+}
+
// static
views::Widget* BackgroundView::CreateWindowContainingView(
const gfx::Rect& bounds,
+ const GURL& background_url,
BackgroundView** view) {
ResetXCursor();
WidgetGtk* window = new WidgetGtk(WidgetGtk::TYPE_WINDOW);
window->Init(NULL, bounds);
*view = new BackgroundView();
+ (*view)->Init(background_url);
+
+ if ((*view)->ScreenSaverEnabled())
+ (*view)->ShowScreenSaver();
+
window->SetContentsView(*view);
(*view)->UpdateWindowType();
@@ -78,6 +142,72 @@ void BackgroundView::SetStatusAreaVisible(bool visible) {
status_area_->SetVisible(visible);
}
+void BackgroundView::SetOobeProgressBarVisible(bool visible) {
+ if (!progress_bar_ && visible)
+ InitProgressBar();
+
+ if (progress_bar_)
+ progress_bar_->SetVisible(visible);
+}
+
+bool BackgroundView::IsOobeProgressBarVisible() {
+ return progress_bar_ && progress_bar_->IsVisible();
+}
+
+void BackgroundView::SetOobeProgress(LoginStep step) {
+ DCHECK(step <= PICTURE);
+ if (progress_bar_)
+ progress_bar_->SetProgress(step);
+}
+
+// Toggles GoIncognito button visibility.
+void BackgroundView::SetGoIncognitoButtonVisible(bool visible,
+ Delegate *delegate) {
+ // Set delegate to handle button pressing.
+ delegate_ = delegate;
+ bool currently_visible =
+ go_incognito_button_ && go_incognito_button_->IsVisible();
+ if (currently_visible != visible) {
+ if (!go_incognito_button_) {
+ InitGoIncognitoButton();
+ }
+ go_incognito_button_->SetVisible(visible);
+ }
+}
+
+void BackgroundView::ShowScreenSaver() {
+ SetStatusAreaVisible(false);
+ background_area_->SetVisible(true);
+}
+
+void BackgroundView::HideScreenSaver() {
+ SetStatusAreaVisible(true);
+ // TODO(oshima): we need a way to suspend screen saver
+ // to save power when it's not visible.
+ background_area_->SetVisible(false);
+}
+
+bool BackgroundView::IsScreenSaverVisible() {
+ return ScreenSaverEnabled() && background_area_->IsVisible();
+}
+
+bool BackgroundView::ScreenSaverEnabled() {
+ return background_area_ != NULL;
+}
+
+void BackgroundView::OnOwnerChanged() {
+ if (go_incognito_button_) {
+ // BackgroundView is passed among multiple controllers, so they should
+ // explicitly enable "Go incognito" button if needed.
+ RemoveChildView(go_incognito_button_);
+ delete go_incognito_button_;
+ go_incognito_button_ = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BackgroundView protected:
+
void BackgroundView::Paint(gfx::Canvas* canvas) {
views::View::Paint(canvas);
if (!did_paint_) {
@@ -87,14 +217,19 @@ void BackgroundView::Paint(gfx::Canvas* canvas) {
}
void BackgroundView::Layout() {
- int corner_padding = 5;
- int kInfoLeftPadding = 60;
- int kInfoBottomPadding = 40;
- int kInfoBetweenLinesPadding = 4;
+ const int kCornerPadding = 5;
+ const int kInfoLeftPadding = 60;
+ const int kInfoBottomPadding = 10;
+ const int kInfoBetweenLinesPadding = 4;
+ const int kProgressBarBottomPadding = 20;
+ const int kProgressBarWidth = 750;
+ const int kProgressBarHeight = 70;
+ const int kGoIncognitoButtonBottomPadding = 12;
+ const int kGoIncognitoButtonRightPadding = 12;
gfx::Size status_area_size = status_area_->GetPreferredSize();
status_area_->SetBounds(
- width() - status_area_size.width() - corner_padding,
- corner_padding,
+ width() - status_area_size.width() - kCornerPadding,
+ kCornerPadding,
status_area_size.width(),
status_area_size.height());
gfx::Size version_size = os_version_label_->GetPreferredSize();
@@ -109,8 +244,25 @@ void BackgroundView::Layout() {
boot_times_label_->SetBounds(
kInfoLeftPadding,
height() - (version_size.height() + kInfoBottomPadding),
- width() - 2 * corner_padding,
+ width() - 2 * kCornerPadding,
version_size.height());
+ if (progress_bar_) {
+ progress_bar_->SetBounds(
+ (width() - kProgressBarWidth) / 2,
+ (height() - kProgressBarBottomPadding - kProgressBarHeight),
+ kProgressBarWidth,
+ kProgressBarHeight);
+ }
+ if (go_incognito_button_) {
+ gfx::Size go_button_size = go_incognito_button_->GetPreferredSize();
+ go_incognito_button_->SetBounds(
+ width() - go_button_size.width()- kGoIncognitoButtonRightPadding,
+ height() - go_button_size.height() - kGoIncognitoButtonBottomPadding,
+ go_button_size.width(),
+ go_button_size.height());
+ }
+ if (background_area_)
+ background_area_->SetBounds(this->bounds());
}
void BackgroundView::ChildPreferredSizeChanged(View* child) {
@@ -118,6 +270,12 @@ void BackgroundView::ChildPreferredSizeChanged(View* child) {
SchedulePaint();
}
+void BackgroundView::OnLocaleChanged() {
+ UpdateLocalizedStrings();
+ Layout();
+ SchedulePaint();
+}
+
gfx::NativeWindow BackgroundView::GetNativeWindow() const {
return
GTK_WINDOW(static_cast<WidgetGtk*>(GetWidget())->GetNativeView());
@@ -138,12 +296,6 @@ void BackgroundView::OpenButtonOptions(const views::View* button_view) const {
// TODO(avayvod): Add some dialog for options or remove them completely.
}
-bool BackgroundView::IsButtonVisible(const views::View* button_view) const {
- if (button_view == status_area_->feedback_view())
- return false;
- return true;
-}
-
bool BackgroundView::IsBrowserMode() const {
return false;
}
@@ -152,15 +304,25 @@ bool BackgroundView::IsScreenLockerMode() const {
return false;
}
-void BackgroundView::LocaleChanged() {
- Layout();
- SchedulePaint();
+void BackgroundView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ if (sender == go_incognito_button_) {
+ DCHECK(delegate_);
+ if (delegate_) {
+ delegate_->OnGoIncognitoButton();
+ }
+ }
}
+///////////////////////////////////////////////////////////////////////////////
+// BackgroundView private:
+
void BackgroundView::InitStatusArea() {
DCHECK(status_area_ == NULL);
status_area_ = new StatusAreaView(this);
status_area_->Init();
+ // Feedback button shoudn't be visible on OOBE/login/screen lock.
+ status_area_->feedback_view()->SetVisible(false);
AddChildView(status_area_);
}
@@ -190,6 +352,66 @@ void BackgroundView::InitInfoLabels() {
}
}
+void BackgroundView::InitProgressBar() {
+ std::vector<int> steps;
+ steps.push_back(IDS_OOBE_SELECT_NETWORK);
+#if defined(OFFICIAL_BUILD)
+ steps.push_back(IDS_OOBE_EULA);
+#endif
+ steps.push_back(IDS_OOBE_SIGNIN);
+#if defined(OFFICIAL_BUILD)
+ steps.push_back(IDS_OOBE_REGISTRATION);
+#endif
+ steps.push_back(IDS_OOBE_PICTURE);
+ progress_bar_ = new OobeProgressBar(steps);
+ AddChildView(progress_bar_);
+}
+
+void BackgroundView::InitGoIncognitoButton() {
+ SkColor kButtonColor = 0xFF4F6985;
+ SkColor kStrokeColor = 0xFF657A91;
+ int kStrokeWidth = 1;
+ int kVerticalPadding = 8;
+ int kHorizontalPadding = 12;
+ int kCornerRadius = 4;
+
+ go_incognito_button_ =
+ new TextButtonWithHandCursorOver(this, std::wstring());
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ go_incognito_button_->SetIcon(*rb.GetBitmapNamed(IDR_INCOGNITO_GUY));
+ go_incognito_button_->SetFocusable(true);
+ // Set label colors.
+ go_incognito_button_->SetEnabledColor(SK_ColorWHITE);
+ go_incognito_button_->SetDisabledColor(SK_ColorWHITE);
+ go_incognito_button_->SetHighlightColor(SK_ColorWHITE);
+ go_incognito_button_->SetHoverColor(SK_ColorWHITE);
+ // Disable throbbing and make border always visible.
+ go_incognito_button_->SetAnimationDuration(0);
+ go_incognito_button_->SetNormalHasBorder(true);
+ // Setup round shapes.
+ go_incognito_button_->set_background(
+ CreateRoundedBackground(
+ kCornerRadius, kStrokeWidth, kButtonColor, kStrokeColor));
+
+ go_incognito_button_->set_border(
+ views::Border::CreateEmptyBorder(kVerticalPadding,
+ kHorizontalPadding,
+ kVerticalPadding,
+ kHorizontalPadding));
+ // Set button text.
+ UpdateLocalizedStrings();
+ // Enable and add to the views hierarchy.
+ go_incognito_button_->SetEnabled(true);
+ AddChildView(go_incognito_button_);
+}
+
+void BackgroundView::UpdateLocalizedStrings() {
+ if (go_incognito_button_) {
+ go_incognito_button_->SetText(
+ UTF8ToWide(l10n_util::GetStringUTF8(IDS_GO_INCOGNITO_BUTTON)));
+ }
+}
+
void BackgroundView::UpdateWindowType() {
std::vector<int> params;
params.push_back(did_paint_ ? 1 : 0);
@@ -223,7 +445,7 @@ void BackgroundView::OnBootTimes(
if (boot_times.chrome > 0) {
boot_times_text =
- StringPrintf(
+ base::StringPrintf(
kBootTimesChromeExec,
boot_times.total,
boot_times.firmware,
@@ -232,7 +454,7 @@ void BackgroundView::OnBootTimes(
boot_times.chrome);
} else {
boot_times_text =
- StringPrintf(
+ base::StringPrintf(
kBootTimesNoChromeExec,
boot_times.total,
boot_times.firmware,
diff --git a/chrome/browser/chromeos/login/background_view.h b/chrome/browser/chromeos/login/background_view.h
index f5c4540..9fcad2a 100644
--- a/chrome/browser/chromeos/login/background_view.h
+++ b/chrome/browser/chromeos/login/background_view.h
@@ -4,45 +4,108 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_BACKGROUND_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_BACKGROUND_VIEW_H_
+#pragma once
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/chromeos/version_loader.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
+#include "chrome/browser/chromeos/version_loader.h"
+#include "views/controls/button/button.h"
#include "views/view.h"
namespace views {
class Widget;
class Label;
+class TextButton;
}
+class DOMView;
+class GURL;
class Profile;
namespace chromeos {
+class OobeProgressBar;
class StatusAreaView;
// View used to render the background during login. BackgroundView contains
// StatusAreaView.
-class BackgroundView : public views::View, public StatusAreaHost {
+class BackgroundView : public views::View,
+ public StatusAreaHost,
+ public views::ButtonListener {
public:
+ // Delegate class to handle notificatoin from the view.
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Initializes incognito login.
+ virtual void OnGoIncognitoButton() = 0;
+ };
+
+ enum LoginStep {
+ SELECT_NETWORK,
+#if defined(OFFICIAL_BUILD)
+ EULA,
+#endif
+ SIGNIN,
+#if defined(OFFICIAL_BUILD)
+ REGISTRATION,
+#endif
+ PICTURE
+ };
+
BackgroundView();
+ // Initializes the background view. It backgroun_url is given (non empty),
+ // it creates a DOMView background area that renders a webpage.
+ void Init(const GURL& background_url);
+
// Creates a window containing an instance of WizardContentsView as the root
// view. The caller is responsible for showing (and closing) the returned
- // widget. The BackgroundView is set in |view|.
- static views::Widget* CreateWindowContainingView(const gfx::Rect& bounds,
- BackgroundView** view);
+ // widget. The BackgroundView is set in |view|. If background_url is non
+ // empty, the content page of the url is displayed as a background.
+ static views::Widget* CreateWindowContainingView(
+ const gfx::Rect& bounds,
+ const GURL& background_url,
+ BackgroundView** view);
// Toggles status area visibility.
void SetStatusAreaVisible(bool visible);
+ // Toggles OOBE progress bar visibility, the bar is hidden by default.
+ void SetOobeProgressBarVisible(bool visible);
+
+ // Gets progress bar visibility.
+ bool IsOobeProgressBarVisible();
+
+ // Sets current step on OOBE progress bar.
+ void SetOobeProgress(LoginStep step);
+
+ // Toggles GoIncognito button visibility.
+ void SetGoIncognitoButtonVisible(bool visible, Delegate *delegate);
+
+ // Shows screen saver.
+ void ShowScreenSaver();
+
+ // Hides screen saver.
+ void HideScreenSaver();
+
+ // Tells if screen saver is visible.
+ bool IsScreenSaverVisible();
+
+ // Tells if screen saver is enabled.
+ bool ScreenSaverEnabled();
+
+ // Tells that owner has been changed.
+ void OnOwnerChanged();
+
protected:
// Overridden from views::View:
virtual void Paint(gfx::Canvas* canvas);
virtual void Layout();
virtual void ChildPreferredSizeChanged(View* child);
- virtual void LocaleChanged();
+ virtual void OnLocaleChanged();
// Overridden from StatusAreaHost:
virtual Profile* GetProfile() const { return NULL; }
@@ -51,15 +114,24 @@ class BackgroundView : public views::View, public StatusAreaHost {
virtual bool ShouldOpenButtonOptions(
const views::View* button_view) const;
virtual void OpenButtonOptions(const views::View* button_view) const;
- virtual bool IsButtonVisible(const views::View* button_view) const;
virtual bool IsBrowserMode() const;
virtual bool IsScreenLockerMode() const;
-private:
+ // Overridden from views::ButtonListener.
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+
+ private:
// Creates and adds the status_area.
void InitStatusArea();
// Creates and adds the labels for version and boot time.
void InitInfoLabels();
+ // Creates and add OOBE progress bar.
+ void InitProgressBar();
+ // Creates and add GoIncoginito button.
+ void InitGoIncognitoButton();
+
+ // Updates string from the resources.
+ void UpdateLocalizedStrings();
// Invokes SetWindowType for the window. This is invoked during startup and
// after we've painted.
@@ -71,9 +143,12 @@ private:
void OnBootTimes(
BootTimesLoader::Handle handle, BootTimesLoader::BootTimes boot_times);
+ // All of these variables could be NULL.
StatusAreaView* status_area_;
views::Label* os_version_label_;
views::Label* boot_times_label_;
+ OobeProgressBar* progress_bar_;
+ views::TextButton* go_incognito_button_;
// Handles asynchronously loading the version.
VersionLoader version_loader_;
@@ -90,6 +165,11 @@ private:
// TODO(sky): nuke this when the wm knows when chrome has painted.
bool did_paint_;
+ Delegate *delegate_;
+
+ // DOMView for rendering a webpage as a background.
+ DOMView* background_area_;
+
DISALLOW_COPY_AND_ASSIGN(BackgroundView);
};
diff --git a/chrome/browser/chromeos/login/camera.cc b/chrome/browser/chromeos/login/camera.cc
index db0fde7..8e1bef6 100644
--- a/chrome/browser/chromeos/login/camera.cc
+++ b/chrome/browser/chromeos/login/camera.cc
@@ -21,6 +21,7 @@
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "gfx/size.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -242,7 +243,7 @@ void Camera::StopCapturing() {
int Camera::OpenDevice(const char* device_name) const {
struct stat st;
if (stat(device_name, &st) == -1) {
- log_errno(StringPrintf("Cannot identify %s", device_name));
+ log_errno(base::StringPrintf("Cannot identify %s", device_name));
return -1;
}
if (!S_ISCHR(st.st_mode)) {
@@ -251,7 +252,7 @@ int Camera::OpenDevice(const char* device_name) const {
}
int fd = open(device_name, O_RDWR | O_NONBLOCK, 0);
if (fd == -1) {
- log_errno(StringPrintf("Cannot open %s", device_name));
+ log_errno(base::StringPrintf("Cannot open %s", device_name));
return -1;
}
return fd;
diff --git a/chrome/browser/chromeos/login/camera.h b/chrome/browser/chromeos/login/camera.h
index 0acfecd..eb4498c 100644
--- a/chrome/browser/chromeos/login/camera.h
+++ b/chrome/browser/chromeos/login/camera.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_CAMERA_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/chromeos/login/captcha_view.h b/chrome/browser/chromeos/login/captcha_view.h
index 872729a..491c438 100644
--- a/chrome/browser/chromeos/login/captcha_view.h
+++ b/chrome/browser/chromeos/login/captcha_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_CAPTCHA_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_CAPTCHA_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/client_login_response_handler.h b/chrome/browser/chromeos/login/client_login_response_handler.h
index c0f1227..8fc1fe1 100644
--- a/chrome/browser/chromeos/login/client_login_response_handler.h
+++ b/chrome/browser/chromeos/login/client_login_response_handler.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_CLIENT_LOGIN_RESPONSE_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_CLIENT_LOGIN_RESPONSE_HANDLER_H_
+#pragma once
#include <string>
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "chrome/browser/chromeos/login/auth_response_handler.h"
class URLRequestContextGetter;
diff --git a/chrome/browser/chromeos/login/cookie_fetcher.cc b/chrome/browser/chromeos/login/cookie_fetcher.cc
index 48c7dec..0ea3c74 100644
--- a/chrome/browser/chromeos/login/cookie_fetcher.cc
+++ b/chrome/browser/chromeos/login/cookie_fetcher.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/chromeos/login/cookie_fetcher.h"
#include "base/command_line.h"
-#include "base/file_path.h"
#include "base/path_service.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/client_login_response_handler.h"
diff --git a/chrome/browser/chromeos/login/cookie_fetcher.h b/chrome/browser/chromeos/login/cookie_fetcher.h
index ef82d55..4c6d66a 100644
--- a/chrome/browser/chromeos/login/cookie_fetcher.h
+++ b/chrome/browser/chromeos/login/cookie_fetcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_COOKIE_FETCHER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_COOKIE_FETCHER_H_
+#pragma once
#include <string>
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc b/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc
index d068007..b5e3a4f 100644
--- a/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc
+++ b/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc
@@ -5,16 +5,17 @@
#include <errno.h>
#include <string>
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/login/cookie_fetcher.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/login/client_login_response_handler.h"
+#include "chrome/browser/chromeos/login/cookie_fetcher.h"
#include "chrome/browser/chromeos/login/issue_response_handler.h"
#include "chrome/browser/chromeos/login/mock_auth_response_handler.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/test/testing_profile.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_status.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
using ::testing::Return;
diff --git a/chrome/browser/chromeos/login/eula_view.cc b/chrome/browser/chromeos/login/eula_view.cc
index 2efe93f..b9e7b2a 100644
--- a/chrome/browser/chromeos/login/eula_view.cc
+++ b/chrome/browser/chromeos/login/eula_view.cc
@@ -10,42 +10,55 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/basictypes.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/customization_document.h"
+#include "chrome/browser/chromeos/login/help_app_launcher.h"
#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
-#include "chrome/browser/chromeos/login/screen_observer.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/options_util.h"
+#include "chrome/browser/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"
+#include "chrome/common/native_web_keyboard_event.h"
+#include "chrome/common/url_constants.h"
#include "chrome/installer/util/google_update_settings.h"
+#include "cros/chromeos_cryptohome.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
-#include "views/controls/textfield/textfield.h"
#include "views/grid_layout.h"
+#include "views/layout_manager.h"
#include "views/standard_layout.h"
+#include "views/widget/widget_gtk.h"
+#include "views/window/dialog_delegate.h"
+#include "views/window/window.h"
+
+#if defined(USE_LINUX_BREAKPAD)
+#include "chrome/app/breakpad_linux.h"
+#endif
+
+using views::WidgetGtk;
namespace {
const int kBorderSize = 10;
const int kMargin = 20;
const int kLastButtonHorizontalMargin = 10;
-const int kTextMargin = 10;
const int kCheckBowWidth = 22;
+const int kTextMargin = 10;
-// Fake EULA texts. TODO(glotov): implement reading actual file.
-const wchar_t kLoremIpsum[] = L"Lorem ipsum dolor sit amet, "
- L"consectetur adipisicing elit, sed do eiusmod tempor incididunt ut"
- L"labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud "
- L"exercitation ullamco laboris nisi ut aliquip ex ea commodo "
- L"consequat. Duis aute irure dolor in reprehenderit in voluptate velit "
- L"esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat "
- L"cupidatat non proident, sunt in culpa qui officia deserunt mollit anim "
- L"id est laborum.\n";
-const wchar_t kFakeGoogleEula[] = L"\nGoogle Chrome Terms of Service\n"
- L"These Terms of Service apply to the executable code version of "
- L"Google Chrome. ";
-const wchar_t kFakeOemEula[] = L"\nYBH Terms of Service\n";
+// TODO(glotov): this URL should be changed to actual Google ChromeOS EULA.
+// See crbug.com/4647
+const char kGoogleEulaUrl[] = "about:terms";
enum kLayoutColumnsets {
SINGLE_CONTROL_ROW,
@@ -54,35 +67,106 @@ enum kLayoutColumnsets {
LAST_ROW
};
+// A simple LayoutManager that causes the associated view's one child to be
+// sized to match the bounds of its parent except the bounds, if set.
+struct FillLayoutWithBorder : public views::LayoutManager {
+ // Overridden from LayoutManager:
+ virtual void Layout(views::View* host) {
+ DCHECK(host->GetChildViewCount());
+ host->GetChildViewAt(0)->SetBounds(host->GetLocalBounds(false));
+ }
+ virtual gfx::Size GetPreferredSize(views::View* host) {
+ return gfx::Size(host->width(), host->height());
+ }
+};
+
+// System security setting dialog.
+class TpmInfoView : public views::View,
+ public views::DialogDelegate {
+ public:
+ explicit TpmInfoView(std::wstring password) : password_(password) { }
+ void Init();
+
+ protected:
+ // views::DialogDelegate overrides:
+ virtual bool Accept() { return true; }
+ virtual bool IsModal() const { return true; }
+ virtual views::View* GetContentsView() { return this; }
+ virtual int GetDialogButtons() const {
+ return MessageBoxFlags::DIALOGBUTTON_OK;
+ }
+
+ // views::View overrides:
+ virtual std::wstring GetWindowTitle() const {
+ return l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTING);
+ }
+
+ gfx::Size GetPreferredSize() {
+ return gfx::Size(views::Window::GetLocalizedContentsSize(
+ IDS_TPM_INFO_DIALOG_WIDTH_CHARS,
+ IDS_TPM_INFO_DIALOG_HEIGHT_LINES));
+ }
+
+ private:
+ std::wstring password_;
+ DISALLOW_COPY_AND_ASSIGN(TpmInfoView);
+};
+
+void TpmInfoView::Init() {
+ views::GridLayout* layout = CreatePanelGridLayout(this);
+ SetLayoutManager(layout);
+ views::ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
+ layout->StartRow(0, 0);
+ views::Label* label = new views::Label(
+ l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTING_DESCRIPTION));
+ label->SetMultiLine(true);
+ layout->AddView(label);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+
+ column_set = layout->AddColumnSet(1);
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
+ layout->StartRow(0, 1);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ gfx::Font password_font =
+ rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::BOLD);
+ label = new views::Label(password_, password_font);
+ layout->AddView(label);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+}
+
} // namespace
namespace chromeos {
+////////////////////////////////////////////////////////////////////////////////
+// EulaView, public:
+
EulaView::EulaView(chromeos::ScreenObserver* observer)
- : google_eula_text_(NULL),
+ : google_eula_label_(NULL),
+ google_eula_view_(NULL),
usage_statistics_checkbox_(NULL),
learn_more_link_(NULL),
- oem_eula_text_(NULL),
+ oem_eula_label_(NULL),
+ oem_eula_view_(NULL),
system_security_settings_link_(NULL),
- cancel_button_(NULL),
+ back_button_(NULL),
continue_button_(NULL),
- observer_(observer) {
+ observer_(observer),
+ bubble_(NULL) {
}
EulaView::~EulaView() {
+ // bubble_ will be set to NULL in callback.
+ if (bubble_)
+ bubble_->Close();
}
-void EulaView::Init() {
- // Use rounded rect background.
- views::Painter* painter = CreateWizardPainter(
- &BorderDefinition::kScreenBorder);
- set_background(
- views::Background::CreateBackgroundPainter(true, painter));
-
- // Layout created controls.
+// Convenience function to set layout's columnsets for this screen.
+static void SetUpGridLayout(views::GridLayout* layout) {
static const int kPadding = kBorderSize + kMargin;
- views::GridLayout* layout = new views::GridLayout(this);
- SetLayoutManager(layout);
views::ColumnSet* column_set = layout->AddColumnSet(SINGLE_CONTROL_ROW);
column_set->AddPaddingColumn(0, kPadding);
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
@@ -111,21 +195,77 @@ void EulaView::Init() {
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
views::GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, kLastButtonHorizontalMargin + kBorderSize);
+}
+
+// Convenience function. Returns URL of the OEM EULA page that should be
+// displayed using current locale and manifest. Returns empty URL otherwise.
+static GURL GetOemEulaPagePath() {
+ const StartupCustomizationDocument *customization =
+ WizardController::default_controller()->GetCustomization();
+ if (customization) {
+ std::string locale = g_browser_process->GetApplicationLocale();
+ FilePath eula_page_path = customization->GetEULAPagePath(locale);
+ if (eula_page_path.empty()) {
+ LOG(INFO) << "No eula found for locale: " << locale;
+ locale = customization->initial_locale();
+ eula_page_path = customization->GetEULAPagePath(locale);
+ }
+ if (!eula_page_path.empty()) {
+ const std::string page_path = std::string(chrome::kFileScheme) +
+ chrome::kStandardSchemeSeparator + eula_page_path.value();
+ return GURL(page_path);
+ } else {
+ LOG(INFO) << "No eula found for locale: " << locale;
+ }
+ } else {
+ LOG(ERROR) << "No manifest found.";
+ }
+ return GURL();
+}
+
+void EulaView::Init() {
+ // Use rounded rect background.
+ views::Painter* painter = CreateWizardPainter(
+ &BorderDefinition::kScreenBorder);
+ set_background(
+ views::Background::CreateBackgroundPainter(true, painter));
+ // Layout created controls.
+ views::GridLayout* layout = new views::GridLayout(this);
+ SetLayoutManager(layout);
+ SetUpGridLayout(layout);
+
+ static const int kPadding = kBorderSize + kMargin;
layout->AddPaddingRow(0, kPadding);
+ layout->StartRow(0, SINGLE_CONTROL_ROW);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ gfx::Font label_font =
+ rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::NORMAL);
+ google_eula_label_ = new views::Label(std::wstring(), label_font);
+ layout->AddView(google_eula_label_, 1, 1,
+ views::GridLayout::LEADING, views::GridLayout::FILL);
+
+ layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
layout->StartRow(1, SINGLE_CONTROL_ROW);
- google_eula_text_ = new views::Textfield(views::Textfield::STYLE_MULTILINE);
- google_eula_text_->SetReadOnly(true);
- google_eula_text_->SetFocusable(true);
- google_eula_text_->SetHorizontalMargins(kTextMargin, kTextMargin);
- layout->AddView(google_eula_text_);
+ views::View* box_view = new views::View();
+ box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
+ box_view->SetLayoutManager(new FillLayoutWithBorder());
+ layout->AddView(box_view);
+ google_eula_view_ = new DOMView();
+ box_view->AddChildView(google_eula_view_);
+
+ layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
layout->StartRow(0, SINGLE_CONTROL_WITH_SHIFT_ROW);
usage_statistics_checkbox_ = new views::Checkbox();
usage_statistics_checkbox_->SetMultiLine(true);
- usage_statistics_checkbox_->SetChecked(
- GoogleUpdateSettings::GetCollectStatsConsent());
+
+ // TODO(zelidrag): http://crosbug/6367 - Change default settings for checked
+ // and enabled state of usage_statistics_checkbox_ before the product is
+ // released.
+ usage_statistics_checkbox_->SetChecked(true);
layout->AddView(usage_statistics_checkbox_);
+ usage_statistics_checkbox_->SetEnabled(false);
layout->StartRow(0, SINGLE_LINK_WITH_SHIFT_ROW);
learn_more_link_ = new views::Link();
@@ -133,22 +273,37 @@ void EulaView::Init() {
layout->AddView(learn_more_link_);
layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
- layout->StartRow(1, SINGLE_CONTROL_ROW);
- oem_eula_text_ = new views::Textfield(views::Textfield::STYLE_MULTILINE);
- oem_eula_text_->SetReadOnly(true);
- oem_eula_text_->SetFocusable(true);
- oem_eula_text_->SetHorizontalMargins(kTextMargin, kTextMargin);
- layout->AddView(oem_eula_text_);
+ layout->StartRow(0, SINGLE_CONTROL_ROW);
+ oem_eula_label_ = new views::Label(std::wstring(), label_font);
+ layout->AddView(oem_eula_label_, 1, 1,
+ views::GridLayout::LEADING, views::GridLayout::FILL);
+
+ oem_eula_page_ = GetOemEulaPagePath();
+ if (!oem_eula_page_.is_empty()) {
+ layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
+ layout->StartRow(1, SINGLE_CONTROL_ROW);
+ box_view = new views::View();
+ box_view->SetLayoutManager(new FillLayoutWithBorder());
+ box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
+ layout->AddView(box_view);
+
+ oem_eula_view_ = new DOMView();
+ box_view->AddChildView(oem_eula_view_);
+ }
- layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, LAST_ROW);
system_security_settings_link_ = new views::Link();
system_security_settings_link_->SetController(this);
+ if (!chromeos::CrosLibrary::Get()->EnsureLoaded() ||
+ !chromeos::CryptohomeTpmIsEnabled()) {
+ system_security_settings_link_->SetEnabled(false);
+ // TODO(glotov): add tooltip with description.
+ }
layout->AddView(system_security_settings_link_);
- cancel_button_ = new views::NativeButton(this, std::wstring());
- cancel_button_->SetEnabled(false);
- layout->AddView(cancel_button_);
+ back_button_ = new views::NativeButton(this, std::wstring());
+ layout->AddView(back_button_);
continue_button_ = new views::NativeButton(this, std::wstring());
layout->AddView(continue_button_);
@@ -158,28 +313,36 @@ void EulaView::Init() {
}
void EulaView::UpdateLocalizedStrings() {
- google_eula_text_->SetText(WideToUTF16(kFakeGoogleEula) +
- WideToUTF16(kLoremIpsum) +
- WideToUTF16(kLoremIpsum));
- oem_eula_text_->SetText(WideToUTF16(kFakeOemEula) +
- WideToUTF16(kLoremIpsum) +
- WideToUTF16(kLoremIpsum));
+ // Load Google EULA and its title.
+ LoadEulaView(google_eula_view_, google_eula_label_, GURL(kGoogleEulaUrl));
+
+ // Load OEM EULA and its title.
+ if (!oem_eula_page_.is_empty())
+ LoadEulaView(oem_eula_view_, oem_eula_label_, oem_eula_page_);
+
+ // Set tooltip for usage statistics checkbox if the metric is unmanaged.
+ if (!usage_statistics_checkbox_->IsEnabled()) {
+ usage_statistics_checkbox_->SetTooltipText(
+ l10n_util::GetString(IDS_OPTION_DISABLED_BY_POLICY));
+ }
+
+ // Load other labels from resources.
usage_statistics_checkbox_->SetLabel(
l10n_util::GetString(IDS_EULA_CHECKBOX_ENABLE_LOGGING));
learn_more_link_->SetText(
l10n_util::GetString(IDS_LEARN_MORE));
system_security_settings_link_->SetText(
- l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTINGS_LINK));
+ l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTING));
continue_button_->SetLabel(
l10n_util::GetString(IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON));
- cancel_button_->SetLabel(
- l10n_util::GetString(IDS_CANCEL));
+ back_button_->SetLabel(
+ l10n_util::GetString(IDS_ACCNAME_BACK));
}
////////////////////////////////////////////////////////////////////////////////
-// views::View: implementation:
+// EulaView, protected, views::View implementation:
-void EulaView::LocaleChanged() {
+void EulaView::OnLocaleChanged() {
UpdateLocalizedStrings();
Layout();
}
@@ -190,19 +353,114 @@ void EulaView::LocaleChanged() {
void EulaView::ButtonPressed(views::Button* sender, const views::Event& event) {
if (sender == continue_button_) {
if (usage_statistics_checkbox_) {
- GoogleUpdateSettings::SetCollectStatsConsent(
- usage_statistics_checkbox_->checked());
+ bool enable_reporting = usage_statistics_checkbox_->checked();
+ enable_reporting =
+ OptionsUtil::ResolveMetricsReportingEnabled(enable_reporting);
+#if defined(USE_LINUX_BREAKPAD)
+ if (enable_reporting)
+ InitCrashReporter();
+#endif
}
observer_->OnExit(ScreenObserver::EULA_ACCEPTED);
+ } else if (sender == back_button_) {
+ observer_->OnExit(ScreenObserver::EULA_BACK);
}
- // TODO(glotov): handle cancel button.
}
////////////////////////////////////////////////////////////////////////////////
// views::LinkController implementation:
void EulaView::LinkActivated(views::Link* source, int event_flags) {
- // TODO(glotov): handle link clicks.
+ if (source == learn_more_link_) {
+ if (!help_app_.get())
+ help_app_.reset(new HelpAppLauncher(GetNativeWindow()));
+ help_app_->ShowHelpTopic(HelpAppLauncher::HELP_STATS_USAGE);
+ } else if (source == system_security_settings_link_) {
+ // Pull the password from TPM.
+ std::string password;
+ if (!chromeos::CrosLibrary::Get()->EnsureLoaded()) {
+ LOG(ERROR) << "Cros library not loaded. "
+ << "We must have disabled the link that led here.";
+ return;
+ } else if (chromeos::CryptohomeTpmIsReady() &&
+ chromeos::CryptohomeTpmGetPassword(&password)) {
+ TpmInfoView* view = new TpmInfoView(ASCIIToWide(password));
+ view->Init();
+ views::Window* window = views::Window::CreateChromeWindow(
+ GetNativeWindow(), gfx::Rect(), view);
+ window->SetIsAlwaysOnTop(true);
+ window->Show();
+ } else {
+ if (!bubble_)
+ bubble_ = MessageBubble::Show(
+ system_security_settings_link_->GetWidget(),
+ system_security_settings_link_->GetScreenBounds(),
+ BubbleBorder::LEFT_TOP,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
+ l10n_util::GetString(IDS_EULA_TPM_BUSY),
+ std::wstring(), this);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TabContentsDelegate implementation:
+
+// Convenience function. Queries |eula_view| for HTML title and, if it
+// is ready, assigns it to |eula_label| and returns true so the caller
+// view calls Layout().
+static bool PublishTitleIfReady(const TabContents* contents,
+ DOMView* eula_view,
+ views::Label* eula_label) {
+ if (contents != eula_view->tab_contents())
+ return false;
+ eula_label->SetText(UTF16ToWide(eula_view->tab_contents()->GetTitle()));
+ return true;
+}
+
+void EulaView::NavigationStateChanged(const TabContents* contents,
+ unsigned changed_flags) {
+ if (changed_flags & TabContents::INVALIDATE_TITLE) {
+ if (PublishTitleIfReady(contents, google_eula_view_, google_eula_label_) ||
+ PublishTitleIfReady(contents, oem_eula_view_, oem_eula_label_)) {
+ Layout();
+ }
+ }
+}
+
+void EulaView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
+ views::Widget* widget = GetWidget();
+ if (widget && event.os_event && !event.skip_in_browser)
+ static_cast<views::WidgetGtk*>(widget)->HandleKeyboardEvent(event.os_event);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// EulaView, private:
+
+gfx::NativeWindow EulaView::GetNativeWindow() const {
+ return GTK_WINDOW(static_cast<WidgetGtk*>(GetWidget())->GetNativeView());
+}
+
+void EulaView::LoadEulaView(DOMView* eula_view,
+ views::Label* eula_label,
+ const GURL& eula_url) {
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ eula_view->Init(profile,
+ SiteInstance::CreateSiteInstanceForURL(profile, eula_url));
+ eula_view->LoadURL(eula_url);
+ eula_view->tab_contents()->set_delegate(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// EulaView, private, views::View implementation:
+
+bool EulaView::OnKeyPressed(const views::KeyEvent&) {
+ // Close message bubble if shown. bubble_ will be set to NULL in callback.
+ if (bubble_) {
+ bubble_->Close();
+ return true;
+ }
+ return false;
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/eula_view.h b/chrome/browser/chromeos/login/eula_view.h
index 9e7c112..ca40400 100644
--- a/chrome/browser/chromeos/login/eula_view.h
+++ b/chrome/browser/chromeos/login/eula_view.h
@@ -4,10 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EULA_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_EULA_VIEW_H_
+#pragma once
-#include <string>
-
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/view_screen.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "gfx/native_widget_types.h"
#include "views/controls/button/button.h"
#include "views/controls/link.h"
#include "views/view.h"
@@ -18,16 +21,63 @@ class Checkbox;
class Label;
class Link;
class NativeButton;
-class Textfield;
} // namespace views
+class DOMView;
+
namespace chromeos {
+class HelpAppLauncher;
+
+// Delegate for TabContents that will show EULA.
+// Blocks context menu and other actions.
+class EULATabContentsDelegate : public TabContentsDelegate {
+ public:
+ EULATabContentsDelegate() {}
+ virtual ~EULATabContentsDelegate() {}
+
+ protected:
+ // TabContentsDelegate implementation:
+ virtual void OpenURLFromTab(TabContents* source,
+ const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {}
+ virtual void NavigationStateChanged(const TabContents* source,
+ unsigned changed_flags) {}
+ virtual void AddNewContents(TabContents* source,
+ TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {}
+ virtual void ActivateContents(TabContents* contents) {}
+ virtual void DeactivateContents(TabContents* contents) {}
+ virtual void LoadingStateChanged(TabContents* source) {}
+ virtual void CloseContents(TabContents* source) {}
+ virtual bool IsPopup(TabContents* source) { return false; }
+ virtual void URLStarredChanged(TabContents* source, bool starred) {}
+ virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
+ virtual bool ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type) {
+ return false;
+ }
+ virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
+ virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
+ virtual bool HandleContextMenu(const ContextMenuParams& params) {
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EULATabContentsDelegate);
+};
+
class EulaView
: public views::View,
public views::ButtonListener,
- public views::LinkController {
+ public views::LinkController,
+ public MessageBubbleDelegate,
+ public EULATabContentsDelegate {
public:
explicit EulaView(chromeos::ScreenObserver* observer);
virtual ~EulaView();
@@ -40,7 +90,7 @@ class EulaView
protected:
// views::View implementation.
- virtual void LocaleChanged();
+ virtual void OnLocaleChanged();
// views::ButtonListener implementation.
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
@@ -49,17 +99,55 @@ class EulaView
void LinkActivated(views::Link* source, int event_flags);
private:
+ // views::View implementation.
+ virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
+ return true; }
+ virtual bool OnKeyPressed(const views::KeyEvent& e);
+
+ // TabContentsDelegate implementation.
+ virtual void NavigationStateChanged(const TabContents* contents,
+ unsigned changed_flags);
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
+
+ // Returns corresponding native window.
+ gfx::NativeWindow GetNativeWindow() const;
+
+ // Loads specified URL to the specified DOMView and updates specified
+ // label with its title.
+ void LoadEulaView(DOMView* eula_view,
+ views::Label* eula_label,
+ const GURL& eula_url);
+
+ // Overridden from views::InfoBubbleDelegate.
+ virtual void InfoBubbleClosing(InfoBubble* info_bubble,
+ bool closed_by_escape) { bubble_ = NULL; }
+ virtual bool CloseOnEscape() { return true; }
+ virtual bool FadeInOnShow() { return false; }
+ virtual void OnHelpLinkActivated() {}
+
// Dialog controls.
- views::Textfield* google_eula_text_;
+ views::Label* google_eula_label_;
+ DOMView* google_eula_view_;
views::Checkbox* usage_statistics_checkbox_;
views::Link* learn_more_link_;
- views::Textfield* oem_eula_text_;
+ views::Label* oem_eula_label_;
+ DOMView* oem_eula_view_;
views::Link* system_security_settings_link_;
- views::NativeButton* cancel_button_;
+ views::NativeButton* back_button_;
views::NativeButton* continue_button_;
chromeos::ScreenObserver* observer_;
+ // URL of the OEM EULA page (on disk).
+ GURL oem_eula_page_;
+
+ // Help application used for help dialogs.
+ scoped_ptr<HelpAppLauncher> help_app_;
+
+ // Pointer to shown message bubble. We don't need to delete it because
+ // it will be deleted on bubble closing.
+ MessageBubble* bubble_;
+
DISALLOW_COPY_AND_ASSIGN(EulaView);
};
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 5e6abeb..e8a609d 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -10,25 +10,27 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_thread.h"
+#include "base/values.h"
#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/cros/network_library.h"
-#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/cros_settings_provider_user.h"
#include "chrome/browser/chromeos/login/background_view.h"
+#include "chrome/browser/chromeos/login/help_app_launcher.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "gfx/native_widget_types.h"
+#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/screen.h"
#include "views/widget/widget_gtk.h"
@@ -40,20 +42,14 @@ namespace {
// Max number of users we'll show. The true max is the min of this and the
// number of windows that fit on the screen.
-const size_t kMaxUsers = 6;
+const size_t kMaxUsers = 5;
// Used to indicate no user has been selected.
const size_t kNotSelected = -1;
-// ClientLogin response parameters.
-const char kError[] = "Error=";
-const char kCaptchaError[] = "CaptchaRequired";
-const char kCaptchaUrlParam[] = "CaptchaUrl=";
-const char kCaptchaTokenParam[] = "CaptchaToken=";
-const char kParamSuffix[] = "\n";
-
-// URL prefix for CAPTCHA image.
-const char kCaptchaUrlPrefix[] = "http://www.google.com/accounts/";
+// Offset of cursor in first position from edit left side. It's used to position
+// info bubble arrow to cursor.
+const int kCursorOffset = 5;
// Checks if display names are unique. If there are duplicates, enables
// tooltips with full emails to let users distinguish their accounts.
@@ -65,14 +61,30 @@ void EnableTooltipsIfNeeded(const std::vector<UserController*>& controllers) {
controllers[i]->user().GetDisplayName();
++visible_display_names[display_name];
}
- for (size_t i = 0; i + 1 < controllers.size(); ++i) {
+ for (size_t i = 0; i < controllers.size(); ++i) {
const std::string& display_name =
controllers[i]->user().GetDisplayName();
- bool show_tooltip = visible_display_names[display_name] > 1;
+ bool show_tooltip = controllers[i]->is_new_user() ||
+ controllers[i]->is_bwsi() ||
+ visible_display_names[display_name] > 1;
controllers[i]->EnableNameTooltip(show_tooltip);
}
}
+// Returns true if given email is in user whitelist.
+// Note this function is for display purpose only and should use
+// CheckWhitelist op for the real whitelist check.
+bool IsEmailInCachedWhitelist(const std::string& email) {
+ StringValue email_value(email);
+ const ListValue* whitelist = UserCrosSettingsProvider::cached_whitelist();
+ for (ListValue::const_iterator i(whitelist->begin());
+ i != whitelist->end(); ++i) {
+ if ((*i)->Equals(&email_value))
+ return true;
+ }
+ return false;
+}
+
} // namespace
ExistingUserController*
@@ -85,38 +97,66 @@ ExistingUserController::ExistingUserController(
background_window_(NULL),
background_view_(NULL),
selected_view_index_(kNotSelected),
+ num_login_attempts_(0),
bubble_(NULL) {
if (delete_scheduled_instance_)
delete_scheduled_instance_->Delete();
// Caclulate the max number of users from available screen size.
- size_t max_users = kMaxUsers;
- int screen_width = background_bounds.width();
- if (screen_width > 0) {
- max_users = std::max(static_cast<size_t>(2), std::min(kMaxUsers,
- static_cast<size_t>((screen_width - login::kUserImageSize)
- / (UserController::kUnselectedSize +
- UserController::kPadding))));
+ if (UserCrosSettingsProvider::cached_show_users_on_signin()) {
+ size_t max_users = kMaxUsers;
+ int screen_width = background_bounds.width();
+ if (screen_width > 0) {
+ max_users = std::max(static_cast<size_t>(2), std::min(kMaxUsers,
+ static_cast<size_t>((screen_width - login::kUserImageSize)
+ / (UserController::kUnselectedSize +
+ UserController::kPadding))));
+ }
+
+ size_t visible_users_count = std::min(users.size(), max_users - 1);
+ for (size_t i = 0; i < users.size(); ++i) {
+ if (controllers_.size() == visible_users_count)
+ break;
+
+ // TODO(xiyuan): Clean user profile whose email is not in whitelist.
+ if (UserCrosSettingsProvider::cached_allow_guest() ||
+ IsEmailInCachedWhitelist(users[i].email())) {
+ controllers_.push_back(new UserController(this, users[i]));
+ }
+ }
}
- size_t visible_users_count = std::min(users.size(), max_users - 1);
- for (size_t i = 0; i < visible_users_count; ++i)
- controllers_.push_back(new UserController(this, users[i]));
+ if (!controllers_.empty() && UserCrosSettingsProvider::cached_allow_bwsi())
+ controllers_.push_back(new UserController(this, true));
- // Add the view representing the guest user last.
- controllers_.push_back(new UserController(this));
+ // Add the view representing the new user.
+ controllers_.push_back(new UserController(this, false));
}
void ExistingUserController::Init() {
if (!background_window_) {
+ std::string url_string =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kScreenSaverUrl);
+
background_window_ = BackgroundView::CreateWindowContainingView(
background_bounds_,
+ GURL(url_string),
&background_view_);
+
+ if (!WizardController::IsDeviceRegistered()) {
+ background_view_->SetOobeProgressBarVisible(true);
+ background_view_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
+ }
+
background_window_->Show();
}
+ // If there's only new user pod, show BWSI link on it.
+ bool show_bwsi_link = controllers_.size() == 1;
for (size_t i = 0; i < controllers_.size(); ++i) {
(controllers_[i])->Init(static_cast<int>(i),
- static_cast<int>(controllers_.size()));
+ static_cast<int>(controllers_.size()),
+ show_bwsi_link);
}
EnableTooltipsIfNeeded(controllers_);
@@ -133,6 +173,28 @@ void ExistingUserController::OwnBackground(
DCHECK(!background_window_);
background_window_ = background_widget;
background_view_ = background_view;
+ background_view_->OnOwnerChanged();
+}
+
+void ExistingUserController::LoginNewUser(const std::string& username,
+ const std::string& password) {
+ SelectNewUser();
+ UserController* new_user = controllers_.back();
+ 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();
+}
+
+void ExistingUserController::SelectNewUser() {
+ SelectUser(controllers_.size() - 1);
}
ExistingUserController::~ExistingUserController() {
@@ -171,33 +233,47 @@ void ExistingUserController::Login(UserController* source,
std::vector<UserController*>::const_iterator i =
std::find(controllers_.begin(), controllers_.end(), source);
DCHECK(i != controllers_.end());
- selected_view_index_ = i - controllers_.begin();
-
- authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
- Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(authenticator_.get(),
- &Authenticator::AuthenticateToLogin,
- profile,
- controllers_[selected_view_index_]->user().email(),
- UTF16ToUTF8(password),
- login_token_,
- login_captcha_));
+
+ if (i == controllers_.begin() + selected_view_index_) {
+ num_login_attempts_++;
+ } else {
+ selected_view_index_ = i - controllers_.begin();
+ num_login_attempts_ = 0;
+ }
// Disable clicking on other windows.
SendSetLoginState(false);
+
+ // Use the same LoginPerformer for subsequent login as it has state
+ // such as CAPTCHA challenge token & corresponding user input.
+ if (!login_performer_.get() || num_login_attempts_ <= 1) {
+ login_performer_.reset(new LoginPerformer(this));
+ }
+ login_performer_->Login(controllers_[selected_view_index_]->user().email(),
+ UTF16ToUTF8(password));
+}
+
+void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
+ ShowError(IDS_LOGIN_ERROR_WHITELIST, email);
+
+ // Reenable userview and use ClearAndEnablePassword to keep username on
+ // screen with the error bubble.
+ controllers_[selected_view_index_]->ClearAndEnablePassword();
+
+ // Reenable clicking on other windows.
+ SendSetLoginState(true);
}
void ExistingUserController::LoginOffTheRecord() {
- authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(authenticator_.get(),
- &Authenticator::LoginOffTheRecord));
+ // Check allow_bwsi in case this call is fired from key accelerator.
+ if (!UserCrosSettingsProvider::cached_allow_bwsi())
+ return;
// Disable clicking on other windows.
SendSetLoginState(false);
+
+ login_performer_.reset(new LoginPerformer(this));
+ login_performer_->LoginOffTheRecord();
}
void ExistingUserController::ClearErrors() {
@@ -213,8 +289,9 @@ void ExistingUserController::OnUserSelected(UserController* source) {
size_t new_selected_index = i - controllers_.begin();
if (new_selected_index != selected_view_index_ &&
selected_view_index_ != kNotSelected) {
- controllers_[selected_view_index_]->ClearAndEnablePassword();
- ClearCaptchaState();
+ controllers_[selected_view_index_]->ClearAndEnableFields();
+ login_performer_.reset(NULL);
+ num_login_attempts_ = 0;
}
selected_view_index_ = new_selected_index;
}
@@ -222,13 +299,15 @@ void ExistingUserController::OnUserSelected(UserController* source) {
void ExistingUserController::ActivateWizard(const std::string& screen_name) {
// WizardController takes care of deleting itself when done.
WizardController* controller = new WizardController();
- controller->Init(screen_name, background_bounds_);
- controller->Show();
// Give the background window to the controller.
controller->OwnBackground(background_window_, background_view_);
background_window_ = NULL;
+ controller->Init(screen_name, background_bounds_);
+ controller->set_start_url(start_url_);
+ controller->Show();
+
// And schedule us for deletion. We delay for a second as the window manager
// is doing an animation with our windows.
DCHECK(!delete_scheduled_instance_);
@@ -242,14 +321,18 @@ void ExistingUserController::RemoveUser(UserController* source) {
UserManager::Get()->RemoveUser(source->user().email());
- // We need to unmap entry windows, the windows will be unmapped in destructor.
controllers_.erase(controllers_.begin() + source->user_index());
- delete source;
EnableTooltipsIfNeeded(controllers_);
+
+ // Update user count before unmapping windows, otherwise window manager won't
+ // be in the right state.
int new_size = static_cast<int>(controllers_.size());
for (int i = 0; i < new_size; ++i)
controllers_[i]->UpdateUserCount(i, new_size);
+
+ // We need to unmap entry windows, the windows will be unmapped in destructor.
+ delete source;
}
void ExistingUserController::SelectUser(int index) {
@@ -261,9 +344,12 @@ void ExistingUserController::SelectUser(int index) {
}
}
-void ExistingUserController::OnLoginFailure(const std::string& error) {
- LOG(INFO) << "OnLoginFailure";
- ClearCaptchaState();
+void ExistingUserController::OnGoIncognitoButton() {
+ LoginOffTheRecord();
+}
+
+void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
+ std::string error = failure.GetErrorString();
// Check networking after trying to login in case user is
// cached locally or the local admin account.
@@ -273,28 +359,25 @@ void ExistingUserController::OnLoginFailure(const std::string& error) {
} else if (!network->Connected()) {
ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
} else {
- std::string error_code = LoginUtils::ExtractClientLoginParam(error,
- kError,
- kParamSuffix);
- std::string captcha_url;
- if (error_code == kCaptchaError)
- captcha_url = LoginUtils::ExtractClientLoginParam(error,
- kCaptchaUrlParam,
- kParamSuffix);
- if (captcha_url.empty()) {
- ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
+ if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED &&
+ failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) {
+ if (!failure.error().captcha().image_url.is_empty()) {
+ CaptchaView* view =
+ new CaptchaView(failure.error().captcha().image_url);
+ view->set_delegate(this);
+ views::Window* window = views::Window::CreateChromeWindow(
+ GetNativeWindow(), gfx::Rect(), view);
+ window->SetIsAlwaysOnTop(true);
+ window->Show();
+ } else {
+ LOG(WARNING) << "No captcha image url was found?";
+ ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
+ }
} else {
- // Save token for next login retry.
- login_token_ = LoginUtils::ExtractClientLoginParam(error,
- kCaptchaTokenParam,
- kParamSuffix);
- CaptchaView* view =
- new CaptchaView(GURL(kCaptchaUrlPrefix + captcha_url));
- view->set_delegate(this);
- views::Window* window = views::Window::CreateChromeWindow(
- GetNativeWindow(), gfx::Rect(), view);
- window->SetIsAlwaysOnTop(true);
- window->Show();
+ if (controllers_[selected_view_index_]->is_new_user())
+ ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error);
+ else
+ ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
}
}
@@ -305,15 +388,8 @@ void ExistingUserController::OnLoginFailure(const std::string& error) {
}
void ExistingUserController::AppendStartUrlToCmdline() {
- if (start_url_.is_valid()) {
- CommandLine::ForCurrentProcess()->AppendLooseValue(
- UTF8ToWide(start_url_.spec()));
- }
-}
-
-void ExistingUserController::ClearCaptchaState() {
- login_token_.clear();
- login_captcha_.clear();
+ if (start_url_.is_valid())
+ CommandLine::ForCurrentProcess()->AppendArg(start_url_.spec());
}
gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
@@ -325,14 +401,31 @@ void ExistingUserController::ShowError(int error_id,
const std::string& details) {
ClearErrors();
std::wstring error_text = l10n_util::GetString(error_id);
- if (!details.empty())
- error_text += L"\n" + ASCIIToWide(details);
+ // TODO(dpolukhin): show detailed error info. |details| string contains
+ // low level error info that is not localized and even is not user friendly.
+ // 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();
+ BubbleBorder::ArrowLocation arrow;
+ if (controllers_[selected_view_index_]->is_new_user()) {
+ arrow = BubbleBorder::LEFT_TOP;
+ } else {
+ // Point info bubble arrow to cursor position (approximately).
+ bounds.set_width(kCursorOffset * 2);
+ arrow = BubbleBorder::BOTTOM_LEFT;
+ }
+ std::wstring help_link;
+ if (num_login_attempts_ > static_cast<size_t>(1))
+ help_link = l10n_util::GetString(IDS_CANT_ACCESS_ACCOUNT_BUTTON);
+
bubble_ = MessageBubble::Show(
controllers_[selected_view_index_]->controls_window(),
- controllers_[selected_view_index_]->GetScreenBounds(),
- BubbleBorder::BOTTOM_LEFT,
+ bounds,
+ arrow,
ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
error_text,
+ help_link,
this);
}
@@ -340,11 +433,14 @@ void ExistingUserController::OnLoginSuccess(const std::string& username,
const GaiaAuthConsumer::ClientLoginResult& credentials) {
AppendStartUrlToCmdline();
- if (selected_view_index_ + 1 == controllers_.size()) {
+ if (selected_view_index_ + 1 == controllers_.size() &&
+ !UserManager::Get()->IsKnownUser(username)) {
// For new user login don't launch browser until we pass image screen.
- chromeos::LoginUtils::Get()->EnableBrowserLaunch(false);
+ LoginUtils::Get()->EnableBrowserLaunch(false);
LoginUtils::Get()->CompleteLogin(username, credentials);
- ActivateWizard(WizardController::kUserImageScreenName);
+ ActivateWizard(WizardController::IsDeviceRegistered() ?
+ WizardController::kUserImageScreenName :
+ WizardController::kRegistrationScreenName);
} else {
// Hide the login windows now.
WmIpc::Message message(WM_IPC_MESSAGE_WM_HIDE_LOGIN);
@@ -358,23 +454,22 @@ void ExistingUserController::OnLoginSuccess(const std::string& username,
}
void ExistingUserController::OnOffTheRecordLoginSuccess() {
- AppendStartUrlToCmdline();
- LoginUtils::Get()->CompleteOffTheRecordLogin();
+ if (WizardController::IsDeviceRegistered()) {
+ LoginUtils::Get()->CompleteOffTheRecordLogin(start_url_);
+ } else {
+ // Postpone CompleteOffTheRecordLogin until registration completion.
+ ActivateWizard(WizardController::kRegistrationScreenName);
+ }
}
void ExistingUserController::OnPasswordChangeDetected(
const GaiaAuthConsumer::ClientLoginResult& credentials) {
// When signing in as a "New user" always remove old cryptohome.
if (selected_view_index_ == controllers_.size() - 1) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(authenticator_.get(),
- &Authenticator::ResyncEncryptedData,
- credentials));
+ login_performer_->ResyncEncryptedData();
return;
}
- cached_credentials_ = credentials;
PasswordChangedView* view = new PasswordChangedView(this);
views::Window* window = views::Window::CreateChromeWindow(GetNativeWindow(),
gfx::Rect(),
@@ -383,28 +478,38 @@ void ExistingUserController::OnPasswordChangeDetected(
window->Show();
}
+void ExistingUserController::OnHelpLinkActivated() {
+ DCHECK(login_performer_->error().state() != GoogleServiceAuthError::NONE);
+ if (!help_app_.get())
+ help_app_.reset(new HelpAppLauncher(GetNativeWindow()));
+ switch (login_performer_->error().state()) {
+ case(GoogleServiceAuthError::CONNECTION_FAILED):
+ help_app_->ShowHelpTopic(
+ HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE);
+ break;
+ case(GoogleServiceAuthError::ACCOUNT_DISABLED):
+ help_app_->ShowHelpTopic(
+ HelpAppLauncher::HELP_ACCOUNT_DISABLED);
+ break;
+ default:
+ help_app_->ShowHelpTopic(login_performer_->login_timed_out() ?
+ HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE :
+ HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
+ break;
+ }
+}
+
void ExistingUserController::OnCaptchaEntered(const std::string& captcha) {
- login_captcha_ = captcha;
+ login_performer_->set_captcha(captcha);
}
void ExistingUserController::RecoverEncryptedData(
const std::string& old_password) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(authenticator_.get(),
- &Authenticator::RecoverEncryptedData,
- old_password,
- cached_credentials_));
- cached_credentials_ = GaiaAuthConsumer::ClientLoginResult();
+ login_performer_->RecoverEncryptedData(old_password);
}
void ExistingUserController::ResyncEncryptedData() {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(authenticator_.get(),
- &Authenticator::ResyncEncryptedData,
- cached_credentials_));
- cached_credentials_ = GaiaAuthConsumer::ClientLoginResult();
+ login_performer_->ResyncEncryptedData();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index 856f7ca..6d97740 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -4,34 +4,33 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EXISTING_USER_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_EXISTING_USER_CONTROLLER_H_
+#pragma once
#include <string>
#include <vector>
-#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "base/task.h"
#include "base/timer.h"
+#include "chrome/browser/chromeos/login/background_view.h"
#include "chrome/browser/chromeos/login/captcha_view.h"
-#include "chrome/browser/chromeos/login/login_status_consumer.h"
+#include "chrome/browser/chromeos/login/login_performer.h"
+#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/password_changed_view.h"
-#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/user_controller.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/wm_message_listener.h"
-#include "chrome/browser/views/info_bubble.h"
-#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "gfx/size.h"
namespace chromeos {
-class Authenticator;
-class BackgroundView;
+class HelpAppLauncher;
class MessageBubble;
// ExistingUserController is used to handle login when someone has already
// logged into the machine. When Init is invoked a UserController is created for
-// each of the Users's in the UserManager (including one for guest), and the
-// window manager is then told to show the windows. If the user clicks on the
-// guest entry the WizardWindow is swapped in.
+// each of the Users's in the UserManager (including one for new user and
+// one for BWSI login), and the window manager is then told to show the windows.
//
// To use ExistingUserController create an instance of it and invoke Init.
//
@@ -39,8 +38,9 @@ class MessageBubble;
// the user logs in (or chooses to see other settings).
class ExistingUserController : public WmMessageListener::Observer,
public UserController::Delegate,
- public LoginStatusConsumer,
- public InfoBubbleDelegate,
+ public BackgroundView::Delegate,
+ public LoginPerformer::Delegate,
+ public MessageBubbleDelegate,
public CaptchaView::Delegate,
public PasswordChangedView::Delegate {
public:
@@ -56,6 +56,13 @@ class ExistingUserController : public WmMessageListener::Observer,
void OwnBackground(views::Widget* background_widget,
chromeos::BackgroundView* background_view);
+ // Tries to login from new user pod with given user login and password.
+ // Called after creating new account.
+ void LoginNewUser(const std::string& username, const std::string& password);
+
+ // Selects new user pod.
+ void SelectNewUser();
+
private:
friend class DeleteTask<ExistingUserController>;
@@ -78,13 +85,17 @@ class ExistingUserController : public WmMessageListener::Observer,
virtual void AddStartUrl(const GURL& start_url) { start_url_ = start_url; }
virtual void SelectUser(int index);
- // LoginStatusConsumer:
- virtual void OnLoginFailure(const std::string& error);
+ // BackgroundView::Delegate
+ virtual void OnGoIncognitoButton();
+
+ // LoginPerformer::Delegate implementation:
+ virtual void OnLoginFailure(const LoginFailure& error);
virtual void OnLoginSuccess(const std::string& username,
const GaiaAuthConsumer::ClientLoginResult& credentials);
virtual void OnOffTheRecordLoginSuccess();
virtual void OnPasswordChangeDetected(
const GaiaAuthConsumer::ClientLoginResult& credentials);
+ virtual void WhiteListCheckFailed(const std::string& email);
// Overridden from views::InfoBubbleDelegate.
virtual void InfoBubbleClosing(InfoBubble* info_bubble,
@@ -93,6 +104,7 @@ class ExistingUserController : public WmMessageListener::Observer,
}
virtual bool CloseOnEscape() { return true; }
virtual bool FadeInOnShow() { return false; }
+ virtual void OnHelpLinkActivated();
// CaptchaView::Delegate:
virtual void OnCaptchaEntered(const std::string& captcha);
@@ -104,9 +116,6 @@ class ExistingUserController : public WmMessageListener::Observer,
// Adds start url to command line.
void AppendStartUrlToCmdline();
- // Clears existing captcha state;
- void ClearCaptchaState();
-
// Returns corresponding native window.
gfx::NativeWindow GetNativeWindow() const;
@@ -128,12 +137,16 @@ class ExistingUserController : public WmMessageListener::Observer,
// The set of UserControllers.
std::vector<UserController*> controllers_;
- // Used for logging in.
- scoped_refptr<Authenticator> authenticator_;
+ // Used to execute login operations.
+ scoped_ptr<LoginPerformer> login_performer_;
// Index of selected view (user).
size_t selected_view_index_;
+ // Number of login attempts. Used to show help link when > 1 unsuccessful
+ // logins for the same user.
+ size_t num_login_attempts_;
+
// See comment in ProcessWmMessage.
base::OneShotTimer<ExistingUserController> delete_timer_;
@@ -145,17 +158,11 @@ class ExistingUserController : public WmMessageListener::Observer,
// it will be deleted on bubble closing.
MessageBubble* bubble_;
- // Token representing the specific CAPTCHA challenge.
- std::string login_token_;
-
- // String entered by the user as an answer to a CAPTCHA challenge.
- std::string login_captcha_;
-
// URL that will be opened on browser startup.
GURL start_url_;
- // Cached credentials data when password change is detected.
- GaiaAuthConsumer::ClientLoginResult cached_credentials_;
+ // Help application used for help dialogs.
+ scoped_ptr<HelpAppLauncher> help_app_;
DISALLOW_COPY_AND_ASSIGN(ExistingUserController);
};
diff --git a/chrome/browser/chromeos/login/google_authenticator.cc b/chrome/browser/chromeos/login/google_authenticator.cc
index 94361be..f6e53b4 100644
--- a/chrome/browser/chromeos/login/google_authenticator.cc
+++ b/chrome/browser/chromeos/login/google_authenticator.cc
@@ -22,10 +22,12 @@
#include "chrome/browser/chromeos/login/auth_response_handler.h"
#include "chrome/browser/chromeos/login/authentication_notification_details.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
+#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/gaia/gaia_authenticator2.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_service.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -45,7 +47,7 @@ namespace chromeos {
const char GoogleAuthenticator::kLocalaccountFile[] = "localaccount";
// static
-const int GoogleAuthenticator::kClientLoginTimeoutMs = 5000;
+const int GoogleAuthenticator::kClientLoginTimeoutMs = 10000;
// static
const int GoogleAuthenticator::kLocalaccountRetryIntervalMs = 20;
@@ -57,21 +59,32 @@ GoogleAuthenticator::GoogleAuthenticator(LoginStatusConsumer* consumer)
try_again_(true),
checked_for_localaccount_(false) {
CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
+ // If not already owned, this is a no-op. If it is, this loads the owner's
+ // public key off of disk.
+ OwnershipService::GetSharedInstance()->StartLoadOwnerKeyAttempt();
}
GoogleAuthenticator::~GoogleAuthenticator() {}
void GoogleAuthenticator::CancelClientLogin() {
if (gaia_authenticator_->HasPendingFetch()) {
+ LOG(INFO) << "Canceling ClientLogin attempt.";
gaia_authenticator_->CancelRequest();
- OnLoginFailure("Login has timed out; please try again!");
+
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(this,
+ &GoogleAuthenticator::LoadLocalaccount,
+ std::string(kLocalaccountFile)));
+
+ CheckOffline(LoginFailure(LoginFailure::LOGIN_TIMED_OUT));
}
}
void GoogleAuthenticator::TryClientLogin() {
gaia_authenticator_->StartClientLogin(username_,
password_,
- GaiaAuthenticator2::kContactsService,
+ GaiaConstants::kContactsService,
login_token_,
login_captcha_);
ChromeThread::PostDelayedTask(
@@ -114,7 +127,7 @@ bool GoogleAuthenticator::AuthenticateToLogin(
gaia_authenticator_.reset(
new GaiaAuthenticator2(this,
- GaiaAuthenticator2::kChromeOSSource,
+ GaiaConstants::kChromeOSSource,
profile->GetRequestContext()));
// Will be used for retries.
PrepareClientLoginAttempt(password, login_token, login_captcha);
@@ -139,7 +152,7 @@ bool GoogleAuthenticator::AuthenticateToUnlock(const std::string& username,
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this, &GoogleAuthenticator::CheckOffline,
- std::string("unlock failed")));
+ LoginFailure(LoginFailure::UNLOCK_FAILED)));
}
return true;
}
@@ -155,8 +168,9 @@ void GoogleAuthenticator::LoginOffTheRecord() {
Details<AuthenticationNotificationDetails>(&details));
consumer_->OnOffTheRecordLoginSuccess();
} else {
- LOG(ERROR) << "Could not mount tmpfs cryptohome: " << mount_error;
- consumer_->OnLoginFailure("Could not mount tmpfs cryptohome");
+ LOG(ERROR) << "Could not mount tmpfs: " << mount_error;
+ consumer_->OnLoginFailure(
+ LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
}
}
@@ -174,9 +188,9 @@ void GoogleAuthenticator::OnClientLoginSuccess(
}
void GoogleAuthenticator::OnClientLoginFailure(
- const GaiaAuthConsumer::GaiaAuthError& error) {
+ const GoogleServiceAuthError& error) {
- if (error.code == GaiaAuthConsumer::REQUEST_CANCELED) {
+ if (error.state() == GoogleServiceAuthError::REQUEST_CANCELED) {
if (try_again_) {
try_again_ = false;
LOG(ERROR) << "Login attempt canceled!?!? Trying again.";
@@ -188,7 +202,7 @@ void GoogleAuthenticator::OnClientLoginFailure(
ClearClientLoginAttempt();
- if (error.code == GaiaAuthConsumer::TWO_FACTOR) {
+ if (error.state() == GoogleServiceAuthError::TWO_FACTOR) {
LOG(WARNING) << "Two factor authenticated. Sync will not work.";
OnClientLoginSuccess(GaiaAuthConsumer::ClientLoginResult());
return;
@@ -200,12 +214,14 @@ void GoogleAuthenticator::OnClientLoginFailure(
&GoogleAuthenticator::LoadLocalaccount,
std::string(kLocalaccountFile)));
- if (error.code == GaiaAuthConsumer::NETWORK_ERROR) {
+ LoginFailure failure_details = LoginFailure::FromNetworkAuthFailure(error);
+
+ if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
// The fetch failed for network reasons, try offline login.
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this, &GoogleAuthenticator::CheckOffline,
- net::ErrorToString(error.network_error)));
+ failure_details));
return;
}
@@ -214,7 +230,7 @@ void GoogleAuthenticator::OnClientLoginFailure(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this,
&GoogleAuthenticator::CheckLocalaccount,
- error.data));
+ failure_details));
}
void GoogleAuthenticator::OnLoginSuccess(
@@ -237,11 +253,11 @@ void GoogleAuthenticator::OnLoginSuccess(
mount_error == chromeos::kCryptohomeMountErrorKeyFailure) {
consumer_->OnPasswordChangeDetected(credentials);
} else {
- OnLoginFailure("Could not mount cryptohome");
+ OnLoginFailure(LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME));
}
}
-void GoogleAuthenticator::CheckOffline(const std::string& error) {
+void GoogleAuthenticator::CheckOffline(const LoginFailure& error) {
LOG(INFO) << "Attempting offline login";
if (CrosLibrary::Get()->GetCryptohomeLibrary()->CheckKey(
username_.c_str(),
@@ -255,7 +271,7 @@ void GoogleAuthenticator::CheckOffline(const std::string& error) {
}
}
-void GoogleAuthenticator::CheckLocalaccount(const std::string& error) {
+void GoogleAuthenticator::CheckLocalaccount(const LoginFailure& error) {
{
AutoLock for_this_block(localaccount_lock_);
LOG(INFO) << "Checking localaccount";
@@ -271,25 +287,30 @@ void GoogleAuthenticator::CheckLocalaccount(const std::string& error) {
}
}
int mount_error = chromeos::kCryptohomeMountErrorNone;
- if (!localaccount_.empty() && localaccount_ == username_ &&
- CrosLibrary::Get()->GetCryptohomeLibrary()->MountForBwsi(&mount_error)) {
- LOG(WARNING) << "Logging in with localaccount: " << localaccount_;
- consumer_->OnLoginSuccess(username_, GaiaAuthConsumer::ClientLoginResult());
+ if (!localaccount_.empty() && localaccount_ == username_) {
+ if (CrosLibrary::Get()->GetCryptohomeLibrary()->MountForBwsi(
+ &mount_error)) {
+ LOG(WARNING) << "Logging in with localaccount: " << localaccount_;
+ consumer_->OnLoginSuccess(username_,
+ GaiaAuthConsumer::ClientLoginResult());
+ } else {
+ LOG(ERROR) << "Could not mount tmpfs for local account: " << mount_error;
+ OnLoginFailure(
+ LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS));
+ }
} else {
OnLoginFailure(error);
}
}
-void GoogleAuthenticator::OnLoginFailure(const std::string& error) {
+void GoogleAuthenticator::OnLoginFailure(const LoginFailure& error) {
// Send notification of failure
AuthenticationNotificationDetails details(false);
NotificationService::current()->Notify(
NotificationType::LOGIN_AUTHENTICATION,
NotificationService::AllSources(),
Details<AuthenticationNotificationDetails>(&details));
- LOG(WARNING) << "Login failed: " << error;
- // TODO(cmasone): what can we do to expose these OS/server-side error strings
- // in an internationalizable way?
+ LOG(WARNING) << "Login failed: " << error.GetErrorString();
consumer_->OnLoginFailure(error);
}
@@ -313,7 +334,7 @@ void GoogleAuthenticator::ResyncEncryptedData(
if (CrosLibrary::Get()->GetCryptohomeLibrary()->Remove(username_)) {
OnLoginSuccess(credentials);
} else {
- OnLoginFailure("Could not destroy your old data!");
+ OnLoginFailure(LoginFailure(LoginFailure::DATA_REMOVAL_FAILED));
}
}
@@ -413,19 +434,4 @@ bool GoogleAuthenticator::BinaryToHex(const std::vector<unsigned char>& binary,
return true;
}
-// static
-std::string GoogleAuthenticator::Canonicalize(
- const std::string& email_address) {
- std::vector<std::string> parts;
- char at = '@';
- SplitString(email_address, at, &parts);
- DCHECK_EQ(parts.size(), 2U) << "email_address should have only one @";
- 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));
- LOG(INFO) << "Canonicalized " << email_address << " to " << new_email;
- return new_email;
-}
-
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/google_authenticator.h b/chrome/browser/chromeos/login/google_authenticator.h
index 2fae711..7c71952 100644
--- a/chrome/browser/chromeos/login/google_authenticator.h
+++ b/chrome/browser/chromeos/login/google_authenticator.h
@@ -4,15 +4,14 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
-#include "base/sha2.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/authenticator.h"
@@ -23,6 +22,8 @@
class Lock;
class Profile;
class GaiaAuthenticator2;
+class GoogleServiceAuthError;
+class LoginFailure;
namespace chromeos {
@@ -30,7 +31,6 @@ class GoogleAuthenticatorTest;
class LoginStatusConsumer;
class GoogleAuthenticator : public Authenticator, public GaiaAuthConsumer {
-
public:
explicit GoogleAuthenticator(LoginStatusConsumer* consumer);
virtual ~GoogleAuthenticator();
@@ -74,9 +74,9 @@ class GoogleAuthenticator : public Authenticator, public GaiaAuthConsumer {
// These methods must be called on the UI thread, as they make DBus calls
// and also call back to the login UI.
void OnLoginSuccess(const GaiaAuthConsumer::ClientLoginResult& credentials);
- void CheckOffline(const std::string& error);
- void CheckLocalaccount(const std::string& error);
- void OnLoginFailure(const std::string& error);
+ void CheckOffline(const LoginFailure& error);
+ void CheckLocalaccount(const LoginFailure& error);
+ void OnLoginFailure(const LoginFailure& error);
// Call these methods on the UI thread.
void RecoverEncryptedData(
@@ -85,15 +85,9 @@ class GoogleAuthenticator : public Authenticator, public GaiaAuthConsumer {
void ResyncEncryptedData(
const GaiaAuthConsumer::ClientLoginResult& credentials);
- // Perform basic canonicalization of |email_address|, taking into account
- // that gmail does not consider '.' or caps inside a username to matter.
- // For example, c.masone@gmail.com == cMaSone@gmail.com, per
- // http://mail.google.com/support/bin/answer.py?hl=en&ctx=mail&answer=10313#
- static std::string Canonicalize(const std::string& email_address);
-
// Callbacks from GaiaAuthenticator2
virtual void OnClientLoginFailure(
- const GaiaAuthConsumer::GaiaAuthError& error);
+ const GoogleServiceAuthError& error);
virtual void OnClientLoginSuccess(
const GaiaAuthConsumer::ClientLoginResult& credentials);
diff --git a/chrome/browser/chromeos/login/google_authenticator_unittest.cc b/chrome/browser/chromeos/login/google_authenticator_unittest.cc
index 3789feb..6762f88 100644
--- a/chrome/browser/chromeos/login/google_authenticator_unittest.cc
+++ b/chrome/browser/chromeos/login/google_authenticator_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 "chrome/browser/chromeos/login/google_authenticator.h"
+
#include <string>
#include <vector>
@@ -9,16 +11,16 @@
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
#include "chrome/browser/chromeos/cros/mock_library_loader.h"
#include "chrome/browser/chromeos/login/client_login_response_handler.h"
-#include "chrome/browser/chromeos/login/google_authenticator.h"
#include "chrome/browser/chromeos/login/issue_response_handler.h"
#include "chrome/browser/chromeos/login/mock_auth_response_handler.h"
+#include "chrome/browser/chromeos/login/mock_url_fetchers.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/gaia/gaia_authenticator2_unittest.h"
#include "chrome/common/net/url_fetcher.h"
@@ -43,7 +45,7 @@ class MockConsumer : public LoginStatusConsumer {
public:
MockConsumer() {}
~MockConsumer() {}
- MOCK_METHOD1(OnLoginFailure, void(const std::string& error));
+ MOCK_METHOD1(OnLoginFailure, void(const LoginFailure& error));
MOCK_METHOD2(OnLoginSuccess, void(const std::string& username,
const GaiaAuthConsumer::ClientLoginResult& result));
MOCK_METHOD0(OnOffTheRecordLoginSuccess, void(void));
@@ -133,6 +135,14 @@ class GoogleAuthenticatorTest : public ::testing::Test {
auth->SetLocalaccount("");
}
+ void CancelLogin(GoogleAuthenticator* auth) {
+ ChromeThread::PostTask(
+ ChromeThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(auth,
+ &GoogleAuthenticator::CancelClientLogin));
+ }
+
unsigned char fake_hash_[32];
std::string hash_ascii_;
std::string username_;
@@ -162,51 +172,6 @@ TEST_F(GoogleAuthenticatorTest, SaltToAscii) {
EXPECT_EQ("0a010000000000a0", auth->SaltAsAscii());
}
-TEST_F(GoogleAuthenticatorTest, EmailAddressNoOp) {
- const char lower_case[] = "user@what.com";
- EXPECT_EQ(lower_case, GoogleAuthenticator::Canonicalize(lower_case));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressIgnoreCaps) {
- EXPECT_EQ(GoogleAuthenticator::Canonicalize("user@what.com"),
- GoogleAuthenticator::Canonicalize("UsEr@what.com"));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressIgnoreDomainCaps) {
- EXPECT_EQ(GoogleAuthenticator::Canonicalize("user@what.com"),
- GoogleAuthenticator::Canonicalize("UsEr@what.COM"));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressIgnoreOneUsernameDot) {
- EXPECT_EQ(GoogleAuthenticator::Canonicalize("us.er@what.com"),
- GoogleAuthenticator::Canonicalize("UsEr@what.com"));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressIgnoreManyUsernameDots) {
- EXPECT_EQ(GoogleAuthenticator::Canonicalize("u.ser@what.com"),
- GoogleAuthenticator::Canonicalize("Us.E.r@what.com"));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressIgnoreConsecutiveUsernameDots) {
- EXPECT_EQ(GoogleAuthenticator::Canonicalize("use.r@what.com"),
- GoogleAuthenticator::Canonicalize("Us....E.r@what.com"));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressDifferentOnesRejected) {
- EXPECT_NE(GoogleAuthenticator::Canonicalize("who@what.com"),
- GoogleAuthenticator::Canonicalize("Us....E.r@what.com"));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressIgnorePlusSuffix) {
- EXPECT_EQ(GoogleAuthenticator::Canonicalize("user+cc@what.com"),
- GoogleAuthenticator::Canonicalize("user@what.com"));
-}
-
-TEST_F(GoogleAuthenticatorTest, EmailAddressIgnoreMultiPlusSuffix) {
- EXPECT_EQ(GoogleAuthenticator::Canonicalize("user+cc+bcc@what.com"),
- GoogleAuthenticator::Canonicalize("user@what.com"));
-}
-
TEST_F(GoogleAuthenticatorTest, ReadLocalaccount) {
FilePath tmp_file_path = FakeLocalaccountFile(bytes_as_ascii_);
@@ -218,7 +183,8 @@ TEST_F(GoogleAuthenticatorTest, ReadLocalaccount) {
TEST_F(GoogleAuthenticatorTest, ReadLocalaccountTrailingWS) {
FilePath tmp_file_path =
- FakeLocalaccountFile(StringPrintf("%s\n", bytes_as_ascii_.c_str()));
+ FakeLocalaccountFile(base::StringPrintf("%s\n",
+ bytes_as_ascii_.c_str()));
scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(NULL));
ReadLocalaccountFile(auth.get(), tmp_file_path.BaseName().value());
@@ -352,15 +318,14 @@ TEST_F(GoogleAuthenticatorTest, LoginNetFailure) {
MessageLoopForUI message_loop;
ChromeThread ui_thread(ChromeThread::UI, &message_loop);
- int error_no = net::ERR_CONNECTION_RESET;
- std::string data(net::ErrorToString(error_no));
+ GoogleServiceAuthError error =
+ GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET);
- GaiaAuthConsumer::GaiaAuthError error;
- error.code = GaiaAuthConsumer::NETWORK_ERROR;
- error.network_error = error_no;
+ LoginFailure failure =
+ LoginFailure::FromNetworkAuthFailure(error);
MockConsumer consumer;
- EXPECT_CALL(consumer, OnLoginFailure(data))
+ EXPECT_CALL(consumer, OnLoginFailure(failure))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*mock_library_, CheckKey(username_, hash_ascii_))
@@ -377,8 +342,8 @@ TEST_F(GoogleAuthenticatorTest, LoginDenied) {
MessageLoopForUI message_loop;
ChromeThread ui_thread(ChromeThread::UI, &message_loop);
- GaiaAuthConsumer::GaiaAuthError error;
- error.code = GaiaAuthConsumer::PERMISSION_DENIED;
+ GoogleServiceAuthError client_error(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
MockConsumer consumer;
EXPECT_CALL(consumer, OnLoginFailure(_))
@@ -387,7 +352,61 @@ TEST_F(GoogleAuthenticatorTest, LoginDenied) {
scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
PrepForLogin(auth.get());
- auth->OnClientLoginFailure(error);
+ auth->OnClientLoginFailure(client_error);
+ message_loop.RunAllPending();
+}
+
+TEST_F(GoogleAuthenticatorTest, LoginAccountDisabled) {
+ MessageLoopForUI message_loop;
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+
+ GoogleServiceAuthError client_error(
+ GoogleServiceAuthError::ACCOUNT_DISABLED);
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
+ PrepForLogin(auth.get());
+ auth->OnClientLoginFailure(client_error);
+ message_loop.RunAllPending();
+}
+
+TEST_F(GoogleAuthenticatorTest, LoginAccountDeleted) {
+ MessageLoopForUI message_loop;
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+
+ GoogleServiceAuthError client_error(
+ GoogleServiceAuthError::ACCOUNT_DELETED);
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
+ PrepForLogin(auth.get());
+ auth->OnClientLoginFailure(client_error);
+ message_loop.RunAllPending();
+}
+
+TEST_F(GoogleAuthenticatorTest, LoginServiceUnavailable) {
+ MessageLoopForUI message_loop;
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+
+ GoogleServiceAuthError client_error(
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+
+ MockConsumer consumer;
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
+ PrepForLogin(auth.get());
+ auth->OnClientLoginFailure(client_error);
message_loop.RunAllPending();
}
@@ -395,22 +414,22 @@ TEST_F(GoogleAuthenticatorTest, CaptchaErrorOutputted) {
MessageLoopForUI message_loop;
ChromeThread ui_thread(ChromeThread::UI, &message_loop);
- // TODO(chron): Swap out this captcha passing for actual captcha parsing.
- GaiaAuthConsumer::GaiaAuthError error;
- error.code = GaiaAuthConsumer::PERMISSION_DENIED;
- error.data = "Url=http://www.google.com/login/captcha\n"
- "Error=CaptchaRequired\n"
- "CaptchaToken=DQAAAGgA...dkI1LK9\n"
- "CaptchaUrl=Captcha?ctoken=...\n";
+ GoogleServiceAuthError auth_error =
+ GoogleServiceAuthError::FromCaptchaChallenge(
+ "CCTOKEN",
+ GURL("http://www.google.com/accounts/Captcha?ctoken=CCTOKEN"),
+ GURL("http://www.google.com/login/captcha"));
+
+ LoginFailure failure = LoginFailure::FromNetworkAuthFailure(auth_error);
MockConsumer consumer;
- EXPECT_CALL(consumer, OnLoginFailure(error.data))
+ EXPECT_CALL(consumer, OnLoginFailure(failure))
.Times(1)
.RetiresOnSaturation();
scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
PrepForLogin(auth.get());
- auth->OnClientLoginFailure(error);
+ auth->OnClientLoginFailure(auth_error);
message_loop.RunAllPending();
}
@@ -418,9 +437,8 @@ TEST_F(GoogleAuthenticatorTest, OfflineLogin) {
MessageLoopForUI message_loop;
ChromeThread ui_thread(ChromeThread::UI, &message_loop);
- GaiaAuthConsumer::GaiaAuthError error;
- error.code = GaiaAuthConsumer::NETWORK_ERROR;
- error.network_error = net::ERR_CONNECTION_RESET;
+ GoogleServiceAuthError auth_error(
+ GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET));
MockConsumer consumer;
EXPECT_CALL(consumer, OnLoginSuccess(username_, result_))
@@ -435,7 +453,7 @@ TEST_F(GoogleAuthenticatorTest, OfflineLogin) {
scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
PrepForLogin(auth.get());
- auth->OnClientLoginFailure(error);
+ auth->OnClientLoginFailure(auth_error);
message_loop.RunAllPending();
}
@@ -473,20 +491,37 @@ TEST_F(GoogleAuthenticatorTest, CheckLocalaccount) {
PrepForLogin(auth.get());
auth->SetLocalaccount(username_);
- auth->CheckLocalaccount(std::string());
+ auth->CheckLocalaccount(LoginFailure(LoginFailure::LOGIN_TIMED_OUT));
}
+namespace {
+
// Compatible with LoginStatusConsumer::OnLoginSuccess()
-static void Quit(const std::string& username,
- const GaiaAuthConsumer::ClientLoginResult& credentials) {
+static void OnSuccessQuit(
+ const std::string& username,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ MessageLoop::current()->Quit();
+}
+
+static void OnSuccessQuitAndFail(
+ const std::string& username,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ ADD_FAILURE() << "Login should NOT have succeeded!";
MessageLoop::current()->Quit();
}
+
// Compatible with LoginStatusConsumer::OnLoginFailure()
-static void QuitAndFail(const std::string& error) {
+static void OnFailQuit(const LoginFailure& error) {
+ MessageLoop::current()->Quit();
+}
+
+static void OnFailQuitAndFail(const LoginFailure& error) {
ADD_FAILURE() << "Login should have succeeded!";
MessageLoop::current()->Quit();
}
+} // anonymous namespace
+
TEST_F(GoogleAuthenticatorTest, LocalaccountLogin) {
// This test checks the logic that governs asynchronously reading the
// localaccount name off disk and trying to authenticate against it
@@ -495,17 +530,15 @@ TEST_F(GoogleAuthenticatorTest, LocalaccountLogin) {
ChromeThread ui_thread(ChromeThread::UI, &message_loop);
MockConsumer consumer;
- ON_CALL(consumer, OnLoginSuccess(username_, _))
- .WillByDefault(Invoke(Quit));
EXPECT_CALL(consumer, OnLoginSuccess(username_, _))
- .Times(1)
+ .WillOnce(Invoke(OnSuccessQuit))
.RetiresOnSaturation();
EXPECT_CALL(*mock_library_, MountForBwsi(_))
.WillOnce(Return(true))
.RetiresOnSaturation();
// Enable the test to terminate (and fail), even if the login fails.
ON_CALL(consumer, OnLoginFailure(_))
- .WillByDefault(Invoke(QuitAndFail));
+ .WillByDefault(Invoke(OnFailQuitAndFail));
// Manually prep for login, so that localaccount isn't set for us.
scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
@@ -518,7 +551,7 @@ TEST_F(GoogleAuthenticatorTest, LocalaccountLogin) {
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(auth.get(),
&GoogleAuthenticator::CheckLocalaccount,
- std::string("fail")));
+ LoginFailure(LoginFailure::LOGIN_TIMED_OUT)));
message_loop.RunAllPending();
// The foregoing has now rescheduled itself in a few ms because we don't
// yet have the localaccount loaded off disk.
@@ -537,8 +570,6 @@ TEST_F(GoogleAuthenticatorTest, LocalaccountLogin) {
TEST_F(GoogleAuthenticatorTest, FullLogin) {
MessageLoopForUI message_loop;
ChromeThread ui_thread(ChromeThread::UI, &message_loop);
- GURL source(AuthResponseHandler::kTokenAuthUrl);
- URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
chromeos::CryptohomeBlob salt_v(fake_hash_, fake_hash_ + sizeof(fake_hash_));
MockConsumer consumer;
@@ -549,15 +580,13 @@ TEST_F(GoogleAuthenticatorTest, FullLogin) {
.WillOnce(Return(true))
.RetiresOnSaturation();
- ON_CALL(*mock_library_, GetSystemSalt())
- .WillByDefault(Return(salt_v));
EXPECT_CALL(*mock_library_, GetSystemSalt())
- .Times(1)
+ .WillOnce(Return(salt_v))
.RetiresOnSaturation();
TestingProfile profile;
- MockFactory factory;
+ MockFactory<MockFetcher> factory;
URLFetcher::set_factory(&factory);
scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
@@ -568,4 +597,109 @@ TEST_F(GoogleAuthenticatorTest, FullLogin) {
message_loop.RunAllPending();
}
+TEST_F(GoogleAuthenticatorTest, CancelLogin) {
+ MessageLoop message_loop(MessageLoop::TYPE_UI);
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+ chromeos::CryptohomeBlob salt_v(fake_hash_, fake_hash_ + sizeof(fake_hash_));
+
+ MockConsumer consumer;
+ // The expected case.
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .WillOnce(Invoke(OnFailQuit))
+ .RetiresOnSaturation();
+
+ // A failure case, but we still want the test to finish gracefully.
+ ON_CALL(consumer, OnLoginSuccess(username_, _))
+ .WillByDefault(Invoke(OnSuccessQuitAndFail));
+
+ // Stuff we expect to happen along the way.
+ EXPECT_CALL(*mock_library_, GetSystemSalt())
+ .WillOnce(Return(salt_v))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_library_, CheckKey(username_, _))
+ .WillOnce(Return(false))
+ .RetiresOnSaturation();
+
+ TestingProfile profile;
+
+ // This is how we inject fake URLFetcher objects, with a factory.
+ // This factory creates fake URLFetchers that Start() a fake fetch attempt
+ // and then come back on the UI thread after a small delay. They expect to
+ // be canceled before they come back, and the test will fail if they are not.
+ MockFactory<ExpectCanceledFetcher> factory;
+ URLFetcher::set_factory(&factory);
+
+ scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
+
+ // For when |auth| tries to load the localaccount file.
+ ChromeThread file_thread(ChromeThread::FILE);
+ file_thread.Start();
+
+ // Start an authentication attempt, which will kick off a URL "fetch" that
+ // we expect to cancel before it completes.
+ auth->AuthenticateToLogin(
+ &profile, username_, hash_ascii_, std::string(), std::string());
+
+ // Post a task to cancel the login attempt.
+ CancelLogin(auth.get());
+
+ URLFetcher::set_factory(NULL);
+
+ // Run the UI thread until we exit it gracefully.
+ message_loop.Run();
+}
+
+TEST_F(GoogleAuthenticatorTest, CancelLoginAlreadyGotLocalaccount) {
+ MessageLoop message_loop(MessageLoop::TYPE_UI);
+ ChromeThread ui_thread(ChromeThread::UI, &message_loop);
+ chromeos::CryptohomeBlob salt_v(fake_hash_, fake_hash_ + sizeof(fake_hash_));
+
+ MockConsumer consumer;
+ // The expected case.
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .WillOnce(Invoke(OnFailQuit))
+ .RetiresOnSaturation();
+
+ // A failure case, but we still want the test to finish gracefully.
+ ON_CALL(consumer, OnLoginSuccess(username_, _))
+ .WillByDefault(Invoke(OnSuccessQuitAndFail));
+
+ // Stuff we expect to happen along the way.
+ EXPECT_CALL(*mock_library_, GetSystemSalt())
+ .WillOnce(Return(salt_v))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_library_, CheckKey(username_, _))
+ .WillOnce(Return(false))
+ .RetiresOnSaturation();
+
+ TestingProfile profile;
+
+ // This is how we inject fake URLFetcher objects, with a factory.
+ // This factory creates fake URLFetchers that Start() a fake fetch attempt
+ // and then come back on the UI thread after a small delay. They expect to
+ // be canceled before they come back, and the test will fail if they are not.
+ MockFactory<ExpectCanceledFetcher> factory;
+ URLFetcher::set_factory(&factory);
+
+ scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
+
+ // This time, instead of allowing |auth| to go get the localaccount file
+ // itself, we simulate the case where the file is already loaded, which
+ // happens when this isn't the first login since chrome started.
+ ReadLocalaccountFile(auth.get(), "");
+
+ // Start an authentication attempt, which will kick off a URL "fetch" that
+ // we expect to cancel before it completes.
+ auth->AuthenticateToLogin(
+ &profile, username_, hash_ascii_, std::string(), std::string());
+
+ // Post a task to cancel the login attempt.
+ CancelLogin(auth.get());
+
+ URLFetcher::set_factory(NULL);
+
+ // Run the UI thread until we exit it gracefully.
+ message_loop.Run();
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/helper.cc b/chrome/browser/chromeos/login/helper.cc
index 4ea9ed4..d2da133 100644
--- a/chrome/browser/chromeos/login/helper.cc
+++ b/chrome/browser/chromeos/login/helper.cc
@@ -2,8 +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/chromeos/login/helper.h"
+
#include "app/resource_bundle.h"
+#include "chrome/browser/google/google_util.h"
#include "gfx/canvas_skia.h"
+#include "googleurl/src/gurl.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "views/controls/throbber.h"
@@ -23,6 +27,9 @@ const int kThrobberStartDelayMs = 500;
const SkColor kBackgroundCenterColor = SkColorSetRGB(41, 50, 67);
const SkColor kBackgroundEdgeColor = SK_ColorBLACK;
+const char kAccountRecoveryHelpUrl[] =
+ "http://www.google.com/support/accounts/bin/answer.py?answer=48598";
+
class BackgroundPainter : public views::Painter {
public:
BackgroundPainter() {}
@@ -87,5 +94,9 @@ gfx::Rect CalculateScreenBounds(const gfx::Size& size) {
return bounds;
}
+GURL GetAccountRecoveryHelpUrl() {
+ return google_util::AppendGoogleLocaleParam(GURL(kAccountRecoveryHelpUrl));
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/helper.h b/chrome/browser/chromeos/login/helper.h
index a98d2f2..4e7de2a 100644
--- a/chrome/browser/chromeos/login/helper.h
+++ b/chrome/browser/chromeos/login/helper.h
@@ -6,9 +6,17 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_HELPER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_HELPER_H_
+#pragma once
#include "third_party/skia/include/core/SkColor.h"
+class GURL;
+
+namespace gfx {
+class Rect;
+class Size;
+} // namespace gfx
+
namespace views {
class Painter;
class Throbber;
@@ -30,6 +38,9 @@ views::Painter* CreateBackgroundPainter();
// |size| is not empty. Otherwise the whole monitor is occupied.
gfx::Rect CalculateScreenBounds(const gfx::Size& size);
+// Returns URL used for account recovery.
+GURL GetAccountRecoveryHelpUrl();
+
// Define the constants in |login| namespace to avoid potential
// conflict with other chromeos components.
namespace login {
@@ -41,7 +52,7 @@ enum Command {
};
// Gap between edge and image view, and image view and controls.
-const int kBorderSize = 4;
+const int kBorderSize = 6;
// The size of user image.
const int kUserImageSize = 256;
@@ -52,6 +63,15 @@ const SkColor kBackgroundColor = SK_ColorWHITE;
// Text color on the login controls.
const SkColor kTextColor = SK_ColorWHITE;
+// Default size of the OOBE screen. Includes 10px shadow from each side.
+// See rounded_rect_painter.cc for border definitions.
+const int kWizardScreenWidth = 700;
+const int kWizardScreenHeight = 416;
+
+const int kScreenCornerRadius = 10;
+const int kUserCornerRadius = 5;
+
+
} // namespace login
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/image_decoder.h b/chrome/browser/chromeos/login/image_decoder.h
index fdb9e1c..02ad1ce 100644
--- a/chrome/browser/chromeos/login/image_decoder.h
+++ b/chrome/browser/chromeos/login/image_decoder.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_IMAGE_DECODER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_IMAGE_DECODER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/chromeos/login/image_downloader.cc b/chrome/browser/chromeos/login/image_downloader.cc
index dfcd797..367e27e 100644
--- a/chrome/browser/chromeos/login/image_downloader.cc
+++ b/chrome/browser/chromeos/login/image_downloader.cc
@@ -6,6 +6,8 @@
#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/chrome_thread.h"
#include "chrome/browser/profile_manager.h"
@@ -30,7 +32,7 @@ ImageDownloader::ImageDownloader(ImageDecoder::Delegate* delegate,
ProfileManager::GetDefaultProfile()->GetRequestContext());
if (!auth_token.empty()) {
image_fetcher_->set_extra_request_headers(
- StringPrintf(kAuthorizationHeader, auth_token.c_str()));
+ base::StringPrintf(kAuthorizationHeader, auth_token.c_str()));
}
image_fetcher_->Start();
}
diff --git a/chrome/browser/chromeos/login/image_downloader.h b/chrome/browser/chromeos/login/image_downloader.h
index 61d773c..06193bf 100644
--- a/chrome/browser/chromeos/login/image_downloader.h
+++ b/chrome/browser/chromeos/login/image_downloader.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_IMAGE_DOWNLOADER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_IMAGE_DOWNLOADER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/issue_response_handler.cc b/chrome/browser/chromeos/login/issue_response_handler.cc
index bfc1ae2..54abf99 100644
--- a/chrome/browser/chromeos/login/issue_response_handler.cc
+++ b/chrome/browser/chromeos/login/issue_response_handler.cc
@@ -23,9 +23,8 @@ URLFetcher* IssueResponseHandler::Handle(
const std::string& to_process,
URLFetcher::Delegate* catcher) {
LOG(INFO) << "Handling IssueAuthToken response";
- token_url_.assign(StringPrintf("%s%s",
- AuthResponseHandler::kTokenAuthUrl,
- to_process.c_str()));
+ token_url_.assign(base::StringPrintf("%s%s",
+ AuthResponseHandler::kTokenAuthUrl, to_process.c_str()));
URLFetcher* fetcher =
new URLFetcher(GURL(token_url_), URLFetcher::GET, catcher);
fetcher->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES);
diff --git a/chrome/browser/chromeos/login/issue_response_handler.h b/chrome/browser/chromeos/login/issue_response_handler.h
index 4741c80..e724111 100644
--- a/chrome/browser/chromeos/login/issue_response_handler.h
+++ b/chrome/browser/chromeos/login/issue_response_handler.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_ISSUE_RESPONSE_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_ISSUE_RESPONSE_HANDLER_H_
+#pragma once
#include <string>
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "chrome/browser/chromeos/login/auth_response_handler.h"
class URLRequestContextGetter;
diff --git a/chrome/browser/chromeos/login/language_switch_menu.cc b/chrome/browser/chromeos/login/language_switch_menu.cc
index d93e8fe..5f5d8c6 100644
--- a/chrome/browser/chromeos/login/language_switch_menu.cc
+++ b/chrome/browser/chromeos/login/language_switch_menu.cc
@@ -4,14 +4,15 @@
#include "chrome/browser/chromeos/login/language_switch_menu.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.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/keyboard_library.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "views/widget/widget_gtk.h"
@@ -69,18 +70,9 @@ std::wstring LanguageSwitchMenu::GetCurrentLocaleName() const {
language_list_->GetIndexFromLocale(locale));
};
-// Currently, views::Menu is implemented directly with the Gtk
-// widgets. So we use native gtk callbacks to get its future size.
-int LanguageSwitchMenu::GetFirstLevelMenuWidth() const {
- DCHECK(menu_ != NULL);
- GtkRequisition box_size;
- gtk_widget_size_request(menu_->GetNativeMenu(), &box_size);
- return box_size.width;
-}
-
void LanguageSwitchMenu::SetFirstLevelMenuWidth(int width) {
DCHECK(menu_ != NULL);
- gtk_widget_set_size_request(menu_->GetNativeMenu(), width, -1);
+ menu_->SetMinimumWidth(width);
}
// static
@@ -97,12 +89,13 @@ void LanguageSwitchMenu::SwitchLanguage(const std::string& locale) {
prefs->SavePersistentPrefs();
// Switch the locale.
- ResourceBundle::ReloadSharedInstance(UTF8ToWide(locale));
+ ResourceBundle::ReloadSharedInstance(locale);
// Enable the keyboard layouts that are necessary for the new locale.
- chromeos::input_method::EnableInputMethods(
- locale, chromeos::input_method::kKeyboardLayoutsOnly,
- kHardwareKeyboardLayout);
+ input_method::EnableInputMethods(
+ locale, input_method::kKeyboardLayoutsOnly,
+ CrosLibrary::Get()->GetKeyboardLibrary()->
+ GetHardwareKeyboardLayoutName());
// The following line does not seem to affect locale anyhow. Maybe in
// future..
diff --git a/chrome/browser/chromeos/login/language_switch_menu.h b/chrome/browser/chromeos/login/language_switch_menu.h
index 849d537..a3db06e 100644
--- a/chrome/browser/chromeos/login/language_switch_menu.h
+++ b/chrome/browser/chromeos/login/language_switch_menu.h
@@ -4,16 +4,17 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_LANGUAGE_SWITCH_MENU_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_LANGUAGE_SWITCH_MENU_H_
+#pragma once
#include <string>
#include "app/menus/simple_menu_model.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/language_combobox_model.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
#include "views/controls/menu/menu_2.h"
#include "views/controls/menu/view_menu_delegate.h"
#include "views/view.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
class WizardControllerTest_SwitchLanguage_Test;
@@ -32,8 +33,7 @@ class LanguageSwitchMenu : public views::ViewMenuDelegate,
// Returns current locale name to be placed on the language menu-button.
std::wstring GetCurrentLocaleName() const;
- // Returns original width of the first level menu to be shown when called.
- int GetFirstLevelMenuWidth() const;
+ // Sets the minimum width of the first level menu to be shown.
void SetFirstLevelMenuWidth(int width);
void set_menu_offset(int delta_x, int delta_y) {
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index dd89fb3..85a99ba 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -6,7 +6,6 @@
#include "base/time.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
-#include "chrome/browser/profile_manager.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"
@@ -14,13 +13,14 @@
#include "chrome/browser/chromeos/cros/mock_network_library.h"
#include "chrome/browser/chromeos/cros/mock_power_library.h"
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
-#include "chrome/browser/chromeos/cros/mock_synaptics_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/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
using ::testing::_;
@@ -50,8 +50,10 @@ class LoginTestBase : public InProcessBrowserTest {
testApi_->SetPowerLibrary(&mock_power_library_, false);
EXPECT_CALL(mock_power_library_, battery_time_to_empty())
.WillRepeatedly((Return(base::TimeDelta::FromMinutes(42))));
+ EXPECT_CALL(mock_power_library_, battery_time_to_full())
+ .WillRepeatedly((Return(base::TimeDelta::FromMinutes(24))));
- testApi_->SetSynapticsLibrary(&mock_synaptics_library_, false);
+ testApi_->SetTouchpadLibrary(&mock_touchpad_library_, false);
testApi_->SetCryptohomeLibrary(&mock_cryptohome_library_, false);
testApi_->SetScreenLockLibrary(&mock_screen_lock_library_, false);
testApi_->SetSystemLibrary(&mock_system_library_, false);
@@ -65,7 +67,7 @@ class LoginTestBase : public InProcessBrowserTest {
NiceMock<MockNetworkLibrary> mock_network_library_;
NiceMock<MockPowerLibrary> mock_power_library_;
NiceMock<MockScreenLockLibrary> mock_screen_lock_library_;
- NiceMock<MockSynapticsLibrary> mock_synaptics_library_;
+ NiceMock<MockTouchpadLibrary> mock_touchpad_library_;
NiceMock<MockSystemLibrary> mock_system_library_;
ImePropertyList ime_properties_;
chromeos::CrosLibrary::TestApi* testApi_;
@@ -81,9 +83,8 @@ class LoginUserTest : public LoginTestBase {
}
virtual void SetUpCommandLine(CommandLine* command_line) {
- command_line->AppendSwitchWithValue(
- switches::kLoginUser, "TestUser@gmail.com");
- command_line->AppendSwitchWithValue(switches::kLoginProfile, "user");
+ command_line->AppendSwitchASCII(switches::kLoginUser, "TestUser@gmail.com");
+ command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
command_line->AppendSwitch(switches::kNoFirstRun);
}
};
@@ -96,7 +97,7 @@ class LoginProfileTest : public LoginTestBase {
}
virtual void SetUpCommandLine(CommandLine* command_line) {
- command_line->AppendSwitchWithValue(switches::kLoginProfile, "user");
+ command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
command_line->AppendSwitch(switches::kNoFirstRun);
}
};
diff --git a/chrome/browser/chromeos/login/login_html_dialog.cc b/chrome/browser/chromeos/login/login_html_dialog.cc
index a895626..a05c7de 100644
--- a/chrome/browser/chromeos/login/login_html_dialog.cc
+++ b/chrome/browser/chromeos/login/login_html_dialog.cc
@@ -4,18 +4,35 @@
#include "chrome/browser/chromeos/login/login_html_dialog.h"
+#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/views/browser_dialogs.h"
+#include "chrome/browser/views/html_dialog_view.h"
#include "gfx/native_widget_types.h"
+#include "gfx/rect.h"
#include "gfx/size.h"
#include "views/window/window.h"
namespace chromeos {
namespace {
+// Default width/height ratio of screen size.
+const float kDefaultWidthRatio = 0.8;
+const float kDefaultHeightRatio = 0.8;
-const int kDefaultWidth = 800;
-const int kDefaultHeight = 600;
+// Custom HtmlDialogView with disabled context menu.
+class HtmlDialogWithoutContextMenuView : public HtmlDialogView {
+ public:
+ HtmlDialogWithoutContextMenuView(Profile* profile,
+ HtmlDialogUIDelegate* delegate)
+ : HtmlDialogView(profile, delegate) {}
+ virtual ~HtmlDialogWithoutContextMenuView() {}
+
+ // TabContentsDelegate implementation.
+ bool HandleContextMenu(const ContextMenuParams& params) {
+ // Disable context menu.
+ return true;
+ }
+};
} // namespace
@@ -30,6 +47,9 @@ LoginHtmlDialog::LoginHtmlDialog(Delegate* delegate,
parent_window_(parent_window),
title_(title),
url_(url) {
+ gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size(0, 0)));
+ width_ = static_cast<int>(kDefaultWidthRatio * screen_bounds.width());
+ height_ = static_cast<int>(kDefaultHeightRatio * screen_bounds.height());
}
LoginHtmlDialog::~LoginHtmlDialog() {
@@ -37,9 +57,18 @@ LoginHtmlDialog::~LoginHtmlDialog() {
}
void LoginHtmlDialog::Show() {
- browser::ShowHtmlDialogView(parent_window_,
- ProfileManager::GetDefaultProfile(),
- this);
+ HtmlDialogWithoutContextMenuView* html_view =
+ new HtmlDialogWithoutContextMenuView(ProfileManager::GetDefaultProfile(),
+ this);
+ views::Window::CreateChromeWindow(parent_window_, gfx::Rect(), html_view);
+ html_view->InitDialog();
+ html_view->window()->Show();
+}
+
+void LoginHtmlDialog::SetDialogSize(int width, int height) {
+ DCHECK(width >= 0 && height >= 0);
+ width_ = width;
+ height_ = height;
}
///////////////////////////////////////////////////////////////////////////////
@@ -57,7 +86,7 @@ void LoginHtmlDialog::OnCloseContents(TabContents* source,
}
void LoginHtmlDialog::GetDialogSize(gfx::Size* size) const {
- size->SetSize(kDefaultWidth, kDefaultHeight);
+ size->SetSize(width_, height_);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_html_dialog.h b/chrome/browser/chromeos/login/login_html_dialog.h
index 81c6628..367bb56 100644
--- a/chrome/browser/chromeos/login/login_html_dialog.h
+++ b/chrome/browser/chromeos/login/login_html_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_HTML_DIALOG_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_HTML_DIALOG_H_
+#pragma once
#include <string>
@@ -34,6 +35,11 @@ class LoginHtmlDialog : public HtmlDialogUIDelegate {
// Shows created dialog.
void Show();
+ // Overrides default width/height for dialog.
+ void SetDialogSize(int width, int height);
+
+ void set_url(const GURL& url) { url_ = url; }
+
protected:
// HtmlDialogUIDelegate implementation.
virtual bool IsDialogModal() const { return true; }
@@ -54,6 +60,10 @@ class LoginHtmlDialog : public HtmlDialogUIDelegate {
std::wstring title_;
GURL url_;
+ // Dialog display size.
+ int width_;
+ int height_;
+
DISALLOW_COPY_AND_ASSIGN(LoginHtmlDialog);
};
diff --git a/chrome/browser/chromeos/login/login_screen.cc b/chrome/browser/chromeos/login/login_screen.cc
index 9e1d886..6f34d0e 100644
--- a/chrome/browser/chromeos/login/login_screen.cc
+++ b/chrome/browser/chromeos/login/login_screen.cc
@@ -17,12 +17,14 @@
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/login/authentication_notification_details.h"
+#include "chrome/browser/chromeos/login/helper.h"
#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 "grit/generated_resources.h"
#include "grit/theme_resources.h"
namespace chromeos {
@@ -41,7 +43,7 @@ LoginScreen::~LoginScreen() {
}
NewUserView* LoginScreen::AllocateView() {
- return new NewUserView(this, true);
+ return new NewUserView(this, true, true);
}
void LoginScreen::OnLogin(const std::string& username,
@@ -73,7 +75,8 @@ void LoginScreen::ClearErrors() {
bubble_->Close();
}
-void LoginScreen::OnLoginFailure(const std::string& error) {
+void LoginScreen::OnLoginFailure(const LoginFailure& failure) {
+ const std::string error = failure.GetErrorString();
LOG(INFO) << "LoginManagerView: OnLoginFailure() " << error;
NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
@@ -84,7 +87,7 @@ void LoginScreen::OnLoginFailure(const std::string& error) {
} else if (!network->Connected()) {
ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
} else {
- ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
+ ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error);
}
view()->ClearAndEnablePassword();
@@ -100,28 +103,32 @@ void LoginScreen::OnLoginSuccess(const std::string& username,
void LoginScreen::OnOffTheRecordLoginSuccess() {
delegate()->GetObserver(this)->OnExit(ScreenObserver::LOGIN_GUEST_SELECTED);
- AppendStartUrlToCmdline();
- LoginUtils::Get()->CompleteOffTheRecordLogin();
+}
+
+void LoginScreen::OnHelpLinkActivated() {
+ AddStartUrl(GetAccountRecoveryHelpUrl());
+ OnLoginOffTheRecord();
}
void LoginScreen::AppendStartUrlToCmdline() {
- if (start_url_.is_valid()) {
- CommandLine::ForCurrentProcess()->AppendLooseValue(
- UTF8ToWide(start_url_.spec()));
- }
+ if (start_url_.is_valid())
+ CommandLine::ForCurrentProcess()->AppendArg(start_url_.spec());
}
void LoginScreen::ShowError(int error_id, const std::string& details) {
ClearErrors();
std::wstring error_text = l10n_util::GetString(error_id);
- if (!details.empty())
- error_text += L"\n" + ASCIIToWide(details);
+ // TODO(dpolukhin): show detailed error info. |details| string contains
+ // low level error info that is not localized and even is not user friendly.
+ // For now just ignore it because error_text contains all required information
+ // for end users, developers can see details string in Chrome logs.
bubble_ = MessageBubble::Show(
view()->GetWidget(),
view()->GetPasswordBounds(),
BubbleBorder::LEFT_TOP,
ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
error_text,
+ l10n_util::GetString(IDS_CANT_ACCESS_ACCOUNT_BUTTON),
this);
}
diff --git a/chrome/browser/chromeos/login/login_screen.h b/chrome/browser/chromeos/login/login_screen.h
index 3b3645c..59bcd0e 100644
--- a/chrome/browser/chromeos/login/login_screen.h
+++ b/chrome/browser/chromeos/login/login_screen.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_SCREEN_H_
+#pragma once
#include <string>
#include "base/ref_counted.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
+#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/new_user_view.h"
#include "chrome/browser/chromeos/login/view_screen.h"
-#include "chrome/browser/views/info_bubble.h"
namespace chromeos {
@@ -21,7 +22,7 @@ class MessageBubble;
class LoginScreen : public ViewScreen<NewUserView>,
public NewUserView::Delegate,
public LoginStatusConsumer,
- public InfoBubbleDelegate {
+ public MessageBubbleDelegate {
public:
explicit LoginScreen(WizardScreenDelegate* delegate);
virtual ~LoginScreen();
@@ -37,9 +38,10 @@ class LoginScreen : public ViewScreen<NewUserView>,
virtual void OnCreateAccount();
virtual void AddStartUrl(const GURL& start_url) { start_url_ = start_url; }
virtual void ClearErrors();
+ virtual void NavigateAway() {}
// Overridden from LoginStatusConsumer.
- virtual void OnLoginFailure(const std::string& error);
+ virtual void OnLoginFailure(const LoginFailure& error);
virtual void OnLoginSuccess(const std::string& username,
const GaiaAuthConsumer::ClientLoginResult& credentials);
virtual void OnOffTheRecordLoginSuccess();
@@ -51,6 +53,7 @@ class LoginScreen : public ViewScreen<NewUserView>,
}
virtual bool CloseOnEscape() { return true; }
virtual bool FadeInOnShow() { return false; }
+ virtual void OnHelpLinkActivated();
private:
// ViewScreen<NewUserView>:
diff --git a/chrome/browser/chromeos/login/login_screen_browsertest.cc b/chrome/browser/chromeos/login/login_screen_browsertest.cc
index 3184426..35425e3 100644
--- a/chrome/browser/chromeos/login/login_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_screen_browsertest.cc
@@ -28,21 +28,31 @@ const char kPassword[] = "test_password";
class LoginScreenTest : public WizardInProcessBrowserTest {
public:
- LoginScreenTest(): WizardInProcessBrowserTest("login") {
+ LoginScreenTest(): WizardInProcessBrowserTest("login"),
+ mock_cryptohome_library_(NULL),
+ mock_login_library_(NULL),
+ mock_network_library_(NULL) {
}
protected:
+ MockCryptohomeLibrary *mock_cryptohome_library_;
+ MockLoginLibrary *mock_login_library_;
+ MockNetworkLibrary *mock_network_library_;
+
virtual void SetUpInProcessBrowserTestFixture() {
WizardInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
- InitStatusAreaMocks();
- SetStatusAreaMocksExpectations();
+ cros_mock_->InitStatusAreaMocks();
+ cros_mock_->SetStatusAreaMocksExpectations();
+
+ mock_network_library_ = cros_mock_->mock_network_library();
mock_login_library_ = new MockLoginLibrary();
EXPECT_CALL(*mock_login_library_, EmitLoginPromptReady())
.Times(1);
- test_api()->SetLoginLibrary(mock_login_library_, true);
+ cros_mock_->test_api()->SetLoginLibrary(mock_login_library_, true);
- InitMockCryptohomeLibrary();
+ cros_mock_->InitMockCryptohomeLibrary();
+ mock_cryptohome_library_ = cros_mock_->mock_cryptohome_library();
EXPECT_CALL(*mock_cryptohome_library_, IsMounted())
.Times(AnyNumber())
.WillRepeatedly((Return(true)));
@@ -51,12 +61,10 @@ class LoginScreenTest : public WizardInProcessBrowserTest {
virtual void TearDownInProcessBrowserTestFixture() {
WizardInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
- test_api()->SetLoginLibrary(NULL, false);
+ cros_mock_->test_api()->SetLoginLibrary(NULL, false);
}
private:
- MockLoginLibrary* mock_login_library_;
-
DISALLOW_COPY_AND_ASSIGN(LoginScreenTest);
};
@@ -77,10 +85,6 @@ IN_PROC_BROWSER_TEST_F(LoginScreenTest, TestBasic) {
controller()->set_observer(mock_screen_observer.get());
NewUserView* login = controller()->GetLoginScreen()->view();
- // NOTE: When adding new controls check RecreateNativeControls()
- // that |sign_in_button_| is added with correct index.
- // See kSignInButtonFocusOrderIndex constant.
- EXPECT_EQ(9, login->GetChildViewCount());
login->SetUsername(kUsername);
login->SetPassword(kPassword);
diff --git a/chrome/browser/chromeos/login/login_status_consumer.h b/chrome/browser/chromeos/login/login_status_consumer.h
index 1fa0104..b762e38 100644
--- a/chrome/browser/chromeos/login/login_status_consumer.h
+++ b/chrome/browser/chromeos/login/login_status_consumer.h
@@ -4,19 +4,95 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_STATUS_CONSUMER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_STATUS_CONSUMER_H_
+#pragma once
#include <string>
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "net/base/net_errors.h"
namespace chromeos {
+class LoginFailure {
+ public:
+ enum FailureReason {
+ NONE,
+ COULD_NOT_MOUNT_CRYPTOHOME,
+ COULD_NOT_MOUNT_TMPFS,
+ DATA_REMOVAL_FAILED, // Could not destroy your old data
+ LOGIN_TIMED_OUT,
+ UNLOCK_FAILED,
+ NETWORK_AUTH_FAILED, // Could not authenticate against Google
+ };
+
+ explicit LoginFailure(FailureReason reason)
+ : reason_(reason),
+ error_(GoogleServiceAuthError::NONE) {
+ DCHECK(reason != NETWORK_AUTH_FAILED);
+ }
+
+ inline bool operator==(const LoginFailure &b) const {
+ if (reason_ != b.reason_) {
+ return false;
+ }
+ if (reason_ == NETWORK_AUTH_FAILED) {
+ return error_ == b.error_;
+ }
+ return true;
+ }
+
+ static LoginFailure FromNetworkAuthFailure(
+ const GoogleServiceAuthError& error) {
+ return LoginFailure(NETWORK_AUTH_FAILED, error);
+ }
+
+ static LoginFailure None() {
+ return LoginFailure(NONE);
+ }
+
+ const std::string GetErrorString() const {
+ switch (reason_) {
+ case DATA_REMOVAL_FAILED:
+ return "Could not destroy your old data.";
+ case COULD_NOT_MOUNT_CRYPTOHOME:
+ return "Could not mount cryptohome.";
+ case COULD_NOT_MOUNT_TMPFS:
+ return "Could not mount tmpfs.";
+ case LOGIN_TIMED_OUT:
+ return "Login timed out. Please try again.";
+ case UNLOCK_FAILED:
+ return "Unlock failed.";
+ case NETWORK_AUTH_FAILED:
+ if (error_.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
+ return net::ErrorToString(error_.network_error());
+ }
+ return "Google authentication failed.";
+ default:
+ NOTREACHED();
+ return std::string();
+ }
+ }
+
+ const GoogleServiceAuthError& error() const { return error_; }
+ const FailureReason& reason() const { return reason_; }
+
+ private:
+ LoginFailure(FailureReason reason, GoogleServiceAuthError error)
+ : reason_(reason),
+ error_(error) {
+ }
+
+ FailureReason reason_;
+ GoogleServiceAuthError error_;
+};
+
// An interface that defines the callbacks for objects that the
// Authenticator class will call to report the success/failure of
// authentication for Chromium OS.
class LoginStatusConsumer {
public:
virtual ~LoginStatusConsumer() {}
- virtual void OnLoginFailure(const std::string& error) = 0;
+ virtual void OnLoginFailure(const LoginFailure& error) = 0;
virtual void OnLoginSuccess(const std::string& username,
const GaiaAuthConsumer::ClientLoginResult& credentials) = 0;
virtual void OnOffTheRecordLoginSuccess() {}
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index d8a9fbf..30bed68 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -8,32 +8,33 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/lock.h"
-#include "base/nss_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
+#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_init.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/login_library.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/external_cookie_handler.h"
+#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/login/cookie_fetcher.h"
#include "chrome/browser/chromeos/login/google_authenticator.h"
+#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/login/user_image_downloader.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
-#include "chrome/common/logging_chrome.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/logging_chrome.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/net/url_request_context_getter.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/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "net/base/cookie_store.h"
#include "net/url_request/url_request_context.h"
@@ -43,7 +44,6 @@ namespace chromeos {
namespace {
-static char kIncognitoUser[] = "incognito";
// Prefix for Auth token received from ClientLogin request.
const char kAuthPrefix[] = "Auth=";
@@ -52,15 +52,10 @@ const char kAuthSuffix[] = "\n";
} // namespace
-class LoginUtilsImpl : public LoginUtils,
- public NotificationObserver {
+class LoginUtilsImpl : public LoginUtils {
public:
LoginUtilsImpl()
: browser_launch_enabled_(true) {
- registrar_.Add(
- this,
- NotificationType::LOGIN_USER_CHANGED,
- NotificationService::AllSources());
}
// Invoked after the user has successfully logged in. This launches a browser
@@ -70,7 +65,7 @@ class LoginUtilsImpl : public LoginUtils,
// Invoked after the tmpfs is successfully mounted.
// Launches a browser in the off the record (incognito) mode.
- virtual void CompleteOffTheRecordLogin();
+ virtual void CompleteOffTheRecordLogin(const GURL& start_url);
// Creates and returns the authenticator to use. The caller owns the returned
// Authenticator and must delete it when done.
@@ -86,17 +81,7 @@ class LoginUtilsImpl : public LoginUtils,
// Returns auth token for 'cp' Contacts service.
virtual const std::string& GetAuthToken() const { return auth_token_; }
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
private:
- // Attempt to connect to the preferred network if available.
- void ConnectToPreferredNetwork();
-
- NotificationRegistrar registrar_;
-
// Indicates if DoBrowserLaunch will actually launch the browser or not.
bool browser_launch_enabled_;
@@ -137,8 +122,8 @@ void LoginUtilsImpl::CompleteLogin(const std::string& username,
if (CrosLibrary::Get()->EnsureLoaded())
CrosLibrary::Get()->GetLoginLibrary()->StartSession(username, "");
+ bool first_login = !UserManager::Get()->IsKnownUser(username);
UserManager::Get()->UserLoggedIn(username);
- ConnectToPreferredNetwork();
// Now launch the initial browser window.
FilePath user_data_dir;
@@ -153,8 +138,23 @@ void LoginUtilsImpl::CompleteLogin(const std::string& username,
*(CommandLine::ForCurrentProcess()),
logging::DELETE_OLD_LOG_FILE);
- // Supply credentials for sync and others to use
- profile->GetTokenService()->SetClientLoginResult(credentials);
+ // Supply credentials for sync and others to use. Load tokens from disk.
+ TokenService* token_service = profile->GetTokenService();
+ token_service->Initialize(GaiaConstants::kChromeOSSource,
+ profile);
+ token_service->LoadTokensFromDB();
+ token_service->UpdateCredentials(credentials);
+ if (token_service->AreCredentialsValid()) {
+ token_service->StartFetchingTokens();
+ }
+
+ // Set the CrOS user by getting this constructor run with the
+ // user's email on first retrieval.
+ profile->GetProfileSyncService(username);
+
+ // Attempt to take ownership; this will fail if device is already owned.
+ OwnershipService::GetSharedInstance()->StartTakeOwnershipAttempt(
+ UserManager::Get()->logged_in_user().email());
// Take the credentials passed in and try to exchange them for
// full-fledged Google authentication cookies. This is
@@ -165,21 +165,77 @@ void LoginUtilsImpl::CompleteLogin(const std::string& username,
CookieFetcher* cf = new CookieFetcher(profile);
cf->AttemptFetch(credentials.data);
auth_token_ = credentials.token;
+
+ 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);
+ }
+ }
}
-void LoginUtilsImpl::CompleteOffTheRecordLogin() {
+void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
LOG(INFO) << "Completing off the record login";
- if (CrosLibrary::Get()->EnsureLoaded())
- CrosLibrary::Get()->GetLoginLibrary()->StartSession(kIncognitoUser, "");
-
- // Incognito flag is not set by default.
- CommandLine::ForCurrentProcess()->AppendSwitch(switches::kIncognito);
-
UserManager::Get()->OffTheRecordUserLoggedIn();
- ConnectToPreferredNetwork();
- LoginUtils::DoBrowserLaunch(
- ProfileManager::GetDefaultProfile()->GetOffTheRecordProfile());
+
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ // For BWSI we ask session manager to restart Chrome with --bwsi flag.
+ // We keep only some of the arguments of this process.
+ static const char* kForwardSwitches[] = {
+ switches::kLoggingLevel,
+ switches::kEnableLogging,
+ switches::kUserDataDir,
+ switches::kScrollPixels,
+ switches::kEnableGView,
+ switches::kNoFirstRun,
+ switches::kLoginProfile
+ };
+ const CommandLine& browser_command_line =
+ *CommandLine::ForCurrentProcess();
+ CommandLine command_line(browser_command_line.GetProgram());
+ command_line.CopySwitchesFrom(browser_command_line,
+ kForwardSwitches,
+ arraysize(kForwardSwitches));
+ command_line.AppendSwitch(switches::kBWSI);
+ command_line.AppendSwitch(switches::kIncognito);
+ command_line.AppendSwitch(switches::kEnableTabbedOptions);
+ command_line.AppendSwitchASCII(
+ switches::kLoginUser,
+ UserManager::Get()->logged_in_user().email());
+ if (start_url.is_valid())
+ command_line.AppendArg(start_url.spec());
+ CrosLibrary::Get()->GetLoginLibrary()->RestartJob(
+ getpid(),
+ command_line.command_line_string());
+ }
}
Authenticator* LoginUtilsImpl::CreateAuthenticator(
@@ -195,18 +251,6 @@ bool LoginUtilsImpl::IsBrowserLaunchEnabled() const {
return browser_launch_enabled_;
}
-void LoginUtilsImpl::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::LOGIN_USER_CHANGED)
- base::OpenPersistentNSSDB();
-}
-
-void LoginUtilsImpl::ConnectToPreferredNetwork() {
- CrosLibrary::Get()->GetNetworkLibrary()->
- ConnectToPreferredNetworkIfAvailable();
-}
-
LoginUtils* LoginUtils::Get() {
return Singleton<LoginUtilsWrapper>::get()->get();
}
@@ -229,23 +273,9 @@ void LoginUtils::DoBrowserLaunch(Profile* profile) {
int return_code;
browser_init.LaunchBrowser(*CommandLine::ForCurrentProcess(),
profile,
- std::wstring(),
+ FilePath(),
true,
&return_code);
}
-std::string LoginUtils::ExtractClientLoginParam(
- const std::string& credentials,
- const std::string& param_prefix,
- const std::string& param_suffix) {
- size_t start = credentials.find(param_prefix);
- if (start == std::string::npos)
- return std::string();
- start += param_prefix.size();
- size_t end = credentials.find(param_suffix, start);
- if (end == std::string::npos)
- return std::string();
- return credentials.substr(start, end - start);
-}
-
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_utils.h b/chrome/browser/chromeos/login/login_utils.h
index 757fd21..b23c60d 100644
--- a/chrome/browser/chromeos/login/login_utils.h
+++ b/chrome/browser/chromeos/login/login_utils.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_UTILS_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_UTILS_H_
+#pragma once
#include <string>
-#include <vector>
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+class GURL;
class Profile;
namespace chromeos {
@@ -30,13 +31,6 @@ class LoginUtils {
// Task posted to the UI thread.
static void DoBrowserLaunch(Profile* profile);
- // Extracts specified param from given ClientLogin response.
- // Returns the param value if found, empty string otherwise.
- // Ex. prefix: "Auth=", suffix: "\n"
- static std::string ExtractClientLoginParam(const std::string& credentials,
- const std::string& param_prefix,
- const std::string& param_suffix);
-
virtual ~LoginUtils() {}
// Invoked after the user has successfully logged in. This launches a browser
@@ -45,8 +39,9 @@ class LoginUtils {
const GaiaAuthConsumer::ClientLoginResult& credentials) = 0;
// Invoked after the tmpfs is successfully mounted.
- // Launches a browser in the off the record (incognito) mode.
- virtual void CompleteOffTheRecordLogin() = 0;
+ // 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;
// Creates and returns the authenticator to use. The caller owns the returned
// Authenticator and must delete it when done.
diff --git a/chrome/browser/chromeos/login/message_bubble.cc b/chrome/browser/chromeos/login/message_bubble.cc
index 3c69f89..82cb775 100644
--- a/chrome/browser/chromeos/login/message_bubble.cc
+++ b/chrome/browser/chromeos/login/message_bubble.cc
@@ -19,10 +19,17 @@ namespace chromeos {
static const int kBorderSize = 4;
static const int kMaxLabelWidth = 250;
-MessageBubble::MessageBubble(views::WidgetGtk::Type type, views::Widget* parent,
- SkBitmap* image, const std::wstring& text, bool grab_enabled)
+MessageBubble::MessageBubble(views::WidgetGtk::Type type,
+ views::Widget* parent,
+ SkBitmap* image,
+ const std::wstring& text,
+ const std::wstring& help,
+ bool grab_enabled,
+ MessageBubbleDelegate* delegate)
: InfoBubble(type),
parent_(parent),
+ help_link_(NULL),
+ message_delegate_(delegate),
grab_enabled_(grab_enabled) {
using views::GridLayout;
@@ -38,6 +45,12 @@ MessageBubble::MessageBubble(views::WidgetGtk::Type type, views::Widget* parent,
column_set->AddPaddingColumn(0, kBorderSize);
column_set->AddColumn(GridLayout::TRAILING, GridLayout::LEADING, 0,
GridLayout::USE_PREF, 0, 0);
+ if (!help.empty()) {
+ column_set = layout->AddColumnSet(1);
+ column_set->AddPaddingColumn(0, kBorderSize + image->width());
+ column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 1,
+ GridLayout::USE_PREF, 0, 0);
+ }
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
@@ -60,6 +73,13 @@ MessageBubble::MessageBubble(views::WidgetGtk::Type type, views::Widget* parent,
close_button_->SetImage(views::CustomButton::BS_PUSHED,
rb.GetBitmapNamed(IDR_CLOSE_BAR_P));
layout->AddView(close_button_);
+
+ if (!help.empty()) {
+ layout->StartRowWithPadding(0, 1, 0, kBorderSize);
+ help_link_ = new views::Link(help);
+ help_link_->SetController(this);
+ layout->AddView(help_link_);
+ }
}
void MessageBubble::ButtonPressed(views::Button* sender,
@@ -71,16 +91,26 @@ void MessageBubble::ButtonPressed(views::Button* sender,
}
}
+void MessageBubble::LinkActivated(views::Link* source, int event_flags) {
+ if (source == help_link_) {
+ if (message_delegate_)
+ message_delegate_->OnHelpLinkActivated();
+ } else {
+ NOTREACHED() << "Unknown view";
+ }
+}
+
// static
MessageBubble* MessageBubble::Show(views::Widget* parent,
const gfx::Rect& position_relative_to,
BubbleBorder::ArrowLocation arrow_location,
SkBitmap* image,
const std::wstring& text,
- InfoBubbleDelegate* delegate) {
+ const std::wstring& help,
+ MessageBubbleDelegate* delegate) {
// The bubble will be destroyed when it is closed.
MessageBubble* bubble = new MessageBubble(
- views::WidgetGtk::TYPE_WINDOW, parent, image, text, true);
+ views::WidgetGtk::TYPE_WINDOW, parent, image, text, help, true, delegate);
bubble->Init(parent, position_relative_to, arrow_location,
bubble->text_->GetParent(), delegate);
return bubble;
@@ -93,10 +123,11 @@ MessageBubble* MessageBubble::ShowNoGrab(
BubbleBorder::ArrowLocation arrow_location,
SkBitmap* image,
const std::wstring& text,
- InfoBubbleDelegate* delegate) {
+ const std::wstring& help,
+ MessageBubbleDelegate* delegate) {
// The bubble will be destroyed when it is closed.
MessageBubble* bubble = new MessageBubble(
- views::WidgetGtk::TYPE_CHILD, parent, image, text, false);
+ views::WidgetGtk::TYPE_CHILD, parent, image, text, help, false, delegate);
bubble->Init(parent, position_relative_to, arrow_location,
bubble->text_->GetParent(), delegate);
return bubble;
diff --git a/chrome/browser/chromeos/login/message_bubble.h b/chrome/browser/chromeos/login/message_bubble.h
index d265ac1..f29ecf8 100644
--- a/chrome/browser/chromeos/login/message_bubble.h
+++ b/chrome/browser/chromeos/login/message_bubble.h
@@ -4,9 +4,11 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MESSAGE_BUBBLE_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_MESSAGE_BUBBLE_H_
+#pragma once
#include "chrome/browser/views/info_bubble.h"
#include "views/controls/button/button.h"
+#include "views/controls/link.h"
#include "views/view.h"
#include "views/widget/widget_gtk.h"
@@ -20,9 +22,16 @@ class Label;
namespace chromeos {
+class MessageBubbleDelegate : public InfoBubbleDelegate {
+ public:
+ // Called when the user clicked on help link.
+ virtual void OnHelpLinkActivated() = 0;
+};
+
// MessageBubble is used to show error and info messages on OOBE screens.
class MessageBubble : public InfoBubble,
- public views::ButtonListener {
+ public views::ButtonListener,
+ public views::LinkController {
public:
// Create and show bubble. position_relative_to must be in screen coordinates.
static MessageBubble* Show(views::Widget* parent,
@@ -30,7 +39,8 @@ class MessageBubble : public InfoBubble,
BubbleBorder::ArrowLocation arrow_location,
SkBitmap* image,
const std::wstring& text,
- InfoBubbleDelegate* delegate);
+ const std::wstring& help,
+ MessageBubbleDelegate* delegate);
// Create and show bubble which does not grab pointer. This creates
// a TYPE_CHILD WidgetGtk and |position_relative_to| must be in parent's
@@ -40,7 +50,8 @@ class MessageBubble : public InfoBubble,
BubbleBorder::ArrowLocation arrow_location,
SkBitmap* image,
const std::wstring& text,
- InfoBubbleDelegate* delegate);
+ const std::wstring& help,
+ MessageBubbleDelegate* delegate);
// Overridden from WidgetGtk.
virtual void Close();
@@ -52,23 +63,32 @@ class MessageBubble : public InfoBubble,
}
protected:
- // views::ButtonListener implmenets.
+ // Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender,
const views::Event& event);
+ // Overridden from views::LinkController:
+ virtual void LinkActivated(views::Link* source, int event_flags);
+
// Overridden from WidgetGtk.
virtual void IsActiveChanged();
virtual void DoGrab();
private:
MessageBubble(views::WidgetGtk::Type type,
- views::Widget* parent, SkBitmap* image,
- const std::wstring& text, bool grab_enabled);
+ views::Widget* parent,
+ SkBitmap* image,
+ const std::wstring& text,
+ const std::wstring& help,
+ bool grab_enabled,
+ MessageBubbleDelegate* delegate);
views::Widget* parent_;
views::ImageView* icon_;
views::Label* text_;
views::ImageButton* close_button_;
+ views::Link* help_link_;
+ MessageBubbleDelegate* message_delegate_;
bool grab_enabled_;
DISALLOW_COPY_AND_ASSIGN(MessageBubble);
diff --git a/chrome/browser/chromeos/login/mock_auth_response_handler.h b/chrome/browser/chromeos/login/mock_auth_response_handler.h
index 81c33b2..db4651a 100644
--- a/chrome/browser/chromeos/login/mock_auth_response_handler.h
+++ b/chrome/browser/chromeos/login/mock_auth_response_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_AUTH_RESPONSE_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_AUTH_RESPONSE_HANDLER_H_
+#pragma once
#include "chrome/browser/chromeos/login/auth_response_handler.h"
diff --git a/chrome/browser/chromeos/login/mock_authenticator.h b/chrome/browser/chromeos/login/mock_authenticator.h
index 788708a..31a8542 100644
--- a/chrome/browser/chromeos/login/mock_authenticator.h
+++ b/chrome/browser/chromeos/login/mock_authenticator.h
@@ -4,11 +4,14 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_AUTHENTICATOR_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_AUTHENTICATOR_H_
+#pragma once
#include <string>
+#include "chrome/browser/chrome_thread.h"
#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"
#include "testing/gtest/include/gtest/gtest.h"
class Profile;
@@ -43,11 +46,13 @@ class MockAuthenticator : public Authenticator {
GaiaAuthConsumer::ClientLoginResult()));
return true;
} else {
+ GoogleServiceAuthError error(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this,
&MockAuthenticator::OnLoginFailure,
- std::string("Login failed")));
+ LoginFailure::FromNetworkAuthFailure(error)));
return false;
}
}
@@ -68,8 +73,8 @@ class MockAuthenticator : public Authenticator {
consumer_->OnLoginSuccess(expected_username_, credentials);
}
- void OnLoginFailure(const std::string& data) {
- consumer_->OnLoginFailure(data);
+ void OnLoginFailure(const LoginFailure& failure) {
+ consumer_->OnLoginFailure(failure);
LOG(INFO) << "Posting a QuitTask to UI thread";
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE, new MessageLoop::QuitTask);
@@ -106,7 +111,7 @@ class MockLoginUtils : public LoginUtils {
EXPECT_EQ(expected_username_, username);
}
- virtual void CompleteOffTheRecordLogin() {
+ virtual void CompleteOffTheRecordLogin(const GURL& start_url) {
}
virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer) {
diff --git a/chrome/browser/chromeos/login/mock_screen_observer.h b/chrome/browser/chromeos/login/mock_screen_observer.h
index 1df4106..951c045 100644
--- a/chrome/browser/chromeos/login/mock_screen_observer.h
+++ b/chrome/browser/chromeos/login/mock_screen_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_SCREEN_OBSERVER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_SCREEN_OBSERVER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/mock_update_screen.h b/chrome/browser/chromeos/login/mock_update_screen.h
index 2e6beb2..ad34cb8 100644
--- a/chrome/browser/chromeos/login/mock_update_screen.h
+++ b/chrome/browser/chromeos/login/mock_update_screen.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_UPDATE_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_UPDATE_SCREEN_H_
+#pragma once
#include "chrome/browser/chromeos/login/update_screen.h"
#include "chrome/browser/chromeos/login/view_screen.h"
diff --git a/chrome/browser/chromeos/login/network_screen.cc b/chrome/browser/chromeos/login/network_screen.cc
index 2851966..9b4414d 100644
--- a/chrome/browser/chromeos/login/network_screen.cc
+++ b/chrome/browser/chromeos/login/network_screen.cc
@@ -5,12 +5,17 @@
#include "chrome/browser/chromeos/login/network_screen.h"
#include "app/l10n_util.h"
-#include "base/utf_string_conversions.h"
+#include "app/resource_bundle.h"
#include "base/logging.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/login/help_app_launcher.h"
#include "chrome/browser/chromeos/login/network_selection_view.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
+#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
#include "views/widget/widget.h"
#include "views/window/window.h"
@@ -20,6 +25,10 @@ namespace {
// Time in seconds for connection timeout.
const int kConnectionTimeoutSec = 15;
+// Considering 10px shadow from each side & welcome title height at 30px.
+const int kWelcomeScreenWidth = 580;
+const int kWelcomeScreenHeight = 335;
+
} // namespace
namespace chromeos {
@@ -27,15 +36,13 @@ namespace chromeos {
///////////////////////////////////////////////////////////////////////////////
// NetworkScreen, public:
-NetworkScreen::NetworkScreen(WizardScreenDelegate* delegate, bool is_out_of_box)
- : ViewScreen<NetworkSelectionView>(delegate),
+NetworkScreen::NetworkScreen(WizardScreenDelegate* delegate)
+ : ViewScreen<NetworkSelectionView>(delegate,
+ kWelcomeScreenWidth,
+ kWelcomeScreenHeight),
is_network_subscribed_(false),
- wifi_disabled_(false),
- is_out_of_box_(is_out_of_box),
- is_waiting_for_connect_(false),
continue_pressed_(false),
- ethernet_preselected_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
+ bubble_(NULL) {
}
NetworkScreen::~NetworkScreen() {
@@ -44,60 +51,12 @@ NetworkScreen::~NetworkScreen() {
}
////////////////////////////////////////////////////////////////////////////////
-// ComboboxModel implementation:
-
-int NetworkScreen::GetItemCount() {
- // Item with index = 0 is either "no networks are available" or
- // "no selection".
- // If WiFi is disabled adding extra item to enable it.
- return static_cast<int>(networks_.GetNetworkCount()) + 1 +
- (wifi_disabled_ ? 1 : 0);
-}
-
-std::wstring NetworkScreen::GetItemAt(int index) {
- if (index == 0) {
- return networks_.IsEmpty() ?
- l10n_util::GetString(IDS_STATUSBAR_NO_NETWORKS_MESSAGE) :
- l10n_util::GetString(IDS_NETWORK_SELECTION_NONE);
- }
- if (wifi_disabled_ &&
- index == static_cast<int>(networks_.GetNetworkCount()) + 1) {
- return l10n_util::GetStringF(
- IDS_STATUSBAR_NETWORK_DEVICE_ENABLE,
- l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_WIFI));
- }
- NetworkList::NetworkItem* network =
- networks_.GetNetworkAt(index - 1);
- return network ? UTF16ToWide(network->label) : std::wstring();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// views::Combobox::Listener implementation:
-
-void NetworkScreen::ItemChanged(views::Combobox* sender,
- int prev_index,
- int new_index) {
- view()->EnableContinue(new_index > 0);
- // Corner case: item with index 0 is "No selection". Just select it.
- if (new_index == prev_index || new_index <= 0 || prev_index < 0)
- return;
-
- if (wifi_disabled_ &&
- new_index == static_cast<int>(networks_.GetNetworkCount()) + 1) {
- view()->EnableContinue(false);
- MessageLoop::current()->PostTask(FROM_HERE,
- task_factory_.NewRunnableMethod(&NetworkScreen::EnableWiFi));
- return;
- }
-
- if (networks_.IsEmpty())
- return;
+// NetworkScreen, NetworkScreenDelegate implementation:
- // Connect to network as early as possible.
- const NetworkList::NetworkItem* network =
- networks_.GetNetworkAt(new_index - 1);
- MessageLoop::current()->PostTask(FROM_HERE, task_factory_.NewRunnableMethod(
- &NetworkScreen::ConnectToNetwork, network->network_type, network->label));
+void NetworkScreen::ClearErrors() {
+ // bubble_ will be set to NULL in callback.
+ if (bubble_)
+ bubble_->Close();
}
///////////////////////////////////////////////////////////////////////////////
@@ -105,24 +64,13 @@ void NetworkScreen::ItemChanged(views::Combobox* sender,
void NetworkScreen::ButtonPressed(views::Button* sender,
const views::Event& event) {
- // Proceed only when selected network is connected.
- const NetworkList::NetworkItem* network = GetSelectedNetwork();
- if (!network)
- return;
- if (networks_.IsNetworkConnected(network->network_type, network->label)) {
- MessageLoop::current()->PostTask(FROM_HERE,
- task_factory_.NewRunnableMethod(&NetworkScreen::NotifyOnConnection));
+ ClearErrors();
+ NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
+ if (network && network->Connected()) {
+ NotifyOnConnection();
} else {
continue_pressed_ = true;
- if (is_waiting_for_connect_) {
- ShowConnectingStatus();
- } else {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- task_factory_.NewRunnableMethod(&NetworkScreen::ConnectToNetwork,
- network->network_type,
- network->label));
- }
+ WaitForConnection(network_id_);
}
}
@@ -130,58 +78,7 @@ void NetworkScreen::ButtonPressed(views::Button* sender,
// NetworkLibrary::Observer implementation:
void NetworkScreen::NetworkChanged(NetworkLibrary* network_lib) {
- if (!view())
- return;
-
- // TODO(nkostylev): Reuse network menu button - http://crosbug.com/4133
- wifi_disabled_ = !chromeos::CrosLibrary::Get()->
- GetNetworkLibrary()->wifi_enabled();
-
- // Save network selection in case it would be available after refresh.
- NetworkList::NetworkType network_type = NetworkList::NETWORK_EMPTY;
- string16 network_id;
- const NetworkList::NetworkItem* selected_network = GetSelectedNetwork();
- if (selected_network) {
- network_type = selected_network->network_type;
- network_id = selected_network->label;
- }
- networks_.NetworkChanged(network_lib);
- if (is_waiting_for_connect_ &&
- networks_.IsNetworkConnected(connecting_network_.network_type,
- connecting_network_.label)) {
- // Stop waiting & don't update spinner status.
- StopWaitingForConnection(false);
- if (continue_pressed_) {
- MessageLoop::current()->PostTask(FROM_HERE,
- task_factory_.NewRunnableMethod(&NetworkScreen::NotifyOnConnection));
- return;
- }
- }
- view()->NetworkModelChanged();
- // Prefer Ethernet when it's connected (only once).
- if (!ethernet_preselected_ &&
- networks_.IsNetworkConnected(NetworkList::NETWORK_ETHERNET, string16())) {
- ethernet_preselected_ = true;
- SelectNetwork(NetworkList::NETWORK_ETHERNET, string16());
- } else {
- SelectNetwork(network_type, network_id);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NetworkLibrary::Observer implementation:
-
-void NetworkScreen::OnDialogAccepted() {
- const NetworkList::NetworkItem* network = GetSelectedNetwork();
- if (network)
- WaitForConnection(network);
-}
-
-void NetworkScreen::OnDialogCancelled() {
- if (view()) {
- view()->EnableContinue(false);
- view()->SetSelectedNetworkItem(0);
- }
+ UpdateStatus(network_lib);
}
///////////////////////////////////////////////////////////////////////////////
@@ -196,6 +93,15 @@ NetworkSelectionView* NetworkScreen::AllocateView() {
return new NetworkSelectionView(this);
}
+///////////////////////////////////////////////////////////////////////////////
+// NetworkScreen, views::InfoBubbleDelegate implementation:
+
+void NetworkScreen::OnHelpLinkActivated() {
+ if (!help_app_.get())
+ help_app_.reset(new HelpAppLauncher(view()->GetNativeWindow()));
+ help_app_->ShowHelpTopic(HelpAppLauncher::HELP_CONNECTIVITY);
+}
+
////////////////////////////////////////////////////////////////////////////////
// NetworkScreen, public:
@@ -209,37 +115,6 @@ void NetworkScreen::Refresh() {
////////////////////////////////////////////////////////////////////////////////
// NetworkScreen, private:
-void NetworkScreen::ConnectToNetwork(NetworkList::NetworkType type,
- const string16& id) {
- const NetworkList::NetworkItem* network =
- networks_.GetNetworkById(type, id);
- if (network &&
- !networks_.IsNetworkConnected(type, id)) {
- if (NetworkList::NETWORK_WIFI == network->network_type) {
- if (network->wifi_network.encrypted()) {
- OpenPasswordDialog(network->wifi_network);
- return;
- } else {
- WaitForConnection(network);
- chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
- ConnectToWifiNetwork(network->wifi_network,
- std::string(), std::string(), std::string());
- }
- } else if (NetworkList::NETWORK_CELLULAR == network->network_type) {
- WaitForConnection(network);
- chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
- ConnectToCellularNetwork(network->cellular_network);
- }
- }
-}
-
-void NetworkScreen::EnableWiFi() {
- if (CrosLibrary::Get()->EnsureLoaded()) {
- chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
- EnableWifiNetworkDevice(true);
- }
-}
-
void NetworkScreen::SubscribeNetworkNotification() {
if (!is_network_subscribed_) {
is_network_subscribed_ = true;
@@ -254,13 +129,6 @@ void NetworkScreen::UnsubscribeNetworkNotification() {
}
}
-NetworkList::NetworkItem* NetworkScreen::GetSelectedNetwork() {
- if (!view())
- return NULL;
-
- return networks_.GetNetworkAt(view()->GetSelectedNetworkItem() - 1);
-}
-
void NetworkScreen::NotifyOnConnection() {
// TODO(nkostylev): Check network connectivity.
UnsubscribeNetworkNotification();
@@ -269,62 +137,71 @@ void NetworkScreen::NotifyOnConnection() {
}
void NetworkScreen::OnConnectionTimeout() {
- continue_pressed_ = false;
- // TODO(nkostylev): Notify on connection error.
- if (is_waiting_for_connect_) {
- // Stop waiting & show selection combobox.
- StopWaitingForConnection(true);
- }
-}
-
-void NetworkScreen::OpenPasswordDialog(WifiNetwork network) {
- NetworkConfigView* dialog = new NetworkConfigView(network, true);
- dialog->set_delegate(this);
- dialog->set_browser_mode(false);
- views::Window* window = views::Window::CreateChromeWindow(
- view()->GetNativeWindow(), gfx::Rect(), dialog);
- window->SetIsAlwaysOnTop(true);
- window->Show();
- dialog->SetLoginTextfieldFocus();
-}
+ StopWaitingForConnection(network_id_);
+ // Show error bubble.
+ ClearErrors();
+ views::View* network_control = view()->GetNetworkControlView();
+ bubble_ = MessageBubble::Show(
+ network_control->GetWidget(),
+ network_control->GetScreenBounds(),
+ BubbleBorder::LEFT_TOP,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
+ l10n_util::GetStringF(IDS_NETWORK_SELECTION_ERROR,
+ l10n_util::GetString(IDS_PRODUCT_OS_NAME),
+ UTF16ToWide(network_id_)),
+ l10n_util::GetString(IDS_NETWORK_SELECTION_ERROR_HELP),
+ this);
+}
+
+void NetworkScreen::UpdateStatus(NetworkLibrary* network) {
+ if (!view() || !network)
+ return;
-void NetworkScreen::SelectNetwork(NetworkList::NetworkType type,
- const string16& id) {
- int index = networks_.GetNetworkIndexById(type, id);
- if (index >= 0) {
- view()->SetSelectedNetworkItem(index + 1);
+ if (network->ethernet_connected()) {
+ StopWaitingForConnection(
+ l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET));
+ } else if (network->wifi_connected()) {
+ StopWaitingForConnection(ASCIIToUTF16(network->wifi_name()));
+ } else if (network->cellular_connected()) {
+ StopWaitingForConnection(ASCIIToUTF16(network->cellular_name()));
+ } else if (network->ethernet_connecting()) {
+ WaitForConnection(
+ l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET));
+ } else if (network->wifi_connecting()) {
+ WaitForConnection(ASCIIToUTF16(network->wifi_name()));
+ } else if (network->cellular_connecting()) {
+ WaitForConnection(ASCIIToUTF16(network->cellular_name()));
} else {
- view()->SetSelectedNetworkItem(0);
+ view()->EnableContinue(network->Connected());
}
}
-void NetworkScreen::ShowConnectingStatus() {
- view()->ShowConnectingStatus(is_waiting_for_connect_,
- connecting_network_.label);
-}
+void NetworkScreen::StopWaitingForConnection(const string16& network_id) {
+ NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
+ bool is_connected = network && network->Connected();
+ if (is_connected && continue_pressed_) {
+ NotifyOnConnection();
+ return;
+ }
+
+ continue_pressed_ = false;
+ connection_timer_.Stop();
-void NetworkScreen::StopWaitingForConnection(bool show_combobox) {
- if (connection_timer_.IsRunning())
- connection_timer_.Stop();
- is_waiting_for_connect_ = false;
- connecting_network_.network_type = NetworkList::NETWORK_EMPTY;
- connecting_network_.label.clear();
- if (show_combobox)
- ShowConnectingStatus();
+ network_id_ = network_id;
+ view()->ShowConnectingStatus(false, network_id_);
+ view()->EnableContinue(is_connected);
}
-void NetworkScreen::WaitForConnection(const NetworkList::NetworkItem* network) {
- is_waiting_for_connect_ = true;
- DCHECK(network);
- connecting_network_.network_type = network->network_type;
- connecting_network_.label = network->label;
- if (connection_timer_.IsRunning())
- connection_timer_.Stop();
+void NetworkScreen::WaitForConnection(const string16& network_id) {
+ connection_timer_.Stop();
connection_timer_.Start(base::TimeDelta::FromSeconds(kConnectionTimeoutSec),
this,
&NetworkScreen::OnConnectionTimeout);
- if (continue_pressed_)
- ShowConnectingStatus();
+
+ network_id_ = network_id;
+ view()->ShowConnectingStatus(true, network_id_);
+
+ view()->EnableContinue(false);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/network_screen.h b/chrome/browser/chromeos/login/network_screen.h
index e7d00cb..860e901 100644
--- a/chrome/browser/chromeos/login/network_screen.h
+++ b/chrome/browser/chromeos/login/network_screen.h
@@ -4,14 +4,16 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_NETWORK_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_NETWORK_SCREEN_H_
+#pragma once
-#include <string>
-
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/task.h"
#include "base/timer.h"
#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/language_switch_menu.h"
+#include "chrome/browser/chromeos/login/message_bubble.h"
+#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/view_screen.h"
#include "chrome/browser/chromeos/network_list.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
@@ -20,39 +22,28 @@ class WizardScreenDelegate;
namespace chromeos {
+class HelpAppLauncher;
class NetworkSelectionView;
class NetworkScreen : public ViewScreen<NetworkSelectionView>,
- public NetworkScreenDelegate,
- public NetworkConfigView::Delegate {
+ public MessageBubbleDelegate,
+ public NetworkScreenDelegate {
public:
- NetworkScreen(WizardScreenDelegate* delegate, bool is_out_of_box);
+ explicit NetworkScreen(WizardScreenDelegate* delegate);
virtual ~NetworkScreen();
// NetworkScreenDelegate implementation:
+ virtual void ClearErrors();
virtual LanguageSwitchMenu* language_switch_menu() {
return &language_switch_menu_;
}
-
- // ComboboxModel implementation:
- virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
-
- // views::Combobox::Listener implementation:
- virtual void ItemChanged(views::Combobox* sender,
- int prev_index,
- int new_index);
+ virtual gfx::Size size() const { return GetScreenSize(); }
// views::ButtonListener implementation:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
// NetworkLibrary::Observer implementation:
virtual void NetworkChanged(NetworkLibrary* network_lib);
- virtual void NetworkTraffic(NetworkLibrary* cros, int traffic_type) {}
-
- // NetworkConfigView::Delegate implementation:
- virtual void OnDialogAccepted();
- virtual void OnDialogCancelled();
protected:
// Subscribes NetworkScreen to the network change notification,
@@ -60,15 +51,18 @@ class NetworkScreen : public ViewScreen<NetworkSelectionView>,
void Refresh();
private:
+ FRIEND_TEST(NetworkScreenTest, Timeout);
+
// ViewScreen implementation:
virtual void CreateView();
virtual NetworkSelectionView* AllocateView();
- // Connects to network if needed and updates screen state.
- void ConnectToNetwork(NetworkList::NetworkType type, const string16& id);
-
- // Enables WiFi device.
- void EnableWiFi();
+ // Overridden from views::InfoBubbleDelegate.
+ virtual void InfoBubbleClosing(InfoBubble* info_bubble,
+ bool closed_by_escape) { bubble_ = NULL; }
+ virtual bool CloseOnEscape() { return true; }
+ virtual bool FadeInOnShow() { return false; }
+ virtual void OnHelpLinkActivated();
// Subscribes to network change notifications.
void SubscribeNetworkNotification();
@@ -76,63 +70,43 @@ class NetworkScreen : public ViewScreen<NetworkSelectionView>,
// Unsubscribes from network change notifications.
void UnsubscribeNetworkNotification();
- // Returns currently selected network in the combobox.
- NetworkList::NetworkItem* GetSelectedNetwork();
-
// Notifies wizard on successful connection.
void NotifyOnConnection();
// Called by |connection_timer_| when connection to the network timed out.
void OnConnectionTimeout();
- // Opens password dialog for the encrypted networks.
- void OpenPasswordDialog(WifiNetwork network);
-
- // Selects network by type and id.
- void SelectNetwork(NetworkList::NetworkType type,
- const string16& id);
-
- // Switches connecting status based on |is_waiting_for_connect_|.
- void ShowConnectingStatus();
+ // Update UI based on current network status.
+ void UpdateStatus(NetworkLibrary* network);
// Stops waiting for network to connect.
- // If |show_combobox| is false, spinner is left on screen. Used on exit.
- void StopWaitingForConnection(bool show_combobox);
+ void StopWaitingForConnection(const string16& network_id);
// Starts waiting for network connection. Shows spinner.
- void WaitForConnection(const NetworkList::NetworkItem* network);
+ void WaitForConnection(const string16& network_id);
// True if subscribed to network change notification.
bool is_network_subscribed_;
- // Networks model, contains current state of available networks.
- NetworkList networks_;
-
- // True if WiFi is currently disabled.
- bool wifi_disabled_;
-
- // True if full OOBE flow should be shown.
- bool is_out_of_box_;
-
- // True if we're waiting for the selected network being connected.
- bool is_waiting_for_connect_;
+ // ID of the the network that we are waiting for.
+ string16 network_id_;
- // True if "Continue" button was pressed.
- // Set only when there's a network selected.
+ // True if user pressed continue button so we should proceed with OOBE
+ // as soon as we are connected.
bool continue_pressed_;
- // True if Ethernet was already preselected in combobox.
- bool ethernet_preselected_;
-
// Timer for connection timeout.
base::OneShotTimer<NetworkScreen> connection_timer_;
- // Network which we're connecting to.
- NetworkList::NetworkItem connecting_network_;
-
- ScopedRunnableMethodFactory<NetworkScreen> task_factory_;
LanguageSwitchMenu language_switch_menu_;
+ // Pointer to shown message bubble. We don't need to delete it because
+ // it will be deleted on bubble closing.
+ MessageBubble* bubble_;
+
+ // Help application used for help dialogs.
+ scoped_ptr<HelpAppLauncher> help_app_;
+
DISALLOW_COPY_AND_ASSIGN(NetworkScreen);
};
diff --git a/chrome/browser/chromeos/login/network_screen_browsertest.cc b/chrome/browser/chromeos/login/network_screen_browsertest.cc
index e31bac8..43fa5b7 100644
--- a/chrome/browser/chromeos/login/network_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/network_screen_browsertest.cc
@@ -8,22 +8,24 @@
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/mock_login_library.h"
#include "chrome/browser/chromeos/cros/mock_network_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/chromeos/login/network_selection_view.h"
-#include "chrome/browser/chromeos/login/network_screen.h"
#include "chrome/browser/chromeos/login/mock_screen_observer.h"
+#include "chrome/browser/chromeos/login/network_screen.h"
+#include "chrome/browser/chromeos/login/network_selection_view.h"
#include "chrome/browser/chromeos/login/view_screen.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h"
#include "chrome/browser/chromeos/login/wizard_screen.h"
#include "chrome/test/ui_test_utils.h"
#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/button/text_button.h"
#include "views/controls/combobox/combobox.h"
@@ -42,28 +44,19 @@ class DummyButtonListener : public views::ButtonListener {
const views::Event& event) {}
};
-class DummyComboboxModel : public ComboboxModel {
- public:
- virtual int GetItemCount() { return 2; }
-
- virtual std::wstring GetItemAt(int index) {
- return L"Item " + IntToWString(index);
- }
-};
-
class NetworkScreenTest : public WizardInProcessBrowserTest {
public:
- NetworkScreenTest(): WizardInProcessBrowserTest("network") {
- cellular_.set_name("Cellular network");
- wifi_.set_name("WiFi network");
+ NetworkScreenTest(): WizardInProcessBrowserTest("network"),
+ mock_login_library_(NULL),
+ mock_network_library_(NULL) {
}
protected:
virtual void SetUpInProcessBrowserTestFixture() {
- InitStatusAreaMocks();
-
+ cros_mock_->InitStatusAreaMocks();
+ mock_network_library_ = cros_mock_->mock_network_library();
mock_login_library_ = new MockLoginLibrary();
- test_api()->SetLoginLibrary(mock_login_library_, true);
+ cros_mock_->test_api()->SetLoginLibrary(mock_login_library_, true);
EXPECT_CALL(*mock_login_library_, EmitLoginPromptReady())
.Times(1);
@@ -71,99 +64,40 @@ class NetworkScreenTest : public WizardInProcessBrowserTest {
// Status bar expectations are defined with RetiresOnSaturation() so
// these mocks will be active once status bar is initialized.
EXPECT_CALL(*mock_network_library_, ethernet_connected())
- .Times(1)
- .WillOnce((Return(false)));
- EXPECT_CALL(*mock_network_library_, ethernet_connecting())
- .Times(1)
- .WillOnce((Return(false)));
- EXPECT_CALL(*mock_network_library_, wifi_enabled())
- .Times(1)
- .WillOnce((Return(true)));
- EXPECT_CALL(*mock_network_library_, wifi_networks())
- .Times(1)
- .WillOnce((ReturnRef(wifi_networks_)));
- EXPECT_CALL(*mock_network_library_, cellular_networks())
- .Times(1)
- .WillOnce((ReturnRef(cellular_networks_)));
- EXPECT_CALL(*mock_network_library_, AddObserver(_))
- .Times(1);
- EXPECT_CALL(*mock_network_library_, RemoveObserver(_))
- .Times(1);
-
- SetStatusAreaMocksExpectations();
- }
-
- virtual void TearDownInProcessBrowserTestFixture() {
- CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
- test_api()->SetLoginLibrary(NULL, false);
- }
-
- void NetworkChangedExpectations(bool wifi_enabled) {
- EXPECT_CALL(*mock_network_library_, wifi_enabled())
- .Times(1)
- .WillOnce((Return(wifi_enabled)));
- }
-
- void EthernetExpectations(bool connected, bool connecting) {
- EXPECT_CALL(*mock_network_library_, ethernet_connected())
- .Times(1)
- .WillRepeatedly((Return(connected)));
+ .Times(3)
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*mock_network_library_, ethernet_connecting())
.Times(1)
- .WillRepeatedly((Return(connecting)));
- }
-
- void WifiExpectations(bool connected, bool connecting) {
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*mock_network_library_, wifi_connected())
- .Times(1)
- .WillOnce((Return(connected)));
+ .Times(3)
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*mock_network_library_, wifi_connecting())
- .Times(1)
- .WillOnce((Return(connecting)));
- }
-
- void SetupWifiNetwork(bool connected, bool connecting) {
- wifi_networks_.clear();
- wifi_.set_connected(connected);
- wifi_.set_connecting(connecting);
- wifi_networks_.push_back(wifi_);
- }
-
- void SetupCellularNetwork(bool connected, bool connecting) {
- cellular_networks_.clear();
- cellular_.set_connected(connected);
- cellular_.set_connecting(connecting);
- cellular_networks_.push_back(cellular_);
- }
-
- void CellularExpectations(bool connected, bool connecting) {
+ .Times(3)
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*mock_network_library_, cellular_connected())
- .Times(1)
- .WillOnce((Return(connected)));
+ .Times(3)
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*mock_network_library_, cellular_connecting())
- .Times(1)
- .WillOnce((Return(connecting)));
- }
-
- void WifiCellularNetworksExpectations() {
- EXPECT_CALL(*mock_network_library_, wifi_networks())
- .Times(1)
- .WillOnce((ReturnRef(wifi_networks_)));
- EXPECT_CALL(*mock_network_library_, cellular_networks())
- .Times(1)
- .WillOnce((ReturnRef(cellular_networks_)));
- }
+ .Times(3)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*mock_network_library_, Connected())
+ .Times(3)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*mock_network_library_, Connecting())
+ .Times(2)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*mock_network_library_, AddObserver(_))
+ .Times(2);
+ EXPECT_CALL(*mock_network_library_, RemoveObserver(_))
+ .Times(2);
- void WifiSsidExpectation(const std::string& ssid) {
- EXPECT_CALL(*mock_network_library_, wifi_name())
- .Times(1)
- .WillOnce((ReturnRef(ssid)));
+ cros_mock_->SetStatusAreaMocksExpectations();
}
- void CellularNameExpectation(const std::string& name) {
- EXPECT_CALL(*mock_network_library_, cellular_name())
- .Times(1)
- .WillOnce((ReturnRef(name)));
+ virtual void TearDownInProcessBrowserTestFixture() {
+ CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
+ cros_mock_->test_api()->SetLoginLibrary(NULL, false);
}
void EmulateContinueButtonExit(NetworkScreen* network_screen) {
@@ -172,6 +106,8 @@ class NetworkScreenTest : public WizardInProcessBrowserTest {
EXPECT_CALL(*mock_screen_observer,
OnExit(ScreenObserver::NETWORK_CONNECTED))
.Times(1);
+ EXPECT_CALL(*mock_network_library_, Connected())
+ .WillOnce(Return(true));
controller()->set_observer(mock_screen_observer.get());
DummyButtonListener button_listener;
views::TextButton button(&button_listener, L"Button");
@@ -184,18 +120,13 @@ class NetworkScreenTest : public WizardInProcessBrowserTest {
}
MockLoginLibrary* mock_login_library_;
-
- CellularNetworkVector cellular_networks_;
- WifiNetworkVector wifi_networks_;
-
- CellularNetwork cellular_;
- WifiNetwork wifi_;
+ MockNetworkLibrary* mock_network_library_;
private:
DISALLOW_COPY_AND_ASSIGN(NetworkScreenTest);
};
-IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Basic) {
+IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Ethernet) {
ASSERT_TRUE(controller());
NetworkScreen* network_screen = controller()->GetNetworkScreen();
ASSERT_TRUE(network_screen != NULL);
@@ -203,328 +134,148 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Basic) {
NetworkSelectionView* network_view = network_screen->view();
ASSERT_TRUE(network_view != NULL);
- ASSERT_EQ(1, network_screen->GetItemCount());
- EXPECT_EQ(l10n_util::GetString(IDS_STATUSBAR_NO_NETWORKS_MESSAGE),
- network_screen->GetItemAt(0));
-}
+ EXPECT_FALSE(network_view->IsContinueEnabled());
-IN_PROC_BROWSER_TEST_F(NetworkScreenTest, EnableWifi) {
- ASSERT_TRUE(controller());
- NetworkScreen* network_screen = controller()->GetNetworkScreen();
- ASSERT_TRUE(network_screen != NULL);
- ASSERT_EQ(network_screen, controller()->current_screen());
- NetworkSelectionView* network_view = network_screen->view();
- ASSERT_TRUE(network_view != NULL);
- NetworkLibrary* network_library =
- chromeos::CrosLibrary::Get()->GetNetworkLibrary();
-
- // WiFi is disabled.
- NetworkChangedExpectations(false);
- EthernetExpectations(false, false);
- WifiCellularNetworksExpectations();
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
- EXPECT_EQ(l10n_util::GetString(IDS_STATUSBAR_NO_NETWORKS_MESSAGE),
- network_screen->GetItemAt(0));
- EXPECT_EQ(l10n_util::GetStringF(IDS_STATUSBAR_NETWORK_DEVICE_ENABLE,
- l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_WIFI)),
- network_screen->GetItemAt(1));
-
- // Emulate "Enable Wifi" item press.
- EXPECT_CALL(*mock_network_library_, EnableWifiNetworkDevice(true))
- .Times(1);
- DummyComboboxModel combobox_model;
- views::Combobox combobox(&combobox_model);
- network_screen->ItemChanged(&combobox, 0, 1);
- network_view->SetSelectedNetworkItem(1);
- ui_test_utils::RunAllPendingInMessageLoop();
- ASSERT_EQ(network_screen, controller()->current_screen());
-}
+ EXPECT_CALL(*mock_network_library_, ethernet_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, wifi_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, cellular_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, ethernet_connecting())
+ .WillOnce((Return(true)));
-IN_PROC_BROWSER_TEST_F(NetworkScreenTest, NetworksConnectedNotSelected) {
- ASSERT_TRUE(controller());
- NetworkLibrary* network_library =
- chromeos::CrosLibrary::Get()->GetNetworkLibrary();
- NetworkScreen* network_screen = controller()->GetNetworkScreen();
- ASSERT_TRUE(network_screen != NULL);
- NetworkSelectionView* network_view = network_screen->view();
- ASSERT_TRUE(network_view != NULL);
+ network_screen->NetworkChanged(mock_network_library_);
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_TRUE(network_view->IsConnecting());
- EthernetExpectations(true, false);
- WifiCellularNetworksExpectations();
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- // Ethernet is preselected once.
- EXPECT_EQ(1, network_view->GetSelectedNetworkItem());
- ASSERT_EQ(network_screen, controller()->current_screen());
- ASSERT_EQ(2, network_screen->GetItemCount());
- EXPECT_EQ(l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET),
- network_screen->GetItemAt(1));
-
- // Ethernet - disconnected, WiFi & Cellular - connected.
- EthernetExpectations(false, false);
- SetupWifiNetwork(true, false);
- WifiExpectations(true, false);
- SetupCellularNetwork(true, false);
- CellularExpectations(true, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(wifi_.name());
- CellularNameExpectation(cellular_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(network_screen, controller()->current_screen());
- ASSERT_EQ(3, network_screen->GetItemCount());
- EXPECT_EQ(ASCIIToWide(wifi_.name()), network_screen->GetItemAt(1));
- EXPECT_EQ(ASCIIToWide(cellular_.name()), network_screen->GetItemAt(2));
-
- // Ethernet, WiFi & Cellular - connected.
- EthernetExpectations(true, false);
- WifiExpectations(true, false);
- CellularExpectations(true, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(wifi_.name());
- CellularNameExpectation(cellular_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(network_screen, controller()->current_screen());
- ASSERT_EQ(4, network_screen->GetItemCount());
- EXPECT_EQ(l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET),
- network_screen->GetItemAt(1));
- EXPECT_EQ(ASCIIToWide(wifi_.name()), network_screen->GetItemAt(2));
- EXPECT_EQ(ASCIIToWide(cellular_.name()), network_screen->GetItemAt(3));
- // Ethernet is only preselected once.
- EXPECT_EQ(0, network_view->GetSelectedNetworkItem());
-}
+ EXPECT_CALL(*mock_network_library_, ethernet_connected())
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mock_network_library_, Connected())
+ .WillOnce(Return(true));
-IN_PROC_BROWSER_TEST_F(NetworkScreenTest, EthernetSelected) {
- ASSERT_TRUE(controller());
- NetworkLibrary* network_library =
- chromeos::CrosLibrary::Get()->GetNetworkLibrary();
- NetworkScreen* network_screen = controller()->GetNetworkScreen();
- ASSERT_TRUE(network_screen != NULL);
- NetworkSelectionView* network_view = network_screen->view();
- ASSERT_TRUE(network_view != NULL);
-
- // Emulate connecting to Ethernet.
- EthernetExpectations(false, true);
- WifiCellularNetworksExpectations();
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
- EXPECT_EQ(l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET),
- network_screen->GetItemAt(1));
- ASSERT_EQ(network_screen, controller()->current_screen());
+ network_screen->NetworkChanged(mock_network_library_);
+ EXPECT_TRUE(network_view->IsContinueEnabled());
- // Emulate combobox selection - nothing happens.
- DummyComboboxModel combobox_model;
- views::Combobox combobox(&combobox_model);
- network_screen->ItemChanged(&combobox, 0, 1);
- network_view->SetSelectedNetworkItem(1);
- ui_test_utils::RunAllPendingInMessageLoop();
- ASSERT_EQ(network_screen, controller()->current_screen());
-
- // Emulate connected Ethernet - it should be preselected.
- EthernetExpectations(true, false);
- WifiCellularNetworksExpectations();
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
- EXPECT_EQ(1, network_view->GetSelectedNetworkItem());
- ASSERT_EQ(network_screen, controller()->current_screen());
-
- // "Continue" button with connected network should proceed to next screen.
EmulateContinueButtonExit(network_screen);
}
-IN_PROC_BROWSER_TEST_F(NetworkScreenTest, WifiSelected) {
+IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Wifi) {
ASSERT_TRUE(controller());
- NetworkLibrary* network_library =
- chromeos::CrosLibrary::Get()->GetNetworkLibrary();
NetworkScreen* network_screen = controller()->GetNetworkScreen();
ASSERT_TRUE(network_screen != NULL);
- NetworkSelectionView* network_view = network_screen->view();
- ASSERT_TRUE(network_view != NULL);
-
- EthernetExpectations(false, false);
- SetupWifiNetwork(false, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(std::string());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
- EXPECT_EQ(ASCIIToWide(wifi_.name()), network_screen->GetItemAt(1));
-
- DummyComboboxModel combobox_model;
- views::Combobox combobox(&combobox_model);
-
- // Emulate combobox selection.
- EthernetExpectations(false, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(std::string());
- network_screen->ItemChanged(&combobox, 0, 1);
- network_view->SetSelectedNetworkItem(1);
- EXPECT_CALL(*mock_network_library_,
- ConnectToWifiNetwork(A<WifiNetwork>(), std::string(),
- std::string(), std::string()))
- .Times(1);
- ui_test_utils::RunAllPendingInMessageLoop();
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
-
- // Emulate connecting to WiFi network.
- EthernetExpectations(false, false);
- SetupWifiNetwork(false, true);
- WifiExpectations(false, true);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(wifi_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
ASSERT_EQ(network_screen, controller()->current_screen());
- // Emulate connected WiFi network.
- EthernetExpectations(false, false);
- SetupWifiNetwork(true, false);
- WifiExpectations(true, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(wifi_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ui_test_utils::RunAllPendingInMessageLoop();
- ASSERT_EQ(network_screen, controller()->current_screen());
+ 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)));
+ EXPECT_CALL(*mock_network_library_, wifi_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, cellular_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, ethernet_connecting())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, wifi_connecting())
+ .WillOnce((Return(true)));
+ std::string wifi_name = "wifi";
+ EXPECT_CALL(*mock_network_library_, wifi_name())
+ .WillOnce(ReturnRef(wifi_name));
+
+ network_screen->NetworkChanged(mock_network_library_);
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_TRUE(network_view->IsConnecting());
+
+ EXPECT_CALL(*mock_network_library_, ethernet_connected())
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mock_network_library_, Connected())
+ .WillOnce(Return(true));
+
+ network_screen->NetworkChanged(mock_network_library_);
+ EXPECT_TRUE(network_view->IsContinueEnabled());
- // "Continue" button with connected network should proceed to next screen.
EmulateContinueButtonExit(network_screen);
}
-IN_PROC_BROWSER_TEST_F(NetworkScreenTest, CellularSelected) {
+IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Cellular) {
ASSERT_TRUE(controller());
- NetworkLibrary* network_library =
- chromeos::CrosLibrary::Get()->GetNetworkLibrary();
NetworkScreen* network_screen = controller()->GetNetworkScreen();
ASSERT_TRUE(network_screen != NULL);
- NetworkSelectionView* network_view = network_screen->view();
- ASSERT_TRUE(network_view != NULL);
-
- EthernetExpectations(false, false);
- SetupCellularNetwork(false, false);
- WifiCellularNetworksExpectations();
- CellularNameExpectation(std::string());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
- EXPECT_EQ(ASCIIToWide(cellular_.name()), network_screen->GetItemAt(1));
-
- DummyComboboxModel combobox_model;
- views::Combobox combobox(&combobox_model);
-
- // Emulate combobox selection.
- EthernetExpectations(false, false);
- WifiCellularNetworksExpectations();
- CellularNameExpectation(std::string());
- network_screen->ItemChanged(&combobox, 0, 1);
- network_view->SetSelectedNetworkItem(1);
- EXPECT_CALL(*mock_network_library_, ConnectToCellularNetwork(_))
- .Times(1);
- ui_test_utils::RunAllPendingInMessageLoop();
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
-
- // Emulate connecting to cellular network.
- EthernetExpectations(false, false);
- SetupCellularNetwork(false, true);
- CellularExpectations(false, true);
- WifiCellularNetworksExpectations();
- CellularNameExpectation(cellular_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
ASSERT_EQ(network_screen, controller()->current_screen());
- // Emulate connected cellular network.
- EthernetExpectations(false, false);
- SetupCellularNetwork(true, false);
- CellularExpectations(true, false);
- WifiCellularNetworksExpectations();
- CellularNameExpectation(cellular_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ui_test_utils::RunAllPendingInMessageLoop();
- ASSERT_EQ(network_screen, controller()->current_screen());
+ 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)));
+ EXPECT_CALL(*mock_network_library_, wifi_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, cellular_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, ethernet_connecting())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, wifi_connecting())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, cellular_connecting())
+ .WillOnce((Return(true)));
+ std::string cellular_name = "3G";
+ EXPECT_CALL(*mock_network_library_, cellular_name())
+ .WillOnce(ReturnRef(cellular_name));
+
+ network_screen->NetworkChanged(mock_network_library_);
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_TRUE(network_view->IsConnecting());
+
+ EXPECT_CALL(*mock_network_library_, ethernet_connected())
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mock_network_library_, Connected())
+ .WillOnce(Return(true));
+
+ network_screen->NetworkChanged(mock_network_library_);
+ EXPECT_TRUE(network_view->IsContinueEnabled());
- // "Continue" button with connected network should proceed to next screen.
EmulateContinueButtonExit(network_screen);
}
-IN_PROC_BROWSER_TEST_F(NetworkScreenTest, WifiWaiting) {
+IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Timeout) {
ASSERT_TRUE(controller());
- NetworkLibrary* network_library =
- chromeos::CrosLibrary::Get()->GetNetworkLibrary();
NetworkScreen* network_screen = controller()->GetNetworkScreen();
ASSERT_TRUE(network_screen != NULL);
- NetworkSelectionView* network_view = network_screen->view();
- ASSERT_TRUE(network_view != NULL);
-
- EthernetExpectations(false, false);
- SetupWifiNetwork(false, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(std::string());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
-
- DummyComboboxModel combobox_model;
- views::Combobox combobox(&combobox_model);
-
- // Emulate combobox selection.
- EthernetExpectations(false, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(std::string());
- network_screen->ItemChanged(&combobox, 0, 1);
- network_view->SetSelectedNetworkItem(1);
- EXPECT_CALL(*mock_network_library_,
- ConnectToWifiNetwork(A<WifiNetwork>(), std::string(),
- std::string(), std::string()))
- .Times(1);
- ui_test_utils::RunAllPendingInMessageLoop();
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ASSERT_EQ(2, network_screen->GetItemCount());
-
- // Emulate connecting to WiFi network.
- EthernetExpectations(false, false);
- SetupWifiNetwork(false, true);
- WifiExpectations(false, true);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(wifi_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
-
- // Continue but wait for connection.
- scoped_ptr<MockScreenObserver>
- mock_screen_observer(new MockScreenObserver());
- EXPECT_CALL(*mock_screen_observer,
- OnExit(ScreenObserver::NETWORK_CONNECTED))
- .Times(1);
- controller()->set_observer(mock_screen_observer.get());
- DummyButtonListener button_listener;
- views::TextButton button(&button_listener, L"Button");
- views::MouseEvent event(views::Event::ET_MOUSE_RELEASED,
- 0, 0,
- views::Event::EF_LEFT_BUTTON_DOWN);
- network_screen->ButtonPressed(&button, event);
- ui_test_utils::RunAllPendingInMessageLoop();
ASSERT_EQ(network_screen, controller()->current_screen());
- // Emulate connected WiFi network.
- EthernetExpectations(false, false);
- SetupWifiNetwork(true, false);
- WifiExpectations(true, false);
- WifiCellularNetworksExpectations();
- WifiSsidExpectation(wifi_.name());
- NetworkChangedExpectations(true);
- network_screen->NetworkChanged(network_library);
- ui_test_utils::RunAllPendingInMessageLoop();
- controller()->set_observer(NULL);
+ 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)));
+ EXPECT_CALL(*mock_network_library_, wifi_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, cellular_connected())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, ethernet_connecting())
+ .WillOnce((Return(false)));
+ EXPECT_CALL(*mock_network_library_, wifi_connecting())
+ .WillOnce((Return(true)));
+ std::string wifi_name = "wifi";
+ EXPECT_CALL(*mock_network_library_, wifi_name())
+ .WillOnce(ReturnRef(wifi_name));
+ EXPECT_CALL(*mock_network_library_, Connected())
+ .WillOnce(Return(false));
+
+ network_screen->NetworkChanged(mock_network_library_);
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_TRUE(network_view->IsConnecting());
+
+ network_screen->OnConnectionTimeout();
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_FALSE(network_view->IsConnecting());
+
+ // Close infobubble with error message - it makes test stable.
+ network_screen->ClearErrors();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/network_screen_delegate.h b/chrome/browser/chromeos/login/network_screen_delegate.h
index a0c911a..683c71b 100644
--- a/chrome/browser/chromeos/login/network_screen_delegate.h
+++ b/chrome/browser/chromeos/login/network_screen_delegate.h
@@ -4,24 +4,32 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_NETWORK_SCREEN_DELEGATE_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_NETWORK_SCREEN_DELEGATE_H_
+#pragma once
#include "app/combobox_model.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "views/controls/button/button.h"
#include "views/controls/combobox/combobox.h"
+namespace gfx {
+class Size;
+} // namespace gfx
+
namespace chromeos {
class LanguageSwitchMenu;
// Interface that NetworkScreen exposes to the NetworkSelectionView.
-class NetworkScreenDelegate : public ComboboxModel,
- public views::Combobox::Listener,
- public views::ButtonListener,
+class NetworkScreenDelegate : public views::ButtonListener,
public NetworkLibrary::Observer {
public:
+ // Cleares all error notifications.
+ virtual void ClearErrors() = 0;
+
virtual LanguageSwitchMenu* language_switch_menu() = 0;
+ virtual gfx::Size size() const = 0;
+
protected:
virtual ~NetworkScreenDelegate() {}
};
diff --git a/chrome/browser/chromeos/login/network_selection_view.cc b/chrome/browser/chromeos/login/network_selection_view.cc
index 2e206a1..4b80b9c 100644
--- a/chrome/browser/chromeos/login/network_selection_view.cc
+++ b/chrome/browser/chromeos/login/network_selection_view.cc
@@ -11,16 +11,21 @@
#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/language_switch_menu.h"
#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
-#include "chrome/browser/chromeos/login/language_switch_menu.h"
+#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
+#include "chrome/browser/chromeos/status/network_dropdown_button.h"
+#include "gfx/size.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/native_button.h"
-#include "views/controls/combobox/combobox.h"
#include "views/controls/label.h"
#include "views/controls/throbber.h"
+#include "views/grid_layout.h"
+#include "views/standard_layout.h"
#include "views/widget/widget.h"
#include "views/widget/widget_gtk.h"
#include "views/window/non_client_view.h"
@@ -28,64 +33,242 @@
#include "views/window/window_gtk.h"
using views::Background;
+using views::GridLayout;
using views::Label;
-using views::SmoothedThrobber;
using views::View;
using views::Widget;
using views::WidgetGtk;
namespace {
-const int kWelcomeLabelY = 170;
-const int kContinueButtonSpacingX = 30;
-const int kSpacing = 25;
-const int kHorizontalSpacing = 25;
-const int kSelectionBoxWidthMin = 200;
+enum kLayoutColumnsets {
+ STANDARD_ROW,
+ THROBBER_ROW,
+};
+
+enum kContentsLayoutColumnsets {
+ WELCOME_ROW,
+ CONTENTS_ROW,
+};
+
+// Grid layout constants.
+const int kBorderSize = 10;
+const int kWelcomeTitlePadding = 10;
+const int kPaddingColumnWidth = 55;
+const int kMediumPaddingColumnWidth = 20;
+const int kControlPaddingRow = 15;
+
+// Fixed size for language/network controls height.
const int kSelectionBoxHeight = 29;
-const int kSelectionBoxSpacing = 7;
// Menu button is drawn using our custom icons in resources. See
// TextButtonBorder::Paint() for details. So this offset compensate
// horizontal size, eaten by those icons.
-const int kMenuButtonHorizontalOffset = 1;
+const int kMenuHorizontalOffset = -1;
// Vertical addition to the menu window to make it appear exactly below
// MenuButton.
-const int kMenuButtonVerticalOffset = 3;
+const int kMenuVerticalOffset = 3;
-const SkColor kWelcomeColor = 0xFF1D6AB1;
+// Offset that compensates menu width so that it matches
+// menu button visual width when being in pushed state.
+const int kMenuWidthOffset = 6;
-const int kThrobberFrameMs = 60;
-const int kThrobberStartDelayMs = 500;
+const SkColor kWelcomeColor = 0xFFCDD3D6;
} // namespace
namespace chromeos {
+// NetworkDropdownButton with custom accelerator enabled.
+class NetworkControlWithAccelerators : public NetworkDropdownButton {
+ public:
+ NetworkControlWithAccelerators(bool browser_mode,
+ gfx::NativeWindow parent_window,
+ NetworkScreenDelegate* delegate)
+ : NetworkDropdownButton(browser_mode, parent_window),
+ delegate_(delegate),
+ accel_clear_errors_(views::Accelerator(app::VKEY_ESCAPE,
+ false, false, false)) {
+ AddAccelerator(accel_clear_errors_);
+ }
+
+ // Overridden from View:
+ bool AcceleratorPressed(const views::Accelerator& accel) {
+ if (accel == accel_clear_errors_) {
+ delegate_->ClearErrors();
+ return true;
+ }
+ return false;
+ }
+
+ // Overridden from MenuButton:
+ virtual bool Activate() {
+ delegate_->ClearErrors();
+ return MenuButton::Activate();
+ }
+
+ private:
+ NetworkScreenDelegate* delegate_;
+
+ // ESC accelerator for closing error info bubble.
+ views::Accelerator accel_clear_errors_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkControlWithAccelerators);
+};
+
+// MenuButton with custom processing on focus events.
+class NotifyingMenuButton : public views::MenuButton {
+ public:
+ NotifyingMenuButton(views::ButtonListener* listener,
+ const std::wstring& text,
+ views::ViewMenuDelegate* menu_delegate,
+ bool show_menu_marker,
+ NetworkScreenDelegate* delegate)
+ : MenuButton(listener, text, menu_delegate, show_menu_marker),
+ delegate_(delegate) {}
+
+ // Overridden from View:
+ virtual void DidGainFocus() {
+ delegate_->ClearErrors();
+ }
+
+ private:
+ NetworkScreenDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotifyingMenuButton);
+};
+
NetworkSelectionView::NetworkSelectionView(NetworkScreenDelegate* delegate)
- : network_combobox_(NULL),
+ : contents_view_(NULL),
languages_menubutton_(NULL),
welcome_label_(NULL),
select_language_label_(NULL),
select_network_label_(NULL),
connecting_network_label_(NULL),
+ network_dropdown_(NULL),
continue_button_(NULL),
- throbber_(NULL),
+ throbber_(CreateDefaultSmoothedThrobber()),
+ proxy_settings_link_(NULL),
delegate_(delegate) {
}
NetworkSelectionView::~NetworkSelectionView() {
- network_combobox_->set_listener(NULL);
- network_combobox_ = NULL;
throbber_->Stop();
throbber_ = NULL;
}
+void NetworkSelectionView::AddControlsToLayout(const gfx::Size& size,
+ views::GridLayout* contents_layout) {
+ if (IsConnecting()) {
+ const int v_padding = (size.height() -
+ throbber_->GetPreferredSize().height()) / 2;
+ contents_layout->AddPaddingRow(0, v_padding);
+ contents_layout->StartRow(0, THROBBER_ROW);
+ contents_layout->AddView(connecting_network_label_);
+ contents_layout->AddView(throbber_);
+ contents_layout->AddPaddingRow(0, v_padding);
+ } else {
+ const int v_padding = (size.height() -
+ 3 * kControlPaddingRow - 2 * kSelectionBoxHeight -
+ proxy_settings_link_->GetPreferredSize().height() -
+ continue_button_->GetPreferredSize().height()) / 2;
+ contents_layout->AddPaddingRow(0, v_padding);
+ contents_layout->StartRow(0, STANDARD_ROW);
+ contents_layout->AddView(select_language_label_);
+ contents_layout->AddView(languages_menubutton_, 1, 1,
+ GridLayout::FILL, GridLayout::FILL,
+ languages_menubutton_->GetPreferredSize().width(),
+ kSelectionBoxHeight);
+ contents_layout->AddPaddingRow(0, kControlPaddingRow);
+ contents_layout->StartRow(0, STANDARD_ROW);
+ contents_layout->AddView(select_network_label_);
+ contents_layout->AddView(network_dropdown_, 1, 1,
+ GridLayout::FILL, GridLayout::FILL,
+ network_dropdown_->GetPreferredSize().width(),
+ kSelectionBoxHeight);
+ contents_layout->AddPaddingRow(0, kControlPaddingRow);
+ contents_layout->StartRow(0, STANDARD_ROW);
+ contents_layout->SkipColumns(1);
+ contents_layout->AddView(proxy_settings_link_, 1, 1,
+ GridLayout::LEADING, GridLayout::CENTER);
+ contents_layout->AddPaddingRow(0, kControlPaddingRow);
+ contents_layout->StartRow(0, STANDARD_ROW);
+ contents_layout->SkipColumns(1);
+ contents_layout->AddView(continue_button_, 1, 1,
+ GridLayout::LEADING, GridLayout::CENTER);
+ contents_layout->AddPaddingRow(0, v_padding);
+ }
+}
+
+void NetworkSelectionView::InitLayout() {
+ gfx::Size screen_size = delegate_->size();
+ const int widest_label = std::max(
+ select_language_label_->GetPreferredSize().width(),
+ select_network_label_->GetPreferredSize().width());
+ const int dropdown_width = screen_size.width() - 2 * kBorderSize -
+ 2 * kPaddingColumnWidth - kMediumPaddingColumnWidth - widest_label;
+ delegate_->language_switch_menu()->SetFirstLevelMenuWidth(
+ dropdown_width - kMenuWidthOffset);
+
+ // Define layout and column set for entire screen (welcome + screen).
+ views::GridLayout* screen_layout = new views::GridLayout(this);
+ SetLayoutManager(screen_layout);
+ views::ColumnSet* column_set = screen_layout->AddColumnSet(WELCOME_ROW);
+ const int welcome_width = screen_size.width() - 2 * kWelcomeTitlePadding -
+ 2 * kBorderSize;
+ column_set->AddPaddingColumn(0, kWelcomeTitlePadding + kBorderSize);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::FIXED, welcome_width, welcome_width);
+ column_set->AddPaddingColumn(0, kWelcomeTitlePadding + kBorderSize);
+ column_set = screen_layout->AddColumnSet(CONTENTS_ROW);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::FIXED, screen_size.width(), screen_size.width());
+ screen_layout->StartRow(0, WELCOME_ROW);
+ screen_layout->AddView(welcome_label_);
+ screen_layout->StartRow(0, CONTENTS_ROW);
+ screen_layout->AddView(contents_view_);
+
+ // Welcome label size might have been changed after adding to grid layout.
+ // Screen size includes welcome label height & border on each side.
+ screen_size.set_height(screen_size.height() - 2 * kBorderSize -
+ welcome_label_->GetPreferredSize().height());
+
+ // Define layout and column set for screen contents.
+ views::GridLayout* contents_layout = new views::GridLayout(contents_view_);
+ contents_view_->SetLayoutManager(contents_layout);
+
+ column_set = contents_layout->AddColumnSet(STANDARD_ROW);
+ column_set->AddPaddingColumn(0, kPaddingColumnWidth);
+ column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
+ GridLayout::FIXED, widest_label, widest_label);
+ column_set->AddPaddingColumn(0, kMediumPaddingColumnWidth);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::FIXED, dropdown_width, dropdown_width);
+ column_set->AddPaddingColumn(1, kPaddingColumnWidth);
+
+ const int h_padding = (screen_size.width() - 2 * kBorderSize -
+ connecting_network_label_->GetPreferredSize().width() -
+ throbber_->GetPreferredSize().width()) / 2;
+ column_set = contents_layout->AddColumnSet(THROBBER_ROW);
+ column_set->AddPaddingColumn(0, h_padding);
+ column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
+ column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, h_padding);
+
+ AddControlsToLayout(screen_size, contents_layout);
+}
+
void NetworkSelectionView::Init() {
+ contents_view_ = new views::View();
+
// Use rounded rect background.
views::Painter* painter = CreateWizardPainter(
&BorderDefinition::kScreenBorder);
- set_background(
+ contents_view_->set_background(
views::Background::CreateBackgroundPainter(true, painter));
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
@@ -100,41 +283,36 @@ void NetworkSelectionView::Init() {
select_language_label_ = new views::Label();
select_language_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
+ languages_menubutton_ = new NotifyingMenuButton(
+ NULL, std::wstring(), delegate_->language_switch_menu(), true, delegate_);
+ languages_menubutton_->SetFocusable(true);
+ languages_menubutton_->SetNormalHasBorder(true);
+ // Menu is positioned by bottom right corner of the MenuButton.
+ delegate_->language_switch_menu()->set_menu_offset(kMenuHorizontalOffset,
+ kMenuVerticalOffset);
+
select_network_label_ = new views::Label();
select_network_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
+ network_dropdown_ = new NetworkControlWithAccelerators(false,
+ GetNativeWindow(),
+ delegate_);
+ network_dropdown_->SetNormalHasBorder(true);
+ network_dropdown_->SetFocusable(true);
+
connecting_network_label_ = new views::Label();
connecting_network_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
connecting_network_label_->SetVisible(false);
- throbber_ = new views::SmoothedThrobber(kThrobberFrameMs);
- throbber_->SetFrames(
- ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_SPINNER));
- throbber_->set_start_delay_ms(kThrobberStartDelayMs);
- AddChildView(throbber_);
-
- network_combobox_ = new views::Combobox(delegate_);
- network_combobox_->set_listener(delegate_);
-
- languages_menubutton_ = new views::MenuButton(
- NULL, std::wstring(), delegate_->language_switch_menu(), true);
- languages_menubutton_->SetFocusable(true);
- languages_menubutton_->SetNormalHasBorder(true);
- delegate_->language_switch_menu()->set_menu_offset(
- kMenuButtonHorizontalOffset, kMenuButtonVerticalOffset);
-
- AddChildView(welcome_label_);
- AddChildView(select_language_label_);
- AddChildView(select_network_label_);
- AddChildView(connecting_network_label_);
- AddChildView(languages_menubutton_);
- AddChildView(network_combobox_);
+ proxy_settings_link_ = new views::Link();
+ proxy_settings_link_->SetController(this);
+ proxy_settings_link_->SetVisible(true);
+ proxy_settings_link_->SetFocusable(true);
UpdateLocalizedStrings();
}
void NetworkSelectionView::UpdateLocalizedStrings() {
- RecreateNativeControls();
languages_menubutton_->SetText(
delegate_->language_switch_menu()->GetCurrentLocaleName());
welcome_label_->SetText(l10n_util::GetStringF(IDS_NETWORK_SELECTION_TITLE,
@@ -143,130 +321,42 @@ void NetworkSelectionView::UpdateLocalizedStrings() {
l10n_util::GetString(IDS_LANGUAGE_SELECTION_SELECT));
select_network_label_->SetText(
l10n_util::GetString(IDS_NETWORK_SELECTION_SELECT));
- continue_button_->SetLabel(
- l10n_util::GetString(IDS_NETWORK_SELECTION_CONTINUE_BUTTON));
+ proxy_settings_link_->SetText(
+ l10n_util::GetString(IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON));
+ RecreateNativeControls();
UpdateConnectingNetworkLabel();
+ network_dropdown_->Refresh();
+ InitLayout();
}
////////////////////////////////////////////////////////////////////////////////
// views::View: implementation:
-void NetworkSelectionView::ChildPreferredSizeChanged(View* child) {
- Layout();
- SchedulePaint();
-}
-
-void NetworkSelectionView::LocaleChanged() {
+void NetworkSelectionView::OnLocaleChanged() {
UpdateLocalizedStrings();
- NetworkModelChanged();
- // Explicitly set selected item - index 0 is a localized string.
- if (GetSelectedNetworkItem() <= 0 &&
- delegate_->GetItemCount() > 0) {
- SetSelectedNetworkItem(0);
- }
+ // Proxy settings dialog contains localized title. Zap it.
+ proxy_settings_dialog_.reset(NULL);
+
Layout();
SchedulePaint();
}
-gfx::Size NetworkSelectionView::GetPreferredSize() {
- return gfx::Size(width(), height());
-}
-
-void NetworkSelectionView::Layout() {
- gfx::Insets insets = GetInsets();
- int max_width = this->width() - insets.width() - 2 * kHorizontalSpacing;
- welcome_label_->SizeToFit(max_width);
- int y = kWelcomeLabelY;
- y -= welcome_label_->GetPreferredSize().height() / 2;
-
- welcome_label_->SetBounds(
- (width() - welcome_label_->GetPreferredSize().width()) / 2,
- y,
- welcome_label_->GetPreferredSize().width(),
- welcome_label_->GetPreferredSize().height());
- y += welcome_label_->GetPreferredSize().height() + kSpacing;
-
- // Use menu preffered size to calculate boxes width accordingly.
- int box_width = delegate_->language_switch_menu()->GetFirstLevelMenuWidth() +
- kMenuButtonHorizontalOffset * 2;
- const int widest_label = std::max(
- select_language_label_->GetPreferredSize().width(),
- select_network_label_->GetPreferredSize().width());
- if (box_width < kSelectionBoxWidthMin) {
- box_width = kSelectionBoxWidthMin;
- delegate_->language_switch_menu()->SetFirstLevelMenuWidth(
- box_width - kMenuButtonHorizontalOffset * 2);
- } else if (widest_label + box_width + 2 * kHorizontalSpacing > width()) {
- box_width = width() - widest_label - 2 * kHorizontalSpacing;
- }
- const int labels_x = (width() - widest_label - box_width) / 2;
- select_language_label_->SetBounds(
- labels_x,
- y,
- select_language_label_->GetPreferredSize().width(),
- select_language_label_->GetPreferredSize().height());
-
- const int selection_box_x = labels_x + widest_label + kHorizontalSpacing;
- const int label_y_offset =
- (kSelectionBoxHeight -
- select_language_label_->GetPreferredSize().height()) / 2;
- languages_menubutton_->SetBounds(selection_box_x, y - label_y_offset,
- box_width, kSelectionBoxHeight);
-
- y += kSelectionBoxHeight + kSelectionBoxSpacing;
- select_network_label_->SetBounds(
- labels_x,
- y,
- select_network_label_->GetPreferredSize().width(),
- select_network_label_->GetPreferredSize().height());
-
- connecting_network_label_->SetBounds(
- kHorizontalSpacing,
- y,
- width() - kHorizontalSpacing * 2,
- connecting_network_label_->GetPreferredSize().height());
-
- throbber_->SetBounds(
- width() / 2 + connecting_network_label_->GetPreferredSize().width() / 2 +
- kHorizontalSpacing,
- y + (connecting_network_label_->GetPreferredSize().height() -
- throbber_->GetPreferredSize().height()) / 2,
- throbber_->GetPreferredSize().width(),
- throbber_->GetPreferredSize().height());
-
- network_combobox_->SetBounds(selection_box_x, y - label_y_offset,
- box_width, kSelectionBoxHeight);
-
- y = height() - continue_button_->GetPreferredSize().height() - kSpacing;
- continue_button_->SetBounds(
- width() - kContinueButtonSpacingX -
- continue_button_->GetPreferredSize().width(),
- y,
- continue_button_->GetPreferredSize().width(),
- continue_button_->GetPreferredSize().height());
-
- // Need to refresh combobox layout explicitly.
- network_combobox_->Layout();
- continue_button_->Layout();
+void NetworkSelectionView::ViewHierarchyChanged(bool is_add,
+ View* parent,
+ View* child) {
+ if (is_add && this == child)
+ WizardAccessibilityHelper::GetInstance()->MaybeEnableAccessibility(this);
}
////////////////////////////////////////////////////////////////////////////////
// NetworkSelectionView, public:
-int NetworkSelectionView::GetSelectedNetworkItem() const {
- return network_combobox_->selected_item();
-}
-
-void NetworkSelectionView::SetSelectedNetworkItem(int index) {
- network_combobox_->SetSelectedItem(index);
-}
-
-gfx::NativeWindow NetworkSelectionView::GetNativeWindow() {
+gfx::NativeWindow NetworkSelectionView::GetNativeWindow() const {
return GTK_WINDOW(static_cast<WidgetGtk*>(GetWidget())->GetNativeView());
}
-void NetworkSelectionView::NetworkModelChanged() {
- network_combobox_->ModelChanged();
+views::View* NetworkSelectionView::GetNetworkControlView() const {
+ return network_dropdown_;
}
void NetworkSelectionView::ShowConnectingStatus(bool connecting,
@@ -276,32 +366,62 @@ void NetworkSelectionView::ShowConnectingStatus(bool connecting,
select_language_label_->SetVisible(!connecting);
languages_menubutton_->SetVisible(!connecting);
select_network_label_->SetVisible(!connecting);
- network_combobox_->SetVisible(!connecting);
+ network_dropdown_->SetVisible(!connecting);
continue_button_->SetVisible(!connecting);
+ proxy_settings_link_->SetVisible(!connecting);
connecting_network_label_->SetVisible(connecting);
+ InitLayout();
Layout();
if (connecting) {
throbber_->Start();
+ network_dropdown_->CancelMenu();
} else {
throbber_->Stop();
}
}
+bool NetworkSelectionView::IsConnecting() const {
+ return connecting_network_label_->IsVisible();
+}
+
void NetworkSelectionView::EnableContinue(bool enabled) {
if (continue_button_)
continue_button_->SetEnabled(enabled);
}
+bool NetworkSelectionView::IsContinueEnabled() const {
+ return continue_button_ && continue_button_->IsEnabled();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// views::LinkController implementation:
+
+void NetworkSelectionView::LinkActivated(views::Link* source, int) {
+ if (source == proxy_settings_link_) {
+ if (!proxy_settings_dialog_.get()) {
+ static const char kProxySettingsURL[] = "chrome://settings/proxy";
+ proxy_settings_dialog_.reset(new LoginHtmlDialog(
+ this,
+ GetNativeWindow(),
+ l10n_util::GetString(IDS_OPTIONS_PROXY_TAB_LABEL),
+ GURL(kProxySettingsURL)));
+ }
+ proxy_settings_dialog_->Show();
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// NetworkSelectionView, private:
void NetworkSelectionView::RecreateNativeControls() {
// There is no way to get native button preferred size after the button was
// sized so delete and recreate the button on text update.
+ bool is_continue_enabled = IsContinueEnabled();
delete continue_button_;
- continue_button_ = new views::NativeButton(delegate_, std::wstring());
- continue_button_->SetEnabled(false);
- AddChildView(continue_button_);
+ continue_button_ = new views::NativeButton(
+ delegate_,
+ l10n_util::GetString(IDS_NETWORK_SELECTION_CONTINUE_BUTTON));
+ continue_button_->SetEnabled(is_continue_enabled);
}
void NetworkSelectionView::UpdateConnectingNetworkLabel() {
diff --git a/chrome/browser/chromeos/login/network_selection_view.h b/chrome/browser/chromeos/login/network_selection_view.h
index 5843e33..b089ff8 100644
--- a/chrome/browser/chromeos/login/network_selection_view.h
+++ b/chrome/browser/chromeos/login/network_selection_view.h
@@ -4,28 +4,39 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_NETWORK_SELECTION_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_NETWORK_SELECTION_VIEW_H_
+#pragma once
-#include <string>
-
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "chrome/browser/chromeos/login/login_html_dialog.h"
#include "views/controls/button/menu_button.h"
+#include "views/controls/link.h"
#include "views/view.h"
#include "views/widget/widget_gtk.h"
#include "views/window/window_delegate.h"
+namespace gfx {
+class Size;
+} // namespace gfx
+
namespace views {
class Combobox;
+class GridLayout;
class Label;
class NativeButton;
-class SmoothedThrobber;
+class Throbber;
} // namespace views
namespace chromeos {
+class NetworkDropdownButton;
class NetworkScreenDelegate;
class ScreenObserver;
// View for the network selection/initial welcome screen.
-class NetworkSelectionView : public views::View {
+class NetworkSelectionView : public views::View,
+ public views::LinkController,
+ public LoginHtmlDialog::Delegate {
public:
explicit NetworkSelectionView(NetworkScreenDelegate* delegate);
virtual ~NetworkSelectionView();
@@ -36,31 +47,47 @@ class NetworkSelectionView : public views::View {
// Update strings from the resources. Executed on language change.
void UpdateLocalizedStrings();
- // views::View: implementation:
- virtual gfx::Size GetPreferredSize();
- virtual void Layout();
-
- // Gets/Sets the selected item in the network combobox.
- int GetSelectedNetworkItem() const;
- void SetSelectedNetworkItem(int index);
+ // Returns top level native window for the view.
+ gfx::NativeWindow GetNativeWindow() const;
- gfx::NativeWindow GetNativeWindow();
-
- // Inform the network combobox that its model changed.
- void NetworkModelChanged();
+ // Returns network control view.
+ views::View* GetNetworkControlView() const;
// Shows network connecting status or network selection otherwise.
void ShowConnectingStatus(bool connecting, const string16& network_id);
+ // Returns true if only throbber is visible, the view is in waiting status.
+ bool IsConnecting() const;
+
// Sets whether continue control is enabled.
void EnableContinue(bool enabled);
+ // Returns whether continue button is enabled.
+ bool IsContinueEnabled() const;
+
+ // views::LinkController implementation.
+ virtual void LinkActivated(views::Link* source, int);
+
protected:
// Overridden from views::View.
- virtual void ChildPreferredSizeChanged(View* child);
- virtual void LocaleChanged();
+ virtual void OnLocaleChanged();
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child);
+
+ // LoginHtmlDialog::Delegate implementation:
+ virtual void OnDialogClosed() {}
private:
+ // Add screen controls to the contents layout specified.
+ // Based on state (connecting to the network or not)
+ // different controls are added.
+ void AddControlsToLayout(const gfx::Size& size,
+ views::GridLayout* contents_layout);
+
+ // Initializes grid layout of the screen. Called on language change too.
+ void InitLayout();
+
// Delete and recreate native controls that
// fail to update preferred size after string update.
void RecreateNativeControls();
@@ -68,15 +95,19 @@ class NetworkSelectionView : public views::View {
// Updates text on label with currently connecting network.
void UpdateConnectingNetworkLabel();
- // Dialog controls.
- views::Combobox* network_combobox_;
+ // View that contains defines screen contents.
+ views::View* contents_view_;
+
+ // Screen controls.
views::MenuButton* languages_menubutton_;
views::Label* welcome_label_;
views::Label* select_language_label_;
views::Label* select_network_label_;
views::Label* connecting_network_label_;
+ NetworkDropdownButton* network_dropdown_;
views::NativeButton* continue_button_;
- views::SmoothedThrobber* throbber_;
+ views::Throbber* throbber_;
+ views::Link* proxy_settings_link_;
// NetworkScreen delegate.
NetworkScreenDelegate* delegate_;
@@ -84,6 +115,9 @@ class NetworkSelectionView : public views::View {
// Id of the network that is in process of connecting.
string16 network_id_;
+ // Dialog used for to launch proxy settings.
+ scoped_ptr<LoginHtmlDialog> proxy_settings_dialog_;
+
DISALLOW_COPY_AND_ASSIGN(NetworkSelectionView);
};
diff --git a/chrome/browser/chromeos/login/new_user_view.cc b/chrome/browser/chromeos/login/new_user_view.cc
index 397821d..ae97457 100644
--- a/chrome/browser/chromeos/login/new_user_view.cc
+++ b/chrome/browser/chromeos/login/new_user_view.cc
@@ -10,20 +10,22 @@
#include <algorithm>
#include <vector>
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/process_util.h"
-#include "base/utf_string_conversions.h"
#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/google_util.h"
+#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
+#include "grit/app_resources.h"
+#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
@@ -37,20 +39,15 @@ using views::WidgetGtk;
namespace {
-// NOTE: When adding new controls check RecreateNativeControls()
-// that |sign_in_button_| is added with correct index.
-const int kSignInButtonFocusOrderIndex = 3;
const int kTextfieldWidth = 286;
+const int kSplitterHeight = 1;
const int kRowPad = 7;
const int kColumnPad = 7;
-const int kLanguagesMenuWidth = 200;
const int kLanguagesMenuHeight = 30;
+const SkColor kLanguagesMenuTextColor = 0xFF999999;
const SkColor kErrorColor = 0xFF8F384F;
const char kDefaultDomain[] = "@gmail.com";
-const char kAccountRecoveryHelpUrl[] =
- "http://www.google.com/support/accounts/bin/answer.py?answer=48598";
-
// Textfield that adds domain to the entered username if focus is lost and
// username doesn't have full domain.
class UsernameField : public views::Textfield {
@@ -76,23 +73,33 @@ class UsernameField : public views::Textfield {
namespace chromeos {
-NewUserView::NewUserView(Delegate* delegate, bool need_border)
+NewUserView::NewUserView(Delegate* delegate,
+ bool need_border,
+ bool need_browse_without_signin)
: username_field_(NULL),
password_field_(NULL),
title_label_(NULL),
+ title_hint_label_(NULL),
+ splitter_(NULL),
sign_in_button_(NULL),
create_account_link_(NULL),
- cant_access_account_link_(NULL),
browse_without_signin_link_(NULL),
languages_menubutton_(NULL),
throbber_(NULL),
- accel_focus_user_(views::Accelerator(base::VKEY_U, false, false, true)),
- accel_focus_pass_(views::Accelerator(base::VKEY_P, false, false, true)),
+ 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()),
delegate_(delegate),
ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)),
focus_delayed_(false),
login_in_process_(false),
- need_border_(need_border) {
+ need_border_(need_border),
+ need_browse_without_signin_(need_browse_without_signin),
+ need_create_account_(false),
+ languages_menubutton_order_(-1),
+ sign_in_button_order_(-1) {
}
NewUserView::~NewUserView() {
@@ -105,14 +112,12 @@ void NewUserView::Init() {
views::Painter* painter = CreateWizardPainter(
&BorderDefinition::kScreenBorder);
set_background(views::Background::CreateBackgroundPainter(true, painter));
- } else {
- set_background(views::Background::CreateSolidBackground(
- BorderDefinition::kScreenBorder.top_color));
}
// Set up fonts.
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
gfx::Font title_font = rb.GetFont(ResourceBundle::MediumBoldFont);
+ gfx::Font title_hint_font = rb.GetFont(ResourceBundle::BoldFont);
title_label_ = new views::Label();
title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
@@ -120,6 +125,18 @@ void NewUserView::Init() {
title_label_->SetMultiLine(true);
AddChildView(title_label_);
+ title_hint_label_ = new views::Label();
+ title_hint_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ title_hint_label_->SetFont(title_hint_font);
+ title_hint_label_->SetColor(SK_ColorGRAY);
+ title_hint_label_->SetMultiLine(true);
+ AddChildView(title_hint_label_);
+
+ splitter_ = new views::View();
+ splitter_->set_background(
+ views::Background::CreateSolidBackground(SK_ColorGRAY));
+ AddChildView(splitter_);
+
username_field_ = new UsernameField();
AddChildView(username_field_);
@@ -129,18 +146,24 @@ void NewUserView::Init() {
throbber_ = CreateDefaultSmoothedThrobber();
AddChildView(throbber_);
- InitLink(&create_account_link_);
- InitLink(&cant_access_account_link_);
- InitLink(&browse_without_signin_link_);
-
language_switch_menu_.InitLanguageMenu();
- languages_menubutton_ = new views::MenuButton(
- NULL, std::wstring(), &language_switch_menu_, true);
- languages_menubutton_->SetFocusable(true);
+
+ RecreatePeculiarControls();
+
+ AddChildView(sign_in_button_);
+ if (need_create_account_) {
+ InitLink(&create_account_link_);
+ }
+ if (need_browse_without_signin_) {
+ InitLink(&browse_without_signin_link_);
+ }
AddChildView(languages_menubutton_);
+ // Set up accelerators.
AddAccelerator(accel_focus_user_);
AddAccelerator(accel_focus_pass_);
+ AddAccelerator(accel_login_off_the_record_);
+ AddAccelerator(accel_enable_accessibility_);
UpdateLocalizedStrings();
RequestFocus();
@@ -151,55 +174,100 @@ void NewUserView::Init() {
if (!CrosLibrary::Get()->EnsureLoaded()) {
EnableInputControls(false);
}
+
+ // The 'Sign in' button should be disabled when there is no text in the
+ // username and password fields.
+ sign_in_button_->SetEnabled(false);
}
bool NewUserView::AcceleratorPressed(const views::Accelerator& accelerator) {
if (accelerator == accel_focus_user_) {
username_field_->RequestFocus();
- return true;
- }
-
- if (accelerator == accel_focus_pass_) {
+ } else if (accelerator == accel_focus_pass_) {
password_field_->RequestFocus();
- return true;
+ } else if (accelerator == accel_login_off_the_record_) {
+ delegate_->OnLoginOffTheRecord();
+ } else if (accelerator == accel_enable_accessibility_) {
+ WizardAccessibilityHelper::GetInstance()->EnableAccessibility(this);
+ } else {
+ return false;
}
-
- return false;
+ return true;
}
-void NewUserView::RecreateNativeControls() {
+void NewUserView::RecreatePeculiarControls() {
+ // PreferredSize reported by MenuButton (and TextField) is not able
+ // to shrink, only grow; so recreate on text change.
+ delete languages_menubutton_;
+ languages_menubutton_ = new views::MenuButton(
+ NULL, std::wstring(), &language_switch_menu_, true);
+ languages_menubutton_->set_menu_marker(
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_MENU_DROPARROW_SHARP));
+ languages_menubutton_->SetEnabledColor(kLanguagesMenuTextColor);
+ languages_menubutton_->SetFocusable(true);
+
// There is no way to get native button preferred size after the button was
// sized so delete and recreate the button on text update.
delete sign_in_button_;
sign_in_button_ = new views::NativeButton(this, std::wstring());
- // Add button after label, user & password fields.
- DCHECK(GetChildViewCount() >= kSignInButtonFocusOrderIndex);
- AddChildView(kSignInButtonFocusOrderIndex, sign_in_button_);
+ UpdateSignInButtonState();
+
if (!CrosLibrary::Get()->EnsureLoaded())
sign_in_button_->SetEnabled(false);
}
-void NewUserView::UpdateLocalizedStrings() {
- RecreateNativeControls();
+void NewUserView::UpdateSignInButtonState() {
+ bool enabled = !username_field_->text().empty() &&
+ !password_field_->text().empty();
+ sign_in_button_->SetEnabled(enabled);
+}
- title_label_->SetText(l10n_util::GetString(IDS_LOGIN_TITLE));
+void NewUserView::AddChildView(View* view) {
+ // languages_menubutton_ and sign_in_button_ are recreated on text change,
+ // so we restore their original position in layout.
+ if (view == languages_menubutton_) {
+ if (languages_menubutton_order_ < 0) {
+ languages_menubutton_order_ = GetChildViewCount();
+ }
+ views::View::AddChildView(languages_menubutton_order_, view);
+ } else if (view == sign_in_button_) {
+ if (sign_in_button_order_ < 0) {
+ sign_in_button_order_ = GetChildViewCount();
+ }
+ views::View::AddChildView(sign_in_button_order_, view);
+ } else {
+ views::View::AddChildView(view);
+ }
+}
+
+void NewUserView::UpdateLocalizedStrings() {
+ title_label_->SetText(l10n_util::GetStringF(
+ IDS_LOGIN_TITLE, l10n_util::GetString(IDS_PRODUCT_OS_NAME)));
+ title_hint_label_->SetText(l10n_util::GetString(IDS_LOGIN_TITLE_HINT));
username_field_->set_text_to_display_when_empty(
l10n_util::GetStringUTF16(IDS_LOGIN_USERNAME));
password_field_->set_text_to_display_when_empty(
l10n_util::GetStringUTF16(IDS_LOGIN_PASSWORD));
sign_in_button_->SetLabel(l10n_util::GetString(IDS_LOGIN_BUTTON));
- create_account_link_->SetText(
- l10n_util::GetString(IDS_CREATE_ACCOUNT_BUTTON));
- cant_access_account_link_->SetText(
- l10n_util::GetString(IDS_CANT_ACCESS_ACCOUNT_BUTTON));
- browse_without_signin_link_->SetText(
- l10n_util::GetString(IDS_BROWSE_WITHOUT_SIGNING_IN_BUTTON));
+ if (need_create_account_) {
+ create_account_link_->SetText(
+ l10n_util::GetString(IDS_CREATE_ACCOUNT_BUTTON));
+ }
+ if (need_browse_without_signin_) {
+ browse_without_signin_link_->SetText(
+ l10n_util::GetString(IDS_BROWSE_WITHOUT_SIGNING_IN_BUTTON));
+ }
delegate_->ClearErrors();
languages_menubutton_->SetText(language_switch_menu_.GetCurrentLocaleName());
}
-void NewUserView::LocaleChanged() {
+void NewUserView::OnLocaleChanged() {
+ RecreatePeculiarControls();
UpdateLocalizedStrings();
+ AddChildView(sign_in_button_);
+ AddChildView(languages_menubutton_);
+
Layout();
SchedulePaint();
}
@@ -217,6 +285,7 @@ void NewUserView::ViewHierarchyChanged(bool is_add,
MessageLoop::current()->PostTask(FROM_HERE,
focus_grabber_factory_.NewRunnableMethod(
&NewUserView::FocusFirstField));
+ WizardAccessibilityHelper::GetInstance()->MaybeEnableAccessibility(this);
}
}
@@ -265,32 +334,49 @@ void NewUserView::Layout() {
// Place language selection in top right corner.
int x = std::max(0,
- this->width() - insets.right() - kLanguagesMenuWidth - kColumnPad);
+ this->width() - insets.right() -
+ languages_menubutton_->GetPreferredSize().width() - kColumnPad);
int y = insets.top() + kRowPad;
int width = std::min(this->width() - insets.width() - 2 * kColumnPad,
- kLanguagesMenuWidth);
+ languages_menubutton_->GetPreferredSize().width());
int height = kLanguagesMenuHeight;
languages_menubutton_->SetBounds(x, y, width, height);
+ y += height + kRowPad;
width = std::min(this->width() - insets.width() - 2 * kColumnPad,
kTextfieldWidth);
x = (this->width() - width) / 2;
int max_width = this->width() - x - insets.right();
title_label_->SizeToFit(max_width);
+ title_hint_label_->SizeToFit(max_width);
+
+ // Top align title and title hint.
+ y += setViewBounds(title_label_, x, y, max_width, false);
+ y += setViewBounds(title_hint_label_, x, y, max_width, false);
+ int title_end = y;
+
+ // Center align all other controls.
+ int create_account_link_height = need_create_account_ ?
+ create_account_link_->GetPreferredSize().height() : 0;
+ int browse_without_signin_link_height = need_browse_without_signin_ ?
+ browse_without_signin_link_->GetPreferredSize().height() : 0;
- height = title_label_->GetPreferredSize().height() +
- username_field_->GetPreferredSize().height() +
+ height = username_field_->GetPreferredSize().height() +
password_field_->GetPreferredSize().height() +
sign_in_button_->GetPreferredSize().height() +
- create_account_link_->GetPreferredSize().height() +
- cant_access_account_link_->GetPreferredSize().height() +
- browse_without_signin_link_->GetPreferredSize().height() +
- 4 * kRowPad;
- y = (this->height() - height) / 2;
+ create_account_link_height +
+ browse_without_signin_link_height +
+ 5 * kRowPad;
+ y += (this->height() - y - height) / 2;
+
+ int corner_radius = need_border_ ? login::kScreenCornerRadius : 0;
+ splitter_->SetBounds(insets.left() - corner_radius / 2,
+ title_end + (y - title_end) / 2,
+ this->width() - insets.width() + corner_radius,
+ kSplitterHeight);
- y += (setViewBounds(title_label_, x, y, max_width, false) + kRowPad);
y += (setViewBounds(username_field_, x, y, width, true) + kRowPad);
- y += (setViewBounds(password_field_, x, y, width, true) + kRowPad);
+ y += (setViewBounds(password_field_, x, y, width, true) + 3 * kRowPad);
int throbber_y = y;
y += (setViewBounds(sign_in_button_, x, y, width, false) + kRowPad);
setViewBounds(throbber_,
@@ -299,10 +385,13 @@ void NewUserView::Layout() {
throbber_->GetPreferredSize().height()) / 2,
width,
false);
- y += setViewBounds(create_account_link_, x, y, max_width, false);
- y += setViewBounds(cant_access_account_link_, x, y, max_width, false);
- y += setViewBounds(browse_without_signin_link_, x, y, max_width, false);
+ if (need_create_account_) {
+ y += setViewBounds(create_account_link_, x, y, max_width, false);
+ }
+ if (need_browse_without_signin_) {
+ y += setViewBounds(browse_without_signin_link_, x, y, max_width, false);
+ }
SchedulePaint();
}
@@ -338,8 +427,8 @@ void NewUserView::Login() {
}
// Sign in button causes a login attempt.
-void NewUserView::ButtonPressed(
- views::Button* sender, const views::Event& event) {
+void NewUserView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
DCHECK(sender == sign_in_button_);
Login();
}
@@ -349,12 +438,6 @@ void NewUserView::LinkActivated(views::Link* source, int event_flags) {
delegate_->OnCreateAccount();
} else if (source == browse_without_signin_link_) {
delegate_->OnLoginOffTheRecord();
- } else if (source == cant_access_account_link_) {
- // TODO(nkostylev): Display offline help when network is not connected.
- // http://crosbug.com/3874
- delegate_->AddStartUrl(
- google_util::AppendGoogleLocaleParam(GURL(kAccountRecoveryHelpUrl)));
- delegate_->OnLoginOffTheRecord();
}
}
@@ -366,12 +449,21 @@ void NewUserView::ClearAndEnablePassword() {
throbber_->Stop();
}
+void NewUserView::ClearAndEnableFields() {
+ login_in_process_ = false;
+ EnableInputControls(true);
+ SetUsername(std::string());
+ SetPassword(std::string());
+ username_field_->RequestFocus();
+ throbber_->Stop();
+}
+
gfx::Rect NewUserView::GetPasswordBounds() const {
- gfx::Rect screen_bounds(password_field_->bounds());
- gfx::Point origin(screen_bounds.origin());
- views::View::ConvertPointToScreen(password_field_->GetParent(), &origin);
- screen_bounds.set_origin(origin);
- return screen_bounds;
+ return password_field_->GetScreenBounds();
+}
+
+gfx::Rect NewUserView::GetUsernameBounds() const {
+ return username_field_->GetScreenBounds();
}
void NewUserView::StopThrobber() {
@@ -383,26 +475,39 @@ bool NewUserView::HandleKeystroke(views::Textfield* s,
if (!CrosLibrary::Get()->EnsureLoaded() || login_in_process_)
return false;
- if (keystroke.GetKeyboardCode() == base::VKEY_RETURN) {
+ if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
Login();
// Return true so that processing ends
return true;
- } else {
- delegate_->ClearErrors();
- return false;
+ } 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
return false;
}
+void NewUserView::ContentsChanged(views::Textfield* sender,
+ const string16& new_contents) {
+ UpdateSignInButtonState();
+}
+
void NewUserView::EnableInputControls(bool enabled) {
languages_menubutton_->SetEnabled(enabled);
username_field_->SetEnabled(enabled);
password_field_->SetEnabled(enabled);
sign_in_button_->SetEnabled(enabled);
- create_account_link_->SetEnabled(enabled);
- cant_access_account_link_->SetEnabled(enabled);
- browse_without_signin_link_->SetEnabled(enabled);
+ if (need_create_account_) {
+ create_account_link_->SetEnabled(enabled);
+ }
+ if (need_browse_without_signin_) {
+ browse_without_signin_link_->SetEnabled(enabled);
+ }
}
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 bd3b20b..758d587 100644
--- a/chrome/browser/chromeos/login/new_user_view.h
+++ b/chrome/browser/chromeos/login/new_user_view.h
@@ -4,13 +4,10 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_NEW_USER_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_NEW_USER_VIEW_H_
+#pragma once
#include <string>
-#include <vector>
-#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/chromeos/login/language_switch_menu.h"
#include "views/accelerator.h"
#include "views/controls/button/button.h"
@@ -54,10 +51,16 @@ class NewUserView : public views::View,
// User started typing so clear all error messages.
virtual void ClearErrors() = 0;
+
+ // User tries to navigate away from NewUserView pod.
+ virtual void NavigateAway() = 0;
};
// If |need_border| is true, RoundedRect border and background are required.
- NewUserView(Delegate* delegate, bool need_border);
+ NewUserView(Delegate* delegate,
+ bool need_border,
+ bool need_browse_without_signin);
+
virtual ~NewUserView();
// Initialize view layout.
@@ -69,12 +72,18 @@ class NewUserView : public views::View,
// Resets password text and sets the enabled state of the password.
void ClearAndEnablePassword();
+ // Resets password and username text and focuses on username.
+ void ClearAndEnableFields();
+
// Stops throbber shown during login.
void StopThrobber();
// Returns bounds of password field in screen coordinates.
gfx::Rect GetPasswordBounds() const;
+ // Returns bounds of username field in screen coordinates.
+ gfx::Rect GetUsernameBounds() const;
+
// Overridden from views::View:
virtual gfx::Size GetPreferredSize();
virtual void Layout();
@@ -92,7 +101,7 @@ class NewUserView : public views::View,
virtual bool HandleKeystroke(views::Textfield* sender,
const views::Textfield::Keystroke& keystroke);
virtual void ContentsChanged(views::Textfield* sender,
- const string16& new_contents) {}
+ const string16& new_contents);
// Overridden from views::ButtonListener.
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
@@ -104,12 +113,14 @@ class NewUserView : public views::View,
protected:
// views::View overrides:
- virtual void ViewHierarchyChanged(bool is_add, views::View *parent,
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View *parent,
views::View *child);
virtual void NativeViewHierarchyChanged(bool attached,
gfx::NativeView native_view,
views::RootView* root_view);
- virtual void LocaleChanged();
+ virtual void OnLocaleChanged();
+ void AddChildView(View* view);
private:
// Enables/disables input controls (textfields, buttons).
@@ -120,24 +131,33 @@ class NewUserView : public views::View,
void InitLink(views::Link** link);
// Delete and recreate native controls that fail to update preferred size
- // after string update.
- void RecreateNativeControls();
+ // after text/locale update.
+ void RecreatePeculiarControls();
+
+ // Enable or disable the |sign_in_button_| based on the contents of the
+ // |username_field_| and |password_field_|. If there is text in both the
+ // button is enabled, otherwise it's disabled.
+ void UpdateSignInButtonState();
// Screen controls.
- // NOTE: When adding new controls check RecreateNativeControls()
- // that |sign_in_button_| is added with correct index.
+ // NOTE: sign_in_button_ and languages_menubutton_ are handled with
+ // special care: they are recreated on any text/locale change
+ // because they are not resized properly.
views::Textfield* username_field_;
views::Textfield* password_field_;
views::Label* title_label_;
+ views::Label* title_hint_label_;
+ views::View* splitter_;
views::NativeButton* sign_in_button_;
views::Link* create_account_link_;
- views::Link* cant_access_account_link_;
views::Link* browse_without_signin_link_;
views::MenuButton* languages_menubutton_;
views::Throbber* throbber_;
- views::Accelerator accel_focus_user_;
views::Accelerator accel_focus_pass_;
+ views::Accelerator accel_focus_user_;
+ views::Accelerator accel_login_off_the_record_;
+ views::Accelerator accel_enable_accessibility_;
// Notifications receiver.
Delegate* delegate_;
@@ -156,6 +176,17 @@ class NewUserView : public views::View,
// If true, this view needs RoundedRect border and background.
bool need_border_;
+ // Whether browse without signin is needed.
+ bool need_browse_without_signin_;
+
+ // Whether create account link is needed. Set to false for now but we may
+ // need it back in near future.
+ bool need_create_account_;
+
+ // Ordinal position of controls inside view layout.
+ int languages_menubutton_order_;
+ int sign_in_button_order_;
+
FRIEND_TEST_ALL_PREFIXES(LoginScreenTest, IncognitoLogin);
friend class LoginScreenTest;
diff --git a/chrome/browser/chromeos/login/owner_key_utils.cc b/chrome/browser/chromeos/login/owner_key_utils.cc
index 916d9c7..3016561 100644
--- a/chrome/browser/chromeos/login/owner_key_utils.cc
+++ b/chrome/browser/chromeos/login/owner_key_utils.cc
@@ -12,58 +12,79 @@
#include <limits>
+#include "base/crypto/rsa_private_key.h"
+#include "base/crypto/signature_creator.h"
+#include "base/crypto/signature_verifier.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
-#include "base/nss_util_internal.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"
+#include "chrome/browser/chromeos/cros/login_library.h"
+#include "chrome/common/extensions/extension_constants.h"
+
+using base::RSAPrivateKey;
+using extension_misc::kSignatureAlgorithm;
+
+namespace chromeos {
+
+///////////////////////////////////////////////////////////////////////////
+// OwnerKeyUtils
// static
OwnerKeyUtils::Factory* OwnerKeyUtils::factory_ = NULL;
+OwnerKeyUtils::OwnerKeyUtils() {}
+
+OwnerKeyUtils::~OwnerKeyUtils() {}
+
+///////////////////////////////////////////////////////////////////////////
+// OwnerKeyUtilsImpl
+
class OwnerKeyUtilsImpl : public OwnerKeyUtils {
public:
OwnerKeyUtilsImpl();
- virtual ~OwnerKeyUtilsImpl();
- bool GenerateKeyPair(SECKEYPrivateKey** private_key_out,
- SECKEYPublicKey** public_key_out);
+ RSAPrivateKey* GenerateKeyPair();
+
+ bool ExportPublicKeyViaDbus(RSAPrivateKey* pair,
+ LoginLibrary::Delegate* d);
+
+ bool ExportPublicKeyToFile(RSAPrivateKey* pair, const FilePath& key_file);
+
+ bool ImportPublicKey(const FilePath& key_file,
+ std::vector<uint8>* output);
+
+ bool Verify(const std::string& data,
+ const std::vector<uint8> signature,
+ const std::vector<uint8> public_key);
+
+ bool Sign(const std::string& data,
+ std::vector<uint8>* OUT_signature,
+ base::RSAPrivateKey* key);
+
+ RSAPrivateKey* FindPrivateKey(const std::vector<uint8>& key);
- bool ExportPublicKey(SECKEYPublicKey* key, const FilePath& key_file);
+ FilePath GetOwnerKeyFilePath();
- SECKEYPublicKey* ImportPublicKey(const FilePath& key_file);
+ protected:
+ virtual ~OwnerKeyUtilsImpl();
private:
- // Fills in fields of |key_der| with DER encoded data from a file at
- // |key_file|. The caller must pass in a pointer to an actual SECItem
- // struct for |key_der|. |key_der->data| should be initialized to NULL
- // and |key_der->len| should be set to 0.
- //
- // Upon success, data is stored in key_der->data, and the caller takes
- // ownership. Returns false on error.
- //
- // To free the data, call
- // SECITEM_FreeItem(key_der, PR_FALSE);
- static bool ReadDERFromFile(const FilePath& key_file, SECItem* key_der);
-
- // The place outside the owner's encrypted home directory where her
+ // The file outside the owner's encrypted home directory where her
// key will live.
static const char kOwnerKeyFile[];
// Key generation parameters.
- static const uint32 kKeyGenMechanism; // used by PK11_GenerateKeyPair()
- static const unsigned long kExponent;
- static const int kKeySizeInBits;
+ static const uint16 kKeySizeInBits;
DISALLOW_COPY_AND_ASSIGN(OwnerKeyUtilsImpl);
};
-OwnerKeyUtils::OwnerKeyUtils() {}
-
-OwnerKeyUtils::~OwnerKeyUtils() {}
-
+// Defined here, instead of up above, because we need OwnerKeyUtilsImpl.
OwnerKeyUtils* OwnerKeyUtils::Create() {
if (!factory_)
return new OwnerKeyUtilsImpl();
@@ -76,162 +97,63 @@ const char OwnerKeyUtilsImpl::kOwnerKeyFile[] = "/var/lib/whitelist/owner.key";
// We're generating and using 2048-bit RSA keys.
// static
-const uint32 OwnerKeyUtilsImpl::kKeyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
-// static
-const unsigned long OwnerKeyUtilsImpl::kExponent = 65537UL;
-// static
-const int OwnerKeyUtilsImpl::kKeySizeInBits = 2048;
-
-OwnerKeyUtilsImpl::OwnerKeyUtilsImpl(){}
-
-OwnerKeyUtilsImpl::~OwnerKeyUtilsImpl() {}
-
-bool OwnerKeyUtilsImpl::GenerateKeyPair(SECKEYPrivateKey** private_key_out,
- SECKEYPublicKey** public_key_out) {
- DCHECK(private_key_out);
- DCHECK(public_key_out);
-
- *private_key_out = NULL;
- *public_key_out = NULL;
-
- // Temporary structures used for generating the result
- // in the right format.
- PK11SlotInfo* slot = NULL;
- PK11RSAGenParams rsa_key_gen_params;
- void* key_gen_params;
-
- bool is_success = true; // Set to false as soon as a step fails.
-
- rsa_key_gen_params.keySizeInBits = kKeySizeInBits;
- rsa_key_gen_params.pe = kExponent;
- key_gen_params = &rsa_key_gen_params;
+const uint16 OwnerKeyUtilsImpl::kKeySizeInBits = 2048;
+OwnerKeyUtilsImpl::OwnerKeyUtilsImpl() {
// Ensure NSS is initialized.
base::EnsureNSSInit();
+}
- slot = base::GetDefaultNSSKeySlot();
- if (!slot) {
- LOG(ERROR) << "Couldn't get Internal key slot!";
- is_success = false;
- goto failure;
- }
+OwnerKeyUtilsImpl::~OwnerKeyUtilsImpl() {}
- // Need to make sure that the token was initialized.
- // Assume a null password.
- if (SECSuccess != PK11_Authenticate(slot, PR_TRUE, NULL)) {
- LOG(ERROR) << "Couldn't initialze PK11 token!";
- is_success = false;
- goto failure;
- }
+RSAPrivateKey* OwnerKeyUtilsImpl::GenerateKeyPair() {
+ return RSAPrivateKey::CreateSensitive(kKeySizeInBits);
+}
- LOG(INFO) << "Creating key pair...";
- {
- base::AutoNSSWriteLock lock;
- *private_key_out = PK11_GenerateKeyPair(slot,
- kKeyGenMechanism,
- key_gen_params,
- public_key_out,
- PR_TRUE, // isPermanent?
- PR_TRUE, // isSensitive?
- NULL);
- }
- LOG(INFO) << "done.";
+bool OwnerKeyUtilsImpl::ExportPublicKeyViaDbus(RSAPrivateKey* pair,
+ LoginLibrary::Delegate* d) {
+ DCHECK(pair);
+ bool ok = false;
- if (!*private_key_out) {
- LOG(INFO) << "Generation of Keypair failed!";
- is_success = false;
- goto failure;
+ std::vector<uint8> to_export;
+ if (!pair->ExportPublicKey(&to_export)) {
+ LOG(ERROR) << "Formatting key for export via dbus failed!";
+ return false;
}
- failure:
- if (!is_success) {
- LOG(ERROR) << "Owner key generation failed! (NSS error code "
- << PR_GetError() << ")";
- // Do cleanups
- base::AutoNSSWriteLock lock;
- if (*private_key_out) {
- PK11_DestroyTokenObject((*private_key_out)->pkcs11Slot,
- (*private_key_out)->pkcs11ID);
- SECKEY_DestroyPrivateKey(*private_key_out);
- }
- if (*public_key_out) {
- PK11_DestroyTokenObject((*public_key_out)->pkcs11Slot,
- (*public_key_out)->pkcs11ID);
- SECKEY_DestroyPublicKey(*public_key_out);
- }
- } else {
- LOG(INFO) << "Owner key generation succeeded!";
- }
- if (slot != NULL) {
- PK11_FreeSlot(slot);
- }
+ if (CrosLibrary::Get()->EnsureLoaded())
+ ok = CrosLibrary::Get()->GetLoginLibrary()->SetOwnerKeyAsync(to_export, d);
- return is_success;
+ return ok;
}
-bool OwnerKeyUtilsImpl::ExportPublicKey(SECKEYPublicKey* key,
- const FilePath& key_file) {
- DCHECK(key);
- SECItem* der;
+bool OwnerKeyUtilsImpl::ExportPublicKeyToFile(RSAPrivateKey* pair,
+ const FilePath& key_file) {
+ DCHECK(pair);
bool ok = false;
int safe_file_size = 0;
- // Instead of exporting/importing the key directly, I'm actually
- // going to use a SubjectPublicKeyInfo. The reason is because NSS
- // exports functions that encode/decode these kinds of structures, while
- // it does not export the ones that deal directly with public keys.
- der = SECKEY_EncodeDERSubjectPublicKeyInfo(key);
- if (!der) {
- LOG(ERROR) << "Could not encode public key for export!";
+ std::vector<uint8> to_export;
+ if (!pair->ExportPublicKey(&to_export)) {
+ LOG(ERROR) << "Formatting key for export failed!";
return false;
}
- if (der->len > static_cast<uint>(INT_MAX)) {
- LOG(ERROR) << "key is too big! " << der->len;
+ if (to_export.size() > static_cast<uint>(INT_MAX)) {
+ LOG(ERROR) << "key is too big! " << to_export.size();
} else {
- safe_file_size = static_cast<int>(der->len);
+ safe_file_size = static_cast<int>(to_export.size());
ok = (safe_file_size ==
file_util::WriteFile(key_file,
- reinterpret_cast<char*>(der->data),
- der->len));
+ reinterpret_cast<char*>(&to_export.front()),
+ safe_file_size));
}
- SECITEM_FreeItem(der, PR_TRUE);
return ok;
}
-SECKEYPublicKey* OwnerKeyUtilsImpl::ImportPublicKey(const FilePath& key_file) {
- SECItem key_der;
-
- if (!ReadDERFromFile(key_file, &key_der)) {
- PLOG(ERROR) << "Could not read in key from " << key_file.value() << ":";
- return NULL;
- }
-
- // See the comment in ExportPublicKey() for why I wrote a
- // SubjectPublicKeyInfo to disk instead of a key.
- CERTSubjectPublicKeyInfo* spki =
- SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
- if (!spki) {
- LOG(ERROR) << "Could not decode key info: " << PR_GetError();
- SECITEM_FreeItem(&key_der, PR_FALSE);
- return NULL;
- }
-
- SECKEYPublicKey *public_key = SECKEY_ExtractPublicKey(spki);
- SECKEY_DestroySubjectPublicKeyInfo(spki);
- SECITEM_FreeItem(&key_der, PR_FALSE);
- return public_key;
-}
-
-// static
-bool OwnerKeyUtilsImpl::ReadDERFromFile(const FilePath& key_file,
- SECItem* key_der) {
- // I'd use NSS' SECU_ReadDERFromFile() here, but the SECU_* functions are
- // considered internal to the NSS command line utils.
- // This code is lifted, in spirit, from the implementation of that function.
- DCHECK(key_der) << "Don't pass NULL for |key_der|";
-
+bool OwnerKeyUtilsImpl::ImportPublicKey(const FilePath& key_file,
+ std::vector<uint8>* output) {
// Get the file size (must fit in a 32 bit int for NSS).
int64 file_size;
if (!file_util::GetFileSize(key_file, &file_size)) {
@@ -245,23 +167,48 @@ bool OwnerKeyUtilsImpl::ReadDERFromFile(const FilePath& key_file,
}
int32 safe_file_size = static_cast<int32>(file_size);
- // Allocate space for the DER encoded data.
- key_der->data = NULL;
- if (!SECITEM_AllocItem(NULL, key_der, safe_file_size)) {
- LOG(ERROR) << "Could not create space for DER encoded key";
- return false;
- }
-
+ output->resize(safe_file_size);
// Get the key data off of disk
int data_read = file_util::ReadFile(key_file,
- reinterpret_cast<char*>(key_der->data),
+ reinterpret_cast<char*>(&(output->at(0))),
safe_file_size);
+ return data_read == safe_file_size;
+}
+
+bool OwnerKeyUtilsImpl::Verify(const std::string& data,
+ const std::vector<uint8> signature,
+ const std::vector<uint8> public_key) {
+ base::SignatureVerifier verifier;
+ if (!verifier.VerifyInit(kSignatureAlgorithm, sizeof(kSignatureAlgorithm),
+ &signature[0], signature.size(),
+ &public_key[0], public_key.size())) {
+ return false;
+ }
+
+ verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),
+ data.length());
+ return (verifier.VerifyFinal());
+}
- if (data_read != safe_file_size) {
- LOG(ERROR) << "Read the wrong amount of data from the DER encoded key! "
- << data_read;
- SECITEM_FreeItem(key_der, PR_FALSE);
+bool OwnerKeyUtilsImpl::Sign(const std::string& data,
+ std::vector<uint8>* OUT_signature,
+ base::RSAPrivateKey* key) {
+ scoped_ptr<base::SignatureCreator> signer(
+ base::SignatureCreator::Create(key));
+ if (!signer->Update(reinterpret_cast<const uint8*>(data.c_str()),
+ data.length())) {
return false;
}
- return true;
+ return signer->Final(OUT_signature);
+}
+
+RSAPrivateKey* OwnerKeyUtilsImpl::FindPrivateKey(
+ const std::vector<uint8>& key) {
+ return RSAPrivateKey::FindFromPublicKeyInfo(key);
+}
+
+FilePath OwnerKeyUtilsImpl::GetOwnerKeyFilePath() {
+ return FilePath(OwnerKeyUtilsImpl::kOwnerKeyFile);
}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/owner_key_utils.h b/chrome/browser/chromeos/login/owner_key_utils.h
index 8900ed4..4921745 100644
--- a/chrome/browser/chromeos/login/owner_key_utils.h
+++ b/chrome/browser/chromeos/login/owner_key_utils.h
@@ -4,21 +4,23 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_KEY_UTILS_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_KEY_UTILS_H_
+#pragma once
+
+#include <vector>
#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/chromeos/cros/login_library.h"
-// Forward declarations of NSS data structures.
-struct SECKEYPrivateKeyStr;
-struct SECKEYPublicKeyStr;
-struct SECItemStr;
+class FilePath;
-typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey;
-typedef struct SECKEYPublicKeyStr SECKEYPublicKey;
-typedef struct SECItemStr SECItem;
+namespace base {
+class RSAPrivateKey;
+}
-class FilePath;
+namespace chromeos {
-class OwnerKeyUtils {
+class OwnerKeyUtils : public base::RefCounted<OwnerKeyUtils> {
public:
class Factory {
public:
@@ -26,7 +28,6 @@ class OwnerKeyUtils {
};
OwnerKeyUtils();
- virtual ~OwnerKeyUtils();
// Sets the factory used by the static method Create to create an
// OwnerKeyUtils. OwnerKeyUtils does not take ownership of
@@ -42,29 +43,59 @@ class OwnerKeyUtils {
// Generate a public/private RSA keypair and store them in the NSS database.
// The keys will be kKeySizeInBits in length (Recommend >= 2048 bits).
+ // The caller takes ownership.
//
- // Returns false on error.
- //
- // The caller takes ownership of both objects, which are allocated by libnss.
- // To free them, call
- // SECKEY_DestroyPrivateKey(*private_key_out);
- // SECKEY_DestroyPublicKey(*public_key_out);
- virtual bool GenerateKeyPair(SECKEYPrivateKey** private_key_out,
- SECKEYPublicKey** public_key_out) = 0;
-
- // DER encodes |key| and writes it out to |key_file|.
+ // Returns NULL on error.
+ virtual base::RSAPrivateKey* GenerateKeyPair() = 0;
+
+ // DER encodes public half of |pair| and asynchronously exports it via DBus.
+ // The data sent is a DER-encoded X509 SubjectPublicKeyInfo object.
+ // Returns false on error, true if the attempt is successfully begun.
+ // d->Run() will be called with a boolean indicating success or failure when
+ // the attempt is complete.
+ virtual bool ExportPublicKeyViaDbus(base::RSAPrivateKey* pair,
+ LoginLibrary::Delegate* d) = 0;
+
+ // DER encodes public half of |pair| and writes it out to |key_file|.
// The blob on disk is a DER-encoded X509 SubjectPublicKeyInfo object.
// Returns false on error.
- virtual bool ExportPublicKey(SECKEYPublicKey* key,
- const FilePath& key_file) = 0;
+ virtual bool ExportPublicKeyToFile(base::RSAPrivateKey* pair,
+ const FilePath& key_file) = 0;
// Assumes that the file at |key_file| exists.
- // Caller takes ownership of returned object; returns NULL on error.
- // To free, call SECKEY_DestroyPublicKey.
- virtual SECKEYPublicKey* ImportPublicKey(const FilePath& key_file) = 0;
+ // Upon success, returns true and populates |output|. False on failure.
+ virtual bool ImportPublicKey(const FilePath& key_file,
+ std::vector<uint8>* output) = 0;
+
+ // Verfiy that |signature| is a Sha1-with-RSA signature over |data| with
+ // |public_key|
+ // Returns true if so, false on bad signature or other error.
+ virtual bool Verify(const std::string& data,
+ const std::vector<uint8> signature,
+ const std::vector<uint8> public_key) = 0;
+
+ // Sign |data| with |key| using Sha1 with RSA. If successful, return true
+ // and populate |OUT_signature|.
+ virtual bool Sign(const std::string& data,
+ std::vector<uint8>* OUT_signature,
+ base::RSAPrivateKey* key) = 0;
+
+ // Looks for the private key associated with |key| in the default slot,
+ // and returns it if it can be found. Returns NULL otherwise.
+ // Caller takes ownership.
+ virtual base::RSAPrivateKey* FindPrivateKey(
+ const std::vector<uint8>& key) = 0;
+
+ virtual FilePath GetOwnerKeyFilePath() = 0;
+
+ protected:
+ virtual ~OwnerKeyUtils();
private:
+ friend class base::RefCounted<OwnerKeyUtils>;
static Factory* factory_;
};
+} // namespace chromeos
+
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_OWNER_KEY_UTILS_H_
diff --git a/chrome/browser/chromeos/login/owner_key_utils_unittest.cc b/chrome/browser/chromeos/login/owner_key_utils_unittest.cc
index 7a7e9e7..3b21466 100644
--- a/chrome/browser/chromeos/login/owner_key_utils_unittest.cc
+++ b/chrome/browser/chromeos/login/owner_key_utils_unittest.cc
@@ -4,112 +4,57 @@
#include "chrome/browser/chromeos/login/owner_key_utils.h"
-#include <cert.h>
-#include <keyhi.h>
-#include <keythi.h> // KeyType enum
-#include <pk11pub.h>
-#include <stdlib.h>
-
#include <string>
+#include <vector>
+#include "base/crypto/rsa_private_key.h"
#include "base/file_path.h"
#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/nss_util_internal.h"
#include "base/nss_util.h"
-#include "base/scoped_ptr.h"
+#include "base/nss_util_internal.h"
+#include "base/ref_counted.h"
#include "base/scoped_temp_dir.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
class OwnerKeyUtilsTest : public ::testing::Test {
public:
- OwnerKeyUtilsTest()
- : private_key_(NULL),
- public_key_(NULL),
- utils_(OwnerKeyUtils::Create()) {
-
- }
+ OwnerKeyUtilsTest() : utils_(OwnerKeyUtils::Create()) {}
virtual ~OwnerKeyUtilsTest() {}
virtual void SetUp() {
base::OpenPersistentNSSDB();
}
- virtual void TearDown() {
- if (private_key_) {
- PK11_DestroyTokenObject(private_key_->pkcs11Slot, private_key_->pkcs11ID);
- SECKEY_DestroyPrivateKey(private_key_);
- }
- if (public_key_) {
- PK11_DestroyTokenObject(public_key_->pkcs11Slot, public_key_->pkcs11ID);
- SECKEY_DestroyPublicKey(public_key_);
- }
- }
-
- SECKEYPrivateKey* private_key_;
- SECKEYPublicKey* public_key_;
- scoped_ptr<OwnerKeyUtils> utils_;
+ scoped_refptr<OwnerKeyUtils> utils_;
};
-TEST_F(OwnerKeyUtilsTest, KeyGenerate) {
- EXPECT_TRUE(utils_->GenerateKeyPair(&private_key_, &public_key_));
- EXPECT_TRUE(private_key_ != NULL);
- ASSERT_TRUE(public_key_ != NULL);
- EXPECT_EQ(public_key_->keyType, rsaKey);
-}
-
TEST_F(OwnerKeyUtilsTest, ExportImportPublicKey) {
- EXPECT_TRUE(utils_->GenerateKeyPair(&private_key_, &public_key_));
+ scoped_ptr<base::RSAPrivateKey> pair(utils_->GenerateKeyPair());
+ ASSERT_NE(pair.get(), reinterpret_cast<base::RSAPrivateKey*>(NULL));
+ // Export public key to file.
ScopedTempDir tmpdir;
FilePath tmpfile;
ASSERT_TRUE(tmpdir.CreateUniqueTempDir());
ASSERT_TRUE(file_util::CreateTemporaryFileInDir(tmpdir.path(), &tmpfile));
-
- EXPECT_TRUE(utils_->ExportPublicKey(public_key_, tmpfile));
-
- // Now, verify that we can look up the private key, given the public key
- // we exported. We'll create
- // an ID from the key, and then use that ID to query the token in the
- // default slot for a matching private key. Then we'll make sure it's
- // the same as |private_key_|
- PK11SlotInfo* slot = NULL;
- SECItem* ck_id = NULL;
- SECKEYPublicKey* from_disk = NULL;
- SECKEYPrivateKey* found = NULL;
-
- slot = base::GetDefaultNSSKeySlot();
- EXPECT_TRUE(slot != NULL);
- if (NULL == slot)
- goto cleanup;
-
- from_disk = utils_->ImportPublicKey(tmpfile);
- ASSERT_TRUE(from_disk != NULL);
-
- ck_id = PK11_MakeIDFromPubKey(&(from_disk->u.rsa.modulus));
- EXPECT_TRUE(ck_id != NULL);
- if (NULL == ck_id)
- goto cleanup;
-
- found = PK11_FindKeyByKeyID(slot, ck_id, NULL);
- EXPECT_TRUE(found != NULL);
- if (NULL == found)
- goto cleanup;
-
- EXPECT_EQ(private_key_->pkcs11ID, found->pkcs11ID);
-
- cleanup:
- if (slot)
- PK11_FreeSlot(slot);
- if (from_disk)
- SECKEY_DestroyPublicKey(from_disk);
- if (found)
- SECKEY_DestroyPrivateKey(found);
- if (ck_id)
- SECITEM_ZfreeItem(ck_id, PR_TRUE);
+ ASSERT_TRUE(utils_->ExportPublicKeyToFile(pair.get(), tmpfile));
+
+ // Export public key, so that we can compare it to the one we get off disk.
+ std::vector<uint8> public_key;
+ ASSERT_TRUE(pair->ExportPublicKey(&public_key));
+ std::vector<uint8> from_disk;
+ ASSERT_TRUE(utils_->ImportPublicKey(tmpfile, &from_disk));
+
+ std::vector<uint8>::iterator pubkey_it;
+ std::vector<uint8>::iterator disk_it;
+ for (pubkey_it = public_key.begin(), disk_it = from_disk.begin();
+ pubkey_it < public_key.end();
+ pubkey_it++, disk_it++) {
+ EXPECT_EQ(*pubkey_it, *disk_it);
+ }
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/password_changed_view.cc b/chrome/browser/chromeos/login/password_changed_view.cc
index ddb36ae..87c89d5 100644
--- a/chrome/browser/chromeos/login/password_changed_view.cc
+++ b/chrome/browser/chromeos/login/password_changed_view.cc
@@ -4,11 +4,12 @@
#include "chrome/browser/chromeos/login/password_changed_view.h"
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "base/keyboard_codes.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
+#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "views/controls/button/radio_button.h"
@@ -60,8 +61,10 @@ gfx::Size PasswordChangedView::GetPreferredSize() {
void PasswordChangedView::ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) {
- if (is_add && child == this)
+ if (is_add && child == this) {
Init();
+ WizardAccessibilityHelper::GetInstance()->MaybeEnableAccessibility(this);
+ }
}
void PasswordChangedView::Init() {
@@ -162,7 +165,7 @@ void PasswordChangedView::ButtonPressed(Button* sender,
bool PasswordChangedView::HandleKeystroke(views::Textfield* s,
const views::Textfield::Keystroke& keystroke) {
- if (keystroke.GetKeyboardCode() == base::VKEY_RETURN) {
+ if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
ExitDialog();
return true;
}
diff --git a/chrome/browser/chromeos/login/password_changed_view.h b/chrome/browser/chromeos/login/password_changed_view.h
index 535a05a..48f6ca3 100644
--- a/chrome/browser/chromeos/login/password_changed_view.h
+++ b/chrome/browser/chromeos/login/password_changed_view.h
@@ -4,10 +4,10 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_PASSWORD_CHANGED_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_PASSWORD_CHANGED_VIEW_H_
+#pragma once
#include <string>
-#include "app/message_box_flags.h"
#include "views/controls/button/button.h"
#include "views/controls/textfield/textfield.h"
#include "views/view.h"
diff --git a/chrome/browser/chromeos/login/registration_screen.cc b/chrome/browser/chromeos/login/registration_screen.cc
index 40348d7..5c60331 100644
--- a/chrome/browser/chromeos/login/registration_screen.cc
+++ b/chrome/browser/chromeos/login/registration_screen.cc
@@ -17,6 +17,7 @@
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_about_job.h"
#include "net/url_request/url_request_filter.h"
+#include "views/widget/widget_gtk.h"
namespace chromeos {
@@ -86,15 +87,14 @@ void RegistrationScreen::OnPageLoaded() {
if (g_browser_process) {
const std::string locale = g_browser_process->GetApplicationLocale();
input_method::EnableInputMethods(
- locale, input_method::kKeyboardLayoutsOnly, "");
- // TODO(yusukes,suzhe): Change the 2nd argument to kAllInputMethods when
- // crosbug.com/2670 is fixed.
+ locale, input_method::kAllInputMethods, "");
}
view()->ShowPageContent();
}
void RegistrationScreen::OnPageLoadFailed(const std::string& url) {
- CloseScreen(ScreenObserver::CONNECTION_FAILED);
+ LOG(ERROR) << "Error loading registration page: " << url;
+ CloseScreen(ScreenObserver::REGISTRATION_SKIPPED);
}
///////////////////////////////////////////////////////////////////////////////
@@ -106,9 +106,11 @@ void RegistrationScreen::OnPageLoadFailed(const std::string& url) {
PageTransition::Type transition) {
if (url.spec() == kRegistrationSuccessUrl) {
source->Stop();
+ LOG(INFO) << "Registration form completed.";
CloseScreen(ScreenObserver::REGISTRATION_SUCCESS);
} else if (url.spec() == kRegistrationSkippedUrl) {
source->Stop();
+ LOG(INFO) << "Registration form skipped.";
CloseScreen(ScreenObserver::REGISTRATION_SKIPPED);
} else {
source->Stop();
@@ -118,6 +120,13 @@ void RegistrationScreen::OnPageLoadFailed(const std::string& url) {
}
}
+void RegistrationScreen::HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) {
+ views::Widget* widget = view()->GetWidget();
+ if (widget && event.os_event && !event.skip_in_browser)
+ static_cast<views::WidgetGtk*>(widget)->HandleKeyboardEvent(event.os_event);
+}
+
///////////////////////////////////////////////////////////////////////////////
// RegistrationScreen, private:
void RegistrationScreen::CloseScreen(ScreenObserver::ExitCodes code) {
diff --git a/chrome/browser/chromeos/login/registration_screen.h b/chrome/browser/chromeos/login/registration_screen.h
index 89d1cdb..6c10f9f 100644
--- a/chrome/browser/chromeos/login/registration_screen.h
+++ b/chrome/browser/chromeos/login/registration_screen.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_REGISTRATION_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_REGISTRATION_SCREEN_H_
+#pragma once
#include <string>
@@ -91,6 +92,7 @@ class RegistrationScreen : public ViewScreen<RegistrationView>,
const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition);
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
// WebPageScreen implementation:
virtual void CloseScreen(ScreenObserver::ExitCodes code);
diff --git a/chrome/browser/chromeos/login/rounded_rect_painter.cc b/chrome/browser/chromeos/login/rounded_rect_painter.cc
index 3c2c361..a4878e5 100644
--- a/chrome/browser/chromeos/login/rounded_rect_painter.cc
+++ b/chrome/browser/chromeos/login/rounded_rect_painter.cc
@@ -4,11 +4,11 @@
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
-#include "app/resource_bundle.h"
#include "base/logging.h"
#include "gfx/canvas_skia.h"
-#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "chrome/browser/chromeos/login/helper.h"
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
#include "views/border.h"
#include "views/painter.h"
@@ -16,7 +16,6 @@ namespace chromeos {
namespace {
-const int kCornerRadius = 5;
const SkColor kScreenTopColor = SkColorSetRGB(250, 251, 251);
const SkColor kScreenBottomColor = SkColorSetRGB(204, 209, 212);
const SkColor kScreenShadowColor = SkColorSetARGB(64, 34, 54, 115);
@@ -183,7 +182,48 @@ void RoundedRectBorder::GetInsets(gfx::Insets* insets) const {
insets->Set(inset - shadow / 3, inset, inset + shadow / 3, inset);
}
-} // namespace
+// Simple solid round background.
+class RoundedBackground : public views::Background {
+ public:
+ explicit RoundedBackground(int corner_radius,
+ int stroke_width,
+ const SkColor& background_color,
+ const SkColor& stroke_color)
+ : corner_radius_(corner_radius),
+ stroke_width_(stroke_width),
+ stroke_color_(stroke_color) {
+ SetNativeControlColor(background_color);
+ }
+
+ virtual void Paint(gfx::Canvas* canvas, views::View* view) const {
+ SkRect rect;
+ rect.iset(0, 0, view->width(), view->height());
+ SkPath path;
+ path.addRoundRect(rect,
+ SkIntToScalar(corner_radius_),
+ SkIntToScalar(corner_radius_));
+ // Draw interior.
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ paint.setColor(get_color());
+ canvas->AsCanvasSkia()->drawPath(path, paint);
+ // Redraw boundary region with correspoinding color.
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(stroke_width_));
+ paint.setColor(stroke_color_);
+ canvas->AsCanvasSkia()->drawPath(path, paint);
+ }
+
+ private:
+ int corner_radius_;
+ int stroke_width_;
+ SkColor stroke_color_;
+
+ DISALLOW_COPY_AND_ASSIGN(RoundedBackground);
+};
+
+} // namespace
// static
const BorderDefinition BorderDefinition::kScreenBorder = {
@@ -191,7 +231,17 @@ const BorderDefinition BorderDefinition::kScreenBorder = {
SK_ColorBLACK,
kScreenShadow,
kScreenShadowColor,
- kCornerRadius,
+ login::kScreenCornerRadius,
+ kScreenTopColor,
+ kScreenBottomColor
+};
+
+const BorderDefinition BorderDefinition::kUserBorder = {
+ 0,
+ SK_ColorBLACK,
+ 0,
+ kScreenShadowColor,
+ login::kUserCornerRadius,
kScreenTopColor,
kScreenBottomColor
};
@@ -204,4 +254,12 @@ views::Border* CreateWizardBorder(const BorderDefinition* const border) {
return new RoundedRectBorder(border);
}
+views::Background* CreateRoundedBackground(int corner_radius,
+ int stroke_width,
+ SkColor background_color,
+ SkColor stroke_color) {
+ return new RoundedBackground(
+ corner_radius, stroke_width, background_color, stroke_color);
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/rounded_rect_painter.h b/chrome/browser/chromeos/login/rounded_rect_painter.h
index 3788c1b..4bd36ec 100644
--- a/chrome/browser/chromeos/login/rounded_rect_painter.h
+++ b/chrome/browser/chromeos/login/rounded_rect_painter.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_ROUNDED_RECT_PAINTER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_ROUNDED_RECT_PAINTER_H_
+#pragma once
#include "third_party/skia/include/core/SkColor.h"
namespace views {
+class Background;
class Border;
class Painter;
} // namespace views
@@ -24,6 +26,7 @@ struct BorderDefinition {
SkColor bottom_color;
static const BorderDefinition kScreenBorder;
+ static const BorderDefinition kUserBorder;
};
// Creates painter to paint view background with parameters specified.
@@ -32,6 +35,11 @@ views::Painter* CreateWizardPainter(const BorderDefinition* const border);
// that actually draws both border and background.
views::Border* CreateWizardBorder(const BorderDefinition* const border);
+// Creates simple round background.
+views::Background* CreateRoundedBackground(int corner_radius,
+ int stroke_width,
+ SkColor background_color,
+ SkColor stroke_color);
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_ROUNDED_RECT_PAINTER_H_
diff --git a/chrome/browser/chromeos/login/screen_lock_view.cc b/chrome/browser/chromeos/login/screen_lock_view.cc
index f387d48..f7d3330 100644
--- a/chrome/browser/chromeos/login/screen_lock_view.cc
+++ b/chrome/browser/chromeos/login/screen_lock_view.cc
@@ -8,9 +8,12 @@
#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"
#include "chrome/browser/chromeos/login/user_view.h"
+#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
+#include "chrome/browser/profile_manager.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -25,6 +28,8 @@ namespace chromeos {
namespace {
+const int kCornerRadius = 5;
+
// A Textfield for password, which also sets focus to itself
// when a mouse is clicked on it. This is necessary in screen locker
// as mouse events are grabbed in the screen locker.
@@ -64,10 +69,17 @@ void ScreenLockView::Init() {
NotificationType::LOGIN_USER_IMAGE_CHANGED,
NotificationService::AllSources());
- user_view_ = new UserView(this, false);
+ user_view_ = new UserView(this,
+ false, // is_login
+ true); // need_background
views::View* main = new views::View();
+ // Use rounded rect background.
+ views::Painter* painter =
+ CreateWizardPainter(&BorderDefinition::kUserBorder);
+
main->set_background(
- views::Background::CreateSolidBackground(login::kBackgroundColor));
+ views::Background::CreateBackgroundPainter(true, painter));
+ main->set_border(CreateWizardBorder(&BorderDefinition::kUserBorder));
// Password field.
password_field_ = new PasswordField();
@@ -184,7 +196,7 @@ bool ScreenLockView::HandleKeystroke(
views::Textfield* sender,
const views::Textfield::Keystroke& keystroke) {
screen_locker_->ClearErrors();
- if (keystroke.GetKeyboardCode() == base::VKEY_RETURN) {
+ if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
screen_locker_->Authenticate(password_field_->text());
return true;
}
@@ -205,4 +217,10 @@ void ScreenLockView::Observe(
user_view_->SetImage(user->image());
}
+void ScreenLockView::ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ 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 eb75d78..e826271 100644
--- a/chrome/browser/chromeos/login/screen_lock_view.h
+++ b/chrome/browser/chromeos/login/screen_lock_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCK_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCK_VIEW_H_
+#pragma once
#include "chrome/browser/chromeos/login/user_view.h"
#include "chrome/common/notification_observer.h"
@@ -67,6 +68,12 @@ class ScreenLockView : public views::View,
// UserView::Delegate implementation:
virtual void OnSignout();
+ protected:
+ // views::View implementation:
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child);
+
private:
friend class test::ScreenLockerTester;
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index ebd120d..382f854 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -9,14 +9,19 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/command_line.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"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
+#include "chrome/browser/chromeos/cros/keyboard_library.h"
+#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/cros/screen_lock_library.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/login/authenticator.h"
@@ -26,10 +31,12 @@
#include "chrome/browser/chromeos/login/screen_lock_view.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/metrics/user_metrics.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 "cros/chromeos_wm_ipc_enums.h"
#include "views/screen.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_gtk.h"
@@ -43,6 +50,9 @@ const int kGrabFailureLimit = 60;
// Each keyboard layout has a dummy input method ID which starts with "xkb:".
const char kValidInputMethodPrefix[] = "xkb:";
+// A idle time to show the screen saver in seconds.
+const int kScreenSaverIdleTimeout = 15;
+
// Observer to start ScreenLocker when the screen lock
class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
public NotificationObserver {
@@ -65,6 +75,7 @@ class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
}
virtual void LockScreen(chromeos::ScreenLockLibrary* obj) {
+ LOG(INFO) << "In: ScreenLockObserver::LockScreen";
SetupInputMethodsForScreenLocker();
chromeos::ScreenLocker::Show();
}
@@ -90,11 +101,21 @@ class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
saved_active_input_method_list_.empty()) {
chromeos::InputMethodLibrary* language =
chromeos::CrosLibrary::Get()->GetInputMethodLibrary();
+ chromeos::KeyboardLibrary* keyboard =
+ chromeos::CrosLibrary::Get()->GetKeyboardLibrary();
+
saved_previous_input_method_id_ = language->previous_input_method().id;
saved_current_input_method_id_ = language->current_input_method().id;
scoped_ptr<chromeos::InputMethodDescriptors> active_input_method_list(
language->GetActiveInputMethods());
+ const std::string hardware_keyboard =
+ keyboard->GetHardwareKeyboardLayoutName(); // e.g. "xkb:us::eng"
+ // We'll add the hardware keyboard if it's not included in
+ // |active_input_method_list| so that the user can always use the hardware
+ // keyboard on the screen locker.
+ bool should_add_hardware_keyboard = true;
+
chromeos::ImeConfigValue value;
value.type = chromeos::ImeConfigValue::kValueTypeStringList;
for (size_t i = 0; i < active_input_method_list->size(); ++i) {
@@ -105,13 +126,17 @@ class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
if (!StartsWithASCII(input_method_id, kValidInputMethodPrefix, true))
continue;
value.string_list_value.push_back(input_method_id);
+ if (input_method_id == hardware_keyboard) {
+ should_add_hardware_keyboard = false;
+ }
}
- if (value.string_list_value.empty()) {
- value.string_list_value.push_back(kFallbackInputMethodId); // US qwerty
+ if (should_add_hardware_keyboard) {
+ value.string_list_value.push_back(hardware_keyboard);
}
- language->SetImeConfig(chromeos::kGeneralSectionName,
- chromeos::kPreloadEnginesConfigName,
- value);
+ language->SetImeConfig(
+ chromeos::language_prefs::kGeneralSectionName,
+ chromeos::language_prefs::kPreloadEnginesConfigName,
+ value);
}
}
@@ -124,9 +149,10 @@ class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
chromeos::ImeConfigValue value;
value.type = chromeos::ImeConfigValue::kValueTypeStringList;
value.string_list_value = saved_active_input_method_list_;
- language->SetImeConfig(chromeos::kGeneralSectionName,
- chromeos::kPreloadEnginesConfigName,
- value);
+ language->SetImeConfig(
+ chromeos::language_prefs::kGeneralSectionName,
+ chromeos::language_prefs::kPreloadEnginesConfigName,
+ value);
// Send previous input method id first so Ctrl+space would work fine.
if (!saved_previous_input_method_id_.empty())
language->ChangeInputMethod(saved_previous_input_method_id_);
@@ -169,6 +195,11 @@ class LockWindow : public views::WidgetGtk {
return false;
}
+ virtual void OnDestroy(GtkWidget* object) {
+ LOG(INFO) << "OnDestroy: LockWindow destroyed";
+ views::WidgetGtk::OnDestroy(object);
+ }
+
virtual void ClearNativeFocus() {
DCHECK(toplevel_focus_widget_);
gtk_widget_grab_focus(toplevel_focus_widget_);
@@ -206,6 +237,11 @@ class GrabWidget : public views::WidgetGtk {
virtual void Show() {
views::WidgetGtk::Show();
+ // Now steal all inputs.
+ TryGrabAllInputs();
+ }
+
+ void ClearGrab() {
GtkWidget* current_grab_window;
// Grab gtk input first so that the menu holding grab will close itself.
gtk_grab_add(window_contents());
@@ -217,9 +253,6 @@ class GrabWidget : public views::WidgetGtk {
// until it's empty.
while ((current_grab_window = gtk_grab_get_current()) != NULL)
gtk_grab_remove(current_grab_window);
-
- // Now steal all inputs.
- TryGrabAllInputs();
}
virtual gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event) {
@@ -256,9 +289,12 @@ class GrabWidget : public views::WidgetGtk {
};
void GrabWidget::TryGrabAllInputs() {
- if (kbd_grab_status_ != GDK_GRAB_SUCCESS)
+ ClearGrab();
+
+ if (kbd_grab_status_ != GDK_GRAB_SUCCESS) {
kbd_grab_status_ = gdk_keyboard_grab(window_contents()->window, FALSE,
GDK_CURRENT_TIME);
+ }
if (mouse_grab_status_ != GDK_GRAB_SUCCESS) {
mouse_grab_status_ =
gdk_pointer_grab(window_contents()->window,
@@ -273,8 +309,8 @@ void GrabWidget::TryGrabAllInputs() {
if ((kbd_grab_status_ != GDK_GRAB_SUCCESS ||
mouse_grab_status_ != GDK_GRAB_SUCCESS) &&
grab_failure_count_++ < kGrabFailureLimit) {
- DLOG(WARNING) << "Failed to grab inputs. Trying again in 1 second: kbd="
- << kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
+ LOG(WARNING) << "Failed to grab inputs. Trying again in 1 second: kbd="
+ << kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
task_factory_.NewRunnableMethod(&GrabWidget::TryGrabAllInputs),
@@ -293,7 +329,7 @@ void GrabWidget::TryGrabAllInputs() {
// addition to other background components.
class ScreenLockerBackgroundView : public chromeos::BackgroundView {
public:
- ScreenLockerBackgroundView(views::WidgetGtk* lock_widget)
+ explicit ScreenLockerBackgroundView(views::WidgetGtk* lock_widget)
: lock_widget_(lock_widget) {
}
@@ -330,23 +366,30 @@ ScreenLocker* ScreenLocker::screen_locker_ = NULL;
// See screen_locker.h for more details.
class MouseEventRelay : public MessageLoopForUI::Observer {
public:
- MouseEventRelay(GdkWindow* src, GdkWindow* dest) : src_(src), dest_(dest) {
+ MouseEventRelay(GdkWindow* src, GdkWindow* dest)
+ : src_(src),
+ dest_(dest),
+ initialized_(false) {
DCHECK(src_);
DCHECK(dest_);
- gint src_x, src_y, dest_x, dest_y, width, height, depth;
- gdk_window_get_geometry(src_, &src_x, &src_y, &width, &height, &depth);
- gdk_window_get_geometry(dest_, &dest_x, &dest_y, &width, &height, &depth);
-
- offset_.SetPoint(dest_x - src_x, dest_y - src_y);
}
virtual void WillProcessEvent(GdkEvent* event) {}
virtual void DidProcessEvent(GdkEvent* event) {
- if (event->any.window != src_) {
+ if (event->any.window != src_)
return;
+ if (!initialized_) {
+ gint src_x, src_y, dest_x, dest_y, width, height, depth;
+ gdk_window_get_geometry(dest_, &dest_x, &dest_y, &width, &height, &depth);
+ // wait to compute offset until the info bubble widget's location
+ // is available.
+ if (dest_x < 0 || dest_y < 0)
+ return;
+ gdk_window_get_geometry(src_, &src_x, &src_y, &width, &height, &depth);
+ offset_.SetPoint(dest_x - src_x, dest_y - src_y);
+ initialized_ = true;
}
-
if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_BUTTON_RELEASE) {
GdkEvent* copy = gdk_event_copy(event);
@@ -359,8 +402,8 @@ class MouseEventRelay : public MessageLoopForUI::Observer {
gdk_event_free(copy);
} else if (event->type == GDK_MOTION_NOTIFY) {
GdkEvent* copy = gdk_event_copy(event);
- copy->button.window = dest_;
- g_object_ref(copy->button.window);
+ copy->motion.window = dest_;
+ g_object_ref(copy->motion.window);
copy->motion.x -= offset_.x();
copy->motion.y -= offset_.y();
@@ -372,6 +415,7 @@ class MouseEventRelay : public MessageLoopForUI::Observer {
private:
GdkWindow* src_;
GdkWindow* dest_;
+ bool initialized_;
// Offset from src_'s origin to dest_'s origin.
gfx::Point offset_;
@@ -381,6 +425,7 @@ class MouseEventRelay : public MessageLoopForUI::Observer {
// A event observer used to unlock the screen upon user's action
// without asking password. Used in BWSI and auto login mode.
+// TODO(oshima): consolidate InputEventObserver and LockerInputEventObserver.
class InputEventObserver : public MessageLoopForUI::Observer {
public:
explicit InputEventObserver(ScreenLocker* screen_locker)
@@ -411,7 +456,42 @@ class InputEventObserver : public MessageLoopForUI::Observer {
DISALLOW_COPY_AND_ASSIGN(InputEventObserver);
};
-////////////////////////////////////////////////////////////////////////////////
+// A event observer used to show the screen locker upon
+// user action: mouse or keyboard interactions.
+// TODO(oshima): this has to be disabled while authenticating.
+class LockerInputEventObserver : public MessageLoopForUI::Observer {
+ public:
+ explicit LockerInputEventObserver(ScreenLocker* screen_locker)
+ : screen_locker_(screen_locker),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ timer_(base::TimeDelta::FromSeconds(kScreenSaverIdleTimeout), this,
+ &LockerInputEventObserver::StartScreenSaver)) {
+ }
+
+ virtual void WillProcessEvent(GdkEvent* event) {
+ if ((event->type == GDK_KEY_PRESS ||
+ event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_MOTION_NOTIFY)) {
+ timer_.Reset();
+ screen_locker_->StopScreenSaver();
+ }
+ }
+
+ virtual void DidProcessEvent(GdkEvent* event) {
+ }
+
+ private:
+ void StartScreenSaver() {
+ screen_locker_->StartScreenSaver();
+ }
+
+ chromeos::ScreenLocker* screen_locker_;
+ base::DelayTimer<LockerInputEventObserver> timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockerInputEventObserver);
+};
+
+//////////////////////////////////////////////////////////////////////////////
// ScreenLocker, public:
ScreenLocker::ScreenLocker(const UserManager::User& user)
@@ -461,14 +541,20 @@ void ScreenLocker::Init() {
lock_widget_->GetRootView()->SetVisible(false);
lock_widget_->Show();
- views::View* screen = new ScreenLockerBackgroundView(lock_widget_);
+ // Configuring the background url.
+ std::string url_string =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kScreenSaverUrl);
+ background_view_ = new ScreenLockerBackgroundView(lock_widget_);
+ background_view_->Init(GURL(url_string));
DCHECK(GTK_WIDGET_REALIZED(lock_window_->GetNativeView()));
WmIpc::instance()->SetWindowType(
lock_window_->GetNativeView(),
WM_IPC_WINDOW_CHROME_SCREEN_LOCKER,
NULL);
- lock_window_->SetContentsView(screen);
+
+ lock_window_->SetContentsView(background_view_);
lock_window_->Show();
// Don't let X draw default background, which was causing flash on
@@ -480,7 +566,7 @@ void ScreenLocker::Init() {
lock_window->set_toplevel_focus_widget(lock_widget_->window_contents());
}
-void ScreenLocker::OnLoginFailure(const std::string& error) {
+void ScreenLocker::OnLoginFailure(const LoginFailure& error) {
DLOG(INFO) << "OnLoginFailure";
EnableInput();
// Don't enable signout button here as we're showing
@@ -494,8 +580,9 @@ void ScreenLocker::OnLoginFailure(const std::string& error) {
if (error_info_)
error_info_->Close();
std::wstring msg = l10n_util::GetString(IDS_LOGIN_ERROR_AUTHENTICATING);
- if (!error.empty())
- msg += L"\n" + ASCIIToWide(error);
+ const std::string error_text = error.GetErrorString();
+ if (!error_text.empty())
+ msg += L"\n" + ASCIIToWide(error_text);
InputMethodLibrary* input_method_library =
CrosLibrary::Get()->GetInputMethodLibrary();
@@ -508,6 +595,7 @@ void ScreenLocker::OnLoginFailure(const std::string& error) {
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());
@@ -520,9 +608,7 @@ void ScreenLocker::OnLoginFailure(const std::string& error) {
void ScreenLocker::OnLoginSuccess(const std::string& username,
const GaiaAuthConsumer::ClientLoginResult& unused) {
-
- DLOG(INFO) << "OnLoginSuccess";
-
+ LOG(INFO) << "OnLoginSuccess: Sending Unlock request.";
if (CrosLibrary::Get()->EnsureLoaded())
CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenUnlockRequested();
}
@@ -565,7 +651,9 @@ void ScreenLocker::EnableInput() {
void ScreenLocker::Signout() {
if (!error_info_) {
// TODO(oshima): record this action in user metrics.
- BrowserList::CloseAllBrowsersAndExit();
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ CrosLibrary::Get()->GetLoginLibrary()->StopSession("");
+ }
// Don't hide yet the locker because the chrome screen may become visible
// briefly.
@@ -581,25 +669,27 @@ void ScreenLocker::OnGrabInputs() {
// static
void ScreenLocker::Show() {
+ LOG(INFO) << "In ScreenLocker::Show";
DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
// Exit fullscreen.
Browser* browser = BrowserList::GetLastActive();
- DCHECK(browser);
- if (browser->window()->IsFullscreen()) {
+ // browser can be NULL if we receive a lock request before the first browser
+ // window is shown.
+ if (browser && browser->window()->IsFullscreen()) {
browser->ToggleFullscreenMode();
}
- // TODO(oshima): Currently, PowerManager may send a lock screen event
- // even if a screen is locked. Investigate & solve the issue and
- // enable this again if it's possible.
- // DCHECK(!screen_locker_);
if (!screen_locker_) {
+ LOG(INFO) << "Show: Locking screen";
ScreenLocker* locker =
new ScreenLocker(UserManager::Get()->logged_in_user());
locker->Init();
} else {
- LOG(INFO) << "Show(): screen locker already exists. "
+ // PowerManager re-sends lock screen signal if it doesn't
+ // receive the response within timeout. Just send complete
+ // signal.
+ LOG(INFO) << "Show: locker already exists. "
<< "just sending completion event";
if (CrosLibrary::Get()->EnsureLoaded())
CrosLibrary::Get()->GetScreenLockLibrary()->NotifyScreenLockCompleted();
@@ -610,7 +700,7 @@ void ScreenLocker::Show() {
void ScreenLocker::Hide() {
DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
DCHECK(screen_locker_);
- LOG(INFO) << "Hide Screen Locker:" << screen_locker_;
+ LOG(INFO) << "Hide: Deleting ScreenLocker:" << screen_locker_;
MessageLoopForUI::current()->DeleteSoon(FROM_HERE, screen_locker_);
}
@@ -618,13 +708,17 @@ void ScreenLocker::Hide() {
void ScreenLocker::UnlockScreenFailed() {
DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
if (screen_locker_) {
+ // Power manager decided no to unlock the screen even if a user
+ // typed in password, for example, when a user closed the lid
+ // immediately after typing in the password.
+ LOG(INFO) << "UnlockScreenFailed: re-enabling screen locker";
screen_locker_->EnableInput();
} else {
// This can happen when a user requested unlock, but PowerManager
// rejected because the computer is closed, then PowerManager unlocked
// because it's open again and the above failure message arrives.
// This'd be extremely rare, but may still happen.
- LOG(INFO) << "Screen is unlocked";
+ LOG(INFO) << "UnlockScreenFailed: screen is already unlocked.";
}
}
@@ -641,12 +735,18 @@ ScreenLocker::~ScreenLocker() {
ClearErrors();
if (input_event_observer_.get())
MessageLoopForUI::current()->RemoveObserver(input_event_observer_.get());
+ if (locker_input_event_observer_.get()) {
+ lock_widget_->GetFocusManager()->UnregisterAccelerator(
+ views::Accelerator(app::VKEY_ESCAPE, false, false, false), this);
+ MessageLoopForUI::current()->RemoveObserver(
+ locker_input_event_observer_.get());
+ }
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
gdk_pointer_ungrab(GDK_CURRENT_TIME);
DCHECK(lock_window_);
- LOG(INFO) << "Closing ScreenLocker window";
+ LOG(INFO) << "~ScreenLocker(): Closing ScreenLocker window";
lock_window_->Close();
// lock_widget_ will be deleted by gtk's destroy signal.
screen_locker_ = NULL;
@@ -664,10 +764,20 @@ void ScreenLocker::SetAuthenticator(Authenticator* authenticator) {
}
void ScreenLocker::ScreenLockReady() {
- DLOG(INFO) << "ScreenLockReady";
+ LOG(INFO) << "ScreenLockReady: sending completed signal to power manager.";
// Don't show the password field until we grab all inputs.
lock_widget_->GetRootView()->SetVisible(true);
- EnableInput();
+ if (background_view_->ScreenSaverEnabled()) {
+ lock_widget_->GetFocusManager()->RegisterAccelerator(
+ views::Accelerator(app::VKEY_ESCAPE, false, false, false), this);
+ locker_input_event_observer_.reset(new LockerInputEventObserver(this));
+ MessageLoopForUI::current()->AddObserver(
+ locker_input_event_observer_.get());
+ StartScreenSaver();
+ } else {
+ EnableInput();
+ }
+
bool state = true;
NotificationService::current()->Notify(
NotificationType::SCREEN_LOCK_STATE_CHANGED,
@@ -692,4 +802,36 @@ void ScreenLocker::OnWindowManagerReady() {
ScreenLockReady();
}
+void ScreenLocker::StopScreenSaver() {
+ if (background_view_->IsScreenSaverVisible()) {
+ LOG(INFO) << "StopScreenSaver";
+ background_view_->HideScreenSaver();
+ if (screen_lock_view_) {
+ screen_lock_view_->SetVisible(true);
+ screen_lock_view_->RequestFocus();
+ }
+ EnableInput();
+ }
+}
+
+void ScreenLocker::StartScreenSaver() {
+ if (!background_view_->IsScreenSaverVisible()) {
+ LOG(INFO) << "StartScreenSaver";
+ background_view_->ShowScreenSaver();
+ if (screen_lock_view_) {
+ screen_lock_view_->SetEnabled(false);
+ screen_lock_view_->SetVisible(false);
+ }
+ ClearErrors();
+ }
+}
+
+bool ScreenLocker::AcceleratorPressed(const views::Accelerator& accelerator) {
+ if (!background_view_->IsScreenSaverVisible()) {
+ StartScreenSaver();
+ return true;
+ }
+ return false;
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h
index f2681b7..5162263 100644
--- a/chrome/browser/chromeos/login/screen_locker.h
+++ b/chrome/browser/chromeos/login/screen_locker.h
@@ -4,13 +4,15 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_H_
+#pragma once
#include <string>
#include "base/task.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"
-#include "chrome/browser/views/info_bubble.h"
+#include "views/accelerator.h"
namespace gfx {
class Rect;
@@ -23,10 +25,13 @@ class WidgetGtk;
namespace chromeos {
class Authenticator;
+class BackgroundView;
class InputEventObserver;
+class LockerInputEventObserver;
class MessageBubble;
class MouseEventRelay;
class ScreenLockView;
+class LoginFailure;
namespace test {
class ScreenLockerTester;
@@ -36,7 +41,8 @@ class ScreenLockerTester;
// authenticate the user. ScreenLocker manages its life cycle and will
// delete itself when it's unlocked.
class ScreenLocker : public LoginStatusConsumer,
- public InfoBubbleDelegate {
+ public MessageBubbleDelegate,
+ public views::AcceleratorTarget {
public:
explicit ScreenLocker(const UserManager::User& user);
@@ -44,7 +50,7 @@ class ScreenLocker : public LoginStatusConsumer,
void Init();
// LoginStatusConsumer implements:
- virtual void OnLoginFailure(const std::string& error);
+ virtual void OnLoginFailure(const chromeos::LoginFailure& error);
virtual void OnLoginSuccess(const std::string& username,
const GaiaAuthConsumer::ClientLoginResult& result);
@@ -53,6 +59,7 @@ class ScreenLocker : public LoginStatusConsumer,
bool closed_by_escape);
virtual bool CloseOnEscape() { return true; }
virtual bool FadeInOnShow() { return false; }
+ virtual void OnHelpLinkActivated() {}
// Authenticates the user with given |password| and authenticator.
void Authenticate(const string16& password);
@@ -94,6 +101,7 @@ class ScreenLocker : public LoginStatusConsumer,
private:
friend class DeleteTask<ScreenLocker>;
friend class test::ScreenLockerTester;
+ friend class LockerInputEventObserver;
virtual ~ScreenLocker();
@@ -106,6 +114,15 @@ class ScreenLocker : public LoginStatusConsumer,
// Called when the window manager is ready to handle locked state.
void OnWindowManagerReady();
+ // Stops screen saver.
+ void StopScreenSaver();
+
+ // Starts screen saver.
+ void StartScreenSaver();
+
+ // Overridden from AcceleratorTarget:
+ virtual bool AcceleratorPressed(const views::Accelerator& accelerator);
+
// Event handler for client-event.
CHROMEGTK_CALLBACK_1(ScreenLocker, void, OnClientEvent, GdkEventClient*);
@@ -118,6 +135,9 @@ class ScreenLocker : public LoginStatusConsumer,
// A view that accepts password.
ScreenLockView* screen_lock_view_;
+ // A view that can display html page as background.
+ BackgroundView* background_view_;
+
// Logged in user.
UserManager::User user_;
@@ -134,6 +154,10 @@ class ScreenLocker : public LoginStatusConsumer,
// Used when |unlock_on_input_| is true.
scoped_ptr<InputEventObserver> input_event_observer_;
+ // A message loop observer to detect user's keyboard/mouse event.
+ // Used when to show the screen locker upon such an event.
+ scoped_ptr<LockerInputEventObserver> locker_input_event_observer_;
+
// An info bubble to display login failure message.
MessageBubble* error_info_;
diff --git a/chrome/browser/chromeos/login/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
index 01b615c..2b0258b 100644
--- a/chrome/browser/chromeos/login/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/screen_locker_browsertest.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/command_line.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/automation/ui_controls.h"
@@ -9,11 +10,11 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
-#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
+#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
+#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_locker_tester.h"
-#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
@@ -30,7 +31,7 @@ namespace {
// An object that wait for lock state and fullscreen state.
class Waiter : public NotificationObserver {
public:
- Waiter(Browser* browser)
+ explicit Waiter(Browser* browser)
: browser_(browser) {
registrar_.Add(this,
NotificationType::SCREEN_LOCK_STATE_CHANGED,
@@ -90,9 +91,13 @@ namespace chromeos {
class ScreenLockerTest : public CrosInProcessBrowserTest {
public:
- ScreenLockerTest() {}
+ ScreenLockerTest() : mock_screen_lock_library_(NULL),
+ mock_input_method_library_(NULL) {
+ }
protected:
+ MockScreenLockLibrary *mock_screen_lock_library_;
+ MockInputMethodLibrary *mock_input_method_library_;
// Test the no password mode with different unlock scheme given by
// |unlock| function.
@@ -125,8 +130,10 @@ class ScreenLockerTest : public CrosInProcessBrowserTest {
private:
virtual void SetUpInProcessBrowserTestFixture() {
- InitStatusAreaMocks();
- InitMockScreenLockLibrary();
+ cros_mock_->InitStatusAreaMocks();
+ cros_mock_->InitMockScreenLockLibrary();
+ mock_screen_lock_library_ = cros_mock_->mock_screen_lock_library();
+ mock_input_method_library_ = cros_mock_->mock_input_method_library();
EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_))
.Times(1)
.RetiresOnSaturation();
@@ -134,13 +141,13 @@ class ScreenLockerTest : public CrosInProcessBrowserTest {
.Times(1)
.RetiresOnSaturation();
// Expectations for the status are on the screen lock window.
- SetStatusAreaMocksExpectations();
+ cros_mock_->SetStatusAreaMocksExpectations();
// Expectations for the status area on the browser window.
- SetStatusAreaMocksExpectations();
+ cros_mock_->SetStatusAreaMocksExpectations();
}
virtual void SetUpCommandLine(CommandLine* command_line) {
- command_line->AppendSwitchWithValue(switches::kLoginProfile, "user");
+ command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
command_line->AppendSwitch(switches::kNoFirstRun);
}
@@ -165,6 +172,14 @@ IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestBasic) {
ui_test_utils::WaitForNotification(
NotificationType::SCREEN_LOCK_STATE_CHANGED);
+ // Test to make sure that the widget is actually appearing and is of
+ // reasonable size, preventing a regression of
+ // http://code.google.com/p/chromium-os/issues/detail?id=5987
+ gfx::Rect lock_bounds;
+ tester->GetChildWidget()->GetBounds(&lock_bounds, true);
+ EXPECT_GT(lock_bounds.width(), 10);
+ EXPECT_GT(lock_bounds.height(), 10);
+
tester->InjectMockAuthenticator("user", "pass");
EXPECT_TRUE(tester->IsLocked());
tester->EnterPassword("fail");
@@ -208,6 +223,7 @@ IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestFullscreenExit) {
}
tester->InjectMockAuthenticator("user", "pass");
tester->EnterPassword("pass");
+ ui_test_utils::RunAllPendingInMessageLoop();
ScreenLocker::Hide();
ui_test_utils::RunAllPendingInMessageLoop();
EXPECT_FALSE(tester->IsLocked());
@@ -231,7 +247,7 @@ IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithMouseClick) {
void KeyPress(views::Widget* widget) {
ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()),
- base::VKEY_SPACE, false, false, false, false);
+ app::VKEY_SPACE, false, false, false, false);
}
IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestNoPasswordWithKeyPress) {
diff --git a/chrome/browser/chromeos/login/screen_locker_tester.cc b/chrome/browser/chromeos/login/screen_locker_tester.cc
index 8172fb9..aeec099 100644
--- a/chrome/browser/chromeos/login/screen_locker_tester.cc
+++ b/chrome/browser/chromeos/login/screen_locker_tester.cc
@@ -6,16 +6,16 @@
#include <gdk/gdkkeysyms.h>
-#include "app/l10n_util.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
-#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_lock_view.h"
+#include "chrome/browser/chromeos/login/screen_locker.h"
#include "views/controls/button/button.h"
#include "views/controls/label.h"
#include "views/controls/textfield/textfield.h"
-#include "views/widget/widget_gtk.h"
#include "views/widget/root_view.h"
+#include "views/widget/widget_gtk.h"
namespace chromeos {
@@ -65,6 +65,11 @@ views::Widget* ScreenLockerTester::GetWidget() {
return ScreenLocker::screen_locker_->lock_window_;
}
+views::Widget* ScreenLockerTester::GetChildWidget() {
+ DCHECK(ScreenLocker::screen_locker_);
+ return ScreenLocker::screen_locker_->lock_widget_;
+}
+
} // namespace test
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screen_locker_tester.h b/chrome/browser/chromeos/login/screen_locker_tester.h
index 33dc41e..bc8800e 100644
--- a/chrome/browser/chromeos/login/screen_locker_tester.h
+++ b/chrome/browser/chromeos/login/screen_locker_tester.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_TESTER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_TESTER_H_
+#pragma once
#include "base/basictypes.h"
@@ -38,6 +39,8 @@ class ScreenLockerTester {
// Returns the widget for screen locker window.
views::Widget* GetWidget();
+ views::Widget* GetChildWidget();
+
private:
friend class chromeos::ScreenLocker;
diff --git a/chrome/browser/chromeos/login/screen_observer.h b/chrome/browser/chromeos/login/screen_observer.h
index 85875f1..4cba1bb 100644
--- a/chrome/browser/chromeos/login/screen_observer.h
+++ b/chrome/browser/chromeos/login/screen_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_OBSERVER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_OBSERVER_H_
+#pragma once
#include <string>
@@ -34,6 +35,7 @@ class ScreenObserver {
USER_IMAGE_SELECTED,
USER_IMAGE_SKIPPED,
EULA_ACCEPTED,
+ EULA_BACK,
REGISTRATION_SUCCESS,
REGISTRATION_SKIPPED,
EXIT_CODES_COUNT // not a real code, must be the last
diff --git a/chrome/browser/chromeos/login/update_screen.cc b/chrome/browser/chromeos/login/update_screen.cc
index 8e9a05a..20b04b0 100644
--- a/chrome/browser/chromeos/login/update_screen.cc
+++ b/chrome/browser/chromeos/login/update_screen.cc
@@ -5,18 +5,24 @@
#include "chrome/browser/chromeos/login/update_screen.h"
#include "base/logging.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
#include "chrome/browser/chromeos/login/update_view.h"
namespace {
-// Update window should appear for at least kMinimalUpdateTime seconds.
-const int kMinimalUpdateTime = 3;
+// Progress bar stages. Each represents progress bar value
+// at the beginning of each stage.
+// TODO(nkostylev): Base stage progress values on approximate time.
+// TODO(nkostylev): Animate progress during each state.
+const int kBeforeUpdateCheckProgress = 7;
+const int kBeforeDownloadProgress = 14;
+const int kBeforeVerifyingProgress = 74;
+const int kBeforeFinalizingProgress = 81;
+const int kProgressComplete = 100;
-// Progress bar increment step.
-const int kBeforeUpdateCheckProgressIncrement = 10;
-const int kAfterUpdateCheckProgressIncrement = 10;
-const int kUpdateCompleteProgressIncrement = 75;
+// Defines what part of update progress does download part takes.
+const int kDownloadProgressIncrement = 60;
} // anonymous namespace
@@ -24,64 +30,64 @@ namespace chromeos {
UpdateScreen::UpdateScreen(WizardScreenDelegate* delegate)
: DefaultViewScreen<chromeos::UpdateView>(delegate),
- update_result_(UPGRADE_STARTED),
- update_error_(GOOGLE_UPDATE_NO_ERROR),
- checking_for_update_(true) {
+ checking_for_update_(true),
+ maximal_curtain_time_(0),
+ reboot_check_delay_(0) {
}
UpdateScreen::~UpdateScreen() {
// Remove pointer to this object from view.
if (view())
view()->set_controller(NULL);
- // Google Updater is holding a pointer to us until it reports status,
- // so we need to remove it in case we were still listening.
- if (google_updater_.get())
- google_updater_->set_status_listener(NULL);
+ CrosLibrary::Get()->GetUpdateLibrary()->RemoveObserver(this);
}
-void UpdateScreen::OnReportResults(GoogleUpdateUpgradeResult result,
- GoogleUpdateErrorCode error_code,
- const std::wstring& version) {
- // Drop the last reference to the object so that it gets cleaned up here.
- if (google_updater_.get()) {
- google_updater_->set_status_listener(NULL);
- google_updater_ = NULL;
+void UpdateScreen::UpdateStatusChanged(UpdateLibrary* library) {
+ UpdateStatusOperation status = library->status().status;
+ if (checking_for_update_ && status > UPDATE_STATUS_CHECKING_FOR_UPDATE) {
+ checking_for_update_ = false;
}
- // Depending on the result decide what to do next.
- update_result_ = result;
- update_error_ = error_code;
- LOG(INFO) << "Update result: " << result;
- if (error_code != GOOGLE_UPDATE_NO_ERROR)
- LOG(INFO) << "Update error code: " << error_code;
- LOG(INFO) << "Update version: " << version;
- switch (update_result_) {
- case UPGRADE_IS_AVAILABLE:
- checking_for_update_ = false;
- // Advance view progress bar.
- view()->AddProgress(kAfterUpdateCheckProgressIncrement);
- // Create new Google Updater instance and install the update.
- google_updater_ = CreateGoogleUpdate();
- google_updater_->CheckForUpdate(true, NULL);
- LOG(INFO) << "Installing an update";
+
+ switch (status) {
+ case UPDATE_STATUS_CHECKING_FOR_UPDATE:
+ // Do nothing in these cases, we don't want to notify the user of the
+ // check unless there is an update.
break;
- case UPGRADE_SUCCESSFUL:
- view()->AddProgress(kUpdateCompleteProgressIncrement);
- minimal_update_time_timer_.Stop();
- checking_for_update_ = false;
- // TODO(nkostylev): Call reboot API. http://crosbug.com/4002
- ExitUpdate();
+ case UPDATE_STATUS_UPDATE_AVAILABLE:
+ view()->SetProgress(kBeforeDownloadProgress);
+ LOG(INFO) << "Update available: " << library->status().new_version;
break;
- case UPGRADE_ALREADY_UP_TO_DATE:
- checking_for_update_ = false;
- view()->AddProgress(kAfterUpdateCheckProgressIncrement);
- // Fall through.
- case UPGRADE_ERROR:
- if (MinimalUpdateTimeElapsed()) {
- ExitUpdate();
+ case UPDATE_STATUS_DOWNLOADING:
+ {
+ view()->ShowCurtain(false);
+ int download_progress = static_cast<int>(
+ library->status().download_progress * kDownloadProgressIncrement);
+ view()->SetProgress(kBeforeDownloadProgress + download_progress);
}
break;
+ case UPDATE_STATUS_VERIFYING:
+ view()->SetProgress(kBeforeVerifyingProgress);
+ break;
+ case UPDATE_STATUS_FINALIZING:
+ view()->SetProgress(kBeforeFinalizingProgress);
+ break;
+ case UPDATE_STATUS_UPDATED_NEED_REBOOT:
+ view()->SetProgress(kProgressComplete);
+ view()->ShowCurtain(false);
+ CrosLibrary::Get()->GetUpdateLibrary()->RebootAfterUpdate();
+ LOG(INFO) << "Reboot API was called. Waiting for reboot.";
+ reboot_timer_.Start(base::TimeDelta::FromSeconds(reboot_check_delay_),
+ this,
+ &UpdateScreen::OnWaitForRebootTimeElapsed);
+ break;
+ case UPDATE_STATUS_IDLE:
+ case UPDATE_STATUS_ERROR:
+ case UPDATE_STATUS_REPORTING_ERROR_EVENT:
+ ExitUpdate();
+ break;
default:
NOTREACHED();
+ break;
}
}
@@ -90,72 +96,81 @@ void UpdateScreen::StartUpdate() {
view()->Reset();
view()->set_controller(this);
- // Start the minimal update time timer.
- minimal_update_time_timer_.Start(
- base::TimeDelta::FromSeconds(kMinimalUpdateTime),
- this,
- &UpdateScreen::OnMinimalUpdateTimeElapsed);
-
- // Create Google Updater object and check if there is an update available.
- checking_for_update_ = true;
- google_updater_ = CreateGoogleUpdate();
- google_updater_->CheckForUpdate(false, NULL);
- view()->AddProgress(kBeforeUpdateCheckProgressIncrement);
- LOG(INFO) << "Checking for update";
+ // Start the maximal curtain time timer.
+ if (maximal_curtain_time_ > 0) {
+ maximal_curtain_time_timer_.Start(
+ base::TimeDelta::FromSeconds(maximal_curtain_time_),
+ this,
+ &UpdateScreen::OnMaximalCurtainTimeElapsed);
+ } else {
+ view()->ShowCurtain(false);
+ }
+
+ view()->SetProgress(kBeforeUpdateCheckProgress);
+
+ if (!CrosLibrary::Get()->EnsureLoaded()) {
+ LOG(ERROR) << "Error loading CrosLibrary";
+ } else {
+ CrosLibrary::Get()->GetUpdateLibrary()->AddObserver(this);
+ LOG(INFO) << "Checking for update";
+ if (!CrosLibrary::Get()->GetUpdateLibrary()->CheckForUpdate()) {
+ ExitUpdate();
+ }
+ }
}
void UpdateScreen::CancelUpdate() {
#if !defined(OFFICIAL_BUILD)
- update_result_ = UPGRADE_ALREADY_UP_TO_DATE;
- update_error_ = GOOGLE_UPDATE_NO_ERROR;
ExitUpdate();
#endif
}
void UpdateScreen::ExitUpdate() {
- if (google_updater_.get()) {
- google_updater_->set_status_listener(NULL);
- google_updater_ = NULL;
- }
- minimal_update_time_timer_.Stop();
+ maximal_curtain_time_timer_.Stop();
ScreenObserver* observer = delegate()->GetObserver(this);
- if (observer) {
- switch (update_result_) {
- case UPGRADE_ALREADY_UP_TO_DATE:
- observer->OnExit(ScreenObserver::UPDATE_NOUPDATE);
- break;
- case UPGRADE_SUCCESSFUL:
- observer->OnExit(ScreenObserver::UPDATE_INSTALLED);
- break;
- case UPGRADE_ERROR:
- if (checking_for_update_) {
- observer->OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE);
- } else {
- observer->OnExit(ScreenObserver::UPDATE_ERROR_UPDATING);
- }
- break;
- default:
- NOTREACHED();
- }
+
+ if (!CrosLibrary::Get()->EnsureLoaded()) {
+ observer->OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE);
+ }
+
+ UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary();
+ update_library->RemoveObserver(this);
+ switch (update_library->status().status) {
+ case UPDATE_STATUS_IDLE:
+ observer->OnExit(ScreenObserver::UPDATE_NOUPDATE);
+ break;
+ case UPDATE_STATUS_ERROR:
+ case UPDATE_STATUS_REPORTING_ERROR_EVENT:
+ observer->OnExit(checking_for_update_ ?
+ ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE :
+ ScreenObserver::UPDATE_ERROR_UPDATING);
+ break;
+ default:
+ NOTREACHED();
}
}
-bool UpdateScreen::MinimalUpdateTimeElapsed() {
- return !minimal_update_time_timer_.IsRunning();
+void UpdateScreen::OnMaximalCurtainTimeElapsed() {
+ view()->ShowCurtain(false);
}
-GoogleUpdate* UpdateScreen::CreateGoogleUpdate() {
- GoogleUpdate* updater = new GoogleUpdate();
- updater->set_status_listener(this);
- return updater;
+void UpdateScreen::OnWaitForRebootTimeElapsed() {
+ LOG(ERROR) << "Unable to reboot - asking user for a manual reboot.";
+ view()->ShowManualRebootInfo();
}
-void UpdateScreen::OnMinimalUpdateTimeElapsed() {
- if (update_result_ == UPGRADE_SUCCESSFUL ||
- update_result_ == UPGRADE_ALREADY_UP_TO_DATE ||
- update_result_ == UPGRADE_ERROR) {
- ExitUpdate();
- }
+void UpdateScreen::SetMaximalCurtainTime(int seconds) {
+ if (seconds <= 0)
+ maximal_curtain_time_timer_.Stop();
+ DCHECK(!maximal_curtain_time_timer_.IsRunning());
+ maximal_curtain_time_ = seconds;
+}
+
+void UpdateScreen::SetRebootCheckDelay(int seconds) {
+ if (seconds <= 0)
+ reboot_timer_.Stop();
+ DCHECK(!reboot_timer_.IsRunning());
+ reboot_check_delay_ = seconds;
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/update_screen.h b/chrome/browser/chromeos/login/update_screen.h
index 825a2b5..2253c2e 100644
--- a/chrome/browser/chromeos/login/update_screen.h
+++ b/chrome/browser/chromeos/login/update_screen.h
@@ -4,12 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_UPDATE_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_UPDATE_SCREEN_H_
+#pragma once
-#include "base/ref_counted.h"
#include "base/timer.h"
+#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/login/update_view.h"
#include "chrome/browser/chromeos/login/view_screen.h"
-#include "chrome/browser/google_update.h"
namespace chromeos {
@@ -22,16 +22,14 @@ class UpdateController {
};
class UpdateScreen: public DefaultViewScreen<chromeos::UpdateView>,
- public GoogleUpdateStatusListener,
+ public UpdateLibrary::Observer,
public UpdateController {
public:
explicit UpdateScreen(WizardScreenDelegate* delegate);
virtual ~UpdateScreen();
- // Overridden from GoogleUpdateStatusListener:
- virtual void OnReportResults(GoogleUpdateUpgradeResult result,
- GoogleUpdateErrorCode error_code,
- const std::wstring& version);
+ // UpdateLibrary::Observer implementation:
+ virtual void UpdateStatusChanged(UpdateLibrary* library);
// Overridden from UpdateController:
virtual void StartUpdate();
@@ -39,25 +37,38 @@ class UpdateScreen: public DefaultViewScreen<chromeos::UpdateView>,
// Reports update results to the ScreenObserver.
virtual void ExitUpdate();
- // Returns true if minimal update time has elapsed.
- virtual bool MinimalUpdateTimeElapsed();
- // Creates GoogleUpdate object.
- virtual GoogleUpdate* CreateGoogleUpdate();
+
+ // Maximal curtain time get/set, in seconds.
+ int maximal_curtain_time() const { return maximal_curtain_time_; }
+ void SetMaximalCurtainTime(int seconds);
+
+ // Reboot check delay get/set, in seconds.
+ int reboot_check_delay() const { return reboot_check_delay_; }
+ void SetRebootCheckDelay(int seconds);
private:
- // Timer notification handler.
- void OnMinimalUpdateTimeElapsed();
+ // Timer notification handlers.
+ void OnMaximalCurtainTimeElapsed();
+ void OnWaitForRebootTimeElapsed();
- // Timer.
- base::OneShotTimer<UpdateScreen> minimal_update_time_timer_;
+ // Timer for the interval while curtain view is shown.
+ base::OneShotTimer<UpdateScreen> maximal_curtain_time_timer_;
- // Update status.
- GoogleUpdateUpgradeResult update_result_;
- GoogleUpdateErrorCode update_error_;
+ // Timer for the interval to wait for the reboot.
+ // If reboot didn't happen - ask user to reboot manually.
+ base::OneShotTimer<UpdateScreen> reboot_timer_;
+
+ // True if in the process of checking for update.
bool checking_for_update_;
- // Google Updater.
- scoped_refptr<GoogleUpdate> google_updater_;
+ // Maximal time (secs) the curtain view is shown. Updating progress is shown
+ // to the user when this time elapsed.
+ int maximal_curtain_time_;
+
+ // Time in seconds after which we decide that the device has not rebooted
+ // automatically. If reboot didn't happen during this interval, ask user to
+ // reboot device manually.
+ int reboot_check_delay_;
DISALLOW_COPY_AND_ASSIGN(UpdateScreen);
};
diff --git a/chrome/browser/chromeos/login/update_view.cc b/chrome/browser/chromeos/login/update_view.cc
index 9facdbe..59e20dd 100644
--- a/chrome/browser/chromeos/login/update_view.cc
+++ b/chrome/browser/chromeos/login/update_view.cc
@@ -8,13 +8,16 @@
#include "app/l10n_util.h"
#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/update_screen.h"
+#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "views/border.h"
#include "views/controls/label.h"
#include "views/controls/progress_bar.h"
+#include "views/controls/throbber.h"
#include "views/focus/focus_manager.h"
#include "views/widget/widget.h"
@@ -25,29 +28,42 @@ using views::Widget;
namespace {
+// TODO(nkostylev): Switch to GridLayout.
+
// Y offset for the 'installing updates' label.
-const int kInstallingUpdatesLabelY = 200;
+const int kInstallingUpdatesLabelYBottomFromProgressBar = 18;
// Y offset for the progress bar.
-const int kProgressBarY = 250;
+const int kProgressBarY = 199;
+// Y offset for the 'computer will restart' label.
+const int kRebootLabelYFromProgressBar = 77;
// Y offset for the 'ESCAPE to skip' label.
-const int kEscapeToSkipLabelY = 290;
+const int kEscapeToSkipLabelY = 48;
// Progress bar width.
-const int kProgressBarWidth = 450;
+const int kProgressBarWidth = 550;
+// Progress bar height.
+const int kProgressBarHeight = 18;
// Horizontal spacing (ex. min left and right margins for label on the screen).
-const int kHorizontalSpacing = 25;
+const int kHorizontalSpacing = 75;
+// Horizontal spacing between spinner and label on the curtain screen.
+const int kBetweenSpacing = 25;
// Label color.
const SkColor kLabelColor = 0xFF000000;
const SkColor kSkipLabelColor = 0xFFAA0000;
+const SkColor kManualRebootLabelColor = 0xFFAA0000;
} // namespace
namespace chromeos {
UpdateView::UpdateView(chromeos::ScreenObserver* observer)
- : escape_accelerator_(base::VKEY_ESCAPE, false, false, false),
+ : escape_accelerator_(app::VKEY_ESCAPE, false, false, false),
installing_updates_label_(NULL),
+ reboot_label_(NULL),
+ manual_reboot_label_(NULL),
progress_bar_(NULL),
+ show_curtain_(true),
+ show_manual_reboot_label_(false),
observer_(observer) {
}
@@ -60,30 +76,35 @@ void UpdateView::Init() {
&chromeos::BorderDefinition::kScreenBorder);
set_background(views::Background::CreateBackgroundPainter(true, painter));
- ResourceBundle& res_bundle = ResourceBundle::GetSharedInstance();
- gfx::Font base_font = res_bundle.GetFont(ResourceBundle::BaseFont);
-
InitLabel(&installing_updates_label_);
- installing_updates_label_->SetFont(base_font);
+ InitLabel(&reboot_label_);
+ InitLabel(&manual_reboot_label_);
+ manual_reboot_label_->SetVisible(false);
+ manual_reboot_label_->SetColor(kManualRebootLabelColor);
progress_bar_ = new views::ProgressBar();
AddChildView(progress_bar_);
- UpdateLocalizedStrings();
+ // Curtain view.
+ InitLabel(&checking_label_);
+ throbber_ = CreateDefaultThrobber();
+ AddChildView(throbber_);
#if !defined(OFFICIAL_BUILD)
- escape_to_skip_label_ = new views::Label();
+ InitLabel(&escape_to_skip_label_);
escape_to_skip_label_->SetColor(kSkipLabelColor);
- escape_to_skip_label_->SetFont(base_font);
escape_to_skip_label_->SetText(
L"Press ESCAPE to skip (Non-official builds only)");
- AddChildView(escape_to_skip_label_);
#endif
+
+ UpdateLocalizedStrings();
+ UpdateVisibility();
}
void UpdateView::Reset() {
progress_bar_->SetProgress(0);
#if !defined(OFFICIAL_BUILD)
+ ResetAccelerators();
AddAccelerator(escape_accelerator_);
#endif
}
@@ -92,35 +113,86 @@ void UpdateView::UpdateLocalizedStrings() {
installing_updates_label_->SetText(
l10n_util::GetStringF(IDS_INSTALLING_UPDATE,
l10n_util::GetString(IDS_PRODUCT_OS_NAME)));
+ reboot_label_->SetText(l10n_util::GetString(IDS_INSTALLING_UPDATE_DESC));
+ manual_reboot_label_->SetText(l10n_util::GetString(IDS_UPDATE_COMPLETED));
+ checking_label_->SetText(l10n_util::GetString(IDS_CHECKING_FOR_UPDATES));
}
void UpdateView::AddProgress(int ticks) {
progress_bar_->AddProgress(ticks);
}
-// Sets the bounds of the view, placing it at the center of the screen
-// with the |y| coordinate provided. |width| could specify desired view width
-// otherwise preferred width/height are used.
-// |x_center| specifies screen center.
-static void setViewBounds(
- views::View* view, int x_center, int y, int width = -1) {
- int preferred_width = (width >= 0) ? width : view->GetPreferredSize().width();
+void UpdateView::SetProgress(int progress) {
+ progress_bar_->SetProgress(progress);
+}
+
+void UpdateView::ShowManualRebootInfo() {
+ show_manual_reboot_label_ = true;
+ UpdateVisibility();
+}
+
+void UpdateView::ShowCurtain(bool show_curtain) {
+ if (show_curtain_ != show_curtain) {
+ show_curtain_ = show_curtain;
+ UpdateVisibility();
+ }
+}
+
+// Sets the bounds of the view, placing center of the view at the given
+// coordinates (|x| and |y|).
+static void setViewBounds(views::View* view, int x, int y) {
+ int preferred_width = view->GetPreferredSize().width();
int preferred_height = view->GetPreferredSize().height();
view->SetBounds(
- x_center - preferred_width / 2,
- y,
+ x - preferred_width / 2,
+ y - preferred_height / 2,
preferred_width,
preferred_height);
}
void UpdateView::Layout() {
- int x_center = width() / 2;
int max_width = width() - GetInsets().width() - 2 * kHorizontalSpacing;
+ int right_margin = GetInsets().right() + kHorizontalSpacing;
+ int max_height = height() - GetInsets().height();
+ int vertical_center = GetInsets().top() + max_height / 2;
+
installing_updates_label_->SizeToFit(max_width);
- setViewBounds(installing_updates_label_, x_center, kInstallingUpdatesLabelY);
- setViewBounds(progress_bar_, x_center, kProgressBarY, kProgressBarWidth);
+ reboot_label_->SizeToFit(max_width);
+ manual_reboot_label_->SizeToFit(max_width);
+
+ progress_bar_->SetBounds(right_margin,
+ vertical_center - kProgressBarHeight / 2,
+ max_width,
+ kProgressBarHeight);
+
+ installing_updates_label_->SetX(right_margin);
+ installing_updates_label_->SetY(
+ progress_bar_->y() -
+ kInstallingUpdatesLabelYBottomFromProgressBar -
+ installing_updates_label_->height());
+ reboot_label_->SetX(right_margin);
+ reboot_label_->SetY(
+ progress_bar_->y() +
+ progress_bar_->height() +
+ kRebootLabelYFromProgressBar);
+ manual_reboot_label_->SetX(reboot_label_->x());
+ manual_reboot_label_->SetY(reboot_label_->y());
+ // Curtain layout is independed.
+ int x_center = width() / 2;
+ int throbber_width = throbber_->GetPreferredSize().width();
+ checking_label_->SizeToFit(max_width - throbber_width - kBetweenSpacing);
+ int checking_label_width = checking_label_->GetPreferredSize().width();
+ int space_half = (kBetweenSpacing + 1) / 2;
+ setViewBounds(
+ throbber_, x_center - checking_label_width / 2 - space_half,
+ vertical_center);
+ setViewBounds(
+ checking_label_, x_center + (throbber_width + 1) / 2 + space_half,
+ vertical_center);
#if !defined(OFFICIAL_BUILD)
- setViewBounds(escape_to_skip_label_, x_center, kEscapeToSkipLabelY);
+ escape_to_skip_label_->SizeToFit(max_width);
+ escape_to_skip_label_->SetX(right_margin);
+ escape_to_skip_label_->SetY(kEscapeToSkipLabelY);
#endif
SchedulePaint();
}
@@ -128,7 +200,7 @@ void UpdateView::Layout() {
bool UpdateView::AcceleratorPressed(const views::Accelerator& a) {
#if !defined(OFFICIAL_BUILD)
RemoveAccelerator(escape_accelerator_);
- if (a.GetKeyCode() == base::VKEY_ESCAPE) {
+ if (a.GetKeyCode() == app::VKEY_ESCAPE) {
if (controller_ != NULL) {
controller_->CancelUpdate();
}
@@ -138,12 +210,38 @@ bool UpdateView::AcceleratorPressed(const views::Accelerator& a) {
return false;
}
+void UpdateView::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+ if (is_add && this == child)
+ WizardAccessibilityHelper::GetInstance()->MaybeEnableAccessibility(this);
+}
+
void UpdateView::InitLabel(views::Label** label) {
*label = new views::Label();
(*label)->SetColor(kLabelColor);
- (*label)->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
+ (*label)->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
(*label)->SetMultiLine(true);
+
+ ResourceBundle& res_bundle = ResourceBundle::GetSharedInstance();
+ gfx::Font label_font = res_bundle.GetFont(ResourceBundle::MediumBoldFont);
+ (*label)->SetFont(label_font);
+
AddChildView(*label);
}
+void UpdateView::UpdateVisibility() {
+ installing_updates_label_->SetVisible(
+ !show_curtain_&& !show_manual_reboot_label_);
+ reboot_label_->SetVisible(!show_curtain_&& !show_manual_reboot_label_);
+ manual_reboot_label_->SetVisible(!show_curtain_ && show_manual_reboot_label_);
+ progress_bar_->SetVisible(!show_curtain_);
+
+ checking_label_->SetVisible(show_curtain_);
+ throbber_->SetVisible(show_curtain_);
+ if (show_curtain_) {
+ throbber_->Start();
+ } else {
+ throbber_->Stop();
+ }
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/update_view.h b/chrome/browser/chromeos/login/update_view.h
index b5b09fb..0549edf 100644
--- a/chrome/browser/chromeos/login/update_view.h
+++ b/chrome/browser/chromeos/login/update_view.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_UPDATE_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_UPDATE_VIEW_H_
+#pragma once
#include "views/view.h"
namespace views {
class Label;
class ProgressBar;
+class Throbber;
} // namespace views
namespace chromeos {
@@ -23,34 +25,66 @@ class UpdateView : public views::View {
explicit UpdateView(ScreenObserver* observer);
virtual ~UpdateView();
- virtual void Init();
- virtual void Reset();
- virtual void UpdateLocalizedStrings();
+ void Init();
+ void Reset();
+ void UpdateLocalizedStrings();
// Sets update controller.
- virtual void set_controller(UpdateController* controller) {
+ void set_controller(UpdateController* controller) {
controller_ = controller;
}
// Advances view's progress bar. Maximum progress is 100.
- virtual void AddProgress(int progress);
+ void AddProgress(int progress);
+
+ // Sets the current value for the progress bar. Maximum progress is 100.
+ void SetProgress(int progress);
+
+ // Shows label with instructions for user to do a manual reboot.
+ // Usually is not called since we rely on API that will reboot after update.
+ void ShowManualRebootInfo();
+
+ // Whether curtain window with throbber and label in the center should
+ // be shown.
+ void ShowCurtain(bool show_curtain);
// views::View implementation:
virtual void Layout();
virtual bool AcceleratorPressed(const views::Accelerator& a);
+ protected:
+ // views::View implementation:
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child);
+
private:
// Creates Label control and adds it as a child.
void InitLabel(views::Label** label);
+ // Updates visibility of the elements.
+ void UpdateVisibility();
+
// Keyboard accelerator to allow cancelling update by hitting escape.
views::Accelerator escape_accelerator_;
// Dialog controls.
views::Label* installing_updates_label_;
+ views::Label* reboot_label_;
+ views::Label* manual_reboot_label_;
views::Label* escape_to_skip_label_;
views::ProgressBar* progress_bar_;
+ // Curtain views.
+ views::Label* checking_label_;
+ views::Throbber* throbber_;
+
+ // Show curtain view?
+ bool show_curtain_;
+
+ // Show manual reboot label?
+ bool show_manual_reboot_label_;
+
// Notifications receiver.
chromeos::ScreenObserver* observer_;
// Update controller.
diff --git a/chrome/browser/chromeos/login/user_controller.cc b/chrome/browser/chromeos/login/user_controller.cc
index e7de077..c005270 100644
--- a/chrome/browser/chromeos/login/user_controller.cc
+++ b/chrome/browser/chromeos/login/user_controller.cc
@@ -9,20 +9,24 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/existing_user_view.h"
#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/user_view.h"
#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 "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#include "cros/chromeos_wm_ipc_enums.h"
#include "views/background.h"
-#include "views/controls/label.h"
#include "views/controls/button/native_button.h"
+#include "views/controls/label.h"
#include "views/grid_layout.h"
+#include "views/screen.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_gtk.h"
@@ -38,7 +42,7 @@ namespace {
const int kUserNameGap = 4;
// Approximate height of controls window, this constant is used in new user
-// case to make border window size close to exsisting users.
+// case to make border window size close to existing users.
const int kControlsHeight = 26;
// Widget that notifies window manager about clicking on itself.
@@ -54,7 +58,7 @@ class ClickNotifyingWidget : public views::WidgetGtk {
private:
gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event) {
if (!controller_->is_user_selected())
- controller_->SelectUser(controller_->user_index());
+ controller_->SelectUser(controller_->user_index(), true);
return views::WidgetGtk::OnButtonPress(widget, event);
}
@@ -64,81 +68,6 @@ class ClickNotifyingWidget : public views::WidgetGtk {
DISALLOW_COPY_AND_ASSIGN(ClickNotifyingWidget);
};
-// Returns tooltip text for user name. Tooltip contains user's display name
-// and his email domain to distinguish this user from the other one with the
-// same display name.
-std::string GetNameTooltip(const UserManager::User& user) {
- const std::string& email = user.email();
- size_t at_pos = email.rfind('@');
- if (at_pos == std::string::npos) {
- NOTREACHED();
- return std::string();
- }
- size_t domain_start = at_pos + 1;
- std::string domain = email.substr(domain_start,
- email.length() - domain_start);
- return StringPrintf("%s (%s)",
- user.GetDisplayName().c_str(),
- domain.c_str());
-}
-
-// NativeButton that will always return focus to password field.
-class UserEntryNativeButton : public views::NativeButton {
- public:
- UserEntryNativeButton(UserController* controller,
- views::ButtonListener* listener,
- const std::wstring& label)
- : NativeButton(listener, label),
- controller_(controller) {}
-
- // Overridden from View:
- virtual void DidGainFocus() {
- controller_->FocusPasswordField();
- }
-
- private:
- UserController* controller_;
-
- DISALLOW_COPY_AND_ASSIGN(UserEntryNativeButton);
-};
-
-// Textfield with custom processing for Tab/Shift+Tab to select entries.
-class UserEntryTextfield : public views::Textfield {
- public:
- explicit UserEntryTextfield(UserController* controller)
- : Textfield(),
- controller_(controller) {}
-
- UserEntryTextfield(UserController* controller,
- views::Textfield::StyleFlags style)
- : Textfield(style),
- controller_(controller) {}
-
- // Overridden from View:
- virtual bool OnKeyPressed(const views::KeyEvent& e) {
- if (e.GetKeyCode() == base::VKEY_TAB) {
- int index = controller_->user_index() + (e.IsShiftDown() ? -1 : 1);
- controller_->SelectUser(index);
- return true;
- } else {
- return false;
- }
- }
-
- // Overridden from views::Textfield:
- virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
- if (e.GetKeyCode() == base::VKEY_TAB)
- return true;
- else
- return views::Textfield::SkipDefaultKeyEventProcessing(e);
- }
-
- private:
- UserController* controller_;
-
- DISALLOW_COPY_AND_ASSIGN(UserEntryTextfield);
-};
-
} // namespace
using login::kBackgroundColor;
@@ -152,14 +81,13 @@ const int UserController::kPadding = 20;
// Max size needed when an entry is not selected.
const int UserController::kUnselectedSize = 100;
-UserController::UserController(Delegate* delegate)
+UserController::UserController(Delegate* delegate, bool is_bwsi)
: user_index_(-1),
is_user_selected_(false),
- is_guest_(true),
+ is_new_user_(!is_bwsi),
+ is_bwsi_(is_bwsi),
show_name_tooltip_(false),
delegate_(delegate),
- password_field_(NULL),
- submit_button_(NULL),
controls_window_(NULL),
image_window_(NULL),
border_window_(NULL),
@@ -167,6 +95,7 @@ UserController::UserController(Delegate* delegate)
unselected_label_window_(NULL),
user_view_(NULL),
new_user_view_(NULL),
+ existing_user_view_(NULL),
label_view_(NULL),
unselected_label_view_(NULL) {
registrar_.Add(
@@ -179,12 +108,11 @@ UserController::UserController(Delegate* delegate,
const UserManager::User& user)
: user_index_(-1),
is_user_selected_(false),
- is_guest_(false),
+ is_new_user_(false),
+ is_bwsi_(false),
show_name_tooltip_(false),
user_(user),
delegate_(delegate),
- password_field_(NULL),
- submit_button_(NULL),
controls_window_(NULL),
image_window_(NULL),
border_window_(NULL),
@@ -192,6 +120,7 @@ UserController::UserController(Delegate* delegate,
unselected_label_window_(NULL),
user_view_(NULL),
new_user_view_(NULL),
+ existing_user_view_(NULL),
label_view_(NULL),
unselected_label_view_(NULL) {
registrar_.Add(
@@ -208,9 +137,12 @@ UserController::~UserController() {
unselected_label_window_->Close();
}
-void UserController::Init(int index, int total_user_count) {
+void UserController::Init(int index,
+ int total_user_count,
+ bool need_browse_without_signin) {
int controls_height = 0;
- controls_window_ = CreateControlsWindow(index, &controls_height);
+ controls_window_ =
+ CreateControlsWindow(index, &controls_height, need_browse_without_signin);
image_window_ = CreateImageWindow(index);
CreateBorderWindow(index, total_user_count, controls_height);
label_window_ = CreateLabelWindow(index, WM_IPC_WINDOW_LOGIN_LABEL);
@@ -219,29 +151,63 @@ void UserController::Init(int index, int total_user_count) {
}
void UserController::SetPasswordEnabled(bool enable) {
- DCHECK(!is_guest_);
- password_field_->SetEnabled(enable);
- submit_button_->SetEnabled(enable);
+ DCHECK(!is_new_user_);
+ existing_user_view_->password_field()->SetEnabled(enable);
+ existing_user_view_->submit_button()->SetEnabled(enable);
enable ? user_view_->StopThrobber() : user_view_->StartThrobber();
}
+std::wstring UserController::GetNameTooltip() const {
+ if (is_new_user_)
+ return l10n_util::GetString(IDS_ADD_USER);
+ if (is_bwsi_)
+ return l10n_util::GetString(IDS_GO_INCOGNITO_BUTTON);
+
+ // Tooltip contains user's display name and his email domain to distinguish
+ // this user from the other one with the same display name.
+ const std::wstring& email = UTF8ToWide(user_.email());
+ size_t at_pos = email.rfind('@');
+ if (at_pos == std::wstring::npos) {
+ NOTREACHED();
+ return std::wstring();
+ }
+ size_t domain_start = at_pos + 1;
+ std::wstring domain = email.substr(domain_start,
+ email.length() - domain_start);
+ return base::StringPrintf(L"%s (%s)",
+ user_.GetDisplayName().c_str(),
+ domain.c_str());
+}
+
+void UserController::UpdateSubmitButtonState() {
+ if (!is_new_user_) {
+ existing_user_view_->submit_button()->SetEnabled(
+ !existing_user_view_->password_field()->text().empty());
+ }
+}
+
void UserController::ClearAndEnablePassword() {
- if (is_guest_) {
+ if (is_new_user_) {
new_user_view_->ClearAndEnablePassword();
} else {
- password_field_->SetText(string16());
+ existing_user_view_->password_field()->SetText(string16());
SetPasswordEnabled(true);
FocusPasswordField();
}
}
-void UserController::EnableNameTooltip(bool enable) {
- if (is_guest_)
- return;
+void UserController::ClearAndEnableFields() {
+ if (is_new_user_) {
+ new_user_view_->ClearAndEnableFields();
+ } else {
+ ClearAndEnablePassword();
+ }
+}
+void UserController::EnableNameTooltip(bool enable) {
std::wstring tooltip_text;
if (enable)
- tooltip_text = UTF8ToWide(GetNameTooltip(user_));
+ tooltip_text = GetNameTooltip();
if (user_view_)
user_view_->SetTooltipText(tooltip_text);
@@ -259,20 +225,25 @@ void UserController::ButtonPressed(views::Button* sender,
bool UserController::HandleKeystroke(
views::Textfield* sender,
const views::Textfield::Keystroke& keystroke) {
- if (keystroke.GetKeyboardCode() == base::VKEY_RETURN) {
+ if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
Login();
return true;
- } else if (keystroke.GetKeyboardCode() == base::VKEY_LEFT) {
- SelectUser(user_index() - 1);
+ } else if (keystroke.GetKeyboardCode() == app::VKEY_LEFT) {
+ SelectUser(user_index() - 1, false);
return true;
- } else if (keystroke.GetKeyboardCode() == base::VKEY_RIGHT) {
- SelectUser(user_index() + 1);
+ } else if (keystroke.GetKeyboardCode() == app::VKEY_RIGHT) {
+ SelectUser(user_index() + 1, false);
return true;
}
delegate_->ClearErrors();
return false;
}
+void UserController::ContentsChanged(views::Textfield* sender,
+ const string16& new_contents) {
+ UpdateSubmitButtonState();
+}
+
void UserController::Observe(
NotificationType type,
const NotificationSource& source,
@@ -290,20 +261,44 @@ void UserController::Observe(
}
void UserController::Login() {
- // Delegate will reenable as necessary.
- SetPasswordEnabled(false);
+ if (is_bwsi_) {
+ delegate_->LoginOffTheRecord();
+ } else {
+ // Delegate will reenable as necessary.
+ SetPasswordEnabled(false);
- delegate_->Login(this, password_field_->text());
+ delegate_->Login(this, existing_user_view_->password_field()->text());
+ }
}
void UserController::IsActiveChanged(bool active) {
is_user_selected_ = active;
if (active) {
delegate_->OnUserSelected(this);
- user_view_->SetMenuVisible(!is_guest_);
+ user_view_->SetRemoveButtonVisible(!is_new_user_ && !is_bwsi_);
+ // Background is NULL for inactive new user pod to make it transparent.
+ if (is_new_user_ && !border_window_->GetRootView()->background()) {
+ views::Painter* painter = CreateWizardPainter(
+ &BorderDefinition::kUserBorder);
+ border_window_->GetRootView()->set_background(
+ views::Background::CreateBackgroundPainter(true, painter));
+ border_window_->GetRootView()->SchedulePaint();
+ }
} else {
- user_view_->SetMenuVisible(false);
+ user_view_->SetRemoveButtonVisible(false);
delegate_->ClearErrors();
+ if (is_new_user_) {
+ gfx::Rect controls_bounds;
+ controls_window_->GetBounds(&controls_bounds, true);
+ gfx::Rect screen_bounds =
+ views::Screen::GetMonitorWorkAreaNearestWindow(NULL);
+ // The windows was moved out of screen so the pod was really deactivated,
+ // otherwise it just some dialog was shown and took focus.
+ if (!screen_bounds.Intersects(controls_bounds)) {
+ border_window_->GetRootView()->set_background(NULL);
+ border_window_->GetRootView()->SchedulePaint();
+ }
+ }
}
}
@@ -330,39 +325,27 @@ void UserController::ConfigureLoginWindow(WidgetGtk* window,
window->Show();
}
-WidgetGtk* UserController::CreateControlsWindow(int index, int* height) {
+WidgetGtk* UserController::CreateControlsWindow(
+ int index,
+ int* height,
+ bool need_browse_without_signin) {
views::View* control_view;
- if (is_guest_) {
- new_user_view_ = new NewUserView(this, false);
+ if (is_new_user_) {
+ new_user_view_ =
+ new NewUserView(this, false, need_browse_without_signin);
new_user_view_->Init();
control_view = new_user_view_;
} else {
- password_field_ = new UserEntryTextfield(this,
- views::Textfield::STYLE_PASSWORD);
- password_field_->set_text_to_display_when_empty(
- l10n_util::GetStringUTF16(IDS_LOGIN_EMPTY_PASSWORD_TEXT));
- password_field_->SetController(this);
- submit_button_ = new UserEntryNativeButton(
- this, this, l10n_util::GetString(IDS_LOGIN_BUTTON));
- submit_button_->SetFocusable(false);
- control_view = new views::View();
- GridLayout* layout = new GridLayout(control_view);
- control_view->SetLayoutManager(layout);
- views::ColumnSet* column_set = layout->AddColumnSet(0);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- column_set->AddPaddingColumn(0, kBorderSize);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
- GridLayout::USE_PREF, 0, 0);
-
- layout->StartRow(0, 0);
- layout->AddView(password_field_);
- layout->AddView(submit_button_);
+ existing_user_view_ = new ExistingUserView(this);
+ existing_user_view_->RecreateFields();
+ control_view = existing_user_view_;
}
*height = kControlsHeight;
- if (is_guest_)
+ if (is_new_user_)
*height += kUserImageSize + kUserNameGap;
+ if (is_bwsi_)
+ *height = 1;
WidgetGtk* window = new WidgetGtk(WidgetGtk::TYPE_WINDOW);
ConfigureLoginWindow(window,
@@ -374,13 +357,16 @@ WidgetGtk* UserController::CreateControlsWindow(int index, int* height) {
}
WidgetGtk* UserController::CreateImageWindow(int index) {
- user_view_ = new UserView(this, true);
+ user_view_ = new UserView(this, true, !is_new_user_);
- if (!is_guest_) {
- user_view_->SetImage(user_.image());
- } else {
+ if (is_bwsi_) {
+ user_view_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_LOGIN_GUEST));
+ } else if (is_new_user_) {
user_view_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_LOGIN_OTHER_USER));
+ IDR_LOGIN_ADD_USER));
+ } else {
+ user_view_->SetImage(user_.image());
}
WidgetGtk* window = new ClickNotifyingWidget(WidgetGtk::TYPE_WINDOW, this);
@@ -389,22 +375,30 @@ WidgetGtk* UserController::CreateImageWindow(int index) {
gfx::Rect(user_view_->GetPreferredSize()),
WM_IPC_WINDOW_LOGIN_IMAGE,
user_view_);
+
return window;
}
void UserController::CreateBorderWindow(int index,
int total_user_count,
int controls_height) {
- // Guest login controls window is much higher than exsisting user's controls
+ // New user login controls window is much higher than existing user's controls
// window so window manager will place the control instead of image window.
- int width = kUserImageSize + kBorderSize * 2;
+ int width = kBorderSize * 2 + kUserImageSize;
int height = kBorderSize * 2 + controls_height;
- if (!is_guest_)
+ if (!is_new_user_)
height += kBorderSize + kUserImageSize;
+ if (is_bwsi_)
+ height = kBorderSize * 2 + kUserImageSize + 1;
border_window_ = new WidgetGtk(WidgetGtk::TYPE_WINDOW);
+ border_window_->MakeTransparent();
border_window_->Init(NULL, gfx::Rect(0, 0, width, height));
- border_window_->GetRootView()->set_background(
- views::Background::CreateSolidBackground(kBackgroundColor));
+ if (!is_new_user_) {
+ views::Painter* painter = CreateWizardPainter(
+ &BorderDefinition::kUserBorder);
+ border_window_->GetRootView()->set_background(
+ views::Background::CreateBackgroundPainter(true, painter));
+ }
UpdateUserCount(index, total_user_count);
GdkWindow* gdk_window = border_window_->GetNativeView()->window;
@@ -432,8 +426,18 @@ WidgetGtk* UserController::CreateLabelWindow(int index,
const gfx::Font& font = (type == WM_IPC_WINDOW_LOGIN_LABEL) ?
rb.GetFont(ResourceBundle::LargeFont).DeriveFont(0, gfx::Font::BOLD) :
rb.GetFont(ResourceBundle::BaseFont).DeriveFont(0, gfx::Font::BOLD);
- std::wstring text = is_guest_ ? l10n_util::GetString(IDS_GUEST) :
- UTF8ToWide(user_.GetDisplayName());
+ std::wstring text;
+ if (is_bwsi_) {
+ text = l10n_util::GetString(IDS_GUEST);
+ } else if (is_new_user_) {
+ // Add user should have label only in activated state.
+ // When new user is the only, label is not needed.
+ if (type == WM_IPC_WINDOW_LOGIN_LABEL && index != 0)
+ text = l10n_util::GetString(IDS_ADD_USER);
+ } else {
+ text = UTF8ToWide(user_.GetDisplayName());
+ }
+
views::Label* label = new views::Label(text);
label->SetColor(kTextColor);
label->SetFont(font);
@@ -455,15 +459,10 @@ WidgetGtk* UserController::CreateLabelWindow(int index,
}
gfx::Rect UserController::GetScreenBounds() const {
- if (is_guest_) {
- return new_user_view_->GetPasswordBounds();
- } else {
- gfx::Rect screen_bounds(password_field_->bounds());
- gfx::Point origin(screen_bounds.origin());
- views::View::ConvertPointToScreen(password_field_->GetParent(), &origin);
- screen_bounds.set_origin(origin);
- return screen_bounds;
- }
+ if (is_new_user_)
+ return new_user_view_->GetUsernameBounds();
+ else
+ return existing_user_view_->password_field()->GetScreenBounds();
}
void UserController::OnLogin(const std::string& username,
@@ -484,20 +483,23 @@ void UserController::ClearErrors() {
delegate_->ClearErrors();
}
-void UserController::OnRemoveUser() {
- delegate_->RemoveUser(this);
+void UserController::NavigateAway() {
+ SelectUser(user_index() - 1, false);
}
-void UserController::OnChangePhoto() {
- // TODO(dpolukhin): implement change user photo, see http://crosbug.com/2348
+void UserController::OnRemoveUser() {
+ delegate_->RemoveUser(this);
}
-void UserController::SelectUser(int index) {
- delegate_->SelectUser(index);
+void UserController::SelectUser(int index, bool is_click) {
+ if (is_click && is_bwsi_)
+ delegate_->LoginOffTheRecord();
+ else
+ delegate_->SelectUser(index);
}
void UserController::FocusPasswordField() {
- password_field_->RequestFocus();
+ existing_user_view_->FocusPasswordField();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_controller.h b/chrome/browser/chromeos/login/user_controller.h
index d702fcd..c62e94c 100644
--- a/chrome/browser/chromeos/login/user_controller.h
+++ b/chrome/browser/chromeos/login/user_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_CONTROLLER_H_
+#pragma once
#include <string>
@@ -26,6 +27,7 @@ class WidgetGtk;
namespace chromeos {
class UserView;
+class ExistingUserView;
// UserController manages the set of windows needed to login a single existing
// user or first time login for a new user. ExistingUserController creates
@@ -55,8 +57,8 @@ class UserController : public views::ButtonListener,
virtual ~Delegate() {}
};
- // Creates a UserController representing the guest (other user) login.
- explicit UserController(Delegate* delegate);
+ // Creates a UserController representing new user or bwsi login.
+ UserController(Delegate* delegate, bool is_bwsi);
// Creates a UserController for the specified user.
UserController(Delegate* delegate, const UserManager::User& user);
@@ -66,7 +68,7 @@ class UserController : public views::ButtonListener,
// Initializes the UserController, creating the set of windows/controls.
// |index| is the index of this user, and |total_user_count| the total
// number of users.
- void Init(int index, int total_user_count);
+ void Init(int index, int total_user_count, bool need_browse_without_signin);
// Update border window parameters to notify window manager about new numbers.
// |index| of this user and |total_user_count| of users.
@@ -74,7 +76,9 @@ class UserController : public views::ButtonListener,
int user_index() const { return user_index_; }
bool is_user_selected() const { return is_user_selected_; }
- bool is_guest() const { return is_guest_; }
+ bool is_new_user() const { return is_new_user_; }
+ bool is_bwsi() const { return is_bwsi_; }
+ NewUserView* new_user_view() const { return new_user_view_; }
const UserManager::User& user() const { return user_; }
@@ -84,7 +88,11 @@ class UserController : public views::ButtonListener,
// 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;
// Get widget that contains all controls.
@@ -97,7 +105,7 @@ class UserController : public views::ButtonListener,
// Textfield::Controller:
virtual void ContentsChanged(views::Textfield* sender,
- const string16& new_contents) {}
+ const string16& new_contents);
virtual bool HandleKeystroke(views::Textfield* sender,
const views::Textfield::Keystroke& keystroke);
@@ -118,13 +126,14 @@ class UserController : public views::ButtonListener,
delegate_->AddStartUrl(start_url);
}
virtual void ClearErrors();
+ virtual void NavigateAway();
// UserView::Delegate implementation:
virtual void OnRemoveUser();
- virtual void OnChangePhoto();
- // Selects user entry with specified |index|.
- void SelectUser(int index);
+ // Selects user entry with specified |index|, |is_click| is true if the entry
+ // was selected by mouse click.
+ void SelectUser(int index, bool is_click);
// Sets focus on password field.
void FocusPasswordField();
@@ -145,7 +154,9 @@ class UserController : public views::ButtonListener,
const gfx::Rect& bounds,
chromeos::WmIpcWindowType type,
views::View* contents_view);
- views::WidgetGtk* CreateControlsWindow(int index, int* height);
+ views::WidgetGtk* CreateControlsWindow(int index,
+ int* height,
+ bool need_browse_without_signin);
views::WidgetGtk* CreateImageWindow(int index);
views::WidgetGtk* CreateLabelWindow(int index, WmIpcWindowType type);
void CreateBorderWindow(int index, int total_user_count, int controls_height);
@@ -159,30 +170,34 @@ class UserController : public views::ButtonListener,
// Sets the enabled state of the password field to |enable|.
void SetPasswordEnabled(bool enable);
+ // Returns tooltip text for user name.
+ std::wstring GetNameTooltip() const;
+
+ // Enable or disable the 'Submit' button based on the contents of
+ // |password_field_|. Enabled if there is text, otherwise disabled.
+ void UpdateSubmitButtonState();
+
// User index within all the users.
int user_index_;
// Is this user selected now?
bool is_user_selected_;
- // Is this the guest user?
- const bool is_guest_;
+ // Is this the new user pod?
+ const bool is_new_user_;
+
+ // Is this the bwsi pod?
+ const bool is_bwsi_;
// Should we show tooltips above user image and label to help distinguish
// users with the same display name.
bool show_name_tooltip_;
- // If is_guest_ is false, this is the user being shown.
+ // If is_new_user_ and is_bwsi_ are false, this is the user being shown.
UserManager::User user_;
Delegate* delegate_;
- // For editing the password.
- views::Textfield* password_field_;
-
- // Button to start login.
- views::NativeButton* submit_button_;
-
// A window is used to represent the individual chunks.
views::WidgetGtk* controls_window_;
views::WidgetGtk* image_window_;
@@ -196,6 +211,9 @@ class UserController : public views::ButtonListener,
// View that is used for new user login.
NewUserView* new_user_view_;
+ // View that is used for existing user login.
+ ExistingUserView* existing_user_view_;
+
// Views that show display name of the user.
views::Label* label_view_;
views::Label* unselected_label_view_;
diff --git a/chrome/browser/chromeos/login/user_image_downloader.cc b/chrome/browser/chromeos/login/user_image_downloader.cc
index 83f5d45..3deea71 100644
--- a/chrome/browser/chromeos/login/user_image_downloader.cc
+++ b/chrome/browser/chromeos/login/user_image_downloader.cc
@@ -8,10 +8,11 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/chromeos/login/google_authenticator.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"
@@ -50,7 +51,7 @@ UserImageDownloader::UserImageDownloader(const std::string& username,
profile_fetcher_->set_request_context(
ProfileManager::GetDefaultProfile()->GetRequestContext());
profile_fetcher_->set_extra_request_headers(
- StringPrintf(kAuthorizationHeader, auth_token_.c_str()));
+ base::StringPrintf(kAuthorizationHeader, auth_token_.c_str()));
profile_fetcher_->Start();
}
@@ -85,8 +86,12 @@ void UserImageDownloader::OnURLFetchComplete(const URLFetcher* source,
void UserImageDownloader::OnImageDecoded(const SkBitmap& decoded_image) {
// Save the image to file and its path to preferences.
chromeos::UserManager* user_manager = chromeos::UserManager::Get();
- if (user_manager)
+ if (user_manager) {
+ if (user_manager->logged_in_user().email() == username_) {
+ user_manager->SetLoggedInUserImage(decoded_image);
+ }
user_manager->SaveUserImage(username_, decoded_image);
+ }
}
bool UserImageDownloader::GetImageURL(const std::string& json_data,
@@ -105,11 +110,11 @@ bool UserImageDownloader::GetImageURL(const std::string& json_data,
DictionaryValue* root_dictionary =
static_cast<DictionaryValue*>(root.get());
DictionaryValue* feed_dictionary = NULL;
- if (!root_dictionary->GetDictionary(L"feed", &feed_dictionary))
+ if (!root_dictionary->GetDictionary("feed", &feed_dictionary))
return false;
ListValue* entry_list = NULL;
- if (!feed_dictionary->GetList(L"entry", &entry_list))
+ if (!feed_dictionary->GetList("entry", &entry_list))
return false;
return GetImageURLFromEntries(entry_list, image_url);
@@ -125,7 +130,7 @@ bool UserImageDownloader::GetImageURLFromEntries(ListValue* entry_list,
continue;
ListValue* email_list = NULL;
- if (!entry_dictionary->GetList(L"gd$email", &email_list))
+ if (!entry_dictionary->GetList("gd$email", &email_list))
continue;
// Match entry email address to understand that this is user's entry.
@@ -133,7 +138,7 @@ bool UserImageDownloader::GetImageURLFromEntries(ListValue* entry_list,
continue;
ListValue* link_list = NULL;
- if (!entry_dictionary->GetList(L"link", &link_list))
+ if (!entry_dictionary->GetList("link", &link_list))
continue;
if (GetImageURLFromLinks(link_list, image_url))
@@ -153,7 +158,7 @@ bool UserImageDownloader::IsUserEntry(ListValue* email_list) const {
if (!email_dictionary->GetStringASCII("address", &email))
continue;
- if (GoogleAuthenticator::Canonicalize(email) == username_)
+ if (Authenticator::Canonicalize(email) == username_)
return true;
}
return false;
diff --git a/chrome/browser/chromeos/login/user_image_downloader.h b/chrome/browser/chromeos/login/user_image_downloader.h
index f4de665..5eba206 100644
--- a/chrome/browser/chromeos/login/user_image_downloader.h
+++ b/chrome/browser/chromeos/login/user_image_downloader.h
@@ -4,12 +4,11 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_DOWNLOADER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_DOWNLOADER_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/basictypes.h"
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/chromeos/login/image_decoder.h"
#include "chrome/common/net/url_fetcher.h"
diff --git a/chrome/browser/chromeos/login/user_image_loader.h b/chrome/browser/chromeos/login/user_image_loader.h
index 454900b..4c7e0ad 100644
--- a/chrome/browser/chromeos/login/user_image_loader.h
+++ b/chrome/browser/chromeos/login/user_image_loader.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_LOADER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_LOADER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/user_image_screen.cc b/chrome/browser/chromeos/login/user_image_screen.cc
index 9b617cc..a990f31 100644
--- a/chrome/browser/chromeos/login/user_image_screen.cc
+++ b/chrome/browser/chromeos/login/user_image_screen.cc
@@ -71,6 +71,7 @@ void UserImageScreen::OnOK(const SkBitmap& image) {
UserManager* user_manager = UserManager::Get();
if (user_manager) {
// TODO(avayvod): Check that there's logged in user actually.
+ user_manager->SetLoggedInUserImage(image);
const UserManager::User& user = user_manager->logged_in_user();
user_manager->SaveUserImage(user.email(), image);
}
@@ -78,15 +79,8 @@ void UserImageScreen::OnOK(const SkBitmap& image) {
delegate()->GetObserver(this)->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
}
-void UserImageScreen::OnCancel() {
- // Download user image from his Google account.
- UserManager* user_manager = UserManager::Get();
- if (user_manager) {
- // TODO(avayvod): Check that there's logged in user actually.
- const UserManager::User& user = user_manager->logged_in_user();
- new UserImageDownloader(user.email(),
- LoginUtils::Get()->GetAuthToken());
- }
+void UserImageScreen::OnSkip() {
+ // TODO(avayvod): Use one of the default images. See http://crosbug.com/5780.
if (delegate())
delegate()->GetObserver(this)->OnExit(ScreenObserver::USER_IMAGE_SKIPPED);
}
diff --git a/chrome/browser/chromeos/login/user_image_screen.h b/chrome/browser/chromeos/login/user_image_screen.h
index 609e5f6..5dd0142 100644
--- a/chrome/browser/chromeos/login/user_image_screen.h
+++ b/chrome/browser/chromeos/login/user_image_screen.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_SCREEN_H_
+#pragma once
#include "chrome/browser/chromeos/login/camera.h"
#include "chrome/browser/chromeos/login/user_image_view.h"
@@ -32,7 +33,7 @@ class UserImageScreen: public ViewScreen<UserImageView>,
// UserImageView::Delegate implementation:
virtual void OnOK(const SkBitmap& image);
- virtual void OnCancel();
+ virtual void OnSkip();
// NotificationObserver implementation:
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/chromeos/login/user_image_view.cc b/chrome/browser/chromeos/login/user_image_view.cc
index eb93af3..dfd89ea 100644
--- a/chrome/browser/chromeos/login/user_image_view.cc
+++ b/chrome/browser/chromeos/login/user_image_view.cc
@@ -9,8 +9,10 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#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 "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -19,6 +21,7 @@
#include "views/controls/button/native_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
+#include "views/grid_layout.h"
namespace {
@@ -30,8 +33,15 @@ const int kVerticalMargin = 10;
const int kHorizontalPadding = 10;
// Padding between vertically neighboring elements.
const int kVerticalPadding = 10;
-// Size for button with video image.
-const int kVideoImageSize = 256;
+// Size for user image shown on the screen.
+const int kUserImageSize = 256;
+
+// IDs of column sets for grid layout manager.
+enum ColumnSets {
+ kTitleRow, // Column set for screen title.
+ kImageRow, // Column set for image from camera and snapshot button.
+ kButtonsRow, // Column set for Skip and OK buttons.
+};
} // namespace
@@ -42,11 +52,11 @@ using login::kUserImageSize;
UserImageView::UserImageView(Delegate* delegate)
: title_label_(NULL),
ok_button_(NULL),
- cancel_button_(NULL),
- video_button_(NULL),
- selected_image_(NULL),
+ skip_button_(NULL),
+ snapshot_button_(NULL),
+ user_image_(NULL),
delegate_(delegate),
- image_selected_(false) {
+ is_capturing_(true) {
}
UserImageView::~UserImageView() {
@@ -59,158 +69,107 @@ void UserImageView::Init() {
&BorderDefinition::kScreenBorder);
set_background(views::Background::CreateBackgroundPainter(true, painter));
- // Set up fonts.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- gfx::Font title_font = rb.GetFont(ResourceBundle::MediumBoldFont);
-
- title_label_ = new views::Label();
+ title_label_ =
+ new views::Label(l10n_util::GetString(IDS_USER_IMAGE_SCREEN_TITLE));
title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
- title_label_->SetFont(title_font);
title_label_->SetMultiLine(true);
- AddChildView(title_label_);
-
- SkBitmap video_button_image =
- skia::ImageOperations::Resize(
- *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_USER_IMAGE_NO_VIDEO),
- skia::ImageOperations::RESIZE_BOX,
- kVideoImageSize,
- kVideoImageSize);
-
- video_button_ = new views::ImageButton(this);
- video_button_->SetImage(views::CustomButton::BS_NORMAL, &video_button_image);
- AddChildView(video_button_);
- selected_image_ = new views::ImageView();
- selected_image_->SetImageSize(
+ user_image_ = new views::ImageView();
+ user_image_->SetImageSize(
gfx::Size(kUserImageSize, kUserImageSize));
- selected_image_->SetImage(
- *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_LOGIN_OTHER_USER));
- AddChildView(selected_image_);
+ user_image_->SetImage(
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_USER_IMAGE_NO_VIDEO));
- UpdateLocalizedStrings();
-}
+ snapshot_button_ = new views::ImageButton(this);
+ snapshot_button_->SetFocusable(true);
+ snapshot_button_->SetImage(views::CustomButton::BS_NORMAL,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_USER_IMAGE_CAPTURE));
-void UserImageView::RecreateNativeControls() {
- // There is no way to get native button preferred size after the button was
- // sized so delete and recreate the button on text update.
- delete ok_button_;
- ok_button_ = new views::NativeButton(this, std::wstring());
- AddChildView(ok_button_);
- ok_button_->SetEnabled(image_selected_);
- if (image_selected_)
- ok_button_->RequestFocus();
-
- delete cancel_button_;
- cancel_button_ = new views::NativeButton(this, std::wstring());
- AddChildView(cancel_button_);
- cancel_button_->SetEnabled(true);
-}
+ ok_button_ = new views::NativeButton(this, l10n_util::GetString(IDS_OK));
+ ok_button_->SetEnabled(!is_capturing_);
-void UserImageView::UpdateLocalizedStrings() {
- RecreateNativeControls();
+ skip_button_ = new views::NativeButton(this, l10n_util::GetString(IDS_SKIP));
+ skip_button_->SetEnabled(true);
- title_label_->SetText(l10n_util::GetString(IDS_USER_IMAGE_SCREEN_TITLE));
- ok_button_->SetLabel(l10n_util::GetString(IDS_OK));
- cancel_button_->SetLabel(l10n_util::GetString(IDS_CANCEL));
- selected_image_->SetTooltipText(
- l10n_util::GetString(IDS_USER_IMAGE_SELECTED_TOOLTIP));
+ InitLayout();
+ // Request focus only after the button is added to views hierarchy.
+ snapshot_button_->RequestFocus();
}
-void UserImageView::UpdateVideoFrame(const SkBitmap& frame) {
- last_frame_.reset(new SkBitmap(frame));
- SkBitmap video_button_image =
- skia::ImageOperations::Resize(
- *last_frame_,
- skia::ImageOperations::RESIZE_BOX,
- kVideoImageSize,
- kVideoImageSize);
-
- video_button_->SetImage(views::CustomButton::BS_NORMAL, &video_button_image);
- video_button_->SchedulePaint();
+void UserImageView::InitLayout() {
+ views::GridLayout* layout = new views::GridLayout(this);
+ layout->SetInsets(GetInsets());
+ SetLayoutManager(layout);
+
+ // The title is left-top aligned.
+ views::ColumnSet* column_set = layout->AddColumnSet(kTitleRow);
+ column_set->AddPaddingColumn(0, kHorizontalMargin);
+ column_set->AddColumn(views::GridLayout::LEADING,
+ views::GridLayout::LEADING,
+ 1,
+ views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kHorizontalMargin);
+
+ // User image and snapshot button are centered horizontally.
+ column_set = layout->AddColumnSet(kImageRow);
+ column_set->AddPaddingColumn(0, kHorizontalMargin);
+ column_set->AddColumn(views::GridLayout::CENTER,
+ views::GridLayout::LEADING,
+ 1,
+ views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kHorizontalMargin);
+
+ // OK and Skip buttons are in the right bottom corner of the view.
+ column_set = layout->AddColumnSet(kButtonsRow);
+ column_set->AddPaddingColumn(0, kHorizontalMargin);
+ // This column takes the empty space to the left of the buttons.
+ column_set->AddPaddingColumn(1, 1);
+ column_set->AddColumn(views::GridLayout::TRAILING,
+ views::GridLayout::TRAILING,
+ 0,
+ views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kHorizontalPadding);
+ column_set->AddColumn(views::GridLayout::TRAILING,
+ views::GridLayout::TRAILING,
+ 0,
+ views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kHorizontalMargin);
+
+ // Fill the layout with rows and views now.
+ layout->StartRowWithPadding(0, kTitleRow, 0, kVerticalMargin);
+ layout->AddView(title_label_);
+ layout->StartRowWithPadding(0, kImageRow, 0, kVerticalPadding);
+ layout->AddView(user_image_);
+ layout->StartRowWithPadding(1, kImageRow, 0, kVerticalPadding);
+ layout->AddView(snapshot_button_);
+ layout->StartRowWithPadding(0, kButtonsRow, 0, kVerticalPadding);
+ layout->AddView(skip_button_);
+ layout->AddView(ok_button_);
+ layout->AddPaddingRow(0, kVerticalMargin);
}
-void UserImageView::OnVideoImageClicked() {
- // TODO(avayvod): Snapshot sound.
- if (!last_frame_.get())
+void UserImageView::UpdateVideoFrame(const SkBitmap& frame) {
+ if (!is_capturing_)
return;
- selected_image_->SetImage(
+ last_frame_.reset(new SkBitmap(frame));
+ SkBitmap user_image =
skia::ImageOperations::Resize(
*last_frame_,
- skia::ImageOperations::RESIZE_LANCZOS3,
+ skia::ImageOperations::RESIZE_BOX,
kUserImageSize,
- kUserImageSize));
- image_selected_ = true;
- ok_button_->SetEnabled(true);
- ok_button_->RequestFocus();
-}
+ kUserImageSize);
-void UserImageView::LocaleChanged() {
- UpdateLocalizedStrings();
- Layout();
+ user_image_->SetImage(&user_image);
}
-void UserImageView::Layout() {
- gfx::Insets insets = GetInsets();
-
- // Place title at the top.
- int title_x = insets.left() + kHorizontalMargin;
- int title_y = insets.top() + kVerticalMargin;
- int max_width = width() - insets.width() - kHorizontalMargin * 2;
- title_label_->SizeToFit(max_width);
-
- gfx::Size title_size = title_label_->GetPreferredSize();
- title_label_->SetBounds(title_x,
- title_y,
- std::min(max_width, title_size.width()),
- title_size.height());
-
- // Put OK button at the right bottom corner.
- gfx::Size ok_size = ok_button_->GetPreferredSize();
- int ok_x = width() - insets.right() - kHorizontalMargin - ok_size.width();
- int ok_y = height() - insets.bottom() - kVerticalMargin - ok_size.height();
- ok_button_->SetBounds(ok_x, ok_y, ok_size.width(), ok_size.height());
-
- // Put Cancel button to the left from OK.
- gfx::Size cancel_size = cancel_button_->GetPreferredSize();
- int cancel_x = ok_x - kHorizontalPadding - cancel_size.width();
- int cancel_y = ok_y; // Height should be the same for both buttons.
- cancel_button_->SetBounds(cancel_x,
- cancel_y,
- cancel_size.width(),
- cancel_size.height());
-
- // The area between buttons and title is for images.
- int title_bottom = title_label_->y() + title_label_->height();
- gfx::Rect images_area(insets.left() + kHorizontalMargin,
- title_bottom + kVerticalPadding,
- max_width,
- ok_button_->y() - title_bottom -
- 2 * kVerticalPadding);
-
- // Selected image is floating in the middle between top and height, near
- // the right border.
- gfx::Size selected_image_size = selected_image_->GetPreferredSize();
- int selected_image_x = images_area.right() - selected_image_size.width();
- int selected_image_y = images_area.y() +
- (images_area.height() - selected_image_size.height()) / 2;
- selected_image_->SetBounds(selected_image_x,
- selected_image_y,
- selected_image_size.width(),
- selected_image_size.height());
-
- // Video capture image is on the left side of the area, top aligned with
- // selected image.
- int video_button_x = images_area.x();
- int video_button_y = selected_image_y;
- video_button_->SetBounds(video_button_x,
- video_button_y,
- kVideoImageSize,
- kVideoImageSize);
-
- SchedulePaint();
+void UserImageView::ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ if (is_add && this == child)
+ WizardAccessibilityHelper::GetInstance()->MaybeEnableAccessibility(this);
}
gfx::Size UserImageView::GetPreferredSize() {
@@ -220,16 +179,30 @@ gfx::Size UserImageView::GetPreferredSize() {
void UserImageView::ButtonPressed(
views::Button* sender, const views::Event& event) {
DCHECK(delegate_);
- if (sender == video_button_) {
- OnVideoImageClicked();
- return;
- }
- if (sender == ok_button_)
- delegate_->OnOK(selected_image_->GetImage());
- else if (sender == cancel_button_)
- delegate_->OnCancel();
- else
+ if (sender == snapshot_button_) {
+ if (is_capturing_) {
+ ok_button_->SetEnabled(true);
+ ok_button_->RequestFocus();
+ snapshot_button_->SetImage(
+ views::CustomButton::BS_NORMAL,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_USER_IMAGE_RECYCLE));
+ } else {
+ ok_button_->SetEnabled(false);
+ snapshot_button_->SetImage(
+ views::CustomButton::BS_NORMAL,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_USER_IMAGE_CAPTURE));
+ }
+ snapshot_button_->SchedulePaint();
+ is_capturing_ = !is_capturing_;
+ } else if (sender == ok_button_) {
+ delegate_->OnOK(user_image_->GetImage());
+ } else if (sender == skip_button_) {
+ delegate_->OnSkip();
+ } else {
NOTREACHED();
+ }
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_view.h b/chrome/browser/chromeos/login/user_image_view.h
index 028499d..7f59381 100644
--- a/chrome/browser/chromeos/login/user_image_view.h
+++ b/chrome/browser/chromeos/login/user_image_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_VIEW_H_
+#pragma once
#include "views/controls/button/button.h"
#include "views/view.h"
@@ -11,10 +12,10 @@
class SkBitmap;
namespace views {
+class ImageButton;
class ImageView;
class Label;
class NativeButton;
-class ImageButton;
} // namespace views
namespace chromeos {
@@ -33,51 +34,46 @@ class UserImageView : public views::View,
virtual void OnOK(const SkBitmap& image) = 0;
// Called if user decides to skip image selection screen.
- virtual void OnCancel() = 0;
+ virtual void OnSkip() = 0;
};
explicit UserImageView(Delegate* delegate);
virtual ~UserImageView();
- // Initialize view layout.
+ // Initializes this view, its children and layout.
void Init();
- // Update strings from the resources. Executed on language change.
- void UpdateLocalizedStrings();
-
- // Updates snapshot from camera on camera image view.
+ // Updates image from camera.
void UpdateVideoFrame(const SkBitmap& frame);
- // Called when user left-clicks video image control.
- void OnVideoImageClicked();
-
// Overridden from views::View:
virtual gfx::Size GetPreferredSize();
- virtual void Layout();
// Overridden from views::ButtonListener.
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
protected:
// views::View overrides:
- virtual void LocaleChanged();
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child);
private:
- // Delete and recreate native controls that fail to update preferred size
- // after string update.
- void RecreateNativeControls();
+ // Initializes layout manager for this view.
+ void InitLayout();
views::Label* title_label_;
views::NativeButton* ok_button_;
- views::NativeButton* cancel_button_;
- views::ImageButton* video_button_;
- views::ImageView* selected_image_;
+ views::NativeButton* skip_button_;
+ views::ImageButton* snapshot_button_;
+ views::ImageView* user_image_;
// Notifications receiver.
Delegate* delegate_;
- // Indicates that some image was selected and OK can be pressed.
- bool image_selected_;
+ // Indicates that we're in capturing mode. When |false|, new video frames
+ // are not shown to user if received.
+ bool is_capturing_;
// Last frame that was received from the camera in its original resolution.
scoped_ptr<SkBitmap> last_frame_;
diff --git a/chrome/browser/chromeos/login/user_manager.cc b/chrome/browser/chromeos/login/user_manager.cc
index f0c18a8..f6edcbe 100644
--- a/chrome/browser/chromeos/login/user_manager.cc
+++ b/chrome/browser/chromeos/login/user_manager.cc
@@ -9,6 +9,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/nss_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/time.h"
@@ -16,10 +17,14 @@
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/input_method_library.h"
+#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
#include "gfx/codec/png_codec.h"
#include "grit/theme_resources.h"
@@ -28,9 +33,13 @@ namespace chromeos {
namespace {
// A vector pref of the users who have logged into the device.
-const wchar_t kLoggedInUsers[] = L"LoggedInUsers";
+const char kLoggedInUsers[] = "LoggedInUsers";
// A dictionary that maps usernames to file paths to their images.
-const wchar_t kUserImages[] = L"UserImages";
+const char kUserImages[] = "UserImages";
+
+// Incognito user is represented by an empty string (since some code already
+// depends on that and it's hard to figure out what).
+const char kIncognitoUser[] = "";
// The one true UserManager.
static UserManager* user_manager_ = NULL;
@@ -42,8 +51,7 @@ void save_path_to_local_state(const std::string& username,
PrefService* local_state = g_browser_process->local_state();
DictionaryValue* images =
local_state->GetMutableDictionary(kUserImages);
- images->SetWithoutPathExpansion(UTF8ToWide(username),
- new StringValue(image_path));
+ images->SetWithoutPathExpansion(username, new StringValue(image_path));
LOG(INFO) << "Saving path to user image in Local State.";
local_state->SavePersistentPrefs();
}
@@ -74,6 +82,14 @@ void save_image_to_file(const SkBitmap& image,
username, image_path.value()));
}
+// Checks current user's ownership on file thread.
+void CheckOwnership() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ UserManager::Get()->set_current_user_is_owner(
+ OwnershipService::GetSharedInstance()->CurrentUserIsOwner());
+}
+
} // namespace
UserManager::User::User() {
@@ -124,8 +140,7 @@ std::vector<UserManager::User> UserManager::GetUsers() const {
std::string image_path;
if (image_it == user_images_.end()) {
if (prefs_images &&
- prefs_images->GetStringWithoutPathExpansion(
- ASCIIToWide(email), &image_path)) {
+ prefs_images->GetStringWithoutPathExpansion(email, &image_path)) {
// Insert the default image so we don't send another request if
// GetUsers is called twice.
user_images_[email] = user.image();
@@ -142,10 +157,17 @@ std::vector<UserManager::User> UserManager::GetUsers() const {
}
void UserManager::OffTheRecordUserLoggedIn() {
+ logged_in_user_ = User();
+ logged_in_user_.set_email(kIncognitoUser);
NotifyOnLogin();
}
void UserManager::UserLoggedIn(const std::string& email) {
+ if (email == kIncognitoUser) {
+ OffTheRecordUserLoggedIn();
+ return;
+ }
+
// Get a copy of the current users.
std::vector<User> users = GetUsers();
@@ -193,6 +215,25 @@ void UserManager::RemoveUser(const std::string& email) {
prefs->SavePersistentPrefs();
}
+bool UserManager::IsKnownUser(const std::string& email) {
+ std::vector<User> users = GetUsers();
+ for (std::vector<User>::iterator it = users.begin();
+ it < users.end();
+ ++it) {
+ if (it->email() == email)
+ return true;
+ }
+
+ return false;
+}
+
+void UserManager::SetLoggedInUserImage(const SkBitmap& image) {
+ if (logged_in_user_.email().empty())
+ return;
+ logged_in_user_.set_image(image);
+ OnImageLoaded(logged_in_user_.email(), image);
+}
+
void UserManager::SaveUserImage(const std::string& username,
const SkBitmap& image) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
@@ -224,7 +265,10 @@ void UserManager::OnImageLoaded(const std::string& username,
// Private constructor and destructor. Do nothing.
UserManager::UserManager()
- : ALLOW_THIS_IN_INITIALIZER_LIST(image_loader_(new UserImageLoader(this))) {
+ : ALLOW_THIS_IN_INITIALIZER_LIST(image_loader_(new UserImageLoader(this))),
+ current_user_is_owner_(false) {
+ registrar_.Add(this, NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED,
+ NotificationService::AllSources());
}
UserManager::~UserManager() {
@@ -237,8 +281,28 @@ void UserManager::NotifyOnLogin() {
Source<UserManager>(this),
Details<const User>(&logged_in_user_));
+ chromeos::CrosLibrary::Get()->GetInputMethodLibrary()->
+ SetDeferImeStartup(false);
+ // Shut down the IME so that it will reload the user's settings.
+ chromeos::CrosLibrary::Get()->GetInputMethodLibrary()->
+ StopInputMethodProcesses();
// Let the window manager know that we're logged in now.
WmIpc::instance()->SetLoggedInProperty(true);
+ // Ensure we've opened the real user's key/certificate database.
+ base::OpenPersistentNSSDB();
+
+ // Schedules current user ownership check on file thread.
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(&CheckOwnership));
+}
+
+void UserManager::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) {
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(&CheckOwnership));
+ }
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h
index 0e4ce31..d3e40be 100644
--- a/chrome/browser/chromeos/login/user_manager.h
+++ b/chrome/browser/chromeos/login/user_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_MANAGER_H_
+#pragma once
#include <string>
#include <vector>
@@ -12,6 +13,8 @@
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "chrome/browser/chromeos/login/user_image_loader.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
#include "third_party/skia/include/core/SkBitmap.h"
class PrefService;
@@ -20,7 +23,8 @@ namespace chromeos {
// This class provides a mechanism for discovering users who have logged
// into this chromium os device before and updating that list.
-class UserManager : public UserImageLoader::Delegate {
+class UserManager : public UserImageLoader::Delegate,
+ public NotificationObserver {
public:
// A class representing information about a previously logged in user.
class User {
@@ -65,11 +69,18 @@ class UserManager : public UserImageLoader::Delegate {
// Remove user from persistent list. NOTE: user's data won't be removed.
void RemoveUser(const std::string& email);
+ // Returns true if given user has logged into the device before.
+ bool IsKnownUser(const std::string& email);
+
// Returns the logged-in user.
const User& logged_in_user() {
return logged_in_user_;
}
+ // Sets image for logged-in user and sends LOGIN_USER_IMAGE_CHANGED
+ // notification about the image changed via NotificationService.
+ void SetLoggedInUserImage(const SkBitmap& image);
+
// Saves image to file and saves image path in local state preferences.
void SaveUserImage(const std::string& username,
const SkBitmap& image);
@@ -78,6 +89,19 @@ class UserManager : public UserImageLoader::Delegate {
virtual void OnImageLoaded(const std::string& username,
const SkBitmap& image);
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Accessor for current_user_is_owner_
+ bool current_user_is_owner() const {
+ return current_user_is_owner_;
+ }
+ void set_current_user_is_owner(bool current_user_is_owner) {
+ current_user_is_owner_ = current_user_is_owner;
+ }
+
private:
UserManager();
~UserManager();
@@ -95,6 +119,11 @@ class UserManager : public UserImageLoader::Delegate {
// The logged-in user.
User logged_in_user_;
+ // Cached flag of whether currently logged-in user is owner or not.
+ bool current_user_is_owner_;
+
+ NotificationRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(UserManager);
};
diff --git a/chrome/browser/chromeos/login/user_view.cc b/chrome/browser/chromeos/login/user_view.cc
index 10db8b0..77afcb9 100644
--- a/chrome/browser/chromeos/login/user_view.cc
+++ b/chrome/browser/chromeos/login/user_view.cc
@@ -7,12 +7,14 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/button/text_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
-#include "views/controls/menu/menu_2.h"
+#include "views/controls/link.h"
#include "views/controls/throbber.h"
namespace {
@@ -20,28 +22,25 @@ namespace {
// Background color of the login status label and signout button.
const SkColor kSignoutBackgroundColor = 0xFF007700;
-// Left margin to the "Active User" text.
-const int kSignoutLeftOffset = 10;
+// Horiz/Vert insets for Signout view.
+const int kSignoutViewHorizontalInsets = 10;
+const int kSignoutViewVerticalInsets = 5;
-// Padding between menu button and left right image corner.
-const int kMenuButtonPadding = 4;
-
-const int kIdRemove = 1;
-const int kIdChangePhoto = 2;
+// Padding between remove button and top right image corner.
+const int kRemoveButtonPadding = 3;
} // namespace
namespace chromeos {
using login::kBackgroundColor;
-using login::kBorderSize;
using login::kTextColor;
using login::kUserImageSize;
// The view that shows the Sign out button below the user's image.
class SignoutView : public views::View {
public:
- explicit SignoutView(views::ButtonListener* listener) {
+ explicit SignoutView(views::LinkController* link_controller) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
const gfx::Font& font = rb.GetFont(ResourceBundle::SmallFont);
@@ -50,16 +49,15 @@ class SignoutView : public views::View {
active_user_label_->SetFont(font);
active_user_label_->SetColor(kTextColor);
- signout_button_ = new views::TextButton(
- listener, l10n_util::GetString(IDS_SCREEN_LOCK_SIGN_OUT));
- signout_button_->SetFont(font);
- signout_button_->SetEnabledColor(kTextColor);
- signout_button_->SetNormalHasBorder(false);
- signout_button_->set_tag(login::SIGN_OUT);
- signout_button_->SetFocusable(true);
+ signout_link_ = new views::Link(
+ l10n_util::GetString(IDS_SCREEN_LOCK_SIGN_OUT));
+ signout_link_->SetController(link_controller);
+ signout_link_->SetFont(font);
+ signout_link_->SetColor(kTextColor);
+ signout_link_->SetFocusable(true);
AddChildView(active_user_label_);
- AddChildView(signout_button_);
+ AddChildView(signout_link_);
set_background(views::Background::CreateSolidBackground(
kSignoutBackgroundColor));
@@ -68,51 +66,133 @@ class SignoutView : public views::View {
// views::View overrides.
virtual void Layout() {
gfx::Size label = active_user_label_->GetPreferredSize();
- gfx::Size button = signout_button_->GetPreferredSize();
- active_user_label_->SetBounds(kSignoutLeftOffset,
- (height() - label.height()) / 2,
- label.width(), label.height());
- signout_button_->SetBounds(
- width() - button.width(), (height() - button.height()) / 2,
+ gfx::Size button = signout_link_->GetPreferredSize();
+ active_user_label_->SetBounds(
+ kSignoutViewHorizontalInsets, (height() - label.height()) / 2,
+ label.width(), label.height());
+ signout_link_->SetBounds(
+ width() - button.width() - kSignoutViewHorizontalInsets,
+ (height() - button.height()) / 2,
button.width(), button.height());
}
virtual gfx::Size GetPreferredSize() {
gfx::Size label = active_user_label_->GetPreferredSize();
- gfx::Size button = signout_button_->GetPreferredSize();
+ gfx::Size button = signout_link_->GetPreferredSize();
return gfx::Size(label.width() + button.width(),
- std::max(label.height(), button.height()));
+ std::max(label.height(), button.height()) +
+ kSignoutViewVerticalInsets * 2);
}
- views::Button* signout_button() { return signout_button_; }
+ views::Link* signout_link() { return signout_link_; }
private:
friend class UserView;
views::Label* active_user_label_;
- views::TextButton* signout_button_;
+ views::Link* signout_link_;
DISALLOW_COPY_AND_ASSIGN(SignoutView);
};
-UserView::UserView(Delegate* delegate, bool is_login)
+class RemoveButton : public views::TextButton {
+ public:
+ RemoveButton(views::ButtonListener* listener,
+ const SkBitmap& icon,
+ const std::wstring& text,
+ const gfx::Point& top_right)
+ : views::TextButton(listener, std::wstring()),
+ icon_(icon),
+ text_(text),
+ top_right_(top_right) {
+ SetEnabledColor(SK_ColorWHITE);
+ SetDisabledColor(SK_ColorWHITE);
+ SetHighlightColor(SK_ColorWHITE);
+ SetHoverColor(SK_ColorWHITE);
+ SetIcon(icon_);
+ set_border(NULL);
+ UpdatePosition();
+ }
+
+ protected:
+ // Overridden from View:
+ virtual void OnMouseEntered(const views::MouseEvent& e) {
+ SetIcon(SkBitmap());
+ views::TextButton::SetText(text_);
+
+ const SkColor kStrokeColor = SK_ColorWHITE;
+ const SkColor kButtonColor = 0xFFE94949;
+ const int kStrokeWidth = 1;
+ const int kVerticalPadding = 4;
+ const int kHorizontalPadding = 8;
+ const int kCornerRadius = 4;
+
+ set_background(
+ CreateRoundedBackground(
+ kCornerRadius, kStrokeWidth, kButtonColor, kStrokeColor));
+
+ set_border(
+ views::Border::CreateEmptyBorder(kVerticalPadding,
+ kHorizontalPadding,
+ kVerticalPadding,
+ kHorizontalPadding));
+
+ UpdatePosition();
+ }
+
+ void OnMouseMoved(const views::MouseEvent& e) {
+ }
+
+ virtual void OnMouseExited(const views::MouseEvent& e) {
+ SetIcon(icon_);
+ views::TextButton::SetText(std::wstring());
+ ClearMaxTextSize();
+ set_background(NULL);
+ set_border(NULL);
+ UpdatePosition();
+ }
+
+ void SetText(const std::wstring& text) {
+ text_ = text;
+ }
+
+ private:
+ // Update button position and schedule paint event for the view and parent.
+ void UpdatePosition() {
+ gfx::Size size = GetPreferredSize();
+ gfx::Point origin = top_right_;
+ origin.Offset(-size.width(), 0);
+ SetBounds(gfx::Rect(origin, size));
+
+ if (GetParent())
+ GetParent()->SchedulePaint();
+ }
+
+ SkBitmap icon_;
+ std::wstring text_;
+ gfx::Point top_right_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoveButton);
+};
+
+UserView::UserView(Delegate* delegate, bool is_login, bool need_background)
: delegate_(delegate),
signout_view_(NULL),
image_view_(new views::ImageView()),
throbber_(CreateDefaultSmoothedThrobber()),
- menu_button_(NULL) {
+ remove_button_(NULL) {
DCHECK(delegate);
if (!is_login)
signout_view_ = new SignoutView(this);
- if (is_login)
- menu_button_ = new views::MenuButton(NULL, std::wstring(), this, true);
- Init();
+ Init(need_background);
}
-void UserView::Init() {
- image_view_->set_background(
- views::Background::CreateSolidBackground(kBackgroundColor));
+void UserView::Init(bool need_background) {
+ if (need_background) {
+ image_view_->set_background(
+ views::Background::CreateSolidBackground(kBackgroundColor));
+ }
if (throbber_) {
int w = throbber_->GetPreferredSize().width();
int h = throbber_->GetPreferredSize().height();
@@ -132,14 +212,15 @@ void UserView::Init() {
signout_view_->GetPreferredSize().height());
AddChildView(signout_view_);
}
- if (menu_button_) {
- int w = menu_button_->GetPreferredSize().width();
- int h = menu_button_->GetPreferredSize().height();
- menu_button_->SetBounds(kUserImageSize - w - kMenuButtonPadding,
- kMenuButtonPadding, w, h);
- menu_button_->SetVisible(false);
- AddChildView(menu_button_);
- }
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ remove_button_ = new RemoveButton(
+ this,
+ *rb.GetBitmapNamed(IDR_CLOSE_BAR_H),
+ l10n_util::GetString(IDS_LOGIN_REMOVE),
+ gfx::Point(kUserImageSize - kRemoveButtonPadding, kRemoveButtonPadding));
+ remove_button_->SetVisible(false);
+ AddChildView(remove_button_);
}
void UserView::SetImage(const SkBitmap& image) {
@@ -175,58 +256,28 @@ gfx::Size UserView::GetPreferredSize() {
void UserView::SetSignoutEnabled(bool enabled) {
DCHECK(signout_view_);
- signout_view_->signout_button_->SetEnabled(enabled);
+ signout_view_->signout_link_->SetEnabled(enabled);
}
-void UserView::ButtonPressed(views::Button* sender, const views::Event& event) {
+void UserView::LinkActivated(views::Link* source, int event_flags) {
DCHECK(delegate_);
- if (sender->tag() == login::SIGN_OUT)
+ DCHECK(signout_view_);
+ if (signout_view_->signout_link_ == source)
delegate_->OnSignout();
}
-void UserView::SetMenuVisible(bool flag) {
- DCHECK(menu_button_);
- menu_button_->SetVisible(flag);
-}
-
-void UserView::BuildMenu() {
- menu_model_.reset(new menus::SimpleMenuModel(this));
- menu_model_->AddItemWithStringId(kIdRemove, IDS_LOGIN_REMOVE);
- menu_model_->AddItemWithStringId(kIdChangePhoto, IDS_LOGIN_CHANGE_PHOTO);
- menu_.reset(new views::Menu2(menu_model_.get()));
-}
-
-void UserView::RunMenu(View* source, const gfx::Point& pt) {
- if (!menu_.get())
- BuildMenu();
-
- menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
-}
-
-bool UserView::IsCommandIdChecked(int command_id) const {
- return false;
-}
-
-bool UserView::IsCommandIdEnabled(int command_id) const {
- // TODO(dpolukhin): implement and enable change photo.
- return command_id != kIdChangePhoto;
+void UserView::SetRemoveButtonVisible(bool flag) {
+ remove_button_->SetVisible(flag);
}
-bool UserView::GetAcceleratorForCommandId(int command_id,
- menus::Accelerator* accelerator) {
- return false;
+void UserView::ButtonPressed(views::Button* sender, const views::Event& event) {
+ DCHECK(delegate_);
+ if (remove_button_ == sender)
+ delegate_->OnRemoveUser();
}
-void UserView::ExecuteCommand(int command_id) {
- switch (command_id) {
- case kIdRemove:
- delegate_->OnRemoveUser();
- break;
-
- case kIdChangePhoto:
- delegate_->OnChangePhoto();
- break;
- }
+void UserView::OnLocaleChanged() {
+ remove_button_->SetText(l10n_util::GetString(IDS_LOGIN_REMOVE));
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_view.h b/chrome/browser/chromeos/login/user_view.h
index 25eb9d9..772910c 100644
--- a/chrome/browser/chromeos/login/user_view.h
+++ b/chrome/browser/chromeos/login/user_view.h
@@ -4,20 +4,19 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_VIEW_H_
+#pragma once
#include <string>
-#include "app/menus/simple_menu_model.h"
#include "views/controls/button/button.h"
-#include "views/controls/menu/view_menu_delegate.h"
+#include "views/controls/link.h"
#include "views/view.h"
class SkBitmap;
namespace views {
class ImageView;
-class Menu2;
-class MenuButton;
+class TextButton;
class Throbber;
} // namespace views
@@ -26,9 +25,8 @@ namespace chromeos {
class SignoutView;
class UserView : public views::View,
- public views::ButtonListener,
- public views::ViewMenuDelegate,
- public menus::SimpleMenuModel::Delegate {
+ public views::LinkController,
+ public views::ButtonListener {
public:
class Delegate {
public:
@@ -39,19 +37,17 @@ class UserView : public views::View,
// Notifies that user would like to remove this user from login screen.
virtual void OnRemoveUser() {}
-
- // Notifies that user would like to take new picture for this user on
- // login screen.
- virtual void OnChangePhoto() {}
};
// Creates UserView for login screen (|is_login| == true) or screen locker.
// On login screen this will have addition menu with user specific actions.
- // On screen locker it will have sign out button.
- UserView(Delegate* delegate, bool is_login);
+ // On screen locker it will have sign out button. |need_background| is needed
+ // to show image with transparent areas.
+ UserView(Delegate* delegate, bool is_login, bool need_background);
// view::View overrides.
virtual gfx::Size GetPreferredSize();
+ virtual void OnLocaleChanged();
// Sets the user's image.
void SetImage(const SkBitmap& image);
@@ -63,27 +59,21 @@ class UserView : public views::View,
void StartThrobber();
void StopThrobber();
- // Show/Hide menu for user specific actions.
- void SetMenuVisible(bool flag);
+ // Show/Hide remove button.
+ void SetRemoveButtonVisible(bool flag);
// Enable/Disable sign-out button.
void SetSignoutEnabled(bool enabled);
- // ButtonListener:
- virtual void ButtonPressed(views::Button* sender, const views::Event& event);
-
- // ViewMenuDelegate:
- virtual void RunMenu(View* source, const gfx::Point& pt);
+ // Implements LinkController.
+ // Called when a signout link is clicked.
+ virtual void LinkActivated(views::Link* source, int event_flags);
- // 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);
+ // Overridden from views::ButtonListener.
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
private:
- void Init();
+ void Init(bool need_background);
void BuildMenu();
Delegate* delegate_;
@@ -95,10 +85,7 @@ class UserView : public views::View,
views::Throbber* throbber_;
- // Menu for user specific actions.
- scoped_ptr<menus::SimpleMenuModel> menu_model_;
- scoped_ptr<views::Menu2> menu_;
- views::MenuButton* menu_button_;
+ views::TextButton* remove_button_;
DISALLOW_COPY_AND_ASSIGN(UserView);
};
@@ -106,4 +93,3 @@ class UserView : public views::View,
} // chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_USER_VIEW_H_
-
diff --git a/chrome/browser/chromeos/login/view_screen.h b/chrome/browser/chromeos/login/view_screen.h
index ea9d437..81586e4 100644
--- a/chrome/browser/chromeos/login/view_screen.h
+++ b/chrome/browser/chromeos/login/view_screen.h
@@ -4,19 +4,27 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_VIEW_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_VIEW_SCREEN_H_
+#pragma once
#include "base/message_loop.h"
+#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/wizard_screen.h"
+#include "gfx/size.h"
template <class V>
class ViewScreen : public WizardScreen {
public:
+ // Create screen with default size.
explicit ViewScreen(WizardScreenDelegate* delegate);
+
+ // Create screen with the specified size.
+ ViewScreen(WizardScreenDelegate* delegate, int width, int height);
virtual ~ViewScreen();
// Overridden from WizardScreen:
virtual void Show();
virtual void Hide();
+ virtual gfx::Size GetScreenSize() const { return size_; }
V* view() { return view_; }
@@ -35,6 +43,9 @@ class ViewScreen : public WizardScreen {
V* view_;
+ // Size of the screen.
+ gfx::Size size_;
+
DISALLOW_COPY_AND_ASSIGN(ViewScreen);
};
@@ -53,7 +64,16 @@ class DefaultViewScreen : public ViewScreen<V> {
template <class V>
ViewScreen<V>::ViewScreen(WizardScreenDelegate* delegate)
: WizardScreen(delegate),
- view_(NULL) {
+ view_(NULL),
+ size_(chromeos::login::kWizardScreenWidth,
+ chromeos::login::kWizardScreenHeight) {
+}
+
+template <class V>
+ViewScreen<V>::ViewScreen(WizardScreenDelegate* delegate, int width, int height)
+ : WizardScreen(delegate),
+ view_(NULL),
+ size_(width, height) {
}
template <class V>
diff --git a/chrome/browser/chromeos/login/web_page_screen.h b/chrome/browser/chromeos/login/web_page_screen.h
index 5c9bc17..c9746bf 100644
--- a/chrome/browser/chromeos/login/web_page_screen.h
+++ b/chrome/browser/chromeos/login/web_page_screen.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_WEB_PAGE_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_WEB_PAGE_SCREEN_H_
+#pragma once
-#include "base/scoped_ptr.h"
#include "base/timer.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -37,18 +37,23 @@ class WebPageScreen : public TabContentsDelegate {
const gfx::Rect& initial_pos,
bool user_gesture) {}
virtual void ActivateContents(TabContents* contents) {}
+ virtual void DeactivateContents(TabContents* contents) {}
virtual void LoadingStateChanged(TabContents* source) = 0;
virtual void CloseContents(TabContents* source) {}
virtual bool IsPopup(TabContents* source) { return false; }
virtual void URLStarredChanged(TabContents* source, bool starred) {}
virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
- virtual bool ShouldAddNavigationToHistory() const { return false; }
+ virtual bool ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type) {
+ return false;
+ }
virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
virtual bool HandleContextMenu(const ContextMenuParams& params);
// Called by |timeout_timer_|. Stops page fetching and closes screen.
- void OnNetworkTimeout();
+ virtual void OnNetworkTimeout();
// Start/stop timeout timer.
void StartTimeoutTimer();
diff --git a/chrome/browser/chromeos/login/web_page_view.cc b/chrome/browser/chromeos/login/web_page_view.cc
index daac923..5205fa1 100644
--- a/chrome/browser/chromeos/login/web_page_view.cc
+++ b/chrome/browser/chromeos/login/web_page_view.cc
@@ -7,9 +7,9 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
+#include "base/logging.h"
#include "base/string_util.h"
#include "base/time.h"
-#include "base/values.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
@@ -53,7 +53,7 @@ WizardWebPageViewTabContents::WizardWebPageViewTabContents(
Profile* profile,
SiteInstance* site_instance,
WebPageDelegate* page_delegate)
- : TabContents(profile, site_instance, MSG_ROUTING_NONE, NULL),
+ : TabContents(profile, site_instance, MSG_ROUTING_NONE, NULL, NULL),
page_delegate_(page_delegate) {
}
@@ -63,15 +63,18 @@ void WizardWebPageViewTabContents::DidFailProvisionalLoadWithError(
int error_code,
const GURL& url,
bool showing_repost_interstitial) {
+ LOG(ERROR) << "Page load failed. URL = " << url << ", error: " << error_code;
page_delegate_->OnPageLoadFailed(url.spec());
}
void WizardWebPageViewTabContents::DidDisplayInsecureContent() {
- page_delegate_->OnPageLoadFailed("");
+ LOG(ERROR) << "Page load failed: did display insecure content";
+ page_delegate_->OnPageLoadFailed("Displayed insecure content");
}
void WizardWebPageViewTabContents::DidRunInsecureContent(
const std::string& security_origin) {
+ LOG(ERROR) << "Page load failed: did run insecure content";
page_delegate_->OnPageLoadFailed(security_origin);
}
@@ -80,6 +83,7 @@ void WizardWebPageViewTabContents::DocumentLoadedInFrame() {
}
void WizardWebPageViewTabContents::OnContentBlocked(ContentSettingsType type) {
+ LOG(ERROR) << "Page load failed: content blocked. Type: " << type;
page_delegate_->OnPageLoadFailed("");
}
diff --git a/chrome/browser/chromeos/login/web_page_view.h b/chrome/browser/chromeos/login/web_page_view.h
index 8197743..b497715 100644
--- a/chrome/browser/chromeos/login/web_page_view.h
+++ b/chrome/browser/chromeos/login/web_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_WEB_PAGE_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_WEB_PAGE_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 8506921..fa0f938 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -11,20 +11,25 @@
#include <string>
#include <vector>
-#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
#include "base/command_line.h"
+#include "base/file_util.h"
#include "base/logging.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/login_library.h"
#include "chrome/browser/chromeos/cros/system_library.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/login/account_screen.h"
+#include "chrome/browser/chromeos/login/apply_services_customization.h"
#include "chrome/browser/chromeos/login/background_view.h"
#include "chrome/browser/chromeos/login/eula_view.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/html_page_screen.h"
#include "chrome/browser/chromeos/login/language_switch_menu.h"
#include "chrome/browser/chromeos/login/login_screen.h"
#include "chrome/browser/chromeos/login/login_utils.h"
@@ -34,11 +39,13 @@
#include "chrome/browser/chromeos/login/update_screen.h"
#include "chrome/browser/chromeos/login/user_image_screen.h"
#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
#include "cros/chromeos_wm_ipc_enums.h"
#include "unicode/timezone.h"
#include "views/accelerator.h"
@@ -49,39 +56,54 @@
namespace {
// A boolean pref of the OOBE complete flag.
-const wchar_t kOobeComplete[] = L"OobeComplete";
+const char kOobeComplete[] = "OobeComplete";
-// Default size of the OOBE screen.
-const int kWizardScreenWidth = 700;
-const int kWizardScreenHeight = 416;
+// Path to OEM partner startup customization manifest.
+const char kStartupCustomizationManifestPath[] =
+ "/mnt/partner_partition/etc/chromeos/startup_manifest.json";
+
+// Path to flag file indicating that OOBE was completed successfully.
+const char kOobeCompleteFlagFilePath[] =
+ "/home/chronos/.oobe_completed";
+
+// Upadate window will be behind the curtain at most |kMaximalCurtainTimeSec|.
+const int kMaximalCurtainTimeSec = 15;
+
+// Time in seconds that we wait for the device to reboot.
+// If reboot didn't happen, ask user to reboot device manually.
+const int kWaitForRebootTimeSec = 3;
// RootView of the Widget WizardController creates. Contains the contents of the
// WizardController.
class ContentView : public views::View {
public:
- ContentView(int window_x, int window_y, int screen_w, int screen_h)
- : window_x_(window_x),
- window_y_(window_y),
- screen_w_(screen_w),
- screen_h_(screen_h),
- accel_account_screen_(views::Accelerator(base::VKEY_A,
- false, true, true)),
- accel_login_screen_(views::Accelerator(base::VKEY_L,
- false, true, true)),
- accel_network_screen_(views::Accelerator(base::VKEY_N,
- false, true, true)),
- accel_update_screen_(views::Accelerator(base::VKEY_U,
- false, true, true)),
- accel_image_screen_(views::Accelerator(base::VKEY_I,
- false, true, true)),
- accel_eula_screen_(views::Accelerator(base::VKEY_E,
- false, true, true)) {
+ ContentView()
+ : accel_enable_accessibility_(
+ WizardAccessibilityHelper::GetAccelerator()) {
+ AddAccelerator(accel_enable_accessibility_);
+#if !defined(OFFICIAL_BUILD)
+ accel_account_screen_ = views::Accelerator(app::VKEY_A,
+ false, true, true);
+ accel_login_screen_ = views::Accelerator(app::VKEY_L,
+ false, true, true);
+ accel_network_screen_ = views::Accelerator(app::VKEY_N,
+ false, true, true);
+ accel_update_screen_ = views::Accelerator(app::VKEY_U,
+ false, true, true);
+ accel_image_screen_ = views::Accelerator(app::VKEY_I,
+ false, true, true);
+ accel_eula_screen_ = views::Accelerator(app::VKEY_E,
+ false, true, true);
+ accel_register_screen_ = views::Accelerator(app::VKEY_R,
+ false, true, true);
AddAccelerator(accel_account_screen_);
AddAccelerator(accel_login_screen_);
AddAccelerator(accel_network_screen_);
AddAccelerator(accel_update_screen_);
AddAccelerator(accel_image_screen_);
AddAccelerator(accel_eula_screen_);
+ AddAccelerator(accel_register_screen_);
+#endif
}
~ContentView() {
@@ -96,7 +118,11 @@ class ContentView : public views::View {
if (!controller)
return false;
- if (accel == accel_account_screen_) {
+ if (accel == accel_enable_accessibility_) {
+ WizardAccessibilityHelper::GetInstance()->EnableAccessibility(
+ controller->contents());
+#if !defined(OFFICIAL_BUILD)
+ } else if (accel == accel_account_screen_) {
controller->ShowAccountScreen();
} else if (accel == accel_login_screen_) {
controller->ShowLoginScreen();
@@ -108,6 +134,9 @@ class ContentView : public views::View {
controller->ShowUserImageScreen();
} else if (accel == accel_eula_screen_) {
controller->ShowEulaScreen();
+ } else if (accel == accel_register_screen_) {
+ controller->ShowRegistrationScreen();
+#endif
} else {
return false;
}
@@ -115,16 +144,6 @@ class ContentView : public views::View {
return true;
}
- void PaintBackground(gfx::Canvas* canvas) {
- if (painter_.get()) {
- // TODO(sky): nuke this once new login manager is in place. This needs to
- // exist because with no window manager transparency isn't really
- // supported.
- canvas->TranslateInt(-window_x_, -window_y_);
- painter_->Paint(screen_w_, screen_h_, canvas);
- }
- }
-
virtual void Layout() {
for (int i = 0; i < GetChildViewCount(); ++i) {
views::View* cur = GetChildViewAt(i);
@@ -136,17 +155,16 @@ class ContentView : public views::View {
private:
scoped_ptr<views::Painter> painter_;
- const int window_x_;
- const int window_y_;
- const int screen_w_;
- const int screen_h_;
-
+#if !defined(OFFICIAL_BUILD)
views::Accelerator accel_account_screen_;
views::Accelerator accel_login_screen_;
views::Accelerator accel_network_screen_;
views::Accelerator accel_update_screen_;
views::Accelerator accel_image_screen_;
views::Accelerator accel_eula_screen_;
+ views::Accelerator accel_register_screen_;
+#endif
+ views::Accelerator accel_enable_accessibility_;
DISALLOW_COPY_AND_ASSIGN(ContentView);
};
@@ -162,6 +180,26 @@ void DeleteWizardControllerAndLaunchBrowser(WizardController* controller) {
ProfileManager::GetDefaultProfile()));
}
+const chromeos::StartupCustomizationDocument* LoadStartupManifest() {
+ // Load partner customization startup manifest if it is available.
+ FilePath startup_manifest_path(kStartupCustomizationManifestPath);
+ if (file_util::PathExists(startup_manifest_path)) {
+ scoped_ptr<chromeos::StartupCustomizationDocument> customization(
+ new chromeos::StartupCustomizationDocument());
+ bool manifest_loaded = customization->LoadManifestFromFile(
+ startup_manifest_path);
+ if (manifest_loaded) {
+ LOG(INFO) << "Startup manifest loaded successfully";
+ return customization.release();
+ } else {
+ LOG(ERROR) << "Error loading startup manifest. " <<
+ kStartupCustomizationManifestPath;
+ }
+ }
+
+ return NULL;
+}
+
} // namespace
const char WizardController::kNetworkScreenName[] = "network";
@@ -171,6 +209,7 @@ const char WizardController::kUpdateScreenName[] = "update";
const char WizardController::kUserImageScreenName[] = "image";
const char WizardController::kEulaScreenName[] = "eula";
const char WizardController::kRegistrationScreenName[] = "register";
+const char WizardController::kHTMLPageScreenName[] = "html";
// Passing this parameter as a "first screen" initiates full OOBE flow.
const char WizardController::kOutOfBoxScreenName[] = "oobe";
@@ -191,6 +230,11 @@ WizardController::WizardController()
background_view_(NULL),
contents_(NULL),
current_screen_(NULL),
+#if defined(OFFICIAL_BUILD)
+ is_official_build_(true),
+#else
+ is_official_build_(false),
+#endif
is_out_of_box_(false),
is_test_mode_(false),
observer_(NULL) {
@@ -211,56 +255,43 @@ WizardController::~WizardController() {
void WizardController::Init(const std::string& first_screen_name,
const gfx::Rect& screen_bounds) {
+ LOG(INFO) << "Starting OOBE wizard with screen: " << first_screen_name;
DCHECK(!contents_);
+ first_screen_name_ = first_screen_name;
- int offset_x = (screen_bounds.width() - kWizardScreenWidth) / 2;
- int offset_y = (screen_bounds.height() - kWizardScreenHeight) / 2;
- int window_x = screen_bounds.x() + offset_x;
- int window_y = screen_bounds.y() + offset_y;
+ // When device is not registered yet we need to load startup manifest as well.
+ // In case of OOBE (network-EULA-update) manifest has been loaded in
+ // ShowLoginWizard().
+ if (IsOobeCompleted() && !IsDeviceRegistered())
+ SetCustomization(LoadStartupManifest());
- contents_ = new ContentView(offset_x, offset_y,
- screen_bounds.width(), screen_bounds.height());
-
- views::WidgetGtk* window =
- new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
- widget_ = window;
- window->MakeTransparent();
- // Window transparency makes background flicker through controls that
- // are constantly updating its contents (like image view with video
- // stream). Hence enabling double buffer.
- window->EnableDoubleBuffer(true);
- window->Init(NULL, gfx::Rect(window_x, window_y, kWizardScreenWidth,
- kWizardScreenHeight));
- chromeos::WmIpc::instance()->SetWindowType(
- window->GetNativeView(),
- chromeos::WM_IPC_WINDOW_LOGIN_GUEST,
- NULL);
- window->SetContentsView(contents_);
-
- PrefService* prefs = g_browser_process->local_state();
- bool oobe_complete = prefs->GetBoolean(kOobeComplete);
+ screen_bounds_ = screen_bounds;
+ contents_ = new ContentView();
+ bool oobe_complete = IsOobeCompleted();
if (!oobe_complete || first_screen_name == kOutOfBoxScreenName) {
is_out_of_box_ = true;
}
ShowFirstScreen(first_screen_name);
-
- // This keeps the window from flashing at startup.
- GdkWindow* gdk_window = window->GetNativeView()->window;
- gdk_window_set_back_pixmap(gdk_window, NULL, false);
}
void WizardController::Show() {
- DCHECK(widget_);
- widget_->Show();
+ // In tests we might startup without initial screen
+ // so widget_ hasn't been created yet.
+ if (first_screen_name_ != kTestNoScreenName)
+ DCHECK(widget_);
+ if (widget_)
+ widget_->Show();
}
void WizardController::ShowBackground(const gfx::Rect& bounds) {
DCHECK(!background_widget_);
background_widget_ =
chromeos::BackgroundView::CreateWindowContainingView(bounds,
+ GURL(),
&background_view_);
+ background_view_->SetOobeProgressBarVisible(true);
background_widget_->Show();
}
@@ -270,11 +301,12 @@ void WizardController::OwnBackground(
DCHECK(!background_widget_);
background_widget_ = background_widget;
background_view_ = background_view;
+ background_view_->OnOwnerChanged();
}
chromeos::NetworkScreen* WizardController::GetNetworkScreen() {
if (!network_screen_.get())
- network_screen_.reset(new chromeos::NetworkScreen(this, is_out_of_box_));
+ network_screen_.reset(new chromeos::NetworkScreen(this));
return network_screen_.get();
}
@@ -291,8 +323,11 @@ chromeos::AccountScreen* WizardController::GetAccountScreen() {
}
chromeos::UpdateScreen* WizardController::GetUpdateScreen() {
- if (!update_screen_.get())
+ if (!update_screen_.get()) {
update_screen_.reset(new chromeos::UpdateScreen(this));
+ update_screen_->SetMaximalCurtainTime(kMaximalCurtainTimeSec);
+ update_screen_->SetRebootCheckDelay(kWaitForRebootTimeSec);
+ }
return update_screen_.get();
}
@@ -314,13 +349,35 @@ chromeos::RegistrationScreen* WizardController::GetRegistrationScreen() {
return registration_screen_.get();
}
+chromeos::HTMLPageScreen* WizardController::GetHTMLPageScreen() {
+ if (!html_page_screen_.get()) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ std::string url;
+ // It's strange but args may contains empty strings.
+ for (size_t i = 0; i < command_line->args().size(); i++) {
+ if (!command_line->args()[i].empty()) {
+ DCHECK(url.empty()) << "More than one URL in command line";
+ url = command_line->args()[i];
+ }
+ }
+ DCHECK(!url.empty()) << "No URL in commane line";
+ html_page_screen_.reset(new chromeos::HTMLPageScreen(this, url));
+ }
+ return html_page_screen_.get();
+}
+
void WizardController::ShowNetworkScreen() {
SetStatusAreaVisible(false);
SetCurrentScreen(GetNetworkScreen());
+ background_view_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
}
-void WizardController::ShowLoginScreen() {
+chromeos::ExistingUserController* WizardController::ShowLoginScreen() {
SetStatusAreaVisible(true);
+ background_view_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
+
+ // Initiate services customization.
+ chromeos::ApplyServicesCustomization::StartIfNeeded();
// When run under automation test show plain login screen.
if (!is_test_mode_ &&
@@ -338,44 +395,71 @@ void WizardController::ShowLoginScreen() {
controller->Init();
background_widget_ = NULL;
background_view_ = NULL;
+
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
- return;
+
+ return controller;
}
SetCurrentScreen(GetLoginScreen());
+ return NULL;
}
void WizardController::ShowAccountScreen() {
+ LOG(INFO) << "Showing create account screen.";
SetStatusAreaVisible(true);
SetCurrentScreen(GetAccountScreen());
}
void WizardController::ShowUpdateScreen() {
+ LOG(INFO) << "Showing update screen.";
SetStatusAreaVisible(true);
SetCurrentScreen(GetUpdateScreen());
+ // There is no special step for update.
+#if defined(OFFICIAL_BUILD)
+ background_view_->SetOobeProgress(chromeos::BackgroundView::EULA);
+#else
+ background_view_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
+#endif
}
void WizardController::ShowUserImageScreen() {
- SetStatusAreaVisible(true);
+ LOG(INFO) << "Showing user image screen.";
+ SetStatusAreaVisible(false);
SetCurrentScreen(GetUserImageScreen());
+ background_view_->SetOobeProgress(chromeos::BackgroundView::PICTURE);
}
void WizardController::ShowEulaScreen() {
+ LOG(INFO) << "Showing EULA screen.";
SetStatusAreaVisible(false);
SetCurrentScreen(GetEulaScreen());
+#if defined(OFFICIAL_BUILD)
+ background_view_->SetOobeProgress(chromeos::BackgroundView::EULA);
+#endif
}
void WizardController::ShowRegistrationScreen() {
+ if (!GetCustomization() ||
+ !GURL(GetCustomization()->registration_url()).is_valid()) {
+ LOG(INFO) <<
+ "Skipping registration screen: manifest not defined or invalid URL.";
+ OnRegistrationSkipped();
+ return;
+ }
+ LOG(INFO) << "Showing registration screen.";
SetStatusAreaVisible(true);
SetCurrentScreen(GetRegistrationScreen());
+#if defined(OFFICIAL_BUILD)
+ background_view_->SetOobeProgress(chromeos::BackgroundView::REGISTRATION);
+#endif
}
-void WizardController::SetStatusAreaVisible(bool visible) {
- // When ExistingUserController passes background ownership
- // to WizardController it happens after screen is shown.
- if (background_view_) {
- background_view_->SetStatusAreaVisible(visible);
- }
+void WizardController::ShowHTMLPageScreen() {
+ LOG(INFO) << "Showing HTML page screen.";
+ SetStatusAreaVisible(true);
+ background_view_->SetOobeProgressBarVisible(false);
+ SetCurrentScreen(GetHTMLPageScreen());
}
void WizardController::SetCustomization(
@@ -384,13 +468,25 @@ void WizardController::SetCustomization(
}
const chromeos::StartupCustomizationDocument*
- WizardController::GetCustomization() {
+ WizardController::GetCustomization() const {
return customization_.get();
}
+void WizardController::SkipRegistration() {
+ if (current_screen_ == GetRegistrationScreen())
+ OnRegistrationSkipped();
+ else
+ LOG(ERROR) << "Registration screen is not active.";
+}
+
// static
void WizardController::RegisterPrefs(PrefService* local_state) {
local_state->RegisterBooleanPref(kOobeComplete, false);
+ // Check if the pref is already registered in case
+ // Preferences::RegisterUserPrefs runs before this code in the future.
+ if (local_state->FindPreference(prefs::kAccessibilityEnabled) == NULL) {
+ local_state->RegisterBooleanPref(prefs::kAccessibilityEnabled, false);
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -416,12 +512,11 @@ void WizardController::OnLoginCreateAccount() {
}
void WizardController::OnNetworkConnected() {
- if (is_out_of_box_) {
+ if (is_official_build_) {
+ ShowEulaScreen();
+ } else {
ShowUpdateScreen();
GetUpdateScreen()->StartUpdate();
- } else {
- // TODO(nkostylev): Remove this path after accelerator is removed.
- ShowLoginScreen();
}
}
@@ -432,22 +527,20 @@ void WizardController::OnNetworkOffline() {
}
void WizardController::OnAccountCreateBack() {
- ShowLoginScreen();
+ chromeos::ExistingUserController* controller = ShowLoginScreen();
+ if (controller)
+ controller->SelectNewUser();
}
void WizardController::OnAccountCreated() {
- ShowLoginScreen();
- chromeos::LoginScreen* login = GetLoginScreen();
- if (!username_.empty()) {
- login->view()->SetUsername(username_);
- if (!password_.empty()) {
- login->view()->SetPassword(password_);
- // TODO(dpolukhin): clear password memory for real. Now it is not
- // a problem becuase we can't extract password from the form.
- password_.clear();
- login->view()->Login();
- }
- }
+ chromeos::ExistingUserController* controller = ShowLoginScreen();
+ if (controller)
+ controller->LoginNewUser(username_, password_);
+ else
+ Login(username_, password_);
+ // TODO(dpolukhin): clear password memory for real. Now it is not
+ // a problem because we can't extract password from the form.
+ password_.clear();
}
void WizardController::OnConnectionFailed() {
@@ -456,12 +549,12 @@ void WizardController::OnConnectionFailed() {
}
void WizardController::OnUpdateCompleted() {
- ShowEulaScreen();
+ OnOOBECompleted();
}
void WizardController::OnEulaAccepted() {
- MarkOobeCompleted();
- ShowLoginScreen();
+ ShowUpdateScreen();
+ GetUpdateScreen()->StartUpdate();
}
void WizardController::OnUpdateErrorCheckingForUpdate() {
@@ -470,7 +563,7 @@ void WizardController::OnUpdateErrorCheckingForUpdate() {
// screen if there is any error checking for an update.
// They could use "browse without sign-in" feature to set up the network to be
// able to perform the update later.
- ShowEulaScreen();
+ OnOOBECompleted();
}
void WizardController::OnUpdateErrorUpdating() {
@@ -479,7 +572,7 @@ void WizardController::OnUpdateErrorUpdating() {
// TODO(nkostylev): Show message to the user explaining update error.
// TODO(nkostylev): Update should be required during OOBE.
// Temporary fix, need to migrate to new API. http://crosbug.com/4321
- ShowEulaScreen();
+ OnOOBECompleted();
}
void WizardController::OnUserImageSelected() {
@@ -499,8 +592,12 @@ void WizardController::OnUserImageSkipped() {
}
void WizardController::OnRegistrationSuccess() {
- // TODO(nkostylev): Registration screen should be shown on first sign in.
- ShowLoginScreen();
+ MarkDeviceRegistered();
+ if (chromeos::UserManager::Get()->logged_in_user().email().empty()) {
+ chromeos::LoginUtils::Get()->CompleteOffTheRecordLogin(start_url_);
+ } else {
+ ShowUserImageScreen();
+ }
}
void WizardController::OnRegistrationSkipped() {
@@ -508,26 +605,92 @@ void WizardController::OnRegistrationSkipped() {
OnRegistrationSuccess();
}
+void WizardController::OnOOBECompleted() {
+ MarkOobeCompleted();
+ ShowLoginScreen();
+}
+
///////////////////////////////////////////////////////////////////////////////
// WizardController, private:
+views::WidgetGtk* WizardController::CreateScreenWindow(
+ const gfx::Rect& bounds, bool initial_show) {
+ views::WidgetGtk* window =
+ new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
+ widget_ = window;
+ window->MakeTransparent();
+ // Window transparency makes background flicker through controls that
+ // are constantly updating its contents (like image view with video
+ // stream). Hence enabling double buffer.
+ window->EnableDoubleBuffer(true);
+ window->Init(NULL, bounds);
+ std::vector<int> params;
+ // For initial show WM would animate background window.
+ // Otherwise it stays unchaged.
+ params.push_back(initial_show);
+ chromeos::WmIpc::instance()->SetWindowType(
+ window->GetNativeView(),
+ chromeos::WM_IPC_WINDOW_LOGIN_GUEST,
+ &params);
+ window->SetContentsView(contents_);
+ return window;
+}
+
+gfx::Rect WizardController::GetWizardScreenBounds(int screen_width,
+ int screen_height) const {
+ int offset_x = (screen_bounds_.width() - screen_width) / 2;
+ int offset_y = (screen_bounds_.height() - screen_height) / 2;
+ int window_x = screen_bounds_.x() + offset_x;
+ int window_y = screen_bounds_.y() + offset_y;
+ return gfx::Rect(window_x, window_y, screen_width, screen_height);
+}
+
+
void WizardController::SetCurrentScreen(WizardScreen* new_current) {
- if (current_screen_ == new_current)
+ if (current_screen_ == new_current ||
+ new_current == NULL)
return;
- if (current_screen_)
+
+ bool initial_show = true;
+ if (current_screen_) {
+ initial_show = false;
current_screen_->Hide();
+ }
+
current_screen_ = new_current;
- if (current_screen_) {
- current_screen_->Show();
- contents_->Layout();
+ bool force_widget_show = false;
+ views::WidgetGtk* window = NULL;
+
+ gfx::Rect current_bounds;
+ if (widget_)
+ widget_->GetBounds(&current_bounds, false);
+ gfx::Size new_screen_size = current_screen_->GetScreenSize();
+ gfx::Rect new_bounds = GetWizardScreenBounds(new_screen_size.width(),
+ new_screen_size.height());
+ if (new_bounds != current_bounds) {
+ if (widget_)
+ widget_->Close();
+ force_widget_show = true;
+ window = CreateScreenWindow(new_bounds, initial_show);
}
+ current_screen_->Show();
+ contents_->Layout();
contents_->SchedulePaint();
+ if (force_widget_show) {
+ // This keeps the window from flashing at startup.
+ GdkWindow* gdk_window = window->GetNativeView()->window;
+ gdk_window_set_back_pixmap(gdk_window, NULL, false);
+ if (widget_)
+ widget_->Show();
+ }
}
-void WizardController::OnSetUserNamePassword(const std::string& username,
- const std::string& password) {
- username_ = username;
- password_ = password;
+void WizardController::SetStatusAreaVisible(bool visible) {
+ // When ExistingUserController passes background ownership
+ // to WizardController it happens after screen is shown.
+ if (background_view_) {
+ background_view_->SetStatusAreaVisible(visible);
+ }
}
void WizardController::ShowFirstScreen(const std::string& first_screen_name) {
@@ -547,7 +710,14 @@ void WizardController::ShowFirstScreen(const std::string& first_screen_name) {
} else if (first_screen_name == kEulaScreenName) {
ShowEulaScreen();
} else if (first_screen_name == kRegistrationScreenName) {
- ShowRegistrationScreen();
+ if (is_official_build_) {
+ ShowRegistrationScreen();
+ } else {
+ // Just proceed to image screen.
+ OnRegistrationSuccess();
+ }
+ } else if (first_screen_name == kHTMLPageScreenName) {
+ ShowHTMLPageScreen();
} else if (first_screen_name != kTestNoScreenName) {
if (is_out_of_box_) {
ShowNetworkScreen();
@@ -557,6 +727,25 @@ void WizardController::ShowFirstScreen(const std::string& first_screen_name) {
}
}
+void WizardController::Login(const std::string& username,
+ const std::string& password) {
+ chromeos::LoginScreen* login = GetLoginScreen();
+ if (username.empty())
+ return;
+ login->view()->SetUsername(username);
+
+ if (password.empty())
+ return;
+ login->view()->SetPassword(password);
+ login->view()->Login();
+}
+
+// static
+bool WizardController::IsOobeCompleted() {
+ return g_browser_process->local_state()->GetBoolean(kOobeComplete);
+}
+
+// static
void WizardController::MarkOobeCompleted() {
PrefService* prefs = g_browser_process->local_state();
prefs->SetBoolean(kOobeComplete, true);
@@ -564,9 +753,26 @@ void WizardController::MarkOobeCompleted() {
prefs->SavePersistentPrefs();
}
+// static
+bool WizardController::IsDeviceRegistered() {
+ FilePath oobe_complete_flag_file_path(kOobeCompleteFlagFilePath);
+ return file_util::PathExists(oobe_complete_flag_file_path);
+}
+
+// static
+void WizardController::MarkDeviceRegistered() {
+ // Create flag file for boot-time init scripts.
+ FilePath oobe_complete_path(kOobeCompleteFlagFilePath);
+ FILE* oobe_flag_file = file_util::OpenFile(oobe_complete_path, "w+b");
+ DCHECK(oobe_flag_file != NULL) << kOobeCompleteFlagFilePath;
+ if (oobe_flag_file != NULL)
+ file_util::CloseFile(oobe_flag_file);
+}
+
///////////////////////////////////////////////////////////////////////////////
// WizardController, chromeos::ScreenObserver overrides:
void WizardController::OnExit(ExitCodes exit_code) {
+ LOG(INFO) << "Wizard screen exit code: " << exit_code;
switch (exit_code) {
case LOGIN_SIGN_IN_SELECTED:
OnLoginSignInSelected();
@@ -611,6 +817,9 @@ void WizardController::OnExit(ExitCodes exit_code) {
case EULA_ACCEPTED:
OnEulaAccepted();
break;
+ case EULA_BACK:
+ ShowNetworkScreen();
+ break;
case REGISTRATION_SUCCESS:
OnRegistrationSuccess();
break;
@@ -622,6 +831,12 @@ void WizardController::OnExit(ExitCodes exit_code) {
}
}
+void WizardController::OnSetUserNamePassword(const std::string& username,
+ const std::string& password) {
+ username_ = username;
+ password_ = password;
+}
+
///////////////////////////////////////////////////////////////////////////////
// WizardController, WizardScreen overrides:
views::View* WizardController::GetWizardView() {
@@ -639,6 +854,10 @@ void ShowLoginWizard(const std::string& first_screen_name,
const gfx::Size& size) {
LOG(INFO) << "showing login screen: " << first_screen_name;
+ // The login screen will enable alternate keyboard layouts, but we don't want
+ // to start the IME process unless one is selected.
+ chromeos::CrosLibrary::Get()->GetInputMethodLibrary()->
+ SetDeferImeStartup(true);
// Tell the window manager that the user isn't logged in.
chromeos::WmIpc::instance()->SetLoggedInProperty(false);
@@ -648,7 +867,7 @@ void ShowLoginWizard(const std::string& first_screen_name,
const std::string locale = g_browser_process->GetApplicationLocale();
const std::string initial_input_method_id =
g_browser_process->local_state()->GetString(
- chromeos::kPreferredKeyboardLayout);
+ chromeos::language_prefs::kPreferredKeyboardLayout);
chromeos::input_method::EnableInputMethods(
locale, chromeos::input_method::kKeyboardLayoutsOnly,
initial_input_method_id);
@@ -657,8 +876,7 @@ void ShowLoginWizard(const std::string& first_screen_name,
gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(size));
// Check whether we need to execute OOBE process.
- bool oobe_complete = g_browser_process->local_state()->
- GetBoolean(kOobeComplete);
+ bool oobe_complete = WizardController::IsOobeCompleted();
if (first_screen_name.empty() &&
oobe_complete &&
@@ -667,52 +885,73 @@ void ShowLoginWizard(const std::string& first_screen_name,
switches::kEnableLoginImages)) {
std::vector<chromeos::UserManager::User> users =
chromeos::UserManager::Get()->GetUsers();
+
+ // Fix for users who updated device and thus never passed register screen.
+ // If we already have user we assume that it is not a second part of OOBE.
+ // See http://crosbug.com/6289
+ if (!WizardController::IsDeviceRegistered() && !users.empty()) {
+ LOG(INFO) << "Mark device registered because there are remembered users: "
+ << users.size();
+ WizardController::MarkDeviceRegistered();
+ }
+
// ExistingUserController deletes itself.
(new chromeos::ExistingUserController(users, screen_bounds))->Init();
+
+ // Initiate services customization.
+ chromeos::ApplyServicesCustomization::StartIfNeeded();
+
return;
}
- scoped_ptr<chromeos::StartupCustomizationDocument> customization;
-
- if (!oobe_complete) {
- // Load partner customization startup manifest if needed.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kStartupManifest)) {
- customization.reset(new chromeos::StartupCustomizationDocument());
- FilePath manifest_path =
- CommandLine::ForCurrentProcess()->GetSwitchValuePath(
- switches::kStartupManifest);
- bool manifest_loaded = customization->LoadManifestFromFile(manifest_path);
- DCHECK(manifest_loaded) << manifest_path.value();
- }
+ // Create and show the wizard.
+ WizardController* controller = new WizardController();
- // Do UX customizations if needed.
- if (customization != NULL) {
- // Switch to initial locale if specified by customization.
- const std::string locale = customization->initial_locale();
- if (!locale.empty()) {
- chromeos::LanguageSwitchMenu::SwitchLanguage(locale);
- }
+ // Load startup manifest.
+ controller->SetCustomization(LoadStartupManifest());
- // Set initial timezone if specified by customization.
- const std::string timezone_name = customization->initial_timezone();
- if (!timezone_name.empty()) {
- icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
- icu::UnicodeString::fromUTF8(timezone_name));
- chromeos::CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone);
+ std::string locale;
+ if (controller->GetCustomization()) {
+ // Switch to initial locale if specified by customization
+ // and has not been set yet. We cannot call
+ // chromeos::LanguageSwitchMenu::SwitchLanguage here before
+ // EmitLoginPromptReady.
+ const std::string current_locale =
+ g_browser_process->local_state()->GetString(
+ prefs::kApplicationLocale);
+ LOG(INFO) << "current locale: " << current_locale;
+ if (current_locale.empty()) {
+ locale = controller->GetCustomization()->initial_locale();
+ LOG(INFO) << "initial locale: " << locale;
+ if (!locale.empty()) {
+ ResourceBundle::ReloadSharedInstance(locale);
}
}
}
- // Create and show the wizard.
- WizardController* controller = new WizardController();
- if (!oobe_complete)
- controller->SetCustomization(customization.release());
controller->ShowBackground(screen_bounds);
controller->Init(first_screen_name, screen_bounds);
controller->Show();
+
if (chromeos::CrosLibrary::Get()->EnsureLoaded())
chromeos::CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady();
+
+ if (controller->GetCustomization()) {
+ if (!locale.empty())
+ chromeos::LanguageSwitchMenu::SwitchLanguage(locale);
+
+ // Set initial timezone if specified by customization.
+ const std::string timezone_name =
+ controller->GetCustomization()->initial_timezone();
+ LOG(INFO) << "initial time zone: " << timezone_name;
+ // Apply locale customizations only once so preserve whatever locale
+ // user has changed to during OOBE.
+ if (!timezone_name.empty()) {
+ icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
+ icu::UnicodeString::fromUTF8(timezone_name));
+ chromeos::CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone);
+ }
+ }
}
} // namespace browser
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 25394ff..44fb432 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_WIZARD_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_WIZARD_CONTROLLER_H_
+#pragma once
#include <string>
@@ -12,6 +13,8 @@
#include "chrome/browser/chromeos/login/screen_observer.h"
#include "chrome/browser/chromeos/login/view_screen.h"
#include "chrome/browser/chromeos/login/wizard_screen.h"
+#include "gfx/rect.h"
+#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
class PrefService;
@@ -22,6 +25,8 @@ namespace chromeos {
class AccountScreen;
class BackgroundView;
class EulaScreen;
+class ExistingUserController;
+class HTMLPageScreen;
class LoginScreen;
class NetworkScreen;
class RegistrationScreen;
@@ -37,6 +42,7 @@ class Rect;
namespace views {
class Views;
class Widget;
+class WidgetGtk;
}
// Class that manages control flow between wizard screens. Wizard controller
@@ -52,6 +58,18 @@ class WizardController : public chromeos::ScreenObserver,
return default_controller_;
}
+ // Returns OOBE completion status.
+ static bool IsOobeCompleted();
+
+ // Marks OOBE process as completed.
+ static void MarkOobeCompleted();
+
+ // Returns device registration completion status, i.e. second part of OOBE.
+ static bool IsDeviceRegistered();
+
+ // Marks device registered. i.e. second part of OOBE is completed.
+ static void MarkDeviceRegistered();
+
// Shows the first screen defined by |first_screen_name| or by default
// if the parameter is empty. |screen_bounds| are used to calculate position
// of the wizard screen.
@@ -79,33 +97,41 @@ class WizardController : public chromeos::ScreenObserver,
chromeos::UserImageScreen* GetUserImageScreen();
chromeos::EulaScreen* GetEulaScreen();
chromeos::RegistrationScreen* GetRegistrationScreen();
+ chromeos::HTMLPageScreen* GetHTMLPageScreen();
// Show specific screen.
void ShowNetworkScreen();
- void ShowLoginScreen();
void ShowAccountScreen();
void ShowUpdateScreen();
void ShowUserImageScreen();
void ShowEulaScreen();
void ShowRegistrationScreen();
+ void ShowHTMLPageScreen();
+ // Shows the default login screen and returns NULL or shows images login
+ // screen and returns the corresponding controller instance for optional
+ // tweaking.
+ chromeos::ExistingUserController* ShowLoginScreen();
// Returns a pointer to the current screen or NULL if there's no such
// screen.
WizardScreen* current_screen() const { return current_screen_; }
- // True if WizardController is in OOBE mode.
- bool is_oobe() { return is_out_of_box_; }
-
// Overrides observer for testing.
void set_observer(ScreenObserver* observer) { observer_ = observer; }
+ // Set URL to open on browser launch.
+ void set_start_url(const GURL& start_url) { start_url_ = start_url; }
+
// Sets partner startup customization. WizardController takes ownership
// of the document object.
void SetCustomization(
const chromeos::StartupCustomizationDocument* customization);
// Returns partner startup customization document owned by WizardController.
- const chromeos::StartupCustomizationDocument* GetCustomization();
+ const chromeos::StartupCustomizationDocument* GetCustomization() const;
+
+ // If being at register screen proceeds to the next one.
+ void SkipRegistration();
// Registers OOBE preferences.
static void RegisterPrefs(PrefService* local_state);
@@ -119,6 +145,7 @@ class WizardController : public chromeos::ScreenObserver,
static const char kOutOfBoxScreenName[];
static const char kTestNoScreenName[];
static const char kEulaScreenName[];
+ static const char kHTMLPageScreenName[];
private:
// Exit handlers:
@@ -138,6 +165,17 @@ class WizardController : public chromeos::ScreenObserver,
void OnUserImageSkipped();
void OnRegistrationSuccess();
void OnRegistrationSkipped();
+ void OnOOBECompleted();
+
+ // Creates wizard screen window with the specified |bounds|.
+ // If |initial_show| initial animation (window & background) is shown.
+ // Otherwise only window is animated.
+ views::WidgetGtk* CreateScreenWindow(const gfx::Rect& bounds,
+ bool initial_show);
+
+ // Returns bounds for the wizard screen host window in screen coordinates.
+ // Calculates bounds using screen_bounds_.
+ gfx::Rect GetWizardScreenBounds(int screen_width, int screen_height) const;
// Switches from one screen to another.
void SetCurrentScreen(WizardScreen* screen);
@@ -158,8 +196,8 @@ class WizardController : public chromeos::ScreenObserver,
// sets it as the current one.
void ShowFirstScreen(const std::string& first_screen_name);
- // Marks OOBE process as completed.
- void MarkOobeCompleted();
+ // Logs in the specified user via default login screen.
+ void Login(const std::string& username, const std::string& password);
// Widget we're showing in.
views::Widget* widget_;
@@ -171,6 +209,9 @@ class WizardController : public chromeos::ScreenObserver,
// Contents view.
views::View* contents_;
+ // Used to calculate position of the wizard screen.
+ gfx::Rect screen_bounds_;
+
// Screens.
scoped_ptr<chromeos::NetworkScreen> network_screen_;
scoped_ptr<chromeos::LoginScreen> login_screen_;
@@ -179,6 +220,7 @@ class WizardController : public chromeos::ScreenObserver,
scoped_ptr<chromeos::UserImageScreen> user_image_screen_;
scoped_ptr<chromeos::EulaScreen> eula_screen_;
scoped_ptr<chromeos::RegistrationScreen> registration_screen_;
+ scoped_ptr<chromeos::HTMLPageScreen> html_page_screen_;
// Screen that's currently active.
WizardScreen* current_screen_;
@@ -186,6 +228,9 @@ class WizardController : public chromeos::ScreenObserver,
std::string username_;
std::string password_;
+ // True if running official BUILD.
+ bool is_official_build_;
+
// True if full OOBE flow should be shown.
bool is_out_of_box_;
@@ -193,6 +238,9 @@ class WizardController : public chromeos::ScreenObserver,
// login screen.
bool is_test_mode_;
+ // Value of the screen name that WizardController was started with.
+ std::string first_screen_name_;
+
// NULL by default - controller itself is observer. Mock could be assigned.
ScreenObserver* observer_;
@@ -202,8 +250,12 @@ class WizardController : public chromeos::ScreenObserver,
// Partner startup customizations.
scoped_ptr<const chromeos::StartupCustomizationDocument> customization_;
+ // URL to open on browser launch.
+ GURL start_url_;
+
FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest, ControlFlowErrorNetwork);
FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest, ControlFlowErrorUpdate);
+ FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest, ControlFlowEulaDeclined);
FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest,
ControlFlowLanguageOnLogin);
FRIEND_TEST_ALL_PREFIXES(WizardControllerFlowTest,
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 6459286..e38fdda 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -47,7 +47,7 @@ CreateMockWizardScreenHelper<T>::Create(WizardController* wizard) {
template <> MockOutShowHide<chromeos::NetworkScreen>*
CreateMockWizardScreenHelper<chromeos::NetworkScreen>::Create(
WizardController* wizard) {
- return new MockOutShowHide<chromeos::NetworkScreen>(wizard, true);
+ return new MockOutShowHide<chromeos::NetworkScreen>(wizard);
}
#define MOCK(mock_var, screen_name, mocked_class) \
@@ -71,7 +71,7 @@ class WizardControllerTest : public chromeos::WizardInProcessBrowserTest {
IN_PROC_BROWSER_TEST_F(WizardControllerTest, SwitchLanguage) {
WizardController* const wizard = controller();
ASSERT_TRUE(wizard != NULL);
- wizard->ShowFirstScreen(WizardController::kOutOfBoxScreenName);
+ wizard->ShowFirstScreen(WizardController::kNetworkScreenName);
views::View* current_screen = wizard->contents();
ASSERT_TRUE(current_screen != NULL);
@@ -105,6 +105,9 @@ class WizardControllerFlowTest : public WizardControllerTest {
virtual Browser* CreateBrowser(Profile* profile) {
Browser* ret = WizardControllerTest::CreateBrowser(profile);
+ // Make sure that OOBE is run as an "official" build.
+ WizardController::default_controller()->is_official_build_ = true;
+
// Set up the mocks for all screens.
MOCK(mock_account_screen_, account_screen_, chromeos::AccountScreen);
MOCK(mock_login_screen_, login_screen_, chromeos::LoginScreen);
@@ -115,7 +118,7 @@ class WizardControllerFlowTest : public WizardControllerTest {
// Switch to the initial screen.
EXPECT_EQ(NULL, controller()->current_screen());
EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
- controller()->ShowFirstScreen(WizardController::kOutOfBoxScreenName);
+ controller()->ShowFirstScreen(WizardController::kNetworkScreenName);
return ret;
}
@@ -133,19 +136,20 @@ class WizardControllerFlowTest : public WizardControllerTest {
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowMain) {
EXPECT_EQ(controller()->GetNetworkScreen(), controller()->current_screen());
EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
+ EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
+ controller()->OnExit(chromeos::ScreenObserver::NETWORK_CONNECTED);
+
+ EXPECT_EQ(controller()->GetEulaScreen(), controller()->current_screen());
+ EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
EXPECT_CALL(*mock_update_screen_, StartUpdate()).Times(1);
EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
- controller()->OnExit(chromeos::ScreenObserver::NETWORK_CONNECTED);
+ controller()->OnExit(chromeos::ScreenObserver::EULA_ACCEPTED);
EXPECT_EQ(controller()->GetUpdateScreen(), controller()->current_screen());
EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
- EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
- controller()->OnExit(chromeos::ScreenObserver::UPDATE_INSTALLED);
-
- EXPECT_EQ(controller()->GetEulaScreen(), controller()->current_screen());
- EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
+ EXPECT_CALL(*mock_eula_screen_, Show()).Times(0);
EXPECT_CALL(*mock_login_screen_, Show()).Times(1);
- controller()->OnExit(chromeos::ScreenObserver::EULA_ACCEPTED);
+ controller()->OnExit(chromeos::ScreenObserver::UPDATE_INSTALLED);
EXPECT_EQ(controller()->GetLoginScreen(), controller()->current_screen());
EXPECT_CALL(*mock_login_screen_, Hide()).Times(1);
@@ -163,19 +167,43 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowMain) {
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowErrorUpdate) {
EXPECT_EQ(controller()->GetNetworkScreen(), controller()->current_screen());
- EXPECT_CALL(*mock_update_screen_, StartUpdate()).Times(1);
- EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
+ EXPECT_CALL(*mock_update_screen_, StartUpdate()).Times(0);
+ EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
+ EXPECT_CALL(*mock_update_screen_, Show()).Times(0);
EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
controller()->OnExit(chromeos::ScreenObserver::NETWORK_CONNECTED);
+ EXPECT_EQ(controller()->GetEulaScreen(), controller()->current_screen());
+ EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
+ EXPECT_CALL(*mock_update_screen_, StartUpdate()).Times(1);
+ EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
+ controller()->OnExit(chromeos::ScreenObserver::EULA_ACCEPTED);
+
EXPECT_EQ(controller()->GetUpdateScreen(), controller()->current_screen());
EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
- EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
+ EXPECT_CALL(*mock_eula_screen_, Show()).Times(0);
EXPECT_CALL(*mock_eula_screen_, Hide()).Times(0); // last transition
+ EXPECT_CALL(*mock_login_screen_, Show()).Times(1);
controller()->OnExit(
chromeos::ScreenObserver::UPDATE_ERROR_UPDATING);
+ EXPECT_EQ(controller()->GetLoginScreen(), controller()->current_screen());
+}
+
+IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowEulaDeclined) {
+ EXPECT_EQ(controller()->GetNetworkScreen(), controller()->current_screen());
+ EXPECT_CALL(*mock_update_screen_, StartUpdate()).Times(0);
+ EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
+ EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
+ controller()->OnExit(chromeos::ScreenObserver::NETWORK_CONNECTED);
+
EXPECT_EQ(controller()->GetEulaScreen(), controller()->current_screen());
+ EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1);
+ EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
+ EXPECT_CALL(*mock_network_screen_, Hide()).Times(0); // last transition
+ controller()->OnExit(chromeos::ScreenObserver::EULA_BACK);
+
+ EXPECT_EQ(controller()->GetNetworkScreen(), controller()->current_screen());
}
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowErrorNetwork) {
@@ -191,41 +219,46 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, Accelerators) {
views::FocusManager* focus_manager =
controller()->contents()->GetFocusManager();
- views::Accelerator accel_account_screen(base::VKEY_A, false, true, true);
- views::Accelerator accel_login_screen(base::VKEY_L, false, true, true);
- views::Accelerator accel_network_screen(base::VKEY_N, false, true, true);
- views::Accelerator accel_update_screen(base::VKEY_U, false, true, true);
- views::Accelerator accel_image_screen(base::VKEY_I, false, true, true);
- views::Accelerator accel_eula_screen(base::VKEY_E, false, true, true);
+ views::Accelerator accel_account_screen(app::VKEY_A, false, true, true);
+ views::Accelerator accel_login_screen(app::VKEY_L, false, true, true);
+ views::Accelerator accel_network_screen(app::VKEY_N, false, true, true);
+ views::Accelerator accel_update_screen(app::VKEY_U, false, true, true);
+ views::Accelerator accel_image_screen(app::VKEY_I, false, true, true);
+ views::Accelerator accel_eula_screen(app::VKEY_E, false, true, true);
EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
EXPECT_CALL(*mock_account_screen_, Show()).Times(1);
EXPECT_TRUE(focus_manager->ProcessAccelerator(accel_account_screen));
EXPECT_EQ(controller()->GetAccountScreen(), controller()->current_screen());
+ focus_manager = controller()->contents()->GetFocusManager();
EXPECT_CALL(*mock_account_screen_, Hide()).Times(1);
EXPECT_CALL(*mock_login_screen_, Show()).Times(1);
EXPECT_TRUE(focus_manager->ProcessAccelerator(accel_login_screen));
EXPECT_EQ(controller()->GetLoginScreen(), controller()->current_screen());
+ focus_manager = controller()->contents()->GetFocusManager();
EXPECT_CALL(*mock_login_screen_, Hide()).Times(1);
EXPECT_CALL(*mock_network_screen_, Show()).Times(1);
EXPECT_TRUE(focus_manager->ProcessAccelerator(accel_network_screen));
EXPECT_EQ(controller()->GetNetworkScreen(), controller()->current_screen());
+ focus_manager = controller()->contents()->GetFocusManager();
EXPECT_CALL(*mock_network_screen_, Hide()).Times(1);
EXPECT_CALL(*mock_update_screen_, Show()).Times(1);
EXPECT_TRUE(focus_manager->ProcessAccelerator(accel_update_screen));
EXPECT_EQ(controller()->GetUpdateScreen(), controller()->current_screen());
+ focus_manager = controller()->contents()->GetFocusManager();
EXPECT_CALL(*mock_update_screen_, Hide()).Times(1);
EXPECT_TRUE(focus_manager->ProcessAccelerator(accel_image_screen));
EXPECT_EQ(controller()->GetUserImageScreen(), controller()->current_screen());
+ focus_manager = controller()->contents()->GetFocusManager();
EXPECT_CALL(*mock_eula_screen_, Show()).Times(1);
EXPECT_TRUE(focus_manager->ProcessAccelerator(accel_eula_screen));
EXPECT_EQ(controller()->GetEulaScreen(), controller()->current_screen());
}
-COMPILE_ASSERT(chromeos::ScreenObserver::EXIT_CODES_COUNT == 17,
+COMPILE_ASSERT(chromeos::ScreenObserver::EXIT_CODES_COUNT == 18,
add_tests_for_new_control_flow_you_just_introduced);
diff --git a/chrome/browser/chromeos/login/wizard_in_process_browser_test.h b/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
index d9b634e..da23b35 100644
--- a/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
+++ b/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_WIZARD_IN_PROCESS_BROWSER_TEST_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_WIZARD_IN_PROCESS_BROWSER_TEST_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/login/wizard_screen.h b/chrome/browser/chromeos/login/wizard_screen.h
index 3eb3e9e..d0b0d8b 100644
--- a/chrome/browser/chromeos/login/wizard_screen.h
+++ b/chrome/browser/chromeos/login/wizard_screen.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_WIZARD_SCREEN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_WIZARD_SCREEN_H_
+#pragma once
#include "gfx/canvas.h"
@@ -11,6 +12,9 @@ class WizardScreen;
namespace chromeos {
class ScreenObserver;
} // namespace chromeos
+namespace gfx {
+class Size;
+} // namespace gfx
namespace views {
class View;
} // namespace views
@@ -36,6 +40,8 @@ class WizardScreen {
virtual void Show() = 0;
// Makes wizard screen invisible.
virtual void Hide() = 0;
+ // Returns the size the screen.
+ virtual gfx::Size GetScreenSize() const = 0;
protected:
explicit WizardScreen(WizardScreenDelegate* delegate): delegate_(delegate) {}
@@ -51,4 +57,3 @@ class WizardScreen {
};
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_WIZARD_SCREEN_H_
-
diff --git a/chrome/browser/chromeos/low_battery_observer.cc b/chrome/browser/chromeos/low_battery_observer.cc
index b923f08..0513cc2 100644
--- a/chrome/browser/chromeos/low_battery_observer.cc
+++ b/chrome/browser/chromeos/low_battery_observer.cc
@@ -72,7 +72,7 @@ void LowBatteryObserver::PowerChanged(PowerLibrary* object) {
void LowBatteryObserver::Show(base::TimeDelta remaining, bool urgent) {
notification_.Show(l10n_util::GetStringFUTF16(IDS_LOW_BATTERY_MESSAGE,
- WideToUTF16(TimeFormat::TimeRemaining(remaining))), urgent);
+ TimeFormat::TimeRemaining(remaining)), urgent, true);
remaining_ = remaining.InMinutes();
}
@@ -81,4 +81,3 @@ void LowBatteryObserver::Hide() {
}
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/low_battery_observer.h b/chrome/browser/chromeos/low_battery_observer.h
index 5bbed0a..1756f50 100644
--- a/chrome/browser/chromeos/low_battery_observer.h
+++ b/chrome/browser/chromeos/low_battery_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOW_BATTERY_OBSERVER_H_
#define CHROME_BROWSER_CHROMEOS_LOW_BATTERY_OBSERVER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/time.h"
diff --git a/chrome/browser/chromeos/mock_cros_settings.cc b/chrome/browser/chromeos/mock_cros_settings.cc
deleted file mode 100644
index 5cec066..0000000
--- a/chrome/browser/chromeos/mock_cros_settings.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/chromeos/mock_cros_settings.h"
-
-namespace chromeos {
-
-MockCrosSettings::MockCrosSettings()
- : dict_(new DictionaryValue) {
- // Some mock settings
- SetBoolean(kAccountsPrefAllowBWSI, true);
- SetBoolean(kAccountsPrefAllowGuest, true);
-
- ListValue* user_list = new ListValue;
-
- DictionaryValue* mock_user = new DictionaryValue;
- mock_user->SetString(L"email", L"mock_user_1@gmail.com");
- user_list->Append(mock_user);
-
- mock_user = new DictionaryValue;
- mock_user->SetString(L"email", L"mock_user_2@gmail.com");
- user_list->Append(mock_user);
-
- Set(kAccountsPrefUsers, user_list);
-}
-
-void MockCrosSettings::Set(const std::wstring& path, Value* in_value) {
- dict_->Set(path, in_value);
-}
-
-bool MockCrosSettings::Get(const std::wstring& path, Value** out_value) const {
- return dict_->Get(path, out_value);
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/mock_cros_settings.h b/chrome/browser/chromeos/mock_cros_settings.h
deleted file mode 100644
index 606dbdf..0000000
--- a/chrome/browser/chromeos/mock_cros_settings.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_CHROMEOS_MOCK_CROS_SETTINGS_H_
-#define CHROME_BROWSER_CHROMEOS_MOCK_CROS_SETTINGS_H_
-
-#include "base/singleton.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/chromeos/cros_settings.h"
-
-namespace chromeos {
-
-class MockCrosSettings : public CrosSettings {
- public:
- virtual void Set(const std::wstring& path, Value* in_value);
- virtual bool Get(const std::wstring& path, Value** out_value) const;
-
- private:
- scoped_ptr<DictionaryValue> dict_;
-
- MockCrosSettings();
- friend struct DefaultSingletonTraits<MockCrosSettings>;
-
- DISALLOW_COPY_AND_ASSIGN(MockCrosSettings);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_MOCK_CROS_SETTINGS_H_
diff --git a/chrome/browser/chromeos/native_dialog_window.cc b/chrome/browser/chromeos/native_dialog_window.cc
index ec9ffbf..200dd62 100644
--- a/chrome/browser/chromeos/native_dialog_window.cc
+++ b/chrome/browser/chromeos/native_dialog_window.cc
@@ -4,9 +4,12 @@
#include "chrome/browser/chromeos/native_dialog_window.h"
+#include <gtk/gtk.h>
+
#include "app/gtk_signal.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/frame/bubble_window.h"
#include "views/controls/native/native_view_host.h"
#include "views/window/dialog_delegate.h"
#include "views/window/non_client_view.h"
@@ -18,6 +21,30 @@ const int kDialogPadding = 3;
const char kNativeDialogHost[] = "_chromeos_native_dialog_host_";
+// TODO(xiyuan): Use gtk_window_get_default_widget with GTK 2.14+.
+// Gets the default widget of given dialog.
+GtkWidget* GetDialogDefaultWidget(GtkDialog* dialog) {
+ GtkWidget* default_widget = NULL;
+
+ GList* children = gtk_container_get_children(
+ GTK_CONTAINER(dialog->action_area));
+
+ GList* current = children;
+ while (current) {
+ GtkWidget* widget = reinterpret_cast<GtkWidget*>(current->data);
+ if (GTK_WIDGET_HAS_DEFAULT(widget)) {
+ default_widget = widget;
+ break;
+ }
+
+ current = g_list_next(current);
+ }
+
+ g_list_free(children);
+
+ return default_widget;
+}
+
} // namespace
namespace chromeos {
@@ -165,6 +192,12 @@ void NativeDialogHost::Init() {
if (contents_view_)
return;
+ // Get default widget of the dialog.
+ GtkWidget* default_widget = GetDialogDefaultWidget(GTK_DIALOG(dialog_));
+
+ // Get focus widget of the dialog.
+ GtkWidget* focus_widget = gtk_window_get_focus(GTK_WINDOW(dialog_));
+
// Create a GtkAlignment as dialog contents container.
GtkWidget* contents = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
gtk_alignment_set_padding(GTK_ALIGNMENT(contents),
@@ -185,6 +218,8 @@ void NativeDialogHost::Init() {
gtk_widget_show_all(contents);
contents_view_ = new views::NativeViewHost();
+ contents_view_->set_background(views::Background::CreateSolidBackground(
+ BubbleWindow::kBackgroundColor));
AddChildView(contents_view_);
contents_view_->Attach(contents);
@@ -207,6 +242,12 @@ void NativeDialogHost::Init() {
}
CheckSize();
+
+ if (default_widget)
+ gtk_widget_grab_default(default_widget);
+
+ if (focus_widget)
+ gtk_widget_grab_focus(focus_widget);
}
void NativeDialogHost::CheckSize() {
@@ -224,7 +265,7 @@ void ShowNativeDialog(gfx::NativeWindow parent,
const gfx::Size& min_size) {
NativeDialogHost* native_dialog_host =
new NativeDialogHost(native_dialog, flags, size, min_size);
- views::Window::CreateChromeWindow(parent, gfx::Rect(), native_dialog_host);
+ BubbleWindow::Create(parent, gfx::Rect(), native_dialog_host);
native_dialog_host->window()->Show();
}
diff --git a/chrome/browser/chromeos/native_dialog_window.h b/chrome/browser/chromeos/native_dialog_window.h
index 6792231..47a478b 100644
--- a/chrome/browser/chromeos/native_dialog_window.h
+++ b/chrome/browser/chromeos/native_dialog_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_NATIVE_DIALOG_WINDOW_H_
#define CHROME_BROWSER_CHROMEOS_NATIVE_DIALOG_WINDOW_H_
+#pragma once
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/chromeos/network_list.cc b/chrome/browser/chromeos/network_list.cc
index f92190f..9780642 100644
--- a/chrome/browser/chromeos/network_list.cc
+++ b/chrome/browser/chromeos/network_list.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/chromeos/network_list.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/chromeos/network_list.h b/chrome/browser/chromeos/network_list.h
index f08b23a..5b320fc 100644
--- a/chrome/browser/chromeos/network_list.h
+++ b/chrome/browser/chromeos/network_list.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_NETWORK_LIST_H_
#define CHROME_BROWSER_CHROMEOS_NETWORK_LIST_H_
+#pragma once
#include <string>
#include <vector>
+#include "base/string16.h"
#include "chrome/browser/chromeos/cros/network_library.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/network_message_observer.cc b/chrome/browser/chromeos/network_message_observer.cc
index 192ff28..c87a21b 100644
--- a/chrome/browser/chromeos/network_message_observer.cc
+++ b/chrome/browser/chromeos/network_message_observer.cc
@@ -5,28 +5,125 @@
#include "chrome/browser/chromeos/network_message_observer.h"
#include "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/options/network_config_view.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#include "views/window/dialog_delegate.h"
+#include "views/window/window.h"
namespace chromeos {
NetworkMessageObserver::NetworkMessageObserver(Profile* profile)
- : notification_(profile, "network_connection.chromeos",
+ : initialized_(false),
+ notification_(profile, "network_connection.chromeos",
IDR_NOTIFICATION_NETWORK_FAILED,
l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE)) {
+ NetworkChanged(CrosLibrary::Get()->GetNetworkLibrary());
+ initialized_ = true;
}
NetworkMessageObserver::~NetworkMessageObserver() {
notification_.Hide();
}
+void NetworkMessageObserver::CreateModalPopup(views::WindowDelegate* view) {
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser && browser->type() != Browser::TYPE_NORMAL) {
+ browser = BrowserList::FindBrowserWithType(browser->profile(),
+ Browser::TYPE_NORMAL,
+ true);
+ }
+ DCHECK(browser);
+ views::Window* window = views::Window::CreateChromeWindow(
+ browser->window()->GetNativeHandle(), gfx::Rect(), view);
+ window->SetIsAlwaysOnTop(true);
+ window->Show();
+}
+
void NetworkMessageObserver::NetworkChanged(NetworkLibrary* obj) {
- // TODO(chocobo): Display open networks notification here.
-// notification_.Show(l10n_util::GetStringFUTF16(
-// IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
-// ASCIIToUTF16(network.name())), true);
+ const WifiNetworkVector& wifi_networks = obj->wifi_networks();
+ const CellularNetworkVector& cellular_networks = obj->cellular_networks();
+
+ NetworkConfigView* view = NULL;
+ std::string new_failed_network;
+ // Check to see if we have any newly failed wifi network.
+ for (WifiNetworkVector::const_iterator it = wifi_networks.begin();
+ it < wifi_networks.end(); it++) {
+ const WifiNetwork& wifi = *it;
+ if (wifi.failed()) {
+ ServicePathWifiMap::iterator iter =
+ wifi_networks_.find(wifi.service_path());
+ // If the network did not previously exist, then don't do anything.
+ // For example, if the user travels to a location and finds a service
+ // that has previously failed, we don't want to show a notification.
+ if (iter == wifi_networks_.end())
+ continue;
+
+ const WifiNetwork& wifi_old = iter->second;
+ // If this network was in a failed state previously, then it's not new.
+ if (wifi_old.failed())
+ continue;
+
+ // Display login box again for bad_passphrase and bad_wepkey errors.
+ if (wifi.error() == ERROR_BAD_PASSPHRASE ||
+ wifi.error() == ERROR_BAD_WEPKEY) {
+ // The NetworkConfigView will show the appropriate error message.
+ view = new NetworkConfigView(wifi, true);
+ // 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.
+ break;
+ }
+
+ // If network connection failed, display a notification.
+ // We only do this if we were trying to make a new connection.
+ // So if a previously connected network got disconnected for any reason,
+ // we don't display notification.
+ if (wifi_old.connecting()) {
+ new_failed_network = wifi.name();
+ // Like above, there should only be one newly failed network.
+ break;
+ }
+ }
+
+ // If we find any network connecting, we hide any notifications.
+ if (wifi.connecting()) {
+ notification_.Hide();
+ }
+ }
+
+ // Refresh stored networks.
+ wifi_networks_.clear();
+ for (WifiNetworkVector::const_iterator it = wifi_networks.begin();
+ it < wifi_networks.end(); it++) {
+ const WifiNetwork& wifi = *it;
+ wifi_networks_[wifi.service_path()] = wifi;
+ }
+ cellular_networks_.clear();
+ for (CellularNetworkVector::const_iterator it = cellular_networks.begin();
+ it < cellular_networks.end(); it++) {
+ const CellularNetwork& cellular = *it;
+ cellular_networks_[cellular.service_path()] = cellular;
+ }
+
+ // Show notification if necessary.
+ if (!new_failed_network.empty()) {
+ // Hide if already shown to force show it in case user has closed it.
+ if (notification_.visible())
+ notification_.Hide();
+ notification_.Show(l10n_util::GetStringFUTF16(
+ IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
+ ASCIIToUTF16(new_failed_network)), false, true);
+ }
+
+ // Show login box if necessary.
+ if (view && initialized_)
+ CreateModalPopup(view);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/network_message_observer.h b/chrome/browser/chromeos/network_message_observer.h
index a62e636..554628f 100644
--- a/chrome/browser/chromeos/network_message_observer.h
+++ b/chrome/browser/chromeos/network_message_observer.h
@@ -4,8 +4,9 @@
#ifndef CHROME_BROWSER_CHROMEOS_NETWORK_MESSAGE_OBSERVER_H_
#define CHROME_BROWSER_CHROMEOS_NETWORK_MESSAGE_OBSERVER_H_
+#pragma once
-#include <set>
+#include <map>
#include <string>
#include "base/basictypes.h"
@@ -13,6 +14,9 @@
#include "chrome/browser/chromeos/notifications/system_notification.h"
class Profile;
+namespace views {
+class WindowDelegate;
+}
namespace chromeos {
@@ -24,10 +28,19 @@ class NetworkMessageObserver : public NetworkLibrary::Observer {
explicit NetworkMessageObserver(Profile* profile);
virtual ~NetworkMessageObserver();
+ typedef std::map<std::string, WifiNetwork> ServicePathWifiMap;
+ typedef std::map<std::string, CellularNetwork> ServicePathCellularMap;
private:
+ virtual void CreateModalPopup(views::WindowDelegate* view);
+
+ // NetworkLibrary::Observer implementation.
virtual void NetworkChanged(NetworkLibrary* obj);
- virtual void NetworkTraffic(NetworkLibrary* obj, int traffic_type) {}
+ bool initialized_;
+ // Wifi networks by service path.
+ ServicePathWifiMap wifi_networks_;
+ // Cellular networks by service path.
+ ServicePathCellularMap cellular_networks_;
SystemNotification notification_;
DISALLOW_COPY_AND_ASSIGN(NetworkMessageObserver);
diff --git a/chrome/browser/chromeos/network_state_notifier.h b/chrome/browser/chromeos/network_state_notifier.h
index a64f264..9d49d94 100644
--- a/chrome/browser/chromeos/network_state_notifier.h
+++ b/chrome/browser/chromeos/network_state_notifier.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_NETWORK_STATE_NOTIFIER_H_
#define CHROME_BROWSER_CHROMEOS_NETWORK_STATE_NOTIFIER_H_
+#pragma once
#include "chrome/browser/chromeos/cros/network_library.h"
@@ -60,7 +61,6 @@ class NetworkStateNotifier : public NetworkLibrary::Observer {
// NetworkLibrary::Observer implementation.
virtual void NetworkChanged(NetworkLibrary* cros);
- virtual void NetworkTraffic(NetworkLibrary* cros, int traffic_type) {}
private:
friend struct DefaultSingletonTraits<NetworkStateNotifier>;
diff --git a/chrome/browser/chromeos/network_state_notifier_browsertest.cc b/chrome/browser/chromeos/network_state_notifier_browsertest.cc
index 520dbcf..4833d48 100644
--- a/chrome/browser/chromeos/network_state_notifier_browsertest.cc
+++ b/chrome/browser/chromeos/network_state_notifier_browsertest.cc
@@ -7,11 +7,11 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_network_library.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_registrar.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gmock/include/gmock/gmock.h"
+#include "chrome/common/notification_service.h"
#include "chrome/test/ui_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
@@ -21,15 +21,16 @@ using ::testing::_;
class NetworkStateNotifierTest : public CrosInProcessBrowserTest,
public NotificationObserver {
public:
- NetworkStateNotifierTest() {
+ NetworkStateNotifierTest() : mock_network_library_(NULL) {
}
protected:
virtual void SetUpInProcessBrowserTestFixture() {
- InitStatusAreaMocks();
- SetStatusAreaMocksExpectations();
+ cros_mock_->InitStatusAreaMocks();
+ cros_mock_->SetStatusAreaMocksExpectations();
// Initialize network state notifier.
ASSERT_TRUE(CrosLibrary::Get()->EnsureLoaded());
+ mock_network_library_ = cros_mock_->mock_network_library();
ASSERT_TRUE(mock_network_library_);
EXPECT_CALL(*mock_network_library_, Connected())
.Times(1)
@@ -55,6 +56,7 @@ class NetworkStateNotifierTest : public CrosInProcessBrowserTest,
}
protected:
+ MockNetworkLibrary *mock_network_library_;
NetworkStateDetails::State state_;
};
diff --git a/chrome/browser/chromeos/notifications/balloon_collection_impl.cc b/chrome/browser/chromeos/notifications/balloon_collection_impl.cc
index 31a6ef7..1cc3740 100644
--- a/chrome/browser/chromeos/notifications/balloon_collection_impl.cc
+++ b/chrome/browser/chromeos/notifications/balloon_collection_impl.cc
@@ -61,16 +61,28 @@ void BalloonCollectionImpl::Add(const Notification& notification,
space_change_listener_->OnBalloonSpaceChanged();
}
+bool BalloonCollectionImpl::AddDOMUIMessageCallback(
+ const Notification& notification,
+ const std::string& message,
+ MessageCallback* callback) {
+ Balloons::iterator iter = FindBalloon(notification);
+ if (iter == balloons_.end()) {
+ delete callback;
+ return false;
+ }
+ BalloonViewHost* host =
+ static_cast<BalloonViewHost*>((*iter)->view()->GetHost());
+ return host->AddDOMUIMessageCallback(message, callback);
+}
+
void BalloonCollectionImpl::AddSystemNotification(
const Notification& notification,
Profile* profile,
bool sticky,
bool control) {
- // TODO(oshima): We need to modify BallonCollection/MakeBalloon pattern
- // in order to add unit tests for system notification.
Balloon* new_balloon = new Balloon(notification, profile, this);
new_balloon->set_view(
- new chromeos::BalloonViewImpl(sticky, control));
+ new chromeos::BalloonViewImpl(sticky, control, true));
balloons_.push_back(new_balloon);
new_balloon->Show();
notification_ui_->Add(new_balloon);
@@ -164,7 +176,7 @@ void BalloonCollectionImpl::Shutdown() {
Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification,
Profile* profile) {
Balloon* new_balloon = new Balloon(notification, profile, this);
- new_balloon->set_view(new chromeos::BalloonViewImpl(false, true));
+ new_balloon->set_view(new chromeos::BalloonViewImpl(false, true, false));
return new_balloon;
}
diff --git a/chrome/browser/chromeos/notifications/balloon_collection_impl.h b/chrome/browser/chromeos/notifications/balloon_collection_impl.h
index 7ae7763..79cfe14 100644
--- a/chrome/browser/chromeos/notifications/balloon_collection_impl.h
+++ b/chrome/browser/chromeos/notifications/balloon_collection_impl.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_BALLOON_COLLECTION_IMPL_H_
#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_BALLOON_COLLECTION_IMPL_H_
+#pragma once
-#include <deque>
+#include <string>
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/notifications/balloon_view_host.h"
#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/point.h"
@@ -70,6 +72,15 @@ class BalloonCollectionImpl : public BalloonCollection,
const NotificationSource& source,
const NotificationDetails& details);
+ // Adds a callback for DOMUI message. Returns true if the callback
+ // is succssfully registered, or false otherwise. It fails to add if
+ // there is no notification that matches NotificationDelegate::id(),
+ // or a callback for given message already exists. The callback
+ // object is owned and deleted by callee.
+ bool AddDOMUIMessageCallback(const Notification& notification,
+ const std::string& message,
+ MessageCallback* callback);
+
// Adds new system notification.
// |sticky| is used to indicate that the notification
// is sticky and cannot be dismissed by a user. |controls| turns on/off
diff --git a/chrome/browser/chromeos/notifications/balloon_view.cc b/chrome/browser/chromeos/notifications/balloon_view.cc
index 6ee8043..24a6004 100644
--- a/chrome/browser/chromeos/notifications/balloon_view.cc
+++ b/chrome/browser/chromeos/notifications/balloon_view.cc
@@ -11,6 +11,7 @@
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/notifications/balloon_view_host.h"
#include "chrome/browser/chromeos/notifications/notification_panel.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
@@ -153,12 +154,12 @@ class NotificationControlView : public views::View,
void CreateOptionsMenu() {
if (options_menu_contents_.get())
return;
- const string16 source_label_text = WideToUTF16Hack(l10n_util::GetStringF(
+ const string16 source_label_text = l10n_util::GetStringFUTF16(
IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
- balloon_view_->balloon_->notification().display_source()));
- const string16 label_text = WideToUTF16Hack(l10n_util::GetStringF(
+ balloon_view_->balloon_->notification().display_source());
+ const string16 label_text = l10n_util::GetStringFUTF16(
IDS_NOTIFICATION_BALLOON_REVOKE_MESSAGE,
- balloon_view_->balloon_->notification().display_source()));
+ balloon_view_->balloon_->notification().display_source());
options_menu_contents_.reset(new menus::SimpleMenuModel(this));
// TODO(oshima): Showing the source info in the menu for now.
@@ -181,14 +182,15 @@ class NotificationControlView : public views::View,
DISALLOW_COPY_AND_ASSIGN(NotificationControlView);
};
-BalloonViewImpl::BalloonViewImpl(bool sticky, bool controls)
+BalloonViewImpl::BalloonViewImpl(bool sticky, bool controls, bool dom_ui)
: balloon_(NULL),
html_contents_(NULL),
method_factory_(this),
stale_(false),
sticky_(sticky),
controls_(controls),
- closed_(false) {
+ closed_(false),
+ dom_ui_(dom_ui) {
// This object is not to be deleted by the views hierarchy,
// as it is owned by the balloon.
set_parent_owned(false);
@@ -208,8 +210,9 @@ BalloonViewImpl::~BalloonViewImpl() {
void BalloonViewImpl::Show(Balloon* balloon) {
balloon_ = balloon;
-
html_contents_ = new BalloonViewHost(balloon);
+ if (dom_ui_)
+ html_contents_->EnableDOMUI();
AddChildView(html_contents_->view());
notification_registrar_.Add(this,
NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon));
diff --git a/chrome/browser/chromeos/notifications/balloon_view.h b/chrome/browser/chromeos/notifications/balloon_view.h
index c6032e6..e275915 100644
--- a/chrome/browser/chromeos/notifications/balloon_view.h
+++ b/chrome/browser/chromeos/notifications/balloon_view.h
@@ -6,11 +6,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_BALLOON_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_BALLOON_VIEW_H_
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
#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"
@@ -27,13 +29,13 @@ class TextButton;
class WidgetGtk;
} // namespace views
-class BalloonViewHost;
class Notification;
class NotificationDetails;
class NotificationSource;
namespace chromeos {
+class BalloonViewHost;
class NotificationControlView;
// A balloon view is the UI component for a notification panel.
@@ -41,8 +43,8 @@ class BalloonViewImpl : public BalloonView,
public views::View,
public NotificationObserver {
public:
- BalloonViewImpl(bool sticky, bool controls);
- ~BalloonViewImpl();
+ BalloonViewImpl(bool sticky, bool controls, bool dom_ui);
+ virtual ~BalloonViewImpl();
// views::View interface.
virtual void Layout();
@@ -122,6 +124,8 @@ class BalloonViewImpl : public BalloonView,
bool controls_;
// True if the notification is being closed.
bool closed_;
+ // True to enable domui in the notification.
+ bool dom_ui_;
DISALLOW_COPY_AND_ASSIGN(BalloonViewImpl);
};
diff --git a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc
index cbdf0e4..6824f97 100644
--- a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc
+++ b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc
@@ -4,6 +4,10 @@
#include "chrome/browser/chromeos/notifications/desktop_notifications_unittest.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/render_messages_params.h"
+
namespace chromeos {
// static
@@ -193,7 +197,7 @@ TEST_F(DesktopNotificationsTest, TestManyNotifications) {
// Request lots of identical notifications.
const int kLotsOfToasts = 20;
for (int id = 1; id <= kLotsOfToasts; ++id) {
- SCOPED_TRACE(StringPrintf("Creation loop: id=%d", id));
+ SCOPED_TRACE(base::StringPrintf("Creation loop: id=%d", id));
ViewHostMsg_ShowNotification_Params params = StandardTestNotification();
params.notification_id = id;
EXPECT_TRUE(service_->ShowDesktopNotification(
@@ -217,7 +221,7 @@ TEST_F(DesktopNotificationsTest, TestManyNotifications) {
for (id = 1;
id <= cancelled;
++id) {
- SCOPED_TRACE(StringPrintf("Cancel half of notifications: id=%d", id));
+ SCOPED_TRACE(base::StringPrintf("Cancel half of notifications: id=%d", id));
service_->CancelDesktopNotification(process_id, route_id, id);
MessageLoopForUI::current()->RunAllPending();
expected_log.append("notification closed by script\n");
@@ -228,7 +232,7 @@ TEST_F(DesktopNotificationsTest, TestManyNotifications) {
// Now cancel the rest. It should empty the balloon space.
for (; id <= kLotsOfToasts; ++id) {
- SCOPED_TRACE(StringPrintf("Cancel loop: id=%d", id));
+ SCOPED_TRACE(base::StringPrintf("Cancel loop: id=%d", id));
service_->CancelDesktopNotification(process_id, route_id, id);
expected_log.append("notification closed by script\n");
MessageLoopForUI::current()->RunAllPending();
@@ -243,7 +247,7 @@ TEST_F(DesktopNotificationsTest, TestEarlyDestruction) {
// Create some toasts and then prematurely delete the notification service,
// just to make sure nothing crashes/leaks.
for (int id = 0; id <= 3; ++id) {
- SCOPED_TRACE(StringPrintf("Show Text loop: id=%d", id));
+ SCOPED_TRACE(base::StringPrintf("Show Text loop: id=%d", id));
EXPECT_TRUE(service_->ShowDesktopNotification(
StandardTestNotification(), 0, 0,
diff --git a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h
index b424c67..fedd4f0 100644
--- a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h
+++ b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_DESKTOP_NOTIFICATIONS_UNITTEST_H_
#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_DESKTOP_NOTIFICATIONS_UNITTEST_H_
+#pragma once
#include <set>
#include <string>
diff --git a/chrome/browser/chromeos/notifications/notification_browsertest.cc b/chrome/browser/chromeos/notifications/notification_browsertest.cc
index a1e1152..2d76a3d 100644
--- a/chrome/browser/chromeos/notifications/notification_browsertest.cc
+++ b/chrome/browser/chromeos/notifications/notification_browsertest.cc
@@ -5,6 +5,11 @@
#include "app/x11_util.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h"
@@ -26,6 +31,7 @@ class MockNotificationDelegate : public NotificationDelegate {
virtual void Display() {}
virtual void Error() {}
virtual void Close(bool by_user) {}
+ virtual void Click() {}
virtual std::string id() const { return id_; }
private:
@@ -50,6 +56,10 @@ class NotificationTest : public InProcessBrowserTest,
expected_(PanelController::INITIAL) {
}
+ void HandleDOMUIMessage(const ListValue* value) {
+ MessageLoop::current()->Quit();
+ }
+
protected:
virtual void SetUp() {
// Detect if we're running under ChromeOS WindowManager. See
@@ -249,7 +259,7 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestSystemNotification) {
// Dismiss the notification.
// TODO(oshima): Consider updating API to Remove(NotificationDelegate)
// or Remove(std::string id);
- collection->Remove(Notification(GURL(), GURL(), std::wstring(), string16(),
+ collection->Remove(Notification(GURL(), GURL(), string16(), string16(),
delegate.get()));
ui_test_utils::RunAllPendingInMessageLoop();
@@ -414,7 +424,8 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestCloseOpen) {
EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
}
-IN_PROC_BROWSER_TEST_F(NotificationTest, TestScrollBalloonToVisible) {
+// TODO(oshima): bug chromium-os:7139 Fix this flaky test on ChromeOS.
+IN_PROC_BROWSER_TEST_F(NotificationTest, FLAKY_TestScrollBalloonToVisible) {
BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
NotificationPanel* panel = GetNotificationPanel();
NotificationPanelTester* tester = panel->GetTester();
@@ -426,8 +437,8 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestScrollBalloonToVisible) {
// new notification is always visible
for (int i = 0; i < create_count; i++) {
{
- SCOPED_TRACE(StringPrintf("new n%d", i));
- std::string id = StringPrintf("n%d", i);
+ SCOPED_TRACE(base::StringPrintf("new n%d", i));
+ std::string id = base::StringPrintf("n%d", i);
collection->Add(NewMockNotification(id), profile);
EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
BalloonViewImpl* view =
@@ -436,8 +447,8 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestScrollBalloonToVisible) {
EXPECT_TRUE(tester->IsVisible(view));
}
{
- SCOPED_TRACE(StringPrintf("new s%d", i));
- std::string id = StringPrintf("s%d", i);
+ SCOPED_TRACE(base::StringPrintf("new s%d", i));
+ std::string id = base::StringPrintf("s%d", i);
collection->AddSystemNotification(
NewMockNotification(id), browser()->profile(), true, false);
ui_test_utils::RunAllPendingInMessageLoop();
@@ -450,8 +461,8 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestScrollBalloonToVisible) {
// Update should not change the visibility
for (int i = 0; i < create_count; i++) {
{
- SCOPED_TRACE(StringPrintf("update n%d", i));
- Notification notify = NewMockNotification(StringPrintf("n%d", i));
+ SCOPED_TRACE(base::StringPrintf("update n%d", i));
+ Notification notify = NewMockNotification(base::StringPrintf("n%d", i));
// The last shown notification is sticky, which makes all non sticky
// invisible.
EXPECT_TRUE(collection->UpdateNotification(notify));
@@ -460,8 +471,8 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestScrollBalloonToVisible) {
EXPECT_FALSE(tester->IsVisible(view));
}
{
- SCOPED_TRACE(StringPrintf("update s%d", i));
- Notification notify = NewMockNotification(StringPrintf("s%d", i));
+ SCOPED_TRACE(base::StringPrintf("update s%d", i));
+ Notification notify = NewMockNotification(base::StringPrintf("s%d", i));
BalloonViewImpl* view = tester->GetBalloonView(collection, notify);
bool currently_visible = tester->IsVisible(view);
EXPECT_TRUE(collection->UpdateNotification(notify));
@@ -473,16 +484,16 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestScrollBalloonToVisible) {
// UpdateAndShowNotification makes notification visible
for (int i = 0; i < create_count; i++) {
{
- SCOPED_TRACE(StringPrintf("update and show n%d", i));
- Notification notify = NewMockNotification(StringPrintf("n%d", i));
+ SCOPED_TRACE(base::StringPrintf("update and show n%d", i));
+ Notification notify = NewMockNotification(base::StringPrintf("n%d", i));
EXPECT_TRUE(collection->UpdateAndShowNotification(notify));
ui_test_utils::RunAllPendingInMessageLoop();
BalloonViewImpl* view = tester->GetBalloonView(collection, notify);
EXPECT_TRUE(tester->IsVisible(view));
}
{
- SCOPED_TRACE(StringPrintf("update and show s%d", i));
- Notification notify = NewMockNotification(StringPrintf("s%d", i));
+ SCOPED_TRACE(base::StringPrintf("update and show s%d", i));
+ Notification notify = NewMockNotification(base::StringPrintf("s%d", i));
EXPECT_TRUE(collection->UpdateAndShowNotification(notify));
ui_test_utils::RunAllPendingInMessageLoop();
BalloonViewImpl* view = tester->GetBalloonView(collection, notify);
@@ -546,4 +557,58 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestCloseDismissAllNonSticky) {
EXPECT_EQ(1, tester->GetStickyNotificationCount());
}
+IN_PROC_BROWSER_TEST_F(NotificationTest, TestAddDOMUIMessageCallback) {
+ BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
+ Profile* profile = browser()->profile();
+
+ collection->AddSystemNotification(
+ NewMockNotification("1"), profile, false, false);
+
+ EXPECT_TRUE(collection->AddDOMUIMessageCallback(
+ NewMockNotification("1"),
+ "test",
+ NewCallback(
+ static_cast<NotificationTest*>(this),
+ &NotificationTest::HandleDOMUIMessage)));
+
+ // Adding callback for the same message twice should fail.
+ EXPECT_FALSE(collection->AddDOMUIMessageCallback(
+ NewMockNotification("1"),
+ "test",
+ NewCallback(
+ static_cast<NotificationTest*>(this),
+ &NotificationTest::HandleDOMUIMessage)));
+
+ // Adding callback to nonexistent notification should fail.
+ EXPECT_FALSE(collection->AddDOMUIMessageCallback(
+ NewMockNotification("2"),
+ "test1",
+ NewCallback(
+ static_cast<NotificationTest*>(this),
+ &NotificationTest::HandleDOMUIMessage)));
+}
+
+IN_PROC_BROWSER_TEST_F(NotificationTest, TestDOMUIMessageCallback) {
+ BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
+ Profile* profile = browser()->profile();
+ // a notification that sends 'test' domui message back to chrome.
+ const GURL content_url(
+ "data:text/html;charset=utf-8,"
+ "<html><script>function send() { chrome.send('test', ['']); }</script>"
+ "<body onload='send()'></body></html>");
+ collection->AddSystemNotification(
+ Notification(GURL(), content_url, string16(), string16(),
+ new MockNotificationDelegate("1")),
+ profile,
+ false,
+ false);
+ EXPECT_TRUE(collection->AddDOMUIMessageCallback(
+ NewMockNotification("1"),
+ "test",
+ NewCallback(
+ static_cast<NotificationTest*>(this),
+ &NotificationTest::HandleDOMUIMessage)));
+ MessageLoop::current()->Run();
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/notifications/notification_panel.cc b/chrome/browser/chromeos/notifications/notification_panel.cc
index 0f53f9f..2b48256 100644
--- a/chrome/browser/chromeos/notifications/notification_panel.cc
+++ b/chrome/browser/chromeos/notifications/notification_panel.cc
@@ -10,9 +10,9 @@
#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 "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/notifications/notification_panel.h b/chrome/browser/chromeos/notifications/notification_panel.h
index 7b795e4..96739bc 100644
--- a/chrome/browser/chromeos/notifications/notification_panel.h
+++ b/chrome/browser/chromeos/notifications/notification_panel.h
@@ -6,9 +6,10 @@
#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_NOTIFICATION_PANEL_H_
#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_NOTIFICATION_PANEL_H_
+#pragma once
-#include "base/task.h"
#include "base/scoped_ptr.h"
+#include "base/task.h"
#include "chrome/browser/chromeos/frame/panel_controller.h"
#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/chromeos/notifications/system_notification.cc b/chrome/browser/chromeos/notifications/system_notification.cc
index f2d9d4a..ad54253 100644
--- a/chrome/browser/chromeos/notifications/system_notification.cc
+++ b/chrome/browser/chromeos/notifications/system_notification.cc
@@ -4,11 +4,10 @@
#include "chrome/browser/chromeos/notifications/system_notification.h"
-#include "app/resource_bundle.h"
-#include "base/base64.h"
#include "base/move.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/notifications/system_notification_factory.h"
+#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
@@ -23,15 +22,9 @@ SystemNotification::SystemNotification(Profile* profile, std::string id,
title_(move(title)),
visible_(false),
urgent_(false) {
- // Load resource icon and covert to base64 encoded data url
- scoped_refptr<RefCountedMemory> raw_icon(ResourceBundle::GetSharedInstance().
- LoadDataResourceBytes(icon_resource_id));
- std::string str_gurl;
- std::copy(raw_icon->front(), raw_icon->front() + raw_icon->size(),
- std::back_inserter(str_gurl));
- base::Base64Encode(str_gurl, &str_gurl);
- str_gurl.insert(0, "data:image/png;base64,");
- GURL tmp_gurl(str_gurl);
+ std::string url = dom_ui_util::GetImageDataUrlFromResource(icon_resource_id);
+ DCHECK(!url.empty());
+ GURL tmp_gurl(url);
icon_.Swap(&tmp_gurl);
}
@@ -39,7 +32,9 @@ SystemNotification::~SystemNotification() {
Hide();
}
-void SystemNotification::Show(const string16& message, bool urgent) {
+void SystemNotification::Show(const string16& message,
+ bool urgent,
+ bool sticky) {
Notification notify = SystemNotificationFactory::Create(icon_,
title_, message, delegate_.get());
if (visible_) {
@@ -50,7 +45,8 @@ void SystemNotification::Show(const string16& message, bool urgent) {
collection_->UpdateNotification(notify);
}
} else {
- collection_->AddSystemNotification(notify, profile_, true /* sticky */,
+ collection_->AddSystemNotification(notify, profile_,
+ sticky,
false /* no controls */);
}
visible_ = true;
@@ -59,7 +55,7 @@ void SystemNotification::Show(const string16& message, bool urgent) {
void SystemNotification::Hide() {
if (visible_) {
- collection_->Remove(Notification(GURL(), GURL(), std::wstring(), string16(),
+ collection_->Remove(Notification(GURL(), GURL(), string16(), string16(),
delegate_.get()));
visible_ = false;
diff --git a/chrome/browser/chromeos/notifications/system_notification.h b/chrome/browser/chromeos/notifications/system_notification.h
index ff1efef..a5ac224 100644
--- a/chrome/browser/chromeos/notifications/system_notification.h
+++ b/chrome/browser/chromeos/notifications/system_notification.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_H_
#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_H_
+#pragma once
#include <string>
@@ -29,12 +30,12 @@ class SystemNotification {
SystemNotification(Profile* profile, std::string id, int icon_resource_id,
string16 title);
- ~SystemNotification();
+ virtual ~SystemNotification();
// Show will show or update the message for this notification
// on a transition to urgent, the notification will be shown if it was
// previously hidden or minimized by the user.
- void Show(const string16& message, bool urgent);
+ void Show(const string16& message, bool urgent, bool sticky);
// Hide will dismiss the notification, if the notification is already
// hidden it does nothing
@@ -53,6 +54,7 @@ class SystemNotification {
void Display() {}
void Error() {}
void Close(bool by_user) {}
+ void Click() {}
std::string id() const { return id_; }
private:
@@ -75,4 +77,3 @@ class SystemNotification {
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_H_
-
diff --git a/chrome/browser/chromeos/notifications/system_notification_factory.cc b/chrome/browser/chromeos/notifications/system_notification_factory.cc
index ac01322..51b308f 100644
--- a/chrome/browser/chromeos/notifications/system_notification_factory.cc
+++ b/chrome/browser/chromeos/notifications/system_notification_factory.cc
@@ -15,7 +15,8 @@ Notification SystemNotificationFactory::Create(
NotificationDelegate* delegate) {
string16 content_url = DesktopNotificationService::CreateDataUrl(
icon, title, text, WebKit::WebTextDirectionDefault);
- return Notification(GURL(), GURL(content_url), std::wstring(), string16(),
+ return Notification(GURL(), GURL(content_url), string16(), string16(),
delegate);
}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/notifications/system_notification_factory.h b/chrome/browser/chromeos/notifications/system_notification_factory.h
index 6acd53a..c81b07d 100644
--- a/chrome/browser/chromeos/notifications/system_notification_factory.h
+++ b/chrome/browser/chromeos/notifications/system_notification_factory.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_FACTORY_H_
#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_FACTORY_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/notifications/notification.h"
diff --git a/chrome/browser/chromeos/offline/offline_load_page.cc b/chrome/browser/chromeos/offline/offline_load_page.cc
index 0dc9826..ece8fb6 100644
--- a/chrome/browser/chromeos/offline/offline_load_page.cc
+++ b/chrome/browser/chromeos/offline/offline_load_page.cc
@@ -9,6 +9,8 @@
#include "base/histogram.h"
#include "base/i18n/rtl.h"
#include "base/string_piece.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/chrome_thread.h"
@@ -27,8 +29,8 @@ namespace {
const int kMaxBlankPeriod = 3000;
// A utility function to set the dictionary's value given by |resource_id|.
-void SetString(DictionaryValue* strings, const wchar_t* name, int resource_id) {
- strings->SetString(name, l10n_util::GetString(resource_id));
+void SetString(DictionaryValue* strings, const char* name, int resource_id) {
+ strings->SetString(name, l10n_util::GetStringUTF16(resource_id));
}
} // namespace
@@ -61,27 +63,28 @@ OfflineLoadPage::OfflineLoadPage(TabContents* tab_contents,
std::string OfflineLoadPage::GetHTMLContents() {
DictionaryValue strings;
- SetString(&strings, L"headLine", IDS_OFFLINE_LOAD_HEADLINE);
- SetString(&strings, L"description", IDS_OFFLINE_LOAD_DESCRIPTION);
- SetString(&strings, L"load_button", IDS_OFFLINE_LOAD_BUTTON);
- SetString(&strings, L"back_button", IDS_OFFLINE_BACK_BUTTON);
+ SetString(&strings, "headLine", IDS_OFFLINE_LOAD_HEADLINE);
+ SetString(&strings, "description", IDS_OFFLINE_LOAD_DESCRIPTION);
+ SetString(&strings, "load_button", IDS_OFFLINE_LOAD_BUTTON);
+ SetString(&strings, "back_button", IDS_OFFLINE_BACK_BUTTON);
// TODO(oshima): tab()->GetTitle() always return url. This has to be
// a cached title.
- strings.SetString(L"title", UTF16ToWide(tab()->GetTitle()));
- strings.SetString(L"textdirection", base::i18n::IsRTL() ? L"rtl" : L"ltr");
- strings.SetString(L"display_go_back",
- tab()->controller().CanGoBack() ? L"inline" : L"none");
+ strings.SetString("title", tab()->GetTitle());
+ strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
+ strings.SetString("display_go_back",
+ tab()->controller().CanGoBack() ? "inline" : "none");
int64 time_to_wait = std::max(
static_cast<int64>(0),
kMaxBlankPeriod -
NetworkStateNotifier::GetOfflineDuration().InMilliseconds());
- strings.SetString(L"on_load",
- StringPrintf(L"startTimer(%ld)", time_to_wait));
+ strings.SetString("on_load",
+ WideToUTF16Hack(base::StringPrintf(L"startTimer(%ld)",
+ time_to_wait)));
// TODO(oshima): thumbnail is not working yet. fix this.
const std::string url = "chrome://thumb/" + GetURL().spec();
- strings.SetString(L"thumbnailUrl", "url(" + url + ")");
+ strings.SetString("thumbnailUrl", "url(" + url + ")");
base::StringPiece html(
ResourceBundle::GetSharedInstance().GetRawDataResource(
diff --git a/chrome/browser/chromeos/offline/offline_load_page.h b/chrome/browser/chromeos/offline/offline_load_page.h
index 3363853..b6eb046 100644
--- a/chrome/browser/chromeos/offline/offline_load_page.h
+++ b/chrome/browser/chromeos/offline/offline_load_page.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_OFFLINE_OFFLINE_LOAD_PAGE_H_
#define CHROME_BROWSER_CHROMEOS_OFFLINE_OFFLINE_LOAD_PAGE_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/offline/offline_load_page_unittest.cc b/chrome/browser/chromeos/offline/offline_load_page_unittest.cc
index a619243..9f5fcfb 100644
--- a/chrome/browser/chromeos/offline/offline_load_page_unittest.cc
+++ b/chrome/browser/chromeos/offline/offline_load_page_unittest.cc
@@ -7,7 +7,9 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/offline/offline_load_page.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* kURL1 = "http://www.google.com/";
static const char* kURL2 = "http://www.gmail.com/";
diff --git a/chrome/browser/chromeos/offline/offline_load_service.cc b/chrome/browser/chromeos/offline/offline_load_service.cc
index 63602f5..a000357 100644
--- a/chrome/browser/chromeos/offline/offline_load_service.cc
+++ b/chrome/browser/chromeos/offline/offline_load_service.cc
@@ -4,13 +4,13 @@
#include "chrome/browser/chromeos/offline/offline_load_service.h"
-#include "base/singleton.h"
#include "base/ref_counted.h"
-#include "chrome/common/notification_service.h"
+#include "base/singleton.h"
#include "chrome/browser/chrome_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/browser/tab_contents/navigation_controller.h"
+#include "chrome/common/notification_service.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/offline/offline_load_service.h b/chrome/browser/chromeos/offline/offline_load_service.h
index 119475e..d052d51 100644
--- a/chrome/browser/chromeos/offline/offline_load_service.h
+++ b/chrome/browser/chromeos/offline/offline_load_service.h
@@ -4,13 +4,14 @@
#ifndef CHROME_BROWSER_CHROMEOS_OFFLINE_OFFLINE_LOAD_SERVICE_H_
#define CHROME_BROWSER_CHROMEOS_OFFLINE_OFFLINE_LOAD_SERVICE_H_
+#pragma once
#include <tr1/unordered_set>
#include "base/ref_counted.h"
#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_type.h"
#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_type.h"
class GURL;
class NavigationController;
diff --git a/chrome/browser/chromeos/options/cellular_config_view.cc b/chrome/browser/chromeos/options/cellular_config_view.cc
index be1e761..725efe8 100644
--- a/chrome/browser/chromeos/options/cellular_config_view.cc
+++ b/chrome/browser/chromeos/options/cellular_config_view.cc
@@ -5,23 +5,83 @@
#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_(cellular),
- autoconnect_checkbox_(NULL) {
+ 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();
}
+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();
@@ -36,28 +96,128 @@ void CellularConfigView::Init() {
views::GridLayout* layout = CreatePanelGridLayout(this);
SetLayoutManager(layout);
- int column_view_set_id = 0;
- views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
+ 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::FILL, views::GridLayout::FILL, 1,
+ column_set->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL, 1,
views::GridLayout::USE_PREF, 0, 0);
- layout->StartRow(0, column_view_set_id);
- layout->AddView(new views::Label(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID)));
- views::Label* label = new views::Label(ASCIIToWide(cellular_.name()));
- label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
- layout->AddView(label);
+ layout->StartRow(0, kColumnSetId);
+ layout->AddView(purchase_info_, 2, 1);
+ layout->AddView(purchase_more_button_);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- // Autoconnect checkbox
- autoconnect_checkbox_ = new views::Checkbox(
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT));
- autoconnect_checkbox_->SetChecked(cellular_.auto_connect());
- layout->StartRow(0, column_view_set_id);
- layout->AddView(autoconnect_checkbox_, 2, 1);
+ 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_, &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
index f2ad38e..9120c6d 100644
--- a/chrome/browser/chromeos/options/cellular_config_view.h
+++ b/chrome/browser/chromeos/options/cellular_config_view.h
@@ -1,28 +1,42 @@
-// 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.
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_CELLULAR_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_CELLULAR_CONFIG_VIEW_H_
-
-#include <string>
+#pragma once
#include "chrome/browser/chromeos/cros/network_library.h"
-#include "views/controls/button/checkbox.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 {
+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();
@@ -31,11 +45,20 @@ class CellularConfigView : public views::View {
// Initializes UI.
void Init();
+ // Updates UI.
+ void Update();
+
NetworkConfigView* parent_;
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);
};
diff --git a/chrome/browser/chromeos/options/internet_page_view.cc b/chrome/browser/chromeos/options/internet_page_view.cc
index 71f3e55..a095f3b 100644
--- a/chrome/browser/chromeos/options/internet_page_view.cc
+++ b/chrome/browser/chromeos/options/internet_page_view.cc
@@ -6,11 +6,14 @@
#include <string>
-#include "app/combobox_model.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/string_util.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/browser/chromeos/options/options_window_view.h"
-#include "chrome/browser/chromeos/status/network_menu_button.h"
+#include "chrome/browser/chromeos/status/network_menu.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/native_button.h"
@@ -246,7 +249,7 @@ void WiredSection::InitSection() {
SkBitmap icon = *rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK);
if (!cros->ethernet_connecting() && !cros->ethernet_connected()) {
- icon = NetworkMenuButton::IconForDisplay(icon,
+ icon = NetworkMenu::IconForDisplay(icon,
*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_DISCONNECTED));
}
@@ -317,10 +320,10 @@ void WirelessSection::InitSection() {
for (size_t i = 0; i < wifi_networks_.size(); ++i) {
std::wstring name = ASCIIToWide(wifi_networks_[i].name());
- SkBitmap icon = NetworkMenuButton::IconForNetworkStrength(
+ SkBitmap icon = NetworkMenu::IconForNetworkStrength(
wifi_networks_[i].strength(), true);
if (wifi_networks_[i].encrypted()) {
- icon = NetworkMenuButton::IconForDisplay(icon,
+ icon = NetworkMenu::IconForDisplay(icon,
*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
}
@@ -335,12 +338,12 @@ void WirelessSection::InitSection() {
for (size_t i = 0; i < celluar_networks_.size(); ++i) {
std::wstring name = ASCIIToWide(celluar_networks_[i].name());
- SkBitmap icon = NetworkMenuButton::IconForNetworkStrength(
+ SkBitmap icon = NetworkMenu::IconForNetworkStrength(
celluar_networks_[i].strength(), true);
// TODO(chocobo): Check cellular network 3g/edge.
SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_3G);
// SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_EDGE);
- icon = NetworkMenuButton::IconForDisplay(icon, badge);
+ icon = NetworkMenu::IconForDisplay(icon, badge);
bool connecting = celluar_networks_[i].connecting();
bool connected = celluar_networks_[i].connected();
@@ -446,7 +449,7 @@ void RememberedSection::InitSection() {
SkBitmap icon = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0);
if (wifi_networks_[i].encrypted()) {
- icon = NetworkMenuButton::IconForDisplay(icon,
+ icon = NetworkMenu::IconForDisplay(icon,
*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
}
@@ -463,7 +466,7 @@ void RememberedSection::InitSection() {
// TODO(chocobo): Check cellular network 3g/edge.
SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_3G);
// SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_EDGE);
- icon = NetworkMenuButton::IconForDisplay(icon, badge);
+ icon = NetworkMenu::IconForDisplay(icon, badge);
AddNetwork(i, icon, name, false, std::wstring(), FORGET_BUTTON,
TYPE_CELLULAR);
@@ -474,12 +477,12 @@ void RememberedSection::ButtonClicked(int button, int connection_type, int id) {
if (connection_type == TYPE_CELLULAR) {
if (static_cast<int>(celluar_networks_.size()) > id) {
CrosLibrary::Get()->GetNetworkLibrary()->ForgetWirelessNetwork(
- celluar_networks_[id]);
+ celluar_networks_[id].service_path());
}
} else if (connection_type == TYPE_WIFI) {
if (static_cast<int>(wifi_networks_.size()) > id) {
CrosLibrary::Get()->GetNetworkLibrary()->ForgetWirelessNetwork(
- wifi_networks_[id]);
+ wifi_networks_[id].service_path());
}
} else {
NOTREACHED();
@@ -522,7 +525,7 @@ class InternetPageContentView : public SettingsPageView {
InternetPageContentView::InternetPageContentView(Profile* profile)
: SettingsPageView(profile) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- line_height_ = rb.GetFont(ResourceBundle::BaseFont).height();
+ line_height_ = rb.GetFont(ResourceBundle::BaseFont).GetHeight();
}
void InternetPageContentView::RefreshContents() {
diff --git a/chrome/browser/chromeos/options/internet_page_view.h b/chrome/browser/chromeos/options/internet_page_view.h
index 2b6f9ed..71b7399 100644
--- a/chrome/browser/chromeos/options/internet_page_view.h
+++ b/chrome/browser/chromeos/options/internet_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_INTERNET_PAGE_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_INTERNET_PAGE_VIEW_H_
+#pragma once
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/options/settings_page_view.h"
@@ -25,7 +26,6 @@ class InternetPageView : public SettingsPageView,
// NetworkLibrary::Observer implementation.
virtual void NetworkChanged(NetworkLibrary* obj);
- virtual void NetworkTraffic(NetworkLibrary* obj, int traffic_type) {}
// views::View overrides:
virtual void Layout();
diff --git a/chrome/browser/chromeos/options/ip_config_view.cc b/chrome/browser/chromeos/options/ip_config_view.cc
index 9fb1520..8e596a2 100644
--- a/chrome/browser/chromeos/options/ip_config_view.cc
+++ b/chrome/browser/chromeos/options/ip_config_view.cc
@@ -6,6 +6,7 @@
#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"
diff --git a/chrome/browser/chromeos/options/ip_config_view.h b/chrome/browser/chromeos/options/ip_config_view.h
index f144666..c09fcc3 100644
--- a/chrome/browser/chromeos/options/ip_config_view.h
+++ b/chrome/browser/chromeos/options/ip_config_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_IP_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_IP_CONFIG_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/options/language_chewing_config_view.cc b/chrome/browser/chromeos/options/language_chewing_config_view.cc
index 376be8f..40a597e 100644
--- a/chrome/browser/chromeos/options/language_chewing_config_view.cc
+++ b/chrome/browser/chromeos/options/language_chewing_config_view.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/chromeos/options/language_chewing_config_view.h"
-#include "app/combobox_model.h"
#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
@@ -26,29 +25,34 @@ namespace chromeos {
LanguageChewingConfigView::LanguageChewingConfigView(Profile* profile)
: OptionsPageView(profile), contents_(NULL) {
- for (size_t i = 0; i < kNumChewingBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
chewing_boolean_prefs_[i].Init(
- kChewingBooleanPrefs[i].pref_name, profile->GetPrefs(), this);
+ language_prefs::kChewingBooleanPrefs[i].pref_name,
+ profile->GetPrefs(), this);
chewing_boolean_checkboxes_[i] = NULL;
}
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
ChewingPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
current.multiple_choice_pref.Init(
- kChewingMultipleChoicePrefs[i].pref_name, profile->GetPrefs(), this);
+ language_prefs::kChewingMultipleChoicePrefs[i].pref_name,
+ profile->GetPrefs(), this);
current.combobox_model =
- new LanguageComboboxModel<const char*>(&kChewingMultipleChoicePrefs[i]);
+ new LanguageComboboxModel<const char*>(
+ &language_prefs::kChewingMultipleChoicePrefs[i]);
current.combobox = NULL;
}
hsu_sel_key_type_.multiple_choice_pref.Init(
- kChewingHsuSelKeyType.pref_name, profile->GetPrefs(), this);
+ language_prefs::kChewingHsuSelKeyType.pref_name, profile->GetPrefs(),
+ this);
hsu_sel_key_type_.combobox_model =
- new LanguageComboboxModel<int>(&kChewingHsuSelKeyType);
+ new LanguageComboboxModel<int>(&language_prefs::kChewingHsuSelKeyType);
hsu_sel_key_type_.combobox = NULL;
- for (size_t i = 0; i < kNumChewingIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
chewing_integer_prefs_[i].Init(
- kChewingIntegerPrefs[i].pref_name, profile->GetPrefs(), this);
+ language_prefs::kChewingIntegerPrefs[i].pref_name,
+ profile->GetPrefs(), this);
chewing_integer_sliders_[i] = NULL;
}
}
@@ -60,13 +64,14 @@ void LanguageChewingConfigView::ButtonPressed(
views::Button* sender, const views::Event& event) {
views::Checkbox* checkbox = static_cast<views::Checkbox*>(sender);
const int pref_id = checkbox->tag();
- DCHECK(pref_id >= 0 && pref_id < static_cast<int>(kNumChewingBooleanPrefs));
+ DCHECK(pref_id >= 0 && pref_id < static_cast<int>(
+ language_prefs::kNumChewingBooleanPrefs));
chewing_boolean_prefs_[pref_id].SetValue(checkbox->checked());
}
void LanguageChewingConfigView::ItemChanged(
views::Combobox* sender, int prev_index, int new_index) {
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
ChewingPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
if (current.combobox == sender) {
const std::string config_value =
@@ -88,11 +93,12 @@ void LanguageChewingConfigView::ItemChanged(
void LanguageChewingConfigView::SliderValueChanged(views::Slider* sender) {
size_t pref_id;
- for (pref_id = 0; pref_id < kNumChewingIntegerPrefs; ++pref_id) {
+ for (pref_id = 0; pref_id < language_prefs::kNumChewingIntegerPrefs;
+ ++pref_id) {
if (chewing_integer_sliders_[pref_id] == sender)
break;
}
- DCHECK(pref_id < kNumChewingIntegerPrefs);
+ DCHECK(pref_id < language_prefs::kNumChewingIntegerPrefs);
chewing_integer_prefs_[pref_id].SetValue(sender->value());
}
@@ -145,13 +151,14 @@ void LanguageChewingConfigView::InitControlLayout() {
column_set->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1,
GridLayout::USE_PREF, 0, 0);
- for (size_t i = 0; i < kNumChewingBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
chewing_boolean_checkboxes_[i] = new views::Checkbox(
- l10n_util::GetString(kChewingBooleanPrefs[i].message_id));
+ l10n_util::GetString(
+ language_prefs::kChewingBooleanPrefs[i].message_id));
chewing_boolean_checkboxes_[i]->set_listener(this);
chewing_boolean_checkboxes_[i]->set_tag(i);
}
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
ChewingPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
current.combobox = new LanguageCombobox(current.combobox_model);
current.combobox->set_listener(this);
@@ -160,31 +167,32 @@ void LanguageChewingConfigView::InitControlLayout() {
new LanguageCombobox(hsu_sel_key_type_.combobox_model);
hsu_sel_key_type_.combobox->set_listener(this);
- for (size_t i = 0; i < kNumChewingIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
chewing_integer_sliders_[i] = new views::Slider(
- kChewingIntegerPrefs[i].min_pref_value,
- kChewingIntegerPrefs[i].max_pref_value,
+ language_prefs::kChewingIntegerPrefs[i].min_pref_value,
+ language_prefs::kChewingIntegerPrefs[i].max_pref_value,
1,
static_cast<views::Slider::StyleFlags>(
views::Slider::STYLE_DRAW_VALUE |
views::Slider::STYLE_UPDATE_ON_RELEASE),
this);
}
- for (size_t i = 0; i < kNumChewingBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
layout->StartRow(0, kColumnSetId);
layout->AddView(chewing_boolean_checkboxes_[i]);
}
- for (size_t i = 0; i < kNumChewingIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
layout->StartRow(0, kColumnSetId);
layout->AddView(new views::Label(
- l10n_util::GetString(kChewingIntegerPrefs[i].message_id)));
+ l10n_util::GetString(
+ language_prefs::kChewingIntegerPrefs[i].message_id)));
layout->AddView(chewing_integer_sliders_[i]);
}
NotifyPrefChanged();
// Show the comboboxes.
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
const ChewingPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
layout->StartRow(0, kColumnSetId);
layout->AddView(new views::Label(current.combobox_model->GetLabel()));
@@ -205,15 +213,15 @@ void LanguageChewingConfigView::Observe(NotificationType type,
}
void LanguageChewingConfigView::NotifyPrefChanged() {
- for (size_t i = 0; i < kNumChewingBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
const bool checked = chewing_boolean_prefs_[i].GetValue();
chewing_boolean_checkboxes_[i]->SetChecked(checked);
}
- for (size_t i = 0; i < kNumChewingIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
const int value = chewing_integer_prefs_[i].GetValue();
chewing_integer_sliders_[i]->SetValue(value);
}
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
ChewingPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
const std::string value = current.multiple_choice_pref.GetValue();
for (int i = 0; i < current.combobox_model->num_items(); ++i) {
diff --git a/chrome/browser/chromeos/options/language_chewing_config_view.h b/chrome/browser/chromeos/options/language_chewing_config_view.h
index cdffac4..d7a33cf 100644
--- a/chrome/browser/chromeos/options/language_chewing_config_view.h
+++ b/chrome/browser/chromeos/options/language_chewing_config_view.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CHEWING_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CHEWING_CONFIG_VIEW_H_
+#pragma once
#include <string>
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/combobox/combobox.h"
@@ -69,20 +70,24 @@ class LanguageChewingConfigView : public views::ButtonListener,
// Updates the chewing checkboxes.
void NotifyPrefChanged();
- BooleanPrefMember chewing_boolean_prefs_[kNumChewingBooleanPrefs];
- IntegerPrefMember chewing_integer_prefs_[kNumChewingIntegerPrefs];
+ BooleanPrefMember chewing_boolean_prefs_[
+ language_prefs::kNumChewingBooleanPrefs];
+ IntegerPrefMember chewing_integer_prefs_[
+ language_prefs::kNumChewingIntegerPrefs];
views::View* contents_;
// Checkboxes for Chewing.
- views::Checkbox* chewing_boolean_checkboxes_[kNumChewingBooleanPrefs];
+ views::Checkbox* chewing_boolean_checkboxes_[
+ language_prefs::kNumChewingBooleanPrefs];
- views::Slider* chewing_integer_sliders_[kNumChewingIntegerPrefs];
+ views::Slider* chewing_integer_sliders_[
+ language_prefs::kNumChewingIntegerPrefs];
struct ChewingPrefAndAssociatedCombobox {
StringPrefMember multiple_choice_pref;
LanguageComboboxModel<const char*>* combobox_model;
LanguageCombobox* combobox;
- } prefs_and_comboboxes_[kNumChewingMultipleChoicePrefs];
+ } prefs_and_comboboxes_[language_prefs::kNumChewingMultipleChoicePrefs];
struct HsuSelKeyTypePrefAndAssociatedCombobox {
IntegerPrefMember multiple_choice_pref;
diff --git a/chrome/browser/chromeos/options/language_config_model.cc b/chrome/browser/chromeos/options/language_config_model.cc
index fafa2f6..3502c2f 100644
--- a/chrome/browser/chromeos/options/language_config_model.cc
+++ b/chrome/browser/chromeos/options/language_config_model.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "app/l10n_util.h"
+#include "base/string_split.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
@@ -16,6 +17,7 @@
#include "chrome/browser/chromeos/preferences.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
namespace chromeos {
@@ -30,14 +32,13 @@ int AddLanguageComboboxModel::GetItemCount() {
return get_languages_count() + 1 - ignore_set_.size();
}
-std::wstring AddLanguageComboboxModel::GetItemAt(int index) {
+string16 AddLanguageComboboxModel::GetItemAt(int index) {
// Show "Add language" as the first item.
if (index == 0) {
- return l10n_util::GetString(
+ return l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_LANGUAGE_COMBOBOX);
}
- return input_method::MaybeRewriteLanguageName(
- GetLanguageNameAt(GetLanguageIndex(index)));
+ return WideToUTF16Hack(GetLanguageNameAt(GetLanguageIndex(index)));
}
int AddLanguageComboboxModel::GetLanguageIndex(int index) const {
@@ -213,10 +214,6 @@ void LanguageConfigModel::GetInputMethodIdsFromLanguageCode(
input_method_ids->clear();
input_method::GetInputMethodIdsFromLanguageCode(
language_code, input_method::kAllInputMethods, input_method_ids);
-
- // Reorder the input methods.
- input_method::ReorderInputMethodIdsForLanguageCode(
- language_code, input_method_ids);
}
void LanguageConfigModel::NotifyPrefChanged() {
diff --git a/chrome/browser/chromeos/options/language_config_model.h b/chrome/browser/chromeos/options/language_config_model.h
index 352208c..05a63ac 100644
--- a/chrome/browser/chromeos/options/language_config_model.h
+++ b/chrome/browser/chromeos/options/language_config_model.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CONFIG_MODEL_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CONFIG_MODEL_H_
+#pragma once
-#include <map>
#include <set>
#include <string>
#include <vector>
+#include "base/string16.h"
#include "chrome/browser/language_combobox_model.h"
-#include "chrome/browser/pref_member.h"
-#include "chrome/browser/pref_service.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"
@@ -21,13 +22,13 @@ namespace chromeos {
// The combobox model is used for adding languages in the language config
// view.
-class AddLanguageComboboxModel : public LanguageComboboxModel {
+class AddLanguageComboboxModel : public ::LanguageComboboxModel {
public:
AddLanguageComboboxModel(Profile* profile,
const std::vector<std::string>& locale_codes);
// LanguageComboboxModel overrides.
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
// Converts the given index (index of the items in the combobox) to the
// index of the internal language list. The returned index can be used
diff --git a/chrome/browser/chromeos/options/language_config_model_unittest.cc b/chrome/browser/chromeos/options/language_config_model_unittest.cc
index e9b593d..0d7e12f 100644
--- a/chrome/browser/chromeos/options/language_config_model_unittest.cc
+++ b/chrome/browser/chromeos/options/language_config_model_unittest.cc
@@ -26,18 +26,18 @@ TEST(AddLanguageComboboxModelTest, AddLanguageComboboxModel) {
ASSERT_EQ(4, model.GetItemCount());
// The first item should be "Add language" labe.
- EXPECT_EQ(l10n_util::GetString(
+ EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_LANGUAGES_ADD_LANGUAGE_COMBOBOX),
model.GetItemAt(0));
// Other items should be sorted language display names for UI (hence
// French comes before German). Note that the returned display names
// are followed by their native representations. To simplify matching,
// use StartsWith() here.
- EXPECT_TRUE(StartsWith(model.GetItemAt(1), L"French", true))
+ EXPECT_TRUE(StartsWith(model.GetItemAt(1), ASCIIToUTF16("French"), true))
<< model.GetItemAt(1);
- EXPECT_TRUE(StartsWith(model.GetItemAt(2), L"German", true))
+ EXPECT_TRUE(StartsWith(model.GetItemAt(2), ASCIIToUTF16("German"), true))
<< model.GetItemAt(2);
- EXPECT_TRUE(StartsWith(model.GetItemAt(3), L"Korean", true))
+ EXPECT_TRUE(StartsWith(model.GetItemAt(3), ASCIIToUTF16("Korean"), true))
<< model.GetItemAt(3);
// GetLanguageIndex() returns the given index -1 to offset "Add language".
diff --git a/chrome/browser/chromeos/options/language_config_util.h b/chrome/browser/chromeos/options/language_config_util.h
index cc80ee7..6f262cf 100644
--- a/chrome/browser/chromeos/options/language_config_util.h
+++ b/chrome/browser/chromeos/options/language_config_util.h
@@ -4,7 +4,10 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CONFIG_UTIL_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CONFIG_UTIL_H_
+#pragma once
+#include "app/combobox_model.h"
+#include "base/string16.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "views/controls/combobox/combobox.h"
@@ -15,12 +18,14 @@ template <typename DataType>
class LanguageComboboxModel : public ComboboxModel {
public:
explicit LanguageComboboxModel(
- const LanguageMultipleChoicePreference<DataType>* pref_data)
+ const language_prefs::LanguageMultipleChoicePreference<DataType>*
+ pref_data)
: pref_data_(pref_data), num_items_(0) {
// Check how many items are defined in the |pref_data->values_and_ids|
// array.
for (size_t i = 0;
- i < LanguageMultipleChoicePreference<DataType>::kMaxItems; ++i) {
+ i < language_prefs::LanguageMultipleChoicePreference<DataType>::
+ kMaxItems; ++i) {
if ((pref_data_->values_and_ids)[i].item_message_id == 0) {
break;
}
@@ -34,13 +39,13 @@ class LanguageComboboxModel : public ComboboxModel {
}
// Implements ComboboxModel interface.
- virtual std::wstring GetItemAt(int index) {
+ virtual string16 GetItemAt(int index) {
if (index < 0 || index >= num_items_) {
LOG(ERROR) << "Index is out of bounds: " << index;
- return L"";
+ return string16();
}
const int message_id = (pref_data_->values_and_ids)[index].item_message_id;
- return l10n_util::GetString(message_id);
+ return l10n_util::GetStringUTF16(message_id);
}
// Gets a label for the combobox like "Input mode". This function is NOT part
@@ -65,7 +70,7 @@ class LanguageComboboxModel : public ComboboxModel {
}
private:
- const LanguageMultipleChoicePreference<DataType>* pref_data_;
+ const language_prefs::LanguageMultipleChoicePreference<DataType>* pref_data_;
int num_items_;
DISALLOW_COPY_AND_ASSIGN(LanguageComboboxModel);
diff --git a/chrome/browser/chromeos/options/language_config_view.cc b/chrome/browser/chromeos/options/language_config_view.cc
index d9f482e..1ee7845 100644
--- a/chrome/browser/chromeos/options/language_config_view.cc
+++ b/chrome/browser/chromeos/options/language_config_view.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/chromeos/options/options_window_view.h"
#include "chrome/browser/chromeos/preferences.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/restart_message_box.h"
#include "chrome/common/notification_type.h"
@@ -515,8 +515,7 @@ void LanguageConfigView::AddUiLanguageSection(const std::string& language_code,
g_browser_process->GetApplicationLocale();
const string16 language_name16 = l10n_util::GetDisplayNameForLocale(
language_code, application_locale, true);
- const std::wstring language_name
- = input_method::MaybeRewriteLanguageName(UTF16ToWide(language_name16));
+ const std::wstring language_name = UTF16ToWide(language_name16);
views::Label* language_name_label = new views::Label(language_name);
language_name_label->SetFont(
language_name_label->font().DeriveFont(0, gfx::Font::BOLD));
diff --git a/chrome/browser/chromeos/options/language_config_view.h b/chrome/browser/chromeos/options/language_config_view.h
index bd2b0e3..a7dd980 100644
--- a/chrome/browser/chromeos/options/language_config_view.h
+++ b/chrome/browser/chromeos/options/language_config_view.h
@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_CONFIG_VIEW_H_
+#pragma once
#include <map>
#include <set>
#include <string>
-#include <vector>
#include "app/table_model.h"
#include "chrome/browser/chromeos/options/language_config_model.h"
diff --git a/chrome/browser/chromeos/options/language_hangul_config_view.cc b/chrome/browser/chromeos/options/language_hangul_config_view.cc
index 9158c89..0e8227d 100644
--- a/chrome/browser/chromeos/options/language_hangul_config_view.cc
+++ b/chrome/browser/chromeos/options/language_hangul_config_view.cc
@@ -6,14 +6,15 @@
#include "app/combobox_model.h"
#include "app/l10n_util.h"
+#include "base/string16.h"
#include "base/utf_string_conversions.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#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/common/notification_type.h"
+#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "views/controls/button/checkbox.h"
@@ -28,10 +29,12 @@ namespace chromeos {
class HangulKeyboardComboboxModel : public ComboboxModel {
public:
HangulKeyboardComboboxModel() {
- for (size_t i = 0; i < arraysize(kHangulKeyboardNameIDPairs); ++i) {
+ for (size_t i = 0; i < language_prefs::kNumHangulKeyboardNameIDPairs;
+ ++i) {
layouts_.push_back(std::make_pair(
- l10n_util::GetStringUTF8(kHangulKeyboardNameIDPairs[i].message_id),
- kHangulKeyboardNameIDPairs[i].keyboard_id));
+ l10n_util::GetStringUTF8(
+ language_prefs::kHangulKeyboardNameIDPairs[i].message_id),
+ language_prefs::kHangulKeyboardNameIDPairs[i].keyboard_id));
}
}
@@ -41,12 +44,12 @@ class HangulKeyboardComboboxModel : public ComboboxModel {
}
// Implements ComboboxModel interface.
- virtual std::wstring GetItemAt(int index) {
+ virtual string16 GetItemAt(int index) {
if (index < 0 || index > GetItemCount()) {
LOG(ERROR) << "Index is out of bounds: " << index;
- return L"";
+ return string16();
}
- return UTF8ToWide(layouts_.at(index).first);
+ return UTF8ToUTF16(layouts_.at(index).first);
}
// Gets a keyboard layout ID (e.g. "2", "3f", ..) for an item at zero-origin
diff --git a/chrome/browser/chromeos/options/language_hangul_config_view.h b/chrome/browser/chromeos/options/language_hangul_config_view.h
index 88f3188..58466b0 100644
--- a/chrome/browser/chromeos/options/language_hangul_config_view.h
+++ b/chrome/browser/chromeos/options/language_hangul_config_view.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_HANGUL_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_HANGUL_CONFIG_VIEW_H_
+#pragma once
#include <string>
#include "base/scoped_ptr.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "views/controls/combobox/combobox.h"
#include "views/controls/label.h"
diff --git a/chrome/browser/chromeos/options/language_mozc_config_view.cc b/chrome/browser/chromeos/options/language_mozc_config_view.cc
index a48f5ec..15fbfdf 100644
--- a/chrome/browser/chromeos/options/language_mozc_config_view.cc
+++ b/chrome/browser/chromeos/options/language_mozc_config_view.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/chromeos/options/language_mozc_config_view.h"
-#include "app/combobox_model.h"
#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
@@ -26,7 +25,7 @@ namespace {
enum ButtonTag {
// 0 to kNumMozcBooleanPrefs - 1 are reserved for the checkboxes for integer
// preferences.
- kResetToDefaultsButton = chromeos::kNumMozcBooleanPrefs,
+ kResetToDefaultsButton = chromeos::language_prefs::kNumMozcBooleanPrefs,
};
} // namespace
@@ -36,30 +35,34 @@ LanguageMozcConfigView::LanguageMozcConfigView(Profile* profile)
: OptionsPageView(profile),
contents_(NULL),
reset_to_defaults_button_(NULL) {
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
MozcPrefAndAssociatedCheckbox& current = prefs_and_checkboxes_[i];
current.boolean_pref.Init(
- kMozcBooleanPrefs[i].pref_name, profile->GetPrefs(), this);
+ language_prefs::kMozcBooleanPrefs[i].pref_name, profile->GetPrefs(),
+ this);
current.checkbox = NULL;
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
MozcPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
current.multiple_choice_pref.Init(
- kMozcMultipleChoicePrefs[i].pref_name, profile->GetPrefs(), this);
+ language_prefs::kMozcMultipleChoicePrefs[i].pref_name,
+ profile->GetPrefs(), this);
current.combobox_model =
- new LanguageComboboxModel<const char*>(&kMozcMultipleChoicePrefs[i]);
+ new LanguageComboboxModel<const char*>(
+ &language_prefs::kMozcMultipleChoicePrefs[i]);
current.combobox = NULL;
}
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
MozcPrefAndAssociatedSlider& current = prefs_and_sliders_[i];
current.integer_pref.Init(
- kMozcIntegerPrefs[i].pref_name, profile->GetPrefs(), this);
+ language_prefs::kMozcIntegerPrefs[i].pref_name, profile->GetPrefs(),
+ this);
current.slider = NULL;
}
}
LanguageMozcConfigView::~LanguageMozcConfigView() {
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
delete prefs_and_comboboxes_[i].combobox_model;
}
}
@@ -72,7 +75,8 @@ void LanguageMozcConfigView::ButtonPressed(
return;
}
views::Checkbox* checkbox = static_cast<views::Checkbox*>(sender);
- DCHECK(pref_id >= 0 && pref_id < static_cast<int>(kNumMozcBooleanPrefs));
+ DCHECK(pref_id >= 0 && pref_id < static_cast<int>(
+ language_prefs::kNumMozcBooleanPrefs));
prefs_and_checkboxes_[pref_id].boolean_pref.SetValue(checkbox->checked());
}
@@ -82,7 +86,7 @@ void LanguageMozcConfigView::ItemChanged(
LOG(ERROR) << "Invalid new_index: " << new_index;
return;
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
MozcPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
if (current.combobox == sender) {
const std::string config_value =
@@ -97,11 +101,12 @@ void LanguageMozcConfigView::ItemChanged(
void LanguageMozcConfigView::SliderValueChanged(views::Slider* sender) {
size_t pref_id;
- for (pref_id = 0; pref_id < kNumMozcIntegerPrefs; ++pref_id) {
+ for (pref_id = 0; pref_id < language_prefs::kNumMozcIntegerPrefs;
+ ++pref_id) {
if (prefs_and_sliders_[pref_id].slider == sender)
break;
}
- DCHECK(pref_id < kNumMozcIntegerPrefs);
+ DCHECK(pref_id < language_prefs::kNumMozcIntegerPrefs);
prefs_and_sliders_[pref_id].integer_pref.SetValue(sender->value());
}
@@ -159,23 +164,23 @@ void LanguageMozcConfigView::InitControlLayout() {
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
GridLayout::USE_PREF, 0, 0);
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
MozcPrefAndAssociatedCheckbox& current = prefs_and_checkboxes_[i];
current.checkbox = new views::Checkbox(
- l10n_util::GetString(kMozcBooleanPrefs[i].message_id));
+ l10n_util::GetString(language_prefs::kMozcBooleanPrefs[i].message_id));
current.checkbox->set_listener(this);
current.checkbox->set_tag(i);
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
MozcPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
current.combobox = new LanguageCombobox(current.combobox_model);
current.combobox->set_listener(this);
}
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
MozcPrefAndAssociatedSlider& current = prefs_and_sliders_[i];
current.slider = new views::Slider(
- kMozcIntegerPrefs[i].min_pref_value,
- kMozcIntegerPrefs[i].max_pref_value,
+ language_prefs::kMozcIntegerPrefs[i].min_pref_value,
+ language_prefs::kMozcIntegerPrefs[i].max_pref_value,
1,
static_cast<views::Slider::StyleFlags>(
views::Slider::STYLE_DRAW_VALUE |
@@ -192,23 +197,24 @@ void LanguageMozcConfigView::InitControlLayout() {
layout->AddView(reset_to_defaults_button_);
// Show the checkboxes.
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
const MozcPrefAndAssociatedCheckbox& current = prefs_and_checkboxes_[i];
layout->StartRow(0, kColumnSetId);
layout->AddView(current.checkbox, 3, 1);
}
// Show the comboboxes.
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
const MozcPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
layout->StartRow(0, kColumnSetId);
layout->AddView(new views::Label(current.combobox_model->GetLabel()));
layout->AddView(current.combobox);
}
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
const MozcPrefAndAssociatedSlider& current = prefs_and_sliders_[i];
layout->StartRow(0, kColumnSetId);
layout->AddView(new views::Label(
- l10n_util::GetString(kMozcIntegerPrefs[i].message_id)));
+ l10n_util::GetString(
+ language_prefs::kMozcIntegerPrefs[i].message_id)));
layout->AddView(current.slider);
}
NotifyPrefChanged(); // Sync the slider with current Chrome prefs.
@@ -225,12 +231,12 @@ void LanguageMozcConfigView::Observe(NotificationType type,
void LanguageMozcConfigView::NotifyPrefChanged() {
// Update comboboxes.
// TODO(yusukes): We don't have to update all UI controls.
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
MozcPrefAndAssociatedCheckbox& current = prefs_and_checkboxes_[i];
const bool checked = current.boolean_pref.GetValue();
current.checkbox->SetChecked(checked);
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
MozcPrefAndAssociatedCombobox& current = prefs_and_comboboxes_[i];
const std::string value = current.multiple_choice_pref.GetValue();
for (int i = 0; i < current.combobox_model->num_items(); ++i) {
@@ -240,7 +246,7 @@ void LanguageMozcConfigView::NotifyPrefChanged() {
}
}
}
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
MozcPrefAndAssociatedSlider& current = prefs_and_sliders_[i];
const int value = current.integer_pref.GetValue();
current.slider->SetValue(value);
@@ -248,17 +254,17 @@ void LanguageMozcConfigView::NotifyPrefChanged() {
}
void LanguageMozcConfigView::ResetToDefaults() {
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
prefs_and_checkboxes_[i].boolean_pref.SetValue(
- kMozcBooleanPrefs[i].default_pref_value);
+ language_prefs::kMozcBooleanPrefs[i].default_pref_value);
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
prefs_and_comboboxes_[i].multiple_choice_pref.SetValue(
- kMozcMultipleChoicePrefs[i].default_pref_value);
+ language_prefs::kMozcMultipleChoicePrefs[i].default_pref_value);
}
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
prefs_and_sliders_[i].integer_pref.SetValue(
- kMozcIntegerPrefs[i].default_pref_value);
+ language_prefs::kMozcIntegerPrefs[i].default_pref_value);
}
// Reflect the preference changes to the controls.
NotifyPrefChanged();
diff --git a/chrome/browser/chromeos/options/language_mozc_config_view.h b/chrome/browser/chromeos/options/language_mozc_config_view.h
index 0ee0266..496ec14 100644
--- a/chrome/browser/chromeos/options/language_mozc_config_view.h
+++ b/chrome/browser/chromeos/options/language_mozc_config_view.h
@@ -4,13 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_MOZC_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_MOZC_CONFIG_VIEW_H_
+#pragma once
#include <string>
-#include "base/scoped_ptr.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "views/controls/combobox/combobox.h"
#include "views/controls/label.h"
@@ -83,18 +83,18 @@ class LanguageMozcConfigView : public views::ButtonListener,
struct MozcPrefAndAssociatedCheckbox {
BooleanPrefMember boolean_pref;
views::Checkbox* checkbox;
- } prefs_and_checkboxes_[kNumMozcBooleanPrefs];
+ } prefs_and_checkboxes_[language_prefs::kNumMozcBooleanPrefs];
struct MozcPrefAndAssociatedCombobox {
StringPrefMember multiple_choice_pref;
LanguageComboboxModel<const char*>* combobox_model;
LanguageCombobox* combobox;
- } prefs_and_comboboxes_[kNumMozcMultipleChoicePrefs];
+ } prefs_and_comboboxes_[language_prefs::kNumMozcMultipleChoicePrefs];
struct MozcPrefAndAssociatedSlider {
IntegerPrefMember integer_pref;
views::Slider* slider;
- } prefs_and_sliders_[kNumMozcIntegerPrefs];
+ } prefs_and_sliders_[language_prefs::kNumMozcIntegerPrefs];
DISALLOW_COPY_AND_ASSIGN(LanguageMozcConfigView);
};
diff --git a/chrome/browser/chromeos/options/language_pinyin_config_view.cc b/chrome/browser/chromeos/options/language_pinyin_config_view.cc
index 48d79d7..2290f4e 100644
--- a/chrome/browser/chromeos/options/language_pinyin_config_view.cc
+++ b/chrome/browser/chromeos/options/language_pinyin_config_view.cc
@@ -4,16 +4,15 @@
#include "chrome/browser/chromeos/options/language_pinyin_config_view.h"
-#include "app/combobox_model.h"
#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#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/common/notification_type.h"
+#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "views/controls/button/checkbox.h"
@@ -26,16 +25,19 @@ namespace chromeos {
LanguagePinyinConfigView::LanguagePinyinConfigView(Profile* profile)
: OptionsPageView(profile), contents_(NULL) {
- for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
pinyin_boolean_prefs_[i].Init(
- kPinyinBooleanPrefs[i].pref_name, profile->GetPrefs(), this);
+ language_prefs::kPinyinBooleanPrefs[i].pref_name, profile->GetPrefs(),
+ this);
pinyin_boolean_checkboxes_[i] = NULL;
}
double_pinyin_schema_.multiple_choice_pref.Init(
- kPinyinDoublePinyinSchema.pref_name, profile->GetPrefs(), this);
+ language_prefs::kPinyinDoublePinyinSchema.pref_name,
+ profile->GetPrefs(), this);
double_pinyin_schema_.combobox_model =
- new LanguageComboboxModel<int>(&kPinyinDoublePinyinSchema);
+ new LanguageComboboxModel<int>(
+ &language_prefs::kPinyinDoublePinyinSchema);
double_pinyin_schema_.combobox = NULL;
}
@@ -46,7 +48,8 @@ void LanguagePinyinConfigView::ButtonPressed(
views::Button* sender, const views::Event& event) {
views::Checkbox* checkbox = static_cast<views::Checkbox*>(sender);
const int pref_id = checkbox->tag();
- DCHECK(pref_id >= 0 && pref_id < static_cast<int>(kNumPinyinBooleanPrefs));
+ DCHECK(pref_id >= 0 && pref_id < static_cast<int>(
+ language_prefs::kNumPinyinBooleanPrefs));
pinyin_boolean_prefs_[pref_id].SetValue(checkbox->checked());
}
@@ -110,9 +113,10 @@ void LanguagePinyinConfigView::InitControlLayout() {
column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
GridLayout::USE_PREF, 0, 0);
- for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
pinyin_boolean_checkboxes_[i] = new views::Checkbox(
- l10n_util::GetString(kPinyinBooleanPrefs[i].message_id));
+ l10n_util::GetString(
+ language_prefs::kPinyinBooleanPrefs[i].message_id));
pinyin_boolean_checkboxes_[i]->set_listener(this);
pinyin_boolean_checkboxes_[i]->set_tag(i);
}
@@ -121,7 +125,7 @@ void LanguagePinyinConfigView::InitControlLayout() {
double_pinyin_schema_.combobox->set_listener(this);
NotifyPrefChanged();
- for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
layout->StartRow(0, kColumnSetId);
layout->AddView(pinyin_boolean_checkboxes_[i]);
}
@@ -140,7 +144,7 @@ void LanguagePinyinConfigView::Observe(NotificationType type,
}
void LanguagePinyinConfigView::NotifyPrefChanged() {
- for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
const bool checked = pinyin_boolean_prefs_[i].GetValue();
pinyin_boolean_checkboxes_[i]->SetChecked(checked);
}
diff --git a/chrome/browser/chromeos/options/language_pinyin_config_view.h b/chrome/browser/chromeos/options/language_pinyin_config_view.h
index 9879f28..6d38bd5 100644
--- a/chrome/browser/chromeos/options/language_pinyin_config_view.h
+++ b/chrome/browser/chromeos/options/language_pinyin_config_view.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_PINYIN_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_LANGUAGE_PINYIN_CONFIG_VIEW_H_
+#pragma once
#include <string>
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/combobox/combobox.h"
@@ -64,12 +65,14 @@ class LanguagePinyinConfigView : public views::ButtonListener,
// Updates the pinyin checkboxes.
void NotifyPrefChanged();
- BooleanPrefMember pinyin_boolean_prefs_[kNumPinyinBooleanPrefs];
+ BooleanPrefMember pinyin_boolean_prefs_[
+ language_prefs::kNumPinyinBooleanPrefs];
// TODO(yusukes): Support integer prefs if needed.
views::View* contents_;
// A checkboxes for Pinyin.
- views::Checkbox* pinyin_boolean_checkboxes_[kNumPinyinBooleanPrefs];
+ views::Checkbox* pinyin_boolean_checkboxes_[
+ language_prefs::kNumPinyinBooleanPrefs];
struct DoublePinyinSchemaPrefAndAssociatedCombobox {
IntegerPrefMember multiple_choice_pref;
diff --git a/chrome/browser/chromeos/options/network_config_view.cc b/chrome/browser/chromeos/options/network_config_view.cc
index b139b56..d18006e 100644
--- a/chrome/browser/chromeos/options/network_config_view.cc
+++ b/chrome/browser/chromeos/options/network_config_view.cc
@@ -6,6 +6,7 @@
#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"
@@ -178,7 +179,7 @@ void NetworkConfigView::Init() {
if (flags_ & FLAG_CELLULAR) {
cellularconfig_view_ = new CellularConfigView(this, cellular_);
tabs_->AddTab(
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_NETWORK_CONFIG),
+ l10n_util::GetString(IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USAGE),
cellularconfig_view_);
}
if (flags_ & FLAG_WIFI) {
diff --git a/chrome/browser/chromeos/options/network_config_view.h b/chrome/browser/chromeos/options/network_config_view.h
index 2bdd392..2fda171 100644
--- a/chrome/browser/chromeos/options/network_config_view.h
+++ b/chrome/browser/chromeos/options/network_config_view.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_NETWORK_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_NETWORK_CONFIG_VIEW_H_
+#pragma once
#include <string>
-#include "base/string16.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/window/dialog_delegate.h"
diff --git a/chrome/browser/chromeos/options/options_window_view.cc b/chrome/browser/chromeos/options/options_window_view.cc
index 4535e8b..b9602f2 100644
--- a/chrome/browser/chromeos/options/options_window_view.cc
+++ b/chrome/browser/chromeos/options/options_window_view.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/options_window.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
@@ -15,8 +14,9 @@
#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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/views/accessible_view_helper.h"
#include "chrome/browser/window_sizer.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
@@ -143,6 +143,8 @@ class OptionsWindowView : public views::View,
// The last page the user was on when they opened the Options window.
IntegerPrefMember last_selected_page_;
+ scoped_ptr<AccessibleViewHelper> accessible_view_helper_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(OptionsWindowView);
};
@@ -253,6 +255,9 @@ void OptionsWindowView::Layout() {
tabs_->SetBounds(kDialogPadding, kDialogPadding,
width() - (2 * kDialogPadding),
height() - (2 * kDialogPadding));
+ if (!accessible_view_helper_.get()) {
+ accessible_view_helper_.reset(new AccessibleViewHelper(this, profile_));
+ }
}
gfx::Size OptionsWindowView::GetPreferredSize() {
diff --git a/chrome/browser/chromeos/options/options_window_view.h b/chrome/browser/chromeos/options/options_window_view.h
index a6b31b6..784ec8d 100644
--- a/chrome/browser/chromeos/options/options_window_view.h
+++ b/chrome/browser/chromeos/options/options_window_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_OPTIONS_WINDOW_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_OPTIONS_WINDOW_VIEW_H_
+#pragma once
namespace chromeos {
diff --git a/chrome/browser/chromeos/options/settings_page_view.cc b/chrome/browser/chromeos/options/settings_page_view.cc
index e6afc30..84d9654 100644
--- a/chrome/browser/chromeos/options/settings_page_view.cc
+++ b/chrome/browser/chromeos/options/settings_page_view.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/chromeos/options/settings_page_view.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/string_util.h"
#include "gfx/skia_utils_gtk.h"
#include "views/controls/label.h"
#include "views/fill_layout.h"
diff --git a/chrome/browser/chromeos/options/settings_page_view.h b/chrome/browser/chromeos/options/settings_page_view.h
index 5793980..35e9934 100644
--- a/chrome/browser/chromeos/options/settings_page_view.h
+++ b/chrome/browser/chromeos/options/settings_page_view.h
@@ -4,13 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_SETTINGS_PAGE_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_SETTINGS_PAGE_VIEW_H_
+#pragma once
#include <gtk/gtk.h>
#include "chrome/browser/views/options/options_page_view.h"
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "views/grid_layout.h"
#include "views/standard_layout.h"
diff --git a/chrome/browser/chromeos/options/system_page_view.cc b/chrome/browser/chromeos/options/system_page_view.cc
index f074889..3cd9d40 100644
--- a/chrome/browser/chromeos/options/system_page_view.cc
+++ b/chrome/browser/chromeos/options/system_page_view.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.
@@ -8,13 +8,20 @@
#include <vector>
#include "app/combobox_model.h"
+#include "app/l10n_util.h"
#include "base/stl_util-inl.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/stringprintf.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/cros/system_library.h"
+#include "chrome/browser/chromeos/language_preferences.h"
+#include "chrome/browser/chromeos/options/language_config_util.h"
#include "chrome/browser/chromeos/options/language_config_view.h"
#include "chrome/browser/chromeos/options/options_window_view.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
@@ -121,14 +128,15 @@ class DateTimeSection : public SettingsPageSection,
return static_cast<int>(timezones_.size());
}
- virtual std::wstring GetItemAt(int index) {
+ virtual string16 GetItemAt(int index) {
icu::UnicodeString name;
timezones_[index]->getDisplayName(name);
std::wstring output;
UTF16ToWide(name.getBuffer(), name.length(), &output);
int hour_offset = timezones_[index]->getRawOffset() / 3600000;
- return StringPrintf(hour_offset == 0 ? L"(GMT) " : (hour_offset > 0 ?
- L"(GMT+%d) " : L"(GMT%d) "), hour_offset) + output;
+ return WideToUTF16Hack(
+ base::StringPrintf(hour_offset == 0 ? L"(GMT) " : (hour_offset > 0 ?
+ L"(GMT+%d) " : L"(GMT%d) "), hour_offset) + output);
}
virtual icu::TimeZone* GetTimeZoneAt(int index) {
@@ -211,7 +219,7 @@ class TouchpadSection : public SettingsPageSection,
protected:
// SettingsPageSection overrides:
virtual void InitContents(GridLayout* layout);
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
// The View that contains the contents of the section.
@@ -219,14 +227,10 @@ class TouchpadSection : public SettingsPageSection,
// Controls for this section:
views::Checkbox* enable_tap_to_click_checkbox_;
- views::Checkbox* enable_vert_edge_scroll_checkbox_;
- views::Slider* speed_factor_slider_;
views::Slider* sensitivity_slider_;
// Preferences for this section:
BooleanPrefMember tap_to_click_enabled_;
- BooleanPrefMember vert_edge_scroll_enabled_;
- IntegerPrefMember speed_factor_;
IntegerPrefMember sensitivity_;
DISALLOW_COPY_AND_ASSIGN(TouchpadSection);
@@ -235,8 +239,6 @@ class TouchpadSection : public SettingsPageSection,
TouchpadSection::TouchpadSection(Profile* profile)
: SettingsPageSection(profile, IDS_OPTIONS_SETTINGS_SECTION_TITLE_TOUCHPAD),
enable_tap_to_click_checkbox_(NULL),
- enable_vert_edge_scroll_checkbox_(NULL),
- speed_factor_slider_(NULL),
sensitivity_slider_(NULL) {
}
@@ -249,24 +251,11 @@ void TouchpadSection::ButtonPressed(
UserMetricsAction("Options_TapToClickCheckbox_Disable"),
profile()->GetPrefs());
tap_to_click_enabled_.SetValue(enabled);
- } else if (sender == enable_vert_edge_scroll_checkbox_) {
- bool enabled = enable_vert_edge_scroll_checkbox_->checked();
- UserMetricsRecordAction(enabled ?
- UserMetricsAction("Options_VertEdgeScrollCheckbox_Enable") :
- UserMetricsAction("Options_VertEdgeScrollCheckbox_Disable"),
- profile()->GetPrefs());
- vert_edge_scroll_enabled_.SetValue(enabled);
}
}
void TouchpadSection::SliderValueChanged(views::Slider* sender) {
- if (sender == speed_factor_slider_) {
- double value = speed_factor_slider_->value();
- UserMetricsRecordAction(
- UserMetricsAction("Options_SpeedFactorSlider_Changed"),
- profile()->GetPrefs());
- speed_factor_.SetValue(value);
- } else if (sender == sensitivity_slider_) {
+ if (sender == sensitivity_slider_) {
double value = sensitivity_slider_->value();
UserMetricsRecordAction(
UserMetricsAction("Options_SensitivitySlider_Changed"),
@@ -280,18 +269,8 @@ void TouchpadSection::InitContents(GridLayout* layout) {
IDS_OPTIONS_SETTINGS_TAP_TO_CLICK_ENABLED_DESCRIPTION));
enable_tap_to_click_checkbox_->set_listener(this);
enable_tap_to_click_checkbox_->SetMultiLine(true);
- enable_vert_edge_scroll_checkbox_ = new views::Checkbox(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_VERT_EDGE_SCROLL_ENABLED_DESCRIPTION));
- enable_vert_edge_scroll_checkbox_->set_listener(this);
- enable_vert_edge_scroll_checkbox_->SetMultiLine(true);
- // Create speed factor slider with values between 1 and 10 step 1
- speed_factor_slider_ = new views::Slider(1, 10, 1,
- static_cast<views::Slider::StyleFlags>(
- views::Slider::STYLE_DRAW_VALUE |
- views::Slider::STYLE_UPDATE_ON_RELEASE),
- this);
- // Create sensitivity slider with values between 1 and 10 step 1
- sensitivity_slider_ = new views::Slider(1, 10, 1,
+ // Create sensitivity slider with values between 1 and 5 step 1
+ sensitivity_slider_ = new views::Slider(1, 5, 1,
static_cast<views::Slider::StyleFlags>(
views::Slider::STYLE_DRAW_VALUE |
views::Slider::STYLE_UPDATE_ON_RELEASE),
@@ -302,42 +281,22 @@ void TouchpadSection::InitContents(GridLayout* layout) {
l10n_util::GetString(IDS_OPTIONS_SETTINGS_SENSITIVITY_DESCRIPTION)));
layout->AddView(sensitivity_slider_);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, double_column_view_set_id());
- layout->AddView(new views::Label(
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SPEED_FACTOR_DESCRIPTION)));
- layout->AddView(speed_factor_slider_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, single_column_view_set_id());
layout->AddView(enable_tap_to_click_checkbox_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, single_column_view_set_id());
- layout->AddView(enable_vert_edge_scroll_checkbox_);
layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
// Init member prefs so we can update the controls if prefs change.
tap_to_click_enabled_.Init(prefs::kTapToClickEnabled,
profile()->GetPrefs(), this);
- vert_edge_scroll_enabled_.Init(prefs::kVertEdgeScrollEnabled,
- profile()->GetPrefs(), this);
- speed_factor_.Init(prefs::kTouchpadSpeedFactor,
- profile()->GetPrefs(), this);
sensitivity_.Init(prefs::kTouchpadSensitivity,
profile()->GetPrefs(), this);
}
-void TouchpadSection::NotifyPrefChanged(const std::wstring* pref_name) {
+void TouchpadSection::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kTapToClickEnabled) {
bool enabled = tap_to_click_enabled_.GetValue();
enable_tap_to_click_checkbox_->SetChecked(enabled);
}
- if (!pref_name || *pref_name == prefs::kVertEdgeScrollEnabled) {
- bool enabled = vert_edge_scroll_enabled_.GetValue();
- enable_vert_edge_scroll_checkbox_->SetChecked(enabled);
- }
- if (!pref_name || *pref_name == prefs::kTouchpadSpeedFactor) {
- double value = speed_factor_.GetValue();
- speed_factor_slider_->SetValue(value);
- }
if (!pref_name || *pref_name == prefs::kTouchpadSensitivity) {
double value = sensitivity_.GetValue();
sensitivity_slider_->SetValue(value);
@@ -349,7 +308,8 @@ void TouchpadSection::NotifyPrefChanged(const std::wstring* pref_name) {
// TextInput section for text input settings.
class LanguageSection : public SettingsPageSection,
- public views::ButtonListener {
+ public views::ButtonListener,
+ public views::Combobox::Listener {
public:
explicit LanguageSection(Profile* profile);
virtual ~LanguageSection() {}
@@ -360,28 +320,58 @@ class LanguageSection : public SettingsPageSection,
};
// Overridden from SettingsPageSection:
virtual void InitContents(GridLayout* layout);
+ void NotifyPrefChanged(const std::string* pref_name);
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender,
const views::Event& event);
+ // Overridden from views::Combobox::Listener:
+ virtual void ItemChanged(views::Combobox* sender,
+ int prev_index,
+ int new_index);
+
+ IntegerPrefMember xkb_remap_search_key_pref_;
+ IntegerPrefMember xkb_remap_control_key_pref_;
+ IntegerPrefMember xkb_remap_alt_key_pref_;
+ views::Combobox* xkb_modifier_combobox_;
+ chromeos::LanguageComboboxModel<int> xkb_modifier_combobox_model_;
+
DISALLOW_COPY_AND_ASSIGN(LanguageSection);
};
LanguageSection::LanguageSection(Profile* profile)
: SettingsPageSection(profile,
- IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE) {
+ IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE),
+ xkb_modifier_combobox_(NULL),
+ xkb_modifier_combobox_model_(
+ &language_prefs::kXkbModifierMultipleChoicePrefs) {
+ xkb_remap_search_key_pref_.Init(
+ prefs::kLanguageXkbRemapSearchKeyTo, profile->GetPrefs(), this);
+ xkb_remap_control_key_pref_.Init(
+ prefs::kLanguageXkbRemapControlKeyTo, profile->GetPrefs(), this);
+ xkb_remap_alt_key_pref_.Init(
+ prefs::kLanguageXkbRemapAltKeyTo, profile->GetPrefs(), this);
}
void LanguageSection::InitContents(GridLayout* layout) {
- // Add the customize button.
- layout->StartRow(0, single_column_view_set_id());
+ // Add the customize button and XKB combobox.
+ layout->StartRow(0, double_column_view_set_id());
views::NativeButton* customize_languages_button = new views::NativeButton(
this,
l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE));
customize_languages_button->set_tag(kCustomizeLanguagesButton);
+
+ xkb_modifier_combobox_ = new views::Combobox(&xkb_modifier_combobox_model_);
+ xkb_modifier_combobox_->set_listener(this);
+
+ // Initialize the combobox to what's saved in user preferences. Otherwise,
+ // ItemChanged() will be called with |new_index| == 0.
+ NotifyPrefChanged(NULL);
+
layout->AddView(customize_languages_button, 1, 1,
GridLayout::LEADING, GridLayout::CENTER);
+ layout->AddView(xkb_modifier_combobox_);
layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
}
@@ -392,6 +382,59 @@ void LanguageSection::ButtonPressed(
}
}
+void LanguageSection::ItemChanged(views::Combobox* sender,
+ int prev_index,
+ int new_index) {
+ LOG(INFO) << "Changing XKB modofier pref to " << new_index;
+ switch (new_index) {
+ default:
+ LOG(ERROR) << "Unexpected mapping: " << new_index;
+ /* fall through */
+ case language_prefs::kNoRemap:
+ xkb_remap_search_key_pref_.SetValue(kSearchKey);
+ xkb_remap_control_key_pref_.SetValue(kLeftControlKey);
+ xkb_remap_alt_key_pref_.SetValue(kLeftAltKey);
+ break;
+ case language_prefs::kSwapCtrlAndAlt:
+ xkb_remap_search_key_pref_.SetValue(kSearchKey);
+ xkb_remap_control_key_pref_.SetValue(kLeftAltKey);
+ xkb_remap_alt_key_pref_.SetValue(kLeftControlKey);
+ break;
+ case language_prefs::kSwapSearchAndCtrl:
+ xkb_remap_search_key_pref_.SetValue(kLeftControlKey);
+ xkb_remap_control_key_pref_.SetValue(kSearchKey);
+ xkb_remap_alt_key_pref_.SetValue(kLeftAltKey);
+ break;
+ }
+}
+
+void LanguageSection::NotifyPrefChanged(const std::string* pref_name) {
+ if (!pref_name || (*pref_name == prefs::kLanguageXkbRemapSearchKeyTo ||
+ *pref_name == prefs::kLanguageXkbRemapControlKeyTo ||
+ *pref_name == prefs::kLanguageXkbRemapAltKeyTo)) {
+ const int search_remap = xkb_remap_search_key_pref_.GetValue();
+ const int control_remap = xkb_remap_control_key_pref_.GetValue();
+ const int alt_remap = xkb_remap_alt_key_pref_.GetValue();
+ if ((search_remap == kSearchKey) &&
+ (control_remap == kLeftControlKey) &&
+ (alt_remap == kLeftAltKey)) {
+ xkb_modifier_combobox_->SetSelectedItem(language_prefs::kNoRemap);
+ } else if ((search_remap == kLeftControlKey) &&
+ (control_remap == kSearchKey) &&
+ (alt_remap == kLeftAltKey)) {
+ xkb_modifier_combobox_->SetSelectedItem(
+ language_prefs::kSwapSearchAndCtrl);
+ } else if ((search_remap == kSearchKey) &&
+ (control_remap == kLeftAltKey) &&
+ (alt_remap == kLeftControlKey)) {
+ xkb_modifier_combobox_->SetSelectedItem(language_prefs::kSwapCtrlAndAlt);
+ } else {
+ LOG(ERROR) << "Unexpected mapping. The prefs are updated by DOMUI?";
+ xkb_modifier_combobox_->SetSelectedItem(language_prefs::kNoRemap);
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// AccessibilitySection
@@ -409,7 +452,7 @@ class AccessibilitySection : public SettingsPageSection,
// Overridden from SettingsPageSection:
virtual void InitContents(GridLayout* layout);
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
// The View that contains the contents of the section.
@@ -454,7 +497,7 @@ void AccessibilitySection::ButtonPressed(
}
}
-void AccessibilitySection::NotifyPrefChanged(const std::wstring* pref_name) {
+void AccessibilitySection::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kAccessibilityEnabled) {
bool enabled = accessibility_enabled_.GetValue();
accessibility_checkbox_->SetChecked(enabled);
diff --git a/chrome/browser/chromeos/options/system_page_view.h b/chrome/browser/chromeos/options/system_page_view.h
index c560a61..933ff98 100644
--- a/chrome/browser/chromeos/options/system_page_view.h
+++ b/chrome/browser/chromeos/options/system_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_SYSTEM_PAGE_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_SYSTEM_PAGE_VIEW_H_
+#pragma once
#include "chrome/browser/chromeos/options/settings_page_view.h"
diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc
index 6486672..4df5d39 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view.cc
@@ -87,6 +87,16 @@ void WifiConfigView::ContentsChanged(views::Textfield* sender,
UpdateCanLogin();
}
+bool WifiConfigView::HandleKeystroke(
+ views::Textfield* sender,
+ const views::Textfield::Keystroke& keystroke) {
+ if (sender == passphrase_textfield_ &&
+ keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
+ parent_->GetDialogClientView()->AcceptWindow();
+ }
+ return false;
+}
+
void WifiConfigView::ButtonPressed(views::Button* sender,
const views::Event& event) {
if (sender == passphrase_visible_button_) {
@@ -124,7 +134,7 @@ bool WifiConfigView::Login() {
CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
GetSSID(), GetPassphrase(),
identity_string, certificate_path_,
- autoconnect_checkbox_->checked());
+ autoconnect_checkbox_ ? autoconnect_checkbox_->checked() : true);
} else {
Save();
CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
@@ -139,10 +149,12 @@ bool WifiConfigView::Save() {
if (!other_network_) {
bool changed = false;
- bool auto_connect = autoconnect_checkbox_->checked();
- if (auto_connect != wifi_.auto_connect()) {
- wifi_.set_auto_connect(auto_connect);
- changed = true;
+ 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_) {
@@ -303,15 +315,34 @@ void WifiConfigView::Init() {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
}
+ // If there's an error, add an error message label.
+ // Right now, only displaying bad_passphrase and bad_wepkey errors.
+ if (wifi_.error() == ERROR_BAD_PASSPHRASE ||
+ wifi_.error() == ERROR_BAD_WEPKEY) {
+ layout->StartRow(0, column_view_set_id);
+ layout->SkipColumns(1);
+ int id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE;
+ if (wifi_.error() == ERROR_BAD_WEPKEY)
+ id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_WEPKEY;
+ views::Label* label_error = new views::Label(l10n_util::GetString(id));
+ label_error->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ label_error->SetColor(SK_ColorRED);
+ layout->AddView(label_error);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ }
+
// Autoconnect checkbox
- 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);
+ // Only show if this network is already remembered (a favorite).
+ if (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 18c0f78..43078b7 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.h
+++ b/chrome/browser/chromeos/options/wifi_config_view.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_WIFI_CONFIG_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_OPTIONS_WIFI_CONFIG_VIEW_H_
+#pragma once
#include <string>
-#include "base/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/string16.h"
#include "chrome/browser/chromeos/cros/network_library.h"
@@ -19,6 +19,8 @@
#include "views/controls/textfield/textfield.h"
#include "views/view.h"
+class FilePath;
+
namespace chromeos {
class NetworkConfigView;
@@ -37,9 +39,7 @@ class WifiConfigView : public views::View,
virtual void ContentsChanged(views::Textfield* sender,
const string16& new_contents);
virtual bool HandleKeystroke(views::Textfield* sender,
- const views::Textfield::Keystroke& keystroke) {
- return false;
- }
+ const views::Textfield::Keystroke& keystroke);
// views::ButtonListener
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
diff --git a/chrome/browser/chromeos/options/wifi_config_view_browsertest.cc b/chrome/browser/chromeos/options/wifi_config_view_browsertest.cc
index 07e846e..4c26499 100644
--- a/chrome/browser/chromeos/options/wifi_config_view_browsertest.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view_browsertest.cc
@@ -4,6 +4,8 @@
#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"
@@ -16,11 +18,14 @@ using ::testing::_;
class WifiConfigViewTest : public CrosInProcessBrowserTest {
protected:
+ MockNetworkLibrary *mock_network_library_;
+
WifiConfigViewTest() : CrosInProcessBrowserTest() {}
virtual void SetUpInProcessBrowserTestFixture() {
- InitStatusAreaMocks();
- SetStatusAreaMocksExpectations();
+ cros_mock_->InitStatusAreaMocks();
+ cros_mock_->SetStatusAreaMocksExpectations();
+ mock_network_library_ = cros_mock_->mock_network_library();
}
};
@@ -34,7 +39,10 @@ IN_PROC_BROWSER_TEST_F(WifiConfigViewTest, NoChangeSaveTest) {
// Test that if autoconnect was changed, we call SaveWifiNetwork.
IN_PROC_BROWSER_TEST_F(WifiConfigViewTest, ChangeAutoConnectSaveTest) {
EXPECT_CALL(*mock_network_library_, SaveWifiNetwork(_)).Times(1);
- WifiConfigView* view = new WifiConfigView(NULL, WifiNetwork());
+ WifiNetwork remembered_network = WifiNetwork();
+ remembered_network.set_favorite(true);
+ WifiConfigView* view = new WifiConfigView(NULL, remembered_network);
+ ASSERT_TRUE(view->autoconnect_checkbox_ != NULL);
view->autoconnect_checkbox_->SetChecked(
!view->autoconnect_checkbox_->checked());
view->Save();
diff --git a/chrome/browser/chromeos/panels/panel_scroller.cc b/chrome/browser/chromeos/panels/panel_scroller.cc
index daaa3fc..a568341 100644
--- a/chrome/browser/chromeos/panels/panel_scroller.cc
+++ b/chrome/browser/chromeos/panels/panel_scroller.cc
@@ -8,9 +8,10 @@
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
-#include "gfx/canvas.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/panels/panel_scroller_container.h"
#include "chrome/browser/chromeos/panels/panel_scroller_header.h"
+#include "gfx/canvas.h"
#include "views/widget/widget_gtk.h"
struct PanelScroller::Panel {
diff --git a/chrome/browser/chromeos/panels/panel_scroller.h b/chrome/browser/chromeos/panels/panel_scroller.h
index 51eedff..cc9befb 100644
--- a/chrome/browser/chromeos/panels/panel_scroller.h
+++ b/chrome/browser/chromeos/panels/panel_scroller.h
@@ -1,9 +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.
+// Copyright (c) 2010 The Chromium Authors. All rights 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_PANELS_PANEL_SCROLLER_H_
#define CHROME_BROWSER_CHROMEOS_PANELS_PANEL_SCROLLER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/chromeos/panels/panel_scroller_container.h b/chrome/browser/chromeos/panels/panel_scroller_container.h
index 5007e95..76cca15 100644
--- a/chrome/browser/chromeos/panels/panel_scroller_container.h
+++ b/chrome/browser/chromeos/panels/panel_scroller_container.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef CHROME_BROWSER_CHROMEOS_PANELS_PANEL_SCROLLER_CONTAINER_H_
#define CHROME_BROWSER_CHROMEOS_PANELS_PANEL_SCROLLER_CONTAINER_H_
+#pragma once
#include "base/basictypes.h"
#include "views/view.h"
@@ -34,4 +35,3 @@ class PanelScrollerContainer : public views::View {
};
#endif // CHROME_BROWSER_CHROMEOS_PANELS_PANEL_SCROLLER_CONTAINER_H_
-
diff --git a/chrome/browser/chromeos/panels/panel_scroller_header.h b/chrome/browser/chromeos/panels/panel_scroller_header.h
index 701acb5..fe4d7d4 100644
--- a/chrome/browser/chromeos/panels/panel_scroller_header.h
+++ b/chrome/browser/chromeos/panels/panel_scroller_header.h
@@ -1,11 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef CHROME_BROWSER_CHROMEOS_PANELS_PANEL_SCROLLER_HEADER_H_
#define CHROME_BROWSER_CHROMEOS_PANELS_PANEL_SCROLLER_HEADER_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "base/string16.h"
@@ -18,9 +17,7 @@ class PanelScrollerHeader : public views::View {
explicit PanelScrollerHeader(PanelScroller* scroller);
virtual ~PanelScrollerHeader();
- void set_title(const string16& title) {
- title_ = title;
- }
+ void set_title(const string16& title) { title_ = title; }
// views::View overrides.
virtual bool OnMousePressed(const views::MouseEvent& event);
@@ -39,4 +36,3 @@ class PanelScrollerHeader : public views::View {
};
#endif // CHROME_BROWSER_CHROMEOS_PANELS_PANEL_SCROLLER_HEADER_H_
-
diff --git a/chrome/browser/chromeos/pipe_reader.cc b/chrome/browser/chromeos/pipe_reader.cc
index 2ed5e7c..8664e35 100644
--- a/chrome/browser/chromeos/pipe_reader.cc
+++ b/chrome/browser/chromeos/pipe_reader.cc
@@ -1,13 +1,28 @@
-// 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.
#include "chrome/browser/chromeos/pipe_reader.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "base/file_path.h"
#include "base/scoped_ptr.h"
namespace chromeos {
+PipeReader::PipeReader(const FilePath& pipe_name)
+ : pipe_(NULL),
+ pipe_name_(pipe_name.value()) {
+}
+
+PipeReader::~PipeReader() {
+ if (pipe_)
+ fclose(pipe_);
+}
+
std::string PipeReader::Read(const uint32 bytes_to_read) {
scoped_array<char> buffer(new char[bytes_to_read]);
if (pipe_ || (pipe_ = fopen(pipe_name_.c_str(), "r"))) {
diff --git a/chrome/browser/chromeos/pipe_reader.h b/chrome/browser/chromeos/pipe_reader.h
index d89405d..821fe95 100644
--- a/chrome/browser/chromeos/pipe_reader.h
+++ b/chrome/browser/chromeos/pipe_reader.h
@@ -1,20 +1,19 @@
-// 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.
#ifndef CHROME_BROWSER_CHROMEOS_PIPE_READER_H_
#define CHROME_BROWSER_CHROMEOS_PIPE_READER_H_
+#pragma once
-#include <fcntl.h>
#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
#include <string>
#include "base/basictypes.h"
-#include "base/file_path.h"
+
+class FilePath;
namespace chromeos {
@@ -29,14 +28,8 @@ namespace chromeos {
class PipeReader {
public:
- explicit PipeReader(const FilePath& pipe_name)
- : pipe_(NULL),
- pipe_name_(pipe_name.value()) {
- }
- virtual ~PipeReader() {
- if (pipe_)
- fclose(pipe_);
- }
+ explicit PipeReader(const FilePath& pipe_name);
+ virtual ~PipeReader();
// Reads data from the pipe up until either a '\n' or |bytes_to_read| bytes.
virtual std::string Read(const uint32 bytes_to_read);
diff --git a/chrome/browser/chromeos/pipe_reader_unittest.cc b/chrome/browser/chromeos/pipe_reader_unittest.cc
index e745655..3646b30 100644
--- a/chrome/browser/chromeos/pipe_reader_unittest.cc
+++ b/chrome/browser/chromeos/pipe_reader_unittest.cc
@@ -1,10 +1,13 @@
-// 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.
#include "chrome/browser/chromeos/pipe_reader.h"
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "base/file_path.h"
#include "base/safe_strerror_posix.h"
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 7a993d9..6881ae9 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -1,18 +1,22 @@
-// 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.
#include "chrome/browser/chromeos/preferences.h"
+#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/synaptics_library.h"
+#include "chrome/browser/chromeos/cros/keyboard_library.h"
+#include "chrome/browser/chromeos/cros/touchpad_library.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
-#include "chrome/browser/pref_member.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/extensions/extensions_service.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/common/pref_names.h"
#include "unicode/timezone.h"
@@ -20,76 +24,102 @@
namespace chromeos {
static const char kFallbackInputMethodLocale[] = "en-US";
+static const char kTalkAppExtensionId[] = "ggnioahjipcehijkhpdjekioddnjoben";
+
+Preferences::Preferences(Profile* profile)
+ : profile_(profile) {
+}
// static
void Preferences::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(prefs::kTapToClickEnabled, false);
prefs->RegisterBooleanPref(prefs::kLabsMediaplayerEnabled, false);
prefs->RegisterBooleanPref(prefs::kLabsAdvancedFilesystemEnabled, false);
- prefs->RegisterBooleanPref(prefs::kAccessibilityEnabled, false);
- prefs->RegisterBooleanPref(prefs::kVertEdgeScrollEnabled, false);
- prefs->RegisterIntegerPref(prefs::kTouchpadSpeedFactor, 9);
- prefs->RegisterIntegerPref(prefs::kTouchpadSensitivity, 5);
+ // Check if the accessibility pref is already registered, which can happen
+ // in WizardController::RegisterPrefs. We still want to try to register
+ // the pref here in case of Chrome/Linux with ChromeOS=1.
+ if (prefs->FindPreference(prefs::kAccessibilityEnabled) == NULL) {
+ prefs->RegisterBooleanPref(prefs::kAccessibilityEnabled, false);
+ }
+ prefs->RegisterIntegerPref(prefs::kLabsTalkEnabled, 0);
+ prefs->RegisterIntegerPref(prefs::kTouchpadSensitivity, 3);
prefs->RegisterStringPref(prefs::kLanguageCurrentInputMethod, "");
prefs->RegisterStringPref(prefs::kLanguagePreviousInputMethod, "");
prefs->RegisterStringPref(prefs::kLanguageHotkeyNextEngineInMenu,
- kHotkeyNextEngineInMenu);
+ language_prefs::kHotkeyNextEngineInMenu);
prefs->RegisterStringPref(prefs::kLanguageHotkeyPreviousEngine,
- kHotkeyPreviousEngine);
- prefs->RegisterStringPref(prefs::kLanguagePreferredLanguages, "");
+ language_prefs::kHotkeyPreviousEngine);
+ prefs->RegisterStringPref(prefs::kLanguagePreferredLanguages,
+ kFallbackInputMethodLocale);
prefs->RegisterStringPref(prefs::kLanguagePreloadEngines,
kFallbackInputMethodId); // EN layout
- for (size_t i = 0; i < kNumChewingBooleanPrefs; ++i) {
- prefs->RegisterBooleanPref(kChewingBooleanPrefs[i].pref_name,
- kChewingBooleanPrefs[i].default_pref_value);
+ for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
+ prefs->RegisterBooleanPref(
+ language_prefs::kChewingBooleanPrefs[i].pref_name,
+ language_prefs::kChewingBooleanPrefs[i].default_pref_value);
}
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
prefs->RegisterStringPref(
- kChewingMultipleChoicePrefs[i].pref_name,
- kChewingMultipleChoicePrefs[i].default_pref_value);
+ language_prefs::kChewingMultipleChoicePrefs[i].pref_name,
+ language_prefs::kChewingMultipleChoicePrefs[i].default_pref_value);
}
- prefs->RegisterIntegerPref(kChewingHsuSelKeyType.pref_name,
- kChewingHsuSelKeyType.default_pref_value);
+ prefs->RegisterIntegerPref(
+ language_prefs::kChewingHsuSelKeyType.pref_name,
+ language_prefs::kChewingHsuSelKeyType.default_pref_value);
- for (size_t i = 0; i < kNumChewingIntegerPrefs; ++i) {
- prefs->RegisterIntegerPref(kChewingIntegerPrefs[i].pref_name,
- kChewingIntegerPrefs[i].default_pref_value);
+ for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
+ prefs->RegisterIntegerPref(
+ language_prefs::kChewingIntegerPrefs[i].pref_name,
+ language_prefs::kChewingIntegerPrefs[i].default_pref_value);
}
prefs->RegisterStringPref(
prefs::kLanguageHangulKeyboard,
- kHangulKeyboardNameIDPairs[0].keyboard_id);
- prefs->RegisterStringPref(prefs::kLanguageHangulHanjaKeys, kHangulHanjaKeys);
- for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
- prefs->RegisterBooleanPref(kPinyinBooleanPrefs[i].pref_name,
- kPinyinBooleanPrefs[i].default_pref_value);
- }
- for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
- prefs->RegisterIntegerPref(kPinyinIntegerPrefs[i].pref_name,
- kPinyinIntegerPrefs[i].default_pref_value);
- }
- prefs->RegisterIntegerPref(kPinyinDoublePinyinSchema.pref_name,
- kPinyinDoublePinyinSchema.default_pref_value);
+ language_prefs::kHangulKeyboardNameIDPairs[0].keyboard_id);
+ prefs->RegisterStringPref(prefs::kLanguageHangulHanjaKeys,
+ language_prefs::kHangulHanjaKeys);
+ for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
+ prefs->RegisterBooleanPref(
+ language_prefs::kPinyinBooleanPrefs[i].pref_name,
+ language_prefs::kPinyinBooleanPrefs[i].default_pref_value);
+ }
+ for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) {
+ prefs->RegisterIntegerPref(
+ language_prefs::kPinyinIntegerPrefs[i].pref_name,
+ language_prefs::kPinyinIntegerPrefs[i].default_pref_value);
+ }
+ prefs->RegisterIntegerPref(
+ language_prefs::kPinyinDoublePinyinSchema.pref_name,
+ language_prefs::kPinyinDoublePinyinSchema.default_pref_value);
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
- prefs->RegisterBooleanPref(kMozcBooleanPrefs[i].pref_name,
- kMozcBooleanPrefs[i].default_pref_value);
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
+ prefs->RegisterBooleanPref(
+ language_prefs::kMozcBooleanPrefs[i].pref_name,
+ language_prefs::kMozcBooleanPrefs[i].default_pref_value);
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
prefs->RegisterStringPref(
- kMozcMultipleChoicePrefs[i].pref_name,
- kMozcMultipleChoicePrefs[i].default_pref_value);
- }
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
- prefs->RegisterIntegerPref(kMozcIntegerPrefs[i].pref_name,
- kMozcIntegerPrefs[i].default_pref_value);
- }
+ language_prefs::kMozcMultipleChoicePrefs[i].pref_name,
+ language_prefs::kMozcMultipleChoicePrefs[i].default_pref_value);
+ }
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
+ prefs->RegisterIntegerPref(
+ language_prefs::kMozcIntegerPrefs[i].pref_name,
+ language_prefs::kMozcIntegerPrefs[i].default_pref_value);
+ }
+ prefs->RegisterIntegerPref(prefs::kLanguageXkbRemapSearchKeyTo, kSearchKey);
+ prefs->RegisterIntegerPref(prefs::kLanguageXkbRemapControlKeyTo,
+ kLeftControlKey);
+ prefs->RegisterIntegerPref(prefs::kLanguageXkbRemapAltKeyTo, kLeftAltKey);
+ prefs->RegisterBooleanPref(prefs::kLanguageXkbAutoRepeatEnabled, true);
+ prefs->RegisterIntegerPref(prefs::kLanguageXkbAutoRepeatDelay,
+ language_prefs::kXkbAutoRepeatDelayInMs);
+ prefs->RegisterIntegerPref(prefs::kLanguageXkbAutoRepeatInterval,
+ language_prefs::kXkbAutoRepeatIntervalInMs);
}
void Preferences::Init(PrefService* prefs) {
tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, this);
accessibility_enabled_.Init(prefs::kAccessibilityEnabled, prefs, this);
- vert_edge_scroll_enabled_.Init(prefs::kVertEdgeScrollEnabled, prefs, this);
- speed_factor_.Init(prefs::kTouchpadSpeedFactor, prefs, this);
sensitivity_.Init(prefs::kTouchpadSensitivity, prefs, this);
language_hotkey_next_engine_in_menu_.Init(
prefs::kLanguageHotkeyNextEngineInMenu, prefs, this);
@@ -98,68 +128,59 @@ void Preferences::Init(PrefService* prefs) {
language_preferred_languages_.Init(prefs::kLanguagePreferredLanguages,
prefs, this);
language_preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, this);
- for (size_t i = 0; i < kNumChewingBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
language_chewing_boolean_prefs_[i].Init(
- kChewingBooleanPrefs[i].pref_name, prefs, this);
+ language_prefs::kChewingBooleanPrefs[i].pref_name, prefs, this);
}
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
language_chewing_multiple_choice_prefs_[i].Init(
- kChewingMultipleChoicePrefs[i].pref_name, prefs, this);
+ language_prefs::kChewingMultipleChoicePrefs[i].pref_name, prefs, this);
}
language_chewing_hsu_sel_key_type_.Init(
- kChewingHsuSelKeyType.pref_name, prefs, this);
- for (size_t i = 0; i < kNumChewingIntegerPrefs; ++i) {
+ language_prefs::kChewingHsuSelKeyType.pref_name, prefs, this);
+ for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
language_chewing_integer_prefs_[i].Init(
- kChewingIntegerPrefs[i].pref_name, prefs, this);
+ language_prefs::kChewingIntegerPrefs[i].pref_name, prefs, this);
}
language_hangul_keyboard_.Init(prefs::kLanguageHangulKeyboard, prefs, this);
language_hangul_hanja_keys_.Init(
prefs::kLanguageHangulHanjaKeys, prefs, this);
- for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
language_pinyin_boolean_prefs_[i].Init(
- kPinyinBooleanPrefs[i].pref_name, prefs, this);
+ language_prefs::kPinyinBooleanPrefs[i].pref_name, prefs, this);
}
- for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) {
language_pinyin_int_prefs_[i].Init(
- kPinyinIntegerPrefs[i].pref_name, prefs, this);
+ language_prefs::kPinyinIntegerPrefs[i].pref_name, prefs, this);
}
language_pinyin_double_pinyin_schema_.Init(
- kPinyinDoublePinyinSchema.pref_name, prefs, this);
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
+ language_prefs::kPinyinDoublePinyinSchema.pref_name, prefs, this);
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
language_mozc_boolean_prefs_[i].Init(
- kMozcBooleanPrefs[i].pref_name, prefs, this);
+ language_prefs::kMozcBooleanPrefs[i].pref_name, prefs, this);
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
language_mozc_multiple_choice_prefs_[i].Init(
- kMozcMultipleChoicePrefs[i].pref_name, prefs, this);
+ language_prefs::kMozcMultipleChoicePrefs[i].pref_name, prefs, this);
}
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
language_mozc_integer_prefs_[i].Init(
- kMozcIntegerPrefs[i].pref_name, prefs, this);
- }
+ language_prefs::kMozcIntegerPrefs[i].pref_name, prefs, this);
+ }
+ language_xkb_remap_search_key_to_.Init(
+ prefs::kLanguageXkbRemapSearchKeyTo, prefs, this);
+ language_xkb_remap_control_key_to_.Init(
+ prefs::kLanguageXkbRemapControlKeyTo, prefs, this);
+ language_xkb_remap_alt_key_to_.Init(
+ prefs::kLanguageXkbRemapAltKeyTo, prefs, this);
+ language_xkb_auto_repeat_enabled_.Init(
+ prefs::kLanguageXkbAutoRepeatEnabled, prefs, this);
+ language_xkb_auto_repeat_delay_pref_.Init(
+ prefs::kLanguageXkbAutoRepeatDelay, prefs, this);
+ language_xkb_auto_repeat_interval_pref_.Init(
+ prefs::kLanguageXkbAutoRepeatInterval, prefs, this);
- 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 &&
- !prefs->HasPrefPath(prefs::kLanguagePreloadEngines)) {
- 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 += JoinString(input_method_ids, ',');
- }
- language_preload_engines_.SetValue(preload_engines);
- }
- // Add the UI language to the preferred languages the user first logs in.
- if (!prefs->HasPrefPath(prefs::kLanguagePreferredLanguages)) {
- language_preferred_languages_.SetValue(locale);
- }
+ labs_talk_enabled_.Init(prefs::kLabsTalkEnabled, prefs, this);
// Initialize touchpad settings to what's saved in user preferences.
NotifyPrefChanged(NULL);
@@ -169,29 +190,17 @@ void Preferences::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED)
- NotifyPrefChanged(Details<std::wstring>(details).ptr());
+ NotifyPrefChanged(Details<std::string>(details).ptr());
}
-void Preferences::NotifyPrefChanged(const std::wstring* pref_name) {
+void Preferences::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kTapToClickEnabled) {
- CrosLibrary::Get()->GetSynapticsLibrary()->SetBoolParameter(
- PARAM_BOOL_TAP_TO_CLICK,
+ CrosLibrary::Get()->GetTouchpadLibrary()->SetTapToClick(
tap_to_click_enabled_.GetValue());
}
- if (!pref_name || *pref_name == prefs::kVertEdgeScrollEnabled) {
- CrosLibrary::Get()->GetSynapticsLibrary()->SetBoolParameter(
- PARAM_BOOL_VERTICAL_EDGE_SCROLLING,
- vert_edge_scroll_enabled_.GetValue());
- }
- if (!pref_name || *pref_name == prefs::kTouchpadSpeedFactor) {
- CrosLibrary::Get()->GetSynapticsLibrary()->SetRangeParameter(
- PARAM_RANGE_SPEED_SENSITIVITY,
- speed_factor_.GetValue());
- }
if (!pref_name || *pref_name == prefs::kTouchpadSensitivity) {
- CrosLibrary::Get()->GetSynapticsLibrary()->SetRangeParameter(
- PARAM_RANGE_TOUCH_SENSITIVITY,
- sensitivity_.GetValue());
+ CrosLibrary::Get()->GetTouchpadLibrary()->SetSensitivity(
+ sensitivity_.GetValue());
}
// We don't handle prefs::kLanguageCurrentInputMethod and PreviousInputMethod
@@ -199,14 +208,14 @@ void Preferences::NotifyPrefChanged(const std::wstring* pref_name) {
if (!pref_name || *pref_name == prefs::kLanguageHotkeyNextEngineInMenu) {
SetLanguageConfigStringListAsCSV(
- kHotKeySectionName,
- kNextEngineInMenuConfigName,
+ language_prefs::kHotKeySectionName,
+ language_prefs::kNextEngineInMenuConfigName,
language_hotkey_next_engine_in_menu_.GetValue());
}
if (!pref_name || *pref_name == prefs::kLanguageHotkeyPreviousEngine) {
SetLanguageConfigStringListAsCSV(
- kHotKeySectionName,
- kPreviousEngineConfigName,
+ language_prefs::kHotKeySectionName,
+ language_prefs::kPreviousEngineConfigName,
language_hotkey_previous_engine_.GetValue());
}
if (!pref_name || *pref_name == prefs::kLanguagePreferredLanguages) {
@@ -214,88 +223,126 @@ void Preferences::NotifyPrefChanged(const std::wstring* pref_name) {
// preferencs, we don't need to send this to ibus-daemon.
}
if (!pref_name || *pref_name == prefs::kLanguagePreloadEngines) {
- SetLanguageConfigStringListAsCSV(kGeneralSectionName,
- kPreloadEnginesConfigName,
+ SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName,
+ language_prefs::kPreloadEnginesConfigName,
language_preload_engines_.GetValue());
}
- for (size_t i = 0; i < kNumChewingBooleanPrefs; ++i) {
- if (!pref_name || *pref_name == kChewingBooleanPrefs[i].pref_name) {
- SetLanguageConfigBoolean(kChewingSectionName,
- kChewingBooleanPrefs[i].ibus_config_name,
- language_chewing_boolean_prefs_[i].GetValue());
+ for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kChewingBooleanPrefs[i].pref_name) {
+ SetLanguageConfigBoolean(
+ language_prefs::kChewingSectionName,
+ language_prefs::kChewingBooleanPrefs[i].ibus_config_name,
+ language_chewing_boolean_prefs_[i].GetValue());
}
}
- for (size_t i = 0; i < kNumChewingMultipleChoicePrefs; ++i) {
- if (!pref_name || *pref_name == kChewingMultipleChoicePrefs[i].pref_name) {
+ for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
+ if (!pref_name ||
+ *pref_name ==
+ language_prefs::kChewingMultipleChoicePrefs[i].pref_name) {
SetLanguageConfigString(
- kChewingSectionName,
- kChewingMultipleChoicePrefs[i].ibus_config_name,
+ language_prefs::kChewingSectionName,
+ language_prefs::kChewingMultipleChoicePrefs[i].ibus_config_name,
language_chewing_multiple_choice_prefs_[i].GetValue());
}
}
- if (!pref_name || *pref_name == kChewingHsuSelKeyType.pref_name) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kChewingHsuSelKeyType.pref_name) {
SetLanguageConfigInteger(
- kChewingSectionName,
- kChewingHsuSelKeyType.ibus_config_name,
+ language_prefs::kChewingSectionName,
+ language_prefs::kChewingHsuSelKeyType.ibus_config_name,
language_chewing_hsu_sel_key_type_.GetValue());
}
- for (size_t i = 0; i < kNumChewingIntegerPrefs; ++i) {
- if (!pref_name || *pref_name == kChewingIntegerPrefs[i].pref_name) {
- SetLanguageConfigInteger(kChewingSectionName,
- kChewingIntegerPrefs[i].ibus_config_name,
- language_chewing_integer_prefs_[i].GetValue());
+ for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kChewingIntegerPrefs[i].pref_name) {
+ SetLanguageConfigInteger(
+ language_prefs::kChewingSectionName,
+ language_prefs::kChewingIntegerPrefs[i].ibus_config_name,
+ language_chewing_integer_prefs_[i].GetValue());
}
}
- if (!pref_name || *pref_name == prefs::kLanguageHangulKeyboard) {
- SetLanguageConfigString(kHangulSectionName, kHangulKeyboardConfigName,
+ if (!pref_name ||
+ *pref_name == prefs::kLanguageHangulKeyboard) {
+ SetLanguageConfigString(language_prefs::kHangulSectionName,
+ language_prefs::kHangulKeyboardConfigName,
language_hangul_keyboard_.GetValue());
}
if (!pref_name || *pref_name == prefs::kLanguageHangulHanjaKeys) {
- SetLanguageConfigString(kHangulSectionName, kHangulHanjaKeysConfigName,
+ SetLanguageConfigString(language_prefs::kHangulSectionName,
+ language_prefs::kHangulHanjaKeysConfigName,
language_hangul_hanja_keys_.GetValue());
}
- for (size_t i = 0; i < kNumPinyinBooleanPrefs; ++i) {
- if (!pref_name || *pref_name == kPinyinBooleanPrefs[i].pref_name) {
- SetLanguageConfigBoolean(kPinyinSectionName,
- kPinyinBooleanPrefs[i].ibus_config_name,
- language_pinyin_boolean_prefs_[i].GetValue());
+ for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kPinyinBooleanPrefs[i].pref_name) {
+ SetLanguageConfigBoolean(
+ language_prefs::kPinyinSectionName,
+ language_prefs::kPinyinBooleanPrefs[i].ibus_config_name,
+ language_pinyin_boolean_prefs_[i].GetValue());
}
}
- for (size_t i = 0; i < kNumPinyinIntegerPrefs; ++i) {
- if (!pref_name || *pref_name == kPinyinIntegerPrefs[i].pref_name) {
- SetLanguageConfigInteger(kPinyinSectionName,
- kPinyinIntegerPrefs[i].ibus_config_name,
- language_pinyin_int_prefs_[i].GetValue());
+ for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kPinyinIntegerPrefs[i].pref_name) {
+ SetLanguageConfigInteger(
+ language_prefs::kPinyinSectionName,
+ language_prefs::kPinyinIntegerPrefs[i].ibus_config_name,
+ language_pinyin_int_prefs_[i].GetValue());
}
}
- if (!pref_name || *pref_name == kPinyinDoublePinyinSchema.pref_name) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kPinyinDoublePinyinSchema.pref_name) {
SetLanguageConfigInteger(
- kPinyinSectionName,
- kPinyinDoublePinyinSchema.ibus_config_name,
+ language_prefs::kPinyinSectionName,
+ language_prefs::kPinyinDoublePinyinSchema.ibus_config_name,
language_pinyin_double_pinyin_schema_.GetValue());
}
- for (size_t i = 0; i < kNumMozcBooleanPrefs; ++i) {
- if (!pref_name || *pref_name == kMozcBooleanPrefs[i].pref_name) {
- SetLanguageConfigBoolean(kMozcSectionName,
- kMozcBooleanPrefs[i].ibus_config_name,
- language_mozc_boolean_prefs_[i].GetValue());
+ for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kMozcBooleanPrefs[i].pref_name) {
+ SetLanguageConfigBoolean(
+ language_prefs::kMozcSectionName,
+ language_prefs::kMozcBooleanPrefs[i].ibus_config_name,
+ language_mozc_boolean_prefs_[i].GetValue());
}
}
- for (size_t i = 0; i < kNumMozcMultipleChoicePrefs; ++i) {
- if (!pref_name || *pref_name == kMozcMultipleChoicePrefs[i].pref_name) {
+ for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kMozcMultipleChoicePrefs[i].pref_name) {
SetLanguageConfigString(
- kMozcSectionName,
- kMozcMultipleChoicePrefs[i].ibus_config_name,
+ language_prefs::kMozcSectionName,
+ language_prefs::kMozcMultipleChoicePrefs[i].ibus_config_name,
language_mozc_multiple_choice_prefs_[i].GetValue());
}
}
- for (size_t i = 0; i < kNumMozcIntegerPrefs; ++i) {
- if (!pref_name || *pref_name == kMozcIntegerPrefs[i].pref_name) {
- SetLanguageConfigInteger(kMozcSectionName,
- kMozcIntegerPrefs[i].ibus_config_name,
- language_mozc_integer_prefs_[i].GetValue());
+ for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
+ if (!pref_name ||
+ *pref_name == language_prefs::kMozcIntegerPrefs[i].pref_name) {
+ SetLanguageConfigInteger(
+ language_prefs::kMozcSectionName,
+ language_prefs::kMozcIntegerPrefs[i].ibus_config_name,
+ language_mozc_integer_prefs_[i].GetValue());
}
}
+ if (!pref_name || (*pref_name == prefs::kLanguageXkbRemapSearchKeyTo ||
+ *pref_name == prefs::kLanguageXkbRemapControlKeyTo ||
+ *pref_name == prefs::kLanguageXkbRemapAltKeyTo)) {
+ UpdateModifierKeyMapping();
+ }
+ if (!pref_name || *pref_name == prefs::kLanguageXkbAutoRepeatEnabled) {
+ const bool enabled = language_xkb_auto_repeat_enabled_.GetValue();
+ CrosLibrary::Get()->GetKeyboardLibrary()->SetAutoRepeatEnabled(enabled);
+ }
+ if (!pref_name || ((*pref_name == prefs::kLanguageXkbAutoRepeatDelay) ||
+ (*pref_name == prefs::kLanguageXkbAutoRepeatInterval))) {
+ UpdateAutoRepeatRate();
+ }
+
+ // Listen for explicit changes as ExtensionsService handles startup case.
+ if (pref_name && *pref_name == prefs::kLabsTalkEnabled) {
+ UpdateTalkApp();
+ }
}
void Preferences::SetLanguageConfigBoolean(const char* section,
@@ -355,4 +402,48 @@ void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
SetLanguageConfigStringList(section, name, split_values);
}
+void Preferences::UpdateModifierKeyMapping() {
+ const int search_remap = language_xkb_remap_search_key_to_.GetValue();
+ const int control_remap = language_xkb_remap_control_key_to_.GetValue();
+ const int alt_remap = language_xkb_remap_alt_key_to_.GetValue();
+ if ((search_remap < kNumModifierKeys) && (search_remap >= 0) &&
+ (control_remap < kNumModifierKeys) && (control_remap >= 0) &&
+ (alt_remap < kNumModifierKeys) && (alt_remap >= 0)) {
+ chromeos::ModifierMap modifier_map;
+ modifier_map.push_back(
+ ModifierKeyPair(kSearchKey, ModifierKey(search_remap)));
+ modifier_map.push_back(
+ ModifierKeyPair(kLeftControlKey, ModifierKey(control_remap)));
+ modifier_map.push_back(
+ ModifierKeyPair(kLeftAltKey, ModifierKey(alt_remap)));
+ CrosLibrary::Get()->GetKeyboardLibrary()->RemapModifierKeys(modifier_map);
+ } else {
+ LOG(ERROR) << "Failed to remap modifier keys. Unexpected value(s): "
+ << search_remap << ", " << control_remap << ", " << alt_remap;
+ }
+}
+
+void Preferences::UpdateAutoRepeatRate() {
+ AutoRepeatRate rate;
+ rate.initial_delay_in_ms = language_xkb_auto_repeat_delay_pref_.GetValue();
+ rate.repeat_interval_in_ms =
+ language_xkb_auto_repeat_interval_pref_.GetValue();
+ DCHECK(rate.initial_delay_in_ms > 0);
+ DCHECK(rate.repeat_interval_in_ms > 0);
+ CrosLibrary::Get()->GetKeyboardLibrary()->SetAutoRepeatRate(rate);
+}
+
+void Preferences::UpdateTalkApp() {
+ if (!profile_->GetExtensionsService()->is_ready()) {
+ NOTREACHED() << "Extensions service should be ready";
+ return;
+ }
+
+ if (labs_talk_enabled_.GetValue() == 0) {
+ profile_->GetExtensionsService()->DisableExtension(kTalkAppExtensionId);
+ } else {
+ profile_->GetExtensionsService()->EnableExtension(kTalkAppExtensionId);
+ }
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h
index a9a2250..2226a3a 100644
--- a/chrome/browser/chromeos/preferences.h
+++ b/chrome/browser/chromeos/preferences.h
@@ -4,15 +4,17 @@
#ifndef CHROME_BROWSER_CHROMEOS_PREFERENCES_H_
#define CHROME_BROWSER_CHROMEOS_PREFERENCES_H_
+#pragma once
#include <string>
#include <vector>
#include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/common/notification_observer.h"
class PrefService;
+class Profile;
namespace chromeos {
@@ -22,7 +24,7 @@ namespace chromeos {
// When the preferences change, we change the settings to reflect the new value.
class Preferences : public NotificationObserver {
public:
- Preferences() {}
+ explicit Preferences(Profile* profile);
virtual ~Preferences() {}
// This method will register the prefs associated with Chrome OS settings.
@@ -36,13 +38,12 @@ class Preferences : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details);
- protected:
+ private:
// This will set the OS settings when the preference changes.
// If this method is called with NULL, it will set all OS settings to what's
// stored in the preferences.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ void NotifyPrefChanged(const std::string* pref_name);
- private:
// Writes boolean |value| to the input method (IBus) configuration daemon.
// |section| (e.g. "general") and |name| (e.g. "use_global_engine") should
// not be NULL.
@@ -74,6 +75,19 @@ class Preferences : public NotificationObserver {
const char* name,
const std::string& value);
+ // Updates the mapping of modifier keys following current prefs values.
+ void UpdateModifierKeyMapping();
+
+ // Updates the initial key repeat delay and key repeat interval following
+ // current prefs values. We set the delay and interval at once since an
+ // underlying XKB API requires it.
+ void UpdateAutoRepeatRate();
+
+ // Updates whether the Talk app is enabled.
+ void UpdateTalkApp();
+
+ Profile* profile_;
+
BooleanPrefMember tap_to_click_enabled_;
BooleanPrefMember vert_edge_scroll_enabled_;
BooleanPrefMember accessibility_enabled_;
@@ -85,20 +99,35 @@ class Preferences : public NotificationObserver {
StringPrefMember language_hotkey_previous_engine_;
StringPrefMember language_preferred_languages_;
StringPrefMember language_preload_engines_;
- BooleanPrefMember language_chewing_boolean_prefs_[kNumChewingBooleanPrefs];
+ BooleanPrefMember language_chewing_boolean_prefs_[
+ language_prefs::kNumChewingBooleanPrefs];
StringPrefMember language_chewing_multiple_choice_prefs_[
- kNumChewingMultipleChoicePrefs];
+ language_prefs::kNumChewingMultipleChoicePrefs];
IntegerPrefMember language_chewing_hsu_sel_key_type_;
- IntegerPrefMember language_chewing_integer_prefs_[kNumChewingIntegerPrefs];
+ IntegerPrefMember language_chewing_integer_prefs_[
+ language_prefs::kNumChewingIntegerPrefs];
StringPrefMember language_hangul_keyboard_;
StringPrefMember language_hangul_hanja_keys_;
- BooleanPrefMember language_pinyin_boolean_prefs_[kNumPinyinBooleanPrefs];
- IntegerPrefMember language_pinyin_int_prefs_[kNumPinyinIntegerPrefs];
+ BooleanPrefMember language_pinyin_boolean_prefs_[
+ language_prefs::kNumPinyinBooleanPrefs];
+ IntegerPrefMember language_pinyin_int_prefs_[
+ language_prefs::kNumPinyinIntegerPrefs];
IntegerPrefMember language_pinyin_double_pinyin_schema_;
- BooleanPrefMember language_mozc_boolean_prefs_[kNumMozcBooleanPrefs];
+ BooleanPrefMember language_mozc_boolean_prefs_[
+ language_prefs::kNumMozcBooleanPrefs];
StringPrefMember language_mozc_multiple_choice_prefs_[
- kNumMozcMultipleChoicePrefs];
- IntegerPrefMember language_mozc_integer_prefs_[kNumMozcIntegerPrefs];
+ language_prefs::kNumMozcMultipleChoicePrefs];
+ IntegerPrefMember language_mozc_integer_prefs_[
+ language_prefs::kNumMozcIntegerPrefs];
+ IntegerPrefMember language_xkb_remap_search_key_to_;
+ IntegerPrefMember language_xkb_remap_control_key_to_;
+ IntegerPrefMember language_xkb_remap_alt_key_to_;
+ BooleanPrefMember language_xkb_auto_repeat_enabled_;
+ IntegerPrefMember language_xkb_auto_repeat_delay_pref_;
+ IntegerPrefMember language_xkb_auto_repeat_interval_pref_;
+
+ // Labs preferences.
+ IntegerPrefMember labs_talk_enabled_;
DISALLOW_COPY_AND_ASSIGN(Preferences);
};
diff --git a/chrome/browser/chromeos/pulse_audio_mixer.cc b/chrome/browser/chromeos/pulse_audio_mixer.cc
index a091c8c..7cc4d3e 100644
--- a/chrome/browser/chromeos/pulse_audio_mixer.cc
+++ b/chrome/browser/chromeos/pulse_audio_mixer.cc
@@ -21,8 +21,6 @@ namespace chromeos {
// synchronously get the value back.
//
// TODO(davej): Serialize volume/mute to preserve settings when restarting?
-// TODO(davej): Check if we need some thread safety mechanism (will someone be
-// calling GetVolume while another process is calling SetVolume?)
namespace {
@@ -30,14 +28,15 @@ const int kInvalidDeviceId = -1;
// Used for passing custom data to the PulseAudio callbacks.
struct CallbackWrapper {
- pa_threaded_mainloop* mainloop;
- void* data;
+ PulseAudioMixer* instance;
+ bool done;
+ void* userdata;
};
} // namespace
// AudioInfo contains all the values we care about when getting info for a
-// Sink (output device) used by GetAudioInfo()
+// Sink (output device) used by GetAudioInfo().
struct PulseAudioMixer::AudioInfo {
pa_cvolume cvolume;
bool muted;
@@ -46,6 +45,8 @@ struct PulseAudioMixer::AudioInfo {
PulseAudioMixer::PulseAudioMixer()
: device_id_(kInvalidDeviceId),
last_channels_(0),
+ mainloop_lock_count_(0),
+ mixer_state_lock_(),
mixer_state_(UNINITIALIZED),
pa_context_(NULL),
pa_mainloop_(NULL),
@@ -55,48 +56,48 @@ PulseAudioMixer::PulseAudioMixer()
PulseAudioMixer::~PulseAudioMixer() {
PulseAudioFree();
thread_->Stop();
+ thread_.reset();
}
bool PulseAudioMixer::Init(InitDoneCallback* callback) {
- // Just start up worker thread, then post the task of starting up, which can
- // block for 200-500ms, so best not to do it on this thread.
- if (mixer_state_ != UNINITIALIZED)
+ if (!InitThread())
return false;
- mixer_state_ = INITIALIZING;
- if (thread_ == NULL) {
- thread_.reset(new base::Thread("PulseAudioMixer"));
- if (!thread_->Start()) {
- thread_.reset();
- return false;
- }
- }
+ // Post the task of starting up, which can block for 200-500ms,
+ // so best not to do it on the caller's thread.
thread_->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &PulseAudioMixer::DoInit,
- callback));
+ NewRunnableMethod(this, &PulseAudioMixer::DoInit, callback));
return true;
}
+bool PulseAudioMixer::InitSync() {
+ if (!InitThread())
+ return false;
+ return PulseAudioInit();
+}
+
double PulseAudioMixer::GetVolumeDb() const {
- if (!PulseAudioValid())
- return pa_sw_volume_to_dB(0); // this returns -inf
+ if (!MainloopLockIfReady())
+ return pa_sw_volume_to_dB(0); // this returns -inf.
AudioInfo data;
GetAudioInfo(&data);
+ MainloopUnlock();
return pa_sw_volume_to_dB(data.cvolume.values[0]);
}
-void PulseAudioMixer::GetVolumeDbAsync(GetVolumeCallback* callback,
+bool PulseAudioMixer::GetVolumeDbAsync(GetVolumeCallback* callback,
void* user) {
- if (!PulseAudioValid())
- return;
+ if (CheckState() != READY)
+ return false;
thread_->message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(this,
&PulseAudioMixer::DoGetVolume,
callback, user));
+ return true;
}
void PulseAudioMixer::SetVolumeDb(double vol_db) {
- if (!PulseAudioValid())
+ if (!MainloopLockIfReady())
return;
// last_channels_ determines the number of channels on the main output device,
@@ -110,40 +111,38 @@ void PulseAudioMixer::SetVolumeDb(double vol_db) {
pa_operation* pa_op;
pa_cvolume cvolume;
pa_cvolume_set(&cvolume, last_channels_, pa_sw_volume_from_dB(vol_db));
- pa_threaded_mainloop_lock(pa_mainloop_);
pa_op = pa_context_set_sink_volume_by_index(pa_context_, device_id_,
&cvolume, NULL, NULL);
pa_operation_unref(pa_op);
- pa_threaded_mainloop_unlock(pa_mainloop_);
+ MainloopUnlock();
}
bool PulseAudioMixer::IsMute() const {
- if (!PulseAudioValid())
+ if (!MainloopLockIfReady())
return false;
AudioInfo data;
GetAudioInfo(&data);
+ MainloopUnlock();
return data.muted;
}
void PulseAudioMixer::SetMute(bool mute) {
- if (!PulseAudioValid())
+ if (!MainloopLockIfReady())
return;
pa_operation* pa_op;
- pa_threaded_mainloop_lock(pa_mainloop_);
pa_op = pa_context_set_sink_mute_by_index(pa_context_, device_id_,
mute ? 1 : 0, NULL, NULL);
pa_operation_unref(pa_op);
- pa_threaded_mainloop_unlock(pa_mainloop_);
+ MainloopUnlock();
}
-bool PulseAudioMixer::IsValid() const {
- if (mixer_state_ == READY)
- return true;
- if (!pa_context_)
- return false;
- if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY)
- return false;
- return true;
+PulseAudioMixer::State PulseAudioMixer::CheckState() const {
+ AutoLock lock(mixer_state_lock_);
+ // If we think it's ready, verify it is actually so.
+ if ((mixer_state_ == READY) &&
+ (pa_context_get_state(pa_context_) != PA_CONTEXT_READY))
+ mixer_state_ = IN_ERROR;
+ return mixer_state_;
}
////////////////////////////////////////////////////////////////////////////////
@@ -161,17 +160,23 @@ void PulseAudioMixer::DoGetVolume(GetVolumeCallback* callback,
delete callback;
}
-struct ConnectToPulseCallbackData {
- PulseAudioMixer* instance;
- bool connect_done;
-};
+bool PulseAudioMixer::InitThread() {
+ if (thread_ == NULL) {
+ thread_.reset(new base::Thread("PulseAudioMixer"));
+ if (!thread_->Start()) {
+ thread_.reset();
+ return false;
+ }
+ }
+ return true;
+}
// static
void PulseAudioMixer::ConnectToPulseCallbackThunk(
pa_context* context, void* userdata) {
- ConnectToPulseCallbackData* data =
- static_cast<ConnectToPulseCallbackData*>(userdata);
- data->instance->OnConnectToPulseCallback(context, &data->connect_done);
+ CallbackWrapper* data =
+ static_cast<CallbackWrapper*>(userdata);
+ data->instance->OnConnectToPulseCallback(context, &data->done);
}
void PulseAudioMixer::OnConnectToPulseCallback(
@@ -182,13 +187,20 @@ void PulseAudioMixer::OnConnectToPulseCallback(
state == PA_CONTEXT_TERMINATED) {
// Connection process has reached a terminal state. Wake PulseAudioInit().
*connect_done = true;
- pa_threaded_mainloop_signal(pa_mainloop_, 0);
+ MainloopSignal();
}
}
bool PulseAudioMixer::PulseAudioInit() {
pa_context_state_t state = PA_CONTEXT_FAILED;
+ {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != UNINITIALIZED)
+ return false;
+ mixer_state_ = INITIALIZING;
+ }
+
while (true) {
// Create connection to default server.
pa_mainloop_ = pa_threaded_mainloop_new();
@@ -202,7 +214,8 @@ bool PulseAudioMixer::PulseAudioInit() {
break;
}
- pa_threaded_mainloop_lock(pa_mainloop_);
+ if (!MainloopSafeLock())
+ return false;
while (true) {
pa_mainloop_api* pa_mlapi = pa_threaded_mainloop_get_api(pa_mainloop_);
@@ -217,10 +230,11 @@ bool PulseAudioMixer::PulseAudioInit() {
break;
}
- ConnectToPulseCallbackData data;
- data.instance = this;
- data.connect_done = false;
+ MainloopUnlock();
+ if (!MainloopSafeLock())
+ return false;
+ CallbackWrapper data = {this, false, NULL};
pa_context_set_state_callback(pa_context_,
&ConnectToPulseCallbackThunk,
&data);
@@ -231,13 +245,13 @@ bool PulseAudioMixer::PulseAudioInit() {
} else {
// Wait until we have a completed connection or fail.
do {
- pa_threaded_mainloop_wait(pa_mainloop_);
- } while (!data.connect_done);
+ MainloopWait();
+ } while (!data.done);
state = pa_context_get_state(pa_context_);
if (state == PA_CONTEXT_FAILED) {
- LOG(ERROR) << "PulseAudio context connection failed";
+ LOG(ERROR) << "PulseAudio connection failed (daemon not running?)";
} else if (state == PA_CONTEXT_TERMINATED) {
LOG(ERROR) << "PulseAudio connection terminated early";
} else if (state != PA_CONTEXT_READY) {
@@ -249,15 +263,20 @@ bool PulseAudioMixer::PulseAudioInit() {
break;
}
- pa_threaded_mainloop_unlock(pa_mainloop_);
+ MainloopUnlock();
if (state != PA_CONTEXT_READY)
break;
- last_channels_ = 0;
+ if (!MainloopSafeLock())
+ return false;
GetDefaultPlaybackDevice();
- mixer_state_ = READY;
+ MainloopUnlock();
+ if (device_id_ == kInvalidDeviceId)
+ break;
+
+ set_mixer_state(READY);
return true;
}
@@ -270,78 +289,76 @@ void PulseAudioMixer::PulseAudioFree() {
if (!pa_mainloop_)
return;
- DCHECK_NE(mixer_state_, UNINITIALIZED);
- mixer_state_ = SHUTTING_DOWN;
+ {
+ AutoLock lock(mixer_state_lock_);
+ DCHECK_NE(mixer_state_, UNINITIALIZED);
+ if (mixer_state_ == SHUTTING_DOWN)
+ return;
+ // If still initializing on another thread, this will cause it to exit.
+ mixer_state_ = SHUTTING_DOWN;
+ }
+ MainloopLock();
if (pa_context_) {
- pa_threaded_mainloop_lock(pa_mainloop_);
pa_context_disconnect(pa_context_);
pa_context_unref(pa_context_);
- pa_threaded_mainloop_unlock(pa_mainloop_);
pa_context_ = NULL;
}
+ MainloopUnlock();
pa_threaded_mainloop_stop(pa_mainloop_);
pa_threaded_mainloop_free(pa_mainloop_);
pa_mainloop_ = NULL;
- mixer_state_ = UNINITIALIZED;
-}
-
-bool PulseAudioMixer::PulseAudioValid() const {
- if (mixer_state_ != READY)
- return false;
- if (!pa_context_) {
- DLOG(ERROR) << "Trying to use PulseAudio when no context";
- return false;
- }
- if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY) {
- LOG(ERROR) << "PulseAudio context not ready ("
- << pa_context_get_state(pa_context_) << ")";
- return false;
- }
- if (device_id_ == kInvalidDeviceId)
- return false;
-
- return true;
+ set_mixer_state(UNINITIALIZED);
}
-void PulseAudioMixer::CompleteOperationAndUnlock(pa_operation* pa_op) const {
+void PulseAudioMixer::CompleteOperation(pa_operation* pa_op,
+ bool* done) const {
// After starting any operation, this helper checks if it started OK, then
// waits for it to complete by iterating through the mainloop until the
// operation is not running anymore.
CHECK(pa_op);
while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
- pa_threaded_mainloop_wait(pa_mainloop_);
+ // If operation still running, but we got what we needed, cancel it now.
+ if (*done) {
+ pa_operation_cancel(pa_op);
+ break;
+ }
+ MainloopWait();
}
pa_operation_unref(pa_op);
- pa_threaded_mainloop_unlock(pa_mainloop_);
}
+// Must be called with mainloop lock held
void PulseAudioMixer::GetDefaultPlaybackDevice() {
+ DCHECK_GT(mainloop_lock_count_, 0);
DCHECK(pa_context_);
DCHECK(pa_context_get_state(pa_context_) == PA_CONTEXT_READY);
- pa_threaded_mainloop_lock(pa_mainloop_);
+ CallbackWrapper data = {this, false, NULL};
+
pa_operation* pa_op = pa_context_get_sink_info_list(pa_context_,
EnumerateDevicesCallback,
- this);
- CompleteOperationAndUnlock(pa_op);
+ &data);
+ CompleteOperation(pa_op, &data.done);
return;
}
void PulseAudioMixer::OnEnumerateDevices(const pa_sink_info* sink_info,
- int eol) {
- // If eol is set to a positive number, you're at the end of the list.
- if (eol > 0)
+ int eol, bool* done) {
+ if (device_id_ != kInvalidDeviceId)
return;
// TODO(davej): Should we handle cases of more than one output sink device?
- if (device_id_ == kInvalidDeviceId)
- device_id_ = sink_info->index;
- pa_threaded_mainloop_signal(pa_mainloop_, 0);
+ // eol is < 0 for error, > 0 for end of list, ==0 while listing.
+ if (eol == 0) {
+ device_id_ = sink_info->index;
+ }
+ *done = true;
+ MainloopSignal();
}
// static
@@ -349,19 +366,20 @@ void PulseAudioMixer::EnumerateDevicesCallback(pa_context* unused,
const pa_sink_info* sink_info,
int eol,
void* userdata) {
- PulseAudioMixer* inst = static_cast<PulseAudioMixer*>(userdata);
- inst->OnEnumerateDevices(sink_info, eol);
+ CallbackWrapper* data =
+ static_cast<CallbackWrapper*>(userdata);
+ data->instance->OnEnumerateDevices(sink_info, eol, &data->done);
}
+// Must be called with lock held
void PulseAudioMixer::GetAudioInfo(AudioInfo* info) const {
- CallbackWrapper cb_data = {pa_mainloop_, info};
- pa_threaded_mainloop_lock(pa_mainloop_);
- pa_operation* pa_op;
- pa_op = pa_context_get_sink_info_by_index(pa_context_,
- device_id_,
- GetAudioInfoCallback,
- &cb_data);
- CompleteOperationAndUnlock(pa_op);
+ DCHECK_GT(mainloop_lock_count_, 0);
+ CallbackWrapper data = {const_cast<PulseAudioMixer*>(this), false, info};
+ pa_operation* pa_op = pa_context_get_sink_info_by_index(pa_context_,
+ device_id_,
+ GetAudioInfoCallback,
+ &data);
+ CompleteOperation(pa_op, &data.done);
}
// static
@@ -369,15 +387,58 @@ void PulseAudioMixer::GetAudioInfoCallback(pa_context* unused,
const pa_sink_info* sink_info,
int eol,
void* userdata) {
- CallbackWrapper* cb_data = static_cast<CallbackWrapper*>(userdata);
- AudioInfo* data = static_cast<AudioInfo*>(cb_data->data);
+ CallbackWrapper* data = static_cast<CallbackWrapper*>(userdata);
+ AudioInfo* info = static_cast<AudioInfo*>(data->userdata);
// Copy just the information we care about.
if (eol == 0) {
- data->cvolume = sink_info->volume;
- data->muted = sink_info->mute ? true : false;
+ info->cvolume = sink_info->volume;
+ info->muted = sink_info->mute ? true : false;
+ data->done = true;
}
- pa_threaded_mainloop_signal(cb_data->mainloop, 0);
+ data->instance->MainloopSignal();
+}
+
+inline void PulseAudioMixer::MainloopLock() const {
+ pa_threaded_mainloop_lock(pa_mainloop_);
+ ++mainloop_lock_count_;
+}
+
+inline void PulseAudioMixer::MainloopUnlock() const {
+ --mainloop_lock_count_;
+ pa_threaded_mainloop_unlock(pa_mainloop_);
+}
+
+// Must be called with the lock held.
+inline void PulseAudioMixer::MainloopWait() const {
+ DCHECK_GT(mainloop_lock_count_, 0);
+ pa_threaded_mainloop_wait(pa_mainloop_);
+}
+
+// Must be called with the lock held.
+inline void PulseAudioMixer::MainloopSignal() const {
+ DCHECK_GT(mainloop_lock_count_, 0);
+ pa_threaded_mainloop_signal(pa_mainloop_, 0);
+}
+
+inline bool PulseAudioMixer::MainloopSafeLock() const {
+ AutoLock lock(mixer_state_lock_);
+ if ((mixer_state_ == SHUTTING_DOWN) || (!pa_mainloop_))
+ return false;
+ pa_threaded_mainloop_lock(pa_mainloop_);
+ ++mainloop_lock_count_;
+ return true;
+}
+
+inline bool PulseAudioMixer::MainloopLockIfReady() const {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != READY)
+ return false;
+ if (!pa_mainloop_)
+ return false;
+ pa_threaded_mainloop_lock(pa_mainloop_);
+ ++mainloop_lock_count_;
+ return true;
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/pulse_audio_mixer.h b/chrome/browser/chromeos/pulse_audio_mixer.h
index 223fe33..5d7de39 100644
--- a/chrome/browser/chromeos/pulse_audio_mixer.h
+++ b/chrome/browser/chromeos/pulse_audio_mixer.h
@@ -4,9 +4,11 @@
#ifndef CHROME_BROWSER_CHROMEOS_PULSE_AUDIO_MIXER_H_
#define CHROME_BROWSER_CHROMEOS_PULSE_AUDIO_MIXER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
@@ -20,6 +22,14 @@ namespace chromeos {
class PulseAudioMixer {
public:
+ enum State {
+ UNINITIALIZED = 0,
+ INITIALIZING,
+ READY,
+ SHUTTING_DOWN,
+ IN_ERROR
+ };
+
PulseAudioMixer();
~PulseAudioMixer();
@@ -28,12 +38,16 @@ class PulseAudioMixer {
typedef Callback1<bool>::Type InitDoneCallback;
bool Init(InitDoneCallback* callback);
+ // Blocking init call guarantees PulseAudio is started before returning.
+ bool InitSync();
+
// Blocking call. Returns a default of -inf on error.
double GetVolumeDb() const;
- // Non-blocking, volume sent in as first param to callback
+ // Non-blocking, volume sent in as first param to callback. The callback is
+ // only called if the function returns true.
typedef Callback2<double, void*>::Type GetVolumeCallback;
- void GetVolumeDbAsync(GetVolumeCallback* callback, void* user);
+ bool GetVolumeDbAsync(GetVolumeCallback* callback, void* user);
// Non-blocking call.
void SetVolumeDb(double vol_db);
@@ -45,20 +59,14 @@ class PulseAudioMixer {
// Non-Blocking call.
void SetMute(bool mute);
- // Call any time to see if we have a valid working connection to PulseAudio.
- // Non-blocking call.
- bool IsValid() const;
+ // Returns READY if we have a valid working connection to PulseAudio.
+ // This can return IN_ERROR if we lose the connection, even after an original
+ // successful init. Non-blocking call.
+ State CheckState() const;
private:
struct AudioInfo;
- enum State {
- UNINITIALIZED = 0,
- INITIALIZING,
- READY,
- SHUTTING_DOWN
- };
-
// These are the tasks to be run in the background on the worker thread.
void DoInit(InitDoneCallback* callback);
void DoGetVolume(GetVolumeCallback* callback, void* user);
@@ -66,6 +74,9 @@ class PulseAudioMixer {
static void ConnectToPulseCallbackThunk(pa_context* c, void* userdata);
void OnConnectToPulseCallback(pa_context* c, bool* connect_done);
+ // Helper function to just get our messsage loop thread going.
+ bool InitThread();
+
// This goes through sequence of connecting to the default PulseAudio server.
// We will block until we either have a valid connection or something failed.
// If a connection is lost for some reason, delete and recreate the object.
@@ -74,14 +85,9 @@ class PulseAudioMixer {
// PulseAudioFree. Disconnect from server.
void PulseAudioFree();
- // Check if the PA system is ready for communication, as well as if a default
- // device is available to talk to. This can return false if we lose the
- // connection, even after an original successful init.
- bool PulseAudioValid() const;
-
// Iterates the PA mainloop and only returns once an operation has completed
- // (successfully or unsuccessfully). This call only blocks the worker thread.
- void CompleteOperationAndUnlock(pa_operation* pa_op) const;
+ // (successfully or unsuccessfully) or *done is true.
+ void CompleteOperation(pa_operation* pa_op, bool* done) const;
// For now, this just gets the first device returned from the enumeration
// request. This will be the 'default' or 'master' device that all further
@@ -91,7 +97,7 @@ class PulseAudioMixer {
const pa_sink_info* sink_info,
int eol,
void* userdata);
- void OnEnumerateDevices(const pa_sink_info* sink_info, int eol);
+ void OnEnumerateDevices(const pa_sink_info* sink_info, int eol, bool* done);
// Get the info we're interested in from the default device. Currently this
// is an array of volumes, and the mute state. Blocking call.
@@ -101,12 +107,34 @@ class PulseAudioMixer {
int eol,
void* userdata);
+ void set_mixer_state(State state) {
+ AutoLock lock(mixer_state_lock_);
+ mixer_state_ = state;
+ }
+
+ // These call down to PulseAudio's mainloop locking functions
+ void MainloopLock() const;
+ void MainloopUnlock() const;
+ void MainloopWait() const;
+ void MainloopSignal() const;
+
+ // Same as Lock(), but we fail if we are shutting down or mainloop invalid.
+ bool MainloopSafeLock() const;
+
+ // Lock the mainloop pa_lock_ if mixer_state_ is READY.
+ bool MainloopLockIfReady() const;
+
// The PulseAudio index of the main device being used.
- mutable int device_id_;
+ int device_id_;
// Set to the number of channels on the main device.
int last_channels_;
- State mixer_state_;
+
+ // For informational purposes only, just used to assert lock is held.
+ mutable int mainloop_lock_count_;
+
+ mutable Lock mixer_state_lock_;
+ mutable State mixer_state_;
// Cached contexts for use in PulseAudio calls.
pa_context* pa_context_;
diff --git a/chrome/browser/chromeos/status/clock_menu_button.cc b/chrome/browser/chromeos/status/clock_menu_button.cc
index 9576490..f63593f 100644
--- a/chrome/browser/chromeos/status/clock_menu_button.cc
+++ b/chrome/browser/chromeos/status/clock_menu_button.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,6 +9,7 @@
#include "base/i18n/time_formatting.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
@@ -25,17 +26,18 @@ namespace chromeos {
const int kTimerSlopSeconds = 1;
ClockMenuButton::ClockMenuButton(StatusAreaHost* host)
- : MenuButton(NULL, std::wstring(), this, false),
+ : StatusAreaButton(this),
host_(host) {
// Add as SystemLibrary observer. We update the clock if timezone changes.
CrosLibrary::Get()->GetSystemLibrary()->AddObserver(this);
set_border(NULL);
+ set_use_menu_button_paint(true);
SetFont(ResourceBundle::GetSharedInstance().GetFont(
ResourceBundle::BaseFont).DeriveFont(1, gfx::Font::BOLD));
SetEnabledColor(0xB3FFFFFF); // White with 70% Alpha
- SetShowHighlighted(false);
- set_alignment(TextButton::ALIGN_RIGHT);
+ SetShowMultipleIconStates(false);
+ set_alignment(TextButton::ALIGN_CENTER);
UpdateTextAndSetNextTimer();
}
@@ -68,18 +70,9 @@ void ClockMenuButton::UpdateTextAndSetNextTimer() {
}
void ClockMenuButton::UpdateText() {
- int cur_width = GetPreferredSize().width();
- SetText(base::TimeFormatTimeOfDay(base::Time::Now()));
- // TextButtons normally remember the max text size, so the button's preferred
- // size will always be as large as the largest text ever put in it.
- // We clear that max text size, so we can adjust the size to fit the text.
- ClearMaxTextSize();
- int new_width = GetPreferredSize().width();
-
- // If width has changed, we want to relayout the StatusAreaView.
- if (new_width != cur_width)
- PreferredSizeChanged();
-
+ base::Time time(base::Time::Now());
+ SetText(base::TimeFormatTimeOfDay(time));
+ SetTooltipText(base::TimeFormatShortDate(time));
SchedulePaint();
}
diff --git a/chrome/browser/chromeos/status/clock_menu_button.h b/chrome/browser/chromeos/status/clock_menu_button.h
index b5daa2c..405d00a 100644
--- a/chrome/browser/chromeos/status/clock_menu_button.h
+++ b/chrome/browser/chromeos/status/clock_menu_button.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_CLOCK_MENU_BUTTON_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_CLOCK_MENU_BUTTON_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "base/timer.h"
#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"
@@ -21,7 +23,7 @@ class StatusAreaHost;
// The clock menu button in the status area.
// This button shows the current time.
-class ClockMenuButton : public views::MenuButton,
+class ClockMenuButton : public StatusAreaButton,
public views::ViewMenuDelegate,
public menus::MenuModel,
public SystemLibrary::Observer {
diff --git a/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc b/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
index b0a3106..f7a6f1c 100644
--- a/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
+++ b/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/chromeos/frame/browser_view.h"
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/view_ids.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/in_process_browser_test.h"
@@ -25,6 +25,11 @@ namespace chromeos {
class ClockMenuButtonTest : public InProcessBrowserTest {
protected:
ClockMenuButtonTest() : InProcessBrowserTest() {}
+ virtual void SetUpInProcessBrowserTestFixture() {
+ // This test requires actual libcros, but InProcessBrowserTest has set
+ // to use stub, so reset it here.
+ CrosLibrary::Get()->GetTestApi()->ResetUseStubImpl();
+ }
ClockMenuButton* GetClockMenuButton() {
BrowserView* view = static_cast<BrowserView*>(browser()->window());
return static_cast<StatusAreaView*>(view->
@@ -35,13 +40,18 @@ class ClockMenuButtonTest : public InProcessBrowserTest {
IN_PROC_BROWSER_TEST_F(ClockMenuButtonTest, TimezoneTest) {
ClockMenuButton* clock = GetClockMenuButton();
ASSERT_TRUE(clock != NULL);
+
// Update timezone and make sure clock text changes.
- std::wstring text_before = clock->text();
- scoped_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone(
+ scoped_ptr<icu::TimeZone> timezone_first(icu::TimeZone::createTimeZone(
icu::UnicodeString::fromUTF8("Asia/Hong_Kong")));
- CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone.get());
+ CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone_first.get());
+ std::wstring text_before = clock->text();
+ scoped_ptr<icu::TimeZone> timezone_second(icu::TimeZone::createTimeZone(
+ icu::UnicodeString::fromUTF8("Pacific/Samoa")));
+ 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/feedback_menu_button.cc b/chrome/browser/chromeos/status/feedback_menu_button.cc
index 1b8ead6..d3b14d3 100644
--- a/chrome/browser/chromeos/status/feedback_menu_button.cc
+++ b/chrome/browser/chromeos/status/feedback_menu_button.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
@@ -22,6 +23,7 @@ FeedbackMenuButton::FeedbackMenuButton(StatusAreaHost* host)
: StatusAreaButton(this),
host_(host) {
DCHECK(host_);
+ SetTooltipText(l10n_util::GetString(IDS_STATUSBAR_FEEDBACK_TOOLTIP));
}
FeedbackMenuButton::~FeedbackMenuButton() {
diff --git a/chrome/browser/chromeos/status/feedback_menu_button.h b/chrome/browser/chromeos/status/feedback_menu_button.h
index 1b6b1df..9e1590b 100644
--- a/chrome/browser/chromeos/status/feedback_menu_button.h
+++ b/chrome/browser/chromeos/status/feedback_menu_button.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_FEEDBACK_MENU_BUTTON_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_FEEDBACK_MENU_BUTTON_H_
+#pragma once
-#include "app/menus/simple_menu_model.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
#include "views/controls/menu/menu_2.h"
#include "views/controls/menu/view_menu_delegate.h"
diff --git a/chrome/browser/chromeos/status/language_menu_button.cc b/chrome/browser/chromeos/status/language_menu_button.cc
index 169640d..24f2da5 100644
--- a/chrome/browser/chromeos/status/language_menu_button.cc
+++ b/chrome/browser/chromeos/status/language_menu_button.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.
@@ -8,6 +8,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -15,10 +16,12 @@
#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/language_preferences.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -71,7 +74,6 @@ enum {
// input method list to avoid conflict.
const int kRadioGroupLanguage = 1 << 16;
const int kRadioGroupNone = -1;
-const wchar_t kSpacer[] = L"MMM";
// A mapping from an input method id to a text for the language indicator. The
// mapping is necessary since some input methods belong to the same language.
@@ -91,13 +93,9 @@ const struct {
// For traditional Chinese input methods
{ "chewing", "\xe9\x85\xb7" }, // U+9177
{ "m17n:zh:cangjie", "\xe5\x80\x89" }, // U+5009
- // TODO(yusukes): Add m17n:zh:quick if there's a good Hanzi character for it.
-
- // Handle "m17n:t" input methods here since ICU is not able to handle the
- // language code "t". Note: most users use either latn-pre or latn-post
- // methods, not both. The same is true for mozc/mozc-jp.
- { "m17n:t:latn-pre", "LAT" },
- { "m17n:t:latn-post", "LAT" },
+ { "m17n:zh:quick", "\xe9\x80\x9f" }, // U+901F
+ // For Hangul input method.
+ { "hangul", "\xed\x95\x9c" }, // U+D55C
};
const size_t kMappingFromIdToIndicatorTextLen =
ARRAYSIZE_UNSAFE(kMappingFromIdToIndicatorText);
@@ -126,7 +124,7 @@ namespace chromeos {
// LanguageMenuButton
LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
- : MenuButton(NULL, std::wstring(), this, false),
+ : StatusAreaButton(this),
input_method_descriptors_(CrosLibrary::Get()->GetInputMethodLibrary()->
GetActiveInputMethods()),
model_(NULL),
@@ -139,15 +137,16 @@ LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
DCHECK(input_method_descriptors_.get() &&
!input_method_descriptors_->empty());
set_border(NULL);
+ set_use_menu_button_paint(true);
SetFont(ResourceBundle::GetSharedInstance().GetFont(
ResourceBundle::BaseFont).DeriveFont(1, gfx::Font::BOLD));
SetEnabledColor(0xB3FFFFFF); // White with 70% Alpha
SetDisabledColor(0x00FFFFFF); // White with 00% Alpha (invisible)
- SetShowHighlighted(false);
+ SetShowMultipleIconStates(false);
+ set_alignment(TextButton::ALIGN_CENTER);
+
// Update the model
RebuildModel();
- // Grab the real estate.
- UpdateIndicator(kSpacer, L"" /* no tooltip */);
// Draw the default indicator "US". The default indicator "US" is used when
// |pref_service| is not available (for example, unit tests) or |pref_service|
@@ -325,12 +324,7 @@ string16 LanguageMenuButton::GetLabelAt(int index) const {
std::wstring name;
if (IndexIsInInputMethodList(index)) {
- const std::string language_code =
- input_method::GetLanguageCodeFromDescriptor(
- input_method_descriptors_->at(index));
- bool need_method_name = (need_method_name_.count(language_code) > 0);
- name = GetTextForMenu(input_method_descriptors_->at(index),
- need_method_name);
+ name = GetTextForMenu(input_method_descriptors_->at(index));
} else if (GetPropertyIndex(index, &index)) {
const ImePropertyList& property_list
= CrosLibrary::Get()->GetInputMethodLibrary()->current_ime_properties();
@@ -398,6 +392,22 @@ void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
GetActiveInputMethods());
RebuildModel();
language_menu_.Rebuild();
+
+ // Disallow the menu widget to grab the keyboard focus. This is necessary to
+ // enable users to change status of an input method (e.g. change the input
+ // mode from Japanese Hiragana to Japanese Katakana) without discarding a
+ // preedit string. See crosbug.com/5796 for details. Note that menus other
+ // than this one should not call the Gtk+ API since it is a special API only
+ // for a menu related to IME/keyboard. See the Gtk+ API reference at:
+ // http://library.gnome.org/devel/gtk/stable/GtkMenuShell.html
+ gfx::NativeMenu native_menu = language_menu_.GetNativeMenu();
+ if (native_menu) {
+ gtk_menu_shell_set_take_focus(GTK_MENU_SHELL(native_menu), FALSE);
+ } else {
+ LOG(ERROR)
+ << "Can't call gtk_menu_shell_set_take_focus since NativeMenu is NULL";
+ }
+
language_menu_.UpdateStates();
language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
}
@@ -428,7 +438,7 @@ void LanguageMenuButton::InputMethodChanged(InputMethodLibrary* obj) {
// buttun for the login screen is destroyed.
if (!logged_in_ && g_browser_process && g_browser_process->local_state()) {
g_browser_process->local_state()->SetString(
- kPreferredKeyboardLayout, current_input_method.id);
+ language_prefs::kPreferredKeyboardLayout, current_input_method.id);
g_browser_process->local_state()->SavePersistentPrefs();
}
}
@@ -446,7 +456,8 @@ void LanguageMenuButton::ImePropertiesChanged(InputMethodLibrary* obj) {
////////////////////////////////////////////////////////////////////////////////
// views::View implementation:
-void LanguageMenuButton::LocaleChanged() {
+void LanguageMenuButton::OnLocaleChanged() {
+ input_method::OnLocaleChanged();
const InputMethodDescriptor& input_method =
CrosLibrary::Get()->GetInputMethodLibrary()->current_input_method();
UpdateIndicatorFromInputMethod(input_method);
@@ -474,15 +485,13 @@ void LanguageMenuButton::UpdateIndicator(
SetTooltipText(tooltip);
}
SetText(name);
- set_alignment(TextButton::ALIGN_RIGHT);
SchedulePaint();
}
void LanguageMenuButton::UpdateIndicatorFromInputMethod(
const InputMethodDescriptor& input_method) {
const std::wstring name = GetTextForIndicator(input_method);
- const std::wstring tooltip =
- GetTextForMenu(input_method, true /* add_method_name */);
+ const std::wstring tooltip = GetTextForMenu(input_method);
UpdateIndicator(name, tooltip);
}
@@ -492,26 +501,14 @@ void LanguageMenuButton::RebuildModel() {
// Indicates if separator's needed before each section.
bool need_separator = false;
- need_method_name_.clear();
- std::set<std::string> languages_seen;
if (!input_method_descriptors_->empty()) {
// We "abuse" the command_id and group_id arguments of AddRadioItem method.
// A COMMAND_ID_XXX enum value is passed as command_id, and array index of
// |input_method_descriptors_| or |property_list| is passed as group_id.
for (size_t i = 0; i < input_method_descriptors_->size(); ++i) {
model_->AddRadioItem(COMMAND_ID_INPUT_METHODS, dummy_label, i);
-
- const std::string language_code
- = input_method::GetLanguageCodeFromDescriptor(
- input_method_descriptors_->at(i));
- // If there is more than one input method for this language, then we need
- // to display the method name.
- if (languages_seen.find(language_code) == languages_seen.end()) {
- languages_seen.insert(language_code);
- } else {
- need_method_name_.insert(language_code);
- }
}
+
need_separator = true;
}
@@ -634,31 +631,33 @@ std::wstring LanguageMenuButton::GetTextForIndicator(
}
std::wstring LanguageMenuButton::GetTextForMenu(
- const InputMethodDescriptor& input_method, bool add_method_name) {
+ const InputMethodDescriptor& input_method) {
+ // We don't show language here. Name of keyboard layout or input method
+ // usually imply (or explicitly include) its language.
+
+ // Special case for Dutch, French and German: these languages have multiple
+ // keyboard layouts and share the same laout of keyboard (Belgian). We need to
+ // show explicitly the language for the layout.
+ // For Arabic and Hindi: they share "Standard Input Method".
const std::string language_code
= input_method::GetLanguageCodeFromDescriptor(input_method);
-
std::wstring text;
- if (language_code == "t") {
- text = UTF8ToWide(input_method.display_name);
+ if (language_code == "ar" ||
+ language_code == "hi" ||
+ language_code == "nl" ||
+ language_code == "fr" ||
+ language_code == "de") {
+ text = GetLanguageName(language_code) + L" - ";
}
+ text += input_method::GetString(input_method.display_name);
- // For the drop-down menu and tooltip, we'll show language names like
- // "Chinese (Simplified)" and "Japanese", instead of input method names
- // like "Pinyin" and "Mozc".
- if (text.empty()) {
- text = GetLanguageName(language_code);
- if (add_method_name) {
- text += L" - ";
- text += input_method::GetString(input_method.display_name);
- }
- }
DCHECK(!text.empty());
return text;
}
void LanguageMenuButton::RegisterPrefs(PrefService* local_state) {
- local_state->RegisterStringPref(kPreferredKeyboardLayout, "");
+ local_state->RegisterStringPref(language_prefs::kPreferredKeyboardLayout,
+ "");
}
void LanguageMenuButton::Observe(NotificationType type,
diff --git a/chrome/browser/chromeos/status/language_menu_button.h b/chrome/browser/chromeos/status/language_menu_button.h
index dcafac1..7610e8c 100644
--- a/chrome/browser/chromeos/status/language_menu_button.h
+++ b/chrome/browser/chromeos/status/language_menu_button.h
@@ -4,11 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_LANGUAGE_MENU_BUTTON_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_LANGUAGE_MENU_BUTTON_H_
+#pragma once
#include "app/menus/simple_menu_model.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
-#include "chrome/browser/pref_member.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"
@@ -24,7 +25,7 @@ class StatusAreaHost;
// The language menu button in the status area.
// This class will handle getting the IME/XKB status and populating the menu.
-class LanguageMenuButton : public views::MenuButton,
+class LanguageMenuButton : public StatusAreaButton,
public views::ViewMenuDelegate,
public menus::MenuModel,
public InputMethodLibrary::Observer,
@@ -69,15 +70,14 @@ class LanguageMenuButton : public views::MenuButton,
// Converts an InputMethodDescriptor object into human readable string.
// Returns a string for the drop-down menu and the tooltip for the indicator.
- static std::wstring GetTextForMenu(
- const InputMethodDescriptor& input_method, bool add_method_name);
+ static std::wstring GetTextForMenu(const InputMethodDescriptor& input_method);
// Registers input method preferences for the login screen.
static void RegisterPrefs(PrefService* local_state);
protected:
// views::View implementation.
- virtual void LocaleChanged();
+ virtual void OnLocaleChanged();
private:
// views::ViewMenuDelegate implementation.
@@ -114,9 +114,6 @@ class LanguageMenuButton : public views::MenuButton,
StringPrefMember previous_input_method_pref_;
StringPrefMember current_input_method_pref_;
- // Languages that need the input method name displayed.
- std::set<std::string> need_method_name_;
-
// We borrow menus::SimpleMenuModel implementation to maintain the current
// content of the pop-up menu. The menus::MenuModel is implemented using this
// |model_|.
diff --git a/chrome/browser/chromeos/status/language_menu_button_browsertest.cc b/chrome/browser/chromeos/status/language_menu_button_browsertest.cc
index 452e598..2176997 100644
--- a/chrome/browser/chromeos/status/language_menu_button_browsertest.cc
+++ b/chrome/browser/chromeos/status/language_menu_button_browsertest.cc
@@ -23,8 +23,8 @@ class LanguageMenuButtonTest : public CrosInProcessBrowserTest {
}
virtual void SetUpInProcessBrowserTestFixture() {
- InitStatusAreaMocks();
- SetStatusAreaMocksExpectations();
+ cros_mock_->InitStatusAreaMocks();
+ cros_mock_->SetStatusAreaMocksExpectations();
}
LanguageMenuButton* GetLanguageMenuButton() {
diff --git a/chrome/browser/chromeos/status/language_menu_button_unittest.cc b/chrome/browser/chromeos/status/language_menu_button_unittest.cc
index 2f4044a..b760fbc 100644
--- a/chrome/browser/chromeos/status/language_menu_button_unittest.cc
+++ b/chrome/browser/chromeos/status/language_menu_button_unittest.cc
@@ -20,7 +20,8 @@ TEST(LanguageMenuButtonTest, GetTextForIndicatorTest) {
}
{
InputMethodDescriptor desc("hangul", "Korean", "us", "ko");
- EXPECT_EQ(L"KO", LanguageMenuButton::GetTextForIndicator(desc));
+ EXPECT_EQ(UTF8ToWide("\xed\x95\x9c"),
+ LanguageMenuButton::GetTextForIndicator(desc));
}
{
InputMethodDescriptor desc("invalid-id", "unregistered string", "us", "xx");
@@ -30,7 +31,7 @@ TEST(LanguageMenuButtonTest, GetTextForIndicatorTest) {
// Test special cases.
{
- InputMethodDescriptor desc("xkb:us:dvorak:eng", "Dvorak", "us", "us");
+ InputMethodDescriptor desc("xkb:us:dvorak:eng", "Dvorak", "us", "eng");
EXPECT_EQ(L"DV", LanguageMenuButton::GetTextForIndicator(desc));
}
{
@@ -60,39 +61,97 @@ TEST(LanguageMenuButtonTest, GetTextForIndicatorTest) {
}
{
InputMethodDescriptor desc("m17n:zh:quick", "Quick", "us", "zh-TW");
- EXPECT_EQ(UTF8ToWide("TW"),
- LanguageMenuButton::GetTextForIndicator(desc));
- }
- {
- InputMethodDescriptor desc("m17n:t:latn-pre", "latn-pre", "us", "t");
- EXPECT_EQ(L"LAT",
+ EXPECT_EQ(UTF8ToWide("\xe9\x80\x9f"),
LanguageMenuButton::GetTextForIndicator(desc));
}
}
-TEST(LanguageMenuButtonTest, GetTextForTooltipTest) {
- const bool kAddMethodName = true;
+
+// Test whether the function returns language name for non-ambiguous languages.
+TEST(LanguageMenuButtonTest, GetTextForMenuTest) {
+ // For most languages input method or keyboard layout name is returned.
+ // See below for exceptions.
{
InputMethodDescriptor desc("m17n:fa:isiri", "isiri (m17n)", "us", "fa");
- EXPECT_EQ(L"Persian - Persian input method (ISIRI 2901 layout)",
- LanguageMenuButton::GetTextForMenu(desc, kAddMethodName));
+ EXPECT_EQ(L"Persian input method (ISIRI 2901 layout)",
+ LanguageMenuButton::GetTextForMenu(desc));
}
{
InputMethodDescriptor desc("hangul", "Korean", "us", "ko");
- EXPECT_EQ(L"Korean - Korean input method",
- LanguageMenuButton::GetTextForMenu(desc, kAddMethodName));
+ EXPECT_EQ(L"Korean input method",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("m17n:vi:tcvn", "tcvn (m17n)", "us", "vi");
+ EXPECT_EQ(L"Vietnamese input method (TCVN6064)",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("mozc", "Mozc (US keyboard layout)", "us", "ja");
+ EXPECT_EQ(L"Japanese input method (for US keyboard)",
+ LanguageMenuButton::GetTextForMenu(desc));
}
{
+ InputMethodDescriptor desc("xkb:jp::jpn", "Japan", "jp", "jpn");
+ EXPECT_EQ(L"Japanese keyboard layout",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("xkb:us:dvorak:eng", "USA - Dvorak",
+ "us(dvorak)", "eng");
+ EXPECT_EQ(L"English (Dvorak)",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+
+ // For Arabic, Dutch, French, German and Hindi,
+ // "language - keyboard layout" pair is returned.
+ {
+ InputMethodDescriptor desc("m17n:ar:kbd", "kbd (m17n)", "us", "ar");
+ EXPECT_EQ(L"Arabic - Standard input method",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("xkb:nl::nld", "Netherlands", "nl", "nld");
+ EXPECT_EQ(L"Dutch - Dutch keyboard layout",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("xkb:be::nld", "Belgium", "be", "nld");
+ EXPECT_EQ(L"Dutch - Belgian keyboard layout",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("xkb:fr::fra", "France", "fr", "fra");
+ EXPECT_EQ(L"French - French keyboard layout",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("xkb:be::fra", "Belgium", "be", "fra");
+ EXPECT_EQ(L"French - Belgian keyboard layout",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("xkb:de::ger", "Germany", "de", "ger");
+ EXPECT_EQ(L"German - German keyboard layout",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("xkb:be::ger", "Belgium", "be", "ger");
+ EXPECT_EQ(L"German - Belgian keyboard layout",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+ {
+ InputMethodDescriptor desc("m17n:hi:itrans", "itrans (m17n)", "us", "hi");
+ EXPECT_EQ(L"Hindi - Standard input method",
+ LanguageMenuButton::GetTextForMenu(desc));
+ }
+
+ {
InputMethodDescriptor desc("invalid-id", "unregistered string", "us", "xx");
// You can safely ignore the "Resouce ID is not found for: unregistered
// string" error.
- EXPECT_EQ(L"xx - unregistered string",
- LanguageMenuButton::GetTextForMenu(desc, kAddMethodName));
- }
- {
- InputMethodDescriptor desc("m17n:t:latn-pre", "latn-pre", "us", "t");
- EXPECT_EQ(L"latn-pre",
- LanguageMenuButton::GetTextForMenu(desc, kAddMethodName));
+ EXPECT_EQ(L"unregistered string",
+ LanguageMenuButton::GetTextForMenu(desc));
}
}
diff --git a/chrome/browser/chromeos/status/network_menu_button.cc b/chrome/browser/chromeos/status/network_menu_button.cc
index 7ea165e..9ed0854 100644
--- a/chrome/browser/chromeos/status/network_menu_button.cc
+++ b/chrome/browser/chromeos/status/network_menu_button.cc
@@ -4,19 +4,19 @@
#include "chrome/browser/chromeos/status/network_menu_button.h"
+#include <algorithm>
#include <limits>
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string_util.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/browser/chromeos/status/status_area_host.h"
#include "gfx/canvas_skia.h"
-#include "gfx/skbitmap_operations.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#include "views/widget/widget.h"
#include "views/window/window.h"
namespace chromeos {
@@ -25,13 +25,12 @@ namespace chromeos {
// NetworkMenuButton
// static
-const int NetworkMenuButton::kNumWifiImages = 9;
const int NetworkMenuButton::kThrobDuration = 1000;
NetworkMenuButton::NetworkMenuButton(StatusAreaHost* host)
: StatusAreaButton(this),
+ NetworkMenu(),
host_(host),
- ALLOW_THIS_IN_INITIALIZER_LIST(network_menu_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(animation_connecting_(this)) {
animation_connecting_.SetThrobDuration(kThrobDuration);
animation_connecting_.SetTweenType(Tween::LINEAR);
@@ -44,142 +43,6 @@ NetworkMenuButton::~NetworkMenuButton() {
}
////////////////////////////////////////////////////////////////////////////////
-// NetworkMenuButton, menus::MenuModel implementation:
-
-int NetworkMenuButton::GetItemCount() const {
- return static_cast<int>(menu_items_.size());
-}
-
-menus::MenuModel::ItemType NetworkMenuButton::GetTypeAt(int index) const {
- return menu_items_[index].type;
-}
-
-string16 NetworkMenuButton::GetLabelAt(int index) const {
- return menu_items_[index].label;
-}
-
-const gfx::Font* NetworkMenuButton::GetLabelFontAt(int index) const {
- return (menu_items_[index].flags & FLAG_ASSOCIATED) ?
- &ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BoldFont) :
- NULL;
-}
-
-bool NetworkMenuButton::IsItemCheckedAt(int index) const {
- // All menus::MenuModel::TYPE_CHECK menu items are checked.
- return true;
-}
-
-bool NetworkMenuButton::GetIconAt(int index, SkBitmap* icon) const {
- if (!menu_items_[index].icon.empty()) {
- *icon = menu_items_[index].icon;
- return true;
- }
- return false;
-}
-
-bool NetworkMenuButton::IsEnabledAt(int index) const {
- return !(menu_items_[index].flags & FLAG_DISABLED);
-}
-
-void NetworkMenuButton::ActivatedAt(int index) {
- // When we are refreshing the menu, ignore menu item activation.
- if (refreshing_menu_)
- return;
-
- NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
- int flags = menu_items_[index].flags;
- if (flags & FLAG_OPTIONS) {
- host_->OpenButtonOptions(this);
- } else if (flags & FLAG_TOGGLE_ETHERNET) {
- cros->EnableEthernetNetworkDevice(!cros->ethernet_enabled());
- } else if (flags & FLAG_TOGGLE_WIFI) {
- cros->EnableWifiNetworkDevice(!cros->wifi_enabled());
- } else if (flags & FLAG_TOGGLE_CELLULAR) {
- cros->EnableCellularNetworkDevice(!cros->cellular_enabled());
- } else if (flags & FLAG_TOGGLE_OFFLINE) {
- cros->EnableOfflineMode(!cros->offline_mode());
- } else if (flags & FLAG_OTHER_NETWORK) {
- NetworkConfigView* view = new NetworkConfigView();
- view->set_browser_mode(host_->IsBrowserMode());
- views::Window* window = views::Window::CreateChromeWindow(
- host_->GetNativeWindow(), gfx::Rect(), view);
- window->SetIsAlwaysOnTop(true);
- window->Show();
- view->SetLoginTextfieldFocus();
- } else if (flags & FLAG_ETHERNET) {
- if (cros->ethernet_connected()) {
- NetworkConfigView* view = new NetworkConfigView(cros->ethernet_network());
- view->set_browser_mode(host_->IsBrowserMode());
- views::Window* window = views::Window::CreateChromeWindow(
- host_->GetNativeWindow(), gfx::Rect(), view);
- window->SetIsAlwaysOnTop(true);
- window->Show();
- }
- } else if (flags & FLAG_WIFI) {
- WifiNetwork wifi;
- bool wifi_exists = cros->FindWifiNetworkByPath(
- menu_items_[index].wireless_path, &wifi);
- if (!wifi_exists) {
- // If we are attempting to connect to a network that no longer exists,
- // display a notification.
- // TODO(stevenjb): Show notification.
- } else if (wifi.name() == cros->wifi_name()) {
- if (cros->wifi_connected()) {
- // If we are already connected, open the config dialog.
- NetworkConfigView* view = new NetworkConfigView(wifi, false);
- view->set_browser_mode(host_->IsBrowserMode());
- views::Window* window = views::Window::CreateChromeWindow(
- host_->GetNativeWindow(), gfx::Rect(), view);
- window->SetIsAlwaysOnTop(true);
- window->Show();
- } else {
- // TODO(stevenjb): Connection in progress. Show dialog?
- }
- } else {
- // If wifi network is not encrypted, then directly connect.
- // Otherwise, we open password dialog window.
- if (!wifi.encrypted()) {
- cros->ConnectToWifiNetwork(wifi, std::string(),
- std::string(), std::string());
- } else {
- NetworkConfigView* view = new NetworkConfigView(wifi, true);
- view->set_browser_mode(host_->IsBrowserMode());
- views::Window* window = views::Window::CreateChromeWindow(
- host_->GetNativeWindow(), gfx::Rect(), view);
- window->SetIsAlwaysOnTop(true);
- window->Show();
- view->SetLoginTextfieldFocus();
- }
- }
- } else if (flags & FLAG_CELLULAR) {
- CellularNetwork cellular;
- bool cellular_exists = cros->FindCellularNetworkByPath(
- menu_items_[index].wireless_path, &cellular);
-
- if (!cellular_exists) {
- // If we are attempting to connect to a network that no longer exists,
- // display a notification.
- // TODO(stevenjb): Show notification.
- } else if (cellular.name() == cros->cellular_name()) {
- // If clicked on a network that we are already connected to or we are
- // currently trying to connect to, then open config dialog.
- if (cros->cellular_connected()) {
- NetworkConfigView* view = new NetworkConfigView(cellular);
- view->set_browser_mode(host_->IsBrowserMode());
- views::Window* window = views::Window::CreateChromeWindow(
- host_->GetNativeWindow(), gfx::Rect(), view);
- window->SetIsAlwaysOnTop(true);
- window->Show();
- } else {
- // TODO(stevenjb): Connection in progress. Show dialog?
- }
- } else {
- cros->ConnectToCellularNetwork(cellular);
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
// NetworkMenuButton, AnimationDelegate implementation:
void NetworkMenuButton::AnimationProgressed(const Animation* animation) {
@@ -221,144 +84,6 @@ void NetworkMenuButton::DrawIcon(gfx::Canvas* canvas) {
canvas->DrawBitmapInt(IconForDisplay(icon(), badge()), 0, 0);
}
-// Override the DrawIcon method to draw the wifi icon.
-// The wifi icon is composed of 1 or more alpha-blended icons to show the
-// network strength. We also draw an animation for when there's upload/download
-// traffic.
-/* TODO(chocobo): Add this code back in when UI is finalized.
-void NetworkMenuButton::DrawIcon(gfx::Canvas* canvas) {
-
- // First draw the base icon.
- canvas->DrawBitmapInt(icon(), 0, 0);
-
- // If wifi, we draw the wifi signal bars.
- NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
- if (cros->wifi_connecting() ||
- (!cros->ethernet_connected() && cros->wifi_connected())) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- // We want a value between 0-1.
- // 0 reperesents no signal and 1 represents full signal strength.
- double value = cros->wifi_connecting() ?
- animation_connecting_.GetCurrentValue() :
- cros->wifi_strength() / 100.0;
- if (value < 0)
- value = 0;
- else if (value > 1)
- value = 1;
-
- // If we are animating network traffic and not connecting, then we need to
- // figure out if we are to also draw the extra image.
- int downloading_index = -1;
- int uploading_index = -1;
- if (!animation_connecting_.is_animating()) {
- // For network animation, we only show animation in one direction.
- // So when we are hiding, we just use 1 minus the value.
- // We have kNumWifiImages + 1 number of states. For the first state, where
- // we are not adding any images, we set the index to -1.
- if (animation_downloading_.is_animating()) {
- double value_downloading = animation_downloading_.IsShowing() ?
- animation_downloading_.GetCurrentValue() :
- 1.0 - animation_downloading_.GetCurrentValue();
- downloading_index = static_cast<int>(value_downloading *
- nextafter(static_cast<float>(kNumWifiImages + 1), 0)) - 1;
- }
- if (animation_uploading_.is_animating()) {
- double value_uploading = animation_uploading_.IsShowing() ?
- animation_uploading_.GetCurrentValue() :
- 1.0 - animation_uploading_.GetCurrentValue();
- uploading_index = static_cast<int>(value_uploading *
- nextafter(static_cast<float>(kNumWifiImages + 1), 0)) - 1;
- }
- }
-
- // We need to determine opacity for each of the kNumWifiImages images.
- // We split the range (0-1) into equal ranges per kNumWifiImages images.
- // For example if kNumWifiImages is 3, then [0-0.33) is the first image and
- // [0.33-0.66) is the second image and [0.66-1] is the last image.
- // For each of the image:
- // If value < the range of this image, draw at kMinOpacity opacity.
- // If value > the range of this image, draw at kMaxOpacity-1 opacity.
- // If value within the range of this image, draw at an opacity value
- // between kMinOpacity and kMaxOpacity-1 relative to where in the range
- // value is at.
- // NOTE: Use an array rather than just calculating a resource number to
- // avoid creating implicit ordering dependencies on the resource values.
- static const int kWifiUpImages[kNumWifiImages] = {
- IDR_STATUSBAR_WIFI_UP1,
- IDR_STATUSBAR_WIFI_UP2,
- IDR_STATUSBAR_WIFI_UP3,
- IDR_STATUSBAR_WIFI_UP4,
- IDR_STATUSBAR_WIFI_UP5,
- IDR_STATUSBAR_WIFI_UP6,
- IDR_STATUSBAR_WIFI_UP7,
- IDR_STATUSBAR_WIFI_UP8,
- IDR_STATUSBAR_WIFI_UP9,
- };
- static const int kWifiUpPImages[kNumWifiImages] = {
- IDR_STATUSBAR_WIFI_UP1P,
- IDR_STATUSBAR_WIFI_UP2P,
- IDR_STATUSBAR_WIFI_UP3P,
- IDR_STATUSBAR_WIFI_UP4P,
- IDR_STATUSBAR_WIFI_UP5P,
- IDR_STATUSBAR_WIFI_UP6P,
- IDR_STATUSBAR_WIFI_UP7P,
- IDR_STATUSBAR_WIFI_UP8P,
- IDR_STATUSBAR_WIFI_UP9P,
- };
- static const int kWifiDownImages[kNumWifiImages] = {
- IDR_STATUSBAR_WIFI_DOWN1,
- IDR_STATUSBAR_WIFI_DOWN2,
- IDR_STATUSBAR_WIFI_DOWN3,
- IDR_STATUSBAR_WIFI_DOWN4,
- IDR_STATUSBAR_WIFI_DOWN5,
- IDR_STATUSBAR_WIFI_DOWN6,
- IDR_STATUSBAR_WIFI_DOWN7,
- IDR_STATUSBAR_WIFI_DOWN8,
- IDR_STATUSBAR_WIFI_DOWN9,
- };
- static const int kWifiDownPImages[kNumWifiImages] = {
- IDR_STATUSBAR_WIFI_DOWN1P,
- IDR_STATUSBAR_WIFI_DOWN2P,
- IDR_STATUSBAR_WIFI_DOWN3P,
- IDR_STATUSBAR_WIFI_DOWN4P,
- IDR_STATUSBAR_WIFI_DOWN5P,
- IDR_STATUSBAR_WIFI_DOWN6P,
- IDR_STATUSBAR_WIFI_DOWN7P,
- IDR_STATUSBAR_WIFI_DOWN8P,
- IDR_STATUSBAR_WIFI_DOWN9P,
- };
-
- double value_per_image = 1.0 / kNumWifiImages;
- SkPaint paint;
- for (int i = 0; i < kNumWifiImages; i++) {
- if (value > value_per_image) {
- paint.setAlpha(kMaxOpacity - 1);
- value -= value_per_image;
- } else {
- // Map value between 0 and value_per_image to [kMinOpacity,kMaxOpacity).
- paint.setAlpha(kMinOpacity + static_cast<int>(value / value_per_image *
- nextafter(static_cast<float>(kMaxOpacity - kMinOpacity), 0)));
- // For following iterations, we want to draw at kMinOpacity.
- // So we set value to 0 here.
- value = 0;
- }
- canvas->DrawBitmapInt(*rb.GetBitmapNamed(kWifiUpImages[i]), 0, 0, paint);
- canvas->DrawBitmapInt(*rb.GetBitmapNamed(kWifiDownImages[i]), 0, 0,
- paint);
-
- // Draw network traffic downloading/uploading image if necessary.
- if (i == downloading_index) {
- canvas->DrawBitmapInt(*rb.GetBitmapNamed(kWifiDownPImages[i]), 0, 0,
- paint);
- }
- if (i == uploading_index) {
- canvas->DrawBitmapInt(*rb.GetBitmapNamed(kWifiUpPImages[i]), 0, 0,
- paint);
- }
- }
- }
-}
-*/
////////////////////////////////////////////////////////////////////////////////
// NetworkMenuButton, NetworkLibrary::Observer implementation:
@@ -372,19 +97,37 @@ void NetworkMenuButton::NetworkChanged(NetworkLibrary* cros) {
animation_connecting_.StartThrobbing(std::numeric_limits<int>::max());
SetIcon(*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS1));
}
+ std::string network_name = cros->wifi_connecting() ?
+ cros->wifi_name() : cros->cellular_name();
+ SetTooltipText(
+ l10n_util::GetStringF(IDS_STATUSBAR_NETWORK_CONNECTING_TOOLTIP,
+ UTF8ToWide(network_name)));
} else {
// Stop connecting animation since we are not connecting.
animation_connecting_.Stop();
// Always show the higher priority connection first. Ethernet then wifi.
- if (cros->ethernet_connected())
+ if (cros->ethernet_connected()) {
SetIcon(*rb.GetBitmapNamed(IDR_STATUSBAR_WIRED));
- else if (cros->wifi_connected())
+ SetTooltipText(
+ l10n_util::GetStringF(
+ IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP,
+ l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET)));
+ } else if (cros->wifi_connected()) {
SetIcon(IconForNetworkStrength(cros->wifi_strength(), false));
- else if (cros->cellular_connected())
+ SetTooltipText(l10n_util::GetStringF(
+ IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP,
+ UTF8ToWide(cros->wifi_name())));
+ } else if (cros->cellular_connected()) {
SetIcon(IconForNetworkStrength(cros->cellular_strength(), false));
- else
+ SetTooltipText(l10n_util::GetStringF(
+ IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP,
+ UTF8ToWide(cros->cellular_name())));
+ } else {
SetIcon(*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0));
+ SetTooltipText(l10n_util::GetString(
+ IDS_STATUSBAR_NETWORK_NO_NETWORK_TOOLTIP));
+ }
}
if (!cros->Connected() && !cros->Connecting()) {
@@ -400,211 +143,34 @@ void NetworkMenuButton::NetworkChanged(NetworkLibrary* cros) {
} else {
SetIcon(*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0));
SetBadge(*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_WARNING));
+ SetTooltipText(l10n_util::GetString(
+ IDS_STATUSBAR_NETWORK_NO_NETWORK_TOOLTIP));
}
SchedulePaint();
}
-void NetworkMenuButton::NetworkTraffic(NetworkLibrary* cros, int traffic_type) {
-/* TODO(chocobo): Add this code back in when network traffic UI is finalized.
- if (!cros->ethernet_connected() && cros->wifi_connected() &&
- !cros->wifi_connecting()) {
- // For downloading/uploading animation, we want to force at least one cycle
- // so that it looks smooth. And if we keep downloading/uploading, we will
- // keep calling StartThrobbing which will update the cycle count back to 2.
- if (traffic_type & TRAFFIC_DOWNLOAD)
- animation_downloading_.StartThrobbing(2);
- if (traffic_type & TRAFFIC_UPLOAD)
- animation_uploading_.StartThrobbing(2);
- }
- */
-}
-
void NetworkMenuButton::SetBadge(const SkBitmap& badge) {
badge_ = badge;
}
-// static
-SkBitmap NetworkMenuButton::IconForNetworkStrength(int strength, bool black) {
- // Compose wifi icon by superimposing various icons.
- // NOTE: Use an array rather than just calculating a resource number to avoid
- // creating implicit ordering dependencies on the resource values.
- static const int kBarsImages[kNumWifiImages] = {
- IDR_STATUSBAR_NETWORK_BARS1,
- IDR_STATUSBAR_NETWORK_BARS2,
- IDR_STATUSBAR_NETWORK_BARS3,
- IDR_STATUSBAR_NETWORK_BARS4,
- IDR_STATUSBAR_NETWORK_BARS5,
- IDR_STATUSBAR_NETWORK_BARS6,
- IDR_STATUSBAR_NETWORK_BARS7,
- IDR_STATUSBAR_NETWORK_BARS8,
- IDR_STATUSBAR_NETWORK_BARS9,
- };
- static const int kBarsBlackImages[kNumWifiImages] = {
- IDR_STATUSBAR_NETWORK_BARS1_BLACK,
- IDR_STATUSBAR_NETWORK_BARS2_BLACK,
- IDR_STATUSBAR_NETWORK_BARS3_BLACK,
- IDR_STATUSBAR_NETWORK_BARS4_BLACK,
- IDR_STATUSBAR_NETWORK_BARS5_BLACK,
- IDR_STATUSBAR_NETWORK_BARS6_BLACK,
- IDR_STATUSBAR_NETWORK_BARS7_BLACK,
- IDR_STATUSBAR_NETWORK_BARS8_BLACK,
- IDR_STATUSBAR_NETWORK_BARS9_BLACK,
- };
+////////////////////////////////////////////////////////////////////////////////
+// NetworkMenuButton, NetworkMenu implementation:
- int index = static_cast<int>(strength / 100.0 *
- nextafter(static_cast<float>(kNumWifiImages), 0));
- index = std::max(std::min(index, kNumWifiImages - 1), 0);
- return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- black ? kBarsBlackImages[index] : kBarsImages[index]);
+bool NetworkMenuButton::IsBrowserMode() const {
+ return host_->IsBrowserMode();
}
-// static
-SkBitmap NetworkMenuButton::IconForDisplay(SkBitmap icon, SkBitmap badge) {
- // Icons are 24x24.
- static const int kIconWidth = 24;
- static const int kIconHeight = 24;
- // Draw the network icon 3 pixels down to center it.
- static const int kIconX = 0;
- static const int kIconY = 3;
- // Draw badge at (14,14).
- static const int kBadgeX = 14;
- static const int kBadgeY = 14;
-
- gfx::CanvasSkia canvas(kIconWidth, kIconHeight, false);
- canvas.DrawBitmapInt(icon, kIconX, kIconY);
- if (!badge.empty())
- canvas.DrawBitmapInt(badge, kBadgeX, kBadgeY);
- return canvas.ExtractBitmap();
+gfx::NativeWindow NetworkMenuButton::GetNativeWindow() const {
+ return host_->GetNativeWindow();
}
-////////////////////////////////////////////////////////////////////////////////
-// NetworkMenuButton, views::ViewMenuDelegate implementation:
-
-void NetworkMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
- refreshing_menu_ = true;
- NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
- cros->RequestWifiScan();
- cros->UpdateSystemInfo();
- InitMenuItems();
- network_menu_.Rebuild();
- network_menu_.UpdateStates();
- refreshing_menu_ = false;
- network_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
+void NetworkMenuButton::OpenButtonOptions() const {
+ host_->OpenButtonOptions(this);
}
-void NetworkMenuButton::InitMenuItems() {
- menu_items_.clear();
- // Populate our MenuItems with the current list of wifi networks.
- NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-
- // Ethernet
- string16 label = l10n_util::GetStringUTF16(
- IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
- SkBitmap icon = *rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK);
- SkBitmap badge = cros->ethernet_connecting() || cros->ethernet_connected() ?
- SkBitmap() : *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_DISCONNECTED);
- int flag = (cros->ethernet_connecting() || cros->ethernet_connected()) ?
- FLAG_ETHERNET | FLAG_ASSOCIATED : FLAG_ETHERNET;
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label,
- IconForDisplay(icon, badge), std::string(), flag));
-
- // Wifi
- const WifiNetworkVector& wifi_networks = cros->wifi_networks();
- // Wifi networks ssids.
- for (size_t i = 0; i < wifi_networks.size(); ++i) {
- label = ASCIIToUTF16(wifi_networks[i].name());
- SkBitmap icon = IconForNetworkStrength(wifi_networks[i].strength(), true);
- SkBitmap badge = wifi_networks[i].encrypted() ?
- *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE) : SkBitmap();
- flag = (wifi_networks[i].name() == cros->wifi_name()) ?
- FLAG_WIFI | FLAG_ASSOCIATED : FLAG_WIFI;
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label,
- IconForDisplay(icon, badge), wifi_networks[i].service_path(), flag));
- }
-
- // Cellular
- const CellularNetworkVector& cell_networks = cros->cellular_networks();
- // Cellular networks ssids.
- for (size_t i = 0; i < cell_networks.size(); ++i) {
- label = ASCIIToUTF16(cell_networks[i].name());
- SkBitmap icon = IconForNetworkStrength(cell_networks[i].strength(), true);
- // TODO(chocobo): Check cellular network 3g/edge.
- SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_3G);
-// SkBitmap badge = *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_EDGE);
- flag = (cell_networks[i].name() == cros->cellular_name()) ?
- FLAG_CELLULAR | FLAG_ASSOCIATED : FLAG_CELLULAR;
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label,
- IconForDisplay(icon, badge), cell_networks[i].service_path(), flag));
- }
-
- // No networks available message.
- if (wifi_networks.empty() && cell_networks.empty()) {
- label = l10n_util::GetStringFUTF16(IDS_STATUSBAR_NETWORK_MENU_ITEM_INDENT,
- l10n_util::GetStringUTF16(IDS_STATUSBAR_NO_NETWORKS_MESSAGE));
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label,
- SkBitmap(), std::string(), FLAG_DISABLED));
- }
-
- // Other networks
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND,
- l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_NETWORKS),
- IconForDisplay(*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0),
- SkBitmap()),
- std::string(), FLAG_OTHER_NETWORK));
-
- if (cros->wifi_available() || cros->cellular_available()) {
- // Separator.
- menu_items_.push_back(MenuItem());
-
- // Turn Wifi Off. (only if wifi available)
- if (cros->wifi_available()) {
- int id = cros->wifi_enabled() ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE :
- IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
- label = l10n_util::GetStringFUTF16(id,
- l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI));
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label,
- SkBitmap(), std::string(), FLAG_TOGGLE_WIFI));
- }
-
- // Turn Cellular Off. (only if cellular available)
- if (cros->cellular_available()) {
- int id = cros->cellular_enabled() ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE :
- IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
- label = l10n_util::GetStringFUTF16(id,
- l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR));
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label,
- SkBitmap(), std::string(), FLAG_TOGGLE_CELLULAR));
- }
- }
-
- // TODO(chocobo): Uncomment once we figure out how to do offline mode.
- // Offline mode.
-// menu_items_.push_back(MenuItem(cros->offline_mode() ?
-// menus::MenuModel::TYPE_CHECK : menus::MenuModel::TYPE_COMMAND,
-// l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_OFFLINE_MODE),
-// SkBitmap(), std::string(), FLAG_TOGGLE_OFFLINE));
-
- if (cros->Connected() || host_->ShouldOpenButtonOptions(this)) {
- // Separator.
- menu_items_.push_back(MenuItem());
-
- // IP address
- if (cros->Connected()) {
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND,
- ASCIIToUTF16(cros->IPAddress()), SkBitmap(),
- std::string(), FLAG_DISABLED));
- }
-
- // Network settings.
- if (host_->ShouldOpenButtonOptions(this)) {
- label =
- l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_OPEN_OPTIONS_DIALOG);
- menu_items_.push_back(MenuItem(menus::MenuModel::TYPE_COMMAND, label,
- SkBitmap(), std::string(), FLAG_OPTIONS));
- }
- }
+bool NetworkMenuButton::ShouldOpenButtonOptions() const {
+ return host_->ShouldOpenButtonOptions(this);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/status/network_menu_button.h b/chrome/browser/chromeos/status/network_menu_button.h
index e5325ad..bb5ff96 100644
--- a/chrome/browser/chromeos/status/network_menu_button.h
+++ b/chrome/browser/chromeos/status/network_menu_button.h
@@ -4,19 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_NETWORK_MENU_BUTTON_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_NETWORK_MENU_BUTTON_H_
-
-#include <string>
-#include <vector>
+#pragma once
#include "app/throb_animation.h"
#include "base/timer.h"
#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/chromeos/options/network_config_view.h"
+#include "chrome/browser/chromeos/status/network_menu.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
-#include "views/controls/menu/menu_2.h"
-#include "views/controls/menu/view_menu_delegate.h"
-
-class SkBitmap;
namespace gfx {
class Canvas;
@@ -51,50 +45,17 @@ class StatusAreaHost;
// <icon> will show the strength of the wifi/cellular networks.
// The label will be BOLD if the network is currently connected.
class NetworkMenuButton : public StatusAreaButton,
- public views::ViewMenuDelegate,
- public menus::MenuModel,
+ public NetworkMenu,
public NetworkLibrary::Observer {
public:
explicit NetworkMenuButton(StatusAreaHost* host);
virtual ~NetworkMenuButton();
- // menus::MenuModel implementation.
- virtual bool HasIcons() const { return true; }
- virtual int GetItemCount() const;
- 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 const gfx::Font* GetLabelFontAt(int index) const;
- virtual bool GetAcceleratorAt(int index,
- menus::Accelerator* accelerator) const { return false; }
- virtual bool IsItemCheckedAt(int index) const;
- virtual int GetGroupIdAt(int index) const { return 0; }
- virtual bool GetIconAt(int index, SkBitmap* icon) const;
- virtual menus::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const {
- return NULL;
- }
- virtual bool IsEnabledAt(int index) const;
- virtual menus::MenuModel* GetSubmenuModelAt(int index) const { return NULL; }
- virtual void HighlightChangedTo(int index) {}
- virtual void ActivatedAt(int index);
- virtual void MenuWillShow() {}
-
// AnimationDelegate implementation.
virtual void AnimationProgressed(const Animation* animation);
// NetworkLibrary::Observer implementation.
virtual void NetworkChanged(NetworkLibrary* obj);
- virtual void NetworkTraffic(NetworkLibrary* cros, int traffic_type);
-
- // Returns the Icon for a network strength between 0 and 100.
- // |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);
-
- // This method will convert the |icon| bitmap to the correct size for display.
- // If the |badge| icon is not empty, it will draw that on top of the icon.
- static SkBitmap IconForDisplay(SkBitmap icon, SkBitmap badge);
// Sets the badge icon.
void SetBadge(const SkBitmap& badge);
@@ -105,62 +66,16 @@ class NetworkMenuButton : public StatusAreaButton,
virtual void DrawPressed(gfx::Canvas* canvas);
virtual void DrawIcon(gfx::Canvas* canvas);
- private:
- enum MenuItemFlags {
- FLAG_DISABLED = 1 << 0,
- FLAG_TOGGLE_ETHERNET = 1 << 1,
- FLAG_TOGGLE_WIFI = 1 << 2,
- FLAG_TOGGLE_CELLULAR = 1 << 3,
- FLAG_TOGGLE_OFFLINE = 1 << 4,
- FLAG_ASSOCIATED = 1 << 5,
- FLAG_ETHERNET = 1 << 6,
- FLAG_WIFI = 1 << 7,
- FLAG_CELLULAR = 1 << 8,
- FLAG_OPTIONS = 1 << 9,
- FLAG_OTHER_NETWORK = 1 << 10,
- };
-
- struct MenuItem {
- MenuItem()
- : type(menus::MenuModel::TYPE_SEPARATOR),
- flags(0) {}
- MenuItem(menus::MenuModel::ItemType type, string16 label, SkBitmap icon,
- const std::string& wireless_path, int flags)
- : type(type),
- label(label),
- icon(icon),
- wireless_path(wireless_path),
- flags(flags) {}
-
- menus::MenuModel::ItemType type;
- string16 label;
- SkBitmap icon;
- std::string wireless_path;
- int flags;
- };
- typedef std::vector<MenuItem> MenuItemVector;
-
- // views::ViewMenuDelegate implementation.
- virtual void RunMenu(views::View* source, const gfx::Point& pt);
-
- // Called by RunMenu to initialize our list of menu items.
- void InitMenuItems();
-
- // Set to true if we are currently refreshing the menu.
- bool refreshing_menu_;
-
- // The number of wifi strength images.
- static const int kNumWifiImages;
-
- // Our menu items.
- MenuItemVector menu_items_;
+ // NetworkMenu implementation:
+ virtual bool IsBrowserMode() const;
+ virtual gfx::NativeWindow GetNativeWindow() const;
+ virtual void OpenButtonOptions() const;
+ virtual bool ShouldOpenButtonOptions() const;
+ private:
// The status area host,
StatusAreaHost* host_;
- // The network menu.
- views::Menu2 network_menu_;
-
// A badge icon displayed on top of the icon.
SkBitmap badge_;
diff --git a/chrome/browser/chromeos/status/power_menu_button.cc b/chrome/browser/chromeos/status/power_menu_button.cc
index de10159..de942cb 100644
--- a/chrome/browser/chromeos/status/power_menu_button.cc
+++ b/chrome/browser/chromeos/status/power_menu_button.cc
@@ -6,7 +6,9 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
@@ -22,9 +24,13 @@ const int PowerMenuButton::kNumPowerImages = 12;
PowerMenuButton::PowerMenuButton()
: StatusAreaButton(this),
- ALLOW_THIS_IN_INITIALIZER_LIST(power_menu_(this)),
- icon_id_(-1) {
- UpdateIcon();
+ battery_is_present_(false),
+ line_power_on_(false),
+ battery_fully_charged_(false),
+ battery_percentage_(0.0),
+ icon_id_(-1),
+ ALLOW_THIS_IN_INITIALIZER_LIST(power_menu_(this)) {
+ UpdateIconAndLabelInfo();
CrosLibrary::Get()->GetPowerLibrary()->AddObserver(this);
}
@@ -44,45 +50,44 @@ menus::MenuModel::ItemType PowerMenuButton::GetTypeAt(int index) const {
}
string16 PowerMenuButton::GetLabelAt(int index) const {
- PowerLibrary* cros = CrosLibrary::Get()->GetPowerLibrary();
// The first item shows the percentage of battery left.
if (index == 0) {
- // If fully charged, always show 100% even if internal number is a bit less.
- double percent = cros->battery_fully_charged() ? 100 :
- cros->battery_percentage();
return l10n_util::GetStringFUTF16(IDS_STATUSBAR_BATTERY_PERCENTAGE,
- IntToString16(static_cast<int>(percent)));
- }
-
- // The second item shows the battery is charged if it is.
- if (cros->battery_fully_charged())
- return l10n_util::GetStringUTF16(IDS_STATUSBAR_BATTERY_IS_CHARGED);
-
- // If battery is in an intermediate charge state, we show how much time left.
- base::TimeDelta time = cros->line_power_on() ? cros->battery_time_to_full() :
- cros->battery_time_to_empty();
- if (time.InSeconds() == 0) {
- // If time is 0, then that means we are still calculating how much time.
- // Depending if line power is on, we either show a message saying that we
- // are calculating time until full or calculating remaining time.
- int msg = cros->line_power_on() ?
- IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_FULL :
- IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_EMPTY;
- return l10n_util::GetStringUTF16(msg);
+ base::IntToString16(static_cast<int>(battery_percentage_)));
+ } else if (index == 1) {
+ // The second item shows the battery is charged if it is.
+ if (battery_fully_charged_)
+ return l10n_util::GetStringUTF16(IDS_STATUSBAR_BATTERY_IS_CHARGED);
+
+ // If battery is in an intermediate charge state, show how much time left.
+ base::TimeDelta time = line_power_on_ ? battery_time_to_full_ :
+ battery_time_to_empty_;
+ if (time.InSeconds() == 0) {
+ // If time is 0, then that means we are still calculating how much time.
+ // Depending if line power is on, we either show a message saying that we
+ // are calculating time until full or calculating remaining time.
+ int msg = line_power_on_ ?
+ IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_FULL :
+ IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_EMPTY;
+ return l10n_util::GetStringUTF16(msg);
+ } else {
+ // Depending if line power is on, we either show a message saying XX:YY
+ // until full or XX:YY remaining where XX is number of hours and YY is
+ // number of minutes.
+ int msg = line_power_on_ ? IDS_STATUSBAR_BATTERY_TIME_UNTIL_FULL :
+ IDS_STATUSBAR_BATTERY_TIME_UNTIL_EMPTY;
+ int hour = time.InHours();
+ int min = (time - base::TimeDelta::FromHours(hour)).InMinutes();
+ string16 hour_str = base::IntToString16(hour);
+ string16 min_str = base::IntToString16(min);
+ // Append a "0" before the minute if it's only a single digit.
+ if (min < 10)
+ min_str = ASCIIToUTF16("0") + min_str;
+ return l10n_util::GetStringFUTF16(msg, hour_str, min_str);
+ }
} else {
- // Depending if line power is on, we either show a message saying XX:YY
- // until full or XX:YY remaining where XX is number of hours and YY is
- // number of minutes.
- int msg = cros->line_power_on() ? IDS_STATUSBAR_BATTERY_TIME_UNTIL_FULL :
- IDS_STATUSBAR_BATTERY_TIME_UNTIL_EMPTY;
- int hour = time.InHours();
- int min = (time - base::TimeDelta::FromHours(hour)).InMinutes();
- string16 hour_str = IntToString16(hour);
- string16 min_str = IntToString16(min);
- // Append a "0" before the minute if it's only a single digit.
- if (min < 10)
- min_str = ASCIIToUTF16("0") + min_str;
- return l10n_util::GetStringFUTF16(msg, hour_str, min_str);
+ NOTREACHED();
+ return string16();
}
}
@@ -99,7 +104,7 @@ void PowerMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
// PowerMenuButton, PowerLibrary::Observer implementation:
void PowerMenuButton::PowerChanged(PowerLibrary* obj) {
- UpdateIcon();
+ UpdateIconAndLabelInfo();
}
////////////////////////////////////////////////////////////////////////////////
@@ -120,59 +125,74 @@ void PowerMenuButton::DrawPowerIcon(gfx::Canvas* canvas, SkBitmap icon) {
canvas->DrawBitmapInt(icon, 0, kIconVerticalPadding);
}
-void PowerMenuButton::UpdateIcon() {
+void PowerMenuButton::UpdateIconAndLabelInfo() {
PowerLibrary* cros = CrosLibrary::Get()->GetPowerLibrary();
- icon_id_ = IDR_STATUSBAR_BATTERY_UNKNOWN;
- if (CrosLibrary::Get()->EnsureLoaded()) {
- if (!cros->battery_is_present()) {
- icon_id_ = IDR_STATUSBAR_BATTERY_MISSING;
- } else if (cros->line_power_on() && cros->battery_fully_charged()) {
- icon_id_ = IDR_STATUSBAR_BATTERY_CHARGED;
- } else {
- // Get the power image depending on battery percentage. Percentage is
- // from 0 to 100, so we need to convert that to 0 to kNumPowerImages - 1.
- // NOTE: Use an array rather than just calculating a resource number to
- // avoid creating implicit ordering dependencies on the resource values.
- static const int kChargingImages[kNumPowerImages] = {
- IDR_STATUSBAR_BATTERY_CHARGING_1,
- IDR_STATUSBAR_BATTERY_CHARGING_2,
- IDR_STATUSBAR_BATTERY_CHARGING_3,
- IDR_STATUSBAR_BATTERY_CHARGING_4,
- IDR_STATUSBAR_BATTERY_CHARGING_5,
- IDR_STATUSBAR_BATTERY_CHARGING_6,
- IDR_STATUSBAR_BATTERY_CHARGING_7,
- IDR_STATUSBAR_BATTERY_CHARGING_8,
- IDR_STATUSBAR_BATTERY_CHARGING_9,
- IDR_STATUSBAR_BATTERY_CHARGING_10,
- IDR_STATUSBAR_BATTERY_CHARGING_11,
- IDR_STATUSBAR_BATTERY_CHARGING_12,
- };
- static const int kDischargingImages[kNumPowerImages] = {
- IDR_STATUSBAR_BATTERY_DISCHARGING_1,
- IDR_STATUSBAR_BATTERY_DISCHARGING_2,
- IDR_STATUSBAR_BATTERY_DISCHARGING_3,
- IDR_STATUSBAR_BATTERY_DISCHARGING_4,
- IDR_STATUSBAR_BATTERY_DISCHARGING_5,
- IDR_STATUSBAR_BATTERY_DISCHARGING_6,
- IDR_STATUSBAR_BATTERY_DISCHARGING_7,
- IDR_STATUSBAR_BATTERY_DISCHARGING_8,
- IDR_STATUSBAR_BATTERY_DISCHARGING_9,
- IDR_STATUSBAR_BATTERY_DISCHARGING_10,
- IDR_STATUSBAR_BATTERY_DISCHARGING_11,
- IDR_STATUSBAR_BATTERY_DISCHARGING_12,
- };
-
- // If fully charged, always show 100% even if percentage is a bit less.
- double percent = cros->battery_fully_charged() ?
- 100 : cros->battery_percentage();
- int index = static_cast<int>(percent / 100.0 *
- nextafter(static_cast<float>(kNumPowerImages), 0));
- index = std::max(std::min(index, kNumPowerImages - 1), 0);
- icon_id_ = cros->line_power_on() ?
- kChargingImages[index] : kDischargingImages[index];
- }
+ if (!cros)
+ return;
+
+ bool cros_loaded = CrosLibrary::Get()->EnsureLoaded();
+ if (cros_loaded) {
+ battery_is_present_ = cros->battery_is_present();
+ line_power_on_ = cros->line_power_on();
+ battery_fully_charged_ = cros->battery_fully_charged();
+ battery_percentage_ = cros->battery_percentage();
+ // If fully charged, always show 100% even if internal number is a bit less.
+ // Note: we always call cros->battery_percentage() for test predictability.
+ if (battery_fully_charged_)
+ battery_percentage_ = 100.0;
+ battery_time_to_full_ = cros->battery_time_to_full();
+ battery_time_to_empty_ = cros->battery_time_to_empty();
+ }
+
+ if (!cros_loaded) {
+ icon_id_ = IDR_STATUSBAR_BATTERY_UNKNOWN;
+ } else if (!battery_is_present_) {
+ icon_id_ = IDR_STATUSBAR_BATTERY_MISSING;
+ } else if (line_power_on_ && battery_fully_charged_) {
+ icon_id_ = IDR_STATUSBAR_BATTERY_CHARGED;
+ } else {
+ // Get the power image depending on battery percentage. Percentage is
+ // from 0 to 100, so we need to convert that to 0 to kNumPowerImages - 1.
+ // NOTE: Use an array rather than just calculating a resource number to
+ // avoid creating implicit ordering dependencies on the resource values.
+ static const int kChargingImages[kNumPowerImages] = {
+ IDR_STATUSBAR_BATTERY_CHARGING_1,
+ IDR_STATUSBAR_BATTERY_CHARGING_2,
+ IDR_STATUSBAR_BATTERY_CHARGING_3,
+ IDR_STATUSBAR_BATTERY_CHARGING_4,
+ IDR_STATUSBAR_BATTERY_CHARGING_5,
+ IDR_STATUSBAR_BATTERY_CHARGING_6,
+ IDR_STATUSBAR_BATTERY_CHARGING_7,
+ IDR_STATUSBAR_BATTERY_CHARGING_8,
+ IDR_STATUSBAR_BATTERY_CHARGING_9,
+ IDR_STATUSBAR_BATTERY_CHARGING_10,
+ IDR_STATUSBAR_BATTERY_CHARGING_11,
+ IDR_STATUSBAR_BATTERY_CHARGING_12,
+ };
+ static const int kDischargingImages[kNumPowerImages] = {
+ IDR_STATUSBAR_BATTERY_DISCHARGING_1,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_2,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_3,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_4,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_5,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_6,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_7,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_8,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_9,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_10,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_11,
+ IDR_STATUSBAR_BATTERY_DISCHARGING_12,
+ };
+
+ int index = static_cast<int>(battery_percentage_ / 100.0 *
+ nextafter(static_cast<float>(kNumPowerImages), 0));
+ index = std::max(std::min(index, kNumPowerImages - 1), 0);
+ icon_id_ = line_power_on_ ?
+ kChargingImages[index] : kDischargingImages[index];
}
+
SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed(icon_id_));
+ SetTooltipText(UTF16ToWide(GetLabelAt(0)));
SchedulePaint();
}
diff --git a/chrome/browser/chromeos/status/power_menu_button.h b/chrome/browser/chromeos/status/power_menu_button.h
index 413b744..7f27333 100644
--- a/chrome/browser/chromeos/status/power_menu_button.h
+++ b/chrome/browser/chromeos/status/power_menu_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_POWER_MENU_BUTTON_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_POWER_MENU_BUTTON_H_
+#pragma once
#include "app/menus/menu_model.h"
#include "chrome/browser/chromeos/cros/power_library.h"
@@ -11,6 +12,10 @@
#include "views/controls/menu/menu_2.h"
#include "views/controls/menu/view_menu_delegate.h"
+namespace base {
+class TimeDelta;
+}
+
class SkBitmap;
namespace chromeos {
@@ -63,18 +68,27 @@ class PowerMenuButton : public StatusAreaButton,
// This method will draw the |icon| in the appropriate place on the |canvas|.
void DrawPowerIcon(gfx::Canvas* canvas, SkBitmap icon);
- // Update the power icon depending on the power status.
- void UpdateIcon();
+ // Update the power icon and menu label info depending on the power status.
+ void UpdateIconAndLabelInfo();
// The number of power images.
static const int kNumPowerImages;
- // The power menu.
- views::Menu2 power_menu_;
+ // Stored data gathered from CrosLibrary::PowerLibrary.
+ bool battery_is_present_;
+ bool line_power_on_;
+ bool battery_fully_charged_;
+ double battery_percentage_;
+ base::TimeDelta battery_time_to_full_;
+ base::TimeDelta battery_time_to_empty_;
// The currently showing icon bitmap id.
int icon_id_;
+ // The power menu. This needs to be initialized last since it calls into
+ // GetLabelAt() during construction.
+ views::Menu2 power_menu_;
+
DISALLOW_COPY_AND_ASSIGN(PowerMenuButton);
};
diff --git a/chrome/browser/chromeos/status/power_menu_button_browsertest.cc b/chrome/browser/chromeos/status/power_menu_button_browsertest.cc
index 62ffab6..66042fd 100644
--- a/chrome/browser/chromeos/status/power_menu_button_browsertest.cc
+++ b/chrome/browser/chromeos/status/power_menu_button_browsertest.cc
@@ -22,11 +22,16 @@ using ::testing::_;
class PowerMenuButtonTest : public CrosInProcessBrowserTest {
protected:
- PowerMenuButtonTest() : CrosInProcessBrowserTest() {}
+ MockPowerLibrary *mock_power_library_;
+
+ PowerMenuButtonTest() : CrosInProcessBrowserTest(),
+ mock_power_library_(NULL) {
+ }
virtual void SetUpInProcessBrowserTestFixture() {
- InitStatusAreaMocks();
- SetStatusAreaMocksExpectations();
+ cros_mock_->InitStatusAreaMocks();
+ cros_mock_->SetStatusAreaMocksExpectations();
+ mock_power_library_ = cros_mock_->mock_power_library();
}
PowerMenuButton* GetPowerMenuButton() {
@@ -45,27 +50,70 @@ class PowerMenuButtonTest : public CrosInProcessBrowserTest {
IN_PROC_BROWSER_TEST_F(PowerMenuButtonTest, BatteryMissingTest) {
EXPECT_CALL(*mock_power_library_, battery_is_present())
- .WillRepeatedly((Return(false)));
+ .WillOnce((Return(false))) // no battery
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_percentage())
+ .WillOnce((Return(42.0)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_fully_charged())
+ .WillOnce((Return(false)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, line_power_on())
+ .WillOnce((Return(false)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_empty())
+ .WillOnce((Return(base::TimeDelta::FromMinutes(42))))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_full())
+ .WillOnce((Return(base::TimeDelta::FromMinutes(24))))
+ .RetiresOnSaturation();
EXPECT_EQ(IDR_STATUSBAR_BATTERY_MISSING, CallPowerChangedAndGetIconId());
}
IN_PROC_BROWSER_TEST_F(PowerMenuButtonTest, BatteryChargedTest) {
EXPECT_CALL(*mock_power_library_, battery_is_present())
- .WillRepeatedly((Return(true)));
+ .WillOnce((Return(true)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_percentage())
+ .WillOnce((Return(42.0)))
+ .RetiresOnSaturation();
EXPECT_CALL(*mock_power_library_, battery_fully_charged())
- .WillRepeatedly((Return(true)));
+ .WillOnce((Return(true))) // fully charged
+ .RetiresOnSaturation();
EXPECT_CALL(*mock_power_library_, line_power_on())
- .WillRepeatedly((Return(true)));
+ .WillOnce((Return(true))) // plugged in
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_empty())
+ .WillOnce((Return(base::TimeDelta::FromMinutes(42))))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_full())
+ .WillOnce((Return(base::TimeDelta::FromMinutes(0))))
+ .RetiresOnSaturation();
EXPECT_EQ(IDR_STATUSBAR_BATTERY_CHARGED, CallPowerChangedAndGetIconId());
}
IN_PROC_BROWSER_TEST_F(PowerMenuButtonTest, BatteryChargingTest) {
+ const int NUM_TIMES = 12; // 6 + 8*12 = 102
EXPECT_CALL(*mock_power_library_, battery_is_present())
- .WillRepeatedly((Return(true)));
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(true)))
+ .RetiresOnSaturation();
EXPECT_CALL(*mock_power_library_, battery_fully_charged())
- .WillRepeatedly((Return(false)));
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(false)))
+ .RetiresOnSaturation();
EXPECT_CALL(*mock_power_library_, line_power_on())
- .WillRepeatedly((Return(true)));
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(true))) // plugged in
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_empty())
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(base::TimeDelta::FromMinutes(42))))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_full())
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(base::TimeDelta::FromMinutes(24))))
+ .RetiresOnSaturation();
// Test the 12 battery charging states.
// NOTE: Use an array rather than just calculating a resource number to avoid
@@ -87,7 +135,8 @@ IN_PROC_BROWSER_TEST_F(PowerMenuButtonTest, BatteryChargingTest) {
size_t id = 0;
for (float percent = 6.0; percent < 100.0; percent += 8.0) {
EXPECT_CALL(*mock_power_library_, battery_percentage())
- .WillRepeatedly((Return(percent)));
+ .WillOnce((Return(percent)))
+ .RetiresOnSaturation();
ASSERT_LT(id, arraysize(kChargingImages));
EXPECT_EQ(kChargingImages[id], CallPowerChangedAndGetIconId());
id++;
@@ -95,12 +144,27 @@ IN_PROC_BROWSER_TEST_F(PowerMenuButtonTest, BatteryChargingTest) {
}
IN_PROC_BROWSER_TEST_F(PowerMenuButtonTest, BatteryDischargingTest) {
+ const int NUM_TIMES = 12; // 6 + 8*12 = 102
EXPECT_CALL(*mock_power_library_, battery_is_present())
- .WillRepeatedly((Return(true)));
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(true)))
+ .RetiresOnSaturation();
EXPECT_CALL(*mock_power_library_, battery_fully_charged())
- .WillRepeatedly((Return(false)));
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(false)))
+ .RetiresOnSaturation();
EXPECT_CALL(*mock_power_library_, line_power_on())
- .WillRepeatedly((Return(false)));
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(false)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_empty())
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(base::TimeDelta::FromMinutes(42))))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*mock_power_library_, battery_time_to_full())
+ .Times(NUM_TIMES)
+ .WillRepeatedly((Return(base::TimeDelta::FromMinutes(24))))
+ .RetiresOnSaturation();
// Test the 12 battery discharing states.
// NOTE: Use an array rather than just calculating a resource number to avoid
@@ -122,7 +186,8 @@ IN_PROC_BROWSER_TEST_F(PowerMenuButtonTest, BatteryDischargingTest) {
size_t id = 0;
for (float percent = 6.0; percent < 100.0; percent += 8.0) {
EXPECT_CALL(*mock_power_library_, battery_percentage())
- .WillRepeatedly((Return(percent)));
+ .WillOnce((Return(percent)))
+ .RetiresOnSaturation();
ASSERT_LT(id, arraysize(kDischargingImages));
EXPECT_EQ(kDischargingImages[id], CallPowerChangedAndGetIconId());
id++;
diff --git a/chrome/browser/chromeos/status/status_area_button.cc b/chrome/browser/chromeos/status/status_area_button.cc
index 13aaad2..d2c34e6 100644
--- a/chrome/browser/chromeos/status/status_area_button.cc
+++ b/chrome/browser/chromeos/status/status_area_button.cc
@@ -1,10 +1,9 @@
-// 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.
#include "chrome/browser/chromeos/status/status_area_button.h"
-#include "app/resource_bundle.h"
#include "gfx/canvas.h"
#include "gfx/skbitmap_operations.h"
#include "grit/theme_resources.h"
@@ -17,29 +16,70 @@ namespace chromeos {
// StatusAreaButton
StatusAreaButton::StatusAreaButton(views::ViewMenuDelegate* menu_delegate)
- : MenuButton(NULL, std::wstring(), menu_delegate, false) {
+ : MenuButton(NULL, std::wstring(), menu_delegate, false),
+ use_menu_button_paint_(false) {
set_border(NULL);
- SetShowHighlighted(true);
+
+ // Use an offset that is top aligned with toolbar.
+ set_menu_offset(0, 2);
}
void StatusAreaButton::Paint(gfx::Canvas* canvas, bool for_drag) {
if (state() == BS_PUSHED) {
- DrawPressed(canvas);
+ // Apply 10% white when pushed down.
+ canvas->FillRectInt(SkColorSetARGB(0x19, 0xFF, 0xFF, 0xFF),
+ 0, 0, width(), height());
+ }
+
+ if (use_menu_button_paint_) {
+ views::MenuButton::Paint(canvas, for_drag);
+ } else {
+ if (state() == BS_PUSHED)
+ DrawPressed(canvas);
+
+ DrawIcon(canvas);
+ PaintFocusBorder(canvas);
}
- DrawIcon(canvas);
- PaintFocusBorder(canvas);
}
gfx::Size StatusAreaButton::GetPreferredSize() {
// icons are 24x24
static const int kIconWidth = 24;
static const int kIconHeight = 24;
- gfx::Insets insets = GetInsets();
+ gfx::Insets insets = views::MenuButton::GetInsets();
gfx::Size prefsize(kIconWidth + insets.width(),
kIconHeight + insets.height());
+
+ // Adjusts size when use menu button paint.
+ if (use_menu_button_paint_) {
+ gfx::Size menu_button_size = views::MenuButton::GetPreferredSize();
+ prefsize.SetSize(
+ std::max(prefsize.width(), menu_button_size.width()),
+ std::max(prefsize.height(), menu_button_size.height())
+ );
+
+ // Shift 1-pixel down for odd number of pixels in vertical space.
+ if ((prefsize.height() - menu_button_size.height()) % 2) {
+ insets_.Set(insets.top() + 1, insets.left(),
+ insets.bottom(), insets.right());
+ }
+ }
+
return prefsize;
}
+gfx::Insets StatusAreaButton::GetInsets() const {
+ return insets_;
+}
+
+void StatusAreaButton::SetText(const std::wstring& text) {
+ // TextButtons normally remember the max text size, so the button's preferred
+ // size will always be as large as the largest text ever put in it.
+ // We clear that max text size, so we can adjust the size to fit the text.
+ ClearMaxTextSize();
+ views::MenuButton::SetText(text);
+}
+
void StatusAreaButton::DrawIcon(gfx::Canvas* canvas) {
canvas->DrawBitmapInt(icon(), 0, 0);
}
diff --git a/chrome/browser/chromeos/status/status_area_button.h b/chrome/browser/chromeos/status/status_area_button.h
index b751653..6d57178 100644
--- a/chrome/browser/chromeos/status/status_area_button.h
+++ b/chrome/browser/chromeos/status/status_area_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_STATUS_AREA_BUTTON_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_STATUS_AREA_BUTTON_H_
+#pragma once
#include "views/controls/button/menu_button.h"
#include "views/controls/menu/view_menu_delegate.h"
@@ -18,6 +19,15 @@ class StatusAreaButton : public views::MenuButton {
virtual ~StatusAreaButton() {}
virtual void Paint(gfx::Canvas* canvas, bool for_drag);
virtual gfx::Size GetPreferredSize();
+ virtual gfx::Insets GetInsets() const;
+
+ // Overrides TextButton's SetText to clear max text size before seting new
+ // text content so that the button size would fit the new text size.
+ virtual void SetText(const std::wstring& text);
+
+ void set_use_menu_button_paint(bool use_menu_button_paint) {
+ use_menu_button_paint_ = use_menu_button_paint;
+ }
protected:
// Draws the pressed icon. This is called before DrawIcon if the state is
@@ -30,6 +40,12 @@ class StatusAreaButton : public views::MenuButton {
// Otherwise, just call SetIcon() and the it will be handled for you.
virtual void DrawIcon(gfx::Canvas* canvas);
+ // True if the button wants to use views::MenuButton drawings.
+ bool use_menu_button_paint_;
+
+ // Insets to use for this button.
+ gfx::Insets insets_;
+
DISALLOW_COPY_AND_ASSIGN(StatusAreaButton);
};
diff --git a/chrome/browser/chromeos/status/status_area_host.h b/chrome/browser/chromeos/status/status_area_host.h
index e61cf7c..7e86e67 100644
--- a/chrome/browser/chromeos/status/status_area_host.h
+++ b/chrome/browser/chromeos/status/status_area_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_STATUS_AREA_HOST_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_STATUS_AREA_HOST_H_
+#pragma once
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/chromeos/status/status_area_view.cc b/chrome/browser/chromeos/status/status_area_view.cc
index 4f08452..27a3a54 100644
--- a/chrome/browser/chromeos/status/status_area_view.cc
+++ b/chrome/browser/chromeos/status/status_area_view.cc
@@ -19,9 +19,6 @@ namespace chromeos {
// Number of pixels to separate each icon.
const int kSeparation = 6;
-// BrowserWindowGtk tiles its image with this offset
-const int kCustomFrameBackgroundVerticalOffset = 15;
-
StatusAreaView::StatusAreaView(StatusAreaHost* host)
: host_(host),
clock_view_(NULL),
diff --git a/chrome/browser/chromeos/status/status_area_view.h b/chrome/browser/chromeos/status/status_area_view.h
index d30378b..0e4ecc3 100644
--- a/chrome/browser/chromeos/status/status_area_view.h
+++ b/chrome/browser/chromeos/status/status_area_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_STATUS_STATUS_AREA_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_STATUS_STATUS_AREA_VIEW_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/views/accessible_toolbar_view.h"
diff --git a/chrome/browser/chromeos/system_key_event_listener.h b/chrome/browser/chromeos/system_key_event_listener.h
index 117a3a8..b731b94 100644
--- a/chrome/browser/chromeos/system_key_event_listener.h
+++ b/chrome/browser/chromeos/system_key_event_listener.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_KEY_EVENT_LISTENER_H_
#define CHROME_BROWSER_CHROMEOS_SYSTEM_KEY_EVENT_LISTENER_H_
+#pragma once
#include "base/singleton.h"
#include "chrome/browser/chromeos/wm_message_listener.h"
diff --git a/chrome/browser/chromeos/tab_closeable_state_watcher.cc b/chrome/browser/chromeos/tab_closeable_state_watcher.cc
index d5a01b0..7b7f2cb 100644
--- a/chrome/browser/chromeos/tab_closeable_state_watcher.cc
+++ b/chrome/browser/chromeos/tab_closeable_state_watcher.cc
@@ -4,10 +4,14 @@
#include "chrome/browser/chromeos/tab_closeable_state_watcher.h"
+#include "base/command_line.h"
+#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/profile.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/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
@@ -63,7 +67,9 @@ void TabCloseableStateWatcher::TabStripWatcher::TabChangedAt(
TabCloseableStateWatcher::TabCloseableStateWatcher()
: can_close_tab_(true),
- signing_off_(false) {
+ signing_off_(false),
+ bwsi_session_(
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kBWSI)) {
BrowserList::AddObserver(this);
notification_registrar_.Add(this, NotificationType::APP_EXITING,
NotificationService::AllSources());
@@ -71,7 +77,8 @@ TabCloseableStateWatcher::TabCloseableStateWatcher()
TabCloseableStateWatcher::~TabCloseableStateWatcher() {
BrowserList::RemoveObserver(this);
- DCHECK(tabstrip_watchers_.empty());
+ if (!browser_shutdown::ShuttingDownWithoutClosingBrowsers())
+ DCHECK(tabstrip_watchers_.empty());
}
bool TabCloseableStateWatcher::CanCloseTab(const Browser* browser) const {
@@ -183,7 +190,7 @@ void TabCloseableStateWatcher::CheckAndUpdateState(
} else { // There's only 1 normal browser.
if (!browser_to_check)
browser_to_check = tabstrip_watchers_[0]->browser();
- if (browser_to_check->profile()->IsOffTheRecord()) {
+ if (browser_to_check->profile()->IsOffTheRecord() && !bwsi_session_) {
new_can_close = true;
} else {
TabStripModel* tabstrip_model = browser_to_check->tabstrip_model();
@@ -232,8 +239,8 @@ bool TabCloseableStateWatcher::CanCloseBrowserImpl(const Browser* browser,
return true;
// If last normal browser is incognito, open a non-incognito window,
- // and allow closing of incognito one.
- if (browser->profile()->IsOffTheRecord()) {
+ // and allow closing of incognito one (if not BWSI).
+ if (browser->profile()->IsOffTheRecord() && !bwsi_session_) {
*action_type = OPEN_WINDOW;
return true;
}
diff --git a/chrome/browser/chromeos/tab_closeable_state_watcher.h b/chrome/browser/chromeos/tab_closeable_state_watcher.h
index 5b786f2..9da71f2 100644
--- a/chrome/browser/chromeos/tab_closeable_state_watcher.h
+++ b/chrome/browser/chromeos/tab_closeable_state_watcher.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_TAB_CLOSEABLE_STATE_WATCHER_H_
#define CHROME_BROWSER_CHROMEOS_TAB_CLOSEABLE_STATE_WATCHER_H_
+#pragma once
#include <vector>
#include "chrome/browser/browser_list.h"
#include "chrome/browser/tab_closeable_state_watcher.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
#include "chrome/common/notification_registrar.h"
namespace chromeos {
@@ -17,6 +18,8 @@ namespace chromeos {
// This class overrides ::TabCloseableStateWatcher to allow or disallow tabs or
// browsers to be closed based on increase or decrease in number of tabs or
// browsers. We only do this on Chromeos and only for non-tests.
+//
+// Normal session:
// 1) A tab, and hence its containing browser, is not closeable if the tab is
// the last NewTabPage in the last normal non-incognito browser and user is not
// signing off.
@@ -26,6 +29,15 @@ namespace chromeos {
// 3) Or, if user closes a normal incognito browser or the last tab in it, the
// browser closes, a new non-incognito normal browser is opened with a
// NewTabPage (which, by rule 1, will not be closeable).
+//
+// BWSI session (all browsers are incognito):
+// Almost the same as in the normal session, but
+// 1) A tab, and hence its containing browser, is not closeable if the tab is
+// the last NewTabPage in the last browser (again, all browsers are incognito
+// browsers).
+// 2-3) Otherwise, if user closes a normal incognito browser or the last tab in
+// it, the browser stays open, the existing tabs are closed, and a new
+// NewTabPage is open.
class TabCloseableStateWatcher : public ::TabCloseableStateWatcher,
public BrowserList::Observer,
@@ -86,6 +98,9 @@ class TabCloseableStateWatcher : public ::TabCloseableStateWatcher,
// allow closing of all tabs and browsers in this situation.
bool signing_off_;
+ // In BWSI session?
+ bool bwsi_session_;
+
NotificationRegistrar notification_registrar_;
// TabStripWatcher is a TabStripModelObserver that funnels all interesting
diff --git a/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc b/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc
index 3d01ab1..ea49119 100644
--- a/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc
+++ b/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc
@@ -1,16 +1,18 @@
-// 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.
#include "chrome/browser/chromeos/tab_closeable_state_watcher.h"
#include "base/file_path.h"
-#include "base/logging.h"
#include "chrome/browser/app_modal_dialog.h"
#include "chrome/browser/browser.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/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -36,7 +38,8 @@ class TabCloseableStateWatcherTest : public InProcessBrowserTest {
// Wrapper for Browser::AddTabWithURL
void AddTabWithURL(Browser* browser, const GURL& url) {
browser->AddTabWithURL(url, GURL(), PageTransition::TYPED, 0,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser);
// Wait for page to finish loading.
ui_test_utils::WaitForNavigation(
&browser->GetSelectedTabContents()->controller());
@@ -280,7 +283,7 @@ IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
TabContents* tab_contents = browser()->GetSelectedTabContents();
browser()->CloseWindow();
AppModalDialog* confirm = ui_test_utils::WaitForAppModalDialog();
- confirm->CancelWindow();
+ confirm->native_dialog()->CancelAppModalDialog();
ui_test_utils::RunAllPendingInMessageLoop();
EXPECT_EQ(1u, BrowserList::size());
EXPECT_EQ(browser(), *(BrowserList::begin()));
@@ -290,7 +293,7 @@ IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
// Close the browser.
browser()->CloseWindow();
confirm = ui_test_utils::WaitForAppModalDialog();
- confirm->AcceptWindow();
+ confirm->native_dialog()->AcceptAppModalDialog();
ui_test_utils::RunAllPendingInMessageLoop();
}
@@ -306,7 +309,7 @@ IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
// Close browser, click OK in BeforeUnload confirm dialog.
browser()->CloseWindow();
AppModalDialog* confirm = ui_test_utils::WaitForAppModalDialog();
- confirm->AcceptWindow();
+ confirm->native_dialog()->AcceptAppModalDialog();
NewTabObserver new_tab_observer(browser());
EXPECT_EQ(1u, BrowserList::size());
EXPECT_EQ(browser(), *(BrowserList::begin()));
@@ -315,4 +318,3 @@ IN_PROC_BROWSER_TEST_F(TabCloseableStateWatcherTest,
}
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/testdata/services_manifest.json b/chrome/browser/chromeos/testdata/services_manifest.json
deleted file mode 100644
index 5efb835..0000000
--- a/chrome/browser/chromeos/testdata/services_manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- // Required.
- "version": "1.0",
- "app_menu" : {
- "section_title" : "A partner application menu section title.",
- "web_apps" : [
- "http://localhost/a/1",
- "http://localhost/a/2",
- ],
- "support_page": "http://localhost/h",
- "extensions": [
- "http://localhost/e/1",
- "http://localhost/e/2",
- ],
- },
-
- // Optional.
- "initial_start_page": "http://localhost",
-}
diff --git a/chrome/browser/chromeos/testdata/startup_manifest.json b/chrome/browser/chromeos/testdata/startup_manifest.json
deleted file mode 100644
index 25521a2..0000000
--- a/chrome/browser/chromeos/testdata/startup_manifest.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- // Required.
- "version": "1.0",
- "product_sku" : "SKU",
-
- // Optional.
- "initial_locale" : "ru",
- "initial_timezone" : "Asia/Tokyo",
- "background_color" : "#880088",
- "registration_url" : "http://www.google.com",
- "setup_content" : [
- {
- "content_locale" : "en_US",
- "help_page" : "setup_content/en_US/help.html",
- "eula_page" : "setup_content/en_US/eula.html",
- },
- {
- "content_locale" : "ru",
- "help_page" : "setup_content/ru/help.html",
- "eula_page" : "setup_content/ru/eula.html",
- },
- ]
-}
diff --git a/chrome/browser/chromeos/update_browsertest.cc b/chrome/browser/chromeos/update_browsertest.cc
index 9dca0bb..bbb67c3 100644
--- a/chrome/browser/chromeos/update_browsertest.cc
+++ b/chrome/browser/chromeos/update_browsertest.cc
@@ -4,13 +4,13 @@
#include "base/ref_counted.h"
#include "base/utf_string_conversions.h"
-#include "chrome/test/automation/dom_element_proxy.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/chromeos/update_observer.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/common/url_constants.h"
+#include "chrome/test/automation/dom_element_proxy.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -34,7 +34,7 @@ void CallObservers(chromeos::MockUpdateLibrary* lib,
.WillRepeatedly((ReturnRef(x)))
.RetiresOnSaturation();
FOR_EACH_OBSERVER(chromeos::UpdateLibrary::Observer, *observers,
- Changed(lib));
+ UpdateStatusChanged(lib));
}
void FireSuccessSequence(chromeos::MockUpdateLibrary* lib,
diff --git a/chrome/browser/chromeos/update_observer.cc b/chrome/browser/chromeos/update_observer.cc
index ac1af56..60bd1e8 100644
--- a/chrome/browser/chromeos/update_observer.cc
+++ b/chrome/browser/chromeos/update_observer.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/chromeos/update_observer.h"
#include "app/l10n_util.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
@@ -15,52 +15,22 @@ namespace chromeos {
UpdateObserver::UpdateObserver(Profile* profile)
: notification_(profile, "update.chromeos", IDR_NOTIFICATION_UPDATE,
- l10n_util::GetStringUTF16(IDS_UPDATE_TITLE)),
- progress_(-1) {}
+ l10n_util::GetStringUTF16(IDS_UPDATE_TITLE)) {}
UpdateObserver::~UpdateObserver() {
notification_.Hide();
}
-void UpdateObserver::Changed(UpdateLibrary* object) {
- switch (object->status().status) {
- case UPDATE_STATUS_ERROR:
- notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_ERROR), true);
- break;
- case UPDATE_STATUS_IDLE:
- case UPDATE_STATUS_CHECKING_FOR_UPDATE:
- // Do nothing in these cases, we don't want to notify the user of the
- // check unless there is an update. We don't hide here because
- // we want the final state to be sticky.
- break;
- case UPDATE_STATUS_UPDATE_AVAILABLE:
- notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE),
- false);
- break;
- case UPDATE_STATUS_DOWNLOADING:
- {
- int progress = static_cast<int>(object->status().download_progress *
- 100.0);
- if (progress != progress_) {
- progress_ = progress;
- notification_.Show(l10n_util::GetStringFUTF16(IDS_UPDATE_DOWNLOADING,
- IntToString16(progress_)), false);
- }
- }
- break;
- case UPDATE_STATUS_VERIFYING:
- notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING),
- false);
- break;
- case UPDATE_STATUS_FINALIZING:
- notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING),
- false);
- break;
- case UPDATE_STATUS_UPDATED_NEED_REBOOT:
- notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED), true);
- break;
+void UpdateObserver::UpdateStatusChanged(UpdateLibrary* library) {
+#if 0
+ // TODO seanparent@chromium.org : This update should only be shown when an
+ // update is critical and should include a restart button using the
+ // update_engine restart API. Currently removed entirely per Kan's request.
+
+ if (library->status().status == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
+ notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED), true);
}
+#endif
}
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/update_observer.h b/chrome/browser/chromeos/update_observer.h
index e199958..3ec372b 100644
--- a/chrome/browser/chromeos/update_observer.h
+++ b/chrome/browser/chromeos/update_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_UPDATE_OBSERVER_H_
#define CHROME_BROWSER_CHROMEOS_UPDATE_OBSERVER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/time.h"
@@ -23,10 +24,9 @@ class UpdateObserver : public UpdateLibrary::Observer {
virtual ~UpdateObserver();
private:
- virtual void Changed(UpdateLibrary* object);
+ virtual void UpdateStatusChanged(UpdateLibrary* library);
SystemNotification notification_;
- int progress_; // Last displayed remaining time in minutes
DISALLOW_COPY_AND_ASSIGN(UpdateObserver);
};
diff --git a/chrome/browser/chromeos/usb_mount_observer.cc b/chrome/browser/chromeos/usb_mount_observer.cc
index d0e329f..fbfb501 100644
--- a/chrome/browser/chromeos/usb_mount_observer.cc
+++ b/chrome/browser/chromeos/usb_mount_observer.cc
@@ -8,8 +8,10 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/dom_ui/filebrowse_ui.h"
-#include "chrome/browser/pref_service.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 "chrome/common/url_constants.h"
namespace chromeos {
@@ -52,7 +54,11 @@ void USBMountObserver::OpenFileBrowse(const std::string& url,
bool small) {
Browser* browser;
Profile* profile;
- profile = BrowserList::GetLastActive()->profile();
+ browser = BrowserList::GetLastActive();
+ if (browser == NULL) {
+ return;
+ }
+ profile = browser->profile();
PrefService* pref_service = profile->GetPrefs();
if (!pref_service->GetBoolean(prefs::kLabsAdvancedFilesystemEnabled)) {
return;
diff --git a/chrome/browser/chromeos/usb_mount_observer.h b/chrome/browser/chromeos/usb_mount_observer.h
index 1dd78d3..5f30b31 100644
--- a/chrome/browser/chromeos/usb_mount_observer.h
+++ b/chrome/browser/chromeos/usb_mount_observer.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_CHROMEOS_USB_MOUNT_OBSERVER_H_
#define CHROME_BROWSER_CHROMEOS_USB_MOUNT_OBSERVER_H_
+#pragma once
#include <string>
#include <vector>
#include "chrome/browser/chromeos/cros/mount_library.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 "chrome/common/notification_registrar.h"
class Browser;
class Profile;
diff --git a/chrome/browser/chromeos/usb_mount_observer_browsertest.cc b/chrome/browser/chromeos/usb_mount_observer_browsertest.cc
index 3621067..e6a5c99 100644
--- a/chrome/browser/chromeos/usb_mount_observer_browsertest.cc
+++ b/chrome/browser/chromeos/usb_mount_observer_browsertest.cc
@@ -4,7 +4,6 @@
#include "base/ref_counted.h"
#include "base/utf_string_conversions.h"
-#include "chrome/test/automation/dom_element_proxy.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chromeos/cros/mock_mount_library.h"
@@ -12,6 +11,7 @@
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/url_constants.h"
+#include "chrome/test/automation/dom_element_proxy.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/chromeos/version_loader.cc b/chrome/browser/chromeos/version_loader.cc
index 9475205..e24b357 100644
--- a/chrome/browser/chromeos/version_loader.cc
+++ b/chrome/browser/chromeos/version_loader.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,6 +9,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/version_loader.h b/chrome/browser/chromeos/version_loader.h
index c7072b5..0e5acb5 100644
--- a/chrome/browser/chromeos/version_loader.h
+++ b/chrome/browser/chromeos/version_loader.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_VERSION_LOADER_H_
#define CHROME_BROWSER_CHROMEOS_VERSION_LOADER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/chromeos/view_ids.h b/chrome/browser/chromeos/view_ids.h
index 8f0e016..f8b2794 100644
--- a/chrome/browser/chromeos/view_ids.h
+++ b/chrome/browser/chromeos/view_ids.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_VIEW_IDS_H_
#define CHROME_BROWSER_CHROMEOS_VIEW_IDS_H_
+#pragma once
#include "chrome/browser/view_ids.h"
@@ -12,7 +13,6 @@ enum ChromeOSViewIds {
// Start with the offset that is big enough to avoid possible
// collison.
VIEW_ID_STATUS_AREA = VIEW_ID_PREDEFINED_COUNT + 10000,
- VIEW_ID_OTR_AVATAR,
};
#endif // CHROME_BROWSER_CHROMEOS_VIEW_IDS_H_
diff --git a/chrome/browser/chromeos/volume_bubble.cc b/chrome/browser/chromeos/volume_bubble.cc
index 9b7543a..6c71fb3 100644
--- a/chrome/browser/chromeos/volume_bubble.cc
+++ b/chrome/browser/chromeos/volume_bubble.cc
@@ -17,7 +17,7 @@ const int kBubbleShowTimeoutSec = 2;
const int kAnimationDurationMs = 200;
// Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost.
-const double kVolumeBubbleXRatio = 0.18;
+const double kVolumeBubbleXRatio = 0.5;
// Vertical gap from the bottom of the screen in pixels.
const int kVolumeBubbleBottomGap = 30;
diff --git a/chrome/browser/chromeos/volume_bubble.h b/chrome/browser/chromeos/volume_bubble.h
index 90bb034..c2da38e 100644
--- a/chrome/browser/chromeos/volume_bubble.h
+++ b/chrome/browser/chromeos/volume_bubble.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_H_
#define CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_H_
+#pragma once
-#include "app/active_window_watcher_x.h"
#include "app/slide_animation.h"
#include "base/singleton.h"
#include "chrome/browser/views/info_bubble.h"
diff --git a/chrome/browser/chromeos/volume_bubble_view.cc b/chrome/browser/chromeos/volume_bubble_view.cc
index 5aa99c1..7bb500f 100644
--- a/chrome/browser/chromeos/volume_bubble_view.cc
+++ b/chrome/browser/chromeos/volume_bubble_view.cc
@@ -6,8 +6,8 @@
#include <string>
-#include "app/l10n_util.h"
#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"
diff --git a/chrome/browser/chromeos/volume_bubble_view.h b/chrome/browser/chromeos/volume_bubble_view.h
index fbf77d2..f9ec0b0 100644
--- a/chrome/browser/chromeos/volume_bubble_view.h
+++ b/chrome/browser/chromeos/volume_bubble_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_VIEW_H_
#define CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_VIEW_H_
+#pragma once
#include "views/view.h"
diff --git a/chrome/browser/chromeos/wm_ipc.cc b/chrome/browser/chromeos/wm_ipc.cc
index 1bb9a52..1dd0af5 100644
--- a/chrome/browser/chromeos/wm_ipc.cc
+++ b/chrome/browser/chromeos/wm_ipc.cc
@@ -11,8 +11,8 @@ extern "C" {
#include "app/x11_util.h"
#include "base/logging.h"
-#include "base/singleton.h"
#include "base/scoped_ptr.h"
+#include "base/singleton.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/wm_ipc.h b/chrome/browser/chromeos/wm_ipc.h
index 6161749..92fef71 100644
--- a/chrome/browser/chromeos/wm_ipc.h
+++ b/chrome/browser/chromeos/wm_ipc.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_WM_IPC_H_
#define CHROME_BROWSER_CHROMEOS_WM_IPC_H_
+#pragma once
#include <gtk/gtk.h>
#include <map>
diff --git a/chrome/browser/chromeos/wm_message_listener.h b/chrome/browser/chromeos/wm_message_listener.h
index 5972889..f389c4c 100644
--- a/chrome/browser/chromeos/wm_message_listener.h
+++ b/chrome/browser/chromeos/wm_message_listener.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_WM_MESSAGE_LISTENER_H_
#define CHROME_BROWSER_CHROMEOS_WM_MESSAGE_LISTENER_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/chromeos/wm_overview_controller.cc b/chrome/browser/chromeos/wm_overview_controller.cc
index 5e40520..8fbd74f 100644
--- a/chrome/browser/chromeos/wm_overview_controller.cc
+++ b/chrome/browser/chromeos/wm_overview_controller.cc
@@ -20,6 +20,7 @@
#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/tabs/tab_strip_model.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/common/notification_service.h"
#include "views/widget/root_view.h"
diff --git a/chrome/browser/chromeos/wm_overview_controller.h b/chrome/browser/chromeos/wm_overview_controller.h
index 19a4ed0..c007b72 100644
--- a/chrome/browser/chromeos/wm_overview_controller.h
+++ b/chrome/browser/chromeos/wm_overview_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_CONTROLLER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/chromeos/wm_overview_fav_icon.cc b/chrome/browser/chromeos/wm_overview_fav_icon.cc
index 0568932..dea1b0e 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 "skia/ext/image_operations.h"
#include "cros/chromeos_wm_ipc_enums.h"
+#include "skia/ext/image_operations.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_fav_icon.h b/chrome/browser/chromeos/wm_overview_fav_icon.h
index 0d22498..d4b4427 100644
--- a/chrome/browser/chromeos/wm_overview_fav_icon.h
+++ b/chrome/browser/chromeos/wm_overview_fav_icon.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_FAV_ICON_H_
#define CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_FAV_ICON_H_
+#pragma once
#include "views/widget/widget_gtk.h"
diff --git a/chrome/browser/chromeos/wm_overview_snapshot.h b/chrome/browser/chromeos/wm_overview_snapshot.h
index 1257866..d6eeee0 100644
--- a/chrome/browser/chromeos/wm_overview_snapshot.h
+++ b/chrome/browser/chromeos/wm_overview_snapshot.h
@@ -4,11 +4,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_SNAPSHOT_H_
#define CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_SNAPSHOT_H_
+#pragma once
#include "third_party/skia/include/core/SkBitmap.h"
+#include "views/controls/image_view.h"
#include "views/view.h"
#include "views/widget/widget_gtk.h"
-#include "views/controls/image_view.h"
class Browser;
diff --git a/chrome/browser/chromeos/wm_overview_title.cc b/chrome/browser/chromeos/wm_overview_title.cc
index 2c21bc6..0325065 100644
--- a/chrome/browser/chromeos/wm_overview_title.cc
+++ b/chrome/browser/chromeos/wm_overview_title.cc
@@ -8,6 +8,7 @@
#include "app/x11_util.h"
#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/drop_shadow_label.h"
@@ -42,9 +43,9 @@ namespace {
// given value (well, unless the font at size 1 is taller than the
// given value).
Font FindFontThisHigh(int pixels, Font base) {
- Font font = Font::CreateFont(base.FontName(), 1);
+ Font font(base.GetFontName(), 1);
Font last_font = font;
- while (font.height() < pixels) {
+ while (font.GetHeight() < pixels) {
last_font = font;
font = font.DeriveFont(1, Font::BOLD);
}
diff --git a/chrome/browser/chromeos/wm_overview_title.h b/chrome/browser/chromeos/wm_overview_title.h
index 90e4bd5..b145432 100644
--- a/chrome/browser/chromeos/wm_overview_title.h
+++ b/chrome/browser/chromeos/wm_overview_title.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_TITLE_H_
#define CHROME_BROWSER_CHROMEOS_WM_OVERVIEW_TITLE_H_
+#pragma once
#include "base/string16.h"
#include "views/widget/widget_gtk.h"
diff --git a/chrome/browser/clipboard_dispatcher.h b/chrome/browser/clipboard_dispatcher.h
index 30273e7..8b9b4eb 100644
--- a/chrome/browser/clipboard_dispatcher.h
+++ b/chrome/browser/clipboard_dispatcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CLIPBOARD_DISPATCHER_H_
#define CHROME_BROWSER_CLIPBOARD_DISPATCHER_H_
+#pragma once
#include <vector>
@@ -38,4 +39,3 @@ class ClipboardDispatcher {
};
#endif // CHROME_BROWSER_CLIPBOARD_DISPATCHER_H_
-
diff --git a/chrome/browser/clipboard_dispatcher_gtk.cc b/chrome/browser/clipboard_dispatcher_gtk.cc
index ce7e39b..a448468 100644
--- a/chrome/browser/clipboard_dispatcher_gtk.cc
+++ b/chrome/browser/clipboard_dispatcher_gtk.cc
@@ -30,4 +30,3 @@ bool ClipboardDispatcher::ReadFilenames(Clipboard::Buffer buffer,
filenames->clear();
return false;
}
-
diff --git a/chrome/browser/clipboard_dispatcher_win.cc b/chrome/browser/clipboard_dispatcher_win.cc
index ce7e39b..a448468 100644
--- a/chrome/browser/clipboard_dispatcher_win.cc
+++ b/chrome/browser/clipboard_dispatcher_win.cc
@@ -30,4 +30,3 @@ bool ClipboardDispatcher::ReadFilenames(Clipboard::Buffer buffer,
filenames->clear();
return false;
}
-
diff --git a/chrome/browser/cocoa/about_ipc_bridge.h b/chrome/browser/cocoa/about_ipc_bridge.h
index 6ac1ec0..0d91e3c 100644
--- a/chrome/browser/cocoa/about_ipc_bridge.h
+++ b/chrome/browser/cocoa/about_ipc_bridge.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/about_ipc_controller.h b/chrome/browser/cocoa/about_ipc_controller.h
index e907af7..c6e8dc0 100644
--- a/chrome/browser/cocoa/about_ipc_controller.h
+++ b/chrome/browser/cocoa/about_ipc_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_ABOUT_IPC_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_ABOUT_IPC_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/about_ipc_controller.mm b/chrome/browser/cocoa/about_ipc_controller.mm
index 32a9933..ccccf8b 100644
--- a/chrome/browser/cocoa/about_ipc_controller.mm
+++ b/chrome/browser/cocoa/about_ipc_controller.mm
@@ -38,19 +38,19 @@
}
- (NSString*)message {
- if (data_.message_name == L"") {
+ 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::SysWideToNSString(data_.message_name);
+ return base::SysUTF8ToNSString(data_.message_name);
}
}
- (NSString*)flags {
- return base::SysWideToNSString(data_.flags);
+ return base::SysUTF8ToNSString(data_.flags);
}
- (NSString*)dispatch {
@@ -68,7 +68,7 @@
}
- (NSString*)parameters {
- return base::SysWideToNSString(data_.params);
+ return base::SysUTF8ToNSString(data_.params);
}
@end
diff --git a/chrome/browser/cocoa/about_ipc_controller_unittest.mm b/chrome/browser/cocoa/about_ipc_controller_unittest.mm
index efe1a56..b36100a 100644
--- a/chrome/browser/cocoa/about_ipc_controller_unittest.mm
+++ b/chrome/browser/cocoa/about_ipc_controller_unittest.mm
@@ -24,9 +24,9 @@ TEST_F(AboutIPCControllerTest, TestFilter) {
IPC::LogData data;
// Make sure generic names do NOT get filtered.
- std::wstring names[] = { L"PluginProcessingIsMyLife",
- L"ViewMsgFoo",
- L"NPObjectHell" };
+ 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]
@@ -35,7 +35,7 @@ TEST_F(AboutIPCControllerTest, TestFilter) {
}
// Flip a checkbox, see it filtered, flip back, all is fine.
- data.message_name = L"ViewMsgFoo";
+ data.message_name = "ViewMsgFoo";
scoped_nsobject<CocoaLogData> cdata([[CocoaLogData alloc]
initWithLogData:data]);
[controller setDisplayViewMessages:NO];
diff --git a/chrome/browser/cocoa/about_ipc_dialog.h b/chrome/browser/cocoa/about_ipc_dialog.h
index e190f7a..c819769 100644
--- a/chrome/browser/cocoa/about_ipc_dialog.h
+++ b/chrome/browser/cocoa/about_ipc_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_ABOUT_IPC_DIALOG_H_
#define CHROME_BROWSER_COCOA_ABOUT_IPC_DIALOG_H_
+#pragma once
#include "ipc/ipc_message.h"
diff --git a/chrome/browser/cocoa/about_window_controller.h b/chrome/browser/cocoa/about_window_controller.h
index 99e6073..6578c46 100644
--- a/chrome/browser/cocoa/about_window_controller.h
+++ b/chrome/browser/cocoa/about_window_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
+#pragma once
#import <AppKit/AppKit.h>
diff --git a/chrome/browser/cocoa/about_window_controller.mm b/chrome/browser/cocoa/about_window_controller.mm
index 0b24762..bb8044c 100644
--- a/chrome/browser/cocoa/about_window_controller.mm
+++ b/chrome/browser/cocoa/about_window_controller.mm
@@ -4,10 +4,12 @@
#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"
@@ -131,10 +133,10 @@ static BOOL recentShownUserActionFailedStatus = NO;
NSString* versionModifier = @"";
NSString* svnRevision = @"";
- string16 modifier = platform_util::GetVersionStringModifier();
- if (modifier.length())
+ std::string modifier = platform_util::GetVersionStringModifier();
+ if (!modifier.empty())
versionModifier = [NSString stringWithFormat:@" %@",
- base::SysUTF16ToNSString(modifier)];
+ base::SysUTF8ToNSString(modifier)];
#if !defined(GOOGLE_CHROME_BUILD)
svnRevision = [NSString stringWithFormat:@" (%@)",
@@ -452,7 +454,7 @@ static BOOL recentShownUserActionFailedStatus = NO;
// just to get the throbber to stop spinning if it's running.
imageID = IDR_UPDATE_FAIL;
message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- IntToString16(status));
+ base::IntToString16(status));
break;
@@ -550,14 +552,14 @@ static BOOL recentShownUserActionFailedStatus = NO;
// just to get the throbber to stop spinning if it's running.
imageID = IDR_UPDATE_FAIL;
message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- IntToString16(status));
+ base::IntToString16(status));
break;
case kAutoupdateRegisterFailed:
imageID = IDR_UPDATE_FAIL;
message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- IntToString16(status));
+ base::IntToString16(status));
enablePromoteButton = false;
break;
@@ -565,7 +567,7 @@ static BOOL recentShownUserActionFailedStatus = NO;
case kAutoupdateCheckFailed:
imageID = IDR_UPDATE_FAIL;
message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- IntToString16(status));
+ base::IntToString16(status));
break;
@@ -574,7 +576,7 @@ static BOOL recentShownUserActionFailedStatus = NO;
imageID = IDR_UPDATE_FAIL;
message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- IntToString16(status));
+ base::IntToString16(status));
// Allow another chance.
enableUpdateButton = true;
@@ -586,7 +588,7 @@ static BOOL recentShownUserActionFailedStatus = NO;
imageID = IDR_UPDATE_FAIL;
message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- IntToString16(status));
+ base::IntToString16(status));
break;
diff --git a/chrome/browser/cocoa/about_window_controller_unittest.mm b/chrome/browser/cocoa/about_window_controller_unittest.mm
index 64a4f6d..3538dda 100644
--- a/chrome/browser/cocoa/about_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/about_window_controller_unittest.mm
@@ -10,6 +10,7 @@
#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 {
@@ -95,28 +96,23 @@ TEST_F(AboutWindowControllerTest, TestCallbacks) {
NSString *lastText = [[about_window_controller_ updateText]
stringValue];
PostAutoupdateStatusNotification(kAutoupdateCurrent, @"foo");
- ASSERT_FALSE([lastText isEqual:[[about_window_controller_ updateText]
- stringValue]]);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
lastText = [[about_window_controller_ updateText] stringValue];
PostAutoupdateStatusNotification(kAutoupdateCurrent, @"foo");
- ASSERT_TRUE([lastText isEqual:[[about_window_controller_ updateText]
- stringValue]]);
+ ASSERT_NSEQ(lastText, [[about_window_controller_ updateText] stringValue]);
lastText = [[about_window_controller_ updateText] stringValue];
PostAutoupdateStatusNotification(kAutoupdateCurrent, @"bar");
- ASSERT_FALSE([lastText isEqual:[[about_window_controller_ updateText]
- stringValue]]);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
lastText = [[about_window_controller_ updateText] stringValue];
PostAutoupdateStatusNotification(kAutoupdateAvailable, nil);
- ASSERT_FALSE([lastText isEqual:[[about_window_controller_ updateText]
- stringValue]]);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
lastText = [[about_window_controller_ updateText] stringValue];
PostAutoupdateStatusNotification(kAutoupdateCheckFailed, nil);
- ASSERT_FALSE([lastText isEqual:[[about_window_controller_ updateText]
- stringValue]]);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
#if 0
// TODO(mark): The kAutoupdateInstalled portion of the test is disabled
@@ -126,19 +122,16 @@ TEST_F(AboutWindowControllerTest, TestCallbacks) {
lastText = [[about_window_controller_ updateText] stringValue];
PostAutoupdateStatusNotification(kAutoupdateInstalled, @"ver");
- ASSERT_FALSE([lastText isEqual:[[about_window_controller_ updateText]
- stringValue]]);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
lastText = [[about_window_controller_ updateText] stringValue];
PostAutoupdateStatusNotification(kAutoupdateInstalled, nil);
- ASSERT_FALSE([lastText isEqual:[[about_window_controller_ updateText]
- stringValue]]);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
#endif
lastText = [[about_window_controller_ updateText] stringValue];
PostAutoupdateStatusNotification(kAutoupdateInstallFailed, nil);
- ASSERT_FALSE([lastText isEqual:[[about_window_controller_
- updateText] stringValue]]);
+ 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
index d4478f2..b8eaac8 100644
--- a/chrome/browser/cocoa/accelerators_cocoa.h
+++ b/chrome/browser/cocoa/accelerators_cocoa.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_ACCELERATORS_COCOA_H_
#define CHROME_BROWSER_COCOA_ACCELERATORS_COCOA_H_
+#pragma once
#include <map>
diff --git a/chrome/browser/cocoa/accelerators_cocoa.mm b/chrome/browser/cocoa/accelerators_cocoa.mm
index 8682997..86b4bd5 100644
--- a/chrome/browser/cocoa/accelerators_cocoa.mm
+++ b/chrome/browser/cocoa/accelerators_cocoa.mm
@@ -15,6 +15,7 @@ const struct AcceleratorMapping {
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 },
diff --git a/chrome/browser/cocoa/accelerators_cocoa_unittest.mm b/chrome/browser/cocoa/accelerators_cocoa_unittest.mm
index cac5c20..28b9986 100644
--- a/chrome/browser/cocoa/accelerators_cocoa_unittest.mm
+++ b/chrome/browser/cocoa/accelerators_cocoa_unittest.mm
@@ -9,13 +9,14 @@
#include "chrome/app/chrome_dll_resource.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_TRUE([@"c" isEqualToString:accelerator->characters()]);
+ EXPECT_NSEQ(@"c", accelerator->characters());
EXPECT_EQ(NSCommandKeyMask, accelerator->modifiers());
}
diff --git a/chrome/browser/cocoa/animatable_image.h b/chrome/browser/cocoa/animatable_image.h
index 74f9804..d61187d 100644
--- a/chrome/browser/cocoa/animatable_image.h
+++ b/chrome/browser/cocoa/animatable_image.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_ANIMATABLE_IMAGE_H_
#define CHROME_BROWSER_COCOA_ANIMATABLE_IMAGE_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>
diff --git a/chrome/browser/cocoa/animatable_image.mm b/chrome/browser/cocoa/animatable_image.mm
index db08224..1c73f55 100644
--- a/chrome/browser/cocoa/animatable_image.mm
+++ b/chrome/browser/cocoa/animatable_image.mm
@@ -5,6 +5,7 @@
#import "chrome/browser/cocoa/animatable_image.h"
#include "base/logging.h"
+#import "base/mac_util.h"
#include "base/scoped_cftyperef.h"
#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
@@ -126,36 +127,13 @@
[CATransaction commit];
}
-// CALayer expects a CGImageRef contents. If the image is a PDF, 10.5 CGImage
-// cannot handle the conversion to bitmap. To get it to work, rasterize the
-// image into a bitmap CGImageRef. This is based loosely on
-// http://www.cocoadev.com/index.pl?CGImageRef.
+// Sets the layer contents by converting the NSImage to a CGImageRef. This will
+// rasterize PDF resources.
- (void)setLayerContents:(CALayer*)layer {
- NSSize size = [image_ size];
- CGContextRef context =
- CGBitmapContextCreate(NULL, // Allow CG to allocate memory.
- size.width,
- size.height,
- 8, // bitsPerComponent
- 0, // bytesPerRow - CG will calculate by default.
- [[NSColorSpace genericRGBColorSpace] CGColorSpace],
- kCGBitmapByteOrder32Host |
- kCGImageAlphaPremultipliedFirst);
-
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:
- [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]];
- [image_ drawInRect:NSMakeRect(0,0, size.width, size.height)
- fromRect:NSZeroRect
- operation:NSCompositeCopy
- fraction:1.0];
- [NSGraphicsContext restoreGraphicsState];
-
- scoped_cftyperef<CGImageRef> cgImage(CGBitmapContextCreateImage(context));
- CGContextRelease(context);
-
+ scoped_cftyperef<CGImageRef> image(
+ mac_util::CopyNSImageToCGImage(image_.get()));
// Create the layer that will be animated.
- [layer setContents:(id)cgImage.get()];
+ [layer setContents:(id)image.get()];
}
// CAAnimation delegate method called when the animation is complete.
diff --git a/chrome/browser/cocoa/animatable_image_unittest.mm b/chrome/browser/cocoa/animatable_image_unittest.mm
index 2fc9577..af2bc6a 100644
--- a/chrome/browser/cocoa/animatable_image_unittest.mm
+++ b/chrome/browser/cocoa/animatable_image_unittest.mm
@@ -33,4 +33,14 @@ TEST_F(AnimatableImageTest, BasicAnimation) {
[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
index 9221095..9c8a456 100644
--- a/chrome/browser/cocoa/animatable_view.h
+++ b/chrome/browser/cocoa/animatable_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
#define CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/authorization_util.h b/chrome/browser/cocoa/authorization_util.h
index 9370949..d5daf4a 100644
--- a/chrome/browser/cocoa/authorization_util.h
+++ b/chrome/browser/cocoa/authorization_util.h
@@ -4,6 +4,7 @@
#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
diff --git a/chrome/browser/cocoa/authorization_util.mm b/chrome/browser/cocoa/authorization_util.mm
index a879db2..e255993 100644
--- a/chrome/browser/cocoa/authorization_util.mm
+++ b/chrome/browser/cocoa/authorization_util.mm
@@ -13,6 +13,7 @@
#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"
@@ -47,7 +48,8 @@ AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
// The OS will append " Type an administrator's name and password to allow
// <CFBundleDisplayName> to make changes."
- NSString* prompt_ns = reinterpret_cast<const NSString*>(prompt);
+ 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;
@@ -118,7 +120,7 @@ OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
--line_length;
}
std::string line(line_c, line_length);
- if (!StringToInt(line, &line_pid)) {
+ 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;
diff --git a/chrome/browser/cocoa/back_forward_menu_controller.h b/chrome/browser/cocoa/back_forward_menu_controller.h
index bb3dad0..8e0bef1 100644
--- a/chrome/browser/cocoa/back_forward_menu_controller.h
+++ b/chrome/browser/cocoa/back_forward_menu_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/background_gradient_view.h b/chrome/browser/cocoa/background_gradient_view.h
index db6aa9e..be5a433 100644
--- a/chrome/browser/cocoa/background_gradient_view.h
+++ b/chrome/browser/cocoa/background_gradient_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BACKGROUND_GRADIENT_VIEW_H_
#define CHROME_BROWSER_COCOA_BACKGROUND_GRADIENT_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/background_gradient_view.mm b/chrome/browser/cocoa/background_gradient_view.mm
index 7dd93b6..9910412 100644
--- a/chrome/browser/cocoa/background_gradient_view.mm
+++ b/chrome/browser/cocoa/background_gradient_view.mm
@@ -4,8 +4,8 @@
#include "chrome/browser/cocoa/background_gradient_view.h"
-#import "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/themed_window.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
#include "grit/theme_resources.h"
#define kToolbarTopOffset 12
diff --git a/chrome/browser/cocoa/background_tile_view.h b/chrome/browser/cocoa/background_tile_view.h
index 70760c0..1b947c5 100644
--- a/chrome/browser/cocoa/background_tile_view.h
+++ b/chrome/browser/cocoa/background_tile_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
#define CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/base_bubble_controller.h b/chrome/browser/cocoa/base_bubble_controller.h
index 795f1a1..51cfa58 100644
--- a/chrome/browser/cocoa/base_bubble_controller.h
+++ b/chrome/browser/cocoa/base_bubble_controller.h
@@ -5,8 +5,6 @@
#import <Cocoa/Cocoa.h>
#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
@class InfoBubbleView;
diff --git a/chrome/browser/cocoa/base_view.h b/chrome/browser/cocoa/base_view.h
index d59a2c2..c3d49fd 100644
--- a/chrome/browser/cocoa/base_view.h
+++ b/chrome/browser/cocoa/base_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BASE_VIEW_H_
#define CHROME_BROWSER_COCOA_BASE_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -29,8 +30,8 @@
- (void)keyEvent:(NSEvent *)theEvent;
// Useful rect conversions (doing coordinate flipping)
-- (gfx::Rect)NSRectToRect:(NSRect)rect;
-- (NSRect)RectToNSRect:(gfx::Rect)rect;
+- (gfx::Rect)flipNSRectToRect:(NSRect)rect;
+- (NSRect)flipRectToNSRect:(gfx::Rect)rect;
@end
diff --git a/chrome/browser/cocoa/base_view.mm b/chrome/browser/cocoa/base_view.mm
index cee8951..4c9f999 100644
--- a/chrome/browser/cocoa/base_view.mm
+++ b/chrome/browser/cocoa/base_view.mm
@@ -127,13 +127,13 @@
[self keyEvent:theEvent];
}
-- (gfx::Rect)NSRectToRect:(NSRect)rect {
+- (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)RectToNSRect:(gfx::Rect)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;
diff --git a/chrome/browser/cocoa/base_view_unittest.mm b/chrome/browser/cocoa/base_view_unittest.mm
index bbfc75e..ff97571 100644
--- a/chrome/browser/cocoa/base_view_unittest.mm
+++ b/chrome/browser/cocoa/base_view_unittest.mm
@@ -29,16 +29,16 @@ 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, NSRectToRect) {
+TEST_F(BaseViewTest, flipNSRectToRect) {
NSRect convert = NSMakeRect(10, 10, 50, 50);
- gfx::Rect converted = [view_ NSRectToRect:convert];
+ 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_ RectToNSRect:converted];
+ 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);
diff --git a/chrome/browser/cocoa/bookmark_all_tabs_controller.h b/chrome/browser/cocoa/bookmark_all_tabs_controller.h
index 45386ed..4b34467 100644
--- a/chrome/browser/cocoa/bookmark_all_tabs_controller.h
+++ b/chrome/browser/cocoa/bookmark_all_tabs_controller.h
@@ -4,15 +4,17 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_ALL_TABS_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_ALL_TABS_CONTROLLER_H_
+#pragma once
#include <utility>
#include <vector>
+#include "base/string16.h"
#import "chrome/browser/cocoa/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<std::wstring, GURL> ActiveTabNameURLPair;
+typedef std::pair<string16, GURL> ActiveTabNameURLPair;
typedef std::vector<ActiveTabNameURLPair> ActiveTabsNameURLPairVector;
// A controller for the Bookmark All Tabs sheet which is presented upon
diff --git a/chrome/browser/cocoa/bookmark_all_tabs_controller.mm b/chrome/browser/cocoa/bookmark_all_tabs_controller.mm
index 2d8184a..b47f92a 100644
--- a/chrome/browser/cocoa/bookmark_all_tabs_controller.mm
+++ b/chrome/browser/cocoa/bookmark_all_tabs_controller.mm
@@ -4,11 +4,13 @@
#import "chrome/browser/cocoa/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/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "grit/generated_resources.h"
@implementation BookmarkAllTabsController
@@ -42,7 +44,7 @@
const int tabCount = tabstrip_model->count();
for (int i = 0; i < tabCount; ++i) {
TabContents* tc = tabstrip_model->GetTabContentsAt(i);
- const std::wstring tabTitle = UTF16ToWideHack(tc->GetTitle());
+ const string16 tabTitle = tc->GetTitle();
const GURL& tabURL(tc->GetURL());
ActiveTabNameURLPair tabPair(tabTitle, tabURL);
activeTabPairsVector_.push_back(tabPair);
@@ -60,7 +62,7 @@
int newIndex = newParentNode->GetChildCount();
// Create the new folder which will contain all of the tab URLs.
NSString* newFolderName = [self displayName];
- std::wstring newFolderString = base::SysNSStringToWide(newFolderName);
+ string16 newFolderString = base::SysNSStringToUTF16(newFolderName);
BookmarkModel* model = [self bookmarkModel];
const BookmarkNode* newFolder = model->AddGroup(newParentNode, newIndex,
newFolderString);
diff --git a/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm b/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm
index 48dd371..7f9878d 100644
--- a/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_all_tabs_controller_unittest.mm
@@ -6,6 +6,8 @@
#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/bookmark_all_tabs_controller.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
@@ -22,11 +24,11 @@
[self activeTabPairsVector];
activeTabPairsVector->clear();
activeTabPairsVector->push_back(
- ActiveTabNameURLPair(L"at-0", GURL("http://at-0.com")));
+ ActiveTabNameURLPair(ASCIIToUTF16("at-0"), GURL("http://at-0.com")));
activeTabPairsVector->push_back(
- ActiveTabNameURLPair(L"at-1", GURL("http://at-1.com")));
+ ActiveTabNameURLPair(ASCIIToUTF16("at-1"), GURL("http://at-1.com")));
activeTabPairsVector->push_back(
- ActiveTabNameURLPair(L"at-2", GURL("http://at-2.com")));
+ ActiveTabNameURLPair(ASCIIToUTF16("at-2"), GURL("http://at-2.com")));
}
@end
@@ -41,10 +43,10 @@ class BookmarkAllTabsControllerTest : public CocoaTest {
BookmarkAllTabsControllerTest() {
BookmarkModel& model(*(helper_.profile()->GetBookmarkModel()));
const BookmarkNode* root = model.GetBookmarkBarNode();
- group_a_ = model.AddGroup(root, 0, L"a");
- model.AddURL(group_a_, 0, L"a-0", GURL("http://a-0.com"));
- model.AddURL(group_a_, 1, L"a-1", GURL("http://a-1.com"));
- model.AddURL(group_a_, 2, L"a-2", GURL("http://a-2.com"));
+ 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() {
@@ -75,6 +77,6 @@ TEST_F(BookmarkAllTabsControllerTest, BookmarkAllTabs) {
[controller_ ok:nil];
EXPECT_EQ(4, group_a_->GetChildCount());
const BookmarkNode* folderChild = group_a_->GetChild(3);
- EXPECT_EQ(folderChild->GetTitle(), L"ALL MY TABS");
+ EXPECT_EQ(folderChild->GetTitle(), ASCIIToUTF16("ALL MY TABS"));
EXPECT_EQ(3, folderChild->GetChildCount());
}
diff --git a/chrome/browser/cocoa/bookmark_bar_bridge.h b/chrome/browser/cocoa/bookmark_bar_bridge.h
index 23c6c78..78461e3 100644
--- a/chrome/browser/cocoa/bookmark_bar_bridge.h
+++ b/chrome/browser/cocoa/bookmark_bar_bridge.h
@@ -10,6 +10,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_BRIDGE_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_BRIDGE_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
diff --git a/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm b/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm
index d932d74..4588fc7 100644
--- a/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_bridge_unittest.mm
@@ -7,6 +7,7 @@
#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): add OCMock to Chromium to save some typing.
@@ -128,7 +129,7 @@ TEST_F(BookmarkBarBridgeTest, TestRedirect) {
EXPECT_TRUE([controller.get()->callbacks_ count] == 9);
for (int x = 1; x < 9; x++) {
- NSNumber *num = [NSNumber numberWithInt:x-1];
- EXPECT_TRUE([[controller.get()->callbacks_ objectAtIndex:x] isEqual:num]);
+ NSNumber* num = [NSNumber numberWithInt:x-1];
+ EXPECT_NSEQ(num, [controller.get()->callbacks_ objectAtIndex:x]);
}
}
diff --git a/chrome/browser/cocoa/bookmark_bar_constants.h b/chrome/browser/cocoa/bookmark_bar_constants.h
index 0c0a905..bb2a8f6 100644
--- a/chrome/browser/cocoa/bookmark_bar_constants.h
+++ b/chrome/browser/cocoa/bookmark_bar_constants.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_CONSTANTS_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_CONSTANTS_H_
+#pragma once
namespace bookmarks {
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h
index 8060385..332a0ae 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller.h
+++ b/chrome/browser/cocoa/bookmark_bar_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#include <map>
@@ -30,7 +31,6 @@ class BookmarkNode;
class Browser;
class GURL;
class PrefService;
-class Profile;
class TabContents;
@class ToolbarController;
@protocol ViewResizer;
@@ -50,6 +50,7 @@ const CGFloat kBookmarkMenuButtonMaximumWidth = 485.0;
const CGFloat kBookmarkVerticalPadding = 2.0;
const CGFloat kBookmarkHorizontalPadding = 1.0;
+const CGFloat kBookmarkSubMenuHorizontalPadding = 5.0;
const CGFloat kBookmarkHorizontalScreenPadding = 8.0;
// Our NSScrollView is supposed to be just barely big enough to fit its
@@ -61,7 +62,7 @@ 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 = 1.0;
+const CGFloat kBookmarkMenuOverlap = 5.0;
// Delay before opening a subfolder (and closing the previous one)
// when hovering over a folder button.
@@ -199,7 +200,7 @@ willAnimateFromState:(bookmarks::VisualState)oldState
NSRect originalImportBookmarksRect_; // Original, pre-resized field rect.
// "Other bookmarks" button on the right side.
- scoped_nsobject<NSButton> otherBookmarksButton_;
+ scoped_nsobject<BookmarkButton> otherBookmarksButton_;
// We have a special menu for folder buttons. This starts as a copy
// of the bar menu.
@@ -294,6 +295,9 @@ willAnimateFromState:(bookmarks::VisualState)oldState
// 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;
@@ -346,7 +350,7 @@ willAnimateFromState:(bookmarks::VisualState)oldState
- (NSMenu*)offTheSideMenu;
- (NSButton*)offTheSideButton;
- (BOOL)offTheSideButtonIsHidden;
-- (NSButton*)otherBookmarksButton;
+- (BookmarkButton*)otherBookmarksButton;
- (BookmarkBarFolderController*)folderController;
- (id)folderTarget;
- (int)displayedButtonCount;
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm
index f05f9cd..0c7ec9d 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller.mm
+++ b/chrome/browser/cocoa/bookmark_bar_controller.mm
@@ -12,7 +12,6 @@
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
-#import "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/background_gradient_view.h"
#import "chrome/browser/cocoa/bookmark_bar_bridge.h"
#import "chrome/browser/cocoa/bookmark_bar_constants.h"
@@ -37,10 +36,11 @@
#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/pref_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/tab_contents/tab_contents_view.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/pref_names.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
@@ -228,12 +228,16 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
defaultImage_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]);
- // Register for theme changes.
+ // 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
@@ -243,6 +247,40 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
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];
@@ -468,6 +506,15 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
[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 {
@@ -827,7 +874,12 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
// Enable or disable items. We are the menu delegate for both the bar
// and for bookmark folder buttons.
-- (BOOL)validateUserInterfaceItem:(id)item {
+- (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;
@@ -867,10 +919,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
(action == @selector(deleteBookmark:)) ||
(action == @selector(cutBookmark:)) ||
(action == @selector(copyBookmark:))) {
- // Don't allow edit/delete of the bar node, or of "Other Bookmarks"
- if ((node == nil) ||
- (node == bookmarkModel_->other_node()) ||
- (node == bookmarkModel_->GetBookmarkBarNode())) {
+ if (![self canEditBookmark:node]) {
return NO;
}
}
@@ -946,7 +995,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
// Add a tooltip
std::string url_string = child->GetURL().possibly_invalid_spec();
NSString* tooltip = [NSString stringWithFormat:@"%@\n%s",
- base::SysWideToNSString(child->GetTitle()),
+ base::SysUTF16ToNSString(child->GetTitle()),
url_string.c_str()];
[item setToolTip:tooltip];
}
@@ -975,7 +1024,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
- (NSMenu *)menuForFolderNode:(const BookmarkNode*)node {
if (!node->is_folder())
return nil;
- NSString* title = base::SysWideToNSString(node->GetTitle());
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
NSMenu* menu = [[[NSMenu alloc] initWithTitle:title] autorelease];
[self addFolderNode:node toMenu:menu];
@@ -1067,7 +1116,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
[button setTarget:self];
[button setAction:@selector(openBookmark:)];
// Add a tooltip.
- NSString* title = base::SysWideToNSString(node->GetTitle());
+ 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()];
@@ -1335,6 +1384,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
if (NSMaxX([button frame]) < maxViewX)
break;
[buttons_ removeLastObject];
+ [button setDelegate:nil];
[button removeFromSuperview];
--displayedButtonCount_;
}
@@ -1383,7 +1433,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
return [offTheSideButton_ isHidden];
}
-- (NSButton*)otherBookmarksButton {
+- (BookmarkButton*)otherBookmarksButton {
return otherBookmarksButton_.get();
}
@@ -1402,7 +1452,10 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
// Delete all buttons (bookmarks, chevron, "other bookmarks") from the
// bookmark bar; reset knowledge of bookmarks.
- (void)clearBookmarkBar {
- [buttons_ makeObjectsPerformSelector:@selector(removeFromSuperview)];
+ for (BookmarkButton* button in buttons_.get()) {
+ [button setDelegate:nil];
+ [button removeFromSuperview];
+ }
[buttons_ removeAllObjects];
[self clearMenuTagMap];
displayedButtonCount_ = 0;
@@ -1573,6 +1626,13 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
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;
}
@@ -1962,6 +2022,21 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
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
@@ -2155,6 +2230,17 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
// 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];
@@ -2168,6 +2254,11 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
// 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
@@ -2249,8 +2340,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
if (gurl.is_valid()) {
bookmarkModel_->AddURL(destParent,
destIndex++,
- base::SysNSStringToWide([titles
- objectAtIndex:i]),
+ base::SysNSStringToUTF16(
+ [titles objectAtIndex:i]),
gurl);
nodesWereAdded = YES;
}
@@ -2336,11 +2427,9 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
// If we are deleting a button whose folder is currently open, close it!
[self closeAllBookmarkFolders];
}
- NSRect poofFrame = [oldButton bounds];
- NSPoint poofPoint = NSMakePoint(NSMidX(poofFrame), NSMidY(poofFrame));
- poofPoint = [oldButton convertPoint:poofPoint toView:nil];
- poofPoint = [[oldButton window] convertBaseToScreen:poofPoint];
+ NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation];
NSRect oldFrame = [oldButton frame];
+ [oldButton setDelegate:nil];
[oldButton removeFromSuperview];
if (animate && !ignoreAnimations_ && [self isVisible])
NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint,
diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm
index f418abb..2a8887f 100644
--- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm
@@ -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,8 +7,11 @@
#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/bookmark_bar_constants.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_bar_folder_window.h"
@@ -24,6 +27,7 @@
#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"
@@ -316,7 +320,7 @@ class BookmarkBarControllerTest : public BookmarkBarControllerTestBase {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* node = model->AddURL(parent, parent->GetChildCount(),
- L"A title", gurl);
+ ASCIIToUTF16("A title"), gurl);
[menu_ setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
return menu_item_;
}
@@ -512,7 +516,7 @@ TEST_F(BookmarkBarControllerTest, NoItemContainerGoesAway) {
EXPECT_FALSE([noItemContainer isHidden]);
const BookmarkNode* node = model->AddURL(bar, bar->GetChildCount(),
- L"title",
+ ASCIIToUTF16("title"),
GURL("http://www.google.com"));
EXPECT_TRUE([noItemContainer isHidden]);
model->Remove(bar, bar->IndexOfChild(node));
@@ -521,7 +525,7 @@ TEST_F(BookmarkBarControllerTest, NoItemContainerGoesAway) {
// Now try it using a bookmark from the Other Bookmarks.
const BookmarkNode* otherBookmarks = model->other_node();
node = model->AddURL(otherBookmarks, otherBookmarks->GetChildCount(),
- L"TheOther",
+ ASCIIToUTF16("TheOther"),
GURL("http://www.other.com"));
EXPECT_FALSE([noItemContainer isHidden]);
// Move it from Other Bookmarks to the bar.
@@ -541,14 +545,15 @@ TEST_F(BookmarkBarControllerTest, OffTheSideButtonHidden) {
EXPECT_TRUE([bar_ offTheSideButtonIsHidden]);
for (int i = 0; i < 2; i++) {
- model->SetURLStarred(GURL("http://www.foo.com"), L"small", true);
+ 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(),
- L"super duper wide title",
+ ASCIIToUTF16("super duper wide title"),
GURL("http://superfriends.hall-of-justice.edu"));
}
EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
@@ -592,8 +597,7 @@ TEST_F(BookmarkBarControllerTest, DeleteFromOffTheSideWhileItIsOpen) {
for (int i = 0; i < 100; i++) {
std::ostringstream title;
title << "super duper wide title " << i;
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToWide(title.str().c_str()),
+ model->AddURL(parent, parent->GetChildCount(), ASCIIToUTF16(title.str()),
GURL("http://superfriends.hall-of-justice.edu"));
}
EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
@@ -683,8 +687,9 @@ TEST_F(BookmarkBarControllerTest, MenuForFolderNode) {
// Test two bookmarks.
GURL gurl("http://www.foo.com");
- model->SetURLStarred(gurl, L"small", true);
- model->SetURLStarred(GURL("http://www.cnn.com"), L"bigger title", true);
+ 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"];
@@ -702,11 +707,11 @@ TEST_F(BookmarkBarControllerTest, MenuForFolderNode) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* folder = model->AddGroup(parent,
parent->GetChildCount(),
- L"group");
+ ASCIIToUTF16("group"));
model->AddURL(folder, folder->GetChildCount(),
- L"f1", GURL("http://framma-lamma.com"));
+ ASCIIToUTF16("f1"), GURL("http://framma-lamma.com"));
model->AddURL(folder, folder->GetChildCount(),
- L"f2", GURL("http://framma-lamma-ding-dong.com"));
+ ASCIIToUTF16("f2"), GURL("http://framma-lamma-ding-dong.com"));
menu = [bar_ menuForFolderNode:model->GetBookmarkBarNode()];
EXPECT_EQ([menu numberOfItems], 3);
@@ -774,13 +779,13 @@ TEST_F(BookmarkBarControllerTest, TestAddRemoveAndClear) {
// narrow.
// TODO(viettrungluu): make the test independent of window/view size, font
// metrics, button size and spacing, and everything else.
- std::wstring title1(L"x");
+ 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");
- std::wstring title2(L"y");
+ string16 title2(ASCIIToUTF16("y"));
model->SetURLStarred(gurl2, title2, true);
EXPECT_EQ(2U, [[bar_ buttons] count]);
EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]);
@@ -815,7 +820,7 @@ TEST_F(BookmarkBarControllerTest, TestButtonLimits) {
// Add one; make sure we see it.
const BookmarkNode* parent = model->GetBookmarkBarNode();
model->AddURL(parent, parent->GetChildCount(),
- L"title", GURL("http://www.google.com"));
+ 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
@@ -824,7 +829,7 @@ TEST_F(BookmarkBarControllerTest, TestButtonLimits) {
EXPECT_EQ(0U, [[bar_ buttons] count]);
for (int i=0; i<30; i++) {
model->AddURL(parent, parent->GetChildCount(),
- L"title", GURL("http://www.google.com"));
+ ASCIIToUTF16("title"), GURL("http://www.google.com"));
}
int count = [[bar_ buttons] count];
EXPECT_LT(count, 30L);
@@ -833,7 +838,7 @@ TEST_F(BookmarkBarControllerTest, TestButtonLimits) {
// 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 */
- L"title", GURL("http://www.google.com"));
+ ASCIIToUTF16("title"), GURL("http://www.google.com"));
}
// Finally, grow the view and make sure the button count goes up.
@@ -871,11 +876,11 @@ TEST_F(BookmarkBarControllerTest, TestButtonMarch) {
TEST_F(BookmarkBarControllerTest, CheckForGrowth) {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
GURL gurl1("http://www.google.com");
- std::wstring title1(L"x");
+ string16 title1(ASCIIToUTF16("x"));
model->SetURLStarred(gurl1, title1, true);
GURL gurl2("http://www.google.com/blah");
- std::wstring title2(L"y");
+ string16 title2(ASCIIToUTF16("y"));
model->SetURLStarred(gurl2, title2, true);
EXPECT_EQ(2U, [[bar_ buttons] count]);
@@ -904,7 +909,7 @@ TEST_F(BookmarkBarControllerTest, DeleteBookmark) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
for (unsigned int i = 0; i < arraysize(urls); i++) {
model->AddURL(parent, parent->GetChildCount(),
- L"title", GURL(urls[i]));
+ ASCIIToUTF16("title"), GURL(urls[i]));
}
EXPECT_EQ(3, parent->GetChildCount());
const BookmarkNode* middle_node = parent->GetChild(1);
@@ -926,13 +931,13 @@ TEST_F(BookmarkBarControllerTest, Cell) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
model->AddURL(parent, parent->GetChildCount(),
- L"supertitle",
+ ASCIIToUTF16("supertitle"),
GURL("http://superfriends.hall-of-justice.edu"));
const BookmarkNode* node = parent->GetChild(0);
NSCell* cell = [bar_ cellForBookmarkNode:node];
EXPECT_TRUE(cell);
- EXPECT_TRUE([[cell title] isEqual:@"supertitle"]);
+ EXPECT_NSEQ(@"supertitle", [cell title]);
EXPECT_EQ(node, [[cell representedObject] pointerValue]);
EXPECT_TRUE([cell menu]);
@@ -954,7 +959,7 @@ TEST_F(BookmarkBarControllerTest, Display) {
TEST_F(BookmarkBarControllerTest, MiddleClick) {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
GURL gurl1("http://www.google.com/");
- std::wstring title1(L"x");
+ string16 title1(ASCIIToUTF16("x"));
model->SetURLStarred(gurl1, title1, true);
EXPECT_EQ(1U, [[bar_ buttons] count]);
@@ -976,7 +981,7 @@ TEST_F(BookmarkBarControllerTest, HidesHelpMessageWithBookmark) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
model->AddURL(parent, parent->GetChildCount(),
- L"title", GURL("http://one.com"));
+ ASCIIToUTF16("title"), GURL("http://one.com"));
[bar_ loaded:model];
EXPECT_TRUE([[[bar_ buttonView] noItemContainer] isHidden]);
@@ -987,7 +992,7 @@ TEST_F(BookmarkBarControllerTest, BookmarkButtonSizing) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
model->AddURL(parent, parent->GetChildCount(),
- L"title", GURL("http://one.com"));
+ ASCIIToUTF16("title"), GURL("http://one.com"));
[bar_ loaded:model];
@@ -1009,11 +1014,11 @@ TEST_F(BookmarkBarControllerTest, DropBookmarks) {
"javascript:alert('lolwut')",
"file://localhost/tmp/local-file.txt" // As if dragged from the desktop.
};
- std::wstring titles[] = {
- std::wstring(L"Philosophoraptor"),
- std::wstring(L"Can't draw"),
- std::wstring(L"Inspiration"),
- std::wstring(L"Frum stuf")
+ const char* titles[] = {
+ "Philosophoraptor",
+ "Can't draw",
+ "Inspiration",
+ "Frum stuf"
};
EXPECT_EQ(arraysize(urls), arraysize(titles));
@@ -1021,7 +1026,7 @@ TEST_F(BookmarkBarControllerTest, DropBookmarks) {
NSMutableArray* nstitles = [NSMutableArray array];
for (size_t i = 0; i < arraysize(urls); ++i) {
[nsurls addObject:base::SysUTF8ToNSString(urls[i])];
- [nstitles addObject:base::SysWideToNSString(titles[i])];
+ [nstitles addObject:base::SysUTF8ToNSString(titles[i])];
}
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
@@ -1039,18 +1044,18 @@ TEST_F(BookmarkBarControllerTest, DropBookmarks) {
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(), titles[i]);
+ EXPECT_EQ(parent->GetChild(i)->GetTitle(), ASCIIToUTF16(titles[i]));
}
}
TEST_F(BookmarkBarControllerTest, TestButtonOrBar) {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
GURL gurl1("http://www.google.com");
- std::wstring title1(L"x");
+ string16 title1(ASCIIToUTF16("x"));
model->SetURLStarred(gurl1, title1, true);
GURL gurl2("http://www.google.com/gurl_power");
- std::wstring title2(L"gurl power");
+ string16 title2(ASCIIToUTF16("gurl power"));
model->SetURLStarred(gurl2, title2, true);
NSButton* first = [[bar_ buttons] objectAtIndex:0];
@@ -1078,7 +1083,7 @@ TEST_F(BookmarkBarControllerTest, TestMenuNodeAndDisable) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* folder = model->AddGroup(parent,
parent->GetChildCount(),
- L"group");
+ ASCIIToUTF16("group"));
NSButton* button = [[bar_ buttons] objectAtIndex:0];
EXPECT_TRUE(button);
@@ -1095,7 +1100,7 @@ TEST_F(BookmarkBarControllerTest, TestMenuNodeAndDisable) {
// Now add a child and make sure the item would be enabled.
model->AddURL(folder, folder->GetChildCount(),
- L"super duper wide title",
+ ASCIIToUTF16("super duper wide title"),
GURL("http://superfriends.hall-of-justice.edu"));
EXPECT_TRUE([bar_ validateUserInterfaceItem:item]);
}
@@ -1106,27 +1111,29 @@ TEST_F(BookmarkBarControllerTest, TestDragButton) {
GURL gurls[] = { GURL("http://www.google.com/a"),
GURL("http://www.google.com/b"),
GURL("http://www.google.com/c") };
- std::wstring titles[] = { L"a", L"b", L"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_TRUE([[[[bar_ buttons] objectAtIndex:0] title] isEqual:@"a"]);
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
[bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
to:NSMakePoint(0, 0)
copy:NO];
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:0] title] isEqual:@"c"]);
+ 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_TRUE([[[[bar_ buttons] objectAtIndex:0] title] isEqual:@"c"]);
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:1] title] isEqual:@"b"]);
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:2] title] isEqual:@"a"]);
+ 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.
@@ -1135,9 +1142,9 @@ TEST_F(BookmarkBarControllerTest, TestDragButton) {
[bar_ dragButton:[[bar_ buttons] objectAtIndex:0]
to:NSMakePoint(x, 0)
copy:NO];
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:0] title] isEqual:@"b"]);
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:1] title] isEqual:@"c"]);
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:2] title] isEqual:@"a"]);
+ 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.)
@@ -1151,15 +1158,15 @@ TEST_F(BookmarkBarControllerTest, TestDragButton) {
// A drop on a folder button.
const BookmarkNode* folder = model->AddGroup(model->GetBookmarkBarNode(),
0,
- L"awesome group");
+ ASCIIToUTF16("awesome group"));
DCHECK(folder);
- model->AddURL(folder, 0, L"already", GURL("http://www.google.com"));
+ 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;
- std::wstring title = [[[bar_ buttons] objectAtIndex:2]
- bookmarkNode]->GetTitle();
+ string16 title = [[[bar_ buttons] objectAtIndex:2] bookmarkNode]->GetTitle();
[bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
to:NSMakePoint(x, 0)
copy:NO];
@@ -1177,12 +1184,14 @@ TEST_F(BookmarkBarControllerTest, TestCopyButton) {
GURL gurls[] = { GURL("http://www.google.com/a"),
GURL("http://www.google.com/b"),
GURL("http://www.google.com/c") };
- std::wstring titles[] = { L"a", L"b", L"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_TRUE([[[[bar_ buttons] objectAtIndex:0] title] isEqual:@"a"]);
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
// Drag 'a' between 'b' and 'c'.
CGFloat x = NSMinX([[[bar_ buttons] objectAtIndex:2] frame]);
@@ -1190,10 +1199,10 @@ TEST_F(BookmarkBarControllerTest, TestCopyButton) {
[bar_ dragButton:[[bar_ buttons] objectAtIndex:0]
to:NSMakePoint(x, 0)
copy:YES];
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:0] title] isEqual:@"a"]);
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:1] title] isEqual:@"b"]);
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:2] title] isEqual:@"a"]);
- EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:3] title] isEqual:@"c"]);
+ 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);
}
@@ -1201,7 +1210,7 @@ TEST_F(BookmarkBarControllerTest, TestCopyButton) {
// 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"), L"small", true);
+ model->SetURLStarred(GURL("http://www.foo.com"), ASCIIToUTF16("small"), true);
BookmarkButton* button = [[bar_ buttons] objectAtIndex:0];
EXPECT_TRUE(button);
@@ -1213,12 +1222,12 @@ TEST_F(BookmarkBarControllerTest, TestThemedButton) {
[bar_ updateTheme:&theme];
NSAttributedString* astr = [button attributedTitle];
EXPECT_TRUE(astr);
- EXPECT_TRUE([[astr string] isEqual:@"small"]);
+ 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_TRUE([newColor isEqual:color]);
+ EXPECT_NSEQ(newColor, color);
}
}
@@ -1229,7 +1238,9 @@ TEST_F(BookmarkBarControllerTest, TestClearOnDealloc) {
GURL gurls[] = { GURL("http://www.foo.com/"),
GURL("http://www.bar.com/"),
GURL("http://www.baz.com/") };
- std::wstring titles[] = { L"foo", L"bar", L"baz" };
+ string16 titles[] = { ASCIIToUTF16("a"),
+ ASCIIToUTF16("b"),
+ ASCIIToUTF16("c") };
for (size_t i = 0; i < arraysize(titles); i++)
model->SetURLStarred(gurls[i], titles[i], true);
@@ -1263,10 +1274,11 @@ TEST_F(BookmarkBarControllerTest, TestFolders) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* folder = model->AddGroup(parent,
parent->GetChildCount(),
- L"group");
+ ASCIIToUTF16("group"));
model->AddURL(folder, folder->GetChildCount(),
- L"f1", GURL("http://framma-lamma.com"));
- folder = model->AddGroup(parent, parent->GetChildCount(), L"empty");
+ ASCIIToUTF16("f1"), GURL("http://framma-lamma.com"));
+ folder = model->AddGroup(parent, parent->GetChildCount(),
+ ASCIIToUTF16("empty"));
EXPECT_EQ([[bar_ buttons] count], 2U);
@@ -1301,17 +1313,17 @@ TEST_F(BookmarkBarControllerTest, TestFolders) {
TEST_F(BookmarkBarControllerTest, TestFolderButtons) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2b ] 3b 4f:[ 4f1b 4f2b ] ");
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ 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(), L"CLICK ME",
+ model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("CLICK ME"),
GURL("http://www.google.com/"));
// Click on a folder button.
@@ -1375,13 +1387,15 @@ TEST_F(BookmarkBarControllerTest, OffTheSideFolder) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
for (int x = 0; x < 30; x++) {
model->AddURL(parent, parent->GetChildCount(),
- L"medium-size-title", GURL("http://framma-lamma.com"));
+ 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(),
- L"DELETE_ME", GURL("http://ashton-tate.com"));
+ ASCIIToUTF16("DELETE_ME"), GURL("http://ashton-tate.com"));
model->AddURL(parent, parent->GetChildCount(),
- L"medium-size-title", GURL("http://framma-lamma.com"));
+ ASCIIToUTF16("medium-size-title"),
+ GURL("http://framma-lamma.com"));
// Should no longer be hidden.
EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
@@ -1450,8 +1464,8 @@ TEST_F(BookmarkBarControllerTest, DropDestination) {
// Make some buttons.
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
const BookmarkNode* parent = model->GetBookmarkBarNode();
- model->AddGroup(parent, parent->GetChildCount(), L"group 1");
- model->AddGroup(parent, parent->GetChildCount(), L"group 2");
+ 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.
@@ -1492,7 +1506,7 @@ TEST_F(BookmarkBarControllerTest, NodeDeletedWhileMenuIsOpen) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* initialNode = model->AddURL(
parent, parent->GetChildCount(),
- L"initial",
+ ASCIIToUTF16("initial"),
GURL("http://www.google.com"));
NSMenuItem* item = ItemForBookmarkBarMenu(initialNode);
@@ -1531,9 +1545,9 @@ TEST_F(BookmarkBarControllerTest, NodeDeletedWhileContextMenuIsOpen) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* folder = model->AddGroup(parent,
parent->GetChildCount(),
- L"group");
+ ASCIIToUTF16("group"));
const BookmarkNode* framma = model->AddURL(folder, folder->GetChildCount(),
- L"f1",
+ ASCIIToUTF16("f1"),
GURL("http://framma-lamma.com"));
// Mock in a menu
@@ -1555,14 +1569,14 @@ TEST_F(BookmarkBarControllerTest, CloseFolderOnAnimate) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* folder = model->AddGroup(parent,
parent->GetChildCount(),
- L"group");
+ ASCIIToUTF16("group"));
model->AddGroup(parent, parent->GetChildCount(),
- L"sibbling group");
- model->AddURL(folder, folder->GetChildCount(), L"title a",
+ ASCIIToUTF16("sibbling group"));
+ model->AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("title a"),
GURL("http://www.google.com/a"));
model->AddURL(folder, folder->GetChildCount(),
- L"title super duper long long whoa momma title you betcha",
- GURL("http://www.google.com/b"));
+ 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];
@@ -1586,11 +1600,11 @@ TEST_F(BookmarkBarControllerTest, CloseFolderOnAnimate) {
TEST_F(BookmarkBarControllerTest, MoveRemoveAddButtons) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2b ] 3b ");
+ const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Remember how many buttons are showing.
@@ -1599,40 +1613,40 @@ TEST_F(BookmarkBarControllerTest, MoveRemoveAddButtons) {
// Move a button around a bit.
[bar_ moveButtonFromIndex:0 toIndex:2];
- EXPECT_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"2f"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"3b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"1b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"2f"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"3b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"2f1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"2f"]);
- EXPECT_TRUE([[[buttons objectAtIndex:3] title] isEqualToString:@"3b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"2f1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"2f"]);
- EXPECT_TRUE([[[buttons objectAtIndex:3] title] isEqualToString:@"3b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:4] title] isEqualToString:@"2f2b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"2f1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"2f"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"3b"]);
+ 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]);
}
@@ -1677,15 +1691,16 @@ public:
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
parent_ = model->GetBookmarkBarNode();
// { one, { two-one, two-two }, three }
- model->AddURL(parent_, parent_->GetChildCount(), L"title",
+ model->AddURL(parent_, parent_->GetChildCount(), ASCIIToUTF16("title"),
GURL("http://one.com"));
- folder_ = model->AddGroup(parent_, parent_->GetChildCount(), L"group");
+ folder_ = model->AddGroup(parent_, parent_->GetChildCount(),
+ ASCIIToUTF16("group"));
model->AddURL(folder_, folder_->GetChildCount(),
- L"title", GURL("http://two-one.com"));
+ ASCIIToUTF16("title"), GURL("http://two-one.com"));
model->AddURL(folder_, folder_->GetChildCount(),
- L"title", GURL("http://two-two.com"));
+ ASCIIToUTF16("title"), GURL("http://two-two.com"));
model->AddURL(parent_, parent_->GetChildCount(),
- L"title", GURL("https://three.com"));
+ ASCIIToUTF16("title"), GURL("https://three.com"));
}
const BookmarkNode* parent_; // Weak
const BookmarkNode* folder_; // Weak
@@ -1837,7 +1852,7 @@ class BookmarkBarControllerDragDropTest : public BookmarkBarControllerTestBase {
TEST_F(BookmarkBarControllerDragDropTest, DragMoveBarBookmarkToOffTheSide) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1bWithLongName 2fWithLongName:[ "
+ const std::string model_string("1bWithLongName 2fWithLongName:[ "
"2f1bWithLongName 2f2fWithLongName:[ 2f2f1bWithLongName "
"2f2f2bWithLongName 2f2f3bWithLongName 2f4b ] 2f3bWithLongName ] "
"3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName "
@@ -1846,7 +1861,7 @@ TEST_F(BookmarkBarControllerDragDropTest, DragMoveBarBookmarkToOffTheSide) {
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Insure that the off-the-side is not showing.
@@ -1889,16 +1904,16 @@ TEST_F(BookmarkBarControllerDragDropTest, DragMoveBarBookmarkToOffTheSide) {
TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ 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::wstring other_string(L"O1b O2b O3f:[ O3f1b O3f2f ] "
- "O4f:[ O4f1b O4f2f ] 05b ");
+ 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::wstring actual = model_test_utils::ModelStringFromNode(root);
+ std::string actual = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actual);
actual = model_test_utils::ModelStringFromNode(other);
EXPECT_EQ(other_string, actual);
@@ -1920,8 +1935,8 @@ TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) {
int newChildCount = root->GetChildCount();
EXPECT_EQ(oldChildCount + 1, newChildCount);
// Verify the model.
- const std::wstring expected(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] O3f:[ O3f1b O3f2f ] 3b 4b ");
+ 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;
@@ -1931,7 +1946,7 @@ TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) {
ASSERT_TRUE(targetButton);
NSPoint targetPoint = [targetButton center];
newNode = other->GetChild(2); // Should be O4f.
- EXPECT_EQ(newNode->GetTitle(), L"O4f");
+ EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
[bar_ setDragDataNode:newNode];
[dragInfo setDropLocation:targetPoint];
[bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
@@ -1939,9 +1954,9 @@ TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) {
newChildCount = root->GetChildCount();
EXPECT_EQ(oldChildCount, newChildCount);
// Verify the model.
- const std::wstring expected1(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b O4f:[ O4f1b O4f2f ] ] O3f:[ O3f1b O3f2f ] "
- "3b 4b ");
+ 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);
}
@@ -1949,12 +1964,12 @@ TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) {
TEST_F(BookmarkBarControllerDragDropTest, AddURLs) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
+ 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::wstring actual = model_test_utils::ModelStringFromNode(root);
+ std::string actual = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actual);
// Remember the children.
@@ -1972,8 +1987,8 @@ TEST_F(BookmarkBarControllerDragDropTest, AddURLs) {
int newChildCount = root->GetChildCount();
EXPECT_EQ(oldChildCount + 2, newChildCount);
// Verify the model.
- const std::wstring expected(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] SiteA SiteB 3b 4b ");
+ 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);
}
@@ -1981,11 +1996,11 @@ TEST_F(BookmarkBarControllerDragDropTest, AddURLs) {
TEST_F(BookmarkBarControllerDragDropTest, ControllerForNode) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2b ] 3b ");
+ const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Find the main bar controller.
@@ -1997,11 +2012,11 @@ TEST_F(BookmarkBarControllerDragDropTest, ControllerForNode) {
TEST_F(BookmarkBarControllerDragDropTest, DropPositionIndicator) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
+ const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModel = model_test_utils::ModelStringFromNode(root);
+ 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.
@@ -2026,4 +2041,72 @@ TEST_F(BookmarkBarControllerDragDropTest, DropPositionIndicator) {
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/bookmark_bar_folder_button_cell.h b/chrome/browser/cocoa/bookmark_bar_folder_button_cell.h
index afcfd34..f1a2ae7 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_button_cell.h
+++ b/chrome/browser/cocoa/bookmark_bar_folder_button_cell.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
+#pragma once
#import "chrome/browser/cocoa/bookmark_button_cell.h"
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller.h b/chrome/browser/cocoa/bookmark_bar_folder_controller.h
index 6918950..e03d06f 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_controller.h
+++ b/chrome/browser/cocoa/bookmark_bar_folder_controller.h
@@ -168,6 +168,7 @@
- (id)folderTarget;
- (void)configureWindowLevel;
- (void)performOneScroll:(CGFloat)delta;
+- (BookmarkButton*)buttonThatMouseIsIn;
// Set to YES in order to prevent animations.
- (void)setIgnoreAnimations:(BOOL)ignore;
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller.mm b/chrome/browser/cocoa/bookmark_bar_folder_controller.mm
index a58745e..970fcda 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_controller.mm
+++ b/chrome/browser/cocoa/bookmark_bar_folder_controller.mm
@@ -3,20 +3,21 @@
// found in the LICENSE file.
#import "chrome/browser/cocoa/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/browser_theme_provider.h"
#import "chrome/browser/cocoa/bookmark_bar_constants.h" // namespace bookmarks
#import "chrome/browser/cocoa/bookmark_bar_controller.h" // namespace bookmarks
-#import "chrome/browser/cocoa/bookmark_bar_folder_view.h"
#import "chrome/browser/cocoa/bookmark_bar_folder_button_cell.h"
#import "chrome/browser/cocoa/bookmark_bar_folder_hover_state.h"
+#import "chrome/browser/cocoa/bookmark_bar_folder_view.h"
#import "chrome/browser/cocoa/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 {
@@ -145,6 +146,14 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
[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
@@ -174,8 +183,10 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
- (void)reconfigureMenu {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
- for (BookmarkButton* button in buttons_.get())
+ for (BookmarkButton* button in buttons_.get()) {
+ [button setDelegate:nil];
[button removeFromSuperview];
+ }
[buttons_ removeAllObjects];
[self configureWindow];
}
@@ -250,7 +261,7 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
[button setTarget:self];
[button setAction:@selector(openBookmark:)];
// Add a tooltip.
- NSString* title = base::SysWideToNSString(node->GetTitle());
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
std::string urlString = node->GetURL().possibly_invalid_spec();
NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", title,
urlString.c_str()];
@@ -294,7 +305,8 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
x = NSMaxX([[parentButton_ window] frame]) -
bookmarks::kBookmarkMenuOverlap;
// If off the screen, switch direction.
- if ((x + windowWidth + bookmarks::kBookmarkHorizontalScreenPadding) >
+ if ((x + windowWidth +
+ bookmarks::kBookmarkHorizontalScreenPadding) >
NSMaxX([[[self window] screen] frame])) {
[self setSubFolderGrowthToRight:NO];
} else {
@@ -374,39 +386,63 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
// 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::kBookmarkVerticalPadding) +
- bookmarks::kScrollViewContentWidthMargin;
+ [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,
- windowWidth,
- windowHeight);
-
+ 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));
+ 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;
}
- [[self window] setFrame:windowFrame display:YES];
- // If scrollable then offset the view and show the arrows.
- if (scrollable_) {
- [mainView_ scrollPoint:NSMakePoint(0, (NSHeight(mainViewFrame) -
- NSHeight(windowFrame)))];
+ [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.
@@ -421,15 +457,18 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
int buttons = std::max(node->GetChildCount() - startingIndex, 1);
// Prelim height of the window. We'll trim later as needed.
- int height = buttons * bookmarks::kBookmarkButtonHeight;
+ int height = (buttons * (bookmarks::kBookmarkButtonHeight +
+ bookmarks::kBookmarkVerticalPadding)) +
+ bookmarks::kBookmarkVerticalPadding;
// 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::kBookmarkHorizontalPadding,
- height - bookmarks::kBookmarkButtonHeight,
+ bookmarks::kBookmarkSubMenuHorizontalPadding,
+ (height -
+ (bookmarks::kBookmarkButtonHeight + bookmarks::kBookmarkVerticalPadding)),
bookmarks::kDefaultBookmarkWidth,
bookmarks::kBookmarkButtonHeight);
@@ -451,7 +490,8 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
frame:buttonsOuterFrame];
[buttons_ addObject:button];
[mainView_ addSubview:button];
- buttonsOuterFrame.origin.y -= bookmarks::kBookmarkButtonHeight;
+ buttonsOuterFrame.origin.y -= (bookmarks::kBookmarkButtonHeight +
+ bookmarks::kBookmarkVerticalPadding);
}
}
@@ -678,11 +718,13 @@ const CGFloat kScrollWindowVerticalMargin = 0.0;
NSPoint eventScreenLocation =
[[theEvent window] convertBaseToScreen:[theEvent locationInWindow]];
- NSRect visibleRect = [[[self window] screen] visibleFrame];
+ // 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) -
- kBookmarkBarFolderScrollAmount;
+ verticalScrollArrowHeight_;
CGFloat closeToBottomOfScreen = NSMinY(visibleRect) +
- kBookmarkBarFolderScrollAmount;
+ verticalScrollArrowHeight_;
if (eventScreenLocation.y <= closeToBottomOfScreen) {
[self beginScrollWindowUp];
@@ -1006,6 +1048,21 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
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.
@@ -1187,41 +1244,38 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
- (void)addButtonForNode:(const BookmarkNode*)node
atIndex:(NSInteger)buttonIndex {
- NSRect buttonFrame = NSMakeRect(bookmarks::kBookmarkHorizontalPadding,
- bookmarks::kBookmarkVerticalPadding,
- NSWidth([mainView_ frame]) - 2 * bookmarks::kBookmarkHorizontalPadding -
- bookmarks::kScrollViewContentWidthMargin,
- bookmarks::kBookmarkBarHeight - 2 *
- bookmarks::kBookmarkVerticalPadding);
+ // Propose the frame for the new button.
+ NSRect newButtonFrame = NSMakeRect(0, 0, 500, 500); // Placeholder values.
// 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];
- } else {
- // Set us up to remember the last moved button's frame.
- buttonFrame.origin.y += NSHeight([mainView_ frame]) +
- bookmarks::kBookmarkBarHeight;
}
if (buttonIndex == -1)
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];
- buttonFrame = [button frame];
- buttonFrame.origin.y += bookmarks::kBookmarkBarHeight;
+ // 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::kBookmarkBarHeight +
+ bookmarks::kBookmarkVerticalPadding;
[button setFrame:buttonFrame];
}
[[button cell] mouseExited:nil]; // De-highlight.
- if (parentNode->GetChildCount() > 1)
- buttonFrame.origin.y -= bookmarks::kBookmarkBarHeight;
BookmarkButton* newButton = [self makeButtonForNode:node
- frame:buttonFrame];
+ frame:newButtonFrame];
[buttons_ insertObject:newButton atIndex:buttonIndex];
[mainView_ addSubview:newButton];
@@ -1229,7 +1283,9 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
[self closeBookmarkFolder:self];
// Prelim height of the window. We'll trim later as needed.
- int height = [buttons_ count] * bookmarks::kBookmarkButtonHeight;
+ int height = [buttons_ count] * (bookmarks::kBookmarkButtonHeight +
+ bookmarks::kBookmarkVerticalPadding) +
+ bookmarks::kBookmarkVerticalPadding;
[self adjustWindowForHeight:height];
}
@@ -1267,7 +1323,7 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
if (gurl.is_valid()) {
bookmarkModel->AddURL(destParent,
destIndex++,
- base::SysNSStringToWide([titles objectAtIndex:i]),
+ base::SysNSStringToUTF16([titles objectAtIndex:i]),
gurl);
nodesWereAdded = YES;
}
@@ -1290,7 +1346,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
for (NSInteger i = fromIndex; i < toIndex; ++i) {
BookmarkButton* button = [buttons_ objectAtIndex:i];
NSRect frame = [button frame];
- frame.origin.y += bookmarks::kBookmarkBarHeight;
+ frame.origin.y += bookmarks::kBookmarkBarHeight +
+ bookmarks::kBookmarkVerticalPadding;
[button setFrameOrigin:frame.origin];
}
} else {
@@ -1299,7 +1356,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
for (NSInteger i = fromIndex - 1; i >= toIndex; --i) {
BookmarkButton* button = [buttons_ objectAtIndex:i];
NSRect buttonFrame = [button frame];
- buttonFrame.origin.y -= bookmarks::kBookmarkBarHeight;
+ buttonFrame.origin.y -= bookmarks::kBookmarkBarHeight +
+ bookmarks::kBookmarkVerticalPadding;
[button setFrameOrigin:buttonFrame.origin];
}
}
@@ -1313,15 +1371,29 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
- (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate {
// TODO(mrossetti): Get disappearing animation to work. http://crbug.com/42360
BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex];
- NSRect poofFrame = [oldButton bounds];
- NSPoint poofPoint = NSMakePoint(NSMidX(poofFrame), NSMidY(poofFrame));
- poofPoint = [oldButton convertPoint:poofPoint toView:nil];
- poofPoint = [[oldButton window] convertBaseToScreen:poofPoint];
+ NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation];
// If a hover-open is pending, cancel it.
- if (oldButton == buttonThatMouseIsIn_)
+ 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,
@@ -1330,7 +1402,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
for (NSInteger i = 0; i < buttonIndex; ++i) {
BookmarkButton* button = [buttons_ objectAtIndex:i];
NSRect buttonFrame = [button frame];
- buttonFrame.origin.y -= bookmarks::kBookmarkBarHeight;
+ buttonFrame.origin.y -= bookmarks::kBookmarkBarHeight -
+ bookmarks::kBookmarkVerticalPadding;
[button setFrame:buttonFrame];
}
// Search for and adjust submenus, if necessary.
@@ -1347,13 +1420,14 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
} else {
// If all nodes have been removed from this folder then add in the
// 'empty' placeholder button.
- NSRect buttonFrame = NSMakeRect(bookmarks::kBookmarkHorizontalPadding,
- bookmarks::kBookmarkButtonHeight -
- (bookmarks::kBookmarkBarHeight -
- bookmarks::kBookmarkVerticalPadding),
- bookmarks::kDefaultBookmarkWidth,
- (bookmarks::kBookmarkBarHeight -
- 2 * bookmarks::kBookmarkVerticalPadding));
+ 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];
@@ -1362,7 +1436,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
}
// Propose a height for the window. We'll trim later as needed.
- int height = buttonCount * bookmarks::kBookmarkButtonHeight;
+ int height = buttonCount * bookmarks::kBookmarkButtonHeight +
+ bookmarks::kBookmarkVerticalPadding;
[self adjustWindowForHeight:height];
}
@@ -1381,4 +1456,8 @@ static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
ignoreAnimations_ = ignore;
}
+- (BookmarkButton*)buttonThatMouseIsIn {
+ return buttonThatMouseIsIn_;
+}
+
@end // BookmarkBarFolderController
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm
index 4b5dda2..e6e3701 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_folder_controller_unittest.mm
@@ -6,6 +6,8 @@
#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/bookmark_bar_constants.h" // namespace bookmarks
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_bar_folder_button_cell.h"
@@ -16,6 +18,7 @@
#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.
@@ -121,7 +124,7 @@ const int kLotsOfNodesCount = 150;
class BookmarkBarFolderControllerTest : public CocoaTest {
public:
BrowserTestHelper helper_;
- scoped_nsobject<BookmarkBarController> parentBarController_;
+ scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
const BookmarkNode* folderA_; // owned by model
const BookmarkNode* longTitleNode_; // owned by model
@@ -130,40 +133,40 @@ class BookmarkBarFolderControllerTest : public CocoaTest {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* folderA = model->AddGroup(parent,
parent->GetChildCount(),
- L"group");
+ ASCIIToUTF16("group"));
folderA_ = folderA;
model->AddGroup(parent, parent->GetChildCount(),
- L"sibbling group");
+ ASCIIToUTF16("sibbling group"));
const BookmarkNode* folderB = model->AddGroup(folderA,
folderA->GetChildCount(),
- L"subgroup 1");
+ ASCIIToUTF16("subgroup 1"));
model->AddGroup(folderA,
folderA->GetChildCount(),
- L"subgroup 2");
- model->AddURL(folderA, folderA->GetChildCount(), L"title a",
+ ASCIIToUTF16("subgroup 2"));
+ model->AddURL(folderA, folderA->GetChildCount(), ASCIIToUTF16("title a"),
GURL("http://www.google.com/a"));
longTitleNode_ = model->AddURL(
folderA, folderA->GetChildCount(),
- L"title super duper long long whoa momma title you betcha",
+ ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
GURL("http://www.google.com/b"));
- model->AddURL(folderB, folderB->GetChildCount(), L"t",
+ model->AddURL(folderB, folderB->GetChildCount(), ASCIIToUTF16("t"),
GURL("http://www.google.com/c"));
- parentBarController_.reset(
+ bar_.reset(
[[BookmarkBarControllerChildFolderRedirect alloc]
initWithBrowser:helper_.browser()
initialWidth:300
delegate:nil
resizeDelegate:nil]);
- [parentBarController_ loaded:model];
+ [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:[parentBarController_ view]];
- [parentBarController_ setBookmarkBarEnabled:YES];
+ [fakeToolbarView addSubview:[bar_ view]];
+ [bar_ setBookmarkBarEnabled:YES];
}
// Remove the bookmark with the long title.
@@ -178,22 +181,21 @@ class BookmarkBarFolderControllerTest : public CocoaTest {
int AddLotsOfNodes() {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
for (int i = 0; i < kLotsOfNodesCount; i++) {
- model->AddURL(folderA_, folderA_->GetChildCount(), L"repeated title",
+ 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 = [[parentBarController_ buttons]
- objectAtIndex:0];
+ BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
BookmarkBarFolderControllerPong* c =
[[BookmarkBarFolderControllerPong alloc]
initWithParentButton:parentButton
parentController:nil
- barController:parentBarController_];
+ barController:bar_];
[c window]; // Force nib load.
return c;
}
@@ -214,7 +216,9 @@ TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
Class cellClass = [BookmarkBarFolderButtonCell class];
for (BookmarkButton* button in buttons) {
NSRect r = [[bbfc mainView] convertRect:[button frame] fromView:button];
- EXPECT_TRUE(NSContainsRect([[bbfc mainView] frame], r));
+ // TODO(jrg): remove this adjustment.
+ NSRect bigger = NSInsetRect([[bbfc mainView] frame], -2, 0);
+ EXPECT_TRUE(NSContainsRect(bigger, r));
EXPECT_TRUE([[button cell] isKindOfClass:cellClass]);
}
@@ -241,8 +245,7 @@ TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
}
TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
- BookmarkButton* parentButton = [[parentBarController_ buttons]
- objectAtIndex:0];
+ BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
EXPECT_TRUE(parentButton);
// If parent is a BookmarkBarController, grow down.
@@ -250,7 +253,7 @@ TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
bbfc.reset([[BookmarkBarFolderControllerLow alloc]
initWithParentButton:parentButton
parentController:nil
- barController:parentBarController_]);
+ barController:bar_]);
[bbfc window];
[bbfc setRealTopLeft:YES];
NSPoint pt = [bbfc windowTopLeftForWidth:0]; // screen coords
@@ -259,8 +262,10 @@ TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
convertBaseToScreen:[parentButton
convertRectToBase:[parentButton frame]].origin];
// Within margin
- EXPECT_LE(abs(pt.x - buttonOriginInScreen.x), 2);
- EXPECT_LE(abs(pt.y - buttonOriginInScreen.y), 2);
+ 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];
@@ -272,7 +277,7 @@ TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
bbfc2.reset([[BookmarkBarFolderControllerLow alloc]
initWithParentButton:[[bbfc buttons] objectAtIndex:0]
parentController:bbfc.get()
- barController:parentBarController_]);
+ barController:bar_]);
[bbfc2 window];
[bbfc2 setRealTopLeft:YES];
pt = [bbfc2 windowTopLeftForWidth:0];
@@ -292,13 +297,12 @@ TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
int i;
// Make some super duper deeply nested folders.
for (i=0; i<count; i++) {
- folder = model->AddGroup(folder, 0, L"nested folder");
+ folder = model->AddGroup(folder, 0, ASCIIToUTF16("nested folder"));
}
// Setup initial state for opening all folders.
folder = parent;
- BookmarkButton* parentButton = [[parentBarController_ buttons]
- objectAtIndex:0];
+ BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
BookmarkBarFolderController* parentController = nil;
EXPECT_TRUE(parentButton);
@@ -310,7 +314,7 @@ TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
[[BookmarkBarFolderControllerNoLevel alloc]
initWithParentButton:parentButton
parentController:parentController
- barController:parentBarController_];
+ barController:bar_];
[folder_controller_array addObject:bbfcl];
[bbfcl autorelease];
[bbfcl window];
@@ -412,7 +416,7 @@ TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
bbfc.reset(SimpleBookmarkBarFolderController());
EXPECT_TRUE(bbfc.get());
- [parentBarController_ setChildFolderDelegate:bbfc.get()];
+ [bar_ setChildFolderDelegate:bbfc.get()];
EXPECT_FALSE([bbfc childFolderWillShow]);
[bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
@@ -422,7 +426,7 @@ TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
[bbfc closeBookmarkFolder:nil];
EXPECT_TRUE([bbfc childFolderWillClose]);
- [parentBarController_ setChildFolderDelegate:nil];
+ [bar_ setChildFolderDelegate:nil];
}
// Make sure bookmark folders have variable widths.
@@ -505,6 +509,59 @@ TEST_F(BookmarkBarFolderControllerTest, SimpleScroll) {
}
}
+// 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_;
@@ -595,13 +652,13 @@ class BookmarkBarFolderControllerMenuTest : public CocoaTest {
TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ 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.
@@ -627,7 +684,7 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
to:[targetButton center]
copy:NO];
// The button should have landed just after "2f1b".
- const std::wstring expected_string(L"2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
+ 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));
@@ -646,10 +703,10 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
// and grown vertically.
NSRect expectedToWindowFrame = oldToWindowFrame;
expectedToWindowFrame.origin.x -= horizontalShift;
- expectedToWindowFrame.origin.y -=
- bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
- expectedToWindowFrame.size.height +=
- bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
+ CGFloat diff = (bookmarks::kBookmarkBarHeight +
+ 2*bookmarks::kBookmarkVerticalPadding);
+ expectedToWindowFrame.origin.y -= diff;
+ expectedToWindowFrame.size.height += diff;
EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
// Move the button back to the bar at the beginning.
@@ -667,13 +724,13 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ 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.
@@ -698,7 +755,7 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
to:[targetButton center]
copy:YES];
// The button should have landed just after "2f1b".
- const std::wstring expected_1(L"1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
+ 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));
@@ -710,10 +767,10 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame);
// The toWindow should have shifted down vertically and grown vertically.
NSRect expectedToWindowFrame = oldToWindowFrame;
- expectedToWindowFrame.origin.y -=
- bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
- expectedToWindowFrame.size.height +=
- bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
+ 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".
@@ -724,7 +781,7 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
[bar_ dragButton:draggedButton
to:[targetButton left]
copy:YES];
- const std::wstring expected_2(L"1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
+ 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));
@@ -733,13 +790,13 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Pop up a folder menu and a subfolder menu.
@@ -774,7 +831,7 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
to:[targetButton center]
copy:NO];
// The button should have landed just after "2f".
- const std::wstring expected_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
+ 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));
@@ -795,13 +852,13 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Pop up a folder menu.
@@ -825,7 +882,7 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
to:[targetButton top]
copy:NO];
// The button should have landed above "4f1f".
- const std::wstring expected_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
+ 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));
@@ -841,13 +898,13 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Pop up a folder menu.
@@ -875,13 +932,13 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Pop up a folder menu and a subfolder menu.
@@ -911,7 +968,7 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
to:[targetButton top]
copy:NO];
// The button should have landed above "4f2f".
- const std::wstring expected_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ 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));
@@ -925,12 +982,12 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring
- model_string(L"a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
+ const std::string
+ model_string("a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Pop up a folder menu.
@@ -954,8 +1011,8 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
to:[targetButton center]
copy:NO];
// Verify the model change.
- const std::wstring
- expected_string(L"a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
+ 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]);
@@ -965,11 +1022,11 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
+ const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Pop up a folder menu.
@@ -986,50 +1043,50 @@ TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
// Move a button around a bit.
[folder moveButtonFromIndex:0 toIndex:2];
- EXPECT_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"2f2b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"2f3b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"2f1b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"2f1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"2f2b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"2f3b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"3b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"2f1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"2f2b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:3] title] isEqualToString:@"2f3b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"3b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"2f1b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"2f2b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:3] title] isEqualToString:@"2f3b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:4] title] isEqualToString:@"4b"]);
+ 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_TRUE([[[buttons objectAtIndex:0] title] isEqualToString:@"3b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:1] title] isEqualToString:@"2f2b"]);
- EXPECT_TRUE([[[buttons objectAtIndex:2] title] isEqualToString:@"2f3b"]);
+ 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]);
}
TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2b ] 3b ");
+ const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Find the main bar controller.
@@ -1060,17 +1117,17 @@ TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2b 3b ");
+ const std::string model_string("1b 2b 3b ");
model_test_utils::AddNodesFromModelString(model, root, model_string);
// Validate initial model.
- std::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ 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(),
- L"BIG");
+ ASCIIToUTF16("BIG"));
// Pop open the new folder window and verify it has one (empty) item.
BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
@@ -1080,14 +1137,16 @@ TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
EXPECT_TRUE(folderController);
NSWindow* folderMenu = [folderController window];
EXPECT_TRUE(folderMenu);
- CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkButtonHeight;
+ 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(), L"a", GURL("http://a.com/"));
+ model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("a"),
+ GURL("http://a.com/"));
folderController = [bar_ folderController];
EXPECT_TRUE(folderController);
folderMenu = [folderController window];
@@ -1099,12 +1158,12 @@ TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
button = [folderController buttonWithTitleEqualTo:@"a"];
CGFloat buttonWidth = NSWidth([button frame]);
CGFloat expectedWidth =
- buttonWidth + (2 * bookmarks::kBookmarkVerticalPadding) +
- bookmarks::kScrollViewContentWidthMargin;
+ 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(), L"A really, really long name",
+ 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]));
@@ -1120,7 +1179,8 @@ TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
menuHeight = NSHeight([folderMenu frame]);
NSUInteger tripWire = 0; // Prevent a runaway.
while (![folderController scrollable] && ++tripWire < 100) {
- model.AddURL(folder, folder->GetChildCount(), L"B", GURL("http://b.com/"));
+ model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("B"),
+ GURL("http://b.com/"));
oldMenuHeight = menuHeight;
menuHeight = NSHeight([folderMenu frame]);
}
@@ -1141,6 +1201,38 @@ TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
EXPECT_GT(buttonWidth, NSWidth([button frame]));
}
+// 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 {
@@ -1179,16 +1271,16 @@ TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
+ 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::wstring other_string(L"O1b O2b O3f:[ O3f1b O3f2f ] "
- "O4f:[ O4f1b O4f2f ] 05b ");
+ 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::wstring actual = model_test_utils::ModelStringFromNode(root);
+ std::string actual = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actual);
actual = model_test_utils::ModelStringFromNode(other);
EXPECT_EQ(other_string, actual);
@@ -1200,7 +1292,6 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
initWithParentButton:button
parentController:nil
barController:bar_]);
- [folderController window];
BookmarkButton* targetButton =
[folderController buttonWithTitleEqualTo:@"2f1b"];
ASSERT_TRUE(targetButton);
@@ -1213,8 +1304,8 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
[folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
// Verify the model.
- const std::wstring expected(L"1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
- "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
+ 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);
@@ -1222,28 +1313,67 @@ TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"];
ASSERT_TRUE(targetButton);
newNode = other->GetChild(2); // Should be O4f.
- EXPECT_EQ(newNode->GetTitle(), L"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::wstring expectedA(L"1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
- "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
+ 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);
}
+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);
+}
+
TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
+ 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::wstring actual = model_test_utils::ModelStringFromNode(root);
+ std::string actual = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actual);
// Pop open a folder.
@@ -1271,8 +1401,8 @@ TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
int newDisplayedButtons = [buttons count];
EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons);
// Verify the model.
- const std::wstring expected(L"1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4b ");
+ 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);
}
@@ -1280,12 +1410,12 @@ TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
+ 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::wstring actual = model_test_utils::ModelStringFromNode(root);
+ std::string actual = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actual);
// Pop open the folder.
@@ -1336,12 +1466,12 @@ class BookmarkBarFolderControllerClosingTest : public
TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) {
BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::wstring model_string(L"1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
- "2f3b ] 3b ");
+ 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::wstring actualModelString = model_test_utils::ModelStringFromNode(root);
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
EXPECT_EQ(model_string, actualModelString);
// Open the folder menu and submenu.
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_view.mm b/chrome/browser/cocoa/bookmark_bar_folder_view.mm
index d7fd23f..89d9d2a 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_view.mm
+++ b/chrome/browser/cocoa/bookmark_bar_folder_view.mm
@@ -6,6 +6,7 @@
#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_folder_target.h"
+#include "chrome/browser/metrics/user_metrics.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
@implementation BookmarkBarFolderView
@@ -182,6 +183,7 @@
doDrag = [[self controller] dragButton:button
to:[info draggingLocation]
copy:copy];
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd"));
}
return doDrag;
}
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm b/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm
index 3fb4d11..15046a3 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_folder_view_unittest.mm
@@ -8,6 +8,7 @@
#import "chrome/browser/cocoa/bookmark_button.h"
#import "chrome/browser/cocoa/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"
@@ -82,12 +83,7 @@ namespace {
// NSPasteboard mocking functions.
- (BOOL)containsURLData {
- NSArray* urlTypes = [NSArray arrayWithObjects:
- kWebURLsWithTitlesPboardType,
- NSURLPboardType,
- NSFilenamesPboardType,
- NSStringPboardType,
- nil];
+ NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
if (dragDataType_)
return [urlTypes containsObject:dragDataType_];
return NO;
@@ -182,36 +178,16 @@ TEST_F(BookmarkBarFolderViewTest, URLDragAndDrop) {
[view_ setController:info.get()];
[info reset];
- [info setDragDataType:kWebURLsWithTitlesPboardType];
- 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];
-
- [info setDragDataType:NSURLPboardType];
- 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];
-
- [info setDragDataType:NSFilenamesPboardType];
- 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];
-
- [info setDragDataType:NSStringPboardType];
- 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]);
+ 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) {
diff --git a/chrome/browser/cocoa/bookmark_bar_folder_window.h b/chrome/browser/cocoa/bookmark_bar_folder_window.h
index 7337521..99997d7 100644
--- a/chrome/browser/cocoa/bookmark_bar_folder_window.h
+++ b/chrome/browser/cocoa/bookmark_bar_folder_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_FOLDER_WINDOW_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_FOLDER_WINDOW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#import "base/cocoa_protocols_mac.h"
diff --git a/chrome/browser/cocoa/bookmark_bar_state.h b/chrome/browser/cocoa/bookmark_bar_state.h
index 4d6af05..718f111 100644
--- a/chrome/browser/cocoa/bookmark_bar_state.h
+++ b/chrome/browser/cocoa/bookmark_bar_state.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_STATE_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_STATE_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_bar_toolbar_view.h b/chrome/browser/cocoa/bookmark_bar_toolbar_view.h
index b2b08ac..5a866e4 100644
--- a/chrome/browser/cocoa/bookmark_bar_toolbar_view.h
+++ b/chrome/browser/cocoa/bookmark_bar_toolbar_view.h
@@ -9,6 +9,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_TOOLBAR_VIEW_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_TOOLBAR_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm b/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm
index 9f50222..f2c8494 100644
--- a/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm
+++ b/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm
@@ -6,12 +6,12 @@
#include "app/theme_provider.h"
#include "gfx/rect.h"
-#include "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/bookmark_bar_constants.h"
#import "chrome/browser/cocoa/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;
diff --git a/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm b/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm
index eaf3a34..0b5a1cc 100644
--- a/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm
@@ -6,10 +6,10 @@
#include "app/theme_provider.h"
#include "base/scoped_nsobject.h"
-#include "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/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"
diff --git a/chrome/browser/cocoa/bookmark_bar_unittest_helper.h b/chrome/browser/cocoa/bookmark_bar_unittest_helper.h
index c122dff..d62e962 100644
--- a/chrome/browser/cocoa/bookmark_bar_unittest_helper.h
+++ b/chrome/browser/cocoa/bookmark_bar_unittest_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_AUTOCOMPLETE_BOOKMARK_BAR_UNITTEST_HELPER_H_
#define CHROME_BROWSER_COCOA_AUTOCOMPLETE_BOOKMARK_BAR_UNITTEST_HELPER_H_
+#pragma once
#import <Foundation/Foundation.h>
diff --git a/chrome/browser/cocoa/bookmark_bar_view.h b/chrome/browser/cocoa/bookmark_bar_view.h
index 6f2a7ac..f8439fa 100644
--- a/chrome/browser/cocoa/bookmark_bar_view.h
+++ b/chrome/browser/cocoa/bookmark_bar_view.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BAR_VIEW_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_bar_view.mm b/chrome/browser/cocoa/bookmark_bar_view.mm
index 2098521..ffc8441 100644
--- a/chrome/browser/cocoa/bookmark_bar_view.mm
+++ b/chrome/browser/cocoa/bookmark_bar_view.mm
@@ -5,12 +5,13 @@
#import "chrome/browser/cocoa/bookmark_bar_view.h"
#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
-#import "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_button.h"
#import "chrome/browser/cocoa/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)
@@ -226,6 +227,7 @@
rtn = [controller_ dragButton:button
to:[info draggingLocation]
copy:copy];
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragEnd"));
}
return rtn;
}
diff --git a/chrome/browser/cocoa/bookmark_bar_view_unittest.mm b/chrome/browser/cocoa/bookmark_bar_view_unittest.mm
index 287d01d..710a9b9 100644
--- a/chrome/browser/cocoa/bookmark_bar_view_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bar_view_unittest.mm
@@ -8,6 +8,7 @@
#import "chrome/browser/cocoa/bookmark_button.h"
#import "chrome/browser/cocoa/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"
@@ -82,12 +83,7 @@ namespace {
// NSPasteboard mocking functions.
- (BOOL)containsURLData {
- NSArray* urlTypes = [NSArray arrayWithObjects:
- kWebURLsWithTitlesPboardType,
- NSURLPboardType,
- NSFilenamesPboardType,
- NSStringPboardType,
- nil];
+ NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
if (dragDataType_)
return [urlTypes containsObject:dragDataType_];
return NO;
@@ -186,36 +182,16 @@ TEST_F(BookmarkBarViewTest, URLDragAndDrop) {
[view_ setController:info.get()];
[info reset];
- [info setDragDataType:kWebURLsWithTitlesPboardType];
- 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];
-
- [info setDragDataType:NSURLPboardType];
- 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];
-
- [info setDragDataType:NSFilenamesPboardType];
- 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];
-
- [info setDragDataType:NSStringPboardType];
- 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]);
+ 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) {
diff --git a/chrome/browser/cocoa/bookmark_bubble_controller.h b/chrome/browser/cocoa/bookmark_bubble_controller.h
index 2305d2f..8ff05da 100644
--- a/chrome/browser/cocoa/bookmark_bubble_controller.h
+++ b/chrome/browser/cocoa/bookmark_bubble_controller.h
@@ -26,6 +26,9 @@ class BookmarkNode;
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.
diff --git a/chrome/browser/cocoa/bookmark_bubble_controller.mm b/chrome/browser/cocoa/bookmark_bubble_controller.mm
index 3d9726d..0258d0d 100644
--- a/chrome/browser/cocoa/bookmark_bubble_controller.mm
+++ b/chrome/browser/cocoa/bookmark_bubble_controller.mm
@@ -3,10 +3,13 @@
// found in the LICENSE file.
#import "chrome/browser/cocoa/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/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"
@@ -108,6 +111,48 @@ void BookmarkBubbleNotificationBridge::Observe(
[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
@@ -126,6 +171,7 @@ void BookmarkBubbleNotificationBridge::Observe(
[[NSNotificationCenter defaultCenter] removeObserver:self];
bookmark_observer_.reset(NULL);
chrome_observer_.reset(NULL);
+ [self stopPulsingBookmarkButton];
[self autorelease];
}
@@ -173,6 +219,9 @@ void BookmarkBubbleNotificationBridge::Observe(
chrome_observer_.reset(new BookmarkBubbleNotificationBridge(
self, @selector(dismissWithoutEditing:)));
+ // Pulse something interesting on the bookmark bar.
+ [self startPulsingBookmarkButton:node_];
+
[window makeKeyAndOrderFront:self];
}
@@ -209,6 +258,7 @@ void BookmarkBubbleNotificationBridge::Observe(
}
- (IBAction)ok:(id)sender {
+ [self stopPulsingBookmarkButton]; // before parent changes
[self updateBookmarkNode];
[self close];
}
@@ -226,6 +276,8 @@ void BookmarkBubbleNotificationBridge::Observe(
}
- (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());
@@ -271,10 +323,10 @@ void BookmarkBubbleNotificationBridge::Observe(
if (!node_) return;
// First the title...
- NSString* oldTitle = base::SysWideToNSString(node_->GetTitle());
+ NSString* oldTitle = base::SysUTF16ToNSString(node_->GetTitle());
NSString* newTitle = [nameTextField_ stringValue];
if (![oldTitle isEqual:newTitle]) {
- model_->SetTitle(node_, base::SysNSStringToWide(newTitle));
+ model_->SetTitle(node_, base::SysNSStringToUTF16(newTitle));
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBubble_ChangeTitleInBubble"),
model_->profile());
@@ -300,7 +352,7 @@ void BookmarkBubbleNotificationBridge::Observe(
// Fill in all information related to the folder pop up button.
- (void)fillInFolderList {
- [nameTextField_ setStringValue:base::SysWideToNSString(node_->GetTitle())];
+ [nameTextField_ setStringValue:base::SysUTF16ToNSString(node_->GetTitle())];
DCHECK([folderPopUpButton_ numberOfItems] == 0);
[self addFolderNodes:model_->root_node()
toPopUpButton:folderPopUpButton_
@@ -334,7 +386,7 @@ void BookmarkBubbleNotificationBridge::Observe(
toPopUpButton:(NSPopUpButton*)button
indentation:(int)indentation {
if (!model_->is_root(parent)) {
- NSString* title = base::SysWideToNSString(parent->GetTitle());
+ NSString* title = base::SysUTF16ToNSString(parent->GetTitle());
NSMenu* menu = [button menu];
NSMenuItem* item = [menu addItemWithTitle:title
action:NULL
diff --git a/chrome/browser/cocoa/bookmark_bubble_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bubble_controller_unittest.mm
index e392ed4..2c445f3 100644
--- a/chrome/browser/cocoa/bookmark_bubble_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_bubble_controller_unittest.mm
@@ -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,6 +6,7 @@
#include "base/basictypes.h"
#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
#import "chrome/browser/cocoa/bookmark_bubble_controller.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
#include "chrome/browser/cocoa/browser_window_controller.h"
@@ -13,8 +14,44 @@
#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 {
@@ -69,7 +106,7 @@ TEST_F(BookmarkBubbleControllerTest, TestBubbleWindow) {
BookmarkModel* model = GetBookmarkModel();
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
0,
- L"Bookie markie title",
+ ASCIIToUTF16("Bookie markie title"),
GURL("http://www.google.com"));
BookmarkBubbleController* controller = ControllerForNode(node);
EXPECT_TRUE(controller);
@@ -84,7 +121,7 @@ TEST_F(BookmarkBubbleControllerTest, TestClosingParentWindow) {
BookmarkModel* model = GetBookmarkModel();
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
0,
- L"Bookie markie title",
+ ASCIIToUTF16("Bookie markie title"),
GURL("http://www.google.com"));
BookmarkBubbleController* controller = ControllerForNode(node);
EXPECT_TRUE(controller);
@@ -102,22 +139,25 @@ TEST_F(BookmarkBubbleControllerTest, TestFillInFolder) {
EXPECT_TRUE(model);
const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0, L"one");
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("one"));
EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1, L"two");
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
+ ASCIIToUTF16("two"));
EXPECT_TRUE(node2);
- const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2, L"three");
+ const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
+ ASCIIToUTF16("three"));
EXPECT_TRUE(node3);
- const BookmarkNode* node4 = model->AddGroup(node2, 0, L"sub");
+ const BookmarkNode* node4 = model->AddGroup(node2, 0, ASCIIToUTF16("sub"));
EXPECT_TRUE(node4);
- const BookmarkNode* node5 =
- model->AddURL(node1, 0, L"title1", GURL("http://www.google.com"));
+ const BookmarkNode* node5 = model->AddURL(node1, 0, ASCIIToUTF16("title1"),
+ GURL("http://www.google.com"));
EXPECT_TRUE(node5);
- const BookmarkNode* node6 =
- model->AddURL(node3, 0, L"title2", GURL("http://www.google.com"));
+ const BookmarkNode* node6 = model->AddURL(node3, 0, ASCIIToUTF16("title2"),
+ GURL("http://www.google.com"));
EXPECT_TRUE(node6);
- const BookmarkNode* node7 =
- model->AddURL(node4, 0, L"title3", GURL("http://www.google.com/reader"));
+ const BookmarkNode* node7 = model->AddURL(node4, 0, ASCIIToUTF16("title3"),
+ GURL("http://www.google.com/reader"));
EXPECT_TRUE(node7);
BookmarkBubbleController* controller = ControllerForNode(node4);
@@ -140,14 +180,17 @@ TEST_F(BookmarkBubbleControllerTest, TestFolderWithBlankName) {
EXPECT_TRUE(model);
const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0, L"one");
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("one"));
EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1, L"");
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
+ ASCIIToUTF16(""));
EXPECT_TRUE(node2);
- const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2, L"three");
+ const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
+ ASCIIToUTF16("three"));
EXPECT_TRUE(node3);
- const BookmarkNode* node2_1 =
- model->AddURL(node2, 0, L"title1", GURL("http://www.google.com"));
+ const BookmarkNode* node2_1 = model->AddURL(node2, 0, ASCIIToUTF16("title1"),
+ GURL("http://www.google.com"));
EXPECT_TRUE(node2_1);
BookmarkBubbleController* controller = ControllerForNode(node1);
@@ -174,7 +217,7 @@ TEST_F(BookmarkBubbleControllerTest, TestEdit) {
BookmarkModel* model = GetBookmarkModel();
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
0,
- L"Bookie markie title",
+ ASCIIToUTF16("Bookie markie title"),
GURL("http://www.google.com"));
BookmarkBubbleController* controller = ControllerForNode(node);
EXPECT_TRUE(controller);
@@ -187,20 +230,25 @@ TEST_F(BookmarkBubbleControllerTest, TestEdit) {
}
// 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,
- L"Bookie markie title",
- GURL("http://www.google.com"));
+ 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
@@ -211,11 +259,13 @@ TEST_F(BookmarkBubbleControllerTest, TestUserEdit) {
EXPECT_TRUE(bookmarkBarNode);
const BookmarkNode* node = model->AddURL(bookmarkBarNode,
0,
- L"short-title",
+ ASCIIToUTF16("short-title"),
GURL("http://www.google.com"));
- const BookmarkNode* grandma = model->AddGroup(bookmarkBarNode, 0, L"grandma");
+ const BookmarkNode* grandma = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("grandma"));
EXPECT_TRUE(grandma);
- const BookmarkNode* grandpa = model->AddGroup(bookmarkBarNode, 0, L"grandpa");
+ const BookmarkNode* grandpa = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("grandpa"));
EXPECT_TRUE(grandpa);
BookmarkBubbleController* controller = ControllerForNode(node);
@@ -226,8 +276,8 @@ TEST_F(BookmarkBubbleControllerTest, TestUserEdit) {
[controller edit:controller];
// Make sure bookmark has changed
- EXPECT_EQ(node->GetTitle(), L"oops");
- EXPECT_EQ(node->GetParent()->GetTitle(), L"grandma");
+ EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("oops"));
+ EXPECT_EQ(node->GetParent()->GetTitle(), ASCIIToUTF16("grandma"));
}
// Confirm happiness with parent nodes that have the same name.
@@ -239,14 +289,15 @@ TEST_F(BookmarkBubbleControllerTest, TestNewParentSameName) {
for (int i=0; i<2; i++) {
const BookmarkNode* node = model->AddURL(bookmarkBarNode,
0,
- L"short-title",
+ ASCIIToUTF16("short-title"),
GURL("http://www.google.com"));
EXPECT_TRUE(node);
- const BookmarkNode* group = model->AddGroup(bookmarkBarNode, 0, L"NAME");
+ const BookmarkNode* group = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("NAME"));
EXPECT_TRUE(group);
- group = model->AddGroup(bookmarkBarNode, 0, L"NAME");
+ group = model->AddGroup(bookmarkBarNode, 0, ASCIIToUTF16("NAME"));
EXPECT_TRUE(group);
- group = model->AddGroup(bookmarkBarNode, 0, L"NAME");
+ group = model->AddGroup(bookmarkBarNode, 0, ASCIIToUTF16("NAME"));
EXPECT_TRUE(group);
BookmarkBubbleController* controller = ControllerForNode(node);
EXPECT_TRUE(controller);
@@ -266,9 +317,11 @@ TEST_F(BookmarkBubbleControllerTest, TestDuplicateNodeNames) {
BookmarkModel* model = GetBookmarkModel();
const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0, L"NAME");
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("NAME"));
EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 0, L"NAME");
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("NAME"));
EXPECT_TRUE(node2);
BookmarkBubbleController* controller = ControllerForNode(bookmarkBarNode);
EXPECT_TRUE(controller);
@@ -277,11 +330,11 @@ TEST_F(BookmarkBubbleControllerTest, TestDuplicateNodeNames) {
[controller setParentFolderSelection:node1];
NSMenuItem* item = [button selectedItem];
id itemObject = [item representedObject];
- EXPECT_TRUE([itemObject isEqual:[NSValue valueWithPointer:node1]]);
+ EXPECT_NSEQ([NSValue valueWithPointer:node1], itemObject);
[controller setParentFolderSelection:node2];
item = [button selectedItem];
itemObject = [item representedObject];
- EXPECT_TRUE([itemObject isEqual:[NSValue valueWithPointer:node2]]);
+ EXPECT_NSEQ([NSValue valueWithPointer:node2], itemObject);
}
// Click the "remove" button
@@ -290,7 +343,7 @@ TEST_F(BookmarkBubbleControllerTest, TestRemove) {
GURL gurl("http://www.google.com");
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
0,
- L"Bookie markie title",
+ ASCIIToUTF16("Bookie markie title"),
gurl);
BookmarkBubbleController* controller = ControllerForNode(node);
EXPECT_TRUE(controller);
@@ -306,7 +359,7 @@ TEST_F(BookmarkBubbleControllerTest, PopUpSelectionChanged) {
BookmarkModel* model = GetBookmarkModel();
GURL gurl("http://www.google.com");
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0, L"super-title",
+ 0, ASCIIToUTF16("super-title"),
gurl);
BookmarkBubbleController* controller = ControllerForNode(node);
EXPECT_TRUE(controller);
@@ -326,7 +379,7 @@ TEST_F(BookmarkBubbleControllerTest, EscapeRemovesNewBookmark) {
GURL gurl("http://www.google.com");
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
0,
- L"Bookie markie title",
+ ASCIIToUTF16("Bookie markie title"),
gurl);
BookmarkBubbleController* controller =
[[BookmarkBubbleController alloc]
@@ -348,7 +401,7 @@ TEST_F(BookmarkBubbleControllerTest, EscapeDoesntTouchExistingBookmark) {
GURL gurl("http://www.google.com");
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
0,
- L"Bookie markie title",
+ ASCIIToUTF16("Bookie markie title"),
gurl);
BookmarkBubbleController* controller = ControllerForNode(node);
EXPECT_TRUE(controller);
@@ -364,13 +417,17 @@ TEST_F(BookmarkBubbleControllerTest, TestMenuIndentation) {
EXPECT_TRUE(model);
const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0, L"one");
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("one"));
EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1, L"two");
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
+ ASCIIToUTF16("two"));
EXPECT_TRUE(node2);
- const BookmarkNode* node2_1 = model->AddGroup(node2, 0, L"two dot one");
+ const BookmarkNode* node2_1 = model->AddGroup(node2, 0,
+ ASCIIToUTF16("two dot one"));
EXPECT_TRUE(node2_1);
- const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2, L"three");
+ const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
+ ASCIIToUTF16("three"));
EXPECT_TRUE(node3);
BookmarkBubbleController* controller = ControllerForNode(node1);
@@ -393,7 +450,7 @@ TEST_F(BookmarkBubbleControllerTest, BubbleGoesAwayOnNewTab) {
BookmarkModel* model = GetBookmarkModel();
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
0,
- L"Bookie markie title",
+ ASCIIToUTF16("Bookie markie title"),
GURL("http://www.google.com"));
EXPECT_EQ(edits_, 0);
diff --git a/chrome/browser/cocoa/bookmark_button.h b/chrome/browser/cocoa/bookmark_button.h
index 745d141..56d9bc1 100644
--- a/chrome/browser/cocoa/bookmark_button.h
+++ b/chrome/browser/cocoa/bookmark_button.h
@@ -40,6 +40,13 @@ class ThemeProvider;
// 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
@@ -180,6 +187,10 @@ class ThemeProvider;
// 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;
@@ -198,6 +209,17 @@ class ThemeProvider;
// 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
@@ -205,3 +227,17 @@ class ThemeProvider;
- (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/bookmark_button.mm b/chrome/browser/cocoa/bookmark_button.mm
index bfacc8f..6c773d6 100644
--- a/chrome/browser/cocoa/bookmark_button.mm
+++ b/chrome/browser/cocoa/bookmark_button.mm
@@ -9,10 +9,21 @@
#import "chrome/browser/cocoa/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.
@@ -35,6 +46,8 @@ static const CGFloat kDragImageOpacity = 0.7;
}
- (void)dealloc {
+ if ([[self cell] respondsToSelector:@selector(safelyStopPulsing)])
+ [[self cell] safelyStopPulsing];
view_id_util::UnsetID(self);
[super dealloc];
}
@@ -52,6 +65,37 @@ static const CGFloat kDragImageOpacity = 0.7;
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 {
@@ -86,6 +130,15 @@ static const CGFloat kDragImageOpacity = 0.7;
withAnimation:NO
delay:NO];
}
+ const BookmarkNode* node = [self bookmarkNode];
+ const BookmarkNode* parent = node ? node->GetParent() : NULL;
+ BOOL isWithinFolder = parent && parent->type() == BookmarkNode::FOLDER;
+ UserMetrics::RecordAction(UserMetricsAction(
+ isWithinFolder ? "BookmarkBarFolder_DragStart" :
+ "BookmarkBar_DragStart"));
+
+ dragMouseOffset_ = [self convertPointFromBase:[event locationInWindow]];
+ dragPending_ = YES;
CGFloat yAt = [self bounds].size.height;
NSSize dragOffset = NSMakeSize(0.0, 0.0);
@@ -93,6 +146,7 @@ static const CGFloat kDragImageOpacity = 0.7;
event:event pasteboard:pboard source:self slideBack:YES];
// And we're done.
+ dragPending_ = NO;
[self autorelease];
} else {
// Avoid blowing up, but we really shouldn't get here.
@@ -111,8 +165,23 @@ static const CGFloat kDragImageOpacity = 0.7;
}
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
- return isLocal ? NSDragOperationCopy | NSDragOperationMove
- : NSDragOperationCopy;
+ 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
diff --git a/chrome/browser/cocoa/bookmark_button_cell.h b/chrome/browser/cocoa/bookmark_button_cell.h
index c05aff8..23bd601 100644
--- a/chrome/browser/cocoa/bookmark_button_cell.h
+++ b/chrome/browser/cocoa/bookmark_button_cell.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_BUTTON_CELL_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_BUTTON_CELL_H_
+#pragma once
#import "base/cocoa_protocols_mac.h"
#import "chrome/browser/cocoa/gradient_button_cell.h"
diff --git a/chrome/browser/cocoa/bookmark_button_cell.mm b/chrome/browser/cocoa/bookmark_button_cell.mm
index f8d0ffc..368f34f 100644
--- a/chrome/browser/cocoa/bookmark_button_cell.mm
+++ b/chrome/browser/cocoa/bookmark_button_cell.mm
@@ -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.
@@ -48,7 +48,7 @@
[self setBookmarkNode:node];
if (node) {
- NSString* title = base::SysWideToNSString(node->GetTitle());
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
[self setBookmarkCellText:title image:cellImage];
[self setMenu:contextMenu];
} else {
@@ -180,6 +180,8 @@
// 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];
@@ -187,8 +189,8 @@
// See comment above mouseEntered:, above.
- (void)mouseExited:(NSEvent*)event {
- [super mouseExited:event];
[[self controlView] mouseExited:event];
+ [super mouseExited:event];
}
- (void)setDrawFolderArrow:(BOOL)draw {
diff --git a/chrome/browser/cocoa/bookmark_button_cell_unittest.mm b/chrome/browser/cocoa/bookmark_button_cell_unittest.mm
index a665a48..7d483bb 100644
--- a/chrome/browser/cocoa/bookmark_button_cell_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_button_cell_unittest.mm
@@ -1,9 +1,11 @@
-// 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.
#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/bookmark_button_cell.h"
#import "chrome/browser/cocoa/bookmark_menu.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
@@ -157,7 +159,8 @@ TEST_F(BookmarkButtonCellTest, Awake) {
TEST_F(BookmarkButtonCellTest, FolderArrow) {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
const BookmarkNode* bar = model->GetBookmarkBarNode();
- const BookmarkNode* node = model->AddURL(bar, bar->GetChildCount(), L"title",
+ const BookmarkNode* node = model->AddURL(bar, bar->GetChildCount(),
+ ASCIIToUTF16("title"),
GURL("http://www.google.com"));
scoped_nsobject<BookmarkButtonCell> cell(
[[BookmarkButtonCell alloc] initForNode:node
diff --git a/chrome/browser/cocoa/bookmark_button_unittest.mm b/chrome/browser/cocoa/bookmark_button_unittest.mm
index bd0f89e..59cb39e 100644
--- a/chrome/browser/cocoa/bookmark_button_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_button_unittest.mm
@@ -1,8 +1,10 @@
-// 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.
#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
#import "chrome/browser/cocoa/bookmark_button.h"
#import "chrome/browser/cocoa/bookmark_button_cell.h"
#import "chrome/browser/cocoa/browser_test_helper.h"
@@ -16,6 +18,8 @@
@public
int entered_;
int exited_;
+ BOOL canDragToTrash_;
+ int didDragToTrashCount_;
}
@end
@@ -40,6 +44,15 @@
- (NSWindow*)browserWindow {
return nil;
}
+
+- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button {
+ return canDragToTrash_;
+}
+
+- (void)didDragBookmarkToTrash:(BookmarkButton*)button {
+ didDragToTrashCount_++;
+}
+
@end
namespace {
@@ -79,7 +92,8 @@ TEST_F(BookmarkButtonTest, FolderAndEmptyOrNot) {
EXPECT_TRUE([button isFolder]);
EXPECT_EQ([button bookmarkNode], node);
- node = model->AddURL(node, 0, L"hi mom", GURL("http://www.google.com"));
+ node = model->AddURL(node, 0, ASCIIToUTF16("hi mom"),
+ GURL("http://www.google.com"));
[cell setBookmarkNode:node];
EXPECT_FALSE([button isEmpty]);
EXPECT_FALSE([button isFolder]);
@@ -111,4 +125,50 @@ TEST_F(BookmarkButtonTest, MouseEnterExitRedirect) {
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/bookmark_editor_base_controller.h b/chrome/browser/cocoa/bookmark_editor_base_controller.h
index 1c758f8..34705bd 100644
--- a/chrome/browser/cocoa/bookmark_editor_base_controller.h
+++ b/chrome/browser/cocoa/bookmark_editor_base_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_editor_base_controller.mm b/chrome/browser/cocoa/bookmark_editor_base_controller.mm
index af88ea7..03a7942 100644
--- a/chrome/browser/cocoa/bookmark_editor_base_controller.mm
+++ b/chrome/browser/cocoa/bookmark_editor_base_controller.mm
@@ -395,7 +395,7 @@ class BookmarkEditorBaseControllerBridge : public BookmarkModelObserver {
for (int i = 0; i < childCount; ++i) {
const BookmarkNode* childNode = node->GetChild(i);
if (childNode->type() != BookmarkNode::URL) {
- NSString* childName = base::SysWideToNSString(childNode->GetTitle());
+ NSString* childName = base::SysUTF16ToNSString(childNode->GetTitle());
NSMutableArray* children = [self addChildFoldersFromNode:childNode];
BookmarkFolderInfo* folderInfo =
[BookmarkFolderInfo bookmarkFolderInfoWithFolderName:childName
@@ -463,7 +463,7 @@ class BookmarkEditorBaseControllerBridge : public BookmarkModelObserver {
BookmarkModel* model = [self bookmarkModel];
const BookmarkNode* newFolder =
model->AddGroup(parentNode, i,
- base::SysNSStringToWide([subFolderInfo folderName]));
+ base::SysNSStringToUTF16([subFolderInfo folderName]));
// Update our dictionary with the actual folder node just created.
[subFolderInfo setFolderNode:newFolder];
[subFolderInfo setNewFolder:NO];
diff --git a/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm b/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm
index 17159db..363461b 100644
--- a/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_editor_base_controller_unittest.mm
@@ -7,11 +7,14 @@
#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/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 {
@@ -37,28 +40,28 @@ class BookmarkEditorBaseControllerTest : public CocoaTest {
// b-4
BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
const BookmarkNode* root = model.GetBookmarkBarNode();
- group_a_ = model.AddGroup(root, 0, L"a");
- model.AddURL(group_a_, 0, L"a-0", GURL("http://a-0.com"));
- model.AddURL(group_a_, 1, L"a-1", GURL("http://a-1.com"));
- model.AddURL(group_a_, 2, L"a-2", GURL("http://a-2.com"));
-
- group_b_ = model.AddGroup(root, 1, L"b");
- group_b_0_ = model.AddGroup(group_b_, 0, L"b-0");
- model.AddURL(group_b_0_, 0, L"bb-0", GURL("http://bb-0.com"));
- model.AddURL(group_b_, 1, L"b-1", GURL("http://b-1.com"));
- model.AddURL(group_b_, 2, L"b-2", GURL("http://b-2.com"));
- group_b_3_ = model.AddGroup(group_b_, 3, L"b-3");
- model.AddURL(group_b_3_, 0, L"b-30", GURL("http://b-30.com"));
- model.AddURL(group_b_3_, 1, L"b-31", GURL("http://b-31.com"));
- model.AddURL(group_b_, 4, L"b-4", GURL("http://b-4.com"));
-
- group_c_ = model.AddGroup(root, 2, L"c");
- model.AddURL(group_c_, 0, L"c-0", GURL("http://c-0.com"));
- model.AddURL(group_c_, 1, L"c-1", GURL("http://c-1.com"));
- model.AddURL(group_c_, 2, L"c-2", GURL("http://c-2.com"));
- model.AddURL(group_c_, 3, L"c-3", GURL("http://c-3.com"));
-
- model.AddURL(root, 3, L"d", GURL("http://d-0.com"));
+ 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() {
@@ -154,7 +157,7 @@ TEST_F(BookmarkEditorBaseControllerTest, CreateFolder) {
BookmarkFolderInfo* newFolderInfo = [controller_ selectedFolder];
EXPECT_TRUE(newFolderInfo);
NSString* newFolderName = [newFolderInfo folderName];
- EXPECT_TRUE([newFolderName isEqualToString:expectedName]);
+ EXPECT_NSEQ(expectedName, newFolderName);
[controller_ createNewFolders];
// Verify that the tab folder was added to the new folder.
EXPECT_EQ(3, group_b_3_->GetChildCount());
@@ -205,7 +208,8 @@ TEST_F(BookmarkEditorBaseControllerTest, FolderAdded) {
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, L"added");
+ const BookmarkNode* group_added = model.AddGroup(root, 0,
+ ASCIIToUTF16("added"));
[controller_ selectTestNodeInBrowser:group_added];
EXPECT_EQ(group_added, [controller_ selectedNode]);
diff --git a/chrome/browser/cocoa/bookmark_editor_controller.h b/chrome/browser/cocoa/bookmark_editor_controller.h
index 24fde02..696c1d2 100644
--- a/chrome/browser/cocoa/bookmark_editor_controller.h
+++ b/chrome/browser/cocoa/bookmark_editor_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_CONTROLLER_H_
+#pragma once
#import "chrome/browser/cocoa/bookmark_editor_base_controller.h"
diff --git a/chrome/browser/cocoa/bookmark_editor_controller.mm b/chrome/browser/cocoa/bookmark_editor_controller.mm
index fed6d7d..90b47ed 100644
--- a/chrome/browser/cocoa/bookmark_editor_controller.mm
+++ b/chrome/browser/cocoa/bookmark_editor_controller.mm
@@ -4,6 +4,7 @@
#import "chrome/browser/cocoa/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"
@@ -47,7 +48,7 @@
// 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::SysWideToNSString(node_->GetTitle())];
+ [self setInitialName:base::SysUTF16ToNSString(node_->GetTitle())];
std::string url_string = node_->GetURL().possibly_invalid_spec();
initialUrl_.reset([[NSString stringWithUTF8String:url_string.c_str()]
retain]);
@@ -104,7 +105,7 @@
- (NSNumber*)didCommit {
NSString* name = [[self displayName] stringByTrimmingCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
- std::wstring newTitle = base::SysNSStringToWide(name);
+ string16 newTitle = base::SysNSStringToUTF16(name);
const BookmarkNode* newParentNode = [self selectedNode];
GURL newURL = [self GURLFromUrlField];
if (!newURL.is_valid()) {
diff --git a/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm b/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm
index 209fca2..8c826ac 100644
--- a/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm
@@ -4,11 +4,15 @@
#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/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 {
@@ -17,7 +21,7 @@ class BookmarkEditorControllerTest : public CocoaTest {
const BookmarkNode* default_node_;
const BookmarkNode* default_parent_;
const char* default_name_;
- std::wstring default_title_;
+ string16 default_title_;
BookmarkEditorController* controller_;
virtual void SetUp() {
@@ -25,7 +29,7 @@ class BookmarkEditorControllerTest : public CocoaTest {
BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
default_parent_ = model->GetBookmarkBarNode();
default_name_ = "http://www.zim-bop-a-dee.com/";
- default_title_ = L"ooh title";
+ default_title_ = ASCIIToUTF16("ooh title");
const BookmarkNode* default_node = model->AddURL(default_parent_, 0,
default_title_,
GURL(default_name_));
@@ -57,7 +61,7 @@ TEST_F(BookmarkEditorControllerTest, EditTitle) {
[controller_ ok:nil];
ASSERT_EQ(default_parent_->GetChildCount(), 1);
const BookmarkNode* child = default_parent_->GetChild(0);
- EXPECT_EQ(child->GetTitle(), L"whamma jamma bamma");
+ EXPECT_EQ(child->GetTitle(), ASCIIToUTF16("whamma jamma bamma"));
EXPECT_EQ(child->GetURL(), GURL(default_name_));
}
@@ -118,12 +122,12 @@ TEST_F(BookmarkEditorControllerTest, GoodAndBadURLsChangeColor) {
[controller_ setDisplayURL:@""];
NSColor *urlColorB = [controller_ urlFieldColor];
EXPECT_TRUE(urlColorB);
- EXPECT_FALSE([urlColorB isEqual:urlColorA]);
+ EXPECT_NSNE(urlColorA, urlColorB);
[controller_ setDisplayURL:@"http://www.google.com"];
[controller_ cancel:nil];
urlColorB = [controller_ urlFieldColor];
EXPECT_TRUE(urlColorB);
- EXPECT_TRUE([urlColorB isEqual:urlColorA]);
+ EXPECT_NSEQ(urlColorA, urlColorB);
}
class BookmarkEditorControllerNoNodeTest : public CocoaTest {
@@ -161,7 +165,7 @@ TEST_F(BookmarkEditorControllerNoNodeTest, NoNodeNoTree) {
class BookmarkEditorControllerYesNodeTest : public CocoaTest {
public:
BrowserTestHelper browser_helper_;
- std::wstring default_title_;
+ string16 default_title_;
const char* url_name_;
BookmarkEditorController* controller_;
@@ -169,7 +173,7 @@ class BookmarkEditorControllerYesNodeTest : public CocoaTest {
CocoaTest::SetUp();
BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
const BookmarkNode* parent = model->GetBookmarkBarNode();
- default_title_ = L"wooh title";
+ 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_));
@@ -190,11 +194,11 @@ class BookmarkEditorControllerYesNodeTest : public CocoaTest {
};
TEST_F(BookmarkEditorControllerYesNodeTest, YesNodeShowTree) {
- EXPECT_TRUE([base::SysWideToNSString(default_title_)
- isEqual:[controller_ displayName]]);
- EXPECT_TRUE([[NSString stringWithCString:url_name_
- encoding:NSUTF8StringEncoding]
- isEqual:[controller_ displayURL]]);
+ EXPECT_NSEQ(base::SysUTF16ToNSString(default_title_),
+ [controller_ displayName]);
+ EXPECT_NSEQ([NSString stringWithCString:url_name_
+ encoding:NSUTF8StringEncoding],
+ [controller_ displayURL]);
[controller_ cancel:nil];
}
@@ -224,35 +228,36 @@ class BookmarkEditorControllerTreeTest : public CocoaTest {
// b-2
BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
const BookmarkNode* root = model.GetBookmarkBarNode();
- group_a_ = model.AddGroup(root, 0, L"a");
- model.AddURL(group_a_, 0, L"a-0", GURL("http://a-0.com"));
- model.AddURL(group_a_, 1, L"a-1", GURL("http://a-1.com"));
- model.AddURL(group_a_, 2, L"a-2", GURL("http://a-2.com"));
-
- group_b_ = model.AddGroup(root, 1, L"b");
- model.AddURL(group_b_, 0, L"b-0", GURL("http://b-0.com"));
- group_bb_ = model.AddGroup(group_b_, 1, L"bb");
- model.AddURL(group_bb_, 0, L"bb-0", GURL("http://bb-0.com"));
- model.AddURL(group_bb_, 1, L"bb-1", GURL("http://bb-1.com"));
- model.AddURL(group_bb_, 2, L"bb-2", GURL("http://bb-2.com"));
+ 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, L"bb-3", bb3_url_1_);
+ bookmark_bb_3_ = model.AddURL(group_bb_, 3, ASCIIToUTF16("bb-3"),
+ bb3_url_1_);
- model.AddURL(group_bb_, 4, L"bb-4", GURL("http://bb-4.com"));
- model.AddURL(group_b_, 2, L"b-1", GURL("http://b-2.com"));
- model.AddURL(group_b_, 3, L"b-2", GURL("http://b-3.com"));
+ 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, L"c");
- model.AddURL(group_c_, 0, L"c-0", GURL("http://c-0.com"));
- model.AddURL(group_c_, 1, L"c-1", GURL("http://c-1.com"));
- model.AddURL(group_c_, 2, L"c-2", GURL("http://c-2.com"));
- model.AddURL(group_c_, 3, L"c-3", GURL("http://c-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, L"d", GURL("http://d-0.com"));
+ model.AddURL(root, 3, ASCIIToUTF16("d"), GURL("http://d-0.com"));
}
virtual BookmarkEditorController* CreateController() {
@@ -383,7 +388,7 @@ TEST_F(BookmarkEditorControllerTreeTest, ChangeNameAndBookmarkGroup) {
ASSERT_EQ(parent, group_c_);
int childIndex = parent->IndexOfChild(bookmark_bb_3_);
ASSERT_EQ(4, childIndex);
- EXPECT_EQ(bookmark_bb_3_->GetTitle(), L"NEW NAME");
+ EXPECT_EQ(bookmark_bb_3_->GetTitle(), ASCIIToUTF16("NEW NAME"));
}
TEST_F(BookmarkEditorControllerTreeTest, AddFolderWithGroupSelected) {
@@ -413,6 +418,6 @@ TEST_F(BookmarkEditorControllerTreeNoNodeTest, NewBookmarkNoNode) {
[controller_ ok:nil];
const BookmarkNode* new_node = group_bb_->GetChild(5);
ASSERT_EQ(0, new_node->GetChildCount());
- EXPECT_EQ(new_node->GetTitle(), L"NEW BOOKMARK");
+ EXPECT_EQ(new_node->GetTitle(), ASCIIToUTF16("NEW BOOKMARK"));
EXPECT_EQ(new_node->GetURL(), GURL("http://NEWURL.com"));
}
diff --git a/chrome/browser/cocoa/bookmark_folder_target.h b/chrome/browser/cocoa/bookmark_folder_target.h
index 2c02c45..60c766b 100644
--- a/chrome/browser/cocoa/bookmark_folder_target.h
+++ b/chrome/browser/cocoa/bookmark_folder_target.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_folder_target.mm b/chrome/browser/cocoa/bookmark_folder_target.mm
index b47e5a7..1aac77f 100644
--- a/chrome/browser/cocoa/bookmark_folder_target.mm
+++ b/chrome/browser/cocoa/bookmark_folder_target.mm
@@ -43,10 +43,24 @@ NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType";
// 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([NSApp currentEvent]);
- if (disposition == NEW_BACKGROUND_TAB) {
+ 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;
@@ -79,7 +93,7 @@ NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType";
} else {
const std::string spec = node->GetURL().spec();
NSString* url = base::SysUTF8ToNSString(spec);
- NSString* title = base::SysWideToNSString(node->GetTitle());
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
[pboard declareURLPasteboardWithAdditionalTypes:[NSArray array]
owner:nil];
[pboard setDataForURL:url title:title];
diff --git a/chrome/browser/cocoa/bookmark_folder_target_unittest.mm b/chrome/browser/cocoa/bookmark_folder_target_unittest.mm
index 4fd01ef..22f421f 100644
--- a/chrome/browser/cocoa/bookmark_folder_target_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_folder_target_unittest.mm
@@ -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 "chrome/browser/bookmarks/bookmark_model.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_bar_folder_controller.h"
#import "chrome/browser/cocoa/bookmark_folder_target.h"
diff --git a/chrome/browser/cocoa/bookmark_menu_bridge.h b/chrome/browser/cocoa/bookmark_menu_bridge.h
index 36da750..f39f0a6 100644
--- a/chrome/browser/cocoa/bookmark_menu_bridge.h
+++ b/chrome/browser/cocoa/bookmark_menu_bridge.h
@@ -19,6 +19,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_MENU_BRIDGE_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_MENU_BRIDGE_H_
+#pragma once
#include <map>
#include "base/scoped_nsobject.h"
diff --git a/chrome/browser/cocoa/bookmark_menu_bridge.mm b/chrome/browser/cocoa/bookmark_menu_bridge.mm
index e635548..493e5e8 100644
--- a/chrome/browser/cocoa/bookmark_menu_bridge.mm
+++ b/chrome/browser/cocoa/bookmark_menu_bridge.mm
@@ -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.
@@ -222,8 +222,8 @@ void BookmarkMenuBridge::ConfigureMenuItem(const BookmarkNode* node,
// Add a tooltip
std::string url_string = node->GetURL().possibly_invalid_spec();
NSString* tooltip = [NSString stringWithFormat:@"%@\n%s",
- base::SysWideToNSString(node->GetTitle()),
- url_string.c_str()];
+ base::SysUTF16ToNSString(node->GetTitle()),
+ url_string.c_str()];
[item setToolTip:tooltip];
// Check to see if we have a favicon.
diff --git a/chrome/browser/cocoa/bookmark_menu_bridge_unittest.mm b/chrome/browser/cocoa/bookmark_menu_bridge_unittest.mm
index 47585aa..56590ff 100644
--- a/chrome/browser/cocoa/bookmark_menu_bridge_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_menu_bridge_unittest.mm
@@ -1,15 +1,20 @@
-// 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.
#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_dll_resource.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/cocoa/bookmark_menu_bridge.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
#include "testing/platform_test.h"
class TestBookmarkMenuBridge : public BookmarkMenuBridge {
@@ -84,8 +89,7 @@ TEST_F(BookmarkMenuBridgeTest, TestBookmarkMenuAutoSeparator) {
// 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/";
- std::wstring title(L"Bookmark");
- model->AddURL(parent, 0, title, GURL(url));
+ 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
@@ -113,7 +117,7 @@ TEST_F(BookmarkMenuBridgeTest, TestClearBookmarkMenu) {
// submenus removed, and all separator items are gone.
EXPECT_EQ(2, [menu numberOfItems]);
for (NSMenuItem *item in [menu itemArray]) {
- EXPECT_FALSE([[item title] isEqual:@"not"]);
+ EXPECT_NSNE(@"not", [item title]);
}
}
@@ -137,8 +141,7 @@ TEST_F(BookmarkMenuBridgeTest, TestInvalidation) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const char* url = "http://www.zim-bop-a-dee.com/";
- std::wstring title(L"Bookmark");
- model->AddURL(parent, 0, title, GURL(url));
+ model->AddURL(parent, 0, ASCIIToUTF16("Bookmark"), GURL(url));
EXPECT_FALSE(menu_is_valid());
bridge_->UpdateMenu(bridge_->menu_);
@@ -148,7 +151,7 @@ TEST_F(BookmarkMenuBridgeTest, TestInvalidation) {
// Test that AddNodeToMenu() properly adds bookmark nodes as menus,
// including the recursive case.
TEST_F(BookmarkMenuBridgeTest, TestAddNodeToMenu) {
- std::wstring empty;
+ string16 empty;
NSMenu* menu = bridge_->menu_.get();
BookmarkModel* model = bridge_->GetBookmarkModel();
@@ -164,11 +167,11 @@ TEST_F(BookmarkMenuBridgeTest, TestAddNodeToMenu) {
// 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, ASCIIToWide(short_url), GURL(short_url));
+ 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, ASCIIToWide(long_url), GURL(long_url));
+ 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"));
@@ -203,7 +206,7 @@ TEST_F(BookmarkMenuBridgeTest, TestAddNodeToMenu) {
// Make sure a short title looks fine
NSString* s = [short_item title];
- EXPECT_TRUE([s isEqual:[NSString stringWithUTF8String:short_url]]);
+ EXPECT_NSEQ([NSString stringWithUTF8String:short_url], s);
// Make sure a super-long title gets trimmed
s = [long_item title];
@@ -223,7 +226,7 @@ TEST_F(BookmarkMenuBridgeTest, TestAddNodeToMenu) {
// Makes sure our internal map of BookmarkNode to NSMenuItem works.
TEST_F(BookmarkMenuBridgeTest, TestGetMenuItemForNode) {
- std::wstring empty;
+ string16 empty;
NSMenu* menu = bridge_->menu_.get();
BookmarkModel* model = bridge_->GetBookmarkModel();
@@ -231,11 +234,11 @@ TEST_F(BookmarkMenuBridgeTest, TestGetMenuItemForNode) {
const BookmarkNode* root = model->AddGroup(bookmark_bar, 0, empty);
EXPECT_TRUE(model && root);
- model->AddURL(root, 0, ASCIIToWide("Test Item"), GURL("http://test"));
+ 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, ASCIIToWide("Test 2"), GURL("http://second-test"));
+ 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)));
@@ -255,7 +258,6 @@ TEST_F(BookmarkMenuBridgeTest, TestGetMenuItemForNode) {
// Test that Loaded() adds both the bookmark bar nodes and the "other" nodes.
TEST_F(BookmarkMenuBridgeTest, TestAddNodeToOther) {
- std::wstring empty;
NSMenu* menu = bridge_->menu_.get();
BookmarkModel* model = bridge_->GetBookmarkModel();
@@ -263,7 +265,7 @@ TEST_F(BookmarkMenuBridgeTest, TestAddNodeToOther) {
EXPECT_TRUE(model && root);
const char* short_url = "http://foo/";
- model->AddURL(root, 0, ASCIIToWide(short_url), GURL(short_url));
+ model->AddURL(root, 0, ASCIIToUTF16(short_url), GURL(short_url));
bridge_->UpdateMenu(menu);
ASSERT_GT([menu numberOfItems], 0);
@@ -271,11 +273,10 @@ TEST_F(BookmarkMenuBridgeTest, TestAddNodeToOther) {
EXPECT_TRUE(other);
EXPECT_TRUE([other hasSubmenu]);
ASSERT_GT([[other submenu] numberOfItems], 0);
- EXPECT_TRUE([[[[other submenu] itemAtIndex:0] title] isEqual:@"http://foo/"]);
+ EXPECT_NSEQ(@"http://foo/", [[[other submenu] itemAtIndex:0] title]);
}
TEST_F(BookmarkMenuBridgeTest, TestFavIconLoading) {
- std::wstring empty;
NSMenu* menu = bridge_->menu_;
BookmarkModel* model = bridge_->GetBookmarkModel();
@@ -283,7 +284,7 @@ TEST_F(BookmarkMenuBridgeTest, TestFavIconLoading) {
EXPECT_TRUE(model && root);
const BookmarkNode* node =
- model->AddURL(root, 0, ASCIIToWide("Test Item"),
+ model->AddURL(root, 0, ASCIIToUTF16("Test Item"),
GURL("http://favicon-test"));
bridge_->UpdateMenu(menu);
NSMenuItem* item = [menu itemWithTitle:@"Test Item"];
@@ -300,13 +301,13 @@ TEST_F(BookmarkMenuBridgeTest, TestChangeTitle) {
EXPECT_TRUE(model && root);
const BookmarkNode* node =
- model->AddURL(root, 0, L"Test Item",
+ 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, L"New Title");
+ model->SetTitle(node, ASCIIToUTF16("New Title"));
item = [menu itemWithTitle:@"Test Item"];
EXPECT_FALSE(item);
diff --git a/chrome/browser/cocoa/bookmark_menu_cocoa_controller.h b/chrome/browser/cocoa/bookmark_menu_cocoa_controller.h
index 8beeab5..c78ea7b 100644
--- a/chrome/browser/cocoa/bookmark_menu_cocoa_controller.h
+++ b/chrome/browser/cocoa/bookmark_menu_cocoa_controller.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_MENU_COCOA_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_MENU_COCOA_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_menu_cocoa_controller.mm b/chrome/browser/cocoa/bookmark_menu_cocoa_controller.mm
index ff5306d..898e2f9 100644
--- a/chrome/browser/cocoa/bookmark_menu_cocoa_controller.mm
+++ b/chrome/browser/cocoa/bookmark_menu_cocoa_controller.mm
@@ -6,6 +6,7 @@
#include "app/text_elider.h"
#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h" // IDC_BOOKMARK_MENU
#import "chrome/browser/app_controller_mac.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -28,10 +29,9 @@ const NSUInteger kMaximumMenuPixelsWide = 300;
+ (NSString*)menuTitleForNode:(const BookmarkNode*)node {
NSFont* nsfont = [NSFont menuBarFontOfSize:0]; // 0 means "default"
- gfx::Font font = gfx::Font::CreateFont(base::SysNSStringToWide([nsfont
- fontName]),
- (int)[nsfont pointSize]);
- std::wstring title = gfx::ElideText(node->GetTitle(),
+ gfx::Font font(base::SysNSStringToWide([nsfont fontName]),
+ static_cast<int>([nsfont pointSize]));
+ std::wstring title = gfx::ElideText(UTF16ToWideHack(node->GetTitle()),
font,
kMaximumMenuPixelsWide,
false);
@@ -74,8 +74,9 @@ const NSUInteger kMaximumMenuPixelsWide = 300;
// Open the URL of the given BookmarkNode in the current tab.
- (void)openURLForNode:(const BookmarkNode*)node {
- Browser* browser =
- Browser::GetOrCreateTabbedBrowser(bridge_->GetProfile());
+ 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,
diff --git a/chrome/browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm b/chrome/browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm
index 23ecf3e..f63d7c3 100644
--- a/chrome/browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm
@@ -1,11 +1,12 @@
-// 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.
+#include "base/string16.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h"
+#import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h"
#include "testing/gtest/include/gtest/gtest.h"
@interface FakeBookmarkMenuController : BookmarkMenuCocoaController {
@@ -20,7 +21,7 @@
- (id)init {
if ((self = [super init])) {
- std::wstring empty;
+ string16 empty;
helper_ = new BrowserTestHelper();
BookmarkModel* model = helper_->browser()->profile()->GetBookmarkModel();
const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
diff --git a/chrome/browser/cocoa/bookmark_model_observer_for_cocoa.h b/chrome/browser/cocoa/bookmark_model_observer_for_cocoa.h
index b5ba908..6b20fd1 100644
--- a/chrome/browser/cocoa/bookmark_model_observer_for_cocoa.h
+++ b/chrome/browser/cocoa/bookmark_model_observer_for_cocoa.h
@@ -18,6 +18,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
#define CHROME_BROWSER_COCOA_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_model_observer_for_cocoa_unittest.mm b/chrome/browser/cocoa/bookmark_model_observer_for_cocoa_unittest.mm
index dc80711..1008ef8 100644
--- a/chrome/browser/cocoa/bookmark_model_observer_for_cocoa_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_model_observer_for_cocoa_unittest.mm
@@ -6,6 +6,7 @@
#include "base/scoped_ptr.h"
#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
#import "chrome/browser/cocoa/bookmark_model_observer_for_cocoa.h"
#import "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
@@ -39,7 +40,7 @@ class BookmarkModelObserverForCocoaTest : public CocoaTest {
TEST_F(BookmarkModelObserverForCocoaTest, TestCallback) {
BookmarkModel* model = helper_.profile()->GetBookmarkModel();
const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0, L"super",
+ 0, ASCIIToUTF16("super"),
GURL("http://www.google.com"));
scoped_nsobject<ObserverPingTracker>
@@ -52,7 +53,7 @@ TEST_F(BookmarkModelObserverForCocoaTest, TestCallback) {
EXPECT_EQ(0, pingCount.get()->pings);
- model->SetTitle(node, L"duper");
+ 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);
diff --git a/chrome/browser/cocoa/bookmark_name_folder_controller.h b/chrome/browser/cocoa/bookmark_name_folder_controller.h
index ba4c3f4..1d944a0 100644
--- a/chrome/browser/cocoa/bookmark_name_folder_controller.h
+++ b/chrome/browser/cocoa/bookmark_name_folder_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bookmark_name_folder_controller.mm b/chrome/browser/cocoa/bookmark_name_folder_controller.mm
index 108d87a..a854b8f 100644
--- a/chrome/browser/cocoa/bookmark_name_folder_controller.mm
+++ b/chrome/browser/cocoa/bookmark_name_folder_controller.mm
@@ -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.
@@ -32,7 +32,7 @@
DCHECK_LE(newIndex, parent->GetChildCount());
}
if (node_) {
- initialName_.reset([base::SysWideToNSString(node_->GetTitle()) retain]);
+ initialName_.reset([base::SysUTF16ToNSString(node_->GetTitle()) retain]);
} else {
NSString* newString =
l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
@@ -90,11 +90,11 @@
NSString* name = [nameField_ stringValue];
BookmarkModel* model = profile_->GetBookmarkModel();
if (node_) {
- model->SetTitle(node_, base::SysNSStringToWide(name));
+ model->SetTitle(node_, base::SysNSStringToUTF16(name));
} else {
model->AddGroup(parent_,
newIndex_,
- base::SysNSStringToWide(name));
+ base::SysNSStringToUTF16(name));
}
[NSApp endSheet:[self window]];
}
diff --git a/chrome/browser/cocoa/bookmark_name_folder_controller_unittest.mm b/chrome/browser/cocoa/bookmark_name_folder_controller_unittest.mm
index 5b3e3b5..f78cf22 100644
--- a/chrome/browser/cocoa/bookmark_name_folder_controller_unittest.mm
+++ b/chrome/browser/cocoa/bookmark_name_folder_controller_unittest.mm
@@ -1,14 +1,16 @@
-// 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.
#import <Cocoa/Cocoa.h>
#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
#import "chrome/browser/cocoa/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 {
@@ -44,7 +46,7 @@ TEST_F(BookmarkNameFolderControllerTest, AddNew) {
[controller ok:nil];
EXPECT_EQ(1, parent->GetChildCount());
EXPECT_TRUE(parent->GetChild(0)->is_folder());
- EXPECT_EQ(L"Bozo", parent->GetChild(0)->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("Bozo"), parent->GetChild(0)->GetTitle());
}
// Add new but specify a sibling.
@@ -53,8 +55,10 @@ TEST_F(BookmarkNameFolderControllerTest, AddNewWithSibling) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
// Add 2 nodes. We will place the new folder in the middle of these.
- model->AddURL(parent, 0, L"title 1", GURL("http://www.google.com"));
- model->AddURL(parent, 1, L"title 3", GURL("http://www.google.com"));
+ 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>
@@ -72,7 +76,7 @@ TEST_F(BookmarkNameFolderControllerTest, AddNewWithSibling) {
// 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(L"middle", parent->GetChild(1)->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("middle"), parent->GetChild(1)->GetTitle());
}
// Make sure we are allowed to create a folder named "New Folder".
@@ -122,7 +126,7 @@ TEST_F(BookmarkNameFolderControllerTest, Rename) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
const BookmarkNode* folder = model->AddGroup(parent,
parent->GetChildCount(),
- L"group");
+ ASCIIToUTF16("group"));
// Rename the folder by creating a controller that originates from
// the node.
@@ -133,12 +137,12 @@ TEST_F(BookmarkNameFolderControllerTest, Rename) {
node:folder]);
[controller window]; // force nib load
- EXPECT_TRUE([[controller folderName] isEqual:@"group"]);
+ 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(L"Zobo", parent->GetChild(0)->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("Zobo"), parent->GetChild(0)->GetTitle());
}
TEST_F(BookmarkNameFolderControllerTest, EditAndConfirmOKButton) {
diff --git a/chrome/browser/cocoa/bookmark_tree_browser_cell.h b/chrome/browser/cocoa/bookmark_tree_browser_cell.h
index 595cf2a..d083b5b 100644
--- a/chrome/browser/cocoa/bookmark_tree_browser_cell.h
+++ b/chrome/browser/cocoa/bookmark_tree_browser_cell.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BOOKMARK_TREE_BROWSER_CELL_H_
#define CHROME_BROWSER_COCOA_BOOKMARK_TREE_BROWSER_CELL_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/browser_accessibility.h b/chrome/browser/cocoa/browser_accessibility.h
index f891327..32af50e 100644
--- a/chrome/browser/cocoa/browser_accessibility.h
+++ b/chrome/browser/cocoa/browser_accessibility.h
@@ -4,19 +4,20 @@
#ifndef CHROME_BROWSER_COCOA_BROWSER_ACCESSIBILITY_H
#define CHROME_BROWSER_COCOA_BROWSER_ACCESSIBILITY_H
+#pragma once
#import <Cocoa/Cocoa.h>
#import "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_accessibility_delegate.h"
+#import "chrome/browser/cocoa/browser_accessibility_delegate.h"
#include "webkit/glue/webaccessibility.h"
using webkit_glue::WebAccessibility;
// BrowserAccessibility is a cocoa wrapper around the WebAccessibility
// object. The renderer converts webkit's accessibility tree into a
-// WebAccessibility tree and passes it to us over IPC. This class
-// converts it into a format Cocoa can query.
+// WebAccessibility tree and passes it to the browser process over IPC.
+// This class converts it into a format Cocoa can query.
@interface BrowserAccessibility : NSObject {
@private
WebAccessibility webAccessibility_;
@@ -24,17 +25,31 @@ using webkit_glue::WebAccessibility;
scoped_nsobject<NSMutableArray> children_;
// The parent of the accessibility object. This can be another
// BrowserAccessibility or a RenderWidgetHostViewCocoa.
- id parent_;
+ id parent_; // weak
}
-- (id)initWithObject:(const WebAccessibility)accessibility
+// This creates a cocoa browser accessibility object around
+// the webkit glue WebAccessibility object. The delegate is
+// used to communicate with the host renderer. None of these
+// parameters can be null.
+- (id)initWithObject:(const WebAccessibility&)accessibility
delegate:(id<BrowserAccessibilityDelegate>)delegate
parent:(id)parent;
+// Children is an array of BrowserAccessibility objects, representing
+// the accessibility children of this object.
@property(nonatomic, readonly) NSArray* children;
+// isIgnored returns whether or not the accessibility object
+// should be ignored by the accessibility hierarchy.
@property(nonatomic, readonly, getter=isIgnored) BOOL ignored;
+// The origin of this object in the page's document.
+// This is relative to webkit's top-left origin, not Cocoa's
+// bottom-left origin.
@property(nonatomic, readonly) NSPoint origin;
+// A string indicating the role of this object as far as accessibility
+// is concerned.
@property(nonatomic, readonly) NSString* role;
+// The size of this object.
@property(nonatomic, readonly) NSSize size;
@end
diff --git a/chrome/browser/cocoa/browser_accessibility.mm b/chrome/browser/cocoa/browser_accessibility.mm
index 6dbf3ce..06b9cfb 100644
--- a/chrome/browser/cocoa/browser_accessibility.mm
+++ b/chrome/browser/cocoa/browser_accessibility.mm
@@ -4,10 +4,13 @@
#include <execinfo.h>
+#import "chrome/browser/cocoa/browser_accessibility.h"
+
+#include "app/l10n_util_mac.h"
#include "base/string16.h"
#include "base/sys_string_conversions.h"
-#include "chrome/browser/cocoa/browser_accessibility.h"
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#include "grit/webkit_strings.h"
#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
using webkit_glue::WebAccessibility;
@@ -16,9 +19,9 @@ namespace {
// Returns an autoreleased copy of the WebAccessibility's attribute.
NSString* NSStringForWebAccessibilityAttribute(
- std::map<int32, string16>& attributes,
+ const std::map<int32, string16>& attributes,
WebAccessibility::Attribute attribute) {
- std::map<int32, string16>::iterator iter =
+ std::map<int32, string16>::const_iterator iter =
attributes.find(attribute);
NSString* returnValue = @"";
if (iter != attributes.end()) {
@@ -54,15 +57,17 @@ static const RoleEntry roles[] = {
{ WebAccessibility::ROLE_WEBCORE_LINK, NSAccessibilityLinkRole},
};
+// GetState checks the bitmask used in webaccessibility.h to check
+// if the given state was set on the accessibility object.
bool GetState(WebAccessibility accessibility, int state) {
return ((accessibility.state >> state) & 1);
}
-} // anonymous namespace
+} // namespace
@implementation BrowserAccessibility
-- (id)initWithObject:(const WebAccessibility)accessibility
+- (id)initWithObject:(const WebAccessibility&)accessibility
delegate:(id<BrowserAccessibilityDelegate>)delegate
parent:(id)parent {
if ((self = [super init])) {
@@ -73,6 +78,8 @@ bool GetState(WebAccessibility accessibility, int state) {
return self;
}
+// Returns an array of BrowserAccessibility objects, representing the
+// accessibility children of this object.
- (NSArray*)children {
if (!children_.get()) {
const std::vector<WebAccessibility>& accessibilityChildren =
@@ -83,28 +90,33 @@ bool GetState(WebAccessibility accessibility, int state) {
std::vector<WebAccessibility>::const_iterator iterator;
for (iterator = accessibilityChildren.begin();
iterator != accessibilityChildren.end();
- iterator++) {
- BrowserAccessibility* child =
+ ++iterator) {
+ scoped_nsobject<BrowserAccessibility> child(
[[BrowserAccessibility alloc]
initWithObject:*iterator
delegate:delegate_
- parent:self];
- [child autorelease];
+ parent:self]);
[children_ addObject:child];
}
}
return children_;
}
+// Returns whether or not this node should be ignored in the
+// accessibility tree.
- (BOOL)isIgnored {
return webAccessibility_.role == WebAccessibility::ROLE_IGNORED;
}
+// The origin of this accessibility object in the page's document.
+// This is relative to webkit's top-left origin, not Cocoa's
+// bottom-left origin.
- (NSPoint)origin {
return NSMakePoint(webAccessibility_.location.x,
webAccessibility_.location.y);
}
+// Returns a string indicating the role of this object.
- (NSString*)role {
NSString* role = NSAccessibilityUnknownRole;
WebAccessibility::Role value = webAccessibility_.role;
@@ -118,46 +130,74 @@ bool GetState(WebAccessibility accessibility, int state) {
return role;
}
+// Returns a string indicating the role description of this object.
+- (NSString*)roleDescription {
+ // The following descriptions are specific to webkit.
+ if ([[self role] isEqualToString:@"AXWebArea"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_WEB_AREA);
+
+ if ([[self role] isEqualToString:@"NSAccessibilityLinkRole"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_LINK);
+
+ if ([[self role] isEqualToString:@"AXHeading"])
+ return l10n_util::GetNSString(IDS_AX_ROLE_HEADING);
+
+ return NSAccessibilityRoleDescription([self role], nil);
+}
+
+// Returns the size of this object.
- (NSSize)size {
return NSMakeSize(webAccessibility_.location.width,
webAccessibility_.location.height);
}
-- (id)accessibilityAttributeValue:(NSString *)attribute {
+// Returns the accessibility value for the given attribute. If the value isn't
+// supported this will return nil.
+- (id)accessibilityAttributeValue:(NSString*)attribute {
if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
return [self role];
- } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
return NSStringForWebAccessibilityAttribute(webAccessibility_.attributes,
WebAccessibility::ATTR_DESCRIPTION);
- } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
return [NSValue valueWithPoint:[delegate_ accessibilityPointInScreen:self]];
- } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
return [NSValue valueWithSize:[self size]];
- } else if (
- [attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute] ||
+ }
+ if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute] ||
[attribute isEqualToString:NSAccessibilityWindowAttribute]) {
return [delegate_ window];
- } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
return [self children];
- } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
if (parent_) {
return NSAccessibilityUnignoredAncestor(parent_);
}
- } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
return base::SysUTF16ToNSString(webAccessibility_.name);
- } else if ([attribute isEqualToString:NSAccessibilityHelpAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityHelpAttribute]) {
return NSStringForWebAccessibilityAttribute(webAccessibility_.attributes,
WebAccessibility::ATTR_HELP);
- } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
return base::SysUTF16ToNSString(webAccessibility_.value);
- } else if (
- [attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
- return NSAccessibilityRoleDescription([self role], nil);
- } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
+ }
+ if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
+ return [self roleDescription];
+ }
+ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
NSNumber* ret = [NSNumber numberWithBool:
GetState(webAccessibility_, WebAccessibility::STATE_FOCUSED)];
return ret;
- } else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute] ||
+ }
+ if ([attribute isEqualToString:NSAccessibilityEnabledAttribute] ||
[attribute isEqualToString:@"AXVisited"] ||
[attribute isEqualToString:@"AXLoaded"]) {
return [NSNumber numberWithBool:YES];
@@ -165,14 +205,21 @@ bool GetState(WebAccessibility accessibility, int state) {
return nil;
}
-- (NSArray *)accessibilityActionNames {
+// Returns an array of action names that this object will respond to.
+- (NSArray*)accessibilityActionNames {
return [NSArray arrayWithObjects:
NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
}
-- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute
- index:(NSUInteger)index
- maxCount:(NSUInteger)maxCount {
+// Returns a sub-array of values for the given attribute value, starting at
+// index, with up to maxCount items. If the given index is out of bounds,
+// or there are no values for the given attribute, it will return nil.
+// This method is used for querying subsets of values, without having to
+// return a large set of data, such as elements with a large number of
+// children.
+- (NSArray*)accessibilityArrayAttributeValues:(NSString*)attribute
+ index:(NSUInteger)index
+ maxCount:(NSUInteger)maxCount {
NSArray* fullArray = [self accessibilityAttributeValue:attribute];
if (!fullArray)
return nil;
@@ -188,34 +235,39 @@ bool GetState(WebAccessibility accessibility, int state) {
return [fullArray subarrayWithRange:subRange];
}
-- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute {
+// Returns the count of the specified accessibility array attribute.
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute {
NSArray* fullArray = [self accessibilityAttributeValue:attribute];
return [fullArray count];
}
-- (NSArray *)accessibilityAttributeNames {
+// Returns the list of accessibility attributes that this object supports.
+- (NSArray*)accessibilityAttributeNames {
return [NSArray arrayWithObjects:
- NSAccessibilityRoleAttribute,
- NSAccessibilityRoleDescriptionAttribute,
NSAccessibilityChildrenAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilityFocusedAttribute,
NSAccessibilityHelpAttribute,
NSAccessibilityParentAttribute,
NSAccessibilityPositionAttribute,
+ NSAccessibilityRoleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
NSAccessibilitySizeAttribute,
NSAccessibilityTitleAttribute,
- NSAccessibilityDescriptionAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
NSAccessibilityValueAttribute,
- NSAccessibilityFocusedAttribute,
- NSAccessibilityEnabledAttribute,
NSAccessibilityWindowAttribute,
- NSAccessibilityTopLevelUIElementAttribute,
nil];
}
+// Returns the deepest child that has user focus.
+// TODO(feldstein): This does not work yet.
- (id)accessibilityFocusedUIElement {
return self;
}
+// Returns the index of the child in this objects array of children.
- (NSUInteger)accessibilityIndexOfChild:(id)child {
NSUInteger index = 0;
for (BrowserAccessibility* childToCheck in [self children]) {
@@ -227,34 +279,43 @@ bool GetState(WebAccessibility accessibility, int state) {
return NSNotFound;
}
-- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
- if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
+// Returns whether or not the specified attribute can be set by the
+// accessibility API via |accessibilitySetValue:forAttribute:|.
+- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
+ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
return GetState(webAccessibility_, WebAccessibility::STATE_FOCUSABLE);
- } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ if ([attribute isEqualToString:NSAccessibilityValueAttribute])
return !GetState(webAccessibility_, WebAccessibility::STATE_READONLY);
- }
return NO;
}
+// Returns whether or not this object should be ignored in the accessibilty
+// tree.
- (BOOL)accessibilityIsIgnored {
return [self isIgnored];
}
-- (void)accessibilityPerformAction:(NSString *)action {
+// Performs the given accessibilty action on the webkit accessibility object
+// that backs this object.
+- (void)accessibilityPerformAction:(NSString*)action {
// TODO(feldstein): Support more actions.
[delegate_ doDefaultAction:webAccessibility_.id];
}
+// Returns the description of the given action.
- (NSString*)accessibilityActionDescription:(NSString*)action {
return NSAccessibilityActionDescription(action);
}
+// Sets an override value for a specific accessibility attribute.
+// This class does not support this.
- (BOOL)accessibilitySetOverrideValue:(id)value
- forAttribute:(NSString *)attribute {
+ forAttribute:(NSString*)attribute {
return NO;
}
-- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
+// Sets the value for an accessibility attribute via the accessibility API.
+- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
NSNumber* focusedNumber = value;
BOOL focused = [focusedNumber intValue];
@@ -263,6 +324,9 @@ bool GetState(WebAccessibility accessibility, int state) {
}
}
+// Returns the deepest accessibility child that should not be ignored.
+// It is assumed that the hit test has been narrowed down to this object
+// or one of its children, so this will never return nil.
- (id)accessibilityHitTest:(NSPoint)point {
id hit = self;
for (id child in [self children]) {
diff --git a/chrome/browser/cocoa/browser_accessibility_delegate.h b/chrome/browser/cocoa/browser_accessibility_delegate.h
index 988df26..800174d 100644
--- a/chrome/browser/cocoa/browser_accessibility_delegate.h
+++ b/chrome/browser/cocoa/browser_accessibility_delegate.h
@@ -4,10 +4,14 @@
#ifndef CHROME_BROWSER_COCOA_BROWSER_ACCESSIBILITY_DELEGATE_H
#define CHROME_BROWSER_COCOA_BROWSER_ACCESSIBILITY_DELEGATE_H
+#pragma once
@class BrowserAccessibility;
@class NSWindow;
+// This protocol is used by the BrowserAccessibility objects to pass messages
+// to, or otherwise communicate with, their underlying WebAccessibility
+// objects over the IPC boundary.
@protocol BrowserAccessibilityDelegate
- (NSPoint)accessibilityPointInScreen:(BrowserAccessibility*)accessibility;
- (void)doDefaultAction:(int32)accessibilityObjectId;
diff --git a/chrome/browser/cocoa/browser_accessibility_unittest.mm b/chrome/browser/cocoa/browser_accessibility_unittest.mm
index 2fa93e0..104c26e 100644
--- a/chrome/browser/cocoa/browser_accessibility_unittest.mm
+++ b/chrome/browser/cocoa/browser_accessibility_unittest.mm
@@ -5,9 +5,11 @@
#import <Cocoa/Cocoa.h>
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/cocoa/browser_accessibility.h"
#include "chrome/browser/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
@interface MockAccessibilityDelegate : NSObject<BrowserAccessibilityDelegate>
@@ -53,38 +55,63 @@ class BrowserAccessibilityTest : public CocoaTest {
child1.location.y = 0;
child1.location.width = 250;
child1.location.height = 100;
-
+
WebAccessibility child2;
child2.location.x = 250;
child2.location.y = 0;
child2.location.width = 250;
child2.location.height = 100;
-
+
root.children.push_back(child1);
- root.children.push_back(child2);
-
+ root.children.push_back(child2);
+
delegate_.reset([[MockAccessibilityDelegate alloc] init]);
accessibility_.reset(
[[BrowserAccessibility alloc] initWithObject:root
delegate:delegate_
parent:delegate_]);
}
-
+
protected:
scoped_nsobject<MockAccessibilityDelegate> delegate_;
scoped_nsobject<BrowserAccessibility> accessibility_;
};
+// Standard hit test.
TEST_F(BrowserAccessibilityTest, HitTestTest) {
BrowserAccessibility* firstChild =
[accessibility_ accessibilityHitTest:NSMakePoint(50, 50)];
- EXPECT_TRUE(
- [[firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]
- isEqualToString:@"Child1"]);
+ EXPECT_NSEQ(@"Child1",
+ [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
}
+// Test doing a hit test on the edge of a child.
+TEST_F(BrowserAccessibilityTest, EdgeHitTest) {
+ BrowserAccessibility* firstChild =
+ [accessibility_ accessibilityHitTest:NSMakePoint(0, 0)];
+ EXPECT_NSEQ(@"Child1",
+ [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
+}
+
+// This will test a hit test with invalid coordinates. It is assumed that
+// the hit test has been narrowed down to this object or one of its children
+// so it should return itself since it has no better hit result.
+TEST_F(BrowserAccessibilityTest, InvalidHitTestCoordsTest) {
+ BrowserAccessibility* hitTestResult =
+ [accessibility_ accessibilityHitTest:NSMakePoint(-50, 50)];
+ EXPECT_NSEQ(accessibility_, hitTestResult);
+}
+
+// Test to ensure querying standard attributes works.
TEST_F(BrowserAccessibilityTest, BasicAttributeTest) {
NSString* helpText = [accessibility_
accessibilityAttributeValue:NSAccessibilityHelpAttribute];
- EXPECT_TRUE([helpText isEqualToString: @"HelpText"]);
+ EXPECT_NSEQ(@"HelpText", helpText);
+}
+
+// Test querying for an invalid attribute to ensure it doesn't crash.
+TEST_F(BrowserAccessibilityTest, InvalidAttributeTest) {
+ NSString* shouldBeNil = [accessibility_
+ accessibilityAttributeValue:@"NSAnInvalidAttribute"];
+ EXPECT_TRUE(shouldBeNil == nil);
}
diff --git a/chrome/browser/cocoa/browser_command_executor.h b/chrome/browser/cocoa/browser_command_executor.h
index 4a76ff1..e6e01cf 100644
--- a/chrome/browser/cocoa/browser_command_executor.h
+++ b/chrome/browser/cocoa/browser_command_executor.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_BROWSER_COMMAND_EXECUTOR_H_
#define CHROME_BROWSER_BROWSER_COMMAND_EXECUTOR_H_
+#pragma once
// Defines a protocol for any object that can execute commands in the
// context of some underlying browser object.
diff --git a/chrome/browser/cocoa/browser_frame_view.mm b/chrome/browser/cocoa/browser_frame_view.mm
index dfc8003..96e3542 100644
--- a/chrome/browser/cocoa/browser_frame_view.mm
+++ b/chrome/browser/cocoa/browser_frame_view.mm
@@ -9,9 +9,9 @@
#include "base/logging.h"
#include "base/scoped_nsautorelease_pool.h"
-#import "chrome/browser/browser_theme_provider.h"
-#import "chrome/browser/cocoa/chrome_browser_window.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;
@@ -24,6 +24,7 @@ static BOOL gCanGetCornerRadius = NO;
- (void)drawRectOriginal:(NSRect)rect;
- (BOOL)_mouseInGroup:(NSButton*)widget;
- (void)updateTrackingAreas;
+- (NSUInteger)_shadowFlagsOriginal;
@end
// Undocumented APIs. They are really on NSGrayFrame rather than
@@ -33,6 +34,7 @@ static BOOL gCanGetCornerRadius = NO;
- (float)roundedCornerRadius;
- (CGRect)_titlebarTitleRect;
- (void)_drawTitleStringIn:(struct CGRect)arg1 withColor:(id)color;
+- (NSUInteger)_shadowFlags;
@end
@@ -49,7 +51,7 @@ static BOOL gCanGetCornerRadius = NO;
DCHECK(grayFrameClass);
if (!grayFrameClass) return;
- // Exchange draw rect
+ // Exchange draw rect.
Method m0 = class_getInstanceMethod([self class], @selector(drawRect:));
DCHECK(m0);
if (m0) {
@@ -69,7 +71,7 @@ static BOOL gCanGetCornerRadius = NO;
}
}
- // Add _mouseInGroup
+ // Add _mouseInGroup.
m0 = class_getInstanceMethod([self class], @selector(_mouseInGroup:));
DCHECK(m0);
if (m0) {
@@ -79,7 +81,7 @@ static BOOL gCanGetCornerRadius = NO;
method_getTypeEncoding(m0));
DCHECK(didAdd);
}
- // Add updateTrackingArea
+ // Add updateTrackingArea.
m0 = class_getInstanceMethod([self class], @selector(updateTrackingAreas));
DCHECK(m0);
if (m0) {
@@ -98,6 +100,31 @@ static BOOL gCanGetCornerRadius = NO;
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 {
@@ -116,7 +143,7 @@ static BOOL gCanGetCornerRadius = NO;
- (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:[ChromeBrowserWindow class]]) {
+ if (![[self window] isKindOfClass:[FramedBrowserWindow class]]) {
[self drawRectOriginal:rect];
return;
}
@@ -327,9 +354,9 @@ static BOOL gCanGetCornerRadius = NO;
// 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:[ChromeBrowserWindow class]]) {
- ChromeBrowserWindow* window =
- static_cast<ChromeBrowserWindow*>([self window]);
+ 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];
@@ -340,11 +367,33 @@ static BOOL gCanGetCornerRadius = NO;
// Let our window handle updating the window widget tracking area.
- (void)updateTrackingAreas {
[super updateTrackingAreas];
- if ([[self window] isKindOfClass:[ChromeBrowserWindow class]]) {
- ChromeBrowserWindow* window =
- static_cast<ChromeBrowserWindow*>([self window]);
+ 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_test_helper.h b/chrome/browser/cocoa/browser_test_helper.h
index a264317..4ff40ba 100644
--- a/chrome/browser/cocoa/browser_test_helper.h
+++ b/chrome/browser/cocoa/browser_test_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BROWSER_TEST_HELPER_H_
#define CHROME_BROWSER_COCOA_BROWSER_TEST_HELPER_H_
+#pragma once
#include "chrome/browser/browser.h"
#include "chrome/browser/chrome_thread.h"
@@ -28,8 +29,8 @@ class BrowserTestHelper {
public:
BrowserTestHelper()
: ui_thread_(ChromeThread::UI, &message_loop_),
- file_thread_(ChromeThread::FILE, &message_loop_),
- io_thread_(ChromeThread::IO, &message_loop_) {
+ file_thread_(new ChromeThread(ChromeThread::FILE, &message_loop_)),
+ io_thread_(new ChromeThread(ChromeThread::IO, &message_loop_)) {
profile_.reset(new TestingProfile());
profile_->CreateBookmarkModel(true);
profile_->BlockUntilBookmarkModelLoaded();
@@ -49,6 +50,11 @@ class 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();
}
@@ -79,8 +85,8 @@ class BrowserTestHelper {
scoped_ptr<Browser> browser_;
MessageLoopForUI message_loop_;
ChromeThread ui_thread_;
- ChromeThread file_thread_;
- ChromeThread io_thread_;
+ scoped_ptr<ChromeThread> file_thread_;
+ scoped_ptr<ChromeThread> 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
index e363a6e..2fe7b8f 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/cocoa/browser_window_cocoa.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_
#define CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_
+#pragma once
#include "base/task.h"
#include "chrome/browser/browser_window.h"
@@ -34,13 +35,13 @@ class BrowserWindowCocoa : public BrowserWindow,
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 SelectedTabExtensionShelfSizeChanged();
virtual void UpdateTitleBar();
virtual void ShelfVisibilityChanged();
virtual void UpdateDevTools();
@@ -68,7 +69,6 @@ class BrowserWindowCocoa : public BrowserWindow,
virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
Profile* profile);
virtual void ToggleBookmarkBar();
- virtual void ToggleExtensionShelf();
virtual views::Window* ShowAboutChromeDialog();
virtual void ShowUpdateChromeDialog();
virtual void ShowTaskManager();
@@ -105,6 +105,10 @@ class BrowserWindowCocoa : public BrowserWindow,
virtual void Copy();
virtual void Paste();
virtual void ToggleTabStripMode();
+ virtual void OpenTabpose();
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
+ virtual gfx::Rect GetMatchPreviewBounds();
// Overridden from NotificationObserver
virtual void Observe(NotificationType type,
@@ -124,6 +128,7 @@ class BrowserWindowCocoa : public BrowserWindow,
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
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm
index 8b16348..168300e 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/cocoa/browser_window_cocoa.mm
@@ -5,7 +5,7 @@
#include "chrome/browser/cocoa/browser_window_cocoa.h"
#include "app/l10n_util_mac.h"
-#include "base/keyboard_codes.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/sys_string_conversions.h"
@@ -15,7 +15,7 @@
#include "chrome/browser/browser_list.h"
#import "chrome/browser/cocoa/browser_window_controller.h"
#import "chrome/browser/cocoa/bug_report_window_controller.h"
-#import "chrome/browser/cocoa/chrome_browser_window.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"
@@ -35,9 +35,13 @@
#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/pref_service.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/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"
@@ -53,6 +57,8 @@ BrowserWindowCocoa::BrowserWindowCocoa(Browser* 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() {
@@ -108,6 +114,11 @@ void BrowserWindowCocoa::Activate() {
[controller_ activate];
}
+void BrowserWindowCocoa::Deactivate() {
+ // TODO(jcivelli): http://crbug.com/51364 Implement me.
+ NOTIMPLEMENTED();
+}
+
void BrowserWindowCocoa::FlashFrame() {
[NSApp requestUserAttention:NSInformationalRequest];
}
@@ -136,10 +147,6 @@ void BrowserWindowCocoa::SelectedTabToolbarSizeChanged(bool is_animating) {
// sort on Mac.
}
-void BrowserWindowCocoa::SelectedTabExtensionShelfSizeChanged() {
- NOTIMPLEMENTED();
-}
-
void BrowserWindowCocoa::UpdateTitleBar() {
NSString* newTitle =
base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());
@@ -271,10 +278,6 @@ void BrowserWindowCocoa::ToggleBookmarkBar() {
bookmark_utils::ToggleWhenVisible(browser_->profile());
}
-void BrowserWindowCocoa::ToggleExtensionShelf() {
- NOTIMPLEMENTED();
-}
-
void BrowserWindowCocoa::AddFindBar(
FindBarCocoaController* find_bar_cocoa_controller) {
return [controller_ addFindBar:find_bar_cocoa_controller];
@@ -398,7 +401,11 @@ void BrowserWindowCocoa::ShowPageInfo(Profile* profile,
const GURL& url,
const NavigationEntry::SSLStatus& ssl,
bool show_history) {
- PageInfoWindowMac::ShowPageInfo(profile, url, ssl, show_history);
+ const CommandLine* command_line(CommandLine::ForCurrentProcess());
+ if (command_line->HasSwitch(switches::kEnableNewPageInfoBubble))
+ browser::ShowPageInfoBubble(window(), profile, url, ssl, show_history);
+ else
+ browser::ShowPageInfo(window(), profile, url, ssl, show_history);
}
void BrowserWindowCocoa::ShowAppMenu() {
@@ -553,6 +560,26 @@ void BrowserWindowCocoa::ToggleTabStripMode() {
[controller_ toggleTabStripDisplayMode];
}
+void BrowserWindowCocoa::OpenTabpose() {
+ [controller_ openTabpose];
+}
+
+void BrowserWindowCocoa::ShowMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowCocoa::HideMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
+gfx::Rect BrowserWindowCocoa::GetMatchPreviewBounds() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
void BrowserWindowCocoa::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -562,6 +589,10 @@ void BrowserWindowCocoa::Observe(NotificationType type,
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;
@@ -578,3 +609,9 @@ void BrowserWindowCocoa::DestroyBrowser() {
NSWindow* BrowserWindowCocoa::window() const {
return [controller_ window];
}
+
+void BrowserWindowCocoa::UpdateSidebarForContents(TabContents* tab_contents) {
+ if (tab_contents == browser_->tabstrip_model()->GetSelectedTabContents()) {
+ [controller_ updateSidebarForContents:tab_contents];
+ }
+}
diff --git a/chrome/browser/cocoa/browser_window_controller.h b/chrome/browser/cocoa/browser_window_controller.h
index ab44977..f0b3363 100644
--- a/chrome/browser/cocoa/browser_window_controller.h
+++ b/chrome/browser/cocoa/browser_window_controller.h
@@ -4,6 +4,7 @@
#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
@@ -17,6 +18,7 @@
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_bubble_controller.h"
#import "chrome/browser/cocoa/browser_command_executor.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"
@@ -27,8 +29,8 @@
class Browser;
class BrowserWindow;
class BrowserWindowCocoa;
-@class ChromeBrowserWindow;
class ConstrainedWindowMac;
+@class DevToolsController;
@class DownloadShelfController;
@class FindBarCocoaController;
@class FullscreenController;
@@ -36,10 +38,10 @@ class ConstrainedWindowMac;
@class IncognitoImageView;
@class InfoBarContainerController;
class LocationBarViewMac;
+@class SidebarController;
class StatusBubbleMac;
class TabContents;
@class TabStripController;
-class TabStripModelObserverBridge;
@class TabStripView;
@class ToolbarController;
@@ -48,7 +50,8 @@ class TabStripModelObserverBridge;
TabWindowController<NSUserInterfaceValidations,
BookmarkBarControllerDelegate,
BrowserCommandExecutor,
- ViewResizer> {
+ ViewResizer,
+ 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
@@ -56,7 +59,6 @@ class TabStripModelObserverBridge;
// (tab/toolbar/bookmark models, profiles, etc).
scoped_ptr<Browser> browser_;
NSWindow* savedRegularWindow_;
- scoped_ptr<TabStripModelObserverBridge> tabObserver_;
scoped_ptr<BrowserWindowCocoa> windowShim_;
scoped_nsobject<ToolbarController> toolbarController_;
scoped_nsobject<TabStripController> tabStripController_;
@@ -64,6 +66,8 @@ class TabStripModelObserverBridge;
scoped_nsobject<InfoBarContainerController> infoBarContainerController_;
scoped_nsobject<DownloadShelfController> downloadShelfController_;
scoped_nsobject<BookmarkBarController> bookmarkBarController_;
+ scoped_nsobject<DevToolsController> devToolsController_;
+ scoped_nsobject<SidebarController> sidebarController_;
scoped_nsobject<FullscreenController> fullscreenController_;
// Strong. StatusBubble is a special case of a strong reference that
@@ -75,7 +79,6 @@ class TabStripModelObserverBridge;
BookmarkBubbleController* bookmarkBubbleController_; // Weak.
BOOL initializing_; // YES while we are currently in initWithBrowser:
BOOL ownsBrowser_; // Only ever NO when testing
- CGFloat verticalOffsetForStatusBubble_;
// 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
@@ -215,8 +218,8 @@ class TabStripModelObserverBridge;
// "chrome/app/chrome_dll_resource.h" file.
- (void)executeCommand:(int)command;
-// Delegate method for the status bubble to query about its vertical offset.
-- (CGFloat)verticalOffsetForStatusBubble;
+// 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
@@ -235,6 +238,10 @@ class TabStripModelObserverBridge;
// 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;
@@ -336,6 +343,9 @@ class TabStripModelObserverBridge;
// 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)
@@ -366,6 +376,10 @@ class TabStripModelObserverBridge;
// 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)
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index 61741e9..d33c0ca 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -6,6 +6,7 @@
#include <Carbon/Carbon.h>
+#include "app/l10n_util.h"
#include "app/l10n_util_mac.h"
#include "base/mac_util.h"
#include "base/nsimage_cache_mac.h"
@@ -13,48 +14,50 @@
#import "base/scoped_nsobject.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h" // IDC_*
+#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_theme_provider.h"
-#include "chrome/browser/dock_info.h"
-#include "chrome/browser/encoding_menu_controller.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/window_sizer.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
#import "chrome/browser/cocoa/background_gradient_view.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/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_shelf_controller.h"
#import "chrome/browser/cocoa/event_utils.h"
#import "chrome/browser/cocoa/fast_resize_view.h"
-#import "chrome/browser/cocoa/find_bar_cocoa_controller.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/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_model_observer_bridge.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/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/tabs/tab_strip_model.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/window_sizer.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
@@ -189,8 +192,6 @@
initializing_ = YES;
browser_.reset(browser);
ownsBrowser_ = ownIt;
- tabObserver_.reset(
- new TabStripModelObserverBridge(browser->tabstrip_model(), self));
NSWindow* window = [self window];
windowShim_.reset(new BrowserWindowCocoa(browser, self, window));
@@ -210,7 +211,8 @@
// offscreen, but there will always be enough window onscreen to
// drag the whole window back into view.
NSSize minSize = [[self window] minSize];
- gfx::Rect windowRect = browser_->GetSavedWindowBounds();
+ gfx::Rect desiredContentRect = browser_->GetSavedWindowBounds();
+ gfx::Rect windowRect = desiredContentRect;
if (windowRect.width() < minSize.width)
windowRect.set_width(minSize.width);
if (windowRect.height() < minSize.height)
@@ -224,11 +226,28 @@
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] init]);
+ [[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 tabstrip controller is
+ // instantiated.
+ sidebarController_.reset([[SidebarController alloc] init]);
+ [[sidebarController_ view] setFrame:[[devToolsController_ view] bounds]];
+ [[devToolsController_ view] addSubview:[sidebarController_ 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
@@ -238,9 +257,7 @@
// Create the infobar container view, so we can pass it to the
// ToolbarController.
infoBarContainerController_.reset(
- [[InfoBarContainerController alloc]
- initWithTabStripModel:(browser_->tabstrip_model())
- resizeDelegate:self]);
+ [[InfoBarContainerController alloc] initWithResizeDelegate:self]);
[[[self window] contentView] addSubview:[infoBarContainerController_ view]];
// Create a controller for the toolbar, giving it the toolbar model object
@@ -285,6 +302,27 @@
// 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);
@@ -394,7 +432,11 @@
}
- (void)updateDevToolsForContents:(TabContents*)contents {
- [tabStripController_ updateDevToolsForContents:contents];
+ [devToolsController_ updateDevToolsForTabContents:contents];
+}
+
+- (void)updateSidebarForContents:(TabContents*)contents {
+ [sidebarController_ updateSidebarForTabContents:contents];
}
// Called when the user wants to close a window or from the shutdown process.
@@ -933,11 +975,11 @@
DCHECK([targetController isKindOfClass:[BrowserWindowController class]]);
NSInteger command = [sender tag];
NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags];
- if ((command == IDC_RELOAD) && (modifierFlags & NSShiftKeyMask)) {
+ if ((command == IDC_RELOAD) &&
+ (modifierFlags & (NSShiftKeyMask | NSControlKeyMask))) {
command = IDC_RELOAD_IGNORING_CACHE;
- // Mask off shift so it isn't interpreted as affecting the disposition
- // below.
- modifierFlags &= ~NSShiftKeyMask;
+ // 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
@@ -971,11 +1013,14 @@
browser_->ExecuteCommand(command);
}
-// StatusBubble delegate method: tell the status bubble how far above the bottom
-// of the window it should position itself.
-- (CGFloat)verticalOffsetForStatusBubble {
- return verticalOffsetForStatusBubble_ +
- [[tabStripController_ activeTabContentsController] devToolsHeight];
+// StatusBubble delegate method: tell the status bubble the frame it should
+// position itself in.
+- (NSRect)statusBubbleBaseFrame {
+ NSView* baseView = [sidebarController_ view];
+ NSArray* contentsSubviews = [baseView subviews];
+ if ([contentsSubviews count] > 0)
+ baseView = [contentsSubviews objectAtIndex:0];
+ return [[baseView superview] convertRect:[baseView frame] toView:nil];
}
- (GTMWindowSheetController*)sheetController {
@@ -1141,7 +1186,15 @@
gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y,
windowRect.size.width, windowRect.size.height);
- NSRect tabRect = [tabView frame];
+ 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);
@@ -1155,10 +1208,8 @@
// Create the new window with a single tab in its model, the one being
// dragged.
DockInfo dockInfo;
- Browser* newBrowser =
- browser_->tabstrip_model()->TearOffTabContents(contents,
- browserRect,
- 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).
@@ -1293,41 +1344,44 @@
return [self supportsWindowFeature:Browser::FEATURE_TABSTRIP];
}
-- (void)selectTabWithContents:(TabContents*)newContents
- previousContents:(TabContents*)oldContents
- atIndex:(NSInteger)index
- userGesture:(bool)wasUserGesture {
- DCHECK(oldContents != newContents);
-
+// TabStripControllerDelegate protocol.
+- (void)onSelectTabWithContents:(TabContents*)contents {
// Update various elements that are interested in knowing the current
// TabContents.
// Update all the UI bits.
windowShim_->UpdateTitleBar();
+ [self updateSidebarForContents:contents];
+ [self updateDevToolsForContents: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];
}
-- (void)tabChangedWithContents:(TabContents*)contents
- atIndex:(NSInteger)index
- changeType:(TabStripModelObserver::TabChangeType)change {
- if (index == browser_->tabstrip_model()->selected_index()) {
- // 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)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 {
@@ -1473,6 +1527,7 @@
// 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
@@ -1622,6 +1677,27 @@ willAnimateFromState:(bookmarks::VisualState)oldState
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 {
@@ -1716,6 +1792,11 @@ willAnimateFromState:(bookmarks::VisualState)oldState
DCHECK(savedRegularWindow_);
destWindow = [savedRegularWindow_ autorelease];
savedRegularWindow_ = nil;
+
+ CGSWorkspaceID workspace;
+ if ([window cr_workspace:&workspace]) {
+ [destWindow cr_moveToWorkspace:workspace];
+ }
}
DCHECK(destWindow);
@@ -1841,6 +1922,26 @@ willAnimateFromState:(bookmarks::VisualState)oldState
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)
diff --git a/chrome/browser/cocoa/browser_window_controller_private.h b/chrome/browser/cocoa/browser_window_controller_private.h
index a9915a7..ec93540 100644
--- a/chrome/browser/cocoa/browser_window_controller_private.h
+++ b/chrome/browser/cocoa/browser_window_controller_private.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/browser_window_controller_private.mm b/chrome/browser/cocoa/browser_window_controller_private.mm
index 9f14c2e..cc3e726 100644
--- a/chrome/browser/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/cocoa/browser_window_controller_private.mm
@@ -9,24 +9,23 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_theme_provider.h"
-#import "chrome/browser/cocoa/chrome_browser_window.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/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/pref_service.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/common/pref_names.h"
-
namespace {
// Space between the incognito badge and the right edge of the window.
@@ -51,10 +50,13 @@ const CGFloat kLocBarBottomInset = 1;
if ([self useVerticalTabs])
factory = [SideTabStripController class];
+ DCHECK([sidebarController_ view]);
+ DCHECK([[sidebarController_ view] window]);
tabStripController_.reset([[factory alloc]
initWithView:[self tabStripView]
- switchView:[self tabContentArea]
- browser:browser_.get()]);
+ switchView:[sidebarController_ view]
+ browser:browser_.get()
+ delegate:self]);
}
- (void)saveWindowPositionIfNeeded {
@@ -100,16 +102,16 @@ const CGFloat kLocBarBottomInset = 1;
DictionaryValue* windowPreferences = prefs->GetMutableDictionary(
browser_->GetWindowPlacementKey().c_str());
- windowPreferences->SetInteger(L"left", bounds.x());
- windowPreferences->SetInteger(L"top", bounds.y());
- windowPreferences->SetInteger(L"right", bounds.right());
- windowPreferences->SetInteger(L"bottom", bounds.bottom());
- windowPreferences->SetBoolean(L"maximized", false);
- windowPreferences->SetBoolean(L"always_on_top", false);
- windowPreferences->SetInteger(L"work_area_left", workArea.x());
- windowPreferences->SetInteger(L"work_area_top", workArea.y());
- windowPreferences->SetInteger(L"work_area_right", workArea.right());
- windowPreferences->SetInteger(L"work_area_bottom", workArea.bottom());
+ 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
@@ -230,9 +232,6 @@ willPositionSheet:(NSWindow*)sheet
NSRect contentAreaRect = NSMakeRect(minX, minY, width, maxY - minY);
[self layoutTabContentArea:contentAreaRect];
- // Place the status bubble at the bottom of the content area.
- verticalOffsetForStatusBubble_ = minY;
-
// Normally, we don't need to tell the toolbar whether or not to show the
// divider, but things break down during animation.
[toolbarController_
diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm
index 8431aa1..17886c2 100644
--- a/chrome/browser/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm
@@ -12,7 +12,7 @@
#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/pref_service.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"
@@ -50,6 +50,14 @@
return [findBarCocoaController_ view];
}
+- (NSSplitView*)devToolsView {
+ return static_cast<NSSplitView*>([devToolsController_ view]);
+}
+
+- (NSView*)sidebarView {
+ return [sidebarController_ view];
+}
+
- (BOOL)bookmarkBarVisible {
return [bookmarkBarController_ isVisible];
}
@@ -547,6 +555,38 @@ TEST_F(BrowserWindowControllerTest, TestFindBarOnTop) {
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
@@ -587,6 +627,10 @@ TEST_F(BrowserWindowFullScreenControllerTest, TestFullscreen) {
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]);
diff --git a/chrome/browser/cocoa/browser_window_factory.mm b/chrome/browser/cocoa/browser_window_factory.mm
index ef83956..e655813 100644
--- a/chrome/browser/cocoa/browser_window_factory.mm
+++ b/chrome/browser/cocoa/browser_window_factory.mm
@@ -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.
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/cocoa/browser_window_cocoa.h"
diff --git a/chrome/browser/cocoa/bubble_view.mm b/chrome/browser/cocoa/bubble_view.mm
index 9c5f569..e7815b8 100644
--- a/chrome/browser/cocoa/bubble_view.mm
+++ b/chrome/browser/cocoa/bubble_view.mm
@@ -4,8 +4,8 @@
#import "chrome/browser/cocoa/bubble_view.h"
-#include "chrome/browser/browser_theme_provider.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"
diff --git a/chrome/browser/cocoa/bubble_view_unittest.mm b/chrome/browser/cocoa/bubble_view_unittest.mm
index d4179af..3b3bf77 100644
--- a/chrome/browser/cocoa/bubble_view_unittest.mm
+++ b/chrome/browser/cocoa/bubble_view_unittest.mm
@@ -6,6 +6,7 @@
#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:
@@ -37,10 +38,10 @@ TEST_F(BubbleViewTest, SetContent) {
[view_ setContent:nil];
EXPECT_TRUE([view_ content] == nil);
[view_ setContent:@""];
- EXPECT_TRUE([[view_ content] isEqualToString:@""]);
+ EXPECT_NSEQ(@"", [view_ content]);
NSString* str = @"This is a really really long string that's just too long";
[view_ setContent:str];
- EXPECT_TRUE([[view_ content] isEqualToString:str]);
+ EXPECT_NSEQ(str, [view_ content]);
}
TEST_F(BubbleViewTest, CornerFlags) {
diff --git a/chrome/browser/cocoa/bug_report_window_controller.h b/chrome/browser/cocoa/bug_report_window_controller.h
index 7b7d98c..116044a 100644
--- a/chrome/browser/cocoa/bug_report_window_controller.h
+++ b/chrome/browser/cocoa/bug_report_window_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/bug_report_window_controller.mm b/chrome/browser/cocoa/bug_report_window_controller.mm
index c7e920d..df29f99 100644
--- a/chrome/browser/cocoa/bug_report_window_controller.mm
+++ b/chrome/browser/cocoa/bug_report_window_controller.mm
@@ -113,7 +113,6 @@
base::SysNSStringToUTF8(pageTitle_),
[self bugTypeFromIndex],
base::SysNSStringToUTF8(pageURL_),
- std::string(),
base::SysNSStringToUTF8(bugDescription_),
sendScreenshot_ && !pngData_.empty() ?
reinterpret_cast<const char *>(&(pngData_[0])) : NULL,
diff --git a/chrome/browser/cocoa/bug_report_window_controller_unittest.mm b/chrome/browser/cocoa/bug_report_window_controller_unittest.mm
index 941327f..5c78c67 100644
--- a/chrome/browser/cocoa/bug_report_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/bug_report_window_controller_unittest.mm
@@ -6,10 +6,13 @@
#include "base/ref_counted.h"
#import "chrome/browser/cocoa/bug_report_window_controller.h"
+#include "chrome/browser/chrome_thread.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 {
@@ -39,8 +42,8 @@ TEST_F(BugReportWindowControllerUnittest, DISABLED_ReportBugWithNewTabPageOpen)
EXPECT_FALSE([controller isPhishingReport]);
// Make sure that the tab was correctly recorded.
- EXPECT_TRUE([[controller pageURL] isEqualToString:@"chrome://newtab/"]);
- EXPECT_TRUE([[controller pageTitle] isEqualToString:@"New Tab"]);
+ 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.
diff --git a/chrome/browser/cocoa/chrome_browser_window.h b/chrome/browser/cocoa/chrome_browser_window.h
index ca2f439..488bf0b 100644
--- a/chrome/browser/cocoa/chrome_browser_window.h
+++ b/chrome/browser/cocoa/chrome_browser_window.h
@@ -1,63 +1,27 @@
-// 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.
#ifndef CHROME_BROWSER_COCOA_CHROME_BROWSER_WINDOW_H_
#define CHROME_BROWSER_COCOA_CHROME_BROWSER_WINDOW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
-#include "base/scoped_nsobject.h"
#include "chrome/browser/cocoa/chrome_event_processing_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 kChromeWindowButtonsWithTabStripOffsetFromTop = 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 kChromeWindowButtonsWithoutTabStripOffsetFromTop = 4;
-
-// Offset from the left of the window frame to the top of the window controls
-// (zoom, close, miniaturize).
-const NSInteger kChromeWindowButtonsOffsetFromLeft = 8;
-
-// Offset between the window controls (zoom, close, miniaturize).
-const NSInteger kChromeWindowButtonsInterButtonSpacing = 7;
-
-// Cocoa class representing a Chrome 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.
+// 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
- BOOL shouldHideTitle_;
- NSButton* closeButton_;
- NSButton* miniaturizeButton_;
- NSButton* zoomButton_;
- BOOL entered_;
- scoped_nsobject<NSTrackingArea> widgetTrackingArea_;
+ int underlaySurfaceCount_;
}
-// 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;
+// 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
diff --git a/chrome/browser/cocoa/chrome_browser_window.mm b/chrome/browser/cocoa/chrome_browser_window.mm
index 35aae1a..6dc6cea 100644
--- a/chrome/browser/cocoa/chrome_browser_window.mm
+++ b/chrome/browser/cocoa/chrome_browser_window.mm
@@ -1,350 +1,31 @@
-// 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.
#import "chrome/browser/cocoa/chrome_browser_window.h"
#include "base/logging.h"
-#include "chrome/browser/browser_theme_provider.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"
-
-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 ChromeBrowserWindow(ChromeBrowserWindowPrivateMethods)
-// Return the view that does the "frame" drawing.
-- (NSView*)frameView;
-@end
+#include "chrome/browser/themes/browser_theme_provider.h"
@implementation ChromeBrowserWindow
-- (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] ?
- kChromeWindowButtonsWithTabStripOffsetFromTop :
- kChromeWindowButtonsWithoutTabStripOffsetFromTop;
- closeButtonFrame.origin =
- NSMakePoint(kChromeWindowButtonsOffsetFromLeft,
- (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) +
- kChromeWindowButtonsInterButtonSpacing),
- 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) +
- kChromeWindowButtonsInterButtonSpacing),
- 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)underlaySurfaceAdded {
+ DCHECK_GE(underlaySurfaceCount_, 0);
+ ++underlaySurfaceCount_;
-- (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];
+ // 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)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;
+- (void)underlaySurfaceRemoved {
+ --underlaySurfaceCount_;
+ DCHECK_GE(underlaySurfaceCount_, 0);
- return [super constrainFrameRect:frame toScreen:screen];
+ if (underlaySurfaceCount_ == 0)
+ [self setOpaque:YES];
}
- (ThemeProvider*)themeProvider {
diff --git a/chrome/browser/cocoa/chrome_browser_window_unittest.mm b/chrome/browser/cocoa/chrome_browser_window_unittest.mm
index 4ab4a2a..2b82f79 100644
--- a/chrome/browser/cocoa/chrome_browser_window_unittest.mm
+++ b/chrome/browser/cocoa/chrome_browser_window_unittest.mm
@@ -1,18 +1,14 @@
-// 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.
#import <Cocoa/Cocoa.h>
-#include "base/scoped_nsobject.h"
-#include "chrome/app/chrome_dll_resource.h"
#import "chrome/browser/cocoa/chrome_browser_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"
#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 ChromeBrowserWindowTest : public CocoaTest {
public:
@@ -38,19 +34,6 @@ class ChromeBrowserWindowTest : public CocoaTest {
CocoaTest::TearDown();
}
- // Returns a canonical snapshot of the window.
- NSData* WindowContentsAsTIFF() {
- NSRect frame([window_ frame]);
- frame.origin = [window_ convertScreenToBase:frame.origin];
-
- NSData* pdfData = [window_ dataWithPDFInsideRect:frame];
-
- // |pdfData| can differ for windows which look the same, so make it
- // canonical.
- NSImage* image = [[[NSImage alloc] initWithData:pdfData] autorelease];
- return [image TIFFRepresentation];
- }
-
ChromeBrowserWindow* window_;
};
@@ -59,119 +42,3 @@ class ChromeBrowserWindowTest : public CocoaTest {
TEST_F(ChromeBrowserWindowTest, ShowAndClose) {
[window_ display];
}
-
-// Test that undocumented title-hiding API we're using does the job.
-TEST_F(ChromeBrowserWindowTest, 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 emtpy 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(ChromeBrowserWindowTest, 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) -
- kChromeWindowButtonsWithoutTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(closeBoxFrame), kChromeWindowButtonsOffsetFromLeft);
-
- NSCell* miniaturizeCell = [window_ accessibilityAttributeValue:
- NSAccessibilityMinimizeButtonAttribute];
- NSView* miniaturizeControl = [miniaturizeCell controlView];
- EXPECT_TRUE(miniaturizeControl);
- NSRect miniaturizeFrame = [miniaturizeControl frame];
- EXPECT_EQ(NSMaxY(miniaturizeFrame),
- NSMaxY(windowBounds) -
- kChromeWindowButtonsWithoutTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(miniaturizeFrame),
- NSMaxX(closeBoxFrame) + kChromeWindowButtonsInterButtonSpacing);
-
- // 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) -
- kChromeWindowButtonsWithTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(closeBoxFrame), kChromeWindowButtonsOffsetFromLeft);
-
- miniaturizeCell = [window_ accessibilityAttributeValue:
- NSAccessibilityMinimizeButtonAttribute];
- miniaturizeControl = [miniaturizeCell controlView];
- EXPECT_TRUE(miniaturizeControl);
- miniaturizeFrame = [miniaturizeControl frame];
- EXPECT_EQ(NSMaxY(miniaturizeFrame),
- NSMaxY(windowBounds) -
- kChromeWindowButtonsWithTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(miniaturizeFrame),
- NSMaxX(closeBoxFrame) + kChromeWindowButtonsInterButtonSpacing);
- [window_ setWindowController:nil];
-}
-
-// Test that we actually have a tracking area in place.
-TEST_F(ChromeBrowserWindowTest, 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_TRUE([[area owner] isEqual:frameView]);
- break;
- }
- }
- EXPECT_TRUE(foundArea);
-}
-
diff --git a/chrome/browser/cocoa/chrome_event_processing_window.h b/chrome/browser/cocoa/chrome_event_processing_window.h
index 4159be7..a470ddd 100644
--- a/chrome/browser/cocoa/chrome_event_processing_window.h
+++ b/chrome/browser/cocoa/chrome_event_processing_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
#define CHROME_BROWSER_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/chrome_event_processing_window_unittest.mm b/chrome/browser/cocoa/chrome_event_processing_window_unittest.mm
index 05b99f5..1b54dcb 100644
--- a/chrome/browser/cocoa/chrome_event_processing_window_unittest.mm
+++ b/chrome/browser/cocoa/chrome_event_processing_window_unittest.mm
@@ -50,19 +50,6 @@ class ChromeEventProcessingWindowTest : public CocoaTest {
CocoaTest::TearDown();
}
- // Returns a canonical snapshot of the window.
- NSData* WindowContentsAsTIFF() {
- NSRect frame([window_ frame]);
- frame.origin = [window_ convertScreenToBase:frame.origin];
-
- NSData* pdfData = [window_ dataWithPDFInsideRect:frame];
-
- // |pdfData| can differ for windows which look the same, so make it
- // canonical.
- NSImage* image = [[[NSImage alloc] initWithData:pdfData] autorelease];
- return [image TIFFRepresentation];
- }
-
ChromeEventProcessingWindow* window_;
};
diff --git a/chrome/browser/cocoa/clear_browsing_data_controller.h b/chrome/browser/cocoa/clear_browsing_data_controller.h
index 230fdf4..7be460e 100644
--- a/chrome/browser/cocoa/clear_browsing_data_controller.h
+++ b/chrome/browser/cocoa/clear_browsing_data_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
#define CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/clear_browsing_data_controller.mm b/chrome/browser/cocoa/clear_browsing_data_controller.mm
index 7d9d290..c79525f 100644
--- a/chrome/browser/cocoa/clear_browsing_data_controller.mm
+++ b/chrome/browser/cocoa/clear_browsing_data_controller.mm
@@ -11,7 +11,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/browsing_data_remover.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/locale_settings.h"
diff --git a/chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm b/chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm
index 8efa160..9de805e 100644
--- a/chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm
+++ b/chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm
@@ -9,7 +9,7 @@
#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/pref_service.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"
diff --git a/chrome/browser/cocoa/clickhold_button_cell.h b/chrome/browser/cocoa/clickhold_button_cell.h
index 1982281..e80edc5 100644
--- a/chrome/browser/cocoa/clickhold_button_cell.h
+++ b/chrome/browser/cocoa/clickhold_button_cell.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_CLICKHOLD_BUTTON_CELL_H_
#define CHROME_BROWSER_COCOA_CLICKHOLD_BUTTON_CELL_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/cocoa_test_helper.h b/chrome/browser/cocoa/cocoa_test_helper.h
index 50d0707..da244e4 100644
--- a/chrome/browser/cocoa/cocoa_test_helper.h
+++ b/chrome/browser/cocoa/cocoa_test_helper.h
@@ -1,21 +1,19 @@
-// 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.
#ifndef CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_
#define CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
-#include <vector>
#import "base/chrome_application_mac.h"
#include "base/debug_util.h"
-#include "base/file_path.h"
#include "base/mac_util.h"
#include "base/path_service.h"
#import "base/scoped_nsautorelease_pool.h"
#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
#include "chrome/common/chrome_constants.h"
#include "testing/platform_test.h"
@@ -123,71 +121,6 @@ class CocoaTest : public PlatformTest {
[test_view display]; \
}
-// The classes below are deprecated and will be removed shortly. Do not write
-// any tests based on them.
-
-// A class that initializes Cocoa and sets up resources for many of our
-// Cocoa controller unit tests. It does several key things:
-// - Creates and displays an empty Cocoa window for views to live in
-// - Loads the appropriate bundle so nib loading works. When loading the
-// nib in the class being tested, your must use |mac_util::MainAppBundle()|
-// as the bundle. If you do not specify a bundle, your test will likely
-// fail.
-// It currently does not create an autorelease pool, though that can easily be
-// added. If your test wants one, it can derive from PlatformTest instead of
-// testing::Test.
-
-// Provides the Cocoa goodness without the extraneous window.
-
-// DEPRECATED
-// TODO(dmaclach): remove as soon as I can get my other CLs in that get rid
-// of any dependencies on this. 10/30/09 at the latest.
-class CocoaNoWindowTestHelper {
- public:
- CocoaNoWindowTestHelper() {
- CocoaTest::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];
- }
-};
-
-// DEPRECATED
-// TODO(dmaclach): remove as soon as I can get my other CLs in that get rid
-// of any dependencies on this. 11/30/09 at the latest.
-class CocoaTestHelper : public CocoaNoWindowTestHelper {
- public:
- CocoaTestHelper() {
- window_.reset([[CocoaTestHelperWindow alloc] init]);
- if (DebugUtil::BeingDebugged()) {
- [window_ orderFront:nil];
- } else {
- [window_ orderBack:nil];
- }
- }
-
- // Access the Cocoa window created for the test.
- NSWindow* window() const { return window_.get(); }
- NSView* contentView() const { return [window_ contentView]; }
-
- // Set |window_| to pretend to be key and make |aView| its
- // firstResponder.
- void makeFirstResponder(NSView* aView) {
- [window_ makeFirstResponder:aView];
- [window_ setPretendIsKeyWindow:YES];
- }
-
- // Clear |window_| firstResponder and stop pretending to be key.
- void clearFirstResponder() {
- [window_ setPretendIsKeyWindow:NO];
- [window_ makeFirstResponder:nil];
- }
-
- private:
- scoped_nsobject<CocoaTestHelperWindow> window_;
-};
-
// A macro which determines the proper float epsilon for a CGFloat.
#if CGFLOAT_IS_DOUBLE
#define CGFLOAT_EPSILON DBL_EPSILON
diff --git a/chrome/browser/cocoa/collected_cookies_mac.h b/chrome/browser/cocoa/collected_cookies_mac.h
index 9f5b5dd..2392763 100644
--- a/chrome/browser/cocoa/collected_cookies_mac.h
+++ b/chrome/browser/cocoa/collected_cookies_mac.h
@@ -4,7 +4,6 @@
#import <Cocoa/Cocoa.h>
-#include "app/tree_model.h"
#include "base/cocoa_protocols_mac.h"
#include "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
@@ -14,6 +13,7 @@
#include "chrome/common/notification_registrar.h"
@class CollectedCookiesWindowController;
+@class VerticalGradientView;
class TabContents;
// The constrained window delegate reponsible for managing the collected
@@ -74,8 +74,18 @@ class CollectedCookiesMac : public ConstrainedWindowMacDelegateCustomSheet,
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;
diff --git a/chrome/browser/cocoa/collected_cookies_mac.mm b/chrome/browser/cocoa/collected_cookies_mac.mm
index 693c8e4..671bf87 100644
--- a/chrome/browser/cocoa/collected_cookies_mac.mm
+++ b/chrome/browser/cocoa/collected_cookies_mac.mm
@@ -10,7 +10,7 @@
#include "app/resource_bundle.h"
#import "base/mac_util.h"
#include "base/sys_string_conversions.h"
-#include "chrome/browser/cocoa/content_settings_dialog_controller.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"
@@ -19,8 +19,20 @@
#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"
-static const CGFloat kMinCollectedCookiesViewHeight = 116;
+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
@@ -101,6 +113,13 @@ void CollectedCookiesMac::OnSheetDidEnd(NSWindow* sheet) {
#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 =
@@ -113,20 +132,78 @@ void CollectedCookiesMac::OnSheetDidEnd(NSWindow* sheet) {
- (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])) {
- tabContents_ = tabContents;
-
[self loadTreeModelFromTabContents];
+
+ animation_.reset([[NSViewAnimation alloc] init]);
+ [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
}
return self;
}
+- (void)awakeFromNib {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* infoIcon = rb.GetNSImageNamed(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];
}
@@ -137,6 +214,8 @@ void CollectedCookiesMac::OnSheetDidEnd(NSWindow* sheet) {
- (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]);
@@ -149,11 +228,14 @@ void CollectedCookiesMac::OnSheetDidEnd(NSWindow* sheet) {
origin_node->CreateContentException(
tabContents_->profile()->GetHostContentSettingsMap(),
setting);
+ if (!lastDomain.empty())
+ multipleDomainsChanged = YES;
+ lastDomain = origin_node->GetTitle();
}
- [[ContentSettingsDialogController
- showContentSettingsForType:CONTENT_SETTINGS_TYPE_COOKIES
- profile:tabContents_->profile()]
- showCookieExceptions:self];
+ if (multipleDomainsChanged)
+ [self showInfoBarForMultipleDomainsAndSetting:setting];
+ else
+ [self showInfoBarForDomain:lastDomain setting:setting];
}
- (IBAction)allowOrigin:(id)sender {
@@ -299,4 +381,119 @@ void CollectedCookiesMac::OnSheetDidEnd(NSWindow* sheet) {
[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
index ff6f3c5..033cc71 100644
--- a/chrome/browser/cocoa/collected_cookies_mac_unittest.mm
+++ b/chrome/browser/cocoa/collected_cookies_mac_unittest.mm
@@ -11,6 +11,7 @@
#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 {
diff --git a/chrome/browser/cocoa/command_observer_bridge.h b/chrome/browser/cocoa/command_observer_bridge.h
index e4487c8..83b5577 100644
--- a/chrome/browser/cocoa/command_observer_bridge.h
+++ b/chrome/browser/cocoa/command_observer_bridge.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_COMMAND_OBSERVER_BRIDGE
#define CHROME_BROWSER_COCOA_COMMAND_OBSERVER_BRIDGE
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/constrained_window_mac.h b/chrome/browser/cocoa/constrained_window_mac.h
index 0fd315d..321f9c7 100644
--- a/chrome/browser/cocoa/constrained_window_mac.h
+++ b/chrome/browser/cocoa/constrained_window_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_CONSTRAINED_WINDOW_MAC_H_
#define CHROME_BROWSER_COCOA_CONSTRAINED_WINDOW_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -59,6 +60,16 @@ class ConstrainedWindowMacDelegateSystemSheet
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);
diff --git a/chrome/browser/cocoa/constrained_window_mac.mm b/chrome/browser/cocoa/constrained_window_mac.mm
index eec4dba..e063896 100644
--- a/chrome/browser/cocoa/constrained_window_mac.mm
+++ b/chrome/browser/cocoa/constrained_window_mac.mm
@@ -11,15 +11,21 @@
ConstrainedWindowMacDelegate::~ConstrainedWindowMacDelegate() {}
-void ConstrainedWindowMacDelegateSystemSheet::RunSheet(
- GTMWindowSheetController* sheetController,
- NSView* view) {
- NSArray* params = [NSArray arrayWithObjects:
+NSArray* ConstrainedWindowMacDelegateSystemSheet::GetSheetParameters(
+ id delegate,
+ SEL didEndSelector) {
+ return [NSArray arrayWithObjects:
[NSNull null], // window, must be [NSNull null]
- delegate_.get(),
- [NSValue valueWithPointer:didEndSelector_],
+ 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];
diff --git a/chrome/browser/cocoa/content_blocked_bubble_controller.h b/chrome/browser/cocoa/content_blocked_bubble_controller.h
deleted file mode 100644
index 3d824cf..0000000
--- a/chrome/browser/cocoa/content_blocked_bubble_controller.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.
-
-#include <map>
-#include <string>
-
-#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_blocked_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 ContentBlockedBubbleController : BaseBubbleController {
- @private
- IBOutlet NSTextField* titleLabel_;
- IBOutlet NSMatrix* allowBlockRadioGroup_;
-
- IBOutlet NSButton* manageButton_;
- IBOutlet NSButton* doneButton_;
-
- // The container for the bubble contents of the geolocation bubble.
- IBOutlet NSView* contentsContainer_;
-
- scoped_ptr<ContentSettingBubbleModel> contentSettingBubbleModel_;
- content_blocked_bubble::PopupLinks popupLinks_;
-}
-
-// Creates and shows a content blocked bubble. Takes ownership of
-// |contentSettingBubbleModel| but not of the other objects.
-+ (ContentBlockedBubbleController*)
- 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;
-
-@end
diff --git a/chrome/browser/cocoa/content_blocked_bubble_controller.mm b/chrome/browser/cocoa/content_blocked_bubble_controller.mm
deleted file mode 100644
index b4c453b..0000000
--- a/chrome/browser/cocoa/content_blocked_bubble_controller.mm
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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_blocked_bubble_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/blocked_popup_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 "grit/generated_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.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;
-
-// 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 ContentBlockedBubbleController(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)initializeTitle;
-- (void)initializeRadioGroup;
-- (void)initializePopupList;
-- (void)initializeGeoLists;
-- (void)sizeToFitManageDoneButtons;
-- (void)popupLinkClicked:(id)sender;
-- (void)clearGeolocationForCurrentHost:(id)sender;
-@end
-
-@implementation ContentBlockedBubbleController
-
-+ (ContentBlockedBubbleController*)
- showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchor {
- // Autoreleases itself on bubble close.
- return [[ContentBlockedBubbleController 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;
-
- // 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.
- // TODO(joth): Implement the generic case, getting localized strings from the
- // bubble model instead of the xib, or remove it if it's never needed.
- // http://crbug.com/38432
- const ContentSettingBubbleModel::RadioGroup& radioGroup =
- contentSettingBubbleModel_->bubble_content().radio_group;
-
- // Select appropriate radio button.
- [allowBlockRadioGroup_ selectCellWithTag:
- radioGroup.default_item == 0 ? kAllowTag : kBlockTag];
-
- // Copy |host_| into radio group label.
- NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag];
- [radioCell setTitle:cocoa_l10n_util::ReplaceNSStringPlaceholders(
- [radioCell title], UTF8ToUTF16(radioGroup.url.host()), NULL)];
-
- // 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)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)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 {
- [[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];
- if (allowBlockRadioGroup_) // not bound in cookie bubble xib
- [self initializeRadioGroup];
- if (contentSettingBubbleModel_->content_type() ==
- CONTENT_SETTINGS_TYPE_POPUPS)
- [self initializePopupList];
- if (contentSettingBubbleModel_->content_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];
-}
-
-- (void)popupLinkClicked:(id)sender {
- content_blocked_bubble::PopupLinks::iterator i(popupLinks_.find(sender));
- DCHECK(i != popupLinks_.end());
- contentSettingBubbleModel_->OnPopupClicked(i->second);
-}
-
-- (void)clearGeolocationForCurrentHost:(id)sender {
- contentSettingBubbleModel_->OnClearLinkClicked();
- [self close];
-}
-
-@end // ContentBlockedBubbleController
diff --git a/chrome/browser/cocoa/content_blocked_bubble_controller_unittest.mm b/chrome/browser/cocoa/content_blocked_bubble_controller_unittest.mm
deleted file mode 100644
index 4ecc51a..0000000
--- a/chrome/browser/cocoa/content_blocked_bubble_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.
-
-#import "chrome/browser/cocoa/content_blocked_bubble_controller.h"
-
-#import <Cocoa/Cocoa.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 ContentBlockedBubbleControllerTest : public CocoaTest {
-};
-
-// Check that the bubble doesn't crash or leak for any settings type
-TEST_F(ContentBlockedBubbleControllerTest, 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 (DebugUtil::BeingDebugged())
- [parent.get() orderFront:nil];
- else
- [parent.get() orderBack:nil];
-
- ContentBlockedBubbleController* controller = [ContentBlockedBubbleController
- 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_exceptions_window_controller.h b/chrome/browser/cocoa/content_exceptions_window_controller.h
index 5c012f3..ede76f7 100644
--- a/chrome/browser/cocoa/content_exceptions_window_controller.h
+++ b/chrome/browser/cocoa/content_exceptions_window_controller.h
@@ -4,8 +4,6 @@
#import <Cocoa/Cocoa.h>
-#include <string>
-
#include "base/cocoa_protocols_mac.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/host_content_settings_map.h"
diff --git a/chrome/browser/cocoa/content_exceptions_window_controller.mm b/chrome/browser/cocoa/content_exceptions_window_controller.mm
index 86de896..e671492 100644
--- a/chrome/browser/cocoa/content_exceptions_window_controller.mm
+++ b/chrome/browser/cocoa/content_exceptions_window_controller.mm
@@ -4,12 +4,15 @@
#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/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
@@ -493,8 +496,8 @@ static ContentExceptionsWindowController*
}
- (size_t)menuItemCount {
- return showSession_ ?
- arraysize(kSessionSettings) : arraysize(kNoSessionSettings);
+ return showSession_ ? arraysize(kSessionSettings)
+ : arraysize(kNoSessionSettings);
}
- (NSString*)titleForIndex:(size_t)index {
diff --git a/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm b/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm
index 2c842b5..3ec1944 100644
--- a/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm
@@ -112,6 +112,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddRemove) {
ClickAdd(controller);
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
&settings);
EXPECT_EQ(0u, settings.size());
@@ -121,6 +122,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddRemove) {
[controller close];
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
&settings);
EXPECT_EQ(0u, settings.size());
}
@@ -138,6 +140,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddRemoveAll) {
HostContentSettingsMap::SettingsForOneType settings;
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
&settings);
EXPECT_EQ(0u, settings.size());
}
@@ -154,6 +157,7 @@ TEST_F(ContentExceptionsWindowControllerTest, Add) {
HostContentSettingsMap::SettingsForOneType settings;
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
&settings);
EXPECT_EQ(1u, settings.size());
EXPECT_EQ(HostContentSettingsMap::Pattern("addedhost"), settings[0].first);
@@ -169,6 +173,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddEscDoesNotAdd) {
HostContentSettingsMap::SettingsForOneType settings;
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
&settings);
EXPECT_EQ(0u, settings.size());
EXPECT_FALSE([controller editingNewException]);
@@ -191,6 +196,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddEditAddAdd) {
HostContentSettingsMap::SettingsForOneType settings;
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
&settings);
EXPECT_EQ(0u, settings.size());
}
@@ -198,6 +204,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddEditAddAdd) {
TEST_F(ContentExceptionsWindowControllerTest, AddExistingEditAdd) {
settingsMap_->SetContentSetting(HostContentSettingsMap::Pattern("myhost"),
CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
CONTENT_SETTING_BLOCK);
ContentExceptionsWindowController* controller =
@@ -213,6 +220,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddExistingEditAdd) {
HostContentSettingsMap::SettingsForOneType settings;
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
&settings);
EXPECT_EQ(1u, settings.size());
}
@@ -220,6 +228,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddExistingEditAdd) {
TEST_F(ContentExceptionsWindowControllerTest, AddExistingDoesNotOverwrite) {
settingsMap_->SetContentSetting(HostContentSettingsMap::Pattern("myhost"),
CONTENT_SETTINGS_TYPE_COOKIES,
+ "",
CONTENT_SETTING_SESSION_ONLY);
ContentExceptionsWindowController* controller =
@@ -233,6 +242,7 @@ TEST_F(ContentExceptionsWindowControllerTest, AddExistingDoesNotOverwrite) {
HostContentSettingsMap::SettingsForOneType settings;
settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES,
+ "",
&settings);
EXPECT_EQ(1u, settings.size());
EXPECT_EQ(CONTENT_SETTING_SESSION_ONLY, settings[0].second);
diff --git a/chrome/browser/cocoa/content_settings_dialog_controller.h b/chrome/browser/cocoa/content_settings_dialog_controller.h
index 3e1013b..8fe92da 100644
--- a/chrome/browser/cocoa/content_settings_dialog_controller.h
+++ b/chrome/browser/cocoa/content_settings_dialog_controller.h
@@ -7,10 +7,11 @@
#import "base/cocoa_protocols_mac.h"
#include "base/scoped_ptr.h"
#include "chrome/common/content_settings_types.h"
-#include "chrome/browser/pref_member.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
-// for the cookies tab.
+// the ones below.
const NSInteger kContentSettingsEnabledIndex = 0;
const NSInteger kContentSettingsDisabledIndex = 1;
@@ -18,6 +19,11 @@ const NSInteger kContentSettingsDisabledIndex = 1;
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 kPluginsAllowSandboxedIndex = 1;
+const NSInteger kPluginsBlockIndex = 2;
+
// Indices of the various geolocation settings in the geolocation radio group.
const NSInteger kGeolocationEnabledIndex = 0;
const NSInteger kGeolocationAskIndex = 1;
@@ -45,6 +51,7 @@ class Profile;
Profile* profile_; // weak
IntegerPrefMember lastSelectedTab_;
BooleanPrefMember clearSiteDataOnExit_;
+ PrefChangeRegistrar registrar_;
scoped_ptr<ContentSettingsDialogControllerInternal::PrefObserverBridge>
observer_; // Watches for pref changes.
}
@@ -75,13 +82,13 @@ class Profile;
@interface ContentSettingsDialogController (TestingAPI)
// Properties that the radio groups and checkboxes are bound to.
-@property(assign, nonatomic) NSInteger cookieSettingIndex;
-@property(assign, nonatomic) BOOL blockThirdPartyCookies;
-@property(assign, nonatomic) BOOL clearSiteDataOnExit;
-@property(assign, nonatomic) NSInteger imagesEnabledIndex;
-@property(assign, nonatomic) NSInteger javaScriptEnabledIndex;
-@property(assign, nonatomic) NSInteger popupsEnabledIndex;
-@property(assign, nonatomic) NSInteger pluginsEnabledIndex;
-@property(assign, nonatomic) NSInteger geolocationSettingIndex;
-@property(assign, nonatomic) NSInteger notificationsSettingIndex;
+@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;
@end
diff --git a/chrome/browser/cocoa/content_settings_dialog_controller.mm b/chrome/browser/cocoa/content_settings_dialog_controller.mm
index d98948d..001a3ec 100644
--- a/chrome/browser/cocoa/content_settings_dialog_controller.mm
+++ b/chrome/browser/cocoa/content_settings_dialog_controller.mm
@@ -7,6 +7,7 @@
#import <Cocoa/Cocoa.h>
#include "app/l10n_util.h"
+#include "base/command_line.h"
#include "base/mac_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
@@ -20,8 +21,10 @@
#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/pref_service.h"
+#include "chrome/browser/plugin_exceptions_table_model.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.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"
@@ -43,7 +46,7 @@ ContentSettingsDialogController* g_instance = nil;
// Callback when preferences are changed. |prefName| is the name of the
// pref that has changed.
-- (void)prefChanged:(std::wstring*)prefName;
+- (void)prefChanged:(std::string*)prefName;
@end
@@ -61,7 +64,7 @@ class PrefObserverBridge : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details) {
if (!disabled_ && type == NotificationType::PREF_CHANGED) {
- [controller_ prefChanged:Details<std::wstring>(details).ptr()];
+ [controller_ prefChanged:Details<std::string>(details).ptr()];
}
}
@@ -137,10 +140,11 @@ class PrefObserverDisabler {
// Manually observe notifications for preferences that are grouped in
// the HostContentSettingsMap or GeolocationContentSettingsMap.
PrefService* prefs = profile_->GetPrefs();
- prefs->AddPrefObserver(prefs::kBlockThirdPartyCookies, observer_.get());
- prefs->AddPrefObserver(prefs::kDefaultContentSettings, observer_.get());
- prefs->AddPrefObserver(prefs::kGeolocationDefaultContentSetting,
- observer_.get());
+ 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,
@@ -149,18 +153,6 @@ class PrefObserverDisabler {
return self;
}
-- (void)dealloc {
- if (profile_) {
- PrefService* prefs = profile_->GetPrefs();
- prefs->RemovePrefObserver(prefs::kBlockThirdPartyCookies, observer_.get());
- prefs->RemovePrefObserver(prefs::kDefaultContentSettings, observer_.get());
- prefs->RemovePrefObserver(prefs::kGeolocationDefaultContentSetting,
- observer_.get());
- }
-
- [super dealloc];
-}
-
- (void)closeExceptionsSheet {
NSWindow* attachedSheet = [[self window] attachedSheet];
if (attachedSheet) {
@@ -287,11 +279,14 @@ class PrefObserverDisabler {
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];
+ appcacheHelper:appcacheHelper
+ indexedDBHelper:indexedDBHelper];
[controller attachSheetTo:[self window]];
}
@@ -324,7 +319,21 @@ class PrefObserverDisabler {
}
- (IBAction)showPluginsExceptions:(id)sender {
- [self showExceptionsForType:CONTENT_SETTINGS_TYPE_PLUGINS];
+ 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 {
@@ -396,20 +405,39 @@ class PrefObserverDisabler {
}
- (void)setPluginsEnabledIndex:(NSInteger)value {
- ContentSetting setting = value == kContentSettingsEnabledIndex ?
- CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
+ ContentSetting setting = CONTENT_SETTING_DEFAULT;
+ bool blockNonsandboxedPlugins = false;
+ switch (value) {
+ case kPluginsAllowSandboxedIndex:
+ blockNonsandboxedPlugins = true;
+ // Fall through to the next case.
+ case kPluginsAllowIndex:
+ setting = CONTENT_SETTING_ALLOW;
+ break;
+ case kPluginsBlockIndex:
+ setting = CONTENT_SETTING_BLOCK;
+ break;
+ default:
+ NOTREACHED();
+ }
ContentSettingsDialogControllerInternal::PrefObserverDisabler
disabler(observer_.get());
profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_PLUGINS, setting);
+ profile_->GetHostContentSettingsMap()->SetBlockNonsandboxedPlugins(
+ blockNonsandboxedPlugins);
}
- (NSInteger)pluginsEnabledIndex {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- bool enabled =
- settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS) ==
- CONTENT_SETTING_ALLOW;
- return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex;
+ HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
+ ContentSetting setting =
+ map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ if (setting == CONTENT_SETTING_ALLOW) {
+ if (map->GetBlockNonsandboxedPlugins())
+ return kPluginsAllowSandboxedIndex;
+ return kPluginsAllowIndex;
+ }
+ return kPluginsBlockIndex;
}
- (void)setPopupsEnabledIndex:(NSInteger)value {
@@ -487,7 +515,7 @@ class PrefObserverDisabler {
// Callback when preferences are changed. |prefName| is the name of the
// pref that has changed and should not be NULL.
-- (void)prefChanged:(std::wstring*)prefName {
+- (void)prefChanged:(std::string*)prefName {
DCHECK(prefName);
if (!prefName) return;
if (*prefName == prefs::kClearSiteDataOnExit) {
@@ -498,6 +526,10 @@ class PrefObserverDisabler {
[self willChangeValueForKey:@"blockThirdPartyCookies"];
[self didChangeValueForKey:@"blockThirdPartyCookies"];
}
+ 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
diff --git a/chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm b/chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm
index c0f1c32..9298349 100644
--- a/chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm
+++ b/chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm
@@ -9,7 +9,9 @@
#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 "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -156,23 +158,35 @@ TEST_F(ContentSettingsDialogControllerTest, PluginsSetting) {
// Change setting, check dialog property.
settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
CONTENT_SETTING_ALLOW);
- EXPECT_EQ([controller_ pluginsEnabledIndex], kContentSettingsEnabledIndex);
+ settingsMap_->SetBlockNonsandboxedPlugins(false);
+ EXPECT_EQ(kPluginsAllowIndex, [controller_ pluginsEnabledIndex]);
+
+ settingsMap_->SetBlockNonsandboxedPlugins(true);
+ EXPECT_EQ(kPluginsAllowSandboxedIndex, [controller_ pluginsEnabledIndex]);
settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
CONTENT_SETTING_BLOCK);
- EXPECT_EQ([controller_ pluginsEnabledIndex], kContentSettingsDisabledIndex);
+ EXPECT_EQ(kPluginsBlockIndex, [controller_ pluginsEnabledIndex]);
// Change dialog property, check setting.
NSInteger setting;
- [controller_ setPluginsEnabledIndex:kContentSettingsEnabledIndex];
+ [controller_ setPluginsEnabledIndex:kPluginsAllowIndex];
setting =
settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
- EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
+ EXPECT_EQ(false, settingsMap_->GetBlockNonsandboxedPlugins());
- [controller_ setPluginsEnabledIndex:kContentSettingsDisabledIndex];
+ [controller_ setPluginsEnabledIndex:kPluginsAllowSandboxedIndex];
setting =
settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
- EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
+ EXPECT_EQ(true, settingsMap_->GetBlockNonsandboxedPlugins());
+
+ [controller_ setPluginsEnabledIndex:kPluginsBlockIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK, setting);
+ EXPECT_EQ(false, settingsMap_->GetBlockNonsandboxedPlugins());
}
TEST_F(ContentSettingsDialogControllerTest, PopupsSetting) {
diff --git a/chrome/browser/cocoa/cookie_details.h b/chrome/browser/cocoa/cookie_details.h
index ce50dd9..5298ad8 100644
--- a/chrome/browser/cocoa/cookie_details.h
+++ b/chrome/browser/cocoa/cookie_details.h
@@ -5,6 +5,7 @@
#import <Cocoa/Cocoa.h>
#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 "base/scoped_nsobject.h"
#include "net/base/cookie_monster.h"
@@ -21,31 +22,35 @@ enum CocoaCookieDetailsType {
// Detailed information about a cookie, used both in the cookie
// tree and the cookie prompt.
- kCocoaCookieDetailsTypeCookie = 1,
+ kCocoaCookieDetailsTypeCookie,
// Detailed information about a web database used for
// display in the cookie tree.
- kCocoaCookieDetailsTypeTreeDatabase = 2,
+ kCocoaCookieDetailsTypeTreeDatabase,
// Detailed information about local storage used for
// display in the cookie tree.
- kCocoaCookieDetailsTypeTreeLocalStorage = 3,
+ kCocoaCookieDetailsTypeTreeLocalStorage,
// Detailed information about an appcache used for display in the
// cookie tree.
- kCocoaCookieDetailsTypeTreeAppCache = 4,
+ kCocoaCookieDetailsTypeTreeAppCache,
+
+ // Detailed information about an IndexedDB used for display in the
+ // cookie tree.
+ kCocoaCookieDetailsTypeTreeIndexedDB,
// Detailed information about a web database used for display
// in the cookie prompt dialog.
- kCocoaCookieDetailsTypePromptDatabase = 5,
+ kCocoaCookieDetailsTypePromptDatabase,
// Detailed information about local storage used for display
// in the cookie prompt dialog.
- kCocoaCookieDetailsTypePromptLocalStorage = 6,
+ kCocoaCookieDetailsTypePromptLocalStorage,
// Detailed information about app caches used for display
// in the cookie prompt dialog.
- kCocoaCookieDetailsTypePromptAppCache = 7
+ kCocoaCookieDetailsTypePromptAppCache
};
// This class contains all of the information that can be displayed in
@@ -67,48 +72,52 @@ enum CocoaCookieDetailsType {
// it will expire with the session.
BOOL hasExpiration_;
- // These members are only set for type kCocoaCookieDetailsTypeCookie.
+ // Only set for type kCocoaCookieDetailsTypeCookie.
scoped_nsobject<NSString> content_;
scoped_nsobject<NSString> path_;
scoped_nsobject<NSString> sendFor_;
// Stringifed dates.
scoped_nsobject<NSString> expires_;
- // These members are only set for type kCocoaCookieDetailsTypeCookie and
+ // Only set for type kCocoaCookieDetailsTypeCookie and
// kCocoaCookieDetailsTypeTreeAppCache nodes.
scoped_nsobject<NSString> created_;
- // These members are only set for types kCocoaCookieDetailsTypeCookie,
- // kCocoaCookieDetailsTypePromptDatabase.
+ // Only set for types kCocoaCookieDetailsTypeCookie,
+ // kCocoaCookieDetailsTypePromptDatabase, and
+ // kCocoaCookieDetailsTypeTreeIndexedDB nodes.
scoped_nsobject<NSString> name_;
// Only set for type kCocoaCookieDetailsTypeTreeLocalStorage,
// kCocoaCookieDetailsTypeTreeDatabase,
- // kCocoaCookieDetailsTypePromptDatabase and
+ // kCocoaCookieDetailsTypePromptDatabase,
+ // kCocoaCookieDetailsTypeTreeIndexedDB, and
// kCocoaCookieDetailsTypeTreeAppCache nodes.
scoped_nsobject<NSString> fileSize_;
- // Only set for types kCocoaCookieDetailsTypeTreeLocalStorage and
- // kCocoaCookieDetailsTypeTreeDatabase nodes.
+ // Only set for types kCocoaCookieDetailsTypeTreeLocalStorage,
+ // kCocoaCookieDetailsTypeTreeDatabase, and
+ // kCocoaCookieDetailsTypeTreeIndexedDB nodes.
scoped_nsobject<NSString> lastModified_;
// Only set for type kCocoaCookieDetailsTypeTreeAppCache nodes.
scoped_nsobject<NSString> lastAccessed_;
- // These members are only set for types kCocoaCookieDetailsTypeCookie,
- // kCocoaCookieDetailsTypePromptDatabase and
- // kCocoaCookieDetailsTypePromptLocalStorage nodes.
+ // Only set for type kCocoaCookieDetailsTypeCookie,
+ // kCocoaCookieDetailsTypePromptDatabase,
+ // kCocoaCookieDetailsTypePromptLocalStorage, and
+ // kCocoaCookieDetailsTypeTreeIndexedDB nodes.
scoped_nsobject<NSString> domain_;
- // Used only for type kCocoaCookieTreeNodeTypeDatabaseStorage and
+ // Only set for type kCocoaCookieTreeNodeTypeDatabaseStorage and
// kCocoaCookieDetailsTypePromptDatabase nodes.
scoped_nsobject<NSString> databaseDescription_;
- // Used only for type kCocoaCookieDetailsTypePromptLocalStorage.
+ // Only set for type kCocoaCookieDetailsTypePromptLocalStorage.
scoped_nsobject<NSString> localStorageKey_;
scoped_nsobject<NSString> localStorageValue_;
- // Used only for type kCocoaCookieDetailsTypeTreeAppCache and
+ // Only set for type kCocoaCookieDetailsTypeTreeAppCache and
// kCocoaCookieDetailsTypePromptAppCache.
scoped_nsobject<NSString> manifestURL_;
}
@@ -128,11 +137,12 @@ enum CocoaCookieDetailsType {
// hidden value is |true|.
- (BOOL)shouldHideCookieDetailsView;
- (BOOL)shouldShowLocalStorageTreeDetailsView;
+- (BOOL)shouldShowLocalStoragePromptDetailsView;
- (BOOL)shouldShowDatabaseTreeDetailsView;
- (BOOL)shouldShowDatabasePromptDetailsView;
-- (BOOL)shouldShowLocalStoragePromptDetailsView;
- (BOOL)shouldShowAppCachePromptDetailsView;
- (BOOL)shouldShowAppCacheTreeDetailsView;
+- (BOOL)shouldShowIndexedDBTreeDetailsView;
- (NSString*)name;
- (NSString*)content;
@@ -185,15 +195,14 @@ enum CocoaCookieDetailsType {
// for an appcache, at that time only the manifest URL of the appcache is known.
- (id)initWithAppCacheManifestURL:(const std::string&)manifestURL;
+// Used for IndexedDB details in the cookie tree.
+- (id)initWithIndexedDBInfo:
+ (const BrowsingDataIndexedDBHelper::IndexedDBInfo*)indexedDB;
+
// A factory method to create a configured instance given a node from
// the cookie tree in |treeNode|.
+ (CocoaCookieDetails*)createFromCookieTreeNode:(CookieTreeNode*)treeNode;
-// A factory method to create a configured instance given a cookie prompt
-// modal dialog in |dialog|.
-+ (CocoaCookieDetails*)createFromPromptModalDialog:
- (CookiePromptModalDialog*)dialog;
-
@end
// The subpanes of the cookie details view expect to be able to bind to methods
diff --git a/chrome/browser/cocoa/cookie_details.mm b/chrome/browser/cocoa/cookie_details.mm
index 7d625b2..4c483d1 100644
--- a/chrome/browser/cocoa/cookie_details.mm
+++ b/chrome/browser/cocoa/cookie_details.mm
@@ -8,7 +8,6 @@
#import "base/i18n/time_formatting.h"
#include "base/sys_string_conversions.h"
#include "grit/generated_resources.h"
-#include "chrome/browser/cookie_modal_dialog.h"
#include "chrome/browser/cookies_tree_model.h"
#include "webkit/appcache/appcache_service.h"
@@ -29,6 +28,10 @@
return type_ == kCocoaCookieDetailsTypeTreeLocalStorage;
}
+- (BOOL)shouldShowLocalStoragePromptDetailsView {
+ return type_ == kCocoaCookieDetailsTypePromptLocalStorage;
+}
+
- (BOOL)shouldShowDatabaseTreeDetailsView {
return type_ == kCocoaCookieDetailsTypeTreeDatabase;
}
@@ -41,14 +44,14 @@
return type_ == kCocoaCookieDetailsTypePromptDatabase;
}
-- (BOOL)shouldShowLocalStoragePromptDetailsView {
- return type_ == kCocoaCookieDetailsTypePromptLocalStorage;
-}
-
- (BOOL)shouldShowAppCachePromptDetailsView {
return type_ == kCocoaCookieDetailsTypePromptAppCache;
}
+- (BOOL)shouldShowIndexedDBTreeDetailsView {
+ return type_ == kCocoaCookieDetailsTypeTreeIndexedDB;
+}
+
- (NSString*)name {
return name_.get();
}
@@ -153,7 +156,7 @@
canEditExpiration_ = NO;
databaseDescription_.reset([base::SysUTF8ToNSString(
databaseInfo->description) retain]);
- fileSize_.reset([base::SysWideToNSString(FormatBytes(databaseInfo->size,
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(databaseInfo->size,
GetByteDisplayUnits(databaseInfo->size), true)) retain]);
lastModified_.reset([base::SysWideToNSString(
base::TimeFormatFriendlyDateAndTime(
@@ -168,7 +171,7 @@
type_ = kCocoaCookieDetailsTypeTreeLocalStorage;
canEditExpiration_ = NO;
domain_.reset([base::SysUTF8ToNSString(storageInfo->origin) retain]);
- fileSize_.reset([base::SysWideToNSString(FormatBytes(storageInfo->size,
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(storageInfo->size,
GetByteDisplayUnits(storageInfo->size), true)) retain]);
lastModified_.reset([base::SysWideToNSString(
base::TimeFormatFriendlyDateAndTime(
@@ -183,7 +186,7 @@
canEditExpiration_ = NO;
manifestURL_.reset([base::SysUTF8ToNSString(
appcacheInfo->manifest_url.spec()) retain]);
- fileSize_.reset([base::SysWideToNSString(FormatBytes(appcacheInfo->size,
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(appcacheInfo->size,
GetByteDisplayUnits(appcacheInfo->size), true)) retain]);
created_.reset([base::SysWideToNSString(
base::TimeFormatFriendlyDateAndTime(
@@ -206,7 +209,7 @@
domain_.reset([base::SysUTF8ToNSString(domain) retain]);
databaseDescription_.reset(
[base::SysUTF16ToNSString(databaseDescription) retain]);
- fileSize_.reset([base::SysWideToNSString(FormatBytes(fileSize,
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(fileSize,
GetByteDisplayUnits(fileSize), true)) retain]);
}
return self;
@@ -234,59 +237,47 @@
return self;
}
-+ (CocoaCookieDetails*)createFromCookieTreeNode:(CookieTreeNode*)treeNode {
- CookieTreeNode::DetailedInfo info = treeNode->GetDetailedInfo();
- CookieTreeNode::DetailedInfo::NodeType nodeType = info.node_type;
- if (nodeType == CookieTreeNode::DetailedInfo::TYPE_COOKIE) {
- NSString* origin = base::SysWideToNSString(info.origin.c_str());
- return [[[CocoaCookieDetails alloc] initWithCookie:info.cookie
- origin:origin
- canEditExpiration:NO] autorelease];
- } else if (nodeType == CookieTreeNode::DetailedInfo::TYPE_DATABASE) {
- return [[[CocoaCookieDetails alloc]
- initWithDatabase:info.database_info] autorelease];
- } else if (nodeType == CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE) {
- return [[[CocoaCookieDetails alloc]
- initWithLocalStorage:info.local_storage_info] autorelease];
- } else if (nodeType == CookieTreeNode::DetailedInfo::TYPE_APPCACHE) {
- return [[[CocoaCookieDetails alloc]
- initWithAppCacheInfo:info.appcache_info] autorelease];
- } else {
- return [[[CocoaCookieDetails alloc] initAsFolder] autorelease];
+- (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]);
+ name_.reset([base::SysUTF8ToNSString(indexedDBInfo->database_name) retain]);
}
+ return self;
}
-+ (CocoaCookieDetails*)createFromPromptModalDialog:(CookiePromptModalDialog*)
- dialog {
- CookiePromptModalDialog::DialogType type(dialog->dialog_type());
- CocoaCookieDetails* details = nil;
- if (type == CookiePromptModalDialog::DIALOG_TYPE_COOKIE) {
- net::CookieMonster::ParsedCookie pc(dialog->cookie_line());
- net::CookieMonster::CanonicalCookie cookie(dialog->origin(), pc);
- const std::string& domain(pc.HasDomain() ? pc.Domain() :
- dialog->origin().host());
- NSString* domainString = base::SysUTF8ToNSString(domain);
- details = [[CocoaCookieDetails alloc] initWithCookie:&cookie
- origin:domainString
- canEditExpiration:YES];
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_LOCAL_STORAGE) {
- details = [[CocoaCookieDetails alloc]
- initWithLocalStorage:dialog->origin().host()
- key:dialog->local_storage_key()
- value:dialog->local_storage_value()];
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_DATABASE) {
- details = [[CocoaCookieDetails alloc]
- initWithDatabase:dialog->origin().host()
- databaseName:dialog->database_name()
- databaseDescription:dialog->display_name()
- fileSize:dialog->estimated_size()];
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) {
- details = [[CocoaCookieDetails alloc]
- initWithAppCacheManifestURL:dialog->appcache_manifest_url().spec()];
- } else {
- NOTIMPLEMENTED();
++ (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];
}
- return [details autorelease];
}
@end
diff --git a/chrome/browser/cocoa/cookie_details_unittest.mm b/chrome/browser/cocoa/cookie_details_unittest.mm
index 9883a6a..897d92a 100644
--- a/chrome/browser/cocoa/cookie_details_unittest.mm
+++ b/chrome/browser/cocoa/cookie_details_unittest.mm
@@ -6,6 +6,7 @@
#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 {
@@ -32,19 +33,20 @@ TEST_F(CookiesDetailsTest, CreateForCookie) {
canEditExpiration:NO]);
EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeCookie);
- EXPECT_TRUE([@"PHPSESSID" isEqualToString:[details.get() name]]);
- EXPECT_TRUE([@"0123456789abcdef0123456789abcdef"
- isEqualToString:[details.get() content]]);
- EXPECT_TRUE([@"http://chromium.org" isEqualToString:[details.get() domain]]);
- EXPECT_TRUE([@"/" isEqualToString:[details.get() path]]);
- EXPECT_FALSE([@"" isEqualToString:[details.get() lastModified]]);
- EXPECT_FALSE([@"" isEqualToString:[details.get() created]]);
- EXPECT_FALSE([@"" isEqualToString:[details.get() sendFor]]);
+ 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]);
@@ -63,15 +65,15 @@ TEST_F(CookiesDetailsTest, CreateForTreeDatabase) {
details.reset([[CocoaCookieDetails alloc] initWithDatabase:&info]);
EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeDatabase);
- EXPECT_TRUE([@"a great place to climb" isEqualToString:[details.get()
- databaseDescription]]);
- EXPECT_TRUE([@"1234 B" isEqualToString:[details.get() fileSize]]);
- EXPECT_FALSE([@"" isEqualToString:[details.get() lastModified]]);
+ 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]);
@@ -84,7 +86,7 @@ TEST_F(CookiesDetailsTest, CreateForTreeLocalStorage) {
unsigned short port = 80;
std::string database_identifier("id");
std::string origin("chromium.org");
- FilePath file_path(FilePath::FromWStringHack(std::wstring(L"/")));
+ FilePath file_path(FILE_PATH_LITERAL("/"));
int64 size = 1234;
base::Time last_modified = base::Time::Now();
BrowsingDataLocalStorageHelper::LocalStorageInfo info(protocol, host, port,
@@ -92,14 +94,15 @@ TEST_F(CookiesDetailsTest, CreateForTreeLocalStorage) {
details.reset([[CocoaCookieDetails alloc] initWithLocalStorage:&info]);
EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeLocalStorage);
- EXPECT_TRUE([@"chromium.org" isEqualToString:[details.get() domain]]);
- EXPECT_TRUE([@"1234 B" isEqualToString:[details.get() fileSize]]);
- EXPECT_FALSE([@"" isEqualToString:[details.get() lastModified]]);
+ 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]);
@@ -118,16 +121,56 @@ TEST_F(CookiesDetailsTest, CreateForTreeAppCache) {
details.reset([[CocoaCookieDetails alloc] initWithAppCacheInfo:&info]);
EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeAppCache);
- EXPECT_TRUE([@"http://chromium.org/stuff.manifest"
- isEqualToString:[details.get() manifestURL]]);
- EXPECT_TRUE([@"2678 B" isEqualToString:[details.get() fileSize]]);
- EXPECT_FALSE([@"" isEqualToString:[details.get() lastAccessed]]);
- EXPECT_FALSE([@"" isEqualToString:[details.get() created]]);
+ 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");
+ std::string name("name");
+ 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,
+ name,
+ 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]);
@@ -144,15 +187,16 @@ TEST_F(CookiesDetailsTest, CreateForPromptDatabase) {
fileSize:94]);
EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptDatabase);
- EXPECT_TRUE([@"chromium.org" isEqualToString:[details.get() domain]]);
- EXPECT_TRUE([@"wicked_name" isEqualToString:[details.get() name]]);
- EXPECT_TRUE([@"desc" isEqualToString:[details.get() databaseDescription]]);
- EXPECT_TRUE([@"94 B" isEqualToString:[details.get() fileSize]]);
+ 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]);
@@ -168,14 +212,15 @@ TEST_F(CookiesDetailsTest, CreateForPromptLocalStorage) {
value:value]);
EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptLocalStorage);
- EXPECT_TRUE([@"chromium.org" isEqualToString:[details.get() domain]]);
- EXPECT_TRUE([@"testKey" isEqualToString:[details.get() localStorageKey]]);
- EXPECT_TRUE([@"testValue" isEqualToString:[details.get() localStorageValue]]);
+ 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]);
@@ -188,13 +233,14 @@ TEST_F(CookiesDetailsTest, CreateForPromptAppCache) {
initWithAppCacheManifestURL:manifestURL.c_str()]);
EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptAppCache);
- EXPECT_TRUE([@"http://html5demos.com/html5demo.manifest"
- isEqualToString:[details.get() manifestURL]]);
+ 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
index c9f9635..cad42f4 100644
--- a/chrome/browser/cocoa/cookie_details_view_controller.h
+++ b/chrome/browser/cocoa/cookie_details_view_controller.h
@@ -5,8 +5,6 @@
#import <Cocoa/Cocoa.h>
#include "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
#include "net/base/cookie_monster.h"
@class CocoaCookieTreeNode;
diff --git a/chrome/browser/cocoa/cookie_details_view_controller.mm b/chrome/browser/cocoa/cookie_details_view_controller.mm
index 01341d5..885779b 100644
--- a/chrome/browser/cocoa/cookie_details_view_controller.mm
+++ b/chrome/browser/cocoa/cookie_details_view_controller.mm
@@ -9,7 +9,6 @@
#import "base/mac_util.h"
#include "base/sys_string_conversions.h"
#import "chrome/browser/cocoa/cookie_tree_node.h"
-#import "chrome/browser/cookie_modal_dialog.h"
#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
namespace {
diff --git a/chrome/browser/cocoa/cookie_details_view_controller_unittest.mm b/chrome/browser/cocoa/cookie_details_view_controller_unittest.mm
index 76f6e56..a1df90e 100644
--- a/chrome/browser/cocoa/cookie_details_view_controller_unittest.mm
+++ b/chrome/browser/cocoa/cookie_details_view_controller_unittest.mm
@@ -6,7 +6,6 @@
#include "chrome/browser/cocoa/cocoa_test_helper.h"
#include "chrome/browser/cocoa/cookie_details.h"
#include "chrome/browser/cocoa/cookie_details_view_controller.h"
-#include "chrome/browser/cookie_modal_dialog.h"
namespace {
diff --git a/chrome/browser/cocoa/cookie_prompt_window_controller.h b/chrome/browser/cocoa/cookie_prompt_window_controller.h
deleted file mode 100644
index 6ae68b4..0000000
--- a/chrome/browser/cocoa/cookie_prompt_window_controller.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.
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-
-class CookiePromptModalDialog;
-class CookieTreeNode;
-
-@class CookieDetailsViewController;
-@class CocoaCookieTreeNode;
-
-// This class is the controller for the window displayed
-// to the user as a modal dialog prompting them to accept or
-// block new cookies and other browser data.
-@interface CookiePromptWindowController : NSWindowController {
- @private
- // Provides access to platform independent information for
- // the cookie prompt dialog.
- CookiePromptModalDialog* dialog_; // weak;
-
- // The controller managing the instances of the cookies details view
- // embedded in the prompt window.
- scoped_nsobject<CookieDetailsViewController> detailsViewController_;
-
- // The adapter object that supplies the methods expected by
- // the cookie details view.
- scoped_nsobject<NSObject> selectionAdapterObject_;
-
- // Outlets to provide quick access to subviews
- // in the prompt window.
- IBOutlet NSTextField* description_;
- IBOutlet NSView* disclosedViewPlaceholder_;
- IBOutlet NSButton* disclosureButton_;
- IBOutlet NSView* disclosureButtonSuperView_;
- IBOutlet NSMatrix* radioGroupMatrix_;
- IBOutlet NSButtonCell* rememberChoiceCell_;
-}
-
-// Designated initializer.
-- (id)initWithDialog:(CookiePromptModalDialog*)bridge;
-
-// Performs the modal dialog loop for the cookie prompt dialog
-// and processes the result.
-- (void)doModalDialog:(void*)context;
-
-// Handles the toggling of the disclosure triangle
-// to reveal cookie data
-- (IBAction)disclosureButtonPressed:(id)sender;
-
-// Callback for "block" button.
-- (IBAction)block:(id)sender;
-
-// Callback for "accept" button.
-- (IBAction)accept:(id)sender;
-
-// Processes the selection result code made in the cookie prompt.
-// Part of the public interface for the tests.
-- (void)processModalDialogResult:(void*)contextInfo
- returnCode:(int)returnCode;
-
-@end
diff --git a/chrome/browser/cocoa/cookie_prompt_window_controller.mm b/chrome/browser/cocoa/cookie_prompt_window_controller.mm
deleted file mode 100644
index 84aa661..0000000
--- a/chrome/browser/cocoa/cookie_prompt_window_controller.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.
-
-#import "chrome/browser/cocoa/cookie_prompt_window_controller.h"
-
-#include <string>
-#include <vector>
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#import "base/i18n/time_formatting.h"
-#import "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/cookie_details_view_controller.h"
-#include "chrome/browser/cocoa/cookie_tree_node.h"
-#include "chrome/browser/cookie_modal_dialog.h"
-#include "chrome/browser/cookies_tree_model.h"
-#include "grit/generated_resources.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-static const CGFloat kExtraMarginForDetailsView = 10;
-}
-
-@implementation CookiePromptWindowController
-
-- (id)initWithDialog:(CookiePromptModalDialog*)dialog {
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"CookiePrompt"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- dialog_ = dialog;
- CocoaCookieDetails* details = [CocoaCookieDetails
- createFromPromptModalDialog:dialog];
- selectionAdapterObject_.reset([[CookiePromptContentDetailsAdapter alloc]
- initWithDetails:details]);
- }
- return self;
-}
-
-// Ensures that all parameterized localized strings are filled in.
-- (void)doLocalizationTweaks {
- int descriptionStringId = 0;
- switch (dialog_->dialog_type()) {
- case CookiePromptModalDialog::DIALOG_TYPE_COOKIE:
- descriptionStringId = IDS_COOKIE_ALERT_LABEL;
- break;
- case CookiePromptModalDialog::DIALOG_TYPE_LOCAL_STORAGE:
- case CookiePromptModalDialog::DIALOG_TYPE_DATABASE:
- case CookiePromptModalDialog::DIALOG_TYPE_APPCACHE:
- descriptionStringId = IDS_DATA_ALERT_LABEL;
- break;
- default:
- NOTREACHED();
- break;
- }
-
- string16 displayHost = UTF8ToUTF16(dialog_->origin().host());
- NSString* description = l10n_util::GetNSStringF(
- descriptionStringId, displayHost);
- [description_ setStringValue:description];
-
- // Add the host to the "remember for future prompts" radio button.
- NSString* allowText = l10n_util::GetNSStringWithFixup(
- IDS_COOKIE_ALERT_REMEMBER_RADIO);
- NSString* replacedCellText = base::SysUTF16ToNSString(
- ReplaceStringPlaceholders(base::SysNSStringToUTF16(allowText),
- displayHost, NULL));
- [rememberChoiceCell_ setTitle:replacedCellText];
-}
-
-// Adjust the vertical layout of the views in the window so that
-// they are spaced correctly with their fully localized contents.
-- (void)doLayoutTweaks {
- // Wrap the description text.
- CGFloat sizeDelta = [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:description_];
- NSRect descriptionFrame = [description_ frame];
- descriptionFrame.origin.y -= sizeDelta;
- [description_ setFrame:descriptionFrame];
-
- // |wrapRadioGroupForWidth:| takes the font that is set on the
- // radio group to do the wrapping. It must be set explicitly, otherwise
- // the wrapping is based on the |NSRegularFontSize| rather than
- // |NSSmallFontSize|
- CGFloat fontSize = [NSFont systemFontSizeForControlSize:NSSmallControlSize];
- [radioGroupMatrix_ setFont:[NSFont controlContentFontOfSize:fontSize]];
-
- // Wrap the radio buttons to fit if necessary.
- [GTMUILocalizerAndLayoutTweaker
- wrapRadioGroupForWidth:radioGroupMatrix_];
- sizeDelta += [GTMUILocalizerAndLayoutTweaker
- sizeToFitView:radioGroupMatrix_].height;
- NSRect radioGroupFrame = [radioGroupMatrix_ frame];
- radioGroupFrame.origin.y -= sizeDelta;
- [radioGroupMatrix_ setFrame:radioGroupFrame];
-
- // Adjust views location, they may have moved through the
- // expansion of the radio buttons and description text.
- NSRect disclosureViewFrame = [disclosureButtonSuperView_ frame];
- disclosureViewFrame.origin.y -= sizeDelta;
- [disclosureButtonSuperView_ setFrame:disclosureViewFrame];
-
- // Adjust the final window size by the size of the cookie details
- // view, since it will be initially hidden.
- NSRect detailsViewRect = [disclosedViewPlaceholder_ frame];
- sizeDelta -= detailsViewRect.size.height;
- sizeDelta -= kExtraMarginForDetailsView;
-
- // Final resize the window to fit all of the adjustments
- NSRect frame = [[self window] frame];
- frame.origin.y -= sizeDelta;
- frame.size.height += sizeDelta;
- [[self window] setFrame:frame display:NO animate:NO];
-}
-
-- (void)replaceCookieDetailsView {
- detailsViewController_.reset([[CookieDetailsViewController alloc] init]);
-
- [detailsViewController_ setContentObject:selectionAdapterObject_.get()];
-
- [[disclosedViewPlaceholder_ superview]
- replaceSubview:disclosedViewPlaceholder_
- with:[detailsViewController_ view]];
-
- [detailsViewController_ shrinkViewToFit];
-}
-
-- (void)awakeFromNib {
- DCHECK(disclosureButton_);
- DCHECK(radioGroupMatrix_);
- DCHECK(disclosedViewPlaceholder_);
- DCHECK(disclosureButtonSuperView_);
-
- [self doLocalizationTweaks];
- [self doLayoutTweaks];
- [self replaceCookieDetailsView];
-
- [[detailsViewController_ view] setHidden:YES];
-}
-
-- (void)windowWillClose:(NSNotification*)notif {
- [self autorelease];
-}
-
-// |contextInfo| is the bridge back to the C++ CookiePromptModalDialog.
-- (void)processModalDialogResult:(void*)contextInfo
- returnCode:(int)returnCode {
- CookiePromptModalDialog* bridge =
- reinterpret_cast<CookiePromptModalDialog*>(contextInfo);
- bool remember = [radioGroupMatrix_ selectedRow] == 0;
- switch (returnCode) {
- case NSAlertFirstButtonReturn: { // OK
- bool sessionExpire = ![detailsViewController_.get() hasExpiration];
- bridge->AllowSiteData(remember, sessionExpire);
- break;
- }
- case NSAlertSecondButtonReturn: { // Cancel
- bridge->BlockSiteData(remember);
- break;
- }
- default: {
- NOTREACHED();
- remember = false;
- bridge->BlockSiteData(remember);
- }
- }
-}
-
-- (void)doModalDialog:(void*)context {
- NSInteger returnCode = [NSApp runModalForWindow:[self window]];
- [self processModalDialogResult:context returnCode:returnCode];
-}
-
-- (IBAction)disclosureButtonPressed:(id)sender {
- NSWindow* window = [self window];
- NSRect frame = [[self window] frame];
- CGFloat sizeChange = [[detailsViewController_.get() view] frame].size.height +
- kExtraMarginForDetailsView;
- switch ([sender state]) {
- case NSOnState:
- frame.size.height += sizeChange;
- frame.origin.y -= sizeChange;
- break;
- case NSOffState:
- frame.size.height -= sizeChange;
- frame.origin.y += sizeChange;
- break;
- default:
- NOTREACHED();
- break;
- }
- if ([sender state] == NSOffState) {
- [[detailsViewController_ view] setHidden:YES];
- }
- [window setFrame:frame display:YES animate:YES];
- if ([sender state] == NSOnState) {
- [[detailsViewController_ view] setHidden:NO];
- }
-}
-
-// Callback for "accept" button.
-- (IBAction)accept:(id)sender {
- [[self window] close];
- [NSApp stopModalWithCode:NSAlertFirstButtonReturn];
-}
-
-// Callback for "block" button.
-- (IBAction)block:(id)sender {
- [[self window] close];
- [NSApp stopModalWithCode:NSAlertSecondButtonReturn];
-}
-
-@end
diff --git a/chrome/browser/cocoa/cookie_prompt_window_controller_unittest.mm b/chrome/browser/cocoa/cookie_prompt_window_controller_unittest.mm
deleted file mode 100644
index 211e53a..0000000
--- a/chrome/browser/cocoa/cookie_prompt_window_controller_unittest.mm
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. 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_prompt_window_controller.h"
-#include "chrome/browser/cookie_modal_dialog.h"
-#include "chrome/test/testing_profile.h"
-
-// A mock class which implements just enough functionality to
-// act as a radio with a pre-specified selected button.
-@interface MockRadioButtonMatrix : NSObject {
- @private
- NSInteger selectedRow_;
-}
-- (NSInteger)selectedRow;
-@end
-
-@implementation MockRadioButtonMatrix
-
-- (id)initWithSelectedRow:(NSInteger)selectedRow {
- if ((self = [super init])) {
- selectedRow_ = selectedRow;
- }
- return self;
-}
-
-- (NSInteger)selectedRow {
- return selectedRow_;
-}
-@end
-
-namespace {
-
-// A subclass of the |CookiePromptModalDialog| that allows tests of
-// some of the prompt window controller's functionality without having
-// a full environment by overriding select methods and intercepting
-// calls that would otherwise rely on behavior only present in a full
-// environment.
-class CookiePromptModalDialogMock : public CookiePromptModalDialog {
- public:
- CookiePromptModalDialogMock(const GURL& origin,
- const std::string& cookieLine,
- HostContentSettingsMap* hostContentSettingsMap);
-
- virtual void AllowSiteData(bool remember, bool session_expire);
- virtual void BlockSiteData(bool remember);
-
- bool allow() const { return allow_; }
- bool remember() const { return remember_; }
-
- private:
-
- // The result of the block/unblock decision.
- bool allow_;
-
- // Whether the block/accept decision should be remembered.
- bool remember_;
-};
-
-CookiePromptModalDialogMock::CookiePromptModalDialogMock(
- const GURL& origin,
- const std::string& cookieLine,
- HostContentSettingsMap* hostContentSettingsMap)
- : CookiePromptModalDialog(NULL, hostContentSettingsMap, origin, cookieLine,
- NULL),
- allow_(false),
- remember_(false) {
-}
-
-void CookiePromptModalDialogMock::AllowSiteData(bool remember,
- bool session_expire) {
- remember_ = remember;
- allow_ = true;
-}
-
-void CookiePromptModalDialogMock::BlockSiteData(bool remember) {
- remember_ = remember;
- allow_ = false;
-}
-
-class CookiePromptWindowControllerTest : public CocoaTest {
- public:
- CookiePromptWindowControllerTest()
- : ui_thread_(ChromeThread::UI, &message_loop_) {
- hostContentSettingsMap_ = profile_.GetHostContentSettingsMap();
- }
-
- MessageLoopForUI message_loop_;
- ChromeThread ui_thread_;
- TestingProfile profile_;
- scoped_refptr<HostContentSettingsMap> hostContentSettingsMap_;
-};
-
-TEST_F(CookiePromptWindowControllerTest, CreateForCookie) {
- GURL url("http://chromium.org");
- std::string cookieLine(
- "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
- scoped_ptr<CookiePromptModalDialog> dialog(
- new CookiePromptModalDialog(NULL, hostContentSettingsMap_, url,
- cookieLine, NULL));
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:dialog.get()]);
- EXPECT_TRUE(controller.get());
- EXPECT_TRUE([controller.get() window]);
-}
-
-TEST_F(CookiePromptWindowControllerTest, CreateForDatabase) {
- GURL url("http://google.com");
- string16 databaseName(base::SysNSStringToUTF16(@"some database"));
- string16 databaseDescription(base::SysNSStringToUTF16(@"some desc"));
- scoped_ptr<CookiePromptModalDialog> dialog(
- new CookiePromptModalDialog(NULL, hostContentSettingsMap_,
- url, databaseName, databaseDescription, 3456,
- NULL));
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:dialog.get()]);
- EXPECT_TRUE(controller.get());
- EXPECT_TRUE([controller.get() window]);
-}
-
-TEST_F(CookiePromptWindowControllerTest, CreateForLocalStorage) {
- GURL url("http://chromium.org");
- string16 key(base::SysNSStringToUTF16(@"key"));
- string16 value(base::SysNSStringToUTF16(@"value"));
- scoped_ptr<CookiePromptModalDialog> dialog(
- new CookiePromptModalDialog(NULL, hostContentSettingsMap_, url, key,
- value, NULL));
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:dialog.get()]);
- EXPECT_TRUE(controller.get());
- EXPECT_TRUE([controller.get() window]);
-}
-
-TEST_F(CookiePromptWindowControllerTest, RememberMyChoiceAllow) {
- GURL url("http://chromium.org");
- std::string cookieLine(
- "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
- scoped_ptr<CookiePromptModalDialogMock> dialog(
- new CookiePromptModalDialogMock(url, cookieLine,
- hostContentSettingsMap_));
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:dialog.get()]);
- scoped_nsobject<MockRadioButtonMatrix> checkbox([[MockRadioButtonMatrix alloc]
- initWithSelectedRow:0]);
- [controller.get() setValue:checkbox.get() forKey:@"radioGroupMatrix_"];
-
- [controller.get() processModalDialogResult:dialog.get()
- returnCode:NSAlertFirstButtonReturn];
-
- // Need to make sure that the retainCount for the mock radio button
- // goes back down to 1--the controller won't do it for us. And
- // even calling setValue:forKey: again with a nil doesn't
- // decrement it. Ugly, but otherwise valgrind complains.
- [checkbox.get() release];
-
- EXPECT_TRUE(dialog->remember());
- EXPECT_TRUE(dialog->allow());
-}
-
-TEST_F(CookiePromptWindowControllerTest, RememberMyChoiceBlock) {
- GURL url("http://codereview.chromium.org");
- std::string cookieLine(
- "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
- scoped_ptr<CookiePromptModalDialogMock> dialog(
- new CookiePromptModalDialogMock(url, cookieLine,
- hostContentSettingsMap_));
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:dialog.get()]);
- scoped_nsobject<MockRadioButtonMatrix> checkbox([[MockRadioButtonMatrix alloc]
- initWithSelectedRow:0]);
- [controller.get() setValue:checkbox.get() forKey:@"radioGroupMatrix_"];
-
- [controller.get() processModalDialogResult:dialog.get()
- returnCode:NSAlertSecondButtonReturn];
-
- // Need to make sure that the retainCount for the mock radio button
- // goes back down to 1--the controller won't do it for us. And
- // even calling setValue:forKey: again with nil doesn't
- // decrement it. Ugly, but otherwise valgrind complains.
- [checkbox.get() release];
-
- EXPECT_TRUE(dialog->remember());
- EXPECT_FALSE(dialog->allow());
-}
-
-TEST_F(CookiePromptWindowControllerTest, DontRememberMyChoiceAllow) {
- GURL url("http://chromium.org");
- std::string cookieLine(
- "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
- scoped_ptr<CookiePromptModalDialogMock> dialog(
- new CookiePromptModalDialogMock(url, cookieLine,
- hostContentSettingsMap_));
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:dialog.get()]);
- scoped_nsobject<MockRadioButtonMatrix> checkbox([[MockRadioButtonMatrix alloc]
- initWithSelectedRow:1]);
- [controller.get() setValue:checkbox.get() forKey:@"radioGroupMatrix_"];
-
- [controller.get() processModalDialogResult:dialog.get()
- returnCode:NSAlertFirstButtonReturn];
-
- // Need to make sure that the retainCount for the mock radio button
- // goes back down to 1--the controller won't do it for us. And
- // even calling setValue:forKey: again with a nil doesn't
- // decrement it. Ugly, but otherwise valgrind complains.
- [checkbox.get() release];
-
- EXPECT_FALSE(dialog->remember());
- EXPECT_TRUE(dialog->allow());
-}
-
-TEST_F(CookiePromptWindowControllerTest, DontRememberMyChoiceBlock) {
- GURL url("http://codereview.chromium.org");
- std::string cookieLine(
- "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
- scoped_ptr<CookiePromptModalDialogMock> dialog(
- new CookiePromptModalDialogMock(url, cookieLine,
- hostContentSettingsMap_));
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:dialog.get()]);
- scoped_nsobject<MockRadioButtonMatrix> checkbox([[MockRadioButtonMatrix alloc]
- initWithSelectedRow:1]);
- [controller.get() setValue:checkbox.get() forKey:@"radioGroupMatrix_"];
-
- [controller.get() processModalDialogResult:dialog.get()
- returnCode:NSAlertSecondButtonReturn];
-
- // Need to make sure that the retainCount for the mock radio button
- // goes back down to 1--the controller won't do it for us. And
- // even calling setValue:forKey: again with a nil doesn't
- // decrement it. Ugly, but otherwise valgrind complains.
- [checkbox.get() release];
-
- EXPECT_FALSE(dialog->remember());
- EXPECT_FALSE(dialog->allow());
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/cookie_tree_node.mm b/chrome/browser/cocoa/cookie_tree_node.mm
index 553a7bb..4b0dd6f 100644
--- a/chrome/browser/cocoa/cookie_tree_node.mm
+++ b/chrome/browser/cocoa/cookie_tree_node.mm
@@ -18,7 +18,7 @@
}
- (void)rebuild {
- title_.reset([base::SysWideToNSString(treeNode_->GetTitle()) retain]);
+ title_.reset([base::SysUTF16ToNSString(treeNode_->GetTitle()) retain]);
children_.reset();
// The tree node assumes ownership of the cookie details object
details_.reset([[CocoaCookieDetails createFromCookieTreeNode:(treeNode_)]
diff --git a/chrome/browser/cocoa/cookies_window_controller.h b/chrome/browser/cocoa/cookies_window_controller.h
index 2ebe4d0..0f2098b 100644
--- a/chrome/browser/cocoa/cookies_window_controller.h
+++ b/chrome/browser/cocoa/cookies_window_controller.h
@@ -4,7 +4,6 @@
#import <Cocoa/Cocoa.h>
-#include "app/tree_model.h"
#include "base/cocoa_protocols_mac.h"
#include "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
@@ -15,6 +14,8 @@
@class CookiesWindowController;
@class CookieDetailsViewController;
class Profile;
+class TreeModel;
+class TreeModelNode;
namespace {
class CookiesWindowControllerTest;
@@ -26,25 +27,17 @@ class CookiesTreeModelObserverBridge : public CookiesTreeModel::Observer {
public:
explicit CookiesTreeModelObserverBridge(CookiesWindowController* controller);
- // Notification that nodes were added to the specified parent.
+ // Begin TreeModelObserver implementation.
virtual void TreeNodesAdded(TreeModel* model,
TreeModelNode* parent,
int start,
int count);
-
- // Notification that nodes were removed from the specified parent.
virtual void TreeNodesRemoved(TreeModel* model,
TreeModelNode* parent,
int start,
int count);
-
- // Notification the children of |parent| have been reordered. Note, only
- // the direct children of |parent| have been reordered, not descendants.
- virtual void TreeNodeChildrenReordered(TreeModel* model,
- TreeModelNode* parent);
-
- // Notification that the contents of a node has changed.
virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node);
+ // End TreeModelObserver implementation.
virtual void TreeModelBeginBatch(CookiesTreeModel* model);
virtual void TreeModelEndBatch(CookiesTreeModel* model);
@@ -110,6 +103,7 @@ class CookiesTreeModelObserverBridge : public CookiesTreeModel::Observer {
BrowsingDataDatabaseHelper* databaseHelper_; // weak
BrowsingDataLocalStorageHelper* storageHelper_; // weak
BrowsingDataAppCacheHelper* appcacheHelper_; // weak
+ BrowsingDataIndexedDBHelper* indexedDBHelper_; // weak
}
@property (assign, nonatomic) BOOL removeButtonEnabled;
@property (readonly, nonatomic) NSTreeController* treeController;
@@ -118,7 +112,8 @@ class CookiesTreeModelObserverBridge : public CookiesTreeModel::Observer {
- (id)initWithProfile:(Profile*)profile
databaseHelper:(BrowsingDataDatabaseHelper*)databaseHelper
storageHelper:(BrowsingDataLocalStorageHelper*)storageHelper
- appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper;
+ appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper
+ indexedDBHelper:(BrowsingDataIndexedDBHelper*)indexedDBHelper;
// Shows the cookies window as a modal sheet attached to |window|.
- (void)attachSheetTo:(NSWindow*)window;
diff --git a/chrome/browser/cocoa/cookies_window_controller.mm b/chrome/browser/cocoa/cookies_window_controller.mm
index 75a8ab7..453c216 100644
--- a/chrome/browser/cocoa/cookies_window_controller.mm
+++ b/chrome/browser/cocoa/cookies_window_controller.mm
@@ -9,7 +9,6 @@
#include "app/l10n_util_mac.h"
#include "app/resource_bundle.h"
-#import "base/i18n/time_formatting.h"
#import "base/mac_util.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/browsing_data_remover.h"
@@ -71,35 +70,6 @@ void CookiesTreeModelObserverBridge::TreeNodesRemoved(TreeModel* model,
[window_controller_ didChangeValueForKey:kCocoaTreeModel];
}
-// Notification the children of |parent| have been reordered. Note, only
-// the direct children of |parent| have been reordered, not descendants.
-void CookiesTreeModelObserverBridge::TreeNodeChildrenReordered(TreeModel* model,
- TreeModelNode* parent) {
- // 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];
-
- CookieTreeNode* cookie_parent = static_cast<CookieTreeNode*>(parent);
- const int child_count = cookie_parent->GetChildCount();
-
- [window_controller_ willChangeValueForKey:kCocoaTreeModel];
- for (int i = 0; i < child_count; ++i) {
- CookieTreeNode* swap_in = cookie_parent->GetChild(i);
- for (int j = i; j < child_count; ++j) {
- CocoaCookieTreeNode* child = [cocoa_children objectAtIndex:j];
- TreeModelNode* swap_out = [child treeNode];
- if (swap_in == swap_out) {
- [cocoa_children exchangeObjectAtIndex:j withObjectAtIndex:i];
- break;
- }
- }
- }
- [window_controller_ didChangeValueForKey:kCocoaTreeModel];
-}
-
// Notification that the contents of a node has changed.
void CookiesTreeModelObserverBridge::TreeNodeChanged(TreeModel* model,
TreeModelNode* node) {
@@ -195,7 +165,8 @@ bool CookiesTreeModelObserverBridge::HasCocoaModel() {
- (id)initWithProfile:(Profile*)profile
databaseHelper:(BrowsingDataDatabaseHelper*)databaseHelper
storageHelper:(BrowsingDataLocalStorageHelper*)storageHelper
- appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper {
+ appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper
+ indexedDBHelper:(BrowsingDataIndexedDBHelper*)indexedDBHelper {
DCHECK(profile);
NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"Cookies"
ofType:@"nib"];
@@ -204,6 +175,7 @@ bool CookiesTreeModelObserverBridge::HasCocoaModel() {
databaseHelper_ = databaseHelper;
storageHelper_ = storageHelper;
appcacheHelper_ = appcacheHelper;
+ indexedDBHelper_ = indexedDBHelper;
[self loadTreeModelFromProfile];
@@ -444,7 +416,11 @@ bool CookiesTreeModelObserverBridge::HasCocoaModel() {
- (void)loadTreeModelFromProfile {
treeModel_.reset(new CookiesTreeModel(
profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(),
- databaseHelper_, storageHelper_, appcacheHelper_));
+ databaseHelper_,
+ storageHelper_,
+ NULL,
+ appcacheHelper_,
+ indexedDBHelper_));
modelObserver_.reset(new CookiesTreeModelObserverBridge(self));
treeModel_->AddObserver(modelObserver_.get());
diff --git a/chrome/browser/cocoa/cookies_window_controller_unittest.mm b/chrome/browser/cocoa/cookies_window_controller_unittest.mm
index 48f4a0e..7b63243 100644
--- a/chrome/browser/cocoa/cookies_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/cookies_window_controller_unittest.mm
@@ -8,6 +8,7 @@
#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"
@@ -24,6 +25,7 @@
#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"
@@ -137,21 +139,21 @@ TEST_F(CookiesWindowControllerTest, FindCocoaNodeRecursive) {
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);
+ 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_TRUE([@"B" isEqualToString:[details content]]);
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_COOKIE_EXPIRES_SESSION)
- isEqualToString:[details expires]]);
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_COOKIE_SENDFOR_ANY)
- isEqualToString:[details sendFor]]);
- EXPECT_TRUE([@"A" isEqualToString:[cookie title]]);
- EXPECT_TRUE([@"A" isEqualToString:[details name]]);
- EXPECT_TRUE([@"/" isEqualToString:[details path]]);
+ 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]);
@@ -161,7 +163,7 @@ TEST_F(CookiesWindowControllerTest, CocoaNodeFromTreeNodeCookie) {
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);
+ 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);
@@ -170,30 +172,29 @@ TEST_F(CookiesWindowControllerTest, CocoaNodeFromTreeNodeRecursive) {
CocoaCookieTreeNode* cookie = [[cookies children] objectAtIndex:0];
// Test domain-level node.
- EXPECT_TRUE([@"foo.com" isEqualToString:[domain title]]);
+ 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_TRUE([l10n_util::GetNSString(IDS_COOKIES_COOKIES) isEqualToString:
- [cookies title]]);
+ 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_TRUE([@"B" isEqualToString:[details content]]);
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_COOKIE_EXPIRES_SESSION)
- isEqualToString:[details expires]]);
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_COOKIE_SENDFOR_ANY)
- isEqualToString:[details sendFor]]);
- EXPECT_TRUE([@"A" isEqualToString:[cookie title]]);
- EXPECT_TRUE([@"A" isEqualToString:[details name]]);
- EXPECT_TRUE([@"/" isEqualToString:[details path]]);
- EXPECT_TRUE([@"foo.com" isEqualToString:[details domain]]);
+ 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]);
@@ -272,57 +273,7 @@ TEST_F(CookiesWindowControllerTest, TreeNodesRemoved) {
EXPECT_EQ(1U, [cocoa_children count]);
NSString* title = [[[cocoa_children objectAtIndex:0] details] name];
- EXPECT_TRUE([@"A" isEqualToString:title]);
-}
-
-TEST_F(CookiesWindowControllerTest, TreeNodeChildrenReordered) {
- 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]);
-
- // Check default ordering.
- CocoaCookieTreeNode* node = [cocoa_children objectAtIndex:0];
- EXPECT_TRUE([@"A" isEqualToString:[[node details] name]]);
- node = [cocoa_children objectAtIndex:1];
- EXPECT_TRUE([@"C" isEqualToString:[[node details] name]]);
- node = [cocoa_children objectAtIndex:2];
- EXPECT_TRUE([@"E" isEqualToString:[[node details] name]]);
-
- CookiesTreeModel* model = [controller_ treeModel];
- // Root --> foo.com --> Cookies.
- CookieTreeNode* parent = model->GetRoot()->GetChild(0)->GetChild(0);
-
- // Reorder the nodes.
- CookieTreeNode* node_e = parent->Remove(2);
- CookieTreeNode* node_c = parent->Remove(1);
- parent->Add(0, node_e);
- parent->Add(2, node_c);
-
- // Notify the observer of the reordering.
- [controller_ modelObserver]->TreeNodeChildrenReordered(model, parent);
-
- // Check the new order.
- node = [cocoa_children objectAtIndex:0];
- EXPECT_TRUE([@"E" isEqualToString:[[node details] name]]);
- node = [cocoa_children objectAtIndex:1];
- EXPECT_TRUE([@"A" isEqualToString:[[node details] name]]);
- node = [cocoa_children objectAtIndex:2];
- EXPECT_TRUE([@"C" isEqualToString:[[node details] name]]);
+ EXPECT_NSEQ(@"A", title);
}
TEST_F(CookiesWindowControllerTest, TreeNodeChanged) {
@@ -346,16 +297,16 @@ TEST_F(CookiesWindowControllerTest, TreeNodeChanged) {
[[[[[controller_ cocoaTreeModel] children] objectAtIndex:0]
children] objectAtIndex:0];
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_COOKIES) isEqualToString:
- [cocoa_node title]]);
+ 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(L"Silly Change");
+ node->SetTitle(ASCIIToUTF16("Silly Change"));
[controller_ modelObserver]->TreeNodeChanged(model, node);
- EXPECT_TRUE([@"Silly Change" isEqualToString:[cocoa_node title]]);
+ EXPECT_NSEQ(@"Silly Change", [cocoa_node title]);
}
TEST_F(CookiesWindowControllerTest, DeleteCookie) {
@@ -388,8 +339,8 @@ TEST_F(CookiesWindowControllerTest, DeleteCookie) {
NSArray* cookies = [[[[[[controller cocoaTreeModel] children]
objectAtIndex:0] children] objectAtIndex:0] children];
EXPECT_EQ(1U, [cookies count]);
- EXPECT_TRUE([@"C" isEqualToString:[[cookies lastObject] title]]);
- EXPECT_TRUE([indexPath isEqual:[treeController selectionIndexPath]]);
+ EXPECT_NSEQ(@"C", [[cookies lastObject] title]);
+ EXPECT_NSEQ(indexPath, [treeController selectionIndexPath]);
// Select cookie E.
NSUInteger pathE[3] = {1, 0, 0};
@@ -631,46 +582,44 @@ TEST_F(CookiesWindowControllerTest, CreateDatabaseStorageNodes) {
// Root --> gdbhost1.
CocoaCookieTreeNode* node =
[[[controller_ cocoaTreeModel] children] objectAtIndex:0];
- EXPECT_TRUE([@"gdbhost1" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"gdbhost1", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
EXPECT_EQ(1U, [[node children] count]);
// host1 --> Web Databases.
node = [[node children] lastObject];
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_WEB_DATABASES)
- isEqualToString:[node title]]);
+ 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_TRUE([@"db1" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"db1", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeTreeDatabase, [node nodeType]);
CocoaCookieDetails* details = [node details];
- EXPECT_TRUE([@"description 1" isEqualToString:[details databaseDescription]]);
+ EXPECT_NSEQ(@"description 1", [details databaseDescription]);
EXPECT_TRUE([details lastModified]);
EXPECT_TRUE([details fileSize]);
// Root --> gdbhost2.
node =
[[[controller_ cocoaTreeModel] children] objectAtIndex:1];
- EXPECT_TRUE([@"gdbhost2" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"gdbhost2", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
EXPECT_EQ(1U, [[node children] count]);
// host1 --> Web Databases.
node = [[node children] lastObject];
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_WEB_DATABASES)
- isEqualToString:[node title]]);
+ 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_TRUE([@"db2" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"db2", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeTreeDatabase, [node nodeType]);
details = [node details];
- EXPECT_TRUE([@"description 2" isEqualToString:[details databaseDescription]]);
+ EXPECT_NSEQ(@"description 2", [details databaseDescription]);
EXPECT_TRUE([details lastModified]);
EXPECT_TRUE([details fileSize]);
}
@@ -695,44 +644,42 @@ TEST_F(CookiesWindowControllerTest, CreateLocalStorageNodes) {
// Root --> host1.
CocoaCookieTreeNode* node =
[[[controller_ cocoaTreeModel] children] objectAtIndex:2];
- EXPECT_TRUE([@"host1" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"host1", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
EXPECT_EQ(1U, [[node children] count]);
// host1 --> Local Storage.
node = [[node children] lastObject];
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_LOCAL_STORAGE)
- isEqualToString:[node title]]);
+ 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_TRUE([@"http://host1:1/" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"http://host1:1/", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeTreeLocalStorage, [node nodeType]);
- EXPECT_TRUE([@"http://host1:1/" isEqualToString:[[node details] domain]]);
+ 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_TRUE([@"host2" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"host2", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
EXPECT_EQ(1U, [[node children] count]);
// host2 --> Local Storage.
node = [[node children] lastObject];
- EXPECT_TRUE([l10n_util::GetNSString(IDS_COOKIES_LOCAL_STORAGE)
- isEqualToString:[node title]]);
+ 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_TRUE([@"http://host2:2/" isEqualToString:[node title]]);
+ EXPECT_NSEQ(@"http://host2:2/", [node title]);
EXPECT_EQ(kCocoaCookieDetailsTypeTreeLocalStorage, [node nodeType]);
- EXPECT_TRUE([@"http://host2:2/" isEqualToString:[[node details] domain]]);
+ EXPECT_NSEQ(@"http://host2:2/", [[node details] domain]);
EXPECT_TRUE([[node details] lastModified]);
EXPECT_TRUE([[node details] fileSize]);
}
diff --git a/chrome/browser/cocoa/custom_home_pages_model.h b/chrome/browser/cocoa/custom_home_pages_model.h
index 98ae8ba..962bc79 100644
--- a/chrome/browser/cocoa/custom_home_pages_model.h
+++ b/chrome/browser/cocoa/custom_home_pages_model.h
@@ -1,14 +1,16 @@
-// 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.
#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;
@@ -35,6 +37,10 @@ class Profile;
- (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.
@@ -47,11 +53,31 @@ class Profile;
- (void)removeObjectFromCustomHomePagesAtIndex:(NSUInteger)index;
@end
-@interface CustomHomePagesModel(InternalOrTestingAPI)
+////////////////////////////////////////////////////////////////////////////////
+
+// 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;
+- (void)setURLStringEmptyAt:(NSUInteger)index;
@end
diff --git a/chrome/browser/cocoa/custom_home_pages_model.mm b/chrome/browser/cocoa/custom_home_pages_model.mm
index 084cf11..692150d 100644
--- a/chrome/browser/cocoa/custom_home_pages_model.mm
+++ b/chrome/browser/cocoa/custom_home_pages_model.mm
@@ -5,29 +5,16 @@
#import "chrome/browser/cocoa/custom_home_pages_model.h"
#include "base/sys_string_conversions.h"
-#include "chrome/browser/history/history.h"
#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
NSString* const kHomepageEntryChangedNotification =
@"kHomepageEntryChangedNotification";
-// 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;
+@interface CustomHomePagesModel (Private)
+- (void)setURLsInternal:(const std::vector<GURL>&)urls;
@end
-//----------------------------------------------------------------------------
-
-
@implementation CustomHomePagesModel
- (id)initWithProfile:(Profile*)profile {
@@ -52,6 +39,8 @@ NSString* const kHomepageEntryChangedNotification =
- (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
@@ -70,6 +59,15 @@ NSString* const kHomepageEntryChangedNotification =
- (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(
@@ -81,6 +79,12 @@ NSString* const kHomepageEntryChangedNotification =
[entries_ addObject:entry];
}
}
+}
+
+- (void)reloadURLs {
+ [self willChangeValueForKey:@"customHomePages"];
+ SessionStartupPref pref(SessionStartupPref::GetStartupPref(profile_));
+ [self setURLsInternal:pref.urls];
[self didChangeValueForKey:@"customHomePages"];
}
@@ -129,4 +133,8 @@ NSString* const kHomepageEntryChangedNotification =
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
index 3d7a32b..534f681 100644
--- a/chrome/browser/cocoa/custom_home_pages_model_unittest.mm
+++ b/chrome/browser/cocoa/custom_home_pages_model_unittest.mm
@@ -1,11 +1,13 @@
-// 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.
#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
@@ -29,6 +31,24 @@
}
@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() {
@@ -78,9 +98,9 @@ TEST_F(CustomHomePagesModelTest, KVOObserveWhenListChanges) {
scoped_nsobject<CustomHomePageHelper> kvo_helper(
[[CustomHomePageHelper alloc] init]);
[model_ addObserver:kvo_helper
- forKeyPath:@"customHomePages"
- options:0L
- context:NULL];
+ forKeyPath:@"customHomePages"
+ options:0L
+ context:NULL];
EXPECT_FALSE(kvo_helper.get()->sawNotification_);
std::vector<GURL> urls;
@@ -99,38 +119,35 @@ TEST_F(CustomHomePagesModelTest, KVO) {
scoped_nsobject<CustomHomePageHelper> kvo_helper(
[[CustomHomePageHelper alloc] init]);
[model_ addObserver:kvo_helper
- forKeyPath:@"customHomePages"
- options:0L
- context:NULL];
+ 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:@"www.google.com" inCustomHomePagesAtIndex:0];
+ [model_ insertObject:MakeEntry(@"www.google.com") inCustomHomePagesAtIndex:0];
EXPECT_TRUE(kvo_helper.get()->sawNotification_);
- [model_ insertObject:@"www.yahoo.com" inCustomHomePagesAtIndex:1];
- [model_ insertObject:@"dev.chromium.org" inCustomHomePagesAtIndex:2];
+ [model_ insertObject:MakeEntry(@"www.yahoo.com") inCustomHomePagesAtIndex:1];
+ [model_ insertObject:MakeEntry(@"dev.chromium.org")
+ inCustomHomePagesAtIndex:2];
EXPECT_EQ([model_ countOfCustomHomePages], 3U);
- EXPECT_TRUE([[model_ objectInCustomHomePagesAtIndex:1]
- isEqualToString:@"www.yahoo.com"]);
+ 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_TRUE([[model_ objectInCustomHomePagesAtIndex:1]
- isEqualToString:@"dev.chromium.org"]);
- EXPECT_TRUE([[model_ objectInCustomHomePagesAtIndex:0]
- isEqualToString:@"www.google.com"]);
+ 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"];
}
-@interface NSObject()
-- (void)setURL:(NSString*)url;
-@end
-
// Test that when individual items are changed that they broadcast a message.
TEST_F(CustomHomePagesModelTest, ModelChangedNotification) {
scoped_nsobject<CustomHomePageHelper> kvo_helper(
@@ -149,3 +166,31 @@ TEST_F(CustomHomePagesModelTest, ModelChangedNotification) {
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
index 45cc856..f626f71 100644
--- a/chrome/browser/cocoa/delayedmenu_button.h
+++ b/chrome/browser/cocoa/delayedmenu_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_DELAYEDMENU_BUTTON_H_
#define CHROME_BROWSER_COCOA_DELAYEDMENU_BUTTON_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/download_item_cell.h b/chrome/browser/cocoa/download_item_cell.h
index 484abab..54d745b 100644
--- a/chrome/browser/cocoa/download_item_cell.h
+++ b/chrome/browser/cocoa/download_item_cell.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_ITEM_CELL_H_
#define CHROME_BROWSER_COCOA_DOWNLOAD_ITEM_CELL_H_
+#pragma once
#import "base/cocoa_protocols_mac.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/cocoa/download_item_cell.mm b/chrome/browser/cocoa/download_item_cell.mm
index 8ae9fd9..93687f4 100644
--- a/chrome/browser/cocoa/download_item_cell.mm
+++ b/chrome/browser/cocoa/download_item_cell.mm
@@ -8,7 +8,6 @@
#include "app/text_elider.h"
#include "base/mac_util.h"
#include "base/sys_string_conversions.h"
-#import "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/download_item_cell.h"
#import "chrome/browser/cocoa/image_utils.h"
#import "chrome/browser/cocoa/themed_window.h"
@@ -16,6 +15,7 @@
#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"
@@ -395,19 +395,17 @@ NSGradient* BackgroundTheme::GetNSGradient(int id) const {
- (NSString*)elideTitle:(int)availableWidth {
NSFont* font = [self font];
- gfx::Font font_chr =
- gfx::Font::CreateFont(base::SysNSStringToWide([font fontName]),
- [font pointSize]);
+ gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
- return base::SysWideToNSString(
+ return base::SysUTF16ToNSString(
ElideFilename(downloadPath_, font_chr, availableWidth));
}
- (NSString*)elideStatus:(int)availableWidth {
NSFont* font = [self secondaryFont];
- gfx::Font font_chr =
- gfx::Font::CreateFont(base::SysNSStringToWide([font fontName]),
- [font pointSize]);
+ gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
return base::SysWideToNSString(ElideText(
base::SysNSStringToWide([self secondaryTitle]),
diff --git a/chrome/browser/cocoa/download_item_controller.mm b/chrome/browser/cocoa/download_item_controller.mm
index 00e2110..cbd18fc 100644
--- a/chrome/browser/cocoa/download_item_controller.mm
+++ b/chrome/browser/cocoa/download_item_controller.mm
@@ -9,9 +9,10 @@
#include "app/text_elider.h"
#include "base/histogram.h"
#include "base/mac_util.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/browser_theme_provider.h"
#import "chrome/browser/cocoa/download_item_button.h"
#import "chrome/browser/cocoa/download_item_cell.h"
#include "chrome/browser/cocoa/download_item_mac.h"
@@ -22,6 +23,7 @@
#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"
@@ -243,11 +245,14 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
}
- (IBAction)handleButtonClick:(id)sender {
- DownloadItem* download = bridge_->download_model()->download();
- if (download->state() == DownloadItem::IN_PROGRESS)
- download->set_open_when_complete(!download->open_when_complete());
- else if (download->state() == DownloadItem::COMPLETE)
- download_util::OpenDownload(download);
+ 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 {
@@ -262,10 +267,10 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
}
- (void)updateToolTip {
- std::wstring elidedFilename = gfx::ElideFilename(
+ string16 elidedFilename = gfx::ElideFilename(
[self download]->GetFileName(),
gfx::Font(), kToolTipMaxWidth);
- [progressView_ setToolTip:base::SysWideToNSString(elidedFilename)];
+ [progressView_ setToolTip:base::SysUTF16ToNSString(elidedFilename)];
}
- (void)clearDangerousMode {
@@ -318,8 +323,7 @@ class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
base::Time::Now() - creationTime_);
// This will change the state and notify us.
- bridge_->download_model()->download()->manager()->DangerousDownloadValidated(
- bridge_->download_model()->download());
+ bridge_->download_model()->download()->DangerousDownloadValidated();
}
- (IBAction)discardDownload:(id)sender {
diff --git a/chrome/browser/cocoa/download_item_mac.h b/chrome/browser/cocoa/download_item_mac.h
index 91a8702..7c2555d 100644
--- a/chrome/browser/cocoa/download_item_mac.h
+++ b/chrome/browser/cocoa/download_item_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_ITEM_MAC_H_
#define CHROME_BROWSER_COCOA_DOWNLOAD_ITEM_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/download_shelf_controller.mm b/chrome/browser/cocoa/download_shelf_controller.mm
index 7fa1bf9..715fcfa 100644
--- a/chrome/browser/cocoa/download_shelf_controller.mm
+++ b/chrome/browser/cocoa/download_shelf_controller.mm
@@ -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,10 +9,9 @@
#include "base/mac_util.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/animatable_view.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
#include "chrome/browser/cocoa/browser_window_cocoa.h"
+#import "chrome/browser/cocoa/browser_window_controller.h"
#include "chrome/browser/cocoa/download_item_controller.h"
#include "chrome/browser/cocoa/download_shelf_mac.h"
#import "chrome/browser/cocoa/download_shelf_view.h"
@@ -20,6 +19,7 @@
#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 "grit/generated_resources.h"
#include "grit/theme_resources.h"
#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
diff --git a/chrome/browser/cocoa/download_shelf_mac.h b/chrome/browser/cocoa/download_shelf_mac.h
index 2e09988..462b38f 100644
--- a/chrome/browser/cocoa/download_shelf_mac.h
+++ b/chrome/browser/cocoa/download_shelf_mac.h
@@ -1,15 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_SHELF_MAC_H_
#define CHROME_BROWSER_COCOA_DOWNLOAD_SHELF_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
-#include <vector>
-
-#include "base/scoped_ptr.h"
#include "chrome/browser/download/download_shelf.h"
class BaseDownloadItemModel;
diff --git a/chrome/browser/cocoa/download_shelf_view.h b/chrome/browser/cocoa/download_shelf_view.h
index 5b05dd6..c125fdf 100644
--- a/chrome/browser/cocoa/download_shelf_view.h
+++ b/chrome/browser/cocoa/download_shelf_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_SHELF_VIEW_H_
#define CHROME_BROWSER_COCOA_SHELF_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/download_shelf_view.mm b/chrome/browser/cocoa/download_shelf_view.mm
index bd43cf5..b382037 100644
--- a/chrome/browser/cocoa/download_shelf_view.mm
+++ b/chrome/browser/cocoa/download_shelf_view.mm
@@ -5,9 +5,9 @@
#import "chrome/browser/cocoa/download_shelf_view.h"
#include "base/scoped_nsobject.h"
-#include "chrome/browser/browser_theme_provider.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
diff --git a/chrome/browser/cocoa/download_started_animation_mac.mm b/chrome/browser/cocoa/download_started_animation_mac.mm
index f756bb0..0ff5ef9 100644
--- a/chrome/browser/cocoa/download_started_animation_mac.mm
+++ b/chrome/browser/cocoa/download_started_animation_mac.mm
@@ -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.
//
@@ -35,8 +35,9 @@ class DownloadAnimationTabObserver;
};
+ (void)startAnimationWithTabContents:(TabContents*)tabContents;
-// Called by our DownloadAnimationTabObserver if the tab is hidden or closed.
-- (void)animationComplete;
+
+// Called by the Observer if the tab is hidden or closed.
+- (void)closeAnimation;
@end
@@ -62,7 +63,7 @@ class DownloadAnimationTabObserver : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details) {
// This ends up deleting us.
- [owner_ animationComplete];
+ [owner_ closeAnimation];
}
private:
@@ -162,21 +163,26 @@ class DownloadAnimationTabObserver : public NotificationObserver {
[animation_ setFrame:frame display:YES];
}
-- (void)windowWillClose:(NSNotification*)notification {
- DCHECK([[notification object] isEqual:animation_]);
- [self animationComplete];
+- (void)closeAnimation {
+ [animation_ close];
}
-- (void)animationComplete {
+// 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 is complete in -animationComplete.
+ // Will be deleted when the animation window closes.
DownloadStartedAnimationMac* controller =
[[self alloc] initWithTabContents:contents];
- // The |animation_| releaes itself when done.
+ // The initializer can return nil.
+ if (!controller)
+ return;
+
+ // The |animation_| releases itself when done.
[controller->animation_ startAnimation];
}
diff --git a/chrome/browser/cocoa/download_util_mac.h b/chrome/browser/cocoa/download_util_mac.h
index b623d71..f71810f 100644
--- a/chrome/browser/cocoa/download_util_mac.h
+++ b/chrome/browser/cocoa/download_util_mac.h
@@ -1,12 +1,16 @@
-// 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.
//
// Download utility functions for Mac OS X.
+#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_UTIL_MAC_H_
+#define CHROME_BROWSER_COCOA_DOWNLOAD_UTIL_MAC_H_
+#pragma once
+
#import <Cocoa/Cocoa.h>
-#include "base/file_path.h"
+class FilePath;
namespace download_util {
@@ -17,3 +21,5 @@ void AddFileToPasteboard(NSPasteboard* pasteboard, const FilePath& path);
void NotifySystemOfDownloadComplete(const FilePath& path);
} // namespace download_util
+
+#endif // CHROME_BROWSER_COCOA_DOWNLOAD_UTIL_MAC_H_
diff --git a/chrome/browser/cocoa/download_util_mac_unittest.mm b/chrome/browser/cocoa/download_util_mac_unittest.mm
index 8a3a90c..88d6097 100644
--- a/chrome/browser/cocoa/download_util_mac_unittest.mm
+++ b/chrome/browser/cocoa/download_util_mac_unittest.mm
@@ -10,17 +10,18 @@
#import "chrome/browser/cocoa/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 DownloadUtilTest : public CocoaTest {
+class DownloadUtilMacTest : public CocoaTest {
public:
- DownloadUtilTest() {
+ DownloadUtilMacTest() {
pasteboard_ = [NSPasteboard pasteboardWithUniqueName];
}
- virtual ~DownloadUtilTest() {
+ virtual ~DownloadUtilMacTest() {
[pasteboard_ releaseGlobally];
}
@@ -31,7 +32,7 @@ class DownloadUtilTest : public CocoaTest {
};
// Ensure adding files to the pasteboard methods works as expected.
-TEST_F(DownloadUtilTest, AddFileToPasteboardTest) {
+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));
@@ -51,7 +52,7 @@ TEST_F(DownloadUtilTest, AddFileToPasteboardTest) {
ASSERT_TRUE(files != nil);
NSString* expectedPath = [files objectAtIndex:0];
NSString* realPath = base::SysWideToNSString(testPath.ToWStringHack());
- EXPECT_TRUE([expectedPath isEqualToString:realPath]);
+ EXPECT_NSEQ(expectedPath, realPath);
}
} // namespace
diff --git a/chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm b/chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm
index dcb97ed..8ddff56 100644
--- a/chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm
+++ b/chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm
@@ -6,9 +6,11 @@
#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_model.h"
+#include "chrome/browser/search_engines/template_url.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -119,8 +121,8 @@ void ShiftOriginY(NSView* view, CGFloat amount) {
- (IBAction)save:(id)sender {
DCHECK([self validateFields]);
- std::wstring title = base::SysNSStringToWide([nameField_ stringValue]);
- std::wstring keyword = base::SysNSStringToWide([keywordField_ stringValue]);
+ 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];
@@ -156,14 +158,14 @@ void ShiftOriginY(NSView* view, CGFloat amount) {
// 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 {
- std::wstring title = base::SysNSStringToWide([nameField_ stringValue]);
+ 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_];
- std::wstring keyword = base::SysNSStringToWide([keywordField_ stringValue]);
+ string16 keyword = base::SysNSStringToUTF16([keywordField_ stringValue]);
BOOL keywordValid = controller_->IsKeywordValid(keyword);
[self setIsValid:keywordValid
toolTip:IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT
diff --git a/chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm b/chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm
index e38c022..c05803e 100644
--- a/chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm
+++ b/chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm
@@ -8,9 +8,11 @@
#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/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 {
@@ -83,7 +85,7 @@ TEST_F(EditSearchEngineControllerTest, ValidImageOriginals) {
// Test window title is set correctly.
NSString* title = l10n_util::GetNSString(
IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE);
- EXPECT_TRUE([title isEqualToString:[[controller_ window] title]]);
+ EXPECT_NSEQ(title, [[controller_ window] title]);
}
TEST_F(EditSearchEngineControllerTest, SetImageViews) {
@@ -101,23 +103,23 @@ TEST_F(EditSearchEngineControllerTest, InvalidState) {
NSString* toolTip = nil;
EXPECT_FALSE([controller_ validateFields]);
- EXPECT_TRUE([@"" isEqualToString:[[controller_ nameField] stringValue]]);
+ EXPECT_NSEQ(@"", [[controller_ nameField] stringValue]);
EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
toolTip = l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_TITLE_TT);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ nameField] toolTip]]);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ nameImage] toolTip]]);
+ EXPECT_NSEQ(toolTip, [[controller_ nameField] toolTip]);
+ EXPECT_NSEQ(toolTip, [[controller_ nameImage] toolTip]);
// Keywords can not be empty strings.
- EXPECT_TRUE([@"" isEqualToString:[[controller_ keywordField] stringValue]]);
+ EXPECT_NSEQ(@"", [[controller_ keywordField] stringValue]);
EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
EXPECT_TRUE([[controller_ keywordField] toolTip]);
EXPECT_TRUE([[controller_ keywordImage] toolTip]);
- EXPECT_TRUE([@"" isEqualToString:[[controller_ urlField] stringValue]]);
+ EXPECT_NSEQ(@"", [[controller_ urlField] stringValue]);
EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
toolTip = l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_URL_TT);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ urlField] toolTip]]);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ urlImage] toolTip]]);
+ EXPECT_NSEQ(toolTip, [[controller_ urlField] toolTip]);
+ EXPECT_NSEQ(toolTip, [[controller_ urlImage] toolTip]);
}
// Tests that the single name field validates.
@@ -128,8 +130,8 @@ TEST_F(EditSearchEngineControllerTest, ValidateName) {
EXPECT_FALSE([controller_ validateFields]);
NSString* toolTip =
l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_TITLE_TT);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ nameField] toolTip]]);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ nameImage] toolTip]]);
+ 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]);
@@ -162,8 +164,8 @@ TEST_F(EditSearchEngineControllerTest, ValidateURL) {
EXPECT_FALSE([controller_ validateFields]);
NSString* toolTip =
l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_URL_TT);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ urlField] toolTip]]);
- EXPECT_TRUE([toolTip isEqualToString:[[controller_ urlImage] toolTip]]);
+ 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]);
@@ -217,13 +219,13 @@ TEST_F(EditSearchEngineControllerTest, EditTemplateURL) {
EXPECT_TRUE([controller window]);
NSString* title = l10n_util::GetNSString(
IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE);
- EXPECT_TRUE([title isEqualToString:[[controller window] title]]);
+ EXPECT_NSEQ(title, [[controller window] title]);
NSString* nameString = [[controller nameField] stringValue];
- EXPECT_TRUE([@"Foobar" isEqualToString:nameString]);
+ EXPECT_NSEQ(@"Foobar", nameString);
NSString* keywordString = [[controller keywordField] stringValue];
- EXPECT_TRUE([@"keyword" isEqualToString:keywordString]);
+ EXPECT_NSEQ(@"keyword", keywordString);
NSString* urlValueString = [[controller urlField] stringValue];
- EXPECT_TRUE([@"http://foo-bar.com" isEqualToString:urlValueString]);
+ EXPECT_NSEQ(@"http://foo-bar.com", urlValueString);
EXPECT_TRUE([controller validateFields]);
[controller close];
}
diff --git a/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h b/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h
index 882d54c..cca76b5 100644
--- a/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h
+++ b/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h
@@ -4,6 +4,7 @@
#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
diff --git a/chrome/browser/cocoa/event_utils.h b/chrome/browser/cocoa/event_utils.h
index 7921187..fb33cd0 100644
--- a/chrome/browser/cocoa/event_utils.h
+++ b/chrome/browser/cocoa/event_utils.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_EVENT_UTILS_H_
#define CHROME_BROWSER_COCOA_EVENT_UTILS_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/extension_install_prompt.mm b/chrome/browser/cocoa/extension_install_prompt.mm
index b73ebc2..cb33136 100644
--- a/chrome/browser/cocoa/extension_install_prompt.mm
+++ b/chrome/browser/cocoa/extension_install_prompt.mm
@@ -21,7 +21,7 @@ class Profile;
void ExtensionInstallUI::ShowExtensionInstallUIPromptImpl(
Profile* profile, Delegate* delegate, Extension* extension, SkBitmap* icon,
- const string16& warning_text, ExtensionInstallUI::PromptType type) {
+ ExtensionInstallUI::PromptType type) {
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
NSButton* continueButton = [alert addButtonWithTitle:l10n_util::GetNSString(
@@ -37,12 +37,11 @@ void ExtensionInstallUI::ShowExtensionInstallUIPromptImpl(
[alert setMessageText:l10n_util::GetNSStringF(
ExtensionInstallUI::kHeadingIds[type],
UTF8ToUTF16(extension->name()))];
- [alert setInformativeText:base::SysUTF16ToNSString(warning_text)];
[alert setAlertStyle:NSWarningAlertStyle];
[alert setIcon:gfx::SkBitmapToNSImage(*icon)];
if ([alert runModal] == NSAlertFirstButtonReturn) {
- delegate->InstallUIProceed(false);
+ delegate->InstallUIProceed();
} else {
delegate->InstallUIAbort();
}
diff --git a/chrome/browser/cocoa/extension_installed_bubble_bridge.h b/chrome/browser/cocoa/extension_installed_bubble_bridge.h
index f838fd5..999fd0a 100644
--- a/chrome/browser/cocoa/extension_installed_bubble_bridge.h
+++ b/chrome/browser/cocoa/extension_installed_bubble_bridge.h
@@ -7,6 +7,7 @@
#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"
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller.h b/chrome/browser/cocoa/extension_installed_bubble_controller.h
index 3deb91c..de2998a 100644
--- a/chrome/browser/cocoa/extension_installed_bubble_controller.h
+++ b/chrome/browser/cocoa/extension_installed_bubble_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller.mm b/chrome/browser/cocoa/extension_installed_bubble_controller.mm
index 511fba4..4a22436 100644
--- a/chrome/browser/cocoa/extension_installed_bubble_controller.mm
+++ b/chrome/browser/cocoa/extension_installed_bubble_controller.mm
@@ -7,6 +7,7 @@
#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/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/cocoa/browser_window_cocoa.h"
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm b/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm
index a8a78be..adcc426 100644
--- a/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm
+++ b/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm
@@ -9,6 +9,7 @@
#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"
diff --git a/chrome/browser/cocoa/extension_view_mac.h b/chrome/browser/cocoa/extension_view_mac.h
index 74152ff..6534ed3 100644
--- a/chrome/browser/cocoa/extension_view_mac.h
+++ b/chrome/browser/cocoa/extension_view_mac.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/extensions/browser_action_button.h b/chrome/browser/cocoa/extensions/browser_action_button.h
index ffd8240..606b033 100644
--- a/chrome/browser/cocoa/extensions/browser_action_button.h
+++ b/chrome/browser/cocoa/extensions/browser_action_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -25,8 +26,6 @@ extern NSString* const kBrowserActionButtonDraggingNotification;
// Fired when the user drops the button.
extern NSString* const kBrowserActionButtonDragEndNotification;
-extern const CGFloat kBrowserActionWidth;
-
@interface BrowserActionButton : NSButton {
@private
// Bridge to proxy Chrome notifications to the Obj-C class as well as load the
@@ -57,9 +56,10 @@ extern const CGFloat kBrowserActionWidth;
BOOL dragCouldStart_;
}
-- (id)initWithExtension:(Extension*)extension
- profile:(Profile*)profile
- tabId:(int)tabId;
+- (id)initWithFrame:(NSRect)frame
+ extension:(Extension*)extension
+ profile:(Profile*)profile
+ tabId:(int)tabId;
- (void)setFrame:(NSRect)frameRect animate:(BOOL)animate;
diff --git a/chrome/browser/cocoa/extensions/browser_action_button.mm b/chrome/browser/cocoa/extensions/browser_action_button.mm
index 202cd93..70f15ee 100644
--- a/chrome/browser/cocoa/extensions/browser_action_button.mm
+++ b/chrome/browser/cocoa/extensions/browser_action_button.mm
@@ -35,15 +35,6 @@ NSString* const kBrowserActionButtonDragEndNotification =
static const CGFloat kBrowserActionBadgeOriginYOffset = 5;
-// 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.
-static const CGFloat kBrowserActionOriginYOffset = 6.0;
-
-// The size of each button on the toolbar.
-static const CGFloat kBrowserActionHeight = 27;
-const CGFloat kBrowserActionWidth = 29;
-
namespace {
const CGFloat kAnimationDuration = 0.2;
const CGFloat kShadowOffset = 2.0;
@@ -121,13 +112,10 @@ class ExtensionImageTrackerBridge : public NotificationObserver,
return [BrowserActionCell class];
}
-- (id)initWithExtension:(Extension*)extension
- profile:(Profile*)profile
- tabId:(int)tabId {
- NSRect frame = NSMakeRect(0.0,
- kBrowserActionOriginYOffset,
- kBrowserActionWidth,
- kBrowserActionHeight);
+- (id)initWithFrame:(NSRect)frame
+ extension:(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
@@ -280,7 +268,7 @@ class ExtensionImageTrackerBridge : public NotificationObserver,
}
- (NSImage*)compositedImage {
- NSRect bounds = NSMakeRect(0, 0, kBrowserActionWidth, kBrowserActionHeight);
+ NSRect bounds = [self bounds];
NSImage* image = [[[NSImage alloc] initWithSize:bounds.size] autorelease];
[image lockFocus];
diff --git a/chrome/browser/cocoa/extensions/browser_actions_container_view.h b/chrome/browser/cocoa/extensions/browser_actions_container_view.h
index 8569ece..d90851e 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_container_view.h
+++ b/chrome/browser/cocoa/extensions/browser_actions_container_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/extensions/browser_actions_container_view.mm b/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
index 234ed6c..e250fe6 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
+++ b/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/logging.h"
+#include "base/basictypes.h"
#import "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/view_id_util.h"
@@ -19,13 +19,8 @@ NSString* const kBrowserActionGrippyDragFinishedNotification =
namespace {
const CGFloat kAnimationDuration = 0.2;
-const CGFloat kGrippyWidth = 8.0;
-const CGFloat kLowerPadding = 6.0;
+const CGFloat kGrippyWidth = 4.0;
const CGFloat kMinimumContainerWidth = 10.0;
-const CGFloat kRightBorderXOffset = -1.0;
-const CGFloat kRightBorderWidth = 1.0;
-const CGFloat kRightBorderGrayscale = 0.5;
-const CGFloat kUpperPadding = 9.0;
} // namespace
@interface BrowserActionsContainerView(Private)
@@ -57,24 +52,6 @@ const CGFloat kUpperPadding = 9.0;
return self;
}
-- (void)drawRect:(NSRect)dirtyRect {
- NSRect bounds = [self bounds];
- NSColor* middleColor =
- [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:1.0];
- NSColor* endPointColor =
- [NSColor colorWithCalibratedWhite:kRightBorderGrayscale alpha:0.0];
- scoped_nsobject<NSGradient> borderGradient([[NSGradient alloc]
- initWithColorsAndLocations:endPointColor, (CGFloat)0.0,
- middleColor, (CGFloat)0.5,
- endPointColor, (CGFloat)1.0,
- nil]);
- CGFloat xPos = bounds.origin.x + bounds.size.width - kRightBorderWidth +
- kRightBorderXOffset;
- NSRect borderRect = NSMakeRect(xPos, kLowerPadding, kRightBorderWidth,
- bounds.size.height - kUpperPadding);
- [borderGradient drawInRect:borderRect angle:90.0];
-}
-
- (void)setResizable:(BOOL)resizable {
if (resizable == resizable_)
return;
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.h b/chrome/browser/cocoa/extensions/browser_actions_controller.h
index 5638ede..21b0b95 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.h
+++ b/chrome/browser/cocoa/extensions/browser_actions_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -21,9 +22,6 @@ class ExtensionsServiceObserverBridge;
class PrefService;
class Profile;
-// The padding between browser action buttons.
-extern const CGFloat kBrowserActionButtonPadding;
-
// Sent when the visibility of the Browser Actions changes.
extern NSString* const kBrowserActionVisibilityChangedNotification;
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/cocoa/extensions/browser_actions_controller.mm
index 19a1d56..e5a58ad 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/cocoa/extensions/browser_actions_controller.mm
@@ -7,42 +7,59 @@
#include <cmath>
#include <string>
-#include "app/resource_bundle.h"
+#include "base/nsimage_cache_mac.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/pref_service.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/common/extensions/extension_action.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/pref_names.h"
-#include "grit/theme_resources.h"
#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-const CGFloat kBrowserActionButtonPadding = 3;
-
NSString* const kBrowserActionVisibilityChangedNotification =
@"BrowserActionVisibilityChangedNotification";
namespace {
const CGFloat kAnimationDuration = 0.2;
-// When determining the opacity during a drag, we artificially reduce the
-// distance to the edge in order to make the fade more apparent.
-const CGFloat kButtonOpacityLeadPadding = 5.0;
-const CGFloat kChevronHeight = 28.0;
-const CGFloat kChevronLowerPadding = 5.0;
-const CGFloat kChevronRightPadding = 5.0;
+
const CGFloat kChevronWidth = 14.0;
-const CGFloat kGrippyXOffset = 5.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)
@@ -360,24 +377,20 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
- (NSPoint)popupPointForBrowserAction:(Extension*)extension {
if (!extension->browser_action())
return NSZeroPoint;
- BrowserActionButton* button = [self buttonForExtension:extension];
+
+ NSButton* button = [self buttonForExtension:extension];
if (!button)
return NSZeroPoint;
- NSView* view = button;
- BOOL isHidden = [hiddenButtons_ containsObject:button];
- if (isHidden)
- view = chevronMenuButton_.get();
-
- NSPoint arrowPoint = [view frame].origin;
- // Adjust the anchor point to be at the center of the browser action button
- // or chevron.
- arrowPoint.x += NSWidth([view frame]) / 2;
- // Move the arrow up a bit in the case that it's pointing to the chevron.
- if (isHidden)
- arrowPoint.y += NSHeight([view frame]) / 4;
+ if ([hiddenButtons_ containsObject:button])
+ button = chevronMenuButton_.get();
- return [[view superview] convertPoint:arrowPoint toView:nil];
+ // 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 {
@@ -449,10 +462,14 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
if ([self buttonCount] == 0)
[containerView_ setHidden:NO];
- BrowserActionButton* newButton = [[[BrowserActionButton alloc]
- initWithExtension:extension
- profile:profile_
- tabId:[self currentTabId]] autorelease];
+ 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());
@@ -524,7 +541,6 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
- (void)updateButtonOpacity {
for (BrowserActionButton* button in [buttons_ allValues]) {
NSRect buttonFrame = [button frame];
- buttonFrame.origin.x += kButtonOpacityLeadPadding;
if (NSContainsRect([containerView_ bounds], buttonFrame)) {
if ([button alphaValue] != 1.0)
[button setAlphaValue:1.0];
@@ -533,8 +549,7 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
}
CGFloat intersectionWidth =
NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame));
- CGFloat alpha = std::max(0.0f,
- (intersectionWidth - kButtonOpacityLeadPadding) / NSWidth(buttonFrame));
+ CGFloat alpha = std::max(0.0f, intersectionWidth / NSWidth(buttonFrame));
[button setAlphaValue:alpha];
[button setNeedsDisplay:YES];
}
@@ -549,25 +564,34 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
}
- (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount {
- CGFloat width = 0.0;
+ // 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 = kGrippyXOffset + (2 * kBrowserActionButtonPadding) +
- (buttonCount * (kBrowserActionWidth + kBrowserActionButtonPadding));
+ width += buttonCount * kBrowserActionWidth;
+ width += (buttonCount - 1) * kBrowserActionButtonPadding;
}
+
// Make room for the chevron if any buttons are hidden.
if ([self buttonCount] != [self visibleButtonCount]) {
- width += kChevronWidth + kBrowserActionButtonPadding;
- // Add more space if all buttons are hidden.
- if ([self visibleButtonCount] == 0)
- width += 3 * kBrowserActionButtonPadding;
+ // 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 {
- CGFloat containerWidth = [self savedWidth];
- return (containerWidth - kGrippyXOffset) /
+ // 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);
}
@@ -668,7 +692,7 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
- (void)moveButton:(BrowserActionButton*)button
toIndex:(NSUInteger)index
animate:(BOOL)animate {
- CGFloat xOffset = kGrippyXOffset +
+ CGFloat xOffset = kBrowserActionLeftPadding +
(index * (kBrowserActionWidth + kBrowserActionButtonPadding));
NSRect buttonFrame = [button frame];
buttonFrame.origin.x = xOffset;
@@ -733,11 +757,11 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
}
- (void)updateChevronPositionInFrame:(NSRect)frame {
- CGFloat xPos = NSWidth(frame) - kChevronWidth - kChevronRightPadding;
+ CGFloat xPos = NSWidth(frame) - kChevronWidth;
NSRect buttonFrame = NSMakeRect(xPos,
- kChevronLowerPadding,
+ kBrowserActionOriginYOffset,
kChevronWidth,
- kChevronHeight);
+ kBrowserActionHeight);
[chevronMenuButton_ setFrame:buttonFrame];
}
@@ -748,10 +772,11 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
return;
if (!chevronMenuButton_.get()) {
- chevronMenuButton_.reset([[MenuButton alloc] init]);
+ chevronMenuButton_.reset([[ChevronMenuButton alloc] init]);
[chevronMenuButton_ setBordered:NO];
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- [chevronMenuButton_ setImage:rb.GetNSImageNamed(IDR_BOOKMARK_BAR_CHEVRONS)];
+ [chevronMenuButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ NSImage* chevronImage = nsimage_cache::ImageNamed(kOverflowChevronsName);
+ [chevronMenuButton_ setImage:chevronImage];
[containerView_ addSubview:chevronMenuButton_];
}
diff --git a/chrome/browser/cocoa/extensions/extension_action_context_menu.h b/chrome/browser/cocoa/extensions/extension_action_context_menu.h
index 06c2276..3c9e216 100644
--- a/chrome/browser/cocoa/extensions/extension_action_context_menu.h
+++ b/chrome/browser/cocoa/extensions/extension_action_context_menu.h
@@ -4,6 +4,7 @@
#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>
diff --git a/chrome/browser/cocoa/extensions/extension_action_context_menu.mm b/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
index 797f517..81aa61e 100644
--- a/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
+++ b/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
@@ -18,7 +18,8 @@
#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/pref_service.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"
@@ -45,8 +46,7 @@ class AsyncUninstaller : public ExtensionInstallUI::Delegate {
~AsyncUninstaller() {}
// Overridden by ExtensionInstallUI::Delegate.
- virtual void InstallUIProceed(bool create_shortcut) {
- DCHECK(!create_shortcut);
+ virtual void InstallUIProceed() {
profile_->GetExtensionsService()->
UninstallExtension(extension_->id(), false);
}
@@ -72,14 +72,10 @@ class DevmodeObserver : public NotificationObserver {
DevmodeObserver(ExtensionActionContextMenu* menu,
PrefService* service)
: menu_(menu), pref_service_(service) {
- pref_service_->AddPrefObserver(prefs::kExtensionsUIDeveloperMode,
- this);
- }
-
- ~DevmodeObserver() {
- pref_service_->RemovePrefObserver(prefs::kExtensionsUIDeveloperMode,
- this);
+ registrar_.Init(pref_service_);
+ registrar_.Add(prefs::kExtensionsUIDeveloperMode, this);
}
+ virtual ~DevmodeObserver() {}
void Observe(NotificationType type,
const NotificationSource& source,
@@ -93,6 +89,7 @@ class DevmodeObserver : public NotificationObserver {
private:
ExtensionActionContextMenu* menu_;
PrefService* pref_service_;
+ PrefChangeRegistrar registrar_;
};
} // namespace extension_action_context_menu
@@ -241,13 +238,18 @@ int CurrentTabId() {
[window->cocoa_controller() toolbarController];
LocationBarViewMac* locationBarView =
[toolbarController locationBarBridge];
- NSPoint popupPoint = locationBarView->GetPageActionBubblePoint(action_);
- // If there was no matching page action, it was a browser action.
- if (NSEqualPoints(popupPoint, NSZeroPoint)) {
+ 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();
diff --git a/chrome/browser/cocoa/extensions/extension_infobar_controller.h b/chrome/browser/cocoa/extensions/extension_infobar_controller.h
index c1dd730..f17a785 100644
--- a/chrome/browser/cocoa/extensions/extension_infobar_controller.h
+++ b/chrome/browser/cocoa/extensions/extension_infobar_controller.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/extensions/extension_infobar_controller.mm b/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
index f9599fa..1bb1a5f 100644
--- a/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
+++ b/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
@@ -15,6 +15,7 @@
#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"
@@ -64,13 +65,13 @@ class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver,
// Load the Extension's icon image.
void LoadIcon() {
- ExtensionResource icon_resource;
Extension* extension = delegate_->extension_host()->extension();
- Extension::Icons size =
- extension->GetIconPathAllowLargerSize(&icon_resource,
- Extension::EXTENSION_ICON_BITTY);
+ 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(size, size),
+ tracker_.LoadImage(extension, icon_resource,
+ gfx::Size(Extension::EXTENSION_ICON_BITTY,
+ Extension::EXTENSION_ICON_BITTY),
ImageLoadingTracker::DONT_CACHE);
} else {
OnImageLoaded(NULL, icon_resource, 0);
diff --git a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.h b/chrome/browser/cocoa/extensions/extension_install_prompt_controller.h
index fce4ac3..0fb4d4e 100644
--- a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.h
+++ b/chrome/browser/cocoa/extensions/extension_install_prompt_controller.h
@@ -4,13 +4,14 @@
#ifndef CHROME_BROWSER_COCOA_EXTENSION_INSTALL_PROMPT_H_
#define CHROME_BROWSER_COCOA_EXTENSION_INSTALL_PROMPT_H_
+#pragma once
-#include <string>
#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"
diff --git a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm b/chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm
index 5c738a1..9ba758b 100644
--- a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm
+++ b/chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm
@@ -117,7 +117,7 @@ void OffsetControlVertically(NSControl* control, CGFloat amount) {
}
- (IBAction)ok:(id)sender {
- delegate_->InstallUIProceed(false); // Don't create shortcut.
+ delegate_->InstallUIProceed();
[NSApp endSheet:[self window]];
}
diff --git a/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm b/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
index aa1e586..f596851 100644
--- a/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
+++ b/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
@@ -18,6 +18,7 @@
#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"
@@ -81,13 +82,11 @@ class MockExtensionInstallUIDelegate : public ExtensionInstallUI::Delegate {
public:
MockExtensionInstallUIDelegate()
: proceed_count_(0),
- abort_count_(0),
- last_proceed_was_create_app_shortcut_(0) {}
+ abort_count_(0) {}
// ExtensionInstallUI::Delegate overrides.
- virtual void InstallUIProceed(bool create_app_shortcut) {
+ virtual void InstallUIProceed() {
proceed_count_++;
- last_proceed_was_create_app_shortcut_ = create_app_shortcut;
}
virtual void InstallUIAbort() {
@@ -96,17 +95,12 @@ class MockExtensionInstallUIDelegate : public ExtensionInstallUI::Delegate {
int proceed_count() { return proceed_count_; }
int abort_count() { return abort_count_; }
- bool last_proceed_was_create_app_shortcut() {
- return last_proceed_was_create_app_shortcut_;
- }
protected:
int proceed_count_;
int abort_count_;
- bool last_proceed_was_create_app_shortcut_;
};
-
// 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) {
@@ -128,7 +122,7 @@ TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalCancel) {
[controller window]; // force nib load
// Test the right nib loaded.
- EXPECT_TRUE([[controller windowNibName] isEqual:@"ExtensionInstallPrompt"]);
+ EXPECT_NSEQ(@"ExtensionInstallPrompt", [controller windowNibName]);
// Check all the controls.
// Make sure everything is non-nil, and that the fields that are
@@ -145,8 +139,8 @@ TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalCancel) {
EXPECT_NE('^', [[[controller subtitleField] stringValue] characterAtIndex:0]);
EXPECT_TRUE([controller warningsField] != nil);
- EXPECT_TRUE([[[controller warningsField] stringValue]
- isEqual:(base::SysUTF16ToNSString(warnings[0]))]);
+ EXPECT_NSEQ([[controller warningsField] stringValue],
+ base::SysUTF16ToNSString(warnings[0]));
EXPECT_TRUE([controller warningsBox] != nil);
@@ -162,7 +156,6 @@ TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalCancel) {
[controller cancel:nil];
EXPECT_EQ(1, delegate->abort_count());
EXPECT_EQ(0, delegate->proceed_count());
- EXPECT_FALSE(delegate->last_proceed_was_create_app_shortcut());
}
@@ -187,7 +180,6 @@ TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalOK) {
EXPECT_EQ(0, delegate->abort_count());
EXPECT_EQ(1, delegate->proceed_count());
- EXPECT_FALSE(delegate->last_proceed_was_create_app_shortcut());
}
// Test that controls get repositioned when there are two warnings vs one
@@ -270,8 +262,7 @@ TEST_F(ExtensionInstallPromptControllerTest, BasicsSkinny) {
[controller window]; // force nib load
// Test the right nib loaded.
- EXPECT_TRUE([[controller windowNibName]
- isEqual:@"ExtensionInstallPromptNoWarnings"]);
+ EXPECT_NSEQ(@"ExtensionInstallPromptNoWarnings", [controller windowNibName]);
// Check all the controls.
// In the skinny prompt, only the icon, title and buttons are non-nill.
diff --git a/chrome/browser/cocoa/extensions/extension_popup_controller.h b/chrome/browser/cocoa/extensions/extension_popup_controller.h
index d7042ea..4fd4c81 100644
--- a/chrome/browser/cocoa/extensions/extension_popup_controller.h
+++ b/chrome/browser/cocoa/extensions/extension_popup_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm b/chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm
index 235d85b..ba7e2b7 100644
--- a/chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm
+++ b/chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm
@@ -24,11 +24,10 @@ class ExtensionTestingProfile : public TestingProfile {
DCHECK(!GetExtensionProcessManager());
DCHECK(!GetExtensionsService());
- manager_.reset(new ExtensionProcessManager(this));
+ manager_.reset(ExtensionProcessManager::Create(this));
service_ = new ExtensionsService(this,
CommandLine::ForCurrentProcess(),
- GetPrefs(),
- GetExtensionsInstallDir(),
+ GetExtensionsInstallDir(),
false);
service_->set_extensions_enabled(true);
service_->set_show_extensions_prompts(false);
diff --git a/chrome/browser/cocoa/external_protocol_dialog.mm b/chrome/browser/cocoa/external_protocol_dialog.mm
index dc3ca24..3a7849a 100644
--- a/chrome/browser/cocoa/external_protocol_dialog.mm
+++ b/chrome/browser/cocoa/external_protocol_dialog.mm
@@ -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.
@@ -116,10 +116,8 @@ void ExternalProtocolHandler::RunExternalProtocolDialog(
}
// Set the "don't warn me again" info.
- if ([[alert_ suppressionButton] state] == NSOnState) {
- ExternalProtocolHandler::SetBlockState(UTF8ToWide(url_.scheme()),
- blockState);
- }
+ if ([[alert_ suppressionButton] state] == NSOnState)
+ ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState);
if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
diff --git a/chrome/browser/cocoa/fast_resize_view.h b/chrome/browser/cocoa/fast_resize_view.h
index d87b9b8..d6e8bed 100644
--- a/chrome/browser/cocoa/fast_resize_view.h
+++ b/chrome/browser/cocoa/fast_resize_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_FAST_RESIZE_VIEW_H_
#define CHROME_BROWSER_COCOA_FAST_RESIZE_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/file_metadata.h b/chrome/browser/cocoa/file_metadata.h
index 192a92c..e7448d7 100644
--- a/chrome/browser/cocoa/file_metadata.h
+++ b/chrome/browser/cocoa/file_metadata.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_FILE_METADATA_H_
#define CHROME_BROWSER_COCOA_FILE_METADATA_H_
+#pragma once
class FilePath;
class GURL;
diff --git a/chrome/browser/cocoa/find_bar_bridge.h b/chrome/browser/cocoa/find_bar_bridge.h
index 39c146e..5623ca4 100644
--- a/chrome/browser/cocoa/find_bar_bridge.h
+++ b/chrome/browser/cocoa/find_bar_bridge.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm b/chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm
index 6532371..eb5e3fc 100644
--- a/chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm
+++ b/chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm
@@ -32,6 +32,14 @@
- (FindBarTextField*)findTextField {
return findText_;
}
+
+- (NSButton*)nextButton {
+ return nextButton_;
+}
+
+- (NSButton*)previousButton {
+ return previousButton_;
+}
@end
namespace {
@@ -50,6 +58,11 @@ class FindBarCocoaControllerTest : public CocoaTest {
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];
diff --git a/chrome/browser/cocoa/find_bar_text_field.mm b/chrome/browser/cocoa/find_bar_text_field.mm
index e6f1e75..da36f12 100644
--- a/chrome/browser/cocoa/find_bar_text_field.mm
+++ b/chrome/browser/cocoa/find_bar_text_field.mm
@@ -16,6 +16,9 @@
- (void)awakeFromNib {
DCHECK([[self cell] isKindOfClass:[FindBarTextFieldCell class]]);
+
+ [self registerForDraggedTypes:
+ [NSArray arrayWithObjects:NSStringPboardType, nil]];
}
- (FindBarTextFieldCell*)findBarTextFieldCell {
@@ -27,4 +30,11 @@
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.mm b/chrome/browser/cocoa/find_bar_text_field_cell.mm
index 9b52c5f..62f2564 100644
--- a/chrome/browser/cocoa/find_bar_text_field_cell.mm
+++ b/chrome/browser/cocoa/find_bar_text_field_cell.mm
@@ -6,6 +6,7 @@
#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"
@@ -43,6 +44,14 @@ CGFloat WidthForResults(NSAttributedString* resultsString) {
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();
@@ -65,9 +74,10 @@ CGFloat WidthForResults(NSAttributedString* resultsString) {
- (void)setActiveMatch:(NSInteger)current of:(NSInteger)total {
NSString* results =
- base::SysWideToNSString(l10n_util::GetStringF(IDS_FIND_IN_PAGE_COUNT,
- IntToWString(current),
- IntToWString(total)));
+ 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)]]);
diff --git a/chrome/browser/cocoa/find_bar_view.h b/chrome/browser/cocoa/find_bar_view.h
index 0bdf8d5..41d1ec3 100644
--- a/chrome/browser/cocoa/find_bar_view.h
+++ b/chrome/browser/cocoa/find_bar_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_FIND_BAR_VIEW_H_
#define CHROME_BROWSER_COCOA_FIND_BAR_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/find_bar_view.mm b/chrome/browser/cocoa/find_bar_view.mm
index ce224a7..a928452 100644
--- a/chrome/browser/cocoa/find_bar_view.mm
+++ b/chrome/browser/cocoa/find_bar_view.mm
@@ -6,6 +6,7 @@
#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;
@@ -13,6 +14,11 @@ CGFloat kCurveSize = 8;
@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);
@@ -113,6 +119,11 @@ CGFloat kCurveSize = 8;
- (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;
}
diff --git a/chrome/browser/cocoa/find_pasteboard.h b/chrome/browser/cocoa/find_pasteboard.h
index bf5d213..6460997 100644
--- a/chrome/browser/cocoa/find_pasteboard.h
+++ b/chrome/browser/cocoa/find_pasteboard.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_FIND_PASTEBOARD_H_
#define CHROME_BROWSER_COCOA_FIND_PASTEBOARD_H_
+#pragma once
#include "base/string16.h"
diff --git a/chrome/browser/cocoa/first_run_bubble_controller.mm b/chrome/browser/cocoa/first_run_bubble_controller.mm
index 6c4ea32..0469eee 100644
--- a/chrome/browser/cocoa/first_run_bubble_controller.mm
+++ b/chrome/browser/cocoa/first_run_bubble_controller.mm
@@ -16,6 +16,7 @@
- (id)initRelativeToView:(NSView*)view
offset:(NSPoint)offset
profile:(Profile*)profile;
+- (void)closeIfNotKey;
@end
@implementation FirstRunBubbleController
@@ -37,6 +38,13 @@
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;
}
@@ -59,4 +67,18 @@
[[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_dialog.h b/chrome/browser/cocoa/first_run_dialog.h
index 807d8b0..3e575a3 100644
--- a/chrome/browser/cocoa/first_run_dialog.h
+++ b/chrome/browser/cocoa/first_run_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_FIRST_RUN_DIALOG_H_
#define CHROME_BROWSER_FIRST_RUN_DIALOG_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -12,14 +13,8 @@
// us improve Chromium.
@interface FirstRunDialogController : NSWindowController {
@private
- BOOL userDidCancel_;
BOOL statsEnabled_;
- BOOL statsCheckboxHidden_;
BOOL makeDefaultBrowser_;
- BOOL importBookmarks_;
- int browserImportSelectedIndex_;
- NSArray* browserImportList_;
- BOOL browserImportListHidden_;
IBOutlet NSArray* objectsToSize_;
IBOutlet NSButton* statsCheckbox_;
@@ -29,21 +24,12 @@
// Called when the "Start Google Chrome" button is pressed.
- (IBAction)ok:(id)sender;
-// Cancel button calls this.
-- (IBAction)cancel:(id)sender;
-
// Called when the "Learn More" button is pressed.
- (IBAction)learnMore:(id)sender;
// Properties for bindings.
-@property(assign, nonatomic) BOOL userDidCancel;
@property(assign, nonatomic) BOOL statsEnabled;
-@property(assign, nonatomic) BOOL statsCheckboxHidden;
@property(assign, nonatomic) BOOL makeDefaultBrowser;
-@property(assign, nonatomic) BOOL importBookmarks;
-@property(assign, nonatomic) int browserImportSelectedIndex;
-@property(retain, nonatomic) NSArray* browserImportList;
-@property(assign, nonatomic) BOOL browserImportListHidden;
@end
diff --git a/chrome/browser/cocoa/first_run_dialog.mm b/chrome/browser/cocoa/first_run_dialog.mm
index e63262e..123b80b 100644
--- a/chrome/browser/cocoa/first_run_dialog.mm
+++ b/chrome/browser/cocoa/first_run_dialog.mm
@@ -1,16 +1,21 @@
-// 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.
#import "chrome/browser/cocoa/first_run_dialog.h"
#include "app/l10n_util_mac.h"
-#include "base/logging.h"
#include "base/mac_util.h"
-#import "base/scoped_nsobject.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
@@ -26,18 +31,30 @@ NSInteger CompareFrameY(id view1, id view2, void* context) {
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 userDidCancel = userDidCancel_;
@synthesize statsEnabled = statsEnabled_;
-@synthesize statsCheckboxHidden = statsCheckboxHidden_;
@synthesize makeDefaultBrowser = makeDefaultBrowser_;
-@synthesize importBookmarks = importBookmarks_;
-@synthesize browserImportSelectedIndex = browserImportSelectedIndex_;
-@synthesize browserImportList = browserImportList_;
-@synthesize browserImportListHidden = browserImportListHidden_;
- (id)init {
NSString* nibpath =
@@ -47,23 +64,28 @@ NSInteger CompareFrameY(id view1, id view2, void* context) {
if (self != nil) {
// Bound to the dialog checkbox, default to true.
statsEnabled_ = YES;
- importBookmarks_ = YES;
-
-#if !defined(GOOGLE_CHROME_BUILD)
- // In Chromium builds all stats reporting is disabled so there's no reason
- // to display the checkbox - the setting is always OFF.
- statsCheckboxHidden_ = YES;
-#endif // !GOOGLE_CHROME_BUILD
}
return self;
}
- (void)dealloc {
- [browserImportList_ release];
[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.
@@ -95,15 +117,13 @@ NSInteger CompareFrameY(id view1, id view2, void* context) {
[win setFrame:windowFrame display:NO];
}
- // The stats checkbox (if visible) gets some really long text, so it gets
- // word wrapped and then sized.
+ // The stats checkbox gets some really long text, so it gets word wrapped
+ // and then sized.
DCHECK(statsCheckbox_);
CGFloat statsCheckboxHeightChange = 0.0;
- if (![self statsCheckboxHidden]) {
- [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:statsCheckbox_];
- statsCheckboxHeightChange =
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:statsCheckbox_].height;
- }
+ [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:statsCheckbox_];
+ statsCheckboxHeightChange =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:statsCheckbox_].height;
// Walk bottom up shuffling for all the hidden views.
NSArray* subViews =
@@ -161,42 +181,15 @@ NSInteger CompareFrameY(id view1, id view2, void* context) {
[NSApp runModalForWindow:win];
}
-- (void)closeDialog {
+- (IBAction)ok:(id)sender {
[[self window] close];
[NSApp stopModal];
}
-- (IBAction)ok:(id)sender {
- [self closeDialog];
-}
-
-- (IBAction)cancel:(id)sender {
- [self closeDialog];
- [self setUserDidCancel:YES];
-}
-
- (IBAction)learnMore:(id)sender {
NSString* urlStr = l10n_util::GetNSString(IDS_LEARN_MORE_REPORTING_URL);
NSURL* learnMoreUrl = [NSURL URLWithString:urlStr];
[[NSWorkspace sharedWorkspace] openURL:learnMoreUrl];
}
-// Custom property getters
-
-- (BOOL)importBookmarks {
- // If the UI for browser import is hidden, report the choice as off.
- if ([self browserImportListHidden]) {
- return NO;
- }
- return importBookmarks_;
-}
-
-- (BOOL)statsEnabled {
- // If the UI for stats is hidden, report the choice as off.
- if ([self statsCheckboxHidden]) {
- return NO;
- }
- return statsEnabled_;
-}
-
@end
diff --git a/chrome/browser/cocoa/floating_bar_backing_view.h b/chrome/browser/cocoa/floating_bar_backing_view.h
index 66ee53f..c5e503e 100644
--- a/chrome/browser/cocoa/floating_bar_backing_view.h
+++ b/chrome/browser/cocoa/floating_bar_backing_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
#define CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/focus_tracker.mm b/chrome/browser/cocoa/focus_tracker.mm
index ecbb864..86b612d 100644
--- a/chrome/browser/cocoa/focus_tracker.mm
+++ b/chrome/browser/cocoa/focus_tracker.mm
@@ -1,10 +1,10 @@
-// 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.
#import "chrome/browser/cocoa/focus_tracker.h"
-#include "base/logging.h"
+#include "base/basictypes.h"
@implementation FocusTracker
diff --git a/chrome/browser/cocoa/font_language_settings_controller.h b/chrome/browser/cocoa/font_language_settings_controller.h
index 173df84..9e03323 100644
--- a/chrome/browser/cocoa/font_language_settings_controller.h
+++ b/chrome/browser/cocoa/font_language_settings_controller.h
@@ -6,7 +6,7 @@
#include "base/cocoa_protocols_mac.h"
#include "base/scoped_nsobject.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
class Profile;
diff --git a/chrome/browser/cocoa/font_language_settings_controller.mm b/chrome/browser/cocoa/font_language_settings_controller.mm
index 1958e00..6395a1e 100644
--- a/chrome/browser/cocoa/font_language_settings_controller.mm
+++ b/chrome/browser/cocoa/font_language_settings_controller.mm
@@ -9,7 +9,7 @@
#include "base/sys_string_conversions.h"
#include "chrome/browser/character_encoding.h"
#include "chrome/browser/fonts_languages_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/cocoa/font_language_settings_controller_unittest.mm b/chrome/browser/cocoa/font_language_settings_controller_unittest.mm
index 59d41bb..075d495 100644
--- a/chrome/browser/cocoa/font_language_settings_controller_unittest.mm
+++ b/chrome/browser/cocoa/font_language_settings_controller_unittest.mm
@@ -9,6 +9,7 @@
#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
@@ -66,8 +67,8 @@ TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayField) {
withFont:font
withLabel:label];
- ASSERT_TRUE([[font fontName] isEqualToString:[[field font] fontName]]);
- ASSERT_TRUE([@"Times-Roman, 12" isEqualToString:[field stringValue]]);
+ ASSERT_NSEQ([font fontName], [[field font] fontName]);
+ ASSERT_NSEQ(@"Times-Roman, 12", [field stringValue]);
}
TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayFieldNilFont) {
@@ -80,7 +81,7 @@ TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayFieldNilFont) {
withFont:nil
withLabel:label];
- ASSERT_TRUE([@"foo" isEqualToString:[field stringValue]]);
+ ASSERT_NSEQ(@"foo", [field stringValue]);
}
TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayFieldNilField) {
diff --git a/chrome/browser/cocoa/fullscreen_controller.h b/chrome/browser/cocoa/fullscreen_controller.h
index 85c7f7b..f213fa3 100644
--- a/chrome/browser/cocoa/fullscreen_controller.h
+++ b/chrome/browser/cocoa/fullscreen_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -115,7 +116,7 @@
@end
// Notification posted when we're about to enter or leave fullscreen.
-extern const NSString* kWillEnterFullscreenNotification;
-extern const NSString* kWillLeaveFullscreenNotification;
+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
index f5d66bf..d0604f3 100644
--- a/chrome/browser/cocoa/fullscreen_controller.mm
+++ b/chrome/browser/cocoa/fullscreen_controller.mm
@@ -9,9 +9,9 @@
#import "chrome/browser/cocoa/browser_window_controller.h"
#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-const NSString* kWillEnterFullscreenNotification =
+NSString* const kWillEnterFullscreenNotification =
@"WillEnterFullscreenNotification";
-const NSString* kWillLeaveFullscreenNotification =
+NSString* const kWillLeaveFullscreenNotification =
@"WillLeaveFullscreenNotification";
namespace {
@@ -199,6 +199,11 @@ const CGFloat kFloatingBarVerticalOffset = 22;
object:window];
[nc addObserver:self
+ selector:@selector(windowDidMove:)
+ name:NSWindowDidMoveNotification
+ object:window];
+
+ [nc addObserver:self
selector:@selector(windowDidBecomeMain:)
name:NSWindowDidBecomeMainNotification
object:window];
@@ -222,6 +227,10 @@ const CGFloat kFloatingBarVerticalOffset = 22;
[browserController_ resizeFullscreenWindow];
}
+- (void)windowDidMove:(NSNotification*)notification {
+ [browserController_ resizeFullscreenWindow];
+}
+
- (void)windowDidBecomeMain:(NSNotification*)notification {
[self showActiveWindowUI];
}
diff --git a/chrome/browser/cocoa/fullscreen_window.h b/chrome/browser/cocoa/fullscreen_window.h
index d43059d..ba01abf 100644
--- a/chrome/browser/cocoa/fullscreen_window.h
+++ b/chrome/browser/cocoa/fullscreen_window.h
@@ -3,14 +3,14 @@
// found in the LICENSE file.
#include <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/chrome_event_processing_window.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 ChromeEventProcessingWindow to inherit
-// special event handling (e.g. handleExtraKeyboardShortcut).
-@interface FullscreenWindow : ChromeEventProcessingWindow
+// 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.
diff --git a/chrome/browser/cocoa/fullscreen_window.mm b/chrome/browser/cocoa/fullscreen_window.mm
index 4fd2be1..d0fb304 100644
--- a/chrome/browser/cocoa/fullscreen_window.mm
+++ b/chrome/browser/cocoa/fullscreen_window.mm
@@ -5,8 +5,8 @@
#import "chrome/browser/cocoa/fullscreen_window.h"
#include "base/mac_util.h"
-#include "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/themed_window.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
@implementation FullscreenWindow
@@ -82,25 +82,4 @@
return [super validateUserInterfaceItem:item];
}
-- (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/gradient_button_cell.h b/chrome/browser/cocoa/gradient_button_cell.h
index 5e29878..9280ce3 100644
--- a/chrome/browser/cocoa/gradient_button_cell.h
+++ b/chrome/browser/cocoa/gradient_button_cell.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
#define CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -31,6 +32,23 @@ enum {
};
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
@@ -41,6 +59,9 @@ typedef NSInteger ButtonType;
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_;
}
@@ -67,15 +88,33 @@ typedef NSInteger ButtonType;
- (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
index 5fb8c29..4cab381 100644
--- a/chrome/browser/cocoa/gradient_button_cell.mm
+++ b/chrome/browser/cocoa/gradient_button_cell.mm
@@ -6,9 +6,9 @@
#include "base/logging.h"
#import "base/scoped_nsobject.h"
-#import "chrome/browser/browser_theme_provider.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"
@@ -27,14 +27,188 @@
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];
@@ -72,29 +246,9 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
[[self controlView] setNeedsDisplay:YES];
}
-// 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];
-}
+#endif
- (NSGradient*)gradientForHoverAlpha:(CGFloat)hoverAlpha
isThemed:(BOOL)themed {
@@ -121,6 +275,9 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
- (void)sharedInit {
shouldTheme_ = YES;
+ pulseState_ = gradient_button_cell::kPulsedOff;
+ pulseMultiplier_ = 1.0;
+ outerStrokeAlphaMult_ = 1.0;
gradient_.reset([[self gradientForHoverAlpha:0.0 isThemed:NO] retain]);
}
@@ -283,12 +440,15 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
// Draw the outer stroke.
NSColor* strokeColor = nil;
if (showClickedGradient) {
- strokeColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.3];
+ 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.6];
+ true) : [NSColor colorWithCalibratedWhite:0.0
+ alpha:0.6 * outerStrokeAlphaMult_];
}
[strokeColor setStroke];
@@ -357,23 +517,36 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
innerPath:&innerPath
clipPath:NULL];
- BOOL pressed = [self isHighlighted];
+ 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.
+ // 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 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:pressed
+ showClickedGradient:showClickedGradient
showHighlightGradient:[self isHighlighted]
- hoverAlpha:[self hoverAlpha]
+ hoverAlpha:hoverAlpha
active:active
cellFrame:cellFrame
defaultGradient:nil];
@@ -405,18 +578,18 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
CGContextRef context =
(CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]);
- ThemeProvider* themeProvider = [[controlView window] themeProvider];
+ BrowserThemeProvider* themeProvider = static_cast<BrowserThemeProvider*>(
+ [[controlView window] themeProvider]);
NSColor* color = themeProvider ?
themeProvider->GetNSColorTint(BrowserThemeProvider::TINT_BUTTONS,
true) :
[NSColor blackColor];
- if (isTemplate) {
+ if (isTemplate && themeProvider && themeProvider->UsingDefaultTheme()) {
scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- NSColor* shadowColor = [color gtm_legibleTextColor];
- shadowColor = [shadowColor colorWithAlphaComponent:0.25];
- [shadow.get() setShadowColor:shadowColor];
- [shadow.get() setShadowOffset:NSMakeSize(0, -1.0)];
+ [shadow.get() setShadowColor:themeProvider->GetNSColor(
+ BrowserThemeProvider::COLOR_TOOLBAR_BEZEL, true)];
+ [shadow.get() setShadowOffset:NSMakeSize(0.0, -1.0)];
[shadow setShadowBlurRadius:1.0];
[shadow set];
}
@@ -430,18 +603,16 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
operation:NSCompositeSourceOver
fraction:[self isEnabled] ? 1.0 : 0.5
neverFlipped:YES];
- if (isTemplate) {
- if (color) {
- [color set];
- NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop);
- }
+ if (isTemplate && color) {
+ [color set];
+ NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop);
}
CGContextEndTransparencyLayer(context);
[NSGraphicsContext restoreGraphicsState];
} else {
- // NSCell draws these uncentered for some reason, probably because of the
- // of control in the xib
+ // 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];
}
@@ -457,6 +628,80 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
}
}
+// 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];
+
+ // Don't complicate drawing unless we need to clip
+ if (floor(size.width) <= NSWidth(cellFrame)) {
+ 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;
diff --git a/chrome/browser/cocoa/gradient_button_cell_unittest.mm b/chrome/browser/cocoa/gradient_button_cell_unittest.mm
index 8c6fdd7..1290e11 100644
--- a/chrome/browser/cocoa/gradient_button_cell_unittest.mm
+++ b/chrome/browser/cocoa/gradient_button_cell_unittest.mm
@@ -11,7 +11,7 @@
#include "testing/platform_test.h"
@interface GradientButtonCell (HoverValueTesting)
-- (void)adjustHoverValue;
+- (void)performOnePulseStep;
@end
namespace {
@@ -51,7 +51,7 @@ TEST_F(GradientButtonCellTest, Hover) {
[cell setMouseInside:NO animate:YES];
CGFloat alpha1 = [cell hoverAlpha];
- [cell adjustHoverValue];
+ [cell performOnePulseStep];
CGFloat alpha2 = [cell hoverAlpha];
EXPECT_TRUE(alpha2 < alpha1);
}
@@ -77,4 +77,36 @@ TEST_F(GradientButtonCellTest, TrackingRects) {
[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
index 92be247..2743752 100644
--- a/chrome/browser/cocoa/history_menu_bridge.h
+++ b/chrome/browser/cocoa/history_menu_bridge.h
@@ -4,17 +4,19 @@
#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 "base/scoped_ptr.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;
@@ -22,6 +24,7 @@ class NotificationRegistrar;
class PageUsageData;
class Profile;
class TabNavigationEntry;
+class TabRestoreService;
@class HistoryMenuCocoaController;
namespace {
@@ -53,26 +56,16 @@ class HistoryMenuBridgeTest;
// 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 TabRestoreService::Observer {
+ 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()
- : icon_requested(false),
- menu_item(nil),
- session_id(0) {}
-
+ HistoryItem();
// Copy constructor allowed.
- HistoryItem(const HistoryItem& copy)
- : title(copy.title),
- url(copy.url),
- icon_requested(false),
- menu_item(nil),
- session_id(copy.session_id) {}
-
- ~HistoryItem() {}
+ HistoryItem(const HistoryItem& copy);
+ ~HistoryItem();
// The title for the menu item.
string16 title;
@@ -135,7 +128,7 @@ class HistoryMenuBridge : public NotificationObserver,
const NotificationSource& source,
const NotificationDetails& details);
- // For TabRestoreService::Observer
+ // For TabRestoreServiceObserver
virtual void TabRestoreServiceChanged(TabRestoreService* service);
virtual void TabRestoreServiceDestroyed(TabRestoreService* service);
diff --git a/chrome/browser/cocoa/history_menu_bridge.mm b/chrome/browser/cocoa/history_menu_bridge.mm
index 7795bf7..10e1bc2 100644
--- a/chrome/browser/cocoa/history_menu_bridge.mm
+++ b/chrome/browser/cocoa/history_menu_bridge.mm
@@ -8,6 +8,7 @@
#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_dll_resource.h" // IDC_HISTORY_MENU
@@ -45,6 +46,23 @@ 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),
@@ -207,7 +225,7 @@ void HistoryMenuBridge::TabRestoreServiceChanged(TabRestoreService* service) {
} else {
item->title =l10n_util::GetStringFUTF16(
IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE,
- IntToString16(item->tabs.size()));
+ base::IntToString16(item->tabs.size()));
}
// Sometimes it is possible for there to not be any subitems for a given
diff --git a/chrome/browser/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/cocoa/history_menu_bridge_unittest.mm
index 1fd47a2..e370fe8 100644
--- a/chrome/browser/cocoa/history_menu_bridge_unittest.mm
+++ b/chrome/browser/cocoa/history_menu_bridge_unittest.mm
@@ -8,6 +8,7 @@
#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_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/cancelable_request.h"
@@ -18,6 +19,7 @@
#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 {
@@ -132,8 +134,8 @@ TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuUntilEnd) {
ClearMenuSection(menu, HistoryMenuBridge::kMostVisited);
EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_TRUE([@"HEADER" isEqualToString:
- [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]]);
+ EXPECT_NSEQ(@"HEADER",
+ [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]);
}
// Skip menu items that are not hooked up to |-openHistoryMenuItem:|.
@@ -150,10 +152,10 @@ TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuSkipping) {
ClearMenuSection(menu, tag);
EXPECT_EQ(2, [menu numberOfItems]);
- EXPECT_TRUE([@"HEADER" isEqualToString:
- [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]]);
- EXPECT_TRUE([@"TITLE" isEqualToString:
- [[menu itemAtIndex:1] title]]);
+ EXPECT_NSEQ(@"HEADER",
+ [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]);
+ EXPECT_NSEQ(@"TITLE",
+ [[menu itemAtIndex:1] title]);
}
// Edge case test for clearing an empty menu.
@@ -164,8 +166,8 @@ TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuEmpty) {
ClearMenuSection(menu, HistoryMenuBridge::kMostVisited);
EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_TRUE([@"HEADER" isEqualToString:
- [[menu itemWithTag:HistoryMenuBridge::kMostVisited] title]]);
+ EXPECT_NSEQ(@"HEADER",
+ [[menu itemWithTag:HistoryMenuBridge::kMostVisited] title]);
}
// Test that AddItemToMenu() properly adds HistoryItem objects as menus.
@@ -236,13 +238,13 @@ TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabs) {
MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1);
EXPECT_TRUE(hist1);
EXPECT_EQ(24, hist1->session_id);
- EXPECT_TRUE([@"Google" isEqualToString:[item1 title]]);
+ 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_TRUE([@"Apple" isEqualToString:[item2 title]]);
+ EXPECT_NSEQ(@"Apple", [item2 title]);
}
// Test that the menu is created for a mix of windows and tabs.
@@ -296,7 +298,7 @@ TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) {
MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1);
EXPECT_TRUE(hist1);
EXPECT_EQ(24, hist1->session_id);
- EXPECT_TRUE([@"Google" isEqualToString:[item1 title]]);
+ EXPECT_NSEQ(@"Google", [item1 title]);
NSMenuItem* item2 = [menu itemAtIndex:1];
MockBridge::HistoryItem* hist2 = bridge_->HistoryItemForMenuItem(item2);
@@ -308,14 +310,14 @@ TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) {
EXPECT_EQ(4U, [[submenu1 itemArray] count]);
// Do not test Restore All Tabs because it is localiced.
EXPECT_TRUE([[submenu1 itemAtIndex:1] isSeparatorItem]);
- EXPECT_TRUE([@"foo" isEqualToString:[[submenu1 itemAtIndex:2] title]]);
- EXPECT_TRUE([@"bar" isEqualToString:[[submenu1 itemAtIndex:3] title]]);
+ 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_TRUE([@"Apple" isEqualToString:[item3 title]]);
+ EXPECT_NSEQ(@"Apple", [item3 title]);
NSMenuItem* item4 = [menu itemAtIndex:3];
MockBridge::HistoryItem* hist4 = bridge_->HistoryItemForMenuItem(item4);
@@ -327,9 +329,9 @@ TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) {
EXPECT_EQ(5U, [[submenu2 itemArray] count]);
// Do not test Restore All Tabs because it is localiced.
EXPECT_TRUE([[submenu2 itemAtIndex:1] isSeparatorItem]);
- EXPECT_TRUE([@"magic" isEqualToString:[[submenu2 itemAtIndex:2] title]]);
- EXPECT_TRUE([@"goats" isEqualToString:[[submenu2 itemAtIndex:3] title]]);
- EXPECT_TRUE([@"teleporter" isEqualToString:[[submenu2 itemAtIndex:4] title]]);
+ 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.
diff --git a/chrome/browser/cocoa/history_menu_cocoa_controller.h b/chrome/browser/cocoa/history_menu_cocoa_controller.h
index efe7645..4cb6dc6 100644
--- a/chrome/browser/cocoa/history_menu_cocoa_controller.h
+++ b/chrome/browser/cocoa/history_menu_cocoa_controller.h
@@ -8,6 +8,7 @@
#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"
diff --git a/chrome/browser/cocoa/hover_close_button.h b/chrome/browser/cocoa/hover_close_button.h
index 97c49ce..da1180a 100644
--- a/chrome/browser/cocoa/hover_close_button.h
+++ b/chrome/browser/cocoa/hover_close_button.h
@@ -5,25 +5,13 @@
#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 : NSButton {
+@interface HoverCloseButton : HoverButton {
@private
- // Enumeration of the hover states that the close button can be in at any one
- // time. The button cannot be in more than one hover state at a time.
- enum HoverState {
- kHoverStateNone = 0,
- kHoverStateMouseOver = 1,
- kHoverStateMouseDown = 2
- };
-
- HoverState hoverState_;
-
- // Tracking area for close button mouseover states.
- scoped_nsobject<NSTrackingArea> closeTrackingArea_;
-
// Bezier path for drawing the 'x' within the button.
scoped_nsobject<NSBezierPath> xPath_;
@@ -31,17 +19,8 @@
scoped_nsobject<NSBezierPath> circlePath_;
}
-// Enables or disables the |NSTrackingRect|s for the button.
-- (void)setTrackingEnabled:(BOOL)enabled;
-
// Sets up the button's tracking areas and accessibility info when instantiated
// via initWithFrame or awakeFromNib.
- (void)commonInit;
-// Checks to see whether the mouse is in the button's bounds and update
-// the image in case it gets out of sync. This occurs when you close a
-// tab so the tab to the left of it takes its place, and drag the button
-// without moving the mouse before you press the button down.
-- (void)checkImageState;
-
@end
diff --git a/chrome/browser/cocoa/hover_close_button.mm b/chrome/browser/cocoa/hover_close_button.mm
index 14571a7..7620e95 100644
--- a/chrome/browser/cocoa/hover_close_button.mm
+++ b/chrome/browser/cocoa/hover_close_button.mm
@@ -36,6 +36,7 @@ const CGFloat kXShadowCircleAlpha = 0.1;
}
- (void)awakeFromNib {
+ [super awakeFromNib];
[self commonInit];
}
@@ -70,10 +71,6 @@ const CGFloat kXShadowCircleAlpha = 0.1;
}
- (void)commonInit {
- [self setTrackingEnabled:YES];
- hoverState_ = kHoverStateNone;
- [self updateTrackingAreas];
-
// Set accessibility description.
NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_CLOSE);
[[self cell]
@@ -108,77 +105,4 @@ const CGFloat kXShadowCircleAlpha = 0.1;
[xPath_ transformUsingAffineTransform:transform];
}
-- (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<HoverCloseButton> 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) {
- closeTrackingArea_.reset(
- [[NSTrackingArea alloc] initWithRect:[self bounds]
- options:NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways
- owner:self
- userInfo:nil]);
- [self addTrackingArea:closeTrackingArea_.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 (closeTrackingArea_.get()) {
- [self removeTrackingArea:closeTrackingArea_.get()];
- closeTrackingArea_.reset(nil);
- }
- }
-}
-
-- (void)updateTrackingAreas {
- [super updateTrackingAreas];
- [self checkImageState];
-}
-
-- (void)checkImageState {
- if (!closeTrackingArea_.get())
- return;
-
- // Update the close buttons if the tab 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/html_dialog_window_controller.h b/chrome/browser/cocoa/html_dialog_window_controller.h
index 9c871b1..ae2e109 100644
--- a/chrome/browser/cocoa/html_dialog_window_controller.h
+++ b/chrome/browser/cocoa/html_dialog_window_controller.h
@@ -1,12 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
-
-#include <string>
-#include <vector>
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/html_dialog_window_controller.mm b/chrome/browser/cocoa/html_dialog_window_controller.mm
index 75c6b6e..b959798 100644
--- a/chrome/browser/cocoa/html_dialog_window_controller.mm
+++ b/chrome/browser/cocoa/html_dialog_window_controller.mm
@@ -4,7 +4,7 @@
#import "chrome/browser/cocoa/html_dialog_window_controller.h"
-#include "base/keyboard_codes.h"
+#include "app/keyboard_codes.h"
#include "base/logging.h"
#include "base/scoped_nsobject.h"
#include "base/sys_string_conversions.h"
@@ -14,6 +14,7 @@
#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"
@@ -193,8 +194,8 @@ void HtmlDialogWindowDelegateBridge::HandleKeyboardEvent(
// 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 == base::VKEY_ESCAPE) ||
- (event.windowsKeyCode == base::VKEY_OEM_PERIOD &&
+ ((event.windowsKeyCode == app::VKEY_ESCAPE) ||
+ (event.windowsKeyCode == app::VKEY_OEM_PERIOD &&
event.modifiers == NativeWebKeyboardEvent::MetaKey))) {
[controller_ close];
return;
@@ -264,8 +265,8 @@ void HtmlDialogWindowDelegateBridge::HandleKeyboardEvent(
}
- (void)loadDialogContents {
- tabContents_.reset(
- new TabContents(delegate_->profile(), NULL, MSG_ROUTING_NONE, NULL));
+ tabContents_.reset(new TabContents(
+ delegate_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL));
[[self window] setContentView:tabContents_->GetNativeView()];
tabContents_->set_delegate(delegate_.get());
diff --git a/chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h b/chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h
index 9bcd975..41279ff 100644
--- a/chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h
+++ b/chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/html_dialog_window_controller_unittest.mm b/chrome/browser/cocoa/html_dialog_window_controller_unittest.mm
index 8b64443..2ec3f6f 100644
--- a/chrome/browser/cocoa/html_dialog_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/html_dialog_window_controller_unittest.mm
@@ -15,6 +15,7 @@
#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"
@@ -40,6 +41,7 @@ class HtmlDialogWindowControllerTest : public BrowserWithTestWindowTest {
public:
virtual void SetUp() {
BrowserWithTestWindowTest::SetUp();
+ CocoaTest::BootstrapCocoa();
title_ = L"Mock Title";
size_ = gfx::Size(50, 100);
gurl_ = GURL("");
@@ -51,7 +53,6 @@ class HtmlDialogWindowControllerTest : public BrowserWithTestWindowTest {
GURL gurl_;
// Order here is important.
- CocoaTestHelper cocoa_helper_;
MockDelegate delegate_;
};
@@ -65,8 +66,7 @@ using ::testing::SetArgumentPointee;
TEST_F(HtmlDialogWindowControllerTest, showDialog) {
// We want to make sure html_dialog_window_controller below gets
- // destroyed before cocoa_helper_ and delegate_, so we specify our
- // own autorelease pool.
+ // 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.
diff --git a/chrome/browser/cocoa/hung_renderer_controller.h b/chrome/browser/cocoa/hung_renderer_controller.h
index b9cad53..8635a53 100644
--- a/chrome/browser/cocoa/hung_renderer_controller.h
+++ b/chrome/browser/cocoa/hung_renderer_controller.h
@@ -1,9 +1,10 @@
-// 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.
#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
@@ -19,8 +20,6 @@
#import <Cocoa/Cocoa.h>
-#include <vector>
-
#import "base/cocoa_protocols_mac.h"
#import "base/scoped_nsobject.h"
diff --git a/chrome/browser/cocoa/image_utils.h b/chrome/browser/cocoa/image_utils.h
index 36a3bb4..22ed80e 100644
--- a/chrome/browser/cocoa/image_utils.h
+++ b/chrome/browser/cocoa/image_utils.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_IMAGE_UTILS_H_
#define CHROME_BROWSER_COCOA_IMAGE_UTILS_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/image_utils_unittest.mm b/chrome/browser/cocoa/image_utils_unittest.mm
index 4398371..4d97ed1 100644
--- a/chrome/browser/cocoa/image_utils_unittest.mm
+++ b/chrome/browser/cocoa/image_utils_unittest.mm
@@ -103,11 +103,7 @@ class ImageUtilTest : public CocoaTest {
[[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
[view_ unlockFocus];
- scoped_nsobject<NSImage> image(
- [[NSImage alloc] initWithSize:bounds.size]);
- [image addRepresentation:bitmap];
-
- return [image TIFFRepresentation];
+ return [bitmap TIFFRepresentation];
}
NSData* SnapshotViewBase() {
diff --git a/chrome/browser/cocoa/import_progress_dialog.h b/chrome/browser/cocoa/import_progress_dialog.h
index f3f69a1..c1b405b 100644
--- a/chrome/browser/cocoa/import_progress_dialog.h
+++ b/chrome/browser/cocoa/import_progress_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORT_PROGRESS_DIALOG_H_
#define CHROME_BROWSER_IMPORT_PROGRESS_DIALOG_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/import_progress_dialog.mm b/chrome/browser/cocoa/import_progress_dialog.mm
index 83da1d3..109365b 100644
--- a/chrome/browser/cocoa/import_progress_dialog.mm
+++ b/chrome/browser/cocoa/import_progress_dialog.mm
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/import_settings_dialog.h b/chrome/browser/cocoa/import_settings_dialog.h
index 908c7de..d31433c 100644
--- a/chrome/browser/cocoa/import_settings_dialog.h
+++ b/chrome/browser/cocoa/import_settings_dialog.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_COCOA_IMPORT_SETTINGS_DIALOG_H_
#define CHROME_BROWSER_COCOA_IMPORT_SETTINGS_DIALOG_H_
+#pragma once
#import <Cocoa/Cocoa.h>
-#include "base/ref_counted.h"
#include "base/scoped_nsobject.h"
#include "chrome/browser/importer/importer.h"
diff --git a/chrome/browser/cocoa/importer_lock_dialog.h b/chrome/browser/cocoa/importer_lock_dialog.h
index f526818..adf3a55 100644
--- a/chrome/browser/cocoa/importer_lock_dialog.h
+++ b/chrome/browser/cocoa/importer_lock_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_IMPORTER_LOCK_DIALOG_H_
#define CHROME_BROWSER_COCOA_IMPORTER_LOCK_DIALOG_H_
+#pragma once
class ImporterHost;
diff --git a/chrome/browser/cocoa/info_bubble_view.h b/chrome/browser/cocoa/info_bubble_view.h
index 2cd5119..58e33ff 100644
--- a/chrome/browser/cocoa/info_bubble_view.h
+++ b/chrome/browser/cocoa/info_bubble_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_INFO_BUBBLE_VIEW_H_
#define CHROME_BROWSER_COCOA_INFO_BUBBLE_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -21,8 +22,9 @@ enum BubbleArrowLocation {
};
enum InfoBubbleType {
- kGradientInfoBubble,
- kWhiteInfoBubble
+ kWhiteInfoBubble,
+ // Gradient bubbles are deprecated, per alcor@google.com. Please use white.
+ kGradientInfoBubble
};
} // namespace info_bubble
diff --git a/chrome/browser/cocoa/info_bubble_view.mm b/chrome/browser/cocoa/info_bubble_view.mm
index 7a90513..b54e875 100644
--- a/chrome/browser/cocoa/info_bubble_view.mm
+++ b/chrome/browser/cocoa/info_bubble_view.mm
@@ -16,7 +16,7 @@
- (id)initWithFrame:(NSRect)frameRect {
if ((self = [super initWithFrame:frameRect])) {
arrowLocation_ = info_bubble::kTopLeft;
- bubbleType_ = info_bubble::kGradientInfoBubble;
+ bubbleType_ = info_bubble::kWhiteInfoBubble;
}
return self;
diff --git a/chrome/browser/cocoa/infobar.h b/chrome/browser/cocoa/infobar.h
index 0ebd2a9..9c8ed05 100644
--- a/chrome/browser/cocoa/infobar.h
+++ b/chrome/browser/cocoa/infobar.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_INFOBAR_H_
#define CHROME_BROWSER_COCOA_INFOBAR_H_
+#pragma once
#include "base/logging.h" // for DCHECK
diff --git a/chrome/browser/cocoa/infobar_container_controller.h b/chrome/browser/cocoa/infobar_container_controller.h
index 81e82f4..495b6e8 100644
--- a/chrome/browser/cocoa/infobar_container_controller.h
+++ b/chrome/browser/cocoa/infobar_container_controller.h
@@ -2,6 +2,10 @@
// 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"
@@ -14,7 +18,6 @@ class InfoBarDelegate;
class InfoBarNotificationObserver;
class TabContents;
class TabStripModel;
-class TabStripModelObserverBridge;
// Protocol for basic container methods, as needed by an InfoBarController.
// This protocol exists to make mocking easier in unittests.
@@ -40,9 +43,6 @@ class TabStripModelObserverBridge;
// Holds the InfoBarControllers currently owned by this container.
scoped_nsobject<NSMutableArray> infobarControllers_;
- // Lets us get TabChanged/TabDetachedAt notifications.
- scoped_ptr<TabStripModelObserverBridge> tabObserver_;
-
// Lets us registers for INFOBAR_ADDED/INFOBAR_REMOVED
// notifications. The actual notifications are sent to the
// InfoBarNotificationObserver object, which proxies them back to us.
@@ -50,8 +50,7 @@ class TabStripModelObserverBridge;
scoped_ptr<InfoBarNotificationObserver> infoBarObserver_;
}
-- (id)initWithTabStripModel:(TabStripModel*)model
- resizeDelegate:(id<ViewResizer>)resizeDelegate;
+- (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
@@ -65,6 +64,19 @@ class TabStripModelObserverBridge;
// |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
@@ -97,3 +109,5 @@ class TabStripModelObserverBridge;
- (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
index 374d920..7fe8aed 100644
--- a/chrome/browser/cocoa/infobar_container_controller.mm
+++ b/chrome/browser/cocoa/infobar_container_controller.mm
@@ -8,7 +8,6 @@
#include "chrome/browser/cocoa/infobar.h"
#import "chrome/browser/cocoa/infobar_container_controller.h"
#import "chrome/browser/cocoa/infobar_controller.h"
-#include "chrome/browser/cocoa/tab_strip_model_observer_bridge.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"
@@ -64,25 +63,15 @@ class InfoBarNotificationObserver : public NotificationObserver {
// adding together the heights of all its subviews.
- (CGFloat)desiredHeight;
-// 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;
-
@end
@implementation InfoBarContainerController
-- (id)initWithTabStripModel:(TabStripModel*)model
- resizeDelegate:(id<ViewResizer>)resizeDelegate {
+- (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate {
DCHECK(resizeDelegate);
if ((self = [super initWithNibName:@"InfoBarContainer"
bundle:mac_util::MainAppBundle()])) {
resizeDelegate_ = resizeDelegate;
- tabObserver_.reset(new TabStripModelObserverBridge(model, self));
infoBarObserver_.reset(new InfoBarNotificationObserver(self));
// NSMutableArray needs an initial capacity, and we rarely ever see
@@ -122,16 +111,30 @@ class InfoBarNotificationObserver : public NotificationObserver {
[self positionInfoBarsAndRedraw];
}
-// TabStripModelObserverBridge notifications
-- (void)selectTabWithContents:(TabContents*)newContents
- previousContents:(TabContents*)oldContents
- atIndex:(NSInteger)index
- userGesture:(bool)wasUserGesture {
- [self changeTabContents:newContents];
+- (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
- atIndex:(NSInteger)index {
+- (void)tabDetachedWithContents:(TabContents*)contents {
if (currentTabContents_ == contents)
[self changeTabContents:NULL];
}
@@ -159,29 +162,6 @@ class InfoBarNotificationObserver : public NotificationObserver {
return height;
}
-- (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)addInfoBar:(InfoBarDelegate*)delegate animate:(BOOL)animate {
scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar());
InfoBarController* controller = infobar->controller();
diff --git a/chrome/browser/cocoa/infobar_container_controller_unittest.mm b/chrome/browser/cocoa/infobar_container_controller_unittest.mm
index 569ed72..b9f74c7 100644
--- a/chrome/browser/cocoa/infobar_container_controller_unittest.mm
+++ b/chrome/browser/cocoa/infobar_container_controller_unittest.mm
@@ -5,7 +5,6 @@
#import <Cocoa/Cocoa.h>
#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.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"
@@ -19,11 +18,9 @@ class InfoBarContainerControllerTest : public CocoaTest {
virtual void SetUp() {
CocoaTest::SetUp();
resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- TabStripModel* model = browser_helper_.browser()->tabstrip_model();
ViewResizerPong *viewResizer = resizeDelegate_.get();
controller_ =
- [[InfoBarContainerController alloc] initWithTabStripModel:model
- resizeDelegate:viewResizer];
+ [[InfoBarContainerController alloc] initWithResizeDelegate:viewResizer];
NSView* view = [controller_ view];
[[test_window() contentView] addSubview:view];
}
@@ -35,7 +32,6 @@ class InfoBarContainerControllerTest : public CocoaTest {
}
public:
- BrowserTestHelper browser_helper_;
scoped_nsobject<ViewResizerPong> resizeDelegate_;
InfoBarContainerController* controller_;
};
diff --git a/chrome/browser/cocoa/infobar_controller.mm b/chrome/browser/cocoa/infobar_controller.mm
index cd7d14d..8ccc9c5 100644
--- a/chrome/browser/cocoa/infobar_controller.mm
+++ b/chrome/browser/cocoa/infobar_controller.mm
@@ -244,7 +244,10 @@ const float kAnimateCloseDuration = 0.12;
}
- (void)removeInfoBar {
- DCHECK(delegate_);
+ // 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_];
}
@@ -344,7 +347,7 @@ const float kAnimateCloseDuration = 0.12;
// Insert the text.
AlertInfoBarDelegate* delegate = delegate_->AsAlertInfoBarDelegate();
DCHECK(delegate);
- [self setLabelToMessage:base::SysWideToNSString(delegate->GetMessageText())];
+ [self setLabelToMessage:base::SysUTF16ToNSString(delegate->GetMessageText())];
}
@end
@@ -368,9 +371,9 @@ const float kAnimateCloseDuration = 0.12;
LinkInfoBarDelegate* delegate = delegate_->AsLinkInfoBarDelegate();
DCHECK(delegate);
size_t offset = std::wstring::npos;
- std::wstring message = delegate->GetMessageTextWithOffset(&offset);
- [self setLabelToMessage:base::SysWideToNSString(message)
- withLink:base::SysWideToNSString(delegate->GetLinkText())
+ string16 message = delegate->GetMessageTextWithOffset(&offset);
+ [self setLabelToMessage:base::SysUTF16ToNSString(message)
+ withLink:base::SysUTF16ToNSString(delegate->GetLinkText())
atOffset:offset];
}
@@ -426,7 +429,7 @@ const float kAnimateCloseDuration = 0.12;
// Update and position the Cancel button if needed. Otherwise, hide it.
if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
- [cancelButton_ setTitle:base::SysWideToNSString(
+ [cancelButton_ setTitle:base::SysUTF16ToNSString(
delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL))];
[GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_];
cancelButtonFrame = [cancelButton_ frame];
@@ -443,7 +446,7 @@ const float kAnimateCloseDuration = 0.12;
// Update and position the OK button if needed. Otherwise, hide it.
if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK) {
- [okButton_ setTitle:base::SysWideToNSString(
+ [okButton_ setTitle:base::SysUTF16ToNSString(
delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK))];
[GTMUILocalizerAndLayoutTweaker sizeToFitView:okButton_];
okButtonFrame = [okButton_ frame];
@@ -477,8 +480,8 @@ const float kAnimateCloseDuration = 0.12;
[label_.get() setFrame:frame];
// Set the text and link.
- NSString* message = base::SysWideToNSString(delegate->GetMessageText());
- std::wstring link = delegate->GetLinkText();
+ 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];
@@ -490,7 +493,7 @@ const float kAnimateCloseDuration = 0.12;
// Add spacing between the label and the link.
message = [message stringByAppendingString:@" "];
[self setLabelToMessage:message
- withLink:base::SysWideToNSString(link)
+ withLink:base::SysUTF16ToNSString(link)
atOffset:[message length]];
}
}
diff --git a/chrome/browser/cocoa/infobar_controller_unittest.mm b/chrome/browser/cocoa/infobar_controller_unittest.mm
index ec7bf1e..114a94c 100644
--- a/chrome/browser/cocoa/infobar_controller_unittest.mm
+++ b/chrome/browser/cocoa/infobar_controller_unittest.mm
@@ -134,8 +134,8 @@ TEST_F(AlertInfoBarControllerTest, ShowAndDismiss) {
EXPECT_TRUE(delegate_.icon_accessed);
// Check to make sure the infobar message was set properly.
- EXPECT_EQ(std::wstring(kMockAlertInfoBarMessage),
- base::SysNSStringToWide([controller_.get() labelString]));
+ EXPECT_EQ(kMockAlertInfoBarMessage,
+ base::SysNSStringToUTF8([controller_.get() labelString]));
// Check that dismissing the infobar calls InfoBarClosed() on the delegate.
[controller_ dismiss:nil];
@@ -204,8 +204,8 @@ TEST_F(ConfirmInfoBarControllerTest, ShowAndDismiss) {
EXPECT_TRUE(delegate_.icon_accessed);
// Check to make sure the infobar message was set properly.
- EXPECT_EQ(std::wstring(kMockConfirmInfoBarMessage),
- base::SysNSStringToWide([controller_.get() labelString]));
+ EXPECT_EQ(kMockConfirmInfoBarMessage,
+ base::SysNSStringToUTF8([controller_.get() labelString]));
// Check that dismissing the infobar calls InfoBarClosed() on the delegate.
[controller_ dismiss:nil];
diff --git a/chrome/browser/cocoa/infobar_gradient_view.h b/chrome/browser/cocoa/infobar_gradient_view.h
index 27c303d..c5f3c1d 100644
--- a/chrome/browser/cocoa/infobar_gradient_view.h
+++ b/chrome/browser/cocoa/infobar_gradient_view.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/infobar_gradient_view.mm b/chrome/browser/cocoa/infobar_gradient_view.mm
index 1dc0b7c..180a286 100644
--- a/chrome/browser/cocoa/infobar_gradient_view.mm
+++ b/chrome/browser/cocoa/infobar_gradient_view.mm
@@ -5,8 +5,8 @@
#include "chrome/browser/cocoa/infobar_gradient_view.h"
#include "base/scoped_nsobject.h"
-#import "chrome/browser/browser_theme_provider.h"
#import "chrome/browser/cocoa/themed_window.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
namespace {
diff --git a/chrome/browser/cocoa/infobar_test_helper.h b/chrome/browser/cocoa/infobar_test_helper.h
index d83bdc1..d01a71b 100644
--- a/chrome/browser/cocoa/infobar_test_helper.h
+++ b/chrome/browser/cocoa/infobar_test_helper.h
@@ -4,11 +4,13 @@
#include "chrome/browser/tab_contents/infobar_delegate.h"
+#include "base/utf_string_conversions.h"
+
namespace {
-const wchar_t* kMockAlertInfoBarMessage = L"MockAlertInfoBarMessage";
-const wchar_t* kMockLinkInfoBarMessage = L"MockLinkInfoBarMessage";
-const wchar_t* kMockLinkInfoBarLink = L"http://dev.chromium.org";
-const wchar_t* kMockConfirmInfoBarMessage = L"MockConfirmInfoBarMessage";
+const char kMockAlertInfoBarMessage[] = "MockAlertInfoBarMessage";
+const char kMockLinkInfoBarMessage[] = "MockLinkInfoBarMessage";
+const char kMockLinkInfoBarLink[] = "http://dev.chromium.org";
+const char kMockConfirmInfoBarMessage[] = "MockConfirmInfoBarMessage";
}
//////////////////////////////////////////////////////////////////////////
@@ -23,9 +25,9 @@ class MockAlertInfoBarDelegate : public AlertInfoBarDelegate {
closed(false) {
}
- virtual std::wstring GetMessageText() const {
+ virtual string16 GetMessageText() const {
message_text_accessed = true;
- return kMockAlertInfoBarMessage;
+ return ASCIIToUTF16(kMockAlertInfoBarMessage);
}
virtual SkBitmap* GetIcon() const {
@@ -55,14 +57,14 @@ class MockLinkInfoBarDelegate : public LinkInfoBarDelegate {
closes_on_action(true) {
}
- virtual std::wstring GetMessageTextWithOffset(size_t* link_offset) const {
+ virtual string16 GetMessageTextWithOffset(size_t* link_offset) const {
message_text_accessed = true;
- return kMockLinkInfoBarMessage;
+ return ASCIIToUTF16(kMockLinkInfoBarMessage);
}
- virtual std::wstring GetLinkText() const {
+ virtual string16 GetLinkText() const {
link_text_accessed = true;
- return kMockLinkInfoBarLink;
+ return ASCIIToUTF16(kMockLinkInfoBarLink);
}
virtual SkBitmap* GetIcon() const {
@@ -108,11 +110,11 @@ class MockConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
return (BUTTON_OK | BUTTON_CANCEL);
}
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
if (button == BUTTON_OK)
- return L"OK";
+ return ASCIIToUTF16("OK");
else
- return L"Cancel";
+ return ASCIIToUTF16("Cancel");
}
virtual bool Accept() {
@@ -125,9 +127,9 @@ class MockConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
return closes_on_action;
}
- virtual std::wstring GetMessageText() const {
+ virtual string16 GetMessageText() const {
message_text_accessed = true;
- return kMockConfirmInfoBarMessage;
+ return ASCIIToUTF16(kMockConfirmInfoBarMessage);
}
virtual SkBitmap* GetIcon() const {
@@ -139,9 +141,9 @@ class MockConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
closed = true;
}
- virtual std::wstring GetLinkText() {
+ virtual string16 GetLinkText() {
link_text_accessed = true;
- return std::wstring();
+ return string16();
}
virtual bool LinkClicked(WindowOpenDisposition disposition) {
diff --git a/chrome/browser/cocoa/install_from_dmg.h b/chrome/browser/cocoa/install_from_dmg.h
index 437973d..ec9248a 100644
--- a/chrome/browser/cocoa/install_from_dmg.h
+++ b/chrome/browser/cocoa/install_from_dmg.h
@@ -4,6 +4,7 @@
#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
diff --git a/chrome/browser/cocoa/install_from_dmg.mm b/chrome/browser/cocoa/install_from_dmg.mm
index 27ffa38..cffe3fc 100644
--- a/chrome/browser/cocoa/install_from_dmg.mm
+++ b/chrome/browser/cocoa/install_from_dmg.mm
@@ -13,6 +13,7 @@
#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"
diff --git a/chrome/browser/cocoa/keystone_glue.h b/chrome/browser/cocoa/keystone_glue.h
index fb16171..69b5351 100644
--- a/chrome/browser/cocoa/keystone_glue.h
+++ b/chrome/browser/cocoa/keystone_glue.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_KEYSTONE_GLUE_H_
#define CHROME_BROWSER_COCOA_KEYSTONE_GLUE_H_
+#pragma once
#include "base/string16.h"
diff --git a/chrome/browser/cocoa/keystone_glue.mm b/chrome/browser/cocoa/keystone_glue.mm
index a097fd7..a0162a3 100644
--- a/chrome/browser/cocoa/keystone_glue.mm
+++ b/chrome/browser/cocoa/keystone_glue.mm
@@ -9,6 +9,7 @@
#include <vector>
+#include "app/l10n_util.h"
#import "app/l10n_util_mac.h"
#include "base/logging.h"
#include "base/mac_util.h"
diff --git a/chrome/browser/cocoa/keystone_infobar.h b/chrome/browser/cocoa/keystone_infobar.h
index 60083b9..9a89027 100644
--- a/chrome/browser/cocoa/keystone_infobar.h
+++ b/chrome/browser/cocoa/keystone_infobar.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_KEYSTONE_INFOBAR_H_
#define CHROME_BROWSER_COCOA_KEYSTONE_INFOBAR_H_
+#pragma once
class Profile;
diff --git a/chrome/browser/cocoa/keystone_infobar.mm b/chrome/browser/cocoa/keystone_infobar.mm
index 2cf13e5..8e6126c 100644
--- a/chrome/browser/cocoa/keystone_infobar.mm
+++ b/chrome/browser/cocoa/keystone_infobar.mm
@@ -16,8 +16,8 @@
#import "chrome/browser/cocoa/keystone_glue.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/first_run.h"
-#include "chrome/browser/pref_service.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"
@@ -62,9 +62,9 @@ class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate {
// Inherited from AlertInfoBarDelegate and overridden.
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetStringF(IDS_PROMOTE_INFOBAR_TEXT,
- l10n_util::GetString(IDS_PRODUCT_NAME));
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_PROMOTE_INFOBAR_TEXT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
}
virtual SkBitmap* GetIcon() const {
@@ -78,10 +78,10 @@ class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate {
return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
}
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
return button == BUTTON_OK ?
- l10n_util::GetString(IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON) :
- l10n_util::GetString(IDS_PROMOTE_INFOBAR_DONT_ASK_BUTTON);
+ l10n_util::GetStringUTF16(IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON) :
+ l10n_util::GetStringUTF16(IDS_PROMOTE_INFOBAR_DONT_ASK_BUTTON);
}
virtual bool Accept() {
diff --git a/chrome/browser/cocoa/keyword_editor_cocoa_controller.h b/chrome/browser/cocoa/keyword_editor_cocoa_controller.h
index 647b200..d833cec 100644
--- a/chrome/browser/cocoa/keyword_editor_cocoa_controller.h
+++ b/chrome/browser/cocoa/keyword_editor_cocoa_controller.h
@@ -7,10 +7,11 @@
#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.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
class EditSearchEngineControllerDelegate;
@class KeywordEditorCocoaController;
@@ -35,8 +36,8 @@ class KeywordEditorModelObserver : public TemplateURLModelObserver,
// indicates a new TemplateURL should be created rather than modifying an
// existing TemplateURL.
virtual void OnEditedKeyword(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url);
// TableModelObserver overrides. Invalidate icon cache.
diff --git a/chrome/browser/cocoa/keyword_editor_cocoa_controller.mm b/chrome/browser/cocoa/keyword_editor_cocoa_controller.mm
index 21c7a20..20a3c93 100644
--- a/chrome/browser/cocoa/keyword_editor_cocoa_controller.mm
+++ b/chrome/browser/cocoa/keyword_editor_cocoa_controller.mm
@@ -12,13 +12,15 @@
#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/pref_service.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 {
@@ -50,8 +52,8 @@ void KeywordEditorModelObserver::OnTemplateURLModelChanged() {
void KeywordEditorModelObserver::OnEditedKeyword(
const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url) {
KeywordEditorController* controller = [controller_ controller];
if (template_url) {
@@ -156,8 +158,7 @@ typedef std::map<Profile*,KeywordEditorCocoaController*> ProfileControllerMap;
sizeSaver_.reset([[WindowSizeAutosaver alloc]
initWithWindow:[self window]
prefService:g_browser_process->local_state()
- path:prefs::kKeywordEditorWindowPlacement
- state:kSaveWindowRect]);
+ path:prefs::kKeywordEditorWindowPlacement]);
}
}
return self;
diff --git a/chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm b/chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm
index 2ea9648..7c7610d 100644
--- a/chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm
+++ b/chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm
@@ -8,6 +8,8 @@
#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/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/cocoa/location_bar/autocomplete_text_field.h
index 0340874..0c8f060 100644
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field.h
+++ b/chrome/browser/cocoa/location_bar/autocomplete_text_field.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
#define CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -89,6 +90,9 @@ class AutocompleteTextFieldObserver {
// Called whenever the autocomplete text field is losing focus.
virtual void OnKillFocus() = 0;
+
+ protected:
+ virtual ~AutocompleteTextFieldObserver() {}
};
@interface AutocompleteTextField : StyledTextField<NSTextViewDelegate,
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field.mm
index afb5d91..4f18f68 100644
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field.mm
+++ b/chrome/browser/cocoa/location_bar/autocomplete_text_field.mm
@@ -27,6 +27,8 @@
- (void)awakeFromNib {
DCHECK([[self cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
+ [[self cell] setTruncatesLastVisibleLine:YES];
+ [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail];
currentToolTips_.reset([[NSMutableArray alloc] init]);
}
@@ -251,27 +253,6 @@
}
}
-- (BOOL)textView:(NSTextView*)textView doCommandBySelector:(SEL)cmd {
- // TODO(shess): Review code for cases where we're fruitlessly attempting to
- // work in spite of not having an observer_.
- if (observer_ && observer_->OnDoCommandBySelector(cmd)) {
- return YES;
- }
-
- // 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 YES;
- }
- }
-
- return NO;
-}
-
// When the window resigns, make sure the autocomplete popup is no
// longer visible, since the user's focus is elsewhere.
- (void)windowDidResignKey:(NSNotification*)notification {
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm
index 8acb8ba..5d1742b 100644
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm
+++ b/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm
@@ -11,17 +11,18 @@
namespace {
-const CGFloat kBaselineAdjust = 2.0;
+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 = 3.0;
+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|?
-const CGFloat kRightDecorationXOffset = 4.0;
+// |kDecorationOuterXOffset|?
+const CGFloat kRightDecorationXOffset = 5.0;
// The amount of padding on either side reserved for drawing
// decorations. [Views has |kItemPadding| == 3.]
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm
index 9304474..4904e50 100644
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm
+++ b/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm
@@ -271,6 +271,17 @@
[self didChangeText];
}
+- (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;
@@ -297,6 +308,33 @@
}
}
+- (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);
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
index 543d4fa..cfb1595 100644
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
+++ b/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
@@ -14,6 +14,7 @@
#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"
@@ -63,7 +64,12 @@ class AutocompleteTextFieldEditorTest : public CocoaTest {
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) {
@@ -73,28 +79,28 @@ TEST_F(AutocompleteTextFieldEditorTest, InsertStripsControlChars) {
[editor_ selectAll:nil];
[editor_ insertText:@"t"];
- EXPECT_TRUE([[field_ stringValue] isEqualToString:@"t"]);
+ EXPECT_NSEQ(@"t", [field_ stringValue]);
[editor_ insertText:@"h"];
- EXPECT_TRUE([[field_ stringValue] isEqualToString:@"th"]);
+ EXPECT_NSEQ(@"th", [field_ stringValue]);
// TAB doesn't get inserted.
[editor_ insertText:[NSString stringWithFormat:@"%c", 7]];
- EXPECT_TRUE([[field_ stringValue] isEqualToString:@"th"]);
+ EXPECT_NSEQ(@"th", [field_ stringValue]);
// Newline doesn't get inserted.
[editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
- EXPECT_TRUE([[field_ stringValue] isEqualToString:@"th"]);
+ EXPECT_NSEQ(@"th", [field_ stringValue]);
// Multi-character strings get through.
[editor_ insertText:[NSString stringWithFormat:@"i%cs%c", 8, 127]];
- EXPECT_TRUE([[field_ stringValue] isEqualToString:@"this"]);
+ 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_TRUE([[field_ stringValue] isEqualToString:@""]);
+ EXPECT_NSEQ(@"", [field_ stringValue]);
}
// Test that |delegate| can provide page action menus.
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm
index 341058c..f39400e 100644
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm
+++ b/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm
@@ -16,6 +16,7 @@
#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::InSequence;
@@ -427,7 +428,7 @@ TEST_F(AutocompleteTextFieldTest, ClickBorderSelectsAll) {
TEST_F(AutocompleteTextFieldTest, ClickSelectsAll) {
EXPECT_FALSE([field_ currentEditor]);
- const NSPoint point(NSMakePoint(20.0, 5.0));
+ 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];
@@ -468,7 +469,7 @@ TEST_F(AutocompleteTextFieldTest, ClickDragSelectsText) {
TEST_F(AutocompleteTextFieldTest, DoubleClickSelectsWord) {
EXPECT_FALSE([field_ currentEditor]);
- const NSPoint point(NSMakePoint(20.0, 5.0));
+ 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));
@@ -654,11 +655,11 @@ TEST_F(AutocompleteTextFieldTest, SetAttributedStringBaseline) {
attributes:attributes]);
// Check that what we get back looks like what we put in.
- EXPECT_FALSE([[field_ stringValue] isEqualToString:kString]);
+ EXPECT_NSNE(kString, [field_ stringValue]);
[field_ setAttributedStringValue:attributedString];
EXPECT_TRUE([[field_ attributedStringValue]
isEqualToAttributedString:attributedString]);
- EXPECT_TRUE([[field_ stringValue] isEqualToString:kString]);
+ EXPECT_NSEQ(kString, [field_ stringValue]);
// Try that again with focus.
[test_window() makePretendKeyWindowAndSetFirstResponder:field_];
@@ -667,11 +668,11 @@ TEST_F(AutocompleteTextFieldTest, SetAttributedStringBaseline) {
// Check that what we get back looks like what we put in.
[field_ setStringValue:@""];
- EXPECT_FALSE([[field_ stringValue] isEqualToString:kString]);
+ EXPECT_NSNE(kString, [field_ stringValue]);
[field_ setAttributedStringValue:attributedString];
EXPECT_TRUE([[field_ attributedStringValue]
isEqualToAttributedString:attributedString]);
- EXPECT_TRUE([[field_ stringValue] isEqualToString:kString]);
+ EXPECT_NSEQ(kString, [field_ stringValue]);
}
// -setAttributedStringValue: shouldn't reset the undo state if things
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
index 3b96e08..eb78594 100644
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
+++ b/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
@@ -4,6 +4,7 @@
#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>
diff --git a/chrome/browser/cocoa/location_bar/bubble_decoration.h b/chrome/browser/cocoa/location_bar/bubble_decoration.h
index 224050f..8be1aa7 100644
--- a/chrome/browser/cocoa/location_bar/bubble_decoration.h
+++ b/chrome/browser/cocoa/location_bar/bubble_decoration.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
#define CHROME_BROWSER_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -21,6 +22,7 @@ class BubbleDecoration : public LocationBarDecoration {
~BubbleDecoration();
// Setup the drawing parameters.
+ NSImage* GetImage();
void SetImage(NSImage* image);
void SetLabel(NSString* label);
void SetColors(NSColor* border_color,
@@ -45,7 +47,7 @@ class BubbleDecoration : public LocationBarDecoration {
FRIEND_TEST_ALL_PREFIXES(SelectedKeywordDecorationTest,
UsesPartialKeywordIfNarrow);
- // Contains font attribute for drawing |label_|.
+ // Contains font and color attribute for drawing |label_|.
scoped_nsobject<NSDictionary> attributes_;
// Image drawn in the left side of the bubble.
@@ -58,7 +60,6 @@ class BubbleDecoration : public LocationBarDecoration {
// constructor.
scoped_nsobject<NSColor> background_color_;
scoped_nsobject<NSColor> border_color_;
- scoped_nsobject<NSColor> text_color_;
DISALLOW_COPY_AND_ASSIGN(BubbleDecoration);
};
diff --git a/chrome/browser/cocoa/location_bar/bubble_decoration.mm b/chrome/browser/cocoa/location_bar/bubble_decoration.mm
index 5e2a9ad..79570a5 100644
--- a/chrome/browser/cocoa/location_bar/bubble_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/bubble_decoration.mm
@@ -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 <cmath>
+
#import "chrome/browser/cocoa/location_bar/bubble_decoration.h"
#include "base/logging.h"
@@ -10,10 +12,24 @@
namespace {
// Padding between the icon/label and bubble edges.
-const CGFloat kBubblePadding = 7.0;
+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;
-// How far to inset the keywork token from sides.
-const NSInteger kKeywordYInset = 4;
+// 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
@@ -39,14 +55,23 @@ CGFloat BubbleDecoration::GetWidthForImageAndLabel(NSImage* image,
if (!label)
return kBubblePadding + image_width;
- const CGFloat label_width = [label sizeWithAttributes:attributes_].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, kKeywordYInset);
- if (image_)
- imageRect.size = [image_ size];
+ 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;
}
@@ -63,13 +88,16 @@ CGFloat BubbleDecoration::GetWidthForSpace(CGFloat width) {
}
void BubbleDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
- const NSRect decorationFrame = NSInsetRect(frame, 0.0, kKeywordYInset);
+ const NSRect decorationFrame = NSInsetRect(frame, 0.0, kBubbleYInset);
- const NSRect bubbleFrame = NSInsetRect(decorationFrame, 0.5, 0.5);
+ // 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:4.0
- yRadius:4.0];
+ xRadius:kBubbleCornerRadius
+ yRadius:kBubbleCornerRadius];
[background_color_ setFill];
[path fill];
@@ -80,7 +108,11 @@ void BubbleDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
NSRect imageRect = decorationFrame;
if (image_) {
- imageRect.size = [image_ size];
+ // 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
@@ -94,11 +126,14 @@ void BubbleDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
NSRect textRect = decorationFrame;
textRect.origin.x = NSMaxX(imageRect);
textRect.size.width = NSMaxX(decorationFrame) - NSMinX(textRect);
- [text_color_ set];
[label_ drawInRect:textRect withAttributes:attributes_];
}
}
+NSImage* BubbleDecoration::GetImage() {
+ return image_;
+}
+
void BubbleDecoration::SetImage(NSImage* image) {
image_.reset([image retain]);
}
@@ -116,5 +151,8 @@ void BubbleDecoration::SetColors(NSColor* border_color,
NSColor* text_color) {
border_color_.reset([border_color retain]);
background_color_.reset([background_color retain]);
- text_color_.reset([text_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
index bba2140..d54db31 100644
--- a/chrome/browser/cocoa/location_bar/content_setting_decoration.h
+++ b/chrome/browser/cocoa/location_bar/content_setting_decoration.h
@@ -4,6 +4,7 @@
#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"
@@ -25,7 +26,8 @@ class ContentSettingDecoration : public ImageDecoration {
virtual ~ContentSettingDecoration();
// Updates the image and visibility state based on the supplied TabContents.
- void UpdateFromTabContents(const TabContents* tab_contents);
+ // Returns true if the decoration's visible state changed.
+ bool UpdateFromTabContents(const TabContents* tab_contents);
// Overridden from |LocationBarDecoration|
virtual bool AcceptsMousePress() { return true; }
@@ -33,6 +35,11 @@ class ContentSettingDecoration : public ImageDecoration {
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_;
diff --git a/chrome/browser/cocoa/location_bar/content_setting_decoration.mm b/chrome/browser/cocoa/location_bar/content_setting_decoration.mm
index 6f2b8a3..212dd7f 100644
--- a/chrome/browser/cocoa/location_bar/content_setting_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/content_setting_decoration.mm
@@ -6,17 +6,26 @@
#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_blocked_bubble_controller.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/pref_service.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,
@@ -31,10 +40,14 @@ ContentSettingDecoration::ContentSettingDecoration(
ContentSettingDecoration::~ContentSettingDecoration() {
}
-void ContentSettingDecoration::UpdateFromTabContents(
+bool ContentSettingDecoration::UpdateFromTabContents(
const 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
@@ -43,6 +56,13 @@ void ContentSettingDecoration::UpdateFromTabContents(
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) {
@@ -61,10 +81,11 @@ bool ContentSettingDecoration::OnMousePressed(NSRect frame) {
// Find point for bubble's arrow in screen coordinates.
// TODO(shess): |owner_| is only being used to fetch |field|.
- // Consider passing in |control_view|.
+ // 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();
- frame = GetDrawRectInFrame(frame);
- NSPoint anchor = NSMakePoint(NSMidX(frame) + 1, NSMaxY(frame));
+ NSPoint anchor = GetBubblePointInFrame(frame);
anchor = [field convertPoint:anchor toView:nil];
anchor = [[field window] convertBaseToScreen:anchor];
@@ -73,7 +94,7 @@ bool ContentSettingDecoration::OnMousePressed(NSRect frame) {
ContentSettingBubbleModel::CreateContentSettingBubbleModel(
tabContents, profile_,
content_setting_image_model_->get_content_settings_type());
- [ContentBlockedBubbleController showForModel:model
+ [ContentSettingBubbleController showForModel:model
parentWindow:[field window]
anchoredAt:anchor];
return true;
diff --git a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.h b/chrome/browser/cocoa/location_bar/ev_bubble_decoration.h
index ecbdf1d..ae06586 100644
--- a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.h
+++ b/chrome/browser/cocoa/location_bar/ev_bubble_decoration.h
@@ -4,6 +4,7 @@
#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>
@@ -24,7 +25,12 @@ 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);
+
// Implement |LocationBarDecoration|.
+ virtual CGFloat GetWidthForSpace(CGFloat width);
virtual bool IsDraggable();
virtual NSPasteboard* GetDragPasteboard();
virtual NSImage* GetDragImage();
@@ -35,6 +41,12 @@ class EVBubbleDecoration : public BubbleDecoration {
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);
diff --git a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm b/chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm
index ed42fcf..d2bfe63 100644
--- a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm
@@ -4,16 +4,34 @@
#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;
+
// 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.
-const NSColor* ColorWithRGBBytes(int rr, int gg, int bb) {
+NSColor* ColorWithRGBBytes(int rr, int gg, int bb) {
DCHECK_LE(rr, 255);
DCHECK_LE(bb, 255);
DCHECK_LE(gg, 255);
@@ -29,6 +47,7 @@ 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);
@@ -37,6 +56,39 @@ EVBubbleDecoration::EVBubbleDecoration(
SetColors(border_color, background_color, text_color);
}
+void EVBubbleDecoration::SetFullLabel(NSString* label) {
+ full_label_.reset([label retain]);
+ SetLabel(full_label_);
+}
+
+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::SysWideToNSString(
+ ElideText(base::SysNSStringToWide(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();
diff --git a/chrome/browser/cocoa/location_bar/image_decoration.h b/chrome/browser/cocoa/location_bar/image_decoration.h
index 3395307..9324554 100644
--- a/chrome/browser/cocoa/location_bar/image_decoration.h
+++ b/chrome/browser/cocoa/location_bar/image_decoration.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/location_bar/image_decoration.mm b/chrome/browser/cocoa/location_bar/image_decoration.mm
index a5cdc80..980d98d 100644
--- a/chrome/browser/cocoa/location_bar/image_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/image_decoration.mm
@@ -27,9 +27,12 @@ NSRect ImageDecoration::GetDrawRectInFrame(NSRect frame) {
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);
- return NSInsetRect(frame, 0.0, y_inset);
+ 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) {
diff --git a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.h b/chrome/browser/cocoa/location_bar/keyword_hint_decoration.h
index a7e021e..d5972a7 100644
--- a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.h
+++ b/chrome/browser/cocoa/location_bar/keyword_hint_decoration.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
#define CHROME_BROWSER_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm b/chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm
index 250abbf..885b3dd 100644
--- a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm
@@ -2,11 +2,14 @@
// 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"
@@ -22,10 +25,21 @@ const CGFloat kHintTextYInset = 4.0;
// 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) {
@@ -71,10 +85,10 @@ void KeywordHintDecoration::SetKeyword(const std::wstring& short_name,
// Where to put the [tab] image.
const size_t split = content_param_offsets.front();
- hint_prefix_.reset(
- [base::SysWideToNSString(keyword_hint.substr(0, split)) retain]);
- hint_suffix_.reset(
- [base::SysWideToNSString(keyword_hint.substr(split)) retain]);
+ // 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) {
@@ -88,10 +102,14 @@ CGFloat KeywordHintDecoration::GetWidthForSpace(CGFloat width) {
if (width < image_width)
return kOmittedWidth;
- // Show the full hint if it won't take up too much space.
+ // 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 =
- [hint_prefix_ sizeWithAttributes:attributes_].width +
- image_width + [hint_suffix_ sizeWithAttributes:attributes_].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;
@@ -105,28 +123,38 @@ void KeywordHintDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
const bool draw_full = NSWidth(frame) > image_width;
if (draw_full) {
- NSRect prefixRect = NSInsetRect(frame, 0.0, kHintTextYInset);
- prefixRect.size.width =
+ NSRect prefix_rect = NSInsetRect(frame, 0.0, kHintTextYInset);
+ const CGFloat prefix_width =
[hint_prefix_ sizeWithAttributes:attributes_].width;
- [hint_prefix_ drawInRect:prefixRect withAttributes:attributes_];
- frame.origin.x += NSWidth(prefixRect);
- frame.size.width -= NSWidth(prefixRect);
+ 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 imageRect = NSInsetRect(frame, 0.0, kHintImageYInset);
- imageRect.size = [image size];
- [image drawInRect:imageRect
+ 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(imageRect);
- frame.size.width -= NSWidth(imageRect);
+ frame.origin.x += NSWidth(image_rect);
+ frame.size.width -= NSWidth(image_rect);
if (draw_full) {
- NSRect suffixRect = NSInsetRect(frame, 0.0, kHintTextYInset);
- suffixRect.size.width =
+ NSRect suffix_rect = NSInsetRect(frame, 0.0, kHintTextYInset);
+ const CGFloat suffix_width =
[hint_suffix_ sizeWithAttributes:attributes_].width;
- [hint_suffix_ drawInRect:suffixRect withAttributes:attributes_];
+
+ // 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/location_bar_decoration.h b/chrome/browser/cocoa/location_bar/location_bar_decoration.h
index 56a4b83..58b6f92 100644
--- a/chrome/browser/cocoa/location_bar/location_bar_decoration.h
+++ b/chrome/browser/cocoa/location_bar/location_bar_decoration.h
@@ -4,6 +4,7 @@
#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>
diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
index f5e895c..0ec9058 100644
--- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
+++ b/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
@@ -4,10 +4,9 @@
#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_VIEW_MAC_H_
#define CHROME_BROWSER_COCOA_LOCATION_BAR_VIEW_MAC_H_
+#pragma once
#include <string>
-#include <map>
-#include <vector>
#import <Cocoa/Cocoa.h>
@@ -17,11 +16,10 @@
#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.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"
-#include "third_party/skia/include/core/SkBitmap.h"
@class AutocompleteTextField;
class CommandUpdater;
@@ -34,6 +32,7 @@ class LocationIconDecoration;
class PageActionDecoration;
class Profile;
class SelectedKeywordDecoration;
+class SkBitmap;
class StarDecoration;
class ToolbarModel;
@@ -55,6 +54,7 @@ class LocationBarViewMac : public AutocompleteEditController,
// 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;
@@ -111,9 +111,17 @@ class LocationBarViewMac : public AutocompleteEditController,
bool preview_enabled);
// Return |page_action|'s info-bubble point in window coordinates.
- // Returns |NSZeroPoint| if |page_action| is not present.
+ // 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;
+
virtual void OnAutocompleteAccept(const GURL& url,
WindowOpenDisposition disposition,
PageTransition::Type transition,
@@ -151,7 +159,7 @@ class LocationBarViewMac : public AutocompleteEditController,
// Updates visibility of the content settings icons based on the current
// tab contents state.
- void RefreshContentSettingsDecorations();
+ bool RefreshContentSettingsDecorations();
void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type);
diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
index c6eccaa..d8b8b80 100644
--- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
@@ -6,17 +6,17 @@
#include "app/l10n_util_mac.h"
#include "app/resource_bundle.h"
-#include "base/i18n/rtl.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_dll_resource.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"
#include "chrome/browser/browser_list.h"
-#import "chrome/browser/cocoa/content_blocked_bubble_controller.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"
@@ -33,6 +33,7 @@
#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"
@@ -51,6 +52,7 @@
#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"
// TODO(shess): This code is mostly copied from the gtk
@@ -69,12 +71,14 @@ LocationBarViewMac::LocationBarViewMac(
disposition_(CURRENT_TAB),
location_icon_decoration_(new LocationIconDecoration(this)),
selected_keyword_decoration_(
- new SelectedKeywordDecoration([field_ font])),
+ new SelectedKeywordDecoration(
+ AutocompleteEditViewMac::GetFieldFont())),
ev_bubble_decoration_(
new EVBubbleDecoration(location_icon_decoration_.get(),
- [field_ font])),
+ AutocompleteEditViewMac::GetFieldFont())),
star_decoration_(new StarDecoration(command_updater)),
- keyword_hint_decoration_(new KeywordHintDecoration([field_ font])),
+ keyword_hint_decoration_(
+ new KeywordHintDecoration(AutocompleteEditViewMac::GetFieldFont())),
profile_(profile),
browser_(browser),
toolbar_model_(toolbar_model),
@@ -120,6 +124,11 @@ std::wstring LocationBarViewMac::GetInputString() const {
return location_input_;
}
+void LocationBarViewMac::SetSuggestedText(const string16& text) {
+ // TODO: implement me.
+ NOTIMPLEMENTED();
+}
+
WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const {
return disposition_;
}
@@ -143,9 +152,10 @@ void LocationBarViewMac::FocusSearch() {
}
void LocationBarViewMac::UpdateContentSettingsIcons() {
- RefreshContentSettingsDecorations();
- [field_ updateCursorAndToolTipRects];
- [field_ setNeedsDisplay:YES];
+ if (RefreshContentSettingsDecorations()) {
+ [field_ updateCursorAndToolTipRects];
+ [field_ setNeedsDisplay:YES];
+ }
}
void LocationBarViewMac::UpdatePageActions() {
@@ -179,6 +189,10 @@ void LocationBarViewMac::SaveStateToContents(TabContents* 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.
@@ -283,6 +297,8 @@ PageActionDecoration* LocationBarViewMac::GetPageActionDecoration(
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;
}
@@ -322,6 +338,19 @@ NSPoint LocationBarViewMac::GetPageActionBubblePoint(
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();
@@ -352,7 +381,8 @@ void LocationBarViewMac::TestPageActionPressed(size_t index) {
void LocationBarViewMac::SetEditable(bool editable) {
[field_ setEditable:editable ? YES : NO];
- star_decoration_->SetVisible(editable);
+ star_decoration_->SetVisible(browser_defaults::bookmarks_enabled &&
+ editable && !toolbar_model_->input_in_progress());
UpdatePageActions();
Layout();
}
@@ -415,13 +445,16 @@ void LocationBarViewMac::PostNotification(NSString* notification) {
object:[NSValue valueWithPointer:this]];
}
-void LocationBarViewMac::RefreshContentSettingsDecorations() {
+bool LocationBarViewMac::RefreshContentSettingsDecorations() {
const bool input_in_progress = toolbar_model_->input_in_progress();
const TabContents* tab_contents =
input_in_progress ? NULL : browser_->GetSelectedTabContents();
+ bool icons_updated = false;
for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
- content_setting_decorations_[i]->UpdateFromTabContents(tab_contents);
+ icons_updated |=
+ content_setting_decorations_[i]->UpdateFromTabContents(tab_contents);
}
+ return icons_updated;
}
void LocationBarViewMac::DeletePageActionDecorations() {
@@ -468,8 +501,10 @@ void LocationBarViewMac::RefreshPageActionDecorations() {
return;
GURL url = GURL(WideToUTF8(toolbar_model_->GetText()));
- for (size_t i = 0; i < page_action_decorations_.size(); ++i)
- page_action_decorations_[i]->UpdateVisibility(contents, url);
+ 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
@@ -526,7 +561,7 @@ void LocationBarViewMac::Layout() {
ev_bubble_decoration_->SetVisible(true);
std::wstring label(toolbar_model_->GetEVCertName());
- ev_bubble_decoration_->SetLabel(base::SysWideToNSString(label));
+ 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);
diff --git a/chrome/browser/cocoa/location_bar/location_icon_decoration.h b/chrome/browser/cocoa/location_bar/location_icon_decoration.h
index ec14264..028a0ab 100644
--- a/chrome/browser/cocoa/location_bar/location_icon_decoration.h
+++ b/chrome/browser/cocoa/location_bar/location_icon_decoration.h
@@ -4,6 +4,7 @@
#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>
diff --git a/chrome/browser/cocoa/location_bar/page_action_decoration.h b/chrome/browser/cocoa/location_bar/page_action_decoration.h
index 7bbf443..2608912 100644
--- a/chrome/browser/cocoa/location_bar/page_action_decoration.h
+++ b/chrome/browser/cocoa/location_bar/page_action_decoration.h
@@ -4,6 +4,7 @@
#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"
@@ -11,6 +12,7 @@
#include "googleurl/src/gurl.h"
class ExtensionAction;
+@class ExtensionActionContextMenu;
class LocationBarViewMac;
class Profile;
class TabContents;
@@ -50,6 +52,7 @@ class PageActionDecoration : public ImageDecoration,
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();
@@ -99,6 +102,9 @@ class PageActionDecoration : public ImageDecoration,
// 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.
diff --git a/chrome/browser/cocoa/location_bar/page_action_decoration.mm b/chrome/browser/cocoa/location_bar/page_action_decoration.mm
index 1813bb8..337cd2f 100644
--- a/chrome/browser/cocoa/location_bar/page_action_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/page_action_decoration.mm
@@ -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 <cmath>
+
#import "chrome/browser/cocoa/location_bar/page_action_decoration.h"
#include "base/sys_string_conversions.h"
@@ -16,6 +18,16 @@
#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,
@@ -26,6 +38,7 @@ PageActionDecoration::PageActionDecoration(
tracker_(this),
current_tab_id_(-1),
preview_enabled_(false) {
+ DCHECK(profile);
Extension* extension = profile->GetExtensionsService()->GetExtensionById(
page_action->extension_id(), false);
DCHECK(extension);
@@ -48,11 +61,16 @@ PageActionDecoration::PageActionDecoration(
Source<Profile>(profile_));
}
-PageActionDecoration::~PageActionDecoration() {
+PageActionDecoration::~PageActionDecoration() {}
+
+// Always |kPageActionIconMaxSize| wide. |ImageDecoration| draws the
+// image centered.
+CGFloat PageActionDecoration::GetWidthForSpace(CGFloat width) {
+ return Extension::kPageActionIconMaxSize;
}
-// Overridden from LocationBarImageView. Either notify listeners or show a
-// popup depending on the Page Action.
+// 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.";
@@ -103,15 +121,15 @@ void PageActionDecoration::OnImageLoaded(
owner_->UpdatePageActions();
}
-void PageActionDecoration::UpdateVisibility(
- TabContents* contents, const GURL& url) {
+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_ = ExtensionTabUtil::GetTabId(contents);
+ current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1;
current_url_ = url;
- bool visible = preview_enabled_ ||
- page_action_->GetIsVisible(current_tab_id_);
+ bool visible = contents &&
+ (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
if (visible) {
SetToolTip(page_action_->GetTitle(current_tab_id_));
@@ -128,22 +146,28 @@ void PageActionDecoration::UpdateVisibility(
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;
- if (icon_index >= 0)
- icon_path = page_action_->icon_paths()->at(icon_index);
- else
- icon_path = page_action_->default_icon_path();
-
+ 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())
+ 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(
@@ -166,8 +190,19 @@ NSString* PageActionDecoration::GetToolTip() {
}
NSPoint PageActionDecoration::GetBubblePointInFrame(NSRect frame) {
- frame = GetDrawRectInFrame(frame);
- return NSMakePoint(NSMidX(frame), NSMaxY(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() {
@@ -181,10 +216,12 @@ NSMenu* PageActionDecoration::GetMenu() {
DCHECK(extension);
if (!extension)
return nil;
- return [[[ExtensionActionContextMenu alloc]
- initWithExtension:extension
- profile:profile_
- extensionAction:page_action_] autorelease];
+ menu_.reset([[ExtensionActionContextMenu alloc]
+ initWithExtension:extension
+ profile:profile_
+ extensionAction:page_action_]);
+
+ return menu_.get();
}
void PageActionDecoration::Observe(
diff --git a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.h b/chrome/browser/cocoa/location_bar/selected_keyword_decoration.h
index 683a8ed..e2df50a 100644
--- a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.h
+++ b/chrome/browser/cocoa/location_bar/selected_keyword_decoration.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
#define CHROME_BROWSER_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm b/chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm
index 3c593ac..9d18bcb 100644
--- a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm
@@ -14,8 +14,8 @@
SelectedKeywordDecoration::SelectedKeywordDecoration(NSFont* font)
: BubbleDecoration(font) {
- search_image_.reset(
- [AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH) retain]);
+ 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];
diff --git a/chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm b/chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm
index bd0f42f..6a7907a 100644
--- a/chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm
+++ b/chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm
@@ -8,6 +8,7 @@
#import "chrome/browser/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
namespace {
@@ -41,24 +42,24 @@ TEST_F(SelectedKeywordDecorationTest, UsesPartialKeywordIfNarrow) {
// Wide width chooses the full string and image.
const CGFloat all_width = decoration_.GetWidthForSpace(kWidth);
EXPECT_TRUE(decoration_.image_);
- EXPECT_TRUE([decoration_.label_ isEqualToString:kFullString]);
+ 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_TRUE([decoration_.label_ isEqualToString:kFullString]);
+ 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_TRUE([decoration_.label_ isEqualToString:kPartialString]);
+ 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_TRUE([decoration_.label_ isEqualToString:kFullString]);
+ 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
index 6fbe91d..7e02e2c 100644
--- a/chrome/browser/cocoa/location_bar/star_decoration.h
+++ b/chrome/browser/cocoa/location_bar/star_decoration.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_STAR_DECORATION_H_
#define CHROME_BROWSER_COCOA_LOCATION_BAR_STAR_DECORATION_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/location_bar/star_decoration.mm b/chrome/browser/cocoa/location_bar/star_decoration.mm
index 1015f58..adedd16 100644
--- a/chrome/browser/cocoa/location_bar/star_decoration.mm
+++ b/chrome/browser/cocoa/location_bar/star_decoration.mm
@@ -14,9 +14,10 @@
namespace {
// The info-bubble point should look like it points to the point
-// between the star's lower tips. Determined via Pixie.app
+// 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 = 4.0;
+const CGFloat kStarPointYOffset = 2.0;
} // namespace
@@ -30,7 +31,7 @@ StarDecoration::~StarDecoration() {
}
void StarDecoration::SetStarred(bool starred) {
- const int image_id = starred ? IDR_OMNIBOX_STAR_LIT : IDR_OMNIBOX_STAR;
+ 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]);
diff --git a/chrome/browser/cocoa/menu_button.h b/chrome/browser/cocoa/menu_button.h
index c03caa2..7e8392a 100644
--- a/chrome/browser/cocoa/menu_button.h
+++ b/chrome/browser/cocoa/menu_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_MENU_BUTTON_H_
#define CHROME_BROWSER_COCOA_MENU_BUTTON_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/menu_controller.h b/chrome/browser/cocoa/menu_controller.h
index d14d62b..c47af7f 100644
--- a/chrome/browser/cocoa/menu_controller.h
+++ b/chrome/browser/cocoa/menu_controller.h
@@ -4,11 +4,11 @@
#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"
-#include "base/scoped_ptr.h"
namespace menus {
class MenuModel;
diff --git a/chrome/browser/cocoa/menu_controller.mm b/chrome/browser/cocoa/menu_controller.mm
index a5b8256..4e0aa16 100644
--- a/chrome/browser/cocoa/menu_controller.mm
+++ b/chrome/browser/cocoa/menu_controller.mm
@@ -143,6 +143,7 @@
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));
diff --git a/chrome/browser/cocoa/menu_controller_unittest.mm b/chrome/browser/cocoa/menu_controller_unittest.mm
index de0362a..448fa80 100644
--- a/chrome/browser/cocoa/menu_controller_unittest.mm
+++ b/chrome/browser/cocoa/menu_controller_unittest.mm
@@ -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.
@@ -45,12 +45,12 @@ TEST_F(MenuControllerTest, EmptyMenu) {
TEST_F(MenuControllerTest, BasicCreation) {
Delegate delegate;
menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, WideToUTF16(L"one"));
- model.AddItem(2, WideToUTF16(L"two"));
- model.AddItem(3, WideToUTF16(L"three"));
+ model.AddItem(1, ASCIIToUTF16("one"));
+ model.AddItem(2, ASCIIToUTF16("two"));
+ model.AddItem(3, ASCIIToUTF16("three"));
model.AddSeparator();
- model.AddItem(4, WideToUTF16(L"four"));
- model.AddItem(5, WideToUTF16(L"five"));
+ model.AddItem(4, ASCIIToUTF16("four"));
+ model.AddItem(5, ASCIIToUTF16("five"));
scoped_nsobject<MenuController> menu(
[[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
@@ -60,7 +60,7 @@ TEST_F(MenuControllerTest, BasicCreation) {
// element.
NSMenuItem* itemTwo = [[menu menu] itemAtIndex:2];
NSString* title = [itemTwo title];
- EXPECT_EQ(WideToUTF16(L"three"), base::SysNSStringToUTF16(title));
+ EXPECT_EQ(ASCIIToUTF16("three"), base::SysNSStringToUTF16(title));
EXPECT_EQ([itemTwo tag], 2);
EXPECT_EQ([[itemTwo representedObject] pointerValue], &model);
@@ -70,13 +70,13 @@ TEST_F(MenuControllerTest, BasicCreation) {
TEST_F(MenuControllerTest, Submenus) {
Delegate delegate;
menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, WideToUTF16(L"one"));
+ model.AddItem(1, ASCIIToUTF16("one"));
menus::SimpleMenuModel submodel(&delegate);
- submodel.AddItem(2, WideToUTF16(L"sub-one"));
- submodel.AddItem(3, WideToUTF16(L"sub-two"));
- submodel.AddItem(4, WideToUTF16(L"sub-three"));
+ 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, WideToUTF16(L"three"));
+ model.AddItem(6, ASCIIToUTF16("three"));
scoped_nsobject<MenuController> menu(
[[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
@@ -91,7 +91,7 @@ TEST_F(MenuControllerTest, Submenus) {
// represented object and the proper tag.
NSMenuItem* submenuItem = [submenu itemAtIndex:1];
NSString* title = [submenuItem title];
- EXPECT_EQ(WideToUTF16(L"sub-two"), base::SysNSStringToUTF16(title));
+ EXPECT_EQ(ASCIIToUTF16("sub-two"), base::SysNSStringToUTF16(title));
EXPECT_EQ([submenuItem tag], 1);
EXPECT_EQ([[submenuItem representedObject] pointerValue], &submodel);
@@ -99,7 +99,7 @@ TEST_F(MenuControllerTest, Submenus) {
// object is back to the top model.
NSMenuItem* item = [[menu menu] itemAtIndex:2];
title = [item title];
- EXPECT_EQ(WideToUTF16(L"three"), base::SysNSStringToUTF16(title));
+ EXPECT_EQ(ASCIIToUTF16("three"), base::SysNSStringToUTF16(title));
EXPECT_EQ([item tag], 2);
EXPECT_EQ([[item representedObject] pointerValue], &model);
}
@@ -107,7 +107,7 @@ TEST_F(MenuControllerTest, Submenus) {
TEST_F(MenuControllerTest, EmptySubmenu) {
Delegate delegate;
menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, WideToUTF16(L"one"));
+ model.AddItem(1, ASCIIToUTF16("one"));
menus::SimpleMenuModel submodel(&delegate);
model.AddSubMenuWithStringId(2, IDS_ZOOM_MENU, &submodel);
@@ -119,9 +119,9 @@ TEST_F(MenuControllerTest, EmptySubmenu) {
TEST_F(MenuControllerTest, PopUpButton) {
Delegate delegate;
menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, WideToUTF16(L"one"));
- model.AddItem(2, WideToUTF16(L"two"));
- model.AddItem(3, WideToUTF16(L"three"));
+ 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.
@@ -139,7 +139,7 @@ TEST_F(MenuControllerTest, PopUpButton) {
TEST_F(MenuControllerTest, Execute) {
Delegate delegate;
menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, WideToUTF16(L"one"));
+ model.AddItem(1, ASCIIToUTF16("one"));
scoped_nsobject<MenuController> menu(
[[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
EXPECT_EQ([[menu menu] numberOfItems], 1);
@@ -163,10 +163,10 @@ void Validate(MenuController* controller, NSMenu* menu) {
TEST_F(MenuControllerTest, Validate) {
Delegate delegate;
menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, WideToUTF16(L"one"));
- model.AddItem(2, WideToUTF16(L"two"));
+ model.AddItem(1, ASCIIToUTF16("one"));
+ model.AddItem(2, ASCIIToUTF16("two"));
menus::SimpleMenuModel submodel(&delegate);
- submodel.AddItem(2, WideToUTF16(L"sub-one"));
+ submodel.AddItem(2, ASCIIToUTF16("sub-one"));
model.AddSubMenuWithStringId(3, IDS_ZOOM_MENU, &submodel);
scoped_nsobject<MenuController> menu(
@@ -179,9 +179,9 @@ TEST_F(MenuControllerTest, Validate) {
TEST_F(MenuControllerTest, DefaultInitializer) {
Delegate delegate;
menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, WideToUTF16(L"one"));
- model.AddItem(2, WideToUTF16(L"two"));
- model.AddItem(3, WideToUTF16(L"three"));
+ 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]);
@@ -192,6 +192,6 @@ TEST_F(MenuControllerTest, DefaultInitializer) {
EXPECT_EQ(3, [[menu menu] numberOfItems]);
// Check immutability.
- model.AddItem(4, WideToUTF16(L"four"));
+ model.AddItem(4, ASCIIToUTF16("four"));
EXPECT_EQ(3, [[menu menu] numberOfItems]);
}
diff --git a/chrome/browser/cocoa/multi_key_equivalent_button.h b/chrome/browser/cocoa/multi_key_equivalent_button.h
index 4d2c3b6..5342a21 100644
--- a/chrome/browser/cocoa/multi_key_equivalent_button.h
+++ b/chrome/browser/cocoa/multi_key_equivalent_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
#define CHROME_BROWSER_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
+#pragma once
#import <AppKit/AppKit.h>
diff --git a/chrome/browser/cocoa/notifications/balloon_controller.h b/chrome/browser/cocoa/notifications/balloon_controller.h
index f5fb0ba..8199265 100644
--- a/chrome/browser/cocoa/notifications/balloon_controller.h
+++ b/chrome/browser/cocoa/notifications/balloon_controller.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#include "base/scoped_nsobject.h"
#include "base/cocoa_protocols_mac.h"
-#import "chrome/browser/cocoa/hover_close_button.h"
+#import "chrome/browser/cocoa/hover_image_button.h"
#import "chrome/browser/cocoa/notifications/balloon_view.h"
#import "chrome/browser/cocoa/notifications/balloon_view_host_mac.h"
#include "chrome/browser/notifications/balloon.h"
@@ -34,13 +35,16 @@ class NotificationOptionsMenuModel;
IBOutlet BalloonShelfViewCocoa* shelf_;
// The close button.
- IBOutlet HoverCloseButton* closeButton_;
+ 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 NSButton* optionsButton_;
+ IBOutlet HoverImageButton* optionsButton_;
scoped_ptr<NotificationOptionsMenuModel> menuModel_;
scoped_nsobject<MenuController> menuController_;
diff --git a/chrome/browser/cocoa/notifications/balloon_controller.mm b/chrome/browser/cocoa/notifications/balloon_controller.mm
index 08d47a6..55ee041 100644
--- a/chrome/browser/cocoa/notifications/balloon_controller.mm
+++ b/chrome/browser/cocoa/notifications/balloon_controller.mm
@@ -7,6 +7,8 @@
#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/menu_controller.h"
@@ -24,16 +26,23 @@ namespace {
// Margin, in pixels, between the notification frame and the contents
// of the notification.
const int kTopMargin = 1;
-const int kBottomMargin = 1;
-const int kLeftMargin = 1;
-const int kRightMargin = 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 {
- if ((self = [super initWithWindowNibName:@"Notification"])) {
+ 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));
@@ -47,21 +56,66 @@ const int kRightMargin = 1;
DCHECK([self window]);
DCHECK_EQ(self, [[self window] delegate]);
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* image = rb.GetNSImageNamed(IDR_BALLOON_WRENCH);
- DCHECK(image);
- [optionsButton_ setImage:image];
+ 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,
- WideToUTF16(balloon_->notification().display_source()));
+ balloon_->notification().display_source());
[originLabel_ setStringValue:sourceLabelText];
- gfx::NativeView contents = htmlContents_->native_view();
- [contents setFrame:NSMakeRect(kLeftMargin, kTopMargin, 0, 0)];
- [[htmlContainer_ superview] addSubview:contents
- positioned:NSWindowBelow
- relativeTo:nil];
+ // 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];
+}
+
+- (void) mouseEntered:(NSEvent*)event {
+ [[closeButton_ cell] setHighlighted:YES];
+}
+
+- (void) mouseExited:(NSEvent*)event {
+ [[closeButton_ cell] setHighlighted:NO];
}
- (IBAction)optionsButtonPressed:(id)sender {
@@ -81,12 +135,20 @@ const int kRightMargin = 1;
[self close];
}
+- (void)close {
+ if (closeButtonTrackingTag_)
+ [shelf_ removeTrackingRect:closeButtonTrackingTag_];
+
+ [super close];
+}
+
- (void)closeBalloon:(bool)byUser {
DCHECK(balloon_);
[self close];
if (htmlContents_.get())
htmlContents_->Shutdown();
- balloon_->OnClose(byUser);
+ if (balloon_)
+ balloon_->OnClose(byUser);
balloon_ = NULL;
}
@@ -104,10 +166,11 @@ const int kRightMargin = 1;
int w = [self desiredTotalWidth];
int h = [self desiredTotalHeight];
- htmlContents_->UpdateActualSize(balloon_->content_size());
- [[self window] setFrame:NSMakeRect(x, y, w, h)
- display:YES
- animate:YES];
+ 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.
diff --git a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm b/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm
index c8c2743..ff1176e 100644
--- a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm
+++ b/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm
@@ -3,6 +3,7 @@
// 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"
@@ -13,6 +14,16 @@
#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.
@@ -63,41 +74,38 @@ class BalloonControllerTest : public RenderViewHostTestHarness {
TEST_F(BalloonControllerTest, ShowAndCloseTest) {
Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"),
- L"http://www.google.com", ASCIIToUTF16(""),
+ 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 = [BalloonController alloc];
-
- id mock = [OCMockObject partialMockForObject:controller];
- [[mock expect] initializeHost];
+ BalloonController* controller =
+ [[TestBalloonController alloc] initWithBalloon:balloon.get()];
- [controller initWithBalloon:balloon.get()];
[controller showWindow:nil];
[controller closeBalloon:YES];
-
- [mock verify];
}
TEST_F(BalloonControllerTest, SizesTest) {
Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"),
- L"http://www.google.com", ASCIIToUTF16(""),
+ 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 = [BalloonController alloc];
-
- id mock = [OCMockObject partialMockForObject:controller];
- [[mock expect] initializeHost];
+ BalloonController* controller =
+ [[TestBalloonController alloc] initWithBalloon:balloon.get()];
- [controller initWithBalloon:balloon.get()];
+ [controller showWindow:nil];
EXPECT_TRUE([controller desiredTotalWidth] > 100);
EXPECT_TRUE([controller desiredTotalHeight] > 100);
- [mock verify];
+
+ [controller closeBalloon:YES];
}
}
diff --git a/chrome/browser/cocoa/notifications/balloon_view.h b/chrome/browser/cocoa/notifications/balloon_view.h
index 95d3e69..5164360 100644
--- a/chrome/browser/cocoa/notifications/balloon_view.h
+++ b/chrome/browser/cocoa/notifications/balloon_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
#define CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/notifications/balloon_view.mm b/chrome/browser/cocoa/notifications/balloon_view.mm
index 3797f9c..3a5d13e 100644
--- a/chrome/browser/cocoa/notifications/balloon_view.mm
+++ b/chrome/browser/cocoa/notifications/balloon_view.mm
@@ -6,13 +6,13 @@
#import <Cocoa/Cocoa.h>
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "base/scoped_nsobject.h"
#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
namespace {
-const int kRoundedCornerSize = 6.5;
+const int kRoundedCornerSize = 6;
} // namespace
@@ -32,6 +32,10 @@ const int kRoundedCornerSize = 6.5;
}
return self;
}
+
+- (BOOL)canBecomeMainWindow {
+ return NO;
+}
@end
@implementation BalloonShelfViewCocoa
@@ -45,20 +49,25 @@ const int kRoundedCornerSize = 6.5;
[[NSColor colorWithCalibratedWhite:0.957 alpha:1.0] set];
[path fill];
- [[NSColor blackColor] set];
- [path stroke];
+
+ [[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:[self bounds]
+ [NSBezierPath gtm_bezierPathWithRoundRect:rect
topLeftCornerRadius:0.0
topRightCornerRadius:0.0
bottomLeftCornerRadius:kRoundedCornerSize
bottomRightCornerRadius:kRoundedCornerSize];
- [[NSColor blackColor] set];
+ [[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
index e967608..01adcd8 100644
--- a/chrome/browser/cocoa/notifications/balloon_view_bridge.h
+++ b/chrome/browser/cocoa/notifications/balloon_view_bridge.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
#define CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
+#pragma once
#include "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/notifications/balloon_controller.h"
diff --git a/chrome/browser/cocoa/notifications/balloon_view_bridge.mm b/chrome/browser/cocoa/notifications/balloon_view_bridge.mm
index a1be94b..7f6aa7c 100644
--- a/chrome/browser/cocoa/notifications/balloon_view_bridge.mm
+++ b/chrome/browser/cocoa/notifications/balloon_view_bridge.mm
@@ -31,7 +31,7 @@ void BalloonViewBridge::RepositionToBalloon() {
void BalloonViewBridge::Show(Balloon* balloon) {
controller_ = [[BalloonController alloc] initWithBalloon:balloon];
- [controller_ repositionToBalloon];
+ [controller_ setShouldCascadeWindows:NO];
[controller_ showWindow:nil];
}
diff --git a/chrome/browser/cocoa/notifications/balloon_view_host_mac.h b/chrome/browser/cocoa/notifications/balloon_view_host_mac.h
index 72220bd..286d5b1 100644
--- a/chrome/browser/cocoa/notifications/balloon_view_host_mac.h
+++ b/chrome/browser/cocoa/notifications/balloon_view_host_mac.h
@@ -4,6 +4,7 @@
#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"
#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
diff --git a/chrome/browser/cocoa/nsmenuitem_additions.h b/chrome/browser/cocoa/nsmenuitem_additions.h
index 2e17674..5a647fa 100644
--- a/chrome/browser/cocoa/nsmenuitem_additions.h
+++ b/chrome/browser/cocoa/nsmenuitem_additions.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_NSMENUITEM_ADDITIONS_H_
#define CHROME_BROWSER_COCOA_NSMENUITEM_ADDITIONS_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/objc_method_swizzle.h b/chrome/browser/cocoa/objc_method_swizzle.h
index 328e79f..368b33c 100644
--- a/chrome/browser/cocoa/objc_method_swizzle.h
+++ b/chrome/browser/cocoa/objc_method_swizzle.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_OBJC_METHOD_SWIZZLE_H_
#define CHROME_BROWSER_COCOA_OBJC_METHOD_SWIZZLE_H_
+#pragma once
#import <objc/objc-class.h>
diff --git a/chrome/browser/cocoa/objc_zombie.h b/chrome/browser/cocoa/objc_zombie.h
index 86508a7..ccb7342 100644
--- a/chrome/browser/cocoa/objc_zombie.h
+++ b/chrome/browser/cocoa/objc_zombie.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_NSOBJECT_ZOMBIE_H_
#define CHROME_BROWSER_COCOA_NSOBJECT_ZOMBIE_H_
+#pragma once
#import <Foundation/Foundation.h>
diff --git a/chrome/browser/cocoa/page_info_window_controller.mm b/chrome/browser/cocoa/page_info_window_controller.mm
index 521ab68..3a699d7 100644
--- a/chrome/browser/cocoa/page_info_window_controller.mm
+++ b/chrome/browser/cocoa/page_info_window_controller.mm
@@ -6,11 +6,10 @@
#include "app/l10n_util_mac.h"
#include "base/mac_util.h"
-#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/cocoa/page_info_window_mac.h"
#include "chrome/browser/cocoa/window_size_autosaver.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
@@ -41,8 +40,7 @@ const NSInteger kWindowWidth = 460;
sizeSaver_.reset([[WindowSizeAutosaver alloc]
initWithWindow:[self window]
prefService:g_browser_process->local_state()
- path:prefs::kPageInfoWindowPlacement
- state:kSaveWindowPos]);
+ path:prefs::kPageInfoWindowPlacement]);
}
}
return self;
diff --git a/chrome/browser/cocoa/page_info_window_mac.h b/chrome/browser/cocoa/page_info_window_mac.h
index c1beccf..587a320 100644
--- a/chrome/browser/cocoa/page_info_window_mac.h
+++ b/chrome/browser/cocoa/page_info_window_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_PAGE_INFO_WINDOW_MAC_H_
#define CHROME_BROWSER_COCOA_PAGE_INFO_WINDOW_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -16,9 +17,7 @@ class Profile;
@class PageInfoWindowController;
namespace {
-
class PageInfoWindowMacTest;
-
};
// This bridge is responsible for getting information from the cross-platform
@@ -29,8 +28,10 @@ class PageInfoWindowMac : public PageInfoModel::PageInfoModelObserver {
public:
virtual ~PageInfoWindowMac();
- // Creates and shows the page info.
- static void ShowPageInfo(Profile* profile,
+ // Used to create the page info window; called from the cross-platform
+ // function.
+ static void ShowPageInfo(gfx::NativeWindow parent,
+ Profile* profile,
const GURL& url,
const NavigationEntry::SSLStatus& ssl,
bool show_history);
@@ -46,7 +47,7 @@ class PageInfoWindowMac : public PageInfoModel::PageInfoModelObserver {
private:
friend class ::PageInfoWindowMacTest;
- // Private constructor, called by ShowPageInfo().
+ // Constructor; private. Called by ShowPageInfo().
PageInfoWindowMac(PageInfoWindowController* controller,
Profile* profile,
const GURL& url,
diff --git a/chrome/browser/cocoa/page_info_window_mac.mm b/chrome/browser/cocoa/page_info_window_mac.mm
index cc40b2e..c98e357 100644
--- a/chrome/browser/cocoa/page_info_window_mac.mm
+++ b/chrome/browser/cocoa/page_info_window_mac.mm
@@ -8,13 +8,13 @@
#include "app/l10n_util.h"
#include "base/scoped_cftyperef.h"
-#include "base/i18n/time_formatting.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#import "chrome/browser/cocoa/page_info_window_controller.h"
#include "chrome/browser/cert_store.h"
#include "chrome/browser/certificate_viewer.h"
+#include "chrome/browser/page_info_window.h"
#include "chrome/browser/profile.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -47,24 +47,26 @@ const CGFloat kImageSize = 30;
} // namespace
-void PageInfoWindowMac::ShowPageInfo(Profile* profile,
- const GURL& url,
- const NavigationEntry::SSLStatus& ssl,
- bool show_history) {
- // The controller will clean itself up after the NSWindow it manages closes.
- // We do not manage it as it owns us.
- PageInfoWindowController* controller =
- [[PageInfoWindowController alloc] init];
- PageInfoWindowMac* page_info = new PageInfoWindowMac(controller,
- profile,
- url,
- ssl,
- show_history);
- [controller setPageInfo:page_info];
- page_info->LayoutSections();
- page_info->Show();
+namespace browser {
+
+void ShowPageInfo(gfx::NativeWindow parent,
+ Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history) {
+ PageInfoWindowMac::ShowPageInfo(parent, profile, url, ssl, show_history);
+}
+
+void ShowPageInfoBubble(gfx::NativeWindow parent,
+ Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history) {
+ NOTIMPLEMENTED();
}
+} // namespace browser
+
PageInfoWindowMac::PageInfoWindowMac(PageInfoWindowController* controller,
Profile* profile,
const GURL& url,
@@ -84,6 +86,26 @@ PageInfoWindowMac::PageInfoWindowMac(PageInfoWindowController* controller,
Init();
}
+// static
+void PageInfoWindowMac::ShowPageInfo(gfx::NativeWindow parent,
+ Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history) {
+ // The controller will clean itself up after the NSWindow it manages closes.
+ // We do not manage it as it owns us.
+ PageInfoWindowController* controller =
+ [[PageInfoWindowController alloc] init];
+ PageInfoWindowMac* page_info = new PageInfoWindowMac(controller,
+ profile,
+ url,
+ ssl,
+ show_history);
+ [controller setPageInfo:page_info];
+ page_info->LayoutSections();
+ page_info->Show();
+}
+
void PageInfoWindowMac::Init() {
// Load the image refs.
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
@@ -98,15 +120,19 @@ void PageInfoWindowMac::Init() {
PageInfoWindowMac::~PageInfoWindowMac() {
}
-void PageInfoWindowMac::Show() {
- [[controller_ window] makeKeyAndOrderFront:nil];
-}
-
void PageInfoWindowMac::ShowCertDialog(int) {
DCHECK(cert_id_ != 0);
ShowCertificateViewerByID([controller_ window], cert_id_);
}
+void PageInfoWindowMac::ModelChanged() {
+ LayoutSections();
+}
+
+void PageInfoWindowMac::Show() {
+ [[controller_ window] makeKeyAndOrderFront:nil];
+}
+
// 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
@@ -195,7 +221,8 @@ void PageInfoWindowMac::LayoutSections() {
scoped_nsobject<NSImageView> image_view(
[[NSImageView alloc] initWithFrame:image_view_rect]);
[image_view setImageFrameStyle:NSImageFrameNone];
- [image_view setImage:(info.state) ? good_image_.get() : bad_image_.get()];
+ [image_view setImage:(info.state == PageInfoModel::SECTION_STATE_OK) ?
+ good_image_.get() : bad_image_.get()];
// Add the box to the list of new subviews.
[box addSubview:image_view.get()];
@@ -231,7 +258,3 @@ void PageInfoWindowMac::LayoutSections() {
display:YES
animate:[[controller_ window] isVisible]];
}
-
-void PageInfoWindowMac::ModelChanged() {
- LayoutSections();
-}
diff --git a/chrome/browser/cocoa/page_info_window_mac_unittest.mm b/chrome/browser/cocoa/page_info_window_mac_unittest.mm
index ab9fdbe..632aac1 100644
--- a/chrome/browser/cocoa/page_info_window_mac_unittest.mm
+++ b/chrome/browser/cocoa/page_info_window_mac_unittest.mm
@@ -5,7 +5,9 @@
#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/page_info_window_mac.h"
#import "chrome/browser/cocoa/page_info_window_controller.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
@@ -17,14 +19,16 @@ namespace {
class FakeModel : public PageInfoModel {
public:
- void AddSection(bool state,
+ void AddSection(SectionInfoState state,
const string16& title,
- const string16& description) {
+ const string16& description,
+ SectionInfoType type) {
sections_.push_back(SectionInfo(
state,
title,
string16(),
- description));
+ description,
+ type));
}
};
@@ -107,16 +111,18 @@ class PageInfoWindowMacTest : public CocoaTest {
TEST_F(PageInfoWindowMacTest, NoHistoryNoSecurity) {
- model_->AddSection(false,
+ model_->AddSection(PageInfoModel::SECTION_STATE_ERROR,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_IDENTITY_TITLE),
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY,
- ASCIIToUTF16("google.com")));
- model_->AddSection(false,
+ ASCIIToUTF16("google.com")),
+ PageInfoModel::SECTION_INFO_IDENTITY);
+ model_->AddSection(PageInfoModel::SECTION_STATE_ERROR,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_CONNECTION_TITLE),
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
- ASCIIToUTF16("google.com")));
+ ASCIIToUTF16("google.com")),
+ PageInfoModel::SECTION_INFO_CONNECTION);
bridge_->ModelChanged();
@@ -125,26 +131,29 @@ TEST_F(PageInfoWindowMacTest, NoHistoryNoSecurity) {
TEST_F(PageInfoWindowMacTest, HistoryNoSecurity) {
- model_->AddSection(false,
+ model_->AddSection(PageInfoModel::SECTION_STATE_ERROR,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_IDENTITY_TITLE),
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY,
- ASCIIToUTF16("google.com")));
- model_->AddSection(false,
+ ASCIIToUTF16("google.com")),
+ PageInfoModel::SECTION_INFO_IDENTITY);
+ model_->AddSection(PageInfoModel::SECTION_STATE_ERROR,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_CONNECTION_TITLE),
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
- ASCIIToUTF16("google.com")));
+ 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.
bridge_->ModelChanged();
- model_->AddSection(false,
+ model_->AddSection(PageInfoModel::SECTION_STATE_ERROR,
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_PERSONAL_HISTORY_TITLE),
l10n_util::GetStringUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY));
+ IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY),
+ PageInfoModel::SECTION_INFO_FIRST_VISIT);
bridge_->ModelChanged();
@@ -153,26 +162,28 @@ TEST_F(PageInfoWindowMacTest, HistoryNoSecurity) {
TEST_F(PageInfoWindowMacTest, NoHistoryMixedSecurity) {
- model_->AddSection(true,
+ model_->AddSection(PageInfoModel::SECTION_STATE_OK,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_IDENTITY_TITLE),
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY,
- ASCIIToUTF16("Goat Security Systems")));
+ ASCIIToUTF16("Goat Security Systems")),
+ PageInfoModel::SECTION_INFO_IDENTITY);
// This string is super long and the text should overflow the default clip
// region (kImageSize).
string16 title =
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_CONNECTION_TITLE);
- model_->AddSection(true,
+ model_->AddSection(PageInfoModel::SECTION_STATE_OK,
title,
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"),
- IntToString16(1024)),
+ base::IntToString16(1024)),
l10n_util::GetStringUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING)));
+ IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING)),
+ PageInfoModel::SECTION_INFO_CONNECTION);
bridge_->ModelChanged();
diff --git a/chrome/browser/cocoa/popup_blocked_animation_mac.mm b/chrome/browser/cocoa/popup_blocked_animation_mac.mm
index cee6812..8db52fe 100644
--- a/chrome/browser/cocoa/popup_blocked_animation_mac.mm
+++ b/chrome/browser/cocoa/popup_blocked_animation_mac.mm
@@ -9,6 +9,8 @@
#import "base/nsimage_cache_mac.h"
#import "chrome/browser/cocoa/animatable_image.h"
+#import "chrome/browser/cocoa/browser_window_controller.h"
+#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
@@ -23,8 +25,8 @@ class PopupBlockedAnimationObserver;
AnimatableImage* animation_;
};
-// Called by our the Observer if the tab is hidden or closed.
-- (void)animationComplete;
+// Called by the Observer if the tab is hidden or closed.
+- (void)closeAnimation;
@end
@@ -50,7 +52,7 @@ class PopupBlockedAnimationObserver : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details) {
// This ends up deleting us.
- [owner_ animationComplete];
+ [owner_ closeAnimation];
}
private:
@@ -106,7 +108,6 @@ class PopupBlockedAnimationObserver : public NotificationObserver {
[parentWindow addChildWindow:animation_ ordered:NSWindowAbove];
// Start the animation from the center of the window.
- NSRect contentFrame = [[animation_ contentView] frame];
[animation_ setStartFrame:CGRectMake(0,
imageHeight / 2,
imageWidth,
@@ -116,9 +117,28 @@ class PopupBlockedAnimationObserver : public NotificationObserver {
// slightly to the Omnibox. While the geometry won't align perfectly, it's
// close enough for the user to take note of the new icon. These numbers
// come from measuring the Omnibox without any page actions.
- [animation_ setEndFrame:CGRectMake(animationFrame.size.width - 115,
- animationFrame.size.height - 50,
- 16, 16)];
+ CGRect endFrame = CGRectMake(animationFrame.size.width - 115,
+ animationFrame.size.height - 50,
+ 16, 16);
+
+ // If the location-bar can be found, ask it for better
+ // coordinates.
+ BrowserWindowController* bwc = [parentWindow windowController];
+ if ([bwc isKindOfClass:[BrowserWindowController class]]) {
+ LocationBarViewMac* lbvm = [bwc locationBarBridge];
+ if (lbvm) {
+ NSRect frame = lbvm->GetBlockedPopupRect();
+ if (!NSIsEmptyRect(frame)) {
+ // Convert up to the screen, then back down to the animation
+ // window.
+ NSPoint screenPoint = [parentWindow convertBaseToScreen:frame.origin];
+ frame.origin = [animation_ convertScreenToBase:screenPoint];
+ endFrame = NSRectToCGRect(frame);
+ }
+ }
+ }
+
+ [animation_ setEndFrame:endFrame];
[animation_ setStartOpacity:1.0];
[animation_ setEndOpacity:0.2];
[animation_ setDuration:0.7];
@@ -142,12 +162,13 @@ class PopupBlockedAnimationObserver : public NotificationObserver {
[super dealloc];
}
-- (void)windowWillClose:(NSNotification*)notification {
- DCHECK([[notification object] isEqual:animation_]);
- [self animationComplete];
+- (void)closeAnimation {
+ [animation_ close];
}
-- (void)animationComplete {
+// When the animation window closes, release self.
+- (void)windowWillClose:(NSNotification*)notification {
+ DCHECK([[notification object] isEqual:animation_]);
[[animation_ parentWindow] removeChildWindow:animation_];
[self release];
}
diff --git a/chrome/browser/cocoa/preferences_window_controller.h b/chrome/browser/cocoa/preferences_window_controller.h
index 707f597..54d4778 100644
--- a/chrome/browser/cocoa/preferences_window_controller.h
+++ b/chrome/browser/cocoa/preferences_window_controller.h
@@ -7,7 +7,9 @@
#include "base/scoped_ptr.h"
#include "base/scoped_nsobject.h"
#include "chrome/browser/options_window.h"
-#include "chrome/browser/pref_member.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;
@@ -44,6 +46,7 @@ class ProfileSyncService;
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>
@@ -89,9 +92,13 @@ class ProfileSyncService;
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_;
// User Data panel
BooleanPrefMember askSavePasswords_;
+ BooleanPrefMember autoFillEnabled_;
IBOutlet NSButton* autoFillSettingsButton_;
IBOutlet NSButton* syncButton_;
IBOutlet NSButton* syncCustomizeButton_;
@@ -101,6 +108,9 @@ class ProfileSyncService;
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_;
@@ -111,7 +121,7 @@ class ProfileSyncService;
BooleanPrefMember useSuggest_;
BooleanPrefMember dnsPrefetch_;
BooleanPrefMember safeBrowsing_;
- BooleanPrefMember metricsRecording_;
+ BooleanPrefMember metricsReporting_;
IBOutlet NSPathControl* downloadLocationControl_;
IBOutlet NSButton* downloadLocationButton_;
StringPrefMember defaultDownloadLocation_;
@@ -123,6 +133,18 @@ class ProfileSyncService;
FontLanguageSettingsController* fontLanguageSettings_;
StringPrefMember currentTheme_;
IBOutlet NSButton* enableLoggingCheckbox_;
+ scoped_ptr<PrefSetObserver> proxyPrefs_;
+ BOOL showAlternateErrorPagesEnabled_;
+ BOOL useSuggestEnabled_;
+ BOOL dnsPrefetchEnabled_;
+ BOOL safeBrowsingEnabled_;
+ BOOL metricsReportingEnabled_;
+ BOOL proxiesConfigureButtonEnabled_;
+ IBOutlet NSTextField* backgroundModeTitle_;
+ IBOutlet NSButton* backgroundModeCheckbox_;
+ IBOutlet NSTextField* backgroundModeDescription_;
+ IBOutlet NSButton* backgroundModeLearnMore_;
+ BooleanPrefMember backgroundModeEnabled_;
}
// Designated initializer. |profile| should not be NULL.
@@ -134,6 +156,9 @@ class ProfileSyncService;
// 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
@@ -163,6 +188,7 @@ class ProfileSyncService;
- (IBAction)changeFontAndLanguageSettings:(id)sender;
- (IBAction)openProxyPreferences:(id)sender;
- (IBAction)showCertificates:(id)sender;
+- (IBAction)backgroundModeLearnMore:(id)sender;
- (IBAction)resetToDefaults:(id)sender;
// When a toolbar button is clicked
@@ -171,6 +197,20 @@ class ProfileSyncService;
// 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 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)
@@ -198,4 +238,3 @@ class ProfileSyncService;
- (NSView*)getPrefsViewForPage:(OptionsPage)page;
@end
-
diff --git a/chrome/browser/cocoa/preferences_window_controller.mm b/chrome/browser/cocoa/preferences_window_controller.mm
index 0aa1501..0f11f63 100644
--- a/chrome/browser/cocoa/preferences_window_controller.mm
+++ b/chrome/browser/cocoa/preferences_window_controller.mm
@@ -11,6 +11,7 @@
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "base/mac_util.h"
+#include "base/scoped_aedesc.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
@@ -31,18 +32,19 @@
#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/managed_prefs_banner_base.h"
#include "chrome/browser/metrics/metrics_service.h"
#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/options_window.h"
#include "chrome/browser/options_util.h"
-#include "chrome/browser/pref_service.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/session_startup_pref.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_ui_util.h"
@@ -58,8 +60,8 @@
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
namespace {
@@ -321,14 +323,13 @@ CGFloat AutoSizeUnderTheHoodContent(NSView* view,
@interface PreferencesWindowController(Private)
// Callback when preferences are changed. |prefName| is the name of the
// pref that has changed.
-- (void)prefChanged:(std::wstring*)prefName;
+- (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)unregisterPrefObservers;
// KVC setter methods.
- (void)setNewTabPageIsHomePageIndex:(NSInteger)val;
@@ -341,11 +342,12 @@ CGFloat AutoSizeUnderTheHoodContent(NSView* view,
- (void)setUseSuggest:(BOOL)value;
- (void)setDnsPrefetch:(BOOL)value;
- (void)setSafeBrowsing:(BOOL)value;
-- (void)setMetricsRecording:(BOOL)value;
+- (void)setMetricsReporting:(BOOL)value;
- (void)setAskForSaveLocation:(BOOL)value;
- (void)setFileHandlerUIEnabled:(BOOL)value;
- (void)setTranslateEnabled:(BOOL)value;
- (void)setTabsToLinks:(BOOL)value;
+- (void)setBackgroundModeEnabled:(BOOL)value;
- (void)displayPreferenceViewForPage:(OptionsPage)page
animate:(BOOL)animate;
- (void)resetSubViews;
@@ -372,7 +374,7 @@ class PrefObserverBridge : public NotificationObserver,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED)
- [controller_ prefChanged:Details<std::wstring>(details).ptr()];
+ [controller_ prefChanged:Details<std::string>(details).ptr()];
}
// Overridden from ProfileSyncServiceObserver.
@@ -386,14 +388,15 @@ class PrefObserverBridge : public NotificationObserver,
// Tracks state for a managed prefs banner and triggers UI updates through the
// PreferencesWindowController as appropriate.
-class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
+class ManagedPrefsBannerState : public policy::ManagedPrefsBannerBase {
public:
virtual ~ManagedPrefsBannerState() { }
explicit ManagedPrefsBannerState(PreferencesWindowController* controller,
OptionsPage page,
+ PrefService* local_state,
PrefService* prefs)
- : ManagedPrefsBannerBase(prefs, page),
+ : policy::ManagedPrefsBannerBase(local_state, prefs, page),
controller_(controller),
page_(page) { }
@@ -416,6 +419,19 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
@implementation PreferencesWindowController
+@synthesize restoreButtonsEnabled = restoreButtonsEnabled_;
+@synthesize restoreURLsEnabled = restoreURLsEnabled_;
+@synthesize showHomeButtonEnabled = showHomeButtonEnabled_;
+@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
@@ -483,6 +499,27 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
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 show home button and
+ // restore on startup elements.
+ [self setShowHomeButtonEnabled:!showHomeButton_.IsManaged()];
+ [self setEnabledStateOfRestoreOnStartup];
+
+ // 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;
}
@@ -512,6 +549,15 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
RemoveViewFromView(underTheHoodContentView_, enableLoggingCheckbox_);
#endif // !defined(GOOGLE_CHROME_BUILD)
+ // If BackgroundMode is not enabled, hide the related prefs UI.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBackgroundMode)) {
+ RemoveViewFromView(underTheHoodContentView_, backgroundModeTitle_);
+ RemoveViewFromView(underTheHoodContentView_, backgroundModeCheckbox_);
+ RemoveViewFromView(underTheHoodContentView_, backgroundModeDescription_);
+ RemoveViewFromView(underTheHoodContentView_, backgroundModeLearnMore_);
+ }
+
// There are four problem children within the groups:
// Basics - Default Browser
// Personal Stuff - Sync
@@ -684,8 +730,7 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
sizeSaver_.reset([[WindowSizeAutosaver alloc]
initWithWindow:[self window]
prefService:g_browser_process->local_state()
- path:prefs::kPreferencesWindowPlacement
- state:kSaveWindowRect]);
+ path:prefs::kPreferencesWindowPlacement]);
}
// Initialize the banner gradient and stroke color.
@@ -715,7 +760,6 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
syncService_->RemoveObserver(observer_.get());
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
- [self unregisterPrefObservers];
[animation_ setDelegate:nil];
[animation_ stopAnimation];
[super dealloc];
@@ -735,7 +779,8 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
if (!prefs_) return;
// Basics panel
- prefs_->AddPrefObserver(prefs::kURLsToRestoreOnStartup, observer_.get());
+ registrar_.Init(prefs_);
+ registrar_.Add(prefs::kURLsToRestoreOnStartup, observer_.get());
restoreOnStartup_.Init(prefs::kRestoreOnStartup, prefs_, observer_.get());
newTabPageIsHomePage_.Init(prefs::kHomePageIsNewTabPage,
prefs_, observer_.get());
@@ -745,6 +790,7 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
// 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
@@ -756,6 +802,8 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
autoOpenFiles_.Init(
prefs::kDownloadExtensionsToOpen, prefs_, observer_.get());
translateEnabled_.Init(prefs::kEnableTranslate, prefs_, observer_.get());
+ backgroundModeEnabled_.Init(prefs::kBackgroundModeEnabled, prefs_,
+ observer_.get());
tabsToLinks_.Init(prefs::kWebkitTabsToLinks, prefs_, observer_.get());
// During unit tests, there is no local state object, so we fall back to
@@ -764,7 +812,7 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
PrefService* local = g_browser_process->local_state();
if (!local)
local = prefs_;
- metricsRecording_.Init(prefs::kMetricsReportingEnabled,
+ metricsReporting_.Init(prefs::kMetricsReportingEnabled,
local, observer_.get());
defaultDownloadLocation_.Init(prefs::kDownloadDefaultDirectory, prefs_,
observer_.get());
@@ -774,17 +822,6 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
lastSelectedPage_.Init(prefs::kOptionsWindowLastTabIndex, local, NULL);
}
-// Clean up what was registered in -registerPrefObservers. We only have to
-// clean up the non-PrefMember registrations.
-- (void)unregisterPrefObservers {
- if (!prefs_) return;
-
- // Basics
- prefs_->RemovePrefObserver(prefs::kURLsToRestoreOnStartup, observer_.get());
-
- // Nothing to do for other panels...
-}
-
// Called when the window wants to be closed.
- (BOOL)windowShouldClose:(id)sender {
// Stop any animation and clear the delegate to avoid stale pointers.
@@ -813,7 +850,7 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
if ([key isEqualToString:@"isHomepageURLEnabled"]) {
paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
paths = [paths setByAddingObject:@"homepageURL"];
- } else if ([key isEqualToString:@"enableRestoreButtons"]) {
+ } else if ([key isEqualToString:@"restoreURLsEnabled"]) {
paths = [paths setByAddingObject:@"restoreOnStartupIndex"];
} else if ([key isEqualToString:@"isHomepageChoiceEnabled"]) {
paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
@@ -869,17 +906,17 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
// 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::wstring*)prefName {
+- (void)basicsPrefChanged:(std::string*)prefName {
if (*prefName == prefs::kRestoreOnStartup) {
const SessionStartupPref startupPref =
SessionStartupPref::GetStartupPref(prefs_);
[self setRestoreOnStartupIndex:startupPref.type];
+ [self setEnabledStateOfRestoreOnStartup];
}
if (*prefName == prefs::kURLsToRestoreOnStartup) {
- const SessionStartupPref startupPref =
- SessionStartupPref::GetStartupPref(prefs_);
- [customPagesSource_ setURLs:startupPref.urls];
+ [customPagesSource_ reloadURLs];
+ [self setEnabledStateOfRestoreOnStartup];
}
if (*prefName == prefs::kHomePageIsNewTabPage) {
@@ -893,6 +930,7 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
if (*prefName == prefs::kShowHomeButton) {
[self setShowHomeButton:showHomeButton_.GetValue() ? YES : NO];
+ [self setShowHomeButtonEnabled:!showHomeButton_.IsManaged()];
}
}
@@ -934,10 +972,13 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase {
[self saveSessionStartupWithType:startupType];
}
-// Returns whether or not the +/-/Current buttons should be enabled, based on
-// the current pref value for the startup urls.
-- (BOOL)enableRestoreButtons {
- return [self restoreOnStartupIndex] == SessionStartupPref::URLS;
+// 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.
@@ -1054,10 +1095,13 @@ enum { kHomepageNewTabPage, kHomepageURL };
// appropriate user metric.
- (void)setNewTabPageIsHomePageIndex:(NSInteger)index {
bool useNewTabPage = index == kHomepageNewTabPage ? true : false;
- if (useNewTabPage)
+ if (useNewTabPage) {
[self recordUserAction:UserMetricsAction("Options_Homepage_UseNewTab")];
- else
+ } else {
[self recordUserAction:UserMetricsAction("Options_Homepage_UseURL")];
+ if ([self isHomepageNewTabUIURL])
+ homepage_.SetValueIfNotManaged(std::string());
+ }
newTabPageIsHomePage_.SetValueIfNotManaged(useNewTabPage);
}
@@ -1105,7 +1149,7 @@ enum { kHomepageNewTabPage, kHomepageURL };
else
[self recordUserAction:UserMetricsAction(
"Options_Homepage_HideHomeButton")];
- showHomeButton_.SetValue(value ? true : false);
+ showHomeButton_.SetValueIfNotManaged(value ? true : false);
}
// Getter for the |searchEngineModel| property for bindings.
@@ -1175,9 +1219,10 @@ enum { kHomepageNewTabPage, kHomepageURL };
stringId = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
else
stringId = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN;
- std::wstring text =
- l10n_util::GetStringF(stringId, l10n_util::GetString(IDS_PRODUCT_NAME));
- return base::SysWideToNSString(text);
+ string16 text =
+ l10n_util::GetStringFUTF16(stringId,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ return base::SysUTF16ToNSString(text);
}
//-------------------------------------------------------------------------
@@ -1192,10 +1237,18 @@ const int kDisabledIndex = 1;
// 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::wstring*)prefName {
+- (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];
@@ -1285,7 +1338,7 @@ const int kDisabledIndex = 1;
} else {
// Otherwise, the sync button was a "sync my bookmarks" button.
// Kick off the sync setup process.
- syncService_->EnableForUser(NULL);
+ syncService_->ShowLoginDialog(NULL);
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
}
}
@@ -1318,18 +1371,13 @@ const int kDisabledIndex = 1;
else
[self recordUserAction:UserMetricsAction(
"Options_PasswordManager_Disable")];
- askSavePasswords_.SetValue(value == kEnabledIndex ? true : false);
+ askSavePasswords_.SetValueIfNotManaged(value == kEnabledIndex ? true : false);
}
- (NSInteger)passwordManagerEnabledIndex {
return askSavePasswords_.GetValue() ? kEnabledIndex : kDisabledIndex;
}
-// Returns whether the password manager buttons should be enabled.
-- (BOOL)isPasswordManagerEnabled {
- return !askSavePasswords_.IsManaged();
-}
-
- (void)setIsUsingDefaultTheme:(BOOL)value {
if (value)
[self recordUserAction:UserMetricsAction(
@@ -1350,22 +1398,32 @@ const int kDisabledIndex = 1;
// 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::wstring*)prefName {
+- (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 setMetricsRecording:metricsRecording_.GetValue() ? YES : NO];
+ [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];
@@ -1373,6 +1431,10 @@ const int kDisabledIndex = 1;
else if (*prefName == prefs::kEnableTranslate) {
[self setTranslateEnabled:translateEnabled_.GetValue() ? YES : NO];
}
+ else if (*prefName == prefs::kBackgroundModeEnabled) {
+ [self setBackgroundModeEnabled:backgroundModeEnabled_.GetValue() ?
+ YES : NO];
+ }
else if (*prefName == prefs::kWebkitTabsToLinks) {
[self setTabsToLinks:tabsToLinks_.GetValue() ? YES : NO];
}
@@ -1380,6 +1442,9 @@ const int kDisabledIndex = 1;
// 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.
@@ -1433,8 +1498,16 @@ const int kDisabledIndex = 1;
GURL(), NEW_WINDOW, PageTransition::LINK);
}
+- (IBAction)backgroundModeLearnMore:(id)sender {
+ // We open a new browser window so the Options dialog doesn't get lost
+ // behind other windows.
+ Browser::Create(profile_)->OpenURL(
+ GURL(l10n_util::GetStringUTF16(IDS_LEARN_MORE_BACKGROUND_MODE_URL)),
+ GURL(), NEW_WINDOW, PageTransition::LINK);
+}
+
- (IBAction)resetAutoOpenFiles:(id)sender {
- profile_->GetDownloadManager()->ResetAutoOpenFiles();
+ profile_->GetDownloadManager()->download_prefs()->ResetAutoOpen();
[self recordUserAction:UserMetricsAction("Options_ResetAutoOpenFiles")];
}
@@ -1443,21 +1516,18 @@ const int kDisabledIndex = 1;
@"/System/Library/PreferencePanes/Network.prefPane"]];
const char* proxyPrefCommand = "Proxies";
- AEDesc openParams = { typeNull, NULL };
+ scoped_aedesc<> openParams;
OSStatus status = AECreateDesc('ptru',
proxyPrefCommand,
strlen(proxyPrefCommand),
- &openParams);
+ openParams.OutPointer());
LOG_IF(ERROR, status != noErr) << "Failed to create open params: " << status;
LSLaunchURLSpec launchSpec = { 0 };
launchSpec.itemURLs = (CFArrayRef)itemsToOpen;
- launchSpec.passThruParams = &openParams;
+ launchSpec.passThruParams = openParams;
launchSpec.launchFlags = kLSLaunchAsync | kLSLaunchDontAddToRecents;
LSOpenFromURLSpec(&launchSpec, NULL);
-
- if (openParams.descriptorType != typeNull)
- AEDisposeDesc(&openParams);
}
// Returns whether the alternate error page checkbox should be checked based
@@ -1475,12 +1545,7 @@ const int kDisabledIndex = 1;
else
[self recordUserAction:UserMetricsAction(
"Options_LinkDoctorCheckbox_Disable")];
- alternateErrorPages_.SetValue(value ? true : false);
-}
-
-// Returns whether the alternate error page checkbox should be enabled.
-- (BOOL)isAlternateErrorPagesEnabled {
- return !alternateErrorPages_.IsManaged();
+ alternateErrorPages_.SetValueIfNotManaged(value ? true : false);
}
// Returns whether the suggest checkbox should be checked based on the
@@ -1498,12 +1563,7 @@ const int kDisabledIndex = 1;
else
[self recordUserAction:UserMetricsAction(
"Options_UseSuggestCheckbox_Disable")];
- useSuggest_.SetValue(value ? true : false);
-}
-
-// Returns whether the suggest checkbox should be enabled.
-- (BOOL)isSuggestEnabled {
- return !useSuggest_.IsManaged();
+ useSuggest_.SetValueIfNotManaged(value ? true : false);
}
// Returns whether the DNS prefetch checkbox should be checked based on the
@@ -1521,13 +1581,8 @@ const int kDisabledIndex = 1;
else
[self recordUserAction:UserMetricsAction(
"Options_DnsPrefetchCheckbox_Disable")];
- dnsPrefetch_.SetValue(value ? true : false);
- chrome_browser_net::EnablePredictor(value ? true : false);
-}
-
-// Returns whether the DNS prefetch checkbox should be enabled.
-- (BOOL)isDnsPrefetchEnabled {
- return !dnsPrefetch_.IsManaged();
+ dnsPrefetch_.SetValueIfNotManaged(value ? true : false);
+ chrome_browser_net::EnablePredictor(dnsPrefetch_.GetValue());
}
// Returns whether the safe browsing checkbox should be checked based on the
@@ -1545,36 +1600,37 @@ const int kDisabledIndex = 1;
else
[self recordUserAction:UserMetricsAction(
"Options_SafeBrowsingCheckbox_Disable")];
- bool enabled = value ? true : false;
- safeBrowsing_.SetValue(enabled);
+ 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, enabled));
-}
-
-// Returns whether the safe browsing checkbox should be enabled.
-- (BOOL)isSafeBrowsingEnabled {
- return !safeBrowsing_.IsManaged();
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(safeBrowsingService,
+ &SafeBrowsingService::OnEnable,
+ safeBrowsing_.GetValue()));
}
-// Returns whether the metrics recording checkbox should be checked based on the
+// Returns whether the metrics reporting checkbox should be checked based on the
// preference.
-- (BOOL)metricsRecording {
- return metricsRecording_.GetValue() ? YES : NO;
+- (BOOL)metricsReporting {
+ return metricsReporting_.GetValue() ? YES : NO;
}
-// Sets the backend pref for whether or not the metrics recording checkbox
+// Sets the backend pref for whether or not the metrics reporting checkbox
// should be displayed based on |value|.
-- (void)setMetricsRecording:(BOOL)value {
+- (void)setMetricsReporting:(BOOL)value {
if (value)
[self recordUserAction:UserMetricsAction(
"Options_MetricsReportingCheckbox_Enable")];
else
[self recordUserAction:UserMetricsAction(
"Options_MetricsReportingCheckbox_Disable")];
- bool enabled = value ? true : false;
+ // 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) {
@@ -1595,15 +1651,6 @@ const int kDisabledIndex = 1;
else
metrics->Stop();
}
-
- // TODO(pinkerton): windows shows a dialog here telling the user they need to
- // restart for this to take effect. http://crbug.com/34653
- metricsRecording_.SetValue(enabled);
-}
-
-// Returns whether the metrics recording checkbox should be enabled.
-- (BOOL)isMetricsRecordingEnabled {
- return !metricsRecording_.IsManaged();
}
- (NSURL*)defaultDownloadLocation {
@@ -1630,7 +1677,7 @@ const int kDisabledIndex = 1;
- (BOOL)fileHandlerUIEnabled {
if (!profile_->GetDownloadManager()) // Not set in unit tests.
return NO;
- return profile_->GetDownloadManager()->HasAutoOpenFileTypesRegistered();
+ return profile_->GetDownloadManager()->download_prefs()->IsAutoOpenUsed();
}
- (void)setFileHandlerUIEnabled:(BOOL)value {
@@ -1650,6 +1697,19 @@ const int kDisabledIndex = 1;
translateEnabled_.SetValue(value);
}
+- (BOOL)backgroundModeEnabled {
+ return backgroundModeEnabled_.GetValue();
+}
+
+- (void)setBackgroundModeEnabled:(BOOL)value {
+ if (value) {
+ [self recordUserAction:UserMetricsAction("Options_BackgroundMode_Enable")];
+ } else {
+ [self recordUserAction:UserMetricsAction("Options_BackgroundMode_Disable")];
+ }
+ backgroundModeEnabled_.SetValue(value);
+}
+
- (BOOL)tabsToLinks {
return tabsToLinks_.GetValue();
}
@@ -1721,7 +1781,7 @@ const int kDisabledIndex = 1;
// Callback when preferences are changed. |prefName| is the name of the
// pref that has changed and should not be NULL.
-- (void)prefChanged:(std::wstring*)prefName {
+- (void)prefChanged:(std::string*)prefName {
DCHECK(prefName);
if (!prefName) return;
[self basicsPrefChanged:prefName];
@@ -1783,10 +1843,6 @@ const int kDisabledIndex = 1;
[syncStatus_ setBackgroundColor:syncStatusNoErrorBackgroundColor_];
[syncLinkCell setBackgroundColor:syncLinkNoErrorBackgroundColor_];
}
-
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kShowPrivacyDashboardLink))
- [privacyDashboardLink_ setHidden:YES];
}
// Show the preferences window.
@@ -1950,9 +2006,16 @@ const int kDisabledIndex = 1;
// 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, prefs_));
+ self, page, local, prefs_));
}
- (void)switchToPage:(OptionsPage)page animate:(BOOL)animate {
diff --git a/chrome/browser/cocoa/preferences_window_controller_unittest.mm b/chrome/browser/cocoa/preferences_window_controller_unittest.mm
index cd47d5c..c22a581 100644
--- a/chrome/browser/cocoa/preferences_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/preferences_window_controller_unittest.mm
@@ -12,6 +12,7 @@
#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
@@ -197,27 +198,25 @@ TEST_F(PrefsControllerTest, SwitchToPage) {
EXPECT_TRUE([basicsView isDescendantOf:contentView]);
EXPECT_FALSE([personalStuffView isDescendantOf:contentView]);
EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
- EXPECT_TRUE([[toolbar selectedItemIdentifier] isEqualTo:basicsIdentifier]);
+ EXPECT_NSEQ(basicsIdentifier, [toolbar selectedItemIdentifier]);
EXPECT_EQ(OPTIONS_PAGE_GENERAL, lastSelectedPage->GetValue());
- EXPECT_TRUE([[window title] isEqualTo:[basicsToolbarItem label]]);
+ 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_TRUE([[toolbar selectedItemIdentifier]
- isEqualTo:personalStuffIdentifier]);
+ EXPECT_NSEQ([toolbar selectedItemIdentifier], personalStuffIdentifier);
EXPECT_EQ(OPTIONS_PAGE_CONTENT, lastSelectedPage->GetValue());
- EXPECT_TRUE([[window title] isEqualTo:[personalStuffToolbarItem label]]);
+ 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_TRUE([[toolbar selectedItemIdentifier]
- isEqualTo:underTheHoodIdentifier]);
+ EXPECT_NSEQ([toolbar selectedItemIdentifier], underTheHoodIdentifier);
EXPECT_EQ(OPTIONS_PAGE_ADVANCED, lastSelectedPage->GetValue());
- EXPECT_TRUE([[window title] isEqualTo:[underTheHoodToolbarItem label]]);
+ EXPECT_NSEQ([underTheHoodToolbarItem label], [window title]);
// Test OPTIONS_PAGE_DEFAULT.
@@ -226,10 +225,9 @@ TEST_F(PrefsControllerTest, SwitchToPage) {
EXPECT_FALSE([basicsView isDescendantOf:contentView]);
EXPECT_TRUE([personalStuffView isDescendantOf:contentView]);
EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
- EXPECT_TRUE([[toolbar selectedItemIdentifier]
- isEqualTo:personalStuffIdentifier]);
+ EXPECT_NSEQ(personalStuffIdentifier, [toolbar selectedItemIdentifier]);
EXPECT_EQ(OPTIONS_PAGE_CONTENT, lastSelectedPage->GetValue());
- EXPECT_TRUE([[window title] isEqualTo:[personalStuffToolbarItem label]]);
+ 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.
diff --git a/chrome/browser/cocoa/reload_button.h b/chrome/browser/cocoa/reload_button.h
index c26f047..493da1c 100644
--- a/chrome/browser/cocoa/reload_button.h
+++ b/chrome/browser/cocoa/reload_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
#define CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/reload_button.mm b/chrome/browser/cocoa/reload_button.mm
index 4f82bf0..4a46a51 100644
--- a/chrome/browser/cocoa/reload_button.mm
+++ b/chrome/browser/cocoa/reload_button.mm
@@ -6,6 +6,7 @@
#include "base/nsimage_cache_mac.h"
#include "chrome/app/chrome_dll_resource.h"
+#import "chrome/browser/cocoa/gradient_button_cell.h"
#import "chrome/browser/cocoa/view_id_util.h"
namespace {
@@ -58,15 +59,26 @@ NSString* const kStopImageName = @"stop_Template.pdf";
// 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 make no change.
+ // that reload mode is desired and disable the button.
if (isLoading) {
[self setImage:nsimage_cache::ImageNamed(kStopImageName)];
[self setTag:IDC_STOP];
+ [self setEnabled:YES];
} else if (force || ![self isMouseInside]) {
[self setImage:nsimage_cache::ImageNamed(kReloadImageName)];
[self setTag: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) {
pendingReloadMode_ = YES;
+ [self setEnabled:NO];
}
}
diff --git a/chrome/browser/cocoa/reload_button_unittest.mm b/chrome/browser/cocoa/reload_button_unittest.mm
index 64deb96..c2c9e84 100644
--- a/chrome/browser/cocoa/reload_button_unittest.mm
+++ b/chrome/browser/cocoa/reload_button_unittest.mm
@@ -154,6 +154,7 @@ TEST_F(ReloadButtonTest, StopAfterReloadSet) {
// Get to stop mode.
[button_ setIsLoading:YES force:YES];
EXPECT_EQ([button_ tag], IDC_STOP);
+ EXPECT_TRUE([button_ isEnabled]);
// Expect the action once.
[[mock_target expect] anAction:button_];
@@ -165,21 +166,23 @@ TEST_F(ReloadButtonTest, StopAfterReloadSet) {
[NSApp postEvent:click.second atStart:YES];
[button_ mouseDown:click.first];
EXPECT_EQ([button_ tag], IDC_RELOAD);
+ EXPECT_TRUE([button_ isEnabled]);
// Get back to stop mode.
[button_ setIsLoading:YES force:YES];
EXPECT_EQ([button_ tag], IDC_STOP);
+ EXPECT_TRUE([button_ isEnabled]);
- // If hover prevented reload mode immediately taking effect, clicks
- // should not send any action, but should still transition to reload
- // mode.
+ // 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([button_ tag], IDC_STOP);
+ EXPECT_FALSE([button_ isEnabled]);
[NSApp postEvent:click.second atStart:YES];
[button_ mouseDown:click.first];
- EXPECT_EQ([button_ tag], IDC_RELOAD);
+ EXPECT_EQ([button_ tag], IDC_STOP);
[button_ setTarget:nil];
}
diff --git a/chrome/browser/cocoa/repost_form_warning_mac.h b/chrome/browser/cocoa/repost_form_warning_mac.h
index a1ebeee..25f3f3e 100644
--- a/chrome/browser/cocoa/repost_form_warning_mac.h
+++ b/chrome/browser/cocoa/repost_form_warning_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_REPOST_FORM_WARNING_MAC_H_
#define CHROME_BROWSER_COCOA_REPOST_FORM_WARNING_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/restart_browser.h b/chrome/browser/cocoa/restart_browser.h
index 1d6ab41..73d6562 100644
--- a/chrome/browser/cocoa/restart_browser.h
+++ b/chrome/browser/cocoa/restart_browser.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
#define CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/restart_browser.mm b/chrome/browser/cocoa/restart_browser.mm
index d3747d6..db1dc16 100644
--- a/chrome/browser/cocoa/restart_browser.mm
+++ b/chrome/browser/cocoa/restart_browser.mm
@@ -4,10 +4,11 @@
#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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.h b/chrome/browser/cocoa/rwhvm_editcommand_helper.h
index cd38cd8..706f8a0 100644
--- a/chrome/browser/cocoa/rwhvm_editcommand_helper.h
+++ b/chrome/browser/cocoa/rwhvm_editcommand_helper.h
@@ -1,15 +1,16 @@
-// 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.
#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 "base/logging.h"
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
// RenderWidgetHostViewMacEditCommandHelper is the real name of this class
@@ -68,4 +69,4 @@ class RWHVMEditCommandHelper {
DISALLOW_COPY_AND_ASSIGN(RWHVMEditCommandHelper);
};
-#endif // CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
+#endif // CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
diff --git a/chrome/browser/cocoa/sad_tab_controller.h b/chrome/browser/cocoa/sad_tab_controller.h
index 148729a..b348710 100644
--- a/chrome/browser/cocoa/sad_tab_controller.h
+++ b/chrome/browser/cocoa/sad_tab_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_SAD_TAB_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_SAD_TAB_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/sad_tab_controller_unittest.mm b/chrome/browser/cocoa/sad_tab_controller_unittest.mm
index bce97a6..c125f87 100644
--- a/chrome/browser/cocoa/sad_tab_controller_unittest.mm
+++ b/chrome/browser/cocoa/sad_tab_controller_unittest.mm
@@ -7,6 +7,8 @@
#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.
diff --git a/chrome/browser/cocoa/sad_tab_view.h b/chrome/browser/cocoa/sad_tab_view.h
index f89e679..7713c72 100644
--- a/chrome/browser/cocoa/sad_tab_view.h
+++ b/chrome/browser/cocoa/sad_tab_view.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/scoped_authorizationref.h b/chrome/browser/cocoa/scoped_authorizationref.h
index 7763f82..3ffa18b 100644
--- a/chrome/browser/cocoa/scoped_authorizationref.h
+++ b/chrome/browser/cocoa/scoped_authorizationref.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_SCOPED_AUTHORIZATIONREF_H_
#define CHROME_BROWSER_COCOA_SCOPED_AUTHORIZATIONREF_H_
+#pragma once
#include <Security/Authorization.h>
diff --git a/chrome/browser/cocoa/search_engine_list_model.h b/chrome/browser/cocoa/search_engine_list_model.h
index 3d1fd58..a3e3c2a 100644
--- a/chrome/browser/cocoa/search_engine_list_model.h
+++ b/chrome/browser/cocoa/search_engine_list_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
#define CHROME_BROWSER_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/search_engine_list_model.mm b/chrome/browser/cocoa/search_engine_list_model.mm
index 50eac21..50c606c 100644
--- a/chrome/browser/cocoa/search_engine_list_model.mm
+++ b/chrome/browser/cocoa/search_engine_list_model.mm
@@ -7,6 +7,7 @@
#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";
diff --git a/chrome/browser/cocoa/search_engine_list_model_unittest.mm b/chrome/browser/cocoa/search_engine_list_model_unittest.mm
index c6a45cf..683d454 100644
--- a/chrome/browser/cocoa/search_engine_list_model_unittest.mm
+++ b/chrome/browser/cocoa/search_engine_list_model_unittest.mm
@@ -9,6 +9,7 @@
#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.
@@ -103,7 +104,7 @@ TEST_F(SearchEngineListModelTest, Default) {
EXPECT_EQ([model_ defaultIndex], 2U);
NSString* defaultString = [[model_ searchEngines] objectAtIndex:2];
- EXPECT_TRUE([@"google4" isEqualToString:defaultString]);
+ EXPECT_NSEQ(@"google4", defaultString);
}
// Make sure that when the back-end model changes that we get a notification.
diff --git a/chrome/browser/cocoa/shell_dialogs_mac.mm b/chrome/browser/cocoa/shell_dialogs_mac.mm
index 6ee68f0..59fc881 100644
--- a/chrome/browser/cocoa/shell_dialogs_mac.mm
+++ b/chrome/browser/cocoa/shell_dialogs_mac.mm
@@ -9,6 +9,7 @@
#include <map>
#include <set>
+#include <vector>
#include "app/l10n_util_mac.h"
#import "base/cocoa_protocols_mac.h"
@@ -63,14 +64,14 @@ class SelectFileDialogImpl : public SelectFileDialog {
void* params);
// Callback from ObjC bridge.
- void FileWasSelected(NSPanel* dialog,
+ void FileWasSelected(NSSavePanel* dialog,
NSWindow* parent_window,
bool was_cancelled,
bool is_multi,
const std::vector<FilePath>& files,
int index);
- bool ShouldEnableFilename(NSPanel* dialog, NSString* filename);
+ bool ShouldEnableFilename(NSSavePanel* dialog, NSString* filename);
struct SheetContext {
Type type;
@@ -89,13 +90,13 @@ class SelectFileDialogImpl : public SelectFileDialog {
scoped_nsobject<SelectFileDialogBridge> bridge_;
// A map from file dialogs to the |params| user data associated with them.
- std::map<NSPanel*, void*> params_map_;
+ 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<NSPanel*, Type> type_map_;
+ std::map<NSSavePanel*, Type> type_map_;
DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
};
@@ -112,6 +113,19 @@ SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener)
}
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 {
@@ -230,7 +244,7 @@ void SelectFileDialogImpl::SelectFile(
}
}
-void SelectFileDialogImpl::FileWasSelected(NSPanel* dialog,
+void SelectFileDialogImpl::FileWasSelected(NSSavePanel* dialog,
NSWindow* parent_window,
bool was_cancelled,
bool is_multi,
@@ -311,7 +325,7 @@ NSView* SelectFileDialogImpl::GetAccessoryView(const FileTypeInfo* file_types,
return accessory_view;
}
-bool SelectFileDialogImpl::ShouldEnableFilename(NSPanel* dialog,
+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)
diff --git a/chrome/browser/cocoa/side_tab_strip_controller.mm b/chrome/browser/cocoa/side_tab_strip_controller.mm
index 0f59329..9ff73d1 100644
--- a/chrome/browser/cocoa/side_tab_strip_controller.mm
+++ b/chrome/browser/cocoa/side_tab_strip_controller.mm
@@ -14,8 +14,12 @@
- (id)initWithView:(TabStripView*)view
switchView:(NSView*)switchView
- browser:(Browser*)browser {
- self = [super initWithView:view switchView:switchView browser:browser];
+ 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.
diff --git a/chrome/browser/cocoa/simple_content_exceptions_window_controller.h b/chrome/browser/cocoa/simple_content_exceptions_window_controller.h
index aa1cfcf..0e29f68 100644
--- a/chrome/browser/cocoa/simple_content_exceptions_window_controller.h
+++ b/chrome/browser/cocoa/simple_content_exceptions_window_controller.h
@@ -6,26 +6,25 @@
#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,
- NSTableViewDataSource,
- NSTableViewDelegate> {
+ <NSWindowDelegate> {
@private
IBOutlet NSTableView* tableView_;
IBOutlet NSButton* removeButton_;
IBOutlet NSButton* removeAllButton_;
IBOutlet NSButton* doneButton_;
+ IBOutlet TableModelArrayController* arrayController_;
scoped_ptr<RemoveRowsTableModel> model_;
- scoped_ptr<RemoveRowsObserverBridge> tableObserver_;
}
-// Shows or makes frontmost the geolocation exceptions window.
+// 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;
@@ -36,7 +35,4 @@ class RemoveRowsObserverBridge;
- (void)attachSheetTo:(NSWindow*)window;
- (IBAction)closeSheet:(id)sender;
-- (IBAction)removeRow:(id)sender;
-- (IBAction)removeAll:(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
index 7be52a9..e61efa8 100644
--- a/chrome/browser/cocoa/simple_content_exceptions_window_controller.mm
+++ b/chrome/browser/cocoa/simple_content_exceptions_window_controller.mm
@@ -4,10 +4,9 @@
#import "chrome/browser/cocoa/simple_content_exceptions_window_controller.h"
-#include <set>
-
#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"
@@ -16,35 +15,8 @@
@interface SimpleContentExceptionsWindowController (Private)
- (id)initWithTableModel:(RemoveRowsTableModel*)model;
-- (void)selectedRows:(RemoveRowsTableModel::Rows*)rows;
-- (void)adjustEditingButtons;
-- (void)modelDidChange;
@end
-// Observer for a RemoveRowsTableModel.
-class RemoveRowsObserverBridge : public TableModelObserver {
- public:
- RemoveRowsObserverBridge(SimpleContentExceptionsWindowController* controller)
- : controller_(controller) {}
- virtual ~RemoveRowsObserverBridge() {}
-
- virtual void OnModelChanged() {
- [controller_ modelDidChange];
- }
- virtual void OnItemsChanged(int start, int length) {
- [controller_ modelDidChange];
- }
- virtual void OnItemsAdded(int start, int length) {
- [controller_ modelDidChange];
- }
- virtual void OnItemsRemoved(int start, int length) {
- [controller_ modelDidChange];
- }
-
- private:
- SimpleContentExceptionsWindowController* controller_; // weak
-};
-
namespace {
const CGFloat kButtonBarHeight = 35.0;
@@ -69,8 +41,6 @@ SimpleContentExceptionsWindowController* g_exceptionWindow = nil;
ofType:@"nib"];
if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
model_.reset(model);
- tableObserver_.reset(new RemoveRowsObserverBridge(self));
- model_->SetObserver(tableObserver_.get());
// TODO(thakis): autoremember window rect.
// TODO(thakis): sorting support.
@@ -82,15 +52,19 @@ SimpleContentExceptionsWindowController* g_exceptionWindow = nil;
DCHECK([self window]);
DCHECK_EQ(self, [[self window] delegate]);
DCHECK(tableView_);
- DCHECK_EQ(self, [tableView_ dataSource]);
- DCHECK_EQ(self, [tableView_ delegate]);
+ DCHECK(arrayController_);
CGFloat minWidth = [[removeButton_ superview] bounds].size.width +
[[doneButton_ superview] bounds].size.width;
[[self window] setMinSize:NSMakeSize(minWidth,
[[self window] minSize].height)];
-
- [self adjustEditingButtons];
+ 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 {
@@ -104,9 +78,6 @@ SimpleContentExceptionsWindowController* g_exceptionWindow = nil;
}
- (void)windowWillClose:(NSNotification*)notification {
- // Without this, some of the unit tests fail on 10.6:
- [tableView_ setDataSource:nil];
-
g_exceptionWindow = nil;
[self autorelease];
}
@@ -124,7 +95,7 @@ SimpleContentExceptionsWindowController* g_exceptionWindow = nil;
case NSDeleteFunctionKey:
// Delete deletes.
if ([[tableView_ selectedRowIndexes] count] > 0)
- [self removeRow:self];
+ [arrayController_ remove:event];
return;
}
}
@@ -150,68 +121,5 @@ SimpleContentExceptionsWindowController* g_exceptionWindow = nil;
[NSApp endSheet:[self window]];
}
-- (IBAction)removeRow:(id)sender {
- RemoveRowsTableModel::Rows rows;
- [self selectedRows:&rows];
- model_->RemoveRows(rows);
-}
-
-- (IBAction)removeAll:(id)sender {
- model_->RemoveAll();
-}
-
-// Table View Data Source -----------------------------------------------------
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView*)table {
- return model_->RowCount();
-}
-
-- (id)tableView:(NSTableView*)tv
- objectValueForTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)row {
- NSObject* result = nil;
- NSString* identifier = [tableColumn identifier];
- if ([identifier isEqualToString:@"hostname"]) {
- std::wstring host = model_->GetText(row, IDS_EXCEPTIONS_HOSTNAME_HEADER);
- result = base::SysWideToNSString(host);
- } else if ([identifier isEqualToString:@"action"]) {
- std::wstring action = model_->GetText(row, IDS_EXCEPTIONS_ACTION_HEADER);
- result = base::SysWideToNSString(action);
- } else {
- NOTREACHED();
- }
- return result;
-}
-
-// Table View Delegate --------------------------------------------------------
-
-// When the selection in the table view changes, we need to adjust buttons.
-- (void)tableViewSelectionDidChange:(NSNotification*)notification {
- [self adjustEditingButtons];
-}
-
-// Private --------------------------------------------------------------------
-
-// Returns the selected rows.
-- (void)selectedRows:(RemoveRowsTableModel::Rows*)rows {
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- for (NSUInteger index = [selection lastIndex]; index != NSNotFound;
- index = [selection indexLessThanIndex:index])
- rows->insert(index);
-}
-
-// This method appropriately sets the enabled states on the table's editing
-// buttons.
-- (void)adjustEditingButtons {
- RemoveRowsTableModel::Rows rows;
- [self selectedRows:&rows];
- [removeButton_ setEnabled:model_->CanRemoveRows(rows)];
- [removeAllButton_ setEnabled:([tableView_ numberOfRows] > 0)];
-}
-
-- (void)modelDidChange {
- [tableView_ reloadData];
- [self adjustEditingButtons];
-}
@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
index 34e96a5..05b025c 100644
--- a/chrome/browser/cocoa/simple_content_exceptions_window_controller_unittest.mm
+++ b/chrome/browser/cocoa/simple_content_exceptions_window_controller_unittest.mm
@@ -11,9 +11,26 @@
#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 {
@@ -21,12 +38,13 @@ class SimpleContentExceptionsWindowControllerTest : public CocoaTest {
virtual void SetUp() {
CocoaTest::SetUp();
TestingProfile* profile = browser_helper_.profile();
- settingsMap_ = new GeolocationContentSettingsMap(profile);
+ geolocation_settings_ = new GeolocationContentSettingsMap(profile);
+ content_settings_ = new HostContentSettingsMap(profile);
}
SimpleContentExceptionsWindowController* GetController() {
- GeolocationExceptionsTableModel* model = // Freed by window controller.
- new GeolocationExceptionsTableModel(settingsMap_.get());
+ GeolocationExceptionsTableModel* model = // Freed by window controller.
+ new GeolocationExceptionsTableModel(geolocation_settings_.get());
id controller = [SimpleContentExceptionsWindowController
controllerWithTableModel:model];
[controller showWindow:nil];
@@ -34,17 +52,27 @@ class SimpleContentExceptionsWindowControllerTest : public CocoaTest {
}
void ClickRemoveAll(SimpleContentExceptionsWindowController* controller) {
- [controller removeAll:nil];
+ [controller.arrayController removeAll:nil];
}
protected:
BrowserTestHelper browser_helper_;
- scoped_refptr<GeolocationContentSettingsMap> settingsMap_;
+ scoped_refptr<GeolocationContentSettingsMap> geolocation_settings_;
+ scoped_refptr<HostContentSettingsMap> content_settings_;
};
TEST_F(SimpleContentExceptionsWindowControllerTest, Construction) {
GeolocationExceptionsTableModel* model = // Freed by window controller.
- new GeolocationExceptionsTableModel(settingsMap_.get());
+ 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];
@@ -52,7 +80,7 @@ TEST_F(SimpleContentExceptionsWindowControllerTest, Construction) {
}
TEST_F(SimpleContentExceptionsWindowControllerTest, AddExistingEditAdd) {
- settingsMap_->SetContentSetting(
+ geolocation_settings_->SetContentSetting(
GURL("http://myhost"), GURL(), CONTENT_SETTING_BLOCK);
SimpleContentExceptionsWindowController* controller = GetController();
@@ -60,7 +88,7 @@ TEST_F(SimpleContentExceptionsWindowControllerTest, AddExistingEditAdd) {
[controller close];
- EXPECT_EQ(0u, settingsMap_->GetAllOriginsSettings().size());
+ EXPECT_EQ(0u, geolocation_settings_->GetAllOriginsSettings().size());
}
} // namespace
diff --git a/chrome/browser/cocoa/ssl_client_certificate_selector.mm b/chrome/browser/cocoa/ssl_client_certificate_selector.mm
index 3f057af..b1d2da1 100644
--- a/chrome/browser/cocoa/ssl_client_certificate_selector.mm
+++ b/chrome/browser/cocoa/ssl_client_certificate_selector.mm
@@ -15,11 +15,64 @@
#import "base/scoped_nsobject.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/cocoa/constrained_window_mac.h"
#include "chrome/browser/chrome_thread.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.
@@ -30,21 +83,22 @@
scoped_nsobject<NSMutableArray> identities_;
// The corresponding list of certificates.
std::vector<scoped_refptr<net::X509Certificate> > certificates_;
- // The panel we display.
- scoped_nsobject<SFChooseIdentityPanel> panel_;
+ // The currently open dialog.
+ ConstrainedWindow* window_;
}
- (id)initWithHandler:(SSLClientAuthHandler*)handler
certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo;
-- (void)displayDialog:(gfx::NativeWindow)parent;
+- (void)displayDialog:(TabContents*)parent;
@end
namespace browser {
void ShowSSLClientCertificateSelector(
- gfx::NativeWindow parent,
+ TabContents* parent,
net::SSLCertRequestInfo* cert_request_info,
SSLClientAuthHandler* delegate) {
+ // TODO(davidben): Implement a tab-modal dialog.
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
SSLClientCertificateSelectorCocoa* selector =
[[[SSLClientCertificateSelectorCocoa alloc]
@@ -64,6 +118,7 @@ void ShowSSLClientCertificateSelector(
if ((self = [super init])) {
handler_ = handler;
certRequestInfo_ = certRequestInfo;
+ window_ = NULL;
}
return self;
}
@@ -71,22 +126,32 @@ void ShowSSLClientCertificateSelector(
- (void)sheetDidEnd:(NSWindow*)parent
returnCode:(NSInteger)returnCode
context:(void*)context {
- net::X509Certificate* cert = NULL;
+ DCHECK(context);
+ SFChooseIdentityPanel* panel = static_cast<SFChooseIdentityPanel*>(context);
+ net::X509Certificate* cert = NULL;
if (returnCode == NSFileHandlingPanelOKButton) {
- NSUInteger index = [identities_ indexOfObject:(id)[panel_ identity]];
- DCHECK(index != NSNotFound);
- cert = certificates_[index];
+ 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);
- // Clean up. The retain occurred just before the sheet opened.
- [self release];
+ // 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:(gfx::NativeWindow)parent {
- DCHECK(!panel_.get());
+- (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]);
@@ -108,38 +173,24 @@ void ShowSSLClientCertificateSelector(
ASCIIToUTF16(certRequestInfo_->host_and_port));
// Create and set up a system choose-identity panel.
- panel_.reset([[SFChooseIdentityPanel alloc] init]);
- NSString* domain = base::SysUTF8ToNSString(
- "https://" + certRequestInfo_->host_and_port);
- // Setting the domain causes the dialog to record the preferred
- // identity in the system keychain.
- [panel_ setDomain:domain];
- [panel_ setInformativeText:message];
- [panel_ setDefaultButtonTitle:l10n_util::GetNSString(IDS_OK)];
- [panel_ setAlternateButtonTitle:l10n_util::GetNSString(IDS_CANCEL)];
+ 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];
+ [panel setPolicies:(id)sslPolicy];
CFRelease(sslPolicy);
}
- // Increase the retain count to keep |self| alive while the sheet
- // runs. -sheetDidEnd:returnCode:context: will release the
- // additional reference.
- [self retain];
- if (parent) {
- // Open the cert panel as a sheet on the browser window.
- [panel_ beginSheetForWindow:parent
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:context:)
- contextInfo:nil
- identities:identities_
- message:title];
- } else {
- // No available browser window, so run independently as a (blocking) dialog.
- int returnCode = [panel_ runModalForIdentities:identities_ message:title];
- [self sheetDidEnd:panel_ returnCode:returnCode context:nil];
- }
+ 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
index e1dadb9..de331d4 100644
--- a/chrome/browser/cocoa/status_bubble_mac.h
+++ b/chrome/browser/cocoa/status_bubble_mac.h
@@ -4,14 +4,17 @@
#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;
@@ -33,8 +36,8 @@ class StatusBubbleMac : public StatusBubble {
virtual ~StatusBubbleMac();
// StatusBubble implementation.
- virtual void SetStatus(const std::wstring& status);
- virtual void SetURL(const GURL& url, const std::wstring& languages);
+ 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);
@@ -53,6 +56,9 @@ class StatusBubbleMac : public StatusBubble {
// 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;
@@ -61,7 +67,7 @@ class StatusBubbleMac : public StatusBubble {
void SetState(StatusBubbleState state);
// Sets the bubble text for SetStatus and SetURL.
- void SetText(const std::wstring& text, bool is_url);
+ void SetText(const string16& text, bool is_url);
// Construct the window/widget if it does not already exist. (Safe to call if
// it does.)
@@ -101,11 +107,18 @@ class StatusBubbleMac : public StatusBubble {
void StartShowing();
void StartHiding();
+ // Cancel the expansion timer.
+ void CancelExpandTimer();
+
// The timer factory used for show and hide delay timers.
ScopedRunnableMethodFactory<StatusBubbleMac> timer_factory_;
- // Calculate the appropriate frame for the status bubble window.
- NSRect CalculateWindowFrame();
+ // 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
@@ -131,17 +144,29 @@ class StatusBubbleMac : public StatusBubble {
// 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 vertical offset (if any) that should
-// be applied to the StatusBubble's position.
-- (CGFloat)verticalOffsetForStatusBubble;
+// 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 // #ifndef CHROME_BROWSER_COCOA_STATUS_BUBBLE_MAC_H_
+#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
index a286c4d..e937668 100644
--- a/chrome/browser/cocoa/status_bubble_mac.mm
+++ b/chrome/browser/cocoa/status_bubble_mac.mm
@@ -11,9 +11,10 @@
#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 "googleurl/src/gurl.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"
@@ -23,7 +24,7 @@ namespace {
const int kWindowHeight = 18;
// The width of the bubble in relation to the width of the parent window.
-const double kWindowWidthPercent = 1.0 / 3.0;
+const CGFloat kWindowWidthPercent = 1.0 / 3.0;
// How close the mouse can get to the infobubble before it starts sliding
// off-screen.
@@ -51,6 +52,9 @@ const NSTimeInterval kHideFadeOutDurationSeconds = 0.200;
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 {
@@ -92,13 +96,15 @@ const NSTimeInterval kMinimumTimeInterval =
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) {
+ immediate_(false),
+ is_expanded_(false) {
}
StatusBubbleMac::~StatusBubbleMac() {
@@ -112,35 +118,70 @@ StatusBubbleMac::~StatusBubbleMac() {
}
}
-void StatusBubbleMac::SetStatus(const std::wstring& status) {
+void StatusBubbleMac::SetStatus(const string16& status) {
Create();
SetText(status, false);
}
-void StatusBubbleMac::SetURL(const GURL& url, const std::wstring& languages) {
+void StatusBubbleMac::SetURL(const GURL& url, const string16& languages) {
+ url_ = url;
+ languages_ = languages;
+
Create();
NSRect frame = [window_ frame];
- int text_width = static_cast<int>(frame.size.width -
+
+ // 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 =
- gfx::Font::CreateFont(base::SysNSStringToWide([font fontName]),
- [font pointSize]);
+ gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
- std::wstring status = gfx::ElideUrl(url, font_chr, text_width, languages);
+ string16 original_url_text = net::FormatUrl(url, UTF16ToUTF8(languages));
+ string16 status = WideToUTF16(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 std::wstring& text, bool is_url) {
+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::SysWideToNSString(text);
+ NSString* text_ns = base::SysUTF16ToNSString(text);
NSString** main;
NSString** backup;
@@ -178,6 +219,8 @@ void StatusBubbleMac::SetText(const std::wstring& text, bool is_url) {
void StatusBubbleMac::Hide() {
CancelTimer();
+ CancelExpandTimer();
+ is_expanded_ = false;
bool fade_out = false;
if (state_ == kBubbleHidingFadeOut || state_ == kBubbleShowingFadeIn) {
@@ -200,6 +243,17 @@ void StatusBubbleMac::Hide() {
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];
@@ -218,18 +272,16 @@ void StatusBubbleMac::MouseMoved(
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_ frame].origin;
-
- bool isShelfVisible = false;
-
- // Adjust the position to sit on top of download and extension shelves.
- // |delegate_| can be nil during unit tests.
- if ([delegate_ respondsToSelector:@selector(verticalOffsetForStatusBubble)]) {
- window_frame.origin.y += [delegate_ verticalOffsetForStatusBubble];
- isShelfVisible = [delegate_ verticalOffsetForStatusBubble] > 0;
- }
+ window_frame.origin = [parent_ convertBaseToScreen:baseFrame.origin];
// Get the cursor position relative to the popup.
cursor_location.x -= NSMaxX(window_frame);
@@ -258,7 +310,11 @@ void StatusBubbleMac::MouseMoved(
isOnScreen = false;
}
- if (isOnScreen && !isShelfVisible) {
+ // 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).
@@ -275,12 +331,12 @@ void StatusBubbleMac::MouseMoved(
}
window_frame.origin.y -= offset;
} else {
- // The bubble will obscure the download shelf. Move the bubble to the
- // right and reset Y offset_ to zero.
+ // 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([parent_ frame]) - NSWidth(window_frame);
+ window_frame.origin.x += NSWidth(baseFrame) - NSWidth(window_frame);
}
} else {
[[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
@@ -297,7 +353,7 @@ void StatusBubbleMac::Create() {
return;
// TODO(avi):fix this for RTL
- NSRect window_rect = CalculateWindowFrame();
+ NSRect window_rect = CalculateWindowFrame(/*expand=*/false);
// initWithContentRect has origin in screen coords and size in scaled window
// coordinates.
window_rect.size =
@@ -347,8 +403,10 @@ void StatusBubbleMac::Create() {
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())
+ if (!is_attached()) {
[parent_ addChildWindow:window_ ordered:NSWindowAbove];
+ UpdateSizeAndPosition();
+ }
}
void StatusBubbleMac::Detach() {
@@ -532,11 +590,74 @@ void StatusBubbleMac::StartHiding() {
// 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 = WideToUTF16(gfx::ElideUrl(url_, font_chr,
+ max_bubble_width, UTF16ToWide(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() display:YES];
+ [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:YES];
}
void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) {
@@ -557,14 +678,26 @@ void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) {
UpdateSizeAndPosition();
}
-NSRect StatusBubbleMac::CalculateWindowFrame() {
+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];
- NSRect rect = [parent_ frame];
- rect.size.height = size.height;
- rect.size.width = static_cast<int>(kWindowWidthPercent * rect.size.width);
- return rect;
+ 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
index 6a15f8b..771dff5 100644
--- a/chrome/browser/cocoa/status_bubble_mac_unittest.mm
+++ b/chrome/browser/cocoa/status_bubble_mac_unittest.mm
@@ -6,23 +6,50 @@
#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);
}
@@ -50,7 +77,8 @@ class StatusBubbleMacTest : public CocoaTest {
CocoaTest::SetUp();
NSWindow* window = test_window();
EXPECT_TRUE(window);
- delegate_.reset([[StatusBubbleMacTestDelegate alloc] init]);
+ delegate_.reset(
+ [[StatusBubbleMacTestDelegate alloc] initWithWindow: window]);
EXPECT_TRUE(delegate_.get());
bubble_ = new StatusBubbleMacIgnoreMouseMoved(window, delegate_);
EXPECT_TRUE(bubble_);
@@ -111,42 +139,42 @@ class StatusBubbleMacTest : public CocoaTest {
};
TEST_F(StatusBubbleMacTest, SetStatus) {
- bubble_->SetStatus(L"");
- bubble_->SetStatus(L"This is a test");
- EXPECT_TRUE([GetText() isEqualToString:@"This is a test"]);
+ 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(L"This is a test");
- EXPECT_TRUE([GetText() isEqualToString:@"This is a test"]);
+ bubble_->SetStatus(UTF8ToUTF16("This is a test"));
+ EXPECT_NSEQ(@"This is a test", GetText());
// Hide it
- bubble_->SetStatus(L"");
+ bubble_->SetStatus(string16());
EXPECT_FALSE(IsVisible());
}
TEST_F(StatusBubbleMacTest, SetURL) {
- bubble_->SetURL(GURL(), L"");
+ bubble_->SetURL(GURL(), string16());
EXPECT_FALSE(IsVisible());
- bubble_->SetURL(GURL("bad url"), L"");
+ bubble_->SetURL(GURL("bad url"), string16());
EXPECT_FALSE(IsVisible());
- bubble_->SetURL(GURL("http://"), L"");
+ bubble_->SetURL(GURL("http://"), string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetURLText() isEqualToString:@"http:"]);
- bubble_->SetURL(GURL("about:blank"), L"");
+ EXPECT_NSEQ(@"http:", GetURLText());
+ bubble_->SetURL(GURL("about:blank"), string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetURLText() isEqualToString:@"about:blank"]);
- bubble_->SetURL(GURL("foopy://"), L"");
+ EXPECT_NSEQ(@"about:blank", GetURLText());
+ bubble_->SetURL(GURL("foopy://"), string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetURLText() isEqualToString:@"foopy://"]);
- bubble_->SetURL(GURL("http://www.cnn.com"), L"");
+ EXPECT_NSEQ(@"foopy://", GetURLText());
+ bubble_->SetURL(GURL("http://www.cnn.com"), string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetURLText() isEqualToString:@"www.cnn.com"]);
+ EXPECT_NSEQ(@"www.cnn.com", GetURLText());
}
// Test hiding bubble that's already hidden.
TEST_F(StatusBubbleMacTest, Hides) {
- bubble_->SetStatus(L"Showing");
+ bubble_->SetStatus(UTF8ToUTF16("Showing"));
EXPECT_TRUE(IsVisible());
bubble_->Hide();
EXPECT_FALSE(IsVisible());
@@ -157,27 +185,27 @@ TEST_F(StatusBubbleMacTest, Hides) {
// Test the "main"/"backup" behavior in StatusBubbleMac::SetText().
TEST_F(StatusBubbleMacTest, SetStatusAndURL) {
EXPECT_FALSE(IsVisible());
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]);
- bubble_->SetURL(GURL("http://www.nytimes.com"), L"");
+ EXPECT_NSEQ(@"Status", GetBubbleViewText());
+ bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com"]);
- bubble_->SetURL(GURL(), L"");
+ EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
+ bubble_->SetURL(GURL(), string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]);
- bubble_->SetStatus(L"");
+ EXPECT_NSEQ(@"Status", GetBubbleViewText());
+ bubble_->SetStatus(string16());
EXPECT_FALSE(IsVisible());
- bubble_->SetURL(GURL("http://www.nytimes.com"), L"");
+ bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com"]);
- bubble_->SetStatus(L"Status");
+ EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]);
- bubble_->SetStatus(L"");
+ EXPECT_NSEQ(@"Status", GetBubbleViewText());
+ bubble_->SetStatus(string16());
EXPECT_TRUE(IsVisible());
- EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com"]);
- bubble_->SetURL(GURL(), L"");
+ EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
+ bubble_->SetURL(GURL(), string16());
EXPECT_FALSE(IsVisible());
}
@@ -193,7 +221,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"");
+ bubble_->SetStatus(string16());
EXPECT_FALSE(IsVisible());
EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
EXPECT_TRUE(States()->empty()); // no change from initial kBubbleHidden state
@@ -201,7 +229,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
// Next, a few ordinary cases
// Test StartShowing from kBubbleHidden
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
EXPECT_TRUE(IsVisible());
// Check GetState before checking States to make sure that all state
// transitions have been flushed to States.
@@ -213,19 +241,19 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
// Test StartShowing from kBubbleShown with the same message
States()->clear();
- bubble_->SetStatus(L"Status");
+ 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(L"New Status");
+ bubble_->SetStatus(UTF8ToUTF16("New Status"));
EXPECT_TRUE(IsVisible());
EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
EXPECT_TRUE(States()->empty());
// Test StartHiding from kBubbleShown
- bubble_->SetStatus(L"");
+ bubble_->SetStatus(string16());
EXPECT_FALSE(IsVisible());
// Check GetState before checking States to make sure that all state
// transitions have been flushed to States.
@@ -237,7 +265,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
// Test StartHiding from kBubbleHidden
States()->clear();
- bubble_->SetStatus(L"");
+ bubble_->SetStatus(string16());
EXPECT_FALSE(IsVisible());
EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
EXPECT_TRUE(States()->empty());
@@ -245,101 +273,103 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
// Now, the edge cases
// Test StartShowing from kBubbleShowingTimer
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleShowingTimer);
[GetWindow() setAlphaValue:0.0];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"Status");
+ 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(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleShowingFadeIn);
[GetWindow() setAlphaValue:0.5];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"Status");
+ 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(L""); // Go back to a deterministic state.
+ bubble_->SetStatus(string16()); // Go back to a deterministic state.
// Test StartShowing from kBubbleHidingTimer
- bubble_->SetStatus(L"");
+ bubble_->SetStatus(string16());
SetState(StatusBubbleMac::kBubbleHidingTimer);
[GetWindow() setAlphaValue:1.0];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"Status");
+ 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(L"");
+ bubble_->SetStatus(string16());
SetState(StatusBubbleMac::kBubbleHidingFadeOut);
[GetWindow() setAlphaValue:0.5];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"Status");
+ 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(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleShowingTimer);
[GetWindow() setAlphaValue:0.0];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"");
+ 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(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleShowingFadeIn);
[GetWindow() setAlphaValue:0.5];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"");
+ 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(L"");
+ bubble_->SetStatus(string16());
SetState(StatusBubbleMac::kBubbleHidingTimer);
[GetWindow() setAlphaValue:1.0];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"");
+ 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.
- bubble_->SetStatus(L"Status"); // Go back to a deterministic state.
+ // Go back to a deterministic state.
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
// Test StartHiding from kBubbleHidingFadeOut
- bubble_->SetStatus(L"");
+ bubble_->SetStatus(string16());
SetState(StatusBubbleMac::kBubbleHidingFadeOut);
[GetWindow() setAlphaValue:0.5];
States()->clear();
EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(L"");
+ 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.
- bubble_->SetStatus(L"Status"); // Go back to a deterministic state.
+ // Go back to a deterministic state.
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
// Test Hide from kBubbleHidden
- bubble_->SetStatus(L"");
+ bubble_->SetStatus(string16());
EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
States()->clear();
EXPECT_TRUE(States()->empty());
@@ -348,7 +378,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
EXPECT_TRUE(States()->empty());
// Test Hide from kBubbleShowingTimer
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleShowingTimer);
[GetWindow() setAlphaValue:0.0];
States()->clear();
@@ -359,7 +389,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
// Test Hide from kBubbleShowingFadeIn
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleShowingFadeIn);
[GetWindow() setAlphaValue:0.5];
States()->clear();
@@ -371,7 +401,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
// Test Hide from kBubbleShown
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
States()->clear();
EXPECT_TRUE(States()->empty());
bubble_->Hide();
@@ -380,7 +410,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
// Test Hide from kBubbleHidingTimer
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleHidingTimer);
States()->clear();
EXPECT_TRUE(States()->empty());
@@ -390,7 +420,7 @@ TEST_F(StatusBubbleMacTest, StateTransitions) {
EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
// Test Hide from kBubbleHidingFadeOut
- bubble_->SetStatus(L"Status");
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
SetState(StatusBubbleMac::kBubbleHidingFadeOut);
[GetWindow() setAlphaValue:0.5];
States()->clear();
@@ -409,7 +439,7 @@ TEST_F(StatusBubbleMacTest, Delete) {
// Create then delete while visible.
bubble = new StatusBubbleMac(window, nil);
- bubble->SetStatus(L"showing");
+ bubble->SetStatus(UTF8ToUTF16("showing"));
delete bubble;
}
@@ -422,7 +452,7 @@ TEST_F(StatusBubbleMacTest, UpdateSizeAndPosition) {
// Create a status bubble (with contents) and call resize (without actually
// resizing); the frame size shouldn't change.
- bubble_->SetStatus(L"UpdateSizeAndPosition test");
+ bubble_->SetStatus(UTF8ToUTF16("UpdateSizeAndPosition test"));
ASSERT_TRUE(GetWindow());
NSRect rect_before = [GetWindow() frame];
bubble_->UpdateSizeAndPosition();
@@ -458,3 +488,97 @@ TEST_F(StatusBubbleMacTest, UpdateSizeAndPosition) {
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
index 0f99539..78a2283 100644
--- a/chrome/browser/cocoa/status_icons/status_icon_mac.h
+++ b/chrome/browser/cocoa/status_icons/status_icon_mac.h
@@ -4,6 +4,7 @@
#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>
@@ -25,6 +26,10 @@ class StatusIconMac : public StatusIcon {
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();
diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/cocoa/status_icons/status_icon_mac.mm
index 5e824b8..6b79b45 100644
--- a/chrome/browser/cocoa/status_icons/status_icon_mac.mm
+++ b/chrome/browser/cocoa/status_icons/status_icon_mac.mm
@@ -75,3 +75,8 @@ void StatusIconMac::SetPressedImage(const SkBitmap& bitmap) {
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
index fe15bca..39246ab 100644
--- a/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm
+++ b/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/status_icons/status_tray_mac.h b/chrome/browser/cocoa/status_icons/status_tray_mac.h
index 9b4df80..3552db4 100644
--- a/chrome/browser/cocoa/status_icons/status_tray_mac.h
+++ b/chrome/browser/cocoa/status_icons/status_tray_mac.h
@@ -4,6 +4,7 @@
#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"
@@ -13,7 +14,7 @@ class StatusTrayMac : public StatusTray {
protected:
// Factory method for creating a status icon.
- virtual StatusIcon* CreateStatusIcon();
+ virtual StatusIcon* CreatePlatformStatusIcon();
private:
DISALLOW_COPY_AND_ASSIGN(StatusTrayMac);
diff --git a/chrome/browser/cocoa/status_icons/status_tray_mac.mm b/chrome/browser/cocoa/status_icons/status_tray_mac.mm
index 8c9449b..d4e176f 100644
--- a/chrome/browser/cocoa/status_icons/status_tray_mac.mm
+++ b/chrome/browser/cocoa/status_icons/status_tray_mac.mm
@@ -13,6 +13,6 @@ StatusTray* StatusTray::Create() {
StatusTrayMac::StatusTrayMac() {
}
-StatusIcon* StatusTrayMac::CreateStatusIcon() {
+StatusIcon* StatusTrayMac::CreatePlatformStatusIcon() {
return new StatusIconMac();
}
diff --git a/chrome/browser/cocoa/styled_text_field_cell.h b/chrome/browser/cocoa/styled_text_field_cell.h
index c89f7d1..5e8e286 100644
--- a/chrome/browser/cocoa/styled_text_field_cell.h
+++ b/chrome/browser/cocoa/styled_text_field_cell.h
@@ -4,9 +4,15 @@
#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
@@ -40,6 +46,9 @@
// 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;
diff --git a/chrome/browser/cocoa/styled_text_field_cell.mm b/chrome/browser/cocoa/styled_text_field_cell.mm
index 5289175..96a6c9f 100644
--- a/chrome/browser/cocoa/styled_text_field_cell.mm
+++ b/chrome/browser/cocoa/styled_text_field_cell.mm
@@ -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,21 +6,30 @@
#include "app/resource_bundle.h"
#include "base/logging.h"
-#include "chrome/browser/browser_theme_provider.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(const NSRect frame,
+NSBezierPath* RectPathWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
+ const NSRect frame,
const CGFloat inset,
const CGFloat outerRadius) {
- const NSRect insetFrame = NSInsetRect(frame, inset, inset);
+ NSRect insetFrame = NSInsetRect(frame, inset, inset);
+
if (outerRadius > 0.0) {
- return [NSBezierPath bezierPathWithRoundedRect:insetFrame
- xRadius:outerRadius - inset
- yRadius:outerRadius - inset];
+ 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];
}
@@ -29,11 +38,13 @@ NSBezierPath* RectPathWithInset(const NSRect frame,
// 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(const NSRect frame,
+void FillRectWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
+ const NSRect frame,
const CGFloat inset,
const CGFloat outerRadius,
NSColor* color) {
- NSBezierPath* path = RectPathWithInset(frame, inset, outerRadius);
+ NSBezierPath* path =
+ RectPathWithInset(roundedFlags, frame, inset, outerRadius);
[color setFill];
[path fill];
}
@@ -42,13 +53,15 @@ void FillRectWithInset(const NSRect frame,
// 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(const NSRect frame,
+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(frame, finalInset, outerRadius);
+ NSBezierPath* path =
+ RectPathWithInset(roundedFlags, frame, finalInset, outerRadius);
[color setStroke];
[path setLineWidth:lineWidth];
[path stroke];
@@ -85,6 +98,10 @@ private:
return 0.0;
}
+- (StyledTextFieldCellRoundedFlags)roundedFlags {
+ return StyledTextFieldCellRoundedAll;
+}
+
- (BOOL)shouldDrawBezel {
return NO;
}
@@ -121,6 +138,7 @@ private:
// 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.
@@ -129,7 +147,8 @@ private:
// Paint button background image if there is one (otherwise the border won't
// look right).
- ThemeProvider* themeProvider = [[controlView window] themeProvider];
+ BrowserThemeProvider* themeProvider =
+ static_cast<BrowserThemeProvider*>([[controlView window] themeProvider]);
if (themeProvider) {
NSColor* backgroundImageColor =
themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND, false);
@@ -142,7 +161,7 @@ private:
// 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(frame, 0.5, radius, backgroundImageColor);
+ FillRectWithInset(roundedFlags, frame, 0.5, radius, backgroundImageColor);
}
// Draw the outer stroke (over the background).
@@ -151,11 +170,11 @@ private:
active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
true);
- FrameRectWithInset(frame, 0.0, radius, 1.0, strokeColor);
+ FrameRectWithInset(roundedFlags, frame, 0.0, radius, 1.0, strokeColor);
}
// Fill interior with background color.
- FillRectWithInset(frame, 1.0, radius, [self backgroundColor]);
+ 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
@@ -164,15 +183,19 @@ private:
// will clip the bottom and right edges (and corner).
{
ScopedSaveGraphicsState state;
- [RectPathWithInset(frame, 1.0, radius) addClip];
+ [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(shadowFrame, 0.5, radius - 0.5, 1.0, shadowShade);
+ FrameRectWithInset(roundedFlags, shadowFrame, 0.5, radius - 0.5,
+ 1.0, shadowShade);
}
// Draw optional bezel below bottom stroke.
- if ([self shouldDrawBezel]) {
- [[NSColor colorWithCalibratedWhite:0.96 alpha:1.0] set];
+ 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),
@@ -185,7 +208,7 @@ private:
if ([self showsFirstResponder]) {
NSColor* color =
[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5];
- FrameRectWithInset(frame, 0.0, radius, 2.0, color);
+ FrameRectWithInset(roundedFlags, frame, 0.0, radius, 2.0, color);
}
[self drawInteriorWithFrame:cellFrame inView:controlView];
diff --git a/chrome/browser/cocoa/tab_contents_controller.h b/chrome/browser/cocoa/tab_contents_controller.h
index e3c27c1..64a60cc 100644
--- a/chrome/browser/cocoa/tab_contents_controller.h
+++ b/chrome/browser/cocoa/tab_contents_controller.h
@@ -4,28 +4,24 @@
#ifndef CHROME_BROWSER_COCOA_TAB_CONTENTS_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_TAB_CONTENTS_CONTROLLER_H_
+#pragma once
#include <Cocoa/Cocoa.h>
class TabContents;
-class TabContentsCommandObserver;
-class TabStripModel;
// A class that controls the web contents of a tab. It manages displaying the
-// native view for a given TabContents and optionally its docked devtools in
-// |contentsContainer_|.
-// Note that just creating the class does not display the view in
-// |contentsContainer_|. 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.
+// 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
- TabContentsCommandObserver* observer_; // nil if |commands_| is nil
TabContents* contents_; // weak
-
- IBOutlet NSSplitView* contentsContainer_;
}
+@property(readonly, nonatomic) TabContents* tabContents;
// Create the contents of a tab represented by |contents| and loaded from the
// nib given by |name|.
@@ -41,6 +37,10 @@ class TabStripModel;
// enabled.
- (void)willBecomeSelectedTab;
+// 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;
@@ -50,15 +50,6 @@ class TabStripModel;
// an entirely new tab contents object.
- (void)tabDidChange:(TabContents*)updatedContents;
-// Shows |devToolsContents| in a split view, or removes the bottom view in the
-// split viewif |devToolsContents| is NULL.
-// TODO(thakis): Either move this to tab_window or move infobar handling to here
-// too -- http://crbug.com/31633 .
-- (void)showDevToolsContents:(TabContents*)devToolsContents;
-
-// Returns the height required by devtools and divider, or 0 if no devtools are
-// docked to the tab.
-- (CGFloat)devToolsHeight;
@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
index 292097a..ac0c8c2 100644
--- a/chrome/browser/cocoa/tab_contents_controller.mm
+++ b/chrome/browser/cocoa/tab_contents_controller.mm
@@ -5,24 +5,13 @@
#import "chrome/browser/cocoa/tab_contents_controller.h"
#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/pref_service.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/common/pref_names.h"
-
-// Default offset of the contents splitter in pixels.
-static 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).
-static const int kMinWebHeight = 50;
@implementation TabContentsController
+@synthesize tabContents = contents_;
- (id)initWithNibName:(NSString*)name
contents:(TabContents*)contents {
@@ -39,15 +28,28 @@ static const int kMinWebHeight = 50;
[super dealloc];
}
+- (void)ensureContentsSizeDoesNotChange {
+ 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 {
- NSArray* subviews = [contentsContainer_ subviews];
- if ([subviews count] == 0)
- [contentsContainer_ addSubview:contents_->GetNativeView()];
- else if ([subviews objectAtIndex:0] != contents_->GetNativeView())
- [contentsContainer_ replaceSubview:[subviews objectAtIndex:0]
- with:contents_->GetNativeView()];
+ NSView* contentsContainer = [self view];
+ NSArray* subviews = [contentsContainer subviews];
+ NSView* contentsNativeView = contents_->GetNativeView();
+ [contentsNativeView setFrame:[contentsContainer frame]];
+ if ([subviews count] == 0) {
+ [contentsContainer addSubview:contentsNativeView];
+ } else if ([subviews objectAtIndex:0] != contentsNativeView) {
+ [contentsContainer replaceSubview:[subviews objectAtIndex:0]
+ with:contentsNativeView];
+ }
+ [contentsNativeView setAutoresizingMask:NSViewWidthSizable|
+ NSViewHeightSizable];
}
// Returns YES if the tab represented by this controller is the front-most.
@@ -58,15 +60,18 @@ static const int kMinWebHeight = 50;
}
- (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 = contents_->render_view_host();
- if (rvh)
+ if (rvh && rvh->view() && rvh->view()->HasFocus())
rvh->Blur();
}
- (void)willBecomeSelectedTab {
- RenderViewHost* rvh = contents_->render_view_host();
- if (rvh)
- rvh->Focus();
+ // 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 {
@@ -79,72 +84,4 @@ static const int kMinWebHeight = 50;
}
}
-- (void)showDevToolsContents:(TabContents*)devToolsContents {
- NSArray* subviews = [contentsContainer_ subviews];
- if (devToolsContents) {
- DCHECK_GE([subviews count], 1u);
-
- // Load the default split offset. If we are already showing devtools, we
- // will replace the default with the current devtools height.
- CGFloat splitOffset = g_browser_process->local_state()->GetInteger(
- prefs::kDevToolsSplitLocation);
- if (splitOffset == -1) {
- // Initial load, set to default value.
- splitOffset = kDefaultContentsSplitOffset;
- }
-
- // |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.
- NSView* devtoolsView = devToolsContents->GetNativeView();
- view_id_util::SetID(devtoolsView, VIEW_ID_DEV_TOOLS_DOCKED);
- if ([subviews count] == 1) {
- [contentsContainer_ addSubview:devtoolsView];
- } else {
- DCHECK_EQ([subviews count], 2u);
- [contentsContainer_ replaceSubview:[subviews objectAtIndex:1]
- with:devToolsContents->GetNativeView()];
- // If devtools are already visible, keep the current size.
- splitOffset = NSHeight([devtoolsView frame]);
- }
-
- // Make sure |splitOffset| isn't too large or too small.
- splitOffset = MIN(splitOffset,
- NSHeight([contentsContainer_ frame]) - kMinWebHeight);
- DCHECK_GE(splitOffset, 0) << "kMinWebHeight needs to be smaller than "
- << "smallest available tab contents space.";
- splitOffset = MAX(0, splitOffset);
-
- // 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.
- NSRect devtoolsFrame = [devtoolsView frame];
- devtoolsFrame.size.height = splitOffset;
- [devtoolsView setFrame:devtoolsFrame];
-
- NSRect webFrame = [[subviews objectAtIndex:0] frame];
- webFrame.size.height = NSHeight([contentsContainer_ frame]) -
- [self devToolsHeight];
- [[subviews objectAtIndex:0] setFrame:webFrame];
-
- [contentsContainer_ adjustSubviews];
- } 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];
- }
- }
-}
-
-- (CGFloat)devToolsHeight {
- NSArray* subviews = [contentsContainer_ subviews];
- if ([subviews count] < 2)
- return 0;
- return NSHeight([[subviews objectAtIndex:1] frame]) +
- [contentsContainer_ dividerThickness];
-}
-
@end
diff --git a/chrome/browser/cocoa/tab_controller.h b/chrome/browser/cocoa/tab_controller.h
index 36ddad1..02190a7 100644
--- a/chrome/browser/cocoa/tab_controller.h
+++ b/chrome/browser/cocoa/tab_controller.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm
index 040f9d6..9e5403c 100644
--- a/chrome/browser/cocoa/tab_controller.mm
+++ b/chrome/browser/cocoa/tab_controller.mm
@@ -4,12 +4,12 @@
#include "app/l10n_util_mac.h"
#include "base/mac_util.h"
-#import "chrome/browser/browser_theme_provider.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"
diff --git a/chrome/browser/cocoa/tab_controller_target.h b/chrome/browser/cocoa/tab_controller_target.h
index df1dad7..4e27b69 100644
--- a/chrome/browser/cocoa/tab_controller_target.h
+++ b/chrome/browser/cocoa/tab_controller_target.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/tab_controller_unittest.mm b/chrome/browser/cocoa/tab_controller_unittest.mm
index 16f527c..51f453e 100644
--- a/chrome/browser/cocoa/tab_controller_unittest.mm
+++ b/chrome/browser/cocoa/tab_controller_unittest.mm
@@ -9,6 +9,7 @@
#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
@@ -121,7 +122,7 @@ TEST_F(TabControllerTest, ToolTip) {
EXPECT_TRUE([[controller toolTip] length] == 0);
NSString *tooltip_string = @"Some text to use as a tab title";
[controller setTitle:tooltip_string];
- EXPECT_TRUE([tooltip_string isEqualToString:[controller toolTip]]);
+ EXPECT_NSEQ(tooltip_string, [controller toolTip]);
}
// Tests setting the |loading| property via code.
diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h
index ace64ba..170d3ac 100644
--- a/chrome/browser/cocoa/tab_strip_controller.h
+++ b/chrome/browser/cocoa/tab_strip_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_TAB_STRIP_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_TAB_STRIP_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -13,6 +14,7 @@
#import "chrome/browser/cocoa/url_drop_target.h"
#import "third_party/GTM/AppKit/GTMWindowSheetController.h"
+@class NewTabButton;
@class TabContentsController;
@class TabView;
@class TabStripView;
@@ -24,6 +26,26 @@ class TabStripModel;
class TabContents;
class ToolbarModel;
+// The interface for the tab strip controller's delegate. Currently, the
+// delegate is the BWC and is responsible for subviews layout and forwarding
+// these events to InfoBarContainerController.
+// Delegating TabStripModelObserverBridge's events (in lieu of subscrining
+// BWC and InfoBarContainerController to TabStripModelObserverBridge events)
+// 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: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
@@ -40,17 +62,22 @@ class ToolbarModel;
BOOL verticalLayout_;
@private
- TabContents* currentTab_; // weak, tab for which we're showing state
scoped_nsobject<TabStripView> tabStripView_;
NSView* switchView_; // weak
scoped_nsobject<NSView> dragBlockingView_; // avoid bad window server drags
- NSButton* newTabButton_; // weak, obtained from the nib.
+ 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
@@ -121,9 +148,12 @@ class ToolbarModel;
// "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;
+ browser:(Browser*)browser
+ delegate:(id<TabStripControllerDelegate>)delegate;
// Return the view for the currently selected tab.
- (NSView*)selectedTabView;
@@ -216,7 +246,6 @@ class ToolbarModel;
// functions.
- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window;
- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window;
-- (void)updateDevToolsForContents:(TabContents*)contents;
@end
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm
index 1a907bd..e7fe84f 100644
--- a/chrome/browser/cocoa/tab_strip_controller.mm
+++ b/chrome/browser/cocoa/tab_strip_controller.mm
@@ -22,6 +22,7 @@
#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"
@@ -30,6 +31,8 @@
#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"
@@ -133,6 +136,7 @@ private:
- (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
@@ -275,13 +279,15 @@ private:
- (id)initWithView:(TabStripView*)view
switchView:(NSView*)switchView
- browser:(Browser*)browser {
- DCHECK(view && switchView && browser);
+ 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]);
@@ -308,6 +314,7 @@ private:
[newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabImage)];
[newTabButton_
setAlternateImage:nsimage_cache::ImageNamed(kNewTabPressedImage)];
+ newTabButtonShowingHoverImage_ = NO;
newTabTrackingArea_.reset(
[[NSTrackingArea alloc] initWithRect:[newTabButton_ bounds]
options:(NSTrackingMouseEnteredAndExited |
@@ -435,9 +442,10 @@ private:
// 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];
- NSRect frame = [switchView_ bounds];
- [newView setFrame:frame];
- [controller ensureContentsVisible];
+
+ // 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
@@ -446,11 +454,23 @@ private:
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 resores 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).
TabContents* newTab = tabStripModel_->GetTabContentsAt(modelIndex);
@@ -616,10 +636,17 @@ private:
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
- NSView* penultimateTab = [self viewAtIndex:numberOfOpenTabs - 2];
- availableResizeWidth_ = NSMaxX([penultimateTab frame]);
+ 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
@@ -882,13 +909,9 @@ private:
NSWindow* window = [tabStripView_ window];
NSPoint currentMouse = [window mouseLocationOutsideOfEventStream];
currentMouse = [tabStripView_ convertPoint:currentMouse fromView:nil];
- NSString* imageName = nil;
- if (NSPointInRect(currentMouse, newTabNewFrame)) {
- imageName = kNewTabHoverImage;
- } else {
- imageName = kNewTabImage;
- }
- [newTabButton_ setImage:nsimage_cache::ImageNamed(imageName)];
+
+ 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
@@ -1040,7 +1063,6 @@ private:
// Swap in the contents for the new tab.
[self swapInTabAtIndex:modelIndex];
- [self updateDevToolsForContents:newContents];
if (newContents) {
newContents->DidBecomeSelected();
@@ -1146,13 +1168,12 @@ private:
[self removeTab:tab];
}
- // Does nothing, purely for consistency with the windows/linux code.
- [self updateDevToolsForContents:NULL];
-
// Send a broadcast that the number of tabs have changed.
[[NSNotificationCenter defaultCenter]
postNotificationName:kTabStripNumberOfTabsChanged
object:self];
+
+ [delegate_ onTabDetachedWithContents:contents];
}
// A helper routine for creating an NSImageView to hold the fav icon or app icon
@@ -1265,6 +1286,9 @@ private:
// 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.
@@ -1312,6 +1336,8 @@ private:
// 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.
@@ -1457,20 +1483,25 @@ private:
- (void)mouseMoved:(NSEvent*)event {
// Use hit test to figure out what view we are hovering over.
- TabView* targetView =
- (TabView*)[tabStripView_ hitTest:[event locationInWindow]];
- if (![targetView isKindOfClass:[TabView class]]) {
- if ([[targetView superview] isKindOfClass:[TabView class]]) {
- targetView = (TabView*)[targetView superview];
+ 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 {
- targetView = nil;
+ tabView = nil;
}
}
- if (hoveredTab_ != targetView) {
+ if (hoveredTab_ != tabView) {
[hoveredTab_ mouseExited:nil]; // We don't pass event because moved events
- [targetView mouseEntered:nil]; // don't have valid tracking areas
- hoveredTab_ = targetView;
+ [tabView mouseEntered:nil]; // don't have valid tracking areas
+ hoveredTab_ = tabView;
} else {
[hoveredTab_ mouseMoved:event];
}
@@ -1482,8 +1513,6 @@ private:
mouseInside_ = YES;
[self setTabTrackingAreasEnabled:YES];
[self mouseMoved:event];
- } else if ([area isEqual:newTabTrackingArea_]) {
- [newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabHoverImage)];
}
}
@@ -1500,7 +1529,11 @@ private:
hoveredTab_ = nil;
[self layoutTabs];
} else if ([area isEqual:newTabTrackingArea_]) {
- [newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabImage)];
+ // 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];
}
}
@@ -1525,6 +1558,18 @@ private:
}
}
+// 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
@@ -1653,7 +1698,7 @@ private:
browser_->AddTabWithURL(url, GURL(), PageTransition::TYPED, index,
TabStripModel::ADD_SELECTED |
TabStripModel::ADD_FORCE_INDEX,
- NULL, std::string());
+ NULL, std::string(), NULL);
break;
case CURRENT_TAB:
UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLOnTab"),
@@ -1761,13 +1806,12 @@ private:
// View hierarchy of the contents view:
// NSView -- switchView, same for all tabs
- // +- NSView -- TabContentsController's view
- // +- NSSplitView
- // +- TabContentsViewCocoa
+ // +- 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] superview];
+ NSView* tabContentsView = [window->owner()->GetNativeView() superview];
window->delegate()->RunSheet([self sheetController], tabContentsView);
// TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets
@@ -1785,8 +1829,7 @@ private:
}
- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window {
- NSView* tabContentsView =
- [[window->owner()->GetNativeView() superview] superview];
+ 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
@@ -1801,24 +1844,4 @@ private:
}
}
-- (void)updateDevToolsForContents:(TabContents*)contents {
- int modelIndex = tabStripModel_->GetIndexOfTabContents(contents);
-
- // This happens e.g. if one hits cmd-q with a docked devtools window open.
- if (modelIndex == TabStripModel::kNoTab)
- return;
-
- NSInteger index = [self indexFromModelIndex:modelIndex];
- DCHECK_GE(index, 0);
- DCHECK_LT(index, (NSInteger)[tabContentsArray_ count]);
- if (index < 0 || index >= (NSInteger)[tabContentsArray_ count])
- return;
-
- TabContentsController* tabController =
- [tabContentsArray_ objectAtIndex:index];
- TabContents* devtoolsContents = contents ?
- DevToolsWindow::GetDevToolsContents(contents) : NULL;
- [tabController showDevToolsContents:devtoolsContents];
-}
-
@end
diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm
index 2a161ab..b4f6c61 100644
--- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm
+++ b/chrome/browser/cocoa/tab_strip_controller_unittest.mm
@@ -7,6 +7,7 @@
#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"
@@ -14,6 +15,20 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+@interface TestTabStripControllerDelegate :
+ NSObject<TabStripControllerDelegate> {
+}
+@end
+
+@implementation TestTabStripControllerDelegate
+- (void)onSelectTabWithContents:(TabContents*)contents {
+}
+- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change {
+}
+- (void)onTabDetachedWithContents:(TabContents*)contents {
+}
+@end
+
namespace {
// Stub model delegate
@@ -27,7 +42,8 @@ class TestTabStripDelegate : public TabStripModelDelegate {
}
virtual Browser* CreateNewStripWithContents(TabContents* contents,
const gfx::Rect& window_bounds,
- const DockInfo& dock_info) {
+ const DockInfo& dock_info,
+ bool maximize) {
return NULL;
}
virtual void ContinueDraggingDetachedTab(TabContents* contents,
@@ -62,11 +78,15 @@ class TestTabStripDelegate : public TabStripModelDelegate {
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 {
@@ -93,17 +113,19 @@ class TabStripControllerTest : public CocoaTest {
[[TabStripView alloc] initWithFrame:strip_frame]);
[parent addSubview:tab_strip.get()];
NSRect button_frame = NSMakeRect(0, 0, 15, 15);
- scoped_nsobject<NSButton> new_tab_button(
- [[NSButton alloc] initWithFrame:button_frame]);
+ 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]);
+ browser:browser
+ delegate:controller_delegate_.get()]);
}
virtual void TearDown() {
@@ -118,6 +140,7 @@ class TabStripControllerTest : public CocoaTest {
BrowserTestHelper browser_helper_;
scoped_ptr<TestTabStripDelegate> delegate_;
TabStripModel* model_;
+ scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
scoped_nsobject<TabStripController> controller_;
};
@@ -129,7 +152,7 @@ TEST_F(TabStripControllerTest, AddRemoveTabs) {
SiteInstance::CreateSiteInstance(browser_helper_.profile());
TabContents* tab_contents =
new TabContents(browser_helper_.profile(), instance, MSG_ROUTING_NONE,
- NULL);
+ NULL, NULL);
model_->AppendTabContents(tab_contents, true);
EXPECT_EQ(model_->count(), 1);
}
diff --git a/chrome/browser/cocoa/tab_strip_model_observer_bridge.h b/chrome/browser/cocoa/tab_strip_model_observer_bridge.h
index 689cd3e..140ccc1 100644
--- a/chrome/browser/cocoa/tab_strip_model_observer_bridge.h
+++ b/chrome/browser/cocoa/tab_strip_model_observer_bridge.h
@@ -4,12 +4,14 @@
#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.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
class TabContents;
+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
@@ -41,6 +43,7 @@ class TabStripModelObserverBridge : public TabStripModelObserver {
int index);
virtual void TabMiniStateChanged(TabContents* contents, int index);
virtual void TabStripEmpty();
+ virtual void TabStripModelDeleted();
private:
id controller_; // weak, owns me
@@ -71,6 +74,7 @@ class TabStripModelObserverBridge : public TabStripModelObserver {
- (void)tabMiniStateChangedWithContents:(TabContents*)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
index e5280dc..a6a06f9 100644
--- a/chrome/browser/cocoa/tab_strip_model_observer_bridge.mm
+++ b/chrome/browser/cocoa/tab_strip_model_observer_bridge.mm
@@ -4,6 +4,8 @@
#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) {
@@ -99,3 +101,8 @@ 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
index 770e83d..55214da 100644
--- a/chrome/browser/cocoa/tab_strip_view.h
+++ b/chrome/browser/cocoa/tab_strip_view.h
@@ -4,12 +4,15 @@
#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.
@@ -21,7 +24,7 @@
scoped_nsobject<URLDropTargetHandler> dropHandler_;
// Weak; the following come from the nib.
- NSButton* newTabButton_;
+ NewTabButton* newTabButton_;
// Whether the drop-indicator arrow is shown, and if it is, the coordinate of
// its tip.
@@ -29,7 +32,7 @@
NSPoint dropArrowPosition_;
}
-@property(assign, nonatomic) IBOutlet NSButton* newTabButton;
+@property(assign, nonatomic) IBOutlet NewTabButton* newTabButton;
@property(assign, nonatomic) BOOL dropArrowShown;
@property(assign, nonatomic) NSPoint dropArrowPosition;
diff --git a/chrome/browser/cocoa/tab_strip_view.mm b/chrome/browser/cocoa/tab_strip_view.mm
index d1199b9..1e0daf8 100644
--- a/chrome/browser/cocoa/tab_strip_view.mm
+++ b/chrome/browser/cocoa/tab_strip_view.mm
@@ -4,11 +4,12 @@
#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 "base/logging.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
@implementation TabStripView
@@ -41,7 +42,18 @@
[[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMinYEdge);
- [[NSColor colorWithCalibratedWhite:0.96 alpha:1.0] set];
+
+ 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);
}
diff --git a/chrome/browser/cocoa/tab_view.h b/chrome/browser/cocoa/tab_view.h
index 6d4898e..74689c7 100644
--- a/chrome/browser/cocoa/tab_view.h
+++ b/chrome/browser/cocoa/tab_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_TAB_VIEW_H_
#define CHROME_BROWSER_COCOA_TAB_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#include <ApplicationServices/ApplicationServices.h>
diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm
index 450f263..e2d7d49 100644
--- a/chrome/browser/cocoa/tab_view.mm
+++ b/chrome/browser/cocoa/tab_view.mm
@@ -8,11 +8,11 @@
#import "base/mac_util.h"
#include "base/nsimage_cache_mac.h"
#include "base/scoped_cftyperef.h"
-#include "chrome/browser/browser_theme_provider.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 {
@@ -627,7 +627,8 @@ const CGFloat kRapidCloseDist = 2.5;
NSGraphicsContext* context = [NSGraphicsContext currentContext];
[context saveGraphicsState];
- ThemeProvider* themeProvider = [[self window] themeProvider];
+ BrowserThemeProvider* themeProvider =
+ static_cast<BrowserThemeProvider*>([[self window] themeProvider]);
[context setPatternPhase:[[self window] themePatternPhase]];
NSRect rect = [self bounds];
@@ -716,10 +717,14 @@ const CGFloat kRapidCloseDist = 2.5;
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 = [NSColor colorWithCalibratedWhite:0.96 alpha:1.0];
-
- // Draw the top inner highlight within the currently selected tab.
- if (selected) {
+ 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]);
diff --git a/chrome/browser/cocoa/tab_view_picker_table_unittest.mm b/chrome/browser/cocoa/tab_view_picker_table_unittest.mm
index 00440fe..3055844 100644
--- a/chrome/browser/cocoa/tab_view_picker_table_unittest.mm
+++ b/chrome/browser/cocoa/tab_view_picker_table_unittest.mm
@@ -10,6 +10,7 @@
#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> {
@@ -100,15 +101,15 @@ TEST_F(TabViewPickerTableTest, RowsCorrect) {
id item;
item = [[view_ dataSource] outlineView:view_ child:0 ofItem:nil];
- EXPECT_TRUE([@"label 1" isEqualToString:[[view_ dataSource]
- outlineView:view_
- objectValueForTableColumn:nil // ignored
- byItem:item]]);
+ EXPECT_NSEQ(@"label 1",
+ [[view_ dataSource] outlineView:view_
+ objectValueForTableColumn:nil // ignored
+ byItem:item]);
item = [[view_ dataSource] outlineView:view_ child:1 ofItem:nil];
- EXPECT_TRUE([@"label 2" isEqualToString:[[view_ dataSource]
- outlineView:view_
- objectValueForTableColumn:nil // ignored
- byItem:item]]);
+ EXPECT_NSEQ(@"label 2",
+ [[view_ dataSource] outlineView:view_
+ objectValueForTableColumn:nil // ignored
+ byItem:item]);
}
TEST_F(TabViewPickerTableTest, TestListUpdatesTabView) {
diff --git a/chrome/browser/cocoa/tab_window_controller.h b/chrome/browser/cocoa/tab_window_controller.h
index fbdb6da..ad0d5b7 100644
--- a/chrome/browser/cocoa/tab_window_controller.h
+++ b/chrome/browser/cocoa/tab_window_controller.h
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
+#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
@@ -31,6 +32,7 @@
#include "base/scoped_nsobject.h"
@class FastResizeView;
+@class FocusTracker;
@class TabStripView;
@class TabView;
@@ -45,6 +47,7 @@
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
@@ -171,4 +174,4 @@
- (void)layoutSubviews;
@end
-#endif // CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
+#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
index c1701f1..4e886eb 100644
--- a/chrome/browser/cocoa/tab_window_controller.mm
+++ b/chrome/browser/cocoa/tab_window_controller.mm
@@ -6,6 +6,7 @@
#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"
@@ -193,13 +194,21 @@
[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];
- [window makeFirstResponder:cachedContentView_];
+ [focusBeforeOverlay_ restoreFocusInWindow:window];
+ focusBeforeOverlay_.reset(nil);
[window display];
[window removeChildWindow:overlayWindow_];
[overlayWindow_ orderOut:nil];
diff --git a/chrome/browser/cocoa/table_row_nsimage_cache.h b/chrome/browser/cocoa/table_row_nsimage_cache.h
index 6409123..84dbb69 100644
--- a/chrome/browser/cocoa/table_row_nsimage_cache.h
+++ b/chrome/browser/cocoa/table_row_nsimage_cache.h
@@ -4,26 +4,31 @@
#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"
-#include "third_party/skia/include/core/SkBitmap.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;
- };
+ // 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);
diff --git a/chrome/browser/cocoa/table_row_nsimage_cache.mm b/chrome/browser/cocoa/table_row_nsimage_cache.mm
index 11d5bb5..ed10af7 100644
--- a/chrome/browser/cocoa/table_row_nsimage_cache.mm
+++ b/chrome/browser/cocoa/table_row_nsimage_cache.mm
@@ -6,6 +6,7 @@
#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),
diff --git a/chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm b/chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm
index 271534a..1cc8471 100644
--- a/chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm
+++ b/chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm
@@ -5,6 +5,7 @@
#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 {
diff --git a/chrome/browser/cocoa/task_manager_mac.h b/chrome/browser/cocoa/task_manager_mac.h
index b76f80a..0c6feac 100644
--- a/chrome/browser/cocoa/task_manager_mac.h
+++ b/chrome/browser/cocoa/task_manager_mac.h
@@ -4,18 +4,25 @@
#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.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 {
+@interface TaskManagerWindowController :
+ NSWindowController<NSTableViewDataSource,
+ NSTableViewDelegate> {
@private
IBOutlet NSTableView* tableView_;
IBOutlet NSButton* endProcessButton_;
@@ -24,6 +31,14 @@ class TaskManagerMac;
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.
@@ -42,11 +57,15 @@ class TaskManagerMac;
- (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();
+ TaskManagerMac(TaskManager* task_manager);
virtual ~TaskManagerMac();
// TaskManagerModelObserver
@@ -60,8 +79,8 @@ class TaskManagerMac : public TaskManagerModelObserver,
void WindowWasClosed();
// TableRowNSImageCache::Table
- virtual int RowCount() const { return model_->ResourceCount(); }
- virtual SkBitmap GetIcon(int r) const { return model_->GetResourceIcon(r); }
+ 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.
@@ -73,9 +92,11 @@ class TaskManagerMac : public TaskManagerModelObserver,
// 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
+ TaskManager* const task_manager_; // weak
// Our model.
TaskManagerModel* const model_; // weak
diff --git a/chrome/browser/cocoa/task_manager_mac.mm b/chrome/browser/cocoa/task_manager_mac.mm
index b0a70a6..b4cee66 100644
--- a/chrome/browser/cocoa/task_manager_mac.mm
+++ b/chrome/browser/cocoa/task_manager_mac.mm
@@ -14,18 +14,17 @@
#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"
-// TODO(thakis): Column sort comparator
-// TODO(thakis): Clicking column header doesn't sort
-// TODO(thakis): Default sort column
+namespace {
// Width of "a" and most other letters/digits in "small" table views.
-static const int kCharWidth = 6;
+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.
-static const struct ColumnWidth {
+const struct ColumnWidth {
int columnId;
int minWidth;
int maxWidth; // If this is -1, 1.5*minColumWidth is used as max width.
@@ -50,16 +49,52 @@ static const struct ColumnWidth {
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
////////////////////////////////////////////////////////////////////////////////
@@ -80,15 +115,49 @@ static const struct ColumnWidth {
size_saver_.reset([[WindowSizeAutosaver alloc]
initWithWindow:[self window]
prefService:g_browser_process->local_state()
- path:prefs::kTaskManagerWindowPlacement
- state:kSaveWindowRect]);
+ path:prefs::kTaskManagerWindowPlacement]);
}
- [[self window] makeKeyAndOrderFront:self];
+ [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];
}
@@ -102,7 +171,7 @@ static const struct ColumnWidth {
for (NSUInteger i = [selection lastIndex];
i != NSNotFound;
i = [selection indexLessThanIndex:i]) {
- taskManager_->KillProcess(i);
+ taskManager_->KillProcess(viewToModelMap_[i]);
}
}
@@ -110,7 +179,11 @@ static const struct ColumnWidth {
NSInteger row = [tableView_ clickedRow];
if (row < 0)
return; // Happens e.g. if the table header is double-clicked.
- taskManager_->ActivateProcess(row);
+ taskManager_->ActivateProcess(viewToModelMap_[row]);
+}
+
+- (NSTableView*)tableView {
+ return tableView_;
}
- (void)awakeFromNib {
@@ -119,6 +192,7 @@ static const struct ColumnWidth {
[self adjustSelectionAndEndProcessButton];
[tableView_ setDoubleAction:@selector(selectDoubleClickedTab:)];
+ [tableView_ sizeToFit];
}
// Adds a column which has the given string id as title. |isVisible| specifies
@@ -141,6 +215,14 @@ static const struct ColumnWidth {
[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;
@@ -181,6 +263,10 @@ static const struct ColumnWidth {
[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];
@@ -192,6 +278,9 @@ static const struct ColumnWidth {
[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];
}
@@ -242,24 +331,39 @@ static const struct ColumnWidth {
for (NSUInteger i = [selection lastIndex];
i != NSNotFound;
i = [selection indexLessThanIndex:i]) {
- if (taskManager_->IsBrowserProcess(i))
+ int modelIndex = viewToModelMap_[i];
+ if (taskManager_->IsBrowserProcess(modelIndex))
selectionContainsBrowserProcess = true;
- std::pair<int, int> rangePair = model_->GetGroupRangeForResource(i);
- NSRange range = NSMakeRange(rangePair.first, rangePair.second);
- NSIndexSet* rangeIndexSet = [NSIndexSet indexSetWithIndexesInRange:range];
- [tableView_ selectRowIndexes:rangeIndexSet byExtendingSelection:YES];
+ 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)
@@ -270,58 +374,72 @@ static const struct ColumnWidth {
}
- (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::SysWideToNSString(model_->GetResourceTitle(row));
+ return base::SysUTF16ToNSString(model_->GetResourceTitle(row));
case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(model_->GetResourcePrivateMemory(row));
+ return base::SysUTF16ToNSString(model_->GetResourcePrivateMemory(row));
case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(model_->GetResourceSharedMemory(row));
+ return base::SysUTF16ToNSString(model_->GetResourceSharedMemory(row));
case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: // Memory
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(model_->GetResourcePhysicalMemory(row));
+ return base::SysUTF16ToNSString(model_->GetResourcePhysicalMemory(row));
case IDS_TASK_MANAGER_CPU_COLUMN: // CPU
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(model_->GetResourceCPUUsage(row));
+ return base::SysUTF16ToNSString(model_->GetResourceCPUUsage(row));
case IDS_TASK_MANAGER_NET_COLUMN: // Net
- return base::SysWideToNSString(model_->GetResourceNetworkUsage(row));
+ return base::SysUTF16ToNSString(model_->GetResourceNetworkUsage(row));
case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: // Process ID
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(model_->GetResourceProcessId(row));
+ return base::SysUTF16ToNSString(model_->GetResourceProcessId(row));
case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: // WebCore image cache
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(
+ return base::SysUTF16ToNSString(
model_->GetResourceWebCoreImageCacheSize(row));
case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: // WebCore script cache
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(
+ return base::SysUTF16ToNSString(
model_->GetResourceWebCoreScriptsCacheSize(row));
case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: // WebCore CSS cache
if (!model_->IsResourceFirstInGroup(row))
return @"";
- return base::SysWideToNSString(
+ 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::SysWideToNSString(model_->GetResourceGoatsTeleported(row));
+ return base::SysUTF16ToNSString(model_->GetResourceGoatsTeleported(row));
default:
NOTREACHED();
@@ -354,7 +472,8 @@ static const struct ColumnWidth {
NSString* title = [self modelTextForRow:rowIndex
column:[[tableColumn identifier] intValue]];
[buttonCell setTitle:title];
- [buttonCell setImage:taskManagerObserver_->GetImageForRow(rowIndex)];
+ [buttonCell setImage:
+ taskManagerObserver_->GetImageForRow(viewToModelMap_[rowIndex])];
[buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
[buttonCell setHighlightsBy:NSNoCellMask];
}
@@ -362,14 +481,24 @@ static const struct ColumnWidth {
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()
- : task_manager_(TaskManager::GetInstance()),
- model_(TaskManager::GetInstance()->model()),
+TaskManagerMac::TaskManagerMac(TaskManager* task_manager)
+ : task_manager_(task_manager),
+ model_(task_manager->model()),
icon_cache_(this) {
window_controller_ =
[[TaskManagerWindowController alloc] initWithTaskManagerObserver:this];
@@ -380,7 +509,11 @@ TaskManagerMac::TaskManagerMac()
TaskManagerMac* TaskManagerMac::instance_ = NULL;
TaskManagerMac::~TaskManagerMac() {
- task_manager_->OnWindowClosed();
+ 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);
}
@@ -389,6 +522,7 @@ TaskManagerMac::~TaskManagerMac() {
void TaskManagerMac::OnModelChanged() {
icon_cache_.OnModelChanged();
+ [window_controller_ deselectRows];
[window_controller_ reloadData];
}
@@ -399,11 +533,13 @@ void TaskManagerMac::OnItemsChanged(int start, int length) {
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];
}
@@ -419,6 +555,14 @@ void TaskManagerMac::WindowWasClosed() {
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_) {
@@ -426,7 +570,7 @@ void TaskManagerMac::Show() {
[[instance_->window_controller_ window]
makeKeyAndOrderFront:instance_->window_controller_];
} else {
- instance_ = new TaskManagerMac;
+ 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
index 45a2ab2..a1e6b29 100644
--- a/chrome/browser/cocoa/task_manager_mac_unittest.mm
+++ b/chrome/browser/cocoa/task_manager_mac_unittest.mm
@@ -5,33 +5,110 @@
#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 TaskManagerWindowControllerTest : public CocoaTest {
+class TestResource : public TaskManager::Resource {
public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- controller_ = [[TaskManagerWindowController alloc] init];
- }
+ 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 bool SupportNetworkUsage() const { return false; }
+ virtual void SetSupportNetworkUsage() { NOTREACHED(); }
+ virtual void Refresh() {}
+ string16 title_;
+ pid_t pid_;
+};
- virtual void TearDown() {
- [controller_ close];
- CocoaTest::TearDown();
- }
+} // namespace
- TaskManagerWindowController *controller_;
+class TaskManagerWindowControllerTest : public CocoaTest {
};
-// Test creation, to ensure nothing leaks or crashes
+// 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];
}
-// TODO(thakis): Add tests for more methods as they become implemented
-// (TaskManager::Show() etc).
+TEST_F(TaskManagerWindowControllerTest, Sort) {
+ TaskManager task_manager;
-} // namespace
+ 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
index f81fc6c..aeda255 100644
--- a/chrome/browser/cocoa/test_event_utils.h
+++ b/chrome/browser/cocoa/test_event_utils.h
@@ -1,15 +1,16 @@
-// 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.
#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/logging.h"
+#include "base/basictypes.h"
// Within a given scope, replace the selector |selector| on |target| with that
// from |source|.
@@ -39,8 +40,8 @@ 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);
+std::pair<NSEvent*, NSEvent*> MouseClickInView(NSView* view,
+ NSUInteger clickCount);
} // namespace test_event_utils
diff --git a/chrome/browser/cocoa/theme_install_bubble_view.h b/chrome/browser/cocoa/theme_install_bubble_view.h
index ea308ba..f8208df 100644
--- a/chrome/browser/cocoa/theme_install_bubble_view.h
+++ b/chrome/browser/cocoa/theme_install_bubble_view.h
@@ -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 "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/cocoa/themed_window.h b/chrome/browser/cocoa/themed_window.h
index c1b4a31..1e6d5fb 100644
--- a/chrome/browser/cocoa/themed_window.h
+++ b/chrome/browser/cocoa/themed_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_THEMED_WINDOW_H_
#define CHROME_BROWSER_COCOA_THEMED_WINDOW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/throbber_view.h b/chrome/browser/cocoa/throbber_view.h
index b15a8f5..c9b7802 100644
--- a/chrome/browser/cocoa/throbber_view.h
+++ b/chrome/browser/cocoa/throbber_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_THROBBER_VIEW_H_
#define CHROME_BROWSER_COCOA_THROBBER_VIEW_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -25,7 +26,6 @@
@interface ThrobberView : NSView {
@private
id<ThrobberDataDelegate> dataDelegate_;
- NSTimer* timer_; // Animation timer. Weak, owned by runloop.
}
// Creates a filmstrip view with |frame| and image |image|.
diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h
index 458401a..9e0c2bc 100644
--- a/chrome/browser/cocoa/toolbar_controller.h
+++ b/chrome/browser/cocoa/toolbar_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_TOOLBAR_CONTROLLER_H_
#define CHROME_BROWSER_COCOA_TOOLBAR_CONTROLLER_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -13,7 +14,7 @@
#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/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
@class AutocompleteTextField;
@class AutocompleteTextFieldEditor;
@@ -27,8 +28,8 @@ class LocationBar;
class LocationBarViewMac;
@class MenuButton;
namespace ToolbarControllerInternal {
-class MenuDelegate;
class NotificationBridge;
+class WrenchAcceleratorDelegate;
} // namespace ToolbarControllerInternal
class Profile;
@class ReloadButton;
@@ -73,7 +74,8 @@ class WrenchMenuModel;
// 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::MenuDelegate> menuDelegate_;
+ scoped_ptr<ToolbarControllerInternal::WrenchAcceleratorDelegate>
+ acceleratorDelegate_;
scoped_ptr<WrenchMenuModel> wrenchMenuModel_;
// Used for monitoring the optional toolbar button prefs.
diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm
index a2abf32..1d37b09 100644
--- a/chrome/browser/cocoa/toolbar_controller.mm
+++ b/chrome/browser/cocoa/toolbar_controller.mm
@@ -6,10 +6,10 @@
#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/keyboard_codes.h"
#include "base/mac_util.h"
#include "base/nsimage_cache_mac.h"
#include "base/singleton.h"
@@ -17,7 +17,6 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#import "chrome/browser/cocoa/accelerators_cocoa.h"
#import "chrome/browser/cocoa/back_forward_menu_controller.h"
@@ -36,10 +35,11 @@
#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/pref_service.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"
@@ -80,7 +80,7 @@ const CGFloat kWrenchMenuLeftPadding = 3.0;
@interface ToolbarController(Private)
- (void)addAccessibilityDescriptions;
- (void)initCommandStatus:(CommandUpdater*)commands;
-- (void)prefChanged:(std::wstring*)prefName;
+- (void)prefChanged:(std::string*)prefName;
- (BackgroundGradientView*)backgroundGradientView;
- (void)toolbarFrameChanged;
- (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate;
@@ -95,24 +95,9 @@ const CGFloat kWrenchMenuLeftPadding = 3.0;
namespace ToolbarControllerInternal {
-// A C++ delegate that handles enabling/disabling menu items and handling when
-// a menu command is chosen.
-class MenuDelegate : public menus::SimpleMenuModel::Delegate {
+// A C++ delegate that handles the accelerators in the wrench menu.
+class WrenchAcceleratorDelegate : public menus::AcceleratorProvider {
public:
- explicit MenuDelegate(Browser* browser)
- : browser_(browser) { }
-
- // Overridden from menus::SimpleMenuModel::Delegate
- virtual bool IsCommandIdChecked(int command_id) const {
- if (command_id == IDC_SHOW_BOOKMARK_BAR) {
- return browser_->profile()->GetPrefs()->GetBoolean(
- prefs::kShowBookmarkBar);
- }
- return false;
- }
- virtual bool IsCommandIdEnabled(int command_id) const {
- return browser_->command_updater()->IsCommandEnabled(command_id);
- }
virtual bool GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator_generic) {
// Downcast so that when the copy constructor is invoked below, the key
@@ -128,26 +113,6 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate {
}
return false;
}
- virtual void ExecuteCommand(int command_id) {
- browser_->ExecuteCommand(command_id);
- }
- virtual bool IsLabelForCommandIdDynamic(int command_id) const {
- // On Mac, switch between "Enter Full Screen" and "Exit Full Screen".
- return (command_id == IDC_FULLSCREEN);
- }
- virtual string16 GetLabelForCommandId(int command_id) const {
- if (command_id == 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);
- }
- return menus::SimpleMenuModel::Delegate::GetLabelForCommandId(command_id);
- }
-
- private:
- Browser* browser_;
};
// A class registered for C++ notifications. This is used to detect changes in
@@ -166,7 +131,7 @@ class NotificationBridge : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED)
- [controller_ prefChanged:Details<std::wstring>(details).ptr()];
+ [controller_ prefChanged:Details<std::string>(details).ptr()];
else if (type == NotificationType::UPGRADE_RECOMMENDED)
[controller_ badgeWrenchMenu];
}
@@ -337,6 +302,8 @@ class NotificationBridge : public NotificationObserver {
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 {
@@ -420,9 +387,6 @@ class NotificationBridge : public NotificationObserver {
case IDC_FORWARD:
button = forwardButton_;
break;
- case IDC_RELOAD:
- button = reloadButton_;
- break;
case IDC_HOME:
button = homeButton_;
break;
@@ -436,7 +400,7 @@ class NotificationBridge : public NotificationObserver {
[backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO];
[forwardButton_
setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO];
- [reloadButton_ setEnabled:commands->IsCommandEnabled(IDC_RELOAD) ? YES : NO];
+ [reloadButton_ setEnabled:YES];
[homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO];
}
@@ -538,7 +502,6 @@ class NotificationBridge : public NotificationObserver {
if (hide)
moveX *= -1; // Reverse the direction of the move.
- [reloadButton_ setFrame:NSOffsetRect([reloadButton_ frame], moveX, 0)];
[locationBar_ setFrame:[self adjustRect:[locationBar_ frame]
byAmount:moveX]];
[homeButton_ setHidden:hide];
@@ -549,9 +512,11 @@ class NotificationBridge : public NotificationObserver {
- (void)installWrenchMenu {
if (wrenchMenuModel_.get())
return;
- menuDelegate_.reset(new ToolbarControllerInternal::MenuDelegate(browser_));
+ acceleratorDelegate_.reset(
+ new ToolbarControllerInternal::WrenchAcceleratorDelegate());
- wrenchMenuModel_.reset(new WrenchMenuModel(menuDelegate_.get(), browser_));
+ wrenchMenuModel_.reset(new WrenchMenuModel(
+ acceleratorDelegate_.get(), browser_));
[wrenchMenuController_ setModel:wrenchMenuModel_.get()];
[wrenchMenuController_ setUseWithPopUpButtonCell:YES];
[wrenchButton_ setAttachedMenu:[wrenchMenuController_ menu]];
@@ -562,17 +527,10 @@ class NotificationBridge : public NotificationObserver {
}
- (void)badgeWrenchMenu {
- // The wrench menu gets an upgrade dot. This gets ugly because we only have a
- // PNG so we need to position it. TODO(avi): Get a PDF version, one ready for
- // overlaying. http://crbug.com/49668
- //
// 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.)
- ThemeProvider* theme_provider = profile_->GetThemeProvider();
- NSImage* badge = theme_provider->GetNSImageNamed(IDR_UPGRADE_DOT_INACTIVE,
- true);
-
+ NSImage* badge = nsimage_cache::ImageNamed(@"upgrade_dot.pdf");
NSImage* wrenchImage = nsimage_cache::ImageNamed(kWrenchButtonImageName);
NSSize wrenchImageSize = [wrenchImage size];
@@ -589,7 +547,7 @@ class NotificationBridge : public NotificationObserver {
[[wrenchButton_ cell] setOverlayImage:overlayImage];
}
-- (void)prefChanged:(std::wstring*)prefName {
+- (void)prefChanged:(std::string*)prefName {
if (!prefName) return;
if (*prefName == prefs::kShowHomeButton) {
[self showOptionalHomeButton];
diff --git a/chrome/browser/cocoa/toolbar_controller_unittest.mm b/chrome/browser/cocoa/toolbar_controller_unittest.mm
index c5f155d..03914c6 100644
--- a/chrome/browser/cocoa/toolbar_controller_unittest.mm
+++ b/chrome/browser/cocoa/toolbar_controller_unittest.mm
@@ -11,7 +11,7 @@
#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/pref_service.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"
@@ -161,23 +161,20 @@ TEST_F(ToolbarControllerTest, LoadingState) {
}
// Check that toggling the state of the home button changes the visible
-// state of the home button and moves the other buttons accordingly.
+// 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* reloadButton = [[bar_ toolbarViews] objectAtIndex:kReloadIndex];
NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex];
- NSRect originalReloadFrame = [reloadButton frame];
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(originalReloadFrame), NSMinX([reloadButton frame]));
EXPECT_NE(NSMinX(originalLocationBarFrame), NSMinX([locationBar frame]));
EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame]));
}
diff --git a/chrome/browser/cocoa/toolbar_view.h b/chrome/browser/cocoa/toolbar_view.h
index 678fe75..b620606 100644
--- a/chrome/browser/cocoa/toolbar_view.h
+++ b/chrome/browser/cocoa/toolbar_view.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm b/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm
index 44beb4b..baa0eef 100644
--- a/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm
+++ b/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm
@@ -36,7 +36,7 @@ NSButton* CreateNSButtonWithResourceIDAndParameter(
- (void)initializeExtraControls {
TranslateInfoBarDelegate* delegate = [self delegate];
const string16& language = delegate->GetLanguageDisplayableNameAt(
- delegate->original_language_index());
+ delegate->original_language_index());
neverTranslateButton_.reset(
CreateNSButtonWithResourceIDAndParameter(
IDS_TRANSLATE_INFOBAR_NEVER_TRANSLATE, language));
diff --git a/chrome/browser/cocoa/translate/translate_infobar_base.h b/chrome/browser/cocoa/translate/translate_infobar_base.h
index 116abd5..b23250f 100644
--- a/chrome/browser/cocoa/translate/translate_infobar_base.h
+++ b/chrome/browser/cocoa/translate/translate_infobar_base.h
@@ -4,6 +4,7 @@
#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"
@@ -58,7 +59,10 @@ void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
scoped_nsobject<NSPopUpButton> toLanguagePopUp_;
scoped_nsobject<NSPopUpButton> optionsPopUp_;
scoped_nsobject<NSButton> showOriginalButton_;
- scoped_nsobject<NSButton> tryAgainButton_;
+ // 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.
@@ -128,6 +132,9 @@ void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
// 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
@@ -146,8 +153,9 @@ void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
// Returns the underlying options menu.
- (NSMenu*)optionsMenu;
-// Returns the "try again" button.
-- (NSButton*)tryAgainButton;
+// Returns |translateMessageButton_|, see declaration of member
+// variable for a full description.
+- (NSButton*)translateMessageButton;
@end // TranslateInfoBarControllerBase (TestingAPI)
diff --git a/chrome/browser/cocoa/translate/translate_infobar_base.mm b/chrome/browser/cocoa/translate/translate_infobar_base.mm
index e267074..b396de8 100644
--- a/chrome/browser/cocoa/translate/translate_infobar_base.mm
+++ b/chrome/browser/cocoa/translate/translate_infobar_base.mm
@@ -83,17 +83,21 @@ 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) {
- NSMenuItem* item = [[[NSMenuItem alloc]
+ 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];
+ [item setTag:tag];
+ [menu addItem:item];
+ [item setTarget:target];
+ if (checked)
+ [item setState:NSOnState];
+ if (!enabled)
+ [item setEnabled:NO];
+ }
}
} // namespace TranslateInfoBarUtilities
@@ -178,7 +182,6 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
targetLanguageMenuModel_.reset(
new LanguagesMenuModel([self delegate],
LanguagesMenuModel::TARGET));
- optionsMenuModel_.reset(new OptionsMenuModel([self delegate]));
}
return self;
}
@@ -202,8 +205,8 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
pullsDown:NO]);
toLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame
pullsDown:NO]);
- showOriginalButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]);
- tryAgainButton_.reset([[NSButton alloc] initWithFrame:bogusFrame]);
+ showOriginalButton_.reset([[NSButton alloc] init]);
+ translateMessageButton_.reset([[NSButton alloc] init]);
}
- (void)sourceLanguageModified:(NSInteger)newLanguageIdx {
@@ -234,6 +237,7 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
[self loadLabelText];
[self clearAllControls];
[self showVisibleControls:[self visibleControls]];
+ [optionsPopUp_ setHidden:![self shouldShowOptionsPopUp]];
[self layout];
[self adjustOptionsButtonSizeAndVisibilityForView:
[[self visibleControls] lastObject]];
@@ -304,6 +308,9 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
}
- (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(
@@ -334,6 +341,10 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
}
}
+- (BOOL)shouldShowOptionsPopUp {
+ return YES;
+}
+
- (void)populateLanguageMenus {
NSMenu* originalLanguageMenu = [fromLanguagePopUp_ menu];
[originalLanguageMenu setAutoenablesItems:NO];
@@ -415,7 +426,6 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
// Set up "Show original" and "Try again" buttons.
[showOriginalButton_ setFrame:okButtonFrame];
- [tryAgainButton_ setFrame:okButtonFrame];
// Set each of the buttons and popups to the NSTexturedRoundedBezelStyle
// (metal-looking) style.
@@ -436,13 +446,11 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
[showOriginalButton_ setTarget:self];
[showOriginalButton_ setAction:@selector(showOriginal:)];
- [tryAgainButton_ setTarget:self];
- [tryAgainButton_ setAction:@selector(ok:)];
+ [translateMessageButton_ setTarget:self];
+ [translateMessageButton_ setAction:@selector(messageButtonPressed:)];
[showOriginalButton_
setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_REVERT)];
- [tryAgainButton_
- setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_RETRY)];
// Add and configure controls that are visible in all modes.
[optionsPopUp_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin |
@@ -505,6 +513,10 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
[super dismiss:nil];
}
+- (void)messageButtonPressed:(id)sender {
+ [self delegate]->MessageInfoBarButtonPressed();
+}
+
- (IBAction)showOriginal:(id)sender {
[self delegate]->RevertTranslation();
}
@@ -559,7 +571,7 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
- (NSArray*)allControls {
return [NSArray arrayWithObjects:label1_.get(),fromLanguagePopUp_.get(),
label2_.get(), toLanguagePopUp_.get(), label3_.get(), okButton_,
- cancelButton_, showOriginalButton_.get(), tryAgainButton_.get(),
+ cancelButton_, showOriginalButton_.get(), translateMessageButton_.get(),
nil];
}
@@ -567,8 +579,8 @@ InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
return [optionsPopUp_ menu];
}
-- (NSButton*)tryAgainButton {
- return tryAgainButton_.get();
+- (NSButton*)translateMessageButton {
+ return translateMessageButton_.get();
}
- (bool)verifyLayout {
diff --git a/chrome/browser/cocoa/translate/translate_infobar_unittest.mm b/chrome/browser/cocoa/translate/translate_infobar_unittest.mm
index 668d8bf..a389eba 100644
--- a/chrome/browser/cocoa/translate/translate_infobar_unittest.mm
+++ b/chrome/browser/cocoa/translate/translate_infobar_unittest.mm
@@ -6,6 +6,7 @@
#import "base/scoped_nsobject.h"
#import "base/string_util.h"
+#include "base/utf_string_conversions.h"
#import "chrome/app/chrome_dll_resource.h" // For translate menu command ids.
#import "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
@@ -66,15 +67,22 @@ class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate {
class TranslationInfoBarTest : public CocoaTest {
public:
+ BrowserTestHelper browser_helper_;
+ scoped_ptr<TabContents> tab_contents;
scoped_ptr<MockTranslateInfoBarDelegate> infobar_delegate;
scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller;
- BrowserTestHelper browser_helper_;
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();
}
@@ -83,13 +91,6 @@ class TranslationInfoBarTest : public CocoaTest {
}
void CreateInfoBar(TranslateInfoBarDelegate::Type type) {
- SiteInstance* instance =
- SiteInstance::CreateSiteInstance(browser_helper_.profile());
- scoped_ptr<TabContents> tab_contents(
- new TabContents(browser_helper_.profile(),
- instance,
- MSG_ROUTING_NONE,
- NULL));
TranslateErrors::Type error = TranslateErrors::NONE;
if (type == TranslateInfoBarDelegate::TRANSLATION_ERROR)
error = TranslateErrors::NETWORK;
@@ -155,7 +156,8 @@ TEST_F(TranslationInfoBarTest, OptionsMenuItemsHookedUp) {
// that the target on that is setup correctly.
for (NSUInteger i = 1; i < [optionsMenuItems count]; ++i) {
NSMenuItem* item = [optionsMenuItems objectAtIndex:i];
- EXPECT_EQ([item target], infobar_controller.get());
+ if (![item isSeparatorItem])
+ EXPECT_EQ([item target], infobar_controller.get());
}
NSMenuItem* alwaysTranslateLanguateItem = [optionsMenuItems objectAtIndex:1];
NSMenuItem* neverTranslateLanguateItem = [optionsMenuItems objectAtIndex:2];
diff --git a/chrome/browser/cocoa/translate/translate_message_infobar_controller.h b/chrome/browser/cocoa/translate/translate_message_infobar_controller.h
index ddb7110..985bf2a 100644
--- a/chrome/browser/cocoa/translate/translate_message_infobar_controller.h
+++ b/chrome/browser/cocoa/translate/translate_message_infobar_controller.h
@@ -5,9 +5,6 @@
#import "chrome/browser/cocoa/translate/translate_infobar_base.h"
@interface TranslateMessageInfobarController : TranslateInfoBarControllerBase {
- // This keeps track of whether the infobar is displaying a message or an
- // error. If it is an error it should have a try again button.
- TranslateInfoBarDelegate::Type state_;
}
@end
diff --git a/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm b/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm
index 5b4fcaf..1146fdc 100644
--- a/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm
+++ b/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm
@@ -10,24 +10,15 @@ using TranslateInfoBarUtilities::MoveControl;
@implementation TranslateMessageInfobarController
-- (id)initWithDelegate:(InfoBarDelegate*)delegate {
- if ((self = [super initWithDelegate:delegate])) {
- TranslateInfoBarDelegate* delegate = [self delegate];
- if (delegate->IsError())
- state_ = TranslateInfoBarDelegate::TRANSLATION_ERROR;
- else
- state_ = TranslateInfoBarDelegate::TRANSLATING;
- }
- return self;
-}
-
- (void)layout {
- [optionsPopUp_ setHidden:YES];
[self removeOkCancelButtons];
- MoveControl(label1_, tryAgainButton_, spaceBetweenControls_ * 2, true);
+ MoveControl(label1_, translateMessageButton_, spaceBetweenControls_ * 2, true);
TranslateInfoBarDelegate* delegate = [self delegate];
- if (delegate->IsError())
- MoveControl(label1_, tryAgainButton_, spaceBetweenControls_ * 2, true);
+ if ([self delegate]->ShouldShowMessageInfoBarButton()) {
+ string16 buttonText = delegate->GetMessageInfoBarButtonText();
+ [translateMessageButton_ setTitle:base::SysUTF16ToNSString(buttonText)];
+ [translateMessageButton_ sizeToFit];
+ }
}
- (void)adjustOptionsButtonSizeAndVisibilityForView:(NSView*)lastView {
@@ -37,8 +28,8 @@ using TranslateInfoBarUtilities::MoveControl;
- (NSArray*)visibleControls {
NSMutableArray* visibleControls =
[NSMutableArray arrayWithObjects:label1_.get(), nil];
- if (state_ == TranslateInfoBarDelegate::TRANSLATION_ERROR)
- [visibleControls addObject:tryAgainButton_];
+ if ([self delegate]->ShouldShowMessageInfoBarButton())
+ [visibleControls addObject:translateMessageButton_];
return visibleControls;
}
@@ -55,4 +46,8 @@ using TranslateInfoBarUtilities::MoveControl;
return [super verifyLayout];
}
+- (BOOL)shouldShowOptionsPopUp {
+ return NO;
+}
+
@end
diff --git a/chrome/browser/cocoa/ui_localizer.h b/chrome/browser/cocoa/ui_localizer.h
index fc7b57b..1ac9f0a 100644
--- a/chrome/browser/cocoa/ui_localizer.h
+++ b/chrome/browser/cocoa/ui_localizer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_UI_LOCALIZER_H_
#define CHROME_BROWSER_COCOA_UI_LOCALIZER_H_
+#pragma once
#import "third_party/GTM/AppKit/GTMUILocalizer.h"
diff --git a/chrome/browser/cocoa/ui_localizer.mm b/chrome/browser/cocoa/ui_localizer.mm
index 77e9154..d085353 100644
--- a/chrome/browser/cocoa/ui_localizer.mm
+++ b/chrome/browser/cocoa/ui_localizer.mm
@@ -7,6 +7,7 @@
#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"
diff --git a/chrome/browser/cocoa/url_drop_target.h b/chrome/browser/cocoa/url_drop_target.h
index 6b94113..f362b8a 100644
--- a/chrome/browser/cocoa/url_drop_target.h
+++ b/chrome/browser/cocoa/url_drop_target.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_URL_DROP_TARGET_H_
#define CHROME_BROWSER_COCOA_URL_DROP_TARGET_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -17,6 +18,9 @@
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;
diff --git a/chrome/browser/cocoa/url_drop_target.mm b/chrome/browser/cocoa/url_drop_target.mm
index f0cf1fd..5c648b8 100644
--- a/chrome/browser/cocoa/url_drop_target.mm
+++ b/chrome/browser/cocoa/url_drop_target.mm
@@ -1,10 +1,10 @@
-// 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.
#import "chrome/browser/cocoa/url_drop_target.h"
-#include "base/logging.h"
+#include "base/basictypes.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
@interface URLDropTargetHandler(Private)
@@ -19,15 +19,18 @@
@implementation URLDropTargetHandler
-- (id)initWithView:(NSView<URLDropTarget>*)view {
- if ((self = [super init])) {
- view_ = view;
- [view_ registerForDraggedTypes:
- [NSArray arrayWithObjects:kWebURLsWithTitlesPboardType,
++ (NSArray*)handledDragTypes {
+ return [NSArray arrayWithObjects:kWebURLsWithTitlesPboardType,
NSURLPboardType,
NSStringPboardType,
NSFilenamesPboardType,
- nil]];
+ nil];
+}
+
+- (id)initWithView:(NSView<URLDropTarget>*)view {
+ if ((self = [super init])) {
+ view_ = view;
+ [view_ registerForDraggedTypes:[URLDropTargetHandler handledDragTypes]];
}
return self;
}
@@ -81,6 +84,9 @@
@implementation URLDropTargetHandler(Private)
- (NSDragOperation)getDragOperation:(id<NSDraggingInfo>)sender {
+ if (![[sender draggingPasteboard] containsURLData])
+ return NSDragOperationNone;
+
// Only allow the copy operation.
return [sender draggingSourceOperationMask] & NSDragOperationCopy;
}
diff --git a/chrome/browser/cocoa/vertical_gradient_view.h b/chrome/browser/cocoa/vertical_gradient_view.h
index d6364c2..299209f 100644
--- a/chrome/browser/cocoa/vertical_gradient_view.h
+++ b/chrome/browser/cocoa/vertical_gradient_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_VERTICAL_GRADIENT_VIEW_H_
#define CHROME_BROWSER_COCOA_VERTICAL_GRADIENT_VIEW_H_
+#pragma once
#include "base/scoped_nsobject.h"
diff --git a/chrome/browser/cocoa/view_id_util.h b/chrome/browser/cocoa/view_id_util.h
index f8d6ee8..e2b0291 100644
--- a/chrome/browser/cocoa/view_id_util.h
+++ b/chrome/browser/cocoa/view_id_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_VIEW_ID_UTIL_H_
#define CHROME_BROWSER_COCOA_VIEW_ID_UTIL_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/view_id_util_browsertest.mm b/chrome/browser/cocoa/view_id_util_browsertest.mm
index 2f887f9..e18ae03 100644
--- a/chrome/browser/cocoa/view_id_util_browsertest.mm
+++ b/chrome/browser/cocoa/view_id_util_browsertest.mm
@@ -2,14 +2,18 @@
// 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/basictypes.h"
+#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/cocoa/view_id_util.h"
#include "chrome/browser/download/download_shelf.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/sidebar/sidebar_manager.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"
@@ -18,7 +22,10 @@
// Basic sanity check of ViewID use on the mac.
class ViewIDTest : public InProcessBrowserTest {
public:
- ViewIDTest() : root_window_(nil) {}
+ ViewIDTest() : root_window_(nil) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ }
void CheckViewID(ViewID view_id, bool should_have) {
if (!root_window_)
@@ -34,6 +41,13 @@ class ViewIDTest : public InProcessBrowserTest {
// 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);
@@ -53,14 +67,11 @@ class ViewIDTest : public InProcessBrowserTest {
}
for (int i = VIEW_ID_TOOLBAR; i < VIEW_ID_PREDEFINED_COUNT; ++i) {
- // Extension shelf is being removed, http://crbug.com/30178.
- if (i == VIEW_ID_DEV_EXTENSION_SHELF)
- continue;
-
// 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_CONTENTS_SPLIT ||
+ i == VIEW_ID_SIDE_BAR_SPLIT) {
continue;
}
diff --git a/chrome/browser/cocoa/view_resizer.h b/chrome/browser/cocoa/view_resizer.h
index 18bb0d1..645e9dd 100644
--- a/chrome/browser/cocoa/view_resizer.h
+++ b/chrome/browser/cocoa/view_resizer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_VIEW_RESIZER_H_
#define CHROME_BROWSER_COCOA_VIEW_RESIZER_H_
+#pragma once
#include "chrome/browser/tabs/tab_strip_model.h"
diff --git a/chrome/browser/cocoa/view_resizer_pong.h b/chrome/browser/cocoa/view_resizer_pong.h
index 5b66151..de7193b 100644
--- a/chrome/browser/cocoa/view_resizer_pong.h
+++ b/chrome/browser/cocoa/view_resizer_pong.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_
#define CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/cocoa/web_contents_drag_source.h b/chrome/browser/cocoa/web_contents_drag_source.h
index 8d451ea..168ce31 100644
--- a/chrome/browser/cocoa/web_contents_drag_source.h
+++ b/chrome/browser/cocoa/web_contents_drag_source.h
@@ -4,13 +4,11 @@
#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 "app/download_file_interface.h"
-#include "base/file_path.h"
#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
@class TabContentsViewCocoa;
@@ -61,5 +59,4 @@
@end
-#endif // define CHROME_BROWSER_COCOA_WEB_CONTENTS_DRAG_SOURCE_H_
-
+#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
index 8bc883c..8d74a88 100644
--- a/chrome/browser/cocoa/web_contents_drag_source.mm
+++ b/chrome/browser/cocoa/web_contents_drag_source.mm
@@ -4,7 +4,6 @@
#import "chrome/browser/cocoa/web_contents_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"
diff --git a/chrome/browser/cocoa/web_drag_source.h b/chrome/browser/cocoa/web_drag_source.h
index a853c6b..9cfcba5 100644
--- a/chrome/browser/cocoa/web_drag_source.h
+++ b/chrome/browser/cocoa/web_drag_source.h
@@ -4,7 +4,6 @@
#import <Cocoa/Cocoa.h>
-#include "app/download_file_interface.h"
#include "base/file_path.h"
#include "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/cocoa/web_drag_source.mm b/chrome/browser/cocoa/web_drag_source.mm
index 98e22af..a2402da 100644
--- a/chrome/browser/cocoa/web_drag_source.mm
+++ b/chrome/browser/cocoa/web_drag_source.mm
@@ -13,6 +13,7 @@
#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"
@@ -367,11 +368,11 @@ void PromiseWriterTask::Run() {
&downloadURL_)) {
std::string contentDisposition =
"attachment; filename=" + fileName.value();
- DownloadManager::GenerateFileName(downloadURL_,
- contentDisposition,
- std::string(),
- UTF16ToUTF8(mimeType),
- &downloadFileName_);
+ download_util::GenerateFileName(downloadURL_,
+ contentDisposition,
+ std::string(),
+ UTF16ToUTF8(mimeType),
+ &downloadFileName_);
fileExtension = SysUTF8ToNSString(downloadFileName_.Extension());
}
}
diff --git a/chrome/browser/cocoa/web_drop_target_unittest.mm b/chrome/browser/cocoa/web_drop_target_unittest.mm
index 99405bb..6849646 100644
--- a/chrome/browser/cocoa/web_drop_target_unittest.mm
+++ b/chrome/browser/cocoa/web_drop_target_unittest.mm
@@ -8,6 +8,7 @@
#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"
diff --git a/chrome/browser/cocoa/window_size_autosaver.h b/chrome/browser/cocoa/window_size_autosaver.h
index c8ace00..6556e58 100644
--- a/chrome/browser/cocoa/window_size_autosaver.h
+++ b/chrome/browser/cocoa/window_size_autosaver.h
@@ -4,19 +4,11 @@
#ifndef CHROME_BROWSER_COCOA_WINDOW_SIZE_AUTOSAVER_H_
#define CHROME_BROWSER_COCOA_WINDOW_SIZE_AUTOSAVER_H_
+#pragma once
class PrefService;
@class NSWindow;
-enum WindowSizeAutosaverState {
-
- // Autosave only the window's bottom-right corner.
- kSaveWindowPos,
-
- // Autosave the whole window rect, i.e. both position and size.
- kSaveWindowRect,
-};
-
// 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
@@ -31,14 +23,12 @@ enum WindowSizeAutosaverState {
@interface WindowSizeAutosaver : NSObject {
NSWindow* window_; // weak
PrefService* prefService_; // weak
- const wchar_t* path_;
- WindowSizeAutosaverState state_;
+ const char* path_;
}
- (id)initWithWindow:(NSWindow*)window
prefService:(PrefService*)prefs
- path:(const wchar_t*)path
- state:(WindowSizeAutosaverState)state;
+ 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
index a200090..c93525e 100644
--- a/chrome/browser/cocoa/window_size_autosaver.mm
+++ b/chrome/browser/cocoa/window_size_autosaver.mm
@@ -6,7 +6,7 @@
#import "chrome/browser/cocoa/window_size_autosaver.h"
-#include "chrome/browser/pref_service.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
@@ -25,13 +25,11 @@ const int kMinWindowHeight = 17;
- (id)initWithWindow:(NSWindow*)window
prefService:(PrefService*)prefs
- path:(const wchar_t*)path
- state:(WindowSizeAutosaverState)state {
+ path:(const char*)path {
if ((self = [super init])) {
window_ = window;
prefService_ = prefs;
path_ = path;
- state_ = state;
[self restore];
[[NSNotificationCenter defaultCenter]
@@ -56,57 +54,53 @@ const int kMinWindowHeight = 17;
- (void)save:(NSNotification*)notification {
DictionaryValue* windowPrefs = prefService_->GetMutableDictionary(path_);
NSRect frame = [window_ frame];
- if (state_ == kSaveWindowRect) {
+ if ([window_ styleMask] & NSResizableWindowMask) {
// Save the origin of the window.
- windowPrefs->SetInteger(L"left", NSMinX(frame));
- windowPrefs->SetInteger(L"right", NSMaxX(frame));
+ 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(L"top", NSMinY(frame));
- windowPrefs->SetInteger(L"bottom", NSMaxY(frame));
- } else if (state_ == kSaveWindowPos) {
- // Save the origin of the window.
- windowPrefs->SetInteger(L"x", frame.origin.x);
- windowPrefs->SetInteger(L"y", frame.origin.y);
+ windowPrefs->SetInteger("top", NSMinY(frame));
+ windowPrefs->SetInteger("bottom", NSMaxY(frame));
} else {
- NOTREACHED();
+ // 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 (state_ == kSaveWindowRect) {
+ if ([window_ styleMask] & NSResizableWindowMask) {
int x1, x2, y1, y2;
- if (!windowPrefs->GetInteger(L"left", &x1) ||
- !windowPrefs->GetInteger(L"right", &x2) ||
- !windowPrefs->GetInteger(L"top", &y1) ||
- !windowPrefs->GetInteger(L"bottom", &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(L"left", NULL);
- windowPrefs->Remove(L"right", NULL);
- windowPrefs->Remove(L"top", NULL);
- windowPrefs->Remove(L"bottom", NULL);
+ 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 if (state_ == kSaveWindowPos) {
+ } else {
int x, y;
- if (!windowPrefs->GetInteger(L"x", &x) ||
- !windowPrefs->GetInteger(L"y", &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];
- } else {
- NOTREACHED();
}
}
diff --git a/chrome/browser/cocoa/window_size_autosaver_unittest.mm b/chrome/browser/cocoa/window_size_autosaver_unittest.mm
index b3ce0d2..b220ea0 100644
--- a/chrome/browser/cocoa/window_size_autosaver_unittest.mm
+++ b/chrome/browser/cocoa/window_size_autosaver_unittest.mm
@@ -9,7 +9,7 @@
#include "base/scoped_nsobject.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -18,10 +18,11 @@ namespace {
class WindowSizeAutosaverTest : public CocoaTest {
virtual void SetUp() {
CocoaTest::SetUp();
- path_ = L"WindowSizeAutosaverTest";
+ path_ = "WindowSizeAutosaverTest";
window_ =
[[NSWindow alloc] initWithContentRect:NSMakeRect(100, 101, 150, 151)
- styleMask:NSTitledWindowMask
+ styleMask:NSTitledWindowMask|
+ NSResizableWindowMask
backing:NSBackingStoreBuffered
defer:NO];
browser_helper_.profile()->GetPrefs()->RegisterDictionaryPref(path_);
@@ -35,7 +36,7 @@ class WindowSizeAutosaverTest : public CocoaTest {
public:
BrowserTestHelper browser_helper_;
NSWindow* window_;
- const wchar_t* path_;
+ const char* path_;
};
TEST_F(WindowSizeAutosaverTest, RestoresAndSavesPos) {
@@ -45,6 +46,14 @@ TEST_F(WindowSizeAutosaverTest, RestoresAndSavesPos) {
// 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
@@ -56,8 +65,7 @@ TEST_F(WindowSizeAutosaverTest, RestoresAndSavesPos) {
scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
initWithWindow:window_
prefService:pref
- path:path_
- state:kSaveWindowPos]);
+ path:path_]);
EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
@@ -75,8 +83,7 @@ TEST_F(WindowSizeAutosaverTest, RestoresAndSavesPos) {
scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
initWithWindow:window_
prefService:pref
- path:path_
- state:kSaveWindowPos]);
+ path:path_]);
EXPECT_EQ(300, NSMinX([window_ frame]));
EXPECT_EQ(310, NSMinY([window_ frame]));
EXPECT_EQ(160, NSWidth([window_ frame]));
@@ -87,12 +94,12 @@ TEST_F(WindowSizeAutosaverTest, RestoresAndSavesPos) {
EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
int x, y;
DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
- EXPECT_FALSE(windowPref->GetInteger(L"left", &x));
- EXPECT_FALSE(windowPref->GetInteger(L"right", &x));
- EXPECT_FALSE(windowPref->GetInteger(L"top", &x));
- EXPECT_FALSE(windowPref->GetInteger(L"bottom", &x));
- ASSERT_TRUE(windowPref->GetInteger(L"x", &x));
- ASSERT_TRUE(windowPref->GetInteger(L"y", &y));
+ 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);
}
@@ -115,8 +122,7 @@ TEST_F(WindowSizeAutosaverTest, RestoresAndSavesRect) {
scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
initWithWindow:window_
prefService:pref
- path:path_
- state:kSaveWindowRect]);
+ path:path_]);
EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
@@ -134,8 +140,7 @@ TEST_F(WindowSizeAutosaverTest, RestoresAndSavesRect) {
scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
initWithWindow:window_
prefService:pref
- path:path_
- state:kSaveWindowRect]);
+ path:path_]);
EXPECT_EQ(300, NSMinX([window_ frame]));
EXPECT_EQ(310, NSMinY([window_ frame]));
EXPECT_EQ(250, NSWidth([window_ frame]));
@@ -146,12 +151,12 @@ TEST_F(WindowSizeAutosaverTest, RestoresAndSavesRect) {
EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
int x1, y1, x2, y2;
DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
- EXPECT_FALSE(windowPref->GetInteger(L"x", &x1));
- EXPECT_FALSE(windowPref->GetInteger(L"y", &x1));
- ASSERT_TRUE(windowPref->GetInteger(L"left", &x1));
- ASSERT_TRUE(windowPref->GetInteger(L"right", &x2));
- ASSERT_TRUE(windowPref->GetInteger(L"top", &y1));
- ASSERT_TRUE(windowPref->GetInteger(L"bottom", &y2));
+ 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);
@@ -164,10 +169,10 @@ TEST_F(WindowSizeAutosaverTest, DoesNotRestoreButClearsEmptyRect) {
ASSERT_TRUE(pref != NULL);
DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
- windowPref->SetInteger(L"left", 50);
- windowPref->SetInteger(L"right", 50);
- windowPref->SetInteger(L"top", 60);
- windowPref->SetInteger(L"bottom", 60);
+ windowPref->SetInteger("left", 50);
+ windowPref->SetInteger("right", 50);
+ windowPref->SetInteger("top", 60);
+ windowPref->SetInteger("bottom", 60);
{
// Window rect shouldn't change...
@@ -175,8 +180,7 @@ TEST_F(WindowSizeAutosaverTest, DoesNotRestoreButClearsEmptyRect) {
scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
initWithWindow:window_
prefService:pref
- path:path_
- state:kSaveWindowRect]);
+ path:path_]);
EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
@@ -186,12 +190,12 @@ TEST_F(WindowSizeAutosaverTest, DoesNotRestoreButClearsEmptyRect) {
// ...and it should be gone from the profile, too.
EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
int x1, y1, x2, y2;
- EXPECT_FALSE(windowPref->GetInteger(L"x", &x1));
- EXPECT_FALSE(windowPref->GetInteger(L"y", &x1));
- ASSERT_FALSE(windowPref->GetInteger(L"left", &x1));
- ASSERT_FALSE(windowPref->GetInteger(L"right", &x2));
- ASSERT_FALSE(windowPref->GetInteger(L"top", &y1));
- ASSERT_FALSE(windowPref->GetInteger(L"bottom", &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_controller.h b/chrome/browser/cocoa/wrench_menu_controller.h
index 6ec1f55..bbfa995 100644
--- a/chrome/browser/cocoa/wrench_menu_controller.h
+++ b/chrome/browser/cocoa/wrench_menu_controller.h
@@ -4,15 +4,22 @@
#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
@@ -21,15 +28,19 @@ class WrenchMenuModel;
//
// This object is instantiated in Toolbar.xib and is configured by the
// ToolbarController.
-@interface WrenchMenuController : MenuController <NSMenuDelegate> {
- IBOutlet NSView* editItem_;
- IBOutlet NSSegmentedControl* editControl_;
+@interface WrenchMenuController : MenuController<NSMenuDelegate> {
+ IBOutlet MenuTrackedRootView* editItem_;
+ IBOutlet NSButton* editCut_;
+ IBOutlet NSButton* editCopy_;
+ IBOutlet NSButton* editPaste_;
- IBOutlet NSView* zoomItem_;
+ 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.
@@ -41,6 +52,21 @@ class WrenchMenuModel;
// 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
index ce17447..3c76d92 100644
--- a/chrome/browser/cocoa/wrench_menu_controller.mm
+++ b/chrome/browser/cocoa/wrench_menu_controller.mm
@@ -4,24 +4,62 @@
#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_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
+#import "chrome/browser/cocoa/menu_tracked_root_view.h"
#import "chrome/browser/cocoa/toolbar_controller.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)
-- (WrenchMenuModel*)wrenchMenuModel;
- (void)adjustPositioning;
-- (void)dispatchCommandInternal:(NSNumber*)tag;
+- (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 {
- self = [super init];
+ if ((self = [super init])) {
+ observer_.reset(new WrenchMenuControllerInternal::ZoomLevelObserver(self));
+ }
return self;
}
@@ -49,10 +87,12 @@
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();
@@ -75,6 +115,12 @@
[self wrenchMenuModel]->GetLabelForCommandId(IDC_ZOOM_PERCENT_DISPLAY));
[[zoomItem_ viewWithTag:IDC_ZOOM_PERCENT_DISPLAY] setTitle:title];
+ bool plusEnabled = [self wrenchMenuModel]->IsCommandIdEnabled(IDC_ZOOM_PLUS);
+ bool minusEnabled = [self wrenchMenuModel]->IsCommandIdEnabled(
+ IDC_ZOOM_MINUS);
+ [zoomPlus_ setEnabled:plusEnabled];
+ [zoomMinus_ setEnabled:minusEnabled];
+
NSImage* icon = [self wrenchMenuModel]->browser()->window()->IsFullscreen() ?
[NSImage imageNamed:NSImageNameExitFullScreenTemplate] :
[NSImage imageNamed:NSImageNameEnterFullScreenTemplate];
@@ -87,27 +133,35 @@
// 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];
+ }
+}
- // NSSegmentedControls (used for the Edit item) need a little help to get the
- // command_id of the pressed item.
- if ([sender isKindOfClass:[NSSegmentedControl class]])
- tag = [[sender cell] tagForSegment:[sender selectedSegment]];
-
- // The custom views within the Wrench menu are abnormal and keep the menu open
- // after a target-action. Close the menu manually.
- // TODO(rsesek): It'd be great if the zoom buttons didn't have to close the
- // menu. See http://crbug.com/48679 for more info.
- [menu_ cancelTracking];
+- (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(dispatchCommandInternal:)
+ [self performSelector:@selector(performCommandDispatch:)
withObject:[NSNumber numberWithInt:tag]
afterDelay:0.0];
}
// Used to perform the actual dispatch on the outermost runloop.
-- (void)dispatchCommandInternal:(NSNumber*)tag {
+- (void)performCommandDispatch:(NSNumber*)tag {
[self wrenchMenuModel]->ExecuteCommand([tag intValue]);
}
@@ -118,28 +172,48 @@
// 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];
- NSRect controlFrame = [editControl_ frame];
-
- CGFloat originalControlWidth = NSWidth(controlFrame);
- // Maintain the carefully pixel-pushed gap between the edge of the menu and
- // the rightmost control.
- CGFloat edge = NSWidth(itemFrame) -
- (controlFrame.origin.x + originalControlWidth);
-
- // Resize the edit segmented control to fit the localized strings.
- [editControl_ sizeToFit];
- controlFrame = [editControl_ frame];
- CGFloat resizeAmount = NSWidth(controlFrame) - originalControlWidth;
-
- // Adjust the size of the entire menu item to account for changes in the size
- // of the segmented control.
- itemFrame.size.width += resizeAmount;
+ itemFrame.size.width += delta;
[editItem_ setFrame:itemFrame];
- // Keep the spacing between the right edges of the menu and the control.
- controlFrame.origin.x = NSWidth(itemFrame) - edge - NSWidth(controlFrame);
- [editControl_ setFrame:controlFrame];
+ // 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
index c775013..446bd80 100644
--- a/chrome/browser/cocoa/wrench_menu_controller_unittest.mm
+++ b/chrome/browser/cocoa/wrench_menu_controller_unittest.mm
@@ -14,11 +14,28 @@
#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));
};
@@ -48,14 +65,12 @@ class WrenchMenuControllerTest : public CocoaTest {
scoped_nsobject<ToolbarController> toolbar_controller_;
};
-// Test crashes sometimes. http://crbug.com/49206
-TEST_F(WrenchMenuControllerTest, DISABLED_Initialized) {
+TEST_F(WrenchMenuControllerTest, Initialized) {
EXPECT_TRUE([controller() menu]);
EXPECT_GE([[controller() menu] numberOfItems], 5);
}
-// Test crashes sometimes. http://crbug.com/49206
-TEST_F(WrenchMenuControllerTest, DISABLED_DispatchSimple) {
+TEST_F(WrenchMenuControllerTest, DispatchSimple) {
scoped_nsobject<NSButton> button([[NSButton alloc] init]);
[button setTag:IDC_ZOOM_PLUS];
@@ -66,19 +81,4 @@ TEST_F(WrenchMenuControllerTest, DISABLED_DispatchSimple) {
[controller() dispatchWrenchMenuCommand:button.get()];
}
-// Test crashes sometimes. http://crbug.com/49206
-TEST_F(WrenchMenuControllerTest, DISABLED_DispatchSegmentedControl) {
- // Set fake model to test dispatching.
- EXPECT_CALL(fake_model_, ExecuteCommand(IDC_CUT));
- [controller() setModel:&fake_model_];
-
- scoped_nsobject<NSSegmentedControl> control(
- [[NSSegmentedControl alloc] init]);
- [control setSegmentCount:2];
- [[control cell] setTag:IDC_CUT forSegment:0];
- [[control cell] setSelectedSegment:0];
-
- [controller() dispatchWrenchMenuCommand:control.get()];
-}
-
} // namespace
diff --git a/chrome/browser/collected_cookies_uitest.cc b/chrome/browser/collected_cookies_uitest.cc
index cfd3b1e..92b97b0 100644
--- a/chrome/browser/collected_cookies_uitest.cc
+++ b/chrome/browser/collected_cookies_uitest.cc
@@ -11,11 +11,11 @@
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
} // namespace
@@ -23,9 +23,9 @@ typedef UITest CollectedCookiesTest;
// Test is flaky. http://crbug.com/49539
TEST_F(CollectedCookiesTest, FLAKY_DoubleDisplay) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
@@ -37,7 +37,7 @@ TEST_F(CollectedCookiesTest, FLAKY_DoubleDisplay) {
CONTENT_SETTING_BLOCK));
// Load a page with cookies.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("files/cookie1.html")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("files/cookie1.html")));
// Click on the info link twice.
ASSERT_TRUE(tab->ShowCollectedCookiesDialog());
@@ -46,9 +46,9 @@ TEST_F(CollectedCookiesTest, FLAKY_DoubleDisplay) {
// Test is flaky. http://crbug.com/49539
TEST_F(CollectedCookiesTest, FLAKY_NavigateAway) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
@@ -60,11 +60,11 @@ TEST_F(CollectedCookiesTest, FLAKY_NavigateAway) {
CONTENT_SETTING_BLOCK));
// Load a page with cookies.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("files/cookie1.html")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("files/cookie1.html")));
// Click on the info link.
ASSERT_TRUE(tab->ShowCollectedCookiesDialog());
// Navigate to another page.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("files/cookie2.html")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("files/cookie2.html")));
}
diff --git a/chrome/browser/command_updater.h b/chrome/browser/command_updater.h
index bd30e84..024658d 100644
--- a/chrome/browser/command_updater.h
+++ b/chrome/browser/command_updater.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_COMMAND_UPDATER_H_
#define CHROME_BROWSER_COMMAND_UPDATER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/hash_tables.h"
diff --git a/chrome/browser/config_dir_policy_provider.cc b/chrome/browser/config_dir_policy_provider.cc
deleted file mode 100644
index f0ec6eb..0000000
--- a/chrome/browser/config_dir_policy_provider.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/config_dir_policy_provider.h"
-
-#include <set>
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/common/json_value_serializer.h"
-
-ConfigDirPolicyProvider::ConfigDirPolicyProvider(const FilePath& config_dir)
- : config_dir_(config_dir) {
-}
-
-bool ConfigDirPolicyProvider::Provide(ConfigurationPolicyStore* store) {
- scoped_ptr<DictionaryValue> policy(ReadPolicies());
- DecodePolicyValueTree(policy.get(), store);
- return true;
-}
-
-DictionaryValue* ConfigDirPolicyProvider::ReadPolicies() {
- // Enumerate the files and sort them lexicographically.
- std::set<FilePath> files;
- file_util::FileEnumerator file_enumerator(config_dir_, false,
- file_util::FileEnumerator::FILES);
- for (FilePath config_file_path = file_enumerator.Next();
- !config_file_path.empty(); config_file_path = file_enumerator.Next())
- files.insert(config_file_path);
-
- // Start with an empty dictionary and merge the files' contents.
- DictionaryValue* policy = new DictionaryValue;
- for (std::set<FilePath>::iterator config_file_iter = files.begin();
- config_file_iter != files.end(); ++config_file_iter) {
- JSONFileValueSerializer deserializer(*config_file_iter);
- int error_code = 0;
- std::string error_msg;
- scoped_ptr<Value> value(deserializer.Deserialize(&error_code, &error_msg));
- if (!value.get()) {
- LOG(WARNING) << "Failed to read configuration file "
- << config_file_iter->value() << ": " << error_msg;
- continue;
- }
- if (!value->IsType(Value::TYPE_DICTIONARY)) {
- LOG(WARNING) << "Expected JSON dictionary in configuration file "
- << config_file_iter->value();
- continue;
- }
- policy->MergeDictionary(static_cast<DictionaryValue*>(value.get()));
- }
-
- return policy;
-}
-
-void ConfigDirPolicyProvider::DecodePolicyValueTree(
- DictionaryValue* policies,
- ConfigurationPolicyStore* store) {
- const PolicyValueMap* mapping = PolicyValueMapping();
- for (PolicyValueMap::const_iterator i = mapping->begin();
- i != mapping->end(); ++i) {
- const PolicyValueMapEntry& entry(*i);
- Value* value;
- if (policies->Get(UTF8ToWide(entry.name), &value) &&
- value->IsType(entry.value_type))
- store->Apply(entry.policy_type, value->DeepCopy());
- }
-
- // TODO(mnissler): Handle preference overrides once |ConfigurationPolicyStore|
- // supports it.
-}
-
diff --git a/chrome/browser/config_dir_policy_provider.h b/chrome/browser/config_dir_policy_provider.h
deleted file mode 100644
index 06c1363..0000000
--- a/chrome/browser/config_dir_policy_provider.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_CONFIG_DIR_POLICY_PROVIDER_H_
-#define CHROME_BROWSER_CONFIG_DIR_POLICY_PROVIDER_H_
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "chrome/browser/configuration_policy_provider.h"
-
-class DictionaryValue;
-
-// A policy provider 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
-// ConfigurationPolicyProvider interface. The files are consulted in
-// lexicographic file name order, so the last value read takes precedence in
-// case of preference key collisions.
-class ConfigDirPolicyProvider : public ConfigurationPolicyProvider {
- public:
- explicit ConfigDirPolicyProvider(const FilePath& config_dir);
- virtual ~ConfigDirPolicyProvider() { }
-
- // ConfigurationPolicyProvider implementation.
- virtual bool Provide(ConfigurationPolicyStore* store);
-
- private:
- // Read and merge the files from the configuration directory.
- DictionaryValue* ReadPolicies();
-
- // Decodes the value tree and writes the configuration to the given |store|.
- void DecodePolicyValueTree(DictionaryValue* policies,
- ConfigurationPolicyStore* store);
-
- // The directory in which we look for configuration files.
- const FilePath config_dir_;
-
- DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyProvider);
-};
-
-#endif // CHROME_BROWSER_CONFIG_DIR_POLICY_PROVIDER_H_
diff --git a/chrome/browser/config_dir_policy_provider_unittest.cc b/chrome/browser/config_dir_policy_provider_unittest.cc
deleted file mode 100644
index c992ff3..0000000
--- a/chrome/browser/config_dir_policy_provider_unittest.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. 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/path_service.h"
-#include "base/string_util.h"
-#include "chrome/browser/config_dir_policy_provider.h"
-#include "chrome/browser/mock_configuration_policy_store.h"
-#include "chrome/common/json_value_serializer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class ConfigDirPolicyProviderTest : public testing::Test {
- protected:
- virtual void SetUp() {
- // Determine the directory to use for testing.
- ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
- test_dir_ =
- test_dir_.Append(FILE_PATH_LITERAL("ConfigDirPolicyProviderTest"));
-
- // Make sure the directory is fresh.
- file_util::Delete(test_dir_, true);
- file_util::CreateDirectory(test_dir_);
- ASSERT_TRUE(file_util::DirectoryExists(test_dir_));
-
- // Create a fresh policy store mock.
- policy_store_.reset(new MockConfigurationPolicyStore());
- }
-
- virtual void TearDown() {
- // Clean up test directory.
- ASSERT_TRUE(file_util::Delete(test_dir_, true));
- ASSERT_FALSE(file_util::PathExists(test_dir_));
- }
-
- // JSON-encode a dictionary and write it to a file.
- void WriteConfigFile(const DictionaryValue& dict,
- const std::string& file_name) {
- std::string data;
- JSONStringValueSerializer serializer(&data);
- serializer.Serialize(dict);
- FilePath file_path(test_dir_.AppendASCII(file_name));
- file_util::WriteFile(file_path, data.c_str(), data.size());
- }
-
- FilePath test_dir_;
- scoped_ptr<MockConfigurationPolicyStore> policy_store_;
-};
-
-// The preferences dictionary is expected to be empty when there are no files to
-// load.
-TEST_F(ConfigDirPolicyProviderTest, ReadPrefsEmpty) {
- ConfigDirPolicyProvider provider(test_dir_);
- EXPECT_TRUE(provider.Provide(policy_store_.get()));
- EXPECT_TRUE(policy_store_->policy_map().empty());
-}
-
-// Reading from a non-existent directory should result in an empty preferences
-// dictionary.
-TEST_F(ConfigDirPolicyProviderTest, ReadPrefsNonExistentDirectory) {
- FilePath non_existent_dir(test_dir_.Append(FILE_PATH_LITERAL("not_there")));
- ConfigDirPolicyProvider provider(non_existent_dir);
- EXPECT_TRUE(provider.Provide(policy_store_.get()));
- EXPECT_TRUE(policy_store_->policy_map().empty());
-}
-
-// Test reading back a single preference value.
-TEST_F(ConfigDirPolicyProviderTest, ReadPrefsSinglePref) {
- DictionaryValue test_dict;
- test_dict.SetString(L"HomepageLocation", L"http://www.google.com");
- WriteConfigFile(test_dict, "config_file");
- ConfigDirPolicyProvider provider(test_dir_);
-
- EXPECT_TRUE(provider.Provide(policy_store_.get()));
- const MockConfigurationPolicyStore::PolicyMap& policy_map(
- policy_store_->policy_map());
- EXPECT_EQ(1U, policy_map.size());
- MockConfigurationPolicyStore::PolicyMap::const_iterator entry =
- policy_map.find(ConfigurationPolicyStore::kPolicyHomePage);
- ASSERT_TRUE(entry != policy_map.end());
-
- std::wstring str_value;
- EXPECT_TRUE(entry->second->GetAsString(&str_value));
- EXPECT_EQ(L"http://www.google.com", str_value);
-}
-
-// Test merging values from different files.
-TEST_F(ConfigDirPolicyProviderTest, ReadPrefsMergePrefs) {
- // Write a bunch of data files in order to increase the chance to detect the
- // provider not respecting lexicographic ordering when reading them. Since the
- // filesystem may return files in arbitrary order, there is no way to be sure,
- // but this is better than nothing.
- DictionaryValue test_dict_bar;
- test_dict_bar.SetString(L"HomepageLocation", L"http://bar.com");
- for (unsigned int i = 1; i <= 4; ++i)
- WriteConfigFile(test_dict_bar, IntToString(i));
- DictionaryValue test_dict_foo;
- test_dict_foo.SetString(L"HomepageLocation", L"http://foo.com");
- WriteConfigFile(test_dict_foo, "9");
- for (unsigned int i = 5; i <= 8; ++i)
- WriteConfigFile(test_dict_bar, IntToString(i));
- ConfigDirPolicyProvider provider(test_dir_);
-
- EXPECT_TRUE(provider.Provide(policy_store_.get()));
- const MockConfigurationPolicyStore::PolicyMap& policy_map(
- policy_store_->policy_map());
- EXPECT_EQ(1U, policy_map.size());
- MockConfigurationPolicyStore::PolicyMap::const_iterator entry =
- policy_map.find(ConfigurationPolicyStore::kPolicyHomePage);
- ASSERT_TRUE(entry != policy_map.end());
-
- std::wstring str_value;
- EXPECT_TRUE(entry->second->GetAsString(&str_value));
- EXPECT_EQ(L"http://foo.com", str_value);
-}
diff --git a/chrome/browser/configuration_policy_pref_store.cc b/chrome/browser/configuration_policy_pref_store.cc
deleted file mode 100644
index dc12e63..0000000
--- a/chrome/browser/configuration_policy_pref_store.cc
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/configuration_policy_pref_store.h"
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/string16.h"
-#include "base/string_util.h"
-#include "base/values.h"
-#include "chrome/browser/configuration_policy_provider.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-
-const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
- ConfigurationPolicyPrefStore::simple_policy_map_[] = {
- { Value::TYPE_STRING, kPolicyHomePage, prefs::kHomePage },
- { Value::TYPE_BOOLEAN, kPolicyHomepageIsNewTabPage,
- prefs::kHomePageIsNewTabPage },
- { Value::TYPE_BOOLEAN, kPolicyAlternateErrorPagesEnabled,
- prefs::kAlternateErrorPagesEnabled },
- { Value::TYPE_BOOLEAN, kPolicySearchSuggestEnabled,
- prefs::kSearchSuggestEnabled },
- { Value::TYPE_BOOLEAN, kPolicyDnsPrefetchingEnabled,
- prefs::kDnsPrefetchingEnabled },
- { Value::TYPE_BOOLEAN, kPolicySafeBrowsingEnabled,
- prefs::kSafeBrowsingEnabled },
- { Value::TYPE_BOOLEAN, kPolicyPasswordManagerEnabled,
- prefs::kPasswordManagerEnabled },
- { Value::TYPE_BOOLEAN, kPolicyMetricsReportingEnabled,
- prefs::kMetricsReportingEnabled },
- { Value::TYPE_STRING, kPolicyApplicationLocale,
- prefs::kApplicationLocale},
-};
-
-const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
- ConfigurationPolicyPrefStore::proxy_policy_map_[] = {
- { Value::TYPE_STRING, kPolicyProxyServer, prefs::kProxyServer },
- { Value::TYPE_STRING, kPolicyProxyPacUrl, prefs::kProxyPacUrl },
- { Value::TYPE_STRING, kPolicyProxyBypassList, prefs::kProxyBypassList }
-};
-
-ConfigurationPolicyPrefStore::ConfigurationPolicyPrefStore(
- const CommandLine* command_line,
- ConfigurationPolicyProvider* provider)
- : command_line_(command_line),
- provider_(provider),
- prefs_(new DictionaryValue()),
- command_line_proxy_settings_cleared_(false),
- proxy_disabled_(false),
- proxy_configuration_specified_(false),
- use_system_proxy_(false) {
-}
-
-void ConfigurationPolicyPrefStore::ApplyProxySwitches() {
- bool proxy_disabled = command_line_->HasSwitch(switches::kNoProxyServer);
- if (proxy_disabled) {
- prefs_->Set(prefs::kNoProxyServer, Value::CreateBooleanValue(true));
- }
- bool has_explicit_proxy_config = false;
- if (command_line_->HasSwitch(switches::kProxyAutoDetect)) {
- has_explicit_proxy_config = true;
- prefs_->Set(prefs::kProxyAutoDetect, Value::CreateBooleanValue(true));
- }
- if (command_line_->HasSwitch(switches::kProxyServer)) {
- has_explicit_proxy_config = true;
- prefs_->Set(prefs::kProxyServer, Value::CreateStringValue(
- command_line_->GetSwitchValue(switches::kProxyServer)));
- }
- if (command_line_->HasSwitch(switches::kProxyPacUrl)) {
- has_explicit_proxy_config = true;
- prefs_->Set(prefs::kProxyPacUrl, Value::CreateStringValue(
- command_line_->GetSwitchValue(switches::kProxyPacUrl)));
- }
- if (command_line_->HasSwitch(switches::kProxyBypassList)) {
- has_explicit_proxy_config = true;
- prefs_->Set(prefs::kProxyBypassList, Value::CreateStringValue(
- command_line_->GetSwitchValue(switches::kProxyBypassList)));
- }
-
- // Warn about all the other proxy config switches we get if
- // the --no-proxy-server command-line argument is present.
- if (proxy_disabled && has_explicit_proxy_config) {
- LOG(WARNING) << "Additional command-line proxy switches specified when --"
- << switches::kNoProxyServer << " was also specified.";
- }
-}
-
-PrefStore::PrefReadError ConfigurationPolicyPrefStore::ReadPrefs() {
- // Initialize proxy preference values from command-line switches. This is done
- // before calling Provide to allow the provider to overwrite proxy-related
- // preferences that are specified by line settings.
- ApplyProxySwitches();
-
- proxy_disabled_ = false;
- proxy_configuration_specified_ = false;
- command_line_proxy_settings_cleared_ = false;
-
- return (provider_.get() == NULL || provider_->Provide(this)) ?
- PrefStore::PREF_READ_ERROR_NONE : PrefStore::PREF_READ_ERROR_OTHER;
-}
-
-bool ConfigurationPolicyPrefStore::ApplyProxyPolicy(PolicyType policy,
- Value* value) {
- bool result = false;
- bool warn_about_proxy_disable_config = false;
- bool warn_about_proxy_system_config = false;
-
- const PolicyToPreferenceMapEntry* match_entry_ = NULL;
- for (const PolicyToPreferenceMapEntry* current = proxy_policy_map_;
- current != proxy_policy_map_ + arraysize(proxy_policy_map_); ++current) {
- if (current->policy_type == policy) {
- match_entry_ = current;
- }
- }
-
- // When the first proxy-related policy is applied, ALL proxy-related
- // preferences that have been set by command-line switches must be
- // removed. Otherwise it's possible for a user to interfere with proxy
- // policy by using proxy-related switches that are related to, but not
- // identical, to the ones set through policy.
- if ((match_entry_ ||
- policy == ConfigurationPolicyPrefStore::kPolicyProxyServerMode) &&
- !command_line_proxy_settings_cleared_) {
- for (const PolicyToPreferenceMapEntry* i = proxy_policy_map_;
- i != proxy_policy_map_ + arraysize(proxy_policy_map_); ++i) {
- if (prefs_->Get(i->preference_path, NULL)) {
- LOG(WARNING) << "proxy configuration options were specified on the"
- << " command-line but will be ignored because an"
- << " explicit proxy configuration has been specified"
- << " through a centrally-administered policy.";
- break;
- }
- }
-
- // Now actually do the preference removal.
- for (const PolicyToPreferenceMapEntry* current = proxy_policy_map_;
- current != proxy_policy_map_ + arraysize(proxy_policy_map_); ++current)
- prefs_->Remove(current->preference_path, NULL);
- prefs_->Remove(prefs::kNoProxyServer, NULL);
- prefs_->Remove(prefs::kProxyAutoDetect, NULL);
-
- command_line_proxy_settings_cleared_ = true;
- }
-
- // Translate the proxy policy into preferences.
- if (policy == ConfigurationPolicyStore::kPolicyProxyServerMode) {
- int int_value;
- bool proxy_auto_detect = false;
- if (value->GetAsInteger(&int_value)) {
- result = true;
- switch (int_value) {
- case ConfigurationPolicyStore::kPolicyNoProxyServerMode:
- if (!proxy_disabled_) {
- if (proxy_configuration_specified_)
- warn_about_proxy_disable_config = true;
- proxy_disabled_ = true;
- }
- break;
- case ConfigurationPolicyStore::kPolicyAutoDetectProxyMode:
- proxy_auto_detect = true;
- break;
- case ConfigurationPolicyStore::kPolicyManuallyConfiguredProxyMode:
- break;
- case ConfigurationPolicyStore::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));
- }
-
- // No proxy and system proxy mode should ensure that no other
- // proxy preferences are set.
- if (int_value == ConfigurationPolicyStore::kPolicyNoProxyServerMode ||
- int_value == kPolicyUseSystemProxyMode) {
- for (const PolicyToPreferenceMapEntry* current = proxy_policy_map_;
- current != proxy_policy_map_ + arraysize(proxy_policy_map_);
- ++current)
- prefs_->Remove(current->preference_path, NULL);
- }
- }
- } 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.";
- }
-
- // If the policy was a proxy policy, cleanup |value|.
- if (result && value)
- delete value;
- return result;
-}
-
-bool ConfigurationPolicyPrefStore::ApplyPluginPolicy(PolicyType policy,
- Value* value) {
- if (policy == kPolicyDisabledPlugins) {
- string16 plugin_list;
- if (value->GetAsUTF16(&plugin_list)) {
- std::vector<string16> plugin_names;
- // Change commas into tabs so that we can change escaped
- // tabs back into commas, leaving non-escaped commas as tabs
- // that can be used for splitting the string. Note that plugin
- // names must not contain backslashes, since a trailing backslash
- // in a plugin name before a comma would get swallowed during the
- // splitting.
- std::replace(plugin_list.begin(), plugin_list.end(), L',', L'\t');
- ReplaceSubstringsAfterOffset(&plugin_list, 0,
- ASCIIToUTF16("\\\t"), ASCIIToUTF16(","));
- SplitString(plugin_list, L'\t', &plugin_names);
- bool added_plugin = false;
- scoped_ptr<ListValue> list(new ListValue());
- for (std::vector<string16>::const_iterator i(plugin_names.begin());
- i != plugin_names.end(); ++i) {
- if (!i->empty()) {
- list->Append(Value::CreateStringValueFromUTF16(*i));
- added_plugin = true;
- }
- }
- if (added_plugin) {
- prefs_->Set(prefs::kPluginsPluginsBlacklist, list.release());
- delete value;
- return true;
- }
- }
- }
- return false;
-}
-
-bool ConfigurationPolicyPrefStore::ApplySyncPolicy(PolicyType policy,
- Value* value) {
- if (policy == ConfigurationPolicyStore::kPolicySyncDisabled) {
- bool disable_sync;
- if (value->GetAsBoolean(&disable_sync) && disable_sync)
- prefs_->Set(prefs::kSyncManaged, value);
- else
- delete value;
- return true;
- }
- return false;
-}
-
-bool ConfigurationPolicyPrefStore::ApplyPolicyFromMap(PolicyType policy,
- Value* value, const PolicyToPreferenceMapEntry map[], int size) {
- const PolicyToPreferenceMapEntry* end = map + size;
- for (const PolicyToPreferenceMapEntry* current = map;
- current != end; ++current) {
- if (current->policy_type == policy) {
- DCHECK(current->value_type == value->GetType());
- prefs_->Set(current->preference_path, value);
- return true;
- }
- }
- return false;
-}
-
-void ConfigurationPolicyPrefStore::Apply(PolicyType policy, Value* value) {
- if (ApplyProxyPolicy(policy, value))
- return;
-
- if (ApplyPluginPolicy(policy, value))
- return;
-
- if (ApplySyncPolicy(policy, value))
- return;
-
- if (ApplyPolicyFromMap(policy, value, simple_policy_map_,
- arraysize(simple_policy_map_)))
- return;
-
- // Other policy implementations go here.
- NOTIMPLEMENTED();
- delete value;
-}
diff --git a/chrome/browser/configuration_policy_pref_store.h b/chrome/browser/configuration_policy_pref_store.h
deleted file mode 100644
index afbb541..0000000
--- a/chrome/browser/configuration_policy_pref_store.h
+++ /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.
-
-#ifndef CHROME_BROWSER_CONFIGURATION_POLICY_PREF_STORE_H_
-#define CHROME_BROWSER_CONFIGURATION_POLICY_PREF_STORE_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/scoped_ptr.h"
-#include "base/values.h"
-#include "chrome/browser/configuration_policy_provider.h"
-#include "chrome/browser/configuration_policy_store.h"
-#include "chrome/common/pref_store.h"
-
-class CommandLine;
-
-// An implementation of the |PrefStore| that holds a Dictionary
-// created through applied policy.
-class ConfigurationPolicyPrefStore : public PrefStore,
- public ConfigurationPolicyStore {
- public:
- // The ConfigurationPolicyPrefStore takes the ownership of the passed
- // |provider|.
- ConfigurationPolicyPrefStore(const CommandLine* command_line,
- ConfigurationPolicyProvider* provider);
- virtual ~ConfigurationPolicyPrefStore() { }
-
- // PrefStore methods:
- virtual PrefReadError ReadPrefs();
- virtual DictionaryValue* prefs() { return prefs_.get(); }
-
- private:
- // For unit tests.
- friend class ConfigurationPolicyPrefStoreTest;
-
- // 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;
- PolicyType policy_type;
- const wchar_t* preference_path; // A DictionaryValue path, not a file path.
- };
-
- static const PolicyToPreferenceMapEntry simple_policy_map_[];
- static const PolicyToPreferenceMapEntry proxy_policy_map_[];
-
- const CommandLine* command_line_;
- scoped_ptr<ConfigurationPolicyProvider> provider_;
- scoped_ptr<DictionaryValue> prefs_;
-
- // Set to false until the first proxy-relevant policy is applied. Allows
- // the Apply method to erase all switch-specified proxy configuration before
- // applying proxy policy configuration;
- bool command_line_proxy_settings_cleared_;
-
- // 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_;
-
- // ConfigurationPolicyStore methods:
- virtual void Apply(PolicyType setting, Value* value);
-
- // Initializes default preference values from proxy-related command-line
- // switches in |command_line_|.
- void ApplyProxySwitches();
-
- bool ApplyPolicyFromMap(PolicyType 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(PolicyType policy, Value* value);
-
- // Processes plugin policies. Returns true if the specified policy
- // is a plugin-related policy. ApplyPluginPolicy assumes the ownership
- // of |value| in the case that the policy is plugin-specific.
- bool ApplyPluginPolicy(PolicyType policy, Value* value);
-
- // Handles sync-related policies. Returns true if the policy was handled.
- // Assumes ownership of |value| in that case.
- bool ApplySyncPolicy(PolicyType policy, Value* value);
-
- DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefStore);
-};
-
-#endif // CHROME_BROWSER_CONFIGURATION_POLICY_PREF_STORE_H_
diff --git a/chrome/browser/configuration_policy_pref_store_unittest.cc b/chrome/browser/configuration_policy_pref_store_unittest.cc
deleted file mode 100644
index 0e74c94..0000000
--- a/chrome/browser/configuration_policy_pref_store_unittest.cc
+++ /dev/null
@@ -1,469 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// 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/command_line.h"
-#include "chrome/browser/configuration_policy_pref_store.h"
-#include "chrome/browser/mock_configuration_policy_provider.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/chrome_switches.h"
-
-class ConfigurationPolicyPrefStoreTest : public testing::Test {
- public:
- // Applies a policy that has a string value.
- void ApplyStringPolicyValue(
- ConfigurationPolicyPrefStore* store,
- ConfigurationPolicyStore::PolicyType type,
- const wchar_t* policy_value);
-
- // The following three methods test a policy which controls a string
- // preference.
- // Checks that by default, it's an empty string.
- void TestStringPolicyGetDefault(const wchar_t* pref_name);
- // Checks that values can be set.
- void TestStringPolicySetValue(const wchar_t* pref_name,
- ConfigurationPolicyStore::PolicyType type);
- // A wrapper that calls the above two methods.
- void TestStringPolicy(const wchar_t* pref_name,
- ConfigurationPolicyStore::PolicyType type);
-
- // The following three methods test a policy which controls a boolean
- // preference.
- // Checks that there's no deafult.
- void TestBooleanPolicyGetDefault(const wchar_t* pref_name);
- // Checks that values can be set.
- void TestBooleanPolicySetValue(const wchar_t* pref_name,
- ConfigurationPolicyStore::PolicyType type);
- // A wrapper that calls the above two methods.
- void TestBooleanPolicy(const wchar_t* pref_name,
- ConfigurationPolicyStore::PolicyType type);
-
- // The following three methods test a policy which controls an integer
- // preference.
- // Checks that by default, it's 0.
- void TestIntegerPolicyGetDefault(const wchar_t* pref_name);
- // Checks that values can be set.
- void TestIntegerPolicySetValue(const wchar_t* pref_name,
- ConfigurationPolicyStore::PolicyType type);
- // A wrapper that calls the above two methods.
- void TestIntegerPolicy(const wchar_t* pref_name,
- ConfigurationPolicyStore::PolicyType type);
-};
-
-void ConfigurationPolicyPrefStoreTest::ApplyStringPolicyValue(
- ConfigurationPolicyPrefStore* store,
- ConfigurationPolicyStore::PolicyType type,
- const wchar_t* policy_value) {
- store->Apply(type, Value::CreateStringValue(policy_value));
-}
-
-void ConfigurationPolicyPrefStoreTest::TestStringPolicyGetDefault(
- const wchar_t* pref_name) {
- ConfigurationPolicyPrefStore store(NULL, NULL);
- std::wstring result;
- store.prefs()->GetString(pref_name, &result);
- EXPECT_EQ(result, L"");
-}
-
-void ConfigurationPolicyPrefStoreTest::TestStringPolicySetValue(
- const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) {
- ConfigurationPolicyPrefStore store(NULL, NULL);
- ApplyStringPolicyValue(&store, type, L"http://chromium.org");
- std::wstring result;
- store.prefs()->GetString(pref_name, &result);
- EXPECT_EQ(result, L"http://chromium.org");
-}
-
-void ConfigurationPolicyPrefStoreTest::TestStringPolicy(
- const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) {
- TestStringPolicyGetDefault(pref_name);
- TestStringPolicySetValue(pref_name, type);
-}
-
-void ConfigurationPolicyPrefStoreTest::TestBooleanPolicyGetDefault(
- const wchar_t* pref_name) {
- ConfigurationPolicyPrefStore store(NULL, NULL);
- bool result = false;
- store.prefs()->GetBoolean(pref_name, &result);
- EXPECT_FALSE(result);
- result = true;
- store.prefs()->GetBoolean(pref_name, &result);
- EXPECT_TRUE(result);
-}
-
-void ConfigurationPolicyPrefStoreTest::TestBooleanPolicySetValue(
- const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) {
- ConfigurationPolicyPrefStore store(NULL, NULL);
- store.Apply(type, Value::CreateBooleanValue(false));
- bool result = true;
- store.prefs()->GetBoolean(pref_name, &result);
- EXPECT_FALSE(result);
-
- store.Apply(type, Value::CreateBooleanValue(true));
- result = false;
- store.prefs()->GetBoolean(pref_name, &result);
- EXPECT_TRUE(result);
-}
-
-void ConfigurationPolicyPrefStoreTest::TestBooleanPolicy(
- const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) {
- TestBooleanPolicyGetDefault(pref_name);
- TestBooleanPolicySetValue(pref_name, type);
-}
-
-void ConfigurationPolicyPrefStoreTest::TestIntegerPolicyGetDefault(
- const wchar_t* pref_name) {
- ConfigurationPolicyPrefStore store(NULL, NULL);
- int result = 0;
- store.prefs()->GetInteger(pref_name, &result);
- EXPECT_EQ(result, 0);
-}
-
-void ConfigurationPolicyPrefStoreTest::TestIntegerPolicySetValue(
- const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) {
- ConfigurationPolicyPrefStore store(NULL, NULL);
- store.Apply(type, Value::CreateIntegerValue(2));
- int result = 0;
- store.prefs()->GetInteger(pref_name, &result);
- EXPECT_EQ(result, 2);
-}
-
-void ConfigurationPolicyPrefStoreTest::TestIntegerPolicy(
- const wchar_t* pref_name, ConfigurationPolicyStore::PolicyType type) {
- TestIntegerPolicyGetDefault(pref_name);
- TestIntegerPolicySetValue(pref_name, type);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingHomePageDefault) {
- TestStringPolicy(prefs::kHomePage,
- ConfigurationPolicyPrefStore::kPolicyHomePage);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyHomepageIsNewTabPage) {
- TestBooleanPolicy(prefs::kHomePageIsNewTabPage,
- ConfigurationPolicyPrefStore::kPolicyHomepageIsNewTabPage);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyAlternateErrorPagesEnabled) {
- TestBooleanPolicy(prefs::kAlternateErrorPagesEnabled,
- ConfigurationPolicyStore::kPolicyAlternateErrorPagesEnabled);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicySearchSuggestEnabled) {
- TestBooleanPolicy(prefs::kSearchSuggestEnabled,
- ConfigurationPolicyStore::kPolicySearchSuggestEnabled);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyDnsPrefetchingEnabled) {
- TestBooleanPolicy(prefs::kDnsPrefetchingEnabled,
- ConfigurationPolicyStore::kPolicyDnsPrefetchingEnabled);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicySafeBrowsingEnabled) {
- TestBooleanPolicy(prefs::kSafeBrowsingEnabled,
- ConfigurationPolicyStore::kPolicySafeBrowsingEnabled);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyMetricsReportingEnabled) {
- TestBooleanPolicy(prefs::kMetricsReportingEnabled,
- ConfigurationPolicyStore::kPolicyMetricsReportingEnabled);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyPasswordManagerEnabled) {
- TestBooleanPolicy(prefs::kPasswordManagerEnabled,
- ConfigurationPolicyStore::kPolicyPasswordManagerEnabled);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingProxyServer) {
- TestStringPolicy(prefs::kProxyServer,
- ConfigurationPolicyPrefStore::kPolicyProxyServer);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingProxyPacUrl) {
- TestStringPolicy(prefs::kProxyPacUrl,
- ConfigurationPolicyPrefStore::kPolicyProxyPacUrl);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingProxyBypassList) {
- TestStringPolicy(prefs::kProxyBypassList,
- ConfigurationPolicyPrefStore::kPolicyProxyBypassList);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestSettingsProxyConfig) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- command_line.AppendSwitch(switches::kNoProxyServer);
- command_line.AppendSwitch(switches::kProxyAutoDetect);
- command_line.AppendSwitchWithValue(switches::kProxyPacUrl,
- L"http://chromium.org/test.pac");
- command_line.AppendSwitchWithValue(switches::kProxyServer,
- L"http://chromium2.org");
- command_line.AppendSwitchWithValue(switches::kProxyBypassList,
- L"http://chromium3.org");
-
- ConfigurationPolicyPrefStore store(&command_line, NULL);
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- // Ensure that all traces of the command-line specified proxy
- // switches have been overriden.
- std::wstring string_result;
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_EQ(string_result, L"http://chromium3.org");
-
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result));
- EXPECT_EQ(string_result, L"http://chromium.org/test.pac");
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
- EXPECT_EQ(string_result, L"http://chromium2.org");
- 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_TRUE(bool_result);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfigManualOverride) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- command_line.AppendSwitch(switches::kNoProxyServer);
- command_line.AppendSwitch(switches::kProxyAutoDetect);
- command_line.AppendSwitchWithValue(switches::kProxyPacUrl,
- L"http://chromium.org/test.pac");
- command_line.AppendSwitchWithValue(switches::kProxyServer,
- L"http://chromium.org");
- command_line.AppendSwitchWithValue(switches::kProxyBypassList,
- L"http://chromium.org");
-
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- ConfigurationPolicyStore::kPolicyManuallyConfiguredProxyMode));
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList,
- Value::CreateStringValue(L"http://chromium.org/override"));
-
- ConfigurationPolicyPrefStore store(&command_line,
- provider.release());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- // Ensure that all traces of the command-line specified proxy
- // switches have been overriden.
- std::wstring string_result;
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_EQ(string_result, L"http://chromium.org/override");
-
- 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_FALSE(bool_result);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfigNoProxy) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList,
- Value::CreateStringValue(L"http://chromium.org/override"));
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- ConfigurationPolicyStore::kPolicyNoProxyServerMode));
-
- ConfigurationPolicyPrefStore store(&command_line, provider.release());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::wstring 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(ConfigurationPolicyPrefStoreTest,
- TestPolicyProxyConfigNoProxyReversedApplyOrder) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- ConfigurationPolicyStore::kPolicyNoProxyServerMode));
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList,
- Value::CreateStringValue(L"http://chromium.org/override"));
-
- ConfigurationPolicyPrefStore store(&command_line, provider.release());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::wstring 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(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfigAutoDetect) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList,
- Value::CreateStringValue(L"http://chromium.org/override"));
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- ConfigurationPolicyStore::kPolicyAutoDetectProxyMode));
-
- ConfigurationPolicyPrefStore store(&command_line, provider.release());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- // Ensure that all traces of the command-line specified proxy
- // switches have been overriden.
- std::wstring string_result;
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_EQ(string_result, L"http://chromium.org/override");
-
- 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);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest, TestPolicyProxyConfiguseSystem) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList,
- Value::CreateStringValue(L"http://chromium.org/override"));
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- ConfigurationPolicyStore::kPolicyUseSystemProxyMode));
-
- ConfigurationPolicyPrefStore store(&command_line, provider.release());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::wstring string_result;
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_EQ(string_result, L"");
-
- 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(ConfigurationPolicyPrefStoreTest,
- TestPolicyProxyConfiguseSystemReversedApplyOrder) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- ConfigurationPolicyStore::kPolicyUseSystemProxyMode));
- provider->AddPolicy(ConfigurationPolicyStore::kPolicyProxyBypassList,
- Value::CreateStringValue(L"http://chromium.org/override"));
-
- ConfigurationPolicyPrefStore store(&command_line, provider.release());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::wstring string_result;
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_EQ(string_result, L"");
-
- 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(ConfigurationPolicyPrefStoreTest,
- TestPolicyProxyDisabledPlugin) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
-
- ConfigurationPolicyPrefStore store(&command_line, provider.release());
- ApplyStringPolicyValue(&store,
- ConfigurationPolicyStore::kPolicyDisabledPlugins,
- L"plugin1");
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- ListValue* plugin_blacklist = NULL;
- EXPECT_TRUE(store.prefs()->GetList(prefs::kPluginsPluginsBlacklist,
- &plugin_blacklist));
-
- ListValue::const_iterator current(plugin_blacklist->begin());
- ListValue::const_iterator end(plugin_blacklist->end());
-
- ASSERT_TRUE(current != end);
- std::string plugin_name;
- (*current)->GetAsString(&plugin_name);
- EXPECT_EQ("plugin1", plugin_name);
- ++current;
- EXPECT_TRUE(current == end);
-}
-
-TEST_F(ConfigurationPolicyPrefStoreTest,
- TestPolicyProxyDisabledPluginEscapedComma) {
- FilePath unused_path(FILE_PATH_LITERAL("foo.exe"));
- CommandLine command_line(unused_path);
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
-
- ConfigurationPolicyPrefStore store(&command_line, provider.release());
- ApplyStringPolicyValue(&store,
- ConfigurationPolicyStore::kPolicyDisabledPlugins,
- L"plugin1,plugin2\\,");
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- ListValue* plugin_blacklist = NULL;
- EXPECT_TRUE(store.prefs()->GetList(prefs::kPluginsPluginsBlacklist,
- &plugin_blacklist));
- ListValue::const_iterator current(plugin_blacklist->begin());
- ListValue::const_iterator end(plugin_blacklist->end());
- ASSERT_TRUE(current != end);
- std::string plugin_name;
- (*current)->GetAsString(&plugin_name);
- EXPECT_EQ("plugin1", plugin_name);
- ++current;
- ASSERT_TRUE(current != end);
- (*current)->GetAsString(&plugin_name);
- EXPECT_EQ("plugin2,", plugin_name);
- ++current;
- EXPECT_TRUE(current == end);
-}
-
diff --git a/chrome/browser/configuration_policy_provider.cc b/chrome/browser/configuration_policy_provider.cc
deleted file mode 100644
index cb6e210..0000000
--- a/chrome/browser/configuration_policy_provider.cc
+++ /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.
-
-#include "chrome/browser/configuration_policy_provider.h"
-
-#include "base/values.h"
-
-namespace {
-
-// TODO(avi): Use this mapping to auto-generate MCX manifests and Windows
-// ADM/ADMX files. http://crbug.com/49316
-
-struct InternalPolicyValueMapEntry {
- ConfigurationPolicyStore::PolicyType policy_type;
- Value::ValueType value_type;
- const char* name;
-};
-
-const InternalPolicyValueMapEntry kPolicyValueMap[] = {
- { ConfigurationPolicyStore::kPolicyHomePage,
- Value::TYPE_STRING, "HomepageLocation" },
- { ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage,
- Value::TYPE_BOOLEAN, "HomepageIsNewTabPage" },
- { ConfigurationPolicyStore::kPolicyProxyServerMode,
- Value::TYPE_INTEGER, "ProxyServerMode" },
- { ConfigurationPolicyStore::kPolicyProxyServer,
- Value::TYPE_STRING, "ProxyServer" },
- { ConfigurationPolicyStore::kPolicyProxyPacUrl,
- Value::TYPE_STRING, "ProxyPacUrl" },
- { ConfigurationPolicyStore::kPolicyProxyBypassList,
- Value::TYPE_STRING, "ProxyBypassList" },
- { ConfigurationPolicyStore::kPolicyAlternateErrorPagesEnabled,
- Value::TYPE_BOOLEAN, "AlternateErrorPagesEnabled" },
- { ConfigurationPolicyStore::kPolicySearchSuggestEnabled,
- Value::TYPE_BOOLEAN, "SearchSuggestEnabled" },
- { ConfigurationPolicyStore::kPolicyDnsPrefetchingEnabled,
- Value::TYPE_BOOLEAN, "DnsPrefetchingEnabled" },
- { ConfigurationPolicyStore::kPolicySafeBrowsingEnabled,
- Value::TYPE_BOOLEAN, "SafeBrowsingEnabled" },
- { ConfigurationPolicyStore::kPolicyMetricsReportingEnabled,
- Value::TYPE_BOOLEAN, "MetricsReportingEnabled" },
- { ConfigurationPolicyStore::kPolicyPasswordManagerEnabled,
- Value::TYPE_BOOLEAN, "PasswordManagerEnabled" },
- { ConfigurationPolicyStore::kPolicyDisabledPlugins,
- Value::TYPE_STRING, "DisabledPluginsList" },
- { ConfigurationPolicyStore::kPolicyApplicationLocale,
- Value::TYPE_STRING, "ApplicationLocaleValue" },
- { ConfigurationPolicyStore::kPolicySyncDisabled,
- Value::TYPE_BOOLEAN, "SyncDisabled" },
-};
-
-} // namespace
-
-/* static */
-const ConfigurationPolicyProvider::PolicyValueMap*
- ConfigurationPolicyProvider::PolicyValueMapping() {
- static PolicyValueMap* mapping;
- if (!mapping) {
- mapping = new PolicyValueMap();
- for (size_t i = 0; i < arraysize(kPolicyValueMap); ++i) {
- const InternalPolicyValueMapEntry& internal_entry = kPolicyValueMap[i];
- PolicyValueMapEntry entry;
- entry.policy_type = internal_entry.policy_type;
- entry.value_type = internal_entry.value_type;
- entry.name = std::string(internal_entry.name);
- mapping->push_back(entry);
- }
- }
- return mapping;
-}
diff --git a/chrome/browser/configuration_policy_provider.h b/chrome/browser/configuration_policy_provider.h
deleted file mode 100644
index f0f6051..0000000
--- a/chrome/browser/configuration_policy_provider.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_CONFIGURATION_POLICY_PROVIDER_H_
-#define CHROME_BROWSER_CONFIGURATION_POLICY_PROVIDER_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "chrome/browser/configuration_policy_store.h"
-
-class DictionaryValue;
-
-// A mostly-abstract super class for platform-specific policy providers.
-// Platform-specific policy providers (Windows Group Policy, gconf,
-// etc.) should implement a subclass of this class.
-class ConfigurationPolicyProvider {
- public:
- 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.
- virtual bool Provide(ConfigurationPolicyStore* store) = 0;
-
- protected:
- // A structure mapping policies to their implementations by providers.
- struct PolicyValueMapEntry {
- ConfigurationPolicyStore::PolicyType policy_type;
- Value::ValueType value_type;
- std::string name;
- };
- typedef std::vector<PolicyValueMapEntry> PolicyValueMap;
-
- // Returns the mapping from policy values to the actual names used by
- // implementations.
- static const PolicyValueMap* PolicyValueMapping();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProvider);
-};
-
-#endif // CHROME_BROWSER_CONFIGURATION_POLICY_PROVIDER_H_
-
diff --git a/chrome/browser/configuration_policy_provider_mac.cc b/chrome/browser/configuration_policy_provider_mac.cc
deleted file mode 100644
index c1a9c2c..0000000
--- a/chrome/browser/configuration_policy_provider_mac.cc
+++ /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.
-
-#include "chrome/browser/configuration_policy_provider_mac.h"
-
-#include "base/logging.h"
-#include "base/scoped_cftyperef.h"
-#include "base/sys_string_conversions.h"
-
-ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac()
- : preferences_(new MacPreferences()) {
-}
-
-ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac(
- MacPreferences* preferences) : preferences_(preferences) {
-}
-
-bool ConfigurationPolicyProviderMac::Provide(ConfigurationPolicyStore* store) {
- bool success = true;
- const PolicyValueMap* mapping = PolicyValueMapping();
-
- for (PolicyValueMap::const_iterator current = mapping->begin();
- current != mapping->end(); ++current) {
- scoped_cftyperef<CFStringRef> name(
- base::SysUTF8ToCFStringRef(current->name));
- scoped_cftyperef<CFPropertyListRef> value(
- preferences_->CopyAppValue(name, kCFPreferencesCurrentApplication));
- if (!value.get())
- continue;
- if (!preferences_->AppValueIsForced(name, kCFPreferencesCurrentApplication))
- continue;
-
- switch (current->value_type) {
- case Value::TYPE_STRING:
- if (CFGetTypeID(value) == CFStringGetTypeID()) {
- std::string string_value =
- base::SysCFStringRefToUTF8((CFStringRef)value.get());
- store->Apply(
- current->policy_type,
- Value::CreateStringValue(string_value));
- } else {
- success = false;
- }
- break;
- case Value::TYPE_BOOLEAN:
- if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
- bool bool_value = CFBooleanGetValue((CFBooleanRef)value.get());
- store->Apply(current->policy_type,
- Value::CreateBooleanValue(bool_value));
- } else {
- success = false;
- }
- break;
- case Value::TYPE_INTEGER:
- if (CFGetTypeID(value) == CFNumberGetTypeID()) {
- int int_value;
- bool cast = CFNumberGetValue((CFNumberRef)value.get(),
- kCFNumberIntType,
- &int_value);
- if (cast)
- store->Apply(current->policy_type,
- Value::CreateIntegerValue(int_value));
- else
- success = false;
- } else {
- success = false;
- }
- break;
- default:
- NOTREACHED();
- return false;
- }
- }
-
- return success;
-}
-
diff --git a/chrome/browser/configuration_policy_provider_mac.h b/chrome/browser/configuration_policy_provider_mac.h
deleted file mode 100644
index 1cb67a1..0000000
--- a/chrome/browser/configuration_policy_provider_mac.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_CONFIGURATION_POLICY_PROVIDER_MAC_H_
-#define CHROME_BROWSER_CONFIGURATION_POLICY_PROVIDER_MAC_H_
-
-#include "base/scoped_ptr.h"
-#include "chrome/browser/configuration_policy_store.h"
-#include "chrome/browser/configuration_policy_provider.h"
-#include "chrome/browser/preferences_mac.h"
-
-// An implementation of |ConfigurationPolicyProvider| using the mechanism
-// provided by Mac OS X's managed preferences.
-class ConfigurationPolicyProviderMac : public ConfigurationPolicyProvider {
- public:
- ConfigurationPolicyProviderMac();
- // For testing; takes ownership of |preferences|.
- explicit ConfigurationPolicyProviderMac(MacPreferences* preferences);
- virtual ~ConfigurationPolicyProviderMac() { }
-
- // ConfigurationPolicyProvider method overrides:
- virtual bool Provide(ConfigurationPolicyStore* store);
-
- protected:
- scoped_ptr<MacPreferences> preferences_;
-};
-
-#endif // CHROME_BROWSER_CONFIGURATION_POLICY_PROVIDER_MAC_H_
-
diff --git a/chrome/browser/configuration_policy_provider_mac_unittest.cc b/chrome/browser/configuration_policy_provider_mac_unittest.cc
deleted file mode 100644
index 4e6885d..0000000
--- a/chrome/browser/configuration_policy_provider_mac_unittest.cc
+++ /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.
-
-#include <gtest/gtest.h>
-
-#include "base/stl_util-inl.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/configuration_policy_provider_mac.h"
-#include "chrome/browser/mock_configuration_policy_store.h"
-#include "chrome/browser/preferences_mock_mac.h"
-
-// A subclass of |ConfigurationPolicyProviderMac| providing access to various
-// internal things without an orgy of FRIEND_TESTS.
-class TestConfigurationPolicyProviderMac
- : public ConfigurationPolicyProviderMac {
- public:
- TestConfigurationPolicyProviderMac() :
- ConfigurationPolicyProviderMac(new MockPreferences()) { }
- virtual ~TestConfigurationPolicyProviderMac() { }
-
- void AddTestItem(ConfigurationPolicyStore::PolicyType policy,
- CFPropertyListRef value,
- bool is_forced);
-
- typedef std::vector<PolicyValueMapEntry> PolicyValueMap;
- static const PolicyValueMap* PolicyValueMapping() {
- return ConfigurationPolicyProvider::PolicyValueMapping();
- }
-};
-
-void TestConfigurationPolicyProviderMac::AddTestItem(
- ConfigurationPolicyStore::PolicyType policy,
- CFPropertyListRef value,
- bool is_forced) {
- const PolicyValueMap* mapping = PolicyValueMapping();
- for (PolicyValueMap::const_iterator current = mapping->begin();
- current != mapping->end(); ++current) {
- if (current->policy_type == policy) {
- scoped_cftyperef<CFStringRef> name(
- base::SysUTF8ToCFStringRef(current->name));
- static_cast<MockPreferences*>(preferences_.get())->
- AddTestItem(name, value, is_forced);
- }
- }
-}
-
-TEST(ConfigurationPolicyProviderMacTest, TestPolicyDefault) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderMac provider;
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage));
-}
-
-TEST(ConfigurationPolicyProviderMacTest, TestHomePagePolicy) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderMac provider;
- provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomePage,
- CFSTR("http://chromium.org"),
- true);
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- MockConfigurationPolicyStore::PolicyMap::const_iterator i =
- map.find(ConfigurationPolicyStore::kPolicyHomePage);
- ASSERT_TRUE(i != map.end());
- std::string value;
- i->second->GetAsString(&value);
- EXPECT_EQ("http://chromium.org", value);
-}
-
-TEST(ConfigurationPolicyProviderMacTest, TestHomePagePolicyUnforced) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderMac provider;
- provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomePage,
- CFSTR("http://chromium.org"),
- false);
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage));
-}
-
-TEST(ConfigurationPolicyProviderMacTest, TestHomePagePolicyWrongType) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderMac provider;
- provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomePage,
- kCFBooleanTrue,
- true);
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage));
-}
-
-TEST(ConfigurationPolicyProviderMacTest, TestHomepageIsNewTabPagePolicy) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderMac provider;
- provider.AddTestItem(ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage,
- kCFBooleanTrue,
- true);
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- MockConfigurationPolicyStore::PolicyMap::const_iterator i =
- map.find(ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage);
- ASSERT_TRUE(i != map.end());
- bool value = false;
- i->second->GetAsBoolean(&value);
- EXPECT_EQ(true, value);
-}
-
diff --git a/chrome/browser/configuration_policy_provider_win.cc b/chrome/browser/configuration_policy_provider_win.cc
deleted file mode 100644
index d39adee..0000000
--- a/chrome/browser/configuration_policy_provider_win.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/configuration_policy_provider_win.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/registry.h"
-#include "base/scoped_ptr.h"
-#include "base/string_piece.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-
-#if defined(GOOGLE_CHROME_BUILD)
-const wchar_t ConfigurationPolicyProviderWin::kPolicyRegistrySubKey[] =
- L"SOFTWARE\\Policies\\Google\\Chrome";
-#else
-const wchar_t ConfigurationPolicyProviderWin::kPolicyRegistrySubKey[] =
- L"SOFTWARE\\Policies\\Chromium";
-#endif
-
-ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin() {
-}
-
-bool ConfigurationPolicyProviderWin::GetRegistryPolicyString(
- const wchar_t* value_name, string16* result) {
- DWORD value_size = 0;
- DWORD key_type = 0;
- scoped_array<uint8> buffer;
- RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kPolicyRegistrySubKey);
- if (hkcu_policy_key.ReadValue(value_name, 0, &value_size, &key_type)) {
- 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 prefill to zeros to guarantee
- // the 0-termination.
- buffer.reset(new uint8[value_size + 2]);
- memset(buffer.get(), 0, value_size + 2);
- hkcu_policy_key.ReadValue(value_name, buffer.get(), &value_size);
- } else {
- RegKey hklm_policy_key(HKEY_CURRENT_USER, kPolicyRegistrySubKey);
- if (hklm_policy_key.ReadValue(value_name, 0, &value_size, &key_type)) {
- 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 prefill to zeros to guarantee
- // the 0-termination.
- buffer.reset(new uint8[value_size + 2]);
- memset(buffer.get(), 0, value_size + 2);
- hklm_policy_key.ReadValue(value_name, buffer.get(), &value_size);
- } else {
- return false;
- }
- }
-
- result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
- return true;
-}
-
-bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean(
- const wchar_t* value_name, bool* result) {
- DWORD value;
- RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kPolicyRegistrySubKey);
- if (hkcu_policy_key.ReadValueDW(value_name, &value)) {
- *result = value != 0;
- return true;
- }
-
- RegKey hklm_policy_key(HKEY_CURRENT_USER, kPolicyRegistrySubKey);
- if (hklm_policy_key.ReadValueDW(value_name, &value)) {
- *result = value != 0;
- return true;
- }
- return false;
-}
-
-bool ConfigurationPolicyProviderWin::GetRegistryPolicyInteger(
- const wchar_t* value_name, uint32* result) {
- DWORD value;
- RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kPolicyRegistrySubKey);
- if (hkcu_policy_key.ReadValueDW(value_name, &value)) {
- *result = value;
- return true;
- }
-
- RegKey hklm_policy_key(HKEY_CURRENT_USER, kPolicyRegistrySubKey);
- if (hklm_policy_key.ReadValueDW(value_name, &value)) {
- *result = value;
- return true;
- }
- return false;
-}
-
-bool ConfigurationPolicyProviderWin::Provide(
- ConfigurationPolicyStore* store) {
- const PolicyValueMap* mapping = PolicyValueMapping();
-
- for (PolicyValueMap::const_iterator current = mapping->begin();
- current != mapping->end(); ++current) {
- std::wstring name = UTF8ToWide(current->name);
- std::wstring string_value;
- uint32 int_value;
- bool bool_value;
- switch (current->value_type) {
- case Value::TYPE_STRING:
- if (GetRegistryPolicyString(name.c_str(), &string_value)) {
- store->Apply(
- current->policy_type,
- Value::CreateStringValueFromUTF16(string_value));
- }
- break;
- case Value::TYPE_BOOLEAN:
- if (GetRegistryPolicyBoolean(name.c_str(), &bool_value)) {
- store->Apply(current->policy_type,
- Value::CreateBooleanValue(bool_value));
- }
- break;
- case Value::TYPE_INTEGER:
- if (GetRegistryPolicyInteger(name.c_str(), &int_value)) {
- store->Apply(current->policy_type,
- Value::CreateIntegerValue(int_value));
- }
- break;
- default:
- NOTREACHED();
- return false;
- }
- }
-
- return true;
-}
-
diff --git a/chrome/browser/configuration_policy_provider_win.h b/chrome/browser/configuration_policy_provider_win.h
deleted file mode 100644
index f5c5eee..0000000
--- a/chrome/browser/configuration_policy_provider_win.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_CONFIGURATION_POLICY_PROVIDER_WIN_H_
-#define CHROME_BROWSER_CONFIGURATION_POLICY_PROVIDER_WIN_H_
-
-#include "chrome/browser/configuration_policy_store.h"
-#include "chrome/browser/configuration_policy_provider.h"
-
-// An implementation of |ConfigurationPolicyProvider| using the
-// mechanism provided by Windows Groups Policy. Policy decisions are
-// stored as values in a special section of the Windows Registry.
-// 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:
- ConfigurationPolicyProviderWin();
- virtual ~ConfigurationPolicyProviderWin() { }
-
- // ConfigurationPolicyProvider method overrides:
- virtual bool Provide(ConfigurationPolicyStore* store);
-
- protected:
- // The sub key path for Chromium's Group Policy information in the
- // Windows registry.
- static const wchar_t kPolicyRegistrySubKey[];
-
- private:
- // Methods to perfrom type-specific policy lookups in the registry.
- // HKLM is checked first, then HKCU.
- bool GetRegistryPolicyString(const wchar_t* value_name, string16* result);
- bool GetRegistryPolicyBoolean(const wchar_t* value_name, bool* result);
- bool GetRegistryPolicyInteger(const wchar_t* value_name, uint32* result);
-};
-
-#endif // CHROME_BROWSER_CONFIGURATION_POLICY_PROVIDER_WIN_H_
-
diff --git a/chrome/browser/configuration_policy_provider_win_unittest.cc b/chrome/browser/configuration_policy_provider_win_unittest.cc
deleted file mode 100644
index 6197780..0000000
--- a/chrome/browser/configuration_policy_provider_win_unittest.cc
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// 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 <windows.h>
-
-#include "base/logging.h"
-#include "base/registry.h"
-#include "base/scoped_ptr.h"
-#include "base/stl_util-inl.h"
-#include "base/string_piece.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/configuration_policy_provider_win.h"
-#include "chrome/browser/mock_configuration_policy_store.h"
-#include "chrome/common/pref_names.h"
-
-namespace {
-
-const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests";
-const wchar_t kUnitTestMachineOverrideSubKey[] =
- L"SOFTWARE\\Chromium Unit Tests\\HKLM Override";
-const wchar_t kUnitTestUserOverrideSubKey[] =
- L"SOFTWARE\\Chromium Unit Tests\\HKCU Override";
-
-} // namespace
-
-// A subclass of |ConfigurationPolicyProviderWin| providing access to
-// internal protected constants without an orgy of FRIEND_TESTS.
-class TestConfigurationPolicyProviderWin
- : public ConfigurationPolicyProviderWin {
- public:
- TestConfigurationPolicyProviderWin() : ConfigurationPolicyProviderWin() { }
- virtual ~TestConfigurationPolicyProviderWin() { }
-
- void SetHomepageRegistryValue(HKEY hive, const wchar_t* value);
- void SetHomepageRegistryValueWrongType(HKEY hive);
- void SetBooleanPolicy(ConfigurationPolicyStore::PolicyType type,
- HKEY hive, bool value);
- void SetCookiesMode(HKEY hive, uint32 value);
-
- typedef std::vector<PolicyValueMapEntry> PolicyValueMap;
- static const PolicyValueMap* PolicyValueMapping() {
- return ConfigurationPolicyProvider::PolicyValueMapping();
- }
-};
-
-namespace {
-
-std::wstring NameForPolicy(ConfigurationPolicyStore::PolicyType policy) {
- const TestConfigurationPolicyProviderWin::PolicyValueMap* mapping =
- TestConfigurationPolicyProviderWin::PolicyValueMapping();
- for (TestConfigurationPolicyProviderWin::PolicyValueMap::const_iterator
- current = mapping->begin(); current != mapping->end(); ++current) {
- if (current->policy_type == policy)
- return UTF8ToWide(current->name);
- }
- return NULL;
-}
-
-} // namespace
-
-void TestConfigurationPolicyProviderWin::SetHomepageRegistryValue(
- HKEY hive,
- const wchar_t* value) {
- RegKey key(hive,
- ConfigurationPolicyProviderWin::kPolicyRegistrySubKey,
- KEY_ALL_ACCESS);
- EXPECT_TRUE(key.WriteValue(
- NameForPolicy(ConfigurationPolicyStore::kPolicyHomePage).c_str(),
- value));
-}
-
-void TestConfigurationPolicyProviderWin::SetHomepageRegistryValueWrongType(
- HKEY hive) {
- RegKey key(hive,
- ConfigurationPolicyProviderWin::kPolicyRegistrySubKey,
- KEY_ALL_ACCESS);
- EXPECT_TRUE(key.WriteValue(
- NameForPolicy(ConfigurationPolicyStore::kPolicyHomePage).c_str(),
- 5));
-}
-
-void TestConfigurationPolicyProviderWin::SetBooleanPolicy(
- ConfigurationPolicyStore::PolicyType type,
- HKEY hive,
- bool value) {
- RegKey key(hive, ConfigurationPolicyProviderWin::kPolicyRegistrySubKey,
- KEY_ALL_ACCESS);
- EXPECT_TRUE(key.WriteValue(NameForPolicy(type).c_str(), value));
-}
-
-// This test class provides sandboxing and mocking for the parts of the
-// Windows Registry implementing Group Policy. The |SetUp| method prepares
-// two temporary sandbox keys in |kUnitTestRegistrySubKey|, one for HKLM and one
-// for HKCU. A test's calls to the registry are redirected by Windows to these
-// sandboxes, allowing the tests to manipulate and access policy as if it
-// were active, but without actually changing the parts of the Registry that
-// are managed by Group Policy.
-class ConfigurationPolicyProviderWinTest : public testing::Test {
- public:
- ConfigurationPolicyProviderWinTest();
-
- // testing::Test method overrides:
- virtual void SetUp();
- virtual void TearDown();
-
- void ActivateOverrides();
- void DeactivateOverrides();
-
- // Deletes the registry key created during the tests.
- void DeleteRegistrySandbox();
-
- void TestBooleanPolicyDefault(ConfigurationPolicyStore::PolicyType type);
- void TestBooleanPolicyHKLM(ConfigurationPolicyStore::PolicyType type);
- void TestBooleanPolicy(ConfigurationPolicyStore::PolicyType type);
-
- private:
- // Keys are created for the lifetime of a test to contain
- // the sandboxed HKCU and HKLM hives, respectively.
- RegKey temp_hkcu_hive_key_;
- RegKey temp_hklm_hive_key_;
-};
-
-ConfigurationPolicyProviderWinTest::ConfigurationPolicyProviderWinTest()
- : temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey),
- temp_hkcu_hive_key_(HKEY_CURRENT_USER, kUnitTestUserOverrideSubKey) {
-}
-
-void ConfigurationPolicyProviderWinTest::SetUp() {
- // Cleanup any remnants of previous tests.
- DeleteRegistrySandbox();
-
- // Create the subkeys to hold the overridden HKLM and HKCU
- // policy settings.
- temp_hklm_hive_key_.Create(HKEY_CURRENT_USER,
- kUnitTestMachineOverrideSubKey,
- KEY_ALL_ACCESS);
- temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER,
- kUnitTestUserOverrideSubKey,
- KEY_ALL_ACCESS);
-
- ActivateOverrides();
-}
-
-void ConfigurationPolicyProviderWinTest::ActivateOverrides() {
- HRESULT result = RegOverridePredefKey(HKEY_LOCAL_MACHINE,
- temp_hklm_hive_key_.Handle());
- EXPECT_EQ(ERROR_SUCCESS, result);
- result = RegOverridePredefKey(HKEY_CURRENT_USER,
- temp_hkcu_hive_key_.Handle());
- EXPECT_EQ(ERROR_SUCCESS, result);
-}
-
-void ConfigurationPolicyProviderWinTest::DeactivateOverrides() {
- uint32 result = RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0);
- EXPECT_EQ(ERROR_SUCCESS, result);
- result = RegOverridePredefKey(HKEY_CURRENT_USER, 0);
- EXPECT_EQ(ERROR_SUCCESS, result);
-}
-
-void ConfigurationPolicyProviderWinTest::TearDown() {
- DeactivateOverrides();
- DeleteRegistrySandbox();
-}
-
-void ConfigurationPolicyProviderWinTest::DeleteRegistrySandbox() {
- temp_hklm_hive_key_.Close();
- temp_hkcu_hive_key_.Close();
- RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, KEY_ALL_ACCESS);
- key.DeleteKey(L"");
-}
-
-void ConfigurationPolicyProviderWinTest::TestBooleanPolicyDefault(
- ConfigurationPolicyStore::PolicyType type) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderWin provider;
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- EXPECT_FALSE(ContainsKey(map, type));
-}
-
-void ConfigurationPolicyProviderWinTest::TestBooleanPolicyHKLM(
- ConfigurationPolicyStore::PolicyType type) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderWin provider;
- provider.SetBooleanPolicy(type, HKEY_LOCAL_MACHINE, true);
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- MockConfigurationPolicyStore::PolicyMap::const_iterator i = map.find(type);
- ASSERT_TRUE(i != map.end());
- bool value = false;
- i->second->GetAsBoolean(&value);
- EXPECT_EQ(true, value);
-}
-
-void ConfigurationPolicyProviderWinTest::TestBooleanPolicy(
- ConfigurationPolicyStore::PolicyType type) {
- TestBooleanPolicyDefault(type);
- TestBooleanPolicyHKLM(type);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyDefault) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderWin provider;
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage));
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKCU) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderWin provider;
- provider.SetHomepageRegistryValue(HKEY_CURRENT_USER,
- L"http://chromium.org");
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- MockConfigurationPolicyStore::PolicyMap::const_iterator i =
- map.find(ConfigurationPolicyStore::kPolicyHomePage);
- ASSERT_TRUE(i != map.end());
- string16 value;
- i->second->GetAsString(&value);
- EXPECT_EQ(L"http://chromium.org", value);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKCUWrongType) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderWin provider;
- provider.SetHomepageRegistryValueWrongType(HKEY_CURRENT_USER);
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- EXPECT_FALSE(ContainsKey(map, ConfigurationPolicyStore::kPolicyHomePage));
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKLM) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderWin provider;
- provider.SetHomepageRegistryValue(HKEY_LOCAL_MACHINE,
- L"http://chromium.org");
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- MockConfigurationPolicyStore::PolicyMap::const_iterator i =
- map.find(ConfigurationPolicyStore::kPolicyHomePage);
- ASSERT_TRUE(i != map.end());
- string16 value;
- i->second->GetAsString(&value);
- EXPECT_EQ(L"http://chromium.org", value);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest, TestHomePagePolicyHKLMOverHKCU) {
- MockConfigurationPolicyStore store;
- TestConfigurationPolicyProviderWin provider;
- provider.SetHomepageRegistryValue(HKEY_CURRENT_USER,
- L"http://chromium.org");
- provider.SetHomepageRegistryValue(HKEY_LOCAL_MACHINE,
- L"http://crbug.com");
-
- provider.Provide(&store);
-
- const MockConfigurationPolicyStore::PolicyMap& map(store.policy_map());
- MockConfigurationPolicyStore::PolicyMap::const_iterator i =
- map.find(ConfigurationPolicyStore::kPolicyHomePage);
- ASSERT_TRUE(i != map.end());
- string16 value;
- i->second->GetAsString(&value);
- EXPECT_EQ(L"http://crbug.com", value);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest,
- TestHomepageIsNewTabPagePolicy) {
- TestBooleanPolicy(ConfigurationPolicyStore::kPolicyHomepageIsNewTabPage);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest,
- TestPolicyAlternateErrorPagesEnabled) {
- TestBooleanPolicy(
- ConfigurationPolicyStore::kPolicyAlternateErrorPagesEnabled);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest,
- TestPolicySearchSuggestEnabled) {
- TestBooleanPolicy(ConfigurationPolicyStore::kPolicySearchSuggestEnabled);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest,
- TestPolicyDnsPrefetchingEnabled) {
- TestBooleanPolicy(ConfigurationPolicyStore::kPolicyDnsPrefetchingEnabled);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest,
- TestPolicySafeBrowsingEnabled) {
- TestBooleanPolicy(ConfigurationPolicyStore::kPolicySafeBrowsingEnabled);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest,
- TestPolicyMetricsReportingEnabled) {
- TestBooleanPolicy(ConfigurationPolicyStore::kPolicyMetricsReportingEnabled);
-}
-
-TEST_F(ConfigurationPolicyProviderWinTest,
- TestPolicyPasswordManagerEnabled) {
- TestBooleanPolicy(ConfigurationPolicyStore::kPolicyPasswordManagerEnabled);
-}
-
diff --git a/chrome/browser/configuration_policy_store.h b/chrome/browser/configuration_policy_store.h
deleted file mode 100644
index cbf1bb1..0000000
--- a/chrome/browser/configuration_policy_store.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_CONFIGURATION_POLICY_STORE_H_
-#define CHROME_BROWSER_CONFIGURATION_POLICY_STORE_H_
-
-#include "base/values.h"
-
-// An abstract super class for policy stores that provides a method that can be
-// called by a |ConfigurationPolicyProvider| to specify a policy.
-class ConfigurationPolicyStore {
- public:
- ConfigurationPolicyStore() {}
- virtual ~ConfigurationPolicyStore() {}
-
- enum PolicyType {
- kPolicyHomePage,
- kPolicyHomepageIsNewTabPage,
- kPolicyProxyServerMode,
- kPolicyProxyServer,
- kPolicyProxyPacUrl,
- kPolicyProxyBypassList,
- kPolicyAlternateErrorPagesEnabled,
- kPolicySearchSuggestEnabled,
- kPolicyDnsPrefetchingEnabled,
- kPolicySafeBrowsingEnabled,
- kPolicyMetricsReportingEnabled,
- kPolicyPasswordManagerEnabled,
- kPolicySyncDisabled,
- kPolicyApplicationLocale,
-
- // A policy for allowing administrators to forcibly disable
- // specific plugins. This policy is a comma-separated list of
- // plugin names. Plugin names must not include the backslash
- // character.
- kPolicyDisabledPlugins
- };
-
- static const int kPolicyNoProxyServerMode = 0;
- static const int kPolicyAutoDetectProxyMode = 1;
- static const int kPolicyManuallyConfiguredProxyMode = 2;
- static const int kPolicyUseSystemProxyMode = 3;
-
- // A |ConfigurationPolicyProvider| specifes the value of a policy setting
- // through a call to |Apply|.
- // The configuration policy pref store takes over the ownership of |value|.
- virtual void Apply(PolicyType policy, Value* value) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyStore);
-};
-
-#endif // CHROME_BROWSER_CONFIGURATION_POLICY_STORE_H_
diff --git a/chrome/browser/content_exceptions_table_model.cc b/chrome/browser/content_exceptions_table_model.cc
index d149a6d..bf32612 100644
--- a/chrome/browser/content_exceptions_table_model.cc
+++ b/chrome/browser/content_exceptions_table_model.cc
@@ -19,9 +19,12 @@ ContentExceptionsTableModel::ContentExceptionsTableModel(
content_type_(type),
observer_(NULL) {
// Load the contents.
- map->GetSettingsForOneType(type, &entries_);
- if (off_the_record_map)
- off_the_record_map->GetSettingsForOneType(type, &off_the_record_entries_);
+ map->GetSettingsForOneType(type, "", &entries_);
+ if (off_the_record_map) {
+ off_the_record_map->GetSettingsForOneType(type,
+ "",
+ &off_the_record_entries_);
+ }
}
void ContentExceptionsTableModel::AddException(
@@ -35,7 +38,10 @@ void ContentExceptionsTableModel::AddException(
entries(is_off_the_record).push_back(
HostContentSettingsMap::PatternSettingPair(pattern, setting));
- map(is_off_the_record)->SetContentSetting(pattern, content_type_, setting);
+ map(is_off_the_record)->SetContentSetting(pattern,
+ content_type_,
+ "",
+ setting);
if (observer_)
observer_->OnItemsAdded(insert_position, 1);
}
@@ -47,7 +53,7 @@ void ContentExceptionsTableModel::RemoveException(int row) {
const HostContentSettingsMap::PatternSettingPair& pair = entry_at(row);
map(is_off_the_record)->SetContentSetting(
- pair.first, content_type_, CONTENT_SETTING_DEFAULT);
+ pair.first, content_type_, "", CONTENT_SETTING_DEFAULT);
entries(is_off_the_record).erase(
entries(is_off_the_record).begin() + position_to_delete);
if (observer_)
diff --git a/chrome/browser/content_exceptions_table_model.h b/chrome/browser/content_exceptions_table_model.h
index 469dac0..8e29591 100644
--- a/chrome/browser/content_exceptions_table_model.h
+++ b/chrome/browser/content_exceptions_table_model.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_CONTENT_EXCEPTIONS_TABLE_MODEL_H_
#define CHROME_BROWSER_CONTENT_EXCEPTIONS_TABLE_MODEL_H_
+#pragma once
#include <string>
#include "app/table_model.h"
+#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"
@@ -62,8 +64,8 @@ class ContentExceptionsTableModel : public TableModel {
return is_off_the_record ? off_the_record_entries_ : entries_;
}
- HostContentSettingsMap* map_;
- HostContentSettingsMap* off_the_record_map_;
+ scoped_refptr<HostContentSettingsMap> map_;
+ scoped_refptr<HostContentSettingsMap> off_the_record_map_;
ContentSettingsType content_type_;
HostContentSettingsMap::SettingsForOneType entries_;
HostContentSettingsMap::SettingsForOneType off_the_record_entries_;
diff --git a/chrome/browser/content_exceptions_table_model_unittest.cc b/chrome/browser/content_exceptions_table_model_unittest.cc
new file mode 100644
index 0000000..646ab9e
--- /dev/null
+++ b/chrome/browser/content_exceptions_table_model_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 "chrome/browser/content_exceptions_table_model.h"
+
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ContentExceptionsTableModelTest : public testing::Test {
+ public:
+ ContentExceptionsTableModelTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_) {}
+
+ protected:
+ MessageLoop message_loop_;
+ ChromeThread ui_thread_;
+};
+
+TEST_F(ContentExceptionsTableModelTest, Incognito) {
+ TestingProfile profile;
+ TestingProfile* otr_profile = new TestingProfile();
+ otr_profile->set_off_the_record(true);
+ ContentExceptionsTableModel model(profile.GetHostContentSettingsMap(),
+ otr_profile->GetHostContentSettingsMap(),
+ CONTENT_SETTINGS_TYPE_COOKIES);
+ delete otr_profile;
+ model.AddException(HostContentSettingsMap::Pattern("example.com"),
+ CONTENT_SETTING_BLOCK, true);
+}
+
+} // namespace
diff --git a/chrome/browser/content_setting_bubble_model.cc b/chrome/browser/content_setting_bubble_model.cc
index 6d8b902..71055a6 100644
--- a/chrome/browser/content_setting_bubble_model.cc
+++ b/chrome/browser/content_setting_bubble_model.cc
@@ -5,13 +5,19 @@
#include "chrome/browser/content_setting_bubble_model.h"
#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.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_delegate.h"
+#include "chrome/browser/tab_contents/tab_specific_content_settings.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
@@ -24,25 +30,71 @@ class ContentSettingTitleAndLinkModel : public ContentSettingBubbleModel {
: ContentSettingBubbleModel(tab_contents, profile, content_type) {
// Notifications do not have a bubble.
DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+ SetBlockedResources();
SetTitle();
SetManageLink();
}
private:
+ void SetBlockedResources() {
+ TabSpecificContentSettings* settings =
+ tab_contents()->GetTabSpecificContentSettings();
+ const std::set<std::string>& resources = settings->BlockedResourcesForType(
+ content_type());
+ for (std::set<std::string>::const_iterator it = resources.begin();
+ it != resources.end(); ++it) {
+ AddBlockedResource(*it);
+ }
+ }
+
void SetTitle() {
- static const int kTitleIDs[] = {
+ static const int kBlockedTitleIDs[] = {
IDS_BLOCKED_COOKIES_TITLE,
IDS_BLOCKED_IMAGES_TITLE,
IDS_BLOCKED_JAVASCRIPT_TITLE,
- IDS_BLOCKED_PLUGINS_TITLE,
+ IDS_BLOCKED_PLUGINS_MESSAGE,
IDS_BLOCKED_POPUPS_TITLE,
0, // Geolocation does not have an overall title.
0, // Notifications do not have a bubble.
};
- COMPILE_ASSERT(arraysize(kTitleIDs) == CONTENT_SETTINGS_NUM_TYPES,
+ // Fields as for kBlockedTitleIDs, above.
+ static const int kResourceSpecificBlockedTitleIDs[] = {
+ 0,
+ 0,
+ 0,
+ IDS_BLOCKED_PLUGINS_TITLE,
+ 0,
+ 0,
+ 0,
+ };
+ static const int kAccessedTitleIDs[] = {
+ IDS_ACCESSED_COOKIES_TITLE,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ };
+ COMPILE_ASSERT(arraysize(kAccessedTitleIDs) == CONTENT_SETTINGS_NUM_TYPES,
Need_a_setting_for_every_content_settings_type);
- if (kTitleIDs[content_type()])
- set_title(l10n_util::GetStringUTF8(kTitleIDs[content_type()]));
+ COMPILE_ASSERT(arraysize(kBlockedTitleIDs) == CONTENT_SETTINGS_NUM_TYPES,
+ Need_a_setting_for_every_content_settings_type);
+ COMPILE_ASSERT(arraysize(kResourceSpecificBlockedTitleIDs) ==
+ CONTENT_SETTINGS_NUM_TYPES,
+ Need_a_setting_for_every_content_settings_type);
+ const int *title_ids = kBlockedTitleIDs;
+ if (tab_contents() &&
+ tab_contents()->GetTabSpecificContentSettings()->IsContentAccessed(
+ content_type()) &&
+ !tab_contents()->GetTabSpecificContentSettings()->IsContentBlocked(
+ content_type())) {
+ title_ids = kAccessedTitleIDs;
+ } else if (!bubble_content().resource_identifiers.empty()) {
+ title_ids = kResourceSpecificBlockedTitleIDs;
+ }
+ if (title_ids[content_type()])
+ set_title(l10n_util::GetStringUTF8(title_ids[content_type()]));
}
void SetManageLink() {
@@ -124,6 +176,9 @@ class ContentSettingSingleRadioGroup : public ContentSettingTitleAndLinkModel {
&display_host_wide, NULL, NULL);
std::string display_host(WideToUTF8(display_host_wide));
+ const std::set<std::string>& resources =
+ bubble_content().resource_identifiers;
+
RadioGroup radio_group;
radio_group.url = url;
@@ -131,16 +186,31 @@ class ContentSettingSingleRadioGroup : public ContentSettingTitleAndLinkModel {
0, // We don't manage cookies here.
IDS_BLOCKED_IMAGES_UNBLOCK,
IDS_BLOCKED_JAVASCRIPT_UNBLOCK,
- IDS_BLOCKED_PLUGINS_UNBLOCK,
+ IDS_BLOCKED_PLUGINS_UNBLOCK_ALL,
IDS_BLOCKED_POPUPS_UNBLOCK,
0, // We don't manage geolocation here.
0, // Notifications do not have a bubble.
};
COMPILE_ASSERT(arraysize(kAllowIDs) == CONTENT_SETTINGS_NUM_TYPES,
Need_a_setting_for_every_content_settings_type);
+ // Fields as for kAllowIDs, above.
+ static const int kResourceSpecificAllowIDs[] = {
+ 0,
+ 0,
+ 0,
+ IDS_BLOCKED_PLUGINS_UNBLOCK,
+ 0,
+ 0,
+ 0,
+ };
+ COMPILE_ASSERT(
+ arraysize(kResourceSpecificAllowIDs) == CONTENT_SETTINGS_NUM_TYPES,
+ Need_a_setting_for_every_content_settings_type);
std::string radio_allow_label;
+ const int* allowIDs = resources.empty() ?
+ kAllowIDs : kResourceSpecificAllowIDs;
radio_allow_label = l10n_util::GetStringFUTF8(
- kAllowIDs[content_type()], UTF8ToUTF16(display_host));
+ allowIDs[content_type()], UTF8ToUTF16(display_host));
static const int kBlockIDs[] = {
0, // We don't manage cookies here.
@@ -159,17 +229,80 @@ class ContentSettingSingleRadioGroup : public ContentSettingTitleAndLinkModel {
radio_group.radio_items.push_back(radio_allow_label);
radio_group.radio_items.push_back(radio_block_label);
- radio_group.default_item =
- profile()->GetHostContentSettingsMap()->GetContentSetting(url,
- content_type()) == CONTENT_SETTING_ALLOW ? 0 : 1;
+ HostContentSettingsMap* map = profile()->GetHostContentSettingsMap();
+ if (resources.empty()) {
+ ContentSetting setting = map->GetContentSetting(url, content_type(),
+ std::string());
+ radio_group.default_item = (setting == CONTENT_SETTING_ALLOW) ? 0 : 1;
+ } else {
+ // The default item is "block" if at least one of the resources
+ // is blocked.
+ radio_group.default_item = 0;
+ for (std::set<std::string>::const_iterator it = resources.begin();
+ it != resources.end(); ++it) {
+ ContentSetting setting = map->GetContentSetting(
+ url, content_type(), *it);
+ if (setting == CONTENT_SETTING_BLOCK) {
+ radio_group.default_item = 1;
+ break;
+ }
+ }
+ }
set_radio_group(radio_group);
}
- virtual void OnRadioClicked(int radio_index) {
+ void AddException(ContentSetting setting,
+ const std::string& resource_identifier) {
profile()->GetHostContentSettingsMap()->AddExceptionForURL(
- bubble_content().radio_group.url,
- content_type(),
- radio_index == 0 ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
+ bubble_content().radio_group.url, content_type(), resource_identifier,
+ setting);
+ }
+
+ virtual void OnRadioClicked(int radio_index) {
+ ContentSetting setting =
+ radio_index == 0 ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
+ const std::set<std::string>& resources =
+ bubble_content().resource_identifiers;
+ if (resources.empty()) {
+ AddException(setting, std::string());
+ } else {
+ for (std::set<std::string>::const_iterator it = resources.begin();
+ it != resources.end(); ++it) {
+ AddException(setting, *it);
+ }
+ }
+ }
+};
+
+class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup {
+ public:
+ ContentSettingPluginBubbleModel(TabContents* tab_contents, Profile* profile,
+ ContentSettingsType content_type)
+ : ContentSettingSingleRadioGroup(tab_contents, profile, content_type) {
+ DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS);
+ SetLoadPluginsLinkTitle();
+ }
+
+ private:
+ void SetLoadPluginsLinkTitle() {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableClickToPlay)) {
+ set_load_plugins_link_title(
+ l10n_util::GetStringUTF8(IDS_BLOCKED_PLUGINS_LOAD_ALL));
+ }
+ }
+
+ virtual void OnLoadPluginsLinkClicked() {
+ DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableClickToPlay));
+ 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);
}
};
@@ -183,8 +316,10 @@ class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
private:
void SetPopups() {
+ // check for crbug.com/53176
+ if (!tab_contents()->blocked_popup_container())
+ return;
BlockedPopupContainer::BlockedContents blocked_contents;
- DCHECK(tab_contents()->blocked_popup_container());
tab_contents()->blocked_popup_container()->GetBlockedContents(
&blocked_contents);
for (BlockedPopupContainer::BlockedContents::const_iterator
@@ -300,6 +435,10 @@ ContentSettingBubbleModel*
return new ContentSettingDomainListBubbleModel(tab_contents, profile,
content_type);
}
+ if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ return new ContentSettingPluginBubbleModel(tab_contents, profile,
+ content_type);
+ }
return new ContentSettingSingleRadioGroup(tab_contents, profile,
content_type);
}
@@ -309,6 +448,13 @@ ContentSettingBubbleModel::ContentSettingBubbleModel(
ContentSettingsType content_type)
: 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));
}
@@ -316,6 +462,11 @@ ContentSettingBubbleModel::ContentSettingBubbleModel(
ContentSettingBubbleModel::~ContentSettingBubbleModel() {
}
+void ContentSettingBubbleModel::AddBlockedResource(
+ const std::string& resource_identifier) {
+ bubble_content_.resource_identifiers.insert(resource_identifier);
+}
+
void ContentSettingBubbleModel::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/content_setting_bubble_model.h b/chrome/browser/content_setting_bubble_model.h
index a8aa744..97664d8 100644
--- a/chrome/browser/content_setting_bubble_model.h
+++ b/chrome/browser/content_setting_bubble_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CONTENT_SETTING_BUBBLE_MODEL_H_
#define CHROME_BROWSER_CONTENT_SETTING_BUBBLE_MODEL_H_
+#pragma once
#include <set>
#include <string>
@@ -57,9 +58,12 @@ class ContentSettingBubbleModel : public NotificationObserver {
PopupItems popup_items;
RadioGroup radio_group;
std::vector<DomainList> domain_lists;
+ std::set<std::string> resource_identifiers;
std::string manage_link;
std::string clear_link;
std::string info_link;
+ std::string load_plugins_link_title;
+ bool load_plugins_link_enabled;
};
const BubbleContent& bubble_content() const { return bubble_content_; }
@@ -74,6 +78,7 @@ class ContentSettingBubbleModel : public NotificationObserver {
virtual void OnManageLinkClicked() {}
virtual void OnClearLinkClicked() {}
virtual void OnInfoLinkClicked() {}
+ virtual void OnLoadPluginsLinkClicked() {}
protected:
ContentSettingBubbleModel(TabContents* tab_contents, Profile* profile,
@@ -101,6 +106,13 @@ class ContentSettingBubbleModel : public NotificationObserver {
void set_info_link(const std::string& link) {
bubble_content_.info_link = link;
}
+ 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 AddBlockedResource(const std::string& resource_identifier);
private:
TabContents* tab_contents_;
diff --git a/chrome/browser/content_setting_bubble_model_unittest.cc b/chrome/browser/content_setting_bubble_model_unittest.cc
index 5f96e49..d114e89 100644
--- a/chrome/browser/content_setting_bubble_model_unittest.cc
+++ b/chrome/browser/content_setting_bubble_model_unittest.cc
@@ -4,7 +4,9 @@
#include "chrome/browser/content_setting_bubble_model.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/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"
#include "chrome/test/testing_profile.h"
@@ -38,6 +40,7 @@ class ContentSettingBubbleModelTest : public RenderViewHostTestHarness {
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);
}
ChromeThread ui_thread_;
@@ -46,7 +49,8 @@ class ContentSettingBubbleModelTest : public RenderViewHostTestHarness {
TEST_F(ContentSettingBubbleModelTest, ImageRadios) {
TabSpecificContentSettings* content_settings =
contents()->GetTabSpecificContentSettings();
- content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES);
+ content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES,
+ std::string());
scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -58,12 +62,14 @@ TEST_F(ContentSettingBubbleModelTest, ImageRadios) {
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);
}
TEST_F(ContentSettingBubbleModelTest, Cookies) {
TabSpecificContentSettings* content_settings =
contents()->GetTabSpecificContentSettings();
- content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
+ content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES,
+ std::string());
scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -74,6 +80,25 @@ TEST_F(ContentSettingBubbleModelTest, Cookies) {
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);
+}
+
+TEST_F(ContentSettingBubbleModelTest, Plugins) {
+ TabSpecificContentSettings* content_settings =
+ contents()->GetTabSpecificContentSettings();
+ content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_PLUGINS,
+ std::string());
+
+ scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
+ ContentSettingBubbleModel::CreateContentSettingBubbleModel(
+ contents(), profile_.get(), CONTENT_SETTINGS_TYPE_PLUGINS));
+ const ContentSettingBubbleModel::BubbleContent& bubble_content =
+ content_setting_bubble_model->bubble_content();
+ 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);
}
TEST_F(ContentSettingBubbleModelTest, Geolocation) {
diff --git a/chrome/browser/content_setting_combo_model.cc b/chrome/browser/content_setting_combo_model.cc
index 678ea73..c1fabfc 100644
--- a/chrome/browser/content_setting_combo_model.cc
+++ b/chrome/browser/content_setting_combo_model.cc
@@ -5,6 +5,9 @@
#include "chrome/browser/content_setting_combo_model.h"
#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/string16.h"
+#include "chrome/common/chrome_switches.h"
#include "grit/generated_resources.h"
namespace {
@@ -28,22 +31,22 @@ ContentSettingComboModel::~ContentSettingComboModel() {
}
int ContentSettingComboModel::GetItemCount() {
- return show_session_ ?
- arraysize(kSessionSettings) : arraysize(kNoSessionSettings);
+ return show_session_ ? arraysize(kSessionSettings)
+ : arraysize(kNoSessionSettings);
}
-std::wstring ContentSettingComboModel::GetItemAt(int index) {
+string16 ContentSettingComboModel::GetItemAt(int index) {
switch (SettingForIndex(index)) {
case CONTENT_SETTING_ALLOW:
- return l10n_util::GetString(IDS_EXCEPTIONS_ALLOW_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_EXCEPTIONS_ALLOW_BUTTON);
case CONTENT_SETTING_BLOCK:
- return l10n_util::GetString(IDS_EXCEPTIONS_BLOCK_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_EXCEPTIONS_BLOCK_BUTTON);
case CONTENT_SETTING_SESSION_ONLY:
- return l10n_util::GetString(IDS_EXCEPTIONS_SESSION_ONLY_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_EXCEPTIONS_SESSION_ONLY_BUTTON);
default:
NOTREACHED();
}
- return std::wstring();
+ return string16();
}
ContentSetting ContentSettingComboModel::SettingForIndex(int index) {
diff --git a/chrome/browser/content_setting_combo_model.h b/chrome/browser/content_setting_combo_model.h
index 255f02a..6e9a740 100644
--- a/chrome/browser/content_setting_combo_model.h
+++ b/chrome/browser/content_setting_combo_model.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_CONTENT_SETTING_COMBO_MODEL_H_
#define CHROME_BROWSER_CONTENT_SETTING_COMBO_MODEL_H_
+#pragma once
#include "app/combobox_model.h"
#include "base/basictypes.h"
+#include "base/string16.h"
#include "chrome/common/content_settings.h"
class ContentSettingComboModel : public ComboboxModel {
@@ -16,8 +18,7 @@ class ContentSettingComboModel : public ComboboxModel {
virtual ~ContentSettingComboModel();
virtual int GetItemCount();
-
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
ContentSetting SettingForIndex(int index);
diff --git a/chrome/browser/content_setting_image_model.cc b/chrome/browser/content_setting_image_model.cc
index 26e349a..84d19cd 100644
--- a/chrome/browser/content_setting_image_model.cc
+++ b/chrome/browser/content_setting_image_model.cc
@@ -5,7 +5,11 @@
#include "chrome/browser/content_setting_image_model.h"
#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/tab_contents/tab_contents.h"
+#include "chrome/common/chrome_switches.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -17,8 +21,10 @@ class ContentSettingBlockedImageModel : public ContentSettingImageModel {
virtual void UpdateFromTabContents(const TabContents* tab_contents);
private:
+ static const int kAccessedIconIDs[];
static const int kBlockedIconIDs[];
- static const int kTooltipIDs[];
+ static const int kAccessedTooltipIDs[];
+ static const int kBlockedTooltipIDs[];
};
class ContentSettingGeolocationImageModel : public ContentSettingImageModel {
@@ -43,14 +49,29 @@ const int ContentSettingBlockedImageModel::kBlockedIconIDs[] = {
IDR_BLOCKED_POPUPS,
};
-const int ContentSettingBlockedImageModel::kTooltipIDs[] = {
- IDS_BLOCKED_COOKIES_TITLE,
- IDS_BLOCKED_IMAGES_TITLE,
- IDS_BLOCKED_JAVASCRIPT_TITLE,
- IDS_BLOCKED_PLUGINS_TITLE,
- IDS_BLOCKED_POPUPS_TOOLTIP,
+const int ContentSettingBlockedImageModel::kAccessedIconIDs[] = {
+ IDR_ACCESSED_COOKIES,
+ 0,
+ 0,
+ 0,
+ 0,
};
+const int ContentSettingBlockedImageModel::kBlockedTooltipIDs[] = {
+ IDS_BLOCKED_COOKIES_TITLE,
+ IDS_BLOCKED_IMAGES_TITLE,
+ IDS_BLOCKED_JAVASCRIPT_TITLE,
+ IDS_BLOCKED_PLUGINS_MESSAGE,
+ IDS_BLOCKED_POPUPS_TOOLTIP,
+};
+
+const int ContentSettingBlockedImageModel::kAccessedTooltipIDs[] = {
+ IDS_ACCESSED_COOKIES_TITLE,
+ 0,
+ 0,
+ 0,
+ 0,
+};
ContentSettingBlockedImageModel::ContentSettingBlockedImageModel(
ContentSettingsType content_settings_type)
@@ -61,14 +82,31 @@ void ContentSettingBlockedImageModel::UpdateFromTabContents(
const TabContents* tab_contents) {
TabSpecificContentSettings* content_settings = tab_contents ?
tab_contents->GetTabSpecificContentSettings() : NULL;
- if (!content_settings ||
- !content_settings->IsContentBlocked(get_content_settings_type())) {
+ const int* icon_ids;
+ const int* tooltip_ids;
+
+ if (!content_settings) {
+ set_visible(false);
+ return;
+ }
+ if (content_settings->IsContentBlocked(get_content_settings_type())) {
+ icon_ids = kBlockedIconIDs;
+ tooltip_ids = kBlockedTooltipIDs;
+ } else if (tab_contents->profile()->GetHostContentSettingsMap()->
+ GetDefaultContentSetting(get_content_settings_type()) ==
+ CONTENT_SETTING_BLOCK &&
+ content_settings->IsContentAccessed(get_content_settings_type())) {
+ // If a content type is blocked by default and was accessed, display the
+ // accessed icon.
+ icon_ids = kAccessedIconIDs;
+ tooltip_ids = kAccessedTooltipIDs;
+ } else {
set_visible(false);
return;
}
- set_icon(kBlockedIconIDs[get_content_settings_type()]);
+ set_icon(icon_ids[get_content_settings_type()]);
set_tooltip(
- l10n_util::GetStringUTF8(kTooltipIDs[get_content_settings_type()]));
+ l10n_util::GetStringUTF8(tooltip_ids[get_content_settings_type()]));
set_visible(true);
}
diff --git a/chrome/browser/content_setting_image_model.h b/chrome/browser/content_setting_image_model.h
index f5d5a66..2ea709a 100644
--- a/chrome/browser/content_setting_image_model.h
+++ b/chrome/browser/content_setting_image_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CONTENT_SETTING_IMAGE_MODEL_H_
#define CHROME_BROWSER_CONTENT_SETTING_IMAGE_MODEL_H_
+#pragma once
#include <string>
@@ -15,6 +16,8 @@ class TabContents;
// that are displayed in the location bar.
class ContentSettingImageModel {
public:
+ virtual ~ContentSettingImageModel() {}
+
// Factory function.
static ContentSettingImageModel* CreateContentSettingImageModel(
ContentSettingsType content_settings_type);
diff --git a/chrome/browser/content_setting_image_model_unittest.cc b/chrome/browser/content_setting_image_model_unittest.cc
index 02a5af3..f16ab93 100644
--- a/chrome/browser/content_setting_image_model_unittest.cc
+++ b/chrome/browser/content_setting_image_model_unittest.cc
@@ -4,13 +4,25 @@
#include "chrome/browser/content_setting_image_model.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/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"
#include "testing/gtest/include/gtest/gtest.h"
-typedef RenderViewHostTestHarness ContentSettingImageModelTest;
+class ContentSettingImageModelTest : public RenderViewHostTestHarness {
+ public:
+ ContentSettingImageModelTest()
+ : RenderViewHostTestHarness(),
+ ui_thread_(ChromeThread::UI, &message_loop_) {}
+
+ private:
+ ChromeThread ui_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSettingImageModelTest);
+};
TEST_F(ContentSettingImageModelTest, UpdateFromTabContents) {
TestTabContents tab_contents(profile_.get(), NULL);
@@ -21,12 +33,33 @@ TEST_F(ContentSettingImageModelTest, UpdateFromTabContents) {
CONTENT_SETTINGS_TYPE_IMAGES));
EXPECT_FALSE(content_setting_image_model->is_visible());
EXPECT_EQ(0, content_setting_image_model->get_icon());
- EXPECT_EQ("", content_setting_image_model->get_tooltip());
+ EXPECT_EQ(std::string(), content_setting_image_model->get_tooltip());
- content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES);
+ content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES,
+ std::string());
content_setting_image_model->UpdateFromTabContents(&tab_contents);
EXPECT_TRUE(content_setting_image_model->is_visible());
EXPECT_NE(0, content_setting_image_model->get_icon());
- EXPECT_NE("", content_setting_image_model->get_tooltip());
+ EXPECT_NE(std::string(), content_setting_image_model->get_tooltip());
+}
+
+TEST_F(ContentSettingImageModelTest, CookieAccessed) {
+ TestTabContents tab_contents(profile_.get(), NULL);
+ TabSpecificContentSettings* content_settings =
+ tab_contents.GetTabSpecificContentSettings();
+ profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+ scoped_ptr<ContentSettingImageModel> content_setting_image_model(
+ ContentSettingImageModel::CreateContentSettingImageModel(
+ CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_FALSE(content_setting_image_model->is_visible());
+ EXPECT_EQ(0, content_setting_image_model->get_icon());
+ EXPECT_EQ(std::string(), content_setting_image_model->get_tooltip());
+
+ content_settings->OnCookieAccessed(GURL("http://google.com"), "A=B", false);
+ content_setting_image_model->UpdateFromTabContents(&tab_contents);
+ EXPECT_TRUE(content_setting_image_model->is_visible());
+ EXPECT_NE(0, content_setting_image_model->get_icon());
+ EXPECT_NE(std::string(), content_setting_image_model->get_tooltip());
}
diff --git a/chrome/browser/cookie_modal_dialog.cc b/chrome/browser/cookie_modal_dialog.cc
deleted file mode 100644
index 011833b..0000000
--- a/chrome/browser/cookie_modal_dialog.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 "chrome/browser/cookie_modal_dialog.h"
-
-#include "app/message_box_flags.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/pref_names.h"
-
-// Cookies
-CookiePromptModalDialog::CookiePromptModalDialog(
- TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const std::string& cookie_line,
- CookiePromptModalDialogDelegate* delegate)
- : AppModalDialog(tab_contents, std::wstring()),
- host_content_settings_map_(host_content_settings_map),
- dialog_type_(DIALOG_TYPE_COOKIE),
- origin_(origin),
- cookie_line_(cookie_line),
- delegate_(delegate) {
-}
-
-// LocalStorage
-CookiePromptModalDialog::CookiePromptModalDialog(
- TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const string16& key,
- const string16& value,
- CookiePromptModalDialogDelegate* delegate)
- : AppModalDialog(tab_contents, std::wstring()),
- host_content_settings_map_(host_content_settings_map),
- dialog_type_(DIALOG_TYPE_LOCAL_STORAGE),
- origin_(origin),
- local_storage_key_(key),
- local_storage_value_(value),
- delegate_(delegate) {
-}
-
-// Database
-CookiePromptModalDialog::CookiePromptModalDialog(
- TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const string16& database_name,
- const string16& display_name,
- unsigned long estimated_size,
- CookiePromptModalDialogDelegate* delegate)
- : AppModalDialog(tab_contents, std::wstring()),
- host_content_settings_map_(host_content_settings_map),
- dialog_type_(DIALOG_TYPE_DATABASE),
- origin_(origin),
- database_name_(database_name),
- display_name_(display_name),
- estimated_size_(estimated_size),
- delegate_(delegate) {
-}
-
-// AppCache
-CookiePromptModalDialog::CookiePromptModalDialog(
- TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& appcache_manifest_url,
- CookiePromptModalDialogDelegate* delegate)
- : AppModalDialog(tab_contents, std::wstring()),
- host_content_settings_map_(host_content_settings_map),
- dialog_type_(DIALOG_TYPE_APPCACHE),
- origin_(appcache_manifest_url.GetOrigin()),
- appcache_manifest_url_(appcache_manifest_url),
- delegate_(delegate) {
-}
-
-CookiePromptModalDialog::~CookiePromptModalDialog() {
-}
-
-bool CookiePromptModalDialog::IsValid() {
- ContentSetting content_setting =
- host_content_settings_map_->GetContentSetting(
- origin_, CONTENT_SETTINGS_TYPE_COOKIES);
- if (content_setting != CONTENT_SETTING_ASK) {
- if (content_setting == CONTENT_SETTING_ALLOW) {
- AllowSiteData(false, false);
- } else if (content_setting == CONTENT_SETTING_SESSION_ONLY) {
- AllowSiteData(false, true);
- } else {
- DCHECK(content_setting == CONTENT_SETTING_BLOCK);
- BlockSiteData(false);
- }
- return false;
- }
- return !skip_this_dialog_;
-}
-
-void CookiePromptModalDialog::AllowSiteData(bool remember,
- bool session_expire) {
- if (remember) {
- // Make sure there is no entry that would override the pattern we are about
- // to insert for exactly this URL.
- host_content_settings_map_->SetContentSetting(
- HostContentSettingsMap::Pattern::FromURLNoWildcard(origin_),
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_DEFAULT);
- host_content_settings_map_->SetContentSetting(
- HostContentSettingsMap::Pattern::FromURL(origin_),
- CONTENT_SETTINGS_TYPE_COOKIES,
- session_expire ? CONTENT_SETTING_SESSION_ONLY : CONTENT_SETTING_ALLOW);
- }
-
- if (delegate_) {
- delegate_->AllowSiteData(session_expire);
- delegate_ = NULL; // It can be deleted at any point now.
- }
-}
-
-void CookiePromptModalDialog::BlockSiteData(bool remember) {
- if (remember) {
- // Make sure there is no entry that would override the pattern we are about
- // to insert for exactly this URL.
- host_content_settings_map_->SetContentSetting(
- HostContentSettingsMap::Pattern::FromURLNoWildcard(origin_),
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_DEFAULT);
- host_content_settings_map_->SetContentSetting(
- HostContentSettingsMap::Pattern::FromURL(origin_),
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
- }
-
- if (delegate_) {
- delegate_->BlockSiteData();
- delegate_ = NULL; // It can be deleted at any point now.
- }
-}
-
-// static
-void CookiePromptModalDialog::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterBooleanPref(prefs::kCookiePromptExpanded, false);
-}
-
-int CookiePromptModalDialog::GetDialogButtons() {
- // Enable the automation interface to accept/dismiss this dialog.
- return MessageBoxFlags::DIALOGBUTTON_OK |
- MessageBoxFlags::DIALOGBUTTON_CANCEL;
-}
diff --git a/chrome/browser/cookie_modal_dialog.h b/chrome/browser/cookie_modal_dialog.h
deleted file mode 100644
index 5308186..0000000
--- a/chrome/browser/cookie_modal_dialog.h
+++ /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 CHROME_BROWSER_COOKIE_MODAL_DIALOG_H_
-#define CHROME_BROWSER_COOKIE_MODAL_DIALOG_H_
-
-#include <string>
-
-#include "base/ref_counted.h"
-#include "chrome/browser/app_modal_dialog.h"
-#include "chrome/browser/browsing_data_local_storage_helper.h"
-#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h"
-#include "googleurl/src/gurl.h"
-
-#if defined(OS_LINUX)
-#include "app/gtk_signal.h"
-#endif
-
-#if defined(OS_MACOSX)
-#if __OBJC__
-@class NSWindow;
-#else
-class NSWindow;
-#endif
-#endif
-
-class HostContentSettingsMap;
-class PrefService;
-
-#if defined(OS_LINUX)
-typedef struct _GtkWidget GtkWidget;
-typedef struct _GParamSpec GParamSpec;
-#endif
-
-// A controller+model class for cookie and local storage warning prompt.
-// |NativeDialog| is a platform specific view.
-class CookiePromptModalDialog : public AppModalDialog {
- public:
- enum DialogType {
- DIALOG_TYPE_COOKIE = 0,
- DIALOG_TYPE_LOCAL_STORAGE,
- DIALOG_TYPE_DATABASE,
- DIALOG_TYPE_APPCACHE
- };
-
- // A union of data necessary to determine the type of message box to
- // show.
- CookiePromptModalDialog(TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const std::string& cookie_line,
- CookiePromptModalDialogDelegate* delegate);
- CookiePromptModalDialog(TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const string16& key,
- const string16& value,
- CookiePromptModalDialogDelegate* delegate);
- CookiePromptModalDialog(TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const string16& database_name,
- const string16& display_name,
- unsigned long estimated_size,
- CookiePromptModalDialogDelegate* delegate);
- CookiePromptModalDialog(TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& appcache_manifest_url,
- CookiePromptModalDialogDelegate* delegate);
- virtual ~CookiePromptModalDialog();
-
- static void RegisterUserPrefs(PrefService* prefs);
-
- // AppModalDialog overrides.
-#if defined(OS_LINUX) || defined(OS_MACOSX)
- virtual void CreateAndShowDialog();
-#endif
- virtual int GetDialogButtons();
- virtual void AcceptWindow();
- virtual void CancelWindow();
- virtual bool IsValid();
-
-#if defined(OS_MACOSX)
- virtual void CloseModalDialog();
-#endif
-
- DialogType dialog_type() const { return dialog_type_; }
- const GURL& origin() const { return origin_; }
- const std::string& cookie_line() const { return cookie_line_; }
- const string16& local_storage_key() const { return local_storage_key_; }
- const string16& local_storage_value() const { return local_storage_value_; }
- const string16& database_name() const { return database_name_; }
- const string16& display_name() const { return display_name_; }
- unsigned long estimated_size() const { return estimated_size_; }
- const GURL& appcache_manifest_url() const { return appcache_manifest_url_; }
- TabContents* tab_contents() const { return tab_contents_; }
-
- // Implement CookiePromptModalDialogDelegate.
- virtual void AllowSiteData(bool remember, bool session_expire);
- virtual void BlockSiteData(bool remember);
-
- protected:
- // AppModalDialog overrides.
- virtual NativeDialog CreateNativeDialog();
-#if defined(OS_LINUX)
- virtual void HandleDialogResponse(GtkDialog* dialog, gint response_id);
- CHROMEGTK_CALLBACK_1(CookiePromptModalDialog,
- void,
- OnExpanderActivate,
- GParamSpec*);
-#endif
-
- private:
-
-#if defined(OS_MACOSX)
- NSWindow* dialog_;
-#endif
-
- // Used to verify our request is still necessary and when the response should
- // persist.
- scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
-
- const DialogType dialog_type_;
-
- // The origin connected to this request.
- const GURL origin_;
-
- // Which data members are relevant depends on the dialog_type.
- const std::string cookie_line_;
- const string16 local_storage_key_;
- const string16 local_storage_value_;
- const string16 database_name_;
- const string16 display_name_;
- unsigned long estimated_size_;
- const GURL appcache_manifest_url_;
-
- // The caller should provide a delegate in order to receive results
- // from this delegate. Any time after calling one of these methods, the
- // delegate could be deleted
- CookiePromptModalDialogDelegate* delegate_;
-
-#if defined(OS_LINUX)
- // The "remember this choice" radio button in the dialog.
- GtkWidget* remember_radio_;
-
- // The cookie view; we keep this to querry the result combobox.
- GtkWidget* cookie_view_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(CookiePromptModalDialog);
-};
-
-#endif // CHROME_BROWSER_COOKIE_MODAL_DIALOG_H_
diff --git a/chrome/browser/cookie_modal_dialog_gtk.cc b/chrome/browser/cookie_modal_dialog_gtk.cc
deleted file mode 100644
index f00dc19..0000000
--- a/chrome/browser/cookie_modal_dialog_gtk.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 "chrome/browser/cookie_modal_dialog.h"
-
-#include "app/gtk_util.h"
-#include "app/l10n_util.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/gtk/gtk_chrome_cookie_view.h"
-#include "chrome/browser/gtk/gtk_chrome_link_button.h"
-#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/cookie_prompt_view.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-
-void CookiePromptModalDialog::CreateAndShowDialog() {
- dialog_ = CreateNativeDialog();
- gtk_util::ShowModalDialogWithMinLocalizedWidth(GTK_WIDGET(dialog_),
- IDS_ALERT_DIALOG_WIDTH_CHARS);
-}
-
-void CookiePromptModalDialog::AcceptWindow() {
- HandleDialogResponse(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
-}
-
-void CookiePromptModalDialog::CancelWindow() {
- HandleDialogResponse(GTK_DIALOG(dialog_), GTK_RESPONSE_REJECT);
-}
-
-NativeDialog CookiePromptModalDialog::CreateNativeDialog() {
- gtk_util::MakeAppModalWindowGroup();
-
- gfx::NativeWindow window = tab_contents_->GetMessageBoxRootWindow();
- CookiePromptModalDialog::DialogType type = dialog_type();
- NativeDialog dialog = gtk_dialog_new_with_buttons(
- l10n_util::GetStringFUTF8(
- type == CookiePromptModalDialog::DIALOG_TYPE_COOKIE ?
- IDS_COOKIE_ALERT_TITLE : IDS_DATA_ALERT_TITLE,
- UTF8ToUTF16(origin().host())).c_str(),
- window,
- static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
- l10n_util::GetStringUTF8(IDS_COOKIE_ALERT_BLOCK_BUTTON).c_str(),
- GTK_RESPONSE_REJECT,
- l10n_util::GetStringUTF8(IDS_COOKIE_ALERT_ALLOW_BUTTON).c_str(),
- GTK_RESPONSE_ACCEPT,
- NULL);
- gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
-
- GtkWidget* content_area = GTK_DIALOG(dialog)->vbox;
- gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing);
-
- string16 display_host = UTF8ToUTF16(origin().host());
- GtkWidget* label = gtk_util::LeftAlignMisc(gtk_label_new(
- l10n_util::GetStringFUTF8(
- type == CookiePromptModalDialog::DIALOG_TYPE_COOKIE ?
- IDS_COOKIE_ALERT_LABEL : IDS_DATA_ALERT_LABEL,
- display_host).c_str()));
- gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0);
-
- // Create a vbox for all the radio buttons so they aren't too far away from
- // each other.
- GtkWidget* radio_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
- remember_radio_ = gtk_radio_button_new_with_label(NULL,
- l10n_util::GetStringFUTF8(IDS_COOKIE_ALERT_REMEMBER_RADIO,
- display_host).c_str());
- gtk_box_pack_start(GTK_BOX(radio_box), remember_radio_, FALSE, FALSE, 0);
-
- GtkWidget* ask_radio = gtk_radio_button_new_with_label_from_widget(
- GTK_RADIO_BUTTON(remember_radio_),
- l10n_util::GetStringUTF8(IDS_COOKIE_ALERT_ASK_RADIO).c_str());
- gtk_box_pack_start(GTK_BOX(radio_box), ask_radio, FALSE, FALSE, 0);
-
- gtk_box_pack_start(GTK_BOX(content_area), radio_box, FALSE, FALSE, 0);
-
- GtkWidget* expander = gtk_expander_new(
- l10n_util::GetStringUTF8(IDS_COOKIE_SHOW_DETAILS_LABEL).c_str());
- gtk_expander_set_expanded(GTK_EXPANDER(expander),
- tab_contents_->profile()->GetPrefs()->
- GetBoolean(prefs::kCookiePromptExpanded));
- g_signal_connect(expander, "notify::expanded",
- G_CALLBACK(OnExpanderActivateThunk), this);
- cookie_view_ = gtk_chrome_cookie_view_new(TRUE);
- gtk_chrome_cookie_view_clear(GTK_CHROME_COOKIE_VIEW(cookie_view_));
- if (type == CookiePromptModalDialog::DIALOG_TYPE_COOKIE) {
- gtk_chrome_cookie_view_display_cookie_string(
- GTK_CHROME_COOKIE_VIEW(cookie_view_),
- origin(), cookie_line());
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_LOCAL_STORAGE) {
- gtk_chrome_cookie_view_display_local_storage_item(
- GTK_CHROME_COOKIE_VIEW(cookie_view_),
- origin().host(),
- local_storage_key(),
- local_storage_value());
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_DATABASE) {
- gtk_chrome_cookie_view_display_database_accessed(
- GTK_CHROME_COOKIE_VIEW(cookie_view_),
- origin().host(),
- database_name(),
- display_name(),
- estimated_size());
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) {
- gtk_chrome_cookie_view_display_appcache_created(
- GTK_CHROME_COOKIE_VIEW(cookie_view_),
- appcache_manifest_url());
- } else {
- NOTIMPLEMENTED();
- }
- gtk_container_add(GTK_CONTAINER(expander), cookie_view_);
-
- gtk_box_pack_end(GTK_BOX(content_area), GTK_WIDGET(expander),
- FALSE, FALSE, 0);
-
- gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
- g_signal_connect(dialog, "response",
- G_CALLBACK(AppModalDialog::OnDialogResponse),
- reinterpret_cast<AppModalDialog*>(this));
-
- return dialog;
-}
-
-void CookiePromptModalDialog::HandleDialogResponse(GtkDialog* dialog,
- gint response_id) {
- bool remember_radio = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(remember_radio_));
- if (response_id == GTK_RESPONSE_REJECT) {
- BlockSiteData(remember_radio);
- } else if (response_id == GTK_RESPONSE_ACCEPT) {
- bool expires = gtk_chrome_cookie_view_session_expires(
- GTK_CHROME_COOKIE_VIEW(cookie_view_));
- AllowSiteData(remember_radio, expires);
- } else {
- BlockSiteData(false);
- }
- gtk_widget_destroy(GTK_WIDGET(dialog));
-
- CompleteDialog();
-
- gtk_util::AppModalDismissedUngroupWindows();
- delete this;
-}
-
-void CookiePromptModalDialog::OnExpanderActivate(GtkWidget* expander,
- GParamSpec* property) {
- tab_contents_->profile()->GetPrefs()->
- SetBoolean(prefs::kCookiePromptExpanded,
- gtk_expander_get_expanded(GTK_EXPANDER(expander)));
-}
diff --git a/chrome/browser/cookie_modal_dialog_mac.mm b/chrome/browser/cookie_modal_dialog_mac.mm
deleted file mode 100644
index 35a54e0..0000000
--- a/chrome/browser/cookie_modal_dialog_mac.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/cookie_modal_dialog.h"
-#import "chrome/browser/cocoa/cookie_prompt_window_controller.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "app/l10n_util_mac.h"
-#import "base/cocoa_protocols_mac.h"
-#include "base/mac_util.h"
-#include "base/scoped_nsobject.h"
-#include "base/logging.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "grit/generated_resources.h"
-
-void CookiePromptModalDialog::CreateAndShowDialog() {
- scoped_nsobject<CookiePromptWindowController> controller(
- [[CookiePromptWindowController alloc] initWithDialog:this]);
- [controller.get() doModalDialog:this];
-
- // Other than JavaScriptAppModalDialog, the cross-platform part of this class
- // does not call |CompleteDialog()|, an explicit call is required.
- CompleteDialog();
- Cleanup();
- delete this;
-}
-
-// The functions below are used by the automation framework.
-
-void CookiePromptModalDialog::AcceptWindow() {
- NOTIMPLEMENTED();
-}
-
-void CookiePromptModalDialog::CancelWindow() {
- NOTIMPLEMENTED();
-}
-
-void CookiePromptModalDialog::CloseModalDialog() {
- dialog_ = nil;
-}
-
-// This is only used by the app-modal dialog machinery on windows.
-NativeDialog CookiePromptModalDialog::CreateNativeDialog() {
- NOTIMPLEMENTED();
- return nil;
-}
diff --git a/chrome/browser/cookie_modal_dialog_uitest.cc b/chrome/browser/cookie_modal_dialog_uitest.cc
deleted file mode 100644
index 1c85bed..0000000
--- a/chrome/browser/cookie_modal_dialog_uitest.cc
+++ /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.
-
-#include "chrome/browser/net/url_request_mock_http_job.h"
-#include "chrome/test/automation/tab_proxy.h"
-#include "chrome/test/ui/ui_test.h"
-
-class CookieModalDialogTest : public UITest {
- public:
- void RunBasicTest(MessageBoxFlags::DialogButton button_to_press,
- const std::wstring& expected_title) {
- scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
- ASSERT_TRUE(browser);
-
- ASSERT_TRUE(browser->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
- CONTENT_SETTING_ASK));
-
- GURL url(URLRequestMockHTTPJob::GetMockUrl(
- FilePath(FILE_PATH_LITERAL("cookie2.html"))));
-
- scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
- ASSERT_TRUE(tab_proxy);
-
- int64 last_navigation_time;
- ASSERT_TRUE(tab_proxy->GetLastNavigationTime(&last_navigation_time));
- ASSERT_TRUE(tab_proxy->NavigateToURLAsync(url));
-
- // cookie2.html sets a cookie and then reads back the cookie within onload,
- // which means that the navigation will not complete until the cookie
- // prompt is dismissed.
-
- bool modal_dialog_showing = false;
- MessageBoxFlags::DialogButton available_buttons;
- ASSERT_TRUE(automation()->WaitForAppModalDialog());
- ASSERT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing,
- &available_buttons));
- ASSERT_TRUE(modal_dialog_showing);
- ASSERT_NE((button_to_press & available_buttons), 0);
- ASSERT_TRUE(automation()->ClickAppModalDialogButton(button_to_press));
-
- // Now, the cookie prompt is dismissed, and we can wait for the navigation
- // to complete. Before returning from onload, the test updates the title.
- // We can therefore be sure that upon return from WaitForNavigation that
- // the title has been updated with the final test result.
-
- ASSERT_TRUE(tab_proxy->WaitForNavigation(last_navigation_time));
-
- std::wstring title;
- ASSERT_TRUE(tab_proxy->GetTabTitle(&title));
-
- EXPECT_EQ(expected_title, title);
- }
-};
-
-// TODO(port): Enable these once the cookie dialogs are fully implemented.
-#if defined(OS_WIN)
-TEST_F(CookieModalDialogTest, AllowCookies) {
- RunBasicTest(MessageBoxFlags::DIALOGBUTTON_OK, L"cookie allowed");
-}
-
-TEST_F(CookieModalDialogTest, BlockCookies) {
- RunBasicTest(MessageBoxFlags::DIALOGBUTTON_CANCEL, L"cookie blocked");
-}
-#endif
diff --git a/chrome/browser/cookie_modal_dialog_views.cc b/chrome/browser/cookie_modal_dialog_views.cc
deleted file mode 100644
index 94c3f6f..0000000
--- a/chrome/browser/cookie_modal_dialog_views.cc
+++ /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.
-
-#include "chrome/browser/cookie_modal_dialog.h"
-
-#include "base/logging.h"
-#include "chrome/browser/views/cookie_prompt_view.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "views/window/window.h"
-
-
-// TODO(zelidrag): Make this work on Linux (views).
-
-void CookiePromptModalDialog::AcceptWindow() {
-#if defined(OS_WIN)
- views::DialogClientView* client_view =
- dialog_->window()->GetClientView()->AsDialogClientView();
- client_view->AcceptWindow();
-#endif
-}
-
-void CookiePromptModalDialog::CancelWindow() {
-#if defined(OS_WIN)
- views::DialogClientView* client_view =
- dialog_->window()->GetClientView()->AsDialogClientView();
- client_view->CancelWindow();
-#endif
-}
-
-
-NativeDialog CookiePromptModalDialog::CreateNativeDialog() {
-#if defined(OS_WIN)
- return new CookiePromptView(this,
- tab_contents_->GetMessageBoxRootWindow(),
- tab_contents_->profile());
-#else
- NOTIMPLEMENTED();
- return NULL;
-#endif
-}
diff --git a/chrome/browser/cookie_prompt_modal_dialog_delegate.h b/chrome/browser/cookie_prompt_modal_dialog_delegate.h
deleted file mode 100644
index 3708c05..0000000
--- a/chrome/browser/cookie_prompt_modal_dialog_delegate.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_COOKIE_PROMPT_MODAL_DIALOG_DELEGATE_H_
-#define CHROME_BROWSER_COOKIE_PROMPT_MODAL_DIALOG_DELEGATE_H_
-
-// Delegate for handling modal dialog results from CookiePromptModalDialog.
-// The implementer of this MUST guarentee that from the time it's passed to the
-// CookieModalDialog until one of these methods are called it will not be
-// deleted.
-class CookiePromptModalDialogDelegate {
- public:
- // Allow site data to be set.
- virtual void AllowSiteData(bool session_expire) = 0;
-
- // Block site data from being stored.
- virtual void BlockSiteData() = 0;
-
- protected:
- virtual ~CookiePromptModalDialogDelegate() {}
-};
-
-#endif // CHROME_BROWSER_COOKIE_PROMPT_MODAL_DIALOG_DELEGATE_H_
-
diff --git a/chrome/browser/cookies_tree_model.cc b/chrome/browser/cookies_tree_model.cc
index d4d577b..2fbd557 100644
--- a/chrome/browser/cookies_tree_model.cc
+++ b/chrome/browser/cookies_tree_model.cc
@@ -10,12 +10,10 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "app/table_model_observer.h"
-#include "app/tree_node_model.h"
#include "base/callback.h"
-#include "base/i18n/rtl.h"
#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/in_process_webkit/webkit_context.h"
#include "grit/app_resources.h"
@@ -49,7 +47,7 @@ CookiesTreeModel* CookieTreeNode::GetModel() const {
CookieTreeCookieNode::CookieTreeCookieNode(
net::CookieMonster::CanonicalCookie* cookie)
- : CookieTreeNode(UTF8ToWide(cookie->Name())),
+ : CookieTreeNode(UTF8ToUTF16(cookie->Name())),
cookie_(cookie) {
}
@@ -61,8 +59,7 @@ void CookieTreeCookieNode::DeleteStoredObjects() {
// vector storing the cookies in-tact and not delete from there (that would
// invalidate our pointers), and the fact that it contains semi out-of-date
// data is not problematic as we don't re-build the model based on that.
- GetModel()->cookie_monster_->
- DeleteCookie(cookie_->Domain(), *cookie_, true);
+ GetModel()->cookie_monster_->DeleteCanonicalCookie(*cookie_);
}
namespace {
@@ -75,8 +72,8 @@ class OriginNodeComparator {
// google.com, ad.google.com, www.google.com,
// microsoft.com, ad.microsoft.com. CanonicalizeHost transforms the origins
// into a form like google.com.www so that string comparisons work.
- return (CanonicalizeHost(lhs->GetTitleAsString16()) <
- CanonicalizeHost(rhs->GetTitleAsString16()));
+ return (CanonicalizeHost(lhs->GetTitle()) <
+ CanonicalizeHost(rhs->GetTitle()));
}
private:
@@ -129,7 +126,7 @@ class OriginNodeComparator {
CookieTreeAppCacheNode::CookieTreeAppCacheNode(
const appcache::AppCacheInfo* appcache_info)
- : CookieTreeNode(UTF8ToWide(appcache_info->manifest_url.spec())),
+ : CookieTreeNode(UTF8ToUTF16(appcache_info->manifest_url.spec())),
appcache_info_(appcache_info) {
}
@@ -145,8 +142,8 @@ void CookieTreeAppCacheNode::DeleteStoredObjects() {
CookieTreeDatabaseNode::CookieTreeDatabaseNode(
BrowsingDataDatabaseHelper::DatabaseInfo* database_info)
: CookieTreeNode(database_info->database_name.empty() ?
- l10n_util::GetString(IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME) :
- UTF8ToWide(database_info->database_name)),
+ l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME) :
+ UTF8ToUTF16(database_info->database_name)),
database_info_(database_info) {
}
@@ -160,7 +157,7 @@ void CookieTreeDatabaseNode::DeleteStoredObjects() {
CookieTreeLocalStorageNode::CookieTreeLocalStorageNode(
BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info)
- : CookieTreeNode(UTF8ToWide(
+ : CookieTreeNode(UTF8ToUTF16(
local_storage_info->origin.empty() ?
local_storage_info->database_identifier :
local_storage_info->origin)),
@@ -173,6 +170,34 @@ void CookieTreeLocalStorageNode::DeleteStoredObjects() {
}
///////////////////////////////////////////////////////////////////////////////
+// CookieTreeSessionStorageNode, public:
+
+CookieTreeSessionStorageNode::CookieTreeSessionStorageNode(
+ BrowsingDataLocalStorageHelper::LocalStorageInfo* session_storage_info)
+ : CookieTreeNode(UTF8ToUTF16(
+ session_storage_info->origin.empty() ?
+ session_storage_info->database_identifier :
+ session_storage_info->origin)),
+ session_storage_info_(session_storage_info) {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CookieTreeIndexedDBNode, public:
+
+CookieTreeIndexedDBNode::CookieTreeIndexedDBNode(
+ BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info)
+ : CookieTreeNode(indexed_db_info->database_name.empty() ?
+ l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME) :
+ UTF8ToUTF16(indexed_db_info->database_name)),
+ indexed_db_info_(indexed_db_info) {
+}
+
+void CookieTreeIndexedDBNode::DeleteStoredObjects() {
+ GetModel()->indexed_db_helper_->DeleteIndexedDBFile(
+ indexed_db_info_->file_path);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// CookieTreeRootNode, public:
CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode(
@@ -187,7 +212,7 @@ CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode(
OriginNodeComparator());
if (origin_node_iterator != children().end() &&
- CookieTreeOriginNode::TitleForUrl(url) ==
+ WideToUTF16Hack(CookieTreeOriginNode::TitleForUrl(url)) ==
(*origin_node_iterator)->GetTitle())
return static_cast<CookieTreeOriginNode*>(*origin_node_iterator);
// Node doesn't exist, create a new one and insert it into the (ordered)
@@ -208,11 +233,13 @@ std::wstring CookieTreeOriginNode::TitleForUrl(
}
CookieTreeOriginNode::CookieTreeOriginNode(const GURL& url)
- : CookieTreeNode(TitleForUrl(url)),
+ : CookieTreeNode(WideToUTF16Hack(TitleForUrl(url))),
cookies_child_(NULL),
databases_child_(NULL),
local_storages_child_(NULL),
+ session_storages_child_(NULL),
appcaches_child_(NULL),
+ indexed_dbs_child_(NULL),
url_(url) {}
@@ -241,6 +268,15 @@ CookieTreeLocalStoragesNode*
return local_storages_child_;
}
+CookieTreeSessionStoragesNode*
+ CookieTreeOriginNode::GetOrCreateSessionStoragesNode() {
+ if (session_storages_child_)
+ return session_storages_child_;
+ session_storages_child_ = new CookieTreeSessionStoragesNode;
+ AddChildSortedByTitle(session_storages_child_);
+ return session_storages_child_;
+}
+
CookieTreeAppCachesNode* CookieTreeOriginNode::GetOrCreateAppCachesNode() {
if (appcaches_child_)
return appcaches_child_;
@@ -249,11 +285,20 @@ CookieTreeAppCachesNode* CookieTreeOriginNode::GetOrCreateAppCachesNode() {
return appcaches_child_;
}
+CookieTreeIndexedDBsNode* CookieTreeOriginNode::GetOrCreateIndexedDBsNode() {
+ if (indexed_dbs_child_)
+ return indexed_dbs_child_;
+ indexed_dbs_child_ = new CookieTreeIndexedDBsNode;
+ AddChildSortedByTitle(indexed_dbs_child_);
+ return indexed_dbs_child_;
+}
+
void CookieTreeOriginNode::CreateContentException(
HostContentSettingsMap* content_settings, ContentSetting setting) const {
if (CanCreateContentException()) {
content_settings->AddExceptionForURL(url_,
CONTENT_SETTINGS_TYPE_COOKIES,
+ "",
setting);
}
}
@@ -266,28 +311,43 @@ bool CookieTreeOriginNode::CanCreateContentException() const {
// CookieTreeCookiesNode, public:
CookieTreeCookiesNode::CookieTreeCookiesNode()
- : CookieTreeNode(l10n_util::GetString(IDS_COOKIES_COOKIES)) {
+ : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
}
///////////////////////////////////////////////////////////////////////////////
// CookieTreeAppCachesNode, public:
CookieTreeAppCachesNode::CookieTreeAppCachesNode()
- : CookieTreeNode(l10n_util::GetString(IDS_COOKIES_APPLICATION_CACHES)) {
+ : CookieTreeNode(l10n_util::GetStringUTF16(
+ IDS_COOKIES_APPLICATION_CACHES)) {
}
///////////////////////////////////////////////////////////////////////////////
// CookieTreeDatabasesNode, public:
CookieTreeDatabasesNode::CookieTreeDatabasesNode()
- : CookieTreeNode(l10n_util::GetString(IDS_COOKIES_WEB_DATABASES)) {
+ : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
}
///////////////////////////////////////////////////////////////////////////////
// CookieTreeLocalStoragesNode, public:
CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
- : CookieTreeNode(l10n_util::GetString(IDS_COOKIES_LOCAL_STORAGE)) {
+ : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CookieTreeSessionStoragesNode, public:
+
+CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
+ : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CookieTreeIndexedDBsNode, public:
+
+CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
+ : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DB)) {
}
///////////////////////////////////////////////////////////////////////////////
@@ -299,7 +359,7 @@ bool CookieTreeNode::NodeTitleComparator::operator() (
static_cast<const CookieTreeNode*>(lhs);
const CookieTreeNode* right =
static_cast<const CookieTreeNode*>(rhs);
- return (left->GetTitleAsString16() < right->GetTitleAsString16());
+ return (left->GetTitle() < right->GetTitle());
}
void CookieTreeNode::AddChildSortedByTitle(CookieTreeNode* new_child) {
@@ -318,13 +378,17 @@ CookiesTreeModel::CookiesTreeModel(
net::CookieMonster* cookie_monster,
BrowsingDataDatabaseHelper* database_helper,
BrowsingDataLocalStorageHelper* local_storage_helper,
- BrowsingDataAppCacheHelper* appcache_helper)
+ BrowsingDataLocalStorageHelper* session_storage_helper,
+ BrowsingDataAppCacheHelper* appcache_helper,
+ BrowsingDataIndexedDBHelper* indexed_db_helper)
: ALLOW_THIS_IN_INITIALIZER_LIST(TreeNodeModel<CookieTreeNode>(
new CookieTreeRootNode(this))),
cookie_monster_(cookie_monster),
appcache_helper_(appcache_helper),
database_helper_(database_helper),
local_storage_helper_(local_storage_helper),
+ session_storage_helper_(session_storage_helper),
+ indexed_db_helper_(indexed_db_helper),
batch_update_(0) {
LoadCookies();
DCHECK(database_helper_);
@@ -332,7 +396,11 @@ CookiesTreeModel::CookiesTreeModel(
this, &CookiesTreeModel::OnDatabaseModelInfoLoaded));
DCHECK(local_storage_helper_);
local_storage_helper_->StartFetching(NewCallback(
- this, &CookiesTreeModel::OnStorageModelInfoLoaded));
+ this, &CookiesTreeModel::OnLocalStorageModelInfoLoaded));
+ if (session_storage_helper_) {
+ session_storage_helper_->StartFetching(NewCallback(
+ this, &CookiesTreeModel::OnSessionStorageModelInfoLoaded));
+ }
// TODO(michaeln): when all of the ui impls have been updated,
// make this a required parameter.
@@ -340,13 +408,22 @@ CookiesTreeModel::CookiesTreeModel(
appcache_helper_->StartFetching(NewCallback(
this, &CookiesTreeModel::OnAppCacheModelInfoLoaded));
}
+
+ if (indexed_db_helper_) {
+ indexed_db_helper_->StartFetching(NewCallback(
+ this, &CookiesTreeModel::OnIndexedDBModelInfoLoaded));
+ }
}
CookiesTreeModel::~CookiesTreeModel() {
database_helper_->CancelNotification();
local_storage_helper_->CancelNotification();
+ if (session_storage_helper_)
+ session_storage_helper_->CancelNotification();
if (appcache_helper_)
appcache_helper_->CancelNotification();
+ if (indexed_db_helper_)
+ indexed_db_helper_->CancelNotification();
}
///////////////////////////////////////////////////////////////////////////////
@@ -382,9 +459,15 @@ int CookiesTreeModel::GetIconIndex(TreeModelNode* node) {
case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
return DATABASE; // close enough
break;
+ case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
+ return DATABASE; // ditto
+ break;
case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
return DATABASE; // ditto
break;
+ case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
+ return DATABASE; // ditto
+ break;
default:
return -1;
}
@@ -452,7 +535,9 @@ void CookiesTreeModel::UpdateSearchResults(const std::wstring& filter) {
LoadCookiesWithFilter(filter);
PopulateDatabaseInfoWithFilter(filter);
PopulateLocalStorageInfoWithFilter(filter);
+ PopulateSessionStorageInfoWithFilter(filter);
PopulateAppCacheInfoWithFilter(filter);
+ PopulateIndexedDBInfoWithFilter(filter);
NotifyObserverTreeNodeChanged(root);
NotifyObserverEndBatch();
}
@@ -539,7 +624,7 @@ void CookiesTreeModel::PopulateDatabaseInfoWithFilter(
NotifyObserverEndBatch();
}
-void CookiesTreeModel::OnStorageModelInfoLoaded(
+void CookiesTreeModel::OnLocalStorageModelInfoLoaded(
const LocalStorageInfoList& local_storage_info) {
local_storage_info_list_ = local_storage_info;
PopulateLocalStorageInfoWithFilter(std::wstring());
@@ -572,6 +657,72 @@ void CookiesTreeModel::PopulateLocalStorageInfoWithFilter(
NotifyObserverEndBatch();
}
+void CookiesTreeModel::OnSessionStorageModelInfoLoaded(
+ const LocalStorageInfoList& session_storage_info) {
+ session_storage_info_list_ = session_storage_info;
+ PopulateSessionStorageInfoWithFilter(std::wstring());
+}
+
+void CookiesTreeModel::PopulateSessionStorageInfoWithFilter(
+ const std::wstring& filter) {
+ if (session_storage_info_list_.empty())
+ return;
+ CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
+ NotifyObserverBeginBatch();
+ for (LocalStorageInfoList::iterator session_storage_info =
+ session_storage_info_list_.begin();
+ session_storage_info != session_storage_info_list_.end();
+ ++session_storage_info) {
+ GURL origin(session_storage_info->origin);
+
+ if (!filter.size() ||
+ (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
+ std::wstring::npos)) {
+ CookieTreeOriginNode* origin_node =
+ root->GetOrCreateOriginNode(origin);
+ CookieTreeSessionStoragesNode* session_storages_node =
+ origin_node->GetOrCreateSessionStoragesNode();
+ session_storages_node->AddSessionStorageNode(
+ new CookieTreeSessionStorageNode(&(*session_storage_info)));
+ }
+ }
+ NotifyObserverTreeNodeChanged(root);
+ NotifyObserverEndBatch();
+}
+
+void CookiesTreeModel::OnIndexedDBModelInfoLoaded(
+ const IndexedDBInfoList& indexed_db_info) {
+ indexed_db_info_list_ = indexed_db_info;
+ PopulateIndexedDBInfoWithFilter(std::wstring());
+}
+
+void CookiesTreeModel::PopulateIndexedDBInfoWithFilter(
+ const std::wstring& filter) {
+ if (indexed_db_info_list_.empty())
+ return;
+ CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
+ NotifyObserverBeginBatch();
+ for (IndexedDBInfoList::iterator indexed_db_info =
+ indexed_db_info_list_.begin();
+ indexed_db_info != indexed_db_info_list_.end();
+ ++indexed_db_info) {
+ GURL origin(indexed_db_info->origin);
+
+ if (!filter.size() ||
+ (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
+ std::wstring::npos)) {
+ CookieTreeOriginNode* origin_node =
+ root->GetOrCreateOriginNode(origin);
+ CookieTreeIndexedDBsNode* indexed_dbs_node =
+ origin_node->GetOrCreateIndexedDBsNode();
+ indexed_dbs_node->AddIndexedDBNode(
+ new CookieTreeIndexedDBNode(&(*indexed_db_info)));
+ }
+ }
+ NotifyObserverTreeNodeChanged(root);
+ NotifyObserverEndBatch();
+}
+
void CookiesTreeModel::NotifyObserverBeginBatch() {
// Only notify the model once if we're batching in a nested manner.
if (batch_update_++ == 0) {
diff --git a/chrome/browser/cookies_tree_model.h b/chrome/browser/cookies_tree_model.h
index 435b532..509084a 100644
--- a/chrome/browser/cookies_tree_model.h
+++ b/chrome/browser/cookies_tree_model.h
@@ -4,15 +4,22 @@
#ifndef CHROME_BROWSER_COOKIES_TREE_MODEL_H_
#define CHROME_BROWSER_COOKIES_TREE_MODEL_H_
+#pragma once
+
+// TODO(viettrungluu): This header file #includes far too much and has too much
+// inline code (which shouldn't be inline).
#include <string>
#include <vector>
#include "app/tree_node_model.h"
#include "base/observer_list.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browsing_data_appcache_helper.h"
#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 "net/base/cookie_monster.h"
@@ -25,6 +32,10 @@ class CookieTreeDatabaseNode;
class CookieTreeDatabasesNode;
class CookieTreeLocalStorageNode;
class CookieTreeLocalStoragesNode;
+class CookieTreeSessionStorageNode;
+class CookieTreeSessionStoragesNode;
+class CookieTreeIndexedDBNode;
+class CookieTreeIndexedDBsNode;
class CookieTreeOriginNode;
// CookieTreeNode -------------------------------------------------------------
@@ -47,37 +58,79 @@ class CookieTreeNode : public TreeNode<CookieTreeNode> {
TYPE_DATABASE, // This is used for CookieTreeDatabaseNode.
TYPE_LOCAL_STORAGES, // This is used for CookieTreeLocalStoragesNode.
TYPE_LOCAL_STORAGE, // This is used for CookieTreeLocalStorageNode.
+ TYPE_SESSION_STORAGES, // This is used for CookieTreeSessionStoragesNode.
+ TYPE_SESSION_STORAGE, // This is used for CookieTreeSessionStorageNode.
TYPE_APPCACHES, // This is used for CookieTreeAppCachesNode.
TYPE_APPCACHE, // This is used for CookieTreeAppCacheNode.
+ TYPE_INDEXED_DBS, // This is used for CookieTreeIndexedDBsNode.
+ TYPE_INDEXED_DB, // This is used for CookieTreeIndexedDBNode.
};
+ // TODO(viettrungluu): Figure out whether we want to store |origin| as a
+ // |string16| or a (UTF-8) |std::string|, and convert. Remove constructor
+ // taking an |std::wstring|.
+ DetailedInfo(const string16& origin, NodeType node_type,
+ const net::CookieMonster::CanonicalCookie* cookie,
+ const BrowsingDataDatabaseHelper::DatabaseInfo* database_info,
+ const BrowsingDataLocalStorageHelper::LocalStorageInfo*
+ local_storage_info,
+ const BrowsingDataLocalStorageHelper::LocalStorageInfo*
+ session_storage_info,
+ const appcache::AppCacheInfo* appcache_info,
+ const BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info)
+ : origin(UTF16ToWideHack(origin)),
+ node_type(node_type),
+ cookie(cookie),
+ database_info(database_info),
+ local_storage_info(local_storage_info),
+ session_storage_info(session_storage_info),
+ appcache_info(appcache_info),
+ indexed_db_info(indexed_db_info) {
+ DCHECK((node_type != TYPE_DATABASE) || database_info);
+ DCHECK((node_type != TYPE_LOCAL_STORAGE) || local_storage_info);
+ DCHECK((node_type != TYPE_SESSION_STORAGE) || session_storage_info);
+ DCHECK((node_type != TYPE_APPCACHE) || appcache_info);
+ DCHECK((node_type != TYPE_INDEXED_DB) || indexed_db_info);
+ }
+#if !defined(WCHAR_T_IS_UTF16)
DetailedInfo(const std::wstring& origin, NodeType node_type,
const net::CookieMonster::CanonicalCookie* cookie,
const BrowsingDataDatabaseHelper::DatabaseInfo* database_info,
const BrowsingDataLocalStorageHelper::LocalStorageInfo*
local_storage_info,
- const appcache::AppCacheInfo* appcache_info)
+ const BrowsingDataLocalStorageHelper::LocalStorageInfo*
+ session_storage_info,
+ const appcache::AppCacheInfo* appcache_info,
+ const BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info)
: origin(origin),
node_type(node_type),
cookie(cookie),
database_info(database_info),
local_storage_info(local_storage_info),
- appcache_info(appcache_info) {
+ session_storage_info(session_storage_info),
+ appcache_info(appcache_info),
+ indexed_db_info(indexed_db_info) {
DCHECK((node_type != TYPE_DATABASE) || database_info);
DCHECK((node_type != TYPE_LOCAL_STORAGE) || local_storage_info);
+ DCHECK((node_type != TYPE_SESSION_STORAGE) || session_storage_info);
DCHECK((node_type != TYPE_APPCACHE) || appcache_info);
+ DCHECK((node_type != TYPE_INDEXED_DB) || indexed_db_info);
}
+#endif
std::wstring origin;
NodeType node_type;
const net::CookieMonster::CanonicalCookie* cookie;
const BrowsingDataDatabaseHelper::DatabaseInfo* database_info;
const BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info;
+ const BrowsingDataLocalStorageHelper::LocalStorageInfo*
+ session_storage_info;
const appcache::AppCacheInfo* appcache_info;
+ const BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info;
};
CookieTreeNode() {}
- explicit CookieTreeNode(const std::wstring& title)
+ explicit CookieTreeNode(const string16& title)
: TreeNode<CookieTreeNode>(title) {}
virtual ~CookieTreeNode() {}
@@ -117,8 +170,9 @@ class CookieTreeRootNode : public CookieTreeNode {
// CookieTreeNode methods:
virtual CookiesTreeModel* GetModel() const { return model_; }
virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(std::wstring(), DetailedInfo::TYPE_ROOT, NULL, NULL,
- NULL, NULL);
+ return DetailedInfo(string16(),
+ DetailedInfo::TYPE_ROOT,
+ NULL, NULL, NULL, NULL, NULL, NULL);
}
private:
@@ -138,15 +192,18 @@ class CookieTreeOriginNode : public CookieTreeNode {
// CookieTreeNode methods:
virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetTitle(), DetailedInfo::TYPE_ORIGIN, NULL, NULL,
- NULL, NULL);
+ return DetailedInfo(GetTitle(),
+ DetailedInfo::TYPE_ORIGIN,
+ NULL, NULL, NULL, NULL, NULL, NULL);
}
// CookieTreeOriginNode methods:
CookieTreeCookiesNode* GetOrCreateCookiesNode();
CookieTreeDatabasesNode* GetOrCreateDatabasesNode();
CookieTreeLocalStoragesNode* GetOrCreateLocalStoragesNode();
+ CookieTreeSessionStoragesNode* GetOrCreateSessionStoragesNode();
CookieTreeAppCachesNode* GetOrCreateAppCachesNode();
+ CookieTreeIndexedDBsNode* GetOrCreateIndexedDBsNode();
// Creates an content exception for this origin of type
// CONTENT_SETTINGS_TYPE_COOKIES.
@@ -157,15 +214,17 @@ class CookieTreeOriginNode : public CookieTreeNode {
bool CanCreateContentException() const;
private:
- // Pointers to the cookies, databases, local storage and appcache nodes.
- // When we build up the tree we need to quickly get a reference to the COOKIES
- // node to add children. Checking each child and interrogating them to see if
- // they are a COOKIES, APPCACHES, DATABASES etc node seems less preferable
- // than storing an extra pointer per origin.
+ // Pointers to the cookies, databases, local and session storage and appcache
+ // nodes. When we build up the tree we need to quickly get a reference to
+ // the COOKIES node to add children. Checking each child and interrogating
+ // them to see if they are a COOKIES, APPCACHES, DATABASES etc node seems
+ // less preferable than storing an extra pointer per origin.
CookieTreeCookiesNode* cookies_child_;
CookieTreeDatabasesNode* databases_child_;
CookieTreeLocalStoragesNode* local_storages_child_;
+ CookieTreeSessionStoragesNode* session_storages_child_;
CookieTreeAppCachesNode* appcaches_child_;
+ CookieTreeIndexedDBsNode* indexed_dbs_child_;
// The URL for which this node was initially created.
GURL url_;
@@ -187,7 +246,8 @@ class CookieTreeCookieNode : public CookieTreeNode {
virtual void DeleteStoredObjects();
virtual DetailedInfo GetDetailedInfo() const {
return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_COOKIE, cookie_, NULL, NULL, NULL);
+ DetailedInfo::TYPE_COOKIE,
+ cookie_, NULL, NULL, NULL, NULL, NULL);
}
private:
@@ -204,8 +264,9 @@ class CookieTreeCookiesNode : public CookieTreeNode {
virtual ~CookieTreeCookiesNode() {}
virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetTitle(), DetailedInfo::TYPE_COOKIES,
- NULL, NULL, NULL, NULL);
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_COOKIES,
+ NULL, NULL, NULL, NULL, NULL, NULL);
}
void AddCookieNode(CookieTreeCookieNode* child) {
@@ -231,7 +292,7 @@ class CookieTreeAppCacheNode : public CookieTreeNode {
virtual DetailedInfo GetDetailedInfo() const {
return DetailedInfo(GetParent()->GetParent()->GetTitle(),
DetailedInfo::TYPE_APPCACHE,
- NULL, NULL, NULL, appcache_info_);
+ NULL, NULL, NULL, NULL, appcache_info_, NULL);
}
private:
@@ -247,7 +308,7 @@ class CookieTreeAppCachesNode : public CookieTreeNode {
virtual DetailedInfo GetDetailedInfo() const {
return DetailedInfo(GetParent()->GetTitle(),
DetailedInfo::TYPE_APPCACHES,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, NULL, NULL);
}
void AddAppCacheNode(CookieTreeAppCacheNode* child) {
@@ -272,8 +333,8 @@ class CookieTreeDatabaseNode : public CookieTreeNode {
virtual void DeleteStoredObjects();
virtual DetailedInfo GetDetailedInfo() const {
return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_DATABASE, NULL, database_info_,
- NULL, NULL);
+ DetailedInfo::TYPE_DATABASE,
+ NULL, database_info_, NULL, NULL, NULL, NULL);
}
private:
@@ -292,7 +353,7 @@ class CookieTreeDatabasesNode : public CookieTreeNode {
virtual DetailedInfo GetDetailedInfo() const {
return DetailedInfo(GetParent()->GetTitle(),
DetailedInfo::TYPE_DATABASES,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, NULL, NULL);
}
void AddDatabaseNode(CookieTreeDatabaseNode* child) {
@@ -307,20 +368,19 @@ class CookieTreeDatabasesNode : public CookieTreeNode {
// CookieTreeLocalStorageNode -------------------------------------------------
class CookieTreeLocalStorageNode : public CookieTreeNode {
public:
- friend class CookieTreeLocalStoragesNode;
-
// Does not take ownership of local_storage_info, and local_storage_info
- // should remain valid at least as long as the CookieTreeStorageNode is valid.
+ // should remain valid at least as long as the CookieTreeLocalStorageNode is
+ // valid.
explicit CookieTreeLocalStorageNode(
BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info);
virtual ~CookieTreeLocalStorageNode() {}
- // CookieTreeStorageNode methods:
+ // CookieTreeNode methods:
virtual void DeleteStoredObjects();
virtual DetailedInfo GetDetailedInfo() const {
return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_LOCAL_STORAGE, NULL, NULL,
- local_storage_info_, NULL);
+ DetailedInfo::TYPE_LOCAL_STORAGE,
+ NULL, NULL, local_storage_info_, NULL, NULL, NULL);
}
private:
@@ -339,7 +399,7 @@ class CookieTreeLocalStoragesNode : public CookieTreeNode {
virtual DetailedInfo GetDetailedInfo() const {
return DetailedInfo(GetParent()->GetTitle(),
DetailedInfo::TYPE_LOCAL_STORAGES,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, NULL, NULL);
}
void AddLocalStorageNode(CookieTreeLocalStorageNode* child) {
@@ -347,9 +407,103 @@ class CookieTreeLocalStoragesNode : public CookieTreeNode {
}
private:
+
DISALLOW_COPY_AND_ASSIGN(CookieTreeLocalStoragesNode);
};
+
+// CookieTreeSessionStorageNode -----------------------------------------------
+class CookieTreeSessionStorageNode : public CookieTreeNode {
+ public:
+ // Does not take ownership of session_storage_info, and session_storage_info
+ // should remain valid at least as long as the CookieTreeSessionStorageNode
+ // is valid.
+ explicit CookieTreeSessionStorageNode(
+ BrowsingDataLocalStorageHelper::LocalStorageInfo* session_storage_info);
+ 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);
+ }
+
+ private:
+ // session_storage_info_ is not owned by the node, and is expected to remain
+ // valid as long as the CookieTreeSessionStorageNode is valid.
+ BrowsingDataLocalStorageHelper::LocalStorageInfo* session_storage_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(CookieTreeSessionStorageNode);
+};
+
+class CookieTreeSessionStoragesNode : public CookieTreeNode {
+ public:
+ CookieTreeSessionStoragesNode();
+ virtual ~CookieTreeSessionStoragesNode() {}
+
+ virtual DetailedInfo GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_SESSION_STORAGES,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+
+ void AddSessionStorageNode(CookieTreeSessionStorageNode* child) {
+ AddChildSortedByTitle(child);
+ }
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(CookieTreeSessionStoragesNode);
+};
+
+// CookieTreeIndexedDBNode -----------------------------------------------
+class CookieTreeIndexedDBNode : public CookieTreeNode {
+ public:
+ // Does not take ownership of session_storage_info, and session_storage_info
+ // should remain valid at least as long as the CookieTreeSessionStorageNode
+ // is valid.
+ explicit CookieTreeIndexedDBNode(
+ BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info);
+ 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_);
+ }
+
+ private:
+ // indexed_db_info_ is not owned by the node, and is expected to remain
+ // valid as long as the CookieTreeIndexedDBNode is valid.
+ BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(CookieTreeIndexedDBNode);
+};
+
+class CookieTreeIndexedDBsNode : public CookieTreeNode {
+ public:
+ CookieTreeIndexedDBsNode();
+ virtual ~CookieTreeIndexedDBsNode() {}
+
+ virtual DetailedInfo GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_INDEXED_DBS,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+
+ void AddIndexedDBNode(CookieTreeIndexedDBNode* child) {
+ AddChildSortedByTitle(child);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CookieTreeIndexedDBsNode);
+};
+
+
+// CookiesTreeModel -----------------------------------------------------------
class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> {
public:
// Because non-cookie nodes are fetched in a background thread, they are not
@@ -367,7 +521,9 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> {
net::CookieMonster* cookie_monster_,
BrowsingDataDatabaseHelper* database_helper,
BrowsingDataLocalStorageHelper* local_storage_helper,
- BrowsingDataAppCacheHelper* appcache_helper);
+ BrowsingDataLocalStorageHelper* session_storage_helper,
+ BrowsingDataAppCacheHelper* appcache_helper,
+ BrowsingDataIndexedDBHelper* indexed_db_helper);
virtual ~CookiesTreeModel();
// TreeModel methods:
@@ -408,17 +564,28 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> {
DatabaseInfoList;
typedef std::vector<BrowsingDataLocalStorageHelper::LocalStorageInfo>
LocalStorageInfoList;
+ typedef std::vector<BrowsingDataLocalStorageHelper::LocalStorageInfo>
+ SessionStorageInfoList;
+ typedef std::vector<BrowsingDataIndexedDBHelper::IndexedDBInfo>
+ IndexedDBInfoList;
void LoadCookies();
void LoadCookiesWithFilter(const std::wstring& filter);
void OnAppCacheModelInfoLoaded();
void OnDatabaseModelInfoLoaded(const DatabaseInfoList& database_info);
- void OnStorageModelInfoLoaded(const LocalStorageInfoList& local_storage_info);
+ void OnLocalStorageModelInfoLoaded(
+ const LocalStorageInfoList& local_storage_info);
+ void OnSessionStorageModelInfoLoaded(
+ const LocalStorageInfoList& local_storage_info);
+ void OnIndexedDBModelInfoLoaded(
+ const IndexedDBInfoList& indexed_db_info);
void PopulateAppCacheInfoWithFilter(const std::wstring& filter);
void PopulateDatabaseInfoWithFilter(const std::wstring& filter);
void PopulateLocalStorageInfoWithFilter(const std::wstring& filter);
+ void PopulateSessionStorageInfoWithFilter(const std::wstring& filter);
+ void PopulateIndexedDBInfoWithFilter(const std::wstring& filter);
void NotifyObserverBeginBatch();
void NotifyObserverEndBatch();
@@ -432,7 +599,11 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> {
DatabaseInfoList database_info_list_;
scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_helper_;
+ scoped_refptr<BrowsingDataLocalStorageHelper> session_storage_helper_;
+ scoped_refptr<BrowsingDataIndexedDBHelper> indexed_db_helper_;
LocalStorageInfoList local_storage_info_list_;
+ LocalStorageInfoList session_storage_info_list_;
+ IndexedDBInfoList indexed_db_info_list_;
// The CookiesTreeModel maintains a separate list of observers that are
// specifically of the type CookiesTreeModel::Observer.
@@ -447,6 +618,7 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> {
friend class CookieTreeCookieNode;
friend class CookieTreeDatabaseNode;
friend class CookieTreeLocalStorageNode;
+ friend class CookieTreeIndexedDBNode;
DISALLOW_COPY_AND_ASSIGN(CookiesTreeModel);
};
diff --git a/chrome/browser/cookies_tree_model_unittest.cc b/chrome/browser/cookies_tree_model_unittest.cc
index 793a9ac..75844d0 100644
--- a/chrome/browser/cookies_tree_model_unittest.cc
+++ b/chrome/browser/cookies_tree_model_unittest.cc
@@ -6,12 +6,15 @@
#include <string>
-#include "app/l10n_util.h"
#include "chrome/browser/host_content_settings_map.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"
#include "testing/gtest/include/gtest/gtest.h"
@@ -58,8 +61,12 @@ class CookiesTreeModelTest : public testing::Test {
new MockBrowsingDataDatabaseHelper(profile_.get());
mock_browsing_data_local_storage_helper_ =
new MockBrowsingDataLocalStorageHelper(profile_.get());
+ mock_browsing_data_session_storage_helper_ =
+ new MockBrowsingDataLocalStorageHelper(profile_.get());
mock_browsing_data_appcache_helper_ =
new MockBrowsingDataAppCacheHelper(profile_.get());
+ mock_browsing_data_indexed_db_helper_ =
+ new MockBrowsingDataIndexedDBHelper(profile_.get());
}
CookiesTreeModel* CreateCookiesTreeModelWithInitialSample() {
@@ -70,22 +77,37 @@ class CookiesTreeModelTest : public testing::Test {
CookiesTreeModel* cookies_model = new CookiesTreeModel(
monster, mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
+ mock_browsing_data_session_storage_helper_,
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
mock_browsing_data_local_storage_helper_->Notify();
+ mock_browsing_data_session_storage_helper_->AddLocalStorageSamples();
+ mock_browsing_data_session_storage_helper_->Notify();
+ mock_browsing_data_indexed_db_helper_->AddIndexedDBSamples();
+ mock_browsing_data_indexed_db_helper_->Notify();
{
- SCOPED_TRACE("Initial State 3 cookies, 2 databases, 2 local storages");
- // 22 because there's the root, then foo1 -> cookies -> a,
+ SCOPED_TRACE("Initial State 3 cookies, 2 databases, 2 local storages, "
+ "2 session storages, 2 indexed DBs");
+ // 32 because there's the root, then foo1 -> cookies -> a,
// foo2 -> cookies -> b, foo3 -> cookies -> c,
// dbhost1 -> database -> db1, dbhost2 -> database -> db2,
// host1 -> localstorage -> http://host1:1/,
// host2 -> localstorage -> http://host2:2/.
- EXPECT_EQ(22, cookies_model->GetRoot()->GetTotalNodeCount());
+ // host1 -> sessionstorage -> http://host1:1/,
+ // host2 -> sessionstorage -> http://host2:2/,
+ // idbhost1 -> indexeddb -> http://idbhost1:1/,
+ // idbhost2 -> indexeddb -> http://idbhost2:2/.
+ EXPECT_EQ(32, cookies_model->GetRoot()->GetTotalNodeCount());
EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model));
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model));
}
return cookies_model;
}
@@ -116,6 +138,8 @@ class CookiesTreeModelTest : public testing::Test {
} else {
if (node->GetDetailedInfo().node_type == node_type) {
switch (node_type) {
+ case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
+ return node->GetDetailedInfo().session_storage_info->origin + ",";
case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
return node->GetDetailedInfo().local_storage_info->origin + ",";
case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
@@ -125,6 +149,8 @@ class CookiesTreeModelTest : public testing::Test {
case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
return node->GetDetailedInfo().appcache_info->manifest_url.spec() +
",";
+ case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
+ return node->GetDetailedInfo().indexed_db_info->origin + ",";
default:
return "";
}
@@ -148,6 +174,16 @@ class CookiesTreeModelTest : public testing::Test {
CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE);
}
+ std::string GetSessionStoragesOfChildren(const CookieTreeNode* node) {
+ return GetNodesOfChildren(
+ node, CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE);
+ }
+
+ std::string GetIndexedDBsOfChildren(const CookieTreeNode* node) {
+ return GetNodesOfChildren(
+ node, CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB);
+ }
+
// Get the nodes names displayed in the view (if we had one) in the order
// they are displayed, as a comma seperated string.
// Ex: EXPECT_STREQ("X,Y", GetDisplayedNodes(cookies_view, type).c_str());
@@ -176,11 +212,21 @@ class CookiesTreeModelTest : public testing::Test {
CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE);
}
+ std::string GetDisplayedSessionStorages(CookiesTreeModel* cookies_model) {
+ return GetDisplayedNodes(
+ cookies_model, CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE);
+ }
+
std::string GetDisplayedAppCaches(CookiesTreeModel* cookies_model) {
return GetDisplayedNodes(cookies_model,
CookieTreeNode::DetailedInfo::TYPE_APPCACHE);
}
+ std::string GetDisplayedIndexedDBs(CookiesTreeModel* cookies_model) {
+ return GetDisplayedNodes(cookies_model,
+ CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB);
+ }
+
// do not call on the root
void DeleteStoredObjects(CookieTreeNode* node) {
node->DeleteStoredObjects();
@@ -200,8 +246,12 @@ class CookiesTreeModelTest : public testing::Test {
mock_browsing_data_database_helper_;
scoped_refptr<MockBrowsingDataLocalStorageHelper>
mock_browsing_data_local_storage_helper_;
+ scoped_refptr<MockBrowsingDataLocalStorageHelper>
+ mock_browsing_data_session_storage_helper_;
scoped_refptr<MockBrowsingDataAppCacheHelper>
mock_browsing_data_appcache_helper_;
+ scoped_refptr<MockBrowsingDataIndexedDBHelper>
+ mock_browsing_data_indexed_db_helper_;
};
TEST_F(CookiesTreeModelTest, RemoveAll) {
@@ -218,10 +268,16 @@ TEST_F(CookiesTreeModelTest, RemoveAll) {
GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
}
mock_browsing_data_database_helper_->Reset();
mock_browsing_data_local_storage_helper_->Reset();
+ mock_browsing_data_session_storage_helper_->Reset();
+ mock_browsing_data_indexed_db_helper_->Reset();
cookies_model->DeleteAllStoredObjects();
@@ -234,6 +290,8 @@ TEST_F(CookiesTreeModelTest, RemoveAll) {
GetDisplayedCookies(cookies_model.get()));
EXPECT_TRUE(mock_browsing_data_database_helper_->AllDeleted());
EXPECT_TRUE(mock_browsing_data_local_storage_helper_->AllDeleted());
+ EXPECT_FALSE(mock_browsing_data_session_storage_helper_->AllDeleted());
+ EXPECT_TRUE(mock_browsing_data_indexed_db_helper_->AllDeleted());
}
}
@@ -250,7 +308,11 @@ TEST_F(CookiesTreeModelTest, Remove) {
EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- EXPECT_EQ(19, cookies_model->GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(29, cookies_model->GetRoot()->GetTotalNodeCount());
}
DeleteStoredObjects(cookies_model->GetRoot()->GetChild(2));
@@ -261,7 +323,11 @@ TEST_F(CookiesTreeModelTest, Remove) {
EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- EXPECT_EQ(16, cookies_model->GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(26, cookies_model->GetRoot()->GetTotalNodeCount());
}
DeleteStoredObjects(cookies_model->GetRoot()->GetChild(3));
@@ -272,7 +338,26 @@ TEST_F(CookiesTreeModelTest, Remove) {
EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- EXPECT_EQ(13, cookies_model->GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(21, cookies_model->GetRoot()->GetTotalNodeCount());
+ }
+
+ DeleteStoredObjects(cookies_model->GetRoot()->GetChild(4));
+ {
+ SCOPED_TRACE("First IndexedDB origin removed");
+ EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
+ EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
+ EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
+ EXPECT_EQ("http://host2:2/",
+ GetDisplayedLocalStorages(cookies_model.get()));
+ EXPECT_EQ("http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(18, cookies_model->GetRoot()->GetTotalNodeCount());
}
}
@@ -286,16 +371,22 @@ TEST_F(CookiesTreeModelTest, RemoveCookiesNode) {
SCOPED_TRACE("First origin removed");
EXPECT_STREQ("B,C", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str());
- // 20 because in this case, the origin remains, although the COOKIES
+ // 28 because in this case, the origin remains, although the COOKIES
// node beneath it has been deleted. So, we have
// root -> foo1 -> cookies -> a, foo2, foo3 -> cookies -> c
// dbhost1 -> database -> db1, dbhost2 -> database -> db2,
// host1 -> localstorage -> http://host1:1/,
- // host2 -> localstorage -> http://host2:2/.
- EXPECT_EQ(20, cookies_model->GetRoot()->GetTotalNodeCount());
+ // host2 -> localstorage -> http://host2:2/,
+ // idbhost1 -> sessionstorage -> http://idbhost1:1/,
+ // idbhost2 -> sessionstorage -> http://idbhost2:2/.
+ EXPECT_EQ(30, cookies_model->GetRoot()->GetTotalNodeCount());
EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
}
DeleteStoredObjects(cookies_model->GetRoot()->GetChild(3)->GetChild(0));
@@ -306,7 +397,11 @@ TEST_F(CookiesTreeModelTest, RemoveCookiesNode) {
EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- EXPECT_EQ(18, cookies_model->GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(28, cookies_model->GetRoot()->GetTotalNodeCount());
}
DeleteStoredObjects(cookies_model->GetRoot()->GetChild(5)->GetChild(0));
@@ -317,7 +412,11 @@ TEST_F(CookiesTreeModelTest, RemoveCookiesNode) {
EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- EXPECT_EQ(16, cookies_model->GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(26, cookies_model->GetRoot()->GetTotalNodeCount());
}
}
@@ -334,13 +433,21 @@ TEST_F(CookiesTreeModelTest, RemoveCookieNode) {
EXPECT_EQ("db1,db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- // 20 because in this case, the origin remains, although the COOKIES
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ // 28 because in this case, the origin remains, although the COOKIES
// node beneath it has been deleted. So, we have
// root -> foo1 -> cookies -> a, foo2, foo3 -> cookies -> c
// dbhost1 -> database -> db1, dbhost2 -> database -> db2,
// host1 -> localstorage -> http://host1:1/,
// host2 -> localstorage -> http://host2:2/.
- EXPECT_EQ(20, cookies_model->GetRoot()->GetTotalNodeCount());
+ // host1 -> sessionstorage -> http://host1:1/,
+ // host2 -> sessionstorage -> http://host2:2/,
+ // idbhost1 -> sessionstorage -> http://idbhost1:1/,
+ // idbhost2 -> sessionstorage -> http://idbhost2:2/.
+ EXPECT_EQ(30, cookies_model->GetRoot()->GetTotalNodeCount());
}
DeleteStoredObjects(cookies_model->GetRoot()->GetChild(3)->GetChild(0));
@@ -351,7 +458,11 @@ TEST_F(CookiesTreeModelTest, RemoveCookieNode) {
EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- EXPECT_EQ(18, cookies_model->GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(28, cookies_model->GetRoot()->GetTotalNodeCount());
}
DeleteStoredObjects(cookies_model->GetRoot()->GetChild(5)->GetChild(0));
@@ -362,7 +473,11 @@ TEST_F(CookiesTreeModelTest, RemoveCookieNode) {
EXPECT_EQ("db2", GetDisplayedDatabases(cookies_model.get()));
EXPECT_EQ("http://host2:2/",
GetDisplayedLocalStorages(cookies_model.get()));
- EXPECT_EQ(16, cookies_model->GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(cookies_model.get()));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(cookies_model.get()));
+ EXPECT_EQ(26, cookies_model->GetRoot()->GetTotalNodeCount());
}
}
@@ -375,25 +490,40 @@ TEST_F(CookiesTreeModelTest, RemoveSingleCookieNode) {
CookiesTreeModel cookies_model(monster,
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
+ mock_browsing_data_session_storage_helper_,
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
mock_browsing_data_local_storage_helper_->Notify();
+ mock_browsing_data_session_storage_helper_->AddLocalStorageSamples();
+ mock_browsing_data_session_storage_helper_->Notify();
+ mock_browsing_data_indexed_db_helper_->AddIndexedDBSamples();
+ mock_browsing_data_indexed_db_helper_->Notify();
{
- SCOPED_TRACE("Initial State 4 cookies, 2 databases, 2 local storages");
- // 23 because there's the root, then foo1 -> cookies -> a,
+ SCOPED_TRACE("Initial State 4 cookies, 2 databases, 2 local storages, "
+ "2 session storages, 2 indexed DBs");
+ // 33 because there's the root, then foo1 -> cookies -> a,
// foo2 -> cookies -> b, foo3 -> cookies -> c,d
// dbhost1 -> database -> db1, dbhost2 -> database -> db2,
// host1 -> localstorage -> http://host1:1/,
// host2 -> localstorage -> http://host2:2/.
- EXPECT_EQ(23, cookies_model.GetRoot()->GetTotalNodeCount());
+ // host1 -> sessionstorage -> http://host1:1/,
+ // host2 -> sessionstorage -> http://host2:2/,
+ // idbhost1 -> sessionstorage -> http://idbhost1:1/,
+ // idbhost2 -> sessionstorage -> http://idbhost2:2/.
+ EXPECT_EQ(33, cookies_model.GetRoot()->GetTotalNodeCount());
EXPECT_STREQ("A,B,C,D", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("A,B,C,D", GetDisplayedCookies(&cookies_model).c_str());
EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(&cookies_model));
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(&cookies_model));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(&cookies_model));
}
DeleteStoredObjects(cookies_model.GetRoot()->GetChild(2));
{
@@ -403,7 +533,11 @@ TEST_F(CookiesTreeModelTest, RemoveSingleCookieNode) {
EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(&cookies_model));
- EXPECT_EQ(19, cookies_model.GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(&cookies_model));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(&cookies_model));
+ EXPECT_EQ(29, cookies_model.GetRoot()->GetTotalNodeCount());
}
}
@@ -417,25 +551,40 @@ TEST_F(CookiesTreeModelTest, RemoveSingleCookieNodeOf3) {
CookiesTreeModel cookies_model(monster,
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
+ mock_browsing_data_session_storage_helper_,
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
mock_browsing_data_local_storage_helper_->Notify();
+ mock_browsing_data_session_storage_helper_->AddLocalStorageSamples();
+ mock_browsing_data_session_storage_helper_->Notify();
+ mock_browsing_data_indexed_db_helper_->AddIndexedDBSamples();
+ mock_browsing_data_indexed_db_helper_->Notify();
{
- SCOPED_TRACE("Initial State 5 cookies, 2 databases, 2 local storages");
- // 24 because there's the root, then foo1 -> cookies -> a,
+ SCOPED_TRACE("Initial State 5 cookies, 2 databases, 2 local storages, "
+ "2 session storages, 2 indexed DBs");
+ // 34 because there's the root, then foo1 -> cookies -> a,
// foo2 -> cookies -> b, foo3 -> cookies -> c,d,e
// dbhost1 -> database -> db1, dbhost2 -> database -> db2,
// host1 -> localstorage -> http://host1:1/,
// host2 -> localstorage -> http://host2:2/.
- EXPECT_EQ(24, cookies_model.GetRoot()->GetTotalNodeCount());
+ // host1 -> sessionstorage -> http://host1:1/,
+ // host2 -> sessionstorage -> http://host2:2/,
+ // idbhost1 -> sessionstorage -> http://idbhost1:1/,
+ // idbhost2 -> sessionstorage -> http://idbhost2:2/.
+ EXPECT_EQ(34, cookies_model.GetRoot()->GetTotalNodeCount());
EXPECT_STREQ("A,B,C,D,E", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("A,B,C,D,E", GetDisplayedCookies(&cookies_model).c_str());
EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(&cookies_model));
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(&cookies_model));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(&cookies_model));
}
DeleteStoredObjects(cookies_model.GetRoot()->GetChild(2)->GetChild(0)->
GetChild(1));
@@ -443,10 +592,14 @@ TEST_F(CookiesTreeModelTest, RemoveSingleCookieNodeOf3) {
SCOPED_TRACE("Middle cookie in third origin removed");
EXPECT_STREQ("A,B,C,E", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("A,B,C,E", GetDisplayedCookies(&cookies_model).c_str());
- EXPECT_EQ(23, cookies_model.GetRoot()->GetTotalNodeCount());
+ EXPECT_EQ(33, cookies_model.GetRoot()->GetTotalNodeCount());
EXPECT_EQ("db1,db2", GetDisplayedDatabases(&cookies_model));
EXPECT_EQ("http://host1:1/,http://host2:2/",
GetDisplayedLocalStorages(&cookies_model));
+ EXPECT_EQ("http://host1:1/,http://host2:2/",
+ GetDisplayedSessionStorages(&cookies_model));
+ EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/",
+ GetDisplayedIndexedDBs(&cookies_model));
}
}
@@ -460,7 +613,9 @@ TEST_F(CookiesTreeModelTest, RemoveSecondOrigin) {
CookiesTreeModel cookies_model(monster,
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
+ mock_browsing_data_session_storage_helper_,
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
{
SCOPED_TRACE("Initial State 5 cookies");
// 11 because there's the root, then foo1 -> cookies -> a,
@@ -494,19 +649,21 @@ TEST_F(CookiesTreeModelTest, OriginOrdering) {
CookiesTreeModel cookies_model(monster,
new MockBrowsingDataDatabaseHelper(profile_.get()),
new MockBrowsingDataLocalStorageHelper(profile_.get()),
- new MockBrowsingDataAppCacheHelper(profile_.get()));
+ new MockBrowsingDataLocalStorageHelper(profile_.get()),
+ new MockBrowsingDataAppCacheHelper(profile_.get()),
+ new MockBrowsingDataIndexedDBHelper(profile_.get()));
{
SCOPED_TRACE("Initial State 8 cookies");
- // D starts with a ., CookieMonster orders that lexicographically first
- EXPECT_STREQ("D,E,A,C,F,B,G,H", GetMonsterCookies(monster).c_str());
+ // CookieMonster orders cookies by pathlength, then by creation time.
+ // All paths are length 1.
+ EXPECT_STREQ("A,B,C,D,E,F,G,H", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("F,E,C,B,A,G,D,H",
GetDisplayedCookies(&cookies_model).c_str());
}
DeleteStoredObjects(cookies_model.GetRoot()->GetChild(1)); // Delete "E"
{
- SCOPED_TRACE("Second origin removed");
- EXPECT_STREQ("D,A,C,F,B,G,H", GetMonsterCookies(monster).c_str());
+ EXPECT_STREQ("A,B,C,D,F,G,H", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("F,C,B,A,G,D,H", GetDisplayedCookies(&cookies_model).c_str());
}
}
@@ -520,7 +677,9 @@ TEST_F(CookiesTreeModelTest, ContentSettings) {
CookiesTreeModel cookies_model(monster,
new MockBrowsingDataDatabaseHelper(profile_.get()),
new MockBrowsingDataLocalStorageHelper(profile_.get()),
- new MockBrowsingDataAppCacheHelper(profile_.get()));
+ new MockBrowsingDataLocalStorageHelper(profile_.get()),
+ new MockBrowsingDataAppCacheHelper(profile_.get()),
+ new MockBrowsingDataIndexedDBHelper(profile_.get()));
TestingProfile profile;
HostContentSettingsMap* content_settings =
@@ -539,7 +698,8 @@ TEST_F(CookiesTreeModelTest, ContentSettings) {
EXPECT_EQ(2, observer.counter);
EXPECT_EQ(pattern, observer.last_pattern);
EXPECT_EQ(CONTENT_SETTING_SESSION_ONLY,
- content_settings->GetContentSetting(host, CONTENT_SETTINGS_TYPE_COOKIES));
+ content_settings->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
}
} // namespace
diff --git a/chrome/browser/crash_handler_host_linux.cc b/chrome/browser/crash_handler_host_linux.cc
index 61ffd7d..6f3d183 100644
--- a/chrome/browser/crash_handler_host_linux.cc
+++ b/chrome/browser/crash_handler_host_linux.cc
@@ -20,6 +20,8 @@
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/string_util.h"
+#include "base/task.h"
+#include "base/thread.h"
#include "breakpad/src/client/linux/handler/exception_handler.h"
#include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
#include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
@@ -30,14 +32,27 @@
using google_breakpad::ExceptionHandler;
+namespace {
+
+// Handles the crash dump and frees the allocated BreakpadInfo struct.
+void CrashDumpTask(BreakpadInfo* info) {
+ HandleCrashDump(*info);
+ delete[] info->filename;
+ delete[] info->process_type;
+ delete[] info->crash_url;
+ delete[] info->guid;
+ delete[] info->distro;
+ delete info;
+}
+
+} // namespace
+
// Since classes derived from CrashHandlerHostLinux are singletons, it's only
// destroyed at the end of the processes lifetime, which is greater in span than
// the lifetime of the IO message loop.
DISABLE_RUNNABLE_METHOD_REFCOUNT(CrashHandlerHostLinux);
-CrashHandlerHostLinux::CrashHandlerHostLinux()
- : process_socket_(-1),
- browser_socket_(-1) {
+CrashHandlerHostLinux::CrashHandlerHostLinux() {
int fds[2];
// We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
// sending datagrams to other sockets on the system. The sandbox may prevent
@@ -62,6 +77,9 @@ CrashHandlerHostLinux::CrashHandlerHostLinux()
CrashHandlerHostLinux::~CrashHandlerHostLinux() {
HANDLE_EINTR(close(process_socket_));
HANDLE_EINTR(close(browser_socket_));
+
+ // If we are quitting and there are crash dumps in the queue, discard them.
+ uploader_thread_->message_loop()->QuitNow();
}
void CrashHandlerHostLinux::Init() {
@@ -73,6 +91,13 @@ void CrashHandlerHostLinux::Init() {
ml->AddDestructionObserver(this);
}
+void CrashHandlerHostLinux::InitCrashUploaderThread() {
+ SetProcessType();
+ uploader_thread_.reset(
+ new base::Thread(std::string(process_type_ + "_crash_uploader").c_str()));
+ uploader_thread_->Start();
+}
+
void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) {
DCHECK(false);
}
@@ -87,7 +112,7 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
// The length of the control message:
static const unsigned kControlMsgSize =
- CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
+ CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
// The length of the regular payload:
static const unsigned kCrashContextSize =
sizeof(ExceptionHandler::CrashContext);
@@ -95,24 +120,26 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
struct msghdr msg = {0};
struct iovec iov[6];
char crash_context[kCrashContextSize];
- char guid[kGuidSize + 1];
- char crash_url[kMaxActiveURLSize + 1];
- char distro[kDistroSize + 1];
+ 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;
char control[kControlMsgSize];
- const ssize_t expected_msg_size = sizeof(crash_context) + sizeof(guid) +
- sizeof(crash_url) + sizeof(distro) +
+ const ssize_t expected_msg_size = sizeof(crash_context) +
+ kGuidSize + 1 +
+ kMaxActiveURLSize + 1 +
+ kDistroSize + 1 +
sizeof(tid_buf_addr) + sizeof(tid_fd);
iov[0].iov_base = crash_context;
iov[0].iov_len = sizeof(crash_context);
iov[1].iov_base = guid;
- iov[1].iov_len = sizeof(guid);
+ iov[1].iov_len = kGuidSize + 1;
iov[2].iov_base = crash_url;
- iov[2].iov_len = sizeof(crash_url);
+ iov[2].iov_len = kMaxActiveURLSize + 1;
iov[3].iov_base = distro;
- iov[3].iov_len = sizeof(distro);
+ iov[3].iov_len = kDistroSize + 1;
iov[4].iov_base = &tid_buf_addr;
iov[4].iov_len = sizeof(tid_buf_addr);
iov[5].iov_base = &tid_fd;
@@ -144,6 +171,7 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
// Walk the control payload an extract the file descriptor and validated pid.
pid_t crashing_pid = -1;
+ int partner_fd = -1;
int signal_fd = -1;
for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
hdr = CMSG_NXTHDR(&msg, hdr)) {
@@ -154,16 +182,17 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
(((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
DCHECK_EQ(len % sizeof(int), 0u);
const unsigned num_fds = len / sizeof(int);
- if (num_fds > 1 || num_fds == 0) {
+ if (num_fds != 2) {
// A nasty process could try and send us too many descriptors and
// force a leak.
- LOG(ERROR) << "Death signal contained too many descriptors;"
+ LOG(ERROR) << "Death signal contained wrong number of descriptors;"
<< " num_fds:" << num_fds;
for (unsigned i = 0; i < num_fds; ++i)
HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
return;
} else {
- signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
+ partner_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
+ signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[1];
}
} else if (hdr->cmsg_type == SCM_CREDENTIALS) {
const struct ucred *cred =
@@ -172,10 +201,12 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
}
}
- if (crashing_pid == -1 || signal_fd == -1) {
+ if (crashing_pid == -1 || partner_fd == -1 || signal_fd == -1) {
LOG(ERROR) << "Death signal message didn't contain all expected control"
<< " messages";
- if (signal_fd)
+ if (partner_fd >= 0)
+ HANDLE_EINTR(close(partner_fd));
+ if (signal_fd >= 0)
HANDLE_EINTR(close(signal_fd));
return;
}
@@ -186,20 +217,27 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
// In the future we can remove this workaround, but we have to wait a couple
// of years to be sure that it's worked its way out into the world.
+ // The crashing process closes its copy of the signal_fd immediately after
+ // calling sendmsg(). We can thus not reliably look for with with
+ // FindProcessHoldingSocket(). But by necessity, it has to keep the
+ // partner_fd open until the crashdump is complete.
uint64_t inode_number;
- if (!base::FileDescriptorGetInode(&inode_number, signal_fd)) {
+ if (!base::FileDescriptorGetInode(&inode_number, partner_fd)) {
LOG(WARNING) << "Failed to get inode number for passed socket";
+ HANDLE_EINTR(close(partner_fd));
HANDLE_EINTR(close(signal_fd));
return;
}
+ HANDLE_EINTR(close(partner_fd));
pid_t actual_crashing_pid = -1;
- if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number - 1)) {
+ if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number)) {
LOG(WARNING) << "Failed to find process holding other end of crash reply "
"socket";
HANDLE_EINTR(close(signal_fd));
return;
}
+
if (actual_crashing_pid != crashing_pid) {
crashing_pid = actual_crashing_pid;
@@ -236,6 +274,7 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
bool upload = true;
FilePath dumps_path("/tmp");
+ PathService::Get(base::DIR_TEMP, &dumps_path);
if (getenv(env_vars::kHeadless)) {
upload = false;
PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
@@ -265,20 +304,57 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
// Sanitize the string data a bit more
guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0;
- BreakpadInfo info;
- info.filename = minidump_filename.c_str();
- info.process_type = process_type_.c_str();
- info.process_type_length = process_type_.length();
- info.crash_url = crash_url;
- info.crash_url_length = strlen(crash_url);
- info.guid = guid;
- info.guid_length = strlen(guid);
- info.distro = distro;
- info.distro_length = strlen(distro);
- info.upload = upload;
- HandleCrashDump(info);
+ BreakpadInfo* info = new BreakpadInfo;
+
+ char* minidump_filename_str = new char[minidump_filename.length() + 1];
+ minidump_filename.copy(minidump_filename_str, minidump_filename.length());
+ minidump_filename_str[minidump_filename.length()] = '\0';
+ info->filename = minidump_filename_str;
+
+ info->process_type_length = process_type_.length();
+ char* process_type_str = new char[info->process_type_length + 1];
+ process_type_.copy(process_type_str, info->process_type_length);
+ process_type_str[info->process_type_length] = '\0';
+ info->process_type = process_type_str;
+
+ info->crash_url_length = strlen(crash_url);
+ info->crash_url = crash_url;
+
+ info->guid_length = strlen(guid);
+ info->guid = guid;
+
+ info->distro_length = strlen(distro);
+ info->distro = distro;
+
+ info->upload = upload;
+
+ uploader_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(&CrashDumpTask, info));
}
void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
file_descriptor_watcher_.StopWatchingFileDescriptor();
}
+
+PluginCrashHandlerHostLinux::PluginCrashHandlerHostLinux() {
+ InitCrashUploaderThread();
+}
+
+PluginCrashHandlerHostLinux::~PluginCrashHandlerHostLinux() {
+}
+
+void PluginCrashHandlerHostLinux::SetProcessType() {
+ process_type_ = "plugin";
+}
+
+RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() {
+ InitCrashUploaderThread();
+}
+
+RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() {
+}
+
+void RendererCrashHandlerHostLinux::SetProcessType() {
+ process_type_ = "renderer";
+}
diff --git a/chrome/browser/crash_handler_host_linux.h b/chrome/browser/crash_handler_host_linux.h
index 3f1ea2e..0e7bf6e 100644
--- a/chrome/browser/crash_handler_host_linux.h
+++ b/chrome/browser/crash_handler_host_linux.h
@@ -1,14 +1,20 @@
-// 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.
#ifndef CHROME_BROWSER_CRASH_HANDLER_HOST_LINUX_H_
#define CHROME_BROWSER_CRASH_HANDLER_HOST_LINUX_H_
+#pragma once
#include <string>
-#include "base/singleton.h"
#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/singleton.h"
+
+namespace base {
+class Thread;
+}
// This is the base class for singleton objects which crash dump renderers and
// plugins on Linux. We perform the crash dump from the browser because it
@@ -38,18 +44,30 @@ class CrashHandlerHostLinux : public MessageLoopForIO::Watcher,
protected:
CrashHandlerHostLinux();
- ~CrashHandlerHostLinux();
- // This is here on purpose to make CrashHandlerHostLinux abstract.
- virtual void SetProcessType() = 0;
+ virtual ~CrashHandlerHostLinux();
+
+#if defined(USE_LINUX_BREAKPAD)
+ // Only called in concrete subclasses.
+ void InitCrashUploaderThread();
std::string process_type_;
+#endif
private:
void Init();
+#if defined(USE_LINUX_BREAKPAD)
+ // This is here on purpose to make CrashHandlerHostLinux abstract.
+ virtual void SetProcessType() = 0;
+#endif
+
int process_socket_;
int browser_socket_;
+
+#if defined(USE_LINUX_BREAKPAD)
MessageLoopForIO::FileDescriptorWatcher file_descriptor_watcher_;
+ scoped_ptr<base::Thread> uploader_thread_;
+#endif
DISALLOW_COPY_AND_ASSIGN(CrashHandlerHostLinux);
};
@@ -57,14 +75,12 @@ class CrashHandlerHostLinux : public MessageLoopForIO::Watcher,
class PluginCrashHandlerHostLinux : public CrashHandlerHostLinux {
private:
friend struct DefaultSingletonTraits<PluginCrashHandlerHostLinux>;
- PluginCrashHandlerHostLinux() {
- SetProcessType();
- }
- ~PluginCrashHandlerHostLinux() {}
+ PluginCrashHandlerHostLinux();
+ virtual ~PluginCrashHandlerHostLinux();
- virtual void SetProcessType() {
- process_type_ = "plugin";
- }
+#if defined(USE_LINUX_BREAKPAD)
+ virtual void SetProcessType();
+#endif
DISALLOW_COPY_AND_ASSIGN(PluginCrashHandlerHostLinux);
};
@@ -72,14 +88,12 @@ class PluginCrashHandlerHostLinux : public CrashHandlerHostLinux {
class RendererCrashHandlerHostLinux : public CrashHandlerHostLinux {
private:
friend struct DefaultSingletonTraits<RendererCrashHandlerHostLinux>;
- RendererCrashHandlerHostLinux() {
- SetProcessType();
- }
- ~RendererCrashHandlerHostLinux() {}
+ RendererCrashHandlerHostLinux();
+ virtual ~RendererCrashHandlerHostLinux();
- virtual void SetProcessType() {
- process_type_ = "renderer";
- }
+#if defined(USE_LINUX_BREAKPAD)
+ virtual void SetProcessType();
+#endif
DISALLOW_COPY_AND_ASSIGN(RendererCrashHandlerHostLinux);
};
diff --git a/chrome/browser/crash_handler_host_linux_stub.cc b/chrome/browser/crash_handler_host_linux_stub.cc
index e95f679..6835bc2 100644
--- a/chrome/browser/crash_handler_host_linux_stub.cc
+++ b/chrome/browser/crash_handler_host_linux_stub.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.
@@ -23,3 +23,15 @@ void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) {
void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
}
+
+PluginCrashHandlerHostLinux::PluginCrashHandlerHostLinux() {
+}
+
+PluginCrashHandlerHostLinux::~PluginCrashHandlerHostLinux() {
+}
+
+RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() {
+}
+
+RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() {
+}
diff --git a/chrome/browser/crash_recovery_browsertest.cc b/chrome/browser/crash_recovery_browsertest.cc
index b37c1a5..6cc6a0d 100644
--- a/chrome/browser/crash_recovery_browsertest.cc
+++ b/chrome/browser/crash_recovery_browsertest.cc
@@ -32,6 +32,10 @@ class CrashRecoveryBrowserTest : public InProcessBrowserTest {
#if defined(OS_MACOSX)
#define MAYBE_Reload DISABLED_Reload
#define MAYBE_LoadInNewTab DISABLED_LoadInNewTab
+#elif defined(OS_WIN)
+// http://crbug.com/57158 - Times out sometimes on windows.
+#define MAYBE_LoadInNewTab DISABLED_LoadInNewTab
+#define MAYBE_Reload Reload
#else
#define MAYBE_Reload Reload
#define MAYBE_LoadInNewTab LoadInNewTab
diff --git a/chrome/browser/cross_site_request_manager.h b/chrome/browser/cross_site_request_manager.h
index 966595c..d3c4dd6 100644
--- a/chrome/browser/cross_site_request_manager.h
+++ b/chrome/browser/cross_site_request_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CROSS_SITE_REQUEST_MANAGER_H__
#define CHROME_BROWSER_CROSS_SITE_REQUEST_MANAGER_H__
+#pragma once
#include <set>
#include <utility>
diff --git a/chrome/browser/custom_home_pages_table_model.cc b/chrome/browser/custom_home_pages_table_model.cc
index 446aea5..59b9ca4 100644
--- a/chrome/browser/custom_home_pages_table_model.cc
+++ b/chrome/browser/custom_home_pages_table_model.cc
@@ -8,30 +8,57 @@
#include "app/resource_bundle.h"
#include "app/table_model_observer.h"
#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/pref_service.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 "chrome/common/url_constants.h"
#include "gfx/codec/png_codec.h"
+#include "googleurl/src/gurl.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "net/base/net_util.h"
+#include "third_party/skia/include/core/SkBitmap.h"
-// static
-SkBitmap CustomHomePagesTableModel::default_favicon_;
+struct CustomHomePagesTableModel::Entry {
+ Entry() : title_handle(0), fav_icon_handle(0) {}
+
+ // URL of the page.
+ GURL url;
+
+ // Page title. If this is empty, we'll display the URL as the entry.
+ std::wstring title;
+
+ // Icon for the page.
+ SkBitmap icon;
+
+ // If non-zero, indicates we're loading the title for the page.
+ HistoryService::Handle title_handle;
+
+ // If non-zero, indicates we're loading the favicon for the page.
+ FaviconService::Handle fav_icon_handle;
+};
CustomHomePagesTableModel::CustomHomePagesTableModel(Profile* profile)
- : profile_(profile),
+ : default_favicon_(NULL),
+ profile_(profile),
observer_(NULL) {
- InitClass();
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ default_favicon_ = rb.GetBitmapNamed(IDR_DEFAULT_FAVICON);
+}
+
+CustomHomePagesTableModel::~CustomHomePagesTableModel() {
}
void CustomHomePagesTableModel::SetURLs(const std::vector<GURL>& urls) {
entries_.resize(urls.size());
for (size_t i = 0; i < urls.size(); ++i) {
entries_[i].url = urls[i];
+ entries_[i].title.erase();
+ entries_[i].icon.reset();
LoadTitleAndFavIcon(&(entries_[i]));
}
// Complete change, so tell the view to just rebuild itself.
@@ -84,7 +111,9 @@ void CustomHomePagesTableModel::SetToCurrentlyOpenPages() {
for (int tab_index = 0; tab_index < browser->tab_count(); ++tab_index) {
const GURL url = browser->GetTabContentsAt(tab_index)->GetURL();
- if (!url.is_empty())
+ if (!url.is_empty() &&
+ !(url.SchemeIs(chrome::kChromeUIScheme) &&
+ url.host() == chrome::kChromeUISettingsHost))
Add(add_index++, url);
}
}
@@ -109,7 +138,7 @@ std::wstring CustomHomePagesTableModel::GetText(int row, int column_id) {
SkBitmap CustomHomePagesTableModel::GetIcon(int row) {
DCHECK(row >= 0 && row < RowCount());
- return entries_[row].icon.isNull() ? default_favicon_ : entries_[row].icon;
+ return entries_[row].icon.isNull() ? *default_favicon_ : entries_[row].icon;
}
std::wstring CustomHomePagesTableModel::GetTooltip(int row) {
@@ -122,15 +151,6 @@ void CustomHomePagesTableModel::SetObserver(TableModelObserver* observer) {
observer_ = observer;
}
-void CustomHomePagesTableModel::InitClass() {
- static bool initialized = false;
- if (!initialized) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- default_favicon_ = *rb.GetBitmapNamed(IDR_DEFAULT_FAVICON);
- initialized = true;
- }
-}
-
void CustomHomePagesTableModel::LoadTitleAndFavIcon(Entry* entry) {
HistoryService* history_service =
profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
@@ -213,9 +233,9 @@ CustomHomePagesTableModel::Entry*
}
std::wstring CustomHomePagesTableModel::FormattedURL(int row) const {
- std::wstring languages =
- UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
- std::wstring url(net::FormatUrl(entries_[row].url, languages));
- base::i18n::GetDisplayStringInLTRDirectionality(&url);
- return url;
+ std::string languages =
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
+ string16 url = net::FormatUrl(entries_[row].url, languages);
+ url = base::i18n::GetDisplayStringInLTRDirectionality(url);
+ return UTF16ToWide(url);
}
diff --git a/chrome/browser/custom_home_pages_table_model.h b/chrome/browser/custom_home_pages_table_model.h
index b67c4b8..4115daa 100644
--- a/chrome/browser/custom_home_pages_table_model.h
+++ b/chrome/browser/custom_home_pages_table_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_CUSTOM_HOME_PAGES_TABLE_MODEL_H_
#define CHROME_BROWSER_CUSTOM_HOME_PAGES_TABLE_MODEL_H_
+#pragma once
#include <string>
#include <vector>
@@ -11,10 +12,10 @@
#include "app/table_model.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/favicon_service.h"
-#include "googleurl/src/gurl.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+class GURL;
class Profile;
+class SkBitmap;
class TableModelObserver;
// CustomHomePagesTableModel is the model for the TableView showing the list
@@ -23,7 +24,7 @@ class TableModelObserver;
class CustomHomePagesTableModel : public TableModel {
public:
explicit CustomHomePagesTableModel(Profile* profile);
- virtual ~CustomHomePagesTableModel() {}
+ virtual ~CustomHomePagesTableModel();
// Sets the set of urls that this model contains.
void SetURLs(const std::vector<GURL>& urls);
@@ -51,26 +52,7 @@ class CustomHomePagesTableModel : public TableModel {
private:
// Each item in the model is represented as an Entry. Entry stores the URL,
// title, and favicon of the page.
- struct Entry {
- Entry() : title_handle(0), fav_icon_handle(0) {}
-
- // URL of the page.
- GURL url;
-
- // Page title. If this is empty, we'll display the URL as the entry.
- std::wstring title;
-
- // Icon for the page.
- SkBitmap icon;
-
- // If non-zero, indicates we're loading the title for the page.
- HistoryService::Handle title_handle;
-
- // If non-zero, indicates we're loading the favicon for the page.
- FaviconService::Handle fav_icon_handle;
- };
-
- static void InitClass();
+ struct Entry;
// Loads the title and favicon for the specified entry.
void LoadTitleAndFavIcon(Entry* entry);
@@ -108,7 +90,7 @@ class CustomHomePagesTableModel : public TableModel {
std::vector<Entry> entries_;
// Default icon to show when one can't be found for the URL.
- static SkBitmap default_favicon_;
+ SkBitmap* default_favicon_;
// Profile used to load titles and icons.
Profile* profile_;
diff --git a/chrome/browser/debugger/debugger_host.h b/chrome/browser/debugger/debugger_host.h
index 71857e5..63fbaaa 100644
--- a/chrome/browser/debugger/debugger_host.h
+++ b/chrome/browser/debugger/debugger_host.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEBUGGER_HOST_H_
#define CHROME_BROWSER_DEBUGGER_DEBUGGER_HOST_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/debugger/debugger_remote_service.cc b/chrome/browser/debugger/debugger_remote_service.cc
index 91fca90..4c3341b 100644
--- a/chrome/browser/debugger/debugger_remote_service.cc
+++ b/chrome/browser/debugger/debugger_remote_service.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,7 +9,8 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
-#include "base/string_util.h"
+#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"
@@ -20,23 +21,14 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/devtools_messages.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
namespace {
-// A constant for the "data" JSON message field.
-// The type is wstring because the constant is used to get a
-// DictionaryValue field (which requires a wide string).
-static const std::wstring kDataWide = L"data";
-
-// A constant for the "result" JSON message field.
-// The type is wstring because the constant is used to get a
-// DictionaryValue field (which requires a wide string).
-static const std::wstring kResultWide = L"result";
-
-// A constant for the "command" JSON message field.
-// The type is wstring because the constant is used to get a
-// DictionaryValue field (which requires a wide string).
-static const std::wstring kCommandWide = L"command";
+// Constants for the "data", "result", and "command" JSON message fields.
+const char kDataKey[] = "data";
+const char kResultKey[] = "result";
+const char kCommandKey[] = "command";
} // namespace
@@ -78,32 +70,32 @@ void DebuggerRemoteService::HandleMessage(
return;
}
content = static_cast<DictionaryValue*>(request.get());
- if (!content->HasKey(kCommandWide)) {
+ if (!content->HasKey(kCommandKey)) {
NOTREACHED(); // Broken protocol :(
return;
}
std::string command;
DictionaryValue response;
- content->GetString(kCommandWide, &command);
- response.SetString(kCommandWide, command);
+ content->GetString(kCommandKey, &command);
+ response.SetString(kCommandKey, command);
bool send_response = true;
if (destination.size() == 0) {
// Unknown command (bad format?)
NOTREACHED();
- response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND);
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
SendResponse(response, message.tool(), message.destination());
return;
}
int32 tab_uid = -1;
- StringToInt(destination, &tab_uid);
+ base::StringToInt(destination, &tab_uid);
if (command == DebuggerRemoteServiceCommand::kAttach) {
// TODO(apavlov): handle 0 for a new tab
- response.SetString(kCommandWide, DebuggerRemoteServiceCommand::kAttach);
+ response.SetString(kCommandKey, DebuggerRemoteServiceCommand::kAttach);
AttachToTab(destination, &response);
} else if (command == DebuggerRemoteServiceCommand::kDetach) {
- response.SetString(kCommandWide, DebuggerRemoteServiceCommand::kDetach);
+ response.SetString(kCommandKey, DebuggerRemoteServiceCommand::kDetach);
DetachFromTab(destination, &response);
} else if (command == DebuggerRemoteServiceCommand::kDebuggerCommand) {
send_response = DispatchDebuggerCommand(tab_uid, content, &response);
@@ -112,7 +104,7 @@ void DebuggerRemoteService::HandleMessage(
} else {
// Unknown command
NOTREACHED();
- response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND);
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
}
if (send_response) {
@@ -166,12 +158,12 @@ void DebuggerRemoteService::DebuggerOutput(int32 tab_uid,
std::string content = StringPrintf(
"{\"command\":\"%s\",\"result\":%s,\"data\":%s}",
DebuggerRemoteServiceCommand::kDebuggerCommand.c_str(),
- IntToString(RESULT_OK).c_str(),
+ base::IntToString(RESULT_OK).c_str(),
message.c_str());
scoped_ptr<DevToolsRemoteMessage> response_message(
DevToolsRemoteMessageBuilder::instance().Create(
kToolName,
- IntToString(tab_uid),
+ base::IntToString(tab_uid),
content));
delegate_->Send(*(response_message.get()));
}
@@ -183,10 +175,10 @@ void DebuggerRemoteService::DebuggerOutput(int32 tab_uid,
void DebuggerRemoteService::FrameNavigate(int32 tab_uid,
const std::string& url) {
DictionaryValue value;
- value.SetString(kCommandWide, DebuggerRemoteServiceCommand::kFrameNavigate);
- value.SetInteger(kResultWide, RESULT_OK);
- value.SetString(kDataWide, url);
- SendResponse(value, kToolName, IntToString(tab_uid));
+ value.SetString(kCommandKey, DebuggerRemoteServiceCommand::kFrameNavigate);
+ value.SetInteger(kResultKey, RESULT_OK);
+ value.SetString(kDataKey, url);
+ SendResponse(value, kToolName, base::IntToString(tab_uid));
}
// Gets invoked from a DevToolsClientHost callback whenever
@@ -194,9 +186,9 @@ void DebuggerRemoteService::FrameNavigate(int32 tab_uid,
// Sends the corresponding message to the remote debugger.
void DebuggerRemoteService::TabClosed(int32 tab_id) {
DictionaryValue value;
- value.SetString(kCommandWide, DebuggerRemoteServiceCommand::kTabClosed);
- value.SetInteger(kResultWide, RESULT_OK);
- SendResponse(value, kToolName, IntToString(tab_id));
+ value.SetString(kCommandKey, DebuggerRemoteServiceCommand::kTabClosed);
+ value.SetInteger(kResultKey, RESULT_OK);
+ SendResponse(value, kToolName, base::IntToString(tab_id));
}
// Attaches a remote debugger to the target tab specified by |destination|
@@ -205,23 +197,23 @@ void DebuggerRemoteService::TabClosed(int32 tab_id) {
void DebuggerRemoteService::AttachToTab(const std::string& destination,
DictionaryValue* response) {
int32 tab_uid = -1;
- StringToInt(destination, &tab_uid);
+ base::StringToInt(destination, &tab_uid);
if (tab_uid < 0) {
// Bad tab_uid received from remote debugger (perhaps NaN)
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return;
}
if (tab_uid == 0) { // single tab_uid
// We've been asked to open a new tab with URL
// TODO(apavlov): implement
NOTIMPLEMENTED();
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return;
}
TabContents* tab_contents = ToTabContents(tab_uid);
if (tab_contents == NULL) {
// No active tab contents with tab_uid
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return;
}
RenderViewHost* target_host = tab_contents->render_view_host();
@@ -233,13 +225,13 @@ void DebuggerRemoteService::AttachToTab(const std::string& destination,
DevToolsManager* manager = DevToolsManager::GetInstance();
if (manager != NULL) {
manager->RegisterDevToolsClientHostFor(target_host, client_host);
- response->SetInteger(kResultWide, RESULT_OK);
+ response->SetInteger(kResultKey, RESULT_OK);
} else {
- response->SetInteger(kResultWide, RESULT_DEBUGGER_ERROR);
+ response->SetInteger(kResultKey, RESULT_DEBUGGER_ERROR);
}
} else {
// DevToolsClientHost for this tab is already registered
- response->SetInteger(kResultWide, RESULT_ILLEGAL_TAB_STATE);
+ response->SetInteger(kResultKey, RESULT_ILLEGAL_TAB_STATE);
}
}
@@ -249,11 +241,11 @@ void DebuggerRemoteService::AttachToTab(const std::string& destination,
void DebuggerRemoteService::DetachFromTab(const std::string& destination,
DictionaryValue* response) {
int32 tab_uid = -1;
- StringToInt(destination, &tab_uid);
+ base::StringToInt(destination, &tab_uid);
if (tab_uid == -1) {
// Bad tab_uid received from remote debugger (NaN)
if (response != NULL) {
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
}
return;
}
@@ -268,7 +260,7 @@ void DebuggerRemoteService::DetachFromTab(const std::string& destination,
result_code = RESULT_UNKNOWN_TAB;
}
if (response != NULL) {
- response->SetInteger(kResultWide, result_code);
+ response->SetInteger(kResultKey, result_code);
}
}
@@ -281,30 +273,30 @@ bool DebuggerRemoteService::DispatchDebuggerCommand(int tab_uid,
DictionaryValue* response) {
if (tab_uid == -1) {
// Invalid tab_uid from remote debugger (perhaps NaN)
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return true;
}
DevToolsManager* manager = DevToolsManager::GetInstance();
if (manager == NULL) {
- response->SetInteger(kResultWide, RESULT_DEBUGGER_ERROR);
+ response->SetInteger(kResultKey, RESULT_DEBUGGER_ERROR);
return true;
}
TabContents* tab_contents = ToTabContents(tab_uid);
if (tab_contents == NULL) {
// Unknown tab_uid from remote debugger
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return true;
}
DevToolsClientHost* client_host =
manager->GetDevToolsClientHostFor(tab_contents->render_view_host());
if (client_host == NULL) {
// tab_uid is not being debugged (Attach has not been invoked)
- response->SetInteger(kResultWide, RESULT_ILLEGAL_TAB_STATE);
+ response->SetInteger(kResultKey, RESULT_ILLEGAL_TAB_STATE);
return true;
}
std::string v8_command;
DictionaryValue* v8_command_value;
- content->GetDictionary(kDataWide, &v8_command_value);
+ content->GetDictionary(kDataKey, &v8_command_value);
base::JSONWriter::Write(v8_command_value, false, &v8_command);
manager->ForwardToDevToolsAgent(
client_host, DevToolsAgentMsg_DebuggerCommand(v8_command));
@@ -322,26 +314,26 @@ bool DebuggerRemoteService::DispatchEvaluateJavascript(
DictionaryValue* response) {
if (tab_uid == -1) {
// Invalid tab_uid from remote debugger (perhaps NaN)
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return true;
}
TabContents* tab_contents = ToTabContents(tab_uid);
if (tab_contents == NULL) {
// Unknown tab_uid from remote debugger
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return true;
}
RenderViewHost* render_view_host = tab_contents->render_view_host();
if (render_view_host == NULL) {
// No RenderViewHost
- response->SetInteger(kResultWide, RESULT_UNKNOWN_TAB);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
return true;
}
- std::wstring javascript;
- content->GetString(kDataWide, &javascript);
+ std::string javascript;
+ content->GetString(kDataKey, &javascript);
render_view_host->Send(
new ViewMsg_ScriptEvalRequest(render_view_host->routing_id(),
L"",
- javascript));
+ UTF8ToWide(javascript)));
return false;
}
diff --git a/chrome/browser/debugger/debugger_remote_service.h b/chrome/browser/debugger/debugger_remote_service.h
index 7f6e4e8..83b1f40 100644
--- a/chrome/browser/debugger/debugger_remote_service.h
+++ b/chrome/browser/debugger/debugger_remote_service.h
@@ -7,6 +7,7 @@
// "V8Debugger" tool.
#ifndef CHROME_BROWSER_DEBUGGER_DEBUGGER_REMOTE_SERVICE_H_
#define CHROME_BROWSER_DEBUGGER_DEBUGGER_REMOTE_SERVICE_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/debugger/debugger_wrapper.h b/chrome/browser/debugger/debugger_wrapper.h
index 0a82366..a9cf7bf 100644
--- a/chrome/browser/debugger/debugger_wrapper.h
+++ b/chrome/browser/debugger/debugger_wrapper.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.
@@ -8,8 +8,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEBUGGER_WRAPPER_H_
#define CHROME_BROWSER_DEBUGGER_DEBUGGER_WRAPPER_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
diff --git a/chrome/browser/debugger/devtools_client_host.h b/chrome/browser/debugger/devtools_client_host.h
index 71534fb..e62237d 100644
--- a/chrome/browser/debugger/devtools_client_host.h
+++ b/chrome/browser/debugger/devtools_client_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_CLIENT_HOST_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_CLIENT_HOST_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.cc b/chrome/browser/debugger/devtools_http_protocol_handler.cc
index 2f24e07..4ab1a79 100644
--- a/chrome/browser/debugger/devtools_http_protocol_handler.cc
+++ b/chrome/browser/debugger/devtools_http_protocol_handler.cc
@@ -7,8 +7,9 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
@@ -16,6 +17,7 @@
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/devtools_messages.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "googleurl/src/gurl.h"
@@ -37,28 +39,29 @@ class DevToolsClientHostImpl : public DevToolsClientHost {
~DevToolsClientHostImpl() {}
// DevToolsClientHost interface
- virtual void InspectedTabClosing() {}
+ virtual void InspectedTabClosing() {
+ ChromeThread::PostTask(
+ ChromeThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(socket_,
+ &HttpListenSocket::Close));
+ }
+
virtual void SendMessageToClient(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg)
- IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage);
+ IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ OnDispatchOnInspectorFrontend);
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
}
+ void NotifyCloseListener() {
+ DevToolsClientHost::NotifyCloseListener();
+ }
private:
// Message handling routines
- void OnRpcMessage(const DevToolsMessageData& data) {
- std::string message;
- message += "devtools$$dispatch(\"" + data.class_name + "\", \"" +
- data.method_name + "\"";
- for (std::vector<std::string>::const_iterator it = data.arguments.begin();
- it != data.arguments.end(); ++it) {
- std::string param = *it;
- if (!param.empty())
- message += ", " + param;
- }
- message += ")";
- socket_->SendOverWebSocket(message);
+ void OnDispatchOnInspectorFrontend(const std::string& data) {
+ socket_->SendOverWebSocket(data);
}
HttpListenSocket* socket_;
};
@@ -82,9 +85,29 @@ void DevToolsHttpProtocolHandler::Stop() {
NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Teardown));
}
-void DevToolsHttpProtocolHandler::OnHttpRequest(HttpListenSocket* socket,
- HttpServerRequestInfo* info) {
- URLRequest* request = new URLRequest(GURL("chrome:/" + info->path), this);
+void DevToolsHttpProtocolHandler::OnHttpRequest(
+ HttpListenSocket* socket,
+ const HttpServerRequestInfo& info) {
+ if (info.path == "" || info.path == "/") {
+ // Pages discovery request.
+ ChromeThread::PostTask(
+ ChromeThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &DevToolsHttpProtocolHandler::OnHttpRequestUI,
+ socket,
+ info));
+ return;
+ }
+
+ size_t pos = info.path.find("/devtools/");
+ if (pos != 0) {
+ socket->Send404();
+ return;
+ }
+
+ // Proxy static files from chrome://devtools/*.
+ URLRequest* request = new URLRequest(GURL("chrome:/" + info.path), this);
Bind(request, socket);
request->set_context(
Profile::GetDefaultRequestContext()->GetURLRequestContext());
@@ -93,8 +116,15 @@ void DevToolsHttpProtocolHandler::OnHttpRequest(HttpListenSocket* socket,
void DevToolsHttpProtocolHandler::OnWebSocketRequest(
HttpListenSocket* socket,
- HttpServerRequestInfo* request) {
- socket->AcceptWebSocket(request);
+ const HttpServerRequestInfo& request) {
+ ChromeThread::PostTask(
+ ChromeThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &DevToolsHttpProtocolHandler::OnWebSocketRequestUI,
+ socket,
+ request));
}
void DevToolsHttpProtocolHandler::OnWebSocketMessage(HttpListenSocket* socket,
@@ -109,58 +139,139 @@ void DevToolsHttpProtocolHandler::OnWebSocketMessage(HttpListenSocket* socket,
data));
}
-void DevToolsHttpProtocolHandler::OnWebSocketMessageUI(
- HttpListenSocket* socket,
- const std::string& d) {
- std::string data = d;
- if (!client_host_.get() && data == "attach") {
- client_host_.reset(new DevToolsClientHostImpl(socket));
- BrowserList::const_iterator it = BrowserList::begin();
- TabContents* tab_contents = (*it)->tabstrip_model()->GetTabContentsAt(0);
- DevToolsManager* manager = DevToolsManager::GetInstance();
- manager->RegisterDevToolsClientHostFor(tab_contents->render_view_host(),
- client_host_.get());
- } else {
- // TODO(pfeldman): Replace with proper parsing / dispatching.
- DevToolsMessageData message_data;
- message_data.class_name = "ToolsAgent";
- message_data.method_name = "dispatchOnInspectorController";
+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();
+ it2 != it->second.end(); ++it2) {
+ URLRequest* request = *it2;
+ request->Cancel();
+ request_to_socket_io_.erase(request);
+ request_to_buffer_io_.erase(request);
+ delete request;
+ }
+ socket_to_requests_io_.erase(socket);
+ }
+
+ ChromeThread::PostTask(
+ ChromeThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &DevToolsHttpProtocolHandler::OnCloseUI,
+ socket));
+}
- size_t pos = data.find(" ");
- message_data.arguments.push_back(data.substr(0, pos));
- data = data.substr(pos + 1);
+void DevToolsHttpProtocolHandler::OnHttpRequestUI(
+ HttpListenSocket* socket,
+ const HttpServerRequestInfo& info) {
+ std::string response = "<html><body>";
+ for (BrowserList::const_iterator it = BrowserList::begin(),
+ end = BrowserList::end(); it != end; ++it) {
+ TabStripModel* model = (*it)->tabstrip_model();
+ for (int i = 0, size = model->count(); i < size; ++i) {
+ TabContents* tab_contents = model->GetTabContentsAt(i);
+ NavigationController& controller = tab_contents->controller();
+ NavigationEntry* entry = controller.GetActiveEntry();
+ if (entry == NULL)
+ continue;
+
+ if (!entry->url().is_valid())
+ continue;
+
+ DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
+ GetDevToolsClientHostFor(tab_contents->render_view_host());
+ if (!client_host) {
+ response += StringPrintf(
+ "<a href='/devtools/devtools.html?page=%d'>%s (%s)</a><br>",
+ controller.session_id().id(),
+ UTF16ToUTF8(entry->title()).c_str(),
+ entry->url().spec().c_str());
+ } else {
+ response += StringPrintf(
+ "%s (%s)<br>",
+ UTF16ToUTF8(entry->title()).c_str(),
+ entry->url().spec().c_str());
+ }
+ }
+ }
+ response += "</body></html>";
+ Send200(socket, response, "text/html; charset=UTF-8");
+}
- pos = data.find(" ");
- message_data.arguments.push_back(data.substr(0, pos));
- data = data.substr(pos + 1);
+void DevToolsHttpProtocolHandler::OnWebSocketRequestUI(
+ HttpListenSocket* socket,
+ const HttpServerRequestInfo& request) {
+ std::string prefix = "/devtools/page/";
+ size_t pos = request.path.find(prefix);
+ if (pos != 0) {
+ Send404(socket);
+ return;
+ }
+ std::string page_id = request.path.substr(prefix.length());
+ int id = 0;
+ if (!base::StringToInt(page_id, &id)) {
+ Send500(socket, "Invalid page id: " + page_id);
+ return;
+ }
- message_data.arguments.push_back(data);
+ TabContents* tab_contents = GetTabContents(id);
+ if (tab_contents == NULL) {
+ Send500(socket, "No such page id: " + page_id);
+ return;
+ }
- DevToolsManager* manager = DevToolsManager::GetInstance();
- manager->ForwardToDevToolsAgent(client_host_.get(),
- DevToolsAgentMsg_RpcMessage(DevToolsMessageData(message_data)));
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ if (manager->GetDevToolsClientHostFor(tab_contents->render_view_host())) {
+ Send500(socket, "Page with given id is being inspected: " + page_id);
+ return;
}
+
+ DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(socket);
+ socket_to_client_host_ui_[socket] = client_host;
+
+ manager->RegisterDevToolsClientHostFor(
+ tab_contents->render_view_host(),
+ client_host);
+ AcceptWebSocket(socket, request);
}
-void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) {
- SocketToRequestsMap::iterator it = socket_to_requests_.find(socket);
- if (it == socket_to_requests_.end())
+void DevToolsHttpProtocolHandler::OnWebSocketMessageUI(
+ HttpListenSocket* socket,
+ const std::string& data) {
+ SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket);
+ if (it == socket_to_client_host_ui_.end())
return;
- for (std::set<URLRequest*>::iterator it2 = it->second.begin();
- it2 != it->second.end(); ++it2) {
- URLRequest* request = *it2;
- request->Cancel();
- request_to_socket_.erase(request);
- request_to_buffer_.erase(request);
- delete request;
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+
+ if (data == "loaded") {
+ manager->ForwardToDevToolsAgent(
+ it->second,
+ DevToolsAgentMsg_FrontendLoaded());
+ return;
}
- socket_to_requests_.erase(socket);
+
+ manager->ForwardToDevToolsAgent(
+ it->second,
+ DevToolsAgentMsg_DispatchOnInspectorBackend(data));
+}
+
+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);
}
void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
- RequestToSocketMap::iterator it = request_to_socket_.find(request);
- if (it == request_to_socket_.end())
+ RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
+ if (it == request_to_socket_io_.end())
return;
HttpListenSocket* socket = it->second;
@@ -178,9 +289,7 @@ void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
content_type.c_str(),
expected_size));
} else {
- socket->Send("HTTP/1.1 404 Not Found\r\n"
- "Content-Length: 0\r\n"
- "\r\n");
+ socket->Send404();
}
int bytes_read = 0;
@@ -188,7 +297,7 @@ void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
// network connection as soon as possible, signal that the request has
// completed immediately, without trying to read any data back (all we care
// about is the response code and headers, which we already have).
- net::IOBuffer* buffer = request_to_buffer_[request].get();
+ net::IOBuffer* buffer = request_to_buffer_io_[request].get();
if (request->status().is_success())
request->Read(buffer, kBufferSize, &bytes_read);
OnReadCompleted(request, bytes_read);
@@ -196,13 +305,13 @@ void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
void DevToolsHttpProtocolHandler::OnReadCompleted(URLRequest* request,
int bytes_read) {
- RequestToSocketMap::iterator it = request_to_socket_.find(request);
- if (it == request_to_socket_.end())
+ RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
+ if (it == request_to_socket_io_.end())
return;
HttpListenSocket* socket = it->second;
- net::IOBuffer* buffer = request_to_buffer_[request].get();
+ net::IOBuffer* buffer = request_to_buffer_io_[request].get();
do {
if (!request->status().is_success() || bytes_read <= 0)
break;
@@ -230,27 +339,78 @@ void DevToolsHttpProtocolHandler::Teardown() {
void DevToolsHttpProtocolHandler::Bind(URLRequest* request,
HttpListenSocket* socket) {
- request_to_socket_[request] = socket;
- SocketToRequestsMap::iterator it = socket_to_requests_.find(socket);
- if (it == socket_to_requests_.end()) {
+ 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(
socket,
std::set<URLRequest*>());
- it = socket_to_requests_.insert(value).first;
+ it = socket_to_requests_io_.insert(value).first;
}
it->second.insert(request);
- request_to_buffer_[request] = new net::IOBuffer(kBufferSize);
+ request_to_buffer_io_[request] = new net::IOBuffer(kBufferSize);
}
void DevToolsHttpProtocolHandler::RequestCompleted(URLRequest* request) {
- RequestToSocketMap::iterator it = request_to_socket_.find(request);
- if (it == request_to_socket_.end())
+ RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
+ if (it == request_to_socket_io_.end())
return;
HttpListenSocket* socket = it->second;
- request_to_socket_.erase(request);
- SocketToRequestsMap::iterator it2 = socket_to_requests_.find(socket);
+ request_to_socket_io_.erase(request);
+ SocketToRequestsMap::iterator it2 = socket_to_requests_io_.find(socket);
it2->second.erase(request);
- request_to_buffer_.erase(request);
+ request_to_buffer_io_.erase(request);
delete request;
}
+
+void DevToolsHttpProtocolHandler::Send200(HttpListenSocket* socket,
+ const std::string& data,
+ const std::string& mime_type) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(socket,
+ &HttpListenSocket::Send200,
+ data,
+ mime_type));
+}
+
+void DevToolsHttpProtocolHandler::Send404(HttpListenSocket* socket) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(socket,
+ &HttpListenSocket::Send404));
+}
+
+void DevToolsHttpProtocolHandler::Send500(HttpListenSocket* socket,
+ const std::string& message) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(socket,
+ &HttpListenSocket::Send500,
+ message));
+}
+
+void DevToolsHttpProtocolHandler::AcceptWebSocket(
+ HttpListenSocket* socket,
+ const HttpServerRequestInfo& request) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(socket,
+ &HttpListenSocket::AcceptWebSocket,
+ request));
+}
+
+TabContents* DevToolsHttpProtocolHandler::GetTabContents(int session_id) {
+ for (BrowserList::const_iterator it = BrowserList::begin(),
+ end = BrowserList::end(); it != end; ++it) {
+ TabStripModel* model = (*it)->tabstrip_model();
+ for (int i = 0, size = model->count(); i < size; ++i) {
+ NavigationController& controller =
+ model->GetTabContentsAt(i)->controller();
+ if (controller.session_id().id() == session_id)
+ return controller.tab_contents();
+ }
+ }
+ return NULL;
+}
diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.h b/chrome/browser/debugger/devtools_http_protocol_handler.h
index 14163d5..332fbaa 100644
--- a/chrome/browser/debugger/devtools_http_protocol_handler.h
+++ b/chrome/browser/debugger/devtools_http_protocol_handler.h
@@ -4,17 +4,18 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_HTTP_PROTOCOL_HANDLER_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_HTTP_PROTOCOL_HANDLER_H_
+#pragma once
#include <set>
#include <string>
#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "net/server/http_listen_socket.h"
#include "net/url_request/url_request.h"
class DevToolsClientHost;
class DevToolsHttpServer;
+class TabContents;
class DevToolsHttpProtocolHandler
: public HttpListenSocket::Delegate,
@@ -29,41 +30,61 @@ class DevToolsHttpProtocolHandler
// This method should be called before the object destruction.
void Stop();
+ private:
+ friend class base::RefCountedThreadSafe<DevToolsHttpProtocolHandler>;
+ virtual ~DevToolsHttpProtocolHandler();
+
// HttpListenSocket::Delegate implementation.
virtual void OnHttpRequest(HttpListenSocket* socket,
- HttpServerRequestInfo* info);
+ const HttpServerRequestInfo& info);
virtual void OnWebSocketRequest(HttpListenSocket* socket,
- HttpServerRequestInfo* info);
+ const HttpServerRequestInfo& info);
virtual void OnWebSocketMessage(HttpListenSocket* socket,
const std::string& data);
virtual void OnClose(HttpListenSocket* socket);
+ virtual void OnHttpRequestUI(HttpListenSocket* socket,
+ const HttpServerRequestInfo& info);
+ virtual void OnWebSocketRequestUI(HttpListenSocket* socket,
+ const HttpServerRequestInfo& info);
+ virtual void OnWebSocketMessageUI(HttpListenSocket* socket,
+ 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);
- private:
- friend class base::RefCountedThreadSafe<DevToolsHttpProtocolHandler>;
- virtual ~DevToolsHttpProtocolHandler();
-
void Init();
void Teardown();
void Bind(URLRequest* request, HttpListenSocket* socket);
void RequestCompleted(URLRequest* request);
- void OnWebSocketMessageUI(HttpListenSocket* socket, const std::string& data);
+
+ void Send200(HttpListenSocket* socket,
+ const std::string& data,
+ const std::string& mime_type = "text/html");
+ void Send404(HttpListenSocket* socket);
+ void Send500(HttpListenSocket* socket,
+ const std::string& message);
+ void AcceptWebSocket(HttpListenSocket* socket,
+ const HttpServerRequestInfo& request);
+
+ TabContents* GetTabContents(int session_id);
int port_;
scoped_refptr<HttpListenSocket> server_;
typedef std::map<URLRequest*, HttpListenSocket*>
RequestToSocketMap;
- RequestToSocketMap request_to_socket_;
+ RequestToSocketMap request_to_socket_io_;
typedef std::map<HttpListenSocket*, std::set<URLRequest*> >
SocketToRequestsMap;
- SocketToRequestsMap socket_to_requests_;
+ SocketToRequestsMap socket_to_requests_io_;
typedef std::map<URLRequest*, scoped_refptr<net::IOBuffer> >
BuffersMap;
- BuffersMap request_to_buffer_;
- scoped_ptr<DevToolsClientHost> client_host_;
+ BuffersMap request_to_buffer_io_;
+ typedef std::map<HttpListenSocket*, DevToolsClientHost*>
+ SocketToClientHostMap;
+ SocketToClientHostMap socket_to_client_host_ui_;
DISALLOW_COPY_AND_ASSIGN(DevToolsHttpProtocolHandler);
};
diff --git a/chrome/browser/debugger/devtools_manager.cc b/chrome/browser/debugger/devtools_manager.cc
index 6b958cc..5116d85 100644
--- a/chrome/browser/debugger/devtools_manager.cc
+++ b/chrome/browser/debugger/devtools_manager.cc
@@ -13,12 +13,11 @@
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/debugger/devtools_client_host.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/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/devtools_messages.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
@@ -64,8 +63,8 @@ void DevToolsManager::RegisterDevToolsClientHostFor(
DevToolsClientHost* client_host) {
DCHECK(!GetDevToolsClientHostFor(inspected_rvh));
- RuntimeFeatures initial_features;
- BindClientHost(inspected_rvh, client_host, initial_features);
+ DevToolsRuntimeProperties initial_properties;
+ BindClientHost(inspected_rvh, client_host, initial_properties);
client_host->set_close_listener(this);
SendAttachToAgent(inspected_rvh);
}
@@ -143,29 +142,28 @@ void DevToolsManager::ToggleDevToolsWindow(
ToggleDevToolsWindow(inspected_rvh, false, action);
}
-void DevToolsManager::RuntimeFeatureStateChanged(RenderViewHost* inspected_rvh,
- const std::string& feature,
- bool enabled) {
- RuntimeFeaturesMap::iterator it = runtime_features_map_.find(inspected_rvh);
- if (it == runtime_features_map_.end()) {
- std::pair<RenderViewHost*, std::set<std::string> > value(
+void DevToolsManager::RuntimePropertyChanged(RenderViewHost* inspected_rvh,
+ const std::string& name,
+ const std::string& value) {
+ RuntimePropertiesMap::iterator it = runtime_properties_map_.find(inspected_rvh);
+ if (it == runtime_properties_map_.end()) {
+ std::pair<RenderViewHost*, DevToolsRuntimeProperties> value(
inspected_rvh,
- std::set<std::string>());
- it = runtime_features_map_.insert(value).first;
+ DevToolsRuntimeProperties());
+ it = runtime_properties_map_.insert(value).first;
}
- if (enabled)
- it->second.insert(feature);
- else
- it->second.erase(feature);
+ it->second[name] = value;
}
void DevToolsManager::InspectElement(RenderViewHost* inspected_rvh,
int x,
int y) {
- OpenDevToolsWindow(inspected_rvh);
IPC::Message* m = new DevToolsAgentMsg_InspectElement(x, y);
m->set_routing_id(inspected_rvh->routing_id());
inspected_rvh->Send(m);
+ // TODO(loislo): we should initiate DevTools window opening from within
+ // renderer. Otherwise, we still can hit a race condition here.
+ OpenDevToolsWindow(inspected_rvh);
}
void DevToolsManager::ClientHostClosing(DevToolsClientHost* host) {
@@ -265,8 +263,8 @@ int DevToolsManager::DetachClientHost(RenderViewHost* from_rvh) {
int cookie = last_orphan_cookie_++;
orphan_client_hosts_[cookie] =
- std::pair<DevToolsClientHost*, RuntimeFeatures>(
- client_host, runtime_features_map_[from_rvh]);
+ std::pair<DevToolsClientHost*, DevToolsRuntimeProperties>(
+ client_host, runtime_properties_map_[from_rvh]);
UnbindClientHost(from_rvh, client_host);
return cookie;
@@ -291,14 +289,14 @@ void DevToolsManager::SendAttachToAgent(RenderViewHost* inspected_rvh) {
ChildProcessSecurityPolicy::GetInstance()->GrantReadRawCookies(
inspected_rvh->process()->id());
- std::vector<std::string> features;
- RuntimeFeaturesMap::iterator it =
- runtime_features_map_.find(inspected_rvh);
- if (it != runtime_features_map_.end()) {
- features = std::vector<std::string>(it->second.begin(),
- it->second.end());
+ DevToolsRuntimeProperties properties;
+ RuntimePropertiesMap::iterator it =
+ runtime_properties_map_.find(inspected_rvh);
+ if (it != runtime_properties_map_.end()) {
+ properties = DevToolsRuntimeProperties(it->second.begin(),
+ it->second.end());
}
- IPC::Message* m = new DevToolsAgentMsg_Attach(features);
+ IPC::Message* m = new DevToolsAgentMsg_Attach(properties);
m->set_routing_id(inspected_rvh->routing_id());
inspected_rvh->Send(m);
}
@@ -379,9 +377,10 @@ void DevToolsManager::ToggleDevToolsWindow(
}
}
-void DevToolsManager::BindClientHost(RenderViewHost* inspected_rvh,
- DevToolsClientHost* client_host,
- const RuntimeFeatures& runtime_features) {
+void DevToolsManager::BindClientHost(
+ RenderViewHost* inspected_rvh,
+ DevToolsClientHost* client_host,
+ const DevToolsRuntimeProperties& runtime_properties) {
DCHECK(inspected_rvh_to_client_host_.find(inspected_rvh) ==
inspected_rvh_to_client_host_.end());
DCHECK(client_host_to_inspected_rvh_.find(client_host) ==
@@ -389,7 +388,7 @@ void DevToolsManager::BindClientHost(RenderViewHost* inspected_rvh,
inspected_rvh_to_client_host_[inspected_rvh] = client_host;
client_host_to_inspected_rvh_[client_host] = inspected_rvh;
- runtime_features_map_[inspected_rvh] = runtime_features;
+ runtime_properties_map_[inspected_rvh] = runtime_properties;
}
void DevToolsManager::UnbindClientHost(RenderViewHost* inspected_rvh,
@@ -401,5 +400,5 @@ void DevToolsManager::UnbindClientHost(RenderViewHost* inspected_rvh,
inspected_rvh_to_client_host_.erase(inspected_rvh);
client_host_to_inspected_rvh_.erase(client_host);
- runtime_features_map_.erase(inspected_rvh);
+ runtime_properties_map_.erase(inspected_rvh);
}
diff --git a/chrome/browser/debugger/devtools_manager.h b/chrome/browser/debugger/devtools_manager.h
index 20835af..1c60a4d 100644
--- a/chrome/browser/debugger/devtools_manager.h
+++ b/chrome/browser/debugger/devtools_manager.h
@@ -1,17 +1,18 @@
-// 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.
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_MANAGER_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_MANAGER_H_
+#pragma once
#include <map>
-#include <set>
#include <string>
#include "base/ref_counted.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
+#include "chrome/common/devtools_messages.h"
namespace IPC {
class Message;
@@ -57,9 +58,9 @@ class DevToolsManager : public DevToolsClientHost::CloseListener,
void OpenDevToolsWindow(RenderViewHost* inspected_rvh);
void ToggleDevToolsWindow(RenderViewHost* inspected_rvh,
DevToolsToggleAction action);
- void RuntimeFeatureStateChanged(RenderViewHost* inspected_rvh,
- const std::string& feature,
- bool enabled);
+ void RuntimePropertyChanged(RenderViewHost* inspected_rvh,
+ const std::string& name,
+ const std::string& value);
// Starts element inspection in the devtools client.
// Creates one by means of OpenDevToolsWindow if no client
@@ -82,7 +83,6 @@ class DevToolsManager : public DevToolsClientHost::CloseListener,
private:
friend class base::RefCounted<DevToolsManager>;
- typedef std::set<std::string> RuntimeFeatures;
virtual ~DevToolsManager();
@@ -111,7 +111,7 @@ class DevToolsManager : public DevToolsClientHost::CloseListener,
void BindClientHost(RenderViewHost* inspected_rvh,
DevToolsClientHost* client_host,
- const RuntimeFeatures& runtime_features);
+ const DevToolsRuntimeProperties& runtime_properties);
void UnbindClientHost(RenderViewHost* inspected_rvh,
DevToolsClientHost* client_host);
@@ -132,14 +132,15 @@ class DevToolsManager : public DevToolsClientHost::CloseListener,
ClientHostToInspectedRvhMap;
ClientHostToInspectedRvhMap client_host_to_inspected_rvh_;
- typedef std::map<RenderViewHost*, RuntimeFeatures>
- RuntimeFeaturesMap;
- RuntimeFeaturesMap runtime_features_map_;
+ typedef std::map<RenderViewHost*, DevToolsRuntimeProperties>
+ RuntimePropertiesMap;
+ RuntimePropertiesMap runtime_properties_map_;
RenderViewHost* inspected_rvh_for_reopen_;
bool in_initial_show_;
- typedef std::map<int, std::pair<DevToolsClientHost*, RuntimeFeatures> >
+ typedef std::map<int,
+ std::pair<DevToolsClientHost*, DevToolsRuntimeProperties> >
OrphanClientHosts;
OrphanClientHosts orphan_client_hosts_;
int last_orphan_cookie_;
diff --git a/chrome/browser/debugger/devtools_protocol_handler.h b/chrome/browser/debugger/devtools_protocol_handler.h
index fff65eb..92889cc 100644
--- a/chrome/browser/debugger/devtools_protocol_handler.h
+++ b/chrome/browser/debugger/devtools_protocol_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_PROTOCOL_HANDLER_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_PROTOCOL_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/debugger/devtools_remote.h b/chrome/browser/debugger/devtools_remote.h
index a0edc6d..9c7953b 100644
--- a/chrome/browser/debugger/devtools_remote.h
+++ b/chrome/browser/debugger/devtools_remote.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_H_
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
diff --git a/chrome/browser/debugger/devtools_remote_listen_socket.cc b/chrome/browser/debugger/devtools_remote_listen_socket.cc
index 87b88d0..bce2ba4 100644
--- a/chrome/browser/debugger/devtools_remote_listen_socket.cc
+++ b/chrome/browser/debugger/devtools_remote_listen_socket.cc
@@ -20,9 +20,10 @@
#include "net/base/net_errors.h"
#endif
+#include "base/compiler_specific.h"
#include "base/eintr_wrapper.h"
#include "base/platform_thread.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/debugger/devtools_remote.h"
#include "chrome/browser/debugger/devtools_remote_message.h"
@@ -60,7 +61,7 @@ void DevToolsRemoteListenSocket::StartNextField() {
if (protocol_field_.size() == 0) { // empty line - end of headers
const std::string& payload_length_string = GetHeader(
DevToolsRemoteMessageHeaders::kContentLength, "0");
- remaining_payload_length_ = StringToInt(payload_length_string);
+ base::StringToInt(payload_length_string, &remaining_payload_length_);
state_ = PAYLOAD;
if (remaining_payload_length_ == 0) { // no payload
DispatchField();
diff --git a/chrome/browser/debugger/devtools_remote_listen_socket.h b/chrome/browser/debugger/devtools_remote_listen_socket.h
index 9424a76..5497861 100644
--- a/chrome/browser/debugger/devtools_remote_listen_socket.h
+++ b/chrome/browser/debugger/devtools_remote_listen_socket.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_LISTEN_SOCKET_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_LISTEN_SOCKET_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/debugger/devtools_remote_listen_socket_unittest.h b/chrome/browser/debugger/devtools_remote_listen_socket_unittest.h
index b839cc7..56835eb 100644
--- a/chrome/browser/debugger/devtools_remote_listen_socket_unittest.h
+++ b/chrome/browser/debugger/devtools_remote_listen_socket_unittest.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_LISTEN_SOCKET_UNITTEST_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_LISTEN_SOCKET_UNITTEST_H_
+#pragma once
#include "build/build_config.h"
@@ -22,7 +23,6 @@
#include "base/thread.h"
#include "base/basictypes.h"
#include "base/message_loop.h"
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/thread.h"
diff --git a/chrome/browser/debugger/devtools_remote_message.cc b/chrome/browser/debugger/devtools_remote_message.cc
index 97c6875..eb63009 100644
--- a/chrome/browser/debugger/devtools_remote_message.cc
+++ b/chrome/browser/debugger/devtools_remote_message.cc
@@ -1,10 +1,11 @@
-// 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.
-#include "base/string_util.h"
#include "chrome/browser/debugger/devtools_remote_message.h"
+#include "base/string_number_conversions.h"
+
const char DevToolsRemoteMessageHeaders::kContentLength[] = "Content-Length";
const char DevToolsRemoteMessageHeaders::kTool[] = "Tool";
const char DevToolsRemoteMessageHeaders::kDestination[] = "Destination";
@@ -47,7 +48,7 @@ DevToolsRemoteMessage* DevToolsRemoteMessageBuilder::Create(
const std::string& content) {
DevToolsRemoteMessage::HeaderMap headers;
headers[DevToolsRemoteMessageHeaders::kContentLength] =
- IntToString(content.size());
+ base::IntToString(content.size());
headers[DevToolsRemoteMessageHeaders::kTool] = tool;
headers[DevToolsRemoteMessageHeaders::kDestination] = destination;
return new DevToolsRemoteMessage(headers, content);
diff --git a/chrome/browser/debugger/devtools_remote_message.h b/chrome/browser/debugger/devtools_remote_message.h
index 0fa5e97..bea9ae5 100644
--- a/chrome/browser/debugger/devtools_remote_message.h
+++ b/chrome/browser/debugger/devtools_remote_message.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_MESSAGE_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_MESSAGE_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/debugger/devtools_remote_message_unittest.cc b/chrome/browser/debugger/devtools_remote_message_unittest.cc
index bc84a4c..0b74e3f 100644
--- a/chrome/browser/debugger/devtools_remote_message_unittest.cc
+++ b/chrome/browser/debugger/devtools_remote_message_unittest.cc
@@ -1,18 +1,18 @@
-// 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.
#include <string>
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/debugger/devtools_remote.h"
#include "chrome/browser/debugger/devtools_remote_message.h"
#include "testing/gtest/include/gtest/gtest.h"
class DevToolsRemoteMessageTest : public testing::Test {
public:
- DevToolsRemoteMessageTest() : testing::Test() {
- }
+ DevToolsRemoteMessageTest() : testing::Test() {}
protected:
virtual void SetUp() {
@@ -25,7 +25,7 @@ TEST_F(DevToolsRemoteMessageTest, ConstructInstanceManually) {
std::string content = "{\"command\":\"ping\"}";
headers[DevToolsRemoteMessageHeaders::kTool] = "DevToolsService";
headers[DevToolsRemoteMessageHeaders::kContentLength] =
- IntToString(content.size());
+ base::IntToString(content.size());
DevToolsRemoteMessage message(headers, content);
ASSERT_STREQ("DevToolsService",
@@ -41,11 +41,11 @@ TEST_F(DevToolsRemoteMessageTest, ConstructInstanceManually) {
TEST_F(DevToolsRemoteMessageTest, ConstructWithBuilder) {
std::string content = "Responsecontent";
- testing::internal::scoped_ptr<DevToolsRemoteMessage> message(
+ scoped_ptr<DevToolsRemoteMessage> message(
DevToolsRemoteMessageBuilder::instance().Create(
"V8Debugger", // tool
- "2", // destination
- content)); // content
+ "2", // destination
+ content)); // content
ASSERT_EQ(static_cast<DevToolsRemoteMessage::HeaderMap::size_type>(3),
message->headers().size());
diff --git a/chrome/browser/debugger/devtools_remote_service.cc b/chrome/browser/debugger/devtools_remote_service.cc
index 3f786af9..d67174c 100644
--- a/chrome/browser/debugger/devtools_remote_service.cc
+++ b/chrome/browser/debugger/devtools_remote_service.cc
@@ -16,14 +16,17 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/devtools_messages.h"
-const std::string DevToolsRemoteServiceCommand::kPing = "ping";
-const std::string DevToolsRemoteServiceCommand::kVersion = "version";
-const std::string DevToolsRemoteServiceCommand::kListTabs = "list_tabs";
+const char DevToolsRemoteServiceCommand::kPing[] = "ping";
+const char DevToolsRemoteServiceCommand::kVersion[] = "version";
+const char DevToolsRemoteServiceCommand::kListTabs[] = "list_tabs";
-const std::wstring DevToolsRemoteService::kCommandWide = L"command";
-const std::wstring DevToolsRemoteService::kDataWide = L"data";
-const std::wstring DevToolsRemoteService::kResultWide = L"result";
-const std::string DevToolsRemoteService::kToolName = "DevToolsService";
+const char DevToolsRemoteService::kToolName[] = "DevToolsService";
+
+namespace {
+const char kCommandKey[] = "command";
+const char kDataKey[] = "data";
+const char kResultKey[] = "result";
+} // namespace
DevToolsRemoteService::DevToolsRemoteService(DevToolsProtocolHandler* delegate)
: delegate_(delegate) {}
@@ -41,7 +44,7 @@ void DevToolsRemoteService::HandleMessage(
DictionaryValue* json;
if (request->IsType(Value::TYPE_DICTIONARY)) {
json = static_cast<DictionaryValue*>(request.get());
- if (!json->HasKey(kCommandWide)) {
+ if (!json->HasKey(kCommandKey)) {
NOTREACHED(); // Broken protocol - no "command" specified
return;
}
@@ -59,15 +62,15 @@ void DevToolsRemoteService::ProcessJson(DictionaryValue* json,
std::string command;
DictionaryValue response;
- json->GetString(kCommandWide, &command);
- response.SetString(kCommandWide, command);
+ json->GetString(kCommandKey, &command);
+ response.SetString(kCommandKey, command);
if (command == DevToolsRemoteServiceCommand::kPing) {
- response.SetInteger(kResultWide, Result::kOk);
- response.SetString(kDataWide, kOkResponse);
+ response.SetInteger(kResultKey, Result::kOk);
+ response.SetString(kDataKey, kOkResponse);
} else if (command == DevToolsRemoteServiceCommand::kVersion) {
- response.SetInteger(kResultWide, Result::kOk);
- response.SetString(kDataWide, kVersion);
+ response.SetInteger(kResultKey, Result::kOk);
+ response.SetString(kDataKey, kVersion);
} else if (command == DevToolsRemoteServiceCommand::kListTabs) {
ListValue* data = new ListValue();
const InspectableTabProxy::ControllersMap& navcon_map =
@@ -86,12 +89,12 @@ void DevToolsRemoteService::ProcessJson(DictionaryValue* json,
data->Append(tab);
}
}
- response.SetInteger(kResultWide, Result::kOk);
- response.Set(kDataWide, data);
+ response.SetInteger(kResultKey, Result::kOk);
+ response.Set(kDataKey, data);
} else {
// Unknown protocol command.
NOTREACHED();
- response.SetInteger(kResultWide, Result::kUnknownCommand);
+ response.SetInteger(kResultKey, Result::kUnknownCommand);
}
std::string response_json;
base::JSONWriter::Write(&response, false, &response_json);
diff --git a/chrome/browser/debugger/devtools_remote_service.h b/chrome/browser/debugger/devtools_remote_service.h
index 68518ef..bd813bd 100644
--- a/chrome/browser/debugger/devtools_remote_service.h
+++ b/chrome/browser/debugger/devtools_remote_service.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_SERVICE_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_REMOTE_SERVICE_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/debugger/devtools_remote.h"
@@ -17,9 +16,9 @@ class Value;
// Contains constants for DevToolsRemoteService tool protocol commands.
struct DevToolsRemoteServiceCommand {
- static const std::string kPing;
- static const std::string kVersion;
- static const std::string kListTabs;
+ static const char kPing[];
+ static const char kVersion[];
+ static const char kListTabs[];
};
// Handles Chrome remote debugger protocol service commands.
@@ -31,7 +30,7 @@ class DevToolsRemoteService : public DevToolsRemoteListener {
virtual void HandleMessage(const DevToolsRemoteMessage& message);
virtual void OnConnectionLost() {}
- static const std::string kToolName;
+ static const char kToolName[];
private:
// Operation result returned in the "result" field.
@@ -41,9 +40,6 @@ class DevToolsRemoteService : public DevToolsRemoteListener {
};
virtual ~DevToolsRemoteService();
void ProcessJson(DictionaryValue* json, const DevToolsRemoteMessage& message);
- static const std::wstring kCommandWide;
- static const std::wstring kDataWide;
- static const std::wstring kResultWide;
DevToolsProtocolHandler* delegate_;
DISALLOW_COPY_AND_ASSIGN(DevToolsRemoteService);
};
diff --git a/chrome/browser/debugger/devtools_sanity_unittest.cc b/chrome/browser/debugger/devtools_sanity_unittest.cc
index 346c545..dbaa4e2 100644
--- a/chrome/browser/debugger/devtools_sanity_unittest.cc
+++ b/chrome/browser/debugger/devtools_sanity_unittest.cc
@@ -1,8 +1,11 @@
-// 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.
#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
@@ -18,6 +21,7 @@
#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"
namespace {
@@ -47,11 +51,8 @@ const int kActionDelayMs = 500;
const char kConsoleTestPage[] = "files/devtools/console_test_page.html";
const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html";
-const char kEvalTestPage[] = "files/devtools/eval_test_page.html";
const char kJsPage[] = "files/devtools/js_page.html";
const char kHeapProfilerPage[] = "files/devtools/heap_profiler.html";
-const char kPauseOnExceptionTestPage[] =
- "files/devtools/pause_on_exception.html";
const char kPauseWhenLoadingDevTools[] =
"files/devtools/pause_when_loading_devtools.html";
const char kPauseWhenScriptIsRunning[] =
@@ -59,14 +60,6 @@ const char kPauseWhenScriptIsRunning[] =
const char kResourceContentLengthTestPage[] = "files/devtools/image.html";
const char kResourceTestPage[] = "files/devtools/resource_test_page.html";
const char kSimplePage[] = "files/devtools/simple_page.html";
-const char kSyntaxErrorTestPage[] =
- "files/devtools/script_syntax_error.html";
-const char kDebuggerStepTestPage[] =
- "files/devtools/debugger_step.html";
-const char kDebuggerClosurePage[] =
- "files/devtools/debugger_closure.html";
-const char kDebuggerIntrinsicPropertiesPage[] =
- "files/devtools/debugger_intrinsic_properties.html";
const char kCompletionOnPause[] =
"files/devtools/completion_on_pause.html";
const char kPageWithContentScript[] =
@@ -112,8 +105,8 @@ class DevToolsSanityTest : public InProcessBrowserTest {
}
void OpenDevToolsWindow(const std::string& test_page) {
- HTTPTestServer* server = StartHTTPServer();
- GURL url = server->TestServerPage(test_page);
+ ASSERT_TRUE(test_server()->Start());
+ GURL url = test_server()->GetURL(test_page);
ui_test_utils::NavigateToURL(browser(), url);
inspected_rvh_ = GetInspectedTab()->render_view_host();
@@ -261,21 +254,6 @@ class DevToolsExtensionDebugTest : public DevToolsSanityTest,
FilePath test_extensions_dir_;
};
-// WebInspector opens.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHostIsPresent) {
- RunTest("testHostIsPresent", kSimplePage);
-}
-
-// Tests elements panel basics.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestElementsTreeRoot) {
- RunTest("testElementsTreeRoot", kSimplePage);
-}
-
-// Tests main resource load.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMainResource) {
- RunTest("testMainResource", kSimplePage);
-}
-
// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEnableResourcesTab) {
RunTest("testEnableResourcesTab", kSimplePage);
@@ -345,16 +323,6 @@ IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}
-// Tests set breakpoint.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestSetBreakpoint) {
- RunTest("testSetBreakpoint", kDebuggerTestPage);
-}
-
-// Tests pause on exception.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseOnException) {
- RunTest("testPauseOnException", kPauseOnExceptionTestPage);
-}
-
// Tests that debugger works correctly if pause event occurs when DevTools
// frontend is being loaded.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) {
@@ -367,79 +335,13 @@ IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) {
RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
}
-// Tests eval on call frame.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalOnCallFrame) {
- RunTest("testEvalOnCallFrame", kDebuggerTestPage);
-}
-
-#if defined(OS_WIN) || defined(OS_LINUX)
-// Sometimes it times out.
-// See http://crbug.com/45080
-// See http://crbug.com/46299
-#define MAYBE_TestStepOver FLAKY_TestStepOver
-#else
-#define MAYBE_TestStepOver TestStepOver
-#endif
-// Tests step over functionality in the debugger.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestStepOver) {
- RunTest("testStepOver", kDebuggerStepTestPage);
-}
-
-#if defined(OS_WIN) || defined(OS_LINUX)
-// Sometimes it times out.
-// See http://crbug.com/45080
-// See http://crbug.com/46299
-#define MAYBE_TestStepOut FLAKY_TestStepOut
-#elif defined(OS_CHROMEOS)
-// See http://crbug.com/43479
-#define MAYBE_TestStepOut FLAKY_TestStepOut
-#else
-#define MAYBE_TestStepOut TestStepOut
-#endif
-// Tests step out functionality in the debugger.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestStepOut) {
- RunTest("testStepOut", kDebuggerStepTestPage);
-}
-
-#if defined(OS_WIN) || defined(OS_LINUX)
-// Sometimes it times out.
-// See http://crbug.com/45080
-// See http://crbug.com/46299
-#define MAYBE_TestStepIn FLAKY_TestStepIn
-#elif defined(OS_CHROMEOS)
-// See http://crbug.com/43479
-#define MAYBE_TestStepIn FLAKY_TestStepIn
+// Fails after WebKit roll 66724:66804, http://crbug.com/54592
+#if defined(OS_LINUX) || defined(OS_WIN)
+#define MAYBE_TestCompletionOnPause FAILS_TestCompletionOnPause
#else
-#define MAYBE_TestStepIn TestStepIn
-#endif
-// Disable TestStepIn completely while test expectations are not updated
-// in Webkit. See http://crbug.com/46235
-#undef MAYBE_TestStepIn
-#define MAYBE_TestStepIn DISABLED_TestStepIn
-
-// Tests step in functionality in the debugger.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestStepIn) {
- RunTest("testStepIn", kDebuggerStepTestPage);
-}
-
-// Tests that scope can be expanded and contains expected variables.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestExpandScope) {
- RunTest("testExpandScope", kDebuggerClosurePage);
-}
-
-// Tests that intrinsic properties(__proto__, prototype, constructor) are
-// present.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDebugIntrinsicProperties) {
- RunTest("testDebugIntrinsicProperties", kDebuggerIntrinsicPropertiesPage);
-}
-
-// Tests that execution continues automatically when there is a syntax error in
-// script and DevTools are open.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestAutoContinueOnSyntaxError) {
- RunTest("testAutoContinueOnSyntaxError", kSyntaxErrorTestPage);
-}
-
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCompletionOnPause) {
+#define MAYBE_TestCompletionOnPause TestCompletionOnPause
+#endif // defined(OS_LINUX) || defined(OS_WIN)
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestCompletionOnPause) {
RunTest("testCompletionOnPause", kCompletionOnPause);
}
@@ -448,28 +350,4 @@ IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) {
RunTest("testPauseInEval", kDebuggerTestPage);
}
-// Tests console eval.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleEval) {
- RunTest("testConsoleEval", kEvalTestPage);
-}
-
-// Tests console log.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleLog) {
- RunTest("testConsoleLog", kConsoleTestPage);
-}
-
-// Tests eval global values.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalGlobal) {
- RunTest("testEvalGlobal", kEvalTestPage);
-}
-
-// Test that Storage panel can be shown.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowStoragePanel) {
- RunTest("testShowStoragePanel", kDebuggerTestPage);
-}
-
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMessageLoopReentrant) {
- RunTest("testMessageLoopReentrant", kDebuggerTestPage);
-}
-
} // namespace
diff --git a/chrome/browser/debugger/devtools_toggle_action.h b/chrome/browser/debugger/devtools_toggle_action.h
index a8c4c53..33b0321 100644
--- a/chrome/browser/debugger/devtools_toggle_action.h
+++ b/chrome/browser/debugger/devtools_toggle_action.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_TOGGLE_ACTION_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_TOGGLE_ACTION_H_
+#pragma once
enum DevToolsToggleAction {
DEVTOOLS_TOGGLE_ACTION_NONE,
diff --git a/chrome/browser/debugger/devtools_window.cc b/chrome/browser/debugger/devtools_window.cc
index fc74431..a185444 100644
--- a/chrome/browser/debugger/devtools_window.cc
+++ b/chrome/browser/debugger/devtools_window.cc
@@ -1,17 +1,22 @@
-// 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.
-#include "app/l10n_util.h"
#include "base/command_line.h"
+#include "base/json/json_writer.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/extensions/extensions_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/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
@@ -19,6 +24,7 @@
#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/themes/browser_theme_provider.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -26,7 +32,7 @@
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
-const std::wstring DevToolsWindow::kDevToolsApp = L"DevToolsApp";
+const char DevToolsWindow::kDevToolsApp[] = "DevToolsApp";
// static
TabContents* DevToolsWindow::GetDevToolsContents(TabContents* inspected_tab) {
@@ -59,7 +65,7 @@ DevToolsWindow::DevToolsWindow(Profile* profile,
is_loaded_(false),
action_on_load_(DEVTOOLS_TOGGLE_ACTION_NONE) {
// Create TabContents with devtools.
- tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL);
+ tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL, NULL);
tab_contents_->render_view_host()->AllowBindings(BindingsPolicy::DOM_UI);
tab_contents_->controller().LoadURL(
GetDevToolsUrl(), GURL(), PageTransition::START_PAGE);
@@ -133,13 +139,14 @@ void DevToolsWindow::Show(DevToolsToggleAction action) {
}
}
- if (!browser_)
- CreateDevToolsBrowser();
-
// Avoid consecutive window switching if the devtools window has been opened
// and the Inspect Element shortcut is pressed in the inspected tab.
bool should_show_window =
!browser_ || action != DEVTOOLS_TOGGLE_ACTION_INSPECT;
+
+ if (!browser_)
+ CreateDevToolsBrowser();
+
if (should_show_window)
browser_->window()->Show();
SetAttachedWindow();
@@ -194,9 +201,9 @@ RenderViewHost* DevToolsWindow::GetRenderViewHost() {
void DevToolsWindow::CreateDevToolsBrowser() {
// TODO(pfeldman): Make browser's getter for this key static.
- std::wstring wp_key = L"";
+ std::string wp_key;
wp_key.append(prefs::kBrowserWindowPlacement);
- wp_key.append(L"_");
+ wp_key.append("_");
wp_key.append(kDevToolsApp);
PrefService* prefs = g_browser_process->local_state();
@@ -207,12 +214,12 @@ void DevToolsWindow::CreateDevToolsBrowser() {
const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str());
if (!wp_pref) {
DictionaryValue* defaults = prefs->GetMutableDictionary(wp_key.c_str());
- defaults->SetInteger(L"left", 100);
- defaults->SetInteger(L"top", 100);
- defaults->SetInteger(L"right", 740);
- defaults->SetInteger(L"bottom", 740);
- defaults->SetBoolean(L"maximized", false);
- defaults->SetBoolean(L"always_on_top", false);
+ defaults->SetInteger("left", 100);
+ defaults->SetInteger("top", 100);
+ defaults->SetInteger("right", 740);
+ defaults->SetInteger("bottom", 740);
+ defaults->SetBoolean("maximized", false);
+ defaults->SetBoolean("always_on_top", false);
}
browser_ = Browser::CreateForDevTools(profile_);
@@ -242,14 +249,43 @@ void DevToolsWindow::SetAttachedWindow() {
L"WebInspector.setAttachedWindow(false);");
}
+
+void DevToolsWindow::AddDevToolsExtensionsToClient() {
+ ListValue results;
+ const ExtensionsService* extension_service = tab_contents_->profile()->
+ GetOriginalProfile()->GetExtensionsService();
+ const ExtensionList* extensions = extension_service->extensions();
+
+ for (ExtensionList::const_iterator extension = extensions->begin();
+ extension != extensions->end(); ++extension) {
+ if ((*extension)->devtools_url().is_empty())
+ continue;
+ DictionaryValue* extension_info = new DictionaryValue();
+ extension_info->Set("startPage",
+ new StringValue((*extension)->devtools_url().spec()));
+ results.Append(extension_info);
+ }
+ CallClientFunction(L"WebInspector.addExtensions", results);
+}
+
+void DevToolsWindow::CallClientFunction(const std::wstring& function_name,
+ const Value& arg) {
+ std::string json;
+ base::JSONWriter::Write(&arg, false, &json);
+ std::wstring javascript = function_name + L"(" + UTF8ToWide(json) + L");";
+ tab_contents_->render_view_host()->
+ ExecuteJavascriptInWebFrame(L"", javascript);
+}
+
void DevToolsWindow::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type == NotificationType::LOAD_STOP) {
+ if (type == NotificationType::LOAD_STOP && !is_loaded_) {
SetAttachedWindow();
is_loaded_ = true;
UpdateTheme();
DoAction();
+ AddDevToolsExtensionsToClient();
} else if (type == NotificationType::TAB_CLOSING) {
if (Source<NavigationController>(source).ptr() ==
&tab_contents_->controller()) {
@@ -296,7 +332,7 @@ std::string SkColorToRGBAString(SkColor color) {
// locale specific formatters (e.g., use , instead of . in German).
return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color),
- DoubleToString(SkColorGetA(color) / 255.0).c_str());
+ base::DoubleToString(SkColorGetA(color) / 255.0).c_str());
}
GURL DevToolsWindow::GetDevToolsUrl() {
diff --git a/chrome/browser/debugger/devtools_window.h b/chrome/browser/debugger/devtools_window.h
index 0bdcd67..89914a6 100644
--- a/chrome/browser/debugger/devtools_window.h
+++ b/chrome/browser/debugger/devtools_window.h
@@ -1,17 +1,18 @@
-// 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.
#ifndef CHROME_BROWSER_DEBUGGER_DEVTOOLS_WINDOW_H_
#define CHROME_BROWSER_DEBUGGER_DEVTOOLS_WINDOW_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
#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"
@@ -24,13 +25,14 @@ class BrowserWindow;
class Profile;
class RenderViewHost;
class TabContents;
+class Value;
class DevToolsWindow
: public DevToolsClientHost,
public NotificationObserver,
public TabContentsDelegate {
public:
- static const std::wstring kDevToolsApp;
+ static const char kDevToolsApp[];
static TabContents* GetDevToolsContents(TabContents* inspected_tab);
DevToolsWindow(Profile* profile, RenderViewHost* inspected_rvh, bool docked);
@@ -64,7 +66,9 @@ class DevToolsWindow
void DoAction();
GURL GetDevToolsUrl();
void UpdateTheme();
-
+ void AddDevToolsExtensionsToClient();
+ void CallClientFunction(const std::wstring& function_name,
+ const Value& arg);
// Overridden from TabContentsDelegate.
virtual void OpenURLFromTab(TabContents* source,
const GURL& url,
@@ -79,10 +83,10 @@ class DevToolsWindow
const gfx::Rect& initial_pos,
bool user_gesture) {}
virtual void ActivateContents(TabContents* contents) {}
+ virtual void DeactivateContents(TabContents* contents) {}
virtual void LoadingStateChanged(TabContents* source) {}
virtual void CloseContents(TabContents* source) {}
virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
- virtual bool IsPopup(TabContents* source) { return false; }
virtual bool CanReloadContents(TabContents* source) const { return false; }
virtual void URLStarredChanged(TabContents* source, bool starred) {}
virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
diff --git a/chrome/browser/debugger/extension_ports_remote_service.cc b/chrome/browser/debugger/extension_ports_remote_service.cc
index d2a05ea..29cc11f 100644
--- a/chrome/browser/debugger/extension_ports_remote_service.cc
+++ b/chrome/browser/debugger/extension_ports_remote_service.cc
@@ -12,7 +12,7 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/devtools_manager.h"
@@ -25,6 +25,7 @@
#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"
namespace {
@@ -74,38 +75,38 @@ namespace {
// "data" field in this case.
// Commands:
-static const std::string kConnect = "connect";
-static const std::string kDisconnect = "disconnect";
-static const std::string kPostMessage = "postMessage";
+const char kConnect[] = "connect";
+const char kDisconnect[] = "disconnect";
+const char kPostMessage[] = "postMessage";
// Events:
-static const std::string kOnMessage = "onMessage";
-static const std::string kOnDisconnect = "onDisconnect";
+const char kOnMessage[] = "onMessage";
+const char kOnDisconnect[] = "onDisconnect";
// Constants for the JSON message fields.
// The type is wstring because the constant is used to get a
// DictionaryValue field (which requires a wide string).
// Mandatory.
-static const std::wstring kCommandWide = L"command";
+const char kCommandKey[] = "command";
// Always present in messages sent to the external client.
-static const std::wstring kResultWide = L"result";
+const char kResultKey[] = "result";
// Field for command-specific parameters. Not strictly necessary, but
// makes it more similar to the remote debugger protocol, which should
// allow easier reuse of client code.
-static const std::wstring kDataWide = L"data";
+const char kDataKey[] = "data";
// Fields within the "data" dictionary:
// Required for "connect":
-static const std::wstring kExtensionIdWide = L"extensionId";
+const char kExtensionIdKey[] = "extensionId";
// Optional in "connect":
-static const std::wstring kChannelNameWide = L"channelName";
-static const std::wstring kTabIdWide = L"tabId";
+const char kChannelNameKey[] = "channelName";
+const char kTabIdKey[] = "tabId";
// Present under "data" in replies to a successful "connect" .
-static const std::wstring kPortIdWide = L"portId";
+const char kPortIdKey[] = "portId";
} // namespace
@@ -137,10 +138,6 @@ ExtensionPortsRemoteService::ExtensionPortsRemoteService(
}
ExtensionPortsRemoteService::~ExtensionPortsRemoteService() {
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PORT_DELETED_DEBUG,
- Source<IPC::Message::Sender>(this),
- NotificationService::NoDetails());
}
void ExtensionPortsRemoteService::HandleMessage(
@@ -159,48 +156,48 @@ void ExtensionPortsRemoteService::HandleMessage(
return;
}
content = static_cast<DictionaryValue*>(request.get());
- if (!content->HasKey(kCommandWide)) {
+ if (!content->HasKey(kCommandKey)) {
NOTREACHED(); // Broken protocol :(
return;
}
std::string command;
DictionaryValue response;
- content->GetString(kCommandWide, &command);
- response.SetString(kCommandWide, command);
+ content->GetString(kCommandKey, &command);
+ response.SetString(kCommandKey, command);
if (!service_) {
// This happens if we failed to obtain an ExtensionMessageService
// during initialization.
NOTREACHED();
- response.SetInteger(kResultWide, RESULT_NO_SERVICE);
+ response.SetInteger(kResultKey, RESULT_NO_SERVICE);
SendResponse(response, message.tool(), message.destination());
return;
}
int destination = -1;
if (destinationString.size() != 0)
- StringToInt(destinationString, &destination);
+ base::StringToInt(destinationString, &destination);
if (command == kConnect) {
if (destination != -1) // destination should be empty for this command.
- response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND);
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
else
ConnectCommand(content, &response);
} else if (command == kDisconnect) {
if (destination == -1) // Destination required for this command.
- response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND);
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
else
DisconnectCommand(destination, &response);
} else if (command == kPostMessage) {
if (destination == -1) // Destination required for this command.
- response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND);
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
else
PostMessageCommand(destination, content, &response);
} else {
// Unknown command
NOTREACHED();
- response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND);
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
}
SendResponse(response, message.tool(), message.destination());
}
@@ -271,44 +268,44 @@ void ExtensionPortsRemoteService::OnExtensionMessage(
<< ", < " << message << ">";
// Transpose the information into a JSON message for the external client.
DictionaryValue content;
- content.SetString(kCommandWide, kOnMessage);
- content.SetInteger(kResultWide, RESULT_OK);
+ content.SetString(kCommandKey, kOnMessage);
+ content.SetInteger(kResultKey, RESULT_OK);
// Turn the stringified message body back into JSON.
Value* data = base::JSONReader::Read(message, false);
if (!data) {
NOTREACHED();
return;
}
- content.Set(kDataWide, data);
- SendResponse(content, kToolName, IntToString(port_id));
+ content.Set(kDataKey, data);
+ SendResponse(content, kToolName, base::IntToString(port_id));
}
void ExtensionPortsRemoteService::OnExtensionPortDisconnected(int port_id) {
LOG(INFO) << "Disconnect event for port " << port_id;
openPortIds_.erase(port_id);
DictionaryValue content;
- content.SetString(kCommandWide, kOnDisconnect);
- content.SetInteger(kResultWide, RESULT_OK);
- SendResponse(content, kToolName, IntToString(port_id));
+ content.SetString(kCommandKey, kOnDisconnect);
+ content.SetInteger(kResultKey, RESULT_OK);
+ SendResponse(content, kToolName, base::IntToString(port_id));
}
void ExtensionPortsRemoteService::ConnectCommand(
DictionaryValue* content, DictionaryValue* response) {
// Parse out the parameters.
DictionaryValue* data;
- if (!content->GetDictionary(kDataWide, &data)) {
- response->SetInteger(kResultWide, RESULT_PARAMETER_ERROR);
+ if (!content->GetDictionary(kDataKey, &data)) {
+ response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR);
return;
}
std::string extension_id;
- if (!data->GetString(kExtensionIdWide, &extension_id)) {
- response->SetInteger(kResultWide, RESULT_PARAMETER_ERROR);
+ if (!data->GetString(kExtensionIdKey, &extension_id)) {
+ response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR);
return;
}
std::string channel_name = "";
- data->GetString(kChannelNameWide, &channel_name); // optional.
+ data->GetString(kChannelNameKey, &channel_name); // optional.
int tab_id = -1;
- data->GetInteger(kTabIdWide, &tab_id); // optional.
+ data->GetInteger(kTabIdKey, &tab_id); // optional.
int port_id;
if (tab_id != -1) { // Resolve the tab ID.
const InspectableTabProxy::ControllersMap& navcon_map =
@@ -320,7 +317,7 @@ void ExtensionPortsRemoteService::ConnectCommand(
tab_contents = it->second->tab_contents();
if (!tab_contents) {
LOG(INFO) << "tab not found: " << tab_id;
- response->SetInteger(kResultWide, RESULT_TAB_NOT_FOUND);
+ response->SetInteger(kResultKey, RESULT_TAB_NOT_FOUND);
return;
}
// Ask the ExtensionMessageService to open the channel.
@@ -341,16 +338,16 @@ void ExtensionPortsRemoteService::ConnectCommand(
if (port_id == -1) {
// Failure: probably the extension ID doesn't exist.
LOG(INFO) << "Connect failed";
- response->SetInteger(kResultWide, RESULT_CONNECT_FAILED);
+ response->SetInteger(kResultKey, RESULT_CONNECT_FAILED);
return;
}
LOG(INFO) << "Connected: port " << port_id;
openPortIds_.insert(port_id);
// Reply to external client with the port ID assigned to the new channel.
DictionaryValue* reply_data = new DictionaryValue();
- reply_data->SetInteger(kPortIdWide, port_id);
- response->Set(kDataWide, reply_data);
- response->SetInteger(kResultWide, RESULT_OK);
+ reply_data->SetInteger(kPortIdKey, port_id);
+ response->Set(kDataKey, reply_data);
+ response->SetInteger(kResultKey, RESULT_OK);
}
void ExtensionPortsRemoteService::DisconnectCommand(
@@ -359,20 +356,20 @@ void ExtensionPortsRemoteService::DisconnectCommand(
PortIdSet::iterator portEntry = openPortIds_.find(port_id);
if (portEntry == openPortIds_.end()) { // unknown port ID.
LOG(INFO) << "unknown port: " << port_id;
- response->SetInteger(kResultWide, RESULT_UNKNOWN_PORT);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_PORT);
return;
}
DCHECK(service_);
service_->CloseChannel(port_id);
openPortIds_.erase(portEntry);
- response->SetInteger(kResultWide, RESULT_OK);
+ response->SetInteger(kResultKey, RESULT_OK);
}
void ExtensionPortsRemoteService::PostMessageCommand(
int port_id, DictionaryValue* content, DictionaryValue* response) {
Value* data;
- if (!content->Get(kDataWide, &data)) {
- response->SetInteger(kResultWide, RESULT_PARAMETER_ERROR);
+ if (!content->Get(kDataKey, &data)) {
+ response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR);
return;
}
std::string message;
@@ -383,12 +380,12 @@ void ExtensionPortsRemoteService::PostMessageCommand(
PortIdSet::iterator portEntry = openPortIds_.find(port_id);
if (portEntry == openPortIds_.end()) { // Unknown port ID.
LOG(INFO) << "unknown port: " << port_id;
- response->SetInteger(kResultWide, RESULT_UNKNOWN_PORT);
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_PORT);
return;
}
// Post the message through the ExtensionMessageService.
DCHECK(service_);
service_->PostMessageFromRenderer(port_id, message);
// Confirm to the external client that we sent its message.
- response->SetInteger(kResultWide, RESULT_OK);
+ response->SetInteger(kResultKey, RESULT_OK);
}
diff --git a/chrome/browser/debugger/extension_ports_remote_service.h b/chrome/browser/debugger/extension_ports_remote_service.h
index 6067f44..0b4c892 100644
--- a/chrome/browser/debugger/extension_ports_remote_service.h
+++ b/chrome/browser/debugger/extension_ports_remote_service.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_EXTENSION_PORTS_REMOTE_SERVICE_H_
#define CHROME_BROWSER_DEBUGGER_EXTENSION_PORTS_REMOTE_SERVICE_H_
+#pragma once
#include <set>
#include <string>
diff --git a/chrome/browser/debugger/inspectable_tab_proxy.cc b/chrome/browser/debugger/inspectable_tab_proxy.cc
index 2c5924b..96d4e3e 100644
--- a/chrome/browser/debugger/inspectable_tab_proxy.cc
+++ b/chrome/browser/debugger/inspectable_tab_proxy.cc
@@ -1,9 +1,10 @@
-// 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.
#include "chrome/browser/debugger/inspectable_tab_proxy.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
@@ -28,29 +29,16 @@ void DevToolsClientHostImpl::Close() {
void DevToolsClientHostImpl::SendMessageToClient(
const IPC::Message& msg) {
+ // TODO(prybin): Restore FrameNavigate.
IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg)
- IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage);
+ IPC_MESSAGE_HANDLER(DevToolsClientMsg_DebuggerOutput, OnDebuggerOutput);
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
}
-void DevToolsClientHostImpl::OnRpcMessage(const DevToolsMessageData& data) {
- static const std::string kDebuggerAgentDelegate = "DebuggerAgentDelegate";
- static const std::string kToolsAgentDelegate = "ToolsAgentDelegate";
- static const std::string kDebuggerOutput = "debuggerOutput";
- static const std::string kFrameNavigate = "frameNavigate";
- if (data.class_name == kDebuggerAgentDelegate &&
- data.method_name == kDebuggerOutput) {
- DebuggerOutput(data.arguments[0]);
- } else if (data.class_name == kToolsAgentDelegate &&
- data.method_name == kFrameNavigate) {
- FrameNavigate(data.arguments[0]);
- }
-}
-
-void DevToolsClientHostImpl::DebuggerOutput(const std::string& msg) {
- service_->DebuggerOutput(id_, msg);
+void DevToolsClientHostImpl::OnDebuggerOutput(const std::string& data) {
+ service_->DebuggerOutput(id_, data);
}
void DevToolsClientHostImpl::FrameNavigate(const std::string& url) {
@@ -98,7 +86,7 @@ DevToolsClientHost* InspectableTabProxy::NewClientHost(
void InspectableTabProxy::OnRemoteDebuggerDetached() {
while (id_to_client_host_map_.size() > 0) {
IdToClientHostMap::iterator it = id_to_client_host_map_.begin();
- it->second->debugger_remote_service()->DetachFromTab(IntToString(it->first),
- NULL);
+ it->second->debugger_remote_service()->DetachFromTab(
+ base::IntToString(it->first), NULL);
}
}
diff --git a/chrome/browser/debugger/inspectable_tab_proxy.h b/chrome/browser/debugger/inspectable_tab_proxy.h
index 67b5952..af08232 100644
--- a/chrome/browser/debugger/inspectable_tab_proxy.h
+++ b/chrome/browser/debugger/inspectable_tab_proxy.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEBUGGER_INSPECTABLE_TAB_PROXY_H_
#define CHROME_BROWSER_DEBUGGER_INSPECTABLE_TAB_PROXY_H_
+#pragma once
#include <string>
@@ -82,8 +83,7 @@ class DevToolsClientHostImpl : public DevToolsClientHost {
private:
// Message handling routines
- void OnRpcMessage(const DevToolsMessageData& data);
- void DebuggerOutput(const std::string& msg);
+ void OnDebuggerOutput(const std::string& msg);
void FrameNavigate(const std::string& url);
void TabClosed();
diff --git a/chrome/browser/default_encoding_combo_model.cc b/chrome/browser/default_encoding_combo_model.cc
index 83477b8..f900713 100644
--- a/chrome/browser/default_encoding_combo_model.cc
+++ b/chrome/browser/default_encoding_combo_model.cc
@@ -6,8 +6,9 @@
#include "app/l10n_util.h"
#include "app/l10n_util_collator.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
@@ -23,9 +24,16 @@ DefaultEncodingComboboxModel::DefaultEncodingComboboxModel() {
l10n_util::SortVectorWithStringKey(locale, &sorted_encoding_list_, true);
}
-std::wstring DefaultEncodingComboboxModel::GetItemAt(int index) {
+DefaultEncodingComboboxModel::~DefaultEncodingComboboxModel() {
+}
+
+int DefaultEncodingComboboxModel::GetItemCount() {
+ return static_cast<int>(sorted_encoding_list_.size());
+}
+
+string16 DefaultEncodingComboboxModel::GetItemAt(int index) {
DCHECK(index >= 0 && index < GetItemCount());
- return sorted_encoding_list_[index].encoding_display_name;
+ return WideToUTF16Hack(sorted_encoding_list_[index].encoding_display_name);
}
std::string DefaultEncodingComboboxModel::GetEncodingCharsetByIndex(int index) {
diff --git a/chrome/browser/default_encoding_combo_model.h b/chrome/browser/default_encoding_combo_model.h
index 9901238..a4d5a50 100644
--- a/chrome/browser/default_encoding_combo_model.h
+++ b/chrome/browser/default_encoding_combo_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DEFAULT_ENCODING_COMBO_MODEL_H_
#define CHROME_BROWSER_DEFAULT_ENCODING_COMBO_MODEL_H_
+#pragma once
#include <string>
#include <vector>
@@ -16,14 +17,12 @@ class Profile;
class DefaultEncodingComboboxModel : public ComboboxModel {
public:
DefaultEncodingComboboxModel();
- virtual ~DefaultEncodingComboboxModel() {}
+ virtual ~DefaultEncodingComboboxModel();
// Overridden from ComboboxModel.
- virtual int GetItemCount() {
- return static_cast<int>(sorted_encoding_list_.size());
- }
+ virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
std::string GetEncodingCharsetByIndex(int index);
diff --git a/chrome/browser/defaults.cc b/chrome/browser/defaults.cc
index 35844a7..f985c5f 100644
--- a/chrome/browser/defaults.cc
+++ b/chrome/browser/defaults.cc
@@ -8,10 +8,15 @@ namespace browser_defaults {
#if defined(OS_CHROMEOS)
-const double kAutocompleteEditFontPixelSize = 12.0;
-const double kAutocompleteEditFontPixelSizeInPopup = kAutocompletePopupFontSize;
+// Make the regular omnibox text two points larger than the nine-point font
+// used in the tab strip (11pt / 72pt/in * 96px/in = 14.667px).
+const double kAutocompleteEditFontPixelSize = 14.7;
+const double kAutocompleteEditFontPixelSizeInPopup = 10.0;
+// This is only used by AutocompletePopupViewGtk which is unused
+// unless TOOLKIT_VIEWS is undefined:
const int kAutocompletePopupFontSize = 7;
+
const SessionStartupPref::Type kDefaultSessionStartupType =
SessionStartupPref::LAST;
const int kMiniTabWidth = 64;
@@ -77,4 +82,6 @@ const bool kBrowserAliveWithNoWindows = false;
const bool kPhantomTabsEnabled = false;
+bool bookmarks_enabled = true;
+
} // namespace browser_defaults
diff --git a/chrome/browser/defaults.h b/chrome/browser/defaults.h
index 6414290..cd635b0 100644
--- a/chrome/browser/defaults.h
+++ b/chrome/browser/defaults.h
@@ -6,9 +6,10 @@
#ifndef CHROME_BROWSER_DEFAULTS_H_
#define CHROME_BROWSER_DEFAULTS_H_
+#pragma once
#include "build/build_config.h"
-#include "chrome/browser/session_startup_pref.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
namespace browser_defaults {
@@ -73,6 +74,13 @@ extern const bool kAlwaysOpenIncognitoWindow;
// Are phantom tabs enabled?
extern const bool kPhantomTabsEnabled;
+//=============================================================================
+// Runtime "const" - set only once after parsing command line option and should
+// never be modified after that.
+
+// Are bookmark enabled? True by default.
+extern bool bookmarks_enabled;
+
} // namespace browser_defaults
#endif // CHROME_BROWSER_DEFAULTS_H_
diff --git a/chrome/browser/diagnostics/diagnostics_main.cc b/chrome/browser/diagnostics/diagnostics_main.cc
index 89a2533..bf88222 100644
--- a/chrome/browser/diagnostics/diagnostics_main.cc
+++ b/chrome/browser/diagnostics/diagnostics_main.cc
@@ -22,10 +22,6 @@
#include "chrome/browser/diagnostics/diagnostics_model.h"
#include "chrome/common/chrome_paths.h"
-#if defined(OS_WIN)
-#include "base/win_util.h"
-#endif
-
namespace {
// This is a minimalistic interface to wrap the platform console. This will be
// eventually replaced by a view that can be subclassed for each platform and
@@ -139,7 +135,7 @@ SimpleConsole* SimpleConsole::Create() {
class PosixConsole : public SimpleConsole {
public:
- PosixConsole() { }
+ PosixConsole() : use_color_(false) { }
virtual bool Init() {
// Technically, we should also check the terminal capabilities before using
@@ -256,7 +252,9 @@ std::wstring PrintableUSCurrentTime() {
// More info at http://martinfowler.com/eaaDev/PassiveScreen.html
class TestController : public DiagnosticsModel::Observer {
public:
- explicit TestController(TestWriter* writer) : writer_(writer) {
+ explicit TestController(TestWriter* writer)
+ : model_(NULL),
+ writer_(writer) {
}
// Run all the diagnostics of |model| and invoke the view as the model
@@ -278,7 +276,7 @@ class TestController : public DiagnosticsModel::Observer {
model->RunAll(this);
}
- // Next four are overriden from DiagnosticsModel::Observer
+ // Next four are overridden from DiagnosticsModel::Observer.
virtual void OnProgress(int id, int percent, DiagnosticsModel* model) {
}
diff --git a/chrome/browser/diagnostics/diagnostics_main.h b/chrome/browser/diagnostics/diagnostics_main.h
index 0ce1404..9a71a24 100644
--- a/chrome/browser/diagnostics/diagnostics_main.h
+++ b/chrome/browser/diagnostics/diagnostics_main.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_
#define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MAIN_H_
+#pragma once
class CommandLine;
diff --git a/chrome/browser/diagnostics/diagnostics_model.h b/chrome/browser/diagnostics/diagnostics_model.h
index 42d259c..45c46e9 100644
--- a/chrome/browser/diagnostics/diagnostics_model.h
+++ b/chrome/browser/diagnostics/diagnostics_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MODEL_H_
#define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_MODEL_H_
+#pragma once
#include "base/string16.h"
diff --git a/chrome/browser/diagnostics/diagnostics_test.h b/chrome/browser/diagnostics/diagnostics_test.h
index 6e17518..998a0d1 100644
--- a/chrome/browser/diagnostics/diagnostics_test.h
+++ b/chrome/browser/diagnostics/diagnostics_test.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_TEST_H_
#define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_TEST_H_
+#pragma once
#include "base/file_path.h"
#include "base/path_service.h"
diff --git a/chrome/browser/diagnostics/recon_diagnostics.cc b/chrome/browser/diagnostics/recon_diagnostics.cc
index 9f3e3d8..52f2ff0 100644
--- a/chrome/browser/diagnostics/recon_diagnostics.cc
+++ b/chrome/browser/diagnostics/recon_diagnostics.cc
@@ -6,11 +6,10 @@
#include <string>
-#include "app/app_paths.h"
#include "base/file_util.h"
-#include "base/file_version_info.h"
#include "base/json/json_reader.h"
#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/path_service.h"
@@ -116,26 +115,23 @@ class VersionTest : public DiagnosticTest {
virtual int GetId() { return 0; }
virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
- scoped_ptr<FileVersionInfo> version_info(
- chrome::GetChromeVersionInfo());
- if (!version_info.get()) {
+ chrome::VersionInfo version_info;
+ if (!version_info.is_valid()) {
RecordFailure(ASCIIToUTF16("No Version"));
return true;
}
- string16 current_version = WideToUTF16(version_info->file_version());
+ std::string current_version = version_info.Version();
if (current_version.empty()) {
RecordFailure(ASCIIToUTF16("Empty Version"));
return true;
}
- string16 version_modifier = platform_util::GetVersionStringModifier();
- if (!version_modifier.empty()) {
- current_version += ASCIIToUTF16(" ");
- current_version += version_modifier;
- }
+ std::string version_modifier = platform_util::GetVersionStringModifier();
+ if (!version_modifier.empty())
+ current_version += " " + version_modifier;
#if defined(GOOGLE_CHROME_BUILD)
- current_version += ASCIIToUTF16(" GCB");
+ current_version += " GCB";
#endif // defined(GOOGLE_CHROME_BUILD)
- RecordSuccess(current_version);
+ RecordSuccess(ASCIIToUTF16(current_version));
return true;
}
@@ -203,8 +199,7 @@ class PathTest : public DiagnosticTest {
return true;
}
DataUnits units = GetByteDisplayUnits(dir_or_file_size);
- string16 printable_size =
- WideToUTF16(FormatBytes(dir_or_file_size, units, true));
+ string16 printable_size = FormatBytes(dir_or_file_size, units, true);
if (path_info_.max_size > 0) {
if (dir_or_file_size > path_info_.max_size) {
@@ -248,8 +243,7 @@ class DiskSpaceTest : public DiagnosticTest {
return true;
}
DataUnits units = GetByteDisplayUnits(disk_space);
- string16 printable_size =
- WideToUTF16(FormatBytes(disk_space, units, true));
+ string16 printable_size = FormatBytes(disk_space, units, true);
if (disk_space < 80 * kOneMeg) {
RecordFailure(ASCIIToUTF16("Low disk space : ") + printable_size);
return true;
@@ -296,7 +290,7 @@ class JSONTest : public DiagnosticTest {
scoped_ptr<Value> json_root(json.Deserialize(&error_code, &error_message));
if (base::JSONReader::JSON_NO_ERROR != error_code) {
if (error_message.empty()) {
- error_message = "Parse error " + IntToString(error_code);
+ error_message = "Parse error " + base::IntToString(error_code);
}
RecordFailure(UTF8ToUTF16(error_message));
return true;
diff --git a/chrome/browser/diagnostics/recon_diagnostics.h b/chrome/browser/diagnostics/recon_diagnostics.h
index 47f9cc1..d7c52e9 100644
--- a/chrome/browser/diagnostics/recon_diagnostics.h
+++ b/chrome/browser/diagnostics/recon_diagnostics.h
@@ -1,11 +1,11 @@
-// 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.
#ifndef CHROME_BROWSER_DIAGNOSTICS_RECON_DIAGNOSTICS_H_
#define CHROME_BROWSER_DIAGNOSTICS_RECON_DIAGNOSTICS_H_
+#pragma once
-#include "base/string16.h"
#include "chrome/browser/diagnostics/diagnostics_test.h"
DiagnosticTest* MakeOperatingSystemTest();
diff --git a/chrome/browser/diagnostics/sqlite_diagnostics.cc b/chrome/browser/diagnostics/sqlite_diagnostics.cc
index d7f81fb..15c758a 100644
--- a/chrome/browser/diagnostics/sqlite_diagnostics.cc
+++ b/chrome/browser/diagnostics/sqlite_diagnostics.cc
@@ -6,17 +6,17 @@
#include "app/sql/connection.h"
#include "app/sql/diagnostic_error_delegate.h"
-#include "app/sql/init_status.h"
#include "app/sql/statement.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/singleton.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
#include "webkit/appcache/appcache_interfaces.h"
#include "webkit/database/database_tracker.h"
@@ -59,7 +59,7 @@ class SqliteIntegrityTest : public DiagnosticTest {
RecordFailure(ASCIIToUTF16("DB locked by another process"));
} else {
string16 str(ASCIIToUTF16("Pragma failed. Error: "));
- str += IntToString16(error);
+ str += base::IntToString16(error);
RecordFailure(str);
}
return false;
@@ -73,7 +73,7 @@ class SqliteIntegrityTest : public DiagnosticTest {
// All done. Report to the user.
if (errors != 0) {
string16 str(ASCIIToUTF16("Database corruption detected :"));
- str += IntToString16(errors) + ASCIIToUTF16(" errors");
+ str += base::IntToString16(errors) + ASCIIToUTF16(" errors");
RecordFailure(str);
return true;
}
diff --git a/chrome/browser/diagnostics/sqlite_diagnostics.h b/chrome/browser/diagnostics/sqlite_diagnostics.h
index c416e88..8a390d7 100644
--- a/chrome/browser/diagnostics/sqlite_diagnostics.h
+++ b/chrome/browser/diagnostics/sqlite_diagnostics.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DIAGNOSTICS_SQLITE_DIAGNOSTICS_H_
#define CHROME_BROWSER_DIAGNOSTICS_SQLITE_DIAGNOSTICS_H_
+#pragma once
#include "chrome/browser/diagnostics/diagnostics_test.h"
diff --git a/chrome/browser/dock_info.h b/chrome/browser/dock_info.h
index a207d79..d0bf90c 100644
--- a/chrome/browser/dock_info.h
+++ b/chrome/browser/dock_info.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOCK_INFO_H_
#define CHROME_BROWSER_DOCK_INFO_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/dock_info_mac.cc b/chrome/browser/dock_info_mac.cc
index d67588d..7c4113c 100644
--- a/chrome/browser/dock_info_mac.cc
+++ b/chrome/browser/dock_info_mac.cc
@@ -4,8 +4,6 @@
#include "chrome/browser/dock_info.h"
-#include "base/logging.h"
-
bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds,
bool* maximize_new_window) const {
// TODO(pinkerton): Implement DockInfo, http://crbug.com/9274.
diff --git a/chrome/browser/dock_info_win.cc b/chrome/browser/dock_info_win.cc
index bdcbb59..68b3c17 100644
--- a/chrome/browser/dock_info_win.cc
+++ b/chrome/browser/dock_info_win.cc
@@ -1,11 +1,10 @@
-// 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/dock_info.h"
#include "base/basictypes.h"
-#include "base/logging.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
@@ -78,6 +77,22 @@ class TopMostFinder : public BaseWindowFinder {
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
diff --git a/chrome/browser/dom_operation_notification_details.h b/chrome/browser/dom_operation_notification_details.h
index 3f22f5d..9b2266e 100644
--- a/chrome/browser/dom_operation_notification_details.h
+++ b/chrome/browser/dom_operation_notification_details.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_DOM_OPERATION_NOTIFICATION_DETAILS_H__
#define CHROME_BROWSER_DOM_OPERATION_NOTIFICATION_DETAILS_H__
+#pragma once
class DomOperationNotificationDetails {
public:
diff --git a/chrome/browser/dom_ui/advanced_options_handler.cc b/chrome/browser/dom_ui/advanced_options_handler.cc
index 6999dea..778dab6 100644
--- a/chrome/browser/dom_ui/advanced_options_handler.cc
+++ b/chrome/browser/dom_ui/advanced_options_handler.cc
@@ -4,35 +4,38 @@
#include "chrome/browser/dom_ui/advanced_options_handler.h"
-#if defined(OS_WIN)
-#include <cryptuiapi.h>
-#pragma comment(lib, "cryptui.lib")
-#endif
-
#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_managed_banner_handler.h"
#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/download/download_prefs.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/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/chrome_switches.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
-#if defined(OS_WIN)
-#include "net/base/ssl_config_service_win.h"
+#if !defined(OS_CHROMEOS)
+#include "chrome/browser/dom_ui/advanced_options_utils.h"
#endif
-#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
-// The URL for Linux ssl certificate configuration help.
-const char* const kLinuxCertificatesConfigUrl =
- "http://code.google.com/p/chromium/wiki/LinuxCertManagement";
+#if defined(OS_WIN)
+#include "chrome/browser/gears_integration.h"
+#include "net/base/ssl_config_service_win.h"
#endif
AdvancedOptionsHandler::AdvancedOptionsHandler() {
@@ -45,90 +48,126 @@ void AdvancedOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"privacyLearnMoreURL",
- l10n_util::GetString(IDS_LEARN_MORE_PRIVACY_URL));
- localized_strings->SetString(L"privacyLearnMoreLabel",
- l10n_util::GetString(IDS_OPTIONS_LEARN_MORE_LABEL));
- localized_strings->SetString(L"downloadLocationGroupName",
- l10n_util::GetString(IDS_OPTIONS_DOWNLOADLOCATION_GROUP_NAME));
- localized_strings->SetString(L"downloadLocationBrowseButton",
- l10n_util::GetString(IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_BUTTON));
- localized_strings->SetString(L"downloadLocationBrowseTitle",
- l10n_util::GetString(IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_TITLE));
- localized_strings->SetString(L"downloadLocationBrowseWindowTitle",
- l10n_util::GetString(IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_WINDOW_TITLE));
- localized_strings->SetString(L"downloadLocationAskForSaveLocation",
- l10n_util::GetString(IDS_OPTIONS_DOWNLOADLOCATION_ASKFORSAVELOCATION));
- localized_strings->SetString(L"autoOpenFileTypesInfo",
- l10n_util::GetString(IDS_OPTIONS_AUTOOPENFILETYPES_INFO));
- localized_strings->SetString(L"autoOpenFileTypesResetToDefault",
- l10n_util::GetString(IDS_OPTIONS_AUTOOPENFILETYPES_RESETTODEFAULT));
- localized_strings->SetString(L"gearSettingsGroupName",
- l10n_util::GetString(IDS_OPTIONS_GEARSSETTINGS_GROUP_NAME));
- localized_strings->SetString(L"gearSettingsConfigureGearsButton",
- l10n_util::GetString(IDS_OPTIONS_GEARSSETTINGS_CONFIGUREGEARS_BUTTON));
- localized_strings->SetString(L"translateEnableTranslate",
- l10n_util::GetString(IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE));
- localized_strings->SetString(L"certificatesLabel",
- l10n_util::GetString(IDS_OPTIONS_CERTIFICATES_LABEL));
- localized_strings->SetString(L"certificatesManageButton",
- l10n_util::GetString(IDS_OPTIONS_CERTIFICATES_MANAGE_BUTTON));
- localized_strings->SetString(L"proxiesLabel",
- l10n_util::GetString(IDS_OPTIONS_PROXIES_LABEL));
- localized_strings->SetString(L"proxiesConfigureButton",
- l10n_util::GetString(IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON));
- localized_strings->SetString(L"safeBrowsingEnableProtection",
- l10n_util::GetString(IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION));
- localized_strings->SetString(L"sslGroupDescription",
- l10n_util::GetString(IDS_OPTIONS_SSL_GROUP_DESCRIPTION));
- localized_strings->SetString(L"sslUseSSL2",
- l10n_util::GetString(IDS_OPTIONS_SSL_USESSL2));
- localized_strings->SetString(L"sslCheckRevocation",
- l10n_util::GetString(IDS_OPTIONS_SSL_CHECKREVOCATION));
- localized_strings->SetString(L"sslUseSSL3",
- l10n_util::GetString(IDS_OPTIONS_SSL_USESSL3));
- localized_strings->SetString(L"sslUseTLS1",
- l10n_util::GetString(IDS_OPTIONS_SSL_USETLS1));
- localized_strings->SetString(L"networkDNSPrefetchEnabledDescription",
- l10n_util::GetString(IDS_NETWORK_DNS_PREFETCH_ENABLED_DESCRIPTION));
- localized_strings->SetString(L"privacyContentSettingsButton",
- l10n_util::GetString(IDS_OPTIONS_PRIVACY_CONTENT_SETTINGS_BUTTON));
- localized_strings->SetString(L"privacyClearDataButton",
- l10n_util::GetString(IDS_OPTIONS_PRIVACY_CLEAR_DATA_BUTTON));
- localized_strings->SetString(L"linkDoctorPref",
- l10n_util::GetString(IDS_OPTIONS_LINKDOCTOR_PREF));
- localized_strings->SetString(L"suggestPref",
- l10n_util::GetString(IDS_OPTIONS_SUGGEST_PREF));
- localized_strings->SetString(L"tabsToLinksPref",
- l10n_util::GetString(IDS_OPTIONS_TABS_TO_LINKS_PREF));
- localized_strings->SetString(L"fontSettingsInfo",
- l10n_util::GetString(IDS_OPTIONS_FONTSETTINGS_INFO));
- localized_strings->SetString(L"fontSettingsConfigureFontsOnlyButton",
- l10n_util::GetString(IDS_OPTIONS_FONTSETTINGS_CONFIGUREFONTSONLY_BUTTON));
- localized_strings->SetString(L"advancedSectionTitlePrivacy",
- l10n_util::GetString(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY));
- localized_strings->SetString(L"advancedSectionTitleContent",
- l10n_util::GetString(IDS_OPTIONS_ADVANCED_SECTION_TITLE_CONTENT));
- localized_strings->SetString(L"advancedSectionTitleSecurity",
- l10n_util::GetString(IDS_OPTIONS_ADVANCED_SECTION_TITLE_SECURITY));
- localized_strings->SetString(L"advancedSectionTitleNetwork",
- l10n_util::GetString(IDS_OPTIONS_ADVANCED_SECTION_TITLE_NETWORK));
- localized_strings->SetString(L"advancedSectionTitleTranslate",
- l10n_util::GetString(IDS_OPTIONS_ADVANCED_SECTION_TITLE_TRANSLATE));
- localized_strings->SetString(L"translateEnableTranslate",
- l10n_util::GetString(IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE));
- localized_strings->SetString(L"enableLogging",
- l10n_util::GetString(IDS_OPTIONS_ENABLE_LOGGING));
- localized_strings->SetString(L"disableServices",
- l10n_util::GetString(IDS_OPTIONS_DISABLE_SERVICES));
+ localized_strings->SetString("privacyLearnMoreURL",
+ l10n_util::GetStringUTF16(IDS_LEARN_MORE_PRIVACY_URL));
+ localized_strings->SetString("privacyLearnMoreLabel",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_LEARN_MORE_LABEL));
+ 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("downloadLocationBrowseTitle",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_TITLE));
+ localized_strings->SetString("downloadLocationBrowseWindowTitle",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_WINDOW_TITLE));
+ localized_strings->SetString("downloadLocationAskForSaveLocation",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_DOWNLOADLOCATION_ASKFORSAVELOCATION));
+ localized_strings->SetString("autoOpenFileTypesInfo",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOOPENFILETYPES_INFO));
+ localized_strings->SetString("autoOpenFileTypesResetToDefault",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOOPENFILETYPES_RESETTODEFAULT));
+ localized_strings->SetString("gearSettingsGroupName",
+ 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",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PROXIES_LABEL));
+ localized_strings->SetString("proxiesConfigureButton",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON));
+ localized_strings->SetString("safeBrowsingEnableProtection",
+ 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",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SSL_USESSL3));
+ localized_strings->SetString("sslUseTLS1",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SSL_USETLS1));
+ localized_strings->SetString("networkDNSPrefetchEnabledDescription",
+ l10n_util::GetStringUTF16(IDS_NETWORK_DNS_PREFETCH_ENABLED_DESCRIPTION));
+ localized_strings->SetString("privacyContentSettingsButton",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PRIVACY_CONTENT_SETTINGS_BUTTON));
+ localized_strings->SetString("privacyClearDataButton",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PRIVACY_CLEAR_DATA_BUTTON));
+ localized_strings->SetString("linkDoctorPref",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_LINKDOCTOR_PREF));
+ localized_strings->SetString("suggestPref",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_SUGGEST_PREF));
+ localized_strings->SetString("tabsToLinksPref",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_TABS_TO_LINKS_PREF));
+ localized_strings->SetString("fontSettingsInfo",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_FONTSETTINGS_INFO));
+ localized_strings->SetString("fontSettingsConfigureFontsOnlyButton",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_FONTSETTINGS_CONFIGUREFONTSONLY_BUTTON));
+ localized_strings->SetString("advancedSectionTitlePrivacy",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY));
+ localized_strings->SetString("advancedSectionTitleContent",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_CONTENT));
+ localized_strings->SetString("advancedSectionTitleSecurity",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_SECURITY));
+ localized_strings->SetString("advancedSectionTitleNetwork",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_NETWORK));
+ localized_strings->SetString("advancedSectionTitleTranslate",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_TRANSLATE));
+ localized_strings->SetString("translateEnableTranslate",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE));
+ // Add ChromeApps preferences if background mode is runtime-enabled.
+ bool background_mode_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBackgroundMode);
+ localized_strings->SetString("enable-background-mode",
+ background_mode_enabled ? "true" : "false");
+ localized_strings->SetString("advancedSectionTitleChromeApps",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_CHROME_APPS));
+ localized_strings->SetString("chromeAppsEnableBackgroundMode",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_CHROME_APPS_ENABLE_BACKGROUND_MODE));
+ localized_strings->SetString("chromeAppsLearnMoreBackgroundModeLabel",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_LEARN_MORE_LABEL));
+ localized_strings->SetString("chromeAppsLearnMoreBackgroundModeURL",
+ l10n_util::GetStringUTF16(IDS_LEARN_MORE_BACKGROUND_MODE_URL));
+ 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));
}
void AdvancedOptionsHandler::Initialize() {
+ DCHECK(dom_ui_);
+ SetupMetricsReportingCheckbox(false);
SetupDownloadLocationPath();
SetupAutoOpenFileTypesDisabledAttribute();
+ SetupProxySettingsSection();
#if defined(OS_WIN)
SetupSSLConfigSettings();
#endif
+ banner_handler_.reset(
+ new OptionsManagedBannerHandler(dom_ui_,
+ ASCIIToUTF16("AdvancedOptions"),
+ OPTIONS_PAGE_ADVANCED));
}
DOMMessageHandler* AdvancedOptionsHandler::Attach(DOMUI* dom_ui) {
@@ -138,11 +177,14 @@ DOMMessageHandler* AdvancedOptionsHandler::Attach(DOMUI* dom_ui) {
// Register for preferences that we need to observe manually. These have
// special behaviors that aren't handled by the standard prefs UI.
DCHECK(dom_ui_);
- PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
+ PrefService* prefs = dom_ui_->GetProfile()->GetPrefs();
+ enable_metrics_recording_.Init(prefs::kMetricsReportingEnabled,
+ g_browser_process->local_state(), this);
default_download_location_.Init(prefs::kDownloadDefaultDirectory,
- pref_service, this);
- auto_open_files_.Init(prefs::kDownloadExtensionsToOpen,
- pref_service, this);
+ prefs, this);
+ auto_open_files_.Init(prefs::kDownloadExtensionsToOpen, prefs, this);
+ proxy_prefs_.reset(
+ PrefSetObserver::CreateProxyPrefSetObserver(prefs, this));
// Return result from the superclass.
return handler;
@@ -157,21 +199,34 @@ void AdvancedOptionsHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("autoOpenFileTypesAction",
NewCallback(this,
&AdvancedOptionsHandler::HandleAutoOpenButton));
+ dom_ui_->RegisterMessageCallback("resetToDefaults",
+ NewCallback(this,
+ &AdvancedOptionsHandler::HandleResetToDefaults));
+ dom_ui_->RegisterMessageCallback("metricsReportingCheckboxAction",
+ NewCallback(this,
+ &AdvancedOptionsHandler::HandleMetricsReportingCheckbox));
+#if !defined(USE_NSS)
dom_ui_->RegisterMessageCallback("showManageSSLCertificates",
NewCallback(this,
&AdvancedOptionsHandler::ShowManageSSLCertificates));
+#endif
+#if !defined(OS_CHROMEOS)
dom_ui_->RegisterMessageCallback("showNetworkProxySettings",
NewCallback(this,
&AdvancedOptionsHandler::ShowNetworkProxySettings));
+#endif
#if defined(OS_WIN)
// Setup Windows specific callbacks.
dom_ui_->RegisterMessageCallback("checkRevocationCheckboxAction",
- NewCallback(this,
- &AdvancedOptionsHandler::HandleCheckRevocationCheckbox));
+ NewCallback(this,
+ &AdvancedOptionsHandler::HandleCheckRevocationCheckbox));
dom_ui_->RegisterMessageCallback("useSSL2CheckboxAction",
- NewCallback(this,
- &AdvancedOptionsHandler::HandleUseSSL2Checkbox));
+ NewCallback(this,
+ &AdvancedOptionsHandler::HandleUseSSL2Checkbox));
+ dom_ui_->RegisterMessageCallback("showGearsSettings",
+ NewCallback(this,
+ &AdvancedOptionsHandler::HandleShowGearsSettings));
#endif
}
@@ -179,16 +234,19 @@ void AdvancedOptionsHandler::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED) {
- std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ std::string* pref_name = Details<std::string>(details).ptr();
if (*pref_name == prefs::kDownloadDefaultDirectory) {
SetupDownloadLocationPath();
} else if (*pref_name == prefs::kDownloadExtensionsToOpen) {
SetupAutoOpenFileTypesDisabledAttribute();
+ } else if (proxy_prefs_->IsObserved(*pref_name)) {
+ SetupProxySettingsSection();
}
}
}
-void AdvancedOptionsHandler::HandleSelectDownloadLocation(const Value* value) {
+void AdvancedOptionsHandler::HandleSelectDownloadLocation(
+ const ListValue* args) {
PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
select_folder_dialog_ = SelectFileDialog::Create(this);
select_folder_dialog_->SelectFile(
@@ -201,75 +259,134 @@ void AdvancedOptionsHandler::HandleSelectDownloadLocation(const Value* value) {
void AdvancedOptionsHandler::FileSelected(const FilePath& path, int index,
void* params) {
+ UserMetricsRecordAction(UserMetricsAction("Options_SetDownloadDirectory"));
default_download_location_.SetValue(path);
SetupDownloadLocationPath();
}
-void AdvancedOptionsHandler::HandleAutoOpenButton(const Value* value) {
- DCHECK(dom_ui_);
+void AdvancedOptionsHandler::HandleAutoOpenButton(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_ResetAutoOpenFiles"));
DownloadManager* manager = dom_ui_->GetProfile()->GetDownloadManager();
- if (manager) manager->ResetAutoOpenFiles();
+ if (manager)
+ 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)
+ std::string checked_str = WideToUTF8(ExtractStringValue(args));
+ bool enabled = (checked_str == "true");
+ UserMetricsRecordAction(
+ enabled ?
+ UserMetricsAction("Options_MetricsReportingCheckbox_Enable") :
+ 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);
+#endif
}
#if defined(OS_WIN)
-void AdvancedOptionsHandler::HandleCheckRevocationCheckbox(const Value* value) {
- if (!value || !value->IsType(Value::TYPE_LIST)) {
- LOG(WARNING) << "checkRevocationCheckboxAction called with missing or " <<
- "invalid value";
- return;
- }
- const ListValue* list = static_cast<const ListValue*>(value);
- if (list->GetSize() < 1) {
- LOG(WARNING) << "checkRevocationCheckboxAction called with too few " <<
- "arguments";
- return;
- }
- std::string checked_str;
- if (list->GetString(0, &checked_str)) {
- net::SSLConfigServiceWin::SetRevCheckingEnabled(checked_str == "true");
- }
+void AdvancedOptionsHandler::HandleCheckRevocationCheckbox(
+ const ListValue* args) {
+ std::string checked_str = WideToUTF8(ExtractStringValue(args));
+ std::string metric =
+ (checked_str == "true" ? "Options_CheckCertRevocation_Enable"
+ : "Options_CheckCertRevocation_Disable");
+ UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
+ net::SSLConfigServiceWin::SetRevCheckingEnabled(checked_str == "true");
}
-void AdvancedOptionsHandler::HandleUseSSL2Checkbox(const Value* value) {
- if (!value || !value->IsType(Value::TYPE_LIST)) {
- LOG(WARNING) << "useSSL2CheckboxAction called with missing or " <<
- "invalid value";
- return;
- }
- const ListValue* list = static_cast<const ListValue*>(value);
- if (list->GetSize() < 1) {
- LOG(WARNING) << "useSSL2CheckboxAction called with too few " <<
- "arguments";
- return;
- }
- std::string checked_str;
- if (list->GetString(0, &checked_str)) {
- net::SSLConfigServiceWin::SetSSL2Enabled(checked_str == "true");
- }
+void AdvancedOptionsHandler::HandleUseSSL2Checkbox(const ListValue* args) {
+ std::string checked_str = WideToUTF8(ExtractStringValue(args));
+ std::string metric =
+ (checked_str == "true" ? "Options_SSL2_Enable"
+ : "Options_SSL2_Disable");
+ UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
+ net::SSLConfigServiceWin::SetSSL2Enabled(checked_str == "true");
+}
+
+void AdvancedOptionsHandler::HandleShowGearsSettings(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_GearsSettings"));
+ GearsSettingsPressed(
+ dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow());
+}
+#endif
+
+#if !defined(OS_CHROMEOS)
+void AdvancedOptionsHandler::ShowNetworkProxySettings(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_ShowProxySettings"));
+ AdvancedOptionsUtilities::ShowNetworkProxySettings(dom_ui_->tab_contents());
}
#endif
+#if !defined(USE_NSS)
+void AdvancedOptionsHandler::ShowManageSSLCertificates(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_ManageSSLCertificates"));
+ AdvancedOptionsUtilities::ShowManageSSLCertificates(dom_ui_->tab_contents());
+}
+#endif
+
+void AdvancedOptionsHandler::SetupMetricsReportingCheckbox(bool user_changed) {
+#if defined(GOOGLE_CHROME_BUILD)
+ 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);
+#endif
+}
+
void AdvancedOptionsHandler::SetupDownloadLocationPath() {
- DCHECK(dom_ui_);
StringValue value(default_download_location_.GetValue().value());
dom_ui_->CallJavascriptFunction(
- L"advancedOptionsSetDownloadLocationPath", value);
+ L"options.AdvancedOptions.SetDownloadLocationPath", value);
}
void AdvancedOptionsHandler::SetupAutoOpenFileTypesDisabledAttribute() {
// Set the enabled state for the AutoOpenFileTypesResetToDefault button.
// We enable the button if the user has any auto-open file types registered.
- DCHECK(dom_ui_);
DownloadManager* manager = dom_ui_->GetProfile()->GetDownloadManager();
- bool disabled = !(manager && manager->HasAutoOpenFileTypesRegistered());
+ bool disabled = !(manager && manager->download_prefs()->IsAutoOpenUsed());
FundamentalValue value(disabled);
dom_ui_->CallJavascriptFunction(
- L"advancedOptionsSetAutoOpenFileTypesDisabledAttribute", value);
+ L"options.AdvancedOptions.SetAutoOpenFileTypesDisabledAttribute", value);
+}
+
+void AdvancedOptionsHandler::SetupProxySettingsSection() {
+ // Disable the button if proxy settings are managed by a sysadmin or
+ // overridden by an extension.
+ PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
+ const PrefService::Preference* proxy_server =
+ pref_service->FindPreference(prefs::kProxyServer);
+ DCHECK(proxy_server);
+
+ FundamentalValue disabled(proxy_prefs_->IsManaged() ||
+ proxy_server->IsExtensionControlled());
+
+ // Get the appropriate info string to describe the button.
+ string16 label_str;
+ if (proxy_server->IsExtensionControlled()) {
+ label_str = l10n_util::GetStringUTF16(IDS_OPTIONS_EXTENSION_PROXIES_LABEL);
+ } else {
+ label_str = l10n_util::GetStringFUTF16(IDS_OPTIONS_SYSTEM_PROXIES_LABEL,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ }
+ StringValue label(label_str);
+
+ dom_ui_->CallJavascriptFunction(
+ L"options.AdvancedOptions.SetupProxySettingsSection", disabled, label);
}
#if defined(OS_WIN)
void AdvancedOptionsHandler::SetupSSLConfigSettings() {
- DCHECK(dom_ui_);
bool checkRevocationSetting = false;
bool useSSLSetting = false;
@@ -280,32 +397,10 @@ void AdvancedOptionsHandler::SetupSSLConfigSettings() {
}
FundamentalValue checkRevocationValue(checkRevocationSetting);
dom_ui_->CallJavascriptFunction(
- L"advancedOptionsSetCheckRevocationCheckboxState", checkRevocationValue);
+ L"options.AdvancedOptions.SetCheckRevocationCheckboxState",
+ checkRevocationValue);
FundamentalValue useSSLValue(useSSLSetting);
dom_ui_->CallJavascriptFunction(
- L"advancedOptionsSetUseSSL2CheckboxStatechecked", useSSLValue);
+ L"options.AdvancedOptions.SetUseSSL2CheckboxStatechecked", useSSLValue);
}
#endif
-
-void AdvancedOptionsHandler::ShowNetworkProxySettings(const Value* value) {
-#if defined(OS_MACOSX)
- AdvancedOptionsUtilities::ShowNetworkProxySettings();
-#endif
-}
-
-void AdvancedOptionsHandler::ShowManageSSLCertificates(const Value* value) {
-#if defined(OS_MACOSX)
- AdvancedOptionsUtilities::ShowManageSSLCertificates();
-#elif defined(OS_WIN)
- DCHECK(dom_ui_);
- CRYPTUI_CERT_MGR_STRUCT cert_mgr = { 0 };
- cert_mgr.dwSize = sizeof(CRYPTUI_CERT_MGR_STRUCT);
- cert_mgr.hwndParent =
- dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow();
- ::CryptUIDlgCertMgr(&cert_mgr);
-#elif defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
- DCHECK(dom_ui_);
- dom_ui_->tab_contents()->OpenURL(GURL(kLinuxCertificatesConfigUrl), GURL(),
- NEW_WINDOW, PageTransition::LINK);
-#endif
-}
diff --git a/chrome/browser/dom_ui/advanced_options_handler.h b/chrome/browser/dom_ui/advanced_options_handler.h
index 2fd9054..f85ec2a 100644
--- a/chrome/browser/dom_ui/advanced_options_handler.h
+++ b/chrome/browser/dom_ui/advanced_options_handler.h
@@ -4,14 +4,14 @@
#ifndef CHROME_BROWSER_DOM_UI_ADVANCED_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_ADVANCED_OPTIONS_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/options_ui.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/prefs/pref_set_observer.h"
#include "chrome/browser/shell_dialogs.h"
-#if defined(OS_MACOSX)
-#include "chrome/browser/dom_ui/advanced_options_utils_mac.h"
-#endif
+class OptionsManagedBannerHandler;
// Chrome advanced options page UI handler.
class AdvancedOptionsHandler
@@ -40,44 +40,67 @@ class AdvancedOptionsHandler
private:
// Callback for the "selectDownloadLocation" message. This will prompt
// the user for a destination folder using platform-specific APIs.
- void HandleSelectDownloadLocation(const Value* value);
+ void HandleSelectDownloadLocation(const ListValue* args);
// Callback for the "autoOpenFileTypesResetToDefault" message. This will
// remove all auto-open file-type settings.
- void HandleAutoOpenButton(const Value* value);
+ 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);
#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 Value* value);
+ 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 Value* value);
+ void HandleUseSSL2Checkbox(const ListValue* args);
+
+ // Callback for the "Show Gears Settings" button.
+ void HandleShowGearsSettings(const ListValue* args);
+#endif
+
+#if !defined(OS_CHROMEOS)
+ // Callback for the "showNetworkProxySettings" message. This will invoke
+ // an appropriate dialog for configuring proxy settings.
+ void ShowNetworkProxySettings(const ListValue* args);
#endif
+#if !defined(USE_NSS)
+ // Callback for the "showManageSSLCertificates" message. This will invoke
+ // an appropriate certificate management action based on the platform.
+ void ShowManageSSLCertificates(const ListValue* args);
+#endif
+
+ // Setup the checked state for the metrics reporting checkbox.
+ void SetupMetricsReportingCheckbox(bool user_changed);
+
// Setup the download path based on user preferences.
void SetupDownloadLocationPath();
// Setup the enabled state of the reset button.
void SetupAutoOpenFileTypesDisabledAttribute();
+ // Setup the proxy settings section UI.
+ void SetupProxySettingsSection();
+
#if defined(OS_WIN)
- // Setup the checked state SSL related checkboxes.
+ // Setup the checked state for SSL related checkboxes.
void SetupSSLConfigSettings();
#endif
- // Callback for the "showNetworkProxySettings" message. This will invoke
- // an appropriate dialog for configuring proxy settings.
- void ShowNetworkProxySettings(const Value* value);
-
- // Callback for the "showManageSSLCertificates" message. This will invoke
- // an appropriate certificate management action based on the platform.
- void ShowManageSSLCertificates(const Value* value);
-
scoped_refptr<SelectFileDialog> select_folder_dialog_;
+ BooleanPrefMember enable_metrics_recording_;
FilePathPrefMember default_download_location_;
StringPrefMember auto_open_files_;
+ scoped_ptr<PrefSetObserver> proxy_prefs_;
+ scoped_ptr<OptionsManagedBannerHandler> banner_handler_;
DISALLOW_COPY_AND_ASSIGN(AdvancedOptionsHandler);
};
diff --git a/chrome/browser/dom_ui/advanced_options_utils_mac.h b/chrome/browser/dom_ui/advanced_options_utils_mac.h
deleted file mode 100644
index efcad1a..0000000
--- a/chrome/browser/dom_ui/advanced_options_utils_mac.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 CHROME_BROWSER_DOM_UI_ADVANCED_OPTIONS_UTILS_MAC_H_
-#define CHROME_BROWSER_DOM_UI_ADVANCED_OPTIONS_UTILS_MAC_H_
-
-#include "base/basictypes.h"
-
-// Chrome advanced options utility methods for Mac OS X.
-class AdvancedOptionsUtilities {
- public:
- // Invoke the Mac OS X Network panel for configuring proxy settings.
- static void ShowNetworkProxySettings();
-
- // Invoke the Mac OS X Keychain application for inspecting certificates.
- static void ShowManageSSLCertificates();
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(AdvancedOptionsUtilities);
-};
-
-#endif // CHROME_BROWSER_DOM_UI_ADVANCED_OPTIONS_UTILS_MAC_H_
diff --git a/chrome/browser/dom_ui/advanced_options_utils_mac.mm b/chrome/browser/dom_ui/advanced_options_utils_mac.mm
index c4784f0..0557df4 100644
--- a/chrome/browser/dom_ui/advanced_options_utils_mac.mm
+++ b/chrome/browser/dom_ui/advanced_options_utils_mac.mm
@@ -4,32 +4,33 @@
#import <Cocoa/Cocoa.h>
-#include "chrome/browser/dom_ui/advanced_options_utils_mac.h"
+#include "chrome/browser/dom_ui/advanced_options_utils.h"
+
#include "base/logging.h"
+#include "base/scoped_aedesc.h"
-void AdvancedOptionsUtilities::ShowNetworkProxySettings() {
+void AdvancedOptionsUtilities::ShowNetworkProxySettings(
+ TabContents* tab_contents) {
NSArray* itemsToOpen = [NSArray arrayWithObject:[NSURL fileURLWithPath:
@"/System/Library/PreferencePanes/Network.prefPane"]];
const char* proxyPrefCommand = "Proxies";
- AEDesc openParams = { typeNull, NULL };
+ scoped_aedesc<> openParams;
OSStatus status = AECreateDesc('ptru',
proxyPrefCommand,
strlen(proxyPrefCommand),
- &openParams);
+ openParams.OutPointer());
LOG_IF(ERROR, status != noErr) << "Failed to create open params: " << status;
LSLaunchURLSpec launchSpec = { 0 };
launchSpec.itemURLs = (CFArrayRef)itemsToOpen;
- launchSpec.passThruParams = &openParams;
+ launchSpec.passThruParams = openParams;
launchSpec.launchFlags = kLSLaunchAsync | kLSLaunchDontAddToRecents;
LSOpenFromURLSpec(&launchSpec, NULL);
-
- if (openParams.descriptorType != typeNull)
- AEDisposeDesc(&openParams);
}
-void AdvancedOptionsUtilities::ShowManageSSLCertificates() {
+void AdvancedOptionsUtilities::ShowManageSSLCertificates(
+ TabContents* tab_contents) {
NSString* const kKeychainBundleId = @"com.apple.keychainaccess";
[[NSWorkspace sharedWorkspace]
launchAppWithBundleIdentifier:kKeychainBundleId
diff --git a/chrome/browser/dom_ui/app_launcher_handler.cc b/chrome/browser/dom_ui/app_launcher_handler.cc
index ce6f273..9c867d1 100644
--- a/chrome/browser/dom_ui/app_launcher_handler.cc
+++ b/chrome/browser/dom_ui/app_launcher_handler.cc
@@ -5,19 +5,21 @@
#include "chrome/browser/dom_ui/app_launcher_handler.h"
#include "app/animation.h"
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/base64.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/app_launched_animation.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/tab_contents/tab_contents.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_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
@@ -33,13 +35,22 @@ bool ExtractInt(const ListValue* list, size_t index, int* out_int) {
std::string string_value;
if (list->GetString(index, &string_value)) {
- *out_int = StringToInt(string_value);
+ base::StringToInt(string_value, out_int);
return true;
}
return false;
}
+std::string GetIconURL(Extension* extension, Extension::Icons icon,
+ const std::string& default_val) {
+ GURL url = extension->GetIconURL(icon, ExtensionIconSet::MATCH_EXACTLY);
+ if (!url.is_empty())
+ return url.spec();
+ else
+ return default_val;
+}
+
} // namespace
AppLauncherHandler::AppLauncherHandler(ExtensionsService* extension_service)
@@ -58,6 +69,8 @@ void AppLauncherHandler::RegisterMessages() {
NewCallback(this, &AppLauncherHandler::HandleGetApps));
dom_ui_->RegisterMessageCallback("launchApp",
NewCallback(this, &AppLauncherHandler::HandleLaunchApp));
+ dom_ui_->RegisterMessageCallback("setLaunchType",
+ NewCallback(this, &AppLauncherHandler::HandleSetLaunchType));
dom_ui_->RegisterMessageCallback("uninstallApp",
NewCallback(this, &AppLauncherHandler::HandleUninstallApp));
}
@@ -71,7 +84,15 @@ void AppLauncherHandler::Observe(NotificationType type,
if (dom_ui_->tab_contents())
HandleGetApps(NULL);
break;
+ case NotificationType::PREF_CHANGED: {
+ if (!dom_ui_->tab_contents())
+ break;
+ DictionaryValue dictionary;
+ FillAppDictionary(&dictionary);
+ dom_ui_->CallJavascriptFunction(L"appsPrefChangeCallback", dictionary);
+ break;
+ }
default:
NOTREACHED();
}
@@ -79,46 +100,44 @@ void AppLauncherHandler::Observe(NotificationType type,
// static
void AppLauncherHandler::CreateAppInfo(Extension* extension,
+ ExtensionPrefs* extension_prefs,
DictionaryValue* value) {
value->Clear();
- value->SetString(L"id", extension->id());
- value->SetString(L"name", extension->name());
- value->SetString(L"description", extension->description());
- value->SetString(L"launch_url", extension->GetFullLaunchURL().spec());
- value->SetString(L"options_url", extension->options_url().spec());
-
- FilePath relative_path =
- extension->GetIconPath(Extension::EXTENSION_ICON_LARGE).relative_path();
-
-#if defined(OS_POSIX)
- std::string path = relative_path.value();
-#elif defined(OS_WIN)
- std::string path = WideToUTF8(relative_path.value());
-#endif // OS_WIN
-
- GURL icon_url = extension->GetResourceURL(path);
- value->SetString(L"icon", icon_url.spec());
+ value->SetString("id", extension->id());
+ value->SetString("name", extension->name());
+ value->SetString("description", extension->description());
+ value->SetString("launch_url", extension->GetFullLaunchURL().spec());
+ value->SetString("options_url", extension->options_url().spec());
+ value->SetString("icon_big", GetIconURL(
+ extension, Extension::EXTENSION_ICON_LARGE,
+ "chrome://theme/IDR_APP_DEFAULT_ICON"));
+ value->SetString("icon_small", GetIconURL(
+ extension, Extension::EXTENSION_ICON_BITTY,
+ std::string("chrome://favicon/") + extension->GetFullLaunchURL().spec()));
+ value->SetInteger("launch_container", extension->launch_container());
+ value->SetInteger("launch_type",
+ extension_prefs->GetLaunchType(extension->id()));
}
-void AppLauncherHandler::HandleGetApps(const Value* value) {
- bool show_debug_link = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAppsDebug);
-
- DictionaryValue dictionary;
- dictionary.SetBoolean(L"showDebugLink", show_debug_link);
-
+void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) {
ListValue* list = new ListValue();
const ExtensionList* extensions = extensions_service_->extensions();
for (ExtensionList::const_iterator it = extensions->begin();
it != extensions->end(); ++it) {
- if ((*it)->is_app()) {
- DictionaryValue* app_info = new DictionaryValue();
- CreateAppInfo(*it, app_info);
- list->Append(app_info);
- }
+ // Don't include the WebStore component app. The WebStore launcher
+ // gets special treatment in ntp/apps.js.
+ if ((*it)->is_app() && (*it)->id() != extension_misc::kWebStoreAppId) {
+ DictionaryValue* app_info = new DictionaryValue();
+ CreateAppInfo(*it, extensions_service_->extension_prefs(), app_info);
+ list->Append(app_info);
+ }
}
+ dictionary->Set("apps", list);
+}
- dictionary.Set(L"apps", list);
+void AppLauncherHandler::HandleGetApps(const ListValue* args) {
+ DictionaryValue dictionary;
+ FillAppDictionary(&dictionary);
dom_ui_->CallJavascriptFunction(L"getAppsCallback", dictionary);
// First time we get here we set up the observer so that we can tell update
@@ -129,28 +148,25 @@ void AppLauncherHandler::HandleGetApps(const Value* value) {
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
}
-}
-
-void AppLauncherHandler::HandleLaunchApp(const Value* value) {
- if (!value->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
- return;
+ if (pref_change_registrar_.IsEmpty()) {
+ pref_change_registrar_.Init(
+ extensions_service_->extension_prefs()->pref_service());
+ pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref, this);
}
+}
+void AppLauncherHandler::HandleLaunchApp(const ListValue* args) {
std::string extension_id;
- std::string launch_container;
int left = 0;
int top = 0;
int width = 0;
int height = 0;
- const ListValue* list = static_cast<const ListValue*>(value);
- if (!list->GetString(0, &extension_id) ||
- !list->GetString(1, &launch_container) ||
- !ExtractInt(list, 2, &left) ||
- !ExtractInt(list, 3, &top) ||
- !ExtractInt(list, 4, &width) ||
- !ExtractInt(list, 5, &height)) {
+ if (!args->GetString(0, &extension_id) ||
+ !ExtractInt(args, 1, &left) ||
+ !ExtractInt(args, 2, &top) ||
+ !ExtractInt(args, 3, &width) ||
+ !ExtractInt(args, 4, &height)) {
NOTREACHED();
return;
}
@@ -162,27 +178,10 @@ void AppLauncherHandler::HandleLaunchApp(const Value* value) {
dom_ui_->tab_contents()->GetContainerBounds(&tab_contents_bounds);
rect.Offset(tab_contents_bounds.origin());
- // Override the default launch container.
Extension* extension =
extensions_service_->GetExtensionById(extension_id, false);
DCHECK(extension);
-
Profile* profile = extensions_service_->profile();
- if (launch_container.empty()) {
- AnimateAppIcon(extension, rect);
- Browser::OpenApplication(profile, extension_id);
- return;
- }
-
- Extension::LaunchContainer container = extension->launch_container();
- if (launch_container == "tab")
- container = Extension::LAUNCH_TAB;
- else if (launch_container == "panel")
- container = Extension::LAUNCH_PANEL;
- else if (launch_container == "window")
- container = Extension::LAUNCH_WINDOW;
- else
- NOTREACHED() << "Unexpected launch container: " << launch_container << ".";
// To give a more "launchy" experience when using the NTP launcher, we close
// it automatically.
@@ -192,7 +191,7 @@ void AppLauncherHandler::HandleLaunchApp(const Value* value) {
old_contents = browser->GetSelectedTabContents();
AnimateAppIcon(extension, rect);
- Browser::OpenApplication(profile, extension, container);
+ Browser::OpenApplication(profile, extension, extension->launch_container());
if (old_contents &&
old_contents->GetURL().GetOrigin() ==
@@ -201,6 +200,24 @@ void AppLauncherHandler::HandleLaunchApp(const Value* value) {
}
}
+void AppLauncherHandler::HandleSetLaunchType(const ListValue* args) {
+ std::string extension_id;
+ int launch_type;
+ if (!args->GetString(0, &extension_id) ||
+ !ExtractInt(args, 1, &launch_type)) {
+ NOTREACHED();
+ return;
+ }
+
+ Extension* extension =
+ extensions_service_->GetExtensionById(extension_id, false);
+ DCHECK(extension);
+
+ extensions_service_->extension_prefs()->SetLaunchType(
+ extension_id,
+ static_cast<ExtensionPrefs::LaunchType>(launch_type));
+}
+
void AppLauncherHandler::AnimateAppIcon(Extension* extension,
const gfx::Rect& rect) {
// We make this check for the case of minimized windows, unit tests, etc.
@@ -214,23 +231,41 @@ void AppLauncherHandler::AnimateAppIcon(Extension* extension,
}
}
-void AppLauncherHandler::HandleUninstallApp(const Value* value) {
- if (!value->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
+void AppLauncherHandler::HandleUninstallApp(const ListValue* args) {
+ std::string extension_id = WideToUTF8(ExtractStringValue(args));
+ Extension* extension = extensions_service_->GetExtensionById(
+ extension_id, false);
+ if (!extension)
return;
- }
- std::string extension_id;
- const ListValue* list = static_cast<const ListValue*>(value);
- if (!list->GetString(0, &extension_id)) {
- NOTREACHED();
- return;
- }
+ if (!extension_id_prompting_.empty())
+ return; // Only one prompt at a time.
+
+ extension_id_prompting_ = extension_id;
+ GetExtensionInstallUI()->ConfirmUninstall(this, extension);
+}
+
+ExtensionInstallUI* AppLauncherHandler::GetExtensionInstallUI() {
+ if (!install_ui_.get())
+ install_ui_.reset(new ExtensionInstallUI(dom_ui_->GetProfile()));
+ return install_ui_.get();
+}
- // Make sure that the extension exists.
+void AppLauncherHandler::InstallUIProceed() {
+ DCHECK(!extension_id_prompting_.empty());
+
+ // The extension can be uninstalled in another window while the UI was
+ // showing. Do nothing in that case.
Extension* extension =
- extensions_service_->GetExtensionById(extension_id, false);
- DCHECK(extension);
+ extensions_service_->GetExtensionById(extension_id_prompting_, true);
+ if (!extension)
+ return;
+
+ extensions_service_->UninstallExtension(extension_id_prompting_,
+ false /* external_uninstall */);
+ extension_id_prompting_ = "";
+}
- extensions_service_->UninstallExtension(extension_id, false);
+void AppLauncherHandler::InstallUIAbort() {
+ extension_id_prompting_ = "";
}
diff --git a/chrome/browser/dom_ui/app_launcher_handler.h b/chrome/browser/dom_ui/app_launcher_handler.h
index b20923c..23c1753 100644
--- a/chrome/browser/dom_ui/app_launcher_handler.h
+++ b/chrome/browser/dom_ui/app_launcher_handler.h
@@ -4,12 +4,20 @@
#ifndef CHROME_BROWSER_DOM_UI_APP_LAUNCHER_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_APP_LAUNCHER_HANDLER_H_
+#pragma once
+#include "base/scoped_ptr.h"
#include "chrome/browser/dom_ui/dom_ui.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class Extension;
+class ExtensionPrefs;
class ExtensionsService;
+class NotificationRegistrar;
+class PrefChangeRegistrar;
namespace gfx {
class Rect;
@@ -18,6 +26,7 @@ namespace gfx {
// The handler for Javascript messages related to the "apps" view.
class AppLauncherHandler
: public DOMMessageHandler,
+ public ExtensionInstallUI::Delegate,
public NotificationObserver {
public:
explicit AppLauncherHandler(ExtensionsService* extension_service);
@@ -33,18 +42,35 @@ class AppLauncherHandler
const NotificationDetails& details);
// Populate a dictionary with the information from an extension.
- static void CreateAppInfo(Extension* extension, DictionaryValue* value);
+ static void CreateAppInfo(Extension* extension,
+ ExtensionPrefs* extension_prefs,
+ DictionaryValue* value);
+
+ // Populate the given dictionary with all installed app info.
+ void FillAppDictionary(DictionaryValue* value);
// Callback for the "getApps" message.
- void HandleGetApps(const Value* value);
+ void HandleGetApps(const ListValue* args);
// Callback for the "launchApp" message.
- void HandleLaunchApp(const Value* value);
+ void HandleLaunchApp(const ListValue* args);
+
+ // Callback for the "setLaunchType" message.
+ void HandleSetLaunchType(const ListValue* args);
// Callback for the "uninstallApp" message.
- void HandleUninstallApp(const Value* value);
+ void HandleUninstallApp(const ListValue* args);
private:
+ // ExtensionInstallUI::Delegate implementation, used for receiving
+ // notification about uninstall confirmation dialog selections.
+ virtual void InstallUIProceed();
+ virtual void InstallUIAbort();
+
+ // Returns the ExtensionInstallUI object for this class, creating it if
+ // needed.
+ ExtensionInstallUI* GetExtensionInstallUI();
+
// Starts the animation of the app icon.
void AnimateAppIcon(Extension* extension, const gfx::Rect& rect);
@@ -55,6 +81,16 @@ class AppLauncherHandler
// when necessary.
NotificationRegistrar registrar_;
+ // Monitor extension preference changes so that the DOM UI can be notified.
+ PrefChangeRegistrar pref_change_registrar_;
+
+ // Used to show confirmation UI for uninstalling/enabling extensions in
+ // incognito mode.
+ scoped_ptr<ExtensionInstallUI> install_ui_;
+
+ // The id of the extension we are prompting the user about.
+ std::string extension_id_prompting_;
+
DISALLOW_COPY_AND_ASSIGN(AppLauncherHandler);
};
diff --git a/chrome/browser/dom_ui/bookmarks_ui.h b/chrome/browser/dom_ui/bookmarks_ui.h
index c8f2f79..8e8e61b 100644
--- a/chrome/browser/dom_ui/bookmarks_ui.h
+++ b/chrome/browser/dom_ui/bookmarks_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_BOOKMARKS_UI_H_
#define CHROME_BROWSER_DOM_UI_BOOKMARKS_UI_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/dom_ui/browser_options_handler.cc b/chrome/browser/dom_ui/browser_options_handler.cc
index 58d002d..3a21171 100644
--- a/chrome/browser/dom_ui/browser_options_handler.cc
+++ b/chrome/browser/dom_ui/browser_options_handler.cc
@@ -7,16 +7,27 @@
#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/singleton.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/chrome_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_managed_banner_handler.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/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/installer/util/browser_distribution.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
BrowserOptionsHandler::BrowserOptionsHandler()
- : template_url_model_(NULL) {
+ : template_url_model_(NULL), startup_custom_pages_table_model_(NULL) {
#if !defined(OS_MACOSX)
default_browser_worker_ = new ShellIntegration::DefaultBrowserWorker(this);
#endif
@@ -32,40 +43,40 @@ BrowserOptionsHandler::~BrowserOptionsHandler() {
void BrowserOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"startupGroupName",
- l10n_util::GetString(IDS_OPTIONS_STARTUP_GROUP_NAME));
- localized_strings->SetString(L"startupShowDefaultAndNewTab",
- l10n_util::GetString(IDS_OPTIONS_STARTUP_SHOW_DEFAULT_AND_NEWTAB));
- localized_strings->SetString(L"startupShowLastSession",
- l10n_util::GetString(IDS_OPTIONS_STARTUP_SHOW_LAST_SESSION));
- localized_strings->SetString(L"startupShowPages",
- l10n_util::GetString(IDS_OPTIONS_STARTUP_SHOW_PAGES));
- localized_strings->SetString(L"startupAddButton",
- l10n_util::GetString(IDS_OPTIONS_STARTUP_ADD_BUTTON));
- localized_strings->SetString(L"startupRemoveButton",
- l10n_util::GetString(IDS_OPTIONS_STARTUP_REMOVE_BUTTON));
- localized_strings->SetString(L"startupUseCurrent",
- l10n_util::GetString(IDS_OPTIONS_STARTUP_USE_CURRENT));
- localized_strings->SetString(L"homepageGroupName",
- l10n_util::GetString(IDS_OPTIONS_HOMEPAGE_GROUP_NAME));
- localized_strings->SetString(L"homepageUseNewTab",
- l10n_util::GetString(IDS_OPTIONS_HOMEPAGE_USE_NEWTAB));
- localized_strings->SetString(L"homepageUseURL",
- l10n_util::GetString(IDS_OPTIONS_HOMEPAGE_USE_URL));
- localized_strings->SetString(L"homepageShowButton",
- l10n_util::GetString(IDS_OPTIONS_HOMEPAGE_SHOW_BUTTON));
- localized_strings->SetString(L"defaultSearchGroupName",
- l10n_util::GetString(IDS_OPTIONS_DEFAULTSEARCH_GROUP_NAME));
- localized_strings->SetString(L"defaultSearchManageEnginesLink",
- l10n_util::GetString(IDS_OPTIONS_DEFAULTSEARCH_MANAGE_ENGINES_LINK));
- localized_strings->SetString(L"defaultBrowserGroupName",
- l10n_util::GetString(IDS_OPTIONS_DEFAULTBROWSER_GROUP_NAME));
- localized_strings->SetString(L"defaultBrowserUnknown",
- l10n_util::GetStringF(IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
- localized_strings->SetString(L"defaultBrowserUseAsDefault",
- l10n_util::GetStringF(IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
+ localized_strings->SetString("startupGroupName",
+ 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("startupUseCurrent",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_USE_CURRENT));
+ localized_strings->SetString("homepageGroupName",
+ 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("homepageShowButton",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_HOMEPAGE_SHOW_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));
+ localized_strings->SetString("defaultBrowserGroupName",
+ 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)));
+ localized_strings->SetString("defaultBrowserUseAsDefault",
+ l10n_util::GetStringFUTF16(IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
}
void BrowserOptionsHandler::RegisterMessages() {
@@ -75,17 +86,33 @@ void BrowserOptionsHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback(
"setDefaultSearchEngine",
NewCallback(this, &BrowserOptionsHandler::SetDefaultSearchEngine));
+ dom_ui_->RegisterMessageCallback(
+ "removeStartupPages",
+ NewCallback(this, &BrowserOptionsHandler::RemoveStartupPages));
+ dom_ui_->RegisterMessageCallback(
+ "addStartupPage",
+ NewCallback(this, &BrowserOptionsHandler::AddStartupPage));
+ dom_ui_->RegisterMessageCallback(
+ "setStartupPagesToCurrentPages",
+ NewCallback(this, &BrowserOptionsHandler::SetStartupPagesToCurrentPages));
}
void BrowserOptionsHandler::Initialize() {
- UpdateDefaultBrowserState();
+ // Create our favicon data source.
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ Singleton<ChromeURLDataManager>::get(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(new DOMUIFavIconSource(dom_ui_->GetProfile()))));
- template_url_model_ = dom_ui_->GetProfile()->GetTemplateURLModel();
- if (template_url_model_) {
- template_url_model_->Load();
- template_url_model_->AddObserver(this);
- OnTemplateURLModelChanged();
- }
+ UpdateDefaultBrowserState();
+ UpdateStartupPages();
+ UpdateSearchEngines();
+ banner_handler_.reset(
+ new OptionsManagedBannerHandler(dom_ui_,
+ ASCIIToUTF16("BrowserOptions"),
+ OPTIONS_PAGE_GENERAL));
}
void BrowserOptionsHandler::UpdateDefaultBrowserState() {
@@ -114,7 +141,8 @@ void BrowserOptionsHandler::UpdateDefaultBrowserState() {
#endif
}
-void BrowserOptionsHandler::BecomeDefaultBrowser(const Value* value) {
+void BrowserOptionsHandler::BecomeDefaultBrowser(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_SetAsDefaultBrowser"));
#if defined(OS_MACOSX)
if (ShellIntegration::SetAsDefaultBrowser())
UpdateDefaultBrowserState();
@@ -150,8 +178,8 @@ void BrowserOptionsHandler::SetDefaultBrowserUIState(
void BrowserOptionsHandler::SetDefaultBrowserUIString(int status_string_id) {
scoped_ptr<Value> status_string(Value::CreateStringValue(
- l10n_util::GetStringF(status_string_id,
- l10n_util::GetString(IDS_PRODUCT_NAME))));
+ l10n_util::GetStringFUTF16(status_string_id,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))));
scoped_ptr<Value> is_default(Value::CreateBooleanValue(
status_string_id == IDS_OPTIONS_DEFAULTBROWSER_DEFAULT));
@@ -177,8 +205,8 @@ void BrowserOptionsHandler::OnTemplateURLModelChanged() {
continue;
DictionaryValue* entry = new DictionaryValue();
- entry->SetString(L"name", model_urls[i]->short_name());
- entry->SetInteger(L"index", i);
+ entry->SetString("name", WideToUTF16Hack(model_urls[i]->short_name()));
+ entry->SetInteger("index", i);
search_engines.Append(entry);
if (model_urls[i] == default_url)
default_index = i;
@@ -190,24 +218,126 @@ void BrowserOptionsHandler::OnTemplateURLModelChanged() {
search_engines, *(default_value.get()));
}
-void BrowserOptionsHandler::SetDefaultSearchEngine(const Value* value) {
- if (!value || !value->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
- return;
- }
- const ListValue* param_values = static_cast<const ListValue*>(value);
- std::string string_value;
- if (param_values->GetSize() != 1 ||
- !param_values->GetString(0, &string_value)) {
+void BrowserOptionsHandler::SetDefaultSearchEngine(const ListValue* args) {
+ int selected_index = -1;
+ if (!ExtractIntegerValue(args, &selected_index)) {
NOTREACHED();
return;
}
- int selected_index = StringToInt(string_value);
std::vector<const TemplateURL*> model_urls =
template_url_model_->GetTemplateURLs();
if (selected_index >= 0 &&
selected_index < static_cast<int>(model_urls.size()))
template_url_model_->SetDefaultSearchProvider(model_urls[selected_index]);
+
+ UserMetricsRecordAction(UserMetricsAction("Options_SearchEngineChanged"));
+}
+
+void BrowserOptionsHandler::UpdateSearchEngines() {
+ template_url_model_ = dom_ui_->GetProfile()->GetTemplateURLModel();
+ if (template_url_model_) {
+ template_url_model_->Load();
+ template_url_model_->AddObserver(this);
+ OnTemplateURLModelChanged();
+ }
+}
+
+void BrowserOptionsHandler::UpdateStartupPages() {
+ Profile* profile = dom_ui_->GetProfile();
+ startup_custom_pages_table_model_.reset(
+ new CustomHomePagesTableModel(profile));
+ startup_custom_pages_table_model_->SetObserver(this);
+
+ const SessionStartupPref startup_pref =
+ SessionStartupPref::GetStartupPref(profile->GetPrefs());
+ startup_custom_pages_table_model_->SetURLs(startup_pref.urls);
+}
+
+void BrowserOptionsHandler::OnModelChanged() {
+ ListValue startup_pages;
+ int page_count = startup_custom_pages_table_model_->RowCount();
+ std::vector<GURL> urls = startup_custom_pages_table_model_->GetURLs();
+ for (int i = 0; i < page_count; ++i) {
+ DictionaryValue* entry = new DictionaryValue();
+ entry->SetString("title", WideToUTF16Hack(
+ startup_custom_pages_table_model_->GetText(i, 0)));
+ entry->SetString("url", urls[i].spec());
+ entry->SetString("tooltip", WideToUTF16Hack(
+ startup_custom_pages_table_model_->GetTooltip(i)));
+ startup_pages.Append(entry);
+ }
+
+ dom_ui_->CallJavascriptFunction(L"BrowserOptions.updateStartupPages",
+ startup_pages);
+}
+
+void BrowserOptionsHandler::OnItemsChanged(int start, int length) {
+ OnModelChanged();
+}
+
+void BrowserOptionsHandler::OnItemsAdded(int start, int length) {
+ OnModelChanged();
+}
+
+void BrowserOptionsHandler::OnItemsRemoved(int start, int length) {
+ OnModelChanged();
}
+void BrowserOptionsHandler::SetStartupPagesToCurrentPages(
+ const ListValue* args) {
+ startup_custom_pages_table_model_->SetToCurrentlyOpenPages();
+ SaveStartupPagesPref();
+}
+
+void BrowserOptionsHandler::RemoveStartupPages(const ListValue* args) {
+ for (int i = args->GetSize() - 1; i >= 0; --i) {
+ std::string string_value;
+ if (!args->GetString(i, &string_value)) {
+ NOTREACHED();
+ return;
+ }
+ int selected_index;
+ base::StringToInt(string_value, &selected_index);
+ if (selected_index < 0 ||
+ selected_index >= startup_custom_pages_table_model_->RowCount()) {
+ NOTREACHED();
+ return;
+ }
+ startup_custom_pages_table_model_->Remove(selected_index);
+ }
+
+ SaveStartupPagesPref();
+}
+
+void BrowserOptionsHandler::AddStartupPage(const ListValue* args) {
+ std::string url_string;
+ std::string index_string;
+ int index;
+ if (args->GetSize() != 2 ||
+ !args->GetString(0, &url_string) ||
+ !args->GetString(1, &index_string) ||
+ !base::StringToInt(index_string, &index)) {
+ NOTREACHED();
+ return;
+ };
+
+ if (index == -1)
+ index = startup_custom_pages_table_model_->RowCount();
+ else
+ ++index;
+
+ GURL url = URLFixerUpper::FixupURL(url_string, std::string());
+
+ startup_custom_pages_table_model_->Add(index, url);
+ SaveStartupPagesPref();
+}
+
+void BrowserOptionsHandler::SaveStartupPagesPref() {
+ PrefService* prefs = dom_ui_->GetProfile()->GetPrefs();
+
+ SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
+ pref.urls = startup_custom_pages_table_model_->GetURLs();
+
+ SessionStartupPref::SetStartupPref(prefs, pref);
+}
diff --git a/chrome/browser/dom_ui/browser_options_handler.h b/chrome/browser/dom_ui/browser_options_handler.h
index 3fb1a8e..0bc1ebb 100644
--- a/chrome/browser/dom_ui/browser_options_handler.h
+++ b/chrome/browser/dom_ui/browser_options_handler.h
@@ -4,15 +4,22 @@
#ifndef CHROME_BROWSER_DOM_UI_BROWSER_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_BROWSER_OPTIONS_HANDLER_H_
+#pragma once
+#include "app/table_model_observer.h"
#include "chrome/browser/dom_ui/options_ui.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
#include "chrome/browser/shell_integration.h"
+class CustomHomePagesTableModel;
+class OptionsManagedBannerHandler;
+class TemplateURLModel;
+
// Chrome browser options page UI handler.
class BrowserOptionsHandler : public OptionsPageUIHandler,
public ShellIntegration::DefaultBrowserObserver,
- public TemplateURLModelObserver {
+ public TemplateURLModelObserver,
+ public TableModelObserver {
public:
BrowserOptionsHandler();
virtual ~BrowserOptionsHandler();
@@ -30,12 +37,28 @@ class BrowserOptionsHandler : public OptionsPageUIHandler,
// TemplateURLModelObserver implementation.
virtual void OnTemplateURLModelChanged();
+ // TableModelObserver implementation.
+ 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:
// Makes this the default browser. Called from DOMUI.
- void BecomeDefaultBrowser(const Value* value);
+ void BecomeDefaultBrowser(const ListValue* args);
// Sets the search engine at the given index to be default. Called from DOMUI.
- void SetDefaultSearchEngine(const Value* value);
+ void SetDefaultSearchEngine(const ListValue* args);
+
+ // Removes the startup page at the given indexes. Called from DOMUI.
+ void RemoveStartupPages(const ListValue* args);
+
+ // Adds a startup page with the given URL after the given index.
+ // Called from DOMUI.
+ void AddStartupPage(const ListValue* args);
+
+ // Sets the startup page set to the current pages. Called from DOMUI.
+ void SetStartupPagesToCurrentPages(const ListValue* args);
// Returns the string ID for the given default browser state.
int StatusStringIdForState(ShellIntegration::DefaultBrowserState state);
@@ -47,10 +70,25 @@ class BrowserOptionsHandler : public OptionsPageUIHandler,
// Updates the UI with the given state for the default browser.
void SetDefaultBrowserUIString(int status_string_id);
+ // Loads the current set of custom startup pages and reports it to the DOMUI.
+ void UpdateStartupPages();
+
+ // Loads the possible default search engine list and reports it to the DOMUI.
+ void UpdateSearchEngines();
+
+ // Writes the current set of startup pages to prefs.
+ void SaveStartupPagesPref();
+
scoped_refptr<ShellIntegration::DefaultBrowserWorker> default_browser_worker_;
TemplateURLModel* template_url_model_; // Weak.
+ // TODO(stuartmorgan): Once there are no other clients of
+ // CustomHomePagesTableModel, consider changing it to something more like
+ // TemplateURLModel.
+ scoped_ptr<CustomHomePagesTableModel> startup_custom_pages_table_model_;
+ scoped_ptr<OptionsManagedBannerHandler> banner_handler_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserOptionsHandler);
};
diff --git a/chrome/browser/dom_ui/chrome_url_data_manager.cc b/chrome/browser/dom_ui/chrome_url_data_manager.cc
index 3f50a11..e25bea9 100644
--- a/chrome/browser/dom_ui/chrome_url_data_manager.cc
+++ b/chrome/browser/dom_ui/chrome_url_data_manager.cc
@@ -9,6 +9,7 @@
#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/path_service.h"
+#include "base/ref_counted_memory.h"
#include "base/singleton.h"
#include "base/string_util.h"
#include "base/thread.h"
@@ -270,6 +271,14 @@ void ChromeURLDataManager::DataAvailable(
}
}
+ChromeURLDataManager::DataSource::DataSource(const std::string& source_name,
+ MessageLoop* message_loop)
+ : source_name_(source_name), message_loop_(message_loop) {
+}
+
+ChromeURLDataManager::DataSource::~DataSource() {
+}
+
void ChromeURLDataManager::DataSource::SendResponse(
RequestID request_id,
RefCountedMemory* bytes) {
@@ -288,8 +297,8 @@ MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath(
// static
void ChromeURLDataManager::DataSource::SetFontAndTextDirection(
DictionaryValue* localized_strings) {
- localized_strings->SetString(L"fontfamily",
- l10n_util::GetString(IDS_WEB_FONT_FAMILY));
+ localized_strings->SetString("fontfamily",
+ l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY));
int web_font_size_id = IDS_WEB_FONT_SIZE;
#if defined(OS_WIN)
@@ -298,11 +307,11 @@ void ChromeURLDataManager::DataSource::SetFontAndTextDirection(
if (win_util::GetWinVersion() < win_util::WINVERSION_VISTA)
web_font_size_id = IDS_WEB_FONT_SIZE_XP;
#endif
- localized_strings->SetString(L"fontsize",
- l10n_util::GetString(web_font_size_id));
+ localized_strings->SetString("fontsize",
+ l10n_util::GetStringUTF16(web_font_size_id));
- localized_strings->SetString(L"textdirection",
- base::i18n::IsRTL() ? L"rtl" : L"ltr");
+ localized_strings->SetString("textdirection",
+ base::i18n::IsRTL() ? "rtl" : "ltr");
}
URLRequestJob* ChromeURLDataManager::Factory(URLRequest* request,
diff --git a/chrome/browser/dom_ui/chrome_url_data_manager.h b/chrome/browser/dom_ui/chrome_url_data_manager.h
index f08daaf..389b5fd 100644
--- a/chrome/browser/dom_ui/chrome_url_data_manager.h
+++ b/chrome/browser/dom_ui/chrome_url_data_manager.h
@@ -1,20 +1,22 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_CHROME_URL_DATA_MANAGER_H_
#define CHROME_BROWSER_DOM_UI_CHROME_URL_DATA_MANAGER_H_
+#pragma once
#include <map>
#include <string>
#include "base/task.h"
-#include "base/ref_counted_memory.h"
+#include "base/ref_counted.h"
class DictionaryValue;
class FilePath;
class GURL;
class MessageLoop;
+class RefCountedMemory;
class URLRequest;
class URLRequestChromeJob;
class URLRequestJob;
@@ -33,17 +35,19 @@ class ChromeURLDataManager {
typedef int RequestID;
// A DataSource is an object that can answer requests for data
- // asynchronously. It should live on a thread that outlives the IO thread
- // (in particular, the UI thread).
- // An implementation of DataSource should handle calls to StartDataRequest()
- // by starting its (implementation-specific) asynchronous request for
- // the data, then call SendResponse() to notify
+ // asynchronously. DataSources are collectively owned with refcounting smart
+ // pointers and should never be deleted on the IO thread, since their calls
+ // are handled almost always on the UI thread and there's a possibility of a
+ // data race.
+ //
+ // An implementation of DataSource should handle calls to
+ // StartDataRequest() by starting its (implementation-specific) asynchronous
+ // request for the data, then call SendResponse() to notify
class DataSource : public base::RefCountedThreadSafe<DataSource> {
public:
// See source_name_ and message_loop_ below for docs on these parameters.
DataSource(const std::string& source_name,
- MessageLoop* message_loop)
- : source_name_(source_name), message_loop_(message_loop) {}
+ MessageLoop* message_loop);
// Sent by the DataManager to request data at |path|. The source should
// call SendResponse() when the data is available or if the request could
@@ -80,7 +84,7 @@ class ChromeURLDataManager {
protected:
friend class base::RefCountedThreadSafe<DataSource>;
- virtual ~DataSource() {}
+ virtual ~DataSource();
private:
// The name of this source.
diff --git a/chrome/browser/dom_ui/clear_browser_data_handler.cc b/chrome/browser/dom_ui/clear_browser_data_handler.cc
index b8eeb55..61b1ffd 100644
--- a/chrome/browser/dom_ui/clear_browser_data_handler.cc
+++ b/chrome/browser/dom_ui/clear_browser_data_handler.cc
@@ -6,20 +6,126 @@
#include "app/l10n_util.h"
#include "base/basictypes.h"
+#include "base/string16.h"
#include "base/values.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
-ClearBrowserDataHandler::ClearBrowserDataHandler() {
+ClearBrowserDataHandler::ClearBrowserDataHandler() : remover_(NULL) {
}
ClearBrowserDataHandler::~ClearBrowserDataHandler() {
+ if (remover_) {
+ remover_->RemoveObserver(this);
+ }
}
void ClearBrowserDataHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"clearBrowsingDataTitle",
- l10n_util::GetString(IDS_CLEAR_BROWSING_DATA_TITLE));
+ localized_strings->SetString("clearBrowsingDataTitle",
+ l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_TITLE));
+ localized_strings->SetString("clearBrowsingDataLabel",
+ l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_LABEL));
+ localized_strings->SetString("clearBrowsingDataTimeLabel",
+ l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_TIME_LABEL));
+ localized_strings->SetString("deleteBrowsingHistoryCheckbox",
+ l10n_util::GetStringUTF16(IDS_DEL_BROWSING_HISTORY_CHKBOX));
+ localized_strings->SetString("deleteDownloadHistoryCheckbox",
+ l10n_util::GetStringUTF16(IDS_DEL_DOWNLOAD_HISTORY_CHKBOX));
+ localized_strings->SetString("deleteCacheCheckbox",
+ l10n_util::GetStringUTF16(IDS_DEL_CACHE_CHKBOX));
+ localized_strings->SetString("deleteCookiesCheckbox",
+ l10n_util::GetStringUTF16(IDS_DEL_COOKIES_CHKBOX));
+ localized_strings->SetString("deletePasswordsCheckbox",
+ l10n_util::GetStringUTF16(IDS_DEL_PASSWORDS_CHKBOX));
+ localized_strings->SetString("deleteFormDataCheckbox",
+ l10n_util::GetStringUTF16(IDS_DEL_FORM_DATA_CHKBOX));
+ localized_strings->SetString("clearBrowsingDataCommit",
+ l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_COMMIT));
+ localized_strings->SetString("flashStorageSettings",
+ l10n_util::GetStringUTF16(IDS_FLASH_STORAGE_SETTINGS));
+ localized_strings->SetString("flash_storage_url",
+ l10n_util::GetStringUTF16(IDS_FLASH_STORAGE_URL));
+ localized_strings->SetString("clearDataDeleting",
+ l10n_util::GetStringUTF16(IDS_CLEAR_DATA_DELETING));
+
+ ListValue* time_list = new ListValue;
+ for (int i = 0; i < 5; i++) {
+ string16 label_string;
+ switch (i) {
+ case 0:
+ label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_HOUR);
+ break;
+ case 1:
+ label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_DAY);
+ break;
+ case 2:
+ label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_WEEK);
+ break;
+ case 3:
+ label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_4WEEKS);
+ break;
+ case 4:
+ label_string = l10n_util::GetStringUTF16(IDS_CLEAR_DATA_EVERYTHING);
+ break;
+ }
+ ListValue* option = new ListValue();
+ option->Append(Value::CreateIntegerValue(i));
+ option->Append(Value::CreateStringValue(label_string));
+ time_list->Append(option);
+ }
+ localized_strings->Set("clearBrowsingDataTimeList", time_list);
+}
+
+void ClearBrowserDataHandler::RegisterMessages() {
+ // Setup handlers specific to this panel.
+ DCHECK(dom_ui_);
+ dom_ui_->RegisterMessageCallback("performClearBrowserData",
+ NewCallback(this, &ClearBrowserDataHandler::HandleClearBrowserData));
+}
+
+void ClearBrowserDataHandler::HandleClearBrowserData(const ListValue* value) {
+ Profile *profile = dom_ui_->GetProfile();
+ PrefService *prefs = profile->GetPrefs();
+
+ int remove_mask = 0;
+ if (prefs->GetBoolean(prefs::kDeleteBrowsingHistory))
+ remove_mask |= BrowsingDataRemover::REMOVE_HISTORY;
+ if (prefs->GetBoolean(prefs::kDeleteDownloadHistory))
+ remove_mask |= BrowsingDataRemover::REMOVE_DOWNLOADS;
+ if (prefs->GetBoolean(prefs::kDeleteCache))
+ remove_mask |= BrowsingDataRemover::REMOVE_CACHE;
+ if (prefs->GetBoolean(prefs::kDeleteCookies))
+ remove_mask |= BrowsingDataRemover::REMOVE_COOKIES;
+ if (prefs->GetBoolean(prefs::kDeletePasswords))
+ remove_mask |= BrowsingDataRemover::REMOVE_PASSWORDS;
+ if (prefs->GetBoolean(prefs::kDeleteFormData))
+ remove_mask |= BrowsingDataRemover::REMOVE_FORM_DATA;
+
+ int period_selected = prefs->GetInteger(prefs::kDeleteTimePeriod);
+
+ FundamentalValue state(true);
+ dom_ui_->CallJavascriptFunction(L"ClearBrowserDataOverlay.setClearingState",
+ state);
+
+ // BrowsingDataRemover deletes itself when done.
+ remover_ = new BrowsingDataRemover(profile,
+ static_cast<BrowsingDataRemover::TimePeriod>(period_selected),
+ base::Time());
+ remover_->AddObserver(this);
+ remover_->Remove(remove_mask);
+}
+
+void ClearBrowserDataHandler::OnBrowsingDataRemoverDone() {
+ // No need to remove ourselves as an observer as BrowsingDataRemover deletes
+ // itself after we return.
+ remover_ = NULL;
+ DCHECK(dom_ui_);
+ dom_ui_->CallJavascriptFunction(L"ClearBrowserDataOverlay.dismiss");
}
diff --git a/chrome/browser/dom_ui/clear_browser_data_handler.h b/chrome/browser/dom_ui/clear_browser_data_handler.h
index 138c5ec..7c29b79 100644
--- a/chrome/browser/dom_ui/clear_browser_data_handler.h
+++ b/chrome/browser/dom_ui/clear_browser_data_handler.h
@@ -4,11 +4,14 @@
#ifndef CHROME_BROWSER_DOM_UI_CLEAR_BROWSER_DATA_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_CLEAR_BROWSER_DATA_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/options_ui.h"
+#include "chrome/browser/browsing_data_remover.h"
-// Chrome personal options page UI handler.
-class ClearBrowserDataHandler : public OptionsPageUIHandler {
+// Clear browser data handler page UI handler.
+class ClearBrowserDataHandler : public OptionsPageUIHandler,
+ public BrowsingDataRemover::Observer {
public:
ClearBrowserDataHandler();
virtual ~ClearBrowserDataHandler();
@@ -16,9 +19,20 @@ class ClearBrowserDataHandler : public OptionsPageUIHandler {
// OptionsUIHandler implementation.
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+ // DOMMessageHandler implementation.
+ virtual void RegisterMessages();
+
private:
+ void HandleClearBrowserData(const ListValue* value);
+
+ // Callback from BrowsingDataRemover. Closes the dialog.
+ virtual void OnBrowsingDataRemoverDone();
+
+ // If non-null it means removal is in progress. BrowsingDataRemover takes care
+ // of deleting itself when done.
+ BrowsingDataRemover* remover_;
+
DISALLOW_COPY_AND_ASSIGN(ClearBrowserDataHandler);
};
#endif // CHROME_BROWSER_DOM_UI_CLEAR_BROWSER_DATA_HANDLER_H_
-
diff --git a/chrome/browser/dom_ui/content_settings_handler.cc b/chrome/browser/dom_ui/content_settings_handler.cc
index 9a006b8..ce84717 100644
--- a/chrome/browser/dom_ui/content_settings_handler.cc
+++ b/chrome/browser/dom_ui/content_settings_handler.cc
@@ -6,38 +6,24 @@
#include "app/l10n_util.h"
#include "base/callback.h"
+#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "base/values.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/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/url_constants.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
-namespace {
+typedef HostContentSettingsMap::ContentSettingsDetails ContentSettingsDetails;
-std::wstring ContentSettingsTypeToGroupName(ContentSettingsType type) {
- switch (type) {
- case CONTENT_SETTINGS_TYPE_COOKIES:
- return L"cookies";
- case CONTENT_SETTINGS_TYPE_IMAGES:
- return L"images";
- case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
- return L"javascript";
- case CONTENT_SETTINGS_TYPE_PLUGINS:
- return L"plugins";
- case CONTENT_SETTINGS_TYPE_POPUPS:
- return L"popups";
- case CONTENT_SETTINGS_TYPE_GEOLOCATION:
- return L"location";
- case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
- return L"notifications";
-
- default:
- NOTREACHED();
- return L"";
- }
-}
+namespace {
ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
if (name == "cookies")
@@ -67,6 +53,8 @@ std::string ContentSettingToString(ContentSetting setting) {
return "ask";
case CONTENT_SETTING_BLOCK:
return "block";
+ case CONTENT_SETTING_SESSION_ONLY:
+ return "session";
default:
NOTREACHED();
@@ -81,6 +69,8 @@ ContentSetting ContentSettingFromString(const std::string& name) {
return CONTENT_SETTING_ASK;
if (name == "block")
return CONTENT_SETTING_BLOCK;
+ if (name == "session")
+ return CONTENT_SETTING_SESSION_ONLY;
NOTREACHED();
return CONTENT_SETTING_DEFAULT;
@@ -98,155 +88,435 @@ void ContentSettingsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"content_exceptions",
- l10n_util::GetString(IDS_COOKIES_EXCEPTIONS_BUTTON));
- localized_strings->SetString(L"contentSettingsPage",
- l10n_util::GetString(IDS_CONTENT_SETTINGS_TITLE));
+ localized_strings->SetString("content_exceptions",
+ l10n_util::GetStringUTF16(IDS_COOKIES_EXCEPTIONS_BUTTON));
+ localized_strings->SetString("contentSettingsPage",
+ l10n_util::GetStringUTF16(IDS_CONTENT_SETTINGS_TITLE));
+ localized_strings->SetString("allowException",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_ALLOW_BUTTON));
+ localized_strings->SetString("blockException",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_BLOCK_BUTTON));
+ localized_strings->SetString("sessionException",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_SESSION_ONLY_BUTTON));
+ localized_strings->SetString("askException",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_ASK_BUTTON));
+ localized_strings->SetString("addExceptionRow",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_ADD_BUTTON));
+ localized_strings->SetString("removeExceptionRow",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_REMOVE_BUTTON));
+ localized_strings->SetString("editExceptionRow",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_EDIT_BUTTON));
+ localized_strings->SetString("otr_exceptions_explanation",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_OTR_LABEL));
// Cookies filter.
- localized_strings->SetString(L"cookies_tab_label",
- l10n_util::GetString(IDS_COOKIES_TAB_LABEL));
- localized_strings->SetString(L"cookies_modify",
- l10n_util::GetString(IDS_MODIFY_COOKIE_STORING_LABEL));
- localized_strings->SetString(L"cookies_allow",
- l10n_util::GetString(IDS_COOKIES_ALLOW_RADIO));
- localized_strings->SetString(L"cookies_block",
- l10n_util::GetString(IDS_COOKIES_BLOCK_RADIO));
- localized_strings->SetString(L"cookies_block_3rd_party",
- l10n_util::GetString(IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX));
- localized_strings->SetString(L"cookies_clear_on_exit",
- l10n_util::GetString(IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX));
- localized_strings->SetString(L"cookies_show_cookies",
- l10n_util::GetString(IDS_COOKIES_SHOW_COOKIES_BUTTON));
- localized_strings->SetString(L"flash_storage_settings",
- l10n_util::GetString(IDS_FLASH_STORAGE_SETTINGS));
- localized_strings->SetString(L"flash_storage_url",
- l10n_util::GetString(IDS_FLASH_STORAGE_URL));
+ 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_allow",
+ l10n_util::GetStringUTF16(IDS_COOKIES_ALLOW_RADIO));
+ localized_strings->SetString("cookies_ask",
+ l10n_util::GetStringUTF16(IDS_COOKIES_ASK_EVERY_TIME_RADIO));
+ localized_strings->SetString("cookies_block",
+ l10n_util::GetStringUTF16(IDS_COOKIES_BLOCK_RADIO));
+ localized_strings->SetString("cookies_block_3rd_party",
+ l10n_util::GetStringUTF16(IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX));
+ localized_strings->SetString("cookies_clear_on_exit",
+ l10n_util::GetStringUTF16(IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX));
+ localized_strings->SetString("cookies_show_cookies",
+ l10n_util::GetStringUTF16(IDS_COOKIES_SHOW_COOKIES_BUTTON));
+ localized_strings->SetString("flash_storage_settings",
+ l10n_util::GetStringUTF16(IDS_FLASH_STORAGE_SETTINGS));
+ localized_strings->SetString("flash_storage_url",
+ l10n_util::GetStringUTF16(IDS_FLASH_STORAGE_URL));
// Image filter.
- localized_strings->SetString(L"images_tab_label",
- l10n_util::GetString(IDS_IMAGES_TAB_LABEL));
- localized_strings->SetString(L"images_setting",
- l10n_util::GetString(IDS_IMAGES_SETTING_LABEL));
- localized_strings->SetString(L"images_allow",
- l10n_util::GetString(IDS_IMAGES_LOAD_RADIO));
- localized_strings->SetString(L"images_block",
- l10n_util::GetString(IDS_IMAGES_NOLOAD_RADIO));
+ 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_allow",
+ l10n_util::GetStringUTF16(IDS_IMAGES_LOAD_RADIO));
+ localized_strings->SetString("images_block",
+ l10n_util::GetStringUTF16(IDS_IMAGES_NOLOAD_RADIO));
// JavaScript filter.
- localized_strings->SetString(L"javascript_tab_label",
- l10n_util::GetString(IDS_JAVASCRIPT_TAB_LABEL));
- localized_strings->SetString(L"javascript_setting",
- l10n_util::GetString(IDS_JS_SETTING_LABEL));
- localized_strings->SetString(L"javascript_allow",
- l10n_util::GetString(IDS_JS_ALLOW_RADIO));
- localized_strings->SetString(L"javascript_block",
- l10n_util::GetString(IDS_JS_DONOTALLOW_RADIO));
+ 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_allow",
+ l10n_util::GetStringUTF16(IDS_JS_ALLOW_RADIO));
+ localized_strings->SetString("javascript_block",
+ l10n_util::GetStringUTF16(IDS_JS_DONOTALLOW_RADIO));
// Plug-ins filter.
- localized_strings->SetString(L"plugins_tab_label",
- l10n_util::GetString(IDS_PLUGIN_TAB_LABEL));
- localized_strings->SetString(L"plugins_setting",
- l10n_util::GetString(IDS_PLUGIN_SETTING_LABEL));
- localized_strings->SetString(L"plugins_allow",
- l10n_util::GetString(IDS_PLUGIN_LOAD_RADIO));
- localized_strings->SetString(L"plugins_block",
- l10n_util::GetString(IDS_PLUGIN_NOLOAD_RADIO));
- localized_strings->SetString(L"disable_individual_plugins",
- l10n_util::GetString(IDS_PLUGIN_SELECTIVE_DISABLE));
- localized_strings->SetString(L"chrome_plugin_url",
+ 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_allow_sandboxed",
+ l10n_util::GetStringUTF16(IDS_PLUGIN_LOAD_SANDBOXED_RADIO));
+ localized_strings->SetString("plugins_allow",
+ l10n_util::GetStringUTF16(IDS_PLUGIN_LOAD_RADIO));
+ localized_strings->SetString("plugins_block",
+ l10n_util::GetStringUTF16(IDS_PLUGIN_NOLOAD_RADIO));
+ localized_strings->SetString("disable_individual_plugins",
+ l10n_util::GetStringUTF16(IDS_PLUGIN_SELECTIVE_DISABLE));
+ localized_strings->SetString("chrome_plugin_url",
chrome::kChromeUIPluginsURL);
// Pop-ups filter.
- localized_strings->SetString(L"popups_tab_label",
- l10n_util::GetString(IDS_POPUP_TAB_LABEL));
- localized_strings->SetString(L"popups_setting",
- l10n_util::GetString(IDS_POPUP_SETTING_LABEL));
- localized_strings->SetString(L"popups_allow",
- l10n_util::GetString(IDS_POPUP_ALLOW_RADIO));
- localized_strings->SetString(L"popups_block",
- l10n_util::GetString(IDS_POPUP_BLOCK_RADIO));
+ 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_allow",
+ l10n_util::GetStringUTF16(IDS_POPUP_ALLOW_RADIO));
+ localized_strings->SetString("popups_block",
+ l10n_util::GetStringUTF16(IDS_POPUP_BLOCK_RADIO));
// Location filter.
- localized_strings->SetString(L"location_tab_label",
- l10n_util::GetString(IDS_GEOLOCATION_TAB_LABEL));
- localized_strings->SetString(L"location_setting",
- l10n_util::GetString(IDS_GEOLOCATION_SETTING_LABEL));
- localized_strings->SetString(L"location_allow",
- l10n_util::GetString(IDS_GEOLOCATION_ALLOW_RADIO));
- localized_strings->SetString(L"location_ask",
- l10n_util::GetString(IDS_GEOLOCATION_ASK_RADIO));
- localized_strings->SetString(L"location_block",
- l10n_util::GetString(IDS_GEOLOCATION_BLOCK_RADIO));
+ 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_allow",
+ l10n_util::GetStringUTF16(IDS_GEOLOCATION_ALLOW_RADIO));
+ localized_strings->SetString("location_ask",
+ l10n_util::GetStringUTF16(IDS_GEOLOCATION_ASK_RADIO));
+ localized_strings->SetString("location_block",
+ l10n_util::GetStringUTF16(IDS_GEOLOCATION_BLOCK_RADIO));
// Notifications filter.
- localized_strings->SetString(L"notifications_tab_label",
- l10n_util::GetString(IDS_NOTIFICATIONS_TAB_LABEL));
- localized_strings->SetString(L"notifications_setting",
- l10n_util::GetString(IDS_NOTIFICATIONS_SETTING_LABEL));
- localized_strings->SetString(L"notifications_allow",
- l10n_util::GetString(IDS_NOTIFICATIONS_ALLOW_RADIO));
- localized_strings->SetString(L"notifications_ask",
- l10n_util::GetString(IDS_NOTIFICATIONS_ASK_RADIO));
- localized_strings->SetString(L"notifications_block",
- l10n_util::GetString(IDS_NOTIFICATIONS_BLOCK_RADIO));
+ 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_allow",
+ l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_ALLOW_RADIO));
+ localized_strings->SetString("notifications_ask",
+ l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_ASK_RADIO));
+ localized_strings->SetString("notifications_block",
+ l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_BLOCK_RADIO));
+}
+
+void ContentSettingsHandler::Initialize() {
+ const HostContentSettingsMap* settings_map = GetContentSettingsMap();
+ scoped_ptr<Value> block_3rd_party(Value::CreateBooleanValue(
+ settings_map->BlockThirdPartyCookies()));
+ dom_ui_->CallJavascriptFunction(
+ L"ContentSettings.setBlockThirdPartyCookies", *block_3rd_party.get());
+
+ UpdateAllExceptionsViewsFromModel();
+ notification_registrar_.Add(
+ this, NotificationType::CONTENT_SETTINGS_CHANGED,
+ Source<const HostContentSettingsMap>(settings_map));
+}
+
+void ContentSettingsHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type != NotificationType::CONTENT_SETTINGS_CHANGED)
+ return OptionsPageUIHandler::Observe(type, source, details);
+
+ const ContentSettingsDetails* settings_details =
+ static_cast<Details<const ContentSettingsDetails> >(details).ptr();
+
+ // TODO(estade): we pretend update_all() is always true.
+ if (settings_details->update_all_types())
+ UpdateAllExceptionsViewsFromModel();
+ else
+ UpdateExceptionsViewFromModel(settings_details->type());
+}
+
+void ContentSettingsHandler::UpdateExceptionsDefaultFromModel(
+ ContentSettingsType type) {
+ DictionaryValue filter_settings;
+ filter_settings.SetString(ContentSettingsTypeToGroupName(type),
+ GetExceptionsDefaultFromModel(type));
+
+ dom_ui_->CallJavascriptFunction(
+ L"ContentSettings.setContentFilterSettingsValue", filter_settings);
+}
+
+std::string ContentSettingsHandler::GetExceptionsDefaultFromModel(
+ ContentSettingsType type) {
+ ContentSetting default_setting;
+ const HostContentSettingsMap* settings_map = GetContentSettingsMap();
+ if (type == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ default_setting = settings_map->GetDefaultContentSetting(type);
+ if (settings_map->GetBlockNonsandboxedPlugins())
+ default_setting = CONTENT_SETTING_ASK;
+ } else if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ default_setting = dom_ui_->GetProfile()->
+ GetGeolocationContentSettingsMap()->GetDefaultContentSetting();
+ } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+ default_setting = dom_ui_->GetProfile()->
+ GetDesktopNotificationService()->GetDefaultContentSetting();
+ } else {
+ default_setting = GetContentSettingsMap()->GetDefaultContentSetting(type);
+ }
+
+ return ContentSettingToString(default_setting);
+}
+
+void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
+ for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
+ type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
+ UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
+ }
+}
+
+void ContentSettingsHandler::UpdateExceptionsViewFromModel(
+ ContentSettingsType type) {
+ HostContentSettingsMap::SettingsForOneType entries;
+ GetContentSettingsMap()->GetSettingsForOneType(type, "", &entries);
+
+ ListValue exceptions;
+ for (size_t i = 0; i < entries.size(); ++i) {
+ ListValue* exception = new ListValue();
+ exception->Append(new StringValue(entries[i].first.AsString()));
+ exception->Append(
+ new StringValue(ContentSettingToString(entries[i].second)));
+ exceptions.Append(exception);
+ }
+
+ StringValue type_string(ContentSettingsTypeToGroupName(type));
+ dom_ui_->CallJavascriptFunction(
+ L"ContentSettings.setExceptions", type_string, exceptions);
+
+ // The default may also have changed (we won't get a separate notification).
+ // If it hasn't changed, this call will be harmless.
+ UpdateExceptionsDefaultFromModel(type);
+
+ const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
+ if (otr_settings_map && type != CONTENT_SETTINGS_TYPE_GEOLOCATION &&
+ type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+ HostContentSettingsMap::SettingsForOneType otr_entries;
+ otr_settings_map->GetSettingsForOneType(type, "", &otr_entries);
+
+ ListValue otr_exceptions;
+ for (size_t i = 0; i < otr_entries.size(); ++i) {
+ ListValue* exception = new ListValue();
+ exception->Append(new StringValue(otr_entries[i].first.AsString()));
+ exception->Append(
+ new StringValue(ContentSettingToString(otr_entries[i].second)));
+ otr_exceptions.Append(exception);
+ }
+
+ dom_ui_->CallJavascriptFunction(
+ L"ContentSettings.setOTRExceptions", type_string, otr_exceptions);
+ }
}
void ContentSettingsHandler::RegisterMessages() {
- dom_ui_->RegisterMessageCallback("getContentFilterSettings",
- NewCallback(this,
- &ContentSettingsHandler::GetContentFilterSettings));
dom_ui_->RegisterMessageCallback("setContentFilter",
NewCallback(this,
&ContentSettingsHandler::SetContentFilter));
dom_ui_->RegisterMessageCallback("setAllowThirdPartyCookies",
NewCallback(this,
&ContentSettingsHandler::SetAllowThirdPartyCookies));
+ dom_ui_->RegisterMessageCallback("removeExceptions",
+ NewCallback(this,
+ &ContentSettingsHandler::RemoveExceptions));
+ dom_ui_->RegisterMessageCallback("setException",
+ NewCallback(this,
+ &ContentSettingsHandler::SetException));
+ dom_ui_->RegisterMessageCallback("checkExceptionPatternValidity",
+ NewCallback(this,
+ &ContentSettingsHandler::CheckExceptionPatternValidity));
}
-void ContentSettingsHandler::GetContentFilterSettings(const Value* value) {
- // We send a list of the <input> IDs that should be checked.
- DictionaryValue dict_value;
-
- const HostContentSettingsMap* settings_map =
- dom_ui_->GetProfile()->GetHostContentSettingsMap();
- for (int i = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
- i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
- ContentSettingsType type = static_cast<ContentSettingsType>(i);
- ContentSetting default_setting = settings_map->
- GetDefaultContentSetting(type);
+void ContentSettingsHandler::SetContentFilter(const ListValue* args) {
+ DCHECK_EQ(2U, args->GetSize());
+ std::string group, setting;
+ if (!(args->GetString(0, &group) &&
+ args->GetString(1, &setting))) {
+ NOTREACHED();
+ return;
+ }
- dict_value.SetString(ContentSettingsTypeToGroupName(type),
- ContentSettingToString(default_setting));
+ ContentSetting default_setting = ContentSettingFromString(setting);
+ ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
+ if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ if (default_setting == CONTENT_SETTING_ASK) {
+ default_setting = CONTENT_SETTING_ALLOW;
+ GetContentSettingsMap()->SetBlockNonsandboxedPlugins(true);
+ } else {
+ GetContentSettingsMap()->SetBlockNonsandboxedPlugins(false);
+ }
+ GetContentSettingsMap()->
+ SetDefaultContentSetting(content_type, default_setting);
+ } else if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ dom_ui_->GetProfile()->GetGeolocationContentSettingsMap()->
+ SetDefaultContentSetting(default_setting);
+ } else if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+ dom_ui_->GetProfile()->GetDesktopNotificationService()->
+ SetDefaultContentSetting(default_setting);
+ } else {
+ GetContentSettingsMap()->
+ SetDefaultContentSetting(content_type, default_setting);
}
+}
- dom_ui_->CallJavascriptFunction(
- L"ContentSettings.setInitialContentFilterSettingsValue", dict_value);
+void ContentSettingsHandler::SetAllowThirdPartyCookies(const ListValue* args) {
+ std::wstring allow = ExtractStringValue(args);
- scoped_ptr<Value> bool_value(Value::CreateBooleanValue(
- settings_map->BlockThirdPartyCookies()));
- dom_ui_->CallJavascriptFunction(
- L"ContentSettings.setBlockThirdPartyCookies", *bool_value.get());
+ GetContentSettingsMap()->SetBlockThirdPartyCookies(allow == L"true");
}
-void ContentSettingsHandler::SetContentFilter(const Value* value) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- DCHECK_EQ(2U, list_value->GetSize());
- std::string group, setting;
- if (!(list_value->GetString(0, &group) &&
- list_value->GetString(1, &setting))) {
+void ContentSettingsHandler::RemoveExceptions(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));
+ }
+ } 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);
+ }
+ }
+ }
+}
+
+void ContentSettingsHandler::SetException(const ListValue* args) {
+ size_t arg_i = 0;
+ std::string type_string;
+ CHECK(args->GetString(arg_i++, &type_string));
+ std::string mode;
+ CHECK(args->GetString(arg_i++, &mode));
+ std::string pattern;
+ CHECK(args->GetString(arg_i++, &pattern));
+ std::string setting;
+ CHECK(args->GetString(arg_i++, &setting));
+
+ ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
+ if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
+ type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
NOTREACHED();
return;
}
- dom_ui_->GetProfile()->GetHostContentSettingsMap()->SetDefaultContentSetting(
- ContentSettingsTypeFromGroupName(group),
- ContentSettingFromString(setting));
+ 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)
+ return;
+
+ settings_map->
+ SetContentSetting(HostContentSettingsMap::Pattern(pattern),
+ type,
+ "",
+ ContentSettingFromString(setting));
}
-void ContentSettingsHandler::SetAllowThirdPartyCookies(const Value* value) {
- std::wstring allow = ExtractStringValue(value);
+void ContentSettingsHandler::CheckExceptionPatternValidity(
+ const ListValue* args) {
+ size_t arg_i = 0;
+ Value* type;
+ CHECK(args->Get(arg_i++, &type));
+ std::string mode_string;
+ CHECK(args->GetString(arg_i++, &mode_string));
+ std::string pattern_string;
+ CHECK(args->GetString(arg_i++, &pattern_string));
+
+ HostContentSettingsMap::Pattern pattern(pattern_string);
+
+ scoped_ptr<Value> mode_value(Value::CreateStringValue(mode_string));
+ scoped_ptr<Value> pattern_value(Value::CreateStringValue(pattern_string));
+ scoped_ptr<Value> valid_value(Value::CreateBooleanValue(pattern.IsValid()));
+
+ dom_ui_->CallJavascriptFunction(
+ L"ContentSettings.patternValidityCheckComplete", *type,
+ *mode_value.get(),
+ *pattern_value.get(),
+ *valid_value.get());
+}
+
+// static
+std::string ContentSettingsHandler::ContentSettingsTypeToGroupName(
+ ContentSettingsType type) {
+ switch (type) {
+ case CONTENT_SETTINGS_TYPE_COOKIES:
+ return "cookies";
+ case CONTENT_SETTINGS_TYPE_IMAGES:
+ return "images";
+ case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
+ return "javascript";
+ case CONTENT_SETTINGS_TYPE_PLUGINS:
+ return "plugins";
+ case CONTENT_SETTINGS_TYPE_POPUPS:
+ return "popups";
+ case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+ return "location";
+ case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+ return "notifications";
+
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
+HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
+ return dom_ui_->GetProfile()->GetHostContentSettingsMap();
+}
- dom_ui_->GetProfile()->GetHostContentSettingsMap()->SetBlockThirdPartyCookies(
- allow == L"true");
+HostContentSettingsMap*
+ ContentSettingsHandler::GetOTRContentSettingsMap() {
+ Profile* profile = dom_ui_->GetProfile();
+ if (profile->HasOffTheRecordProfile())
+ return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
+ return NULL;
}
diff --git a/chrome/browser/dom_ui/content_settings_handler.h b/chrome/browser/dom_ui/content_settings_handler.h
index b20651a..f0803e0 100644
--- a/chrome/browser/dom_ui/content_settings_handler.h
+++ b/chrome/browser/dom_ui/content_settings_handler.h
@@ -4,8 +4,14 @@
#ifndef CHROME_BROWSER_DOM_UI_CONTENT_SETTINGS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_CONTENT_SETTINGS_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/options_ui.h"
+#include "chrome/common/content_settings_types.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class HostContentSettingsMap;
class ContentSettingsHandler : public OptionsPageUIHandler {
public:
@@ -15,12 +21,32 @@ class ContentSettingsHandler : public OptionsPageUIHandler {
// OptionsUIHandler implementation.
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+ virtual void Initialize();
+
virtual void RegisterMessages();
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Gets a string identifier for the group name, for use in HTML.
+ static std::string ContentSettingsTypeToGroupName(ContentSettingsType type);
+
private:
- void GetContentFilterSettings(const Value* value);
- void SetContentFilter(const Value* value);
- void SetAllowThirdPartyCookies(const Value* value);
+ void UpdateExceptionsDefaultFromModel(ContentSettingsType type);
+ std::string GetExceptionsDefaultFromModel(ContentSettingsType type);
+ void UpdateAllExceptionsViewsFromModel();
+ void UpdateExceptionsViewFromModel(ContentSettingsType type);
+ void SetContentFilter(const ListValue* args);
+ void SetAllowThirdPartyCookies(const ListValue* args);
+ void RemoveExceptions(const ListValue* args);
+ void SetException(const ListValue* args);
+ void CheckExceptionPatternValidity(const ListValue* args);
+ HostContentSettingsMap* GetContentSettingsMap();
+ HostContentSettingsMap* GetOTRContentSettingsMap();
+
+ NotificationRegistrar notification_registrar_;
DISALLOW_COPY_AND_ASSIGN(ContentSettingsHandler);
};
diff --git a/chrome/browser/dom_ui/core_options_handler.cc b/chrome/browser/dom_ui/core_options_handler.cc
index c162335..849e768 100644
--- a/chrome/browser/dom_ui/core_options_handler.cc
+++ b/chrome/browser/dom_ui/core_options_handler.cc
@@ -5,13 +5,15 @@
#include "chrome/browser/dom_ui/core_options_handler.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#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/common/notification_service.h"
#include "chrome/common/notification_type.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/profile.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -21,49 +23,83 @@
CoreOptionsHandler::CoreOptionsHandler() {
}
-CoreOptionsHandler::~CoreOptionsHandler() {
- // Remove registered preference change notification observers.
- DCHECK(dom_ui_);
- PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
- std::wstring last_pref;
+void CoreOptionsHandler::GetLocalizedValues(
+ DictionaryValue* localized_strings) {
+ DCHECK(localized_strings);
+ // Main
+ localized_strings->SetString("title",
+ l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));
+ localized_strings->SetString("browserPage",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_GENERAL_TAB_LABEL));
+ localized_strings->SetString("personalPage",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_CONTENT_TAB_LABEL));
+ localized_strings->SetString("advancedPage",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_TAB_LABEL));
+#if defined(OS_CHROMEOS)
+ localized_strings->SetString("internetPage",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_INTERNET_TAB_LABEL));
+ localized_strings->SetString("languageChewingPage",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTINGS_TITLE));
+ localized_strings->SetString("languageHangulPage",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_HANGUL_SETTINGS_TITLE));
+ localized_strings->SetString("languageMozcPage",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_MOZC_SETTINGS_TITLE));
+ localized_strings->SetString("languagePinyinPage",
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_SETTINGS_LANGUAGES_PINYIN_SETTINGS_TITLE));
+#endif
+ localized_strings->SetString("managedPrefsBannerText",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_MANAGED_PREFS));
+
+ localized_strings->SetString("ok",
+ l10n_util::GetStringUTF16(IDS_OK));
+ localized_strings->SetString("cancel",
+ l10n_util::GetStringUTF16(IDS_CANCEL));
+ localized_strings->SetString("delete",
+ l10n_util::GetStringUTF16(IDS_DELETE));
+ localized_strings->SetString("edit",
+ l10n_util::GetStringUTF16(IDS_EDIT));
+ localized_strings->SetString("learnMore",
+ l10n_util::GetStringUTF16(IDS_LEARN_MORE));
+ localized_strings->SetString("abort",
+ l10n_util::GetStringUTF16(IDS_ABORT));
+ localized_strings->SetString("close",
+ l10n_util::GetStringUTF16(IDS_CLOSE));
+ localized_strings->SetString("done",
+ l10n_util::GetStringUTF16(IDS_DONE));
+ localized_strings->SetString("yesButtonLabel",
+ l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL));
+ localized_strings->SetString("noButtonLabel",
+ l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
+}
+
+void CoreOptionsHandler::Uninitialize() {
+ std::string last_pref;
for (PreferenceCallbackMap::const_iterator iter = pref_callback_map_.begin();
iter != pref_callback_map_.end();
++iter) {
if (last_pref != iter->first) {
- pref_service->RemovePrefObserver(iter->first.c_str(), this);
+ StopObservingPref(iter->first);
last_pref = iter->first;
}
}
}
-void CoreOptionsHandler::GetLocalizedValues(
- DictionaryValue* localized_strings) {
- DCHECK(localized_strings);
- // Main
- localized_strings->SetString(L"title",
- l10n_util::GetStringF(IDS_OPTIONS_DIALOG_TITLE,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
-
- localized_strings->SetString(L"browserPage",
- l10n_util::GetString(IDS_OPTIONS_GENERAL_TAB_LABEL));
- localized_strings->SetString(L"personalPage",
- l10n_util::GetString(IDS_OPTIONS_CONTENT_TAB_LABEL));
- localized_strings->SetString(L"advancedPage",
- l10n_util::GetString(IDS_OPTIONS_ADVANCED_TAB_LABEL));
-#if defined(OS_CHROMEOS)
- localized_strings->SetString(L"internetPage",
- l10n_util::GetString(IDS_OPTIONS_INTERNET_TAB_LABEL));
- localized_strings->SetString(L"languageHangulPage",
- l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_LANGUAGES_HANGUL_SETTINGS_TITLE));
-#endif
+DOMMessageHandler* CoreOptionsHandler::Attach(DOMUI* dom_ui) {
+ DOMMessageHandler* result = DOMMessageHandler::Attach(dom_ui);
+ DCHECK(dom_ui_);
+ registrar_.Init(dom_ui_->GetProfile()->GetPrefs());
+ return result;
}
void CoreOptionsHandler::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED)
- NotifyPrefChanged(Details<std::wstring>(details).ptr());
+ NotifyPrefChanged(Details<std::string>(details).ptr());
}
void CoreOptionsHandler::RegisterMessages() {
@@ -81,32 +117,41 @@ void CoreOptionsHandler::RegisterMessages() {
NewCallback(this, &CoreOptionsHandler::HandleSetStringPref));
dom_ui_->RegisterMessageCallback("setObjectPref",
NewCallback(this, &CoreOptionsHandler::HandleSetObjectPref));
+ dom_ui_->RegisterMessageCallback("coreOptionsUserMetricsAction",
+ NewCallback(this, &CoreOptionsHandler::HandleUserMetricsAction));
}
-void CoreOptionsHandler::HandleInitialize(const Value* value) {
- (static_cast<OptionsUI*>(dom_ui_))->InitializeHandlers();
+void CoreOptionsHandler::HandleInitialize(const ListValue* args) {
+ static_cast<OptionsUI*>(dom_ui_)->InitializeHandlers();
}
-Value* CoreOptionsHandler::FetchPref(const std::wstring& pref_name) {
+Value* CoreOptionsHandler::FetchPref(const std::string& pref_name) {
DCHECK(dom_ui_);
PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
const PrefService::Preference* pref =
pref_service->FindPreference(pref_name.c_str());
- return pref ? pref->GetValue()->DeepCopy() : Value::CreateNullValue();
+ Value* return_value;
+ if (pref) {
+ DictionaryValue* dict = new DictionaryValue;
+ dict->Set("value", pref->GetValue()->DeepCopy());
+ dict->SetBoolean("managed", pref->IsManaged());
+ return_value = dict;
+ } else {
+ return_value = Value::CreateNullValue();
+ }
+ return return_value;
}
-void CoreOptionsHandler::ObservePref(const std::wstring& pref_name) {
- DCHECK(dom_ui_);
- PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
-
- pref_service->AddPrefObserver(pref_name.c_str(), this);
+void CoreOptionsHandler::ObservePref(const std::string& pref_name) {
+ registrar_.Add(pref_name.c_str(), this);
}
-void CoreOptionsHandler::SetPref(const std::wstring& pref_name,
+void CoreOptionsHandler::SetPref(const std::string& pref_name,
Value::ValueType pref_type,
- const std::string& value_string) {
+ const std::string& value_string,
+ const std::string& metric) {
DCHECK(dom_ui_);
PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
@@ -116,7 +161,7 @@ void CoreOptionsHandler::SetPref(const std::wstring& pref_name,
break;
case Value::TYPE_INTEGER:
int int_value;
- if (StringToInt(value_string, &int_value))
+ if (base::StringToInt(value_string, &int_value))
pref_service->SetInteger(pref_name.c_str(), int_value);
break;
case Value::TYPE_STRING:
@@ -124,29 +169,43 @@ void CoreOptionsHandler::SetPref(const std::wstring& pref_name,
break;
default:
NOTREACHED();
+ return;
}
+
+ pref_service->ScheduleSavePersistentPrefs();
+ ProcessUserMetric(pref_type, value_string, metric);
}
-void CoreOptionsHandler::HandleFetchPrefs(const Value* value) {
- if (!value || !value->IsType(Value::TYPE_LIST))
+void CoreOptionsHandler::ProcessUserMetric(Value::ValueType pref_type,
+ const std::string& value_string,
+ const std::string& metric) {
+ if (metric.empty())
return;
- const ListValue* param_values = static_cast<const ListValue*>(value);
+ std::string metric_string = metric;
+ if (pref_type == Value::TYPE_BOOLEAN)
+ metric_string += (value_string == "true" ? "_Enable" : "_Disable");
+ UserMetricsRecordAction(UserMetricsAction(metric_string.c_str()));
+}
+
+void CoreOptionsHandler::StopObservingPref(const std::string& path) {
+ registrar_.Remove(path.c_str(), this);
+}
+
+void CoreOptionsHandler::HandleFetchPrefs(const ListValue* args) {
// First param is name of callback function, so, there needs to be at least
// one more element for the actual preference identifier.
const size_t kMinFetchPrefsParamCount = 2;
- if (param_values->GetSize() < kMinFetchPrefsParamCount)
+ if (args->GetSize() < kMinFetchPrefsParamCount)
return;
- size_t idx = param_values->GetSize();
- LOG(INFO) << "param_values->GetSize() = " << idx;
// Get callback JS function name.
Value* callback;
- if (!param_values->Get(0, &callback) || !callback->IsType(Value::TYPE_STRING))
+ if (!args->Get(0, &callback) || !callback->IsType(Value::TYPE_STRING))
return;
- std::wstring callback_function;
+ string16 callback_function;
if (!callback->GetAsString(&callback_function))
return;
@@ -154,48 +213,43 @@ void CoreOptionsHandler::HandleFetchPrefs(const Value* value) {
DictionaryValue result_value;
Value* list_member;
- for (size_t i = 1; i < param_values->GetSize(); i++) {
- if (!param_values->Get(i, &list_member))
+ for (size_t i = 1; i < args->GetSize(); i++) {
+ if (!args->Get(i, &list_member))
break;
if (!list_member->IsType(Value::TYPE_STRING))
continue;
- std::wstring pref_name;
+ std::string pref_name;
if (!list_member->GetAsString(&pref_name))
continue;
result_value.Set(pref_name.c_str(), FetchPref(pref_name));
}
- dom_ui_->CallJavascriptFunction(callback_function.c_str(), result_value);
+ dom_ui_->CallJavascriptFunction(UTF16ToWideHack(callback_function).c_str(),
+ result_value);
}
-void CoreOptionsHandler::HandleObservePrefs(const Value* value) {
- if (!value || !value->IsType(Value::TYPE_LIST))
- return;
-
- DictionaryValue result_value;
- const ListValue* list_value = static_cast<const ListValue*>(value);
-
+void CoreOptionsHandler::HandleObservePrefs(const ListValue* args) {
// First param is name is JS callback function name, the rest are pref
// identifiers that we are observing.
const size_t kMinObservePrefsParamCount = 2;
- if (list_value->GetSize() < kMinObservePrefsParamCount)
+ if (args->GetSize() < kMinObservePrefsParamCount)
return;
// Get preference change callback function name.
- std::wstring callback_func_name;
- if (!list_value->GetString(0, &callback_func_name))
+ string16 callback_func_name;
+ if (!args->GetString(0, &callback_func_name))
return;
// Get all other parameters - pref identifiers.
- for (size_t i = 1; i < list_value->GetSize(); i++) {
+ for (size_t i = 1; i < args->GetSize(); i++) {
Value* list_member;
- if (!list_value->Get(i, &list_member))
+ if (!args->Get(i, &list_member))
break;
// Just ignore bad pref identifiers for now.
- std::wstring pref_name;
+ std::string pref_name;
if (!list_member->IsType(Value::TYPE_STRING) ||
!list_member->GetAsString(&pref_name))
continue;
@@ -204,48 +258,54 @@ void CoreOptionsHandler::HandleObservePrefs(const Value* value) {
ObservePref(pref_name);
pref_callback_map_.insert(
- PreferenceCallbackMap::value_type(pref_name, callback_func_name));
+ PreferenceCallbackMap::value_type(pref_name,
+ UTF16ToWideHack(callback_func_name)));
}
}
-void CoreOptionsHandler::HandleSetBooleanPref(const Value* value) {
- HandleSetPref(value, Value::TYPE_BOOLEAN);
+void CoreOptionsHandler::HandleSetBooleanPref(const ListValue* args) {
+ HandleSetPref(args, Value::TYPE_BOOLEAN);
}
-void CoreOptionsHandler::HandleSetIntegerPref(const Value* value) {
- HandleSetPref(value, Value::TYPE_INTEGER);
+void CoreOptionsHandler::HandleSetIntegerPref(const ListValue* args) {
+ HandleSetPref(args, Value::TYPE_INTEGER);
}
-void CoreOptionsHandler::HandleSetStringPref(const Value* value) {
- HandleSetPref(value, Value::TYPE_STRING);
+void CoreOptionsHandler::HandleSetStringPref(const ListValue* args) {
+ HandleSetPref(args, Value::TYPE_STRING);
}
-void CoreOptionsHandler::HandleSetObjectPref(const Value* value) {
- HandleSetPref(value, Value::TYPE_NULL);
+void CoreOptionsHandler::HandleSetObjectPref(const ListValue* args) {
+ HandleSetPref(args, Value::TYPE_NULL);
}
-void CoreOptionsHandler::HandleSetPref(const Value* value,
+void CoreOptionsHandler::HandleSetPref(const ListValue* args,
Value::ValueType type) {
- if (!value || !value->IsType(Value::TYPE_LIST))
- return;
- const ListValue* param_values = static_cast<const ListValue*>(value);
- size_t size = param_values->GetSize();
- LOG(INFO) << "Array size = " << size;
- if (param_values->GetSize() != 2)
+ if (args->GetSize() < 2)
return;
- std::wstring pref_name;
- if (!param_values->GetString(0, &pref_name))
+ std::string pref_name;
+ if (!args->GetString(0, &pref_name))
return;
std::string value_string;
- if (!param_values->GetString(1, &value_string))
+ if (!args->GetString(1, &value_string))
return;
- SetPref(pref_name, type, value_string);
+ std::string metric;
+ if (args->GetSize() > 2)
+ args->GetString(2, &metric);
+
+ SetPref(pref_name, type, value_string, metric);
}
-void CoreOptionsHandler::NotifyPrefChanged(const std::wstring* pref_name) {
+void CoreOptionsHandler::HandleUserMetricsAction(const ListValue* args) {
+ std::string metric = WideToUTF8(ExtractStringValue(args));
+ if (!metric.empty())
+ UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
+}
+
+void CoreOptionsHandler::NotifyPrefChanged(const std::string* pref_name) {
DCHECK(pref_name);
DCHECK(dom_ui_);
PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
@@ -258,8 +318,14 @@ void CoreOptionsHandler::NotifyPrefChanged(const std::wstring* pref_name) {
const std::wstring& callback_function = iter->second;
ListValue result_value;
result_value.Append(Value::CreateStringValue(pref_name->c_str()));
- result_value.Append(pref->GetValue()->DeepCopy());
+
+ DictionaryValue* dict = new DictionaryValue;
+ dict->Set("value", pref->GetValue()->DeepCopy());
+ dict->SetBoolean("managed", pref->IsManaged());
+ result_value.Append(dict);
+
dom_ui_->CallJavascriptFunction(callback_function, result_value);
}
}
}
+
diff --git a/chrome/browser/dom_ui/core_options_handler.h b/chrome/browser/dom_ui/core_options_handler.h
index ed6d2f1..fd94d10 100644
--- a/chrome/browser/dom_ui/core_options_handler.h
+++ b/chrome/browser/dom_ui/core_options_handler.h
@@ -4,22 +4,24 @@
#ifndef CHROME_BROWSER_DOM_UI_CORE_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_CORE_OPTIONS_HANDLER_H_
+#pragma once
#include <map>
#include <string>
#include "base/values.h"
#include "chrome/browser/dom_ui/options_ui.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
// Core options UI handler.
// Handles resource and JS calls common to all options sub-pages.
class CoreOptionsHandler : public OptionsPageUIHandler {
public:
CoreOptionsHandler();
- virtual ~CoreOptionsHandler();
// OptionsUIHandler implementation.
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+ virtual void Uninitialize();
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
@@ -28,50 +30,66 @@ class CoreOptionsHandler : public OptionsPageUIHandler {
// DOMMessageHandler implementation.
virtual void RegisterMessages();
+ virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
protected:
// Fetches a pref value of given |pref_name|.
// Note that caller owns the returned Value.
- virtual Value* FetchPref(const std::wstring& pref_name);
+ virtual Value* FetchPref(const std::string& pref_name);
// Observes a pref of given |pref_name|.
- virtual void ObservePref(const std::wstring& pref_name);
+ virtual void ObservePref(const std::string& pref_name);
// Sets a pref value |value_string| of |pref_type| to given |pref_name|.
- virtual void SetPref(const std::wstring& pref_name,
+ virtual void SetPref(const std::string& pref_name,
Value::ValueType pref_type,
- const std::string& value_string);
+ const std::string& value_string,
+ const std::string& metric);
+ // Stops observing given preference identified by |path|.
+ virtual void StopObservingPref(const std::string& path);
+
+ // Records a user metric action for the given value.
+ void ProcessUserMetric(Value::ValueType pref_type,
+ const std::string& value_string,
+ const std::string& metric);
+
+ typedef std::multimap<std::string, std::wstring> PreferenceCallbackMap;
+ PreferenceCallbackMap pref_callback_map_;
private:
- typedef std::multimap<std::wstring, std::wstring> PreferenceCallbackMap;
// Callback for the "coreOptionsInitialize" message. This message will
// trigger the Initialize() method of all other handlers so that final
// setup can be performed before the page is shown.
- void HandleInitialize(const Value* value);
+ void HandleInitialize(const ListValue* args);
// Callback for the "fetchPrefs" message. This message accepts the list of
// preference names passed as |value| parameter (ListValue). It passes results
// dictionary of preference values by calling prefsFetched() JS method on the
// page.
- void HandleFetchPrefs(const Value* value);
+ void HandleFetchPrefs(const ListValue* args);
// Callback for the "observePrefs" message. This message initiates
// notification observing for given array of preference names.
- void HandleObservePrefs(const Value* value);
+ void HandleObservePrefs(const ListValue* args);
// Callbacks for the "set<type>Pref" message. This message saves the new
// preference value. The input value is an array of strings representing
// name-value preference pair.
- void HandleSetBooleanPref(const Value* value);
- void HandleSetIntegerPref(const Value* value);
- void HandleSetStringPref(const Value* value);
- void HandleSetObjectPref(const Value* value);
+ void HandleSetBooleanPref(const ListValue* args);
+ void HandleSetIntegerPref(const ListValue* args);
+ void HandleSetStringPref(const ListValue* args);
+ void HandleSetObjectPref(const ListValue* args);
- void HandleSetPref(const Value* value, Value::ValueType type);
+ void HandleSetPref(const ListValue* args, Value::ValueType type);
- void NotifyPrefChanged(const std::wstring* pref_name);
+ // Callback for the "coreOptionsUserMetricsAction" message. This records
+ // an action that should be tracked if metrics recording is enabled.
+ void HandleUserMetricsAction(const ListValue* args);
+
+ void NotifyPrefChanged(const std::string* pref_name);
+
+ PrefChangeRegistrar registrar_;
- PreferenceCallbackMap pref_callback_map_;
DISALLOW_COPY_AND_ASSIGN(CoreOptionsHandler);
};
diff --git a/chrome/browser/dom_ui/devtools_ui.cc b/chrome/browser/dom_ui/devtools_ui.cc
index 04fcd04..ddb55c8 100644
--- a/chrome/browser/dom_ui/devtools_ui.cc
+++ b/chrome/browser/dom_ui/devtools_ui.cc
@@ -6,7 +6,6 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/render_messages.h"
-#include "chrome/common/url_constants.h"
DevToolsUI::DevToolsUI(TabContents* contents) : DOMUI(contents) {
}
diff --git a/chrome/browser/dom_ui/devtools_ui.h b/chrome/browser/dom_ui/devtools_ui.h
index ecdc413..f41c871 100644
--- a/chrome/browser/dom_ui/devtools_ui.h
+++ b/chrome/browser/dom_ui/devtools_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_DEVTOOLS_UI_H_
#define CHROME_BROWSER_DOM_UI_DEVTOOLS_UI_H_
+#pragma once
#include "chrome/browser/dom_ui/dom_ui.h"
diff --git a/chrome/browser/dom_ui/dom_ui.cc b/chrome/browser/dom_ui/dom_ui.cc
index 8b9c45f..f257d1e 100644
--- a/chrome/browser/dom_ui/dom_ui.cc
+++ b/chrome/browser/dom_ui/dom_ui.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,20 +7,39 @@
#include "base/i18n/rtl.h"
#include "base/json/json_writer.h"
#include "base/stl_util-inl.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_theme_provider.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/themes/browser_theme_provider.h"
#include "chrome/common/bindings_policy.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+
+namespace {
+
+std::wstring GetJavascript(const std::wstring& function_name,
+ const std::vector<const Value*>& arg_list) {
+ std::wstring parameters;
+ std::string json;
+ for (size_t i = 0; i < arg_list.size(); ++i) {
+ if (i > 0)
+ parameters += L",";
+
+ base::JSONWriter::Write(arg_list[i], false, &json);
+ parameters += UTF8ToWide(json);
+ }
+ return function_name + L"(" + parameters + L");";
+}
+
+} // namespace
DOMUI::DOMUI(TabContents* contents)
: hide_favicon_(false),
force_bookmark_bar_visible_(false),
- force_extension_shelf_visible_(false),
focus_location_bar_by_default_(false),
should_hide_url_(false),
link_transition_type_(PageTransition::LINK),
@@ -36,19 +55,15 @@ DOMUI::~DOMUI() {
// DOMUI, public: -------------------------------------------------------------
-void DOMUI::ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
+void DOMUI::ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params) {
// Look up the callback for this message.
MessageCallbackMap::const_iterator callback =
- message_callbacks_.find(message);
+ message_callbacks_.find(params.name);
if (callback == message_callbacks_.end())
return;
// Forward this message and content on.
- callback->second->Run(content);
+ callback->second->Run(&params.arguments);
}
void DOMUI::CallJavascriptFunction(const std::wstring& function_name) {
@@ -58,23 +73,42 @@ void DOMUI::CallJavascriptFunction(const std::wstring& function_name) {
void DOMUI::CallJavascriptFunction(const std::wstring& function_name,
const Value& arg) {
- std::string json;
- base::JSONWriter::Write(&arg, false, &json);
- std::wstring javascript = function_name + L"(" + UTF8ToWide(json) + L");";
-
- ExecuteJavascript(javascript);
+ std::vector<const Value*> args;
+ args.push_back(&arg);
+ ExecuteJavascript(GetJavascript(function_name, args));
}
void DOMUI::CallJavascriptFunction(
const std::wstring& function_name,
const Value& arg1, const Value& arg2) {
- std::string json;
- base::JSONWriter::Write(&arg1, false, &json);
- std::wstring javascript = function_name + L"(" + UTF8ToWide(json);
- base::JSONWriter::Write(&arg2, false, &json);
- javascript += L"," + UTF8ToWide(json) + L");";
+ std::vector<const Value*> args;
+ args.push_back(&arg1);
+ args.push_back(&arg2);
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
- ExecuteJavascript(javascript);
+void DOMUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const Value& arg1, const Value& arg2, const Value& arg3) {
+ std::vector<const Value*> args;
+ args.push_back(&arg1);
+ args.push_back(&arg2);
+ args.push_back(&arg3);
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
+
+void DOMUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2,
+ const Value& arg3,
+ const Value& arg4) {
+ std::vector<const Value*> args;
+ args.push_back(&arg1);
+ args.push_back(&arg2);
+ args.push_back(&arg3);
+ args.push_back(&arg4);
+ ExecuteJavascript(GetJavascript(function_name, args));
}
ThemeProvider* DOMUI::GetThemeProvider() const {
@@ -86,7 +120,7 @@ void DOMUI::RegisterMessageCallback(const std::string &message,
message_callbacks_.insert(std::make_pair(message, callback));
}
-Profile* DOMUI::GetProfile() {
+Profile* DOMUI::GetProfile() const {
return tab_contents()->profile();
}
@@ -117,13 +151,12 @@ DOMMessageHandler* DOMMessageHandler::Attach(DOMUI* dom_ui) {
void DOMMessageHandler::SetURLAndTitle(DictionaryValue* dictionary,
string16 title,
const GURL& gurl) {
- string16 url16 = UTF8ToUTF16(gurl.spec());
- dictionary->SetStringFromUTF16(L"url", url16);
+ dictionary->SetString("url", gurl.spec());
bool using_url_as_the_title = false;
if (title.empty()) {
using_url_as_the_title = true;
- title = url16;
+ title = UTF8ToUTF16(gurl.spec());
}
// Since the title can contain BiDi text, we need to mark the text as either
@@ -140,27 +173,23 @@ void DOMMessageHandler::SetURLAndTitle(DictionaryValue* dictionary,
DCHECK(success ? (title != title_to_set) : (title == title_to_set));
}
}
- dictionary->SetStringFromUTF16(L"title", title_to_set);
+ dictionary->SetString("title", title_to_set);
}
-bool DOMMessageHandler::ExtractIntegerValue(const Value* value, int* out_int) {
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string string_value;
- if (list_value->GetString(0, &string_value)) {
- *out_int = StringToInt(string_value);
- return true;
- }
- }
+bool DOMMessageHandler::ExtractIntegerValue(const ListValue* value,
+ int* out_int) {
+ std::string string_value;
+ if (value->GetString(0, &string_value))
+ return base::StringToInt(string_value, out_int);
+ NOTREACHED();
return false;
}
-std::wstring DOMMessageHandler::ExtractStringValue(const Value* value) {
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::wstring wstring_value;
- if (list_value->GetString(0, &wstring_value))
- return wstring_value;
- }
+// TODO(viettrungluu): convert to string16 (or UTF-8 std::string?).
+std::wstring DOMMessageHandler::ExtractStringValue(const ListValue* value) {
+ string16 string16_value;
+ if (value->GetString(0, &string16_value))
+ return UTF16ToWideHack(string16_value);
+ NOTREACHED();
return std::wstring();
}
diff --git a/chrome/browser/dom_ui/dom_ui.h b/chrome/browser/dom_ui/dom_ui.h
index 4c20dff..d180a51 100644
--- a/chrome/browser/dom_ui/dom_ui.h
+++ b/chrome/browser/dom_ui/dom_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_DOM_UI_H_
#define CHROME_BROWSER_DOM_UI_DOM_UI_H_
+#pragma once
#include <map>
#include <string>
@@ -19,9 +20,10 @@ class GURL;
class ListValue;
class Profile;
class RenderViewHost;
-class Value;
class TabContents;
class ThemeProvider;
+class Value;
+struct ViewHostMsg_DomMessage_Params;
// A DOMUI sets up the datasources and message handlers for a given HTML-based
// UI. It is contained by a DOMUIManager.
@@ -41,14 +43,10 @@ class DOMUI {
virtual void RenderViewReused(RenderViewHost* render_view_host) {}
// Called from TabContents.
- virtual void ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback);
+ virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params);
// Used by DOMMessageHandlers.
- typedef Callback1<const Value*>::Type MessageCallback;
+ typedef Callback1<const ListValue*>::Type MessageCallback;
void RegisterMessageCallback(const std::string& message,
MessageCallback* callback);
@@ -63,12 +61,6 @@ class DOMUI {
return force_bookmark_bar_visible_;
}
- // Returns true if the extension shelf should be forced to being visible
- // (if it contains any items), overriding the user's preference.
- bool force_extension_shelf_visible() const {
- return force_extension_shelf_visible_;
- }
-
// Returns true if the location bar should be focused by default rather than
// the page contents. Some pages will want to use this to encourage the user
// to type in the URL bar.
@@ -103,19 +95,28 @@ class DOMUI {
// the renderer. This is asynchronous; there's no way to get the result
// of the call, and should be thought of more like sending a message to
// the page.
- // There are two function variants for one-arg and two-arg calls.
+ // There are variants for calls with more arguments.
void CallJavascriptFunction(const std::wstring& function_name);
void CallJavascriptFunction(const std::wstring& function_name,
const Value& arg);
void CallJavascriptFunction(const std::wstring& function_name,
const Value& arg1,
const Value& arg2);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2,
+ const Value& arg3);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2,
+ const Value& arg3,
+ const Value& arg4);
ThemeProvider* GetThemeProvider() const;
TabContents* tab_contents() const { return tab_contents_; }
- Profile* GetProfile();
+ Profile* GetProfile() const;
protected:
void AddMessageHandler(DOMMessageHandler* handler);
@@ -124,7 +125,6 @@ class DOMUI {
// bool options default to false. See the public getters for more information.
bool hide_favicon_;
bool force_bookmark_bar_visible_;
- bool force_extension_shelf_visible_;
bool focus_location_bar_by_default_;
bool should_hide_url_;
string16 overridden_title_; // Defaults to empty string.
@@ -173,10 +173,10 @@ class DOMMessageHandler {
virtual void RegisterMessages() = 0;
// Extract an integer value from a list Value.
- bool ExtractIntegerValue(const Value* value, int* out_int);
+ bool ExtractIntegerValue(const ListValue* value, int* out_int);
// Extract a string value from a list Value.
- std::wstring ExtractStringValue(const Value* value);
+ std::wstring ExtractStringValue(const ListValue* value);
DOMUI* dom_ui_;
diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc
index f51fe22..ac3c462 100644
--- a/chrome/browser/dom_ui/dom_ui_factory.cc
+++ b/chrome/browser/dom_ui/dom_ui_factory.cc
@@ -7,11 +7,16 @@
#include "base/command_line.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/bookmarks_ui.h"
+#include "chrome/browser/dom_ui/bug_report_ui.h"
#include "chrome/browser/dom_ui/downloads_ui.h"
#include "chrome/browser/dom_ui/devtools_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/labs_ui.h"
#include "chrome/browser/dom_ui/net_internals_ui.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/dom_ui/options_ui.h"
@@ -21,6 +26,7 @@
#include "chrome/browser/extensions/extension_dom_ui.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extensions_ui.h"
+#include "chrome/browser/labs.h"
#include "chrome/browser/printing/print_dialog_cloud.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -30,9 +36,12 @@
#include "googleurl/src/gurl.h"
#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/dom_ui/imageburner_ui.h"
+#include "chrome/browser/chromeos/dom_ui/mobile_setup_ui.h"
+#include "chrome/browser/chromeos/dom_ui/register_page_ui.h"
+#include "chrome/browser/chromeos/dom_ui/system_info_ui.h"
#include "chrome/browser/dom_ui/filebrowse_ui.h"
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
-#include "chrome/browser/dom_ui/register_page_ui.h"
#endif
const DOMUITypeID DOMUIFactory::kNoDOMUI = NULL;
@@ -51,14 +60,13 @@ DOMUI* NewDOMUI(TabContents* contents, const GURL& url) {
// Special case for extensions.
template<>
DOMUI* NewDOMUI<ExtensionDOMUI>(TabContents* contents, const GURL& url) {
- // Don't use a DOMUI for non-existent extensions or for incognito tabs. The
- // latter restriction is because we require extensions to run within a single
- // process.
+ // Don't use a DOMUI for incognito tabs because we require extensions to run
+ // within a single process.
ExtensionsService* service = contents->profile()->GetExtensionsService();
- bool valid_extension =
- (service && service->GetExtensionById(url.host(), false));
- if (valid_extension && !contents->profile()->IsOffTheRecord())
- return new ExtensionDOMUI(contents);
+ if (service &&
+ service->ExtensionBindingsAllowed(url)) {
+ return new ExtensionDOMUI(contents, url);
+ }
return NULL;
}
@@ -66,12 +74,14 @@ DOMUI* NewDOMUI<ExtensionDOMUI>(TabContents* contents, const GURL& url) {
// tab, based on its URL. Returns NULL if the URL doesn't have DOMUI associated
// with it. Even if the factory function is valid, it may yield a NULL DOMUI
// when invoked for a particular tab - see NewDOMUI<ExtensionDOMUI>.
-static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) {
+static DOMUIFactoryFunction GetDOMUIFactoryFunction(Profile* profile,
+ const GURL& url) {
// Currently, any gears: URL means an HTML dialog.
if (url.SchemeIs(chrome::kGearsScheme))
return &NewDOMUI<HtmlDialogUI>;
- if (url.SchemeIs(chrome::kExtensionScheme))
+ ExtensionsService* service = profile->GetExtensionsService();
+ if (service && service->ExtensionBindingsAllowed(url))
return &NewDOMUI<ExtensionDOMUI>;
// All platform builds of Chrome will need to have a cloud printing
@@ -86,7 +96,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) {
!url.SchemeIs(chrome::kChromeUIScheme))
return NULL;
- if (url.host() == chrome::kChromeUISyncResourcesHost)
+ if (url.host() == chrome::kChromeUISyncResourcesHost ||
+ url.host() == chrome::kChromeUIRemotingResourcesHost)
return &NewDOMUI<HtmlDialogUI>;
// Special case the new tab page. In older versions of Chrome, the new tab
@@ -101,6 +112,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) {
// after the host name.
if (url.host() == chrome::kChromeUIBookmarksHost)
return &NewDOMUI<BookmarksUI>;
+ if (url.host() == chrome::kChromeUIBugReportHost)
+ return &NewDOMUI<BugReportUI>;
if (url.host() == chrome::kChromeUIDevToolsHost)
return &NewDOMUI<DevToolsUI>;
if (url.host() == chrome::kChromeUIDownloadsHost)
@@ -111,6 +124,12 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) {
return &NewDOMUI<HistoryUI>;
if (url.host() == chrome::kChromeUIHistory2Host)
return &NewDOMUI<HistoryUI2>;
+ if (about_labs::IsEnabled() && url.host() == chrome::kChromeUILabsHost)
+ return &NewDOMUI<LabsUI>;
+#if defined(TOUCH_UI)
+ if (url.host() == chrome::kChromeUIKeyboardHost)
+ return &NewDOMUI<KeyboardUI>;
+#endif
if (url.host() == chrome::kChromeUINetInternalsHost)
return &NewDOMUI<NetInternalsUI>;
if (url.host() == chrome::kChromeUIPluginsHost)
@@ -118,7 +137,7 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) {
#if defined(ENABLE_REMOTING)
if (url.host() == chrome::kChromeUIRemotingHost) {
if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableChromoting)) {
+ switches::kEnableRemoting)) {
return &NewDOMUI<RemotingUI>;
}
}
@@ -127,16 +146,22 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) {
#if defined(OS_CHROMEOS)
if (url.host() == chrome::kChromeUIFileBrowseHost)
return &NewDOMUI<FileBrowseUI>;
+ if (url.host() == chrome::kChromeUIImageBurnerHost)
+ return &NewDOMUI<ImageBurnUI>;
if (url.host() == chrome::kChromeUIMediaplayerHost)
return &NewDOMUI<MediaplayerUI>;
+ if (url.host() == chrome::kChromeUIMobileSetupHost)
+ return &NewDOMUI<MobileSetupUI>;
+ if (url.host() == chrome::kChromeUISettingsHost)
+ return &NewDOMUI<OptionsUI>;
if (url.host() == chrome::kChromeUIRegisterPageHost)
return &NewDOMUI<RegisterPageUI>;
if (url.host() == chrome::kChromeUISlideshowHost)
return &NewDOMUI<SlideshowUI>;
- if (url.host() == chrome::kChromeUIOptionsHost)
- return &NewDOMUI<OptionsUI>;
+ if (url.host() == chrome::kChromeUISystemInfoHost)
+ return &NewDOMUI<SystemInfoUI>;
#else
- if (url.host() == chrome::kChromeUIOptionsHost) {
+ if (url.host() == chrome::kChromeUISettingsHost) {
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableTabbedOptions)) {
return &NewDOMUI<OptionsUI>;
@@ -148,8 +173,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) {
}
// static
-DOMUITypeID DOMUIFactory::GetDOMUIType(const GURL& url) {
- DOMUIFactoryFunction function = GetDOMUIFactoryFunction(url);
+DOMUITypeID DOMUIFactory::GetDOMUIType(Profile* profile, const GURL& url) {
+ DOMUIFactoryFunction function = GetDOMUIFactoryFunction(profile, url);
return function ? reinterpret_cast<DOMUITypeID>(function) : kNoDOMUI;
}
@@ -161,14 +186,15 @@ bool DOMUIFactory::HasDOMUIScheme(const GURL& url) {
}
// static
-bool DOMUIFactory::UseDOMUIForURL(const GURL& url) {
- return GetDOMUIFactoryFunction(url) != NULL;
+bool DOMUIFactory::UseDOMUIForURL(Profile* profile, const GURL& url) {
+ return GetDOMUIFactoryFunction(profile, url) != NULL;
}
// static
DOMUI* DOMUIFactory::CreateDOMUIForURL(TabContents* tab_contents,
const GURL& url) {
- DOMUIFactoryFunction function = GetDOMUIFactoryFunction(url);
+ DOMUIFactoryFunction function = GetDOMUIFactoryFunction(
+ tab_contents->profile(), url);
if (!function)
return NULL;
return (*function)(tab_contents, url);
@@ -222,7 +248,10 @@ RefCountedMemory* DOMUIFactory::GetFaviconResourceBytes(Profile* profile,
if (page_url.host() == chrome::kChromeUIHistory2Host)
return HistoryUI2::GetFaviconResourceBytes();
- if (page_url.host() == chrome::kChromeUIOptionsHost)
+ if (about_labs::IsEnabled() && page_url.host() == chrome::kChromeUILabsHost)
+ return LabsUI::GetFaviconResourceBytes();
+
+ if (page_url.host() == chrome::kChromeUISettingsHost)
return OptionsUI::GetFaviconResourceBytes();
if (page_url.host() == chrome::kChromeUIPluginsHost)
diff --git a/chrome/browser/dom_ui/dom_ui_factory.h b/chrome/browser/dom_ui/dom_ui_factory.h
index 781b7f3..3a7bfc6 100644
--- a/chrome/browser/dom_ui/dom_ui_factory.h
+++ b/chrome/browser/dom_ui/dom_ui_factory.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_DOM_UI_FACTORY_H_
#define CHROME_BROWSER_DOM_UI_DOM_UI_FACTORY_H_
-
-#include <vector>
+#pragma once
#include "chrome/browser/favicon_service.h"
@@ -28,7 +27,7 @@ class DOMUIFactory {
// Returns a type identifier indicating what DOMUI we would use for the
// given URL. This is useful for comparing the potential DOMUIs for two URLs.
// Returns kNoDOMUI if the given URL will not use the DOM UI system.
- static DOMUITypeID GetDOMUIType(const GURL& url);
+ static DOMUITypeID GetDOMUIType(Profile* profile, const GURL& url);
// Returns true if the given URL's scheme would trigger the DOM UI system.
// This is a less precise test than UseDONUIForURL, which tells you whether
@@ -37,7 +36,7 @@ class DOMUIFactory {
static bool HasDOMUIScheme(const GURL& url);
// Returns true if the given URL will use the DOM UI system.
- static bool UseDOMUIForURL(const GURL& url);
+ static bool UseDOMUIForURL(Profile* profile, const GURL& url);
// Allocates a new DOMUI object for the given URL, and returns it. If the URL
// is not a DOM UI URL, then it will return NULL. When non-NULL, ownership of
diff --git a/chrome/browser/dom_ui/dom_ui_favicon_source.cc b/chrome/browser/dom_ui/dom_ui_favicon_source.cc
index f80aa70..55818a3 100644
--- a/chrome/browser/dom_ui/dom_ui_favicon_source.cc
+++ b/chrome/browser/dom_ui/dom_ui_favicon_source.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.
@@ -6,6 +6,7 @@
#include "app/resource_bundle.h"
#include "base/callback.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/common/url_constants.h"
#include "grit/app_resources.h"
@@ -15,6 +16,9 @@ DOMUIFavIconSource::DOMUIFavIconSource(Profile* profile)
profile_(profile) {
}
+DOMUIFavIconSource::~DOMUIFavIconSource() {
+}
+
void DOMUIFavIconSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
@@ -22,6 +26,11 @@ void DOMUIFavIconSource::StartDataRequest(const std::string& path,
profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
if (favicon_service) {
FaviconService::Handle handle;
+ if (path.empty()) {
+ SendDefaultResponse(request_id);
+ return;
+ }
+
if (path.size() > 8 && path.substr(0, 8) == "iconurl/") {
handle = favicon_service->GetFavicon(
GURL(path.substr(8)),
@@ -40,6 +49,12 @@ void DOMUIFavIconSource::StartDataRequest(const std::string& path,
}
}
+std::string DOMUIFavIconSource::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";
+}
+
void DOMUIFavIconSource::OnFavIconDataAvailable(
FaviconService::Handle request_handle,
bool know_favicon,
@@ -55,12 +70,16 @@ void DOMUIFavIconSource::OnFavIconDataAvailable(
// Forward the data along to the networking system.
SendResponse(request_id, data);
} else {
- if (!default_favicon_.get()) {
- default_favicon_ =
- ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
- IDR_DEFAULT_FAVICON);
- }
+ SendDefaultResponse(request_id);
+ }
+}
- SendResponse(request_id, default_favicon_);
+void DOMUIFavIconSource::SendDefaultResponse(int request_id) {
+ if (!default_favicon_.get()) {
+ default_favicon_ =
+ ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
+ IDR_DEFAULT_FAVICON);
}
+
+ SendResponse(request_id, default_favicon_);
}
diff --git a/chrome/browser/dom_ui/dom_ui_favicon_source.h b/chrome/browser/dom_ui/dom_ui_favicon_source.h
index a3ba511..84c29fc 100644
--- a/chrome/browser/dom_ui/dom_ui_favicon_source.h
+++ b/chrome/browser/dom_ui/dom_ui_favicon_source.h
@@ -1,14 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_DOM_UI_FAVICON_SOURCE_H_
#define CHROME_BROWSER_DOM_UI_DOM_UI_FAVICON_SOURCE_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/favicon_service.h"
@@ -27,11 +28,7 @@ class DOMUIFavIconSource : 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;
// Called when favicon data is available from the history backend.
void OnFavIconDataAvailable(FaviconService::Handle request_handle,
@@ -41,7 +38,10 @@ class DOMUIFavIconSource : public ChromeURLDataManager::DataSource {
GURL url);
private:
- virtual ~DOMUIFavIconSource() {}
+ // Sends the default favicon.
+ void SendDefaultResponse(int request_id);
+
+ virtual ~DOMUIFavIconSource();
Profile* profile_;
CancelableRequestConsumerT<int, 0> cancelable_consumer_;
diff --git a/chrome/browser/dom_ui/dom_ui_theme_source.cc b/chrome/browser/dom_ui/dom_ui_theme_source.cc
index f34091e..d2a91ba 100644
--- a/chrome/browser/dom_ui/dom_ui_theme_source.cc
+++ b/chrome/browser/dom_ui/dom_ui_theme_source.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,11 +7,12 @@
#include "app/resource_bundle.h"
#include "app/theme_provider.h"
#include "base/message_loop.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "base/ref_counted_memory.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/ntp_resource_cache.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/resources_util.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
@@ -35,6 +36,9 @@ DOMUIThemeSource::DOMUIThemeSource(Profile* profile)
profile->IsOffTheRecord());
}
+DOMUIThemeSource::~DOMUIThemeSource() {
+}
+
void DOMUIThemeSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
diff --git a/chrome/browser/dom_ui/dom_ui_theme_source.h b/chrome/browser/dom_ui/dom_ui_theme_source.h
index 5c74649..61f3abf 100644
--- a/chrome/browser/dom_ui/dom_ui_theme_source.h
+++ b/chrome/browser/dom_ui/dom_ui_theme_source.h
@@ -1,15 +1,17 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_DOM_UI_THEME_SOURCE_H_
#define CHROME_BROWSER_DOM_UI_DOM_UI_THEME_SOURCE_H_
+#pragma once
#include <string>
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
class Profile;
+class RefCountedBytes;
// ThumbnailSource is the gateway between network-level chrome:
// requests for thumbnails and the history backend that serves these.
@@ -28,7 +30,7 @@ class DOMUIThemeSource : public ChromeURLDataManager::DataSource {
virtual MessageLoop* MessageLoopForRequestPath(const std::string& path) const;
protected:
- virtual ~DOMUIThemeSource() {}
+ virtual ~DOMUIThemeSource();
private:
// Fetch and send the theme bitmap.
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 c093e1e..54888b1 100644
--- a/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc
+++ b/chrome/browser/dom_ui/dom_ui_theme_source_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/browser_theme_provider.h"
+#include "base/ref_counted_memory.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/dom_ui_theme_source.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/testing_profile.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/dom_ui/dom_ui_thumbnail_source.cc b/chrome/browser/dom_ui/dom_ui_thumbnail_source.cc
index a89c92f..f17586f 100644
--- a/chrome/browser/dom_ui/dom_ui_thumbnail_source.cc
+++ b/chrome/browser/dom_ui/dom_ui_thumbnail_source.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.
@@ -6,10 +6,8 @@
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "base/command_line.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/history/top_sites.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "gfx/codec/jpeg_codec.h"
@@ -22,11 +20,14 @@ DOMUIThumbnailSource::DOMUIThumbnailSource(Profile* profile)
profile_(profile) {
}
+DOMUIThumbnailSource::~DOMUIThumbnailSource() {
+}
+
void DOMUIThumbnailSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTopSites)) {
- scoped_refptr<history::TopSites> top_sites = profile_->GetTopSites();
+ if (history::TopSites::IsEnabled()) {
+ history::TopSites* top_sites = profile_->GetTopSites();
RefCountedBytes* data = NULL;
if (top_sites->GetPageThumbnail(GURL(path), &data)) {
// We have the thumbnail.
@@ -35,7 +36,7 @@ void DOMUIThumbnailSource::StartDataRequest(const std::string& path,
SendDefaultThumbnail(request_id);
}
return;
- } // end --top-sites switch
+ }
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (hs) {
@@ -51,6 +52,12 @@ void DOMUIThumbnailSource::StartDataRequest(const std::string& path,
}
}
+std::string DOMUIThumbnailSource::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";
+}
+
void DOMUIThumbnailSource::SendDefaultThumbnail(int request_id) {
// Use placeholder thumbnail.
if (!default_thumbnail_.get()) {
diff --git a/chrome/browser/dom_ui/dom_ui_thumbnail_source.h b/chrome/browser/dom_ui/dom_ui_thumbnail_source.h
index cadf542..3c0578b 100644
--- a/chrome/browser/dom_ui/dom_ui_thumbnail_source.h
+++ b/chrome/browser/dom_ui/dom_ui_thumbnail_source.h
@@ -1,16 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_DOM_UI_THUMBNAIL_SOURCE_H_
#define CHROME_BROWSER_DOM_UI_DOM_UI_THUMBNAIL_SOURCE_H_
+#pragma once
#include <string>
-#include <utility>
-#include <vector>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/history/history.h"
#include "chrome/common/notification_registrar.h"
@@ -30,18 +29,14 @@ class DOMUIThumbnailSource : 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;
// Called when thumbnail data is available from the history backend.
void OnThumbnailDataAvailable(HistoryService::Handle request_handle,
scoped_refptr<RefCountedBytes> data);
private:
- ~DOMUIThumbnailSource() {}
+ virtual ~DOMUIThumbnailSource();
// Send the default thumbnail when we are missing a real one.
void SendDefaultThumbnail(int request_id);
@@ -53,10 +48,6 @@ class DOMUIThumbnailSource : public ChromeURLDataManager::DataSource {
// database doesn't have a thumbnail for a webpage.
scoped_refptr<RefCountedMemory> default_thumbnail_;
- // Store requests when the ThumbnailStore isn't ready. When a notification is
- // received that it is ready, then serve these requests.
- std::vector<std::pair<std::string, int> > pending_requests_;
-
// To register to be notified when the ThumbnailStore is ready.
NotificationRegistrar registrar_;
diff --git a/chrome/browser/dom_ui/dom_ui_unittest.cc b/chrome/browser/dom_ui/dom_ui_unittest.cc
index 8c00663..6bee126 100644
--- a/chrome/browser/dom_ui/dom_ui_unittest.cc
+++ b/chrome/browser/dom_ui/dom_ui_unittest.cc
@@ -2,9 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/new_tab_ui.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/navigation_controller.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
class DOMUITest : public RenderViewHostTestHarness {
@@ -84,7 +89,6 @@ class DOMUITest : public RenderViewHostTestHarness {
// TabContents when we first navigate to a DOM UI page, then to a standard
// non-DOM-UI page.
TEST_F(DOMUITest, DOMUIToStandard) {
- profile_->CreateBookmarkModel(true);
DoNavigationTest(contents(), 1);
// Test the case where we're not doing the initial navigation. This is
diff --git a/chrome/browser/dom_ui/dom_ui_util.cc b/chrome/browser/dom_ui/dom_ui_util.cc
index e247655..a5d36e4 100644
--- a/chrome/browser/dom_ui/dom_ui_util.cc
+++ b/chrome/browser/dom_ui/dom_ui_util.cc
@@ -4,24 +4,23 @@
#include "chrome/browser/dom_ui/dom_ui_util.h"
+#include <vector>
+
+#include "app/resource_bundle.h"
+#include "base/base64.h"
#include "base/logging.h"
#include "base/values.h"
+#include "gfx/codec/png_codec.h"
namespace dom_ui_util {
-std::string GetJsonResponseFromFirstArgumentInList(const Value* content) {
- return GetJsonResponseFromArgumentList(content, 0);
+std::string GetJsonResponseFromFirstArgumentInList(const ListValue* args) {
+ return GetJsonResponseFromArgumentList(args, 0);
}
-std::string GetJsonResponseFromArgumentList(const Value* content,
+std::string GetJsonResponseFromArgumentList(const ListValue* args,
size_t list_index) {
std::string result;
-
- if (!content || !content->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
- return result;
- }
- const ListValue* args = static_cast<const ListValue*>(content);
if (args->GetSize() <= list_index) {
NOTREACHED();
return result;
@@ -30,8 +29,36 @@ std::string GetJsonResponseFromArgumentList(const Value* content,
Value* value = NULL;
if (args->Get(list_index, &value))
value->GetAsString(&result);
+ else
+ NOTREACHED();
return result;
}
+std::string GetImageDataUrl(const SkBitmap& bitmap) {
+ std::vector<unsigned char> output;
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output);
+ std::string str_url;
+ std::copy(output.begin(), output.end(),
+ std::back_inserter(str_url));
+ base::Base64Encode(str_url, &str_url);
+ str_url.insert(0, "data:image/png;base64,");
+ return str_url;
+}
+
+std::string GetImageDataUrlFromResource(int res) {
+ // Load resource icon and covert to base64 encoded data url
+ RefCountedStaticMemory* icon_data =
+ ResourceBundle::GetSharedInstance().LoadDataResourceBytes(res);
+ if (!icon_data)
+ return std::string();
+ scoped_refptr<RefCountedMemory> raw_icon(icon_data);
+ std::string str_url;
+ std::copy(raw_icon->front(), raw_icon->front() + raw_icon->size(),
+ std::back_inserter(str_url));
+ base::Base64Encode(str_url, &str_url);
+ str_url.insert(0, "data:image/png;base64,");
+ return str_url;
+}
+
} // end of namespace dom_ui_util
diff --git a/chrome/browser/dom_ui/dom_ui_util.h b/chrome/browser/dom_ui/dom_ui_util.h
index 48c68a1..335ef05 100644
--- a/chrome/browser/dom_ui/dom_ui_util.h
+++ b/chrome/browser/dom_ui/dom_ui_util.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_DOM_UI_DOM_UI_UTIL_H_
#define CHROME_BROWSER_DOM_UI_DOM_UI_UTIL_H_
+#pragma once
#include <string>
-class Value;
+class ListValue;
+class SkBitmap;
namespace dom_ui_util {
@@ -17,7 +19,7 @@ namespace dom_ui_util {
// one entry in it, and that first entry must be a string, which is
// returned. The parameter is a Value for convenience. Returns an
// empty string on error or if the parameter is not a ListValue.
-std::string GetJsonResponseFromFirstArgumentInList(const Value* content);
+std::string GetJsonResponseFromFirstArgumentInList(const ListValue* args);
// Convenience routine to get one of the response strings from an
// argument list. content must be a ListValue, with at least
@@ -26,9 +28,22 @@ std::string GetJsonResponseFromFirstArgumentInList(const Value* content);
// which is returned. The parameter is a Value for convenience.
// Returns an empty string on error or if the parameter is not a
// ListValue.
-std::string GetJsonResponseFromArgumentList(const Value* content,
+std::string GetJsonResponseFromArgumentList(const ListValue* args,
size_t list_index);
+
+// Convenience routine to convert SkBitmap object to data url
+// so that it can be used in DOMUI.
+std::string GetImageDataUrl(const SkBitmap& bitmap);
+
+// Convenience routine to get data url that corresponds to given
+// resource_id as an image. This function does not check if the
+// resource for the |resource_id| is an image, therefore it is the
+// caller's responsibility to make sure the resource is indeed an
+// image. Returns empty string if a resource does not exist for given
+// |resource_id|.
+std::string GetImageDataUrlFromResource(int resource_id);
+
} // end of namespace
#endif // CHROME_BROWSER_DOM_UI_DOM_UI_UTIL_H_
diff --git a/chrome/browser/dom_ui/downloads_dom_handler.cc b/chrome/browser/dom_ui/downloads_dom_handler.cc
index 126a8be..80386eb 100644
--- a/chrome/browser/dom_ui/downloads_dom_handler.cc
+++ b/chrome/browser/dom_ui/downloads_dom_handler.cc
@@ -4,17 +4,18 @@
#include "chrome/browser/dom_ui/downloads_dom_handler.h"
-#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/fileicon_source.h"
+#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -45,7 +46,8 @@ class DownloadItemSorter : public std::binary_function<DownloadItem*,
DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
: search_text_(),
- download_manager_(dlm) {
+ download_manager_(dlm),
+ callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
// Create our fileicon data source.
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
@@ -111,19 +113,11 @@ void DownloadsDOMHandler::OnDownloadUpdated(DownloadItem* download) {
}
// A download has started or been deleted. Query our DownloadManager for the
-// current set of downloads, which will call us back in SetDownloads once it
-// has retrieved them.
+// current set of downloads.
void DownloadsDOMHandler::ModelChanged() {
ClearDownloadItems();
- download_manager_->GetDownloads(this, search_text_);
-}
-
-void DownloadsDOMHandler::SetDownloads(
- std::vector<DownloadItem*>& downloads) {
- ClearDownloadItems();
-
- // Swap new downloads in.
- download_items_.swap(downloads);
+ download_manager_->SearchDownloads(WideToUTF16(search_text_),
+ &download_items_);
sort(download_items_.begin(), download_items_.end(), DownloadItemSorter());
// Scan for any in progress downloads and add ourself to them as an observer.
@@ -145,25 +139,24 @@ void DownloadsDOMHandler::SetDownloads(
SendCurrentDownloads();
}
-void DownloadsDOMHandler::HandleGetDownloads(const Value* value) {
- std::wstring new_search = ExtractStringValue(value);
+void DownloadsDOMHandler::HandleGetDownloads(const ListValue* args) {
+ std::wstring new_search = ExtractStringValue(args);
if (search_text_.compare(new_search) != 0) {
search_text_ = new_search;
- ClearDownloadItems();
- download_manager_->GetDownloads(this, search_text_);
+ ModelChanged();
} else {
SendCurrentDownloads();
}
}
-void DownloadsDOMHandler::HandleOpenFile(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file)
- download_manager_->OpenDownload(file, NULL);
+ file->OpenDownload();
}
-void DownloadsDOMHandler::HandleDrag(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandleDrag(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file) {
IconManager* im = g_browser_process->icon_manager();
SkBitmap* icon = im->LookupIcon(file->full_path(), IconLoader::NORMAL);
@@ -172,43 +165,43 @@ void DownloadsDOMHandler::HandleDrag(const Value* value) {
}
}
-void DownloadsDOMHandler::HandleSaveDangerous(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file)
download_manager_->DangerousDownloadValidated(file);
}
-void DownloadsDOMHandler::HandleDiscardDangerous(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandleDiscardDangerous(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file)
file->Remove(true);
}
-void DownloadsDOMHandler::HandleShow(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandleShow(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file)
- download_manager_->ShowDownloadInShell(file);
+ file->ShowDownloadInShell();
}
-void DownloadsDOMHandler::HandlePause(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandlePause(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file)
file->TogglePause();
}
-void DownloadsDOMHandler::HandleRemove(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandleRemove(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file)
file->Remove(false);
}
-void DownloadsDOMHandler::HandleCancel(const Value* value) {
- DownloadItem* file = GetDownloadByValue(value);
+void DownloadsDOMHandler::HandleCancel(const ListValue* args) {
+ DownloadItem* file = GetDownloadByValue(args);
if (file)
file->Cancel(true);
}
-void DownloadsDOMHandler::HandleClearAll(const Value* value) {
+void DownloadsDOMHandler::HandleClearAll(const ListValue* args) {
download_manager_->RemoveAllDownloads();
}
@@ -247,9 +240,9 @@ DownloadItem* DownloadsDOMHandler::GetDownloadById(int id) {
return NULL;
}
-DownloadItem* DownloadsDOMHandler::GetDownloadByValue(const Value* value) {
+DownloadItem* DownloadsDOMHandler::GetDownloadByValue(const ListValue* args) {
int id;
- if (ExtractIntegerValue(value, &id)) {
+ if (ExtractIntegerValue(args, &id)) {
return GetDownloadById(id);
}
return NULL;
diff --git a/chrome/browser/dom_ui/downloads_dom_handler.h b/chrome/browser/dom_ui/downloads_dom_handler.h
index 99af1f5..5013db5 100644
--- a/chrome/browser/dom_ui/downloads_dom_handler.h
+++ b/chrome/browser/dom_ui/downloads_dom_handler.h
@@ -4,14 +4,16 @@
#ifndef CHROME_BROWSER_DOM_UI_DOWNLOADS_DOM_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_DOWNLOADS_DOM_HANDLER_H_
+#pragma once
#include <vector>
+#include "base/scoped_callback_factory.h"
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_manager.h"
-class Value;
+class ListValue;
// The handler for Javascript messages related to the "downloads" view,
// also observes changes to the download manager.
@@ -34,40 +36,39 @@ class DownloadsDOMHandler : public DOMMessageHandler,
// DownloadManager::Observer interface
virtual void ModelChanged();
- virtual void SetDownloads(std::vector<DownloadItem*>& downloads);
// Callback for the "getDownloads" message.
- void HandleGetDownloads(const Value* value);
+ void HandleGetDownloads(const ListValue* args);
// Callback for the "openFile" message - opens the file in the shell.
- void HandleOpenFile(const Value* value);
+ void HandleOpenFile(const ListValue* args);
// Callback for the "drag" message - initiates a file object drag.
- void HandleDrag(const Value* value);
+ void HandleDrag(const ListValue* args);
// Callback for the "saveDangerous" message - specifies that the user
// wishes to save a dangerous file.
- void HandleSaveDangerous(const Value* value);
+ void HandleSaveDangerous(const ListValue* args);
// Callback for the "discardDangerous" message - specifies that the user
// wishes to discard (remove) a dangerous file.
- void HandleDiscardDangerous(const Value* value);
+ void HandleDiscardDangerous(const ListValue* args);
// Callback for the "show" message - shows the file in explorer.
- void HandleShow(const Value* value);
+ void HandleShow(const ListValue* args);
// Callback for the "pause" message - pauses the file download.
- void HandlePause(const Value* value);
+ void HandlePause(const ListValue* args);
// Callback for the "remove" message - removes the file download from shelf
// and list.
- void HandleRemove(const Value* value);
+ void HandleRemove(const ListValue* args);
// Callback for the "cancel" message - cancels the download.
- void HandleCancel(const Value* value);
+ void HandleCancel(const ListValue* args);
// Callback for the "clearAll" message - clears all the downloads.
- void HandleClearAll(const Value* value);
+ void HandleClearAll(const ListValue* args);
private:
// Send the current list of downloads to the page.
@@ -80,7 +81,7 @@ class DownloadsDOMHandler : public DOMMessageHandler,
DownloadItem* GetDownloadById(int id);
// Return the download that is referred to in a given value.
- DownloadItem* GetDownloadByValue(const Value* value);
+ DownloadItem* GetDownloadByValue(const ListValue* args);
// Current search text.
std::wstring search_text_;
@@ -94,6 +95,8 @@ class DownloadsDOMHandler : public DOMMessageHandler,
typedef std::vector<DownloadItem*> OrderedDownloads;
OrderedDownloads download_items_;
+ base::ScopedCallbackFactory<DownloadsDOMHandler> callback_factory_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadsDOMHandler);
};
diff --git a/chrome/browser/dom_ui/downloads_ui.cc b/chrome/browser/dom_ui/downloads_ui.cc
index d0f3cad..2fe1067 100644
--- a/chrome/browser/dom_ui/downloads_ui.cc
+++ b/chrome/browser/dom_ui/downloads_ui.cc
@@ -57,46 +57,46 @@ void DownloadsUIHTMLSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
DictionaryValue localized_strings;
- localized_strings.SetString(L"title",
- l10n_util::GetString(IDS_DOWNLOAD_TITLE));
- localized_strings.SetString(L"searchbutton",
- l10n_util::GetString(IDS_DOWNLOAD_SEARCH_BUTTON));
- localized_strings.SetString(L"no_results",
- l10n_util::GetString(IDS_DOWNLOAD_SEARCH_BUTTON));
- localized_strings.SetString(L"searchresultsfor",
- l10n_util::GetString(IDS_DOWNLOAD_SEARCHRESULTSFOR));
- localized_strings.SetString(L"downloads",
- l10n_util::GetString(IDS_DOWNLOAD_TITLE));
- localized_strings.SetString(L"clear_all",
- l10n_util::GetString(IDS_DOWNLOAD_LINK_CLEAR_ALL));
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_TITLE));
+ localized_strings.SetString("searchbutton",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_SEARCH_BUTTON));
+ localized_strings.SetString("no_results",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_SEARCH_BUTTON));
+ localized_strings.SetString("searchresultsfor",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_SEARCHRESULTSFOR));
+ localized_strings.SetString("downloads",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_TITLE));
+ localized_strings.SetString("clear_all",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_CLEAR_ALL));
// Status.
- localized_strings.SetString(L"status_cancelled",
- l10n_util::GetString(IDS_DOWNLOAD_TAB_CANCELED));
- localized_strings.SetString(L"status_paused",
- l10n_util::GetString(IDS_DOWNLOAD_PROGRESS_PAUSED));
+ localized_strings.SetString("status_cancelled",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_TAB_CANCELED));
+ localized_strings.SetString("status_paused",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED));
// Dangerous file.
- localized_strings.SetString(L"danger_desc",
- l10n_util::GetString(IDS_PROMPT_DANGEROUS_DOWNLOAD));
- localized_strings.SetString(L"danger_save",
- l10n_util::GetString(IDS_SAVE_DOWNLOAD));
- localized_strings.SetString(L"danger_discard",
- l10n_util::GetString(IDS_DISCARD_DOWNLOAD));
+ localized_strings.SetString("danger_desc",
+ l10n_util::GetStringUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD));
+ localized_strings.SetString("danger_save",
+ l10n_util::GetStringUTF16(IDS_SAVE_DOWNLOAD));
+ localized_strings.SetString("danger_discard",
+ l10n_util::GetStringUTF16(IDS_DISCARD_DOWNLOAD));
// Controls.
- localized_strings.SetString(L"control_pause",
- l10n_util::GetString(IDS_DOWNLOAD_LINK_PAUSE));
+ localized_strings.SetString("control_pause",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_PAUSE));
if (browser_defaults::kDownloadPageHasShowInFolder) {
- localized_strings.SetString(L"control_showinfolder",
- l10n_util::GetString(IDS_DOWNLOAD_LINK_SHOW));
+ localized_strings.SetString("control_showinfolder",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_SHOW));
}
- localized_strings.SetString(L"control_cancel",
- l10n_util::GetString(IDS_DOWNLOAD_LINK_CANCEL));
- localized_strings.SetString(L"control_resume",
- l10n_util::GetString(IDS_DOWNLOAD_LINK_RESUME));
- localized_strings.SetString(L"control_removefromlist",
- l10n_util::GetString(IDS_DOWNLOAD_LINK_REMOVE));
+ localized_strings.SetString("control_cancel",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_CANCEL));
+ localized_strings.SetString("control_resume",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_RESUME));
+ localized_strings.SetString("control_removefromlist",
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_REMOVE));
SetFontAndTextDirection(&localized_strings);
diff --git a/chrome/browser/dom_ui/downloads_ui.h b/chrome/browser/dom_ui/downloads_ui.h
index d153894..c6f5727 100644
--- a/chrome/browser/dom_ui/downloads_ui.h
+++ b/chrome/browser/dom_ui/downloads_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_DOWNLOADS_UI_H_
#define CHROME_BROWSER_DOM_UI_DOWNLOADS_UI_H_
+#pragma once
#include "chrome/browser/dom_ui/dom_ui.h"
diff --git a/chrome/browser/dom_ui/file_browse_browsertest.cc b/chrome/browser/dom_ui/file_browse_browsertest.cc
index 4c4af11..c8d7a1f 100644
--- a/chrome/browser/dom_ui/file_browse_browsertest.cc
+++ b/chrome/browser/dom_ui/file_browse_browsertest.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 "base/file_path.h"
-#include "base/file_util.h"
#include "base/task.h"
-#include "base/values.h"
#include "base/path_service.h"
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
@@ -16,6 +13,7 @@
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+#include "net/test/test_server.h"
namespace {
@@ -105,9 +103,9 @@ class FileBrowseUiObserver : public NotificationObserver {
};
IN_PROC_BROWSER_TEST_F(FileBrowseBrowserTest, InputFileTriggerFileBrowse) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(test_server()->Start());
ui_test_utils::NavigateToURL(browser(),
- server->TestServerPage("files/input_file.html"));
+ test_server()->GetURL("files/input_file.html"));
DOMElementProxyRef doc = ui_test_utils::GetActiveDOMDocument(browser());
diff --git a/chrome/browser/dom_ui/filebrowse_ui.cc b/chrome/browser/dom_ui/filebrowse_ui.cc
index 7886752..4d93086 100644
--- a/chrome/browser/dom_ui/filebrowse_ui.cc
+++ b/chrome/browser/dom_ui/filebrowse_ui.cc
@@ -15,6 +15,7 @@
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/weak_ptr.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -23,27 +24,27 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
+#include "chrome/browser/dom_ui/mediaplayer_ui.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_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/dom_ui/mediaplayer_ui.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
-#include "net/base/escape.h"
-
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
+#include "net/base/escape.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/cros/cros_library.h"
@@ -54,16 +55,16 @@
// Maximum number of search results to return in a given search. We should
// eventually remove this.
static const int kMaxSearchResults = 100;
-static const std::wstring kPropertyPath = L"path";
-static const std::wstring kPropertyTitle = L"title";
-static const std::wstring kPropertyDirectory = L"isDirectory";
-static const std::string kPicasawebUserPrefix =
+static const char kPropertyPath[] = "path";
+static const char kPropertyTitle[] = "title";
+static const char kPropertyDirectory[] = "isDirectory";
+static const char kPicasawebUserPrefix[] =
"http://picasaweb.google.com/data/feed/api/user/";
-static const std::string kPicasawebDefault = "/albumid/default";
-static const std::string kPicasawebDropBox = "/home";
-static const std::string kPicasawebBaseUrl = "http://picasaweb.google.com/";
-static const std::string kMediaPath = "/media";
-static const char* kFilebrowseURLHash = "chrome://filebrowse#";
+static const char kPicasawebDefault[] = "/albumid/default";
+static const char kPicasawebDropBox[] = "/home";
+static const char kPicasawebBaseUrl[] = "http://picasaweb.google.com/";
+static const char kMediaPath[] = "/media";
+static const char kFilebrowseURLHash[] = "chrome://filebrowse#";
static const int kPopupLeft = 0;
static const int kPopupTop = 0;
@@ -106,7 +107,8 @@ class FilebrowseHandler : public net::DirectoryLister::DirectoryListerDelegate,
void Init();
// DirectoryLister::DirectoryListerDelegate methods:
- virtual void OnListFile(const file_util::FileEnumerator::FindInfo& data);
+ virtual void OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data);
virtual void OnListDone(int error);
// DOMMessageHandler implementation.
@@ -126,10 +128,9 @@ class FilebrowseHandler : public net::DirectoryLister::DirectoryListerDelegate,
// DownloadManager::Observer interface
virtual void ModelChanged();
- virtual void SetDownloads(std::vector<DownloadItem*>& downloads);
// Callback for the "getRoots" message.
- void HandleGetRoots(const Value* value);
+ void HandleGetRoots(const ListValue* args);
void GetChildrenForPath(FilePath& path, bool is_refresh);
@@ -141,37 +142,40 @@ class FilebrowseHandler : public net::DirectoryLister::DirectoryListerDelegate,
const std::string& data);
// Callback for the "getChildren" message.
- void HandleGetChildren(const Value* value);
+ void HandleGetChildren(const ListValue* args);
// Callback for the "refreshDirectory" message.
- void HandleRefreshDirectory(const Value* value);
- void HandleIsAdvancedEnabled(const Value* value);
+ void HandleRefreshDirectory(const ListValue* args);
+ void HandleIsAdvancedEnabled(const ListValue* args);
// Callback for the "getMetadata" message.
- void HandleGetMetadata(const Value* value);
+ void HandleGetMetadata(const ListValue* args);
// Callback for the "openNewWindow" message.
- void OpenNewFullWindow(const Value* value);
- void OpenNewPopupWindow(const Value* value);
+ void OpenNewFullWindow(const ListValue* args);
+ void OpenNewPopupWindow(const ListValue* args);
// Callback for the "uploadToPicasaweb" message.
- void UploadToPicasaweb(const Value* value);
+ void UploadToPicasaweb(const ListValue* args);
// Callback for the "getDownloads" message.
- void HandleGetDownloads(const Value* value);
+ void HandleGetDownloads(const ListValue* args);
- void HandleCreateNewFolder(const Value* value);
+ void HandleCreateNewFolder(const ListValue* args);
- void PlayMediaFile(const Value* value);
- void EnqueueMediaFile(const Value* value);
+ void PlayMediaFile(const ListValue* args);
+ void EnqueueMediaFile(const ListValue* args);
- void HandleDeleteFile(const Value* value);
+ void HandleDeleteFile(const ListValue* args);
+ void HandleCopyFile(const ListValue* value);
+ void CopyFile(const FilePath& src, const FilePath& dest);
void DeleteFile(const FilePath& path);
void FireDeleteComplete(const FilePath& path);
+ void FireCopyComplete(const FilePath& src, const FilePath& dest);
- void HandlePauseToggleDownload(const Value* value);
+ void HandlePauseToggleDownload(const ListValue* args);
- void HandleCancelDownload(const Value* value);
- void HandleAllowDownload(const Value* value);
+ void HandleCancelDownload(const ListValue* args);
+ void HandleAllowDownload(const ListValue* args);
void ReadInFile();
void FireUploadComplete();
@@ -179,7 +183,7 @@ class FilebrowseHandler : public net::DirectoryLister::DirectoryListerDelegate,
void SendPicasawebRequest();
private:
- void OpenNewWindow(const Value* value, bool popup);
+ void OpenNewWindow(const ListValue* args, bool popup);
// Clear all download items and their observers.
void ClearDownloadItems();
@@ -211,10 +215,15 @@ class FilebrowseHandler : public net::DirectoryLister::DirectoryListerDelegate,
class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
public:
- explicit TaskProxy(const base::WeakPtr<FilebrowseHandler>& handler,
- FilePath& path)
+ TaskProxy(const base::WeakPtr<FilebrowseHandler>& handler,
+ const FilePath& path, const FilePath& dest)
: handler_(handler),
- path_(path) {}
+ src_(path),
+ dest_(dest) {}
+ TaskProxy(const base::WeakPtr<FilebrowseHandler>& handler,
+ const FilePath& path)
+ : handler_(handler),
+ src_(path) {}
void ReadInFileProxy() {
if (handler_) {
handler_->ReadInFile();
@@ -236,18 +245,30 @@ class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
void DeleteFileProxy() {
if (handler_) {
- handler_->DeleteFile(path_);
+ handler_->DeleteFile(src_);
+ }
+ }
+
+ void CopyFileProxy() {
+ if (handler_) {
+ handler_->CopyFile(src_, dest_);
}
}
void FireDeleteCompleteProxy() {
if (handler_) {
- handler_->FireDeleteComplete(path_);
+ handler_->FireDeleteComplete(src_);
+ }
+ }
+ void FireCopyCompleteProxy() {
+ if (handler_) {
+ handler_->FireCopyComplete(src_, dest_);
}
}
private:
base::WeakPtr<FilebrowseHandler> handler_;
- FilePath path_;
+ FilePath src_;
+ FilePath dest_;
friend class base::RefCountedThreadSafe<TaskProxy>;
DISALLOW_COPY_AND_ASSIGN(TaskProxy);
};
@@ -269,49 +290,50 @@ void FileBrowseUIHTMLSource::StartDataRequest(const std::string& path,
DictionaryValue localized_strings;
// TODO(dhg): Add stirings to localized strings, also add more strings
// that are currently hardcoded.
- localized_strings.SetString(L"title",
- l10n_util::GetString(IDS_FILEBROWSER_TITLE));
- localized_strings.SetString(L"pause",
- l10n_util::GetString(IDS_FILEBROWSER_PAUSE));
- localized_strings.SetString(L"resume",
- l10n_util::GetString(IDS_FILEBROWSER_RESUME));
- localized_strings.SetString(L"scanning",
- l10n_util::GetString(IDS_FILEBROWSER_SCANNING));
- localized_strings.SetString(L"confirmdelete",
- l10n_util::GetString(IDS_FILEBROWSER_CONFIRM_DELETE));
- localized_strings.SetString(L"confirmyes",
- l10n_util::GetString(IDS_FILEBROWSER_CONFIRM_YES));
- localized_strings.SetString(L"confirmcancel",
- l10n_util::GetString(IDS_FILEBROWSER_CONFIRM_CANCEL));
- localized_strings.SetString(L"allowdownload",
- l10n_util::GetString(IDS_FILEBROWSER_CONFIRM_DOWNLOAD));
- localized_strings.SetString(L"filenameprompt",
- l10n_util::GetString(IDS_FILEBROWSER_PROMPT_FILENAME));
- localized_strings.SetString(L"save",
- l10n_util::GetString(IDS_FILEBROWSER_SAVE));
- localized_strings.SetString(L"newfolder",
- l10n_util::GetString(IDS_FILEBROWSER_NEW_FOLDER));
- localized_strings.SetString(L"open",
- l10n_util::GetString(IDS_FILEBROWSER_OPEN));
- localized_strings.SetString(L"picasaweb",
- l10n_util::GetString(IDS_FILEBROWSER_UPLOAD_PICASAWEB));
- localized_strings.SetString(L"flickr",
- l10n_util::GetString(IDS_FILEBROWSER_UPLOAD_FLICKR));
- localized_strings.SetString(L"email",
- l10n_util::GetString(IDS_FILEBROWSER_UPLOAD_EMAIL));
- localized_strings.SetString(L"delete",
- l10n_util::GetString(IDS_FILEBROWSER_DELETE));
- localized_strings.SetString(L"enqueue",
- l10n_util::GetString(IDS_FILEBROWSER_ENQUEUE));
- localized_strings.SetString(L"mediapath", kMediaPath);
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_TITLE));
+ localized_strings.SetString("pause",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_PAUSE));
+ localized_strings.SetString("resume",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_RESUME));
+ localized_strings.SetString("scanning",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_SCANNING));
+ localized_strings.SetString("confirmdelete",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_DELETE));
+ localized_strings.SetString("confirmyes",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_YES));
+ localized_strings.SetString("confirmcancel",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_CANCEL));
+ localized_strings.SetString("allowdownload",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_CONFIRM_DOWNLOAD));
+ localized_strings.SetString("filenameprompt",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_PROMPT_FILENAME));
+ localized_strings.SetString("save",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_SAVE));
+ localized_strings.SetString("newfolder",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_NEW_FOLDER));
+ localized_strings.SetString("open",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_OPEN));
+ localized_strings.SetString("picasaweb",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_PICASAWEB));
+ localized_strings.SetString("flickr",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_FLICKR));
+ localized_strings.SetString("email",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_UPLOAD_EMAIL));
+ localized_strings.SetString("delete",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_DELETE));
+ localized_strings.SetString("enqueue",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_ENQUEUE));
+ localized_strings.SetString("mediapath", kMediaPath);
FilePath default_download_path;
if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
&default_download_path)) {
NOTREACHED();
}
- localized_strings.SetString(L"downloadpath", default_download_path.value());
- localized_strings.SetString(L"error_unknown_file_type",
- l10n_util::GetString(IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE));
+ // TODO(viettrungluu): this is wrong -- FilePath's need not be Unicode.
+ localized_strings.SetString("downloadpath", default_download_path.value());
+ localized_strings.SetString("error_unknown_file_type",
+ l10n_util::GetStringUTF16(IDS_FILEBROWSER_ERROR_UNKNOWN_FILE_TYPE));
SetFontAndTextDirection(&localized_strings);
static const base::StringPiece filebrowse_html(
@@ -385,7 +407,7 @@ DOMMessageHandler* FilebrowseHandler::Attach(DOMUI* dom_ui) {
}
void FilebrowseHandler::Init() {
- download_manager_ = profile_->GetOriginalProfile()->GetDownloadManager();
+ download_manager_ = profile_->GetDownloadManager();
download_manager_->AddObserver(this);
TaskProxy* task = new TaskProxy(AsWeakPtr(), currentpath_);
task->AddRef();
@@ -427,6 +449,8 @@ void FilebrowseHandler::RegisterMessages() {
NewCallback(this, &FilebrowseHandler::HandlePauseToggleDownload));
dom_ui_->RegisterMessageCallback("deleteFile",
NewCallback(this, &FilebrowseHandler::HandleDeleteFile));
+ dom_ui_->RegisterMessageCallback("copyFile",
+ NewCallback(this, &FilebrowseHandler::HandleCopyFile));
dom_ui_->RegisterMessageCallback("cancelDownload",
NewCallback(this, &FilebrowseHandler::HandleCancelDownload));
dom_ui_->RegisterMessageCallback("allowDownload",
@@ -444,10 +468,17 @@ void FilebrowseHandler::FireDeleteComplete(const FilePath& path) {
GetChildrenForPath(dir_path, true);
};
+void FilebrowseHandler::FireCopyComplete(const FilePath& src,
+ const FilePath& dest) {
+ // Notify the UI somehow.
+ FilePath dir_path = dest.DirName();
+ GetChildrenForPath(dir_path, true);
+};
+
void FilebrowseHandler::FireUploadComplete() {
#if defined(OS_CHROMEOS)
DictionaryValue info_value;
- info_value.SetString(L"path", current_file_uploaded_);
+ info_value.SetString("path", current_file_uploaded_);
std::string username;
chromeos::UserManager* user_man = chromeos::UserManager::Get();
@@ -463,12 +494,11 @@ void FilebrowseHandler::FireUploadComplete() {
return;
}
username = username.erase(username.find_first_of('@',0));
- std::string picture_url;
- picture_url = kPicasawebBaseUrl;
+ std::string picture_url = kPicasawebBaseUrl;
picture_url += username;
picture_url += kPicasawebDropBox;
- info_value.SetString(L"url", picture_url);
- info_value.SetInteger(L"status_code", upload_response_code_);
+ info_value.SetString("url", picture_url);
+ info_value.SetInteger("status_code", upload_response_code_);
dom_ui_->CallJavascriptFunction(L"uploadComplete", info_value);
#endif
}
@@ -501,7 +531,7 @@ void FilebrowseHandler::OnURLFetchComplete(const URLFetcher* source,
fetch_.reset();
}
-void FilebrowseHandler::HandleGetRoots(const Value* value) {
+void FilebrowseHandler::HandleGetRoots(const ListValue* args) {
ListValue results_value;
DictionaryValue info_value;
// TODO(dhg): add other entries, make this more general
@@ -514,8 +544,7 @@ void FilebrowseHandler::HandleGetRoots(const Value* value) {
if (!disks[i].mount_path.empty()) {
DictionaryValue* page_value = new DictionaryValue();
page_value->SetString(kPropertyPath, disks[i].mount_path);
- FilePath currentpath;
- currentpath = FilePath(disks[i].mount_path);
+ FilePath currentpath(disks[i].mount_path);
std::string filename;
filename = currentpath.BaseName().value();
page_value->SetString(kPropertyTitle, filename);
@@ -544,230 +573,138 @@ void FilebrowseHandler::HandleGetRoots(const Value* value) {
results_value.Append(download_value);
- info_value.SetString(L"functionCall", "getRoots");
+ info_value.SetString("functionCall", "getRoots");
info_value.SetString(kPropertyPath, "");
dom_ui_->CallJavascriptFunction(L"browseFileResult",
info_value, results_value);
}
-void FilebrowseHandler::HandleCreateNewFolder(const Value* value) {
+void FilebrowseHandler::HandleCreateNewFolder(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string path;
-
- // Get path string.
- if (list_value->GetString(0, &path)) {
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
- FilePath currentpath;
- currentpath = FilePath(path);
-
- if (!file_util::CreateDirectory(currentpath)) {
- LOG(ERROR) << "unable to create directory";
- }
- } else {
- LOG(ERROR) << "Unable to get string";
- return;
- }
- }
+ if (!file_util::CreateDirectory(currentpath))
+ LOG(ERROR) << "unable to create directory";
#endif
}
-void FilebrowseHandler::PlayMediaFile(const Value* value) {
+void FilebrowseHandler::PlayMediaFile(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string path;
-
- // Get path string.
- if (list_value->GetString(0, &path)) {
- FilePath currentpath;
- currentpath = FilePath(path);
-
- MediaPlayer* mediaplayer = MediaPlayer::Get();
- std::string url = currentpath.value();
+ std::string url = WideToUTF8(ExtractStringValue(args));
+ GURL gurl(url);
- GURL gurl(url);
- Browser* browser = Browser::GetBrowserForController(
- &tab_contents_->controller(), NULL);
- mediaplayer->ForcePlayMediaURL(gurl, browser);
- } else {
- LOG(ERROR) << "Unable to get string";
- return;
- }
- }
+ Browser* browser = Browser::GetBrowserForController(
+ &tab_contents_->controller(), NULL);
+ MediaPlayer* mediaplayer = MediaPlayer::Get();
+ mediaplayer->ForcePlayMediaURL(gurl, browser);
#endif
}
-void FilebrowseHandler::EnqueueMediaFile(const Value* value) {
+void FilebrowseHandler::EnqueueMediaFile(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string path;
-
- // Get path string.
- if (list_value->GetString(0, &path)) {
- FilePath currentpath;
- currentpath = FilePath(path);
-
- MediaPlayer* mediaplayer = MediaPlayer::Get();
- std::string url = currentpath.value();
+ std::string url = WideToUTF8(ExtractStringValue(args));
+ GURL gurl(url);
- GURL gurl(url);
- Browser* browser = Browser::GetBrowserForController(
- &tab_contents_->controller(), NULL);
- mediaplayer->EnqueueMediaURL(gurl, browser);
- } else {
- LOG(ERROR) << "Unable to get string";
- return;
- }
- }
+ Browser* browser = Browser::GetBrowserForController(
+ &tab_contents_->controller(), NULL);
+ MediaPlayer* mediaplayer = MediaPlayer::Get();
+ mediaplayer->EnqueueMediaURL(gurl, browser);
#endif
}
-void FilebrowseHandler::HandleIsAdvancedEnabled(const Value* value) {
+void FilebrowseHandler::HandleIsAdvancedEnabled(const ListValue* args) {
#if defined(OS_CHROMEOS)
- Profile* profile = BrowserList::GetLastActive()->profile();
- PrefService* pref_service = profile->GetPrefs();
- bool is_enabled = pref_service->GetBoolean(
- prefs::kLabsAdvancedFilesystemEnabled);
- bool mp_enabled = pref_service->GetBoolean(prefs::kLabsMediaplayerEnabled);
+ Browser* browser = BrowserList::GetLastActive();
+ bool is_enabled = false;
+ bool mp_enabled = false;
+ if (browser) {
+ Profile* profile = browser->profile();
+ PrefService* pref_service = profile->GetPrefs();
+ is_enabled = pref_service->GetBoolean(
+ prefs::kLabsAdvancedFilesystemEnabled);
+ mp_enabled = pref_service->GetBoolean(prefs::kLabsMediaplayerEnabled);
+ }
DictionaryValue info_value;
- info_value.SetBoolean(L"enabled", is_enabled);
- info_value.SetBoolean(L"mpEnabled", mp_enabled);
+ info_value.SetBoolean("enabled", is_enabled);
+ info_value.SetBoolean("mpEnabled", mp_enabled);
dom_ui_->CallJavascriptFunction(L"enabledResult",
info_value);
+
#endif
}
-void FilebrowseHandler::HandleRefreshDirectory(const Value* value) {
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string path;
- // Get path string.
- if (list_value->GetString(0, &path)) {
- FilePath currentpath;
-#if defined(OS_WIN)
- currentpath = FilePath(ASCIIToWide(path));
-#else
- currentpath = FilePath(path);
+void FilebrowseHandler::HandleRefreshDirectory(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
+ GetChildrenForPath(currentpath, true);
#endif
- GetChildrenForPath(currentpath, true);
- } else {
- LOG(ERROR) << "Unable to get string";
- return;
- }
- }
}
-void FilebrowseHandler::HandlePauseToggleDownload(const Value* value) {
+void FilebrowseHandler::HandlePauseToggleDownload(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- int id;
- std::string str_id;
-
- if (list_value->GetString(0, &str_id)) {
- id = atoi(str_id.c_str());
- DownloadItem* item = active_download_items_[id];
- item->TogglePause();
- } else {
- LOG(ERROR) << "Unable to get id for download to pause";
- return;
- }
+ int id;
+ ExtractIntegerValue(args, &id);
+ if ((id - 1) >= (int)active_download_items_.size()) {
+ return;
}
+ DownloadItem* item = active_download_items_[id];
+ item->TogglePause();
#endif
}
-void FilebrowseHandler::HandleAllowDownload(const Value* value) {
+void FilebrowseHandler::HandleAllowDownload(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- int id;
- std::string str_id;
-
- if (list_value->GetString(0, &str_id)) {
- id = atoi(str_id.c_str());
- DownloadItem* item = active_download_items_[id];
- download_manager_->DangerousDownloadValidated(item);
- } else {
- LOG(ERROR) << "Unable to get id for download to pause";
- return;
- }
+ int id;
+ ExtractIntegerValue(args, &id);
+ if ((id - 1) >= (int)active_download_items_.size()) {
+ return;
}
+
+ DownloadItem* item = active_download_items_[id];
+ download_manager_->DangerousDownloadValidated(item);
#endif
}
-void FilebrowseHandler::HandleCancelDownload(const Value* value) {
+void FilebrowseHandler::HandleCancelDownload(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- int id;
- std::string str_id;
-
- if (list_value->GetString(0, &str_id)) {
- id = atoi(str_id.c_str());
- DownloadItem* item = active_download_items_[id];
- item->Cancel(true);
- FilePath path = item->full_path();
- FilePath dir_path = path.DirName();
- item->Remove(true);
- GetChildrenForPath(dir_path, true);
- } else {
- LOG(ERROR) << "Unable to get id for download to pause";
- return;
- }
+ int id;
+ ExtractIntegerValue(args, &id);
+ if ((id - 1) >= (int)active_download_items_.size()) {
+ return;
}
+ DownloadItem* item = active_download_items_[id];
+ FilePath path = item->full_path();
+ item->Cancel(true);
+ FilePath dir_path = path.DirName();
+ item->Remove(true);
+ GetChildrenForPath(dir_path, true);
#endif
}
-void FilebrowseHandler::OpenNewFullWindow(const Value* value) {
- OpenNewWindow(value, false);
+void FilebrowseHandler::OpenNewFullWindow(const ListValue* args) {
+ OpenNewWindow(args, false);
}
-void FilebrowseHandler::OpenNewPopupWindow(const Value* value) {
- OpenNewWindow(value, true);
+void FilebrowseHandler::OpenNewPopupWindow(const ListValue* args) {
+ OpenNewWindow(args, true);
}
-void FilebrowseHandler::OpenNewWindow(const Value* value, bool popup) {
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- Value* list_member;
- std::string path;
-
- // Get path string.
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string_value->GetAsString(&path);
- } else {
- LOG(ERROR) << "Unable to get string";
- return;
- }
- Browser* browser;
- if (popup) {
- browser = Browser::CreateForPopup(profile_);
- } else {
- browser = BrowserList::GetLastActive();
- }
- TabContents* contents = browser->AddTabWithURL(
- GURL(path), GURL(), PageTransition::LINK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
- // AddTabWithURL could have picked another Browser instance to create this
- // new tab at. So we have to reset the ptr of the browser that we want to
- // talk to.
- browser = contents->delegate()->GetBrowser();
- if (popup) {
- // TODO(dhg): Remove these from being hardcoded. Allow javascript
- // to specify.
- browser->window()->SetBounds(gfx::Rect(0, 0, 400, 300));
- }
- browser->window()->Show();
- } else {
- LOG(ERROR) << "Wasn't able to get the List if requested files.";
- return;
+void FilebrowseHandler::OpenNewWindow(const ListValue* args, bool popup) {
+ std::string url = WideToUTF8(ExtractStringValue(args));
+ Browser* browser = popup ?
+ Browser::CreateForType(Browser::TYPE_APP_PANEL, profile_) :
+ BrowserList::GetLastActive();
+ browser->AddTabWithURL(GURL(url), GURL(), PageTransition::LINK, -1,
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser);
+ if (popup) {
+ // TODO(dhg): Remove these from being hardcoded. Allow javascript
+ // to specify.
+ browser->window()->SetBounds(gfx::Rect(0, 0, 400, 300));
}
+ browser->window()->Show();
}
void FilebrowseHandler::SendPicasawebRequest() {
@@ -810,8 +747,7 @@ void FilebrowseHandler::ReadInFile() {
url += username;
url += kPicasawebDefault;
- FilePath currentpath;
- currentpath = FilePath(current_file_uploaded_);
+ FilePath currentpath(current_file_uploaded_);
// Get the filename
std::string filename;
filename = currentpath.BaseName().value();
@@ -836,28 +772,12 @@ void FilebrowseHandler::ReadInFile() {
// This is just a prototype for allowing generic uploads to various sites
// TODO(dhg): Remove this and implement general upload.
-void FilebrowseHandler::UploadToPicasaweb(const Value* value) {
- std::string path;
+void FilebrowseHandler::UploadToPicasaweb(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- Value* list_member;
-
- // Get search string.
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string_value->GetAsString(&path);
- }
-
- } else {
- LOG(ERROR) << "Wasn't able to get the List if requested files.";
- return;
- }
- current_file_uploaded_ = path;
+ std::string search_string = WideToUTF8(ExtractStringValue(args));
+ current_file_uploaded_ = search_string;
// ReadInFile();
- FilePath current_path(path);
+ FilePath current_path(search_string);
TaskProxy* task = new TaskProxy(AsWeakPtr(), current_path);
task->AddRef();
current_task_ = task;
@@ -870,7 +790,7 @@ void FilebrowseHandler::UploadToPicasaweb(const Value* value) {
void FilebrowseHandler::GetChildrenForPath(FilePath& path, bool is_refresh) {
filelist_value_.reset(new ListValue());
- currentpath_ = FilePath(path);
+ currentpath_ = path;
if (lister_.get()) {
lister_->Cancel();
@@ -879,47 +799,40 @@ void FilebrowseHandler::GetChildrenForPath(FilePath& path, bool is_refresh) {
}
is_refresh_ = is_refresh;
- lister_ = new net::DirectoryLister(currentpath_, this);
+ FilePath default_download_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &default_download_path)) {
+ NOTREACHED();
+ }
+ if (currentpath_ == default_download_path) {
+ lister_ = new net::DirectoryLister(currentpath_,
+ false,
+ net::DirectoryLister::DATE,
+ this);
+ } else {
+ lister_ = new net::DirectoryLister(currentpath_, this);
+ }
lister_->Start();
}
-void FilebrowseHandler::HandleGetChildren(const Value* value) {
- std::string path;
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- Value* list_member;
-
- // Get search string.
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string_value->GetAsString(&path);
- }
-
- } else {
- LOG(ERROR) << "Wasn't able to get the List if requested files.";
- return;
- }
+void FilebrowseHandler::HandleGetChildren(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
filelist_value_.reset(new ListValue());
- FilePath currentpath;
-#if defined(OS_WIN)
- currentpath = FilePath(ASCIIToWide(path));
-#else
- currentpath = FilePath(path);
-#endif
GetChildrenForPath(currentpath, false);
+#endif
}
void FilebrowseHandler::OnListFile(
- const file_util::FileEnumerator::FindInfo& data) {
+ const net::DirectoryLister::DirectoryListerData& data) {
#if defined(OS_WIN)
- if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
+ if (data.info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
return;
}
#elif defined(OS_POSIX)
- if (data.filename[0] == '.') {
+ if (data.info.filename[0] == '.') {
return;
}
#endif
@@ -927,19 +840,18 @@ void FilebrowseHandler::OnListFile(
DictionaryValue* file_value = new DictionaryValue();
#if defined(OS_WIN)
- int64 size = (static_cast<int64>(data.nFileSizeHigh) << 32) |
- data.nFileSizeLow;
- file_value->SetString(kPropertyTitle, data.cFileName);
+ int64 size = (static_cast<int64>(data.info.nFileSizeHigh) << 32) |
+ data.info.nFileSizeLow;
+ file_value->SetString(kPropertyTitle, data.info.cFileName);
file_value->SetString(kPropertyPath,
- currentpath_.Append(data.cFileName).value());
+ currentpath_.Append(data.info.cFileName).value());
file_value->SetBoolean(kPropertyDirectory,
- (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false);
-
+ (data.info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false);
#elif defined(OS_POSIX)
- file_value->SetString(kPropertyTitle, data.filename);
+ file_value->SetString(kPropertyTitle, data.info.filename);
file_value->SetString(kPropertyPath,
- currentpath_.Append(data.filename).value());
- file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.stat.st_mode));
+ currentpath_.Append(data.info.filename).value());
+ file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.info.stat.st_mode));
#endif
filelist_value_->Append(file_value);
}
@@ -947,9 +859,9 @@ void FilebrowseHandler::OnListFile(
void FilebrowseHandler::OnListDone(int error) {
DictionaryValue info_value;
if (is_refresh_) {
- info_value.SetString(L"functionCall", "refresh");
+ info_value.SetString("functionCall", "refresh");
} else {
- info_value.SetString(L"functionCall", "getChildren");
+ info_value.SetString("functionCall", "getChildren");
}
info_value.SetString(kPropertyPath, currentpath_.value());
dom_ui_->CallJavascriptFunction(L"browseFileResult",
@@ -957,20 +869,19 @@ void FilebrowseHandler::OnListDone(int error) {
SendCurrentDownloads();
}
-void FilebrowseHandler::HandleGetMetadata(const Value* value) {
+void FilebrowseHandler::HandleGetMetadata(const ListValue* args) {
}
-void FilebrowseHandler::HandleGetDownloads(const Value* value) {
+void FilebrowseHandler::HandleGetDownloads(const ListValue* args) {
ModelChanged();
}
void FilebrowseHandler::ModelChanged() {
ClearDownloadItems();
- download_manager_->GetAllDownloads(this, FilePath());
-}
-void FilebrowseHandler::SetDownloads(std::vector<DownloadItem*>& downloads) {
- ClearDownloadItems();
+ std::vector<DownloadItem*> downloads;
+ download_manager_->GetAllDownloads(FilePath(), &downloads);
+
std::vector<DownloadItem*> new_downloads;
// Scan for any in progress downloads and add ourself to them as an observer.
for (DownloadList::iterator it = downloads.begin();
@@ -1011,34 +922,65 @@ void FilebrowseHandler::DeleteFile(const FilePath& path) {
NewRunnableMethod(current_task_, &TaskProxy::FireDeleteCompleteProxy));
}
-void FilebrowseHandler::HandleDeleteFile(const Value* value) {
- #if defined(OS_CHROMEOS)
+void FilebrowseHandler::CopyFile(const FilePath& src, const FilePath& dest) {
+ if (file_util::DirectoryExists(src)) {
+ if (!file_util::CopyDirectory(src, dest, true)) {
+ LOG(ERROR) << "unable to copy directory:" << src.value();
+ }
+ } else {
+ if (!file_util::CopyFile(src, dest)) {
+ LOG(ERROR) << "unable to copy file" << src.value();
+ }
+ }
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(current_task_, &TaskProxy::FireCopyCompleteProxy));
+}
+
+void FilebrowseHandler::HandleDeleteFile(const ListValue* args) {
+#if defined(OS_CHROMEOS)
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ FilePath currentpath(path);
+ for (unsigned int x = 0; x < active_download_items_.size(); x++) {
+ FilePath item = active_download_items_[x]->full_path();
+ if (item == currentpath) {
+ active_download_items_[x]->Cancel(true);
+ active_download_items_[x]->Remove(true);
+ FilePath dir_path = item.DirName();
+ GetChildrenForPath(dir_path, true);
+ return;
+ }
+ }
+ TaskProxy* task = new TaskProxy(AsWeakPtr(), currentpath);
+ task->AddRef();
+ current_task_ = task;
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ task, &TaskProxy::DeleteFileProxy));
+#endif
+}
+
+void FilebrowseHandler::HandleCopyFile(const ListValue* value) {
+#if defined(OS_CHROMEOS)
if (value && value->GetType() == Value::TYPE_LIST) {
const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string path;
+ std::string src;
+ std::string dest;
// Get path string.
- if (list_value->GetString(0, &path)) {
-
- FilePath currentpath;
- currentpath = FilePath(path);
- for (unsigned int x = 0; x < active_download_items_.size(); x++) {
- FilePath item = active_download_items_[x]->full_path();
- if (item == currentpath) {
- active_download_items_[x]->Cancel(true);
- active_download_items_[x]->Remove(true);
- FilePath dir_path = item.DirName();
- GetChildrenForPath(dir_path, true);
- return;
- }
- }
- TaskProxy* task = new TaskProxy(AsWeakPtr(), currentpath);
+ if (list_value->GetString(0, &src) &&
+ list_value->GetString(1, &dest)) {
+ FilePath SrcPath = FilePath(src);
+ FilePath DestPath = FilePath(dest);
+
+ TaskProxy* task = new TaskProxy(AsWeakPtr(), SrcPath, DestPath);
task->AddRef();
current_task_ = task;
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(
- task, &TaskProxy::DeleteFileProxy));
+ task, &TaskProxy::CopyFileProxy));
} else {
LOG(ERROR) << "Unable to get string";
return;
@@ -1047,6 +989,7 @@ void FilebrowseHandler::HandleDeleteFile(const Value* value) {
#endif
}
+
void FilebrowseHandler::OnDownloadUpdated(DownloadItem* download) {
DownloadList::iterator it = find(active_download_items_.begin(),
active_download_items_.end(),
@@ -1106,11 +1049,11 @@ Browser* FileBrowseUI::OpenPopup(Profile* profile,
int width,
int height) {
// Get existing pop up for given hashArgument.
- Browser* browser = GetPopupForPath(hashArgument);
+ Browser* browser = GetPopupForPath(hashArgument, profile);
// Create new browser if no matching pop up found.
if (browser == NULL) {
- browser = Browser::CreateForPopup(profile);
+ browser = Browser::CreateForType(Browser::TYPE_APP_PANEL, profile);
std::string url;
if (hashArgument.empty()) {
url = chrome::kChromeUIFileBrowseURL;
@@ -1121,22 +1064,46 @@ Browser* FileBrowseUI::OpenPopup(Profile* profile,
browser->AddTabWithURL(
GURL(url), GURL(), PageTransition::LINK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser);
browser->window()->SetBounds(gfx::Rect(kPopupLeft,
kPopupTop,
width,
height));
browser->window()->Show();
+ } else {
+ browser->window()->Show();
}
return browser;
}
-Browser* FileBrowseUI::GetPopupForPath(const std::string& path) {
+Browser* FileBrowseUI::GetPopupForPath(const std::string& path,
+ Profile* profile) {
+ std::string current_path = path;
+ if (current_path.empty()) {
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser == NULL) {
+ return NULL;
+ }
+ Profile* profile = browser->profile();
+ PrefService* pref_service = profile->GetPrefs();
+ bool is_enabled = pref_service->GetBoolean(
+ prefs::kLabsAdvancedFilesystemEnabled);
+ if (!is_enabled) {
+ FilePath default_download_path;
+ if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
+ &default_download_path)) {
+ NOTREACHED();
+ }
+ current_path = default_download_path.value();
+ }
+ }
+
for (BrowserList::const_iterator it = BrowserList::begin();
it != BrowserList::end(); ++it) {
- if ((*it)->type() == Browser::TYPE_POPUP) {
+ if (((*it)->type() == Browser::TYPE_APP_PANEL)) {
TabContents* tab_contents = (*it)->GetSelectedTabContents();
DCHECK(tab_contents);
if (!tab_contents)
@@ -1145,7 +1112,8 @@ Browser* FileBrowseUI::GetPopupForPath(const std::string& path) {
if (url.SchemeIs(chrome::kChromeUIScheme) &&
url.host() == chrome::kChromeUIFileBrowseHost &&
- url.ref() == path) {
+ url.ref() == current_path &&
+ (*it)->profile() == profile) {
return (*it);
}
}
diff --git a/chrome/browser/dom_ui/filebrowse_ui.h b/chrome/browser/dom_ui/filebrowse_ui.h
index ce02a8f..5d2e867 100644
--- a/chrome/browser/dom_ui/filebrowse_ui.h
+++ b/chrome/browser/dom_ui/filebrowse_ui.h
@@ -1,21 +1,18 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_FILEBROWSE_UI_H_
#define CHROME_BROWSER_DOM_UI_FILEBROWSE_UI_H_
+#pragma once
#include <string>
-#include "base/file_path.h"
-#include "base/scoped_ptr.h"
-#include "base/values.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "chrome/browser/history/history.h"
#include "net/base/directory_lister.h"
-
class Browser;
class Profile;
@@ -32,7 +29,8 @@ class FileBrowseUI : public HtmlDialogUI {
const std::string& hashArgument,
int width,
int height);
- static Browser* GetPopupForPath(const std::string& path);
+ static Browser* GetPopupForPath(const std::string& path,
+ Profile* profile);
private:
DISALLOW_COPY_AND_ASSIGN(FileBrowseUI);
diff --git a/chrome/browser/dom_ui/fileicon_source.cc b/chrome/browser/dom_ui/fileicon_source.cc
index e2d2135..599c755 100644
--- a/chrome/browser/dom_ui/fileicon_source.cc
+++ b/chrome/browser/dom_ui/fileicon_source.cc
@@ -1,10 +1,12 @@
-// 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.
#include "chrome/browser/dom_ui/fileicon_source.h"
#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/ref_counted_memory.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/time_format.h"
diff --git a/chrome/browser/dom_ui/fileicon_source.h b/chrome/browser/dom_ui/fileicon_source.h
index 2f32262..b8e1d2f 100644
--- a/chrome/browser/dom_ui/fileicon_source.h
+++ b/chrome/browser/dom_ui/fileicon_source.h
@@ -4,14 +4,15 @@
#ifndef CHROME_BROWSER_DOM_UI_FILEICON_SOURCE_H_
#define CHROME_BROWSER_DOM_UI_FILEICON_SOURCE_H_
+#pragma once
#include <string>
-#include "app/resource_bundle.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/icon_manager.h"
class GURL;
+class RefCountedBytes;
// FileIconSource is the gateway between network-level chrome:
// requests for favicons and the history backend that serves these.
diff --git a/chrome/browser/dom_ui/font_settings_handler.cc b/chrome/browser/dom_ui/font_settings_handler.cc
index 821150b..fd5d955 100644
--- a/chrome/browser/dom_ui/font_settings_handler.cc
+++ b/chrome/browser/dom_ui/font_settings_handler.cc
@@ -6,7 +6,16 @@
#include "app/l10n_util.h"
#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "base/values.h"
+#include "chrome/browser/character_encoding.h"
+#include "chrome/browser/dom_ui/font_settings_utils.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -20,7 +29,131 @@ void FontSettingsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"fontSettingsTitle",
- l10n_util::GetString(IDS_FONT_LANGUAGE_SETTING_FONT_TAB_TITLE));
+ localized_strings->SetString("fontSettingsTitle",
+ l10n_util::GetStringUTF16(IDS_FONT_LANGUAGE_SETTING_FONT_TAB_TITLE));
+ localized_strings->SetString("fontSettingsFontTitle",
+ l10n_util::GetStringUTF16(
+ IDS_FONT_LANGUAGE_SETTING_FONT_SUB_DIALOG_FONT_TITLE));
+ localized_strings->SetString("fontSettingsSerifLabel",
+ l10n_util::GetStringUTF16(
+ IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SERIF_LABEL));
+ localized_strings->SetString("fontSettingsSansSerifLabel",
+ l10n_util::GetStringUTF16(
+ IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SANS_SERIF_LABEL));
+ localized_strings->SetString("fontSettingsFixedWidthLabel",
+ l10n_util::GetStringUTF16(
+ IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_FIXED_WIDTH_LABEL));
+ localized_strings->SetString("fontSettingsSizeLabel",
+ l10n_util::GetStringUTF16(
+ IDS_FONT_LANGUAGE_SETTING_FONT_SIZE_SELECTOR_LABEL));
+ localized_strings->SetString("fontSettingsEncodingTitle",
+ l10n_util::GetStringUTF16(
+ IDS_FONT_LANGUAGE_SETTING_FONT_SUB_DIALOG_ENCODING_TITLE));
+ localized_strings->SetString("fontSettingsEncodingLabel",
+ l10n_util::GetStringUTF16(
+ IDS_FONT_LANGUAGE_SETTING_FONT_DEFAULT_ENCODING_SELECTOR_LABEL));
+
+ // Fonts
+ ListValue* font_list = FontSettingsUtilities::GetFontsList();
+ if (font_list) localized_strings->Set("fontSettingsFontList", font_list);
+
+ // Font sizes
+ int font_sizes[] = { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26,
+ 28, 30, 32, 34, 36, 40, 44, 48, 56, 64, 72 };
+ int count = arraysize(font_sizes);
+ ListValue* font_size_list = new ListValue;
+ for (int i = 0; i < count; i++) {
+ ListValue* option = new ListValue();
+ option->Append(Value::CreateIntegerValue(font_sizes[i]));
+ option->Append(Value::CreateStringValue(base::IntToString(font_sizes[i])));
+ font_size_list->Append(option);
+ }
+ localized_strings->Set("fontSettingsFontSizeList", font_size_list);
+
+ // Encodings
+ count = CharacterEncoding::GetSupportCanonicalEncodingCount();
+ ListValue* encoding_list = new ListValue;
+ for (int i = 0; i < count; ++i) {
+ int cmd_id = CharacterEncoding::GetEncodingCommandIdByIndex(i);
+ std::string encoding =
+ CharacterEncoding::GetCanonicalEncodingNameByCommandId(cmd_id);
+ string16 name =
+ CharacterEncoding::GetCanonicalEncodingDisplayNameByCommandId(cmd_id);
+
+ ListValue* option = new ListValue();
+ option->Append(Value::CreateStringValue(encoding));
+ option->Append(Value::CreateStringValue(name));
+ encoding_list->Append(option);
+ }
+ localized_strings->Set("fontSettingsEncodingList", encoding_list);
+}
+
+void FontSettingsHandler::Initialize() {
+ SetupSerifFontPreview();
+ SetupSansSerifFontPreview();
+ SetupFixedFontPreview();
+}
+
+DOMMessageHandler* FontSettingsHandler::Attach(DOMUI* dom_ui) {
+ // Call through to superclass.
+ DOMMessageHandler* handler = OptionsPageUIHandler::Attach(dom_ui);
+
+ // Perform validation for saved fonts.
+ DCHECK(dom_ui_);
+ PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
+ FontSettingsUtilities::ValidateSavedFonts(pref_service);
+
+ // Register for preferences that we need to observe manually.
+ serif_font_.Init(prefs::kWebKitSerifFontFamily, pref_service, this);
+ sans_serif_font_.Init(prefs::kWebKitSansSerifFontFamily, pref_service, this);
+ fixed_font_.Init(prefs::kWebKitFixedFontFamily, pref_service, this);
+ default_font_size_.Init(prefs::kWebKitDefaultFontSize, pref_service, this);
+ default_fixed_font_size_.Init(prefs::kWebKitDefaultFixedFontSize,
+ pref_service, this);
+
+ // Return result from the superclass.
+ return handler;
+}
+
+void FontSettingsHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED) {
+ std::string* pref_name = Details<std::string>(details).ptr();
+ if (*pref_name == prefs::kWebKitSerifFontFamily ||
+ *pref_name == prefs::kWebKitDefaultFontSize) {
+ SetupSerifFontPreview();
+ } else if (*pref_name == prefs::kWebKitSansSerifFontFamily ||
+ *pref_name == prefs::kWebKitDefaultFontSize) {
+ SetupSansSerifFontPreview();
+ } else if (*pref_name == prefs::kWebKitFixedFontFamily ||
+ *pref_name == prefs::kWebKitDefaultFixedFontSize) {
+ SetupFixedFontPreview();
+ }
+ }
+}
+
+void FontSettingsHandler::SetupSerifFontPreview() {
+ DCHECK(dom_ui_);
+ StringValue font_value(serif_font_.GetValue());
+ FundamentalValue size_value(default_font_size_.GetValue());
+ dom_ui_->CallJavascriptFunction(
+ L"FontSettings.setupSerifFontPreview", font_value, size_value);
+}
+
+void FontSettingsHandler::SetupSansSerifFontPreview() {
+ DCHECK(dom_ui_);
+ StringValue font_value(sans_serif_font_.GetValue());
+ FundamentalValue size_value(default_font_size_.GetValue());
+ dom_ui_->CallJavascriptFunction(
+ L"FontSettings.setupSansSerifFontPreview", font_value, size_value);
+}
+
+void FontSettingsHandler::SetupFixedFontPreview() {
+ DCHECK(dom_ui_);
+ StringValue font_value(fixed_font_.GetValue());
+ FundamentalValue size_value(default_fixed_font_size_.GetValue());
+ dom_ui_->CallJavascriptFunction(
+ L"FontSettings.setupFixedFontPreview", font_value, size_value);
}
diff --git a/chrome/browser/dom_ui/font_settings_handler.h b/chrome/browser/dom_ui/font_settings_handler.h
index 4463c9e..512be16 100644
--- a/chrome/browser/dom_ui/font_settings_handler.h
+++ b/chrome/browser/dom_ui/font_settings_handler.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_DOM_UI_FONT_SETTINGS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_FONT_SETTINGS_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/options_ui.h"
+#include "chrome/browser/prefs/pref_member.h"
-// Chrome personal options page UI handler.
+// Font settings overlay page UI handler.
class FontSettingsHandler : public OptionsPageUIHandler {
public:
FontSettingsHandler();
@@ -15,8 +17,27 @@ class FontSettingsHandler : public OptionsPageUIHandler {
// OptionsUIHandler implementation.
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+ virtual void Initialize();
+
+ // DOMMessageHandler implementation.
+ virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
private:
+ void SetupSerifFontPreview();
+ void SetupSansSerifFontPreview();
+ void SetupFixedFontPreview();
+
+ StringPrefMember serif_font_;
+ StringPrefMember sans_serif_font_;
+ StringPrefMember fixed_font_;
+ IntegerPrefMember default_font_size_;
+ IntegerPrefMember default_fixed_font_size_;
+
DISALLOW_COPY_AND_ASSIGN(FontSettingsHandler);
};
diff --git a/chrome/browser/dom_ui/history2_ui.cc b/chrome/browser/dom_ui/history2_ui.cc
index 151186f..f2107a1 100644
--- a/chrome/browser/dom_ui/history2_ui.cc
+++ b/chrome/browser/dom_ui/history2_ui.cc
@@ -10,13 +10,16 @@
#include "base/i18n/time_formatting.h"
#include "base/message_loop.h"
#include "base/singleton.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
-#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -54,40 +57,40 @@ void HistoryUIHTMLSource2::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
DictionaryValue localized_strings;
- localized_strings.SetString(L"loading",
- l10n_util::GetString(IDS_HISTORY_LOADING));
- localized_strings.SetString(L"title",
- l10n_util::GetString(IDS_HISTORY_TITLE));
- localized_strings.SetString(L"loading",
- l10n_util::GetString(IDS_HISTORY_LOADING));
- localized_strings.SetString(L"newest",
- l10n_util::GetString(IDS_HISTORY_NEWEST));
- localized_strings.SetString(L"newer",
- l10n_util::GetString(IDS_HISTORY_NEWER));
- localized_strings.SetString(L"older",
- l10n_util::GetString(IDS_HISTORY_OLDER));
- localized_strings.SetString(L"searchresultsfor",
- l10n_util::GetString(IDS_HISTORY_SEARCHRESULTSFOR));
- localized_strings.SetString(L"history",
- l10n_util::GetString(IDS_HISTORY_BROWSERESULTS));
- localized_strings.SetString(L"cont",
- l10n_util::GetString(IDS_HISTORY_CONTINUED));
- localized_strings.SetString(L"searchbutton",
- l10n_util::GetString(IDS_HISTORY_SEARCH_BUTTON));
- localized_strings.SetString(L"noresults",
- l10n_util::GetString(IDS_HISTORY_NO_RESULTS));
- localized_strings.SetString(L"noitems",
- l10n_util::GetString(IDS_HISTORY_NO_ITEMS));
- localized_strings.SetString(L"edithistory",
- l10n_util::GetString(IDS_HISTORY_START_EDITING_HISTORY));
- localized_strings.SetString(L"doneediting",
- l10n_util::GetString(IDS_HISTORY_STOP_EDITING_HISTORY));
- localized_strings.SetString(L"removeselected",
- l10n_util::GetString(IDS_HISTORY_REMOVE_SELECTED_ITEMS));
- localized_strings.SetString(L"clearallhistory",
- l10n_util::GetString(IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG));
- localized_strings.SetString(L"deletewarning",
- l10n_util::GetString(IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING));
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_HISTORY_TITLE));
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("newest",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWEST));
+ localized_strings.SetString("newer",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWER));
+ localized_strings.SetString("older",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OLDER));
+ localized_strings.SetString("searchresultsfor",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCHRESULTSFOR));
+ localized_strings.SetString("history",
+ l10n_util::GetStringUTF16(IDS_HISTORY_BROWSERESULTS));
+ localized_strings.SetString("cont",
+ l10n_util::GetStringUTF16(IDS_HISTORY_CONTINUED));
+ localized_strings.SetString("searchbutton",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCH_BUTTON));
+ localized_strings.SetString("noresults",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_RESULTS));
+ localized_strings.SetString("noitems",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_ITEMS));
+ localized_strings.SetString("edithistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_START_EDITING_HISTORY));
+ localized_strings.SetString("doneediting",
+ l10n_util::GetStringUTF16(IDS_HISTORY_STOP_EDITING_HISTORY));
+ localized_strings.SetString("removeselected",
+ l10n_util::GetStringUTF16(IDS_HISTORY_REMOVE_SELECTED_ITEMS));
+ localized_strings.SetString("clearallhistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG));
+ localized_strings.SetString("deletewarning",
+ l10n_util::GetStringUTF16(IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING));
SetFontAndTextDirection(&localized_strings);
@@ -144,13 +147,13 @@ void BrowsingHistoryHandler2::RegisterMessages() {
NewCallback(this, &BrowsingHistoryHandler2::HandleClearBrowsingData));
}
-void BrowsingHistoryHandler2::HandleGetHistory(const Value* value) {
+void BrowsingHistoryHandler2::HandleGetHistory(const ListValue* args) {
// Anything in-flight is invalid.
cancelable_search_consumer_.CancelAllRequests();
// Get arguments (if any).
int day = 0;
- ExtractIntegerValue(value, &day);
+ ExtractIntegerValue(args, &day);
// Set our query options.
history::QueryOptions options;
@@ -170,14 +173,14 @@ void BrowsingHistoryHandler2::HandleGetHistory(const Value* value) {
NewCallback(this, &BrowsingHistoryHandler2::QueryComplete));
}
-void BrowsingHistoryHandler2::HandleSearchHistory(const Value* value) {
+void BrowsingHistoryHandler2::HandleSearchHistory(const ListValue* args) {
// Anything in-flight is invalid.
cancelable_search_consumer_.CancelAllRequests();
// Get arguments (if any).
int month = 0;
string16 query;
- ExtractSearchHistoryArguments(value, &month, &query);
+ ExtractSearchHistoryArguments(args, &month, &query);
// Set the query ranges for the given month.
history::QueryOptions options = CreateMonthQueryOptions(month);
@@ -195,17 +198,15 @@ void BrowsingHistoryHandler2::HandleSearchHistory(const Value* value) {
NewCallback(this, &BrowsingHistoryHandler2::QueryComplete));
}
-void BrowsingHistoryHandler2::HandleRemoveURLsOnOneDay(const Value* value) {
+void BrowsingHistoryHandler2::HandleRemoveURLsOnOneDay(const ListValue* args) {
if (cancelable_delete_consumer_.HasPendingRequests()) {
dom_ui_->CallJavascriptFunction(L"deleteFailed");
return;
}
- DCHECK(value && value->GetType() == Value::TYPE_LIST);
-
// Get day to delete data from.
int visit_time = 0;
- ExtractIntegerValue(value, &visit_time);
+ ExtractIntegerValue(args, &visit_time);
base::Time::Exploded exploded;
base::Time::FromTimeT(
static_cast<time_t>(visit_time)).LocalExplode(&exploded);
@@ -215,14 +216,13 @@ void BrowsingHistoryHandler2::HandleRemoveURLsOnOneDay(const Value* value) {
// Get URLs.
std::set<GURL> urls;
- const ListValue* list_value = static_cast<const ListValue*>(value);
- for (ListValue::const_iterator v = list_value->begin() + 1;
- v != list_value->end(); ++v) {
+ for (ListValue::const_iterator v = args->begin() + 1;
+ v != args->end(); ++v) {
if ((*v)->GetType() != Value::TYPE_STRING)
continue;
const StringValue* string_value = static_cast<const StringValue*>(*v);
string16 string16_value;
- if (!string_value->GetAsUTF16(&string16_value))
+ if (!string_value->GetAsString(&string16_value))
continue;
urls.insert(GURL(string16_value));
}
@@ -234,9 +234,12 @@ void BrowsingHistoryHandler2::HandleRemoveURLsOnOneDay(const Value* value) {
NewCallback(this, &BrowsingHistoryHandler2::RemoveComplete));
}
-void BrowsingHistoryHandler2::HandleClearBrowsingData(const Value* value) {
- dom_ui_->tab_contents()->delegate()->GetBrowser()->
- OpenClearBrowsingDataDialog();
+void BrowsingHistoryHandler2::HandleClearBrowsingData(const ListValue* args) {
+ // TODO(beng): This is an improper direct dependency on Browser. Route this
+ // through some sort of delegate.
+ Browser* browser = BrowserList::FindBrowserWithProfile(dom_ui_->GetProfile());
+ if (browser)
+ browser->OpenClearBrowsingDataDialog();
}
void BrowsingHistoryHandler2::QueryComplete(
@@ -252,7 +255,7 @@ void BrowsingHistoryHandler2::QueryComplete(
SetURLAndTitle(page_value, page.title(), page.url());
// Need to pass the time in epoch time (fastest JS conversion).
- page_value->SetInteger(L"time",
+ page_value->SetInteger("time",
static_cast<int>(page.visit_time().ToTimeT()));
// Until we get some JS i18n infrastructure, we also need to
@@ -263,31 +266,33 @@ void BrowsingHistoryHandler2::QueryComplete(
// and snippet, browse results need day and time information).
if (search_text_.empty()) {
// Figure out the relative date string.
- std::wstring date_str = TimeFormat::RelativeDate(page.visit_time(),
- &midnight_today);
+ string16 date_str = TimeFormat::RelativeDate(page.visit_time(),
+ &midnight_today);
if (date_str.empty()) {
- date_str = base::TimeFormatFriendlyDate(page.visit_time());
+ date_str =
+ WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time()));
} else {
- date_str = l10n_util::GetStringF(
+ date_str = l10n_util::GetStringFUTF16(
IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
- date_str, base::TimeFormatFriendlyDate(page.visit_time()));
+ date_str,
+ WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time())));
}
- page_value->SetString(L"dateRelativeDay", date_str);
- page_value->SetString(L"dateTimeOfDay",
- base::TimeFormatTimeOfDay(page.visit_time()));
+ page_value->SetString("dateRelativeDay", date_str);
+ page_value->SetString("dateTimeOfDay",
+ WideToUTF16Hack(base::TimeFormatTimeOfDay(page.visit_time())));
} else {
- page_value->SetString(L"dateShort",
- base::TimeFormatShortDate(page.visit_time()));
- page_value->SetStringFromUTF16(L"snippet", page.snippet().text());
+ page_value->SetString("dateShort",
+ WideToUTF16Hack(base::TimeFormatShortDate(page.visit_time())));
+ page_value->SetString("snippet", page.snippet().text());
}
- page_value->SetBoolean(L"starred",
+ page_value->SetBoolean("starred",
dom_ui_->GetProfile()->GetBookmarkModel()->IsBookmarked(page.url()));
results_value.Append(page_value);
}
DictionaryValue info_value;
- info_value.SetStringFromUTF16(L"term", search_text_);
- info_value.SetBoolean(L"finished", results->reached_beginning());
+ info_value.SetString("term", search_text_);
+ info_value.SetBoolean("finished", results->reached_beginning());
dom_ui_->CallJavascriptFunction(L"historyResult", info_value, results_value);
}
@@ -297,32 +302,29 @@ void BrowsingHistoryHandler2::RemoveComplete() {
dom_ui_->CallJavascriptFunction(L"deleteComplete");
}
-void BrowsingHistoryHandler2::ExtractSearchHistoryArguments(const Value* value,
- int* month,
- string16* query) {
+void BrowsingHistoryHandler2::ExtractSearchHistoryArguments(
+ const ListValue* args,
+ int* month,
+ string16* query) {
*month = 0;
+ Value* list_member;
+
+ // Get search string.
+ if (args->Get(0, &list_member) &&
+ list_member->GetType() == Value::TYPE_STRING) {
+ const StringValue* string_value =
+ static_cast<const StringValue*>(list_member);
+ string_value->GetAsString(query);
+ }
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- Value* list_member;
-
- // Get search string.
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string_value->GetAsUTF16(query);
- }
-
- // Get search month.
- if (list_value->Get(1, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string16 string16_value;
- string_value->GetAsUTF16(&string16_value);
- *month = StringToInt(string16_value);
- }
+ // Get search month.
+ if (args->Get(1, &list_member) &&
+ list_member->GetType() == Value::TYPE_STRING) {
+ const StringValue* string_value =
+ static_cast<const StringValue*>(list_member);
+ string16 string16_value;
+ string_value->GetAsString(&string16_value);
+ base::StringToInt(string16_value, month);
}
}
diff --git a/chrome/browser/dom_ui/history2_ui.h b/chrome/browser/dom_ui/history2_ui.h
index 0ad8d2f..b38650e 100644
--- a/chrome/browser/dom_ui/history2_ui.h
+++ b/chrome/browser/dom_ui/history2_ui.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_DOM_UI_HISTORY2_UI_H_
#define CHROME_BROWSER_DOM_UI_HISTORY2_UI_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/string16.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
@@ -52,16 +52,16 @@ class BrowsingHistoryHandler2 : public DOMMessageHandler,
virtual void RegisterMessages();
// Callback for the "getHistory" message.
- void HandleGetHistory(const Value* value);
+ void HandleGetHistory(const ListValue* args);
// Callback for the "searchHistory" message.
- void HandleSearchHistory(const Value* value);
+ void HandleSearchHistory(const ListValue* args);
// Callback for the "removeURLsOnOneDay" message.
- void HandleRemoveURLsOnOneDay(const Value* value);
+ void HandleRemoveURLsOnOneDay(const ListValue* args);
// Handle for "clearBrowsingData" message.
- void HandleClearBrowsingData(const Value* value);
+ void HandleClearBrowsingData(const ListValue* args);
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
@@ -77,7 +77,7 @@ class BrowsingHistoryHandler2 : public DOMMessageHandler,
void RemoveComplete();
// Extract the arguments from the call to HandleSearchHistory.
- void ExtractSearchHistoryArguments(const Value* value,
+ void ExtractSearchHistoryArguments(const ListValue* args,
int* month,
string16* query);
diff --git a/chrome/browser/dom_ui/history_ui.cc b/chrome/browser/dom_ui/history_ui.cc
index cb3b4cc..60ff39f 100644
--- a/chrome/browser/dom_ui/history_ui.cc
+++ b/chrome/browser/dom_ui/history_ui.cc
@@ -10,13 +10,16 @@
#include "base/i18n/time_formatting.h"
#include "base/message_loop.h"
#include "base/singleton.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
-#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -54,40 +57,40 @@ void HistoryUIHTMLSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
DictionaryValue localized_strings;
- localized_strings.SetString(L"loading",
- l10n_util::GetString(IDS_HISTORY_LOADING));
- localized_strings.SetString(L"title",
- l10n_util::GetString(IDS_HISTORY_TITLE));
- localized_strings.SetString(L"loading",
- l10n_util::GetString(IDS_HISTORY_LOADING));
- localized_strings.SetString(L"newest",
- l10n_util::GetString(IDS_HISTORY_NEWEST));
- localized_strings.SetString(L"newer",
- l10n_util::GetString(IDS_HISTORY_NEWER));
- localized_strings.SetString(L"older",
- l10n_util::GetString(IDS_HISTORY_OLDER));
- localized_strings.SetString(L"searchresultsfor",
- l10n_util::GetString(IDS_HISTORY_SEARCHRESULTSFOR));
- localized_strings.SetString(L"history",
- l10n_util::GetString(IDS_HISTORY_BROWSERESULTS));
- localized_strings.SetString(L"cont",
- l10n_util::GetString(IDS_HISTORY_CONTINUED));
- localized_strings.SetString(L"searchbutton",
- l10n_util::GetString(IDS_HISTORY_SEARCH_BUTTON));
- localized_strings.SetString(L"noresults",
- l10n_util::GetString(IDS_HISTORY_NO_RESULTS));
- localized_strings.SetString(L"noitems",
- l10n_util::GetString(IDS_HISTORY_NO_ITEMS));
- localized_strings.SetString(L"edithistory",
- l10n_util::GetString(IDS_HISTORY_START_EDITING_HISTORY));
- localized_strings.SetString(L"doneediting",
- l10n_util::GetString(IDS_HISTORY_STOP_EDITING_HISTORY));
- localized_strings.SetString(L"removeselected",
- l10n_util::GetString(IDS_HISTORY_REMOVE_SELECTED_ITEMS));
- localized_strings.SetString(L"clearallhistory",
- l10n_util::GetString(IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG));
- localized_strings.SetString(L"deletewarning",
- l10n_util::GetString(IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING));
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_HISTORY_TITLE));
+ localized_strings.SetString("loading",
+ l10n_util::GetStringUTF16(IDS_HISTORY_LOADING));
+ localized_strings.SetString("newest",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWEST));
+ localized_strings.SetString("newer",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NEWER));
+ localized_strings.SetString("older",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OLDER));
+ localized_strings.SetString("searchresultsfor",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCHRESULTSFOR));
+ localized_strings.SetString("history",
+ l10n_util::GetStringUTF16(IDS_HISTORY_BROWSERESULTS));
+ localized_strings.SetString("cont",
+ l10n_util::GetStringUTF16(IDS_HISTORY_CONTINUED));
+ localized_strings.SetString("searchbutton",
+ l10n_util::GetStringUTF16(IDS_HISTORY_SEARCH_BUTTON));
+ localized_strings.SetString("noresults",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_RESULTS));
+ localized_strings.SetString("noitems",
+ l10n_util::GetStringUTF16(IDS_HISTORY_NO_ITEMS));
+ localized_strings.SetString("edithistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_START_EDITING_HISTORY));
+ localized_strings.SetString("doneediting",
+ l10n_util::GetStringUTF16(IDS_HISTORY_STOP_EDITING_HISTORY));
+ localized_strings.SetString("removeselected",
+ l10n_util::GetStringUTF16(IDS_HISTORY_REMOVE_SELECTED_ITEMS));
+ localized_strings.SetString("clearallhistory",
+ l10n_util::GetStringUTF16(IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG));
+ localized_strings.SetString("deletewarning",
+ l10n_util::GetStringUTF16(IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING));
SetFontAndTextDirection(&localized_strings);
@@ -144,13 +147,13 @@ void BrowsingHistoryHandler::RegisterMessages() {
NewCallback(this, &BrowsingHistoryHandler::HandleClearBrowsingData));
}
-void BrowsingHistoryHandler::HandleGetHistory(const Value* value) {
+void BrowsingHistoryHandler::HandleGetHistory(const ListValue* args) {
// Anything in-flight is invalid.
cancelable_search_consumer_.CancelAllRequests();
// Get arguments (if any).
int day = 0;
- ExtractIntegerValue(value, &day);
+ ExtractIntegerValue(args, &day);
// Set our query options.
history::QueryOptions options;
@@ -170,14 +173,14 @@ void BrowsingHistoryHandler::HandleGetHistory(const Value* value) {
NewCallback(this, &BrowsingHistoryHandler::QueryComplete));
}
-void BrowsingHistoryHandler::HandleSearchHistory(const Value* value) {
+void BrowsingHistoryHandler::HandleSearchHistory(const ListValue* args) {
// Anything in-flight is invalid.
cancelable_search_consumer_.CancelAllRequests();
// Get arguments (if any).
int month = 0;
string16 query;
- ExtractSearchHistoryArguments(value, &month, &query);
+ ExtractSearchHistoryArguments(args, &month, &query);
// Set the query ranges for the given month.
history::QueryOptions options = CreateMonthQueryOptions(month);
@@ -195,17 +198,15 @@ void BrowsingHistoryHandler::HandleSearchHistory(const Value* value) {
NewCallback(this, &BrowsingHistoryHandler::QueryComplete));
}
-void BrowsingHistoryHandler::HandleRemoveURLsOnOneDay(const Value* value) {
+void BrowsingHistoryHandler::HandleRemoveURLsOnOneDay(const ListValue* args) {
if (cancelable_delete_consumer_.HasPendingRequests()) {
dom_ui_->CallJavascriptFunction(L"deleteFailed");
return;
}
- DCHECK(value && value->GetType() == Value::TYPE_LIST);
-
// Get day to delete data from.
int visit_time = 0;
- ExtractIntegerValue(value, &visit_time);
+ ExtractIntegerValue(args, &visit_time);
base::Time::Exploded exploded;
base::Time::FromTimeT(
static_cast<time_t>(visit_time)).LocalExplode(&exploded);
@@ -215,14 +216,13 @@ void BrowsingHistoryHandler::HandleRemoveURLsOnOneDay(const Value* value) {
// Get URLs.
std::set<GURL> urls;
- const ListValue* list_value = static_cast<const ListValue*>(value);
- for (ListValue::const_iterator v = list_value->begin() + 1;
- v != list_value->end(); ++v) {
+ for (ListValue::const_iterator v = args->begin() + 1;
+ v != args->end(); ++v) {
if ((*v)->GetType() != Value::TYPE_STRING)
continue;
const StringValue* string_value = static_cast<const StringValue*>(*v);
string16 string16_value;
- if (!string_value->GetAsUTF16(&string16_value))
+ if (!string_value->GetAsString(&string16_value))
continue;
urls.insert(GURL(string16_value));
}
@@ -234,9 +234,12 @@ void BrowsingHistoryHandler::HandleRemoveURLsOnOneDay(const Value* value) {
NewCallback(this, &BrowsingHistoryHandler::RemoveComplete));
}
-void BrowsingHistoryHandler::HandleClearBrowsingData(const Value* value) {
- dom_ui_->tab_contents()->delegate()->GetBrowser()->
- OpenClearBrowsingDataDialog();
+void BrowsingHistoryHandler::HandleClearBrowsingData(const ListValue* args) {
+ // TODO(beng): This is an improper direct dependency on Browser. Route this
+ // through some sort of delegate.
+ Browser* browser = BrowserList::FindBrowserWithProfile(dom_ui_->GetProfile());
+ if (browser)
+ browser->OpenClearBrowsingDataDialog();
}
void BrowsingHistoryHandler::QueryComplete(
@@ -252,7 +255,7 @@ void BrowsingHistoryHandler::QueryComplete(
SetURLAndTitle(page_value, page.title(), page.url());
// Need to pass the time in epoch time (fastest JS conversion).
- page_value->SetInteger(L"time",
+ page_value->SetInteger("time",
static_cast<int>(page.visit_time().ToTimeT()));
// Until we get some JS i18n infrastructure, we also need to
@@ -263,31 +266,33 @@ void BrowsingHistoryHandler::QueryComplete(
// and snippet, browse results need day and time information).
if (search_text_.empty()) {
// Figure out the relative date string.
- std::wstring date_str = TimeFormat::RelativeDate(page.visit_time(),
- &midnight_today);
+ string16 date_str = TimeFormat::RelativeDate(page.visit_time(),
+ &midnight_today);
if (date_str.empty()) {
- date_str = base::TimeFormatFriendlyDate(page.visit_time());
+ date_str =
+ WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time()));
} else {
- date_str = l10n_util::GetStringF(
+ date_str = l10n_util::GetStringFUTF16(
IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
- date_str, base::TimeFormatFriendlyDate(page.visit_time()));
+ date_str,
+ WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time())));
}
- page_value->SetString(L"dateRelativeDay", date_str);
- page_value->SetString(L"dateTimeOfDay",
- base::TimeFormatTimeOfDay(page.visit_time()));
+ page_value->SetString("dateRelativeDay", date_str);
+ page_value->SetString("dateTimeOfDay",
+ WideToUTF16Hack(base::TimeFormatTimeOfDay(page.visit_time())));
} else {
- page_value->SetString(L"dateShort",
- base::TimeFormatShortDate(page.visit_time()));
- page_value->SetStringFromUTF16(L"snippet", page.snippet().text());
+ page_value->SetString("dateShort",
+ WideToUTF16Hack(base::TimeFormatShortDate(page.visit_time())));
+ page_value->SetString("snippet", page.snippet().text());
}
- page_value->SetBoolean(L"starred",
+ page_value->SetBoolean("starred",
dom_ui_->GetProfile()->GetBookmarkModel()->IsBookmarked(page.url()));
results_value.Append(page_value);
}
DictionaryValue info_value;
- info_value.SetStringFromUTF16(L"term", search_text_);
- info_value.SetBoolean(L"finished", results->reached_beginning());
+ info_value.SetString("term", search_text_);
+ info_value.SetBoolean("finished", results->reached_beginning());
dom_ui_->CallJavascriptFunction(L"historyResult", info_value, results_value);
}
@@ -297,33 +302,18 @@ void BrowsingHistoryHandler::RemoveComplete() {
dom_ui_->CallJavascriptFunction(L"deleteComplete");
}
-void BrowsingHistoryHandler::ExtractSearchHistoryArguments(const Value* value,
- int* month,
- string16* query) {
- *month = 0;
-
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- Value* list_member;
-
- // Get search string.
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string_value->GetAsUTF16(query);
- }
+void BrowsingHistoryHandler::ExtractSearchHistoryArguments(
+ const ListValue* args,
+ int* month,
+ string16* query) {
+ CHECK(args->GetSize() == 2);
+ query->clear();
+ CHECK(args->GetString(0, query));
- // Get search month.
- if (list_value->Get(1, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string16 string16_value;
- string_value->GetAsUTF16(&string16_value);
- *month = StringToInt(string16_value);
- }
- }
+ string16 string16_value;
+ CHECK(args->GetString(1, &string16_value));
+ *month = 0;
+ base::StringToInt(string16_value, month);
}
history::QueryOptions BrowsingHistoryHandler::CreateMonthQueryOptions(
diff --git a/chrome/browser/dom_ui/history_ui.h b/chrome/browser/dom_ui/history_ui.h
index ff3849a..8d33afe 100644
--- a/chrome/browser/dom_ui/history_ui.h
+++ b/chrome/browser/dom_ui/history_ui.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_DOM_UI_HISTORY_UI_H_
#define CHROME_BROWSER_DOM_UI_HISTORY_UI_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/string16.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
@@ -48,16 +48,16 @@ class BrowsingHistoryHandler : public DOMMessageHandler,
virtual void RegisterMessages();
// Callback for the "getHistory" message.
- void HandleGetHistory(const Value* value);
+ void HandleGetHistory(const ListValue* args);
// Callback for the "searchHistory" message.
- void HandleSearchHistory(const Value* value);
+ void HandleSearchHistory(const ListValue* args);
// Callback for the "removeURLsOnOneDay" message.
- void HandleRemoveURLsOnOneDay(const Value* value);
+ void HandleRemoveURLsOnOneDay(const ListValue* args);
// Handle for "clearBrowsingData" message.
- void HandleClearBrowsingData(const Value* value);
+ void HandleClearBrowsingData(const ListValue* args);
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
@@ -73,7 +73,7 @@ class BrowsingHistoryHandler : public DOMMessageHandler,
void RemoveComplete();
// Extract the arguments from the call to HandleSearchHistory.
- void ExtractSearchHistoryArguments(const Value* value,
+ void ExtractSearchHistoryArguments(const ListValue* args,
int* month,
string16* query);
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 a2ba5eb..0230f88 100644
--- a/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc
+++ b/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
// Incognito profiles are not long-lived, so we always want to store a
// non-incognito profile.
@@ -43,7 +44,7 @@ void HtmlDialogTabContentsDelegate::OpenURLFromTab(
TabContents* new_contents =
browser->AddTabWithURL(url, referrer, transition, -1,
TabStripModel::ADD_SELECTED, NULL,
- std::string());
+ std::string(), &browser);
DCHECK(new_contents);
browser->window()->Show();
new_contents->Focus();
@@ -76,6 +77,11 @@ void HtmlDialogTabContentsDelegate::ActivateContents(TabContents* contents) {
// this frame and we don't have a TabStripModel.
}
+void HtmlDialogTabContentsDelegate::DeactivateContents(TabContents* contents) {
+ // We don't care about this notification (called when a user gesture triggers
+ // a call to window.blur()).
+}
+
void HtmlDialogTabContentsDelegate::LoadingStateChanged(TabContents* source) {
// We don't care about this notification.
}
@@ -85,7 +91,7 @@ void HtmlDialogTabContentsDelegate::CloseContents(TabContents* source) {
// cleanup somewhere else (namely, HtmlDialogUIDelegate::OnDialogClosed()).
}
-bool HtmlDialogTabContentsDelegate::IsPopup(TabContents* source) {
+bool HtmlDialogTabContentsDelegate::IsPopup(const TabContents* source) const {
// This needs to return true so that we are allowed to be resized by our
// contents.
return true;
@@ -102,7 +108,9 @@ void HtmlDialogTabContentsDelegate::UpdateTargetURL(TabContents* source,
// Ignored.
}
-bool HtmlDialogTabContentsDelegate::ShouldAddNavigationToHistory() const {
+bool HtmlDialogTabContentsDelegate::ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type) {
return false;
}
diff --git a/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h b/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h
index d827424..b0ab266 100644
--- a/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h
+++ b/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_HTML_DIALOG_TAB_CONTENTS_DELEGATE_H_
#define CHROME_BROWSER_DOM_UI_HTML_DIALOG_TAB_CONTENTS_DELEGATE_H_
+#pragma once
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -47,12 +48,15 @@ class HtmlDialogTabContentsDelegate : public TabContentsDelegate {
const gfx::Rect& initial_pos,
bool user_gesture);
virtual void ActivateContents(TabContents* contents);
+ virtual void DeactivateContents(TabContents* contents);
virtual void LoadingStateChanged(TabContents* source);
virtual void CloseContents(TabContents* source);
- virtual bool IsPopup(TabContents* source);
+ virtual bool IsPopup(const TabContents* source) const;
virtual void URLStarredChanged(TabContents* source, bool starred);
virtual void UpdateTargetURL(TabContents* source, const GURL& url);
- virtual bool ShouldAddNavigationToHistory() const;
+ virtual bool ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type);
protected:
// Overridden only for testing.
diff --git a/chrome/browser/dom_ui/html_dialog_tab_contents_delegate_unittest.cc b/chrome/browser/dom_ui/html_dialog_tab_contents_delegate_unittest.cc
index a088671..ac3ccaa 100644
--- a/chrome/browser/dom_ui/html_dialog_tab_contents_delegate_unittest.cc
+++ b/chrome/browser/dom_ui/html_dialog_tab_contents_delegate_unittest.cc
@@ -10,9 +10,12 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/browser_with_test_window_test.h"
#include "chrome/test/test_browser_window.h"
+#include "chrome/test/testing_profile.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -99,7 +102,12 @@ class HtmlDialogTabContentsDelegateTest : public BrowserWithTestWindowTest {
TEST_F(HtmlDialogTabContentsDelegateTest, DoNothingMethodsTest) {
// None of the following calls should do anything.
EXPECT_TRUE(test_tab_contents_delegate_->IsPopup(NULL));
- EXPECT_FALSE(test_tab_contents_delegate_->ShouldAddNavigationToHistory());
+ scoped_refptr<history::HistoryAddPageArgs> should_add_args(
+ new history::HistoryAddPageArgs(
+ GURL(), base::Time::Now(), 0, 0, GURL(), history::RedirectList(),
+ PageTransition::TYPED, history::SOURCE_SYNCED, false));
+ EXPECT_FALSE(test_tab_contents_delegate_->ShouldAddNavigationToHistory(
+ *should_add_args, NavigationType::NEW_PAGE));
test_tab_contents_delegate_->NavigationStateChanged(NULL, 0);
test_tab_contents_delegate_->ActivateContents(NULL);
test_tab_contents_delegate_->LoadingStateChanged(NULL);
@@ -133,7 +141,7 @@ TEST_F(HtmlDialogTabContentsDelegateTest, AddNewContentsTest) {
test_tab_contents_delegate_->SetWindowForNextCreatedBrowser(window);
TabContents* contents =
- new TabContents(profile(), NULL, MSG_ROUTING_NONE, NULL);
+ new TabContents(profile(), NULL, MSG_ROUTING_NONE, NULL, NULL);
test_tab_contents_delegate_->AddNewContents(
NULL, contents, NEW_FOREGROUND_TAB, gfx::Rect(), false);
EXPECT_EQ(0, browser()->tab_count());
diff --git a/chrome/browser/dom_ui/html_dialog_ui.cc b/chrome/browser/dom_ui/html_dialog_ui.cc
index f93e9ca..ff49805 100644
--- a/chrome/browser/dom_ui/html_dialog_ui.cc
+++ b/chrome/browser/dom_ui/html_dialog_ui.cc
@@ -59,12 +59,13 @@ void HtmlDialogUI::RenderViewCreated(RenderViewHost* render_view_host) {
}
}
-void HtmlDialogUI::OnDialogClosed(const Value* content) {
+void HtmlDialogUI::OnDialogClosed(const ListValue* args) {
HtmlDialogUIDelegate** delegate = GetPropertyAccessor().GetProperty(
tab_contents()->property_bag());
- if (delegate)
+ if (delegate) {
(*delegate)->OnDialogClosed(
- dom_ui_util::GetJsonResponseFromFirstArgumentInList(content));
+ dom_ui_util::GetJsonResponseFromFirstArgumentInList(args));
+ }
}
ExternalHtmlDialogUI::ExternalHtmlDialogUI(TabContents* tab_contents)
diff --git a/chrome/browser/dom_ui/html_dialog_ui.h b/chrome/browser/dom_ui/html_dialog_ui.h
index be2df7f..38673c4 100644
--- a/chrome/browser/dom_ui/html_dialog_ui.h
+++ b/chrome/browser/dom_ui/html_dialog_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_HTML_DIALOG_UI_H_
#define CHROME_BROWSER_DOM_UI_HTML_DIALOG_UI_H_
+#pragma once
#include <string>
#include <vector>
@@ -51,7 +52,7 @@ class HtmlDialogUIDelegate {
virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) = 0;
protected:
- ~HtmlDialogUIDelegate() {}
+ virtual ~HtmlDialogUIDelegate() {}
};
// Displays file URL contents inside a modal HTML dialog.
@@ -90,7 +91,7 @@ class HtmlDialogUI : public DOMUI {
virtual void RenderViewCreated(RenderViewHost* render_view_host);
// JS message handler.
- void OnDialogClosed(const Value* content);
+ void OnDialogClosed(const ListValue* args);
DISALLOW_COPY_AND_ASSIGN(HtmlDialogUI);
};
diff --git a/chrome/browser/dom_ui/mediaplayer_browsertest.cc b/chrome/browser/dom_ui/mediaplayer_browsertest.cc
index e2c582f..1dcbfae 100644
--- a/chrome/browser/dom_ui/mediaplayer_browsertest.cc
+++ b/chrome/browser/dom_ui/mediaplayer_browsertest.cc
@@ -8,7 +8,8 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
-#include "chrome/browser/pref_service.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 "chrome/common/url_constants.h"
@@ -28,7 +29,7 @@ class MediaPlayerBrowserTest : public InProcessBrowserTest {
bool IsPlayerVisible() {
for (BrowserList::const_iterator it = BrowserList::begin();
it != BrowserList::end(); ++it) {
- if ((*it)->type() == Browser::TYPE_POPUP) {
+ if ((*it)->type() == Browser::TYPE_APP_PANEL) {
const GURL& url =
(*it)->GetTabContentsAt((*it)->selected_index())->GetURL();
@@ -44,7 +45,7 @@ class MediaPlayerBrowserTest : public InProcessBrowserTest {
bool IsPlaylistVisible() {
for (BrowserList::const_iterator it = BrowserList::begin();
it != BrowserList::end(); ++it) {
- if ((*it)->type() == Browser::TYPE_POPUP) {
+ if ((*it)->type() == Browser::TYPE_APP_PANEL) {
const GURL& url =
(*it)->GetTabContentsAt((*it)->selected_index())->GetURL();
@@ -60,7 +61,7 @@ class MediaPlayerBrowserTest : public InProcessBrowserTest {
};
IN_PROC_BROWSER_TEST_F(MediaPlayerBrowserTest, Popup) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
// Doing this so we have a valid profile.
ui_test_utils::NavigateToURL(browser(),
GURL("chrome://downloads"));
@@ -78,7 +79,7 @@ IN_PROC_BROWSER_TEST_F(MediaPlayerBrowserTest, Popup) {
}
IN_PROC_BROWSER_TEST_F(MediaPlayerBrowserTest, PopupPlaylist) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
// Doing this so we have a valid profile.
ui_test_utils::NavigateToURL(browser(),
GURL("chrome://downloads"));
diff --git a/chrome/browser/dom_ui/mediaplayer_ui.cc b/chrome/browser/dom_ui/mediaplayer_ui.cc
index 5cad6dc..e545da0 100644
--- a/chrome/browser/dom_ui/mediaplayer_ui.cc
+++ b/chrome/browser/dom_ui/mediaplayer_ui.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "base/message_loop.h"
@@ -26,15 +25,20 @@
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/pref_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/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_job.h"
@@ -43,23 +47,17 @@
#include "chrome/browser/chromeos/frame/panel_browser_view.h"
#endif
-#include "grit/browser_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-
-static const std::wstring kPropertyPath = L"path";
-static const std::wstring kPropertyForce = L"force";
-static const std::wstring kPropertyTitle = L"title";
-static const std::wstring kPropertyOffset = L"currentOffset";
-static const std::wstring kPropertyError = L"error";
+static const char kPropertyPath[] = "path";
+static const char kPropertyForce[] = "force";
+static const char kPropertyOffset[] = "currentOffset";
+static const char kPropertyError[] = "error";
-const char* kMediaplayerURL = "chrome://mediaplayer";
-const char* kMediaplayerPlaylistURL = "chrome://mediaplayer#playlist";
-const int kPopupLeft = 0;
-const int kPopupTop = 0;
-const int kPopupWidth = 350;
-const int kPopupHeight = 300;
+static const char* kMediaplayerURL = "chrome://mediaplayer";
+static const char* kMediaplayerPlaylistURL = "chrome://mediaplayer#playlist";
+static const int kPopupLeft = 0;
+static const int kPopupTop = 0;
+static const int kPopupWidth = 350;
+static const int kPopupHeight = 300;
class MediaplayerUIHTMLSource : public ChromeURLDataManager::DataSource {
public:
@@ -108,7 +106,7 @@ class MediaplayerHandler : public DOMMessageHandler,
virtual void RegisterMessages();
// Callback for the "currentOffsetChanged" message.
- void HandleCurrentOffsetChanged(const Value* value);
+ void HandleCurrentOffsetChanged(const ListValue* args);
void FirePlaylistChanged(const std::string& path,
bool force,
@@ -118,18 +116,18 @@ class MediaplayerHandler : public DOMMessageHandler,
void EnqueueMediaFile(const GURL& url);
- void GetPlaylistValue(ListValue& value);
+ void GetPlaylistValue(ListValue& args);
// Callback for the "playbackError" message.
- void HandlePlaybackError(const Value* value);
+ void HandlePlaybackError(const ListValue* args);
// Callback for the "getCurrentPlaylist" message.
- void HandleGetCurrentPlaylist(const Value* value);
+ void HandleGetCurrentPlaylist(const ListValue* args);
- void HandleTogglePlaylist(const Value* value);
- void HandleShowPlaylist(const Value* value);
- void HandleSetCurrentPlaylistOffset(const Value* value);
- void HandleToggleFullscreen(const Value* value);
+ void HandleTogglePlaylist(const ListValue* args);
+ void HandleShowPlaylist(const ListValue* args);
+ void HandleSetCurrentPlaylistOffset(const ListValue* args);
+ void HandleToggleFullscreen(const ListValue* args);
const UrlVector& GetCurrentPlaylist();
@@ -167,7 +165,7 @@ void MediaplayerUIHTMLSource::StartDataRequest(const std::string& path,
DictionaryValue localized_strings;
// TODO(dhg): Fix the strings that are currently hardcoded so they
// use the localized versions.
- localized_strings.SetString(L"errorstring", "Error Playing Back");
+ localized_strings.SetString("errorstring", "Error Playing Back");
SetFontAndTextDirection(&localized_strings);
@@ -247,12 +245,12 @@ void MediaplayerHandler::RegisterMessages() {
NewCallback(this, &MediaplayerHandler::HandleShowPlaylist));
}
-void MediaplayerHandler::GetPlaylistValue(ListValue& value) {
+void MediaplayerHandler::GetPlaylistValue(ListValue& urls) {
for (size_t x = 0; x < current_playlist_.size(); x++) {
DictionaryValue* url_value = new DictionaryValue();
url_value->SetString(kPropertyPath, current_playlist_[x].url.spec());
url_value->SetBoolean(kPropertyError, current_playlist_[x].haderror);
- value.Append(url_value);
+ urls.Append(url_value);
}
}
@@ -271,22 +269,14 @@ int MediaplayerHandler::GetCurrentPlaylistOffset() {
return current_offset_;
}
-void MediaplayerHandler::HandleToggleFullscreen(const Value* value) {
+void MediaplayerHandler::HandleToggleFullscreen(const ListValue* args) {
MediaPlayer::Get()->ToggleFullscreen();
}
-void MediaplayerHandler::HandleSetCurrentPlaylistOffset(const Value* value) {
- ListValue results_value;
- DictionaryValue info_value;
- if (value && value->GetType() == Value::TYPE_LIST) {
- // Get the new playlist offset;
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string val;
- if (list_value->GetString(0, &val)) {
- int id = atoi(val.c_str());
- MediaPlayer::Get()->SetPlaylistOffset(id);
- }
- }
+void MediaplayerHandler::HandleSetCurrentPlaylistOffset(const ListValue* args) {
+ int id;
+ CHECK(ExtractIntegerValue(args, &id));
+ MediaPlayer::Get()->SetPlaylistOffset(id);
}
void MediaplayerHandler::FirePlaylistChanged(const std::string& path,
@@ -319,51 +309,36 @@ void MediaplayerHandler::EnqueueMediaFile(const GURL& url) {
MediaPlayer::Get()->NotifyPlaylistChanged();
}
-void MediaplayerHandler::HandleCurrentOffsetChanged(const Value* value) {
- ListValue results_value;
- DictionaryValue info_value;
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string val;
-
- // Get the new playlist offset;
- if (list_value->GetString(0, &val)) {
- int id = atoi(val.c_str());
- current_offset_ = id;
- MediaPlayer::Get()->NotifyPlaylistChanged();
- }
- }
+void MediaplayerHandler::HandleCurrentOffsetChanged(const ListValue* args) {
+ CHECK(ExtractIntegerValue(args, &current_offset_));
+ MediaPlayer::Get()->NotifyPlaylistChanged();
}
-void MediaplayerHandler::HandlePlaybackError(const Value* value) {
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string error;
- std::string url;
- // Get path string.
- if (list_value->GetString(0, &error)) {
- LOG(ERROR) << "Playback error" << error;
- }
- if (list_value->GetString(1, &url)) {
- for (size_t x = 0; x < current_playlist_.size(); x++) {
- if (current_playlist_[x].url == GURL(url)) {
- current_playlist_[x].haderror = true;
- }
+void MediaplayerHandler::HandlePlaybackError(const ListValue* args) {
+ std::string error;
+ std::string url;
+ // Get path string.
+ if (args->GetString(0, &error))
+ LOG(ERROR) << "Playback error" << error;
+ if (args->GetString(1, &url)) {
+ for (size_t x = 0; x < current_playlist_.size(); x++) {
+ if (current_playlist_[x].url == GURL(url)) {
+ current_playlist_[x].haderror = true;
}
- FirePlaylistChanged(std::string(), false, current_offset_);
}
+ FirePlaylistChanged(std::string(), false, current_offset_);
}
}
-void MediaplayerHandler::HandleGetCurrentPlaylist(const Value* value) {
+void MediaplayerHandler::HandleGetCurrentPlaylist(const ListValue* args) {
FirePlaylistChanged(std::string(), false, current_offset_);
}
-void MediaplayerHandler::HandleTogglePlaylist(const Value* value) {
+void MediaplayerHandler::HandleTogglePlaylist(const ListValue* args) {
MediaPlayer::Get()->TogglePlaylistWindowVisible();
}
-void MediaplayerHandler::HandleShowPlaylist(const Value* value) {
+void MediaplayerHandler::HandleShowPlaylist(const ListValue* args) {
MediaPlayer::Get()->ShowPlaylistWindow();
}
@@ -377,6 +352,9 @@ void MediaplayerHandler::HandleShowPlaylist(const Value* value) {
// won't be deleted until it's last InvokeLater is run.
DISABLE_RUNNABLE_METHOD_REFCOUNT(MediaPlayer);
+MediaPlayer::~MediaPlayer() {
+}
+
void MediaPlayer::EnqueueMediaURL(const GURL& url, Browser* creator) {
if (!Enabled()) {
return;
@@ -518,10 +496,12 @@ void MediaPlayer::RemoveHandler(MediaplayerHandler* handler) {
void MediaPlayer::PopupPlaylist(Browser* creator) {
Profile* profile = BrowserList::GetLastActive()->profile();
- playlist_browser_ = Browser::CreateForPopup(profile);
+ playlist_browser_ = Browser::CreateForType(Browser::TYPE_APP_PANEL,
+ profile);
playlist_browser_->AddTabWithURL(
GURL(kMediaplayerPlaylistURL), GURL(), PageTransition::LINK,
- -1, TabStripModel::ADD_SELECTED, NULL, std::string());
+ -1, TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &playlist_browser_);
playlist_browser_->window()->SetBounds(gfx::Rect(kPopupLeft,
kPopupTop,
kPopupWidth,
@@ -538,7 +518,8 @@ void MediaPlayer::PopupMediaPlayer(Browser* creator) {
return;
}
Profile* profile = BrowserList::GetLastActive()->profile();
- mediaplayer_browser_ = Browser::CreateForPopup(profile);
+ mediaplayer_browser_ = Browser::CreateForType(Browser::TYPE_APP_PANEL,
+ profile);
#if defined(OS_CHROMEOS)
// Since we are on chromeos, popups should be a PanelBrowserView,
// so we can just cast it.
@@ -553,7 +534,8 @@ void MediaPlayer::PopupMediaPlayer(Browser* creator) {
#endif
mediaplayer_browser_->AddTabWithURL(
GURL(kMediaplayerURL), GURL(), PageTransition::LINK,
- -1, TabStripModel::ADD_SELECTED, NULL, std::string());
+ -1, TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &mediaplayer_browser_);
mediaplayer_browser_->window()->SetBounds(gfx::Rect(kPopupLeft,
kPopupTop,
kPopupWidth,
diff --git a/chrome/browser/dom_ui/mediaplayer_ui.h b/chrome/browser/dom_ui/mediaplayer_ui.h
index 24e2585..c339799 100644
--- a/chrome/browser/dom_ui/mediaplayer_ui.h
+++ b/chrome/browser/dom_ui/mediaplayer_ui.h
@@ -4,13 +4,12 @@
#ifndef CHROME_BROWSER_DOM_UI_MEDIAPLAYER_UI_H_
#define CHROME_BROWSER_DOM_UI_MEDIAPLAYER_UI_H_
+#pragma once
+#include <set>
#include <vector>
-#include "base/file_path.h"
-#include "base/scoped_ptr.h"
#include "base/singleton.h"
-#include "base/values.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"
@@ -27,7 +26,7 @@ class Browser;
class MediaPlayer : public NotificationObserver,
public URLRequest::Interceptor {
public:
- ~MediaPlayer() {}
+ ~MediaPlayer();
// Enqueues this url into the current playlist. If the mediaplayer is
// not currently visible, show it, and play the given url.
diff --git a/chrome/browser/dom_ui/most_visited_handler.cc b/chrome/browser/dom_ui/most_visited_handler.cc
index 690beb2..95d326f 100644
--- a/chrome/browser/dom_ui/most_visited_handler.cc
+++ b/chrome/browser/dom_ui/most_visited_handler.cc
@@ -12,6 +12,8 @@
#include "base/md5.h"
#include "base/singleton.h"
#include "base/scoped_vector.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/thread.h"
#include "base/values.h"
@@ -20,19 +22,17 @@
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
#include "chrome/browser/dom_ui/dom_ui_thumbnail_source.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/google_util.h"
#include "chrome/browser/history/page_usage_data.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
+#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
@@ -45,24 +45,26 @@ const size_t kMostVisitedPages = 8;
// The number of days of history we consider for most visited entries.
const int kMostVisitedScope = 90;
-// Adds the fields in the page to the dictionary.
-void SetMostVisistedPage(DictionaryValue* dict,
- const MostVisitedHandler::MostVisitedPage& page) {
- NewTabUI::SetURLTitleAndDirection(dict, WideToUTF16(page.title), page.url);
- if (!page.favicon_url.is_empty())
- dict->SetString(L"faviconUrl", page.favicon_url.spec());
- if (!page.thumbnail_url.is_empty())
- dict->SetString(L"thumbnailUrl", page.thumbnail_url.spec());
-}
-
} // namespace
+// This struct is used when getting the pre-populated pages in case the user
+// hasn't filled up his most visited pages.
+struct MostVisitedHandler::MostVisitedPage {
+ string16 title;
+ GURL url;
+ GURL thumbnail_url;
+ GURL favicon_url;
+};
+
MostVisitedHandler::MostVisitedHandler()
: url_blacklist_(NULL),
pinned_urls_(NULL),
got_first_most_visited_request_(false) {
}
+MostVisitedHandler::~MostVisitedHandler() {
+}
+
DOMMessageHandler* MostVisitedHandler::Attach(DOMUI* dom_ui) {
url_blacklist_ = dom_ui->GetProfile()->GetPrefs()->
GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist);
@@ -118,7 +120,7 @@ void MostVisitedHandler::RegisterMessages() {
NewCallback(this, &MostVisitedHandler::HandleRemovePinnedURL));
}
-void MostVisitedHandler::HandleGetMostVisited(const Value* value) {
+void MostVisitedHandler::HandleGetMostVisited(const ListValue* args) {
if (!got_first_most_visited_request_) {
// If our intial data is already here, return it.
SendPagesValue();
@@ -128,28 +130,21 @@ void MostVisitedHandler::HandleGetMostVisited(const Value* value) {
}
}
-// Set a DictionaryValue |dict| from a MostVisitedURL.
-void SetDictionaryValue(const history::MostVisitedURL& url,
- DictionaryValue& dict) {
- NewTabUI::SetURLTitleAndDirection(&dict, url.title, url.url);
- dict.SetString(L"url", url.url.spec());
- dict.SetString(L"faviconUrl", url.favicon_url.spec());
- // TODO(Nik): Need thumbnailUrl?
- // TODO(Nik): Add pinned and blacklisted URLs.
- dict.SetBoolean(L"pinned", false);
-}
-
void MostVisitedHandler::SendPagesValue() {
if (pages_value_.get()) {
+ history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
FundamentalValue first_run(IsFirstRun());
+ FundamentalValue has_blacklisted_urls(ts->HasBlacklistedItems());
dom_ui_->CallJavascriptFunction(L"mostVisitedPages",
- *(pages_value_.get()), first_run);
+ *(pages_value_.get()),
+ first_run,
+ has_blacklisted_urls);
pages_value_.reset();
}
}
void MostVisitedHandler::StartQueryForMostVisited() {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTopSites)) {
+ if (history::TopSites::IsEnabled()) {
// Use TopSites.
history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
ts->GetMostVisitedURLs(
@@ -176,34 +171,17 @@ void MostVisitedHandler::StartQueryForMostVisited() {
}
}
-void MostVisitedHandler::HandleBlacklistURL(const Value* value) {
- if (!value->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
- return;
- }
- std::string url;
- const ListValue* list = static_cast<const ListValue*>(value);
- if (list->GetSize() == 0 || !list->GetString(0, &url)) {
- NOTREACHED();
- return;
- }
+void MostVisitedHandler::HandleBlacklistURL(const ListValue* args) {
+ std::string url = WideToUTF8(ExtractStringValue(args));
BlacklistURL(GURL(url));
}
-void MostVisitedHandler::HandleRemoveURLsFromBlacklist(const Value* urls) {
- if (!urls->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
- return;
- }
- const ListValue* list = static_cast<const ListValue*>(urls);
- if (list->GetSize() == 0) {
- NOTREACHED();
- return;
- }
+void MostVisitedHandler::HandleRemoveURLsFromBlacklist(const ListValue* args) {
+ DCHECK(args->GetSize() != 0);
- for (ListValue::const_iterator iter = list->begin();
- iter != list->end(); ++iter) {
- std::wstring url;
+ for (ListValue::const_iterator iter = args->begin();
+ iter != args->end(); ++iter) {
+ std::string url;
bool r = (*iter)->GetAsString(&url);
if (!r) {
NOTREACHED();
@@ -211,58 +189,71 @@ void MostVisitedHandler::HandleRemoveURLsFromBlacklist(const Value* urls) {
}
UserMetrics::RecordAction(UserMetricsAction("MostVisited_UrlRemoved"),
dom_ui_->GetProfile());
- r = url_blacklist_->Remove(GetDictionaryKeyForURL(WideToUTF8(url)), NULL);
+ if (history::TopSites::IsEnabled()) {
+ history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
+ ts->RemoveBlacklistedURL(GURL(url));
+ return;
+ }
+
+ r = url_blacklist_->Remove(GetDictionaryKeyForURL(url), NULL);
DCHECK(r) << "Unknown URL removed from the NTP Most Visited blacklist.";
}
}
-void MostVisitedHandler::HandleClearBlacklist(const Value* value) {
+void MostVisitedHandler::HandleClearBlacklist(const ListValue* args) {
UserMetrics::RecordAction(UserMetricsAction("MostVisited_BlacklistCleared"),
dom_ui_->GetProfile());
- url_blacklist_->Clear();
-}
-
-void MostVisitedHandler::HandleAddPinnedURL(const Value* value) {
- if (!value->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
+ if (history::TopSites::IsEnabled()) {
+ history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
+ ts->ClearBlacklistedURLs();
return;
}
- const ListValue* list = static_cast<const ListValue*>(value);
- DCHECK_EQ(5U, list->GetSize()) << "Wrong number of params to addPinnedURL";
+ url_blacklist_->Clear();
+}
+
+void MostVisitedHandler::HandleAddPinnedURL(const ListValue* args) {
+ DCHECK_EQ(5U, args->GetSize()) << "Wrong number of params to addPinnedURL";
MostVisitedPage mvp;
std::string tmp_string;
+ string16 tmp_string16;
int index;
- bool r = list->GetString(0, &tmp_string);
+ bool r = args->GetString(0, &tmp_string);
DCHECK(r) << "Missing URL in addPinnedURL from the NTP Most Visited.";
mvp.url = GURL(tmp_string);
- r = list->GetString(1, &tmp_string);
+ r = args->GetString(1, &tmp_string16);
DCHECK(r) << "Missing title in addPinnedURL from the NTP Most Visited.";
- mvp.title = UTF8ToWide(tmp_string);
+ mvp.title = tmp_string16;
- r = list->GetString(2, &tmp_string);
+ r = args->GetString(2, &tmp_string);
DCHECK(r) << "Failed to read the favicon URL in addPinnedURL from the NTP "
<< "Most Visited.";
if (!tmp_string.empty())
mvp.favicon_url = GURL(tmp_string);
- r = list->GetString(3, &tmp_string);
+ r = args->GetString(3, &tmp_string);
DCHECK(r) << "Failed to read the thumbnail URL in addPinnedURL from the NTP "
<< "Most Visited.";
if (!tmp_string.empty())
mvp.thumbnail_url = GURL(tmp_string);
- r = list->GetString(4, &tmp_string);
+ r = args->GetString(4, &tmp_string);
DCHECK(r) << "Missing index in addPinnedURL from the NTP Most Visited.";
- index = StringToInt(tmp_string);
+ base::StringToInt(tmp_string, &index);
AddPinnedURL(mvp, index);
}
void MostVisitedHandler::AddPinnedURL(const MostVisitedPage& page, int index) {
+ if (history::TopSites::IsEnabled()) {
+ history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
+ ts->AddPinnedURL(page.url, index);
+ return;
+ }
+
// Remove any pinned URL at the given index.
MostVisitedPage old_page;
if (GetPinnedURLAtIndex(index, &old_page)) {
@@ -272,7 +263,7 @@ void MostVisitedHandler::AddPinnedURL(const MostVisitedPage& page, int index) {
DictionaryValue* new_value = new DictionaryValue();
SetMostVisistedPage(new_value, page);
- new_value->SetInteger(L"index", index);
+ new_value->SetInteger("index", index);
pinned_urls_->Set(GetDictionaryKeyForURL(page.url.spec()), new_value);
// TODO(arv): Notify observers?
@@ -280,23 +271,19 @@ void MostVisitedHandler::AddPinnedURL(const MostVisitedPage& page, int index) {
// Don't call HandleGetMostVisited. Let the client call this as needed.
}
-void MostVisitedHandler::HandleRemovePinnedURL(const Value* value) {
- if (!value->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
- return;
- }
-
- const ListValue* list = static_cast<const ListValue*>(value);
- std::string url;
-
- bool r = list->GetString(0, &url);
- DCHECK(r) << "Failed to read the URL to remove from the NTP Most Visited.";
-
+void MostVisitedHandler::HandleRemovePinnedURL(const ListValue* args) {
+ std::string url = WideToUTF8(ExtractStringValue(args));
RemovePinnedURL(GURL(url));
}
void MostVisitedHandler::RemovePinnedURL(const GURL& url) {
- const std::wstring key = GetDictionaryKeyForURL(url.spec());
+ if (history::TopSites::IsEnabled()) {
+ history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
+ ts->RemovePinnedURL(url);
+ return;
+ }
+
+ const std::string key = GetDictionaryKeyForURL(url.spec());
if (pinned_urls_->HasKey(key))
pinned_urls_->Remove(key, NULL);
@@ -316,26 +303,27 @@ bool MostVisitedHandler::GetPinnedURLAtIndex(int index,
Value* value;
if (pinned_urls_->GetWithoutPathExpansion(*it, &value)) {
if (!value->IsType(DictionaryValue::TYPE_DICTIONARY)) {
- NOTREACHED();
+ // Moved on to TopSites and now going back.
+ pinned_urls_->Clear();
return false;
}
int dict_index;
DictionaryValue* dict = static_cast<DictionaryValue*>(value);
- if (dict->GetInteger(L"index", &dict_index) && dict_index == index) {
+ if (dict->GetInteger("index", &dict_index) && dict_index == index) {
// The favicon and thumbnail URLs may be empty.
std::string tmp_string;
- if (dict->GetString(L"faviconUrl", &tmp_string))
+ if (dict->GetString("faviconUrl", &tmp_string))
page->favicon_url = GURL(tmp_string);
- if (dict->GetString(L"thumbnailUrl", &tmp_string))
+ if (dict->GetString("thumbnailUrl", &tmp_string))
page->thumbnail_url = GURL(tmp_string);
- if (dict->GetString(L"url", &tmp_string))
+ if (dict->GetString("url", &tmp_string))
page->url = GURL(tmp_string);
else
return false;
- return dict->GetString(L"title", &page->title);
+ return dict->GetString("title", &page->title);
}
} else {
NOTREACHED() << "DictionaryValue iterators are filthy liars.";
@@ -364,7 +352,6 @@ void MostVisitedHandler::SetPagesValue(std::vector<PageUsageData*>* data) {
size_t pre_populated_index = 0;
const std::vector<MostVisitedPage> pre_populated_pages =
MostVisitedHandler::GetPrePopulatedPages();
- bool add_chrome_store = !HasApps();
while (output_index < kMostVisitedPages) {
bool found = false;
@@ -384,17 +371,17 @@ void MostVisitedHandler::SetPagesValue(std::vector<PageUsageData*>* data) {
mvp.url = page.GetURL();
// Don't include blacklisted or pinned URLs.
- std::wstring key = GetDictionaryKeyForURL(mvp.url.spec());
+ std::string key = GetDictionaryKeyForURL(mvp.url.spec());
if (pinned_urls_->HasKey(key) || url_blacklist_->HasKey(key))
continue;
- mvp.title = UTF16ToWide(page.GetTitle());
+ mvp.title = page.GetTitle();
found = true;
}
while (!found && pre_populated_index < pre_populated_pages.size()) {
mvp = pre_populated_pages[pre_populated_index++];
- std::wstring key = GetDictionaryKeyForURL(mvp.url.spec());
+ std::string key = GetDictionaryKeyForURL(mvp.url.spec());
if (pinned_urls_->HasKey(key) || url_blacklist_->HasKey(key) ||
seen_urls.find(mvp.url) != seen_urls.end())
continue;
@@ -402,79 +389,64 @@ void MostVisitedHandler::SetPagesValue(std::vector<PageUsageData*>* data) {
found = true;
}
- if (!found && add_chrome_store) {
- mvp = GetChromeStorePage();
- std::wstring key = GetDictionaryKeyForURL(mvp.url.spec());
- if (!pinned_urls_->HasKey(key) && !url_blacklist_->HasKey(key) &&
- seen_urls.find(mvp.url) == seen_urls.end()) {
- found = true;
- }
- add_chrome_store = false;
- }
-
if (found) {
// Add fillers as needed.
while (pages_value_->GetSize() < output_index) {
DictionaryValue* filler_value = new DictionaryValue();
- filler_value->SetBoolean(L"filler", true);
+ filler_value->SetBoolean("filler", true);
pages_value_->Append(filler_value);
}
DictionaryValue* page_value = new DictionaryValue();
SetMostVisistedPage(page_value, mvp);
- page_value->SetBoolean(L"pinned", pinned);
+ page_value->SetBoolean("pinned", pinned);
pages_value_->Append(page_value);
most_visited_urls_.push_back(mvp.url);
seen_urls.insert(mvp.url);
}
output_index++;
}
-
- // If we still need to show the Chrome Store go backwards until we find a non
- // pinned item we can replace.
- if (add_chrome_store) {
- MostVisitedPage chrome_store_page = GetChromeStorePage();
- if (seen_urls.find(chrome_store_page.url) != seen_urls.end())
- return;
-
- std::wstring key = GetDictionaryKeyForURL(chrome_store_page.url.spec());
- if (url_blacklist_->HasKey(key))
- return;
-
- for (int i = kMostVisitedPages - 1; i >= 0; --i) {
- GURL url = most_visited_urls_[i];
- std::wstring key = GetDictionaryKeyForURL(url.spec());
- if (!pinned_urls_->HasKey(key)) {
- // Not pinned, replace.
- DictionaryValue* page_value = new DictionaryValue();
- SetMostVisistedPage(page_value, chrome_store_page);
- pages_value_->Set(i, page_value);
- return;
- }
- }
- }
}
-// Converts a MostVisitedURLList into a vector of PageUsageData to be
-// sent to the Javascript side to the New Tab Page.
-// Caller takes ownership of the PageUsageData objects in the vector.
-// NOTE: this doesn't set the thumbnail and favicon, only URL and title.
-static void MakePageUsageDataVector(const history::MostVisitedURLList& data,
- std::vector<PageUsageData*>* result) {
+void MostVisitedHandler::SetPagesValueFromTopSites(
+ const history::MostVisitedURLList& data) {
+ DCHECK(history::TopSites::IsEnabled());
+ pages_value_.reset(new ListValue);
for (size_t i = 0; i < data.size(); i++) {
const history::MostVisitedURL& url = data[i];
- PageUsageData* pud = new PageUsageData(0);
- pud->SetURL(url.url);
- pud->SetTitle(url.title);
- result->push_back(pud);
+ DictionaryValue* page_value = new DictionaryValue();
+ if (url.url.is_empty()) {
+ page_value->SetBoolean("filler", true);
+ pages_value_->Append(page_value);
+ continue;
+ }
+
+ NewTabUI::SetURLTitleAndDirection(page_value,
+ url.title,
+ url.url);
+ if (!url.favicon_url.is_empty())
+ page_value->SetString("faviconUrl", url.favicon_url.spec());
+
+ // Special case for prepopulated pages: thumbnailUrl is different from url.
+ if (url.url.spec() == l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL)) {
+ page_value->SetString("thumbnailUrl",
+ "chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_THUMBNAIL");
+ } else if (url.url.spec() ==
+ l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)) {
+ page_value->SetString("thumbnailUrl",
+ "chrome://theme/IDR_NEWTAB_THEMES_GALLERY_THUMBNAIL");
+ }
+
+ history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
+ if (ts->IsURLPinned(url.url))
+ page_value->SetBoolean("pinned", true);
+ pages_value_->Append(page_value);
}
}
void MostVisitedHandler::OnMostVisitedURLsAvailable(
- const history::MostVisitedURLList& data) {
- ScopedVector<PageUsageData> result;
- MakePageUsageDataVector(data, &result.get());
- SetPagesValue(&(result.get()));
+ history::MostVisitedURLList data) {
+ SetPagesValueFromTopSites(data);
if (got_first_most_visited_request_) {
SendPagesValue();
}
@@ -491,6 +463,18 @@ bool MostVisitedHandler::IsFirstRun() {
}
// static
+void MostVisitedHandler::SetMostVisistedPage(
+ DictionaryValue* dict,
+ const MostVisitedHandler::MostVisitedPage& page) {
+ NewTabUI::SetURLTitleAndDirection(dict, page.title, page.url);
+ if (!page.favicon_url.is_empty())
+ dict->SetString("faviconUrl", page.favicon_url.spec());
+ if (!page.thumbnail_url.is_empty())
+ dict->SetString("thumbnailUrl", page.thumbnail_url.spec());
+}
+
+
+// static
const std::vector<MostVisitedHandler::MostVisitedPage>&
MostVisitedHandler::GetPrePopulatedPages() {
// TODO(arv): This needs to get the data from some configurable place.
@@ -498,15 +482,15 @@ const std::vector<MostVisitedHandler::MostVisitedPage>&
static std::vector<MostVisitedPage> pages;
if (pages.empty()) {
MostVisitedPage welcome_page = {
- l10n_util::GetString(IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE),
- GURL(WideToUTF8(l10n_util::GetString(IDS_CHROME_WELCOME_URL))),
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE),
+ GURL(l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL)),
GURL("chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_THUMBNAIL"),
GURL("chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_FAVICON")};
pages.push_back(welcome_page);
MostVisitedPage gallery_page = {
- l10n_util::GetString(IDS_NEW_TAB_THEMES_GALLERY_PAGE_TITLE),
- GURL(WideToUTF8(l10n_util::GetString(IDS_THEMES_GALLERY_URL))),
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_THEMES_GALLERY_PAGE_TITLE),
+ GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)),
GURL("chrome://theme/IDR_NEWTAB_THEMES_GALLERY_THUMBNAIL"),
GURL("chrome://theme/IDR_NEWTAB_THEMES_GALLERY_FAVICON")};
pages.push_back(gallery_page);
@@ -515,16 +499,6 @@ const std::vector<MostVisitedHandler::MostVisitedPage>&
return pages;
}
-// static
-MostVisitedHandler::MostVisitedPage MostVisitedHandler::GetChromeStorePage() {
- MostVisitedHandler::MostVisitedPage page = {
- l10n_util::GetString(IDS_EXTENSION_WEB_STORE_TITLE),
- google_util::AppendGoogleLocaleParam(GURL(Extension::ChromeStoreURL())),
- GURL("chrome://theme/IDR_NEWTAB_CHROME_STORE_PAGE_THUMBNAIL"),
- GURL("chrome://theme/IDR_NEWTAB_CHROME_STORE_PAGE_FAVICON")};
- return page;
-}
-
void MostVisitedHandler::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -538,17 +512,22 @@ void MostVisitedHandler::Observe(NotificationType type,
}
void MostVisitedHandler::BlacklistURL(const GURL& url) {
+ if (history::TopSites::IsEnabled()) {
+ history::TopSites* ts = dom_ui_->GetProfile()->GetTopSites();
+ ts->AddBlacklistedURL(url);
+ return;
+ }
+
RemovePinnedURL(url);
- std::wstring key = GetDictionaryKeyForURL(url.spec());
+ std::string key = GetDictionaryKeyForURL(url.spec());
if (url_blacklist_->HasKey(key))
return;
url_blacklist_->SetBoolean(key, true);
}
-std::wstring MostVisitedHandler::GetDictionaryKeyForURL(
- const std::string& url) {
- return ASCIIToWide(MD5String(url));
+std::string MostVisitedHandler::GetDictionaryKeyForURL(const std::string& url) {
+ return MD5String(url);
}
// static
@@ -556,11 +535,3 @@ void MostVisitedHandler::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(prefs::kNTPMostVisitedURLsBlacklist);
prefs->RegisterDictionaryPref(prefs::kNTPMostVisitedPinnedURLs);
}
-
-bool MostVisitedHandler::HasApps() const {
- ExtensionsService* service = dom_ui_->GetProfile()->GetExtensionsService();
- if (!service)
- return false;
-
- return service->HasApps();
-}
diff --git a/chrome/browser/dom_ui/most_visited_handler.h b/chrome/browser/dom_ui/most_visited_handler.h
index 507cb7d..92aaa2e 100644
--- a/chrome/browser/dom_ui/most_visited_handler.h
+++ b/chrome/browser/dom_ui/most_visited_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_MOST_VISITED_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_MOST_VISITED_HANDLER_H_
+#pragma once
#include <string>
#include <vector>
@@ -13,9 +14,9 @@
#include "chrome/browser/history/history_types.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "googleurl/src/gurl.h"
class DictionaryValue;
+class GURL;
class ListValue;
class PageUsageData;
class PrefService;
@@ -25,39 +26,31 @@ class Value;
class MostVisitedHandler : public DOMMessageHandler,
public NotificationObserver {
public:
- // This struct is used when getting the pre-populated pages in case the user
- // hasn't filled up his most visited pages.
- struct MostVisitedPage {
- std::wstring title;
- GURL url;
- GURL thumbnail_url;
- GURL favicon_url;
- };
MostVisitedHandler();
- virtual ~MostVisitedHandler() { }
+ virtual ~MostVisitedHandler();
// DOMMessageHandler override and implementation.
virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
virtual void RegisterMessages();
// Callback for the "getMostVisited" message.
- void HandleGetMostVisited(const Value* value);
+ void HandleGetMostVisited(const ListValue* args);
// Callback for the "blacklistURLFromMostVisited" message.
- void HandleBlacklistURL(const Value* url);
+ void HandleBlacklistURL(const ListValue* args);
// Callback for the "removeURLsFromMostVisitedBlacklist" message.
- void HandleRemoveURLsFromBlacklist(const Value* url);
+ void HandleRemoveURLsFromBlacklist(const ListValue* args);
// Callback for the "clearMostVisitedURLsBlacklist" message.
- void HandleClearBlacklist(const Value* url);
+ void HandleClearBlacklist(const ListValue* args);
// Callback for the "addPinnedURL" message.
- void HandleAddPinnedURL(const Value* value);
+ void HandleAddPinnedURL(const ListValue* args);
// Callback for the "removePinnedURL" message.
- void HandleRemovePinnedURL(const Value* value);
+ void HandleRemovePinnedURL(const ListValue* args);
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
@@ -71,6 +64,8 @@ class MostVisitedHandler : public DOMMessageHandler,
static void RegisterUserPrefs(PrefService* prefs);
private:
+ struct MostVisitedPage;
+
// Send a request to the HistoryService to get the most visited pages.
void StartQueryForMostVisited();
@@ -78,18 +73,21 @@ class MostVisitedHandler : public DOMMessageHandler,
void OnSegmentUsageAvailable(CancelableRequestProvider::Handle handle,
std::vector<PageUsageData*>* data);
- // Sets pages_value_ form a vector of URLs.
+ // Sets pages_value_ from a vector of URLs.
void SetPagesValue(std::vector<PageUsageData*>* data);
+ // Sets pages_value_ from a format produced by TopSites.
+ void SetPagesValueFromTopSites(const history::MostVisitedURLList& data);
+
// Callback for TopSites.
- void OnMostVisitedURLsAvailable(const history::MostVisitedURLList& data);
+ void OnMostVisitedURLsAvailable(history::MostVisitedURLList data);
// Puts the passed URL in the blacklist (so it does not show as a thumbnail).
void BlacklistURL(const GURL& url);
// Returns the key used in url_blacklist_ and pinned_urls_ for the passed
// |url|.
- std::wstring GetDictionaryKeyForURL(const std::string& url);
+ std::string GetDictionaryKeyForURL(const std::string& url);
// Gets the page data for a pinned URL at a given index. This returns
// true if found.
@@ -104,12 +102,12 @@ class MostVisitedHandler : public DOMMessageHandler,
// Returns true if we should treat this as the first run of the new tab page.
bool IsFirstRun();
- static const std::vector<MostVisitedPage>& GetPrePopulatedPages();
+ // Adds the fields in the page to the dictionary.
+ static void SetMostVisistedPage(
+ DictionaryValue* dict,
+ const MostVisitedHandler::MostVisitedPage& page);
- static MostVisitedPage GetChromeStorePage();
-
- // Whether we have any apps installed.
- bool HasApps() const;
+ static const std::vector<MostVisitedPage>& GetPrePopulatedPages();
NotificationRegistrar registrar_;
diff --git a/chrome/browser/dom_ui/net_internals_ui.cc b/chrome/browser/dom_ui/net_internals_ui.cc
index 951aef4..9b50165 100644
--- a/chrome/browser/dom_ui/net_internals_ui.cc
+++ b/chrome/browser/dom_ui/net_internals_ui.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/dom_ui/net_internals_ui.h"
#include <algorithm>
-#include <sstream>
#include <string>
#include <utility>
#include <vector>
@@ -14,12 +13,11 @@
#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "base/file_util.h"
-#include "base/file_version_info.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/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
@@ -45,14 +43,23 @@
#include "net/base/sys_addrinfo.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_proxy_client_socket_pool.h"
#include "net/proxy/proxy_service.h"
+#include "net/socket/socks_client_socket_pool.h"
+#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/tcp_client_socket_pool.h"
#include "net/url_request/url_request_context.h"
+#ifdef OS_WIN
+#include "chrome/browser/net/service_providers_win.h"
+#endif
namespace {
// Formats |t| as a decimal number, in milliseconds.
std::string TickCountToString(const base::TimeTicks& t) {
- return Int64ToString((t - base::TimeTicks()).InMilliseconds());
+ return base::Int64ToString((t - base::TimeTicks()).InMilliseconds());
}
// Returns the HostCache for |context|'s primary HostResolver, or NULL if
@@ -79,49 +86,27 @@ disk_cache::Backend* GetDiskCacheBackend(URLRequestContext* context) {
return http_cache->GetCurrentBackend();
}
-// Serializes the specified event to a DictionaryValue.
-Value* EntryToDictionaryValue(net::NetLog::EventType type,
- const base::TimeTicks& time,
- const net::NetLog::Source& source,
- net::NetLog::EventPhase phase,
- net::NetLog::EventParameters* params) {
- DictionaryValue* entry_dict = new DictionaryValue();
-
- // Set the entry time. (Note that we send it as a string since integers
- // might overflow).
- entry_dict->SetString(L"time", TickCountToString(time));
-
- // Set the entry source.
- DictionaryValue* source_dict = new DictionaryValue();
- source_dict->SetInteger(L"id", source.id);
- source_dict->SetInteger(L"type", static_cast<int>(source.type));
- entry_dict->Set(L"source", source_dict);
-
- // Set the event info.
- entry_dict->SetInteger(L"type", static_cast<int>(type));
- entry_dict->SetInteger(L"phase", static_cast<int>(phase));
-
- // Set the event-specific parameters.
- if (params)
- entry_dict->Set(L"params", params->ToValue());
+// Returns the http network session for |context| if there is one.
+// Otherwise, returns NULL.
+net::HttpNetworkSession* GetHttpNetworkSession(URLRequestContext* context) {
+ if (!context->http_transaction_factory())
+ return NULL;
- return entry_dict;
+ return context->http_transaction_factory()->GetSession();
}
Value* ExperimentToValue(const ConnectionTester::Experiment& experiment) {
DictionaryValue* dict = new DictionaryValue();
if (experiment.url.is_valid())
- dict->SetString(L"url", experiment.url.spec());
-
- dict->SetStringFromUTF16(
- L"proxy_settings_experiment",
- ConnectionTester::ProxySettingsExperimentDescription(
- experiment.proxy_settings_experiment));
- dict->SetStringFromUTF16(
- L"host_resolver_experiment",
- ConnectionTester::HostResolverExperimentDescription(
- experiment.host_resolver_experiment));
+ dict->SetString("url", experiment.url.spec());
+
+ dict->SetString("proxy_settings_experiment",
+ ConnectionTester::ProxySettingsExperimentDescription(
+ experiment.proxy_settings_experiment));
+ dict->SetString("host_resolver_experiment",
+ ConnectionTester::HostResolverExperimentDescription(
+ experiment.host_resolver_experiment));
return dict;
}
@@ -186,7 +171,7 @@ class NetInternalsMessageHandler::IOThreadImpl
public ConnectionTester::Delegate {
public:
// Type for methods that can be used as MessageHandler callbacks.
- typedef void (IOThreadImpl::*MessageHandler)(const Value*);
+ typedef void (IOThreadImpl::*MessageHandler)(const ListValue*);
// Creates a proxy for |handler| that will live on the IO thread.
// |handler| is a weak pointer, since it is possible for the DOMMessageHandler
@@ -216,17 +201,21 @@ class NetInternalsMessageHandler::IOThreadImpl
// 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 Value* value);
-
- void OnGetProxySettings(const Value* value);
- void OnReloadProxySettings(const Value* value);
- void OnGetBadProxies(const Value* value);
- void OnClearBadProxies(const Value* value);
- void OnGetHostResolverCache(const Value* value);
- void OnClearHostResolverCache(const Value* value);
- void OnGetPassiveLogEntries(const Value* value);
- void OnStartConnectionTests(const Value* value);
- void OnGetHttpCacheInfo(const Value* value);
+ void OnRendererReady(const ListValue* list);
+
+ void OnGetProxySettings(const ListValue* list);
+ void OnReloadProxySettings(const ListValue* list);
+ void OnGetBadProxies(const ListValue* list);
+ void OnClearBadProxies(const ListValue* list);
+ void OnGetHostResolverCache(const ListValue* list);
+ void OnClearHostResolverCache(const ListValue* list);
+ void OnGetPassiveLogEntries(const ListValue* list);
+ void OnStartConnectionTests(const ListValue* list);
+ void OnGetHttpCacheInfo(const ListValue* list);
+ void OnGetSocketPoolInfo(const ListValue* list);
+#ifdef OS_WIN
+ void OnGetServiceProviders(const ListValue* list);
+#endif
// ChromeNetLog::Observer implementation:
virtual void OnAddEntry(net::NetLog::EventType type,
@@ -248,7 +237,7 @@ class NetInternalsMessageHandler::IOThreadImpl
class CallbackHelper;
// Helper that runs |method| with |arg|, and deletes |arg| on completion.
- void DispatchToMessageHandler(Value* arg, MessageHandler method);
+ void DispatchToMessageHandler(ListValue* arg, MessageHandler method);
// Helper that executes |function_name| in the attached renderer.
// The function takes ownership of |arg|.
@@ -283,20 +272,21 @@ class NetInternalsMessageHandler::IOThreadImpl::CallbackHelper
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
}
- virtual void RunWithParams(const Tuple1<const Value*>& params) {
+ virtual void RunWithParams(const Tuple1<const ListValue*>& params) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// We need to make a copy of the value in order to pass it over to the IO
// thread. We will delete this in IOThreadImpl::DispatchMessageHandler().
- Value* value_copy = params.a ? params.a->DeepCopy() : NULL;
+ ListValue* list_copy = static_cast<ListValue*>(
+ params.a ? params.a->DeepCopy() : NULL);
if (!ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableMethod(instance_.get(),
&IOThreadImpl::DispatchToMessageHandler,
- value_copy, method_))) {
- // Failed posting the task, avoid leaking |value_copy|.
- delete value_copy;
+ list_copy, method_))) {
+ // Failed posting the task, avoid leaking |list_copy|.
+ delete list_copy;
}
}
@@ -406,6 +396,14 @@ void NetInternalsMessageHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback(
"getHttpCacheInfo",
proxy_->CreateCallback(&IOThreadImpl::OnGetHttpCacheInfo));
+ dom_ui_->RegisterMessageCallback(
+ "getSocketPoolInfo",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetSocketPoolInfo));
+#ifdef OS_WIN
+ dom_ui_->RegisterMessageCallback(
+ "getServiceProviders",
+ proxy_->CreateCallback(&IOThreadImpl::OnGetServiceProviders));
+#endif
}
void NetInternalsMessageHandler::CallJavascriptFunction(
@@ -429,7 +427,8 @@ NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
const base::WeakPtr<NetInternalsMessageHandler>& handler,
IOThread* io_thread,
URLRequestContextGetter* context_getter)
- : handler_(handler),
+ : Observer(net::NetLog::LOG_ALL),
+ handler_(handler),
io_thread_(io_thread),
context_getter_(context_getter),
is_observing_log_(false) {
@@ -458,7 +457,7 @@ void NetInternalsMessageHandler::IOThreadImpl::Detach() {
}
void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
- const Value* value) {
+ const ListValue* list) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
DCHECK(!is_observing_log_) << "notifyReady called twice";
@@ -476,8 +475,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
for (size_t i = 0; i < event_types.size(); ++i) {
const char* name = net::NetLog::EventTypeToString(event_types[i]);
- dict->SetInteger(ASCIIToWide(name),
- static_cast<int>(event_types[i]));
+ dict->SetInteger(name, static_cast<int>(event_types[i]));
}
CallJavascriptFunction(L"g_browser.receivedLogEventTypeConstants", dict);
@@ -488,28 +486,23 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
{
DictionaryValue* dict = new DictionaryValue();
- scoped_ptr<FileVersionInfo> version_info(
- chrome::GetChromeVersionInfo());
-
- if (version_info == NULL) {
- DLOG(ERROR) << "Unable to create FileVersionInfo object";
+ 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(L"version", version_info->file_version());
- dict->SetString(L"cl", version_info->last_change());
- dict->SetStringFromUTF16(L"version_mod",
- platform_util::GetVersionStringModifier());
-
- if (version_info->is_official_build()) {
- dict->SetString(L"official",
- l10n_util::GetString(IDS_ABOUT_VERSION_OFFICIAL));
- } else {
- dict->SetString(L"official",
- l10n_util::GetString(IDS_ABOUT_VERSION_UNOFFICIAL));
- }
-
- dict->SetString(L"command_line",
+ 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());
}
@@ -523,7 +516,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
DictionaryValue* dict = new DictionaryValue();
#define LOAD_FLAG(label, value) \
- dict->SetInteger(ASCIIToWide(# label), static_cast<int>(value));
+ dict->SetInteger(# label, static_cast<int>(value));
#include "net/base/load_flags_list.h"
#undef LOAD_FLAG
@@ -536,7 +529,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
DictionaryValue* dict = new DictionaryValue();
#define NET_ERROR(label, value) \
- dict->SetInteger(ASCIIToWide(# label), static_cast<int>(value));
+ dict->SetInteger(# label, static_cast<int>(value));
#include "net/base/net_error_list.h"
#undef NET_ERROR
@@ -548,9 +541,9 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
{
DictionaryValue* dict = new DictionaryValue();
- dict->SetInteger(L"PHASE_BEGIN", net::NetLog::PHASE_BEGIN);
- dict->SetInteger(L"PHASE_END", net::NetLog::PHASE_END);
- dict->SetInteger(L"PHASE_NONE", net::NetLog::PHASE_NONE);
+ dict->SetInteger("PHASE_BEGIN", net::NetLog::PHASE_BEGIN);
+ dict->SetInteger("PHASE_END", net::NetLog::PHASE_END);
+ dict->SetInteger("PHASE_NONE", net::NetLog::PHASE_NONE);
CallJavascriptFunction(L"g_browser.receivedLogEventPhaseConstants", dict);
}
@@ -560,7 +553,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
{
DictionaryValue* dict = new DictionaryValue();
-#define SOURCE_TYPE(label, value) dict->SetInteger(ASCIIToWide(# label), value);
+#define SOURCE_TYPE(label, value) dict->SetInteger(# label, value);
#include "net/base/net_log_source_type_list.h"
#undef SOURCE_TYPE
@@ -589,7 +582,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
// Pass it as a string, since it may be too large to fit in an integer.
CallJavascriptFunction(L"g_browser.receivedTimeTickOffset",
Value::CreateStringValue(
- Int64ToString(tick_to_unix_time_ms)));
+ base::Int64ToString(tick_to_unix_time_ms)));
}
OnGetPassiveLogEntries(NULL);
@@ -597,30 +590,28 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
OnGetBadProxies(NULL);
OnGetHostResolverCache(NULL);
OnGetHttpCacheInfo(NULL);
+ OnGetSocketPoolInfo(NULL);
+#ifdef OS_WIN
+ OnGetServiceProviders(NULL);
+#endif
}
void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
- const Value* value) {
+ const ListValue* list) {
URLRequestContext* context = context_getter_->GetURLRequestContext();
net::ProxyService* proxy_service = context->proxy_service();
- // TODO(eroman): send a dictionary rather than a flat string, so client can do
- // its own presentation.
- std::string settings_string;
-
- if (proxy_service->config_has_been_initialized()) {
- // net::ProxyConfig defines an operator<<.
- std::ostringstream stream;
- stream << proxy_service->config();
- settings_string = stream.str();
- }
+ DictionaryValue* dict = new DictionaryValue();
+ if (proxy_service->fetched_config().is_valid())
+ dict->Set("original", proxy_service->fetched_config().ToValue());
+ if (proxy_service->config().is_valid())
+ dict->Set("effective", proxy_service->config().ToValue());
- CallJavascriptFunction(L"g_browser.receivedProxySettings",
- Value::CreateStringValue(settings_string));
+ CallJavascriptFunction(L"g_browser.receivedProxySettings", dict);
}
void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
- const Value* value) {
+ const ListValue* list) {
URLRequestContext* context = context_getter_->GetURLRequestContext();
context->proxy_service()->ForceReloadProxyConfig();
@@ -629,13 +620,13 @@ void NetInternalsMessageHandler::IOThreadImpl::OnReloadProxySettings(
}
void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
- const Value* value) {
+ const ListValue* list) {
URLRequestContext* context = context_getter_->GetURLRequestContext();
const net::ProxyRetryInfoMap& bad_proxies_map =
context->proxy_service()->proxy_retry_info();
- ListValue* list = new ListValue();
+ ListValue* dict_list = new ListValue();
for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
it != bad_proxies_map.end(); ++it) {
@@ -643,17 +634,17 @@ void NetInternalsMessageHandler::IOThreadImpl::OnGetBadProxies(
const net::ProxyRetryInfo& retry_info = it->second;
DictionaryValue* dict = new DictionaryValue();
- dict->SetString(L"proxy_uri", proxy_uri);
- dict->SetString(L"bad_until", TickCountToString(retry_info.bad_until));
+ dict->SetString("proxy_uri", proxy_uri);
+ dict->SetString("bad_until", TickCountToString(retry_info.bad_until));
- list->Append(dict);
+ dict_list->Append(dict);
}
- CallJavascriptFunction(L"g_browser.receivedBadProxies", list);
+ CallJavascriptFunction(L"g_browser.receivedBadProxies", dict_list);
}
void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
- const Value* value) {
+ const ListValue* list) {
URLRequestContext* context = context_getter_->GetURLRequestContext();
context->proxy_service()->ClearBadProxiesCache();
@@ -662,7 +653,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnClearBadProxies(
}
void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverCache(
- const Value* value) {
+ const ListValue* list) {
net::HostCache* cache =
GetHostResolverCache(context_getter_->GetURLRequestContext());
@@ -674,12 +665,12 @@ void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverCache(
DictionaryValue* dict = new DictionaryValue();
- dict->SetInteger(L"capacity", static_cast<int>(cache->max_entries()));
+ dict->SetInteger("capacity", static_cast<int>(cache->max_entries()));
dict->SetInteger(
- L"ttl_success_ms",
+ "ttl_success_ms",
static_cast<int>(cache->success_entry_ttl().InMilliseconds()));
dict->SetInteger(
- L"ttl_failure_ms",
+ "ttl_failure_ms",
static_cast<int>(cache->failure_entry_ttl().InMilliseconds()));
ListValue* entry_list = new ListValue();
@@ -693,13 +684,13 @@ void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverCache(
DictionaryValue* entry_dict = new DictionaryValue();
- entry_dict->SetString(L"hostname", key.hostname);
- entry_dict->SetInteger(L"address_family",
+ entry_dict->SetString("hostname", key.hostname);
+ entry_dict->SetInteger("address_family",
static_cast<int>(key.address_family));
- entry_dict->SetString(L"expiration", TickCountToString(entry->expiration));
+ entry_dict->SetString("expiration", TickCountToString(entry->expiration));
if (entry->error != net::OK) {
- entry_dict->SetInteger(L"error", entry->error);
+ entry_dict->SetInteger("error", entry->error);
} else {
// Append all of the resolved addresses.
ListValue* address_list = new ListValue();
@@ -709,19 +700,19 @@ void NetInternalsMessageHandler::IOThreadImpl::OnGetHostResolverCache(
net::NetAddressToStringWithPort(current_address)));
current_address = current_address->ai_next;
}
- entry_dict->Set(L"addresses", address_list);
+ entry_dict->Set("addresses", address_list);
}
entry_list->Append(entry_dict);
}
- dict->Set(L"entries", entry_list);
+ dict->Set("entries", entry_list);
CallJavascriptFunction(L"g_browser.receivedHostResolverCache", dict);
}
void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
- const Value* value) {
+ const ListValue* list) {
net::HostCache* cache =
GetHostResolverCache(context_getter_->GetURLRequestContext());
@@ -733,33 +724,31 @@ void NetInternalsMessageHandler::IOThreadImpl::OnClearHostResolverCache(
}
void NetInternalsMessageHandler::IOThreadImpl::OnGetPassiveLogEntries(
- const Value* value) {
+ const ListValue* list) {
ChromeNetLog* net_log = io_thread_->globals()->net_log.get();
PassiveLogCollector::EntryList passive_entries;
net_log->passive_collector()->GetAllCapturedEvents(&passive_entries);
- ListValue* list = new ListValue();
+ ListValue* dict_list = new ListValue();
for (size_t i = 0; i < passive_entries.size(); ++i) {
const PassiveLogCollector::Entry& e = passive_entries[i];
- list->Append(EntryToDictionaryValue(e.type,
- e.time,
- e.source,
- e.phase,
- e.params));
+ dict_list->Append(net::NetLog::EntryToDictionaryValue(e.type,
+ e.time,
+ e.source,
+ e.phase,
+ e.params,
+ false));
}
- CallJavascriptFunction(L"g_browser.receivedPassiveLogEntries", list);
+ CallJavascriptFunction(L"g_browser.receivedPassiveLogEntries", dict_list);
}
void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
- const Value* value) {
+ const ListValue* list) {
// |value| should be: [<URL to test>].
string16 url_str;
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list = static_cast<const ListValue*>(value);
- list->GetStringAsUTF16(0, &url_str);
- }
+ CHECK(list->GetString(0, &url_str));
// Try to fix-up the user provided URL into something valid.
// For example, turn "www.google.com" into "http://www.google.com".
@@ -770,7 +759,7 @@ void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
}
void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
- const Value* value) {
+ const ListValue* list) {
DictionaryValue* info_dict = new DictionaryValue();
DictionaryValue* stats_dict = new DictionaryValue();
@@ -782,16 +771,70 @@ void NetInternalsMessageHandler::IOThreadImpl::OnGetHttpCacheInfo(
std::vector<std::pair<std::string, std::string> > stats;
disk_cache->GetStats(&stats);
for (size_t i = 0; i < stats.size(); ++i) {
- stats_dict->Set(ASCIIToWide(stats[i].first),
+ stats_dict->Set(stats[i].first,
Value::CreateStringValue(stats[i].second));
}
}
- info_dict->Set(L"stats", stats_dict);
+ info_dict->Set("stats", stats_dict);
CallJavascriptFunction(L"g_browser.receivedHttpCacheInfo", info_dict);
}
+void NetInternalsMessageHandler::IOThreadImpl::OnGetSocketPoolInfo(
+ const ListValue* list) {
+ net::HttpNetworkSession* http_network_session =
+ GetHttpNetworkSession(context_getter_->GetURLRequestContext());
+
+ Value* socket_pool_info = NULL;
+ if (http_network_session)
+ socket_pool_info = http_network_session->SocketPoolInfoToValue();
+
+ CallJavascriptFunction(L"g_browser.receivedSocketPoolInfo", socket_pool_info);
+}
+
+#ifdef OS_WIN
+void NetInternalsMessageHandler::IOThreadImpl::OnGetServiceProviders(
+ const ListValue* list) {
+
+ DictionaryValue* service_providers = new DictionaryValue();
+
+ WinsockLayeredServiceProviderList layered_providers;
+ GetWinsockLayeredServiceProviders(&layered_providers);
+ ListValue* layered_provider_list = new ListValue();
+ for (size_t i = 0; i < layered_providers.size(); ++i) {
+ DictionaryValue* service_dict = new DictionaryValue();
+ service_dict->SetString("name", layered_providers[i].name);
+ service_dict->SetInteger("version", layered_providers[i].version);
+ service_dict->SetInteger("chain_length", layered_providers[i].chain_length);
+ service_dict->SetInteger("socket_type", layered_providers[i].socket_type);
+ service_dict->SetInteger("socket_protocol",
+ layered_providers[i].socket_protocol);
+ service_dict->SetString("path", layered_providers[i].path);
+
+ layered_provider_list->Append(service_dict);
+ }
+ service_providers->Set("service_providers", layered_provider_list);
+
+ WinsockNamespaceProviderList namespace_providers;
+ GetWinsockNamespaceProviders(&namespace_providers);
+ ListValue* namespace_list = new ListValue;
+ for (size_t i = 0; i < namespace_providers.size(); ++i) {
+ DictionaryValue* namespace_dict = new DictionaryValue();
+ namespace_dict->SetString("name", namespace_providers[i].name);
+ namespace_dict->SetBoolean("active", namespace_providers[i].active);
+ namespace_dict->SetInteger("version", namespace_providers[i].version);
+ namespace_dict->SetInteger("type", namespace_providers[i].type);
+
+ namespace_list->Append(namespace_dict);
+ }
+ service_providers->Set("namespace_providers", namespace_list);
+
+ CallJavascriptFunction(L"g_browser.receivedServiceProviders",
+ service_providers);
+}
+#endif
+
void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
net::NetLog::EventType type,
const base::TimeTicks& time,
@@ -802,7 +845,8 @@ void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
CallJavascriptFunction(
L"g_browser.receivedLogEntry",
- EntryToDictionaryValue(type, time, source, phase, params));
+ net::NetLog::EntryToDictionaryValue(type, time, source, phase, params,
+ false));
}
void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTestSuite() {
@@ -822,8 +866,8 @@ NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestExperiment(
int result) {
DictionaryValue* dict = new DictionaryValue();
- dict->Set(L"experiment", ExperimentToValue(experiment));
- dict->SetInteger(L"result", result);
+ dict->Set("experiment", ExperimentToValue(experiment));
+ dict->SetInteger("result", result);
CallJavascriptFunction(
L"g_browser.receivedCompletedConnectionTestExperiment",
@@ -838,7 +882,7 @@ NetInternalsMessageHandler::IOThreadImpl::OnCompletedConnectionTestSuite() {
}
void NetInternalsMessageHandler::IOThreadImpl::DispatchToMessageHandler(
- Value* arg, MessageHandler method) {
+ ListValue* arg, MessageHandler method) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
(this->*method)(arg);
delete arg;
diff --git a/chrome/browser/dom_ui/net_internals_ui.h b/chrome/browser/dom_ui/net_internals_ui.h
index f1c210e..3c67963 100644
--- a/chrome/browser/dom_ui/net_internals_ui.h
+++ b/chrome/browser/dom_ui/net_internals_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_NET_INTERNALS_UI_H_
#define CHROME_BROWSER_DOM_UI_NET_INTERNALS_UI_H_
+#pragma once
#include "chrome/browser/dom_ui/dom_ui.h"
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 9b0d0c9..53c008e 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
@@ -6,11 +6,12 @@
#include "app/l10n_util.h"
#include "base/callback.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -110,7 +111,7 @@ void NewTabPageSyncHandler::RegisterMessages() {
NewCallback(this, &NewTabPageSyncHandler::HandleSyncLinkClicked));
}
-void NewTabPageSyncHandler::HandleGetSyncMessage(const Value* value) {
+void NewTabPageSyncHandler::HandleGetSyncMessage(const ListValue* args) {
waiting_for_initial_page_load_ = false;
BuildAndSendSyncStatus();
}
@@ -147,7 +148,7 @@ void NewTabPageSyncHandler::BuildAndSendSyncStatus() {
UTF16ToUTF8(status_msg), UTF16ToUTF8(link_text));
}
-void NewTabPageSyncHandler::HandleSyncLinkClicked(const Value* value) {
+void NewTabPageSyncHandler::HandleSyncLinkClicked(const ListValue* args) {
DCHECK(!waiting_for_initial_page_load_);
DCHECK(sync_service_);
if (!sync_service_->IsSyncEnabled())
@@ -156,19 +157,25 @@ void NewTabPageSyncHandler::HandleSyncLinkClicked(const Value* value) {
if (sync_service_->GetAuthError().state() ==
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
sync_service_->GetAuthError().state() ==
- GoogleServiceAuthError::CAPTCHA_REQUIRED) {
+ GoogleServiceAuthError::CAPTCHA_REQUIRED ||
+ sync_service_->GetAuthError().state() ==
+ GoogleServiceAuthError::ACCOUNT_DELETED ||
+ sync_service_->GetAuthError().state() ==
+ GoogleServiceAuthError::ACCOUNT_DISABLED ||
+ sync_service_->GetAuthError().state() ==
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
sync_service_->ShowLoginDialog(NULL);
return;
}
DictionaryValue value;
- value.SetString(L"syncEnabledMessage",
- l10n_util::GetStringF(IDS_SYNC_NTP_SYNCED_TO,
- UTF16ToWide(sync_service_->GetAuthenticatedUsername())));
+ value.SetString("syncEnabledMessage",
+ l10n_util::GetStringFUTF16(IDS_SYNC_NTP_SYNCED_TO,
+ sync_service_->GetAuthenticatedUsername()));
dom_ui_->CallJavascriptFunction(L"syncAlreadyEnabled", value);
} else {
// User clicked the 'Start now' link to begin syncing.
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_NTP);
- sync_service_->EnableForUser(NULL);
+ sync_service_->ShowLoginDialog(NULL);
}
}
@@ -183,36 +190,35 @@ void NewTabPageSyncHandler::SendSyncMessageToPage(
MessageType type, std::string msg,
std::string linktext) {
DictionaryValue value;
- std::wstring user;
+ std::string user;
std::string title;
std::string linkurl;
// If there is no message to show, we should hide the sync section
// altogether.
if (type == HIDE || msg.empty()) {
- value.SetBoolean(L"syncsectionisvisible", false);
+ value.SetBoolean("syncsectionisvisible", false);
} else { // type == SYNC_ERROR
- title = WideToUTF8(
- l10n_util::GetString(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE));
+ title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE);
- value.SetBoolean(L"syncsectionisvisible", true);
- value.SetString(L"msg", msg);
- value.SetString(L"title", title);
+ value.SetBoolean("syncsectionisvisible", true);
+ value.SetString("msg", msg);
+ value.SetString("title", title);
if (linktext.empty()) {
- value.SetBoolean(L"linkisvisible", false);
+ value.SetBoolean("linkisvisible", false);
} else {
- value.SetBoolean(L"linkisvisible", true);
- value.SetString(L"linktext", linktext);
+ value.SetBoolean("linkisvisible", true);
+ value.SetString("linktext", linktext);
// The only time we set the URL is when the user is synced and we need to
// show a link to a web interface (e.g. http://docs.google.com). When we
// set that URL, HandleSyncLinkClicked won't be called when the user
// clicks on the link.
if (linkurl.empty()) {
- value.SetBoolean(L"linkurlisset", false);
+ value.SetBoolean("linkurlisset", false);
} else {
- value.SetBoolean(L"linkurlisset", true);
- value.SetString(L"linkurl", linkurl);
+ value.SetBoolean("linkurlisset", true);
+ value.SetString("linkurl", linkurl);
}
}
}
diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.h b/chrome/browser/dom_ui/new_tab_page_sync_handler.h
index fcd2a7a..9db005b 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.h
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_NEW_TAB_PAGE_SYNC_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_NEW_TAB_PAGE_SYNC_HANDLER_H_
+#pragma once
#include <string>
@@ -11,7 +12,7 @@
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_ui_util.h"
-class Value;
+class ListValue;
// Sends sync-state changes to the New Tab Page for UI updating and forwards
// link clicks on the page to the sync service.
@@ -26,9 +27,9 @@ class NewTabPageSyncHandler : public DOMMessageHandler,
virtual void RegisterMessages();
// Callback for "GetSyncMessage".
- void HandleGetSyncMessage(const Value* value);
+ void HandleGetSyncMessage(const ListValue* args);
// Callback for "SyncLinkClicked".
- void HandleSyncLinkClicked(const Value* value);
+ void HandleSyncLinkClicked(const ListValue* args);
// ProfileSyncServiceObserver
virtual void OnStateChanged();
diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc
index d367db3..7438d80 100644
--- a/chrome/browser/dom_ui/new_tab_ui.cc
+++ b/chrome/browser/dom_ui/new_tab_ui.cc
@@ -14,37 +14,36 @@
#include "base/histogram.h"
#include "base/i18n/rtl.h"
#include "base/singleton.h"
+#include "base/string_number_conversions.h"
#include "base/thread.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/app_launcher_handler.h"
#include "chrome/browser/dom_ui/dom_ui_theme_source.h"
+#include "chrome/browser/dom_ui/foreign_session_handler.h"
#include "chrome/browser/dom_ui/most_visited_handler.h"
#include "chrome/browser/dom_ui/new_tab_page_sync_handler.h"
#include "chrome/browser/dom_ui/ntp_resource_cache.h"
#include "chrome/browser/dom_ui/shown_sections_handler.h"
#include "chrome/browser/dom_ui/tips_handler.h"
-#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/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"
+#include "chrome/browser/sessions/tab_restore_service_observer.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.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
-
-#if defined(OS_WIN)
-#include "chrome/browser/views/importer_view.h"
-#include "views/window/window.h"
-#endif
+#include "grit/theme_resources.h"
namespace {
@@ -56,8 +55,8 @@ const int kSearchURLs = 3;
// Strings sent to the page via jstemplates used to set the direction of the
// HTML document based on locale.
-const wchar_t kRTLHtmlTextDirection[] = L"rtl";
-const wchar_t kDefaultHtmlTextDirection[] = L"ltr";
+const char kRTLHtmlTextDirection[] = "rtl";
+const char kDefaultHtmlTextDirection[] = "ltr";
////////////////////////////////////////////////////////////////////////////////
// PaintTimer
@@ -80,6 +79,8 @@ class PaintTimer : public RenderWidgetHost::PaintObserver {
}
// A callback that is invoked whenever our RenderWidgetHost paints.
+ virtual void RenderWidgetHostWillPaint(RenderWidgetHost* rhw) {}
+
virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh) {
last_paint_ = base::TimeTicks::Now();
}
@@ -124,7 +125,7 @@ class PaintTimer : public RenderWidgetHost::PaintObserver {
// RecentlyClosedTabsHandler
class RecentlyClosedTabsHandler : public DOMMessageHandler,
- public TabRestoreService::Observer {
+ public TabRestoreServiceObserver {
public:
RecentlyClosedTabsHandler() : tab_restore_service_(NULL) {}
virtual ~RecentlyClosedTabsHandler();
@@ -135,12 +136,12 @@ class RecentlyClosedTabsHandler : public DOMMessageHandler,
// Callback for the "reopenTab" message. Rewrites the history of the
// currently displayed tab to be the one in TabRestoreService with a
// history of a session passed in through the content pointer.
- void HandleReopenTab(const Value* content);
+ void HandleReopenTab(const ListValue* args);
// Callback for the "getRecentlyClosedTabs" message.
- void HandleGetRecentlyClosedTabs(const Value* content);
+ void HandleGetRecentlyClosedTabs(const ListValue* args);
- // Observer callback for TabRestoreService::Observer. Sends data on
+ // Observer callback for TabRestoreServiceObserver. Sends data on
// recently closed tabs to the javascript side of this page to
// display to the user.
virtual void TabRestoreServiceChanged(TabRestoreService* service);
@@ -164,7 +165,7 @@ class RecentlyClosedTabsHandler : public DOMMessageHandler,
// tab was already in the list, true if it was absent. A tab is
// considered unique if no other tab shares both its title and its url.
bool EnsureTabIsUnique(const DictionaryValue* tab,
- std::set<std::wstring>& unique_items);
+ std::set<std::string>* unique_items);
// TabRestoreService that we are observing.
TabRestoreService* tab_restore_service_;
@@ -185,38 +186,21 @@ RecentlyClosedTabsHandler::~RecentlyClosedTabsHandler() {
tab_restore_service_->RemoveObserver(this);
}
-void RecentlyClosedTabsHandler::HandleReopenTab(const Value* content) {
+void RecentlyClosedTabsHandler::HandleReopenTab(const ListValue* args) {
Browser* browser = Browser::GetBrowserForController(
&dom_ui_->tab_contents()->controller(), NULL);
if (!browser)
return;
- // Extract the integer value of the tab session to restore from the
- // incoming string array. This will be greatly simplified when
- // DOMUIBindings::send() is generalized to all data types instead of
- // silently failing when passed anything other then an array of
- // strings.
- if (content->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(content);
- Value* list_member;
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- std::wstring wstring_value;
- if (string_value->GetAsString(&wstring_value)) {
- int session_to_restore = StringToInt(WideToUTF16Hack(wstring_value));
- tab_restore_service_->RestoreEntryById(browser, session_to_restore,
- true);
- // The current tab has been nuked at this point; don't touch any member
- // variables.
- }
- }
- }
+ int session_to_restore;
+ if (ExtractIntegerValue(args, &session_to_restore))
+ tab_restore_service_->RestoreEntryById(browser, session_to_restore, true);
+ // The current tab has been nuked at this point; don't touch any member
+ // variables.
}
void RecentlyClosedTabsHandler::HandleGetRecentlyClosedTabs(
- const Value* content) {
+ const ListValue* args) {
if (!tab_restore_service_) {
tab_restore_service_ = dom_ui_->GetProfile()->GetTabRestoreService();
@@ -239,7 +223,7 @@ void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
TabRestoreService* service) {
const TabRestoreService::Entries& entries = service->entries();
ListValue list_value;
- std::set<std::wstring> unique_items;
+ std::set<std::string> unique_items;
int added_count = 0;
const int max_count = 10;
@@ -252,11 +236,11 @@ void RecentlyClosedTabsHandler::TabRestoreServiceChanged(
DictionaryValue* value = new DictionaryValue();
if ((entry->type == TabRestoreService::TAB &&
TabToValue(*static_cast<TabRestoreService::Tab*>(entry), value) &&
- EnsureTabIsUnique(value, unique_items)) ||
+ EnsureTabIsUnique(value, &unique_items)) ||
(entry->type == TabRestoreService::WINDOW &&
WindowToValue(*static_cast<TabRestoreService::Window*>(entry),
value))) {
- value->SetInteger(L"sessionId", entry->id);
+ value->SetInteger("sessionId", entry->id);
list_value.Append(value);
added_count++;
} else {
@@ -284,8 +268,8 @@ bool RecentlyClosedTabsHandler::TabToValue(
NewTabUI::SetURLTitleAndDirection(dictionary, current_navigation.title(),
current_navigation.virtual_url());
- dictionary->SetString(L"type", L"tab");
- dictionary->SetReal(L"timestamp", tab.timestamp.ToDoubleT());
+ dictionary->SetString("type", "tab");
+ dictionary->SetReal("timestamp", tab.timestamp.ToDoubleT());
return true;
}
@@ -310,23 +294,27 @@ bool RecentlyClosedTabsHandler::WindowToValue(
return false;
}
- dictionary->SetString(L"type", L"window");
- dictionary->SetReal(L"timestamp", window.timestamp.ToDoubleT());
- dictionary->Set(L"tabs", tab_values);
+ dictionary->SetString("type", "window");
+ dictionary->SetReal("timestamp", window.timestamp.ToDoubleT());
+ dictionary->Set("tabs", tab_values);
return true;
}
-bool RecentlyClosedTabsHandler::EnsureTabIsUnique(const DictionaryValue* tab,
- std::set<std::wstring>& unique_items) {
- std::wstring title;
- std::wstring url;
- if (tab->GetString(L"title", &title) &&
- tab->GetString(L"url", &url)) {
- std::wstring unique_key = title + url;
- if (unique_items.find(unique_key) != unique_items.end())
+bool RecentlyClosedTabsHandler::EnsureTabIsUnique(
+ const DictionaryValue* tab,
+ std::set<std::string>* unique_items) {
+ DCHECK(unique_items);
+ std::string title;
+ std::string url;
+ if (tab->GetString("title", &title) &&
+ tab->GetString("url", &url)) {
+ // TODO(viettrungluu): this isn't obviously reliable, since different
+ // combinations of titles/urls may conceivably yield the same string.
+ std::string unique_key = title + url;
+ if (unique_items->find(unique_key) != unique_items->end())
return false;
else
- unique_items.insert(unique_key);
+ unique_items->insert(unique_key);
}
return true;
}
@@ -350,10 +338,10 @@ class MetricsHandler : public DOMMessageHandler {
virtual void RegisterMessages();
// Callback which records a user action.
- void HandleMetrics(const Value* content);
+ void HandleMetrics(const ListValue* args);
// Callback for the "logEventTime" message.
- void HandleLogEventTime(const Value* content);
+ void HandleLogEventTime(const ListValue* args);
private:
@@ -368,35 +356,14 @@ void MetricsHandler::RegisterMessages() {
NewCallback(this, &MetricsHandler::HandleLogEventTime));
}
-void MetricsHandler::HandleMetrics(const Value* content) {
- if (content && content->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(content);
- Value* list_member;
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- std::wstring wstring_value;
- if (string_value->GetAsString(&wstring_value)) {
- UserMetrics::RecordComputedAction(WideToASCII(wstring_value),
- dom_ui_->GetProfile());
- }
- }
- }
+void MetricsHandler::HandleMetrics(const ListValue* args) {
+ std::string string_action = WideToUTF8(ExtractStringValue(args));
+ UserMetrics::RecordComputedAction(string_action, dom_ui_->GetProfile());
}
-void MetricsHandler::HandleLogEventTime(const Value* content) {
- if (content && content->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(content);
- Value* list_member;
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- std::string event_name;
- if (list_member->GetAsString(&event_name)) {
- dom_ui_->tab_contents()->LogNewTabTime(event_name);
- }
- }
- }
+void MetricsHandler::HandleLogEventTime(const ListValue* args) {
+ std::string event_name = WideToUTF8(ExtractStringValue(args));
+ dom_ui_->tab_contents()->LogNewTabTime(event_name);
}
///////////////////////////////////////////////////////////////////////////////
@@ -413,7 +380,7 @@ class NewTabPageSetHomePageHandler : public DOMMessageHandler {
virtual void RegisterMessages();
// Callback for "setHomePage".
- void HandleSetHomePage(const Value* value);
+ void HandleSetHomePage(const ListValue* args);
private:
@@ -426,54 +393,17 @@ void NewTabPageSetHomePageHandler::RegisterMessages() {
}
void NewTabPageSetHomePageHandler::HandleSetHomePage(
- const Value* value) {
+ const ListValue* args) {
dom_ui_->GetProfile()->GetPrefs()->SetBoolean(prefs::kHomePageIsNewTabPage,
true);
ListValue list_value;
list_value.Append(new StringValue(
- l10n_util::GetString(IDS_NEW_TAB_HOME_PAGE_SET_NOTIFICATION)));
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_HOME_PAGE_SET_NOTIFICATION)));
list_value.Append(new StringValue(
- l10n_util::GetString(IDS_NEW_TAB_HOME_PAGE_HIDE_NOTIFICATION)));
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_HOME_PAGE_HIDE_NOTIFICATION)));
dom_ui_->CallJavascriptFunction(L"onHomePageSet", list_value);
}
-///////////////////////////////////////////////////////////////////////////////
-// NewTabPageImportBookmarksHandler
-class NewTabPageImportBookmarksHandler : public DOMMessageHandler {
- public:
- NewTabPageImportBookmarksHandler() {}
- virtual ~NewTabPageImportBookmarksHandler() {}
-
- // DOMMessageHandler implementation.
- virtual void RegisterMessages();
-
- // Callback for "importBookmarks".
- void HandleImportBookmarks(const Value* value);
- private:
-
- DISALLOW_COPY_AND_ASSIGN(NewTabPageImportBookmarksHandler);
-};
-
-void NewTabPageImportBookmarksHandler::RegisterMessages() {
- dom_ui_->RegisterMessageCallback("importBookmarks", NewCallback(
- this, &NewTabPageImportBookmarksHandler::HandleImportBookmarks));
-}
-
-void NewTabPageImportBookmarksHandler::HandleImportBookmarks(
- const Value* value) {
- Browser* browser = NULL;
- TabContentsDelegate* delegate = dom_ui_->tab_contents()->delegate();
- if (delegate)
- browser = delegate->GetBrowser();
- DCHECK(browser);
-#if defined(OS_WIN)
- views::Window::CreateChromeWindow(
- browser->window()->GetNativeHandle(),
- gfx::Rect(),
- new ImporterView(dom_ui_->GetProfile(), importer::FAVORITES))->Show();
-#endif
-}
-
} // namespace
///////////////////////////////////////////////////////////////////////////////
@@ -484,10 +414,9 @@ NewTabUI::NewTabUI(TabContents* contents)
// Override some options on the DOM UI.
hide_favicon_ = true;
force_bookmark_bar_visible_ = true;
- force_extension_shelf_visible_ = true;
focus_location_bar_by_default_ = true;
should_hide_url_ = true;
- overridden_title_ = WideToUTF16Hack(l10n_util::GetString(IDS_NEW_TAB_TITLE));
+ overridden_title_ = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
// We count all link clicks as AUTO_BOOKMARK, so that site can be ranked more
// highly. Note this means we're including clicks on not only most visited
@@ -499,21 +428,17 @@ NewTabUI::NewTabUI(TabContents* contents)
static bool first_view = true;
if (first_view) {
- Profile* profile = GetProfile();
- profile->GetPrefs()->SetInteger(prefs::kNTPPromoViewsRemaining,
- profile->GetPrefs()->GetInteger(prefs::kNTPPromoViewsRemaining) - 1);
- profile->GetBookmarkModel()->AddObserver(this);
first_view = false;
}
if (!GetProfile()->IsOffTheRecord()) {
PrefService* pref_service = GetProfile()->GetPrefs();
AddMessageHandler((new ShownSectionsHandler(pref_service))->Attach(this));
+ AddMessageHandler((new browser_sync::ForeignSessionHandler())->
+ Attach(this));
AddMessageHandler((new MostVisitedHandler())->Attach(this));
AddMessageHandler((new RecentlyClosedTabsHandler())->Attach(this));
AddMessageHandler((new MetricsHandler())->Attach(this));
- if (WebResourcesEnabled())
- AddMessageHandler((new TipsHandler())->Attach(this));
if (GetProfile()->IsSyncAccessible())
AddMessageHandler((new NewTabPageSyncHandler())->Attach(this));
if (Extension::AppsAreEnabled()) {
@@ -525,7 +450,6 @@ NewTabUI::NewTabUI(TabContents* contents)
}
AddMessageHandler((new NewTabPageSetHomePageHandler())->Attach(this));
- AddMessageHandler((new NewTabPageImportBookmarksHandler())->Attach(this));
}
// Initializing the CSS and HTML can require some CPU, so do it after
@@ -550,9 +474,6 @@ NewTabUI::NewTabUI(TabContents* contents)
}
NewTabUI::~NewTabUI() {
- BookmarkModel* bookmark_model = GetProfile()->GetBookmarkModel();
- if (bookmark_model)
- bookmark_model->RemoveObserver(this);
}
void NewTabUI::RenderViewCreated(RenderViewHost* render_view_host) {
@@ -563,20 +484,17 @@ void NewTabUI::RenderViewReused(RenderViewHost* render_view_host) {
render_view_host->set_paint_observer(new PaintTimer);
}
-void NewTabUI::BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index) {
- // Stop showing the promo, and no longer observe the bookmark model.
- GetProfile()->GetPrefs()->SetInteger(prefs::kNTPPromoViewsRemaining, 0);
- GetProfile()->GetBookmarkModel()->RemoveObserver(this);
-}
-
void NewTabUI::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (NotificationType::BROWSER_THEME_CHANGED == type) {
InitializeCSSCaches();
- CallJavascriptFunction(L"themeChanged");
+ ListValue args;
+ args.Append(Value::CreateStringValue(
+ GetProfile()->GetThemeProvider()->HasCustomImage(
+ IDR_THEME_NTP_ATTRIBUTION) ?
+ "true" : "false"));
+ CallJavascriptFunction(L"themeChanged", args);
} else if (NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED) {
if (GetProfile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar))
CallJavascriptFunction(L"bookmarkBarAttached");
@@ -641,16 +559,13 @@ bool NewTabUI::FirstRunDisabled() {
void NewTabUI::SetURLTitleAndDirection(DictionaryValue* dictionary,
const string16& title,
const GURL& gurl) {
- std::wstring wstring_url = UTF8ToWide(gurl.spec());
- dictionary->SetString(L"url", wstring_url);
-
- std::wstring wstring_title = UTF16ToWide(title);
+ dictionary->SetString("url", gurl.spec());
bool using_url_as_the_title = false;
- std::wstring title_to_set(wstring_title);
+ string16 title_to_set(title);
if (title_to_set.empty()) {
using_url_as_the_title = true;
- title_to_set = wstring_url;
+ title_to_set = UTF8ToUTF16(gurl.spec());
}
// We set the "dir" attribute of the title, so that in RTL locales, a LTR
@@ -673,12 +588,12 @@ void NewTabUI::SetURLTitleAndDirection(DictionaryValue* dictionary,
// entire title within a tooltip when the mouse is over the title link.. For
// example, without LRE-PDF pair, the title "Yahoo!" will be rendered as
// "!Yahoo" within the tooltip when the mouse is over the title link.
- std::wstring direction = kDefaultHtmlTextDirection;
+ std::string direction = kDefaultHtmlTextDirection;
if (base::i18n::IsRTL()) {
if (using_url_as_the_title) {
base::i18n::WrapStringWithLTRFormatting(&title_to_set);
} else {
- if (base::i18n::StringContainsStrongRTLChars(wstring_title)) {
+ if (base::i18n::StringContainsStrongRTLChars(title)) {
base::i18n::WrapStringWithRTLFormatting(&title_to_set);
direction = kRTLHtmlTextDirection;
} else {
@@ -686,8 +601,8 @@ void NewTabUI::SetURLTitleAndDirection(DictionaryValue* dictionary,
}
}
}
- dictionary->SetString(L"title", title_to_set);
- dictionary->SetString(L"direction", direction);
+ dictionary->SetString("title", title_to_set);
+ dictionary->SetString("direction", direction);
}
///////////////////////////////////////////////////////////////////////////////
@@ -717,3 +632,7 @@ void NewTabUI::NewTabHTMLSource::StartDataRequest(const std::string& path,
SendResponse(request_id, html_bytes);
}
+
+std::string NewTabUI::NewTabHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h
index 7598764..35e2a87 100644
--- a/chrome/browser/dom_ui/new_tab_ui.h
+++ b/chrome/browser/dom_ui/new_tab_ui.h
@@ -4,13 +4,14 @@
#ifndef CHROME_BROWSER_DOM_UI_NEW_TAB_UI_H_
#define CHROME_BROWSER_DOM_UI_NEW_TAB_UI_H_
+#pragma once
#include <string>
#include "base/gtest_prod_util.h"
-#include "chrome/browser/bookmarks/bookmark_model_observer.h"
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class GURL;
@@ -20,8 +21,7 @@ class Profile;
// The TabContents used for the New Tab page.
class NewTabUI : public DOMUI,
- public NotificationObserver,
- public BookmarkModelObserver {
+ public NotificationObserver {
public:
explicit NewTabUI(TabContents* manager);
~NewTabUI();
@@ -31,29 +31,6 @@ class NewTabUI : public DOMUI,
virtual void RenderViewCreated(RenderViewHost* render_view_host);
virtual void RenderViewReused(RenderViewHost* render_view_host);
- // Overridden from BookmarkModelObserver so we can remove the promo for
- // importing bookmarks if the user adds a bookmark in any way.
- virtual void BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index);
-
- // These methods must be overridden so that the NTP can be a
- // 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 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) {}
-
static void RegisterUserPrefs(PrefService* prefs);
static void MigrateUserPrefs(PrefService* prefs, int old_pref_version,
int new_pref_version);
@@ -84,16 +61,14 @@ class NewTabUI : public DOMUI,
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;
// Setters and getters for first_run.
static void set_first_run(bool first_run) { first_run_ = first_run; }
static bool first_run() { return first_run_; }
private:
- ~NewTabHTMLSource() {}
+ virtual ~NewTabHTMLSource() {}
// Whether this is the first run.
static bool first_run_;
@@ -121,7 +96,7 @@ class NewTabUI : public DOMUI,
NotificationRegistrar registrar_;
// The preference version. This used for migrating prefs of the NTP.
- static const int current_pref_version_ = 2;
+ static const int current_pref_version_ = 3;
DISALLOW_COPY_AND_ASSIGN(NewTabUI);
};
diff --git a/chrome/browser/dom_ui/new_tab_ui_uitest.cc b/chrome/browser/dom_ui/new_tab_ui_uitest.cc
index e2a3368..a00e8e1 100644
--- a/chrome/browser/dom_ui/new_tab_ui_uitest.cc
+++ b/chrome/browser/dom_ui/new_tab_ui_uitest.cc
@@ -4,11 +4,10 @@
#include "chrome/test/ui/ui_test.h"
-#include "base/file_path.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
-#include "chrome/browser/pref_value_store.h"
+#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
@@ -22,7 +21,7 @@ class NewTabUITest : public UITest {
dom_automation_enabled_ = true;
// Set home page to the empty string so that we can set the home page using
// preferences.
- homepage_ = L"";
+ homepage_ = "";
// Setup the DEFAULT_THEME profile (has fake history entries).
set_template_user_data(UITest::ComputeTypicalUserDataSource(
@@ -41,14 +40,14 @@ TEST_F(NewTabUITest, NTPHasThumbnails) {
int load_time;
ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));
- // Blank thumbnails on the NTP have the class 'filler' applied to the div.
- // If all the thumbnails load, there should be no div's with 'filler'.
scoped_refptr<TabProxy> tab = window->GetActiveTab();
ASSERT_TRUE(tab.get());
+ // TopSites should return at least 3 non-filler pages.
+ // 8 - 3 = max 5 filler pages.
ASSERT_TRUE(WaitUntilJavaScriptCondition(tab, L"",
L"window.domAutomationController.send("
- L"document.getElementsByClassName('filler').length == 0)",
+ L"document.getElementsByClassName('filler').length <= 5)",
action_max_timeout_ms()));
}
@@ -73,7 +72,8 @@ TEST_F(NewTabUITest, FLAKY_ChromeInternalLoadsNTP) {
EXPECT_GT(thumbnails_count, 0);
}
-TEST_F(NewTabUITest, UpdateUserPrefsVersion) {
+// Flaky on XP bots: http://crbug.com/51726
+TEST_F(NewTabUITest, FLAKY_UpdateUserPrefsVersion) {
// PrefService with JSON user-pref file only, no enforced or advised prefs.
scoped_ptr<PrefService> prefs(new TestingPrefService);
@@ -95,70 +95,3 @@ TEST_F(NewTabUITest, UpdateUserPrefsVersion) {
migrated = NewTabUI::UpdateUserPrefsVersion(prefs.get());
ASSERT_FALSE(migrated);
}
-
-TEST_F(NewTabUITest, HomePageLink) {
- scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
- ASSERT_TRUE(browser.get());
-
- ASSERT_TRUE(
- browser->SetBooleanPreference(prefs::kHomePageIsNewTabPage, false));
-
- // Bring up a new tab page.
- ASSERT_TRUE(browser->RunCommand(IDC_NEW_TAB));
- int load_time;
- ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));
-
- scoped_refptr<TabProxy> tab = browser->GetActiveTab();
- ASSERT_TRUE(tab.get());
-
- // TODO(arv): Extract common patterns for doing js testing.
-
- // Fire click. Because tip service is turned off for testing, we first
- // force the "make this my home page" tip to appear.
- // TODO(arv): Find screen position of element and use a lower level click
- // emulation.
- bool result;
- ASSERT_TRUE(tab->ExecuteAndExtractBool(L"",
- L"window.domAutomationController.send("
- L"(function() {"
- L" tipCache = [{\"set_homepage_tip\":\"Make this the home page\"}];"
- L" renderTip();"
- L" var e = document.createEvent('Event');"
- L" e.initEvent('click', true, true);"
- L" var el = document.querySelector('#tip-line > button');"
- L" el.dispatchEvent(e);"
- L" return true;"
- L"})()"
- L")",
- &result));
- ASSERT_TRUE(result);
-
- // Make sure text of "set as home page" tip has been removed.
- std::wstring tip_text_content;
- ASSERT_TRUE(tab->ExecuteAndExtractString(L"",
- L"window.domAutomationController.send("
- L"(function() {"
- L" var el = document.querySelector('#tip-line');"
- L" return el.textContent;"
- L"})()"
- L")",
- &tip_text_content));
- ASSERT_EQ(L"", tip_text_content);
-
- // Make sure that the notification is visible
- bool has_class;
- ASSERT_TRUE(tab->ExecuteAndExtractBool(L"",
- L"window.domAutomationController.send("
- L"(function() {"
- L" var el = document.querySelector('#notification');"
- L" return el.classList.contains('show');"
- L"})()"
- L")",
- &has_class));
- ASSERT_TRUE(has_class);
-
- bool is_home_page;
- ASSERT_TRUE(browser->GetBooleanPreference(prefs::kHomePageIsNewTabPage,
- &is_home_page));
- ASSERT_TRUE(is_home_page);
-}
diff --git a/chrome/browser/dom_ui/ntp_resource_cache.cc b/chrome/browser/dom_ui/ntp_resource_cache.cc
index e9f046d..377d3eb 100644
--- a/chrome/browser/dom_ui/ntp_resource_cache.cc
+++ b/chrome/browser/dom_ui/ntp_resource_cache.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.
@@ -11,17 +11,20 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/theme_provider.h"
-#include "base/command_line.h"
#include "base/file_util.h"
#include "base/ref_counted_memory.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
-#include "chrome/browser/google_util.h"
-#include "chrome/browser/pref_service.h"
+#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/themes/browser_theme_provider.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -45,6 +48,8 @@
#include "chrome/browser/gtk/bookmark_bar_gtk.h"
#endif
+using base::Time;
+
namespace {
// The URL for the the Learn More page shown on incognito new tab.
@@ -59,8 +64,8 @@ const char kSyncServiceHelpUrl[] =
const char kHelpContentUrl[] =
"http://www.google.com/support/chrome/";
-std::wstring GetUrlWithLang(const GURL& url) {
- return ASCIIToWide(google_util::AppendGoogleLocaleParam(url).spec());
+string16 GetUrlWithLang(const GURL& url) {
+ return ASCIIToUTF16(google_util::AppendGoogleLocaleParam(url).spec());
}
std::string SkColorToRGBAString(SkColor color) {
@@ -68,7 +73,7 @@ std::string SkColorToRGBAString(SkColor color) {
// locale specific formatters (e.g., use , instead of . in German).
return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color),
- DoubleToString(SkColorGetA(color) / 255.0).c_str());
+ base::DoubleToString(SkColorGetA(color) / 255.0).c_str());
}
// Get the CSS string for the background position on the new tab page for the
@@ -104,10 +109,10 @@ std::string GetNewTabBackgroundCSS(const ThemeProvider* theme_provider,
if (alignment & BrowserThemeProvider::ALIGN_TOP) {
if (alignment & BrowserThemeProvider::ALIGN_LEFT)
- return "0% " + IntToString(-offset) + "px";
+ return "0% " + base::IntToString(-offset) + "px";
else if (alignment & BrowserThemeProvider::ALIGN_RIGHT)
- return "100% " + IntToString(-offset) + "px";
- return "center " + IntToString(-offset) + "px";
+ return "100% " + base::IntToString(-offset) + "px";
+ return "center " + base::IntToString(-offset) + "px";
}
return BrowserThemeProvider::AlignmentToString(alignment);
}
@@ -128,15 +133,9 @@ NTPResourceCache::NTPResourceCache(Profile* profile) : profile_(profile) {
NotificationService::AllSources());
// Watch for pref changes that cause us to need to invalidate the HTML cache.
- PrefService* pref_service = profile_->GetPrefs();
- pref_service->AddPrefObserver(prefs::kShowBookmarkBar, this);
- pref_service->AddPrefObserver(prefs::kNTPShownSections, this);
-}
-
-NTPResourceCache::~NTPResourceCache() {
- PrefService* pref_service = profile_->GetPrefs();
- pref_service->RemovePrefObserver(prefs::kShowBookmarkBar, this);
- pref_service->RemovePrefObserver(prefs::kNTPShownSections, this);
+ pref_change_registrar_.Init(profile_->GetPrefs());
+ pref_change_registrar_.Add(prefs::kShowBookmarkBar, this);
+ pref_change_registrar_.Add(prefs::kNTPShownSections, this);
}
RefCountedBytes* NTPResourceCache::GetNewTabHTML(bool is_off_the_record) {
@@ -174,7 +173,7 @@ void NTPResourceCache::Observe(NotificationType type,
new_tab_incognito_css_ = NULL;
new_tab_css_ = NULL;
} else if (NotificationType::PREF_CHANGED == type) {
- std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ std::string* pref_name = Details<std::string>(details).ptr();
if (*pref_name == prefs::kShowBookmarkBar ||
*pref_name == prefs::kHomePageIsNewTabPage ||
*pref_name == prefs::kNTPShownSections) {
@@ -190,18 +189,18 @@ void NTPResourceCache::Observe(NotificationType type,
void NTPResourceCache::CreateNewTabIncognitoHTML() {
DictionaryValue localized_strings;
- localized_strings.SetString(L"title",
- l10n_util::GetString(IDS_NEW_TAB_TITLE));
- localized_strings.SetString(L"content",
- l10n_util::GetStringF(IDS_NEW_TAB_OTR_MESSAGE,
- GetUrlWithLang(GURL(kLearnMoreIncognitoUrl))));
- localized_strings.SetString(L"extensionsmessage",
- l10n_util::GetStringF(IDS_NEW_TAB_OTR_EXTENSIONS_MESSAGE,
- l10n_util::GetString(IDS_PRODUCT_NAME),
- ASCIIToWide(chrome::kChromeUIExtensionsURL)));
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
+ localized_strings.SetString("content",
+ l10n_util::GetStringFUTF16(IDS_NEW_TAB_OTR_MESSAGE,
+ GetUrlWithLang(GURL(kLearnMoreIncognitoUrl))));
+ localized_strings.SetString("extensionsmessage",
+ l10n_util::GetStringFUTF16(IDS_NEW_TAB_OTR_EXTENSIONS_MESSAGE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+ ASCIIToUTF16(chrome::kChromeUIExtensionsURL)));
bool bookmark_bar_attached = profile_->GetPrefs()->GetBoolean(
prefs::kShowBookmarkBar);
- localized_strings.SetString(L"bookmarkbarattached",
+ localized_strings.SetString("bookmarkbarattached",
bookmark_bar_attached ? "true" : "false");
ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
@@ -222,92 +221,110 @@ void NTPResourceCache::CreateNewTabIncognitoHTML() {
void NTPResourceCache::CreateNewTabHTML() {
// Show the profile name in the title and most visited labels if the current
// profile is not the default.
- std::wstring title = l10n_util::GetString(IDS_NEW_TAB_TITLE);
- std::wstring most_visited = l10n_util::GetString(IDS_NEW_TAB_MOST_VISITED);
+ string16 apps = l10n_util::GetStringUTF16(IDS_NEW_TAB_APPS);
+ string16 title = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
+ string16 most_visited = l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED);
DictionaryValue localized_strings;
- localized_strings.SetString(L"bookmarkbarattached",
+ localized_strings.SetString("bookmarkbarattached",
profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
"true" : "false");
- localized_strings.SetString(L"hasattribution",
+ localized_strings.SetString("hasattribution",
profile_->GetThemeProvider()->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION) ?
"true" : "false");
- localized_strings.SetString(L"title", title);
- localized_strings.SetString(L"mostvisited", most_visited);
- localized_strings.SetString(L"restorethumbnails",
- l10n_util::GetString(IDS_NEW_TAB_RESTORE_THUMBNAILS_LINK));
- localized_strings.SetString(L"recentlyclosed",
- l10n_util::GetString(IDS_NEW_TAB_RECENTLY_CLOSED));
- localized_strings.SetString(L"closedwindowsingle",
- l10n_util::GetString(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE));
- localized_strings.SetString(L"closedwindowmultiple",
- l10n_util::GetString(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE));
- localized_strings.SetString(L"attributionintro",
- l10n_util::GetString(IDS_NEW_TAB_ATTRIBUTION_INTRO));
- localized_strings.SetString(L"thumbnailremovednotification",
- l10n_util::GetString(IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION));
- localized_strings.SetString(L"undothumbnailremove",
- l10n_util::GetString(IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE));
- localized_strings.SetString(L"removethumbnailtooltip",
- l10n_util::GetString(IDS_NEW_TAB_REMOVE_THUMBNAIL_TOOLTIP));
- localized_strings.SetString(L"pinthumbnailtooltip",
- l10n_util::GetString(IDS_NEW_TAB_PIN_THUMBNAIL_TOOLTIP));
- localized_strings.SetString(L"unpinthumbnailtooltip",
- l10n_util::GetString(IDS_NEW_TAB_UNPIN_THUMBNAIL_TOOLTIP));
- localized_strings.SetString(L"showhidethumbnailtooltip",
- l10n_util::GetString(IDS_NEW_TAB_SHOW_HIDE_THUMBNAIL_TOOLTIP));
- localized_strings.SetString(L"showhidelisttooltip",
- l10n_util::GetString(IDS_NEW_TAB_SHOW_HIDE_LIST_TOOLTIP));
- localized_strings.SetString(L"pagedisplaytooltip",
- l10n_util::GetString(IDS_NEW_TAB_PAGE_DISPLAY_TOOLTIP));
- localized_strings.SetString(L"firstrunnotification",
- l10n_util::GetString(IDS_NEW_TAB_FIRST_RUN_NOTIFICATION));
- localized_strings.SetString(L"closefirstrunnotification",
- l10n_util::GetString(IDS_NEW_TAB_CLOSE_FIRST_RUN_NOTIFICATION));
- localized_strings.SetString(L"tips",
- l10n_util::GetString(IDS_NEW_TAB_TIPS));
- localized_strings.SetString(L"close", l10n_util::GetString(IDS_CLOSE));
- localized_strings.SetString(L"history",
- l10n_util::GetString(IDS_NEW_TAB_HISTORY));
- localized_strings.SetString(L"downloads",
- l10n_util::GetString(IDS_NEW_TAB_DOWNLOADS));
- localized_strings.SetString(L"help",
- l10n_util::GetString(IDS_NEW_TAB_HELP));
- localized_strings.SetString(L"helpurl",
+ localized_strings.SetString("apps", apps);
+ localized_strings.SetString("title", title);
+ localized_strings.SetString("mostvisited", most_visited);
+ localized_strings.SetString("restorethumbnails",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_RESTORE_THUMBNAILS_LINK));
+ localized_strings.SetString("recentlyclosed",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED));
+ localized_strings.SetString("closedwindowsingle",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE));
+ localized_strings.SetString("closedwindowmultiple",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE));
+ localized_strings.SetString("attributionintro",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_ATTRIBUTION_INTRO));
+ localized_strings.SetString("thumbnailremovednotification",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION));
+ localized_strings.SetString("undothumbnailremove",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE));
+ localized_strings.SetString("removethumbnailtooltip",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_REMOVE_THUMBNAIL_TOOLTIP));
+ localized_strings.SetString("pinthumbnailtooltip",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_PIN_THUMBNAIL_TOOLTIP));
+ localized_strings.SetString("unpinthumbnailtooltip",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_UNPIN_THUMBNAIL_TOOLTIP));
+ localized_strings.SetString("showhidethumbnailtooltip",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_SHOW_HIDE_THUMBNAIL_TOOLTIP));
+ localized_strings.SetString("showhidelisttooltip",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_SHOW_HIDE_LIST_TOOLTIP));
+ localized_strings.SetString("pagedisplaytooltip",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_PAGE_DISPLAY_TOOLTIP));
+ localized_strings.SetString("firstrunnotification",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_FIRST_RUN_NOTIFICATION));
+ localized_strings.SetString("closefirstrunnotification",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_CLOSE_FIRST_RUN_NOTIFICATION));
+ localized_strings.SetString("tips",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_TIPS));
+ localized_strings.SetString("close", l10n_util::GetStringUTF16(IDS_CLOSE));
+ localized_strings.SetString("history",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_HISTORY));
+ localized_strings.SetString("downloads",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_DOWNLOADS));
+ localized_strings.SetString("help",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_HELP));
+ localized_strings.SetString("helpurl",
GetUrlWithLang(GURL(kHelpContentUrl)));
- localized_strings.SetString(L"appsettings",
- l10n_util::GetString(IDS_NEW_TAB_APP_SETTINGS));
- localized_strings.SetString(L"appuninstall",
- l10n_util::GetString(IDS_NEW_TAB_APP_UNINSTALL));
- localized_strings.SetString(L"appoptions",
- l10n_util::GetString(IDS_NEW_TAB_APP_OPTIONS));
- localized_strings.SetString(L"web_store_title",
- l10n_util::GetString(IDS_EXTENSION_WEB_STORE_TITLE));
- localized_strings.SetString(L"web_store_url",
+ localized_strings.SetString("appsettings",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_SETTINGS));
+ localized_strings.SetString("appuninstall",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_UNINSTALL));
+ localized_strings.SetString("appoptions",
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_APP_OPTIONS));
+ localized_strings.SetString("applaunchtypepinned",
+ l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_PINNED));
+ localized_strings.SetString("applaunchtyperegular",
+ l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_REGULAR));
+ localized_strings.SetString("applaunchtypefullscreen",
+ l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN));
+ localized_strings.SetString("web_store_title",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
+ localized_strings.SetString("web_store_url",
GetUrlWithLang(GURL(Extension::ChromeStoreURL())));
// Don't initiate the sync related message passing with the page if the sync
// code is not present.
if (profile_->GetProfileSyncService())
- localized_strings.SetString(L"syncispresent", "true");
+ localized_strings.SetString("syncispresent", "true");
else
- localized_strings.SetString(L"syncispresent", "false");
+ localized_strings.SetString("syncispresent", "false");
ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
// Control fade and resize animations.
std::string anim =
Animation::ShouldRenderRichAnimation() ? "true" : "false";
- localized_strings.SetString(L"anim", anim);
-
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- bool has_3d =
- command_line->HasSwitch(switches::kEnableAcceleratedCompositing);
- localized_strings.SetString(L"has_3d", has_3d ? "true" : "false");
+ localized_strings.SetString("anim", anim);
// Pass the shown_sections pref early so that we can prevent flicker.
- const int shown_sections = profile_->GetPrefs()->GetInteger(
- prefs::kNTPShownSections);
- localized_strings.SetInteger(L"shown_sections", shown_sections);
+ const int shown_sections = ShownSectionsHandler::GetShownSections(
+ profile_->GetPrefs());
+ localized_strings.SetInteger("shown_sections", shown_sections);
+
+ // If the user has preferences for a start and end time for a custom logo,
+ // and the time now is between these two times, show the custom logo.
+ if (profile_->GetPrefs()->FindPreference(prefs::kNTPCustomLogoStart) &&
+ profile_->GetPrefs()->FindPreference(prefs::kNTPCustomLogoEnd)) {
+ Time start_time = Time::FromDoubleT(
+ profile_->GetPrefs()->GetReal(prefs::kNTPCustomLogoStart));
+ Time end_time = Time::FromDoubleT(
+ profile_->GetPrefs()->GetReal(prefs::kNTPCustomLogoEnd));
+ localized_strings.SetString("customlogo",
+ (start_time < Time::Now() && end_time > Time::Now()) ?
+ "true" : "false");
+ } else {
+ localized_strings.SetString("customlogo", "false");
+ }
base::StringPiece new_tab_html(ResourceBundle::GetSharedInstance().
GetRawDataResource(IDR_NEW_NEW_TAB_HTML));
@@ -394,6 +411,14 @@ void NTPResourceCache::CreateNewTabCSS() {
tp->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_LINK);
SkColor color_section_link_underline =
tp->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE);
+ SkColor color_section_header_text =
+ tp->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_HEADER_TEXT);
+ SkColor color_section_header_text_hover =
+ tp->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_HEADER_TEXT_HOVER);
+ SkColor color_section_header_rule =
+ tp->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_HEADER_RULE);
+ SkColor color_section_header_rule_light =
+ tp->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_HEADER_RULE_LIGHT);
SkColor color_header =
tp->GetColor(BrowserThemeProvider::COLOR_NTP_HEADER);
@@ -418,6 +443,7 @@ void NTPResourceCache::CreateNewTabCSS() {
// A second list of replacements, each of which must be in $$x format,
// where x is a digit from 1-9.
std::vector<std::string> subst2;
+ std::vector<std::string> subst3;
// Cache-buster for background.
subst.push_back(
@@ -437,10 +463,18 @@ void NTPResourceCache::CreateNewTabCSS() {
subst2.push_back(SkColorToRGBAString(color_section_border)); // $$2
subst2.push_back(SkColorToRGBAString(color_section_text)); // $$3
subst2.push_back(SkColorToRGBAString(color_section_link)); // $$4
- subst2.push_back(
- tp->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION) ? "block" : "none"); // $$5
- subst2.push_back(SkColorToRGBAString(color_link_underline)); // $$6
- subst2.push_back(SkColorToRGBAString(color_section_link_underline)); // $$7
+ subst2.push_back(SkColorToRGBAString(color_link_underline)); // $$5
+ subst2.push_back(SkColorToRGBAString(color_section_link_underline)); // $$6
+ subst2.push_back(SkColorToRGBAString(color_section_header_text)); // $$7
+ subst2.push_back(SkColorToRGBAString(
+ color_section_header_text_hover)); // $$8
+ subst2.push_back(SkColorToRGBAString(color_section_header_rule)); // $$9
+
+ subst3.push_back(SkColorToRGBAString(
+ color_section_header_rule_light)); // $$$1
+ subst3.push_back(SkColorToRGBAString(
+ SkColorSetA(color_section_header_rule, 0))); // $$$2
+
// Get our template.
static const base::StringPiece new_tab_theme_css(
@@ -448,12 +482,13 @@ void NTPResourceCache::CreateNewTabCSS() {
IDR_NEW_TAB_THEME_CSS));
// Create the string from our template and the replacements.
- const std::string css_string = ReplaceStringPlaceholders(
- new_tab_theme_css, subst, NULL);
- std::string full_css = ReplaceStringPlaceholders(css_string, subst2, NULL);
+ std::string css_string;
+ css_string = ReplaceStringPlaceholders(new_tab_theme_css, subst, NULL);
+ css_string = ReplaceStringPlaceholders(css_string, subst2, NULL);
+ css_string = ReplaceStringPlaceholders(css_string, subst3, NULL);
new_tab_css_ = new RefCountedBytes;
- new_tab_css_->data.resize(full_css.size());
- std::copy(full_css.begin(), full_css.end(),
+ new_tab_css_->data.resize(css_string.size());
+ std::copy(css_string.begin(), css_string.end(),
new_tab_css_->data.begin());
}
diff --git a/chrome/browser/dom_ui/ntp_resource_cache.h b/chrome/browser/dom_ui/ntp_resource_cache.h
index 5f36b91..3cdc3e5 100644
--- a/chrome/browser/dom_ui/ntp_resource_cache.h
+++ b/chrome/browser/dom_ui/ntp_resource_cache.h
@@ -1,15 +1,16 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_NTP_RESOURCE_CACHE_H_
#define CHROME_BROWSER_DOM_UI_NTP_RESOURCE_CACHE_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
class Profile;
class RefCountedBytes;
@@ -19,7 +20,7 @@ class RefCountedBytes;
class NTPResourceCache : public NotificationObserver {
public:
explicit NTPResourceCache(Profile* profile);
- virtual ~NTPResourceCache();
+ virtual ~NTPResourceCache() {}
RefCountedBytes* GetNewTabHTML(bool is_off_the_record);
RefCountedBytes* GetNewTabCSS(bool is_off_the_record);
@@ -43,6 +44,7 @@ class NTPResourceCache : public NotificationObserver {
scoped_refptr<RefCountedBytes> new_tab_css_;
NotificationRegistrar registrar_;
+ PrefChangeRegistrar pref_change_registrar_;
DISALLOW_COPY_AND_ASSIGN(NTPResourceCache);
};
diff --git a/chrome/browser/dom_ui/options_ui.cc b/chrome/browser/dom_ui/options_ui.cc
index 3305df3..0ebeba8 100644
--- a/chrome/browser/dom_ui/options_ui.cc
+++ b/chrome/browser/dom_ui/options_ui.cc
@@ -4,10 +4,10 @@
#include "chrome/browser/dom_ui/options_ui.h"
-#include "app/l10n_util.h"
+#include <algorithm>
+
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "base/i18n/time_formatting.h"
#include "base/message_loop.h"
#include "base/singleton.h"
#include "base/string_piece.h"
@@ -16,15 +16,24 @@
#include "base/time.h"
#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/dom_ui/about_page_handler.h"
+#include "chrome/browser/dom_ui/add_startup_page_handler.h"
#include "chrome/browser/dom_ui/advanced_options_handler.h"
+#include "chrome/browser/dom_ui/autofill_options_handler.h"
#include "chrome/browser/dom_ui/browser_options_handler.h"
#include "chrome/browser/dom_ui/clear_browser_data_handler.h"
#include "chrome/browser/dom_ui/content_settings_handler.h"
+#include "chrome/browser/dom_ui/cookies_view_handler.h"
#include "chrome/browser/dom_ui/core_options_handler.h"
+#include "chrome/browser/dom_ui/dom_ui_theme_source.h"
#include "chrome/browser/dom_ui/font_settings_handler.h"
+#include "chrome/browser/dom_ui/import_data_handler.h"
+#include "chrome/browser/dom_ui/passwords_exceptions_handler.h"
#include "chrome/browser/dom_ui/personal_options_handler.h"
+#include "chrome/browser/dom_ui/search_engine_manager_handler.h"
+#include "chrome/browser/dom_ui/sync_options_handler.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_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/tab_contents/tab_contents_delegate.h"
@@ -44,13 +53,22 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/dom_ui/accounts_options_handler.h"
#include "chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h"
+#include "chrome/browser/chromeos/dom_ui/internet_options_handler.h"
#include "chrome/browser/chromeos/dom_ui/labs_handler.h"
+#include "chrome/browser/chromeos/dom_ui/language_chewing_options_handler.h"
+#include "chrome/browser/chromeos/dom_ui/language_customize_modifier_keys_handler.h"
#include "chrome/browser/chromeos/dom_ui/language_hangul_options_handler.h"
+#include "chrome/browser/chromeos/dom_ui/language_mozc_options_handler.h"
#include "chrome/browser/chromeos/dom_ui/language_options_handler.h"
-#include "chrome/browser/chromeos/dom_ui/sync_options_handler.h"
+#include "chrome/browser/chromeos/dom_ui/language_pinyin_options_handler.h"
+#include "chrome/browser/chromeos/dom_ui/proxy_handler.h"
#include "chrome/browser/chromeos/dom_ui/system_options_handler.h"
#endif
+#if defined(USE_NSS)
+#include "chrome/browser/dom_ui/certificate_manager_handler.h"
+#endif
+
////////////////////////////////////////////////////////////////////////////////
//
// OptionsUIHTMLSource
@@ -58,7 +76,7 @@
////////////////////////////////////////////////////////////////////////////////
OptionsUIHTMLSource::OptionsUIHTMLSource(DictionaryValue* localized_strings)
- : DataSource(chrome::kChromeUIOptionsHost, MessageLoop::current()) {
+ : DataSource(chrome::kChromeUISettingsHost, MessageLoop::current()) {
DCHECK(localized_strings);
localized_strings_.reset(localized_strings);
}
@@ -94,10 +112,8 @@ OptionsPageUIHandler::~OptionsPageUIHandler() {
}
void OptionsPageUIHandler::UserMetricsRecordAction(
- const UserMetricsAction& action, PrefService* prefs) {
+ const UserMetricsAction& action) {
UserMetrics::RecordAction(action, dom_ui_->GetProfile());
- if (prefs)
- prefs->ScheduleSavePersistentPrefs();
}
////////////////////////////////////////////////////////////////////////////////
@@ -116,43 +132,80 @@ OptionsUI::OptionsUI(TabContents* contents) : DOMUI(contents) {
AddOptionsPageUIHandler(localized_strings, new CoreOptionsHandler());
#endif
- // TODO(zelidrag): Add all other page handlers here as we implement them.
+ AddOptionsPageUIHandler(localized_strings, new AddStartupPageHandler());
+ AddOptionsPageUIHandler(localized_strings, new AdvancedOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings, new AutoFillOptionsHandler());
AddOptionsPageUIHandler(localized_strings, new BrowserOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings, new ClearBrowserDataHandler());
+ AddOptionsPageUIHandler(localized_strings, new ContentSettingsHandler());
+ AddOptionsPageUIHandler(localized_strings, new CookiesViewHandler());
+ AddOptionsPageUIHandler(localized_strings, new FontSettingsHandler());
+ AddOptionsPageUIHandler(localized_strings, new PasswordsExceptionsHandler());
AddOptionsPageUIHandler(localized_strings, new PersonalOptionsHandler());
- AddOptionsPageUIHandler(localized_strings, new AdvancedOptionsHandler());
-#if defined(OS_CHROMEOS)
- AddOptionsPageUIHandler(localized_strings, new SystemOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings, new SearchEngineManagerHandler());
+ AddOptionsPageUIHandler(localized_strings, new ImportDataHandler());
AddOptionsPageUIHandler(localized_strings, new SyncOptionsHandler());
+#if defined(OS_CHROMEOS)
+ AddOptionsPageUIHandler(localized_strings, new AboutPageHandler());
+ AddOptionsPageUIHandler(localized_strings,
+ new chromeos::AccountsOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings, new InternetOptionsHandler());
AddOptionsPageUIHandler(localized_strings, new LabsHandler());
AddOptionsPageUIHandler(localized_strings,
- new LanguageHangulOptionsHandler());
- AddOptionsPageUIHandler(localized_strings, new LanguageOptionsHandler());
+ new chromeos::LanguageChewingOptionsHandler());
AddOptionsPageUIHandler(localized_strings,
- new chromeos::AccountsOptionsHandler());
+ new chromeos::LanguageCustomizeModifierKeysHandler());
+ AddOptionsPageUIHandler(localized_strings,
+ new chromeos::LanguageHangulOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings,
+ new chromeos::LanguageMozcOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings,
+ new chromeos::LanguageOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings,
+ new chromeos::LanguagePinyinOptionsHandler());
+ AddOptionsPageUIHandler(localized_strings, new chromeos::ProxyHandler());
+ AddOptionsPageUIHandler(localized_strings, new SystemOptionsHandler());
+#endif
+#if defined(USE_NSS)
+ AddOptionsPageUIHandler(localized_strings, new CertificateManagerHandler());
#endif
- AddOptionsPageUIHandler(localized_strings, new ContentSettingsHandler());
- AddOptionsPageUIHandler(localized_strings, new ClearBrowserDataHandler());
- AddOptionsPageUIHandler(localized_strings, new FontSettingsHandler());
// |localized_strings| ownership is taken over by this constructor.
OptionsUIHTMLSource* html_source =
new OptionsUIHTMLSource(localized_strings);
- // Set up the chrome://options/ source.
+ // Set up the chrome://settings/ source.
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableMethod(
Singleton<ChromeURLDataManager>::get(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
+
+ // Set up chrome://theme/ source.
+ DOMUIThemeSource* theme = new DOMUIThemeSource(GetProfile());
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ Singleton<ChromeURLDataManager>::get(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(theme)));
+}
+
+OptionsUI::~OptionsUI() {
+ // Uninitialize all registered handlers. The base class owns them and it will
+ // eventually delete them.
+ for (std::vector<DOMMessageHandler*>::iterator iter = handlers_.begin();
+ iter != handlers_.end();
+ ++iter) {
+ reinterpret_cast<OptionsPageUIHandler*>(*iter)->Uninitialize();
+ }
}
// static
RefCountedMemory* OptionsUI::GetFaviconResourceBytes() {
-// TODO(csilv): uncomment this once we have a FAVICON
-// return ResourceBundle::GetSharedInstance().
-// LoadDataResourceBytes(IDR_OPTIONS_FAVICON);
- return NULL;
+ return ResourceBundle::GetSharedInstance().
+ LoadDataResourceBytes(IDR_SETTINGS_FAVICON);
}
void OptionsUI::InitializeHandlers() {
diff --git a/chrome/browser/dom_ui/options_ui.h b/chrome/browser/dom_ui/options_ui.h
index e8f1585..92817e2 100644
--- a/chrome/browser/dom_ui/options_ui.h
+++ b/chrome/browser/dom_ui/options_ui.h
@@ -4,13 +4,14 @@
#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_UI_H_
#define CHROME_BROWSER_DOM_UI_OPTIONS_UI_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/scoped_ptr.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"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_type.h"
@@ -53,6 +54,9 @@ class OptionsPageUIHandler : public DOMMessageHandler,
// Initialize the page. Called once the DOM is available for manipulation.
virtual void Initialize() {}
+ // Uninitializes the page. Called just before the object is destructed.
+ virtual void Uninitialize() {}
+
// DOMMessageHandler implementation.
virtual void RegisterMessages() {}
@@ -61,8 +65,7 @@ class OptionsPageUIHandler : public DOMMessageHandler,
const NotificationSource& source,
const NotificationDetails& details) {}
- void UserMetricsRecordAction(const UserMetricsAction& action,
- PrefService* prefs);
+ void UserMetricsRecordAction(const UserMetricsAction& action);
protected:
NotificationRegistrar registrar_;
@@ -74,7 +77,7 @@ class OptionsPageUIHandler : public DOMMessageHandler,
class OptionsUI : public DOMUI {
public:
explicit OptionsUI(TabContents* contents);
- virtual ~OptionsUI() {}
+ virtual ~OptionsUI();
static RefCountedMemory* GetFaviconResourceBytes();
diff --git a/chrome/browser/dom_ui/options_ui_uitest.cc b/chrome/browser/dom_ui/options_ui_uitest.cc
index 8c55046..42d00a3 100644
--- a/chrome/browser/dom_ui/options_ui_uitest.cc
+++ b/chrome/browser/dom_ui/options_ui_uitest.cc
@@ -2,7 +2,10 @@
// 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/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
@@ -11,6 +14,9 @@
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
namespace {
class OptionsUITest : public UITest {
@@ -24,7 +30,8 @@ class OptionsUITest : public UITest {
void AssertIsOptionsPage(TabProxy* tab) {
std::wstring title;
ASSERT_TRUE(tab->GetTabTitle(&title));
- ASSERT_EQ(L"Chromium Options", title);
+ string16 expected_title = l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE);
+ ASSERT_EQ(expected_title, WideToUTF16Hack(title));
}
};
@@ -36,7 +43,7 @@ TEST_F(OptionsUITest, LoadOptionsByURL) {
ASSERT_TRUE(tab.get());
// Go to the options tab via URL.
- NavigateToURL(GURL(chrome::kChromeUIOptionsURL));
+ NavigateToURL(GURL(chrome::kChromeUISettingsURL));
AssertIsOptionsPage(tab);
}
@@ -59,7 +66,7 @@ TEST_F(OptionsUITest, CommandOpensOptionsTab) {
}
// TODO(csilv): Investigate why this fails and fix. http://crbug.com/48521
-TEST_F(OptionsUITest, FAILS_CommandAgainGoesBackToOptionsTab) {
+TEST_F(OptionsUITest, FLAKY_CommandAgainGoesBackToOptionsTab) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
@@ -79,7 +86,7 @@ TEST_F(OptionsUITest, FAILS_CommandAgainGoesBackToOptionsTab) {
// Switch to first tab and run command again.
ASSERT_TRUE(browser->ActivateTab(0));
ASSERT_TRUE(browser->WaitForTabToBecomeActive(0, action_max_timeout_ms()));
- ASSERT_TRUE(browser->RunCommandAsync(IDC_OPTIONS));
+ ASSERT_TRUE(browser->RunCommand(IDC_OPTIONS));
// Ensure the options ui tab is active.
ASSERT_TRUE(browser->WaitForTabToBecomeActive(1, action_max_timeout_ms()));
@@ -98,7 +105,7 @@ TEST_F(OptionsUITest, FLAKY_TwoCommandsOneTab) {
ASSERT_EQ(1, tab_count);
ASSERT_TRUE(browser->RunCommand(IDC_OPTIONS));
- ASSERT_TRUE(browser->RunCommandAsync(IDC_OPTIONS));
+ ASSERT_TRUE(browser->RunCommand(IDC_OPTIONS));
ASSERT_TRUE(browser->GetTabCount(&tab_count));
ASSERT_EQ(2, tab_count);
}
diff --git a/chrome/browser/dom_ui/personal_options_handler.cc b/chrome/browser/dom_ui/personal_options_handler.cc
index c0f13b8..095ca52 100644
--- a/chrome/browser/dom_ui/personal_options_handler.cc
+++ b/chrome/browser/dom_ui/personal_options_handler.cc
@@ -6,9 +6,31 @@
#include "app/l10n_util.h"
#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/path_service.h"
+#include "base/stl_util-inl.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/dom_ui/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/sync/profile_sync_service.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
PersonalOptionsHandler::PersonalOptionsHandler() {
}
@@ -19,42 +41,156 @@ PersonalOptionsHandler::~PersonalOptionsHandler() {
void PersonalOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString(L"passwordsGroupName",
- l10n_util::GetString(IDS_OPTIONS_PASSWORDS_GROUP_NAME));
- localized_strings->SetString(L"passwordsAskToSave",
- l10n_util::GetString(IDS_OPTIONS_PASSWORDS_ASKTOSAVE));
- localized_strings->SetString(L"passwordsNeverSave",
- l10n_util::GetString(IDS_OPTIONS_PASSWORDS_NEVERSAVE));
- localized_strings->SetString(L"passwordShowPasswords",
- l10n_util::GetString(IDS_OPTIONS_PASSWORDS_SHOWPASSWORDS));
- localized_strings->SetString(L"autoFillSettingWindowsGroupName",
- l10n_util::GetString(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME));
- localized_strings->SetString(L"autoFillEnable",
- l10n_util::GetString(IDS_OPTIONS_AUTOFILL_ENABLE));
- localized_strings->SetString(L"autoFillDisable",
- l10n_util::GetString(IDS_OPTIONS_AUTOFILL_DISABLE));
- localized_strings->SetString(L"themesGroupName",
- l10n_util::GetString(IDS_THEMES_GROUP_NAME));
-#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
- localized_strings->SetString(L"appearanceGroupName",
- l10n_util::GetString(IDS_APPEARANCE_GROUP_NAME));
- localized_strings->SetString(L"themesGTKButton",
- l10n_util::GetString(IDS_THEMES_GTK_BUTTON));
- localized_strings->SetString(L"themesSetClassic",
- l10n_util::GetString(IDS_THEMES_SET_CLASSIC));
- localized_strings->SetString(L"showWindowDecorationsRadio",
- l10n_util::GetString(IDS_SHOW_WINDOW_DECORATIONS_RADIO));
- localized_strings->SetString(L"hideWindowDecorationsRadio",
- l10n_util::GetString(IDS_HIDE_WINDOW_DECORATIONS_RADIO));
+
+ localized_strings->SetString("sync_section",
+ l10n_util::GetStringUTF16(IDS_SYNC_OPTIONS_GROUP_NAME));
+ localized_strings->SetString("sync_not_setup_info",
+ l10n_util::GetStringFUTF16(IDS_SYNC_NOT_SET_UP_INFO,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ localized_strings->SetString("start_sync",
+ l10n_util::GetStringUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL));
+ localized_strings->SetString("sync_customize",
+ l10n_util::GetStringUTF16(IDS_SYNC_CUSTOMIZE_BUTTON_LABEL));
+ localized_strings->SetString("stop_sync",
+ l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_BUTTON_LABEL));
+ localized_strings->SetString("stop_syncing_explanation",
+ l10n_util::GetStringFUTF16(IDS_SYNC_STOP_SYNCING_EXPLANATION_LABEL,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ localized_strings->SetString("stop_syncing_title",
+ l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_DIALOG_TITLE));
+ localized_strings->SetString("stop_syncing_confirm_button_label",
+ l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_CONFIRM_BUTTON_LABEL));
+
+ localized_strings->SetString("passwords",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_GROUP_NAME));
+ localized_strings->SetString("passwords_asktosave",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_ASKTOSAVE));
+ localized_strings->SetString("passwords_neversave",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_NEVERSAVE));
+ localized_strings->SetString("showpasswords",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_SHOWPASSWORDS));
+
+ localized_strings->SetString("autofill",
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME));
+ localized_strings->SetString("autofill_options",
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS));
+
+ localized_strings->SetString("browsing_data",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME));
+ localized_strings->SetString("import_data",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_IMPORT_DATA_BUTTON));
+
+#if defined(TOOLKIT_GTK)
+ localized_strings->SetString("appearance",
+ l10n_util::GetStringUTF16(IDS_APPEARANCE_GROUP_NAME));
+ localized_strings->SetString("themes_GTK_button",
+ l10n_util::GetStringUTF16(IDS_THEMES_GTK_BUTTON));
+ localized_strings->SetString("themes_set_classic",
+ l10n_util::GetStringUTF16(IDS_THEMES_SET_CLASSIC));
+ localized_strings->SetString("showWindow_decorations_radio",
+ l10n_util::GetStringUTF16(IDS_SHOW_WINDOW_DECORATIONS_RADIO));
+ localized_strings->SetString("hideWindow_decorations_radio",
+ l10n_util::GetStringUTF16(IDS_HIDE_WINDOW_DECORATIONS_RADIO));
+ localized_strings->SetString("themes_gallery",
+ l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_BUTTON));
+#else
+ localized_strings->SetString("themes",
+ l10n_util::GetStringUTF16(IDS_THEMES_GROUP_NAME));
+ localized_strings->SetString("themes_reset",
+ l10n_util::GetStringUTF16(IDS_THEMES_RESET_BUTTON));
+ localized_strings->SetString("themes_gallery",
+ l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_BUTTON));
+ localized_strings->SetString("themes_default",
+ l10n_util::GetStringUTF16(IDS_THEMES_DEFAULT_THEME_LABEL));
+#endif
+}
+
+void PersonalOptionsHandler::RegisterMessages() {
+ DCHECK(dom_ui_);
+ dom_ui_->RegisterMessageCallback(
+ "getSyncStatus",
+ NewCallback(this, &PersonalOptionsHandler::SetSyncStatusUIString));
+ dom_ui_->RegisterMessageCallback(
+ "themesReset",
+ NewCallback(this, &PersonalOptionsHandler::ThemesReset));
+ dom_ui_->RegisterMessageCallback(
+ "themesGallery",
+ NewCallback(this, &PersonalOptionsHandler::ThemesGallery));
+#if defined(TOOLKIT_GTK)
+ dom_ui_->RegisterMessageCallback(
+ "themesSetGTK",
+ NewCallback(this, &PersonalOptionsHandler::ThemesSetGTK));
#endif
- localized_strings->SetString(L"themesResetButton",
- l10n_util::GetString(IDS_THEMES_RESET_BUTTON));
- localized_strings->SetString(L"themesDefaultThemeLabel",
- l10n_util::GetString(IDS_THEMES_DEFAULT_THEME_LABEL));
- localized_strings->SetString(L"themesGalleryButton",
- l10n_util::GetString(IDS_THEMES_GALLERY_BUTTON));
- localized_strings->SetString(L"browsingDataGroupName",
- l10n_util::GetString(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME));
- localized_strings->SetString(L"importDataButton",
- l10n_util::GetString(IDS_OPTIONS_IMPORT_DATA_BUTTON));
}
+
+void PersonalOptionsHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::BROWSER_THEME_CHANGED)
+ ObserveThemeChanged();
+ else
+ OptionsPageUIHandler::Observe(type, source, details);
+}
+
+void PersonalOptionsHandler::ObserveThemeChanged() {
+ Profile* profile = dom_ui_->GetProfile();
+#if defined(TOOLKIT_GTK)
+ GtkThemeProvider* provider = GtkThemeProvider::GetFrom(profile);
+ bool is_gtk_theme = provider->UseGtkTheme();
+ FundamentalValue gtk_enabled(!is_gtk_theme);
+ dom_ui_->CallJavascriptFunction(
+ L"options.PersonalOptions.setGtkThemeButtonEnabled", gtk_enabled);
+#else
+ BrowserThemeProvider* provider =
+ reinterpret_cast<BrowserThemeProvider*>(profile->GetThemeProvider());
+ bool is_gtk_theme = false;
+#endif
+
+ bool is_classic_theme = !is_gtk_theme && provider->GetThemeID().empty();
+ FundamentalValue classic_enabled(!is_classic_theme);
+ dom_ui_->CallJavascriptFunction(
+ L"options.PersonalOptions.setClassicThemeButtonEnabled", classic_enabled);
+}
+
+void PersonalOptionsHandler::Initialize() {
+ banner_handler_.reset(
+ new OptionsManagedBannerHandler(dom_ui_,
+ ASCIIToUTF16("PersonalOptions"),
+ OPTIONS_PAGE_CONTENT));
+
+ // Listen for theme installation.
+ registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
+ NotificationService::AllSources());
+ ObserveThemeChanged();
+}
+
+void PersonalOptionsHandler::SetSyncStatusUIString(const ListValue* args) {
+ ProfileSyncService* service = dom_ui_->GetProfile()->GetProfileSyncService();
+ if (service != NULL && ProfileSyncService::IsSyncEnabled()) {
+ scoped_ptr<Value> status_string(Value::CreateStringValue(
+ l10n_util::GetStringFUTF16(IDS_SYNC_ACCOUNT_SYNCED_TO_USER_WITH_TIME,
+ service->GetAuthenticatedUsername(),
+ service->GetLastSyncedTimeString())));
+
+ dom_ui_->CallJavascriptFunction(
+ L"PersonalOptions.syncStatusCallback",
+ *(status_string.get()));
+ }
+}
+
+void PersonalOptionsHandler::ThemesReset(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_ThemesReset"));
+ dom_ui_->GetProfile()->ClearTheme();
+}
+
+void PersonalOptionsHandler::ThemesGallery(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_ThemesGallery"));
+ BrowserList::GetLastActive()->OpenThemeGalleryTabAndActivate();
+}
+
+#if defined(TOOLKIT_GTK)
+void PersonalOptionsHandler::ThemesSetGTK(const ListValue* args) {
+ UserMetricsRecordAction(UserMetricsAction("Options_GtkThemeSet"));
+ dom_ui_->GetProfile()->SetNativeTheme();
+}
+#endif
diff --git a/chrome/browser/dom_ui/personal_options_handler.h b/chrome/browser/dom_ui/personal_options_handler.h
index cbc0c5c..94ad35b 100644
--- a/chrome/browser/dom_ui/personal_options_handler.h
+++ b/chrome/browser/dom_ui/personal_options_handler.h
@@ -4,8 +4,12 @@
#ifndef CHROME_BROWSER_DOM_UI_PERSONAL_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_PERSONAL_OPTIONS_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/options_ui.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+
+class OptionsManagedBannerHandler;
// Chrome personal options page UI handler.
class PersonalOptionsHandler : public OptionsPageUIHandler {
@@ -15,8 +19,27 @@ class PersonalOptionsHandler : public OptionsPageUIHandler {
// OptionsUIHandler implementation.
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+ virtual void Initialize();
+
+ // DOMMessageHandler implementation.
+ virtual void RegisterMessages();
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
private:
+ void ObserveThemeChanged();
+ void SetSyncStatusUIString(const ListValue* args);
+ void ThemesReset(const ListValue* args);
+ void ThemesGallery(const ListValue* args);
+#if defined(TOOLKIT_GTK)
+ void ThemesSetGTK(const ListValue* args);
+#endif
+
+ scoped_ptr<OptionsManagedBannerHandler> banner_handler_;
+
DISALLOW_COPY_AND_ASSIGN(PersonalOptionsHandler);
};
diff --git a/chrome/browser/dom_ui/plugins_ui.cc b/chrome/browser/dom_ui/plugins_ui.cc
index 158f297..1d2d347 100644
--- a/chrome/browser/dom_ui/plugins_ui.cc
+++ b/chrome/browser/dom_ui/plugins_ui.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/dom_ui/plugins_ui.h"
#include <algorithm>
-#include <set>
#include <string>
#include <vector>
@@ -20,10 +19,12 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/plugin_updater.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/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/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
@@ -64,42 +65,42 @@ void PluginsUIHTMLSource::StartDataRequest(const std::string& path,
int request_id) {
// Strings used in the JsTemplate file.
DictionaryValue localized_strings;
- localized_strings.SetString(L"pluginsTitle",
- l10n_util::GetString(IDS_PLUGINS_TITLE));
- localized_strings.SetString(L"pluginsDetailsModeLink",
- l10n_util::GetString(IDS_PLUGINS_DETAILS_MODE_LINK));
- localized_strings.SetString(L"pluginsNoneInstalled",
- l10n_util::GetString(IDS_PLUGINS_NONE_INSTALLED));
- localized_strings.SetString(L"pluginDisabled",
- l10n_util::GetString(IDS_PLUGINS_DISABLED_PLUGIN));
- localized_strings.SetString(L"pluginDisabledByPolicy",
- l10n_util::GetString(IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN));
- localized_strings.SetString(L"pluginCannotBeEnabledDueToPolicy",
- l10n_util::GetString(IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY));
- localized_strings.SetString(L"pluginDownload",
- l10n_util::GetString(IDS_PLUGINS_DOWNLOAD));
- localized_strings.SetString(L"pluginName",
- l10n_util::GetString(IDS_PLUGINS_NAME));
- localized_strings.SetString(L"pluginPriority",
- l10n_util::GetString(IDS_PLUGINS_PRIORITY));
- localized_strings.SetString(L"pluginVersion",
- l10n_util::GetString(IDS_PLUGINS_VERSION));
- localized_strings.SetString(L"pluginDescription",
- l10n_util::GetString(IDS_PLUGINS_DESCRIPTION));
- localized_strings.SetString(L"pluginPath",
- l10n_util::GetString(IDS_PLUGINS_PATH));
- localized_strings.SetString(L"pluginMimeTypes",
- l10n_util::GetString(IDS_PLUGINS_MIME_TYPES));
- localized_strings.SetString(L"pluginMimeTypesMimeType",
- l10n_util::GetString(IDS_PLUGINS_MIME_TYPES_MIME_TYPE));
- localized_strings.SetString(L"pluginMimeTypesDescription",
- l10n_util::GetString(IDS_PLUGINS_MIME_TYPES_DESCRIPTION));
- localized_strings.SetString(L"pluginMimeTypesFileExtensions",
- l10n_util::GetString(IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS));
- localized_strings.SetString(L"disable",
- l10n_util::GetString(IDS_PLUGINS_DISABLE));
- localized_strings.SetString(L"enable",
- l10n_util::GetString(IDS_PLUGINS_ENABLE));
+ localized_strings.SetString("pluginsTitle",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_TITLE));
+ localized_strings.SetString("pluginsDetailsModeLink",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DETAILS_MODE_LINK));
+ localized_strings.SetString("pluginsNoneInstalled",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_NONE_INSTALLED));
+ localized_strings.SetString("pluginDisabled",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN));
+ localized_strings.SetString("pluginDisabledByPolicy",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN));
+ localized_strings.SetString("pluginCannotBeEnabledDueToPolicy",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY));
+ localized_strings.SetString("pluginDownload",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DOWNLOAD));
+ localized_strings.SetString("pluginName",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_NAME));
+ localized_strings.SetString("pluginPriority",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_PRIORITY));
+ localized_strings.SetString("pluginVersion",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_VERSION));
+ localized_strings.SetString("pluginDescription",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DESCRIPTION));
+ localized_strings.SetString("pluginPath",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_PATH));
+ localized_strings.SetString("pluginMimeTypes",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES));
+ localized_strings.SetString("pluginMimeTypesMimeType",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_MIME_TYPE));
+ localized_strings.SetString("pluginMimeTypesDescription",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_DESCRIPTION));
+ localized_strings.SetString("pluginMimeTypesFileExtensions",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS));
+ localized_strings.SetString("disable",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLE));
+ localized_strings.SetString("enable",
+ l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLE));
ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
@@ -128,43 +129,43 @@ void PluginsUIHTMLSource::StartDataRequest(const std::string& path,
// TODO(viettrungluu): Make plugin list updates notify, and then observe
// changes; maybe replumb plugin list through plugin service?
// <http://crbug.com/39101>
-class PluginsDOMHandler : public DOMMessageHandler {
+class PluginsDOMHandler : public DOMMessageHandler,
+ public NotificationObserver {
public:
- PluginsDOMHandler() {}
+ explicit PluginsDOMHandler();
virtual ~PluginsDOMHandler() {}
// DOMMessageHandler implementation.
virtual void RegisterMessages();
// Callback for the "requestPluginsData" message.
- void HandleRequestPluginsData(const Value* value);
+ void HandleRequestPluginsData(const ListValue* args);
// Callback for the "enablePlugin" message.
- void HandleEnablePluginMessage(const Value* value);
+ void HandleEnablePluginMessage(const ListValue* args);
// Callback for the "showTermsOfService" message. This really just opens a new
// window with about:terms. Flash can't link directly to about:terms due to
// the security model.
- void HandleShowTermsOfServiceMessage(const Value* value);
+ void HandleShowTermsOfServiceMessage(const ListValue* args);
- private:
- // Creates a dictionary containing all the information about the given plugin;
- // this is put into the list to "return" for the "requestPluginsData" message.
- DictionaryValue* CreatePluginDetailValue(
- const WebPluginInfo& plugin,
- const std::set<string16>& plugin_blacklist_set);
-
- // Creates a dictionary containing the important parts of the information
- // about the given plugin; this is put into a list and saved in prefs.
- DictionaryValue* CreatePluginSummaryValue(const WebPluginInfo& plugin);
+ // NotificationObserver method overrides
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
- // Update the user preferences to reflect the current (user-selected) state of
- // plugins.
- void UpdatePreferences();
+ private:
+ NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
};
+PluginsDOMHandler::PluginsDOMHandler() {
+ registrar_.Add(this,
+ NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
+ NotificationService::AllSources());
+}
+
void PluginsDOMHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("requestPluginsData",
NewCallback(this, &PluginsDOMHandler::HandleRequestPluginsData));
@@ -174,50 +175,47 @@ void PluginsDOMHandler::RegisterMessages() {
NewCallback(this, &PluginsDOMHandler::HandleShowTermsOfServiceMessage));
}
-void PluginsDOMHandler::HandleRequestPluginsData(const Value* value) {
- DictionaryValue* results = new DictionaryValue();
- results->Set(L"plugins", plugin_updater::GetPluginGroupsData());
-
- dom_ui_->CallJavascriptFunction(L"returnPluginsData", *results);
+void PluginsDOMHandler::HandleRequestPluginsData(const ListValue* args) {
+ DictionaryValue results;
+ results.Set("plugins",
+ PluginUpdater::GetPluginUpdater()->GetPluginGroupsData());
+ dom_ui_->CallJavascriptFunction(L"returnPluginsData", results);
}
-void PluginsDOMHandler::HandleEnablePluginMessage(const Value* value) {
+void PluginsDOMHandler::HandleEnablePluginMessage(const ListValue* args) {
// Be robust in accepting badness since plug-ins display HTML (hence
// JavaScript).
- if (!value->IsType(Value::TYPE_LIST))
- return;
-
- const ListValue* list = static_cast<const ListValue*>(value);
- if (list->GetSize() != 3)
+ if (args->GetSize() != 3)
return;
std::string enable_str;
std::string is_group_str;
- if (!list->GetString(1, &enable_str) || !list->GetString(2, &is_group_str))
+ if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str))
return;
if (is_group_str == "true") {
- std::wstring group_name;
- if (!list->GetString(0, &group_name))
+ string16 group_name;
+ if (!args->GetString(0, &group_name))
return;
- plugin_updater::EnablePluginGroup(enable_str == "true",
- WideToUTF16(group_name));
+ PluginUpdater::GetPluginUpdater()->EnablePluginGroup(
+ enable_str == "true", group_name);
} else {
FilePath::StringType file_path;
- if (!list->GetString(0, &file_path))
+ if (!args->GetString(0, &file_path))
return;
- plugin_updater::EnablePluginFile(enable_str == "true", file_path);
+ PluginUpdater::GetPluginUpdater()->EnablePluginFile(
+ enable_str == "true", file_path);
}
// TODO(viettrungluu): We might also want to ensure that the plugins
// list is always written to prefs even when the user hasn't disabled a
// plugin. <http://crbug.com/39101>
- plugin_updater::UpdatePreferences(dom_ui_->GetProfile());
+ PluginUpdater::GetPluginUpdater()->UpdatePreferences(dom_ui_->GetProfile());
}
-void PluginsDOMHandler::HandleShowTermsOfServiceMessage(const Value* value) {
+void PluginsDOMHandler::HandleShowTermsOfServiceMessage(const ListValue* args) {
// Show it in a new browser window....
Browser* browser = Browser::Create(dom_ui_->GetProfile());
browser->OpenURL(GURL(chrome::kAboutTermsURL),
@@ -225,6 +223,16 @@ void PluginsDOMHandler::HandleShowTermsOfServiceMessage(const Value* value) {
browser->window()->Show();
}
+void PluginsDOMHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(NotificationType::PLUGIN_ENABLE_STATUS_CHANGED, type.value);
+ DictionaryValue results;
+ results.Set("plugins",
+ PluginUpdater::GetPluginUpdater()->GetPluginGroupsData());
+ dom_ui_->CallJavascriptFunction(L"returnPluginsData", results);
+}
+
} // namespace
///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/dom_ui/plugins_ui.h b/chrome/browser/dom_ui/plugins_ui.h
index 00dbce9..d2813a8 100644
--- a/chrome/browser/dom_ui/plugins_ui.h
+++ b/chrome/browser/dom_ui/plugins_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_PLUGINS_UI_H_
#define CHROME_BROWSER_DOM_UI_PLUGINS_UI_H_
+#pragma once
#include "chrome/browser/dom_ui/dom_ui.h"
diff --git a/chrome/browser/dom_ui/register_page_ui.cc b/chrome/browser/dom_ui/register_page_ui.cc
deleted file mode 100644
index 3cffc7a..0000000
--- a/chrome/browser/dom_ui/register_page_ui.cc
+++ /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 "chrome/browser/dom_ui/register_page_ui.h"
-
-#include <string>
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/string_piece.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "base/weak_ptr.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/url_constants.h"
-#include "grit/browser_resources.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/chromeos/customization_document.h"
-#include "chrome/browser/chromeos/login/wizard_controller.h"
-#include "chrome/browser/chromeos/version_loader.h"
-#endif
-
-namespace {
-// Constant value for os_name sent in setUserInfo.
-const wchar_t kOSName[] = L"ChromeOS";
-} // namespace
-
-class RegisterPageUIHTMLSource : public ChromeURLDataManager::DataSource {
- public:
- RegisterPageUIHTMLSource();
-
- // 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 {
- return "text/html";
- }
-
- private:
- ~RegisterPageUIHTMLSource() {}
-
- DISALLOW_COPY_AND_ASSIGN(RegisterPageUIHTMLSource);
-};
-
-// The handler for Javascript messages related to the "register" view.
-class RegisterPageHandler : public DOMMessageHandler,
- public base::SupportsWeakPtr<RegisterPageHandler> {
- public:
- RegisterPageHandler();
- virtual ~RegisterPageHandler();
-
- // Init work after Attach.
- void Init();
-
- // DOMMessageHandler implementation.
- virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
- virtual void RegisterMessages();
-
- private:
- // Handlers for JS DOMUI messages.
- void HandleGetRegistrationUrl(const Value* value);
- void HandleGetUserInfo(const Value* value);
-
-#if defined(OS_CHROMEOS)
- // Callback from chromeos::VersionLoader giving the version.
- void OnVersion(chromeos::VersionLoader::Handle handle, std::string version);
-#endif
-
- // Sends message to host registration page with system/user info data.
- void SendUserInfo();
-
-#if defined(OS_CHROMEOS)
- // Handles asynchronously loading the version.
- chromeos::VersionLoader version_loader_;
-#endif
-
- // Used to request the version.
- CancelableRequestConsumer version_consumer_;
-
- std::string version_;
-
- DISALLOW_COPY_AND_ASSIGN(RegisterPageHandler);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// RegisterPageUIHTMLSource
-//
-////////////////////////////////////////////////////////////////////////////////
-
-RegisterPageUIHTMLSource::RegisterPageUIHTMLSource()
- : DataSource(chrome::kChromeUIRegisterPageHost, MessageLoop::current()) {
-}
-
-void RegisterPageUIHTMLSource::StartDataRequest(const std::string& path,
- bool is_off_the_record,
- int request_id) {
- // Make sure that chrome://register is available only during
- // OOBE wizard lifetime.
-#if defined(OS_CHROMEOS)
- if (!WizardController::default_controller() &&
- !WizardController::default_controller()->is_oobe()) {
- scoped_refptr<RefCountedBytes> empty_bytes(new RefCountedBytes);
- SendResponse(request_id, empty_bytes);
- return;
- }
-
- static const base::StringPiece register_html(
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_HOST_REGISTRATION_PAGE_HTML));
-
- // TODO(nkostylev): Embed registration form URL from startup manifest.
- // http://crosbug.com/4645.
-
- scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
- html_bytes->data.resize(register_html.size());
- std::copy(register_html.begin(),
- register_html.end(),
- html_bytes->data.begin());
-
- SendResponse(request_id, html_bytes);
-#else
- scoped_refptr<RefCountedBytes> empty_bytes(new RefCountedBytes);
- SendResponse(request_id, empty_bytes);
-#endif
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// RegisterPageHandler
-//
-////////////////////////////////////////////////////////////////////////////////
-RegisterPageHandler::RegisterPageHandler() {
-}
-
-RegisterPageHandler::~RegisterPageHandler() {
-}
-
-DOMMessageHandler* RegisterPageHandler::Attach(DOMUI* dom_ui) {
- return DOMMessageHandler::Attach(dom_ui);
-}
-
-void RegisterPageHandler::Init() {
-}
-
-void RegisterPageHandler::RegisterMessages() {
-#if defined(OS_CHROMEOS)
- dom_ui_->RegisterMessageCallback("getRegistrationUrl",
- NewCallback(this, &RegisterPageHandler::HandleGetRegistrationUrl));
- dom_ui_->RegisterMessageCallback("getUserInfo",
- NewCallback(this, &RegisterPageHandler::HandleGetUserInfo));
-#endif
-}
-
-void RegisterPageHandler::HandleGetRegistrationUrl(const Value* value) {
-#if defined(OS_CHROMEOS)
- if (WizardController::default_controller() &&
- WizardController::default_controller()->GetCustomization()) {
- StringValue url_value(WizardController::default_controller()->
- GetCustomization()->registration_url());
- dom_ui_->CallJavascriptFunction(L"setRegistrationUrl", url_value);
- } else {
- LOG(ERROR) << "Startup manifest not defined.";
- }
-#endif
-}
-
-void RegisterPageHandler::HandleGetUserInfo(const Value* value) {
-#if defined(OS_CHROMEOS)
- if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
- version_loader_.GetVersion(
- &version_consumer_, NewCallback(this,
- &RegisterPageHandler::OnVersion));
- } else {
- LOG(ERROR) << "Error loading cros library.";
- }
-#endif
-}
-
-#if defined(OS_CHROMEOS)
-void RegisterPageHandler::OnVersion(chromeos::VersionLoader::Handle handle,
- std::string version) {
- version_ = version;
- SendUserInfo();
-}
-#endif
-
-void RegisterPageHandler::SendUserInfo() {
-#if defined(OS_CHROMEOS)
- DictionaryValue value;
- // TODO(nkostylev): Extract all available system/user info.
- // http://crosbug.com/4813
-
- std::string system_sku;
- if (WizardController::default_controller() &&
- WizardController::default_controller()->GetCustomization()) {
- system_sku = WizardController::default_controller()->
- GetCustomization()->product_sku();
- } else {
- LOG(ERROR) << "Startup manifest not defined.";
- }
-
- // Required info.
- value.SetString(L"system_hwqual", L"hardware qual identifier");
- value.SetString(L"system_sku", UTF8ToWide(system_sku));
- value.SetString(L"system_serial", L"serial number");
- value.SetString(L"os_language",
- UTF8ToWide(g_browser_process->GetApplicationLocale()));
- value.SetString(L"os_name", kOSName);
- value.SetString(L"os_version", UTF8ToWide(version_));
- value.SetString(L"os_connection", L"connection type");
- value.SetString(L"user_email", L"");
-
- // Optional info.
- value.SetString(L"user_first_name", L"");
- value.SetString(L"user_last_name", L"");
-
- dom_ui_->CallJavascriptFunction(L"setUserInfo", value);
-#endif
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// RegisterPageUI
-//
-////////////////////////////////////////////////////////////////////////////////
-
-RegisterPageUI::RegisterPageUI(TabContents* contents) : DOMUI(contents){
- RegisterPageHandler* handler = new RegisterPageHandler();
- AddMessageHandler((handler)->Attach(this));
- handler->Init();
- RegisterPageUIHTMLSource* html_source = new RegisterPageUIHTMLSource();
-
- // Set up the chrome://register/ source.
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
- &ChromeURLDataManager::AddDataSource,
- make_scoped_refptr(html_source)));
-}
diff --git a/chrome/browser/dom_ui/register_page_ui.h b/chrome/browser/dom_ui/register_page_ui.h
deleted file mode 100644
index 46abc58..0000000
--- a/chrome/browser/dom_ui/register_page_ui.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_DOM_UI_REGISTER_PAGE_UI_H_
-#define CHROME_BROWSER_DOM_UI_REGISTER_PAGE_UI_H_
-
-#include "chrome/browser/dom_ui/dom_ui.h"
-
-// A custom DOMUI that defines datasource for host registration page that
-// is used in Chrome OS to register product on first sign in.
-class RegisterPageUI : public DOMUI {
- public:
- explicit RegisterPageUI(TabContents* contents);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(RegisterPageUI);
-};
-
-#endif // CHROME_BROWSER_DOM_UI_REGISTER_PAGE_UI_H_
diff --git a/chrome/browser/dom_ui/remoting_ui.h b/chrome/browser/dom_ui/remoting_ui.h
index 1d98b98..8012a82 100644
--- a/chrome/browser/dom_ui/remoting_ui.h
+++ b/chrome/browser/dom_ui/remoting_ui.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_REMOTING_UI_H_
#define CHROME_BROWSER_DOM_UI_REMOTING_UI_H_
+#pragma once
#include "chrome/browser/dom_ui/dom_ui.h"
diff --git a/chrome/browser/dom_ui/shared_resources_data_source.h b/chrome/browser/dom_ui/shared_resources_data_source.h
index 0dfe83a..712795e 100644
--- a/chrome/browser/dom_ui/shared_resources_data_source.h
+++ b/chrome/browser/dom_ui/shared_resources_data_source.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOM_UI_SHARED_RESOURCES_DATA_SOURCE_H_
#define CHROME_BROWSER_DOM_UI_SHARED_RESOURCES_DATA_SOURCE_H_
+#pragma once
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
diff --git a/chrome/browser/dom_ui/shown_sections_handler.cc b/chrome/browser/dom_ui/shown_sections_handler.cc
index 9bfd22e..e32511d 100644
--- a/chrome/browser/dom_ui/shown_sections_handler.cc
+++ b/chrome/browser/dom_ui/shown_sections_handler.cc
@@ -6,10 +6,10 @@
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
@@ -23,8 +23,8 @@ namespace {
// was changed to hide/show the most visited thumbnails.
void NotifySectionDisabled(int new_mode, int old_mode, Profile *profile) {
// If the oldmode HAD either thumbs or lists visible.
- bool old_had_it = (old_mode & THUMB) || (old_mode & LIST);
- bool new_has_it = (new_mode & THUMB) || (new_mode & LIST);
+ bool old_had_it = old_mode & THUMB;
+ bool new_has_it = new_mode & THUMB;
if (old_had_it && !new_has_it) {
UserMetrics::RecordAction(
@@ -41,13 +41,15 @@ void NotifySectionDisabled(int new_mode, int old_mode, Profile *profile) {
} // namespace
-ShownSectionsHandler::ShownSectionsHandler(PrefService* pref_service)
- : pref_service_(pref_service) {
- pref_service_->AddPrefObserver(prefs::kNTPShownSections, this);
+// static
+int ShownSectionsHandler::GetShownSections(PrefService* prefs) {
+ return prefs->GetInteger(prefs::kNTPShownSections);
}
-ShownSectionsHandler::~ShownSectionsHandler() {
- pref_service_->RemovePrefObserver(prefs::kNTPShownSections, this);
+ShownSectionsHandler::ShownSectionsHandler(PrefService* pref_service)
+ : pref_service_(pref_service) {
+ registrar_.Init(pref_service);
+ registrar_.Add(prefs::kNTPShownSections, this);
}
void ShownSectionsHandler::RegisterMessages() {
@@ -61,7 +63,7 @@ void ShownSectionsHandler::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(NotificationType::PREF_CHANGED == type);
- std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ std::string* pref_name = Details<std::string>(details).ptr();
DCHECK(*pref_name == prefs::kNTPShownSections);
int sections = pref_service_->GetInteger(prefs::kNTPShownSections);
@@ -69,30 +71,15 @@ void ShownSectionsHandler::Observe(NotificationType type,
dom_ui_->CallJavascriptFunction(L"setShownSections", sections_value);
}
-void ShownSectionsHandler::HandleGetShownSections(const Value* value) {
- int sections = pref_service_->GetInteger(prefs::kNTPShownSections);
+void ShownSectionsHandler::HandleGetShownSections(const ListValue* args) {
+ int sections = GetShownSections(pref_service_);
FundamentalValue sections_value(sections);
dom_ui_->CallJavascriptFunction(L"onShownSections", sections_value);
}
-void ShownSectionsHandler::HandleSetShownSections(const Value* value) {
- if (!value->IsType(Value::TYPE_LIST)) {
- NOTREACHED();
- return;
- }
-
- const ListValue* list = static_cast<const ListValue*>(value);
- std::string mode_string;
-
- if (list->GetSize() < 1) {
- NOTREACHED() << "setShownSections called with too few arguments";
- return;
- }
-
- bool r = list->GetString(0, &mode_string);
- DCHECK(r) << "Missing value in setShownSections from the NTP Most Visited.";
-
- int mode = StringToInt(mode_string);
+void ShownSectionsHandler::HandleSetShownSections(const ListValue* args) {
+ int mode;
+ CHECK(ExtractIntegerValue(args, &mode));
int old_mode = pref_service_->GetInteger(prefs::kNTPShownSections);
if (old_mode != mode) {
@@ -103,8 +90,7 @@ void ShownSectionsHandler::HandleSetShownSections(const Value* value) {
// static
void ShownSectionsHandler::RegisterUserPrefs(PrefService* pref_service) {
- pref_service->RegisterIntegerPref(prefs::kNTPShownSections,
- THUMB | RECENT | TIPS | SYNC);
+ pref_service->RegisterIntegerPref(prefs::kNTPShownSections, THUMB);
}
// static
@@ -114,17 +100,15 @@ void ShownSectionsHandler::MigrateUserPrefs(PrefService* pref_service,
bool changed = false;
int shown_sections = pref_service->GetInteger(prefs::kNTPShownSections);
- if (old_pref_version < 1) {
- // TIPS was used in early builds of the NNTP but since it was removed before
- // Chrome 3.0 we want to ensure that it is shown by default.
- shown_sections |= TIPS | SYNC;
- changed = true;
- }
+ if (old_pref_version < 3) {
+ // In version 3, we went from being able to show multiple sections to being
+ // able to show only one expanded at a time. The only two expandable
+ // sections are APPS and THUMBS.
+ if (shown_sections & APPS)
+ shown_sections = APPS;
+ else
+ shown_sections = THUMB;
- if (old_pref_version < 2) {
- // LIST is no longer used. Change to THUMB.
- shown_sections &= ~LIST;
- shown_sections |= THUMB;
changed = true;
}
diff --git a/chrome/browser/dom_ui/shown_sections_handler.h b/chrome/browser/dom_ui/shown_sections_handler.h
index 8bdbd52..a281346 100644
--- a/chrome/browser/dom_ui/shown_sections_handler.h
+++ b/chrome/browser/dom_ui/shown_sections_handler.h
@@ -1,32 +1,35 @@
-// 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.
#ifndef CHROME_BROWSER_DOM_UI_SHOWN_SECTIONS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_SHOWN_SECTIONS_HANDLER_H_
+#pragma once
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/common/notification_observer.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
class DOMUI;
class Value;
class PrefService;
// Use for the shown sections bitmask.
+// Currently, only the THUMB and APPS sections can be toggled by the user. Other
+// sections are shown automatically if they have data, and hidden otherwise.
enum Section {
THUMB = 1,
- LIST = 2,
- RECENT = 4,
- TIPS = 8,
- SYNC = 16,
- DEBUG = 32
+ APPS = 64
};
class ShownSectionsHandler : public DOMMessageHandler,
public NotificationObserver {
public:
explicit ShownSectionsHandler(PrefService* pref_service);
- virtual ~ShownSectionsHandler();
+ virtual ~ShownSectionsHandler() {}
+
+ // Helper to get the current shown sections.
+ static int GetShownSections(PrefService* pref_service);
// DOMMessageHandler implementation.
virtual void RegisterMessages();
@@ -37,10 +40,10 @@ class ShownSectionsHandler : public DOMMessageHandler,
const NotificationDetails& details);
// Callback for "getShownSections" message.
- void HandleGetShownSections(const Value* value);
+ void HandleGetShownSections(const ListValue* args);
// Callback for "setShownSections" message.
- void HandleSetShownSections(const Value* value);
+ void HandleSetShownSections(const ListValue* args);
static void RegisterUserPrefs(PrefService* pref_service);
@@ -50,6 +53,7 @@ class ShownSectionsHandler : public DOMMessageHandler,
private:
PrefService* pref_service_;
+ PrefChangeRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(ShownSectionsHandler);
};
diff --git a/chrome/browser/dom_ui/shown_sections_handler_unittest.cc b/chrome/browser/dom_ui/shown_sections_handler_unittest.cc
index 934c55a..9e89b1b 100644
--- a/chrome/browser/dom_ui/shown_sections_handler_unittest.cc
+++ b/chrome/browser/dom_ui/shown_sections_handler_unittest.cc
@@ -4,10 +4,9 @@
#include "chrome/browser/dom_ui/shown_sections_handler.h"
-#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_value_store.h"
+#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
@@ -16,35 +15,30 @@
class ShownSectionsHandlerTest : public testing::Test {
};
-TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs) {
- scoped_ptr<PrefService> pref(new TestingPrefService);
-
- // Set an *old* value
- pref->RegisterIntegerPref(prefs::kNTPShownSections, 0);
- pref->SetInteger(prefs::kNTPShownSections, THUMB);
+namespace {
- ShownSectionsHandler::MigrateUserPrefs(pref.get(), 0, 1);
-
- int shown_sections = pref->GetInteger(prefs::kNTPShownSections);
+int MigratePrefValue(PrefService* prefs, int starting_value) {
+ prefs->SetInteger(prefs::kNTPShownSections, starting_value);
+ ShownSectionsHandler::MigrateUserPrefs(prefs, 1, 3);
+ return prefs->GetInteger(prefs::kNTPShownSections);
+}
- EXPECT_TRUE(shown_sections & THUMB);
- EXPECT_FALSE(shown_sections & LIST);
- EXPECT_FALSE(shown_sections & RECENT);
- EXPECT_TRUE(shown_sections & TIPS);
- EXPECT_TRUE(shown_sections & SYNC);
}
-TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs1To2) {
+TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs) {
scoped_ptr<PrefService> pref(new TestingPrefService);
- // Set an *old* value
pref->RegisterIntegerPref(prefs::kNTPShownSections, 0);
- pref->SetInteger(prefs::kNTPShownSections, LIST);
- ShownSectionsHandler::MigrateUserPrefs(pref.get(), 1, 2);
+ EXPECT_EQ(APPS, MigratePrefValue(pref.get(), APPS));
+ EXPECT_EQ(THUMB, MigratePrefValue(pref.get(), THUMB));
+ EXPECT_EQ(APPS, MigratePrefValue(pref.get(), APPS | THUMB));
- int shown_sections = pref->GetInteger(prefs::kNTPShownSections);
+ // 2 is not currently used, but older state may contain it and we should do
+ // something reasonable.
+ EXPECT_EQ(THUMB, MigratePrefValue(pref.get(), 3));
- EXPECT_TRUE(shown_sections & THUMB);
- EXPECT_FALSE(shown_sections & LIST);
+ // 0 can't correspond to any section, but we should still do something
+ // reasonable.
+ EXPECT_EQ(THUMB, MigratePrefValue(pref.get(), 0));
}
diff --git a/chrome/browser/dom_ui/slideshow_ui.cc b/chrome/browser/dom_ui/slideshow_ui.cc
index 79fab3b..1e6543f 100644
--- a/chrome/browser/dom_ui/slideshow_ui.cc
+++ b/chrome/browser/dom_ui/slideshow_ui.cc
@@ -1,19 +1,18 @@
-// 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.
#include "chrome/browser/dom_ui/slideshow_ui.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/weak_ptr.h"
#include "chrome/browser/chrome_thread.h"
@@ -33,10 +32,10 @@
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
-static const std::wstring kPropertyPath = L"path";
-static const std::wstring kPropertyTitle = L"title";
-static const std::wstring kPropertyOffset = L"currentOffset";
-static const std::wstring kPropertyDirectory = L"isDirectory";
+static const char kPropertyPath[] = "path";
+static const char kPropertyTitle[] = "title";
+static const char kPropertyOffset[] = "currentOffset";
+static const char kPropertyDirectory[] = "isDirectory";
class SlideshowUIHTMLSource : public ChromeURLDataManager::DataSource {
public:
@@ -69,19 +68,20 @@ class SlideshowHandler : public net::DirectoryLister::DirectoryListerDelegate,
void Init();
// DirectoryLister::DirectoryListerDelegate methods:
- virtual void OnListFile(const file_util::FileEnumerator::FindInfo& data);
+ virtual void OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data);
virtual void OnListDone(int error);
// DOMMessageHandler implementation.
virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
virtual void RegisterMessages();
- void GetChildrenForPath(FilePath& path, bool is_refresh);
+ void GetChildrenForPath(const FilePath& path, bool is_refresh);
// Callback for the "getChildren" message.
- void HandleGetChildren(const Value* value);
+ void HandleGetChildren(const ListValue* args);
- void HandleRefreshDirectory(const Value* value);
+ void HandleRefreshDirectory(const ListValue* args);
private:
bool PathIsImageFile(const char* filename);
@@ -169,28 +169,17 @@ void SlideshowHandler::RegisterMessages() {
NewCallback(this, &SlideshowHandler::HandleRefreshDirectory));
}
-void SlideshowHandler::HandleRefreshDirectory(const Value* value) {
+void SlideshowHandler::HandleRefreshDirectory(const ListValue* args) {
#if defined(OS_CHROMEOS)
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- std::string path;
-
- // Get path string.
- if (list_value->GetString(0, &path)) {
- FilePath currentpath;
- currentpath = FilePath(path);
- GetChildrenForPath(currentpath, true);
- } else {
- LOG(ERROR) << "Unable to get string";
- return;
- }
- }
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ GetChildrenForPath(FilePath(path), true);
#endif
}
-void SlideshowHandler::GetChildrenForPath(FilePath& path, bool is_refresh) {
+void SlideshowHandler::GetChildrenForPath(const FilePath& path,
+ bool is_refresh) {
filelist_value_.reset(new ListValue());
- currentpath_ = FilePath(path);
+ currentpath_ = path;
if (lister_.get()) {
lister_->Cancel();
@@ -212,29 +201,11 @@ void SlideshowHandler::GetChildrenForPath(FilePath& path, bool is_refresh) {
lister_->Start();
}
-void SlideshowHandler::HandleGetChildren(const Value* value) {
+void SlideshowHandler::HandleGetChildren(const ListValue* args) {
#if defined(OS_CHROMEOS)
- std::string path;
- if (value && value->GetType() == Value::TYPE_LIST) {
- const ListValue* list_value = static_cast<const ListValue*>(value);
- Value* list_member;
-
- // Get search string.
- if (list_value->Get(0, &list_member) &&
- list_member->GetType() == Value::TYPE_STRING) {
- const StringValue* string_value =
- static_cast<const StringValue*>(list_member);
- string_value->GetAsString(&path);
- }
-
- } else {
- LOG(ERROR) << "Wasn't able to get the List if requested files.";
- return;
- }
filelist_value_.reset(new ListValue());
- FilePath currentpath;
- currentpath = FilePath(path);
- GetChildrenForPath(currentpath, false);
+ std::string path = WideToUTF8(ExtractStringValue(args));
+ GetChildrenForPath(FilePath(path), false);
#endif
}
@@ -257,21 +228,21 @@ bool SlideshowHandler::PathIsImageFile(const char* filename) {
}
void SlideshowHandler::OnListFile(
- const file_util::FileEnumerator::FindInfo& data) {
+ const net::DirectoryLister::DirectoryListerData& data) {
#if defined(OS_CHROMEOS)
- if (data.filename[0] == '.') {
+ if (data.info.filename[0] == '.') {
return;
}
- if (!PathIsImageFile(data.filename.c_str())) {
+ if (!PathIsImageFile(data.info.filename.c_str())) {
return;
}
DictionaryValue* file_value = new DictionaryValue();
- file_value->SetString(kPropertyTitle, data.filename);
+ file_value->SetString(kPropertyTitle, data.info.filename);
file_value->SetString(kPropertyPath,
- currentpath_.Append(data.filename).value());
- file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.stat.st_mode));
+ currentpath_.Append(data.info.filename).value());
+ file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.info.stat.st_mode));
filelist_value_->Append(file_value);
std::string val;
file_value->GetString(kPropertyTitle, &val);
@@ -291,9 +262,9 @@ void SlideshowHandler::OnListDone(int error) {
info_value.SetInteger(kPropertyOffset, currentOffset_);
}
if (is_refresh_) {
- info_value.SetString(L"functionCall", "refresh");
+ info_value.SetString("functionCall", "refresh");
} else {
- info_value.SetString(L"functionCall", "getChildren");
+ info_value.SetString("functionCall", "getChildren");
}
info_value.SetString(kPropertyPath, currentpath_.value());
dom_ui_->CallJavascriptFunction(L"browseFileResult",
@@ -306,7 +277,7 @@ void SlideshowHandler::OnListDone(int error) {
//
////////////////////////////////////////////////////////////////////////////////
-SlideshowUI::SlideshowUI(TabContents* contents) : DOMUI(contents){
+SlideshowUI::SlideshowUI(TabContents* contents) : DOMUI(contents) {
SlideshowHandler* handler = new SlideshowHandler();
AddMessageHandler((handler)->Attach(this));
handler->Init();
diff --git a/chrome/browser/dom_ui/slideshow_ui.h b/chrome/browser/dom_ui/slideshow_ui.h
index 1374045..51fbeb0 100644
--- a/chrome/browser/dom_ui/slideshow_ui.h
+++ b/chrome/browser/dom_ui/slideshow_ui.h
@@ -4,12 +4,8 @@
#ifndef CHROME_BROWSER_DOM_UI_SLIDESHOW_UI_H_
#define CHROME_BROWSER_DOM_UI_SLIDESHOW_UI_H_
+#pragma once
-#include <vector>
-
-#include "base/file_path.h"
-#include "base/scoped_ptr.h"
-#include "base/values.h"
#include "chrome/browser/dom_ui/dom_ui.h"
class SlideshowUI : public DOMUI {
diff --git a/chrome/browser/dom_ui/tips_handler.cc b/chrome/browser/dom_ui/tips_handler.cc
index 6a8a2f4..9bf5bdf 100644
--- a/chrome/browser/dom_ui/tips_handler.cc
+++ b/chrome/browser/dom_ui/tips_handler.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.
@@ -21,7 +21,7 @@
DOMMessageHandler* TipsHandler::Attach(DOMUI* dom_ui) {
dom_ui_ = dom_ui;
tips_cache_ = dom_ui_->GetProfile()->GetPrefs()->
- GetMutableDictionary(prefs::kNTPTipsCache);
+ GetMutableDictionary(prefs::kNTPWebResourceCache);
return DOMMessageHandler::Attach(dom_ui);
}
@@ -30,7 +30,7 @@ void TipsHandler::RegisterMessages() {
NewCallback(this, &TipsHandler::HandleGetTips));
}
-void TipsHandler::HandleGetTips(const Value* content) {
+void TipsHandler::HandleGetTips(const ListValue* args) {
// List containing the tips to be displayed.
ListValue list_value;
@@ -45,8 +45,9 @@ void TipsHandler::HandleGetTips(const Value* content) {
// We need to check here because the new tab page calls for tips before
// the tip service starts up.
PrefService* current_prefs = dom_ui_->GetProfile()->GetPrefs();
- if (current_prefs->HasPrefPath(prefs::kNTPTipsServer)) {
- std::string server = current_prefs->GetString(prefs::kNTPTipsServer);
+ if (current_prefs->HasPrefPath(prefs::kNTPTipsResourceServer)) {
+ std::string server = current_prefs->GetString(
+ prefs::kNTPTipsResourceServer);
std::string locale = g_browser_process->GetApplicationLocale();
if (!EndsWith(server, locale, false)) {
dom_ui_->CallJavascriptFunction(L"tips", list_value);
@@ -54,17 +55,6 @@ void TipsHandler::HandleGetTips(const Value* content) {
}
}
- // If the user has just started using Chrome with a fresh profile, send only
- // the "Import bookmarks" promo until the user has either seen it five times
- // or added or imported bookmarks.
- if (current_prefs->GetInteger(prefs::kNTPPromoViewsRemaining) > 0) {
- SendTip(WideToUTF8(l10n_util::GetStringF(IDS_IMPORT_BOOKMARKS_PROMO,
- std::wstring(L"<button class='link'>"),
- std::wstring(L"</button>"))),
- L"set_promo_tip", 0);
- return;
- }
-
if (tips_cache_ != NULL && !tips_cache_->empty()) {
if (tips_cache_->GetInteger(
WebResourceService::kCurrentTipPrefName, &current_tip_index) &&
@@ -81,20 +71,19 @@ void TipsHandler::HandleGetTips(const Value* content) {
bool value;
if (pref && !pref->IsManaged() &&
pref->GetValue()->GetAsBoolean(&value) && !value) {
- SendTip(WideToUTF8(l10n_util::GetString(
- IDS_NEW_TAB_MAKE_THIS_HOMEPAGE)), L"set_homepage_tip",
- current_tip_index);
+ SendTip(l10n_util::GetStringUTF8(IDS_NEW_TAB_MAKE_THIS_HOMEPAGE),
+ "set_homepage_tip", current_tip_index);
return;
}
}
if (wr_list->GetString(current_tip_index, &current_tip)) {
- SendTip(current_tip, L"tip_html_text", current_tip_index + 1);
+ SendTip(current_tip, "tip_html_text", current_tip_index + 1);
}
}
}
}
-void TipsHandler::SendTip(std::string tip, std::wstring tip_type,
+void TipsHandler::SendTip(const std::string& tip, const std::string& tip_type,
int tip_index) {
// List containing the tips to be displayed.
ListValue list_value;
@@ -109,8 +98,8 @@ void TipsHandler::SendTip(std::string tip, std::wstring tip_type,
// static
void TipsHandler::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterDictionaryPref(prefs::kNTPTipsCache);
- prefs->RegisterStringPref(prefs::kNTPTipsServer,
+ prefs->RegisterDictionaryPref(prefs::kNTPWebResourceCache);
+ prefs->RegisterStringPref(prefs::kNTPLogoResourceServer,
WebResourceService::kDefaultResourceServer);
}
diff --git a/chrome/browser/dom_ui/tips_handler.h b/chrome/browser/dom_ui/tips_handler.h
index d85d4d8..b02f233 100644
--- a/chrome/browser/dom_ui/tips_handler.h
+++ b/chrome/browser/dom_ui/tips_handler.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 @@
#ifndef CHROME_BROWSER_DOM_UI_TIPS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_TIPS_HANDLER_H_
+#pragma once
#include <string>
@@ -15,8 +16,8 @@
class DictionaryValue;
class DOMUI;
+class ListValue;
class PrefService;
-class Value;
class TipsHandler : public DOMMessageHandler {
public:
@@ -28,7 +29,7 @@ class TipsHandler : public DOMMessageHandler {
virtual void RegisterMessages();
// Callback which pulls tips data from the preferences.
- void HandleGetTips(const Value* content);
+ void HandleGetTips(const ListValue* args);
// Register tips cache with pref service.
static void RegisterUserPrefs(PrefService* prefs);
@@ -40,7 +41,8 @@ class TipsHandler : public DOMMessageHandler {
// Send a tip to the NTP. tip_type is "tip_html_text" if the tip is from
// the tip server, and "set_homepage_tip" if it's the tip to set the NTP
// as home page.
- void SendTip(std::string tip, std::wstring tip_type, int tip_index);
+ void SendTip(const std::string& tip, const std::string& tip_type,
+ int tip_index);
// So we can push data out to the page that has called this handler.
DOMUI* dom_ui_;
diff --git a/chrome/browser/download/download_exe.cc b/chrome/browser/download/download_exe.cc
index 1d1536f..69ce1c5 100644
--- a/chrome/browser/download/download_exe.cc
+++ b/chrome/browser/download/download_exe.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,8 +7,9 @@
#include "chrome/browser/download/download_util.h"
-#include "base/logging.h"
#include "base/string_util.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_util.h"
namespace download_util {
@@ -141,6 +142,7 @@ static const char* const g_executables[] = {
"wsc",
"wsf",
"wsh",
+ "xbap",
"xht",
"xhtm",
"xhtml",
@@ -166,12 +168,62 @@ static const char* const g_executables[] = {
#endif
};
-bool IsExecutableExtension(const std::string& extension) {
+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(extension, 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=*",
+ // Registry files can cause critical changes to the MS OS behavior.
+ // Addition of this mimetype also addresses bug 7337.
+ "text/x-registry",
+ // 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_file.cc b/chrome/browser/download/download_file.cc
index ebdaa1c..6bf41c7 100644
--- a/chrome/browser/download/download_file.cc
+++ b/chrome/browser/download/download_file.cc
@@ -5,191 +5,36 @@
#include "chrome/browser/download/download_file.h"
#include "base/file_util.h"
-#include "build/build_config.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/history/download_types.h"
-#include "net/base/net_errors.h"
-
-#if defined(OS_WIN)
-#include "app/win_util.h"
-#include "chrome/common/win_safe_util.h"
-#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/file_metadata.h"
-#endif
-
-DownloadFile::DownloadFile(const DownloadCreateInfo* info)
- : file_stream_(info->save_info.file_stream),
- source_url_(info->url),
- referrer_url_(info->referrer_url),
+#include "chrome/browser/history/download_create_info.h"
+
+DownloadFile::DownloadFile(const DownloadCreateInfo* info,
+ DownloadManager* download_manager)
+ : BaseFile(info->save_info.file_path,
+ info->url,
+ info->referrer_url,
+ info->received_bytes,
+ info->save_info.file_stream),
id_(info->download_id),
child_id_(info->child_id),
request_id_(info->request_id),
- full_path_(info->save_info.file_path),
- path_renamed_(false),
- dont_sleep_(true) {
+ download_manager_(download_manager) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-}
-
-DownloadFile::~DownloadFile() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- Close();
-}
-
-bool DownloadFile::Initialize() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- if (!full_path_.empty() ||
- download_util::CreateTemporaryFileForDownload(&full_path_))
- return Open();
- return false;
-}
-
-bool DownloadFile::AppendDataToFile(const char* data, size_t data_len) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-
- if (!file_stream_.get())
- return false;
- // FIXME bug 595247: handle errors on file writes.
- size_t written = file_stream_->Write(data, data_len, NULL);
- return (written == data_len);
}
-void DownloadFile::Cancel() {
+DownloadFile::~DownloadFile() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- Close();
- if (!full_path_.empty())
- file_util::Delete(full_path_, false);
-}
-
-// The UI has provided us with our finalized name.
-bool DownloadFile::Rename(const FilePath& new_path, bool is_final_rename) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-
- // Save the information whether the download is in progress because
- // it will be overwritten by closing the file.
- bool saved_in_progress = in_progress();
-
- // If the new path is same as the old one, there is no need to perform the
- // following renaming logic.
- if (new_path == full_path_) {
- path_renamed_ = is_final_rename;
-
- // Don't close the file if we're not done (finished or canceled).
- if (!saved_in_progress)
- Close();
-
- return true;
- }
-
- Close();
-
- file_util::CreateDirectory(new_path.DirName());
-
-#if defined(OS_WIN)
- // We cannot rename because rename will keep the same security descriptor
- // on the destination file. We want to recreate the security descriptor
- // with the security that makes sense in the new path.
- if (!file_util::RenameFileAndResetSecurityDescriptor(full_path_, new_path))
- return false;
-#elif defined(OS_POSIX)
- {
- // Similarly, on Unix, we're moving a temp file created with permissions
- // 600 to |new_path|. Here, we try to fix up the destination file with
- // appropriate permissions.
- struct stat st;
- // First check the file existence and create an empty file if it doesn't
- // exist.
- if (!file_util::PathExists(new_path))
- file_util::WriteFile(new_path, "", 0);
- bool stat_succeeded = (stat(new_path.value().c_str(), &st) == 0);
-
- // TODO(estade): Move() falls back to copying and deleting when a simple
- // rename fails. Copying sucks for large downloads. crbug.com/8737
- if (!file_util::Move(full_path_, new_path))
- return false;
-
- if (stat_succeeded)
- chmod(new_path.value().c_str(), st.st_mode);
- }
-#endif
-
- full_path_ = new_path;
- path_renamed_ = is_final_rename;
-
- // We don't need to re-open the file if we're done (finished or canceled).
- if (!saved_in_progress)
- return true;
-
- if (!Open())
- return false;
-
- // Move to the end of the new file.
- if (file_stream_->Seek(net::FROM_END, 0) < 0)
- return false;
-
- return true;
}
void DownloadFile::DeleteCrDownload() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
FilePath crdownload = download_util::GetCrDownloadPath(full_path_);
file_util::Delete(crdownload, false);
}
-void DownloadFile::Finish() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- Close();
-}
-
-void DownloadFile::Close() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- if (file_stream_.get()) {
-#if defined(OS_CHROMEOS)
- // Currently we don't really care about the return value, since if it fails
- // theres not much we can do. But we might in the future.
- file_stream_->Flush();
-#endif
- file_stream_->Close();
- file_stream_.reset();
- }
-}
-
-bool DownloadFile::Open() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- DCHECK(!full_path_.empty());
-
- // Create a new file steram if it is not provided.
- if (!file_stream_.get()) {
- file_stream_.reset(new net::FileStream);
- if (file_stream_->Open(full_path_,
- base::PLATFORM_FILE_OPEN_ALWAYS |
- base::PLATFORM_FILE_WRITE) != net::OK) {
- file_stream_.reset();
- return false;
- }
- }
-
-#if defined(OS_WIN)
- AnnotateWithSourceInformation();
-#endif
- return true;
-}
-
-void DownloadFile::AnnotateWithSourceInformation() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-#if defined(OS_WIN)
- // Sets the Zone to tell Windows that this file comes from the internet.
- // We ignore the return value because a failure is not fatal.
- win_util::SetInternetZoneIdentifier(full_path_);
-#elif defined(OS_MACOSX)
- file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_,
- referrer_url_);
- file_metadata::AddOriginMetadataToFile(full_path_, source_url_,
- referrer_url_);
-#endif
-}
-
void DownloadFile::CancelDownloadRequest(ResourceDispatcherHost* rdh) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
ChromeThread::PostTask(
@@ -199,3 +44,8 @@ void DownloadFile::CancelDownloadRequest(ResourceDispatcherHost* rdh) {
child_id_,
request_id_));
}
+
+DownloadManager* DownloadFile::GetDownloadManager() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ return download_manager_.get();
+}
diff --git a/chrome/browser/download/download_file.h b/chrome/browser/download/download_file.h
index 9c9fdf6..46ba40d 100644
--- a/chrome/browser/download/download_file.h
+++ b/chrome/browser/download/download_file.h
@@ -4,51 +4,27 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_H_
-
-#include <map>
-#include <string>
-#include <vector>
+#pragma once
#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/hash_tables.h"
-#include "base/linked_ptr.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/download/base_file.h"
#include "chrome/browser/download/download_types.h"
-#include "chrome/browser/power_save_blocker.h"
-#include "googleurl/src/gurl.h"
struct DownloadCreateInfo;
+class DownloadManager;
class ResourceDispatcherHost;
// These objects live exclusively on the download thread and handle the writing
// operations for one download. These objects live only for the duration that
// the download is 'in progress': once the download has been completed or
// cancelled, the DownloadFile is destroyed.
-class DownloadFile {
+class DownloadFile : public BaseFile {
public:
- explicit DownloadFile(const DownloadCreateInfo* info);
+ DownloadFile(const DownloadCreateInfo* info,
+ DownloadManager* download_manager);
virtual ~DownloadFile();
- bool Initialize();
-
- // Write a new chunk of data to the file. Returns true on success (all bytes
- // written to the file).
- bool AppendDataToFile(const char* data, size_t data_len);
-
- // Abort the download and automatically close the file.
- void Cancel();
-
- // Rename the download file. Returns 'true' if the rename was successful.
- // path_renamed_ is set true only if |is_final_rename| is true.
- // Marked virtual for testing.
- virtual bool Rename(const FilePath& full_path, bool is_final_rename);
-
- // Indicate that the download has finished. No new data will be received.
- void Finish();
-
- // Informs the OS that this file came from the internet.
- void AnnotateWithSourceInformation();
-
// Deletes its .crdownload intermediate file.
// Marked virtual for testing.
virtual void DeleteCrDownload();
@@ -56,27 +32,10 @@ class DownloadFile {
// Cancels the download request associated with this file.
void CancelDownloadRequest(ResourceDispatcherHost* rdh);
- // Accessors.
int id() const { return id_; }
- bool path_renamed() const { return path_renamed_; }
- bool in_progress() const { return file_stream_ != NULL; }
+ DownloadManager* GetDownloadManager();
private:
- // Open or Close the OS file stream. The stream is opened in the constructor
- // based on creation information passed to it, and automatically closed in
- // the destructor.
- void Close();
- bool Open();
-
- // OS file stream for writing
- linked_ptr<net::FileStream> file_stream_;
-
- // Source URL for the file being downloaded.
- GURL source_url_;
-
- // The URL where the download was initiated.
- GURL referrer_url_;
-
// The unique identifier for this download, assigned at creation by
// the DownloadFileManager for its internal record keeping.
int id_;
@@ -87,14 +46,8 @@ class DownloadFile {
// Handle for informing the ResourceDispatcherHost of a UI based cancel.
int request_id_;
- // Full path to the downloaded file.
- FilePath full_path_;
-
- // Whether the download is still using its initial temporary path.
- bool path_renamed_;
-
- // RAII handle to keep the system from sleeping while we're downloading.
- PowerSaveBlocker dont_sleep_;
+ // DownloadManager this download belongs to.
+ scoped_refptr<DownloadManager> download_manager_;
DISALLOW_COPY_AND_ASSIGN(DownloadFile);
};
diff --git a/chrome/browser/download/download_file_manager.cc b/chrome/browser/download/download_file_manager.cc
index d9ba1f2..fc94314 100644
--- a/chrome/browser/download/download_file_manager.cc
+++ b/chrome/browser/download/download_file_manager.cc
@@ -5,13 +5,14 @@
#include "chrome/browser/download/download_file_manager.h"
#include "base/file_util.h"
+#include "base/stl_util-inl.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/history/download_types.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"
@@ -19,6 +20,7 @@
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
+#include "net/base/io_buffer.h"
#if defined(OS_WIN)
#include "app/win_util.h"
@@ -33,6 +35,21 @@ namespace {
// cause it to become unresponsive (in milliseconds).
const int kUpdatePeriodMs = 500;
+DownloadManager* DownloadManagerForRenderViewHost(int render_process_id,
+ int render_view_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
+ render_view_id);
+ if (contents) {
+ Profile* profile = contents->profile();
+ if (profile)
+ return profile->GetDownloadManager();
+ }
+
+ return NULL;
+}
+
} // namespace
DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh)
@@ -41,45 +58,29 @@ DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh)
}
DownloadFileManager::~DownloadFileManager() {
- // Check for clean shutdown.
DCHECK(downloads_.empty());
}
-// Called during the browser shutdown process to clean up any state (open files,
-// timers) that live on the download_thread_.
void DownloadFileManager::Shutdown() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- StopUpdateTimer();
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(this, &DownloadFileManager::OnShutdown));
}
-// Cease download thread operations.
void DownloadFileManager::OnShutdown() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- // Delete any partial downloads during shutdown.
- for (DownloadFileMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- DownloadFile* download = it->second;
- if (download->in_progress())
- download->Cancel();
- delete download;
- }
- downloads_.clear();
+ StopUpdateTimer();
+ STLDeleteValues(&downloads_);
}
-// Notifications sent from the download thread and run on the UI thread.
+void DownloadFileManager::CreateDownloadFile(
+ DownloadCreateInfo* info, DownloadManager* download_manager) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-// Lookup the DownloadManager for this TabContents' profile and inform it of
-// a new download.
-// TODO(paulg): When implementing download restart via the Downloads tab,
-// there will be no 'render_process_id' or 'render_view_id'.
-void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id,
- info->render_view_id);
- if (!manager) {
+ scoped_ptr<DownloadFile> download_file(
+ new DownloadFile(info, download_manager));
+ if (!download_file->Initialize()) {
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableFunction(&download_util::CancelDownloadRequest,
@@ -90,58 +91,39 @@ void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) {
return;
}
+ DCHECK(GetDownloadFile(info->download_id) == NULL);
+ downloads_[info->download_id] = download_file.release();
+ // TODO(phajdan.jr): fix the duplication of path info below.
+ info->path = info->save_info.file_path;
+
+ // The file is now ready, we can un-pause the request and start saving data.
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest,
+ info->child_id, info->request_id));
+
StartUpdateTimer();
- // Add the download manager to our request maps for future updates. We want to
- // be able to cancel all in progress downloads when a DownloadManager is
- // deleted, such as when a profile is closed. We also want to be able to look
- // up the DownloadManager associated with a given request without having to
- // rely on using tab information, since a tab may be closed while a download
- // initiated from that tab is still in progress.
- DownloadRequests& downloads = requests_[manager];
- downloads.insert(info->download_id);
-
- // TODO(paulg): The manager will exist when restarts are implemented.
- DownloadManagerMap::iterator dit = managers_.find(info->download_id);
- if (dit == managers_.end())
- managers_[info->download_id] = manager;
- else
- NOTREACHED();
-
- // StartDownload will clean up |info|.
- manager->StartDownload(info);
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(download_manager,
+ &DownloadManager::StartDownload, info));
}
-// Update the Download Manager with the finish state, and remove the request
-// tracking entries.
-void DownloadFileManager::OnDownloadFinished(int id,
- int64 bytes_so_far) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- DownloadManager* manager = GetDownloadManager(id);
- if (manager)
- manager->DownloadFinished(id, bytes_so_far);
- RemoveDownload(id, manager);
- RemoveDownloadFromUIProgress(id);
+void DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+
+ // This balances the pause in DownloadResourceHandler::OnResponseStarted.
+ resource_dispatcher_host_->PauseRequest(child_id, request_id, false);
}
-// Lookup one in-progress download.
DownloadFile* DownloadFileManager::GetDownloadFile(int id) {
DownloadFileMap::iterator it = downloads_.find(id);
return it == downloads_.end() ? NULL : it->second;
}
-// The UI progress is updated on the file thread and removed on the UI thread.
-void DownloadFileManager::RemoveDownloadFromUIProgress(int id) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- AutoLock lock(progress_lock_);
- if (ui_progress_.find(id) != ui_progress_.end())
- ui_progress_.erase(id);
-}
-
-// Throttle updates to the UI thread by only posting update notifications at a
-// regularly controlled interval.
void DownloadFileManager::StartUpdateTimer() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
if (!update_timer_.IsRunning()) {
update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
this, &DownloadFileManager::UpdateInProgressDownloads);
@@ -149,21 +131,22 @@ void DownloadFileManager::StartUpdateTimer() {
}
void DownloadFileManager::StopUpdateTimer() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
update_timer_.Stop();
}
-// Our periodic timer has fired so send the UI thread updates on all in progress
-// downloads.
void DownloadFileManager::UpdateInProgressDownloads() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- AutoLock lock(progress_lock_);
- ProgressMap::iterator it = ui_progress_.begin();
- for (; it != ui_progress_.end(); ++it) {
- const int id = it->first;
- DownloadManager* manager = GetDownloadManager(id);
- if (manager)
- manager->UpdateDownload(id, it->second);
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ for (DownloadFileMap::iterator i = downloads_.begin();
+ i != downloads_.end(); ++i) {
+ int id = i->first;
+ DownloadFile* download_file = i->second;
+ DownloadManager* manager = download_file->GetDownloadManager();
+ if (manager) {
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(manager, &DownloadManager::UpdateDownload,
+ id, download_file->bytes_so_far()));
+ }
}
}
@@ -174,21 +157,13 @@ int DownloadFileManager::GetNextId() {
return next_id_++;
}
-// Notifications sent from the IO thread and run on the download thread:
-
-// The IO thread created 'info', but the download thread (this method) uses it
-// to create a DownloadFile, then passes 'info' to the UI thread where it is
-// finally consumed and deleted.
void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
DCHECK(info);
- DownloadFile* download = new DownloadFile(info);
- if (!download->Initialize()) {
- // Couldn't open, cancel the operation. The UI thread does not yet know
- // about this download so we have to clean up 'info'. We need to get back
- // to the IO thread to cancel the network request and CancelDownloadRequest
- // on the UI thread is the safe way to do that.
+ DownloadManager* manager = DownloadManagerForRenderViewHost(
+ info->child_id, info->render_view_id);
+ if (!manager) {
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableFunction(&download_util::CancelDownloadRequest,
@@ -196,22 +171,12 @@ void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
info->child_id,
info->request_id));
delete info;
- delete download;
return;
}
- DCHECK(GetDownloadFile(info->download_id) == NULL);
- downloads_[info->download_id] = download;
- // TODO(phajdan.jr): fix the duplication of path info below.
- info->path = info->save_info.file_path;
- {
- AutoLock lock(progress_lock_);
- ui_progress_[info->download_id] = info->received_bytes;
- }
-
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &DownloadFileManager::OnStartDownload, info));
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile,
+ info, manager));
}
// We don't forward an update to the UI thread here, since we want to throttle
@@ -227,28 +192,17 @@ void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) {
contents.swap(buffer->contents);
}
- // Keep track of how many bytes we have successfully saved to update
- // our progress status in the UI.
- int64 progress_bytes = 0;
-
DownloadFile* download = GetDownloadFile(id);
for (size_t i = 0; i < contents.size(); ++i) {
net::IOBuffer* data = contents[i].first;
const int data_len = contents[i].second;
- if (download) {
- if (download->AppendDataToFile(data->data(), data_len))
- progress_bytes += data_len;
- }
+ if (download)
+ download->AppendDataToFile(data->data(), data_len);
data->Release();
}
-
- if (download) {
- AutoLock lock(progress_lock_);
- ui_progress_[download->id()] += progress_bytes;
- }
}
-void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) {
+void DownloadFileManager::OnResponseCompleted(int id, DownloadBuffer* buffer) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
delete buffer;
DownloadFileMap::iterator it = downloads_.find(id);
@@ -256,18 +210,15 @@ void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) {
DownloadFile* download = it->second;
download->Finish();
- int64 download_size = -1;
- {
- AutoLock lock(progress_lock_);
- download_size = ui_progress_[download->id()];
+ DownloadManager* download_manager = download->GetDownloadManager();
+ if (download_manager) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ download_manager, &DownloadManager::OnAllDataSaved,
+ id, download->bytes_so_far()));
}
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &DownloadFileManager::OnDownloadFinished,
- id, download_size));
-
// We need to keep the download around until the UI thread has finalized
// the name.
if (download->path_renamed()) {
@@ -277,9 +228,7 @@ void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) {
}
if (downloads_.empty())
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer));
+ StopUpdateTimer();
}
// This method will be sent via a user action, or shutdown on the UI thread, and
@@ -292,127 +241,40 @@ void DownloadFileManager::CancelDownload(int id) {
DownloadFile* download = it->second;
download->Cancel();
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &DownloadFileManager::RemoveDownloadFromUIProgress,
- download->id()));
-
if (download->path_renamed()) {
downloads_.erase(it);
delete download;
}
}
- if (downloads_.empty()) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer));
- }
-}
-
-// Relate a download ID to its owning DownloadManager.
-DownloadManager* DownloadFileManager::GetDownloadManager(int download_id) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- DownloadManagerMap::iterator it = managers_.find(download_id);
- if (it != managers_.end())
- return it->second;
- return NULL;
-}
-
-// Utility function for look up table maintenance, called on the UI thread.
-// A manager may have multiple downloads in progress, so we just look up the
-// one download (id) and remove it from the set, and remove the set if it
-// becomes empty.
-void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- if (manager) {
- RequestMap::iterator it = requests_.find(manager);
- if (it != requests_.end()) {
- DownloadRequests& downloads = it->second;
- DownloadRequests::iterator rit = downloads.find(id);
- if (rit != downloads.end())
- downloads.erase(rit);
- if (downloads.empty())
- requests_.erase(it);
- }
- }
-
- // A download can only have one manager, so remove it if it exists.
- DownloadManagerMap::iterator dit = managers_.find(id);
- if (dit != managers_.end())
- managers_.erase(dit);
-}
-
-// Utility function for converting request IDs to a TabContents. Must be called
-// only on the UI thread since Profile operations may create UI objects, such as
-// the first call to profile->GetDownloadManager().
-// static
-DownloadManager* DownloadFileManager::DownloadManagerFromRenderIds(
- int render_process_id, int render_view_id) {
- TabContents* contents = tab_util::GetTabContentsByID(render_process_id,
- render_view_id);
- if (contents) {
- Profile* profile = contents->profile();
- if (profile)
- return profile->GetDownloadManager();
- }
-
- return NULL;
+ if (downloads_.empty())
+ StopUpdateTimer();
}
-// Called by DownloadManagers in their destructor, and only on the UI thread.
-void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
DCHECK(manager);
- RequestMap::iterator it = requests_.find(manager);
- if (it == requests_.end())
- return;
- const DownloadRequests& requests = it->second;
- DownloadRequests::const_iterator i = requests.begin();
- for (; i != requests.end(); ++i) {
- DownloadManagerMap::iterator dit = managers_.find(*i);
- if (dit != managers_.end()) {
- DCHECK(dit->second == manager);
- managers_.erase(dit);
+ std::set<DownloadFile*> to_remove;
+
+ for (DownloadFileMap::iterator i = downloads_.begin();
+ i != downloads_.end(); ++i) {
+ DownloadFile* download_file = i->second;
+ if (download_file->GetDownloadManager() == manager) {
+ download_file->CancelDownloadRequest(resource_dispatcher_host_);
+ to_remove.insert(download_file);
}
}
- requests_.erase(it);
+ for (std::set<DownloadFile*>::iterator i = to_remove.begin();
+ i != to_remove.end(); ++i) {
+ downloads_.erase((*i)->id());
+ delete *i;
+ }
}
// Actions from the UI thread and run on the download thread
-// Open a download, or show it in a file explorer window. We run on this
-// thread to avoid blocking the UI with (potentially) slow Shell operations.
-// TODO(paulg): File 'stat' operations.
-#if !defined(OS_MACOSX)
-void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- platform_util::ShowItemInFolder(full_path);
-}
-#endif
-
-// Launches the selected download using ShellExecute 'open' verb. For windows,
-// if there is a valid parent window, the 'safer' version will be used which can
-// display a modal dialog asking for user consent on dangerous files.
-#if !defined(OS_MACOSX)
-void DownloadFileManager::OnOpenDownloadInShell(const FilePath& full_path,
- const GURL& url,
- gfx::NativeView parent_window) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-#if defined(OS_WIN)
- if (NULL != parent_window) {
- win_util::SaferOpenItemViaShell(parent_window, L"", full_path,
- UTF8ToWide(url.spec()));
- return;
- }
-#endif
- platform_util::OpenItem(full_path);
-}
-#endif // OS_MACOSX
-
// The DownloadManager in the UI thread has provided an intermediate .crdownload
// name for the download specified by 'id'. Rename the in progress download.
void DownloadFileManager::OnIntermediateDownloadName(
@@ -446,11 +308,11 @@ void DownloadFileManager::OnFinalDownloadName(int id,
bool need_delete_crdownload,
DownloadManager* manager) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- DownloadFileMap::iterator it = downloads_.find(id);
- if (it == downloads_.end())
+
+ DownloadFile* download = GetDownloadFile(id);
+ if (!download)
return;
- DownloadFile* download = it->second;
if (download->Rename(full_path, true)) {
#if defined(OS_MACOSX)
// Done here because we only want to do this once; see
@@ -474,33 +336,31 @@ void DownloadFileManager::OnFinalDownloadName(int id,
// If the download has completed before we got this final name, we remove it
// from our in progress map.
if (!download->in_progress()) {
- downloads_.erase(it);
+ downloads_.erase(id);
delete download;
}
- if (downloads_.empty()) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer));
- }
+ if (downloads_.empty())
+ StopUpdateTimer();
}
// Called only from OnFinalDownloadName or OnIntermediateDownloadName
// on the FILE thread.
void DownloadFileManager::CancelDownloadOnRename(int id) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- DownloadFileMap::iterator it = downloads_.find(id);
- if (it == downloads_.end())
+
+ DownloadFile* download = GetDownloadFile(id);
+ if (!download)
return;
- DownloadFile* download = it->second;
- DownloadManagerMap::iterator dmit = managers_.find(download->id());
- if (dmit != managers_.end()) {
- DownloadManager* dlm = dmit->second;
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(dlm, &DownloadManager::DownloadCancelled, id));
- } else {
+ DownloadManager* download_manager = download->GetDownloadManager();
+ if (!download_manager) {
download->CancelDownloadRequest(resource_dispatcher_host_);
+ return;
}
+
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(download_manager,
+ &DownloadManager::DownloadCancelled, id));
}
diff --git a/chrome/browser/download/download_file_manager.h b/chrome/browser/download/download_file_manager.h
index 22bb94e..5ccf533 100644
--- a/chrome/browser/download/download_file_manager.h
+++ b/chrome/browser/download/download_file_manager.h
@@ -38,13 +38,12 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_MANAGER_H_
+#pragma once
#include <map>
-#include <string>
#include "base/basictypes.h"
#include "base/hash_tables.h"
-#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/timer.h"
#include "gfx/native_widget_types.h"
@@ -75,29 +74,17 @@ class DownloadFileManager
// Called on the IO thread
int GetNextId();
+ // Called on UI thread to make DownloadFileManager start the download.
+ void StartDownload(DownloadCreateInfo* info);
+
// Handlers for notifications sent from the IO thread and run on the
// download thread.
- void StartDownload(DownloadCreateInfo* info);
void UpdateDownload(int id, DownloadBuffer* buffer);
void CancelDownload(int id);
- void DownloadFinished(int id, DownloadBuffer* buffer);
-
- // Called on the UI thread to remove a download item or manager.
- void RemoveDownloadManager(DownloadManager* manager);
- void RemoveDownload(int id, DownloadManager* manager);
+ void OnResponseCompleted(int id, DownloadBuffer* buffer);
-#if !defined(OS_MACOSX)
- // The open and show methods run on the file thread, which does not work on
- // Mac OS X (which uses the UI thread for opens).
-
- // Handler for shell operations sent from the UI to the download thread.
- void OnShowDownloadInShell(const FilePath& full_path);
-
- // Handler to open or execute a downloaded file.
- void OnOpenDownloadInShell(const FilePath& full_path,
- const GURL& url,
- gfx::NativeView parent_window);
-#endif
+ // Called on FILE thread by DownloadManager at the beginning of its shutdown.
+ void OnDownloadManagerShutdown(DownloadManager* manager);
// The DownloadManager in the UI thread has provided an intermediate
// .crdownload name for the download specified by 'id'.
@@ -125,22 +112,18 @@ class DownloadFileManager
// Clean up helper that runs on the download thread.
void OnShutdown();
- // Handlers for notifications sent from the download thread and run on
- // the UI thread.
- void OnStartDownload(DownloadCreateInfo* info);
- void OnDownloadFinished(int id, int64 bytes_so_far);
+ // Creates DownloadFile on FILE thread and continues starting the download
+ // process.
+ void CreateDownloadFile(DownloadCreateInfo* info,
+ DownloadManager* download_manager);
- // Called only on UI thread to get the DownloadManager for a tab's profile.
- static DownloadManager* DownloadManagerFromRenderIds(int render_process_id,
- int review_view_id);
- DownloadManager* GetDownloadManager(int download_id);
+ // Tells the ResourceDispatcherHost to resume a download request
+ // that was paused to wait for the on-disk file to be created.
+ void ResumeDownloadRequest(int child_id, int request_id);
// Called only on the download thread.
DownloadFile* GetDownloadFile(int id);
- // Called on the UI thread to remove a download from the UI progress table.
- void RemoveDownloadFromUIProgress(int id);
-
// Called only from OnFinalDownloadName or OnIntermediateDownloadName
// on the FILE thread.
void CancelDownloadOnRename(int id);
@@ -152,28 +135,12 @@ class DownloadFileManager
typedef base::hash_map<int, DownloadFile*> DownloadFileMap;
DownloadFileMap downloads_;
- // Throttle updates to the UI thread.
+ // Schedule periodic updates of the download progress. This timer
+ // is controlled from the FILE thread, and posts updates to the UI thread.
base::RepeatingTimer<DownloadFileManager> update_timer_;
ResourceDispatcherHost* resource_dispatcher_host_;
- // Tracking which DownloadManager to send data to, called only on UI thread.
- // DownloadManagerMap maps download IDs to their DownloadManager.
- typedef base::hash_map<int, DownloadManager*> DownloadManagerMap;
- DownloadManagerMap managers_;
-
- // RequestMap maps a DownloadManager to all in-progress download IDs.
- // Called only on the UI thread.
- typedef base::hash_set<int> DownloadRequests;
- typedef std::map<DownloadManager*, DownloadRequests> RequestMap;
- RequestMap requests_;
-
- // Used for progress updates on the UI thread, mapping download->id() to bytes
- // received so far. Written to by the file thread and read by the UI thread.
- typedef base::hash_map<int, int64> ProgressMap;
- ProgressMap ui_progress_;
- Lock progress_lock_;
-
DISALLOW_COPY_AND_ASSIGN(DownloadFileManager);
};
diff --git a/chrome/browser/download/download_item.cc b/chrome/browser/download/download_item.cc
index d885576..787b8ad 100644
--- a/chrome/browser/download/download_item.cc
+++ b/chrome/browser/download/download_item.cc
@@ -4,21 +4,42 @@
#include "chrome/browser/download/download_item.h"
+#include "app/l10n_util.h"
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/timer.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/net_util.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/history/download_types.h"
+#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/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
namespace {
// Update frequency (milliseconds).
const int kUpdateTimeMs = 1000;
+void DeleteDownloadedFile(const FilePath& path) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ // Make sure we only delete files.
+ if (!file_util::DirectoryExists(path))
+ file_util::Delete(path, false);
+}
+
} // namespace
// Constructor for reading from the history service.
-DownloadItem::DownloadItem(const DownloadCreateInfo& info)
+DownloadItem::DownloadItem(DownloadManager* download_manager,
+ const DownloadCreateInfo& info)
: id_(-1),
full_path_(info.path),
url_(info.url),
@@ -31,7 +52,7 @@ DownloadItem::DownloadItem(const DownloadCreateInfo& info)
state_(static_cast<DownloadState>(info.state)),
start_time_(info.start_time),
db_handle_(info.db_handle),
- manager_(NULL),
+ download_manager_(download_manager),
is_paused_(false),
open_when_complete_(false),
safety_state_(SAFE),
@@ -44,66 +65,84 @@ DownloadItem::DownloadItem(const DownloadCreateInfo& info)
is_extension_install_(info.is_extension_install),
name_finalized_(false),
is_temporary_(false),
- need_final_rename_(false) {
+ need_final_rename_(false),
+ opened_(false) {
if (state_ == IN_PROGRESS)
state_ = CANCELLED;
Init(false /* don't start progress timer */);
}
-// Constructor for DownloadItem created via user action in the main thread.
-DownloadItem::DownloadItem(int32 download_id,
+// Constructing for a regular download:
+DownloadItem::DownloadItem(DownloadManager* download_manager,
+ const DownloadCreateInfo& info,
+ bool is_otr)
+ : id_(info.download_id),
+ full_path_(info.path),
+ path_uniquifier_(info.path_uniquifier),
+ url_(info.url),
+ referrer_url_(info.referrer_url),
+ mime_type_(info.mime_type),
+ original_mime_type_(info.original_mime_type),
+ total_bytes_(info.total_bytes),
+ received_bytes_(0),
+ start_tick_(base::TimeTicks::Now()),
+ state_(IN_PROGRESS),
+ start_time_(info.start_time),
+ db_handle_(DownloadHistory::kUninitializedHandle),
+ download_manager_(download_manager),
+ is_paused_(false),
+ open_when_complete_(false),
+ safety_state_(info.is_dangerous ? DANGEROUS : SAFE),
+ auto_opened_(false),
+ original_name_(info.original_name),
+ render_process_id_(info.child_id),
+ request_id_(info.request_id),
+ save_as_(info.prompt_user_for_save_location),
+ is_otr_(is_otr),
+ is_extension_install_(info.is_extension_install),
+ name_finalized_(false),
+ is_temporary_(!info.save_info.file_path.empty()),
+ need_final_rename_(false),
+ opened_(false) {
+ Init(true /* start progress timer */);
+}
+
+// Constructing for the "Save Page As..." feature:
+DownloadItem::DownloadItem(DownloadManager* download_manager,
const FilePath& path,
- int path_uniquifier,
const GURL& url,
- const GURL& referrer_url,
- const std::string& mime_type,
- const std::string& original_mime_type,
- const FilePath& original_name,
- const base::Time start_time,
- int64 download_size,
- int render_process_id,
- int request_id,
- bool is_dangerous,
- bool save_as,
- bool is_otr,
- bool is_extension_install,
- bool is_temporary)
- : id_(download_id),
+ bool is_otr)
+ : id_(1),
full_path_(path),
- path_uniquifier_(path_uniquifier),
+ path_uniquifier_(0),
url_(url),
- referrer_url_(referrer_url),
- mime_type_(mime_type),
- original_mime_type_(original_mime_type),
- total_bytes_(download_size),
+ referrer_url_(GURL()),
+ mime_type_(std::string()),
+ original_mime_type_(std::string()),
+ total_bytes_(0),
received_bytes_(0),
start_tick_(base::TimeTicks::Now()),
state_(IN_PROGRESS),
- start_time_(start_time),
- db_handle_(DownloadManager::kUninitializedHandle),
- manager_(NULL),
+ start_time_(base::Time::Now()),
+ db_handle_(DownloadHistory::kUninitializedHandle),
+ download_manager_(download_manager),
is_paused_(false),
open_when_complete_(false),
- safety_state_(is_dangerous ? DANGEROUS : SAFE),
+ safety_state_(SAFE),
auto_opened_(false),
- original_name_(original_name),
- render_process_id_(render_process_id),
- request_id_(request_id),
- save_as_(save_as),
+ original_name_(FilePath()),
+ render_process_id_(-1),
+ request_id_(-1),
+ save_as_(false),
is_otr_(is_otr),
- is_extension_install_(is_extension_install),
+ is_extension_install_(false),
name_finalized_(false),
- is_temporary_(is_temporary),
- need_final_rename_(false) {
+ is_temporary_(false),
+ need_final_rename_(false),
+ opened_(false) {
Init(true /* start progress timer */);
}
-void DownloadItem::Init(bool start_timer) {
- file_name_ = full_path_.BaseName();
- if (start_timer)
- StartProgressTimer();
-}
-
DownloadItem::~DownloadItem() {
state_ = REMOVING;
UpdateObservers();
@@ -125,18 +164,84 @@ void DownloadItem::NotifyObserversDownloadFileCompleted() {
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadFileCompleted(this));
}
-void DownloadItem::NotifyObserversDownloadOpened() {
- FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
+bool DownloadItem::CanOpenDownload() {
+ FilePath file_to_use = full_path();
+ if (!original_name().value().empty())
+ file_to_use = original_name();
+
+ return !Extension::IsExtension(file_to_use) &&
+ !download_util::IsExecutableFile(file_to_use);
+}
+
+bool DownloadItem::ShouldOpenFileBasedOnExtension() {
+ return download_manager_->ShouldOpenFileBasedOnExtension(full_path());
+}
+
+void DownloadItem::OpenFilesBasedOnExtension(bool open) {
+ DownloadPrefs* prefs = download_manager_->download_prefs();
+ if (open)
+ prefs->EnableAutoOpenBasedOnExtension(full_path());
+ else
+ prefs->DisableAutoOpenBasedOnExtension(full_path());
+}
+
+void DownloadItem::OpenDownload() {
+ if (state() == DownloadItem::IN_PROGRESS) {
+ open_when_complete_ = !open_when_complete_;
+ } else if (state() == DownloadItem::COMPLETE) {
+ opened_ = true;
+ FOR_EACH_OBSERVER(Observer, observers_, OnDownloadOpened(this));
+ if (is_extension_install()) {
+ download_util::OpenChromeExtension(download_manager_->profile(),
+ download_manager_,
+ *this);
+ return;
+ }
+#if defined(OS_MACOSX)
+ // Mac OS X requires opening downloads on the UI thread.
+ platform_util::OpenItem(full_path());
+#else
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(&platform_util::OpenItem, full_path()));
+#endif
+ }
+}
+
+void DownloadItem::ShowDownloadInShell() {
+#if defined(OS_MACOSX)
+ // Mac needs to run this operation on the UI thread.
+ platform_util::ShowItemInFolder(full_path());
+#else
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(&platform_util::ShowItemInFolder,
+ full_path()));
+#endif
+}
+
+void DownloadItem::DangerousDownloadValidated() {
+ download_manager_->DangerousDownloadValidated(this);
}
-// If we've received more data than we were expecting (bad server info?), revert
-// to 'unknown size mode'.
void DownloadItem::UpdateSize(int64 bytes_so_far) {
received_bytes_ = bytes_so_far;
+
+ // If we've received more data than we were expecting (bad server info?),
+ // revert to 'unknown size mode'.
if (received_bytes_ > total_bytes_)
total_bytes_ = 0;
}
+void DownloadItem::StartProgressTimer() {
+ update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this,
+ &DownloadItem::UpdateObservers);
+}
+
+void DownloadItem::StopProgressTimer() {
+ update_timer_.Stop();
+}
+
// Updates from the download thread may have been posted while this download
// was being cancelled in the UI thread, so we'll accept them unless we're
// complete.
@@ -159,33 +264,57 @@ void DownloadItem::Cancel(bool update_history) {
UpdateObservers();
StopProgressTimer();
if (update_history)
- manager_->DownloadCancelled(id_);
+ download_manager_->DownloadCancelled(id_);
}
-void DownloadItem::Finished(int64 size) {
+void DownloadItem::OnAllDataSaved(int64 size) {
state_ = COMPLETE;
UpdateSize(size);
StopProgressTimer();
}
+void DownloadItem::Finished() {
+ // Handle chrome extensions explicitly and skip the shell execute.
+ if (is_extension_install()) {
+ download_util::OpenChromeExtension(download_manager_->profile(),
+ download_manager_,
+ *this);
+ auto_opened_ = true;
+ } else if (open_when_complete() ||
+ download_manager_->ShouldOpenFileBasedOnExtension(full_path()) ||
+ is_temporary()) {
+ // If the download is temporary, like in drag-and-drop, do not open it but
+ // we still need to set it auto-opened so that it can be removed from the
+ // download shelf.
+ if (!is_temporary())
+ OpenDownload();
+ auto_opened_ = true;
+ }
+
+ // Notify our observers that we are complete (the call to OnAllDataSaved()
+ // set the state to complete but did not notify).
+ UpdateObservers();
+
+ // The download file is meant to be completed if both the filename is
+ // finalized and the file data is downloaded. The ordering of these two
+ // actions is indeterministic. Thus, if the filename is not finalized yet,
+ // delay the notification.
+ if (name_finalized())
+ NotifyObserversDownloadFileCompleted();
+}
+
void DownloadItem::Remove(bool delete_on_disk) {
Cancel(true);
state_ = REMOVING;
- if (delete_on_disk)
- manager_->DeleteDownload(full_path_);
- manager_->RemoveDownload(db_handle_);
+ if (delete_on_disk) {
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(&DeleteDownloadedFile, full_path_));
+ }
+ download_manager_->RemoveDownload(db_handle_);
// We have now been deleted.
}
-void DownloadItem::StartProgressTimer() {
- update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdateTimeMs), this,
- &DownloadItem::UpdateObservers);
-}
-
-void DownloadItem::StopProgressTimer() {
- update_timer_.Stop();
-}
-
bool DownloadItem::TimeRemaining(base::TimeDelta* remaining) const {
if (total_bytes_ <= 0)
return false; // We never received the content_length for this download.
@@ -220,11 +349,50 @@ void DownloadItem::Rename(const FilePath& full_path) {
void DownloadItem::TogglePause() {
DCHECK(state_ == IN_PROGRESS);
- manager_->PauseDownload(id_, !is_paused_);
+ download_manager_->PauseDownload(id_, !is_paused_);
is_paused_ = !is_paused_;
UpdateObservers();
}
+void DownloadItem::OnNameFinalized() {
+ name_finalized_ = true;
+
+ // The download file is meant to be completed if both the filename is
+ // finalized and the file data is downloaded. The ordering of these two
+ // actions is indeterministic. Thus, if we are still in downloading the
+ // file, delay the notification.
+ if (state() == DownloadItem::COMPLETE)
+ NotifyObserversDownloadFileCompleted();
+}
+
+bool DownloadItem::MatchesQuery(const string16& query) const {
+ if (query.empty())
+ return true;
+
+ DCHECK_EQ(query, l10n_util::ToLower(query));
+
+ string16 url_raw(l10n_util::ToLower(UTF8ToUTF16(url_.spec())));
+ if (url_raw.find(query) != string16::npos)
+ return true;
+
+ // TODO(phajdan.jr): write a test case for the following code.
+ // A good test case would be:
+ // "/\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xbd\xa0\xe5\xa5\xbd",
+ // L"/\x4f60\x597d\x4f60\x597d",
+ // "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD"
+ PrefService* prefs = download_manager_->profile()->GetPrefs();
+ std::string languages(prefs->GetString(prefs::kAcceptLanguages));
+ string16 url_formatted(l10n_util::ToLower(net::FormatUrl(url_, languages)));
+ if (url_formatted.find(query) != string16::npos)
+ return true;
+
+ string16 path(l10n_util::ToLower(WideToUTF16(full_path_.ToWStringHack())));
+ if (path.find(query) != std::wstring::npos)
+ return true;
+
+ return false;
+}
+
FilePath DownloadItem::GetFileName() const {
if (safety_state_ == DownloadItem::SAFE)
return file_name_;
@@ -235,3 +403,9 @@ FilePath DownloadItem::GetFileName() const {
}
return original_name_;
}
+
+void DownloadItem::Init(bool start_timer) {
+ file_name_ = full_path_.BaseName();
+ if (start_timer)
+ StartProgressTimer();
+}
diff --git a/chrome/browser/download/download_item.h b/chrome/browser/download/download_item.h
index dc6ed2a..3431bc7 100644
--- a/chrome/browser/download/download_item.h
+++ b/chrome/browser/download/download_item.h
@@ -16,6 +16,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_H_
+#pragma once
#include <string>
@@ -64,33 +65,22 @@ class DownloadItem {
};
// Constructing from persistent store:
- explicit DownloadItem(const DownloadCreateInfo& info);
+ DownloadItem(DownloadManager* download_manager,
+ const DownloadCreateInfo& info);
- // Constructing from user action:
- DownloadItem(int32 download_id,
+ // Constructing for a regular download:
+ DownloadItem(DownloadManager* download_manager,
+ const DownloadCreateInfo& info,
+ bool is_otr);
+
+ // Constructing for the "Save Page As..." feature:
+ DownloadItem(DownloadManager* download_manager,
const FilePath& path,
- int path_uniquifier,
const GURL& url,
- const GURL& referrer_url,
- const std::string& mime_type,
- const std::string& original_mime_type,
- const FilePath& original_name,
- const base::Time start_time,
- int64 download_size,
- int render_process_id,
- int request_id,
- bool is_dangerous,
- bool save_as,
- bool is_otr,
- bool is_extension_install,
- bool is_temporary);
+ bool is_otr);
~DownloadItem();
- void Init(bool start_timer);
-
- // Public API
-
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
@@ -100,8 +90,26 @@ class DownloadItem {
// Notifies our observers the downloaded file has been completed.
void NotifyObserversDownloadFileCompleted();
- // Notifies our observers the downloaded file has been opened.
- void NotifyObserversDownloadOpened();
+ // Whether it is OK to open this download.
+ bool CanOpenDownload();
+
+ // Tests if a file type should be opened automatically.
+ bool ShouldOpenFileBasedOnExtension();
+
+ // Registers this file extension for automatic opening upon download
+ // completion if 'open' is true, or prevents the extension from automatic
+ // opening if 'open' is false.
+ void OpenFilesBasedOnExtension(bool open);
+
+ // Open the file associated with this download (wait for the download to
+ // complete if it is in progress).
+ void OpenDownload();
+
+ // Show the download via the OS shell.
+ void ShowDownloadInShell();
+
+ // Called when the user has validated the download of a dangerous file.
+ void DangerousDownloadValidated();
// Received a new chunk of data
void Update(int64 bytes_so_far);
@@ -117,17 +125,17 @@ class DownloadItem {
// when resuming a download (assuming the server supports byte ranges).
void Cancel(bool update_history);
- // Download operation completed.
- void Finished(int64 size);
+ // Called when all data has been saved.
+ void OnAllDataSaved(int64 size);
+
+ // Called when the entire download operation (including renaming etc)
+ // is finished.
+ void Finished();
// The user wants to remove the download from the views and history. If
// |delete_file| is true, the file is deleted on the disk.
void Remove(bool delete_file);
- // Start/stop sending periodic updates to our observers
- void StartProgressTimer();
- void StopProgressTimer();
-
// Simple calculation of the amount of time remaining to completion. Fills
// |*remaining| with the amount of time remaining if successful. Fails and
// returns false if we do not have the number of bytes or the speed so can
@@ -148,13 +156,15 @@ class DownloadItem {
// Allow the user to temporarily pause a download or resume a paused download.
void TogglePause();
+ // Called when the name of the download is finalized.
+ void OnNameFinalized();
+
+ // Returns true if this item matches |query|. |query| must be lower-cased.
+ bool MatchesQuery(const string16& query) const;
+
// Accessors
DownloadState state() const { return state_; }
- FilePath file_name() const { return file_name_; }
- void set_file_name(const FilePath& name) { file_name_ = name; }
FilePath full_path() const { return full_path_; }
- void set_full_path(const FilePath& path) { full_path_ = path; }
- int path_uniquifier() const { return path_uniquifier_; }
void set_path_uniquifier(int uniquifier) { path_uniquifier_ = uniquifier; }
GURL url() const { return url_; }
GURL referrer_url() const { return referrer_url_; }
@@ -167,10 +177,7 @@ class DownloadItem {
base::Time start_time() const { return start_time_; }
void set_db_handle(int64 handle) { db_handle_ = handle; }
int64 db_handle() const { return db_handle_; }
- DownloadManager* manager() const { return manager_; }
- void set_manager(DownloadManager* manager) { manager_ = manager; }
bool is_paused() const { return is_paused_; }
- void set_is_paused(bool pause) { is_paused_ = pause; }
bool open_when_complete() const { return open_when_complete_; }
void set_open_when_complete(bool open) { open_when_complete_ = open; }
int render_process_id() const { return render_process_id_; }
@@ -180,22 +187,18 @@ class DownloadItem {
safety_state_ = safety_state;
}
bool auto_opened() { return auto_opened_; }
- void set_auto_opened(bool auto_opened) { auto_opened_ = auto_opened; }
FilePath original_name() const { return original_name_; }
- void set_original_name(const FilePath& name) { original_name_ = name; }
bool save_as() const { return save_as_; }
bool is_otr() const { return is_otr_; }
bool is_extension_install() const { return is_extension_install_; }
bool name_finalized() const { return name_finalized_; }
- void set_name_finalized(bool name_finalized) {
- name_finalized_ = name_finalized;
- }
bool is_temporary() const { return is_temporary_; }
- void set_is_temporary(bool is_temporary) { is_temporary_ = is_temporary; }
bool need_final_rename() const { return need_final_rename_; }
void set_need_final_rename(bool need_final_rename) {
need_final_rename_ = need_final_rename;
}
+ void set_opened(bool opened) { opened_ = opened; }
+ bool opened() const { return opened_; }
// Returns the file-name that should be reported to the user, which is
// file_name_ for safe downloads and original_name_ for dangerous ones with
@@ -203,9 +206,15 @@ class DownloadItem {
FilePath GetFileName() const;
private:
+ void Init(bool start_timer);
+
// Internal helper for maintaining consistent received and total sizes.
void UpdateSize(int64 size);
+ // Start/stop sending periodic updates to our observers
+ void StartProgressTimer();
+ void StopProgressTimer();
+
// Request ID assigned by the ResourceDispatcherHost.
int32 id_;
@@ -257,7 +266,7 @@ class DownloadItem {
base::RepeatingTimer<DownloadItem> update_timer_;
// Our owning object
- DownloadManager* manager_;
+ DownloadManager* download_manager_;
// In progress downloads may be paused by the user, we note it here
bool is_paused_;
@@ -300,6 +309,12 @@ class DownloadItem {
// True if the file needs final rename.
bool need_final_rename_;
+ // Did the user open the item either directly or indirectly (such as by
+ // setting always open files of this type)? The shelf also sets this field
+ // when the user closes the shelf before the item has been opened but should
+ // be treated as though the user opened it.
+ bool opened_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadItem);
};
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 457a34a..48c75ad 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -7,6 +7,7 @@
#include "app/l10n_util.h"
#include "base/i18n/number_formatting.h"
#include "base/i18n/rtl.h"
+#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/save_package.h"
@@ -31,49 +32,48 @@ std::wstring DownloadItemModel::GetStatusText() {
int64 total = download_->total_bytes();
DataUnits amount_units = GetByteDisplayUnits(total);
- const std::wstring simple_size = FormatBytes(size, amount_units, false);
+ const string16 simple_size = FormatBytes(size, amount_units, false);
// In RTL locales, we render the text "size/total" in an RTL context. This
// is problematic since a string such as "123/456 MB" is displayed
// as "MB 123/456" because it ends with an LTR run. In order to solve this,
// we mark the total string as an LTR string if the UI layout is
// right-to-left so that the string "456 MB" is treated as an LTR run.
- std::wstring simple_total = FormatBytes(total, amount_units, true);
- base::i18n::GetDisplayStringInLTRDirectionality(&simple_total);
+ string16 simple_total = base::i18n::GetDisplayStringInLTRDirectionality(
+ FormatBytes(total, amount_units, true));
TimeDelta remaining;
- std::wstring simple_time;
+ string16 simple_time;
if (download_->state() == DownloadItem::IN_PROGRESS &&
download_->is_paused()) {
- simple_time = l10n_util::GetString(IDS_DOWNLOAD_PROGRESS_PAUSED);
+ simple_time = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
} else if (download_->TimeRemaining(&remaining)) {
simple_time = download_->open_when_complete() ?
TimeFormat::TimeRemainingShort(remaining) :
TimeFormat::TimeRemaining(remaining);
}
- std::wstring status_text;
+ string16 status_text;
switch (download_->state()) {
case DownloadItem::IN_PROGRESS:
if (download_->open_when_complete()) {
if (simple_time.empty()) {
status_text =
- l10n_util::GetString(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE);
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE);
} else {
- status_text = l10n_util::GetStringF(IDS_DOWNLOAD_STATUS_OPEN_IN,
- simple_time);
+ status_text = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPEN_IN,
+ simple_time);
}
} else {
if (simple_time.empty()) {
// Instead of displaying "0 B" we keep the "Starting..." string.
status_text = (size == 0) ?
- l10n_util::GetString(IDS_DOWNLOAD_STATUS_STARTING) :
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING) :
FormatBytes(size, GetByteDisplayUnits(size), true);
} else {
- status_text = l10n_util::GetStringF(IDS_DOWNLOAD_STATUS_IN_PROGRESS,
- simple_size,
- simple_total,
- simple_time);
+ status_text = l10n_util::GetStringFUTF16(
+ IDS_DOWNLOAD_STATUS_IN_PROGRESS, simple_size, simple_total,
+ simple_time);
}
}
break;
@@ -81,7 +81,7 @@ std::wstring DownloadItemModel::GetStatusText() {
status_text.clear();
break;
case DownloadItem::CANCELLED:
- status_text = l10n_util::GetString(IDS_DOWNLOAD_STATUS_CANCELED);
+ status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELED);
break;
case DownloadItem::REMOVING:
break;
@@ -89,7 +89,7 @@ std::wstring DownloadItemModel::GetStatusText() {
NOTREACHED();
}
- return status_text;
+ return UTF16ToWideHack(status_text);
}
// -----------------------------------------------------------------------------
diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h
index 82d70ec..f399489 100644
--- a/chrome/browser/download/download_item_model.h
+++ b/chrome/browser/download/download_item_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_MODEL_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_MODEL_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index 6930755..88743f0 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -11,20 +11,23 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/rand_util.h"
+#include "base/stl_util-inl.h"
#include "base/sys_string_conversions.h"
#include "base/task.h"
+#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.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/crx_installer.h"
-#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/history/download_types.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"
@@ -45,84 +48,36 @@
#if defined(OS_WIN)
#include "app/win_util.h"
-#include "base/registry.h"
-#include "base/win_util.h"
#endif
-namespace {
-
-// Used to sort download items based on descending start time.
-bool CompareStartTime(DownloadItem* first, DownloadItem* second) {
- return first->start_time() > second->start_time();
-}
-
-void DeleteDownloadedFile(const FilePath& path) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
-
- // Make sure we only delete files.
- if (!file_util::DirectoryExists(path))
- file_util::Delete(path, false);
-}
-
-} // namespace
-
-// 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
-// database handles in incognito mode starting at -1 and progressively getting
-// more negative.
-// static
-const int DownloadManager::kUninitializedHandle = 0;
-
-// static
-void DownloadManager::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterBooleanPref(prefs::kPromptForDownload, false);
- prefs->RegisterStringPref(prefs::kDownloadExtensionsToOpen, "");
- prefs->RegisterBooleanPref(prefs::kDownloadDirUpgraded, false);
-
- // The default download path is userprofile\download.
- const FilePath& default_download_path =
- download_util::GetDefaultDownloadDirectory();
- prefs->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
- default_download_path);
-
- // If the download path is dangerous we forcefully reset it. But if we do
- // so we set a flag to make sure we only do it once, to avoid fighting
- // the user if he really wants it on an unsafe place such as the desktop.
-
- if (!prefs->GetBoolean(prefs::kDownloadDirUpgraded)) {
- FilePath current_download_dir = prefs->GetFilePath(
- prefs::kDownloadDefaultDirectory);
- if (download_util::DownloadPathIsDangerous(current_download_dir)) {
- prefs->SetFilePath(prefs::kDownloadDefaultDirectory,
- default_download_path);
- }
- prefs->SetBoolean(prefs::kDownloadDirUpgraded, true);
- }
-}
-
-DownloadManager::DownloadManager()
+DownloadManager::DownloadManager(DownloadStatusUpdater* status_updater)
: shutdown_needed_(false),
profile_(NULL),
file_manager_(NULL),
- fake_db_handle_(kUninitializedHandle - 1) {
+ status_updater_(status_updater) {
+ if (status_updater_)
+ status_updater_->AddDelegate(this);
}
DownloadManager::~DownloadManager() {
- FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown());
-
- if (shutdown_needed_)
- Shutdown();
+ DCHECK(!shutdown_needed_);
+ if (status_updater_)
+ status_updater_->RemoveDelegate(this);
}
void DownloadManager::Shutdown() {
- DCHECK(shutdown_needed_) << "Shutdown called when not needed.";
+ if (!shutdown_needed_)
+ return;
+ shutdown_needed_ = false;
- // Stop receiving download updates
- if (file_manager_)
- file_manager_->RemoveDownloadManager(this);
+ FOR_EACH_OBSERVER(Observer, observers_, ManagerGoingDown());
- // Stop making history service requests
- cancelable_consumer_.CancelAllRequests();
+ if (file_manager_) {
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(file_manager_,
+ &DownloadFileManager::OnDownloadManagerShutdown,
+ this));
+ }
// 'in_progress_' may contain DownloadItems that have not finished the start
// complete (from the history service) and thus aren't in downloads_.
@@ -139,8 +94,8 @@ void DownloadManager::Shutdown() {
}
DCHECK_EQ(DownloadItem::IN_PROGRESS, download->state());
download->Cancel(false);
- UpdateHistoryForDownload(download);
- if (download->db_handle() == kUninitializedHandle) {
+ 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;
@@ -161,7 +116,7 @@ void DownloadManager::Shutdown() {
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 == kUninitializedHandle)
+ if (handle == DownloadHistory::kUninitializedHandle)
delete download;
}
to_remove.clear();
@@ -169,134 +124,48 @@ void DownloadManager::Shutdown() {
in_progress_.clear();
dangerous_finished_.clear();
STLDeleteValues(&downloads_);
+ STLDeleteContainerPointers(save_page_downloads_.begin(),
+ save_page_downloads_.end());
file_manager_ = NULL;
- // Save our file extensions to auto open.
- SaveAutoOpens();
-
// Make sure the save as dialog doesn't notify us back if we're gone before
// it returns.
if (select_file_dialog_.get())
select_file_dialog_->ListenerDestroyed();
- shutdown_needed_ = false;
-}
-
-// Issue a history query for downloads matching 'search_text'. If 'search_text'
-// is empty, return all downloads that we know about.
-void DownloadManager::GetDownloads(Observer* observer,
- const std::wstring& search_text) {
- std::vector<DownloadItem*> otr_downloads;
-
- if (profile_->IsOffTheRecord() && search_text.empty()) {
- // List all incognito downloads and add that to the downloads the parent
- // profile lists.
- otr_downloads.reserve(downloads_.size());
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- DownloadItem* download = it->second;
- if (download->is_otr() && !download->is_extension_install() &&
- !download->is_temporary()) {
- otr_downloads.push_back(download);
- }
- }
- }
-
- profile_->GetOriginalProfile()->GetDownloadManager()->
- DoGetDownloads(observer, search_text, otr_downloads);
-}
-
-void DownloadManager::DoGetDownloads(
- Observer* observer,
- const std::wstring& search_text,
- std::vector<DownloadItem*>& otr_downloads) {
- DCHECK(observer);
-
- // Return a empty list if we've not yet received the set of downloads from the
- // history system (we'll update all observers once we get that list in
- // OnQueryDownloadEntriesComplete), or if there are no downloads at all.
- if (downloads_.empty()) {
- observer->SetDownloads(otr_downloads);
- return;
- }
-
- std::vector<DownloadItem*> download_copy;
- // We already know all the downloads and there is no filter, so just return a
- // copy to the observer.
- if (search_text.empty()) {
- download_copy.reserve(downloads_.size());
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
- if (it->second->db_handle() > kUninitializedHandle)
- download_copy.push_back(it->second);
- }
-
- // Merge sort based on start time.
- std::vector<DownloadItem*> merged_downloads;
- std::merge(otr_downloads.begin(), otr_downloads.end(),
- download_copy.begin(), download_copy.end(),
- std::back_inserter(merged_downloads),
- CompareStartTime);
-
- // We retain ownership of the DownloadItems.
- observer->SetDownloads(merged_downloads);
- return;
- }
+ download_history_.reset();
- DCHECK(otr_downloads.empty());
-
- // Issue a request to the history service for a list of downloads matching
- // our search text.
- HistoryService* hs =
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- HistoryService::Handle h =
- hs->SearchDownloads(WideToUTF16(search_text),
- &cancelable_consumer_,
- NewCallback(this,
- &DownloadManager::OnSearchComplete));
- cancelable_consumer_.SetClientData(hs, h, observer);
- }
+ shutdown_needed_ = false;
}
-void DownloadManager::GetTemporaryDownloads(Observer* observer,
- const FilePath& dir_path) {
- DCHECK(observer);
-
- std::vector<DownloadItem*> download_copy;
+void DownloadManager::GetTemporaryDownloads(
+ const FilePath& dir_path, std::vector<DownloadItem*>* result) {
+ DCHECK(result);
for (DownloadMap::iterator it = downloads_.begin();
it != downloads_.end(); ++it) {
if (it->second->is_temporary() &&
it->second->full_path().DirName() == dir_path)
- download_copy.push_back(it->second);
+ result->push_back(it->second);
}
-
- observer->SetDownloads(download_copy);
}
-void DownloadManager::GetAllDownloads(Observer* observer,
- const FilePath& dir_path) {
- DCHECK(observer);
-
- std::vector<DownloadItem*> download_copy;
+void DownloadManager::GetAllDownloads(
+ const FilePath& dir_path, std::vector<DownloadItem*>* result) {
+ DCHECK(result);
for (DownloadMap::iterator it = downloads_.begin();
it != downloads_.end(); ++it) {
if (!it->second->is_temporary() &&
(dir_path.empty() || it->second->full_path().DirName() == dir_path))
- download_copy.push_back(it->second);
+ result->push_back(it->second);
}
-
- observer->SetDownloads(download_copy);
}
-void DownloadManager::GetCurrentDownloads(Observer* observer,
- const FilePath& dir_path) {
- DCHECK(observer);
-
- std::vector<DownloadItem*> download_copy;
+void DownloadManager::GetCurrentDownloads(
+ const FilePath& dir_path, std::vector<DownloadItem*>* result) {
+ DCHECK(result);
for (DownloadMap::iterator it = downloads_.begin();
it != downloads_.end(); ++it) {
@@ -304,10 +173,44 @@ void DownloadManager::GetCurrentDownloads(Observer* observer,
(it->second->state() == DownloadItem::IN_PROGRESS ||
it->second->safety_state() == DownloadItem::DANGEROUS) &&
(dir_path.empty() || it->second->full_path().DirName() == dir_path))
- download_copy.push_back(it->second);
+ result->push_back(it->second);
+ }
+
+ // If we have a parent profile, let it add its downloads to the results.
+ Profile* original_profile = profile_->GetOriginalProfile();
+ if (original_profile != profile_)
+ original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path,
+ result);
+
+}
+
+void DownloadManager::SearchDownloads(const string16& query,
+ std::vector<DownloadItem*>* result) {
+ DCHECK(result);
+
+ string16 query_lower(l10n_util::ToLower(query));
+
+ for (DownloadMap::iterator it = downloads_.begin();
+ it != downloads_.end(); ++it) {
+ DownloadItem* download_item = it->second;
+
+ if (download_item->is_temporary() || download_item->is_extension_install())
+ continue;
+
+ // Display Incognito downloads only in Incognito window, and vice versa.
+ // The Incognito Downloads page will get the list of non-Incognito downloads
+ // from its parent profile.
+ if (profile_->IsOffTheRecord() != download_item->is_otr())
+ continue;
+
+ if (download_item->MatchesQuery(query_lower))
+ result->push_back(download_item);
}
- observer->SetDownloads(download_copy);
+ // If we have a parent profile, let it add its downloads to the results.
+ Profile* original_profile = profile_->GetOriginalProfile();
+ if (original_profile != profile_)
+ original_profile->GetDownloadManager()->SearchDownloads(query, result);
}
// Query the history service for information about all persisted downloads.
@@ -318,14 +221,11 @@ bool DownloadManager::Init(Profile* profile) {
profile_ = profile;
request_context_getter_ = profile_->GetRequestContext();
+ download_history_.reset(new DownloadHistory(profile));
+ download_history_->Load(
+ NewCallback(this, &DownloadManager::OnQueryDownloadEntriesComplete));
- // 'incognito mode' will have access to past downloads, but we won't store
- // information about new downloads while in that mode.
- QueryHistoryForDownloads();
-
- // Cleans up entries only when called for the first time. Subsequent calls are
- // a no op.
- CleanUpInProgressHistoryEntries();
+ download_prefs_.reset(new DownloadPrefs(profile_->GetPrefs()));
// In test mode, there may be no ResourceDispatcherHost. In this case it's
// safe to avoid setting |file_manager_| because we only call a small set of
@@ -336,62 +236,12 @@ bool DownloadManager::Init(Profile* profile) {
DCHECK(file_manager_);
}
- // Get our user preference state.
- PrefService* prefs = profile_->GetPrefs();
- DCHECK(prefs);
- prompt_for_download_.Init(prefs::kPromptForDownload, prefs, NULL);
-
- download_path_.Init(prefs::kDownloadDefaultDirectory, prefs, NULL);
-
- // Ensure that the download directory specified in the preferences exists.
- ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
- NewRunnableFunction(&file_util::CreateDirectory, download_path()));
-
- // We store any file extension that should be opened automatically at
- // download completion in this pref.
- std::string extensions_to_open =
- prefs->GetString(prefs::kDownloadExtensionsToOpen);
- std::vector<std::string> extensions;
- SplitString(extensions_to_open, ':', &extensions);
-
- for (size_t i = 0; i < extensions.size(); ++i) {
-#if defined(OS_POSIX)
- FilePath path(extensions[i]);
-#elif defined(OS_WIN)
- FilePath path(UTF8ToWide(extensions[i]));
-#endif
- if (!extensions[i].empty() && !IsExecutableFile(path))
- auto_open_.insert(path.value());
- }
-
other_download_manager_observer_.reset(
new OtherDownloadManagerObserver(this));
return true;
}
-void DownloadManager::QueryHistoryForDownloads() {
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- hs->QueryDownloads(
- &cancelable_consumer_,
- NewCallback(this, &DownloadManager::OnQueryDownloadEntriesComplete));
- }
-}
-
-void DownloadManager::CleanUpInProgressHistoryEntries() {
- static bool already_cleaned_up = false;
-
- if (!already_cleaned_up) {
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- hs->CleanUpInProgressEntries();
- already_cleaned_up = true;
- }
- }
-}
-
// We have received a message from DownloadFileManager about a new download. We
// 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
@@ -413,12 +263,12 @@ void DownloadManager::StartDownload(DownloadCreateInfo* info) {
if (info->save_info.file_path.empty()) {
FilePath generated_name;
- GenerateFileNameFromInfo(info, &generated_name);
+ download_util::GenerateFileNameFromInfo(info, &generated_name);
// Freeze the user's preference for showing a Save As dialog. We're going
// to bounce around a bunch of threads and we don't want to worry about race
// conditions where the user changes this pref out from under us.
- if (*prompt_for_download_) {
+ if (download_prefs_->prompt_for_download()) {
// But ignore the user's preference for the following scenarios:
// 1) Extension installation. Note that we only care here about the case
// where an extension is installed, not when one is downloaded with
@@ -433,10 +283,11 @@ 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_path();
+ } else {
+ info->suggested_path = download_prefs_->download_path();
+ }
info->suggested_path = info->suggested_path.Append(generated_name);
} else {
info->suggested_path = info->save_info.file_path;
@@ -447,7 +298,7 @@ void DownloadManager::StartDownload(DownloadCreateInfo* info) {
// 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 (IsDangerous(info->suggested_path.BaseName()))
+ if (download_util::IsExecutableFile(info->suggested_path.BaseName()))
info->is_dangerous = true;
else if (info->is_extension_install &&
!ExtensionsService::IsDownloadFromGallery(info->url,
@@ -465,6 +316,7 @@ void DownloadManager::StartDownload(DownloadCreateInfo* info) {
}
void DownloadManager::CheckIfSuggestedPathExists(DownloadCreateInfo* info) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
DCHECK(info);
// Check writability of the suggested path. If we can't write to it, default
@@ -524,7 +376,6 @@ void DownloadManager::CheckIfSuggestedPathExists(DownloadCreateInfo* info) {
info->suggested_path), "", 0);
}
- // Now we return to the UI thread.
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this,
@@ -558,45 +409,24 @@ void DownloadManager::OnPathExistenceAvailable(DownloadCreateInfo* info) {
owning_window, info);
} else {
// No prompting for download, just continue with the suggested name.
- ContinueStartDownload(info, info->suggested_path);
+ CreateDownloadItem(info, info->suggested_path);
}
}
-void DownloadManager::ContinueStartDownload(DownloadCreateInfo* info,
- const FilePath& target_path) {
+void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info,
+ const FilePath& target_path) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
scoped_ptr<DownloadCreateInfo> infop(info);
info->path = target_path;
- DownloadItem* download = NULL;
- DownloadMap::iterator it = in_progress_.find(info->download_id);
- if (it == in_progress_.end()) {
- download = new DownloadItem(info->download_id,
- info->path,
- info->path_uniquifier,
- info->url,
- info->referrer_url,
- info->mime_type,
- info->original_mime_type,
- info->original_name,
- info->start_time,
- info->total_bytes,
- info->child_id,
- info->request_id,
- info->is_dangerous,
- info->prompt_user_for_save_location,
- profile_->IsOffTheRecord(),
- info->is_extension_install,
- !info->save_info.file_path.empty());
- download->set_manager(this);
- in_progress_[info->download_id] = download;
- } else {
- NOTREACHED(); // Should not exist!
- return;
- }
+ DownloadItem* download = new DownloadItem(this, *info,
+ profile_->IsOffTheRecord());
+ DCHECK(!ContainsKey(in_progress_, info->download_id));
+ in_progress_[info->download_id] = download;
- PendingFinishedMap::iterator pending_it =
- pending_finished_downloads_.find(info->download_id);
- bool download_finished = (pending_it != pending_finished_downloads_.end());
+ bool download_finished = ContainsKey(pending_finished_downloads_,
+ info->download_id);
if (download_finished || info->is_dangerous) {
// The download has already finished or the download is not safe.
@@ -622,82 +452,29 @@ void DownloadManager::ContinueStartDownload(DownloadCreateInfo* info,
if (download_finished) {
// If the download already completed by the time we reached this point, then
// notify observers that it did.
- DownloadFinished(pending_it->first, pending_it->second);
+ OnAllDataSaved(info->download_id,
+ pending_finished_downloads_[info->download_id]);
}
download->Rename(target_path);
- // Do not store the download in the history database for a few special cases:
- // - incognito mode (that is the point of this mode)
- // - extensions (users don't think of extension installation as 'downloading')
- // - temporary download, like in drag-and-drop
- // We have to make sure that these handles don't collide with normal db
- // handles, so we use a negative value. Eventually, they could overlap, but
- // you'd have to do enough downloading that your ISP would likely stab you in
- // the neck first. YMMV.
- if (download->is_otr() || download->is_extension_install() ||
- download->is_temporary()) {
- OnCreateDownloadEntryComplete(*info, fake_db_handle_.GetNext());
- } else {
- // Update the history system with the new download.
- // FIXME(paulg) see bug 958058. EXPLICIT_ACCESS below is wrong.
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- hs->CreateDownload(
- *info, &cancelable_consumer_,
- NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete));
- }
- }
+ download_history_->AddEntry(*info, download,
+ NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete));
UpdateAppIcon();
}
-// Convenience function for updating the history service for a download.
-void DownloadManager::UpdateHistoryForDownload(DownloadItem* download) {
- DCHECK(download);
-
- // Don't store info in the database if the download was initiated while in
- // incognito mode or if it hasn't been initialized in our database table.
- if (download->db_handle() <= kUninitializedHandle)
- return;
-
- // FIXME(paulg) see bug 958058. EXPLICIT_ACCESS below is wrong.
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- hs->UpdateDownload(download->received_bytes(),
- download->state(),
- download->db_handle());
- }
-}
-
-void DownloadManager::RemoveDownloadFromHistory(DownloadItem* download) {
- DCHECK(download);
- // FIXME(paulg) see bug 958058. EXPLICIT_ACCESS below is wrong.
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (download->db_handle() > kUninitializedHandle && hs)
- hs->RemoveDownload(download->db_handle());
-}
-
-void DownloadManager::RemoveDownloadsFromHistoryBetween(
- const base::Time remove_begin,
- const base::Time remove_end) {
- // FIXME(paulg) see bug 958058. EXPLICIT_ACCESS below is wrong.
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs)
- hs->RemoveDownloadsBetween(remove_begin, remove_end);
-}
-
void DownloadManager::UpdateDownload(int32 download_id, int64 size) {
DownloadMap::iterator it = in_progress_.find(download_id);
if (it != in_progress_.end()) {
DownloadItem* download = it->second;
download->Update(size);
- UpdateHistoryForDownload(download);
+ download_history_->UpdateEntry(download);
}
UpdateAppIcon();
}
-void DownloadManager::DownloadFinished(int32 download_id, int64 size) {
+void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) {
DownloadMap::iterator it = in_progress_.find(download_id);
if (it == in_progress_.end()) {
// The download is done, but the user hasn't selected a final location for
@@ -718,13 +495,13 @@ void DownloadManager::DownloadFinished(int32 download_id, int64 size) {
pending_finished_downloads_.erase(erase_it);
DownloadItem* download = it->second;
- download->Finished(size);
+ download->OnAllDataSaved(size);
// Clean up will happen when the history system create callback runs if we
// don't have a valid db_handle yet.
- if (download->db_handle() != kUninitializedHandle) {
+ if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
in_progress_.erase(it);
- UpdateHistoryForDownload(download);
+ download_history_->UpdateEntry(download);
}
UpdateAppIcon();
@@ -763,65 +540,29 @@ void DownloadManager::DownloadFinished(int32 download_id, int64 size) {
void DownloadManager::DownloadRenamedToFinalName(int download_id,
const FilePath& full_path) {
- DownloadMap::iterator it = downloads_.begin();
- while (it != downloads_.end()) {
- DownloadItem* download = it->second;
- if (download->id() == download_id) {
- // The download file is meant to be completed if both the filename is
- // finalized and the file data is downloaded. The ordering of these two
- // actions is indeterministic. Thus, if we are still in downloading the
- // file, delay the notification.
- download->set_name_finalized(true);
- if (download->state() == DownloadItem::COMPLETE)
- download->NotifyObserversDownloadFileCompleted();
-
- // This was called from DownloadFinished; continue to call
- // ContinueDownloadFinished.
- if (download->need_final_rename()) {
- download->set_need_final_rename(false);
- ContinueDownloadFinished(download);
- }
- return;
- }
- it++;
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ DownloadItem* item = GetDownloadItem(download_id);
+ if (!item)
+ return;
+ item->OnNameFinalized();
+
+ // This was called from DownloadFinished; continue to call
+ // ContinueDownloadFinished.
+ if (item->need_final_rename()) {
+ item->set_need_final_rename(false);
+ ContinueDownloadFinished(item);
}
}
void DownloadManager::ContinueDownloadFinished(DownloadItem* download) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::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.
- DownloadMap::iterator it = dangerous_finished_.find(download->id());
- if (it != dangerous_finished_.end())
- dangerous_finished_.erase(it);
-
- // Handle chrome extensions explicitly and skip the shell execute.
- if (download->is_extension_install()) {
- OpenChromeExtension(download->full_path(),
- download->url(),
- download->referrer_url(),
- download->original_mime_type());
- download->set_auto_opened(true);
- } else if (download->open_when_complete() ||
- ShouldOpenFileBasedOnExtension(download->full_path()) ||
- download->is_temporary()) {
- // If the download is temporary, like in drag-and-drop, do not open it but
- // we still need to set it auto-opened so that it can be removed from the
- // download shelf.
- if (!download->is_temporary())
- OpenDownloadInShell(download, NULL);
- download->set_auto_opened(true);
- }
+ dangerous_finished_.erase(download->id());
- // Notify our observers that we are complete (the call to Finished() set the
- // state to complete but did not notify).
- download->UpdateObservers();
-
- // The download file is meant to be completed if both the filename is
- // finalized and the file data is downloaded. The ordering of these two
- // actions is indeterministic. Thus, if the filename is not finalized yet,
- // delay the notification.
- if (download->name_finalized())
- download->NotifyObserversDownloadFileCompleted();
+ download->Finished();
}
// Called on the file thread. Renames the downloaded file to its original name.
@@ -885,9 +626,9 @@ void DownloadManager::DownloadCancelled(int32 download_id) {
// Clean up will happen when the history system create callback runs if we
// don't have a valid db_handle yet.
- if (download->db_handle() != kUninitializedHandle) {
+ if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
in_progress_.erase(it);
- UpdateHistoryForDownload(download);
+ download_history_->UpdateEntry(download);
}
DownloadCancelledInternal(download_id,
@@ -907,8 +648,6 @@ void DownloadManager::DownloadCancelledInternal(int download_id,
render_process_id,
request_id));
- // Tell the file manager to cancel the download.
- file_manager_->RemoveDownload(download_id, this); // On the UI thread
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(
@@ -924,73 +663,33 @@ void DownloadManager::PauseDownload(int32 download_id, bool pause) {
if (pause == download->is_paused())
return;
- // Inform the ResourceDispatcherHost of the new pause state.
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
- NewRunnableFunction(&DownloadManager::OnPauseDownloadRequest,
- g_browser_process->resource_dispatcher_host(),
- download->render_process_id(),
- download->request_id(),
- pause));
-}
-
-// static
-void DownloadManager::OnPauseDownloadRequest(ResourceDispatcherHost* rdh,
- int render_process_id,
- int request_id,
- bool pause) {
- rdh->PauseRequest(render_process_id, request_id, pause);
-}
-
-bool DownloadManager::IsDangerous(const FilePath& file_name) {
- // TODO(jcampan): Improve me.
- return IsExecutableFile(file_name);
+ NewRunnableMethod(this,
+ &DownloadManager::PauseDownloadRequest,
+ g_browser_process->resource_dispatcher_host(),
+ download->render_process_id(),
+ download->request_id(),
+ pause));
}
void DownloadManager::UpdateAppIcon() {
- int64 total_bytes = 0;
- int64 received_bytes = 0;
- int download_count = 0;
- bool progress_known = true;
-
- for (DownloadMap::iterator i = in_progress_.begin();
- i != in_progress_.end();
- ++i) {
- ++download_count;
- const DownloadItem* item = i->second;
- if (item->total_bytes() > 0) {
- total_bytes += item->total_bytes();
- received_bytes += item->received_bytes();
- } else {
- // This download didn't specify a Content-Length, so the combined progress
- // bar neeeds to be indeterminate.
- progress_known = false;
- }
- }
-
- float progress = 0;
- if (progress_known && download_count)
- progress = (float)received_bytes / total_bytes;
-
- download_util::UpdateAppIconDownloadProgress(download_count,
- progress_known,
- progress);
+ if (status_updater_)
+ status_updater_->Update();
}
void DownloadManager::RenameDownload(DownloadItem* download,
const FilePath& new_path) {
download->Rename(new_path);
+ download_history_->UpdateDownloadPath(download, new_path);
+}
- // Update the history.
-
- // No update necessary if the download was initiated while in incognito mode.
- if (download->db_handle() <= kUninitializedHandle)
- return;
-
- // FIXME(paulg) see bug 958058. EXPLICIT_ACCESS below is wrong.
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs)
- hs->UpdateDownloadPath(new_path, download->db_handle());
+void DownloadManager::PauseDownloadRequest(ResourceDispatcherHost* rdh,
+ int render_process_id,
+ int request_id,
+ bool pause) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ rdh->PauseRequest(render_process_id, request_id, pause);
}
void DownloadManager::RemoveDownload(int64 download_handle) {
@@ -1000,7 +699,7 @@ void DownloadManager::RemoveDownload(int64 download_handle) {
// Make history update.
DownloadItem* download = it->second;
- RemoveDownloadFromHistory(download);
+ download_history_->RemoveEntry(download);
// Remove from our tables and delete.
downloads_.erase(it);
@@ -1016,7 +715,7 @@ void DownloadManager::RemoveDownload(int64 download_handle) {
int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
const base::Time remove_end) {
- RemoveDownloadsFromHistoryBetween(remove_begin, remove_end);
+ download_history_->RemoveEntriesBetween(remove_begin, remove_end);
DownloadMap::iterator it = downloads_.begin();
std::vector<DownloadItem*> pending_deletes;
@@ -1036,7 +735,6 @@ int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
dangerous_finished_.erase(dit);
pending_deletes.push_back(download);
- // Observer interface.
continue;
}
@@ -1070,6 +768,10 @@ int DownloadManager::RemoveAllDownloads() {
return RemoveDownloadsBetween(base::Time(), base::Time());
}
+void DownloadManager::SavePageAsDownloadStarted(DownloadItem* download_item) {
+ save_page_downloads_.push_back(download_item);
+}
+
// Initiate a download of a specific URL. We send the request to the
// ResourceDispatcherHost, and let it send us responses like a regular
// download.
@@ -1099,122 +801,6 @@ void DownloadManager::DownloadUrlToFile(const GURL& url,
request_context_getter_));
}
-void DownloadManager::GenerateExtension(
- const FilePath& file_name,
- const std::string& mime_type,
- FilePath::StringType* generated_extension) {
- // We're worried about three things here:
- //
- // 1) Security. Many sites let users upload content, such as buddy icons, to
- // their web sites. We want to mitigate the case where an attacker
- // supplies a malicious executable with an executable file extension but an
- // honest site serves the content with a benign content type, such as
- // image/jpeg.
- //
- // 2) Usability. If the site fails to provide a file extension, we want to
- // guess a reasonable file extension based on the content type.
- //
- // 3) Shell integration. Some file extensions automatically integrate with
- // the shell. We block these extensions to prevent a malicious web site
- // from integrating with the user's shell.
-
- static const FilePath::CharType default_extension[] =
- FILE_PATH_LITERAL("download");
-
- // See if our file name already contains an extension.
- FilePath::StringType extension = file_name.Extension();
- if (!extension.empty())
- extension.erase(extension.begin()); // Erase preceding '.'.
-
-#if defined(OS_WIN)
- // Rename shell-integrated extensions.
- if (win_util::IsShellIntegratedExtension(extension))
- extension.assign(default_extension);
-#endif
-
- std::string mime_type_from_extension;
- net::GetMimeTypeFromFile(file_name,
- &mime_type_from_extension);
- if (mime_type == mime_type_from_extension) {
- // The hinted extension matches the mime type. It looks like a winner.
- generated_extension->swap(extension);
- return;
- }
-
- if (IsExecutableExtension(extension) && !IsExecutableMimeType(mime_type)) {
- // We want to be careful about executable extensions. The worry here is
- // that a trusted web site could be tricked into dropping an executable file
- // on the user's filesystem.
- if (!net::GetPreferredExtensionForMimeType(mime_type, &extension)) {
- // We couldn't find a good extension for this content type. Use a dummy
- // extension instead.
- extension.assign(default_extension);
- }
- }
-
- if (extension.empty()) {
- net::GetPreferredExtensionForMimeType(mime_type, &extension);
- } else {
- // Append extension generated from the mime type if:
- // 1. New extension is not ".txt"
- // 2. New extension is not the same as the already existing extension.
- // 3. New extension is not executable. This action mitigates the case when
- // an executable is hidden in a benign file extension;
- // E.g. my-cat.jpg becomes my-cat.jpg.js if content type is
- // application/x-javascript.
- // 4. New extension is not ".tar" for .gz files. For misconfigured web
- // servers, i.e. bug 5772.
- // 5. The original extension is not ".tgz" & the new extension is not "gz".
- FilePath::StringType append_extension;
- if (net::GetPreferredExtensionForMimeType(mime_type, &append_extension)) {
- if (append_extension != FILE_PATH_LITERAL("txt") &&
- append_extension != extension &&
- !IsExecutableExtension(append_extension) &&
- !(append_extension == FILE_PATH_LITERAL("gz") &&
- extension == FILE_PATH_LITERAL("tgz")) &&
- (append_extension != FILE_PATH_LITERAL("tar") ||
- extension != FILE_PATH_LITERAL("gz"))) {
- extension += FILE_PATH_LITERAL(".");
- extension += append_extension;
- }
- }
- }
-
- generated_extension->swap(extension);
-}
-
-void DownloadManager::GenerateFileNameFromInfo(DownloadCreateInfo* info,
- FilePath* generated_name) {
- GenerateFileName(GURL(info->url),
- info->content_disposition,
- info->referrer_charset,
- info->mime_type,
- generated_name);
-}
-
-void DownloadManager::GenerateFileName(const GURL& url,
- const std::string& content_disposition,
- const std::string& referrer_charset,
- const std::string& mime_type,
- FilePath* generated_name) {
- std::wstring default_name =
- l10n_util::GetString(IDS_DEFAULT_DOWNLOAD_FILENAME);
-#if defined(OS_WIN)
- FilePath default_file_path(default_name);
-#elif defined(OS_POSIX)
- FilePath default_file_path(base::SysWideToNativeMB(default_name));
-#endif
-
- *generated_name = net::GetSuggestedFilename(GURL(url),
- content_disposition,
- referrer_charset,
- default_file_path);
-
- DCHECK(!generated_name->empty());
-
- GenerateSafeFileName(mime_type, generated_name);
-}
-
void DownloadManager::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
observer->ModelChanged();
@@ -1224,216 +810,52 @@ void DownloadManager::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
-// Post Windows Shell operations to the Download thread, to avoid blocking the
-// user interface.
-void DownloadManager::ShowDownloadInShell(const DownloadItem* download) {
- DCHECK(file_manager_);
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-#if defined(OS_MACOSX)
- // Mac needs to run this operation on the UI thread.
- platform_util::ShowItemInFolder(download->full_path());
-#else
- ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(
- file_manager_, &DownloadFileManager::OnShowDownloadInShell,
- FilePath(download->full_path())));
-#endif
-}
-
-void DownloadManager::OpenDownload(const DownloadItem* download,
- gfx::NativeView parent_window) {
- // Open Chrome extensions with ExtensionsService. For everything else do shell
- // execute.
- if (download->is_extension_install()) {
- OpenChromeExtension(download->full_path(),
- download->url(),
- download->referrer_url(),
- download->original_mime_type());
- } else {
- OpenDownloadInShell(download, parent_window);
- }
-}
-
-void DownloadManager::OpenChromeExtension(
- const FilePath& full_path,
- const GURL& download_url,
- const GURL& referrer_url,
- const std::string& original_mime_type) {
- // We don't support extensions in OTR mode.
- ExtensionsService* service = profile_->GetExtensionsService();
- if (service) {
- NotificationService* nservice = NotificationService::current();
- GURL nonconst_download_url = download_url;
- nservice->Notify(NotificationType::EXTENSION_READY_FOR_INSTALL,
- Source<DownloadManager>(this),
- Details<GURL>(&nonconst_download_url));
-
- scoped_refptr<CrxInstaller> installer(
- new CrxInstaller(service->install_directory(),
- service,
- new ExtensionInstallUI(profile_)));
- installer->set_delete_source(true);
-
- if (UserScript::HasUserScriptFileExtension(download_url)) {
- installer->InstallUserScript(full_path, download_url);
- } else {
- bool is_gallery_download =
- ExtensionsService::IsDownloadFromGallery(download_url, referrer_url);
- installer->set_original_mime_type(original_mime_type);
- installer->set_apps_require_extension_mime_type(true);
- installer->set_allow_privilege_increase(true);
- installer->set_original_url(download_url);
- installer->set_limit_web_extent_to_download_host(!is_gallery_download);
- installer->InstallCrx(full_path);
- }
- } else {
- TabContents* contents = NULL;
- // Get last active normal browser of profile.
- Browser* last_active = BrowserList::FindBrowserWithType(profile_,
- Browser::TYPE_NORMAL, true);
- if (last_active)
- contents = last_active->GetSelectedTabContents();
- if (contents) {
- contents->AddInfoBar(
- new SimpleAlertInfoBarDelegate(contents,
- l10n_util::GetString(
- IDS_EXTENSION_INCOGNITO_INSTALL_INFOBAR_LABEL),
- ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_INFOBAR_PLUGIN_INSTALL),
- true));
- }
- }
-}
-
-void DownloadManager::OpenDownloadInShell(const DownloadItem* download,
- gfx::NativeView parent_window) {
- DCHECK(file_manager_);
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-#if defined(OS_MACOSX)
- // Mac OS X requires opening downloads on the UI thread.
- platform_util::OpenItem(download->full_path());
-#else
- ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(
- file_manager_, &DownloadFileManager::OnOpenDownloadInShell,
- download->full_path(), download->url(), parent_window));
-#endif
-}
-
-void DownloadManager::OpenFilesBasedOnExtension(
- const FilePath& path, bool open) {
- FilePath::StringType extension = path.Extension();
- if (extension.empty())
- return;
- DCHECK(extension[0] == FilePath::kExtensionSeparator);
- extension.erase(0, 1);
- if (open && !IsExecutableExtension(extension))
- auto_open_.insert(extension);
- else
- auto_open_.erase(extension);
- SaveAutoOpens();
-}
-
bool DownloadManager::ShouldOpenFileBasedOnExtension(
const FilePath& path) const {
FilePath::StringType extension = path.Extension();
if (extension.empty())
return false;
- if (IsExecutableExtension(extension))
+ if (download_util::IsExecutableExtension(extension))
return false;
if (Extension::IsExtension(path))
return false;
DCHECK(extension[0] == FilePath::kExtensionSeparator);
extension.erase(0, 1);
- if (auto_open_.find(extension) != auto_open_.end())
- return true;
- return false;
+ return download_prefs_->IsAutoOpenEnabledForExtension(extension);
}
-static const char* kExecutableWhiteList[] = {
- // JavaScript is just as powerful as EXE.
- "text/javascript",
- "text/javascript;version=*",
- // Registry files can cause critical changes to the MS OS behavior.
- // Addition of this mimetype also addresses bug 7337.
- "text/x-registry",
- // 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"
-};
-
-// static
-bool DownloadManager::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))
+bool DownloadManager::IsDownloadProgressKnown() {
+ for (DownloadMap::iterator i = in_progress_.begin();
+ i != in_progress_.end(); ++i) {
+ if (i->second->total_bytes() <= 0)
return false;
}
- // We consider only other application types to be executable.
- return net::MatchesMimeType("application/*", mime_type);
-}
-
-bool DownloadManager::IsExecutableFile(const FilePath& path) const {
- return IsExecutableExtension(path.Extension());
-}
-bool DownloadManager::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);
-
- return download_util::IsExecutableExtension(ascii_extension);
+ return true;
}
-void DownloadManager::ResetAutoOpenFiles() {
- auto_open_.clear();
- SaveAutoOpens();
+int64 DownloadManager::GetInProgressDownloadCount() {
+ return in_progress_.size();
}
-bool DownloadManager::HasAutoOpenFileTypesRegistered() const {
- return !auto_open_.empty();
+int64 DownloadManager::GetReceivedDownloadBytes() {
+ DCHECK(IsDownloadProgressKnown());
+ int64 received_bytes = 0;
+ for (DownloadMap::iterator i = in_progress_.begin();
+ i != in_progress_.end(); ++i) {
+ received_bytes += i->second->received_bytes();
+ }
+ return received_bytes;
}
-void DownloadManager::SaveAutoOpens() {
- PrefService* prefs = profile_->GetPrefs();
- if (prefs) {
- std::string extensions;
- for (AutoOpenSet::iterator it = auto_open_.begin();
- it != auto_open_.end(); ++it) {
-#if defined(OS_POSIX)
- std::string this_extension = *it;
-#elif defined(OS_WIN)
- std::string this_extension = base::SysWideToUTF8(*it);
-#endif
- extensions += this_extension + ":";
- }
- if (!extensions.empty())
- extensions.erase(extensions.size() - 1);
-
- prefs->SetString(prefs::kDownloadExtensionsToOpen, extensions);
+int64 DownloadManager::GetTotalDownloadBytes() {
+ DCHECK(IsDownloadProgressKnown());
+ int64 total_bytes = 0;
+ for (DownloadMap::iterator i = in_progress_.begin();
+ i != in_progress_.end(); ++i) {
+ total_bytes += i->second->total_bytes();
}
+ return total_bytes;
}
void DownloadManager::FileSelected(const FilePath& path,
@@ -1441,7 +863,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();
- ContinueStartDownload(info, path);
+ CreateDownloadItem(info, path);
}
void DownloadManager::FileSelectionCanceled(void* params) {
@@ -1453,12 +875,6 @@ void DownloadManager::FileSelectionCanceled(void* params) {
info->request_id);
}
-void DownloadManager::DeleteDownload(const FilePath& path) {
- ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
- NewRunnableFunction(&DeleteDownloadedFile, path));
-}
-
void DownloadManager::DangerousDownloadValidated(DownloadItem* download) {
DCHECK_EQ(DownloadItem::DANGEROUS, download->safety_state());
download->set_safety_state(DownloadItem::DANGEROUS_BUT_VALIDATED);
@@ -1477,29 +893,6 @@ void DownloadManager::DangerousDownloadValidated(DownloadItem* download) {
download->original_name()));
}
-void DownloadManager::GenerateSafeFileName(const std::string& mime_type,
- FilePath* file_name) {
- // Make sure we get the right file extension
- FilePath::StringType extension;
- GenerateExtension(*file_name, mime_type, &extension);
- *file_name = file_name->ReplaceExtension(extension);
-
-#if defined(OS_WIN)
- // Prepend "_" to the file name if it's a reserved name
- FilePath::StringType leaf_name = file_name->BaseName().value();
- DCHECK(!leaf_name.empty());
- if (win_util::IsReservedName(leaf_name)) {
- leaf_name = FilePath::StringType(FILE_PATH_LITERAL("_")) + leaf_name;
- *file_name = file_name->DirName();
- if (file_name->value() == FilePath::kCurrentDirectory) {
- *file_name = FilePath(leaf_name);
- } else {
- *file_name = file_name->Append(leaf_name);
- }
- }
-#endif
-}
-
// Operations posted to us from the history service ----------------------------
// The history service has retrieved all download entries. 'entries' contains
@@ -1507,10 +900,9 @@ void DownloadManager::GenerateSafeFileName(const std::string& mime_type,
void DownloadManager::OnQueryDownloadEntriesComplete(
std::vector<DownloadCreateInfo>* entries) {
for (size_t i = 0; i < entries->size(); ++i) {
- DownloadItem* download = new DownloadItem(entries->at(i));
- DCHECK(downloads_.find(download->db_handle()) == downloads_.end());
+ DownloadItem* download = new DownloadItem(this, entries->at(i));
+ DCHECK(!ContainsKey(downloads_, download->db_handle()));
downloads_[download->db_handle()] = download;
- download->set_manager(this);
}
NotifyModelChanged();
}
@@ -1530,10 +922,10 @@ void DownloadManager::OnCreateDownloadEntryComplete(DownloadCreateInfo info,
// happen when the history database is offline. We cannot have multiple
// DownloadItems with the same invalid db_handle, so we need to assign a
// unique |db_handle| here.
- if (db_handle == kUninitializedHandle)
- db_handle = fake_db_handle_.GetNext();
+ if (db_handle == DownloadHistory::kUninitializedHandle)
+ db_handle = download_history_->GetNextFakeDbHandle();
- DCHECK(download->db_handle() == kUninitializedHandle);
+ DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle);
download->set_db_handle(db_handle);
// Insert into our full map.
@@ -1552,33 +944,13 @@ void DownloadManager::OnCreateDownloadEntryComplete(DownloadCreateInfo info,
// observers so that they get more than just the start notification.
if (download->state() != DownloadItem::IN_PROGRESS) {
in_progress_.erase(it);
- UpdateHistoryForDownload(download);
+ download_history_->UpdateEntry(download);
download->UpdateObservers();
}
UpdateAppIcon();
}
-// Called when the history service has retrieved the list of downloads that
-// match the search text.
-void DownloadManager::OnSearchComplete(HistoryService::Handle handle,
- std::vector<int64>* results) {
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- Observer* requestor = cancelable_consumer_.GetClientData(hs, handle);
- if (!requestor)
- return;
-
- std::vector<DownloadItem*> searched_downloads;
- for (std::vector<int64>::iterator it = results->begin();
- it != results->end(); ++it) {
- DownloadMap::iterator dit = downloads_.find(*it);
- if (dit != downloads_.end())
- searched_downloads.push_back(dit->second);
- }
-
- requestor->SetDownloads(searched_downloads);
-}
-
void DownloadManager::ShowDownloadInBrowser(const DownloadCreateInfo& info,
DownloadItem* download) {
// The 'contents' may no longer exist if the user closed the tab before we
@@ -1609,6 +981,16 @@ void DownloadManager::NotifyModelChanged() {
FOR_EACH_OBSERVER(Observer, observers_, ModelChanged());
}
+DownloadItem* DownloadManager::GetDownloadItem(int id) {
+ for (DownloadMap::iterator it = downloads_.begin();
+ it != downloads_.end(); ++it) {
+ DownloadItem* item = it->second;
+ if (item->id() == id)
+ return item;
+ }
+ return NULL;
+}
+
// DownloadManager::OtherDownloadManagerObserver implementation ----------------
DownloadManager::OtherDownloadManagerObserver::OtherDownloadManagerObserver(
@@ -1634,10 +1016,6 @@ void DownloadManager::OtherDownloadManagerObserver::ModelChanged() {
observing_download_manager_->NotifyModelChanged();
}
-void DownloadManager::OtherDownloadManagerObserver::SetDownloads(
- std::vector<DownloadItem*>& downloads) {
-}
-
void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() {
observed_download_manager_ = NULL;
}
diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h
index 1f23b4f..02c7aa1 100644
--- a/chrome/browser/download/download_manager.h
+++ b/chrome/browser/download/download_manager.h
@@ -26,6 +26,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_H_
+#pragma once
#include <map>
#include <set>
@@ -36,37 +37,40 @@
#include "base/file_path.h"
#include "base/observer_list.h"
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "base/time.h"
-#include "chrome/browser/cancelable_request.h"
-#include "chrome/browser/history/history.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/download/download_status_updater_delegate.h"
#include "chrome/browser/shell_dialogs.h"
class DownloadFileManager;
+class DownloadHistory;
class DownloadItem;
+class DownloadPrefs;
+class DownloadStatusUpdater;
class GURL;
-class PrefService;
class Profile;
class ResourceDispatcherHost;
class URLRequestContextGetter;
class TabContents;
+struct DownloadCreateInfo;
struct DownloadSaveInfo;
// Browser's download manager: manages all downloads and destination view.
-class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
- public SelectFileDialog::Listener {
+class DownloadManager
+ : public base::RefCountedThreadSafe<DownloadManager,
+ ChromeThread::DeleteOnUIThread>,
+ public DownloadStatusUpdaterDelegate,
+ public SelectFileDialog::Listener {
// For testing.
friend class DownloadManagerTest;
friend class MockDownloadManager;
public:
- // A fake download table ID which representas a download that has started,
- // but is not yet in the table.
- static const int kUninitializedHandle;
+ explicit DownloadManager(DownloadStatusUpdater* status_updater);
- DownloadManager();
-
- static void RegisterUserPrefs(PrefService* prefs);
+ // Shutdown the download manager. Must be called before destruction.
+ void Shutdown();
// Interface to implement for observers that wish to be informed of changes
// to the DownloadManager's collection of downloads.
@@ -76,11 +80,6 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
// of downloads.
virtual void ModelChanged() = 0;
- // A callback once the DownloadManager has retrieved the requested set of
- // downloads. The DownloadManagerObserver must copy the vector, but does not
- // own the individual DownloadItems, when this call is made.
- virtual void SetDownloads(std::vector<DownloadItem*>& downloads) = 0;
-
// Called when the DownloadManager is being destroyed to prevent Observers
// from calling back to a stale pointer.
virtual void ManagerGoingDown() {}
@@ -89,48 +88,32 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
virtual ~Observer() {}
};
- // Public API
-
- // If this download manager has an incognito profile, find all incognito
- // downloads and pass them along to the parent profile's download manager
- // via DoGetDownloads. Otherwise, just call DoGetDownloads().
- void GetDownloads(Observer* observer,
- const std::wstring& search_text);
-
- // Begin a search for all downloads matching 'search_text'. If 'search_text'
- // is empty, return all known downloads. The results are returned in the
- // 'SetDownloads' observer callback.
- void DoGetDownloads(Observer* observer,
- const std::wstring& search_text,
- std::vector<DownloadItem*>& otr_downloads);
-
// Return all temporary downloads that reside in the specified directory.
- void GetTemporaryDownloads(Observer* observer,
- const FilePath& dir_path);
+ void GetTemporaryDownloads(const FilePath& dir_path,
+ std::vector<DownloadItem*>* result);
// Return all non-temporary downloads in the specified directory that are
// are in progress or have finished.
- void GetAllDownloads(Observer* observer, const FilePath& dir_path);
+ void GetAllDownloads(const FilePath& dir_path,
+ std::vector<DownloadItem*>* result);
// Return all non-temporary downloads in the specified directory that are
// either in-progress or finished but still waiting for user confirmation.
- void GetCurrentDownloads(Observer* observer, const FilePath& dir_path);
+ void GetCurrentDownloads(const FilePath& dir_path,
+ std::vector<DownloadItem*>* result);
+
+ // Returns all non-temporary downloads matching |query|. Empty query matches
+ // everything.
+ void SearchDownloads(const string16& query,
+ std::vector<DownloadItem*>* result);
// Returns true if initialized properly.
bool Init(Profile* profile);
- // Schedule a query of the history service to retrieve all downloads.
- void QueryHistoryForDownloads();
-
- // Cleans up IN_PROGRESS history entries as these entries are corrupt because
- // of the sudden exit. Changes them to CANCELED. Executed only when called
- // first time, subsequent calls a no op.
- void CleanUpInProgressHistoryEntries();
-
// Notifications sent from the download thread to the UI thread
void StartDownload(DownloadCreateInfo* info);
void UpdateDownload(int32 download_id, int64 size);
- void DownloadFinished(int32 download_id, int64 size);
+ void OnAllDataSaved(int32 download_id, int64 size);
// Called from a view when a user clicks a UI button or link.
void DownloadCancelled(int32 download_id);
@@ -155,6 +138,10 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
// deleted is returned back to the caller.
int RemoveAllDownloads();
+ // Called when a Save Page As download is started. Transfers ownership
+ // of |download_item| to the DownloadManager.
+ void SavePageAsDownloadStarted(DownloadItem* download_item);
+
// Download the object at the URL. Used in cases such as "Save Link As..."
void DownloadUrl(const GURL& url,
const GURL& referrer,
@@ -180,89 +167,42 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
void OnQueryDownloadEntriesComplete(
std::vector<DownloadCreateInfo>* entries);
void OnCreateDownloadEntryComplete(DownloadCreateInfo info, int64 db_handle);
- void OnSearchComplete(HistoryService::Handle handle,
- std::vector<int64>* results);
// Display a new download in the appropriate browser UI.
void ShowDownloadInBrowser(const DownloadCreateInfo& info,
DownloadItem* download);
- // Opens a download. For Chrome extensions call
- // ExtensionsServices::InstallExtension, for everything else call
- // OpenDownloadInShell.
- void OpenDownload(const DownloadItem* download,
- gfx::NativeView parent_window);
-
- // Show a download via the Windows shell.
- void ShowDownloadInShell(const DownloadItem* download);
-
// The number of in progress (including paused) downloads.
int in_progress_count() const {
return static_cast<int>(in_progress_.size());
}
- FilePath download_path() { return *download_path_; }
+ Profile* profile() { return profile_; }
+
+ DownloadHistory* download_history() { return download_history_.get(); }
+
+ DownloadPrefs* download_prefs() { return download_prefs_.get(); }
// Clears the last download path, used to initialize "save as" dialogs.
void ClearLastDownloadPath();
- // Registers this file extension for automatic opening upon download
- // completion if 'open' is true, or prevents the extension from automatic
- // opening if 'open' is false.
- void OpenFilesBasedOnExtension(const FilePath& path, bool open);
-
// Tests if a file type should be opened automatically.
bool ShouldOpenFileBasedOnExtension(const FilePath& path) const;
- // Tests if we think the server means for this mime_type to be executable.
- static bool IsExecutableMimeType(const std::string& mime_type);
-
- // Tests if a file is considered executable, based on its type.
- bool IsExecutableFile(const FilePath& path) const;
-
- // Tests if a file type is considered executable.
- static bool IsExecutableExtension(const FilePath::StringType& extension);
-
- // Resets the automatic open preference.
- void ResetAutoOpenFiles();
-
- // Returns true if there are automatic handlers registered for any file
- // types.
- bool HasAutoOpenFileTypesRegistered() const;
+ // Overridden from DownloadStatusUpdaterDelegate:
+ virtual bool IsDownloadProgressKnown();
+ virtual int64 GetInProgressDownloadCount();
+ virtual int64 GetReceivedDownloadBytes();
+ virtual int64 GetTotalDownloadBytes();
// Overridden from SelectFileDialog::Listener:
virtual void FileSelected(const FilePath& path, int index, void* params);
virtual void FileSelectionCanceled(void* params);
- // Deletes the specified path on the file thread.
- void DeleteDownload(const FilePath& path);
-
- // Called when the user has validated the donwload of a dangerous file.
+ // Called when the user has validated the download of a dangerous file.
void DangerousDownloadValidated(DownloadItem* download);
- // Used to make sure we have a safe file extension and filename for a
- // download. |file_name| can either be just the file name or it can be a
- // full path to a file.
- static void GenerateSafeFileName(const std::string& mime_type,
- FilePath* file_name);
-
- // Create a file name based on the response from the server.
- static void GenerateFileName(const GURL& url,
- const std::string& content_disposition,
- const std::string& referrer_charset,
- const std::string& mime_type,
- FilePath* generated_name);
-
private:
- class FakeDbHandleGenerator {
- public:
- explicit FakeDbHandleGenerator(int64 start_value) : value_(start_value) {}
-
- int64 GetNext() { return value_--; }
- private:
- int64 value_;
- };
-
// This class is used to let an incognito DownloadManager observe changes to
// a normal DownloadManager, to propagate ModelChanged() calls from the parent
// DownloadManager to the observers of the incognito DownloadManager.
@@ -274,7 +214,6 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
// Observer interface.
virtual void ModelChanged();
- virtual void SetDownloads(std::vector<DownloadItem*>& downloads);
virtual void ManagerGoingDown();
private:
@@ -285,24 +224,12 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
DownloadManager* observed_download_manager_;
};
- friend class base::RefCountedThreadSafe<DownloadManager>;
+ friend class ChromeThread;
+ friend class DeleteTask<DownloadManager>;
friend class OtherDownloadManagerObserver;
~DownloadManager();
- // Opens a download via the Windows shell.
- void OpenDownloadInShell(const DownloadItem* download,
- gfx::NativeView parent_window);
-
- // Opens downloaded Chrome extension file (*.crx).
- void OpenChromeExtension(const FilePath& full_path,
- const GURL& download_url,
- const GURL& referrer_url,
- const std::string& original_mime_type);
-
- // Shutdown the download manager. This call is needed only after Init.
- void Shutdown();
-
// Called on the download thread to check whether the suggested file path
// exists. We don't check if the file exists on the UI thread to avoid UI
// stalls from interacting with the file system.
@@ -315,46 +242,20 @@ class DownloadManager : public base::RefCountedThreadSafe<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 ContinueStartDownload(DownloadCreateInfo* info,
- const FilePath& target_path);
-
- // Update the history service for a particular download.
- // Marked virtual for testing.
- virtual void UpdateHistoryForDownload(DownloadItem* download);
- void RemoveDownloadFromHistory(DownloadItem* download);
- void RemoveDownloadsFromHistoryBetween(const base::Time remove_begin,
- const base::Time remove_before);
-
- // Create an extension based on the file name and mime type.
- static void GenerateExtension(const FilePath& file_name,
- const std::string& mime_type,
- FilePath::StringType* generated_extension);
-
- // Create a file name based on the response from the server.
- static void GenerateFileNameFromInfo(DownloadCreateInfo* info,
- FilePath* generated_name);
-
- // Persist the automatic opening preference.
- void SaveAutoOpens();
+ void CreateDownloadItem(DownloadCreateInfo* info,
+ const FilePath& target_path);
// Download cancel helper function.
void DownloadCancelledInternal(int download_id,
int render_process_id,
int request_id);
- // Runs the pause on the IO thread.
- static void OnPauseDownloadRequest(ResourceDispatcherHost* rdh,
- int render_process_id,
- int request_id,
- bool pause);
-
// 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.
- // Marked virtual for testing.
- virtual void ContinueDownloadFinished(DownloadItem* download);
+ void ContinueDownloadFinished(DownloadItem* download);
// Renames a finished dangerous download from its temporary file name to its
// real file name.
@@ -369,20 +270,25 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
const FilePath& new_path,
int new_path_uniquifier);
- // Checks whether a file represents a risk if downloaded.
- bool IsDangerous(const FilePath& file_name);
-
// Updates the app icon about the overall download progress.
- // Marked virtual for testing.
- virtual void UpdateAppIcon();
+ void UpdateAppIcon();
// Changes the paths and file name of the specified |download|, propagating
// the change to the history system.
void RenameDownload(DownloadItem* download, const FilePath& new_path);
+ // Makes the ResourceDispatcherHost pause/un-pause a download request.
+ // Called on the IO thread.
+ void PauseDownloadRequest(ResourceDispatcherHost* rdh,
+ int render_process_id,
+ int request_id,
+ bool pause);
+
// Inform observers that the model has changed.
void NotifyModelChanged();
+ 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
@@ -412,6 +318,10 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
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_;
+
// True if the download manager has been initialized and requires a shutdown.
bool shutdown_needed_;
@@ -422,30 +332,20 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
Profile* profile_;
scoped_refptr<URLRequestContextGetter> request_context_getter_;
- // Used for history service request management.
- CancelableRequestConsumerTSimple<Observer*> cancelable_consumer_;
+ scoped_ptr<DownloadHistory> download_history_;
+
+ scoped_ptr<DownloadPrefs> download_prefs_;
// Non-owning pointer for handling file writing on the download_thread_.
DownloadFileManager* file_manager_;
- // User preferences
- BooleanPrefMember prompt_for_download_;
- FilePathPrefMember download_path_;
+ // Non-owning pointer for updating the download status.
+ DownloadStatusUpdater* status_updater_;
// The user's last choice for download directory. This is only used when the
// user wants us to prompt for a save location for each download.
FilePath last_download_path_;
- // Set of file extensions to open at download completion.
- struct AutoOpenCompareFunctor {
- inline bool operator()(const FilePath::StringType& a,
- const FilePath::StringType& b) const {
- return FilePath::CompareLessIgnoreCase(a, b);
- }
- };
- typedef std::set<FilePath::StringType, AutoOpenCompareFunctor> AutoOpenSet;
- AutoOpenSet auto_open_;
-
// Keep track of downloads that are completed before the user selects the
// destination, so that observers are appropriately notified of completion
// after this determination is made.
@@ -458,12 +358,6 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
// saved.
scoped_refptr<SelectFileDialog> select_file_dialog_;
- // In case we don't have a valid db_handle, we use |fake_db_handle_| instead.
- // This is useful for incognito mode or when the history database is offline.
- // Downloads are expected to have unique handles, so FakeDbHandleGenerator
- // automatically decrement the handle value on every use.
- FakeDbHandleGenerator fake_db_handle_;
-
scoped_ptr<OtherDownloadManagerObserver> other_download_manager_observer_;
DISALLOW_COPY_AND_ASSIGN(DownloadManager);
diff --git a/chrome/browser/download/download_manager_unittest.cc b/chrome/browser/download/download_manager_unittest.cc
index c221a5d..ca71804 100644
--- a/chrome/browser/download/download_manager_unittest.cc
+++ b/chrome/browser/download/download_manager_unittest.cc
@@ -10,39 +10,22 @@
#include "chrome/browser/download/download_file.h"
#include "chrome/browser/download/download_file_manager.h"
#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/history/download_types.h"
+#include "chrome/browser/history/download_create_info.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-#include <locale.h>
-#endif
-
-#if defined(OS_WIN)
-#define JPEG_EXT L".jpg"
-#define HTML_EXT L".htm"
-#define TXT_EXT L".txt"
-#define TAR_EXT L".tar"
-#elif defined(OS_MACOSX)
-#define JPEG_EXT L".jpeg"
-#define HTML_EXT L".html"
-#define TXT_EXT L".txt"
-#define TAR_EXT L".tar"
-#else
-#define JPEG_EXT L".jpg"
-#define HTML_EXT L".html"
-#define TXT_EXT L".txt"
-#define TAR_EXT L".tar"
-#endif
-
class MockDownloadManager : public DownloadManager {
public:
+ MockDownloadManager() : DownloadManager(NULL) {
+ }
+
// Override some functions.
- virtual void UpdateAppIcon() { }
virtual void UpdateHistoryForDownload(DownloadItem*) { }
virtual void ContinueDownloadFinished(DownloadItem*) { }
};
@@ -57,24 +40,12 @@ class DownloadManagerTest : public testing::Test {
}
~DownloadManagerTest() {
+ download_manager_->Shutdown();
// profile_ must outlive download_manager_, so we explicitly delete
// download_manager_ first.
- download_manager_.release();
- }
-
- void GetGeneratedFilename(const std::string& content_disposition,
- const std::string& url,
- const std::string& mime_type,
- const std::string& referrer_charset,
- std::wstring* generated_name_string) {
- DownloadCreateInfo info;
- info.content_disposition = content_disposition;
- info.url = GURL(url);
- info.mime_type = mime_type;
- info.referrer_charset = referrer_charset;
- FilePath generated_name;
- DownloadManager::GenerateFileNameFromInfo(&info, &generated_name);
- *generated_name_string = generated_name.ToWStringHack();
+ download_manager_ = NULL;
+ profile_.reset(NULL);
+ message_loop_.RunAllPending();
}
void AddDownloadToFileManager(int id, DownloadFile* download) {
@@ -102,559 +73,6 @@ class DownloadManagerTest : public testing::Test {
namespace {
const struct {
- const char* disposition;
- const char* url;
- const char* mime_type;
- const wchar_t* expected_name;
-} kGeneratedFiles[] = {
- // No 'filename' keyword in the disposition, use the URL
- {"a_file_name.txt",
- "http://www.evil.com/my_download.txt",
- "text/plain",
- L"my_download.txt"},
-
- // Disposition has relative paths, remove them
- {"filename=../../../../././../a_file_name.txt",
- "http://www.evil.com/my_download.txt",
- "text/plain",
- L"a_file_name.txt"},
-
- // Disposition has parent directories, remove them
- {"filename=dir1/dir2/a_file_name.txt",
- "http://www.evil.com/my_download.txt",
- "text/plain",
- L"a_file_name.txt"},
-
- // No useful information in disposition or URL, use default
- {"", "http://www.truncated.com/path/", "text/plain",
- L"download" TXT_EXT
- },
-
- // A normal avi should get .avi and not .avi.avi
- {"", "https://blah.google.com/misc/2.avi", "video/x-msvideo", L"2.avi"},
-
- // Spaces in the disposition file name
- {"filename=My Downloaded File.exe",
- "http://www.frontpagehacker.com/a_download.exe",
- "application/octet-stream",
- L"My Downloaded File.exe"},
-
- // This block tests whether we append extensions based on MIME types;
- // we don't do this on Linux, so we skip the tests rather than #ifdef
- // them up.
-#if !defined(OS_POSIX) || defined(OS_MACOSX)
- {"filename=my-cat",
- "http://www.example.com/my-cat",
- "image/jpeg",
- L"my-cat" JPEG_EXT
- },
-
- {"filename=my-cat",
- "http://www.example.com/my-cat",
- "text/plain",
- L"my-cat.txt"},
-
- {"filename=my-cat",
- "http://www.example.com/my-cat",
- "text/html",
- L"my-cat" HTML_EXT
- },
-
- {"filename=my-cat",
- "http://www.example.com/my-cat",
- "dance/party",
- L"my-cat"},
-#endif // !defined(OS_POSIX) || defined(OS_MACOSX)
-
- {"filename=my-cat.jpg",
- "http://www.example.com/my-cat.jpg",
- "text/plain",
- L"my-cat.jpg"},
-
- // .exe tests.
-#if defined(OS_WIN)
- {"filename=evil.exe",
- "http://www.goodguy.com/evil.exe",
- "image/jpeg",
- L"evil.jpg"},
-
- {"filename=ok.exe",
- "http://www.goodguy.com/ok.exe",
- "binary/octet-stream",
- L"ok.exe"},
-
- {"filename=evil.exe.exe",
- "http://www.goodguy.com/evil.exe.exe",
- "dance/party",
- L"evil.exe.download"},
-
- {"filename=evil.exe",
- "http://www.goodguy.com/evil.exe",
- "application/xml",
- L"evil.xml"},
-
- {"filename=evil.exe",
- "http://www.goodguy.com/evil.exe",
- "application/html+xml",
- L"evil.download"},
-
- {"filename=evil.exe",
- "http://www.goodguy.com/evil.exe",
- "application/rss+xml",
- L"evil.download"},
-
- // Test truncation of trailing dots and spaces
- {"filename=evil.exe ",
- "http://www.goodguy.com/evil.exe ",
- "binary/octet-stream",
- L"evil.exe"},
-
- {"filename=evil.exe.",
- "http://www.goodguy.com/evil.exe.",
- "binary/octet-stream",
- L"evil.exe"},
-
- {"filename=evil.exe. . .",
- "http://www.goodguy.com/evil.exe. . .",
- "binary/octet-stream",
- L"evil.exe"},
-
- {"filename=evil.",
- "http://www.goodguy.com/evil.",
- "binary/octet-stream",
- L"evil"},
-
- {"filename=. . . . .",
- "http://www.goodguy.com/. . . . .",
- "binary/octet-stream",
- L"download"},
-
-#endif // OS_WIN
-
- {"filename=utils.js",
- "http://www.goodguy.com/utils.js",
- "application/x-javascript",
- L"utils.js"},
-
- {"filename=contacts.js",
- "http://www.goodguy.com/contacts.js",
- "application/json",
- L"contacts.js"},
-
- {"filename=utils.js",
- "http://www.goodguy.com/utils.js",
- "text/javascript",
- L"utils.js"},
-
- {"filename=utils.js",
- "http://www.goodguy.com/utils.js",
- "text/javascript;version=2",
- L"utils.js"},
-
- {"filename=utils.js",
- "http://www.goodguy.com/utils.js",
- "application/ecmascript",
- L"utils.js"},
-
- {"filename=utils.js",
- "http://www.goodguy.com/utils.js",
- "application/ecmascript;version=4",
- L"utils.js"},
-
- {"filename=program.exe",
- "http://www.goodguy.com/program.exe",
- "application/foo-bar",
- L"program.exe"},
-
- {"filename=../foo.txt",
- "http://www.evil.com/../foo.txt",
- "text/plain",
- L"foo.txt"},
-
- {"filename=..\\foo.txt",
- "http://www.evil.com/..\\foo.txt",
- "text/plain",
-#if defined(OS_WIN)
- L"foo.txt"
-#else
- L"\\foo.txt"
-#endif
- },
-
- {"filename=.hidden",
- "http://www.evil.com/.hidden",
- "text/plain",
- L"hidden" TXT_EXT
- },
-
- {"filename=trailing.",
- "http://www.evil.com/trailing.",
- "dance/party",
- L"trailing"
- },
-
- {"filename=trailing.",
- "http://www.evil.com/trailing.",
- "text/plain",
- L"trailing" TXT_EXT
- },
-
- {"filename=.",
- "http://www.evil.com/.",
- "dance/party",
- L"download"},
-
- {"filename=..",
- "http://www.evil.com/..",
- "dance/party",
- L"download"},
-
- {"filename=...",
- "http://www.evil.com/...",
- "dance/party",
- L"download"},
-
- // Note that this one doesn't have "filename=" on it.
- {"a_file_name.txt",
- "http://www.evil.com/",
- "image/jpeg",
- L"download" JPEG_EXT
- },
-
- {"filename=",
- "http://www.evil.com/",
- "image/jpeg",
- L"download" JPEG_EXT
- },
-
- {"filename=simple",
- "http://www.example.com/simple",
- "application/octet-stream",
- L"simple"},
-
- {"filename=COM1",
- "http://www.goodguy.com/COM1",
- "application/foo-bar",
-#if defined(OS_WIN)
- L"_COM1"
-#else
- L"COM1"
-#endif
- },
-
- {"filename=COM4.txt",
- "http://www.goodguy.com/COM4.txt",
- "text/plain",
-#if defined(OS_WIN)
- L"_COM4.txt"
-#else
- L"COM4.txt"
-#endif
- },
-
- {"filename=lpt1.TXT",
- "http://www.goodguy.com/lpt1.TXT",
- "text/plain",
-#if defined(OS_WIN)
- L"_lpt1.TXT"
-#else
- L"lpt1.TXT"
-#endif
- },
-
- {"filename=clock$.txt",
- "http://www.goodguy.com/clock$.txt",
- "text/plain",
-#if defined(OS_WIN)
- L"_clock$.txt"
-#else
- L"clock$.txt"
-#endif
- },
-
- {"filename=mycom1.foo",
- "http://www.goodguy.com/mycom1.foo",
- "text/plain",
- L"mycom1.foo"},
-
- {"filename=Setup.exe.local",
- "http://www.badguy.com/Setup.exe.local",
- "application/foo-bar",
-#if defined(OS_WIN)
- L"Setup.exe.download"
-#else
- L"Setup.exe.local"
-#endif
- },
-
- {"filename=Setup.exe.local.local",
- "http://www.badguy.com/Setup.exe.local",
- "application/foo-bar",
-#if defined(OS_WIN)
- L"Setup.exe.local.download"
-#else
- L"Setup.exe.local.local"
-#endif
- },
-
- {"filename=Setup.exe.lnk",
- "http://www.badguy.com/Setup.exe.lnk",
- "application/foo-bar",
-#if defined(OS_WIN)
- L"Setup.exe.download"
-#else
- L"Setup.exe.lnk"
-#endif
- },
-
- {"filename=Desktop.ini",
- "http://www.badguy.com/Desktop.ini",
- "application/foo-bar",
-#if defined(OS_WIN)
- L"_Desktop.ini"
-#else
- L"Desktop.ini"
-#endif
- },
-
- {"filename=Thumbs.db",
- "http://www.badguy.com/Thumbs.db",
- "application/foo-bar",
-#if defined(OS_WIN)
- L"_Thumbs.db"
-#else
- L"Thumbs.db"
-#endif
- },
-
- {"filename=source.srf",
- "http://www.hotmail.com",
- "image/jpeg",
- L"source.srf" JPEG_EXT
- },
-
- {"filename=source.jpg",
- "http://www.hotmail.com",
- "application/x-javascript",
-#if defined(OS_WIN)
- L"source.jpg"
-#elif defined(OS_MACOSX)
- L"source.jpg.js"
-#else
- L"source.jpg"
-#endif
- },
-
- // NetUtilTest.{GetSuggestedFilename, GetFileNameFromCD} test these
- // more thoroughly. Tested below are a small set of samples.
- {"attachment; filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
- "http://www.examples.com/",
- "image/jpeg",
- L"\uc608\uc220 \uc608\uc220.jpg"},
-
- {"attachment; name=abc de.pdf",
- "http://www.examples.com/q.cgi?id=abc",
- "application/octet-stream",
- L"abc de.pdf"},
-
- {"filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
- "http://www.example.com/path",
- "image/png",
- L"\x82b8\x8853" L"3.png"},
-
- // The following two have invalid CD headers and filenames come
- // from the URL.
- {"attachment; filename==?iiso88591?Q?caf=EG?=",
- "http://www.example.com/test%20123",
- "image/jpeg",
- L"test 123" JPEG_EXT
- },
-
- {"malformed_disposition",
- "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
- "image/jpeg",
- L"\uc608\uc220 \uc608\uc220.jpg"},
-
- // Invalid C-D. No filename from URL. Falls back to 'download'.
- {"attachment; filename==?iso88591?Q?caf=E3?",
- "http://www.google.com/path1/path2/",
- "image/jpeg",
- L"download" JPEG_EXT
- },
-
- // Issue=5772.
- {"",
- "http://www.example.com/foo.tar.gz",
- "application/x-tar",
- L"foo.tar.gz"},
-
- // Issue=7337.
- {"",
- "http://maged.lordaeron.org/blank.reg",
- "text/x-registry",
- L"blank.reg"},
-
- {"",
- "http://www.example.com/bar.tar",
- "application/x-tar",
- L"bar.tar"},
-
- {"",
- "http://www.example.com/bar.bogus",
- "application/x-tar",
- L"bar.bogus" TAR_EXT
- },
-
- // http://code.google.com/p/chromium/issues/detail?id=20337
- {"filename=.download.txt",
- "http://www.example.com/.download.txt",
- "text/plain",
- L"download.txt"},
-};
-
-} // namespace
-
-// Tests to ensure that the file names we generate from hints from the server
-// (content-disposition, URL name, etc) don't cause security holes.
-TEST_F(DownloadManagerTest, TestDownloadFilename) {
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- // This test doesn't run when the locale is not UTF-8 becuase some of the
- // string conversions fail. This is OK (we have the default value) but they
- // don't match our expectations.
- std::string locale = setlocale(LC_CTYPE, NULL);
- StringToLowerASCII(&locale);
- ASSERT_NE(std::string::npos, locale.find("utf-8"))
- << "Your locale must be set to UTF-8 for this test to pass!";
-#endif
-
- std::wstring file_name;
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) {
- GetGeneratedFilename(kGeneratedFiles[i].disposition,
- kGeneratedFiles[i].url,
- kGeneratedFiles[i].mime_type,
- "",
- &file_name);
- EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name);
- GetGeneratedFilename(kGeneratedFiles[i].disposition,
- kGeneratedFiles[i].url,
- kGeneratedFiles[i].mime_type,
- "GBK",
- &file_name);
- EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name);
- }
-
- // A couple of cases with raw 8bit characters in C-D.
- GetGeneratedFilename("attachment; filename=caf\xc3\xa9.png",
- "http://www.example.com/images?id=3",
- "image/png",
- "iso-8859-1",
- &file_name);
- EXPECT_EQ(L"caf\u00e9.png", file_name);
- GetGeneratedFilename("attachment; filename=caf\xe5.png",
- "http://www.example.com/images?id=3",
- "image/png",
- "windows-1253",
- &file_name);
- EXPECT_EQ(L"caf\u03b5.png", file_name);
-}
-
-namespace {
-
-const struct {
- const FilePath::CharType* path;
- const char* mime_type;
- const FilePath::CharType* expected_path;
-} kSafeFilenameCases[] = {
-#if defined(OS_WIN)
- { FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
- "text/html",
- FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
- { FILE_PATH_LITERAL("C:\\foo\\bar.html"),
- "text/html",
- FILE_PATH_LITERAL("C:\\foo\\bar.html") },
- { FILE_PATH_LITERAL("C:\\foo\\bar"),
- "text/html",
- FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
-
- { FILE_PATH_LITERAL("C:\\bar.html"),
- "image/png",
- FILE_PATH_LITERAL("C:\\bar.png") },
- { FILE_PATH_LITERAL("C:\\bar"),
- "image/png",
- FILE_PATH_LITERAL("C:\\bar.png") },
-
- { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
- "text/html",
- FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
- { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
- "image/gif",
- FILE_PATH_LITERAL("C:\\foo\\bar.gif") },
-
- { FILE_PATH_LITERAL("C:\\foo\\google.com"),
- "text/html",
- FILE_PATH_LITERAL("C:\\foo\\google.htm") },
-
- { FILE_PATH_LITERAL("C:\\foo\\con.htm"),
- "text/html",
- FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
- { FILE_PATH_LITERAL("C:\\foo\\con"),
- "text/html",
- FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
-#else
- { FILE_PATH_LITERAL("/foo/bar.htm"),
- "text/html",
- FILE_PATH_LITERAL("/foo/bar.htm") },
- { FILE_PATH_LITERAL("/foo/bar.html"),
- "text/html",
- FILE_PATH_LITERAL("/foo/bar.html") },
- { FILE_PATH_LITERAL("/foo/bar"),
- "text/html",
- FILE_PATH_LITERAL("/foo/bar.html") },
-
- { FILE_PATH_LITERAL("/bar.html"),
- "image/png",
- FILE_PATH_LITERAL("/bar.html.png") },
- { FILE_PATH_LITERAL("/bar"),
- "image/png",
- FILE_PATH_LITERAL("/bar.png") },
-
- { FILE_PATH_LITERAL("/foo/bar.exe"),
- "text/html",
- FILE_PATH_LITERAL("/foo/bar.exe.html") },
- { FILE_PATH_LITERAL("/foo/bar.exe"),
- "image/gif",
- FILE_PATH_LITERAL("/foo/bar.exe.gif") },
-
- { FILE_PATH_LITERAL("/foo/google.com"),
- "text/html",
- FILE_PATH_LITERAL("/foo/google.com.html") },
-
- { FILE_PATH_LITERAL("/foo/con.htm"),
- "text/html",
- FILE_PATH_LITERAL("/foo/con.htm") },
- { FILE_PATH_LITERAL("/foo/con"),
- "text/html",
- FILE_PATH_LITERAL("/foo/con.html") },
-#endif // OS_WIN
-};
-
-} // namespace
-
-#if defined(OS_WIN) || defined(OS_MACOSX)
-// TODO(port): port to Linux/BSD.
-TEST_F(DownloadManagerTest, GetSafeFilename) {
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSafeFilenameCases); ++i) {
- FilePath path(kSafeFilenameCases[i].path);
- download_manager_->GenerateSafeFileName(kSafeFilenameCases[i].mime_type,
- &path);
- EXPECT_EQ(kSafeFilenameCases[i].expected_path, path.value());
- }
-}
-#endif // defined(OS_WIN) || defined(OS_MACOSX)
-
-namespace {
-
-const struct {
const char* url;
const char* mime_type;
bool save_as;
@@ -703,8 +121,8 @@ const struct {
TEST_F(DownloadManagerTest, StartDownload) {
PrefService* prefs = profile_->GetPrefs();
prefs->SetFilePath(prefs::kDownloadDefaultDirectory, FilePath());
- download_manager_->OpenFilesBasedOnExtension(
- FilePath(FILE_PATH_LITERAL("example.pdf")), true);
+ download_manager_->download_prefs()->EnableAutoOpenBasedOnExtension(
+ FilePath(FILE_PATH_LITERAL("example.pdf")));
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kStartDownloadCases); ++i) {
prefs->SetBoolean(prefs::kPromptForDownload,
@@ -763,8 +181,8 @@ const struct {
class MockDownloadFile : public DownloadFile {
public:
- MockDownloadFile(DownloadCreateInfo* info)
- : DownloadFile(info), renamed_count_(0) { }
+ explicit MockDownloadFile(DownloadCreateInfo* info)
+ : DownloadFile(info, NULL), renamed_count_(0) { }
virtual ~MockDownloadFile() { Destructed(); }
MOCK_METHOD2(Rename, bool(const FilePath&, bool));
MOCK_METHOD0(DeleteCrDownload, void());
@@ -827,11 +245,11 @@ TEST_F(DownloadManagerTest, DownloadRenameTest) {
EXPECT_CALL(*download, DeleteCrDownload()).Times(1);
if (kDownloadRenameCases[i].finish_before_rename) {
- download_manager_->DownloadFinished(i, 1024);
+ download_manager_->OnAllDataSaved(i, 1024);
download_manager_->FileSelected(new_path, i, info);
} else {
download_manager_->FileSelected(new_path, i, info);
- download_manager_->DownloadFinished(i, 1024);
+ download_manager_->OnAllDataSaved(i, 1024);
}
message_loop_.RunAllPending();
diff --git a/chrome/browser/download/download_request_infobar_delegate.cc b/chrome/browser/download/download_request_infobar_delegate.cc
index 4a401bb..ecbc108 100644
--- a/chrome/browser/download/download_request_infobar_delegate.cc
+++ b/chrome/browser/download/download_request_infobar_delegate.cc
@@ -27,8 +27,8 @@ void DownloadRequestInfoBarDelegate::InfoBarClosed() {
ConfirmInfoBarDelegate::InfoBarClosed();
}
-std::wstring DownloadRequestInfoBarDelegate::GetMessageText() const {
- return l10n_util::GetString(IDS_MULTI_DOWNLOAD_WARNING);
+string16 DownloadRequestInfoBarDelegate::GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_MULTI_DOWNLOAD_WARNING);
}
SkBitmap* DownloadRequestInfoBarDelegate::GetIcon() const {
@@ -40,12 +40,12 @@ int DownloadRequestInfoBarDelegate::GetButtons() const {
return BUTTON_OK | BUTTON_CANCEL;
}
-std::wstring DownloadRequestInfoBarDelegate::GetButtonLabel(
+string16 DownloadRequestInfoBarDelegate::GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const {
if (button == BUTTON_OK)
- return l10n_util::GetString(IDS_MULTI_DOWNLOAD_WARNING_ALLOW);
+ return l10n_util::GetStringUTF16(IDS_MULTI_DOWNLOAD_WARNING_ALLOW);
else
- return l10n_util::GetString(IDS_MULTI_DOWNLOAD_WARNING_DENY);
+ return l10n_util::GetStringUTF16(IDS_MULTI_DOWNLOAD_WARNING_DENY);
}
bool DownloadRequestInfoBarDelegate::Accept() {
diff --git a/chrome/browser/download/download_request_infobar_delegate.h b/chrome/browser/download/download_request_infobar_delegate.h
index 700c629..c1280cf 100644
--- a/chrome/browser/download/download_request_infobar_delegate.h
+++ b/chrome/browser/download/download_request_infobar_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_INFOBAR_DELEGATE_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/download/download_request_limiter.h"
@@ -28,13 +29,13 @@ class DownloadRequestInfoBarDelegate : public ConfirmInfoBarDelegate {
virtual void InfoBarClosed();
- virtual std::wstring GetMessageText() const;
+ virtual string16 GetMessageText() const;
virtual SkBitmap* GetIcon() const;
virtual int GetButtons() const;
- virtual std::wstring GetButtonLabel(
+ virtual string16 GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const;
virtual bool Accept();
diff --git a/chrome/browser/download/download_request_limiter.h b/chrome/browser/download/download_request_limiter.h
index f5b4cfa..4a685e3 100644
--- a/chrome/browser/download/download_request_limiter.h
+++ b/chrome/browser/download/download_request_limiter.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_LIMITER_H_
+#pragma once
#include <map>
#include <string>
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc
index d8582a9..cf0d90d 100644
--- a/chrome/browser/download/download_request_limiter_unittest.cc
+++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -88,8 +88,7 @@ class DownloadRequestLimiterTest
ChromeThread io_thread_;
};
-// http://code.google.com/p/chromium/issues/detail?id=39753
-TEST_F(DownloadRequestLimiterTest, FLAKY_Allow) {
+TEST_F(DownloadRequestLimiterTest, Allow) {
// All tabs should initially start at ALLOW_ONE_DOWNLOAD.
ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
download_request_limiter_->GetDownloadStatus(
diff --git a/chrome/browser/download/download_shelf.cc b/chrome/browser/download/download_shelf.cc
index fa6ab09..dc69d02 100644
--- a/chrome/browser/download/download_shelf.cc
+++ b/chrome/browser/download/download_shelf.cc
@@ -29,13 +29,10 @@ DownloadShelfContextMenu::~DownloadShelfContextMenu() {
bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id) const {
switch (command_id) {
- case OPEN_WHEN_COMPLETE: {
+ case OPEN_WHEN_COMPLETE:
return download_->open_when_complete();
- }
- case ALWAYS_OPEN_TYPE: {
- return download_->manager()->ShouldOpenFileBasedOnExtension(
- download_->full_path());
- }
+ case ALWAYS_OPEN_TYPE:
+ return download_->ShouldOpenFileBasedOnExtension();
}
return false;
}
@@ -70,7 +67,7 @@ bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const {
case OPEN_WHEN_COMPLETE:
return download_->state() != DownloadItem::CANCELLED;
case ALWAYS_OPEN_TYPE:
- return download_util::CanOpenDownload(download_);
+ return download_->CanOpenDownload();
case CANCEL:
return download_->state() == DownloadItem::IN_PROGRESS;
case TOGGLE_PAUSE:
@@ -83,14 +80,14 @@ bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const {
void DownloadShelfContextMenu::ExecuteCommand(int command_id) {
switch (command_id) {
case SHOW_IN_FOLDER:
- download_->manager()->ShowDownloadInShell(download_);
+ download_->ShowDownloadInShell();
break;
case OPEN_WHEN_COMPLETE:
- download_util::OpenDownload(download_);
+ download_->OpenDownload();
break;
case ALWAYS_OPEN_TYPE: {
- download_->manager()->OpenFilesBasedOnExtension(
- download_->full_path(), !IsCommandIdChecked(ALWAYS_OPEN_TYPE));
+ download_->OpenFilesBasedOnExtension(
+ !IsCommandIdChecked(ALWAYS_OPEN_TYPE));
break;
}
case CANCEL:
diff --git a/chrome/browser/download/download_shelf.h b/chrome/browser/download/download_shelf.h
index c9fdaa9..b6ee780 100644
--- a/chrome/browser/download/download_shelf.h
+++ b/chrome/browser/download/download_shelf.h
@@ -1,16 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SHELF_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SHELF_H_
-
-#include <string>
+#pragma once
#include "app/menus/simple_menu_model.h"
#include "base/basictypes.h"
-#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
class BaseDownloadItemModel;
class Browser;
@@ -19,7 +18,7 @@ class DownloadItem;
// DownloadShelf is an interface for platform-specific download shelf views.
class DownloadShelf {
public:
- virtual ~DownloadShelf() { }
+ virtual ~DownloadShelf() {}
// A new download has started, so add it to our shelf. This object will
// take ownership of |download_model|. Also make the shelf visible.
diff --git a/chrome/browser/download/download_started_animation.h b/chrome/browser/download/download_started_animation.h
index f44dece..1ac93c4 100644
--- a/chrome/browser/download/download_started_animation.h
+++ b/chrome/browser/download/download_started_animation.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STARTED_ANIMATION_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STARTED_ANIMATION_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/download/download_types.h b/chrome/browser/download/download_types.h
index de8bfc8..bf3a9c7 100644
--- a/chrome/browser/download/download_types.h
+++ b/chrome/browser/download/download_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TYPES_H_
+#pragma once
#include <vector>
@@ -23,6 +24,9 @@ class IOBuffer;
// is synchronized via the lock. Each entry in 'contents' represents one data
// buffer and its size in bytes.
struct DownloadBuffer {
+ DownloadBuffer();
+ ~DownloadBuffer();
+
Lock lock;
typedef std::pair<net::IOBuffer*, int> Contents;
std::vector<Contents> contents;
@@ -30,6 +34,11 @@ struct DownloadBuffer {
// Holds the information about how to save a download file.
struct DownloadSaveInfo {
+ DownloadSaveInfo();
+ DownloadSaveInfo(const DownloadSaveInfo& info);
+ ~DownloadSaveInfo();
+ DownloadSaveInfo& operator=(const DownloadSaveInfo& info);
+
FilePath file_path;
linked_ptr<net::FileStream> file_stream;
};
diff --git a/chrome/browser/download/download_uitest.cc b/chrome/browser/download/download_uitest.cc
index d3a7fff..22fef7a 100644
--- a/chrome/browser/download/download_uitest.cc
+++ b/chrome/browser/download/download_uitest.cc
@@ -172,9 +172,10 @@ 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.
+// All download tests are disabled on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
-TEST_F(DownloadTest, FLAKY_DownloadMimeType) {
+TEST_F(DownloadTest, DISABLED_DownloadMimeType) {
FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
EXPECT_EQ(1, GetTabCount());
@@ -192,9 +193,10 @@ TEST_F(DownloadTest, FLAKY_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.
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
-TEST_F(DownloadTest, FLAKY_NoDownload) {
+TEST_F(DownloadTest, DISABLED_NoDownload) {
FilePath file(FILE_PATH_LITERAL("download-test2.html"));
FilePath file_path = download_prefix_.Append(file);
@@ -219,9 +221,10 @@ TEST_F(DownloadTest, FLAKY_NoDownload) {
// Download a 0-size file with a content-disposition header, verify that the
// 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.
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
-TEST_F(DownloadTest, FLAKY_ContentDisposition) {
+TEST_F(DownloadTest, DISABLED_ContentDisposition) {
FilePath file(FILE_PATH_LITERAL("download-test3.gif"));
FilePath download_file(FILE_PATH_LITERAL("download-test3-attachment.gif"));
@@ -240,9 +243,10 @@ TEST_F(DownloadTest, FLAKY_ContentDisposition) {
// tab, opening a second tab, closing the shelf, going back to the first tab,
// 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.
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
-TEST_F(DownloadTest, FLAKY_PerWindowShelf) {
+TEST_F(DownloadTest, DISABLED_PerWindowShelf) {
FilePath file(FILE_PATH_LITERAL("download-test3.gif"));
FilePath download_file(FILE_PATH_LITERAL("download-test3-attachment.gif"));
@@ -281,9 +285,10 @@ TEST_F(DownloadTest, FLAKY_PerWindowShelf) {
// The test will first attempt to download a file; but the server will "pause"
// 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.
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
-TEST_F(DownloadTest, FLAKY_UnknownSize) {
+TEST_F(DownloadTest, DISABLED_UnknownSize) {
GURL url(URLRequestSlowDownloadJob::kUnknownSizeUrl);
FilePath filename;
net::FileURLToFilePath(url, &filename);
@@ -292,8 +297,10 @@ TEST_F(DownloadTest, FLAKY_UnknownSize) {
L"100% - " + filename.ToWStringHack());
}
-// http://crbug.com/35275
-TEST_F(DownloadTest, FLAKY_KnownSize) {
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_KnownSize) {
GURL url(URLRequestSlowDownloadJob::kKnownSizeUrl);
FilePath filename;
net::FileURLToFilePath(url, &filename);
@@ -304,9 +311,10 @@ 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.
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
-TEST_F(DownloadTest, FLAKY_IncognitoDownload) {
+TEST_F(DownloadTest, DISABLED_IncognitoDownload) {
// Open a regular window and sanity check default values for window / tab
// count and shelf visibility.
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -350,8 +358,11 @@ TEST_F(DownloadTest, FLAKY_IncognitoDownload) {
CheckDownload(file);
}
-// All of the following tests are flaky, see http://crbug.com/43066
-TEST_F(DownloadTest, FLAKY_DontCloseNewTab1) {
+// 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.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_DontCloseNewTab1) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
int window_count = 0;
@@ -370,7 +381,10 @@ TEST_F(DownloadTest, FLAKY_DontCloseNewTab1) {
WaitUntilTabCount(2);
}
-TEST_F(DownloadTest, FLAKY_CloseNewTab1) {
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_CloseNewTab1) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
int window_count = 0;
@@ -392,8 +406,11 @@ TEST_F(DownloadTest, FLAKY_CloseNewTab1) {
CheckDownload(file);
}
-// Flaky, see http://crbug.com/43066
-TEST_F(DownloadTest, FLAKY_DontCloseNewTab2) {
+// 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.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_DontCloseNewTab2) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
int window_count = 0;
@@ -417,7 +434,10 @@ TEST_F(DownloadTest, FLAKY_DontCloseNewTab2) {
}
// Flaky, see http://crbug.com/43066
-TEST_F(DownloadTest, FLAKY_DontCloseNewTab3) {
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_DontCloseNewTab3) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
int window_count = 0;
@@ -444,7 +464,10 @@ TEST_F(DownloadTest, FLAKY_DontCloseNewTab3) {
}
// Flaky, see http://crbug.com/43066
-TEST_F(DownloadTest, FLAKY_CloseNewTab2) {
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_CloseNewTab2) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
int window_count = 0;
@@ -468,7 +491,10 @@ TEST_F(DownloadTest, FLAKY_CloseNewTab2) {
}
// Flaky, see http://crbug.com/43066
-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.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_CloseNewTab3) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
int window_count = 0;
@@ -492,8 +518,35 @@ TEST_F(DownloadTest, FLAKY_CloseNewTab3) {
CheckDownload(file);
}
+// All download tests are flaky on all platforms, http://crbug.com/35275,
+// http://crbug.com/48913 and especially http://crbug.com/50060.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_DontCloseNewWindow) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+ int window_count = 0;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ ASSERT_EQ(1, window_count);
+ EXPECT_EQ(1, GetTabCount());
+
+ scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
+ ASSERT_TRUE(tab_proxy.get());
+
+ FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
+ ASSERT_TRUE(tab_proxy->NavigateToURLAsyncWithDisposition(
+ URLRequestMockHTTPJob::GetMockUrl(file), NEW_WINDOW));
+
+ ASSERT_TRUE(automation()->WaitForWindowCountToBecome(2));
+
+ CheckDownload(file);
+}
+
// Regression test for http://crbug.com/44454
-TEST_F(DownloadTest, NewWindow) {
+// 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.
+// Additionally, there is Windows-specific flake, http://crbug.com/20809.
+TEST_F(DownloadTest, DISABLED_NewWindow) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
int window_count = 0;
@@ -508,7 +561,7 @@ TEST_F(DownloadTest, NewWindow) {
ASSERT_TRUE(tab_proxy->NavigateToURLAsyncWithDisposition(
URLRequestMockHTTPJob::GetMockUrl(file), NEW_WINDOW));
- ASSERT_TRUE(automation()->WaitForWindowCountToBecome(1));
+ ASSERT_TRUE(automation()->WaitForWindowCountToBecome(2));
CheckDownload(file);
}
diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc
index 3f97452..5747e51 100644
--- a/chrome/browser/download/download_util.cc
+++ b/chrome/browser/download/download_util.cc
@@ -18,18 +18,29 @@
#include "base/i18n/time_formatting.h"
#include "base/path_service.h"
#include "base/singleton.h"
-#include "base/string_util.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.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/history/download_create_info.h"
#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/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"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/time_format.h"
#include "gfx/canvas_skia.h"
#include "gfx/rect.h"
@@ -37,6 +48,7 @@
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "net/base/mime_util.h"
+#include "net/base/net_util.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkShader.h"
@@ -46,18 +58,20 @@
#include "views/drag_utils.h"
#endif
-#if defined(OS_LINUX)
+#if defined(TOOLKIT_USES_GTK)
#if defined(TOOLKIT_VIEWS)
#include "app/drag_drop_types.h"
#include "views/widget/widget_gtk.h"
#elif defined(TOOLKIT_GTK)
#include "chrome/browser/gtk/custom_drag.h"
#endif // defined(TOOLKIT_GTK)
-#endif // defined(OS_LINUX)
+#endif // defined(TOOLKIT_USES_GTK)
#if defined(OS_WIN)
#include "app/os_exchange_data_provider_win.h"
+#include "app/win_util.h"
#include "base/base_drag_source.h"
+#include "base/registry.h"
#include "base/scoped_comptr_win.h"
#include "base/win_util.h"
#include "chrome/browser/browser_list.h"
@@ -70,26 +84,6 @@ namespace download_util {
// so that the animation ends faded out.
static const int kCompleteAnimationCycles = 5;
-// Download opening ------------------------------------------------------------
-
-bool CanOpenDownload(DownloadItem* download) {
- FilePath file_to_use = download->full_path();
- if (!download->original_name().value().empty())
- file_to_use = download->original_name();
-
- return !Extension::IsExtension(file_to_use) &&
- !download->manager()->IsExecutableFile(file_to_use);
-}
-
-void OpenDownload(DownloadItem* download) {
- if (download->state() == DownloadItem::IN_PROGRESS) {
- download->set_open_when_complete(!download->open_when_complete());
- } else if (download->state() == DownloadItem::COMPLETE) {
- download->NotifyObserversDownloadOpened();
- download->manager()->OpenDownload(download, NULL);
- }
-}
-
// Download temporary file creation --------------------------------------------
class DefaultDownloadDirectory {
@@ -130,6 +124,198 @@ bool DownloadPathIsDangerous(const FilePath& download_path) {
return (download_path == desktop_dir);
}
+void GenerateExtension(const FilePath& file_name,
+ const std::string& mime_type,
+ FilePath::StringType* generated_extension) {
+ // We're worried about three things here:
+ //
+ // 1) Security. Many sites let users upload content, such as buddy icons, to
+ // their web sites. We want to mitigate the case where an attacker
+ // supplies a malicious executable with an executable file extension but an
+ // honest site serves the content with a benign content type, such as
+ // image/jpeg.
+ //
+ // 2) Usability. If the site fails to provide a file extension, we want to
+ // guess a reasonable file extension based on the content type.
+ //
+ // 3) Shell integration. Some file extensions automatically integrate with
+ // the shell. We block these extensions to prevent a malicious web site
+ // from integrating with the user's shell.
+
+ static const FilePath::CharType default_extension[] =
+ FILE_PATH_LITERAL("download");
+
+ // See if our file name already contains an extension.
+ FilePath::StringType extension = file_name.Extension();
+ if (!extension.empty())
+ extension.erase(extension.begin()); // Erase preceding '.'.
+
+#if defined(OS_WIN)
+ // Rename shell-integrated extensions.
+ if (win_util::IsShellIntegratedExtension(extension))
+ extension.assign(default_extension);
+#endif
+
+ std::string mime_type_from_extension;
+ net::GetMimeTypeFromFile(file_name,
+ &mime_type_from_extension);
+ if (mime_type == mime_type_from_extension) {
+ // The hinted extension matches the mime type. It looks like a winner.
+ generated_extension->swap(extension);
+ return;
+ }
+
+ if (IsExecutableExtension(extension) && !IsExecutableMimeType(mime_type)) {
+ // We want to be careful about executable extensions. The worry here is
+ // that a trusted web site could be tricked into dropping an executable file
+ // on the user's filesystem.
+ if (!net::GetPreferredExtensionForMimeType(mime_type, &extension)) {
+ // We couldn't find a good extension for this content type. Use a dummy
+ // extension instead.
+ extension.assign(default_extension);
+ }
+ }
+
+ if (extension.empty()) {
+ net::GetPreferredExtensionForMimeType(mime_type, &extension);
+ } else {
+ // Append extension generated from the mime type if:
+ // 1. New extension is not ".txt"
+ // 2. New extension is not the same as the already existing extension.
+ // 3. New extension is not executable. This action mitigates the case when
+ // an executable is hidden in a benign file extension;
+ // E.g. my-cat.jpg becomes my-cat.jpg.js if content type is
+ // application/x-javascript.
+ // 4. New extension is not ".tar" for .tar.gz/tgz files. For misconfigured
+ // web servers, i.e. bug 5772.
+ // 5. The original extension is not ".tgz" & the new extension is not "gz".
+ FilePath::StringType append_extension;
+ if (net::GetPreferredExtensionForMimeType(mime_type, &append_extension)) {
+ if (append_extension != FILE_PATH_LITERAL("txt") &&
+ append_extension != extension &&
+ !IsExecutableExtension(append_extension) &&
+ !(append_extension == FILE_PATH_LITERAL("gz") &&
+ extension == FILE_PATH_LITERAL("tgz")) &&
+ !(append_extension == FILE_PATH_LITERAL("tar") &&
+ (extension == FILE_PATH_LITERAL("tar.gz") ||
+ extension == FILE_PATH_LITERAL("tgz")))) {
+ extension += FILE_PATH_LITERAL(".");
+ extension += append_extension;
+ }
+ }
+ }
+
+ generated_extension->swap(extension);
+}
+
+void GenerateFileNameFromInfo(DownloadCreateInfo* info,
+ FilePath* generated_name) {
+ GenerateFileName(GURL(info->url),
+ info->content_disposition,
+ info->referrer_charset,
+ info->mime_type,
+ generated_name);
+}
+
+void GenerateFileName(const GURL& url,
+ const std::string& content_disposition,
+ const std::string& referrer_charset,
+ const std::string& mime_type,
+ FilePath* generated_name) {
+ std::wstring default_name =
+ l10n_util::GetString(IDS_DEFAULT_DOWNLOAD_FILENAME);
+#if defined(OS_WIN)
+ FilePath default_file_path(default_name);
+#elif defined(OS_POSIX)
+ FilePath default_file_path(base::SysWideToNativeMB(default_name));
+#endif
+
+ *generated_name = net::GetSuggestedFilename(GURL(url),
+ content_disposition,
+ referrer_charset,
+ default_file_path);
+
+ DCHECK(!generated_name->empty());
+
+ GenerateSafeFileName(mime_type, generated_name);
+}
+
+void GenerateSafeFileName(const std::string& mime_type, FilePath* file_name) {
+ // Make sure we get the right file extension
+ FilePath::StringType extension;
+ GenerateExtension(*file_name, mime_type, &extension);
+ *file_name = file_name->ReplaceExtension(extension);
+
+#if defined(OS_WIN)
+ // Prepend "_" to the file name if it's a reserved name
+ FilePath::StringType leaf_name = file_name->BaseName().value();
+ DCHECK(!leaf_name.empty());
+ if (win_util::IsReservedName(leaf_name)) {
+ leaf_name = FilePath::StringType(FILE_PATH_LITERAL("_")) + leaf_name;
+ *file_name = file_name->DirName();
+ if (file_name->value() == FilePath::kCurrentDirectory) {
+ *file_name = FilePath(leaf_name);
+ } else {
+ *file_name = file_name->Append(leaf_name);
+ }
+ }
+#endif
+}
+
+void OpenChromeExtension(Profile* profile,
+ DownloadManager* download_manager,
+ const DownloadItem& download_item) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(download_item.is_extension_install());
+
+ // We don't support extensions in OTR mode.
+ ExtensionsService* service = profile->GetExtensionsService();
+ if (service) {
+ NotificationService* nservice = NotificationService::current();
+ GURL nonconst_download_url = download_item.url();
+ nservice->Notify(NotificationType::EXTENSION_READY_FOR_INSTALL,
+ Source<DownloadManager>(download_manager),
+ Details<GURL>(&nonconst_download_url));
+
+ scoped_refptr<CrxInstaller> installer(
+ new CrxInstaller(service->install_directory(),
+ service,
+ new ExtensionInstallUI(profile)));
+ installer->set_delete_source(true);
+
+ if (UserScript::HasUserScriptFileExtension(download_item.url())) {
+ installer->InstallUserScript(download_item.full_path(),
+ download_item.url());
+ } else {
+ bool is_gallery_download = ExtensionsService::IsDownloadFromGallery(
+ download_item.url(), download_item.referrer_url());
+ installer->set_original_mime_type(download_item.original_mime_type());
+ installer->set_apps_require_extension_mime_type(true);
+ installer->set_allow_privilege_increase(true);
+ installer->set_original_url(download_item.url());
+ installer->set_limit_web_extent_to_download_host(!is_gallery_download);
+ installer->InstallCrx(download_item.full_path());
+ installer->set_allow_silent_install(is_gallery_download);
+ }
+ } else {
+ TabContents* contents = NULL;
+ // Get last active normal browser of profile.
+ Browser* last_active =
+ BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL, true);
+ if (last_active)
+ contents = last_active->GetSelectedTabContents();
+ if (contents) {
+ contents->AddInfoBar(
+ new SimpleAlertInfoBarDelegate(contents,
+ l10n_util::GetStringUTF16(
+ IDS_EXTENSION_INCOGNITO_INSTALL_INFOBAR_LABEL),
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_INFOBAR_PLUGIN_INSTALL),
+ true));
+ }
+ }
+}
+
// Download progress painting --------------------------------------------------
// Common bitmaps used for download progress animations. We load them once the
@@ -282,8 +468,8 @@ int GetBigProgressIconSize() {
static int big_progress_icon_size = 0;
if (big_progress_icon_size == 0) {
string16 locale_size_str =
- WideToUTF16Hack(l10n_util::GetString(IDS_DOWNLOAD_BIG_PROGRESS_SIZE));
- bool rc = StringToInt(locale_size_str, &big_progress_icon_size);
+ l10n_util::GetStringUTF16(IDS_DOWNLOAD_BIG_PROGRESS_SIZE);
+ bool rc = base::StringToInt(locale_size_str, &big_progress_icon_size);
if (!rc || big_progress_icon_size < kBigProgressIconSize) {
NOTREACHED();
big_progress_icon_size = kBigProgressIconSize;
@@ -308,7 +494,7 @@ void DragDownload(const DownloadItem* download,
OSExchangeData data;
if (icon) {
- drag_utils::CreateDragImageForFile(download->file_name().value(), icon,
+ drag_utils::CreateDragImageForFile(download->GetFileName().value(), icon,
&data);
}
@@ -322,7 +508,7 @@ void DragDownload(const DownloadItem* download,
// Add URL so that we can load supported files when dragged to TabContents.
if (net::IsSupportedMimeType(mime_type)) {
data.SetURL(GURL(WideToUTF8(full_path.ToWStringHack())),
- download->file_name().ToWStringHack());
+ download->GetFileName().ToWStringHack());
}
#if defined(OS_WIN)
@@ -332,7 +518,7 @@ void DragDownload(const DownloadItem* download,
DWORD effects;
DoDragDrop(OSExchangeDataProviderWin::GetIDataObject(data), drag_source.get(),
DROPEFFECT_COPY | DROPEFFECT_LINK, &effects);
-#elif defined(OS_LINUX)
+#elif defined(TOOLKIT_USES_GTK)
GtkWidget* root = gtk_widget_get_toplevel(view);
if (!root)
return;
@@ -343,59 +529,61 @@ void DragDownload(const DownloadItem* download,
widget->DoDrag(data, DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
#endif // OS_WIN
}
-#elif defined(OS_LINUX)
+#elif defined(USE_X11)
void DragDownload(const DownloadItem* download,
SkBitmap* icon,
gfx::NativeView view) {
DownloadItemDrag::BeginDrag(download, icon);
}
-#endif // OS_LINUX
+#endif // USE_X11
DictionaryValue* CreateDownloadItemValue(DownloadItem* download, int id) {
DictionaryValue* file_value = new DictionaryValue();
- file_value->SetInteger(L"started",
- static_cast<int>(download->start_time().ToTimeT()));
- file_value->SetString(L"since_string",
- TimeFormat::RelativeDate(download->start_time(), NULL));
- file_value->SetString(L"date_string",
- base::TimeFormatShortDate(download->start_time()));
- file_value->SetInteger(L"id", id);
- file_value->SetString(L"file_path", download->full_path().ToWStringHack());
+ file_value->SetInteger("started",
+ static_cast<int>(download->start_time().ToTimeT()));
+ file_value->SetString("since_string",
+ TimeFormat::RelativeDate(download->start_time(), NULL));
+ file_value->SetString("date_string",
+ WideToUTF16Hack(base::TimeFormatShortDate(download->start_time())));
+ file_value->SetInteger("id", id);
+ file_value->SetString("file_path",
+ WideToUTF16Hack(download->full_path().ToWStringHack()));
// Keep file names as LTR.
- std::wstring file_name = download->GetFileName().ToWStringHack();
- base::i18n::GetDisplayStringInLTRDirectionality(&file_name);
- file_value->SetString(L"file_name", file_name);
- file_value->SetString(L"url", download->url().spec());
- file_value->SetBoolean(L"otr", download->is_otr());
+ string16 file_name = WideToUTF16Hack(
+ download->GetFileName().ToWStringHack());
+ file_name = base::i18n::GetDisplayStringInLTRDirectionality(file_name);
+ file_value->SetString("file_name", file_name);
+ file_value->SetString("url", download->url().spec());
+ file_value->SetBoolean("otr", download->is_otr());
if (download->state() == DownloadItem::IN_PROGRESS) {
if (download->safety_state() == DownloadItem::DANGEROUS) {
- file_value->SetString(L"state", L"DANGEROUS");
+ file_value->SetString("state", "DANGEROUS");
} else if (download->is_paused()) {
- file_value->SetString(L"state", L"PAUSED");
+ file_value->SetString("state", "PAUSED");
} else {
- file_value->SetString(L"state", L"IN_PROGRESS");
+ file_value->SetString("state", "IN_PROGRESS");
}
- file_value->SetString(L"progress_status_text",
- GetProgressStatusText(download));
+ file_value->SetString("progress_status_text",
+ WideToUTF16Hack(GetProgressStatusText(download)));
- file_value->SetInteger(L"percent",
+ file_value->SetInteger("percent",
static_cast<int>(download->PercentComplete()));
- file_value->SetInteger(L"received",
+ file_value->SetInteger("received",
static_cast<int>(download->received_bytes()));
} else if (download->state() == DownloadItem::CANCELLED) {
- file_value->SetString(L"state", L"CANCELLED");
+ file_value->SetString("state", "CANCELLED");
} else if (download->state() == DownloadItem::COMPLETE) {
if (download->safety_state() == DownloadItem::DANGEROUS) {
- file_value->SetString(L"state", L"DANGEROUS");
+ file_value->SetString("state", "DANGEROUS");
} else {
- file_value->SetString(L"state", L"COMPLETE");
+ file_value->SetString("state", "COMPLETE");
}
}
- file_value->SetInteger(L"total",
+ file_value->SetInteger("total",
static_cast<int>(download->total_bytes()));
return file_value;
@@ -405,7 +593,8 @@ std::wstring GetProgressStatusText(DownloadItem* download) {
int64 total = download->total_bytes();
int64 size = download->received_bytes();
DataUnits amount_units = GetByteDisplayUnits(size);
- std::wstring received_size = FormatBytes(size, amount_units, true);
+ std::wstring received_size = UTF16ToWideHack(FormatBytes(size, amount_units,
+ true));
std::wstring amount = received_size;
// Adjust both strings for the locale direction since we don't yet know which
@@ -418,7 +607,8 @@ std::wstring GetProgressStatusText(DownloadItem* download) {
if (total) {
amount_units = GetByteDisplayUnits(total);
- std::wstring total_text = FormatBytes(total, amount_units, true);
+ std::wstring total_text =
+ UTF16ToWideHack(FormatBytes(total, amount_units, true));
std::wstring total_text_localized;
if (base::i18n::AdjustStringForLocaleDirection(total_text,
&total_text_localized))
@@ -431,17 +621,18 @@ std::wstring GetProgressStatusText(DownloadItem* download) {
amount.assign(received_size);
}
amount_units = GetByteDisplayUnits(download->CurrentSpeed());
- std::wstring speed_text = FormatSpeed(download->CurrentSpeed(),
- amount_units, true);
+ std::wstring speed_text =
+ UTF16ToWideHack(FormatSpeed(download->CurrentSpeed(), amount_units,
+ true));
std::wstring speed_text_localized;
if (base::i18n::AdjustStringForLocaleDirection(speed_text,
&speed_text_localized))
speed_text.assign(speed_text_localized);
base::TimeDelta remaining;
- std::wstring time_remaining;
+ string16 time_remaining;
if (download->is_paused())
- time_remaining = l10n_util::GetString(IDS_DOWNLOAD_PROGRESS_PAUSED);
+ time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
else if (download->TimeRemaining(&remaining))
time_remaining = TimeFormat::TimeRemaining(remaining);
@@ -450,7 +641,7 @@ std::wstring GetProgressStatusText(DownloadItem* download) {
speed_text, amount);
}
return l10n_util::GetStringF(IDS_DOWNLOAD_TAB_PROGRESS_STATUS, speed_text,
- amount, time_remaining);
+ amount, UTF16ToWideHack(time_remaining));
}
#if !defined(OS_MACOSX)
diff --git a/chrome/browser/download/download_util.h b/chrome/browser/download/download_util.h
index 113a3a0..37e8a82 100644
--- a/chrome/browser/download/download_util.h
+++ b/chrome/browser/download/download_util.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,11 +6,12 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UTIL_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UTIL_H_
+#pragma once
-#include <set>
#include <string>
#include "base/basictypes.h"
+#include "base/file_path.h"
#include "gfx/native_widget_types.h"
#if defined(TOOLKIT_VIEWS)
@@ -24,25 +25,18 @@ class Canvas;
class BaseDownloadItemModel;
class DictionaryValue;
class DownloadItem;
-class FilePath;
+class DownloadManager;
class GURL;
+class Profile;
class ResourceDispatcherHost;
class SkBitmap;
class URLRequestContextGetter;
+struct DownloadCreateInfo;
struct DownloadSaveInfo;
namespace download_util {
-// Download opening ------------------------------------------------------------
-
-// Whether it is OK to open this download.
-bool CanOpenDownload(DownloadItem* download);
-
-// Open the file associated with this download (wait for the download to
-// complete if it is in progress).
-void OpenDownload(DownloadItem* download);
-
// Download temporary file creation --------------------------------------------
// Return the default download directory.
@@ -55,6 +49,32 @@ bool CreateTemporaryFileForDownload(FilePath* path);
// Return true if the |download_path| is dangerous path.
bool DownloadPathIsDangerous(const FilePath& download_path);
+// Create an extension based on the file name and mime type.
+void GenerateExtension(const FilePath& file_name,
+ const std::string& mime_type,
+ FilePath::StringType* generated_extension);
+
+// Create a file name based on the response from the server.
+void GenerateFileNameFromInfo(DownloadCreateInfo* info,
+ FilePath* generated_name);
+
+// Create a file name based on the response from the server.
+void GenerateFileName(const GURL& url,
+ const std::string& content_disposition,
+ const std::string& referrer_charset,
+ const std::string& mime_type,
+ FilePath* generated_name);
+
+// Used to make sure we have a safe file extension and filename for a
+// download. |file_name| can either be just the file name or it can be a
+// full path to a file.
+void GenerateSafeFileName(const std::string& mime_type, FilePath* file_name);
+
+// Opens downloaded Chrome extension file (*.crx).
+void OpenChromeExtension(Profile* profile,
+ DownloadManager* download_manager,
+ const DownloadItem& download_item);
+
// Download progress animations ------------------------------------------------
// Arc sweep angle for use with downloads of unknown size
@@ -132,8 +152,14 @@ void DragDownload(const DownloadItem* download,
// 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 std::string& 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 ---------------------------------------------------------------------
diff --git a/chrome/browser/download/drag_download_file.cc b/chrome/browser/download/drag_download_file.cc
index 4b2b370..ad99b75 100644
--- a/chrome/browser/download/drag_download_file.cc
+++ b/chrome/browser/download/drag_download_file.cc
@@ -151,17 +151,13 @@ void DragDownloadFile::DownloadCompleted(bool is_successful) {
void DragDownloadFile::ModelChanged() {
AssertCurrentlyOnUIThread();
- download_manager_->GetTemporaryDownloads(this, file_path_.DirName());
-}
-
-void DragDownloadFile::SetDownloads(std::vector<DownloadItem*>& downloads) {
- AssertCurrentlyOnUIThread();
-
- std::vector<DownloadItem*>::const_iterator it = downloads.begin();
- for (; it != downloads.end(); ++it) {
- if (!download_item_observer_added_ && (*it)->url() == url_) {
+ std::vector<DownloadItem*> downloads;
+ download_manager_->GetTemporaryDownloads(file_path_.DirName(), &downloads);
+ for (std::vector<DownloadItem*>::const_iterator i = downloads.begin();
+ i != downloads.end(); ++i) {
+ if (!download_item_observer_added_ && (*i)->url() == url_) {
download_item_observer_added_ = true;
- (*it)->AddObserver(this);
+ (*i)->AddObserver(this);
}
}
}
diff --git a/chrome/browser/download/drag_download_file.h b/chrome/browser/download/drag_download_file.h
index 4ea3cdf..a6cb190 100644
--- a/chrome/browser/download/drag_download_file.h
+++ b/chrome/browser/download/drag_download_file.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_H_
#define CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_FILE_H_
+#pragma once
#include "app/download_file_interface.h"
#include "base/file_path.h"
@@ -51,7 +52,6 @@ class DragDownloadFile : public DownloadFileProvider,
// DownloadManager::Observer methods.
// Called on UI thread.
virtual void ModelChanged();
- virtual void SetDownloads(std::vector<DownloadItem*>& downloads);
// DownloadItem::Observer methods.
// Called on UI thread.
diff --git a/chrome/browser/download/drag_download_util.cc b/chrome/browser/download/drag_download_util.cc
index a617d41..29fd84e 100644
--- a/chrome/browser/download/drag_download_util.cc
+++ b/chrome/browser/download/drag_download_util.cc
@@ -9,6 +9,7 @@
#include "base/file_util.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "googleurl/src/gurl.h"
@@ -65,9 +66,9 @@ FileStream* CreateFileStreamForDrop(FilePath* file_path) {
new_file_path = *file_path;
} else {
#if defined(OS_WIN)
- std::wstring suffix = std::wstring(L"-") + IntToWString(seq);
+ string16 suffix = ASCIIToUTF16("-") + base::IntToString16(seq);
#else
- std::string suffix = std::string("-") + IntToString(seq);
+ std::string suffix = std::string("-") + base::IntToString(seq);
#endif
new_file_path = file_path->InsertBeforeExtension(suffix);
}
diff --git a/chrome/browser/download/drag_download_util.h b/chrome/browser/download/drag_download_util.h
index c6f8442..bd9d44a 100644
--- a/chrome/browser/download/drag_download_util.h
+++ b/chrome/browser/download/drag_download_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_UTIL_H_
#define CHROME_BROWSER_DOWNLOAD_DRAG_DOWNLOAD_UTIL_H_
+#pragma once
#include "app/download_file_interface.h"
#include "base/basictypes.h"
diff --git a/chrome/browser/download/save_file.cc b/chrome/browser/download/save_file.cc
index b4755ff..98667a3 100644
--- a/chrome/browser/download/save_file.cc
+++ b/chrome/browser/download/save_file.cc
@@ -1,106 +1,22 @@
-// 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/download/save_file.h"
-#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/browser/download/save_types.h"
-#if defined(OS_WIN)
-#include "chrome/common/win_safe_util.h"
-#endif
+#include "chrome/browser/chrome_thread.h"
+#include "net/base/file_stream.h"
SaveFile::SaveFile(const SaveFileCreateInfo* info)
- : info_(info),
- file_(NULL),
- bytes_so_far_(0),
- path_renamed_(false),
- in_progress_(true) {
+ : BaseFile(FilePath(), info->url, GURL(), 0, linked_ptr<net::FileStream>()),
+ info_(info) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
DCHECK(info);
DCHECK(info->path.empty());
- if (file_util::CreateTemporaryFile(&full_path_))
- Open("wb");
}
SaveFile::~SaveFile() {
- Close();
-}
-
-// Return false indicate that we got disk error, save file manager will tell
-// SavePackage this error, then SavePackage will call its Cancel() method to
-// cancel whole save job.
-bool SaveFile::AppendDataToFile(const char* data, size_t data_len) {
- if (file_) {
- if (data_len == fwrite(data, 1, data_len, file_)) {
- bytes_so_far_ += data_len;
- return true;
- } else {
- Close();
- return false;
- }
- }
- // No file_, treat it as disk error.
- return false;
-}
-
-void SaveFile::Cancel() {
- Close();
- // If this job has been canceled, and it has created file,
- // We need to delete this created file.
- if (!full_path_.empty()) {
- file_util::Delete(full_path_, false);
- }
-}
-
-// Rename the file when we have final name.
-bool SaveFile::Rename(const FilePath& new_path) {
- Close();
-
- DCHECK(!path_renamed());
- // We cannot rename because rename will keep the same security descriptor
- // on the destination file. We want to recreate the security descriptor
- // with the security that makes sense in the new path.
- if (!file_util::CopyFile(full_path_, new_path))
- return false;
-
- file_util::Delete(full_path_, false);
-
- full_path_ = new_path;
- path_renamed_ = true;
-
- // Still in saving process, reopen the file.
- if (in_progress_ && !Open("a+b"))
- return false;
- return true;
-}
-
-void SaveFile::Finish() {
- Close();
- in_progress_ = false;
-}
-
-void SaveFile::Close() {
- if (file_) {
- file_util::CloseFile(file_);
- file_ = NULL;
- }
-}
-
-bool SaveFile::Open(const char* open_mode) {
- DCHECK(!full_path_.empty());
- file_ = file_util::OpenFile(full_path_, open_mode);
- if (!file_) {
- return false;
- }
-#if defined(OS_WIN)
- // Sets the zone to tell Windows that this file comes from the Internet.
- // We ignore the return value because a failure is not fatal.
- // TODO(port): Similarly mark on Mac.
- win_util::SetInternetZoneIdentifier(full_path_);
-#endif
- return true;
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
}
diff --git a/chrome/browser/download/save_file.h b/chrome/browser/download/save_file.h
index 1a25ef4..5932c70 100644
--- a/chrome/browser/download/save_file.h
+++ b/chrome/browser/download/save_file.h
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H__
-#define CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H__
+#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H_
+#define CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H_
+#pragma once
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/download/base_file.h"
#include "chrome/browser/download/save_types.h"
// SaveFile ----------------------------------------------------------------
@@ -17,22 +19,11 @@
// the saving job is 'in progress': once the saving job has been completed or
// canceled, the SaveFile is destroyed. One SaveFile object represents one item
// in a save session.
-class SaveFile {
+class SaveFile : public BaseFile {
public:
explicit SaveFile(const SaveFileCreateInfo* info);
~SaveFile();
- // Write a new chunk of data to the file. Returns true on success.
- bool AppendDataToFile(const char* data, size_t data_len);
-
- // Abort the saving job and automatically close the file.
- void Cancel();
-
- // Rename the saved file. Returns 'true' if the rename was successful.
- bool Rename(const FilePath& full_path);
-
- void Finish();
-
// Accessors.
int save_id() const { return info_->save_id; }
int render_process_id() const { return info_->render_process_id; }
@@ -42,37 +33,10 @@ class SaveFile {
return info_->save_source;
}
- int64 bytes_so_far() const { return bytes_so_far_; }
- FilePath full_path() const { return full_path_; }
- bool path_renamed() const { return path_renamed_; }
- bool in_progress() const { return in_progress_; }
-
private:
- // Open or Close the OS file handle. The file is opened in the constructor
- // based on creation information passed to it, and automatically closed in
- // the destructor.
- void Close();
- bool Open(const char* open_mode);
-
scoped_ptr<const SaveFileCreateInfo> info_;
- // OS file handle for writing
- FILE* file_;
-
- // Amount of data received up to this point. We may not know in advance how
- // much data to expect since some servers don't provide that information.
- int64 bytes_so_far_;
-
- // Full path to the saved file including the file name.
- FilePath full_path_;
-
- // Whether the saved file is still using its initial temporary path.
- bool path_renamed_;
-
- // Whether the saved file is still receiving data.
- bool in_progress_;
-
DISALLOW_COPY_AND_ASSIGN(SaveFile);
};
-#endif // CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H__
+#endif // CHROME_BROWSER_DOWNLOAD_SAVE_FILE_H_
diff --git a/chrome/browser/download/save_file_manager.cc b/chrome/browser/download/save_file_manager.cc
index f106d6a..00e9251 100644
--- a/chrome/browser/download/save_file_manager.cc
+++ b/chrome/browser/download/save_file_manager.cc
@@ -220,6 +220,10 @@ void SaveFileManager::StartSave(SaveFileCreateInfo* info) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
DCHECK(info);
SaveFile* save_file = new SaveFile(info);
+
+ // TODO(phajdan.jr): We should check the return value and handle errors here.
+ save_file->Initialize();
+
DCHECK(!LookupSaveFile(info->save_id));
save_file_map_[info->save_id] = save_file;
info->path = save_file->full_path();
@@ -486,7 +490,7 @@ void SaveFileManager::RenameAllFiles(
if (it != save_file_map_.end()) {
SaveFile* save_file = it->second;
DCHECK(!save_file->in_progress());
- save_file->Rename(i->second);
+ save_file->Rename(i->second, true);
delete save_file;
save_file_map_.erase(it);
}
diff --git a/chrome/browser/download/save_file_manager.h b/chrome/browser/download/save_file_manager.h
index 44597d5..4b13acb 100644
--- a/chrome/browser/download/save_file_manager.h
+++ b/chrome/browser/download/save_file_manager.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.
//
@@ -57,11 +57,11 @@
#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__
#define CHROME_BROWSER_DOWNLOAD_SAVE_FILE_MANAGER_H__
+#pragma once
#include <string>
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "chrome/browser/download/save_types.h"
@@ -69,6 +69,7 @@
namespace net {
class IOBuffer;
}
+class FilePath;
class GURL;
class SaveFile;
class SavePackage;
diff --git a/chrome/browser/download/save_item.h b/chrome/browser/download/save_item.h
index 8984dab..724441a 100644
--- a/chrome/browser/download/save_item.h
+++ b/chrome/browser/download/save_item.h
@@ -4,6 +4,7 @@
//
#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_ITEM_H__
#define CHROME_BROWSER_DOWNLOAD_SAVE_ITEM_H__
+#pragma once
#include "base/basictypes.h"
#include "base/file_path.h"
diff --git a/chrome/browser/download/save_package.cc b/chrome/browser/download/save_package.cc
index 7be57c2..f624e44 100644
--- a/chrome/browser/download/save_package.cc
+++ b/chrome/browser/download/save_package.cc
@@ -12,6 +12,7 @@
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/string_piece.h"
+#include "base/string_split.h"
#include "base/utf_string_conversions.h"
#include "base/task.h"
#include "base/thread.h"
@@ -21,11 +22,14 @@
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/download/download_util.h"
#include "chrome/browser/download/save_file.h"
#include "chrome/browser/download/save_file_manager.h"
#include "chrome/browser/download/save_item.h"
+#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_member.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"
@@ -205,28 +209,27 @@ class CreateDownloadDirectoryTask : public Task {
} // namespace
-SavePackage::SavePackage(TabContents* web_content,
+SavePackage::SavePackage(TabContents* tab_contents,
SavePackageType save_type,
const FilePath& file_full_path,
const FilePath& directory_full_path)
: file_manager_(NULL),
- tab_contents_(web_content),
+ tab_contents_(tab_contents),
download_(NULL),
+ page_url_(GetUrlToBeSaved()),
saved_main_file_path_(file_full_path),
saved_main_directory_path_(directory_full_path),
+ title_(tab_contents->GetTitle()),
finished_(false),
user_canceled_(false),
disk_error_occurred_(false),
save_type_(save_type),
all_save_items_count_(0),
wait_state_(INITIALIZE),
- tab_id_(web_content->GetRenderProcessHost()->id()),
+ tab_id_(tab_contents->GetRenderProcessHost()->id()),
unique_id_(g_save_package_id++),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
- DCHECK(web_content);
- const GURL& current_page_url = GetUrlToBeSaved();
- DCHECK(current_page_url.is_valid());
- page_url_ = current_page_url;
+ DCHECK(page_url_.is_valid());
DCHECK(save_type_ == SAVE_AS_ONLY_HTML ||
save_type_ == SAVE_AS_COMPLETE_HTML);
DCHECK(!saved_main_file_path_.empty() &&
@@ -240,6 +243,8 @@ SavePackage::SavePackage(TabContents* tab_contents)
: file_manager_(NULL),
tab_contents_(tab_contents),
download_(NULL),
+ page_url_(GetUrlToBeSaved()),
+ title_(tab_contents->GetTitle()),
finished_(false),
user_canceled_(false),
disk_error_occurred_(false),
@@ -249,10 +254,7 @@ SavePackage::SavePackage(TabContents* tab_contents)
tab_id_(tab_contents->GetRenderProcessHost()->id()),
unique_id_(g_save_package_id++),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
-
- const GURL& current_page_url = GetUrlToBeSaved();
- DCHECK(current_page_url.is_valid());
- page_url_ = current_page_url;
+ DCHECK(page_url_.is_valid());
InternalInit();
}
@@ -276,10 +278,6 @@ SavePackage::SavePackage(TabContents* tab_contents,
tab_id_(0),
unique_id_(g_save_package_id++),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
- DCHECK(!saved_main_file_path_.empty() &&
- saved_main_file_path_.value().length() <= kMaxFilePathLength);
- DCHECK(!saved_main_directory_path_.empty() &&
- saved_main_directory_path_.value().length() < kMaxFilePathLength);
}
SavePackage::~SavePackage() {
@@ -304,14 +302,9 @@ SavePackage::~SavePackage() {
STLDeleteValues(&in_progress_items_);
STLDeleteValues(&saved_failed_items_);
- if (download_) {
- // We call this to remove the view from the shelf. It will invoke
- // DownloadManager::RemoveDownload, but since the fake DownloadItem is not
- // owned by DownloadManager, it will do nothing to our fake item.
- download_->Remove(false);
- delete download_;
- download_ = NULL;
- }
+ // The DownloadItem is owned by DownloadManager.
+ download_ = NULL;
+
file_manager_ = NULL;
// If there's an outstanding save dialog, make sure it doesn't call us back
@@ -328,7 +321,7 @@ GURL SavePackage::GetUrlToBeSaved() {
// rather than the displayed one (returned by GetURL) which may be
// different (like having "view-source:" on the front).
NavigationEntry* active_entry =
- tab_contents_->controller().GetActiveEntry();
+ tab_contents_->controller().GetActiveEntry();
return active_entry->url();
}
@@ -377,10 +370,17 @@ bool SavePackage::Init() {
request_context_getter_ = profile->GetRequestContext();
// Create the fake DownloadItem and display the view.
- download_ = new DownloadItem(1, saved_main_file_path_, 0, page_url_, GURL(),
- "", "", FilePath(), Time::Now(), 0, -1, -1, false, false,
- profile->IsOffTheRecord(), false, false);
- download_->set_manager(tab_contents_->profile()->GetDownloadManager());
+ DownloadManager* download_manager =
+ tab_contents_->profile()->GetDownloadManager();
+ download_ = new DownloadItem(download_manager,
+ saved_main_file_path_,
+ page_url_,
+ profile->IsOffTheRecord());
+
+ // Transfer the ownership to the download manager. We need the DownloadItem
+ // to be alive as long as the Profile is alive.
+ download_manager->SavePageAsDownloadStarted(download_);
+
tab_contents_->OnStartDownload(download_);
// Check save type and process the save page job.
@@ -390,8 +390,7 @@ bool SavePackage::Init() {
GetAllSavableResourceLinksForCurrentPage();
} else {
wait_state_ = NET_FILES;
- GURL u(page_url_);
- SaveFileCreateInfo::SaveFileSource save_source = u.SchemeIsFile() ?
+ SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ?
SaveFileCreateInfo::SAVE_FILE_FROM_FILE :
SaveFileCreateInfo::SAVE_FILE_FROM_NET;
SaveItem* save_item = new SaveItem(page_url_,
@@ -727,9 +726,9 @@ void SavePackage::Finish() {
&SaveFileManager::RemoveSavedFileFromFileMap,
save_ids));
- download_->Finished(all_save_items_count_);
- // Notify download observers that we are complete (the call to Finished() set
- // the state to complete but did not notify).
+ download_->OnAllDataSaved(all_save_items_count_);
+ // Notify download observers that we are complete (the call
+ // to OnAllDataSaved() set the state to complete but did not notify).
download_->UpdateObservers();
NotificationService::current()->Notify(
@@ -1044,9 +1043,8 @@ void SavePackage::GetAllSavableResourceLinksForCurrentPage() {
return;
wait_state_ = RESOURCES_LIST;
- GURL main_page_url(page_url_);
tab_contents_->render_view_host()->
- GetAllSavableResourceLinksForCurrentPage(main_page_url);
+ GetAllSavableResourceLinksForCurrentPage(page_url_);
}
// Give backend the lists which contain all resource links that have local
@@ -1098,18 +1096,28 @@ void SavePackage::SetShouldPromptUser(bool should_prompt) {
g_should_prompt_for_filename = should_prompt;
}
-// static.
-FilePath SavePackage::GetSuggestedNameForSaveAs(const FilePath& name,
+FilePath SavePackage::GetSuggestedNameForSaveAs(
bool can_save_as_complete,
const FilePath::StringType& contents_mime_type) {
- // If the name is a URL, try to use the last path component or if there is
- // none, the domain as the file name.
- FilePath name_with_proper_ext = name;
- GURL url(WideToUTF8(name_with_proper_ext.ToWStringHack()));
- if (url.is_valid()) {
+ FilePath name_with_proper_ext =
+ FilePath::FromWStringHack(UTF16ToWideHack(title_));
+
+ // If the page's title matches its URL, use the URL. Try to use the last path
+ // component or if there is none, the domain as the file name.
+ // Normally we want to base the filename on the page title, or if it doesn't
+ // exist, on the URL. It's not easy to tell if the page has no title, because
+ // if the page has no title, TabContents::GetTitle() will return the page's
+ // URL (adjusted for display purposes). Therefore, we convert the "title"
+ // back to a URL, and if it matches the original page URL, we know the page
+ // had no title (or had a title equal to its URL, which is fine to treat
+ // similarly).
+ GURL fixed_up_title_url =
+ URLFixerUpper::FixupURL(UTF16ToUTF8(title_), std::string());
+
+ if (page_url_ == fixed_up_title_url) {
std::string url_path;
std::vector<std::string> url_parts;
- SplitString(url.path(), '/', &url_parts);
+ SplitString(page_url_.path(), '/', &url_parts);
if (!url_parts.empty()) {
for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) {
url_path = url_parts[i];
@@ -1118,7 +1126,7 @@ FilePath SavePackage::GetSuggestedNameForSaveAs(const FilePath& name,
}
}
if (url_path.empty())
- url_path = url.host();
+ url_path = page_url_.host();
name_with_proper_ext = FilePath::FromWStringHack(UTF8ToWide(url_path));
}
@@ -1235,9 +1243,6 @@ void SavePackage::ContinueGetSaveInfo(FilePath save_dir) {
bool can_save_as_complete =
CanSaveAsComplete(save_params->current_tab_mime_type);
- FilePath title =
- FilePath::FromWStringHack(UTF16ToWideHack(tab_contents_->GetTitle()));
-
#if defined(OS_POSIX)
FilePath::StringType mime_type(save_params->current_tab_mime_type);
#elif defined(OS_WIN)
@@ -1245,9 +1250,8 @@ void SavePackage::ContinueGetSaveInfo(FilePath save_dir) {
UTF8ToWide(save_params->current_tab_mime_type));
#endif // OS_WIN
- FilePath suggested_path =
- save_dir.Append(GetSuggestedNameForSaveAs(title, can_save_as_complete,
- mime_type));
+ FilePath suggested_path = save_dir.Append(
+ GetSuggestedNameForSaveAs(can_save_as_complete, mime_type));
// If the contents can not be saved as complete-HTML, do not show the
// file filters.
@@ -1266,13 +1270,13 @@ void SavePackage::ContinueGetSaveInfo(FilePath save_dir) {
if (add_extra_extension)
file_type_info.extensions[0].push_back(extra_extension);
file_type_info.extension_description_overrides.push_back(
- WideToUTF16(l10n_util::GetString(IDS_SAVE_PAGE_DESC_HTML_ONLY)));
+ l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_HTML_ONLY));
file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("htm"));
file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("html"));
if (add_extra_extension)
file_type_info.extensions[1].push_back(extra_extension);
file_type_info.extension_description_overrides.push_back(
- WideToUTF16(l10n_util::GetString(IDS_SAVE_PAGE_DESC_COMPLETE)));
+ l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_COMPLETE));
file_type_info.include_all_files = false;
default_extension = kDefaultHtmlExtension;
} else {
@@ -1309,10 +1313,8 @@ void SavePackage::ContinueSave(SavePackageParam* param,
int index) {
// Ensure the filename is safe.
param->saved_main_file_path = final_name;
- DownloadManager* dlm = tab_contents_->profile()->GetDownloadManager();
- DCHECK(dlm);
- dlm->GenerateSafeFileName(param->current_tab_mime_type,
- &param->saved_main_file_path);
+ download_util::GenerateSafeFileName(param->current_tab_mime_type,
+ &param->saved_main_file_path);
// The option index is not zero-based.
DCHECK(index > 0 && index < 3);
diff --git a/chrome/browser/download/save_package.h b/chrome/browser/download/save_package.h
index ab78eb8..68b3bf6 100644
--- a/chrome/browser/download/save_package.h
+++ b/chrome/browser/download/save_package.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_H_
#define CHROME_BROWSER_DOWNLOAD_SAVE_PACKAGE_H_
+#pragma once
#include <queue>
#include <string>
@@ -11,6 +12,7 @@
#include "base/basictypes.h"
#include "base/file_path.h"
+#include "base/gtest_prod_util.h"
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/task.h"
@@ -84,12 +86,12 @@ class SavePackage : public base::RefCountedThreadSafe<SavePackage>,
// Constructor for user initiated page saving. This constructor results in a
// SavePackage that will generate and sanitize a suggested name for the user
// in the "Save As" dialog box.
- explicit SavePackage(TabContents* web_content);
+ explicit SavePackage(TabContents* tab_contents);
// This contructor is used only for testing. We can bypass the file and
// directory name generation / sanitization by providing well known paths
// better suited for tests.
- SavePackage(TabContents* web_content,
+ SavePackage(TabContents* tab_contents,
SavePackageType save_type,
const FilePath& file_full_path,
const FilePath& directory_full_path);
@@ -224,7 +226,7 @@ class SavePackage : public base::RefCountedThreadSafe<SavePackage>,
// Helper function for preparing suggested name for the SaveAs Dialog. The
// suggested name is determined by the web document's title.
- static FilePath GetSuggestedNameForSaveAs(const FilePath& name,
+ FilePath GetSuggestedNameForSaveAs(
bool can_save_as_complete,
const FilePath::StringType& contents_mime_type);
@@ -268,6 +270,9 @@ class SavePackage : public base::RefCountedThreadSafe<SavePackage>,
FilePath saved_main_file_path_;
FilePath saved_main_directory_path_;
+ // The title of the page the user wants to save.
+ string16 title_;
+
// Indicates whether the actual saving job is finishing or not.
bool finished_;
@@ -306,6 +311,7 @@ class SavePackage : public base::RefCountedThreadSafe<SavePackage>,
scoped_refptr<SelectFileDialog> select_file_dialog_;
friend class SavePackageTest;
+ FRIEND_TEST_ALL_PREFIXES(SavePackageTest, TestSuggestedSaveNames);
ScopedRunnableMethodFactory<SavePackage> method_factory_;
diff --git a/chrome/browser/download/save_package_unittest.cc b/chrome/browser/download/save_package_unittest.cc
index 551a7d9..b315097 100644
--- a/chrome/browser/download/save_package_unittest.cc
+++ b/chrome/browser/download/save_package_unittest.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,9 +7,11 @@
#include "base/file_path.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -84,13 +86,6 @@ class SavePackageTest : public RenderViewHostTestHarness {
return SavePackage::EnsureMimeExtension(name, content_mime_type);
}
- FilePath GetSuggestedNameForSaveAs(const FilePath& title,
- bool ensure_html_extension,
- const FilePath::StringType& contents_mime_type) {
- return SavePackage::GetSuggestedNameForSaveAs(title, ensure_html_extension,
- contents_mime_type);
- }
-
GURL GetUrlToBeSaved() {
return save_package_success_->GetUrlToBeSaved();
}
@@ -289,26 +284,63 @@ TEST_F(SavePackageTest, TestEnsureMimeExtension) {
// http://www.foo.com/a/path/name.txt will turn into file:
// "http www.foo.com a path name.txt", when we want to save it as "name.txt".
-static const struct {
- const FilePath::CharType* page_title;
+static const struct SuggestedSaveNameTestCase {
+ const char* page_url;
+ const string16 page_title;
const FilePath::CharType* expected_name;
bool ensure_html_extension;
} kSuggestedSaveNames[] = {
- {FPL("A page title"), FPL("A page title") FPL_HTML_EXTENSION, true},
- {FPL("A page title with.ext"), FPL("A page title with.ext"), false},
- {FPL("http://www.foo.com/path/title.txt"), FPL("title.txt"), false},
- {FPL("http://www.foo.com/path/"), FPL("path"), false},
- {FPL("http://www.foo.com/"), FPL("www.foo.com"), false},
+ // Title overrides the URL.
+ { "http://foo.com",
+ ASCIIToUTF16("A page title"),
+ FPL("A page title") FPL_HTML_EXTENSION,
+ true
+ },
+ // Extension is preserved.
+ { "http://foo.com",
+ ASCIIToUTF16("A page title with.ext"),
+ FPL("A page title with.ext"),
+ false
+ },
+ // If the title matches the URL, use the last component of the URL.
+ { "http://foo.com/bar",
+ ASCIIToUTF16("http://foo.com/bar"),
+ FPL("bar"),
+ false
+ },
+ // If the title matches the URL, but there is no "filename" component,
+ // use the domain.
+ { "http://foo.com",
+ ASCIIToUTF16("http://foo.com"),
+ FPL("foo.com"),
+ false
+ },
+ // Make sure fuzzy matching works.
+ { "http://foo.com/bar",
+ ASCIIToUTF16("foo.com/bar"),
+ FPL("bar"),
+ false
+ },
+ // A URL-like title that does not match the title is respected in full.
+ { "http://foo.com",
+ ASCIIToUTF16("http://www.foo.com/path/title.txt"),
+ FPL("http www.foo.com path title.txt"),
+ false
+ },
};
TEST_F(SavePackageTest, TestSuggestedSaveNames) {
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSuggestedSaveNames); ++i) {
- FilePath title = FilePath(kSuggestedSaveNames[i].page_title);
- FilePath save_name =
- GetSuggestedNameForSaveAs(title,
- kSuggestedSaveNames[i].ensure_html_extension,
- FilePath::StringType());
- EXPECT_EQ(save_name.value(), kSuggestedSaveNames[i].expected_name);
+ for (size_t i = 0; i < arraysize(kSuggestedSaveNames); ++i) {
+ scoped_refptr<SavePackage> save_package(
+ new SavePackage(NULL, FilePath(), FilePath()));
+ save_package->page_url_ = GURL(kSuggestedSaveNames[i].page_url);
+ save_package->title_ = kSuggestedSaveNames[i].page_title;
+
+ FilePath save_name = save_package->GetSuggestedNameForSaveAs(
+ kSuggestedSaveNames[i].ensure_html_extension,
+ FilePath::StringType());
+ EXPECT_EQ(kSuggestedSaveNames[i].expected_name, save_name.value()) <<
+ "Test case " << i;
}
}
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 99648b4..bed7228 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
diff --git a/chrome/browser/download/save_types.h b/chrome/browser/download/save_types.h
index 7ddac66..d046b5b 100644
--- a/chrome/browser/download/save_types.h
+++ b/chrome/browser/download/save_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_DOWNLOAD_SAVE_TYPES_H_
#define CHROME_BROWSER_DOWNLOAD_SAVE_TYPES_H_
+#pragma once
#include <string>
#include <utility>
diff --git a/chrome/browser/dummy_configuration_policy_provider.h b/chrome/browser/dummy_configuration_policy_provider.h
deleted file mode 100644
index 47443b2..0000000
--- a/chrome/browser/dummy_configuration_policy_provider.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_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_
-#define CHROME_BROWSER_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_
-
-#include "chrome/browser/configuration_policy_store.h"
-#include "chrome/browser/configuration_policy_provider.h"
-
-class DummyConfigurationPolicyProvider : public ConfigurationPolicyProvider {
- public:
- DummyConfigurationPolicyProvider() {}
- virtual ~DummyConfigurationPolicyProvider() {}
-
- virtual bool Provide(ConfigurationPolicyStore* store) {
- return true;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DummyConfigurationPolicyProvider);
-};
-
-#endif // CHROME_BROWSER_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_
-
diff --git a/chrome/browser/encoding_menu_controller.cc b/chrome/browser/encoding_menu_controller.cc
index 952276b..a286fdf 100644
--- a/chrome/browser/encoding_menu_controller.cc
+++ b/chrome/browser/encoding_menu_controller.cc
@@ -10,7 +10,7 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/encoding_menu_controller.h b/chrome/browser/encoding_menu_controller.h
index 44f5877..fc907f8 100644
--- a/chrome/browser/encoding_menu_controller.h
+++ b/chrome/browser/encoding_menu_controller.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_ENCODING_MENU_CONTROLLER_H_
#define CHROME_BROWSER_ENCODING_MENU_CONTROLLER_H_
+#pragma once
#include <utility>
#include <string>
@@ -13,7 +14,6 @@
#include "base/gtest_prod_util.h"
#include "base/string16.h"
-class Browser;
class Profile;
// Cross-platform logic needed for the encoding menu.
diff --git a/chrome/browser/encoding_menu_controller_unittest.cc b/chrome/browser/encoding_menu_controller_unittest.cc
index e7a7fef..91cd2a4 100644
--- a/chrome/browser/encoding_menu_controller_unittest.cc
+++ b/chrome/browser/encoding_menu_controller_unittest.cc
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "chrome/app/chrome_dll_resource.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"
diff --git a/chrome/browser/errorpage_uitest.cc b/chrome/browser/errorpage_uitest.cc
index 3196a50..6446b56 100644
--- a/chrome/browser/errorpage_uitest.cc
+++ b/chrome/browser/errorpage_uitest.cc
@@ -7,7 +7,7 @@
#include "chrome/test/ui/ui_test.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
class ErrorPageTest : public UITest {
protected:
@@ -168,12 +168,10 @@ TEST_F(ErrorPageTest, IFrame404) {
// In this test, the iframe sets the title of the parent page to "SUCCESS"
// when the iframe loads. If the iframe fails to load (because an alternate
// error page loads instead), then the title will remain as "FAIL".
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL test_url = server->TestServerPage("files/iframe404.html");
- NavigateToURL(test_url);
-
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
+ NavigateToURL(test_server.GetURL("files/iframe404.html"));
EXPECT_TRUE(WaitForTitleMatching(L"SUCCESS"));
}
diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc
index f16dad3..a75fc50 100644
--- a/chrome/browser/extensions/app_background_page_apitest.cc
+++ b/chrome/browser/extensions/app_background_page_apitest.cc
@@ -12,14 +12,13 @@ class AppBackgroundPageApiTest : public ExtensionApiTest {
public:
void SetUpCommandLine(CommandLine* command_line) {
ExtensionApiTest::SetUpCommandLine(command_line);
- command_line->AppendSwitch(switches::kEnableApps);
command_line->AppendSwitch(switches::kDisablePopupBlocking);
}
};
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, Basic) {
host_resolver()->AddRule("a.com", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
LoadExtension(test_data_dir_.AppendASCII(
"app_background_page/app_has_permission"));
@@ -28,7 +27,7 @@ IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, Basic) {
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, LacksPermission) {
host_resolver()->AddRule("a.com", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
LoadExtension(test_data_dir_.AppendASCII(
"app_background_page/app_lacks_permission"));
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 7cdc80b..689a88c 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
@@ -14,16 +16,13 @@
#include "net/base/mock_host_resolver.h"
class AppApiTest : public ExtensionApiTest {
- public:
- void SetUpCommandLine(CommandLine* command_line) {
- ExtensionApiTest::SetUpCommandLine(command_line);
- command_line->AppendSwitch(switches::kEnableApps);
- }
};
// Simulates a page calling window.open on an URL, and waits for the navigation.
static void WindowOpenHelper(Browser* browser,
- RenderViewHost* opener_host, const GURL& url) {
+ RenderViewHost* opener_host,
+ const GURL& url,
+ bool newtab_process_should_equal_opener) {
bool result = false;
ui_test_utils::ExecuteJavaScriptAndExtractBool(
opener_host, L"",
@@ -32,12 +31,21 @@ static void WindowOpenHelper(Browser* browser,
&result);
ASSERT_TRUE(result);
- // Now the current tab should be the new tab.
- TabContents* newtab = browser->GetSelectedTabContents();
+ // The above window.open call is not user-initiated, it will create
+ // a popup window instead of a new tab in current window.
+ // Now the active tab in last active window should be the new tab.
+ Browser* last_active_browser = BrowserList::GetLastActive();
+ EXPECT_TRUE(last_active_browser);
+ TabContents* newtab = last_active_browser->GetSelectedTabContents();
+ EXPECT_TRUE(newtab);
if (!newtab->controller().GetLastCommittedEntry() ||
newtab->controller().GetLastCommittedEntry()->url() != url)
ui_test_utils::WaitForNavigation(&newtab->controller());
EXPECT_EQ(url, newtab->controller().GetLastCommittedEntry()->url());
+ if (newtab_process_should_equal_opener)
+ EXPECT_EQ(opener_host->process(), newtab->render_view_host()->process());
+ else
+ EXPECT_NE(opener_host->process(), newtab->render_view_host()->process());
}
// Simulates a page navigating itself to an URL, and waits for the navigation.
@@ -59,64 +67,51 @@ static void NavigateTabHelper(TabContents* contents, const GURL& url) {
}
IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisablePopupBlocking);
+
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
- ASSERT_TRUE(RunExtensionTest("app_process")) << message_;
+ ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
- Extension* extension = GetSingleLoadedExtension();
- ExtensionHost* host = browser()->profile()->GetExtensionProcessManager()->
- GetBackgroundHostForExtension(extension);
- ASSERT_TRUE(host);
+ // Open two tabs in the app, one outside it.
+ GURL base_url("http://localhost:1337/files/extensions/api_test/app_process/");
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
// The extension should have opened 3 new tabs. Including the original blank
// tab, we now have 4 tabs. Two should be part of the extension app, and
- // grouped in the extension process.
+ // grouped in the same process.
ASSERT_EQ(4, browser()->tab_count());
- EXPECT_EQ(host->render_process_host(),
- browser()->GetTabContentsAt(1)->render_view_host()->process());
- EXPECT_EQ(host->render_process_host(),
+ RenderViewHost* host = browser()->GetTabContentsAt(1)->render_view_host();
+
+ EXPECT_EQ(host->process(),
browser()->GetTabContentsAt(2)->render_view_host()->process());
- EXPECT_NE(host->render_process_host(),
+ EXPECT_NE(host->process(),
browser()->GetTabContentsAt(3)->render_view_host()->process());
// Now let's do the same using window.open. The same should happen.
- GURL base_url("http://localhost:1337/files/extensions/api_test/app_process/");
- WindowOpenHelper(browser(), host->render_view_host(),
- base_url.Resolve("path1/empty.html"));
- WindowOpenHelper(browser(), host->render_view_host(),
- base_url.Resolve("path2/empty.html"));
- WindowOpenHelper(browser(), host->render_view_host(),
- base_url.Resolve("path3/empty.html"));
-
- ASSERT_EQ(7, browser()->tab_count());
- EXPECT_EQ(host->render_process_host(),
- browser()->GetTabContentsAt(4)->render_view_host()->process());
- EXPECT_EQ(host->render_process_host(),
- browser()->GetTabContentsAt(5)->render_view_host()->process());
- EXPECT_NE(host->render_process_host(),
- browser()->GetTabContentsAt(6)->render_view_host()->process());
+ ASSERT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
+ WindowOpenHelper(browser(), host,
+ base_url.Resolve("path1/empty.html"), true);
+ WindowOpenHelper(browser(), host,
+ base_url.Resolve("path2/empty.html"), true);
+ WindowOpenHelper(browser(), host,
+ base_url.Resolve("path3/empty.html"), false);
// Now let's have these pages navigate, into or out of the extension web
// extent. They should switch processes.
const GURL& app_url(base_url.Resolve("path1/empty.html"));
const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
- NavigateTabHelper(browser()->GetTabContentsAt(1), non_app_url);
+ NavigateTabHelper(browser()->GetTabContentsAt(2), non_app_url);
NavigateTabHelper(browser()->GetTabContentsAt(3), app_url);
- EXPECT_NE(host->render_process_host(),
- browser()->GetTabContentsAt(1)->render_view_host()->process());
- EXPECT_EQ(host->render_process_host(),
- browser()->GetTabContentsAt(3)->render_view_host()->process());
-
- // Navigate the non-app tab into the browse extent. It should not enter the
- // app process.
- // Navigate the app tab into the browse extent. It should stay in the app
- // process.
- const GURL& browse_url(base_url.Resolve("path4/empty.html"));
- NavigateTabHelper(browser()->GetTabContentsAt(1), browse_url);
- NavigateTabHelper(browser()->GetTabContentsAt(3), browse_url);
- EXPECT_NE(host->render_process_host(),
- browser()->GetTabContentsAt(1)->render_view_host()->process());
- EXPECT_EQ(host->render_process_host(),
+ EXPECT_NE(host->process(),
+ browser()->GetTabContentsAt(2)->render_view_host()->process());
+ EXPECT_EQ(host->process(),
browser()->GetTabContentsAt(3)->render_view_host()->process());
}
diff --git a/chrome/browser/extensions/autoupdate_interceptor.h b/chrome/browser/extensions/autoupdate_interceptor.h
index 142c46d..42ae024 100644
--- a/chrome/browser/extensions/autoupdate_interceptor.h
+++ b/chrome/browser/extensions/autoupdate_interceptor.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_AUTOUPDATE_INTERCEPTOR_H_
#define CHROME_BROWSER_EXTENSIONS_AUTOUPDATE_INTERCEPTOR_H_
+#pragma once
#include <map>
#include <string>
diff --git a/chrome/browser/extensions/browser_action_apitest.cc b/chrome/browser/extensions/browser_action_apitest.cc
index 63d205b..82f1320 100644
--- a/chrome/browser/extensions/browser_action_apitest.cc
+++ b/chrome/browser/extensions/browser_action_apitest.cc
@@ -45,7 +45,7 @@ class BrowserActionApiTest : public ExtensionApiTest {
};
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, Basic) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_;
Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
@@ -266,7 +266,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, BrowserActionRemovePopup) {
}
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_;
Extension* extension = GetSingleLoadedExtension();
diff --git a/chrome/browser/extensions/browser_action_test_util.h b/chrome/browser/extensions/browser_action_test_util.h
index e2d6050..cadb12c 100644
--- a/chrome/browser/extensions/browser_action_test_util.h
+++ b/chrome/browser/extensions/browser_action_test_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_BROWSER_ACTION_TEST_UTIL_H_
#define CHROME_BROWSER_EXTENSIONS_BROWSER_ACTION_TEST_UTIL_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/extensions/browser_action_test_util_gtk.cc b/chrome/browser/extensions/browser_action_test_util_gtk.cc
index 7761946..8318dce 100644
--- a/chrome/browser/extensions/browser_action_test_util_gtk.cc
+++ b/chrome/browser/extensions/browser_action_test_util_gtk.cc
@@ -15,13 +15,15 @@
namespace {
GtkWidget* GetButton(Browser* browser, int index) {
- GtkWidget* button = NULL;
GtkWidget* toolbar =
ViewIDUtil::GetWidget(GTK_WIDGET(browser->window()->GetNativeHandle()),
VIEW_ID_BROWSER_ACTION_TOOLBAR);
+ GtkWidget* button = NULL;
if (toolbar) {
GList* children = gtk_container_get_children(GTK_CONTAINER(toolbar));
- button = static_cast<GtkWidget*>(g_list_nth(children, index)->data);
+ GtkWidget* alignment =
+ static_cast<GtkWidget*>(g_list_nth(children, index)->data);
+ button = gtk_bin_get_child(GTK_BIN(alignment));
g_list_free(children);
}
return button;
diff --git a/chrome/browser/extensions/browser_action_test_util_views.cc b/chrome/browser/extensions/browser_action_test_util_views.cc
index fad2f7d..85f20a5 100644
--- a/chrome/browser/extensions/browser_action_test_util_views.cc
+++ b/chrome/browser/extensions/browser_action_test_util_views.cc
@@ -41,8 +41,8 @@ void BrowserActionTestUtil::WaitForBrowserActionUpdated(int index) {
}
bool BrowserActionTestUtil::HasIcon(int index) {
- return !GetContainer(browser_)->GetBrowserActionViewAt(index)->
- button()->icon().empty();
+ return GetContainer(browser_)->GetBrowserActionViewAt(index)->button()->
+ HasIcon();
}
void BrowserActionTestUtil::Press(int index) {
diff --git a/chrome/browser/extensions/content_script_all_frames_apitest.cc b/chrome/browser/extensions/content_script_all_frames_apitest.cc
index 13be5fd..fac6362 100644
--- a/chrome/browser/extensions/content_script_all_frames_apitest.cc
+++ b/chrome/browser/extensions/content_script_all_frames_apitest.cc
@@ -5,11 +5,11 @@
#include "chrome/browser/extensions/extension_apitest.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAllFrames) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("content_scripts/all_frames")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionIframe) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("content_scripts/extension_iframe")) << message_;
}
diff --git a/chrome/browser/extensions/content_script_extension_process_apitest.cc b/chrome/browser/extensions/content_script_extension_process_apitest.cc
index 16258fa..46729d2 100644
--- a/chrome/browser/extensions/content_script_extension_process_apitest.cc
+++ b/chrome/browser/extensions/content_script_extension_process_apitest.cc
@@ -10,6 +10,6 @@
#include "chrome/test/ui_test_utils.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionProcess) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("content_scripts/extension_process")) << message_;
}
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index b06553a..d50bec1 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -45,7 +45,7 @@ Extension* ConvertUserScriptToExtension(const FilePath& user_script_path,
CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));
ScopedTempDir temp_dir;
- if (!temp_dir.CreateUniqueTempDirUnderPath(user_data_temp_dir, false)) {
+ if (!temp_dir.CreateUniqueTempDirUnderPath(user_data_temp_dir)) {
*error = "Could not create temporary directory.";
return NULL;
}
diff --git a/chrome/browser/extensions/convert_user_script.h b/chrome/browser/extensions/convert_user_script.h
index ebc9ee2..d392c4d 100644
--- a/chrome/browser/extensions/convert_user_script.h
+++ b/chrome/browser/extensions/convert_user_script.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_CONVERT_USER_SCRIPT_H_
#define CHROME_BROWSER_EXTENSIONS_CONVERT_USER_SCRIPT_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/extensions/crashed_extension_infobar.cc b/chrome/browser/extensions/crashed_extension_infobar.cc
index 685c5f7..053b4b4 100644
--- a/chrome/browser/extensions/crashed_extension_infobar.cc
+++ b/chrome/browser/extensions/crashed_extension_infobar.cc
@@ -25,9 +25,14 @@ CrashedExtensionInfoBarDelegate::CrashedExtensionInfoBarDelegate(
DCHECK(!extension_id_.empty());
}
-std::wstring CrashedExtensionInfoBarDelegate::GetMessageText() const {
- return l10n_util::GetStringF(IDS_EXTENSION_CRASHED_INFOBAR_MESSAGE,
- UTF8ToWide(extension_name_));
+CrashedExtensionInfoBarDelegate* CrashedExtensionInfoBarDelegate::
+AsCrashedExtensionInfoBarDelegate() {
+ return this;
+}
+
+string16 CrashedExtensionInfoBarDelegate::GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_EXTENSION_CRASHED_INFOBAR_MESSAGE,
+ UTF8ToUTF16(extension_name_));
}
void CrashedExtensionInfoBarDelegate::InfoBarClosed() {
@@ -44,10 +49,12 @@ int CrashedExtensionInfoBarDelegate::GetButtons() const {
return BUTTON_OK;
}
-std::wstring CrashedExtensionInfoBarDelegate::GetButtonLabel(
+string16 CrashedExtensionInfoBarDelegate::GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const {
- if (button == BUTTON_OK)
- return l10n_util::GetString(IDS_EXTENSION_CRASHED_INFOBAR_RESTART_BUTTON);
+ if (button == BUTTON_OK) {
+ return l10n_util::GetStringUTF16(
+ IDS_EXTENSION_CRASHED_INFOBAR_RESTART_BUTTON);
+ }
return ConfirmInfoBarDelegate::GetButtonLabel(button);
}
diff --git a/chrome/browser/extensions/crashed_extension_infobar.h b/chrome/browser/extensions/crashed_extension_infobar.h
index 48e9acb..1508ae5 100644
--- a/chrome/browser/extensions/crashed_extension_infobar.h
+++ b/chrome/browser/extensions/crashed_extension_infobar.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_CRASHED_EXTENSION_INFOBAR_H_
#define CHROME_BROWSER_EXTENSIONS_CRASHED_EXTENSION_INFOBAR_H_
+#pragma once
#include <string>
@@ -28,16 +29,14 @@ class CrashedExtensionInfoBarDelegate : public ConfirmInfoBarDelegate {
const std::string extension_id() { return extension_id_; }
// InfoBarDelegate
- virtual CrashedExtensionInfoBarDelegate* AsCrashedExtensionInfoBarDelegate() {
- return this;
- }
+ virtual CrashedExtensionInfoBarDelegate* AsCrashedExtensionInfoBarDelegate();
// ConfirmInfoBarDelegate
- virtual std::wstring GetMessageText() const;
+ virtual string16 GetMessageText() const;
virtual void InfoBarClosed();
virtual SkBitmap* GetIcon() const;
virtual int GetButtons() const;
- virtual std::wstring GetButtonLabel(
+ virtual string16 GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const;
virtual bool Accept();
diff --git a/chrome/browser/extensions/cross_origin_xhr_apitest.cc b/chrome/browser/extensions/cross_origin_xhr_apitest.cc
index a2cf9d8..41474bc 100644
--- a/chrome/browser/extensions/cross_origin_xhr_apitest.cc
+++ b/chrome/browser/extensions/cross_origin_xhr_apitest.cc
@@ -7,6 +7,6 @@
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, CrossOriginXHR) {
host_resolver()->AddRule("*.com", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("cross_origin_xhr")) << message_;
}
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 38ab772..1b0bbeb 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -9,11 +9,15 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
+#include "base/singleton.h"
+#include "base/stringprintf.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
+#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/convert_user_script.h"
+#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/shell_integration.h"
@@ -23,17 +27,48 @@
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
-#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace {
- // Helper function to delete files. This is used to avoid ugly casts which
- // would be necessary with PostMessage since file_util::Delete is overloaded.
- static void DeleteFileHelper(const FilePath& path, bool recursive) {
- file_util::Delete(path, recursive);
+
+// Helper function to delete files. This is used to avoid ugly casts which
+// would be necessary with PostMessage since file_util::Delete is overloaded.
+static void DeleteFileHelper(const FilePath& path, bool recursive) {
+ file_util::Delete(path, recursive);
+}
+
+struct WhitelistedInstallData {
+ WhitelistedInstallData() {}
+ std::list<std::string> ids;
+};
+
+}
+
+// static
+void CrxInstaller::SetWhitelistedInstallId(const std::string& id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ Singleton<WhitelistedInstallData>::get()->ids.push_back(id);
+}
+
+// static
+bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) {
+ std::list<std::string>& ids = Singleton<WhitelistedInstallData>::get()->ids;
+ std::list<std::string>::iterator iter = ids.begin();
+ for (; iter != ids.end(); ++iter) {
+ if (*iter == id) {
+ break;
+ }
}
+
+ if (iter != ids.end()) {
+ ids.erase(iter);
+ return true;
+ }
+
+ return false;
}
CrxInstaller::CrxInstaller(const FilePath& install_directory,
@@ -44,10 +79,10 @@ CrxInstaller::CrxInstaller(const FilePath& install_directory,
delete_source_(false),
allow_privilege_increase_(false),
limit_web_extent_to_download_host_(false),
- create_app_shortcut_(false),
frontend_(frontend),
client_(client),
- apps_require_extension_mime_type_(false) {
+ apps_require_extension_mime_type_(false),
+ allow_silent_install_(false) {
extensions_enabled_ = frontend_->extensions_enabled();
}
@@ -137,13 +172,13 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
!original_url_.SchemeIsFile() &&
apps_require_extension_mime_type_ &&
original_mime_type_ != Extension::kMimeType) {
- ReportFailureFromFileThread(StringPrintf(
+ ReportFailureFromFileThread(base::StringPrintf(
"Applications must be served with content type %s.",
Extension::kMimeType));
return;
}
- // The unpack dir we don't have to delete explicity since it is a child of
+ // We don't have to delete the unpack dir explicity since it is a child of
// the temp dir.
unpacked_extension_root_ = extension_dir;
@@ -158,7 +193,7 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
// Make sure the expected id matches.
// TODO(aa): Also support expected version?
if (!expected_id_.empty() && expected_id_ != extension->id()) {
- ReportFailureFromFileThread(StringPrintf(
+ ReportFailureFromFileThread(base::StringPrintf(
"ID in new extension manifest (%s) does not match expected id (%s)",
extension->id().c_str(),
expected_id_.c_str()));
@@ -174,7 +209,7 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
for (size_t i = 0; i < extension_->web_extent().patterns().size(); ++i) {
if (!pattern.MatchesHost(extension_->web_extent().patterns()[i].host())) {
- ReportFailureFromFileThread(StringPrintf(
+ ReportFailureFromFileThread(base::StringPrintf(
"Apps must be served from the host that they affect."));
return;
}
@@ -200,6 +235,12 @@ void CrxInstaller::ConfirmInstall() {
return;
}
+ if (!frontend_->extension_prefs()->IsExtensionAllowedByPolicy(
+ extension_->id())) {
+ ReportFailureFromUIThread("This extension is blacklisted by admin policy.");
+ return;
+ }
+
GURL overlapping_url;
Extension* overlapping_extension =
frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent());
@@ -213,7 +254,9 @@ void CrxInstaller::ConfirmInstall() {
current_version_ =
frontend_->extension_prefs()->GetVersionString(extension_->id());
- if (client_) {
+ if (client_ &&
+ (!allow_silent_install_ ||
+ !ClearWhitelistedInstallId(extension_->id()))) {
AddRef(); // Balanced in Proceed() and Abort().
client_->ConfirmInstall(this, extension_.get());
} else {
@@ -224,12 +267,7 @@ void CrxInstaller::ConfirmInstall() {
return;
}
-void CrxInstaller::InstallUIProceed(bool create_app_shortcut) {
- if (create_app_shortcut) {
- DCHECK(extension_->GetFullLaunchURL().is_valid());
- create_app_shortcut_ = true;
- }
-
+void CrxInstaller::InstallUIProceed() {
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(this, &CrxInstaller::CompleteInstall));
@@ -273,25 +311,6 @@ void CrxInstaller::CompleteInstall() {
return;
}
- if (create_app_shortcut_) {
- SkBitmap icon = install_icon_.get() ? *install_icon_ :
- *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_EXTENSION_DEFAULT_ICON);
-
- ShellIntegration::ShortcutInfo shortcut_info;
- shortcut_info.url = extension_->GetFullLaunchURL();
- shortcut_info.extension_id = UTF8ToUTF16(extension_->id());
- shortcut_info.title = UTF8ToUTF16(extension_->name());
- shortcut_info.description = UTF8ToUTF16(extension_->description());
- shortcut_info.favicon = icon;
- shortcut_info.create_on_desktop = true;
-
- // TODO(aa): Seems nasty to be reusing the old webapps code this way. What
- // baggage am I inheriting?
- web_app::CreateShortcut(frontend_->profile()->GetPath(), shortcut_info,
- NULL);
- }
-
// This is lame, but we must reload the extension because absolute paths
// inside the content scripts are established inside InitFromValue() and we
// just moved the extension.
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 9ab011b..ca3e90f 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -4,16 +4,17 @@
#ifndef CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
#define CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
+#pragma once
#include <string>
#include "base/file_path.h"
#include "base/ref_counted.h"
#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
#include "chrome/common/extensions/extension.h"
+class ExtensionsService;
class SkBitmap;
// This class installs a crx file into a profile.
@@ -43,6 +44,18 @@ class CrxInstaller
: public SandboxedExtensionUnpackerClient,
public ExtensionInstallUI::Delegate {
public:
+
+ // This is pretty lame, but given the difficulty of connecting a particular
+ // ExtensionFunction to a resulting download in the download manager, it's
+ // currently necessary. This is the |id| of an extension to be installed
+ // *by the web store only* which should not get the permissions install
+ // prompt.
+ // crbug.com/54916
+ static void SetWhitelistedInstallId(const std::string& id);
+
+ // Returns whether |id| was found and removed (was whitelisted).
+ static bool ClearWhitelistedInstallId(const std::string& id);
+
// Constructor. Extensions will be unpacked to |install_directory|.
// Extension objects will be sent to |frontend|, and any UI will be shown
// via |client|. For silent install, pass NULL for |client|.
@@ -59,8 +72,8 @@ class CrxInstaller
void InstallUserScript(const FilePath& source_file,
const GURL& original_url);
- // ExtensionInstallUI::Delegate
- virtual void InstallUIProceed(bool create_app_shortcut);
+ // Overridden from ExtensionInstallUI::Delegate:
+ virtual void InstallUIProceed();
virtual void InstallUIAbort();
const GURL& original_url() const { return original_url_; }
@@ -82,6 +95,9 @@ class CrxInstaller
allow_privilege_increase_ = val;
}
+ bool allow_silent_install() const { return allow_silent_install_; }
+ void set_allow_silent_install(bool val) { allow_silent_install_ = val; }
+
bool limit_web_extent_to_download_host() const {
return limit_web_extent_to_download_host_;
}
@@ -202,6 +218,13 @@ class CrxInstaller
// Used to trigger extra checks before installing.
bool apps_require_extension_mime_type_;
+ // Allows for the possibility of a normal install (one in which a |client|
+ // is provided in the ctor) to procede without showing the permissions prompt
+ // dialog. Note that this will only take place if |allow_silent_install_|
+ // is true AND the unpacked id of the extension is whitelisted with
+ // SetWhitelistedInstallId().
+ bool allow_silent_install_;
+
// The value of the content type header sent with the CRX.
// Ignorred unless |require_extension_mime_type_| is true.
std::string original_mime_type_;
diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc
index 44de6bf..52f519d 100644
--- a/chrome/browser/extensions/execute_code_in_tab_function.cc
+++ b/chrome/browser/extensions/execute_code_in_tab_function.cc
@@ -6,18 +6,29 @@
#include "base/callback.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.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/file_reader.h"
+#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.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/notification_service.h"
namespace keys = extension_tabs_module_constants;
+ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
+ : execute_tab_id_(-1),
+ all_frames_(false) {
+}
+
+ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {
+}
+
bool ExecuteCodeInTabFunction::RunImpl() {
DictionaryValue* script_info;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &script_info));
@@ -113,6 +124,8 @@ void ExecuteCodeInTabFunction::DidLoadFile(bool success,
Execute(data);
} else {
#if defined(OS_POSIX)
+ // TODO(viettrungluu): bug: there's no particular reason the path should be
+ // UTF-8, in which case this may fail.
error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kLoadFileError,
resource_.relative_path().value());
#elif defined(OS_WIN)
diff --git a/chrome/browser/extensions/execute_code_in_tab_function.h b/chrome/browser/extensions/execute_code_in_tab_function.h
index 8da8b75..89d7e5a 100644
--- a/chrome/browser/extensions/execute_code_in_tab_function.h
+++ b/chrome/browser/extensions/execute_code_in_tab_function.h
@@ -1,27 +1,24 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXECUTE_CODE_IN_TAB_FUNCTION_H__
#define CHROME_BROWSER_EXTENSIONS_EXECUTE_CODE_IN_TAB_FUNCTION_H__
+#pragma once
#include <string>
-#include <vector>
-#include "base/file_path.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/common/extensions/extension_resource.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class MessageLoop;
-
// Implement API call tabs.executeScript and tabs.insertCSS.
class ExecuteCodeInTabFunction : public AsyncExtensionFunction,
public NotificationObserver {
public:
- ExecuteCodeInTabFunction() : execute_tab_id_(-1),
- all_frames_(false) {}
+ ExecuteCodeInTabFunction();
+ virtual ~ExecuteCodeInTabFunction();
private:
virtual bool RunImpl();
diff --git a/chrome/browser/extensions/execute_script_apitest.cc b/chrome/browser/extensions/execute_script_apitest.cc
index 07c141c..f6c963b 100644
--- a/chrome/browser/extensions/execute_script_apitest.cc
+++ b/chrome/browser/extensions/execute_script_apitest.cc
@@ -12,7 +12,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_ExecuteScript) {
host_resolver()->AddRuleWithLatency("a.com", "127.0.0.1", 500);
host_resolver()->AddRule("b.com", "127.0.0.1");
host_resolver()->AddRule("c.com", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("executescript/basic")) << message_;
ASSERT_TRUE(RunExtensionTest("executescript/in_frame")) << message_;
@@ -23,7 +23,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_ExecuteScript) {
// (ExecuteScript) tests are de-flakified, reunite this case with it's brethern.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExecuteScriptFileAfterClose) {
host_resolver()->AddRule("b.com", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("executescript/file_after_close")) << message_;
}
diff --git a/chrome/browser/extensions/extension_accessibility_api.cc b/chrome/browser/extensions/extension_accessibility_api.cc
index 8b4630e..bf310f2 100644
--- a/chrome/browser/extensions/extension_accessibility_api.cc
+++ b/chrome/browser/extensions/extension_accessibility_api.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_service.h"
namespace keys = extension_accessibility_api_constants;
@@ -176,7 +177,7 @@ void ExtensionAccessibilityEventRouter::DispatchEvent(
const std::string& json_args) {
if (enabled_ && profile && profile->GetExtensionMessageService()) {
profile->GetExtensionMessageService()->DispatchEventToRenderers(
- event_name, json_args, profile->IsOffTheRecord(), GURL());
+ event_name, json_args, profile, GURL());
}
}
diff --git a/chrome/browser/extensions/extension_accessibility_api.h b/chrome/browser/extensions/extension_accessibility_api.h
index bc724c1..87f94d7 100644
--- a/chrome/browser/extensions/extension_accessibility_api.h
+++ b/chrome/browser/extensions/extension_accessibility_api.h
@@ -4,15 +4,17 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ACCESSIBILITY_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_ACCESSIBILITY_API_H_
+#pragma once
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/singleton.h"
+#include "base/values.h"
#include "chrome/browser/accessibility_events.h"
#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"
// Observes the profile and routes accessibility notifications as events
diff --git a/chrome/browser/extensions/extension_accessibility_api_constants.cc b/chrome/browser/extensions/extension_accessibility_api_constants.cc
index 8ddf5a0..6cad35e 100644
--- a/chrome/browser/extensions/extension_accessibility_api_constants.cc
+++ b/chrome/browser/extensions/extension_accessibility_api_constants.cc
@@ -7,17 +7,17 @@
namespace extension_accessibility_api_constants {
// String keys for AccessibilityObject properties.
-const wchar_t kTypeKey[] = L"type";
-const wchar_t kNameKey[] = L"name";
-const wchar_t kDetailsKey[] = L"details";
-const wchar_t kValueKey[] = L"details.value";
-const wchar_t kPasswordKey[] = L"details.isPassword";
-const wchar_t kItemCountKey[] = L"details.itemCount";
-const wchar_t kItemIndexKey[] = L"details.itemIndex";
-const wchar_t kSelectionStartKey[] = L"details.selectionStart";
-const wchar_t kSelectionEndKey[] = L"details.selectionEnd";
-const wchar_t kCheckedKey[] = L"details.isChecked";
-const wchar_t kHasSubmenuKey[] = L"details.hasSubmenu";
+const char kTypeKey[] = "type";
+const char kNameKey[] = "name";
+const char kDetailsKey[] = "details";
+const char kValueKey[] = "details.value";
+const char kPasswordKey[] = "details.isPassword";
+const char kItemCountKey[] = "details.itemCount";
+const char kItemIndexKey[] = "details.itemIndex";
+const char kSelectionStartKey[] = "details.selectionStart";
+const char kSelectionEndKey[] = "details.selectionEnd";
+const char kCheckedKey[] = "details.isChecked";
+const char kHasSubmenuKey[] = "details.hasSubmenu";
// Events.
const char kOnWindowOpened[] = "experimental.accessibility.onWindowOpened";
diff --git a/chrome/browser/extensions/extension_accessibility_api_constants.h b/chrome/browser/extensions/extension_accessibility_api_constants.h
index c5ce6c8..ce02a7e 100644
--- a/chrome/browser/extensions/extension_accessibility_api_constants.h
+++ b/chrome/browser/extensions/extension_accessibility_api_constants.h
@@ -6,21 +6,22 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ACCESSIBILITY_API_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_ACCESSIBILITY_API_CONSTANTS_H_
+#pragma once
namespace extension_accessibility_api_constants {
// Keys.
-extern const wchar_t kTypeKey[];
-extern const wchar_t kNameKey[];
-extern const wchar_t kDetailsKey[];
-extern const wchar_t kValueKey[];
-extern const wchar_t kPasswordKey[];
-extern const wchar_t kItemCountKey[];
-extern const wchar_t kItemIndexKey[];
-extern const wchar_t kSelectionStartKey[];
-extern const wchar_t kSelectionEndKey[];
-extern const wchar_t kCheckedKey[];
-extern const wchar_t kHasSubmenuKey[];
+extern const char kTypeKey[];
+extern const char kNameKey[];
+extern const char kDetailsKey[];
+extern const char kValueKey[];
+extern const char kPasswordKey[];
+extern const char kItemCountKey[];
+extern const char kItemIndexKey[];
+extern const char kSelectionStartKey[];
+extern const char kSelectionEndKey[];
+extern const char kCheckedKey[];
+extern const char kHasSubmenuKey[];
// Events.
extern const char kOnWindowOpened[];
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index cc16957..7ef7c1a 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -1,29 +1,39 @@
-// 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.
#include "chrome/browser/extensions/extension_apitest.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/test/ui_test_utils.h"
-ExtensionApiTest::ResultCatcher::ResultCatcher() {
+ExtensionApiTest::ResultCatcher::ResultCatcher()
+ : profile_restriction_(NULL),
+ waiting_(false) {
registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED,
NotificationService::AllSources());
}
+ExtensionApiTest::ResultCatcher::~ResultCatcher() {
+}
+
bool ExtensionApiTest::ResultCatcher::GetNextResult() {
// Depending on the tests, multiple results can come in from a single call
// to RunMessageLoop(), so we maintain a queue of results and just pull them
// off as the test calls this, going to the run loop only when the queue is
// empty.
- if (results_.empty())
+ if (results_.empty()) {
+ waiting_ = true;
ui_test_utils::RunMessageLoop();
+ waiting_ = false;
+ }
if (!results_.empty()) {
bool ret = results_.front();
@@ -40,19 +50,26 @@ bool ExtensionApiTest::ResultCatcher::GetNextResult() {
void ExtensionApiTest::ResultCatcher::Observe(
NotificationType type, const NotificationSource& source,
const NotificationDetails& details) {
+ if (profile_restriction_ &&
+ Source<Profile>(source).ptr() != profile_restriction_) {
+ return;
+ }
+
switch (type.value) {
case NotificationType::EXTENSION_TEST_PASSED:
std::cout << "Got EXTENSION_TEST_PASSED notification.\n";
results_.push_back(true);
messages_.push_back("");
- MessageLoopForUI::current()->Quit();
+ if (waiting_)
+ MessageLoopForUI::current()->Quit();
break;
case NotificationType::EXTENSION_TEST_FAILED:
std::cout << "Got EXTENSION_TEST_FAILED notification.\n";
results_.push_back(false);
messages_.push_back(*(Details<std::string>(details).ptr()));
- MessageLoopForUI::current()->Quit();
+ if (waiting_)
+ MessageLoopForUI::current()->Quit();
break;
default:
@@ -60,14 +77,65 @@ void ExtensionApiTest::ResultCatcher::Observe(
}
}
-// Load an extension and wait for it to notify of PASSED or FAILED.
bool ExtensionApiTest::RunExtensionTest(const char* extension_name) {
+ return RunExtensionTestImpl(extension_name, "", false);
+}
+
+bool ExtensionApiTest::RunExtensionTestIncognito(const char* extension_name) {
+ return RunExtensionTestImpl(extension_name, "", true);
+}
+
+bool ExtensionApiTest::RunExtensionSubtest(const char* extension_name,
+ const std::string& page_url) {
+ DCHECK(!page_url.empty()) << "Argument page_url is required.";
+ return RunExtensionTestImpl(extension_name, page_url, false);
+}
+
+bool ExtensionApiTest::RunPageTest(const std::string& page_url) {
+ return RunExtensionSubtest("", page_url);
+}
+
+// Load |extension_name| extension and/or |page_url| and wait for
+// PASSED or FAILED notification.
+bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
+ const std::string& page_url,
+ bool enable_incognito) {
ResultCatcher catcher;
+ DCHECK(!std::string(extension_name).empty() || !page_url.empty()) <<
+ "extension_name and page_url cannot both be empty";
+
+ if (!std::string(extension_name).empty()) {
+ bool loaded = enable_incognito ?
+ LoadExtensionIncognito(test_data_dir_.AppendASCII(extension_name)) :
+ LoadExtension(test_data_dir_.AppendASCII(extension_name));
+ if (!loaded) {
+ message_ = "Failed to load extension.";
+ return false;
+ }
+ }
- LOG(INFO) << "Running ExtensionApiTest with: " << extension_name;
- if (!LoadExtension(test_data_dir_.AppendASCII(extension_name))) {
- message_ = "Failed to load extension.";
- return false;
+ // If there is a page_url to load, navigate it.
+ if (!page_url.empty()) {
+ GURL url = GURL(page_url);
+
+ // Note: We use is_valid() here in the expectation that the provided url
+ // may lack a scheme & host and thus be a relative url within the loaded
+ // extension.
+ if (!url.is_valid()) {
+ DCHECK(!std::string(extension_name).empty()) <<
+ "Relative page_url given with no extension_name";
+
+ ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ Extension* extension =
+ service->GetExtensionById(last_loaded_extension_id_, false);
+ if (!extension)
+ return false;
+
+ url = extension->GetResourceURL(page_url);
+ }
+
+ LOG(ERROR) << "Loading page url: " << url.spec();
+ ui_test_utils::NavigateToURL(browser(), url);
}
if (!catcher.GetNextResult()) {
@@ -90,7 +158,7 @@ Extension* ExtensionApiTest::GetSingleLoadedExtension() {
continue;
if (found_extension_index != -1) {
- message_ = StringPrintf(
+ message_ = base::StringPrintf(
"Expected only one extension to be present. Found %u.",
static_cast<unsigned>(service->extensions()->size()));
return NULL;
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h
index bd05fe5..194750d 100644
--- a/chrome/browser/extensions/extension_apitest.h
+++ b/chrome/browser/extensions/extension_apitest.h
@@ -4,6 +4,10 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_
+#pragma once
+
+#include <deque>
+#include <string>
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/common/notification_service.h"
@@ -29,11 +33,14 @@ class ExtensionApiTest : public ExtensionBrowserTest {
class ResultCatcher : public NotificationObserver {
public:
ResultCatcher();
+ ~ResultCatcher();
// Pumps the UI loop until a notification is received that an API test
// succeeded or failed. Returns true if the test succeeded, false otherwise.
bool GetNextResult();
+ void RestrictToProfile(Profile* profile) { profile_restriction_ = profile; }
+
const std::string& message() { return message_; }
private:
@@ -49,12 +56,34 @@ class ExtensionApiTest : public ExtensionBrowserTest {
// If it failed, what was the error message?
std::deque<std::string> messages_;
std::string message_;
+
+ // If non-NULL, we will listen to events from this profile only.
+ Profile* profile_restriction_;
+
+ // True if we're in a nested message loop waiting for results from
+ // the extension.
+ bool waiting_;
};
// Load |extension_name| and wait for pass / fail notification.
// |extension_name| is a directory in "test/data/extensions/api_test".
bool RunExtensionTest(const char* extension_name);
+ // Same as RunExtensionTest, but enables the extension for incognito mode.
+ bool RunExtensionTestIncognito(const char* extension_name);
+
+ // If not empty, Load |extension_name|, load |page_url| and wait for pass /
+ // fail notification from the extension API on the page. Note that if
+ // |page_url| is not a valid url, it will be treated as a resource within
+ // the extension. |extension_name| is a directory in
+ // "test/data/extensions/api_test".
+ bool RunExtensionSubtest(const char* extension_name,
+ const std::string& page_url);
+
+ // Load |page_url| and wait for pass / fail notification from the extension
+ // API on the page.
+ bool RunPageTest(const std::string& page_url);
+
// Test that exactly one extension loaded. If so, return a pointer to
// the extension. If not, return NULL and set message_.
Extension* GetSingleLoadedExtension();
@@ -64,6 +93,11 @@ class ExtensionApiTest : public ExtensionBrowserTest {
// If it failed, what was the error message?
std::string message_;
+
+ private:
+ bool RunExtensionTestImpl(const char* extension_name,
+ const std::string& test_page,
+ bool enable_incogntio);
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_APITEST_H_
diff --git a/chrome/browser/extensions/extension_bookmark_helpers.cc b/chrome/browser/extensions/extension_bookmark_helpers.cc
index f648a5e..ad7cbb0 100644
--- a/chrome/browser/extensions/extension_bookmark_helpers.cc
+++ b/chrome/browser/extensions/extension_bookmark_helpers.cc
@@ -4,7 +4,9 @@
#include "chrome/browser/extensions/extension_bookmark_helpers.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/extensions/extension_bookmarks_module_constants.h"
namespace keys = extension_bookmarks_module_constants;
@@ -16,11 +18,11 @@ DictionaryValue* GetNodeDictionary(const BookmarkNode* node,
bool recurse,
bool only_folders) {
DictionaryValue* dict = new DictionaryValue();
- dict->SetString(keys::kIdKey, Int64ToString(node->id()));
+ dict->SetString(keys::kIdKey, base::Int64ToString(node->id()));
const BookmarkNode* parent = node->GetParent();
if (parent) {
- dict->SetString(keys::kParentIdKey, Int64ToString(parent->id()));
+ dict->SetString(keys::kParentIdKey, base::Int64ToString(parent->id()));
dict->SetInteger(keys::kIndexKey, parent->IndexOfChild(node));
}
diff --git a/chrome/browser/extensions/extension_bookmark_helpers.h b/chrome/browser/extensions/extension_bookmark_helpers.h
index f58db22..5b0a381 100644
--- a/chrome/browser/extensions/extension_bookmark_helpers.h
+++ b/chrome/browser/extensions/extension_bookmark_helpers.h
@@ -4,9 +4,16 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_HELPERS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_HELPERS_H_
+#pragma once
-#include "base/values.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
+#include <string>
+
+#include "base/basictypes.h"
+
+class BookmarkModel;
+class BookmarkNode;
+class DictionaryValue;
+class ListValue;
// Helper functions.
namespace extension_bookmark_helpers {
@@ -16,9 +23,7 @@ DictionaryValue* GetNodeDictionary(const BookmarkNode* node,
bool only_folders);
// Add a JSON representation of |node| to the JSON |list|.
-void AddNode(const BookmarkNode* node,
- ListValue* list,
- bool recurse);
+void AddNode(const BookmarkNode* node, ListValue* list, bool recurse);
void AddNodeFoldersOnly(const BookmarkNode* node,
ListValue* list,
@@ -29,6 +34,6 @@ bool RemoveNode(BookmarkModel* model,
bool recursive,
std::string* error);
-}
+} // namespace extension_bookmark_helpers
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARKS_HELPERS_H_
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_HELPERS_H_
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc
index 9b796d2..0b0dc0f 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.cc
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc
@@ -8,7 +8,7 @@
#include "app/l10n_util.h"
#include "base/json/json_writer.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -35,7 +35,7 @@ const BookmarkNode* GetNodeFromArguments(BookmarkModel* model,
if (!args->GetString(0, &id_string))
return NULL;
int64 id;
- if (!StringToInt64(id_string, &id))
+ if (!base::StringToInt64(id_string, &id))
return NULL;
return model->GetNodeByID(id);
}
@@ -58,7 +58,7 @@ bool GetNodesFromArguments(BookmarkModel* model, const ListValue* args,
if (!ids->GetString(i, &id_string))
return false;
int64 id;
- if (!StringToInt64(id_string, &id))
+ if (!base::StringToInt64(id_string, &id))
return false;
const BookmarkNode* node = model->GetNodeByID(id);
if (!node)
@@ -77,10 +77,10 @@ void AddNodeToList(ListValue* list, const BookmarkNode& node) {
// Add id and parentId so we can associate the data with existing nodes on the
// client side.
- std::string id_string = Int64ToString(node.id());
+ std::string id_string = base::Int64ToString(node.id());
dict->SetString(keys::kIdKey, id_string);
- std::string parent_id_string = Int64ToString(node.GetParent()->id());
+ std::string parent_id_string = base::Int64ToString(node.GetParent()->id());
dict->SetString(keys::kParentIdKey, parent_id_string);
if (node.is_url())
@@ -106,7 +106,7 @@ void AddElementToList(ListValue* list,
if (element.is_url)
dict->SetString(keys::kUrlKey, element.url.spec());
- dict->SetString(keys::kTitleKey, UTF16ToWide(element.title));
+ dict->SetString(keys::kTitleKey, element.title);
ListValue* children = new ListValue();
for (size_t i = 0; i < element.children.size(); ++i)
@@ -161,7 +161,7 @@ void ExtensionBookmarkManagerEventRouter::DispatchEvent(const char* event_name,
std::string json_args;
base::JSONWriter::Write(args, false, &json_args);
profile_->GetExtensionMessageService()->DispatchEventToRenderers(
- event_name, json_args, profile_->IsOffTheRecord(), GURL());
+ event_name, json_args, profile_, GURL());
}
void ExtensionBookmarkManagerEventRouter::DispatchDragEvent(
@@ -268,66 +268,66 @@ bool SortChildrenBookmarkManagerFunction::RunImpl() {
bool BookmarkManagerGetStringsFunction::RunImpl() {
DictionaryValue* localized_strings = new DictionaryValue();
- localized_strings->SetString(L"title",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_TITLE));
- localized_strings->SetString(L"search_button",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON));
- localized_strings->SetString(L"show_in_folder",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
- localized_strings->SetString(L"sort",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_SORT));
- localized_strings->SetString(L"organize_menu",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU));
- localized_strings->SetString(L"tools_menu",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_TOOLS_MENU));
- localized_strings->SetString(L"import_menu",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
- localized_strings->SetString(L"export_menu",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
- localized_strings->SetString(L"rename_folder",
- l10n_util::GetString(IDS_BOOKMARK_BAR_RENAME_FOLDER));
- localized_strings->SetString(L"edit",
- l10n_util::GetString(IDS_BOOKMARK_BAR_EDIT));
- localized_strings->SetString(L"should_open_all",
- l10n_util::GetString(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL));
- localized_strings->SetString(L"open_incognito",
- l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_INCOGNITO));
- localized_strings->SetString(L"open_in_new_tab",
- l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB));
- localized_strings->SetString(L"open_in_new_window",
- l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW));
- localized_strings->SetString(L"add_new_bookmark",
- l10n_util::GetString(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
- localized_strings->SetString(L"new_folder",
- l10n_util::GetString(IDS_BOOMARK_BAR_NEW_FOLDER));
- localized_strings->SetString(L"open_all",
- l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_ALL));
- localized_strings->SetString(L"open_all_new_window",
- l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- localized_strings->SetString(L"open_all_incognito",
- l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- localized_strings->SetString(L"remove",
- l10n_util::GetString(IDS_BOOKMARK_BAR_REMOVE));
- localized_strings->SetString(L"copy",
- l10n_util::GetString(IDS_CONTENT_CONTEXT_COPY));
- localized_strings->SetString(L"cut",
- l10n_util::GetString(IDS_CONTENT_CONTEXT_CUT));
- localized_strings->SetString(L"paste",
- l10n_util::GetString(IDS_CONTENT_CONTEXT_PASTE));
- localized_strings->SetString(L"delete",
- l10n_util::GetString(IDS_CONTENT_CONTEXT_DELETE));
- localized_strings->SetString(L"new_folder_name",
- l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME));
- localized_strings->SetString(L"name_input_placeholder",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER));
- localized_strings->SetString(L"url_input_placeholder",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER));
- localized_strings->SetString(L"invalid_url",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_INVALID_URL));
- localized_strings->SetString(L"recent",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_RECENT));
- localized_strings->SetString(L"search",
- l10n_util::GetString(IDS_BOOKMARK_MANAGER_SEARCH));
+ localized_strings->SetString("title",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TITLE));
+ localized_strings->SetString("search_button",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH_BUTTON));
+ localized_strings->SetString("show_in_folder",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ localized_strings->SetString("sort",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SORT));
+ localized_strings->SetString("organize_menu",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU));
+ localized_strings->SetString("tools_menu",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_TOOLS_MENU));
+ localized_strings->SetString("import_menu",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_IMPORT_MENU));
+ localized_strings->SetString("export_menu",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_EXPORT_MENU));
+ localized_strings->SetString("rename_folder",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_RENAME_FOLDER));
+ localized_strings->SetString("edit",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_EDIT));
+ localized_strings->SetString("should_open_all",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL));
+ localized_strings->SetString("open_incognito",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_INCOGNITO));
+ localized_strings->SetString("open_in_new_tab",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB));
+ localized_strings->SetString("open_in_new_window",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW));
+ localized_strings->SetString("add_new_bookmark",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ localized_strings->SetString("new_folder",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_NEW_FOLDER));
+ localized_strings->SetString("open_all",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_ALL));
+ localized_strings->SetString("open_all_new_window",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ localized_strings->SetString("open_all_incognito",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ localized_strings->SetString("remove",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_REMOVE));
+ localized_strings->SetString("copy",
+ l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_COPY));
+ localized_strings->SetString("cut",
+ l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_CUT));
+ localized_strings->SetString("paste",
+ l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PASTE));
+ localized_strings->SetString("delete",
+ l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_DELETE));
+ localized_strings->SetString("new_folder_name",
+ l10n_util::GetStringUTF16(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME));
+ localized_strings->SetString("name_input_placeholder",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER));
+ localized_strings->SetString("url_input_placeholder",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER));
+ localized_strings->SetString("invalid_url",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_INVALID_URL));
+ localized_strings->SetString("recent",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_RECENT));
+ localized_strings->SetString("search",
+ l10n_util::GetStringUTF16(IDS_BOOKMARK_MANAGER_SEARCH));
ChromeURLDataManager::DataSource::SetFontAndTextDirection(localized_strings);
@@ -363,7 +363,7 @@ bool DropBookmarkManagerFunction::RunImpl() {
std::string id_string;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_string));
- if (!StringToInt64(id_string, &id)) {
+ if (!base::StringToInt64(id_string, &id)) {
error_ = keys::kInvalidIdError;
return false;
}
@@ -417,7 +417,7 @@ bool GetSubtreeBookmarkManagerFunction::RunImpl() {
if (id_string == "") {
node = model->root_node();
} else {
- if (!StringToInt64(id_string, &id)) {
+ if (!base::StringToInt64(id_string, &id)) {
error_ = keys::kInvalidIdError;
return false;
}
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.h b/chrome/browser/extensions/extension_bookmark_manager_api.h
index ace9124..c129bd3 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.h
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_MANAGER_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARK_MANAGER_API_H_
+#pragma once
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/extensions/extension_bookmarks_module.h"
@@ -11,7 +12,6 @@
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
struct BookmarkDragData;
-class BookmarkNode;
class ListValue;
class Profile;
class TabContents;
diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc
index 0eb7a30..4044bfc 100644
--- a/chrome/browser/extensions/extension_bookmarks_module.cc
+++ b/chrome/browser/extensions/extension_bookmarks_module.cc
@@ -7,7 +7,9 @@
#include "base/json/json_writer.h"
#include "base/sha1.h"
#include "base/stl_util-inl.h"
-#include "base/string_util.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_html_writer.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -19,7 +21,7 @@
#include "chrome/browser/extensions/extensions_quota_service.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/pref_service.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"
@@ -56,7 +58,7 @@ void BookmarksFunction::Run() {
bool BookmarksFunction::GetBookmarkIdAsInt64(
const std::string& id_string, int64* id) {
- if (StringToInt64(id_string, id))
+ if (base::StringToInt64(id_string, id))
return true;
error_ = keys::kInvalidIdError;
@@ -95,7 +97,7 @@ void ExtensionBookmarkEventRouter::DispatchEvent(Profile *profile,
const std::string json_args) {
if (profile->GetExtensionMessageService()) {
profile->GetExtensionMessageService()->DispatchEventToRenderers(
- event_name, json_args, profile->IsOffTheRecord(), GURL());
+ event_name, json_args, profile, GURL());
}
}
@@ -112,12 +114,13 @@ void ExtensionBookmarkEventRouter::BookmarkNodeMoved(
int new_index) {
ListValue args;
const BookmarkNode* node = new_parent->GetChild(new_index);
- args.Append(new StringValue(Int64ToString(node->id())));
+ args.Append(new StringValue(base::Int64ToString(node->id())));
DictionaryValue* object_args = new DictionaryValue();
- object_args->SetString(keys::kParentIdKey, Int64ToString(new_parent->id()));
+ object_args->SetString(keys::kParentIdKey,
+ base::Int64ToString(new_parent->id()));
object_args->SetInteger(keys::kIndexKey, new_index);
object_args->SetString(keys::kOldParentIdKey,
- Int64ToString(old_parent->id()));
+ base::Int64ToString(old_parent->id()));
object_args->SetInteger(keys::kOldIndexKey, old_index);
args.Append(object_args);
@@ -131,7 +134,7 @@ void ExtensionBookmarkEventRouter::BookmarkNodeAdded(BookmarkModel* model,
int index) {
ListValue args;
const BookmarkNode* node = parent->GetChild(index);
- args.Append(new StringValue(Int64ToString(node->id())));
+ args.Append(new StringValue(base::Int64ToString(node->id())));
DictionaryValue* obj =
extension_bookmark_helpers::GetNodeDictionary(node, false, false);
args.Append(obj);
@@ -147,9 +150,10 @@ void ExtensionBookmarkEventRouter::BookmarkNodeRemoved(
int index,
const BookmarkNode* node) {
ListValue args;
- args.Append(new StringValue(Int64ToString(node->id())));
+ args.Append(new StringValue(base::Int64ToString(node->id())));
DictionaryValue* object_args = new DictionaryValue();
- object_args->SetString(keys::kParentIdKey, Int64ToString(parent->id()));
+ object_args->SetString(keys::kParentIdKey,
+ base::Int64ToString(parent->id()));
object_args->SetInteger(keys::kIndexKey, index);
args.Append(object_args);
@@ -161,7 +165,7 @@ void ExtensionBookmarkEventRouter::BookmarkNodeRemoved(
void ExtensionBookmarkEventRouter::BookmarkNodeChanged(
BookmarkModel* model, const BookmarkNode* node) {
ListValue args;
- args.Append(new StringValue(Int64ToString(node->id())));
+ args.Append(new StringValue(base::Int64ToString(node->id())));
// TODO(erikkay) The only three things that BookmarkModel sends this
// notification for are title, url and favicon. Since we're currently
@@ -187,12 +191,12 @@ void ExtensionBookmarkEventRouter::BookmarkNodeFavIconLoaded(
void ExtensionBookmarkEventRouter::BookmarkNodeChildrenReordered(
BookmarkModel* model, const BookmarkNode* node) {
ListValue args;
- args.Append(new StringValue(Int64ToString(node->id())));
+ args.Append(new StringValue(base::Int64ToString(node->id())));
int childCount = node->GetChildCount();
ListValue* children = new ListValue();
for (int i = 0; i < childCount; ++i) {
const BookmarkNode* child = node->GetChild(i);
- Value* child_id = new StringValue(Int64ToString(child->id()));
+ Value* child_id = new StringValue(base::Int64ToString(child->id()));
children->Append(child_id);
}
DictionaryValue* reorder_info = new DictionaryValue();
@@ -318,13 +322,12 @@ bool GetBookmarkTreeFunction::RunImpl() {
}
bool SearchBookmarksFunction::RunImpl() {
- std::wstring query;
+ string16 query;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &query));
BookmarkModel* model = profile()->GetBookmarkModel();
ListValue* json = new ListValue();
- std::wstring lang =
- UTF8ToWide(profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ std::string lang = profile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
std::vector<const BookmarkNode*> nodes;
bookmark_utils::GetBookmarksContainingText(model, query,
std::numeric_limits<int>::max(),
@@ -347,7 +350,7 @@ bool RemoveBookmarkFunction::ExtractIds(const ListValue* args,
if (!args->GetString(0, &id_string))
return false;
int64 id;
- if (StringToInt64(id_string, &id))
+ if (base::StringToInt64(id_string, &id))
ids->push_back(id);
else
*invalid_id = true;
@@ -414,7 +417,7 @@ bool CreateBookmarkFunction::RunImpl() {
}
}
- std::wstring title;
+ string16 title;
json->GetString(keys::kTitleKey, &title); // Optional.
std::string url_string;
json->GetString(keys::kUrlKey, &url_string); // Optional.
@@ -542,7 +545,7 @@ bool UpdateBookmarkFunction::RunImpl() {
DictionaryValue* updates;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &updates));
- std::wstring title;
+ string16 title;
std::string url_string;
// Optional but we need to distinguish non present from an empty title.
@@ -618,17 +621,20 @@ class CreateBookmarkBucketMapper : public BookmarkBucketMapper<std::string> {
return;
}
BookmarkModel* model = profile_->GetBookmarkModel();
- const BookmarkNode* parent = model->GetNodeByID(StringToInt64(parent_id));
+
+ int64 parent_id_int64;
+ base::StringToInt64(parent_id, &parent_id_int64);
+ const BookmarkNode* parent = model->GetNodeByID(parent_id_int64);
if (!parent)
return;
- std::string bucket_id = WideToUTF8(parent->GetTitle());
- std::wstring title;
+ std::string bucket_id = UTF16ToUTF8(parent->GetTitle());
+ std::string title;
json->GetString(keys::kTitleKey, &title);
std::string url_string;
json->GetString(keys::kUrlKey, &url_string);
- bucket_id += WideToUTF8(title);
+ bucket_id += title;
bucket_id += url_string;
// 20 bytes (SHA1 hash length) is very likely less than most of the
// |bucket_id| strings we construct here, so we hash it to save space.
@@ -658,8 +664,8 @@ class RemoveBookmarksBucketMapper : public BookmarkBucketMapper<std::string> {
return;
std::string bucket_id;
- bucket_id += WideToUTF8(node->GetParent()->GetTitle());
- bucket_id += WideToUTF8(node->GetTitle());
+ bucket_id += UTF16ToUTF8(node->GetParent()->GetTitle());
+ bucket_id += UTF16ToUTF8(node->GetTitle());
bucket_id += node->GetURL().spec();
buckets->push_back(GetBucket(base::SHA1HashString(bucket_id)));
}
diff --git a/chrome/browser/extensions/extension_bookmarks_module.h b/chrome/browser/extensions/extension_bookmarks_module.h
index 1a26b02..27c2111 100644
--- a/chrome/browser/extensions/extension_bookmarks_module.h
+++ b/chrome/browser/extensions/extension_bookmarks_module.h
@@ -1,17 +1,20 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARKS_MODULE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARKS_MODULE_H_
+#pragma once
#include <list>
+#include <set>
#include <string>
#include "base/singleton.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/shell_dialogs.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
// Observes BookmarkModel and then routes the notifications as events to
diff --git a/chrome/browser/extensions/extension_bookmarks_module_constants.cc b/chrome/browser/extensions/extension_bookmarks_module_constants.cc
index 0fcb74b..670b5ec 100644
--- a/chrome/browser/extensions/extension_bookmarks_module_constants.cc
+++ b/chrome/browser/extensions/extension_bookmarks_module_constants.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.
@@ -6,21 +6,21 @@
namespace extension_bookmarks_module_constants {
-const wchar_t kIdKey[] = L"id";
-const wchar_t kIndexKey[] = L"index";
-const wchar_t kParentIdKey[] = L"parentId";
-const wchar_t kOldIndexKey[] = L"oldIndex";
-const wchar_t kOldParentIdKey[] = L"oldParentId";
-const wchar_t kUrlKey[] = L"url";
-const wchar_t kTitleKey[] = L"title";
-const wchar_t kChildrenKey[] = L"children";
-const wchar_t kChildIdsKey[] = L"childIds";
-const wchar_t kRecursiveKey[] = L"recursive";
-const wchar_t kDateAddedKey[] = L"dateAdded";
-const wchar_t kDateGroupModifiedKey[] = L"dateGroupModified";
+const char kIdKey[] = "id";
+const char kIndexKey[] = "index";
+const char kParentIdKey[] = "parentId";
+const char kOldIndexKey[] = "oldIndex";
+const char kOldParentIdKey[] = "oldParentId";
+const char kUrlKey[] = "url";
+const char kTitleKey[] = "title";
+const char kChildrenKey[] = "children";
+const char kChildIdsKey[] = "childIds";
+const char kRecursiveKey[] = "recursive";
+const char kDateAddedKey[] = "dateAdded";
+const char kDateGroupModifiedKey[] = "dateGroupModified";
// TODO(arv): Move bookmark manager related constants out of this file.
-const wchar_t kSameProfileKey[] = L"sameProfile";
-const wchar_t kElementsKey[] = L"elements";
+const char kSameProfileKey[] = "sameProfile";
+const char kElementsKey[] = "elements";
const char kNoNodeError[] = "Can't find bookmark for id.";
const char kNoParentError[] = "Can't find parent bookmark for id.";
diff --git a/chrome/browser/extensions/extension_bookmarks_module_constants.h b/chrome/browser/extensions/extension_bookmarks_module_constants.h
index 582866b..27de3a0 100644
--- a/chrome/browser/extensions/extension_bookmarks_module_constants.h
+++ b/chrome/browser/extensions/extension_bookmarks_module_constants.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,25 +6,26 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARKS_MODULE_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BOOKMARKS_MODULE_CONSTANTS_H_
+#pragma once
namespace extension_bookmarks_module_constants {
// Keys.
-extern const wchar_t kIdKey[];
-extern const wchar_t kIndexKey[];
-extern const wchar_t kParentIdKey[];
-extern const wchar_t kOldIndexKey[];
-extern const wchar_t kOldParentIdKey[];
-extern const wchar_t kUrlKey[];
-extern const wchar_t kTitleKey[];
-extern const wchar_t kChildrenKey[];
-extern const wchar_t kChildIdsKey[];
-extern const wchar_t kRecursiveKey[];
-extern const wchar_t kDateAddedKey[];
-extern const wchar_t kDateGroupModifiedKey[];
+extern const char kIdKey[];
+extern const char kIndexKey[];
+extern const char kParentIdKey[];
+extern const char kOldIndexKey[];
+extern const char kOldParentIdKey[];
+extern const char kUrlKey[];
+extern const char kTitleKey[];
+extern const char kChildrenKey[];
+extern const char kChildIdsKey[];
+extern const char kRecursiveKey[];
+extern const char kDateAddedKey[];
+extern const char kDateGroupModifiedKey[];
// TODO(arv): Move bookmark manager related constants out of this file.
-extern const wchar_t kSameProfileKey[];
-extern const wchar_t kElementsKey[];
+extern const char kSameProfileKey[];
+extern const char kElementsKey[];
// Errors.
extern const char kNoNodeError[];
diff --git a/chrome/browser/extensions/extension_bookmarks_unittest.cc b/chrome/browser/extensions/extension_bookmarks_unittest.cc
index 4b1070e..2381c91 100644
--- a/chrome/browser/extensions/extension_bookmarks_unittest.cc
+++ b/chrome/browser/extensions/extension_bookmarks_unittest.cc
@@ -4,6 +4,7 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/extensions/extension_bookmark_helpers.h"
@@ -14,66 +15,66 @@ class ExtensionBookmarksTest : public testing::Test {
public:
virtual void SetUp() {
model_.reset(new BookmarkModel(NULL));
- model_->AddURL(model_->other_node(), 0, L"Digg",
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("Digg"),
GURL("http://www.reddit.com"));
- model_->AddURL(model_->other_node(), 0, L"News",
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("News"),
GURL("http://www.foxnews.com"));
folder =
- model_->AddGroup(model_->other_node(), 0, L"outer folder");
- model_->AddGroup(folder, 0, L"inner folder 1");
- model_->AddGroup(folder, 0, L"inner folder 2");
- model_->AddURL(folder, 0, L"Digg", GURL("http://reddit.com"));
- model_->AddURL(folder, 0, L"CNet", GURL("http://cnet.com"));
+ model_->AddGroup(model_->other_node(), 0, ASCIIToUTF16("outer folder"));
+ model_->AddGroup(folder, 0, ASCIIToUTF16("inner folder 1"));
+ model_->AddGroup(folder, 0, ASCIIToUTF16("inner folder 2"));
+ model_->AddURL(folder, 0, ASCIIToUTF16("Digg"), GURL("http://reddit.com"));
+ model_->AddURL(folder, 0, ASCIIToUTF16("CNet"), GURL("http://cnet.com"));
}
-
+
scoped_ptr<BookmarkModel> model_;
const BookmarkNode* folder;
};
TEST_F(ExtensionBookmarksTest, GetFullTreeFromRoot) {
- DictionaryValue* tree =
- extension_bookmark_helpers::GetNodeDictionary(model_->other_node(),
- true, // recurse
- false); // not only folders
+ DictionaryValue* tree = extension_bookmark_helpers::GetNodeDictionary(
+ model_->other_node(),
+ true, // Recurse.
+ false); // Not only folders.
ListValue* children;
tree->GetList(keys::kChildrenKey, &children);
ASSERT_EQ(3U, children->GetSize());
}
TEST_F(ExtensionBookmarksTest, GetFoldersOnlyFromRoot) {
- DictionaryValue* tree =
- extension_bookmark_helpers::GetNodeDictionary(model_->other_node(),
- true, // recurse
- true); // only folders
+ DictionaryValue* tree = extension_bookmark_helpers::GetNodeDictionary(
+ model_->other_node(),
+ true, // Recurse.
+ true); // Only folders.
ListValue* children;
tree->GetList(keys::kChildrenKey, &children);
ASSERT_EQ(1U, children->GetSize());
}
TEST_F(ExtensionBookmarksTest, GetSubtree) {
- DictionaryValue* tree =
- extension_bookmark_helpers::GetNodeDictionary(folder,
- true, // recurse
- false); // not only folders
+ DictionaryValue* tree = extension_bookmark_helpers::GetNodeDictionary(
+ folder,
+ true, // Recurse.
+ false); // Not only folders.
ListValue* children;
tree->GetList(keys::kChildrenKey, &children);
ASSERT_EQ(4U, children->GetSize());
DictionaryValue* digg;
- children->GetDictionary(1,&digg);
+ ASSERT_TRUE(children->GetDictionary(1, &digg));
std::string title;
digg->GetString(keys::kTitleKey, &title);
ASSERT_EQ("Digg", title);
}
TEST_F(ExtensionBookmarksTest, GetSubtreeFoldersOnly) {
- DictionaryValue* tree =
- extension_bookmark_helpers::GetNodeDictionary(folder,
- true, // recurse
- true); // only folders
+ DictionaryValue* tree = extension_bookmark_helpers::GetNodeDictionary(
+ folder,
+ true, // Recurse.
+ true); // Only folders.
ListValue* children;
tree->GetList(keys::kChildrenKey, &children);
ASSERT_EQ(2U, children->GetSize());
DictionaryValue* inner_folder;
- children->GetDictionary(1,&inner_folder);
+ ASSERT_TRUE(children->GetDictionary(1, &inner_folder));
std::string title;
inner_folder->GetString(keys::kTitleKey, &title);
ASSERT_EQ("inner folder 1", title);
diff --git a/chrome/browser/extensions/extension_browser_actions_api.cc b/chrome/browser/extensions/extension_browser_actions_api.cc
index dfcf2ad..1ce4dfe 100644
--- a/chrome/browser/extensions/extension_browser_actions_api.cc
+++ b/chrome/browser/extensions/extension_browser_actions_api.cc
@@ -1,9 +1,10 @@
-// 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.
#include "chrome/browser/extensions/extension_browser_actions_api.h"
+#include "base/values.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/common/extensions/extension.h"
@@ -22,8 +23,8 @@ bool BrowserActionFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details_));
EXTENSION_FUNCTION_VALIDATE(details_ != NULL);
- if (details_->HasKey(L"tabId"))
- EXTENSION_FUNCTION_VALIDATE(details_->GetInteger(L"tabId", &tab_id_));
+ if (details_->HasKey("tabId"))
+ EXTENSION_FUNCTION_VALIDATE(details_->GetInteger("tabId", &tab_id_));
Extension* extension = GetExtension();
browser_action_ = extension->browser_action();
@@ -44,7 +45,7 @@ bool BrowserActionFunction::RunImpl() {
bool BrowserActionSetIconFunction::RunBrowserAction() {
BinaryValue* binary = NULL;
- EXTENSION_FUNCTION_VALIDATE(details_->GetBinary(L"imageData", &binary));
+ EXTENSION_FUNCTION_VALIDATE(details_->GetBinary("imageData", &binary));
IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize());
void* iter = NULL;
SkBitmap bitmap;
@@ -56,14 +57,14 @@ bool BrowserActionSetIconFunction::RunBrowserAction() {
bool BrowserActionSetTitleFunction::RunBrowserAction() {
std::string title;
- EXTENSION_FUNCTION_VALIDATE(details_->GetString(L"title", &title));
+ EXTENSION_FUNCTION_VALIDATE(details_->GetString("title", &title));
browser_action_->SetTitle(tab_id_, title);
return true;
}
bool BrowserActionSetPopupFunction::RunBrowserAction() {
std::string popup_string;
- EXTENSION_FUNCTION_VALIDATE(details_->GetString(L"popup", &popup_string));
+ EXTENSION_FUNCTION_VALIDATE(details_->GetString("popup", &popup_string));
GURL popup_url;
if (!popup_string.empty())
@@ -75,14 +76,14 @@ bool BrowserActionSetPopupFunction::RunBrowserAction() {
bool BrowserActionSetBadgeTextFunction::RunBrowserAction() {
std::string badge_text;
- EXTENSION_FUNCTION_VALIDATE(details_->GetString(L"text", &badge_text));
+ EXTENSION_FUNCTION_VALIDATE(details_->GetString("text", &badge_text));
browser_action_->SetBadgeText(tab_id_, badge_text);
return true;
}
bool BrowserActionSetBadgeBackgroundColorFunction::RunBrowserAction() {
ListValue* list = NULL;
- EXTENSION_FUNCTION_VALIDATE(details_->GetList(L"color", &list));
+ EXTENSION_FUNCTION_VALIDATE(details_->GetList("color", &list));
EXTENSION_FUNCTION_VALIDATE(list->GetSize() == 4);
int color_array[4] = {0};
diff --git a/chrome/browser/extensions/extension_browser_actions_api.h b/chrome/browser/extensions/extension_browser_actions_api.h
index c958cb3..c6b2e24 100644
--- a/chrome/browser/extensions/extension_browser_actions_api.h
+++ b/chrome/browser/extensions/extension_browser_actions_api.h
@@ -1,19 +1,24 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSER_ACTIONS_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSER_ACTIONS_API_H_
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/common/extensions/extension_action.h"
+class DictionaryValue;
class ExtensionAction;
// Base class for chrome.browserAction.* APIs.
class BrowserActionFunction : public SyncExtensionFunction {
protected:
- BrowserActionFunction() : tab_id_(ExtensionAction::kDefaultTabId) {}
+ BrowserActionFunction()
+ : details_(NULL),
+ tab_id_(ExtensionAction::kDefaultTabId),
+ browser_action_(NULL) {}
virtual ~BrowserActionFunction() {}
virtual bool RunImpl();
virtual bool RunBrowserAction() = 0;
diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc
index 62d1751..cae6bfd 100644
--- a/chrome/browser/extensions/extension_browser_event_router.cc
+++ b/chrome/browser/extensions/extension_browser_event_router.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_service.h"
@@ -68,7 +69,7 @@ static void DispatchEvent(Profile* profile,
const std::string json_args) {
if (profile->GetExtensionMessageService()) {
profile->GetExtensionMessageService()->DispatchEventToRenderers(
- event_name, json_args, profile->IsOffTheRecord(), GURL());
+ event_name, json_args, profile, GURL());
}
}
@@ -133,7 +134,8 @@ void ExtensionBrowserEventRouter::Init(Profile* profile) {
ExtensionBrowserEventRouter::ExtensionBrowserEventRouter()
: initialized_(false),
- focused_window_id_(extension_misc::kUnknownWindowId) { }
+ focused_window_id_(extension_misc::kUnknownWindowId),
+ profile_(NULL) { }
void ExtensionBrowserEventRouter::OnBrowserAdded(const Browser* browser) {
RegisterForBrowserNotifications(browser);
@@ -170,6 +172,14 @@ void ExtensionBrowserEventRouter::RegisterForTabNotifications(
Source<TabContents>(contents));
}
+void ExtensionBrowserEventRouter::UnregisterForTabNotifications(
+ TabContents* contents) {
+ registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(&contents->controller()));
+ registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(contents));
+}
+
void ExtensionBrowserEventRouter::OnBrowserWindowReady(const Browser* browser) {
ListValue args;
@@ -304,10 +314,7 @@ void ExtensionBrowserEventRouter::TabClosingAt(TabContents* contents,
int removed_count = tab_entries_.erase(tab_id);
DCHECK_GT(removed_count, 0);
- registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&contents->controller()));
- registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(contents));
+ UnregisterForTabNotifications(contents);
}
void ExtensionBrowserEventRouter::TabSelectedAt(TabContents* old_contents,
@@ -419,9 +426,15 @@ void ExtensionBrowserEventRouter::TabChangedAt(TabContents* contents,
void ExtensionBrowserEventRouter::TabReplacedAt(TabContents* old_contents,
TabContents* new_contents,
- int index) {
- // TODO: 32913, consider adding better notification for this event.
- TabInsertedAt(new_contents, index, false);
+ int index,
+ TabReplaceType type) {
+ if (type == REPLACE_MATCH_PREVIEW) {
+ // The ids of the two tabs should remain the same:
+ DCHECK_EQ(old_contents->controller().session_id().id(),
+ new_contents->controller().session_id().id());
+ UnregisterForTabNotifications(old_contents);
+ RegisterForTabNotifications(new_contents);
+ }
}
void ExtensionBrowserEventRouter::TabStripEmpty() {}
diff --git a/chrome/browser/extensions/extension_browser_event_router.h b/chrome/browser/extensions/extension_browser_event_router.h
index bd01080..2c02a1c 100644
--- a/chrome/browser/extensions/extension_browser_event_router.h
+++ b/chrome/browser/extensions/extension_browser_event_router.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSER_EVENT_ROUTER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSER_EVENT_ROUTER_H_
+#pragma once
#include <map>
#include <string>
@@ -12,7 +13,7 @@
#include "base/singleton.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
#include "chrome/common/notification_registrar.h"
#if defined(TOOLKIT_VIEWS)
#include "views/view.h"
@@ -69,7 +70,9 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver,
virtual void TabChangedAt(TabContents* contents, int index,
TabChangeType change_type);
virtual void TabReplacedAt(TabContents* old_contents,
- TabContents* new_contents, int index);
+ TabContents* new_contents,
+ int index,
+ TabReplaceType type);
virtual void TabStripEmpty();
// Page Action execute event.
@@ -114,6 +117,9 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver,
// in for a tab.
void RegisterForTabNotifications(TabContents* contents);
+ // Removes notifications added in RegisterForTabNotifications.
+ void UnregisterForTabNotifications(TabContents* contents);
+
ExtensionBrowserEventRouter();
friend struct DefaultSingletonTraits<ExtensionBrowserEventRouter>;
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index d3494da..05f8cec 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -9,6 +9,7 @@
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/path_service.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/location_bar.h"
@@ -25,12 +26,11 @@
#include "chrome/common/notification_type.h"
#include "chrome/test/ui_test_utils.h"
-#if defined(OS_CHROMEOS)
-#include "chrome/common/chrome_switches.h"
-#endif
-
ExtensionBrowserTest::ExtensionBrowserTest()
- : target_page_action_count_(-1),
+ : loaded_(false),
+ installed_(false),
+ extension_installs_observed_(0),
+ target_page_action_count_(-1),
target_visible_page_action_count_(-1) {
}
@@ -44,21 +44,15 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
test_data_dir_ = test_data_dir_.AppendASCII("extensions");
- // There are a number of tests that still use toolstrips. Rather than
- // selectively enabling each of them, enable toolstrips for all extension
- // tests.
- command_line->AppendSwitch(switches::kEnableExtensionToolstrips);
-
#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
// running on chromeos.
- command_line->AppendSwitchWithValue(
- switches::kLoginUser, "TestUser@gmail.com");
- command_line->AppendSwitchWithValue(switches::kLoginProfile, "user");
+ command_line->AppendSwitchASCII(switches::kLoginUser,
+ "TestUser@gmail.com");
+ command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
command_line->AppendSwitch(switches::kNoFirstRun);
#endif
-
}
bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
@@ -148,8 +142,9 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id,
size_t num_after = service->extensions()->size();
if (num_after != (num_before + expected_change)) {
- std::cout << "Num extensions before: " << IntToString(num_before) << " "
- << "num after: " << IntToString(num_after) << " "
+ std::cout << "Num extensions before: "
+ << base::IntToString(num_before) << " "
+ << "num after: " << base::IntToString(num_after) << " "
<< "Installed extensions follow:\n";
for (size_t i = 0; i < service->extensions()->size(); ++i)
@@ -242,8 +237,6 @@ bool ExtensionBrowserTest::WaitForExtensionHostsToLoad() {
iter = manager->begin();
}
}
- LOG(INFO) << "All ExtensionHosts loaded";
-
return true;
}
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index 567e18c..9b7f5f0 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_BROWSERTEST_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc
index 5e6ba57..9a466bd 100644
--- a/chrome/browser/extensions/extension_browsertests_misc.cc
+++ b/chrome/browser/extensions/extension_browsertests_misc.cc
@@ -2,11 +2,14 @@
// 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/ref_counted.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/extensions/autoupdate_interceptor.h"
+#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_host.h"
@@ -17,16 +20,19 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/views/extensions/extension_shelf.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#endif
+#include "chrome/browser/tabs/tab_strip_model.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"
#include "net/base/net_util.h"
+#include "net/test/test_server.h"
+
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/views/frame/browser_view.h"
+#endif
const std::string kSubscribePage = "/subscribe.html";
const std::string kFeedPage = "files/feeds/feed.html";
@@ -69,109 +75,71 @@ static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager,
return host;
}
-#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
-// See http://crbug.com/30151.
-#define Toolstrip DISABLED_Toolstrip
-#endif
-
-// Tests that toolstrips initializes properly and can run basic extension js.
-IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, Toolstrip) {
- FilePath extension_test_data_dir = test_data_dir_.AppendASCII("good").
- AppendASCII("Extensions").AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj").
- AppendASCII("1.0.0.0");
- ASSERT_TRUE(LoadExtension(extension_test_data_dir));
-
- // At this point, there should be three ExtensionHosts loaded because this
- // extension has two toolstrips and one background page. Find the one that is
- // hosting toolstrip1.html.
- ExtensionProcessManager* manager =
- browser()->profile()->GetExtensionProcessManager();
- ExtensionHost* host = FindHostWithPath(manager, "/toolstrip1.html", 3);
-
- // Tell it to run some JavaScript that tests that basic extension code works.
- bool result = false;
- ui_test_utils::ExecuteJavaScriptAndExtractBool(
- host->render_view_host(), L"", L"testTabsAPI()", &result);
- EXPECT_TRUE(result);
-
- // Test for compact language detection API. First navigate to a (static) html
- // file with a French sentence. Then, run the test API in toolstrip1.html to
- // actually call the language detection API through the existing extension,
- // and verify that the language returned is indeed French.
- FilePath language_url = extension_test_data_dir.AppendASCII(
- "french_sentence.html");
- ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(language_url));
+// Tests that extension resources can be loaded from origins which the
+// extension specifies in permissions but not from others.
+IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, OriginPrivileges) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(LoadExtension(test_data_dir_
+ .AppendASCII("origin_privileges").AppendASCII("extension")));
- ui_test_utils::ExecuteJavaScriptAndExtractBool(
- host->render_view_host(), L"", L"testTabsLanguageAPI()", &result);
- EXPECT_TRUE(result);
-}
+ GURL origin_privileges_index(
+ test_server()->GetURL("files/extensions/origin_privileges/index.html"));
-IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ExtensionViews) {
- FilePath extension_test_data_dir = test_data_dir_.AppendASCII("good").
- AppendASCII("Extensions").AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj").
- AppendASCII("1.0.0.0");
- ASSERT_TRUE(LoadExtension(extension_test_data_dir));
+ std::string host_a("a.com");
+ GURL::Replacements make_host_a_com;
+ make_host_a_com.SetHostStr(host_a);
- // At this point, there should be three ExtensionHosts loaded because this
- // extension has two toolstrips and one background page. Find the one that is
- // hosting toolstrip1.html.
- ExtensionProcessManager* manager =
- browser()->profile()->GetExtensionProcessManager();
- ExtensionHost* host = FindHostWithPath(manager, "/toolstrip1.html", 3);
+ std::string host_b("b.com");
+ GURL::Replacements make_host_b_com;
+ make_host_b_com.SetHostStr(host_b);
- FilePath gettabs_url = extension_test_data_dir.AppendASCII(
- "test_gettabs.html");
+ // A web host that has permission.
ui_test_utils::NavigateToURL(
- browser(),
- GURL(gettabs_url.value()));
-
- bool result = false;
- ui_test_utils::ExecuteJavaScriptAndExtractBool(
- host->render_view_host(), L"", L"testgetToolstripsAPI()", &result);
- EXPECT_TRUE(result);
-
- result = false;
- ui_test_utils::ExecuteJavaScriptAndExtractBool(
- host->render_view_host(), L"", L"testgetBackgroundPageAPI()", &result);
- EXPECT_TRUE(result);
-
+ browser(), origin_privileges_index.ReplaceComponents(make_host_a_com));
+ std::string result;
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(), L"",
+ L"window.domAutomationController.send(document.title)",
+ &result);
+ EXPECT_EQ(result, "Loaded");
+
+ // A web host that does not have permission.
+ ui_test_utils::NavigateToURL(
+ browser(), origin_privileges_index.ReplaceComponents(make_host_b_com));
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(), L"",
+ L"window.domAutomationController.send(document.title)",
+ &result);
+ EXPECT_EQ(result, "Image failed to load");
+
+ // A data URL. Data URLs should always be able to load chrome-extension://
+ // resources.
+ std::string file_source;
+ ASSERT_TRUE(file_util::ReadFileToString(
+ test_data_dir_.AppendASCII("origin_privileges")
+ .AppendASCII("index.html"), &file_source));
+ ui_test_utils::NavigateToURL(browser(),
+ GURL(std::string("data:text/html;charset=utf-8,") + file_source));
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(), L"",
+ L"window.domAutomationController.send(document.title)",
+ &result);
+ EXPECT_EQ(result, "Loaded");
+
+ // A different extension. Extensions should always be able to load each
+ // other's resources.
+ ASSERT_TRUE(LoadExtension(test_data_dir_
+ .AppendASCII("origin_privileges").AppendASCII("extension2")));
ui_test_utils::NavigateToURL(
browser(),
- GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/"
- "test_gettabs.html"));
- result = false;
- ui_test_utils::ExecuteJavaScriptAndExtractBool(
- host->render_view_host(), L"", L"testgetExtensionTabsAPI()", &result);
- EXPECT_TRUE(result);
-}
-
-#if defined(TOOLKIT_VIEWS)
-// http://crbug.com/29897 - for other UI toolkits?
-
-// Tests that the ExtensionShelf initializes properly, notices that
-// an extension loaded and has a view available, and then sets that up
-// properly.
-IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, Shelf) {
- // When initialized, there are no extension views and the preferred height
- // should be zero.
- BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
- ExtensionShelf* shelf = browser_view->extension_shelf();
- ASSERT_TRUE(shelf);
- EXPECT_EQ(shelf->GetChildViewCount(), 0);
- EXPECT_EQ(shelf->GetPreferredSize().height(), 0);
-
- ASSERT_TRUE(LoadExtension(
- test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
- .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
- .AppendASCII("1.0.0.0")));
-
- // There should now be two extension views and preferred height of the view
- // should be non-zero.
- EXPECT_EQ(shelf->GetChildViewCount(), 2);
- EXPECT_NE(shelf->GetPreferredSize().height(), 0);
+ GURL("chrome-extension://pbkkcbgdkliohhfaeefcijaghglkahja/index.html"));
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(), L"",
+ L"window.domAutomationController.send(document.title)",
+ &result);
+ EXPECT_EQ(result, "Loaded");
}
-#endif // defined(TOOLKIT_VIEWS)
// Tests that we can load extension pages into the tab area and they can call
// extension APIs.
@@ -206,8 +174,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TabContents) {
// Tests that we can load page actions in the Omnibox.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageAction) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// This page action will not show an icon, since it doesn't specify one but
// is included here to test for a crash (http://crbug.com/25562).
@@ -221,13 +188,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageAction) {
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));
// Navigate to the feed page.
- GURL feed_url = server->TestServerPage(kFeedPage);
+ GURL feed_url = test_server()->GetURL(kFeedPage);
ui_test_utils::NavigateToURL(browser(), feed_url);
// We should now have one page action ready to go in the LocationBar.
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
// Navigate to a page with no feed.
- GURL no_feed = server->TestServerPage(kNoFeedPage);
+ GURL no_feed = test_server()->GetURL(kNoFeedPage);
ui_test_utils::NavigateToURL(browser(), no_feed);
// Make sure the page action goes away.
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));
@@ -235,8 +202,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageAction) {
// Tests that we don't lose the page action icon on in-page navigations.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionInPageNavigation) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
FilePath extension_path(test_data_dir_.AppendASCII("api_test")
.AppendASCII("page_action")
@@ -244,31 +210,30 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionInPageNavigation) {
ASSERT_TRUE(LoadExtension(extension_path));
// Page action should become visible when we navigate here.
- GURL feed_url = server->TestServerPage(kHashPageA);
+ GURL feed_url = test_server()->GetURL(kHashPageA);
ui_test_utils::NavigateToURL(browser(), feed_url);
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
// In-page navigation, page action should remain.
- feed_url = server->TestServerPage(kHashPageAHash);
+ feed_url = test_server()->GetURL(kHashPageAHash);
ui_test_utils::NavigateToURL(browser(), feed_url);
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
// Not an in-page navigation, page action should go away.
- feed_url = server->TestServerPage(kHashPageB);
+ feed_url = test_server()->GetURL(kHashPageB);
ui_test_utils::NavigateToURL(browser(), feed_url);
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));
}
// Tests that the location bar forgets about unloaded page actions.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UnloadPageAction) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
FilePath extension_path(test_data_dir_.AppendASCII("subscribe_page_action"));
ASSERT_TRUE(LoadExtension(extension_path));
// Navigation prompts the location bar to load page actions.
- GURL feed_url = server->TestServerPage(kFeedPage);
+ GURL feed_url = test_server()->GetURL(kFeedPage);
ui_test_utils::NavigateToURL(browser(), feed_url);
ASSERT_TRUE(WaitForPageActionCountChangeTo(1));
@@ -279,7 +244,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UnloadPageAction) {
}
// Flaky crash on Mac debug. http://crbug.com/45079
-#if defined(OS_MACOSX)
+// Stuck/time-out on XP test. http://crbug.com/51814
+#if defined(OS_MACOSX) || defined(OS_WIN)
#define PageActionRefreshCrash DISABLED_PageActionRefreshCrash
#endif
// Tests that we can load page actions in the Omnibox.
@@ -316,8 +282,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionRefreshCrash) {
// Makes sure that the RSS detects RSS feed links, even when rel tag contains
// more than just "alternate".
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
@@ -325,7 +290,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) {
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));
// Navigate to the feed page.
- GURL feed_url = server->TestServerPage(kFeedPageMultiRel);
+ GURL feed_url = test_server()->GetURL(kFeedPageMultiRel);
ui_test_utils::NavigateToURL(browser(), feed_url);
// We should now have one page action ready to go in the LocationBar.
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
@@ -355,8 +320,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) {
// Tests that tooltips of a page action icon can be specified using UTF8.
// See http://crbug.com/25349.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ExtensionsService* service = browser()->profile()->GetExtensionsService();
const size_t size_before = service->extensions()->size();
@@ -366,7 +330,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) {
ASSERT_TRUE(LoadExtension(extension_path));
// Any navigation prompts the location bar to load the page action.
- GURL url = server->TestServerPage(kLocalization);
+ GURL url = test_server()->GetURL(kLocalization);
ui_test_utils::NavigateToURL(browser(), url);
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
@@ -382,9 +346,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) {
extension->page_action()->GetTitle(tab_id).c_str());
}
-GURL GetFeedUrl(HTTPTestServer* server, const std::string& feed_page,
+GURL GetFeedUrl(net::TestServer* server, const std::string& feed_page,
bool direct_url, std::string extension_id) {
- GURL feed_url = server->TestServerPage(feed_page);
+ GURL feed_url = server->GetURL(feed_page);
if (direct_url) {
// We navigate directly to the subscribe page for feeds where the feed
// sniffing won't work, in other words, as is the case for malformed feeds.
@@ -445,7 +409,7 @@ bool ValidatePageElement(TabContents* tab,
// extension to kick in, detect the feed and redirect to a feed preview page.
// |sniff_xml_type| is generally set to true if the feed is sniffable and false
// for invalid feeds.
-void NavigateToFeedAndValidate(HTTPTestServer* server,
+void NavigateToFeedAndValidate(net::TestServer* server,
const std::string& url,
Browser* browser,
bool sniff_xml_type,
@@ -484,13 +448,12 @@ void NavigateToFeedAndValidate(HTTPTestServer* server,
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed1) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
- NavigateToFeedAndValidate(server, kValidFeed1, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeed1, browser(), true,
"Feed for MyFeedTitle",
"Title 1",
"Desc",
@@ -498,13 +461,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed1) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed2) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
- NavigateToFeedAndValidate(server, kValidFeed2, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeed2, browser(), true,
"Feed for MyFeed2",
"My item title1",
"This is a summary.",
@@ -512,13 +474,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed2) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed3) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
- NavigateToFeedAndValidate(server, kValidFeed3, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeed3, browser(), true,
"Feed for Google Code buglist rss feed",
"My dear title",
"My dear content",
@@ -526,13 +487,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed3) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed4) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
- NavigateToFeedAndValidate(server, kValidFeed4, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeed4, browser(), true,
"Feed for Title chars <script> %23 stop",
"Title chars %23 stop",
"My dear content %23 stop",
@@ -540,15 +500,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed4) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed0) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
// Try a feed with a link with an onclick handler (before r27440 this would
// trigger a NOTREACHED).
- NavigateToFeedAndValidate(server, kValidFeed0, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeed0, browser(), true,
"Feed for MyFeedTitle",
"Title 1",
"Desc VIDEO",
@@ -556,14 +515,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed0) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed5) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
// Feed with valid but mostly empty xml.
- NavigateToFeedAndValidate(server, kValidFeed5, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeed5, browser(), true,
"Feed for Unknown feed name",
"element 'anchor_0' not found",
"element 'desc_0' not found",
@@ -571,14 +529,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed5) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed6) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
// Feed that is technically invalid but still parseable.
- NavigateToFeedAndValidate(server, kValidFeed6, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeed6, browser(), true,
"Feed for MyFeedTitle",
"Title 1",
"Desc",
@@ -586,14 +543,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeed6) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed1) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
// Try an empty feed.
- NavigateToFeedAndValidate(server, kInvalidFeed1, browser(), false,
+ NavigateToFeedAndValidate(test_server(), kInvalidFeed1, browser(), false,
"Feed for Unknown feed name",
"element 'anchor_0' not found",
"element 'desc_0' not found",
@@ -601,14 +557,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed1) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed2) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
// Try a garbage feed.
- NavigateToFeedAndValidate(server, kInvalidFeed2, browser(), false,
+ NavigateToFeedAndValidate(test_server(), kInvalidFeed2, browser(), false,
"Feed for Unknown feed name",
"element 'anchor_0' not found",
"element 'desc_0' not found",
@@ -616,14 +571,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed2) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed3) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
// Try a feed that doesn't exist.
- NavigateToFeedAndValidate(server, "foo.xml", browser(), false,
+ NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), false,
"Feed for Unknown feed name",
"element 'anchor_0' not found",
"element 'desc_0' not found",
@@ -631,14 +585,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedInvalidFeed3) {
}
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, ParseFeedValidFeedNoLinks) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("subscribe_page_action")));
// Valid feed but containing no links.
- NavigateToFeedAndValidate(server, kValidFeedNoLinks, browser(), true,
+ NavigateToFeedAndValidate(test_server(), kValidFeedNoLinks, browser(), true,
"Feed for MyFeedTitle",
"Title with no link",
"Desc",
@@ -654,7 +607,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, LastError) {
// Get the ExtensionHost that is hosting our toolstrip page.
ExtensionProcessManager* manager =
browser()->profile()->GetExtensionProcessManager();
- ExtensionHost* host = FindHostWithPath(manager, "/toolstrip.html", 1);
+ ExtensionHost* host = FindHostWithPath(manager, "/bg.html", 1);
bool result = false;
ui_test_utils::ExecuteJavaScriptAndExtractBool(
@@ -674,8 +627,11 @@ static TabContents* WindowOpenHelper(Browser* browser, const GURL& start_url,
L"window.domAutomationController.send(true);", &result);
EXPECT_TRUE(result);
- // Now the current tab should be the new tab.
- TabContents* newtab = browser->GetSelectedTabContents();
+ // Now the active tab in last active window should be the new tab.
+ Browser* last_active_browser = BrowserList::GetLastActive();
+ EXPECT_TRUE(last_active_browser);
+ TabContents* newtab = last_active_browser->GetSelectedTabContents();
+ EXPECT_TRUE(newtab);
GURL expected_url = start_url.Resolve(newtab_url);
if (!newtab->controller().GetLastCommittedEntry() ||
newtab->controller().GetLastCommittedEntry()->url() != expected_url)
@@ -839,3 +795,74 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) {
EXPECT_EQ(extension->GetResourceURL("options.html"),
tab_strip->GetTabContentsAt(1)->GetURL());
}
+
+// Test window.chrome.app.isInstalled .
+IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PropertyAppIsInstalled) {
+
+ std::string app_host("app.com");
+ std::string nonapp_host("nonapp.com");
+
+ host_resolver()->AddRule(app_host, "127.0.0.1");
+ host_resolver()->AddRule(nonapp_host, "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL test_file_url(test_server()->GetURL("extensions/test_file.html"));
+ GURL::Replacements replace_host;
+
+ replace_host.SetHostStr(app_host);
+ GURL app_url(test_file_url.ReplaceComponents(replace_host));
+
+ replace_host.SetHostStr(nonapp_host);
+ GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
+
+
+ // Load an app which includes app.com in its extent.
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("app_dot_com_app")));
+
+
+ // Test that a non-app page has chrome.app.isInstalled = false.
+ ui_test_utils::NavigateToURL(browser(), non_app_url);
+ std::wstring get_app_is_installed =
+ L"window.domAutomationController.send("
+ L" JSON.stringify(window.chrome.app.isInstalled));";
+ std::string result;
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"",
+ get_app_is_installed.c_str(),
+ &result));
+ EXPECT_EQ("false", result);
+
+
+ // Check that an app page has chrome.app.isInstalled = true.
+ ui_test_utils::NavigateToURL(browser(), app_url);
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"",
+ get_app_is_installed.c_str(),
+ &result));
+ EXPECT_EQ("true", result);
+
+
+ // Test that trying to set window.chrome.app.isInstalled throws
+ // an exception.
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"",
+ L"window.domAutomationController.send("
+ L" function() {"
+ L" try {"
+ L" window.chrome.app.isInstalled = false;"
+ L" return 'BAD: Should have thrown by now...';"
+ L" } catch (e) {"
+ L" return 'GOOD: Saw expected error.';"
+ L" }"
+ L" }()"
+ L");",
+ &result));
+ EXPECT_EQ("GOOD: Saw expected error.", result);
+}
diff --git a/chrome/browser/extensions/extension_clipboard_api.cc b/chrome/browser/extensions/extension_clipboard_api.cc
index 22a6253..af1deae 100644
--- a/chrome/browser/extensions/extension_clipboard_api.cc
+++ b/chrome/browser/extensions/extension_clipboard_api.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/extensions/extension_clipboard_api.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -23,8 +23,8 @@ bool ClipboardFunction::RunImpl() {
TabContents* contents = NULL;
if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
NULL, NULL, &contents, NULL)) {
- error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError,
- IntToString(tab_id));
+ error_ = ExtensionErrorUtils::FormatErrorMessage(
+ kNoTabError, base::IntToString(tab_id));
return false;
}
diff --git a/chrome/browser/extensions/extension_clipboard_api.h b/chrome/browser/extensions/extension_clipboard_api.h
index 4789221..1172a07 100644
--- a/chrome/browser/extensions/extension_clipboard_api.h
+++ b/chrome/browser/extensions/extension_clipboard_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_CLIPBOARD_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_CLIPBOARD_API_H_
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
@@ -14,6 +15,9 @@ class ClipboardFunction : public SyncExtensionFunction {
public:
virtual bool RunImpl();
virtual bool RunImpl(RenderViewHost* render_view_host) = 0;
+
+ protected:
+ virtual ~ClipboardFunction() {}
};
class ExecuteCopyClipboardFunction : public ClipboardFunction {
diff --git a/chrome/browser/extensions/extension_clipboard_apitest.cc b/chrome/browser/extensions/extension_clipboard_apitest.cc
index cfabacf..c159f97 100644
--- a/chrome/browser/extensions/extension_clipboard_apitest.cc
+++ b/chrome/browser/extensions/extension_clipboard_apitest.cc
@@ -10,6 +10,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Clipboard) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("clipboard")) << message_;
}
diff --git a/chrome/browser/extensions/extension_context_menu_api.cc b/chrome/browser/extensions/extension_context_menu_api.cc
index 5652245..92e9ad4 100644
--- a/chrome/browser/extensions/extension_context_menu_api.cc
+++ b/chrome/browser/extensions/extension_context_menu_api.cc
@@ -7,18 +7,20 @@
#include <string>
#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/common/extensions/extension_error_utils.h"
-const wchar_t kCheckedKey[] = L"checked";
-const wchar_t kContextsKey[] = L"contexts";
-const wchar_t kDocumentUrlPatternsKey[] = L"documentUrlPatterns";
-const wchar_t kGeneratedIdKey[] = L"generatedId";
-const wchar_t kParentIdKey[] = L"parentId";
-const wchar_t kTargetUrlPatternsKey[] = L"targetUrlPatterns";
-const wchar_t kTitleKey[] = L"title";
-const wchar_t kTypeKey[] = L"type";
+const char kCheckedKey[] = "checked";
+const char kContextsKey[] = "contexts";
+const char kDocumentUrlPatternsKey[] = "documentUrlPatterns";
+const char kGeneratedIdKey[] = "generatedId";
+const char kParentIdKey[] = "parentId";
+const char kTargetUrlPatternsKey[] = "targetUrlPatterns";
+const char kTitleKey[] = "title";
+const char kTypeKey[] = "type";
const char kCannotFindItemError[] = "Cannot find menu item with id *";
const char kCheckedError[] =
@@ -34,7 +36,7 @@ const char kTitleNeededError[] =
bool ExtensionContextMenuFunction::ParseContexts(
const DictionaryValue& properties,
- const wchar_t* key,
+ const char* key,
ExtensionMenuItem::ContextList* result) {
ListValue* list = NULL;
if (!properties.GetList(key, &list)) {
@@ -64,8 +66,7 @@ bool ExtensionContextMenuFunction::ParseContexts(
} else if (value == "audio") {
tmp_result.Add(ExtensionMenuItem::AUDIO);
} else {
- error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidValueError,
- WideToASCII(key));
+ error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidValueError, key);
return false;
}
}
@@ -124,7 +125,7 @@ bool ExtensionContextMenuFunction::ParseChecked(
bool ExtensionContextMenuFunction::ParseURLPatterns(
const DictionaryValue& properties,
- const wchar_t* key,
+ const char* key,
ExtensionExtent* result) {
if (!properties.HasKey(key))
return true;
@@ -187,7 +188,8 @@ bool ExtensionContextMenuFunction::GetParent(
ExtensionMenuItem* parent = manager.GetItemById(parent_id);
if (!parent) {
- error_ = "Cannot find menu item with id " + IntToString(parent_id.second);
+ error_ = "Cannot find menu item with id " +
+ base::IntToString(parent_id.second);
return false;
}
if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -245,7 +247,7 @@ bool CreateContextMenuFunction::RunImpl() {
ExtensionMenuItem* parent = menu_manager->GetItemById(parent_id);
if (!parent) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- kCannotFindItemError, IntToString(parent_id.second));
+ kCannotFindItemError, base::IntToString(parent_id.second));
return false;
}
if (parent->type() != ExtensionMenuItem::NORMAL) {
@@ -272,7 +274,7 @@ bool UpdateContextMenuFunction::RunImpl() {
ExtensionMenuItem* item = manager->GetItemById(item_id);
if (!item || item->extension_id() != extension_id()) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- kCannotFindItemError, IntToString(item_id.second));
+ kCannotFindItemError, base::IntToString(item_id.second));
return false;
}
@@ -340,7 +342,7 @@ bool RemoveContextMenuFunction::RunImpl() {
// Ensure one extension can't remove another's menu items.
if (!item || item->extension_id() != extension_id()) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- kCannotFindItemError, IntToString(id.second));
+ kCannotFindItemError, base::IntToString(id.second));
return false;
}
diff --git a/chrome/browser/extensions/extension_context_menu_api.h b/chrome/browser/extensions/extension_context_menu_api.h
index 3f73251..4ac5670 100644
--- a/chrome/browser/extensions/extension_context_menu_api.h
+++ b/chrome/browser/extensions/extension_context_menu_api.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_CONTEXT_MENU_API_H__
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_CONTEXT_MENU_API_H__
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/extensions/extension_menu_manager.h"
#include "chrome/common/extensions/extension_extent.h"
+class DictionaryValue;
class ExtensionMenuItem;
class ExtensionContextMenuFunction : public SyncExtensionFunction {
@@ -18,7 +20,7 @@ class ExtensionContextMenuFunction : public SyncExtensionFunction {
protected:
// Helper function to read and parse a list of menu item contexts.
bool ParseContexts(const DictionaryValue& properties,
- const wchar_t* key,
+ const char* key,
ExtensionMenuItem::ContextList* result);
// Looks in properties for the "type" key, and reads the value in |result|. On
@@ -38,7 +40,7 @@ class ExtensionContextMenuFunction : public SyncExtensionFunction {
// Helper to read in a set of url patterns from a property with the given key
// name.
bool ParseURLPatterns(const DictionaryValue& properties,
- const wchar_t* key,
+ const char* key,
ExtensionExtent* result);
// Reads in any document and targetUrl patterns from |properties| and sets
diff --git a/chrome/browser/extensions/extension_context_menu_apitest.cc b/chrome/browser/extensions/extension_context_menu_apitest.cc
index 1ae6edf..4cd2c1e 100644
--- a/chrome/browser/extensions/extension_context_menu_apitest.cc
+++ b/chrome/browser/extensions/extension_context_menu_apitest.cc
@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/command_line.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/common/chrome_switches.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContextMenus) {
ASSERT_TRUE(RunExtensionTest("context_menus/basics")) << message_;
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc
index 3eb058f..427a7fc 100644
--- a/chrome/browser/extensions/extension_context_menu_browsertest.cc
+++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -6,10 +6,14 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.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/tab_contents/render_view_context_menu.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
+#include "net/base/mock_host_resolver.h"
#include "third_party/WebKit/WebKit/chromium/public/WebContextMenuData.h"
#include "webkit/glue/context_menu.h"
@@ -27,96 +31,340 @@ class TestRenderViewContextMenu : public RenderViewContextMenu {
virtual ~TestRenderViewContextMenu() {}
- bool HasExtensionItemWithTitle(std::string title) {
+ bool HasExtensionItemWithLabel(const std::string& label) {
+ string16 label16 = UTF8ToUTF16(label);
std::map<int, ExtensionMenuItem::Id>::iterator i;
for (i = extension_item_map_.begin(); i != extension_item_map_.end(); ++i) {
- int id = i->first;
- ExtensionMenuItem* item = GetExtensionMenuItem(id);
- if (item && item->title() == title) {
+ const ExtensionMenuItem::Id& id = i->second;
+ string16 tmp_label;
+ EXPECT_TRUE(GetItemLabel(id, &tmp_label));
+ if (tmp_label == label16)
return true;
+ }
+ return false;
+ }
+
+ // Looks in the menu for an extension item with |id|, and if it is found and
+ // has a label, that is put in |result| and we return true. Otherwise returns
+ // false.
+ bool GetItemLabel(const ExtensionMenuItem::Id& id, string16* result) {
+ int command_id = 0;
+ if (!FindCommandId(id, &command_id))
+ return false;
+
+ MenuModel* model = NULL;
+ int index = -1;
+ if (!GetMenuModelAndItemIndex(command_id, &model, &index)) {
+ return false;
+ }
+ *result = model->GetLabelAt(index);
+ return true;
+ }
+
+ // Searches for an menu item with |command_id|. If it's found, the return
+ // value is true and the model and index where it appears in that model are
+ // returned in |found_model| and |found_index|. Otherwise returns false.
+ bool GetMenuModelAndItemIndex(int command_id,
+ MenuModel** found_model,
+ int *found_index) {
+ std::vector<MenuModel*> models_to_search;
+ models_to_search.push_back(&menu_model_);
+
+ while (!models_to_search.empty()) {
+ MenuModel* model = models_to_search.back();
+ models_to_search.pop_back();
+ for (int i = 0; i < model->GetItemCount(); i++) {
+ if (model->GetCommandIdAt(i) == command_id) {
+ *found_model = model;
+ *found_index = i;
+ return true;
+ } else if (model->GetTypeAt(i) == MenuModel::TYPE_SUBMENU) {
+ models_to_search.push_back(model->GetSubmenuModelAt(i));
+ }
}
}
+
return false;
}
protected:
+ // These two functions implement pure virtual methods of
+ // RenderViewContextMenu.
virtual bool GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator) {
// None of our commands have accelerators, so always return false.
return false;
}
virtual void PlatformInit() {}
+
+
+ // Given an extension menu item id, tries to find the corresponding command id
+ // in the menu.
+ bool FindCommandId(const ExtensionMenuItem::Id& id, int* command_id) {
+ std::map<int, ExtensionMenuItem::Id>::const_iterator i;
+ for (i = extension_item_map_.begin(); i != extension_item_map_.end(); ++i) {
+ if (i->second == id) {
+ *command_id = i->first;
+ return true;
+ }
+ }
+ return false;
+ }
};
class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest {
public:
// Helper to load an extension from context_menus/|subdirectory| in the
// extensions test data dir.
- void LoadContextMenuExtension(std::string subdirectory) {
+ bool LoadContextMenuExtension(std::string subdirectory) {
FilePath extension_dir =
test_data_dir_.AppendASCII("context_menus").AppendASCII(subdirectory);
- ASSERT_TRUE(LoadExtension(extension_dir));
+ return LoadExtension(extension_dir);
}
- // This creates a test menu using |params|, looks for an extension item with
- // the given |title|, and returns true if the item was found.
- bool MenuHasItemWithTitle(const ContextMenuParams& params,
- std::string title) {
+ TestRenderViewContextMenu* CreateMenu(const GURL& page_url,
+ const GURL& link_url) {
TabContents* tab_contents = browser()->GetSelectedTabContents();
- TestRenderViewContextMenu menu(tab_contents, params);
- menu.Init();
- return menu.HasExtensionItemWithTitle(title);
+ WebContextMenuData data;
+ ContextMenuParams params(data);
+ params.page_url = page_url;
+ params.link_url = link_url;
+ TestRenderViewContextMenu* menu =
+ new TestRenderViewContextMenu(tab_contents, params);
+ menu->Init();
+ return menu;
}
-};
-// Returns a new ContextMenuParams initialized with reasonable default values.
-ContextMenuParams* CreateParams() {
- WebContextMenuData data;
- ContextMenuParams* params = new ContextMenuParams(data);
- return params;
-}
+ // Shortcut to return the current ExtensionMenuManager.
+ ExtensionMenuManager* menu_manager() {
+ return browser()->profile()->GetExtensionsService()->menu_manager();
+ }
+
+ // Returns a pointer to the currently loaded extension with |name|, or null
+ // if not found.
+ Extension* GetExtensionNamed(std::string name) {
+ const ExtensionList* extensions =
+ browser()->profile()->GetExtensionsService()->extensions();
+ ExtensionList::const_iterator i;
+ for (i = extensions->begin(); i != extensions->end(); ++i) {
+ if ((*i)->name() == name) {
+ return *i;
+ }
+ }
+ return NULL;
+ }
+ // This gets all the items that any extension has registered for possible
+ // inclusion in context menus.
+ ExtensionMenuItem::List GetItems() {
+ ExtensionMenuItem::List result;
+ std::set<std::string> extension_ids = menu_manager()->ExtensionIds();
+ std::set<std::string>::iterator i;
+ for (i = extension_ids.begin(); i != extension_ids.end(); ++i) {
+ const ExtensionMenuItem::List* list = menu_manager()->MenuItems(*i);
+ result.insert(result.end(), list->begin(), list->end());
+ }
+ return result;
+ }
+
+ // This creates a test menu for a page with |page_url| and |link_url|, looks
+ // for an extension item with the given |label|, and returns true if the item
+ // was found.
+ bool MenuHasItemWithLabel(const GURL& page_url,
+ const GURL& link_url,
+ const std::string& label) {
+ scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, link_url));
+ return menu->HasExtensionItemWithLabel(label);
+ }
+};
+
+// Tests adding a simple context menu item.
IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Simple) {
- LoadContextMenuExtension("simple");
+ ExtensionTestMessageListener listener1("created item");
+ ExtensionTestMessageListener listener2("onclick fired");
+ ASSERT_TRUE(LoadContextMenuExtension("simple"));
- // The extension's background page will create a context menu item and then
- // cause a navigation on success - we wait for that here.
- ASSERT_TRUE(ui_test_utils::WaitForNavigationsInCurrentTab(browser(), 1));
+ // Wait for the extension to tell us it's created an item.
+ ASSERT_TRUE(listener1.WaitUntilSatisfied());
- // Initialize the data we need to create a context menu.
- TabContents* tab_contents = browser()->GetSelectedTabContents();
- scoped_ptr<ContextMenuParams> params(CreateParams());
- params->page_url = GURL("http://www.google.com");
+ GURL page_url("http://www.google.com");
// Create and build our test context menu.
- TestRenderViewContextMenu menu(tab_contents, *params);
- menu.Init();
+ scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(page_url, GURL()));
// Look for the extension item in the menu, and execute it.
int command_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
- ASSERT_TRUE(menu.IsCommandIdEnabled(command_id));
- menu.ExecuteCommand(command_id);
+ ASSERT_TRUE(menu->IsCommandIdEnabled(command_id));
+ menu->ExecuteCommand(command_id);
- // The onclick handler for the extension item will cause a navigation - we
- // wait for that here.
- ASSERT_TRUE(ui_test_utils::WaitForNavigationsInCurrentTab(browser(), 1));
+ // Wait for the extension's script to tell us its onclick fired.
+ ASSERT_TRUE(listener2.WaitUntilSatisfied());
}
+// Tests that setting "documentUrlPatterns" for an item properly restricts
+// those items to matching pages.
IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Patterns) {
- // The js test code will create two items with patterns and then navigate a
- // tab to tell us to proceed.
- LoadContextMenuExtension("patterns");
- ASSERT_TRUE(ui_test_utils::WaitForNavigationsInCurrentTab(browser(), 1));
+ ExtensionTestMessageListener listener("created items");
- scoped_ptr<ContextMenuParams> params(CreateParams());
+ ASSERT_TRUE(LoadContextMenuExtension("patterns"));
+
+ // Wait for the js test code to create its two items with patterns.
+ ASSERT_TRUE(listener.WaitUntilSatisfied());
// Check that a document url that should match the items' patterns appears.
- params->frame_url = GURL("http://www.google.com");
- ASSERT_TRUE(MenuHasItemWithTitle(*params, std::string("test_item1")));
- ASSERT_TRUE(MenuHasItemWithTitle(*params, std::string("test_item2")));
-
- // Now check for a non-matching url.
- params->frame_url = GURL("http://www.test.com");
- ASSERT_FALSE(MenuHasItemWithTitle(*params, std::string("test_item1")));
- ASSERT_FALSE(MenuHasItemWithTitle(*params, std::string("test_item2")));
+ GURL google_url("http://www.google.com");
+ ASSERT_TRUE(MenuHasItemWithLabel(google_url,
+ GURL(),
+ std::string("test_item1")));
+ ASSERT_TRUE(MenuHasItemWithLabel(google_url,
+ GURL(),
+ std::string("test_item2")));
+
+ // Now check with a non-matching url.
+ GURL test_url("http://www.test.com");
+ ASSERT_FALSE(MenuHasItemWithLabel(test_url,
+ GURL(),
+ std::string("test_item1")));
+ ASSERT_FALSE(MenuHasItemWithLabel(test_url,
+ GURL(),
+ std::string("test_item2")));
+}
+
+// Tests registering an item with a very long title that should get truncated in
+// the actual menu displayed.
+IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, LongTitle) {
+ ExtensionTestMessageListener listener("created");
+
+ // Load the extension and wait until it's created a menu item.
+ ASSERT_TRUE(LoadContextMenuExtension("long_title"));
+ ASSERT_TRUE(listener.WaitUntilSatisfied());
+
+ // Make sure we have an item registered with a long title.
+ size_t limit = RenderViewContextMenu::kMaxExtensionItemTitleLength;
+ ExtensionMenuItem::List items = GetItems();
+ ASSERT_EQ(1u, items.size());
+ ExtensionMenuItem* item = items.at(0);
+ ASSERT_GT(item->title().size(), limit);
+
+ // Create a context menu, then find the item's label. It should be properly
+ // truncated.
+ GURL url("http://foo.com/");
+ scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+
+ string16 label;
+ ASSERT_TRUE(menu->GetItemLabel(item->id(), &label));
+ ASSERT_TRUE(label.size() <= limit);
+}
+
+// Checks that in |menu|, the item at |index| has type |expected_type| and a
+// label of |expected_label|.
+static void ExpectLabelAndType(const char* expected_label,
+ MenuModel::ItemType expected_type,
+ const MenuModel& menu,
+ int index) {
+ EXPECT_EQ(expected_type, menu.GetTypeAt(index));
+ EXPECT_EQ(UTF8ToUTF16(expected_label), menu.GetLabelAt(index));
+}
+
+// In the separators test we build a submenu with items and separators in two
+// different ways - this is used to verify the results in both cases.
+static void VerifyMenuForSeparatorsTest(const MenuModel& menu) {
+ // We expect to see the following items in the menu:
+ // radio1
+ // radio2
+ // --separator-- (automatically added)
+ // normal1
+ // --separator--
+ // normal2
+ // --separator--
+ // radio3
+ // radio4
+ // --separator--
+ // normal3
+
+ int index = 0;
+ ASSERT_EQ(11, menu.GetItemCount());
+ ExpectLabelAndType("radio1", MenuModel::TYPE_RADIO, menu, index++);
+ ExpectLabelAndType("radio2", MenuModel::TYPE_RADIO, menu, index++);
+ EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++));
+ ExpectLabelAndType("normal1", MenuModel::TYPE_COMMAND, menu, index++);
+ EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++));
+ ExpectLabelAndType("normal2", MenuModel::TYPE_COMMAND, menu, index++);
+ EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++));
+ ExpectLabelAndType("radio3", MenuModel::TYPE_RADIO, menu, index++);
+ ExpectLabelAndType("radio4", MenuModel::TYPE_RADIO, menu, index++);
+ EXPECT_EQ(MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(index++));
+ ExpectLabelAndType("normal3", MenuModel::TYPE_COMMAND, menu, index++);
+}
+
+// Tests a number of cases for auto-generated and explicitly added separators.
+IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, Separators) {
+ // Load the extension.
+ ASSERT_TRUE(LoadContextMenuExtension("separators"));
+ Extension* extension = GetExtensionNamed("Separators Test");
+ ASSERT_TRUE(extension != NULL);
+
+ // Navigate to test1.html inside the extension, which should create a bunch
+ // of items at the top-level (but they'll get pushed into an auto-generated
+ // parent).
+ ExtensionTestMessageListener listener1("test1 create finished");
+ ui_test_utils::NavigateToURL(browser(),
+ GURL(extension->GetResourceURL("test1.html")));
+ listener1.WaitUntilSatisfied();
+
+ GURL url("http://www.google.com/");
+ scoped_ptr<TestRenderViewContextMenu> menu(CreateMenu(url, GURL()));
+
+ // The top-level item should be an "automagic parent" with the extension's
+ // name.
+ MenuModel* model = NULL;
+ int index = 0;
+ string16 label;
+ ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
+ IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index));
+ EXPECT_EQ(UTF8ToUTF16(extension->name()), model->GetLabelAt(index));
+ ASSERT_EQ(MenuModel::TYPE_SUBMENU, model->GetTypeAt(index));
+
+ // Get the submenu and verify the items there.
+ MenuModel* submenu = model->GetSubmenuModelAt(index);
+ ASSERT_TRUE(submenu != NULL);
+ VerifyMenuForSeparatorsTest(*submenu);
+
+ // Now run our second test - navigate to test2.html which creates an explicit
+ // parent node and populates that with the same items as in test1.
+ ExtensionTestMessageListener listener2("test2 create finished");
+ ui_test_utils::NavigateToURL(browser(),
+ GURL(extension->GetResourceURL("test2.html")));
+ listener2.WaitUntilSatisfied();
+ menu.reset(CreateMenu(url, GURL()));
+ ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
+ IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, &model, &index));
+ EXPECT_EQ(UTF8ToUTF16("parent"), model->GetLabelAt(index));
+ submenu = model->GetSubmenuModelAt(index);
+ ASSERT_TRUE(submenu != NULL);
+ VerifyMenuForSeparatorsTest(*submenu);
+}
+
+// Tests that targetUrlPattern keeps items from appearing when there is no
+// target url.
+IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, TargetURLs) {
+ ExtensionTestMessageListener listener("created items");
+ ASSERT_TRUE(LoadContextMenuExtension("target_urls"));
+ ASSERT_TRUE(listener.WaitUntilSatisfied());
+
+ GURL google_url("http://www.google.com");
+ GURL non_google_url("http://www.foo.com");
+
+ // No target url - the item should not appear.
+ ASSERT_FALSE(MenuHasItemWithLabel(google_url, GURL(), std::string("item1")));
+
+ // A matching target url - the item should appear.
+ ASSERT_TRUE(MenuHasItemWithLabel(google_url,
+ google_url,
+ std::string("item1")));
+
+ // A non-matching target url - the item should not appear.
+ ASSERT_FALSE(MenuHasItemWithLabel(google_url,
+ non_google_url,
+ std::string("item1")));
}
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc
index a13361c..16ef321 100644
--- a/chrome/browser/extensions/extension_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -4,12 +4,12 @@
#include "chrome/browser/extensions/extension_context_menu_model.h"
-#include "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/pref_service.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"
@@ -128,9 +128,7 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id) {
}
}
-void ExtensionContextMenuModel::InstallUIProceed(bool create_app) {
- DCHECK(!create_app);
-
+void ExtensionContextMenuModel::InstallUIProceed() {
std::string id = extension_->id();
profile_->GetExtensionsService()->UninstallExtension(id, false);
diff --git a/chrome/browser/extensions/extension_context_menu_model.h b/chrome/browser/extensions/extension_context_menu_model.h
index c7cb845..35af19d 100644
--- a/chrome/browser/extensions/extension_context_menu_model.h
+++ b/chrome/browser/extensions/extension_context_menu_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_CONTEXT_MENU_MODEL_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_CONTEXT_MENU_MODEL_H_
+#pragma once
#include "app/menus/simple_menu_model.h"
#include "chrome/browser/extensions/extension_install_ui.h"
@@ -27,6 +28,9 @@ class ExtensionContextMenuModel
// Called when the user selects the menu item which requests that the
// popup be shown and inspected.
virtual void InspectPopup(ExtensionAction* action) = 0;
+
+ protected:
+ virtual ~PopupDelegate() {}
};
// Creates a menu model for the given extension action. If
@@ -46,7 +50,7 @@ class ExtensionContextMenuModel
virtual void ExecuteCommand(int command_id);
// ExtensionInstallUI::Delegate overrides.
- virtual void InstallUIProceed(bool create_app);
+ virtual void InstallUIProceed();
virtual void InstallUIAbort();
private:
diff --git a/chrome/browser/extensions/extension_cookies_api.cc b/chrome/browser/extensions/extension_cookies_api.cc
index 096059d..a1e455c 100644
--- a/chrome/browser/extensions/extension_cookies_api.cc
+++ b/chrome/browser/extensions/extension_cookies_api.cc
@@ -8,12 +8,14 @@
#include "base/json/json_writer.h"
#include "base/task.h"
+#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_cookies_api_constants.h"
#include "chrome/browser/extensions/extension_cookies_helpers.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/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"
#include "chrome/common/notification_type.h"
@@ -75,7 +77,7 @@ void ExtensionCookiesEventRouter::DispatchEvent(Profile* profile,
GURL& cookie_domain) {
if (profile && profile->GetExtensionMessageService()) {
profile->GetExtensionMessageService()->DispatchEventToRenderers(
- event_name, json_args, profile->IsOffTheRecord(), cookie_domain);
+ event_name, json_args, profile, cookie_domain);
}
}
@@ -143,6 +145,8 @@ bool CookiesFunction::ParseStoreContext(const DictionaryValue* details,
GetCookieFunction::GetCookieFunction() {}
+GetCookieFunction::~GetCookieFunction() {}
+
bool GetCookieFunction::RunImpl() {
// Return false if the arguments are malformed.
DictionaryValue* details;
@@ -190,7 +194,8 @@ void GetCookieFunction::RespondOnUIThread() {
net::CookieMonster::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 retrieves them in reverse domain-length order.
+ // CookieMonster returns them in canonical order (longest path, then
+ // earliest creation time).
if (it->Name() == name_) {
result_.reset(
extension_cookies_helpers::CreateCookieValue(*it, store_id_));
@@ -205,7 +210,9 @@ void GetCookieFunction::RespondOnUIThread() {
SendResponse(true);
}
-GetAllCookiesFunction::GetAllCookiesFunction() {}
+GetAllCookiesFunction::GetAllCookiesFunction() : details_(NULL) {}
+
+GetAllCookiesFunction::~GetAllCookiesFunction() {}
bool GetAllCookiesFunction::RunImpl() {
// Return false if the arguments are malformed.
@@ -257,7 +264,14 @@ void GetAllCookiesFunction::RespondOnUIThread() {
SendResponse(true);
}
-SetCookieFunction::SetCookieFunction() : secure_(false), http_only_(false) {}
+SetCookieFunction::SetCookieFunction()
+ : secure_(false),
+ http_only_(false),
+ success_(false) {
+}
+
+SetCookieFunction::~SetCookieFunction() {
+}
bool SetCookieFunction::RunImpl() {
// Return false if the arguments are malformed.
@@ -300,7 +314,10 @@ bool SetCookieFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(
expiration_date_value->GetAsReal(&expiration_date));
}
- expiration_time_ = base::Time::FromDoubleT(expiration_date);
+ // Time::FromDoubleT converts double time 0 to empty Time object. So we need
+ // to do special handling here.
+ expiration_time_ = (expiration_date == 0) ?
+ base::Time::UnixEpoch() : base::Time::FromDoubleT(expiration_date);
}
URLRequestContextGetter* store_context = NULL;
@@ -398,8 +415,12 @@ bool RemoveCookieFunction::RunImpl() {
return true;
}
+void RemoveCookieFunction::Run() {
+ SendResponse(RunImpl());
+}
+
bool GetAllCookieStoresFunction::RunImpl() {
- Profile* original_profile = profile()->GetOriginalProfile();
+ Profile* original_profile = profile();
DCHECK(original_profile);
scoped_ptr<ListValue> original_tab_ids(new ListValue());
Profile* incognito_profile = NULL;
@@ -409,6 +430,8 @@ bool GetAllCookieStoresFunction::RunImpl() {
if (incognito_profile)
incognito_tab_ids.reset(new ListValue());
}
+ DCHECK(original_profile != incognito_profile);
+
// Iterate through all browser instances, and for each browser,
// add its tab IDs to either the regular or incognito tab ID list depending
// whether the browser is regular or incognito.
@@ -439,3 +462,7 @@ bool GetAllCookieStoresFunction::RunImpl() {
result_.reset(cookie_store_list);
return true;
}
+
+void GetAllCookieStoresFunction::Run() {
+ SendResponse(RunImpl());
+}
diff --git a/chrome/browser/extensions/extension_cookies_api.h b/chrome/browser/extensions/extension_cookies_api.h
index e783f31..50b922b 100644
--- a/chrome/browser/extensions/extension_cookies_api.h
+++ b/chrome/browser/extensions/extension_cookies_api.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_COOKIES_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_COOKIES_API_H_
+#pragma once
#include <string>
@@ -15,10 +16,12 @@
#include "base/time.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/net/chrome_cookie_notification_details.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
#include "net/base/cookie_monster.h"
+class DictionaryValue;
class URLRequestContextGetter;
// Observes CookieMonster notifications and routes them as events to the
@@ -91,6 +94,7 @@ class CookiesFunction : public AsyncExtensionFunction {
class GetCookieFunction : public CookiesFunction {
public:
GetCookieFunction();
+ ~GetCookieFunction();
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("cookies.get")
@@ -109,6 +113,7 @@ class GetCookieFunction : public CookiesFunction {
class GetAllCookiesFunction : public CookiesFunction {
public:
GetAllCookiesFunction();
+ ~GetAllCookiesFunction();
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("cookies.getAll")
@@ -127,6 +132,7 @@ class GetAllCookiesFunction : public CookiesFunction {
class SetCookieFunction : public CookiesFunction {
public:
SetCookieFunction();
+ ~SetCookieFunction();
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("cookies.set")
@@ -151,9 +157,7 @@ class RemoveCookieFunction : public CookiesFunction {
public:
virtual bool RunImpl();
// RemoveCookieFunction is sync.
- virtual void Run() {
- SendResponse(RunImpl());
- }
+ virtual void Run();
DECLARE_EXTENSION_FUNCTION_NAME("cookies.remove")
};
@@ -162,9 +166,7 @@ class GetAllCookieStoresFunction : public CookiesFunction {
public:
virtual bool RunImpl();
// GetAllCookieStoresFunction is sync.
- virtual void Run() {
- SendResponse(RunImpl());
- }
+ virtual void Run();
DECLARE_EXTENSION_FUNCTION_NAME("cookies.getAllCookieStores")
};
diff --git a/chrome/browser/extensions/extension_cookies_api_constants.cc b/chrome/browser/extensions/extension_cookies_api_constants.cc
index 1524d36..6307079 100644
--- a/chrome/browser/extensions/extension_cookies_api_constants.cc
+++ b/chrome/browser/extensions/extension_cookies_api_constants.cc
@@ -6,21 +6,21 @@
namespace extension_cookies_api_constants {
-const wchar_t kCookieKey[] = L"cookie";
-const wchar_t kDomainKey[] = L"domain";
-const wchar_t kExpirationDateKey[] = L"expirationDate";
-const wchar_t kHostOnlyKey[] = L"hostOnly";
-const wchar_t kHttpOnlyKey[] = L"httpOnly";
-const wchar_t kIdKey[] = L"id";
-const wchar_t kNameKey[] = L"name";
-const wchar_t kPathKey[] = L"path";
-const wchar_t kRemovedKey[] = L"removed";
-const wchar_t kSecureKey[] = L"secure";
-const wchar_t kSessionKey[] = L"session";
-const wchar_t kStoreIdKey[] = L"storeId";
-const wchar_t kTabIdsKey[] = L"tabIds";
-const wchar_t kUrlKey[] = L"url";
-const wchar_t kValueKey[] = L"value";
+const char kCookieKey[] = "cookie";
+const char kDomainKey[] = "domain";
+const char kExpirationDateKey[] = "expirationDate";
+const char kHostOnlyKey[] = "hostOnly";
+const char kHttpOnlyKey[] = "httpOnly";
+const char kIdKey[] = "id";
+const char kNameKey[] = "name";
+const char kPathKey[] = "path";
+const char kRemovedKey[] = "removed";
+const char kSecureKey[] = "secure";
+const char kSessionKey[] = "session";
+const char kStoreIdKey[] = "storeId";
+const char kTabIdsKey[] = "tabIds";
+const char kUrlKey[] = "url";
+const char kValueKey[] = "value";
const char kOnChanged[] = "cookies.onChanged";
diff --git a/chrome/browser/extensions/extension_cookies_api_constants.h b/chrome/browser/extensions/extension_cookies_api_constants.h
index d9c0015..04b8035 100644
--- a/chrome/browser/extensions/extension_cookies_api_constants.h
+++ b/chrome/browser/extensions/extension_cookies_api_constants.h
@@ -6,25 +6,26 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_COOKIES_API_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_COOKIES_API_CONSTANTS_H_
+#pragma once
namespace extension_cookies_api_constants {
// Keys.
-extern const wchar_t kCookieKey[];
-extern const wchar_t kDomainKey[];
-extern const wchar_t kExpirationDateKey[];
-extern const wchar_t kHostOnlyKey[];
-extern const wchar_t kHttpOnlyKey[];
-extern const wchar_t kIdKey[];
-extern const wchar_t kNameKey[];
-extern const wchar_t kPathKey[];
-extern const wchar_t kRemovedKey[];
-extern const wchar_t kSecureKey[];
-extern const wchar_t kSessionKey[];
-extern const wchar_t kStoreIdKey[];
-extern const wchar_t kTabIdsKey[];
-extern const wchar_t kUrlKey[];
-extern const wchar_t kValueKey[];
+extern const char kCookieKey[];
+extern const char kDomainKey[];
+extern const char kExpirationDateKey[];
+extern const char kHostOnlyKey[];
+extern const char kHttpOnlyKey[];
+extern const char kIdKey[];
+extern const char kNameKey[];
+extern const char kPathKey[];
+extern const char kRemovedKey[];
+extern const char kSecureKey[];
+extern const char kSessionKey[];
+extern const char kStoreIdKey[];
+extern const char kTabIdsKey[];
+extern const char kUrlKey[];
+extern const char kValueKey[];
// Events.
extern const char kOnChanged[];
diff --git a/chrome/browser/extensions/extension_cookies_helpers.cc b/chrome/browser/extensions/extension_cookies_helpers.cc
index 2322c1d..ac00183 100644
--- a/chrome/browser/extensions/extension_cookies_helpers.cc
+++ b/chrome/browser/extensions/extension_cookies_helpers.cc
@@ -7,10 +7,12 @@
#include "chrome/browser/extensions/extension_cookies_helpers.h"
#include "base/logging.h"
+#include "base/values.h"
#include "chrome/browser/browser.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/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
@@ -26,9 +28,11 @@ Profile* ChooseProfileFromStoreId(const std::string& store_id,
Profile* profile,
bool include_incognito) {
DCHECK(profile);
- if (store_id == kOriginalProfileStoreId)
+ bool allow_original = !profile->IsOffTheRecord();
+ bool allow_incognito = profile->IsOffTheRecord() || include_incognito;
+ if (store_id == kOriginalProfileStoreId && allow_original)
return profile->GetOriginalProfile();
- if (store_id == kOffTheRecordProfileStoreId && include_incognito)
+ if (store_id == kOffTheRecordProfileStoreId && allow_incognito)
return profile->GetOffTheRecordProfile();
return NULL;
}
@@ -128,15 +132,14 @@ MatchFilter::MatchFilter(const DictionaryValue* details)
bool MatchFilter::MatchesCookie(
const net::CookieMonster::CanonicalCookie& cookie) {
- return
- MatchesString(keys::kNameKey, cookie.Name()) &&
- MatchesDomain(cookie.Domain()) &&
- MatchesString(keys::kPathKey, cookie.Path()) &&
- MatchesBoolean(keys::kSecureKey, cookie.IsSecure()) &&
- MatchesBoolean(keys::kSessionKey, !cookie.DoesExpire());
+ return MatchesString(keys::kNameKey, cookie.Name()) &&
+ MatchesDomain(cookie.Domain()) &&
+ MatchesString(keys::kPathKey, cookie.Path()) &&
+ MatchesBoolean(keys::kSecureKey, cookie.IsSecure()) &&
+ MatchesBoolean(keys::kSessionKey, !cookie.DoesExpire());
}
-bool MatchFilter::MatchesString(const wchar_t* key, const std::string& value) {
+bool MatchFilter::MatchesString(const char* key, const std::string& value) {
if (!details_->HasKey(key))
return true;
std::string filter_value;
@@ -144,7 +147,7 @@ bool MatchFilter::MatchesString(const wchar_t* key, const std::string& value) {
value == filter_value);
}
-bool MatchFilter::MatchesBoolean(const wchar_t* key, bool value) {
+bool MatchFilter::MatchesBoolean(const char* key, bool value) {
if (!details_->HasKey(key))
return true;
bool filter_value = false;
diff --git a/chrome/browser/extensions/extension_cookies_helpers.h b/chrome/browser/extensions/extension_cookies_helpers.h
index a06621f..7bb33d2 100644
--- a/chrome/browser/extensions/extension_cookies_helpers.h
+++ b/chrome/browser/extensions/extension_cookies_helpers.h
@@ -9,14 +9,16 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_COOKIES_HELPERS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_COOKIES_HELPERS_H_
+#pragma once
#include <string>
-#include "base/values.h"
#include "net/base/cookie_monster.h"
class Browser;
+class DictionaryValue;
class Extension;
+class ListValue;
class Profile;
namespace extension_cookies_helpers {
@@ -92,12 +94,12 @@ class MatchFilter {
// Returns true if the details dictionary contains a string with the given
// key and value. Also returns true if the dictionary doesn't contain the
// given key at all (trival match).
- bool MatchesString(const wchar_t* key, const std::string& value);
+ bool MatchesString(const char* key, const std::string& value);
// Returns true if the details dictionary contains a boolean with the given
// key and value. Also returns true if the dictionary doesn't contain the
// given key at all (trival match).
- bool MatchesBoolean(const wchar_t* key, bool value);
+ bool MatchesBoolean(const char* key, bool value);
// Returns true if the given cookie domain string matches the filter's
// domain. Any cookie domain which is equal to or is a subdomain of the
diff --git a/chrome/browser/extensions/extension_cookies_unittest.cc b/chrome/browser/extensions/extension_cookies_unittest.cc
index fbc1fdc..ec9084a 100644
--- a/chrome/browser/extensions/extension_cookies_unittest.cc
+++ b/chrome/browser/extensions/extension_cookies_unittest.cc
@@ -7,9 +7,11 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include "base/values.h"
#include "chrome/browser/extensions/extension_cookies_api_constants.h"
#include "chrome/browser/extensions/extension_cookies_helpers.h"
#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
namespace keys = extension_cookies_api_constants;
@@ -81,16 +83,16 @@ TEST_F(ExtensionCookiesTest, StoreIdProfileConversion) {
EXPECT_EQ(std::string("1"),
extension_cookies_helpers::GetStoreIdFromProfile(&otrProfile));
- EXPECT_EQ(&profile,
+ EXPECT_EQ(NULL,
extension_cookies_helpers::ChooseProfileFromStoreId(
"0", &otrProfile, true));
- EXPECT_EQ(&profile,
+ EXPECT_EQ(NULL,
extension_cookies_helpers::ChooseProfileFromStoreId(
"0", &otrProfile, false));
EXPECT_EQ(&otrProfile,
extension_cookies_helpers::ChooseProfileFromStoreId(
"1", &otrProfile, true));
- EXPECT_EQ(NULL,
+ EXPECT_EQ(&otrProfile,
extension_cookies_helpers::ChooseProfileFromStoreId(
"1", &otrProfile, false));
}
diff --git a/chrome/browser/extensions/extension_creator.h b/chrome/browser/extensions/extension_creator.h
index c483a70..6235584 100644
--- a/chrome/browser/extensions/extension_creator.h
+++ b/chrome/browser/extensions/extension_creator.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_CREATOR_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_CREATOR_H_
+#pragma once
#include <string>
#include <vector>
@@ -34,7 +35,7 @@ class ExtensionCreator {
std::string error_message() { return error_message_; }
private:
- // Verifies input directory's existance. |extension_dir| is the source
+ // Verifies input directory's existence. |extension_dir| is the source
// directory that should contain all the extension resources.
// |private_key_path| is the optional path to an existing private key to sign
// the extension. If not provided, a random key will be created (in which case
diff --git a/chrome/browser/extensions/extension_data_deleter.cc b/chrome/browser/extensions/extension_data_deleter.cc
index dec78eb..6c04755 100644
--- a/chrome/browser/extensions/extension_data_deleter.cc
+++ b/chrome/browser/extensions/extension_data_deleter.cc
@@ -4,11 +4,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/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"
ExtensionDataDeleter::ExtensionDataDeleter(Profile* profile,
const GURL& extension_url) {
@@ -21,6 +24,9 @@ ExtensionDataDeleter::ExtensionDataDeleter(Profile* profile,
webkit_database::DatabaseUtil::GetOriginIdentifier(extension_url_);
}
+ExtensionDataDeleter::~ExtensionDataDeleter() {
+}
+
void ExtensionDataDeleter::StartDeleting() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
diff --git a/chrome/browser/extensions/extension_data_deleter.h b/chrome/browser/extensions/extension_data_deleter.h
index 4b90509..567128f 100644
--- a/chrome/browser/extensions/extension_data_deleter.h
+++ b/chrome/browser/extensions/extension_data_deleter.h
@@ -4,18 +4,20 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DATA_DELETER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DATA_DELETER_H_
-
-#include <string>
+#pragma once
#include "base/ref_counted.h"
+#include "base/string16.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/common/net/url_request_context_getter.h"
#include "googleurl/src/gurl.h"
-#include "webkit/database/database_tracker.h"
-class Extension;
+namespace webkit_database {
+class DatabaseTracker;
+}
+
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
@@ -25,6 +27,7 @@ class ExtensionDataDeleter
ChromeThread::DeleteOnUIThread> {
public:
ExtensionDataDeleter(Profile* profile, const GURL& extension_url);
+ ~ExtensionDataDeleter();
// Start removing data. The extension should not be running when this is
// called. Cookies are deleted on the current thread, local storage and
diff --git a/chrome/browser/extensions/extension_devtools_bridge.cc b/chrome/browser/extensions/extension_devtools_bridge.cc
index d452c04..83cefdb 100644
--- a/chrome/browser/extensions/extension_devtools_bridge.cc
+++ b/chrome/browser/extensions/extension_devtools_bridge.cc
@@ -6,6 +6,7 @@
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/extensions/extension_devtools_events.h"
#include "chrome/browser/extensions/extension_devtools_manager.h"
@@ -65,7 +66,7 @@ void ExtensionDevToolsBridge::InspectedTabClosing() {
// event in extensions.
std::string json("[{}]");
profile_->GetExtensionMessageService()->DispatchEventToRenderers(
- on_tab_close_event_name_, json, profile_->IsOffTheRecord(), GURL());
+ on_tab_close_event_name_, json, profile_, GURL());
// This may result in this object being destroyed.
extension_devtools_manager_->BridgeClosingForTab(tab_id_);
@@ -73,22 +74,16 @@ void ExtensionDevToolsBridge::InspectedTabClosing() {
void ExtensionDevToolsBridge::SendMessageToClient(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(ExtensionDevToolsBridge, msg)
- IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage);
+ IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchToAPU, OnDispatchToAPU);
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
}
-static const char kApuAgentClassName[] = "ApuAgentDelegate";
-static const char kApuPageEventMessageName[] = "dispatchToApu";
-
-void ExtensionDevToolsBridge::OnRpcMessage(const DevToolsMessageData& data) {
+void ExtensionDevToolsBridge::OnDispatchToAPU(const std::string& data) {
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
- if (data.class_name == kApuAgentClassName
- && data.method_name == kApuPageEventMessageName) {
- std::string json = StringPrintf("[%s]", data.arguments[0].c_str());
- profile_->GetExtensionMessageService()->DispatchEventToRenderers(
- on_page_event_name_, json, profile_->IsOffTheRecord(), GURL());
- }
+ std::string json = base::StringPrintf("[%s]", data.c_str());
+ profile_->GetExtensionMessageService()->DispatchEventToRenderers(
+ on_page_event_name_, json, profile_, GURL());
}
diff --git a/chrome/browser/extensions/extension_devtools_bridge.h b/chrome/browser/extensions/extension_devtools_bridge.h
index 5543b97..ad103a2 100644
--- a/chrome/browser/extensions/extension_devtools_bridge.h
+++ b/chrome/browser/extensions/extension_devtools_bridge.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_BRIDGE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_BRIDGE_H_
+#pragma once
#include <string>
@@ -13,7 +14,6 @@
#include "chrome/browser/extensions/extension_message_service.h"
class Profile;
-struct DevToolsMessageData;
// This class is a DevToolsClientHost that fires extension events.
class ExtensionDevToolsBridge : public DevToolsClientHost {
@@ -32,7 +32,7 @@ class ExtensionDevToolsBridge : public DevToolsClientHost {
virtual void SendMessageToClient(const IPC::Message& msg);
private:
- void OnRpcMessage(const DevToolsMessageData& data);
+ void OnDispatchToAPU(const std::string& data);
// ID of the tab we are monitoring.
int tab_id_;
diff --git a/chrome/browser/extensions/extension_devtools_browsertest.cc b/chrome/browser/extensions/extension_devtools_browsertest.cc
index 85d34ac..b8f2300 100644
--- a/chrome/browser/extensions/extension_devtools_browsertest.cc
+++ b/chrome/browser/extensions/extension_devtools_browsertest.cc
@@ -1,9 +1,10 @@
-// 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.
#include "chrome/browser/extensions/extension_devtools_browsertest.h"
+#include "base/command_line.h"
#include "chrome/common/chrome_switches.h"
void ExtensionDevToolsBrowserTest::SetUpCommandLine(CommandLine* command_line) {
diff --git a/chrome/browser/extensions/extension_devtools_browsertest.h b/chrome/browser/extensions/extension_devtools_browsertest.h
index a29d3e5..1f7c3ee 100644
--- a/chrome/browser/extensions/extension_devtools_browsertest.h
+++ b/chrome/browser/extensions/extension_devtools_browsertest.h
@@ -1,13 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_BROWSERTEST_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_BROWSERTEST_H_
+#pragma once
-#include "base/command_line.h"
#include "chrome/browser/extensions/extension_browsertest.h"
+class CommandLine;
+
// Subclass of ExtensionBrowserTest that enables the devtools
// command line features.
class ExtensionDevToolsBrowserTest : public ExtensionBrowserTest {
diff --git a/chrome/browser/extensions/extension_devtools_browsertests.cc b/chrome/browser/extensions/extension_devtools_browsertests.cc
index a8e28ab..4afcb3c 100644
--- a/chrome/browser/extensions/extension_devtools_browsertests.cc
+++ b/chrome/browser/extensions/extension_devtools_browsertests.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/ref_counted.h"
+#include "base/stringprintf.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -17,6 +18,7 @@
#include "chrome/browser/profile.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"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/devtools_messages.h"
#include "chrome/common/notification_service.h"
@@ -45,7 +47,8 @@ static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager,
}
// Tests for the experimental timeline extensions API.
-IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, TimelineApi) {
+// TODO(johnnyg): crbug.com/52544 Test was broken by webkit r65510.
+IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, FLAKY_TimelineApi) {
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("devtools").AppendASCII("timeline_api")));
@@ -64,8 +67,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, TimelineApi) {
// Test setup.
bool result = false;
- std::wstring register_listeners_js = StringPrintf(L"setListenersOnTab(%d)",
- tab_id);
+ std::wstring register_listeners_js = base::StringPrintf(
+ L"setListenersOnTab(%d)", tab_id);
ui_test_utils::ExecuteJavaScriptAndExtractBool(
host->render_view_host(), L"", register_listeners_js, &result);
EXPECT_TRUE(result);
@@ -80,11 +83,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, TimelineApi) {
// Test onPageEvent event.
result = false;
- DevToolsMessageData message_data;
- message_data.class_name = "ApuAgentDelegate";
- message_data.method_name = "dispatchToApu";
- message_data.arguments.push_back("");
- DevToolsClientMsg_RpcMessage pageEventMessage(message_data);
+ DevToolsClientMsg_DispatchToAPU pageEventMessage("");
devtools_client_host->SendMessageToClient(pageEventMessage);
ui_test_utils::ExecuteJavaScriptAndExtractBool(
host->render_view_host(), L"", L"testReceivePageEvent()", &result);
@@ -124,8 +123,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, ProcessRefCounting) {
// Test setup.
bool result = false;
- std::wstring register_listeners_js = StringPrintf(L"setListenersOnTab(%d)",
- tab_id);
+ std::wstring register_listeners_js = base::StringPrintf(
+ L"setListenersOnTab(%d)", tab_id);
ui_test_utils::ExecuteJavaScriptAndExtractBool(
host_one->render_view_host(), L"", register_listeners_js, &result);
EXPECT_TRUE(result);
@@ -136,7 +135,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, ProcessRefCounting) {
tab_contents->render_view_host()));
// Register listeners from the second extension as well.
- std::wstring script = StringPrintf(L"registerListenersForTab(%d)", tab_id);
+ std::wstring script = base::StringPrintf(L"registerListenersForTab(%d)",
+ tab_id);
ui_test_utils::ExecuteJavaScriptAndExtractBool(
host_two->render_view_host(), L"", script, &result);
EXPECT_TRUE(result);
diff --git a/chrome/browser/extensions/extension_devtools_events.cc b/chrome/browser/extensions/extension_devtools_events.cc
index bec5577..f29d459 100644
--- a/chrome/browser/extensions/extension_devtools_events.cc
+++ b/chrome/browser/extensions/extension_devtools_events.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.
@@ -6,7 +6,10 @@
#include <vector>
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
// These string constants and the formats used in this file must stay
// in sync with chrome/renderer/resources/extension_process_bindings.js
@@ -26,7 +29,7 @@ bool ExtensionDevToolsEvents::IsDevToolsEventName(
// At this point we want something like "4.onPageEvent"
std::vector<std::string> parts;
SplitString(event_name.substr(strlen(kDevToolsEventPrefix)), '.', &parts);
- if (parts.size() == 2 && StringToInt(parts[0], tab_id)) {
+ if (parts.size() == 2 && base::StringToInt(parts[0], tab_id)) {
return true;
}
}
@@ -35,17 +38,17 @@ bool ExtensionDevToolsEvents::IsDevToolsEventName(
// static
std::string ExtensionDevToolsEvents::OnPageEventNameForTab(int tab_id) {
- return StringPrintf("%s%d.%s",
- kDevToolsEventPrefix,
- tab_id,
- kOnPageEventName);
+ return base::StringPrintf("%s%d.%s",
+ kDevToolsEventPrefix,
+ tab_id,
+ kOnPageEventName);
}
// static
std::string ExtensionDevToolsEvents::OnTabCloseEventNameForTab(int tab_id) {
- return StringPrintf("%s%d.%s",
- kDevToolsEventPrefix,
- tab_id,
- kOnTabCloseEventName);
+ return base::StringPrintf("%s%d.%s",
+ kDevToolsEventPrefix,
+ tab_id,
+ kOnTabCloseEventName);
}
diff --git a/chrome/browser/extensions/extension_devtools_events.h b/chrome/browser/extensions/extension_devtools_events.h
index c1dd363..255d14d 100644
--- a/chrome/browser/extensions/extension_devtools_events.h
+++ b/chrome/browser/extensions/extension_devtools_events.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_EVENTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_EVENTS_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/extensions/extension_devtools_manager.h b/chrome/browser/extensions/extension_devtools_manager.h
index f1337ef..dc28456 100644
--- a/chrome/browser/extensions/extension_devtools_manager.h
+++ b/chrome/browser/extensions/extension_devtools_manager.h
@@ -1,13 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_MANAGER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DEVTOOLS_MANAGER_H_
+#pragma once
#include <map>
#include <set>
#include <string>
+
#include "base/linked_ptr.h"
#include "base/ref_counted.h"
diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
index 18812a9..884a17a 100644
--- a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
+++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
@@ -4,7 +4,10 @@
#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
+#include <string>
+
#include "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extensions_service.h"
@@ -31,8 +34,8 @@ class ExtensionDisabledDialogDelegate
install_ui_->ConfirmInstall(this, extension_);
}
- // ExtensionInstallUI::Delegate
- virtual void InstallUIProceed(bool create_app_shortcut) {
+ // Overridden from ExtensionInstallUI::Delegate:
+ virtual void InstallUIProceed() {
ExtensionPrefs* prefs = service_->extension_prefs();
prefs->SetDidExtensionEscalatePermissions(extension_, false);
service_->EnableExtension(extension_->id());
@@ -74,9 +77,9 @@ class ExtensionDisabledInfobarDelegate
}
virtual ~ExtensionDisabledInfobarDelegate() {
}
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetStringF(IDS_EXTENSION_DISABLED_INFOBAR_LABEL,
- UTF8ToWide(extension_->name()));
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_INFOBAR_LABEL,
+ UTF8ToUTF16(extension_->name()));
}
virtual SkBitmap* GetIcon() const {
return NULL;
@@ -84,9 +87,10 @@ class ExtensionDisabledInfobarDelegate
virtual int GetButtons() const {
return BUTTON_OK;
}
- virtual std::wstring GetButtonLabel(
+ virtual string16 GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const {
- return l10n_util::GetString(IDS_EXTENSION_DISABLED_INFOBAR_ENABLE_BUTTON);
+ return l10n_util::GetStringUTF16(
+ IDS_EXTENSION_DISABLED_INFOBAR_ENABLE_BUTTON);
}
virtual bool Accept() {
// This object manages its own lifetime.
diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.h b/chrome/browser/extensions/extension_disabled_infobar_delegate.h
index 1e40f00..16d3b6f 100644
--- a/chrome/browser/extensions/extension_disabled_infobar_delegate.h
+++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.h
@@ -1,14 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DISABLED_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DISABLED_INFOBAR_DELEGATE_H_
-
-#include <string>
-
-#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/common/extensions/extension_resource.h"
+#pragma once
class Extension;
class ExtensionsService;
diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc
index 7cbe08f..81c234d 100644
--- a/chrome/browser/extensions/extension_dom_ui.cc
+++ b/chrome/browser/extensions/extension_dom_ui.cc
@@ -6,23 +6,25 @@
#include <set>
-#include "base/file_path.h"
-#include "base/file_util.h"
#include "net/base/file_stream.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
-#include "chrome/browser/pref_service.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/common/bindings_policy.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/url_constants.h"
#include "gfx/codec/png_codec.h"
@@ -70,7 +72,8 @@ class ExtensionDOMUIImageLoadingTracker : public ImageLoadingTracker::Observer {
void Init() {
if (extension_) {
ExtensionResource icon_resource =
- extension_->GetIconPath(Extension::EXTENSION_ICON_BITTY);
+ extension_->GetIconResource(Extension::EXTENSION_ICON_BITTY,
+ ExtensionIconSet::MATCH_EXACTLY);
tracker_.LoadImage(extension_, icon_resource,
gfx::Size(kFavIconSize, kFavIconSize),
@@ -116,18 +119,29 @@ class ExtensionDOMUIImageLoadingTracker : public ImageLoadingTracker::Observer {
} // namespace
-const wchar_t ExtensionDOMUI::kExtensionURLOverrides[] =
- L"extensions.chrome_url_overrides";
+const char ExtensionDOMUI::kExtensionURLOverrides[] =
+ "extensions.chrome_url_overrides";
-ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents)
+ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents, GURL url)
: DOMUI(tab_contents) {
- should_hide_url_ = true;
- bindings_ = BindingsPolicy::EXTENSION;
+ ExtensionsService* service = tab_contents->profile()->GetExtensionsService();
+ Extension* extension = service->GetExtensionByURL(url);
+ if (!extension)
+ extension = service->GetExtensionByWebExtent(url);
+ DCHECK(extension);
+ // Only hide the url for internal pages (e.g. chrome-extension or packaged
+ // component apps like bookmark manager.
+ should_hide_url_ = !extension->is_hosted_app();
+ bindings_ = BindingsPolicy::EXTENSION;
+ // Bind externalHost to Extension DOMUI loaded in Chrome Frame.
+ const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ if (browser_command_line.HasSwitch(switches::kChromeFrame))
+ bindings_ |= BindingsPolicy::EXTERNAL_HOST;
// For chrome:// overrides, some of the defaults are a little different.
- GURL url = tab_contents->GetURL();
- if (url.SchemeIs(chrome::kChromeUIScheme) &&
- url.host() == chrome::kChromeUINewTabHost) {
+ GURL effective_url = tab_contents->GetURL();
+ if (effective_url.SchemeIs(chrome::kChromeUIScheme) &&
+ effective_url.host() == chrome::kChromeUINewTabHost) {
focus_location_bar_by_default_ = true;
}
}
@@ -144,13 +158,14 @@ void ExtensionDOMUI::ResetExtensionFunctionDispatcher(
}
void ExtensionDOMUI::ResetExtensionBookmarkManagerEventRouter() {
- extension_bookmark_manager_event_router_.reset(
- new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents()));
- // We set the link transition type to AUTO_BOOKMARK for the bookmark manager.
- // This doesn't really belong here, but neither does this function.
- // ExtensionDOMUI could potentially be used for extensions besides the
- // bookmark manager, but currently it does not.
- link_transition_type_ = PageTransition::AUTO_BOOKMARK;
+ // Hack: A few things we specialize just for the bookmark manager.
+ if (extension_function_dispatcher_->extension_id() ==
+ extension_misc::kBookmarkManagerId) {
+ extension_bookmark_manager_event_router_.reset(
+ new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents()));
+
+ link_transition_type_ = PageTransition::AUTO_BOOKMARK;
+ }
}
void ExtensionDOMUI::RenderViewCreated(RenderViewHost* render_view_host) {
@@ -163,25 +178,15 @@ void ExtensionDOMUI::RenderViewReused(RenderViewHost* render_view_host) {
ResetExtensionBookmarkManagerEventRouter();
}
-void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
- extension_function_dispatcher_->HandleRequest(message,
- content,
- source_url,
- request_id,
- has_callback);
+void ExtensionDOMUI::ProcessDOMUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {
+ extension_function_dispatcher_->HandleRequest(params);
}
Browser* ExtensionDOMUI::GetBrowser() const {
- Browser* browser = NULL;
- TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
- if (tab_contents_delegate)
- browser = tab_contents_delegate->GetBrowser();
-
- return browser;
+ // TODO(beng): This is an improper direct dependency on Browser. Route this
+ // through some sort of delegate.
+ return BrowserList::FindBrowserWithProfile(DOMUI::GetProfile());
}
Profile* ExtensionDOMUI::GetProfile() {
@@ -219,15 +224,11 @@ bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) {
if (!url->SchemeIs(chrome::kChromeUIScheme))
return false;
- // We can't handle chrome-extension URLs in incognito mode.
- if (profile->IsOffTheRecord())
- return false;
-
const DictionaryValue* overrides =
profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
std::string page = url->host();
ListValue* url_list;
- if (!overrides || !overrides->GetList(UTF8ToWide(page), &url_list))
+ if (!overrides || !overrides->GetList(page, &url_list))
return false;
ExtensionsService* service = profile->GetExtensionsService();
@@ -239,9 +240,10 @@ bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) {
return false;
}
- while (url_list->GetSize()) {
- Value* val;
- url_list->Get(0, &val);
+ size_t i = 0;
+ while (i < url_list->GetSize()) {
+ Value* val = NULL;
+ url_list->Get(i, &val);
// Verify that the override value is good. If not, unregister it and find
// the next one.
@@ -269,6 +271,16 @@ bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) {
continue;
}
+ // We can't handle chrome-extension URLs in incognito mode unless the
+ // extension uses split mode.
+ bool incognito_override_allowed =
+ extension->incognito_split_mode() &&
+ service->IsIncognitoEnabled(extension);
+ if (profile->IsOffTheRecord() && !incognito_override_allowed) {
+ ++i;
+ continue;
+ }
+
*url = extension_url;
return true;
}
@@ -288,8 +300,8 @@ void ExtensionDOMUI::RegisterChromeURLOverrides(
// For each override provided by the extension, add it to the front of
// the override list if it's not already in the list.
Extension::URLOverrideMap::const_iterator iter = overrides.begin();
- for (;iter != overrides.end(); ++iter) {
- const std::wstring key = UTF8ToWide((*iter).first);
+ for (; iter != overrides.end(); ++iter) {
+ const std::string& key = iter->first;
ListValue* page_overrides;
if (!all_overrides->GetList(key, &page_overrides)) {
page_overrides = new ListValue();
@@ -305,7 +317,7 @@ void ExtensionDOMUI::RegisterChromeURLOverrides(
NOTREACHED();
continue;
}
- if (override_val == (*iter).second.spec())
+ if (override_val == iter->second.spec())
break;
}
// This value is already in the list, leave it alone.
@@ -314,7 +326,7 @@ void ExtensionDOMUI::RegisterChromeURLOverrides(
}
// Insert the override at the front of the list. Last registered override
// wins.
- page_overrides->Insert(0, new StringValue((*iter).second.spec()));
+ page_overrides->Insert(0, new StringValue(iter->second.spec()));
}
}
@@ -350,7 +362,7 @@ void ExtensionDOMUI::UnregisterChromeURLOverride(const std::string& page,
DictionaryValue* all_overrides =
prefs->GetMutableDictionary(kExtensionURLOverrides);
ListValue* page_overrides;
- if (!all_overrides->GetList(UTF8ToWide(page), &page_overrides)) {
+ if (!all_overrides->GetList(page, &page_overrides)) {
// If it's being unregistered, it should already be in the list.
NOTREACHED();
return;
@@ -368,16 +380,16 @@ void ExtensionDOMUI::UnregisterChromeURLOverrides(
DictionaryValue* all_overrides =
prefs->GetMutableDictionary(kExtensionURLOverrides);
Extension::URLOverrideMap::const_iterator iter = overrides.begin();
- for (;iter != overrides.end(); ++iter) {
- std::wstring page = UTF8ToWide((*iter).first);
+ for (; iter != overrides.end(); ++iter) {
+ const std::string& page = iter->first;
ListValue* page_overrides;
if (!all_overrides->GetList(page, &page_overrides)) {
// If it's being unregistered, it should already be in the list.
NOTREACHED();
continue;
} else {
- StringValue override((*iter).second.spec());
- UnregisterAndReplaceOverride((*iter).first, profile,
+ StringValue override(iter->second.spec());
+ UnregisterAndReplaceOverride(iter->first, profile,
page_overrides, &override);
}
}
diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h
index a89592e..a6c598f 100644
--- a/chrome/browser/extensions/extension_dom_ui.h
+++ b/chrome/browser/extensions/extension_dom_ui.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_DOM_UI_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DOM_UI_H_
+#pragma once
#include <string>
@@ -14,22 +15,25 @@
#include "chrome/browser/favicon_service.h"
#include "chrome/common/extensions/extension.h"
+class GURL;
class ListValue;
class PrefService;
class Profile;
-class RefCountedMemory;
class RenderViewHost;
class TabContents;
+struct ViewHostMsg_DomMessage_Params;
// This class implements DOMUI for extensions and allows extensions to put UI in
-// the main tab contents area.
+// the main tab contents area. For example, each extension can specify an
+// "options_page", and that page is displayed in the tab contents area and is
+// hosted by this class.
class ExtensionDOMUI
: public DOMUI,
public ExtensionFunctionDispatcher::Delegate {
public:
- static const wchar_t kExtensionURLOverrides[];
+ static const char kExtensionURLOverrides[];
- explicit ExtensionDOMUI(TabContents* tab_contents);
+ explicit ExtensionDOMUI(TabContents* tab_contents, GURL url);
ExtensionFunctionDispatcher* extension_function_dispatcher() const {
return extension_function_dispatcher_.get();
@@ -38,17 +42,15 @@ class ExtensionDOMUI
// DOMUI
virtual void RenderViewCreated(RenderViewHost* render_view_host);
virtual void RenderViewReused(RenderViewHost* render_view_host);
- virtual void ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback);
+ virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params);
// ExtensionFunctionDispatcher::Delegate
virtual Browser* GetBrowser() const;
virtual gfx::NativeView GetNativeViewOfHost();
virtual gfx::NativeWindow GetCustomFrameNativeWindow();
- virtual TabContents* associated_tab_contents() { return tab_contents(); }
+ virtual TabContents* associated_tab_contents() const {
+ return tab_contents();
+ }
virtual Profile* GetProfile();
virtual ExtensionBookmarkManagerEventRouter*
@@ -95,6 +97,8 @@ class ExtensionDOMUI
scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+ // TODO(aa): This seems out of place. Why is it not with the event routers for
+ // the other extension APIs?
scoped_ptr<ExtensionBookmarkManagerEventRouter>
extension_bookmark_manager_event_router_;
};
diff --git a/chrome/browser/extensions/extension_error_reporter.h b/chrome/browser/extensions/extension_error_reporter.h
index f4205e9..824ac9e 100644
--- a/chrome/browser/extensions/extension_error_reporter.h
+++ b/chrome/browser/extensions/extension_error_reporter.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ERROR_REPORTER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_ERROR_REPORTER_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/extensions/extension_event_names.cc b/chrome/browser/extensions/extension_event_names.cc
index 421bab8..a70f293 100644
--- a/chrome/browser/extensions/extension_event_names.cc
+++ b/chrome/browser/extensions/extension_event_names.cc
@@ -13,9 +13,14 @@ const char kOnTabMoved[] = "tabs.onMoved";
const char kOnTabRemoved[] = "tabs.onRemoved";
const char kOnTabSelectionChanged[] = "tabs.onSelectionChanged";
const char kOnTabUpdated[] = "tabs.onUpdated";
+
const char kOnWindowCreated[] = "windows.onCreated";
const char kOnWindowFocusedChanged[] = "windows.onFocusChanged";
const char kOnWindowRemoved[] = "windows.onRemoved";
-} // namespace extension_event_names
+const char kOnExtensionInstalled[] = "experimental.management.onInstalled";
+const char kOnExtensionUninstalled[] = "experimental.management.onUninstalled";
+const char kOnExtensionEnabled[] = "experimental.management.onEnabled";
+const char kOnExtensionDisabled[] = "experimental.management.onDisabled";
+} // namespace extension_event_names
diff --git a/chrome/browser/extensions/extension_event_names.h b/chrome/browser/extensions/extension_event_names.h
index 3e3673a..3c63f90 100644
--- a/chrome/browser/extensions/extension_event_names.h
+++ b/chrome/browser/extensions/extension_event_names.h
@@ -6,9 +6,11 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_EVENT_NAMES_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_EVENT_NAMES_H_
+#pragma once
namespace extension_event_names {
+// Tabs.
extern const char kOnTabAttached[];
extern const char kOnTabCreated[];
extern const char kOnTabDetached[];
@@ -16,11 +18,19 @@ extern const char kOnTabMoved[];
extern const char kOnTabRemoved[];
extern const char kOnTabSelectionChanged[];
extern const char kOnTabUpdated[];
+
+// Windows.
extern const char kOnWindowCreated[];
extern const char kOnWindowFocusedChanged[];
extern const char kOnWindowRemoved[];
+// Management.
+extern const char kOnExtensionInstalled[];
+extern const char kOnExtensionUninstalled[];
+extern const char kOnExtensionEnabled[];
+extern const char kOnExtensionDisabled[];
+
+
}; // namespace extension_event_names
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_EVENT_NAMES_H_
-
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 6f5b100..50babe1 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -11,7 +11,10 @@
#include "chrome/browser/profile.h"
ExtensionFunction::ExtensionFunction()
- : request_id_(-1), name_(""), has_callback_(false) {
+ : request_id_(-1),
+ profile_(NULL),
+ has_callback_(false),
+ include_incognito_(false) {
}
ExtensionFunction::~ExtensionFunction() {
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index a13845c..b48d0a9 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -4,18 +4,20 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_H_
+#pragma once
#include <string>
#include <list>
-#include "base/values.h"
#include "base/scoped_ptr.h"
#include "base/ref_counted.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
class ExtensionFunctionDispatcher;
+class ListValue;
class Profile;
class QuotaLimitHeuristic;
+class Value;
#define EXTENSION_FUNCTION_VALIDATE(test) do { \
if (!(test)) { \
@@ -88,6 +90,9 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> {
void set_include_incognito(bool include) { include_incognito_ = include; }
bool include_incognito() { return include_incognito_; }
+ void set_user_gesture(bool user_gesture) { user_gesture_ = user_gesture; }
+ bool user_gesture() const { return user_gesture_; }
+
// Execute the API. Clients should call set_raw_args() and
// set_request_id() before calling this method. Derived classes should be
// ready to return raw_result() and error() before returning from this
@@ -144,9 +149,15 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> {
// of this call.
bool has_callback_;
- // True if this callback should include information from incognito contexts.
+ // True if this callback should include information from incognito contexts
+ // even if our profile_ is non-incognito. Note that in the case of a "split"
+ // mode extension, this will always be false, and we will limit access to
+ // data from within the same profile_ (either incognito or not).
bool include_incognito_;
+ // True if the call was made in response of user gesture.
+ bool user_gesture_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionFunction);
};
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 4959310..c1867ca 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include <map>
+
#include "base/process_util.h"
#include "base/singleton.h"
#include "base/ref_counted.h"
@@ -13,11 +15,11 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
+#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/extensions/execute_code_in_tab_function.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
#include "chrome/browser/extensions/extension_bookmarks_module.h"
-#include "chrome/browser/extensions/extension_bookmarks_module_constants.h"
#include "chrome/browser/extensions/extension_browser_actions_api.h"
#include "chrome/browser/extensions/extension_clipboard_api.h"
#include "chrome/browser/extensions/extension_context_menu_api.h"
@@ -28,27 +30,35 @@
#include "chrome/browser/extensions/extension_idle_api.h"
#include "chrome/browser/extensions/extension_i18n_api.h"
#include "chrome/browser/extensions/extension_infobar_module.h"
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/extensions/extension_input_api.h"
+#endif
+#include "chrome/browser/extensions/extension_management_api.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_metrics_module.h"
#include "chrome/browser/extensions/extension_omnibox_api.h"
#include "chrome/browser/extensions/extension_page_actions_module.h"
-#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
#include "chrome/browser/extensions/extension_popup_api.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_processes_api.h"
+#include "chrome/browser/extensions/extension_proxy_api.h"
#include "chrome/browser/extensions/extension_rlz_module.h"
+#include "chrome/browser/extensions/extension_sidebar_api.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extension_tabs_module_constants.h"
#include "chrome/browser/extensions/extension_test_api.h"
-#include "chrome/browser/extensions/extension_toolstrip_api.h"
+#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/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/result_codes.h"
#include "chrome/common/url_constants.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
// FactoryRegistry -------------------------------------------------------------
@@ -176,10 +186,6 @@ void FactoryRegistry::ResetFunctions() {
// Idle
RegisterFunction<ExtensionIdleQueryStateFunction>();
- // Toolstrips.
- RegisterFunction<ToolstripExpandFunction>();
- RegisterFunction<ToolstripCollapseFunction>();
-
// I18N.
RegisterFunction<GetAcceptLanguagesFunction>();
@@ -221,11 +227,17 @@ void FactoryRegistry::ResetFunctions() {
RegisterFunction<ExtensionTestLogFunction>();
RegisterFunction<ExtensionTestQuotaResetFunction>();
RegisterFunction<ExtensionTestCreateIncognitoTabFunction>();
+ RegisterFunction<ExtensionTestSendMessageFunction>();
// Accessibility.
RegisterFunction<GetFocusedControlFunction>();
RegisterFunction<SetAccessibilityEnabledFunction>();
+ // Text-to-speech.
+ RegisterFunction<ExtensionTtsSpeakFunction>();
+ RegisterFunction<ExtensionTtsStopSpeakingFunction>();
+ RegisterFunction<ExtensionTtsIsSpeakingFunction>();
+
// Clipboard.
RegisterFunction<ExecuteCopyClipboardFunction>();
RegisterFunction<ExecuteCutClipboardFunction>();
@@ -239,6 +251,37 @@ void FactoryRegistry::ResetFunctions() {
// Omnibox.
RegisterFunction<OmniboxSendSuggestionsFunction>();
+
+ // Proxies.
+ RegisterFunction<UseCustomProxySettingsFunction>();
+
+ // Sidebar.
+ RegisterFunction<CollapseSidebarFunction>();
+ RegisterFunction<ExpandSidebarFunction>();
+ RegisterFunction<GetStateSidebarFunction>();
+ RegisterFunction<HideSidebarFunction>();
+ RegisterFunction<NavigateSidebarFunction>();
+ RegisterFunction<SetBadgeTextSidebarFunction>();
+ RegisterFunction<SetIconSidebarFunction>();
+ RegisterFunction<SetTitleSidebarFunction>();
+ RegisterFunction<ShowSidebarFunction>();
+
+#if defined(TOOLKIT_VIEWS)
+ // Input.
+ RegisterFunction<SendKeyboardEventInputFunction>();
+#endif
+
+ // Management.
+ RegisterFunction<GetAllExtensionsFunction>();
+ RegisterFunction<LaunchAppFunction>();
+ RegisterFunction<SetEnabledFunction>();
+ RegisterFunction<UninstallFunction>();
+
+ // WebstorePrivate.
+ RegisterFunction<GetSyncLoginFunction>();
+ RegisterFunction<GetStoreLoginFunction>();
+ RegisterFunction<InstallFunction>();
+ RegisterFunction<SetStoreLoginFunction>();
}
void FactoryRegistry::GetAllNames(std::vector<std::string>* names) {
@@ -293,7 +336,13 @@ ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create(
render_view_host->process()->profile()->GetExtensionsService();
DCHECK(service);
+ if (!service->ExtensionBindingsAllowed(url))
+ return NULL;
+
Extension* extension = service->GetExtensionByURL(url);
+ if (!extension)
+ extension = service->GetExtensionByWebExtent(url);
+
if (extension)
return new ExtensionFunctionDispatcher(render_view_host, delegate,
extension, url);
@@ -310,10 +359,12 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
render_view_host_(render_view_host),
delegate_(delegate),
url_(url),
+ extension_id_(extension->id()),
ALLOW_THIS_IN_INITIALIZER_LIST(peer_(new Peer(this))) {
// TODO(erikkay) should we do something for these errors in Release?
- DCHECK(url.SchemeIs(chrome::kExtensionScheme));
DCHECK(extension);
+ DCHECK(url.SchemeIs(chrome::kExtensionScheme) ||
+ extension->location() == Extension::COMPONENT);
// Notify the ExtensionProcessManager that the view was created.
ExtensionProcessManager* epm = profile()->GetExtensionProcessManager();
@@ -343,7 +394,7 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
render_view_host->Send(new ViewMsg_Extension_SetHostPermissions(
extension->url(), extension->host_permissions()));
render_view_host->Send(new ViewMsg_Extension_ExtensionSetIncognitoEnabled(
- extension->id(), incognito_enabled));
+ extension->id(), incognito_enabled, extension->incognito_split_mode()));
NotificationService::current()->Notify(
NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED,
@@ -364,54 +415,59 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
bool include_incognito) {
Browser* browser = delegate_->GetBrowser();
- // If the delegate has an associated browser and that browser is in the right
- // incognito state, we can return it.
- if (browser) {
- if (include_incognito || !browser->profile()->IsOffTheRecord())
- return browser;
- }
+ // If the delegate has an associated browser, that is always the right answer.
+ if (browser)
+ return browser;
- // Otherwise, try to default to a reasonable browser.
+ // Otherwise, try to default to a reasonable browser. If |include_incognito|
+ // is true, we will also search browsers in the incognito version of this
+ // profile. Note that the profile may already be incognito, in which case
+ // we will search the incognito version only, regardless of the value of
+ // |include_incognito|.
Profile* profile = render_view_host()->process()->profile();
-
- // Make sure we don't return an incognito browser without proper access.
- if (!include_incognito)
- profile = profile->GetOriginalProfile();
-
- browser = BrowserList::FindBrowserWithType(profile, Browser::TYPE_ANY,
+ browser = BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL,
include_incognito);
// NOTE(rafaelw): This can return NULL in some circumstances. In particular,
- // a toolstrip or background_page onload chrome.tabs api call can make it
- // into here before the browser is sufficiently initialized to return here.
+ // a background_page onload chrome.tabs api call can make it into here
+ // before the browser is sufficiently initialized to return here.
// A similar situation may arise during shutdown.
// TODO(rafaelw): Delay creation of background_page until the browser
// is available. http://code.google.com/p/chromium/issues/detail?id=13284
return browser;
}
-void ExtensionFunctionDispatcher::HandleRequest(const std::string& name,
- const ListValue* args,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
+void ExtensionFunctionDispatcher::HandleRequest(
+ const ViewHostMsg_DomMessage_Params& params) {
scoped_refptr<ExtensionFunction> function(
- FactoryRegistry::instance()->NewFunction(name));
+ FactoryRegistry::instance()->NewFunction(params.name));
function->set_dispatcher_peer(peer_);
function->set_profile(profile_);
function->set_extension_id(extension_id());
- function->SetArgs(args);
- function->set_source_url(source_url);
- function->set_request_id(request_id);
- function->set_has_callback(has_callback);
+ function->SetArgs(&params.arguments);
+ function->set_source_url(params.source_url);
+ 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();
DCHECK(service);
Extension* extension = service->GetExtensionById(extension_id(), false);
DCHECK(extension);
- function->set_include_incognito(service->IsIncognitoEnabled(extension));
+ function->set_include_incognito(service->IsIncognitoEnabled(extension) &&
+ !extension->incognito_split_mode());
+
+ if (!service->ExtensionBindingsAllowed(function->source_url()) ||
+ !extension->HasApiPermission(function->name())) {
+ render_view_host_->BlockExtensionRequest(function->request_id());
+ return;
+ }
ExtensionsQuotaService* quota = service->quota_service();
- if (quota->Assess(extension_id(), function, args, base::TimeTicks::Now())) {
+ if (quota->Assess(extension_id(), function, &params.arguments,
+ base::TimeTicks::Now())) {
+ // See crbug.com/39178.
+ ExternalProtocolHandler::PermitLaunchUrl();
+
function->Run();
} else {
render_view_host_->SendExtensionResponse(function->request_id(), false,
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index d9b973d..99328f7 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -1,12 +1,12 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DISPATCHER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DISPATCHER_H_
+#pragma once
#include <string>
-#include <set>
#include <vector>
#include "base/ref_counted.h"
@@ -15,14 +15,12 @@
class Browser;
class Extension;
-class ExtensionDOMUI;
class ExtensionFunction;
-class ExtensionHost;
class ListValue;
class Profile;
class RenderViewHost;
-class RenderViewHostDelegate;
class TabContents;
+struct ViewHostMsg_DomMessage_Params;
// A factory function for creating new ExtensionFunction instances.
typedef ExtensionFunction* (*ExtensionFunctionFactory)();
@@ -53,7 +51,7 @@ class ExtensionFunctionDispatcher {
// context. For example, the TabContents in which an infobar or
// chrome-extension://<id> URL are being shown. Callers must check for a
// NULL return value (as in the case of a background page).
- virtual TabContents* associated_tab_contents() = 0;
+ virtual TabContents* associated_tab_contents() const = 0;
protected:
virtual ~Delegate() {}
@@ -95,8 +93,7 @@ class ExtensionFunctionDispatcher {
Delegate* delegate() { return delegate_; }
// Handle a request to execute an extension function.
- void HandleRequest(const std::string& name, const ListValue* args,
- const GURL& source_url, int request_id, bool has_callback);
+ void HandleRequest(const ViewHostMsg_DomMessage_Params& params);
// Send a response to a function.
void SendResponse(ExtensionFunction* api, bool success);
@@ -117,7 +114,7 @@ class ExtensionFunctionDispatcher {
const GURL& url() { return url_; }
// Gets the ID for this extension.
- const std::string extension_id() { return url_.host(); }
+ const std::string extension_id() { return extension_id_; }
// The profile that this dispatcher is associated with.
Profile* profile();
@@ -142,6 +139,8 @@ class ExtensionFunctionDispatcher {
GURL url_;
+ std::string extension_id_;
+
scoped_refptr<Peer> peer_;
// AutomationExtensionFunction requires access to the RenderViewHost
diff --git a/chrome/browser/extensions/extension_history_api.cc b/chrome/browser/extensions/extension_history_api.cc
index 23f861f..fac0e1f 100644
--- a/chrome/browser/extensions/extension_history_api.cc
+++ b/chrome/browser/extensions/extension_history_api.cc
@@ -7,7 +7,7 @@
#include "base/callback.h"
#include "base/json/json_writer.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/task.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_history_api_constants.h"
@@ -28,9 +28,9 @@ double MilliSecondsFromTime(const base::Time& time) {
void GetHistoryItemDictionary(const history::URLRow& row,
DictionaryValue* value) {
- value->SetString(keys::kIdKey, Int64ToString(row.id()));
+ value->SetString(keys::kIdKey, base::Int64ToString(row.id()));
value->SetString(keys::kUrlKey, row.url().spec());
- value->SetStringFromUTF16(keys::kTitleKey, row.title());
+ value->SetString(keys::kTitleKey, row.title());
value->SetReal(keys::kLastVisitdKey, MilliSecondsFromTime(row.last_visit()));
value->SetInteger(keys::kTypedCountKey, row.typed_count());
value->SetInteger(keys::kVisitCountKey, row.visit_count());
@@ -44,11 +44,11 @@ void AddHistoryNode(const history::URLRow& row, ListValue* list) {
void GetVisitInfoDictionary(const history::VisitRow& row,
DictionaryValue* value) {
- value->SetString(keys::kIdKey, Int64ToString(row.url_id));
- value->SetString(keys::kVisitId, Int64ToString(row.visit_id));
+ value->SetString(keys::kIdKey, base::Int64ToString(row.url_id));
+ value->SetString(keys::kVisitId, base::Int64ToString(row.visit_id));
value->SetReal(keys::kVisitTime, MilliSecondsFromTime(row.visit_time));
value->SetString(keys::kReferringVisitId,
- Int64ToString(row.referring_visit));
+ base::Int64ToString(row.referring_visit));
const char* trans = PageTransition::CoreTransitionString(row.transition);
DCHECK(trans) << "Invalid transition.";
@@ -143,7 +143,7 @@ void ExtensionHistoryEventRouter::DispatchEvent(Profile* profile,
const std::string& json_args) {
if (profile && profile->GetExtensionMessageService()) {
profile->GetExtensionMessageService()->DispatchEventToRenderers(
- event_name, json_args, profile->IsOffTheRecord(), GURL());
+ event_name, json_args, profile, GURL());
}
}
@@ -180,10 +180,19 @@ bool HistoryFunction::GetTimeFromValue(Value* value, base::Time* time) {
// The history service has seconds resolution, while javascript Date() has
// milliseconds resolution.
double seconds_from_epoch = ms_from_epoch / 1000.0;
- *time = base::Time::FromDoubleT(seconds_from_epoch);
+ // Time::FromDoubleT converts double time 0 to empty Time object. So we need
+ // to do special handling here.
+ *time = (seconds_from_epoch == 0) ?
+ base::Time::UnixEpoch() : base::Time::FromDoubleT(seconds_from_epoch);
return true;
}
+HistoryFunctionWithCallback::HistoryFunctionWithCallback() {
+}
+
+HistoryFunctionWithCallback::~HistoryFunctionWithCallback() {
+}
+
bool HistoryFunctionWithCallback::RunImpl() {
AddRef(); // Balanced in SendAysncRepose() and below.
bool retval = RunAsyncImpl();
@@ -248,8 +257,7 @@ bool SearchHistoryFunction::RunAsyncImpl() {
// Initialize the HistoryQuery
string16 search_text;
- EXTENSION_FUNCTION_VALIDATE(json->GetStringAsUTF16(keys::kTextKey,
- &search_text));
+ EXTENSION_FUNCTION_VALIDATE(json->GetString(keys::kTextKey, &search_text));
history::QueryOptions options;
options.SetRecentDayRange(1);
@@ -305,7 +313,7 @@ bool AddUrlHistoryFunction::RunImpl() {
return false;
HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
- hs->AddPage(url);
+ hs->AddPage(url, history::SOURCE_EXTENSION);
SendResponse(true);
return true;
@@ -363,7 +371,7 @@ bool DeleteAllHistoryFunction::RunAsyncImpl() {
HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
hs->ExpireHistoryBetween(
restrict_urls,
- base::Time::FromDoubleT(0), // From the beginning of the epoch.
+ base::Time::UnixEpoch(), // From the beginning of the epoch.
base::Time::Now(), // To the current time.
&cancelable_consumer_,
NewCallback(this, &DeleteAllHistoryFunction::DeleteComplete));
diff --git a/chrome/browser/extensions/extension_history_api.h b/chrome/browser/extensions/extension_history_api.h
index 8cff707..9bd89e3 100644
--- a/chrome/browser/extensions/extension_history_api.h
+++ b/chrome/browser/extensions/extension_history_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_HISTORY_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_HISTORY_API_H_
+#pragma once
#include <map>
#include <string>
@@ -70,6 +71,9 @@ class HistoryFunction : public AsyncExtensionFunction {
// chrome services and the extension thread.
class HistoryFunctionWithCallback : public HistoryFunction {
public:
+ HistoryFunctionWithCallback();
+ ~HistoryFunctionWithCallback();
+
// Return true if the async call was completed, false otherwise.
virtual bool RunAsyncImpl() = 0;
diff --git a/chrome/browser/extensions/extension_history_api_constants.cc b/chrome/browser/extensions/extension_history_api_constants.cc
index 927f76e..b04b7eb 100644
--- a/chrome/browser/extensions/extension_history_api_constants.cc
+++ b/chrome/browser/extensions/extension_history_api_constants.cc
@@ -6,25 +6,25 @@
namespace extension_history_api_constants {
-const wchar_t kAllHistoryKey[] = L"allHistory";
-const wchar_t kEndTimeKey[] = L"endTime";
-const wchar_t kFavIconUrlKey[] = L"favIconUrl";
-const wchar_t kIdKey[] = L"id";
-const wchar_t kLastVisitdKey[] = L"lastVisitTime";
-const wchar_t kMaxResultsKey[] = L"maxResults";
-const wchar_t kNewKey[] = L"new";
-const wchar_t kReferringVisitId[] = L"referringVisitId";
-const wchar_t kRemovedKey[] = L"removed";
-const wchar_t kStartTimeKey[] = L"startTime";
-const wchar_t kTextKey[] = L"text";
-const wchar_t kTitleKey[] = L"title";
-const wchar_t kTypedCountKey[] = L"typedCount";
-const wchar_t kVisitCountKey[] = L"visitCount";
-const wchar_t kTransition[] = L"transition";
-const wchar_t kUrlKey[] = L"url";
-const wchar_t kUrlsKey[] = L"urls";
-const wchar_t kVisitId[] = L"visitId";
-const wchar_t kVisitTime[] = L"visitTime";
+const char kAllHistoryKey[] = "allHistory";
+const char kEndTimeKey[] = "endTime";
+const char kFavIconUrlKey[] = "favIconUrl";
+const char kIdKey[] = "id";
+const char kLastVisitdKey[] = "lastVisitTime";
+const char kMaxResultsKey[] = "maxResults";
+const char kNewKey[] = "new";
+const char kReferringVisitId[] = "referringVisitId";
+const char kRemovedKey[] = "removed";
+const char kStartTimeKey[] = "startTime";
+const char kTextKey[] = "text";
+const char kTitleKey[] = "title";
+const char kTypedCountKey[] = "typedCount";
+const char kVisitCountKey[] = "visitCount";
+const char kTransition[] = "transition";
+const char kUrlKey[] = "url";
+const char kUrlsKey[] = "urls";
+const char kVisitId[] = "visitId";
+const char kVisitTime[] = "visitTime";
const char kOnVisited[] = "history.onVisited";
const char kOnVisitRemoved[] = "history.onVisitRemoved";
diff --git a/chrome/browser/extensions/extension_history_api_constants.h b/chrome/browser/extensions/extension_history_api_constants.h
index 77596ab..6417b9e 100644
--- a/chrome/browser/extensions/extension_history_api_constants.h
+++ b/chrome/browser/extensions/extension_history_api_constants.h
@@ -6,29 +6,30 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_HISTORY_API_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_HISTORY_API_CONSTANTS_H_
+#pragma once
namespace extension_history_api_constants {
// Keys.
-extern const wchar_t kAllHistoryKey[];
-extern const wchar_t kEndTimeKey[];
-extern const wchar_t kFavIconUrlKey[];
-extern const wchar_t kIdKey[];
-extern const wchar_t kLastVisitdKey[];
-extern const wchar_t kMaxResultsKey[];
-extern const wchar_t kNewKey[];
-extern const wchar_t kReferringVisitId[];
-extern const wchar_t kRemovedKey[];
-extern const wchar_t kStartTimeKey[];
-extern const wchar_t kTextKey[];
-extern const wchar_t kTitleKey[];
-extern const wchar_t kTypedCountKey[];
-extern const wchar_t kVisitCountKey[];
-extern const wchar_t kTransition[];
-extern const wchar_t kUrlKey[];
-extern const wchar_t kUrlsKey[];
-extern const wchar_t kVisitId[];
-extern const wchar_t kVisitTime[];
+extern const char kAllHistoryKey[];
+extern const char kEndTimeKey[];
+extern const char kFavIconUrlKey[];
+extern const char kIdKey[];
+extern const char kLastVisitdKey[];
+extern const char kMaxResultsKey[];
+extern const char kNewKey[];
+extern const char kReferringVisitId[];
+extern const char kRemovedKey[];
+extern const char kStartTimeKey[];
+extern const char kTextKey[];
+extern const char kTitleKey[];
+extern const char kTypedCountKey[];
+extern const char kVisitCountKey[];
+extern const char kTransition[];
+extern const char kUrlKey[];
+extern const char kUrlsKey[];
+extern const char kVisitId[];
+extern const char kVisitTime[];
// Events.
extern const char kOnVisited[];
diff --git a/chrome/browser/extensions/extension_history_apitest.cc b/chrome/browser/extensions/extension_history_apitest.cc
index a9a99ef..9815ac8 100644
--- a/chrome/browser/extensions/extension_history_apitest.cc
+++ b/chrome/browser/extensions/extension_history_apitest.cc
@@ -11,7 +11,7 @@
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_History) {
host_resolver()->AddRule("www.a.com", "127.0.0.1");
host_resolver()->AddRule("www.b.com", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("history")) << message_;
}
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index e52f41b..b2ea7f4 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -6,45 +6,47 @@
#include <list>
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "base/keyboard_codes.h"
+#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/singleton.h"
#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/browser_window.h"
#include "chrome/browser/browsing_instance.h"
#include "chrome/browser/debugger/devtools_manager.h"
#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/extension_tabs_module_constants.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/in_process_webkit/dom_storage_context.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/message_box_handler.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/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_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_preferences_util.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/common/bindings_policy.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
-#include "chrome/common/view_types.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
+#include "chrome/common/view_types.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "webkit/glue/context_menu.h"
@@ -59,8 +61,6 @@ using WebKit::WebDragOperationsMask;
// static
bool ExtensionHost::enable_dom_automation_ = false;
-static const char* kToolstripTextColorSubstitution = "$TEXT_COLOR$";
-
// Helper class that rate-limits the creation of renderer processes for
// ExtensionHosts, to avoid blocking the UI.
class ExtensionHost::ProcessCreationQueue {
@@ -130,10 +130,8 @@ ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance,
url_(url),
extension_host_type_(host_type),
associated_tab_contents_(NULL) {
- int64 session_storage_namespace_id = profile_->GetWebKitContext()->
- dom_storage_context()->AllocateSessionStorageNamespaceId();
render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE,
- session_storage_namespace_id);
+ NULL);
render_view_host_->set_is_extension_process(true);
render_view_host_->AllowBindings(BindingsPolicy::EXTENSION);
if (enable_dom_automation_)
@@ -156,6 +154,14 @@ ExtensionHost::~ExtensionHost() {
Details<ExtensionHost>(this));
ProcessCreationQueue::get()->Remove(this);
render_view_host_->Shutdown(); // deletes render_view_host
+
+ if (recently_deleted()->size() >= 20)
+ recently_deleted()->pop_front();
+ recently_deleted()->push_back(this);
+}
+
+ExtensionHost::HostPointerList* ExtensionHost::recently_deleted() {
+ return Singleton<HostPointerList>::get();
}
void ExtensionHost::CreateView(Browser* browser) {
@@ -189,7 +195,6 @@ bool ExtensionHost::IsRenderViewLive() const {
}
void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) {
- LOG(INFO) << "Creating RenderView for " + extension_->name();
render_view_host_->set_view(host_view);
if (render_view_host_->process()->HasConnection()) {
// If the process is already started, go ahead and initialize the RenderView
@@ -202,15 +207,23 @@ void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) {
}
void ExtensionHost::CreateRenderViewNow() {
- render_view_host_->CreateRenderView(profile_->GetRequestContext(),
- string16());
+ render_view_host_->CreateRenderView(string16());
NavigateToURL(url_);
DCHECK(IsRenderViewLive());
+ if (is_background_page())
+ profile_->GetExtensionsService()->DidCreateRenderViewForBackgroundPage(
+ this);
+}
+
+Browser* ExtensionHost::GetBrowser() const {
+ return view() ? view()->browser() : NULL;
+}
+
+gfx::NativeView ExtensionHost::GetNativeViewOfHost() {
+ return view() ? view()->native_view() : NULL;
}
void ExtensionHost::NavigateToURL(const GURL& url) {
- LOG(INFO) << "Request to NavigateToURL " << url.spec() << " for "
- << extension_->name();
// Prevent explicit navigation to another extension id's pages.
// This method is only called by some APIs, so we still need to protect
// DidNavigate below (location = "").
@@ -223,14 +236,12 @@ void ExtensionHost::NavigateToURL(const GURL& url) {
url_ = url;
if (!is_background_page() && !extension_->GetBackgroundPageReady()) {
- LOG(INFO) << "...Waiting on EXTENSION_BACKGROUND_PAGE_READY";
// Make sure the background page loads before any others.
registrar_.Add(this, NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
Source<Extension>(extension_));
return;
}
- LOG(INFO) << "Navigating to " << url_.spec();
render_view_host_->NavigateToURL(url_);
}
@@ -242,14 +253,7 @@ void ExtensionHost::Observe(NotificationType type,
DCHECK(extension_->GetBackgroundPageReady());
NavigateToURL(url_);
break;
- case NotificationType::BROWSER_THEME_CHANGED:
- if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP ||
- extension_host_type_ == ViewType::EXTENSION_MOLE) {
- InsertThemedToolstripCSS();
- }
- break;
case NotificationType::RENDERER_PROCESS_CREATED:
- LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED";
NotificationService::current()->Notify(
NotificationType::EXTENSION_PROCESS_CREATED,
Source<Profile>(profile_),
@@ -290,7 +294,6 @@ void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host) {
if (!extension_)
return;
- LOG(INFO) << "Sending EXTENSION_PROCESS_TERMINATED for " + extension_->name();
DCHECK_EQ(render_view_host_, render_view_host);
NotificationService::current()->Notify(
NotificationType::EXTENSION_PROCESS_TERMINATED,
@@ -318,15 +321,12 @@ void ExtensionHost::DidNavigate(RenderViewHost* render_view_host,
// In both cases, we preserve the old URL and reset the EFD to NULL. This
// will leave the host in kind of a bad state with poor UI and errors, but
// it's better than the alternative.
- // TODO(erikkay) Perhaps we should display log errors or display a big 404
- // in the toolstrip or something like that.
+ // TODO(erikkay) Perhaps we should display errors in developer mode.
if (params.url.host() != extension_->id()) {
extension_function_dispatcher_.reset(NULL);
return;
}
- LOG(INFO) << "(DidNavigate) Resetting EFD to " << url_.spec() << " for "
- << extension_->name();
url_ = params.url;
extension_function_dispatcher_.reset(
ExtensionFunctionDispatcher::Create(render_view_host_, this, url_));
@@ -343,36 +343,6 @@ void ExtensionHost::InsertInfobarCSS() {
L"", css.as_string(), "InfobarThemeCSS");
}
-void ExtensionHost::InsertThemedToolstripCSS() {
- DCHECK(!is_background_page());
-
- static const base::StringPiece toolstrip_theme_css(
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_EXTENSIONS_TOOLSTRIP_THEME_CSS));
-
- std::string css = toolstrip_theme_css.as_string();
- ThemeProvider* theme_provider =
- render_view_host()->process()->profile()->GetThemeProvider();
-
- SkColor text_color = theme_provider ?
- theme_provider->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT) :
- SK_ColorBLACK;
-
- std::string hex_color_string = StringPrintf(
- "#%02x%02x%02x", SkColorGetR(text_color),
- SkColorGetG(text_color),
- SkColorGetB(text_color));
- size_t pos = css.find(kToolstripTextColorSubstitution);
- while (pos != std::string::npos) {
- css.replace(pos, 12, hex_color_string);
- pos = css.find(kToolstripTextColorSubstitution);
- }
-
- // As a toolstrip, inject our toolstrip CSS to make it easier for toolstrips
- // to blend in with the chrome UI.
- render_view_host()->InsertCSSInWebFrame(L"", css, "ToolstripThemeCSS");
-}
-
void ExtensionHost::DisableScrollbarsForSmallWindows(
const gfx::Size& size_limit) {
render_view_host()->Send(new ViewMsg_DisableScrollbarsForSmallWindows(
@@ -382,9 +352,7 @@ void ExtensionHost::DisableScrollbarsForSmallWindows(
void ExtensionHost::DidStopLoading() {
bool notify = !did_stop_loading_;
did_stop_loading_ = true;
- if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP ||
- extension_host_type_ == ViewType::EXTENSION_MOLE ||
- extension_host_type_ == ViewType::EXTENSION_POPUP ||
+ if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
#if defined(TOOLKIT_VIEWS)
if (view_.get())
@@ -392,7 +360,6 @@ void ExtensionHost::DidStopLoading() {
#endif
}
if (notify) {
- LOG(INFO) << "Sending EXTENSION_HOST_DID_STOP_LOADING";
NotificationService::current()->Notify(
NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
Source<Profile>(profile_),
@@ -403,9 +370,6 @@ void ExtensionHost::DidStopLoading() {
} else if (extension_host_type_ == ViewType::EXTENSION_POPUP) {
UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime",
since_created_.Elapsed());
- } else if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP) {
- UMA_HISTOGRAM_TIMES("Extensions.ToolstripLoadTime",
- since_created_.Elapsed());
} else if (extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime",
since_created_.Elapsed());
@@ -427,22 +391,14 @@ void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) {
case ViewType::EXTENSION_INFOBAR:
InsertInfobarCSS();
break;
- case ViewType::EXTENSION_TOOLSTRIP:
- case ViewType::EXTENSION_MOLE:
- // See also BROWSER_THEME_CHANGED in the Observe function.
- InsertThemedToolstripCSS();
-
- // Listen for browser changes so we can resend the CSS.
- registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
- NotificationService::AllSources());
- break;
default:
break; // No style sheet for other types, at the moment.
}
}
}
-void ExtensionHost::DocumentOnLoadCompletedInMainFrame(RenderViewHost* rvh) {
+void ExtensionHost::DocumentOnLoadCompletedInMainFrame(RenderViewHost* rvh,
+ int32 page_id) {
if (ViewType::EXTENSION_POPUP == GetRenderViewType()) {
NotificationService::current()->Notify(
NotificationType::EXTENSION_POPUP_VIEW_READY,
@@ -461,20 +417,8 @@ void ExtensionHost::RunJavaScriptMessage(const std::wstring& message,
// Unlike for page alerts, navigations aren't a good signal for when to
// resume showing alerts, so we can't reasonably stop showing them even if
// the extension is spammy.
- RunJavascriptMessageBox(this, frame_url, flags, message, default_prompt,
- false, reply_msg);
-}
-
-std::wstring ExtensionHost::GetMessageBoxTitle(const GURL& frame_url,
- bool is_alert) {
- if (extension_->name().empty())
- return l10n_util::GetString(
- is_alert ? IDS_EXTENSION_ALERT_DEFAULT_TITLE
- : IDS_EXTENSION_MESSAGEBOX_DEFAULT_TITLE);
-
- return l10n_util::GetStringF(
- is_alert ? IDS_EXTENSION_ALERT_TITLE : IDS_EXTENSION_MESSAGEBOX_TITLE,
- UTF8ToWide(extension_->name()));
+ RunJavascriptMessageBox(profile_, this, frame_url, flags, message,
+ default_prompt, false, reply_msg);
}
gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() {
@@ -512,6 +456,13 @@ void ExtensionHost::Close(RenderViewHost* render_view_host) {
RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const {
RendererPreferences preferences;
+
+ TabContents* associated_contents = associated_tab_contents();
+ if (associated_contents)
+ preferences =
+ static_cast<RenderViewHostDelegate*>(associated_contents)->
+ GetRendererPrefs(profile);
+
renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile);
return preferences;
}
@@ -539,14 +490,10 @@ WebPreferences ExtensionHost::GetWebkitPrefs() {
return webkit_prefs;
}
-void ExtensionHost::ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
+void ExtensionHost::ProcessDOMUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {
if (extension_function_dispatcher_.get()) {
- extension_function_dispatcher_->HandleRequest(
- message, content, source_url, request_id, has_callback);
+ extension_function_dispatcher_->HandleRequest(params);
}
}
@@ -558,14 +505,21 @@ void ExtensionHost::CreateNewWindow(
int route_id,
WindowContainerType window_container_type,
const string16& frame_name) {
- delegate_view_helper_.CreateNewWindow(
+ // TODO(aa): Use the browser's profile if the extension is split mode
+ // incognito.
+ TabContents* new_contents = delegate_view_helper_.CreateNewWindow(
route_id,
render_view_host()->process()->profile(),
site_instance(),
- DOMUIFactory::GetDOMUIType(url_),
+ DOMUIFactory::GetDOMUIType(render_view_host()->process()->profile(),
+ url_),
this,
window_container_type,
frame_name);
+
+ TabContents* associated_contents = associated_tab_contents();
+ if (associated_contents && associated_contents->delegate())
+ associated_contents->delegate()->TabContentsCreated(new_contents);
}
void ExtensionHost::CreateNewWidget(int route_id,
@@ -573,6 +527,12 @@ void ExtensionHost::CreateNewWidget(int route_id,
CreateNewWidgetInternal(route_id, popup_type);
}
+void ExtensionHost::CreateNewFullscreenWidget(int route_id,
+ WebKit::WebPopupType popup_type) {
+ NOTREACHED()
+ << "ExtensionHost does not support showing full screen popups yet.";
+}
+
RenderWidgetHostView* ExtensionHost::CreateNewWidgetInternal(
int route_id, WebKit::WebPopupType popup_type) {
return delegate_view_helper_.CreateNewWidget(route_id, popup_type,
@@ -587,12 +547,31 @@ void ExtensionHost::ShowCreatedWindow(int route_id,
if (!contents)
return;
- Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(
- profile_->GetExtensionsService()->IsIncognitoEnabled(extension_));
- if (!browser)
- return;
+ Browser* browser = BrowserList::FindBrowserWithType(
+ contents->profile(),
+ Browser::TYPE_NORMAL,
+ false); // Match incognito exactly.
+ if (!browser) {
+ // If no browser is associated with the created TabContents, then the
+ // created TabContents may be an intermediate structure used during topmost
+ // url navigation from within an experimental extension popup view.
+ //
+ // If the ExtensionHost has an associated TabContents, then register the
+ // new contents with this contents. This will allow top-level link
+ // navigation within the new contents to function just as navigation
+ // within the current host.
+ TabContents* associated_contents = associated_tab_contents();
+ if (associated_contents) {
+ associated_contents->AddNewContents(contents, disposition, initial_pos,
+ user_gesture);
+ } else {
+ browser = Browser::Create(contents->profile());
+ browser->window()->Show();
+ }
+ }
- browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
+ if (browser)
+ browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
}
void ExtensionHost::ShowCreatedWidget(int route_id,
@@ -601,6 +580,11 @@ void ExtensionHost::ShowCreatedWidget(int route_id,
initial_pos);
}
+void ExtensionHost::ShowCreatedFullscreenWidget(int route_id) {
+ NOTREACHED()
+ << "ExtensionHost does not support showing full screen popups yet.";
+}
+
void ExtensionHost::ShowCreatedWidgetInternal(
RenderWidgetHostView* widget_host_view,
const gfx::Rect& initial_pos) {
@@ -647,11 +631,20 @@ void ExtensionHost::GotFocus() {
void ExtensionHost::TakeFocus(bool reverse) {
}
+void ExtensionHost::LostCapture() {
+}
+
+void ExtensionHost::Activate() {
+}
+
+void ExtensionHost::Deactivate() {
+}
+
bool ExtensionHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) {
if (extension_host_type_ == ViewType::EXTENSION_POPUP &&
event.type == NativeWebKeyboardEvent::RawKeyDown &&
- event.windowsKeyCode == base::VKEY_ESCAPE) {
+ event.windowsKeyCode == app::VKEY_ESCAPE) {
DCHECK(is_keyboard_shortcut != NULL);
*is_keyboard_shortcut = true;
}
@@ -661,7 +654,7 @@ bool ExtensionHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
void ExtensionHost::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
if (extension_host_type_ == ViewType::EXTENSION_POPUP) {
if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
- event.windowsKeyCode == base::VKEY_ESCAPE) {
+ event.windowsKeyCode == app::VKEY_ESCAPE) {
NotificationService::current()->Notify(
NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
Source<Profile>(profile_),
@@ -672,13 +665,16 @@ void ExtensionHost::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
UnhandledKeyboardEvent(event);
}
-void ExtensionHost::HandleMouseEvent() {
+void ExtensionHost::HandleMouseMove() {
#if defined(OS_WIN)
if (view_.get())
- view_->HandleMouseEvent();
+ view_->HandleMouseMove();
#endif
}
+void ExtensionHost::HandleMouseDown() {
+}
+
void ExtensionHost::HandleMouseLeave() {
#if defined(OS_WIN)
if (view_.get())
@@ -686,12 +682,10 @@ void ExtensionHost::HandleMouseLeave() {
#endif
}
-void ExtensionHost::SetRenderViewType(ViewType::Type type) {
- DCHECK(type == ViewType::EXTENSION_MOLE ||
- type == ViewType::EXTENSION_TOOLSTRIP ||
- type == ViewType::EXTENSION_POPUP);
- extension_host_type_ = type;
- render_view_host()->ViewTypeChanged(extension_host_type_);
+void ExtensionHost::HandleMouseUp() {
+}
+
+void ExtensionHost::HandleMouseActivate() {
}
ViewType::Type ExtensionHost::GetRenderViewType() const {
@@ -706,27 +700,27 @@ void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) {
// we'll create 2 EFDs for the first navigation. We should try to find a
// better way to unify them.
// See http://code.google.com/p/chromium/issues/detail?id=18240
- LOG(INFO) << "(RenderViewCreated) Resetting EFD to " << url_.spec() << " for "
- << extension_->name();
extension_function_dispatcher_.reset(
ExtensionFunctionDispatcher::Create(render_view_host, this, url_));
- if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP ||
- extension_host_type_ == ViewType::EXTENSION_MOLE ||
- extension_host_type_ == ViewType::EXTENSION_POPUP ||
+ if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
render_view_host->EnablePreferredSizeChangedMode(
kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow);
}
}
+RenderViewHostDelegate::FileSelect* ExtensionHost::GetFileSelectDelegate() {
+ if (file_select_helper_.get() == NULL)
+ file_select_helper_.reset(new FileSelectHelper(profile()));
+ return file_select_helper_.get();
+}
+
int ExtensionHost::GetBrowserWindowID() const {
// Hosts not attached to any browser window have an id of -1. This includes
// those mentioned below, and background pages.
int window_id = extension_misc::kUnknownWindowId;
- if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP ||
- extension_host_type_ == ViewType::EXTENSION_MOLE ||
- extension_host_type_ == ViewType::EXTENSION_POPUP ||
+ if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
// If the host is bound to a browser, then extract its window id.
// Extensions hosted in ExternalTabContainer objects may not have
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 4eb81d9..fda120a 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_H_
+#pragma once
#include <string>
+#include <list>
#include "base/perftimer.h"
#include "base/scoped_ptr.h"
@@ -22,12 +24,10 @@
#endif
#include "chrome/common/notification_registrar.h"
-
class Browser;
class Extension;
-class ExtensionProcessManager;
+class FileSelectHelper;
class RenderProcessHost;
-class RenderWidgetHost;
class RenderWidgetHostView;
class TabContents;
struct WebPreferences;
@@ -47,6 +47,9 @@ class ExtensionHost : public RenderViewHostDelegate,
// Enable DOM automation in created render view hosts.
static void EnableDOMAutomation() { enable_dom_automation_ = true; }
+ typedef std::list<ExtensionHost*> HostPointerList;
+ static HostPointerList* recently_deleted();
+
ExtensionHost(Extension* extension, SiteInstance* site_instance,
const GURL& url, ViewType::Type host_type);
~ExtensionHost();
@@ -83,16 +86,13 @@ class ExtensionHost : public RenderViewHostDelegate,
ViewType::Type extension_host_type() const { return extension_host_type_; }
// ExtensionFunctionDispatcher::Delegate
- virtual TabContents* associated_tab_contents() {
+ virtual TabContents* associated_tab_contents() const {
return associated_tab_contents_;
}
void set_associated_tab_contents(TabContents* associated_tab_contents) {
associated_tab_contents_ = associated_tab_contents;
}
- // Sets the the ViewType of this host (e.g. mole, toolstrip).
- void SetRenderViewType(ViewType::Type type);
-
// Returns true if the render view is initialized and didn't crash.
bool IsRenderViewLive() const;
@@ -107,18 +107,15 @@ class ExtensionHost : public RenderViewHostDelegate,
// Insert a default style sheet for Extension Infobars.
void InsertInfobarCSS();
- // Insert the theme CSS for a toolstrip/mole.
- void InsertThemedToolstripCSS();
-
// Tell the renderer not to draw scrollbars on windows smaller than
// |size_limit| in both width and height.
void DisableScrollbarsForSmallWindows(const gfx::Size& size_limit);
- // RenderViewHostDelegate implementation.
- virtual RenderViewHostDelegate::View* GetViewDelegate();
+ // RenderViewHostDelegate::View implementation.
virtual const GURL& GetURL() const { return url_; }
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 DidNavigate(RenderViewHost* render_view_host,
@@ -126,14 +123,13 @@ class ExtensionHost : public RenderViewHostDelegate,
virtual void DidStopLoading();
virtual void DocumentAvailableInMainFrame(RenderViewHost* render_view_host);
virtual void DocumentOnLoadCompletedInMainFrame(
- RenderViewHost* render_view_host);
+ RenderViewHost* render_view_host,
+ int32 page_id);
+ // RenderViewHostDelegate implementation.
+ virtual RenderViewHostDelegate::View* GetViewDelegate();
virtual WebPreferences GetWebkitPrefs();
- virtual void ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback);
+ virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params);
virtual void RunJavaScriptMessage(const std::wstring& message,
const std::wstring& default_prompt,
const GURL& frame_url,
@@ -149,12 +145,15 @@ class ExtensionHost : public RenderViewHostDelegate,
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 StartDragging(const WebDropData& drop_data,
WebKit::WebDragOperationsMask allowed_operations,
@@ -163,11 +162,17 @@ class ExtensionHost : public RenderViewHostDelegate,
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 HandleMouseEvent();
+ virtual void HandleMouseMove();
+ virtual void HandleMouseDown();
virtual void HandleMouseLeave();
+ virtual void HandleMouseUp();
+ virtual void HandleMouseActivate();
virtual void UpdatePreferredSize(const gfx::Size& new_size);
// NotificationObserver
@@ -176,8 +181,6 @@ class ExtensionHost : public RenderViewHostDelegate,
const NotificationDetails& details);
// JavaScriptMessageBoxClient
- virtual std::wstring GetMessageBoxTitle(const GURL& frame_url,
- bool is_alert);
virtual gfx::NativeWindow GetMessageBoxRootWindow();
virtual void OnMessageBoxClosed(IPC::Message* reply_msg,
bool success,
@@ -212,12 +215,8 @@ class ExtensionHost : public RenderViewHostDelegate,
void CreateRenderViewNow();
// ExtensionFunctionDispatcher::Delegate
- virtual Browser* GetBrowser() const {
- return view() ? view()->browser() : NULL;
- }
- virtual gfx::NativeView GetNativeViewOfHost() {
- return view() ? view()->native_view() : NULL;
- }
+ virtual Browser* GetBrowser() const;
+ virtual gfx::NativeView GetNativeViewOfHost();
// Handles keyboard events that were not handled by HandleKeyboardEvent().
// Platform specific implementation may override this method to handle the
@@ -262,7 +261,7 @@ class ExtensionHost : public RenderViewHostDelegate,
scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
- // Only EXTENSION_TOOLSTRIP, EXTENSION_POPUP, and EXTENSION_BACKGROUND_PAGE
+ // Only EXTENSION_INFOBAR, EXTENSION_POPUP, and EXTENSION_BACKGROUND_PAGE
// are used here, others are not hosted by ExtensionHost.
ViewType::Type extension_host_type_;
@@ -272,6 +271,9 @@ class ExtensionHost : public RenderViewHostDelegate,
// Used to measure how long it's been since the host was created.
PerfTimer since_created_;
+ // FileSelectHelper, lazily created.
+ scoped_ptr<FileSelectHelper> file_select_helper_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionHost);
};
diff --git a/chrome/browser/extensions/extension_host_mac.h b/chrome/browser/extensions/extension_host_mac.h
index 1bdbcfc..65aceaa 100644
--- a/chrome/browser/extensions/extension_host_mac.h
+++ b/chrome/browser/extensions/extension_host_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_MAC_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_HOST_MAC_H_
+#pragma once
#include "chrome/browser/extensions/extension_host.h"
diff --git a/chrome/browser/extensions/extension_i18n_api.cc b/chrome/browser/extensions/extension_i18n_api.cc
index 146e62a..40964a7 100644
--- a/chrome/browser/extensions/extension_i18n_api.cc
+++ b/chrome/browser/extensions/extension_i18n_api.cc
@@ -4,8 +4,9 @@
#include "chrome/browser/extensions/extension_i18n_api.h"
+#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
@@ -13,8 +14,8 @@
static const char kEmptyAcceptLanguagesError[] = "accept-languages is empty.";
bool GetAcceptLanguagesFunction::RunImpl() {
- std::wstring acceptLanguages =
- UTF8ToWide(profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ string16 acceptLanguages =
+ UTF8ToUTF16(profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
// Currently, there are 2 ways to set browser's accept-languages: through UI
// or directly modify the preference file. The accept-languages set through
// UI is guranteed to be valid, and the accept-languages string returned from
@@ -32,19 +33,18 @@ bool GetAcceptLanguagesFunction::RunImpl() {
}
size_t begin = 0;
size_t end;
- std::wstring acceptLang;
while (1) {
end = acceptLanguages.find(',', begin);
if (end > begin) {
// Guard against a malformed value with multiple "," in a row.
- acceptLang = acceptLanguages.substr(begin, end - begin);
+ string16 acceptLang = acceptLanguages.substr(begin, end - begin);
static_cast<ListValue*>(result_.get())->
Append(Value::CreateStringValue(acceptLang));
}
begin = end + 1;
// 'begin >= acceptLanguages.length()' to guard against a value
// ending with ','.
- if (end == std::wstring::npos || begin >= acceptLanguages.length())
+ if (end == string16::npos || begin >= acceptLanguages.length())
break;
}
if (static_cast<ListValue*>(result_.get())->GetSize() == 0) {
diff --git a/chrome/browser/extensions/extension_i18n_api.h b/chrome/browser/extensions/extension_i18n_api.h
index 275c882..4fcc2c7 100644
--- a/chrome/browser/extensions/extension_i18n_api.h
+++ b/chrome/browser/extensions/extension_i18n_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_I18N_API_H__
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_I18N_API_H__
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
diff --git a/chrome/browser/extensions/extension_icon_manager.cc b/chrome/browser/extensions/extension_icon_manager.cc
index 1e3befc..53c8923 100644
--- a/chrome/browser/extensions/extension_icon_manager.cc
+++ b/chrome/browser/extensions/extension_icon_manager.cc
@@ -8,7 +8,9 @@
#include "base/logging.h"
#include "base/stl_util-inl.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 "gfx/color_utils.h"
#include "gfx/favicon_size.h"
#include "gfx/skbitmap_operations.h"
@@ -16,21 +18,44 @@
#include "grit/theme_resources.h"
#include "skia/ext/image_operations.h"
+namespace {
+
+// Helper function to create a new bitmap with |padding| amount of empty space
+// around the original bitmap.
+static SkBitmap ApplyPadding(const SkBitmap& source,
+ const gfx::Insets& padding) {
+ scoped_ptr<gfx::CanvasSkia> result(
+ new gfx::CanvasSkia(source.width() + padding.width(),
+ source.height() + padding.height(), false));
+ result->DrawBitmapInt(
+ source,
+ 0, 0, source.width(), source.height(),
+ padding.left(), padding.top(), source.width(), source.height(),
+ false);
+ return result->ExtractBitmap();
+}
+
+} // namespace
+
ExtensionIconManager::ExtensionIconManager()
: ALLOW_THIS_IN_INITIALIZER_LIST(image_tracker_(this)),
monochrome_(false) {
}
+ExtensionIconManager::~ExtensionIconManager() {
+}
+
void ExtensionIconManager::LoadIcon(Extension* extension) {
- ExtensionResource icon_resource;
- extension->GetIconPathAllowLargerSize(&icon_resource,
- Extension::EXTENSION_ICON_BITTY);
+ ExtensionResource icon_resource = extension->GetIconResource(
+ Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_BIGGER);
if (!icon_resource.extension_root().empty()) {
+ // Insert into pending_icons_ first because LoadImage can call us back
+ // synchronously if the image is already cached.
+ pending_icons_.insert(extension->id());
image_tracker_.LoadImage(extension,
icon_resource,
gfx::Size(kFavIconSize, kFavIconSize),
ImageLoadingTracker::CACHE);
- pending_icons_.insert(extension->id());
}
}
@@ -43,8 +68,8 @@ const SkBitmap& ExtensionIconManager::GetIcon(const std::string& extension_id) {
result = &default_icon_;
}
DCHECK(result);
- DCHECK(result->width() == kFavIconSize);
- DCHECK(result->height() == kFavIconSize);
+ DCHECK_EQ(kFavIconSize + padding_.width(), result->width());
+ DCHECK_EQ(kFavIconSize + padding_.height(), result->height());
return *result;
}
@@ -92,5 +117,8 @@ SkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) {
result = SkBitmapOperations::CreateHSLShiftedBitmap(result, shift);
}
+ if (!padding_.empty())
+ result = ApplyPadding(result, padding_);
+
return result;
}
diff --git a/chrome/browser/extensions/extension_icon_manager.h b/chrome/browser/extensions/extension_icon_manager.h
index abf7192..876f5e0 100644
--- a/chrome/browser/extensions/extension_icon_manager.h
+++ b/chrome/browser/extensions/extension_icon_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ICON_MANAGER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_ICON_MANAGER_H_
+#pragma once
#include <map>
#include <set>
@@ -11,6 +12,7 @@
#include "base/basictypes.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "gfx/insets.h"
#include "third_party/skia/include/core/SkBitmap.h"
class Extension;
@@ -18,6 +20,7 @@ class Extension;
class ExtensionIconManager : public ImageLoadingTracker::Observer {
public:
ExtensionIconManager();
+ virtual ~ExtensionIconManager();
// Start loading the icon for the given extension.
void LoadIcon(Extension* extension);
@@ -35,6 +38,7 @@ class ExtensionIconManager : public ImageLoadingTracker::Observer {
int index);
void set_monochrome(bool value) { monochrome_ = value; }
+ void set_padding(const gfx::Insets& value) { padding_ = value; }
private:
// Makes sure we've done one-time initialization of the default extension icon
@@ -60,6 +64,9 @@ class ExtensionIconManager : public ImageLoadingTracker::Observer {
// If true, we will desaturate the icons to make them monochromatic.
bool monochrome_;
+ // Specifies the amount of empty padding to place around the icon.
+ gfx::Insets padding_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionIconManager);
};
diff --git a/chrome/browser/extensions/extension_idle_api.cc b/chrome/browser/extensions/extension_idle_api.cc
index 0a6a25f..0de5032 100644
--- a/chrome/browser/extensions/extension_idle_api.cc
+++ b/chrome/browser/extensions/extension_idle_api.cc
@@ -42,7 +42,7 @@ struct ExtensionIdlePollingData {
static ExtensionIdlePollingData polling_data;
// Forward declaration of utility methods.
-static const wchar_t* IdleStateToDescription(IdleState state);
+static const char* IdleStateToDescription(IdleState state);
static StringValue* CreateIdleValue(IdleState idle_state);
static int CheckThresholdBounds(int timeout);
static IdleState CalculateIdleStateAndUpdateTimestamp(int threshold);
@@ -64,7 +64,7 @@ class ExtensionIdlePollingTask : public Task {
DISALLOW_COPY_AND_ASSIGN(ExtensionIdlePollingTask);
};
-const wchar_t* IdleStateToDescription(IdleState state) {
+const char* IdleStateToDescription(IdleState state) {
if (IDLE_STATE_ACTIVE == state)
return keys::kStateActive;
if (IDLE_STATE_IDLE == state)
@@ -153,8 +153,5 @@ void ExtensionIdleEventRouter::OnIdleStateChange(Profile* profile,
base::JSONWriter::Write(&args, false, &json_args);
profile->GetExtensionMessageService()->DispatchEventToRenderers(
- keys::kOnStateChanged,
- json_args,
- profile->IsOffTheRecord(),
- GURL());
+ keys::kOnStateChanged, json_args, profile, GURL());
}
diff --git a/chrome/browser/extensions/extension_idle_api.h b/chrome/browser/extensions/extension_idle_api.h
index ab27ec1..d6e0c89 100644
--- a/chrome/browser/extensions/extension_idle_api.h
+++ b/chrome/browser/extensions/extension_idle_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_IDLE_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_IDLE_API_H_
+#pragma once
#include "chrome/browser/idle.h"
#include "chrome/browser/profile.h"
diff --git a/chrome/browser/extensions/extension_idle_api_constants.cc b/chrome/browser/extensions/extension_idle_api_constants.cc
index cf0c8e7..f9087b2 100644
--- a/chrome/browser/extensions/extension_idle_api_constants.cc
+++ b/chrome/browser/extensions/extension_idle_api_constants.cc
@@ -6,13 +6,13 @@
namespace extension_idle_api_constants {
-const wchar_t kSecondsKey[] = L"seconds";
-const wchar_t kStateKey[] = L"state";
+const char kSecondsKey[] = "seconds";
+const char kStateKey[] = "state";
const char kOnStateChanged[] = "idle.onStateChanged";
-const wchar_t kStateActive[] = L"active";
-const wchar_t kStateIdle[] = L"idle";
-const wchar_t kStateLocked[] = L"locked";
+const char kStateActive[] = "active";
+const char kStateIdle[] = "idle";
+const char kStateLocked[] = "locked";
} // namespace extension_idle_api_constants
diff --git a/chrome/browser/extensions/extension_idle_api_constants.h b/chrome/browser/extensions/extension_idle_api_constants.h
index 5bdf696..ae5ff8e 100644
--- a/chrome/browser/extensions/extension_idle_api_constants.h
+++ b/chrome/browser/extensions/extension_idle_api_constants.h
@@ -4,20 +4,21 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_IDLE_API_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_IDLE_API_CONSTANTS_H_
+#pragma once
namespace extension_idle_api_constants {
// Keys.
-extern const wchar_t kSecondsKey[];
-extern const wchar_t kStateKey[];
+extern const char kSecondsKey[];
+extern const char kStateKey[];
// Events.
extern const char kOnStateChanged[];
// States
-extern const wchar_t kStateActive[];
-extern const wchar_t kStateIdle[];
-extern const wchar_t kStateLocked[];
+extern const char kStateActive[];
+extern const char kStateIdle[];
+extern const char kStateLocked[];
}; // namespace extension_idle_api_constants
diff --git a/chrome/browser/extensions/extension_incognito_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc
index a996bcc..c287fda 100644
--- a/chrome/browser/extensions/extension_incognito_apitest.cc
+++ b/chrome/browser/extensions/extension_incognito_apitest.cc
@@ -18,7 +18,7 @@
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
// Loads a simple extension which attempts to change the title of every page
// that loads to "modified".
@@ -44,7 +44,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
// Load a dummy extension. This just tests that we don't regress a
// crash fix when multiple incognito- and non-incognito-enabled extensions
@@ -78,11 +78,19 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
EXPECT_TRUE(result);
}
+// Tests that an extension which is enabled for incognito mode doesn't
+// 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_FALSE(browser()->profile()->HasOffTheRecordProfile());
+}
+
// Tests that the APIs in an incognito-enabled extension work properly.
-// Flaky, http://crbug.com/42844.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_Incognito) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ResultCatcher catcher;
@@ -96,11 +104,38 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_Incognito) {
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
+// Tests that the APIs in an incognito-enabled split-mode extension work
+// properly.
+// Hangy, http://crbug.com/53991.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoSplitMode) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+
+ // We need 2 ResultCatchers because we'll be running the same test in both
+ // regular and incognito mode.
+ ResultCatcher catcher;
+ catcher.RestrictToProfile(browser()->profile());
+ ResultCatcher catcher_incognito;
+ catcher_incognito.RestrictToProfile(
+ browser()->profile()->GetOffTheRecordProfile());
+
+ // Open incognito window and navigate to test page.
+ ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
+ GURL("http://www.example.com:1337/files/extensions/test_file.html"));
+
+ ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
+ .AppendASCII("incognito").AppendASCII("split")));
+
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message();
+}
+
// Tests that the APIs in an incognito-disabled extension don't see incognito
// events or callbacks.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoDisabled) {
+// Hangy, http://crbug.com/53869.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoDisabled) {
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ResultCatcher catcher;
@@ -117,7 +152,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoDisabled) {
// Test that opening a popup from an incognito browser window works properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ResultCatcher catcher;
diff --git a/chrome/browser/extensions/extension_infobar_delegate.cc b/chrome/browser/extensions/extension_infobar_delegate.cc
index c741d94..b3b8a39 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.cc
+++ b/chrome/browser/extensions/extension_infobar_delegate.cc
@@ -58,6 +58,15 @@ void ExtensionInfoBarDelegate::InfoBarClosed() {
delete this;
}
+ExtensionInfoBarDelegate*
+ExtensionInfoBarDelegate::AsExtensionInfoBarDelegate() {
+ return this;
+}
+
+InfoBarDelegate::Type ExtensionInfoBarDelegate::GetInfoBarType() {
+ return PAGE_ACTION_TYPE;
+}
+
void ExtensionInfoBarDelegate::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/extensions/extension_infobar_delegate.h b/chrome/browser/extensions/extension_infobar_delegate.h
index 01174ef..dae7aa9 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.h
+++ b/chrome/browser/extensions/extension_infobar_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INFOBAR_DELEGATE_H_
+#pragma once
#include "chrome/browser/tab_contents/infobar_delegate.h"
@@ -21,6 +22,9 @@ class ExtensionInfoBarDelegate : public InfoBarDelegate,
class DelegateObserver {
public:
virtual void OnDelegateDeleted() = 0;
+
+ protected:
+ virtual ~DelegateObserver() {}
};
ExtensionInfoBarDelegate(Browser* browser, TabContents* contents,
@@ -37,12 +41,8 @@ class ExtensionInfoBarDelegate : public InfoBarDelegate,
virtual bool EqualsDelegate(InfoBarDelegate* delegate) const;
virtual void InfoBarClosed();
virtual InfoBar* CreateInfoBar();
- virtual ExtensionInfoBarDelegate* AsExtensionInfoBarDelegate() {
- return this;
- }
- virtual Type GetInfoBarType() {
- return PAGE_ACTION_TYPE;
- }
+ virtual ExtensionInfoBarDelegate* AsExtensionInfoBarDelegate();
+ virtual Type GetInfoBarType();
// Overridden from NotificationObserver:
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/extensions/extension_infobar_module.cc b/chrome/browser/extensions/extension_infobar_module.cc
index 2143d89..590bfc1 100644
--- a/chrome/browser/extensions/extension_infobar_module.cc
+++ b/chrome/browser/extensions/extension_infobar_module.cc
@@ -4,7 +4,9 @@
#include "chrome/browser/extensions/extension_infobar_module.h"
-#include "app/l10n_util.h"
+#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/values.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_infobar_module_constants.h"
@@ -45,7 +47,7 @@ bool ShowInfoBarFunction::RunImpl() {
NULL)) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
extension_tabs_module_constants::kTabNotFoundError,
- IntToString(tab_id));
+ base::IntToString(tab_id));
return false;
}
diff --git a/chrome/browser/extensions/extension_infobar_module.h b/chrome/browser/extensions/extension_infobar_module.h
index e05dbf1..24523e1 100644
--- a/chrome/browser/extensions/extension_infobar_module.h
+++ b/chrome/browser/extensions/extension_infobar_module.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INFOBAR_MODULE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INFOBAR_MODULE_H_
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
diff --git a/chrome/browser/extensions/extension_infobar_module_constants.cc b/chrome/browser/extensions/extension_infobar_module_constants.cc
index 1b0eef9..6897ded 100644
--- a/chrome/browser/extensions/extension_infobar_module_constants.cc
+++ b/chrome/browser/extensions/extension_infobar_module_constants.cc
@@ -6,8 +6,8 @@
namespace extension_infobar_module_constants {
-const wchar_t kHtmlPath[] = L"path";
-const wchar_t kTabId[] = L"tabId";
+const char kHtmlPath[] = "path";
+const char kTabId[] = "tabId";
const char kNoCurrentWindowError[] = "No current browser window was found";
const char kTabNotFoundError[] = "Specified tab (or default tab) not found";
diff --git a/chrome/browser/extensions/extension_infobar_module_constants.h b/chrome/browser/extensions/extension_infobar_module_constants.h
index 4af86b8..6f4ff48 100644
--- a/chrome/browser/extensions/extension_infobar_module_constants.h
+++ b/chrome/browser/extensions/extension_infobar_module_constants.h
@@ -6,12 +6,13 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INFOBAR_MODULE_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INFOBAR_MODULE_CONSTANTS_H_
+#pragma once
namespace extension_infobar_module_constants {
// Keys.
-extern const wchar_t kHtmlPath[];
-extern const wchar_t kTabId[];
+extern const char kHtmlPath[];
+extern const char kTabId[];
// Errors.
extern const char kNoCurrentWindowError[];
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index 364d1b4..857b4e8 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -10,7 +10,7 @@
#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "base/file_util.h"
-#include "base/rand_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
@@ -19,32 +19,34 @@
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/views/app_launcher.h"
-#include "chrome/browser/views/extensions/extension_installed_bubble.h"
-#elif defined(TOOLKIT_GTK)
-#include "chrome/browser/gtk/extension_installed_bubble_gtk.h"
-#endif
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
+#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
-#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#if defined(OS_MACOSX)
+#include "chrome/browser/cocoa/extension_installed_bubble_bridge.h"
+#endif
+
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/views/app_launcher.h"
+#include "chrome/browser/views/extensions/extension_installed_bubble.h"
+#endif
+
#if defined(TOOLKIT_GTK)
#include "chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h"
+#include "chrome/browser/gtk/extension_installed_bubble_gtk.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#endif
-#if defined(OS_MACOSX)
-#include "chrome/browser/cocoa/extension_installed_bubble_bridge.h"
-#endif
-
// static
const int ExtensionInstallUI::kTitleIds[NUM_PROMPT_TYPES] = {
IDS_EXTENSION_INSTALL_PROMPT_TITLE,
@@ -63,62 +65,8 @@ const int ExtensionInstallUI::kButtonIds[NUM_PROMPT_TYPES] = {
namespace {
-static void GetV2Warnings(Extension* extension,
- std::vector<string16>* warnings) {
- if (!extension->plugins().empty()) {
- // TODO(aa): This one is a bit awkward. Should we have a separate
- // presentation for this case?
- warnings->push_back(
- l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT2_WARNING_FULL_ACCESS));
- return;
- }
-
- if (extension->HasAccessToAllHosts()) {
- warnings->push_back(
- l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT2_WARNING_ALL_HOSTS));
- } else {
- std::set<std::string> hosts = extension->GetEffectiveHostPermissions();
- if (hosts.size() == 1) {
- warnings->push_back(
- l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT2_WARNING_1_HOST,
- UTF8ToUTF16(*hosts.begin())));
- } else if (hosts.size() == 2) {
- warnings->push_back(
- l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT2_WARNING_2_HOSTS,
- UTF8ToUTF16(*hosts.begin()),
- UTF8ToUTF16(*(++hosts.begin()))));
- } else if (hosts.size() == 3) {
- warnings->push_back(
- l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT2_WARNING_3_HOSTS,
- UTF8ToUTF16(*hosts.begin()),
- UTF8ToUTF16(*(++hosts.begin())),
- UTF8ToUTF16(*(++++hosts.begin()))));
- } else if (hosts.size() >= 4) {
- warnings->push_back(
- l10n_util::GetStringFUTF16(
- IDS_EXTENSION_PROMPT2_WARNING_4_OR_MORE_HOSTS,
- UTF8ToUTF16(*hosts.begin()),
- UTF8ToUTF16(*(++hosts.begin())),
- IntToString16(hosts.size() - 2)));
- }
- }
-
- if (extension->HasEffectiveBrowsingHistoryPermission()) {
- warnings->push_back(
- l10n_util::GetStringUTF16(
- IDS_EXTENSION_PROMPT2_WARNING_BROWSING_HISTORY));
- }
-
- const Extension::SimplePermissions& simple_permissions =
- Extension::GetSimplePermissions();
-
- for (Extension::SimplePermissions::const_iterator iter =
- simple_permissions.begin();
- iter != simple_permissions.end(); ++iter) {
- if (extension->HasApiPermission(iter->first))
- warnings->push_back(iter->second);
- }
-}
+// Size of extension icon in top left of dialog.
+const int kIconSize = 69;
} // namespace
@@ -131,6 +79,9 @@ ExtensionInstallUI::ExtensionInstallUI(Profile* profile)
prompt_type_(NUM_PROMPT_TYPES),
ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {}
+ExtensionInstallUI::~ExtensionInstallUI() {
+}
+
void ExtensionInstallUI::ConfirmInstall(Delegate* delegate,
Extension* extension) {
DCHECK(ui_loop_ == MessageLoop::current());
@@ -155,7 +106,7 @@ void ExtensionInstallUI::ConfirmInstall(Delegate* delegate,
DCHECK(!previous_use_system_theme_);
#endif
- delegate->InstallUIProceed(false);
+ delegate->InstallUIProceed();
return;
}
@@ -198,7 +149,8 @@ void ExtensionInstallUI::OnInstallSuccess(Extension* extension) {
url += "/#";
url += hash_params;
browser->AddTabWithURL(GURL(url), GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ NULL);
}
return;
@@ -249,8 +201,13 @@ void ExtensionInstallUI::OnImageLoaded(
else
icon_ = SkBitmap();
if (icon_.empty()) {
- icon_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_EXTENSION_DEFAULT_ICON);
+ if (extension_->is_app()) {
+ icon_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_APP_DEFAULT_ICON);
+ } else {
+ icon_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_EXTENSION_DEFAULT_ICON);
+ }
}
switch (prompt_type_) {
@@ -262,17 +219,14 @@ void ExtensionInstallUI::OnImageLoaded(
Source<ExtensionInstallUI>(this),
NotificationService::NoDetails());
- std::vector<string16> warnings;
- GetV2Warnings(extension_, &warnings);
- ShowExtensionInstallUIPrompt2Impl(
- profile_, delegate_, extension_, &icon_, warnings);
+ std::vector<string16> warnings = extension_->GetPermissionMessages();
+ ShowExtensionInstallUIPrompt2Impl(profile_, delegate_, extension_, &icon_,
+ warnings);
break;
}
case UNINSTALL_PROMPT: {
- string16 message =
- l10n_util::GetStringUTF16(IDS_EXTENSION_UNINSTALL_CONFIRMATION);
ShowExtensionInstallUIPromptImpl(profile_, delegate_, extension_, &icon_,
- message, UNINSTALL_PROMPT);
+ UNINSTALL_PROMPT);
break;
}
default:
@@ -331,10 +285,10 @@ void ExtensionInstallUI::ShowConfirmation(PromptType prompt_type) {
// Load the image asynchronously. For the response, check OnImageLoaded.
prompt_type_ = prompt_type;
ExtensionResource image =
- extension_->GetIconPath(Extension::EXTENSION_ICON_LARGE);
+ extension_->GetIconResource(Extension::EXTENSION_ICON_LARGE,
+ ExtensionIconSet::MATCH_EXACTLY);
tracker_.LoadImage(extension_, image,
- gfx::Size(Extension::EXTENSION_ICON_LARGE,
- Extension::EXTENSION_ICON_LARGE),
+ gfx::Size(kIconSize, kIconSize),
ImageLoadingTracker::DONT_CACHE);
}
@@ -349,9 +303,11 @@ void ExtensionInstallUI::ShowGenericExtensionInstalledInfoBar(
if (!tab_contents)
return;
- std::wstring msg = l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_HEADING,
- UTF8ToWide(new_extension->name())) +
- L" " + l10n_util::GetString(IDS_EXTENSION_INSTALLED_MANAGE_INFO_MAC);
+ string16 msg =
+ l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALLED_HEADING,
+ UTF8ToUTF16(new_extension->name())) +
+ UTF8ToUTF16(" ") +
+ l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO_MAC);
InfoBarDelegate* delegate = new SimpleAlertInfoBarDelegate(
tab_contents, msg, new SkBitmap(icon_), true);
tab_contents->AddInfoBar(delegate);
diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h
index 6ebcd4c..7ab2c02 100644
--- a/chrome/browser/extensions/extension_install_ui.h
+++ b/chrome/browser/extensions/extension_install_ui.h
@@ -4,24 +4,21 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_UI_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_UI_H_
+#pragma once
#include <string>
#include <vector>
-#include "base/file_path.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/common/extensions/url_pattern.h"
#include "gfx/native_widget_types.h"
#include "third_party/skia/include/core/SkBitmap.h"
class Extension;
-class ExtensionsService;
class MessageLoop;
class Profile;
class InfoBarDelegate;
-class SandboxedExtensionUnpacker;
class TabContents;
// Displays all the UI around extension installation and uninstallation.
@@ -42,16 +39,19 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
public:
// We call this method after ConfirmInstall()/ConfirmUninstall() to signal
// that the installation/uninstallation should continue.
- virtual void InstallUIProceed(bool create_app_shortcut) = 0;
+ virtual void InstallUIProceed() = 0;
// We call this method after ConfirmInstall()/ConfirmUninstall() to signal
// that the installation/uninstallation should stop.
virtual void InstallUIAbort() = 0;
+
+ protected:
+ virtual ~Delegate() {}
};
explicit ExtensionInstallUI(Profile* profile);
- virtual ~ExtensionInstallUI() {}
+ virtual ~ExtensionInstallUI();
// This is called by the installer to verify whether the installation should
// proceed. This is declared virtual for testing.
@@ -109,7 +109,7 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
// NOTE: The implementations of this function is platform-specific.
static void ShowExtensionInstallUIPromptImpl(
Profile* profile, Delegate* delegate, Extension* extension,
- SkBitmap* icon, const string16& warning, PromptType type);
+ SkBitmap* icon, PromptType type);
// Implements the showing of the new install dialog. The implementations of
// this function are platform-specific.
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index a9dc844..14a6a5b 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -33,9 +33,9 @@ class ExtensionInstallUIBrowserTest : public ExtensionBrowserTest {
}
};
-// Flaky, http://crbug.com/43441.
+// Crashy, http://crbug.com/44548.
IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
- FLAKY_TestThemeInstallUndoResetsToDefault) {
+ DISABLED_TestThemeInstallUndoResetsToDefault) {
// Install theme once and undo to verify we go back to default theme.
FilePath theme_path = test_data_dir_.AppendASCII("theme.crx");
ASSERT_TRUE(InstallExtensionWithUI(theme_path, 1));
diff --git a/chrome/browser/extensions/extension_javascript_url_apitest.cc b/chrome/browser/extensions/extension_javascript_url_apitest.cc
index 601a9e4..2b6cf59 100644
--- a/chrome/browser/extensions/extension_javascript_url_apitest.cc
+++ b/chrome/browser/extensions/extension_javascript_url_apitest.cc
@@ -8,7 +8,7 @@
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, JavaScriptURLPermissions) {
host_resolver()->AddRule("a.com", "127.0.0.1");
host_resolver()->AddRule("b.com", "127.0.0.1");
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("tabs/javascript_url_permissions")) << message_;
}
diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc
index 01348c9..f91bd07 100644
--- a/chrome/browser/extensions/extension_management_browsertest.cc
+++ b/chrome/browser/extensions/extension_management_browsertest.cc
@@ -9,6 +9,7 @@
#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_test_message_listener.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/profile.h"
#include "chrome/common/url_constants.h"
@@ -208,10 +209,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
basedir.AppendASCII("v2.crx"));
// Install version 1 of the extension.
+ ExtensionTestMessageListener listener1("v1 installed");
ExtensionsService* service = browser()->profile()->GetExtensionsService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(service->disabled_extensions()->empty());
ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1));
+ listener1.WaitUntilSatisfied();
const ExtensionList* extensions = service->extensions();
ASSERT_EQ(size_before + 1, extensions->size());
ASSERT_TRUE(service->HasInstalledExtensions());
@@ -223,8 +226,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
service->updater()->set_blacklist_checks_enabled(false);
// Run autoupdate and make sure version 2 of the extension was installed.
+ ExtensionTestMessageListener listener2("v2 installed");
service->updater()->CheckNow();
ASSERT_TRUE(WaitForExtensionInstall());
+ listener2.WaitUntilSatisfied();
extensions = service->extensions();
ASSERT_EQ(size_before + 1, extensions->size());
ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf",
@@ -248,3 +253,65 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
extensions->at(size_before)->id());
ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
}
+
+IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) {
+ ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf";
+ // We don't want autoupdate blacklist checks.
+ service->updater()->set_blacklist_checks_enabled(false);
+
+ FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
+
+ // Note: This interceptor gets requests on the IO thread.
+ scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
+ URLFetcher::enable_interception_for_tests(true);
+
+ interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
+ basedir.AppendASCII("manifest_v2.xml"));
+ interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
+ basedir.AppendASCII("v2.crx"));
+
+ const size_t size_before = service->extensions()->size();
+ 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
+ // is race-prone, because instantating the ExtensionService starts a read
+ // of external_extensions.json before this test function starts.
+ service->AddPendingExtensionFromExternalUpdateUrl(
+ kExtensionId, GURL("http://localhost/autoupdate/manifest"));
+
+ // Run autoupdate and make sure version 2 of the extension was installed.
+ service->updater()->CheckNow();
+ ASSERT_TRUE(WaitForExtensionInstall());
+ const ExtensionList* extensions = service->extensions();
+ ASSERT_EQ(size_before + 1, extensions->size());
+ ASSERT_EQ(kExtensionId, extensions->at(size_before)->id());
+ ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
+
+ // Uninstalling the extension should set a pref that keeps the extension from
+ // being installed again the next time external_extensions.json is read.
+
+ UninstallExtension(kExtensionId);
+
+ std::set<std::string> killed_ids;
+ service->extension_prefs()->GetKilledExtensionIds(&killed_ids);
+ EXPECT_TRUE(killed_ids.end() != killed_ids.find(kExtensionId))
+ << "Uninstalling should set kill bit on externaly installed extension.";
+
+ // 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))
+ << "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))
+ << "Uninstalling non-external extension should not set kill bit.";
+}
diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc
index ebc7e85..e4bda71 100644
--- a/chrome/browser/extensions/extension_menu_manager.cc
+++ b/chrome/browser/extensions/extension_menu_manager.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "app/l10n_util.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
@@ -36,16 +37,6 @@ ExtensionMenuItem::~ExtensionMenuItem() {
STLDeleteElements(&children_);
}
-bool ExtensionMenuItem::RemoveChild(const Id& child_id) {
- ExtensionMenuItem* child = ReleaseChild(child_id, true);
- if (child) {
- delete child;
- return true;
- } else {
- return false;
- }
-}
-
ExtensionMenuItem* ExtensionMenuItem::ReleaseChild(const Id& child_id,
bool recursive) {
for (List::iterator i = children_.begin(); i != children_.end(); ++i) {
@@ -76,11 +67,16 @@ std::set<ExtensionMenuItem::Id> ExtensionMenuItem::RemoveAllDescendants() {
}
string16 ExtensionMenuItem::TitleWithReplacement(
- const string16& selection) const {
+ const string16& selection, size_t max_length) const {
string16 result = UTF8ToUTF16(title_);
// TODO(asargent) - Change this to properly handle %% escaping so you can
// 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));
+ }
return result;
}
@@ -245,24 +241,41 @@ bool ExtensionMenuManager::RemoveContextMenuItem(
}
bool result = false;
+ std::set<ExtensionMenuItem::Id> items_removed;
ExtensionMenuItem::List& list = i->second;
ExtensionMenuItem::List::iterator j;
for (j = list.begin(); j < list.end(); ++j) {
- // See if the current item is a match, or if one of its children was.
+ // See if the current top-level item is a match.
if ((*j)->id() == id) {
+ items_removed = (*j)->RemoveAllDescendants();
+ items_removed.insert(id);
delete *j;
list.erase(j);
- items_by_id_.erase(id);
- result = true;
- break;
- } else if ((*j)->RemoveChild(id)) {
- items_by_id_.erase(id);
result = true;
break;
+ } else {
+ // See if the item to remove was found as a descendant of the current
+ // top-level item.
+ ExtensionMenuItem* child = (*j)->ReleaseChild(id, true /* recursive */);
+ if (child) {
+ items_removed = child->RemoveAllDescendants();
+ items_removed.insert(id);
+ delete child;
+ result = true;
+ break;
+ }
}
}
DCHECK(result); // The check at the very top should have prevented this.
+ // Clear entries from the items_by_id_ map.
+ std::set<ExtensionMenuItem::Id>::iterator removed_iter;
+ for (removed_iter = items_removed.begin();
+ removed_iter != items_removed.end();
+ ++removed_iter) {
+ items_by_id_.erase(*removed_iter);
+ }
+
if (list.empty())
icon_manager_.RemoveIcon(extension_id);
@@ -350,7 +363,7 @@ void ExtensionMenuManager::RadioItemSelected(ExtensionMenuItem* item) {
}
static void AddURLProperty(DictionaryValue* dictionary,
- const std::wstring& key, const GURL& url) {
+ const std::string& key, const GURL& url) {
if (!url.is_empty())
dictionary->SetString(key, url.possibly_invalid_spec());
}
@@ -374,32 +387,33 @@ void ExtensionMenuManager::ExecuteCommand(
ListValue args;
DictionaryValue* properties = new DictionaryValue();
- properties->SetInteger(L"menuItemId", item->id().second);
+ properties->SetInteger("menuItemId", item->id().second);
if (item->parent_id())
- properties->SetInteger(L"parentMenuItemId", item->parent_id()->second);
+ properties->SetInteger("parentMenuItemId", item->parent_id()->second);
switch (params.media_type) {
case WebKit::WebContextMenuData::MediaTypeImage:
- properties->SetString(L"mediaType", "IMAGE");
+ properties->SetString("mediaType", "image");
break;
case WebKit::WebContextMenuData::MediaTypeVideo:
- properties->SetString(L"mediaType", "VIDEO");
+ properties->SetString("mediaType", "video");
break;
case WebKit::WebContextMenuData::MediaTypeAudio:
- properties->SetString(L"mediaType", "AUDIO");
+ properties->SetString("mediaType", "audio");
break;
default: {} // Do nothing.
}
- AddURLProperty(properties, L"linkUrl", params.unfiltered_link_url);
- AddURLProperty(properties, L"srcUrl", params.src_url);
- AddURLProperty(properties, L"mainFrameUrl", params.page_url);
- AddURLProperty(properties, L"frameUrl", params.frame_url);
+ AddURLProperty(properties, "linkUrl", params.unfiltered_link_url);
+ AddURLProperty(properties, "srcUrl", params.src_url);
+ AddURLProperty(properties, "pageUrl", params.page_url);
+ AddURLProperty(properties, "frameUrl", params.frame_url);
if (params.selection_text.length() > 0)
- properties->SetString(L"selectionText", params.selection_text);
+ properties->SetString("selectionText",
+ WideToUTF16Hack(params.selection_text));
- properties->SetBoolean(L"editable", params.is_editable);
+ properties->SetBoolean("editable", params.is_editable);
args.Append(properties);
@@ -413,7 +427,7 @@ void ExtensionMenuManager::ExecuteCommand(
if (item->type() == ExtensionMenuItem::CHECKBOX ||
item->type() == ExtensionMenuItem::RADIO) {
bool was_checked = item->checked();
- properties->SetBoolean(L"wasChecked", was_checked);
+ properties->SetBoolean("wasChecked", was_checked);
// RADIO items always get set to true when you click on them, but CHECKBOX
// items get their state toggled.
@@ -421,14 +435,13 @@ void ExtensionMenuManager::ExecuteCommand(
(item->type() == ExtensionMenuItem::RADIO) ? true : !was_checked;
item->SetChecked(checked);
- properties->SetBoolean(L"checked", item->checked());
+ properties->SetBoolean("checked", item->checked());
}
std::string json_args;
base::JSONWriter::Write(&args, false, &json_args);
std::string event_name = "contextMenus/" + item->extension_id();
- service->DispatchEventToRenderers(event_name, json_args,
- profile->IsOffTheRecord(), GURL());
+ service->DispatchEventToRenderers(event_name, json_args, profile, GURL());
}
void ExtensionMenuManager::Observe(NotificationType type,
diff --git a/chrome/browser/extensions/extension_menu_manager.h b/chrome/browser/extensions/extension_menu_manager.h
index 405cae1..a58c1df 100644
--- a/chrome/browser/extensions/extension_menu_manager.h
+++ b/chrome/browser/extensions/extension_menu_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_MENU_MANAGER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_MENU_MANAGER_H_
+#pragma once
#include <map>
#include <set>
@@ -11,6 +12,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "chrome/browser/extensions/extension_icon_manager.h"
@@ -21,7 +23,6 @@
struct ContextMenuParams;
class Extension;
-class ExtensionMessageService;
class Profile;
class SkBitmap;
class TabContents;
@@ -119,8 +120,10 @@ class ExtensionMenuItem {
target_url_patterns_ = patterns;
}
- // Returns the title with any instances of %s replaced by |selection|.
- string16 TitleWithReplacement(const string16& selection) const;
+ // Returns the title with any instances of %s replaced by |selection|. The
+ // result will be no longer than |max_length|.
+ string16 TitleWithReplacement(const string16& selection,
+ size_t max_length) const;
// Set the checked state to |checked|. Returns true if successful.
bool SetChecked(bool checked);
@@ -131,10 +134,6 @@ class ExtensionMenuItem {
// Takes ownership of |item| and sets its parent_id_.
void AddChild(ExtensionMenuItem* item);
- // Removes child menu item with the given id, returning true if the item was
- // found and removed, or false otherwise.
- bool RemoveChild(const Id& child_id);
-
// Takes the child item from this parent. The item is returned and the caller
// then owns the pointer.
ExtensionMenuItem* ReleaseChild(const Id& child_id, bool recursive);
@@ -244,6 +243,8 @@ class ExtensionMenuManager : public NotificationObserver {
static bool HasAllowedScheme(const GURL& url);
private:
+ FRIEND_TEST_ALL_PREFIXES(ExtensionMenuManagerTest, DeleteParent);
+
// This is a helper function which takes care of de-selecting any other radio
// items in the same group (i.e. that are adjacent in the list).
void RadioItemSelected(ExtensionMenuItem* item);
diff --git a/chrome/browser/extensions/extension_menu_manager_unittest.cc b/chrome/browser/extensions/extension_menu_manager_unittest.cc
index e3f82e8..e3a61a1 100644
--- a/chrome/browser/extensions/extension_menu_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_menu_manager_unittest.cc
@@ -9,6 +9,7 @@
#include "base/scoped_temp_dir.h"
#include "base/scoped_vector.h"
#include "base/values.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_menu_manager.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/test_extension_prefs.h"
@@ -152,6 +153,71 @@ TEST_F(ExtensionMenuManagerTest, ChildFunctions) {
ASSERT_EQ(0, item2->child_count());
}
+// Tests that deleting a parent properly removes descendants.
+TEST_F(ExtensionMenuManagerTest, DeleteParent) {
+ Extension* extension = AddExtension("1111");
+
+ // Set up 5 items to add.
+ ExtensionMenuItem* item1 = CreateTestItem(extension);
+ ExtensionMenuItem* item2 = CreateTestItem(extension);
+ ExtensionMenuItem* item3 = CreateTestItem(extension);
+ ExtensionMenuItem* item4 = CreateTestItem(extension);
+ ExtensionMenuItem* item5 = CreateTestItem(extension);
+ ExtensionMenuItem* item6 = CreateTestItem(extension);
+ ExtensionMenuItem::Id item1_id = item1->id();
+ ExtensionMenuItem::Id item2_id = item2->id();
+ ExtensionMenuItem::Id item3_id = item3->id();
+ ExtensionMenuItem::Id item4_id = item4->id();
+ ExtensionMenuItem::Id item5_id = item5->id();
+ ExtensionMenuItem::Id item6_id = item6->id();
+
+ // Add the items in the hierarchy
+ // item1 -> item2 -> item3 -> item4 -> item5 -> item6.
+ ASSERT_TRUE(manager_.AddContextItem(extension, item1));
+ ASSERT_TRUE(manager_.AddChildItem(item1_id, item2));
+ ASSERT_TRUE(manager_.AddChildItem(item2_id, item3));
+ ASSERT_TRUE(manager_.AddChildItem(item3_id, item4));
+ ASSERT_TRUE(manager_.AddChildItem(item4_id, item5));
+ ASSERT_TRUE(manager_.AddChildItem(item5_id, item6));
+ ASSERT_EQ(item1, manager_.GetItemById(item1_id));
+ ASSERT_EQ(item2, manager_.GetItemById(item2_id));
+ ASSERT_EQ(item3, manager_.GetItemById(item3_id));
+ ASSERT_EQ(item4, manager_.GetItemById(item4_id));
+ ASSERT_EQ(item5, manager_.GetItemById(item5_id));
+ ASSERT_EQ(item6, manager_.GetItemById(item6_id));
+ ASSERT_EQ(1u, manager_.MenuItems(extension->id())->size());
+ ASSERT_EQ(6u, manager_.items_by_id_.size());
+
+ // Remove item6 (a leaf node).
+ ASSERT_TRUE(manager_.RemoveContextMenuItem(item6_id));
+ ASSERT_EQ(item1, manager_.GetItemById(item1_id));
+ ASSERT_EQ(item2, manager_.GetItemById(item2_id));
+ ASSERT_EQ(item3, manager_.GetItemById(item3_id));
+ ASSERT_EQ(item4, manager_.GetItemById(item4_id));
+ ASSERT_EQ(item5, manager_.GetItemById(item5_id));
+ ASSERT_EQ(NULL, manager_.GetItemById(item6_id));
+ ASSERT_EQ(1u, manager_.MenuItems(extension->id())->size());
+ ASSERT_EQ(5u, manager_.items_by_id_.size());
+
+ // Remove item4 and make sure item5 is gone as well.
+ ASSERT_TRUE(manager_.RemoveContextMenuItem(item4_id));
+ ASSERT_EQ(item1, manager_.GetItemById(item1_id));
+ ASSERT_EQ(item2, manager_.GetItemById(item2_id));
+ ASSERT_EQ(item3, manager_.GetItemById(item3_id));
+ ASSERT_EQ(NULL, manager_.GetItemById(item4_id));
+ ASSERT_EQ(NULL, manager_.GetItemById(item5_id));
+ ASSERT_EQ(1u, manager_.MenuItems(extension->id())->size());
+ ASSERT_EQ(3u, manager_.items_by_id_.size());
+
+ // Now remove item1 and make sure item2 and item3 are gone as well.
+ ASSERT_TRUE(manager_.RemoveContextMenuItem(item1_id));
+ ASSERT_EQ(0u, manager_.MenuItems(extension->id())->size());
+ ASSERT_EQ(0u, manager_.items_by_id_.size());
+ ASSERT_EQ(NULL, manager_.GetItemById(item1_id));
+ ASSERT_EQ(NULL, manager_.GetItemById(item2_id));
+ ASSERT_EQ(NULL, manager_.GetItemById(item3_id));
+}
+
// Tests changing parents.
TEST_F(ExtensionMenuManagerTest, ChangeParent) {
Extension* extension1 = AddExtension("1111");
@@ -272,7 +338,7 @@ class MockExtensionMessageService : public ExtensionMessageService {
MOCK_METHOD4(DispatchEventToRenderers, void(const std::string& event_name,
const std::string& event_args,
- bool has_incognito_data,
+ Profile* source_profile,
const GURL& event_url));
private:
@@ -347,17 +413,13 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
.Times(1)
.WillOnce(Return(mock_message_service.get()));
- EXPECT_CALL(profile, IsOffTheRecord())
- .Times(AtLeast(1))
- .WillRepeatedly(Return(false));
-
// Use the magic of googlemock to save a parameter to our mock's
// DispatchEventToRenderers method into event_args.
std::string event_args;
std::string expected_event_name = "contextMenus/" + item->extension_id();
EXPECT_CALL(*mock_message_service.get(),
DispatchEventToRenderers(expected_event_name, _,
- profile.IsOffTheRecord(),
+ &profile,
GURL()))
.Times(1)
.WillOnce(SaveArg<1>(&event_args));
@@ -378,22 +440,21 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
ASSERT_TRUE(list->GetDictionary(0, &info));
int tmp_id = 0;
- ASSERT_TRUE(info->GetInteger(L"menuItemId", &tmp_id));
+ ASSERT_TRUE(info->GetInteger("menuItemId", &tmp_id));
ASSERT_EQ(id.second, tmp_id);
std::string tmp;
- ASSERT_TRUE(info->GetString(L"mediaType", &tmp));
- ASSERT_EQ("IMAGE", tmp);
- ASSERT_TRUE(info->GetString(L"srcUrl", &tmp));
+ ASSERT_TRUE(info->GetString("mediaType", &tmp));
+ ASSERT_EQ("image", tmp);
+ ASSERT_TRUE(info->GetString("srcUrl", &tmp));
ASSERT_EQ(params.src_url.spec(), tmp);
- ASSERT_TRUE(info->GetString(L"mainFrameUrl", &tmp));
+ ASSERT_TRUE(info->GetString("pageUrl", &tmp));
ASSERT_EQ(params.page_url.spec(), tmp);
- std::wstring wide_tmp;
- ASSERT_TRUE(info->GetString(L"selectionText", &wide_tmp));
- ASSERT_EQ(params.selection_text, wide_tmp);
+ ASSERT_TRUE(info->GetString("selectionText", &tmp));
+ ASSERT_EQ(WideToUTF8(params.selection_text), tmp);
bool bool_tmp = true;
- ASSERT_TRUE(info->GetBoolean(L"editable", &bool_tmp));
+ ASSERT_TRUE(info->GetBoolean("editable", &bool_tmp));
ASSERT_EQ(params.is_editable, bool_tmp);
}
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc
index bdd5620..2fb59c3 100644
--- a/chrome/browser/extensions/extension_message_service.cc
+++ b/chrome/browser/extensions/extension_message_service.cc
@@ -4,12 +4,11 @@
#include "chrome/browser/extensions/extension_message_service.h"
+#include "base/atomic_sequence_num.h"
#include "base/json/json_writer.h"
-#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/values.h"
#include "chrome/browser/child_process_security_policy.h"
-#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/profile.h"
@@ -37,15 +36,9 @@
struct ExtensionMessageService::MessagePort {
IPC::Message::Sender* sender;
int routing_id;
- // TODO(mpcomplete): remove this when I track down the crasher. Hopefully
- // this guy will show up in some stack traces and potentially give some
- // insight.
- // http://code.google.com/p/chromium/issues/detail?id=21201
- int debug_info;
-
MessagePort(IPC::Message::Sender* sender = NULL,
int routing_id = MSG_ROUTING_CONTROL) :
- sender(sender), routing_id(routing_id), debug_info(0) {}
+ sender(sender), routing_id(routing_id) {}
};
struct ExtensionMessageService::MessageChannel {
@@ -53,9 +46,19 @@ struct ExtensionMessageService::MessageChannel {
ExtensionMessageService::MessagePort receiver;
};
+const char ExtensionMessageService::kDispatchOnConnect[] =
+ "Port.dispatchOnConnect";
+const char ExtensionMessageService::kDispatchOnDisconnect[] =
+ "Port.dispatchOnDisconnect";
+const char ExtensionMessageService::kDispatchOnMessage[] =
+ "Port.dispatchOnMessage";
+const char ExtensionMessageService::kDispatchEvent[] =
+ "Event.dispatchJSON";
namespace {
+static base::AtomicSequenceNumber g_next_channel_id(base::LINKER_INITIALIZED);
+
static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port,
int dest_port_id,
const std::string& channel_name,
@@ -105,15 +108,6 @@ static void DispatchEvent(const ExtensionMessageService::MessagePort& port,
} // namespace
-const char ExtensionMessageService::kDispatchOnConnect[] =
- "Port.dispatchOnConnect";
-const char ExtensionMessageService::kDispatchOnDisconnect[] =
- "Port.dispatchOnDisconnect";
-const char ExtensionMessageService::kDispatchOnMessage[] =
- "Port.dispatchOnMessage";
-const char ExtensionMessageService::kDispatchEvent[] =
- "Event.dispatchJSON";
-
// static
std::string ExtensionMessageService::GetPerExtensionEventName(
const std::string& event_name, const std::string& extension_id) {
@@ -122,10 +116,28 @@ std::string ExtensionMessageService::GetPerExtensionEventName(
return event_name + "/" + extension_id;
}
+// static
+void ExtensionMessageService::AllocatePortIdPair(int* port1, int* port2) {
+ int channel_id = g_next_channel_id.GetNext();
+ int port1_id = channel_id * 2;
+ int port2_id = channel_id * 2 + 1;
+
+ // Sanity checks to make sure our channel<->port converters are correct.
+ DCHECK(IS_OPENER_PORT_ID(port1_id));
+ DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
+ DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
+ DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
+ DCHECK(GET_CHANNEL_ID(port1_id) == channel_id);
+ DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id);
+ DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id);
+
+ *port1 = port1_id;
+ *port2 = port2_id;
+}
+
ExtensionMessageService::ExtensionMessageService(Profile* profile)
: profile_(profile),
- extension_devtools_manager_(NULL),
- next_port_id_(0) {
+ extension_devtools_manager_(NULL) {
registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED,
@@ -141,12 +153,10 @@ ExtensionMessageService::~ExtensionMessageService() {
channels_.clear();
}
-void ExtensionMessageService::ProfileDestroyed() {
+void ExtensionMessageService::DestroyingProfile() {
profile_ = NULL;
- if (!registrar_.IsEmpty()) {
- CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ if (!registrar_.IsEmpty())
registrar_.RemoveAll();
- }
}
void ExtensionMessageService::AddEventListener(const std::string& event_name,
@@ -157,7 +167,6 @@ void ExtensionMessageService::AddEventListener(const std::string& event_name,
if (!rph || rph->ListenersIterator().IsAtEnd())
return;
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
DCHECK_EQ(listeners_[event_name].count(render_process_id), 0u) << event_name;
listeners_[event_name].insert(render_process_id);
@@ -174,7 +183,6 @@ void ExtensionMessageService::RemoveEventListener(const std::string& event_name,
if (!rph || rph->ListenersIterator().IsAtEnd())
return;
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
DCHECK_EQ(listeners_[event_name].count(render_process_id), 1u)
<< " PID=" << render_process_id << " event=" << event_name;
listeners_[event_name].erase(render_process_id);
@@ -191,90 +199,22 @@ bool ExtensionMessageService::HasEventListener(
!listeners_[event_name].empty());
}
-void ExtensionMessageService::AllocatePortIdPair(int* port1, int* port2) {
- AutoLock lock(next_port_id_lock_);
-
- // TODO(mpcomplete): what happens when this wraps?
- int port1_id = next_port_id_++;
- int port2_id = next_port_id_++;
-
- DCHECK(IS_OPENER_PORT_ID(port1_id));
- DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
- DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
- DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
-
- int channel_id = GET_CHANNEL_ID(port1_id);
- DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id);
- DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id);
-
- *port1 = port1_id;
- *port2 = port2_id;
-}
-
-int ExtensionMessageService::OpenChannelToExtension(
- int routing_id, const std::string& source_extension_id,
- const std::string& target_extension_id,
- const std::string& channel_name, ResourceMessageFilter* source) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-
- // Create a channel ID for both sides of the channel.
- int port1_id = -1;
- int port2_id = -1;
- AllocatePortIdPair(&port1_id, &port2_id);
-
- // Each side of the port is given his own port ID. When they send messages,
- // we convert to the opposite port ID. See PostMessageFromRenderer.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ExtensionMessageService::OpenChannelToExtensionOnUIThread,
- source->id(), routing_id, port2_id, source_extension_id,
- target_extension_id, channel_name));
-
- return port1_id;
-}
-
-int ExtensionMessageService::OpenChannelToTab(int routing_id,
- int tab_id,
- const std::string& extension_id,
- const std::string& channel_name,
- ResourceMessageFilter* source) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-
- // Create a channel ID for both sides of the channel.
- int port1_id = -1;
- int port2_id = -1;
- AllocatePortIdPair(&port1_id, &port2_id);
-
- // Each side of the port is given his own port ID. When they send messages,
- // we convert to the opposite port ID. See PostMessageFromRenderer.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ExtensionMessageService::OpenChannelToTabOnUIThread,
- source->id(), routing_id, port2_id, tab_id, extension_id,
- channel_name));
-
- return port1_id;
-}
-
-void ExtensionMessageService::OpenChannelToExtensionOnUIThread(
+void ExtensionMessageService::OpenChannelToExtension(
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) {
- if (!profile_)
- return;
-
RenderProcessHost* source = RenderProcessHost::FromID(source_process_id);
if (!source)
return;
+ // Note: we use the source's profile here. If the source is an incognito
+ // process, we will use the incognito EPM to find the right extension process,
+ // which depends on whether the extension uses spanning or split mode.
MessagePort receiver(
- profile_->GetExtensionProcessManager()->GetExtensionProcess(
+ source->profile()->GetExtensionProcessManager()->GetExtensionProcess(
target_extension_id),
MSG_ROUTING_CONTROL);
- receiver.debug_info = 1;
TabContents* source_contents = tab_util::GetTabContentsByID(
source_process_id, source_routing_id);
@@ -286,13 +226,11 @@ void ExtensionMessageService::OpenChannelToExtensionOnUIThread(
base::JSONWriter::Write(tab_value.get(), false, &tab_json);
}
- OpenChannelOnUIThreadImpl(source, tab_json,
- receiver, receiver_port_id,
- source_extension_id, target_extension_id,
- channel_name);
+ OpenChannelImpl(source, tab_json, receiver, receiver_port_id,
+ source_extension_id, target_extension_id, channel_name);
}
-void ExtensionMessageService::OpenChannelToTabOnUIThread(
+void ExtensionMessageService::OpenChannelToTab(
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) {
@@ -302,12 +240,10 @@ void ExtensionMessageService::OpenChannelToTabOnUIThread(
TabContents* contents = NULL;
MessagePort receiver;
- receiver.debug_info = 2;
if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), true,
NULL, NULL, &contents, NULL)) {
receiver.sender = contents->render_view_host();
receiver.routing_id = contents->render_view_host()->routing_id();
- receiver.debug_info = 3;
}
if (contents && contents->controller().needs_reload()) {
@@ -329,20 +265,17 @@ void ExtensionMessageService::OpenChannelToTabOnUIThread(
base::JSONWriter::Write(tab_value.get(), false, &tab_json);
}
- OpenChannelOnUIThreadImpl(source, tab_json,
- receiver, receiver_port_id,
- extension_id, extension_id, channel_name);
+ OpenChannelImpl(source, tab_json, receiver, receiver_port_id,
+ extension_id, extension_id, channel_name);
}
-bool ExtensionMessageService::OpenChannelOnUIThreadImpl(
+bool ExtensionMessageService::OpenChannelImpl(
IPC::Message::Sender* source,
const std::string& tab_json,
const MessagePort& receiver, int receiver_port_id,
const std::string& source_extension_id,
const std::string& target_extension_id,
const std::string& channel_name) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
-
// TODO(mpcomplete): notify source if receiver doesn't exist
if (!source)
return false; // Closed while in flight.
@@ -380,7 +313,6 @@ bool ExtensionMessageService::OpenChannelOnUIThreadImpl(
int ExtensionMessageService::OpenSpecialChannelToExtension(
const std::string& extension_id, const std::string& channel_name,
const std::string& tab_json, IPC::Message::Sender* source) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
DCHECK(profile_);
int port1_id = -1;
@@ -389,13 +321,10 @@ int ExtensionMessageService::OpenSpecialChannelToExtension(
AllocatePortIdPair(&port1_id, &port2_id);
MessagePort receiver(
- profile_->GetExtensionProcessManager()->
- GetExtensionProcess(extension_id),
+ profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id),
MSG_ROUTING_CONTROL);
- receiver.debug_info = 4;
- if (!OpenChannelOnUIThreadImpl(
- source, tab_json, receiver, port2_id, extension_id, extension_id,
- channel_name))
+ if (!OpenChannelImpl(source, tab_json, receiver, port2_id,
+ extension_id, extension_id, channel_name))
return -1;
return port1_id;
@@ -404,7 +333,6 @@ int ExtensionMessageService::OpenSpecialChannelToExtension(
int ExtensionMessageService::OpenSpecialChannelToTab(
const std::string& extension_id, const std::string& channel_name,
TabContents* target_tab_contents, IPC::Message::Sender* source) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
DCHECK(target_tab_contents);
if (target_tab_contents->controller().needs_reload()) {
@@ -420,18 +348,14 @@ int ExtensionMessageService::OpenSpecialChannelToTab(
MessagePort receiver(
target_tab_contents->render_view_host(),
target_tab_contents->render_view_host()->routing_id());
- receiver.debug_info = 5;
- if (!OpenChannelOnUIThreadImpl(source, "null",
- receiver, port2_id,
- extension_id, extension_id, channel_name))
+ if (!OpenChannelImpl(source, "null", receiver, port2_id,
+ extension_id, extension_id, channel_name))
return -1;
return port1_id;
}
void ExtensionMessageService::CloseChannel(int port_id) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
-
// Note: The channel might be gone already, if the other side closed first.
MessageChannelMap::iterator it = channels_.find(GET_CHANNEL_ID(port_id));
if (it != channels_.end())
@@ -441,8 +365,6 @@ void ExtensionMessageService::CloseChannel(int port_id) {
void ExtensionMessageService::CloseChannelImpl(
MessageChannelMap::iterator channel_iter, int closing_port_id,
bool notify_other_port) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
-
// Notify the other side.
const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ?
channel_iter->second->receiver : channel_iter->second->opener;
@@ -455,8 +377,6 @@ void ExtensionMessageService::CloseChannelImpl(
void ExtensionMessageService::PostMessageFromRenderer(
int source_port_id, const std::string& message) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
-
MessageChannelMap::iterator iter =
channels_.find(GET_CHANNEL_ID(source_port_id));
if (iter == channels_.end())
@@ -472,8 +392,13 @@ void ExtensionMessageService::PostMessageFromRenderer(
void ExtensionMessageService::DispatchEventToRenderers(
const std::string& event_name, const std::string& event_args,
- bool has_incognito_data, const GURL& event_url) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
+ Profile* source_profile, const GURL& event_url) {
+ if (!profile_)
+ return;
+
+ // We don't expect to get events from a completely different profile.
+ DCHECK(!source_profile || profile_->IsSameProfile(source_profile));
+
ListenerMap::iterator it = listeners_.find(event_name);
if (it == listeners_.end())
return;
@@ -491,24 +416,25 @@ void ExtensionMessageService::DispatchEventToRenderers(
continue;
}
- DispatchEvent(
- renderer, event_name, event_args, has_incognito_data, event_url);
+ // Is this event from a different profile than the renderer (ie, an
+ // incognito tab event sent to a normal process, or vice versa).
+ bool cross_profile =
+ source_profile && renderer->profile() != source_profile;
+ DispatchEvent(renderer, event_name, event_args, cross_profile, event_url);
}
}
void ExtensionMessageService::DispatchEventToExtension(
const std::string& extension_id,
const std::string& event_name, const std::string& event_args,
- bool has_incognito_data, const GURL& event_url) {
+ Profile* source_profile, const GURL& event_url) {
DispatchEventToRenderers(GetPerExtensionEventName(event_name, extension_id),
- event_args, has_incognito_data, event_url);
+ event_args, source_profile, event_url);
}
void ExtensionMessageService::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
-
switch (type.value) {
case NotificationType::RENDERER_PROCESS_TERMINATED:
case NotificationType::RENDERER_PROCESS_CLOSED: {
@@ -527,26 +453,6 @@ void ExtensionMessageService::Observe(NotificationType type,
case NotificationType::RENDER_VIEW_HOST_DELETED:
OnSenderClosed(Details<RenderViewHost>(details).ptr());
break;
-
- // We should already have removed this guy from our channel map by this
- // point.
- case NotificationType::EXTENSION_PORT_DELETED_DEBUG: {
- IPC::Message::Sender* sender =
- Details<IPC::Message::Sender>(details).ptr();
- for (MessageChannelMap::iterator it = channels_.begin();
- it != channels_.end(); ) {
- MessageChannelMap::iterator current = it++;
- int debug_info = current->second->receiver.debug_info;
- if (current->second->opener.sender == sender) {
- LOG(FATAL) << "Shouldn't happen:" << debug_info;
- } else if (current->second->receiver.sender == sender) {
- LOG(FATAL) << "Shouldn't happen either: " << debug_info;
- }
- }
- OnSenderClosed(sender);
- break;
- }
-
default:
NOTREACHED();
return;
@@ -561,11 +467,8 @@ void ExtensionMessageService::OnSenderClosed(IPC::Message::Sender* sender) {
MessageChannelMap::iterator current = it++;
// If both sides are the same renderer, and it is closing, there is no
// "other" port, so there's no need to notify it.
- int debug_info = current->second->receiver.debug_info;
- bool debug_check = debug_info == 4 || debug_info == 5;
bool notify_other_port =
- current->second->opener.sender != current->second->receiver.sender ||
- debug_check;
+ current->second->opener.sender != current->second->receiver.sender;
if (current->second->opener.sender == sender) {
CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h
index fa89786..9d8c038 100644
--- a/chrome/browser/extensions/extension_message_service.h
+++ b/chrome/browser/extensions/extension_message_service.h
@@ -4,25 +4,21 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_
+#pragma once
#include <map>
#include <set>
#include <string>
-#include "base/lock.h"
#include "base/ref_counted.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_devtools_manager.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
#include "ipc/ipc_message.h"
class GURL;
-class MessageLoop;
class Profile;
-class RenderProcessHost;
-class ResourceMessageFilter;
class TabContents;
-class URLRequestContext;
// This class manages message and event passing between renderer processes.
// It maintains a list of processes that are listening to events and a set of
@@ -45,9 +41,11 @@ class URLRequestContext;
// port: an IPC::Message::Sender interface and an optional routing_id (in the
// case that the port is a tab). The Sender is usually either a
// RenderProcessHost or a RenderViewHost.
+
+// TODO(mpcomplete): Remove refcounting and make Profile the sole owner of this
+// class. Then we can get rid of ProfileDestroyed().
class ExtensionMessageService
- : public base::RefCountedThreadSafe<
- ExtensionMessageService, ChromeThread::DeleteOnUIThread>,
+ : public base::RefCounted<ExtensionMessageService>,
public NotificationObserver {
public:
// Javascript function name constants.
@@ -66,12 +64,14 @@ class ExtensionMessageService
static std::string GetPerExtensionEventName(const std::string& event_name,
const std::string& extension_id);
- // --- UI thread only:
+ // Allocates a pair of port ids.
+ // NOTE: this can be called from any thread.
+ static void AllocatePortIdPair(int* port1, int* port2);
explicit ExtensionMessageService(Profile* profile);
// Notification that our owning profile is going away.
- void ProfileDestroyed();
+ void DestroyingProfile();
// Add or remove |render_process_pid| as a listener for |event_name|.
void AddEventListener(const std::string& event_name, int render_process_id);
@@ -81,27 +81,37 @@ class ExtensionMessageService
// Returns true if there is at least one listener for the given event.
bool HasEventListener(const std::string& event_name);
- // Closes the message channel associated with the given port, and notifies
- // the other side.
- void CloseChannel(int port_id);
-
- // Sends a message from a renderer to the given port.
- void PostMessageFromRenderer(int port_id, const std::string& message);
-
// Send an event to every registered extension renderer. If
// |has_incognito_data| is true, the event is only sent to extension with the
// permission to access incognito data. If |event_url| is not empty, the
// event is only sent to extension with host permissions for this url.
virtual void DispatchEventToRenderers(
const std::string& event_name, const std::string& event_args,
- bool has_incognito_data, const GURL& event_url);
+ Profile* source_profile, const GURL& event_url);
// Same as above, except use the extension-specific naming scheme for the
// event. This is used by events that are per-extension.
void DispatchEventToExtension(
const std::string& extension_id,
const std::string& event_name, const std::string& event_args,
- bool has_incognito_data, const GURL& event_url);
+ Profile* source_profile, const GURL& event_url);
+
+ // Given an extension's ID, opens a channel between the given renderer "port"
+ // and every listening context owned by that extension. |channel_name| is
+ // an optional identifier for use by extension developers.
+ void OpenChannelToExtension(
+ 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);
+
+ // Same as above, but opens a channel to the tab with the given ID. Messages
+ // are restricted to that tab, so if there are multiple tabs in that process,
+ // only the targeted tab will receive messages.
+ void OpenChannelToTab(
+ 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);
// Given an extension ID, opens a channel between the given
// automation "port" or DevTools service and that extension. the
@@ -125,31 +135,15 @@ class ExtensionMessageService
const std::string& extension_id, const std::string& channel_name,
TabContents* target_tab_contents, IPC::Message::Sender* source);
- // --- IO thread only:
-
- // Given an extension's ID, opens a channel between the given renderer "port"
- // and every listening context owned by that extension. Returns a port ID
- // to be used for posting messages between the processes. |channel_name| is
- // an optional identifier for use by extension developers.
- // This runs on the IO thread so that it can be used in a synchronous IPC
- // message.
- int OpenChannelToExtension(int routing_id,
- const std::string& source_extension_id,
- const std::string& target_extension_id,
- const std::string& channel_name,
- ResourceMessageFilter* source);
+ // Closes the message channel associated with the given port, and notifies
+ // the other side.
+ void CloseChannel(int port_id);
- // Same as above, but opens a channel to the tab with the given ID. Messages
- // are restricted to that tab, so if there are multiple tabs in that process,
- // only the targeted tab will receive messages.
- int OpenChannelToTab(int routing_id, int tab_id,
- const std::string& extension_id,
- const std::string& channel_name,
- ResourceMessageFilter* source);
+ // Sends a message from a renderer to the given port.
+ void PostMessageFromRenderer(int port_id, const std::string& message);
private:
- friend class ChromeThread;
- friend class DeleteTask<ExtensionMessageService>;
+ friend class base::RefCounted<ExtensionMessageService>;
friend class MockExtensionMessageService;
// A map of channel ID to its channel object.
@@ -157,30 +151,8 @@ class ExtensionMessageService
virtual ~ExtensionMessageService();
- // Allocates a pair of port ids.
- // NOTE: this can be called from any thread.
- void AllocatePortIdPair(int* port1, int* port2);
-
- void CloseChannelImpl(MessageChannelMap::iterator channel_iter, int port_id,
- bool notify_other_port);
-
- // --- UI thread only:
-
- // Handles channel creation and notifies the destinations that a channel was
- // opened.
- 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 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);
-
- // Common between OpenChannelOnUIThread and OpenSpecialChannelToExtension.
- bool OpenChannelOnUIThreadImpl(
+ // Common among Open(Special)Channel* variants.
+ bool OpenChannelImpl(
IPC::Message::Sender* source,
const std::string& tab_json,
const MessagePort& receiver, int receiver_port_id,
@@ -188,6 +160,9 @@ class ExtensionMessageService
const std::string& target_extension_id,
const std::string& channel_name);
+ void CloseChannelImpl(MessageChannelMap::iterator channel_iter, int port_id,
+ bool notify_other_port);
+
// NotificationObserver interface.
void Observe(NotificationType type,
const NotificationSource& source,
@@ -209,15 +184,6 @@ class ExtensionMessageService
typedef std::map<std::string, std::set<int> > ListenerMap;
ListenerMap listeners_;
- // --- UI or IO thread:
-
- // For generating unique channel IDs.
- int next_port_id_;
-
- // Protects the next_port_id_ variable, since it can be
- // used on the IO thread or the UI thread.
- Lock next_port_id_lock_;
-
DISALLOW_COPY_AND_ASSIGN(ExtensionMessageService);
};
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 4370375..533b840 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_registrar.h"
+#include "googleurl/src/gurl.h"
namespace {
@@ -27,19 +28,19 @@ class MessageSender : public NotificationObserver {
// from the origin http://b.com/ are supposed to arrive.
message_service->DispatchEventToRenderers("test.onMessage",
"[{\"lastMessage\":false,\"data\":\"no restriction\"}]",
- Source<Profile>(source).ptr()->IsOffTheRecord(),
+ Source<Profile>(source).ptr(),
GURL());
message_service->DispatchEventToRenderers("test.onMessage",
"[{\"lastMessage\":false,\"data\":\"http://a.com/\"}]",
- Source<Profile>(source).ptr()->IsOffTheRecord(),
+ Source<Profile>(source).ptr(),
GURL("http://a.com/"));
message_service->DispatchEventToRenderers("test.onMessage",
"[{\"lastMessage\":false,\"data\":\"http://b.com/\"}]",
- Source<Profile>(source).ptr()->IsOffTheRecord(),
+ Source<Profile>(source).ptr(),
GURL("http://b.com/"));
message_service->DispatchEventToRenderers("test.onMessage",
"[{\"lastMessage\":true,\"data\":\"last message\"}]",
- Source<Profile>(source).ptr()->IsOffTheRecord(),
+ Source<Profile>(source).ptr(),
GURL());
}
@@ -50,7 +51,7 @@ class MessageSender : public NotificationObserver {
// Tests that message passing between extensions and content scripts works.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Messaging) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_;
}
diff --git a/chrome/browser/extensions/extension_messages_unittest.cc b/chrome/browser/extensions/extension_messages_unittest.cc
deleted file mode 100644
index b90e92f..0000000
--- a/chrome/browser/extensions/extension_messages_unittest.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 "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/renderer/extensions/event_bindings.h"
-#include "chrome/renderer/extensions/renderer_extension_bindings.h"
-#include "chrome/test/render_view_test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-static void DispatchOnConnect(int source_port_id, const std::string& name,
- const std::string& tab_json) {
- ListValue args;
- args.Set(0, Value::CreateIntegerValue(source_port_id));
- args.Set(1, Value::CreateStringValue(name));
- args.Set(2, Value::CreateStringValue(tab_json));
- args.Set(3, Value::CreateStringValue("")); // extension ID is empty for tests
- args.Set(4, Value::CreateStringValue("")); // extension ID is empty for tests
- RendererExtensionBindings::Invoke(
- ExtensionMessageService::kDispatchOnConnect, args, NULL, false, GURL());
-}
-
-static void DispatchOnDisconnect(int source_port_id) {
- ListValue args;
- args.Set(0, Value::CreateIntegerValue(source_port_id));
- RendererExtensionBindings::Invoke(
- ExtensionMessageService::kDispatchOnDisconnect, args, NULL, false,
- GURL());
-}
-
-static void DispatchOnMessage(const std::string& message, int source_port_id) {
- ListValue args;
- args.Set(0, Value::CreateStringValue(message));
- args.Set(1, Value::CreateIntegerValue(source_port_id));
- RendererExtensionBindings::Invoke(
- ExtensionMessageService::kDispatchOnMessage, args, NULL, false, GURL());
-}
-
-// Tests that the bindings for opening a channel to an extension and sending
-// and receiving messages through that channel all works.
-TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) {
- render_thread_.sink().ClearMessages();
- LoadHTML("<body></body>");
- ExecuteJavaScript(
- "var port = chrome.extension.connect({name:'testName'});"
- "port.onMessage.addListener(doOnMessage);"
- "port.postMessage({message: 'content ready'});"
- "function doOnMessage(msg, port) {"
- " alert('content got: ' + msg.val);"
- "}");
-
- // Verify that we opened a channel and sent a message through it.
- const IPC::Message* open_channel_msg =
- render_thread_.sink().GetUniqueMessageMatching(
- ViewHostMsg_OpenChannelToExtension::ID);
- ASSERT_TRUE(open_channel_msg);
- void* iter = IPC::SyncMessage::GetDataIterator(open_channel_msg);
- ViewHostMsg_OpenChannelToExtension::SendParam open_params;
- ASSERT_TRUE(IPC::ReadParam(open_channel_msg, &iter, &open_params));
- EXPECT_EQ("testName", open_params.d);
-
- const IPC::Message* post_msg =
- render_thread_.sink().GetUniqueMessageMatching(
- ViewHostMsg_ExtensionPostMessage::ID);
- ASSERT_TRUE(post_msg);
- ViewHostMsg_ExtensionPostMessage::Param post_params;
- ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
- EXPECT_EQ("{\"message\":\"content ready\"}", post_params.b);
-
- // Now simulate getting a message back from the other side.
- render_thread_.sink().ClearMessages();
- const int kPortId = 0;
- DispatchOnMessage("{\"val\": 42}", kPortId);
-
- // Verify that we got it.
- const IPC::Message* alert_msg =
- render_thread_.sink().GetUniqueMessageMatching(
- ViewHostMsg_RunJavaScriptMessage::ID);
- ASSERT_TRUE(alert_msg);
- iter = IPC::SyncMessage::GetDataIterator(alert_msg);
- ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
- ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
- EXPECT_EQ(L"content got: 42", alert_param.a);
-}
-
-// Tests that the bindings for handling a new channel connection and channel
-// closing all works.
-TEST_F(RenderViewTest, ExtensionMessagesOnConnect) {
- LoadHTML("<body></body>");
- ExecuteJavaScript(
- "chrome.extension.onConnect.addListener(function (port) {"
- " port.test = 24;"
- " port.onMessage.addListener(doOnMessage);"
- " port.onDisconnect.addListener(doOnDisconnect);"
- " port.postMessage({message: 'onconnect from ' + port.tab.url + "
- " ' name ' + port.name});"
- "});"
- "function doOnMessage(msg, port) {"
- " alert('got: ' + msg.val);"
- "}"
- "function doOnDisconnect(port) {"
- " alert('disconnected: ' + port.test);"
- "}");
-
- render_thread_.sink().ClearMessages();
-
- // Simulate a new connection being opened.
- const int kPortId = 0;
- const std::string kPortName = "testName";
- DispatchOnConnect(kPortId, kPortName, "{\"url\":\"foo://bar\"}");
-
- // Verify that we handled the new connection by posting a message.
- const IPC::Message* post_msg =
- render_thread_.sink().GetUniqueMessageMatching(
- ViewHostMsg_ExtensionPostMessage::ID);
- ASSERT_TRUE(post_msg);
- ViewHostMsg_ExtensionPostMessage::Param post_params;
- ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
- std::string expected_msg =
- "{\"message\":\"onconnect from foo://bar name " + kPortName + "\"}";
- EXPECT_EQ(expected_msg, post_params.b);
-
- // Now simulate getting a message back from the channel opener.
- render_thread_.sink().ClearMessages();
- DispatchOnMessage("{\"val\": 42}", kPortId);
-
- // Verify that we got it.
- const IPC::Message* alert_msg =
- render_thread_.sink().GetUniqueMessageMatching(
- ViewHostMsg_RunJavaScriptMessage::ID);
- ASSERT_TRUE(alert_msg);
- void* iter = IPC::SyncMessage::GetDataIterator(alert_msg);
- ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
- ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
- EXPECT_EQ(L"got: 42", alert_param.a);
-
- // Now simulate the channel closing.
- render_thread_.sink().ClearMessages();
- DispatchOnDisconnect(kPortId);
-
- // Verify that we got it.
- alert_msg =
- render_thread_.sink().GetUniqueMessageMatching(
- ViewHostMsg_RunJavaScriptMessage::ID);
- ASSERT_TRUE(alert_msg);
- iter = IPC::SyncMessage::GetDataIterator(alert_msg);
- ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
- EXPECT_EQ(L"disconnected: 24", alert_param.a);
-}
diff --git a/chrome/browser/extensions/extension_metrics_module.cc b/chrome/browser/extensions/extension_metrics_module.cc
index 380cf0a..0f0ab14 100644
--- a/chrome/browser/extensions/extension_metrics_module.cc
+++ b/chrome/browser/extensions/extension_metrics_module.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/extension_metrics_module.h"
+#include "base/values.h"
#include "base/histogram.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -82,11 +83,11 @@ bool MetricsRecordValueFunction::RunImpl() {
int min;
int max;
int buckets;
- EXTENSION_FUNCTION_VALIDATE(metric_type->GetString(L"metricName", &name));
- EXTENSION_FUNCTION_VALIDATE(metric_type->GetString(L"type", &type));
- EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger(L"min", &min));
- EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger(L"max", &max));
- EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger(L"buckets", &buckets));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetString("metricName", &name));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetString("type", &type));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger("min", &min));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger("max", &max));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger("buckets", &buckets));
Histogram::ClassType histogram_type(type == "histogram-linear" ?
Histogram::LINEAR_HISTOGRAM : Histogram::HISTOGRAM);
diff --git a/chrome/browser/extensions/extension_metrics_module.h b/chrome/browser/extensions/extension_metrics_module.h
index 81e12be..f7a91dc 100644
--- a/chrome/browser/extensions/extension_metrics_module.h
+++ b/chrome/browser/extensions/extension_metrics_module.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_METRICS_MODULE_H__
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_METRICS_MODULE_H__
+#pragma once
#include <string>
diff --git a/chrome/browser/extensions/extension_omnibox_api.cc b/chrome/browser/extensions/extension_omnibox_api.cc
index c4845a6..26c91bb 100644
--- a/chrome/browser/extensions/extension_omnibox_api.cc
+++ b/chrome/browser/extensions/extension_omnibox_api.cc
@@ -25,19 +25,18 @@ const char kDescriptionStylesLengthError[] =
"Suggestion descriptionStyles contains an offset longer than the"
" description text";
-const wchar_t kSuggestionContent[] = L"content";
-const wchar_t kSuggestionDescription[] = L"description";
-const wchar_t kSuggestionDescriptionStyles[] = L"descriptionStyles";
-const wchar_t kDescriptionStylesType[] = L"type";
-const wchar_t kDescriptionStylesOffset[] = L"offset";
+const char kSuggestionContent[] = "content";
+const char kSuggestionDescription[] = "description";
+const char kSuggestionDescriptionStyles[] = "descriptionStyles";
+const char kDescriptionStylesType[] = "type";
+const char kDescriptionStylesOffset[] = "offset";
}; // namespace
// static
void ExtensionOmniboxEventRouter::OnInputStarted(
Profile* profile, const std::string& extension_id) {
profile->GetExtensionMessageService()->DispatchEventToExtension(
- extension_id, events::kOnInputStarted, "[]", profile->IsOffTheRecord(),
- GURL());
+ extension_id, events::kOnInputStarted, "[]", profile, GURL());
}
// static
@@ -56,8 +55,7 @@ bool ExtensionOmniboxEventRouter::OnInputChanged(
base::JSONWriter::Write(&args, false, &json_args);
profile->GetExtensionMessageService()->DispatchEventToExtension(
- extension_id, events::kOnInputChanged, json_args,
- profile->IsOffTheRecord(), GURL());
+ extension_id, events::kOnInputChanged, json_args, profile, GURL());
return true;
}
@@ -73,8 +71,7 @@ void ExtensionOmniboxEventRouter::OnInputEntered(
base::JSONWriter::Write(&args, false, &json_args);
profile->GetExtensionMessageService()->DispatchEventToExtension(
- extension_id, events::kOnInputEntered, json_args,
- profile->IsOffTheRecord(), GURL());
+ extension_id, events::kOnInputEntered, json_args, profile, GURL());
NotificationService::current()->Notify(
NotificationType::EXTENSION_OMNIBOX_INPUT_ENTERED,
@@ -85,8 +82,7 @@ void ExtensionOmniboxEventRouter::OnInputEntered(
void ExtensionOmniboxEventRouter::OnInputCancelled(
Profile* profile, const std::string& extension_id) {
profile->GetExtensionMessageService()->DispatchEventToExtension(
- extension_id, events::kOnInputCancelled, "[]", profile->IsOffTheRecord(),
- GURL());
+ extension_id, events::kOnInputCancelled, "[]", profile, GURL());
}
bool OmniboxSendSuggestionsFunction::RunImpl() {
@@ -101,9 +97,9 @@ bool OmniboxSendSuggestionsFunction::RunImpl() {
DictionaryValue* suggestion_value;
EXTENSION_FUNCTION_VALIDATE(suggestions_value->GetDictionary(
i, &suggestion_value));
- EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetStringAsUTF16(
+ EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString(
kSuggestionContent, &suggestion.content));
- EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetStringAsUTF16(
+ EXTENSION_FUNCTION_VALIDATE(suggestion_value->GetString(
kSuggestionDescription, &suggestion.description));
if (suggestion_value->HasKey(kSuggestionDescriptionStyles)) {
diff --git a/chrome/browser/extensions/extension_omnibox_api.h b/chrome/browser/extensions/extension_omnibox_api.h
index 320b40a..a648e67 100644
--- a/chrome/browser/extensions/extension_omnibox_api.h
+++ b/chrome/browser/extensions/extension_omnibox_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_OMNIBOX_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_OMNIBOX_API_H_
+#pragma once
#include "base/string16.h"
#include "chrome/browser/autocomplete/autocomplete.h"
diff --git a/chrome/browser/extensions/extension_omnibox_apitest.cc b/chrome/browser/extensions/extension_omnibox_apitest.cc
index 61021b5..f48d9a1 100644
--- a/chrome/browser/extensions/extension_omnibox_apitest.cc
+++ b/chrome/browser/extensions/extension_omnibox_apitest.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 "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
@@ -11,22 +14,31 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/location_bar.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/common/chrome_switches.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
+// Basic test is flaky on ChromeOS.
+// http://crbug.com/52929
+#if defined(OS_CHROMEOS)
+#define MAYBE_Basic FLAKY_Basic
+#else
+#define MAYBE_Basic Basic
+#endif
+
namespace {
std::wstring AutocompleteResultAsString(const AutocompleteResult& result) {
- std::wstring output(StringPrintf(L"{%d} ", result.size()));
+ std::wstring output(base::StringPrintf(L"{%d} ", result.size()));
for (size_t i = 0; i < result.size(); ++i) {
AutocompleteMatch match = result.match_at(i);
std::wstring provider_name(ASCIIToWide(match.provider->name()));
- output.append(StringPrintf(L"[\"%ls\" by \"%ls\"] ",
- match.contents.c_str(),
- provider_name.c_str()));
+ output.append(base::StringPrintf(L"[\"%ls\" by \"%ls\"] ",
+ match.contents.c_str(),
+ provider_name.c_str()));
}
return output;
}
@@ -57,16 +69,16 @@ class OmniboxApiTest : public ExtensionApiTest {
void WaitForAutocompleteDone(AutocompleteController* controller) {
while (!controller->done()) {
ui_test_utils::WaitForNotification(
- NotificationType::AUTOCOMPLETE_CONTROLLER_DEFAULT_MATCH_UPDATED);
+ NotificationType::AUTOCOMPLETE_CONTROLLER_RESULT_UPDATED);
}
}
};
-IN_PROC_BROWSER_TEST_F(OmniboxApiTest, Basic) {
+IN_PROC_BROWSER_TEST_F(OmniboxApiTest, MAYBE_Basic) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;
// The results depend on the TemplateURLModel being loaded. Make sure it is
diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc
index 3063975..1efa5e7 100644
--- a/chrome/browser/extensions/extension_override_apitest.cc
+++ b/chrome/browser/extensions/extension_override_apitest.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,7 @@
#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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/url_constants.h"
@@ -22,7 +22,7 @@ class ExtensionOverrideTest : public ExtensionApiTest {
ExtensionDOMUI::kExtensionURLOverrides);
ListValue* values = NULL;
- if (!overrides->GetList(L"history", &values))
+ if (!overrides->GetList("history", &values))
return false;
std::set<std::string> seen_overrides;
@@ -39,6 +39,18 @@ class ExtensionOverrideTest : public ExtensionApiTest {
return true;
}
+
+#if defined(TOUCH_UI)
+ // Navigate to the keyboard page, and ensure we have arrived at an
+ // extension URL.
+ void NavigateToKeyboard() {
+ ui_test_utils::NavigateToURL(browser(), GURL("chrome://keyboard/"));
+ TabContents* tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(tab->controller().GetActiveEntry());
+ EXPECT_TRUE(tab->controller().GetActiveEntry()->url().
+ SchemeIs(chrome::kExtensionScheme));
+ }
+#endif
};
IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideNewtab) {
@@ -120,7 +132,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, ShouldCleanUpDuplicateEntries) {
list->Append(Value::CreateStringValue("http://www.google.com/"));
browser()->profile()->GetPrefs()->GetMutableDictionary(
- ExtensionDOMUI::kExtensionURLOverrides)->Set(L"history", list);
+ ExtensionDOMUI::kExtensionURLOverrides)->Set("history", list);
ASSERT_FALSE(CheckHistoryOverridesContainsNoDupes());
@@ -128,3 +140,33 @@ IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, ShouldCleanUpDuplicateEntries) {
ASSERT_TRUE(CheckHistoryOverridesContainsNoDupes());
}
+
+#if defined(TOUCH_UI)
+IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideKeyboard) {
+ ASSERT_TRUE(RunExtensionTest("override/keyboard")) << message_;
+ {
+ ResultCatcher catcher;
+ NavigateToKeyboard();
+ ASSERT_TRUE(catcher.GetNextResult());
+ }
+
+ // Load the failing version. This should take precedence.
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("override").AppendASCII("keyboard_fails")));
+ {
+ ResultCatcher catcher;
+ NavigateToKeyboard();
+ ASSERT_FALSE(catcher.GetNextResult());
+ }
+
+ // Unload the failing version. We should be back to passing now.
+ const ExtensionList *extensions =
+ browser()->profile()->GetExtensionsService()->extensions();
+ UnloadExtension((*extensions->rbegin())->id());
+ {
+ ResultCatcher catcher;
+ NavigateToKeyboard();
+ ASSERT_TRUE(catcher.GetNextResult());
+ }
+}
+#endif
diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc
index f91c5ef..86426ee 100644
--- a/chrome/browser/extensions/extension_page_actions_module.cc
+++ b/chrome/browser/extensions/extension_page_actions_module.cc
@@ -1,10 +1,10 @@
-// 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.
#include "chrome/browser/extensions/extension_page_actions_module.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/profile.h"
@@ -68,11 +68,11 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) {
// Find the TabContents that contains this tab id.
TabContents* contents = NULL;
- ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
- NULL, NULL, &contents, NULL);
- if (!contents) {
- error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError,
- IntToString(tab_id));
+ bool result = ExtensionTabUtil::GetTabById(
+ tab_id, profile(), include_incognito(), NULL, NULL, &contents, NULL);
+ if (!result || !contents) {
+ error_ = ExtensionErrorUtils::FormatErrorMessage(
+ kNoTabError, base::IntToString(tab_id));
return false;
}
@@ -101,11 +101,11 @@ bool PageActionFunction::InitCommon(int tab_id) {
// Find the TabContents that contains this tab id.
contents_ = NULL;
- ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
- NULL, NULL, &contents_, NULL);
- if (!contents_) {
- error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError,
- IntToString(tab_id));
+ bool result = ExtensionTabUtil::GetTabById(
+ tab_id, profile(), include_incognito(), NULL, NULL, &contents_, NULL);
+ if (!result || !contents_) {
+ error_ = ExtensionErrorUtils::FormatErrorMessage(
+ kNoTabError, base::IntToString(tab_id));
return false;
}
@@ -144,7 +144,7 @@ bool PageActionSetIconFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
int tab_id;
- EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id));
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
if (!InitCommon(tab_id))
return false;
@@ -152,14 +152,14 @@ bool PageActionSetIconFunction::RunImpl() {
// icon index.
BinaryValue* binary;
int icon_index;
- if (args->GetBinary(L"imageData", &binary)) {
+ if (args->GetBinary("imageData", &binary)) {
IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize());
void* iter = NULL;
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
EXTENSION_FUNCTION_VALIDATE(
IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get()));
page_action_->SetIcon(tab_id, *bitmap);
- } else if (args->GetInteger(L"iconIndex", &icon_index)) {
+ } else if (args->GetInteger("iconIndex", &icon_index)) {
if (icon_index < 0 || static_cast<size_t>(icon_index) >=
page_action_->icon_paths()->size()) {
error_ = kIconIndexOutOfBounds;
@@ -180,12 +180,12 @@ bool PageActionSetTitleFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
int tab_id;
- EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id));
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
if (!InitCommon(tab_id))
return false;
std::string title;
- EXTENSION_FUNCTION_VALIDATE(args->GetString(L"title", &title));
+ EXTENSION_FUNCTION_VALIDATE(args->GetString("title", &title));
page_action_->SetTitle(tab_id, title);
contents_->PageActionStateChanged();
@@ -197,14 +197,14 @@ bool PageActionSetPopupFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
int tab_id;
- EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id));
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
if (!InitCommon(tab_id))
return false;
// TODO(skerner): Consider allowing null and undefined to mean the popup
// should be removed.
std::string popup_string;
- EXTENSION_FUNCTION_VALIDATE(args->GetString(L"popup", &popup_string));
+ EXTENSION_FUNCTION_VALIDATE(args->GetString("popup", &popup_string));
GURL popup_url;
if (!popup_string.empty())
@@ -222,12 +222,12 @@ bool PageActionSetBadgeBackgroundColorFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
int tab_id;
- EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id));
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
if (!InitCommon(tab_id))
return false;
ListValue* color_value;
- EXTENSION_FUNCTION_VALIDATE(args->GetList(L"color", &color_value));
+ EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value));
EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4);
int color_array[4] = {0};
@@ -248,12 +248,12 @@ bool PageActionSetBadgeTextColorFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
int tab_id;
- EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id));
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
if (!InitCommon(tab_id))
return false;
ListValue* color_value;
- EXTENSION_FUNCTION_VALIDATE(args->GetList(L"color", &color_value));
+ EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value));
EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4);
int color_array[4] = {0};
@@ -274,12 +274,12 @@ bool PageActionSetBadgeTextFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
int tab_id;
- EXTENSION_FUNCTION_VALIDATE(args->GetInteger(L"tabId", &tab_id));
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
if (!InitCommon(tab_id))
return false;
std::string text;
- EXTENSION_FUNCTION_VALIDATE(args->GetString(L"text", &text));
+ EXTENSION_FUNCTION_VALIDATE(args->GetString("text", &text));
page_action_->SetBadgeText(tab_id, text);
contents_->PageActionStateChanged();
diff --git a/chrome/browser/extensions/extension_page_actions_module.h b/chrome/browser/extensions/extension_page_actions_module.h
index 3be9ce1..dfbda0a 100644
--- a/chrome/browser/extensions/extension_page_actions_module.h
+++ b/chrome/browser/extensions/extension_page_actions_module.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PAGE_ACTIONS_MODULE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PAGE_ACTIONS_MODULE_H_
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
diff --git a/chrome/browser/extensions/extension_page_actions_module_constants.cc b/chrome/browser/extensions/extension_page_actions_module_constants.cc
index 8690c94..791c002 100644
--- a/chrome/browser/extensions/extension_page_actions_module_constants.cc
+++ b/chrome/browser/extensions/extension_page_actions_module_constants.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.
@@ -6,10 +6,10 @@
namespace extension_page_actions_module_constants {
-const wchar_t kTabIdKey[] = L"tabId";
-const wchar_t kUrlKey[] = L"url";
-const wchar_t kTitleKey[] = L"title";
-const wchar_t kIconIdKey[] = L"iconId";
-const wchar_t kButtonKey[] = L"button";
+const char kTabIdKey[] = "tabId";
+const char kUrlKey[] = "url";
+const char kTitleKey[] = "title";
+const char kIconIdKey[] = "iconId";
+const char kButtonKey[] = "button";
} // namespace extension_page_actions_module_constants
diff --git a/chrome/browser/extensions/extension_page_actions_module_constants.h b/chrome/browser/extensions/extension_page_actions_module_constants.h
index 5bb435e..ed7fb35 100644
--- a/chrome/browser/extensions/extension_page_actions_module_constants.h
+++ b/chrome/browser/extensions/extension_page_actions_module_constants.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,15 +6,16 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PAGE_ACTIONS_MODULE_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PAGE_ACTIONS_MODULE_CONSTANTS_H_
+#pragma once
namespace extension_page_actions_module_constants {
// Keys.
-extern const wchar_t kTabIdKey[];
-extern const wchar_t kUrlKey[];
-extern const wchar_t kTitleKey[];
-extern const wchar_t kIconIdKey[];
-extern const wchar_t kButtonKey[];
+extern const char kTabIdKey[];
+extern const char kUrlKey[];
+extern const char kTitleKey[];
+extern const char kIconIdKey[];
+extern const char kButtonKey[];
}; // namespace extension_page_actions_module_constants
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
index 1d3c3c7..8b12d5b 100644
--- a/chrome/browser/extensions/extension_popup_api.cc
+++ b/chrome/browser/extensions/extension_popup_api.cc
@@ -6,6 +6,8 @@
#include "base/json/json_writer.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/values.h"
#include "chrome/browser/extensions/extension_dom_ui.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_message_service.h"
@@ -45,17 +47,16 @@ const char kBadAnchorArgument[] = "Invalid anchor argument.";
const char kInvalidURLError[] = "Invalid URL.";
const char kNotAnExtension[] = "Not an extension view.";
const char kPopupsDisallowed[] =
- "Popups are only supported from toolstrip or tab-contents views.";
+ "Popups are only supported from tab-contents views.";
// Keys.
-const wchar_t kUrlKey[] = L"url";
-const wchar_t kWidthKey[] = L"width";
-const wchar_t kHeightKey[] = L"height";
-const wchar_t kTopKey[] = L"top";
-const wchar_t kLeftKey[] = L"left";
-const wchar_t kGiveFocusKey[] = L"giveFocus";
-const wchar_t kDomAnchorKey[] = L"domAnchor";
-const wchar_t kBorderStyleKey[] = L"borderStyle";
+const char kWidthKey[] = "width";
+const char kHeightKey[] = "height";
+const char kTopKey[] = "top";
+const char kLeftKey[] = "left";
+const char kGiveFocusKey[] = "giveFocus";
+const char kDomAnchorKey[] = "domAnchor";
+const char kBorderStyleKey[] = "borderStyle";
// chrome enumeration values
const char kRectangleChrome[] = "rectangle";
@@ -165,6 +166,15 @@ class ExtensionPopupHost : public ExtensionPopup::Observer,
GetRoutingFromDispatcher(dispatcher_);
if (router)
router->RegisterRenderViewHost(host->render_view_host());
+
+ // Extension hosts created for popup contents exist in the same tab
+ // contents as the ExtensionFunctionDispatcher that requested the popup.
+ // For example, '_blank' link navigation should be routed through the tab
+ // contents that requested the popup.
+ if (dispatcher_ && dispatcher_->delegate()) {
+ host->set_associated_tab_contents(
+ dispatcher_->delegate()->associated_tab_contents());
+ }
}
virtual void ExtensionPopupResized(ExtensionPopup* popup) {
@@ -356,12 +366,11 @@ void PopupShowFunction::Run() {
}
bool PopupShowFunction::RunImpl() {
- // Popups may only be displayed from TAB_CONTENTS and EXTENSION_TOOLSTRIP
- // views.
+ // Popups may only be displayed from TAB_CONTENTS and EXTENSION_INFOBAR.
ViewType::Type view_type =
dispatcher()->render_view_host()->delegate()->GetRenderViewType();
- if (ViewType::EXTENSION_TOOLSTRIP != view_type &&
- ViewType::TAB_CONTENTS != view_type) {
+ if (ViewType::TAB_CONTENTS != view_type &&
+ ViewType::EXTENSION_INFOBAR != view_type) {
error_ = kPopupsDisallowed;
return false;
}
@@ -444,11 +453,7 @@ bool PopupShowFunction::RunImpl() {
window = GetCurrentBrowser()->window()->GetNativeHandle();
#if defined(TOOLKIT_VIEWS)
- // Pop-up from extension views (ExtensionShelf, etc.), and drop-down when
- // in a TabContents view.
- BubbleBorder::ArrowLocation arrow_location =
- view_type == ViewType::TAB_CONTENTS ?
- BubbleBorder::TOP_LEFT : BubbleBorder::BOTTOM_LEFT;
+ BubbleBorder::ArrowLocation arrow_location = BubbleBorder::TOP_LEFT;
// ExtensionPopupHost manages it's own lifetime.
ExtensionPopupHost* popup_host = new ExtensionPopupHost(dispatcher());
@@ -468,6 +473,7 @@ bool PopupShowFunction::RunImpl() {
popup_->set_close_on_lost_focus(false);
popup_host->set_popup(popup_);
#endif // defined(TOOLKIT_VIEWS)
+
return true;
}
@@ -498,13 +504,10 @@ void PopupShowFunction::Observe(NotificationType type,
// static
void PopupEventRouter::OnPopupClosed(Profile* profile,
int routing_id) {
- std::string full_event_name = StringPrintf(
+ std::string full_event_name = base::StringPrintf(
extension_popup_module_events::kOnPopupClosed,
routing_id);
profile->GetExtensionMessageService()->DispatchEventToRenderers(
- full_event_name,
- base::JSONWriter::kEmptyArray,
- profile->IsOffTheRecord(),
- GURL());
+ full_event_name, base::JSONWriter::kEmptyArray, profile, GURL());
}
diff --git a/chrome/browser/extensions/extension_popup_api.h b/chrome/browser/extensions/extension_popup_api.h
index 7550407..0b62fe4 100644
--- a/chrome/browser/extensions/extension_popup_api.h
+++ b/chrome/browser/extensions/extension_popup_api.h
@@ -1,17 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_POPUP_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_POPUP_API_H_
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-namespace gfx {
-class Point;
-} // namespace gfx
-
class Profile;
class ExtensionPopup;
diff --git a/chrome/browser/extensions/extension_popup_apitest.cc b/chrome/browser/extensions/extension_popup_apitest.cc
index ba6a082..83f5717 100644
--- a/chrome/browser/extensions/extension_popup_apitest.cc
+++ b/chrome/browser/extensions/extension_popup_apitest.cc
@@ -6,18 +6,17 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
-// Flaky on windows. http://crbug.com/46601
-#if defined(OS_WIN)
-#define MAYBE_Popup FLAKY_Popup
-#else
-#define MAYBE_Popup Popup
-#endif
-
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Popup) {
+// Flaky, http://crbug.com/46601.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_Popup) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
+
+ ASSERT_TRUE(RunExtensionTest("popup/popup_main")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupFromInfobar) {
CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableExtensionToolstrips);
+ switches::kEnableExperimentalExtensionApis);
- ASSERT_TRUE(RunExtensionTest("popup")) << message_;
+ ASSERT_TRUE(RunExtensionTest("popup/popup_from_infobar")) << message_;
}
diff --git a/chrome/browser/extensions/extension_pref_store.cc b/chrome/browser/extensions/extension_pref_store.cc
index 437ca77..773e94e 100644
--- a/chrome/browser/extensions/extension_pref_store.cc
+++ b/chrome/browser/extensions/extension_pref_store.cc
@@ -5,107 +5,195 @@
#include "chrome/browser/extensions/extension_pref_store.h"
#include "base/logging.h"
-#include "base/stl_util-inl.h"
#include "base/values.h"
-#include "chrome/browser/pref_service.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(PrefService* pref_service)
- : pref_service_(pref_service),
- prefs_(new DictionaryValue()) {
+ExtensionPrefStore::ExtensionPrefStore(Profile* profile,
+ PrefNotifier::PrefStoreType type)
+ : prefs_(new DictionaryValue()),
+ profile_(profile),
+ type_(type) {
+ RegisterObservers();
}
ExtensionPrefStore::~ExtensionPrefStore() {
STLDeleteElements(&extension_stack_);
+ notification_registrar_.RemoveAll();
}
-// This could be sped up by keeping track of which extension currently controls
-// a given preference, among other optimizations. But we estimate that 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 wchar_t* path) {
- // Query the PrefService to find the current value for this pref.
- // pref_service_ might be null in unit tests.
- scoped_ptr<Value> old_value;
- if (pref_service_) {
- old_value.reset(
- pref_service_->FindPreference(path)->GetValue()->DeepCopy());
+void ExtensionPrefStore::InstallExtensionPref(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::UninstallExtension(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::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 delete it first.
+ // 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_)
- pref_service_->FireObserversIfChanged(path, old_value.get());
+
+ 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);
}
}
-void ExtensionPrefStore::InstallExtensionPref(std::string extension_id,
- const wchar_t* pref_path,
- Value* pref_value) {
- ExtensionStack::iterator i;
- for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) {
- if ((*i)->extension_id == extension_id)
- break;
- }
+PrefService* ExtensionPrefStore::GetPrefService() {
+ if (profile_)
+ return profile_->GetPrefs();
+ return g_browser_process->local_state();
+}
- // If this extension is already in the stack, update or add the value of this
- // preference, but don't change the extension's position in the stack.
- // Otherwise, push the new extension onto the stack.
- PrefValueMap* pref_values;
- if (i != extension_stack_.end()) {
- pref_values = (*i)->pref_values;
- (*pref_values)[pref_path] = pref_value;
- } else {
- pref_values = new PrefValueMap();
- (*pref_values)[pref_path] = pref_value;
+void ExtensionPrefStore::RegisterObservers() {
+ notification_registrar_.Add(this,
+ NotificationType::EXTENSION_PREF_CHANGED,
+ NotificationService::AllSources());
- ExtensionPrefs* extension_prefs = new ExtensionPrefs();
- extension_prefs->extension_id = extension_id;
- extension_prefs->pref_values = pref_values;
- extension_stack_.push_front(extension_prefs);
- }
-
- // Look for an old value with the same type as the one we're modifying.
- UpdateOnePref(pref_path);
+ notification_registrar_.Add(this,
+ NotificationType::EXTENSION_UNLOADED,
+ NotificationService::AllSources());
}
-void ExtensionPrefStore::UninstallExtension(std::string extension_id) {
- // Remove this extension from the stack.
- scoped_ptr<PrefValueMap> pref_values;
- for (ExtensionStack::iterator i = extension_stack_.begin();
- i != extension_stack_.end(); ++i) {
- if ((*i)->extension_id == extension_id) {
- pref_values.reset((*i)->pref_values);
- delete *i;
- extension_stack_.erase(i);
+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();
+ Extension* extension = Details<Extension>(details).ptr();
+ // The ExtensionPrefStore for the local state watches all profiles.
+ if (profile_ == NULL || profile_ == extension_profile)
+ UninstallExtension(extension);
break;
}
+ default: {
+ NOTREACHED();
+ }
}
- if (!pref_values.get())
- return;
-
- UpdatePrefs(pref_values.get());
}
-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);
- }
+ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(Extension* extension,
+ PrefValueMap* values) : extension(extension), pref_values(values) {}
+
+ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() {
+ STLDeleteValues(pref_values);
+ delete pref_values;
}
diff --git a/chrome/browser/extensions/extension_pref_store.h b/chrome/browser/extensions/extension_pref_store.h
index fc10b5b..926f29e 100644
--- a/chrome/browser/extensions/extension_pref_store.h
+++ b/chrome/browser/extensions/extension_pref_store.h
@@ -4,86 +4,119 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PREF_STORE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PREF_STORE_H_
+#pragma once
#include <list>
#include <map>
#include <string>
+#include <utility>
#include <vector>
#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 extension IDs is stored in order of
+// 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 {
+class ExtensionPrefStore : public PrefStore,
+ public NotificationObserver {
public:
- explicit ExtensionPrefStore(PrefService* pref_service);
+ ExtensionPrefStore(Profile* profile, PrefNotifier::PrefStoreType type);
virtual ~ExtensionPrefStore();
- // The PrefService creates the ExtensionPrefStore, so we need to be able to
- // defer setting the PrefService here until after construction.
- void SetPrefService(PrefService* pref_service) {
- pref_service_ = pref_service;
- }
-
// 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.
- virtual void InstallExtensionPref(std::string extension_id,
- const wchar_t* pref_path,
+ // The ExtensionPrefStore will take ownership of the |pref_value|.
+ virtual void InstallExtensionPref(Extension* extension,
+ const char* pref_path,
Value* pref_value);
// 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(std::string extension_id);
+ virtual void UninstallExtension(Extension* extension);
// PrefStore methods:
virtual DictionaryValue* prefs() { return prefs_.get(); }
virtual PrefReadError ReadPrefs() { return PREF_READ_ERROR_NONE; }
+ // 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<Extension*, std::pair<const char*, Value*> >
+ ExtensionPrefDetails;
+
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);
- private:
- // The pref service referring to this pref store. Weak reference.
- PrefService* pref_service_;
+ // 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();
+ private:
// Maps preference paths to their values.
- typedef std::map<const wchar_t*, Value*> PrefValueMap;
+ typedef std::map<const char*, Value*> PrefValueMap;
// Applies the highest-priority extension's setting for the given preference
- // path, or clears the setting in this PrefStore if no extensions wish to
- // control it.
- void UpdateOnePref(const wchar_t* path);
+ // 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 |pref_values| list.
+ // 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_;
- // Associates an extension ID with the prefs it sets.
+ // Associates an extension with the prefs it sets. Owns the pref values.
struct ExtensionPrefs {
- std::string extension_id;
+ ExtensionPrefs(Extension* extension, PrefValueMap* values);
+ ~ExtensionPrefs();
+
+ 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. This stack owns
- // the values in the extensions' PrefValueMaps.
+ // added to the head, but may be removed from the middle.
typedef std::list<ExtensionPrefs*> ExtensionStack;
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_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionPrefStore);
};
diff --git a/chrome/browser/extensions/extension_pref_store_unittest.cc b/chrome/browser/extensions/extension_pref_store_unittest.cc
index 8bbb4b8..aebe5e6 100644
--- a/chrome/browser/extensions/extension_pref_store_unittest.cc
+++ b/chrome/browser/extensions/extension_pref_store_unittest.cc
@@ -2,58 +2,122 @@
// 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 <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/pref_service.h"
-#include "chrome/browser/pref_value_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 {
class TestExtensionPrefStore : public ExtensionPrefStore {
public:
- TestExtensionPrefStore() : ExtensionPrefStore(NULL) {}
+ 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 empty_dict;
+ std::string error;
+
+ ext1_scoped_.reset(new Extension(temp_dir_.path().AppendASCII("ext1")));
+ ext2_scoped_.reset(new Extension(temp_dir_.path().AppendASCII("ext2")));
+ ext3_scoped_.reset(new Extension(temp_dir_.path().AppendASCII("ext3")));
+
+ ext1 = ext1_scoped_.get();
+ ext2 = ext2_scoped_.get();
+ ext3 = ext3_scoped_.get();
+
+ EXPECT_FALSE(ext1->InitFromValue(empty_dict, false, &error));
+ EXPECT_FALSE(ext2->InitFromValue(empty_dict, false, &error));
+ EXPECT_FALSE(ext3->InitFromValue(empty_dict, false, &error));
+ }
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_ptr<Extension> ext1_scoped_;
+ scoped_ptr<Extension> ext2_scoped_;
+ scoped_ptr<Extension> ext3_scoped_;
+
+ // Weak reference.
+ PrefService* pref_service_;
};
-class MockPrefService : public PrefService {
+// Mock PrefNotifier that allows the notifications to be tracked.
+class MockPrefNotifier : public PrefNotifier {
public:
- explicit MockPrefService(PrefValueStore* value_store)
- : PrefService(value_store) {}
+ MockPrefNotifier(PrefService* service, PrefValueStore* value_store)
+ : PrefNotifier(service, value_store) {}
- // Tracks whether the observers would have been notified.
- virtual void FireObserversIfChanged(const wchar_t* pref_name,
- const Value* old_value) {
- fired_observers_ = PrefIsChanged(pref_name, old_value);
+ 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) {
}
- bool fired_observers_;
+ void SetPrefNotifier(MockPrefNotifier* notifier) {
+ pref_notifier_.reset(notifier);
+ }
};
-// Use static constants to avoid confusing std::map with hard-coded strings.
-static const wchar_t* kPref1 = L"path1.subpath";
-static const wchar_t* kPref2 = L"path2";
-static const wchar_t* kPref3 = L"path3";
-static const wchar_t* kPref4 = L"path4";
+// 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;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
+ 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("id1", ids[0]);
+ EXPECT_EQ(eps.ext1->id(), ids[0]);
DictionaryValue* prefs = eps.prefs();
ASSERT_EQ(1u, prefs->size());
@@ -65,16 +129,17 @@ TEST(ExtensionPrefStoreTest, InstallOneExtension) {
// Make sure the last-installed extension wins.
TEST(ExtensionPrefStoreTest, InstallMultipleExtensions) {
TestExtensionPrefStore eps;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref("id2", kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref("id3", kPref1, Value::CreateStringValue("val3"));
+ 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("id3", ids[0]);
- EXPECT_EQ("id2", ids[1]);
- EXPECT_EQ("id1", ids[2]);
+ 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());
@@ -86,23 +151,24 @@ TEST(ExtensionPrefStoreTest, InstallMultipleExtensions) {
// Make sure the last-installed extension wins for each preference.
TEST(ExtensionPrefStoreTest, InstallOverwrittenExtensions) {
TestExtensionPrefStore eps;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref("id2", kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref("id3", kPref1, Value::CreateStringValue("val3"));
+ 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("id1", kPref2, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref("id2", kPref2, Value::CreateStringValue("val5"));
+ eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4"));
+ eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val5"));
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val6"));
- eps.InstallExtensionPref("id1", kPref2, Value::CreateStringValue("val7"));
- eps.InstallExtensionPref("id1", kPref3, Value::CreateStringValue("val8"));
+ 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("id3", ids[0]);
- EXPECT_EQ("id2", ids[1]);
- EXPECT_EQ("id1", ids[2]);
+ 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());
@@ -119,22 +185,23 @@ TEST(ExtensionPrefStoreTest, InstallOverwrittenExtensions) {
// the same or different preferences later.
TEST(ExtensionPrefStoreTest, InstallInterleavedExtensions) {
TestExtensionPrefStore eps;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref("id2", kPref2, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref("id3", kPref3, Value::CreateStringValue("val3"));
+ 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("id3", kPref3, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref("id2", kPref3, Value::CreateStringValue("val5"));
- eps.InstallExtensionPref("id1", kPref3, Value::CreateStringValue("val6"));
+ 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("id3", kPref1, Value::CreateStringValue("val7"));
+ eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val7"));
TestExtensionPrefStore::ExtensionIDs ids;
eps.GetExtensionIDList(&ids);
EXPECT_EQ(3u, ids.size());
- EXPECT_EQ("id3", ids[0]);
- EXPECT_EQ("id2", ids[1]);
- EXPECT_EQ("id1", ids[2]);
+ 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());
@@ -149,11 +216,12 @@ TEST(ExtensionPrefStoreTest, InstallInterleavedExtensions) {
TEST(ExtensionPrefStoreTest, UninstallOnlyExtension) {
TestExtensionPrefStore eps;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref("id1", kPref2, Value::CreateStringValue("val2"));
+ 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 InstallOneExtension already has.
- eps.UninstallExtension("id1");
+ // No need to check the state here; the Install* tests cover that.
+ eps.UninstallExtension(eps.ext1);
TestExtensionPrefStore::ExtensionIDs ids;
eps.GetExtensionIDList(&ids);
@@ -171,18 +239,19 @@ TEST(ExtensionPrefStoreTest, UninstallOnlyExtension) {
// Tests uninstalling an extension that wasn't winning for any preferences.
TEST(ExtensionPrefStoreTest, UninstallIrrelevantExtension) {
TestExtensionPrefStore eps;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref("id2", kPref1, Value::CreateStringValue("val2"));
+ ASSERT_TRUE(eps.ext1 != NULL);
+ eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
+ eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref("id1", kPref2, Value::CreateStringValue("val3"));
- eps.InstallExtensionPref("id2", kPref2, Value::CreateStringValue("val4"));
+ eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val3"));
+ eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val4"));
- eps.UninstallExtension("id1");
+ eps.UninstallExtension(eps.ext1);
TestExtensionPrefStore::ExtensionIDs ids;
eps.GetExtensionIDList(&ids);
EXPECT_EQ(1u, ids.size());
- EXPECT_EQ("id2", ids[0]);
+ EXPECT_EQ(eps.ext2->id(), ids[0]);
DictionaryValue* prefs = eps.prefs();
ASSERT_EQ(2u, prefs->size());
@@ -196,20 +265,21 @@ TEST(ExtensionPrefStoreTest, UninstallIrrelevantExtension) {
// Tests uninstalling an extension that was winning for all preferences.
TEST(ExtensionPrefStoreTest, UninstallExtensionFromTop) {
TestExtensionPrefStore eps;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref("id2", kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref("id3", kPref1, Value::CreateStringValue("val3"));
+ 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("id1", kPref2, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref("id3", kPref2, Value::CreateStringValue("val5"));
+ eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4"));
+ eps.InstallExtensionPref(eps.ext3, kPref2, Value::CreateStringValue("val5"));
- eps.UninstallExtension("id3");
+ eps.UninstallExtension(eps.ext3);
TestExtensionPrefStore::ExtensionIDs ids;
eps.GetExtensionIDList(&ids);
EXPECT_EQ(2u, ids.size());
- EXPECT_EQ("id2", ids[0]);
- EXPECT_EQ("id1", ids[1]);
+ EXPECT_EQ(eps.ext2->id(), ids[0]);
+ EXPECT_EQ(eps.ext1->id(), ids[1]);
DictionaryValue* prefs = eps.prefs();
ASSERT_EQ(2u, prefs->size());
@@ -223,24 +293,25 @@ TEST(ExtensionPrefStoreTest, UninstallExtensionFromTop) {
// Tests uninstalling an extension that was winning for only some preferences.
TEST(ExtensionPrefStoreTest, UninstallExtensionFromMiddle) {
TestExtensionPrefStore eps;
- eps.InstallExtensionPref("id1", kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref("id2", kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref("id3", kPref1, Value::CreateStringValue("val3"));
+ 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("id1", kPref2, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref("id2", kPref2, Value::CreateStringValue("val5"));
+ eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4"));
+ eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val5"));
- eps.InstallExtensionPref("id1", kPref3, Value::CreateStringValue("val6"));
+ eps.InstallExtensionPref(eps.ext1, kPref3, Value::CreateStringValue("val6"));
- eps.InstallExtensionPref("id2", kPref4, Value::CreateStringValue("val7"));
+ eps.InstallExtensionPref(eps.ext2, kPref4, Value::CreateStringValue("val7"));
- eps.UninstallExtension("id2");
+ eps.UninstallExtension(eps.ext2);
TestExtensionPrefStore::ExtensionIDs ids;
eps.GetExtensionIDList(&ids);
EXPECT_EQ(2u, ids.size());
- EXPECT_EQ("id3", ids[0]);
- EXPECT_EQ("id1", ids[1]);
+ EXPECT_EQ(eps.ext3->id(), ids[0]);
+ EXPECT_EQ(eps.ext1->id(), ids[1]);
DictionaryValue* prefs = eps.prefs();
ASSERT_EQ(3u, prefs->size());
@@ -255,26 +326,37 @@ TEST(ExtensionPrefStoreTest, UninstallExtensionFromMiddle) {
}
TEST(ExtensionPrefStoreTest, NotifyWhenNeeded) {
- TestExtensionPrefStore eps;
+ 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.
- PrefValueStore* value_store = new PrefValueStore(NULL, &eps, NULL, NULL,
- NULL);
- MockPrefService* pref_service = new MockPrefService(value_store);
- eps.SetPrefService(pref_service);
+ // only an ExtensionPrefStore. Likewise, the PrefService takes ownership of
+ // the PrefValueStore and PrefNotifier.
+ PrefValueStore* value_store = new TestingPrefService::TestingPrefValueStore(
+ 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());
- eps.InstallExtensionPref("abc", kPref1,
+ EXPECT_CALL(*pref_notifier, FireObservers(kPref1));
+ eps->InstallExtensionPref(eps->ext1, kPref1,
Value::CreateStringValue("https://www.chromium.org"));
- EXPECT_TRUE(pref_service->fired_observers_);
- eps.InstallExtensionPref("abc", kPref1,
+ Mock::VerifyAndClearExpectations(pref_notifier);
+
+ EXPECT_CALL(*pref_notifier, FireObservers(kPref1)).Times(0);
+ eps->InstallExtensionPref(eps->ext1, kPref1,
Value::CreateStringValue("https://www.chromium.org"));
- EXPECT_FALSE(pref_service->fired_observers_);
- eps.InstallExtensionPref("abc", kPref1,
- Value::CreateStringValue("chrome://newtab"));
- EXPECT_TRUE(pref_service->fired_observers_);
+ Mock::VerifyAndClearExpectations(pref_notifier);
- eps.UninstallExtension("abc");
- EXPECT_TRUE(pref_service->fired_observers_);
+ 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 ed44ec4..3fbea88 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -2,8 +2,11 @@
// 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 "chrome/browser/extensions/extension_prefs.h"
+
+#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
@@ -11,64 +14,72 @@ using base::Time;
namespace {
-// Preferences keys
-
-// A preference that keeps track of per-extension settings. This is a dictionary
-// object read from the Preferences file, keyed off of extension id's.
-const wchar_t kExtensionsPref[] = L"extensions.settings";
+// Additional preferences keys
// Where an extension was installed from. (see Extension::Location)
-const wchar_t kPrefLocation[] = L"location";
+const char kPrefLocation[] = "location";
// Enabled, disabled, killed, etc. (see Extension::State)
-const wchar_t kPrefState[] = L"state";
+const char kPrefState[] = "state";
// The path to the current version's manifest file.
-const wchar_t kPrefPath[] = L"path";
+const char kPrefPath[] = "path";
// The dictionary containing the extension's manifest.
-const wchar_t kPrefManifest[] = L"manifest";
+const char kPrefManifest[] = "manifest";
// The version number.
-const wchar_t kPrefVersion[] = L"manifest.version";
+const char kPrefVersion[] = "manifest.version";
// Indicates if an extension is blacklisted:
-const wchar_t kPrefBlacklist[] = L"blacklist";
+const char kPrefBlacklist[] = "blacklist";
// Indicates whether to show an install warning when the user enables.
-const wchar_t kExtensionDidEscalatePermissions[] = L"install_warning_on_enable";
+const char kExtensionDidEscalatePermissions[] = "install_warning_on_enable";
-// A preference that tracks extension shelf configuration. This is a list
-// object read from the Preferences file, containing a list of toolstrip URLs.
-const wchar_t kExtensionShelf[] = L"extensions.shelf";
+// A preference that tracks admin policy regarding which extensions the user
+// can and can not install. This preference is a list object, containing
+// strings that list extension ids. Denylist can contain "*" meaning all
+// extensions.
+const char kExtensionInstallAllowList[] = "extensions.install.allowlist";
+const char kExtensionInstallDenyList[] = "extensions.install.denylist";
// A preference that tracks browser action toolbar configuration. This is a list
// object stored in the Preferences file. The extensions are stored by ID.
-const wchar_t kExtensionToolbar[] = L"extensions.toolbar";
+const char kExtensionToolbar[] = "extensions.toolbar";
// The key for a serialized Time value indicating the start of the day (from the
// server's perspective) an extension last included a "ping" parameter during
// its update check.
-const wchar_t kLastPingDay[] = L"lastpingday";
+const char kLastPingDay[] = "lastpingday";
// Path for settings specific to blacklist update.
-const wchar_t kExtensionsBlacklistUpdate[] = L"extensions.blacklistupdate";
+const char kExtensionsBlacklistUpdate[] = "extensions.blacklistupdate";
// Path and sub-keys for the idle install info dictionary preference.
-const wchar_t kIdleInstallInfo[] = L"idle_install_info";
-const wchar_t kIdleInstallInfoCrxPath[] = L"crx_path";
-const wchar_t kIdleInstallInfoVersion[] = L"version";
-const wchar_t kIdleInstallInfoFetchTime[] = L"fetch_time";
+const char kIdleInstallInfo[] = "idle_install_info";
+const char kIdleInstallInfoCrxPath[] = "crx_path";
+const char kIdleInstallInfoVersion[] = "version";
+const char kIdleInstallInfoFetchTime[] = "fetch_time";
// A preference that, if true, will allow this extension to run in incognito
// mode.
-const wchar_t kPrefIncognitoEnabled[] = L"incognito";
+const char kPrefIncognitoEnabled[] = "incognito";
// A preference to control whether an extension is allowed to inject script in
// pages with file URLs.
-const wchar_t kPrefAllowFileAccess[] = L"allowFileAccess";
-}
+const char kPrefAllowFileAccess[] = "allowFileAccess";
+
+// A preference set by the web store to indicate login information for
+// purchased apps.
+const char kWebStoreLogin[] = "extensions.webstore_login";
+
+// A preference set by the the NTP to persist the desired launch container type
+// used for apps.
+const char kPrefLaunchType[] = "launchType";
+
+} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -79,17 +90,18 @@ namespace {
// id. We can remove this in a couple of months. (See http://crbug.com/40017
// and http://crbug.com/39745 for more details).
static void CleanupBadExtensionKeys(PrefService* prefs) {
- DictionaryValue* dictionary = prefs->GetMutableDictionary(kExtensionsPref);
- std::set<std::wstring> bad_keys;
+ DictionaryValue* dictionary =
+ prefs->GetMutableDictionary(ExtensionPrefs::kExtensionsPref);
+ std::set<std::string> bad_keys;
for (DictionaryValue::key_iterator i = dictionary->begin_keys();
i != dictionary->end_keys(); ++i) {
- const std::wstring key_name = *i;
- if (!Extension::IdIsValid(WideToASCII(key_name))) {
+ const std::string& key_name(*i);
+ if (!Extension::IdIsValid(key_name)) {
bad_keys.insert(key_name);
}
}
bool dirty = false;
- for (std::set<std::wstring>::iterator i = bad_keys.begin();
+ for (std::set<std::string>::iterator i = bad_keys.begin();
i != bad_keys.end(); ++i) {
dirty = true;
dictionary->Remove(*i, NULL);
@@ -110,6 +122,9 @@ ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir)
MakePathsRelative();
}
+// static
+const char ExtensionPrefs::kExtensionsPref[] = "extensions.settings";
+
static FilePath::StringType MakePathRelative(const FilePath& parent,
const FilePath& child,
bool *dirty) {
@@ -153,7 +168,7 @@ void ExtensionPrefs::MakePathsRelative() {
}
}
if (dirty)
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
}
void ExtensionPrefs::MakePathsAbsolute(DictionaryValue* dict) {
@@ -197,7 +212,7 @@ DictionaryValue* ExtensionPrefs::CopyCurrentExtensions() {
}
bool ExtensionPrefs::ReadBooleanFromPref(
- DictionaryValue* ext, const std::wstring& pref_key) {
+ DictionaryValue* ext, const std::string& pref_key) {
if (!ext->HasKey(pref_key)) return false;
bool bool_value = false;
if (!ext->GetBoolean(pref_key, &bool_value)) {
@@ -209,19 +224,49 @@ bool ExtensionPrefs::ReadBooleanFromPref(
}
bool ExtensionPrefs::ReadExtensionPrefBoolean(
- const std::string& extension_id, const std::wstring& pref_key) {
+ const std::string& extension_id, const std::string& pref_key) {
const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
if (!extensions)
return false;
DictionaryValue* ext = NULL;
- if (!extensions->GetDictionary(ASCIIToWide(extension_id), &ext)) {
+ if (!extensions->GetDictionary(extension_id, &ext)) {
// No such extension yet.
return false;
}
return ReadBooleanFromPref(ext, pref_key);
}
+bool ExtensionPrefs::ReadIntegerFromPref(
+ DictionaryValue* ext, const std::string& pref_key, int* out_value) {
+ if (!ext->HasKey(pref_key)) return false;
+ if (!ext->GetInteger(pref_key, out_value)) {
+ NOTREACHED() << "Failed to fetch " << pref_key << " flag.";
+ // In case we could not fetch the flag, we treat it as false.
+ return false;
+ }
+ return out_value != NULL;
+}
+
+bool ExtensionPrefs::ReadExtensionPrefInteger(
+ const std::string& extension_id, const std::string& pref_key,
+ int* out_value) {
+ const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+ if (!extensions)
+ return false;
+ DictionaryValue* ext = NULL;
+ if (!extensions->GetDictionary(extension_id, &ext)) {
+ // No such extension yet.
+ return false;
+ }
+ return ReadIntegerFromPref(ext, pref_key, out_value);
+}
+
+void ExtensionPrefs::SavePrefsAndNotify() {
+ prefs_->ScheduleSavePersistentPrefs();
+ prefs_->pref_notifier()->OnUserPreferenceSet(kExtensionsPref);
+}
+
bool ExtensionPrefs::IsBlacklistBitSet(DictionaryValue* ext) {
return ReadBooleanFromPref(ext, kPrefBlacklist);
}
@@ -230,6 +275,44 @@ bool ExtensionPrefs::IsExtensionBlacklisted(const std::string& extension_id) {
return ReadExtensionPrefBoolean(extension_id, kPrefBlacklist);
}
+bool ExtensionPrefs::IsExtensionAllowedByPolicy(
+ const std::string& extension_id) {
+ std::string string_value;
+
+ const ListValue* blacklist = prefs_->GetList(kExtensionInstallDenyList);
+ if (!blacklist || blacklist->empty())
+ return true;
+
+ // Check the whitelist first.
+ const ListValue* whitelist = prefs_->GetList(kExtensionInstallAllowList);
+ if (whitelist) {
+ for (ListValue::const_iterator it = whitelist->begin();
+ it != whitelist->end(); ++it) {
+ if (!(*it)->GetAsString(&string_value))
+ LOG(WARNING) << "Failed to read whitelist string.";
+ else if (string_value == extension_id)
+ return true;
+ }
+ }
+
+ // Then check the blacklist (the admin blacklist, not the Google blacklist).
+ if (blacklist) {
+ for (ListValue::const_iterator it = blacklist->begin();
+ it != blacklist->end(); ++it) {
+ if (!(*it)->GetAsString(&string_value)) {
+ LOG(WARNING) << "Failed to read blacklist string.";
+ } else {
+ if (string_value == "*")
+ return false; // Only whitelisted extensions are allowed.
+ if (string_value == extension_id)
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
bool ExtensionPrefs::DidExtensionEscalatePermissions(
const std::string& extension_id) {
return ReadExtensionPrefBoolean(extension_id,
@@ -240,11 +323,11 @@ void ExtensionPrefs::SetDidExtensionEscalatePermissions(
Extension* extension, bool did_escalate) {
UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions,
Value::CreateBooleanValue(did_escalate));
- prefs_->SavePersistentPrefs();
+ prefs_->ScheduleSavePersistentPrefs();
}
void ExtensionPrefs::UpdateBlacklist(
- const std::set<std::string>& blacklist_set) {
+ const std::set<std::string>& blacklist_set) {
std::vector<std::string> remove_pref_ids;
std::set<std::string> used_id_set;
const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
@@ -257,7 +340,7 @@ void ExtensionPrefs::UpdateBlacklist(
NOTREACHED() << "Invalid pref for extension " << *extension_id;
continue;
}
- std::string id = WideToASCII(*extension_id);
+ const std::string& id(*extension_id);
if (blacklist_set.find(id) == blacklist_set.end()) {
if (!IsBlacklistBitSet(ext)) {
// This extension is not in blacklist. And it was not blacklisted
@@ -294,8 +377,7 @@ void ExtensionPrefs::UpdateBlacklist(
for (unsigned int i = 0; i < remove_pref_ids.size(); ++i) {
DeleteExtensionPrefs(remove_pref_ids[i]);
}
- // Update persistent registry
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
return;
}
@@ -304,7 +386,7 @@ Time ExtensionPrefs::LastPingDayImpl(const DictionaryValue* dictionary) const {
std::string string_value;
int64 value;
dictionary->GetString(kLastPingDay, &string_value);
- if (StringToInt64(string_value, &value)) {
+ if (base::StringToInt64(string_value, &value)) {
return Time::FromInternalValue(value);
}
}
@@ -317,9 +399,9 @@ void ExtensionPrefs::SetLastPingDayImpl(const Time& time,
NOTREACHED();
return;
}
- std::string value = Int64ToString(time.ToInternalValue());
+ std::string value = base::Int64ToString(time.ToInternalValue());
dictionary->SetString(kLastPingDay, value);
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
}
Time ExtensionPrefs::LastPingDay(const std::string& extension_id) const {
@@ -350,7 +432,7 @@ void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id,
bool enabled) {
UpdateExtensionPref(extension_id, kPrefIncognitoEnabled,
Value::CreateBooleanValue(enabled));
- prefs_->SavePersistentPrefs();
+ SavePrefsAndNotify();
}
bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) {
@@ -361,7 +443,26 @@ void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id,
bool allow) {
UpdateExtensionPref(extension_id, kPrefAllowFileAccess,
Value::CreateBooleanValue(allow));
- prefs_->SavePersistentPrefs();
+ SavePrefsAndNotify();
+}
+
+ExtensionPrefs::LaunchType ExtensionPrefs::GetLaunchType(
+ const std::string& extension_id) {
+ int value;
+ if (ReadExtensionPrefInteger(extension_id, kPrefLaunchType, &value) && (
+ value == LAUNCH_PINNED ||
+ value == LAUNCH_REGULAR ||
+ value == LAUNCH_FULLSCREEN)) {
+ return static_cast<LaunchType>(value);
+ }
+ return LAUNCH_PINNED;
+}
+
+void ExtensionPrefs::SetLaunchType(const std::string& extension_id,
+ LaunchType launch_type) {
+ UpdateExtensionPref(extension_id, kPrefLaunchType,
+ Value::CreateIntegerValue(static_cast<int>(launch_type)));
+ SavePrefsAndNotify();
}
void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) {
@@ -371,10 +472,9 @@ void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) {
for (DictionaryValue::key_iterator i = dict->begin_keys();
i != dict->end_keys(); ++i) {
- std::wstring key_name = *i;
- if (!Extension::IdIsValid(WideToASCII(key_name))) {
- LOG(WARNING) << "Invalid external extension ID encountered: "
- << WideToASCII(key_name);
+ const std::string& key_name(*i);
+ if (!Extension::IdIsValid(key_name)) {
+ LOG(WARNING) << "Invalid external extension ID encountered: " << key_name;
continue;
}
@@ -388,33 +488,9 @@ void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) {
int state;
if (extension->GetInteger(kPrefState, &state) &&
state == static_cast<int>(Extension::KILLBIT)) {
- StringToLowerASCII(&key_name);
- killed_ids->insert(WideToASCII(key_name));
- }
- }
-}
-
-ExtensionPrefs::URLList ExtensionPrefs::GetShelfToolstripOrder() {
- URLList urls;
- const ListValue* toolstrip_urls = prefs_->GetList(kExtensionShelf);
- if (toolstrip_urls) {
- for (size_t i = 0; i < toolstrip_urls->GetSize(); ++i) {
- std::string url;
- if (toolstrip_urls->GetString(i, &url))
- urls.push_back(GURL(url));
+ killed_ids->insert(StringToLowerASCII(key_name));
}
}
- return urls;
-}
-
-void ExtensionPrefs::SetShelfToolstripOrder(const URLList& urls) {
- ListValue* toolstrip_urls = prefs_->GetMutableList(kExtensionShelf);
- toolstrip_urls->Clear();
- for (size_t i = 0; i < urls.size(); ++i) {
- GURL url = urls[i];
- toolstrip_urls->Append(new StringValue(url.spec()));
- }
- prefs_->ScheduleSavePersistentPrefs();
}
std::vector<std::string> ExtensionPrefs::GetToolbarOrder() {
@@ -438,7 +514,7 @@ void ExtensionPrefs::SetToolbarOrder(
iter != extension_ids.end(); ++iter) {
toolbar_order->Append(new StringValue(*iter));
}
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
}
void ExtensionPrefs::OnExtensionInstalled(
@@ -460,7 +536,7 @@ void ExtensionPrefs::OnExtensionInstalled(
UpdateExtensionPref(id, kPrefManifest,
extension->manifest_value()->DeepCopy());
}
- prefs_->SavePersistentPrefs();
+ SavePrefsAndNotify();
}
void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
@@ -473,7 +549,7 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
if (!external_uninstall && Extension::IsExternalLocation(location)) {
UpdateExtensionPref(extension_id, kPrefState,
Value::CreateIntegerValue(Extension::KILLBIT));
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
} else {
DeleteExtensionPrefs(extension_id);
}
@@ -501,7 +577,7 @@ void ExtensionPrefs::SetExtensionState(Extension* extension,
Extension::State state) {
UpdateExtensionPref(extension->id(), kPrefState,
Value::CreateIntegerValue(state));
- prefs_->SavePersistentPrefs();
+ SavePrefsAndNotify();
}
std::string ExtensionPrefs::GetVersionString(const std::string& extension_id) {
@@ -522,7 +598,7 @@ void ExtensionPrefs::UpdateManifest(Extension* extension) {
if (extension->location() != Extension::LOAD) {
UpdateExtensionPref(extension->id(), kPrefManifest,
extension->manifest_value()->DeepCopy());
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
}
}
@@ -531,15 +607,15 @@ FilePath ExtensionPrefs::GetExtensionPath(const std::string& extension_id) {
if (!dict || dict->empty())
return FilePath();
- std::wstring path;
- if (!dict->GetString(ASCIIToWide(extension_id) + L"." + kPrefPath, &path))
+ std::string path;
+ if (!dict->GetString(extension_id + "." + kPrefPath, &path))
return FilePath();
- return install_directory_.Append(FilePath::FromWStringHack(path));
+ return install_directory_.Append(FilePath::FromWStringHack(UTF8ToWide(path)));
}
void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id,
- const std::wstring& key,
+ const std::string& key,
Value* data_value) {
if (!Extension::IdIsValid(extension_id)) {
NOTREACHED() << "Invalid extension_id " << extension_id;
@@ -550,11 +626,10 @@ void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id,
}
void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) {
- std::wstring id = ASCIIToWide(extension_id);
DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
- if (dict->HasKey(id)) {
- dict->Remove(id, NULL);
- prefs_->ScheduleSavePersistentPrefs();
+ if (dict->HasKey(extension_id)) {
+ dict->Remove(extension_id, NULL);
+ SavePrefsAndNotify();
}
}
@@ -563,11 +638,10 @@ DictionaryValue* ExtensionPrefs::GetOrCreateExtensionPref(
DCHECK(Extension::IdIsValid(extension_id));
DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
DictionaryValue* extension = NULL;
- std::wstring id = ASCIIToWide(extension_id);
- if (!dict->GetDictionary(id, &extension)) {
+ if (!dict->GetDictionary(extension_id, &extension)) {
// Extension pref does not exist, create it.
extension = new DictionaryValue();
- dict->Set(id, extension);
+ dict->Set(extension_id, extension);
}
return extension;
}
@@ -578,8 +652,7 @@ DictionaryValue* ExtensionPrefs::GetExtensionPref(
if (!dict)
return NULL;
DictionaryValue* extension = NULL;
- std::wstring id = ASCIIToWide(extension_id);
- dict->GetDictionary(id, &extension);
+ dict->GetDictionary(extension_id, &extension);
return extension;
}
@@ -641,8 +714,7 @@ static ExtensionInfo* GetInstalledExtensionInfoImpl(
// Just a warning for now.
}
- return new ExtensionInfo(manifest, WideToASCII(*extension_id),
- FilePath(path), location);
+ return new ExtensionInfo(manifest, *extension_id, FilePath(path), location);
}
ExtensionPrefs::ExtensionsInfo* ExtensionPrefs::GetInstalledExtensionsInfo() {
@@ -653,7 +725,7 @@ ExtensionPrefs::ExtensionsInfo* ExtensionPrefs::GetInstalledExtensionsInfo() {
for (DictionaryValue::key_iterator extension_id(
extension_data->begin_keys());
extension_id != extension_data->end_keys(); ++extension_id) {
- if (!Extension::IdIsValid(WideToASCII(*extension_id)))
+ if (!Extension::IdIsValid(*extension_id))
continue;
ExtensionInfo* info = GetInstalledExtensionInfoImpl(extension_data.get(),
@@ -672,7 +744,7 @@ ExtensionInfo* ExtensionPrefs::GetInstalledExtensionInfo(
for (DictionaryValue::key_iterator extension_iter(
extension_data->begin_keys());
extension_iter != extension_data->end_keys(); ++extension_iter) {
- if (WideToASCII(*extension_iter) == extension_id) {
+ if (*extension_iter == extension_id) {
return GetInstalledExtensionInfoImpl(extension_data.get(),
extension_iter);
}
@@ -695,9 +767,9 @@ void ExtensionPrefs::SetIdleInstallInfo(const std::string& extension_id,
info->SetString(kIdleInstallInfoCrxPath, crx_path.value());
info->SetString(kIdleInstallInfoVersion, version);
info->SetString(kIdleInstallInfoFetchTime,
- Int64ToString(fetch_time.ToInternalValue()));
+ base::Int64ToString(fetch_time.ToInternalValue()));
extension_prefs->Set(kIdleInstallInfo, info);
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
}
bool ExtensionPrefs::RemoveIdleInstallInfo(const std::string& extension_id) {
@@ -705,7 +777,7 @@ bool ExtensionPrefs::RemoveIdleInstallInfo(const std::string& extension_id) {
if (!extension_prefs)
return false;
bool result = extension_prefs->Remove(kIdleInstallInfo, NULL);
- prefs_->ScheduleSavePersistentPrefs();
+ SavePrefsAndNotify();
return result;
}
@@ -736,7 +808,7 @@ bool ExtensionPrefs::GetIdleInstallInfo(const std::string& extension_id,
return false;
int64 fetch_time_value;
- if (!StringToInt64(fetch_time_string, &fetch_time_value))
+ if (!base::StringToInt64(fetch_time_string, &fetch_time_value))
return false;
if (crx_path)
@@ -760,7 +832,7 @@ std::set<std::string> ExtensionPrefs::GetIdleInstallInfoIds() {
for (DictionaryValue::key_iterator iter = extensions->begin_keys();
iter != extensions->end_keys(); ++iter) {
- std::string id = WideToASCII(*iter);
+ const std::string& id(*iter);
if (!Extension::IdIsValid(id)) {
NOTREACHED();
continue;
@@ -777,12 +849,26 @@ std::set<std::string> ExtensionPrefs::GetIdleInstallInfoIds() {
return result;
}
+bool ExtensionPrefs::GetWebStoreLogin(std::string* result) {
+ if (prefs_->HasPrefPath(kWebStoreLogin)) {
+ *result = prefs_->GetString(kWebStoreLogin);
+ return true;
+ }
+ return false;
+}
+
+void ExtensionPrefs::SetWebStoreLogin(const std::string& login) {
+ prefs_->SetString(kWebStoreLogin, login);
+ SavePrefsAndNotify();
+}
// static
void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(kExtensionsPref);
- prefs->RegisterListPref(kExtensionShelf);
prefs->RegisterListPref(kExtensionToolbar);
prefs->RegisterIntegerPref(prefs::kExtensionToolbarSize, -1);
prefs->RegisterDictionaryPref(kExtensionsBlacklistUpdate);
+ prefs->RegisterListPref(kExtensionInstallAllowList);
+ prefs->RegisterListPref(kExtensionInstallDenyList);
+ prefs->RegisterStringPref(kWebStoreLogin, std::string() /* default_value */);
}
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 38b8402..01226cd 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PREFS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PREFS_H_
+#pragma once
#include <set>
#include <string>
@@ -11,7 +12,7 @@
#include "base/linked_ptr.h"
#include "base/time.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/extensions/extension.h"
#include "googleurl/src/gurl.h"
@@ -20,8 +21,21 @@
// from there.
class ExtensionPrefs {
public:
+ // Key name for a preference that keeps track of per-extension settings. This
+ // is a dictionary object read from the Preferences file, keyed off of
+ // extension ids.
+ static const char kExtensionsPref[];
+
typedef std::vector<linked_ptr<ExtensionInfo> > ExtensionsInfo;
+ // This enum is used for the launch type the user wants to use for an
+ // application.
+ enum LaunchType {
+ LAUNCH_PINNED,
+ LAUNCH_REGULAR,
+ LAUNCH_FULLSCREEN
+ };
+
explicit ExtensionPrefs(PrefService* prefs, const FilePath& root_dir_);
// Returns a copy of the Extensions prefs.
@@ -89,6 +103,10 @@ class ExtensionPrefs {
// Based on extension id, checks prefs to see if it is blacklisted.
bool IsExtensionBlacklisted(const std::string& id);
+ // Is the extension with |extension_id| allowed by policy (checking both
+ // whitelist and blacklist).
+ bool IsExtensionAllowedByPolicy(const std::string& extension_id);
+
// Returns the last value set via SetLastPingDay. If there isn't such a
// pref, the returned Time will return true for is_null().
base::Time LastPingDay(const std::string& extension_id) const;
@@ -111,6 +129,9 @@ class ExtensionPrefs {
bool AllowFileAccess(const std::string& extension_id);
void SetAllowFileAccess(const std::string& extension_id, bool allow);
+ ExtensionPrefs::LaunchType GetLaunchType(const std::string& extension_id);
+ void SetLaunchType(const std::string& extension_id, LaunchType launch_type);
+
// Saves ExtensionInfo for each installed extension with the path to the
// version directory and the location. Blacklisted extensions won't be saved
// and neither will external extensions the user has explicitly uninstalled.
@@ -142,13 +163,20 @@ class ExtensionPrefs {
// Returns the extension id's that have idle install information.
std::set<std::string> GetIdleInstallInfoIds();
+ // We allow the web store to set a string containing login information when a
+ // purchase is made, so that when a user logs into sync with a different
+ // account we can recognize the situation. The Get function returns true if
+ // there was previously stored data (placing it in |result|), or false
+ // otherwise. The Set will overwrite any previous login.
+ bool GetWebStoreLogin(std::string* result);
+ void SetWebStoreLogin(const std::string& login);
+
static void RegisterUserPrefs(PrefService* prefs);
// The underlying PrefService.
PrefService* pref_service() const { return prefs_; }
private:
-
// Converts absolute paths in the pref to paths relative to the
// install_directory_.
void MakePathsRelative();
@@ -159,7 +187,7 @@ class ExtensionPrefs {
// Sets the pref |key| for extension |id| to |value|.
void UpdateExtensionPref(const std::string& id,
- const std::wstring& key,
+ const std::string& key,
Value* value);
// Deletes the pref dictionary for extension |id|.
@@ -167,11 +195,21 @@ class ExtensionPrefs {
// Reads a boolean pref from |ext| with key |pref_key|.
// Return false if the value is false or kPrefBlacklist does not exist.
- bool ReadBooleanFromPref(DictionaryValue* ext, const std::wstring& pref_key);
+ bool ReadBooleanFromPref(DictionaryValue* ext, const std::string& pref_key);
// Reads a boolean pref |pref_key| from extension with id |extension_id|.
bool ReadExtensionPrefBoolean(const std::string& extension_id,
- const std::wstring& pref_key);
+ const std::string& pref_key);
+
+ // Reads an integer pref from |ext| with key |pref_key|.
+ // Return false if the value does not exist.
+ bool ReadIntegerFromPref(DictionaryValue* ext, const std::string& pref_key,
+ int* out_value);
+
+ // Reads an integer pref |pref_key| from extension with id |extension_id|.
+ bool ReadExtensionPrefInteger(const std::string& extension_id,
+ const std::string& pref_key,
+ int* out_value);
// Ensures and returns a mutable dictionary for extension |id|'s prefs.
DictionaryValue* GetOrCreateExtensionPref(const std::string& id);
@@ -179,6 +217,14 @@ class ExtensionPrefs {
// Same as above, but returns NULL if it doesn't exist.
DictionaryValue* GetExtensionPref(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.
+ // TODO(andybons): Switch this to EXTENSION_PREF_CHANGED to be more granular.
+ // TODO(andybons): Use a ScopedPrefUpdate to update observers on changes to
+ // the mutable extension dictionary.
+ void SavePrefsAndNotify();
+
// Checks if kPrefBlacklist is set to true in the DictionaryValue.
// Return false if the value is false or kPrefBlacklist does not exist.
// This is used to decide if an extension is blacklisted.
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 812891b..11194e7 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -6,11 +6,11 @@
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/test_extension_prefs.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -172,7 +172,7 @@ class ExtensionPrefsBlacklist : public ExtensionPrefsTest {
// Install 5 extensions.
for (int i = 0; i < 5; i++) {
- std::string name = "test" + IntToString(i);
+ std::string name = "test" + base::IntToString(i);
extensions_.push_back(linked_ptr<Extension>(prefs_.AddExtension(name)));
}
EXPECT_EQ(NULL, prefs()->GetInstalledExtensionInfo(not_installed_id_));
@@ -225,8 +225,9 @@ class ExtensionPrefsIdleInstallInfo : public ExtensionPrefsTest {
public:
// Sets idle install information for one test extension.
void SetIdleInfo(std::string id, int num) {
- prefs()->SetIdleInstallInfo(id, basedir_.AppendASCII(IntToString(num)),
- "1." + IntToString(num),
+ prefs()->SetIdleInstallInfo(id,
+ basedir_.AppendASCII(base::IntToString(num)),
+ "1." + base::IntToString(num),
now_ + TimeDelta::FromSeconds(num));
}
@@ -239,8 +240,8 @@ class ExtensionPrefsIdleInstallInfo : public ExtensionPrefsTest {
ASSERT_TRUE(prefs()->GetIdleInstallInfo(id, &crx_path, &version,
&fetch_time));
ASSERT_EQ(crx_path.value(),
- basedir_.AppendASCII(IntToString(num)).value());
- ASSERT_EQ("1." + IntToString(num), version);
+ basedir_.AppendASCII(base::IntToString(num)).value());
+ ASSERT_EQ("1." + base::IntToString(num), version);
ASSERT_TRUE(fetch_time == now_ + TimeDelta::FromSeconds(num));
}
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index 3cde54e..954f92d 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -21,6 +21,40 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/url_constants.h"
+
+namespace {
+
+// Incognito profiles use this process manager. It is mostly a shim that decides
+// whether to fall back on the original profile's ExtensionProcessManager based
+// on whether a given extension uses "split" or "spanning" incognito behavior.
+class IncognitoExtensionProcessManager : public ExtensionProcessManager {
+ public:
+ explicit IncognitoExtensionProcessManager(Profile* profile);
+ virtual ~IncognitoExtensionProcessManager() {}
+ virtual ExtensionHost* CreateView(Extension* extension,
+ const GURL& url,
+ Browser* browser,
+ ViewType::Type view_type);
+ virtual void CreateBackgroundHost(Extension* extension, const GURL& url);
+ virtual SiteInstance* GetSiteInstanceForURL(const GURL& url);
+ virtual RenderProcessHost* GetExtensionProcess(const GURL& url);
+
+ private:
+ // NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Returns the extension for an URL, which can either be a chrome-extension
+ // URL or a web app URL.
+ Extension* GetExtensionOrAppByURL(const GURL& url);
+
+ // Returns true if the extension is allowed to run in incognito mode.
+ bool IsIncognitoEnabled(const Extension* extension);
+
+ ExtensionProcessManager* original_manager_;
+};
static void CreateBackgroundHost(
ExtensionProcessManager* manager, Extension* extension) {
@@ -37,6 +71,19 @@ static void CreateBackgroundHosts(
}
}
+} // namespace
+
+//
+// ExtensionProcessManager
+//
+
+// static
+ExtensionProcessManager* ExtensionProcessManager::Create(Profile* profile) {
+ return (profile->IsOffTheRecord()) ?
+ new IncognitoExtensionProcessManager(profile) :
+ new ExtensionProcessManager(profile);
+}
+
ExtensionProcessManager::ExtensionProcessManager(Profile* profile)
: browsing_instance_(new BrowsingInstance(profile)) {
registrar_.Add(this, NotificationType::EXTENSIONS_READY,
@@ -85,7 +132,7 @@ ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url,
// 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();
+ browsing_instance_->profile()->GetExtensionsService();
if (service) {
Extension* extension = service->GetExtensionByURL(url);
if (extension)
@@ -94,17 +141,6 @@ ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url,
return NULL;
}
-ExtensionHost* ExtensionProcessManager::CreateToolstrip(Extension* extension,
- const GURL& url,
- Browser* browser) {
- return CreateView(extension, url, browser, ViewType::EXTENSION_TOOLSTRIP);
-}
-
-ExtensionHost* ExtensionProcessManager::CreateToolstrip(const GURL& url,
- Browser* browser) {
- return CreateView(url, browser, ViewType::EXTENSION_TOOLSTRIP);
-}
-
ExtensionHost* ExtensionProcessManager::CreatePopup(Extension* extension,
const GURL& url,
Browser* browser) {
@@ -127,8 +163,12 @@ ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url,
return CreateView(url, browser, ViewType::EXTENSION_INFOBAR);
}
-ExtensionHost* ExtensionProcessManager::CreateBackgroundHost(
+void ExtensionProcessManager::CreateBackgroundHost(
Extension* extension, const GURL& url) {
+ // Don't create multiple background hosts for an extension.
+ if (GetBackgroundHostForExtension(extension))
+ return;
+
ExtensionHost* host =
#if defined(OS_MACOSX)
new ExtensionHostMac(extension, GetSiteInstanceForURL(url), url,
@@ -140,16 +180,18 @@ ExtensionHost* ExtensionProcessManager::CreateBackgroundHost(
host->CreateRenderViewSoon(NULL); // create a RenderViewHost with no view
OnExtensionHostCreated(host, true);
- return host;
}
void ExtensionProcessManager::OpenOptionsPage(Extension* extension,
Browser* browser) {
DCHECK(!extension->options_url().is_empty());
- // We can't open extensions URLs in incognito windows.
- if (!browser || browser->profile()->IsOffTheRecord())
- browser = Browser::GetOrCreateTabbedBrowser(browsing_instance_->profile());
+ // Force the options page to open in non-OTR window, because it won't be
+ // able to save settings from OTR.
+ if (!browser || browser->profile()->IsOffTheRecord()) {
+ browser = Browser::GetOrCreateTabbedBrowser(
+ browsing_instance_->profile()->GetOriginalProfile());
+ }
browser->OpenURL(extension->options_url(), GURL(), SINGLETON_TAB,
PageTransition::LINK);
@@ -170,6 +212,8 @@ ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension(
void ExtensionProcessManager::RegisterExtensionProcess(
const std::string& extension_id, int process_id) {
+ // TODO(mpcomplete): This is the only place we actually read process_ids_.
+ // Is it necessary?
ProcessIDMap::const_iterator it = process_ids_.find(extension_id);
if (it != process_ids_.end() && (*it).second == process_id)
return;
@@ -208,7 +252,7 @@ RenderProcessHost* ExtensionProcessManager::GetExtensionProcess(
if (!browsing_instance_->HasSiteInstance(url))
return NULL;
scoped_refptr<SiteInstance> site =
- browsing_instance_->GetSiteInstanceForURL(url);
+ browsing_instance_->GetSiteInstanceForURL(url);
if (site->HasProcess())
return site->GetProcess();
return NULL;
@@ -216,13 +260,8 @@ RenderProcessHost* ExtensionProcessManager::GetExtensionProcess(
RenderProcessHost* ExtensionProcessManager::GetExtensionProcess(
const std::string& extension_id) {
- ProcessIDMap::const_iterator it = process_ids_.find(extension_id);
- if (it == process_ids_.end())
- return NULL;
-
- RenderProcessHost* rph = RenderProcessHost::FromID(it->second);
- DCHECK(rph) << "We should have unregistered this host.";
- return rph;
+ return GetExtensionProcess(
+ Extension::GetBaseURLFromExtensionId(extension_id));
}
SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) {
@@ -296,6 +335,8 @@ void ExtensionProcessManager::Observe(NotificationType type,
void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host,
bool is_background) {
+ DCHECK_EQ(browsing_instance_->profile(), host->profile());
+
all_hosts_.insert(host);
if (is_background)
background_hosts_.insert(host);
@@ -312,3 +353,110 @@ void ExtensionProcessManager::CloseBackgroundHosts() {
delete *current;
}
}
+
+//
+// IncognitoExtensionProcessManager
+//
+
+IncognitoExtensionProcessManager::IncognitoExtensionProcessManager(
+ Profile* profile)
+ : ExtensionProcessManager(profile),
+ original_manager_(profile->GetOriginalProfile()->
+ GetExtensionProcessManager()) {
+ DCHECK(profile->IsOffTheRecord());
+
+ registrar_.Add(this, NotificationType::BROWSER_WINDOW_READY,
+ NotificationService::AllSources());
+}
+
+ExtensionHost* IncognitoExtensionProcessManager::CreateView(
+ Extension* extension,
+ const GURL& url,
+ Browser* browser,
+ ViewType::Type view_type) {
+ if (extension->incognito_split_mode()) {
+ if (IsIncognitoEnabled(extension)) {
+ return ExtensionProcessManager::CreateView(extension, url,
+ browser, view_type);
+ } else {
+ NOTREACHED() <<
+ "We shouldn't be trying to create an incognito extension view unless "
+ "it has been enabled for incognito.";
+ return NULL;
+ }
+ } else {
+ return original_manager_->CreateView(extension, url, browser, view_type);
+ }
+}
+
+void IncognitoExtensionProcessManager::CreateBackgroundHost(
+ Extension* extension, const GURL& url) {
+ if (extension->incognito_split_mode()) {
+ if (IsIncognitoEnabled(extension))
+ ExtensionProcessManager::CreateBackgroundHost(extension, url);
+ } else {
+ // Do nothing. If an extension is spanning, then its original-profile
+ // background page is shared with incognito, so we don't create another.
+ }
+}
+
+SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL(
+ const GURL& url) {
+ Extension* extension = GetExtensionOrAppByURL(url);
+ if (!extension || extension->incognito_split_mode()) {
+ return ExtensionProcessManager::GetSiteInstanceForURL(url);
+ } else {
+ return original_manager_->GetSiteInstanceForURL(url);
+ }
+}
+
+RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess(
+ const GURL& url) {
+ Extension* extension = GetExtensionOrAppByURL(url);
+ if (!extension || extension->incognito_split_mode()) {
+ return ExtensionProcessManager::GetExtensionProcess(url);
+ } else {
+ return original_manager_->GetExtensionProcess(url);
+ }
+}
+
+Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL(
+ const GURL& url) {
+ ExtensionsService* service =
+ browsing_instance_->profile()->GetExtensionsService();
+ if (!service)
+ return NULL;
+ return (url.SchemeIs(chrome::kExtensionScheme)) ?
+ service->GetExtensionByURL(url) : service->GetExtensionByWebExtent(url);
+}
+
+bool IncognitoExtensionProcessManager::IsIncognitoEnabled(
+ const Extension* extension) {
+ ExtensionsService* service =
+ browsing_instance_->profile()->GetExtensionsService();
+ return service && service->IsIncognitoEnabled(extension);
+}
+
+void IncognitoExtensionProcessManager::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::BROWSER_WINDOW_READY: {
+ // We want to spawn our background hosts as soon as the user opens an
+ // incognito window. Watch for new browsers and create the hosts if
+ // it matches our profile.
+ Browser* browser = Source<Browser>(source).ptr();
+ if (browser->profile() == browsing_instance_->profile()) {
+ ExtensionsService* service =
+ browsing_instance_->profile()->GetExtensionsService();
+ if (service && service->is_ready())
+ CreateBackgroundHosts(this, service->extensions());
+ }
+ break;
+ }
+ default:
+ ExtensionProcessManager::Observe(type, source, details);
+ break;
+ }
+}
diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h
index 843cc09..d284275 100644
--- a/chrome/browser/extensions/extension_process_manager.h
+++ b/chrome/browser/extensions/extension_process_manager.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESS_MANAGER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESS_MANAGER_H_
+#pragma once
#include <map>
#include <set>
#include <string>
#include "base/ref_counted.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/view_types.h"
@@ -17,35 +19,29 @@ class Browser;
class BrowsingInstance;
class Extension;
class ExtensionHost;
-#if defined(TOOLKIT_VIEWS)
-class ExtensionView;
-#endif
class GURL;
class Profile;
class RenderProcessHost;
class SiteInstance;
-// Manages dynamic state of running Chromium extensions. There is one instance
-// of this class per Profile (including OTR).
+// Manages dynamic state of running Chromium extensions. There is one instance
+// of this class per Profile. OTR Profiles have a separate instance that keeps
+// track of split-mode extensions only.
class ExtensionProcessManager : public NotificationObserver {
public:
- explicit ExtensionProcessManager(Profile* profile);
- ~ExtensionProcessManager();
+ static ExtensionProcessManager* Create(Profile* profile);
+ virtual ~ExtensionProcessManager();
// Creates a new ExtensionHost with its associated view, grouping it in the
// appropriate SiteInstance (and therefore process) based on the URL and
// profile.
- ExtensionHost* CreateView(Extension* extension,
+ virtual ExtensionHost* CreateView(Extension* extension,
const GURL& url,
Browser* browser,
ViewType::Type view_type);
ExtensionHost* CreateView(const GURL& url,
Browser* browser,
ViewType::Type view_type);
- ExtensionHost* CreateToolstrip(Extension* extension,
- const GURL& url,
- Browser* browser);
- ExtensionHost* CreateToolstrip(const GURL& url, Browser* browser);
ExtensionHost* CreatePopup(Extension* extension,
const GURL& url,
Browser* browser);
@@ -56,19 +52,19 @@ class ExtensionProcessManager : public NotificationObserver {
ExtensionHost* CreateInfobar(const GURL& url,
Browser* browser);
- // Creates a new UI-less extension instance. Like CreateView, but not
- // displayed anywhere.
- ExtensionHost* CreateBackgroundHost(Extension* extension, const GURL& url);
-
// Open the extension's options page.
void OpenOptionsPage(Extension* extension, Browser* browser);
+ // Creates a new UI-less extension instance. Like CreateView, but not
+ // displayed anywhere.
+ virtual void CreateBackgroundHost(Extension* extension, const GURL& url);
+
// Gets the ExtensionHost for the background page for an extension, or NULL if
// the extension isn't running or doesn't have a background page.
ExtensionHost* GetBackgroundHostForExtension(Extension* extension);
// Returns the SiteInstance that the given URL belongs to.
- SiteInstance* GetSiteInstanceForURL(const GURL& url);
+ virtual SiteInstance* GetSiteInstanceForURL(const GURL& url);
// Registers an extension process by |extension_id| and specifying which
// |process_id| it belongs to.
@@ -79,33 +75,33 @@ class ExtensionProcessManager : public NotificationObserver {
void UnregisterExtensionProcess(int process_id);
// Returns the extension process that |url| is associated with if it exists.
- RenderProcessHost* GetExtensionProcess(const GURL& url);
+ virtual RenderProcessHost* GetExtensionProcess(const GURL& url);
// Returns the process that the extension with the given ID is running in.
- // NOTE: This does not currently handle app processes with no
- // ExtensionFunctionDispatcher objects.
RenderProcessHost* GetExtensionProcess(const std::string& extension_id);
// Returns true if |host| is managed by this process manager.
bool HasExtensionHost(ExtensionHost* host) const;
- // NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
typedef std::set<ExtensionHost*> ExtensionHostSet;
typedef ExtensionHostSet::const_iterator const_iterator;
const_iterator begin() const { return all_hosts_.begin(); }
const_iterator end() const { return all_hosts_.end(); }
- private:
+ protected:
+ explicit ExtensionProcessManager(Profile* profile);
+
// Called just after |host| is created so it can be registered in our lists.
void OnExtensionHostCreated(ExtensionHost* host, bool is_background);
// Called on browser shutdown to close our extension hosts.
void CloseBackgroundHosts();
+ // NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
NotificationRegistrar registrar_;
// The set of all ExtensionHosts managed by this process manager.
diff --git a/chrome/browser/extensions/extension_process_manager_unittest.cc b/chrome/browser/extensions/extension_process_manager_unittest.cc
index 8ab9517..f73c0b0 100644
--- a/chrome/browser/extensions/extension_process_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_process_manager_unittest.cc
@@ -31,13 +31,13 @@ TEST_F(ExtensionProcessManagerTest, ProcessGrouping) {
// Extensions in different profiles should always be different SiteInstances.
// Note: we don't initialize these, since we're not testing that
// functionality. This means we can get away with a NULL UserScriptMaster.
- TestingProfile profile1(1);
+ TestingProfile profile1;
scoped_ptr<ExtensionProcessManager> manager1(
- new ExtensionProcessManager(&profile1));
+ ExtensionProcessManager::Create(&profile1));
- TestingProfile profile2(2);
+ TestingProfile profile2;
scoped_ptr<ExtensionProcessManager> manager2(
- new ExtensionProcessManager(&profile2));
+ ExtensionProcessManager::Create(&profile2));
// Extensions with common origins ("scheme://id/") should be grouped in the
// same SiteInstance.
diff --git a/chrome/browser/extensions/extension_processes_api.cc b/chrome/browser/extensions/extension_processes_api.cc
index c4895d3..1c6c8dc 100644
--- a/chrome/browser/extensions/extension_processes_api.cc
+++ b/chrome/browser/extensions/extension_processes_api.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/extension_processes_api.h"
+#include "base/values.h"
+
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extension_processes_api_constants.h"
#include "chrome/browser/renderer_host/render_process_host.h"
diff --git a/chrome/browser/extensions/extension_processes_api.h b/chrome/browser/extensions/extension_processes_api.h
index 08b983b..b58cb56 100644
--- a/chrome/browser/extensions/extension_processes_api.h
+++ b/chrome/browser/extensions/extension_processes_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESSES_API_H__
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESSES_API_H__
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
diff --git a/chrome/browser/extensions/extension_processes_api_constants.cc b/chrome/browser/extensions/extension_processes_api_constants.cc
index 20d0dd3..bb0cccb 100644
--- a/chrome/browser/extensions/extension_processes_api_constants.cc
+++ b/chrome/browser/extensions/extension_processes_api_constants.cc
@@ -6,6 +6,6 @@
namespace extension_processes_api_constants {
-const wchar_t kIdKey[] = L"id";
+const char kIdKey[] = "id";
} // namespace extension_processes_api_constants
diff --git a/chrome/browser/extensions/extension_processes_api_constants.h b/chrome/browser/extensions/extension_processes_api_constants.h
index ae25b63..7e6c844 100644
--- a/chrome/browser/extensions/extension_processes_api_constants.h
+++ b/chrome/browser/extensions/extension_processes_api_constants.h
@@ -6,11 +6,12 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESSES_API_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PROCESSES_API_CONSTANTS_H_
+#pragma once
namespace extension_processes_api_constants {
// Keys used in serializing tab data & events.
-extern const wchar_t kIdKey[];
+extern const char kIdKey[];
}; // namespace extension_processes_api_constants
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index 8422a58..874b759 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -65,6 +65,77 @@ class URLRequestResourceBundleJob : public URLRequestSimpleJob {
int resource_id_;
};
+// Returns true if an chrome-extension:// resource should be allowed to load.
+bool AllowExtensionResourceLoad(URLRequest* request,
+ ChromeURLRequestContext* context,
+ const std::string& scheme) {
+ const ResourceDispatcherHostRequestInfo* info =
+ ResourceDispatcherHost::InfoForRequest(request);
+
+ // We have seen crashes where info is NULL: crbug.com/52374.
+ if (!info) {
+ LOG(ERROR) << "Allowing load of " << request->url().spec()
+ << "from unknown origin. Could not find user data for "
+ << "request.";
+ return true;
+ }
+
+ GURL origin_url(info->frame_origin());
+
+ // chrome:// URLs are always allowed to load chrome-extension:// resources.
+ // The app launcher in the NTP uses this feature, as does dev tools.
+ if (origin_url.SchemeIs(chrome::kChromeUIScheme))
+ return true;
+
+ // Disallow loading of packaged resources for hosted apps. We don't allow
+ // hybrid hosted/packaged apps. The one exception is access to icons, since
+ // some extensions want to be able to do things like create their own
+ // launchers.
+ if (context->ExtensionHasWebExtent(request->url().host())) {
+ if (!context->URLIsForExtensionIcon(request->url())) {
+ LOG(ERROR) << "Denying load of " << request->url().spec() << " from "
+ << "hosted app.";
+ return false;
+ }
+ }
+
+ // Don't allow toplevel navigations to extension resources in incognito mode.
+ // This is because an extension must run in a single process, and an
+ // incognito tab prevents that.
+ if (context->is_off_the_record() &&
+ info->resource_type() == ResourceType::MAIN_FRAME &&
+ !context->ExtensionCanLoadInIncognito(request->url().host())) {
+ LOG(ERROR) << "Denying load of " << request->url().spec() << " from "
+ << "incognito tab.";
+ return false;
+ }
+
+ // Otherwise, pages are allowed to load resources from extensions if the
+ // extension has host permissions to (and therefore could be running script
+ // in, which might need access to the extension resources).
+ //
+ // Exceptions are:
+ // - empty origin (needed for some edge cases when we have empty origins)
+ // - chrome-extension:// (for legacy reasons -- some extensions interop)
+ // - data: (basic HTML notifications use data URLs internally)
+ if (origin_url.is_empty() ||
+ origin_url.SchemeIs(chrome::kExtensionScheme) |
+ origin_url.SchemeIs(chrome::kDataScheme)) {
+ return true;
+ } else {
+ ExtensionExtent host_permissions =
+ context->GetEffectiveHostPermissionsForExtension(request->url().host());
+ if (host_permissions.ContainsURL(origin_url)) {
+ return true;
+ } else {
+ LOG(ERROR) << "Denying load of " << request->url().spec() << " from "
+ << origin_url.spec() << " because the extension does not have "
+ << "access to the requesting page.";
+ return false;
+ }
+ }
+}
+
} // namespace
// Factory registered with URLRequest to create URLRequestJobs for extension://
@@ -74,14 +145,8 @@ static URLRequestJob* CreateExtensionURLRequestJob(URLRequest* request,
ChromeURLRequestContext* context =
static_cast<ChromeURLRequestContext*>(request->context());
- // Don't allow toplevel navigations to extension resources in incognito mode.
- // This is because an extension must run in a single process, and an incognito
- // tab prevents that.
// TODO(mpcomplete): better error code.
- const ResourceDispatcherHostRequestInfo* info =
- ResourceDispatcherHost::InfoForRequest(request);
- if (context->is_off_the_record() &&
- info && info->resource_type() == ResourceType::MAIN_FRAME)
+ if (!AllowExtensionResourceLoad(request, context, scheme))
return new URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE);
// chrome-extension://extension-id/resource/path.js
diff --git a/chrome/browser/extensions/extension_protocols.h b/chrome/browser/extensions/extension_protocols.h
index b4fc7da..b8bc4f1 100644
--- a/chrome/browser/extensions/extension_protocols.h
+++ b/chrome/browser/extensions/extension_protocols.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PROTOCOLS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PROTOCOLS_H_
+#pragma once
// Registers support for the extension URL scheme.
void RegisterExtensionProtocols();
diff --git a/chrome/browser/extensions/extension_rlz_apitest.cc b/chrome/browser/extensions/extension_rlz_apitest.cc
index 3d0ea9e..ce97ae0 100644
--- a/chrome/browser/extensions/extension_rlz_apitest.cc
+++ b/chrome/browser/extensions/extension_rlz_apitest.cc
@@ -51,7 +51,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Rlz) {
rlz_lib::ClearProductState(rlz_lib::DESKTOP, access_points);
// Check that the state has really been cleared.
- RegKey key(HKEY_CURRENT_USER, L"Software\\Google\\Common\\Rlz\\Events\\N");
+ RegKey key(HKEY_CURRENT_USER, L"Software\\Google\\Common\\Rlz\\Events\\N",
+ KEY_READ);
+ ASSERT_FALSE(key.Valid());
+
+ key.Open(HKEY_CURRENT_USER, L"Software\\Google\\Common\\Rlz\\Events\\D",
+ KEY_READ);
ASSERT_FALSE(key.Valid());
// Mock out experimental.rlz.sendFinancialPing().
@@ -65,12 +70,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Rlz) {
// Now run all the tests.
ASSERT_TRUE(RunExtensionTest("rlz")) << message_;
- ASSERT_EQ(1, MockRlzSendFinancialPingFunction::expected_count());
+ ASSERT_EQ(3, MockRlzSendFinancialPingFunction::expected_count());
ExtensionFunctionDispatcher::ResetFunctions();
// Now make sure we recorded what was expected. If the code in test.js
// changes, need to make appropriate changes here.
- key.Open(HKEY_CURRENT_USER, L"Software\\Google\\Common\\Rlz\\Events\\N");
+ key.Open(HKEY_CURRENT_USER, L"Software\\Google\\Common\\Rlz\\Events\\N",
+ KEY_READ);
ASSERT_TRUE(key.Valid());
DWORD value;
@@ -84,7 +90,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Rlz) {
ASSERT_TRUE(key.ReadValueDW(L"D4I", &value));
ASSERT_EQ(1, value);
- key.Open(HKEY_CURRENT_USER, L"Software\\Google\\Common\\Rlz\\Events\\D");
+ key.Open(HKEY_CURRENT_USER, L"Software\\Google\\Common\\Rlz\\Events\\D",
+ KEY_READ);
ASSERT_FALSE(key.Valid());
// Cleanup.
diff --git a/chrome/browser/extensions/extension_rlz_module.cc b/chrome/browser/extensions/extension_rlz_module.cc
index 5519e2d..e31fc69 100644
--- a/chrome/browser/extensions/extension_rlz_module.cc
+++ b/chrome/browser/extensions/extension_rlz_module.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/extensions/extension_rlz_module.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/rlz/rlz.h"
+#include "base/values.h"
#include "chrome/common/extensions/extension.h"
#include "rlz/win/lib/lib_values.h"
@@ -86,7 +86,7 @@ bool RlzRecordProductEventFunction::RunImpl() {
rlz_lib::Event event_id;
EXTENSION_FUNCTION_VALIDATE(GetEventFromName(event_name, &event_id));
- return RLZTracker::RecordProductEvent(product, access_point, event_id);
+ return rlz_lib::RecordProductEvent(product, access_point, event_id);
}
bool RlzGetAccessPointRlzFunction::RunImpl() {
@@ -144,10 +144,18 @@ bool RlzSendFinancialPingFunction::RunImpl() {
bool exclude_machine_id;
EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(6, &exclude_machine_id));
- return rlz_lib::SendFinancialPing(product, access_points.get(),
- signature.c_str(), brand.c_str(),
- id.c_str(), lang.c_str(),
- exclude_machine_id);
+ // rlz_lib::SendFinancialPing() will not send a ping more often than once in
+ // any 24-hour period. Calling it more often has no effect. If a ping is
+ // not sent false is returned, but this is not an error, so we should not
+ // use the return value of rlz_lib::SendFinancialPing() as the return value
+ // of this function. Callers interested in the return value can register
+ // an optional callback function.
+ bool sent = rlz_lib::SendFinancialPing(product, access_points.get(),
+ signature.c_str(), brand.c_str(),
+ id.c_str(), lang.c_str(),
+ exclude_machine_id);
+ result_.reset(Value::CreateBooleanValue(sent));
+ return true;
}
bool RlzClearProductStateFunction::RunImpl() {
diff --git a/chrome/browser/extensions/extension_rlz_module.h b/chrome/browser/extensions/extension_rlz_module.h
index 22364ac..83cb662 100644
--- a/chrome/browser/extensions/extension_rlz_module.h
+++ b/chrome/browser/extensions/extension_rlz_module.h
@@ -4,13 +4,12 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_RLZ_MODULE_H__
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_RLZ_MODULE_H__
+#pragma once
#include "build/build_config.h"
#if defined(OS_WIN)
-#include <string>
-
#include "chrome/browser/extensions/extension_function.h"
class RlzRecordProductEventFunction : public SyncExtensionFunction {
diff --git a/chrome/browser/extensions/extension_shelf_model.cc b/chrome/browser/extensions/extension_shelf_model.cc
deleted file mode 100644
index 51a8ce1..0000000
--- a/chrome/browser/extensions/extension_shelf_model.cc
+++ /dev/null
@@ -1,282 +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/extensions/extension_shelf_model.h"
-
-#include "base/stl_util-inl.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_toolstrip_api.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/notification_service.h"
-
-ExtensionShelfModel::ExtensionShelfModel(Browser* browser)
- : browser_(browser), ready_(false) {
- // Watch extensions loaded and unloaded notifications.
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_LOADED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSIONS_READY,
- NotificationService::AllSources());
-
- // Add any already-loaded extensions now, since we missed the notification for
- // those.
- ExtensionsService* service = browser_->profile()->GetExtensionsService();
- if (service) { // This can be null in unit tests.
- prefs_ = browser_->profile()->GetExtensionsService()->extension_prefs();
- registrar_.Add(this, NotificationType::EXTENSION_SHELF_MODEL_CHANGED,
- Source<ExtensionPrefs>(prefs_));
- ready_ = service->is_ready();
- if (ready_) {
- AddExtensions(service->extensions());
- SortToolstrips();
- }
- }
-}
-
-ExtensionShelfModel::~ExtensionShelfModel() {
- FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_,
- ShelfModelDeleting());
-
- observers_.Clear();
-
- for (iterator t = toolstrips_.begin(); t != toolstrips_.end(); ++t)
- delete t->host;
- toolstrips_.clear();
-}
-
-void ExtensionShelfModel::AddObserver(ExtensionShelfModelObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void ExtensionShelfModel::RemoveObserver(
- ExtensionShelfModelObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void ExtensionShelfModel::AppendToolstrip(const ToolstripItem& toolstrip) {
- InsertToolstripAt(count(), toolstrip);
-}
-
-void ExtensionShelfModel::InsertToolstripAt(int index,
- const ToolstripItem& toolstrip) {
- toolstrips_.insert(toolstrips_.begin() + index, toolstrip);
- if (ready_) {
- FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_,
- ToolstripInsertedAt(toolstrip.host, index));
- }
-}
-
-void ExtensionShelfModel::RemoveToolstripAt(int index) {
- ExtensionHost* host = ToolstripAt(index).host;
- FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_,
- ToolstripRemovingAt(host, index));
- toolstrips_.erase(toolstrips_.begin() + index);
- delete host;
-}
-
-void ExtensionShelfModel::MoveToolstripAt(int index, int to_index) {
- DCHECK(index >= 0);
- DCHECK(to_index >= 0);
- if (index == to_index)
- return;
-
- ToolstripItem toolstrip = toolstrips_[index];
- toolstrips_.erase(toolstrips_.begin() + index);
- toolstrips_.insert(toolstrips_.begin() + to_index, toolstrip);
-
- FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_,
- ToolstripMoved(toolstrip.host, index, to_index));
-
- UpdatePrefs();
-}
-
-int ExtensionShelfModel::IndexOfHost(ExtensionHost* host) {
- for (iterator i = toolstrips_.begin(); i != toolstrips_.end(); ++i) {
- if (i->host == host)
- return i - toolstrips_.begin();
- }
- return -1;
-}
-
-ExtensionShelfModel::iterator ExtensionShelfModel::ToolstripForHost(
- ExtensionHost* host) {
- for (iterator i = toolstrips_.begin(); i != toolstrips_.end(); ++i) {
- if (i->host == host)
- return i;
- }
- return toolstrips_.end();
-}
-
-const ExtensionShelfModel::ToolstripItem& ExtensionShelfModel::ToolstripAt(
- int index) {
- DCHECK(index >= 0);
- return toolstrips_[index];
-}
-
-void ExtensionShelfModel::SetToolstripDataAt(int index, void* data) {
- DCHECK(index >= 0);
- toolstrips_[index].data = data;
-}
-
-void ExtensionShelfModel::ExpandToolstrip(iterator toolstrip,
- const GURL& url, int height) {
- if (toolstrip == end())
- return;
- toolstrip->height = height;
- toolstrip->url = url;
- FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_,
- ToolstripChanged(toolstrip));
- int routing_id = toolstrip->host->render_view_host()->routing_id();
- ToolstripEventRouter::OnToolstripExpanded(browser_->profile(),
- routing_id,
- url, height);
- toolstrip->host->SetRenderViewType(ViewType::EXTENSION_MOLE);
-}
-
-void ExtensionShelfModel::CollapseToolstrip(iterator toolstrip,
- const GURL& url) {
- if (toolstrip == end())
- return;
- toolstrip->height = 0;
- toolstrip->url = url;
- FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_,
- ToolstripChanged(toolstrip));
- int routing_id = toolstrip->host->render_view_host()->routing_id();
- ToolstripEventRouter::OnToolstripCollapsed(browser_->profile(),
- routing_id,
- url);
- toolstrip->host->SetRenderViewType(ViewType::EXTENSION_TOOLSTRIP);
-}
-
-void ExtensionShelfModel::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_LOADED:
- if (ready_)
- AddExtension(Details<Extension>(details).ptr());
- break;
- case NotificationType::EXTENSION_UNLOADED:
- RemoveExtension(Details<Extension>(details).ptr());
- break;
- case NotificationType::EXTENSIONS_READY:
- if (browser_->profile()->GetExtensionsService()) {
- AddExtensions(
- browser_->profile()->GetExtensionsService()->extensions());
- SortToolstrips();
- }
- ready_ = true;
- break;
- case NotificationType::EXTENSION_SHELF_MODEL_CHANGED:
- // Ignore changes that this model originated.
- if (Details<ExtensionShelfModel>(details).ptr() != this)
- SortToolstrips();
- break;
- default:
- DCHECK(false) << "Unhandled notification of type: " << type.value;
- break;
- }
-}
-
-void ExtensionShelfModel::AddExtension(Extension* extension) {
- ExtensionProcessManager* manager =
- browser_->profile()->GetExtensionProcessManager();
- DCHECK(manager);
- if (!manager)
- return;
-
- for (std::vector<Extension::ToolstripInfo>::const_iterator toolstrip =
- extension->toolstrips().begin();
- toolstrip != extension->toolstrips().end(); ++toolstrip) {
- GURL url = toolstrip->toolstrip;
- ToolstripItem item;
- item.host = manager->CreateToolstrip(extension, url, browser_);
- item.info = *toolstrip;
- item.data = NULL;
- item.height = 0;
- AppendToolstrip(item);
- }
-}
-
-void ExtensionShelfModel::AddExtensions(const ExtensionList* extensions) {
- if (extensions->size()) {
- ExtensionList::const_iterator extension = extensions->begin();
- for (; extension != extensions->end(); ++extension)
- AddExtension(*extension);
- }
-}
-
-void ExtensionShelfModel::RemoveExtension(Extension* extension) {
- bool changed = false;
- for (int i = count() - 1; i >= 0; --i) {
- ExtensionHost* t = ToolstripAt(i).host;
- if (t->extension()->id() == extension->id()) {
- changed = true;
- RemoveToolstripAt(i);
-
- // There can be more than one toolstrip per extension, so we have to keep
- // looping even after finding a match.
- }
- }
- if (changed)
- UpdatePrefs();
-}
-
-void ExtensionShelfModel::UpdatePrefs() {
- if (!prefs_)
- return;
-
- // It's easiest to just rebuild the list each time.
- ExtensionPrefs::URLList urls;
- for (int i = 0; i < count(); ++i)
- urls.push_back(ToolstripAt(i).host->GetURL());
- prefs_->SetShelfToolstripOrder(urls);
-
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_SHELF_MODEL_CHANGED,
- Source<ExtensionPrefs>(prefs_),
- Details<ExtensionShelfModel>(this));
-}
-
-void ExtensionShelfModel::SortToolstrips() {
- ExtensionPrefs::URLList urls = prefs_->GetShelfToolstripOrder();
- ToolstripList copy =
- ToolstripList(toolstrips_.begin(), toolstrips_.end());
- toolstrips_.clear();
-
- // Go through the urls and find the matching toolstrip, re-adding it to the
- // new list in the proper order.
- for (size_t i = 0; i < urls.size(); ++i) {
- GURL& url = urls[i];
- for (iterator toolstrip = copy.begin();
- toolstrip != copy.end(); ++toolstrip) {
- if (url == toolstrip->host->GetURL()) {
- // Note that it's technically possible for the same URL to appear in
- // multiple toolstrips, so we don't do any testing for uniqueness.
- toolstrips_.push_back(*toolstrip);
-
- // Remove the toolstrip from the list so we don't have to iterate over
- // it next time.
- copy.erase(toolstrip);
- break;
- }
- }
- }
-
- // Any toolstrips remaining in |copy| were somehow missing from the prefs,
- // so just append them to the end.
- for (iterator toolstrip = copy.begin();
- toolstrip != copy.end(); ++toolstrip) {
- toolstrips_.push_back(*toolstrip);
- }
-
- FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_,
- ShelfModelReloaded());
-}
diff --git a/chrome/browser/extensions/extension_shelf_model.h b/chrome/browser/extensions/extension_shelf_model.h
deleted file mode 100644
index 934ec3b..0000000
--- a/chrome/browser/extensions/extension_shelf_model.h
+++ /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.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SHELF_MODEL_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SHELF_MODEL_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-class Browser;
-class ExtensionPrefs;
-class ExtensionShelfModelObserver;
-
-// The model representing the toolstrips on an ExtensionShelf. The order of
-// the toolstrips is common across all of the models for a given Profile,
-// but there are multiple models. Each model contains the hosts/views which
-// are specific to a Browser.
-class ExtensionShelfModel : public NotificationObserver {
- public:
- explicit ExtensionShelfModel(Browser* browser);
- virtual ~ExtensionShelfModel();
-
- struct ToolstripItem {
- ExtensionHost* host;
- Extension::ToolstripInfo info;
- void* data;
- int height;
- GURL url;
- };
-
- typedef std::vector<ToolstripItem> ToolstripList;
- typedef ToolstripList::iterator iterator;
-
- // Add and remove observers to changes within this ExtensionShelfModel.
- void AddObserver(ExtensionShelfModelObserver* observer);
- void RemoveObserver(ExtensionShelfModelObserver* observer);
-
- // The number of toolstrips in the model.
- int count() const { return static_cast<int>(toolstrips_.size()); }
- bool empty() const { return toolstrips_.empty(); }
-
- // Iterators for the toolstrips in the model.
- iterator begin() { return toolstrips_.begin(); }
- ExtensionShelfModel::iterator end() { return toolstrips_.end(); }
-
- // Add |toolstrip| to the end of the shelf.
- void AppendToolstrip(const ToolstripItem& toolstrip);
-
- // Insert |toolstrip| and |data| at |index|.
- void InsertToolstripAt(int index, const ToolstripItem& toolstrip);
-
- // Remove the toolstrip at |index|.
- void RemoveToolstripAt(int index);
-
- // Move the toolstrip at |index| to |to_index|.
- void MoveToolstripAt(int index, int to_index);
-
- // Lookup the index of |host|. Returns -1 if not present.
- int IndexOfHost(ExtensionHost* host);
-
- // Return the toolstrip at |index|.
- const ToolstripItem& ToolstripAt(int index);
-
- // Return the ToolstripItem associated with |host| or NULL if it's not
- // present.
- ToolstripList::iterator ToolstripForHost(ExtensionHost* host);
-
- // Set some arbitrary data associated with a particular toolstrip.
- void SetToolstripDataAt(int index, void* data);
-
- // Update the ToolstripItem for |toolstrip| to set its |url| and |height|
- // and then call ToolstripChanged for all observers.
- // If |url| is empty, no navigation is requested.
- void ExpandToolstrip(iterator toolstrip, const GURL& url, int height);
-
- // Update the ToolstripItem for |toolstrip| to set its |url| and its height
- // to 0, and then call ToolstripChanged for all observers.
- // If |url| is empty, no navigation is requested.
- void CollapseToolstrip(iterator toolstrip, const GURL& url);
-
- // NotificationObserver
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- private:
- // Add all of the toolstrips from |extension|.
- void AddExtension(Extension* extension);
-
- // Add all of the toolstrips from each extension in |extensions|.
- void AddExtensions(const ExtensionList* extensions);
-
- // Remove all of the toolstrips in |extension| from the shelf.
- void RemoveExtension(Extension* extension);
-
- // Update prefs with the most recent changes.
- void UpdatePrefs();
-
- // Reloads order from prefs.
- void SortToolstrips();
-
- // The browser that this model is attached to.
- Browser* browser_;
-
- // The preferences that this model uses.
- ExtensionPrefs* prefs_;
-
- // Manages our notification registrations.
- NotificationRegistrar registrar_;
-
- // The Toolstrips loaded in this model. The model owns these objects.
- ToolstripList toolstrips_;
-
- // Our observers.
- typedef ObserverList<ExtensionShelfModelObserver>
- ExtensionShelfModelObservers;
- ExtensionShelfModelObservers observers_;
-
- // Whether the model has received an EXTENSIONS_READY notification.
- bool ready_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionShelfModel);
-};
-
-// Objects implement this interface when they wish to be notified of changes to
-// the ExtensionShelfModel.
-//
-// Register your ExtensionShelfModelObserver with the ExtensionShelfModel using
-// Add/RemoveObserver methods.
-class ExtensionShelfModelObserver {
- public:
- // A new toolstrip was inserted into ExtensionShelfModel at |index|.
- virtual void ToolstripInsertedAt(ExtensionHost* toolstrip, int index) {}
-
- // The specified toolstrip is being removed and destroyed.
- virtual void ToolstripRemovingAt(ExtensionHost* toolstrip, int index) {}
-
- // |toolstrip| moved from |from_index| to |to_index|.
- virtual void ToolstripMoved(ExtensionHost* toolstrip,
- int from_index,
- int to_index) {}
-
- // The specified toolstrip changed in some way (currently only size changes)
- virtual void ToolstripChanged(ExtensionShelfModel::iterator toolstrip) {}
-
- // There are no more toolstrips in the model.
- virtual void ExtensionShelfEmpty() {}
-
- // The entire model may have changed.
- virtual void ShelfModelReloaded() {}
-
- // The model is being destroyed.
- virtual void ShelfModelDeleting() {}
-
- protected:
- virtual ~ExtensionShelfModelObserver() {}
-};
-
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SHELF_MODEL_H_
diff --git a/chrome/browser/extensions/extension_shelf_model_browsertest.cc b/chrome/browser/extensions/extension_shelf_model_browsertest.cc
deleted file mode 100644
index abb2a93..0000000
--- a/chrome/browser/extensions/extension_shelf_model_browsertest.cc
+++ /dev/null
@@ -1,97 +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/browser.h"
-#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_shelf_model.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/extensions/extension_shelf.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/test/in_process_browser_test.h"
-
-namespace {
-
-// The extension we're using as our test case.
-const char* kExtensionId = "behllobkkfkfnphdnhnkndlbkcpglgmj";
-
-}; // namespace
-
-
-// An InProcessBrowserTest for testing the ExtensionShelfModel.
-// TODO(erikkay) It's unfortunate that this needs to be an in-proc browser test.
-// It would be nice to refactor things so that ExtensionShelfModel,
-// ExtensionHost and ExtensionsService could run without so much of the browser
-// in place.
-class ExtensionShelfModelTest : public ExtensionBrowserTest,
- public ExtensionShelfModelObserver {
- public:
- virtual void SetUp() {
- inserted_count_ = 0;
- removed_count_ = 0;
- moved_count_ = 0;
- InProcessBrowserTest::SetUp();
- }
-
- virtual Browser* CreateBrowser(Profile* profile) {
- Browser* b = InProcessBrowserTest::CreateBrowser(profile);
- BrowserView* browser_view = static_cast<BrowserView*>(b->window());
- model_ = browser_view->extension_shelf()->model();
- model_->AddObserver(this);
- return b;
- }
-
- virtual void CleanUpOnMainThread() {
- model_->RemoveObserver(this);
- }
-
- virtual void ToolstripInsertedAt(ExtensionHost* toolstrip, int index) {
- inserted_count_++;
- }
-
- virtual void ToolstripRemovingAt(ExtensionHost* toolstrip, int index) {
- removed_count_++;
- }
-
- virtual void ToolstripMoved(ExtensionHost* toolstrip,
- int from_index,
- int to_index) {
- moved_count_++;
- }
-
- protected:
- ExtensionShelfModel* model_;
-
- int inserted_count_;
- int removed_count_;
- int moved_count_;
-};
-
-IN_PROC_BROWSER_TEST_F(ExtensionShelfModelTest, Basic) {
- ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII(kExtensionId)
- .AppendASCII("1.0.0.0")));
-
- // extension1 has two toolstrips
- EXPECT_EQ(inserted_count_, 2);
- ExtensionHost* one = model_->ToolstripAt(0).host;
- ExtensionHost* two = model_->ToolstripAt(1).host;
- EXPECT_EQ(one->GetURL().path(), "/toolstrip1.html");
- EXPECT_EQ(two->GetURL().path(), "/toolstrip2.html");
-
- model_->MoveToolstripAt(0, 1);
- EXPECT_EQ(two, model_->ToolstripAt(0).host);
- EXPECT_EQ(one, model_->ToolstripAt(1).host);
- EXPECT_EQ(moved_count_, 1);
-
- model_->RemoveToolstripAt(0);
- EXPECT_EQ(one, model_->ToolstripAt(0).host);
- EXPECT_EQ(1, model_->count());
- EXPECT_EQ(removed_count_, 1);
-}
diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc
index 0d056d0..5342bc1 100644
--- a/chrome/browser/extensions/extension_startup_browsertest.cc
+++ b/chrome/browser/extensions/extension_startup_browsertest.cc
@@ -31,6 +31,13 @@
class ExtensionStartupTestBase : public InProcessBrowserTest {
public:
ExtensionStartupTestBase() : enable_extensions_(false) {
+#if defined(OS_CHROMEOS)
+ // Chromeos disallows extensions with NPAPI plug-ins, so it's count is one
+ // less
+ num_expected_extensions_ = 2;
+#else
+ num_expected_extensions_ = 3;
+#endif
}
protected:
@@ -60,9 +67,8 @@ class ExtensionStartupTestBase : public InProcessBrowserTest {
command_line->AppendSwitch(switches::kDisableExtensions);
}
- if (!load_extension_.value().empty()) {
- command_line->AppendSwitchWithValue(switches::kLoadExtension,
- load_extension_.ToWStringHack());
+ if (!load_extension_.empty()) {
+ command_line->AppendSwitchPath(switches::kLoadExtension, load_extension_);
command_line->AppendSwitch(switches::kDisableExtensionsFileAccessCheck);
}
}
@@ -82,8 +88,14 @@ class ExtensionStartupTestBase : public InProcessBrowserTest {
ui_test_utils::WaitForNotification(NotificationType::EXTENSIONS_READY);
ASSERT_TRUE(service->is_ready());
+ // Count the number of non-component extensions.
+ int found_extensions = 0;
+ for (size_t i = 0; i < service->extensions()->size(); i++)
+ if (service->extensions()->at(i)->location() != Extension::COMPONENT)
+ found_extensions++;
+
ASSERT_EQ(static_cast<uint32>(num_expected_extensions),
- service->extensions()->size());
+ static_cast<uint32>(found_extensions));
ASSERT_EQ(expect_extensions_enabled, service->extensions_enabled());
UserScriptMaster* master = browser()->profile()->GetUserScriptMaster();
@@ -125,6 +137,8 @@ class ExtensionStartupTestBase : public InProcessBrowserTest {
FilePath user_scripts_dir_;
bool enable_extensions_;
FilePath load_extension_;
+
+ int num_expected_extensions_;
};
@@ -140,7 +154,7 @@ class ExtensionsStartupTest : public ExtensionStartupTestBase {
};
IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) {
- WaitForServicesToStart(4, true); // 1 component extension and 3 others.
+ WaitForServicesToStart(num_expected_extensions_, true);
TestInjection(true, true);
}
@@ -153,10 +167,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) {
// Tests that disallowing file access on an extension prevents it from injecting
// script into a page with a file URL.
IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) {
- WaitForServicesToStart(4, true); // 1 component extension and 3 others.
+ WaitForServicesToStart(num_expected_extensions_, true);
ExtensionsService* service = browser()->profile()->GetExtensionsService();
for (size_t i = 0; i < service->extensions()->size(); ++i) {
+ if (service->extensions()->at(i)->location() == Extension::COMPONENT)
+ continue;
if (service->AllowFileAccess(service->extensions()->at(i))) {
service->SetAllowFileAccess(service->extensions()->at(i), false);
ui_test_utils::WaitForNotification(
diff --git a/chrome/browser/extensions/extension_storage_apitest.cc b/chrome/browser/extensions/extension_storage_apitest.cc
index 032c6ba..b75cc0e 100644
--- a/chrome/browser/extensions/extension_storage_apitest.cc
+++ b/chrome/browser/extensions/extension_storage_apitest.cc
@@ -4,13 +4,6 @@
#include "chrome/browser/extensions/extension_apitest.h"
-#if defined(OS_LINUX) || defined(OS_MACOSX)
-// See http://crbug.com/42943.
-#define MAYBE_Storage FLAKY_Storage
-#else
-#define MAYBE_Storage Storage
-#endif
-
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Storage) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Storage) {
ASSERT_TRUE(RunExtensionTest("storage")) << message_;
}
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc
index 5444386..793376d 100644
--- a/chrome/browser/extensions/extension_tabs_apitest.cc
+++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -5,14 +5,22 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
-// Tabs is flaky on chromeos and linux views debug build.
+// Tabs started crashing on CrOS and hanging browser tests
+// http://crbug.com/56479
+#if defined(OS_CHROMEOS)
+#define MAYBE_Tabs DISABLED_Tabs
+// Tabs is flaky on chromeos, windows, linux views and linux dbg.
// http://crbug.com/48920
-#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS) && !defined(NDEBUG)
+#elif defined(OS_LINUX) || defined(OS_WIN)
#define MAYBE_Tabs FLAKY_Tabs
+#elif defined(OS_MACOSX)
+// Tabs appears to timeout, or maybe crash on mac.
+// http://crbug.com/53779
+#define MAYBE_Tabs FAILS_Tabs
#else
#define MAYBE_Tabs Tabs
#endif
@@ -25,16 +33,8 @@
#define MAYBE_TabOnRemoved TabOnRemoved
#endif
-// CaptureVisibleTab fails on karmic 64 bit.
-// http://crbug.com/49040
-#if defined(OS_LINUX) && defined(__x86_64__) && !defined(NDEBUG)
-#define MAYBE_CaptureVisibleTab FLAKY_CaptureVisibleTab
-#else
-#define MAYBE_CaptureVisibleTab CaptureVisibleTab
-#endif
-
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Tabs) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
// The test creates a tab and checks that the URL of the new tab
// is that of the new tab page. Make sure the pref that controls
@@ -46,27 +46,34 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Tabs) {
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabGetCurrent) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("tabs/get_current")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabConnect) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("tabs/connect")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_TabOnRemoved) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("tabs/on_removed")) << message_;
}
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_CaptureVisibleTab) {
- ASSERT_TRUE(StartHTTPServer());
- ASSERT_TRUE(RunExtensionTest("tabs/capture_visible_tab")) << message_;
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, CaptureVisibleTabJpeg) {
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(RunExtensionSubtest("tabs/capture_visible_tab",
+ "test_jpeg.html")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, CaptureVisibleTabPng) {
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(RunExtensionSubtest("tabs/capture_visible_tab",
+ "test_png.html")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabsOnUpdated) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("tabs/on_updated")) << message_;
}
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index a4b1ee1..6cf9c42 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -5,7 +5,10 @@
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "base/base64.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
@@ -120,7 +123,7 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue(
result->SetString(keys::kStatusKey, GetTabStatusText(contents->is_loading()));
result->SetBoolean(keys::kSelectedKey,
tab_strip && tab_index == tab_strip->selected_index());
- result->SetString(keys::kTitleKey, UTF16ToWide(contents->GetTitle()));
+ result->SetString(keys::kTitleKey, contents->GetTitle());
result->SetBoolean(keys::kIncognitoKey,
contents->profile()->IsOffTheRecord());
@@ -187,7 +190,8 @@ bool ExtensionTabUtil::GetTabById(int tab_id, Profile* profile,
TabStripModel* target_tab_strip;
TabContents* target_contents;
Profile* incognito_profile =
- include_incognito ? profile->GetOffTheRecordProfile() : NULL;
+ include_incognito && profile->HasOffTheRecordProfile() ?
+ profile->GetOffTheRecordProfile() : NULL;
for (BrowserList::const_iterator iter = BrowserList::begin();
iter != BrowserList::end(); ++iter) {
target_browser = *iter;
@@ -223,7 +227,7 @@ bool GetWindowFunction::RunImpl() {
include_incognito(), &error_);
if (!browser || !browser->window()) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- keys::kWindowNotFoundError, IntToString(window_id));
+ keys::kWindowNotFoundError, base::IntToString(window_id));
return false;
}
@@ -266,7 +270,8 @@ bool GetAllWindowsFunction::RunImpl() {
result_.reset(new ListValue());
Profile* incognito_profile =
- include_incognito() ? profile()->GetOffTheRecordProfile() : NULL;
+ include_incognito() && profile()->HasOffTheRecordProfile() ?
+ profile()->GetOffTheRecordProfile() : NULL;
for (BrowserList::const_iterator browser = BrowserList::begin();
browser != BrowserList::end(); ++browser) {
// Only examine browsers in the current profile that have windows.
@@ -312,7 +317,7 @@ bool CreateWindowFunction::RunImpl() {
//
// NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here.
// GetBrowserWindowBounds will default to saved "default" values for the app.
- WindowSizer::GetBrowserWindowBounds(std::wstring(), empty_bounds,
+ WindowSizer::GetBrowserWindowBounds(std::string(), empty_bounds,
GetCurrentBrowser(), &bounds,
&maximized);
@@ -371,7 +376,8 @@ bool CreateWindowFunction::RunImpl() {
Browser* new_window = new Browser(window_type, window_profile);
new_window->CreateBrowserWindow();
new_window->AddTabWithURL(url, GURL(), PageTransition::LINK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &new_window);
new_window->window()->SetBounds(bounds);
new_window->window()->Show();
@@ -396,7 +402,7 @@ bool UpdateWindowFunction::RunImpl() {
include_incognito(), &error_);
if (!browser || !browser->window()) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- keys::kWindowNotFoundError, IntToString(window_id));
+ keys::kWindowNotFoundError, base::IntToString(window_id));
return false;
}
@@ -579,15 +585,17 @@ bool CreateTabFunction::RunImpl() {
TabStripModel::ADD_NONE;
add_types |= TabStripModel::ADD_FORCE_INDEX;
TabContents* contents = browser->AddTabWithURL(url, GURL(),
- PageTransition::LINK, index, add_types, NULL, std::string());
- index = tab_strip->GetIndexOfTabContents(contents);
+ PageTransition::LINK, index, add_types, NULL, std::string(), &browser);
+ index = browser->tabstrip_model()->GetIndexOfTabContents(contents);
if (selected)
contents->Focus();
// Return data about the newly created tab.
if (has_callback())
- result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip, index));
+ result_.reset(ExtensionTabUtil::CreateTabValue(contents,
+ browser->tabstrip_model(),
+ index));
return true;
}
@@ -746,7 +754,7 @@ bool MoveTabFunction::RunImpl() {
contents = source_tab_strip->DetachTabContentsAt(tab_index);
if (!contents) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
- keys::kTabNotFoundError, IntToString(tab_id));
+ keys::kTabNotFoundError, base::IntToString(tab_id));
return false;
}
@@ -964,7 +972,8 @@ void CaptureVisibleTabFunction::SendResultFromBitmap(
image_data->data.size());
base::Base64Encode(stream_as_string, &base64_result);
- base64_result.insert(0, StringPrintf("data:%s;base64,", mime_type.c_str()));
+ base64_result.insert(0, base::StringPrintf("data:%s;base64,",
+ mime_type.c_str()));
result_.reset(new StringValue(base64_result));
SendResponse(true);
}
@@ -1049,7 +1058,8 @@ static Browser* GetBrowserInProfileWithId(Profile* profile,
bool include_incognito,
std::string* error_message) {
Profile* incognito_profile =
- include_incognito ? profile->GetOffTheRecordProfile() : NULL;
+ include_incognito && profile->HasOffTheRecordProfile() ?
+ profile->GetOffTheRecordProfile() : NULL;
for (BrowserList::const_iterator browser = BrowserList::begin();
browser != BrowserList::end(); ++browser) {
if (((*browser)->profile() == profile ||
@@ -1060,7 +1070,7 @@ static Browser* GetBrowserInProfileWithId(Profile* profile,
if (error_message)
*error_message = ExtensionErrorUtils::FormatErrorMessage(
- keys::kWindowNotFoundError, IntToString(window_id));
+ keys::kWindowNotFoundError, base::IntToString(window_id));
return NULL;
}
@@ -1078,7 +1088,7 @@ static bool GetTabById(int tab_id, Profile* profile,
if (error_message)
*error_message = ExtensionErrorUtils::FormatErrorMessage(
- keys::kTabNotFoundError, IntToString(tab_id));
+ keys::kTabNotFoundError, base::IntToString(tab_id));
return false;
}
diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h
index 432ee22..cee8a0d 100644
--- a/chrome/browser/extensions/extension_tabs_module.h
+++ b/chrome/browser/extensions/extension_tabs_module.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TABS_MODULE_H__
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TABS_MODULE_H__
+#pragma once
#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"
class BackingStore;
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc
index e96793b..d1647f8 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.cc
+++ b/chrome/browser/extensions/extension_tabs_module_constants.cc
@@ -6,36 +6,36 @@
namespace extension_tabs_module_constants {
-const wchar_t kAllFramesKey[] = L"allFrames";
-const wchar_t kCodeKey[] = L"code";
-const wchar_t kFavIconUrlKey[] = L"favIconUrl";
-const wchar_t kFileKey[] = L"file";
-const wchar_t kFocusedKey[] = L"focused";
-const wchar_t kFormatKey[] = L"format";
-const wchar_t kFromIndexKey[] = L"fromIndex";
-const wchar_t kHeightKey[] = L"height";
-const wchar_t kIdKey[] = L"id";
-const wchar_t kIncognitoKey[] = L"incognito";
-const wchar_t kIndexKey[] = L"index";
-const wchar_t kLeftKey[] = L"left";
-const wchar_t kNewPositionKey[] = L"newPosition";
-const wchar_t kNewWindowIdKey[] = L"newWindowId";
-const wchar_t kOldPositionKey[] = L"oldPosition";
-const wchar_t kOldWindowIdKey[] = L"oldWindowId";
-const wchar_t kPopulateKey[] = L"populate";
-const wchar_t kQualityKey[] = L"quality";
-const wchar_t kSelectedKey[] = L"selected";
-const wchar_t kStatusKey[] = L"status";
-const wchar_t kTabIdKey[] = L"tabId";
-const wchar_t kTabsKey[] = L"tabs";
-const wchar_t kTabUrlKey[] = L"tabUrl";
-const wchar_t kTitleKey[] = L"title";
-const wchar_t kToIndexKey[] = L"toIndex";
-const wchar_t kTopKey[] = L"top";
-const wchar_t kUrlKey[] = L"url";
-const wchar_t kWidthKey[] = L"width";
-const wchar_t kWindowIdKey[] = L"windowId";
-const wchar_t kWindowTypeKey[] = L"type";
+const char kAllFramesKey[] = "allFrames";
+const char kCodeKey[] = "code";
+const char kFavIconUrlKey[] = "favIconUrl";
+const char kFileKey[] = "file";
+const char kFocusedKey[] = "focused";
+const char kFormatKey[] = "format";
+const char kFromIndexKey[] = "fromIndex";
+const char kHeightKey[] = "height";
+const char kIdKey[] = "id";
+const char kIncognitoKey[] = "incognito";
+const char kIndexKey[] = "index";
+const char kLeftKey[] = "left";
+const char kNewPositionKey[] = "newPosition";
+const char kNewWindowIdKey[] = "newWindowId";
+const char kOldPositionKey[] = "oldPosition";
+const char kOldWindowIdKey[] = "oldWindowId";
+const char kPopulateKey[] = "populate";
+const char kQualityKey[] = "quality";
+const char kSelectedKey[] = "selected";
+const char kStatusKey[] = "status";
+const char kTabIdKey[] = "tabId";
+const char kTabsKey[] = "tabs";
+const char kTabUrlKey[] = "tabUrl";
+const char kTitleKey[] = "title";
+const char kToIndexKey[] = "toIndex";
+const char kTopKey[] = "top";
+const char kUrlKey[] = "url";
+const char kWidthKey[] = "width";
+const char kWindowIdKey[] = "windowId";
+const char kWindowTypeKey[] = "type";
const char kFormatValueJpeg[] = "jpeg";
const char kFormatValuePng[] = "png";
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h
index 7011ad3..3f0ddc0 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.h
+++ b/chrome/browser/extensions/extension_tabs_module_constants.h
@@ -6,40 +6,41 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TABS_MODULE_CONSTANTS_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TABS_MODULE_CONSTANTS_H_
+#pragma once
namespace extension_tabs_module_constants {
// Keys used in serializing tab data & events.
-extern const wchar_t kAllFramesKey[];
-extern const wchar_t kCodeKey[];
-extern const wchar_t kFavIconUrlKey[];
-extern const wchar_t kFileKey[];
-extern const wchar_t kFocusedKey[];
-extern const wchar_t kFormatKey[];
-extern const wchar_t kFromIndexKey[];
-extern const wchar_t kHeightKey[];
-extern const wchar_t kIdKey[];
-extern const wchar_t kIndexKey[];
-extern const wchar_t kLeftKey[];
-extern const wchar_t kNewPositionKey[];
-extern const wchar_t kNewWindowIdKey[];
-extern const wchar_t kOldPositionKey[];
-extern const wchar_t kOldWindowIdKey[];
-extern const wchar_t kPopulateKey[];
-extern const wchar_t kQualityKey[];
-extern const wchar_t kSelectedKey[];
-extern const wchar_t kStatusKey[];
-extern const wchar_t kTabIdKey[];
-extern const wchar_t kTabsKey[];
-extern const wchar_t kTabUrlKey[];
-extern const wchar_t kTitleKey[];
-extern const wchar_t kToIndexKey[];
-extern const wchar_t kTopKey[];
-extern const wchar_t kUrlKey[];
-extern const wchar_t kWidthKey[];
-extern const wchar_t kWindowIdKey[];
-extern const wchar_t kIncognitoKey[];
-extern const wchar_t kWindowTypeKey[];
+extern const char kAllFramesKey[];
+extern const char kCodeKey[];
+extern const char kFavIconUrlKey[];
+extern const char kFileKey[];
+extern const char kFocusedKey[];
+extern const char kFormatKey[];
+extern const char kFromIndexKey[];
+extern const char kHeightKey[];
+extern const char kIdKey[];
+extern const char kIndexKey[];
+extern const char kLeftKey[];
+extern const char kNewPositionKey[];
+extern const char kNewWindowIdKey[];
+extern const char kOldPositionKey[];
+extern const char kOldWindowIdKey[];
+extern const char kPopulateKey[];
+extern const char kQualityKey[];
+extern const char kSelectedKey[];
+extern const char kStatusKey[];
+extern const char kTabIdKey[];
+extern const char kTabsKey[];
+extern const char kTabUrlKey[];
+extern const char kTitleKey[];
+extern const char kToIndexKey[];
+extern const char kTopKey[];
+extern const char kUrlKey[];
+extern const char kWidthKey[];
+extern const char kWindowIdKey[];
+extern const char kIncognitoKey[];
+extern const char kWindowTypeKey[];
// Value consts.
extern const char kCanOnlyMoveTabsWithinNormalWindowsError[];
diff --git a/chrome/browser/extensions/extension_test_api.cc b/chrome/browser/extensions/extension_test_api.cc
index e5ae650..858d25b 100644
--- a/chrome/browser/extensions/extension_test_api.cc
+++ b/chrome/browser/extensions/extension_test_api.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/extension_test_api.h"
+#include <string>
+
#include "chrome/browser/browser.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/extensions/extensions_service.h"
@@ -31,8 +33,6 @@ bool ExtensionTestFailFunction::RunImpl() {
bool ExtensionTestLogFunction::RunImpl() {
std::string message;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &message));
- printf("%s\n", message.c_str());
- LOG(INFO) << message;
return true;
}
@@ -50,3 +50,14 @@ bool ExtensionTestCreateIncognitoTabFunction::RunImpl() {
Browser::OpenURLOffTheRecord(profile(), GURL(url));
return true;
}
+
+bool ExtensionTestSendMessageFunction::RunImpl() {
+ std::string message;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &message));
+ std::string id = extension_id();
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_TEST_MESSAGE,
+ Source<std::string>(&id),
+ Details<std::string>(&message));
+ return true;
+}
diff --git a/chrome/browser/extensions/extension_test_api.h b/chrome/browser/extensions/extension_test_api.h
index ee62627..f59d0b5 100644
--- a/chrome/browser/extensions/extension_test_api.h
+++ b/chrome/browser/extensions/extension_test_api.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_
+#pragma once
#include "chrome/browser/extensions/extension_function.h"
@@ -37,4 +38,10 @@ class ExtensionTestCreateIncognitoTabFunction : public SyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION_NAME("test.createIncognitoTab")
};
+class ExtensionTestSendMessageFunction : public SyncExtensionFunction {
+ ~ExtensionTestSendMessageFunction() {}
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("test.sendMessage")
+};
+
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc
index cac48db..100c7aa 100644
--- a/chrome/browser/extensions/extension_toolbar_model.cc
+++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/pref_service.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"
@@ -33,6 +33,10 @@ ExtensionToolbarModel::ExtensionToolbarModel(ExtensionsService* service)
ExtensionToolbarModel::~ExtensionToolbarModel() {
}
+void ExtensionToolbarModel::DestroyingProfile() {
+ registrar_.RemoveAll();
+}
+
void ExtensionToolbarModel::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h
index f2bbe9d..a38fc8c 100644
--- a/chrome/browser/extensions/extension_toolbar_model.h
+++ b/chrome/browser/extensions/extension_toolbar_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLBAR_MODEL_H_
+#pragma once
#include "base/observer_list.h"
#include "chrome/common/extensions/extension.h"
@@ -19,6 +20,10 @@ class ExtensionToolbarModel : public NotificationObserver {
explicit ExtensionToolbarModel(ExtensionsService* service);
~ExtensionToolbarModel();
+ // Notifies the toolbar model that the Profile that suplied its
+ // prefs is being destroyed.
+ void DestroyingProfile();
+
// A class which is informed of changes to the model; represents the view of
// MVC.
class Observer {
@@ -35,6 +40,9 @@ class ExtensionToolbarModel : public NotificationObserver {
// Called when the model has finished loading.
virtual void ModelLoaded() {}
+
+ protected:
+ virtual ~Observer() {}
};
// Functions called by the view.
diff --git a/chrome/browser/extensions/extension_toolstrip_api.cc b/chrome/browser/extensions/extension_toolstrip_api.cc
deleted file mode 100644
index 26618e0..0000000
--- a/chrome/browser/extensions/extension_toolstrip_api.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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_toolstrip_api.h"
-
-#include "base/json/json_writer.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/extensions/extension_shelf_model.h"
-#include "chrome/browser/extensions/extension_tabs_module_constants.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-
-namespace extension_toolstrip_api_events {
-const char kOnToolstripExpanded[] = "toolstrip.onExpanded.%d";
-const char kOnToolstripCollapsed[] = "toolstrip.onCollapsed.%d";
-}; // namespace extension_toolstrip_api_events
-
-namespace {
-// Errors.
-const char kNotAToolstripError[] = "This page is not a toolstrip.";
-const char kAlreadyExpandedError[] = "This toolstrip is already expanded.";
-const char kAlreadyCollapsedError[] = "This toolstrip is already collapsed.";
-const char kInvalidURLError[] = "Invalid URL";
-const char kBadHeightError[] = "Bad height.";
-
-// TODO(erikkay) what are good values here?
-const int kMinHeight = 50;
-const int kMaxHeight = 1000;
-}; // namespace
-
-namespace keys = extension_tabs_module_constants;
-namespace events = extension_toolstrip_api_events;
-
-bool ToolstripFunction::RunImpl() {
- ViewType::Type view_type =
- dispatcher()->render_view_host()->delegate()->GetRenderViewType();
- if (view_type != ViewType::EXTENSION_TOOLSTRIP &&
- view_type != ViewType::EXTENSION_MOLE) {
- error_ = kNotAToolstripError;
- return false;
- }
-
- Browser* browser = GetCurrentBrowser();
- if (!browser) {
- error_ = kNotAToolstripError;
- return false;
- }
-
- model_ = browser->extension_shelf_model();
- if (!model_) {
- error_ = kNotAToolstripError;
- return false;
- }
-
- // Since this is an EXTENSION_TOOLSTRIP or EXTESION_MOLE view type, we know
- // the delegate must be an ExtensionHost.
- ExtensionHost* host =
- static_cast<ExtensionHost*>(dispatcher()->delegate());
- toolstrip_ = model_->ToolstripForHost(host);
- if (toolstrip_ == model_->end()) {
- error_ = kNotAToolstripError;
- return false;
- }
-
- return true;
-}
-
-bool ToolstripExpandFunction::RunImpl() {
- if (!ToolstripFunction::RunImpl())
- return false;
- if (toolstrip_->height != 0) {
- error_ = kAlreadyExpandedError;
- return false;
- }
-
- DictionaryValue* args;
- EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
-
- int height;
- EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kHeightKey,
- &height));
- EXTENSION_FUNCTION_VALIDATE(height >= 0);
- if (height < kMinHeight || height > kMaxHeight) {
- error_ = kBadHeightError;
- return false;
- }
-
- GURL url;
- if (args->HasKey(keys::kUrlKey)) {
- std::string url_string;
- EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kUrlKey,
- &url_string));
- url = dispatcher()->url().Resolve(url_string);
- if (!url.is_valid()) {
- error_ = kInvalidURLError;
- return false;
- }
- }
-
- model_->ExpandToolstrip(toolstrip_, url, height);
- return true;
-}
-
-bool ToolstripCollapseFunction::RunImpl() {
- if (!ToolstripFunction::RunImpl())
- return false;
-
- if (toolstrip_->height == 0) {
- error_ = kAlreadyCollapsedError;
- return false;
- }
-
- GURL url;
- if (HasOptionalArgument(0)) {
- DictionaryValue* args;
- EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
-
- if (args->HasKey(keys::kUrlKey)) {
- std::string url_string;
- EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kUrlKey,
- &url_string));
- url = dispatcher()->url().Resolve(url_string);
- if (!url.is_valid()) {
- error_ = kInvalidURLError;
- return false;
- }
- }
- }
-
- model_->CollapseToolstrip(toolstrip_, url);
- return true;
-}
-
-// static
-void ToolstripEventRouter::DispatchEvent(Profile *profile,
- int routing_id,
- const char *event_name,
- const Value& json) {
- if (profile->GetExtensionMessageService()) {
- std::string json_args;
- base::JSONWriter::Write(&json, false, &json_args);
- std::string full_event_name = StringPrintf(event_name, routing_id);
- profile->GetExtensionMessageService()->DispatchEventToRenderers(
- full_event_name, json_args, profile->IsOffTheRecord(), GURL());
- }
-}
-
-// static
-void ToolstripEventRouter::OnToolstripExpanded(Profile* profile,
- int routing_id,
- const GURL &url,
- int height) {
- ListValue args;
- DictionaryValue* obj = new DictionaryValue();
- if (!url.is_empty())
- obj->SetString(keys::kUrlKey, url.spec());
- obj->SetInteger(keys::kHeightKey, height);
- args.Append(obj);
- DispatchEvent(profile, routing_id, events::kOnToolstripExpanded, args);
-}
-
-// static
-void ToolstripEventRouter::OnToolstripCollapsed(Profile* profile,
- int routing_id,
- const GURL &url) {
- ListValue args;
- DictionaryValue* obj = new DictionaryValue();
- if (!url.is_empty())
- obj->SetString(keys::kUrlKey, url.spec());
- args.Append(obj);
- DispatchEvent(profile, routing_id, events::kOnToolstripCollapsed, args);
-}
diff --git a/chrome/browser/extensions/extension_toolstrip_api.h b/chrome/browser/extensions/extension_toolstrip_api.h
deleted file mode 100644
index cd4c5e0..0000000
--- a/chrome/browser/extensions/extension_toolstrip_api.h
+++ /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.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLSTRIP_API_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLSTRIP_API_H_
-
-#include "chrome/browser/extensions/extension_function.h"
-#include "chrome/browser/extensions/extension_shelf_model.h"
-
-class Profile;
-
-namespace extension_toolstrip_api_events {
- extern const char kOnToolstripExpanded[];
- extern const char kOnToolstripCollapsed[];
-}; // namespace extension_toolstrip_api_events
-
-class ToolstripFunction : public SyncExtensionFunction {
- protected:
- virtual ~ToolstripFunction() {}
- virtual bool RunImpl();
-
- ExtensionShelfModel* model_;
- ExtensionShelfModel::iterator toolstrip_;
-};
-
-class ToolstripExpandFunction : public ToolstripFunction {
- ~ToolstripExpandFunction() {}
- virtual bool RunImpl();
- DECLARE_EXTENSION_FUNCTION_NAME("toolstrip.expand")
-};
-
-class ToolstripCollapseFunction : public ToolstripFunction {
- ~ToolstripCollapseFunction() {}
- virtual bool RunImpl();
- DECLARE_EXTENSION_FUNCTION_NAME("toolstrip.collapse")
-};
-
-class ToolstripEventRouter {
- public:
- // Toolstrip events.
- static void OnToolstripExpanded(Profile* profile,
- int routing_id,
- const GURL& url,
- int height);
- static void OnToolstripCollapsed(Profile* profile,
- int routing_id,
- const GURL& url);
-
- private:
- // Helper to actually dispatch an event to extension listeners.
- static void DispatchEvent(Profile* profile,
- int routing_id,
- const char* event_name,
- const Value& json);
-
- DISALLOW_COPY_AND_ASSIGN(ToolstripEventRouter);
-};
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TOOLSTRIP_API_H_
diff --git a/chrome/browser/extensions/extension_toolstrip_apitest.cc b/chrome/browser/extensions/extension_toolstrip_apitest.cc
deleted file mode 100644
index 05955a0..0000000
--- a/chrome/browser/extensions/extension_toolstrip_apitest.cc
+++ /dev/null
@@ -1,11 +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/extensions/extension_apitest.h"
-
-// Disabled, http://crbug.com/30151 (Linux and ChromeOS),
-// http://crbug.com/35034 (others).
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_Toolstrip) {
- ASSERT_TRUE(RunExtensionTest("toolstrip")) << message_;
-}
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc
index 96af1c8..ba429ba 100644
--- a/chrome/browser/extensions/extension_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_ui_unittest.cc
@@ -31,7 +31,7 @@ namespace {
#if defined(OS_WIN)
FilePath path(FILE_PATH_LITERAL("c:\\foo"));
#elif defined(OS_POSIX)
- FilePath path(FILE_PATH_LITERAL("/foo"));
+ FilePath path(FILE_PATH_LITERAL("/foo"));
#endif
Extension extension(path);
std::string error;
@@ -72,10 +72,10 @@ TEST(ExtensionUITest, GenerateExtensionsJSONData) {
std::vector<ExtensionPage> pages;
pages.push_back(ExtensionPage(
GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/bar.html"),
- 42, 88));
+ 42, 88, false));
pages.push_back(ExtensionPage(
GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/dog.html"),
- 0, 0));
+ 0, 0, false));
expected_output_path = data_test_dir_path.AppendASCII("extensions")
.AppendASCII("ui")
@@ -85,6 +85,7 @@ TEST(ExtensionUITest, GenerateExtensionsJSONData) {
EXPECT_TRUE(CompareExpectedAndActualOutput(extension_path, pages,
expected_output_path)) << extension_path.value();
+#if !defined(OS_CHROMEOS)
// Test Extension2
extension_path = data_test_dir_path.AppendASCII("extensions")
.AppendASCII("good")
@@ -102,6 +103,7 @@ TEST(ExtensionUITest, GenerateExtensionsJSONData) {
EXPECT_TRUE(CompareExpectedAndActualOutput(extension_path, pages,
expected_output_path)) << extension_path.value();
+#endif
// Test Extension3
extension_path = data_test_dir_path.AppendASCII("extensions")
diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc
index 8344d5d..2076949 100644
--- a/chrome/browser/extensions/extension_uitest.cc
+++ b/chrome/browser/extensions/extension_uitest.cc
@@ -57,10 +57,8 @@ class ExtensionUITest : public ExternalTabUITest {
public:
explicit ExtensionUITest(const std::string& extension_path)
: loop_(MessageLoop::current()) {
- FilePath filename(test_data_directory_);
- filename = filename.AppendASCII(extension_path);
- launch_arguments_.AppendSwitchWithValue(switches::kLoadExtension,
- filename.value());
+ FilePath filename = test_data_directory_.AppendASCII(extension_path);
+ launch_arguments_.AppendSwitchPath(switches::kLoadExtension, filename);
functions_enabled_.push_back("*");
}
diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc
index 9f21100..593b04d 100644
--- a/chrome/browser/extensions/extension_updater.cc
+++ b/chrome/browser/extensions/extension_updater.cc
@@ -9,11 +9,12 @@
#include "base/logging.h"
#include "base/file_util.h"
-#include "base/file_version_info.h"
#include "base/histogram.h"
#include "base/rand_util.h"
#include "base/sha2.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/thread.h"
@@ -21,7 +22,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/utility_process_host.h"
#include "chrome/common/chrome_switches.h"
@@ -34,9 +35,7 @@
#include "net/base/load_flags.h"
#include "net/url_request/url_request_status.h"
-#if defined(OS_WIN)
-#include "base/registry.h"
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
#include "base/sys_string_conversions.h"
#endif
@@ -105,8 +104,8 @@ bool ManifestFetchData::AddExtension(std::string id, std::string version,
parts.push_back("uc");
if (ShouldPing(days)) {
- parts.push_back("ping=" + EscapeQueryParamValue("r=" + IntToString(days),
- true));
+ parts.push_back("ping=" +
+ EscapeQueryParamValue("r=" + base::IntToString(days), true));
}
std::string extra = full_url_.has_query() ? "&" : "?";
@@ -159,10 +158,18 @@ ManifestFetchesBuilder::ManifestFetchesBuilder(
}
void ManifestFetchesBuilder::AddExtension(const Extension& extension) {
+ // Skip extensions with empty update URLs converted from user
+ // scripts.
+ if (extension.converted_from_user_script() &&
+ extension.update_url().is_empty()) {
+ return;
+ }
+
AddExtensionData(extension.location(),
extension.id(),
*extension.version(),
- extension.is_theme(),
+ (extension.is_theme() ? PendingExtensionInfo::THEME
+ : PendingExtensionInfo::EXTENSION),
extension.update_url());
}
@@ -174,8 +181,13 @@ void ManifestFetchesBuilder::AddPendingExtension(
// non-zero versions).
scoped_ptr<Version> version(
Version::GetVersionFromString("0.0.0.0"));
- AddExtensionData(Extension::INTERNAL, id, *version,
- info.is_theme, info.update_url);
+
+ Extension::Location location =
+ (info.is_from_sync ? Extension::INTERNAL
+ : Extension::EXTERNAL_PREF_DOWNLOAD);
+
+ AddExtensionData(location, id, *version,
+ info.expected_crx_type, info.update_url);
}
void ManifestFetchesBuilder::ReportStats() const {
@@ -209,8 +221,9 @@ void ManifestFetchesBuilder::AddExtensionData(
Extension::Location location,
const std::string& id,
const Version& version,
- bool is_theme,
+ PendingExtensionInfo::ExpectedCrxType crx_type,
GURL update_url) {
+
// Only internal and external extensions can be autoupdated.
if (location != Extension::INTERNAL &&
!Extension::IsExternalLocation(location)) {
@@ -242,7 +255,7 @@ void ManifestFetchesBuilder::AddExtensionData(
url_stats_.other_url_count++;
}
- if (is_theme) {
+ if (crx_type == PendingExtensionInfo::THEME) {
url_stats_.theme_count++;
}
@@ -335,7 +348,7 @@ ExtensionUpdater::~ExtensionUpdater() {
}
static void EnsureInt64PrefRegistered(PrefService* prefs,
- const wchar_t name[]) {
+ const char name[]) {
if (!prefs->FindPreference(name))
prefs->RegisterInt64Pref(name, 0);
}
@@ -556,7 +569,8 @@ void ExtensionUpdater::ProcessBlacklist(const std::string& data) {
// Verify sha256 hash value.
char sha256_hash_value[base::SHA256_LENGTH];
base::SHA256HashString(data, sha256_hash_value, base::SHA256_LENGTH);
- std::string hash_in_hex = HexEncode(sha256_hash_value, base::SHA256_LENGTH);
+ std::string hash_in_hex = base::HexEncode(sha256_hash_value,
+ base::SHA256_LENGTH);
if (current_extension_fetch_.package_hash != hash_in_hex) {
NOTREACHED() << "Fetched blacklist checksum is not as expected. "
@@ -761,11 +775,10 @@ std::vector<int> ExtensionUpdater::DetermineUpdates(
if (update->browser_min_version.length() > 0) {
// First determine the browser version if we haven't already.
if (!browser_version.get()) {
- scoped_ptr<FileVersionInfo> version_info(
- chrome::GetChromeVersionInfo());
- if (version_info.get()) {
+ chrome::VersionInfo version_info;
+ if (version_info.is_valid()) {
browser_version.reset(Version::GetVersionFromString(
- version_info->product_version()));
+ version_info.Version()));
}
}
scoped_ptr<Version> browser_min_version(
@@ -787,6 +800,10 @@ std::vector<int> ExtensionUpdater::DetermineUpdates(
}
void ExtensionUpdater::StartUpdateCheck(ManifestFetchData* fetch_data) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableBackgroundNetworking))
+ return;
+
std::deque<ManifestFetchData*>::const_iterator i;
for (i = manifests_pending_.begin(); i != manifests_pending_.end(); i++) {
if (fetch_data->full_url() == (*i)->full_url()) {
diff --git a/chrome/browser/extensions/extension_updater.h b/chrome/browser/extensions/extension_updater.h
index 2b7dec3..ad8d243 100644
--- a/chrome/browser/extensions/extension_updater.h
+++ b/chrome/browser/extensions/extension_updater.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_UPDATER_H_
+#pragma once
#include <deque>
#include <map>
@@ -110,7 +111,7 @@ class ManifestFetchesBuilder {
void AddExtensionData(Extension::Location location,
const std::string& id,
const Version& version,
- bool is_theme,
+ PendingExtensionInfo::ExpectedCrxType crx_type,
GURL update_url);
ExtensionUpdateService* service_;
diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc
index 0895501..b40eb6e 100644
--- a/chrome/browser/extensions/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/extension_updater_unittest.cc
@@ -1,14 +1,16 @@
-// 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.
#include <map>
#include "base/file_util.h"
-#include "base/rand_util.h"
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/thread.h"
#include "base/version.h"
#include "chrome/browser/chrome_thread.h"
@@ -16,7 +18,7 @@
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/test_extension_prefs.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
@@ -40,33 +42,37 @@ class MockService : public ExtensionUpdateService {
virtual ~MockService() {}
virtual const ExtensionList* extensions() const {
- EXPECT_TRUE(false);
+ ADD_FAILURE();
return NULL;
}
virtual const PendingExtensionMap& pending_extensions() const {
- EXPECT_TRUE(false);
+ ADD_FAILURE();
return pending_extensions_;
}
virtual void UpdateExtension(const std::string& id,
const FilePath& extension_path,
const GURL& download_url) {
- EXPECT_TRUE(false);
+ FAIL();
}
virtual Extension* GetExtensionById(const std::string& id, bool) {
- EXPECT_TRUE(false);
+ ADD_FAILURE();
return NULL;
}
virtual void UpdateExtensionBlacklist(
- const std::vector<std::string>& blacklist) {
- EXPECT_TRUE(false);
+ const std::vector<std::string>& blacklist) {
+ FAIL();
+ }
+
+ virtual void CheckAdminBlacklist() {
+ FAIL();
}
virtual bool HasInstalledExtensions() {
- EXPECT_TRUE(false);
+ ADD_FAILURE();
return false;
}
@@ -82,9 +88,9 @@ class MockService : public ExtensionUpdateService {
for (int i = 1; i <= count; i++) {
DictionaryValue manifest;
manifest.SetString(extension_manifest_keys::kVersion,
- StringPrintf("%d.0.0.0", i));
+ base::StringPrintf("%d.0.0.0", i));
manifest.SetString(extension_manifest_keys::kName,
- StringPrintf("Extension %d", i));
+ base::StringPrintf("Extension %d", i));
if (update_url)
manifest.SetString(extension_manifest_keys::kUpdateURL, *update_url);
Extension* e = prefs_.AddExtensionWithManifest(manifest);
@@ -112,15 +118,19 @@ std::string GenerateId(std::string input) {
// 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++) {
- bool is_theme = (i % 2) == 0;
+ crx_type = ((i % 2) ? PendingExtensionInfo::EXTENSION
+ : PendingExtensionInfo::THEME);
+ const bool kIsFromSync = true;
const bool kInstallSilently = true;
const Extension::State kInitialState = Extension::ENABLED;
const bool kInitialIncognitoEnabled = false;
- std::string id = GenerateId(StringPrintf("extension%i", i));
+ std::string id = GenerateId(base::StringPrintf("extension%i", i));
(*pending_extensions)[id] =
- PendingExtensionInfo(update_url, is_theme, kInstallSilently,
- kInitialState, kInitialIncognitoEnabled);
+ PendingExtensionInfo(update_url, crx_type, kIsFromSync,
+ kInstallSilently, kInitialState,
+ kInitialIncognitoEnabled);
}
}
@@ -548,14 +558,17 @@ class ExtensionUpdaterTest : public testing::Test {
updater->FetchUpdatedExtension(id, test_url, hash, version->GetString());
if (pending) {
- const bool kIsTheme = false;
+ 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, kIsTheme, kInstallSilently,
- kInitialState, kInitialIncognitoEnabled);
+ PendingExtensionInfo(test_url, kExpectedCrxType, kIsFromSync,
+ kInstallSilently, kInitialState,
+ kInitialIncognitoEnabled);
service.set_pending_extensions(pending_extensions);
}
@@ -767,7 +780,7 @@ class ExtensionUpdaterTest : public testing::Test {
if (ping_days == 0) {
EXPECT_TRUE(url1_query.find(search_string) == std::string::npos);
} else {
- search_string += "%253D" + IntToString(ping_days);
+ search_string += "%253D" + base::IntToString(ping_days);
size_t pos = url1_query.find(search_string);
EXPECT_TRUE(pos != std::string::npos);
}
@@ -883,18 +896,24 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
// Extensions with invalid update URLs should be rejected.
builder.AddPendingExtension(
GenerateId("foo"), PendingExtensionInfo(GURL("http:google.com:foo"),
+ PendingExtensionInfo::EXTENSION,
false, false, true, false));
EXPECT_TRUE(builder.GetFetches().empty());
// Extensions with empty IDs should be rejected.
builder.AddPendingExtension(
- "", PendingExtensionInfo(GURL(), false, false, true, false));
+ "", PendingExtensionInfo(GURL(), PendingExtensionInfo::EXTENSION,
+ false, false, true, false));
EXPECT_TRUE(builder.GetFetches().empty());
+ // TODO(akalin): Test that extensions with empty update URLs
+ // converted from user scripts are rejected.
+
// Extensions with empty update URLs should have a default one
// filled in.
builder.AddPendingExtension(
GenerateId("foo"), PendingExtensionInfo(GURL(),
+ PendingExtensionInfo::EXTENSION,
false, false, true, false));
std::vector<ManifestFetchData*> fetches = builder.GetFetches();
ASSERT_EQ(1u, fetches.size());
diff --git a/chrome/browser/extensions/extension_websocket_apitest.cc b/chrome/browser/extensions/extension_websocket_apitest.cc
index 3d2b6a5..227a01a 100644
--- a/chrome/browser/extensions/extension_websocket_apitest.cc
+++ b/chrome/browser/extensions/extension_websocket_apitest.cc
@@ -2,12 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/path_service.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebSocket) {
+#if defined(OS_MACOSX)
+// WebSocket test started timing out - suspect webkit roll from 67965->68051.
+// http://crbug.com/56596
+#define MAYBE_WebSocket DISABLED_WebSocket
+#else
+#define MAYBE_WebSocket WebSocket
+#endif
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_WebSocket) {
FilePath websocket_root_dir;
PathService::Get(chrome::DIR_TEST_DATA, &websocket_root_dir);
websocket_root_dir = websocket_root_dir.AppendASCII("layout_tests")
diff --git a/chrome/browser/extensions/extensions_quota_service.h b/chrome/browser/extensions/extensions_quota_service.h
index b2999ab..c60a5d3 100644
--- a/chrome/browser/extensions/extensions_quota_service.h
+++ b/chrome/browser/extensions/extensions_quota_service.h
@@ -13,6 +13,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_QUOTA_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_QUOTA_SERVICE_H_
+#pragma once
#include <list>
#include <map>
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index c371aea..737f689 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -4,14 +4,19 @@
#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/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/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/browser_process.h"
@@ -27,14 +32,17 @@
#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_updater.h"
+#include "chrome/browser/extensions/extension_webnavigation_api.h"
#include "chrome/browser/extensions/external_extension_provider.h"
#include "chrome/browser/extensions/external_pref_extension_provider.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/pref_service.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"
@@ -62,7 +70,18 @@ namespace errors = extension_manifest_errors;
namespace {
-static bool ShouldReloadExtensionManifest(const ExtensionInfo& info) {
+#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
+
+bool ShouldReloadExtensionManifest(const ExtensionInfo& info) {
// Always reload LOAD extension manifests, because they can change on disk
// independent of the manifest in our prefs.
if (info.extension_location == Extension::LOAD)
@@ -72,22 +91,55 @@ static bool ShouldReloadExtensionManifest(const ExtensionInfo& info) {
return extension_l10n_util::ShouldRelocalizeManifest(info);
}
+void GetExplicitOriginsInExtent(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,
- bool is_theme,
- bool install_silently,
- bool enable_on_install,
- bool enable_incognito_on_install)
+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)
: update_url(update_url),
- is_theme(is_theme),
+ 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) {}
PendingExtensionInfo::PendingExtensionInfo()
: update_url(),
- is_theme(false),
+ expected_crx_type(PendingExtensionInfo::UNKNOWN),
+ is_from_sync(true),
install_silently(false),
enable_on_install(false),
enable_incognito_on_install(false) {}
@@ -97,16 +149,16 @@ PendingExtensionInfo::PendingExtensionInfo()
const char* ExtensionsService::kInstallDirectoryName = "Extensions";
const char* ExtensionsService::kCurrentVersionFileName = "Current Version";
-bool ExtensionsService::IsGalleryDownloadURL(const GURL& download_url) {
+namespace {
+
+bool IsGalleryDownloadURL(const GURL& download_url) {
if (StartsWithASCII(download_url.spec(),
extension_urls::kMiniGalleryDownloadPrefix, false))
return true;
- GURL gallery_download_prefix(extension_urls::kGalleryDownloadPrefix);
- if (download_url.host() == gallery_download_prefix.host() &&
- StartsWithASCII(download_url.path(),
- gallery_download_prefix.path(), false))
- return true;
+ if (StartsWithASCII(download_url.spec(),
+ extension_urls::kGalleryDownloadPrefix, false))
+ return true;
// Allow command line gallery url to be referrer for the gallery downloads.
std::string command_line_gallery_url =
@@ -114,12 +166,340 @@ bool ExtensionsService::IsGalleryDownloadURL(const GURL& download_url) {
switches::kAppsGalleryURL);
if (!command_line_gallery_url.empty() &&
StartsWithASCII(download_url.spec(),
- extension_urls::kGalleryDownloadPrefix, false))
+ command_line_gallery_url, false))
return true;
return false;
}
+} // namespace
+
+// 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.
+ // |load_external_extensions| indicates whether or not backend should load
+ // external extensions listed in JSON file and Windows registry.
+ ExtensionsServiceBackend(const FilePath& install_directory,
+ bool load_external_extensions);
+
+ // 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(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,
+ Extension::Location location);
+
+ // Clear all ExternalExtensionProviders.
+ void ClearProvidersForTesting();
+
+ // Sets an ExternalExtensionProvider for the service to use during testing.
+ // |location| specifies what type of provider should be added.
+ void SetProviderForTesting(Extension::Location location,
+ 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);
+
+ // Reloads the given extensions from their manifests on disk (instead of what
+ // we have cached in the prefs).
+ void ReloadExtensionManifests(
+ ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
+ base::TimeTicks start_time,
+ scoped_refptr<ExtensionsService> frontend);
+
+ 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,
+ 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);
+
+ // Lookup an external extension by |id| by going through all registered
+ // external extension providers until we find a provider that contains an
+ // extension that matches. If |version| is not NULL, the extension version
+ // will be returned (caller is responsible for deleting that pointer).
+ // |location| can also be null, if not needed. Returns true if extension is
+ // found, false otherwise.
+ bool LookupExternalExtension(const std::string& id,
+ Version** version,
+ Extension::Location* location);
+
+ // 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 map from external extension type to the external extension provider
+ // for that type. Because a single provider may handle more than one
+ // external extension type, more than one key may map to the same object.
+ typedef std::map<Extension::Location,
+ linked_ptr<ExternalExtensionProvider> > ProviderMap;
+ ProviderMap external_extension_providers_;
+
+ // 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(
+ const FilePath& install_directory,
+ bool load_external_extensions)
+ : frontend_(NULL),
+ install_directory_(install_directory),
+ alert_on_error_(false),
+ external_extension_added_(false) {
+ if (!load_external_extensions)
+ return;
+
+ // 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_[Extension::EXTERNAL_PREF] =
+ linked_ptr<ExternalExtensionProvider>(
+ new ExternalPrefExtensionProvider());
+ // EXTERNAL_PREF_DOWNLOAD and EXTERNAL_PREF extensions are handled by the
+ // same object.
+ external_extension_providers_[Extension::EXTERNAL_PREF_DOWNLOAD] =
+ external_extension_providers_[Extension::EXTERNAL_PREF];
+#if defined(OS_WIN)
+ external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
+ linked_ptr<ExternalExtensionProvider>(
+ new ExternalRegistryExtensionProvider());
+#endif
+}
+
+ExtensionsServiceBackend::~ExtensionsServiceBackend() {
+}
+
+void ExtensionsServiceBackend::LoadSingleExtension(
+ const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
+ 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;
+ Extension* extension = extension_file_util::LoadExtension(
+ extension_path,
+ false, // Don't require id
+ &error);
+
+ if (!extension) {
+ ReportExtensionLoadError(extension_path, error);
+ return;
+ }
+
+ extension->set_location(Extension::LOAD);
+
+ // Report this as an installed extension so that it gets remembered in the
+ // prefs.
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(frontend_, &ExtensionsService::OnExtensionInstalled,
+ extension, true));
+}
+
+void ExtensionsServiceBackend::ReportExtensionLoadError(
+ const FilePath& extension_path, const std::string &error) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_,
+ &ExtensionsService::ReportExtensionLoadError, extension_path,
+ error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
+}
+
+bool ExtensionsServiceBackend::LookupExternalExtension(
+ const std::string& id, Version** version, Extension::Location* location) {
+ scoped_ptr<Version> extension_version;
+ for (ProviderMap::const_iterator i = external_extension_providers_.begin();
+ i != external_extension_providers_.end(); ++i) {
+ const ExternalExtensionProvider* provider = i->second.get();
+ extension_version.reset(provider->RegisteredVersion(id, location));
+ if (extension_version.get()) {
+ if (version)
+ *version = extension_version.release();
+ return true;
+ }
+ }
+ return false;
+}
+
+// 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(
+ std::set<std::string> ids_to_ignore,
+ scoped_refptr<ExtensionsService> frontend) {
+ // 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.
+
+ for (ProviderMap::const_iterator i = external_extension_providers_.begin();
+ i != external_extension_providers_.end(); ++i) {
+ ExternalExtensionProvider* provider = i->second.get();
+ provider->VisitRegisteredExtension(this, ids_to_ignore);
+ }
+
+ if (external_extension_added_ && frontend->updater()) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend->updater(), &ExtensionUpdater::CheckNow));
+ }
+}
+
+void ExtensionsServiceBackend::CheckExternalUninstall(
+ scoped_refptr<ExtensionsService> frontend, const std::string& id,
+ Extension::Location location) {
+ // Check if the providers know about this extension.
+ ProviderMap::const_iterator i = external_extension_providers_.find(location);
+ if (i == external_extension_providers_.end()) {
+ NOTREACHED() << "CheckExternalUninstall called for non-external extension "
+ << location;
+ return;
+ }
+
+ scoped_ptr<Version> version;
+ version.reset(i->second->RegisteredVersion(id, NULL));
+ if (version.get())
+ return; // Yup, known extension, don't uninstall.
+
+ // This is an external extension that we don't have registered. Uninstall.
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend.get(), &ExtensionsService::UninstallExtension, id, true));
+}
+
+void ExtensionsServiceBackend::ClearProvidersForTesting() {
+ external_extension_providers_.clear();
+}
+
+void ExtensionsServiceBackend::SetProviderForTesting(
+ Extension::Location location,
+ ExternalExtensionProvider* test_provider) {
+ DCHECK(test_provider);
+ external_extension_providers_[location] =
+ linked_ptr<ExternalExtensionProvider>(test_provider);
+}
+
+void ExtensionsServiceBackend::OnExternalExtensionFileFound(
+ const std::string& id, const Version* version, const FilePath& path,
+ Extension::Location location) {
+ DCHECK(version);
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_, &ExtensionsService::OnExternalExtensionFileFound, id,
+ version->GetString(), path, location));
+}
+
+void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound(
+ const std::string& id,
+ const GURL& update_url) {
+ if (frontend_->GetExtensionById(id, true)) {
+ // Already installed. Do not change the update URL that the extension set.
+ return;
+ }
+
+ frontend_->AddPendingExtensionFromExternalUpdateUrl(id, update_url);
+ external_extension_added_ |= true;
+}
+
+void ExtensionsServiceBackend::ReloadExtensionManifests(
+ ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
+ base::TimeTicks start_time,
+ scoped_refptr<ExtensionsService> frontend) {
+ frontend_ = frontend;
+
+ for (size_t i = 0; i < extensions_to_reload->size(); ++i) {
+ ExtensionInfo* info = extensions_to_reload->at(i).get();
+ if (!ShouldReloadExtensionManifest(*info))
+ continue;
+
+ // We need to reload original manifest in order to localize properly.
+ std::string error;
+ scoped_ptr<Extension> extension(extension_file_util::LoadExtension(
+ info->extension_path, false, &error));
+
+ if (extension.get())
+ extensions_to_reload->at(i)->extension_manifest.reset(
+ static_cast<DictionaryValue*>(
+ extension->manifest_value()->DeepCopy()));
+ }
+
+ // Finish installing on UI thread.
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_,
+ &ExtensionsService::ContinueLoadAllExtensions,
+ extensions_to_reload,
+ start_time,
+ true));
+}
+
// static
bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url,
const GURL& referrer_url) {
@@ -154,11 +534,11 @@ bool ExtensionsService::IsDownloadFromMiniGallery(const GURL& download_url) {
ExtensionsService::ExtensionsService(Profile* profile,
const CommandLine* command_line,
- PrefService* prefs,
const FilePath& install_directory,
bool autoupdate_enabled)
: profile_(profile),
- extension_prefs_(new ExtensionPrefs(prefs, install_directory)),
+ extension_prefs_(new ExtensionPrefs(profile->GetPrefs(),
+ install_directory)),
install_directory_(install_directory),
extensions_enabled_(true),
show_extensions_prompts_(true),
@@ -171,28 +551,37 @@ ExtensionsService::ExtensionsService(Profile* profile,
extensions_enabled_ = false;
}
- registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
- NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
- Source<Profile>(profile_));
+ NotificationService::AllSources());
+ pref_change_registrar_.Init(profile->GetPrefs());
+ pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this);
+ pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this);
// Set up the ExtensionUpdater
if (autoupdate_enabled) {
int update_frequency = kDefaultUpdateFrequencySeconds;
if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
- update_frequency = StringToInt(command_line->GetSwitchValueASCII(
- switches::kExtensionsUpdateFrequency));
+ base::StringToInt(command_line->GetSwitchValueASCII(
+ switches::kExtensionsUpdateFrequency),
+ &update_frequency);
}
- updater_ = new ExtensionUpdater(this, prefs, update_frequency);
+ updater_ = new ExtensionUpdater(this,
+ profile->GetPrefs(),
+ update_frequency);
}
- backend_ = new ExtensionsServiceBackend(install_directory_);
+ backend_ = new ExtensionsServiceBackend(install_directory_,
+ extensions_enabled_);
- // Use monochrome icons for omnibox icons.
+ // 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();
@@ -206,6 +595,8 @@ void ExtensionsService::InitEventRouters() {
ExtensionBookmarkEventRouter::GetSingleton()->Observe(
profile_->GetBookmarkModel());
ExtensionCookiesEventRouter::GetInstance()->Init();
+ ExtensionManagementEventRouter::GetInstance()->Init();
+ ExtensionWebNavigationEventRouter::GetInstance()->Init();
}
void ExtensionsService::Init() {
@@ -248,7 +639,9 @@ void ExtensionsService::UpdateExtension(const std::string& id,
const FilePath& extension_path,
const GURL& download_url) {
PendingExtensionMap::const_iterator it = pending_extensions_.find(id);
- if ((it == pending_extensions_.end()) &&
+ bool is_pending_extension = (it != pending_extensions_.end());
+
+ if (!is_pending_extension &&
!GetExtensionByIdInternal(id, true, true)) {
LOG(WARNING) << "Will not update extension " << id
<< " because it is not installed or pending";
@@ -263,7 +656,7 @@ void ExtensionsService::UpdateExtension(const std::string& id,
// We want a silent install only for non-pending extensions and
// pending extensions that have install_silently set.
ExtensionInstallUI* client =
- ((it == pending_extensions_.end()) || it->second.install_silently) ?
+ (!is_pending_extension || it->second.install_silently) ?
NULL : new ExtensionInstallUI(profile_);
scoped_refptr<CrxInstaller> installer(
@@ -271,40 +664,66 @@ void ExtensionsService::UpdateExtension(const std::string& id,
this, // frontend
client));
installer->set_expected_id(id);
+ if (is_pending_extension && !it->second.is_from_sync)
+ installer->set_install_source(Extension::EXTERNAL_PREF_DOWNLOAD);
installer->set_delete_source(true);
- installer->set_limit_web_extent_to_download_host(true);
installer->set_original_url(download_url);
installer->InstallCrx(extension_path);
}
-void ExtensionsService::AddPendingExtension(
+void ExtensionsService::AddPendingExtensionFromSync(
const std::string& id, const GURL& update_url,
- bool is_theme, bool install_silently,
- bool enable_on_install, bool enable_incognito_on_install) {
+ 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, is_theme, install_silently,
+ id, update_url, expected_crx_type, true, install_silently,
enable_on_install, enable_incognito_on_install);
}
+void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl(
+ const std::string& id, const GURL& update_url) {
+ // Add the extension to this list of extensions to update.
+ // We do not know if the id refers to a theme, so make is_theme unknown.
+ 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);
+}
+
void ExtensionsService::AddPendingExtensionInternal(
const std::string& id, const GURL& update_url,
- bool is_theme, bool install_silently,
+ PendingExtensionInfo::ExpectedCrxType expected_crx_type,
+ bool is_from_sync, bool install_silently,
bool enable_on_install, bool enable_incognito_on_install) {
pending_extensions_[id] =
- PendingExtensionInfo(update_url, is_theme, install_silently,
- enable_on_install, enable_incognito_on_install);
+ PendingExtensionInfo(update_url, expected_crx_type, is_from_sync,
+ install_silently, enable_on_install,
+ enable_incognito_on_install);
}
void ExtensionsService::ReloadExtension(const std::string& extension_id) {
FilePath path;
Extension* current_extension = GetExtensionById(extension_id, false);
- // Unload the extension if it's loaded. It might not be loaded if it crashed.
+ // 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
@@ -321,7 +740,8 @@ void ExtensionsService::ReloadExtension(const std::string& extension_id) {
}
path = current_extension->path();
- UnloadExtension(extension_id);
+ DisableExtension(extension_id);
+ disabled_extension_paths_[extension_id] = path;
} else {
path = unloaded_extension_paths_[extension_id];
}
@@ -345,9 +765,15 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id,
bool external_uninstall) {
Extension* extension = GetExtensionByIdInternal(extension_id, true, true);
- // Callers should not send us nonexistant extensions.
+ // Callers should not send us nonexistent extensions.
DCHECK(extension);
+ // Notify interested parties that we're uninstalling this extension.
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_UNINSTALLED,
+ Source<Profile>(profile_),
+ Details<Extension>(extension));
+
// Get hold of information we need after unloading, since the extension
// pointer will be invalid then.
GURL extension_url(extension->url());
@@ -389,7 +815,6 @@ void ExtensionsService::ClearExtensionData(const GURL& extension_url) {
void ExtensionsService::EnableExtension(const std::string& extension_id) {
Extension* extension = GetExtensionByIdInternal(extension_id, false, true);
if (!extension) {
- NOTREACHED() << "Trying to enable an extension that isn't disabled.";
return;
}
@@ -447,7 +872,7 @@ void ExtensionsService::LoadComponentExtensions() {
JSONStringValueSerializer serializer(it->manifest);
scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
if (!manifest.get()) {
- DLOG(ERROR) << "Failed to retrieve manifest for extension";
+ DLOG(ERROR) << "Failed to parse manifest for extension";
continue;
}
@@ -463,6 +888,21 @@ void ExtensionsService::LoadComponentExtensions() {
return;
}
+ // In order for the --apps-gallery-url switch to work with the gallery
+ // process isolation, we must insert any provided value into the component
+ // app's launch url and web extent.
+ if (extension->id() == extension_misc::kWebStoreAppId) {
+ GURL gallery_url(CommandLine::ForCurrentProcess()
+ ->GetSwitchValueASCII(switches::kAppsGalleryURL));
+ if (gallery_url.is_valid()) {
+ extension->set_launch_web_url(gallery_url.spec());
+ URLPattern pattern(URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS);
+ pattern.Parse(gallery_url.spec());
+ pattern.set_path(pattern.path() + '*');
+ extension->web_extent().AddPattern(pattern);
+ }
+ }
+
OnExtensionLoaded(extension.release(), false); // Don't allow privilege
// increase.
}
@@ -564,7 +1004,9 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
bool write_to_prefs) {
std::string error;
Extension* extension = NULL;
- if (info.extension_manifest.get()) {
+ if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
+ error = errors::kDisabledByPolicy;
+ } else if (info.extension_manifest.get()) {
scoped_ptr<Extension> tmp(new Extension(info.extension_path));
bool require_key = info.extension_location != Extension::LOAD;
if (tmp->InitFromValue(*info.extension_manifest, require_key, &error))
@@ -588,16 +1030,15 @@ void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
OnExtensionLoaded(extension, true);
- if (info.extension_location == Extension::EXTERNAL_PREF ||
- info.extension_location == Extension::EXTERNAL_REGISTRY) {
+ if (Extension::IsExternalLocation(info.extension_location)) {
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(
- backend_.get(),
- &ExtensionsServiceBackend::CheckExternalUninstall,
- scoped_refptr<ExtensionsService>(this),
- info.extension_id,
- info.extension_location));
+ backend_.get(),
+ &ExtensionsServiceBackend::CheckExternalUninstall,
+ scoped_refptr<ExtensionsService>(this),
+ info.extension_id,
+ info.extension_location));
}
}
@@ -612,20 +1053,14 @@ void ExtensionsService::NotifyExtensionLoaded(Extension* extension) {
profile_->RegisterExtensionWithRequestContexts(extension);
// Check if this permission requires unlimited storage quota
- if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission)) {
- string16 origin_identifier =
- webkit_database::DatabaseUtil::GetOriginIdentifier(extension->url());
- ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(
- profile_->GetDatabaseTracker(),
- &webkit_database::DatabaseTracker::SetOriginQuotaInMemory,
- origin_identifier,
- kint64max));
- }
- }
+ if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
+ GrantUnlimitedStorage(extension);
- LOG(INFO) << "Sending EXTENSION_LOADED";
+ // 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,
@@ -634,8 +1069,6 @@ void ExtensionsService::NotifyExtensionLoaded(Extension* extension) {
}
void ExtensionsService::NotifyExtensionUnloaded(Extension* extension) {
- LOG(INFO) << "Sending EXTENSION_UNLOADED";
-
NotificationService::current()->Notify(
NotificationType::EXTENSION_UNLOADED,
Source<Profile>(profile_),
@@ -646,15 +1079,90 @@ void ExtensionsService::NotifyExtensionUnloaded(Extension* extension) {
// Check if this permission required unlimited storage quota, reset its
// in-memory quota.
- if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission)) {
+ 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(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(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(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(extension->url());
+ webkit_database::DatabaseUtil::GetOriginIdentifier(origin);
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetDatabaseTracker(),
+ &webkit_database::DatabaseTracker::SetOriginQuotaInMemory,
+ origin_identifier,
+ kint64max));
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetAppCacheService(),
+ &ChromeAppCacheService::SetOriginQuotaInMemory,
+ origin,
+ kint64max));
+ }
+ }
+}
+
+void ExtensionsService::RevokeUnlimitedStorage(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);
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(
profile_->GetDatabaseTracker(),
&webkit_database::DatabaseTracker::ResetOriginQuotaInMemory,
origin_identifier));
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetAppCacheService(),
+ &ChromeAppCacheService::ResetOriginQuotaInMemory,
+ origin));
}
}
}
@@ -686,6 +1194,28 @@ void ExtensionsService::UpdateExtensionBlacklist(
}
}
+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) {
+ 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.
@@ -700,9 +1230,14 @@ void ExtensionsService::SetIsIncognitoEnabled(Extension* extension,
bool enabled) {
extension_prefs_->SetIsIncognitoEnabled(extension->id(), enabled);
- // Broadcast unloaded and loaded events to update browser state.
- NotifyExtensionUnloaded(extension);
- NotifyExtensionLoaded(extension);
+ // 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::AllowFileAccess(const Extension* extension) {
@@ -761,13 +1296,16 @@ void ExtensionsService::UnloadExtension(const std::string& extension_id) {
scoped_ptr<Extension> extension(
GetExtensionByIdInternal(extension_id, true, true));
- // Callers should not send us nonexistant extensions.
+ // Callers should not send us nonexistent extensions.
CHECK(extension.get());
// 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());
+
ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
extension->GetChromeURLOverrides());
@@ -847,6 +1385,10 @@ void ExtensionsService::OnExtensionLoaded(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(aa): Need to re-evaluate this branch. Does this still make sense now
// that extensions are enabled by default?
if (extensions_enabled() ||
@@ -913,8 +1455,10 @@ void ExtensionsService::OnExtensionLoaded(Extension* extension,
// Load the icon for omnibox-enabled extensions so it will be ready to display
// in the URL bar.
- if (!extension->omnibox_keyword().empty())
+ if (!extension->omnibox_keyword().empty()) {
+ omnibox_popup_icon_manager_.LoadIcon(extension);
omnibox_icon_manager_.LoadIcon(extension);
+ }
}
void ExtensionsService::UpdateActiveExtensionsInCrashReporter() {
@@ -937,14 +1481,22 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
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.
- if (pending_extension_info.is_theme != extension->is_theme()) {
+ PendingExtensionInfo::ExpectedCrxType actual_crx_type =
+ (extension->is_theme() ? PendingExtensionInfo::THEME
+ : PendingExtensionInfo::EXTENSION);
+
+ 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()
- << "; expected is_theme = " << pending_extension_info.is_theme;
+ << " with is_theme = " << extension->is_theme();
// Delete the extension directory since we're not going to
// load it.
ChromeThread::PostTask(
@@ -952,8 +1504,33 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
return;
}
- if (!extension->is_theme() &&
- !browser_sync::IsExtensionSyncable(*extension)) {
+
+ // 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
@@ -968,7 +1545,8 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
// TODO(akalin): Remove this check once we've put in UI to
// approve synced extensions.
LOG(WARNING)
- << "Not installing non-syncable extension " << extension->id();
+ << "Not installing invalid or unsyncable extension "
+ << extension->id();
// Delete the extension directory since we're not going to
// load it.
ChromeThread::PostTask(
@@ -976,7 +1554,7 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
return;
}
- if (pending_extension_info.is_theme) {
+ if (extension->is_theme()) {
DCHECK(pending_extension_info.enable_on_install);
initial_state = Extension::ENABLED;
DCHECK(!pending_extension_info.enable_incognito_on_install);
@@ -989,13 +1567,14 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
pending_extension_info.enable_incognito_on_install;
}
} else {
- // Make sure we don't enable a disabled extension.
+ // 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 = false;
+ initial_enable_incognito =
+ extension_prefs_->IsIncognitoEnabled(extension->id());
}
extension_prefs_->OnExtensionInstalled(
@@ -1058,6 +1637,16 @@ Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) {
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.
+ Extension* extension = GetExtensionByWebExtent(url);
+ return (extension && extension->location() == Extension::COMPONENT);
+}
+
Extension* ExtensionsService::GetExtensionByOverlappingWebExtent(
const ExtensionExtent& extent) {
for (size_t i = 0; i < extensions_.size(); ++i) {
@@ -1073,6 +1662,11 @@ const SkBitmap& ExtensionsService::GetOmniboxIcon(
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() {
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
@@ -1089,10 +1683,11 @@ void ExtensionsService::SetProviderForTesting(
location, test_provider));
}
-void ExtensionsService::OnExternalExtensionFound(const std::string& id,
- const std::string& version,
- const FilePath& path,
- Extension::Location location) {
+void ExtensionsService::OnExternalExtensionFileFound(
+ const std::string& id,
+ const std::string& version,
+ const FilePath& path,
+ Extension::Location location) {
// 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.
@@ -1135,34 +1730,62 @@ void ExtensionsService::ReportExtensionLoadError(
// TODO(port): note that this isn't guaranteed to work properly on Linux.
std::string path_str = WideToUTF8(extension_path.ToWStringHack());
- std::string message = StringPrintf("Could not load extension from '%s'. %s",
- path_str.c_str(), error.c_str());
+ 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_HOST_DID_STOP_LOADING: {
- ExtensionHost* host = Details<ExtensionHost>(details).ptr();
- OrphanedDevTools::iterator iter =
- orphaned_dev_tools_.find(host->extension()->id());
- if (iter == orphaned_dev_tools_.end())
- return;
+ case NotificationType::EXTENSION_PROCESS_TERMINATED: {
+ if (profile_ != Source<Profile>(source).ptr()->GetOriginalProfile())
+ break;
- DevToolsManager::GetInstance()->AttachClientHost(
- iter->second, host->render_view_host());
- orphaned_dev_tools_.erase(iter);
- break;
- }
+ ExtensionHost* host = Details<ExtensionHost>(details).ptr();
- case NotificationType::EXTENSION_PROCESS_TERMINATED: {
- DCHECK_EQ(profile_, Source<Profile>(source).ptr());
+ // TODO(rafaelw): Remove this check and ExtensionHost::recently_deleted().
+ // This is only here to help track down crbug.com/49114.
+ ExtensionHost::HostPointerList::iterator iter =
+ ExtensionHost::recently_deleted()->begin();
+ for (; iter != ExtensionHost::recently_deleted()->end(); iter++) {
+ if (*iter == host) {
+ CHECK(host->GetURL().spec().size() + 2 != 0);
+ break;
+ }
+ }
+ if (iter == ExtensionHost::recently_deleted()->end())
+ CHECK(host->GetURL().spec().size() + 1 != 0);
// 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.
- UnloadExtension(Details<ExtensionHost>(details).ptr()->extension()->id());
+ // 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();
+ DCHECK(*pref_name == prefs::kExtensionInstallAllowList ||
+ *pref_name == prefs::kExtensionInstallDenyList);
+ CheckAdminBlacklist();
break;
}
@@ -1183,190 +1806,3 @@ bool ExtensionsService::HasApps() {
return false;
}
-
-// ExtensionsServicesBackend
-
-ExtensionsServiceBackend::ExtensionsServiceBackend(
- const FilePath& install_directory)
- : frontend_(NULL),
- install_directory_(install_directory),
- alert_on_error_(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_[Extension::EXTERNAL_PREF] =
- linked_ptr<ExternalExtensionProvider>(
- new ExternalPrefExtensionProvider());
-#if defined(OS_WIN)
- external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
- linked_ptr<ExternalExtensionProvider>(
- new ExternalRegistryExtensionProvider());
-#endif
-}
-
-ExtensionsServiceBackend::~ExtensionsServiceBackend() {
-}
-
-void ExtensionsServiceBackend::LoadSingleExtension(
- const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
- frontend_ = frontend;
-
- // Explicit UI loads are always noisy.
- alert_on_error_ = true;
-
- FilePath extension_path = path_in;
- file_util::AbsolutePath(&extension_path);
-
- LOG(INFO) << "Loading single extension from " <<
- extension_path.BaseName().value();
-
- std::string error;
- Extension* extension = extension_file_util::LoadExtension(
- extension_path,
- false, // Don't require id
- &error);
-
- if (!extension) {
- ReportExtensionLoadError(extension_path, error);
- return;
- }
-
- extension->set_location(Extension::LOAD);
-
- // Report this as an installed extension so that it gets remembered in the
- // prefs.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(frontend_, &ExtensionsService::OnExtensionInstalled,
- extension, true));
-}
-
-void ExtensionsServiceBackend::ReportExtensionLoadError(
- const FilePath& extension_path, const std::string &error) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_,
- &ExtensionsService::ReportExtensionLoadError, extension_path,
- error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
-}
-
-bool ExtensionsServiceBackend::LookupExternalExtension(
- const std::string& id, Version** version, Extension::Location* location) {
- scoped_ptr<Version> extension_version;
- for (ProviderMap::const_iterator i = external_extension_providers_.begin();
- i != external_extension_providers_.end(); ++i) {
- const ExternalExtensionProvider* provider = i->second.get();
- extension_version.reset(provider->RegisteredVersion(id, location));
- if (extension_version.get()) {
- if (version)
- *version = extension_version.release();
- return true;
- }
- }
- return false;
-}
-
-// 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(
- std::set<std::string> ids_to_ignore,
- scoped_refptr<ExtensionsService> frontend) {
- // 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;
-
- // Ask each external extension provider to give us a call back for each
- // extension they know about. See OnExternalExtensionFound.
- for (ProviderMap::const_iterator i = external_extension_providers_.begin();
- i != external_extension_providers_.end(); ++i) {
- ExternalExtensionProvider* provider = i->second.get();
- provider->VisitRegisteredExtension(this, ids_to_ignore);
- }
-}
-
-void ExtensionsServiceBackend::CheckExternalUninstall(
- scoped_refptr<ExtensionsService> frontend, const std::string& id,
- Extension::Location location) {
- // Check if the providers know about this extension.
- ProviderMap::const_iterator i = external_extension_providers_.find(location);
- if (i == external_extension_providers_.end()) {
- NOTREACHED() << "CheckExternalUninstall called for non-external extension "
- << location;
- return;
- }
-
- scoped_ptr<Version> version;
- version.reset(i->second->RegisteredVersion(id, NULL));
- if (version.get())
- return; // Yup, known extension, don't uninstall.
-
- // This is an external extension that we don't have registered. Uninstall.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend.get(), &ExtensionsService::UninstallExtension, id, true));
-}
-
-void ExtensionsServiceBackend::ClearProvidersForTesting() {
- external_extension_providers_.clear();
-}
-
-void ExtensionsServiceBackend::SetProviderForTesting(
- Extension::Location location,
- ExternalExtensionProvider* test_provider) {
- DCHECK(test_provider);
- external_extension_providers_[location] =
- linked_ptr<ExternalExtensionProvider>(test_provider);
-}
-
-void ExtensionsServiceBackend::OnExternalExtensionFound(
- const std::string& id, const Version* version, const FilePath& path,
- Extension::Location location) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_, &ExtensionsService::OnExternalExtensionFound, id,
- version->GetString(), path, location));
-}
-
-void ExtensionsServiceBackend::ReloadExtensionManifests(
- ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
- base::TimeTicks start_time,
- scoped_refptr<ExtensionsService> frontend) {
- frontend_ = frontend;
-
- for (size_t i = 0; i < extensions_to_reload->size(); ++i) {
- ExtensionInfo* info = extensions_to_reload->at(i).get();
- if (!ShouldReloadExtensionManifest(*info))
- continue;
-
- // We need to reload original manifest in order to localize properly.
- std::string error;
- scoped_ptr<Extension> extension(extension_file_util::LoadExtension(
- info->extension_path, false, &error));
-
- if (extension.get())
- extensions_to_reload->at(i)->extension_manifest.reset(
- static_cast<DictionaryValue*>(
- extension->manifest_value()->DeepCopy()));
- }
-
- // Finish installing on UI thread.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_,
- &ExtensionsService::ContinueLoadAllExtensions,
- extensions_to_reload,
- start_time,
- true));
-}
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index 8c779cd..7d5ad97 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_
+#pragma once
#include <map>
#include <set>
@@ -18,7 +19,6 @@
#include "base/task.h"
#include "base/time.h"
#include "base/tuple.h"
-#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_icon_manager.h"
#include "chrome/browser/extensions/extension_menu_manager.h"
@@ -28,19 +28,17 @@
#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"
-class Browser;
class ExtensionsServiceBackend;
class ExtensionToolbarModel;
class ExtensionUpdater;
class GURL;
class PrefService;
class Profile;
-class ResourceDispatcherHost;
-class SiteInstance;
class Version;
// A pending extension is an extension that hasn't been installed yet
@@ -48,8 +46,18 @@ class Version;
// 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.
+ THEME,
+ EXTENSION
+ };
+
PendingExtensionInfo(const GURL& update_url,
- bool is_theme,
+ ExpectedCrxType expected_crx_type,
+ bool is_from_sync,
bool install_silently,
bool enable_on_install,
bool enable_incognito_on_install);
@@ -57,7 +65,8 @@ struct PendingExtensionInfo {
PendingExtensionInfo();
GURL update_url;
- bool is_theme;
+ 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;
@@ -80,6 +89,7 @@ class ExtensionUpdateService {
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;
@@ -118,9 +128,6 @@ class ExtensionsService
// The name of the file that the current active version number is stored in.
static const char* kCurrentVersionFileName;
- // Determine if the given url is an instance of a gallery download url.
- static bool IsGalleryDownloadURL(const GURL& download_url);
-
// Determine if a given extension download should be treated as if it came
// from the gallery. Note that this is different from IsGalleryDownloadURL
// (above) in that in requires *both* that the download_url match and
@@ -134,7 +141,6 @@ class ExtensionsService
ExtensionsService(Profile* profile,
const CommandLine* command_line,
- PrefService* prefs,
const FilePath& install_directory,
bool autoupdate_enabled);
@@ -211,10 +217,16 @@ class ExtensionsService
//
// TODO(akalin): Replace |install_silently| with a list of
// pre-enabled permissions.
- void AddPendingExtension(
+ void AddPendingExtensionFromSync(
const std::string& id, const GURL& update_url,
- bool is_theme, bool install_silently,
- bool enable_on_install, bool enable_incognito_on_install);
+ 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);
// Reloads the specified extension.
void ReloadExtension(const std::string& extension_id);
@@ -228,8 +240,8 @@ class ExtensionsService
void UninstallExtension(const std::string& extension_id,
bool external_uninstall);
- // Enable or disable an extension. The extension must be in the opposite state
- // before calling.
+ // 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);
@@ -276,9 +288,18 @@ class ExtensionsService
// extent, if one exists.
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();
@@ -299,16 +320,21 @@ class ExtensionsService
bool allow_privilege_increase);
// Called by the backend when an external extension is found.
- void OnExternalExtensionFound(const std::string& id,
- const std::string& version,
- const FilePath& path,
- Extension::Location location);
+ void OnExternalExtensionFileFound(const std::string& id,
+ const std::string& version,
+ const FilePath& path,
+ Extension::Location location);
// 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_; }
@@ -322,8 +348,9 @@ class ExtensionsService
Profile* profile() { return profile_; }
- // Profile calls this when it is destroyed so that we know not to call it.
- void ProfileDestroyed() { profile_ = NULL; }
+ // 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(); }
@@ -339,6 +366,10 @@ class ExtensionsService
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,
@@ -346,6 +377,10 @@ class ExtensionsService
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,
@@ -372,7 +407,8 @@ class ExtensionsService
// id is not already installed.
void AddPendingExtensionInternal(
const std::string& id, const GURL& update_url,
- bool is_theme, bool install_silently,
+ PendingExtensionInfo::ExpectedCrxType crx_type,
+ bool is_from_sync, bool install_silently,
bool enable_on_install, bool enable_incognito_on_install);
// Handles sending notification that |extension| was loaded.
@@ -385,7 +421,13 @@ class ExtensionsService
void UpdateActiveExtensionsInCrashReporter();
// Helper method. Loads extension from prefs.
- void LoadInstalledExtension(const ExtensionInfo& info, bool relocalize);
+ void LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs);
+
+ // Helper methods to configure the storage services accordingly.
+ void GrantProtectedStorage(Extension* extension);
+ void RevokeProtectedStorage(Extension* extension);
+ void GrantUnlimitedStorage(Extension* extension);
+ void RevokeUnlimitedStorage(Extension* extension);
// The profile this ExtensionsService is part of.
Profile* profile_;
@@ -432,130 +474,50 @@ class ExtensionsService
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_;
+
FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest,
UpdatePendingExtensionAlreadyInstalled);
-
+ FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest,
+ InstallAppsWithUnlimtedStorage);
+ FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest,
+ InstallAppsAndCheckStorageProtection);
DISALLOW_COPY_AND_ASSIGN(ExtensionsService);
};
-// Implements IO for the ExtensionsService.
-// TODO(aa): This can probably move into the .cc file.
-class ExtensionsServiceBackend
- : public base::RefCountedThreadSafe<ExtensionsServiceBackend>,
- public ExternalExtensionProvider::Visitor {
- public:
- // |rdh| can be NULL in the case of test environment.
- // |extension_prefs| contains a dictionary value that points to the extension
- // preferences.
- explicit ExtensionsServiceBackend(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(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,
- Extension::Location location);
-
- // Clear all ExternalExtensionProviders.
- void ClearProvidersForTesting();
-
- // Sets an ExternalExtensionProvider for the service to use during testing.
- // |location| specifies what type of provider should be added.
- void SetProviderForTesting(Extension::Location location,
- ExternalExtensionProvider* test_provider);
-
- // ExternalExtensionProvider::Visitor implementation.
- virtual void OnExternalExtensionFound(const std::string& id,
- const Version* version,
- const FilePath& path,
- Extension::Location location);
-
- // Reloads the given extensions from their manifests on disk (instead of what
- // we have cached in the prefs).
- void ReloadExtensionManifests(
- ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
- base::TimeTicks start_time,
- scoped_refptr<ExtensionsService> frontend);
-
- 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,
- 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);
-
- // Lookup an external extension by |id| by going through all registered
- // external extension providers until we find a provider that contains an
- // extension that matches. If |version| is not NULL, the extension version
- // will be returned (caller is responsible for deleting that pointer).
- // |location| can also be null, if not needed. Returns true if extension is
- // found, false otherwise.
- bool LookupExternalExtension(const std::string& id,
- Version** version,
- Extension::Location* location);
-
- // 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 map of all external extension providers.
- typedef std::map<Extension::Location,
- linked_ptr<ExternalExtensionProvider> > ProviderMap;
- ProviderMap external_extension_providers_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend);
-};
-
#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
index c209f59..9fddb71 100644
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_service_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.
@@ -14,10 +14,14 @@
#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/chrome_thread.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_creator.h"
@@ -25,14 +29,19 @@
#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/pref_value_store.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/chrome_paths.h"
-#include "chrome/common/chrome_switches.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"
@@ -40,12 +49,13 @@
#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"
-#include "net/base/cookie_monster.h"
-#include "net/base/cookie_options.h"
namespace keys = extension_manifest_keys;
@@ -115,7 +125,7 @@ class MockExtensionProvider : public ExternalExtensionProvider {
scoped_ptr<Version> version;
version.reset(Version::GetVersionFromString(i->second.first));
- visitor->OnExternalExtensionFound(
+ visitor->OnExternalExtensionFileFound(
i->first, version.get(), i->second.second, location_);
}
}
@@ -156,7 +166,7 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
Value* json_value = serializer.Deserialize(NULL, NULL);
if (!json_value || !json_value->IsType(Value::TYPE_DICTIONARY)) {
- NOTREACHED() << L"Unable to deserialize json data";
+ NOTREACHED() << "Unable to deserialize json data";
return -1;
} else {
DictionaryValue* external_extensions =
@@ -173,17 +183,17 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
return ids_found_;
}
- virtual void OnExternalExtensionFound(const std::string& id,
- const Version* version,
- const FilePath& path,
- Extension::Location unused) {
+ 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(ASCIIToWide(id), &pref))
- << L"Got back ID (" << id.c_str() << ") we weren't expecting";
+ EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
+ << "Got back ID (" << id.c_str() << ") we weren't expecting";
if (pref) {
// Ask provider if the extension we got back is registered.
@@ -195,7 +205,23 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
EXPECT_EQ(Extension::EXTERNAL_PREF, location);
// Remove it so we won't count it ever again.
- prefs_->Remove(ASCIIToWide(id), NULL);
+ prefs_->Remove(id, NULL);
+ }
+ }
+
+ virtual void OnExternalExtensionUpdateUrlFound(const std::string& id,
+ const GURL& update_url) {
+ ++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";
+
+ if (pref) {
+ // Remove it so we won't count it again.
+ prefs_->Remove(id, NULL);
}
}
@@ -210,7 +236,7 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
class ExtensionTestingProfile : public TestingProfile {
public:
- ExtensionTestingProfile() {
+ ExtensionTestingProfile() : service_(NULL) {
}
void set_extensions_service(ExtensionsService* service) {
@@ -218,14 +244,30 @@ class ExtensionTestingProfile : public TestingProfile {
}
virtual ExtensionsService* GetExtensionsService() { return service_; }
+ virtual ChromeAppCacheService* GetAppCacheService() {
+ if (!appcache_service_) {
+ appcache_service_ = new ChromeAppCacheService;
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(appcache_service_.get(),
+ &ChromeAppCacheService::InitializeOnIOThread,
+ GetPath(), IsOffTheRecord(),
+ make_scoped_refptr(GetHostContentSettingsMap())));
+ }
+ return appcache_service_;
+ }
+
private:
ExtensionsService* service_;
+ scoped_refptr<ChromeAppCacheService> appcache_service_;
};
// Our message loop may be used in tests which require it to be an IO loop.
ExtensionsServiceTestBase::ExtensionsServiceTestBase()
- : loop_(MessageLoop::TYPE_IO),
+ : total_successes_(0),
+ loop_(MessageLoop::TYPE_IO),
ui_thread_(ChromeThread::UI, &loop_),
+ db_thread_(ChromeThread::DB, &loop_),
webkit_thread_(ChromeThread::WEBKIT, &loop_),
file_thread_(ChromeThread::FILE, &loop_),
io_thread_(ChromeThread::IO, &loop_) {
@@ -242,27 +284,25 @@ ExtensionsServiceTestBase::~ExtensionsServiceTestBase() {
void ExtensionsServiceTestBase::InitializeExtensionsService(
const FilePath& pref_file, const FilePath& extensions_install_dir) {
- // Must setup the commandline here, since Extension caches the switch value
- // when the prefs are registered.
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableExtensionToolstrips);
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableApps);
-
ExtensionTestingProfile* profile = new ExtensionTestingProfile();
// Create a preference service that only contains user defined
// preference values.
- prefs_.reset(PrefService::CreateUserPrefService(pref_file));
+ PrefService* prefs = PrefService::CreateUserPrefService(pref_file);
+ Profile::RegisterUserPrefs(prefs);
+ browser::RegisterUserPrefs(prefs);
+ profile->SetPrefService(prefs);
- Profile::RegisterUserPrefs(prefs_.get());
- browser::RegisterUserPrefs(prefs_.get());
profile_.reset(profile);
- service_ = new ExtensionsService(profile_.get(),
- CommandLine::ForCurrentProcess(),
- prefs_.get(),
- extensions_install_dir,
- false);
+ // TODO(scherkus): Remove this when we no longer need to have Talk
+ // component extension state as a preference http://crbug.com/56429
+ DictionaryValue* dict =
+ profile->GetPrefs()->GetMutableDictionary("extensions.settings");
+ dict->Remove("ggnioahjipcehijkhpdjekioddnjoben", NULL);
+
+ 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());
@@ -483,26 +523,27 @@ class ExtensionsServiceTest
void ValidatePrefKeyCount(size_t count) {
DictionaryValue* dict =
- prefs_->GetMutableDictionary(L"extensions.settings");
+ profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
ASSERT_TRUE(dict != NULL);
EXPECT_EQ(count, dict->size());
}
void ValidateBooleanPref(const std::string& extension_id,
- const std::wstring& pref_path,
+ const std::string& pref_path,
bool expected_val) {
- std::wstring msg = L" while checking: ";
- msg += ASCIIToWide(extension_id);
- msg += L" ";
+ std::string msg = " while checking: ";
+ msg += extension_id;
+ msg += " ";
msg += pref_path;
- msg += L" == ";
- msg += expected_val ? L"true" : L"false";
+ msg += " == ";
+ msg += expected_val ? "true" : "false";
+ PrefService* prefs = profile_->GetPrefs();
const DictionaryValue* dict =
- prefs_->GetDictionary(L"extensions.settings");
+ prefs->GetDictionary("extensions.settings");
ASSERT_TRUE(dict != NULL) << msg;
DictionaryValue* pref = NULL;
- ASSERT_TRUE(dict->GetDictionary(ASCIIToWide(extension_id), &pref)) << msg;
+ ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
EXPECT_TRUE(pref != NULL) << msg;
bool val;
ASSERT_TRUE(pref->GetBoolean(pref_path, &val)) << msg;
@@ -510,12 +551,12 @@ class ExtensionsServiceTest
}
bool IsPrefExist(const std::string& extension_id,
- const std::wstring& pref_path) {
+ const std::string& pref_path) {
const DictionaryValue* dict =
- prefs_->GetDictionary(L"extensions.settings");
+ profile_->GetPrefs()->GetDictionary("extensions.settings");
if (dict == NULL) return false;
DictionaryValue* pref = NULL;
- if (!dict->GetDictionary(ASCIIToWide(extension_id), &pref)) {
+ if (!dict->GetDictionary(extension_id, &pref)) {
return false;
}
if (pref == NULL) {
@@ -529,20 +570,21 @@ class ExtensionsServiceTest
}
void ValidateIntegerPref(const std::string& extension_id,
- const std::wstring& pref_path,
+ const std::string& pref_path,
int expected_val) {
- std::wstring msg = L" while checking: ";
- msg += ASCIIToWide(extension_id);
- msg += L" ";
+ std::string msg = " while checking: ";
+ msg += extension_id;
+ msg += " ";
msg += pref_path;
- msg += L" == ";
- msg += IntToWString(expected_val);
+ msg += " == ";
+ msg += base::IntToString(expected_val);
+ PrefService* prefs = profile_->GetPrefs();
const DictionaryValue* dict =
- prefs_->GetDictionary(L"extensions.settings");
+ prefs->GetDictionary("extensions.settings");
ASSERT_TRUE(dict != NULL) << msg;
DictionaryValue* pref = NULL;
- ASSERT_TRUE(dict->GetDictionary(ASCIIToWide(extension_id), &pref)) << msg;
+ ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
EXPECT_TRUE(pref != NULL) << msg;
int val;
ASSERT_TRUE(pref->GetInteger(pref_path, &val)) << msg;
@@ -550,21 +592,21 @@ class ExtensionsServiceTest
}
void ValidateStringPref(const std::string& extension_id,
- const std::wstring& pref_path,
+ const std::string& pref_path,
const std::string& expected_val) {
- std::wstring msg = L" while checking: ";
- msg += ASCIIToWide(extension_id);
- msg += L".manifest.";
+ std::string msg = " while checking: ";
+ msg += extension_id;
+ msg += ".manifest.";
msg += pref_path;
- msg += L" == ";
- msg += ASCIIToWide(expected_val);
+ msg += " == ";
+ msg += expected_val;
const DictionaryValue* dict =
- prefs_->GetDictionary(L"extensions.settings");
+ profile_->GetPrefs()->GetDictionary("extensions.settings");
ASSERT_TRUE(dict != NULL) << msg;
DictionaryValue* pref = NULL;
std::string manifest_path = extension_id + ".manifest";
- ASSERT_TRUE(dict->GetDictionary(ASCIIToWide(manifest_path), &pref)) << msg;
+ ASSERT_TRUE(dict->GetDictionary(manifest_path, &pref)) << msg;
EXPECT_TRUE(pref != NULL) << msg;
std::string val;
ASSERT_TRUE(pref->GetString(pref_path, &val)) << msg;
@@ -572,20 +614,20 @@ class ExtensionsServiceTest
}
void SetPrefInteg(const std::string& extension_id,
- const std::wstring& pref_path,
+ const std::string& pref_path,
int value) {
- std::wstring msg = L" while setting: ";
- msg += ASCIIToWide(extension_id);
- msg += L" ";
+ std::string msg = " while setting: ";
+ msg += extension_id;
+ msg += " ";
msg += pref_path;
- msg += L" = ";
- msg += IntToWString(value);
+ msg += " = ";
+ msg += base::IntToString(value);
const DictionaryValue* dict =
- prefs_->GetMutableDictionary(L"extensions.settings");
+ profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
ASSERT_TRUE(dict != NULL) << msg;
DictionaryValue* pref = NULL;
- ASSERT_TRUE(dict->GetDictionary(ASCIIToWide(extension_id), &pref)) << msg;
+ ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
EXPECT_TRUE(pref != NULL) << msg;
pref->SetInteger(pref_path, value);
}
@@ -599,16 +641,56 @@ class ExtensionsServiceTest
NotificationRegistrar registrar_;
};
-FilePath::StringType NormalizeSeperators(FilePath::StringType path) {
+FilePath NormalizeSeparators(const FilePath& path) {
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
- FilePath::StringType ret_val;
- for (size_t i = 0; i < path.length(); i++) {
- if (FilePath::IsSeparator(path[i]))
- path[i] = FilePath::kSeparators[0];
- }
-#endif // 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.
@@ -626,7 +708,13 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
service_->Init();
loop_.RunAllPending();
- ASSERT_EQ(3u, loaded_.size());
+ // 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"),
@@ -635,20 +723,18 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
loaded_[0]->description());
EXPECT_EQ(Extension::INTERNAL, loaded_[0]->location());
EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false));
- EXPECT_EQ(3u, service_->extensions()->size());
+ EXPECT_EQ(expected_num_extensions, service_->extensions()->size());
ValidatePrefKeyCount(3);
- ValidateIntegerPref(good0, L"state", Extension::ENABLED);
- ValidateIntegerPref(good0, L"location", Extension::INTERNAL);
- ValidateIntegerPref(good1, L"state", Extension::ENABLED);
- ValidateIntegerPref(good1, L"location", Extension::INTERNAL);
- ValidateIntegerPref(good2, L"state", Extension::ENABLED);
- ValidateIntegerPref(good2, L"location", Extension::INTERNAL);
+ 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);
Extension* extension = loaded_[0];
const UserScriptList& scripts = extension->content_scripts();
- const std::vector<Extension::ToolstripInfo>& toolstrips =
- extension->toolstrips();
ASSERT_EQ(2u, scripts.size());
EXPECT_EQ(3u, scripts[0].url_patterns().size());
EXPECT_EQ("file://*",
@@ -684,15 +770,8 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
ASSERT_EQ(2u, permissions.size());
EXPECT_EQ("http://*.google.com/*", permissions[0].GetAsString());
EXPECT_EQ("https://*.google.com/*", permissions[1].GetAsString());
- ASSERT_EQ(2u, toolstrips.size());
- EXPECT_EQ(extension->GetResourceURL("toolstrip1.html"),
- toolstrips[0].toolstrip);
- EXPECT_EQ(extension->GetResourceURL("lorem_ipsum.html"),
- toolstrips[0].mole);
- EXPECT_EQ(200, toolstrips[0].mole_height);
- EXPECT_EQ(extension->GetResourceURL("toolstrip2.html"),
- toolstrips[1].toolstrip);
+#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());
@@ -707,12 +786,14 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
loaded_[1]->plugins()[1].path.value());
EXPECT_FALSE(loaded_[1]->plugins()[1].is_public);
EXPECT_EQ(Extension::INTERNAL, loaded_[1]->location());
+#endif
- EXPECT_EQ(std::string(good2), loaded_[2]->id());
- EXPECT_EQ(std::string("My extension 3"), loaded_[2]->name());
- EXPECT_EQ(std::string(""), loaded_[2]->description());
- EXPECT_EQ(0u, loaded_[2]->content_scripts().size());
- EXPECT_EQ(Extension::INTERNAL, loaded_[2]->location());
+ 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.
@@ -736,19 +817,19 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) {
ASSERT_EQ(4u, GetErrors().size());
ASSERT_EQ(0u, loaded_.size());
- EXPECT_TRUE(MatchPatternASCII(GetErrors()[0],
+ EXPECT_TRUE(MatchPattern(GetErrors()[0],
std::string("Could not load extension from '*'. ") +
extension_manifest_errors::kManifestUnreadable)) << GetErrors()[0];
- EXPECT_TRUE(MatchPatternASCII(GetErrors()[1],
+ EXPECT_TRUE(MatchPattern(GetErrors()[1],
std::string("Could not load extension from '*'. ") +
extension_manifest_errors::kManifestUnreadable)) << GetErrors()[1];
- EXPECT_TRUE(MatchPatternASCII(GetErrors()[2],
+ EXPECT_TRUE(MatchPattern(GetErrors()[2],
std::string("Could not load extension from '*'. ") +
extension_manifest_errors::kMissingFile)) << GetErrors()[2];
- EXPECT_TRUE(MatchPatternASCII(GetErrors()[3],
+ EXPECT_TRUE(MatchPattern(GetErrors()[3],
std::string("Could not load extension from '*'. ") +
extension_manifest_errors::kManifestUnreadable)) << GetErrors()[3];
};
@@ -769,9 +850,10 @@ TEST_F(ExtensionsServiceTest, CleanupOnStartup) {
InitializeInstalledExtensionsService(pref_path, source_install_dir);
// Simulate that one of them got partially deleted by clearing its pref.
- DictionaryValue* dict = prefs_->GetMutableDictionary(L"extensions.settings");
+ DictionaryValue* dict =
+ profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
ASSERT_TRUE(dict != NULL);
- dict->Remove(L"behllobkkfkfnphdnhnkndlbkcpglgmj", NULL);
+ dict->Remove("behllobkkfkfnphdnhnkndlbkcpglgmj", NULL);
service_->Init();
loop_.RunAllPending();
@@ -816,15 +898,15 @@ TEST_F(ExtensionsServiceTest, InstallExtension) {
int pref_count = 0;
ValidatePrefKeyCount(++pref_count);
- ValidateIntegerPref(good_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", Extension::INTERNAL);
+ 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, L"state", Extension::ENABLED);
- ValidateIntegerPref(page_action, L"location", Extension::INTERNAL);
+ ValidateIntegerPref(page_action, "state", Extension::ENABLED);
+ ValidateIntegerPref(page_action, "location", Extension::INTERNAL);
// Bad signature.
path = extensions_path.AppendASCII("bad_signature.crx");
@@ -841,7 +923,7 @@ TEST_F(ExtensionsServiceTest, InstallExtension) {
InstallExtension(path, false);
ValidatePrefKeyCount(pref_count);
- // Extensions cannot have folders or files that have underscores except ofr in
+ // 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.
@@ -935,6 +1017,80 @@ TEST_F(ExtensionsServiceTest, PackExtension) {
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
@@ -979,8 +1135,8 @@ TEST_F(ExtensionsServiceTest, InstallTheme) {
InstallExtension(path, true);
int pref_count = 0;
ValidatePrefKeyCount(++pref_count);
- ValidateIntegerPref(theme_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(theme_crx, L"location", Extension::INTERNAL);
+ 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.
@@ -988,8 +1144,8 @@ TEST_F(ExtensionsServiceTest, InstallTheme) {
path = extensions_path.AppendASCII("theme2.crx");
InstallExtension(path, true);
ValidatePrefKeyCount(++pref_count);
- ValidateIntegerPref(theme2_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(theme2_crx, L"location", Extension::INTERNAL);
+ 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.
@@ -1050,8 +1206,8 @@ TEST_F(ExtensionsServiceTest, InstallApps) {
ValidatePrefKeyCount(++pref_count);
ASSERT_EQ(1u, service_->extensions()->size());
std::string id = service_->extensions()->at(0)->id();
- ValidateIntegerPref(id, L"state", Extension::ENABLED);
- ValidateIntegerPref(id, L"location", Extension::INTERNAL);
+ ValidateIntegerPref(id, "state", Extension::ENABLED);
+ ValidateIntegerPref(id, "location", Extension::INTERNAL);
// Another app with non-overlapping extent. Should succeed.
PackAndInstallExtension(extensions_path.AppendASCII("app2"), true);
@@ -1063,6 +1219,109 @@ TEST_F(ExtensionsServiceTest, InstallApps) {
// 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());
+ 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());
+ 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();
@@ -1079,8 +1338,8 @@ TEST_F(ExtensionsServiceTest, Reinstall) {
ASSERT_EQ(1u, loaded_.size());
ASSERT_EQ(0u, GetErrors().size());
ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", Extension::INTERNAL);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
installed_ = NULL;
loaded_.clear();
@@ -1094,8 +1353,8 @@ TEST_F(ExtensionsServiceTest, Reinstall) {
ASSERT_EQ(1u, loaded_.size());
ASSERT_EQ(0u, GetErrors().size());
ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", Extension::INTERNAL);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
}
// Test upgrading a signed extension.
@@ -1222,32 +1481,64 @@ TEST_F(ExtensionsServiceTest, UpdateToSameVersionIsNoop) {
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);
+ 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());
+ Extension* good2 = service_->disabled_extensions()->at(0);
+ ASSERT_EQ("1.0.0.1", good2->version()->GetString());
+ EXPECT_TRUE(service_->IsIncognitoEnabled(good2));
+}
+
// Test adding a pending extension.
TEST_F(ExtensionsServiceTest, AddPendingExtension) {
InitializeEmptyExtensionsService();
const std::string kFakeId("fake-id");
const GURL kFakeUpdateURL("http:://fake.update/url");
- const bool kFakeIsTheme(false);
+ const PendingExtensionInfo::ExpectedCrxType kFakeExpectedCrxType =
+ PendingExtensionInfo::EXTENSION;
const bool kFakeInstallSilently(true);
const Extension::State kFakeInitialState(Extension::ENABLED);
const bool kFakeInitialIncognitoEnabled(false);
- service_->AddPendingExtension(
- kFakeId, kFakeUpdateURL, kFakeIsTheme, kFakeInstallSilently,
+ 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(kFakeIsTheme, it->second.is_theme);
+ 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 bool kGoodIsTheme = false;
+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;
@@ -1256,8 +1547,8 @@ const bool kGoodInitialIncognitoEnabled = true;
// Test updating a pending extension.
TEST_F(ExtensionsServiceTest, UpdatePendingExtension) {
InitializeEmptyExtensionsService();
- service_->AddPendingExtension(
- kGoodId, GURL(kGoodUpdateURL), kGoodIsTheme,
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension,
kGoodInstallSilently, kGoodInitialState,
kGoodInitialIncognitoEnabled);
EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
@@ -1284,8 +1575,34 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtension) {
// Test updating a pending theme.
TEST_F(ExtensionsServiceTest, UpdatePendingTheme) {
InitializeEmptyExtensionsService();
- service_->AddPendingExtension(
- theme_crx, GURL(), true, false, Extension::ENABLED, false);
+ 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));
+
+ 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());
+
EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
FilePath extensions_path;
@@ -1304,6 +1621,29 @@ TEST_F(ExtensionsServiceTest, UpdatePendingTheme) {
EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
}
+// 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));
+
+ 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().
@@ -1312,9 +1652,9 @@ TEST_F(ExtensionsServiceTest, UpdatePendingTheme) {
TEST_F(ExtensionsServiceTest, UpdatePendingExtensionWrongIsTheme) {
InitializeEmptyExtensionsService();
// Add pending extension with a flipped is_theme.
- service_->AddPendingExtension(
- kGoodId, GURL(kGoodUpdateURL), !kGoodIsTheme,
- kGoodInstallSilently, kGoodInitialState,
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL),
+ kCrxTypeTheme, kGoodInstallSilently, kGoodInitialState,
kGoodInitialIncognitoEnabled);
EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
@@ -1359,13 +1699,15 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled) {
ASSERT_EQ(1u, service_->extensions()->size());
Extension* good = service_->extensions()->at(0);
+ EXPECT_FALSE(good->is_theme());
+
// Use AddPendingExtensionInternal() as AddPendingExtension() would
// balk.
service_->AddPendingExtensionInternal(
- good->id(), good->update_url(), good->is_theme(),
- kGoodInstallSilently, kGoodInitialState,
+ good->id(), good->update_url(),
+ PendingExtensionInfo::EXTENSION,
+ kGoodIsFromSync, kGoodInstallSilently, kGoodInitialState,
kGoodInitialIncognitoEnabled);
-
UpdateExtension(good->id(), path, INSTALLED);
EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
@@ -1383,10 +1725,10 @@ TEST_F(ExtensionsServiceTest, SetUnsetBlacklistInPrefs) {
loop_.RunAllPending();
// blacklist is set for good0,1,2
- ValidateBooleanPref(good0, L"blacklist", true);
- ValidateBooleanPref(good1, L"blacklist", true);
+ ValidateBooleanPref(good0, "blacklist", true);
+ ValidateBooleanPref(good1, "blacklist", true);
// invalid_id should not be inserted to pref.
- EXPECT_FALSE(IsPrefExist("invalid_id", L"blacklist"));
+ EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
// remove good1, add good2
blacklist.pop_back();
@@ -1394,10 +1736,10 @@ TEST_F(ExtensionsServiceTest, SetUnsetBlacklistInPrefs) {
service_->UpdateExtensionBlacklist(blacklist);
// only good0 and good1 should be set
- ValidateBooleanPref(good0, L"blacklist", true);
- EXPECT_FALSE(IsPrefExist(good1, L"blacklist"));
- ValidateBooleanPref(good2, L"blacklist", true);
- EXPECT_FALSE(IsPrefExist("invalid_id", L"blacklist"));
+ ValidateBooleanPref(good0, "blacklist", true);
+ EXPECT_FALSE(IsPrefExist(good1, "blacklist"));
+ ValidateBooleanPref(good2, "blacklist", true);
+ EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
}
// Unload installed extension from blacklist.
@@ -1421,7 +1763,7 @@ TEST_F(ExtensionsServiceTest, UnloadBlacklistedExtension) {
loop_.RunAllPending();
// Now, the good_crx is blacklisted.
- ValidateBooleanPref(good_crx, L"blacklist", true);
+ ValidateBooleanPref(good_crx, "blacklist", true);
EXPECT_EQ(0u, service_->extensions()->size());
// Remove good_crx from blacklist
@@ -1430,7 +1772,7 @@ TEST_F(ExtensionsServiceTest, UnloadBlacklistedExtension) {
// Make sure pref is updated
loop_.RunAllPending();
// blacklist value should not be set for good_crx
- EXPECT_FALSE(IsPrefExist(good_crx, L"blacklist"));
+ EXPECT_FALSE(IsPrefExist(good_crx, "blacklist"));
}
// Unload installed extension from blacklist.
@@ -1443,7 +1785,7 @@ TEST_F(ExtensionsServiceTest, BlacklistedExtensionWillNotInstall) {
loop_.RunAllPending();
// Now, the good_crx is blacklisted.
- ValidateBooleanPref(good_crx, L"blacklist", true);
+ ValidateBooleanPref(good_crx, "blacklist", true);
// We can not install good_crx.
FilePath extensions_path;
@@ -1453,7 +1795,7 @@ TEST_F(ExtensionsServiceTest, BlacklistedExtensionWillNotInstall) {
service_->InstallExtension(path);
loop_.RunAllPending();
EXPECT_EQ(0u, service_->extensions()->size());
- ValidateBooleanPref(good_crx, L"blacklist", true);
+ ValidateBooleanPref(good_crx, "blacklist", true);
}
// Test loading extensions from the profile directory, except
@@ -1471,14 +1813,14 @@ TEST_F(ExtensionsServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) {
.AppendASCII("Preferences");
InitializeInstalledExtensionsService(pref_path, source_install_dir);
- // Blacklist good0.
+ // Blacklist good1.
std::vector<std::string> blacklist;
- blacklist.push_back(good0);
+ blacklist.push_back(good1);
service_->UpdateExtensionBlacklist(blacklist);
// Make sure pref is updated
loop_.RunAllPending();
- ValidateBooleanPref(good0, L"blacklist", true);
+ ValidateBooleanPref(good1, "blacklist", true);
// Load extensions.
service_->Init();
@@ -1491,8 +1833,103 @@ TEST_F(ExtensionsServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) {
}
ASSERT_EQ(2u, loaded_.size());
- EXPECT_NE(std::string(good0), loaded_[0]->id());
- EXPECT_NE(std::string(good0), loaded_[1]->id());
+ 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
@@ -1576,8 +2013,8 @@ TEST_F(ExtensionsServiceTest, UninstallExtension) {
EXPECT_TRUE(file_util::PathExists(extension_path));
ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", Extension::INTERNAL);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
// Uninstall it.
service_->UninstallExtension(extension_id, false);
@@ -1758,8 +2195,8 @@ void ExtensionsServiceTest::TestExternalProvider(
ASSERT_EQ(location, loaded_[0]->location());
ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", location);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", location);
// Reload extensions without changing anything. The extension should be
// loaded again.
@@ -1769,8 +2206,8 @@ void ExtensionsServiceTest::TestExternalProvider(
ASSERT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", location);
+ 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");
@@ -1783,8 +2220,8 @@ void ExtensionsServiceTest::TestExternalProvider(
ASSERT_EQ(1u, loaded_.size());
ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", location);
+ 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.
@@ -1801,20 +2238,20 @@ void ExtensionsServiceTest::TestExternalProvider(
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, L"state", Extension::KILLBIT);
- ValidateIntegerPref(good_crx, L"location", location);
+ ValidateIntegerPref(good_crx, "state", Extension::KILLBIT);
+ ValidateIntegerPref(good_crx, "location", location);
// Now clear the preference and reinstall.
- SetPrefInteg(good_crx, L"state", Extension::ENABLED);
- prefs_->ScheduleSavePersistentPrefs();
+ 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, L"state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, L"location", location);
+ 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).
@@ -1884,49 +2321,86 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
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);
+
+ // Now add providers. Extension system takes ownership of the objects.
+ MockExtensionProvider* pref_provider =
+ new MockExtensionProvider(Extension::EXTERNAL_PREF_DOWNLOAD);
+ SetMockExternalProvider(Extension::EXTERNAL_PREF_DOWNLOAD, pref_provider);
+ TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF_DOWNLOAD);
+}
+
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\""
- "}"
+ " \"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(2, visitor.Visit(json_data, ignore_list));
+ EXPECT_EQ(3, visitor.Visit(json_data, ignore_list));
ignore_list.insert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
- EXPECT_EQ(1, visitor.Visit(json_data, ignore_list));
+ 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));
- // Use a json that contains three invalid extensions:
+ // 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.
- // - Plus one valid extension to make sure the json file is parsed properly.
+ // - 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 =
"{"
- "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
- "\"external_version\": \"1.0\""
- "},"
- "\"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {"
- "\"external_crx\": \"RandomExtension.crx\""
- "},"
- "\"cccccccccccccccccccccccccccccccc\": {"
- "\"external_crx\": \"..\\\\foo\\\\RandomExtension2.crx\","
- "\"external_version\": \"2.0\""
- "},"
- "\"dddddddddddddddddddddddddddddddddd\": {"
- "\"external_crx\": \"RandomValidExtension.crx\","
- "\"external_version\": \"1.0\""
- "}"
+ " \"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));
@@ -1998,19 +2472,19 @@ class ExtensionsReadyRecorder : public NotificationObserver {
// enabled or not.
TEST(ExtensionsServiceTestSimple, Enabledness) {
ExtensionsReadyRecorder recorder;
- TestingProfile profile;
+ scoped_ptr<TestingProfile> profile(new TestingProfile());
MessageLoop loop;
ChromeThread ui_thread(ChromeThread::UI, &loop);
ChromeThread file_thread(ChromeThread::FILE, &loop);
scoped_ptr<CommandLine> command_line;
scoped_refptr<ExtensionsService> service;
- FilePath install_dir = profile.GetPath()
+ FilePath install_dir = profile->GetPath()
.AppendASCII(ExtensionsService::kInstallDirectoryName);
// By default, we are enabled.
command_line.reset(new CommandLine(CommandLine::ARGUMENTS_ONLY));
- service = new ExtensionsService(&profile, command_line.get(),
- profile.GetPrefs(), install_dir, false);
+ service = profile->CreateExtensionsService(command_line.get(),
+ install_dir);
EXPECT_TRUE(service->extensions_enabled());
service->Init();
loop.RunAllPending();
@@ -2018,27 +2492,31 @@ TEST(ExtensionsServiceTestSimple, Enabledness) {
// 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 = new ExtensionsService(&profile, command_line.get(),
- profile.GetPrefs(), install_dir, false);
+ 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.GetPrefs()->SetBoolean(prefs::kDisableExtensions, true);
- service = new ExtensionsService(&profile, command_line.get(),
- profile.GetPrefs(), install_dir, 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::ARGUMENTS_ONLY));
- service = new ExtensionsService(&profile, command_line.get(),
- profile.GetPrefs(), install_dir, false);
+ service = profile->CreateExtensionsService(command_line.get(),
+ install_dir);
EXPECT_FALSE(service->extensions_enabled());
service->Init();
loop.RunAllPending();
@@ -2056,36 +2534,52 @@ TEST_F(ExtensionsServiceTest, StorageQuota) {
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();
- EXPECT_EQ(2u, loaded_.size());
+ ASSERT_EQ(3u, loaded_.size());
EXPECT_TRUE(profile_.get());
EXPECT_FALSE(profile_->IsOffTheRecord());
- // Open a database in each origin to make the tracker aware
- // of the existance of these origins and to get their quotas.
+ // 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(profile_->GetDatabaseTracker()->GetDefaultQuota(), limited_quota);
EXPECT_EQ(kint64max, unlimited_quota);
}
diff --git a/chrome/browser/extensions/extensions_service_unittest.h b/chrome/browser/extensions/extensions_service_unittest.h
index fdb2ddd..fe298b4 100644
--- a/chrome/browser/extensions/extensions_service_unittest.h
+++ b/chrome/browser/extensions/extensions_service_unittest.h
@@ -4,6 +4,7 @@
#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"
@@ -37,13 +38,13 @@ class ExtensionsServiceTestBase : public testing::Test {
protected:
ScopedTempDir temp_dir_;
- scoped_ptr<PrefService> prefs_;
scoped_ptr<Profile> profile_;
FilePath extensions_install_dir_;
scoped_refptr<ExtensionsService> service_;
size_t total_successes_;
MessageLoop loop_;
ChromeThread ui_thread_;
+ ChromeThread db_thread_;
ChromeThread webkit_thread_;
ChromeThread file_thread_;
ChromeThread io_thread_;
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 24ca842..415a922 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -9,9 +9,13 @@
#include "base/base64.h"
#include "base/callback.h"
#include "base/file_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/thread.h"
+#include "base/version.h"
#include "chrome/browser/browser.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"
@@ -23,8 +27,8 @@
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/google_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/google/google_util.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_widget_host.h"
@@ -34,6 +38,7 @@
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/user_script.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/jstemplate_builder.h"
@@ -53,9 +58,9 @@
namespace {
-static bool ShouldShowExtension(Extension* extension) {
- // Don't show the themes since this page's UI isn't really useful for
- // themes.
+bool ShouldShowExtension(Extension* extension) {
+
+ // Don't show themes since this page's UI isn't really useful for themes.
if (extension->is_theme())
return false;
@@ -64,10 +69,18 @@ static bool ShouldShowExtension(Extension* extension) {
if (extension->location() == Extension::COMPONENT)
return false;
+ // Always show unpacked extensions and apps.
+ if (extension->location() == Extension::LOAD)
+ return true;
+
+ // Unless they are unpacked, never show hosted apps.
+ if (extension->is_hosted_app())
+ return false;
+
return true;
}
-}
+} // namespace
////////////////////////////////////////////////////////////////////////////////
//
@@ -82,74 +95,77 @@ ExtensionsUIHTMLSource::ExtensionsUIHTMLSource()
void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path,
bool is_off_the_record, int request_id) {
DictionaryValue localized_strings;
- localized_strings.SetString(L"title",
- l10n_util::GetString(IDS_EXTENSIONS_TITLE));
- localized_strings.SetString(L"devModeLink",
- l10n_util::GetString(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
- localized_strings.SetString(L"devModePrefix",
- l10n_util::GetString(IDS_EXTENSIONS_DEVELOPER_MODE_PREFIX));
- localized_strings.SetString(L"loadUnpackedButton",
- l10n_util::GetString(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
- localized_strings.SetString(L"packButton",
- l10n_util::GetString(IDS_EXTENSIONS_PACK_BUTTON));
- localized_strings.SetString(L"updateButton",
- l10n_util::GetString(IDS_EXTENSIONS_UPDATE_BUTTON));
- localized_strings.SetString(L"noExtensions",
- l10n_util::GetString(IDS_EXTENSIONS_NONE_INSTALLED));
- localized_strings.SetString(L"suggestGallery",
- l10n_util::GetStringF(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
- std::wstring(L"<a href='") +
- ASCIIToWide(google_util::AppendGoogleLocaleParam(
- GURL(Extension::ChromeStoreURL())).spec()) + L"'>",
- L"</a>"));
- localized_strings.SetString(L"getMoreExtensions",
- std::wstring(L"<a href='") +
- ASCIIToWide(google_util::AppendGoogleLocaleParam(
- GURL(Extension::ChromeStoreURL())).spec()) + L"'>" +
- l10n_util::GetString(IDS_GET_MORE_EXTENSIONS) +
- L"</a>");
- localized_strings.SetString(L"extensionDisabled",
- l10n_util::GetString(IDS_EXTENSIONS_DISABLED_EXTENSION));
- localized_strings.SetString(L"inDevelopment",
- l10n_util::GetString(IDS_EXTENSIONS_IN_DEVELOPMENT));
- localized_strings.SetString(L"extensionId",
- l10n_util::GetString(IDS_EXTENSIONS_ID));
- localized_strings.SetString(L"extensionVersion",
- l10n_util::GetString(IDS_EXTENSIONS_VERSION));
- localized_strings.SetString(L"inspectViews",
- l10n_util::GetString(IDS_EXTENSIONS_INSPECT_VIEWS));
- localized_strings.SetString(L"inspectPopupsInstructions",
- l10n_util::GetString(IDS_EXTENSIONS_INSPECT_POPUPS_INSTRUCTIONS));
- localized_strings.SetString(L"disable",
- l10n_util::GetString(IDS_EXTENSIONS_DISABLE));
- localized_strings.SetString(L"enable",
- l10n_util::GetString(IDS_EXTENSIONS_ENABLE));
- localized_strings.SetString(L"enableIncognito",
- l10n_util::GetString(IDS_EXTENSIONS_ENABLE_INCOGNITO));
- localized_strings.SetString(L"allowFileAccess",
- l10n_util::GetString(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
- localized_strings.SetString(L"incognitoWarning",
- l10n_util::GetString(IDS_EXTENSIONS_INCOGNITO_WARNING));
- localized_strings.SetString(L"reload",
- l10n_util::GetString(IDS_EXTENSIONS_RELOAD));
- localized_strings.SetString(L"uninstall",
- l10n_util::GetString(IDS_EXTENSIONS_UNINSTALL));
- localized_strings.SetString(L"options",
- l10n_util::GetString(IDS_EXTENSIONS_OPTIONS));
- localized_strings.SetString(L"packDialogTitle",
- l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_TITLE));
- localized_strings.SetString(L"packDialogHeading",
- l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_HEADING));
- localized_strings.SetString(L"rootDirectoryLabel",
- l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL));
- localized_strings.SetString(L"packDialogBrowse",
- l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_BROWSE));
- localized_strings.SetString(L"privateKeyLabel",
- l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL));
- localized_strings.SetString(L"okButton",
- l10n_util::GetString(IDS_OK));
- localized_strings.SetString(L"cancelButton",
- l10n_util::GetString(IDS_CANCEL));
+ localized_strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_TITLE));
+ localized_strings.SetString("devModeLink",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
+ localized_strings.SetString("devModePrefix",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_PREFIX));
+ localized_strings.SetString("loadUnpackedButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
+ localized_strings.SetString("packButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON));
+ localized_strings.SetString("updateButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON));
+ localized_strings.SetString("noExtensions",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED));
+ localized_strings.SetString("suggestGallery",
+ l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
+ ASCIIToUTF16("<a href='") +
+ ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
+ GURL(Extension::ChromeStoreURL())).spec()) + ASCIIToUTF16("'>"),
+ ASCIIToUTF16("</a>")));
+ localized_strings.SetString("getMoreExtensions",
+ ASCIIToUTF16("<a href='") +
+ ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
+ GURL(Extension::ChromeStoreURL())).spec()) + ASCIIToUTF16("'>") +
+ l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS) +
+ ASCIIToUTF16("</a>"));
+ localized_strings.SetString("extensionDisabled",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLED_EXTENSION));
+ localized_strings.SetString("inDevelopment",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT));
+ localized_strings.SetString("viewIncognito",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO));
+ localized_strings.SetString("extensionId",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID));
+ localized_strings.SetString("extensionVersion",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_VERSION));
+ localized_strings.SetString("inspectViews",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS));
+ localized_strings.SetString("inspectPopupsInstructions",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_POPUPS_INSTRUCTIONS));
+ localized_strings.SetString("disable",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE));
+ localized_strings.SetString("enable",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
+ localized_strings.SetString("enableIncognito",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO));
+ localized_strings.SetString("allowFileAccess",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
+ localized_strings.SetString("incognitoWarning",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING));
+ localized_strings.SetString("reload",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD));
+ localized_strings.SetString("uninstall",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
+ localized_strings.SetString("options",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS));
+ localized_strings.SetString("packDialogTitle",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE));
+ localized_strings.SetString("packDialogHeading",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING));
+ localized_strings.SetString("rootDirectoryLabel",
+ l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL));
+ localized_strings.SetString("packDialogBrowse",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE));
+ localized_strings.SetString("privateKeyLabel",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL));
+ localized_strings.SetString("okButton",
+ l10n_util::GetStringUTF16(IDS_OK));
+ localized_strings.SetString("cancelButton",
+ l10n_util::GetStringUTF16(IDS_CANCEL));
SetFontAndTextDirection(&localized_strings);
@@ -198,7 +214,7 @@ void ExtensionsDOMHandler::IconLoader::LoadIconsOnFileThread(
scoped_ptr<DictionaryValue> json_deleter(json);
ListValue* extensions = NULL;
- CHECK(json->GetList(L"extensions", &extensions));
+ CHECK(json->GetList("extensions", &extensions));
for (size_t i = 0; i < icons->size(); ++i) {
DictionaryValue* extension = NULL;
@@ -209,8 +225,10 @@ void ExtensionsDOMHandler::IconLoader::LoadIconsOnFileThread(
if (icons->at(i).relative_path().empty() ||
!file_util::ReadFileToString(icons->at(i).GetFilePath(),
&file_contents)) {
- // If there's no icon, default to the puzzle icon. This is safe to do from
+ // If there's no icon, use the default icon. This is safe to do from
// the file thread.
+ // TODO(erikkay) Assuming we're going to keep showing apps in this list,
+ // then we need to figure out when we should use the app default icon.
file_contents = ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_EXTENSION_DEFAULT_ICON).as_string();
}
@@ -218,7 +236,7 @@ void ExtensionsDOMHandler::IconLoader::LoadIconsOnFileThread(
// If the extension is disabled, we desaturate the icon to add to the
// disabledness effect.
bool enabled = false;
- CHECK(extension->GetBoolean(L"enabled", &enabled));
+ CHECK(extension->GetBoolean("enabled", &enabled));
if (!enabled) {
const unsigned char* data =
reinterpret_cast<const unsigned char*>(file_contents.data());
@@ -244,7 +262,7 @@ void ExtensionsDOMHandler::IconLoader::LoadIconsOnFileThread(
base::Base64Encode(file_contents, &base64_encoded);
GURL icon_url("data:image/png;base64," + base64_encoded);
- extension->SetString(L"icon", icon_url.spec());
+ extension->SetString("icon", icon_url.spec());
}
ChromeThread::PostTask(
@@ -301,7 +319,7 @@ void ExtensionsDOMHandler::RegisterMessages() {
NewCallback(this, &ExtensionsDOMHandler::HandleSelectFilePathMessage));
}
-void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) {
+void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
DictionaryValue* results = new DictionaryValue();
// Add the extensions to the results structure.
@@ -313,18 +331,14 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) {
std::vector<ExtensionResource>* extension_icons =
new std::vector<ExtensionResource>();
- ExtensionProcessManager* process_manager =
- extensions_service_->profile()->GetExtensionProcessManager();
const ExtensionList* extensions = extensions_service_->extensions();
for (ExtensionList::const_iterator extension = extensions->begin();
extension != extensions->end(); ++extension) {
if (ShouldShowExtension(*extension)) {
- RenderProcessHost* process =
- process_manager->GetExtensionProcess((*extension)->url());
extensions_list->Append(CreateExtensionDetailValue(
extensions_service_.get(),
*extension,
- GetActivePagesForExtension(process, *extension),
+ GetActivePagesForExtension(*extension),
true)); // enabled
extension_icons->push_back(PickExtensionIcon(*extension));
}
@@ -333,21 +347,19 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) {
for (ExtensionList::const_iterator extension = extensions->begin();
extension != extensions->end(); ++extension) {
if (ShouldShowExtension(*extension)) {
- RenderProcessHost* process =
- process_manager->GetExtensionProcess((*extension)->url());
extensions_list->Append(CreateExtensionDetailValue(
extensions_service_.get(),
*extension,
- GetActivePagesForExtension(process, *extension),
+ GetActivePagesForExtension(*extension),
false)); // enabled
extension_icons->push_back(PickExtensionIcon(*extension));
}
}
- results->Set(L"extensions", extensions_list);
+ results->Set("extensions", extensions_list);
bool developer_mode = dom_ui_->GetProfile()->GetPrefs()
->GetBoolean(prefs::kExtensionsUIDeveloperMode);
- results->SetBoolean(L"developerMode", developer_mode);
+ results->SetBoolean("developerMode", developer_mode);
if (icon_loader_.get())
icon_loader_->Cancel();
@@ -393,16 +405,8 @@ void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) {
ExtensionResource ExtensionsDOMHandler::PickExtensionIcon(
Extension* extension) {
- // Try to fetch the medium sized icon, then (if missing) go for the large one.
- const std::map<int, std::string>& icons = extension->icons();
- std::map<int, std::string>::const_iterator iter =
- icons.find(Extension::EXTENSION_ICON_MEDIUM);
- if (iter == icons.end())
- iter = icons.find(Extension::EXTENSION_ICON_LARGE);
- if (iter != icons.end())
- return extension->GetResource(iter->second);
- else
- return ExtensionResource();
+ return extension->GetIconResource(Extension::EXTENSION_ICON_MEDIUM,
+ ExtensionIconSet::MATCH_BIGGER);
}
ExtensionInstallUI* ExtensionsDOMHandler::GetExtensionInstallUI() {
@@ -411,25 +415,23 @@ ExtensionInstallUI* ExtensionsDOMHandler::GetExtensionInstallUI() {
return install_ui_.get();
}
-void ExtensionsDOMHandler::HandleToggleDeveloperMode(const Value* value) {
+void ExtensionsDOMHandler::HandleToggleDeveloperMode(const ListValue* args) {
bool developer_mode = dom_ui_->GetProfile()->GetPrefs()
->GetBoolean(prefs::kExtensionsUIDeveloperMode);
dom_ui_->GetProfile()->GetPrefs()->SetBoolean(
prefs::kExtensionsUIDeveloperMode, !developer_mode);
}
-void ExtensionsDOMHandler::HandleInspectMessage(const Value* value) {
+void ExtensionsDOMHandler::HandleInspectMessage(const ListValue* args) {
std::string render_process_id_str;
std::string render_view_id_str;
int render_process_id;
int render_view_id;
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 2);
- CHECK(list->GetString(0, &render_process_id_str));
- CHECK(list->GetString(1, &render_view_id_str));
- CHECK(StringToInt(render_process_id_str, &render_process_id));
- CHECK(StringToInt(render_view_id_str, &render_view_id));
+ CHECK(args->GetSize() == 2);
+ CHECK(args->GetString(0, &render_process_id_str));
+ CHECK(args->GetString(1, &render_view_id_str));
+ CHECK(base::StringToInt(render_process_id_str, &render_process_id));
+ CHECK(base::StringToInt(render_view_id_str, &render_view_id));
RenderViewHost* host = RenderViewHost::FromID(render_process_id,
render_view_id);
if (!host) {
@@ -442,22 +444,17 @@ void ExtensionsDOMHandler::HandleInspectMessage(const Value* value) {
DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
}
-void ExtensionsDOMHandler::HandleReloadMessage(const Value* value) {
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 1);
- std::string extension_id;
- CHECK(list->GetString(0, &extension_id));
+void ExtensionsDOMHandler::HandleReloadMessage(const ListValue* args) {
+ std::string extension_id = WideToASCII(ExtractStringValue(args));
+ CHECK(!extension_id.empty());
extensions_service_->ReloadExtension(extension_id);
}
-void ExtensionsDOMHandler::HandleEnableMessage(const Value* value) {
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 2);
+void ExtensionsDOMHandler::HandleEnableMessage(const ListValue* args) {
+ CHECK(args->GetSize() == 2);
std::string extension_id, enable_str;
- CHECK(list->GetString(0, &extension_id));
- CHECK(list->GetString(1, &enable_str));
+ CHECK(args->GetString(0, &extension_id));
+ CHECK(args->GetString(1, &enable_str));
if (enable_str == "true") {
ExtensionPrefs* prefs = extensions_service_->extension_prefs();
if (prefs->DidExtensionEscalatePermissions(extension_id)) {
@@ -473,13 +470,11 @@ void ExtensionsDOMHandler::HandleEnableMessage(const Value* value) {
}
}
-void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const Value* value) {
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 2);
+void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const ListValue* args) {
+ CHECK(args->GetSize() == 2);
std::string extension_id, enable_str;
- CHECK(list->GetString(0, &extension_id));
- CHECK(list->GetString(1, &enable_str));
+ CHECK(args->GetString(0, &extension_id));
+ CHECK(args->GetString(1, &enable_str));
Extension* extension = extensions_service_->GetExtensionById(extension_id,
true);
DCHECK(extension);
@@ -500,13 +495,11 @@ void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const Value* value) {
ignore_notifications_ = false;
}
-void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const Value* value) {
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 2);
+void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const ListValue* args) {
+ CHECK(args->GetSize() == 2);
std::string extension_id, allow_str;
- CHECK(list->GetString(0, &extension_id));
- CHECK(list->GetString(1, &allow_str));
+ CHECK(args->GetString(0, &extension_id));
+ CHECK(args->GetString(1, &allow_str));
Extension* extension = extensions_service_->GetExtensionById(extension_id,
true);
DCHECK(extension);
@@ -514,31 +507,21 @@ void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const Value* value) {
extensions_service_->SetAllowFileAccess(extension, allow_str == "true");
}
-void ExtensionsDOMHandler::HandleUninstallMessage(const Value* value) {
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 1);
- std::string extension_id;
- CHECK(list->GetString(0, &extension_id));
-
- Extension *extension =
- extensions_service_->GetExtensionById(extension_id, true);
+void ExtensionsDOMHandler::HandleUninstallMessage(const ListValue* args) {
+ Extension* extension = GetExtension(args);
if (!extension)
return;
if (!extension_id_prompting_.empty())
- return; // only one prompt at a time
+ return; // Only one prompt at a time.
+ std::string extension_id = WideToASCII(ExtractStringValue(args));
extension_id_prompting_ = extension_id;
GetExtensionInstallUI()->ConfirmUninstall(this, extension);
}
-void ExtensionsDOMHandler::InstallUIProceed(bool create_app_shortcut) {
- // We only ever use ExtensionInstallUI for uninstalling, which should never
- // result in it telling us to create a shortcut.
- DCHECK(!create_app_shortcut);
-
+void ExtensionsDOMHandler::InstallUIProceed() {
DCHECK(!extension_id_prompting_.empty());
// The extension can be uninstalled in another window while the UI was
@@ -557,27 +540,18 @@ void ExtensionsDOMHandler::InstallUIAbort() {
extension_id_prompting_ = "";
}
-void ExtensionsDOMHandler::HandleOptionsMessage(const Value* value) {
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 1);
- std::string extension_id;
- CHECK(list->GetString(0, &extension_id));
- Extension *extension =
- extensions_service_->GetExtensionById(extension_id, false);
- if (!extension || extension->options_url().is_empty()) {
+void ExtensionsDOMHandler::HandleOptionsMessage(const ListValue* args) {
+ Extension* extension = GetExtension(args);
+ if (!extension || extension->options_url().is_empty())
return;
- }
dom_ui_->GetProfile()->GetExtensionProcessManager()->OpenOptionsPage(
extension, NULL);
}
-void ExtensionsDOMHandler::HandleLoadMessage(const Value* value) {
+void ExtensionsDOMHandler::HandleLoadMessage(const ListValue* args) {
FilePath::StringType string_path;
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 1) << list->GetSize();
- CHECK(list->GetString(0, &string_path));
+ CHECK(args->GetSize() == 1) << args->GetSize();
+ CHECK(args->GetString(0, &string_path));
extensions_service_->LoadExtension(FilePath(string_path));
}
@@ -587,17 +561,16 @@ void ExtensionsDOMHandler::ShowAlert(const std::string& message) {
dom_ui_->CallJavascriptFunction(L"alert", arguments);
}
-void ExtensionsDOMHandler::HandlePackMessage(const Value* value) {
- std::wstring extension_path;
- std::wstring private_key_path;
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 2);
- CHECK(list->GetString(0, &extension_path));
- CHECK(list->GetString(1, &private_key_path));
+void ExtensionsDOMHandler::HandlePackMessage(const ListValue* args) {
+ std::string extension_path;
+ std::string private_key_path;
+ CHECK(args->GetSize() == 2);
+ CHECK(args->GetString(0, &extension_path));
+ CHECK(args->GetString(1, &private_key_path));
- FilePath root_directory = FilePath::FromWStringHack(extension_path);
- FilePath key_file = FilePath::FromWStringHack(private_key_path);
+ FilePath root_directory =
+ FilePath::FromWStringHack(UTF8ToWide(extension_path));
+ FilePath key_file = FilePath::FromWStringHack(UTF8ToWide(private_key_path));
if (root_directory.empty()) {
if (extension_path.empty()) {
@@ -623,42 +596,29 @@ void ExtensionsDOMHandler::HandlePackMessage(const Value* value) {
void ExtensionsDOMHandler::OnPackSuccess(const FilePath& crx_file,
const FilePath& pem_file) {
- std::string message;
- if (!pem_file.empty()) {
- message = WideToUTF8(l10n_util::GetStringF(
- IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_NEW,
- crx_file.ToWStringHack(),
- pem_file.ToWStringHack()));
- } else {
- message = WideToUTF8(l10n_util::GetStringF(
- IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_UPDATE,
- crx_file.ToWStringHack()));
- }
- ShowAlert(message);
+ ShowAlert(WideToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file,
+ pem_file)));
ListValue results;
dom_ui_->CallJavascriptFunction(L"hidePackDialog", results);
}
-void ExtensionsDOMHandler::OnPackFailure(const std::wstring& error) {
- ShowAlert(WideToUTF8(error));
+void ExtensionsDOMHandler::OnPackFailure(const std::string& error) {
+ ShowAlert(error);
}
-void ExtensionsDOMHandler::HandleAutoUpdateMessage(const Value* value) {
+void ExtensionsDOMHandler::HandleAutoUpdateMessage(const ListValue* args) {
ExtensionUpdater* updater = extensions_service_->updater();
- if (updater) {
+ if (updater)
updater->CheckNow();
- }
}
-void ExtensionsDOMHandler::HandleSelectFilePathMessage(const Value* value) {
+void ExtensionsDOMHandler::HandleSelectFilePathMessage(const ListValue* args) {
std::string select_type;
std::string operation;
- CHECK(value->IsType(Value::TYPE_LIST));
- const ListValue* list = static_cast<const ListValue*>(value);
- CHECK(list->GetSize() == 2);
- CHECK(list->GetString(0, &select_type));
- CHECK(list->GetString(1, &operation));
+ CHECK(args->GetSize() == 2);
+ CHECK(args->GetString(0, &select_type));
+ CHECK(args->GetString(1, &operation));
SelectFileDialog::Type type = SelectFileDialog::SELECT_FOLDER;
static SelectFileDialog::FileTypeInfo info;
@@ -667,19 +627,19 @@ void ExtensionsDOMHandler::HandleSelectFilePathMessage(const Value* value) {
type = SelectFileDialog::SELECT_OPEN_FILE;
string16 select_title;
- if (operation == "load")
+ if (operation == "load") {
select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
- else if (operation == "packRoot")
+ } else if (operation == "packRoot") {
select_title = l10n_util::GetStringUTF16(
IDS_EXTENSION_PACK_DIALOG_SELECT_ROOT);
- else if (operation == "pem") {
+ } else if (operation == "pem") {
select_title = l10n_util::GetStringUTF16(
IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
info.extensions.push_back(std::vector<FilePath::StringType>());
info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
- info.extension_description_overrides.push_back(WideToUTF16(
- l10n_util::GetString(
- IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)));
+ info.extension_description_overrides.push_back(
+ l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
info.include_all_files = true;
file_type_index = 1;
} else {
@@ -742,6 +702,12 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
}
}
+Extension* ExtensionsDOMHandler::GetExtension(const ListValue* args) {
+ std::string extension_id = WideToASCII(ExtractStringValue(args));
+ CHECK(!extension_id.empty());
+ return extensions_service_->GetExtensionById(extension_id, true);
+}
+
void ExtensionsDOMHandler::MaybeUpdateAfterNotification() {
if (!ignore_notifications_ && dom_ui_->tab_contents())
HandleRequestExtensionsData(NULL);
@@ -750,7 +716,7 @@ void ExtensionsDOMHandler::MaybeUpdateAfterNotification() {
static void CreateScriptFileDetailValue(
const FilePath& extension_path, const UserScript::FileList& scripts,
- const wchar_t* key, DictionaryValue* script_data) {
+ const char* key, DictionaryValue* script_data) {
if (scripts.empty())
return;
@@ -769,9 +735,9 @@ static void CreateScriptFileDetailValue(
DictionaryValue* ExtensionsDOMHandler::CreateContentScriptDetailValue(
const UserScript& script, const FilePath& extension_path) {
DictionaryValue* script_data = new DictionaryValue();
- CreateScriptFileDetailValue(extension_path, script.js_scripts(), L"js",
+ CreateScriptFileDetailValue(extension_path, script.js_scripts(), "js",
script_data);
- CreateScriptFileDetailValue(extension_path, script.css_scripts(), L"css",
+ CreateScriptFileDetailValue(extension_path, script.css_scripts(), "css",
script_data);
// Get list of glob "matches" strings
@@ -783,7 +749,7 @@ DictionaryValue* ExtensionsDOMHandler::CreateContentScriptDetailValue(
url_pattern_list->Append(new StringValue(url_pattern->GetAsString()));
}
- script_data->Set(L"matches", url_pattern_list);
+ script_data->Set("matches", url_pattern_list);
return script_data;
}
@@ -808,29 +774,30 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
const std::vector<ExtensionPage>& pages, bool enabled) {
DictionaryValue* extension_data = new DictionaryValue();
- extension_data->SetString(L"id", extension->id());
- extension_data->SetString(L"name", extension->name());
- extension_data->SetString(L"description", extension->description());
- extension_data->SetString(L"version", extension->version()->GetString());
- extension_data->SetBoolean(L"enabled", enabled);
- extension_data->SetBoolean(L"enabledIncognito",
+ extension_data->SetString("id", extension->id());
+ extension_data->SetString("name", extension->name());
+ extension_data->SetString("description", extension->description());
+ extension_data->SetString("version", extension->version()->GetString());
+ extension_data->SetBoolean("enabled", enabled);
+ extension_data->SetBoolean("enabledIncognito",
service ? service->IsIncognitoEnabled(extension) : false);
- extension_data->SetBoolean(L"wantsFileAccess",
+ extension_data->SetBoolean("wantsFileAccess",
ExtensionWantsFileAccess(extension));
- extension_data->SetBoolean(L"allowFileAccess",
+ extension_data->SetBoolean("allowFileAccess",
service ? service->AllowFileAccess(extension) : false);
- extension_data->SetBoolean(L"allow_reload",
+ extension_data->SetBoolean("allow_reload",
extension->location() == Extension::LOAD);
+ extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app());
// Determine the sort order: Extensions loaded through --load-extensions show
// up at the top. Disabled extensions show up at the bottom.
if (extension->location() == Extension::LOAD)
- extension_data->SetInteger(L"order", 1);
+ extension_data->SetInteger("order", 1);
else
- extension_data->SetInteger(L"order", 2);
+ extension_data->SetInteger("order", 2);
if (!extension->options_url().is_empty())
- extension_data->SetString(L"options_url", extension->options_url().spec());
+ extension_data->SetString("options_url", extension->options_url().spec());
// Add list of content_script detail DictionaryValues.
ListValue *content_script_list = new ListValue();
@@ -840,7 +807,7 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
content_script_list->Append(
CreateContentScriptDetailValue(*script, extension->path()));
}
- extension_data->Set(L"content_scripts", content_script_list);
+ extension_data->Set("content_scripts", content_script_list);
// Add permissions.
ListValue *permission_list = new ListValue;
@@ -850,7 +817,7 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
permission_list->Append(Value::CreateStringValue(
permission->GetAsString()));
}
- extension_data->Set(L"permissions", permission_list);
+ extension_data->Set("permissions", permission_list);
// Add views
ListValue* views = new ListValue;
@@ -859,29 +826,55 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
DictionaryValue* view_value = new DictionaryValue;
if (iter->url.scheme() == chrome::kExtensionScheme) {
// No leading slash.
- view_value->SetString(L"path", iter->url.path().substr(1));
+ view_value->SetString("path", iter->url.path().substr(1));
} else {
// For live pages, use the full URL.
- view_value->SetString(L"path", iter->url.spec());
+ view_value->SetString("path", iter->url.spec());
}
- view_value->SetInteger(L"renderViewId", iter->render_view_id);
- view_value->SetInteger(L"renderProcessId", iter->render_process_id);
+ view_value->SetInteger("renderViewId", iter->render_view_id);
+ view_value->SetInteger("renderProcessId", iter->render_process_id);
+ view_value->SetBoolean("incognito", iter->incognito);
views->Append(view_value);
}
- extension_data->Set(L"views", views);
- extension_data->SetBoolean(L"hasPopupAction",
+ extension_data->Set("views", views);
+ extension_data->SetBoolean("hasPopupAction",
extension->browser_action() || extension->page_action());
- extension_data->SetString(L"galleryUrl", extension->GalleryUrl().spec());
+ extension_data->SetString("galleryUrl", extension->GalleryUrl().spec());
return extension_data;
}
std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
- RenderProcessHost* process,
Extension* extension) {
std::vector<ExtensionPage> result;
+
+ // Get the extension process's active views.
+ ExtensionProcessManager* process_manager =
+ extensions_service_->profile()->GetExtensionProcessManager();
+ GetActivePagesForExtensionProcess(
+ process_manager->GetExtensionProcess(extension->url()),
+ extension, &result);
+
+ // Repeat for the incognito process, if applicable.
+ if (extensions_service_->profile()->HasOffTheRecordProfile() &&
+ extension->incognito_split_mode()) {
+ ExtensionProcessManager* process_manager =
+ extensions_service_->profile()->GetOffTheRecordProfile()->
+ GetExtensionProcessManager();
+ GetActivePagesForExtensionProcess(
+ process_manager->GetExtensionProcess(extension->url()),
+ extension, &result);
+ }
+
+ return result;
+}
+
+void ExtensionsDOMHandler::GetActivePagesForExtensionProcess(
+ RenderProcessHost* process,
+ Extension* extension,
+ std::vector<ExtensionPage> *result) {
if (!process)
- return result;
+ return;
RenderProcessHost::listeners_iterator iter = process->ListenersIterator();
for (; !iter.IsAtEnd(); iter.Advance()) {
@@ -903,10 +896,9 @@ std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
continue;
}
- result.push_back(ExtensionPage(url, process->id(), host->routing_id()));
+ result->push_back(ExtensionPage(url, process->id(), host->routing_id(),
+ process->profile()->IsOffTheRecord()));
}
-
- return result;
}
ExtensionsDOMHandler::~ExtensionsDOMHandler() {
diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h
index 120f08a..5660eaa 100644
--- a/chrome/browser/extensions/extensions_ui.h
+++ b/chrome/browser/extensions/extensions_ui.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_UI_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_UI_H_
+#pragma once
#include <string>
#include <vector>
+#include "base/scoped_ptr.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/extensions/extension_install_ui.h"
@@ -22,20 +24,22 @@ class DictionaryValue;
class Extension;
class ExtensionsService;
class FilePath;
+class ListValue;
class PrefService;
class RenderProcessHost;
class UserScript;
-class Value;
// Information about a page running in an extension, for example a toolstrip,
// a background page, or a tab contents.
struct ExtensionPage {
- ExtensionPage(const GURL& url, int render_process_id, int render_view_id)
+ ExtensionPage(const GURL& url, int render_process_id, int render_view_id,
+ bool incognito)
: url(url), render_process_id(render_process_id),
- render_view_id(render_view_id) {}
+ render_view_id(render_view_id), incognito(incognito) {}
GURL url;
int render_process_id;
int render_view_id;
+ bool incognito;
};
class ExtensionsUIHTMLSource : public ChromeURLDataManager::DataSource {
@@ -123,55 +127,58 @@ class ExtensionsDOMHandler
virtual void OnPackSuccess(const FilePath& crx_file,
const FilePath& key_file);
- virtual void OnPackFailure(const std::wstring& message);
+ virtual void OnPackFailure(const std::string& error);
// ExtensionInstallUI::Delegate implementation, used for receiving
// notification about uninstall confirmation dialog selections.
- virtual void InstallUIProceed(bool create_app_shortcut);
+ virtual void InstallUIProceed();
virtual void InstallUIAbort();
private:
// Callback for "requestExtensionsData" message.
- void HandleRequestExtensionsData(const Value* value);
+ void HandleRequestExtensionsData(const ListValue* args);
// Callback for "toggleDeveloperMode" message.
- void HandleToggleDeveloperMode(const Value* value);
+ void HandleToggleDeveloperMode(const ListValue* args);
// Callback for "inspect" message.
- void HandleInspectMessage(const Value* value);
+ void HandleInspectMessage(const ListValue* args);
// Callback for "reload" message.
- void HandleReloadMessage(const Value* value);
+ void HandleReloadMessage(const ListValue* args);
// Callback for "enable" message.
- void HandleEnableMessage(const Value* value);
+ void HandleEnableMessage(const ListValue* args);
// Callback for "enableIncognito" message.
- void HandleEnableIncognitoMessage(const Value* value);
+ void HandleEnableIncognitoMessage(const ListValue* args);
// Callback for "allowFileAcces" message.
- void HandleAllowFileAccessMessage(const Value* value);
+ void HandleAllowFileAccessMessage(const ListValue* args);
// Callback for "uninstall" message.
- void HandleUninstallMessage(const Value* value);
+ void HandleUninstallMessage(const ListValue* args);
// Callback for "options" message.
- void HandleOptionsMessage(const Value* value);
+ void HandleOptionsMessage(const ListValue* args);
// Callback for "load" message.
- void HandleLoadMessage(const Value* value);
+ void HandleLoadMessage(const ListValue* args);
// Callback for "pack" message.
- void HandlePackMessage(const Value* value);
+ void HandlePackMessage(const ListValue* args);
// Callback for "autoupdate" message.
- void HandleAutoUpdateMessage(const Value* value);
+ void HandleAutoUpdateMessage(const ListValue* args);
// Utility for calling javascript window.alert in the page.
void ShowAlert(const std::string& message);
// Callback for "selectFilePath" message.
- void HandleSelectFilePathMessage(const Value* value);
+ void HandleSelectFilePathMessage(const ListValue* args);
+
+ // Utility for callbacks that get an extension ID as the sole argument.
+ Extension* GetExtension(const ListValue* args);
// Forces a UI update if appropriate after a notification is received.
void MaybeUpdateAfterNotification();
@@ -191,9 +198,11 @@ class ExtensionsDOMHandler
const NotificationDetails& details);
// Helper that lists the current active html pages for an extension.
- std::vector<ExtensionPage> GetActivePagesForExtension(
+ std::vector<ExtensionPage> GetActivePagesForExtension(Extension* extension);
+ void GetActivePagesForExtensionProcess(
RenderProcessHost* process,
- Extension* extension);
+ Extension* extension,
+ std::vector<ExtensionPage> *result);
// Returns the best icon to display in the UI for an extension, or an empty
// ExtensionResource if no good icon exists.
diff --git a/chrome/browser/extensions/external_extension_provider.h b/chrome/browser/extensions/external_extension_provider.h
index ffbb654..eddea62 100644
--- a/chrome/browser/extensions/external_extension_provider.h
+++ b/chrome/browser/extensions/external_extension_provider.h
@@ -4,14 +4,15 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_
+#pragma once
#include <set>
#include <string>
-#include "base/version.h"
#include "chrome/common/extensions/extension.h"
class FilePath;
+class Version;
// This class is an abstract class for implementing external extensions
// providers.
@@ -23,10 +24,15 @@ class ExternalExtensionProvider {
// is not transferred to the visitor.
class Visitor {
public:
- virtual void OnExternalExtensionFound(const std::string& id,
- const Version* version,
- const FilePath& path,
- Extension::Location location) = 0;
+ virtual void OnExternalExtensionFileFound(
+ const std::string& id,
+ const Version* version,
+ const FilePath& path,
+ Extension::Location location) = 0;
+
+ virtual void OnExternalExtensionUpdateUrlFound(
+ const std::string& id,
+ const GURL& update_url) = 0;
protected:
virtual ~Visitor() {}
diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc
index 5fe39b4..3eaafc9 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.cc
+++ b/chrome/browser/extensions/external_pref_extension_provider.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,14 +9,16 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/version.h"
#include "chrome/common/json_value_serializer.h"
// Constants for keeping track of extension preferences.
-const wchar_t kLocation[] = L"location";
-const wchar_t kState[] = L"state";
-const wchar_t kExternalCrx[] = L"external_crx";
-const wchar_t kExternalVersion[] = L"external_version";
+const char kLocation[] = "location";
+const char kState[] = "state";
+const char kExternalCrx[] = "external_crx";
+const char kExternalVersion[] = "external_version";
+const char kExternalUpdateUrl[] = "external_update_url";
ExternalPrefExtensionProvider::ExternalPrefExtensionProvider() {
FilePath json_file;
@@ -44,8 +46,8 @@ void ExternalPrefExtensionProvider::VisitRegisteredExtension(
Visitor* visitor, const std::set<std::string>& ids_to_ignore) const {
for (DictionaryValue::key_iterator i = prefs_->begin_keys();
i != prefs_->end_keys(); ++i) {
- const std::wstring& extension_id = *i;
- if (ids_to_ignore.find(WideToASCII(extension_id)) != ids_to_ignore.end())
+ const std::string& extension_id = *i;
+ if (ids_to_ignore.find(extension_id) != ids_to_ignore.end())
continue;
DictionaryValue* extension;
@@ -54,40 +56,75 @@ void ExternalPrefExtensionProvider::VisitRegisteredExtension(
FilePath::StringType external_crx;
std::string external_version;
- if (!extension->GetString(kExternalCrx, &external_crx) ||
- !extension->GetString(kExternalVersion, &external_version)) {
+ std::string external_update_url;
+
+ bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
+ bool has_external_version = extension->GetString(kExternalVersion,
+ &external_version);
+ bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
+ &external_update_url);
+ if (has_external_crx != has_external_version) {
LOG(WARNING) << "Malformed extension dictionary for extension: "
- << extension_id.c_str();
+ << extension_id.c_str() << ". " << kExternalCrx
+ << " and " << kExternalVersion << " must be used together.";
continue;
}
- if (external_crx.find(FilePath::kParentDirectory) !=
- base::StringPiece::npos) {
- LOG(WARNING) << "Path traversal not allowed in path: "
- << external_crx.c_str();
+ if (has_external_crx == has_external_update_url) {
+ LOG(WARNING) << "Malformed extension dictionary for extension: "
+ << extension_id.c_str() << ". Exactly one of the "
+ << "followng keys should be used: " << kExternalCrx
+ << ", " << kExternalUpdateUrl << ".";
continue;
}
- // See if it's an absolute path...
- FilePath path(external_crx);
- if (!path.IsAbsolute()) {
- // Try path as relative path from external extension dir.
- FilePath base_path;
- PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &base_path);
- path = base_path.Append(external_crx);
+ if (has_external_crx) {
+ if (external_crx.find(FilePath::kParentDirectory) !=
+ base::StringPiece::npos) {
+ LOG(WARNING) << "Path traversal not allowed in path: "
+ << external_crx.c_str();
+ continue;
+ }
+
+ // If the path is relative, make it absolute.
+ FilePath path(external_crx);
+ if (!path.IsAbsolute()) {
+ // Try path as relative path from external extension dir.
+ FilePath base_path;
+ PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &base_path);
+ path = base_path.Append(external_crx);
+ }
+
+ scoped_ptr<Version> version;
+ version.reset(Version::GetVersionFromString(external_version));
+ if (!version.get()) {
+ LOG(ERROR) << "Malformed extension dictionary for extension: "
+ << extension_id.c_str() << ". Invalid version string \""
+ << external_version << "\".";
+ continue;
+ }
+ visitor->OnExternalExtensionFileFound(extension_id, version.get(), path,
+ Extension::EXTERNAL_PREF);
+ continue;
}
- scoped_ptr<Version> version;
- version.reset(Version::GetVersionFromString(external_version));
- visitor->OnExternalExtensionFound(WideToASCII(extension_id), version.get(),
- path, Extension::EXTERNAL_PREF);
+ DCHECK(has_external_update_url); // Checking of keys above ensures this.
+ GURL update_url(external_update_url);
+ if (!update_url.is_valid()) {
+ LOG(WARNING) << "Malformed extension dictionary for extension: "
+ << extension_id.c_str() << ". " << kExternalUpdateUrl
+ << " must be a valid URL. Saw \"" << external_update_url
+ << "\".";
+ continue;
+ }
+ visitor->OnExternalExtensionUpdateUrlFound(extension_id, update_url);
}
}
Version* ExternalPrefExtensionProvider::RegisteredVersion(
const std::string& id, Extension::Location* location) const {
DictionaryValue* extension = NULL;
- if (!prefs_->GetDictionary(ASCIIToWide(id), &extension))
+ if (!prefs_->GetDictionary(id, &extension))
return NULL;
std::string external_version;
@@ -105,11 +142,10 @@ void ExternalPrefExtensionProvider::SetPreferences(
Value* extensions = serializer->Deserialize(NULL, &error_msg);
scoped_ptr<DictionaryValue> dictionary(new DictionaryValue());
if (!extensions) {
- LOG(WARNING) << L"Unable to deserialize json data: "
- << error_msg;
+ LOG(WARNING) << "Unable to deserialize json data: " << error_msg;
} else {
if (!extensions->IsType(Value::TYPE_DICTIONARY)) {
- NOTREACHED() << L"Invalid json data";
+ NOTREACHED() << "Invalid json data";
} else {
dictionary.reset(static_cast<DictionaryValue*>(extensions));
}
diff --git a/chrome/browser/extensions/external_pref_extension_provider.h b/chrome/browser/extensions/external_pref_extension_provider.h
index 0b222b5..aef6b17 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.h
+++ b/chrome/browser/extensions/external_pref_extension_provider.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_PROVIDER_H_
#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_PROVIDER_H_
+#pragma once
#include <set>
#include <string>
@@ -11,6 +12,7 @@
#include "chrome/browser/extensions/external_extension_provider.h"
class DictionaryValue;
+class ValueSerializer;
class Version;
// A specialization of the ExternalExtensionProvider that uses a json file to
diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.cc b/chrome/browser/extensions/external_registry_extension_provider_win.cc
index d8057a0..35ed4ae 100644
--- a/chrome/browser/extensions/external_registry_extension_provider_win.cc
+++ b/chrome/browser/extensions/external_registry_extension_provider_win.cc
@@ -7,6 +7,7 @@
#include "base/file_path.h"
#include "base/registry.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/version.h"
// The Registry hive where to look for external extensions.
@@ -36,7 +37,7 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension(
std::wstring key_path = ASCIIToWide(kRegistryExtensions);
key_path.append(L"\\");
key_path.append(iterator.Name());
- if (key.Open(kRegRoot, key_path.c_str())) {
+ if (key.Open(kRegRoot, key_path.c_str(), KEY_READ)) {
std::wstring extension_path;
if (key.ReadValue(kRegistryExtensionPath, &extension_path)) {
std::wstring extension_version;
@@ -51,8 +52,8 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension(
scoped_ptr<Version> version;
version.reset(Version::GetVersionFromString(extension_version));
FilePath path = FilePath::FromWStringHack(extension_path);
- visitor->OnExternalExtensionFound(id, version.get(), path,
- Extension::EXTERNAL_REGISTRY);
+ visitor->OnExternalExtensionFileFound(id, version.get(), path,
+ Extension::EXTERNAL_REGISTRY);
} else {
// TODO(erikkay): find a way to get this into about:extensions
LOG(WARNING) << "Missing value " << kRegistryExtensionVersion <<
@@ -76,7 +77,7 @@ Version* ExternalRegistryExtensionProvider::RegisteredVersion(
key_path.append(L"\\");
key_path.append(ASCIIToWide(id));
- if (!key.Open(kRegRoot, key_path.c_str()))
+ if (!key.Open(kRegRoot, key_path.c_str(), KEY_READ))
return NULL;
std::wstring extension_version;
diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.h b/chrome/browser/extensions/external_registry_extension_provider_win.h
index 39b3a15..b5b44bb 100644
--- a/chrome/browser/extensions/external_registry_extension_provider_win.h
+++ b/chrome/browser/extensions/external_registry_extension_provider_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_
#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_
+#pragma once
#include <set>
#include <string>
diff --git a/chrome/browser/extensions/file_reader.h b/chrome/browser/extensions/file_reader.h
index 97f6cc6..b64d83c 100644
--- a/chrome/browser/extensions/file_reader.h
+++ b/chrome/browser/extensions/file_reader.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_FILE_READER_H_
#define CHROME_BROWSER_EXTENSIONS_FILE_READER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/extensions/fragment_navigation_apitest.cc b/chrome/browser/extensions/fragment_navigation_apitest.cc
index d44c35a..aa7bc46 100644
--- a/chrome/browser/extensions/fragment_navigation_apitest.cc
+++ b/chrome/browser/extensions/fragment_navigation_apitest.cc
@@ -6,13 +6,13 @@
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptFragmentNavigation) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
const char* extension_name = "content_scripts/fragment";
ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExecuteScriptFragmentNavigation) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
const char* extension_name = "executescript/fragment";
ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
}
diff --git a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h
index abb66b5..6fd7f72 100644
--- a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h
@@ -1,16 +1,16 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_GTK_THEME_INSTALLED_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_EXTENSIONS_GTK_THEME_INSTALLED_INFOBAR_DELEGATE_H_
+#pragma once
#include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
#include <string>
class Extension;
-class SkBitmap;
class TabContents;
// A specialization of ThemeInstalledInfoBarDelegate to make "Undo" reset to the
diff --git a/chrome/browser/extensions/image_loading_tracker.h b/chrome/browser/extensions/image_loading_tracker.h
index e32166a..bac2f04 100644
--- a/chrome/browser/extensions/image_loading_tracker.h
+++ b/chrome/browser/extensions/image_loading_tracker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_IMAGE_LOADING_TRACKER_H_
#define CHROME_BROWSER_EXTENSIONS_IMAGE_LOADING_TRACKER_H_
+#pragma once
#include <map>
@@ -60,7 +61,9 @@ class ImageLoadingTracker : public NotificationObserver {
~ImageLoadingTracker();
// Specify image resource to load. If the loaded image is larger than
- // |max_size| it will be resized to those dimensions.
+ // |max_size| it will be resized to those dimensions. IMPORTANT NOTE: this
+ // function may call back your observer synchronously (ie before it returns)
+ // if the image was found in the cache.
void LoadImage(Extension* extension,
const ExtensionResource& resource,
const gfx::Size& max_size,
diff --git a/chrome/browser/extensions/image_loading_tracker_unittest.cc b/chrome/browser/extensions/image_loading_tracker_unittest.cc
index 7522838..930d831 100644
--- a/chrome/browser/extensions/image_loading_tracker_unittest.cc
+++ b/chrome/browser/extensions/image_loading_tracker_unittest.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_service.h"
@@ -102,7 +103,8 @@ TEST_F(ImageLoadingTrackerTest, Cache) {
ASSERT_TRUE(extension.get() != NULL);
ExtensionResource image_resource =
- extension->GetIconPath(Extension::EXTENSION_ICON_SMALLISH);
+ extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_EXACTLY);
gfx::Size max_size(Extension::EXTENSION_ICON_SMALLISH,
Extension::EXTENSION_ICON_SMALLISH);
ImageLoadingTracker loader(static_cast<ImageLoadingTracker::Observer*>(this));
@@ -148,7 +150,8 @@ TEST_F(ImageLoadingTrackerTest, DeleteExtensionWhileWaitingForCache) {
ASSERT_TRUE(extension.get() != NULL);
ExtensionResource image_resource =
- extension->GetIconPath(Extension::EXTENSION_ICON_SMALLISH);
+ extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_EXACTLY);
ImageLoadingTracker loader(static_cast<ImageLoadingTracker::Observer*>(this));
loader.LoadImage(extension.get(),
image_resource,
diff --git a/chrome/browser/extensions/isolated_world_apitest.cc b/chrome/browser/extensions/isolated_world_apitest.cc
index f3ef0eb..4b0761d 100644
--- a/chrome/browser/extensions/isolated_world_apitest.cc
+++ b/chrome/browser/extensions/isolated_world_apitest.cc
@@ -7,7 +7,7 @@
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IsolatedWorld1) {
// This extension runs various bits of script and tests that they all run in
// the same isolated world.
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("content_scripts/isolated_world1")) << message_;
// Now load a different extension, inject into same page, verify worlds aren't
diff --git a/chrome/browser/extensions/notifications_apitest.cc b/chrome/browser/extensions/notifications_apitest.cc
index eb19861..eb51c67 100644
--- a/chrome/browser/extensions/notifications_apitest.cc
+++ b/chrome/browser/extensions/notifications_apitest.cc
@@ -8,8 +8,14 @@
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/profile.h"
+// Fails and hoses bot, http://crbug.com/50060.
// Flaky, http://crbug.com/42314.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_Notifications) {
+#if defined(OS_MACOSX)
+#define MAYBE_Notifications DISABLED_Notifications
+#else
+#define MAYBE_Notifications FLAKY_Notifications
+#endif
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_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 01c2fb6..1896c1e 100644
--- a/chrome/browser/extensions/pack_extension_job.cc
+++ b/chrome/browser/extensions/pack_extension_job.cc
@@ -4,15 +4,19 @@
#include "chrome/browser/extensions/pack_extension_job.h"
+#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "base/task.h"
#include "chrome/browser/extensions/extension_creator.h"
+#include "chrome/common/chrome_constants.h"
+#include "grit/generated_resources.h"
PackExtensionJob::PackExtensionJob(Client* client,
const FilePath& root_directory,
const FilePath& key_file)
- : client_(client), root_directory_(root_directory), key_file_(key_file) {
+ : client_(client), key_file_(key_file) {
+ root_directory_ = root_directory.StripTrailingSeparators();
CHECK(ChromeThread::GetCurrentThreadIdentifier(&client_thread_id_));
}
@@ -27,10 +31,12 @@ void PackExtensionJob::ClearClient() {
}
void PackExtensionJob::RunOnFileThread() {
- crx_file_out_ = root_directory_.ReplaceExtension(FILE_PATH_LITERAL("crx"));
+ crx_file_out_ = FilePath(root_directory_.value() +
+ chrome::kExtensionFileExtension);
if (key_file_.empty())
- key_file_out_ = root_directory_.ReplaceExtension(FILE_PATH_LITERAL("pem"));
+ key_file_out_ = FilePath(root_directory_.value() +
+ chrome::kExtensionKeyFileExtension);
// TODO(aa): Need to internationalize the errors that ExtensionCreator
// returns. See bug 20734.
@@ -38,22 +44,42 @@ void PackExtensionJob::RunOnFileThread() {
if (creator.Run(root_directory_, crx_file_out_, key_file_, key_file_out_)) {
ChromeThread::PostTask(
client_thread_id_, FROM_HERE,
- NewRunnableMethod(this, &PackExtensionJob::ReportSuccessOnUIThread));
+ NewRunnableMethod(this,
+ &PackExtensionJob::ReportSuccessOnClientThread));
} else {
ChromeThread::PostTask(
client_thread_id_, FROM_HERE,
NewRunnableMethod(
- this, &PackExtensionJob::ReportFailureOnUIThread,
+ this, &PackExtensionJob::ReportFailureOnClientThread,
creator.error_message()));
}
}
-void PackExtensionJob::ReportSuccessOnUIThread() {
+void PackExtensionJob::ReportSuccessOnClientThread() {
if (client_)
client_->OnPackSuccess(crx_file_out_, key_file_out_);
}
-void PackExtensionJob::ReportFailureOnUIThread(const std::string& error) {
+void PackExtensionJob::ReportFailureOnClientThread(const std::string& error) {
if (client_)
- client_->OnPackFailure(UTF8ToWide(error));
+ client_->OnPackFailure(error);
+}
+
+// static
+std::wstring PackExtensionJob::StandardSuccessMessage(const FilePath& crx_file,
+ const FilePath& key_file)
+{
+ // TODO(isherman): we should use string16 instead of wstring.
+ // See crbug.com/23581 and crbug.com/24672
+ std::wstring message;
+ if (key_file.empty()) {
+ return l10n_util::GetStringF(
+ IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_UPDATE,
+ crx_file.ToWStringHack());
+ } else {
+ return l10n_util::GetStringF(
+ IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_NEW,
+ crx_file.ToWStringHack(),
+ key_file.ToWStringHack());
+ }
}
diff --git a/chrome/browser/extensions/pack_extension_job.h b/chrome/browser/extensions/pack_extension_job.h
index 2ad95a6..48c0a54 100644
--- a/chrome/browser/extensions/pack_extension_job.h
+++ b/chrome/browser/extensions/pack_extension_job.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_H_
#define CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_H_
+#pragma once
#include <string>
@@ -22,7 +23,10 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> {
public:
virtual void OnPackSuccess(const FilePath& crx_file,
const FilePath& key_file) = 0;
- virtual void OnPackFailure(const std::wstring& message) = 0;
+ virtual void OnPackFailure(const std::string& message) = 0;
+
+ protected:
+ virtual ~Client() {}
};
PackExtensionJob(Client* client,
@@ -37,14 +41,18 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> {
// PackExtensionJob from attempting to access it.
void ClearClient();
+ // The standard packing success message.
+ static std::wstring StandardSuccessMessage(const FilePath& crx_file,
+ const FilePath& key_file);
+
private:
friend class base::RefCountedThreadSafe<PackExtensionJob>;
~PackExtensionJob() {}
void RunOnFileThread();
- void ReportSuccessOnUIThread();
- void ReportFailureOnUIThread(const std::string& error);
+ void ReportSuccessOnClientThread();
+ void ReportFailureOnClientThread(const std::string& error);
ChromeThread::ID client_thread_id_;
Client* client_;
diff --git a/chrome/browser/extensions/page_action_apitest.cc b/chrome/browser/extensions/page_action_apitest.cc
index 6eb30dd..4ae4b39 100644
--- a/chrome/browser/extensions/page_action_apitest.cc
+++ b/chrome/browser/extensions/page_action_apitest.cc
@@ -15,7 +15,7 @@
#include "chrome/test/ui_test_utils.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PageAction) {
- ASSERT_TRUE(StartHTTPServer());
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("page_action/basics")) << message_;
Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
diff --git a/chrome/browser/extensions/permissions_apitest.cc b/chrome/browser/extensions/permissions_apitest.cc
index 82c4068..b3eea8a 100644
--- a/chrome/browser/extensions/permissions_apitest.cc
+++ b/chrome/browser/extensions/permissions_apitest.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.
@@ -41,3 +41,21 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExperimentalPermissionsFail) {
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FavIconPermission) {
ASSERT_TRUE(RunExtensionTest("permissions/favicon")) << message_;
}
+
+// Test functions and APIs that are always allowed (even if you ask for no
+// permissions.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, AlwaysAllowed) {
+ ASSERT_TRUE(RunExtensionTest("permissions/always_allowed")) << message_;
+}
+
+// TODO(gregoryd): run the NaCl test on all systems once
+// http://code.google.com/p/chromium/issues/detail?id=51335 is fixed.
+// Meanwhile we run it on Mac OSX only, since we can be sure that an x86-32 NaCl
+// module will work there.
+// Mark as Flaky. http://crbug.com/51861
+#if defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_NaClPermissionEnabled) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(switches::kInternalNaCl);
+ ASSERT_TRUE(RunExtensionTest("permissions/nacl_enabled")) << message_;
+}
+#endif
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc
index c087649..1c5e319 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker.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.
@@ -12,6 +12,7 @@
#include "base/message_loop.h"
#include "base/scoped_handle.h"
#include "base/task.h"
+#include "base/utf_string_conversions.h" // TODO(viettrungluu): delete me.
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
@@ -42,18 +43,8 @@ void SandboxedExtensionUnpacker::Start() {
// file IO on.
CHECK(ChromeThread::GetCurrentThreadIdentifier(&thread_identifier_));
- // To understand crbug/35198, allow users who can reproduce the bug
- // to loosen permissions on the scoped directory.
- bool loosen_permissions = false;
-#if defined (OS_WIN)
- loosen_permissions = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kIssue35198Permission);
- LOG(INFO) << "loosen_permissions = " << loosen_permissions;
-#endif
-
// Create a temporary directory to work in.
- if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_,
- loosen_permissions)) {
+ if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_)) {
ReportFailure("Could not create temporary directory.");
return;
}
@@ -62,15 +53,6 @@ void SandboxedExtensionUnpacker::Start() {
extension_root_ = temp_dir_.path().AppendASCII(
extension_filenames::kTempExtensionName);
- // To understand crbug/35198, allow users who can reproduce the bug to
- // create the unpack directory in the browser process.
- bool crxdir_in_browser = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kIssue35198CrxDirBrowser);
- LOG(INFO) << "crxdir_in_browser = " << crxdir_in_browser;
- if (crxdir_in_browser && !file_util::CreateDirectory(extension_root_)) {
- LOG(ERROR) << "Failed to create directory " << extension_root_.value();
- }
-
// Extract the public key and validate the package.
if (!ValidateSignature())
return; // ValidateSignature() already reported the error.
@@ -82,20 +64,6 @@ void SandboxedExtensionUnpacker::Start() {
return;
}
- // The utility process will have access to the directory passed to
- // SandboxedExtensionUnpacker. That directory should not contain a
- // symlink or NTFS junction, because when the path is used, following
- // the link will cause file system access outside the sandbox path.
- FilePath normalized_crx_path;
- if (!file_util::NormalizeFilePath(temp_crx_path, &normalized_crx_path)) {
- LOG(ERROR) << "Could not get the normalized path of "
- << temp_crx_path.value();
- normalized_crx_path = temp_crx_path;
- } else {
- LOG(INFO) << "RealFilePath: from " << temp_crx_path.value()
- << " to " << normalized_crx_path.value();
- }
-
// If we are supposed to use a subprocess, kick off the subprocess.
//
// TODO(asargent) we shouldn't need to do this branch here - instead
@@ -103,15 +71,42 @@ void SandboxedExtensionUnpacker::Start() {
bool use_utility_process = rdh_ &&
!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
if (use_utility_process) {
+ // The utility process will have access to the directory passed to
+ // SandboxedExtensionUnpacker. That directory should not contain a
+ // symlink or NTFS reparse point. When the path is used, following
+ // the link/reparse point will cause file system access outside the
+ // sandbox path, and the sandbox will deny the operation.
+ FilePath link_free_crx_path;
+ 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
+ return;
+ }
+
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableMethod(
this,
&SandboxedExtensionUnpacker::StartProcessOnIOThread,
- normalized_crx_path));
+ link_free_crx_path));
} else {
// Otherwise, unpack the extension in this process.
- ExtensionUnpacker unpacker(normalized_crx_path);
+ ExtensionUnpacker unpacker(temp_crx_path);
if (unpacker.Run() && unpacker.DumpImagesToFile() &&
unpacker.DumpMessageCatalogsToFile()) {
OnUnpackExtensionSucceeded(*unpacker.parsed_manifest());
@@ -218,6 +213,10 @@ bool SandboxedExtensionUnpacker::ValidateSignature() {
ReportFailure("Excessively large key or signature");
return false;
}
+ if (header.key_size == 0) {
+ ReportFailure("Key length is zero");
+ return false;
+ }
std::vector<uint8> key;
key.resize(header.key_size);
@@ -236,18 +235,9 @@ bool SandboxedExtensionUnpacker::ValidateSignature() {
return false;
}
- // Note: this structure is an ASN.1 which encodes the algorithm used
- // with its parameters. This is defined in PKCS #1 v2.1 (RFC 3447).
- // It is encoding: { OID sha1WithRSAEncryption PARAMETERS NULL }
- // TODO(aa): This needs to be factored away someplace common.
- const uint8 signature_algorithm[15] = {
- 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00
- };
-
base::SignatureVerifier verifier;
- if (!verifier.VerifyInit(signature_algorithm,
- sizeof(signature_algorithm),
+ if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm,
+ sizeof(extension_misc::kSignatureAlgorithm),
&signature.front(),
signature.size(),
&key.front(),
@@ -387,7 +377,9 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
return false;
}
- FilePath relative_path = FilePath::FromWStringHack(*key_it);
+ // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())|
+ // hack and remove the corresponding #include.
+ 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.");
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.h b/chrome/browser/extensions/sandboxed_extension_unpacker.h
index 60d02a9..00ee232 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker.h
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker.h
@@ -1,20 +1,20 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_SANDBOXED_EXTENSION_UNPACKER_H_
#define CHROME_BROWSER_EXTENSIONS_SANDBOXED_EXTENSION_UNPACKER_H_
+#pragma once
#include <string>
#include "base/file_path.h"
#include "base/ref_counted.h"
#include "base/scoped_temp_dir.h"
-#include "base/values.h"
#include "chrome/browser/utility_process_host.h"
+class DictionaryValue;
class Extension;
-class MessageLoop;
class ResourceDispatcherHost;
class SandboxedExtensionUnpackerClient
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc b/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc
index 748cd46..d461ff4 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc
@@ -8,7 +8,6 @@
#include "base/ref_counted.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
-#include "base/values.h"
#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
@@ -177,22 +176,23 @@ TEST_F(SandboxedExtensionUnpackerTest, WithCatalogsSuccess) {
ASSERT_TRUE(unpacker_->DumpImagesToFile());
ASSERT_TRUE(unpacker_->DumpMessageCatalogsToFile());
- // Check timestamp on _locales/en_US/messages.json.
+ // Set timestamp on _locales/en_US/messages.json into the past.
FilePath messages_file;
messages_file = GetInstallPath().Append(Extension::kLocaleFolder)
.AppendASCII("en_US")
.Append(Extension::kMessagesFilename);
- file_util::FileInfo old_info;
+ base::PlatformFileInfo old_info;
+ EXPECT_TRUE(file_util::GetFileInfo(messages_file, &old_info));
+ base::Time old_time =
+ old_info.last_modified - base::TimeDelta::FromSeconds(2);
+ EXPECT_TRUE(file_util::SetLastModifiedTime(messages_file, old_time));
+ // Refresh old_info, just to be sure.
EXPECT_TRUE(file_util::GetFileInfo(messages_file, &old_info));
- // unpacker_->Run unpacks the extension. OnUnpackSucceeded overwrites some
- // of the files. To force timestamp on overwriten files to be different we use
- // Sleep(1s). See comment on file_util::CountFilesCreatedAfter.
- PlatformThread::Sleep(1000);
OnUnpackSucceeded();
// Check that there is newer _locales/en_US/messages.json file.
- file_util::FileInfo new_info;
+ base::PlatformFileInfo new_info;
EXPECT_TRUE(file_util::GetFileInfo(messages_file, &new_info));
EXPECT_TRUE(new_info.last_modified > old_info.last_modified);
diff --git a/chrome/browser/extensions/stubs_apitest.cc b/chrome/browser/extensions/stubs_apitest.cc
index 091c9e3..72e3a48 100644
--- a/chrome/browser/extensions/stubs_apitest.cc
+++ b/chrome/browser/extensions/stubs_apitest.cc
@@ -5,6 +5,8 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/ui_test_utils.h"
+#include "googleurl/src/gurl.h"
+#include "net/test/test_server.h"
// Tests that we throw errors when you try using extension APIs that aren't
// supported in content scripts.
@@ -14,13 +16,13 @@
// should be available in content scripts) or update the list of privileged APIs
// in renderer_extension_bindings.js.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Stubs) {
- HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("stubs")) << message_;
// Navigate to a simple http:// page, which should get the content script
// injected and run the rest of the test.
- GURL url = server->TestServerPage("file/extensions/test_file.html");
+ GURL url(test_server()->GetURL("file/extensions/test_file.html"));
ui_test_utils::NavigateToURL(browser(), url);
ResultCatcher catcher;
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 8561a4b..5f4c94f 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -6,14 +6,13 @@
#include "base/file_util.h"
-#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/pref_value_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/common/extensions/extension_constants.h"
#include "chrome/common/json_pref_store.h"
diff --git a/chrome/browser/extensions/test_extension_prefs.h b/chrome/browser/extensions/test_extension_prefs.h
index 0ad84c1..b071281 100644
--- a/chrome/browser/extensions/test_extension_prefs.h
+++ b/chrome/browser/extensions/test_extension_prefs.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_PREFS_H_
#define CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_PREFS_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index 4e9ac35..6d00c22 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -9,10 +9,10 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
@@ -43,9 +43,9 @@ void ThemeInstalledInfoBarDelegate::InfoBarClosed() {
delete this;
}
-std::wstring ThemeInstalledInfoBarDelegate::GetMessageText() const {
- return l10n_util::GetStringF(IDS_THEME_INSTALL_INFOBAR_LABEL,
- UTF8ToWide(name_));
+string16 ThemeInstalledInfoBarDelegate::GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_THEME_INSTALL_INFOBAR_LABEL,
+ UTF8ToUTF16(name_));
}
SkBitmap* ThemeInstalledInfoBarDelegate::GetIcon() const {
@@ -64,16 +64,16 @@ int ThemeInstalledInfoBarDelegate::GetButtons() const {
return BUTTON_CANCEL;
}
-std::wstring ThemeInstalledInfoBarDelegate::GetButtonLabel(
+string16 ThemeInstalledInfoBarDelegate::GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const {
switch (button) {
case BUTTON_CANCEL: {
- return l10n_util::GetString(IDS_THEME_INSTALL_INFOBAR_UNDO_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_THEME_INSTALL_INFOBAR_UNDO_BUTTON);
}
default:
// The InfoBar will create a default OK button and make it invisible.
// TODO(mirandac): remove the default OK button from ConfirmInfoBar.
- return L"";
+ return string16();
}
}
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.h b/chrome/browser/extensions/theme_installed_infobar_delegate.h
index 7674a4c..2c54fa5 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_THEME_INSTALLED_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_EXTENSIONS_THEME_INSTALLED_INFOBAR_DELEGATE_H_
+#pragma once
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/common/notification_registrar.h"
@@ -22,11 +23,11 @@ class ThemeInstalledInfoBarDelegate : public ConfirmInfoBarDelegate,
const std::string& previous_theme_id);
virtual ~ThemeInstalledInfoBarDelegate();
virtual void InfoBarClosed();
- virtual std::wstring GetMessageText() const;
+ virtual string16 GetMessageText() const;
virtual SkBitmap* GetIcon() const;
virtual ThemeInstalledInfoBarDelegate* AsThemePreviewInfobarDelegate();
virtual int GetButtons() const;
- virtual std::wstring GetButtonLabel(
+ virtual string16 GetButtonLabel(
ConfirmInfoBarDelegate::InfoBarButton button) const;
virtual bool Cancel();
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
index aba4a6b..111d5ba 100644
--- a/chrome/browser/extensions/user_script_listener.cc
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -10,6 +10,7 @@
#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"
+#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/notification_service.h"
#include "net/url_request/url_request.h"
@@ -66,6 +67,9 @@ void UserScriptListener::WillShutdownResourceQueue() {
resource_queue_ = NULL;
}
+UserScriptListener::~UserScriptListener() {
+}
+
void UserScriptListener::StartDelayedRequests() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
diff --git a/chrome/browser/extensions/user_script_listener.h b/chrome/browser/extensions/user_script_listener.h
index f10240b..05de21a 100644
--- a/chrome/browser/extensions/user_script_listener.h
+++ b/chrome/browser/extensions/user_script_listener.h
@@ -4,15 +4,17 @@
#ifndef CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_LISTENER_H_
#define CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_LISTENER_H_
+#pragma once
#include <list>
#include "base/ref_counted.h"
#include "chrome/browser/renderer_host/resource_queue.h"
-#include "chrome/common/extensions/url_pattern.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class Extension;
+class URLPattern;
class URLRequest;
struct GlobalRequestID;
@@ -46,7 +48,7 @@ class UserScriptListener
typedef std::list<URLPattern> URLPatterns;
- ~UserScriptListener() {}
+ ~UserScriptListener();
// Resume any requests that we delayed in order to wait for user scripts.
void StartDelayedRequests();
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 2f2ced5..6605936 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -1,4 +1,4 @@
-// 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.
@@ -88,7 +88,7 @@ bool UserScriptMaster::ScriptReloader::ParseMetadataHeader(
std::string value;
if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
- // We escape some characters that MatchPatternASCII() considers special.
+ // We escape some characters that MatchPattern() considers special.
ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
script->add_glob(value);
@@ -174,7 +174,6 @@ static bool LoadScriptContent(UserScript::File* script_file) {
script_file->set_content(content);
}
- LOG(INFO) << "Loaded user script file: " << path.value();
return true;
}
@@ -254,7 +253,7 @@ static base::SharedMemory* Serialize(const UserScriptList& scripts) {
// Create the shared memory object.
scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
- if (!shared_memory->Create(std::wstring(), // anonymous
+ if (!shared_memory->Create(std::string(), // anonymous
false, // read-only
false, // open existing
pickle.size()))
diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h
index 964fc73..82adab0 100644
--- a/chrome/browser/extensions/user_script_master.h
+++ b/chrome/browser/extensions/user_script_master.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_MASTER_H_
#define CHROME_BROWSER_EXTENSIONS_USER_SCRIPT_MASTER_H_
+#pragma once
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
@@ -11,13 +12,13 @@
#include "base/shared_memory.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/extensions/user_script.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
namespace base {
class StringPiece;
}
-class Extension;
class Profile;
// Manages a segment of shared memory that contains the user scripts the user
diff --git a/chrome/browser/external_protocol_handler.cc b/chrome/browser/external_protocol_handler.cc
index d8bb81d..e005780 100644
--- a/chrome/browser/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol_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.
@@ -15,7 +15,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"
@@ -32,33 +32,33 @@ void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) {
return;
is_warm = true;
- static const wchar_t* const denied_schemes[] = {
- L"afp",
- L"data",
- L"disk",
- L"disks",
+ static const char* const denied_schemes[] = {
+ "afp",
+ "data",
+ "disk",
+ "disks",
// ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply
// execute the file specified! Hopefully we won't see any "file" schemes
// because we think of file:// URLs as handled URLs, but better to be safe
// than to let an attacker format the user's hard drive.
- L"file",
- L"hcp",
- L"javascript",
- L"ms-help",
- L"nntp",
- L"shell",
- L"vbscript",
+ "file",
+ "hcp",
+ "javascript",
+ "ms-help",
+ "nntp",
+ "shell",
+ "vbscript",
// view-source is a special case in chrome. When it comes through an
// iframe or a redirect, it looks like an external protocol, but we don't
// want to shellexecute it.
- L"view-source",
- L"vnd.ms.radio",
+ "view-source",
+ "vnd.ms.radio",
};
- static const wchar_t* const allowed_schemes[] = {
- L"mailto",
- L"news",
- L"snews",
+ static const char* const allowed_schemes[] = {
+ "mailto",
+ "news",
+ "snews",
};
bool should_block;
@@ -77,7 +77,7 @@ void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) {
// static
ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState(
- const std::wstring& scheme) {
+ const std::string& scheme) {
// If we are being carpet bombed, block the request.
if (!g_accept_requests)
return BLOCK;
@@ -110,7 +110,7 @@ ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState(
}
// static
-void ExternalProtocolHandler::SetBlockState(const std::wstring& scheme,
+void ExternalProtocolHandler::SetBlockState(const std::string& scheme,
BlockState state) {
// Set in the stored prefs.
// TODO(pkasting): http://b/1119651 This kind of thing should go in the
@@ -138,7 +138,7 @@ void ExternalProtocolHandler::LaunchUrl(const GURL& url,
// have parameters unexpected by the external program.
std::string escaped_url_string = EscapeExternalHandlerValue(url.spec());
GURL escaped_url(escaped_url_string);
- BlockState block_state = GetBlockState(ASCIIToWide(escaped_url.scheme()));
+ BlockState block_state = GetBlockState(escaped_url.scheme());
if (block_state == BLOCK)
return;
@@ -180,7 +180,7 @@ void ExternalProtocolHandler::RegisterPrefs(PrefService* prefs) {
}
// static
-void ExternalProtocolHandler::OnUserGesture() {
+void ExternalProtocolHandler::PermitLaunchUrl() {
DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
g_accept_requests = true;
}
diff --git a/chrome/browser/external_protocol_handler.h b/chrome/browser/external_protocol_handler.h
index 20c82bc..f822cc8 100644
--- a/chrome/browser/external_protocol_handler.h
+++ b/chrome/browser/external_protocol_handler.h
@@ -1,15 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_EXTERNAL_PROTOCOL_HANDLER_H_
#define CHROME_BROWSER_EXTERNAL_PROTOCOL_HANDLER_H_
+#pragma once
#include <string>
class DictionaryValue;
class GURL;
-class MessageLoop;
class PrefService;
class ExternalProtocolHandler {
@@ -21,10 +21,10 @@ class ExternalProtocolHandler {
};
// Returns whether we should block a given scheme.
- static BlockState GetBlockState(const std::wstring& scheme);
+ static BlockState GetBlockState(const std::string& scheme);
// Sets whether we should block a given scheme.
- static void SetBlockState(const std::wstring& scheme, BlockState state);
+ static void SetBlockState(const std::string& scheme, BlockState state);
// Checks to see if the protocol is allowed, if it is whitelisted,
// the application associated with the protocol is launched on the io thread,
@@ -68,8 +68,11 @@ class ExternalProtocolHandler {
// preferences for them do not already exist.
static void PrepopulateDictionary(DictionaryValue* win_pref);
- // Called when the user interacts with a web page.
- static void OnUserGesture();
+ // Allows LaunchUrl to proceed with launching an external protocol handler.
+ // This is typically triggered by a user gesture, but is also called for
+ // each extension API function. Note that each call to LaunchUrl resets
+ // the state to false (not allowed).
+ static void PermitLaunchUrl();
};
#endif // CHROME_BROWSER_EXTERNAL_PROTOCOL_HANDLER_H_
diff --git a/chrome/browser/external_tab_container_win.cc b/chrome/browser/external_tab_container_win.cc
index 3257cdc..d2abbb0 100644
--- a/chrome/browser/external_tab_container_win.cc
+++ b/chrome/browser/external_tab_container_win.cc
@@ -6,9 +6,9 @@
#include <string>
-#include "app/win_util.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
+#include "base/trace_event.h"
#include "base/win_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/automation/automation_provider.h"
@@ -16,6 +16,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
+#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"
@@ -29,6 +30,7 @@
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/page_transition_types.h"
@@ -55,13 +57,11 @@ ExternalTabContainer::ExternalTabContainer(
handle_top_level_requests_(false),
external_method_factory_(this),
enabled_extension_automation_(false),
- waiting_for_unload_event_(false),
pending_(false),
infobars_enabled_(true),
focus_manager_(NULL),
external_tab_view_(NULL),
- notification_window_(NULL),
- notification_message_(NULL) {
+ unload_reply_message_(NULL) {
}
ExternalTabContainer::~ExternalTabContainer() {
@@ -104,7 +104,8 @@ bool ExternalTabContainer::Init(Profile* profile,
tab_contents_ = existing_contents;
tab_contents_->controller().set_profile(profile);
} else {
- tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL);
+ tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE,
+ NULL, NULL);
}
tab_contents_->set_delegate(this);
@@ -221,10 +222,6 @@ bool ExternalTabContainer::Reinitialize(
void ExternalTabContainer::SetTabHandle(int handle) {
tab_handle_ = handle;
- if (automation_resource_message_filter_.get() &&
- load_requests_via_automation_) {
- InitializeAutomationRequestContext(tab_handle_);
- }
}
void ExternalTabContainer::ProcessUnhandledAccelerator(const MSG& msg) {
@@ -286,10 +283,10 @@ ExternalTabContainer*
// ExternalTabContainer, TabContentsDelegate implementation:
void ExternalTabContainer::OpenURLFromTab(TabContents* source,
- const GURL& url,
- const GURL& referrer,
- WindowOpenDisposition disposition,
- PageTransition::Type transition) {
+ const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {
if (pending()) {
PendingTopLevelNavigation url_request;
url_request.disposition = disposition;
@@ -326,7 +323,9 @@ void ExternalTabContainer::OpenURLFromTab(TabContents* source,
NavigationController::LoadCommittedDetails details;
details.did_replace_entry = false;
- tab_contents_->UpdateHistoryForNavigation(url, details, params);
+ scoped_refptr<history::HistoryAddPageArgs> add_page_args(
+ tab_contents_->CreateHistoryAddPageArgs(url, details, params));
+ tab_contents_->UpdateHistoryForNavigation(add_page_args);
}
break;
default:
@@ -383,6 +382,8 @@ void ExternalTabContainer::AddNewContents(TabContents* source,
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,
tab_handle_, attach_params_));
} else {
@@ -407,19 +408,23 @@ bool ExternalTabContainer::infobars_enabled() {
void ExternalTabContainer::ActivateContents(TabContents* contents) {
}
+void ExternalTabContainer::DeactivateContents(TabContents* contents) {
+}
+
void ExternalTabContainer::LoadingStateChanged(TabContents* source) {
}
void ExternalTabContainer::CloseContents(TabContents* source) {
- static const int kExternalTabCloseContentsDelayMS = 100;
+ if (!automation_)
+ return;
- if (waiting_for_unload_event_) {
- PostMessage(notification_window_, notification_message_, 0, 0);
- waiting_for_unload_event_ = false;
+ if (unload_reply_message_) {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_,
+ true);
+ automation_->Send(unload_reply_message_);
+ unload_reply_message_ = NULL;
} else {
- if (automation_) {
- automation_->Send(new AutomationMsg_CloseExternalTab(0, tab_handle_));
- }
+ automation_->Send(new AutomationMsg_CloseExternalTab(0, tab_handle_));
}
}
@@ -427,10 +432,6 @@ void ExternalTabContainer::MoveContents(TabContents* source,
const gfx::Rect& pos) {
}
-bool ExternalTabContainer::IsPopup(TabContents* source) {
- return false;
-}
-
void ExternalTabContainer::URLStarredChanged(TabContents* source,
bool starred) {
}
@@ -461,6 +462,10 @@ void ExternalTabContainer::ForwardMessageToExternalHost(
}
}
+bool ExternalTabContainer::IsExternalTabContainer() const {
+ return true;
+}
+
gfx::NativeWindow ExternalTabContainer::GetFrameNativeWindow() {
return hwnd();
}
@@ -610,6 +615,27 @@ void ExternalTabContainer::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
browser_->window()->ShowHTMLDialog(delegate, parent);
}
+void ExternalTabContainer::BeforeUnloadFired(TabContents* tab,
+ bool proceed,
+ bool* proceed_to_fire_unload) {
+ DCHECK(unload_reply_message_);
+ *proceed_to_fire_unload = true;
+
+ if (!automation_) {
+ delete unload_reply_message_;
+ unload_reply_message_ = NULL;
+ return;
+ }
+
+ if (!proceed) {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_,
+ false);
+ automation_->Send(unload_reply_message_);
+ unload_reply_message_ = NULL;
+ *proceed_to_fire_unload = false;
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// ExternalTabContainer, NotificationObserver implementation:
@@ -627,6 +653,8 @@ void ExternalTabContainer::Observe(NotificationType type,
const LoadNotificationDetails* load =
Details<LoadNotificationDetails>(details).ptr();
if (load != NULL && PageTransition::IsMainFrame(load->origin())) {
+ TRACE_EVENT_END("ExternalTabContainer::Navigate", 0,
+ load->url().spec());
automation_->Send(new AutomationMsg_TabLoaded(0, tab_handle_,
load->url()));
}
@@ -713,20 +741,24 @@ void ExternalTabContainer::OnFinalMessage(HWND window) {
Release();
}
-void ExternalTabContainer::RunUnloadHandlers(
- gfx::NativeWindow notification_window,
- int notification_message) {
- DCHECK(::IsWindow(notification_window));
- if (tab_contents_) {
- notification_window_ = notification_window;
- notification_message_ = notification_message;
+void ExternalTabContainer::RunUnloadHandlers(IPC::Message* reply_message) {
+ if (!automation_) {
+ delete reply_message;
+ return;
+ }
- if (Browser::RunUnloadEventsHelper(tab_contents_)) {
- waiting_for_unload_event_ = true;
- }
+ // If we have a pending unload message, then just respond back to this
+ // request and continue processing the previous unload message.
+ if (unload_reply_message_) {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(reply_message, true);
+ automation_->Send(reply_message);
+ return;
}
- if (!waiting_for_unload_event_) {
- PostMessage(notification_window, notification_message, 0, 0);
+ if (tab_contents_ && Browser::RunUnloadEventsHelper(tab_contents_)) {
+ unload_reply_message_ = reply_message;
+ } else {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(reply_message, true);
+ automation_->Send(reply_message);
}
}
@@ -772,6 +804,7 @@ bool ExternalTabContainer::InitNavigationInfo(IPC::NavigationInfo* nav_info,
nav_info->navigation_index =
tab_contents_->controller().GetCurrentEntryIndex();
nav_info->url = entry->url();
+ nav_info->referrer = entry->referrer();
nav_info->title = UTF16ToWideHack(entry->title());
if (nav_info->title.empty())
nav_info->title = UTF8ToWide(nav_info->url.spec());
@@ -874,6 +907,8 @@ void ExternalTabContainer::Navigate(const GURL& url, const GURL& referrer) {
return;
}
+ TRACE_EVENT_BEGIN("ExternalTabContainer::Navigate", 0, url.spec());
+
tab_contents_->controller().LoadURL(url, referrer,
PageTransition::START_PAGE);
}
@@ -888,17 +923,6 @@ bool ExternalTabContainer::OnGoToEntryOffset(int offset) {
return true;
}
-void ExternalTabContainer::InitializeAutomationRequestContext(
- int tab_handle) {
- request_context_ =
- AutomationRequestContext::CreateAutomationURLRequestContextForTab(
- tab_handle, tab_contents_->profile(),
- automation_resource_message_filter_);
-
- DCHECK(request_context_.get() != NULL);
- tab_contents_->set_request_context(request_context_.get());
-}
-
void ExternalTabContainer::LoadAccelerators() {
HACCEL accelerator_table = AtlLoadAccelerators(IDR_CHROMEFRAME);
DCHECK(accelerator_table);
@@ -925,7 +949,7 @@ void ExternalTabContainer::LoadAccelerators() {
bool ctrl_down = (accelerators[i].fVirt & FCONTROL) == FCONTROL;
bool shift_down = (accelerators[i].fVirt & FSHIFT) == FSHIFT;
views::Accelerator accelerator(
- static_cast<base::KeyboardCode>(accelerators[i].key),
+ static_cast<app::KeyboardCode>(accelerators[i].key),
shift_down, ctrl_down, alt_down);
accelerator_table_[accelerator] = accelerators[i].cmd;
@@ -937,8 +961,6 @@ void ExternalTabContainer::LoadAccelerators() {
void ExternalTabContainer::OnReinitialize() {
if (load_requests_via_automation_) {
- InitializeAutomationRequestContext(tab_handle_);
-
RenderViewHost* rvh = tab_contents_->render_view_host();
if (rvh) {
AutomationResourceMessageFilter::ResumePendingRenderView(
@@ -998,4 +1020,3 @@ void ExternalTabContainer::SetupExternalTabView() {
// Note that SetTabContents must be called after AddChildView is called
tab_contents_container_->ChangeTabContents(tab_contents_);
}
-
diff --git a/chrome/browser/external_tab_container_win.h b/chrome/browser/external_tab_container_win.h
index 1d92f49..1148285 100644
--- a/chrome/browser/external_tab_container_win.h
+++ b/chrome/browser/external_tab_container_win.h
@@ -4,12 +4,12 @@
#ifndef CHROME_BROWSER_EXTERNAL_TAB_CONTAINER_WIN_H_
#define CHROME_BROWSER_EXTERNAL_TAB_CONTAINER_WIN_H_
+#pragma once
#include <vector>
#include <map>
#include "base/lazy_instance.h"
#include "chrome/browser/automation/automation_resource_message_filter.h"
-#include "chrome/browser/automation/automation_profile_impl.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -117,10 +117,10 @@ class ExternalTabContainer : public TabContentsDelegate,
const gfx::Rect& initial_pos,
bool user_gesture);
virtual void ActivateContents(TabContents* contents);
+ virtual void DeactivateContents(TabContents* contents);
virtual void LoadingStateChanged(TabContents* source);
virtual void CloseContents(TabContents* source);
virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
- virtual bool IsPopup(TabContents* source);
virtual void URLStarredChanged(TabContents* source, bool starred);
virtual void UpdateTargetURL(TabContents* source, const GURL& url);
virtual void ContentsZoomChange(bool zoom_in);
@@ -128,9 +128,7 @@ class ExternalTabContainer : public TabContentsDelegate,
virtual void ForwardMessageToExternalHost(const std::string& message,
const std::string& origin,
const std::string& target);
- virtual bool IsExternalTabContainer() const {
- return true;
- };
+ virtual bool IsExternalTabContainer() const;
virtual gfx::NativeWindow GetFrameNativeWindow();
virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
@@ -148,17 +146,6 @@ class ExternalTabContainer : public TabContentsDelegate,
const NavigationEntry::SSLStatus& ssl,
bool show_history);
- virtual Browser* GetBrowser() { return browser_.get(); }
-
- // Overriden from TabContentsDelegate::AutomationResourceRoutingDelegate
- virtual void RegisterRenderViewHost(RenderViewHost* render_view_host);
- virtual void UnregisterRenderViewHost(RenderViewHost* render_view_host);
-
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
// Handles the context menu display operation. This allows external
// hosts to customize the menu.
virtual bool HandleContextMenu(const ContextMenuParams& params);
@@ -174,6 +161,19 @@ class ExternalTabContainer : public TabContentsDelegate,
virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
gfx::NativeWindow parent_window);
+ virtual void BeforeUnloadFired(TabContents* tab,
+ bool proceed,
+ bool* proceed_to_fire_unload);
+
+ // Overriden from TabContentsDelegate::AutomationResourceRoutingDelegate
+ virtual void RegisterRenderViewHost(RenderViewHost* render_view_host);
+ virtual void UnregisterRenderViewHost(RenderViewHost* render_view_host);
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
// Returns the ExternalTabContainer instance associated with the cookie
// passed in. It also erases the corresponding reference from the map.
// Returns NULL if we fail to find the cookie in the map.
@@ -206,8 +206,7 @@ class ExternalTabContainer : public TabContentsDelegate,
virtual bool infobars_enabled();
- void RunUnloadHandlers(gfx::NativeWindow notification_window,
- int notification_message);
+ void RunUnloadHandlers(IPC::Message* reply_message);
protected:
// Overridden from views::WidgetWin:
@@ -220,9 +219,6 @@ class ExternalTabContainer : public TabContentsDelegate,
int relative_offset);
void Navigate(const GURL& url, const GURL& referrer);
- // Initializes the request context to be used for automation HTTP requests.
- void InitializeAutomationRequestContext(int tab_handle);
-
private:
friend class base::RefCounted<ExternalTabContainer>;
@@ -313,9 +309,6 @@ class ExternalTabContainer : public TabContentsDelegate,
// A mapping between accelerators and commands.
std::map<views::Accelerator, int> accelerator_table_;
- // Set to true if the tab is waiting for the unload event to complete.
- bool waiting_for_unload_event_;
-
// Contains the list of URL requests which are pending waiting for an ack
// from the external host.
std::vector<PendingTopLevelNavigation> pending_open_url_requests_;
@@ -331,8 +324,7 @@ class ExternalTabContainer : public TabContentsDelegate,
views::View* external_tab_view_;
- gfx::NativeWindow notification_window_;
- int notification_message_;
+ IPC::Message* unload_reply_message_;
DISALLOW_COPY_AND_ASSIGN(ExternalTabContainer);
};
diff --git a/chrome/browser/fav_icon_helper.cc b/chrome/browser/fav_icon_helper.cc
index cfaae6d..a6d2e1b 100644
--- a/chrome/browser/fav_icon_helper.cc
+++ b/chrome/browser/fav_icon_helper.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.
@@ -6,6 +6,8 @@
#include "build/build_config.h"
+#include <vector>
+
#include "base/callback.h"
#include "base/ref_counted_memory.h"
#include "chrome/browser/profile.h"
diff --git a/chrome/browser/fav_icon_helper.h b/chrome/browser/fav_icon_helper.h
index d1922f5..8eb7f17 100644
--- a/chrome/browser/fav_icon_helper.h
+++ b/chrome/browser/fav_icon_helper.h
@@ -4,13 +4,13 @@
#ifndef CHROME_BROWSER_FAV_ICON_HELPER_H__
#define CHROME_BROWSER_FAV_ICON_HELPER_H__
+#pragma once
#include <map>
-#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
diff --git a/chrome/browser/favicon_service.cc b/chrome/browser/favicon_service.cc
index 94baaf7..51b9098 100644
--- a/chrome/browser/favicon_service.cc
+++ b/chrome/browser/favicon_service.cc
@@ -84,6 +84,9 @@ void FaviconService::SetFavicon(const GURL& page_url,
hs->SetFavicon(page_url, icon_url, image_data);
}
+FaviconService::~FaviconService() {
+}
+
void FaviconService::ForwardEmptyResultAsync(GetFaviconRequest* request) {
request->ForwardResultAsync(FaviconDataCallback::TupleType(request->handle(),
false, NULL, false, GURL()));
diff --git a/chrome/browser/favicon_service.h b/chrome/browser/favicon_service.h
index a7b500c..b6ef85b 100644
--- a/chrome/browser/favicon_service.h
+++ b/chrome/browser/favicon_service.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_FAVICON_SERVICE_H__
#define CHROME_BROWSER_FAVICON_SERVICE_H__
+#pragma once
#include <vector>
@@ -89,7 +90,7 @@ class FaviconService : public CancelableRequestProvider,
private:
friend class base::RefCountedThreadSafe<FaviconService>;
- ~FaviconService() {}
+ ~FaviconService();
Profile* profile_;
diff --git a/chrome/browser/file_path_watcher.h b/chrome/browser/file_path_watcher.h
new file mode 100644
index 0000000..b8c857f
--- /dev/null
+++ b/chrome/browser/file_path_watcher.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.
+
+// 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/chrome_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() {
+ impl_->Cancel();
+ }
+
+ // 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 {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ DCHECK(path.IsAbsolute());
+ return impl_->Watch(path, delegate);
+ }
+
+ // Used internally to encapsulate different members on different platforms.
+ class PlatformDelegate
+ : public base::RefCountedThreadSafe<PlatformDelegate,
+ ChromeThread::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_inotify.cc b/chrome/browser/file_path_watcher_inotify.cc
new file mode 100644
index 0000000..744e9a1
--- /dev/null
+++ b/chrome/browser/file_path_watcher_inotify.cc
@@ -0,0 +1,410 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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) {
+ ChromeThread::PostTask(ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::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 (!ChromeThread::CurrentlyOn(ChromeThread::FILE)) {
+ ChromeThread::PostTask(ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::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
new file mode 100644
index 0000000..b95992c
--- /dev/null
+++ b/chrome/browser/file_path_watcher_mac.cc
@@ -0,0 +1,232 @@
+// Copyright (c) 2009 The Chromium Authors. All rights 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/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(ChromeThread::CurrentlyOn(ChromeThread::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.
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(watcher, &FilePathWatcherImpl::UpdateEventStream,
+ root_change_at));
+ }
+
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(watcher, &FilePathWatcherImpl::OnFilePathChanged));
+}
+
+// FilePathWatcherImpl implementation:
+
+FilePathWatcherImpl::FilePathWatcherImpl()
+ : fsevent_stream_(NULL),
+ canceled_(false) {
+}
+
+void FilePathWatcherImpl::OnFilePathChanged() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::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();
+ }
+
+ ChromeThread::PostTask(ChromeThread::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 (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
+ return;
+ }
+
+ canceled_ = true;
+ if (fsevent_stream_)
+ DestroyEventStream();
+}
+
+void FilePathWatcherImpl::UpdateEventStream(FSEventStreamEventId start_event) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::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();
+
+ scoped_cftyperef<CFStringRef> cf_path(CFStringCreateWithCString(
+ NULL, target_.value().c_str(), kCFStringEncodingMacHFS));
+ scoped_cftyperef<CFStringRef> cf_dir_path(CFStringCreateWithCString(
+ NULL, target_.DirName().value().c_str(), kCFStringEncodingMacHFS));
+ CFStringRef paths_array[] = { cf_path.get(), cf_dir_path.get() };
+ scoped_cftyperef<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_)) {
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(delegate_.get(),
+ &FilePathWatcher::Delegate::OnError));
+ }
+}
+
+void FilePathWatcherImpl::DestroyEventStream() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::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
new file mode 100644
index 0000000..5112f48
--- /dev/null
+++ b/chrome/browser/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.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_unittest.cc b/chrome/browser/file_path_watcher_unittest.cc
new file mode 100644
index 0000000..82dfe99
--- /dev/null
+++ b/chrome/browser/file_path_watcher_unittest.cc
@@ -0,0 +1,466 @@
+// 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/file_path_watcher.h"
+
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/lock.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/platform_thread.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "base/thread.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 {
+
+// The time we wait for events to happen. It should be large enough to be
+// reasonably sure all notifications sent in response to file system
+// modifications made by the test are processed. This must also accomodate for
+// the latency interval we pass to the Mac FSEvents API.
+const int kWaitForEventTime = 1000;
+
+// 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 implement simple thread safe call counters in TestDelegate.
+class TestDelegate : public FilePathWatcher::Delegate {
+ public:
+ TestDelegate()
+ : change_count_(0),
+ error_count_(0) {}
+
+ virtual void OnFilePathChanged(const FilePath&) {
+ AutoLock lock(lock_);
+ ++change_count_;
+ }
+
+ virtual void OnError() {
+ AutoLock lock(lock_);
+ ++error_count_;
+ }
+
+ void GetCountsAndReset(int* changes, int* errors) {
+ AutoLock lock(lock_);
+ *errors = error_count_;
+ *changes = change_count_;
+ error_count_ = 0;
+ change_count_ = 0;
+ }
+
+ private:
+ Lock lock_;
+ int change_count_;
+ int error_count_;
+
+ 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_(ChromeThread::UI, &loop_) {
+ }
+
+ protected:
+ virtual void SetUp() {
+ // Create a separate file thread in order to test proper thread usage.
+ file_thread_.reset(new ChromeThread(ChromeThread::FILE));
+ file_thread_->Start();
+ temp_dir_.reset(new ScopedTempDir);
+ ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
+ }
+
+ 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());
+ SyncIfPOSIX();
+ 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;
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ new SetupWatchTask(target, watcher, delegate, &result, &completion));
+ completion.Wait();
+ ASSERT_TRUE(result);
+ }
+
+ int WaitForEvents(TestDelegate* delegate) {
+ // Wait for events and check the expectations of the delegate.
+ loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask,
+ kWaitForEventTime);
+ loop_.Run();
+ int errors;
+ int changes;
+ delegate->GetCountsAndReset(&changes, &errors);
+ EXPECT_EQ(0, errors);
+ return changes;
+ }
+
+ // We need this function for reliable tests on Mac OS X. FSEvents API
+ // has a latency interval and can merge multiple events into one,
+ // and we need a clear distinction between events triggered by test setup code
+ // and test code.
+ void SyncIfPOSIX() {
+#if defined(OS_POSIX)
+ sync();
+#endif // defined(OS_POSIX)
+ }
+
+ MessageLoop loop_;
+ ChromeThread ui_thread_;
+ scoped_ptr<ChromeThread> file_thread_;
+ scoped_ptr<ScopedTempDir> temp_dir_;
+};
+
+// Basic test: Create the file and verify that we notice.
+TEST_F(FilePathWatcherTest, MAYBE(NewFile)) {
+ FilePathWatcher watcher;
+ scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+// 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);
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ // Now make sure we get notified if the file is modified.
+ ASSERT_TRUE(WriteFile(test_file(), "new content"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+// 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);
+ 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()));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+TEST_F(FilePathWatcherTest, MAYBE(DeletedFile)) {
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+ FilePathWatcher watcher;
+ scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ // Now make sure we get notified if the file is deleted.
+ file_util::Delete(test_file(), false);
+ SyncIfPOSIX();
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+// Verify that letting the watcher go out of scope stops notifications.
+TEST_F(FilePathWatcherTest, Unregister) {
+ scoped_refptr<TestDelegate> delegate(new TestDelegate);
+
+ {
+ FilePathWatcher watcher;
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ // And then let it fall out of scope, clearing its watch.
+ }
+
+ // Write a file to the test dir.
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ EXPECT_EQ(0, WaitForEvents(delegate.get()));
+}
+
+namespace {
+// 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_;
+};
+} // anonymous namespace
+
+// 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"));
+ loop_.Run();
+
+ // 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);
+ FilePathWatcher* watcher = new FilePathWatcher;
+ SetupWatch(test_file(), watcher, delegate.get());
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ ChromeThread::DeleteSoon(ChromeThread::FILE, FROM_HERE, watcher);
+ // Success if there is no crash or DCHECK when running the callback.
+ WaitForEvents(delegate.get());
+}
+
+TEST_F(FilePathWatcherTest, MAYBE(MultipleWatchersSingleFile)) {
+ FilePathWatcher watcher1, watcher2;
+ scoped_refptr<TestDelegate> delegate1(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate2(new TestDelegate);
+ SetupWatch(test_file(), &watcher1, delegate1.get());
+ SetupWatch(test_file(), &watcher2, delegate2.get());
+
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ EXPECT_LE(1, WaitForEvents(delegate1.get()));
+ EXPECT_LE(1, WaitForEvents(delegate2.get()));
+}
+
+// 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);
+ SetupWatch(file, &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::CreateDirectory(dir));
+ EXPECT_EQ(0, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(file, "content"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(file, "content v2"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(file_util::Delete(file, false));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+// 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);
+ 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"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(file, "content v2"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+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);
+ SetupWatch(file, &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::Delete(dir, true));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(file_util::CreateDirectory(dir));
+ EXPECT_EQ(0, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(file, "content v2"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+// 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);
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::Delete(test_file(), false));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+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);
+ SetupWatch(dir, &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::CreateDirectory(dir));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(file1, "content"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(file1, "content v2"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(file_util::Delete(file1, false));
+ SyncIfPOSIX();
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+
+ ASSERT_TRUE(WriteFile(file2, "content"));
+ EXPECT_LE(1, WaitForEvents(delegate.get()));
+}
+
+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);
+ SetupWatch(file, &file_watcher, file_delegate.get());
+ scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate);
+ SetupWatch(subdir, &subdir_watcher, subdir_delegate.get());
+
+ // Setup a directory hierarchy.
+ ASSERT_TRUE(file_util::CreateDirectory(subdir));
+ ASSERT_TRUE(WriteFile(file, "content"));
+ EXPECT_LE(1, WaitForEvents(file_delegate.get()));
+ EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
+
+ // Move the parent directory.
+ file_util::Move(dir, dest);
+ EXPECT_LE(1, WaitForEvents(file_delegate.get()));
+ EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
+
+ // Recreate the hierarchy.
+ ASSERT_TRUE(file_util::CreateDirectory(subdir));
+ ASSERT_TRUE(WriteFile(file, "content"));
+ EXPECT_LE(1, WaitForEvents(file_delegate.get()));
+ EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
+}
+
+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"));
+ scoped_refptr<TestDelegate> file_delegate(new TestDelegate);
+ SetupWatch(dest_file, &file_watcher, file_delegate.get());
+ scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate);
+ SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get());
+
+ // Setup a directory hierarchy.
+ ASSERT_TRUE(file_util::CreateDirectory(source_subdir));
+ ASSERT_TRUE(WriteFile(source_file, "content"));
+ EXPECT_EQ(0, WaitForEvents(file_delegate.get()));
+ EXPECT_EQ(0, WaitForEvents(subdir_delegate.get()));
+
+ // Move the directory into place, s.t. the watched file appears.
+ ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
+ EXPECT_LE(1, WaitForEvents(file_delegate.get()));
+ EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
+}
+
+} // namespace
diff --git a/chrome/browser/file_path_watcher_win.cc b/chrome/browser/file_path_watcher_win.cc
new file mode 100644
index 0000000..71622f9
--- /dev/null
+++ b/chrome/browser/file_path_watcher_win.cc
@@ -0,0 +1,243 @@
+// Copyright (c) 2009 The Chromium Authors. All rights 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 (!ChromeThread::CurrentlyOn(ChromeThread::FILE)) {
+ ChromeThread::PostTask(ChromeThread::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_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
new file mode 100644
index 0000000..6ee0b73
--- /dev/null
+++ b/chrome/browser/file_select_helper.cc
@@ -0,0 +1,242 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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_select_helper.h"
+
+#include "app/l10n_util.h"
+#include "base/file_util.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#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/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"
+#include "grit/generated_resources.h"
+
+FileSelectHelper::FileSelectHelper(Profile* profile)
+ : profile_(profile),
+ render_view_host_(NULL),
+ select_file_dialog_(),
+ dialog_type_(SelectFileDialog::SELECT_OPEN_FILE) {
+}
+
+FileSelectHelper::~FileSelectHelper() {
+ // There may be pending file dialogs, we need to tell them that we've gone
+ // away so they don't try and call back to us.
+ if (select_file_dialog_.get())
+ select_file_dialog_->ListenerDestroyed();
+
+ // Stop any pending directory enumeration and prevent a callback.
+ if (directory_lister_.get()) {
+ directory_lister_->set_delegate(NULL);
+ directory_lister_->Cancel();
+ }
+}
+
+void FileSelectHelper::FileSelected(const FilePath& path,
+ int index, void* params) {
+ if (!render_view_host_)
+ return;
+
+ profile_->set_last_selected_directory(path.DirName());
+
+ if (dialog_type_ == SelectFileDialog::SELECT_FOLDER) {
+ DirectorySelected(path);
+ return;
+ }
+
+ std::vector<FilePath> files;
+ files.push_back(path);
+ render_view_host_->FilesSelectedInChooser(files);
+ // We are done with this showing of the dialog.
+ render_view_host_ = NULL;
+}
+
+void FileSelectHelper::MultiFilesSelected(const std::vector<FilePath>& files,
+ void* params) {
+ if (!files.empty())
+ profile_->set_last_selected_directory(files[0].DirName());
+ if (!render_view_host_)
+ return;
+
+ render_view_host_->FilesSelectedInChooser(files);
+ // We are done with this showing of the dialog.
+ render_view_host_ = NULL;
+}
+
+void FileSelectHelper::FileSelectionCanceled(void* params) {
+ if (!render_view_host_)
+ return;
+
+ // If the user cancels choosing a file to upload we pass back an
+ // empty vector.
+ render_view_host_->FilesSelectedInChooser(std::vector<FilePath>());
+
+ // We are done with this showing of the dialog.
+ render_view_host_ = NULL;
+}
+
+void FileSelectHelper::DirectorySelected(const FilePath& path) {
+ directory_lister_ = new net::DirectoryLister(path,
+ true,
+ net::DirectoryLister::NO_SORT,
+ this);
+ if (!directory_lister_->Start())
+ FileSelectionCanceled(NULL);
+}
+
+void FileSelectHelper::OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data) {
+ // Directory upload only cares about files. This util call just checks
+ // the flags in the structure; there's no file I/O going on.
+ if (file_util::FileEnumerator::IsDirectory(data.info))
+ return;
+
+ directory_lister_results_.push_back(data.path);
+}
+
+void FileSelectHelper::OnListDone(int error) {
+ if (!render_view_host_)
+ return;
+
+ if (error) {
+ FileSelectionCanceled(NULL);
+ return;
+ }
+
+ render_view_host_->FilesSelectedInChooser(directory_lister_results_);
+ render_view_host_ = NULL;
+ directory_lister_ = NULL;
+ directory_lister_results_.clear();
+}
+
+SelectFileDialog::FileTypeInfo* FileSelectHelper::GetFileTypesFromAcceptType(
+ const string16& accept_types) {
+ if (accept_types.empty())
+ return NULL;
+
+ // Split the accept-type string on commas.
+ std::vector<string16> mime_types;
+ base::SplitStringUsingSubstr(accept_types, ASCIIToUTF16(","), &mime_types);
+ if (mime_types.empty())
+ return NULL;
+
+ // Create FileTypeInfo and pre-allocate for the first extension list.
+ scoped_ptr<SelectFileDialog::FileTypeInfo> file_type(
+ new SelectFileDialog::FileTypeInfo());
+ file_type->include_all_files = true;
+ file_type->extensions.resize(1);
+ std::vector<FilePath::StringType>* extensions = &file_type->extensions.back();
+
+ // Find the correspondinge extensions.
+ int valid_type_count = 0;
+ int description_id = 0;
+ for (size_t i = 0; i < mime_types.size(); ++i) {
+ string16 mime_type = mime_types[i];
+ std::string ascii_mime_type = StringToLowerASCII(UTF16ToASCII(mime_type));
+
+ TrimWhitespace(ascii_mime_type, TRIM_ALL, &ascii_mime_type);
+ if (ascii_mime_type.empty())
+ continue;
+
+ size_t old_extension_size = extensions->size();
+ if (ascii_mime_type == "image/*") {
+ description_id = IDS_IMAGE_FILES;
+ net::GetImageExtensions(extensions);
+ } else if (ascii_mime_type == "audio/*") {
+ description_id = IDS_AUDIO_FILES;
+ net::GetAudioExtensions(extensions);
+ } else if (ascii_mime_type == "video/*") {
+ description_id = IDS_VIDEO_FILES;
+ net::GetVideoExtensions(extensions);
+ } else {
+ net::GetExtensionsForMimeType(ascii_mime_type, extensions);
+ }
+
+ if (extensions->size() > old_extension_size)
+ valid_type_count++;
+ }
+
+ // Use a generic description "Custom Files" if either of the following is
+ // true:
+ // 1) There're multiple types specified, like "audio/*,video/*"
+ // 2) There're multiple extensions for a MIME type without parameter, like
+ // "ehtml,shtml,htm,html" for "text/html". On Windows, the select file
+ // dialog uses the first extension in the list to form the description,
+ // like "EHTML Files". This is not what we want.
+ if (valid_type_count > 1 ||
+ (valid_type_count == 1 && description_id == 0 && extensions->size() > 1))
+ description_id = IDS_CUSTOM_FILES;
+
+ if (description_id) {
+ file_type->extension_description_overrides.push_back(
+ l10n_util::GetStringUTF16(description_id));
+ }
+
+ return file_type.release();
+}
+
+void FileSelectHelper::RunFileChooser(
+ RenderViewHost* render_view_host,
+ const ViewHostMsg_RunFileChooser_Params &params) {
+ DCHECK(!render_view_host_);
+ render_view_host_ = render_view_host;
+ notification_registrar_.RemoveAll();
+ notification_registrar_.Add(this,
+ NotificationType::RENDER_WIDGET_HOST_DESTROYED,
+ Source<RenderViewHost>(render_view_host));
+
+ if (!select_file_dialog_.get())
+ select_file_dialog_ = SelectFileDialog::Create(this);
+
+ switch (params.mode) {
+ case ViewHostMsg_RunFileChooser_Params::Open:
+ dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE;
+ break;
+ case ViewHostMsg_RunFileChooser_Params::OpenMultiple:
+ dialog_type_ = SelectFileDialog::SELECT_OPEN_MULTI_FILE;
+ break;
+ case ViewHostMsg_RunFileChooser_Params::OpenFolder:
+ dialog_type_ = SelectFileDialog::SELECT_FOLDER;
+ break;
+ case ViewHostMsg_RunFileChooser_Params::Save:
+ dialog_type_ = SelectFileDialog::SELECT_SAVEAS_FILE;
+ break;
+ default:
+ dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE; // Prevent warning.
+ NOTREACHED();
+ }
+ scoped_ptr<SelectFileDialog::FileTypeInfo> file_types(
+ GetFileTypesFromAcceptType(params.accept_types));
+ FilePath default_file_name = params.default_file_name;
+ if (default_file_name.empty())
+ default_file_name = profile_->last_selected_directory();
+
+ gfx::NativeWindow owning_window =
+ platform_util::GetTopLevel(render_view_host_->view()->GetNativeView());
+ select_file_dialog_->SelectFile(dialog_type_,
+ params.title,
+ default_file_name,
+ file_types.get(),
+ 0,
+ FILE_PATH_LITERAL(""),
+ owning_window,
+ NULL);
+}
+
+void FileSelectHelper::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::RENDER_WIDGET_HOST_DESTROYED);
+ DCHECK(Details<RenderViewHost>(details).ptr() == render_view_host_);
+ render_view_host_ = NULL;
+}
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h
new file mode 100644
index 0000000..ba8441b
--- /dev/null
+++ b/chrome/browser/file_select_helper.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_FILE_SELECT_HELPER_H_
+#define CHROME_BROWSER_FILE_SELECT_HELPER_H_
+#pragma once
+
+#include <vector>
+
+#include "chrome/browser/shell_dialogs.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "net/base/directory_lister.h"
+
+class Profile;
+class RenderViewHost;
+struct ViewHostMsg_RunFileChooser_Params;
+
+class FileSelectHelper
+ : public SelectFileDialog::Listener,
+ public net::DirectoryLister::DirectoryListerDelegate,
+ public RenderViewHostDelegate::FileSelect,
+ public NotificationObserver {
+ public:
+ explicit FileSelectHelper(Profile* profile);
+ ~FileSelectHelper();
+
+ // SelectFileDialog::Listener
+ virtual void FileSelected(const FilePath& path, int index, void* params);
+ virtual void MultiFilesSelected(const std::vector<FilePath>& files,
+ void* params);
+ virtual void FileSelectionCanceled(void* params);
+
+ // net::DirectoryLister::DirectoryListerDelegate
+ virtual void OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data);
+ virtual void OnListDone(int error);
+
+ // RenderViewHostDelegate::FileSelect
+ virtual void RunFileChooser(RenderViewHost* render_view_host,
+ const ViewHostMsg_RunFileChooser_Params& params);
+
+ private:
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Helper method for handling the SelectFileDialog::Listener callbacks.
+ void DirectorySelected(const FilePath& path);
+
+ // Helper method to get allowed extensions for select file dialog from
+ // the specified accept types as defined in the spec:
+ // http://whatwg.org/html/number-state.html#attr-input-accept
+ SelectFileDialog::FileTypeInfo* GetFileTypesFromAcceptType(
+ const string16& accept_types);
+
+ // Profile used to set/retrieve the last used directory.
+ Profile* profile_;
+
+ // The RenderViewHost for the page we are associated with.
+ RenderViewHost* render_view_host_;
+
+ // Dialog box used for choosing files to upload from file form fields.
+ scoped_refptr<SelectFileDialog> select_file_dialog_;
+
+ // The type of file dialog last shown.
+ SelectFileDialog::Type dialog_type_;
+
+ // The current directory lister (runs on a separate thread).
+ scoped_refptr<net::DirectoryLister> directory_lister_;
+
+ // The current directory lister results, which may update incrementally
+ // as the listing proceeds.
+ std::vector<FilePath> directory_lister_results_;
+
+ // Registrar for notifications regarding our RenderViewHost.
+ NotificationRegistrar notification_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileSelectHelper);
+};
+
+#endif // CHROME_BROWSER_FILE_SELECT_HELPER_H_
diff --git a/chrome/browser/file_watcher.h b/chrome/browser/file_watcher.h
deleted file mode 100644
index 397feb1..0000000
--- a/chrome/browser/file_watcher.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.
-
-// This module provides a way to monitor a file for changes.
-
-#ifndef CHROME_BROWSER_FILE_WATCHER_H_
-#define CHROME_BROWSER_FILE_WATCHER_H_
-
-#include "base/basictypes.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/chrome_thread.h"
-
-class FilePath;
-// This class lets you register interest in changes on a file. The delegate
-// will get called whenever the file is changed, including created or deleted.
-// WARNING: To be able to get create/delete notifications and to work cross
-// platform, we actually listen for changes to the directory containing
-// the file.
-// WARNING: On OSX and Windows, the OS API doesn't tell us which file in the
-// directory changed. We work around this by watching the file time, but this
-// can result in some extra notifications if we get other notifications within
-// 2s of the file having changed.
-class FileWatcher {
- public:
- class Delegate {
- public:
- virtual ~Delegate() {}
- virtual void OnFileChanged(const FilePath& path) = 0;
- };
-
- FileWatcher();
- ~FileWatcher() {}
-
- // Register interest in any changes on the file |path|.
- // OnFileChanged will be called back for each change to the file. Any
- // background operations will be ran on |backend_thread_id|. Note: The
- // directory containing |path| must exist before you try to watch the file.
- // Returns false if the watch can't be added.
- bool Watch(const FilePath& path, Delegate* delegate) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- return impl_->Watch(path, delegate);
- }
-
- // Used internally to encapsulate different members on different platforms.
- class PlatformDelegate
- : public base::RefCountedThreadSafe<PlatformDelegate,
- ChromeThread::DeleteOnFileThread> {
- public:
- virtual ~PlatformDelegate() {}
-
- virtual bool Watch(const FilePath& path, Delegate* delegate) = 0;
- };
-
- private:
- scoped_refptr<PlatformDelegate> impl_;
-
- DISALLOW_COPY_AND_ASSIGN(FileWatcher);
-};
-
-#endif // CHROME_BROWSER_FILE_WATCHER_H_
diff --git a/chrome/browser/file_watcher_inotify.cc b/chrome/browser/file_watcher_inotify.cc
deleted file mode 100644
index 4026964..0000000
--- a/chrome/browser/file_watcher_inotify.cc
+++ /dev/null
@@ -1,319 +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_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"
-#include "base/waitable_event.h"
-
-namespace {
-
-class FileWatcherImpl;
-
-// 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 |path| for changes. |watcher| will be notified on each change.
- // Returns kInvalidWatch on failure.
- Watch AddWatch(const FilePath& path, FileWatcherImpl* watcher);
-
- // Remove |watch|. Returns true on success.
- bool RemoveWatch(Watch watch, FileWatcherImpl* watcher);
-
- // Callback for InotifyReaderTask.
- void OnInotifyEvent(const inotify_event* event);
-
- private:
- friend struct DefaultSingletonTraits<InotifyReader>;
-
- typedef std::set<FileWatcherImpl*> 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 FileWatcherImpl : public FileWatcher::PlatformDelegate {
- public:
- FileWatcherImpl();
- ~FileWatcherImpl();
-
- // Called for each event coming from the watch.
- void OnInotifyEvent(const inotify_event* event);
-
- // 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, FileWatcher::Delegate* delegate);
-
- private:
- // Delegate to notify upon changes.
- FileWatcher::Delegate* delegate_;
-
- // Watch returned by InotifyReader.
- InotifyReader::Watch watch_;
-
- // The file we're watching.
- FilePath path_;
-
- DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl);
-};
-
-class FileWatcherImplNotifyTask : public Task {
- public:
- FileWatcherImplNotifyTask(FileWatcher::Delegate* delegate,
- const FilePath& path)
- : delegate_(delegate), path_(path) {
- }
-
- virtual void Run() {
- delegate_->OnFileChanged(path_);
- }
-
- private:
- FileWatcher::Delegate* delegate_;
- FilePath path_;
-
- DISALLOW_COPY_AND_ASSIGN(FileWatcherImplNotifyTask);
-};
-
-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, FileWatcherImpl* 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);
-
- if (watch == kInvalidWatch)
- return kInvalidWatch;
-
- watchers_[watch].insert(watcher);
-
- return watch;
-}
-
-bool InotifyReader::RemoveWatch(Watch watch,
- FileWatcherImpl* 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;
-
- // In case you want to limit the scope of this lock, it's not sufficient
- // to just copy things under the lock, and then run the notifications
- // without holding the lock. FileWatcherImpl's dtor removes its watches,
- // and to do that obtains the lock. After it finishes removing watches,
- // it's destroyed. So, if you copy under the lock and notify without the lock,
- // it's possible you'll copy the FileWatcherImpl which is being
- // destroyed, then it will destroy itself, and then you'll try to notify it.
- AutoLock auto_lock(lock_);
-
- for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
- watcher != watchers_[event->wd].end();
- ++watcher) {
- (*watcher)->OnInotifyEvent(event);
- }
-}
-
-FileWatcherImpl::FileWatcherImpl()
- : watch_(InotifyReader::kInvalidWatch) {
-}
-
-FileWatcherImpl::~FileWatcherImpl() {
- if (watch_ == InotifyReader::kInvalidWatch)
- return;
-
- Singleton<InotifyReader>::get()->RemoveWatch(watch_, this);
-}
-
-void FileWatcherImpl::OnInotifyEvent(const inotify_event* event) {
- // Since we're watching the directory, filter out inotify events
- // if it's not related to the file we're watching.
- if (path_ != path_.DirName().Append(event->name))
- return;
-
- ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
- new FileWatcherImplNotifyTask(delegate_, path_));
-}
-
-bool FileWatcherImpl::Watch(const FilePath& path,
- FileWatcher::Delegate* delegate) {
- // Each FileWatcherImpl can only watch one file.
- DCHECK(watch_ == InotifyReader::kInvalidWatch);
-
- // It's not possible to watch a file that doesn't exist, so instead,
- // watch the parent directory.
- if (!file_util::PathExists(path.DirName()))
- return false;
-
- delegate_ = delegate;
- path_ = path;
- watch_ = Singleton<InotifyReader>::get()->AddWatch(path.DirName(), this);
- return watch_ != InotifyReader::kInvalidWatch;
-}
-
-} // namespace
-
-FileWatcher::FileWatcher() {
- impl_ = new FileWatcherImpl();
-}
diff --git a/chrome/browser/file_watcher_mac.cc b/chrome/browser/file_watcher_mac.cc
deleted file mode 100644
index 638654c..0000000
--- a/chrome/browser/file_watcher_mac.cc
+++ /dev/null
@@ -1,157 +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_watcher.h"
-
-#include <CoreServices/CoreServices.h>
-
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/scoped_cftyperef.h"
-#include "base/time.h"
-
-namespace {
-
-const CFAbsoluteTime kEventLatencySeconds = 0.3;
-
-class FileWatcherImpl : public FileWatcher::PlatformDelegate {
- public:
- FileWatcherImpl() {}
- ~FileWatcherImpl() {
- if (!path_.value().empty()) {
- FSEventStreamStop(fsevent_stream_);
- FSEventStreamInvalidate(fsevent_stream_);
- FSEventStreamRelease(fsevent_stream_);
- }
- }
-
- virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate) {
- FilePath parent_dir = path.DirName();
- if (!file_util::AbsolutePath(&parent_dir))
- return false;
-
- // Jump back to the UI thread because FSEventStreamScheduleWithRunLoop
- // requires a UI thread.
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &FileWatcherImpl::WatchImpl, path, delegate));
- } else {
- LOG(INFO) << "Adding FileWatcher watch.";
- // During unittests, there is only one thread and it is both the UI
- // thread and the file thread.
- WatchImpl(path, delegate);
- }
- return true;
- }
-
- bool WatchImpl(const FilePath& path, FileWatcher::Delegate* delegate);
-
- void OnFSEventsCallback(const FilePath& event_path) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- DCHECK(!path_.value().empty());
- FilePath absolute_event_path = event_path;
- if (!file_util::AbsolutePath(&absolute_event_path))
- return;
-
- file_util::FileInfo file_info;
- bool file_exists = file_util::GetFileInfo(path_, &file_info);
- if (file_exists && (last_modified_.is_null() ||
- last_modified_ != file_info.last_modified)) {
- last_modified_ = file_info.last_modified;
- delegate_->OnFileChanged(path_);
- } else if (file_exists && (base::Time::Now() - last_modified_ <
- base::TimeDelta::FromSeconds(2))) {
- // Since we only have a resolution of 1s, if we get a callback within
- // 2s of the file having changed, go ahead and notify our observer. This
- // might be from a different file change, but it's better to notify too
- // much rather than miss a notification.
- delegate_->OnFileChanged(path_);
- } else if (!file_exists && !last_modified_.is_null()) {
- last_modified_ = base::Time();
- delegate_->OnFileChanged(path_);
- }
- }
-
- private:
- // Delegate to notify upon changes.
- FileWatcher::Delegate* delegate_;
-
- // Path we're watching (passed to delegate).
- FilePath path_;
-
- // Backend stream we receive event callbacks from (strong reference).
- FSEventStreamRef fsevent_stream_;
-
- // Keep track of the last modified time of the file. We use nulltime
- // to represent the file not existing.
- base::Time last_modified_;
-
- DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl);
-};
-
-void FSEventsCallback(ConstFSEventStreamRef stream,
- void* event_watcher, size_t num_events,
- void* event_paths, const FSEventStreamEventFlags flags[],
- const FSEventStreamEventId event_ids[]) {
- char** paths = reinterpret_cast<char**>(event_paths);
- FileWatcherImpl* watcher =
- reinterpret_cast<FileWatcherImpl*>(event_watcher);
- for (size_t i = 0; i < num_events; i++) {
- if (!ChromeThread::CurrentlyOn(ChromeThread::FILE)) {
- ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(watcher, &FileWatcherImpl::OnFSEventsCallback,
- FilePath(paths[i])));
- } else {
- LOG(INFO) << "FileWatcher event callback for " << paths[i];
- // During unittests, there is only one thread and it is both the UI
- // thread and the file thread.
- watcher->OnFSEventsCallback(FilePath(paths[i]));
- }
- }
-}
-
-bool FileWatcherImpl::WatchImpl(const FilePath& path,
- FileWatcher::Delegate* delegate) {
- DCHECK(path_.value().empty()); // Can only watch one path.
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-
- file_util::FileInfo file_info;
- if (file_util::GetFileInfo(path, &file_info))
- last_modified_ = file_info.last_modified;
-
- path_ = path;
- delegate_ = delegate;
-
- scoped_cftyperef<CFStringRef> cf_path(CFStringCreateWithCString(
- NULL, path.DirName().value().c_str(), kCFStringEncodingMacHFS));
- CFStringRef path_for_array = cf_path.get();
- scoped_cftyperef<CFArrayRef> watched_paths(CFArrayCreate(
- NULL, reinterpret_cast<const void**>(&path_for_array), 1,
- &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,
- kFSEventStreamEventIdSinceNow,
- kEventLatencySeconds,
- kFSEventStreamCreateFlagNone);
- FSEventStreamScheduleWithRunLoop(fsevent_stream_, CFRunLoopGetCurrent(),
- kCFRunLoopDefaultMode);
- FSEventStreamStart(fsevent_stream_);
-
- return true;
-}
-
-} // namespace
-
-FileWatcher::FileWatcher() {
- impl_ = new FileWatcherImpl();
-}
diff --git a/chrome/browser/file_watcher_stub.cc b/chrome/browser/file_watcher_stub.cc
deleted file mode 100644
index 96e24f4..0000000
--- a/chrome/browser/file_watcher_stub.cc
+++ /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.
-
-// This file exists for Linux systems which don't have the inotify headers, and
-// thus cannot build file_watcher_inotify.cc
-
-#include "chrome/browser/file_watcher.h"
-
-class FileWatcherImpl : public FileWatcher::PlatformDelegate {
- public:
- virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate) {
- return false;
- }
-};
-
-FileWatcher::FileWatcher() {
- impl_ = new FileWatcherImpl();
-}
diff --git a/chrome/browser/file_watcher_unittest.cc b/chrome/browser/file_watcher_unittest.cc
deleted file mode 100644
index c6fca6c..0000000
--- a/chrome/browser/file_watcher_unittest.cc
+++ /dev/null
@@ -1,259 +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/file_watcher.h"
-
-#include <limits>
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/platform_thread.h"
-#include "base/scoped_temp_dir.h"
-#include "base/string_util.h"
-#include "base/thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_MACOSX)
-// TODO(tony): Tests are flaky on mac. http://crbug.com/38188
-#define MAYBE(name) FLAKY_ ## name
-#else
-#define MAYBE(name) name
-#endif
-
-namespace {
-
-// For tests where we wait a bit to verify nothing happened
-const int kWaitForEventTime = 500;
-
-// Maximum amount of time to wait on a test.
-const int kMaxTestTimeMs = 10 * 1000;
-
-class FileWatcherTest : public testing::Test {
- public:
- // Implementation of FileWatcher on Mac requires UI loop.
- FileWatcherTest()
- : loop_(MessageLoop::TYPE_UI),
- ui_thread_(ChromeThread::UI, &loop_),
- file_thread_(ChromeThread::FILE, &loop_),
- notified_delegates_(0),
- expected_notified_delegates_(0) {
- }
-
- void OnTestDelegateFirstNotification() {
- notified_delegates_++;
- if (notified_delegates_ >= expected_notified_delegates_)
- MessageLoop::current()->Quit();
- }
-
- protected:
- virtual void SetUp() {
- temp_dir_.reset(new ScopedTempDir);
- ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
- // Make sure that not getting an event doesn't cause the whole
- // test suite to hang.
- loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask,
- kMaxTestTimeMs);
- }
-
- FilePath test_file() {
- return temp_dir_->path().AppendASCII("FileWatcherTest");
- }
-
- // Write |content| to the test file. Returns true on success.
- bool WriteTestFile(const std::string& content) {
- // Logging to try and figure out why these tests are flaky on mac.
- LOG(INFO) << "WriteTestFile";
- int write_size = file_util::WriteFile(test_file(), content.c_str(),
- content.length());
- SyncIfPOSIX();
- return write_size == static_cast<int>(content.length());
- }
-
- void SetExpectedNumberOfNotifiedDelegates(int n) {
- notified_delegates_ = 0;
- expected_notified_delegates_ = n;
- }
-
- void VerifyExpectedNumberOfNotifiedDelegates() {
- // Check that we get at least the expected number of notified delegates.
- if (expected_notified_delegates_ - notified_delegates_ > 0)
- loop_.Run();
- EXPECT_EQ(expected_notified_delegates_, notified_delegates_);
- }
-
- void VerifyNoExtraNotifications() {
- // Check that we get no more than the expected number of notified delegates.
- loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask,
- kWaitForEventTime);
- loop_.Run();
- EXPECT_EQ(expected_notified_delegates_, notified_delegates_);
- }
-
- // We need this function for reliable tests on Mac OS X. FSEvents API
- // has a latency interval and can merge multiple events into one,
- // and we need a clear distinction between events triggered by test setup code
- // and test code.
- void SyncIfPOSIX() {
-#if defined(OS_POSIX)
- sync();
-#endif // defined(OS_POSIX)
- }
-
- MessageLoop loop_;
- ChromeThread ui_thread_;
- ChromeThread file_thread_;
- scoped_ptr<ScopedTempDir> temp_dir_;
-
- // The number of test delegates which received their notification.
- int notified_delegates_;
-
- // The number of notified test delegates after which we quit the message loop.
- int expected_notified_delegates_;
-};
-
-class TestDelegate : public FileWatcher::Delegate {
- public:
- explicit TestDelegate(FileWatcherTest* test)
- : test_(test),
- got_notification_(false) {
- }
-
- bool got_notification() const {
- return got_notification_;
- }
-
- void reset() {
- got_notification_ = false;
- }
-
- virtual void OnFileChanged(const FilePath& path) {
- EXPECT_TRUE(ChromeThread::CurrentlyOn(ChromeThread::UI));
- if (!got_notification_)
- test_->OnTestDelegateFirstNotification();
- got_notification_ = true;
- }
-
- private:
- // Hold a pointer to current test fixture to inform it on first notification.
- FileWatcherTest* test_;
-
- // Set to true after first notification.
- bool got_notification_;
-};
-
-
-// Basic test: Create the file and verify that we notice.
-TEST_F(FileWatcherTest, MAYBE(NewFile)) {
- FileWatcher watcher;
- TestDelegate delegate(this);
- ASSERT_TRUE(watcher.Watch(test_file(), &delegate));
-
- SetExpectedNumberOfNotifiedDelegates(1);
- ASSERT_TRUE(WriteTestFile("content"));
- VerifyExpectedNumberOfNotifiedDelegates();
-}
-
-// Verify that modifying the file is caught.
-TEST_F(FileWatcherTest, MAYBE(ModifiedFile)) {
- ASSERT_TRUE(WriteTestFile("content"));
-
- FileWatcher watcher;
- TestDelegate delegate(this);
- ASSERT_TRUE(watcher.Watch(test_file(), &delegate));
-
- // Now make sure we get notified if the file is modified.
- SetExpectedNumberOfNotifiedDelegates(1);
- ASSERT_TRUE(WriteTestFile("new content"));
- VerifyExpectedNumberOfNotifiedDelegates();
-}
-
-TEST_F(FileWatcherTest, MAYBE(DeletedFile)) {
- ASSERT_TRUE(WriteTestFile("content"));
-
- FileWatcher watcher;
- TestDelegate delegate(this);
- ASSERT_TRUE(watcher.Watch(test_file(), &delegate));
-
- // Now make sure we get notified if the file is deleted.
- SetExpectedNumberOfNotifiedDelegates(1);
- file_util::Delete(test_file(), false);
- SyncIfPOSIX();
- VerifyExpectedNumberOfNotifiedDelegates();
-}
-
-// Verify that letting the watcher go out of scope stops notifications.
-TEST_F(FileWatcherTest, MAYBE(Unregister)) {
- TestDelegate delegate(this);
-
- {
- FileWatcher watcher;
- ASSERT_TRUE(watcher.Watch(test_file(), &delegate));
-
- // And then let it fall out of scope, clearing its watch.
- }
-
- // Write a file to the test dir.
- SetExpectedNumberOfNotifiedDelegates(0);
- ASSERT_TRUE(WriteTestFile("content"));
- VerifyExpectedNumberOfNotifiedDelegates();
- VerifyNoExtraNotifications();
-}
-
-
-namespace {
-// Used by the DeleteDuringNotify test below.
-// Deletes the FileWatcher when it's notified.
-class Deleter : public FileWatcher::Delegate {
- public:
- Deleter(FileWatcher* watcher, MessageLoop* loop)
- : watcher_(watcher),
- loop_(loop) {
- }
-
- virtual void OnFileChanged(const FilePath& path) {
- watcher_.reset(NULL);
- loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- }
-
- scoped_ptr<FileWatcher> watcher_;
- MessageLoop* loop_;
-};
-} // anonymous namespace
-
-// Verify that deleting a watcher during the callback doesn't crash.
-TEST_F(FileWatcherTest, MAYBE(DeleteDuringNotify)) {
- FileWatcher* watcher = new FileWatcher;
- Deleter deleter(watcher, &loop_); // Takes ownership of watcher.
- ASSERT_TRUE(watcher->Watch(test_file(), &deleter));
-
- ASSERT_TRUE(WriteTestFile("content"));
- loop_.Run();
-
- // We win if we haven't crashed yet.
- // Might as well double-check it got deleted, too.
- ASSERT_TRUE(deleter.watcher_.get() == NULL);
-}
-
-TEST_F(FileWatcherTest, MAYBE(MultipleWatchersSingleFile)) {
- FileWatcher watcher1, watcher2;
- TestDelegate delegate1(this), delegate2(this);
- ASSERT_TRUE(watcher1.Watch(test_file(), &delegate1));
- ASSERT_TRUE(watcher2.Watch(test_file(), &delegate2));
-
- SetExpectedNumberOfNotifiedDelegates(2);
- ASSERT_TRUE(WriteTestFile("content"));
- VerifyExpectedNumberOfNotifiedDelegates();
-}
-
-// Verify that watching a file who's parent directory doesn't exist
-// fails, but doesn't asssert.
-TEST_F(FileWatcherTest, NonExistentDirectory) {
- FileWatcher watcher;
- ASSERT_FALSE(watcher.Watch(test_file().AppendASCII("FileToWatch"), NULL));
-}
-
-} // namespace
diff --git a/chrome/browser/file_watcher_win.cc b/chrome/browser/file_watcher_win.cc
deleted file mode 100644
index 7d19b32..0000000
--- a/chrome/browser/file_watcher_win.cc
+++ /dev/null
@@ -1,111 +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_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 FileWatcherImpl : public FileWatcher::PlatformDelegate,
- public base::ObjectWatcher::Delegate {
- public:
- FileWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
-
- virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate);
-
- // Callback from MessageLoopForIO.
- virtual void OnObjectSignaled(HANDLE object);
-
- private:
- virtual ~FileWatcherImpl();
-
- // Delegate to notify upon changes.
- FileWatcher::Delegate* delegate_;
-
- // Path we're watching (passed to delegate).
- FilePath path_;
-
- // 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_;
-
- DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl);
-};
-
-FileWatcherImpl::~FileWatcherImpl() {
- if (handle_ != INVALID_HANDLE_VALUE) {
- watcher_.StopWatching();
- FindCloseChangeNotification(handle_);
- }
-}
-
-bool FileWatcherImpl::Watch(const FilePath& path,
- FileWatcher::Delegate* delegate) {
- DCHECK(path_.value().empty()); // Can only watch one path.
- file_util::FileInfo file_info;
- if (file_util::GetFileInfo(path, &file_info))
- last_modified_ = file_info.last_modified;
-
- // FindFirstChangeNotification watches directories, so use the parent path.
- handle_ = FindFirstChangeNotification(
- path.DirName().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);
- if (handle_ == INVALID_HANDLE_VALUE)
- return false;
-
- delegate_ = delegate;
- path_ = path;
- watcher_.StartWatching(handle_, this);
-
- return true;
-}
-
-void FileWatcherImpl::OnObjectSignaled(HANDLE object) {
- DCHECK(object == handle_);
- // Make sure we stay alive through the body of this function.
- scoped_refptr<FileWatcherImpl> keep_alive(this);
-
- file_util::FileInfo file_info;
- bool file_exists = file_util::GetFileInfo(path_, &file_info);
- if (file_exists && (last_modified_.is_null() ||
- last_modified_ != file_info.last_modified)) {
- last_modified_ = file_info.last_modified;
- delegate_->OnFileChanged(path_);
- } else if (file_exists && (base::Time::Now() - last_modified_ <
- base::TimeDelta::FromSeconds(2))) {
- // Since we only have a resolution of 1s, if we get a callback within
- // 2s of the file having changed, go ahead and notify our observer. This
- // might be from a different file change, but it's better to notify too
- // much rather than miss a notification.
- delegate_->OnFileChanged(path_);
- } else if (!file_exists && !last_modified_.is_null()) {
- last_modified_ = base::Time();
- delegate_->OnFileChanged(path_);
- }
-
- // Register for more notifications on file change.
- BOOL ok = FindNextChangeNotification(object);
- DCHECK(ok);
- watcher_.StartWatching(object, this);
-}
-
-} // namespace
-
-FileWatcher::FileWatcher() {
- impl_ = new FileWatcherImpl();
-}
diff --git a/chrome/browser/find_backend_unittest.cc b/chrome/browser/find_backend_unittest.cc
index b927b35..ac8c5ce 100644
--- a/chrome/browser/find_backend_unittest.cc
+++ b/chrome/browser/find_backend_unittest.cc
@@ -4,9 +4,12 @@
#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;
diff --git a/chrome/browser/find_bar.h b/chrome/browser/find_bar.h
index b0062fb..041643f 100644
--- a/chrome/browser/find_bar.h
+++ b/chrome/browser/find_bar.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_FIND_BAR_H_
#define CHROME_BROWSER_FIND_BAR_H_
+#pragma once
#include "base/string16.h"
#include "gfx/rect.h"
@@ -15,7 +16,6 @@
class FindBarController;
class FindBarTesting;
class FindNotificationDetails;
-class TabContents;
class FindBar {
public:
diff --git a/chrome/browser/find_bar_controller.h b/chrome/browser/find_bar_controller.h
index 9b57b14..4d949a3 100644
--- a/chrome/browser/find_bar_controller.h
+++ b/chrome/browser/find_bar_controller.h
@@ -4,9 +4,11 @@
#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 {
diff --git a/chrome/browser/find_bar_host_browsertest.cc b/chrome/browser/find_bar_host_browsertest.cc
index 60bde4e..11c5f3e 100644
--- a/chrome/browser/find_bar_host_browsertest.cc
+++ b/chrome/browser/find_bar_host_browsertest.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/keyboard_codes.h"
+#include "app/keyboard_codes.h"
#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/find_bar.h"
@@ -13,9 +15,11 @@
#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/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"
@@ -113,11 +117,10 @@ int FindInPageWchar(TabContents* tab,
// This test loads a page with frames and starts FindInPage requests.
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageFrames) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our frames page.
- GURL url = server->TestServerPage(kFramePage);
+ GURL url = test_server()->GetURL(kFramePage);
ui_test_utils::NavigateToURL(browser(), url);
// Try incremental search (mimicking user typing in).
@@ -206,11 +209,10 @@ std::string FocusedOnPage(TabContents* tab_contents) {
// close the Find box (ie. if you find within a link the link should be
// focused).
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageEndState) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our special focus tracking page.
- GURL url = server->TestServerPage(kEndState);
+ GURL url = test_server()->GetURL(kEndState);
ui_test_utils::NavigateToURL(browser(), url);
TabContents* tab_contents = browser()->GetSelectedTabContents();
@@ -254,11 +256,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageEndState) {
// 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our page.
- GURL url = server->TestServerPage(kFrameData);
+ GURL url = test_server()->GetURL(kFrameData);
ui_test_utils::NavigateToURL(browser(), url);
// Search for 'o', which should make the first item active and return
@@ -294,11 +295,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageOrdinal) {
// This tests that the ordinal is correctly adjusted after a selection
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
SelectChangesOrdinal_Issue20883) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test content.
- GURL url = server->TestServerPage(kSelectChangesOrdinal);
+ GURL url = test_server()->GetURL(kSelectChangesOrdinal);
ui_test_utils::NavigateToURL(browser(), url);
TabContents* tab_contents = browser()->GetSelectedTabContents();
@@ -334,11 +334,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
// This test loads a page with frames and makes sure the ordinal returned makes
// sense.
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageMultiFramesOrdinal) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our page.
- GURL url = server->TestServerPage(kFramePage);
+ GURL url = test_server()->GetURL(kFramePage);
ui_test_utils::NavigateToURL(browser(), url);
// Search for 'a', which should make the first item active and return
@@ -386,11 +385,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageMultiFramesOrdinal) {
// 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our page.
- GURL url = server->TestServerPage(kFramePage);
+ GURL url = test_server()->GetURL(kFramePage);
ui_test_utils::NavigateToURL(browser(), url);
// Search for 'goa' three times (6 matches on page).
@@ -417,30 +415,27 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPage_Issue5132) {
// Load a page with no selectable text and make sure we don't crash.
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindUnSelectableText) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our page.
- GURL url = server->TestServerPage(kUserSelectPage);
+ 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));
- EXPECT_EQ(-1, ordinal); // Nothing is selected.
- EXPECT_EQ(0, FindInPageWchar(tab, L"Non-existing string",
- 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our page.
- GURL url = server->TestServerPage(kCrashPage);
+ 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
@@ -469,11 +464,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindCrash_Issue1341577) {
// 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our page.
- GURL url = server->TestServerPage(kBitstackCrash);
+ GURL url = test_server()->GetURL(kBitstackCrash);
ui_test_utils::NavigateToURL(browser(), url);
// This used to crash the tab.
@@ -492,11 +486,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindCrash_Issue14491) {
// 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our page.
- GURL url = server->TestServerPage(kTooFewMatchesPage);
+ 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
@@ -509,12 +502,13 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindRestarts_Issue1155639) {
}
// This tests bug 11761: FindInPage terminates search prematurely.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FAILS_FindInPagePrematureEnd) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+// 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 = server->TestServerPage(kPrematureEnd);
+ GURL url = test_server()->GetURL(kPrematureEnd);
ui_test_utils::NavigateToURL(browser(), url);
TabContents* tab_contents = browser()->GetSelectedTabContents();
@@ -528,12 +522,11 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FAILS_FindInPagePrematureEnd) {
}
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindDisappearOnNavigate) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our special focus tracking page.
- GURL url = server->TestServerPage(kSimplePage);
- GURL url2 = server->TestServerPage(kFramePage);
+ GURL url = test_server()->GetURL(kSimplePage);
+ GURL url2 = test_server()->GetURL(kFramePage);
ui_test_utils::NavigateToURL(browser(), url);
browser()->ShowFindBar();
@@ -569,11 +562,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindDisappearOnNavigate) {
// when a New Tab is opened.
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
FindDisappearOnNewTabAndHistory) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our special focus tracking page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
browser()->ShowFindBar();
@@ -617,10 +609,9 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
// Make sure Find box moves out of the way if it is obscuring the active match.
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_FindMovesWhenObscuring) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
- GURL url = server->TestServerPage(kMoveIfOver);
+ GURL url = test_server()->GetURL(kMoveIfOver);
ui_test_utils::NavigateToURL(browser(), url);
browser()->ShowFindBar();
@@ -676,11 +667,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_FindMovesWhenObscuring) {
// Make sure F3 in a new tab works if Find has previous string to search for.
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
FindNextInNewTabUsesPrepopulate) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
// Search for 'no_match'. No matches should be found.
@@ -723,11 +713,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
#else
IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, AcceleratorRestoring) {
#endif
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
views::FocusManager* focus_manager =
@@ -735,7 +724,7 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
browser()->window()->GetNativeHandle());
// See where Escape is registered.
- views::Accelerator escape(base::VKEY_ESCAPE, false, false, false);
+ views::Accelerator escape(app::VKEY_ESCAPE, false, false, false);
views::AcceleratorTarget* old_target =
focus_manager->GetCurrentTargetForAccelerator(escape);
EXPECT_TRUE(old_target != NULL);
@@ -762,11 +751,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
// 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
browser()->ShowFindBar();
@@ -787,11 +775,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, StayActive) {
// 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to a simple page.
- GURL url = server->TestServerPage(kSimple);
+ GURL url = test_server()->GetURL(kSimple);
ui_test_utils::NavigateToURL(browser(), url);
// Search for 'page'. Should have 1 match.
@@ -819,11 +806,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, RestartSearchFromF3) {
// 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) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
// Find "Default".
@@ -832,8 +818,11 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PreferPreviousSearch) {
EXPECT_EQ(1, FindInPageWchar(tab1, L"Default", kFwd, kIgnoreCase, &ordinal));
// Create a second tab.
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
browser()->SelectTabContentsAt(1, false);
TabContents* tab2 = browser()->GetSelectedTabContents();
EXPECT_NE(tab1, tab2);
@@ -858,11 +847,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulateSameTab) {
return;
#endif
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimple);
+ GURL url = test_server()->GetURL(kSimple);
ui_test_utils::NavigateToURL(browser(), url);
// Search for the word "page".
@@ -896,11 +884,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulateInNewTab) {
return;
#endif
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimple);
+ GURL url = test_server()->GetURL(kSimple);
ui_test_utils::NavigateToURL(browser(), url);
// Search for the word "page".
@@ -909,8 +896,11 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulateInNewTab) {
EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
// Now create a second tab and load the same page.
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
browser()->SelectTabContentsAt(1, false);
TabContents* tab2 = browser()->GetSelectedTabContents();
EXPECT_NE(tab1, tab2);
@@ -932,11 +922,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulatePreserveLast) {
return;
#endif
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimple);
+ GURL url = test_server()->GetURL(kSimple);
ui_test_utils::NavigateToURL(browser(), url);
// Search for the word "page".
@@ -954,8 +943,11 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulatePreserveLast) {
FindBarController::kKeepSelection);
// Now create a second tab and load the same page.
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
browser()->SelectTabContentsAt(1, false);
TabContents* tab2 = browser()->GetSelectedTabContents();
EXPECT_NE(tab1, tab2);
@@ -993,9 +985,6 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulatePreserveLast) {
// linux views. Investigate and fix. http://crbug.com/40948
#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
#define MAYBE_NoIncognitoPrepopulate DISABLED_NoIncognitoPrepopulate
-#elif defined (OS_WIN)
-// On windows, this test is flaky. http://crbug.com/40948
-#define MAYBE_NoIncognitoPrepopulate FLAKY_NoIncognitoPrepopulate
#else
#define MAYBE_NoIncognitoPrepopulate NoIncognitoPrepopulate
#endif
@@ -1008,11 +997,10 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_NoIncognitoPrepopulate) {
return;
#endif
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to the "simple" test page.
- GURL url = server->TestServerPage(kSimple);
+ GURL url = test_server()->GetURL(kSimple);
ui_test_utils::NavigateToURL(browser(), url);
// Search for the word "page" in the normal browser tab.
@@ -1031,9 +1019,11 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_NoIncognitoPrepopulate) {
// Open a new incognito window and navigate to the same page.
Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
Browser* incognito_browser = Browser::Create(incognito_profile);
+ Browser* browser_used = NULL;
incognito_browser->AddTabWithURL(url, GURL(), PageTransition::START_PAGE, -1,
TabStripModel::ADD_SELECTED, NULL,
- std::string());
+ std::string(), &browser_used);
+ EXPECT_EQ(incognito_browser, browser_used);
ui_test_utils::WaitForNavigation(
&incognito_browser->GetSelectedTabContents()->controller());
incognito_browser->window()->Show();
@@ -1054,7 +1044,9 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_NoIncognitoPrepopulate) {
// Now open a new tab in the original (non-incognito) browser.
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
browser()->SelectTabContentsAt(1, false);
TabContents* tab2 = browser()->GetSelectedTabContents();
EXPECT_NE(tab1, tab2);
@@ -1065,20 +1057,12 @@ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_NoIncognitoPrepopulate) {
EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarTextForBrowser(browser()));
}
-// See http://crbug.com/45594. On Windows, it crashes sometimes.
-#if defined(OS_WIN)
-#define MAYBE_ActivateLinkNavigatesPage DISABLED_ActivateLinkNavigatesPage
-#else
-#define MAYBE_ActivateLinkNavigatesPage ActivateLinkNavigatesPage
-#endif
// This makes sure that dismissing the find bar with kActivateSelection works.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
- MAYBE_ActivateLinkNavigatesPage) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, ActivateLinkNavigatesPage) {
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test content.
- GURL url = server->TestServerPage(kLinkPage);
+ GURL url = test_server()->GetURL(kLinkPage);
ui_test_utils::NavigateToURL(browser(), url);
TabContents* tab = browser()->GetSelectedTabContents();
diff --git a/chrome/browser/find_bar_state.h b/chrome/browser/find_bar_state.h
index b350e30..801779e 100644
--- a/chrome/browser/find_bar_state.h
+++ b/chrome/browser/find_bar_state.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_FIND_BAR_STATE_H_
#define CHROME_BROWSER_FIND_BAR_STATE_H_
+#pragma once
#include "base/basictypes.h"
#include "base/string16.h"
diff --git a/chrome/browser/find_notification_details.h b/chrome/browser/find_notification_details.h
index fbab3c4..ee5fc51 100644
--- a/chrome/browser/find_notification_details.h
+++ b/chrome/browser/find_notification_details.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_
#define CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_
+#pragma once
#include "base/basictypes.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/first_run.cc b/chrome/browser/first_run.cc
deleted file mode 100644
index 5fb2886..0000000
--- a/chrome/browser/first_run.cc
+++ /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.
-
-#include "chrome/browser/first_run.h"
-
-#include "build/build_config.h"
-
-// TODO(port): move more code in back from the first_run_win.cc module.
-
-#if defined(OS_WIN)
-#include "chrome/installer/util/install_util.h"
-#endif
-
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "chrome/browser/importer/importer.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-
-namespace {
-
-// The kSentinelFile file absence will tell us it is a first run.
-const char kSentinelFile[] = "First Run";
-
-} // namespace
-
-// TODO(port): Import switches need to be ported to both Mac and Linux. Not all
-// import switches here are implemented for Linux. None are implemented for Mac
-// (as this function will not be called on Mac).
-int FirstRun::ImportNow(Profile* profile, const CommandLine& cmdline) {
- int return_code = true;
- if (cmdline.HasSwitch(switches::kImportFromFile)) {
- // Silently import preset bookmarks from file.
- // This is an OEM scenario.
- return_code = ImportFromFile(profile, cmdline);
- }
- if (cmdline.HasSwitch(switches::kImport)) {
-#if defined(OS_WIN)
- return_code = ImportFromBrowser(profile, cmdline);
-#else
- NOTIMPLEMENTED();
-#endif
- }
- return return_code;
-}
-
-// static
-bool FirstRun::IsChromeFirstRun() {
- // A troolean, 0 means not yet set, 1 means set to true, 2 set to false.
- static int first_run = 0;
- if (first_run != 0)
- return first_run == 1;
-
- FilePath first_run_sentinel;
- if (!GetFirstRunSentinelFilePath(&first_run_sentinel) ||
- file_util::PathExists(first_run_sentinel)) {
- first_run = 2;
- return false;
- }
- first_run = 1;
- return true;
-}
-
-// static
-bool FirstRun::RemoveSentinel() {
- FilePath first_run_sentinel;
- if (!GetFirstRunSentinelFilePath(&first_run_sentinel))
- return false;
- return file_util::Delete(first_run_sentinel, false);
-}
-
-// static
-bool FirstRun::CreateSentinel() {
- FilePath first_run_sentinel;
- if (!GetFirstRunSentinelFilePath(&first_run_sentinel))
- return false;
- return file_util::WriteFile(first_run_sentinel, "", 0) != -1;
-}
-
-// static
-bool FirstRun::SetShowFirstRunBubblePref(bool show_bubble) {
- PrefService* local_state = g_browser_process->local_state();
- if (!local_state)
- return false;
- if (!local_state->FindPreference(prefs::kShouldShowFirstRunBubble)) {
- local_state->RegisterBooleanPref(prefs::kShouldShowFirstRunBubble, false);
- local_state->SetBoolean(prefs::kShouldShowFirstRunBubble, show_bubble);
- }
- return true;
-}
-
-// static
-bool FirstRun::SetShowWelcomePagePref() {
- PrefService* local_state = g_browser_process->local_state();
- if (!local_state)
- return false;
- if (!local_state->FindPreference(prefs::kShouldShowWelcomePage)) {
- local_state->RegisterBooleanPref(prefs::kShouldShowWelcomePage, false);
- local_state->SetBoolean(prefs::kShouldShowWelcomePage, true);
- }
- return true;
-}
-
-// static
-bool FirstRun::SetOEMFirstRunBubblePref() {
- PrefService* local_state = g_browser_process->local_state();
- if (!local_state)
- return false;
- if (!local_state->FindPreference(prefs::kShouldUseOEMFirstRunBubble)) {
- local_state->RegisterBooleanPref(prefs::kShouldUseOEMFirstRunBubble,
- false);
- local_state->SetBoolean(prefs::kShouldUseOEMFirstRunBubble, true);
- }
- return true;
-}
-
-// static
-bool FirstRun::SetMinimalFirstRunBubblePref() {
- PrefService* local_state = g_browser_process->local_state();
- if (!local_state)
- return false;
- if (!local_state->FindPreference(prefs::kShouldUseMinimalFirstRunBubble)) {
- local_state->RegisterBooleanPref(prefs::kShouldUseMinimalFirstRunBubble,
- false);
- local_state->SetBoolean(prefs::kShouldUseMinimalFirstRunBubble, true);
- }
- return true;
-}
-
-// static
-int FirstRun::ImportFromFile(Profile* profile, const CommandLine& cmdline) {
- FilePath file_path = cmdline.GetSwitchValuePath(switches::kImportFromFile);
- if (file_path.empty()) {
- NOTREACHED();
- return false;
- }
- scoped_refptr<ImporterHost> importer_host = new ImporterHost();
- FirstRunImportObserver observer;
-
- importer_host->set_headless();
-
- ProfileInfo profile_info;
- profile_info.browser_type = importer::BOOKMARKS_HTML;
- profile_info.source_path = file_path;
-
- StartImportingWithUI(
- NULL,
- importer::FAVORITES,
- importer_host,
- profile_info,
- profile,
- &observer,
- true);
-
- observer.RunLoop();
- return observer.import_result();
-}
-
-// static
-bool FirstRun::GetFirstRunSentinelFilePath(FilePath* path) {
- FilePath first_run_sentinel;
-
-#if defined(OS_WIN)
- FilePath exe_path;
- if (!PathService::Get(base::DIR_EXE, &exe_path))
- return false;
- if (InstallUtil::IsPerUserInstall(exe_path.value().c_str())) {
- first_run_sentinel = exe_path;
- } else {
- if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
- return false;
- }
-#else
- if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
- return false;
-#endif
-
- *path = first_run_sentinel.AppendASCII(kSentinelFile);
- return true;
-}
-
-#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
-// static
-void Upgrade::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
- if (new_command_line_) {
- if (!RelaunchChromeBrowser(*new_command_line_)) {
- DLOG(ERROR) << "Launching a new instance of the browser failed.";
- } else {
- DLOG(WARNING) << "Launched a new instance of the browser.";
- }
- delete new_command_line_;
- new_command_line_ = NULL;
- }
-}
-#endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
-
-int FirstRunImportObserver::import_result() const {
- return import_result_;
-}
-
-void FirstRunImportObserver::ImportCanceled() {
- import_result_ = ResultCodes::IMPORTER_CANCEL;
- Finish();
-}
-void FirstRunImportObserver::ImportComplete() {
- import_result_ = ResultCodes::NORMAL_EXIT;
- Finish();
-}
-
-void FirstRunImportObserver::RunLoop() {
- loop_running_ = true;
- MessageLoop::current()->Run();
-}
-
-void FirstRunImportObserver::Finish() {
- if (loop_running_)
- MessageLoop::current()->Quit();
-}
-
diff --git a/chrome/browser/first_run.h b/chrome/browser/first_run.h
deleted file mode 100644
index 6615d93..0000000
--- a/chrome/browser/first_run.h
+++ /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.
-
-#ifndef CHROME_BROWSER_FIRST_RUN_H_
-#define CHROME_BROWSER_FIRST_RUN_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "chrome/browser/browser_process_impl.h"
-#include "chrome/browser/importer/importer.h"
-#include "chrome/common/result_codes.h"
-#include "gfx/native_widget_types.h"
-#include "googleurl/src/gurl.h"
-
-class CommandLine;
-class FilePath;
-class Profile;
-class ProcessSingleton;
-
-// This class contains the chrome first-run installation actions needed to
-// fully test the custom installer. It also contains the opposite actions to
-// execute during uninstall. When the first run UI is ready we won't
-// do the actions unconditionally. Currently the only action is to create a
-// desktop shortcut.
-//
-// The way we detect first-run is by looking at a 'sentinel' file.
-// If it does not exist we understand that we need to do the first time
-// install work for this user. After that the sentinel file is created.
-class FirstRun {
- public:
- // There are three types of possible first run bubbles:
- typedef enum {
- LARGEBUBBLE = 0, // The normal bubble, with search engine choice
- OEMBUBBLE, // Smaller bubble for OEM builds
- MINIMALBUBBLE // Minimal bubble shown after search engine dialog
- } BubbleType;
- // See ProcessMasterPreferences for more info about this structure.
- struct MasterPrefs {
- int ping_delay;
- bool homepage_defined;
- int do_import_items;
- int dont_import_items;
- bool run_search_engine_experiment;
- bool randomize_search_engine_experiment;
- std::vector<GURL> new_tabs;
- std::vector<GURL> bookmarks;
- };
-#if defined(OS_WIN)
- // Creates the desktop shortcut to chrome for the current user. Returns
- // false if it fails. It will overwrite the shortcut if it exists.
- static bool CreateChromeDesktopShortcut();
- // Creates the quick launch shortcut to chrome for the current user. Returns
- // false if it fails. It will overwrite the shortcut if it exists.
- static bool CreateChromeQuickLaunchShortcut();
- // Returns true if we are being run in a locale in which search experiments
- // are allowed.
- static bool InSearchExperimentLocale();
-#endif // OS_WIN
- // Import bookmarks and/or browser items (depending on platform support)
- // in this process. This function is paired with FirstRun::ImportSettings().
- // This function might or might not show a visible UI depending on the
- // cmdline parameters.
- static int ImportNow(Profile* profile, const CommandLine& cmdline);
-
- // Automatically import history and home page (and search engine, if
- // nonorganic).
- static void AutoImport(Profile* profile,
- bool homepage_defined,
- int import_items,
- int dont_import_items,
- bool search_engine_experiment,
- bool randomize_search_engine_experiment,
- ProcessSingleton* process_singleton);
-
- // The master preferences is a JSON file with the same entries as the
- // 'Default\Preferences' file. This function locates this file from a standard
- // location and processes it so it becomes the default preferences in the
- // profile pointed to by |user_data_dir|. After processing the file, the
- // function returns true if and only if showing the first run dialog is
- // needed. The detailed settings in the preference file are reported via
- // |preference_details|.
- //
- // This function destroys any existing prefs file and it is meant to be
- // invoked only on first run.
- //
- // See chrome/installer/util/master_preferences.h for a description of
- // 'master_preferences' file.
- static bool ProcessMasterPreferences(const FilePath& user_data_dir,
- MasterPrefs* out_prefs);
-
- // Returns true if this is the first time chrome is run for this user.
- static bool IsChromeFirstRun();
- // Creates the sentinel file that signals that chrome has been configured.
- static bool CreateSentinel();
- // Removes the sentinel file created in ConfigDone(). Returns false if the
- // sentinel file could not be removed.
- static bool RemoveSentinel();
- // Imports settings in a separate process. It spawns a second dedicated
- // browser process that just does the import with the import progress UI.
- static bool ImportSettings(Profile* profile, int browser_type,
- int items_to_import,
- gfx::NativeView parent_window);
-
- // Sets the kShouldShowFirstRunBubble local state pref so that the browser
- // shows the bubble once the main message loop gets going (or refrains from
- // showing the bubble, if |show_bubble| is false). Returns false if the pref
- // could not be set. This function can be called multiple times, but only the
- // initial call will actually set the preference.
- static bool SetShowFirstRunBubblePref(bool show_bubble);
-
- // Sets the kShouldUseOEMFirstRunBubble local state pref so that the
- // browser shows the OEM first run bubble once the main message loop
- // gets going. Returns false if the pref could not be set.
- static bool SetOEMFirstRunBubblePref();
-
- // Sets the kShouldUseMinimalFirstRunBubble local state pref so that the
- // browser shows the minimal first run bubble once the main message loop
- // gets going. Returns false if the pref could not be set.
- static bool SetMinimalFirstRunBubblePref();
-
- // Sets the kShouldShowWelcomePage local state pref so that the browser
- // loads the welcome tab once the message loop gets going. Returns false
- // if the pref could not be set.
- static bool SetShowWelcomePagePref();
-
- private:
- friend class FirstRunTest;
-
-#if defined(OS_WIN)
- // Imports settings in a separate process. It is the implementation of the
- // public version.
- static bool ImportSettings(Profile* profile, int browser_type,
- int items_to_import,
- const std::wstring& import_path,
- gfx::NativeView parent_window);
- // Import browser items in this process. The browser and the items to
- // import are encoded int the command line.
- static int ImportFromBrowser(Profile* profile, const CommandLine& cmdline);
-#elif defined(OS_LINUX)
- static bool ImportBookmarks(const std::wstring& import_bookmarks_path);
-#endif
-
- // Import bookmarks from an html file. The path to the file is provided in
- // the command line.
- static int ImportFromFile(Profile* profile, const CommandLine& cmdline);
-
- // Gives the full path to the sentinel file. The file might not exist.
- static bool GetFirstRunSentinelFilePath(FilePath* path);
-
- // This class is for scoping purposes.
- DISALLOW_IMPLICIT_CONSTRUCTORS(FirstRun);
-};
-
-#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
-// This class contains the actions that need to be performed when an upgrade
-// is required. This involves mainly swapping the chrome exe and relaunching
-// the new browser.
-class Upgrade {
- public:
-#if defined(OS_WIN)
- // Possible results of ShowTryChromeDialog().
- enum TryResult {
- TD_TRY_CHROME, // Launch chrome right now.
- TD_NOT_NOW, // Don't launch chrome. Exit now.
- TD_UNINSTALL_CHROME, // Initiate chrome uninstall and exit.
- TD_DIALOG_ERROR, // An error occurred creating the dialog.
- TD_LAST_ENUM
- };
-
- // Check if current chrome.exe is already running as a browser process by
- // trying to create a Global event with name same as full path of chrome.exe.
- // This method caches the handle to this event so on subsequent calls also
- // it can first close the handle and check for any other process holding the
- // handle to the event.
- static bool IsBrowserAlreadyRunning();
-
- // If the new_chrome.exe exists (placed by the installer then is swapped
- // to chrome.exe and the old chrome is renamed to old_chrome.exe. If there
- // is no new_chrome.exe or the swap fails the return is false;
- static bool SwapNewChromeExeIfPresent();
-
- // Combines the two methods, RelaunchChromeBrowser and
- // SwapNewChromeExeIfPresent, to perform the rename and relaunch of
- // the browser. Note that relaunch does NOT exit the existing browser process.
- // If this is called before message loop is executed, simply exit the main
- // function. If browser is already running, you will need to exit it.
- static bool DoUpgradeTasks(const CommandLine& command_line);
-
- // Shows a modal dialog asking the user to give chrome another try. See
- // above for the possible outcomes of the function. This is an experimental,
- // non-localized dialog.
- // |version| can be 0, 1 or 2 and selects what strings to present.
- static TryResult ShowTryChromeDialog(size_t version);
-#endif // OS_WIN
-
- // Launches chrome again simulating a 'user' launch. If chrome could not
- // be launched the return is false.
- static bool RelaunchChromeBrowser(const CommandLine& command_line);
-
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- static void SaveLastModifiedTimeOfExe();
-#endif
-
- static void SetNewCommandLine(CommandLine* new_command_line) {
- // Takes ownership of the pointer.
- new_command_line_ = new_command_line;
- }
-
- // Launches a new instance of the browser if the current instance in
- // persistent mode an upgrade is detected.
- static void RelaunchChromeBrowserWithNewCommandLineIfNeeded();
-
- // Windows:
- // Checks if chrome_new.exe is present in the current instance's install.
- // Linux:
- // Checks if the last modified time of chrome is newer than that of the
- // current running instance.
- static bool IsUpdatePendingRestart();
-
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- private:
- static double GetLastModifiedTimeOfExe();
- static double saved_last_modified_time_of_exe_;
-#endif
- static CommandLine* new_command_line_;
-};
-#endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
-
-// A subclass of BrowserProcessImpl that does not have a GoogleURLTracker or
-// IntranetRedirectDetector so we don't do any URL fetches (as we have no IO
-// thread to fetch on).
-class FirstRunBrowserProcess : public BrowserProcessImpl {
- public:
- explicit FirstRunBrowserProcess(const CommandLine& command_line)
- : BrowserProcessImpl(command_line) {
- }
- virtual ~FirstRunBrowserProcess() { }
-
- virtual GoogleURLTracker* google_url_tracker() { return NULL; }
- virtual IntranetRedirectDetector* intranet_redirect_detector() {
- return NULL;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FirstRunBrowserProcess);
-};
-
-// This class is used by FirstRun::ImportNow to get notified of the outcome of
-// the import operation. It differs from ImportProcessRunner in that this
-// class executes in the context of importing child process.
-// The values that it handles are meant to be used as the process exit code.
-class FirstRunImportObserver : public ImportObserver {
- public:
- FirstRunImportObserver()
- : loop_running_(false), import_result_(ResultCodes::NORMAL_EXIT) {
- }
- int import_result() const;
- virtual void ImportCanceled();
- virtual void ImportComplete();
- void RunLoop();
- private:
- void Finish();
- bool loop_running_;
- int import_result_;
- DISALLOW_COPY_AND_ASSIGN(FirstRunImportObserver);
-};
-
-
-// Show the First Run UI to the user, allowing them to create shortcuts for
-// the app, import their bookmarks and other data from another browser into
-// |profile| and perhaps some other tasks.
-// |process_singleton| is used to lock the handling of CopyData messages
-// while the First Run UI is visible.
-// |homepage_defined| true indicates that homepage is defined in master
-// preferences and should not be imported from another browser.
-// |import_items| specifies the items to import, specified in master
-// preferences and will override default behavior of importer.
-// |dont_import_items| specifies the items *not* to import, specified in master
-// preferences and will override default behavior of importer.
-// |search_engine_experiment| indicates whether the experimental search engine
-// window should be shown.
-// |randomize_search_engine_experiment| is true if the logos in the search
-// engine window should be shown in randomized order.
-// Returns true if the user clicked "Start", false if the user pressed "Cancel"
-// or closed the dialog.
-bool OpenFirstRunDialog(Profile* profile,
- bool homepage_defined,
- int import_items,
- int dont_import_items,
- bool search_engine_experiment,
- bool randomize_search_engine_experiment,
- ProcessSingleton* process_singleton);
-
-#endif // CHROME_BROWSER_FIRST_RUN_H_
diff --git a/chrome/browser/first_run_browsertest.cc b/chrome/browser/first_run_browsertest.cc
deleted file mode 100644
index 24572fc..0000000
--- a/chrome/browser/first_run_browsertest.cc
+++ /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 "chrome/browser/browser_process.h"
-#include "chrome/browser/first_run.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/in_process_browser_test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-typedef InProcessBrowserTest FirstRunBrowserTest;
-
-IN_PROC_BROWSER_TEST_F(FirstRunBrowserTest, SetShowFirstRunBubblePref) {
- EXPECT_FALSE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldShowFirstRunBubble));
- EXPECT_TRUE(FirstRun::SetShowFirstRunBubblePref(true));
- ASSERT_TRUE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldShowFirstRunBubble));
- EXPECT_TRUE(g_browser_process->local_state()->GetBoolean(
- prefs::kShouldShowFirstRunBubble));
-}
-
-IN_PROC_BROWSER_TEST_F(FirstRunBrowserTest, SetShowWelcomePagePref) {
- EXPECT_FALSE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldShowWelcomePage));
- EXPECT_TRUE(FirstRun::SetShowWelcomePagePref());
- ASSERT_TRUE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldShowWelcomePage));
- EXPECT_TRUE(g_browser_process->local_state()->GetBoolean(
- prefs::kShouldShowWelcomePage));
-}
-
-IN_PROC_BROWSER_TEST_F(FirstRunBrowserTest, SetOEMFirstRunBubblePref) {
- EXPECT_FALSE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldUseOEMFirstRunBubble));
- EXPECT_TRUE(FirstRun::SetOEMFirstRunBubblePref());
- ASSERT_TRUE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldUseOEMFirstRunBubble));
- EXPECT_TRUE(g_browser_process->local_state()->GetBoolean(
- prefs::kShouldUseOEMFirstRunBubble));
-}
-
-IN_PROC_BROWSER_TEST_F(FirstRunBrowserTest, SetMinimalFirstRunBubblePref) {
- EXPECT_FALSE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldUseMinimalFirstRunBubble));
- EXPECT_TRUE(FirstRun::SetMinimalFirstRunBubblePref());
- ASSERT_TRUE(g_browser_process->local_state()->FindPreference(
- prefs::kShouldUseMinimalFirstRunBubble));
- EXPECT_TRUE(g_browser_process->local_state()->GetBoolean(
- prefs::kShouldUseMinimalFirstRunBubble));
-}
diff --git a/chrome/browser/first_run_gtk.cc b/chrome/browser/first_run_gtk.cc
deleted file mode 100644
index 4b61867..0000000
--- a/chrome/browser/first_run_gtk.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 "chrome/browser/first_run.h"
-
-#include "app/app_switches.h"
-#include "app/resource_bundle.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
-#include "chrome/browser/gtk/first_run_dialog.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/shell_integration.h"
-#include "chrome/common/chrome_switches.h"
-#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 "chrome/installer/util/util_constants.h"
-#include "googleurl/src/gurl.h"
-
-bool OpenFirstRunDialog(Profile* profile, bool homepage_defined,
- int import_items,
- int dont_import_items,
- bool search_engine_experiment,
- bool randomize_search_engine_experiment,
- ProcessSingleton* process_singleton) {
- return FirstRunDialog::Show(profile, process_singleton);
-}
-
-FilePath GetDefaultPrefFilePath(bool create_profile_dir,
- const FilePath& user_data_dir) {
- FilePath default_pref_dir =
- ProfileManager::GetDefaultProfileDir(user_data_dir);
- if (create_profile_dir) {
- if (!file_util::PathExists(default_pref_dir)) {
- if (!file_util::CreateDirectory(default_pref_dir))
- return FilePath();
- }
- }
- return ProfileManager::GetProfilePrefsPath(default_pref_dir);
-}
-
-bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
- MasterPrefs* out_prefs) {
- DCHECK(!user_data_dir.empty());
-
- // The standard location of the master prefs is next to the chrome binary.
- FilePath master_prefs;
- if (!PathService::Get(base::DIR_EXE, &master_prefs))
- return true;
- master_prefs = master_prefs.AppendASCII(installer_util::kDefaultMasterPrefs);
-
- scoped_ptr<DictionaryValue> prefs(
- installer_util::ParseDistributionPreferences(master_prefs));
- if (!prefs.get())
- return true;
-
- out_prefs->new_tabs = installer_util::GetFirstRunTabs(prefs.get());
-
- std::string not_used;
- out_prefs->homepage_defined = prefs->GetString(prefs::kHomePage, &not_used);
-
- bool value = false;
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kAltFirstRunBubble, &value) && value)
- FirstRun::SetOEMFirstRunBubblePref();
-
- FilePath user_prefs = GetDefaultPrefFilePath(true, user_data_dir);
- if (user_prefs.empty())
- return true;
-
- // The master prefs are regular prefs so we can just copy the file
- // to the default place and they just work.
- if (!file_util::CopyFile(master_prefs, user_prefs))
- return true;
-
- // Note we are skipping all other master preferences if skip-first-run-ui
- // is *not* specified.
- if (!installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroSkipFirstRunPref, &value) ||
- !value)
- return true;
-
- // From here on we won't show first run so we need to do the work to set the
- // required state given that FirstRunView is not going to be called.
- FirstRun::SetShowFirstRunBubblePref(true);
-
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroShowWelcomePage, &value) &&
- value)
- FirstRun::SetShowWelcomePagePref();
-
- // We need to be able to create the first run sentinel or else we cannot
- // proceed because ImportSettings will launch the importer process which
- // would end up here if the sentinel is not present.
- if (!FirstRun::CreateSentinel())
- return false;
-
- std::wstring import_bookmarks_path;
- installer_util::GetDistroStringPreference(prefs.get(),
- installer_util::master_preferences::kDistroImportBookmarksFromFilePref,
- &import_bookmarks_path);
-
- if (!import_bookmarks_path.empty()) {
- // There are bookmarks to import from a file.
- if (!FirstRun::ImportBookmarks(import_bookmarks_path)) {
- LOG(WARNING) << "silent bookmark import failed";
- }
- }
- return false;
-}
-
-// TODO(port): This is just a piece of the silent import functionality from
-// ImportSettings for Windows. It would be nice to get the rest of it ported.
-bool FirstRun::ImportBookmarks(const std::wstring& import_bookmarks_path) {
- const CommandLine& cmdline = *CommandLine::ForCurrentProcess();
- CommandLine import_cmd(cmdline.GetProgram());
-
- // Propagate user data directory switch.
- if (cmdline.HasSwitch(switches::kUserDataDir)) {
- import_cmd.AppendSwitchWithValue(
- switches::kUserDataDir,
- cmdline.GetSwitchValueASCII(switches::kUserDataDir));
- }
- // Since ImportSettings is called before the local state is stored on disk
- // we pass the language as an argument. GetApplicationLocale checks the
- // current command line as fallback.
- import_cmd.AppendSwitchWithValue(
- switches::kLang,
- ASCIIToWide(g_browser_process->GetApplicationLocale()));
-
- import_cmd.CommandLine::AppendSwitchWithValue(
- switches::kImportFromFile, import_bookmarks_path);
- // Time to launch the process that is going to do the import. We'll wait
- // for the process to return.
- return base::LaunchApp(import_cmd, true, false, NULL);
-}
-
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-CommandLine* Upgrade::new_command_line_ = NULL;
-double Upgrade::saved_last_modified_time_of_exe_ = 0;
-
-// static
-bool Upgrade::IsUpdatePendingRestart() {
- return saved_last_modified_time_of_exe_ !=
- Upgrade::GetLastModifiedTimeOfExe();
-}
-
-// static
-void Upgrade::SaveLastModifiedTimeOfExe() {
- saved_last_modified_time_of_exe_ = Upgrade::GetLastModifiedTimeOfExe();
-}
-
-// static
-bool Upgrade::RelaunchChromeBrowser(const CommandLine& command_line) {
- return base::LaunchApp(command_line, false, false, NULL);
-}
-
-// static
-double Upgrade::GetLastModifiedTimeOfExe() {
- FilePath exe_file_path;
- if (!PathService::Get(base::FILE_EXE, &exe_file_path)) {
- LOG(WARNING) << "Failed to get FilePath object for FILE_EXE.";
- return saved_last_modified_time_of_exe_;
- }
- file_util::FileInfo exe_file_info;
- if (!file_util::GetFileInfo(exe_file_path, &exe_file_info)) {
- LOG(WARNING) << "Failed to get FileInfo object for FILE_EXE - "
- << exe_file_path.value();
- return saved_last_modified_time_of_exe_;
- }
- return exe_file_info.last_modified.ToDoubleT();
-}
-#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
diff --git a/chrome/browser/first_run_mac.mm b/chrome/browser/first_run_mac.mm
deleted file mode 100644
index a9c5d21..0000000
--- a/chrome/browser/first_run_mac.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 "chrome/browser/first_run.h"
-
-#import "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/app/breakpad_mac.h"
-#import "chrome/browser/cocoa/first_run_dialog.h"
-#import "chrome/browser/cocoa/import_progress_dialog.h"
-#include "chrome/browser/importer/importer.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/shell_integration.h"
-#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/google_update_settings.h"
-
-// Class that handles conducting the first run operation.
-// FirstRunController deletes itself when the first run operation ends.
-class FirstRunController : public ImportObserver {
- public:
- explicit FirstRunController();
- virtual ~FirstRunController() {}
-
- // Overridden methods from ImportObserver.
- virtual void ImportCanceled() {
- FirstRunDone();
- }
- virtual void ImportComplete() {
- FirstRunDone();
- }
-
- // Display first run UI, start the import and return when it's all over.
- bool DoFirstRun(Profile* profile, ProcessSingleton* process_singleton);
-
- private:
- // This method closes the first run window and quits the message loop so that
- // the Chrome startup can continue. This should be called when all the
- // first run tasks are done.
- void FirstRunDone();
-
- scoped_refptr<ImporterHost> importer_host_;
-
- DISALLOW_COPY_AND_ASSIGN(FirstRunController);
-};
-
-
-bool OpenFirstRunDialog(Profile* profile,
- bool homepage_defined,
- int import_items,
- int dont_import_items,
- bool search_engine_experiment,
- bool randomize_search_engine_experiment,
- ProcessSingleton* process_singleton) {
- FirstRunController* controller = new FirstRunController;
- return controller->DoFirstRun(profile, process_singleton);
-}
-
-bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
- MasterPrefs* out_prefs) {
- // TODO(jeremy,viettrungluu): http://crbug.com/44901
- NOTIMPLEMENTED();
- return true;
-}
-
-FirstRunController::FirstRunController()
- : importer_host_(new ExternalProcessImporterHost) {
-}
-
-void FirstRunController::FirstRunDone() {
- // Set preference to show first run bubble and welcome page.
- FirstRun::SetShowFirstRunBubblePref(true);
- FirstRun::SetShowWelcomePagePref();
-}
-
-bool FirstRunController::DoFirstRun(Profile* profile,
- ProcessSingleton* process_singleton) {
- // This object is responsible for deleting itself, make sure that happens.
- scoped_ptr<FirstRunController> gc(this);
-
- // Breakpad should not be enabled on first run until the user has explicitly
- // opted-into stats.
- // TODO: The behavior we probably want here is to enable Breakpad on first run
- // but display a confirmation dialog before sending a crash report so we
- // respect a user's privacy while still getting any crashes that might happen
- // before this point. Then remove the need for that dialog here.
- DCHECK(!IsCrashReporterEnabled());
-
- scoped_nsobject<FirstRunDialogController> dialog(
- [[FirstRunDialogController alloc] init]);
-
- // Set list of browsers we know how to import.
- ssize_t profiles_count = importer_host_->GetAvailableProfileCount();
-
- // TODO(jeremy): Test on newly created account.
- // TODO(jeremy): Correctly handle case where no browsers to import from
- // are detected.
- NSMutableArray *browsers = [NSMutableArray arrayWithCapacity:profiles_count];
- for (int i = 0; i < profiles_count; ++i) {
- std::wstring profile = importer_host_->GetSourceProfileNameAt(i);
- [browsers addObject:base::SysWideToNSString(profile)];
- }
- [dialog.get() setBrowserImportList:browsers];
-
- BOOL browser_import_disabled = profiles_count == 0;
- [dialog.get() setBrowserImportListHidden:browser_import_disabled];
-
- // FirstRunDialogController will call exit if "Cancel" is clicked.
- [dialog.get() showWindow:nil];
-
- // If user clicked cancel, bail - browser_main will return if we haven't
- // turned off the first run flag when this function returns.
- if ([dialog.get() userDidCancel]) {
- return false;
- }
-
- // Don't enable stats in Chromium.
- bool stats_enabled = false;
-#if defined(GOOGLE_CHROME_BUILD)
- stats_enabled = [dialog.get() statsEnabled] ? true : false;
-#endif // GOOGLE_CHROME_BUILD
- FirstRun::CreateSentinel();
- GoogleUpdateSettings::SetCollectStatsConsent(stats_enabled);
-
-#if defined(GOOGLE_CHROME_BUILD)
- // Breakpad is normally enabled very early in the startup process,
- // however, on the first run it's off by default. If the user opts-in to
- // stats, enable breakpad.
- if (stats_enabled) {
- InitCrashReporter();
- InitCrashProcessInfo();
- }
-#endif // GOOGLE_CHROME_BUILD
-
- // If selected set as default browser.
- BOOL make_default_browser = [dialog.get() makeDefaultBrowser];
- if (make_default_browser) {
- bool success = ShellIntegration::SetAsDefaultBrowser();
- DCHECK(success);
- }
-
- // Import bookmarks.
- if (!browser_import_disabled && [dialog.get() importBookmarks]) {
- const importer::ProfileInfo& source_profile = importer_host_->
- GetSourceProfileInfoAt([dialog.get() browserImportSelectedIndex]);
- int16 items = source_profile.services_supported;
- // TODO(port): Do the actual import in a new process like Windows.
- ignore_result(gc.release());
- StartImportingWithUI(nil, items, importer_host_.get(),
- source_profile, profile, this, true);
- } else {
- // This is called by the importer if it runs.
- FirstRunDone();
- }
-
- return true;
-}
diff --git a/chrome/browser/first_run_unittest.cc b/chrome/browser/first_run_unittest.cc
deleted file mode 100644
index 8555370..0000000
--- a/chrome/browser/first_run_unittest.cc
+++ /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/file_util.h"
-#include "chrome/browser/first_run.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class FirstRunTest : public testing::Test {
- protected:
- virtual void SetUp() {
- FirstRun::GetFirstRunSentinelFilePath(&sentinel_path_);
- }
-
- FilePath sentinel_path_;
-};
-
-TEST_F(FirstRunTest, RemoveSentinel) {
- EXPECT_TRUE(FirstRun::CreateSentinel());
- EXPECT_TRUE(file_util::PathExists(sentinel_path_));
-
- EXPECT_TRUE(FirstRun::RemoveSentinel());
- EXPECT_FALSE(file_util::PathExists(sentinel_path_));
-}
diff --git a/chrome/browser/first_run_win.cc b/chrome/browser/first_run_win.cc
deleted file mode 100644
index ed43854..0000000
--- a/chrome/browser/first_run_win.cc
+++ /dev/null
@@ -1,1077 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/first_run.h"
-
-#include <windows.h>
-#include <shellapi.h>
-#include <shlobj.h>
-
-#include <set>
-#include <sstream>
-
-// TODO(port): trim this include list once first run has been refactored fully.
-#include "app/app_switches.h"
-#include "app/l10n_util.h"
-#include "app/l10n_util_win.h"
-#include "app/resource_bundle.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/object_watcher.h"
-#include "base/path_service.h"
-#include "base/process.h"
-#include "base/process_util.h"
-#include "base/registry.h"
-#include "base/scoped_comptr_win.h"
-#include "base/string_util.h"
-#include "base/win_util.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_switches.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/browser/browser_process.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/hang_monitor/hung_window_detector.h"
-#include "chrome/browser/importer/importer.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/process_singleton.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/shell_integration.h"
-#include "chrome/browser/views/first_run_search_engine_view.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/result_codes.h"
-#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/google_update_settings.h"
-#include "chrome/installer/util/install_util.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/shell_util.h"
-#include "chrome/installer/util/util_constants.h"
-#include "google_update_idl.h"
-#include "grit/app_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "grit/theme_resources.h"
-#include "views/background.h"
-#include "views/controls/button/image_button.h"
-#include "views/controls/button/native_button.h"
-#include "views/controls/button/radio_button.h"
-#include "views/controls/image_view.h"
-#include "views/controls/label.h"
-#include "views/controls/link.h"
-#include "views/focus/accelerator_handler.h"
-#include "views/grid_layout.h"
-#include "views/standard_layout.h"
-#include "views/widget/root_view.h"
-#include "views/widget/widget_win.h"
-#include "views/window/window.h"
-#include "views/window/window_delegate.h"
-#include "views/window/window_win.h"
-
-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);
- return true;
-}
-
-FilePath GetDefaultPrefFilePath(bool create_profile_dir,
- const FilePath& user_data_dir) {
- FilePath default_pref_dir =
- ProfileManager::GetDefaultProfileDir(user_data_dir);
- if (create_profile_dir) {
- if (!file_util::PathExists(default_pref_dir)) {
- if (!file_util::CreateDirectory(default_pref_dir))
- return FilePath();
- }
- }
- return ProfileManager::GetProfilePrefsPath(default_pref_dir);
-}
-
-bool InvokeGoogleUpdateForRename() {
- ScopedComPtr<IProcessLauncher> ipl;
- if (!FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass)))) {
- ULONG_PTR phandle = NULL;
- DWORD id = GetCurrentProcessId();
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- if (!FAILED(ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(),
- google_update::kRegRenameCmdField,
- id, &phandle))) {
- HANDLE handle = HANDLE(phandle);
- DWORD exit_code;
- ::GetExitCodeProcess(handle, &exit_code);
- ::CloseHandle(handle);
- if (exit_code == installer_util::RENAME_SUCCESSFUL)
- return true;
- }
- }
- return false;
-}
-
-bool LaunchSetupWithParam(const std::string& param, const std::wstring& value,
- int* ret_code) {
- 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);
- base::ProcessHandle ph;
- CommandLine cl(exe_path);
- cl.AppendSwitchWithValue(param, value);
-
- CommandLine* browser_command_line = CommandLine::ForCurrentProcess();
- if (browser_command_line->HasSwitch(switches::kChromeFrame)) {
- cl.AppendSwitch(switches::kChromeFrame);
- }
-
- if (!base::LaunchApp(cl, false, false, &ph))
- return false;
- DWORD wr = ::WaitForSingleObject(ph, INFINITE);
- if (wr != WAIT_OBJECT_0)
- return false;
- return (TRUE == ::GetExitCodeProcess(ph, reinterpret_cast<DWORD*>(ret_code)));
-}
-
-bool WriteEULAtoTempFile(FilePath* eula_path) {
- base::StringPiece terms =
- ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_TERMS_HTML);
- if (terms.empty())
- return false;
- FilePath temp_dir;
- if (!file_util::GetTempDir(&temp_dir))
- return false;
- *eula_path = temp_dir.Append(L"chrome_eula_iframe.html");
- return (file_util::WriteFile(*eula_path, terms.data(), terms.size()) > 0);
-}
-
-// Helper class that performs delayed first-run tasks that need more of the
-// chrome infrastructure to be up an running before they can be attempted.
-class FirsRunDelayedTasks : public NotificationObserver {
- public:
- enum Tasks {
- NO_TASK,
- INSTALL_EXTENSIONS
- };
-
- explicit FirsRunDelayedTasks(Tasks task) {
- if (task == INSTALL_EXTENSIONS) {
- registrar_.Add(this, NotificationType::EXTENSIONS_READY,
- NotificationService::AllSources());
- }
- registrar_.Add(this, NotificationType::BROWSER_CLOSED,
- NotificationService::AllSources());
- }
-
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- // After processing the notification we always delete ourselves.
- if (type.value == NotificationType::EXTENSIONS_READY)
- DoExtensionWork(Source<Profile>(source).ptr()->GetExtensionsService());
- delete this;
- return;
- }
-
- private:
- // Private ctor forces it to be created only in the heap.
- ~FirsRunDelayedTasks() {}
-
- // 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) {
- if (!service)
- return;
- service->updater()->CheckNow();
- return;
- }
-
- NotificationRegistrar registrar_;
-};
-
-} // namespace
-
-CommandLine* Upgrade::new_command_line_ = NULL;
-
-bool FirstRun::CreateChromeDesktopShortcut() {
- std::wstring 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,
- dist->GetAppDescription(), ShellUtil::CURRENT_USER,
- false, true); // create if doesn't exist.
-}
-
-bool FirstRun::CreateChromeQuickLaunchShortcut() {
- std::wstring chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &chrome_exe))
- return false;
- return ShellUtil::CreateChromeQuickLaunchShortcut(chrome_exe,
- ShellUtil::CURRENT_USER, // create only for current user.
- true); // create if doesn't exist.
-}
-
-bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
- MasterPrefs* out_prefs) {
- DCHECK(!user_data_dir.empty());
-
- // The standard location of the master prefs is next to the chrome exe.
- FilePath master_prefs;
- if (!PathService::Get(base::DIR_EXE, &master_prefs))
- return true;
- master_prefs = master_prefs.AppendASCII(installer_util::kDefaultMasterPrefs);
-
- scoped_ptr<DictionaryValue> prefs(
- installer_util::ParseDistributionPreferences(master_prefs));
- if (!prefs.get())
- return true;
-
- out_prefs->new_tabs = installer_util::GetFirstRunTabs(prefs.get());
-
- if (!installer_util::GetDistroIntegerPreference(prefs.get(),
- installer_util::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;
- }
-
- std::string not_used;
- out_prefs->homepage_defined = prefs->GetString(prefs::kHomePage, &not_used);
-
- bool value = false;
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::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
- // dismisses the dialog.
-
- // The actual eula text is in a resource in chrome. We extract it to
- // a text file so setup.exe can use it as an inner frame.
- FilePath inner_html;
- if (WriteEULAtoTempFile(&inner_html)) {
- int retcode = 0;
- const std::string eula = WideToASCII(installer_util::switches::kShowEula);
- if (!LaunchSetupWithParam(eula, inner_html.ToWStringHack(), &retcode) ||
- (retcode == installer_util::EULA_REJECTED)) {
- LOG(WARNING) << "EULA rejected. Fast exit.";
- ::ExitProcess(1);
- }
- if (retcode == installer_util::EULA_ACCEPTED) {
- LOG(INFO) << "EULA : no collection";
- GoogleUpdateSettings::SetCollectStatsConsent(false);
- } else if (retcode == installer_util::EULA_ACCEPTED_OPT_IN) {
- LOG(INFO) << "EULA : collection consent";
- GoogleUpdateSettings::SetCollectStatsConsent(true);
- }
- }
- }
-
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kAltFirstRunBubble, &value) && value)
- FirstRun::SetOEMFirstRunBubblePref();
-
- FilePath user_prefs = GetDefaultPrefFilePath(true, user_data_dir);
- if (user_prefs.empty())
- return true;
-
- // The master prefs are regular prefs so we can just copy the file
- // to the default place and they just work.
- if (!file_util::CopyFile(master_prefs, user_prefs))
- return true;
-
- DictionaryValue* extensions = 0;
- if (installer_util::HasExtensionsBlock(prefs.get(), &extensions)) {
- LOG(INFO) << "Extensions block found in master preferences";
- new FirsRunDelayedTasks(FirsRunDelayedTasks::INSTALL_EXTENSIONS);
- }
-
- // Add a special exception for import_search_engine preference.
- // Even though we skip all other import_* preferences below, if
- // skip-first-run-ui is not specified, we make exception for this one
- // preference.
- int import_items = 0;
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroImportSearchPref, &value)) {
- if (value) {
- import_items += importer::SEARCH_ENGINES;
- out_prefs->do_import_items += importer::SEARCH_ENGINES;
- } else {
- out_prefs->dont_import_items += importer::SEARCH_ENGINES;
- }
- }
-
- // If we're suppressing the first-run bubble, set that preference now.
- // Otherwise, wait until the user has completed first run to set it, so the
- // user is guaranteed to see the bubble iff he or she has completed the first
- // run process.
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroSuppressFirstRunBubble,
- &value) && value)
- FirstRun::SetShowFirstRunBubblePref(false);
-
- if (InSearchExperimentLocale() &&
- installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kSearchEngineExperimentPref,
- &value) && value) {
- // Set the first run dialog to include the search choice window.
- out_prefs->run_search_engine_experiment = true;
- // Check to see if search engine logos should be randomized.
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::
- kSearchEngineExperimentRandomizePref,
- &value) && value) {
- out_prefs->randomize_search_engine_experiment = true;
- }
- // Set the first run bubble to minimal.
- FirstRun::SetMinimalFirstRunBubblePref();
- }
-
- // History is imported automatically, unless turned off in master_prefs.
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroImportHistoryPref, &value)
- && !value) {
- out_prefs->dont_import_items |= importer::HISTORY;
- }
-
- // Home page is imported automatically only in organic builds, and can be
- // turned off in master_prefs.
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroImportHomePagePref, &value)
- && !value) {
- out_prefs->dont_import_items |= importer::HOME_PAGE;
- }
-
- // Bookmarks are never imported unless specifically turned on.
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroImportBookmarksPref, &value)
- && value) {
- out_prefs->do_import_items |= importer::FAVORITES;
- }
-
- // 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 (!installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroSkipFirstRunPref, &value) ||
- !value)
- return true;
-
- // From here on we won't show first run so we need to do the work to show the
- // bubble anyway, unless it's already been explicitly suppressed.
- FirstRun::SetShowFirstRunBubblePref(true);
-
- // We need to be able to create the first run sentinel or else we cannot
- // proceed because ImportSettings will launch the importer process which
- // would end up here if the sentinel is not present.
- if (!FirstRun::CreateSentinel())
- return false;
-
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kDistroShowWelcomePage, &value) &&
- value)
- FirstRun::SetShowWelcomePagePref();
-
- std::wstring import_bookmarks_path;
- installer_util::GetDistroStringPreference(prefs.get(),
- installer_util::master_preferences::kDistroImportBookmarksFromFilePref,
- &import_bookmarks_path);
-
- if (import_items || !import_bookmarks_path.empty()) {
- // There is something to import from the default browser. This launches
- // the importer process and blocks until done or until it fails.
- scoped_refptr<ImporterHost> importer_host = new ImporterHost();
- if (!FirstRun::ImportSettings(NULL,
- importer_host->GetSourceProfileInfoAt(0).browser_type,
- import_items, import_bookmarks_path, NULL)) {
- LOG(WARNING) << "silent import failed";
- }
- }
-
- if (installer_util::GetDistroBooleanPreference(prefs.get(),
- installer_util::master_preferences::kMakeChromeDefaultForUser, &value) &&
- value)
- ShellIntegration::SetAsDefaultBrowser();
-
- return false;
-}
-
-bool Upgrade::IsBrowserAlreadyRunning() {
- static HANDLE handle = NULL;
- std::wstring exe;
- PathService::Get(base::FILE_EXE, &exe);
- std::replace(exe.begin(), exe.end(), '\\', '!');
- std::transform(exe.begin(), exe.end(), exe.begin(), tolower);
- exe = L"Global\\" + exe;
- if (handle != NULL)
- CloseHandle(handle);
- handle = CreateEvent(NULL, TRUE, TRUE, exe.c_str());
- int error = GetLastError();
- return (error == ERROR_ALREADY_EXISTS || error == ERROR_ACCESS_DENIED);
-}
-
-bool Upgrade::RelaunchChromeBrowser(const CommandLine& command_line) {
- ::SetEnvironmentVariable(
- BrowserDistribution::GetDistribution()->GetEnvVersionKey().c_str(),
- NULL);
- return base::LaunchApp(command_line.command_line_string(),
- false, false, NULL);
-}
-
-bool Upgrade::SwapNewChromeExeIfPresent() {
- FilePath new_chrome_exe;
- if (!GetNewerChromeFile(&new_chrome_exe))
- 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))
- return false;
-
- // First try to rename exe by launching rename command ourselves.
- bool user_install = InstallUtil::IsPerUserInstall(curr_chrome_exe.c_str());
- HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
- BrowserDistribution *dist = BrowserDistribution::GetDistribution();
- RegKey key;
- std::wstring rename_cmd;
- if (key.Open(reg_root, dist->GetVersionKey().c_str(), KEY_READ) &&
- key.ReadValue(google_update::kRegRenameCmdField, &rename_cmd)) {
- base::ProcessHandle handle;
- if (base::LaunchApp(rename_cmd, true, true, &handle)) {
- DWORD exit_code;
- ::GetExitCodeProcess(handle, &exit_code);
- ::CloseHandle(handle);
- if (exit_code == installer_util::RENAME_SUCCESSFUL)
- return true;
- }
- }
-
- // Rename didn't work so try to rename by calling Google Update
- if (InvokeGoogleUpdateForRename())
- return true;
-
- // Rename still didn't work so just try to rename exe ourselves (for
- // backward compatibility, can be deleted once the new process works).
- std::wstring backup_exe;
- if (!GetBackupChromeFile(&backup_exe))
- return false;
- if (::ReplaceFileW(curr_chrome_exe.c_str(), new_chrome_exe.value().c_str(),
- backup_exe.c_str(), REPLACEFILE_IGNORE_MERGE_ERRORS,
- NULL, NULL)) {
- return true;
- }
- return false;
-}
-
-// static
-bool Upgrade::DoUpgradeTasks(const CommandLine& command_line) {
- if (!Upgrade::SwapNewChromeExeIfPresent())
- return false;
- // At this point the chrome.exe has been swapped with the new one.
- if (!Upgrade::RelaunchChromeBrowser(command_line)) {
- // The re-launch fails. Feel free to panic now.
- NOTREACHED();
- }
- return true;
-}
-
-// static
-bool Upgrade::IsUpdatePendingRestart() {
- FilePath new_chrome_exe;
- if (!GetNewerChromeFile(&new_chrome_exe))
- return false;
- return file_util::PathExists(new_chrome_exe);
-}
-
-namespace {
-
-// This class is used by FirstRun::ImportSettings to determine when the import
-// process has ended and what was the result of the operation as reported by
-// the process exit code. This class executes in the context of the main chrome
-// process.
-class ImportProcessRunner : public base::ObjectWatcher::Delegate {
- public:
- // The constructor takes the importer process to watch and then it does a
- // message loop blocking wait until the process ends. This object now owns
- // the import_process handle.
- explicit ImportProcessRunner(base::ProcessHandle import_process)
- : import_process_(import_process),
- exit_code_(ResultCodes::NORMAL_EXIT) {
- watcher_.StartWatching(import_process, this);
- MessageLoop::current()->Run();
- }
- virtual ~ImportProcessRunner() {
- ::CloseHandle(import_process_);
- }
- // Returns the child process exit code. There are 3 expected values:
- // NORMAL_EXIT, IMPORTER_CANCEL or IMPORTER_HUNG.
- int exit_code() const {
- return exit_code_;
- }
- // The child process has terminated. Find the exit code and quit the loop.
- virtual void OnObjectSignaled(HANDLE object) {
- DCHECK(object == import_process_);
- if (!::GetExitCodeProcess(import_process_, &exit_code_)) {
- NOTREACHED();
- }
- MessageLoop::current()->Quit();
- }
-
- private:
- base::ObjectWatcher watcher_;
- base::ProcessHandle import_process_;
- DWORD exit_code_;
-};
-
-// Check every 3 seconds if the importer UI has hung.
-const int kPollHangFrequency = 3000;
-
-// This class specializes on finding hung 'owned' windows. Unfortunately, the
-// HungWindowDetector class cannot be used here because it assumes child
-// windows and not owned top-level windows.
-// This code is executed in the context of the main browser process and will
-// terminate the importer process if it is hung.
-class HungImporterMonitor : public WorkerThreadTicker::Callback {
- public:
- // The ctor takes the owner popup window and the process handle of the
- // process to kill in case the popup or its owned active popup become
- // unresponsive.
- HungImporterMonitor(HWND owner_window, base::ProcessHandle import_process)
- : owner_window_(owner_window),
- import_process_(import_process),
- ticker_(kPollHangFrequency) {
- ticker_.RegisterTickHandler(this);
- ticker_.Start();
- }
- virtual ~HungImporterMonitor() {
- ticker_.Stop();
- ticker_.UnregisterTickHandler(this);
- }
-
- private:
- virtual void OnTick() {
- if (!import_process_)
- return;
- // We find the top active popup that we own, this will be either the
- // owner_window_ itself or the dialog window of the other process. In
- // both cases it is worth hung testing because both windows share the
- // same message queue and at some point the other window could be gone
- // while the other process still not pumping messages.
- HWND active_window = ::GetLastActivePopup(owner_window_);
- if (::IsHungAppWindow(active_window) || ::IsHungAppWindow(owner_window_)) {
- ::TerminateProcess(import_process_, ResultCodes::IMPORTER_HUNG);
- import_process_ = NULL;
- }
- }
-
- HWND owner_window_;
- base::ProcessHandle import_process_;
- WorkerThreadTicker ticker_;
- DISALLOW_COPY_AND_ASSIGN(HungImporterMonitor);
-};
-
-std::wstring EncodeImportParams(int browser_type, int options, HWND window) {
- return StringPrintf(L"%d@%d@%d", browser_type, options, window);
-}
-
-bool DecodeImportParams(const std::wstring& encoded,
- int* browser_type, int* options, HWND* window) {
- std::vector<std::wstring> v;
- SplitString(encoded, L'@', &v);
- if (v.size() != 3)
- return false;
-
- if (!StringToInt(v[0], browser_type))
- return false;
-
- if (!StringToInt(v[1], options))
- return false;
-
- *window = reinterpret_cast<HWND>(StringToInt64(v[2]));
- return true;
-}
-
-} // namespace
-
-void FirstRun::AutoImport(Profile* profile,
- bool homepage_defined,
- int import_items,
- int dont_import_items,
- bool search_engine_experiment,
- bool randomize_search_engine_experiment,
- ProcessSingleton* process_singleton) {
- FirstRun::CreateChromeDesktopShortcut();
- // Windows 7 has deprecated the quick launch bar.
- if (win_util::GetWinVersion() < win_util::WINVERSION_WIN7)
- CreateChromeQuickLaunchShortcut();
-
- scoped_refptr<ImporterHost> importer_host;
- importer_host = new ImporterHost();
- int items = 0;
- // History and home page are always imported unless turned off in
- // master_preferences.
- if (!(dont_import_items & importer::HISTORY))
- items = items | importer::HISTORY;
- if (!((dont_import_items & importer::HOME_PAGE) || homepage_defined))
- items = items | importer::HOME_PAGE;
-
- // Search engine and bookmarks are never imported unless turned on
- // in master_preferences.
- if (import_items & importer::SEARCH_ENGINES)
- items = items | importer::SEARCH_ENGINES;
- if (import_items & importer::FAVORITES)
- items = items | importer::FAVORITES;
- // We need to avoid dispatching new tabs when we are importing because
- // that will lead to data corruption or a crash. Because there is no UI for
- // the import process, we pass NULL as the window to bring to the foreground
- // when a CopyData message comes in; this causes the message to be silently
- // discarded, which is the correct behavior during the import process.
- process_singleton->Lock(NULL);
-
- // Index 0 is the default browser.
- FirstRun::ImportSettings(profile,
- importer_host->GetSourceProfileInfoAt(0).browser_type, items, NULL);
- UserMetrics::RecordAction(UserMetricsAction("FirstRunDef_Accept"));
-
- // Launch the search engine dialog only if build is organic.
- std::wstring brand;
- GoogleUpdateSettings::GetBrand(&brand);
- if (GoogleUpdateSettings::IsOrganic(brand)) {
- // The home page string may be set in the preferences, but the user should
- // initially use Chrome with the NTP as home page in organic builds.
- profile->GetPrefs()->SetBoolean(prefs::kHomePageIsNewTabPage, true);
-
- // Search engine dialog is shown in organic builds unless overridden by
- // master_preferences.
- if (!(import_items & importer::SEARCH_ENGINES)) {
- views::Window* search_engine_dialog = views::Window::CreateChromeWindow(
- NULL,
- gfx::Rect(),
- new FirstRunSearchEngineView(profile,
- randomize_search_engine_experiment));
- DCHECK(search_engine_dialog);
-
- search_engine_dialog->Show();
- views::AcceleratorHandler accelerator_handler;
- MessageLoopForUI::current()->Run(&accelerator_handler);
- search_engine_dialog->Close();
- }
- }
-
- process_singleton->Unlock();
- FirstRun::CreateSentinel();
-}
-
-bool FirstRun::ImportSettings(Profile* profile, int browser_type,
- int items_to_import,
- const std::wstring& import_bookmarks_path,
- HWND parent_window) {
- const CommandLine& cmdline = *CommandLine::ForCurrentProcess();
- CommandLine import_cmd(cmdline.GetProgram());
- // Propagate user data directory switch.
- if (cmdline.HasSwitch(switches::kUserDataDir)) {
- import_cmd.AppendSwitchWithValue(
- switches::kUserDataDir,
- cmdline.GetSwitchValueASCII(switches::kUserDataDir));
- }
-
- // Since ImportSettings is called before the local state is stored on disk
- // we pass the language as an argument. GetApplicationLocale checks the
- // current command line as fallback.
- import_cmd.AppendSwitchWithValue(
- switches::kLang,
- ASCIIToWide(g_browser_process->GetApplicationLocale()));
-
- if (items_to_import) {
- import_cmd.CommandLine::AppendSwitchWithValue(switches::kImport,
- EncodeImportParams(browser_type, items_to_import, parent_window));
- }
-
- if (!import_bookmarks_path.empty()) {
- import_cmd.CommandLine::AppendSwitchWithValue(
- switches::kImportFromFile, import_bookmarks_path.c_str());
- }
-
- if (cmdline.HasSwitch(switches::kChromeFrame)) {
- import_cmd.AppendSwitch(switches::kChromeFrame);
- }
-
- if (cmdline.HasSwitch(switches::kCountry)) {
- import_cmd.AppendSwitchWithValue(switches::kCountry,
- cmdline.GetSwitchValueASCII(switches::kCountry));
- }
-
- // Time to launch the process that is going to do the import.
- base::ProcessHandle import_process;
- if (!base::LaunchApp(import_cmd, false, false, &import_process))
- return false;
-
- // Activate the importer monitor. It awakes periodically in another thread
- // and checks that the importer UI is still pumping messages.
- if (parent_window)
- HungImporterMonitor hang_monitor(parent_window, import_process);
-
- // We block inside the import_runner ctor, pumping messages until the
- // importer process ends. This can happen either by completing the import
- // or by hang_monitor killing it.
- ImportProcessRunner import_runner(import_process);
-
- // Import process finished. Reload the prefs, because importer may set
- // the pref value.
- if (profile)
- profile->GetPrefs()->ReloadPersistentPrefs();
-
- return (import_runner.exit_code() == ResultCodes::NORMAL_EXIT);
-}
-
-bool FirstRun::ImportSettings(Profile* profile, int browser_type,
- int items_to_import,
- HWND parent_window) {
- return ImportSettings(profile, browser_type, items_to_import,
- std::wstring(), parent_window);
-}
-
-int FirstRun::ImportFromBrowser(Profile* profile,
- const CommandLine& cmdline) {
- std::wstring import_info = cmdline.GetSwitchValue(switches::kImport);
- if (import_info.empty()) {
- NOTREACHED();
- return false;
- }
- int browser_type = 0;
- int items_to_import = 0;
- HWND parent_window = NULL;
- if (!DecodeImportParams(import_info, &browser_type, &items_to_import,
- &parent_window)) {
- NOTREACHED();
- return false;
- }
- scoped_refptr<ImporterHost> importer_host = new ImporterHost();
- FirstRunImportObserver observer;
-
- // If there is no parent window, we run in headless mode which amounts
- // to having the windows hidden and if there is user action required the
- // import is automatically canceled.
- if (!parent_window)
- importer_host->set_headless();
-
- StartImportingWithUI(
- parent_window,
- items_to_import,
- importer_host,
- importer_host->GetSourceProfileInfoForBrowserType(browser_type),
- profile,
- &observer,
- true);
- observer.RunLoop();
- return observer.import_result();
-}
-
-// static
-bool FirstRun::InSearchExperimentLocale() {
- static std::set<std::string> allowed_locales;
- if (allowed_locales.empty()) {
- // List of locales in which search experiment can be run.
- allowed_locales.insert("en-GB");
- allowed_locales.insert("en-US");
- }
- const std::string app_locale = g_browser_process->GetApplicationLocale();
- std::set<std::string>::iterator locale = allowed_locales.find(app_locale);
- return locale != allowed_locales.end();
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-namespace {
-
-const wchar_t kHelpCenterUrl[] =
- L"http://www.google.com/support/chrome/bin/answer.py?answer=150752";
-
-// This class displays a modal dialog using the views system. The dialog asks
-// the user to give chrome another try. This class only handles the UI so the
-// resulting actions are up to the caller. One version looks like this:
-//
-// /----------------------------------------\
-// | |icon| You stopped using Google [x] |
-// | |icon| Chrome. Would you like to.. |
-// | [o] Give the new version a try |
-// | [ ] Uninstall Google Chrome |
-// | [ OK ] [Don't bug me] |
-// | _why_am_I_seeign this?__ |
-// ------------------------------------------
-class TryChromeDialog : public views::ButtonListener,
- public views::LinkController {
- public:
- TryChromeDialog()
- : popup_(NULL),
- try_chrome_(NULL),
- kill_chrome_(NULL),
- result_(Upgrade::TD_LAST_ENUM) {
- }
-
- virtual ~TryChromeDialog() {
- };
-
- // Shows the modal dialog asking the user to try chrome. Note that the dialog
- // has no parent and it will position itself in a lower corner of the screen.
- // The dialog does not steal focus and does not have an entry in the taskbar.
- Upgrade::TryResult ShowModal() {
- using views::GridLayout;
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-
- views::ImageView* icon = new views::ImageView();
- icon->SetImage(*rb.GetBitmapNamed(IDR_PRODUCT_ICON_32));
- gfx::Size icon_size = icon->GetPreferredSize();
-
- // An approximate window size. After Layout() we'll get better bounds.
- gfx::Rect pos(310, 160);
- views::WidgetWin* popup = new views::WidgetWin();
- if (!popup) {
- NOTREACHED();
- return Upgrade::TD_DIALOG_ERROR;
- }
- popup->set_delete_on_destroy(true);
- popup->set_window_style(WS_POPUP | WS_CLIPCHILDREN);
- popup->set_window_ex_style(WS_EX_TOOLWINDOW);
- popup->Init(NULL, pos);
-
- views::RootView* root_view = popup->GetRootView();
- // The window color is a tiny bit off-white.
- root_view->set_background(
- views::Background::CreateSolidBackground(0xfc, 0xfc, 0xfc));
-
- views::GridLayout* layout = CreatePanelGridLayout(root_view);
- if (!layout) {
- NOTREACHED();
- return Upgrade::TD_DIALOG_ERROR;
- }
- root_view->SetLayoutManager(layout);
-
- views::ColumnSet* columns;
- // First row: [icon][pad][text][button].
- columns = layout->AddColumnSet(0);
- columns->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
- GridLayout::FIXED, icon_size.width(),
- icon_size.height());
- columns->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- columns->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- columns->AddColumn(GridLayout::TRAILING, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- // Second row: [pad][pad][radio 1].
- columns = layout->AddColumnSet(1);
- columns->AddPaddingColumn(0, icon_size.width());
- columns->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- // Third row: [pad][pad][radio 2].
- columns = layout->AddColumnSet(2);
- columns->AddPaddingColumn(0, icon_size.width());
- columns->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- // Fourth row: [pad][pad][button][pad][button].
- columns = layout->AddColumnSet(3);
- columns->AddPaddingColumn(0, icon_size.width());
- columns->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
- GridLayout::USE_PREF, 0, 0);
- columns->AddPaddingColumn(0, kRelatedButtonHSpacing);
- columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
- GridLayout::USE_PREF, 0, 0);
- // Fifth row: [pad][pad][link].
- columns = layout->AddColumnSet(4);
- columns->AddPaddingColumn(0, icon_size.width());
- columns->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- // First row views.
- layout->StartRow(0, 0);
- layout->AddView(icon);
- // The heading has two flavors of text, the alt one features extensions but
- // we only use it in the US until some international issues are fixed.
- const std::string app_locale = g_browser_process->GetApplicationLocale();
- const std::wstring heading = (app_locale == "en-US") ?
- l10n_util::GetString(IDS_TRY_TOAST_ALT_HEADING) :
- l10n_util::GetString(IDS_TRY_TOAST_HEADING);
- views::Label* label =
- new views::Label(heading);
- label->SetFont(rb.GetFont(ResourceBundle::MediumBoldFont));
- label->SetMultiLine(true);
- label->SizeToFit(200);
- label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
- layout->AddView(label);
- // The close button is custom.
- views::ImageButton* close_button = new views::ImageButton(this);
- close_button->SetImage(views::CustomButton::BS_NORMAL,
- rb.GetBitmapNamed(IDR_CLOSE_BAR));
- close_button->SetImage(views::CustomButton::BS_HOT,
- rb.GetBitmapNamed(IDR_CLOSE_BAR_H));
- close_button->SetImage(views::CustomButton::BS_PUSHED,
- rb.GetBitmapNamed(IDR_CLOSE_BAR_P));
- close_button->set_tag(BT_CLOSE_BUTTON);
- layout->AddView(close_button);
-
- // Second row views.
- const std::wstring try_it(l10n_util::GetString(IDS_TRY_TOAST_TRY_OPT));
- layout->StartRowWithPadding(0, 1, 0, 10);
- try_chrome_ = new views::RadioButton(try_it, 1);
- layout->AddView(try_chrome_);
- try_chrome_->SetChecked(true);
-
- // Third row views.
- const std::wstring
- kill_it(l10n_util::GetString(IDS_UNINSTALL_CHROME));
- layout->StartRow(0, 2);
- kill_chrome_ = new views::RadioButton(kill_it, 1);
- layout->AddView(kill_chrome_);
-
- // Fourth row views.
- const std::wstring ok_it(l10n_util::GetString(IDS_OK));
- const std::wstring cancel_it(l10n_util::GetString(IDS_TRY_TOAST_CANCEL));
- const std::wstring why_this(l10n_util::GetString(IDS_TRY_TOAST_WHY));
- layout->StartRowWithPadding(0, 3, 0, 10);
- views::Button* accept_button = new views::NativeButton(this, ok_it);
- accept_button->set_tag(BT_OK_BUTTON);
- layout->AddView(accept_button);
- views::Button* cancel_button = new views::NativeButton(this, cancel_it);
- cancel_button->set_tag(BT_CLOSE_BUTTON);
- layout->AddView(cancel_button);
- // Fifth row views.
- layout->StartRowWithPadding(0, 4, 0, 10);
- views::Link* link = new views::Link(why_this);
- link->SetController(this);
- layout->AddView(link);
-
- // We resize the window according to the layout manager. This takes into
- // account the differences between XP and Vista fonts and buttons.
- layout->Layout(root_view);
- gfx::Size preferred = layout->GetPreferredSize(root_view);
- pos = ComputeWindowPosition(preferred.width(), preferred.height(),
- base::i18n::IsRTL());
- popup->SetBounds(pos);
-
- // Carve the toast shape into the window.
- SetToastRegion(popup->GetNativeView(),
- preferred.width(), preferred.height());
- // Time to show the window in a modal loop.
- popup_ = popup;
- popup_->Show();
- MessageLoop::current()->Run();
- return result_;
- }
-
- protected:
- // Overridden from ButtonListener. We have two buttons and according to
- // what the user clicked we set |result_| and we should always close and
- // end the modal loop.
- virtual void ButtonPressed(views::Button* sender, const views::Event& event) {
- if (sender->tag() == BT_CLOSE_BUTTON) {
- // The user pressed cancel or the [x] button.
- result_ = Upgrade::TD_NOT_NOW;
- } else if (!try_chrome_) {
- // We don't have radio buttons, the user pressed ok.
- result_ = Upgrade::TD_TRY_CHROME;
- } else {
- // The outcome is according to the selected ratio button.
- result_ = try_chrome_->checked() ? Upgrade::TD_TRY_CHROME :
- Upgrade::TD_UNINSTALL_CHROME;
- }
- popup_->Close();
- MessageLoop::current()->Quit();
- }
-
- // Overridden from LinkController. If the user selects the link we need to
- // fire off the default browser that by some convoluted logic should not be
- // chrome.
- virtual void LinkActivated(views::Link* source, int event_flags) {
- ::ShellExecuteW(NULL, L"open", kHelpCenterUrl, NULL, NULL, SW_SHOW);
- }
-
- private:
- enum ButtonTags {
- BT_NONE,
- BT_CLOSE_BUTTON,
- BT_OK_BUTTON,
- };
-
- // Returns a screen rectangle that is fit to show the window. In particular
- // it has the following properties: a) is visible and b) is attached to
- // the bottom of the working area. For LTR machines it returns a left side
- // rectangle and for RTL it returns a right side rectangle so that the
- // dialog does not compete with the standar place of the start menu.
- gfx::Rect ComputeWindowPosition(int width, int height, bool is_RTL) {
- // The 'Shell_TrayWnd' is the taskbar. We like to show our window in that
- // monitor if we can. This code works even if such window is not found.
- HWND taskbar = ::FindWindowW(L"Shell_TrayWnd", NULL);
- HMONITOR monitor =
- ::MonitorFromWindow(taskbar, MONITOR_DEFAULTTOPRIMARY);
- MONITORINFO info = {sizeof(info)};
- if (!GetMonitorInfoW(monitor, &info)) {
- // Quite unexpected. Do a best guess at a visible rectangle.
- return gfx::Rect(20, 20, width + 20, height + 20);
- }
- // The |rcWork| is the work area. It should account for the taskbars that
- // are in the screen when we called the function.
- int left = is_RTL ? info.rcWork.left : info.rcWork.right - width;
- int top = info.rcWork.bottom - height;
- return gfx::Rect(left, top, width, height);
- }
-
- // Create a windows region that looks like a toast of width |w| and
- // height |h|. This is best effort, so we don't care much if the operation
- // fails.
- void SetToastRegion(HWND window, int w, int h) {
- static const POINT polygon[] = {
- {0, 4}, {1, 2}, {2, 1}, {4, 0}, // Left side.
- {w-4, 0}, {w-2, 1}, {w-1, 2}, {w, 4}, // Right side.
- {w, h}, {0, h}
- };
- HRGN region = ::CreatePolygonRgn(polygon, arraysize(polygon), WINDING);
- ::SetWindowRgn(window, region, FALSE);
- }
-
- // controls which version of the text to use.
- size_t version_;
-
- // We don't own any of this pointers. The |popup_| owns itself and owns
- // the other views.
- views::WidgetWin* popup_;
- views::RadioButton* try_chrome_;
- views::RadioButton* kill_chrome_;
- Upgrade::TryResult result_;
-
- DISALLOW_COPY_AND_ASSIGN(TryChromeDialog);
-};
-
-} // namespace
-
-Upgrade::TryResult Upgrade::ShowTryChromeDialog(size_t version) {
- if (version > 10000) {
- // This is a test value. We want to make sure we exercise
- // returning this early. See EarlyReturnTest test harness.
- return Upgrade::TD_NOT_NOW;
- }
- TryChromeDialog td;
- return td.ShowModal();
-}
diff --git a/chrome/browser/fonts_languages_window.h b/chrome/browser/fonts_languages_window.h
index bfb9bb7..0e47c92 100644
--- a/chrome/browser/fonts_languages_window.h
+++ b/chrome/browser/fonts_languages_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_FONTS_LANGUAGES_WINDOW_H_
#define CHROME_BROWSER_FONTS_LANGUAGES_WINDOW_H_
+#pragma once
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/gears_integration.h b/chrome/browser/gears_integration.h
index 1435641..4723c9b 100644
--- a/chrome/browser/gears_integration.h
+++ b/chrome/browser/gears_integration.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEARS_INTEGRATION_H__
#define CHROME_BROWSER_GEARS_INTEGRATION_H__
+#pragma once
#include "base/callback.h"
#include "base/string16.h"
diff --git a/chrome/browser/geolocation/access_token_store.cc b/chrome/browser/geolocation/access_token_store.cc
index b0d2d5e..63b8478 100644
--- a/chrome/browser/geolocation/access_token_store.cc
+++ b/chrome/browser/geolocation/access_token_store.cc
@@ -4,11 +4,12 @@
#include "chrome/browser/geolocation/access_token_store.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/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
@@ -47,11 +48,11 @@ void ChromePrefsAccessTokenStore::LoadDictionaryStoreInUIThread(
if (token_dictionary != NULL) {
for (DictionaryValue::key_iterator it = token_dictionary->begin_keys();
it != token_dictionary->end_keys(); ++it) {
- GURL url(WideToUTF8(*it));
+ GURL url(*it);
if (!url.is_valid())
continue;
- token_dictionary->GetStringAsUTF16WithoutPathExpansion(
- *it, &access_token_set[url]);
+ token_dictionary->GetStringWithoutPathExpansion(*it,
+ &access_token_set[url]);
}
}
request->ForwardResultAsync(MakeTuple(access_token_set));
@@ -70,8 +71,7 @@ void SetAccessTokenOnUIThread(const GURL& server_url, const string16& token) {
g_browser_process->local_state()->GetMutableDictionary(
prefs::kGeolocationAccessToken);
access_token_dictionary->SetWithoutPathExpansion(
- UTF8ToWide(server_url.spec()),
- Value::CreateStringValueFromUTF16(token));
+ server_url.spec(), Value::CreateStringValue(token));
}
void ChromePrefsAccessTokenStore::SaveAccessToken(
diff --git a/chrome/browser/geolocation/access_token_store.h b/chrome/browser/geolocation/access_token_store.h
index 1002044..b8eb67b 100644
--- a/chrome/browser/geolocation/access_token_store.h
+++ b/chrome/browser/geolocation/access_token_store.h
@@ -12,6 +12,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_ACCESS_TOKEN_STORE_H_
#define CHROME_BROWSER_GEOLOCATION_ACCESS_TOKEN_STORE_H_
+#pragma once
#include <map>
diff --git a/chrome/browser/geolocation/access_token_store_browsertest.cc b/chrome/browser/geolocation/access_token_store_browsertest.cc
index 062fb28..f7ea990 100644
--- a/chrome/browser/geolocation/access_token_store_browsertest.cc
+++ b/chrome/browser/geolocation/access_token_store_browsertest.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/geolocation/access_token_store.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/geolocation/device_data_provider.h b/chrome/browser/geolocation/device_data_provider.h
index f13c770..9cd4390 100644
--- a/chrome/browser/geolocation/device_data_provider.h
+++ b/chrome/browser/geolocation/device_data_provider.h
@@ -21,19 +21,18 @@
#ifndef CHROME_BROWSER_GEOLOCATION_DEVICE_DATA_PROVIDER_H_
#define CHROME_BROWSER_GEOLOCATION_DEVICE_DATA_PROVIDER_H_
+#pragma once
#include <algorithm>
-#include <functional>
#include <set>
-#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/non_thread_safe.h"
+#include "base/ref_counted.h"
#include "base/string16.h"
#include "base/string_util.h"
-#include "base/scoped_ptr.h"
#include "base/task.h"
// The following data structures are used to store cell radio data and wifi
@@ -133,7 +132,7 @@ struct AccessPointData {
// This is to allow AccessPointData to be used in std::set. We order
// lexicographically by MAC address.
-struct AccessPointDataLess : public std::less<AccessPointData> {
+struct AccessPointDataLess {
bool operator()(const AccessPointData& data1,
const AccessPointData& data2) const {
return data1.mac_address < data2.mac_address;
@@ -176,6 +175,49 @@ struct WifiData {
AccessPointDataSet access_point_data;
};
+// Gateway data relating to a single router.
+struct RouterData {
+ RouterData() {}
+ // MAC address, formatted as per MacAddressAsString16.
+ string16 mac_address;
+};
+
+// This is to allow RouterData to be used in std::set. We order
+// lexicographically by MAC address.
+struct RouterDataLess {
+ bool operator()(const RouterData& data1,
+ const RouterData& data2) const {
+ return data1.mac_address < data2.mac_address;
+ }
+};
+
+// All gateway data for routers.
+struct GatewayData {
+ // Determines whether a new set of gateway data differs significantly
+ // from this.
+ bool DiffersSignificantly(const GatewayData& other) const {
+ // Any change is significant.
+ if (this->router_data.size() != other.router_data.size())
+ return true;
+ RouterDataSet::const_iterator iter1 = router_data.begin();
+ RouterDataSet::const_iterator iter2 = other.router_data.begin();
+ while (iter1 != router_data.end()) {
+ if (iter1->mac_address != iter2->mac_address) {
+ // There is a difference between the sets of routers.
+ return true;
+ }
+ ++iter1;
+ ++iter2;
+ }
+ return false;
+ }
+
+ // Store routers as a set, sorted by MAC address. This allows quick
+ // comparison of sets for detecting changes and for caching.
+ typedef std::set<RouterData, RouterDataLess> RouterDataSet;
+ RouterDataSet router_data;
+};
+
template<typename DataType>
class DeviceDataProvider;
@@ -271,6 +313,7 @@ class DeviceDataProviderImplBase : public DeviceDataProviderImplBaseHack {
DISALLOW_COPY_AND_ASSIGN(DeviceDataProviderImplBase);
};
+typedef DeviceDataProviderImplBase<GatewayData> GatewayDataProviderImplBase;
typedef DeviceDataProviderImplBase<RadioData> RadioDataProviderImplBase;
typedef DeviceDataProviderImplBase<WifiData> WifiDataProviderImplBase;
@@ -307,16 +350,20 @@ class DeviceDataProvider : public NonThreadSafe {
// Adds a listener, which will be called back with DeviceDataUpdateAvailable
// whenever new data is available. Returns the singleton instance.
static DeviceDataProvider* Register(ListenerInterface* listener) {
+ bool need_to_start_thread = false;
if (!instance_) {
instance_ = new DeviceDataProvider();
+ need_to_start_thread = true;
}
DCHECK(instance_);
DCHECK(instance_->CalledOnValidThread());
instance_->AddListener(listener);
// Start the provider after adding the listener, to avoid any race in
// it receiving an early callback.
- bool started = instance_->StartDataProvider();
- DCHECK(started);
+ if (need_to_start_thread) {
+ bool started = instance_->StartDataProvider();
+ DCHECK(started);
+ }
return instance_;
}
@@ -407,6 +454,7 @@ template<typename DataType>
typename DeviceDataProvider<DataType>::ImplFactoryFunction
DeviceDataProvider<DataType>::factory_function_ = DefaultFactoryFunction;
+typedef DeviceDataProvider<GatewayData> GatewayDataProvider;
typedef DeviceDataProvider<RadioData> RadioDataProvider;
typedef DeviceDataProvider<WifiData> WifiDataProvider;
diff --git a/chrome/browser/geolocation/empty_device_data_provider.cc b/chrome/browser/geolocation/empty_device_data_provider.cc
index 9e9fc27..b11dd79 100644
--- a/chrome/browser/geolocation/empty_device_data_provider.cc
+++ b/chrome/browser/geolocation/empty_device_data_provider.cc
@@ -20,3 +20,11 @@ WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
}
#endif
+// Only define for platforms that lack a real gateway data provider.
+#if !defined(OS_WIN)
+// static
+template<>
+GatewayDataProviderImplBase* GatewayDataProvider::DefaultFactoryFunction() {
+ return new EmptyDeviceDataProvider<GatewayData>();
+}
+#endif
diff --git a/chrome/browser/geolocation/empty_device_data_provider.h b/chrome/browser/geolocation/empty_device_data_provider.h
index ac68473..e757b4b 100644
--- a/chrome/browser/geolocation/empty_device_data_provider.h
+++ b/chrome/browser/geolocation/empty_device_data_provider.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H_
#define CHROME_BROWSER_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H_
+#pragma once
#include "chrome/browser/geolocation/device_data_provider.h"
diff --git a/chrome/browser/geolocation/fake_access_token_store.h b/chrome/browser/geolocation/fake_access_token_store.h
index d9d272c..5c68267 100644
--- a/chrome/browser/geolocation/fake_access_token_store.h
+++ b/chrome/browser/geolocation/fake_access_token_store.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_FAKE_ACCESS_TOKEN_STORE_H_
#define CHROME_BROWSER_GEOLOCATION_FAKE_ACCESS_TOKEN_STORE_H_
+#pragma once
#include "chrome/browser/geolocation/access_token_store.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index 7420eef..382b614 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -3,8 +3,9 @@
// found in the LICENSE file.
#include "base/compiler_specific.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
-#include "base/waitable_event.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/app_modal_dialog.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
@@ -29,6 +30,7 @@
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/net_util.h"
+#include "net/test/test_server.h"
// Used to block until an iframe is loaded via a javascript call.
// Note: NavigateToURLBlockUntilNavigationsComplete doesn't seem to work for
@@ -191,7 +193,8 @@ class GeolocationBrowserTest : public InProcessBrowserTest {
GeolocationBrowserTest()
: infobar_(NULL),
current_browser_(NULL),
- html_for_tests_("files/geolocation/simple.html") {
+ html_for_tests_("files/geolocation/simple.html"),
+ started_test_server_(false) {
EnableDOMAutomation();
}
@@ -205,14 +208,14 @@ class GeolocationBrowserTest : public InProcessBrowserTest {
bool Initialize(InitializationOptions options) WARN_UNUSED_RESULT {
GeolocationArbitrator::SetProviderFactoryForTest(
&NewAutoSuccessMockNetworkLocationProvider);
- if (!server_.get()) {
- server_ = StartHTTPServer();
- EXPECT_TRUE(server_.get());
- if (!server_.get())
- return false;
- }
- current_url_ = server_->TestServerPage(html_for_tests_);
+ if (!started_test_server_)
+ started_test_server_ = test_server()->Start();
+ EXPECT_TRUE(started_test_server_);
+ if (!started_test_server_)
+ return false;
+
+ current_url_ = test_server()->GetURL(html_for_tests_);
LOG(WARNING) << "before navigate";
if (options == INITIALIZATION_OFFTHERECORD) {
ui_test_utils::OpenURLOffTheRecord(browser()->profile(), current_url_);
@@ -271,10 +274,10 @@ class GeolocationBrowserTest : public InProcessBrowserTest {
void CheckGeoposition(const Geoposition& geoposition) {
// Checks we have no error.
CheckStringValueFromJavascript("0", "geoGetLastError()");
- CheckStringValueFromJavascript(
- DoubleToString(geoposition.latitude), "geoGetLastPositionLatitude()");
- CheckStringValueFromJavascript(
- DoubleToString(geoposition.longitude), "geoGetLastPositionLongitude()");
+ CheckStringValueFromJavascript(base::DoubleToString(geoposition.latitude),
+ "geoGetLastPositionLatitude()");
+ CheckStringValueFromJavascript(base::DoubleToString(geoposition.longitude),
+ "geoGetLastPositionLongitude()");
}
void SetInfobarResponse(const GURL& requesting_url, bool allowed) {
@@ -330,7 +333,6 @@ class GeolocationBrowserTest : public InProcessBrowserTest {
expected, function, current_browser_->GetSelectedTabContents());
}
- scoped_refptr<HTTPTestServer> server_;
InfoBarDelegate* infobar_;
Browser* current_browser_;
// path element of a URL referencing the html content for this test.
@@ -344,6 +346,9 @@ class GeolocationBrowserTest : public InProcessBrowserTest {
GURL iframe0_url_;
// If not empty, the GURL for the second iframe.
GURL iframe1_url_;
+
+ // TODO(phajdan.jr): Remove after we can ask TestServer whether it is started.
+ bool started_test_server_;
};
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DisplaysPermissionBar) {
@@ -366,9 +371,13 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, ErrorOnPermissionDenied) {
CheckStringValueFromJavascript("1", "geoGetLastError()");
}
-// TODO(bulach): investigate why this fails on mac. It may be related to:
-// http://crbug.com/29424. This also fails on Vista: http://crbug.com/44589
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_NoInfobarForSecondTab) {
+// http://crbug.com/44589. Hangs on Mac, crashes on Windows
+#if defined(OS_MACOSX) || defined(OS_WINDOWS)
+#define MAYBE_NoInfobarForSecondTab DISABLED_NoInfobarForSecondTab
+#else
+#define MAYBE_NoInfobarForSecondTab NoInfobarForSecondTab
+#endif
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForSecondTab) {
ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
AddGeolocationWatch(true);
SetInfobarResponse(current_url_, true);
@@ -381,13 +390,12 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_NoInfobarForSecondTab) {
CheckGeoposition(MockLocationProvider::instance_->position_);
}
-#if defined(OS_MACOSX)
-// Fails sometimes on mac: http://crbug.com/47053
-#define MAYBE_NoInfobarForDeniedOrigin FLAKY_NoInfobarForDeniedOrigin
+// http://crbug.com/44589. Hangs on Mac, crashes on Windows
+#if defined(OS_MACOSX) || defined(OS_WINDOWS)
+#define MAYBE_NoInfobarForDeniedOrigin DISABLED_NoInfobarForDeniedOrigin
#else
#define MAYBE_NoInfobarForDeniedOrigin NoInfobarForDeniedOrigin
#endif
-
IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForDeniedOrigin) {
ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
current_browser_->profile()->GetGeolocationContentSettingsMap()->
@@ -410,7 +418,7 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForAllowedOrigin) {
CheckGeoposition(MockLocationProvider::instance_->position_);
}
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, FLAKY_NoInfobarForOffTheRecord) {
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForOffTheRecord) {
// First, check infobar will be created for regular profile
ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
AddGeolocationWatch(true);
@@ -497,7 +505,9 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, IFramesWithCachedPosition) {
CheckGeoposition(cached_position);
}
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, CancelPermissionForFrame) {
+// See http://crbug.com/56033
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
+ FLAKY_CancelPermissionForFrame) {
html_for_tests_ = "files/geolocation/iframes_different_origin.html";
ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
LOG(WARNING) << "frames loaded";
diff --git a/chrome/browser/geolocation/geolocation_content_settings_map.cc b/chrome/browser/geolocation/geolocation_content_settings_map.cc
index 2723870..db8cd75 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_map.cc
+++ b/chrome/browser/geolocation/geolocation_content_settings_map.cc
@@ -15,11 +15,12 @@
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/scoped_pref_update.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
@@ -67,15 +68,15 @@ ContentSetting GeolocationContentSettingsMap::GetContentSetting(
if (all_settings_dictionary != NULL) {
DictionaryValue* requesting_origin_settings;
if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- UTF8ToWide(requesting_origin.spec()), &requesting_origin_settings)) {
+ requesting_origin.spec(), &requesting_origin_settings)) {
int setting;
if (requesting_origin_settings->GetIntegerWithoutPathExpansion(
- UTF8ToWide(embedding_origin.spec()), &setting))
+ embedding_origin.spec(), &setting))
return IntToContentSetting(setting);
// Check for any-embedder setting
if (requesting_origin != embedding_origin &&
requesting_origin_settings->GetIntegerWithoutPathExpansion(
- L"", &setting))
+ "", &setting))
return IntToContentSetting(setting);
}
}
@@ -92,13 +93,13 @@ GeolocationContentSettingsMap::AllOriginsSettings
if (all_settings_dictionary != NULL) {
for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
i != all_settings_dictionary->end_keys(); ++i) {
- const std::wstring& wide_origin(*i);
- GURL origin_as_url(WideToUTF8(wide_origin));
+ const std::string& origin(*i);
+ GURL origin_as_url(origin);
if (!origin_as_url.is_valid())
continue;
DictionaryValue* requesting_origin_settings_dictionary = NULL;
bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- wide_origin, &requesting_origin_settings_dictionary);
+ origin, &requesting_origin_settings_dictionary);
DCHECK(found);
if (!requesting_origin_settings_dictionary)
continue;
@@ -129,8 +130,6 @@ void GeolocationContentSettingsMap::SetContentSetting(
GURL embedding_origin(embedding_url.GetOrigin());
DCHECK(requesting_origin.is_valid());
DCHECK(embedding_origin.is_valid() || embedding_url.is_empty());
- std::wstring wide_requesting_origin(UTF8ToWide(requesting_origin.spec()));
- std::wstring wide_embedding_origin(UTF8ToWide(embedding_origin.spec()));
PrefService* prefs = profile_->GetPrefs();
DictionaryValue* all_settings_dictionary = prefs->GetMutableDictionary(
prefs::kGeolocationContentSettings);
@@ -139,24 +138,24 @@ void GeolocationContentSettingsMap::SetContentSetting(
ScopedPrefUpdate update(prefs, prefs::kGeolocationContentSettings);
DictionaryValue* requesting_origin_settings_dictionary = NULL;
all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- wide_requesting_origin, &requesting_origin_settings_dictionary);
+ requesting_origin.spec(), &requesting_origin_settings_dictionary);
if (setting == CONTENT_SETTING_DEFAULT) {
if (requesting_origin_settings_dictionary) {
requesting_origin_settings_dictionary->RemoveWithoutPathExpansion(
- wide_embedding_origin, NULL);
+ embedding_origin.spec(), NULL);
if (requesting_origin_settings_dictionary->empty())
all_settings_dictionary->RemoveWithoutPathExpansion(
- wide_requesting_origin, NULL);
+ requesting_origin.spec(), NULL);
}
} else {
if (!requesting_origin_settings_dictionary) {
requesting_origin_settings_dictionary = new DictionaryValue;
all_settings_dictionary->SetWithoutPathExpansion(
- wide_requesting_origin, requesting_origin_settings_dictionary);
+ requesting_origin.spec(), requesting_origin_settings_dictionary);
}
DCHECK(requesting_origin_settings_dictionary);
requesting_origin_settings_dictionary->SetWithoutPathExpansion(
- wide_embedding_origin, Value::CreateIntegerValue(setting));
+ embedding_origin.spec(), Value::CreateIntegerValue(setting));
}
}
@@ -177,11 +176,11 @@ void GeolocationContentSettingsMap::GetOneOriginSettingsFromDictionary(
OneOriginSettings* one_origin_settings) {
for (DictionaryValue::key_iterator i(dictionary->begin_keys());
i != dictionary->end_keys(); ++i) {
- const std::wstring& target(*i);
+ const std::string& target(*i);
int setting = kDefaultSetting;
bool found = dictionary->GetIntegerWithoutPathExpansion(target, &setting);
DCHECK(found);
- GURL target_url(WideToUTF8(target));
+ GURL target_url(target);
// An empty URL has a special meaning (wildcard), so only accept invalid
// URLs if the original version was empty (avoids treating corrupted prefs
// as the wildcard entry; see http://crbug.com/39685)
diff --git a/chrome/browser/geolocation/geolocation_content_settings_map.h b/chrome/browser/geolocation/geolocation_content_settings_map.h
index 05dd1a6..ae56044 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_map.h
+++ b/chrome/browser/geolocation/geolocation_content_settings_map.h
@@ -11,9 +11,9 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_CONTENT_SETTINGS_MAP_H_
#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_CONTENT_SETTINGS_MAP_H_
+#pragma once
#include <map>
-#include <string>
#include "base/basictypes.h"
#include "base/ref_counted.h"
diff --git a/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc b/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc
index defba3a..ae6cbaf 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -212,11 +213,11 @@ TEST_F(GeolocationContentSettingsMapTests, IgnoreInvalidURLsInPrefs) {
prefs::kGeolocationContentSettings);
// For simplicity, use the overloads that do path expansion. As '.' is the
// path separator, we can't have dotted hostnames (which is fine).
- all_settings_dictionary->SetInteger(L"http://a/.http://b/",
+ all_settings_dictionary->SetInteger("http://a/.http://b/",
CONTENT_SETTING_ALLOW);
- all_settings_dictionary->SetInteger(L"bad_requester.http://b/",
+ all_settings_dictionary->SetInteger("bad_requester.http://b/",
CONTENT_SETTING_ALLOW);
- all_settings_dictionary->SetInteger(L"http://a/.bad-embedder",
+ all_settings_dictionary->SetInteger("http://a/.bad-embedder",
CONTENT_SETTING_ALLOW);
GeolocationContentSettingsMap* map =
diff --git a/chrome/browser/geolocation/geolocation_dispatcher_host.h b/chrome/browser/geolocation/geolocation_dispatcher_host.h
index 234dde1..38b79ef 100644
--- a/chrome/browser/geolocation/geolocation_dispatcher_host.h
+++ b/chrome/browser/geolocation/geolocation_dispatcher_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
+#pragma once
#include "base/ref_counted.h"
diff --git a/chrome/browser/geolocation/geolocation_exceptions_table_model.h b/chrome/browser/geolocation/geolocation_exceptions_table_model.h
index c458c0e..937bbd8 100644
--- a/chrome/browser/geolocation/geolocation_exceptions_table_model.h
+++ b/chrome/browser/geolocation/geolocation_exceptions_table_model.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_EXCEPTIONS_TABLE_MODEL_H_
#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_EXCEPTIONS_TABLE_MODEL_H_
+#pragma once
-#include <set>
#include <vector>
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
diff --git a/chrome/browser/geolocation/geolocation_exceptions_table_model_unittest.cc b/chrome/browser/geolocation/geolocation_exceptions_table_model_unittest.cc
index a20bc13..66d1168 100644
--- a/chrome/browser/geolocation/geolocation_exceptions_table_model_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_exceptions_table_model_unittest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/common/content_settings_helper.h"
#include "chrome/test/testing_profile.h"
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc
index 9b6733f..7d75f84 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context.cc
@@ -6,13 +6,14 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_dispatcher_host.h"
#include "chrome/browser/geolocation/location_arbitrator.h"
-#include "chrome/browser/pref_service.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"
@@ -91,7 +92,7 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
TabContents* tab_contents, GeolocationInfoBarQueueController* controller,
int render_process_id, int render_view_id, int bridge_id,
const GURL& requesting_frame_url,
- const std::wstring& display_languages)
+ const std::string& display_languages)
: ConfirmInfoBarDelegate(tab_contents),
tab_contents_(tab_contents),
controller_(controller),
@@ -112,20 +113,20 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
virtual bool Accept() { return OnPermissionSet(true); }
virtual bool Cancel() { return OnPermissionSet(false); }
virtual int GetButtons() const { return BUTTON_OK | BUTTON_CANCEL; }
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
switch (button) {
case BUTTON_OK:
- return l10n_util::GetString(IDS_GEOLOCATION_ALLOW_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_GEOLOCATION_ALLOW_BUTTON);
case BUTTON_CANCEL:
- return l10n_util::GetString(IDS_GEOLOCATION_DENY_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_GEOLOCATION_DENY_BUTTON);
default:
// All buttons are labeled above.
NOTREACHED() << "Bad button id " << button;
- return L"";
+ return string16();
}
}
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetStringF(
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringFUTF16(
IDS_GEOLOCATION_INFOBAR_QUESTION,
net::FormatUrl(requesting_frame_url_.GetOrigin(), display_languages_));
}
@@ -133,8 +134,8 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
return ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_GEOLOCATION_INFOBAR_ICON);
}
- virtual std::wstring GetLinkText() {
- return l10n_util::GetString(IDS_LEARN_MORE);
+ virtual string16 GetLinkText() {
+ return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
}
virtual bool LinkClicked(WindowOpenDisposition disposition) {
// Ignore the click dispostion and always open in a new top level tab.
@@ -158,7 +159,7 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
int render_view_id_;
int bridge_id_;
GURL requesting_frame_url_;
- std::wstring display_languages_;
+ std::string display_languages_;
DISALLOW_IMPLICIT_CONSTRUCTORS(GeolocationConfirmInfoBarDelegate);
};
@@ -205,6 +206,23 @@ GeolocationInfoBarQueueController::~GeolocationInfoBarQueueController() {
void GeolocationInfoBarQueueController::CreateInfoBarRequest(
int render_process_id, int render_view_id, int bridge_id,
const GURL& requesting_frame, const GURL& embedder) {
+ // This makes sure that no duplicates are added to
+ // |pending_infobar_requests_| as an artificial permission request may
+ // already exist in the queue as per
+ // GeolocationPermissionContext::StartUpdatingRequested
+ // See http://crbug.com/51899 for more details.
+ // TODO(joth): Once we have CLIENT_BASED_GEOLOCATION and
+ // WTF_USE_PREEMPT_GEOLOCATION_PERMISSION set in WebKit we should be able to
+ // just use a DCHECK to check if a duplicate is attempting to be added.
+ PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
+ while (i != pending_infobar_requests_.end()) {
+ if (i->Equals(render_process_id, render_view_id, bridge_id)) {
+ // The request already exists.
+ DCHECK(i->IsForPair(requesting_frame, embedder));
+ return;
+ }
+ ++i;
+ }
PendingInfoBarRequest pending_infobar_request;
pending_infobar_request.render_process_id = render_process_id;
pending_infobar_request.render_view_id = render_view_id;
@@ -277,24 +295,28 @@ void GeolocationInfoBarQueueController::OnPermissionSet(
void GeolocationInfoBarQueueController::ShowQueuedInfoBar(
int render_process_id, int render_view_id) {
+ TabContents* tab_contents =
+ tab_util::GetTabContentsByID(render_process_id, render_view_id);
for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
- i != pending_infobar_requests_.end(); ++i) {
- if (i->IsForTab(render_process_id, render_view_id)) {
- // Check if already displayed.
- if (i->infobar_delegate)
- break;
- TabContents* tab_contents =
- tab_util::GetTabContentsByID(render_process_id, render_view_id);
- i->infobar_delegate =
- new GeolocationConfirmInfoBarDelegate(
- tab_contents, this,
- render_process_id, render_view_id,
- i->bridge_id, i->requesting_frame,
- UTF8ToWide(profile_->GetPrefs()->GetString(
- prefs::kAcceptLanguages)));
- tab_contents->AddInfoBar(i->infobar_delegate);
- break;
+ i != pending_infobar_requests_.end();) {
+ if (!i->IsForTab(render_process_id, render_view_id)) {
+ ++i;
+ continue;
}
+ if (!tab_contents) {
+ i = pending_infobar_requests_.erase(i);
+ continue;
+ }
+ // Check if already displayed.
+ if (i->infobar_delegate)
+ break;
+ i->infobar_delegate = new GeolocationConfirmInfoBarDelegate(
+ tab_contents, this,
+ render_process_id, render_view_id,
+ i->bridge_id, i->requesting_frame,
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ tab_contents->AddInfoBar(i->infobar_delegate);
+ break;
}
}
diff --git a/chrome/browser/geolocation/geolocation_permission_context.h b/chrome/browser/geolocation/geolocation_permission_context.h
index d3f3e37..c93fec3 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.h
+++ b/chrome/browser/geolocation/geolocation_permission_context.h
@@ -4,10 +4,9 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_PERMISSION_CONTEXT_H_
#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_PERMISSION_CONTEXT_H_
+#pragma once
-#include <map>
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index b31608a..29c1cb3 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -5,15 +5,20 @@
#include "chrome/browser/geolocation/geolocation_permission_context.h"
#include "base/scoped_vector.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include "chrome/browser/geolocation/geolocation_permission_context.h"
#include "chrome/browser/geolocation/location_arbitrator.h"
#include "chrome/browser/geolocation/location_provider.h"
#include "chrome/browser/geolocation/mock_location_provider.h"
#include "chrome/browser/renderer_host/mock_render_process_host.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/render_messages.h"
+#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
// TestTabContents short-circuits TAB_CONTENTS_INFOBAR_REMOVED to call
@@ -184,7 +189,7 @@ TEST_F(GeolocationPermissionContextTests, QueuedPermission) {
ConfirmInfoBarDelegate* infobar_0 =
contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
ASSERT_TRUE(infobar_0);
- std::wstring text_0 = infobar_0->GetMessageText();
+ string16 text_0 = infobar_0->GetMessageText();
// Accept the first frame.
infobar_0->Accept();
@@ -201,7 +206,7 @@ TEST_F(GeolocationPermissionContextTests, QueuedPermission) {
ConfirmInfoBarDelegate* infobar_1 =
contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
ASSERT_TRUE(infobar_1);
- std::wstring text_1 = infobar_1->GetMessageText();
+ string16 text_1 = infobar_1->GetMessageText();
EXPECT_NE(text_0, text_1);
// Cancel (block) this frame.
@@ -248,7 +253,7 @@ TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) {
ConfirmInfoBarDelegate* infobar_0 =
contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
ASSERT_TRUE(infobar_0);
- std::wstring text_0 = infobar_0->GetMessageText();
+ string16 text_0 = infobar_0->GetMessageText();
// Simulate the frame going away, ensure the infobar for this frame
// is removed and the next pending infobar is created.
@@ -262,7 +267,7 @@ TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) {
ConfirmInfoBarDelegate* infobar_1 =
contents()->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate();
ASSERT_TRUE(infobar_1);
- std::wstring text_1 = infobar_1->GetMessageText();
+ string16 text_1 = infobar_1->GetMessageText();
EXPECT_NE(text_0, text_1);
// Allow this frame.
diff --git a/chrome/browser/geolocation/geolocation_prefs.h b/chrome/browser/geolocation/geolocation_prefs.h
index 3873274..cc39b66 100644
--- a/chrome/browser/geolocation/geolocation_prefs.h
+++ b/chrome/browser/geolocation/geolocation_prefs.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_PREFS_H_
#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_PREFS_H_
+#pragma once
class PrefService;
diff --git a/chrome/browser/geolocation/geolocation_settings_state.cc b/chrome/browser/geolocation/geolocation_settings_state.cc
index 6f8548e..5c7b784 100644
--- a/chrome/browser/geolocation/geolocation_settings_state.cc
+++ b/chrome/browser/geolocation/geolocation_settings_state.cc
@@ -4,9 +4,10 @@
#include "chrome/browser/geolocation/geolocation_settings_state.h"
+#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/pref_names.h"
@@ -43,6 +44,10 @@ void GeolocationSettingsState::DidNavigate(
state_map_.clear();
}
+void GeolocationSettingsState::ClearStateMap() {
+ state_map_.clear();
+}
+
void GeolocationSettingsState::GetDetailedInfo(
FormattedHostsPerState* formatted_hosts_per_state,
unsigned int* tab_state_flags) const {
diff --git a/chrome/browser/geolocation/geolocation_settings_state.h b/chrome/browser/geolocation/geolocation_settings_state.h
index fe3b7b7..97e5468 100644
--- a/chrome/browser/geolocation/geolocation_settings_state.h
+++ b/chrome/browser/geolocation/geolocation_settings_state.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_SETTINGS_STATE_H_
#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_SETTINGS_STATE_H_
+#pragma once
#include <map>
#include <set>
@@ -32,6 +33,8 @@ class GeolocationSettingsState {
// may need to clear our settings.
void DidNavigate(const NavigationController::LoadCommittedDetails& details);
+ void ClearStateMap();
+
enum TabState {
TABSTATE_NONE = 0,
// There's at least one entry with non-default setting.
diff --git a/chrome/browser/geolocation/geolocation_settings_state_unittest.cc b/chrome/browser/geolocation/geolocation_settings_state_unittest.cc
index f001ed2..157c9b1 100644
--- a/chrome/browser/geolocation/geolocation_settings_state_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_settings_state_unittest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/geolocation/geolocation_settings_state.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/test/testing_profile.h"
diff --git a/chrome/browser/geolocation/gps_location_provider_linux.cc b/chrome/browser/geolocation/gps_location_provider_linux.cc
index 9c918a9..4b23ff2 100644
--- a/chrome/browser/geolocation/gps_location_provider_linux.cc
+++ b/chrome/browser/geolocation/gps_location_provider_linux.cc
@@ -121,6 +121,6 @@ void GpsLocationProviderLinux::ScheduleNextGpsPoll(int interval) {
interval);
}
-LocationProviderBase* NewGpsLocationProvider() {
+LocationProviderBase* NewSystemLocationProvider() {
return new GpsLocationProviderLinux(LibGps::New);
}
diff --git a/chrome/browser/geolocation/gps_location_provider_linux.h b/chrome/browser/geolocation/gps_location_provider_linux.h
index 67fd5a8..a06ccbd 100644
--- a/chrome/browser/geolocation/gps_location_provider_linux.h
+++ b/chrome/browser/geolocation/gps_location_provider_linux.h
@@ -9,12 +9,12 @@
#ifndef CHROME_BROWSER_GEOLOCATION_GPS_LOCATION_PROVIDER_LINUX_H_
#define CHROME_BROWSER_GEOLOCATION_GPS_LOCATION_PROVIDER_LINUX_H_
-
-#include "chrome/browser/geolocation/location_provider.h"
-#include "chrome/common/geoposition.h"
+#pragma once
#include "base/scoped_ptr.h"
#include "base/task.h"
+#include "chrome/browser/geolocation/location_provider.h"
+#include "chrome/common/geoposition.h"
class LibGps;
@@ -27,8 +27,8 @@ class GpsLocationProviderLinux : public LocationProviderBase {
public:
typedef LibGps* (*LibGpsFactory)();
// |factory| will be used to create the gpsd client library wrapper. (Note
- // NewGpsLocationProvider() will use the default factory).
- GpsLocationProviderLinux(LibGpsFactory libgps_factory);
+ // NewSystemLocationProvider() will use the default factory).
+ explicit GpsLocationProviderLinux(LibGpsFactory libgps_factory);
virtual ~GpsLocationProviderLinux();
// LocationProvider
diff --git a/chrome/browser/geolocation/libgps_wrapper_linux.h b/chrome/browser/geolocation/libgps_wrapper_linux.h
index 7d5986c..ef9e271 100644
--- a/chrome/browser/geolocation/libgps_wrapper_linux.h
+++ b/chrome/browser/geolocation/libgps_wrapper_linux.h
@@ -11,6 +11,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_LIBGPS_WRAPPER_LINUX_H_
#define CHROME_BROWSER_GEOLOCATION_LIBGPS_WRAPPER_LINUX_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/geolocation/location_arbitrator.cc b/chrome/browser/geolocation/location_arbitrator.cc
index 050407b..bf47ed7 100644
--- a/chrome/browser/geolocation/location_arbitrator.cc
+++ b/chrome/browser/geolocation/location_arbitrator.cc
@@ -105,10 +105,10 @@ class DefaultLocationProviderFactory
return ::NewNetworkLocationProvider(access_token_store, context,
url, access_token);
}
- virtual LocationProviderBase* NewGpsLocationProvider() {
+ virtual LocationProviderBase* NewSystemLocationProvider() {
if (g_provider_factory_function_for_test)
return NULL;
- return ::NewGpsLocationProvider();
+ return ::NewSystemLocationProvider();
}
};
@@ -222,7 +222,7 @@ void GeolocationArbitratorImpl::OnAccessTokenStoresLoaded(
i->first, i->second),
&providers_);
}
- RegisterProvider(provider_factory_->NewGpsLocationProvider(),
+ RegisterProvider(provider_factory_->NewSystemLocationProvider(),
&providers_);
StartProviders();
}
@@ -255,9 +255,9 @@ bool GeolocationArbitratorImpl::IsNewPositionBetter(
// Updates location_info if it's better than what we currently have,
// or if it's a newer update from the same provider.
if (!old_position.IsValidFix()) {
- // Older location wasn't locked.
- return true;
- }
+ // Older location wasn't locked.
+ return true;
+ }
if (new_position.IsValidFix()) {
// New location is locked, let's check if it's any better.
if (old_position.accuracy >= new_position.accuracy) {
diff --git a/chrome/browser/geolocation/location_arbitrator.h b/chrome/browser/geolocation/location_arbitrator.h
index 74403b4..a4d166f 100644
--- a/chrome/browser/geolocation/location_arbitrator.h
+++ b/chrome/browser/geolocation/location_arbitrator.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_LOCATION_ARBITRATOR_H_
#define CHROME_BROWSER_GEOLOCATION_LOCATION_ARBITRATOR_H_
+#pragma once
#include "base/string16.h"
#include "base/time.h"
@@ -42,7 +43,7 @@ class GeolocationArbitrator : public base::RefCounted<GeolocationArbitrator> {
URLRequestContextGetter* context,
const GURL& url,
const string16& access_token) = 0;
- virtual LocationProviderBase* NewGpsLocationProvider() = 0;
+ virtual LocationProviderBase* NewSystemLocationProvider() = 0;
protected:
friend class base::RefCounted<ProviderFactory>;
diff --git a/chrome/browser/geolocation/location_arbitrator_unittest.cc b/chrome/browser/geolocation/location_arbitrator_unittest.cc
index 669ac45..76351ac 100644
--- a/chrome/browser/geolocation/location_arbitrator_unittest.cc
+++ b/chrome/browser/geolocation/location_arbitrator_unittest.cc
@@ -16,7 +16,7 @@ namespace {
class MockLocationObserver : public GeolocationArbitrator::Delegate {
public:
void InvalidateLastPosition() {
- last_position_.accuracy = -1;
+ last_position_.latitude = 100;
last_position_.error_code = Geoposition::ERROR_CODE_NONE;
ASSERT_FALSE(last_position_.IsInitialized());
}
@@ -40,7 +40,7 @@ class MockProviderFactory : public GeolocationArbitrator::ProviderFactory {
const string16& access_token) {
return new MockLocationProvider(&cell_);
}
- virtual LocationProviderBase* NewGpsLocationProvider() {
+ virtual LocationProviderBase* NewSystemLocationProvider() {
return new MockLocationProvider(&gps_);
}
diff --git a/chrome/browser/geolocation/location_provider.cc b/chrome/browser/geolocation/location_provider.cc
index cdfd797..7a868d7 100644
--- a/chrome/browser/geolocation/location_provider.cc
+++ b/chrome/browser/geolocation/location_provider.cc
@@ -56,9 +56,8 @@ void LocationProviderBase::UpdateListeners() {
}
}
-// Currently only Linux has a GPS provider.
-#if !defined(OS_LINUX)
-LocationProviderBase* NewGpsLocationProvider() {
+#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN)
+LocationProviderBase* NewSystemLocationProvider() {
return NULL;
}
#endif
diff --git a/chrome/browser/geolocation/location_provider.h b/chrome/browser/geolocation/location_provider.h
index 5f290bd..6c4d8da 100644
--- a/chrome/browser/geolocation/location_provider.h
+++ b/chrome/browser/geolocation/location_provider.h
@@ -7,11 +7,12 @@
// providers to obtain a position fix.
//
// This file declares a base class to be used by all location providers.
-// Primarily, this class declares interface methods to be implemented by derived
-// classes.
+// Primarily, this class declares interface methods to be implemented by
+// derived classes.
#ifndef CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_
#define CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_
+#pragma once
#include <map>
#include "base/non_thread_safe.h"
@@ -84,13 +85,13 @@ class LocationProviderBase : public NonThreadSafe {
ListenerMap listeners_;
};
-// Factory functions for the various types of location provider to abstract over
-// the platform-dependent implementations.
-LocationProviderBase* NewGpsLocationProvider();
+// Factory functions for the various types of location provider to abstract
+// over the platform-dependent implementations.
LocationProviderBase* NewNetworkLocationProvider(
AccessTokenStore* access_token_store,
URLRequestContextGetter* context,
const GURL& url,
const string16& access_token);
+LocationProviderBase* NewSystemLocationProvider();
#endif // CHROME_BROWSER_GEOLOCATION_LOCATION_PROVIDER_H_
diff --git a/chrome/browser/geolocation/mock_location_provider.h b/chrome/browser/geolocation/mock_location_provider.h
index d2c775f..1fcad60 100644
--- a/chrome/browser/geolocation/mock_location_provider.h
+++ b/chrome/browser/geolocation/mock_location_provider.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_MOCK_LOCATION_PROVIDER_H_
#define CHROME_BROWSER_GEOLOCATION_MOCK_LOCATION_PROVIDER_H_
+#pragma once
#include "chrome/browser/geolocation/location_provider.h"
#include "chrome/common/geoposition.h"
diff --git a/chrome/browser/geolocation/network_location_provider.cc b/chrome/browser/geolocation/network_location_provider.cc
index f3f9c0c..1f77fbc 100644
--- a/chrome/browser/geolocation/network_location_provider.cc
+++ b/chrome/browser/geolocation/network_location_provider.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/geolocation/network_location_provider.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/geolocation/access_token_store.h"
namespace {
@@ -25,12 +26,13 @@ class NetworkLocationProvider::PositionCache {
public:
// Caches the current position response for the current set of cell ID and
// WiFi data. Returns true on success, false otherwise.
- bool CachePosition(const RadioData& radio_data,
+ bool CachePosition(const GatewayData& gateway_data,
+ const RadioData& radio_data,
const WifiData& wifi_data,
const Geoposition& position) {
// Check that we can generate a valid key for the device data.
string16 key;
- if (!MakeKey(radio_data, wifi_data, &key)) {
+ if (!MakeKey(gateway_data, radio_data, wifi_data, &key)) {
return false;
}
// If the cache is full, remove the oldest entry.
@@ -52,10 +54,11 @@ class NetworkLocationProvider::PositionCache {
// Searches for a cached position response for the current set of cell ID and
// WiFi data. Returns the cached position if available, NULL otherwise.
- const Geoposition *FindPosition(const RadioData &radio_data,
+ const Geoposition *FindPosition(const GatewayData &gateway_data,
+ const RadioData &radio_data,
const WifiData &wifi_data) {
string16 key;
- if (!MakeKey(radio_data, wifi_data, &key)) {
+ if (!MakeKey(gateway_data, radio_data, wifi_data, &key)) {
return NULL;
}
CacheMap::const_iterator iter = cache_.find(key);
@@ -64,16 +67,26 @@ class NetworkLocationProvider::PositionCache {
// Makes the key for the map of cached positions, using a set of
// device data. Returns true if a good key was generated, false otherwise.
- static bool MakeKey(const RadioData& /*radio_data*/,
+ static bool MakeKey(const GatewayData& gateway_data,
+ const RadioData& /*radio_data*/,
const WifiData& wifi_data,
string16* key) {
- // Currently we use only the WiFi data, and base the key only on the MAC
- // addresses.
+ // Currently we use only the WiFi data and gateway data, and base the
+ // key only on the MAC addresses.
// TODO(steveblock): Make use of radio_data.
DCHECK(key);
key->clear();
- key->reserve(wifi_data.access_point_data.size() * 19);
+ key->reserve(wifi_data.access_point_data.size() * 19 +
+ gateway_data.router_data.size() * 19);
const string16 separator(ASCIIToUTF16("|"));
+ for (GatewayData::RouterDataSet::const_iterator iter =
+ gateway_data.router_data.begin();
+ iter != gateway_data.router_data.end();
+ iter++) {
+ *key += separator;
+ *key += iter->mac_address;
+ *key += separator;
+ }
for (WifiData::AccessPointDataSet::const_iterator iter =
wifi_data.access_point_data.begin();
iter != wifi_data.access_point_data.end();
@@ -114,8 +127,10 @@ NetworkLocationProvider::NetworkLocationProvider(
const GURL& url,
const string16& access_token)
: access_token_store_(access_token_store),
+ gateway_data_provider_(NULL),
radio_data_provider_(NULL),
wifi_data_provider_(NULL),
+ is_gateway_data_complete_(false),
is_radio_data_complete_(false),
is_wifi_data_complete_(false),
access_token_(access_token),
@@ -142,7 +157,8 @@ void NetworkLocationProvider::UpdatePosition() {
// poke each data provider to get them to expedite their next scan.
// Whilst in the delayed start, only send request if all data is ready.
if (delayed_start_task_.empty() ||
- (is_radio_data_complete_ && is_wifi_data_complete_)) {
+ (is_gateway_data_complete_ && is_radio_data_complete_ &&
+ is_wifi_data_complete_)) {
RequestPosition();
}
}
@@ -159,6 +175,13 @@ void NetworkLocationProvider::OnPermissionGranted(
// DeviceDataProviderInterface::ListenerInterface implementation.
void NetworkLocationProvider::DeviceDataUpdateAvailable(
+ GatewayDataProvider* provider) {
+ DCHECK(provider == gateway_data_provider_);
+ is_gateway_data_complete_ = gateway_data_provider_->GetData(&gateway_data_);
+ OnDeviceDataUpdated();
+}
+
+void NetworkLocationProvider::DeviceDataUpdateAvailable(
RadioDataProvider* provider) {
DCHECK(provider == radio_data_provider_);
is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
@@ -177,13 +200,15 @@ void NetworkLocationProvider::LocationResponseAvailable(
const Geoposition& position,
bool server_error,
const string16& access_token,
+ const GatewayData& gateway_data,
const RadioData& radio_data,
const WifiData& wifi_data) {
DCHECK(CalledOnValidThread());
// Record the position and update our cache.
position_ = position;
if (position.IsValidFix()) {
- position_cache_->CachePosition(radio_data, wifi_data, position);
+ position_cache_->CachePosition(gateway_data, radio_data,
+ wifi_data, position);
}
// Record access_token if it's set.
@@ -209,6 +234,7 @@ bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
// Get the device data providers. The first call to Register will create the
// provider and it will be deleted by ref counting.
+ gateway_data_provider_ = GatewayDataProvider::Register(this);
radio_data_provider_ = RadioDataProvider::Register(this);
wifi_data_provider_ = WifiDataProvider::Register(this);
@@ -218,9 +244,11 @@ bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
&NetworkLocationProvider::RequestPosition),
kDataCompleteWaitPeriod);
// Get the device data.
+ is_gateway_data_complete_ = gateway_data_provider_->GetData(&gateway_data_);
is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
- if (is_radio_data_complete_ || is_wifi_data_complete_)
+ if (is_gateway_data_complete_ || is_radio_data_complete_ ||
+ is_wifi_data_complete_)
OnDeviceDataUpdated();
return true;
}
@@ -228,9 +256,11 @@ bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
void NetworkLocationProvider::StopProvider() {
DCHECK(CalledOnValidThread());
if (IsStarted()) {
+ gateway_data_provider_->Unregister(this);
radio_data_provider_->Unregister(this);
wifi_data_provider_->Unregister(this);
}
+ gateway_data_provider_ = NULL;
radio_data_provider_ = NULL;
wifi_data_provider_ = NULL;
delayed_start_task_.RevokeAll();
@@ -243,7 +273,7 @@ void NetworkLocationProvider::RequestPosition() {
return;
const Geoposition* cached_position =
- position_cache_->FindPosition(radio_data_, wifi_data_);
+ position_cache_->FindPosition(gateway_data_, radio_data_, wifi_data_);
DCHECK(!device_data_updated_timestamp_.is_null()) <<
"Timestamp must be set before looking up position";
if (cached_position) {
@@ -277,7 +307,7 @@ void NetworkLocationProvider::RequestPosition() {
// approximation of usage. We do not need to guarantee that this network
// request was triggered by an API call from this specific host.
request_->MakeRequest(most_recent_authorized_host_, access_token_,
- radio_data_, wifi_data_,
+ gateway_data_, radio_data_, wifi_data_,
device_data_updated_timestamp_);
}
@@ -285,11 +315,13 @@ void NetworkLocationProvider::OnDeviceDataUpdated() {
DCHECK(CalledOnValidThread());
device_data_updated_timestamp_ = base::Time::Now();
- is_new_data_available_ = is_radio_data_complete_ || is_wifi_data_complete_;
+ is_new_data_available_ = is_gateway_data_complete_ ||
+ is_radio_data_complete_ || is_wifi_data_complete_;
UpdatePosition();
}
bool NetworkLocationProvider::IsStarted() const {
+ DCHECK_EQ(!!gateway_data_provider_, !!wifi_data_provider_);
DCHECK_EQ(!!radio_data_provider_, !!wifi_data_provider_);
return wifi_data_provider_ != NULL;
}
diff --git a/chrome/browser/geolocation/network_location_provider.h b/chrome/browser/geolocation/network_location_provider.h
index 27f504c..e86f93c 100644
--- a/chrome/browser/geolocation/network_location_provider.h
+++ b/chrome/browser/geolocation/network_location_provider.h
@@ -4,10 +4,13 @@
#ifndef CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H_
#define CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/thread.h"
#include "chrome/browser/geolocation/device_data_provider.h"
@@ -19,6 +22,7 @@ class URLFetcherProtectEntry;
class NetworkLocationProvider
: public LocationProviderBase,
+ public GatewayDataProvider::ListenerInterface,
public RadioDataProvider::ListenerInterface,
public WifiDataProvider::ListenerInterface,
public NetworkLocationRequest::ListenerInterface {
@@ -49,6 +53,7 @@ class NetworkLocationProvider
bool IsStarted() const;
// DeviceDataProvider::ListenerInterface implementation.
+ virtual void DeviceDataUpdateAvailable(GatewayDataProvider* provider);
virtual void DeviceDataUpdateAvailable(RadioDataProvider* provider);
virtual void DeviceDataUpdateAvailable(WifiDataProvider* provider);
@@ -56,18 +61,22 @@ class NetworkLocationProvider
virtual void LocationResponseAvailable(const Geoposition& position,
bool server_error,
const string16& access_token,
+ const GatewayData& gateway_data,
const RadioData& radio_data,
const WifiData& wifi_data);
scoped_refptr<AccessTokenStore> access_token_store_;
// The device data providers, acquired via global factories.
+ GatewayDataProvider* gateway_data_provider_;
RadioDataProvider* radio_data_provider_;
WifiDataProvider* wifi_data_provider_;
// The radio and wifi data, flags to indicate if each data set is complete.
+ GatewayData gateway_data_;
RadioData radio_data_;
WifiData wifi_data_;
+ bool is_gateway_data_complete_;
bool is_radio_data_complete_;
bool is_wifi_data_complete_;
diff --git a/chrome/browser/geolocation/network_location_provider_unittest.cc b/chrome/browser/geolocation/network_location_provider_unittest.cc
index 4e6fdbd..c0e2023 100644
--- a/chrome/browser/geolocation/network_location_provider_unittest.cc
+++ b/chrome/browser/geolocation/network_location_provider_unittest.cc
@@ -58,7 +58,10 @@ class MockDeviceDataProviderImpl
return instance_;
}
- MockDeviceDataProviderImpl() : got_data_(true) {
+ MockDeviceDataProviderImpl()
+ : start_calls_(0),
+ stop_calls_(0),
+ got_data_(true) {
}
virtual ~MockDeviceDataProviderImpl() {
@@ -68,9 +71,12 @@ class MockDeviceDataProviderImpl
// DeviceDataProviderImplBase implementation.
virtual bool StartDataProvider() {
+ ++start_calls_;
return true;
}
- virtual void StopDataProvider() {}
+ virtual void StopDataProvider() {
+ ++stop_calls_;
+ }
virtual bool GetData(DataType* data_out) {
CHECK(data_out);
*data_out = data_;
@@ -86,6 +92,8 @@ class MockDeviceDataProviderImpl
}
void set_got_data(bool got_data) { got_data_ = got_data; }
+ int start_calls_;
+ int stop_calls_;
private:
static MockDeviceDataProviderImpl<DataType>* instance_;
@@ -106,6 +114,8 @@ class GeolocationNetworkProviderTest : public testing::Test {
virtual void SetUp() {
URLFetcher::set_factory(&url_fetcher_factory_);
access_token_store_ = new FakeAccessTokenStore;
+ gateway_data_provider_ =
+ MockDeviceDataProviderImpl<GatewayData>::CreateInstance();
radio_data_provider_ =
MockDeviceDataProviderImpl<RadioData>::CreateInstance();
wifi_data_provider_ =
@@ -133,6 +143,8 @@ class GeolocationNetworkProviderTest : public testing::Test {
GeolocationNetworkProviderTest() : test_server_url_(kTestServerUrl) {
// TODO(joth): Really these should be in SetUp, not here, but they take no
// effect on Mac OS Release builds if done there. I kid not. Figure out why.
+ GatewayDataProvider::SetFactory(
+ MockDeviceDataProviderImpl<GatewayData>::GetInstance);
RadioDataProvider::SetFactory(
MockDeviceDataProviderImpl<RadioData>::GetInstance);
WifiDataProvider::SetFactory(
@@ -167,45 +179,86 @@ class GeolocationNetworkProviderTest : public testing::Test {
return data;
}
- static void ParseRequest(const std::string& request_data,
- WifiData* wifi_data_out,
- int* max_age_out,
- std::string* access_token_out) {
+ // Creates gateway data containing the specified number of routers, with
+ // some differentiating charactistics in each.
+ static GatewayData CreateReferenceRouterData(int router_count) {
+ GatewayData data;
+ for (int i = 0; i < router_count; ++i) {
+ RouterData router;
+ router.mac_address =
+ ASCIIToUTF16(StringPrintf("%02d-34-56-78-54-32", i));
+ data.router_data.insert(router);
+ }
+ return data;
+ }
+
+ static void ParseGatewayRequest(const std::string& request_data,
+ GatewayData* gateway_data_out) {
+ scoped_ptr<Value> value(base::JSONReader::Read(request_data, false));
+ EXPECT_TRUE(value != NULL);
+ EXPECT_EQ(Value::TYPE_DICTIONARY, value->GetType());
+ DictionaryValue* dictionary = static_cast<DictionaryValue*>(value.get());
+ std::string attr_value;
+ EXPECT_TRUE(dictionary->GetString("version", &attr_value));
+ EXPECT_EQ(attr_value, "1.1.0");
+ EXPECT_TRUE(dictionary->GetString("host", &attr_value));
+ EXPECT_EQ(attr_value, kTestHost);
+ // Everything else is optional.
+ ListValue* gateways;
+ if (dictionary->GetList("gateways", &gateways)) {
+ int i = 0;
+ for (ListValue::const_iterator it = gateways->begin();
+ it < gateways->end(); ++it, ++i) {
+ EXPECT_EQ(Value::TYPE_DICTIONARY, (*it)->GetType());
+ DictionaryValue* gateway = static_cast<DictionaryValue*>(*it);
+ RouterData data;
+ gateway->GetString("mac_address", &data.mac_address);
+ gateway_data_out->router_data.insert(data);
+ }
+ } else {
+ gateway_data_out->router_data.clear();
+ }
+ }
+
+ static void ParseWifiRequest(const std::string& request_data,
+ WifiData* wifi_data_out,
+ int* max_age_out,
+ std::string* access_token_out) {
CHECK(wifi_data_out && max_age_out && access_token_out);
scoped_ptr<Value> value(base::JSONReader::Read(request_data, false));
EXPECT_TRUE(value != NULL);
EXPECT_EQ(Value::TYPE_DICTIONARY, value->GetType());
DictionaryValue* dictionary = static_cast<DictionaryValue*>(value.get());
std::string attr_value;
- EXPECT_TRUE(dictionary->GetString(L"version", &attr_value));
+ EXPECT_TRUE(dictionary->GetString("version", &attr_value));
EXPECT_EQ(attr_value, "1.1.0");
- EXPECT_TRUE(dictionary->GetString(L"host", &attr_value));
+ EXPECT_TRUE(dictionary->GetString("host", &attr_value));
EXPECT_EQ(attr_value, kTestHost);
// Everything else is optional.
ListValue* wifi_aps;
*max_age_out = kint32min;
- if (dictionary->GetList(L"wifi_towers", &wifi_aps)) {
+ if (dictionary->GetList("wifi_towers", &wifi_aps)) {
int i = 0;
for (ListValue::const_iterator it = wifi_aps->begin();
it < wifi_aps->end(); ++it, ++i) {
EXPECT_EQ(Value::TYPE_DICTIONARY, (*it)->GetType());
DictionaryValue* ap = static_cast<DictionaryValue*>(*it);
AccessPointData data;
- ap->GetStringAsUTF16(L"mac_address", &data.mac_address);
- ap->GetInteger(L"signal_strength", &data.radio_signal_strength);
+ ap->GetString("mac_address", &data.mac_address);
+ ap->GetInteger("signal_strength", &data.radio_signal_strength);
int age = kint32min;
- ap->GetInteger(L"age", &age);
+ ap->GetInteger("age", &age);
if (age > *max_age_out)
*max_age_out = age;
- ap->GetInteger(L"channel", &data.channel);
- ap->GetInteger(L"signal_to_noise", &data.signal_to_noise);
- ap->GetStringAsUTF16(L"ssid", &data.ssid);
+ ap->GetInteger("channel", &data.channel);
+ ap->GetInteger("signal_to_noise", &data.signal_to_noise);
+ ap->GetString("ssid", &data.ssid);
wifi_data_out->access_point_data.insert(data);
}
} else {
wifi_data_out->access_point_data.clear();
}
- if (!dictionary->GetString(L"access_token", access_token_out))
+ if (!dictionary->GetString("access_token", access_token_out))
access_token_out->clear();
}
@@ -213,45 +266,67 @@ class GeolocationNetworkProviderTest : public testing::Test {
WifiData wifi_aps;
std::string access_token;
int max_age;
- ParseRequest(request_data, &wifi_aps, &max_age, &access_token);
+ ParseWifiRequest(request_data, &wifi_aps, &max_age, &access_token);
EXPECT_EQ(kint32min, max_age);
EXPECT_EQ(0, static_cast<int>(wifi_aps.access_point_data.size()));
EXPECT_TRUE(access_token.empty());
}
static void CheckRequestIsValid(const std::string& request_data,
+ int expected_routers,
int expected_wifi_aps,
const std::string& expected_access_token) {
WifiData wifi_aps;
std::string access_token;
int max_age;
- ParseRequest(request_data, &wifi_aps, &max_age, &access_token);
- EXPECT_GE(max_age, 0) << "Age must not be negative.";
- EXPECT_LT(max_age, 10 * 1000) << "This test really shouldn't take 10s.";
+ ParseWifiRequest(request_data, &wifi_aps, &max_age, &access_token);
EXPECT_EQ(expected_wifi_aps,
static_cast<int>(wifi_aps.access_point_data.size()));
- WifiData expected_data = CreateReferenceWifiScanData(expected_wifi_aps);
- WifiData::AccessPointDataSet::const_iterator expected =
- expected_data.access_point_data.begin();
- WifiData::AccessPointDataSet::const_iterator actual =
- wifi_aps.access_point_data.begin();
- for (int i = 0; i < expected_wifi_aps; ++i) {
+ if (expected_wifi_aps > 0) {
+ EXPECT_GE(max_age, 0) << "Age must not be negative.";
+ EXPECT_LT(max_age, 10 * 1000) << "This test really shouldn't take 10s.";
+ WifiData expected_data = CreateReferenceWifiScanData(expected_wifi_aps);
+ WifiData::AccessPointDataSet::const_iterator expected =
+ expected_data.access_point_data.begin();
+ WifiData::AccessPointDataSet::const_iterator actual =
+ wifi_aps.access_point_data.begin();
+ for (int i = 0; i < expected_wifi_aps; ++i) {
+ EXPECT_EQ(expected->mac_address, actual->mac_address) << i;
+ EXPECT_EQ(expected->radio_signal_strength,
+ actual->radio_signal_strength) << i;
+ EXPECT_EQ(expected->channel, actual->channel) << i;
+ EXPECT_EQ(expected->signal_to_noise, actual->signal_to_noise) << i;
+ EXPECT_EQ(expected->ssid, actual->ssid) << i;
+ ++expected;
+ ++actual;
+ }
+ } else {
+ EXPECT_EQ(max_age, kint32min);
+ }
+ EXPECT_EQ(expected_access_token, access_token);
+
+ GatewayData gateway_data;
+ ParseGatewayRequest(request_data, &gateway_data);
+ EXPECT_EQ(expected_routers,
+ static_cast<int>(gateway_data.router_data.size()));
+ GatewayData expected_data = CreateReferenceRouterData(expected_routers);
+ GatewayData::RouterDataSet::const_iterator expected =
+ expected_data.router_data.begin();
+ GatewayData::RouterDataSet::const_iterator actual =
+ gateway_data.router_data.begin();
+ for (int i = 0; i < expected_routers; ++i) {
EXPECT_EQ(expected->mac_address, actual->mac_address) << i;
- EXPECT_EQ(expected->radio_signal_strength, actual->radio_signal_strength)
- << i;
- EXPECT_EQ(expected->channel, actual->channel) << i;
- EXPECT_EQ(expected->signal_to_noise, actual->signal_to_noise) << i;
- EXPECT_EQ(expected->ssid, actual->ssid) << i;
++expected;
++actual;
}
- EXPECT_EQ(expected_access_token, access_token);
}
const GURL test_server_url_;
MessageLoop main_message_loop_;
scoped_refptr<FakeAccessTokenStore> access_token_store_;
TestURLFetcherFactory url_fetcher_factory_;
+ scoped_refptr<MockDeviceDataProviderImpl<GatewayData> >
+ gateway_data_provider_;
scoped_refptr<MockDeviceDataProviderImpl<RadioData> > radio_data_provider_;
scoped_refptr<MockDeviceDataProviderImpl<WifiData> > wifi_data_provider_;
};
@@ -278,6 +353,42 @@ TEST_F(GeolocationNetworkProviderTest, StartProvider) {
CheckEmptyRequestIsValid(fetcher->upload_data());
}
+TEST_F(GeolocationNetworkProviderTest, MultipleStartProvider) {
+ scoped_ptr<LocationProviderBase> provider_1(CreateProvider(true));
+ scoped_ptr<LocationProviderBase> provider_2(CreateProvider(true));
+ ASSERT_TRUE(gateway_data_provider_);
+ ASSERT_TRUE(radio_data_provider_);
+ ASSERT_TRUE(wifi_data_provider_);
+ EXPECT_EQ(0, gateway_data_provider_->start_calls_);
+ EXPECT_EQ(0, radio_data_provider_->start_calls_);
+ EXPECT_EQ(0, wifi_data_provider_->start_calls_);
+ EXPECT_EQ(0, gateway_data_provider_->stop_calls_);
+ EXPECT_EQ(0, radio_data_provider_->stop_calls_);
+ EXPECT_EQ(0, wifi_data_provider_->stop_calls_);
+
+ // Start first provider.
+ EXPECT_TRUE(provider_1->StartProvider(false));
+ EXPECT_EQ(1, gateway_data_provider_->start_calls_);
+ EXPECT_EQ(1, radio_data_provider_->start_calls_);
+ EXPECT_EQ(1, wifi_data_provider_->start_calls_);
+ // Start second provider.
+ EXPECT_TRUE(provider_2->StartProvider(false));
+ EXPECT_EQ(1, gateway_data_provider_->start_calls_);
+ EXPECT_EQ(1, radio_data_provider_->start_calls_);
+ EXPECT_EQ(1, wifi_data_provider_->start_calls_);
+
+ // Stop first provider.
+ provider_1->StopProvider();
+ EXPECT_EQ(0, gateway_data_provider_->stop_calls_);
+ EXPECT_EQ(0, radio_data_provider_->stop_calls_);
+ EXPECT_EQ(0, wifi_data_provider_->stop_calls_);
+ // Stop second provider.
+ provider_2->StopProvider();
+ EXPECT_EQ(1, gateway_data_provider_->stop_calls_);
+ EXPECT_EQ(1, radio_data_provider_->stop_calls_);
+ EXPECT_EQ(1, wifi_data_provider_->stop_calls_);
+}
+
TEST_F(GeolocationNetworkProviderTest, MultiRegistrations) {
// TODO(joth): Strictly belongs in a base-class unit test file.
MessageLoopQuitListener listener;
@@ -328,7 +439,7 @@ TEST_F(GeolocationNetworkProviderTest, MultipleWifiScansComplete) {
fetcher = get_url_fetcher_and_advance_id();
ASSERT_TRUE(fetcher != NULL);
// The request should have access token (set previously) and the wifi data.
- CheckRequestIsValid(fetcher->upload_data(),
+ CheckRequestIsValid(fetcher->upload_data(), 0,
kFirstScanAps,
REFERENCE_ACCESS_TOKEN);
@@ -402,6 +513,157 @@ TEST_F(GeolocationNetworkProviderTest, MultipleWifiScansComplete) {
EXPECT_TRUE(position.IsValidFix());
}
+TEST_F(GeolocationNetworkProviderTest, GatewayAndWifiScans) {
+ scoped_ptr<LocationProviderBase> provider(CreateProvider(true));
+ EXPECT_TRUE(provider->StartProvider(false));
+
+ TestURLFetcher* fetcher = get_url_fetcher_and_advance_id();
+ ASSERT_TRUE(fetcher != NULL);
+ CheckEmptyRequestIsValid(fetcher->upload_data());
+ // Complete the network request with bad position fix (using #define so we
+ // can paste this into various other strings below)
+ #define REFERENCE_ACCESS_TOKEN "2:k7j3G6LaL6u_lafw:4iXOeOpTh1glSXe"
+ const char* kNoFixNetworkResponse =
+ "{"
+ " \"location\": null,"
+ " \"access_token\": \"" REFERENCE_ACCESS_TOKEN "\""
+ "}";
+ fetcher->delegate()->OnURLFetchComplete(
+ fetcher, test_server_url_, URLRequestStatus(), 200, // OK
+ ResponseCookies(), kNoFixNetworkResponse);
+
+ // This should have set the access token anyhow
+ EXPECT_EQ(UTF8ToUTF16(REFERENCE_ACCESS_TOKEN),
+ access_token_store_->access_token_set_[test_server_url_]);
+
+ Geoposition position;
+ provider->GetPosition(&position);
+ EXPECT_FALSE(position.IsValidFix());
+
+ // Now gateway data arrives -- SetData will notify listeners.
+ const int kFirstScanRouters = 1;
+ gateway_data_provider_->SetData(
+ CreateReferenceRouterData(kFirstScanRouters));
+ main_message_loop_.RunAllPending();
+ fetcher = get_url_fetcher_and_advance_id();
+ ASSERT_TRUE(fetcher != NULL);
+ // The request should have access token (set previously) and the
+ // gateway data.
+ CheckRequestIsValid(fetcher->upload_data(), kFirstScanRouters,
+ 0, REFERENCE_ACCESS_TOKEN);
+
+ // Send a reply with good position fix.
+ const char* kReferenceNetworkResponse_1 =
+ "{"
+ " \"location\": {"
+ " \"latitude\": 51.0,"
+ " \"longitude\": -0.1,"
+ " \"altitude\": 30.1,"
+ " \"accuracy\": 1200.4,"
+ " \"altitude_accuracy\": 10.6"
+ " }"
+ "}";
+ fetcher->delegate()->OnURLFetchComplete(
+ fetcher, test_server_url_, URLRequestStatus(), 200, // OK
+ ResponseCookies(), kReferenceNetworkResponse_1);
+
+ provider->GetPosition(&position);
+ EXPECT_EQ(51.0, position.latitude);
+ EXPECT_EQ(-0.1, position.longitude);
+ EXPECT_EQ(30.1, position.altitude);
+ EXPECT_EQ(1200.4, position.accuracy);
+ EXPECT_EQ(10.6, position.altitude_accuracy);
+ EXPECT_TRUE(position.is_valid_timestamp());
+ EXPECT_TRUE(position.IsValidFix());
+
+ // Token should still be in the store.
+ EXPECT_EQ(UTF8ToUTF16(REFERENCE_ACCESS_TOKEN),
+ access_token_store_->access_token_set_[test_server_url_]);
+
+ // Gateway updated again, with one more router. This is a significant change
+ // so a new request is made.
+ const int kSecondScanRouters = kFirstScanRouters + 1;
+ gateway_data_provider_->SetData(
+ CreateReferenceRouterData(kSecondScanRouters));
+ main_message_loop_.RunAllPending();
+ fetcher = get_url_fetcher_and_advance_id();
+ EXPECT_TRUE(fetcher);
+
+ CheckRequestIsValid(fetcher->upload_data(), kSecondScanRouters,
+ 0, REFERENCE_ACCESS_TOKEN);
+
+ // Send a reply with good position fix.
+ const char* kReferenceNetworkResponse_2 =
+ "{"
+ " \"location\": {"
+ " \"latitude\": 51.1,"
+ " \"longitude\": -0.1,"
+ " \"altitude\": 30.2,"
+ " \"accuracy\": 1100.4,"
+ " \"altitude_accuracy\": 10.6"
+ " }"
+ "}";
+ fetcher->delegate()->OnURLFetchComplete(
+ fetcher, test_server_url_, URLRequestStatus(), 200, // OK
+ ResponseCookies(), kReferenceNetworkResponse_2);
+
+ provider->GetPosition(&position);
+ EXPECT_EQ(51.1, position.latitude);
+ EXPECT_EQ(-0.1, position.longitude);
+ EXPECT_EQ(30.2, position.altitude);
+ EXPECT_EQ(1100.4, position.accuracy);
+ EXPECT_EQ(10.6, position.altitude_accuracy);
+ EXPECT_TRUE(position.is_valid_timestamp());
+ EXPECT_TRUE(position.IsValidFix());
+
+ // Now add new wifi scan data.
+ const int kScanAps = 4;
+ wifi_data_provider_->SetData(CreateReferenceWifiScanData(kScanAps));
+ main_message_loop_.RunAllPending();
+ fetcher = get_url_fetcher_and_advance_id();
+ EXPECT_TRUE(fetcher);
+ CheckRequestIsValid(fetcher->upload_data(), kSecondScanRouters,
+ kScanAps, REFERENCE_ACCESS_TOKEN);
+
+ // Send a reply with good position fix.
+ const char* kReferenceNetworkResponse_3 =
+ "{"
+ " \"location\": {"
+ " \"latitude\": 51.3,"
+ " \"longitude\": -0.1,"
+ " \"altitude\": 30.2,"
+ " \"accuracy\": 50.4,"
+ " \"altitude_accuracy\": 10.6"
+ " }"
+ "}";
+ fetcher->delegate()->OnURLFetchComplete(
+ fetcher, test_server_url_, URLRequestStatus(), 200, // OK
+ ResponseCookies(), kReferenceNetworkResponse_3);
+
+ provider->GetPosition(&position);
+ EXPECT_EQ(51.3, position.latitude);
+ EXPECT_EQ(-0.1, position.longitude);
+ EXPECT_EQ(30.2, position.altitude);
+ EXPECT_EQ(50.4, position.accuracy);
+ EXPECT_EQ(10.6, position.altitude_accuracy);
+ EXPECT_TRUE(position.is_valid_timestamp());
+ EXPECT_TRUE(position.IsValidFix());
+
+ // Wifi scan returns no access points found: should be serviced from cache.
+ wifi_data_provider_->SetData(CreateReferenceWifiScanData(0));
+ main_message_loop_.RunAllPending();
+ EXPECT_FALSE(get_url_fetcher_and_advance_id()); // No new request created.
+
+ provider->GetPosition(&position);
+ EXPECT_EQ(51.1, position.latitude);
+ EXPECT_EQ(-0.1, position.longitude);
+ EXPECT_EQ(30.2, position.altitude);
+ EXPECT_EQ(1100.4, position.accuracy);
+ EXPECT_EQ(10.6, position.altitude_accuracy);
+ EXPECT_TRUE(position.is_valid_timestamp());
+ EXPECT_TRUE(position.IsValidFix());
+}
+
TEST_F(GeolocationNetworkProviderTest, NoRequestOnStartupUntilWifiData) {
MessageLoopQuitListener listener;
wifi_data_provider_->set_got_data(false);
@@ -472,6 +734,6 @@ TEST_F(GeolocationNetworkProviderTest,
EXPECT_EQ(test_server_url_, fetcher->original_url());
- CheckRequestIsValid(fetcher->upload_data(), kScanCount,
- REFERENCE_ACCESS_TOKEN);
+ CheckRequestIsValid(fetcher->upload_data(), 0,
+ kScanCount, REFERENCE_ACCESS_TOKEN);
}
diff --git a/chrome/browser/geolocation/network_location_request.cc b/chrome/browser/geolocation/network_location_request.cc
index 7eae212..9700547 100644
--- a/chrome/browser/geolocation/network_location_request.cc
+++ b/chrome/browser/geolocation/network_location_request.cc
@@ -6,7 +6,8 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/geoposition.h"
#include "chrome/common/net/url_request_context_getter.h"
@@ -19,18 +20,19 @@ const char kMimeApplicationJson[] = "application/json";
// See http://code.google.com/apis/gears/geolocation_network_protocol.html
const char kGeoLocationNetworkProtocolVersion[] = "1.1.0";
-const wchar_t kAccessTokenString[] = L"access_token";
-const wchar_t kLocationString[] = L"location";
-const wchar_t kLatitudeString[] = L"latitude";
-const wchar_t kLongitudeString[] = L"longitude";
-const wchar_t kAltitudeString[] = L"altitude";
-const wchar_t kAccuracyString[] = L"accuracy";
-const wchar_t kAltitudeAccuracyString[] = L"altitude_accuracy";
+const char kAccessTokenString[] = "access_token";
+const char kLocationString[] = "location";
+const char kLatitudeString[] = "latitude";
+const char kLongitudeString[] = "longitude";
+const char kAltitudeString[] = "altitude";
+const char kAccuracyString[] = "accuracy";
+const char kAltitudeAccuracyString[] = "altitude_accuracy";
// Local functions
// Creates the request payload to send to the server.
void FormRequestBody(const std::string& host_name,
const string16& access_token,
+ const GatewayData& gateway_data,
const RadioData& radio_data,
const WifiData& wifi_data,
const base::Time& timestamp,
@@ -46,11 +48,11 @@ void GetLocationFromResponse(bool http_post_result,
const char* RadioTypeToString(RadioType type);
// Adds a string if it's valid to the JSON object.
-void AddString(const std::wstring& property_name,
+void AddString(const std::string& property_name,
const string16& value,
DictionaryValue* object);
// Adds an integer if it's valid to the JSON object.
-void AddInteger(const std::wstring& property_name,
+void AddInteger(const std::string& property_name,
int value,
DictionaryValue* object);
// Parses the server response body. Returns true if parsing was successful.
@@ -60,6 +62,9 @@ bool ParseServerResponse(const std::string& response_body,
const base::Time& timestamp,
Geoposition* position,
string16* access_token);
+void AddGatewayData(const GatewayData& gateway_data,
+ int age_milliseconds,
+ DictionaryValue* body_object);
void AddRadioData(const RadioData& radio_data,
int age_milliseconds,
DictionaryValue* body_object);
@@ -83,6 +88,7 @@ NetworkLocationRequest::~NetworkLocationRequest() {
bool NetworkLocationRequest::MakeRequest(const std::string& host_name,
const string16& access_token,
+ const GatewayData& gateway_data,
const RadioData& radio_data,
const WifiData& wifi_data,
const base::Time& timestamp) {
@@ -90,12 +96,13 @@ bool NetworkLocationRequest::MakeRequest(const std::string& host_name,
DLOG(INFO) << "NetworkLocationRequest : Cancelling pending request";
url_fetcher_.reset();
}
+ gateway_data_ = gateway_data;
radio_data_ = radio_data;
wifi_data_ = wifi_data;
timestamp_ = timestamp;
std::string post_body;
- FormRequestBody(host_name, access_token, radio_data_, wifi_data_,
- timestamp_, &post_body);
+ FormRequestBody(host_name, access_token, gateway_data, radio_data_,
+ wifi_data_, timestamp_, &post_body);
url_fetcher_.reset(URLFetcher::Create(
url_fetcher_id_for_tests, url_, URLFetcher::POST, this));
@@ -130,7 +137,7 @@ void NetworkLocationRequest::OnURLFetchComplete(const URLFetcher* source,
DLOG(INFO) << "NetworkLocationRequest::Run() : "
"Calling listener with position.\n";
listener_->LocationResponseAvailable(position, server_error, access_token,
- radio_data_, wifi_data_);
+ gateway_data_, radio_data_, wifi_data_);
}
// Local functions.
@@ -138,6 +145,7 @@ namespace {
void FormRequestBody(const std::string& host_name,
const string16& access_token,
+ const GatewayData& gateway_data,
const RadioData& radio_data,
const WifiData& wifi_data,
const base::Time& timestamp,
@@ -149,12 +157,12 @@ void FormRequestBody(const std::string& host_name,
COMPILE_ASSERT(sizeof(kGeoLocationNetworkProtocolVersion) > 1,
must_include_valid_version);
DCHECK(!host_name.empty());
- body_object.SetString(L"version", kGeoLocationNetworkProtocolVersion);
- body_object.SetString(L"host", host_name);
+ body_object.SetString("version", kGeoLocationNetworkProtocolVersion);
+ body_object.SetString("host", host_name);
- AddString(L"access_token", access_token, &body_object);
+ AddString("access_token", access_token, &body_object);
- body_object.SetBoolean(L"request_address", false);
+ body_object.SetBoolean("request_address", false);
int age = kint32min; // Invalid so AddInteger() will ignore.
if (!timestamp.is_null()) {
@@ -165,6 +173,7 @@ void FormRequestBody(const std::string& host_name,
}
AddRadioData(radio_data, age, &body_object);
AddWifiData(wifi_data, age, &body_object);
+ AddGatewayData(gateway_data, age, &body_object);
base::JSONWriter::Write(&body_object, false, data);
DLOG(INFO) << "NetworkLocationRequest::FormRequestBody(): Formed body "
@@ -202,7 +211,7 @@ void GetLocationFromResponse(bool http_post_result,
}
if (status_code != 200) { // HTTP OK.
std::string message = "Returned error code ";
- message += IntToString(status_code);
+ message += base::IntToString(status_code);
FormatPositionError(server_url, message, position);
return;
}
@@ -238,16 +247,16 @@ const char* RadioTypeToString(RadioType type) {
return "unknown";
}
-void AddString(const std::wstring& property_name,
+void AddString(const std::string& property_name,
const string16& value,
DictionaryValue* object) {
DCHECK(object);
if (!value.empty()) {
- object->SetStringFromUTF16(property_name, value);
+ object->SetString(property_name, value);
}
}
-void AddInteger(const std::wstring& property_name,
+void AddInteger(const std::string& property_name,
int value,
DictionaryValue* object) {
DCHECK(object);
@@ -261,7 +270,7 @@ void AddInteger(const std::wstring& property_name,
// point numeric values. Note that isIntegral() includes boolean values, which
// is not what we want.
bool GetAsDouble(const DictionaryValue& object,
- const std::wstring& property_name,
+ const std::string& property_name,
double* out) {
DCHECK(out);
Value* value = NULL;
@@ -311,7 +320,7 @@ bool ParseServerResponse(const std::string& response_body,
static_cast<DictionaryValue*>(response_value.get());
// Get the access token, if any.
- response_object->GetStringAsUTF16(kAccessTokenString, access_token);
+ response_object->GetString(kAccessTokenString, access_token);
// Get the location
Value* location_value = NULL;
@@ -362,14 +371,14 @@ void AddRadioData(const RadioData& radio_data,
DictionaryValue* body_object) {
DCHECK(body_object);
- AddInteger(L"home_mobile_country_code", radio_data.home_mobile_country_code,
+ AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code,
body_object);
- AddInteger(L"home_mobile_network_code", radio_data.home_mobile_network_code,
+ AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code,
body_object);
- AddString(L"radio_type",
+ AddString("radio_type",
ASCIIToUTF16(RadioTypeToString(radio_data.radio_type)),
body_object);
- AddString(L"carrier", radio_data.carrier, body_object);
+ AddString("carrier", radio_data.carrier, body_object);
const int num_cell_towers = static_cast<int>(radio_data.cell_data.size());
if (num_cell_towers == 0) {
@@ -378,21 +387,21 @@ void AddRadioData(const RadioData& radio_data,
ListValue* cell_towers = new ListValue;
for (int i = 0; i < num_cell_towers; ++i) {
DictionaryValue* cell_tower = new DictionaryValue;
- AddInteger(L"cell_id", radio_data.cell_data[i].cell_id, cell_tower);
- AddInteger(L"location_area_code",
+ AddInteger("cell_id", radio_data.cell_data[i].cell_id, cell_tower);
+ AddInteger("location_area_code",
radio_data.cell_data[i].location_area_code, cell_tower);
- AddInteger(L"mobile_country_code",
+ AddInteger("mobile_country_code",
radio_data.cell_data[i].mobile_country_code, cell_tower);
- AddInteger(L"mobile_network_code",
+ AddInteger("mobile_network_code",
radio_data.cell_data[i].mobile_network_code, cell_tower);
- AddInteger(L"age", age_milliseconds, cell_tower);
- AddInteger(L"signal_strength",
+ AddInteger("age", age_milliseconds, cell_tower);
+ AddInteger("signal_strength",
radio_data.cell_data[i].radio_signal_strength, cell_tower);
- AddInteger(L"timing_advance", radio_data.cell_data[i].timing_advance,
+ AddInteger("timing_advance", radio_data.cell_data[i].timing_advance,
cell_tower);
cell_towers->Append(cell_tower);
}
- body_object->Set(L"cell_towers", cell_towers);
+ body_object->Set("cell_towers", cell_towers);
}
void AddWifiData(const WifiData& wifi_data,
@@ -410,14 +419,35 @@ void AddWifiData(const WifiData& wifi_data,
iter != wifi_data.access_point_data.end();
iter++) {
DictionaryValue* wifi_tower = new DictionaryValue;
- AddString(L"mac_address", iter->mac_address, wifi_tower);
- AddInteger(L"signal_strength", iter->radio_signal_strength, wifi_tower);
- AddInteger(L"age", age_milliseconds, wifi_tower);
- AddInteger(L"channel", iter->channel, wifi_tower);
- AddInteger(L"signal_to_noise", iter->signal_to_noise, wifi_tower);
- AddString(L"ssid", iter->ssid, wifi_tower);
+ AddString("mac_address", iter->mac_address, wifi_tower);
+ AddInteger("signal_strength", iter->radio_signal_strength, wifi_tower);
+ AddInteger("age", age_milliseconds, wifi_tower);
+ AddInteger("channel", iter->channel, wifi_tower);
+ AddInteger("signal_to_noise", iter->signal_to_noise, wifi_tower);
+ AddString("ssid", iter->ssid, wifi_tower);
wifi_towers->Append(wifi_tower);
}
- body_object->Set(L"wifi_towers", wifi_towers);
+ body_object->Set("wifi_towers", wifi_towers);
+}
+
+void AddGatewayData(const GatewayData& gateway_data,
+ int age_milliseconds,
+ DictionaryValue* body_object) {
+ DCHECK(body_object);
+
+ if (gateway_data.router_data.empty()) {
+ return;
+ }
+
+ ListValue* gateways = new ListValue;
+ for (GatewayData::RouterDataSet::const_iterator iter =
+ gateway_data.router_data.begin();
+ iter != gateway_data.router_data.end();
+ iter++) {
+ DictionaryValue* gateway = new DictionaryValue;
+ AddString("mac_address", iter->mac_address, gateway);
+ gateways->Append(gateway);
+ }
+ body_object->Set("gateways", gateways);
}
} // namespace
diff --git a/chrome/browser/geolocation/network_location_request.h b/chrome/browser/geolocation/network_location_request.h
index 071313c..f7c8a0c 100644
--- a/chrome/browser/geolocation/network_location_request.h
+++ b/chrome/browser/geolocation/network_location_request.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_
#define CHROME_BROWSER_GEOLOCATION_NETWORK_LOCATION_REQUEST_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/geolocation/device_data_provider.h"
#include "chrome/common/net/url_fetcher.h"
#include "googleurl/src/gurl.h"
@@ -32,6 +34,7 @@ class NetworkLocationRequest : private URLFetcher::Delegate {
const Geoposition& position,
bool server_error,
const string16& access_token,
+ const GatewayData& gateway_data,
const RadioData& radio_data,
const WifiData& wifi_data) = 0;
@@ -49,6 +52,7 @@ class NetworkLocationRequest : private URLFetcher::Delegate {
// started. In all cases, any currently pending request will be canceled.
bool MakeRequest(const std::string& host,
const string16& access_token,
+ const GatewayData& gateway_data,
const RadioData& radio_data,
const WifiData& wifi_data,
const base::Time& timestamp);
@@ -72,6 +76,7 @@ class NetworkLocationRequest : private URLFetcher::Delegate {
// Keep a copy of the data sent in the request, so we can refer back to it
// when the response arrives.
+ GatewayData gateway_data_;
RadioData radio_data_;
WifiData wifi_data_;
base::Time timestamp_; // Timestamp of the above data, not of the request.
diff --git a/chrome/browser/geolocation/osx_wifi.h b/chrome/browser/geolocation/osx_wifi.h
index d912034..682041a 100644
--- a/chrome/browser/geolocation/osx_wifi.h
+++ b/chrome/browser/geolocation/osx_wifi.h
@@ -44,6 +44,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_OSX_WIFI_H_
#define CHROME_BROWSER_GEOLOCATION_OSX_WIFI_H_
+#pragma once
#include <CoreFoundation/CoreFoundation.h>
diff --git a/chrome/browser/geolocation/wifi_data_provider_chromeos.cc b/chrome/browser/geolocation/wifi_data_provider_chromeos.cc
index bb1d936..c87386d 100644
--- a/chrome/browser/geolocation/wifi_data_provider_chromeos.cc
+++ b/chrome/browser/geolocation/wifi_data_provider_chromeos.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/geolocation/wifi_data_provider_chromeos.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
namespace {
@@ -84,11 +85,11 @@ WifiDataProviderCommon::WlanApiInterface*
WifiDataProviderCommon::WlanApiInterface*
WifiDataProviderChromeOs::NewWlanApi() {
- if (network_library_ == NULL) {
- network_library_.reset(new chromeos::NetworkLibraryImpl());
- // TODO(joth): Check net_lib loaded ok, if not return NULL.
- }
- return NewWlanApi(network_library_.get());
+ chromeos::CrosLibrary* cros_lib = chromeos::CrosLibrary::Get();
+ DCHECK(cros_lib);
+ if (!cros_lib->EnsureLoaded())
+ return NULL;
+ return NewWlanApi(cros_lib->GetNetworkLibrary());
}
PollingPolicyInterface* WifiDataProviderChromeOs::NewPollingPolicy() {
diff --git a/chrome/browser/geolocation/wifi_data_provider_chromeos.h b/chrome/browser/geolocation/wifi_data_provider_chromeos.h
index 0e041e9..6acef54 100644
--- a/chrome/browser/geolocation/wifi_data_provider_chromeos.h
+++ b/chrome/browser/geolocation/wifi_data_provider_chromeos.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_CHROMEOS_H_
#define CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_CHROMEOS_H_
+#pragma once
#include "chrome/browser/geolocation/wifi_data_provider_common.h"
-#include "base/scoped_ptr.h"
-
-namespace chromeos { class NetworkLibrary; }
+namespace chromeos {
+class NetworkLibrary;
+}
class WifiDataProviderChromeOs : public WifiDataProviderCommon {
public:
@@ -25,8 +26,6 @@ class WifiDataProviderChromeOs : public WifiDataProviderCommon {
virtual WlanApiInterface* NewWlanApi();
virtual PollingPolicyInterface* NewPollingPolicy();
- scoped_ptr<chromeos::NetworkLibrary> network_library_;
-
DISALLOW_COPY_AND_ASSIGN(WifiDataProviderChromeOs);
};
diff --git a/chrome/browser/geolocation/wifi_data_provider_common.cc b/chrome/browser/geolocation/wifi_data_provider_common.cc
index 39df876..bfa1c5e 100644
--- a/chrome/browser/geolocation/wifi_data_provider_common.cc
+++ b/chrome/browser/geolocation/wifi_data_provider_common.cc
@@ -25,11 +25,12 @@ WifiDataProviderCommon::WifiDataProviderCommon()
WifiDataProviderCommon::~WifiDataProviderCommon() {
// Thread must be stopped before entering destructor chain to avoid race
// conditions; see comment in DeviceDataProvider::Unregister.
- DCHECK(!IsRunning()) << "Must call StopDataProvider before destroying me";
+ DCHECK(!IsRunning()); // Must call StopDataProvider before destroying me.
}
bool WifiDataProviderCommon::StartDataProvider() {
DCHECK(CalledOnClientThread());
+ DCHECK(!IsRunning()); // StartDataProvider must only be called once.
return Start();
}
diff --git a/chrome/browser/geolocation/wifi_data_provider_common.h b/chrome/browser/geolocation/wifi_data_provider_common.h
index 77289f0..5f0ee0a 100644
--- a/chrome/browser/geolocation/wifi_data_provider_common.h
+++ b/chrome/browser/geolocation/wifi_data_provider_common.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H_
#define CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H_
+#pragma once
#include <assert.h>
#include "base/logging.h"
+#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/task.h"
#include "base/thread.h"
diff --git a/chrome/browser/geolocation/wifi_data_provider_common_unittest.cc b/chrome/browser/geolocation/wifi_data_provider_common_unittest.cc
index 6947d41..b830040 100644
--- a/chrome/browser/geolocation/wifi_data_provider_common_unittest.cc
+++ b/chrome/browser/geolocation/wifi_data_provider_common_unittest.cc
@@ -9,6 +9,7 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/utf_string_conversions.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -69,7 +70,7 @@ class MessageLoopQuitListener
// Provider should call back on client's thread.
EXPECT_EQ(MessageLoop::current(), message_loop_to_quit_);
provider_ = provider;
- message_loop_to_quit_->Quit();
+ message_loop_to_quit_->QuitNow();
}
MessageLoop* message_loop_to_quit_;
DeviceDataProvider<WifiData>* provider_;
@@ -142,7 +143,7 @@ TEST_F(GeolocationWifiDataProviderCommonTest, StartThread) {
EXPECT_CALL(*polling_policy_, PollingInterval())
.Times(AtLeast(1));
EXPECT_TRUE(provider_->StartDataProvider());
- provider_->StopDataProvider();
+ main_message_loop_.Run();
SUCCEED();
}
diff --git a/chrome/browser/geolocation/wifi_data_provider_common_win.h b/chrome/browser/geolocation/wifi_data_provider_common_win.h
index 15a0740..cb62ed3 100644
--- a/chrome/browser/geolocation/wifi_data_provider_common_win.h
+++ b/chrome/browser/geolocation/wifi_data_provider_common_win.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_WIN_H_
#define CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_WIN_H_
+#pragma once
#include <windows.h>
#include <ntddndis.h>
-#include <vector>
+
#include "chrome/browser/geolocation/device_data_provider.h"
// Extracts access point data from the NDIS_802_11_BSSID_LIST structure and
diff --git a/chrome/browser/geolocation/wifi_data_provider_linux.cc b/chrome/browser/geolocation/wifi_data_provider_linux.cc
index 4bc3441..621e235 100644
--- a/chrome/browser/geolocation/wifi_data_provider_linux.cc
+++ b/chrome/browser/geolocation/wifi_data_provider_linux.cc
@@ -14,6 +14,7 @@
#include <glib.h>
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
namespace {
@@ -294,7 +295,7 @@ bool NetworkManagerWlanApi::GetAccessPointsForAdapter(
std::string mac = g_value_get_string(&mac_g_value.v);
ReplaceSubstringsAfterOffset(&mac, 0U, ":", "");
std::vector<uint8> mac_bytes;
- if (!HexStringToBytes(mac, &mac_bytes) || mac_bytes.size() != 6) {
+ if (!base::HexStringToBytes(mac, &mac_bytes) || mac_bytes.size() != 6) {
DLOG(WARNING) << "Can't parse mac address (found " << mac_bytes.size()
<< " bytes) so using raw string: " << mac;
access_point_data.mac_address = UTF8ToUTF16(mac);
diff --git a/chrome/browser/geolocation/wifi_data_provider_linux.h b/chrome/browser/geolocation/wifi_data_provider_linux.h
index b3a2771..66bb524 100644
--- a/chrome/browser/geolocation/wifi_data_provider_linux.h
+++ b/chrome/browser/geolocation/wifi_data_provider_linux.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H_
#define CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H_
+#pragma once
#include "chrome/browser/geolocation/wifi_data_provider_common.h"
diff --git a/chrome/browser/geolocation/wifi_data_provider_mac.h b/chrome/browser/geolocation/wifi_data_provider_mac.h
index 841176e..d920770 100644
--- a/chrome/browser/geolocation/wifi_data_provider_mac.h
+++ b/chrome/browser/geolocation/wifi_data_provider_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MAC_H_
#define CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MAC_H_
+#pragma once
#include "chrome/browser/geolocation/wifi_data_provider_common.h"
diff --git a/chrome/browser/geolocation/wifi_data_provider_win.h b/chrome/browser/geolocation/wifi_data_provider_win.h
index d0aa040..126f881 100644
--- a/chrome/browser/geolocation/wifi_data_provider_win.h
+++ b/chrome/browser/geolocation/wifi_data_provider_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_WIN_H_
#define CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_WIN_H_
+#pragma once
#include "chrome/browser/geolocation/wifi_data_provider_common.h"
diff --git a/chrome/browser/global_keyboard_shortcuts_mac.h b/chrome/browser/global_keyboard_shortcuts_mac.h
index 873d925..2741ef7 100644
--- a/chrome/browser/global_keyboard_shortcuts_mac.h
+++ b/chrome/browser/global_keyboard_shortcuts_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GLOBAL_KEYBOARD_SHORTCUTS_MAC_H_
#define CHROME_BROWSER_GLOBAL_KEYBOARD_SHORTCUTS_MAC_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/google_service_auth_error.h b/chrome/browser/google_service_auth_error.h
deleted file mode 100644
index f05fd1a..0000000
--- a/chrome/browser/google_service_auth_error.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.
-
-// A GoogleServiceAuthError is immutable, plain old data representing an
-// error from an attempt to authenticate with a Google service.
-// It could be from Google Accounts itself, or any service using Google
-// Accounts (e.g expired credentials). It may contain additional data such as
-// captcha challenges.
-
-// A GoogleServiceAuthError without additional data is just a State, defined
-// below. A case could be made to have this relation implicit, to allow raising
-// error events concisely by doing OnAuthError(GoogleServiceAuthError::NONE),
-// for example. But the truth is this class is ever so slightly more than a
-// transparent wrapper around 'State' due to additional Captcha data
-// (e.g consider operator=), and this would violate the style guide. Thus,
-// you must explicitly use the constructor when all you have is a State.
-// The good news is the implementation nests the enum inside a class, so you
-// may forward declare and typedef GoogleServiceAuthError to something shorter
-// in the comfort of your own translation unit.
-
-#ifndef CHROME_BROWSER_GOOGLE_SERVICE_AUTH_ERROR_H_
-#define CHROME_BROWSER_GOOGLE_SERVICE_AUTH_ERROR_H_
-
-#include <string>
-#include "googleurl/src/gurl.h"
-
-class GoogleServiceAuthError {
- public:
- enum State {
- // The user is authenticated.
- NONE = 0,
-
- // The credentials supplied to GAIA were either invalid, or the locally
- // cached credentials have expired.
- INVALID_GAIA_CREDENTIALS,
-
- // The GAIA user is not authorized to use the service.
- USER_NOT_SIGNED_UP,
-
- // Could not connect to server to verify credentials. This could be in
- // response to either failure to connect to GAIA or failure to connect to
- // the service needing GAIA tokens during authentication.
- CONNECTION_FAILED,
-
- // The user needs to satisfy a CAPTCHA challenge to unlock their account.
- // If no other information is available, this can be resolved by visiting
- // https://www.google.com/accounts/DisplayUnlockCaptcha. Otherwise,
- // captcha() will provide details about the associated challenge.
- CAPTCHA_REQUIRED,
- };
-
- // Additional data for CAPTCHA_REQUIRED errors.
- struct Captcha {
- Captcha() {}
- Captcha(const std::string& t, const GURL& img, const GURL& unlock)
- : token(t), image_url(img), unlock_url(unlock) {}
- std::string token; // Globally identifies the specific CAPTCHA challenge.
- GURL image_url; // The CAPTCHA image to show the user.
- GURL unlock_url; // Pretty unlock page containing above captcha.
- };
-
- // Construct a GoogleServiceAuthError from a State with no additional data.
- explicit GoogleServiceAuthError(State s) : state_(s) {}
-
- // Construct a CAPTCHA_REQUIRED error with CAPTCHA challenge data.
- static GoogleServiceAuthError FromCaptchaChallenge(
- const std::string& captcha_token,
- const GURL& captcha_image_url,
- const GURL& captcha_unlock_url) {
- return GoogleServiceAuthError(CAPTCHA_REQUIRED, captcha_token,
- captcha_image_url, captcha_unlock_url);
- }
-
- // Provided for convenience for clients needing to reset an instance to NONE.
- // (avoids err_ = GoogleServiceAuthError(GoogleServiceAuthError::NONE), due
- // to explicit class and State enum relation. Note: shouldn't be inlined!
- static const GoogleServiceAuthError None() {
- static const GoogleServiceAuthError e(NONE);
- return e;
- }
-
- // The error information.
- const State& state() const { return state_; }
- const Captcha& captcha() const { return captcha_; }
-
- private:
- GoogleServiceAuthError(State s, const std::string& captcha_token,
- const GURL& captcha_image_url,
- const GURL& captcha_unlock_url)
- : state_(s),
- captcha_(captcha_token, captcha_image_url, captcha_unlock_url) {
- }
-
- State state_;
- Captcha captcha_;
-};
-
-#endif // CHROME_BROWSER_GOOGLE_SERVICE_AUTH_ERROR_H_
diff --git a/chrome/browser/google_update.cc b/chrome/browser/google_update.cc
deleted file mode 100644
index dca2e9d..0000000
--- a/chrome/browser/google_update.cc
+++ /dev/null
@@ -1,331 +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/google_update.h"
-
-#include <atlbase.h>
-#include <atlcom.h>
-
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/scoped_comptr_win.h"
-#include "base/string_util.h"
-#include "base/task.h"
-#include "base/thread.h"
-#include "base/win_util.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/helper.h"
-#include "chrome/installer/util/install_util.h"
-#include "views/window/window.h"
-#include "google_update_idl_i.c"
-
-using views::Window;
-
-namespace {
-// Check if the currently running instance can be updated by Google Update.
-// Returns true only if the instance running is a Google Chrome
-// distribution installed in a standard location.
-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);
- 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(),
- machine_exe_path.begin(), tolower);
- if (chrome_exe_path != user_exe_path &&
- chrome_exe_path != machine_exe_path ) {
- LOG(ERROR) << L"Google Update cannot update Chrome installed in a "
- << L"non-standard location: " << chrome_exe_path.c_str()
- << L". The standard location is: " << user_exe_path.c_str()
- << L" or " << machine_exe_path.c_str() << L".";
- return false;
- }
-
- return true;
-#endif
-}
-
-// Creates an instance of a COM Local Server class using either plain vanilla
-// CoCreateInstance, or using the Elevation moniker if running on Vista.
-// hwnd must refer to a foregound window in order to get the UAC prompt
-// showing up in the foreground if running on Vista. It can also be NULL if
-// background UAC prompts are desired.
-HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
- HWND hwnd, void** interface_ptr) {
- if (!interface_ptr)
- return E_POINTER;
-
- // For Vista we need to instantiate the COM server via the elevation
- // moniker. This ensures that the UAC dialog shows up.
- if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) {
- wchar_t class_id_as_string[MAX_PATH] = {0};
- StringFromGUID2(class_id, class_id_as_string,
- arraysize(class_id_as_string));
-
- std::wstring elevation_moniker_name =
- StringPrintf(L"Elevation:Administrator!new:%ls", class_id_as_string);
-
- BIND_OPTS3 bind_opts;
- memset(&bind_opts, 0, sizeof(bind_opts));
- bind_opts.cbStruct = sizeof(bind_opts);
- bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
- bind_opts.hwnd = hwnd;
-
- return CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
- interface_id, reinterpret_cast<void**>(interface_ptr));
- }
-
- return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER,
- interface_id,
- reinterpret_cast<void**>(interface_ptr));
-}
-
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// The GoogleUpdateJobObserver COM class is responsible for receiving status
-// reports from google Update. It keeps track of the progress as Google Update
-// notifies us and ends the message loop we are spinning in once Google Update
-// reports that it is done.
-//
-////////////////////////////////////////////////////////////////////////////////
-class GoogleUpdateJobObserver
- : public CComObjectRootEx<CComSingleThreadModel>,
- public IJobObserver {
- public:
- BEGIN_COM_MAP(GoogleUpdateJobObserver)
- COM_INTERFACE_ENTRY(IJobObserver)
- END_COM_MAP()
-
- GoogleUpdateJobObserver()
- : result_(UPGRADE_ERROR) {
- }
- virtual ~GoogleUpdateJobObserver() {}
-
- // Notifications from Google Update:
- STDMETHOD(OnShow)() {
- return S_OK;
- }
- STDMETHOD(OnCheckingForUpdate)() {
- result_ = UPGRADE_CHECK_STARTED;
- return S_OK;
- }
- STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
- result_ = UPGRADE_IS_AVAILABLE;
- new_version_ = version_string;
- return S_OK;
- }
- STDMETHOD(OnWaitingToDownload)() {
- return S_OK;
- }
- STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
- return S_OK;
- }
- STDMETHOD(OnWaitingToInstall)() {
- return S_OK;
- }
- STDMETHOD(OnInstalling)() {
- result_ = UPGRADE_STARTED;
- return S_OK;
- }
- STDMETHOD(OnPause)() {
- return S_OK;
- }
- STDMETHOD(OnComplete)(CompletionCodes code, const TCHAR* text) {
- switch (code) {
- case COMPLETION_CODE_SUCCESS_CLOSE_UI:
- case COMPLETION_CODE_SUCCESS: {
- if (result_ == UPGRADE_STARTED)
- result_ = UPGRADE_SUCCESSFUL;
- else if (result_ == UPGRADE_CHECK_STARTED)
- result_ = UPGRADE_ALREADY_UP_TO_DATE;
- break;
- }
- default: {
- NOTREACHED();
- result_ = UPGRADE_ERROR;
- break;
- }
- }
-
- event_sink_ = NULL;
-
- // We no longer need to spin the message loop that we started spinning in
- // InitiateGoogleUpdateCheck.
- MessageLoop::current()->Quit();
- return S_OK;
- }
- STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
- event_sink_ = event_sink;
- return S_OK;
- }
-
- // Returns the results of the update operation.
- STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) {
- // Intermediary steps should never be reported to the client.
- DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED);
-
- *result = result_;
- return S_OK;
- }
-
- // Returns which version Google Update found on the server (if a more
- // recent version was found). Otherwise, this will be blank.
- STDMETHOD(GetVersionInfo)(std::wstring* version_string) {
- *version_string = new_version_;
- return S_OK;
- }
-
- private:
- // The status/result of the Google Update operation.
- GoogleUpdateUpgradeResult result_;
-
- // The version string Google Update found.
- std::wstring new_version_;
-
- // Allows us control the upgrade process to a small degree. After OnComplete
- // has been called, this object can not be used.
- ScopedComPtr<IProgressWndEvents> event_sink_;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// GoogleUpdate, public:
-
-GoogleUpdate::GoogleUpdate()
- : listener_(NULL) {
-}
-
-GoogleUpdate::~GoogleUpdate() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// GoogleUpdate, views::DialogDelegate implementation:
-
-void GoogleUpdate::CheckForUpdate(bool install_if_newer, Window* window) {
- // We need to shunt this request over to InitiateGoogleUpdateCheck and have
- // it run in the file thread.
- ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &GoogleUpdate::InitiateGoogleUpdateCheck, install_if_newer,
- window, MessageLoop::current()));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// GoogleUpdate, private:
-
-bool GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
- Window* window,
- MessageLoop* main_loop) {
-
- std::wstring chrome_exe_path;
- if (!PathService::Get(base::DIR_EXE, &chrome_exe_path)) {
- NOTREACHED();
- return false;
- }
-
- std::transform(chrome_exe_path.begin(), chrome_exe_path.end(),
- chrome_exe_path.begin(), tolower);
-
- if (!CanUpdateCurrentChrome(chrome_exe_path)) {
- main_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
- &GoogleUpdate::ReportResults, UPGRADE_ERROR,
- CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY));
- return false;
- }
-
- CComObject<GoogleUpdateJobObserver>* job_observer;
- HRESULT hr =
- CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer);
- if (hr != S_OK) {
- return ReportFailure(hr, GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED,
- main_loop);
- }
-
- ScopedComPtr<IJobObserver> job_holder(job_observer);
-
- ScopedComPtr<IGoogleUpdate> on_demand;
-
- if (InstallUtil::IsPerUserInstall(chrome_exe_path.c_str())) {
- hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
- } else {
- // The Update operation needs Admin privileges for writing
- // to %ProgramFiles%. On Vista we need to elevate before instantiating
- // the updater instance.
- if (!install_if_newer) {
- hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass);
- } else {
- HWND foreground_hwnd = NULL;
- if (window != NULL) {
- foreground_hwnd = window->GetNativeWindow();
- }
-
- hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
- IID_IGoogleUpdate, foreground_hwnd,
- reinterpret_cast<void**>(on_demand.Receive()));
- }
- }
-
- if (hr != S_OK)
- return ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, main_loop);
-
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- if (!install_if_newer)
- hr = on_demand->CheckForUpdate(dist->GetAppGuid().c_str(), job_observer);
- else
- hr = on_demand->Update(dist->GetAppGuid().c_str(), job_observer);
-
- if (hr != S_OK)
- return ReportFailure(hr, GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR,
- main_loop);
-
- // We need to spin the message loop while Google Update is running so that it
- // can report back to us through GoogleUpdateJobObserver. This message loop
- // will terminate once Google Update sends us the completion status
- // (success/error). See OnComplete().
- MessageLoop::current()->Run();
-
- GoogleUpdateUpgradeResult results;
- hr = job_observer->GetResult(&results);
- if (hr != S_OK)
- return ReportFailure(hr, GOOGLE_UPDATE_GET_RESULT_CALL_FAILED, main_loop);
-
- if (results == UPGRADE_ERROR)
- return ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, main_loop);
-
- hr = job_observer->GetVersionInfo(&version_available_);
- if (hr != S_OK)
- return ReportFailure(hr, GOOGLE_UPDATE_GET_VERSION_INFO_FAILED, main_loop);
-
- main_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
- &GoogleUpdate::ReportResults, results, GOOGLE_UPDATE_NO_ERROR));
- job_holder = NULL;
- on_demand = NULL;
- return true;
-}
-
-void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results,
- GoogleUpdateErrorCode error_code) {
- // If we get an error, then error code must not be blank, and vice versa.
- DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR :
- error_code == GOOGLE_UPDATE_NO_ERROR);
- if (listener_)
- listener_->OnReportResults(results, error_code, version_available_);
-}
-
-bool GoogleUpdate::ReportFailure(HRESULT hr, GoogleUpdateErrorCode error_code,
- MessageLoop* main_loop) {
- NOTREACHED() << "Communication with Google Update failed: " << hr
- << " error: " << error_code;
- main_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
- &GoogleUpdate::ReportResults, UPGRADE_ERROR, error_code));
- return false;
-}
diff --git a/chrome/browser/google_update.h b/chrome/browser/google_update.h
deleted file mode 100644
index 9bbe58f..0000000
--- a/chrome/browser/google_update.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_GOOGLE_UPDATE_H_
-#define CHROME_BROWSER_GOOGLE_UPDATE_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/ref_counted.h"
-#if defined(OS_WIN)
-#include "google_update_idl.h"
-#endif
-
-class MessageLoop;
-namespace views {
-class Window;
-}
-
-// The status of the upgrade. UPGRADE_STARTED and UPGRADE_CHECK_STARTED are
-// internal states and will not be reported as results to the listener.
-enum GoogleUpdateUpgradeResult {
- // The upgrade has started.
- UPGRADE_STARTED = 0,
- // A check for upgrade has been initiated.
- UPGRADE_CHECK_STARTED,
- // An update is available.
- UPGRADE_IS_AVAILABLE,
- // The upgrade happened successfully.
- UPGRADE_SUCCESSFUL,
- // No need to upgrade, we are up to date.
- UPGRADE_ALREADY_UP_TO_DATE,
- // An error occurred.
- UPGRADE_ERROR,
-};
-
-enum GoogleUpdateErrorCode {
- // The upgrade completed successfully (or hasn't been started yet).
- GOOGLE_UPDATE_NO_ERROR = 0,
- // Google Update only supports upgrading if Chrome is installed in the default
- // location. This error will appear for developer builds and with
- // installations unzipped to random locations.
- CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY,
- // Failed to create Google Update JobServer COM class.
- GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED,
- // Failed to create Google Update OnDemand COM class.
- GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND,
- // Google Update OnDemand COM class reported an error during a check for
- // update (or while upgrading).
- GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR,
- // A call to GetResults failed.
- GOOGLE_UPDATE_GET_RESULT_CALL_FAILED,
- // A call to GetVersionInfo failed.
- GOOGLE_UPDATE_GET_VERSION_INFO_FAILED,
- // An error occurred while upgrading (or while checking for update).
- // Check the Google Update log in %TEMP% for more details.
- GOOGLE_UPDATE_ERROR_UPDATING,
-};
-
-// The GoogleUpdateStatusListener interface is used by components to receive
-// notifications about the results of an Google Update operation.
-class GoogleUpdateStatusListener {
- public:
- // This function is called when Google Update has finished its operation and
- // wants to notify us about the results. |results| represents what the end
- // state is, |error_code| represents what error occurred and |version|
- // specifies what new version Google Update detected (or installed). This
- // value can be a blank string, if the version tag in the Update{} block
- // (in Google Update's server config for Chrome) is blank.
- virtual void OnReportResults(GoogleUpdateUpgradeResult results,
- GoogleUpdateErrorCode error_code,
- const std::wstring& version) = 0;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// The Google Update class is responsible for communicating with Google Update
-// and get it to perform operations on our behalf (for example, CheckForUpdate).
-// This class will report back to its parent via the GoogleUpdateStatusListener
-// interface and will delete itself after reporting back.
-//
-////////////////////////////////////////////////////////////////////////////////
-class GoogleUpdate : public base::RefCountedThreadSafe<GoogleUpdate> {
- public:
- GoogleUpdate();
-
- // Ask Google Update to see if a new version is available. If the parameter
- // |install_if_newer| is true then Google Update will also install that new
- // version.
- // |window| should point to a foreground window. This is needed to ensure
- // that Vista/Windows 7 UAC prompts show up in the foreground. It may also
- // be null.
- void CheckForUpdate(bool install_if_newer, views::Window* window);
-
- // Pass NULL to clear the listener
- void set_status_listener(GoogleUpdateStatusListener* listener) {
- listener_ = listener;
- }
-
- private:
- friend class base::RefCountedThreadSafe<GoogleUpdate>;
-
- virtual ~GoogleUpdate();
-
-// The chromeos implementation is in browser/chromeos/google_update.cpp
-
-#if defined(OS_WIN)
-
- // This function reports failure from the Google Update operation to the
- // listener.
- // Note, after this function completes, this object will have deleted itself.
- bool ReportFailure(HRESULT hr, GoogleUpdateErrorCode error_code,
- MessageLoop* main_loop);
-
-#endif
-
- // We need to run the update check on another thread than the main thread, and
- // therefore CheckForUpdate will delegate to this function. |main_loop| points
- // to the message loop that we want the response to come from.
- // |window| should point to a foreground window. This is needed to ensure that
- // Vista/Windows 7 UAC prompts show up in the foreground. It may also be null.
- bool InitiateGoogleUpdateCheck(bool install_if_newer, views::Window* window,
- MessageLoop* main_loop);
-
- // This function reports the results of the GoogleUpdate operation to the
- // listener. If results indicates an error, the error_code will indicate which
- // error occurred.
- // Note, after this function completes, this object will have deleted itself.
- void ReportResults(GoogleUpdateUpgradeResult results,
- GoogleUpdateErrorCode error_code);
-
- // Which version string Google Update found (if a new one was available).
- // Otherwise, this will be blank.
- std::wstring version_available_;
-
- // The listener who is interested in finding out the result of the operation.
- GoogleUpdateStatusListener* listener_;
-
- DISALLOW_COPY_AND_ASSIGN(GoogleUpdate);
-};
-
-#endif // CHROME_BROWSER_GOOGLE_UPDATE_H_
diff --git a/chrome/browser/google_update_settings_posix.cc b/chrome/browser/google_update_settings_posix.cc
deleted file mode 100644
index d1ce592..0000000
--- a/chrome/browser/google_update_settings_posix.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 "chrome/installer/util/google_update_settings.h"
-
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/rand_util.h"
-#include "base/string_util.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-
-namespace google_update {
-std::string posix_guid;
-}
-
-// File name used in the user data dir to indicate consent.
-static const char kConsentToSendStats[] = "Consent To Send Stats";
-
-// static
-bool GoogleUpdateSettings::GetCollectStatsConsent() {
- bool forced_enable = CommandLine::ForCurrentProcess()->
- HasSwitch(switches::kEnableCrashReporter);
- FilePath consent_file;
- PathService::Get(chrome::DIR_USER_DATA, &consent_file);
- consent_file = consent_file.Append(kConsentToSendStats);
- std::string tmp_guid;
- bool consented = file_util::ReadFileToString(consent_file, &tmp_guid);
- if (forced_enable || consented)
- google_update::posix_guid.assign(tmp_guid);
- return forced_enable || consented;
-}
-
-// static
-bool GoogleUpdateSettings::SetCollectStatsConsent(bool consented) {
- FilePath consent_dir;
- PathService::Get(chrome::DIR_USER_DATA, &consent_dir);
- if (!file_util::DirectoryExists(consent_dir))
- return false;
-
- FilePath consent_file = consent_dir.AppendASCII(kConsentToSendStats);
- if (consented) {
- if ((!file_util::PathExists(consent_file)) ||
- (file_util::PathExists(consent_file) &&
- !google_update::posix_guid.empty())) {
- const char* c_str = google_update::posix_guid.c_str();
- int size = google_update::posix_guid.size();
- return file_util::WriteFile(consent_file, c_str, size) == size;
- }
- } else {
- google_update::posix_guid.clear();
- return file_util::Delete(consent_file, false);
- }
- return true;
-}
-
-bool GoogleUpdateSettings::SetMetricsId(const std::wstring& client_id) {
- // Make sure that user has consented to send crashes.
- FilePath consent_dir;
- PathService::Get(chrome::DIR_USER_DATA, &consent_dir);
- if (!file_util::DirectoryExists(consent_dir) ||
- !GoogleUpdateSettings::GetCollectStatsConsent())
- return false;
-
- // Since user has consented, write the metrics id to the file.
- google_update::posix_guid = WideToASCII(client_id);
- return GoogleUpdateSettings::SetCollectStatsConsent(true);
-}
-
-// GetLastRunTime and SetLastRunTime are not implemented for posix. Their
-// currebnt return values signal failure which the caller is designed to
-// handle.
-
-// static
-int GoogleUpdateSettings::GetLastRunTime() {
- return -1;
-}
-
-// static
-bool GoogleUpdateSettings::SetLastRunTime() {
- return false;
-}
diff --git a/chrome/browser/google_update_settings_unittest.cc b/chrome/browser/google_update_settings_unittest.cc
deleted file mode 100644
index 8dc56bb..0000000
--- a/chrome/browser/google_update_settings_unittest.cc
+++ /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.
-
-#include "chrome/installer/util/google_update_settings.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-class GoogleUpdateTest : public PlatformTest {
-};
-
-TEST_F(GoogleUpdateTest, StatsConstent) {
- // Stats are off by default.
- EXPECT_FALSE(GoogleUpdateSettings::GetCollectStatsConsent());
- // Stats reporting is ON.
- EXPECT_TRUE(GoogleUpdateSettings::SetCollectStatsConsent(true));
- EXPECT_TRUE(GoogleUpdateSettings::GetCollectStatsConsent());
- // Stats reporting is OFF.
- EXPECT_TRUE(GoogleUpdateSettings::SetCollectStatsConsent(false));
- EXPECT_FALSE(GoogleUpdateSettings::GetCollectStatsConsent());
-}
-
-#if defined(OS_WIN)
-
-TEST_F(GoogleUpdateTest, LastRunTime) {
- // Querying the value that does not exists should fail.
- EXPECT_TRUE(GoogleUpdateSettings::RemoveLastRunTime());
- EXPECT_EQ(-1, GoogleUpdateSettings::GetLastRunTime());
- // Setting and querying the last update time in fast sequence
- // should give 0 days.
- EXPECT_TRUE(GoogleUpdateSettings::SetLastRunTime());
- EXPECT_EQ(0, GoogleUpdateSettings::GetLastRunTime());
-}
-
-#endif // defined(OS_WIN)
diff --git a/chrome/browser/google_url_tracker.cc b/chrome/browser/google_url_tracker.cc
deleted file mode 100644
index b703393..0000000
--- a/chrome/browser/google_url_tracker.cc
+++ /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.
-
-#include "chrome/browser/google_url_tracker.h"
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "net/base/load_flags.h"
-#include "net/url_request/url_request_status.h"
-
-const char GoogleURLTracker::kDefaultGoogleHomepage[] =
- "http://www.google.com/";
-
-GoogleURLTracker::GoogleURLTracker()
- : google_url_(g_browser_process->local_state()->GetString(
- prefs::kLastKnownGoogleURL)),
- ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_factory_(this)),
- in_startup_sleep_(true),
- already_fetched_(false),
- need_to_fetch_(false),
- request_context_available_(!!Profile::GetDefaultRequestContext()) {
- registrar_.Add(this, NotificationType::DEFAULT_REQUEST_CONTEXT_AVAILABLE,
- NotificationService::AllSources());
-
- // Because this function can be called during startup, when kicking off a URL
- // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully
- // long enough to be after startup, but still get results back quickly.
- // Ideally, instead of this timer, we'd do something like "check if the
- // browser is starting up, and if so, come back later", but there is currently
- // no function to do this.
- static const int kStartFetchDelayMS = 5000;
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- fetcher_factory_.NewRunnableMethod(&GoogleURLTracker::FinishSleep),
- kStartFetchDelayMS);
-}
-
-GoogleURLTracker::~GoogleURLTracker() {
-}
-
-// static
-GURL GoogleURLTracker::GoogleURL() {
- const GoogleURLTracker* const tracker =
- g_browser_process->google_url_tracker();
- return tracker ? tracker->google_url_ : GURL(kDefaultGoogleHomepage);
-}
-
-// static
-void GoogleURLTracker::RequestServerCheck() {
- GoogleURLTracker* const tracker = g_browser_process->google_url_tracker();
- if (tracker)
- tracker->SetNeedToFetch();
-}
-
-// static
-void GoogleURLTracker::RegisterPrefs(PrefService* prefs) {
- prefs->RegisterStringPref(prefs::kLastKnownGoogleURL,
- kDefaultGoogleHomepage);
-}
-
-// static
-bool GoogleURLTracker::CheckAndConvertToGoogleBaseURL(const GURL& url,
- GURL* base_url) {
- // Only allow updates if the new URL appears to be on google.xx, google.co.xx,
- // or google.com.xx. Cases other than this are either malicious, or doorway
- // pages for hotel WiFi connections and the like.
- // NOTE: Obviously the above is not as secure as whitelisting all known Google
- // frontpage domains, but for now we're trying to prevent login pages etc.
- // from ruining the user experience, rather than preventing hijacking.
- std::vector<std::string> host_components;
- SplitStringDontTrim(url.host(), '.', &host_components);
- if (host_components.size() < 2)
- return false;
- size_t google_component = host_components.size() - 2;
- const std::string& component = host_components[google_component];
- if (component != "google") {
- if ((host_components.size() < 3) ||
- ((component != "co") && (component != "com")))
- return false;
- google_component = host_components.size() - 3;
- if (host_components[google_component] != "google")
- return false;
- }
- // For Google employees only: If the URL appears to be on
- // [*.]corp.google.com, it's likely a doorway (e.g.
- // wifi.corp.google.com), so ignore it.
- if ((google_component > 0) &&
- (host_components[google_component - 1] == "corp"))
- return false;
-
- // If the url's path does not begin "/intl/", reset it to "/". Other paths
- // represent services such as iGoogle that are irrelevant to the baseURL.
- *base_url = url.path().compare(0, 6, "/intl/") ? url.GetWithEmptyPath() : url;
- return true;
-}
-
-void GoogleURLTracker::SetNeedToFetch() {
- need_to_fetch_ = true;
- StartFetchIfDesirable();
-}
-
-void GoogleURLTracker::FinishSleep() {
- in_startup_sleep_ = false;
- StartFetchIfDesirable();
-}
-
-void GoogleURLTracker::StartFetchIfDesirable() {
- // Bail if a fetch isn't appropriate right now. This function will be called
- // again each time one of the preconditions changes, so we'll fetch
- // immediately once all of them are met.
- //
- // See comments in header on the class, on RequestServerCheck(), and on the
- // various members here for more detail on exactly what the conditions are.
- if (in_startup_sleep_ || already_fetched_ || !need_to_fetch_ ||
- !request_context_available_)
- return;
-
- need_to_fetch_ = false;
- already_fetched_ = true; // If fetching fails, we don't bother to reset this
- // flag; we just live with an outdated URL for this
- // run of the browser.
- fetcher_.reset(new URLFetcher(GURL(kDefaultGoogleHomepage), URLFetcher::HEAD,
- this));
- // We don't want this fetch to affect existing state in the profile. For
- // example, if a user has no Google cookies, this automatic check should not
- // cause one to be set, lest we alarm the user.
- fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE |
- net::LOAD_DO_NOT_SAVE_COOKIES);
- fetcher_->set_request_context(Profile::GetDefaultRequestContext());
- fetcher_->Start();
-}
-
-void GoogleURLTracker::OnURLFetchComplete(const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data) {
- // Delete the fetcher on this function's exit.
- scoped_ptr<URLFetcher> clean_up_fetcher(fetcher_.release());
-
- // Don't update the URL if the request didn't succeed.
- if (!status.is_success() || (response_code != 200))
- return;
-
- // See if the response URL was one we want to use, and if so, convert to the
- // appropriate Google base URL.
- GURL base_url;
- if (!CheckAndConvertToGoogleBaseURL(url, &base_url))
- return;
-
- // Update the saved base URL if it has changed.
- const std::string base_url_str(base_url.spec());
- if (g_browser_process->local_state()->GetString(prefs::kLastKnownGoogleURL) !=
- base_url_str) {
- g_browser_process->local_state()->SetString(prefs::kLastKnownGoogleURL,
- base_url_str);
- google_url_ = base_url;
- NotificationService::current()->Notify(NotificationType::GOOGLE_URL_UPDATED,
- NotificationService::AllSources(),
- NotificationService::NoDetails());
- }
-}
-
-void GoogleURLTracker::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK_EQ(NotificationType::DEFAULT_REQUEST_CONTEXT_AVAILABLE, type.value);
- request_context_available_ = true;
- StartFetchIfDesirable();
-}
diff --git a/chrome/browser/google_url_tracker.h b/chrome/browser/google_url_tracker.h
deleted file mode 100644
index 5158ec8..0000000
--- a/chrome/browser/google_url_tracker.h
+++ /dev/null
@@ -1,113 +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_GOOGLE_URL_TRACKER_H_
-#define CHROME_BROWSER_GOOGLE_URL_TRACKER_H_
-
-#include <string>
-
-#include "base/gtest_prod_util.h"
-#include "base/scoped_ptr.h"
-#include "chrome/common/net/url_fetcher.h"
-#include "chrome/common/notification_registrar.h"
-#include "googleurl/src/gurl.h"
-
-class PrefService;
-
-// This object is responsible for updating the Google URL at most once per run,
-// and tracking the currently known value, which is also saved to a pref.
-//
-// Most consumers should only call GoogleURL(), which is guaranteed to
-// synchronously return a value at all times (even during startup or in unittest
-// mode). Consumers who need to be notified when things change should listen to
-// the notification service for NOTIFY_GOOGLE_URL_UPDATED, and call GoogleURL()
-// again after receiving it, in order to get the updated value.
-//
-// To protect users' privacy and reduce server load, no updates will be
-// performed (ever) unless at least one consumer registers interest by calling
-// RequestServerCheck().
-class GoogleURLTracker : public URLFetcher::Delegate,
- public NotificationObserver {
- public:
- // Only the main browser process loop should call this, when setting up
- // g_browser_process->google_url_tracker_. No code other than the
- // GoogleURLTracker itself should actually use
- // g_browser_process->google_url_tracker() (which shouldn't be hard, since
- // there aren't useful public functions on this object for consumers to access
- // anyway).
- GoogleURLTracker();
-
- ~GoogleURLTracker();
-
- // Returns the current Google URL. This will return a valid URL even in
- // unittest mode.
- //
- // This is the only function most code should ever call.
- static GURL GoogleURL();
-
- // Requests that the tracker perform a server check to update the Google URL
- // as necessary. This will happen at most once per run, not sooner than five
- // seconds after startup (checks requested before that time will occur then;
- // checks requested afterwards will occur immediately, if no other checks have
- // been made during this run).
- //
- // In unittest mode, this function does nothing.
- static void RequestServerCheck();
-
- static void RegisterPrefs(PrefService* prefs);
-
- static const char kDefaultGoogleHomepage[];
-
- private:
- FRIEND_TEST_ALL_PREFIXES(GoogleURLTrackerTest, CheckAndConvertURL);
-
- // Determines if |url| is an appropriate source for a new Google base URL, and
- // update |base_url| to the appropriate base URL if so. Returns whether the
- // check succeeded (and thus whether |base_url| was actually updated).
- static bool CheckAndConvertToGoogleBaseURL(const GURL& url, GURL* base_url);
-
- // Registers consumer interest in getting an updated URL from the server.
- void SetNeedToFetch();
-
- // Called when the five second startup sleep has finished. Runs any pending
- // fetch.
- void FinishSleep();
-
- // Starts the fetch of the up-to-date Google URL if we actually want to fetch
- // it and can currently do so.
- void StartFetchIfDesirable();
-
- // URLFetcher::Delegate
- virtual void OnURLFetchComplete(const URLFetcher *source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data);
-
- // NotificationObserver
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- NotificationRegistrar registrar_;
- GURL google_url_;
- ScopedRunnableMethodFactory<GoogleURLTracker> fetcher_factory_;
- scoped_ptr<URLFetcher> fetcher_;
- bool in_startup_sleep_; // True if we're in the five-second "no fetching"
- // period that begins at browser start.
- bool already_fetched_; // True if we've already fetched a URL once this run;
- // we won't fetch again until after a restart.
- bool need_to_fetch_; // True if a consumer actually wants us to fetch an
- // updated URL. If this is never set, we won't
- // bother to fetch anything.
- bool request_context_available_;
- // True when the profile has been loaded and the
- // default request context created, so we can
- // actually do the fetch with the right data.
-
- DISALLOW_COPY_AND_ASSIGN(GoogleURLTracker);
-};
-
-#endif // CHROME_BROWSER_GOOGLE_URL_TRACKER_H_
diff --git a/chrome/browser/google_url_tracker_unittest.cc b/chrome/browser/google_url_tracker_unittest.cc
deleted file mode 100644
index 9de0b88..0000000
--- a/chrome/browser/google_url_tracker_unittest.cc
+++ /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.
-
-#include "chrome/browser/google_url_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(GoogleURLTrackerTest, CheckAndConvertURL) {
- static const struct {
- const char* const source_url;
- const bool can_convert;
- const char* const base_url;
- } data[] = {
- { "http://www.google.com/", true, "http://www.google.com/", },
- { "http://google.fr/", true, "http://google.fr/", },
- { "http://google.co.uk/", true, "http://google.co.uk/", },
- { "http://www.google.com.by/", true, "http://www.google.com.by/", },
- { "http://www.google.com/ig", true, "http://www.google.com/", },
- { "http://www.google.com/intl/xx", true, "http://www.google.com/intl/xx", },
- { "http://a.b.c.google.com/", true, "http://a.b.c.google.com/", },
- { "http://www.yahoo.com/", false, "", },
- { "http://google.evil.com/", false, "", },
- { "http://google.com.com.com/", false, "", },
- { "http://google/", false, "", },
- { "http://wifi.corp.google.com/", false, "" },
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
- GURL base_url;
- const bool can_convert = GoogleURLTracker::CheckAndConvertToGoogleBaseURL(
- GURL(data[i].source_url), &base_url);
- EXPECT_EQ(data[i].can_convert, can_convert);
- EXPECT_STREQ(data[i].base_url, base_url.spec().c_str());
- }
-}
diff --git a/chrome/browser/google_util.cc b/chrome/browser/google_util.cc
deleted file mode 100644
index e8553e9..0000000
--- a/chrome/browser/google_util.cc
+++ /dev/null
@@ -1,58 +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/google_util.h"
-
-#include <string>
-
-#include "base/string_util.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/google_url_tracker.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/registry_controlled_domain.h"
-
-namespace {
-
-// A helper method for adding a query param to |url|.
-GURL AppendParam(const GURL& url,
- const std::string& param_name,
- const std::string& param_value) {
- std::string query(url.query());
- if (!query.empty())
- query += "&";
- query += param_name + "=" + param_value;
- GURL::Replacements repl;
- repl.SetQueryStr(query);
- return url.ReplaceComponents(repl);
-}
-
-} // anonymous namespace
-
-namespace google_util {
-
-const char kLinkDoctorBaseURL[] =
- "http://linkhelp.clients.google.com/tbproxy/lh/fixurl";
-
-GURL AppendGoogleLocaleParam(const GURL& url) {
- // Google does not yet recognize 'nb' for Norwegian Bokmal, but it uses
- // 'no' for that.
- std::string locale = g_browser_process->GetApplicationLocale();
- if (locale == "nb")
- locale = "no";
- return AppendParam(url, "hl", locale);
-}
-
-GURL AppendGoogleTLDParam(const GURL& url) {
- const std::string google_domain(
- net::RegistryControlledDomainService::GetDomainAndRegistry(
- GoogleURLTracker::GoogleURL()));
- const size_t first_dot = google_domain.find('.');
- if (first_dot == std::string::npos) {
- NOTREACHED();
- return url;
- }
- return AppendParam(url, "sd", google_domain.substr(first_dot + 1));
-}
-
-} // namespace google_util
diff --git a/chrome/browser/google_util.h b/chrome/browser/google_util.h
deleted file mode 100644
index a4f99e3..0000000
--- a/chrome/browser/google_util.h
+++ /dev/null
@@ -1,26 +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.
-//
-// Some Google related utility functions.
-
-#ifndef CHROME_BROWSER_GOOGLE_UTIL_H__
-#define CHROME_BROWSER_GOOGLE_UTIL_H__
-
-class GURL;
-
-namespace google_util {
-
-extern const char kLinkDoctorBaseURL[];
-
-// Adds the Google locale string to the URL (e.g., hl=en-US). This does not
-// check to see if the param already exists.
-GURL AppendGoogleLocaleParam(const GURL& url);
-
-// Adds the Google TLD string to the URL (e.g., sd=com). This does not
-// check to see if the param already exists.
-GURL AppendGoogleTLDParam(const GURL& url);
-
-} // namespace google_util
-
-#endif // CHROME_BROWSER_GOOGLE_UTIL_H__
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc
index cdf1102..f4c6164 100644
--- a/chrome/browser/gpu_process_host.cc
+++ b/chrome/browser/gpu_process_host.cc
@@ -10,10 +10,14 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/gpu_process_host_ui_shim.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/gpu_info.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/common/render_messages.h"
+#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_switches.h"
#if defined(OS_LINUX)
@@ -25,17 +29,14 @@ namespace {
// Tasks used by this file
class RouteOnUIThreadTask : public Task {
public:
- explicit RouteOnUIThreadTask(const IPC::Message& msg) {
- msg_ = new IPC::Message(msg);
+ explicit RouteOnUIThreadTask(const IPC::Message& msg) : msg_(msg) {
}
private:
void Run() {
- GpuProcessHostUIShim::Get()->OnMessageReceived(*msg_);
- delete msg_;
- msg_ = NULL;
+ GpuProcessHostUIShim::Get()->OnMessageReceived(msg_);
}
- IPC::Message* msg_;
+ IPC::Message msg_;
};
// Global GpuProcessHost instance.
@@ -76,33 +77,27 @@ bool GpuProcessHost::Init() {
return false;
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- std::wstring gpu_launcher =
- browser_command_line.GetSwitchValue(switches::kGpuLauncher);
+ CommandLine::StringType gpu_launcher =
+ browser_command_line.GetSwitchValueNative(switches::kGpuLauncher);
FilePath exe_path = ChildProcessHost::GetChildPath(gpu_launcher.empty());
if (exe_path.empty())
return false;
CommandLine* cmd_line = new CommandLine(exe_path);
- cmd_line->AppendSwitchWithValue(switches::kProcessType,
- switches::kGpuProcess);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
// Propagate relevant command line switches.
- static const char* const switch_names[] = {
+ static const char* const kSwitchNames[] = {
switches::kUseGL,
+ switches::kDisableLogging,
+ switches::kEnableLogging,
+ switches::kGpuStartupDialog,
+ switches::kLoggingLevel,
};
-
- for (size_t i = 0; i < arraysize(switch_names); ++i) {
- if (browser_command_line.HasSwitch(switch_names[i])) {
- cmd_line->AppendSwitchWithValue(switch_names[i],
- browser_command_line.GetSwitchValueASCII(switch_names[i]));
- }
- }
-
- const CommandLine& browser_cmd_line = *CommandLine::ForCurrentProcess();
- PropagateBrowserCommandLineToGpu(browser_cmd_line, cmd_line);
+ cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
+ arraysize(kSwitchNames));
// If specified, prepend a launcher program to the command line.
if (!gpu_launcher.empty())
@@ -127,6 +122,16 @@ GpuProcessHost* GpuProcessHost::Get() {
return sole_instance_;
}
+// static
+void GpuProcessHost::SendAboutGpuCrash() {
+ Get()->Send(new GpuMsg_Crash());
+}
+
+// static
+void GpuProcessHost::SendAboutGpuHang() {
+ Get()->Send(new GpuMsg_Hang());
+}
+
bool GpuProcessHost::Send(IPC::Message* msg) {
if (!EnsureInitialized())
return false;
@@ -151,7 +156,7 @@ void GpuProcessHost::EstablishGpuChannel(int renderer_id,
if (Send(new GpuMsg_EstablishChannel(renderer_id))) {
sent_requests_.push(ChannelRequest(filter));
} else {
- ReplyToRenderer(IPC::ChannelHandle(), filter);
+ ReplyToRenderer(IPC::ChannelHandle(), GPUInfo(), filter);
}
}
@@ -169,8 +174,15 @@ void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply, OnSynchronizeReply)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
+ OnGraphicsInfoCollected)
#if defined(OS_LINUX)
IPC_MESSAGE_HANDLER(GpuHostMsg_GetViewXID, OnGetViewXID)
+#elif defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSetIOSurface,
+ OnAcceleratedSurfaceSetIOSurface)
+ IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
+ OnAcceleratedSurfaceBuffersSwapped)
#endif
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
@@ -180,7 +192,7 @@ void GpuProcessHost::OnChannelEstablished(
const IPC::ChannelHandle& channel_handle,
const GPUInfo& gpu_info) {
const ChannelRequest& request = sent_requests_.front();
- ReplyToRenderer(channel_handle, request.filter);
+ ReplyToRenderer(channel_handle, gpu_info, request.filter);
sent_requests_.pop();
gpu_info_ = gpu_info;
child_process_logging::SetGpuInfo(gpu_info);
@@ -193,6 +205,10 @@ void GpuProcessHost::OnSynchronizeReply() {
queued_synchronization_replies_.pop();
}
+void GpuProcessHost::OnGraphicsInfoCollected(const GPUInfo& gpu_info) {
+ gpu_info_ = gpu_info;
+}
+
#if defined(OS_LINUX)
void GpuProcessHost::OnGetViewXID(gfx::NativeViewId id, unsigned long* xid) {
GtkNativeViewManager* manager = Singleton<GtkNativeViewManager>::get();
@@ -201,13 +217,95 @@ void GpuProcessHost::OnGetViewXID(gfx::NativeViewId id, unsigned long* xid) {
*xid = 0;
}
}
+
+#elif defined(OS_MACOSX)
+
+namespace {
+
+class SetIOSurfaceDispatcher : public Task {
+ public:
+ SetIOSurfaceDispatcher(
+ const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params)
+ : params_(params) {
+ }
+
+ void Run() {
+ RenderViewHost* host = RenderViewHost::FromID(params_.renderer_id,
+ params_.render_view_id);
+ if (!host)
+ return;
+ RenderWidgetHostView* view = host->view();
+ if (!view)
+ return;
+ view->AcceleratedSurfaceSetIOSurface(params_.window,
+ params_.width,
+ params_.height,
+ params_.identifier);
+ }
+
+ private:
+ GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params_;
+
+ DISALLOW_COPY_AND_ASSIGN(SetIOSurfaceDispatcher);
+};
+
+} // namespace
+
+void GpuProcessHost::OnAcceleratedSurfaceSetIOSurface(
+ const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ new SetIOSurfaceDispatcher(params));
+}
+
+namespace {
+
+class BuffersSwappedDispatcher : public Task {
+ public:
+ BuffersSwappedDispatcher(
+ int32 renderer_id, int32 render_view_id, gfx::PluginWindowHandle window)
+ : renderer_id_(renderer_id),
+ render_view_id_(render_view_id),
+ window_(window) {
+ }
+
+ void Run() {
+ RenderViewHost* host = RenderViewHost::FromID(renderer_id_,
+ render_view_id_);
+ if (!host)
+ return;
+ RenderWidgetHostView* view = host->view();
+ if (!view)
+ return;
+ view->AcceleratedSurfaceBuffersSwapped(window_);
+ }
+
+ private:
+ int32 renderer_id_;
+ int32 render_view_id_;
+ gfx::PluginWindowHandle window_;
+
+ DISALLOW_COPY_AND_ASSIGN(BuffersSwappedDispatcher);
+};
+
+} // namespace
+
+void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped(
+ int32 renderer_id,
+ int32 render_view_id,
+ gfx::PluginWindowHandle window) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ new BuffersSwappedDispatcher(renderer_id, render_view_id, window));
+}
#endif
void GpuProcessHost::ReplyToRenderer(
const IPC::ChannelHandle& channel,
+ const GPUInfo& gpu_info,
ResourceMessageFilter* filter) {
ViewMsg_GpuChannelEstablished* message =
- new ViewMsg_GpuChannelEstablished(channel);
+ new ViewMsg_GpuChannelEstablished(channel, gpu_info);
// If the renderer process is performing synchronous initialization,
// it needs to handle this message before receiving the reply for
// the synchronous ViewHostMsg_SynchronizeGpu message.
@@ -215,26 +313,6 @@ void GpuProcessHost::ReplyToRenderer(
filter->Send(message);
}
-void GpuProcessHost::PropagateBrowserCommandLineToGpu(
- const CommandLine& browser_cmd,
- CommandLine* gpu_cmd) const {
- // Propagate the following switches to the GPU process command line (along
- // with any associated values) if present in the browser command line.
- static const char* const switch_names[] = {
- switches::kDisableLogging,
- switches::kEnableLogging,
- switches::kGpuStartupDialog,
- switches::kLoggingLevel,
- };
-
- for (size_t i = 0; i < arraysize(switch_names); ++i) {
- if (browser_cmd.HasSwitch(switch_names[i])) {
- gpu_cmd->AppendSwitchWithValue(switch_names[i],
- browser_cmd.GetSwitchValueASCII(switch_names[i]));
- }
- }
-}
-
URLRequestContext* GpuProcessHost::GetRequestContext(
uint32 request_id,
const ViewHostMsg_Resource_Request& request_data) {
diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h
index a331f69..e4d4559 100644
--- a/chrome/browser/gpu_process_host.h
+++ b/chrome/browser/gpu_process_host.h
@@ -4,17 +4,19 @@
#ifndef CHROME_BROWSER_GPU_PROCESS_HOST_H_
#define CHROME_BROWSER_GPU_PROCESS_HOST_H_
+#pragma once
#include <queue>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/gpu_info.h"
#include "gfx/native_widget_types.h"
-class CommandBufferProxy;
+struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params;
+class GPUInfo;
namespace IPC {
struct ChannelHandle;
@@ -26,6 +28,13 @@ class GpuProcessHost : public BrowserChildProcessHost {
// Getter for the singleton. This will return NULL on failure.
static GpuProcessHost* Get();
+ // Tells the GPU process to crash. Useful for testing.
+ static void SendAboutGpuCrash();
+
+ // Tells the GPU process to let its main thread enter an infinite loop.
+ // Useful for testing.
+ static void SendAboutGpuHang();
+
// Shutdown routine, which should only be called upon process
// termination.
static void Shutdown();
@@ -84,19 +93,21 @@ class GpuProcessHost : public BrowserChildProcessHost {
void OnChannelEstablished(const IPC::ChannelHandle& channel_handle,
const GPUInfo& gpu_info);
void OnSynchronizeReply();
+ void OnGraphicsInfoCollected(const GPUInfo& gpu_info);
#if defined(OS_LINUX)
void OnGetViewXID(gfx::NativeViewId id, unsigned long* xid);
+#elif defined(OS_MACOSX)
+ void OnAcceleratedSurfaceSetIOSurface(
+ const GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params& params);
+ void OnAcceleratedSurfaceBuffersSwapped(int32 renderer_id,
+ int32 render_view_id,
+ gfx::PluginWindowHandle window);
#endif
void ReplyToRenderer(const IPC::ChannelHandle& channel,
+ const GPUInfo& gpu_info,
ResourceMessageFilter* filter);
- // Copies applicable command line switches from the given |browser_cmd| line
- // flags to the output |gpu_cmd| line flags. Not all switches will be
- // copied over.
- void PropagateBrowserCommandLineToGpu(const CommandLine& browser_cmd,
- CommandLine* gpu_cmd) const;
-
// ResourceDispatcherHost::Receiver implementation:
virtual URLRequestContext* GetRequestContext(
uint32 request_id,
diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc
index 0b25845..07ad263 100644
--- a/chrome/browser/gpu_process_host_ui_shim.cc
+++ b/chrome/browser/gpu_process_host_ui_shim.cc
@@ -67,3 +67,10 @@ void GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
router_.RouteMessage(message);
}
+void GpuProcessHostUIShim::CollectGraphicsInfoAsynchronously() {
+ DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::IO));
+ ChromeThread::PostTask(
+ ChromeThread::IO,
+ FROM_HERE,
+ new SendOnIOThreadTask(new GpuMsg_CollectGraphicsInfo()));
+}
diff --git a/chrome/browser/gpu_process_host_ui_shim.h b/chrome/browser/gpu_process_host_ui_shim.h
index 70696ca..3e5d93b 100644
--- a/chrome/browser/gpu_process_host_ui_shim.h
+++ b/chrome/browser/gpu_process_host_ui_shim.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
#define CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
+#pragma once
// This class lives on the UI thread and supports classes like the
// BackingStoreProxy, which must live on the UI thread. The IO thread
@@ -41,6 +42,10 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
void AddRoute(int32 routing_id, IPC::Channel::Listener* listener);
void RemoveRoute(int32 routing_id);
+ // Sends a message to the browser process to collect the information from the
+ // graphics card.
+ void CollectGraphicsInfoAsynchronously();
+
private:
friend struct DefaultSingletonTraits<GpuProcessHostUIShim>;
diff --git a/chrome/browser/gtk/about_chrome_dialog.cc b/chrome/browser/gtk/about_chrome_dialog.cc
index f9cdbe5..29f9159 100644
--- a/chrome/browser/gtk/about_chrome_dialog.cc
+++ b/chrome/browser/gtk/about_chrome_dialog.cc
@@ -11,7 +11,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "base/file_version_info.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
@@ -107,18 +107,16 @@ gboolean OnEventBoxExpose(GtkWidget* event_box,
void ShowAboutDialogForProfile(GtkWindow* parent, Profile* profile) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
static GdkPixbuf* background = rb.GetPixbufNamed(IDR_ABOUT_BACKGROUND);
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- std::wstring current_version = version_info->file_version();
+ chrome::VersionInfo version_info;
+ std::string current_version = version_info.Version();
#if !defined(GOOGLE_CHROME_BUILD)
- current_version += L" (";
- current_version += version_info->last_change();
- current_version += L")";
+ current_version += " (";
+ current_version += version_info.LastChange();
+ current_version += ")";
#endif
- string16 version_modifier = platform_util::GetVersionStringModifier();
- if (version_modifier.length()) {
- current_version += L" ";
- current_version += UTF16ToWide(version_modifier);
- }
+ std::string channel = platform_util::GetVersionStringModifier();
+ if (!channel.empty())
+ current_version += " " + channel;
// Build the dialog.
GtkWidget* dialog = gtk_dialog_new_with_buttons(
@@ -158,7 +156,7 @@ void ShowAboutDialogForProfile(GtkWindow* parent, Profile* profile) {
gtk_widget_modify_fg(product_label, GTK_STATE_NORMAL, &black);
gtk_box_pack_start(GTK_BOX(text_vbox), product_label, FALSE, FALSE, 0);
- GtkWidget* version_label = gtk_label_new(WideToUTF8(current_version).c_str());
+ GtkWidget* version_label = gtk_label_new(current_version.c_str());
gtk_misc_set_alignment(GTK_MISC(version_label), 0.0, 0.5);
gtk_label_set_selectable(GTK_LABEL(version_label), TRUE);
gtk_widget_modify_fg(version_label, GTK_STATE_NORMAL, &black);
diff --git a/chrome/browser/gtk/about_chrome_dialog.h b/chrome/browser/gtk/about_chrome_dialog.h
index 5f1f8d3..020e3e5 100644
--- a/chrome/browser/gtk/about_chrome_dialog.h
+++ b/chrome/browser/gtk/about_chrome_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_ABOUT_CHROME_DIALOG_H_
#define CHROME_BROWSER_GTK_ABOUT_CHROME_DIALOG_H_
+#pragma once
class Profile;
typedef struct _GtkWindow GtkWindow;
diff --git a/chrome/browser/gtk/accelerators_gtk.cc b/chrome/browser/gtk/accelerators_gtk.cc
index 3bd670e..f73d03a 100644
--- a/chrome/browser/gtk/accelerators_gtk.cc
+++ b/chrome/browser/gtk/accelerators_gtk.cc
@@ -123,6 +123,7 @@ const struct AcceleratorMapping {
{ GDK_r, IDC_RELOAD_IGNORING_CACHE,
GdkModifierType(GDK_CONTROL_MASK|GDK_SHIFT_MASK) },
{ GDK_F5, IDC_RELOAD, GdkModifierType(0) },
+ { GDK_F5, IDC_RELOAD_IGNORING_CACHE, GDK_CONTROL_MASK },
{ GDK_F5, IDC_RELOAD_IGNORING_CACHE, GDK_SHIFT_MASK },
{ XF86XK_Reload, IDC_RELOAD, GdkModifierType(0) },
{ XF86XK_Refresh, IDC_RELOAD, GdkModifierType(0) },
diff --git a/chrome/browser/gtk/accelerators_gtk.h b/chrome/browser/gtk/accelerators_gtk.h
index 677caea..de08f91 100644
--- a/chrome/browser/gtk/accelerators_gtk.h
+++ b/chrome/browser/gtk/accelerators_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_ACCELERATORS_GTK_H_
#define CHROME_BROWSER_GTK_ACCELERATORS_GTK_H_
+#pragma once
#include "app/menus/accelerator_gtk.h"
#include "base/hash_tables.h"
diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.cc b/chrome/browser/gtk/accessibility_event_router_gtk.cc
index 606fd40..6d04cbd 100644
--- a/chrome/browser/gtk/accessibility_event_router_gtk.cc
+++ b/chrome/browser/gtk/accessibility_event_router_gtk.cc
@@ -12,6 +12,12 @@
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/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"
+#endif
namespace {
@@ -210,6 +216,20 @@ void AccessibilityEventRouterGtk::InstallEventListener(
installed_hooks_.push_back(InstalledHook(signal_id, hook_id));
}
+bool AccessibilityEventRouterGtk::IsPassword(GtkWidget* widget) {
+ bool is_password = false;
+#if defined (TOOLKIT_VIEWS)
+ is_password = (GTK_IS_ENTRY(widget) &&
+ GTK_VIEWS_ENTRY(widget)->host != NULL &&
+ GTK_VIEWS_ENTRY(widget)->host->IsPassword()) ||
+ (GTK_IS_TEXT_VIEW(widget) &&
+ GTK_VIEWS_TEXTVIEW(widget)->host != NULL &&
+ GTK_VIEWS_TEXTVIEW(widget)->host->IsPassword());
+#endif
+ return is_password;
+}
+
+
void AccessibilityEventRouterGtk::InstallEventListeners() {
// Create and destroy each type of widget we need signals for,
// to ensure their modules are loaded, otherwise g_signal_lookup
@@ -325,6 +345,12 @@ void AccessibilityEventRouterGtk::StopListening() {
void AccessibilityEventRouterGtk::DispatchAccessibilityNotification(
GtkWidget* widget, NotificationType type) {
+ // If there's no message loop, we must be about to shutdown or we're
+ // running inside a test; either way, there's no reason to do any
+ // further processing.
+ if (!MessageLoop::current())
+ return;
+
if (!listening_)
return;
@@ -405,6 +431,9 @@ void AccessibilityEventRouterGtk::DispatchAccessibilityNotification(
void AccessibilityEventRouterGtk::PostDispatchAccessibilityNotification(
GtkWidget* widget, NotificationType type) {
+ if (!MessageLoop::current())
+ return;
+
MessageLoop::current()->PostTask(
FROM_HERE, method_factory_.NewRunnableMethod(
&AccessibilityEventRouterGtk::DispatchAccessibilityNotification,
@@ -467,7 +496,7 @@ void AccessibilityEventRouterGtk::SendEntryNotification(
gint start_pos;
gint end_pos;
gtk_editable_get_selection_bounds(GTK_EDITABLE(widget), &start_pos, &end_pos);
- AccessibilityTextBoxInfo info(profile, name, false);
+ AccessibilityTextBoxInfo info(profile, name, IsPassword(widget));
info.SetValue(value, start_pos, end_pos);
SendAccessibilityNotification(type, &info);
}
@@ -485,7 +514,7 @@ void AccessibilityEventRouterGtk::SendTextViewNotification(
gtk_text_buffer_get_selection_bounds(buffer, &sel_start, &sel_end);
int start_pos = gtk_text_iter_get_offset(&sel_start);
int end_pos = gtk_text_iter_get_offset(&sel_end);
- AccessibilityTextBoxInfo info(profile, name, false);
+ AccessibilityTextBoxInfo info(profile, name, IsPassword(widget));
info.SetValue(value, start_pos, end_pos);
SendAccessibilityNotification(type, &info);
}
diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.h b/chrome/browser/gtk/accessibility_event_router_gtk.h
index ecb9b78..e260937 100644
--- a/chrome/browser/gtk/accessibility_event_router_gtk.h
+++ b/chrome/browser/gtk/accessibility_event_router_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_ACCESSIBILITY_EVENT_ROUTER_GTK_H_
#define CHROME_BROWSER_GTK_ACCESSIBILITY_EVENT_ROUTER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -17,6 +18,11 @@
#include "chrome/browser/accessibility_events.h"
class Profile;
+#if defined (TOOLKIT_VIEWS)
+namespace views {
+class NativeTextfieldGtk;
+}
+#endif
// Allows us to use (GtkWidget*) in a hash_map with gcc.
namespace __gnu_cxx {
@@ -132,6 +138,7 @@ class AccessibilityEventRouterGtk {
void SendTextViewNotification(
GtkWidget* widget, NotificationType type, Profile* profile);
+ bool IsPassword(GtkWidget* widget);
void InstallEventListeners();
void RemoveEventListeners();
diff --git a/chrome/browser/gtk/accessible_widget_helper_gtk.h b/chrome/browser/gtk/accessible_widget_helper_gtk.h
index fdd244d..3713dd9 100644
--- a/chrome/browser/gtk/accessible_widget_helper_gtk.h
+++ b/chrome/browser/gtk/accessible_widget_helper_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_ACCESSIBLE_WIDGET_HELPER_GTK_H_
#define CHROME_BROWSER_GTK_ACCESSIBLE_WIDGET_HELPER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/back_forward_button_gtk.cc b/chrome/browser/gtk/back_forward_button_gtk.cc
index 3519502..d5a7f55 100644
--- a/chrome/browser/gtk/back_forward_button_gtk.cc
+++ b/chrome/browser/gtk/back_forward_button_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.
@@ -7,7 +7,6 @@
#include <gtk/gtk.h>
#include "app/l10n_util.h"
-#include "app/menus/menu_model.h"
#include "base/message_loop.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/back_forward_menu_model.h"
@@ -26,36 +25,31 @@ BackForwardButtonGtk::BackForwardButtonGtk(Browser* browser, bool is_forward)
: browser_(browser),
is_forward_(is_forward),
show_menu_factory_(this) {
- int normal, active, highlight, depressed, background, tooltip;
+ int normal, pushed, hover, disabled, tooltip;
const char* stock;
if (is_forward) {
normal = IDR_FORWARD;
- active = IDR_FORWARD_P;
- highlight = IDR_FORWARD_H;
- depressed = IDR_FORWARD_D;
- background = IDR_FORWARD_MASK;
+ pushed = IDR_FORWARD_P;
+ hover = IDR_FORWARD_H;
+ disabled = IDR_FORWARD_D;
tooltip = IDS_TOOLTIP_FORWARD;
stock = GTK_STOCK_GO_FORWARD;
} else {
normal = IDR_BACK;
- active = IDR_BACK_P;
- highlight = IDR_BACK_H;
- depressed = IDR_BACK_D;
- background = IDR_BACK_MASK;
+ pushed = IDR_BACK_P;
+ hover = IDR_BACK_H;
+ disabled = IDR_BACK_D;
tooltip = IDS_TOOLTIP_BACK;
stock = GTK_STOCK_GO_BACK;
}
button_.reset(new CustomDrawButton(
GtkThemeProvider::GetFrom(browser_->profile()),
- normal, active, highlight, depressed, background, stock,
- GTK_ICON_SIZE_SMALL_TOOLBAR));
+ normal, pushed, hover, disabled, stock, GTK_ICON_SIZE_SMALL_TOOLBAR));
gtk_widget_set_tooltip_text(widget(),
l10n_util::GetStringUTF8(tooltip).c_str());
- menu_model_.reset(
- new BackForwardMenuModel(browser,
- is_forward ?
- BackForwardMenuModel::FORWARD_MENU :
- BackForwardMenuModel::BACKWARD_MENU));
+ menu_model_.reset(new BackForwardMenuModel(browser, is_forward ?
+ BackForwardMenuModel::FORWARD_MENU :
+ BackForwardMenuModel::BACKWARD_MENU));
g_signal_connect(widget(), "clicked",
G_CALLBACK(OnClickThunk), this);
@@ -138,4 +132,3 @@ gboolean BackForwardButtonGtk::OnMouseMove(GtkWidget* widget,
ShowBackForwardMenu();
return FALSE;
}
-
diff --git a/chrome/browser/gtk/back_forward_button_gtk.h b/chrome/browser/gtk/back_forward_button_gtk.h
index 3439a75..f32b5bb 100644
--- a/chrome/browser/gtk/back_forward_button_gtk.h
+++ b/chrome/browser/gtk/back_forward_button_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_H_
#define CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc
index 7f9f978..3beb559 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk.cc
@@ -7,13 +7,12 @@
#include <vector>
#include "app/gtk_dnd_util.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "app/text_elider.h"
-#include "base/pickle.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/bookmark_menu_controller_gtk.h"
#include "chrome/browser/gtk/bookmark_tree_model.h"
@@ -34,7 +33,7 @@
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/ntp_background_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -66,7 +65,7 @@ const int kNTPRoundedness = 3;
// The height of the bar when it is "hidden". It is usually not completely
// hidden because even when it is closed it forms the bottom few pixels of
// the toolbar.
-const int kBookmarkBarMinimumHeight = 4;
+const int kBookmarkBarMinimumHeight = 3;
// Left-padding for the instructional text.
const int kInstructionsPadding = 6;
@@ -245,7 +244,7 @@ void BookmarkBarGtk::Init(Profile* profile) {
g_object_set_data(G_OBJECT(overflow_button_), "left-align-popup",
reinterpret_cast<void*>(true));
SetOverflowButtonAppearance();
- ConnectFolderButtonEvents(overflow_button_);
+ ConnectFolderButtonEvents(overflow_button_, false);
gtk_box_pack_start(GTK_BOX(bookmark_hbox_), overflow_button_,
FALSE, FALSE, 0);
@@ -255,7 +254,7 @@ void BookmarkBarGtk::Init(Profile* profile) {
g_signal_connect(bookmark_toolbar_.get(), "drag-motion",
G_CALLBACK(&OnToolbarDragMotionThunk), this);
g_signal_connect(bookmark_toolbar_.get(), "drag-leave",
- G_CALLBACK(&OnToolbarDragLeaveThunk), this);
+ G_CALLBACK(&OnDragLeaveThunk), this);
g_signal_connect(bookmark_toolbar_.get(), "drag-data-received",
G_CALLBACK(&OnDragReceivedThunk), this);
@@ -266,7 +265,7 @@ void BookmarkBarGtk::Init(Profile* profile) {
// We pack the button manually (rather than using gtk_button_set_*) so that
// we can have finer control over its label.
other_bookmarks_button_ = theme_provider_->BuildChromeButton();
- ConnectFolderButtonEvents(other_bookmarks_button_);
+ ConnectFolderButtonEvents(other_bookmarks_button_, false);
GtkWidget* other_padding = gtk_alignment_new(0, 0, 1, 1);
gtk_alignment_set_padding(GTK_ALIGNMENT(other_padding),
kOtherBookmarksPaddingVertical,
@@ -413,7 +412,8 @@ void BookmarkBarGtk::Loaded(BookmarkModel* model) {
void BookmarkBarGtk::BookmarkModelBeingDeleted(BookmarkModel* model) {
// The bookmark model should never be deleted before us. This code exists
// to check for regressions in shutdown code and not crash.
- NOTREACHED();
+ if (!browser_shutdown::ShuttingDownWithoutClosingBrowsers())
+ NOTREACHED();
// Do minimal cleanup, presumably we'll be deleted shortly.
model_->RemoveObserver(this);
@@ -883,7 +883,7 @@ GtkWidget* BookmarkBarGtk::CreateBookmarkButton(const BookmarkNode* node) {
G_CALLBACK(OnClickedThunk), this);
gtk_util::SetButtonTriggersNavigation(button);
} else {
- ConnectFolderButtonEvents(button);
+ ConnectFolderButtonEvents(button, true);
}
return button;
@@ -901,11 +901,25 @@ GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(const BookmarkNode* node) {
return item;
}
-void BookmarkBarGtk::ConnectFolderButtonEvents(GtkWidget* widget) {
- gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_ALL, NULL, 0, kDragAction);
+void BookmarkBarGtk::ConnectFolderButtonEvents(GtkWidget* widget,
+ bool is_tool_item) {
+ // For toolbar items (i.e. not the overflow button or other bookmarks
+ // button), we handle motion and highlighting manually.
+ gtk_drag_dest_set(widget,
+ is_tool_item ? GTK_DEST_DEFAULT_DROP :
+ GTK_DEST_DEFAULT_ALL,
+ NULL,
+ 0,
+ kDragAction);
gtk_dnd_util::SetDestTargetList(widget, kDestTargetList);
g_signal_connect(widget, "drag-data-received",
G_CALLBACK(&OnDragReceivedThunk), this);
+ if (is_tool_item) {
+ g_signal_connect(widget, "drag-motion",
+ G_CALLBACK(&OnFolderDragMotionThunk), this);
+ g_signal_connect(widget, "drag-leave",
+ G_CALLBACK(&OnDragLeaveThunk), this);
+ }
g_signal_connect(widget, "button-press-event",
G_CALLBACK(OnButtonPressedThunk), this);
@@ -1058,12 +1072,7 @@ void BookmarkBarGtk::OnButtonDragEnd(GtkWidget* button,
gtk_widget_show(button);
gtk_widget_set_no_show_all(button, FALSE);
- if (toolbar_drop_item_) {
- g_object_unref(toolbar_drop_item_);
- toolbar_drop_item_ = NULL;
- gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()),
- NULL, 0);
- }
+ ClearToolbarDropHighlighting();
DCHECK(dragged_node_);
dragged_node_ = NULL;
@@ -1101,13 +1110,11 @@ void BookmarkBarGtk::OnFolderClicked(GtkWidget* sender) {
}
}
-gboolean BookmarkBarGtk::OnToolbarDragMotion(GtkWidget* toolbar,
- GdkDragContext* context,
- gint x,
- gint y,
- guint time) {
+gboolean BookmarkBarGtk::ItemDraggedOverToolbar(GdkDragContext* context,
+ int index,
+ guint time) {
GdkAtom target_type =
- gtk_drag_dest_find_target(toolbar, context, NULL);
+ gtk_drag_dest_find_target(bookmark_toolbar_.get(), context, NULL);
if (target_type == GDK_NONE) {
// We shouldn't act like a drop target when something that we can't deal
// with is dragged over the toolbar.
@@ -1128,13 +1135,9 @@ gboolean BookmarkBarGtk::OnToolbarDragMotion(GtkWidget* toolbar,
}
}
- if (toolbar_drop_item_) {
- gint index = gtk_toolbar_get_drop_index(GTK_TOOLBAR(toolbar), x, y);
- gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(toolbar),
- GTK_TOOL_ITEM(toolbar_drop_item_),
- index);
- }
-
+ gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()),
+ GTK_TOOL_ITEM(toolbar_drop_item_),
+ index);
if (target_type ==
gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM)) {
gdk_drag_status(context, GDK_ACTION_MOVE, time);
@@ -1145,15 +1148,75 @@ gboolean BookmarkBarGtk::OnToolbarDragMotion(GtkWidget* toolbar,
return TRUE;
}
-void BookmarkBarGtk::OnToolbarDragLeave(GtkWidget* toolbar,
- GdkDragContext* context,
- guint time) {
+gboolean BookmarkBarGtk::OnToolbarDragMotion(GtkWidget* toolbar,
+ GdkDragContext* context,
+ gint x,
+ gint y,
+ guint time) {
+ gint index = gtk_toolbar_get_drop_index(GTK_TOOLBAR(toolbar), x, y);
+ return ItemDraggedOverToolbar(context, index, time);
+}
+
+int BookmarkBarGtk::GetToolbarIndexForDragOverFolder(
+ GtkWidget* button, gint x) {
+ int margin = std::min(15, static_cast<int>(0.3 * button->allocation.width));
+ if (x > margin && x < (button->allocation.width - margin))
+ return -1;
+
+ gint index = gtk_toolbar_get_item_index(GTK_TOOLBAR(bookmark_toolbar_.get()),
+ GTK_TOOL_ITEM(button->parent));
+ if (x > margin)
+ index++;
+ return index;
+}
+
+gboolean BookmarkBarGtk::OnFolderDragMotion(GtkWidget* button,
+ GdkDragContext* context,
+ gint x,
+ gint y,
+ guint time) {
+ GdkAtom target_type = gtk_drag_dest_find_target(button, context, NULL);
+ if (target_type == GDK_NONE)
+ return FALSE;
+
+ int index = GetToolbarIndexForDragOverFolder(button, x);
+ if (index < 0) {
+ ClearToolbarDropHighlighting();
+
+ // Drag is over middle of folder.
+ gtk_drag_highlight(button);
+ if (target_type ==
+ gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM)) {
+ gdk_drag_status(context, GDK_ACTION_MOVE, time);
+ } else {
+ gdk_drag_status(context, GDK_ACTION_COPY, time);
+ }
+
+ return TRUE;
+ }
+
+ // Remove previous highlighting.
+ gtk_drag_unhighlight(button);
+ return ItemDraggedOverToolbar(context, index, time);
+}
+
+void BookmarkBarGtk::ClearToolbarDropHighlighting() {
if (toolbar_drop_item_) {
g_object_unref(toolbar_drop_item_);
toolbar_drop_item_ = NULL;
}
- gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(toolbar), NULL, 0);
+ gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()),
+ NULL, 0);
+}
+
+void BookmarkBarGtk::OnDragLeave(GtkWidget* sender,
+ GdkDragContext* context,
+ guint time) {
+ if (GTK_IS_BUTTON(sender))
+ gtk_drag_unhighlight(sender);
+
+ ClearToolbarDropHighlighting();
}
void BookmarkBarGtk::OnToolbarSizeAllocate(GtkWidget* widget,
@@ -1179,18 +1242,20 @@ void BookmarkBarGtk::OnDragReceived(GtkWidget* widget,
gboolean dnd_success = FALSE;
gboolean delete_selection_data = FALSE;
- const BookmarkNode* dest_node;
+ const BookmarkNode* dest_node = model_->GetBookmarkBarNode();
gint index;
if (widget == bookmark_toolbar_.get()) {
- dest_node = model_->GetBookmarkBarNode();
index = gtk_toolbar_get_drop_index(
GTK_TOOLBAR(bookmark_toolbar_.get()), x, y);
} else if (widget == instructions_) {
dest_node = model_->GetBookmarkBarNode();
index = 0;
} else {
- dest_node = GetNodeForToolButton(widget);
- index = dest_node->GetChildCount();
+ index = GetToolbarIndexForDragOverFolder(widget, x);
+ if (index < 0) {
+ dest_node = GetNodeForToolButton(widget);
+ index = dest_node->GetChildCount();
+ }
}
switch (target_type) {
@@ -1233,7 +1298,7 @@ void BookmarkBarGtk::OnDragReceived(GtkWidget* widget,
if (!url.is_valid())
break;
std::string title = bookmark_utils::GetNameForURL(url);
- model_->AddURL(dest_node, index, UTF8ToWide(title), url);
+ model_->AddURL(dest_node, index, UTF8ToUTF16(title), url);
dnd_success = TRUE;
break;
}
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.h b/chrome/browser/gtk/bookmark_bar_gtk.h
index b00d61a..2e7f985 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.h
+++ b/chrome/browser/gtk/bookmark_bar_gtk.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_BOOKMARK_BAR_GTK_H_
#define CHROME_BROWSER_GTK_BOOKMARK_BAR_GTK_H_
+#pragma once
#include <gtk/gtk.h>
-#include <string>
#include <vector>
#include "app/gtk_signal.h"
@@ -18,11 +18,11 @@
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
#include "chrome/browser/gtk/bookmark_bar_instructions_gtk.h"
#include "chrome/browser/gtk/menu_bar_helper.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/gtk/view_id_util.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/point.h"
#include "gfx/size.h"
@@ -172,6 +172,20 @@ class BookmarkBarGtk : public AnimationDelegate,
// |throbbing_widget_| doesn't become stale.
void SetThrobbingWidget(GtkWidget* widget);
+ // An item has been dragged over the toolbar, update the drag context
+ // and toolbar UI appropriately.
+ gboolean ItemDraggedOverToolbar(
+ GdkDragContext* context, int index, guint time);
+
+ // When dragging in the middle of a folder, assume the user wants to drop
+ // on the folder. Towards the edges, assume the user wants to drop on the
+ // toolbar. This makes it possible to drop between two folders. This function
+ // returns the index on the toolbar the drag should target, or -1 if the
+ // drag should hit the folder.
+ int GetToolbarIndexForDragOverFolder(GtkWidget* button, gint x);
+
+ void ClearToolbarDropHighlighting();
+
// Overridden from BookmarkModelObserver:
// Invoked when the bookmark model has finished loading. Creates a button
@@ -210,7 +224,7 @@ class BookmarkBarGtk : public AnimationDelegate,
GtkWidget* CreateBookmarkButton(const BookmarkNode* node);
GtkToolItem* CreateBookmarkToolItem(const BookmarkNode* node);
- void ConnectFolderButtonEvents(GtkWidget* widget);
+ void ConnectFolderButtonEvents(GtkWidget* widget, bool is_tool_item);
// Finds the BookmarkNode from the model associated with |button|.
const BookmarkNode* GetNodeForToolButton(GtkWidget* button);
@@ -237,8 +251,6 @@ class BookmarkBarGtk : public AnimationDelegate,
// GtkToolbar callbacks.
CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnToolbarDragMotion,
GdkDragContext*, gint, gint, guint);
- CHROMEGTK_CALLBACK_2(BookmarkBarGtk, void, OnToolbarDragLeave,
- GdkDragContext*, guint);
CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnToolbarSizeAllocate,
GtkAllocation*);
@@ -246,6 +258,12 @@ class BookmarkBarGtk : public AnimationDelegate,
CHROMEGTK_CALLBACK_6(BookmarkBarGtk, void, OnDragReceived,
GdkDragContext*, gint, gint, GtkSelectionData*,
guint, guint);
+ CHROMEGTK_CALLBACK_2(BookmarkBarGtk, void, OnDragLeave,
+ GdkDragContext*, guint);
+
+ // Used for folder buttons.
+ CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnFolderDragMotion,
+ GdkDragContext*, gint, gint, guint);
// GtkEventBox callbacks.
CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnEventBoxExpose,
diff --git a/chrome/browser/gtk/bookmark_bar_gtk_interactive_uitest.cc b/chrome/browser/gtk/bookmark_bar_gtk_interactive_uitest.cc
index c04201e..46d38c8 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk_interactive_uitest.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk_interactive_uitest.cc
@@ -7,12 +7,13 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/gtk/view_id_util.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+#include "net/test/test_server.h"
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
const char kSimplePage[] = "404_is_enough_for_us.html";
void OnClicked(GtkWidget* widget, bool* clicked_bit) {
@@ -27,18 +28,19 @@ class BookmarkBarGtkBrowserTest : public InProcessBrowserTest {
// Makes sure that when you switch back to an NTP with an active findbar,
// the findbar is above the floating bookmark bar.
IN_PROC_BROWSER_TEST_F(BookmarkBarGtkBrowserTest, FindBarTest) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server()->Start());
// Create new tab; open findbar.
browser()->NewTab();
browser()->Find();
// Create new tab with an arbitrary URL.
- GURL url = server->TestServerPage(kSimplePage);
+ Browser* browser_used = NULL;
+ GURL url = test_server()->GetURL(kSimplePage);
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
// Switch back to the NTP with the active findbar.
browser()->SelectTabContentsAt(1, false);
@@ -55,9 +57,7 @@ IN_PROC_BROWSER_TEST_F(BookmarkBarGtkBrowserTest, FindBarTest) {
// Makes sure that you can click on the floating bookmark bar.
IN_PROC_BROWSER_TEST_F(BookmarkBarGtkBrowserTest, ClickOnFloatingTest) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server()->Start());
GtkWidget* other_bookmarks =
ViewIDUtil::GetWidget(GTK_WIDGET(browser()->window()->GetNativeHandle()),
diff --git a/chrome/browser/gtk/bookmark_bar_gtk_unittest.cc b/chrome/browser/gtk/bookmark_bar_gtk_unittest.cc
index 59c6172..c74aac8 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk_unittest.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk_unittest.cc
@@ -1,9 +1,11 @@
-// 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.
#include "chrome/browser/gtk/bookmark_bar_gtk.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/gtk/tabstrip_origin_provider.h"
@@ -25,6 +27,9 @@ class BookmarkBarGtkUnittest : public ::testing::Test {
BookmarkBarGtkUnittest()
: ui_thread_(ChromeThread::UI, &message_loop_),
file_thread_(ChromeThread::FILE, &message_loop_) {
+ }
+
+ virtual void SetUp() {
profile_.reset(new TestingProfile());
profile_->CreateBookmarkModel(true);
profile_->BlockUntilBookmarkModelLoaded();
@@ -35,13 +40,22 @@ class BookmarkBarGtkUnittest : public ::testing::Test {
origin_provider_.get()));
}
+ virtual void TearDown() {
+ bookmark_bar_.reset();
+ origin_provider_.reset();
+ browser_.reset();
+ profile_.reset();
+ message_loop_.RunAllPending();
+ }
+
+ MessageLoopForUI message_loop_;
+ ChromeThread ui_thread_;
+ ChromeThread file_thread_;
+
scoped_ptr<TestingProfile> profile_;
scoped_ptr<Browser> browser_;
scoped_ptr<TabstripOriginProvider> origin_provider_;
scoped_ptr<BookmarkBarGtk> bookmark_bar_;
- MessageLoopForUI message_loop_;
- ChromeThread ui_thread_;
- ChromeThread file_thread_;
};
TEST_F(BookmarkBarGtkUnittest, DisplaysHelpMessageOnEmpty) {
@@ -58,7 +72,7 @@ TEST_F(BookmarkBarGtkUnittest, HidesHelpMessageWithBookmark) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
model->AddURL(parent, parent->GetChildCount(),
- L"title", GURL("http://one.com"));
+ ASCIIToUTF16("title"), GURL("http://one.com"));
bookmark_bar_->Loaded(model);
EXPECT_FALSE(bookmark_bar_->show_instructions_);
@@ -69,9 +83,9 @@ TEST_F(BookmarkBarGtkUnittest, BuildsButtons) {
const BookmarkNode* parent = model->GetBookmarkBarNode();
model->AddURL(parent, parent->GetChildCount(),
- L"title", GURL("http://one.com"));
+ ASCIIToUTF16("title"), GURL("http://one.com"));
model->AddURL(parent, parent->GetChildCount(),
- L"other", GURL("http://two.com"));
+ ASCIIToUTF16("other"), GURL("http://two.com"));
bookmark_bar_->Loaded(model);
diff --git a/chrome/browser/gtk/bookmark_bar_instructions_gtk.cc b/chrome/browser/gtk/bookmark_bar_instructions_gtk.cc
index cada10d..8090c06 100644
--- a/chrome/browser/gtk/bookmark_bar_instructions_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_instructions_gtk.cc
@@ -16,23 +16,6 @@
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
-namespace {
-
-// Calculates the real size request of a label and set its ellipsize mode to
-// PANGO_ELLIPSIZE_END.
-// It must be done when the label is mapped (become visible on the screen),
-// to make sure the pango can get correct font information for the calculation.
-void InitLabelSizeRequestAndEllipsizeMode(GtkWidget* label) {
- GtkRequisition size;
- gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_NONE);
- gtk_widget_set_size_request(label, -1, -1);
- gtk_widget_size_request(label, &size);
- gtk_widget_set_size_request(label, size.width, size.height);
- gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
-}
-
-} // namespace
-
BookmarkBarInstructionsGtk::BookmarkBarInstructionsGtk(Delegate* delegate,
Profile* profile)
: delegate_(delegate),
@@ -47,7 +30,7 @@ BookmarkBarInstructionsGtk::BookmarkBarInstructionsGtk(Delegate* delegate,
gtk_util::CenterWidgetInHBox(instructions_hbox_, instructions_label_,
false, 1);
g_signal_connect(instructions_label_, "map",
- G_CALLBACK(InitLabelSizeRequestAndEllipsizeMode),
+ G_CALLBACK(gtk_util::InitLabelSizeRequestAndEllipsizeMode),
NULL);
instructions_link_ = gtk_chrome_link_button_new(
@@ -64,7 +47,7 @@ BookmarkBarInstructionsGtk::BookmarkBarInstructionsGtk(Delegate* delegate,
gtk_util::CenterWidgetInHBox(instructions_hbox_, instructions_link_,
false, 6);
g_signal_connect(GTK_CHROME_LINK_BUTTON(instructions_link_)->label, "map",
- G_CALLBACK(InitLabelSizeRequestAndEllipsizeMode),
+ G_CALLBACK(gtk_util::InitLabelSizeRequestAndEllipsizeMode),
NULL);
registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
diff --git a/chrome/browser/gtk/bookmark_bar_instructions_gtk.h b/chrome/browser/gtk/bookmark_bar_instructions_gtk.h
index ce711e0..b58e507 100644
--- a/chrome/browser/gtk/bookmark_bar_instructions_gtk.h
+++ b/chrome/browser/gtk/bookmark_bar_instructions_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_BOOKMARK_BAR_INSTRUCTIONS_GTK_H_
#define CHROME_BROWSER_GTK_BOOKMARK_BAR_INSTRUCTIONS_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "base/basictypes.h"
@@ -21,6 +22,9 @@ class BookmarkBarInstructionsGtk : public NotificationObserver {
class Delegate {
public:
virtual void ShowImportDialog() = 0;
+
+ protected:
+ virtual ~Delegate() {}
};
explicit BookmarkBarInstructionsGtk(Delegate* delegate, Profile* profile);
diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.cc b/chrome/browser/gtk/bookmark_bubble_gtk.cc
index d573c84..6c57dc0 100644
--- a/chrome/browser/gtk/bookmark_bubble_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bubble_gtk.cc
@@ -7,11 +7,12 @@
#include <gtk/gtk.h>
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
@@ -43,11 +44,6 @@ void BookmarkBubbleGtk::Show(GtkWidget* anchor,
Profile* profile,
const GURL& url,
bool newly_bookmarked) {
- // TODO(deanm): The Views code deals with the possibility of a bubble already
- // being open, and then it just does nothing. I am not sure how this could
- // happen with the style of our GTK bubble since it has a grab. I would also
- // think that closing the previous bubble and opening the new one would make
- // more sense, but I guess then you would commit the bubble's changes.
DCHECK(!g_bubble);
g_bubble = new BookmarkBubbleGtk(anchor, profile, url, newly_bookmarked);
}
@@ -277,10 +273,8 @@ void BookmarkBubbleGtk::ApplyEdits() {
BookmarkModel* model = profile_->GetBookmarkModel();
const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
if (node) {
- // NOTE: Would be nice to save a strlen and use gtk_entry_get_text_length,
- // but it is fairly new and not always in our GTK version.
- const std::wstring new_title(
- UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(name_entry_))));
+ const string16 new_title(
+ UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(name_entry_))));
if (new_title != node->GetTitle()) {
model->SetTitle(node, new_title);
@@ -312,7 +306,7 @@ std::string BookmarkBubbleGtk::GetTitle() {
return std::string();
}
- return WideToUTF8(node->GetTitle());
+ return UTF16ToUTF8(node->GetTitle());
}
void BookmarkBubbleGtk::ShowEditor() {
@@ -345,7 +339,7 @@ void BookmarkBubbleGtk::InitFolderComboModel() {
// the 'Select another folder...' entry that opens the bookmark editor.
for (int i = 0; i < folder_combo_model_->GetItemCount(); ++i) {
gtk_combo_box_append_text(GTK_COMBO_BOX(folder_combo_),
- WideToUTF8(folder_combo_model_->GetItemAt(i)).c_str());
+ UTF16ToUTF8(folder_combo_model_->GetItemAt(i)).c_str());
}
gtk_combo_box_set_active(GTK_COMBO_BOX(folder_combo_),
diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.h b/chrome/browser/gtk/bookmark_bubble_gtk.h
index c58b224..6c7de88 100644
--- a/chrome/browser/gtk/bookmark_bubble_gtk.h
+++ b/chrome/browser/gtk/bookmark_bubble_gtk.h
@@ -11,6 +11,7 @@
#ifndef CHROME_BROWSER_GTK_BOOKMARK_BUBBLE_GTK_H_
#define CHROME_BROWSER_GTK_BOOKMARK_BUBBLE_GTK_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/gtk/bookmark_editor_gtk.cc b/chrome/browser/gtk/bookmark_editor_gtk.cc
index 318ba91..5aafc6c 100644
--- a/chrome/browser/gtk/bookmark_editor_gtk.cc
+++ b/chrome/browser/gtk/bookmark_editor_gtk.cc
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/gtk/bookmark_tree_model.h"
@@ -131,10 +132,9 @@ void BookmarkEditorGtk::Init(GtkWindow* parent_window) {
name_entry_ = gtk_entry_new();
std::string title;
if (details_.type == EditDetails::EXISTING_NODE) {
- title = WideToUTF8(details_.existing_node->GetTitle());
+ title = UTF16ToUTF8(details_.existing_node->GetTitle());
} else if (details_.type == EditDetails::NEW_FOLDER) {
- title = WideToUTF8(
- l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME));
+ title = l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
}
gtk_entry_set_text(GTK_ENTRY(name_entry_), title.c_str());
g_signal_connect(name_entry_, "changed",
@@ -282,8 +282,8 @@ GURL BookmarkEditorGtk::GetInputURL() const {
std::string());
}
-std::wstring BookmarkEditorGtk::GetInputTitle() const {
- return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(name_entry_)));
+string16 BookmarkEditorGtk::GetInputTitle() const {
+ return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(name_entry_)));
}
void BookmarkEditorGtk::ApplyEdits() {
@@ -308,7 +308,7 @@ void BookmarkEditorGtk::ApplyEdits(GtkTreeIter* selected_parent) {
bb_model_->RemoveObserver(this);
GURL new_url(GetInputURL());
- std::wstring new_title(GetInputTitle());
+ string16 new_title(GetInputTitle());
if (!show_tree_ || !selected_parent) {
bookmark_utils::ApplyEditsWithNoGroupChange(
diff --git a/chrome/browser/gtk/bookmark_editor_gtk.h b/chrome/browser/gtk/bookmark_editor_gtk.h
index af9a984..fda8769 100644
--- a/chrome/browser/gtk/bookmark_editor_gtk.h
+++ b/chrome/browser/gtk/bookmark_editor_gtk.h
@@ -1,15 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_BOOKMARK_EDITOR_GTK_H_
#define CHROME_BROWSER_GTK_BOOKMARK_EDITOR_GTK_H_
-
-#include <string>
+#pragma once
#include "app/gtk_integers.h"
#include "app/gtk_signal.h"
#include "base/gtest_prod_util.h"
+#include "base/string16.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
@@ -78,7 +78,7 @@ class BookmarkEditorGtk : public BookmarkEditor,
GURL GetInputURL() const;
// Returns the title the user has input.
- std::wstring GetInputTitle() const;
+ string16 GetInputTitle() const;
// Invokes ApplyEdits with the selected node.
//
diff --git a/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc b/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc
index 8eba11a..291f66f 100644
--- a/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc
+++ b/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc
@@ -1,15 +1,16 @@
-// 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 <gtk/gtk.h>
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/gtk/bookmark_editor_gtk.h"
#include "chrome/browser/gtk/bookmark_tree_model.h"
-#include "chrome/browser/pref_service.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"
@@ -75,21 +76,21 @@ class BookmarkEditorGtkTest : public testing::Test {
void AddTestData() {
std::string test_base = base_path();
- model_->AddURL(model_->GetBookmarkBarNode(), 0, L"a",
+ model_->AddURL(model_->GetBookmarkBarNode(), 0, ASCIIToUTF16("a"),
GURL(test_base + "a"));
const BookmarkNode* f1 =
- model_->AddGroup(model_->GetBookmarkBarNode(), 1, L"F1");
- model_->AddURL(f1, 0, L"f1a", GURL(test_base + "f1a"));
- const BookmarkNode* f11 = model_->AddGroup(f1, 1, L"F11");
- model_->AddURL(f11, 0, L"f11a", GURL(test_base + "f11a"));
- model_->AddGroup(model_->GetBookmarkBarNode(), 2, L"F2");
+ model_->AddGroup(model_->GetBookmarkBarNode(), 1, ASCIIToUTF16("F1"));
+ model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
+ const BookmarkNode* f11 = model_->AddGroup(f1, 1, ASCIIToUTF16("F11"));
+ model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 2, ASCIIToUTF16("F2"));
// Children of the other node.
- model_->AddURL(model_->other_node(), 0, L"oa",
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
GURL(test_base + "oa"));
const BookmarkNode* of1 =
- model_->AddGroup(model_->other_node(), 1, L"OF1");
- model_->AddURL(of1, 0, L"of1a", GURL(test_base + "of1a"));
+ model_->AddGroup(model_->other_node(), 1, ASCIIToUTF16("OF1"));
+ model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a"));
}
};
@@ -115,21 +116,21 @@ TEST_F(BookmarkEditorGtkTest, ModelsMatch) {
ASSERT_EQ(2, gtk_tree_model_iter_n_children(store, &bookmark_bar_node));
ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &bookmark_bar_node));
f1_iter = child;
- ASSERT_EQ(L"F1", GetTitleFromTreeIter(store, &child));
+ ASSERT_EQ("F1", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
ASSERT_TRUE(gtk_tree_model_iter_next(store, &child));
- ASSERT_EQ(L"F2", GetTitleFromTreeIter(store, &child));
+ ASSERT_EQ("F2", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
ASSERT_FALSE(gtk_tree_model_iter_next(store, &child));
// F1 should have one child, F11
ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &f1_iter));
ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &f1_iter));
- ASSERT_EQ(L"F11", GetTitleFromTreeIter(store, &child));
+ ASSERT_EQ("F11", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
ASSERT_FALSE(gtk_tree_model_iter_next(store, &child));
// Other node should have one child (OF1).
ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &other_node));
ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &other_node));
- ASSERT_EQ(L"OF1", GetTitleFromTreeIter(store, &child));
+ ASSERT_EQ("OF1", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
ASSERT_FALSE(gtk_tree_model_iter_next(store, &child));
}
@@ -147,7 +148,7 @@ TEST_F(BookmarkEditorGtkTest, EditTitleKeepsPosition) {
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
- ASSERT_EQ(L"new_a", bb_node->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("new_a"), bb_node->GetChild(0)->GetTitle());
// The URL shouldn't have changed.
ASSERT_TRUE(GURL(base_path() + "a") == bb_node->GetChild(0)->GetURL());
}
@@ -168,7 +169,7 @@ TEST_F(BookmarkEditorGtkTest, EditURLKeepsPosition) {
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
- ASSERT_EQ(L"a", bb_node->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), bb_node->GetChild(0)->GetTitle());
// The URL should have changed.
ASSERT_TRUE(GURL(base_path() + "new_a") == bb_node->GetChild(0)->GetURL());
ASSERT_TRUE(node_time == bb_node->GetChild(0)->date_added());
@@ -187,7 +188,7 @@ TEST_F(BookmarkEditorGtkTest, ChangeParent) {
editor.ApplyEdits(&gtk_other_node);
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
- ASSERT_EQ(L"a", other_node->GetChild(2)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
ASSERT_TRUE(GURL(base_path() + "a") == other_node->GetChild(2)->GetURL());
}
@@ -209,7 +210,7 @@ TEST_F(BookmarkEditorGtkTest, ChangeParentAndURL) {
editor.ApplyEdits(&gtk_other_node);
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
- ASSERT_EQ(L"a", other_node->GetChild(2)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
ASSERT_TRUE(GURL(base_path() + "new_a") == other_node->GetChild(2)->GetURL());
ASSERT_TRUE(node_time == other_node->GetChild(2)->date_added());
}
@@ -252,14 +253,14 @@ TEST_F(BookmarkEditorGtkTest, MoveToNewParent) {
// F2 in the model should have two children now: F21 and the node edited.
ASSERT_EQ(2, mf2->GetChildCount());
// F21 should be first.
- ASSERT_EQ(L"F21", mf2->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F21"), mf2->GetChild(0)->GetTitle());
// Then a.
- ASSERT_EQ(L"a", mf2->GetChild(1)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), mf2->GetChild(1)->GetTitle());
// F21 should have one child, F211.
const BookmarkNode* mf21 = mf2->GetChild(0);
ASSERT_EQ(1, mf21->GetChildCount());
- ASSERT_EQ(L"F211", mf21->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F211"), mf21->GetChild(0)->GetTitle());
}
// Brings up the editor, creating a new URL on the bookmark bar.
@@ -282,7 +283,7 @@ TEST_F(BookmarkEditorGtkTest, NewURL) {
ASSERT_EQ(4, bb_node->GetChildCount());
const BookmarkNode* new_node = bb_node->GetChild(3);
- EXPECT_EQ(L"new_a", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
EXPECT_TRUE(GURL(base_path() + "a") == new_node->GetURL());
}
@@ -304,7 +305,7 @@ TEST_F(BookmarkEditorGtkTest, ChangeURLNoTree) {
const BookmarkNode* new_node = other_node->GetChild(0);
- EXPECT_EQ(L"new_a", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
EXPECT_TRUE(GURL(base_path() + "a") == new_node->GetURL());
}
@@ -322,5 +323,5 @@ TEST_F(BookmarkEditorGtkTest, ChangeTitleNoTree) {
ASSERT_EQ(2, other_node->GetChildCount());
const BookmarkNode* new_node = other_node->GetChild(0);
- EXPECT_EQ(L"new_a", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
}
diff --git a/chrome/browser/gtk/bookmark_menu_controller_gtk.cc b/chrome/browser/gtk/bookmark_menu_controller_gtk.cc
index e9395f2..f966719 100644
--- a/chrome/browser/gtk/bookmark_menu_controller_gtk.cc
+++ b/chrome/browser/gtk/bookmark_menu_controller_gtk.cc
@@ -8,8 +8,8 @@
#include "app/gtk_dnd_util.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
@@ -147,10 +147,11 @@ void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
// This breaks on word boundaries. Ideally we would break on character
// boundaries.
- std::wstring elided_name =
- l10n_util::TruncateString(node->GetTitle(), kMaxChars);
+ std::string elided_name = WideToUTF8(
+ l10n_util::TruncateString(UTF16ToWideHack(node->GetTitle()),
+ kMaxChars));
GtkWidget* menu_item =
- gtk_image_menu_item_new_with_label(WideToUTF8(elided_name).c_str());
+ gtk_image_menu_item_new_with_label(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_menu_controller_gtk.h b/chrome/browser/gtk/bookmark_menu_controller_gtk.h
index cf0a512..21f2bb9 100644
--- a/chrome/browser/gtk/bookmark_menu_controller_gtk.h
+++ b/chrome/browser/gtk/bookmark_menu_controller_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_BOOKMARK_MENU_CONTROLLER_GTK_H_
#define CHROME_BROWSER_GTK_BOOKMARK_MENU_CONTROLLER_GTK_H_
+#pragma once
#include <map>
@@ -12,7 +13,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
#include "chrome/browser/bookmarks/bookmark_context_menu_controller.h"
-#include "chrome/common/owned_widget_gtk.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "webkit/glue/window_open_disposition.h"
class Browser;
diff --git a/chrome/browser/gtk/bookmark_tree_model.cc b/chrome/browser/gtk/bookmark_tree_model.cc
index 2a9c449..d6ef4de 100644
--- a/chrome/browser/gtk/bookmark_tree_model.cc
+++ b/chrome/browser/gtk/bookmark_tree_model.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.
@@ -6,8 +6,8 @@
#include <gtk/gtk.h>
-#include "app/resource_bundle.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
@@ -26,7 +26,8 @@ void AddSingleNodeToTreeStore(GtkTreeStore* store, const BookmarkNode* node,
// differently).
gtk_tree_store_set(store, iter,
bookmark_utils::FOLDER_ICON, GtkThemeProvider::GetFolderIcon(true),
- bookmark_utils::FOLDER_NAME, WideToUTF8(node->GetTitle()).c_str(),
+ bookmark_utils::FOLDER_NAME,
+ UTF16ToUTF8(node->GetTitle()).c_str(),
bookmark_utils::ITEM_ID, node->id(),
// We don't want to use node->is_folder() because that would let the
// user edit "Bookmarks Bar" and "Other Bookmarks".
@@ -50,7 +51,7 @@ void RecursiveResolve(BookmarkModel* bb_model, const BookmarkNode* bb_node,
if (gtk_tree_model_iter_children(tree_model, &child_iter, parent_iter)) {
do {
int64 id = bookmark_utils::GetIdFromTreeIter(tree_model, &child_iter);
- std::wstring title =
+ string16 title =
bookmark_utils::GetTitleFromTreeIter(tree_model, &child_iter);
const BookmarkNode* child_bb_node = NULL;
if (id == 0) {
@@ -212,13 +213,13 @@ int64 GetIdFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter) {
return ret_val;
}
-std::wstring GetTitleFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter) {
+string16 GetTitleFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter) {
GValue value = { 0, };
- std::wstring ret_val;
+ string16 ret_val;
gtk_tree_model_get_value(model, iter, FOLDER_NAME, &value);
if (G_VALUE_HOLDS_STRING(&value)) {
const gchar* utf8str = g_value_get_string(&value);
- ret_val = UTF8ToWide(utf8str);
+ ret_val = UTF8ToUTF16(utf8str);
g_value_unset(&value);
} else {
NOTREACHED() << "Impossible type mismatch";
diff --git a/chrome/browser/gtk/bookmark_tree_model.h b/chrome/browser/gtk/bookmark_tree_model.h
index 80b1984..1d28fbd 100644
--- a/chrome/browser/gtk/bookmark_tree_model.h
+++ b/chrome/browser/gtk/bookmark_tree_model.h
@@ -1,12 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_BOOKMARK_TREE_MODEL_H_
#define CHROME_BROWSER_GTK_BOOKMARK_TREE_MODEL_H_
+#pragma once
-#include <string>
#include "base/basictypes.h"
+#include "base/string16.h"
class BookmarkModel;
class BookmarkNode;
@@ -68,8 +69,8 @@ const BookmarkNode* CommitTreeStoreDifferencesBetween(
// Returns the id field of the row pointed to by |iter|.
int64 GetIdFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter);
-// Returns the title field of the row pointed to by |iter|.
-std::wstring GetTitleFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter);
+// Returns the title field in utf8 of the row pointed to by |iter|.
+string16 GetTitleFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter);
} // namespace bookmark_utils
diff --git a/chrome/browser/gtk/bookmark_utils_gtk.cc b/chrome/browser/gtk/bookmark_utils_gtk.cc
index 3b5c3b5..73190b0 100644
--- a/chrome/browser/gtk/bookmark_utils_gtk.cc
+++ b/chrome/browser/gtk/bookmark_utils_gtk.cc
@@ -8,7 +8,9 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/pickle.h"
+#include "base/string16.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
@@ -36,9 +38,6 @@ const size_t kMaxCharsOnAButton = 15;
const size_t kMaxTooltipTitleLength = 100;
const size_t kMaxTooltipURLLength = 400;
-// Only used for the background of the drag widget.
-const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xe6, 0xed, 0xf4);
-
// Padding between the chrome button highlight border and the contents (favicon,
// text).
const int kButtonPaddingTop = 0;
@@ -51,7 +50,7 @@ void* AsVoid(const BookmarkNode* node) {
}
// Creates the widget hierarchy for a bookmark button.
-void PackButton(GdkPixbuf* pixbuf, const std::wstring& title, bool ellipsize,
+void PackButton(GdkPixbuf* pixbuf, const string16& title, bool ellipsize,
GtkThemeProvider* provider, GtkWidget* button) {
GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(button));
if (former_child)
@@ -64,7 +63,7 @@ void PackButton(GdkPixbuf* pixbuf, const std::wstring& title, bool ellipsize,
GtkWidget* box = gtk_hbox_new(FALSE, kBarButtonPadding);
gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
- std::string label_string = WideToUTF8(title);
+ std::string label_string = UTF16ToUTF8(title);
if (!label_string.empty()) {
GtkWidget* label = gtk_label_new(label_string.c_str());
// Until we switch to vector graphics, force the font size.
@@ -99,11 +98,11 @@ const int kDragRepresentationWidth = 140;
struct DragRepresentationData {
public:
GdkPixbuf* favicon;
- std::wstring text;
+ string16 text;
SkColor text_color;
DragRepresentationData(GdkPixbuf* favicon,
- const std::wstring& text,
+ const string16& text,
SkColor text_color)
: favicon(favicon),
text(text),
@@ -140,7 +139,7 @@ gboolean OnDragIconExpose(GtkWidget* sender,
int text_width = sender->allocation.width - text_x;
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
- canvas.DrawStringInt(data->text,
+ canvas.DrawStringInt(UTF16ToWide(data->text),
base_font, data->text_color,
text_x, 0, text_width, sender->allocation.height);
@@ -179,7 +178,7 @@ GdkPixbuf* GetPixbufForNode(const BookmarkNode* node, BookmarkModel* model,
}
GtkWidget* GetDragRepresentation(GdkPixbuf* pixbuf,
- const std::wstring& title,
+ const string16& title,
GtkThemeProvider* provider) {
GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
@@ -196,12 +195,12 @@ GtkWidget* GetDragRepresentation(GdkPixbuf* pixbuf,
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
gtk_widget_set_size_request(window, kDragRepresentationWidth,
- base_font.height());
+ base_font.GetHeight());
} else {
if (!provider->UseGtkTheme()) {
- // TODO(erg): Theme wise, which color should I be picking here?
- // COLOR_BUTTON_BACKGROUND doesn't match the default theme!
- gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &kBackgroundColor);
+ GdkColor color = provider->GetGdkColor(
+ BrowserThemeProvider::COLOR_TOOLBAR);
+ gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color);
}
gtk_widget_realize(window);
@@ -231,8 +230,8 @@ void ConfigureButtonForNode(const BookmarkNode* node, BookmarkModel* model,
GtkWidget* button, GtkThemeProvider* provider) {
GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(node, model,
provider->UseGtkTheme());
- PackButton(pixbuf, node->GetTitle(), node != model->other_node(),
- provider, button);
+ PackButton(pixbuf, node->GetTitle(), node != model->other_node(), provider,
+ button);
g_object_unref(pixbuf);
std::string tooltip = BuildTooltipFor(node);
@@ -245,7 +244,7 @@ void ConfigureButtonForNode(const BookmarkNode* node, BookmarkModel* model,
std::string BuildTooltipFor(const BookmarkNode* node) {
const std::string& url = node->GetURL().possibly_invalid_spec();
- const std::string& title = WideToUTF8(node->GetTitle());
+ const std::string& title = UTF16ToUTF8(node->GetTitle());
std::string truncated_url = WideToUTF8(l10n_util::TruncateString(
UTF8ToWide(url), kMaxTooltipURLLength));
@@ -259,7 +258,7 @@ std::string BuildTooltipFor(const BookmarkNode* node) {
return escaped_url;
} else {
std::string truncated_title = WideToUTF8(l10n_util::TruncateString(
- node->GetTitle(), kMaxTooltipTitleLength));
+ UTF16ToWideHack(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);
@@ -327,8 +326,8 @@ void WriteBookmarksToSelection(const std::vector<const BookmarkNode*>& nodes,
}
case gtk_dnd_util::NETSCAPE_URL: {
// _NETSCAPE_URL format is URL + \n + title.
- std::string utf8_text = nodes[0]->GetURL().spec() + "\n" + UTF16ToUTF8(
- nodes[0]->GetTitleAsString16());
+ std::string utf8_text = nodes[0]->GetURL().spec() + "\n" +
+ UTF16ToUTF8(nodes[0]->GetTitle());
gtk_selection_data_set(selection_data,
selection_data->target,
kBitsInAByte,
@@ -407,7 +406,7 @@ bool CreateNewBookmarkFromNamedUrl(GtkSelectionData* selection_data,
if (!gtk_dnd_util::ExtractNamedURL(selection_data, &url, &title))
return false;
- model->AddURL(parent, idx, UTF16ToWideHack(title), url);
+ model->AddURL(parent, idx, title, url);
return true;
}
@@ -417,7 +416,7 @@ bool CreateNewBookmarksFromURIList(GtkSelectionData* selection_data,
gtk_dnd_util::ExtractURIList(selection_data, &urls);
for (size_t i = 0; i < urls.size(); ++i) {
std::string title = GetNameForURL(urls[i]);
- model->AddURL(parent, idx++, UTF8ToWide(title), urls[i]);
+ model->AddURL(parent, idx++, UTF8ToUTF16(title), urls[i]);
}
return true;
}
diff --git a/chrome/browser/gtk/bookmark_utils_gtk.h b/chrome/browser/gtk/bookmark_utils_gtk.h
index 6619461..0e666c7 100644
--- a/chrome/browser/gtk/bookmark_utils_gtk.h
+++ b/chrome/browser/gtk/bookmark_utils_gtk.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_GTK_BOOKMARK_UTILS_GTK_H_
#define CHROME_BROWSER_GTK_BOOKMARK_UTILS_GTK_H_
+#pragma once
#include <vector>
#include <string>
#include "app/gtk_integers.h"
+#include "base/string16.h"
class BookmarkModel;
class BookmarkNode;
@@ -32,7 +34,7 @@ GdkPixbuf* GetPixbufForNode(const BookmarkNode* node, BookmarkModel* model,
// Returns a GtkWindow with a visual hierarchy for passing to
// gtk_drag_set_icon_widget().
GtkWidget* GetDragRepresentation(GdkPixbuf* pixbuf,
- const std::wstring& title,
+ const string16& title,
GtkThemeProvider* provider);
GtkWidget* GetDragRepresentationForNode(const BookmarkNode* node,
BookmarkModel* model,
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
index b60489a..a825d94 100644
--- a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
@@ -33,25 +34,27 @@
#include "gfx/canvas_skia_paint.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
+#include "grit/theme_resources.h"
namespace {
-// The size of each button on the toolbar.
-const int kButtonSize = 29;
+// The width of the browser action buttons.
+const int kButtonWidth = 27;
-// The padding between browser action buttons. Visually, the actual number of
-// "empty" (non-drawing) pixels is this value + 2 when adjacent browser icons
-// use their maximum allowed size.
-const int kButtonPadding = 3;
+// The padding between browser action buttons.
+const int kButtonPadding = 4;
// The padding to the right of the browser action buttons (between the buttons
-// and the separator, or chevron if it's showing).
-const int kPaddingToRightOfButtons = 5;
+// and chevron if they are both showing).
+const int kButtonChevronPadding = 2;
// The padding to the left, top and bottom of the browser actions toolbar
// separator.
const int kSeparatorPadding = 2;
+// Width of the invisible gripper for resizing the toolbar.
+const int kResizeGripperWidth = 4;
+
const char* kDragTarget = "application/x-chrome-browseraction";
GtkTargetEntry GetDragTargetEntry() {
@@ -66,7 +69,7 @@ GtkTargetEntry GetDragTargetEntry() {
// The minimum width in pixels of the button hbox if |icon_count| icons are
// showing.
gint WidthForIconCount(gint icon_count) {
- return std::max((kButtonSize + kButtonPadding) * icon_count - kButtonPadding,
+ return std::max((kButtonWidth + kButtonPadding) * icon_count - kButtonPadding,
0);
}
@@ -80,20 +83,27 @@ class BrowserActionButton : public NotificationObserver,
public MenuGtk::Delegate {
public:
BrowserActionButton(BrowserActionsToolbarGtk* toolbar,
- Extension* extension)
+ Extension* extension,
+ GtkThemeProvider* theme_provider)
: toolbar_(toolbar),
extension_(extension),
image_(NULL),
tracker_(this),
tab_specific_icon_(NULL),
default_icon_(NULL) {
- button_.Own(
- GtkThemeProvider::GetFrom(toolbar->profile_)->BuildChromeButton());
+ button_.reset(new CustomDrawButton(
+ theme_provider,
+ IDR_BROWSER_ACTION,
+ IDR_BROWSER_ACTION_P,
+ IDR_BROWSER_ACTION_H,
+ 0,
+ NULL));
+ alignment_.Own(gtk_alignment_new(0, 0, 1, 1));
+ gtk_container_add(GTK_CONTAINER(alignment_.get()), button());
+ gtk_widget_show(button());
DCHECK(extension_->browser_action());
- gtk_widget_set_size_request(button_.get(), kButtonSize, kButtonSize);
-
UpdateState();
// The Browser Action API does not allow the default icon path to be
@@ -106,14 +116,14 @@ class BrowserActionButton : public NotificationObserver,
ImageLoadingTracker::DONT_CACHE);
}
- signals_.Connect(button_.get(), "button-press-event",
+ signals_.Connect(button(), "button-press-event",
G_CALLBACK(OnButtonPress), this);
- signals_.Connect(button_.get(), "clicked",
+ signals_.Connect(button(), "clicked",
G_CALLBACK(OnClicked), this);
- signals_.ConnectAfter(button_.get(), "expose-event",
- G_CALLBACK(OnExposeEvent), this);
- signals_.Connect(button_.get(), "drag-begin",
+ signals_.Connect(button(), "drag-begin",
G_CALLBACK(&OnDragBegin), this);
+ signals_.ConnectAfter(widget(), "expose-event",
+ G_CALLBACK(OnExposeEvent), this);
registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
Source<ExtensionAction>(extension->browser_action()));
@@ -126,10 +136,12 @@ class BrowserActionButton : public NotificationObserver,
if (default_icon_)
g_object_unref(default_icon_);
- button_.Destroy();
+ alignment_.Destroy();
}
- GtkWidget* widget() { return button_.get(); }
+ GtkWidget* button() { return button_->widget(); }
+
+ GtkWidget* widget() { return alignment_.get(); }
Extension* extension() { return extension_; }
@@ -161,9 +173,9 @@ class BrowserActionButton : public NotificationObserver,
std::string tooltip = extension_->browser_action()->GetTitle(tab_id);
if (tooltip.empty())
- gtk_widget_set_has_tooltip(button_.get(), FALSE);
+ gtk_widget_set_has_tooltip(button(), FALSE);
else
- gtk_widget_set_tooltip_text(button_.get(), tooltip.c_str());
+ gtk_widget_set_tooltip_text(button(), tooltip.c_str());
SkBitmap image = extension_->browser_action()->GetIcon(tab_id);
if (!image.isNull()) {
@@ -175,7 +187,7 @@ class BrowserActionButton : public NotificationObserver,
} else if (default_icon_) {
SetImage(default_icon_);
}
- gtk_widget_queue_draw(button_.get());
+ gtk_widget_queue_draw(button());
}
SkBitmap GetIcon() {
@@ -199,7 +211,7 @@ class BrowserActionButton : public NotificationObserver,
private:
// MenuGtk::Delegate implementation.
virtual void StoppedShowing() {
- gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(button_.get()));
+ button_->UnsetPaintOverride();
// If the context menu was showing for the overflow menu, re-assert the
// grab that was shadowed.
@@ -243,7 +255,7 @@ class BrowserActionButton : public NotificationObserver,
void SetImage(GdkPixbuf* image) {
if (!image_) {
image_ = gtk_image_new_from_pixbuf(image);
- gtk_button_set_image(GTK_BUTTON(button_.get()), image_);
+ gtk_button_set_image(GTK_BUTTON(button()), image_);
} else {
gtk_image_set_from_pixbuf(GTK_IMAGE(image_), image);
}
@@ -255,8 +267,7 @@ class BrowserActionButton : public NotificationObserver,
if (event->button.button != 3)
return FALSE;
- gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(action->button_.get()),
- GTK_STATE_PRELIGHT);
+ action->button_->SetPaintOverride(GTK_STATE_ACTIVE);
action->GetContextMenu()->Popup(widget, event);
return TRUE;
@@ -303,8 +314,11 @@ class BrowserActionButton : public NotificationObserver,
// The extension that contains this browser action.
Extension* extension_;
- // The gtk widget for this browser action.
- OwnedWidgetGtk button_;
+ // The button for this browser action.
+ scoped_ptr<CustomDrawButton> button_;
+
+ // The top level widget (parent of |button_|).
+ OwnedWidgetGtk alignment_;
// The one image subwidget in |button_|. We keep this out so we don't alter
// the widget hierarchy while changing the button image because changing the
@@ -343,21 +357,27 @@ BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
model_(NULL),
hbox_(gtk_hbox_new(FALSE, 0)),
button_hbox_(gtk_chrome_shrinkable_hbox_new(TRUE, FALSE, kButtonPadding)),
- overflow_button_(browser->profile()),
- separator_(theme_provider_->CreateToolbarSeparator()),
drag_button_(NULL),
drop_index_(-1),
resize_animation_(this),
desired_width_(0),
start_width_(0),
- draw_gripper_(false),
method_factory_(this) {
ExtensionsService* extension_service = profile_->GetExtensionsService();
// The |extension_service| can be NULL in Incognito.
if (!extension_service)
return;
+ overflow_button_.reset(new CustomDrawButton(
+ theme_provider_,
+ IDR_BROWSER_ACTIONS_OVERFLOW,
+ IDR_BROWSER_ACTIONS_OVERFLOW_P,
+ IDR_BROWSER_ACTIONS_OVERFLOW_H,
+ 0,
+ gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE)));
+
GtkWidget* gripper = gtk_button_new();
+ gtk_widget_set_size_request(gripper, kResizeGripperWidth, -1);
GTK_WIDGET_UNSET_FLAGS(gripper, GTK_CAN_FOCUS);
gtk_widget_add_events(gripper, GDK_POINTER_MOTION_MASK);
signals_.Connect(gripper, "motion-notify-event",
@@ -372,19 +392,31 @@ BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
G_CALLBACK(OnGripperButtonReleaseThunk), this);
signals_.Connect(gripper, "button-press-event",
G_CALLBACK(OnGripperButtonPressThunk), this);
- signals_.Connect(overflow_button_.widget(), "button-press-event",
+ signals_.Connect(chevron(), "button-press-event",
G_CALLBACK(OnOverflowButtonPressThunk), this);
- // Add some blank space on the right of the browser action buttons.
- GtkWidget* spacer = gtk_alignment_new(0, 0, 1, 1);
- gtk_widget_set_size_request(spacer, kPaddingToRightOfButtons, -1);
+ // |overflow_alignment| adds padding to the right of the browser action
+ // buttons, but only appears when the overflow menu is showing.
+ overflow_alignment_ = gtk_alignment_new(0, 0, 1, 1);
+ gtk_container_add(GTK_CONTAINER(overflow_alignment_), chevron());
+
+ // |overflow_area_| holds the overflow chevron and the separator, which
+ // is only shown in GTK+ theme mode.
+ overflow_area_ = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(overflow_area_), overflow_alignment_,
+ FALSE, FALSE, 0);
+
+ separator_ = gtk_vseparator_new();
+ gtk_box_pack_start(GTK_BOX(overflow_area_), separator_,
+ FALSE, FALSE, 0);
+ gtk_widget_set_no_show_all(separator_, TRUE);
+
+ gtk_widget_show_all(overflow_area_);
+ gtk_widget_set_no_show_all(overflow_area_, TRUE);
gtk_box_pack_start(GTK_BOX(hbox_.get()), gripper, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox_.get()), button_hbox_.get(), TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(hbox_.get()), spacer, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(hbox_.get()), overflow_button_.widget(),
- FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(hbox_.get()), separator_, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox_.get()), overflow_area_, FALSE, FALSE, 0);
model_ = extension_service->toolbar_model();
model_->AddObserver(this);
@@ -401,6 +433,11 @@ BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
G_CALLBACK(OnHierarchyChangedThunk), this);
ViewIDUtil::SetID(button_hbox_.get(), VIEW_ID_BROWSER_ACTION_TOOLBAR);
+
+ registrar_.Add(this,
+ NotificationType::BROWSER_THEME_CHANGED,
+ NotificationService::AllSources());
+ theme_provider_->InitThemesFor(this);
}
BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
@@ -425,6 +462,16 @@ void BrowserActionsToolbarGtk::Update() {
}
}
+void BrowserActionsToolbarGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(NotificationType::BROWSER_THEME_CHANGED == type);
+ if (theme_provider_->UseGtkTheme())
+ gtk_widget_show(separator_);
+ else
+ gtk_widget_hide(separator_);
+}
+
void BrowserActionsToolbarGtk::SetupDrags() {
GtkTargetEntry drag_target = GetDragTargetEntry();
gtk_drag_dest_set(button_hbox_.get(), GTK_DEST_DEFAULT_DROP, &drag_target, 1,
@@ -460,19 +507,19 @@ void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension,
RemoveButtonForExtension(extension);
linked_ptr<BrowserActionButton> button(
- new BrowserActionButton(this, extension));
+ new BrowserActionButton(this, extension, theme_provider_));
gtk_chrome_shrinkable_hbox_pack_start(
GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()), button->widget(), 0);
gtk_box_reorder_child(GTK_BOX(button_hbox_.get()), button->widget(), index);
extension_button_map_[extension->id()] = button;
GtkTargetEntry drag_target = GetDragTargetEntry();
- gtk_drag_source_set(button->widget(), GDK_BUTTON1_MASK, &drag_target, 1,
+ gtk_drag_source_set(button->button(), GDK_BUTTON1_MASK, &drag_target, 1,
GDK_ACTION_MOVE);
// We ignore whether the drag was a "success" or "failure" in Gtk's opinion.
- signals_.Connect(button->widget(), "drag-end",
+ signals_.Connect(button->button(), "drag-end",
G_CALLBACK(&OnDragEndThunk), this);
- signals_.Connect(button->widget(), "drag-failed",
+ signals_.Connect(button->button(), "drag-failed",
G_CALLBACK(&OnDragFailedThunk), this);
// Any time a browser action button is shown or hidden we have to update
@@ -541,7 +588,7 @@ void BrowserActionsToolbarGtk::BrowserActionAdded(Extension* extension,
return;
// Animate the addition if we are showing all browser action buttons.
- if (!GTK_WIDGET_VISIBLE(overflow_button_.widget())) {
+ if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
AnimateToShowNIcons(button_count());
model_->SetVisibleIconCount(button_count());
}
@@ -557,7 +604,7 @@ void BrowserActionsToolbarGtk::BrowserActionRemoved(Extension* extension) {
RemoveButtonForExtension(extension);
- if (!GTK_WIDGET_VISIBLE(overflow_button_.widget())) {
+ if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
AnimateToShowNIcons(button_count());
model_->SetVisibleIconCount(button_count());
}
@@ -613,7 +660,7 @@ void BrowserActionsToolbarGtk::ExecuteCommand(int command_id) {
if (browser_action->HasPopup(tab_id)) {
ExtensionPopupGtk::Show(
browser_action->GetPopupUrl(tab_id), browser(),
- overflow_button_.widget(),
+ chevron(),
false);
} else {
ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
@@ -622,8 +669,7 @@ void BrowserActionsToolbarGtk::ExecuteCommand(int command_id) {
}
void BrowserActionsToolbarGtk::StoppedShowing() {
- gtk_chrome_button_unset_paint_state(
- GTK_CHROME_BUTTON(overflow_button_.widget()));
+ overflow_button_->UnsetPaintOverride();
}
void BrowserActionsToolbarGtk::DragStarted(BrowserActionButton* button,
@@ -648,15 +694,21 @@ void BrowserActionsToolbarGtk::UpdateChevronVisibility() {
int showing_icon_count =
gtk_chrome_shrinkable_hbox_get_visible_child_count(
GTK_CHROME_SHRINKABLE_HBOX(button_hbox_.get()));
+ if (showing_icon_count == 0) {
+ gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_), 0, 0, 0, 0);
+ } else {
+ gtk_alignment_set_padding(GTK_ALIGNMENT(overflow_alignment_), 0, 0,
+ kButtonChevronPadding, 0);
+ }
if (button_count() > showing_icon_count) {
- if (!GTK_WIDGET_VISIBLE(overflow_button_.widget())) {
+ if (!GTK_WIDGET_VISIBLE(overflow_area_)) {
if (drag_button_) {
// During drags, when the overflow chevron shows for the first time,
// take that much space away from |button_hbox_| to make the drag look
// smoother.
GtkRequisition req;
- gtk_widget_size_request(overflow_button_.widget(), &req);
+ gtk_widget_size_request(chevron(), &req);
gint overflow_width = req.width;
gtk_widget_size_request(button_hbox_.get(), &req);
gint button_hbox_width = req.width;
@@ -664,10 +716,10 @@ void BrowserActionsToolbarGtk::UpdateChevronVisibility() {
gtk_widget_set_size_request(button_hbox_.get(), button_hbox_width, -1);
}
- gtk_widget_show(overflow_button_.widget());
+ gtk_widget_show(overflow_area_);
}
} else {
- gtk_widget_hide(overflow_button_.widget());
+ gtk_widget_hide(overflow_area_);
}
}
@@ -680,7 +732,7 @@ gboolean BrowserActionsToolbarGtk::OnDragMotion(GtkWidget* widget,
if (base::i18n::IsRTL())
x = widget->allocation.width - x;
- drop_index_ = x < kButtonSize ? 0 : x / (kButtonSize + kButtonPadding);
+ drop_index_ = x < kButtonWidth ? 0 : x / (kButtonWidth + kButtonPadding);
// We will go ahead and reorder the child in order to provide visual feedback
// to the user. We don't inform the model that it has moved until the drag
@@ -754,21 +806,6 @@ gboolean BrowserActionsToolbarGtk::OnGripperMotionNotify(
gboolean BrowserActionsToolbarGtk::OnGripperExpose(GtkWidget* gripper,
GdkEventExpose* expose) {
- if (!draw_gripper_)
- return TRUE;
-
- cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(expose->window));
-
- CairoCachedSurface* surface = theme_provider_->GetSurfaceNamed(
- IDR_RESIZE_GRIPPER, gripper);
- gfx::Point center = gfx::Rect(gripper->allocation).CenterPoint();
- center.Offset(-surface->Width() / 2, -surface->Height() / 2);
- surface->SetSource(cr, center.x(), center.y());
- gdk_cairo_rectangle(cr, &expose->area);
- cairo_fill(cr);
-
- cairo_destroy(cr);
-
return TRUE;
}
@@ -781,18 +818,13 @@ gboolean BrowserActionsToolbarGtk::OnGripperEnterNotify(
GtkWidget* gripper, GdkEventCrossing* event) {
gdk_window_set_cursor(gripper->window,
gtk_util::GetCursor(GDK_SB_H_DOUBLE_ARROW));
- draw_gripper_ = true;
-
return FALSE;
}
gboolean BrowserActionsToolbarGtk::OnGripperLeaveNotify(
GtkWidget* gripper, GdkEventCrossing* event) {
- if (!(event->state & GDK_BUTTON1_MASK)) {
+ if (!(event->state & GDK_BUTTON1_MASK))
gdk_window_set_cursor(gripper->window, NULL);
- draw_gripper_ = false;
- }
-
return FALSE;
}
@@ -801,11 +833,8 @@ gboolean BrowserActionsToolbarGtk::OnGripperButtonRelease(
gfx::Rect gripper_rect(0, 0,
gripper->allocation.width, gripper->allocation.height);
gfx::Point release_point(event->x, event->y);
- if (!gripper_rect.Contains(release_point)) {
+ if (!gripper_rect.Contains(release_point))
gdk_window_set_cursor(gripper->window, NULL);
- draw_gripper_ = false;
- gtk_widget_queue_draw(gripper);
- }
// After the user resizes the toolbar, we want to smartly resize it to be
// the perfect size to fit the buttons.
@@ -851,9 +880,8 @@ gboolean BrowserActionsToolbarGtk::OnOverflowButtonPress(
signals_.Connect(overflow_menu_->widget(), "button-press-event",
G_CALLBACK(OnOverflowMenuButtonPressThunk), this);
- gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(overflow),
- GTK_STATE_ACTIVE);
- overflow_menu_->PopupAsFromKeyEvent(overflow);
+ overflow_button_->SetPaintOverride(GTK_STATE_ACTIVE);
+ overflow_menu_->PopupAsFromKeyEvent(chevron());
return FALSE;
}
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.h b/chrome/browser/gtk/browser_actions_toolbar_gtk.h
index 262b81d..b80ef59 100644
--- a/chrome/browser/gtk/browser_actions_toolbar_gtk.h
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
#define CHROME_BROWSER_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
+#pragma once
#include <map>
#include <string>
@@ -15,11 +16,12 @@
#include "base/linked_ptr.h"
#include "base/task.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
+#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/gtk/overflow_button.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class Browser;
class BrowserActionButton;
@@ -33,12 +35,14 @@ typedef struct _GtkWidget GtkWidget;
class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
public AnimationDelegate,
public MenuGtk::Delegate,
- public menus::SimpleMenuModel::Delegate {
+ public menus::SimpleMenuModel::Delegate,
+ public NotificationObserver {
public:
explicit BrowserActionsToolbarGtk(Browser* browser);
virtual ~BrowserActionsToolbarGtk();
GtkWidget* widget() { return hbox_.get(); }
+ GtkWidget* chevron() { return overflow_button_->widget(); }
// Returns the widget in use by the BrowserActionButton corresponding to
// |extension|. Used in positioning the ExtensionInstalledBubble for
@@ -55,6 +59,15 @@ class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
// Update the display of all buttons.
void Update();
+ // NotificationObserver implementation.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ bool animating() {
+ return resize_animation_.is_animating();
+ }
+
private:
friend class BrowserActionButton;
@@ -168,12 +181,16 @@ class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
// Contains the browser action buttons.
OwnedWidgetGtk button_hbox_;
- OverflowButton overflow_button_;
+ // The overflow button for chrome theme mode.
+ scoped_ptr<CustomDrawButton> overflow_button_;
+ // The separator just next to the overflow button. Only shown in GTK+ theme
+ // mode. In Chrome theme mode, the overflow button has a separator built in.
+ GtkWidget* separator_;
scoped_ptr<MenuGtk> overflow_menu_;
scoped_ptr<menus::SimpleMenuModel> overflow_menu_model_;
-
- // The vertical separator between the overflow button and the page/app menus.
- GtkWidget* separator_;
+ GtkWidget* overflow_area_;
+ // A widget for adding extra padding to the left of the overflow button.
+ GtkWidget* overflow_alignment_;
// The button that is currently being dragged, or NULL.
BrowserActionButton* drag_button_;
@@ -195,12 +212,10 @@ class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
// This is the width we were at when we started animating.
int start_width_;
- // We only draw the browser action gripper when the user is hovering over it
- // or dragging it.
- bool draw_gripper_;
-
GtkSignalRegistrar signals_;
+ NotificationRegistrar registrar_;
+
ScopedRunnableMethodFactory<BrowserActionsToolbarGtk> method_factory_;
DISALLOW_COPY_AND_ASSIGN(BrowserActionsToolbarGtk);
diff --git a/chrome/browser/gtk/browser_titlebar.cc b/chrome/browser/gtk/browser_titlebar.cc
index 3c712a0..9556ae6 100644
--- a/chrome/browser/gtk/browser_titlebar.cc
+++ b/chrome/browser/gtk/browser_titlebar.cc
@@ -16,6 +16,7 @@
#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/string_tokenizer.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/encoding_menu_controller.h"
@@ -28,7 +29,7 @@
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/gtk/tabs/tab_strip_gtk.h"
-#include "chrome/browser/pref_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/wrench_menu_model.h"
@@ -170,6 +171,7 @@ void PopupPageMenuModel::Build() {
AddItemWithStringId(IDC_RELOAD, IDS_APP_MENU_RELOAD);
AddSeparator();
AddItemWithStringId(IDC_SHOW_AS_TAB, IDS_SHOW_AS_TAB);
+ AddItemWithStringId(IDC_COPY_URL, IDS_APP_MENU_COPY_URL);
AddSeparator();
AddItemWithStringId(IDC_CUT, IDS_CUT);
AddItemWithStringId(IDC_COPY, IDS_COPY);
@@ -183,6 +185,9 @@ void PopupPageMenuModel::Build() {
encoding_menu_model_.reset(new EncodingMenuModel(browser_));
AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
encoding_menu_model_.get());
+
+ AddSeparator();
+ AddItemWithStringId(IDC_CLOSE_WINDOW, IDS_CLOSE);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/gtk/browser_titlebar.h b/chrome/browser/gtk/browser_titlebar.h
index 86f99d5..431eddf 100644
--- a/chrome/browser/gtk/browser_titlebar.h
+++ b/chrome/browser/gtk/browser_titlebar.h
@@ -9,6 +9,7 @@
#ifndef CHROME_BROWSER_GTK_BROWSER_TITLEBAR_H_
#define CHROME_BROWSER_GTK_BROWSER_TITLEBAR_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
index a36eae8..4cff2f2 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -4,24 +4,21 @@
#include "chrome/browser/gtk/browser_toolbar_gtk.h"
+#include <X11/XF86keysym.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#include <X11/XF86keysym.h>
#include "app/gtk_dnd_util.h"
#include "app/l10n_util.h"
#include "app/menus/accelerator_gtk.h"
-#include "app/resource_bundle.h"
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/i18n/rtl.h"
-#include "base/keyboard_codes_posix.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/singleton.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/encoding_menu_controller.h"
#include "chrome/browser/gtk/accelerators_gtk.h"
#include "chrome/browser/gtk/back_forward_button_gtk.h"
@@ -38,9 +35,10 @@
#include "chrome/browser/gtk/tabs/tab_strip_gtk.h"
#include "chrome/browser/gtk/view_id_util.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/pref_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/themes/browser_theme_provider.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_details.h"
@@ -57,28 +55,36 @@
namespace {
+// Padding on left and right of the left toolbar buttons (back, forward, reload,
+// etc.).
+const int kToolbarLeftAreaPadding = 4;
+
// Height of the toolbar in pixels (not counting padding).
const int kToolbarHeight = 29;
// Padding within the toolbar above the buttons and location bar.
-const int kTopPadding = 4;
+const int kTopBottomPadding = 3;
// Height of the toolbar in pixels when we only show the location bar.
const int kToolbarHeightLocationBarOnly = kToolbarHeight - 2;
// Interior spacing between toolbar widgets.
-const int kToolbarWidgetSpacing = 2;
+const int kToolbarWidgetSpacing = 1;
// Amount of rounding on top corners of toolbar. Only used in Gtk theme mode.
const int kToolbarCornerSize = 3;
// The offset in pixels of the upgrade dot on the app menu.
-const int kUpgradeDotOffset = 11;
+const int kUpgradeDotOffset = 6;
// The duration of the upgrade notification animation (actually the duration
// of a half-throb).
const int kThrobDuration = 1000;
+void SetWidgetHeightRequest(GtkWidget* widget, gpointer user_data) {
+ gtk_widget_set_size_request(widget, -1, GPOINTER_TO_INT(user_data));
+}
+
} // namespace
// BrowserToolbarGtk, public ---------------------------------------------------
@@ -108,7 +114,6 @@ BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser, BrowserWindowGtk* window)
upgrade_reminder_animation_.SetThrobDuration(kThrobDuration);
ActiveWindowWatcherX::AddObserver(this);
- MaybeShowUpgradeReminder();
}
BrowserToolbarGtk::~BrowserToolbarGtk() {
@@ -121,9 +126,7 @@ BrowserToolbarGtk::~BrowserToolbarGtk() {
offscreen_entry_.Destroy();
- app_menu_.reset();
- app_menu_button_.Destroy();
- app_menu_image_.Destroy();
+ wrench_menu_.reset();
}
void BrowserToolbarGtk::Init(Profile* profile,
@@ -153,35 +156,37 @@ void BrowserToolbarGtk::Init(Profile* profile,
gtk_container_add(GTK_CONTAINER(event_box_), alignment_);
gtk_container_add(GTK_CONTAINER(alignment_), toolbar_);
- toolbar_left_ = gtk_hbox_new(FALSE, 0);
+ toolbar_left_ = gtk_hbox_new(FALSE, kToolbarWidgetSpacing);
- GtkWidget* back_forward_hbox_ = gtk_hbox_new(FALSE, 0);
back_.reset(new BackForwardButtonGtk(browser_, false));
g_signal_connect(back_->widget(), "clicked",
G_CALLBACK(OnButtonClickThunk), this);
- gtk_box_pack_start(GTK_BOX(back_forward_hbox_), back_->widget(), FALSE,
+ gtk_box_pack_start(GTK_BOX(toolbar_left_), back_->widget(), FALSE,
FALSE, 0);
forward_.reset(new BackForwardButtonGtk(browser_, true));
g_signal_connect(forward_->widget(), "clicked",
G_CALLBACK(OnButtonClickThunk), this);
- gtk_box_pack_start(GTK_BOX(back_forward_hbox_), forward_->widget(), FALSE,
+ gtk_box_pack_start(GTK_BOX(toolbar_left_), forward_->widget(), FALSE,
FALSE, 0);
- gtk_box_pack_start(GTK_BOX(toolbar_left_), back_forward_hbox_, FALSE,
- FALSE, kToolbarWidgetSpacing);
-
reload_.reset(new ReloadButtonGtk(location_bar_.get(), browser_));
gtk_box_pack_start(GTK_BOX(toolbar_left_), reload_->widget(), FALSE, FALSE,
0);
- home_.reset(BuildToolbarButton(IDR_HOME, IDR_HOME_P, IDR_HOME_H, 0,
- IDR_BUTTON_MASK,
- l10n_util::GetStringUTF8(IDS_TOOLTIP_HOME),
- GTK_STOCK_HOME, kToolbarWidgetSpacing));
+ home_.reset(new CustomDrawButton(GtkThemeProvider::GetFrom(profile_),
+ IDR_HOME, IDR_HOME_P, IDR_HOME_H, 0, GTK_STOCK_HOME,
+ GTK_ICON_SIZE_SMALL_TOOLBAR));
+ gtk_widget_set_tooltip_text(home_->widget(),
+ l10n_util::GetStringUTF8(IDS_TOOLTIP_HOME).c_str());
+ g_signal_connect(home_->widget(), "clicked",
+ G_CALLBACK(OnButtonClickThunk), this);
+ gtk_box_pack_start(GTK_BOX(toolbar_left_), home_->widget(), FALSE, FALSE,
+ kToolbarWidgetSpacing);
gtk_util::SetButtonTriggersNavigation(home_->widget());
- gtk_box_pack_start(GTK_BOX(toolbar_), toolbar_left_, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(toolbar_), toolbar_left_, FALSE, FALSE,
+ kToolbarLeftAreaPadding);
location_hbox_ = gtk_hbox_new(FALSE, 0);
location_bar_->Init(ShouldOnlyShowLocation());
@@ -191,37 +196,43 @@ void BrowserToolbarGtk::Init(Profile* profile,
g_signal_connect(location_hbox_, "expose-event",
G_CALLBACK(OnLocationHboxExposeThunk), this);
gtk_box_pack_start(GTK_BOX(toolbar_), location_hbox_, TRUE, TRUE,
- kToolbarWidgetSpacing + (ShouldOnlyShowLocation() ? 1 : 0));
-
- toolbar_right_ = gtk_hbox_new(FALSE, 0);
+ ShouldOnlyShowLocation() ? 1 : 0);
if (!ShouldOnlyShowLocation()) {
actions_toolbar_.reset(new BrowserActionsToolbarGtk(browser_));
- gtk_box_pack_start(GTK_BOX(toolbar_right_), actions_toolbar_->widget(),
+ gtk_box_pack_start(GTK_BOX(toolbar_), actions_toolbar_->widget(),
FALSE, FALSE, 0);
}
- // We need another hbox for the menu buttons so we can place them together,
- // but still have some padding to their collective left/right.
- GtkWidget* menus_hbox = gtk_hbox_new(FALSE, 0);
- GtkWidget* chrome_menu = BuildToolbarMenuButton(
- l10n_util::GetStringFUTF8(IDS_APPMENU_TOOLTIP,
- WideToUTF16(l10n_util::GetString(IDS_PRODUCT_NAME))),
- &app_menu_button_);
- app_menu_image_.Own(gtk_image_new_from_pixbuf(
- theme_provider_->GetRTLEnabledPixbufNamed(IDR_TOOLS)));
- gtk_container_add(GTK_CONTAINER(chrome_menu), app_menu_image_.get());
- g_signal_connect_after(app_menu_image_.get(), "expose-event",
- G_CALLBACK(OnAppMenuImageExposeThunk), this);
-
- app_menu_.reset(new MenuGtk(this, &wrench_menu_model_));
- gtk_box_pack_start(GTK_BOX(menus_hbox), chrome_menu, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(toolbar_right_), menus_hbox, FALSE, FALSE,
- kToolbarWidgetSpacing);
- g_signal_connect(app_menu_->widget(), "show",
- G_CALLBACK(OnAppMenuShowThunk), this);
+ wrench_menu_image_ = gtk_image_new_from_pixbuf(
+ theme_provider_->GetRTLEnabledPixbufNamed(IDR_TOOLS));
+ wrench_menu_button_.reset(new CustomDrawButton(
+ GtkThemeProvider::GetFrom(profile_),
+ IDR_TOOLS, IDR_TOOLS_P, IDR_TOOLS_H, 0,
+ wrench_menu_image_));
+ GtkWidget* wrench_button = wrench_menu_button_->widget();
- gtk_box_pack_start(GTK_BOX(toolbar_), toolbar_right_, FALSE, FALSE, 0);
+ gtk_widget_set_tooltip_text(
+ wrench_button,
+ l10n_util::GetStringFUTF8(IDS_APPMENU_TOOLTIP,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)).c_str());
+ g_signal_connect(wrench_button, "button-press-event",
+ G_CALLBACK(OnMenuButtonPressEventThunk), this);
+ GTK_WIDGET_UNSET_FLAGS(wrench_button, GTK_CAN_FOCUS);
+
+ // Put the wrench button in a box so that we can paint the update notification
+ // over it.
+ GtkWidget* wrench_box = gtk_alignment_new(0, 0, 1, 1);
+ g_signal_connect_after(wrench_box, "expose-event",
+ G_CALLBACK(OnWrenchMenuButtonExposeThunk), this);
+ gtk_container_add(GTK_CONTAINER(wrench_box), wrench_button);
+ gtk_box_pack_start(GTK_BOX(toolbar_), wrench_box, FALSE, FALSE, 4);
+
+ wrench_menu_.reset(new MenuGtk(this, &wrench_menu_model_));
+ g_signal_connect(wrench_menu_->widget(), "show",
+ G_CALLBACK(OnWrenchMenuShowThunk), this);
+ registrar_.Add(this, NotificationType::ZOOM_LEVEL_CHANGED,
+ Source<Profile>(browser_->profile()));
if (ShouldOnlyShowLocation()) {
gtk_widget_show(event_box_);
@@ -243,6 +254,8 @@ void BrowserToolbarGtk::Init(Profile* profile,
SetViewIDs();
theme_provider_->InitThemesFor(this);
+
+ MaybeShowUpgradeReminder();
}
void BrowserToolbarGtk::SetViewIDs() {
@@ -252,7 +265,7 @@ void BrowserToolbarGtk::SetViewIDs() {
ViewIDUtil::SetID(reload_->widget(), VIEW_ID_RELOAD_BUTTON);
ViewIDUtil::SetID(home_->widget(), VIEW_ID_HOME_BUTTON);
ViewIDUtil::SetID(location_bar_->widget(), VIEW_ID_LOCATION_BAR);
- ViewIDUtil::SetID(app_menu_button_.get(), VIEW_ID_APP_MENU);
+ ViewIDUtil::SetID(wrench_menu_button_->widget(), VIEW_ID_APP_MENU);
}
void BrowserToolbarGtk::Show() {
@@ -270,16 +283,15 @@ LocationBar* BrowserToolbarGtk::GetLocationBar() const {
void BrowserToolbarGtk::UpdateForBookmarkBarVisibility(
bool show_bottom_padding) {
gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_),
- ShouldOnlyShowLocation() ? 0 : kTopPadding,
- !show_bottom_padding || ShouldOnlyShowLocation() ? 0 : kTopPadding,
+ ShouldOnlyShowLocation() ? 0 : kTopBottomPadding,
+ !show_bottom_padding || ShouldOnlyShowLocation() ? 0 : kTopBottomPadding,
0, 0);
}
void BrowserToolbarGtk::ShowAppMenu() {
- app_menu_->Cancel();
- gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(app_menu_button_.get()),
- GTK_STATE_ACTIVE);
- app_menu_->PopupAsFromKeyEvent(app_menu_button_.get());
+ wrench_menu_->Cancel();
+ wrench_menu_button_->SetPaintOverride(GTK_STATE_ACTIVE);
+ wrench_menu_->PopupAsFromKeyEvent(wrench_menu_button_->widget());
}
// CommandUpdater::CommandObserver ---------------------------------------------
@@ -316,42 +328,24 @@ void BrowserToolbarGtk::StoppedShowing() {
// Without these calls, the hover state can get stuck since the leave-notify
// event is not sent when clicking a button brings up the menu.
gtk_chrome_button_set_hover_state(
- GTK_CHROME_BUTTON(app_menu_button_.get()), 0.0);
- gtk_chrome_button_unset_paint_state(
- GTK_CHROME_BUTTON(app_menu_button_.get()));
+ GTK_CHROME_BUTTON(wrench_menu_button_->widget()), 0.0);
+ wrench_menu_button_->UnsetPaintOverride();
}
GtkIconSet* BrowserToolbarGtk::GetIconSetForId(int idr) {
return theme_provider_->GetIconSetForId(idr);
}
-// menus::SimpleMenuModel::Delegate
-
-bool BrowserToolbarGtk::IsCommandIdEnabled(int id) const {
- return browser_->command_updater()->IsCommandEnabled(id);
-}
-
-bool BrowserToolbarGtk::IsCommandIdChecked(int id) const {
- if (!profile_)
- return false;
-
- EncodingMenuController controller;
- if (id == IDC_SHOW_BOOKMARK_BAR) {
- return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
- } else if (controller.DoesCommandBelongToEncodingMenu(id)) {
- TabContents* tab_contents = browser_->GetSelectedTabContents();
- if (tab_contents) {
- return controller.IsItemChecked(profile_, tab_contents->encoding(),
- id);
- }
- }
-
- return false;
+// Always show images because we desire that the upgrade icon always show when
+// an upgrade is available regardless of the system setting.
+// TODO(estade): Currently we do not show any other icons in this
+// menu, even though arguably if the system preference is set to show icons,
+// we should show them for Quit, Save, Print, etc.
+bool BrowserToolbarGtk::AlwaysShowImages() {
+ return true;
}
-void BrowserToolbarGtk::ExecuteCommand(int id) {
- browser_->ExecuteCommand(id);
-}
+// menus::AcceleratorProvider
bool BrowserToolbarGtk::GetAcceleratorForCommandId(
int id,
@@ -369,27 +363,23 @@ void BrowserToolbarGtk::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED) {
- NotifyPrefChanged(Details<std::wstring>(details).ptr());
+ NotifyPrefChanged(Details<std::string>(details).ptr());
} else if (type == NotificationType::BROWSER_THEME_CHANGED) {
// Update the spacing around the menu buttons
bool use_gtk = theme_provider_->UseGtkTheme();
int border = use_gtk ? 0 : 2;
gtk_container_set_border_width(
- GTK_CONTAINER(app_menu_button_.get()), border);
-
- // Update the menu button image.
- gtk_image_set_from_pixbuf(GTK_IMAGE(app_menu_image_.get()),
- theme_provider_->GetRTLEnabledPixbufNamed(IDR_TOOLS));
+ GTK_CONTAINER(wrench_menu_button_->widget()), border);
// Force the height of the toolbar so we get the right amount of padding
- // above and below the location bar. We always force the size of the hboxes
+ // above and below the location bar. We always force the size of the widgets
// to either side of the location box, but we only force the location box
// size in chrome-theme mode because that's the only time we try to control
// the font size.
int toolbar_height = ShouldOnlyShowLocation() ?
kToolbarHeightLocationBarOnly : kToolbarHeight;
- gtk_widget_set_size_request(toolbar_left_, -1, toolbar_height);
- gtk_widget_set_size_request(toolbar_right_, -1, toolbar_height);
+ gtk_container_foreach(GTK_CONTAINER(toolbar_), SetWidgetHeightRequest,
+ GINT_TO_POINTER(toolbar_height));
gtk_widget_set_size_request(location_hbox_, -1,
use_gtk ? -1 : toolbar_height);
@@ -398,9 +388,21 @@ void BrowserToolbarGtk::Observe(NotificationType type,
// themes, we want to let the background show through the toolbar.
gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_), use_gtk);
+ if (use_gtk) {
+ // We need to manually update the icon if we are in GTK mode. (Note that
+ // we set the initial value in Init()).
+ gtk_image_set_from_pixbuf(
+ GTK_IMAGE(wrench_menu_image_),
+ theme_provider_->GetRTLEnabledPixbufNamed(IDR_TOOLS));
+ }
+
UpdateRoundedness();
} else if (type == NotificationType::UPGRADE_RECOMMENDED) {
MaybeShowUpgradeReminder();
+ } else if (type == NotificationType::ZOOM_LEVEL_CHANGED) {
+ // If our zoom level changed, we need to tell the menu to update its state,
+ // since the menu could still be open.
+ wrench_menu_->UpdateMenu();
} else {
NOTREACHED();
}
@@ -426,39 +428,6 @@ void BrowserToolbarGtk::UpdateTabContents(TabContents* contents,
// BrowserToolbarGtk, private --------------------------------------------------
-CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton(
- int normal_id, int active_id, int highlight_id, int depressed_id,
- int background_id, const std::string& localized_tooltip,
- const char* stock_id, int spacing) {
- CustomDrawButton* button = new CustomDrawButton(
- GtkThemeProvider::GetFrom(profile_),
- normal_id, active_id, highlight_id, depressed_id, background_id, stock_id,
- GTK_ICON_SIZE_SMALL_TOOLBAR);
-
- gtk_widget_set_tooltip_text(button->widget(),
- localized_tooltip.c_str());
- g_signal_connect(button->widget(), "clicked",
- G_CALLBACK(OnButtonClickThunk), this);
-
- gtk_box_pack_start(GTK_BOX(toolbar_left_), button->widget(), FALSE, FALSE,
- spacing);
- return button;
-}
-
-GtkWidget* BrowserToolbarGtk::BuildToolbarMenuButton(
- const std::string& localized_tooltip,
- OwnedWidgetGtk* owner) {
- GtkWidget* button = theme_provider_->BuildChromeButton();
- owner->Own(button);
-
- gtk_widget_set_tooltip_text(button, localized_tooltip.c_str());
- g_signal_connect(button, "button-press-event",
- G_CALLBACK(OnMenuButtonPressEventThunk), this);
- GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);
-
- return button;
-}
-
void BrowserToolbarGtk::SetUpDragForHomeButton(bool enable) {
if (enable) {
gtk_drag_dest_set(home_->widget(), GTK_DEST_DEFAULT_ALL,
@@ -632,9 +601,8 @@ gboolean BrowserToolbarGtk::OnMenuButtonPressEvent(GtkWidget* button,
if (event->button != 1)
return FALSE;
- gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(button),
- GTK_STATE_ACTIVE);
- app_menu_->Popup(button, reinterpret_cast<GdkEvent*>(event));
+ wrench_menu_button_->SetPaintOverride(GTK_STATE_ACTIVE);
+ wrench_menu_->Popup(button, reinterpret_cast<GdkEvent*>(event));
return TRUE;
}
@@ -657,7 +625,7 @@ void BrowserToolbarGtk::OnDragDataReceived(GtkWidget* widget,
home_page_.SetValue(url.spec());
}
-void BrowserToolbarGtk::NotifyPrefChanged(const std::wstring* pref) {
+void BrowserToolbarGtk::NotifyPrefChanged(const std::string* pref) {
if (!pref || *pref == prefs::kShowHomeButton) {
if (show_home_button_.GetValue() && !ShouldOnlyShowLocation()) {
gtk_widget_show(home_->widget());
@@ -691,13 +659,13 @@ bool BrowserToolbarGtk::ShouldOnlyShowLocation() const {
void BrowserToolbarGtk::AnimationEnded(const Animation* animation) {
DCHECK_EQ(animation, &upgrade_reminder_animation_);
- gtk_widget_queue_draw(app_menu_image_.get());
+ gtk_widget_queue_draw(wrench_menu_button_->widget()->parent);
}
void BrowserToolbarGtk::AnimationProgressed(const Animation* animation) {
DCHECK_EQ(animation, &upgrade_reminder_animation_);
if (UpgradeAnimationIsFaded())
- gtk_widget_queue_draw(app_menu_image_.get());
+ gtk_widget_queue_draw(wrench_menu_button_->widget()->parent);
}
void BrowserToolbarGtk::AnimationCanceled(const Animation* animation) {
@@ -708,15 +676,15 @@ void BrowserToolbarGtk::ActiveWindowChanged(GdkWindow* active_window) {
MaybeShowUpgradeReminder();
}
-void BrowserToolbarGtk::OnAppMenuShow(GtkWidget* sender) {
+void BrowserToolbarGtk::OnWrenchMenuShow(GtkWidget* sender) {
if (upgrade_reminder_animation_.is_animating()) {
upgrade_reminder_canceled_ = true;
MaybeShowUpgradeReminder();
}
}
-gboolean BrowserToolbarGtk::OnAppMenuImageExpose(GtkWidget* sender,
- GdkEventExpose* expose) {
+gboolean BrowserToolbarGtk::OnWrenchMenuButtonExpose(GtkWidget* sender,
+ GdkEventExpose* expose) {
if (!Singleton<UpgradeDetector>::get()->notify_upgrade())
return FALSE;
@@ -735,10 +703,11 @@ gboolean BrowserToolbarGtk::OnAppMenuImageExpose(GtkWidget* sender,
int x_offset = base::i18n::IsRTL() ?
sender->allocation.width - kUpgradeDotOffset - badge.width() :
kUpgradeDotOffset;
+ int y_offset = sender->allocation.height / 2 + badge.height();
canvas.DrawBitmapInt(
badge,
sender->allocation.x + x_offset,
- sender->allocation.y + sender->allocation.height - badge.height());
+ sender->allocation.y + y_offset);
return FALSE;
}
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h
index 511ac49..1eb16ef 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.h
+++ b/chrome/browser/gtk/browser_toolbar_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_BROWSER_TOOLBAR_GTK_H_
#define CHROME_BROWSER_GTK_BROWSER_TOOLBAR_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include <string>
@@ -11,17 +12,18 @@
#include "app/active_window_watcher_x.h"
#include "app/gtk_signal.h"
#include "app/gtk_signal_registrar.h"
+#include "app/menus/accelerator.h"
#include "app/menus/simple_menu_model.h"
#include "app/throb_animation.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/menu_gtk.h"
-#include "chrome/browser/pref_member.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/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class BackForwardButtonGtk;
class Browser;
@@ -39,7 +41,7 @@ class ToolbarModel;
// View class that displays the GTK version of the toolbar and routes gtk
// events back to the Browser.
class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
- public menus::SimpleMenuModel::Delegate,
+ public menus::AcceleratorProvider,
public MenuGtk::Delegate,
public NotificationObserver,
public AnimationDelegate,
@@ -72,7 +74,7 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
ReloadButtonGtk* GetReloadButton() { return reload_.get(); }
- GtkWidget* GetAppMenuButton() { return app_menu_button_.get(); }
+ GtkWidget* GetAppMenuButton() { return wrench_menu_button_->widget(); }
BrowserActionsToolbarGtk* GetBrowserActionsToolbar() {
return actions_toolbar_.get();
@@ -92,11 +94,9 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
// Overridden from MenuGtk::Delegate:
virtual void StoppedShowing();
virtual GtkIconSet* GetIconSetForId(int idr);
+ virtual bool AlwaysShowImages();
- // Overridden from menus::SimpleMenuModel::Delegate:
- virtual bool IsCommandIdEnabled(int id) const;
- virtual bool IsCommandIdChecked(int id) const;
- virtual void ExecuteCommand(int id);
+ // Overridden from menus::AcceleratorProvider:
virtual bool GetAcceleratorForCommandId(int id,
menus::Accelerator* accelerator);
@@ -120,23 +120,6 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
virtual void ActiveWindowChanged(GdkWindow* active_window);
private:
- // Builds a toolbar button with all the properties set.
- // |spacing| is the width of padding (in pixels) on the left and right of the
- // button.
- CustomDrawButton* BuildToolbarButton(int normal_id,
- int active_id,
- int highlight_id,
- int depressed_id,
- int background_id,
- const std::string& localized_tooltip,
- const char* stock_id,
- int spacing);
-
- // Create a menu for the toolbar given the icon id and tooltip. Returns the
- // widget created.
- GtkWidget* BuildToolbarMenuButton(const std::string& localized_tooltip,
- OwnedWidgetGtk* owner);
-
// Connect/Disconnect signals for dragging a url onto the home button.
void SetUpDragForHomeButton(bool enable);
@@ -169,14 +152,14 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
guint, guint);
// Used to stop the upgrade notification animation.
- CHROMEGTK_CALLBACK_0(BrowserToolbarGtk, void, OnAppMenuShow);
+ CHROMEGTK_CALLBACK_0(BrowserToolbarGtk, void, OnWrenchMenuShow);
// Used to draw the upgrade notification badge.
- CHROMEGTK_CALLBACK_1(BrowserToolbarGtk, gboolean, OnAppMenuImageExpose,
+ CHROMEGTK_CALLBACK_1(BrowserToolbarGtk, gboolean, OnWrenchMenuButtonExpose,
GdkEventExpose*);
// Updates preference-dependent state.
- void NotifyPrefChanged(const std::wstring* pref);
+ void NotifyPrefChanged(const std::string* pref);
// Start the upgrade notification animation if we have detected an upgrade
// and the current toolbar is focused.
@@ -206,7 +189,6 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
// set their minimum sizes independently of |location_hbox_| which needs to
// grow/shrink in GTK+ mode.
GtkWidget* toolbar_left_;
- GtkWidget* toolbar_right_;
// Contains all the widgets of the location bar.
GtkWidget* location_hbox_;
@@ -219,18 +201,17 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
scoped_ptr<CustomDrawButton> home_;
scoped_ptr<ReloadButtonGtk> reload_;
scoped_ptr<BrowserActionsToolbarGtk> actions_toolbar_;
- OwnedWidgetGtk app_menu_button_;
+ scoped_ptr<CustomDrawButton> wrench_menu_button_;
- // Keep a pointer to the menu button image because we change it when the theme
- // changes.
- OwnedWidgetGtk app_menu_image_;
+ // The image shown in GTK+ mode in the wrench button.
+ GtkWidget* wrench_menu_image_;
// The model that contains the security level, text, icon to display...
ToolbarModel* model_;
GtkThemeProvider* theme_provider_;
- scoped_ptr<MenuGtk> app_menu_;
+ scoped_ptr<MenuGtk> wrench_menu_;
WrenchMenuModel wrench_menu_model_;
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index 4d8cf72..e6062c1 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -9,12 +9,10 @@
#include <string>
#include "app/gtk_util.h"
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "app/theme_provider.h"
#include "base/base_paths.h"
#include "base/command_line.h"
-#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
@@ -22,6 +20,7 @@
#include "base/singleton.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/app_modal_dialog_queue.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
@@ -29,7 +28,6 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
@@ -69,14 +67,17 @@
#include "chrome/browser/gtk/update_recommended_dialog.h"
#include "chrome/browser/location_bar.h"
#include "chrome/browser/page_info_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.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/themes/browser_theme_provider.h"
#include "chrome/browser/window_sizer.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/color_utils.h"
@@ -263,17 +264,23 @@ GdkColor SkColorToGdkColor(const SkColor& color) {
// A helper method for setting the GtkWindow size that should be used in place
// of calling gtk_window_resize directly. This is done to avoid a WM "feature"
-// where setting the window size to the screen size causes the WM to set the
+// where setting the window size to the monitor size causes the WM to set the
// EWMH for full screen mode.
-void SetWindowSize(GtkWindow* window, int width, int height) {
+void SetWindowSize(GtkWindow* window, const gfx::Size& size) {
GdkScreen* screen = gtk_window_get_screen(window);
- if (width >= gdk_screen_get_width(screen) &&
- height >= gdk_screen_get_height(screen)) {
- // Adjust the height so we don't trigger the WM feature.
- gtk_window_resize(window, width, height - 1);
- } else {
- gtk_window_resize(window, width, height);
+ gint num_monitors = gdk_screen_get_n_monitors(screen);
+ // Make sure the window doesn't match any monitor size. We compare against
+ // all monitors because we don't know which monitor the window is going to
+ // open on (the WM decides that).
+ for (gint i = 0; i < num_monitors; ++i) {
+ GdkRectangle monitor_size;
+ gdk_screen_get_monitor_geometry(screen, i, &monitor_size);
+ if (gfx::Size(monitor_size.width, monitor_size.height) == size) {
+ gtk_window_resize(window, size.width(), size.height() - 1);
+ return;
+ }
}
+ gtk_window_resize(window, size.width(), size.height());
}
GQuark GetBrowserWindowQuarkKey() {
@@ -293,8 +300,8 @@ bool ShouldExecuteReservedCommandImmediately(
// 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 >= base::VKEY_0 && vkey <= base::VKEY_9) ||
- (vkey >= base::VKEY_A && vkey <= base::VKEY_Z))
+ 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.
@@ -639,16 +646,19 @@ void BrowserWindowGtk::Show() {
gtk_widget_set_size_request(contents_container_->widget(), -1, -1);
}
-void BrowserWindowGtk::SetBoundsImpl(const gfx::Rect& bounds, bool exterior) {
+void BrowserWindowGtk::SetBoundsImpl(const gfx::Rect& bounds,
+ bool exterior,
+ bool move) {
gint x = static_cast<gint>(bounds.x());
gint y = static_cast<gint>(bounds.y());
gint width = static_cast<gint>(bounds.width());
gint height = static_cast<gint>(bounds.height());
- gtk_window_move(window_, x, y);
+ if (move)
+ gtk_window_move(window_, x, y);
if (exterior) {
- SetWindowSize(window_, width, height);
+ SetWindowSize(window_, gfx::Size(width, height));
} else {
gtk_widget_set_size_request(contents_container_->widget(),
width, height);
@@ -656,7 +666,7 @@ void BrowserWindowGtk::SetBoundsImpl(const gfx::Rect& bounds, bool exterior) {
}
void BrowserWindowGtk::SetBounds(const gfx::Rect& bounds) {
- SetBoundsImpl(bounds, true);
+ SetBoundsImpl(bounds, true, true);
}
void BrowserWindowGtk::Close() {
@@ -664,11 +674,6 @@ void BrowserWindowGtk::Close() {
if (!window_)
return;
- // Sometimes the tabstrip will get stuck thinking it's in a drag session.
- // Short of figuring out a repro case and actually solving the problem, this
- // is the best way to avoid an immortal window. See http://crbug.com/23733
- tabstrip_->CancelActiveDragSession();
-
if (!CanClose())
return;
@@ -711,6 +716,10 @@ void BrowserWindowGtk::Activate() {
gtk_window_present(window_);
}
+void BrowserWindowGtk::Deactivate() {
+ gdk_window_lower(GTK_WIDGET(window_)->window);
+}
+
bool BrowserWindowGtk::IsActive() const {
return is_active_;
}
@@ -738,10 +747,6 @@ void BrowserWindowGtk::SelectedTabToolbarSizeChanged(bool is_animating) {
// http://code.google.com/p/chromium/issues/detail?id=12291
}
-void BrowserWindowGtk::SelectedTabExtensionShelfSizeChanged() {
- NOTIMPLEMENTED();
-}
-
void BrowserWindowGtk::UpdateTitleBar() {
string16 title = browser_->GetWindowTitleForCurrentTab();
gtk_window_set_title(window_, UTF16ToUTF8(title).c_str());
@@ -815,7 +820,20 @@ void BrowserWindowGtk::SetFullscreen(bool fullscreen) {
if (fullscreen) {
gtk_window_fullscreen(window_);
} else {
+ // Work around a bug where if we try to unfullscreen, metacity immediately
+ // fullscreens us again. This is a little flickery and not necessary if
+ // there's a gnome-panel, but it's not easy to detect whether there's a
+ // panel or not.
+ std::string wm_name;
+ bool unmaximize_before_unfullscreen = IsMaximized() &&
+ x11_util::GetWindowManagerName(&wm_name) && wm_name == "Metacity";
+ if (unmaximize_before_unfullscreen)
+ UnMaximize();
+
gtk_window_unfullscreen(window_);
+
+ if (unmaximize_before_unfullscreen)
+ gtk_window_maximize(window_);
}
}
@@ -896,10 +914,6 @@ void BrowserWindowGtk::ToggleBookmarkBar() {
bookmark_utils::ToggleWhenVisible(browser_->profile());
}
-void BrowserWindowGtk::ToggleExtensionShelf() {
- NOTIMPLEMENTED();
-}
-
views::Window* BrowserWindowGtk::ShowAboutChromeDialog() {
ShowAboutDialogForProfile(window_, browser_->profile());
return NULL;
@@ -1009,7 +1023,11 @@ void BrowserWindowGtk::ShowPageInfo(Profile* profile,
const GURL& url,
const NavigationEntry::SSLStatus& ssl,
bool show_history) {
- browser::ShowPageInfo(window_, profile, url, ssl, show_history);
+ const CommandLine* command_line(CommandLine::ForCurrentProcess());
+ if (command_line->HasSwitch(switches::kEnableNewPageInfoBubble))
+ browser::ShowPageInfoBubble(window_, profile, url, ssl, show_history);
+ else
+ browser::ShowPageInfo(window_, profile, url, ssl, show_history);
}
void BrowserWindowGtk::ShowAppMenu() {
@@ -1115,6 +1133,22 @@ void BrowserWindowGtk::Paste() {
DoCutCopyPaste(this, &RenderViewHost::Paste, "paste-clipboard");
}
+void BrowserWindowGtk::ShowMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowGtk::HideMatchPreview() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+}
+
+gfx::Rect BrowserWindowGtk::GetMatchPreviewBounds() {
+ // TODO: implement me
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads() {
new DownloadInProgressDialogGtk(browser());
}
@@ -1128,7 +1162,7 @@ void BrowserWindowGtk::Observe(NotificationType type,
break;
case NotificationType::PREF_CHANGED: {
- std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ std::string* pref_name = Details<std::string>(details).ptr();
if (*pref_name == prefs::kUseCustomChromeFrame) {
UpdateCustomFrame();
} else {
@@ -1475,15 +1509,10 @@ void BrowserWindowGtk::SetGeometryHints() {
// For popup windows, we assume that if x == y == 0, the opening page
// did not specify a position. Let the WM position the popup instead.
bool is_popup = browser_->type() & Browser::TYPE_POPUP;
- bool popup_without_position = is_popup && bounds.x() == 0 && bounds.y() == 0;
- if (browser_->bounds_overridden() && !popup_without_position) {
- // For popups, bounds are set in terms of the client area rather than the
- // entire window.
- SetBoundsImpl(bounds, !is_popup);
- } else {
- // Ignore the position but obey the size.
- SetWindowSize(window_, bounds.width(), bounds.height());
- }
+ bool popup_without_position = is_popup &&
+ bounds.x() == 0 && bounds.y() == 0;
+ bool move = browser_->bounds_overridden() && !popup_without_position;
+ SetBoundsImpl(bounds, !is_popup, move);
}
void BrowserWindowGtk::ConnectHandlersToSignals() {
@@ -1737,27 +1766,27 @@ void BrowserWindowGtk::SaveWindowPosition() {
if (!g_browser_process->local_state())
return;
- std::wstring window_name = browser_->GetWindowPlacementKey();
+ std::string window_name = browser_->GetWindowPlacementKey();
DictionaryValue* window_preferences =
g_browser_process->local_state()->GetMutableDictionary(
window_name.c_str());
// Note that we store left/top for consistency with Windows, but that we
// *don't* obey them; we only use them for computing width/height. See
// comments in SetGeometryHints().
- window_preferences->SetInteger(L"left", restored_bounds_.x());
- window_preferences->SetInteger(L"top", restored_bounds_.y());
- window_preferences->SetInteger(L"right", restored_bounds_.right());
- window_preferences->SetInteger(L"bottom", restored_bounds_.bottom());
- window_preferences->SetBoolean(L"maximized", IsMaximized());
+ window_preferences->SetInteger("left", restored_bounds_.x());
+ window_preferences->SetInteger("top", restored_bounds_.y());
+ window_preferences->SetInteger("right", restored_bounds_.right());
+ window_preferences->SetInteger("bottom", restored_bounds_.bottom());
+ window_preferences->SetBoolean("maximized", IsMaximized());
scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_info_provider(
WindowSizer::CreateDefaultMonitorInfoProvider());
gfx::Rect work_area(
monitor_info_provider->GetMonitorWorkAreaMatching(restored_bounds_));
- window_preferences->SetInteger(L"work_area_left", work_area.x());
- window_preferences->SetInteger(L"work_area_top", work_area.y());
- window_preferences->SetInteger(L"work_area_right", work_area.right());
- window_preferences->SetInteger(L"work_area_bottom", work_area.bottom());
+ window_preferences->SetInteger("work_area_left", work_area.x());
+ window_preferences->SetInteger("work_area_top", work_area.y());
+ window_preferences->SetInteger("work_area_right", work_area.right());
+ window_preferences->SetInteger("work_area_bottom", work_area.bottom());
}
// static
@@ -1917,8 +1946,8 @@ gboolean BrowserWindowGtk::OnButtonPressEvent(GtkWidget* widget,
NULL);
guint32 click_time = event->time - last_click_time;
- int click_move_x = static_cast<int>(event->x - last_click_position.x());
- int click_move_y = static_cast<int>(event->y - last_click_position.y());
+ int click_move_x = abs(event->x - last_click_position.x());
+ int click_move_y = abs(event->y - last_click_position.y());
if (click_time > static_cast<guint32>(double_click_time) ||
click_move_x > double_click_distance ||
@@ -1927,9 +1956,7 @@ gboolean BrowserWindowGtk::OnButtonPressEvent(GtkWidget* widget,
// We do this to avoid triggering fullscreen mode in metacity
// (without the --no-force-fullscreen flag) and in compiz (with
// Legacy Fullscreen Mode enabled).
- GdkScreen* screen = gtk_window_get_screen(window_);
- if (bounds_.width() != gdk_screen_get_width(screen) ||
- bounds_.height() != gdk_screen_get_height(screen)) {
+ if (!BoundsMatchMonitorSize()) {
gtk_window_begin_move_drag(window_, event->button,
static_cast<gint>(event->x_root),
static_cast<gint>(event->y_root),
@@ -2110,6 +2137,17 @@ bool BrowserWindowGtk::UseCustomFrame() {
browser_->type() != Browser::TYPE_APP_POPUP;
}
+bool BrowserWindowGtk::BoundsMatchMonitorSize() {
+ // A screen can be composed of multiple monitors.
+ GdkScreen* screen = gtk_window_get_screen(window_);
+ gint monitor_num = gdk_screen_get_monitor_at_window(screen,
+ GTK_WIDGET(window_)->window);
+
+ GdkRectangle monitor_size;
+ gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor_size);
+ return bounds_.size() == gfx::Size(monitor_size.width, monitor_size.height);
+}
+
void BrowserWindowGtk::PlaceBookmarkBar(bool is_floating) {
GtkWidget* parent = gtk_widget_get_parent(bookmark_bar_->widget());
if (parent)
diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h
index 03b1af0..b032a96 100644
--- a/chrome/browser/gtk/browser_window_gtk.h
+++ b/chrome/browser/gtk/browser_window_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_BROWSER_WINDOW_GTK_H_
#define CHROME_BROWSER_GTK_BROWSER_WINDOW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -16,8 +17,8 @@
#include "base/timer.h"
#include "build/build_config.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/pref_member.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/rect.h"
@@ -52,13 +53,13 @@ class BrowserWindowGtk : public BrowserWindow,
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 SelectedTabExtensionShelfSizeChanged();
virtual void UpdateTitleBar();
virtual void ShelfVisibilityChanged();
virtual void UpdateDevTools();
@@ -86,7 +87,6 @@ class BrowserWindowGtk : public BrowserWindow,
virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
Profile* profile);
virtual void ToggleBookmarkBar();
- virtual void ToggleExtensionShelf();
virtual views::Window* ShowAboutChromeDialog();
virtual void ShowUpdateChromeDialog();
virtual void ShowTaskManager();
@@ -123,6 +123,9 @@ class BrowserWindowGtk : public BrowserWindow,
virtual void Copy();
virtual void Paste();
virtual void ToggleTabStripMode() {}
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
+ virtual gfx::Rect GetMatchPreviewBounds();
// Overridden from NotificationObserver:
virtual void Observe(NotificationType type,
@@ -262,9 +265,10 @@ class BrowserWindowGtk : public BrowserWindow,
void SaveWindowPosition();
// Set the bounds of the current window. If |exterior| is true, set the size
- // of the window itself, otherwise set the bounds of the web contents. In
- // either case, set the position of the window.
- void SetBoundsImpl(const gfx::Rect& bounds, bool exterior);
+ // of the window itself, otherwise set the bounds of the web contents.
+ // If |move| is true, set the position of the window, otherwise leave the
+ // position to the WM.
+ void SetBoundsImpl(const gfx::Rect& bounds, bool exterior, bool move);
// Callback for when the custom frame alignment needs to be redrawn.
// The content area includes the toolbar and web page but not the tab strip.
@@ -343,6 +347,9 @@ class BrowserWindowGtk : public BrowserWindow,
// Returns |true| if we should use the custom frame.
bool UseCustomFrame();
+ // Returns |true| if the window bounds match the monitor size.
+ bool BoundsMatchMonitorSize();
+
// Put the bookmark bar where it belongs.
void PlaceBookmarkBar(bool is_floating);
diff --git a/chrome/browser/gtk/cairo_cached_surface.h b/chrome/browser/gtk/cairo_cached_surface.h
index 0a2c256..b257062 100644
--- a/chrome/browser/gtk/cairo_cached_surface.h
+++ b/chrome/browser/gtk/cairo_cached_surface.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_CAIRO_CACHED_SURFACE_H_
#define CHROME_BROWSER_GTK_CAIRO_CACHED_SURFACE_H_
+#pragma once
typedef struct _GdkPixbuf GdkPixbuf;
typedef struct _cairo cairo_t;
diff --git a/chrome/browser/gtk/certificate_dialogs.h b/chrome/browser/gtk/certificate_dialogs.h
index 1890a4a..00f1fc1 100644
--- a/chrome/browser/gtk/certificate_dialogs.h
+++ b/chrome/browser/gtk/certificate_dialogs.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_CERTIFICATE_DIALOGS_H_
#define CHROME_BROWSER_GTK_CERTIFICATE_DIALOGS_H_
+#pragma once
#include <cert.h>
diff --git a/chrome/browser/gtk/certificate_manager.cc b/chrome/browser/gtk/certificate_manager.cc
index 51d1c7b..7a16b8c 100644
--- a/chrome/browser/gtk/certificate_manager.cc
+++ b/chrome/browser/gtk/certificate_manager.cc
@@ -20,8 +20,8 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/certificate_viewer.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/pref_member.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
@@ -49,7 +49,8 @@ std::string Stringize(char* nss_text) {
class CertificatePage {
public:
- explicit CertificatePage(psm::CertType type);
+ explicit CertificatePage(net::CertType type);
+ virtual ~CertificatePage() {}
void PopulateTree(CERTCertList* cert_list);
@@ -81,7 +82,7 @@ class CertificatePage {
GtkTreeSelection*);
CHROMEGTK_CALLBACK_0(CertificatePage, void, OnViewClicked);
- psm::CertType type_;
+ net::CertType type_;
// The top-level widget of this page.
GtkWidget* vbox_;
@@ -97,7 +98,7 @@ class CertificatePage {
////////////////////////////////////////////////////////////////////////////////
// CertificatePage implementation.
-CertificatePage::CertificatePage(psm::CertType type) : type_(type) {
+CertificatePage::CertificatePage(net::CertType type) : type_(type) {
vbox_ = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
gtk_container_set_border_width(GTK_CONTAINER(vbox_),
gtk_util::kContentAreaBorder);
@@ -110,7 +111,7 @@ CertificatePage::CertificatePage(psm::CertType type) : type_(type) {
IDS_CERT_MANAGER_UNKNOWN_TREE_DESCRIPTION,
};
DCHECK_EQ(arraysize(kDescriptionIds),
- static_cast<size_t>(psm::NUM_CERT_TYPES));
+ static_cast<size_t>(net::NUM_CERT_TYPES));
GtkWidget* description_label = gtk_label_new(l10n_util::GetStringUTF8(
kDescriptionIds[type]).c_str());
gtk_util::LeftAlignMisc(description_label);
@@ -139,8 +140,8 @@ CertificatePage::CertificatePage(psm::CertType type) : type_(type) {
gtk_tree_view_column_set_sort_column_id(name_col, CERT_NAME);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), name_col);
- if (type == psm::USER_CERT || type == psm::CA_CERT ||
- type == psm::UNKNOWN_CERT) {
+ if (type == net::USER_CERT || type == net::CA_CERT ||
+ type == net::UNKNOWN_CERT) {
GtkTreeViewColumn* device_col = gtk_tree_view_column_new_with_attributes(
l10n_util::GetStringUTF8(
IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL).c_str(),
@@ -151,7 +152,7 @@ CertificatePage::CertificatePage(psm::CertType type) : type_(type) {
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), device_col);
}
- if (type == psm::USER_CERT) {
+ if (type == net::USER_CERT) {
GtkTreeViewColumn* serial_col = gtk_tree_view_column_new_with_attributes(
l10n_util::GetStringUTF8(
IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL).c_str(),
@@ -162,8 +163,8 @@ CertificatePage::CertificatePage(psm::CertType type) : type_(type) {
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), serial_col);
}
- if (type == psm::USER_CERT || type == psm::EMAIL_CERT ||
- type == psm::SERVER_CERT) {
+ if (type == net::USER_CERT || type == net::EMAIL_CERT ||
+ type == net::SERVER_CERT) {
GtkTreeViewColumn* expires_col = gtk_tree_view_column_new_with_attributes(
l10n_util::GetStringUTF8(
IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL).c_str(),
@@ -174,7 +175,7 @@ CertificatePage::CertificatePage(psm::CertType type) : type_(type) {
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), expires_col);
}
- if (type == psm::EMAIL_CERT) {
+ if (type == net::EMAIL_CERT) {
GtkTreeViewColumn* addr_col = gtk_tree_view_column_new_with_attributes(
l10n_util::GetStringUTF8(
IDS_CERT_MANAGER_EMAIL_ADDRESS_COLUMN_LABEL).c_str(),
@@ -239,7 +240,7 @@ void CertificatePage::PopulateTree(CERTCertList* cert_list) {
!CERT_LIST_END(node, cert_list);
node = CERT_LIST_NEXT(node)) {
CERTCertificate* cert = node->cert;
- psm::CertType type = psm::GetCertType(cert);
+ net::CertType type = psm::GetCertType(cert);
if (type == type_) {
std::string org = Stringize(CERT_GetOrgName(&cert->subject));
if (org.empty())
@@ -349,7 +350,7 @@ void CertificatePage::OnViewClicked(GtkWidget* button) {
class CertificateManager {
public:
explicit CertificateManager(gfx::NativeWindow parent, Profile* profile);
- ~CertificateManager();
+ virtual ~CertificateManager();
// Shows the Tab corresponding to the specified |page|.
void ShowCertificatePage(CertificateManagerPage page);
@@ -386,11 +387,11 @@ void OnDestroy(GtkDialog* dialog, CertificateManager* cert_manager) {
CertificateManager::CertificateManager(gfx::NativeWindow parent,
Profile* profile)
- : user_page_(psm::USER_CERT),
- email_page_(psm::EMAIL_CERT),
- server_page_(psm::SERVER_CERT),
- ca_page_(psm::CA_CERT),
- unknown_page_(psm::UNKNOWN_CERT) {
+ : user_page_(net::USER_CERT),
+ email_page_(net::EMAIL_CERT),
+ server_page_(net::SERVER_CERT),
+ ca_page_(net::CA_CERT),
+ unknown_page_(net::UNKNOWN_CERT) {
// We don't need to observe changes in this value.
last_selected_page_.Init(prefs::kCertificateManagerWindowLastTabIndex,
profile->GetPrefs(), NULL);
diff --git a/chrome/browser/gtk/certificate_manager.h b/chrome/browser/gtk/certificate_manager.h
index 5587bcd..304fbe4 100644
--- a/chrome/browser/gtk/certificate_manager.h
+++ b/chrome/browser/gtk/certificate_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_CERTIFICATE_MANAGER_H_
#define CHROME_BROWSER_GTK_CERTIFICATE_MANAGER_H_
+#pragma once
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/gtk/certificate_viewer.cc b/chrome/browser/gtk/certificate_viewer.cc
index f8e13c0..a533060 100644
--- a/chrome/browser/gtk/certificate_viewer.cc
+++ b/chrome/browser/gtk/certificate_viewer.cc
@@ -17,7 +17,7 @@
#include "base/i18n/time_formatting.h"
#include "base/nss_util.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/certificate_dialogs.h"
@@ -52,27 +52,6 @@ std::string Stringize(char* nss_text) {
return s;
}
-// BreakHexLines will insert a newline character every 48 characters. For a hex
-// fingerprint with colons, that's every 128 bits.
-std::string BreakHexLines(const std::string& long_line) {
- static const std::string::size_type line_len = 48;
- if (long_line.size() <= line_len)
- return long_line;
-
- std::string ret;
- std::string::size_type offset = 0;
- while (offset < long_line.size()) {
- if (offset > 0)
- ret.append("\n");
- std::string::size_type todo = long_line.size() - offset;
- if (todo > line_len)
- todo = line_len;
- ret.append(long_line.data() + offset, todo);
- offset += todo;
- }
- return ret;
-}
-
// Hash a certificate using the given algorithm, return the result as a
// colon-seperated hex string. The len specified is the number of bytes
// required for storing the raw fingerprint.
@@ -91,7 +70,7 @@ std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
DCHECK(rv == SECSuccess);
fingerprint_item.data = fingerprint;
fingerprint_item.len = len;
- return BreakHexLines(Stringize(CERT_Hexify(&fingerprint_item, TRUE)));
+ return psm::ProcessRawBytes(&fingerprint_item);
}
std::string ProcessSecAlgorithm(SECAlgorithmID* algorithm_id) {
@@ -415,7 +394,7 @@ void CertificateViewer::FillTreeStoreWithCertFields(GtkTreeStore* store,
if (SEC_ASN1DecodeInteger(&cert->version, &version) == SECSuccess &&
version != ULONG_MAX)
version_str = l10n_util::GetStringFUTF8(IDS_CERT_DETAILS_VERSION_FORMAT,
- UintToString16(version + 1));
+ base::UintToString16(version + 1));
GtkTreeIter iter;
gtk_tree_store_append(store, &iter, &cert_iter);
gtk_tree_store_set(
diff --git a/chrome/browser/gtk/certificate_viewer.h b/chrome/browser/gtk/certificate_viewer.h
index 24e69b9..fdc905d 100644
--- a/chrome/browser/gtk/certificate_viewer.h
+++ b/chrome/browser/gtk/certificate_viewer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_CERTIFICATE_VIEWER_H_
#define CHROME_BROWSER_GTK_CERTIFICATE_VIEWER_H_
+#pragma once
#include "chrome/browser/certificate_viewer.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc
index 56384ba..2607359 100644
--- a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc
+++ b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc
@@ -7,14 +7,13 @@
#include <string>
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browsing_data_remover.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
@@ -46,9 +45,9 @@ ClearBrowsingDataDialogGtk::ClearBrowsingDataDialogGtk(GtkWindow* parent,
(GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
NULL);
- GtkWidget* close_button = gtk_dialog_add_button(GTK_DIALOG(dialog_),
- GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT);
- gtk_widget_grab_focus(close_button);
+ GtkWidget* cancel_button = gtk_dialog_add_button(GTK_DIALOG(dialog_),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
+ gtk_widget_grab_focus(cancel_button);
accessible_widget_helper_.reset(new AccessibleWidgetHelper(dialog_, profile));
accessible_widget_helper_->SendOpenWindowNotification(dialog_name);
@@ -189,6 +188,22 @@ ClearBrowsingDataDialogGtk::~ClearBrowsingDataDialogGtk() {
void ClearBrowsingDataDialogGtk::OnDialogResponse(GtkWidget* widget,
int response) {
if (response == GTK_RESPONSE_ACCEPT) {
+ PrefService* prefs = profile_->GetPrefs();
+ prefs->SetBoolean(prefs::kDeleteBrowsingHistory,
+ IsChecked(del_history_checkbox_));
+ prefs->SetBoolean(prefs::kDeleteDownloadHistory,
+ IsChecked(del_downloads_checkbox_));
+ prefs->SetBoolean(prefs::kDeleteCache,
+ IsChecked(del_cache_checkbox_));
+ prefs->SetBoolean(prefs::kDeleteCookies,
+ IsChecked(del_cookies_checkbox_));
+ prefs->SetBoolean(prefs::kDeletePasswords,
+ IsChecked(del_passwords_checkbox_));
+ prefs->SetBoolean(prefs::kDeleteFormData,
+ IsChecked(del_form_data_checkbox_));
+ prefs->SetInteger(prefs::kDeleteTimePeriod,
+ gtk_combo_box_get_active(GTK_COMBO_BOX(time_period_combobox_)));
+
int period_selected = gtk_combo_box_get_active(
GTK_COMBO_BOX(time_period_combobox_));
@@ -204,28 +219,6 @@ void ClearBrowsingDataDialogGtk::OnDialogResponse(GtkWidget* widget,
}
void ClearBrowsingDataDialogGtk::OnDialogWidgetClicked(GtkWidget* widget) {
- if (widget == del_history_checkbox_) {
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteBrowsingHistory,
- IsChecked(widget));
- } else if (widget == del_downloads_checkbox_) {
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteDownloadHistory,
- IsChecked(widget));
- } else if (widget == del_cache_checkbox_) {
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteCache,
- IsChecked(widget));
- } else if (widget == del_cookies_checkbox_) {
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteCookies,
- IsChecked(widget));
- } else if (widget == del_passwords_checkbox_) {
- profile_->GetPrefs()->SetBoolean(prefs::kDeletePasswords,
- IsChecked(widget));
- } else if (widget == del_form_data_checkbox_) {
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteFormData,
- IsChecked(widget));
- } else if (widget == time_period_combobox_) {
- profile_->GetPrefs()->SetInteger(prefs::kDeleteTimePeriod,
- gtk_combo_box_get_active(GTK_COMBO_BOX(widget)));
- }
UpdateDialogButtons();
}
diff --git a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h
index ba6e512..87a4546 100644
--- a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h
+++ b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_CLEAR_BROWSING_DATA_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_CLEAR_BROWSING_DATA_DIALOG_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "base/basictypes.h"
diff --git a/chrome/browser/gtk/collected_cookies_gtk.cc b/chrome/browser/gtk/collected_cookies_gtk.cc
index 1d83116..324593a 100644
--- a/chrome/browser/gtk/collected_cookies_gtk.cc
+++ b/chrome/browser/gtk/collected_cookies_gtk.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/gtk/collected_cookies_gtk.h"
-#include "app/gtk_util.h"
#include "app/l10n_util.h"
#include "chrome/browser/cookies_tree_model.h"
#include "chrome/browser/gtk/gtk_util.h"
@@ -14,8 +13,56 @@
#include "grit/generated_resources.h"
namespace {
-// Height of the cookie tree view.
+// Width and height of the cookie tree view.
+const int kTreeViewWidth = 450;
const int kTreeViewHeight = 150;
+
+// Padding within the banner box.
+const int kBannerPadding = 3;
+
+// Returns the text to display in the info bar when content settings were
+// created.
+const std::string GetInfobarLabel(ContentSetting setting,
+ bool multiple_domains_added,
+ const string16& domain_name) {
+ if (multiple_domains_added) {
+ switch (setting) {
+ case CONTENT_SETTING_BLOCK:
+ return l10n_util::GetStringUTF8(
+ IDS_COLLECTED_COOKIES_MULTIPLE_BLOCK_RULES_CREATED);
+
+ case CONTENT_SETTING_ALLOW:
+ return l10n_util::GetStringUTF8(
+ IDS_COLLECTED_COOKIES_MULTIPLE_ALLOW_RULES_CREATED);
+
+ case CONTENT_SETTING_SESSION_ONLY:
+ return l10n_util::GetStringUTF8(
+ IDS_COLLECTED_COOKIES_MULTIPLE_SESSION_RULES_CREATED);
+
+ default:
+ NOTREACHED();
+ return std::string();
+ }
+ }
+
+ switch (setting) {
+ case CONTENT_SETTING_BLOCK:
+ return l10n_util::GetStringFUTF8(
+ IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED, domain_name);
+
+ case CONTENT_SETTING_ALLOW:
+ return l10n_util::GetStringFUTF8(
+ IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED, domain_name);
+
+ case CONTENT_SETTING_SESSION_ONLY:
+ return l10n_util::GetStringFUTF8(
+ IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED, domain_name);
+
+ default:
+ NOTREACHED();
+ return std::string();
+ }
+}
} // namespace
CollectedCookiesGtk::CollectedCookiesGtk(GtkWindow* parent,
@@ -30,6 +77,9 @@ CollectedCookiesGtk::CollectedCookiesGtk(GtkWindow* parent,
}
void CollectedCookiesGtk::Init() {
+ HostContentSettingsMap* host_content_settings_map =
+ tab_contents_->profile()->GetHostContentSettingsMap();
+
dialog_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing);
gtk_box_set_spacing(GTK_BOX(dialog_), gtk_util::kContentAreaSpacing);
@@ -64,7 +114,7 @@ void CollectedCookiesGtk::Init() {
new gtk_tree::TreeAdapter(this, allowed_cookies_tree_model_.get()));
allowed_tree_ = gtk_tree_view_new_with_model(
GTK_TREE_MODEL(allowed_cookies_tree_adapter_->tree_store()));
- gtk_widget_set_size_request(allowed_tree_, -1, kTreeViewHeight);
+ gtk_widget_set_size_request(allowed_tree_, kTreeViewWidth, kTreeViewHeight);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(allowed_tree_), FALSE);
gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(allowed_tree_), TRUE);
gtk_container_add(GTK_CONTAINER(scroll_window), allowed_tree_);
@@ -100,15 +150,22 @@ void CollectedCookiesGtk::Init() {
G_CALLBACK(OnBlockAllowedButtonClickedThunk), this);
gtk_container_add(GTK_CONTAINER(button_box), block_allowed_cookie_button_);
+ GtkWidget* separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(dialog_), separator, TRUE, TRUE, 0);
+
// Blocked Cookie list.
cookie_list_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
gtk_box_pack_start(GTK_BOX(dialog_), cookie_list_vbox, TRUE, TRUE, 0);
label = gtk_label_new(
- l10n_util::GetStringUTF8(IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL).
- c_str());
+ l10n_util::GetStringUTF8(
+ host_content_settings_map->BlockThirdPartyCookies() ?
+ IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED :
+ IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL).c_str());
+ gtk_widget_set_size_request(label, kTreeViewWidth, -1);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(cookie_list_vbox), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(cookie_list_vbox), label, TRUE, TRUE, 0);
scroll_window = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window),
@@ -124,7 +181,7 @@ void CollectedCookiesGtk::Init() {
new gtk_tree::TreeAdapter(this, blocked_cookies_tree_model_.get()));
blocked_tree_ = gtk_tree_view_new_with_model(
GTK_TREE_MODEL(blocked_cookies_tree_adapter_->tree_store()));
- gtk_widget_set_size_request(blocked_tree_, -1, kTreeViewHeight);
+ gtk_widget_set_size_request(blocked_tree_, kTreeViewWidth, kTreeViewHeight);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(blocked_tree_), FALSE);
gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(blocked_tree_), TRUE);
gtk_container_add(GTK_CONTAINER(scroll_window), blocked_tree_);
@@ -167,6 +224,24 @@ void CollectedCookiesGtk::Init() {
gtk_container_add(GTK_CONTAINER(button_box),
for_session_blocked_cookie_button_);
+ // Infobar.
+ infobar_ = gtk_frame_new(NULL);
+ GtkWidget* infobar_contents = gtk_hbox_new(FALSE, kBannerPadding);
+ gtk_container_set_border_width(GTK_CONTAINER(infobar_contents),
+ kBannerPadding);
+ gtk_container_add(GTK_CONTAINER(infobar_), infobar_contents);
+ GtkWidget* info_image =
+ gtk_image_new_from_stock(GTK_STOCK_DIALOG_INFO,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_box_pack_start(GTK_BOX(infobar_contents), info_image, FALSE, FALSE, 0);
+ infobar_label_ = gtk_label_new(NULL);
+ gtk_box_pack_start(
+ GTK_BOX(infobar_contents), infobar_label_, FALSE, FALSE, 0);
+ gtk_widget_show_all(infobar_);
+ gtk_widget_set_no_show_all(infobar_, TRUE);
+ gtk_widget_hide(infobar_);
+ gtk_box_pack_start(GTK_BOX(dialog_), infobar_, TRUE, TRUE, 0);
+
// Close button.
button_box = gtk_hbutton_box_new();
gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_END);
@@ -260,6 +335,8 @@ void CollectedCookiesGtk::AddExceptions(GtkTreeSelection* selection,
GtkTreeModel* model;
GList* paths =
gtk_tree_selection_get_selected_rows(selection, &model);
+ string16 last_domain_name;
+ bool multiple_domains_added = false;
for (GList* item = paths; item; item = item->next) {
GtkTreeIter iter;
gtk_tree_model_get_iter(
@@ -267,12 +344,23 @@ void CollectedCookiesGtk::AddExceptions(GtkTreeSelection* selection,
CookieTreeOriginNode* node = static_cast<CookieTreeOriginNode*>(
adapter->GetNode(&iter));
if (node->CanCreateContentException()) {
+ if (!last_domain_name.empty())
+ multiple_domains_added = true;
+ last_domain_name = node->GetTitle();
node->CreateContentException(
tab_contents_->profile()->GetHostContentSettingsMap(), setting);
}
}
g_list_foreach(paths, reinterpret_cast<GFunc>(gtk_tree_path_free), NULL);
g_list_free(paths);
+ if (last_domain_name.empty()) {
+ gtk_widget_hide(infobar_);
+ } else {
+ gtk_label_set_text(
+ GTK_LABEL(infobar_label_), GetInfobarLabel(
+ setting, multiple_domains_added, last_domain_name).c_str());
+ gtk_widget_show(infobar_);
+ }
}
void CollectedCookiesGtk::OnBlockAllowedButtonClicked(GtkWidget* button) {
diff --git a/chrome/browser/gtk/collected_cookies_gtk.h b/chrome/browser/gtk/collected_cookies_gtk.h
index 2d8f2a0..be983c3 100644
--- a/chrome/browser/gtk/collected_cookies_gtk.h
+++ b/chrome/browser/gtk/collected_cookies_gtk.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_GTK_COLLECTED_COOKIES_GTK_H_
#define CHROME_BROWSER_GTK_COLLECTED_COOKIES_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -14,6 +15,7 @@
#include "chrome/browser/gtk/constrained_window_gtk.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/common/content_settings.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class CookiesTreeModel;
@@ -87,6 +89,10 @@ class CollectedCookiesGtk : public ConstrainedDialogDelegate,
GtkTreeSelection* allowed_selection_;
GtkTreeSelection* blocked_selection_;
+ // The infobar widget.
+ GtkWidget* infobar_;
+ GtkWidget* infobar_label_;
+
// The tab contents.
TabContents* tab_contents_;
diff --git a/chrome/browser/gtk/constrained_window_gtk.cc b/chrome/browser/gtk/constrained_window_gtk.cc
index 321aa16..b901083 100644
--- a/chrome/browser/gtk/constrained_window_gtk.cc
+++ b/chrome/browser/gtk/constrained_window_gtk.cc
@@ -16,7 +16,7 @@ ConstrainedWindowGtk::ConstrainedWindowGtk(
: owner_(owner),
delegate_(delegate),
visible_(false),
- accel_group_(gtk_accel_group_new()) {
+ factory_(this) {
DCHECK(owner);
DCHECK(delegate);
GtkWidget* dialog = delegate->GetWidgetRoot();
@@ -34,20 +34,14 @@ ConstrainedWindowGtk::ConstrainedWindowGtk(
gtk_container_add(GTK_CONTAINER(frame), alignment);
gtk_container_add(GTK_CONTAINER(ebox), frame);
border_.Own(ebox);
- ConnectAccelerators();
+
+ gtk_widget_add_events(widget(), GDK_KEY_PRESS_MASK);
+ g_signal_connect(widget(), "key-press-event", G_CALLBACK(OnKeyPressThunk),
+ this);
}
ConstrainedWindowGtk::~ConstrainedWindowGtk() {
border_.Destroy();
-
- gtk_accel_group_disconnect_key(accel_group_, GDK_Escape,
- static_cast<GdkModifierType>(0));
- if (ContainingView() && ContainingView()->GetTopLevelNativeWindow()) {
- gtk_window_remove_accel_group(
- GTK_WINDOW(ContainingView()->GetTopLevelNativeWindow()),
- accel_group_);
- }
- g_object_unref(accel_group_);
}
void ConstrainedWindowGtk::ShowConstrainedWindow() {
@@ -73,29 +67,18 @@ TabContentsViewGtk* ConstrainedWindowGtk::ContainingView() {
return static_cast<TabContentsViewGtk*>(owner_->view());
}
-void ConstrainedWindowGtk::ConnectAccelerators() {
- gtk_accel_group_connect(accel_group_,
- GDK_Escape, static_cast<GdkModifierType>(0),
- static_cast<GtkAccelFlags>(0),
- g_cclosure_new(G_CALLBACK(OnEscapeThunk),
- this, NULL));
- gtk_window_add_accel_group(
- GTK_WINDOW(ContainingView()->GetTopLevelNativeWindow()),
- accel_group_);
-}
-
-
-gboolean ConstrainedWindowGtk::OnEscape(GtkAccelGroup* group,
- GObject* acceleratable,
- guint keyval,
- GdkModifierType modifier) {
- // Handle this accelerator only if this is on the currently selected tab.
- Browser* browser = BrowserList::GetLastActive();
- if (!browser || browser->GetSelectedTabContents() != owner_)
- return FALSE;
+gboolean ConstrainedWindowGtk::OnKeyPress(GtkWidget* sender,
+ GdkEventKey* key) {
+ if (key->keyval == GDK_Escape) {
+ // Let the stack unwind so the event handler can release its ref
+ // on widget().
+ MessageLoop::current()->PostTask(FROM_HERE,
+ factory_.NewRunnableMethod(
+ &ConstrainedWindowGtk::CloseConstrainedWindow));
+ return TRUE;
+ }
- CloseConstrainedWindow();
- return TRUE;
+ return FALSE;
}
// static
@@ -104,4 +87,3 @@ ConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog(
ConstrainedWindowGtkDelegate* delegate) {
return new ConstrainedWindowGtk(parent, delegate);
}
-
diff --git a/chrome/browser/gtk/constrained_window_gtk.h b/chrome/browser/gtk/constrained_window_gtk.h
index 5015b45..117fd33 100644
--- a/chrome/browser/gtk/constrained_window_gtk.h
+++ b/chrome/browser/gtk/constrained_window_gtk.h
@@ -4,17 +4,18 @@
#ifndef CHROME_BROWSER_GTK_CONSTRAINED_WINDOW_GTK_H_
#define CHROME_BROWSER_GTK_CONSTRAINED_WINDOW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include "app/gtk_signal.h"
#include "base/basictypes.h"
+#include "base/task.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/tab_contents/constrained_window.h"
-#include "chrome/common/owned_widget_gtk.h"
class TabContents;
class TabContentsViewGtk;
-typedef struct _GtkWidget GtkWidget;
class ConstrainedWindowGtkDelegate {
public:
@@ -55,12 +56,9 @@ class ConstrainedWindowGtk : public ConstrainedWindow {
ConstrainedWindowGtk(TabContents* owner,
ConstrainedWindowGtkDelegate* delegate);
- // Connects the ESC accelerator to the window.
- void ConnectAccelerators();
-
- // Handles an ESC accelerator being pressed.
- CHROMEG_CALLBACK_3(ConstrainedWindowGtk, gboolean, OnEscape, GtkAccelGroup*,
- GObject*, guint, GdkModifierType);
+ // Handler for Escape.
+ CHROMEGTK_CALLBACK_1(ConstrainedWindowGtk, gboolean, OnKeyPress,
+ GdkEventKey*);
// The TabContents that owns and constrains this ConstrainedWindow.
TabContents* owner_;
@@ -74,7 +72,7 @@ class ConstrainedWindowGtk : public ConstrainedWindow {
// Stores if |ShowConstrainedWindow()| has been called.
bool visible_;
- GtkAccelGroup* accel_group_;
+ ScopedRunnableMethodFactory<ConstrainedWindowGtk> factory_;
DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowGtk);
};
diff --git a/chrome/browser/gtk/content_setting_bubble_gtk.cc b/chrome/browser/gtk/content_setting_bubble_gtk.cc
index f285fd8..116b3a3 100644
--- a/chrome/browser/gtk/content_setting_bubble_gtk.cc
+++ b/chrome/browser/gtk/content_setting_bubble_gtk.cc
@@ -6,6 +6,7 @@
#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/content_setting_bubble_model.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
@@ -13,14 +14,17 @@
#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/plugin_updater.h"
#include "chrome/browser/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_type.h"
+#include "chrome/common/plugin_group.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
+#include "webkit/glue/plugins/plugin_list.h"
// Padding between content and edge of info bubble.
static const int kContentBorder = 7;
@@ -79,6 +83,32 @@ void ContentSettingBubbleGtk::BuildBubble() {
gtk_box_pack_start(GTK_BOX(bubble_content), label, FALSE, FALSE, 0);
}
+ const std::set<std::string>& plugins = content.resource_identifiers;
+ if (!plugins.empty()) {
+ GtkWidget* list_content = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
+
+ for (std::set<std::string>::const_iterator it = plugins.begin();
+ it != plugins.end(); ++it) {
+ std::string name;
+ PluginUpdater::PluginMap groups;
+ PluginUpdater::GetPluginUpdater()->GetPluginGroups(&groups);
+ if (groups.find(*it) != groups.end())
+ name = UTF16ToUTF8(groups[*it]->GetGroupName());
+ else
+ name = *it;
+
+ GtkWidget* label = gtk_label_new(name.c_str());
+ GtkWidget* label_box = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(label_box), label, FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(list_content),
+ label_box,
+ FALSE, FALSE, 0);
+ }
+ gtk_box_pack_start(GTK_BOX(bubble_content), list_content, FALSE, FALSE,
+ gtk_util::kControlSpacing);
+ }
+
if (content_setting_bubble_model_->content_type() ==
CONTENT_SETTINGS_TYPE_POPUPS) {
const std::vector<ContentSettingBubbleModel::PopupItem>& popup_items =
@@ -197,6 +227,22 @@ void ContentSettingBubbleGtk::BuildBubble() {
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);
+ }
+
GtkWidget* bottom_box = gtk_hbox_new(FALSE, 0);
GtkWidget* manage_link =
@@ -281,3 +327,8 @@ void ContentSettingBubbleGtk::OnInfoLinkClicked(GtkWidget* button) {
content_setting_bubble_model_->OnInfoLinkClicked();
Close();
}
+
+void ContentSettingBubbleGtk::OnLoadPluginsLinkClicked(GtkWidget* button) {
+ content_setting_bubble_model_->OnLoadPluginsLinkClicked();
+ Close();
+}
diff --git a/chrome/browser/gtk/content_setting_bubble_gtk.h b/chrome/browser/gtk/content_setting_bubble_gtk.h
index 868eeb2..2fccd66 100644
--- a/chrome/browser/gtk/content_setting_bubble_gtk.h
+++ b/chrome/browser/gtk/content_setting_bubble_gtk.h
@@ -4,14 +4,15 @@
#ifndef CHROME_BROWSER_GTK_CONTENT_SETTING_BUBBLE_GTK_H_
#define CHROME_BROWSER_GTK_CONTENT_SETTING_BUBBLE_GTK_H_
+#pragma once
#include <map>
-#include <string>
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/info_bubble_gtk.h"
#include "chrome/common/content_settings_types.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class ContentSettingBubbleModel;
@@ -59,6 +60,7 @@ class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate,
CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnManageLinkClicked);
CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnClearLinkClicked);
CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnInfoLinkClicked);
+ CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnLoadPluginsLinkClicked);
// We position the bubble near this widget.
GtkWidget* anchor_;
@@ -87,6 +89,8 @@ 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 41eebda..bc4fc83 100644
--- a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
+++ b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
@@ -8,7 +8,8 @@
#include "app/gtk_util.h"
#include "app/l10n_util.h"
-#include "base/env_var.h"
+#include "base/environment.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/shell_integration.h"
@@ -187,10 +188,10 @@ void CreateApplicationShortcutsDialogGtk::CreateDesktopShortcut(
const ShellIntegration::ShortcutInfo& shortcut_info) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
std::string shortcut_template;
- if (ShellIntegration::GetDesktopShortcutTemplate(env_getter.get(),
+ if (ShellIntegration::GetDesktopShortcutTemplate(env.get(),
&shortcut_template)) {
ShellIntegration::CreateDesktopShortcut(shortcut_info,
shortcut_template);
diff --git a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h
index 71a1030..d0d39dc 100644
--- a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h
+++ b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h
@@ -1,14 +1,14 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_CREATE_APPLICATION_SHORTCUTS_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_CREATE_APPLICATION_SHORTCUTS_DIALOG_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "base/basictypes.h"
#include "base/ref_counted.h"
-#include "base/string16.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/shell_integration.h"
#include "googleurl/src/gurl.h"
@@ -32,7 +32,7 @@ class CreateApplicationShortcutsDialogGtk
CreateApplicationShortcutsDialogGtk(GtkWindow* parent,
TabContents* tab_contents);
- ~CreateApplicationShortcutsDialogGtk();
+ virtual ~CreateApplicationShortcutsDialogGtk();
CHROMEGTK_CALLBACK_1(CreateApplicationShortcutsDialogGtk, void,
OnCreateDialogResponse, int);
diff --git a/chrome/browser/gtk/custom_button.cc b/chrome/browser/gtk/custom_button.cc
index 3fee8da..08cd54d 100644
--- a/chrome/browser/gtk/custom_button.cc
+++ b/chrome/browser/gtk/custom_button.cc
@@ -1,12 +1,10 @@
-// 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.
#include "chrome/browser/gtk/custom_button.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "app/theme_provider.h"
#include "base/basictypes.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
@@ -19,15 +17,16 @@
#include "third_party/skia/include/core/SkBitmap.h"
CustomDrawButtonBase::CustomDrawButtonBase(GtkThemeProvider* theme_provider,
- int normal_id, int active_id, int highlight_id, int depressed_id,
- int background_id)
+ int normal_id,
+ int pressed_id,
+ int hover_id,
+ int disabled_id)
: background_image_(NULL),
paint_override_(-1),
normal_id_(normal_id),
- active_id_(active_id),
- highlight_id_(highlight_id),
- depressed_id_(depressed_id),
- button_background_id_(background_id),
+ pressed_id_(pressed_id),
+ hover_id_(hover_id),
+ disabled_id_(disabled_id),
theme_provider_(theme_provider),
flipped_(false) {
for (int i = 0; i < (GTK_STATE_INSENSITIVE + 1); ++i)
@@ -46,14 +45,14 @@ CustomDrawButtonBase::CustomDrawButtonBase(GtkThemeProvider* theme_provider,
// Load the button images from the resource bundle.
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
surfaces_[GTK_STATE_NORMAL]->UsePixbuf(
- normal_id ? rb.GetRTLEnabledPixbufNamed(normal_id) : NULL);
+ normal_id_ ? rb.GetRTLEnabledPixbufNamed(normal_id_) : NULL);
surfaces_[GTK_STATE_ACTIVE]->UsePixbuf(
- active_id ? rb.GetRTLEnabledPixbufNamed(active_id) : NULL);
+ pressed_id_ ? rb.GetRTLEnabledPixbufNamed(pressed_id_) : NULL);
surfaces_[GTK_STATE_PRELIGHT]->UsePixbuf(
- highlight_id ? rb.GetRTLEnabledPixbufNamed(highlight_id) : NULL);
+ hover_id_ ? rb.GetRTLEnabledPixbufNamed(hover_id_) : NULL);
surfaces_[GTK_STATE_SELECTED]->UsePixbuf(NULL);
surfaces_[GTK_STATE_INSENSITIVE]->UsePixbuf(
- depressed_id ? rb.GetRTLEnabledPixbufNamed(depressed_id) : NULL);
+ disabled_id_ ? rb.GetRTLEnabledPixbufNamed(disabled_id_) : NULL);
}
}
@@ -118,6 +117,10 @@ gboolean CustomDrawButtonBase::OnExpose(GtkWidget* widget,
cairo_destroy(cairo_context);
+ GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget));
+ if (child)
+ gtk_container_propagate_expose(GTK_CONTAINER(widget), child, e);
+
return TRUE;
}
@@ -144,24 +147,13 @@ void CustomDrawButtonBase::Observe(NotificationType type,
surfaces_[GTK_STATE_NORMAL]->UsePixbuf(normal_id_ ?
theme_provider_->GetRTLEnabledPixbufNamed(normal_id_) : NULL);
- surfaces_[GTK_STATE_ACTIVE]->UsePixbuf(active_id_ ?
- theme_provider_->GetRTLEnabledPixbufNamed(active_id_) : NULL);
- surfaces_[GTK_STATE_PRELIGHT]->UsePixbuf(highlight_id_ ?
- theme_provider_->GetRTLEnabledPixbufNamed(highlight_id_) : NULL);
+ surfaces_[GTK_STATE_ACTIVE]->UsePixbuf(pressed_id_ ?
+ theme_provider_->GetRTLEnabledPixbufNamed(pressed_id_) : NULL);
+ surfaces_[GTK_STATE_PRELIGHT]->UsePixbuf(hover_id_ ?
+ theme_provider_->GetRTLEnabledPixbufNamed(hover_id_) : NULL);
surfaces_[GTK_STATE_SELECTED]->UsePixbuf(NULL);
- surfaces_[GTK_STATE_INSENSITIVE]->UsePixbuf(depressed_id_ ?
- theme_provider_->GetRTLEnabledPixbufNamed(depressed_id_) : NULL);
-
- // Use the tinted background in some themes.
- if (button_background_id_) {
- SkColor color = theme_provider_->GetColor(
- BrowserThemeProvider::COLOR_BUTTON_BACKGROUND);
- SkBitmap* background = theme_provider_->GetBitmapNamed(
- IDR_THEME_BUTTON_BACKGROUND);
- SkBitmap* mask = theme_provider_->GetBitmapNamed(button_background_id_);
-
- SetBackground(color, background, mask);
- }
+ surfaces_[GTK_STATE_INSENSITIVE]->UsePixbuf(disabled_id_ ?
+ theme_provider_->GetRTLEnabledPixbufNamed(disabled_id_) : NULL);
}
CairoCachedSurface* CustomDrawButtonBase::PixbufForState(int state) {
@@ -194,9 +186,9 @@ void CustomDrawHoverController::Init(GtkWidget* widget) {
DCHECK(widget_ == NULL);
widget_ = widget;
g_signal_connect(widget_, "enter-notify-event",
- G_CALLBACK(OnEnter), this);
+ G_CALLBACK(OnEnterThunk), this);
g_signal_connect(widget_, "leave-notify-event",
- G_CALLBACK(OnLeave), this);
+ G_CALLBACK(OnLeaveThunk), this);
}
void CustomDrawHoverController::AnimationProgressed(
@@ -204,36 +196,32 @@ void CustomDrawHoverController::AnimationProgressed(
gtk_widget_queue_draw(widget_);
}
-// static
gboolean CustomDrawHoverController::OnEnter(
GtkWidget* widget,
- GdkEventCrossing* event,
- CustomDrawHoverController* controller) {
- controller->slide_animation_.Show();
+ GdkEventCrossing* event) {
+ slide_animation_.Show();
return FALSE;
}
-// static
gboolean CustomDrawHoverController::OnLeave(
GtkWidget* widget,
- GdkEventCrossing* event,
- CustomDrawHoverController* controller) {
+ GdkEventCrossing* event) {
// When the user is holding a mouse button, we don't want to animate.
if (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))
- controller->slide_animation_.Reset();
+ slide_animation_.Reset();
else
- controller->slide_animation_.Hide();
+ slide_animation_.Hide();
return FALSE;
}
// CustomDrawButton ------------------------------------------------------------
-CustomDrawButton::CustomDrawButton(int normal_id, int active_id,
- int highlight_id, int depressed_id)
- : button_base_(NULL, normal_id, active_id, highlight_id, depressed_id, 0),
- theme_provider_(NULL),
- gtk_stock_name_(NULL),
- icon_size_(GTK_ICON_SIZE_INVALID) {
+CustomDrawButton::CustomDrawButton(int normal_id,
+ int pressed_id,
+ int hover_id,
+ int disabled_id)
+ : button_base_(NULL, normal_id, pressed_id, hover_id, disabled_id),
+ theme_provider_(NULL) {
Init();
// Initialize the theme stuff with no theme_provider.
@@ -241,13 +229,35 @@ CustomDrawButton::CustomDrawButton(int normal_id, int active_id,
}
CustomDrawButton::CustomDrawButton(GtkThemeProvider* theme_provider,
- int normal_id, int active_id, int highlight_id, int depressed_id,
- int background_id, const char* stock_id, GtkIconSize stock_size)
- : button_base_(theme_provider, normal_id, active_id, highlight_id,
- depressed_id, background_id),
- theme_provider_(theme_provider),
- gtk_stock_name_(stock_id),
- icon_size_(stock_size) {
+ int normal_id,
+ int pressed_id,
+ int hover_id,
+ int disabled_id,
+ const char* stock_id,
+ GtkIconSize stock_size)
+ : button_base_(theme_provider, normal_id, pressed_id, hover_id,
+ disabled_id),
+ theme_provider_(theme_provider) {
+ native_widget_.Own(gtk_image_new_from_stock(stock_id, stock_size));
+
+ Init();
+
+ theme_provider_->InitThemesFor(this);
+ registrar_.Add(this,
+ NotificationType::BROWSER_THEME_CHANGED,
+ NotificationService::AllSources());
+}
+
+CustomDrawButton::CustomDrawButton(GtkThemeProvider* theme_provider,
+ int normal_id,
+ int pressed_id,
+ int hover_id,
+ int disabled_id,
+ GtkWidget* native_widget)
+ : button_base_(theme_provider, normal_id, pressed_id, hover_id,
+ disabled_id),
+ native_widget_(native_widget),
+ theme_provider_(theme_provider) {
Init();
theme_provider_->InitThemesFor(this);
@@ -258,13 +268,14 @@ CustomDrawButton::CustomDrawButton(GtkThemeProvider* theme_provider,
CustomDrawButton::~CustomDrawButton() {
widget_.Destroy();
+ native_widget_.Destroy();
}
void CustomDrawButton::Init() {
widget_.Own(gtk_chrome_button_new());
GTK_WIDGET_UNSET_FLAGS(widget(), GTK_CAN_FOCUS);
g_signal_connect(widget(), "expose-event",
- G_CALLBACK(OnCustomExpose), this);
+ G_CALLBACK(OnCustomExposeThunk), this);
hover_controller_.Init(widget());
}
@@ -291,38 +302,34 @@ void CustomDrawButton::SetBackground(SkColor color,
button_base_.SetBackground(color, image, mask);
}
-// static
-gboolean CustomDrawButton::OnCustomExpose(GtkWidget* widget,
- GdkEventExpose* e,
- CustomDrawButton* button) {
- if (button->theme_provider_ && button->theme_provider_->UseGtkTheme()) {
+gboolean CustomDrawButton::OnCustomExpose(GtkWidget* sender,
+ GdkEventExpose* e) {
+ if (UseGtkTheme()) {
// Continue processing this expose event.
return FALSE;
} else {
- double hover_state = button->hover_controller_.GetCurrentValue();
- return button->button_base_.OnExpose(widget, e, hover_state);
+ double hover_state = hover_controller_.GetCurrentValue();
+ return button_base_.OnExpose(sender, e, hover_state);
}
}
// static
CustomDrawButton* CustomDrawButton::CloseButton(
GtkThemeProvider* theme_provider) {
- CustomDrawButton* button = new CustomDrawButton(
- theme_provider, IDR_CLOSE_BAR, IDR_CLOSE_BAR_P,
- IDR_CLOSE_BAR_H, 0, 0, GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+ CustomDrawButton* button = new CustomDrawButton(theme_provider, IDR_CLOSE_BAR,
+ IDR_CLOSE_BAR_P, IDR_CLOSE_BAR_H, 0, GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
return button;
}
void CustomDrawButton::SetBrowserTheme() {
- bool use_gtk = theme_provider_ && theme_provider_->UseGtkTheme();
-
- if (use_gtk && gtk_stock_name_) {
- gtk_button_set_image(
- GTK_BUTTON(widget()),
- gtk_image_new_from_stock(gtk_stock_name_, icon_size_));
+ if (UseGtkTheme()) {
+ if (native_widget_.get())
+ gtk_button_set_image(GTK_BUTTON(widget()), native_widget_.get());
gtk_widget_set_size_request(widget(), -1, -1);
gtk_widget_set_app_paintable(widget(), FALSE);
} else {
+ if (native_widget_.get())
+ gtk_button_set_image(GTK_BUTTON(widget()), NULL);
gtk_widget_set_size_request(widget(), button_base_.Width(),
button_base_.Height());
@@ -330,5 +337,9 @@ void CustomDrawButton::SetBrowserTheme() {
}
gtk_chrome_button_set_use_gtk_rendering(
- GTK_CHROME_BUTTON(widget()), use_gtk);
+ GTK_CHROME_BUTTON(widget()), UseGtkTheme());
+}
+
+bool CustomDrawButton::UseGtkTheme() {
+ return theme_provider_ && theme_provider_->UseGtkTheme();
}
diff --git a/chrome/browser/gtk/custom_button.h b/chrome/browser/gtk/custom_button.h
index 7c79e42..4d19510 100644
--- a/chrome/browser/gtk/custom_button.h
+++ b/chrome/browser/gtk/custom_button.h
@@ -1,19 +1,19 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_CUSTOM_BUTTON_H_
#define CHROME_BROWSER_GTK_CUSTOM_BUTTON_H_
+#pragma once
#include <gtk/gtk.h>
-#include <string>
-
+#include "app/gtk_signal.h"
#include "app/slide_animation.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/rect.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -33,10 +33,9 @@ class CustomDrawButtonBase : public NotificationObserver {
// pass in NULL for |theme_provider|.
CustomDrawButtonBase(GtkThemeProvider* theme_provider,
int normal_id,
- int active_id,
- int highlight_id,
- int depressed_id,
- int background_id);
+ int pressed_id,
+ int hover_id,
+ int disabled_id);
~CustomDrawButtonBase();
@@ -78,10 +77,9 @@ class CustomDrawButtonBase : public NotificationObserver {
// We need to remember the image ids that the user passes in and the theme
// provider so we can reload images if the user changes theme.
int normal_id_;
- int active_id_;
- int highlight_id_;
- int depressed_id_;
- int button_background_id_;
+ int pressed_id_;
+ int hover_id_;
+ int disabled_id_;
GtkThemeProvider* theme_provider_;
// Whether the button is flipped horizontally. Not used for RTL (we get
@@ -115,10 +113,10 @@ class CustomDrawHoverController : public AnimationDelegate {
private:
virtual void AnimationProgressed(const Animation* animation);
- static gboolean OnEnter(GtkWidget* widget, GdkEventCrossing* event,
- CustomDrawHoverController* controller);
- static gboolean OnLeave(GtkWidget* widget, GdkEventCrossing* event,
- CustomDrawHoverController* controller);
+ CHROMEGTK_CALLBACK_1(CustomDrawHoverController, gboolean, OnEnter,
+ GdkEventCrossing*);
+ CHROMEGTK_CALLBACK_1(CustomDrawHoverController, gboolean, OnLeave,
+ GdkEventCrossing*);
SlideAnimation slide_animation_;
GtkWidget* widget_;
@@ -132,20 +130,29 @@ class CustomDrawButton : public NotificationObserver {
// The constructor takes 4 resource ids. If a resource doesn't exist for a
// button, pass in 0.
CustomDrawButton(int normal_id,
- int active_id,
- int highlight_id,
- int depressed_id);
+ int pressed_id,
+ int hover_id,
+ int disabled_id);
- // Same as above, but uses themed (and possibly tinted) images.
+ // Same as above, but uses themed (and possibly tinted) images. |stock_id| and
+ // |stock_size| are used for GTK+ theme mode.
CustomDrawButton(GtkThemeProvider* theme_provider,
int normal_id,
- int active_id,
- int highlight_id,
- int depressed_id,
- int background_id,
+ int pressed_id,
+ int hover_id,
+ int disabled_id,
const char* stock_id,
GtkIconSize stock_size);
+ // As above, but uses an arbitrary GtkImage rather than a stock icon. This
+ // constructor takes ownership of |native_widget|.
+ CustomDrawButton(GtkThemeProvider* theme_provider,
+ int normal_id,
+ int pressed_id,
+ int hover_id,
+ int disabled_id,
+ GtkWidget* native_widget);
+
~CustomDrawButton();
void Init();
@@ -189,10 +196,13 @@ class CustomDrawButton : public NotificationObserver {
// Sets the button to themed or not.
void SetBrowserTheme();
+ // Whether to use the GTK+ theme. For this to be true, we have to be in GTK+
+ // theme mode and we must have a valid stock icon resource.
+ bool UseGtkTheme();
+
// Callback for custom button expose, used to draw the custom graphics.
- static gboolean OnCustomExpose(GtkWidget* widget,
- GdkEventExpose* e,
- CustomDrawButton* obj);
+ CHROMEGTK_CALLBACK_1(CustomDrawButton, gboolean, OnCustomExpose,
+ GdkEventExpose*);
// The actual button widget.
OwnedWidgetGtk widget_;
@@ -201,13 +211,12 @@ class CustomDrawButton : public NotificationObserver {
CustomDrawHoverController hover_controller_;
+ // The widget to use when we are displaying in GTK+ theme mode.
+ OwnedWidgetGtk native_widget_;
+
// Our theme provider.
GtkThemeProvider* theme_provider_;
- // The stock icon name and size.
- const char* gtk_stock_name_;
- GtkIconSize icon_size_;
-
// Used to listen for theme change notifications.
NotificationRegistrar registrar_;
diff --git a/chrome/browser/gtk/custom_drag.h b/chrome/browser/gtk/custom_drag.h
index 1b7753e..90cfde1 100644
--- a/chrome/browser/gtk/custom_drag.h
+++ b/chrome/browser/gtk/custom_drag.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_CUSTOM_DRAG_H_
#define CHROME_BROWSER_GTK_CUSTOM_DRAG_H_
+#pragma once
#include <gtk/gtk.h>
#include <vector>
diff --git a/chrome/browser/gtk/dialogs_gtk.cc b/chrome/browser/gtk/dialogs_gtk.cc
index aaeebd3..e5aebbf 100644
--- a/chrome/browser/gtk/dialogs_gtk.cc
+++ b/chrome/browser/gtk/dialogs_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.
@@ -284,7 +284,7 @@ void SelectFileDialogImpl::AddFilters(GtkFileChooser* chooser) {
GtkFileFilter* filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*");
gtk_file_filter_set_name(filter,
- WideToUTF8(l10n_util::GetString(IDS_SAVEAS_ALL_FILES)).c_str());
+ l10n_util::GetStringUTF8(IDS_SAVEAS_ALL_FILES).c_str());
gtk_file_chooser_add_filter(chooser, filter);
}
}
diff --git a/chrome/browser/gtk/download_in_progress_dialog_gtk.cc b/chrome/browser/gtk/download_in_progress_dialog_gtk.cc
index 8ee6b30..8a41589 100644
--- a/chrome/browser/gtk/download_in_progress_dialog_gtk.cc
+++ b/chrome/browser/gtk/download_in_progress_dialog_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.
@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include "app/l10n_util.h"
+#include "base/string_number_conversions.h"
#include "base/string16.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
@@ -41,7 +42,8 @@ DownloadInProgressDialogGtk::DownloadInProgressDialogGtk(Browser* browser)
} else {
warning_text =
l10n_util::GetStringFUTF8(IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_WARNING,
- product_name, IntToString16(download_count));
+ product_name,
+ base::IntToString16(download_count));
explanation_text =
l10n_util::GetStringFUTF8(
IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_EXPLANATION, product_name);
diff --git a/chrome/browser/gtk/download_in_progress_dialog_gtk.h b/chrome/browser/gtk/download_in_progress_dialog_gtk.h
index 92532f3..86f736a 100644
--- a/chrome/browser/gtk/download_in_progress_dialog_gtk.h
+++ b/chrome/browser/gtk/download_in_progress_dialog_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_DOWNLOAD_IN_PROGRESS_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_DOWNLOAD_IN_PROGRESS_DIALOG_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "base/basictypes.h"
@@ -16,6 +17,9 @@ class DownloadInProgressDialogGtk {
public:
explicit DownloadInProgressDialogGtk(Browser* browser);
+ protected:
+ virtual ~DownloadInProgressDialogGtk() {}
+
private:
CHROMEGTK_CALLBACK_1(DownloadInProgressDialogGtk, void, OnResponse, int);
diff --git a/chrome/browser/gtk/download_item_gtk.cc b/chrome/browser/gtk/download_item_gtk.cc
index 6744af0..536d2b4 100644
--- a/chrome/browser/gtk/download_item_gtk.cc
+++ b/chrome/browser/gtk/download_item_gtk.cc
@@ -4,9 +4,7 @@
#include "chrome/browser/gtk/download_item_gtk.h"
-#include "app/gtk_util.h"
#include "app/l10n_util.h"
-#include "app/menus/simple_menu_model.h"
#include "app/resource_bundle.h"
#include "app/slide_animation.h"
#include "app/text_elider.h"
@@ -15,6 +13,7 @@
#include "base/histogram.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_item.h"
@@ -504,10 +503,11 @@ void DownloadItemGtk::LoadIcon() {
}
void DownloadItemGtk::UpdateTooltip() {
- std::wstring elided_filename = gfx::ElideFilename(
+ string16 elided_filename = gfx::ElideFilename(
get_download()->GetFileName(),
gfx::Font(), kTooltipMaxWidth);
- gtk_widget_set_tooltip_text(body_.get(), WideToUTF8(elided_filename).c_str());
+ gtk_widget_set_tooltip_text(body_.get(),
+ UTF16ToUTF8(elided_filename).c_str());
}
void DownloadItemGtk::UpdateNameLabel() {
@@ -515,7 +515,7 @@ void DownloadItemGtk::UpdateNameLabel() {
// use gfx::Font() to draw the text. This is why we need to add so
// much padding when we set the size request. We need to either use gfx::Font
// or somehow extend TextElider.
- std::wstring elided_filename = gfx::ElideFilename(
+ string16 elided_filename = gfx::ElideFilename(
get_download()->GetFileName(),
gfx::Font(), kTextWidth);
@@ -524,7 +524,7 @@ void DownloadItemGtk::UpdateNameLabel() {
gtk_util::SetLabelColor(name_label_, theme_provider_->UseGtkTheme() ?
NULL : &color);
gtk_label_set_text(GTK_LABEL(name_label_),
- WideToUTF8(elided_filename).c_str());
+ UTF16ToUTF8(elided_filename).c_str());
}
void DownloadItemGtk::UpdateStatusLabel(const std::string& status_text) {
@@ -561,16 +561,17 @@ void DownloadItemGtk::UpdateDangerWarning() {
if (dangerous_prompt_) {
// We create |dangerous_warning| as a wide string so we can more easily
// calculate its length in characters.
- std::wstring dangerous_warning;
+ string16 dangerous_warning;
if (get_download()->is_extension_install()) {
dangerous_warning =
- l10n_util::GetString(IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
+ l10n_util::GetStringUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
} else {
- std::wstring elided_filename = gfx::ElideFilename(
+ string16 elided_filename = gfx::ElideFilename(
get_download()->original_name(), gfx::Font(), kTextWidth);
dangerous_warning =
- l10n_util::GetStringF(IDS_PROMPT_DANGEROUS_DOWNLOAD, elided_filename);
+ l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
+ elided_filename);
}
if (theme_provider_->UseGtkTheme()) {
@@ -590,7 +591,7 @@ void DownloadItemGtk::UpdateDangerWarning() {
}
gtk_label_set_text(GTK_LABEL(dangerous_label_),
- WideToUTF8(dangerous_warning).c_str());
+ UTF16ToUTF8(dangerous_warning).c_str());
// Until we switch to vector graphics, force the font size.
gtk_util::ForceFontSizePixels(dangerous_label_, kTextSize);
@@ -781,15 +782,7 @@ gboolean DownloadItemGtk::OnExpose(GtkWidget* widget, GdkEventExpose* e) {
void DownloadItemGtk::OnClick(GtkWidget* widget) {
UMA_HISTOGRAM_LONG_TIMES("clickjacking.open_download",
base::Time::Now() - creation_time_);
-
- DownloadItem* download = get_download();
-
- if (download->state() == DownloadItem::IN_PROGRESS) {
- download->set_open_when_complete(
- !download->open_when_complete());
- } else if (download->state() == DownloadItem::COMPLETE) {
- download_util::OpenDownload(download);
- }
+ get_download()->OpenDownload();
}
gboolean DownloadItemGtk::OnProgressAreaExpose(GtkWidget* widget,
@@ -858,7 +851,7 @@ gboolean DownloadItemGtk::OnDangerousPromptExpose(GtkWidget* widget,
void DownloadItemGtk::OnDangerousAccept(GtkWidget* button) {
UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
base::Time::Now() - creation_time_);
- get_download()->manager()->DangerousDownloadValidated(get_download());
+ get_download()->DangerousDownloadValidated();
}
void DownloadItemGtk::OnDangerousDecline(GtkWidget* button) {
diff --git a/chrome/browser/gtk/download_item_gtk.h b/chrome/browser/gtk/download_item_gtk.h
index 1b793dc..5e4d64e 100644
--- a/chrome/browser/gtk/download_item_gtk.h
+++ b/chrome/browser/gtk/download_item_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_DOWNLOAD_ITEM_GTK_H_
#define CHROME_BROWSER_GTK_DOWNLOAD_ITEM_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -15,9 +16,9 @@
#include "base/time.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/icon_manager.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class BaseDownloadItemModel;
class DownloadShelfContextMenuGtk;
diff --git a/chrome/browser/gtk/download_shelf_gtk.h b/chrome/browser/gtk/download_shelf_gtk.h
index 35d7f3e..bd8ff0f 100644
--- a/chrome/browser/gtk/download_shelf_gtk.h
+++ b/chrome/browser/gtk/download_shelf_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_DOWNLOAD_SHELF_GTK_H_
#define CHROME_BROWSER_GTK_DOWNLOAD_SHELF_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -12,10 +13,10 @@
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/gtk/slide_animator_gtk.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/native_widget_types.h"
class BaseDownloadItemModel;
diff --git a/chrome/browser/gtk/edit_search_engine_dialog.cc b/chrome/browser/gtk/edit_search_engine_dialog.cc
index a91ad05..3c4c58a 100644
--- a/chrome/browser/gtk/edit_search_engine_dialog.cc
+++ b/chrome/browser/gtk/edit_search_engine_dialog.cc
@@ -77,6 +77,8 @@ EditSearchEngineDialog::EditSearchEngineDialog(
Init(parent_window, profile);
}
+EditSearchEngineDialog::~EditSearchEngineDialog() {}
+
void EditSearchEngineDialog::Init(GtkWindow* parent_window, Profile* profile) {
std::string dialog_name = l10n_util::GetStringUTF8(
controller_->template_url() ?
@@ -204,12 +206,12 @@ void EditSearchEngineDialog::Init(GtkWindow* parent_window, Profile* profile) {
l10n_util::GetStringUTF8(IDS_SEARCH_ENGINES_EDITOR_URL_DESCRIPTION_LABEL);
if (base::i18n::IsRTL()) {
const std::string reversed_percent("s%");
- std::wstring::size_type percent_index =
- description.find("%s", static_cast<std::string::size_type>(0));
- if (percent_index != std::string::npos)
+ std::string::size_type percent_index = description.find("%s");
+ if (percent_index != std::string::npos) {
description.replace(percent_index,
reversed_percent.length(),
reversed_percent);
+ }
}
GtkWidget* description_label = gtk_label_new(description.c_str());
@@ -227,12 +229,12 @@ void EditSearchEngineDialog::Init(GtkWindow* parent_window, Profile* profile) {
g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroyThunk), this);
}
-std::wstring EditSearchEngineDialog::GetTitleInput() const {
- return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(title_entry_)));
+string16 EditSearchEngineDialog::GetTitleInput() const {
+ return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(title_entry_)));
}
-std::wstring EditSearchEngineDialog::GetKeywordInput() const {
- return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(keyword_entry_)));
+string16 EditSearchEngineDialog::GetKeywordInput() const {
+ return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(keyword_entry_)));
}
std::string EditSearchEngineDialog::GetURLInput() const {
diff --git a/chrome/browser/gtk/edit_search_engine_dialog.h b/chrome/browser/gtk/edit_search_engine_dialog.h
index c7afbef..df5f308 100644
--- a/chrome/browser/gtk/edit_search_engine_dialog.h
+++ b/chrome/browser/gtk/edit_search_engine_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_EDIT_SEARCH_ENGINE_DIALOG_H_
#define CHROME_BROWSER_GTK_EDIT_SEARCH_ENGINE_DIALOG_H_
+#pragma once
#include <gtk/gtk.h>
#include <string>
@@ -11,6 +12,7 @@
#include "app/gtk_signal.h"
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
class AccessibleWidgetHelper;
class EditSearchEngineController;
@@ -24,14 +26,15 @@ class EditSearchEngineDialog {
const TemplateURL* template_url,
EditSearchEngineControllerDelegate* delegate,
Profile* profile);
+ virtual ~EditSearchEngineDialog();
private:
// Create and show the window.
void Init(GtkWindow* parent_window, Profile* profile);
// Retrieve the user input in the various fields.
- std::wstring GetTitleInput() const;
- std::wstring GetKeywordInput() const;
+ string16 GetTitleInput() const;
+ string16 GetKeywordInput() const;
std::string GetURLInput() const;
// Set sensitivity of buttons based on entry state.
diff --git a/chrome/browser/gtk/extension_infobar_gtk.cc b/chrome/browser/gtk/extension_infobar_gtk.cc
index cdc9561..7140afc 100644
--- a/chrome/browser/gtk/extension_infobar_gtk.cc
+++ b/chrome/browser/gtk/extension_infobar_gtk.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "gfx/gtk_util.h"
#include "grit/theme_resources.h"
@@ -46,14 +47,14 @@ void ExtensionInfoBarGtk::OnImageLoaded(
void ExtensionInfoBarGtk::BuildWidgets() {
// Start loading the image for the menu button.
- ExtensionResource icon_resource;
Extension* extension = delegate_->extension_host()->extension();
- Extension::Icons size =
- extension->GetIconPathAllowLargerSize(&icon_resource,
- Extension::EXTENSION_ICON_BITTY);
+ ExtensionResource icon_resource = extension->GetIconResource(
+ Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_EXACTLY);
if (!icon_resource.relative_path().empty()) {
// Create a tracker to load the image. It will report back on OnImageLoaded.
- tracker_.LoadImage(extension, icon_resource, gfx::Size(size, size),
+ tracker_.LoadImage(extension, icon_resource,
+ gfx::Size(Extension::EXTENSION_ICON_BITTY,
+ Extension::EXTENSION_ICON_BITTY),
ImageLoadingTracker::DONT_CACHE);
} else {
OnImageLoaded(NULL, icon_resource, 0); // |image|, |index|.
diff --git a/chrome/browser/gtk/extension_infobar_gtk.h b/chrome/browser/gtk/extension_infobar_gtk.h
index 2fff977..b727c04 100644
--- a/chrome/browser/gtk/extension_infobar_gtk.h
+++ b/chrome/browser/gtk/extension_infobar_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_EXTENSION_INFOBAR_GTK_H_
#define CHROME_BROWSER_GTK_EXTENSION_INFOBAR_GTK_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/extension_install_prompt2_gtk.cc b/chrome/browser/gtk/extension_install_prompt2_gtk.cc
index 106a0eb..6d7008c 100644
--- a/chrome/browser/gtk/extension_install_prompt2_gtk.cc
+++ b/chrome/browser/gtk/extension_install_prompt2_gtk.cc
@@ -4,9 +4,10 @@
#include <gtk/gtk.h>
+#include "app/gtk_util.h"
#include "app/l10n_util.h"
-#include "base/rand_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_install_ui.h"
@@ -21,7 +22,7 @@ class Profile;
namespace {
-const int kRightColumnWidth = 290;
+const int kRightColumnMinWidth = 290;
const int kImageSize = 69;
@@ -44,7 +45,7 @@ GtkWidget* MakeMarkupLabel(const char* format, const std::string& str) {
void OnDialogResponse(GtkDialog* dialog, int response_id,
ExtensionInstallUI::Delegate* delegate) {
if (response_id == GTK_RESPONSE_ACCEPT) {
- delegate->InstallUIProceed(false);
+ delegate->InstallUIProceed();
} else {
delegate->InstallUIAbort();
}
@@ -112,9 +113,9 @@ void ShowInstallPromptDialog2(GtkWindow* parent, SkBitmap* skia_icon,
IDS_EXTENSION_PROMPT2_WILL_HAVE_ACCESS_TO;
GtkWidget* warning_label = gtk_label_new(l10n_util::GetStringUTF8(
label).c_str());
- gtk_label_set_line_wrap(GTK_LABEL(warning_label), TRUE);
- gtk_widget_set_size_request(warning_label, kRightColumnWidth, -1);
gtk_misc_set_alignment(GTK_MISC(warning_label), 0.0, 0.5);
+ gtk_util::SetLabelWidth(warning_label, kRightColumnMinWidth);
+
gtk_box_pack_start(GTK_BOX(right_column_area), warning_label,
FALSE, FALSE, 0);
diff --git a/chrome/browser/gtk/extension_install_prompt_gtk.cc b/chrome/browser/gtk/extension_install_prompt_gtk.cc
index a0feb83..bcb7c0a 100644
--- a/chrome/browser/gtk/extension_install_prompt_gtk.cc
+++ b/chrome/browser/gtk/extension_install_prompt_gtk.cc
@@ -1,12 +1,15 @@
-// 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.
+//
+// Currently this file is only used for the uninstall prompt. The install prompt
+// code is in extension_install_prompt2_gtk.cc.
#include <gtk/gtk.h>
#include "app/l10n_util.h"
-#include "base/rand_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_install_ui.h"
@@ -20,27 +23,13 @@ class Profile;
namespace {
-const int kRightColumnWidth = 290;
-
// Left or right margin.
const int kPanelHorizMargin = 13;
-GtkWidget* MakeMarkupLabel(const char* format, const std::string& str) {
- GtkWidget* label = gtk_label_new(NULL);
- char* markup = g_markup_printf_escaped(format, str.c_str());
- gtk_label_set_markup(GTK_LABEL(label), markup);
- g_free(markup);
-
- // Left align it.
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
-
- return label;
-}
-
void OnDialogResponse(GtkDialog* dialog, int response_id,
ExtensionInstallUI::Delegate* delegate) {
if (response_id == GTK_RESPONSE_ACCEPT) {
- delegate->InstallUIProceed(false);
+ delegate->InstallUIProceed();
} else {
delegate->InstallUIAbort();
}
@@ -51,7 +40,6 @@ void OnDialogResponse(GtkDialog* dialog, int response_id,
void ShowInstallPromptDialog(GtkWindow* parent, SkBitmap* skia_icon,
Extension *extension,
ExtensionInstallUI::Delegate *delegate,
- const string16& warning_text,
ExtensionInstallUI::PromptType type) {
// Build the dialog.
int title_id = ExtensionInstallUI::kTitleIds[type];
@@ -85,21 +73,12 @@ void ShowInstallPromptDialog(GtkWindow* parent, SkBitmap* skia_icon,
gtk_box_pack_start(GTK_BOX(icon_hbox), right_column_area, TRUE, TRUE, 0);
int heading_id = ExtensionInstallUI::kHeadingIds[type];
- std::string heading_text = WideToUTF8(l10n_util::GetStringF(
- heading_id, UTF8ToWide(extension->name())));
- GtkWidget* heading_label = MakeMarkupLabel("<span weight=\"bold\">%s</span>",
- heading_text);
+ std::string heading_text = l10n_util::GetStringFUTF8(
+ heading_id, UTF8ToUTF16(extension->name()));
+ GtkWidget* heading_label = gtk_label_new(heading_text.c_str());
gtk_misc_set_alignment(GTK_MISC(heading_label), 0.0, 0.5);
- gtk_label_set_selectable(GTK_LABEL(heading_label), TRUE);
gtk_box_pack_start(GTK_BOX(right_column_area), heading_label, TRUE, TRUE, 0);
- GtkWidget* warning_label = gtk_label_new(UTF16ToUTF8(warning_text).c_str());
- gtk_label_set_line_wrap(GTK_LABEL(warning_label), TRUE);
- gtk_widget_set_size_request(warning_label, kRightColumnWidth, -1);
- gtk_misc_set_alignment(GTK_MISC(warning_label), 0.0, 0.5);
- gtk_label_set_selectable(GTK_LABEL(warning_label), TRUE);
- gtk_box_pack_start(GTK_BOX(right_column_area), warning_label, TRUE, TRUE, 0);
-
g_signal_connect(dialog, "response", G_CALLBACK(OnDialogResponse), delegate);
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
gtk_widget_show_all(dialog);
@@ -109,7 +88,7 @@ void ShowInstallPromptDialog(GtkWindow* parent, SkBitmap* skia_icon,
void ExtensionInstallUI::ShowExtensionInstallUIPromptImpl(
Profile* profile, Delegate* delegate, Extension* extension, SkBitmap* icon,
- const string16& warning_text, ExtensionInstallUI::PromptType type) {
+ ExtensionInstallUI::PromptType type) {
Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
if (!browser) {
delegate->InstallUIAbort();
@@ -123,6 +102,6 @@ void ExtensionInstallUI::ShowExtensionInstallUIPromptImpl(
return;
}
- ShowInstallPromptDialog(browser_window->window(), icon, extension,
- delegate, warning_text, type);
+ ShowInstallPromptDialog(browser_window->window(), icon, extension, delegate,
+ type);
}
diff --git a/chrome/browser/gtk/extension_installed_bubble_gtk.cc b/chrome/browser/gtk/extension_installed_bubble_gtk.cc
index 37a3c02..7d97f9a 100644
--- a/chrome/browser/gtk/extension_installed_bubble_gtk.cc
+++ b/chrome/browser/gtk/extension_installed_bubble_gtk.cc
@@ -8,6 +8,7 @@
#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.h"
#include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
#include "chrome/browser/gtk/browser_toolbar_gtk.h"
@@ -31,6 +32,12 @@ const int kIconSize = 43;
const int kTextColumnVerticalSpacing = 7;
const int kTextColumnWidth = 350;
+// When showing the bubble for a new browser action, we may have to wait for
+// the toolbar to finish animating to know where the item's final position
+// will be.
+const int kAnimationWaitRetries = 10;
+const int kAnimationWaitMS = 50;
+
// Padding between content and edge of info bubble.
const int kContentBorder = 7;
@@ -46,7 +53,8 @@ ExtensionInstalledBubbleGtk::ExtensionInstalledBubbleGtk(Extension *extension,
SkBitmap icon)
: extension_(extension),
browser_(browser),
- icon_(icon) {
+ icon_(icon),
+ animation_wait_retries_(kAnimationWaitRetries) {
AddRef(); // Balanced in Close().
if (extension_->browser_action()) {
@@ -90,16 +98,29 @@ void ExtensionInstalledBubbleGtk::ShowInternal() {
GtkWidget* reference_widget = NULL;
if (type_ == BROWSER_ACTION) {
- reference_widget = browser_window->GetToolbar()->GetBrowserActionsToolbar()
- ->GetBrowserActionWidget(extension_);
+ BrowserActionsToolbarGtk* toolbar =
+ browser_window->GetToolbar()->GetBrowserActionsToolbar();
+
+ if (toolbar->animating() && animation_wait_retries_-- > 0) {
+ MessageLoopForUI::current()->PostDelayedTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &ExtensionInstalledBubbleGtk::ShowInternal),
+ kAnimationWaitMS);
+ return;
+ }
+
+ reference_widget = toolbar->GetBrowserActionWidget(extension_);
// glib delays recalculating layout, but we need reference_widget to know
// its coordinates, so we force a check_resize here.
gtk_container_check_resize(GTK_CONTAINER(
browser_window->GetToolbar()->widget()));
// If the widget is not visible then browser_window could be incognito
- // with this extension disabled. Fall back to default position.
- if (reference_widget && !GTK_WIDGET_VISIBLE(reference_widget))
- reference_widget = NULL;
+ // with this extension disabled. Try showing it on the chevron.
+ // If that fails, fall back to default position.
+ if (reference_widget && !GTK_WIDGET_VISIBLE(reference_widget)) {
+ reference_widget = GTK_WIDGET_VISIBLE(toolbar->chevron()) ?
+ toolbar->chevron() : NULL;
+ }
} else if (type_ == PAGE_ACTION) {
LocationBarViewGtk* location_bar_view =
browser_window->GetToolbar()->GetLocationBarView();
@@ -158,9 +179,8 @@ void ExtensionInstalledBubbleGtk::ShowInternal() {
// Heading label
GtkWidget* heading_label = gtk_label_new(NULL);
- std::string heading_text = WideToUTF8(l10n_util::GetStringF(
- IDS_EXTENSION_INSTALLED_HEADING,
- UTF8ToWide(extension_->name())));
+ std::string heading_text = l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_INSTALLED_HEADING, UTF8ToUTF16(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);
@@ -172,9 +192,8 @@ void ExtensionInstalledBubbleGtk::ShowInternal() {
// Page action label
if (type_ == ExtensionInstalledBubbleGtk::PAGE_ACTION) {
- GtkWidget* info_label = gtk_label_new(
- WideToUTF8(l10n_util::GetString(
- IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO)).c_str());
+ GtkWidget* info_label = gtk_label_new(l10n_util::GetStringUTF8(
+ IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO).c_str());
gtk_label_set_line_wrap(GTK_LABEL(info_label), TRUE);
gtk_widget_set_size_request(info_label, kTextColumnWidth, -1);
gtk_box_pack_start(GTK_BOX(text_column), info_label, FALSE, FALSE, 0);
@@ -182,8 +201,8 @@ void ExtensionInstalledBubbleGtk::ShowInternal() {
// Manage label
GtkWidget* manage_label = gtk_label_new(
- WideToUTF8(l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_MANAGE_INFO,
- UTF8ToWide(extension_->name()))).c_str());
+ l10n_util::GetStringFUTF8(IDS_EXTENSION_INSTALLED_MANAGE_INFO,
+ UTF8ToUTF16(extension_->name())).c_str());
gtk_label_set_line_wrap(GTK_LABEL(manage_label), TRUE);
gtk_widget_set_size_request(manage_label, kTextColumnWidth, -1);
gtk_box_pack_start(GTK_BOX(text_column), manage_label, FALSE, FALSE, 0);
diff --git a/chrome/browser/gtk/extension_installed_bubble_gtk.h b/chrome/browser/gtk/extension_installed_bubble_gtk.h
index fc4680d..17b6672 100644
--- a/chrome/browser/gtk/extension_installed_bubble_gtk.h
+++ b/chrome/browser/gtk/extension_installed_bubble_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_EXTENSION_INSTALLED_BUBBLE_GTK_H_
#define CHROME_BROWSER_GTK_EXTENSION_INSTALLED_BUBBLE_GTK_H_
+#pragma once
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
@@ -79,6 +80,10 @@ class ExtensionInstalledBubbleGtk
NotificationRegistrar registrar_;
BubbleType type_;
+ // The number of times to retry showing the bubble if the browser action
+ // toolbar is animating.
+ int animation_wait_retries_;
+
// The 'x' that the user can press to hide the info bubble shelf.
scoped_ptr<CustomDrawButton> close_button_;
diff --git a/chrome/browser/gtk/extension_popup_gtk.h b/chrome/browser/gtk/extension_popup_gtk.h
index fcf7015..df983de 100644
--- a/chrome/browser/gtk/extension_popup_gtk.h
+++ b/chrome/browser/gtk/extension_popup_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_EXTENSION_POPUP_GTK_H_
#define CHROME_BROWSER_GTK_EXTENSION_POPUP_GTK_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "base/task.h"
diff --git a/chrome/browser/gtk/extension_view_gtk.h b/chrome/browser/gtk/extension_view_gtk.h
index 26dd8d1..5e5f436 100644
--- a/chrome/browser/gtk/extension_view_gtk.h
+++ b/chrome/browser/gtk/extension_view_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_EXTENSION_VIEW_GTK_H_
#define CHROME_BROWSER_GTK_EXTENSION_VIEW_GTK_H_
+#pragma once
#include "base/basictypes.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/gtk/external_protocol_dialog_gtk.cc b/chrome/browser/gtk/external_protocol_dialog_gtk.cc
index 2530d5b..2819fbb 100644
--- a/chrome/browser/gtk/external_protocol_dialog_gtk.cc
+++ b/chrome/browser/gtk/external_protocol_dialog_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.
@@ -113,10 +113,10 @@ void ExternalProtocolDialogGtk::OnDialogResponse(GtkWidget* widget,
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox_))) {
if (response == GTK_RESPONSE_ACCEPT) {
ExternalProtocolHandler::SetBlockState(
- UTF8ToWide(url_.scheme()), ExternalProtocolHandler::DONT_BLOCK);
+ url_.scheme(), ExternalProtocolHandler::DONT_BLOCK);
} else if (response == GTK_RESPONSE_REJECT) {
ExternalProtocolHandler::SetBlockState(
- UTF8ToWide(url_.scheme()), ExternalProtocolHandler::BLOCK);
+ url_.scheme(), ExternalProtocolHandler::BLOCK);
}
// If the response is GTK_RESPONSE_DELETE, triggered by the user closing
// the dialog, do nothing.
diff --git a/chrome/browser/gtk/external_protocol_dialog_gtk.h b/chrome/browser/gtk/external_protocol_dialog_gtk.h
index 9c2e6dd..0703bc8 100644
--- a/chrome/browser/gtk/external_protocol_dialog_gtk.h
+++ b/chrome/browser/gtk/external_protocol_dialog_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_EXTERNAL_PROTOCOL_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_EXTERNAL_PROTOCOL_DIALOG_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "base/time.h"
@@ -17,6 +18,9 @@ class ExternalProtocolDialogGtk {
public:
explicit ExternalProtocolDialogGtk(const GURL& url);
+ protected:
+ virtual ~ExternalProtocolDialogGtk() {}
+
private:
CHROMEGTK_CALLBACK_1(ExternalProtocolDialogGtk, void, OnDialogResponse, int);
diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc
index 2b43c83..47f9b0c 100644
--- a/chrome/browser/gtk/find_bar_gtk.cc
+++ b/chrome/browser/gtk/find_bar_gtk.cc
@@ -13,7 +13,9 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/find_bar_state.h"
@@ -31,6 +33,7 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
#include "gfx/gtk_util.h"
#include "grit/generated_resources.h"
@@ -240,7 +243,7 @@ void FindBarGtk::InitWidgets() {
find_next_button_.reset(new CustomDrawButton(theme_provider_,
IDR_FINDINPAGE_NEXT, IDR_FINDINPAGE_NEXT_H, IDR_FINDINPAGE_NEXT_H,
- IDR_FINDINPAGE_NEXT_P, 0, GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU));
+ IDR_FINDINPAGE_NEXT_P, GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU));
g_signal_connect(find_next_button_->widget(), "clicked",
G_CALLBACK(OnClicked), this);
gtk_widget_set_tooltip_text(find_next_button_->widget(),
@@ -250,7 +253,7 @@ void FindBarGtk::InitWidgets() {
find_previous_button_.reset(new CustomDrawButton(theme_provider_,
IDR_FINDINPAGE_PREV, IDR_FINDINPAGE_PREV_H, IDR_FINDINPAGE_PREV_H,
- IDR_FINDINPAGE_PREV_P, 0, GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU));
+ IDR_FINDINPAGE_PREV_P, GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU));
g_signal_connect(find_previous_button_->widget(), "clicked",
G_CALLBACK(OnClicked), this);
gtk_widget_set_tooltip_text(find_previous_button_->widget(),
@@ -308,6 +311,14 @@ void FindBarGtk::InitWidgets() {
gtk_widget_show(widget());
}
+FindBarController* FindBarGtk::GetFindBarController() const {
+ return find_bar_controller_;
+}
+
+void FindBarGtk::SetFindBarController(FindBarController* find_bar_controller) {
+ find_bar_controller_ = find_bar_controller;
+}
+
void FindBarGtk::Show(bool animate) {
if (animate) {
slide_widget_->Open();
@@ -384,8 +395,8 @@ void FindBarGtk::UpdateUIForFindResult(const FindNotificationDetails& result,
if (!find_text.empty() && have_valid_range) {
gtk_label_set_text(GTK_LABEL(match_count_label_),
l10n_util::GetStringFUTF8(IDS_FIND_IN_PAGE_COUNT,
- IntToString16(result.active_match_ordinal()),
- IntToString16(result.number_of_matches())).c_str());
+ base::IntToString16(result.active_match_ordinal()),
+ base::IntToString16(result.number_of_matches())).c_str());
UpdateMatchLabelAppearance(result.number_of_matches() == 0 &&
result.final_update());
} else {
@@ -866,10 +877,9 @@ gboolean FindBarGtk::OnExpose(GtkWidget* widget, GdkEventExpose* e,
GtkAllocation border_allocation = bar->border_bin_->allocation;
// Blit the left part of the background image once on the left.
- bool rtl = base::i18n::IsRTL();
- CairoCachedSurface* background_left = bar->theme_provider_->GetSurfaceNamed(
- rtl ? IDR_FIND_BOX_BACKGROUND_LEFT_RTL : IDR_FIND_BOX_BACKGROUND_LEFT,
- widget);
+ CairoCachedSurface* background_left =
+ bar->theme_provider_->GetRTLEnabledSurfaceNamed(
+ IDR_FIND_BOX_BACKGROUND_LEFT, widget);
background_left->SetSource(cr, border_allocation.x, border_allocation.y);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr, border_allocation.x, border_allocation.y,
diff --git a/chrome/browser/gtk/find_bar_gtk.h b/chrome/browser/gtk/find_bar_gtk.h
index 3de3dfd..ee9c0e5 100644
--- a/chrome/browser/gtk/find_bar_gtk.h
+++ b/chrome/browser/gtk/find_bar_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_FIND_BAR_GTK_H_
#define CHROME_BROWSER_GTK_FIND_BAR_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,10 +12,10 @@
#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/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/point.h"
class Browser;
@@ -40,12 +41,8 @@ class FindBarGtk : public FindBar,
GtkWidget* widget() const { return slide_widget_->widget(); }
// Methods from FindBar.
- virtual FindBarController* GetFindBarController() const {
- return find_bar_controller_;
- }
- virtual void SetFindBarController(FindBarController* find_bar_controller) {
- find_bar_controller_ = find_bar_controller;
- }
+ virtual FindBarController* GetFindBarController() const;
+ virtual void SetFindBarController(FindBarController* find_bar_controller);
virtual void Show(bool animate);
virtual void Hide(bool animate);
virtual void SetFocusAndSelection();
diff --git a/chrome/browser/gtk/first_run_bubble.cc b/chrome/browser/gtk/first_run_bubble.cc
index e169aca..fb23e14 100644
--- a/chrome/browser/gtk/first_run_bubble.cc
+++ b/chrome/browser/gtk/first_run_bubble.cc
@@ -8,10 +8,13 @@
#include "app/gtk_util.h"
#include "app/l10n_util.h"
+#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
-#include "chrome/browser/options_window.h"
+#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/search_engines/util.h"
#include "chrome/common/notification_service.h"
#include "gfx/gtk_util.h"
@@ -28,6 +31,10 @@ const int kButtonPadding = 4;
// Padding between content and edge of info bubble.
const int kContentBorder = 7;
+
+// Vertical spacing between labels.
+const int kInterLineSpacing = 5;
+
} // namespace
// static
@@ -35,7 +42,7 @@ void FirstRunBubble::Show(Profile* profile,
GtkWidget* anchor,
const gfx::Rect& rect,
FirstRun::BubbleType bubble_type) {
- new FirstRunBubble(profile, anchor, rect);
+ new FirstRunBubble(profile, anchor, rect, bubble_type);
}
void FirstRunBubble::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
@@ -63,60 +70,81 @@ void FirstRunBubble::Observe(NotificationType type,
FirstRunBubble::FirstRunBubble(Profile* profile,
GtkWidget* anchor,
- const gfx::Rect& rect)
+ const gfx::Rect& rect,
+ FirstRun::BubbleType bubble_type)
: profile_(profile),
theme_provider_(GtkThemeProvider::GetFrom(profile_)),
anchor_(anchor),
content_(NULL),
bubble_(NULL) {
+ content_ = gtk_vbox_new(FALSE, kInterLineSpacing);
+ gtk_container_set_border_width(GTK_CONTAINER(content_), kContentBorder);
+ g_signal_connect(content_, "destroy",
+ G_CALLBACK(&HandleDestroyThunk), this);
+
+ int width_resource = 0;
+ if (bubble_type == FirstRun::LARGE_BUBBLE) {
+ width_resource = IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS;
+ InitializeContentForLarge();
+ } else if (bubble_type == FirstRun::OEM_BUBBLE) {
+ width_resource = IDS_FIRSTRUNOEMBUBBLE_DIALOG_WIDTH_CHARS;
+ InitializeContentForOEM();
+ } else if (bubble_type == FirstRun::MINIMAL_BUBBLE) {
+ width_resource = IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_WIDTH_CHARS;
+ InitializeContentForMinimal();
+ } else {
+ NOTREACHED();
+ }
+
+ InitializeLabels(width_resource);
+
+ InfoBubbleGtk::ArrowLocationGtk arrow_location =
+ !base::i18n::IsRTL() ?
+ InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT :
+ InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT;
+ bubble_ = InfoBubbleGtk::Show(anchor_,
+ &rect,
+ content_,
+ arrow_location,
+ true, // match_system_theme
+ true, // grab_input
+ theme_provider_,
+ this); // delegate
+ if (!bubble_) {
+ NOTREACHED();
+ return;
+ }
+
+ registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
+ NotificationService::AllSources());
+ theme_provider_->InitThemesFor(this);
+}
+
+FirstRunBubble::~FirstRunBubble() {
+}
+
+void FirstRunBubble::InitializeContentForLarge() {
GtkWidget* label1 = gtk_label_new(NULL);
labels_.push_back(label1);
char* markup = g_markup_printf_escaped(kSearchLabelMarkup,
l10n_util::GetStringUTF8(IDS_FR_BUBBLE_TITLE).c_str());
gtk_label_set_markup(GTK_LABEL(label1), markup);
g_free(markup);
- gtk_misc_set_alignment(GTK_MISC(label1), 0, .5);
- // TODO(erg): Theme these colors.
- gtk_widget_modify_fg(label1, GTK_STATE_NORMAL, &gfx::kGdkBlack);
GtkWidget* label2 = gtk_label_new(
l10n_util::GetStringUTF8(IDS_FR_BUBBLE_SUBTEXT).c_str());
labels_.push_back(label2);
- gtk_misc_set_alignment(GTK_MISC(label2), 0, .5);
- gtk_label_set_line_wrap(GTK_LABEL(label2), TRUE);
- gtk_widget_modify_fg(label2, GTK_STATE_NORMAL, &gfx::kGdkBlack);
string16 search_engine = GetDefaultSearchEngineName(profile_);
GtkWidget* label3 = gtk_label_new(
l10n_util::GetStringFUTF8(IDS_FR_BUBBLE_QUESTION, search_engine).c_str());
labels_.push_back(label3);
- gtk_misc_set_alignment(GTK_MISC(label3), 0, .5);
- gtk_label_set_line_wrap(GTK_LABEL(label3), TRUE);
- gtk_widget_modify_fg(label3, GTK_STATE_NORMAL, &gfx::kGdkBlack);
GtkWidget* keep_button = gtk_button_new_with_label(
l10n_util::GetStringFUTF8(IDS_FR_BUBBLE_OK, search_engine).c_str());
GtkWidget* change_button = gtk_button_new_with_label(
l10n_util::GetStringUTF8(IDS_FR_BUBBLE_CHANGE).c_str());
- content_ = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(content_), kContentBorder);
-
- // We compute the widget's size using the anchor widget -- |content_| is
- // unrealized at this point.
- int width = -1, height = -1;
- gtk_util::GetWidgetSizeFromResources(
- anchor_,
- IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS,
- IDS_FIRSTRUNBUBBLE_DIALOG_HEIGHT_LINES,
- &width, &height);
- // Resize the labels so that they don't wrap more than necessary. We leave
- // |content_| unsized so that it'll expand as needed to hold the other
- // widgets -- the buttons may be wider than |width| on high-DPI displays.
- gtk_widget_set_size_request(label1, width, -1);
- gtk_widget_set_size_request(label2, width, -1);
- gtk_widget_set_size_request(label3, width, -1);
-
gtk_box_pack_start(GTK_BOX(content_), label1, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(content_), label2, FALSE, FALSE, 0);
// Leave an empty line.
@@ -135,33 +163,48 @@ FirstRunBubble::FirstRunBubble(Profile* profile,
// We want the focus to start on the keep entry, not on the change button.
gtk_widget_grab_focus(keep_button);
- InfoBubbleGtk::ArrowLocationGtk arrow_location =
- !base::i18n::IsRTL() ?
- InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT :
- InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT;
- bubble_ = InfoBubbleGtk::Show(anchor_,
- &rect,
- content_,
- arrow_location,
- true, // match_system_theme
- true, // grab_input
- theme_provider_,
- this); // delegate
- if (!bubble_) {
- NOTREACHED();
- return;
- }
-
- g_signal_connect(content_, "destroy",
- G_CALLBACK(&HandleDestroyThunk), this);
g_signal_connect(keep_button, "clicked",
G_CALLBACK(&HandleKeepButtonThunk), this);
g_signal_connect(change_button, "clicked",
G_CALLBACK(&HandleChangeButtonThunk), this);
+}
- registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
- NotificationService::AllSources());
- theme_provider_->InitThemesFor(this);
+void FirstRunBubble::InitializeContentForOEM() {
+ NOTIMPLEMENTED() << "Falling back to minimal bubble";
+ InitializeContentForMinimal();
+}
+
+void FirstRunBubble::InitializeContentForMinimal() {
+ GtkWidget* label1 = gtk_label_new(NULL);
+ labels_.push_back(label1);
+ char* markup = g_markup_printf_escaped(kSearchLabelMarkup,
+ l10n_util::GetStringFUTF8(
+ IDS_FR_SE_BUBBLE_TITLE,
+ GetDefaultSearchEngineName(profile_)).c_str());
+ gtk_label_set_markup(GTK_LABEL(label1), markup);
+ g_free(markup);
+
+ GtkWidget* label2 =
+ gtk_label_new(l10n_util::GetStringUTF8(IDS_FR_BUBBLE_SUBTEXT).c_str());
+ labels_.push_back(label2);
+
+ gtk_box_pack_start(GTK_BOX(content_), label1, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(content_), label2, FALSE, FALSE, 0);
+}
+
+void FirstRunBubble::InitializeLabels(int width_resource) {
+ int width = -1;
+
+ gtk_util::GetWidgetSizeFromResources(
+ anchor_, width_resource, 0, &width, NULL);
+
+ for (size_t i = 0; i < labels_.size(); ++i) {
+ // Resize the labels so that they don't wrap more than necessary. We leave
+ // |content_| unsized so that it'll expand as needed to hold the other
+ // widgets -- the buttons may be wider than |width| on high-DPI displays.
+ gtk_util::SetLabelWidth(labels_[i], width);
+ gtk_misc_set_alignment(GTK_MISC(labels_[i]), 0, 0.5);
+ }
}
void FirstRunBubble::HandleDestroy(GtkWidget* sender) {
@@ -171,10 +214,11 @@ void FirstRunBubble::HandleDestroy(GtkWidget* sender) {
void FirstRunBubble::HandleKeepButton(GtkWidget* sender) {
bubble_->Close();
-
}
+
void FirstRunBubble::HandleChangeButton(GtkWidget* sender) {
bubble_->Close();
- ShowOptionsWindow(OPTIONS_PAGE_GENERAL, OPTIONS_GROUP_DEFAULT_SEARCH,
- profile_);
+ Browser* browser = BrowserList::GetLastActive();
+ DCHECK(browser);
+ browser->OpenSearchEngineOptionsDialog();
}
diff --git a/chrome/browser/gtk/first_run_bubble.h b/chrome/browser/gtk/first_run_bubble.h
index 31355d0..211ae68 100644
--- a/chrome/browser/gtk/first_run_bubble.h
+++ b/chrome/browser/gtk/first_run_bubble.h
@@ -8,13 +8,14 @@
#ifndef CHROME_BROWSER_GTK_FIRST_RUN_BUBBLE_H_
#define CHROME_BROWSER_GTK_FIRST_RUN_BUBBLE_H_
+#pragma once
#include <gtk/gtk.h>
#include <vector>
#include "base/basictypes.h"
-#include "chrome/browser/first_run.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"
@@ -43,8 +44,18 @@ class FirstRunBubble : public InfoBubbleGtkDelegate,
private:
FirstRunBubble(Profile* profile,
GtkWidget* anchor,
- const gfx::Rect& rect);
- ~FirstRunBubble() { }
+ const gfx::Rect& rect,
+ FirstRun::BubbleType bubble_type);
+ virtual ~FirstRunBubble();
+
+ // Create and pack widgets for different bubble types.
+ void InitializeContentForLarge();
+ void InitializeContentForOEM();
+ void InitializeContentForMinimal();
+
+ // Contains some common set up for the labels in the bubble. |width| is a
+ // resource that holds the desired width for the labels.
+ void InitializeLabels(int width_resource);
CHROMEGTK_CALLBACK_0(FirstRunBubble, void, HandleDestroy);
CHROMEGTK_CALLBACK_0(FirstRunBubble, void, HandleKeepButton);
diff --git a/chrome/browser/gtk/first_run_dialog.cc b/chrome/browser/gtk/first_run_dialog.cc
index 7c5eae7..c30da15 100644
--- a/chrome/browser/gtk/first_run_dialog.cc
+++ b/chrome/browser/gtk/first_run_dialog.cc
@@ -6,181 +6,380 @@
#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/importer/importer_data_types.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/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/shell_integration.h"
+#include "chrome/common/pref_names.h"
#include "chrome/installer/util/google_update_settings.h"
+#include "gfx/gtk_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
#if defined(USE_LINUX_BREAKPAD)
#include "chrome/app/breakpad_linux.h"
#endif
+namespace {
+
+const gchar* kSearchEngineKey = "template-url-search-engine";
+
+// Height of the label that displays the search engine's logo (in lieu of the
+// actual logo) in chromium.
+const int kLogoLabelHeight = 100;
+
+// Size of the small logo (for when we show 4 search engines).
+const int kLogoLabelWidthSmall = 132;
+const int kLogoLabelHeightSmall = 88;
+
+// The number of search engine options we normally show. It may be less than
+// this number if there are not enough search engines for the current locale,
+// or more if the user's imported default is not one of the top search engines
+// for the current locale.
+const size_t kNormalBallotSize = 3;
+
+// The width of the explanatory label. The 180 is the width of the large images.
+const int kExplanationWidth = kNormalBallotSize * 180;
+
+// Horizontal spacing between search engine choices.
+const int kSearchEngineSpacing = 6;
+
+// Set the (x, y) coordinates of the welcome message (which floats on top of
+// the omnibox image at the top of the first run dialog).
+void SetWelcomePosition(GtkFloatingContainer* container,
+ GtkAllocation* allocation,
+ GtkWidget* label) {
+ GValue value = { 0, };
+ g_value_init(&value, G_TYPE_INT);
+
+ GtkRequisition req;
+ gtk_widget_size_request(label, &req);
+
+ int x = base::i18n::IsRTL() ?
+ allocation->width - req.width - gtk_util::kContentAreaSpacing :
+ gtk_util::kContentAreaSpacing;
+ g_value_set_int(&value, x);
+ gtk_container_child_set_property(GTK_CONTAINER(container),
+ label, "x", &value);
+
+ int y = allocation->height / 2 - req.height / 2;
+ g_value_set_int(&value, y);
+ gtk_container_child_set_property(GTK_CONTAINER(container),
+ label, "y", &value);
+ g_value_unset(&value);
+}
+
+} // namespace
+
// static
bool FirstRunDialog::Show(Profile* profile,
- ProcessSingleton* process_singleton) {
+ bool randomize_search_engine_order) {
int response = -1;
// Object deletes itself.
- FirstRunDialog* first_run = new FirstRunDialog(profile, response);
-
- // Prevent further launches of Chrome until First Run UI is done.
- process_singleton->Lock(GTK_WINDOW(first_run->dialog_));
+ new FirstRunDialog(profile, randomize_search_engine_order, response);
// TODO(port): it should be sufficient to just run the dialog:
// int response = gtk_dialog_run(GTK_DIALOG(dialog));
// but that spins a nested message loop and hoses us. :(
// http://code.google.com/p/chromium/issues/detail?id=12552
// Instead, run a loop and extract the response manually.
- g_signal_connect(first_run->dialog_, "response",
- G_CALLBACK(OnResponseDialogThunk), first_run);
- gtk_widget_show_all(first_run->dialog_);
MessageLoop::current()->Run();
- process_singleton->Unlock();
return (response == GTK_RESPONSE_ACCEPT);
}
-FirstRunDialog::FirstRunDialog(Profile* profile, int& response)
- : dialog_(NULL), report_crashes_(NULL), make_default_(NULL),
- import_data_(NULL), import_profile_(NULL), profile_(profile),
- response_(response), importer_host_(new ImporterHost()) {
+FirstRunDialog::FirstRunDialog(Profile* profile,
+ bool randomize_search_engine_order,
+ int& response)
+ : search_engine_window_(NULL),
+ dialog_(NULL),
+ report_crashes_(NULL),
+ make_default_(NULL),
+ profile_(profile),
+ chosen_search_engine_(NULL),
+ response_(response) {
+ search_engines_model_ = profile_->GetTemplateURLModel();
+ ShowSearchEngineWindow();
+
+ search_engines_model_->AddObserver(this);
+ if (search_engines_model_->loaded())
+ OnTemplateURLModelChanged();
+ else
+ search_engines_model_->Load();
+}
+
+FirstRunDialog::~FirstRunDialog() {
+}
+
+void FirstRunDialog::ShowSearchEngineWindow() {
+ search_engine_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_deletable(GTK_WINDOW(search_engine_window_), FALSE);
+ gtk_window_set_title(
+ GTK_WINDOW(search_engine_window_),
+ l10n_util::GetStringUTF8(IDS_FIRSTRUN_DLG_TITLE).c_str());
+ gtk_window_set_resizable(GTK_WINDOW(search_engine_window_), FALSE);
+ g_signal_connect(search_engine_window_, "destroy",
+ G_CALLBACK(OnSearchEngineWindowDestroyThunk), this);
+ GtkWidget* content_area = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(search_engine_window_), content_area);
+
+ GdkPixbuf* pixbuf =
+ ResourceBundle::GetSharedInstance().GetRTLEnabledPixbufNamed(
+ IDR_SEARCH_ENGINE_DIALOG_TOP);
+ GtkWidget* top_image = gtk_image_new_from_pixbuf(pixbuf);
+ // Right align the image.
+ gtk_misc_set_alignment(GTK_MISC(top_image), 1, 0);
+ gtk_widget_set_size_request(top_image, 0, -1);
+
+ GtkWidget* welcome_message = gtk_util::CreateBoldLabel(
+ l10n_util::GetStringUTF8(IDS_FR_SEARCH_MAIN_LABEL));
+ // Force the font size to make sure the label doesn't overlap the image.
+ // 13.4px == 10pt @ 96dpi
+ gtk_util::ForceFontSizePixels(welcome_message, 13.4);
+
+ GtkWidget* top_area = gtk_floating_container_new();
+ gtk_container_add(GTK_CONTAINER(top_area), top_image);
+ gtk_floating_container_add_floating(GTK_FLOATING_CONTAINER(top_area),
+ welcome_message);
+ g_signal_connect(top_area, "set-floating-position",
+ G_CALLBACK(SetWelcomePosition), welcome_message);
+
+ gtk_box_pack_start(GTK_BOX(content_area), top_area,
+ FALSE, FALSE, 0);
+
+ GtkWidget* bubble_area_background = gtk_event_box_new();
+ gtk_widget_modify_bg(bubble_area_background,
+ GTK_STATE_NORMAL, &gfx::kGdkWhite);
+
+ GtkWidget* bubble_area_box = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(bubble_area_box),
+ gtk_util::kContentAreaSpacing);
+ gtk_container_add(GTK_CONTAINER(bubble_area_background),
+ bubble_area_box);
+
+ GtkWidget* explanation = gtk_label_new(
+ l10n_util::GetStringFUTF8(IDS_FR_SEARCH_TEXT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)).c_str());
+ gtk_misc_set_alignment(GTK_MISC(explanation), 0, 0.5);
+ gtk_util::SetLabelColor(explanation, &gfx::kGdkBlack);
+ gtk_util::SetLabelWidth(explanation, kExplanationWidth);
+ gtk_box_pack_start(GTK_BOX(bubble_area_box), explanation, FALSE, FALSE, 0);
+
+ // We will fill this in after the TemplateURLModel has loaded.
+ // GtkHButtonBox because we want all children to have the same size.
+ search_engine_hbox_ = gtk_hbutton_box_new();
+ gtk_box_set_spacing(GTK_BOX(search_engine_hbox_), kSearchEngineSpacing);
+ gtk_box_pack_start(GTK_BOX(bubble_area_box), search_engine_hbox_,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(content_area), bubble_area_background,
+ TRUE, TRUE, 0);
+
+ gtk_widget_show_all(content_area);
+ gtk_window_present(GTK_WINDOW(search_engine_window_));
+}
+
+void FirstRunDialog::ShowDialog() {
+ // The purpose of the dialog is to ask the user to enable stats and crash
+ // reporting. This setting may be controlled through configuration management
+ // in enterprise scenarios. If that is the case, skip the dialog entirely,
+ // it's not worth bothering the user for only the default browser question
+ // (which is likely to be forced in enterprise deployments anyway).
+ const PrefService::Preference* metrics_reporting_pref =
+ g_browser_process->local_state()->FindPreference(
+ prefs::kMetricsReportingEnabled);
+ if (metrics_reporting_pref && metrics_reporting_pref->IsManaged()) {
+ OnResponseDialog(NULL, GTK_RESPONSE_ACCEPT);
+ return;
+ }
+
+#if defined(GOOGLE_CHROME_BUILD)
dialog_ = gtk_dialog_new_with_buttons(
l10n_util::GetStringUTF8(IDS_FIRSTRUN_DLG_TITLE).c_str(),
NULL, // No parent
(GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
- GTK_STOCK_QUIT,
- GTK_RESPONSE_REJECT,
NULL);
gtk_util::AddButtonToDialog(dialog_,
l10n_util::GetStringUTF8(IDS_FIRSTRUN_DLG_OK).c_str(),
GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT);
+ gtk_window_set_deletable(GTK_WINDOW(dialog_), FALSE);
- // Normally we would do the following:
- // gtk_widget_realize(dialog_);
- // gtk_util::SetWindowSizeFromResources(GTK_WINDOW(dialog_),
- // IDS_FIRSTRUN_DIALOG_WIDTH_CHARS,
- // -1,
- // false); // resizable
- // But because the first run dialog has extra widgets in Windows, the
- // resources specify a dialog that is way too big. So instead in just this
- // one case we let GTK size the dialog itself and just mark it non-resizable
- // manually:
gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
g_signal_connect(dialog_, "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), NULL);
GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
- gtk_box_set_spacing(GTK_BOX(content_area), 18);
- GtkWidget* vbox = gtk_vbox_new(FALSE, 12);
+ make_default_ = gtk_check_button_new_with_label(
+ l10n_util::GetStringUTF8(IDS_FR_CUSTOMIZE_DEFAULT_BROWSER).c_str());
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(make_default_), TRUE);
+ gtk_box_pack_start(GTK_BOX(content_area), make_default_, FALSE, FALSE, 0);
-#if defined(GOOGLE_CHROME_BUILD)
+ report_crashes_ = gtk_check_button_new();
GtkWidget* check_label = gtk_label_new(
l10n_util::GetStringUTF8(IDS_OPTIONS_ENABLE_LOGGING).c_str());
gtk_label_set_line_wrap(GTK_LABEL(check_label), TRUE);
+ gtk_container_add(GTK_CONTAINER(report_crashes_), check_label);
+ GtkWidget* learn_more_vbox = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(learn_more_vbox), report_crashes_,
+ FALSE, FALSE, 0);
GtkWidget* learn_more_link = gtk_chrome_link_button_new(
l10n_util::GetStringUTF8(IDS_LEARN_MORE).c_str());
- // Stick it in an hbox so it doesn't expand to the whole width.
- GtkWidget* learn_more_hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(learn_more_hbox),
+ gtk_button_set_alignment(GTK_BUTTON(learn_more_link), 0.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(learn_more_vbox),
gtk_util::IndentWidget(learn_more_link),
FALSE, FALSE, 0);
g_signal_connect(learn_more_link, "clicked",
G_CALLBACK(OnLearnMoreLinkClickedThunk), this);
- report_crashes_ = gtk_check_button_new();
- gtk_container_add(GTK_CONTAINER(report_crashes_), check_label);
+ gtk_box_pack_start(GTK_BOX(content_area), learn_more_vbox, FALSE, FALSE, 0);
+
+ g_signal_connect(dialog_, "response",
+ G_CALLBACK(OnResponseDialogThunk), this);
+ gtk_widget_show_all(dialog_);
+#else // !defined(GOOGLE_CHROME_BUILD)
+ // We don't show the dialog in chromium. Pretend the user accepted.
+ OnResponseDialog(NULL, GTK_RESPONSE_ACCEPT);
+#endif // !defined(GOOGLE_CHROME_BUILD)
+}
+
+void FirstRunDialog::OnTemplateURLModelChanged() {
+ // We only watch the search engine model change once, on load. Remove
+ // observer so we don't try to redraw if engines change under us.
+ search_engines_model_->RemoveObserver(this);
+
+ // Add search engines in |search_engines_model_| to buttons list.
+ std::vector<const TemplateURL*> ballot_engines =
+ search_engines_model_->GetTemplateURLs();
+ // Drop any not in the first 3.
+ if (ballot_engines.size() > kNormalBallotSize)
+ ballot_engines.resize(kNormalBallotSize);
- GtkWidget* report_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
- gtk_box_pack_start(GTK_BOX(report_vbox), report_crashes_, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(report_vbox), learn_more_hbox, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), report_vbox, FALSE, FALSE, 0);
+ const TemplateURL* default_search_engine =
+ search_engines_model_->GetDefaultSearchProvider();
+ if (std::find(ballot_engines.begin(),
+ ballot_engines.end(),
+ default_search_engine) ==
+ ballot_engines.end()) {
+ ballot_engines.push_back(default_search_engine);
+ }
+
+ std::string choose_text = l10n_util::GetStringUTF8(IDS_FR_SEARCH_CHOOSE);
+ for (std::vector<const TemplateURL*>::iterator search_engine_iter =
+ ballot_engines.begin();
+ search_engine_iter < ballot_engines.end();
+ ++search_engine_iter) {
+ // Create a container for the search engine widgets.
+ GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
+
+ // We show text on Chromium and images on Google Chrome.
+ bool show_images = false;
+#if defined(GOOGLE_CHROME_BUILD)
+ show_images = true;
#endif
- make_default_ = gtk_check_button_new_with_label(
- l10n_util::GetStringUTF8(IDS_FR_CUSTOMIZE_DEFAULT_BROWSER).c_str());
- gtk_box_pack_start(GTK_BOX(vbox), make_default_, FALSE, FALSE, 0);
-
- GtkWidget* combo_hbox = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
- import_data_ = gtk_check_button_new_with_label(
- l10n_util::GetStringUTF8(IDS_FR_CUSTOMIZE_IMPORT).c_str());
- gtk_box_pack_start(GTK_BOX(combo_hbox), import_data_, FALSE, FALSE, 0);
- import_profile_ = gtk_combo_box_new_text();
- gtk_box_pack_start(GTK_BOX(combo_hbox), import_profile_, TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), combo_hbox, FALSE, FALSE, 0);
-
- // Detect any supported browsers that we can import from and fill
- // up the combo box. If none found, disable import data checkbox.
- 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(import_profile_),
- WideToUTF8(profile).c_str());
+ // Create the image (maybe).
+ int logo_id = (*search_engine_iter)->logo_id();
+ if (show_images && logo_id > 0) {
+ GdkPixbuf* pixbuf =
+ ResourceBundle::GetSharedInstance().GetPixbufNamed(logo_id);
+ if (ballot_engines.size() > kNormalBallotSize) {
+ pixbuf = gdk_pixbuf_scale_simple(pixbuf,
+ kLogoLabelWidthSmall,
+ kLogoLabelHeightSmall,
+ GDK_INTERP_HYPER);
+ } else {
+ g_object_ref(pixbuf);
+ }
+
+ GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
+ gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 0);
+ g_object_unref(pixbuf);
+ } else {
+ GtkWidget* logo_label = gtk_label_new(NULL);
+ char* markup = g_markup_printf_escaped(
+ "<span weight='bold' size='x-large' color='black'>%s</span>",
+ WideToUTF8((*search_engine_iter)->short_name()).c_str());
+ gtk_label_set_markup(GTK_LABEL(logo_label), markup);
+ g_free(markup);
+ gtk_widget_set_size_request(logo_label, -1,
+ ballot_engines.size() > kNormalBallotSize ? kLogoLabelHeightSmall :
+ kLogoLabelHeight);
+ gtk_box_pack_start(GTK_BOX(vbox), logo_label, FALSE, FALSE, 0);
}
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(import_data_), TRUE);
- gtk_combo_box_set_active(GTK_COMBO_BOX(import_profile_), 0);
- } else {
- gtk_combo_box_append_text(GTK_COMBO_BOX(import_profile_),
- l10n_util::GetStringUTF8(IDS_IMPORT_NO_PROFILE_FOUND).c_str());
- gtk_combo_box_set_active(GTK_COMBO_BOX(import_profile_), 0);
- gtk_widget_set_sensitive(import_data_, FALSE);
- gtk_widget_set_sensitive(import_profile_, FALSE);
+
+ // Create the button.
+ GtkWidget* button = gtk_button_new_with_label(choose_text.c_str());
+ g_signal_connect(button, "clicked",
+ G_CALLBACK(OnSearchEngineButtonClickedThunk), this);
+ g_object_set_data(G_OBJECT(button), kSearchEngineKey,
+ const_cast<TemplateURL*>(*search_engine_iter));
+
+ GtkWidget* button_centerer = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(button_centerer), button, TRUE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), button_centerer, FALSE, FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(search_engine_hbox_), vbox);
+ gtk_widget_show_all(search_engine_hbox_);
}
+}
- gtk_box_pack_start(GTK_BOX(content_area), vbox, FALSE, FALSE, 0);
+void FirstRunDialog::OnSearchEngineButtonClicked(GtkWidget* sender) {
+ chosen_search_engine_ = static_cast<TemplateURL*>(
+ g_object_get_data(G_OBJECT(sender), kSearchEngineKey));
+ gtk_widget_destroy(search_engine_window_);
+}
+
+void FirstRunDialog::OnSearchEngineWindowDestroy(GtkWidget* sender) {
+ search_engine_window_ = NULL;
+ if (chosen_search_engine_) {
+ search_engines_model_->SetDefaultSearchProvider(chosen_search_engine_);
+ ShowDialog();
+ } else {
+ FirstRunDone();
+ }
}
void FirstRunDialog::OnResponseDialog(GtkWidget* widget, int response) {
- bool import_started = false;
- gtk_widget_hide_all(dialog_);
+ if (dialog_)
+ gtk_widget_hide_all(dialog_);
response_ = response;
- if (response == GTK_RESPONSE_ACCEPT) {
- // Mark that first run has ran.
- FirstRun::CreateSentinel();
+ // Mark that first run has ran.
+ FirstRun::CreateSentinel();
- // Check if user has opted into reporting.
- if (report_crashes_ &&
- gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(report_crashes_))) {
+ // Check if user has opted into reporting.
+ if (report_crashes_ &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(report_crashes_))) {
#if defined(USE_LINUX_BREAKPAD)
- if (GoogleUpdateSettings::SetCollectStatsConsent(true)) {
- InitCrashReporter();
- }
+ if (GoogleUpdateSettings::SetCollectStatsConsent(true))
+ InitCrashReporter();
#endif
- } else {
- GoogleUpdateSettings::SetCollectStatsConsent(false);
- }
+ } else {
+ GoogleUpdateSettings::SetCollectStatsConsent(false);
+ }
- // If selected set as default browser.
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(make_default_)))
- ShellIntegration::SetAsDefaultBrowser();
-
- // Import data if selected.
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(import_data_))) {
- const ProfileInfo& source_profile =
- importer_host_->GetSourceProfileInfoAt(
- gtk_combo_box_get_active(GTK_COMBO_BOX(import_profile_)));
- int items = importer::SEARCH_ENGINES + importer::HISTORY +
- importer::FAVORITES + importer::HOME_PAGE + importer::PASSWORDS;
- // TODO(port): Should we do the actual import in a new process like
- // Windows?
- StartImportingWithUI(GTK_WINDOW(dialog_), items, importer_host_.get(),
- source_profile, profile_, this, true);
- import_started = true;
- }
+ // If selected set as default browser.
+ if (make_default_ &&
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(make_default_))) {
+ ShellIntegration::SetAsDefaultBrowser();
}
- if (!import_started)
- FirstRunDone();
+
+ FirstRunDone();
}
void FirstRunDialog::OnLearnMoreLinkClicked(GtkButton* button) {
@@ -189,11 +388,10 @@ void FirstRunDialog::OnLearnMoreLinkClicked(GtkButton* button) {
}
void FirstRunDialog::FirstRunDone() {
- // Set preference to show first run bubble and welcome page.
- FirstRun::SetShowFirstRunBubblePref(true);
FirstRun::SetShowWelcomePagePref();
- gtk_widget_destroy(dialog_);
+ if (dialog_)
+ gtk_widget_destroy(dialog_);
MessageLoop::current()->Quit();
delete this;
}
diff --git a/chrome/browser/gtk/first_run_dialog.h b/chrome/browser/gtk/first_run_dialog.h
index a2b2a70..fdd47a7 100644
--- a/chrome/browser/gtk/first_run_dialog.h
+++ b/chrome/browser/gtk/first_run_dialog.h
@@ -4,63 +4,73 @@
#ifndef CHROME_BROWSER_GTK_FIRST_RUN_DIALOG_H_
#define CHROME_BROWSER_GTK_FIRST_RUN_DIALOG_H_
+#pragma once
typedef struct _GtkButton GtkButton;
typedef struct _GtkWidget GtkWidget;
#include "app/gtk_signal.h"
-#include "chrome/browser/first_run.h"
-#include "chrome/browser/importer/importer.h"
+#include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
-class FirstRunDialog : public ImportObserver {
+class TemplateURL;
+class TemplateURLModel;
+
+class FirstRunDialog : public TemplateURLModelObserver {
public:
// Displays the first run UI for reporting opt-in, import data etc.
- static bool Show(Profile* profile, ProcessSingleton* process_singleton);
+ static bool Show(Profile* profile, bool randomize_search_engine_order);
- // Overridden from ImportObserver:
- virtual void ImportCanceled() {
- FirstRunDone();
- }
- virtual void ImportComplete() {
- FirstRunDone();
- }
+ virtual void OnTemplateURLModelChanged();
private:
- FirstRunDialog(Profile* profile, int& response);
- ~FirstRunDialog() {}
+ FirstRunDialog(Profile* profile,
+ bool randomize_search_engine_order,
+ int& response);
+ virtual ~FirstRunDialog();
CHROMEGTK_CALLBACK_1(FirstRunDialog, void, OnResponseDialog, int);
+ CHROMEGTK_CALLBACK_0(FirstRunDialog, void, OnSearchEngineButtonClicked);
+ CHROMEGTK_CALLBACK_0(FirstRunDialog, void, OnSearchEngineWindowDestroy);
CHROMEG_CALLBACK_0(FirstRunDialog, void, OnLearnMoreLinkClicked, GtkButton*);
+ void ShowSearchEngineWindow();
+ void ShowDialog();
+
// This method closes the first run window and quits the message loop so that
// the Chrome startup can continue. This should be called when all the
// first run tasks are done.
void FirstRunDone();
- // First Run UI Dialog
+ // The search engine choice window. This is created and shown before
+ // |dialog_|.
+ GtkWidget* search_engine_window_;
+
+ // Dialog that holds the bug reporting and default browser checkboxes.
GtkWidget* dialog_;
+ // Container for the search engine choices.
+ GtkWidget* search_engine_hbox_;
+
// Crash reporting checkbox
GtkWidget* report_crashes_;
// Make browser default checkbox
GtkWidget* make_default_;
- // Import data checkbox
- GtkWidget* import_data_;
-
- // Combo box that displays list of profiles from which we can import.
- GtkWidget* import_profile_;
-
// Our current profile
Profile* profile_;
+ // Owned by the profile_.
+ TemplateURLModel* search_engines_model_;
+
+ // The search engine the user chose, or NULL if the user has not chosen a
+ // search engine.
+ TemplateURL* chosen_search_engine_;
+
// User response (accept or cancel) is returned through this.
int& response_;
- // Utility class that does the actual import.
- scoped_refptr<ImporterHost> importer_host_;
-
DISALLOW_COPY_AND_ASSIGN(FirstRunDialog);
};
diff --git a/chrome/browser/gtk/focus_store_gtk.cc b/chrome/browser/gtk/focus_store_gtk.cc
index f61b2ba..e882e2b 100644
--- a/chrome/browser/gtk/focus_store_gtk.cc
+++ b/chrome/browser/gtk/focus_store_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.
@@ -6,10 +6,11 @@
#include <gtk/gtk.h>
-#include "base/logging.h"
#include "chrome/browser/platform_util.h"
-FocusStoreGtk::FocusStoreGtk() : widget_(NULL) {
+FocusStoreGtk::FocusStoreGtk()
+ : widget_(NULL),
+ destroy_handler_id_(0) {
}
FocusStoreGtk::~FocusStoreGtk() {
@@ -17,19 +18,22 @@ FocusStoreGtk::~FocusStoreGtk() {
}
void FocusStoreGtk::Store(GtkWidget* widget) {
- DisconnectDestroyHandler();
- if (!widget) {
- widget_ = NULL;
- return;
+ GtkWidget* focus_widget = NULL;
+ if (widget) {
+ GtkWindow* window = platform_util::GetTopLevel(widget);
+ if (window)
+ focus_widget = window->focus_widget;
}
- GtkWindow* window = platform_util::GetTopLevel(widget);
- if (!window) {
- widget_ = NULL;
- return;
- }
+ SetWidget(focus_widget);
+}
- widget_ = window->focus_widget;
+void FocusStoreGtk::SetWidget(GtkWidget* widget) {
+ DisconnectDestroyHandler();
+
+ // We don't add a ref. The signal handler below effectively gives us a weak
+ // reference.
+ widget_ = widget;
if (widget_) {
// When invoked, |gtk_widget_destroyed| will set |widget_| to NULL.
destroy_handler_id_ = g_signal_connect(widget_, "destroy",
@@ -39,6 +43,8 @@ void FocusStoreGtk::Store(GtkWidget* widget) {
}
void FocusStoreGtk::DisconnectDestroyHandler() {
- if (widget_)
+ if (widget_) {
g_signal_handler_disconnect(widget_, destroy_handler_id_);
+ widget_ = NULL;
+ }
}
diff --git a/chrome/browser/gtk/focus_store_gtk.h b/chrome/browser/gtk/focus_store_gtk.h
index cfd6c9c..2159f1e 100644
--- a/chrome/browser/gtk/focus_store_gtk.h
+++ b/chrome/browser/gtk/focus_store_gtk.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_FOCUS_STORE_GTK_H_
#define CHROME_BROWSER_GTK_FOCUS_STORE_GTK_H_
+#pragma once
#include "base/basictypes.h"
@@ -18,9 +19,12 @@ class FocusStoreGtk {
GtkWidget* widget() const { return widget_; }
// Save the widget that is currently focused for |widget|'s toplevel (NOT
- // |widget|). Call with NULL to clear |widget_|.
+ // |widget|).
void Store(GtkWidget* widget);
+ // Save |widget| as the focus widget. Call with NULL to clear |widget_|.
+ void SetWidget(GtkWidget* widget);
+
private:
// Disconnect the previous destroy handler (if any).
void DisconnectDestroyHandler();
diff --git a/chrome/browser/gtk/fullscreen_exit_bubble_gtk.h b/chrome/browser/gtk/fullscreen_exit_bubble_gtk.h
index b81348e..91be3ef 100644
--- a/chrome/browser/gtk/fullscreen_exit_bubble_gtk.h
+++ b/chrome/browser/gtk/fullscreen_exit_bubble_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_FULLSCREEN_EXIT_BUBBLE_GTK_H_
#define CHROME_BROWSER_GTK_FULLSCREEN_EXIT_BUBBLE_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "app/gtk_signal_registrar.h"
@@ -19,7 +20,7 @@ class FullscreenExitBubbleGtk {
public:
// We place the bubble in |container|.
explicit FullscreenExitBubbleGtk(GtkFloatingContainer* container);
- ~FullscreenExitBubbleGtk();
+ virtual ~FullscreenExitBubbleGtk();
void InitWidgets();
diff --git a/chrome/browser/gtk/gconf_titlebar_listener.cc b/chrome/browser/gtk/gconf_titlebar_listener.cc
index 109ed99..b33ab17 100644
--- a/chrome/browser/gtk/gconf_titlebar_listener.cc
+++ b/chrome/browser/gtk/gconf_titlebar_listener.cc
@@ -7,7 +7,7 @@
#include <gtk/gtk.h>
#include "base/scoped_ptr.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/xdg_util.h"
#include "chrome/browser/gtk/browser_titlebar.h"
@@ -45,8 +45,8 @@ void GConfTitlebarListener::RemoveObserver(BrowserTitlebar* titlebar) {
// Private:
GConfTitlebarListener::GConfTitlebarListener() : client_(NULL) {
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
- if (base::GetDesktopEnvironment(env_getter.get()) ==
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (base::GetDesktopEnvironment(env.get()) ==
base::DESKTOP_ENVIRONMENT_GNOME) {
client_ = gconf_client_get_default();
// If we fail to get a context, that's OK, since we'll just fallback on
diff --git a/chrome/browser/gtk/gconf_titlebar_listener.h b/chrome/browser/gtk/gconf_titlebar_listener.h
index ad73e05..4b37588 100644
--- a/chrome/browser/gtk/gconf_titlebar_listener.h
+++ b/chrome/browser/gtk/gconf_titlebar_listener.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GCONF_TITLEBAR_LISTENER_H_
#define CHROME_BROWSER_GTK_GCONF_TITLEBAR_LISTENER_H_
+#pragma once
#include <gconf/gconf-client.h>
#include <gtk/gtk.h>
@@ -31,6 +32,9 @@ class GConfTitlebarListener {
// notifications.
void RemoveObserver(BrowserTitlebar* titlebar);
+ protected:
+ virtual ~GConfTitlebarListener() {}
+
private:
// Private constructor to enforce singleton access.
GConfTitlebarListener();
diff --git a/chrome/browser/gtk/gtk_chrome_button.h b/chrome/browser/gtk/gtk_chrome_button.h
index 762f238..e64c00b 100644
--- a/chrome/browser/gtk/gtk_chrome_button.h
+++ b/chrome/browser/gtk/gtk_chrome_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_CHROME_BUTTON_H_
#define CHROME_BROWSER_GTK_GTK_CHROME_BUTTON_H_
+#pragma once
#include <gdk/gdk.h>
#include <gtk/gtkbutton.h>
@@ -17,11 +18,11 @@ G_BEGIN_DECLS
(G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_CHROME_BUTTON, \
GtkChromeButtonClass))
#define GTK_IS_CHROME_BUTTON(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CHROME_BUTTON))
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_CHROME_BUTTON))
#define GTK_IS_CHROME_BUTTON_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CHROME_BUTTON))
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_CHROME_BUTTON))
#define GTK_CHROME_BUTTON_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CHROME_BUTTON, GtkChromeButton))
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_CHROME_BUTTON, GtkChromeButton))
typedef struct _GtkChromeButton GtkChromeButton;
typedef struct _GtkChromeButtonClass GtkChromeButtonClass;
diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.cc b/chrome/browser/gtk/gtk_chrome_cookie_view.cc
index 359cdca..aa4d344 100644
--- a/chrome/browser/gtk/gtk_chrome_cookie_view.cc
+++ b/chrome/browser/gtk/gtk_chrome_cookie_view.cc
@@ -179,6 +179,14 @@ void SetAppCacheDetailsSensitivity(GtkChromeCookieView *self,
gtk_widget_set_sensitive(self->appcache_last_accessed_entry_, enabled);
}
+void SetIndexedDBDetailsSensitivity(GtkChromeCookieView *self,
+ gboolean enabled) {
+ gtk_widget_set_sensitive(self->indexed_db_name_entry_, enabled);
+ gtk_widget_set_sensitive(self->indexed_db_origin_entry_, enabled);
+ gtk_widget_set_sensitive(self->indexed_db_size_entry_, enabled);
+ gtk_widget_set_sensitive(self->indexed_db_last_modified_entry_, enabled);
+}
+
void SetLocalStorageItemSensitivity(GtkChromeCookieView* self,
gboolean enabled) {
gtk_widget_set_sensitive(self->local_storage_item_origin_entry_, enabled);
@@ -237,6 +245,8 @@ void UpdateVisibleDetailedInfo(GtkChromeCookieView *self, GtkWidget* table) {
SetLocalStorageDetailsSensitivity(self,
table == self->local_storage_details_table_);
SetAppCacheDetailsSensitivity(self, table == self->appcache_details_table_);
+ SetIndexedDBDetailsSensitivity(self,
+ table == self->indexed_db_details_table_);
SetLocalStorageItemSensitivity(self,
table == self->local_storage_item_table_);
SetDatabaseAccessedSensitivity(self,
@@ -256,6 +266,8 @@ void UpdateVisibleDetailedInfo(GtkChromeCookieView *self, GtkWidget* table) {
gtk_widget_hide(self->local_storage_details_table_);
if (table != self->appcache_details_table_)
gtk_widget_hide(self->appcache_details_table_);
+ if (table != self->indexed_db_details_table_)
+ gtk_widget_hide(self->indexed_db_details_table_);
if (table != self->local_storage_item_table_)
gtk_widget_hide(self->local_storage_item_table_);
if (table != self->database_accessed_table_)
@@ -363,6 +375,26 @@ void BuildWidgets(GtkChromeCookieView *self, gboolean editable_expiration) {
self->appcache_details_table_,
&self->appcache_last_accessed_entry_);
+ // IndexedDB details.
+ self->indexed_db_details_table_ = gtk_table_new(4, 2, FALSE);
+ gtk_container_add(GTK_CONTAINER(self->table_box_),
+ self->indexed_db_details_table_);
+ gtk_table_set_col_spacing(GTK_TABLE(self->indexed_db_details_table_), 0,
+ gtk_util::kLabelSpacing);
+
+ row = 0;
+ InitDetailRow(row++, IDS_COOKIES_COOKIE_NAME_LABEL,
+ self->indexed_db_details_table_,
+ &self->indexed_db_name_entry_);
+ InitDetailRow(row++, IDS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL,
+ self->indexed_db_details_table_,
+ &self->indexed_db_origin_entry_);
+ InitDetailRow(row++, IDS_COOKIES_LOCAL_STORAGE_SIZE_ON_DISK_LABEL,
+ self->indexed_db_details_table_, &self->indexed_db_size_entry_);
+ InitDetailRow(row++, IDS_COOKIES_LOCAL_STORAGE_LAST_MODIFIED_LABEL,
+ self->indexed_db_details_table_,
+ &self->indexed_db_last_modified_entry_);
+
// Local storage item.
self->local_storage_item_table_ = gtk_table_new(3, 2, FALSE);
gtk_container_add(GTK_CONTAINER(self->table_box_),
@@ -512,7 +544,7 @@ void gtk_chrome_cookie_view_display_database(
gtk_entry_set_text(GTK_ENTRY(self->database_description_entry_),
database_info.description.c_str());
gtk_entry_set_text(GTK_ENTRY(self->database_size_entry_),
- WideToUTF8(FormatBytes(
+ UTF16ToUTF8(FormatBytes(
database_info.size,
GetByteDisplayUnits(database_info.size),
true)).c_str());
@@ -532,7 +564,7 @@ void gtk_chrome_cookie_view_display_local_storage(
gtk_entry_set_text(GTK_ENTRY(self->local_storage_origin_entry_),
local_storage_info.origin.c_str());
gtk_entry_set_text(GTK_ENTRY(self->local_storage_size_entry_),
- WideToUTF8(FormatBytes(
+ UTF16ToUTF8(FormatBytes(
local_storage_info.size,
GetByteDisplayUnits(local_storage_info.size),
true)).c_str());
@@ -551,7 +583,7 @@ void gtk_chrome_cookie_view_display_app_cache(
gtk_entry_set_text(GTK_ENTRY(self->appcache_manifest_entry_),
info.manifest_url.spec().c_str());
gtk_entry_set_text(GTK_ENTRY(self->appcache_size_entry_),
- WideToUTF8(FormatBytes(
+ UTF16ToUTF8(FormatBytes(
info.size,
GetByteDisplayUnits(info.size),
true)).c_str());
@@ -564,6 +596,30 @@ void gtk_chrome_cookie_view_display_app_cache(
SetAppCacheDetailsSensitivity(self, TRUE);
}
+// Switches the display to showing the passed in IndexedDB data.
+void gtk_chrome_cookie_view_display_indexed_db(
+ GtkChromeCookieView* self,
+ const BrowsingDataIndexedDBHelper::IndexedDBInfo& indexed_db_info) {
+ UpdateVisibleDetailedInfo(self, self->indexed_db_details_table_);
+
+ gtk_entry_set_text(GTK_ENTRY(self->indexed_db_name_entry_),
+ indexed_db_info.database_name.empty() ?
+ l10n_util::GetStringUTF8(
+ IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME).c_str() :
+ indexed_db_info.database_name.c_str());
+ gtk_entry_set_text(GTK_ENTRY(self->indexed_db_origin_entry_),
+ indexed_db_info.origin.c_str());
+ gtk_entry_set_text(GTK_ENTRY(self->indexed_db_size_entry_),
+ UTF16ToUTF8(FormatBytes(
+ indexed_db_info.size,
+ GetByteDisplayUnits(indexed_db_info.size),
+ true)).c_str());
+ gtk_entry_set_text(GTK_ENTRY(self->indexed_db_last_modified_entry_),
+ WideToUTF8(base::TimeFormatFriendlyDateAndTime(
+ indexed_db_info.last_modified)).c_str());
+ SetLocalStorageDetailsSensitivity(self, TRUE);
+}
+
void gtk_chrome_cookie_view_display_local_storage_item(
GtkChromeCookieView* self,
const std::string& host,
@@ -595,7 +651,7 @@ void gtk_chrome_cookie_view_display_database_accessed(
gtk_entry_set_text(GTK_ENTRY(self->database_accessed_description_entry_),
UTF16ToUTF8(display_name).c_str());
gtk_entry_set_text(GTK_ENTRY(self->database_accessed_size_entry_),
- WideToUTF8(FormatBytes(
+ UTF16ToUTF8(FormatBytes(
estimated_size,
GetByteDisplayUnits(estimated_size),
true)).c_str());
diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.h b/chrome/browser/gtk/gtk_chrome_cookie_view.h
index aa663a9..049d621 100644
--- a/chrome/browser/gtk/gtk_chrome_cookie_view.h
+++ b/chrome/browser/gtk/gtk_chrome_cookie_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_CHROME_COOKIE_VIEW_H_
#define CHROME_BROWSER_GTK_GTK_CHROME_COOKIE_VIEW_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,6 +12,7 @@
#include "chrome/browser/browsing_data_appcache_helper.h"
#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 "net/base/cookie_monster.h"
@@ -92,6 +94,13 @@ typedef struct {
GtkWidget* appcache_created_entry_;
GtkWidget* appcache_last_accessed_entry_;
+ // The IndexedDB details widgets.
+ GtkWidget* indexed_db_details_table_;
+ GtkWidget* indexed_db_name_entry_;
+ GtkWidget* indexed_db_origin_entry_;
+ GtkWidget* indexed_db_size_entry_;
+ GtkWidget* indexed_db_last_modified_entry_;
+
// The local storage item widgets.
GtkWidget* local_storage_item_table_;
GtkWidget* local_storage_item_origin_entry_;
@@ -156,6 +165,11 @@ void gtk_chrome_cookie_view_display_app_cache(
GtkChromeCookieView* widget,
const appcache::AppCacheInfo& info);
+// Switches the display to showing the passed in IndexedDB data.
+void gtk_chrome_cookie_view_display_indexed_db(
+ GtkChromeCookieView* widget,
+ const BrowsingDataIndexedDBHelper::IndexedDBInfo& info);
+
// Switches the display to an individual storage item.
void gtk_chrome_cookie_view_display_local_storage_item(
GtkChromeCookieView* widget,
diff --git a/chrome/browser/gtk/gtk_chrome_link_button.cc b/chrome/browser/gtk/gtk_chrome_link_button.cc
index fea5822..6c94600 100644
--- a/chrome/browser/gtk/gtk_chrome_link_button.cc
+++ b/chrome/browser/gtk/gtk_chrome_link_button.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.
@@ -6,7 +6,6 @@
#include <stdlib.h>
-#include "base/logging.h"
#include "chrome/browser/gtk/gtk_util.h"
static const gchar* kLinkMarkup = "<u><span color=\"%s\">%s</span></u>";
diff --git a/chrome/browser/gtk/gtk_chrome_link_button.h b/chrome/browser/gtk/gtk_chrome_link_button.h
index 1021cba..4cde366 100644
--- a/chrome/browser/gtk/gtk_chrome_link_button.h
+++ b/chrome/browser/gtk/gtk_chrome_link_button.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.
@@ -9,6 +9,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_CHROME_LINK_BUTTON_H_
#define CHROME_BROWSER_GTK_GTK_CHROME_LINK_BUTTON_H_
+#pragma once
#include <gdk/gdk.h>
#include <gtk/gtk.h>
@@ -23,13 +24,12 @@ G_BEGIN_DECLS
GTK_TYPE_CHROME_LINK_BUTTON, \
GtkChromeLinkButtonClass))
#define GTK_IS_CHROME_LINK_BUTTON(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CHROME_LINK_BUTTON))
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_CHROME_LINK_BUTTON))
#define GTK_IS_CHROME_LINK_BUTTON_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CHROME_LINK_BUTTON))
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_CHROME_LINK_BUTTON))
#define GTK_CHROME_LINK_BUTTON_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), \
- GTK_TYPE_CHROME_LINK_BUTTON, \
- GtkChromeLinkButton))
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_CHROME_LINK_BUTTON, \
+ GtkChromeLinkButton))
typedef struct _GtkChromeLinkButton GtkChromeLinkButton;
typedef struct _GtkChromeLinkButtonClass GtkChromeLinkButtonClass;
diff --git a/chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h b/chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h
index 08d0b37..9793548 100644
--- a/chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h
+++ b/chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_CHROME_SHRINKABLE_HBOX_H_
#define CHROME_BROWSER_GTK_GTK_CHROME_SHRINKABLE_HBOX_H_
+#pragma once
#include <gdk/gdk.h>
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/gtk_custom_menu.cc b/chrome/browser/gtk/gtk_custom_menu.cc
index d666091..15eeb5a 100644
--- a/chrome/browser/gtk/gtk_custom_menu.cc
+++ b/chrome/browser/gtk/gtk_custom_menu.cc
@@ -60,7 +60,8 @@ static gboolean gtk_custom_menu_button_press(GtkWidget* widget,
}
// When processing a button event, abort processing if the cursor isn't in a
-// clickable region.
+// clickable region. If it's in a button that doesn't dismiss the menu, fire
+// that event and abort having the normal GtkMenu code run.
static gboolean gtk_custom_menu_button_release(GtkWidget* widget,
GdkEventButton* event) {
GtkWidget* menu_item = gtk_menu_shell_get_item(
@@ -71,6 +72,11 @@ static gboolean gtk_custom_menu_button_release(GtkWidget* widget,
// Stop processing this event. This isn't a clickable region.
return TRUE;
}
+
+ if (gtk_custom_menu_item_try_no_dismiss_command(
+ GTK_CUSTOM_MENU_ITEM(menu_item))) {
+ return TRUE;
+ }
}
return GTK_WIDGET_CLASS(gtk_custom_menu_parent_class)->
diff --git a/chrome/browser/gtk/gtk_custom_menu.h b/chrome/browser/gtk/gtk_custom_menu.h
index a2fc757..1faa730 100644
--- a/chrome/browser/gtk/gtk_custom_menu.h
+++ b/chrome/browser/gtk/gtk_custom_menu.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_CUSTOM_MENU_H_
#define CHROME_BROWSER_GTK_GTK_CUSTOM_MENU_H_
+#pragma once
// GtkCustomMenu is a GtkMenu subclass that can contain, and collaborates with,
// GtkCustomMenuItem instances. GtkCustomMenuItem is a GtkMenuItem that can
diff --git a/chrome/browser/gtk/gtk_custom_menu_item.cc b/chrome/browser/gtk/gtk_custom_menu_item.cc
index febf8bc..a3d62d4 100644
--- a/chrome/browser/gtk/gtk_custom_menu_item.cc
+++ b/chrome/browser/gtk/gtk_custom_menu_item.cc
@@ -5,11 +5,11 @@
#include "chrome/browser/gtk/gtk_custom_menu_item.h"
#include "base/i18n/rtl.h"
-#include "base/logging.h"
#include "chrome/browser/gtk/gtk_custom_menu.h"
enum {
BUTTON_PUSHED,
+ TRY_BUTTON_PUSHED,
LAST_SIGNAL
};
@@ -103,6 +103,16 @@ static void gtk_custom_menu_item_class_init(GtkCustomMenuItemClass* klass) {
NULL, NULL,
gtk_marshal_NONE__INT,
G_TYPE_NONE, 1, GTK_TYPE_INT);
+ // TODO(erg): Change from BOOL__POINTER to BOOLEAN__INTEGER when we get to
+ // use a modern GTK+.
+ custom_menu_item_signals[TRY_BUTTON_PUSHED] =
+ g_signal_new("try-button-pushed",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ gtk_marshal_BOOL__POINTER,
+ G_TYPE_BOOLEAN, 1, GTK_TYPE_INT);
}
static void gtk_custom_menu_item_finalize(GObject *object) {
@@ -265,11 +275,7 @@ static void gtk_custom_menu_item_activate(GtkMenuItem* menu_item) {
GtkWidget* gtk_custom_menu_item_new(const char* title) {
GtkCustomMenuItem* item = GTK_CUSTOM_MENU_ITEM(
g_object_new(GTK_TYPE_CUSTOM_MENU_ITEM, NULL));
-
- char* markup = g_markup_printf_escaped("<b>%s</b>", title);
- gtk_label_set_markup(GTK_LABEL(item->label), markup);
- g_free(markup);
-
+ gtk_label_set_text(GTK_LABEL(item->label), title);
return GTK_WIDGET(item);
}
@@ -395,3 +401,34 @@ gboolean gtk_custom_menu_item_is_in_clickable_region(
GtkCustomMenuItem* menu_item) {
return menu_item->currently_selected_button != NULL;
}
+
+gboolean gtk_custom_menu_item_try_no_dismiss_command(
+ GtkCustomMenuItem* menu_item) {
+ GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(menu_item);
+ gboolean activated = TRUE;
+
+ // We work with |currently_selected_button| instead of
+ // |previously_selected_button| since we haven't been "deselect"ed yet.
+ gpointer id_ptr = g_object_get_data(
+ G_OBJECT(custom_item->currently_selected_button), "command-id");
+ if (id_ptr != NULL) {
+ int command_id = GPOINTER_TO_INT(id_ptr);
+ g_signal_emit(custom_item, custom_menu_item_signals[TRY_BUTTON_PUSHED], 0,
+ command_id, &activated);
+ }
+
+ return activated;
+}
+
+void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item,
+ GtkCallback callback,
+ gpointer callback_data) {
+ // Even though we're filtering |all_widgets| on GTK_IS_BUTTON(), this isn't
+ // equivalent to |button_widgets| because we also want the button-labels.
+ for (GList* i = menu_item->all_widgets; i && GTK_IS_BUTTON(i->data);
+ i = g_list_next(i)) {
+ if (GTK_IS_BUTTON(i->data)) {
+ callback(GTK_WIDGET(i->data), callback_data);
+ }
+ }
+}
diff --git a/chrome/browser/gtk/gtk_custom_menu_item.h b/chrome/browser/gtk/gtk_custom_menu_item.h
index c89db5d..76e8c9a 100644
--- a/chrome/browser/gtk/gtk_custom_menu_item.h
+++ b/chrome/browser/gtk/gtk_custom_menu_item.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_CUSTOM_MENU_ITEM_H_
#define CHROME_BROWSER_GTK_GTK_CUSTOM_MENU_ITEM_H_
+#pragma once
// GtkCustomMenuItem is a GtkMenuItem subclass that has buttons in it and acts
// to support this. GtkCustomMenuItems only render properly when put in a
@@ -122,6 +123,19 @@ void gtk_custom_menu_item_select_item_by_direction(
gboolean gtk_custom_menu_item_is_in_clickable_region(
GtkCustomMenuItem* menu_item);
+// If the button is released while the |currently_selected_button| isn't
+// supposed to dismiss the menu, this signals to our listeners that we want to
+// run this command if it doesn't dismiss the menu. Returns TRUE if we acted
+// on this button click (and should prevent the normal GtkMenu machinery from
+// firing an "activate" signal).
+gboolean gtk_custom_menu_item_try_no_dismiss_command(
+ GtkCustomMenuItem* menu_item);
+
+// Calls |callback| with every button and button-label in the container.
+void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item,
+ GtkCallback callback,
+ gpointer callback_data);
+
G_END_DECLS
#endif // CHROME_BROWSER_GTK_GTK_CUSTOM_MENU_ITEM_H_
diff --git a/chrome/browser/gtk/gtk_expanded_container.h b/chrome/browser/gtk/gtk_expanded_container.h
index 396177e..0870bbc 100644
--- a/chrome/browser/gtk/gtk_expanded_container.h
+++ b/chrome/browser/gtk/gtk_expanded_container.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_EXPANDED_CONTAINER_H_
#define CHROME_BROWSER_GTK_GTK_EXPANDED_CONTAINER_H_
+#pragma once
#include <gdk/gdk.h>
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/gtk_floating_container.cc b/chrome/browser/gtk/gtk_floating_container.cc
index a8021e6..ab8a49e 100644
--- a/chrome/browser/gtk/gtk_floating_container.cc
+++ b/chrome/browser/gtk/gtk_floating_container.cc
@@ -192,7 +192,7 @@ static void gtk_floating_container_forall(GtkContainer* container,
static void gtk_floating_container_size_request(GtkWidget* widget,
GtkRequisition* requisition) {
- GtkBin *bin = GTK_BIN(widget);
+ GtkBin* bin = GTK_BIN(widget);
if (bin && bin->child) {
gtk_widget_size_request(bin->child, requisition);
} else {
@@ -238,8 +238,8 @@ static void gtk_floating_container_size_allocate(GtkWidget* widget,
if (GTK_WIDGET_VISIBLE(child->widget)) {
gtk_widget_size_request(child->widget, &child_requisition);
- child_allocation.x = child->x;
- child_allocation.y = child->y;
+ child_allocation.x = allocation->x + child->x;
+ child_allocation.y = allocation->y + child->y;
child_allocation.width = std::max(1, std::min(child_requisition.width,
allocation->width));
child_allocation.height = std::max(1, std::min(child_requisition.height,
diff --git a/chrome/browser/gtk/gtk_floating_container.h b/chrome/browser/gtk/gtk_floating_container.h
index 7cd6b0b..b0eed46 100644
--- a/chrome/browser/gtk/gtk_floating_container.h
+++ b/chrome/browser/gtk/gtk_floating_container.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_FLOATING_CONTAINER_H_
#define CHROME_BROWSER_GTK_GTK_FLOATING_CONTAINER_H_
+#pragma once
#include <gdk/gdk.h>
#include <gtk/gtk.h>
@@ -26,7 +27,8 @@
// signature:
//
// void (*set_floating_position)(GtkFloatingContainer* container,
-// GtkAllocation* allocation);
+// GtkAllocation* allocation,
+// gpointer userdata);
//
// Your handler should, for each floating widget, set the "x" and "y" child
// properties.
diff --git a/chrome/browser/gtk/gtk_theme_provider.cc b/chrome/browser/gtk/gtk_theme_provider.cc
index 0f8a254..5bcd8a3 100644
--- a/chrome/browser/gtk/gtk_theme_provider.cc
+++ b/chrome/browser/gtk/gtk_theme_provider.cc
@@ -10,30 +10,30 @@
#include "app/gtk_signal_registrar.h"
#include "app/resource_bundle.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/stl_util-inl.h"
#include "base/xdg_util.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
-#include "chrome/browser/gtk/hover_controller_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
+#include "chrome/browser/gtk/hover_controller_gtk.h"
#include "chrome/browser/gtk/meta_frames.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/common/pref_names.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profile.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"
#include "gfx/color_utils.h"
+#include "gfx/gtk_util.h"
#include "gfx/skbitmap_operations.h"
#include "gfx/skia_utils_gtk.h"
+#include "grit/app_resources.h"
+#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "gfx/gtk_util.h"
-#include "grit/app_resources.h"
-#include "grit/theme_resources.h"
namespace {
@@ -258,7 +258,6 @@ GtkThemeProvider::GtkThemeProvider()
}
GtkThemeProvider::~GtkThemeProvider() {
- profile()->GetPrefs()->RemovePrefObserver(prefs::kUsesSystemTheme, this);
gtk_widget_destroy(fake_window_);
gtk_widget_destroy(fake_frame_);
fake_label_.Destroy();
@@ -273,7 +272,8 @@ GtkThemeProvider::~GtkThemeProvider() {
}
void GtkThemeProvider::Init(Profile* profile) {
- profile->GetPrefs()->AddPrefObserver(prefs::kUsesSystemTheme, this);
+ registrar_.Init(profile->GetPrefs());
+ registrar_.Add(prefs::kUsesSystemTheme, this);
use_gtk_ = profile->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme);
BrowserThemeProvider::Init(profile);
@@ -345,7 +345,7 @@ void GtkThemeProvider::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if ((type == NotificationType::PREF_CHANGED) &&
- (*Details<std::wstring>(details).ptr() == prefs::kUsesSystemTheme))
+ (*Details<std::string>(details).ptr() == prefs::kUsesSystemTheme))
use_gtk_ = profile()->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme);
}
@@ -428,7 +428,7 @@ void GtkThemeProvider::GetScrollbarColors(GdkColor* thumb_active_color,
GtkStyle* style = gtk_rc_get_style(scrollbar);
GdkPixmap* pm = gdk_pixmap_new(window->window, kWidth, kHeight, -1);
GdkRectangle rect = { 0, 0, kWidth, kHeight };
- unsigned char data[3*kWidth*kHeight];
+ unsigned char data[3 * kWidth * kHeight];
for (int i = 0; i < 3; ++i) {
if (i < 2) {
// Thumb part
@@ -443,19 +443,19 @@ void GtkThemeProvider::GetScrollbarColors(GdkColor* thumb_active_color,
}
GdkPixbuf* pb = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB,
FALSE, 8, kWidth, kHeight,
- 3*kWidth, 0, 0);
+ 3 * kWidth, 0, 0);
gdk_pixbuf_get_from_drawable(pb, pm, NULL, 0, 0, 0, 0, kWidth, kHeight);
// Sample pixels
int components[3] = { 0 };
- for (int y = 2; y < kHeight-2; ++y) {
+ for (int y = 2; y < kHeight - 2; ++y) {
for (int c = 0; c < 3; ++c) {
// Sample a vertical slice of pixels at about one-thirds from the
// left edge. This allows us to avoid any fixed graphics that might be
// located at the edges or in the center of the scrollbar.
// Each pixel is made up of a red, green, and blue component; taking up
// a total of three bytes.
- components[c] += data[3*(kWidth/3 + y*kWidth) + c];
+ components[c] += data[3 * (kWidth / 3 + y * kWidth) + c];
}
}
GdkColor* color = i == 0 ? thumb_active_color :
@@ -469,9 +469,9 @@ void GtkThemeProvider::GetScrollbarColors(GdkColor* thumb_active_color,
// We now need to scale the colors from the 0..255 range, to the wider
// 0..65535 range, and we need to actually compute the average color; so,
// we divide by the total number of pixels in the sample.
- color->red = components[0] * 65535 / (255*(kHeight-4));
- color->green = components[1] * 65535 / (255*(kHeight-4));
- color->blue = components[2] * 65535 / (255*(kHeight-4));
+ color->red = components[0] * 65535 / (255 * (kHeight - 4));
+ color->green = components[1] * 65535 / (255 * (kHeight - 4));
+ color->blue = components[2] * 65535 / (255 * (kHeight - 4));
g_object_unref(pb);
}
@@ -481,42 +481,29 @@ void GtkThemeProvider::GetScrollbarColors(GdkColor* thumb_active_color,
}
CairoCachedSurface* GtkThemeProvider::GetSurfaceNamed(
- int id, GtkWidget* widget_on_display) {
- GdkDisplay* display = gtk_widget_get_display(widget_on_display);
- CairoCachedSurfaceMap& surface_map = per_display_surfaces_[display];
-
- // Check to see if we already have the pixbuf in the cache.
- CairoCachedSurfaceMap::const_iterator found = surface_map.find(id);
- if (found != surface_map.end())
- return found->second;
-
- GdkPixbuf* pixbuf = GetPixbufNamed(id);
- CairoCachedSurface* surface = new CairoCachedSurface;
- surface->UsePixbuf(pixbuf);
-
- surface_map[id] = surface;
+ int id,
+ GtkWidget* widget_on_display) {
+ return GetSurfaceNamedImpl(id, GetPixbufNamed(id), widget_on_display);
+}
- return surface;
+CairoCachedSurface* GtkThemeProvider::GetRTLEnabledSurfaceNamed(
+ int id,
+ GtkWidget* widget_on_display) {
+ // We flip the sign of |id| when passing it to GetSurfaceNamedImpl() for the
+ // same reason that BrowserThemeProvider::GetPixbufImpl() does: so that if one
+ // location calls this function with a resource ID, and another place calls
+ // GetSurfaceNamed() with the same ID, they'll correctly get different
+ // surfaces in RTL mode.
+ return GetSurfaceNamedImpl(-id, GetRTLEnabledPixbufNamed(id),
+ widget_on_display);
}
CairoCachedSurface* GtkThemeProvider::GetUnthemedSurfaceNamed(
- int id, GtkWidget* widget_on_display) {
- GdkDisplay* display = gtk_widget_get_display(widget_on_display);
- CairoCachedSurfaceMap& surface_map = per_display_unthemed_surfaces_[display];
-
- // Check to see if we already have the pixbuf in the cache.
- CairoCachedSurfaceMap::const_iterator found = surface_map.find(id);
- if (found != surface_map.end())
- return found->second;
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- GdkPixbuf* pixbuf = rb.GetPixbufNamed(id);
- CairoCachedSurface* surface = new CairoCachedSurface;
- surface->UsePixbuf(pixbuf);
-
- surface_map[id] = surface;
-
- return surface;
+ int id,
+ GtkWidget* widget_on_display) {
+ return GetSurfaceNamedImpl(id,
+ ResourceBundle::GetSharedInstance().GetPixbufNamed(id),
+ widget_on_display);
}
// static
@@ -563,9 +550,9 @@ GdkPixbuf* GtkThemeProvider::GetDefaultFavicon(bool native) {
// static
bool GtkThemeProvider::DefaultUsesSystemTheme() {
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
- switch (base::GetDesktopEnvironment(env_getter.get())) {
+ switch (base::GetDesktopEnvironment(env.get())) {
case base::DESKTOP_ENVIRONMENT_GNOME:
case base::DESKTOP_ENVIRONMENT_XFCE:
return true;
@@ -912,38 +899,23 @@ SkBitmap* GtkThemeProvider::GenerateGtkThemeBitmap(int id) const {
// instead should tint based on the foreground text entry color in GTK+
// mode because some themes that try to be dark *and* light have very
// different colors between the omnibox and the normal background area.
- case IDR_OMNIBOX_SEARCH:
+ case IDR_OMNIBOX_HISTORY:
+ case IDR_OMNIBOX_HTTP:
case IDR_OMNIBOX_MORE:
+ case IDR_OMNIBOX_SEARCH:
case IDR_OMNIBOX_STAR:
case IDR_GEOLOCATION_ALLOWED_LOCATIONBAR_ICON:
case IDR_GEOLOCATION_DENIED_LOCATIONBAR_ICON: {
return GenerateTintedIcon(id, entry_tint_);
}
- // Two sets of omnibox icons, the one for normal http and the one for
- // history, include white backgrounds (and are supposed to, for the windows
- // chrome-theme). On linux, where we have all sorts of wacky themes and
- // color combinations we need to deal with, switch them out with
- // transparent background versions.
- case IDR_OMNIBOX_HTTP: {
- return GenerateTintedIcon(IDR_OMNIBOX_HTTP_TRANSPARENT, entry_tint_);
- }
- case IDR_OMNIBOX_HISTORY: {
- return GenerateTintedIcon(IDR_OMNIBOX_HISTORY_TRANSPARENT, entry_tint_);
- }
// In GTK mode, the dark versions of the omnibox icons only ever appear in
// the autocomplete popup and only against the current theme's GtkEntry
// base[GTK_STATE_SELECTED] color, so tint the icons so they won't collide
// with the selected color.
- case IDR_OMNIBOX_HTTP_DARK: {
- return GenerateTintedIcon(IDR_OMNIBOX_HTTP_DARK_TRANSPARENT,
- selected_entry_tint_);
- }
- case IDR_OMNIBOX_HISTORY_DARK: {
- return GenerateTintedIcon(IDR_OMNIBOX_HISTORY_DARK_TRANSPARENT,
- selected_entry_tint_);
- }
- case IDR_OMNIBOX_SEARCH_DARK:
+ case IDR_OMNIBOX_HISTORY_DARK:
+ case IDR_OMNIBOX_HTTP_DARK:
case IDR_OMNIBOX_MORE_DARK:
+ case IDR_OMNIBOX_SEARCH_DARK:
case IDR_OMNIBOX_STAR_DARK: {
return GenerateTintedIcon(id, selected_entry_tint_);
}
@@ -1012,6 +984,26 @@ void GtkThemeProvider::GetSelectedEntryForegroundHSL(
color_utils::SkColorToHSL(GdkToSkColor(&color), tint);
}
+CairoCachedSurface* GtkThemeProvider::GetSurfaceNamedImpl(
+ int id,
+ GdkPixbuf* pixbuf,
+ GtkWidget* widget_on_display) {
+ GdkDisplay* display = gtk_widget_get_display(widget_on_display);
+ CairoCachedSurfaceMap& surface_map = per_display_surfaces_[display];
+
+ // Check to see if we already have the pixbuf in the cache.
+ CairoCachedSurfaceMap::const_iterator found = surface_map.find(id);
+ if (found != surface_map.end())
+ return found->second;
+
+ CairoCachedSurface* surface = new CairoCachedSurface;
+ surface->UsePixbuf(pixbuf);
+
+ surface_map[id] = surface;
+
+ return surface;
+}
+
void GtkThemeProvider::OnDestroyChromeButton(GtkWidget* button) {
std::vector<GtkWidget*>::iterator it =
find(chrome_buttons_.begin(), chrome_buttons_.end(), button);
diff --git a/chrome/browser/gtk/gtk_theme_provider.h b/chrome/browser/gtk/gtk_theme_provider.h
index 031c5c0..2ecef7a 100644
--- a/chrome/browser/gtk/gtk_theme_provider.h
+++ b/chrome/browser/gtk/gtk_theme_provider.h
@@ -4,17 +4,18 @@
#ifndef CHROME_BROWSER_GTK_GTK_THEME_PROVIDER_H_
#define CHROME_BROWSER_GTK_GTK_THEME_PROVIDER_H_
+#pragma once
#include <map>
-#include <string>
#include <vector>
#include "app/gtk_integers.h"
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/notification_observer.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/color_utils.h"
class CairoCachedSurface;
@@ -97,10 +98,17 @@ class GtkThemeProvider : public BrowserThemeProvider,
// to send the image to the server on each expose.
CairoCachedSurface* GetSurfaceNamed(int id, GtkWidget* widget_on_display);
- // Returns a CairoCachedSurface for a particular Display for an image
- // resource that's unthemed.
- CairoCachedSurface* GetUnthemedSurfaceNamed(
- int id, GtkWidget* widget_on_display);
+ // Same as above, but auto-mirrors the underlying pixbuf in RTL mode.
+ CairoCachedSurface* GetRTLEnabledSurfaceNamed(int id,
+ GtkWidget* widget_on_display);
+
+ // Same as above, but gets the resource from the ResourceBundle instead of the
+ // BrowserThemeProvider.
+ // NOTE: Never call this with resource IDs that are ever passed to the above
+ // two functions! Depending on which call comes first, all callers will
+ // either get the themed or the unthemed version.
+ CairoCachedSurface* GetUnthemedSurfaceNamed(int id,
+ GtkWidget* widget_on_display);
// Returns colors that we pass to webkit to match the system theme.
const SkColor& get_focus_ring_color() const { return focus_ring_color_; }
@@ -201,6 +209,11 @@ class GtkThemeProvider : public BrowserThemeProvider,
// entry.
void GetSelectedEntryForegroundHSL(color_utils::HSL* tint) const;
+ // Implements GetXXXSurfaceNamed(), given the appropriate pixbuf to use.
+ CairoCachedSurface* GetSurfaceNamedImpl(int id,
+ GdkPixbuf* pixbuf,
+ GtkWidget* widget_on_display);
+
// Handles signal from GTK that our theme has been changed.
CHROMEGTK_CALLBACK_1(GtkThemeProvider, void, OnStyleSet, GtkStyle*);
@@ -263,6 +276,8 @@ class GtkThemeProvider : public BrowserThemeProvider,
PerDisplaySurfaceMap per_display_surfaces_;
PerDisplaySurfaceMap per_display_unthemed_surfaces_;
+ PrefChangeRegistrar registrar_;
+
// This is a dummy widget that only exists so we have something to pass to
// gtk_widget_render_icon().
static GtkWidget* icon_widget_;
diff --git a/chrome/browser/gtk/gtk_theme_provider_unittest.cc b/chrome/browser/gtk/gtk_theme_provider_unittest.cc
index f0d8e28..1836b80 100644
--- a/chrome/browser/gtk/gtk_theme_provider_unittest.cc
+++ b/chrome/browser/gtk/gtk_theme_provider_unittest.cc
@@ -5,6 +5,7 @@
#include <gtk/gtk.h>
#include "chrome/browser/gtk/gtk_theme_provider.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"
diff --git a/chrome/browser/gtk/gtk_tree.cc b/chrome/browser/gtk/gtk_tree.cc
index 5594c58..744a4a6 100644
--- a/chrome/browser/gtk/gtk_tree.cc
+++ b/chrome/browser/gtk/gtk_tree.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.
@@ -92,17 +92,107 @@ void TableAdapter::SetModel(TableModel* table_model) {
table_model_->SetObserver(this);
}
+bool TableAdapter::IsGroupRow(GtkTreeIter* iter) const {
+ if (!table_model_->HasGroups())
+ return false;
+ gboolean is_header = false;
+ gboolean is_separator = false;
+ gtk_tree_model_get(GTK_TREE_MODEL(list_store_),
+ iter,
+ COL_IS_HEADER,
+ &is_header,
+ COL_IS_SEPARATOR,
+ &is_separator,
+ -1);
+ return is_header || is_separator;
+}
+
+static int OffsetForGroupIndex(size_t group_index) {
+ // Every group consists of a header and a separator row, and there is a blank
+ // row between groups.
+ return 3 * group_index + 2;
+}
+
+void TableAdapter::MapListStoreIndicesToModelRows(
+ const std::set<int>& list_store_indices,
+ RemoveRowsTableModel::Rows* model_rows) {
+ if (!table_model_->HasGroups()) {
+ for (std::set<int>::const_iterator it = list_store_indices.begin();
+ it != list_store_indices.end();
+ ++it) {
+ model_rows->insert(*it);
+ }
+ return;
+ }
+
+ const TableModel::Groups& groups = table_model_->GetGroups();
+ TableModel::Groups::const_iterator group_it = groups.begin();
+ for (std::set<int>::const_iterator list_store_it = list_store_indices.begin();
+ list_store_it != list_store_indices.end();
+ ++list_store_it) {
+ int list_store_index = *list_store_it;
+ GtkTreeIter iter;
+ bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
+ &iter,
+ NULL,
+ list_store_index);
+ if (!rv) {
+ NOTREACHED();
+ return;
+ }
+ int group = -1;
+ gtk_tree_model_get(GTK_TREE_MODEL(list_store_),
+ &iter,
+ COL_GROUP_ID,
+ &group,
+ -1);
+ while (group_it->id != group) {
+ ++group_it;
+ if (group_it == groups.end()) {
+ NOTREACHED();
+ return;
+ }
+ }
+ int offset = OffsetForGroupIndex(group_it - groups.begin());
+ model_rows->insert(list_store_index - offset);
+ }
+}
+
+int TableAdapter::GetListStoreIndexForModelRow(int model_row) const {
+ if (!table_model_->HasGroups())
+ return model_row;
+ int group = table_model_->GetGroupID(model_row);
+ const TableModel::Groups& groups = table_model_->GetGroups();
+ for (TableModel::Groups::const_iterator it = groups.begin();
+ it != groups.end(); ++it) {
+ if (it->id == group) {
+ return model_row + OffsetForGroupIndex(it - groups.begin());
+ }
+ }
+ NOTREACHED();
+ return -1;
+}
+
void TableAdapter::AddNodeToList(int row) {
GtkTreeIter iter;
- if (row == 0) {
+ int list_store_index = GetListStoreIndexForModelRow(row);
+ if (list_store_index == 0) {
gtk_list_store_prepend(list_store_, &iter);
} else {
GtkTreeIter sibling;
gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_), &sibling, NULL,
- row - 1);
+ list_store_index - 1);
gtk_list_store_insert_after(list_store_, &iter, &sibling);
}
+ if (table_model_->HasGroups()) {
+ gtk_list_store_set(list_store_,
+ &iter,
+ COL_WEIGHT, PANGO_WEIGHT_NORMAL,
+ COL_WEIGHT_SET, TRUE,
+ COL_GROUP_ID, table_model_->GetGroupID(row),
+ -1);
+ }
delegate_->SetColumnValues(row, &iter);
}
@@ -110,21 +200,69 @@ void TableAdapter::OnModelChanged() {
delegate_->OnAnyModelUpdateStart();
gtk_list_store_clear(list_store_);
delegate_->OnModelChanged();
+
+ if (table_model_->HasGroups()) {
+ const TableModel::Groups& groups = table_model_->GetGroups();
+ for (TableModel::Groups::const_iterator it = groups.begin();
+ it != groups.end(); ++it) {
+ GtkTreeIter iter;
+ if (it != groups.begin()) {
+ // Blank row between groups.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(list_store_, &iter, COL_IS_HEADER, TRUE, -1);
+ }
+ // Group title.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(list_store_,
+ &iter,
+ COL_WEIGHT,
+ PANGO_WEIGHT_BOLD,
+ COL_WEIGHT_SET,
+ TRUE,
+ COL_TITLE,
+ WideToUTF8(it->title).c_str(),
+ COL_IS_HEADER,
+ TRUE,
+ -1);
+ // Group separator.
+ gtk_list_store_append(list_store_, &iter);
+ gtk_list_store_set(list_store_,
+ &iter,
+ COL_IS_HEADER,
+ TRUE,
+ COL_IS_SEPARATOR,
+ TRUE,
+ -1);
+ }
+ }
+
for (int i = 0; i < table_model_->RowCount(); ++i)
AddNodeToList(i);
delegate_->OnAnyModelUpdate();
}
void TableAdapter::OnItemsChanged(int start, int length) {
+ if (length == 0)
+ return;
delegate_->OnAnyModelUpdateStart();
+ int list_store_index = GetListStoreIndexForModelRow(start);
GtkTreeIter iter;
- bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_), &iter,
- NULL, start);
+ bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
+ &iter,
+ NULL,
+ list_store_index);
for (int i = 0; i < length; ++i) {
if (!rv) {
NOTREACHED();
return;
}
+ while (IsGroupRow(&iter)) {
+ rv = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store_), &iter);
+ if (!rv) {
+ NOTREACHED();
+ return;
+ }
+ }
delegate_->SetColumnValues(start + i, &iter);
rv = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store_), &iter);
}
@@ -140,20 +278,66 @@ void TableAdapter::OnItemsAdded(int start, int length) {
}
void TableAdapter::OnItemsRemoved(int start, int length) {
+ if (length == 0)
+ return;
delegate_->OnAnyModelUpdateStart();
+ // When this method is called, the model has already removed the items, so
+ // accessing items in the model from |start| on may not be possible anymore.
+ // Therefore we use the item right before that, if it exists.
+ int list_store_index = 0;
+ if (start > 0)
+ list_store_index = GetListStoreIndexForModelRow(start - 1) + 1;
GtkTreeIter iter;
- bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_), &iter,
- NULL, start);
+ bool rv = gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store_),
+ &iter,
+ NULL,
+ list_store_index);
+ if (!rv) {
+ NOTREACHED();
+ return;
+ }
for (int i = 0; i < length; ++i) {
- if (!rv) {
- NOTREACHED();
- return;
+ while (IsGroupRow(&iter)) {
+ rv = gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store_), &iter);
+ if (!rv) {
+ NOTREACHED();
+ return;
+ }
}
- rv = gtk_list_store_remove(list_store_, &iter);
+ gtk_list_store_remove(list_store_, &iter);
}
delegate_->OnAnyModelUpdate();
}
+// static
+gboolean TableAdapter::OnCheckRowIsSeparator(GtkTreeModel* model,
+ GtkTreeIter* iter,
+ gpointer user_data) {
+ gboolean is_separator;
+ gtk_tree_model_get(model,
+ iter,
+ COL_IS_SEPARATOR,
+ &is_separator,
+ -1);
+ return is_separator;
+}
+
+// static
+gboolean TableAdapter::OnSelectionFilter(GtkTreeSelection* selection,
+ GtkTreeModel* model,
+ GtkTreePath* path,
+ gboolean path_currently_selected,
+ gpointer user_data) {
+ GtkTreeIter iter;
+ if (!gtk_tree_model_get_iter(model, &iter, path)) {
+ NOTREACHED();
+ return TRUE;
+ }
+ gboolean is_header;
+ gtk_tree_model_get(model, &iter, COL_IS_HEADER, &is_header, -1);
+ return !is_header;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TreeAdapter
@@ -202,7 +386,7 @@ void TreeAdapter::FillRow(GtkTreeIter* iter, TreeModelNode* node) {
pixbuf = GtkThemeProvider::GetFolderIcon(true);
gtk_tree_store_set(tree_store_, iter,
COL_ICON, pixbuf,
- COL_TITLE, WideToUTF8(node->GetTitle()).c_str(),
+ COL_TITLE, UTF16ToUTF8(node->GetTitle()).c_str(),
COL_NODE_PTR, node,
-1);
}
@@ -278,11 +462,6 @@ void TreeAdapter::TreeNodesRemoved(TreeModel* model,
delegate_->OnAnyModelUpdate();
}
-void TreeAdapter::TreeNodeChildrenReordered(TreeModel* model,
- TreeModelNode* parent) {
- NOTIMPLEMENTED();
-}
-
void TreeAdapter::TreeNodeChanged(TreeModel* model, TreeModelNode* node) {
delegate_->OnAnyModelUpdateStart();
GtkTreeIter iter;
diff --git a/chrome/browser/gtk/gtk_tree.h b/chrome/browser/gtk/gtk_tree.h
index 1357315..ce4feee 100644
--- a/chrome/browser/gtk/gtk_tree.h
+++ b/chrome/browser/gtk/gtk_tree.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_GTK_TREE_H_
#define CHROME_BROWSER_GTK_GTK_TREE_H_
+#pragma once
#include <gtk/gtk.h>
#include <set>
@@ -12,6 +13,7 @@
#include "app/table_model_observer.h"
#include "app/tree_model.h"
#include "base/basictypes.h"
+#include "chrome/browser/remove_rows_table_model.h"
class TableModel;
@@ -43,6 +45,17 @@ void GetSelectedIndices(GtkTreeSelection* selection, std::set<int>* out);
// A helper class for populating a GtkListStore from a TableModel.
class TableAdapter : public TableModelObserver {
public:
+
+ enum ColumnID {
+ COL_TITLE = 0,
+ COL_IS_HEADER,
+ COL_IS_SEPARATOR,
+ COL_GROUP_ID,
+ COL_WEIGHT,
+ COL_WEIGHT_SET,
+ COL_LAST_ID
+ };
+
class Delegate {
public:
// Should fill in the column and row.
@@ -65,8 +78,9 @@ class TableAdapter : public TableModelObserver {
};
// |table_model| may be NULL.
- explicit TableAdapter(Delegate* delegate, GtkListStore* list_store,
- TableModel* table_model);
+ TableAdapter(Delegate* delegate,
+ GtkListStore* list_store,
+ TableModel* table_model);
virtual ~TableAdapter() {}
// Replace the TableModel with a different one. If the list store currenty
@@ -75,6 +89,24 @@ class TableAdapter : public TableModelObserver {
// created with a NULL |table_model|.
void SetModel(TableModel* table_model);
+ // Add all model rows corresponding to the given list store indices to |rows|.
+ void MapListStoreIndicesToModelRows(const std::set<int>& list_store_indices,
+ RemoveRowsTableModel::Rows* model_rows);
+
+ // GtkTreeModel callbacks:
+ // Callback checking whether a row should be drawn as a separator.
+ static gboolean OnCheckRowIsSeparator(GtkTreeModel* model,
+ GtkTreeIter* iter,
+ gpointer user_data);
+
+ // Callback checking whether a row may be selected. We use some rows in the
+ // table as headers/separators for the groups, which should not be selectable.
+ static gboolean OnSelectionFilter(GtkTreeSelection* selection,
+ GtkTreeModel* model,
+ GtkTreePath* path,
+ gboolean path_currently_selected,
+ gpointer user_data);
+
// TableModelObserver implementation.
virtual void OnModelChanged();
virtual void OnItemsChanged(int start, int length);
@@ -82,6 +114,13 @@ class TableAdapter : public TableModelObserver {
virtual void OnItemsRemoved(int start, int length);
private:
+ // Return whether the row pointed to by |iter| is a group row, i.e. a group
+ // header, or a separator.
+ bool IsGroupRow(GtkTreeIter* iter) const;
+
+ // Return the index into the list store for the given model row.
+ int GetListStoreIndexForModelRow(int model_row) const;
+
// Add the values from |row| of the TableModel.
void AddNodeToList(int row);
@@ -94,7 +133,6 @@ class TableAdapter : public TableModelObserver {
// A helper class for populating a GtkTreeStore from a TreeModel.
// TODO(mattm): support SetRootShown(true)
-// TODO(mattm): implement TreeNodeChildrenReordered
class TreeAdapter : public TreeModelObserver {
public:
// Column ids for |tree_store_|.
@@ -113,6 +151,9 @@ class TreeAdapter : public TreeModelObserver {
// Called after any change to the GtkTreeStore.
virtual void OnAnyModelUpdate() {}
+
+ protected:
+ virtual ~Delegate() {}
};
TreeAdapter(Delegate* delegate, TreeModel* tree_model);
@@ -127,7 +168,7 @@ class TreeAdapter : public TreeModelObserver {
// Get the TreeModelNode corresponding to iter in the tree store.
TreeModelNode* GetNode(GtkTreeIter* iter);
- // TreeModelObserver implementation.
+ // Begin TreeModelObserver implementation.
virtual void TreeNodesAdded(TreeModel* model,
TreeModelNode* parent,
int start,
@@ -136,9 +177,8 @@ class TreeAdapter : public TreeModelObserver {
TreeModelNode* parent,
int start,
int count);
- virtual void TreeNodeChildrenReordered(TreeModel* model,
- TreeModelNode* parent);
virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node);
+ // End TreeModelObserver implementation.
private:
// Fill the tree store values for a given node.
@@ -158,6 +198,8 @@ class TreeAdapter : public TreeModelObserver {
GtkTreeStore* tree_store_;
TreeModel* tree_model_;
std::vector<GdkPixbuf*> pixbufs_;
+
+ DISALLOW_COPY_AND_ASSIGN(TreeAdapter);
};
} // namespace gtk_tree
diff --git a/chrome/browser/gtk/gtk_util.cc b/chrome/browser/gtk/gtk_util.cc
index f0bfb55..2ada5d7 100644
--- a/chrome/browser/gtk/gtk_util.cc
+++ b/chrome/browser/gtk/gtk_util.cc
@@ -18,6 +18,7 @@
#include "base/i18n/rtl.h"
#include "base/linux_util.h"
#include "base/logging.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
@@ -71,6 +72,13 @@ gboolean OnMouseButtonReleased(GtkWidget* widget, GdkEventButton* event,
return TRUE;
}
+void OnLabelRealize(GtkWidget* label, gpointer pixel_width) {
+ gtk_label_set_width_chars(
+ GTK_LABEL(label),
+ gtk_util::GetCharacterWidthForPixels(label,
+ GPOINTER_TO_INT(pixel_width)));
+}
+
// Ownership of |icon_list| is passed to the caller.
GList* GetIconList() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
@@ -902,6 +910,26 @@ bool AddWindowAlphaChannel(GtkWidget* window) {
return rgba;
}
+void GetTextColors(GdkColor* normal_base,
+ GdkColor* selected_base,
+ GdkColor* normal_text,
+ GdkColor* selected_text) {
+ GtkWidget* fake_entry = gtk_entry_new();
+ GtkStyle* style = gtk_rc_get_style(fake_entry);
+
+ if (normal_base)
+ *normal_base = style->base[GTK_STATE_NORMAL];
+ if (selected_base)
+ *selected_base = style->base[GTK_STATE_SELECTED];
+ if (normal_text)
+ *normal_text = style->text[GTK_STATE_NORMAL];
+ if (selected_text)
+ *selected_text = style->text[GTK_STATE_SELECTED];
+
+ g_object_ref_sink(fake_entry);
+ g_object_unref(fake_entry);
+}
+
#if defined(OS_CHROMEOS)
GtkWindow* GetDialogTransientParent(GtkWindow* dialog) {
@@ -1026,7 +1054,56 @@ gfx::Rect GetDialogBounds(GtkWidget* dialog) {
return gfx::Rect(x, y, width, height);
}
-
#endif
+string16 GetStockPreferencesMenuLabel() {
+ GtkStockItem stock_item;
+ string16 preferences;
+ if (gtk_stock_lookup(GTK_STOCK_PREFERENCES, &stock_item)) {
+ const char16 kUnderscore[] = { '_', 0 };
+ RemoveChars(UTF8ToUTF16(stock_item.label), kUnderscore, &preferences);
+ }
+ return preferences;
+}
+
+bool IsWidgetAncestryVisible(GtkWidget* widget) {
+ GtkWidget* parent = widget;
+ while (parent && GTK_WIDGET_VISIBLE(parent))
+ parent = parent->parent;
+ return !parent;
+}
+
+void SetGtkFont(const std::string& font_name) {
+ g_object_set(gtk_settings_get_default(),
+ "gtk-font-name", font_name.c_str(), NULL);
+}
+
+void SetLabelWidth(GtkWidget* label, int pixel_width) {
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+
+ // Do the simple thing in LTR because the bug only affects right-aligned
+ // text. Also, when using the workaround, the label tries to maintain
+ // uniform line-length, which we don't really want.
+ if (gtk_widget_get_direction(label) == GTK_TEXT_DIR_LTR) {
+ gtk_widget_set_size_request(label, pixel_width, -1);
+ } else {
+ // The label has to be realized before we can adjust its width.
+ if (GTK_WIDGET_REALIZED(label)) {
+ OnLabelRealize(label, GINT_TO_POINTER(pixel_width));
+ } else {
+ g_signal_connect(label, "realize", G_CALLBACK(OnLabelRealize),
+ GINT_TO_POINTER(pixel_width));
+ }
+ }
+}
+
+void InitLabelSizeRequestAndEllipsizeMode(GtkWidget* label) {
+ GtkRequisition size;
+ gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_NONE);
+ gtk_widget_set_size_request(label, -1, -1);
+ gtk_widget_size_request(label, &size);
+ gtk_widget_set_size_request(label, size.width, size.height);
+ gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
+}
+
} // namespace gtk_util
diff --git a/chrome/browser/gtk/gtk_util.h b/chrome/browser/gtk/gtk_util.h
index 7fed9e4..9c59fb5 100644
--- a/chrome/browser/gtk/gtk_util.h
+++ b/chrome/browser/gtk/gtk_util.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_GTK_GTK_UTIL_H_
#define CHROME_BROWSER_GTK_GTK_UTIL_H_
+#pragma once
#include <gtk/gtk.h>
#include <string>
#include <vector>
#include "app/x11_util.h"
+#include "base/string16.h"
#include "gfx/point.h"
#include "gfx/rect.h"
#include "webkit/glue/window_open_disposition.h"
@@ -280,6 +282,12 @@ bool URLFromPrimarySelection(Profile* profile, GURL* url);
// Set the colormap of the given window to rgba to allow transparency.
bool AddWindowAlphaChannel(GtkWidget* window);
+// Get the default colors for a text entry. Parameters may be NULL.
+void GetTextColors(GdkColor* normal_base,
+ GdkColor* selected_base,
+ GdkColor* normal_text,
+ GdkColor* selected_text);
+
// Wrappers to show a GtkDialog. On Linux, it merely calls gtk_widget_show_all.
// On ChromeOs, it calls ShowNativeDialog which hosts the its vbox
// in a view based Window.
@@ -303,6 +311,30 @@ GtkWindow* GetDialogWindow(GtkWidget* dialog);
// Gets dialog window bounds.
gfx::Rect GetDialogBounds(GtkWidget* dialog);
+// Returns the stock menu item label for the "preferences" item - returns an
+// empty string if no stock item found.
+string16 GetStockPreferencesMenuLabel();
+
+// Checks whether a widget is actually visible, i.e. whether it and all its
+// ancestors up to its toplevel are visible.
+bool IsWidgetAncestryVisible(GtkWidget* widget);
+
+// Sets the GTK font from the given font name (ex. "Arial Black, 10").
+void SetGtkFont(const std::string& font_name);
+
+// Sets the given label's size request to |pixel_width|. This will cause the
+// label to wrap if it needs to. The reason for this function is that some
+// versions of GTK mis-align labels that have a size request and line wrapping,
+// and this function hides the complexity of the workaround.
+void SetLabelWidth(GtkWidget* label, int pixel_width);
+
+// Make the |label| shrinkable within a GthChromeShrinkableHBox
+// It calculates the real size request of a label and set its ellipsize mode to
+// PANGO_ELLIPSIZE_END.
+// It must be done when the label is mapped (become visible on the screen),
+// to make sure the pango can get correct font information for the calculation.
+void InitLabelSizeRequestAndEllipsizeMode(GtkWidget* label);
+
} // namespace gtk_util
#endif // CHROME_BROWSER_GTK_GTK_UTIL_H_
diff --git a/chrome/browser/gtk/hover_controller_gtk.h b/chrome/browser/gtk/hover_controller_gtk.h
index 5a4cd9c..19d1ff4 100644
--- a/chrome/browser/gtk/hover_controller_gtk.h
+++ b/chrome/browser/gtk/hover_controller_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_HOVER_CONTROLLER_GTK_H_
#define CHROME_BROWSER_GTK_HOVER_CONTROLLER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,7 +12,6 @@
#include "app/gtk_signal_registrar.h"
#include "app/slide_animation.h"
#include "app/throb_animation.h"
-#include "base/scoped_ptr.h"
// This class handles the "throbbing" of a GtkChromeButton. The visual effect
// of throbbing is created by painting partially transparent hover effects. It
diff --git a/chrome/browser/gtk/html_dialog_gtk.cc b/chrome/browser/gtk/html_dialog_gtk.cc
index dd4c3db..3c9d1fb 100644
--- a/chrome/browser/gtk/html_dialog_gtk.cc
+++ b/chrome/browser/gtk/html_dialog_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.
@@ -6,12 +6,14 @@
#include <gtk/gtk.h>
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/tab_contents_container_gtk.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/native_web_keyboard_event.h"
#include "ipc/ipc_message.h"
// static
@@ -79,13 +81,14 @@ std::string HtmlDialogGtk::GetDialogArgs() const {
}
void HtmlDialogGtk::OnDialogClosed(const std::string& json_retval) {
- DCHECK(delegate_);
DCHECK(dialog_);
- HtmlDialogUIDelegate* dialog_delegate = delegate_;
- delegate_ = NULL; // We will not communicate further with the delegate.
Detach();
- dialog_delegate->OnDialogClosed(json_retval);
+ if (delegate_) {
+ HtmlDialogUIDelegate* dialog_delegate = delegate_;
+ delegate_ = NULL; // We will not communicate further with the delegate.
+ dialog_delegate->OnDialogClosed(json_retval);
+ }
gtk_widget_destroy(dialog_);
delete this;
}
@@ -121,7 +124,7 @@ void HtmlDialogGtk::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
void HtmlDialogGtk::InitDialog() {
tab_contents_.reset(
- new TabContents(profile(), NULL, MSG_ROUTING_NONE, NULL));
+ new TabContents(profile(), NULL, MSG_ROUTING_NONE, NULL, NULL));
tab_contents_->set_delegate(this);
// This must be done before loading the page; see the comments in
@@ -141,7 +144,7 @@ void HtmlDialogGtk::InitDialog() {
flags,
NULL);
- g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this);
+ g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
tab_contents_container_.reset(new TabContentsContainerGtk(NULL));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
@@ -159,8 +162,6 @@ void HtmlDialogGtk::InitDialog() {
gtk_widget_show_all(dialog_);
}
-// static
-void HtmlDialogGtk::OnResponse(GtkWidget* widget, int response,
- HtmlDialogGtk* dialog) {
- dialog->OnDialogClosed(std::string());
+void HtmlDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
+ OnDialogClosed(std::string());
}
diff --git a/chrome/browser/gtk/html_dialog_gtk.h b/chrome/browser/gtk/html_dialog_gtk.h
index 250f1a0..c004624 100644
--- a/chrome/browser/gtk/html_dialog_gtk.h
+++ b/chrome/browser/gtk/html_dialog_gtk.h
@@ -1,13 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_GTK_HTML_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_HTML_DIALOG_GTK_H_
+#pragma once
#include <string>
#include <vector>
+#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h"
@@ -51,8 +53,7 @@ class HtmlDialogGtk : public HtmlDialogTabContentsDelegate,
virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
private:
- static void OnResponse(GtkWidget* widget, int response,
- HtmlDialogGtk* dialog);
+ CHROMEGTK_CALLBACK_1(HtmlDialogGtk, void, OnResponse, int);
// This view is a delegate to the HTML content since it needs to get notified
// about when the dialog is closing. For all other actions (besides dialog
diff --git a/chrome/browser/gtk/hung_renderer_dialog_gtk.cc b/chrome/browser/gtk/hung_renderer_dialog_gtk.cc
index f17915a..5cdca15 100644
--- a/chrome/browser/gtk/hung_renderer_dialog_gtk.cc
+++ b/chrome/browser/gtk/hung_renderer_dialog_gtk.cc
@@ -9,6 +9,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/process_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/render_process_host.h"
@@ -188,8 +189,10 @@ void HungRendererDialogGtk::OnDialogResponse(gint response_id) {
switch (response_id) {
case kKillPagesButtonResponse:
// Kill the process.
- base::KillProcess(contents_->GetRenderProcessHost()->GetHandle(),
- ResultCodes::HUNG, false);
+ if (contents_ && contents_->GetRenderProcessHost()) {
+ base::KillProcess(contents_->GetRenderProcessHost()->GetHandle(),
+ ResultCodes::HUNG, false);
+ }
break;
case GTK_RESPONSE_OK:
diff --git a/chrome/browser/gtk/import_dialog_gtk.cc b/chrome/browser/gtk/import_dialog_gtk.cc
index 5af8aec..786007c 100644
--- a/chrome/browser/gtk/import_dialog_gtk.cc
+++ b/chrome/browser/gtk/import_dialog_gtk.cc
@@ -7,7 +7,6 @@
#include <string>
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
diff --git a/chrome/browser/gtk/import_dialog_gtk.h b/chrome/browser/gtk/import_dialog_gtk.h
index 8b2b220..a1126b8 100644
--- a/chrome/browser/gtk/import_dialog_gtk.h
+++ b/chrome/browser/gtk/import_dialog_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_IMPORT_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_IMPORT_DIALOG_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "chrome/browser/importer/importer.h"
diff --git a/chrome/browser/gtk/import_lock_dialog_gtk.cc b/chrome/browser/gtk/import_lock_dialog_gtk.cc
index dac4123..02c4b8d 100644
--- a/chrome/browser/gtk/import_lock_dialog_gtk.cc
+++ b/chrome/browser/gtk/import_lock_dialog_gtk.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/gtk/import_lock_dialog_gtk.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/importer/importer.h"
diff --git a/chrome/browser/gtk/import_lock_dialog_gtk.h b/chrome/browser/gtk/import_lock_dialog_gtk.h
index ebcee7f..96f9b13 100644
--- a/chrome/browser/gtk/import_lock_dialog_gtk.h
+++ b/chrome/browser/gtk/import_lock_dialog_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_IMPORT_LOCK_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_IMPORT_LOCK_DIALOG_GTK_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/import_progress_dialog_gtk.cc b/chrome/browser/gtk/import_progress_dialog_gtk.cc
index 09e30da..7e0e297 100644
--- a/chrome/browser/gtk/import_progress_dialog_gtk.cc
+++ b/chrome/browser/gtk/import_progress_dialog_gtk.cc
@@ -7,7 +7,6 @@
#include <string>
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "grit/chromium_strings.h"
diff --git a/chrome/browser/gtk/import_progress_dialog_gtk.h b/chrome/browser/gtk/import_progress_dialog_gtk.h
index a990ca7..d7a6408 100644
--- a/chrome/browser/gtk/import_progress_dialog_gtk.h
+++ b/chrome/browser/gtk/import_progress_dialog_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_IMPORT_PROGRESS_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_IMPORT_PROGRESS_DIALOG_GTK_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/info_bubble_gtk.cc b/chrome/browser/gtk/info_bubble_gtk.cc
index 3f155ea..87c2164 100644
--- a/chrome/browser/gtk/info_bubble_gtk.cc
+++ b/chrome/browser/gtk/info_bubble_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.
@@ -7,7 +7,6 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
@@ -20,14 +19,15 @@
namespace {
// The height of the arrow, and the width will be about twice the height.
-const int kArrowSize = 5;
+const int kArrowSize = 8;
-// Number of pixels to the start of the arrow from the edge of the window.
-const int kArrowX = 13;
+// Number of pixels to the middle of the arrow from the close edge of the
+// window.
+const int kArrowX = 18;
// Number of pixels between the tip of the arrow and the region we're
// pointing to.
-const int kArrowToContentPadding = -6;
+const int kArrowToContentPadding = -4;
// We draw flat diagonal corners, each corner is an NxN square.
const int kCornerSize = 3;
@@ -65,6 +65,7 @@ InfoBubbleGtk::InfoBubbleGtk(GtkThemeProvider* provider,
theme_provider_(provider),
accel_group_(gtk_accel_group_new()),
toplevel_window_(NULL),
+ anchor_widget_(NULL),
mask_region_(NULL),
preferred_arrow_location_(ARROW_LOCATION_TOP_LEFT),
current_arrow_location_(ARROW_LOCATION_TOP_LEFT),
@@ -290,6 +291,7 @@ void InfoBubbleGtk::UpdateWindowShape() {
mask_region_ = gdk_region_polygon(&points[0],
points.size(),
GDK_EVEN_ODD_RULE);
+ gdk_window_shape_combine_region(window_->window, NULL, 0, 0);
gdk_window_shape_combine_region(window_->window, mask_region_, 0, 0);
}
diff --git a/chrome/browser/gtk/info_bubble_gtk.h b/chrome/browser/gtk/info_bubble_gtk.h
index d13a965..39070ee 100644
--- a/chrome/browser/gtk/info_bubble_gtk.h
+++ b/chrome/browser/gtk/info_bubble_gtk.h
@@ -12,12 +12,14 @@
#ifndef CHROME_BROWSER_GTK_INFO_BUBBLE_GTK_H_
#define CHROME_BROWSER_GTK_INFO_BUBBLE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include "app/gtk_signal.h"
#include "app/gtk_signal_registrar.h"
#include "base/basictypes.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/point.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/gtk/infobar_container_gtk.h b/chrome/browser/gtk/infobar_container_gtk.h
index 56a7b95..441072f 100644
--- a/chrome/browser/gtk/infobar_container_gtk.h
+++ b/chrome/browser/gtk/infobar_container_gtk.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_GTK_INFOBAR_CONTAINER_GTK_H_
#define CHROME_BROWSER_GTK_INFOBAR_CONTAINER_GTK_H_
+#pragma once
#include "base/basictypes.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class InfoBarDelegate;
class Profile;
diff --git a/chrome/browser/gtk/infobar_gtk.cc b/chrome/browser/gtk/infobar_gtk.cc
index a389853..1af4315 100644
--- a/chrome/browser/gtk/infobar_gtk.cc
+++ b/chrome/browser/gtk/infobar_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.
@@ -9,6 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
+#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/gtk/infobar_container_gtk.h"
@@ -17,10 +18,10 @@
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};
+// Spacing after message (and before buttons).
+const int kEndOfLabelSpacing = 6;
+// Spacing between buttons.
+const int kButtonButtonSpacing = 3;
// The total height of the info bar.
const int kInfoBarHeight = 37;
@@ -145,21 +146,53 @@ void InfoBar::Observe(NotificationType type,
UpdateBorderColor();
}
+void InfoBar::AddLabelWithInlineLink(const string16& display_text,
+ const string16& link_text,
+ size_t link_offset,
+ GCallback callback) {
+ GtkWidget* link_button = gtk_chrome_link_button_new(
+ UTF16ToUTF8(link_text).c_str());
+ gtk_chrome_link_button_set_use_gtk_theme(
+ GTK_CHROME_LINK_BUTTON(link_button), FALSE);
+ DCHECK(callback);
+ g_signal_connect(link_button, "clicked", callback, this);
+ gtk_util::SetButtonTriggersNavigation(link_button);
+
+ GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
+ // We want the link to be horizontally shrinkable, so that the Chrome
+ // window can be resized freely even with a very long link.
+ gtk_widget_set_size_request(hbox, 0, -1);
+ gtk_box_pack_start(GTK_BOX(hbox_), hbox, TRUE, TRUE, 0);
+
+ // Need to insert the link inside the display text.
+ GtkWidget* initial_label = gtk_label_new(
+ UTF16ToUTF8(display_text.substr(0, link_offset)).c_str());
+ GtkWidget* trailing_label = gtk_label_new(
+ UTF16ToUTF8(display_text.substr(link_offset)).c_str());
+
+ // TODO(joth): Unlike the AddLabalAndLink below, none of the label widgets
+ // are set as shrinkable here, meaning the text will run under the close
+ // button etc. when the width is restricted, rather than eliding.
+ gtk_widget_modify_fg(initial_label, GTK_STATE_NORMAL, &gfx::kGdkBlack);
+ gtk_widget_modify_fg(trailing_label, GTK_STATE_NORMAL, &gfx::kGdkBlack);
+
+ // We don't want any spacing between the elements, so we pack them into
+ // this hbox that doesn't use kElementPadding.
+ gtk_box_pack_start(GTK_BOX(hbox), initial_label, FALSE, FALSE, 0);
+ gtk_util::CenterWidgetInHBox(hbox, link_button, false, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0);
+}
+
// 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 InfoBar::AddLabelAndLink(const std::wstring& display_text,
- const std::wstring& link_text,
- size_t link_offset,
- guint link_padding,
+void InfoBar::AddLabelAndLink(const string16& display_text,
+ const string16& link_text,
GCallback callback) {
GtkWidget* link_button = NULL;
- if (link_text.empty()) {
- // No link text, so skip creating the link and splitting display_text.
- link_offset = std::wstring::npos;
- } else {
+ if (!link_text.empty()) {
// If we have some link text, create the link button.
- link_button = gtk_chrome_link_button_new(WideToUTF8(link_text).c_str());
+ link_button = gtk_chrome_link_button_new(UTF16ToUTF8(link_text).c_str());
gtk_chrome_link_button_set_use_gtk_theme(
GTK_CHROME_LINK_BUTTON(link_button), FALSE);
DCHECK(callback);
@@ -173,39 +206,16 @@ void InfoBar::AddLabelAndLink(const std::wstring& display_text,
gtk_widget_set_size_request(hbox, 0, -1);
gtk_box_pack_start(GTK_BOX(hbox_), hbox, TRUE, TRUE, 0);
- // If link_offset is npos, we right-align the link instead of embedding it
- // in the text.
- if (link_offset == std::wstring::npos) {
- if (link_button)
- gtk_box_pack_end(GTK_BOX(hbox), link_button, FALSE, FALSE, 0);
- GtkWidget* label = gtk_label_new(WideToUTF8(display_text).c_str());
- // In order to avoid the link_button and the label overlapping with each
- // other, we make the label shrinkable.
- gtk_widget_set_size_request(label, 0, -1);
- gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
- gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gfx::kGdkBlack);
- gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
- } else {
- DCHECK(link_button);
- // Need to insert the link inside the display text.
- GtkWidget* initial_label = gtk_label_new(
- WideToUTF8(display_text.substr(0, link_offset)).c_str());
- GtkWidget* trailing_label = gtk_label_new(
- WideToUTF8(display_text.substr(link_offset)).c_str());
-
- // TODO(joth): Unlike the right-align case above, none of the label widgets
- // are set as shrinkable here, meaning the text will run under the close
- // button etc. when the width is restricted, rather than eliding.
- gtk_widget_modify_fg(initial_label, GTK_STATE_NORMAL, &gfx::kGdkBlack);
- gtk_widget_modify_fg(trailing_label, GTK_STATE_NORMAL, &gfx::kGdkBlack);
-
- // We don't want any spacing between the elements, so we pack them into
- // this hbox that doesn't use kElementPadding.
- gtk_box_pack_start(GTK_BOX(hbox), initial_label, FALSE, FALSE, 0);
- gtk_util::CenterWidgetInHBox(hbox, link_button, false, link_padding);
- gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0);
- }
+ if (link_button)
+ gtk_box_pack_end(GTK_BOX(hbox), link_button, FALSE, FALSE, 0);
+ GtkWidget* label = gtk_label_new(UTF16ToUTF8(display_text).c_str());
+ // In order to avoid the link_button and the label overlapping with each
+ // other, we make the label shrinkable.
+ gtk_widget_set_size_request(label, 0, -1);
+ gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+ gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gfx::kGdkBlack);
+ gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
}
void InfoBar::GetTopColor(InfoBarDelegate::Type type,
@@ -214,13 +224,7 @@ void InfoBar::GetTopColor(InfoBarDelegate::Type type,
// browser/views/infobars/infobars.cc, and then changed into 0-1 ranged
// values for cairo.
switch (type) {
- case InfoBarDelegate::INFO_TYPE:
- *r = 170.0 / 255.0;
- *g = 214.0 / 255.0;
- *b = 112.0 / 255.0;
- break;
case InfoBarDelegate::WARNING_TYPE:
- case InfoBarDelegate::ERROR_TYPE:
*r = 255.0 / 255.0;
*g = 242.0 / 255.0;
*b = 183.0 / 255.0;
@@ -236,13 +240,7 @@ void InfoBar::GetTopColor(InfoBarDelegate::Type type,
void InfoBar::GetBottomColor(InfoBarDelegate::Type type,
double* r, double* g, double *b) {
switch (type) {
- case InfoBarDelegate::INFO_TYPE:
- *r = 146.0 / 255.0;
- *g = 205.0 / 255.0;
- *b = 114.0 / 255.0;
- break;
case InfoBarDelegate::WARNING_TYPE:
- case InfoBarDelegate::ERROR_TYPE:
*r = 250.0 / 255.0;
*g = 230.0 / 255.0;
*b = 145.0 / 255.0;
@@ -299,7 +297,7 @@ class AlertInfoBar : public InfoBar {
public:
explicit AlertInfoBar(AlertInfoBarDelegate* delegate)
: InfoBar(delegate) {
- AddLabelAndLink(delegate->GetMessageText(), std::wstring(), 0, 0, NULL);
+ AddLabelAndLink(delegate->GetMessageText(), string16(), NULL);
gtk_widget_show_all(border_bin_.get());
}
};
@@ -311,11 +309,10 @@ class LinkInfoBar : public InfoBar {
explicit LinkInfoBar(LinkInfoBarDelegate* delegate)
: InfoBar(delegate) {
size_t link_offset;
- std::wstring display_text =
- delegate->GetMessageTextWithOffset(&link_offset);
- std::wstring link_text = delegate->GetLinkText();
- AddLabelAndLink(display_text, link_text, link_offset, 0,
- G_CALLBACK(OnLinkClick));
+ string16 display_text = delegate->GetMessageTextWithOffset(&link_offset);
+ string16 link_text = delegate->GetLinkText();
+ AddLabelWithInlineLink(display_text, link_text, link_offset,
+ G_CALLBACK(OnLinkClick));
gtk_widget_show_all(border_bin_.get());
}
@@ -332,64 +329,88 @@ class LinkInfoBar : public InfoBar {
class ConfirmInfoBar : public InfoBar {
public:
- explicit ConfirmInfoBar(ConfirmInfoBarDelegate* delegate)
- : InfoBar(delegate) {
- AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_CANCEL);
- AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_OK);
- std::wstring display_text = delegate->GetMessageText();
- std::wstring link_text = delegate->GetLinkText();
- AddLabelAndLink(display_text, link_text, display_text.size(),
- kElementPadding, G_CALLBACK(OnLinkClick));
- gtk_widget_show_all(border_bin_.get());
- }
+ explicit ConfirmInfoBar(ConfirmInfoBarDelegate* delegate);
private:
// Adds a button to the info bar by type. It will do nothing if the delegate
// doesn't specify a button of the given type.
- void AddConfirmButton(ConfirmInfoBarDelegate::InfoBarButton type) {
- if (delegate_->AsConfirmInfoBarDelegate()->GetButtons() & type) {
- GtkWidget* button = gtk_button_new_with_label(WideToUTF8(
- delegate_->AsConfirmInfoBarDelegate()->GetButtonLabel(type)).c_str());
- gtk_util::CenterWidgetInHBox(hbox_, button, true, 0);
- g_signal_connect(button, "clicked",
- G_CALLBACK(type == ConfirmInfoBarDelegate::BUTTON_OK ?
- OnOkButton : OnCancelButton),
- this);
- }
- }
+ void AddButton(ConfirmInfoBarDelegate::InfoBarButton type);
- static void OnCancelButton(GtkWidget* button, ConfirmInfoBar* info_bar) {
- if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Cancel())
- info_bar->RemoveInfoBar();
- }
+ CHROMEGTK_CALLBACK_0(ConfirmInfoBar, void, OnOkButton);
+ CHROMEGTK_CALLBACK_0(ConfirmInfoBar, void, OnCancelButton);
+ CHROMEGTK_CALLBACK_0(ConfirmInfoBar, void, OnLinkClicked);
- static void OnOkButton(GtkWidget* button, ConfirmInfoBar* info_bar) {
- if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Accept())
- info_bar->RemoveInfoBar();
- }
+ GtkWidget* confirm_hbox_;
- static void OnLinkClick(GtkWidget* button, ConfirmInfoBar* link_info_bar) {
- if (link_info_bar->delegate_->AsConfirmInfoBarDelegate()->
- LinkClicked(gtk_util::DispositionForCurrentButtonPressEvent())) {
- link_info_bar->RemoveInfoBar();
- }
- }
+ DISALLOW_COPY_AND_ASSIGN(ConfirmInfoBar);
};
-// AlertInfoBarDelegate, InfoBarDelegate overrides: ----------------------------
+ConfirmInfoBar::ConfirmInfoBar(ConfirmInfoBarDelegate* delegate)
+ : InfoBar(delegate) {
+ confirm_hbox_ = gtk_chrome_shrinkable_hbox_new(FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox_), confirm_hbox_, TRUE, TRUE, 0);
+ gtk_widget_set_size_request(confirm_hbox_, 0, -1);
+
+ std::string label_text = UTF16ToUTF8(delegate->GetMessageText());
+ GtkWidget* label = gtk_label_new(label_text.c_str());
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+ gtk_util::CenterWidgetInHBox(confirm_hbox_, label, false, kEndOfLabelSpacing);
+ g_signal_connect(label, "map",
+ G_CALLBACK(gtk_util::InitLabelSizeRequestAndEllipsizeMode),
+ NULL);
+
+ AddButton(ConfirmInfoBarDelegate::BUTTON_CANCEL);
+ AddButton(ConfirmInfoBarDelegate::BUTTON_OK);
+
+ std::string link_text = UTF16ToUTF8(delegate->GetLinkText());
+ GtkWidget* link = gtk_chrome_link_button_new(link_text.c_str());
+ gtk_misc_set_alignment(GTK_MISC(GTK_CHROME_LINK_BUTTON(link)->label), 0, 0.5);
+ g_signal_connect(link, "clicked", G_CALLBACK(OnLinkClickedThunk), this);
+ gtk_util::SetButtonTriggersNavigation(link);
+ // Until we switch to vector graphics, force the font size.
+ // 13.4px == 10pt @ 96dpi
+ gtk_util::ForceFontSizePixels(GTK_CHROME_LINK_BUTTON(link)->label, 13.4);
+ gtk_util::CenterWidgetInHBox(hbox_, link, true, kEndOfLabelSpacing);
+
+ gtk_widget_show_all(border_bin_.get());
+}
-InfoBar* AlertInfoBarDelegate::CreateInfoBar() {
- return new AlertInfoBar(this);
+void ConfirmInfoBar::AddButton(ConfirmInfoBarDelegate::InfoBarButton type) {
+ if (delegate_->AsConfirmInfoBarDelegate()->GetButtons() & type) {
+ GtkWidget* button = gtk_button_new_with_label(UTF16ToUTF8(
+ delegate_->AsConfirmInfoBarDelegate()->GetButtonLabel(type)).c_str());
+ gtk_util::CenterWidgetInHBox(confirm_hbox_, button, false,
+ kButtonButtonSpacing);
+ g_signal_connect(button, "clicked",
+ G_CALLBACK(type == ConfirmInfoBarDelegate::BUTTON_OK ?
+ OnOkButtonThunk : OnCancelButtonThunk),
+ this);
+ }
}
-// LinkInfoBarDelegate, InfoBarDelegate overrides: -----------------------------
+void ConfirmInfoBar::OnCancelButton(GtkWidget* widget) {
+ if (delegate_->AsConfirmInfoBarDelegate()->Cancel())
+ RemoveInfoBar();
+}
-InfoBar* LinkInfoBarDelegate::CreateInfoBar() {
- return new LinkInfoBar(this);
+void ConfirmInfoBar::OnOkButton(GtkWidget* widget) {
+ if (delegate_->AsConfirmInfoBarDelegate()->Accept())
+ RemoveInfoBar();
}
-// ConfirmInfoBarDelegate, InfoBarDelegate overrides: --------------------------
+void ConfirmInfoBar::OnLinkClicked(GtkWidget* widget) {
+ if (delegate_->AsConfirmInfoBarDelegate()->LinkClicked(
+ gtk_util::DispositionForCurrentButtonPressEvent())) {
+ RemoveInfoBar();
+ }
+}
+InfoBar* AlertInfoBarDelegate::CreateInfoBar() {
+ return new AlertInfoBar(this);
+}
+InfoBar* LinkInfoBarDelegate::CreateInfoBar() {
+ return new LinkInfoBar(this);
+}
InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() {
return new ConfirmInfoBar(this);
}
diff --git a/chrome/browser/gtk/infobar_gtk.h b/chrome/browser/gtk/infobar_gtk.h
index 9b83354..790b0f6 100644
--- a/chrome/browser/gtk/infobar_gtk.h
+++ b/chrome/browser/gtk/infobar_gtk.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_GTK_INFOBAR_GTK_H_
#define CHROME_BROWSER_GTK_INFOBAR_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/gtk/slide_animator_gtk.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class CustomDrawButton;
class GtkThemeProvider;
@@ -69,14 +70,18 @@ class InfoBar : public SlideAnimatorGtk::Delegate,
// Adds |display_text| to the infobar. If |link_text| is not empty, it is
// rendered as a hyperlink and inserted into |display_text| at |link_offset|,
- // or right aligned in the infobar if |link_offset| is |npos|. |link_padding|
- // pixels are inserted around the link (pass 0 for not padding). If a link
- // is supplied, |link_callback| must not be null. It will be invoked on click.
- void AddLabelAndLink(const std::wstring& display_text,
- const std::wstring& link,
- size_t link_offset,
- guint link_padding,
- GCallback link_callback);
+ // or right aligned in the infobar if |link_offset| is |npos|. If a link is
+ // supplied, |link_callback| must not be null. It will be invoked on click.
+ void AddLabelWithInlineLink(const string16& display_text,
+ const string16& link_text,
+ size_t link_offset,
+ GCallback callback);
+
+ // Adds |display_text| to the infobar. If |link_text| is not empty, it is
+ // right aligned in the infobar.
+ void AddLabelAndLink(const string16& display_text,
+ const string16& link_text,
+ GCallback callback);
// Retrieves the component colors for the infobar's background
// gradient. (This varies by infobars and can be animated to change).
diff --git a/chrome/browser/gtk/keyword_editor_view.cc b/chrome/browser/gtk/keyword_editor_view.cc
index 6786f45..5937bfb 100644
--- a/chrome/browser/gtk/keyword_editor_view.cc
+++ b/chrome/browser/gtk/keyword_editor_view.cc
@@ -23,6 +23,7 @@
#include "gfx/gtk_util.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
+#include "third_party/skia/include/core/SkBitmap.h"
namespace {
@@ -58,8 +59,8 @@ void KeywordEditorView::Show(Profile* profile) {
}
void KeywordEditorView::OnEditedKeyword(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url) {
if (template_url) {
controller_->ModifyTemplateURL(template_url, title, keyword, url);
diff --git a/chrome/browser/gtk/keyword_editor_view.h b/chrome/browser/gtk/keyword_editor_view.h
index 3ce4b49..451d635 100644
--- a/chrome/browser/gtk/keyword_editor_view.h
+++ b/chrome/browser/gtk/keyword_editor_view.h
@@ -4,14 +4,17 @@
#ifndef CHROME_BROWSER_GTK_KEYWORD_EDITOR_VIEW_H_
#define CHROME_BROWSER_GTK_KEYWORD_EDITOR_VIEW_H_
+#pragma once
#include <gtk/gtk.h>
#include "app/table_model_observer.h"
#include "base/basictypes.h"
#include "base/gtest_prod_util.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/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
class AccessibleWidgetHelper;
class KeywordEditorController;
@@ -29,8 +32,8 @@ class KeywordEditorView : public TableModelObserver,
// Overriden from EditSearchEngineControllerDelegate.
virtual void OnEditedKeyword(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url);
private:
// Column ids for |list_store_|.
diff --git a/chrome/browser/gtk/keyword_editor_view_unittest.cc b/chrome/browser/gtk/keyword_editor_view_unittest.cc
index 431a868..636d6bd 100644
--- a/chrome/browser/gtk/keyword_editor_view_unittest.cc
+++ b/chrome/browser/gtk/keyword_editor_view_unittest.cc
@@ -9,7 +9,9 @@
#include <string>
#include <vector>
+#include "base/string16.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
@@ -105,7 +107,8 @@ TEST_F(KeywordEditorViewTest, Add) {
EXPECT_STREQ("!,_,A1 (Default),_,@,_", GetDisplayedEngines(editor).c_str());
EXPECT_EQ(-1, GetSelectedRowNum(editor));
- editor.OnEditedKeyword(NULL, L"B", L"b", "example.com");
+ editor.OnEditedKeyword(NULL, ASCIIToUTF16("B"), ASCIIToUTF16("b"),
+ "example.com");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.add_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.edit_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.remove_button_));
@@ -113,7 +116,8 @@ TEST_F(KeywordEditorViewTest, Add) {
EXPECT_STREQ("!,_,A1 (Default),_,@,_,B", GetDisplayedEngines(editor).c_str());
EXPECT_EQ(6, GetSelectedRowNum(editor));
- editor.OnEditedKeyword(NULL, L"C", L"c", "example.com/{searchTerms}");
+ editor.OnEditedKeyword(NULL, ASCIIToUTF16("C"), ASCIIToUTF16("c"),
+ "example.com/{searchTerms}");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.add_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.edit_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.remove_button_));
@@ -122,7 +126,8 @@ TEST_F(KeywordEditorViewTest, Add) {
GetDisplayedEngines(editor).c_str());
EXPECT_EQ(7, GetSelectedRowNum(editor));
- editor.OnEditedKeyword(NULL, L"D", L"d", "example.com");
+ editor.OnEditedKeyword(NULL, ASCIIToUTF16("D"), ASCIIToUTF16("d"),
+ "example.com");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.add_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.edit_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(editor.remove_button_));
@@ -239,23 +244,28 @@ TEST_F(KeywordEditorViewTest, Edit) {
EXPECT_STREQ("!,_,A,B (Default),_,@,_,C,D",
GetDisplayedEngines(editor).c_str());
- editor.OnEditedKeyword(a, L"AA", L"a", "example.com/{searchTerms}");
+ editor.OnEditedKeyword(a, ASCIIToUTF16("AA"), ASCIIToUTF16("a"),
+ "example.com/{searchTerms}");
EXPECT_STREQ("!,_,AA,B (Default),_,@,_,C,D",
GetDisplayedEngines(editor).c_str());
- editor.OnEditedKeyword(b, L"BB", L"b", "foo.example.com/{searchTerms}");
+ editor.OnEditedKeyword(b, ASCIIToUTF16("BB"), ASCIIToUTF16("b"),
+ "foo.example.com/{searchTerms}");
EXPECT_STREQ("!,_,AA,BB (Default),_,@,_,C,D",
GetDisplayedEngines(editor).c_str());
- editor.OnEditedKeyword(b, L"BBB", L"b", "example.com");
+ editor.OnEditedKeyword(b, ASCIIToUTF16("BBB"), ASCIIToUTF16("b"),
+ "example.com");
EXPECT_STREQ("!,_,AA,BBB,_,@,_,C,D",
GetDisplayedEngines(editor).c_str());
- editor.OnEditedKeyword(d, L"DD", L"d", "example.com");
+ editor.OnEditedKeyword(d, ASCIIToUTF16("DD"), ASCIIToUTF16("d"),
+ "example.com");
EXPECT_STREQ("!,_,AA,BBB,_,@,_,C,DD",
GetDisplayedEngines(editor).c_str());
- editor.OnEditedKeyword(c, L"CC", L"cc", "example.com");
+ editor.OnEditedKeyword(c, ASCIIToUTF16("CC"), ASCIIToUTF16("cc"),
+ "example.com");
EXPECT_STREQ("!,_,AA,BBB,_,@,_,CC,DD",
GetDisplayedEngines(editor).c_str());
}
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index 24c7151..8d68fa5 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -13,6 +13,7 @@
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/accessibility_events.h"
#include "chrome/browser/alternate_nav_url_fetcher.h"
@@ -23,7 +24,6 @@
#include "chrome/browser/content_setting_bubble_model.h"
#include "chrome/browser/content_setting_image_model.h"
#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/extension_accessibility_api_constants.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"
@@ -76,10 +76,10 @@ const int kFirstRunBubbleTopMargin = 5;
// We don't want to edit control's text to be right against the edge,
// as well the tab to search box and other widgets need to have the padding on
// top and bottom to avoid drawing larger than the location bar space.
-const int kHboxBorder = 4;
+const int kHboxBorder = 2;
// Padding between the elements in the bar.
-const int kInnerPadding = 4;
+const int kInnerPadding = 2;
// Padding between the right of the star and the edge of the URL entry.
const int kStarRightPadding = 2;
@@ -118,11 +118,6 @@ const GdkColor LocationBarViewGtk::kBackgroundColor =
LocationBarViewGtk::LocationBarViewGtk(Browser* browser)
: star_image_(NULL),
starred_(false),
- security_icon_event_box_(NULL),
- ev_secure_icon_image_(NULL),
- secure_icon_image_(NULL),
- security_warning_icon_image_(NULL),
- security_error_icon_image_(NULL),
site_type_alignment_(NULL),
site_type_event_box_(NULL),
location_icon_image_(NULL),
@@ -209,7 +204,7 @@ void LocationBarViewGtk::Init(bool popup_window_mode) {
GtkWidget* tab_to_search_hbox = gtk_hbox_new(FALSE, 0);
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
tab_to_search_magnifier_ = gtk_image_new_from_pixbuf(
- rb.GetPixbufNamed(IDR_OMNIBOX_SEARCH));
+ rb.GetPixbufNamed(IDR_KEYWORD_SEARCH_MAGNIFIER));
gtk_box_pack_start(GTK_BOX(tab_to_search_hbox), tab_to_search_magnifier_,
FALSE, FALSE, 0);
gtk_util::CenterWidgetInHBox(tab_to_search_hbox, tab_to_search_label_hbox,
@@ -262,16 +257,16 @@ void LocationBarViewGtk::Init(bool popup_window_mode) {
gtk_box_pack_end(GTK_BOX(entry_box_), tab_to_search_hint_, FALSE, FALSE, 0);
// We don't show the star in popups, app windows, etc.
- if (!ShouldOnlyShowLocation()) {
+ if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) {
CreateStarButton();
gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0);
}
- content_setting_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding));
+ content_setting_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding + 1));
gtk_widget_set_name(content_setting_hbox_.get(),
"chrome-content-setting-hbox");
gtk_box_pack_end(GTK_BOX(hbox_.get()), content_setting_hbox_.get(),
- FALSE, FALSE, 0);
+ FALSE, FALSE, 1);
for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
ContentSettingImageViewGtk* content_setting_view =
@@ -304,7 +299,11 @@ void LocationBarViewGtk::Init(bool popup_window_mode) {
void LocationBarViewGtk::BuildSiteTypeArea() {
location_icon_image_ = gtk_image_new();
gtk_widget_set_name(location_icon_image_, "chrome-location-icon");
- gtk_widget_show(location_icon_image_);
+
+ GtkWidget* icon_alignment = gtk_alignment_new(0, 0, 1, 1);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(icon_alignment), 0, 0, 2, 0);
+ gtk_container_add(GTK_CONTAINER(icon_alignment), location_icon_image_);
+ gtk_widget_show_all(icon_alignment);
security_info_label_ = gtk_label_new(NULL);
gtk_label_set_ellipsize(GTK_LABEL(security_info_label_),
@@ -314,11 +313,11 @@ void LocationBarViewGtk::BuildSiteTypeArea() {
gtk_widget_set_name(security_info_label_,
"chrome-location-bar-security-info-label");
- GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 0);
- gtk_box_pack_start(GTK_BOX(site_type_hbox), location_icon_image_,
+ GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(site_type_hbox), icon_alignment,
FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(site_type_hbox), security_info_label_,
- FALSE, FALSE, kCornerSize);
+ FALSE, FALSE, 1);
site_type_event_box_ = gtk_event_box_new();
gtk_widget_modify_bg(site_type_event_box_, GTK_STATE_NORMAL,
@@ -341,7 +340,7 @@ void LocationBarViewGtk::BuildSiteTypeArea() {
// Put the event box in an alignment to get the padding correct.
site_type_alignment_ = gtk_alignment_new(0, 0, 1, 1);
gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
- 0, 0, 1, 0);
+ 1, 1, 0, 0);
gtk_container_add(GTK_CONTAINER(site_type_alignment_),
site_type_event_box_);
gtk_box_pack_start(GTK_BOX(hbox_.get()), site_type_alignment_,
@@ -408,6 +407,14 @@ GtkWidget* LocationBarViewGtk::GetPageActionWidget(
}
void LocationBarViewGtk::Update(const TabContents* contents) {
+ bool star_enabled = star_.get() && !toolbar_model_->input_in_progress();
+ command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
+ if (star_.get()) {
+ if (star_enabled)
+ gtk_widget_show_all(star_.get());
+ else
+ gtk_widget_hide_all(star_.get());
+ }
UpdateSiteTypeArea();
UpdateContentSettingsIcons();
UpdatePageActions();
@@ -537,6 +544,11 @@ void LocationBarViewGtk::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
MessageLoop::current()->PostTask(FROM_HERE, task);
}
+void LocationBarViewGtk::SetSuggestedText(const string16& text) {
+ // TODO: implement me.
+ NOTIMPLEMENTED();
+}
+
std::wstring LocationBarViewGtk::GetInputString() const {
return location_input_;
}
@@ -616,8 +628,10 @@ void LocationBarViewGtk::UpdatePageActions() {
if (!page_action_views_.empty() && contents) {
GURL url = GURL(WideToUTF8(toolbar_model_->GetText()));
- for (size_t i = 0; i < page_action_views_.size(); i++)
- page_action_views_[i]->UpdateVisibility(contents, url);
+ for (size_t i = 0; i < page_action_views_.size(); i++) {
+ page_action_views_[i]->UpdateVisibility(
+ toolbar_model_->input_in_progress() ? NULL : contents, url);
+ }
}
// If there are no visible page actions, hide the hbox too, so that it does
@@ -647,6 +661,18 @@ void LocationBarViewGtk::Revert() {
location_entry_->RevertAll();
}
+const AutocompleteEditView* LocationBarViewGtk::location_entry() const {
+ return location_entry_.get();
+}
+
+AutocompleteEditView* LocationBarViewGtk::location_entry() {
+ return location_entry_.get();
+}
+
+LocationBarTesting* LocationBarViewGtk::GetLocationBarForTesting() {
+ return this;
+}
+
int LocationBarViewGtk::PageActionVisibleCount() {
int count = 0;
gtk_container_foreach(GTK_CONTAINER(page_action_hbox_.get()),
@@ -724,8 +750,8 @@ void LocationBarViewGtk::Observe(NotificationType type,
&kHintTextColor);
// Until we switch to vector graphics, force the font size of labels.
- gtk_util::ForceFontSizePixels(security_info_label_,
- browser_defaults::kAutocompleteEditFontPixelSize);
+ // 12.1px = 9pt @ 96dpi
+ gtk_util::ForceFontSizePixels(security_info_label_, 12.1);
gtk_util::ForceFontSizePixels(tab_to_search_full_label_,
browser_defaults::kAutocompleteEditFontPixelSize);
gtk_util::ForceFontSizePixels(tab_to_search_partial_label_,
@@ -1005,8 +1031,8 @@ void LocationBarViewGtk::OnIconDragBegin(GtkWidget* sender,
GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&favicon);
if (!pixbuf)
return;
- drag_icon_ = bookmark_utils::GetDragRepresentation(pixbuf, GetTitle(),
- theme_provider_);
+ drag_icon_ = bookmark_utils::GetDragRepresentation(pixbuf,
+ WideToUTF16(GetTitle()), theme_provider_);
g_object_unref(pixbuf);
gtk_drag_set_icon_widget(context, drag_icon_, 0, 0);
}
@@ -1062,7 +1088,7 @@ void LocationBarViewGtk::UpdateStarIcon() {
gtk_image_set_from_pixbuf(GTK_IMAGE(star_image_),
theme_provider_->GetPixbufNamed(
- starred_ ? IDR_OMNIBOX_STAR_LIT : IDR_OMNIBOX_STAR));
+ starred_ ? IDR_STAR_LIT : IDR_STAR));
}
bool LocationBarViewGtk::ShouldOnlyShowLocation() {
@@ -1269,15 +1295,14 @@ void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility(
TabContents* contents, GURL url) {
// Save this off so we can pass it back to the extension when the action gets
// executed. See PageActionImageView::OnMousePressed.
- current_tab_id_ = ExtensionTabUtil::GetTabId(contents);
+ current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1;
current_url_ = url;
- bool visible = preview_enabled_ ||
- page_action_->GetIsVisible(current_tab_id_);
+ bool visible = contents &&
+ (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
if (visible) {
// Set the tooltip.
- gtk_widget_set_tooltip_text(
- event_box_.get(),
+ gtk_widget_set_tooltip_text(event_box_.get(),
page_action_->GetTitle(current_tab_id_).c_str());
// Set the image.
@@ -1305,19 +1330,15 @@ void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility(
// Otherwise look for a dynamically set index, or fall back to the
// default path.
int icon_index = page_action_->GetIconIndex(current_tab_id_);
- std::string icon_path;
- if (icon_index >= 0)
- icon_path = page_action_->icon_paths()->at(icon_index);
- else
- icon_path = page_action_->default_icon_path();
-
+ std::string icon_path = (icon_index < 0) ?
+ page_action_->default_icon_path() :
+ page_action_->icon_paths()->at(icon_index);
if (!icon_path.empty()) {
PixbufMap::iterator iter = pixbufs_.find(icon_path);
if (iter != pixbufs_.end())
pixbuf = iter->second;
}
}
-
// The pixbuf might not be loaded yet.
if (pixbuf)
gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbuf);
diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h
index 7600390..6ad62d1 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/gtk/location_bar_view_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_
#define CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -18,14 +19,14 @@
#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
-#include "chrome/browser/first_run.h"
+#include "chrome/browser/first_run/first_run.h"
#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/common/content_settings_types.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "chrome/common/page_transition_types.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/glue/window_open_disposition.h"
@@ -57,6 +58,9 @@ class LocationBarViewGtk : public AutocompleteEditController,
// Returns the widget the caller should host. You must call Init() first.
GtkWidget* widget() { return hbox_.get(); }
+ // Returns the widget the page info bubble should point to.
+ GtkWidget* location_icon_widget() const { return location_icon_image_; }
+
// Returns the current TabContents.
TabContents* GetTabContents() const;
@@ -97,6 +101,7 @@ class LocationBarViewGtk : public AutocompleteEditController,
// Implement the LocationBar interface.
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;
@@ -108,13 +113,9 @@ class LocationBarViewGtk : public AutocompleteEditController,
virtual void InvalidatePageActions();
virtual void SaveStateToContents(TabContents* contents);
virtual void Revert();
- virtual const AutocompleteEditView* location_entry() const {
- return location_entry_.get();
- }
- virtual AutocompleteEditView* location_entry() {
- return location_entry_.get();
- }
- virtual LocationBarTesting* GetLocationBarForTesting() { return this; }
+ virtual const AutocompleteEditView* location_entry() const;
+ virtual AutocompleteEditView* location_entry();
+ virtual LocationBarTesting* GetLocationBarForTesting();
// Implement the LocationBarTesting interface.
virtual int PageActionCount() { return page_action_views_.size(); }
@@ -331,12 +332,6 @@ class LocationBarViewGtk : public AutocompleteEditController,
GtkWidget* star_image_;
bool starred_;
- // SSL state.
- GtkWidget* security_icon_event_box_;
- GtkWidget* ev_secure_icon_image_;
- GtkWidget* secure_icon_image_;
- GtkWidget* security_warning_icon_image_;
- GtkWidget* security_error_icon_image_;
// An icon to the left of the address bar.
GtkWidget* site_type_alignment_;
GtkWidget* site_type_event_box_;
diff --git a/chrome/browser/gtk/menu_bar_helper.cc b/chrome/browser/gtk/menu_bar_helper.cc
index 1e85475..050760c 100644
--- a/chrome/browser/gtk/menu_bar_helper.cc
+++ b/chrome/browser/gtk/menu_bar_helper.cc
@@ -122,8 +122,8 @@ gboolean MenuBarHelper::OnMenuMotionNotify(GtkWidget* menu,
gint last_y = y;
if (!gtk_widget_translate_coordinates(
last_button, button, last_x, last_y, &x, &y)) {
- NOTREACHED();
- return FALSE;
+ // |button| may not be realized.
+ continue;
}
}
diff --git a/chrome/browser/gtk/menu_bar_helper.h b/chrome/browser/gtk/menu_bar_helper.h
index c3f92cf..286b669 100644
--- a/chrome/browser/gtk/menu_bar_helper.h
+++ b/chrome/browser/gtk/menu_bar_helper.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_GTK_MENU_BAR_HELPER_H_
#define CHROME_BROWSER_GTK_MENU_BAR_HELPER_H_
+#pragma once
#include <gtk/gtk.h>
@@ -31,7 +32,7 @@ class MenuBarHelper {
// |delegate| cannot be null.
explicit MenuBarHelper(Delegate* delegate);
- ~MenuBarHelper();
+ virtual ~MenuBarHelper();
// Must be called whenever a button's menu starts showing. It triggers the
// MenuBarHelper to start listening for certain events.
diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc
index 5bdebea..4d58ae1 100644
--- a/chrome/browser/gtk/menu_gtk.cc
+++ b/chrome/browser/gtk/menu_gtk.cc
@@ -6,11 +6,9 @@
#include <map>
-#include "app/l10n_util.h"
#include "app/menus/accelerator_gtk.h"
#include "app/menus/button_menu_item_model.h"
#include "app/menus/menu_model.h"
-#include "app/resource_bundle.h"
#include "base/gtk_util.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
@@ -56,48 +54,13 @@ menus::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item) {
g_object_get_data(G_OBJECT(menu_item), "model"));
}
-void OnSubmenuShow(GtkWidget* widget, gpointer user_data) {
- gint index = GPOINTER_TO_INT(user_data);
-
- GtkMenuItem* item =
- GTK_MENU_ITEM(g_list_nth(GTK_MENU_SHELL(widget)->children, index)->data);
- menus::MenuModel* model = ModelForMenuItem(item);
- std::string label =
- ConvertAcceleratorsFromWindowsStyle(
- UTF16ToUTF8(model->GetLabelAt(index)));
-
-#if GTK_CHECK_VERSION(2, 16, 0)
- gtk_menu_item_set_label(item, label.c_str());
-#else
- gtk_label_set_label(GTK_LABEL(GTK_BIN(item)->child), label.c_str());
-#endif
-}
-
-void OnSubmenuShowButtonMenuItem(GtkWidget* widget, GtkButton* button) {
- menus::ButtonMenuItemModel* model =
- reinterpret_cast<menus::ButtonMenuItemModel*>(
- g_object_get_data(G_OBJECT(button), "button-model"));
- int index = GPOINTER_TO_INT(g_object_get_data(
- G_OBJECT(button), "button-model-id"));
-
- std::string label =
- ConvertAcceleratorsFromWindowsStyle(
- UTF16ToUTF8(model->GetLabelAt(index)));
- gtk_button_set_label(GTK_BUTTON(button), label.c_str());
-}
-
-void SetupDynamicLabelMenuButton(GtkWidget* button,
- GtkWidget* menu,
- menus::ButtonMenuItemModel* model,
- int index) {
- if (model->IsLabelDynamicAt(index)) {
- g_object_set_data(G_OBJECT(button), "button-model",
- model);
- g_object_set_data(G_OBJECT(button), "button-model-id",
- GINT_TO_POINTER(index));
- g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShowButtonMenuItem),
- button);
- }
+void SetupButtonShowHandler(GtkWidget* button,
+ menus::ButtonMenuItemModel* model,
+ int index) {
+ g_object_set_data(G_OBJECT(button), "button-model",
+ model);
+ g_object_set_data(G_OBJECT(button), "button-model-id",
+ GINT_TO_POINTER(index));
}
void OnSubmenuShowButtonImage(GtkWidget* widget, GtkButton* button) {
@@ -179,8 +142,8 @@ MenuGtk::~MenuGtk() {
void MenuGtk::ConnectSignalHandlers() {
// We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may
// take a long time or even start a nested message loop.
- g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShow), this);
- g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHidden), this);
+ g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this);
+ g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this);
}
GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id,
@@ -215,22 +178,32 @@ GtkWidget* MenuGtk::AppendSeparator() {
}
GtkWidget* MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) {
- return AppendMenuItemToMenu(command_id, menu_item, menu_, true);
+ return AppendMenuItemToMenu(command_id, NULL, menu_item, menu_, true);
}
-GtkWidget* MenuGtk::AppendMenuItemToMenu(int command_id,
+GtkWidget* MenuGtk::AppendMenuItemToMenu(int index,
+ menus::MenuModel* model,
GtkWidget* menu_item,
GtkWidget* menu,
bool connect_to_activate) {
+ SetMenuItemID(menu_item, index);
+
// Native menu items do their own thing, so only selectively listen for the
// activate signal.
if (connect_to_activate) {
- SetMenuItemID(menu_item, command_id);
g_signal_connect(menu_item, "activate",
- G_CALLBACK(OnMenuItemActivated), this);
+ G_CALLBACK(OnMenuItemActivatedThunk), this);
}
- gtk_widget_show(menu_item);
+ // AppendMenuItemToMenu is used both internally when we control menu creation
+ // from a model (where the model can choose to hide certain menu items), and
+ // with immediate commands which don't provide the option.
+ if (model) {
+ if (model->IsVisibleAt(index))
+ gtk_widget_show(menu_item);
+ } else {
+ gtk_widget_show(menu_item);
+ }
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
return menu_item;
}
@@ -260,6 +233,12 @@ void MenuGtk::PopupAsContextAt(guint32 event_time, gfx::Point point) {
PointMenuPositionFunc, &point, 3, event_time);
}
+void MenuGtk::PopupAsContextForStatusIcon(guint32 event_time, guint32 button,
+ GtkStatusIcon* icon) {
+ gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, gtk_status_icon_position_menu,
+ icon, button, event_time);
+}
+
void MenuGtk::PopupAsFromKeyEvent(GtkWidget* widget) {
Popup(widget, 0, gtk_get_current_event_time());
gtk_menu_shell_select_first(GTK_MENU_SHELL(menu_), FALSE);
@@ -269,6 +248,10 @@ void MenuGtk::Cancel() {
gtk_menu_popdown(GTK_MENU(menu_));
}
+void MenuGtk::UpdateMenu() {
+ gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
+}
+
GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
const SkBitmap& icon) {
GtkWidget* menu_item =
@@ -356,12 +339,7 @@ void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
}
g_object_set_data(G_OBJECT(menu_item), "model", model);
- AppendMenuItemToMenu(i, menu_item, menu, connect_to_activate);
-
- if (model->IsLabelDynamicAt(i)) {
- g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShow),
- GINT_TO_POINTER(i));
- }
+ AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate);
menu_item = NULL;
}
@@ -375,7 +353,9 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
// Set up the callback to the model for when it is clicked.
g_object_set_data(G_OBJECT(menu_item), "button-model", model);
g_signal_connect(menu_item, "button-pushed",
- G_CALLBACK(OnMenuButtonPressed), this);
+ G_CALLBACK(OnMenuButtonPressedThunk), this);
+ g_signal_connect(menu_item, "try-button-pushed",
+ G_CALLBACK(OnMenuTryButtonPressedThunk), this);
GtkSizeGroup* group = NULL;
for (int i = 0; i < model->GetItemCount(); ++i) {
@@ -401,7 +381,7 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
UTF16ToUTF8(model->GetLabelAt(i))).c_str());
}
- SetupDynamicLabelMenuButton(button, menu, model, i);
+ SetupButtonShowHandler(button, model, i);
break;
}
case menus::ButtonMenuItemModel::TYPE_BUTTON_LABEL: {
@@ -412,7 +392,7 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
GTK_BUTTON(button),
RemoveWindowsStyleAccelerators(
UTF16ToUTF8(model->GetLabelAt(i))).c_str());
- SetupDynamicLabelMenuButton(button, menu, model, i);
+ SetupButtonShowHandler(button, model, i);
break;
}
}
@@ -432,14 +412,13 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
return menu_item;
}
-// static
-void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) {
+void MenuGtk::OnMenuItemActivated(GtkWidget* menuitem) {
if (block_activation_)
return;
// We receive activation messages when highlighting a menu that has a
// submenu. Ignore them.
- if (gtk_menu_item_get_submenu(menuitem))
+ if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem)))
return;
// The activate signal is sent to radio items as they get deselected;
@@ -450,27 +429,45 @@ void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) {
}
int id;
- if (!GetMenuItemID(GTK_WIDGET(menuitem), &id))
+ if (!GetMenuItemID(menuitem, &id))
return;
- menus::MenuModel* model = ModelForMenuItem(menuitem);
+ menus::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menuitem));
// The menu item can still be activated by hotkeys even if it is disabled.
if (model->IsEnabledAt(id))
- menu->ExecuteCommand(model, id);
+ ExecuteCommand(model, id);
}
-void MenuGtk::OnMenuButtonPressed(GtkMenuItem* menu_item, int command_id,
- MenuGtk* menu) {
+void MenuGtk::OnMenuButtonPressed(GtkWidget* menu_item, int command_id) {
menus::ButtonMenuItemModel* model =
reinterpret_cast<menus::ButtonMenuItemModel*>(
g_object_get_data(G_OBJECT(menu_item), "button-model"));
- if (model) {
- if (menu->delegate_)
- menu->delegate_->CommandWillBeExecuted();
+ if (model && model->IsCommandIdEnabled(command_id)) {
+ if (delegate_)
+ delegate_->CommandWillBeExecuted();
+
+ model->ActivatedCommand(command_id);
+ }
+}
+
+gboolean MenuGtk::OnMenuTryButtonPressed(GtkWidget* menu_item,
+ int command_id) {
+ gboolean pressed = FALSE;
+ menus::ButtonMenuItemModel* model =
+ reinterpret_cast<menus::ButtonMenuItemModel*>(
+ g_object_get_data(G_OBJECT(menu_item), "button-model"));
+ if (model &&
+ model->IsCommandIdEnabled(command_id) &&
+ !model->DoesCommandIdDismissMenu(command_id)) {
+ if (delegate_)
+ delegate_->CommandWillBeExecuted();
model->ActivatedCommand(command_id);
+ pressed = TRUE;
}
+
+ return pressed;
}
// static
@@ -535,10 +532,6 @@ void MenuGtk::PointMenuPositionFunc(GtkMenu* menu,
*y = CalculateMenuYPosition(&screen_rect, &menu_req, NULL, *y);
}
-void MenuGtk::UpdateMenu() {
- gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
-}
-
void MenuGtk::ExecuteCommand(menus::MenuModel* model, int id) {
if (delegate_)
delegate_->CommandWillBeExecuted();
@@ -546,16 +539,32 @@ void MenuGtk::ExecuteCommand(menus::MenuModel* model, int id) {
model->ActivatedAt(id);
}
-// static
-void MenuGtk::OnMenuShow(GtkWidget* widget, MenuGtk* menu) {
+void MenuGtk::OnMenuShow(GtkWidget* widget) {
MessageLoop::current()->PostTask(FROM_HERE,
- menu->factory_.NewRunnableMethod(&MenuGtk::UpdateMenu));
+ factory_.NewRunnableMethod(&MenuGtk::UpdateMenu));
+}
+
+void MenuGtk::OnMenuHidden(GtkWidget* widget) {
+ if (delegate_)
+ delegate_->StoppedShowing();
}
// static
-void MenuGtk::OnMenuHidden(GtkWidget* widget, MenuGtk* menu) {
- if (menu->delegate_)
- menu->delegate_->StoppedShowing();
+void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) {
+ menus::ButtonMenuItemModel* model =
+ reinterpret_cast<menus::ButtonMenuItemModel*>(
+ g_object_get_data(G_OBJECT(button), "button-model"));
+ int index = GPOINTER_TO_INT(g_object_get_data(
+ G_OBJECT(button), "button-model-id"));
+
+ if (model->IsLabelDynamicAt(index)) {
+ std::string label =
+ ConvertAcceleratorsFromWindowsStyle(
+ UTF16ToUTF8(model->GetLabelAt(index)));
+ gtk_button_set_label(GTK_BUTTON(button), label.c_str());
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index));
}
// static
@@ -595,9 +604,35 @@ void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
block_activation_ = false;
}
+ if (GTK_IS_CUSTOM_MENU_ITEM(widget)) {
+ // Iterate across all the buttons to update their visible properties.
+ gtk_custom_menu_item_foreach_button(GTK_CUSTOM_MENU_ITEM(widget),
+ SetButtonItemInfo,
+ userdata);
+ }
+
if (GTK_IS_MENU_ITEM(widget)) {
gtk_widget_set_sensitive(widget, model->IsEnabledAt(id));
+ if (model->IsVisibleAt(id)) {
+ // Update the menu item label if it is dynamic.
+ if (model->IsLabelDynamicAt(id)) {
+ std::string label =
+ ConvertAcceleratorsFromWindowsStyle(
+ UTF16ToUTF8(model->GetLabelAt(id)));
+
+#if GTK_CHECK_VERSION(2, 16, 0)
+ gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str());
+#else
+ gtk_label_set_label(GTK_LABEL(GTK_BIN(widget)->child), label.c_str());
+#endif
+ }
+
+ gtk_widget_show(widget);
+ } else {
+ gtk_widget_hide(widget);
+ }
+
GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
if (submenu) {
gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo,
diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h
index 55767da..b4bc98c 100644
--- a/chrome/browser/gtk/menu_gtk.h
+++ b/chrome/browser/gtk/menu_gtk.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_GTK_MENU_GTK_H_
#define CHROME_BROWSER_GTK_MENU_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include <string>
#include <vector>
+#include "app/gtk_signal.h"
#include "base/task.h"
#include "gfx/point.h"
@@ -62,7 +64,8 @@ class MenuGtk {
const std::string& label);
GtkWidget* AppendSeparator();
GtkWidget* AppendMenuItem(int command_id, GtkWidget* menu_item);
- GtkWidget* AppendMenuItemToMenu(int command_id,
+ GtkWidget* AppendMenuItemToMenu(int index,
+ menus::MenuModel* model,
GtkWidget* menu_item,
GtkWidget* menu,
bool connect_to_activate);
@@ -82,6 +85,10 @@ class MenuGtk {
// Displays the menu at the given coords. |point| is intentionally not const.
void PopupAsContextAt(guint32 event_time, gfx::Point point);
+ // Displays the menu as a context menu for the passed status icon.
+ void PopupAsContextForStatusIcon(guint32 event_time, guint32 button,
+ GtkStatusIcon* icon);
+
// Displays the menu following a keyboard event (such as selecting |widget|
// and pressing "enter").
void PopupAsFromKeyEvent(GtkWidget* widget);
@@ -110,6 +117,9 @@ class MenuGtk {
GtkWidget* widget() const { return menu_; }
+ // Updates all the enabled/checked states and the dynamic labels.
+ void UpdateMenu();
+
private:
// Builds a GtkImageMenuItem.
GtkWidget* BuildMenuItemWithImage(const std::string& label,
@@ -123,26 +133,30 @@ class MenuGtk {
GtkWidget* BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
GtkWidget* menu);
- // Contains implementation for OnMenuShow.
- void UpdateMenu();
-
void ExecuteCommand(menus::MenuModel* model, int id);
// Callback for when a menu item is clicked.
- static void OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu);
+ CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuItemActivated);
// Called when one of the buttons are pressed.
- static void OnMenuButtonPressed(GtkMenuItem* menuitem, int command_id,
- MenuGtk* menu);
+ CHROMEGTK_CALLBACK_1(MenuGtk, void, OnMenuButtonPressed, int);
- // Sets the check mark and enabled/disabled state on our menu items.
- static void SetMenuItemInfo(GtkWidget* widget, void* raw_menu);
+ // Called to maybe activate a button if that button isn't supposed to dismiss
+ // the menu.
+ CHROMEGTK_CALLBACK_1(MenuGtk, gboolean, OnMenuTryButtonPressed, int);
// Updates all the menu items' state.
- static void OnMenuShow(GtkWidget* widget, MenuGtk* menu);
+ CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuShow);
// Sets the activating widget back to a normal appearance.
- static void OnMenuHidden(GtkWidget* widget, MenuGtk* menu);
+ CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuHidden);
+
+ // Sets the enable/disabled state and dynamic labels on our menu items.
+ static void SetButtonItemInfo(GtkWidget* button, gpointer userdata);
+
+ // Sets the check mark, enabled/disabled state and dynamic labels on our menu
+ // items.
+ static void SetMenuItemInfo(GtkWidget* widget, void* raw_menu);
// Queries this object about the menu state.
MenuGtk::Delegate* delegate_;
diff --git a/chrome/browser/gtk/meta_frames.h b/chrome/browser/gtk/meta_frames.h
index ef828ef..bc8a493 100644
--- a/chrome/browser/gtk/meta_frames.h
+++ b/chrome/browser/gtk/meta_frames.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_META_FRAMES_H_
#define CHROME_BROWSER_GTK_META_FRAMES_H_
+#pragma once
#include <gdk/gdk.h>
#include <gtk/gtkwindow.h>
diff --git a/chrome/browser/gtk/nine_box.cc b/chrome/browser/gtk/nine_box.cc
index 973d3c5..9d65387 100644
--- a/chrome/browser/gtk/nine_box.cc
+++ b/chrome/browser/gtk/nine_box.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/gtk/nine_box.h"
#include "app/resource_bundle.h"
-#include "app/theme_provider.h"
#include "base/basictypes.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
diff --git a/chrome/browser/gtk/nine_box.h b/chrome/browser/gtk/nine_box.h
index c00a99b..ecdf44a 100644
--- a/chrome/browser/gtk/nine_box.h
+++ b/chrome/browser/gtk/nine_box.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_NINE_BOX_H_
#define CHROME_BROWSER_GTK_NINE_BOX_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/notifications/balloon_view_gtk.cc b/chrome/browser/gtk/notifications/balloon_view_gtk.cc
index ea9d9ae..24a04cf 100644
--- a/chrome/browser/gtk/notifications/balloon_view_gtk.cc
+++ b/chrome/browser/gtk/notifications/balloon_view_gtk.cc
@@ -15,7 +15,6 @@
#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
@@ -32,6 +31,7 @@
#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"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
@@ -57,14 +57,6 @@ const int kRightMargin = 1;
// balloon bottom.
const int kShelfBorderTopOverlap = 0;
-// Properties of the dismiss button.
-const int kDismissButtonWidth = 60;
-const int kDismissButtonHeight = 20;
-
-// Properties of the options menu.
-const int kOptionsMenuWidth = 60;
-const int kOptionsMenuHeight = 20;
-
// Properties of the origin label.
const int kLeftLabelMargin = 8;
@@ -75,7 +67,7 @@ const int kTopShadowWidth = 0;
const int kBottomShadowWidth = 0;
// Space in pixels between text and icon on the buttons.
-const int kButtonIconSpacing = 10;
+const int kButtonSpacing = 4;
// Number of characters to show in the origin label before ellipsis.
const int kOriginLabelCharacters = 18;
@@ -83,7 +75,7 @@ const int kOriginLabelCharacters = 18;
// The shelf height for the system default font size. It is scaled
// with changes in the default font size.
const int kDefaultShelfHeight = 21;
-const int kShelfVerticalMargin = 3;
+const int kShelfVerticalMargin = 4;
// The amount that the bubble collections class offsets from the side of the
// screen.
@@ -201,7 +193,7 @@ void BalloonViewImpl::Show(Balloon* balloon) {
const std::string source_label_text = l10n_util::GetStringFUTF8(
IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
- WideToUTF16(balloon->notification().display_source()));
+ balloon->notification().display_source());
const std::string options_text =
l10n_util::GetStringUTF8(IDS_NOTIFICATION_OPTIONS_MENU_LABEL);
const std::string dismiss_text =
@@ -263,11 +255,16 @@ void BalloonViewImpl::Show(Balloon* balloon) {
gtk_container_add(GTK_CONTAINER(label_alignment), source_label_);
gtk_box_pack_start(GTK_BOX(hbox_), label_alignment, FALSE, FALSE, 0);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
// Create a button to dismiss the balloon and add it to the toolbar.
- close_button_.reset(new CustomDrawButton(IDR_BALLOON_CLOSE,
- IDR_BALLOON_CLOSE_HOVER,
- IDR_BALLOON_CLOSE_HOVER,
- IDR_BALLOON_CLOSE_HOVER));
+ close_button_.reset(new CustomDrawButton(IDR_TAB_CLOSE,
+ IDR_TAB_CLOSE_P,
+ IDR_TAB_CLOSE_H,
+ IDR_TAB_CLOSE));
+ close_button_->SetBackground(SK_ColorBLACK,
+ rb.GetBitmapNamed(IDR_TAB_CLOSE),
+ rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK));
gtk_widget_set_tooltip_text(close_button_->widget(), dismiss_text.c_str());
g_signal_connect(close_button_->widget(), "clicked",
G_CALLBACK(OnCloseButtonThunk), this);
@@ -275,15 +272,15 @@ void BalloonViewImpl::Show(Balloon* balloon) {
GtkWidget* close_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
gtk_alignment_set_padding(GTK_ALIGNMENT(close_alignment),
kShelfVerticalMargin, kShelfVerticalMargin,
- 0, kButtonIconSpacing);
+ 0, kButtonSpacing);
gtk_container_add(GTK_CONTAINER(close_alignment), close_button_->widget());
gtk_box_pack_end(GTK_BOX(hbox_), close_alignment, FALSE, FALSE, 0);
// Create a button for showing the options menu, and add it to the toolbar.
options_menu_button_.reset(new CustomDrawButton(IDR_BALLOON_WRENCH,
- IDR_BALLOON_WRENCH_HOVER,
- IDR_BALLOON_WRENCH_HOVER,
- IDR_BALLOON_WRENCH_HOVER));
+ IDR_BALLOON_WRENCH_P,
+ IDR_BALLOON_WRENCH_H,
+ 0));
gtk_widget_set_tooltip_text(options_menu_button_->widget(),
options_text.c_str());
g_signal_connect(options_menu_button_->widget(), "clicked",
@@ -292,7 +289,7 @@ void BalloonViewImpl::Show(Balloon* balloon) {
GtkWidget* options_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
gtk_alignment_set_padding(GTK_ALIGNMENT(options_alignment),
kShelfVerticalMargin, kShelfVerticalMargin,
- 0, kButtonIconSpacing);
+ 0, kButtonSpacing);
gtk_container_add(GTK_CONTAINER(options_alignment),
options_menu_button_->widget());
gtk_box_pack_end(GTK_BOX(hbox_), options_alignment, FALSE, FALSE, 0);
@@ -383,6 +380,10 @@ void BalloonViewImpl::Observe(NotificationType type,
}
}
+void BalloonViewImpl::OnCloseButton(GtkWidget* widget) {
+ Close(true);
+}
+
gboolean BalloonViewImpl::OnExpose(GtkWidget* sender, GdkEventExpose* event) {
cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(sender->window));
gdk_cairo_rectangle(cr, &event->area);
diff --git a/chrome/browser/gtk/notifications/balloon_view_gtk.h b/chrome/browser/gtk/notifications/balloon_view_gtk.h
index d80bda6..652a610 100644
--- a/chrome/browser/gtk/notifications/balloon_view_gtk.h
+++ b/chrome/browser/gtk/notifications/balloon_view_gtk.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_GTK_H_
#define CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_GTK_H_
+#pragma once
#include "app/animation.h"
#include "app/gtk_signal.h"
@@ -76,10 +77,7 @@ class BalloonViewImpl : public BalloonView,
// Where the balloon contents should be in screen coordinates.
gfx::Rect GetContentsRectangle() const;
- static void OnCloseButtonThunk(GtkWidget* widget, gpointer user_data) {
- reinterpret_cast<BalloonViewImpl*>(user_data)->Close(true);
- }
-
+ CHROMEGTK_CALLBACK_0(BalloonViewImpl, void, OnCloseButton);
CHROMEGTK_CALLBACK_1(BalloonViewImpl, gboolean, OnExpose, GdkEventExpose*);
CHROMEGTK_CALLBACK_0(BalloonViewImpl, void, OnOptionsMenuButton);
CHROMEGTK_CALLBACK_0(BalloonViewImpl, gboolean, OnDestroy);
diff --git a/chrome/browser/gtk/notifications/balloon_view_host_gtk.h b/chrome/browser/gtk/notifications/balloon_view_host_gtk.h
index f51b875..75dfb92 100644
--- a/chrome/browser/gtk/notifications/balloon_view_host_gtk.h
+++ b/chrome/browser/gtk/notifications/balloon_view_host_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_HOST_GTK_H_
#define CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_HOST_GTK_H_
+#pragma once
#include "chrome/browser/notifications/balloon_host.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/gtk/options/advanced_contents_gtk.cc b/chrome/browser/gtk/options/advanced_contents_gtk.cc
index 6d06209..cda323a 100644
--- a/chrome/browser/gtk/options/advanced_contents_gtk.cc
+++ b/chrome/browser/gtk/options/advanced_contents_gtk.cc
@@ -14,7 +14,8 @@
#include "app/gtk_util.h"
#include "app/l10n_util.h"
#include "base/basictypes.h"
-#include "base/env_var.h"
+#include "base/command_line.h"
+#include "base/environment.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/process_util.h"
@@ -23,6 +24,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/fonts_languages_window.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/clear_browsing_data_dialog_gtk.h"
@@ -33,11 +35,13 @@
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/options_page_base.h"
#include "chrome/browser/options_util.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/prefs/pref_set_observer.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/process_watcher.h"
#include "grit/chromium_strings.h"
@@ -75,8 +79,8 @@ const int kWrapWidth = 475;
GtkWidget* CreateWrappedLabel(int string_id) {
GtkWidget* label = gtk_label_new(
l10n_util::GetStringUTF8(string_id).c_str());
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
- gtk_widget_set_size_request(label, kWrapWidth, -1);
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+ gtk_util::SetLabelWidth(label, kWrapWidth);
return label;
}
@@ -152,7 +156,7 @@ class DownloadSection : public OptionsPageBase {
private:
// Overridden from OptionsPageBase.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// Callbacks for the widgets.
static void OnDownloadLocationChanged(GtkFileChooser* widget,
@@ -267,7 +271,7 @@ DownloadSection::DownloadSection(Profile* profile)
NotifyPrefChanged(NULL);
}
-void DownloadSection::NotifyPrefChanged(const std::wstring* pref_name) {
+void DownloadSection::NotifyPrefChanged(const std::string* pref_name) {
pref_changing_ = true;
if (!pref_name || *pref_name == prefs::kDownloadDefaultDirectory) {
gtk_file_chooser_set_current_folder(
@@ -282,8 +286,8 @@ void DownloadSection::NotifyPrefChanged(const std::wstring* pref_name) {
}
if (!pref_name || *pref_name == prefs::kDownloadExtensionsToOpen) {
- bool enabled =
- profile()->GetDownloadManager()->HasAutoOpenFileTypesRegistered();
+ DownloadPrefs* prefs = profile()->GetDownloadManager()->download_prefs();
+ bool enabled = prefs->IsAutoOpenUsed();
gtk_widget_set_sensitive(reset_file_handlers_label_, enabled);
gtk_widget_set_sensitive(reset_file_handlers_button_, enabled);
}
@@ -330,7 +334,7 @@ void DownloadSection::OnDownloadAskForSaveLocationChanged(
// static
void DownloadSection::OnResetFileHandlersClicked(GtkButton *button,
DownloadSection* section) {
- section->profile()->GetDownloadManager()->ResetAutoOpenFiles();
+ section->profile()->GetDownloadManager()->download_prefs()->ResetAutoOpen();
section->UserMetricsRecordAction(
UserMetricsAction("Options_ResetAutoOpenFiles"),
section->profile()->GetPrefs());
@@ -349,6 +353,9 @@ class NetworkSection : public OptionsPageBase {
}
private:
+ // Overridden from OptionsPageBase.
+ virtual void NotifyPrefChanged(const std::string* pref_name);
+
struct ProxyConfigCommand {
std::string binary;
const char** argv;
@@ -363,9 +370,15 @@ class NetworkSection : public OptionsPageBase {
// Start the given proxy configuration utility.
static void StartProxyConfigUtil(const ProxyConfigCommand& command);
+ // Tracks the state of proxy preferences.
+ scoped_ptr<PrefSetObserver> proxy_prefs_;
+
// The widget containing the options for this section.
GtkWidget* page_;
+ // The proxy configuration button.
+ GtkWidget* change_proxies_button_;
+
DISALLOW_COPY_AND_ASSIGN(NetworkSection);
};
@@ -379,20 +392,30 @@ NetworkSection::NetworkSection(Profile* profile)
gtk_box_pack_start(GTK_BOX(page_), proxy_description_label,
FALSE, FALSE, 0);
- GtkWidget* change_proxies_button = gtk_button_new_with_label(
+ change_proxies_button_ = gtk_button_new_with_label(
l10n_util::GetStringUTF8(
IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON).c_str());
- g_signal_connect(change_proxies_button, "clicked",
+ g_signal_connect(change_proxies_button_, "clicked",
G_CALLBACK(OnChangeProxiesButtonClicked), this);
// Stick it in an hbox so it doesn't expand to the whole width.
GtkWidget* button_hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(button_hbox),
- change_proxies_button,
+ change_proxies_button_,
FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(page_),
gtk_util::IndentWidget(button_hbox),
FALSE, FALSE, 0);
+
+ proxy_prefs_.reset(PrefSetObserver::CreateProxyPrefSetObserver(
+ profile->GetPrefs(), this));
+ NotifyPrefChanged(NULL);
+}
+
+void NetworkSection::NotifyPrefChanged(const std::string* pref_name) {
+ if (!pref_name || proxy_prefs_->IsObserved(*pref_name))
+ gtk_widget_set_sensitive(change_proxies_button_,
+ !proxy_prefs_->IsManaged());
}
// static
@@ -401,11 +424,11 @@ void NetworkSection::OnChangeProxiesButtonClicked(GtkButton *button,
section->UserMetricsRecordAction(UserMetricsAction("Options_ChangeProxies"),
NULL);
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
ProxyConfigCommand command;
bool found_command = false;
- switch (base::GetDesktopEnvironment(env_getter.get())) {
+ switch (base::GetDesktopEnvironment(env.get())) {
case base::DESKTOP_ENVIRONMENT_GNOME: {
size_t index;
ProxyConfigCommand commands[2];
@@ -435,7 +458,7 @@ void NetworkSection::OnChangeProxiesButtonClicked(GtkButton *button,
if (found_command) {
StartProxyConfigUtil(command);
} else {
- const char* name = base::GetDesktopEnvironmentName(env_getter.get());
+ const char* name = base::GetDesktopEnvironmentName(env.get());
if (name)
LOG(ERROR) << "Could not find " << name << " network settings in $PATH";
BrowserList::GetLastActive()->
@@ -500,7 +523,7 @@ class TranslateSection : public OptionsPageBase {
private:
// Overridden from OptionsPageBase.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
CHROMEGTK_CALLBACK_0(TranslateSection, void, OnTranslateClicked);
@@ -546,7 +569,7 @@ TranslateSection::TranslateSection(Profile* profile)
NotifyPrefChanged(NULL);
}
-void TranslateSection::NotifyPrefChanged(const std::wstring* pref_name) {
+void TranslateSection::NotifyPrefChanged(const std::string* pref_name) {
pref_changing_ = true;
if (!pref_name || *pref_name == prefs::kEnableTranslate) {
gtk_toggle_button_set_active(
@@ -568,6 +591,106 @@ void TranslateSection::OnTranslateClicked(GtkWidget* widget) {
}
///////////////////////////////////////////////////////////////////////////////
+// ChromeAppsSection
+
+class ChromeAppsSection : public OptionsPageBase {
+ public:
+ explicit ChromeAppsSection(Profile* profile);
+ virtual ~ChromeAppsSection() {}
+
+ GtkWidget* get_page_widget() const {
+ return page_;
+ }
+
+ private:
+ // Overridden from OptionsPageBase.
+ virtual void NotifyPrefChanged(const std::string* pref_name);
+
+ CHROMEGTK_CALLBACK_0(ChromeAppsSection, void, OnBackgroundModeClicked);
+ CHROMEGTK_CALLBACK_0(ChromeAppsSection, void, OnLearnMoreLinkClicked);
+
+ // Preferences for this section:
+ BooleanPrefMember enable_background_mode_;
+
+ // The widget containing the options for this section.
+ GtkWidget* page_;
+
+ // The checkbox.
+ GtkWidget* background_mode_checkbox_;
+
+ // Flag to ignore gtk callbacks while we are loading prefs, to avoid
+ // then turning around and saving them again.
+ bool pref_changing_;
+
+ scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeAppsSection);
+};
+
+ChromeAppsSection::ChromeAppsSection(Profile* profile)
+ : OptionsPageBase(profile),
+ pref_changing_(true) {
+ page_ = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
+
+ accessible_widget_helper_.reset(new AccessibleWidgetHelper(page_, profile));
+
+ background_mode_checkbox_ = CreateCheckButtonWithWrappedLabel(
+ IDS_OPTIONS_CHROME_APPS_ENABLE_BACKGROUND_MODE);
+ gtk_box_pack_start(GTK_BOX(page_), background_mode_checkbox_,
+ FALSE, FALSE, 0);
+ g_signal_connect(background_mode_checkbox_, "clicked",
+ G_CALLBACK(OnBackgroundModeClickedThunk), this);
+ accessible_widget_helper_->SetWidgetName(
+ background_mode_checkbox_,
+ IDS_OPTIONS_CHROME_APPS_ENABLE_BACKGROUND_MODE);
+
+ // Init member prefs so we can update the controls if prefs change.
+ enable_background_mode_.Init(prefs::kBackgroundModeEnabled,
+ profile->GetPrefs(), this);
+
+ GtkWidget* learn_more_link = gtk_chrome_link_button_new(
+ l10n_util::GetStringUTF8(IDS_LEARN_MORE).c_str());
+ // Stick it in an hbox so it doesn't expand to the whole width.
+ GtkWidget* learn_more_hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(learn_more_hbox), learn_more_link,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(page_), learn_more_hbox,
+ FALSE, FALSE, 0);
+ g_signal_connect(learn_more_link, "clicked",
+ G_CALLBACK(OnLearnMoreLinkClickedThunk), this);
+
+ NotifyPrefChanged(NULL);
+}
+
+void ChromeAppsSection::NotifyPrefChanged(const std::string* pref_name) {
+ pref_changing_ = true;
+ if (!pref_name || *pref_name == prefs::kBackgroundModeEnabled) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(background_mode_checkbox_),
+ enable_background_mode_.GetValue());
+ }
+ pref_changing_ = false;
+}
+
+void ChromeAppsSection::OnBackgroundModeClicked(GtkWidget* widget) {
+ if (pref_changing_)
+ return;
+ bool enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+ UserMetricsRecordAction(
+ enabled ?
+ UserMetricsAction("Options_BackgroundMode_Enable") :
+ UserMetricsAction("Options_BackgroundMode_Disable"),
+ profile()->GetPrefs());
+ enable_background_mode_.SetValue(enabled);
+}
+
+void ChromeAppsSection::OnLearnMoreLinkClicked(GtkWidget* widget) {
+ BrowserList::GetLastActive()->OpenURL(
+ GURL(l10n_util::GetStringUTF8(IDS_LEARN_MORE_BACKGROUND_MODE_URL)),
+ GURL(), NEW_WINDOW, PageTransition::LINK);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
// PrivacySection
class PrivacySection : public OptionsPageBase {
@@ -581,7 +704,7 @@ class PrivacySection : public OptionsPageBase {
private:
// Overridden from OptionsPageBase.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// Try to make the the crash stats consent and the metrics upload
// permission match the |reporting_enabled_checkbox_|.
@@ -739,20 +862,6 @@ PrivacySection::PrivacySection(Profile* profile)
safe_browsing_.Init(prefs::kSafeBrowsingEnabled, profile->GetPrefs(), this);
enable_metrics_recording_.Init(prefs::kMetricsReportingEnabled,
g_browser_process->local_state(), this);
-
- gtk_widget_set_sensitive(enable_link_doctor_checkbox_,
- !alternate_error_pages_.IsManaged());
- gtk_widget_set_sensitive(enable_suggest_checkbox_,
- !use_suggest_.IsManaged());
- gtk_widget_set_sensitive(enable_dns_prefetching_checkbox_,
- !dns_prefetch_enabled_.IsManaged());
- gtk_widget_set_sensitive(enable_safe_browsing_checkbox_,
- !safe_browsing_.IsManaged());
-#if defined(GOOGLE_CHROME_BUILD)
- gtk_widget_set_sensitive(reporting_enabled_checkbox_,
- !enable_metrics_recording_.IsManaged());
-#endif
-
NotifyPrefChanged(NULL);
}
@@ -867,31 +976,48 @@ void PrivacySection::OnLoggingChange(GtkWidget* widget,
privacy_section->enable_metrics_recording_.SetValue(enabled);
}
-void PrivacySection::NotifyPrefChanged(const std::wstring* pref_name) {
+void PrivacySection::NotifyPrefChanged(const std::string* pref_name) {
pref_changing_ = true;
if (!pref_name || *pref_name == prefs::kAlternateErrorPagesEnabled) {
+ gtk_widget_set_sensitive(
+ GTK_WIDGET(enable_link_doctor_checkbox_),
+ !alternate_error_pages_.IsManaged());
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(enable_link_doctor_checkbox_),
alternate_error_pages_.GetValue());
}
if (!pref_name || *pref_name == prefs::kSearchSuggestEnabled) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_suggest_checkbox_),
- use_suggest_.GetValue());
+ gtk_widget_set_sensitive(
+ GTK_WIDGET(enable_suggest_checkbox_),
+ !use_suggest_.IsManaged());
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(enable_suggest_checkbox_),
+ use_suggest_.GetValue());
}
if (!pref_name || *pref_name == prefs::kDnsPrefetchingEnabled) {
+ gtk_widget_set_sensitive(
+ GTK_WIDGET(enable_dns_prefetching_checkbox_),
+ !dns_prefetch_enabled_.IsManaged());
bool enabled = dns_prefetch_enabled_.GetValue();
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(enable_dns_prefetching_checkbox_), enabled);
chrome_browser_net::EnablePredictor(enabled);
}
if (!pref_name || *pref_name == prefs::kSafeBrowsingEnabled) {
+ gtk_widget_set_sensitive(
+ GTK_WIDGET(enable_safe_browsing_checkbox_),
+ !safe_browsing_.IsManaged());
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(enable_safe_browsing_checkbox_),
safe_browsing_.GetValue());
}
#if defined(GOOGLE_CHROME_BUILD)
if (!pref_name || *pref_name == prefs::kMetricsReportingEnabled) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reporting_enabled_checkbox_),
+ gtk_widget_set_sensitive(
+ GTK_WIDGET(reporting_enabled_checkbox_),
+ !enable_metrics_recording_.IsManaged());
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(reporting_enabled_checkbox_),
enable_metrics_recording_.GetValue());
ResolveMetricsReportingEnabled();
}
@@ -941,7 +1067,7 @@ class SecuritySection : public OptionsPageBase {
private:
// Overridden from OptionsPageBase.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// The callback functions for the options widgets.
static void OnManageCertificatesClicked(GtkButton* button,
@@ -1035,7 +1161,7 @@ SecuritySection::SecuritySection(Profile* profile)
NotifyPrefChanged(NULL);
}
-void SecuritySection::NotifyPrefChanged(const std::wstring* pref_name) {
+void SecuritySection::NotifyPrefChanged(const std::string* pref_name) {
pref_changing_ = true;
if (!pref_name || *pref_name == prefs::kCertRevocationCheckingEnabled) {
gtk_toggle_button_set_active(
@@ -1239,5 +1365,13 @@ void AdvancedContentsGtk::Init() {
l10n_util::GetStringUTF8(IDS_OPTIONS_ADVANCED_SECTION_TITLE_SECURITY),
security_section_->get_page_widget(), false);
+ // Add ChromeApps preferences if background mode is runtime-enabled.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBackgroundMode)) {
+ chrome_apps_section_.reset(new ChromeAppsSection(profile_));
+ options_builder->AddOptionGroup(l10n_util::GetStringUTF8(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_CHROME_APPS),
+ chrome_apps_section_->get_page_widget(), false);
+ }
page_ = options_builder->get_page_widget();
}
diff --git a/chrome/browser/gtk/options/advanced_contents_gtk.h b/chrome/browser/gtk/options/advanced_contents_gtk.h
index 40a04b6..f39d6cc 100644
--- a/chrome/browser/gtk/options/advanced_contents_gtk.h
+++ b/chrome/browser/gtk/options/advanced_contents_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_ADVANCED_CONTENTS_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_ADVANCED_CONTENTS_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,6 +12,7 @@
#include "base/scoped_ptr.h"
class Profile;
+class ChromeAppsSection;
class DownloadSection;
class NetworkSection;
class PrivacySection;
@@ -34,6 +36,7 @@ class AdvancedContentsGtk {
Profile* profile_;
// The sections of the page.
+ scoped_ptr<ChromeAppsSection> chrome_apps_section_;
scoped_ptr<DownloadSection> download_section_;
scoped_ptr<NetworkSection> network_section_;
scoped_ptr<TranslateSection> translate_section_;
diff --git a/chrome/browser/gtk/options/advanced_page_gtk.h b/chrome/browser/gtk/options/advanced_page_gtk.h
index 91be437..193a6d6 100644
--- a/chrome/browser/gtk/options/advanced_page_gtk.h
+++ b/chrome/browser/gtk/options/advanced_page_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_ADVANCED_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_ADVANCED_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,7 +12,7 @@
#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/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
class Profile;
diff --git a/chrome/browser/gtk/options/content_exception_editor.cc b/chrome/browser/gtk/options/content_exception_editor.cc
index 10b786a..1c65ea5 100644
--- a/chrome/browser/gtk/options/content_exception_editor.cc
+++ b/chrome/browser/gtk/options/content_exception_editor.cc
@@ -54,7 +54,7 @@ ContentExceptionEditor::ContentExceptionEditor(
action_combo_ = gtk_combo_box_new_text();
for (int i = 0; i < cb_model_.GetItemCount(); ++i) {
gtk_combo_box_append_text(GTK_COMBO_BOX(action_combo_),
- WideToUTF8(cb_model_.GetItemAt(i)).c_str());
+ UTF16ToUTF8(cb_model_.GetItemAt(i)).c_str());
}
gtk_combo_box_set_active(GTK_COMBO_BOX(action_combo_),
cb_model_.IndexForSetting(setting_));
diff --git a/chrome/browser/gtk/options/content_exception_editor.h b/chrome/browser/gtk/options/content_exception_editor.h
index 98dcbf9..fed69c0 100644
--- a/chrome/browser/gtk/options/content_exception_editor.h
+++ b/chrome/browser/gtk/options/content_exception_editor.h
@@ -4,11 +4,10 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTION_EDITOR_H_
#define CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTION_EDITOR_H_
+#pragma once
#include <gtk/gtk.h>
-#include <string>
-
#include "app/gtk_signal.h"
#include "chrome/browser/content_exceptions_table_model.h"
#include "chrome/browser/content_setting_combo_model.h"
@@ -42,6 +41,7 @@ class ContentExceptionEditor {
const HostContentSettingsMap::Pattern& pattern,
ContentSetting setting,
bool is_off_the_record);
+ virtual ~ContentExceptionEditor() {}
private:
// Returns true if we're adding a new item.
diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk.h b/chrome/browser/gtk/options/content_exceptions_window_gtk.h
index b36d8d1..4779833 100644
--- a/chrome/browser/gtk/options/content_exceptions_window_gtk.h
+++ b/chrome/browser/gtk/options/content_exceptions_window_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTIONS_WINDOW_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_CONTENT_EXCEPTIONS_WINDOW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
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 6e603b5..ecfbaba 100644
--- a/chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc
+++ b/chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc
@@ -28,6 +28,7 @@ class ContentExceptionsWindowGtkUnittest : public testing::Test {
host_content_settings_map_->SetContentSetting(
HostContentSettingsMap::Pattern(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 1f0b719..ba66fb1 100644
--- a/chrome/browser/gtk/options/content_filter_page_gtk.cc
+++ b/chrome/browser/gtk/options/content_filter_page_gtk.cc
@@ -5,10 +5,12 @@
#include "chrome/browser/gtk/options/content_filter_page_gtk.h"
#include "app/l10n_util.h"
+#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.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 "chrome/browser/profile.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
@@ -17,6 +19,7 @@
#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/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
@@ -72,7 +75,7 @@ GtkWidget* ContentFilterPageGtk::InitGroup() {
0, // This dialog isn't used for cookies.
0,
0,
- 0,
+ IDS_PLUGIN_LOAD_SANDBOXED_RADIO,
0,
IDS_GEOLOCATION_ASK_RADIO,
IDS_NOTIFICATIONS_ASK_RADIO,
@@ -103,7 +106,12 @@ GtkWidget* ContentFilterPageGtk::InitGroup() {
gtk_box_pack_start(GTK_BOX(vbox), block_radio_, FALSE, FALSE, 0);
ContentSetting default_setting;
- if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ default_setting = profile()->GetHostContentSettingsMap()->
+ GetDefaultContentSetting(content_type_);
+ if (profile()->GetHostContentSettingsMap()->GetBlockNonsandboxedPlugins())
+ default_setting = CONTENT_SETTING_ASK;
+ } else if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
default_setting = profile()->GetGeolocationContentSettingsMap()->
GetDefaultContentSetting();
} else if (content_type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
@@ -170,7 +178,17 @@ void ContentFilterPageGtk::OnAllowToggled(GtkWidget* toggle_button) {
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(block_radio_)) ?
CONTENT_SETTING_BLOCK : CONTENT_SETTING_ASK;
DCHECK(ask_radio_ || default_setting != CONTENT_SETTING_ASK);
- if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ if (default_setting == CONTENT_SETTING_ASK) {
+ default_setting = CONTENT_SETTING_ALLOW;
+ profile()->GetHostContentSettingsMap()->SetBlockNonsandboxedPlugins(true);
+ } else {
+ profile()->GetHostContentSettingsMap()->
+ SetBlockNonsandboxedPlugins(false);
+ }
+ profile()->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ content_type_, default_setting);
+ } else if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
profile()->GetGeolocationContentSettingsMap()->SetDefaultContentSetting(
default_setting);
} else if (content_type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
@@ -205,6 +223,18 @@ void ContentFilterPageGtk::OnExceptionsClicked(GtkWidget* button) {
profile()->HasOffTheRecordProfile() ?
profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap() :
NULL;
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS &&
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings)) {
+ PluginExceptionsTableModel* model =
+ new PluginExceptionsTableModel(settings_map, otr_settings_map);
+ model->LoadSettings();
+ SimpleContentExceptionsWindow::ShowExceptionsWindow(
+ GTK_WINDOW(gtk_widget_get_toplevel(button)),
+ model,
+ IDS_PLUGINS_EXCEPTION_TITLE);
+ return;
+ }
ContentExceptionsWindowGtk::ShowExceptionsWindow(
GTK_WINDOW(gtk_widget_get_toplevel(button)),
settings_map, otr_settings_map, content_type_);
diff --git a/chrome/browser/gtk/options/content_filter_page_gtk.h b/chrome/browser/gtk/options/content_filter_page_gtk.h
index f7f4de9..614178e 100644
--- a/chrome/browser/gtk/options/content_filter_page_gtk.h
+++ b/chrome/browser/gtk/options/content_filter_page_gtk.h
@@ -4,11 +4,10 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_CONTENT_FILTER_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_CONTENT_FILTER_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
-#include <string>
-
#include "app/gtk_signal.h"
#include "chrome/browser/options_page_base.h"
#include "chrome/common/content_settings_types.h"
diff --git a/chrome/browser/gtk/options/content_page_gtk.cc b/chrome/browser/gtk/options/content_page_gtk.cc
index 1532e2c..8aff196 100644
--- a/chrome/browser/gtk/options/content_page_gtk.cc
+++ b/chrome/browser/gtk/options/content_page_gtk.cc
@@ -8,8 +8,8 @@
#include "app/gtk_util.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
@@ -21,7 +21,7 @@
#include "chrome/browser/gtk/options/options_layout_gtk.h"
#include "chrome/browser/gtk/options/passwords_exceptions_window_gtk.h"
#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
@@ -44,7 +44,7 @@ static const GdkColor kSyncLabelErrorBgColor = GDK_COLOR_RGB(0xff, 0x9a, 0x9a);
// Helper for WrapLabelAtAllocationHack.
void OnLabelAllocate(GtkWidget* label, GtkAllocation* allocation) {
- gtk_widget_set_size_request(label, allocation->width, -1);
+ gtk_util::SetLabelWidth(label, allocation->width);
// Disconnect ourselves. Repeatedly resizing based on allocation causes
// the dialog to become unshrinkable.
@@ -75,8 +75,8 @@ ContentPageGtk::ContentPageGtk(Profile* profile)
#if !defined(OS_CHROMEOS)
sync_action_link_background_(NULL),
sync_action_link_(NULL),
- sync_start_stop_button_(NULL),
#endif
+ sync_start_stop_button_(NULL),
sync_customize_button_(NULL),
privacy_dashboard_link_(NULL),
initializing_(true),
@@ -101,6 +101,8 @@ ContentPageGtk::ContentPageGtk(Profile* profile)
// Add preferences observers.
ask_to_save_passwords_.Init(prefs::kPasswordManagerEnabled,
profile->GetPrefs(), this);
+ form_autofill_enabled_.Init(prefs::kAutoFillEnabled,
+ profile->GetPrefs(), this);
if (browser_defaults::kCanToggleSystemTitleBar) {
use_custom_chrome_frame_.Init(prefs::kUseCustomChromeFrame,
profile->GetPrefs(), this);
@@ -112,11 +114,9 @@ ContentPageGtk::ContentPageGtk(Profile* profile)
options_builder->AddOptionGroup(
l10n_util::GetStringUTF8(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME),
InitFormAutoFillGroup(), false);
-#if !defined(OS_CHROMEOS)
options_builder->AddOptionGroup(
l10n_util::GetStringUTF8(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME),
InitBrowsingDataGroup(), false);
-#endif
options_builder->AddOptionGroup(
l10n_util::GetStringUTF8(IDS_APPEARANCE_GROUP_NAME),
InitThemesGroup(), false);
@@ -152,7 +152,7 @@ void ContentPageGtk::OnStateChanged() {
// If |pref_name| is NULL, set the state of all the widgets. (This is used
// in ContentPageGtk() above to initialize the dialog.) Otherwise, reset the
// state of the widget for the given preference name, as it has changed.
-void ContentPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
+void ContentPageGtk::NotifyPrefChanged(const std::string* pref_name) {
initializing_ = true;
if (!pref_name || *pref_name == prefs::kPasswordManagerEnabled) {
if (ask_to_save_passwords_.GetValue()) {
@@ -162,6 +162,19 @@ void ContentPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(passwords_neversave_radio_), TRUE);
}
+ bool isPasswordManagerEnabled = !ask_to_save_passwords_.IsManaged();
+ gtk_widget_set_sensitive(passwords_asktosave_radio_,
+ isPasswordManagerEnabled);
+ gtk_widget_set_sensitive(passwords_neversave_radio_,
+ isPasswordManagerEnabled);
+ gtk_widget_set_sensitive(show_passwords_button_,
+ isPasswordManagerEnabled ||
+ ask_to_save_passwords_.GetValue());
+ }
+ if (!pref_name || *pref_name == prefs::kAutoFillEnabled) {
+ bool disabled_by_policy = form_autofill_enabled_.IsManaged() &&
+ !form_autofill_enabled_.GetValue();
+ gtk_widget_set_sensitive(autofill_button_, !disabled_by_policy);
}
if (browser_defaults::kCanToggleSystemTitleBar &&
(!pref_name || *pref_name == prefs::kUseCustomChromeFrame)) {
@@ -224,21 +237,13 @@ GtkWidget* ContentPageGtk::InitPasswordSavingGroup() {
// depend on the spacing above.
GtkWidget* button_hbox = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
gtk_container_add(GTK_CONTAINER(vbox), button_hbox);
- GtkWidget* show_passwords_button = gtk_button_new_with_label(
+ show_passwords_button_ = gtk_button_new_with_label(
l10n_util::GetStringUTF8(IDS_OPTIONS_PASSWORDS_SHOWPASSWORDS).c_str());
- g_signal_connect(show_passwords_button, "clicked",
+ g_signal_connect(show_passwords_button_, "clicked",
G_CALLBACK(OnShowPasswordsButtonClickedThunk), this);
- gtk_box_pack_start(GTK_BOX(button_hbox), show_passwords_button, FALSE,
+ gtk_box_pack_start(GTK_BOX(button_hbox), show_passwords_button_, FALSE,
FALSE, 0);
- bool isPasswordManagerEnabled = !ask_to_save_passwords_.IsManaged();
- gtk_widget_set_sensitive(passwords_asktosave_radio_,
- isPasswordManagerEnabled);
- gtk_widget_set_sensitive(passwords_neversave_radio_,
- isPasswordManagerEnabled);
- gtk_widget_set_sensitive(show_passwords_button,
- isPasswordManagerEnabled);
-
return vbox;
}
@@ -249,12 +254,12 @@ GtkWidget* ContentPageGtk::InitFormAutoFillGroup() {
gtk_container_add(GTK_CONTAINER(vbox), button_hbox);
// AutoFill button.
- GtkWidget* autofill_button = gtk_button_new_with_label(
+ autofill_button_ = gtk_button_new_with_label(
l10n_util::GetStringUTF8(IDS_AUTOFILL_OPTIONS).c_str());
- g_signal_connect(G_OBJECT(autofill_button), "clicked",
+ g_signal_connect(G_OBJECT(autofill_button_), "clicked",
G_CALLBACK(OnAutoFillButtonClickedThunk), this);
- gtk_box_pack_start(GTK_BOX(button_hbox), autofill_button, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(button_hbox), autofill_button_, FALSE, FALSE, 0);
return vbox;
}
@@ -332,8 +337,7 @@ GtkWidget* ContentPageGtk::InitSyncGroup() {
sync_status_label_ = gtk_label_new("");
WrapLabelAtAllocationHack(sync_status_label_);
- gtk_label_set_line_wrap(GTK_LABEL(sync_status_label_), TRUE);
- gtk_misc_set_alignment(GTK_MISC(sync_status_label_), 0, 0);
+ gtk_misc_set_alignment(GTK_MISC(sync_status_label_), 0, 0.5);
gtk_box_pack_start(GTK_BOX(vbox), sync_status_label_background_, FALSE,
FALSE, 0);
gtk_container_add(GTK_CONTAINER(sync_status_label_background_),
@@ -358,38 +362,33 @@ GtkWidget* ContentPageGtk::InitSyncGroup() {
// depend on the spacing above.
GtkWidget* button_hbox = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
gtk_container_add(GTK_CONTAINER(vbox), button_hbox);
-#if !defined(OS_CHROMEOS)
sync_start_stop_button_ = gtk_button_new_with_label("");
g_signal_connect(sync_start_stop_button_, "clicked",
G_CALLBACK(OnSyncStartStopButtonClickedThunk), this);
gtk_box_pack_start(GTK_BOX(button_hbox), sync_start_stop_button_, FALSE,
FALSE, 0);
-#endif
sync_customize_button_ = gtk_button_new_with_label("");
g_signal_connect(sync_customize_button_, "clicked",
G_CALLBACK(OnSyncCustomizeButtonClickedThunk), this);
gtk_box_pack_start(GTK_BOX(button_hbox), sync_customize_button_, FALSE,
FALSE, 0);
- // Add the privacy dashboard link. Only show it if the command line
- // switch has been provided.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kShowPrivacyDashboardLink)) {
- GtkWidget* dashboard_link_hbox =
- gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
- GtkWidget* dashboard_link_background = gtk_event_box_new();
- std::string dashboard_link_label =
- l10n_util::GetStringUTF8(IDS_SYNC_PRIVACY_DASHBOARD_LINK_LABEL);
- privacy_dashboard_link_ =
- gtk_chrome_link_button_new(dashboard_link_label.c_str());
- g_signal_connect(privacy_dashboard_link_, "clicked",
- G_CALLBACK(OnPrivacyDashboardLinkClickedThunk), this);
- gtk_box_pack_start(GTK_BOX(vbox), dashboard_link_hbox, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(dashboard_link_hbox),
- dashboard_link_background, FALSE, FALSE, 0);
- gtk_container_add(GTK_CONTAINER(dashboard_link_background),
- privacy_dashboard_link_);
- }
+ // Add the privacy dashboard link.
+ GtkWidget* dashboard_link_hbox =
+ gtk_hbox_new(FALSE, gtk_util::kLabelSpacing);
+ GtkWidget* dashboard_link_background = gtk_event_box_new();
+ std::string dashboard_link_label =
+ l10n_util::GetStringUTF8(IDS_SYNC_PRIVACY_DASHBOARD_LINK_LABEL);
+ privacy_dashboard_link_ =
+ gtk_chrome_link_button_new(dashboard_link_label.c_str());
+ g_signal_connect(privacy_dashboard_link_, "clicked",
+ G_CALLBACK(OnPrivacyDashboardLinkClickedThunk), this);
+ gtk_box_pack_start(GTK_BOX(vbox), dashboard_link_hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(dashboard_link_hbox),
+ dashboard_link_background, FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(dashboard_link_background),
+ privacy_dashboard_link_);
+
return vbox;
}
@@ -399,29 +398,49 @@ void ContentPageGtk::UpdateSyncControls() {
string16 status_label;
string16 link_label;
std::string customize_button_label;
- std::string button_label;
bool managed = sync_service_->IsManaged();
bool sync_setup_completed = sync_service_->HasSyncSetupCompleted();
bool status_has_error = sync_ui_util::GetStatusLabels(sync_service_,
&status_label, &link_label) == sync_ui_util::SYNC_ERROR;
customize_button_label =
l10n_util::GetStringUTF8(IDS_SYNC_CUSTOMIZE_BUTTON_LABEL);
+
+ std::string start_stop_button_label;
+ bool is_start_stop_button_visible = false;
+ bool is_start_stop_button_sensitive = false;
if (sync_setup_completed) {
- button_label = l10n_util::GetStringUTF8(IDS_SYNC_STOP_SYNCING_BUTTON_LABEL);
+ start_stop_button_label =
+ l10n_util::GetStringUTF8(IDS_SYNC_STOP_SYNCING_BUTTON_LABEL);
+#if defined(OS_CHROMEOS)
+ is_start_stop_button_visible = false;
+#else
+ is_start_stop_button_visible = true;
+#endif
+ is_start_stop_button_sensitive = !managed;
} else if (sync_service_->SetupInProgress()) {
- button_label = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SETUP_IN_PROGRESS);
+ start_stop_button_label =
+ l10n_util::GetStringUTF8(IDS_SYNC_NTP_SETUP_IN_PROGRESS);
+ is_start_stop_button_visible = true;
+ is_start_stop_button_sensitive = false;
} else {
- button_label = l10n_util::GetStringUTF8(IDS_SYNC_START_SYNC_BUTTON_LABEL);
+ start_stop_button_label =
+ l10n_util::GetStringUTF8(IDS_SYNC_START_SYNC_BUTTON_LABEL);
+ is_start_stop_button_visible = true;
+ is_start_stop_button_sensitive = !managed;
}
+ gtk_widget_set_no_show_all(sync_start_stop_button_,
+ !is_start_stop_button_visible);
+ if (is_start_stop_button_visible)
+ gtk_widget_show(sync_start_stop_button_);
+ else
+ gtk_widget_hide(sync_start_stop_button_);
+ gtk_widget_set_sensitive(sync_start_stop_button_,
+ is_start_stop_button_sensitive);
+ gtk_button_set_label(GTK_BUTTON(sync_start_stop_button_),
+ start_stop_button_label.c_str());
gtk_label_set_label(GTK_LABEL(sync_status_label_),
UTF16ToUTF8(status_label).c_str());
-#if !defined(OS_CHROMEOS)
- gtk_widget_set_sensitive(sync_start_stop_button_,
- !sync_service_->WizardIsVisible() && !managed);
- gtk_button_set_label(GTK_BUTTON(sync_start_stop_button_),
- button_label.c_str());
-#endif
gtk_widget_set_child_visible(sync_customize_button_,
sync_setup_completed && !status_has_error);
@@ -572,7 +591,7 @@ void ContentPageGtk::OnSyncStartStopButtonClicked(GtkWidget* widget) {
gtk_util::ShowDialog(dialog);
return;
} else {
- sync_service_->EnableForUser(NULL);
+ sync_service_->ShowLoginDialog(NULL);
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
}
}
diff --git a/chrome/browser/gtk/options/content_page_gtk.h b/chrome/browser/gtk/options/content_page_gtk.h
index f7239e0..286e28c 100644
--- a/chrome/browser/gtk/options/content_page_gtk.h
+++ b/chrome/browser/gtk/options/content_page_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_CONTENT_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_CONTENT_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,7 +12,7 @@
#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/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -33,7 +34,7 @@ class ContentPageGtk : public OptionsPageBase,
void UpdateSyncControls();
// Overridden from OptionsPageBase.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// Overridden from OptionsPageBase.
virtual void Observe(NotificationType type,
@@ -67,6 +68,10 @@ class ContentPageGtk : public OptionsPageBase,
// Widgets for the Password saving group.
GtkWidget* passwords_asktosave_radio_;
GtkWidget* passwords_neversave_radio_;
+ GtkWidget* show_passwords_button_;
+
+ // Widgets for the AutoFill group.
+ GtkWidget* autofill_button_;
// Widgets for the Appearance group.
GtkWidget* system_title_bar_show_radio_;
@@ -81,9 +86,7 @@ class ContentPageGtk : public OptionsPageBase,
GtkWidget* sync_status_label_;
GtkWidget* sync_action_link_background_;
GtkWidget* sync_action_link_;
-#if !defined(OS_CHROMEOS)
GtkWidget* sync_start_stop_button_;
-#endif
GtkWidget* sync_customize_button_;
GtkWidget* privacy_dashboard_link_;
@@ -92,6 +95,7 @@ class ContentPageGtk : public OptionsPageBase,
// Pref members.
BooleanPrefMember ask_to_save_passwords_;
+ BooleanPrefMember form_autofill_enabled_;
BooleanPrefMember use_custom_chrome_frame_;
// Flag to ignore gtk callbacks while we are loading prefs, to avoid
diff --git a/chrome/browser/gtk/options/content_settings_window_gtk.cc b/chrome/browser/gtk/options/content_settings_window_gtk.cc
index eb336e3..7b2c9e5 100644
--- a/chrome/browser/gtk/options/content_settings_window_gtk.cc
+++ b/chrome/browser/gtk/options/content_settings_window_gtk.cc
@@ -16,7 +16,7 @@
#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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_settings_types.h"
diff --git a/chrome/browser/gtk/options/content_settings_window_gtk.h b/chrome/browser/gtk/options/content_settings_window_gtk.h
index 900e89b..6e32f4a 100644
--- a/chrome/browser/gtk/options/content_settings_window_gtk.h
+++ b/chrome/browser/gtk/options/content_settings_window_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_CONTENT_SETTINGS_WINDOW_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_CONTENT_SETTINGS_WINDOW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,7 +12,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/options/cookie_filter_page_gtk.h"
#include "chrome/browser/gtk/options/content_filter_page_gtk.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/common/content_settings_types.h"
class AccessibleWidgetHelper;
diff --git a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc
index 878fdd0..f60bebd 100644
--- a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc
+++ b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/gtk/options/cookie_filter_page_gtk.h"
#include "app/l10n_util.h"
+#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browsing_data_local_storage_helper.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
@@ -14,6 +15,7 @@
#include "chrome/browser/gtk/options/cookies_view.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
@@ -48,7 +50,7 @@ CookieFilterPageGtk::CookieFilterPageGtk(Profile* profile)
CookieFilterPageGtk::~CookieFilterPageGtk() {
}
-void CookieFilterPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
+void CookieFilterPageGtk::NotifyPrefChanged(const std::string* pref_name) {
initializing_ = true;
if (!pref_name || *pref_name == prefs::kClearSiteDataOnExit) {
@@ -89,9 +91,11 @@ GtkWidget* CookieFilterPageGtk::InitCookieStoringGroup() {
GtkWidget* radio_button = NULL;
if (default_setting == CONTENT_SETTING_ALLOW) {
radio_button = allow_radio_;
- } else {
- DCHECK(default_setting == CONTENT_SETTING_BLOCK);
+ } else if (default_setting == CONTENT_SETTING_BLOCK) {
radio_button = block_radio_;
+ } else {
+ DCHECK(default_setting == CONTENT_SETTING_ASK);
+ radio_button = ask_every_time_radio_;
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE);
@@ -148,6 +152,8 @@ void CookieFilterPageGtk::OnCookiesAllowToggled(GtkWidget* toggle_button) {
ContentSetting setting = CONTENT_SETTING_ALLOW;
if (toggle_button == allow_radio_)
setting = CONTENT_SETTING_ALLOW;
+ else if (toggle_button == ask_every_time_radio_)
+ setting = CONTENT_SETTING_ASK;
else if (toggle_button == block_radio_)
setting = CONTENT_SETTING_BLOCK;
@@ -187,12 +193,10 @@ void CookieFilterPageGtk::OnShowCookiesClicked(GtkWidget* button) {
UserMetricsRecordAction(UserMetricsAction("Options_ShowCookies"), NULL);
CookiesView::Show(GTK_WINDOW(gtk_widget_get_toplevel(button)),
profile(),
- new BrowsingDataDatabaseHelper(
- profile()),
- new BrowsingDataLocalStorageHelper(
- profile()),
- new BrowsingDataAppCacheHelper(
- profile()));
+ new BrowsingDataDatabaseHelper(profile()),
+ new BrowsingDataLocalStorageHelper(profile()),
+ new BrowsingDataAppCacheHelper(profile()),
+ BrowsingDataIndexedDBHelper::Create(profile()));
}
void CookieFilterPageGtk::OnFlashLinkClicked(GtkWidget* button) {
diff --git a/chrome/browser/gtk/options/cookie_filter_page_gtk.h b/chrome/browser/gtk/options/cookie_filter_page_gtk.h
index 062b099..2825d0e 100644
--- a/chrome/browser/gtk/options/cookie_filter_page_gtk.h
+++ b/chrome/browser/gtk/options/cookie_filter_page_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_COOKIE_FILTER_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_COOKIE_FILTER_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,7 +12,7 @@
#include "app/gtk_signal.h"
#include "chrome/browser/options_page_base.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
class Profile;
@@ -29,7 +30,7 @@ class CookieFilterPageGtk : public OptionsPageBase {
private:
// Overridden from OptionsPageBase
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
virtual void HighlightGroup(OptionsGroup highlight_group);
CHROMEGTK_CALLBACK_0(CookieFilterPageGtk, void, OnCookiesAllowToggled);
@@ -43,6 +44,7 @@ class CookieFilterPageGtk : public OptionsPageBase {
// Widgets of the cookie storing group
GtkWidget* allow_radio_;
+ GtkWidget* ask_every_time_radio_;
GtkWidget* block_radio_;
GtkWidget* exceptions_button_;
diff --git a/chrome/browser/gtk/options/cookies_view.cc b/chrome/browser/gtk/options/cookies_view.cc
index b32f664..415dedb 100644
--- a/chrome/browser/gtk/options/cookies_view.cc
+++ b/chrome/browser/gtk/options/cookies_view.cc
@@ -50,11 +50,13 @@ void CookiesView::Show(
Profile* profile,
BrowsingDataDatabaseHelper* browsing_data_database_helper,
BrowsingDataLocalStorageHelper* browsing_data_local_storage_helper,
- BrowsingDataAppCacheHelper* browsing_data_appcache_helper) {
+ BrowsingDataAppCacheHelper* browsing_data_appcache_helper,
+ BrowsingDataIndexedDBHelper* browsing_data_indexed_db_helper) {
DCHECK(profile);
DCHECK(browsing_data_database_helper);
DCHECK(browsing_data_local_storage_helper);
DCHECK(browsing_data_appcache_helper);
+ DCHECK(browsing_data_indexed_db_helper);
// If there's already an existing editor window, activate it.
if (instance_) {
@@ -64,7 +66,8 @@ void CookiesView::Show(
profile,
browsing_data_database_helper,
browsing_data_local_storage_helper,
- browsing_data_appcache_helper);
+ browsing_data_appcache_helper,
+ browsing_data_indexed_db_helper);
}
}
@@ -73,11 +76,13 @@ CookiesView::CookiesView(
Profile* profile,
BrowsingDataDatabaseHelper* browsing_data_database_helper,
BrowsingDataLocalStorageHelper* browsing_data_local_storage_helper,
- BrowsingDataAppCacheHelper* browsing_data_appcache_helper)
+ BrowsingDataAppCacheHelper* browsing_data_appcache_helper,
+ BrowsingDataIndexedDBHelper* browsing_data_indexed_db_helper)
: profile_(profile),
browsing_data_database_helper_(browsing_data_database_helper),
browsing_data_local_storage_helper_(browsing_data_local_storage_helper),
browsing_data_appcache_helper_(browsing_data_appcache_helper),
+ browsing_data_indexed_db_helper_(browsing_data_indexed_db_helper),
filter_update_factory_(this),
destroy_dialog_in_destructor_(false) {
Init(parent);
@@ -90,7 +95,7 @@ CookiesView::CookiesView(
gtk_chrome_cookie_view_clear(GTK_CHROME_COOKIE_VIEW(cookie_display_));
}
-void CookiesView::TestDestroySyncrhonously() {
+void CookiesView::TestDestroySynchronously() {
g_signal_handler_disconnect(dialog_, destroy_handler_);
destroy_dialog_in_destructor_ = true;
}
@@ -187,7 +192,9 @@ void CookiesView::Init(GtkWindow* parent) {
profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(),
browsing_data_database_helper_,
browsing_data_local_storage_helper_,
- browsing_data_appcache_helper_));
+ NULL,
+ browsing_data_appcache_helper_,
+ browsing_data_indexed_db_helper_));
cookies_tree_adapter_.reset(
new gtk_tree::TreeAdapter(this, cookies_tree_model_.get()));
tree_ = gtk_tree_view_new_with_model(
@@ -269,6 +276,11 @@ void CookiesView::EnableControls() {
gtk_chrome_cookie_view_display_app_cache(
GTK_CHROME_COOKIE_VIEW(cookie_display_),
*detailed_info.appcache_info);
+ } else if (detailed_info.node_type ==
+ CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB) {
+ gtk_chrome_cookie_view_display_indexed_db(
+ GTK_CHROME_COOKIE_VIEW(cookie_display_),
+ *detailed_info.indexed_db_info);
} else {
gtk_chrome_cookie_view_clear(GTK_CHROME_COOKIE_VIEW(cookie_display_));
}
diff --git a/chrome/browser/gtk/options/cookies_view.h b/chrome/browser/gtk/options/cookies_view.h
index 8843ac4..27c0e0f 100644
--- a/chrome/browser/gtk/options/cookies_view.h
+++ b/chrome/browser/gtk/options/cookies_view.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_COOKIES_VIEW_H_
#define CHROME_BROWSER_GTK_OPTIONS_COOKIES_VIEW_H_
+#pragma once
#include <gtk/gtk.h>
@@ -16,6 +17,7 @@
#include "base/task.h"
#include "chrome/browser/browsing_data_appcache_helper.h"
#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/gtk/gtk_chrome_cookie_view.h"
#include "chrome/browser/gtk/gtk_tree.h"
@@ -42,7 +44,8 @@ class CookiesView : public gtk_tree::TreeAdapter::Delegate {
Profile* profile,
BrowsingDataDatabaseHelper* browsing_data_database_helper,
BrowsingDataLocalStorageHelper* browsing_data_local_storage_helper,
- BrowsingDataAppCacheHelper* browsing_data_appcache_helper);
+ BrowsingDataAppCacheHelper* browsing_data_appcache_helper,
+ BrowsingDataIndexedDBHelper* browsing_data_indexed_db_helper);
// gtk_tree::TreeAdapter::Delegate implementation.
virtual void OnAnyModelUpdateStart();
@@ -54,11 +57,12 @@ class CookiesView : public gtk_tree::TreeAdapter::Delegate {
Profile* profile,
BrowsingDataDatabaseHelper* browsing_data_database_helper,
BrowsingDataLocalStorageHelper* browsing_data_local_storage_helper,
- BrowsingDataAppCacheHelper* browsing_data_appcache_helper);
+ BrowsingDataAppCacheHelper* browsing_data_appcache_helper,
+ BrowsingDataIndexedDBHelper* browsing_data_indexed_db_helper);
// A method only used in unit tests that sets a bit inside this class that
// lets it be stack allocated.
- void TestDestroySyncrhonously();
+ void TestDestroySynchronously();
// Initialize the dialog contents and layout.
void Init(GtkWindow* parent);
@@ -111,6 +115,7 @@ class CookiesView : public gtk_tree::TreeAdapter::Delegate {
scoped_refptr<BrowsingDataLocalStorageHelper>
browsing_data_local_storage_helper_;
scoped_refptr<BrowsingDataAppCacheHelper> browsing_data_appcache_helper_;
+ scoped_refptr<BrowsingDataIndexedDBHelper> browsing_data_indexed_db_helper_;
// A factory to construct Runnable Methods so that we can be called back to
// re-evaluate the model after the search query string changes.
diff --git a/chrome/browser/gtk/options/cookies_view_unittest.cc b/chrome/browser/gtk/options/cookies_view_unittest.cc
index 903fe25..2a71eea 100644
--- a/chrome/browser/gtk/options/cookies_view_unittest.cc
+++ b/chrome/browser/gtk/options/cookies_view_unittest.cc
@@ -12,6 +12,7 @@
#include "base/string_util.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/browser/gtk/gtk_chrome_cookie_view.h"
#include "chrome/common/net/url_request_context_getter.h"
@@ -36,12 +37,15 @@ class CookiesViewTest : public testing::Test {
new MockBrowsingDataLocalStorageHelper(profile_.get());
mock_browsing_data_appcache_helper_ =
new MockBrowsingDataAppCacheHelper(profile_.get());
+ mock_browsing_data_indexed_db_helper_ =
+ new MockBrowsingDataIndexedDBHelper(profile_.get());
}
void CheckDetailsSensitivity(gboolean expected_cookies,
gboolean expected_database,
gboolean expected_local_storage,
gboolean expected_appcache,
+ gboolean expected_indexed_db,
const CookiesView& cookies_view) {
GtkChromeCookieView* display = GTK_CHROME_COOKIE_VIEW(
cookies_view.cookie_display_);
@@ -84,6 +88,15 @@ class CookiesViewTest : public testing::Test {
GTK_WIDGET_SENSITIVE(display->appcache_created_entry_));
EXPECT_EQ(expected_appcache,
GTK_WIDGET_SENSITIVE(display->appcache_last_accessed_entry_));
+ // IndexedDB
+ EXPECT_EQ(expected_indexed_db,
+ GTK_WIDGET_SENSITIVE(display->indexed_db_name_entry_));
+ EXPECT_EQ(expected_indexed_db,
+ GTK_WIDGET_SENSITIVE(display->indexed_db_origin_entry_));
+ EXPECT_EQ(expected_indexed_db,
+ GTK_WIDGET_SENSITIVE(display->indexed_db_size_entry_));
+ EXPECT_EQ(expected_indexed_db,
+ GTK_WIDGET_SENSITIVE(display->indexed_db_last_modified_entry_));
}
// Get the cookie names in the cookie list, as a comma seperated string.
@@ -194,6 +207,8 @@ class CookiesViewTest : public testing::Test {
mock_browsing_data_local_storage_helper_;
scoped_refptr<MockBrowsingDataAppCacheHelper>
mock_browsing_data_appcache_helper_;
+ scoped_refptr<MockBrowsingDataIndexedDBHelper>
+ mock_browsing_data_indexed_db_helper_;
};
TEST_F(CookiesViewTest, Empty) {
@@ -201,11 +216,12 @@ TEST_F(CookiesViewTest, Empty) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("", GetDisplayedCookies(cookies_view).c_str());
}
@@ -222,8 +238,9 @@ TEST_F(CookiesViewTest, Noop) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -238,7 +255,7 @@ TEST_F(CookiesViewTest, Noop) {
GetDisplayedCookies(cookies_view).c_str());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
TEST_F(CookiesViewTest, RemoveAll) {
@@ -249,8 +266,9 @@ TEST_F(CookiesViewTest, RemoveAll) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -263,7 +281,7 @@ TEST_F(CookiesViewTest, RemoveAll) {
SCOPED_TRACE("Before removing");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("foo,_Cookies,__A,foo2,_Cookies,__B,"
"gdbhost1,_Web Databases,__db1,"
"gdbhost2,_Web Databases,__db2,"
@@ -281,7 +299,7 @@ TEST_F(CookiesViewTest, RemoveAll) {
EXPECT_EQ(0u, monster->GetAllCookies().size());
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("", GetDisplayedCookies(cookies_view).c_str());
EXPECT_TRUE(mock_browsing_data_database_helper_->AllDeleted());
EXPECT_TRUE(mock_browsing_data_local_storage_helper_->AllDeleted());
@@ -296,8 +314,9 @@ TEST_F(CookiesViewTest, RemoveAllWithDefaultSelected) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -309,7 +328,7 @@ TEST_F(CookiesViewTest, RemoveAllWithDefaultSelected) {
SCOPED_TRACE("Before removing");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("foo,_Cookies,__A,foo2,_Cookies,__B,"
"gdbhost1,_Web Databases,__db1,"
"gdbhost2,_Web Databases,__db2,"
@@ -327,7 +346,7 @@ TEST_F(CookiesViewTest, RemoveAllWithDefaultSelected) {
EXPECT_EQ(0u, monster->GetAllCookies().size());
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("", GetDisplayedCookies(cookies_view).c_str());
EXPECT_EQ(0,
gtk_tree_selection_count_selected_rows(cookies_view.selection_));
@@ -345,8 +364,9 @@ TEST_F(CookiesViewTest, Remove) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -359,7 +379,7 @@ TEST_F(CookiesViewTest, Remove) {
SCOPED_TRACE("First selection");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("foo1,_Cookies,__A,foo2,+Cookies,++B,++C,"
"gdbhost1,_Web Databases,__db1,"
"gdbhost2,_Web Databases,__db2,"
@@ -382,7 +402,7 @@ TEST_F(CookiesViewTest, Remove) {
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
EXPECT_STREQ("1:0:0", GetSelectedPath(cookies_view).c_str());
- CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
@@ -400,7 +420,7 @@ TEST_F(CookiesViewTest, Remove) {
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
EXPECT_STREQ("", GetSelectedPath(cookies_view).c_str());
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
ASSERT_TRUE(ExpandByPath(cookies_view, "0"));
@@ -419,7 +439,7 @@ TEST_F(CookiesViewTest, Remove) {
EXPECT_EQ(0u, monster->GetAllCookies().size());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("gdbhost1,_Web Databases,__db1,"
"gdbhost2,_Web Databases,__db2,"
"host1,_Local Storage,__http://host1:1/,"
@@ -442,7 +462,7 @@ TEST_F(CookiesViewTest, Remove) {
EXPECT_EQ(0u, monster->GetAllCookies().size());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("gdbhost2,_Web Databases,__db2,"
"host1,_Local Storage,__http://host1:1/,"
"host2,_Local Storage,__http://host2:2/",
@@ -467,7 +487,7 @@ TEST_F(CookiesViewTest, Remove) {
EXPECT_EQ(0u, monster->GetAllCookies().size());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("gdbhost2,_Web Databases,__db2,"
"host2,_Local Storage,__http://host2:2/",
GetDisplayedCookies(cookies_view).c_str());
@@ -489,8 +509,9 @@ TEST_F(CookiesViewTest, RemoveCookiesByType) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -624,8 +645,9 @@ TEST_F(CookiesViewTest, RemoveByDomain) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -750,8 +772,9 @@ TEST_F(CookiesViewTest, RemoveDefaultSelection) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -858,8 +881,9 @@ TEST_F(CookiesViewTest, Filter) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -928,8 +952,9 @@ TEST_F(CookiesViewTest, FilterRemoveAll) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -997,8 +1022,9 @@ TEST_F(CookiesViewTest, FilterRemove) {
profile_.get(),
mock_browsing_data_database_helper_,
mock_browsing_data_local_storage_helper_,
- mock_browsing_data_appcache_helper_);
- cookies_view.TestDestroySyncrhonously();
+ mock_browsing_data_appcache_helper_,
+ mock_browsing_data_indexed_db_helper_);
+ cookies_view.TestDestroySynchronously();
mock_browsing_data_database_helper_->AddDatabaseSamples();
mock_browsing_data_database_helper_->Notify();
mock_browsing_data_local_storage_helper_->AddLocalStorageSamples();
@@ -1013,7 +1039,8 @@ TEST_F(CookiesViewTest, FilterRemove) {
"host1,_Local Storage,__http://host1:1/,"
"host2,_Local Storage,__http://host2:2/",
GetDisplayedCookies(cookies_view).c_str());
- EXPECT_STREQ("D,A,E,C,B", GetMonsterCookies(monster).c_str());
+ // All default paths; order will be creation time.
+ EXPECT_STREQ("C,D,B,A,E", GetMonsterCookies(monster).c_str());
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.filter_clear_button_));
@@ -1046,33 +1073,33 @@ TEST_F(CookiesViewTest, FilterRemove) {
SCOPED_TRACE("First selection");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
gtk_button_clicked(GTK_BUTTON(cookies_view.remove_button_));
{
SCOPED_TRACE("First selection removed");
- EXPECT_STREQ("D,E,C,B", GetMonsterCookies(monster).c_str());
+ EXPECT_STREQ("C,D,B,E", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("bar0,_Cookies,__D,"
"bar1,+Cookies,++E",
GetDisplayedCookies(cookies_view).c_str());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
EXPECT_STREQ("1:0:0", GetSelectedPath(cookies_view).c_str());
- CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(TRUE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
gtk_button_clicked(GTK_BUTTON(cookies_view.remove_button_));
{
SCOPED_TRACE("Second selection");
- EXPECT_STREQ("D,C,B", GetMonsterCookies(monster).c_str());
+ EXPECT_STREQ("C,D,B", GetMonsterCookies(monster).c_str());
EXPECT_STREQ("bar0,_Cookies,__D",
GetDisplayedCookies(cookies_view).c_str());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
ASSERT_TRUE(ExpandByPath(cookies_view, "0"));
@@ -1085,7 +1112,7 @@ TEST_F(CookiesViewTest, FilterRemove) {
EXPECT_STREQ("C,B", GetMonsterCookies(monster).c_str());
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
EXPECT_STREQ("", GetDisplayedCookies(cookies_view).c_str());
}
@@ -1131,7 +1158,7 @@ TEST_F(CookiesViewTest, FilterRemove) {
SCOPED_TRACE("First selection");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, TRUE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, TRUE, FALSE, FALSE, FALSE, cookies_view);
}
gtk_button_clicked(GTK_BUTTON(cookies_view.remove_button_));
@@ -1145,7 +1172,7 @@ TEST_F(CookiesViewTest, FilterRemove) {
GetDisplayedCookies(cookies_view).c_str());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
ASSERT_TRUE(ExpandByPath(cookies_view, "2"));
@@ -1159,7 +1186,7 @@ TEST_F(CookiesViewTest, FilterRemove) {
SCOPED_TRACE("First selection");
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, TRUE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, TRUE, FALSE, FALSE, cookies_view);
}
gtk_button_clicked(GTK_BUTTON(cookies_view.remove_button_));
@@ -1172,6 +1199,6 @@ TEST_F(CookiesViewTest, FilterRemove) {
GetDisplayedCookies(cookies_view).c_str());
EXPECT_EQ(TRUE, GTK_WIDGET_SENSITIVE(cookies_view.remove_all_button_));
EXPECT_EQ(FALSE, GTK_WIDGET_SENSITIVE(cookies_view.remove_button_));
- CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, cookies_view);
+ CheckDetailsSensitivity(FALSE, FALSE, FALSE, FALSE, FALSE, cookies_view);
}
}
diff --git a/chrome/browser/gtk/options/fonts_page_gtk.cc b/chrome/browser/gtk/options/fonts_page_gtk.cc
index f5b1902..15ebf9b 100644
--- a/chrome/browser/gtk/options/fonts_page_gtk.cc
+++ b/chrome/browser/gtk/options/fonts_page_gtk.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/gtk/options/fonts_page_gtk.h"
#include "app/l10n_util.h"
-#include "app/l10n_util_collator.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"
@@ -22,8 +22,8 @@ std::string MakeFontName(std::string family_name, int pixel_size) {
// The given font might not be available (the default fonts we use are not
// installed by default on some distros). So figure out which font we are
// actually falling back to and display that. (See crbug.com/31381.)
- std::wstring actual_family_name = gfx::Font::CreateFont(
- UTF8ToWide(family_name), pixel_size).FontName();
+ std::wstring actual_family_name = gfx::Font(
+ UTF8ToWide(family_name), pixel_size).GetFontName();
std::string fontname;
// TODO(mattm): We can pass in the size in pixels (px), and the font button
// actually honors it, but when you open the selector it interprets it as
@@ -116,11 +116,11 @@ void FontsPageGtk::InitDefaultEncodingComboBox() {
for (int i = 0; i < default_encoding_combobox_model_->GetItemCount(); ++i) {
gtk_combo_box_append_text(
GTK_COMBO_BOX(default_encoding_combobox_),
- WideToUTF8(default_encoding_combobox_model_->GetItemAt(i)).c_str());
+ UTF16ToUTF8(default_encoding_combobox_model_->GetItemAt(i)).c_str());
}
}
-void FontsPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
+void FontsPageGtk::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kWebKitSerifFontFamily ||
*pref_name == prefs::kWebKitDefaultFontSize) {
gtk_font_button_set_font_name(GTK_FONT_BUTTON(serif_font_button_),
diff --git a/chrome/browser/gtk/options/fonts_page_gtk.h b/chrome/browser/gtk/options/fonts_page_gtk.h
index 837f48f..fc87863 100644
--- a/chrome/browser/gtk/options/fonts_page_gtk.h
+++ b/chrome/browser/gtk/options/fonts_page_gtk.h
@@ -7,15 +7,15 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_FONTS_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_FONTS_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
-#include <vector>
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/pref_member.h"
#include "chrome/browser/options_page_base.h"
+#include "chrome/browser/prefs/pref_member.h"
class DefaultEncodingComboboxModel;
@@ -31,7 +31,7 @@ class FontsPageGtk : public OptionsPageBase {
void InitDefaultEncodingComboBox();
// Overridden from OptionsPageBase.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// Retrieve the font selection from the button and save it to the prefs. Also
// ensure the button(s) are displayed in the proper size, as the
diff --git a/chrome/browser/gtk/options/general_page_gtk.cc b/chrome/browser/gtk/options/general_page_gtk.cc
index 53615f0..734ee8c 100644
--- a/chrome/browser/gtk/options/general_page_gtk.cc
+++ b/chrome/browser/gtk/options/general_page_gtk.cc
@@ -19,10 +19,11 @@
#include "chrome/browser/gtk/options/options_layout_gtk.h"
#include "chrome/browser/gtk/options/url_picker_dialog_gtk.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/session_startup_pref.h"
+#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -94,8 +95,9 @@ GeneralPageGtk::GeneralPageGtk(Profile* profile)
InitDefaultBrowserGroup(), false);
#endif
- profile->GetPrefs()->AddPrefObserver(prefs::kRestoreOnStartup, this);
- profile->GetPrefs()->AddPrefObserver(prefs::kURLsToRestoreOnStartup, this);
+ registrar_.Init(profile->GetPrefs());
+ registrar_.Add(prefs::kRestoreOnStartup, this);
+ registrar_.Add(prefs::kURLsToRestoreOnStartup, this);
new_tab_page_is_home_page_.Init(prefs::kHomePageIsNewTabPage,
profile->GetPrefs(), this);
@@ -107,10 +109,6 @@ GeneralPageGtk::GeneralPageGtk(Profile* profile)
}
GeneralPageGtk::~GeneralPageGtk() {
- profile()->GetPrefs()->RemovePrefObserver(prefs::kRestoreOnStartup, this);
- profile()->GetPrefs()->RemovePrefObserver(
- prefs::kURLsToRestoreOnStartup, this);
-
if (template_url_model_)
template_url_model_->RemoveObserver(this);
@@ -120,37 +118,39 @@ GeneralPageGtk::~GeneralPageGtk() {
///////////////////////////////////////////////////////////////////////////////
// GeneralPageGtk, OptionsPageBase overrides:
-void GeneralPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
+void GeneralPageGtk::NotifyPrefChanged(const std::string* pref_name) {
initializing_ = true;
- if (!pref_name || *pref_name == prefs::kRestoreOnStartup) {
+ if (!pref_name ||
+ *pref_name == prefs::kRestoreOnStartup ||
+ *pref_name == prefs::kURLsToRestoreOnStartup) {
PrefService* prefs = profile()->GetPrefs();
const SessionStartupPref startup_pref =
SessionStartupPref::GetStartupPref(prefs);
+ bool radio_buttons_enabled = !SessionStartupPref::TypeIsManaged(prefs);
+ bool restore_urls_enabled = !SessionStartupPref::URLsAreManaged(prefs);
switch (startup_pref.type) {
case SessionStartupPref::DEFAULT:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(startup_homepage_radio_),
TRUE);
- EnableCustomHomepagesControls(false);
+ restore_urls_enabled = false;
break;
case SessionStartupPref::LAST:
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(startup_last_session_radio_), TRUE);
- EnableCustomHomepagesControls(false);
+ restore_urls_enabled = false;
break;
case SessionStartupPref::URLS:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(startup_custom_radio_),
TRUE);
- EnableCustomHomepagesControls(true);
break;
}
- }
-
- if (!pref_name || *pref_name == prefs::kURLsToRestoreOnStartup) {
- PrefService* prefs = profile()->GetPrefs();
- const SessionStartupPref startup_pref =
- SessionStartupPref::GetStartupPref(prefs);
+ gtk_widget_set_sensitive(startup_homepage_radio_, radio_buttons_enabled);
+ gtk_widget_set_sensitive(startup_last_session_radio_,
+ radio_buttons_enabled);
+ gtk_widget_set_sensitive(startup_custom_radio_, radio_buttons_enabled);
+ EnableCustomHomepagesControls(restore_urls_enabled);
startup_custom_pages_table_model_->SetURLs(startup_pref.urls);
}
@@ -182,6 +182,9 @@ void GeneralPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(homepage_show_home_button_checkbox_),
show_home_button_.GetValue());
+ gtk_widget_set_sensitive(
+ homepage_show_home_button_checkbox_,
+ !show_home_button_.IsManaged());
}
initializing_ = false;
@@ -544,6 +547,12 @@ void GeneralPageGtk::SetCustomUrlListFromCurrentPages() {
}
void GeneralPageGtk::OnAddCustomUrl(const GURL& url) {
+ // The restore URLs policy might have become managed while the dialog is
+ // displayed. While the model makes sure that no changes are made in this
+ // condition, we should still avoid the rest of the method otherwise
+ // graphic elements will become enabled.
+ if (SessionStartupPref::URLsAreManaged(profile()->GetPrefs()))
+ return;
std::set<int> indices;
gtk_tree::GetSelectedIndices(startup_custom_pages_selection_, &indices);
int index;
diff --git a/chrome/browser/gtk/options/general_page_gtk.h b/chrome/browser/gtk/options/general_page_gtk.h
index 93e9aae..143f447 100644
--- a/chrome/browser/gtk/options/general_page_gtk.h
+++ b/chrome/browser/gtk/options/general_page_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_GENERAL_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_GENERAL_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -13,14 +14,16 @@
#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/pref_member.h"
-#include "chrome/browser/search_engines/template_url_model.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 "googleurl/src/gurl.h"
class AccessibleWidgetHelper;
class CustomHomePagesTableModel;
class Profile;
+class TemplateURLModel;
class GeneralPageGtk : public OptionsPageBase,
public TemplateURLModelObserver,
@@ -34,7 +37,7 @@ class GeneralPageGtk : public OptionsPageBase,
private:
// Overridden from OptionsPageBase
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
virtual void HighlightGroup(OptionsGroup highlight_group);
// Initialize the option group widgets, return their container
@@ -158,6 +161,8 @@ class GeneralPageGtk : public OptionsPageBase,
// Tracks managed preference warning banner state.
ManagedPrefsBannerGtk managed_prefs_banner_;
+ PrefChangeRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(GeneralPageGtk);
};
diff --git a/chrome/browser/gtk/options/languages_page_gtk.cc b/chrome/browser/gtk/options/languages_page_gtk.cc
index 59eaacf..443cca8 100644
--- a/chrome/browser/gtk/options/languages_page_gtk.cc
+++ b/chrome/browser/gtk/options/languages_page_gtk.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "app/gtk_signal.h"
+#include "app/gtk_util.h"
#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/message_loop.h"
@@ -32,7 +33,7 @@ GtkWidget* NewComboboxFromModel(ComboboxModel* model) {
int count = model->GetItemCount();
for (int i = 0; i < count; ++i)
gtk_combo_box_append_text(GTK_COMBO_BOX(combobox),
- WideToUTF8(model->GetItemAt(i)).c_str());
+ UTF16ToUTF8(model->GetItemAt(i)).c_str());
return combobox;
}
@@ -42,6 +43,8 @@ GtkWidget* NewComboboxFromModel(ComboboxModel* model) {
class AddLanguageDialog {
public:
AddLanguageDialog(Profile* profile, LanguagesPageGtk* delegate);
+ virtual ~AddLanguageDialog() {}
+
private:
// Callback for dialog buttons.
CHROMEGTK_CALLBACK_1(AddLanguageDialog, void, OnResponse, int);
@@ -139,8 +142,7 @@ void LanguagesPageGtk::Init() {
l10n_util::GetStringUTF8(
IDS_FONT_LANGUAGE_SETTING_LANGUAGES_INSTRUCTIONS).c_str());
gtk_misc_set_alignment(GTK_MISC(languages_instructions_label), 0, .5);
- gtk_label_set_line_wrap(GTK_LABEL(languages_instructions_label), TRUE);
- gtk_widget_set_size_request(languages_instructions_label, kWrapWidth, -1);
+ gtk_util::SetLabelWidth(languages_instructions_label, kWrapWidth);
gtk_box_pack_start(GTK_BOX(languages_vbox), languages_instructions_label,
FALSE, FALSE, 0);
@@ -311,7 +313,7 @@ int LanguagesPageGtk::FirstSelectedRowNum() {
return row_num;
}
-void LanguagesPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
+void LanguagesPageGtk::NotifyPrefChanged(const std::string* pref_name) {
initializing_ = true;
if (!pref_name || *pref_name == prefs::kAcceptLanguages) {
language_order_table_model_->SetAcceptLanguagesString(
diff --git a/chrome/browser/gtk/options/languages_page_gtk.h b/chrome/browser/gtk/options/languages_page_gtk.h
index 17c83cb..81712be 100644
--- a/chrome/browser/gtk/options/languages_page_gtk.h
+++ b/chrome/browser/gtk/options/languages_page_gtk.h
@@ -11,6 +11,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_LANGUAGES_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_LANGUAGES_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -20,8 +21,8 @@
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/gtk_tree.h"
-#include "chrome/browser/pref_member.h"
#include "chrome/browser/options_page_base.h"
+#include "chrome/browser/prefs/pref_member.h"
class LanguageComboboxModel;
class LanguageOrderTableModel;
@@ -58,7 +59,7 @@ class LanguagesPageGtk
int FirstSelectedRowNum();
// Overridden from OptionsPageBase.
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// Callbacks for accept languages widgets.
CHROMEG_CALLBACK_0(LanguagesPageGtk, void, OnSelectionChanged,
diff --git a/chrome/browser/gtk/options/languages_page_gtk_unittest.cc b/chrome/browser/gtk/options/languages_page_gtk_unittest.cc
index cf68dbb..453eea5 100644
--- a/chrome/browser/gtk/options/languages_page_gtk_unittest.cc
+++ b/chrome/browser/gtk/options/languages_page_gtk_unittest.cc
@@ -8,6 +8,7 @@
#include "base/string_util.h"
#include "chrome/browser/language_combobox_model.h"
+#include "chrome/browser/prefs/pref_service.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/options/managed_prefs_banner_gtk.cc b/chrome/browser/gtk/options/managed_prefs_banner_gtk.cc
index a175fad..a402656 100644
--- a/chrome/browser/gtk/options/managed_prefs_banner_gtk.cc
+++ b/chrome/browser/gtk/options/managed_prefs_banner_gtk.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/gtk/options/managed_prefs_banner_gtk.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "grit/generated_resources.h"
@@ -19,7 +18,7 @@ const int kBannerPadding = 3;
ManagedPrefsBannerGtk::ManagedPrefsBannerGtk(PrefService* prefs,
OptionsPage page)
- : ManagedPrefsBannerBase(prefs, page),
+ : policy::ManagedPrefsBannerBase(prefs, page),
banner_widget_(NULL) {
InitWidget();
OnUpdateVisibility();
diff --git a/chrome/browser/gtk/options/managed_prefs_banner_gtk.h b/chrome/browser/gtk/options/managed_prefs_banner_gtk.h
index 499d782..cd7f9c6 100644
--- a/chrome/browser/gtk/options/managed_prefs_banner_gtk.h
+++ b/chrome/browser/gtk/options/managed_prefs_banner_gtk.h
@@ -4,17 +4,16 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_MANAGED_PREFS_BANNER_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_MANAGED_PREFS_BANNER_GTK_H_
-
-#include <set>
+#pragma once
#include <gtk/gtk.h>
-#include "chrome/browser/managed_prefs_banner_base.h"
+#include "chrome/browser/policy/managed_prefs_banner_base.h"
// Constructs and maintains a GTK widget displaying a warning banner. The banner
// is displayed on the preferences dialog whenever there are options that are
// not settable by the user due to policy.
-class ManagedPrefsBannerGtk : public ManagedPrefsBannerBase {
+class ManagedPrefsBannerGtk : public policy::ManagedPrefsBannerBase {
public:
ManagedPrefsBannerGtk(PrefService* prefs, OptionsPage page);
virtual ~ManagedPrefsBannerGtk() { }
diff --git a/chrome/browser/gtk/options/options_layout_gtk.h b/chrome/browser/gtk/options/options_layout_gtk.h
index 96bbc8b..5bf2d3e 100644
--- a/chrome/browser/gtk/options/options_layout_gtk.h
+++ b/chrome/browser/gtk/options/options_layout_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_OPTIONS_LAYOUT_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_OPTIONS_LAYOUT_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include <string>
@@ -12,6 +13,8 @@
class OptionsLayoutBuilderGtk {
public:
+ virtual ~OptionsLayoutBuilderGtk() {}
+
GtkWidget* get_page_widget() {
return page_;
}
@@ -38,7 +41,6 @@ class OptionsLayoutBuilderGtk {
protected:
// The parent widget
GtkWidget* page_;
-
};
#endif // CHROME_BROWSER_GTK_OPTIONS_OPTIONS_LAYOUT_GTK_H_
diff --git a/chrome/browser/gtk/options/options_window_gtk.cc b/chrome/browser/gtk/options/options_window_gtk.cc
index 3b370eb..8c7555c 100644
--- a/chrome/browser/gtk/options/options_window_gtk.cc
+++ b/chrome/browser/gtk/options/options_window_gtk.cc
@@ -18,8 +18,8 @@
#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/pref_member.h"
-#include "chrome/browser/pref_service.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"
@@ -98,8 +98,8 @@ OptionsWindowGtk::OptionsWindowGtk(Profile* profile)
std::string dialog_name =
l10n_util::GetStringFUTF8(
- IDS_OPTIONS_DIALOG_TITLE,
- WideToUTF16(l10n_util::GetString(IDS_PRODUCT_NAME)));
+ IDS_PREFERENCES_DIALOG_TITLE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
dialog_ = gtk_dialog_new_with_buttons(
dialog_name.c_str(),
// Prefs window is shared between all browser windows.
diff --git a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc
index 82f6a25..7bb5909 100644
--- a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc
+++ b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc
@@ -7,12 +7,11 @@
#include <string>
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "gfx/gtk_util.h"
@@ -111,8 +110,8 @@ PasswordStore* PasswordsExceptionsPageGtk::GetPasswordStore() {
void PasswordsExceptionsPageGtk::SetExceptionList(
const std::vector<webkit_glue::PasswordForm*>& result) {
- std::wstring languages = UTF8ToWide(
- profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ std::string languages =
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
gtk_list_store_clear(exception_list_store_);
STLDeleteElements(&exception_list_);
exception_list_ = result;
@@ -120,7 +119,7 @@ void PasswordsExceptionsPageGtk::SetExceptionList(
GtkTreeIter iter;
gtk_list_store_insert_with_values(exception_list_store_, &iter, (gint) i,
COL_SITE,
- WideToUTF8(net::FormatUrl(result[i]->origin, languages)).c_str(), -1);
+ UTF16ToUTF8(net::FormatUrl(result[i]->origin, languages)).c_str(), -1);
}
gtk_widget_set_sensitive(remove_all_button_, result.size() > 0);
}
diff --git a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h
index e2d2d41..c25060a 100644
--- a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h
+++ b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_PASSWORDS_EXCEPTIONS_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_PASSWORDS_EXCEPTIONS_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -19,7 +20,7 @@
class PasswordsExceptionsPageGtk {
public:
explicit PasswordsExceptionsPageGtk(Profile* profile);
- ~PasswordsExceptionsPageGtk();
+ virtual ~PasswordsExceptionsPageGtk();
GtkWidget* get_page_widget() const { return page_; }
diff --git a/chrome/browser/gtk/options/passwords_exceptions_window_gtk.h b/chrome/browser/gtk/options/passwords_exceptions_window_gtk.h
index 45aa8e0..1e5be39 100644
--- a/chrome/browser/gtk/options/passwords_exceptions_window_gtk.h
+++ b/chrome/browser/gtk/options/passwords_exceptions_window_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_PASSWORDS_EXCEPTIONS_WINDOW_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_PASSWORDS_EXCEPTIONS_WINDOW_GTK_H_
+#pragma once
class Profile;
diff --git a/chrome/browser/gtk/options/passwords_page_gtk.cc b/chrome/browser/gtk/options/passwords_page_gtk.cc
index 26fd572..af4d846 100644
--- a/chrome/browser/gtk/options/passwords_page_gtk.cc
+++ b/chrome/browser/gtk/options/passwords_page_gtk.cc
@@ -8,12 +8,13 @@
#include "app/gtk_util.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_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"
#include "gfx/gtk_util.h"
@@ -41,6 +42,9 @@ enum {
PasswordsPageGtk::PasswordsPageGtk(Profile* profile)
: populater(this), password_showing_(false), profile_(profile) {
+ allow_show_passwords_.Init(prefs::kPasswordManagerAllowShowPasswords,
+ profile->GetPrefs(),
+ this);
remove_button_ = gtk_button_new_with_label(
l10n_util::GetStringUTF8(IDS_PASSWORDS_PAGE_VIEW_REMOVE_BUTTON).c_str());
@@ -53,28 +57,18 @@ PasswordsPageGtk::PasswordsPageGtk(Profile* profile)
g_signal_connect(remove_all_button_, "clicked",
G_CALLBACK(OnRemoveAllButtonClickedThunk), this);
+ // We start with the "hide password" text but change it in the realize event.
show_password_button_ = gtk_button_new_with_label(
l10n_util::GetStringUTF8(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON).c_str());
- GtkRequisition hide_size, show_size;
- // Get the size request of the button with the "hide password" text.
- gtk_widget_size_request(show_password_button_, &hide_size);
- gtk_button_set_label(GTK_BUTTON(show_password_button_),
- l10n_util::GetStringUTF8(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON).c_str());
- // Get the size request of the button with the "show password" text.
- gtk_widget_size_request(show_password_button_, &show_size);
- // Determine the maximum width and height.
- if (hide_size.width > show_size.width)
- show_size.width = hide_size.width;
- if (hide_size.height > show_size.height)
- show_size.height = hide_size.height;
- // Force the button to be large enough for both labels.
- gtk_widget_set_size_request(show_password_button_, show_size.width,
- show_size.height);
+ gtk_widget_set_no_show_all(show_password_button_, true);
gtk_widget_set_sensitive(show_password_button_, FALSE);
g_signal_connect(show_password_button_, "clicked",
G_CALLBACK(OnShowPasswordButtonClickedThunk), this);
+ g_signal_connect(show_password_button_, "realize",
+ G_CALLBACK(OnShowPasswordButtonRealizedThunk), this);
password_ = gtk_label_new("");
+ gtk_widget_set_no_show_all(password_, true);
GtkWidget* buttons = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
gtk_box_pack_start(GTK_BOX(buttons), remove_button_, FALSE, FALSE, 0);
@@ -97,6 +91,9 @@ PasswordsPageGtk::PasswordsPageGtk(Profile* profile)
gtk_util::kContentAreaBorder);
gtk_box_pack_end(GTK_BOX(page_), buttons, FALSE, FALSE, 0);
gtk_box_pack_end(GTK_BOX(page_), scroll_window, TRUE, TRUE, 0);
+
+ // Initialize UI state based on current preference values.
+ OnPrefChanged(prefs::kPasswordManagerAllowShowPasswords);
}
PasswordsPageGtk::~PasswordsPageGtk() {
@@ -155,8 +152,8 @@ PasswordStore* PasswordsPageGtk::GetPasswordStore() {
void PasswordsPageGtk::SetPasswordList(
const std::vector<webkit_glue::PasswordForm*>& result) {
- std::wstring languages =
- UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ std::string languages =
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
gtk_list_store_clear(password_list_store_);
STLDeleteElements(&password_list_);
password_list_ = result;
@@ -164,12 +161,42 @@ void PasswordsPageGtk::SetPasswordList(
GtkTreeIter iter;
gtk_list_store_insert_with_values(password_list_store_, &iter, (gint) i,
COL_SITE,
- WideToUTF8(net::FormatUrl(result[i]->origin, languages)).c_str(),
+ UTF16ToUTF8(net::FormatUrl(result[i]->origin, languages)).c_str(),
COL_USERNAME, UTF16ToUTF8(result[i]->username_value).c_str(), -1);
}
gtk_widget_set_sensitive(remove_all_button_, result.size() > 0);
}
+void PasswordsPageGtk::HidePassword() {
+ password_showing_ = false;
+ gtk_label_set_text(GTK_LABEL(password_), "");
+ gtk_button_set_label(GTK_BUTTON(show_password_button_),
+ l10n_util::GetStringUTF8(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON).c_str());
+}
+
+void PasswordsPageGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
+ const std::string* pref_name = Details<std::string>(details).ptr();
+ OnPrefChanged(*pref_name);
+}
+
+void PasswordsPageGtk::OnPrefChanged(const std::string& pref_name) {
+ if (pref_name == prefs::kPasswordManagerAllowShowPasswords) {
+ if (allow_show_passwords_.GetValue()) {
+ gtk_widget_show(show_password_button_);
+ gtk_widget_show(password_);
+ } else {
+ HidePassword();
+ gtk_widget_hide(show_password_button_);
+ gtk_widget_hide(password_);
+ }
+ } else {
+ NOTREACHED();
+ }
+}
+
void PasswordsPageGtk::OnRemoveButtonClicked(GtkWidget* widget) {
GtkTreeIter iter;
if (!gtk_tree_selection_get_selected(password_selection_,
@@ -240,15 +267,13 @@ void PasswordsPageGtk::OnRemoveAllConfirmResponse(GtkWidget* confirm,
}
void PasswordsPageGtk::OnShowPasswordButtonClicked(GtkWidget* widget) {
- password_showing_ = !password_showing_;
- if (!password_showing_) {
+ if (password_showing_ || !allow_show_passwords_.GetValue()) {
// Hide the password.
- gtk_label_set_text(GTK_LABEL(password_), "");
- gtk_button_set_label(GTK_BUTTON(show_password_button_),
- l10n_util::GetStringUTF8(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON).c_str());
+ HidePassword();
return;
}
// Show the password.
+ password_showing_ = true;
GtkTreeIter iter;
if (!gtk_tree_selection_get_selected(password_selection_,
NULL, &iter)) {
@@ -266,12 +291,31 @@ void PasswordsPageGtk::OnShowPasswordButtonClicked(GtkWidget* widget) {
l10n_util::GetStringUTF8(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON).c_str());
}
-void PasswordsPageGtk::OnPasswordSelectionChanged(GtkTreeSelection* selection) {
- // No matter how the selection changed, we want to hide the old password.
- gtk_label_set_text(GTK_LABEL(password_), "");
+void PasswordsPageGtk::OnShowPasswordButtonRealized(GtkWidget* widget) {
+ // We have just realized the "show password" button, so we can now accurately
+ // find out how big it needs to be in order to accomodate both the "show" and
+ // "hide" labels. (This requires font information to work correctly.) The
+ // button starts with the "hide" label so we only have to change it once.
+ GtkRequisition hide_size, show_size;
+ // Get the size request of the button with the "hide password" text.
+ gtk_widget_size_request(show_password_button_, &hide_size);
gtk_button_set_label(GTK_BUTTON(show_password_button_),
l10n_util::GetStringUTF8(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON).c_str());
- password_showing_ = false;
+ // Get the size request of the button with the "show password" text.
+ gtk_widget_size_request(show_password_button_, &show_size);
+ // Determine the maximum width and height.
+ if (hide_size.width > show_size.width)
+ show_size.width = hide_size.width;
+ if (hide_size.height > show_size.height)
+ show_size.height = hide_size.height;
+ // Force the button to be large enough for both labels.
+ gtk_widget_set_size_request(show_password_button_, show_size.width,
+ show_size.height);
+}
+
+void PasswordsPageGtk::OnPasswordSelectionChanged(GtkTreeSelection* selection) {
+ // No matter how the selection changed, we want to hide the old password.
+ HidePassword();
GtkTreeIter iter;
if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
diff --git a/chrome/browser/gtk/options/passwords_page_gtk.h b/chrome/browser/gtk/options/passwords_page_gtk.h
index 328ce35..8d81689 100644
--- a/chrome/browser/gtk/options/passwords_page_gtk.h
+++ b/chrome/browser/gtk/options/passwords_page_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_PASSWORDS_PAGE_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_PASSWORDS_PAGE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,12 +12,14 @@
#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 PasswordsPageGtk {
+class PasswordsPageGtk : public NotificationObserver {
public:
explicit PasswordsPageGtk(Profile* profile);
- ~PasswordsPageGtk();
+ virtual ~PasswordsPageGtk();
GtkWidget* get_page_widget() const { return page_; }
@@ -31,10 +34,22 @@ class PasswordsPageGtk {
// the PasswordForms in the vector.
void SetPasswordList(const std::vector<webkit_glue::PasswordForm*>& result);
+ // Helper that hides the password.
+ void HidePassword();
+
+ // NotificationObserver implementation.
+ 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);
+
CHROMEGTK_CALLBACK_0(PasswordsPageGtk, void, OnRemoveButtonClicked);
CHROMEGTK_CALLBACK_0(PasswordsPageGtk, void, OnRemoveAllButtonClicked);
CHROMEGTK_CALLBACK_1(PasswordsPageGtk, void, OnRemoveAllConfirmResponse, int);
CHROMEGTK_CALLBACK_0(PasswordsPageGtk, void, OnShowPasswordButtonClicked);
+ CHROMEGTK_CALLBACK_0(PasswordsPageGtk, void, OnShowPasswordButtonRealized);
CHROMEG_CALLBACK_0(PasswordsPageGtk, void, OnPasswordSelectionChanged,
GtkTreeSelection*);
@@ -89,6 +104,7 @@ class PasswordsPageGtk {
GtkWidget* page_;
Profile* profile_;
+ BooleanPrefMember allow_show_passwords_;
std::vector<webkit_glue::PasswordForm*> password_list_;
DISALLOW_COPY_AND_ASSIGN(PasswordsPageGtk);
diff --git a/chrome/browser/gtk/options/simple_content_exceptions_window.cc b/chrome/browser/gtk/options/simple_content_exceptions_window.cc
index f38b3ed..68c211a 100644
--- a/chrome/browser/gtk/options/simple_content_exceptions_window.cc
+++ b/chrome/browser/gtk/options/simple_content_exceptions_window.cc
@@ -17,6 +17,11 @@ namespace {
// Singleton for exception window.
SimpleContentExceptionsWindow* instance = NULL;
+enum {
+ COL_ACTION = gtk_tree::TableAdapter::COL_LAST_ID,
+ COL_COUNT
+};
+
} // namespace
// static
@@ -36,18 +41,35 @@ void SimpleContentExceptionsWindow::ShowExceptionsWindow(
SimpleContentExceptionsWindow::SimpleContentExceptionsWindow(
GtkWindow* parent,
RemoveRowsTableModel* model,
- int title_message_id) {
+ int title_message_id)
+ : ignore_selection_changes_(false) {
// Build the model adapters that translate views and TableModels into
// something GTK can use.
- list_store_ = gtk_list_store_new(COL_COUNT, G_TYPE_STRING, G_TYPE_STRING);
+ list_store_ = gtk_list_store_new(COL_COUNT,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING);
treeview_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_));
g_object_unref(list_store_);
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_), TRUE);
+ gtk_tree_view_set_row_separator_func(
+ GTK_TREE_VIEW(treeview_),
+ gtk_tree::TableAdapter::OnCheckRowIsSeparator,
+ NULL,
+ NULL);
+
// Set up the properties of the treeview
GtkTreeViewColumn* hostname_column = gtk_tree_view_column_new_with_attributes(
l10n_util::GetStringUTF8(IDS_EXCEPTIONS_HOSTNAME_HEADER).c_str(),
gtk_cell_renderer_text_new(),
- "text", COL_HOSTNAME,
+ "text", gtk_tree::TableAdapter::COL_TITLE,
+ "weight", gtk_tree::TableAdapter::COL_WEIGHT,
+ "weight-set", gtk_tree::TableAdapter::COL_WEIGHT_SET,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_), hostname_column);
@@ -61,6 +83,11 @@ SimpleContentExceptionsWindow::SimpleContentExceptionsWindow(
treeview_selection_ = gtk_tree_view_get_selection(
GTK_TREE_VIEW(treeview_));
gtk_tree_selection_set_mode(treeview_selection_, GTK_SELECTION_MULTIPLE);
+ gtk_tree_selection_set_select_function(
+ treeview_selection_,
+ gtk_tree::TableAdapter::OnSelectionFilter,
+ NULL,
+ NULL);
g_signal_connect(treeview_selection_, "changed",
G_CALLBACK(OnTreeSelectionChangedThunk), this);
@@ -127,9 +154,9 @@ SimpleContentExceptionsWindow::SimpleContentExceptionsWindow(
}
void SimpleContentExceptionsWindow::SetColumnValues(int row,
- GtkTreeIter* iter) {
+ GtkTreeIter* iter) {
std::wstring hostname = model_->GetText(row, IDS_EXCEPTIONS_HOSTNAME_HEADER);
- gtk_list_store_set(list_store_, iter, COL_HOSTNAME,
+ gtk_list_store_set(list_store_, iter, gtk_tree::TableAdapter::COL_TITLE,
WideToUTF8(hostname).c_str(), -1);
std::wstring action = model_->GetText(row, IDS_EXCEPTIONS_ACTION_HEADER);
@@ -137,27 +164,31 @@ void SimpleContentExceptionsWindow::SetColumnValues(int row,
WideToUTF8(action).c_str(), -1);
}
+void SimpleContentExceptionsWindow::OnAnyModelUpdateStart() {
+ ignore_selection_changes_ = true;
+}
+
+void SimpleContentExceptionsWindow::OnAnyModelUpdate() {
+ ignore_selection_changes_ = false;
+}
+
void SimpleContentExceptionsWindow::UpdateButtonState() {
int row_count = gtk_tree_model_iter_n_children(
GTK_TREE_MODEL(list_store_), NULL);
RemoveRowsTableModel::Rows rows;
- GetSelectedRows(&rows);
- gtk_widget_set_sensitive(remove_button_, model_->CanRemoveRows(rows));
- gtk_widget_set_sensitive(remove_all_button_, row_count > 0);
-}
-
-void SimpleContentExceptionsWindow::GetSelectedRows(
- RemoveRowsTableModel::Rows* rows) {
std::set<int> indices;
gtk_tree::GetSelectedIndices(treeview_selection_, &indices);
- for (std::set<int>::iterator i = indices.begin(); i != indices.end(); ++i)
- rows->insert(*i);
+ model_adapter_->MapListStoreIndicesToModelRows(indices, &rows);
+ gtk_widget_set_sensitive(remove_button_, model_->CanRemoveRows(rows));
+ gtk_widget_set_sensitive(remove_all_button_, row_count > 0);
}
void SimpleContentExceptionsWindow::Remove(GtkWidget* widget) {
RemoveRowsTableModel::Rows rows;
- GetSelectedRows(&rows);
+ std::set<int> indices;
+ gtk_tree::GetSelectedIndices(treeview_selection_, &indices);
+ model_adapter_->MapListStoreIndicesToModelRows(indices, &rows);
model_->RemoveRows(rows);
UpdateButtonState();
}
@@ -174,5 +205,6 @@ void SimpleContentExceptionsWindow::OnWindowDestroy(GtkWidget* widget) {
void SimpleContentExceptionsWindow::OnTreeSelectionChanged(
GtkWidget* selection) {
- UpdateButtonState();
+ if (!ignore_selection_changes_)
+ UpdateButtonState();
}
diff --git a/chrome/browser/gtk/options/simple_content_exceptions_window.h b/chrome/browser/gtk/options/simple_content_exceptions_window.h
index 12700bd..c18dab1 100644
--- a/chrome/browser/gtk/options/simple_content_exceptions_window.h
+++ b/chrome/browser/gtk/options/simple_content_exceptions_window.h
@@ -4,11 +4,10 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_SIMPLE_CONTENT_EXCEPTIONS_WINDOW_H_
#define CHROME_BROWSER_GTK_OPTIONS_SIMPLE_CONTENT_EXCEPTIONS_WINDOW_H_
+#pragma once
#include <gtk/gtk.h>
-#include <set>
-
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/gtk_tree.h"
@@ -26,15 +25,10 @@ class SimpleContentExceptionsWindow
// gtk_tree::TableAdapter::Delegate implementation:
virtual void SetColumnValues(int row, GtkTreeIter* iter);
+ virtual void OnAnyModelUpdateStart();
+ virtual void OnAnyModelUpdate();
private:
- // Column ids for |list_store_|.
- enum {
- COL_HOSTNAME,
- COL_ACTION,
- COL_COUNT
- };
-
// Takes ownership of |model|.
SimpleContentExceptionsWindow(GtkWindow* parent,
RemoveRowsTableModel* model,
@@ -43,8 +37,6 @@ class SimpleContentExceptionsWindow
// Updates which buttons are enabled.
void UpdateButtonState();
- void GetSelectedRows(RemoveRowsTableModel::Rows* rows);
-
// Callbacks for the buttons.
CHROMEGTK_CALLBACK_0(SimpleContentExceptionsWindow, void, Remove);
CHROMEGTK_CALLBACK_0(SimpleContentExceptionsWindow, void, RemoveAll);
@@ -74,6 +66,10 @@ class SimpleContentExceptionsWindow
// The current user selection from |treeview_|.
GtkTreeSelection* treeview_selection_;
+ // Whether to ignore selection changes. This is set during model updates,
+ // when the list store may be inconsistent with the table model.
+ bool ignore_selection_changes_;
+
// Buttons.
GtkWidget* remove_button_;
GtkWidget* remove_all_button_;
diff --git a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc
index 5298a1d..30059ba 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/gtk/options/url_picker_dialog_gtk.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/possible_url_model.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "gfx/gtk_util.h"
@@ -23,6 +23,7 @@
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "net/base/net_util.h"
+#include "third_party/skia/include/core/SkBitmap.h"
namespace {
@@ -195,15 +196,14 @@ std::string UrlPickerDialogGtk::GetURLForPath(GtkTreePath* path) const {
NOTREACHED();
return std::string();
}
- std::wstring languages =
- UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ std::string languages =
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
// Because this gets parsed by FixupURL(), it's safe to omit the scheme or
// trailing slash, and unescape most characters, but we need to not drop any
// username/password, or unescape anything that changes the meaning.
- std::wstring formatted = net::FormatUrl(url_table_model_->GetURL(row),
+ return UTF16ToUTF8(net::FormatUrl(url_table_model_->GetURL(row),
languages, net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword,
- UnescapeRule::SPACES, NULL, NULL, NULL);
- return WideToUTF8(formatted);
+ UnescapeRule::SPACES, NULL, NULL, NULL));
}
void UrlPickerDialogGtk::SetColumnValues(int row, GtkTreeIter* iter) {
diff --git a/chrome/browser/gtk/options/url_picker_dialog_gtk.h b/chrome/browser/gtk/options/url_picker_dialog_gtk.h
index ed2d4a0..6c4429b 100644
--- a/chrome/browser/gtk/options/url_picker_dialog_gtk.h
+++ b/chrome/browser/gtk/options/url_picker_dialog_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_OPTIONS_URL_PICKER_DIALOG_GTK_H_
#define CHROME_BROWSER_GTK_OPTIONS_URL_PICKER_DIALOG_GTK_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/gtk/overflow_button.h b/chrome/browser/gtk/overflow_button.h
index 5362e6b..647221e 100644
--- a/chrome/browser/gtk/overflow_button.h
+++ b/chrome/browser/gtk/overflow_button.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_GTK_OVERFLOW_BUTTON_H_
#define CHROME_BROWSER_GTK_OVERFLOW_BUTTON_H_
+#pragma once
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
typedef struct _GtkWidget GtkWidget;
class Profile;
diff --git a/chrome/browser/gtk/page_info_window_gtk.cc b/chrome/browser/gtk/page_info_window_gtk.cc
index ceefbe2..9eaa63e 100644
--- a/chrome/browser/gtk/page_info_window_gtk.cc
+++ b/chrome/browser/gtk/page_info_window_gtk.cc
@@ -149,16 +149,17 @@ GtkWidget* PageInfoWindowGtk::CreateSection(
GtkWidget* section_box = gtk_hbox_new(FALSE, 0);
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- GtkWidget* image = gtk_image_new_from_pixbuf(section.state ?
+ GtkWidget* image = gtk_image_new_from_pixbuf(
+ section.state == PageInfoModel::SECTION_STATE_OK ?
rb.GetPixbufNamed(IDR_PAGEINFO_GOOD) :
- rb.GetPixbufNamed(IDR_PAGEINFO_BAD));
+ rb.GetPixbufNamed(IDR_PAGEINFO_WARNING_MAJOR));
gtk_box_pack_start(GTK_BOX(section_box), image, FALSE, FALSE,
gtk_util::kControlSpacing);
gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
GtkWidget* text_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
- if (!section.head_line.empty()) {
- label = gtk_label_new(UTF16ToUTF8(section.head_line).c_str());
+ if (!section.headline.empty()) {
+ label = gtk_label_new(UTF16ToUTF8(section.headline).c_str());
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_box_pack_start(GTK_BOX(text_box), label, FALSE, FALSE, 0);
}
diff --git a/chrome/browser/gtk/process_singleton_dialog.h b/chrome/browser/gtk/process_singleton_dialog.h
index fa303e2..ec9641e 100644
--- a/chrome/browser/gtk/process_singleton_dialog.h
+++ b/chrome/browser/gtk/process_singleton_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_PROCESS_SINGLETON_DIALOG_H_
#define CHROME_BROWSER_GTK_PROCESS_SINGLETON_DIALOG_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/gtk/reload_button_gtk.cc b/chrome/browser/gtk/reload_button_gtk.cc
index 8e3cb8f..e5e8857 100644
--- a/chrome/browser/gtk/reload_button_gtk.cc
+++ b/chrome/browser/gtk/reload_button_gtk.cc
@@ -31,26 +31,22 @@ ReloadButtonGtk::ReloadButtonGtk(LocationBarViewGtk* location_bar,
visible_mode_(MODE_RELOAD),
theme_provider_(browser ?
GtkThemeProvider::GetFrom(browser->profile()) : NULL),
- reload_(theme_provider_, IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0,
- IDR_BUTTON_MASK),
- stop_(theme_provider_, IDR_STOP, IDR_STOP_P, IDR_STOP_H, 0,
- IDR_BUTTON_MASK),
+ reload_(theme_provider_, IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0),
+ stop_(theme_provider_, IDR_STOP, IDR_STOP_P, IDR_STOP_H, IDR_STOP_D),
widget_(gtk_chrome_button_new()) {
- gtk_widget_set_size_request(widget_.get(), reload_.Width(), reload_.Height());
+ gtk_widget_set_size_request(widget(), reload_.Width(), reload_.Height());
- gtk_widget_set_app_paintable(widget_.get(), TRUE);
+ gtk_widget_set_app_paintable(widget(), TRUE);
- g_signal_connect(widget_.get(), "expose-event",
- G_CALLBACK(OnExposeThunk), this);
- g_signal_connect(widget_.get(), "leave-notify-event",
+ g_signal_connect(widget(), "clicked", G_CALLBACK(OnClickedThunk), this);
+ g_signal_connect(widget(), "expose-event", G_CALLBACK(OnExposeThunk), this);
+ g_signal_connect(widget(), "leave-notify-event",
G_CALLBACK(OnLeaveNotifyThunk), this);
- g_signal_connect(widget_.get(), "clicked",
- G_CALLBACK(OnClickedThunk), this);
- GTK_WIDGET_UNSET_FLAGS(widget_.get(), GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS(widget(), GTK_CAN_FOCUS);
- gtk_widget_set_has_tooltip(widget_.get(), TRUE);
- g_signal_connect(widget_.get(), "query-tooltip",
- G_CALLBACK(OnQueryTooltipThunk), this);
+ gtk_widget_set_has_tooltip(widget(), TRUE);
+ g_signal_connect(widget(), "query-tooltip", G_CALLBACK(OnQueryTooltipThunk),
+ this);
hover_controller_.Init(widget());
gtk_util::SetButtonTriggersNavigation(widget());
@@ -78,8 +74,30 @@ void ReloadButtonGtk::ChangeMode(Mode mode, bool force) {
!timer_running() : (visible_mode_ != MODE_STOP))) {
timer_.Stop();
visible_mode_ = mode;
- gtk_widget_queue_draw(widget_.get());
+ stop_.set_paint_override(-1);
+ gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(widget_.get()));
+
+ UpdateThemeButtons();
+ gtk_widget_queue_draw(widget());
+ } else if (visible_mode_ != MODE_RELOAD) {
+ // If you read the views implementation of reload_button.cc, you'll see
+ // that instead of screwing with paint states, the views implementation
+ // just changes whether the view is enabled. We can't do that here because
+ // changing the widget state to GTK_STATE_INSENSITIVE will cause a cascade
+ // of messages on all its children and will also trigger a synthesized
+ // leave notification and prevent the real leave notification from turning
+ // the button back to normal. So instead, override the stop_ paint state
+ // for chrome-theme mode, and use this as a flag to discard click events.
+ stop_.set_paint_override(GTK_STATE_INSENSITIVE);
+
+ // Also set the gtk_chrome_button paint state to insensitive to hide
+ // the border drawn around the stop icon.
+ gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget_.get()),
+ GTK_STATE_INSENSITIVE);
+
+ // If we're in GTK theme mode, we need to also render the correct icon for
+ // the stop/insensitive since we won't be using |stop_| to render the icon.
UpdateThemeButtons();
}
}
@@ -97,25 +115,16 @@ void ReloadButtonGtk::Observe(NotificationType type,
}
void ReloadButtonGtk::OnButtonTimer() {
- ChangeMode(intended_mode_, true);
-}
-
-gboolean ReloadButtonGtk::OnExpose(GtkWidget* widget,
- GdkEventExpose* e) {
- if (theme_provider_ && theme_provider_->UseGtkTheme())
- return FALSE;
- return ((visible_mode_ == MODE_RELOAD) ? reload_ : stop_).OnExpose(
- widget, e, hover_controller_.GetCurrentValue());
-}
-
-gboolean ReloadButtonGtk::OnLeaveNotify(GtkWidget* widget,
- GdkEventCrossing* event) {
- ChangeMode(intended_mode_, true);
- return FALSE;
+ ChangeMode(intended_mode_, false);
}
void ReloadButtonGtk::OnClicked(GtkWidget* sender) {
if (visible_mode_ == MODE_STOP) {
+ // The stop button is disabled because the user hovered over the button
+ // until the stop action is no longer selectable.
+ if (stop_.paint_override() == GTK_STATE_INSENSITIVE)
+ return;
+
if (browser_)
browser_->Stop();
@@ -129,11 +138,10 @@ void ReloadButtonGtk::OnClicked(GtkWidget* sender) {
GdkModifierType modifier_state;
gtk_get_current_event_state(&modifier_state);
guint modifier_state_uint = modifier_state;
- if (modifier_state_uint & GDK_SHIFT_MASK) {
+ if (modifier_state_uint & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) {
command = IDC_RELOAD_IGNORING_CACHE;
- // Mask off shift so it isn't interpreted as affecting the disposition
- // below.
- modifier_state_uint &= ~GDK_SHIFT_MASK;
+ // Mask off Shift and Control so they don't affect the disposition below.
+ modifier_state_uint &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
} else {
command = IDC_RELOAD;
}
@@ -147,9 +155,6 @@ void ReloadButtonGtk::OnClicked(GtkWidget* sender) {
location_bar_->Revert();
}
- if (browser_)
- browser_->ExecuteCommandWithDisposition(command, disposition);
-
// Figure out the system double-click time.
if (button_delay_ == 0) {
GtkSettings* settings = gtk_settings_get_default();
@@ -157,18 +162,34 @@ void ReloadButtonGtk::OnClicked(GtkWidget* sender) {
NULL);
}
- // Stop the timer.
- timer_.Stop();
-
// Start a timer - while this timer is running, the reload button cannot be
// changed to a stop button. We do not set |intended_mode_| to MODE_STOP
- // here as we want to wait for the browser to tell us that it has started
- // loading (and this may occur only after some delay).
+ // here as the browser will do that when it actually starts loading (which
+ // may happen synchronously, thus the need to do this before telling the
+ // browser to execute the reload command).
+ timer_.Stop();
timer_.Start(base::TimeDelta::FromMilliseconds(button_delay_), this,
&ReloadButtonGtk::OnButtonTimer);
+
+ if (browser_)
+ browser_->ExecuteCommandWithDisposition(command, disposition);
}
}
+gboolean ReloadButtonGtk::OnExpose(GtkWidget* widget,
+ GdkEventExpose* e) {
+ if (theme_provider_ && theme_provider_->UseGtkTheme())
+ return FALSE;
+ return ((visible_mode_ == MODE_RELOAD) ? reload_ : stop_).OnExpose(
+ widget, e, hover_controller_.GetCurrentValue());
+}
+
+gboolean ReloadButtonGtk::OnLeaveNotify(GtkWidget* widget,
+ GdkEventCrossing* event) {
+ ChangeMode(intended_mode_, true);
+ return FALSE;
+}
+
gboolean ReloadButtonGtk::OnQueryTooltip(GtkWidget* sender,
gint x,
gint y,
@@ -188,31 +209,47 @@ void ReloadButtonGtk::UpdateThemeButtons() {
bool use_gtk = theme_provider_ && theme_provider_->UseGtkTheme();
if (use_gtk) {
- GdkPixbuf* pixbuf = gtk_widget_render_icon(widget(),
- (intended_mode_ == MODE_RELOAD) ? GTK_STOCK_REFRESH : GTK_STOCK_STOP,
- GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
-
- gtk_button_set_image(GTK_BUTTON(widget_.get()),
- gtk_image_new_from_pixbuf(pixbuf));
- g_object_unref(pixbuf);
+ gtk_widget_ensure_style(widget());
+ GtkIconSet* icon_set = gtk_style_lookup_icon_set(
+ widget()->style,
+ (visible_mode_ == MODE_RELOAD) ? GTK_STOCK_REFRESH : GTK_STOCK_STOP);
+ if (icon_set) {
+ GtkStateType state = static_cast<GtkStateType>(
+ GTK_WIDGET_STATE(widget()));
+ if (visible_mode_ == MODE_STOP && stop_.paint_override() != -1)
+ state = static_cast<GtkStateType>(stop_.paint_override());
+
+ GdkPixbuf* pixbuf = gtk_icon_set_render_icon(
+ icon_set,
+ widget()->style,
+ gtk_widget_get_direction(widget()),
+ state,
+ GTK_ICON_SIZE_SMALL_TOOLBAR,
+ widget(),
+ NULL);
+
+ gtk_button_set_image(GTK_BUTTON(widget()),
+ gtk_image_new_from_pixbuf(pixbuf));
+ g_object_unref(pixbuf);
+ }
- gtk_widget_set_size_request(widget_.get(), -1, -1);
+ gtk_widget_set_size_request(widget(), -1, -1);
GtkRequisition req;
gtk_widget_size_request(widget(), &req);
GtkButtonWidth = std::max(GtkButtonWidth, req.width);
- gtk_widget_set_size_request(widget_.get(), GtkButtonWidth, -1);
+ gtk_widget_set_size_request(widget(), GtkButtonWidth, -1);
- gtk_widget_set_app_paintable(widget_.get(), FALSE);
- gtk_widget_set_double_buffered(widget_.get(), TRUE);
+ gtk_widget_set_app_paintable(widget(), FALSE);
+ gtk_widget_set_double_buffered(widget(), TRUE);
} else {
- gtk_widget_set_size_request(widget_.get(), reload_.Width(),
- reload_.Height());
+ gtk_button_set_image(GTK_BUTTON(widget()), NULL);
+
+ gtk_widget_set_size_request(widget(), reload_.Width(), reload_.Height());
- gtk_widget_set_app_paintable(widget_.get(), TRUE);
+ gtk_widget_set_app_paintable(widget(), TRUE);
// We effectively double-buffer by virtue of having only one image...
- gtk_widget_set_double_buffered(widget_.get(), FALSE);
+ gtk_widget_set_double_buffered(widget(), FALSE);
}
- gtk_chrome_button_set_use_gtk_rendering(
- GTK_CHROME_BUTTON(widget_.get()), use_gtk);
+ gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(widget()), use_gtk);
}
diff --git a/chrome/browser/gtk/reload_button_gtk.h b/chrome/browser/gtk/reload_button_gtk.h
index 6cc3a13..2a152a4 100644
--- a/chrome/browser/gtk/reload_button_gtk.h
+++ b/chrome/browser/gtk/reload_button_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_RELOAD_BUTTON_GTK_H_
#define CHROME_BROWSER_GTK_RELOAD_BUTTON_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,9 +12,9 @@
#include "base/basictypes.h"
#include "base/timer.h"
#include "chrome/browser/gtk/custom_button.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class Browser;
class GtkThemeProvider;
@@ -41,10 +42,10 @@ class ReloadButtonGtk : public NotificationObserver {
private:
friend class ReloadButtonGtkPeer;
+ CHROMEGTK_CALLBACK_0(ReloadButtonGtk, void, OnClicked);
CHROMEGTK_CALLBACK_1(ReloadButtonGtk, gboolean, OnExpose, GdkEventExpose*);
CHROMEGTK_CALLBACK_1(ReloadButtonGtk, gboolean, OnLeaveNotify,
GdkEventCrossing*);
- CHROMEGTK_CALLBACK_0(ReloadButtonGtk, void, OnClicked);
CHROMEGTK_CALLBACK_4(ReloadButtonGtk, gboolean, OnQueryTooltip, gint, gint,
gboolean, GtkTooltip*);
diff --git a/chrome/browser/gtk/repost_form_warning_gtk.cc b/chrome/browser/gtk/repost_form_warning_gtk.cc
index 815c1ea..a53aef4 100644
--- a/chrome/browser/gtk/repost_form_warning_gtk.cc
+++ b/chrome/browser/gtk/repost_form_warning_gtk.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/gtk/repost_form_warning_gtk.h"
-#include "app/gtk_util.h"
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "chrome/browser/gtk/gtk_util.h"
@@ -89,4 +88,3 @@ void RepostFormWarningGtk::OnHierarchyChanged(GtkWidget* root,
}
gtk_widget_grab_focus(cancel_);
}
-
diff --git a/chrome/browser/gtk/repost_form_warning_gtk.h b/chrome/browser/gtk/repost_form_warning_gtk.h
index 149216b..6b0f982 100644
--- a/chrome/browser/gtk/repost_form_warning_gtk.h
+++ b/chrome/browser/gtk/repost_form_warning_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_REPOST_FORM_WARNING_GTK_H_
#define CHROME_BROWSER_GTK_REPOST_FORM_WARNING_GTK_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/rounded_window.cc b/chrome/browser/gtk/rounded_window.cc
index 053f9ad..f0d827d 100644
--- a/chrome/browser/gtk/rounded_window.cc
+++ b/chrome/browser/gtk/rounded_window.cc
@@ -7,9 +7,9 @@
#include <gtk/gtk.h>
#include <math.h>
-#include "app/gtk_signal.h"
#include "app/gtk_signal_registrar.h"
#include "base/i18n/rtl.h"
+#include "base/logging.h"
#include "chrome/browser/gtk/gtk_util.h"
namespace gtk_util {
diff --git a/chrome/browser/gtk/rounded_window.h b/chrome/browser/gtk/rounded_window.h
index 7f2c584..d1788f8 100644
--- a/chrome/browser/gtk/rounded_window.h
+++ b/chrome/browser/gtk/rounded_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_ROUNDED_WINDOW_H_
#define CHROME_BROWSER_GTK_ROUNDED_WINDOW_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/sad_tab_gtk.h b/chrome/browser/gtk/sad_tab_gtk.h
index 283f4d5..9c5489b 100644
--- a/chrome/browser/gtk/sad_tab_gtk.h
+++ b/chrome/browser/gtk/sad_tab_gtk.h
@@ -4,18 +4,19 @@
#ifndef CHROME_BROWSER_GTK_SAD_TAB_GTK_H_
#define CHROME_BROWSER_GTK_SAD_TAB_GTK_H_
+#pragma once
typedef struct _GtkWidget GtkWidget;
#include "app/gtk_signal.h"
-#include "chrome/common/owned_widget_gtk.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
class TabContents;
class SadTabGtk {
public:
explicit SadTabGtk(TabContents* tab_contents);
- ~SadTabGtk();
+ virtual ~SadTabGtk();
GtkWidget* widget() const { return event_box_.get(); }
diff --git a/chrome/browser/gtk/slide_animator_gtk.cc b/chrome/browser/gtk/slide_animator_gtk.cc
index ff20c40..0534a7c 100644
--- a/chrome/browser/gtk/slide_animator_gtk.cc
+++ b/chrome/browser/gtk/slide_animator_gtk.cc
@@ -6,7 +6,6 @@
#include "app/animation.h"
#include "app/slide_animation.h"
-#include "base/logging.h"
#include "chrome/browser/gtk/gtk_expanded_container.h"
diff --git a/chrome/browser/gtk/slide_animator_gtk.h b/chrome/browser/gtk/slide_animator_gtk.h
index 799816c..df6d29b 100644
--- a/chrome/browser/gtk/slide_animator_gtk.h
+++ b/chrome/browser/gtk/slide_animator_gtk.h
@@ -13,12 +13,13 @@
#ifndef CHROME_BROWSER_GTK_SLIDE_ANIMATOR_GTK_H_
#define CHROME_BROWSER_GTK_SLIDE_ANIMATOR_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include "app/animation.h"
#include "base/scoped_ptr.h"
-#include "chrome/common/owned_widget_gtk.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
class SlideAnimation;
diff --git a/chrome/browser/gtk/ssl_client_certificate_selector.cc b/chrome/browser/gtk/ssl_client_certificate_selector.cc
index b7c3f5f..987e51a 100644
--- a/chrome/browser/gtk/ssl_client_certificate_selector.cc
+++ b/chrome/browser/gtk/ssl_client_certificate_selector.cc
@@ -10,14 +10,18 @@
#include <string>
#include <vector>
+#include "app/gtk_signal.h"
#include "app/l10n_util.h"
#include "base/i18n/time_formatting.h"
#include "base/logging.h"
#include "base/nss_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/certificate_viewer.h"
+#include "chrome/browser/gtk/constrained_window_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
#include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
@@ -34,68 +38,70 @@ enum {
RESPONSE_SHOW_CERT_INFO = 1,
};
-
///////////////////////////////////////////////////////////////////////////////
// SSLClientCertificateSelector
-class SSLClientCertificateSelector {
+class SSLClientCertificateSelector : public ConstrainedDialogDelegate {
public:
- SSLClientCertificateSelector(gfx::NativeWindow parent,
- net::SSLCertRequestInfo* cert_request_info,
- SSLClientAuthHandler* delegate);
+ explicit SSLClientCertificateSelector(
+ TabContents* parent,
+ net::SSLCertRequestInfo* cert_request_info,
+ SSLClientAuthHandler* delegate);
+ ~SSLClientCertificateSelector();
void Show();
+ // ConstrainedDialogDelegate implementation:
+ virtual GtkWidget* GetWidgetRoot() { return root_widget_.get(); }
+ virtual void DeleteDelegate() { delete this; }
+
private:
void PopulateCerts();
+ net::X509Certificate* GetSelectedCert();
+
static std::string FormatComboBoxText(CERTCertificate* cert,
const char* nickname);
static std::string FormatDetailsText(CERTCertificate* cert);
- static void OnComboBoxChanged(GtkComboBox* combo_box,
- SSLClientCertificateSelector* cert_selector);
- static void OnResponse(GtkDialog* dialog, gint response_id,
- SSLClientCertificateSelector* cert_selector);
- static void OnDestroy(GtkDialog* dialog,
- SSLClientCertificateSelector* cert_selector);
+ CHROMEGTK_CALLBACK_0(SSLClientCertificateSelector, void, OnComboBoxChanged);
+ CHROMEGTK_CALLBACK_0(SSLClientCertificateSelector, void, OnViewClicked);
+ CHROMEGTK_CALLBACK_0(SSLClientCertificateSelector, void, OnCancelClicked);
+ CHROMEGTK_CALLBACK_0(SSLClientCertificateSelector, void, OnOkClicked);
+ CHROMEGTK_CALLBACK_1(SSLClientCertificateSelector, void, OnPromptShown,
+ GtkWidget*);
- scoped_refptr<SSLClientAuthHandler> delegate_;
scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
std::vector<std::string> details_strings_;
- GtkWidget* dialog_;
GtkWidget* cert_combo_box_;
GtkTextBuffer* cert_details_buffer_;
+
+ scoped_refptr<SSLClientAuthHandler> delegate_;
+
+ OwnedWidgetGtk root_widget_;
+ // Hold on to the select button to focus it.
+ GtkWidget* select_button_;
+
+ TabContents* parent_;
+ ConstrainedWindow* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLClientCertificateSelector);
};
SSLClientCertificateSelector::SSLClientCertificateSelector(
- gfx::NativeWindow parent,
+ TabContents* parent,
net::SSLCertRequestInfo* cert_request_info,
SSLClientAuthHandler* delegate)
- : delegate_(delegate),
- cert_request_info_(cert_request_info) {
- dialog_ = gtk_dialog_new_with_buttons(
- l10n_util::GetStringFUTF8(
- IDS_CERT_SELECTOR_DIALOG_TITLE,
- UTF8ToUTF16(cert_request_info->host_and_port)).c_str(),
- parent,
- // Non-modal.
- GTK_DIALOG_NO_SEPARATOR,
- l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str(),
- RESPONSE_SHOW_CERT_INFO,
- GTK_STOCK_CANCEL,
- GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK,
- GTK_RESPONSE_OK,
- NULL);
- gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
- gtk_util::kContentAreaSpacing);
- gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK);
+ : cert_request_info_(cert_request_info),
+ delegate_(delegate),
+ parent_(parent),
+ window_(NULL) {
+ root_widget_.Own(gtk_vbox_new(FALSE, gtk_util::kControlSpacing));
GtkWidget* site_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), site_vbox,
+ gtk_box_pack_start(GTK_BOX(root_widget_.get()), site_vbox,
FALSE, FALSE, 0);
GtkWidget* site_description_label = gtk_util::CreateBoldLabel(
@@ -109,7 +115,7 @@ SSLClientCertificateSelector::SSLClientCertificateSelector(
gtk_box_pack_start(GTK_BOX(site_vbox), site_label, FALSE, FALSE, 0);
GtkWidget* selector_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), selector_vbox,
+ gtk_box_pack_start(GTK_BOX(root_widget_.get()), selector_vbox,
TRUE, TRUE, 0);
GtkWidget* choose_description_label = gtk_util::CreateBoldLabel(
@@ -119,8 +125,8 @@ SSLClientCertificateSelector::SSLClientCertificateSelector(
cert_combo_box_ = gtk_combo_box_new_text();
- g_signal_connect(cert_combo_box_, "changed", G_CALLBACK(OnComboBoxChanged),
- this);
+ g_signal_connect(cert_combo_box_, "changed",
+ G_CALLBACK(OnComboBoxChangedThunk), this);
gtk_box_pack_start(GTK_BOX(selector_vbox), cert_combo_box_,
FALSE, FALSE, 0);
@@ -144,14 +150,44 @@ SSLClientCertificateSelector::SSLClientCertificateSelector(
gtk_container_add(GTK_CONTAINER(details_frame), cert_details_view);
gtk_box_pack_start(GTK_BOX(selector_vbox), details_frame, TRUE, TRUE, 0);
+ // And then create a set of buttons like a GtkDialog would.
+ GtkWidget* button_box = gtk_hbutton_box_new();
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(button_box), gtk_util::kControlSpacing);
+ gtk_box_pack_end(GTK_BOX(root_widget_.get()), button_box, FALSE, FALSE, 0);
+
+ GtkWidget* view_button = gtk_button_new_with_mnemonic(
+ l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str());
+ gtk_box_pack_start(GTK_BOX(button_box), view_button, FALSE, FALSE, 0);
+ g_signal_connect(view_button, "clicked",
+ G_CALLBACK(OnViewClickedThunk), this);
+
+ GtkWidget* cancel_button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ gtk_box_pack_end(GTK_BOX(button_box), cancel_button, FALSE, FALSE, 0);
+ g_signal_connect(cancel_button, "clicked",
+ G_CALLBACK(OnCancelClickedThunk), this);
+
+ GtkWidget* select_button = gtk_button_new_from_stock(GTK_STOCK_OK);
+ gtk_box_pack_end(GTK_BOX(button_box), select_button, FALSE, FALSE, 0);
+ g_signal_connect(select_button, "clicked",
+ G_CALLBACK(OnOkClickedThunk), this);
+
+ // When we are attached to a window, focus the select button.
+ select_button_ = select_button;
+ g_signal_connect(root_widget_.get(), "hierarchy-changed",
+ G_CALLBACK(OnPromptShownThunk), this);
PopulateCerts();
- g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this);
- g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this);
+ gtk_widget_show_all(root_widget_.get());
+}
+
+SSLClientCertificateSelector::~SSLClientCertificateSelector() {
+ root_widget_.Destroy();
}
void SSLClientCertificateSelector::Show() {
- gtk_widget_show_all(dialog_);
+ DCHECK(!window_);
+ window_ = parent_->CreateConstrainedDialog(this);
}
void SSLClientCertificateSelector::PopulateCerts() {
@@ -192,6 +228,15 @@ void SSLClientCertificateSelector::PopulateCerts() {
gtk_combo_box_set_active(GTK_COMBO_BOX(cert_combo_box_), 0);
}
+net::X509Certificate* SSLClientCertificateSelector::GetSelectedCert() {
+ int selected = gtk_combo_box_get_active(GTK_COMBO_BOX(cert_combo_box_));
+ if (selected >= 0 &&
+ selected < static_cast<int>(
+ cert_request_info_->client_certs.size()))
+ return cert_request_info_->client_certs[selected];
+ return NULL;
+}
+
// static
std::string SSLClientCertificateSelector::FormatComboBoxText(
CERTCertificate* cert, const char* nickname) {
@@ -278,46 +323,45 @@ std::string SSLClientCertificateSelector::FormatDetailsText(
return rv;
}
-// static
-void SSLClientCertificateSelector::OnComboBoxChanged(
- GtkComboBox* combo_box, SSLClientCertificateSelector* cert_selector) {
+void SSLClientCertificateSelector::OnComboBoxChanged(GtkWidget* combo_box) {
int selected = gtk_combo_box_get_active(
- GTK_COMBO_BOX(cert_selector->cert_combo_box_));
+ GTK_COMBO_BOX(cert_combo_box_));
if (selected < 0)
return;
- gtk_text_buffer_set_text(cert_selector->cert_details_buffer_,
- cert_selector->details_strings_[selected].c_str(),
- cert_selector->details_strings_[selected].size());
+ gtk_text_buffer_set_text(cert_details_buffer_,
+ details_strings_[selected].c_str(),
+ details_strings_[selected].size());
}
-// static
-void SSLClientCertificateSelector::OnResponse(
- GtkDialog* dialog, gint response_id,
- SSLClientCertificateSelector* cert_selector) {
- net::X509Certificate* cert = NULL;
- if (response_id == GTK_RESPONSE_OK ||
- response_id == RESPONSE_SHOW_CERT_INFO) {
- int selected = gtk_combo_box_get_active(
- GTK_COMBO_BOX(cert_selector->cert_combo_box_));
- if (selected >= 0 &&
- selected < static_cast<int>(
- cert_selector->cert_request_info_->client_certs.size()))
- cert = cert_selector->cert_request_info_->client_certs[selected];
+void SSLClientCertificateSelector::OnViewClicked(GtkWidget* button) {
+ net::X509Certificate* cert = GetSelectedCert();
+ if (cert) {
+ GtkWidget* toplevel = gtk_widget_get_toplevel(root_widget_.get());
+ ShowCertificateViewer(GTK_WINDOW(toplevel), cert);
}
- if (response_id == RESPONSE_SHOW_CERT_INFO) {
- if (cert)
- ShowCertificateViewer(GTK_WINDOW(cert_selector->dialog_), cert);
- return;
- }
- cert_selector->delegate_->CertificateSelected(cert);
- gtk_widget_destroy(GTK_WIDGET(dialog));
}
-// static
-void SSLClientCertificateSelector::OnDestroy(
- GtkDialog* dialog,
- SSLClientCertificateSelector* cert_selector) {
- delete cert_selector;
+void SSLClientCertificateSelector::OnCancelClicked(GtkWidget* button) {
+ delegate_->CertificateSelected(NULL);
+ DCHECK(window_);
+ window_->CloseConstrainedWindow();
+}
+
+void SSLClientCertificateSelector::OnOkClicked(GtkWidget* button) {
+ net::X509Certificate* cert = GetSelectedCert();
+ delegate_->CertificateSelected(cert);
+ DCHECK(window_);
+ window_->CloseConstrainedWindow();
+}
+
+void SSLClientCertificateSelector::OnPromptShown(GtkWidget* widget,
+ GtkWidget* previous_toplevel) {
+ if (!root_widget_.get() ||
+ !GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(root_widget_.get())))
+ return;
+ GTK_WIDGET_SET_FLAGS(select_button_, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default(select_button_);
+ gtk_widget_grab_focus(select_button_);
}
} // namespace
@@ -328,7 +372,7 @@ void SSLClientCertificateSelector::OnDestroy(
namespace browser {
void ShowSSLClientCertificateSelector(
- gfx::NativeWindow parent,
+ TabContents* parent,
net::SSLCertRequestInfo* cert_request_info,
SSLClientAuthHandler* delegate) {
(new SSLClientCertificateSelector(parent,
diff --git a/chrome/browser/gtk/status_bubble_gtk.cc b/chrome/browser/gtk/status_bubble_gtk.cc
index 99fbd32..bc6f9b3 100644
--- a/chrome/browser/gtk/status_bubble_gtk.cc
+++ b/chrome/browser/gtk/status_bubble_gtk.cc
@@ -57,8 +57,8 @@ StatusBubbleGtk::~StatusBubbleGtk() {
container_.Destroy();
}
-void StatusBubbleGtk::SetStatus(const std::wstring& status_text_wide) {
- std::string status_text = WideToUTF8(status_text_wide);
+void StatusBubbleGtk::SetStatus(const string16& status_text_wide) {
+ std::string status_text = UTF16ToUTF8(status_text_wide);
if (status_text_ == status_text)
return;
@@ -72,7 +72,7 @@ void StatusBubbleGtk::SetStatus(const std::wstring& status_text_wide) {
}
}
-void StatusBubbleGtk::SetURL(const GURL& url, const std::wstring& languages) {
+void StatusBubbleGtk::SetURL(const GURL& url, const string16& languages) {
url_ = url;
languages_ = languages;
@@ -107,7 +107,7 @@ void StatusBubbleGtk::SetStatusTextToURL() {
// TODO(tc): We don't actually use gfx::Font as the font in the status
// bubble. We should extend gfx::ElideUrl to take some sort of pango font.
url_text_ = WideToUTF8(gfx::ElideUrl(url_, gfx::Font(), desired_width,
- languages_));
+ UTF16ToWideHack(languages_)));
SetStatusTextTo(url_text_);
}
diff --git a/chrome/browser/gtk/status_bubble_gtk.h b/chrome/browser/gtk/status_bubble_gtk.h
index 497d67e..1706665 100644
--- a/chrome/browser/gtk/status_bubble_gtk.h
+++ b/chrome/browser/gtk/status_bubble_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_STATUS_BUBBLE_GTK_H_
#define CHROME_BROWSER_GTK_STATUS_BUBBLE_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -13,10 +14,10 @@
#include "app/slide_animation.h"
#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/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/point.h"
#include "googleurl/src/gurl.h"
@@ -38,8 +39,8 @@ class StatusBubbleGtk : public StatusBubble,
int y_offset() const { return y_offset_; }
// StatusBubble implementation.
- virtual void SetStatus(const std::wstring& status);
- virtual void SetURL(const GURL& url, const std::wstring& languages);
+ 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);
@@ -128,7 +129,7 @@ class StatusBubbleGtk : public StatusBubble,
// Used to determine the character set that the user can read (for eliding
// the url text).
- std::wstring languages_;
+ string16 languages_;
// A timer that hides our window after a delay.
base::OneShotTimer<StatusBubbleGtk> hide_timer_;
diff --git a/chrome/browser/gtk/status_icons/status_icon_gtk.cc b/chrome/browser/gtk/status_icons/status_icon_gtk.cc
index 3dacfbc..7268b00 100644
--- a/chrome/browser/gtk/status_icons/status_icon_gtk.cc
+++ b/chrome/browser/gtk/status_icons/status_icon_gtk.cc
@@ -7,6 +7,7 @@
#include "base/string16.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/gtk/menu_gtk.h"
#include "gfx/gtk_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -16,6 +17,8 @@ StatusIconGtk::StatusIconGtk() {
g_signal_connect(icon_, "activate",
G_CALLBACK(OnClickThunk), this);
+ g_signal_connect(icon_, "popup-menu",
+ G_CALLBACK(OnPopupMenuThunk), this);
}
StatusIconGtk::~StatusIconGtk() {
@@ -43,3 +46,16 @@ void StatusIconGtk::SetToolTip(const string16& tool_tip) {
void StatusIconGtk::OnClick(GtkWidget* widget) {
DispatchClickEvent();
}
+
+void StatusIconGtk::UpdatePlatformContextMenu(menus::MenuModel* model) {
+ if (!model)
+ menu_.reset();
+ else
+ menu_.reset(new MenuGtk(NULL, model));
+}
+
+void StatusIconGtk::OnPopupMenu(GtkWidget* widget, guint button, guint time) {
+ // If we have a menu - display it.
+ if (menu_.get())
+ menu_->PopupAsContextForStatusIcon(time, button, icon_);
+}
diff --git a/chrome/browser/gtk/status_icons/status_icon_gtk.h b/chrome/browser/gtk/status_icons/status_icon_gtk.h
index 65a07ab..7053ed5 100644
--- a/chrome/browser/gtk/status_icons/status_icon_gtk.h
+++ b/chrome/browser/gtk/status_icons/status_icon_gtk.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_GTK_STATUS_ICONS_STATUS_ICON_GTK_H_
#define CHROME_BROWSER_GTK_STATUS_ICONS_STATUS_ICON_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include "app/gtk_signal.h"
#include "chrome/browser/status_icons/status_icon.h"
+class MenuGtk;
class SkBitmap;
class StatusIconGtk : public StatusIcon {
@@ -25,10 +27,20 @@ class StatusIconGtk : public StatusIcon {
// Exposed for testing.
CHROMEGTK_CALLBACK_0(StatusIconGtk, void, OnClick);
+ protected:
+ // Overridden from StatusIcon.
+ virtual void UpdatePlatformContextMenu(menus::MenuModel* menu);
+
private:
+ // Callback invoked when user right-clicks on the status icon.
+ CHROMEGTK_CALLBACK_2(StatusIconGtk, void, OnPopupMenu, guint, guint);
+
// The currently-displayed icon for the window.
GtkStatusIcon* icon_;
+ // The context menu for this icon (if any).
+ scoped_ptr<MenuGtk> menu_;
+
DISALLOW_COPY_AND_ASSIGN(StatusIconGtk);
};
diff --git a/chrome/browser/gtk/status_icons/status_tray_gtk.cc b/chrome/browser/gtk/status_icons/status_tray_gtk.cc
index 6b2764e..98cf98c 100644
--- a/chrome/browser/gtk/status_icons/status_tray_gtk.cc
+++ b/chrome/browser/gtk/status_icons/status_tray_gtk.cc
@@ -12,7 +12,7 @@ StatusTrayGtk::StatusTrayGtk() {
StatusTrayGtk::~StatusTrayGtk() {
}
-StatusIcon* StatusTrayGtk::CreateStatusIcon() {
+StatusIcon* StatusTrayGtk::CreatePlatformStatusIcon() {
return new StatusIconGtk();
}
diff --git a/chrome/browser/gtk/status_icons/status_tray_gtk.h b/chrome/browser/gtk/status_icons/status_tray_gtk.h
index a41e5df..5e0241b 100644
--- a/chrome/browser/gtk/status_icons/status_tray_gtk.h
+++ b/chrome/browser/gtk/status_icons/status_tray_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_STATUS_ICONS_STATUS_TRAY_GTK_H_
#define CHROME_BROWSER_GTK_STATUS_ICONS_STATUS_TRAY_GTK_H_
+#pragma once
#include "chrome/browser/status_icons/status_tray.h"
@@ -14,7 +15,7 @@ class StatusTrayGtk : public StatusTray {
protected:
// Overriden from StatusTray:
- virtual StatusIcon* CreateStatusIcon();
+ virtual StatusIcon* CreatePlatformStatusIcon();
private:
DISALLOW_COPY_AND_ASSIGN(StatusTrayGtk);
diff --git a/chrome/browser/gtk/status_icons/status_tray_gtk_unittest.cc b/chrome/browser/gtk/status_icons/status_tray_gtk_unittest.cc
index d123e5b..0e28e9e 100644
--- a/chrome/browser/gtk/status_icons/status_tray_gtk_unittest.cc
+++ b/chrome/browser/gtk/status_icons/status_tray_gtk_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 "app/menus/simple_menu_model.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/status_icons/status_icon_gtk.h"
#include "chrome/browser/gtk/status_icons/status_tray_gtk.h"
#include "grit/browser_resources.h"
@@ -26,19 +28,21 @@ TEST(StatusTrayGtkTest, CreateTray) {
TEST(StatusTrayGtkTest, CreateIcon) {
// Create an icon, set the images and tooltip, then shut it down.
StatusTrayGtk tray;
- StatusIcon* icon = tray.GetStatusIcon(ASCIIToUTF16("test"));
+ StatusIcon* icon = tray.CreateStatusIcon();
SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_STATUS_TRAY_ICON);
icon->SetImage(*bitmap);
icon->SetPressedImage(*bitmap);
icon->SetToolTip(ASCIIToUTF16("tool tip"));
+ menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(NULL);
+ menu->AddItem(0, ASCIIToUTF16("foo"));
+ icon->SetContextMenu(menu);
}
TEST(StatusTrayGtkTest, ClickOnIcon) {
// Create an icon, send a fake click event, make sure observer is called.
StatusTrayGtk tray;
- StatusIconGtk* icon = static_cast<StatusIconGtk*>(
- tray.GetStatusIcon(ASCIIToUTF16("test")));
+ StatusIconGtk* icon = static_cast<StatusIconGtk*>(tray.CreateStatusIcon());
MockStatusIconObserver observer;
icon->AddObserver(&observer);
EXPECT_CALL(observer, OnClicked());
diff --git a/chrome/browser/gtk/tab_contents_container_gtk.cc b/chrome/browser/gtk/tab_contents_container_gtk.cc
index af83a0e..1f4a3cc 100644
--- a/chrome/browser/gtk/tab_contents_container_gtk.cc
+++ b/chrome/browser/gtk/tab_contents_container_gtk.cc
@@ -178,8 +178,7 @@ void TabContentsContainerGtk::OnSetFloatingPosition(
gtk_container_child_set_property(GTK_CONTAINER(floating_container),
status->widget(), "x", &value);
- int child_y = std::max(
- allocation->y + allocation->height - requisition.height, 0);
+ int child_y = std::max(allocation->height - requisition.height, 0);
g_value_set_int(&value, child_y + status->y_offset());
gtk_container_child_set_property(GTK_CONTAINER(floating_container),
status->widget(), "y", &value);
diff --git a/chrome/browser/gtk/tab_contents_container_gtk.h b/chrome/browser/gtk/tab_contents_container_gtk.h
index 91c2301..0b3a959 100644
--- a/chrome/browser/gtk/tab_contents_container_gtk.h
+++ b/chrome/browser/gtk/tab_contents_container_gtk.h
@@ -4,13 +4,15 @@
#ifndef CHROME_BROWSER_GTK_TAB_CONTENTS_CONTAINER_GTK_H_
#define CHROME_BROWSER_GTK_TAB_CONTENTS_CONTAINER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include "base/basictypes.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/gtk/view_id_util.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class RenderViewHost;
class StatusBubbleGtk;
diff --git a/chrome/browser/gtk/tab_contents_drag_source.cc b/chrome/browser/gtk/tab_contents_drag_source.cc
index 8bb4402..e6da6ad 100644
--- a/chrome/browser/gtk/tab_contents_drag_source.cc
+++ b/chrome/browser/gtk/tab_contents_drag_source.cc
@@ -10,7 +10,7 @@
#include "base/file_util.h"
#include "base/mime_util.h"
#include "base/utf_string_conversions.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/gtk/gtk_util.h"
@@ -101,7 +101,9 @@ void TabContentsDragSource::StartDragging(const WebDropData& drop_data,
drop_data_.reset(new WebDropData(drop_data));
- if (!image.isNull())
+ // The image we get from WebKit makes heavy use of alpha-shading. This looks
+ // bad on non-compositing WMs. Fall back to the default drag icon.
+ if (!image.isNull() && gtk_util::IsScreenComposited())
drag_pixbuf_ = gfx::GdkPixbufFromSkBitmap(&image);
image_offset_ = image_offset;
@@ -294,11 +296,11 @@ void TabContentsDragSource::OnDragBegin(GtkWidget* sender,
std::string content_disposition("attachment; filename=");
content_disposition += download_file_name_.value();
FilePath generated_download_file_name;
- DownloadManager::GenerateFileName(download_url_,
- content_disposition,
- std::string(),
- download_mime_type,
- &generated_download_file_name);
+ download_util::GenerateFileName(download_url_,
+ content_disposition,
+ std::string(),
+ download_mime_type,
+ &generated_download_file_name);
// Pass the file name to the drop target by setting the source window's
// XdndDirectSave0 property.
@@ -319,10 +321,13 @@ void TabContentsDragSource::OnDragBegin(GtkWidget* sender,
gdk_pixbuf_get_width(drag_pixbuf_),
gdk_pixbuf_get_height(drag_pixbuf_));
- GdkScreen* screen = gtk_widget_get_screen(drag_icon_);
- GdkColormap* rgba = gdk_screen_get_rgba_colormap(screen);
- if (rgba)
- gtk_widget_set_colormap(drag_icon_, rgba);
+ // We only need to do this once.
+ if (!GTK_WIDGET_REALIZED(drag_icon_)) {
+ GdkScreen* screen = gtk_widget_get_screen(drag_icon_);
+ GdkColormap* rgba = gdk_screen_get_rgba_colormap(screen);
+ if (rgba)
+ gtk_widget_set_colormap(drag_icon_, rgba);
+ }
gtk_drag_set_icon_widget(drag_context, drag_icon_,
image_offset_.x(), image_offset_.y());
diff --git a/chrome/browser/gtk/tab_contents_drag_source.h b/chrome/browser/gtk/tab_contents_drag_source.h
index 20eeea3..7b4cc97 100644
--- a/chrome/browser/gtk/tab_contents_drag_source.h
+++ b/chrome/browser/gtk/tab_contents_drag_source.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TAB_CONTENTS_DRAG_SOURCE_H_
#define CHROME_BROWSER_GTK_TAB_CONTENTS_DRAG_SOURCE_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
index 194704b..551aeb8 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
@@ -146,6 +146,10 @@ void DraggedTabControllerGtk::ActivateContents(TabContents* contents) {
// Ignored.
}
+void DraggedTabControllerGtk::DeactivateContents(TabContents* contents) {
+ // Ignored.
+}
+
void DraggedTabControllerGtk::LoadingStateChanged(TabContents* source) {
// TODO(jhawkins): It would be nice to respond to this message by changing the
// screen shot in the dragged tab.
@@ -667,7 +671,7 @@ bool DraggedTabControllerGtk::CompleteDrag() {
window_bounds.set_origin(GetWindowCreatePoint());
Browser* new_browser =
source_tabstrip_->model()->delegate()->CreateNewStripWithContents(
- dragged_contents_, window_bounds, dock_info_);
+ dragged_contents_, window_bounds, dock_info_, window->IsMaximized());
TabStripModel* new_model = new_browser->tabstrip_model();
new_model->SetTabPinned(new_model->GetIndexOfTabContents(dragged_contents_),
pinned_);
diff --git a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h
index 69602a8..b8b8eb3 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h
+++ b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TABS_DRAGGED_TAB_CONTROLLER_GTK_H_
#define CHROME_BROWSER_GTK_TABS_DRAGGED_TAB_CONTROLLER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -14,6 +15,7 @@
#include "base/timer.h"
#include "chrome/browser/dock_info.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class DraggedTabGtk;
@@ -80,6 +82,7 @@ class DraggedTabControllerGtk : public NotificationObserver,
const gfx::Rect& initial_pos,
bool user_gesture);
virtual void ActivateContents(TabContents* contents);
+ virtual void DeactivateContents(TabContents* contents);
virtual void LoadingStateChanged(TabContents* source);
virtual void CloseContents(TabContents* source);
virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
diff --git a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
index 96aae10..27a1846 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
@@ -10,7 +10,6 @@
#include "app/x11_util.h"
#include "base/i18n/rtl.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/tabs/tab_renderer_gtk.h"
#include "chrome/browser/profile.h"
@@ -18,6 +17,7 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "gfx/gtk_util.h"
#include "third_party/skia/include/core/SkShader.h"
diff --git a/chrome/browser/gtk/tabs/dragged_tab_gtk.h b/chrome/browser/gtk/tabs/dragged_tab_gtk.h
index 2eafca2..38c6525 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.h
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TABS_DRAGGED_TAB_GTK_H_
#define CHROME_BROWSER_GTK_TABS_DRAGGED_TAB_GTK_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc
index b62191d..148e7ea 100644
--- a/chrome/browser/gtk/tabs/tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_gtk.cc
@@ -7,10 +7,7 @@
#include <gdk/gdkkeysyms.h>
#include "app/gtk_dnd_util.h"
-#include "app/l10n_util.h"
#include "app/menus/accelerator_gtk.h"
-#include "app/resource_bundle.h"
-#include "base/keyboard_codes_posix.h"
#include "base/singleton.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
@@ -155,7 +152,7 @@ TabGtk::TabGtk(TabDelegate* delegate)
G_CALLBACK(OnLeaveNotifyEventThunk), this);
gtk_widget_add_events(event_box_,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_LEAVE_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
gtk_container_add(GTK_CONTAINER(event_box_), TabRendererGtk::widget());
gtk_widget_show_all(event_box_);
}
diff --git a/chrome/browser/gtk/tabs/tab_gtk.h b/chrome/browser/gtk/tabs/tab_gtk.h
index 6630780..64c5513 100644
--- a/chrome/browser/gtk/tabs/tab_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_gtk.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_GTK_TABS_TAB_GTK_H_
#define CHROME_BROWSER_GTK_TABS_TAB_GTK_H_
+#pragma once
#include "app/gtk_signal.h"
-#include "app/theme_provider.h"
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "chrome/browser/gtk/tabs/tab_renderer_gtk.h"
@@ -79,7 +79,7 @@ class TabGtk : public TabRendererGtk,
virtual ThemeProvider* GetThemeProvider() = 0;
protected:
- ~TabDelegate() {}
+ virtual ~TabDelegate() {}
};
explicit TabGtk(TabDelegate* delegate);
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
index 0ae3023..4dc40a7 100644
--- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
@@ -10,6 +10,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/throb_animation.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
@@ -1077,8 +1078,8 @@ void TabRendererGtk::InitResources() {
// Force the font size to 9pt, which matches Windows' default font size
// (taken from the system).
const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
- title_font_ = new gfx::Font(gfx::Font::CreateFont(base_font.FontName(), 9));
- title_font_height_ = title_font_->height();
+ title_font_ = new gfx::Font(base_font.GetFontName(), 9);
+ title_font_height_ = title_font_->GetHeight();
crashed_fav_icon = rb.GetBitmapNamed(IDR_SAD_FAVICON);
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.h b/chrome/browser/gtk/tabs/tab_renderer_gtk.h
index 1ba697d..092843d 100644
--- a/chrome/browser/gtk/tabs/tab_renderer_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TABS_TAB_RENDERER_GTK_H_
#define CHROME_BROWSER_GTK_TABS_TAB_RENDERER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include <map>
@@ -12,10 +13,11 @@
#include "app/gtk_signal.h"
#include "app/slide_animation.h"
#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
#include "base/string16.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/canvas.h"
#include "gfx/font.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
index e8e4cdf..88ef6a8 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
@@ -12,7 +12,6 @@
#include "base/i18n/rtl.h"
#include "base/string_util.h"
#include "chrome/browser/autocomplete/autocomplete.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
@@ -20,6 +19,8 @@
#include "chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model_delegate.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "gfx/gtk_util.h"
@@ -772,13 +773,6 @@ void TabStripGtk::Hide() {
gtk_widget_hide(tabstrip_.get());
}
-void TabStripGtk::CancelActiveDragSession() {
- if (!IsDragSessionActive())
- return;
-
- drag_controller_->EndDrag(true);
-}
-
void TabStripGtk::Layout() {
// Called from:
// - window resize
@@ -1452,7 +1446,7 @@ int TabStripGtk::tab_start_x() const {
return 0;
}
-void TabStripGtk::ResizeLayoutTabs() {
+bool TabStripGtk::ResizeLayoutTabs() {
resize_layout_factory_.RevokeAll();
// It is critically important that this is unhooked here, otherwise we will
@@ -1464,7 +1458,7 @@ void TabStripGtk::ResizeLayoutTabs() {
if (mini_tab_count == GetTabCount()) {
// Only mini tabs, we know the tab widths won't have changed (all mini-tabs
// have the same width), so there is nothing to do.
- return;
+ return false;
}
TabGtk* first_tab = GetTabAt(mini_tab_count);
double unselected, selected;
@@ -1473,8 +1467,12 @@ void TabStripGtk::ResizeLayoutTabs() {
// We only want to run the animation if we're not already at the desired
// size.
- if (abs(first_tab->width() - w) > 1)
+ if (abs(first_tab->width() - w) > 1) {
StartResizeLayoutAnimation();
+ return true;
+ }
+
+ return false;
}
bool TabStripGtk::IsCursorInTabStripZone() const {
@@ -1909,15 +1907,11 @@ void TabStripGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {
if (GetTabCount() == 0)
return;
- // Do a regular layout on the first configure-event so we don't animate
- // the first tab.
- // TODO(jhawkins): Windows resizes the layout tabs continuously during
- // a resize. I need to investigate which signal to watch in order to
- // reproduce this behavior.
- if (GetTabCount() == 1)
+ // When there is only one tab, Layout() so we don't animate it. With more
+ // tabs, do ResizeLayoutTabs(). In RTL(), we will also need to manually
+ // Layout() when ResizeLayoutTabs() is a no-op.
+ if ((GetTabCount() == 1) || (!ResizeLayoutTabs() && base::i18n::IsRTL()))
Layout();
- else
- ResizeLayoutTabs();
}
gboolean TabStripGtk::OnDragMotion(GtkWidget* widget, GdkDragContext* context,
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h
index 11390e9..bc03bcf 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TABS_TAB_STRIP_GTK_H_
#define CHROME_BROWSER_GTK_TABS_TAB_STRIP_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include <vector>
@@ -12,12 +13,12 @@
#include "base/basictypes.h"
#include "base/task.h"
#include "base/message_loop.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/gtk/tabstrip_origin_provider.h"
#include "chrome/browser/gtk/tabs/tab_gtk.h"
#include "chrome/browser/gtk/view_id_util.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/notification_observer.h"
-#include "chrome/common/owned_widget_gtk.h"
#include "gfx/rect.h"
class BrowserWindowGtk;
@@ -53,9 +54,6 @@ class TabStripGtk : public TabStripModelObserver,
// Returns true if there is an active drag session.
bool IsDragSessionActive() const { return drag_controller_.get() != NULL; }
- // Cancels the current drag session, if any.
- void CancelActiveDragSession();
-
// Sets the bounds of the tabs.
void Layout();
@@ -175,7 +173,7 @@ class TabStripGtk : public TabStripModelObserver,
class DropInfo {
public:
DropInfo(int index, bool drop_before, bool point_down);
- ~DropInfo();
+ virtual ~DropInfo();
// TODO(jhawkins): Factor out this code into a TransparentContainer class.
@@ -309,8 +307,9 @@ class TabStripGtk : public TabStripModelObserver,
// Returns the x-coordinate tabs start from.
int tab_start_x() const;
- // Perform an animated resize-relayout of the TabStrip immediately.
- void ResizeLayoutTabs();
+ // Perform an animated resize-relayout of the TabStrip immediately. The
+ // value returned indicates whether a resize actually took place.
+ bool ResizeLayoutTabs();
// Returns whether or not the cursor is currently in the "tab strip zone"
// which is defined as the region above the TabStrip and a bit below it.
diff --git a/chrome/browser/gtk/tabstrip_origin_provider.h b/chrome/browser/gtk/tabstrip_origin_provider.h
index 47baf91..0904a01 100644
--- a/chrome/browser/gtk/tabstrip_origin_provider.h
+++ b/chrome/browser/gtk/tabstrip_origin_provider.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TABSTRIP_ORIGIN_PROVIDER_H_
#define CHROME_BROWSER_GTK_TABSTRIP_ORIGIN_PROVIDER_H_
+#pragma once
namespace gfx{
class Point;
diff --git a/chrome/browser/gtk/task_manager_gtk.cc b/chrome/browser/gtk/task_manager_gtk.cc
index faffd1c..5259863 100644
--- a/chrome/browser/gtk/task_manager_gtk.cc
+++ b/chrome/browser/gtk/task_manager_gtk.cc
@@ -23,9 +23,8 @@
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/memory_purger.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "gfx/gtk_util.h"
@@ -33,6 +32,12 @@
#include "grit/chromium_strings.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#if defined(TOOLKIT_VIEWS)
+#include "views/controls/menu/menu_2.h"
+#else
+#include "chrome/browser/gtk/menu_gtk.h"
+#endif
+
namespace {
// The task manager window default size.
@@ -60,6 +65,7 @@ enum TaskManagerColumn {
kTaskManagerWebCoreImageCache,
kTaskManagerWebCoreScriptsCache,
kTaskManagerWebCoreCssCache,
+ kTaskManagerSqliteMemoryUsed,
kTaskManagerGoatsTeleported,
kTaskManagerColumnCount,
};
@@ -86,6 +92,8 @@ TaskManagerColumn TaskManagerResourceIDToColumnID(int id) {
return kTaskManagerWebCoreScriptsCache;
case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
return kTaskManagerWebCoreCssCache;
+ case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
+ return kTaskManagerSqliteMemoryUsed;
case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN:
return kTaskManagerGoatsTeleported;
default:
@@ -116,6 +124,8 @@ int TaskManagerColumnIDToResourceID(int id) {
return IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN;
case kTaskManagerWebCoreCssCache:
return IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN;
+ case kTaskManagerSqliteMemoryUsed:
+ return IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN;
case kTaskManagerGoatsTeleported:
return IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN;
default:
@@ -212,18 +222,32 @@ class TaskManagerGtk::ContextMenuController
menu_model_->AddCheckItemWithStringId(
i, TaskManagerColumnIDToResourceID(i));
}
+#if defined(TOOLKIT_VIEWS)
+ menu_.reset(new views::Menu2(menu_model_.get()));
+#else
menu_.reset(new MenuGtk(NULL, menu_model_.get()));
+#endif
}
virtual ~ContextMenuController() {}
+#if defined(TOOLKIT_VIEWS)
+ void RunMenu(const gfx::Point& point) {
+ menu_->RunContextMenuAt(point);
+ }
+#else
void RunMenu() {
menu_->PopupAsContext(gtk_get_current_event_time());
}
+#endif
void Cancel() {
task_manager_ = NULL;
+#if defined(TOOLKIT_VIEWS)
+ menu_->CancelMenu();
+#else
menu_->Cancel();
+#endif
}
private:
@@ -260,7 +284,11 @@ class TaskManagerGtk::ContextMenuController
// The model and view for the right click context menu.
scoped_ptr<menus::SimpleMenuModel> menu_model_;
+#if defined(TOOLKIT_VIEWS)
+ scoped_ptr<views::Menu2> menu_;
+#else
scoped_ptr<MenuGtk> menu_;
+#endif
// The TaskManager the context menu was brought up for. Set to NULL when the
// menu is canceled.
@@ -473,10 +501,10 @@ void TaskManagerGtk::SetInitialDialogSize() {
prefs::kTaskManagerWindowPlacement);
int top = 0, left = 0, bottom = 1, right = 1;
if (placement_pref &&
- placement_pref->GetInteger(L"top", &top) &&
- placement_pref->GetInteger(L"left", &left) &&
- placement_pref->GetInteger(L"bottom", &bottom) &&
- placement_pref->GetInteger(L"right", &right)) {
+ placement_pref->GetInteger("top", &top) &&
+ placement_pref->GetInteger("left", &left) &&
+ placement_pref->GetInteger("bottom", &bottom) &&
+ placement_pref->GetInteger("right", &right)) {
gtk_window_resize(GTK_WINDOW(dialog_),
std::max(1, right - left),
std::max(1, bottom - top));
@@ -504,7 +532,8 @@ void TaskManagerGtk::CreateTaskManagerTreeview() {
process_list_ = gtk_list_store_new(kTaskManagerColumnCount,
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING);
// Support sorting on all columns.
process_list_sort_ = gtk_tree_model_sort_new_with_model(
@@ -540,6 +569,9 @@ void TaskManagerGtk::CreateTaskManagerTreeview() {
kTaskManagerWebCoreCssCache,
CompareWebCoreCssCache, this, NULL);
gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
+ kTaskManagerSqliteMemoryUsed,
+ CompareSqliteMemoryUsed, this, NULL);
+ gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
kTaskManagerGoatsTeleported,
CompareGoatsTeleported, this, NULL);
treeview_ = gtk_tree_view_new_with_model(process_list_sort_);
@@ -557,6 +589,7 @@ void TaskManagerGtk::CreateTaskManagerTreeview() {
TreeViewInsertColumn(treeview_,
IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN);
TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN);
+ TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN);
TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN);
// Hide some columns by default.
@@ -566,6 +599,7 @@ void TaskManagerGtk::CreateTaskManagerTreeview() {
TreeViewColumnSetVisible(treeview_, kTaskManagerWebCoreImageCache, false);
TreeViewColumnSetVisible(treeview_, kTaskManagerWebCoreScriptsCache, false);
TreeViewColumnSetVisible(treeview_, kTaskManagerWebCoreCssCache, false);
+ TreeViewColumnSetVisible(treeview_, kTaskManagerSqliteMemoryUsed, false);
TreeViewColumnSetVisible(treeview_, kTaskManagerGoatsTeleported, false);
g_object_unref(process_list_);
@@ -594,37 +628,40 @@ std::string TaskManagerGtk::GetModelText(int row, int col_id) {
switch (col_id) {
case IDS_TASK_MANAGER_PAGE_COLUMN: // Process
- return WideToUTF8(model_->GetResourceTitle(row));
+ return UTF16ToUTF8(model_->GetResourceTitle(row));
case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory
- return WideToUTF8(model_->GetResourcePrivateMemory(row));
+ return UTF16ToUTF8(model_->GetResourcePrivateMemory(row));
case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory
- return WideToUTF8(model_->GetResourceSharedMemory(row));
+ return UTF16ToUTF8(model_->GetResourceSharedMemory(row));
case IDS_TASK_MANAGER_CPU_COLUMN: // CPU
- return WideToUTF8(model_->GetResourceCPUUsage(row));
+ return UTF16ToUTF8(model_->GetResourceCPUUsage(row));
case IDS_TASK_MANAGER_NET_COLUMN: // Net
- return WideToUTF8(model_->GetResourceNetworkUsage(row));
+ return UTF16ToUTF8(model_->GetResourceNetworkUsage(row));
case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: // Process ID
- return WideToUTF8(model_->GetResourceProcessId(row));
+ return UTF16ToUTF8(model_->GetResourceProcessId(row));
case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
- return WideToUTF8(model_->GetResourceV8MemoryAllocatedSize(row));
+ return UTF16ToUTF8(model_->GetResourceV8MemoryAllocatedSize(row));
case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
- return WideToUTF8(model_->GetResourceWebCoreImageCacheSize(row));
+ return UTF16ToUTF8(model_->GetResourceWebCoreImageCacheSize(row));
case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
- return WideToUTF8(model_->GetResourceWebCoreScriptsCacheSize(row));
+ return UTF16ToUTF8(model_->GetResourceWebCoreScriptsCacheSize(row));
case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
- return WideToUTF8(model_->GetResourceWebCoreCSSCacheSize(row));
+ return UTF16ToUTF8(model_->GetResourceWebCoreCSSCacheSize(row));
+
+ case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
+ return UTF16ToUTF8(model_->GetResourceSqliteMemoryUsed(row));
case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: // Goats Teleported!
- return WideToUTF8(model_->GetResourceGoatsTeleported(row));
+ return UTF16ToUTF8(model_->GetResourceGoatsTeleported(row));
default:
NOTREACHED();
@@ -672,6 +709,10 @@ void TaskManagerGtk::SetRowDataFromModel(int row, GtkTreeIter* iter) {
if (TreeViewColumnIsVisible(treeview_, kTaskManagerWebCoreCssCache))
wk_css_cache = GetModelText(
row, IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN);
+ std::string sqlite_memory;
+ if (TreeViewColumnIsVisible(treeview_, kTaskManagerSqliteMemoryUsed))
+ sqlite_memory = GetModelText(
+ row, IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN);
std::string goats = GetModelText(
row, IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN);
@@ -687,6 +728,7 @@ void TaskManagerGtk::SetRowDataFromModel(int row, GtkTreeIter* iter) {
kTaskManagerWebCoreImageCache, wk_img_cache.c_str(),
kTaskManagerWebCoreScriptsCache, wk_scripts_cache.c_str(),
kTaskManagerWebCoreCssCache, wk_css_cache.c_str(),
+ kTaskManagerSqliteMemoryUsed, sqlite_memory.c_str(),
kTaskManagerGoatsTeleported, goats.c_str(),
-1);
g_object_unref(icon);
@@ -710,12 +752,21 @@ void TaskManagerGtk::KillSelectedProcesses() {
g_list_free(paths);
}
+#if defined(TOOLKIT_VIEWS)
+void TaskManagerGtk::ShowContextMenu(const gfx::Point& point) {
+ if (!menu_controller_.get())
+ menu_controller_.reset(new ContextMenuController(this));
+
+ menu_controller_->RunMenu(point);
+}
+#else
void TaskManagerGtk::ShowContextMenu() {
if (!menu_controller_.get())
menu_controller_.reset(new ContextMenuController(this));
menu_controller_->RunMenu();
}
+#endif
void TaskManagerGtk::ActivateFocusedTab() {
GtkTreeSelection* selection = gtk_tree_view_get_selection(
@@ -790,11 +841,11 @@ void TaskManagerGtk::OnResponse(GtkWidget* dialog, gint response_id) {
prefs::kTaskManagerWindowPlacement);
// Note that we store left/top for consistency with Windows, but that we
// *don't* restore them.
- placement_pref->SetInteger(L"left", dialog_bounds.x());
- placement_pref->SetInteger(L"top", dialog_bounds.y());
- placement_pref->SetInteger(L"right", dialog_bounds.right());
- placement_pref->SetInteger(L"bottom", dialog_bounds.bottom());
- placement_pref->SetBoolean(L"maximized", false);
+ placement_pref->SetInteger("left", dialog_bounds.x());
+ placement_pref->SetInteger("top", dialog_bounds.y());
+ placement_pref->SetInteger("right", dialog_bounds.right());
+ placement_pref->SetInteger("bottom", dialog_bounds.bottom());
+ placement_pref->SetBoolean("maximized", false);
}
instance_ = NULL;
@@ -889,8 +940,14 @@ gboolean TaskManagerGtk::OnButtonPressEvent(GtkWidget* widget,
gboolean TaskManagerGtk::OnButtonReleaseEvent(GtkWidget* widget,
GdkEventButton* event) {
- if (event->button == 3)
+ if (event->button == 3) {
+#if defined(TOOLKIT_VIEWS)
+ gfx::Point pt(event->x_root, event->y_root);
+ ShowContextMenu(pt);
+#else
ShowContextMenu();
+#endif
+ }
return FALSE;
}
diff --git a/chrome/browser/gtk/task_manager_gtk.h b/chrome/browser/gtk/task_manager_gtk.h
index c0ec0ef..75982e1 100644
--- a/chrome/browser/gtk/task_manager_gtk.h
+++ b/chrome/browser/gtk/task_manager_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TASK_MANAGER_GTK_H_
#define CHROME_BROWSER_GTK_TASK_MANAGER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -11,9 +12,15 @@
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/task_manager.h"
+#include "chrome/browser/task_manager/task_manager.h"
#include "grit/generated_resources.h"
+#if defined(TOOLKIT_VIEWS)
+namespace gfx {
+class Point;
+}
+#endif
+
class TaskManagerGtk : public TaskManagerModelObserver {
public:
TaskManagerGtk();
@@ -59,7 +66,11 @@ class TaskManagerGtk : public TaskManagerModelObserver {
void KillSelectedProcesses();
// Opens the context menu used to select the task manager columns.
+#if defined(TOOLKIT_VIEWS)
+ void ShowContextMenu(const gfx::Point& point);
+#else
void ShowContextMenu();
+#endif
// Activates the tab associated with the focused row.
void ActivateFocusedTab();
@@ -168,6 +179,13 @@ class TaskManagerGtk : public TaskManagerModelObserver {
CompareImpl(model, a, b, IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN);
}
+ // Sqlite memory sorting callback.
+ static gint CompareSqliteMemoryUsed(GtkTreeModel* model, GtkTreeIter* a,
+ GtkTreeIter* b, gpointer task_manager) {
+ return reinterpret_cast<TaskManagerGtk*>(task_manager)->
+ CompareImpl(model, a, b, IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN);
+ }
+
// Goats Teleported sorting callback.
static gint CompareGoatsTeleported(GtkTreeModel* model, GtkTreeIter* a,
GtkTreeIter* b, gpointer task_manager) {
diff --git a/chrome/browser/gtk/theme_install_bubble_view_gtk.h b/chrome/browser/gtk/theme_install_bubble_view_gtk.h
index bffaae8..17770a2 100644
--- a/chrome/browser/gtk/theme_install_bubble_view_gtk.h
+++ b/chrome/browser/gtk/theme_install_bubble_view_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_THEME_INSTALL_BUBBLE_VIEW_GTK_H_
#define CHROME_BROWSER_GTK_THEME_INSTALL_BUBBLE_VIEW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
diff --git a/chrome/browser/gtk/translate/after_translate_infobar_gtk.h b/chrome/browser/gtk/translate/after_translate_infobar_gtk.h
index 221b718..bd870be 100644
--- a/chrome/browser/gtk/translate/after_translate_infobar_gtk.h
+++ b/chrome/browser/gtk/translate/after_translate_infobar_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TRANSLATE_AFTER_TRANSLATE_INFOBAR_GTK_H_
#define CHROME_BROWSER_GTK_TRANSLATE_AFTER_TRANSLATE_INFOBAR_GTK_H_
+#pragma once
#include "base/task.h"
#include "chrome/browser/gtk/translate/translate_infobar_base_gtk.h"
diff --git a/chrome/browser/gtk/translate/before_translate_infobar_gtk.h b/chrome/browser/gtk/translate/before_translate_infobar_gtk.h
index 6c90308..1373247 100644
--- a/chrome/browser/gtk/translate/before_translate_infobar_gtk.h
+++ b/chrome/browser/gtk/translate/before_translate_infobar_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TRANSLATE_BEFORE_TRANSLATE_INFOBAR_GTK_H_
#define CHROME_BROWSER_GTK_TRANSLATE_BEFORE_TRANSLATE_INFOBAR_GTK_H_
+#pragma once
#include "chrome/browser/gtk/translate/translate_infobar_base_gtk.h"
diff --git a/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc b/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc
index bb55831..e7a94b8 100644
--- a/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc
+++ b/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/gtk/translate/translate_infobar_base_gtk.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "app/slide_animation.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/translate/options_menu_model.h"
@@ -74,14 +73,14 @@ void TranslateInfoBarBase::GetTopColor(InfoBarDelegate::Type type,
if (background_error_percent_ <= 0) {
InfoBar::GetTopColor(InfoBarDelegate::PAGE_ACTION_TYPE, r, g, b);
} else if (background_error_percent_ >= 1) {
- InfoBar::GetTopColor(InfoBarDelegate::ERROR_TYPE, r, g, b);
+ InfoBar::GetTopColor(InfoBarDelegate::WARNING_TYPE, r, g, b);
} else {
double normal_r, normal_g, normal_b;
InfoBar::GetTopColor(InfoBarDelegate::PAGE_ACTION_TYPE,
&normal_r, &normal_g, &normal_b);
double error_r, error_g, error_b;
- InfoBar::GetTopColor(InfoBarDelegate::ERROR_TYPE,
+ InfoBar::GetTopColor(InfoBarDelegate::WARNING_TYPE,
&error_r, &error_g, &error_b);
double offset_r = error_r - normal_r;
@@ -99,14 +98,14 @@ void TranslateInfoBarBase::GetBottomColor(InfoBarDelegate::Type type,
if (background_error_percent_ <= 0) {
InfoBar::GetBottomColor(InfoBarDelegate::PAGE_ACTION_TYPE, r, g, b);
} else if (background_error_percent_ >= 1) {
- InfoBar::GetBottomColor(InfoBarDelegate::ERROR_TYPE, r, g, b);
+ InfoBar::GetBottomColor(InfoBarDelegate::WARNING_TYPE, r, g, b);
} else {
double normal_r, normal_g, normal_b;
InfoBar::GetBottomColor(InfoBarDelegate::PAGE_ACTION_TYPE,
&normal_r, &normal_g, &normal_b);
double error_r, error_g, error_b;
- InfoBar::GetBottomColor(InfoBarDelegate::ERROR_TYPE,
+ InfoBar::GetBottomColor(InfoBarDelegate::WARNING_TYPE,
&error_r, &error_g, &error_b);
double offset_r = error_r - normal_r;
diff --git a/chrome/browser/gtk/translate/translate_infobar_base_gtk.h b/chrome/browser/gtk/translate/translate_infobar_base_gtk.h
index a1d7292..ce851f9 100644
--- a/chrome/browser/gtk/translate/translate_infobar_base_gtk.h
+++ b/chrome/browser/gtk/translate/translate_infobar_base_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TRANSLATE_TRANSLATE_INFOBAR_BASE_GTK_H_
#define CHROME_BROWSER_GTK_TRANSLATE_TRANSLATE_INFOBAR_BASE_GTK_H_
+#pragma once
#include "chrome/browser/translate/translate_infobar_view.h"
#include "chrome/browser/gtk/infobar_gtk.h"
@@ -75,7 +76,7 @@ class TranslateInfoBarBase : public TranslateInfoBarView,
// A percentage to average the normal page action background with the error
// background. When 0, the infobar background should be pure PAGE_ACTION_TYPE.
- // When 1, the infobar background should be pure ERROR_TYPE.
+ // When 1, the infobar background should be pure WARNING_TYPE.
double background_error_percent_;
// Changes the color of the background from normal to error color and back.
diff --git a/chrome/browser/gtk/translate/translate_message_infobar_gtk.h b/chrome/browser/gtk/translate/translate_message_infobar_gtk.h
index 1dd4665..74db7e3 100644
--- a/chrome/browser/gtk/translate/translate_message_infobar_gtk.h
+++ b/chrome/browser/gtk/translate/translate_message_infobar_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_TRANSLATE_TRANSLATE_MESSAGE_INFOBAR_GTK_H_
#define CHROME_BROWSER_GTK_TRANSLATE_TRANSLATE_MESSAGE_INFOBAR_GTK_H_
+#pragma once
#include "chrome/browser/gtk/translate/translate_infobar_base_gtk.h"
diff --git a/chrome/browser/gtk/update_recommended_dialog.cc b/chrome/browser/gtk/update_recommended_dialog.cc
index e2ab33e..d9b4316 100644
--- a/chrome/browser/gtk/update_recommended_dialog.cc
+++ b/chrome/browser/gtk/update_recommended_dialog.cc
@@ -7,11 +7,10 @@
#include <gtk/gtk.h>
#include "app/l10n_util.h"
-#include "app/message_box_flags.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -28,19 +27,14 @@ UpdateRecommendedDialog::UpdateRecommendedDialog(GtkWindow* parent) {
l10n_util::GetStringUTF8(IDS_PRODUCT_NAME).c_str(),
parent,
static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
- l10n_util::GetStringUTF8(IDS_RESTART_AND_UPDATE).c_str(),
- GTK_RESPONSE_ACCEPT,
l10n_util::GetStringUTF8(IDS_NOT_NOW).c_str(),
GTK_RESPONSE_REJECT,
+ l10n_util::GetStringUTF8(IDS_RESTART_AND_UPDATE).c_str(),
+ GTK_RESPONSE_ACCEPT,
NULL);
g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
- // Create the content-holding vbox.
- GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
- gtk_container_set_border_width(GTK_CONTAINER(vbox),
- gtk_util::kContentAreaBorder);
-
// Add the message text.
std::string text(
l10n_util::GetStringFUTF8(IDS_UPDATE_RECOMMENDED,
@@ -48,10 +42,7 @@ UpdateRecommendedDialog::UpdateRecommendedDialog(GtkWindow* parent) {
GtkWidget* label = gtk_label_new(text.c_str());
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_widget_set_size_request(label, kMessageWidth, -1);
- gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
-
- // Add our vbox to the dialog.
- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), vbox,
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), label,
FALSE, FALSE, 0);
gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
diff --git a/chrome/browser/gtk/update_recommended_dialog.h b/chrome/browser/gtk/update_recommended_dialog.h
index 94e32c8..1105584 100644
--- a/chrome/browser/gtk/update_recommended_dialog.h
+++ b/chrome/browser/gtk/update_recommended_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_UPDATE_RECOMMENDED_DIALOG_H_
#define CHROME_BROWSER_GTK_UPDATE_RECOMMENDED_DIALOG_H_
+#pragma once
#include "app/gtk_integers.h"
#include "app/gtk_signal.h"
diff --git a/chrome/browser/gtk/view_id_util.cc b/chrome/browser/gtk/view_id_util.cc
index 684c669..2b8e396 100644
--- a/chrome/browser/gtk/view_id_util.cc
+++ b/chrome/browser/gtk/view_id_util.cc
@@ -107,9 +107,6 @@ const char* GetNameFromID(ViewID id) {
case VIEW_ID_DEV_TOOLS_DOCKED:
return "chrome-dev-tools-docked";
- case VIEW_ID_DEV_EXTENSION_SHELF:
- return "chrome-extension-shelf";
-
// These are never hit because the tab container uses the delegate to
// set its ID.
case VIEW_ID_TAB_CONTAINER:
diff --git a/chrome/browser/gtk/view_id_util.h b/chrome/browser/gtk/view_id_util.h
index 2640d15..c4833ad 100644
--- a/chrome/browser/gtk/view_id_util.h
+++ b/chrome/browser/gtk/view_id_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_GTK_VIEW_ID_UTIL_H_
#define CHROME_BROWSER_GTK_VIEW_ID_UTIL_H_
+#pragma once
#include "chrome/browser/view_ids.h"
diff --git a/chrome/browser/gtk/view_id_util_browsertest.cc b/chrome/browser/gtk/view_id_util_browsertest.cc
index b647900..be4f38c 100644
--- a/chrome/browser/gtk/view_id_util_browsertest.cc
+++ b/chrome/browser/gtk/view_id_util_browsertest.cc
@@ -33,16 +33,14 @@ IN_PROC_BROWSER_TEST_F(ViewIDTest, Basic) {
browser()->ShowFindBar();
for (int i = VIEW_ID_TOOLBAR; i < VIEW_ID_PREDEFINED_COUNT; ++i) {
- // Extension shelf is being removed, http://crbug.com/25106.
- if (i == VIEW_ID_DEV_EXTENSION_SHELF)
- continue;
-
// The following ids are used only in views implementation.
if (i == VIEW_ID_CONTENTS_SPLIT ||
i == VIEW_ID_INFO_BAR_CONTAINER ||
i == VIEW_ID_DOWNLOAD_SHELF ||
i == VIEW_ID_BOOKMARK_BAR_ELEMENT ||
- i == VIEW_ID_TAB) {
+ i == VIEW_ID_TAB ||
+ i == VIEW_ID_SIDE_BAR_CONTAINER ||
+ i == VIEW_ID_SIDE_BAR_SPLIT) {
continue;
}
diff --git a/chrome/browser/hang_monitor/hung_plugin_action.h b/chrome/browser/hang_monitor/hung_plugin_action.h
index 631bd34..4958def 100644
--- a/chrome/browser/hang_monitor/hung_plugin_action.h
+++ b/chrome/browser/hang_monitor/hung_plugin_action.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HANG_MONITOR_HUNG_PLUGIN_ACTION_H__
#define CHROME_BROWSER_HANG_MONITOR_HUNG_PLUGIN_ACTION_H__
+#pragma once
#include "chrome/browser/hang_monitor/hung_window_detector.h"
// This class provides an implementation the
diff --git a/chrome/browser/hang_monitor/hung_window_detector.h b/chrome/browser/hang_monitor/hung_window_detector.h
index bcf1617..0e48739 100644
--- a/chrome/browser/hang_monitor/hung_window_detector.h
+++ b/chrome/browser/hang_monitor/hung_window_detector.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HANG_MONITOR_HUNG_WINDOW_DETECTOR_H__
#define CHROME_BROWSER_HANG_MONITOR_HUNG_WINDOW_DETECTOR_H__
+#pragma once
#include "base/lock.h"
#include "chrome/common/worker_thread_ticker.h"
diff --git a/chrome/browser/history/archived_database.cc b/chrome/browser/history/archived_database.cc
index 1b9e010..72fa998 100644
--- a/chrome/browser/history/archived_database.cc
+++ b/chrome/browser/history/archived_database.cc
@@ -5,7 +5,6 @@
#include <algorithm>
#include <string>
-#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/string_util.h"
#include "chrome/browser/history/archived_database.h"
@@ -14,7 +13,7 @@ namespace history {
namespace {
-static const int kCurrentVersionNumber = 2;
+static const int kCurrentVersionNumber = 3;
static const int kCompatibleVersionNumber = 2;
} // namespace
@@ -111,6 +110,12 @@ sql::InitStatus ArchivedDatabase::EnsureCurrentVersion() {
std::min(cur_version, kCompatibleVersionNumber));
}
+ if (cur_version == 2) {
+ // This is the version prior to adding visit_source table.
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
// Put future migration cases here.
// When the version is too old, we just try to continue anyway, there should
diff --git a/chrome/browser/history/archived_database.h b/chrome/browser/history/archived_database.h
index c9d8757..9568aa5 100644
--- a/chrome/browser/history/archived_database.h
+++ b/chrome/browser/history/archived_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_ARCHIVED_DATABASE_H_
#define CHROME_BROWSER_HISTORY_ARCHIVED_DATABASE_H_
+#pragma once
#include "app/sql/connection.h"
#include "app/sql/init_status.h"
diff --git a/chrome/browser/history/download_database.cc b/chrome/browser/history/download_database.cc
index aa3dbde..f101e39 100644
--- a/chrome/browser/history/download_database.cc
+++ b/chrome/browser/history/download_database.cc
@@ -7,13 +7,12 @@
#include <limits>
#include <vector>
-#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "base/file_path.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/history/download_types.h"
+#include "chrome/browser/history/download_create_info.h"
// Download schema:
//
@@ -197,22 +196,4 @@ void DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin,
statement.Run();
}
-void DownloadDatabase::SearchDownloads(std::vector<int64>* results,
- const string16& search_text) {
- sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
- "SELECT id FROM downloads WHERE url LIKE ? "
- "OR full_path LIKE ? ORDER BY id"));
- if (!statement)
- return;
-
- std::string text("%");
- text.append(UTF16ToUTF8(search_text));
- text.push_back('%');
- statement.BindString(0, text);
- statement.BindString(1, text);
-
- while (statement.Step())
- results->push_back(statement.ColumnInt64(0));
-}
-
} // namespace history
diff --git a/chrome/browser/history/download_database.h b/chrome/browser/history/download_database.h
index 11adf31..56f650a 100644
--- a/chrome/browser/history/download_database.h
+++ b/chrome/browser/history/download_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_DOWNLOAD_DATABASE_H_
#define CHROME_BROWSER_HISTORY_DOWNLOAD_DATABASE_H_
+#pragma once
#include "chrome/browser/history/history_types.h"
@@ -50,10 +51,6 @@ class DownloadDatabase {
// all downloads that are in progress or are waiting to be cancelled.
void RemoveDownloadsBetween(base::Time remove_begin, base::Time remove_end);
- // Search for downloads matching the search text.
- void SearchDownloads(std::vector<int64>* results,
- const string16& search_text);
-
protected:
// Returns the database for the functions in this interface.
virtual sql::Connection& GetDB() = 0;
diff --git a/chrome/browser/history/download_types.h b/chrome/browser/history/download_types.h
deleted file mode 100644
index 642ac5b..0000000
--- a/chrome/browser/history/download_types.h
+++ /dev/null
@@ -1,104 +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.
-//
-// Download creation struct used for querying the history service.
-
-#ifndef CHROME_BROWSER_HISTORY_DOWNLOAD_TYPES_H_
-#define CHROME_BROWSER_HISTORY_DOWNLOAD_TYPES_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/time.h"
-#include "chrome/browser/download/download_file.h"
-#include "googleurl/src/gurl.h"
-
-// Used for informing the download database of a new download, where we don't
-// want to pass DownloadItems between threads. The history service also uses a
-// vector of these structs for passing us the state of all downloads at
-// initialization time (see DownloadQueryInfo below).
-struct DownloadCreateInfo {
- DownloadCreateInfo(const FilePath& path,
- const GURL& url,
- base::Time start_time,
- int64 received_bytes,
- int64 total_bytes,
- int32 state,
- int32 download_id)
- : path(path),
- url(url),
- path_uniquifier(0),
- start_time(start_time),
- received_bytes(received_bytes),
- total_bytes(total_bytes),
- state(state),
- download_id(download_id),
- child_id(-1),
- render_view_id(-1),
- request_id(-1),
- db_handle(0),
- prompt_user_for_save_location(false),
- is_dangerous(false),
- is_extension_install(false) {
- }
-
- DownloadCreateInfo()
- : path_uniquifier(0),
- received_bytes(0),
- total_bytes(0),
- state(-1),
- download_id(-1),
- child_id(-1),
- render_view_id(-1),
- request_id(-1),
- db_handle(0),
- prompt_user_for_save_location(false),
- is_dangerous(false),
- is_extension_install(false) {
- }
-
- // DownloadItem fields
- FilePath path;
- GURL url;
- GURL referrer_url;
- FilePath suggested_path;
- // A number that should be added to the suggested path to make it unique.
- // 0 means no number should be appended. Not actually stored in the db.
- int path_uniquifier;
- base::Time start_time;
- int64 received_bytes;
- int64 total_bytes;
- int32 state;
- int32 download_id;
- int child_id;
- int render_view_id;
- int request_id;
- int64 db_handle;
- std::string content_disposition;
- std::string mime_type;
- // The value of the content type header sent with the downloaded item. It
- // may be different from |mime_type|, which may be set based on heuristics
- // which may look at the file extension and first few bytes of the file.
- std::string original_mime_type;
-
- // True if we should display the 'save as...' UI and prompt the user
- // for the download location.
- // False if the UI should be supressed and the download performed to the
- // default location.
- bool prompt_user_for_save_location;
- // Whether this download is potentially dangerous (ex: exe, dll, ...).
- bool is_dangerous;
- // The original name for a dangerous download.
- FilePath original_name;
- // Whether this download is for extension install or not.
- bool is_extension_install;
- // The charset of the referring page where the download request comes from.
- // It's used to construct a suggested filename.
- std::string referrer_charset;
- // The download file save info.
- DownloadSaveInfo save_info;
-};
-
-#endif // CHROME_BROWSER_HISTORY_DOWNLOAD_TYPES_H_
diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc
index bd471ad..294c0e6 100644
--- a/chrome/browser/history/expire_history_backend.cc
+++ b/chrome/browser/history/expire_history_backend.cc
@@ -512,7 +512,7 @@ void ExpireHistoryBackend::ExpireURLsForVisits(
void ExpireHistoryBackend::ArchiveURLsAndVisits(
const VisitVector& visits,
DeleteDependencies* dependencies) {
- if (!archived_db_)
+ if (!archived_db_ || !main_db_)
return;
// Make sure all unique URL rows are added to the dependency list and the
@@ -539,6 +539,12 @@ void ExpireHistoryBackend::ArchiveURLsAndVisits(
}
}
+ // Retrieve the sources for all the archived visits before archiving.
+ // The returned visit_sources vector should contain the source for each visit
+ // from visits at the same index.
+ VisitSourceMap visit_sources;
+ main_db_->GetVisitsSource(visits, &visit_sources);
+
// Now archive the visits since we know the URL ID to make them reference.
// The source visit list should still reference the visits in the main DB, but
// we will update it to reflect only the visits that were successfully
@@ -550,7 +556,9 @@ void ExpireHistoryBackend::ArchiveURLsAndVisits(
VisitRow cur_visit(visits[i]);
cur_visit.url_id = main_id_to_archived_id[cur_visit.url_id];
cur_visit.referring_visit = 0;
- archived_db_->AddVisit(&cur_visit);
+ VisitSourceMap::iterator iter = visit_sources.find(visits[i].visit_id);
+ archived_db_->AddVisit(&cur_visit,
+ iter == visit_sources.end() ? SOURCE_BROWSED : iter->second);
// Ignore failures, we will delete it from the main DB no matter what.
}
}
diff --git a/chrome/browser/history/expire_history_backend.h b/chrome/browser/history/expire_history_backend.h
index 9f060ed..96e2e9a 100644
--- a/chrome/browser/history/expire_history_backend.h
+++ b/chrome/browser/history/expire_history_backend.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_
#define CHROME_BROWSER_HISTORY_EXPIRE_HISTORY_BACKEND_H_
+#pragma once
#include <queue>
#include <set>
@@ -105,6 +106,7 @@ class ExpireHistoryBackend {
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, DeleteFaviconsIfPossible);
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ArchiveSomeOldHistory);
FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpiringVisitsReader);
+ FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ArchiveSomeOldHistoryWithSource);
friend class ::TestingProfile;
struct DeleteDependencies;
diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc
index ca822bc..91129ed 100644
--- a/chrome/browser/history/expire_history_backend_unittest.cc
+++ b/chrome/browser/history/expire_history_backend_unittest.cc
@@ -8,6 +8,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/history/archived_database.h"
@@ -16,8 +17,10 @@
#include "chrome/browser/history/history_notifications.h"
#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"
#include "gfx/codec/jpeg_codec.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -53,6 +56,8 @@ class ExpireHistoryTest : public testing::Test,
protected:
// Called by individual tests when they want data populated.
void AddExampleData(URLID url_ids[3], Time visit_times[4]);
+ // Add visits with source information.
+ void AddExampleSourceData(const GURL& url, URLID* id);
// Returns true if the given favicon/thumanil has an entry in the DB.
bool HasFavIcon(FavIconID favicon_id);
@@ -75,7 +80,7 @@ class ExpireHistoryTest : public testing::Test,
void StarURL(const GURL& url) {
bookmark_model_.AddURL(
- bookmark_model_.GetBookmarkBarNode(), 0, std::wstring(), url);
+ bookmark_model_.GetBookmarkBarNode(), 0, string16(), url);
}
static bool IsStringInFile(const FilePath& filename, const char* str);
@@ -90,6 +95,8 @@ class ExpireHistoryTest : public testing::Test,
scoped_ptr<ArchivedDatabase> archived_db_;
scoped_ptr<ThumbnailDatabase> thumb_db_;
scoped_ptr<TextDatabaseManager> text_db_;
+ TestingProfile profile_;
+ scoped_refptr<TopSites> top_sites_;
// Time at the beginning of the test, so everybody agrees what "now" is.
const Time now_;
@@ -134,6 +141,7 @@ class ExpireHistoryTest : public testing::Test,
expirer_.SetDatabases(main_db_.get(), archived_db_.get(), thumb_db_.get(),
text_db_.get());
+ top_sites_ = profile_.GetTopSites();
}
void TearDown() {
@@ -145,6 +153,7 @@ class ExpireHistoryTest : public testing::Test,
archived_db_.reset();
thumb_db_.reset();
text_db_.reset();
+ TopSites::DeleteTopSites(top_sites_);
file_util::Delete(dir_, true);
}
@@ -211,35 +220,35 @@ void ExpireHistoryTest::AddExampleData(URLID url_ids[3], Time visit_times[4]) {
Time time;
GURL gurl;
- thumb_db_->SetPageThumbnail(gurl, url_ids[0], *thumbnail, score, time);
- thumb_db_->SetPageThumbnail(gurl, url_ids[1], *thumbnail, score, time);
- thumb_db_->SetPageThumbnail(gurl, url_ids[2], *thumbnail, score, time);
+ top_sites_->SetPageThumbnail(url_row1.url(), *thumbnail, score);
+ top_sites_->SetPageThumbnail(url_row2.url(), *thumbnail, score);
+ top_sites_->SetPageThumbnail(url_row3.url(), *thumbnail, score);
// Four visits.
VisitRow visit_row1;
visit_row1.url_id = url_ids[0];
visit_row1.visit_time = visit_times[0];
visit_row1.is_indexed = true;
- main_db_->AddVisit(&visit_row1);
+ main_db_->AddVisit(&visit_row1, SOURCE_BROWSED);
VisitRow visit_row2;
visit_row2.url_id = url_ids[1];
visit_row2.visit_time = visit_times[1];
visit_row2.is_indexed = true;
- main_db_->AddVisit(&visit_row2);
+ main_db_->AddVisit(&visit_row2, SOURCE_BROWSED);
VisitRow visit_row3;
visit_row3.url_id = url_ids[1];
visit_row3.visit_time = visit_times[2];
visit_row3.is_indexed = true;
visit_row3.transition = PageTransition::TYPED;
- main_db_->AddVisit(&visit_row3);
+ main_db_->AddVisit(&visit_row3, SOURCE_BROWSED);
VisitRow visit_row4;
visit_row4.url_id = url_ids[2];
visit_row4.visit_time = visit_times[3];
visit_row4.is_indexed = true;
- main_db_->AddVisit(&visit_row4);
+ main_db_->AddVisit(&visit_row4, SOURCE_BROWSED);
// Full text index for each visit.
text_db_->AddPageData(url_row1.url(), visit_row1.url_id, visit_row1.visit_id,
@@ -260,6 +269,35 @@ void ExpireHistoryTest::AddExampleData(URLID url_ids[3], Time visit_times[4]) {
UTF8ToUTF16("goats body"));
}
+void ExpireHistoryTest::AddExampleSourceData(const GURL& url, URLID* id) {
+ if (!main_db_.get())
+ return;
+
+ Time last_visit_time = Time::Now();
+ // Add one URL.
+ URLRow url_row1(url);
+ url_row1.set_last_visit(last_visit_time);
+ url_row1.set_visit_count(4);
+ URLID url_id = main_db_->AddURL(url_row1);
+ *id = url_id;
+
+ // Four times for each visit.
+ VisitRow visit_row1(url_id, last_visit_time - TimeDelta::FromDays(4), 0,
+ PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row1, SOURCE_SYNCED);
+
+ VisitRow visit_row2(url_id, last_visit_time - TimeDelta::FromDays(3), 0,
+ PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row2, SOURCE_BROWSED);
+
+ VisitRow visit_row3(url_id, last_visit_time - TimeDelta::FromDays(2), 0,
+ PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row3, SOURCE_EXTENSION);
+
+ VisitRow visit_row4(url_id, last_visit_time, 0, PageTransition::TYPED, 0);
+ main_db_->AddVisit(&visit_row4, SOURCE_FIREFOX_IMPORTED);
+}
+
bool ExpireHistoryTest::HasFavIcon(FavIconID favicon_id) {
if (!thumb_db_.get())
return false;
@@ -271,8 +309,12 @@ bool ExpireHistoryTest::HasFavIcon(FavIconID favicon_id) {
}
bool ExpireHistoryTest::HasThumbnail(URLID url_id) {
- std::vector<unsigned char> temp_data;
- return thumb_db_->GetPageThumbnail(url_id, &temp_data);
+ URLRow info;
+ if (!main_db_->GetURLRow(url_id, &info))
+ return false;
+ GURL url = info.url();
+ RefCountedBytes *data;
+ return top_sites_->GetPageThumbnail(url, &data);
}
int ExpireHistoryTest::CountTextMatchesForURL(const GURL& url) {
@@ -507,7 +549,7 @@ TEST_F(ExpireHistoryTest, DontDeleteStarredURL) {
ASSERT_TRUE(HasThumbnail(url_row.id()));
// Unstar the URL and delete again.
- bookmark_model_.SetURLStarred(url, std::wstring(), false);
+ bookmark_model_.SetURLStarred(url, string16(), false);
expirer_.DeleteURL(url);
// Now it should be completely deleted.
@@ -804,8 +846,52 @@ TEST_F(ExpireHistoryTest, ExpiringVisitsReader) {
EXPECT_EQ(1U, visits.size());
}
+// Tests how ArchiveSomeOldHistory treats source information.
+TEST_F(ExpireHistoryTest, ArchiveSomeOldHistoryWithSource) {
+ const GURL url("www.testsource.com");
+ URLID url_id;
+ AddExampleSourceData(url, &url_id);
+ const ExpiringVisitsReader* reader = expirer_.GetAllVisitsReader();
+
+ // Archiving all the visits we added.
+ ASSERT_FALSE(expirer_.ArchiveSomeOldHistory(Time::Now(), reader, 10));
+
+ URLRow archived_row;
+ ASSERT_TRUE(archived_db_->GetRowForURL(url, &archived_row));
+ VisitVector archived_visits;
+ archived_db_->GetVisitsForURL(archived_row.id(), &archived_visits);
+ ASSERT_EQ(4U, archived_visits.size());
+ VisitSourceMap sources;
+ archived_db_->GetVisitsSource(archived_visits, &sources);
+ ASSERT_EQ(3U, sources.size());
+ int result = 0;
+ VisitSourceMap::iterator iter;
+ for (int i = 0; i < 4; i++) {
+ iter = sources.find(archived_visits[i].visit_id);
+ if (iter == sources.end())
+ continue;
+ switch (iter->second) {
+ case history::SOURCE_EXTENSION:
+ result |= 0x1;
+ break;
+ case history::SOURCE_FIREFOX_IMPORTED:
+ result |= 0x2;
+ break;
+ case history::SOURCE_SYNCED:
+ result |= 0x4;
+ default:
+ break;
+ }
+ }
+ EXPECT_EQ(0x7, result);
+ main_db_->GetVisitsSource(archived_visits, &sources);
+ EXPECT_EQ(0U, sources.size());
+ main_db_->GetVisitsForURL(url_id, &archived_visits);
+ EXPECT_EQ(0U, archived_visits.size());
+}
+
// TODO(brettw) add some visits with no URL to make sure everything is updated
-// properly. Have the visits also refer to nonexistant FTS rows.
+// properly. Have the visits also refer to nonexistent FTS rows.
//
// Maybe also refer to invalid favicons.
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc
index 0b92b6f..d70fd85 100644
--- a/chrome/browser/history/history.cc
+++ b/chrome/browser/history/history.cc
@@ -24,18 +24,18 @@
#include "chrome/browser/history/history.h"
-#include "app/l10n_util.h"
#include "base/callback.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/ref_counted.h"
+#include "base/string_util.h"
#include "base/task.h"
#include "chrome/browser/autocomplete/history_url_provider.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/history/download_types.h"
+#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/history/history_backend.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/history_types.h"
@@ -222,6 +222,16 @@ history::URLDatabase* HistoryService::InMemoryDatabase() {
return NULL;
}
+history::InMemoryURLIndex* HistoryService::InMemoryIndex() {
+ // NOTE: See comments in BackendLoaded() as to why we call
+ // LoadBackendIfNecessary() here even though it won't affect the return value
+ // for this call.
+ LoadBackendIfNecessary();
+ if (in_memory_backend_.get())
+ return in_memory_backend_->index();
+ return NULL;
+}
+
void HistoryService::SetSegmentPresentationIndex(int64 segment_id, int index) {
ScheduleAndForget(PRIORITY_UI,
&HistoryBackend::SetSegmentPresentationIndex,
@@ -229,7 +239,7 @@ void HistoryService::SetSegmentPresentationIndex(int64 segment_id, int index) {
}
void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& term) {
ScheduleAndForget(PRIORITY_UI,
&HistoryBackend::SetKeywordSearchTermsForURL,
@@ -237,14 +247,14 @@ void HistoryService::SetKeywordSearchTermsForURL(const GURL& url,
}
void HistoryService::DeleteAllSearchTermsForKeyword(
- TemplateURL::IDType keyword_id) {
+ TemplateURLID keyword_id) {
ScheduleAndForget(PRIORITY_UI,
&HistoryBackend::DeleteAllSearchTermsForKeyword,
keyword_id);
}
HistoryService::Handle HistoryService::GetMostRecentKeywordSearchTerms(
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& prefix,
int max_count,
CancelableRequestConsumerBase* consumer,
@@ -291,9 +301,10 @@ void HistoryService::AddPage(const GURL& url,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry) {
AddPage(url, Time::Now(), id_scope, page_id, referrer, transition, redirects,
- did_replace_entry);
+ visit_source, did_replace_entry);
}
void HistoryService::AddPage(const GURL& url,
@@ -303,37 +314,45 @@ void HistoryService::AddPage(const GURL& url,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry) {
+ scoped_refptr<history::HistoryAddPageArgs> request(
+ new history::HistoryAddPageArgs(url, time, id_scope, page_id, referrer,
+ redirects, transition, visit_source,
+ did_replace_entry));
+ AddPage(*request);
+}
+
+void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) {
DCHECK(thread_) << "History service being called after cleanup";
// Filter out unwanted URLs. We don't add auto-subframe URLs. They are a
// large part of history (think iframes for ads) and we never display them in
// history UI. We will still add manual subframes, which are ones the user
// has clicked on to get.
- if (!CanAddURL(url))
+ if (!CanAddURL(add_page_args.url))
return;
// Add link & all redirects to visited link list.
VisitedLinkMaster* visited_links;
if (profile_ && (visited_links = profile_->GetVisitedLinkMaster())) {
- visited_links->AddURL(url);
+ visited_links->AddURL(add_page_args.url);
- if (!redirects.empty()) {
+ if (!add_page_args.redirects.empty()) {
// We should not be asked to add a page in the middle of a redirect chain.
- DCHECK(redirects[redirects.size() - 1] == url);
+ DCHECK_EQ(add_page_args.url,
+ add_page_args.redirects[add_page_args.redirects.size() - 1]);
// We need the !redirects.empty() condition above since size_t is unsigned
// and will wrap around when we subtract one from a 0 size.
- for (size_t i = 0; i < redirects.size() - 1; i++)
- visited_links->AddURL(redirects[i]);
+ for (size_t i = 0; i < add_page_args.redirects.size() - 1; i++)
+ visited_links->AddURL(add_page_args.redirects[i]);
}
}
- scoped_refptr<history::HistoryAddPageArgs> request(
- new history::HistoryAddPageArgs(url, time, id_scope, page_id,
- referrer, redirects, transition,
- did_replace_entry));
- ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage, request);
+ ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::AddPage,
+ scoped_refptr<history::HistoryAddPageArgs>(
+ add_page_args.Clone()));
}
void HistoryService::SetPageTitle(const GURL& url,
@@ -346,7 +365,8 @@ void HistoryService::AddPageWithDetails(const GURL& url,
int visit_count,
int typed_count,
Time last_visit,
- bool hidden) {
+ bool hidden,
+ history::VisitSource visit_source) {
// Filter out unwanted URLs.
if (!CanAddURL(url))
return;
@@ -367,11 +387,12 @@ void HistoryService::AddPageWithDetails(const GURL& url,
rows.push_back(row);
ScheduleAndForget(PRIORITY_NORMAL,
- &HistoryBackend::AddPagesWithDetails, rows);
+ &HistoryBackend::AddPagesWithDetails, rows, visit_source);
}
void HistoryService::AddPagesWithDetails(
- const std::vector<history::URLRow>& info) {
+ const std::vector<history::URLRow>& info,
+ history::VisitSource visit_source) {
// Add to the visited links system.
VisitedLinkMaster* visited_links;
@@ -387,7 +408,7 @@ void HistoryService::AddPagesWithDetails(
}
ScheduleAndForget(PRIORITY_NORMAL,
- &HistoryBackend::AddPagesWithDetails, info);
+ &HistoryBackend::AddPagesWithDetails, info, visit_source);
}
void HistoryService::SetPageContents(const GURL& url,
@@ -529,14 +550,6 @@ void HistoryService::RemoveDownloadsBetween(Time remove_begin,
remove_end);
}
-HistoryService::Handle HistoryService::SearchDownloads(
- const string16& search_text,
- CancelableRequestConsumerBase* consumer,
- DownloadSearchCallback* callback) {
- return Schedule(PRIORITY_NORMAL, &HistoryBackend::SearchDownloads, consumer,
- new history::DownloadSearchRequest(callback), search_text);
-}
-
HistoryService::Handle HistoryService::QueryHistory(
const string16& text_query,
const history::QueryOptions& options,
@@ -744,7 +757,6 @@ void HistoryService::LoadBackendIfNecessary() {
}
void HistoryService::OnDBLoaded() {
- LOG(INFO) << "History backend finished loading";
backend_loaded_ = true;
NotificationService::current()->Notify(NotificationType::HISTORY_LOADED,
Source<Profile>(profile_),
diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h
index 9548f65..3d24981 100644
--- a/chrome/browser/history/history.h
+++ b/chrome/browser/history/history.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_HISTORY_HISTORY_H_
#define CHROME_BROWSER_HISTORY_HISTORY_H_
+#pragma once
-#include <string>
#include <vector>
#include "base/basictypes.h"
@@ -18,7 +18,7 @@
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_id.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/ref_counted_util.h"
@@ -48,14 +48,14 @@ class TypedUrlDataTypeController;
}
namespace history {
-
class InMemoryHistoryBackend;
+class InMemoryURLIndex;
+class HistoryAddPageArgs;
class HistoryBackend;
class HistoryDatabase;
struct HistoryDetails;
class HistoryQueryTest;
class URLDatabase;
-
} // namespace history
@@ -150,6 +150,8 @@ class HistoryService : public CancelableRequestProvider,
// TODO(brettw) this should return the InMemoryHistoryBackend.
history::URLDatabase* InMemoryDatabase();
+ history::InMemoryURLIndex* InMemoryIndex();
+
// Navigation ----------------------------------------------------------------
// Adds the given canonical URL to history with the current time as the visit
@@ -182,6 +184,7 @@ class HistoryService : public CancelableRequestProvider,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry);
// For adding pages to history with a specific time. This is for testing
@@ -193,14 +196,18 @@ class HistoryService : public CancelableRequestProvider,
const GURL& referrer,
PageTransition::Type transition,
const history::RedirectList& redirects,
+ history::VisitSource visit_source,
bool did_replace_entry);
// For adding pages to history where no tracking information can be done.
- void AddPage(const GURL& url) {
- AddPage(url, NULL, 0, GURL(), PageTransition::LINK, history::RedirectList(),
- false);
+ void AddPage(const GURL& url, history::VisitSource visit_source) {
+ AddPage(url, NULL, 0, GURL(), PageTransition::LINK,
+ history::RedirectList(), visit_source, false);
}
+ // All AddPage variants end up here.
+ void AddPage(const history::HistoryAddPageArgs& add_page_args);
+
// 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
@@ -442,15 +449,6 @@ class HistoryService : public CancelableRequestProvider,
// both directions.
void RemoveDownloadsBetween(base::Time remove_begin, base::Time remove_end);
- // Implemented by the caller of 'SearchDownloads' below, and is called when
- // the history system has retrieved the search results.
- typedef Callback2<Handle, std::vector<int64>*>::Type DownloadSearchCallback;
-
- // Search for downloads that match the search text.
- Handle SearchDownloads(const string16& search_text,
- CancelableRequestConsumerBase* consumer,
- DownloadSearchCallback* callback);
-
// Visit Segments ------------------------------------------------------------
typedef Callback2<Handle, std::vector<PageUsageData*>*>::Type
@@ -482,11 +480,11 @@ class HistoryService : public CancelableRequestProvider,
// Sets the search terms for the specified url and keyword. url_id gives the
// id of the url, keyword_id the id of the keyword and term the search term.
void SetKeywordSearchTermsForURL(const GURL& url,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& term);
// Deletes all search terms for the specified keyword.
- void DeleteAllSearchTermsForKeyword(TemplateURL::IDType keyword_id);
+ void DeleteAllSearchTermsForKeyword(TemplateURLID keyword_id);
typedef Callback2<Handle, std::vector<history::KeywordSearchTermVisit>*>::Type
GetMostRecentKeywordSearchTermsCallback;
@@ -496,7 +494,7 @@ class HistoryService : public CancelableRequestProvider,
// in descending order up to |max_count| with the most recent search term
// first.
Handle GetMostRecentKeywordSearchTerms(
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& prefix,
int max_count,
CancelableRequestConsumerBase* consumer,
@@ -541,10 +539,12 @@ class HistoryService : public CancelableRequestProvider,
int visit_count,
int typed_count,
base::Time last_visit,
- bool hidden);
+ bool hidden,
+ history::VisitSource visit_source);
// The same as AddPageWithDetails() but takes a vector.
- void AddPagesWithDetails(const std::vector<history::URLRow>& info);
+ void AddPagesWithDetails(const std::vector<history::URLRow>& info,
+ history::VisitSource visit_source);
// Starts the TopSites migration in the HistoryThread. Called by the
// BackendDelegate.
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 0f512db..237b14b 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -17,11 +17,12 @@
#include "base/time.h"
#include "chrome/browser/autocomplete/history_url_provider.h"
#include "chrome/browser/bookmarks/bookmark_service.h"
-#include "chrome/browser/history/download_types.h"
+#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/history_publisher.h"
#include "chrome/browser/history/in_memory_history_backend.h"
#include "chrome/browser/history/page_usage_data.h"
+#include "chrome/browser/history/top_sites.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_type.h"
@@ -362,8 +363,6 @@ SegmentID HistoryBackend::UpdateSegments(const GURL& url,
}
void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
- DLOG(INFO) << "Adding page " << request->url.possibly_invalid_spec();
-
if (!db_.get())
return;
@@ -405,7 +404,7 @@ void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
// No redirect case (one element means just the page itself).
last_ids = AddPageVisit(request->url, last_recorded_time_,
- last_ids.second, t);
+ last_ids.second, t, request->visit_source);
// Update the segment for this visit. KEYWORD_GENERATED visits should not
// result in changing most visited, so we don't update segments (most
@@ -471,7 +470,8 @@ void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
// them anyway, and if we ever decide to, we can reconstruct their order
// from the redirect chain.
last_ids = AddPageVisit(request->redirects[redirect_index],
- last_recorded_time_, last_ids.second, t);
+ last_recorded_time_, last_ids.second,
+ t, request->visit_source);
if (t & PageTransition::CHAIN_START) {
// Update the segment for this visit.
UpdateSegments(request->redirects[redirect_index],
@@ -548,7 +548,7 @@ void HistoryBackend::InitImpl() {
// Fill the in-memory database and send it back to the history service on the
// main thread.
InMemoryHistoryBackend* mem_backend = new InMemoryHistoryBackend;
- if (mem_backend->Init(history_name))
+ if (mem_backend->Init(history_name, db_.get()))
delegate_->SetInMemoryBackend(mem_backend); // Takes ownership of pointer.
else
delete mem_backend; // Error case, run without the in-memory DB.
@@ -581,11 +581,12 @@ void HistoryBackend::InitImpl() {
// Thumbnail database.
thumbnail_db_.reset(new ThumbnailDatabase());
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTopSites)) {
- if (!db_->needs_version_18_migration()) {
- // No convertion needed - use new filename right away.
- thumbnail_name = GetFaviconsFileName();
- }
+ if (history::TopSites::IsEnabled()) {
+ // TODO(sky): once we reenable top sites this needs to be fixed.
+ // if (!db_->needs_version_18_migration()) {
+ // No convertion needed - use new filename right away.
+ // thumbnail_name = GetFaviconsFileName();
+ // }
}
if (thumbnail_db_->Init(thumbnail_name,
history_publisher_.get()) != sql::INIT_OK) {
@@ -598,11 +599,12 @@ void HistoryBackend::InitImpl() {
thumbnail_db_.reset();
}
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTopSites)) {
- if (db_->needs_version_18_migration()) {
- LOG(INFO) << "Starting TopSites migration";
- delegate_->StartTopSitesMigration();
- }
+ if (history::TopSites::IsEnabled()) {
+ // TODO(sky): fix when reenabling top sites migration.
+ // if (db_->needs_version_18_migration()) {
+ // LOG(INFO) << "Starting TopSites migration";
+ // delegate_->StartTopSitesMigration();
+ // }
}
// Archived database.
@@ -651,7 +653,8 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
const GURL& url,
Time time,
VisitID referring_visit,
- PageTransition::Type transition) {
+ PageTransition::Type transition,
+ VisitSource visit_source) {
// Top-level frame navigations are visible, everything else is hidden
bool new_hidden = !PageTransition::IsMainFrame(transition);
@@ -708,7 +711,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
// Add the visit with the time to the database.
VisitRow visit_info(url_id, time, referring_visit, transition, 0);
- VisitID visit_id = db_->AddVisit(&visit_info);
+ VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
if (visit_info.visit_time < first_recorded_time_)
first_recorded_time_ = visit_info.visit_time;
@@ -727,7 +730,8 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
return std::make_pair(url_id, visit_id);
}
-void HistoryBackend::AddPagesWithDetails(const std::vector<URLRow>& urls) {
+void HistoryBackend::AddPagesWithDetails(const std::vector<URLRow>& urls,
+ VisitSource visit_source) {
if (!db_.get())
return;
@@ -789,7 +793,7 @@ void HistoryBackend::AddPagesWithDetails(const std::vector<URLRow>& urls) {
PageTransition::LINK | PageTransition::CHAIN_START |
PageTransition::CHAIN_END, 0);
visit_info.is_indexed = has_indexed;
- if (!visit_database->AddVisit(&visit_info)) {
+ if (!visit_database->AddVisit(&visit_info, visit_source)) {
NOTREACHED() << "Adding visit failed.";
return;
}
@@ -906,11 +910,12 @@ bool HistoryBackend::UpdateURL(URLID id, const history::URLRow& url) {
}
bool HistoryBackend::AddVisits(const GURL& url,
- const std::vector<base::Time>& visits) {
+ const std::vector<base::Time>& visits,
+ VisitSource visit_source) {
if (db_.get()) {
for (std::vector<base::Time>::const_iterator visit = visits.begin();
visit != visits.end(); ++visit) {
- if (!AddPageVisit(url, *visit, 0, 0).first) {
+ if (!AddPageVisit(url, *visit, 0, 0, visit_source).first) {
return false;
}
}
@@ -1022,7 +1027,7 @@ void HistoryBackend::QuerySegmentUsage(
// Keyword visits --------------------------------------------------------------
void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& term) {
if (!db_.get())
return;
@@ -1040,7 +1045,7 @@ void HistoryBackend::SetKeywordSearchTermsForURL(const GURL& url,
}
void HistoryBackend::DeleteAllSearchTermsForKeyword(
- TemplateURL::IDType keyword_id) {
+ TemplateURLID keyword_id) {
if (!db_.get())
return;
@@ -1051,7 +1056,7 @@ void HistoryBackend::DeleteAllSearchTermsForKeyword(
void HistoryBackend::GetMostRecentKeywordSearchTerms(
scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& prefix,
int max_count) {
if (request->canceled())
@@ -1126,17 +1131,6 @@ void HistoryBackend::RemoveDownloadsBetween(const Time remove_begin,
db_->RemoveDownloadsBetween(remove_begin, remove_end);
}
-void HistoryBackend::SearchDownloads(
- scoped_refptr<DownloadSearchRequest> request,
- const string16& search_text) {
- if (request->canceled())
- return;
- if (db_.get())
- db_->SearchDownloads(&request->value, search_text);
- request->ForwardResult(DownloadSearchRequest::TupleType(request->handle(),
- &request->value));
-}
-
void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
const string16& text_query,
const QueryOptions& options) {
@@ -2156,9 +2150,16 @@ BookmarkService* HistoryBackend::GetBookmarkService() {
}
void HistoryBackend::MigrateThumbnailsDatabase() {
- thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
- GetFaviconsFileName());
- db_->MigrationToTopSitesDone();
+ // If there is no History DB, we can't record that the migration was done.
+ // It will be recorded on the next run.
+ if (db_.get()) {
+ // If there is no thumbnail DB, we can still record a successful migration.
+ if (thumbnail_db_.get()) {
+ thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
+ GetFaviconsFileName());
+ }
+ db_->MigrationToTopSitesDone();
+ }
}
} // namespace history
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index cbda2e9..f3e76cf 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_HISTORY_BACKEND_H_
#define CHROME_BROWSER_HISTORY_HISTORY_BACKEND_H_
+#pragma once
#include <utility>
@@ -11,7 +12,6 @@
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/history/archived_database.h"
-#include "chrome/browser/history/download_types.h"
#include "chrome/browser/history/expire_history_backend.h"
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/history/history_marshaling.h"
@@ -19,9 +19,11 @@
#include "chrome/browser/history/text_database_manager.h"
#include "chrome/browser/history/thumbnail_database.h"
#include "chrome/browser/history/visit_tracker.h"
+#include "chrome/browser/search_engines/template_url_id.h"
#include "chrome/common/mru_cache.h"
class BookmarkService;
+struct DownloadCreateInfo;
class TestingProfile;
struct ThumbnailScore;
@@ -224,8 +226,6 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
void RemoveDownloadsBetween(const base::Time remove_begin,
const base::Time remove_end);
void RemoveDownloads(const base::Time remove_end);
- void SearchDownloads(scoped_refptr<DownloadSearchRequest>,
- const string16& search_text);
// Segment usage -------------------------------------------------------------
@@ -238,14 +238,14 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Keyword search terms ------------------------------------------------------
void SetKeywordSearchTermsForURL(const GURL& url,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& term);
- void DeleteAllSearchTermsForKeyword(TemplateURL::IDType keyword_id);
+ void DeleteAllSearchTermsForKeyword(TemplateURLID keyword_id);
void GetMostRecentKeywordSearchTerms(
scoped_refptr<GetMostRecentKeywordSearchTermsRequest> request,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& prefix,
int max_count);
@@ -259,8 +259,10 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
virtual bool UpdateURL(URLID id, const history::URLRow& url);
+ // While adding visits in batch, the source needs to be provided.
virtual bool AddVisits(const GURL& url,
- const std::vector<base::Time>& visits);
+ const std::vector<base::Time>& visits,
+ VisitSource visit_source);
virtual bool RemoveVisits(const VisitVector& visits);
@@ -293,7 +295,9 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Adds the given rows to the database if it doesn't exist. A visit will be
// added for each given URL at the last visit time in the URLRow.
- void AddPagesWithDetails(const std::vector<URLRow>& info);
+ // Each visit will have the visit_source type set.
+ void AddPagesWithDetails(const std::vector<URLRow>& info,
+ VisitSource visit_source);
#if defined(UNIT_TEST)
HistoryDatabase* db() const { return db_.get(); }
@@ -313,6 +317,11 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, URLsNoLongerBookmarked);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, StripUsernamePasswordTest);
FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, DeleteThumbnailsDatabaseTest);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddPageVisitSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddPageArgsSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, AddVisitsSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, RemoveVisitsSource);
+ FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MigrationVisitSource);
friend class ::TestingProfile;
// Computes the name of the specified database on disk.
@@ -340,7 +349,8 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
std::pair<URLID, VisitID> AddPageVisit(const GURL& url,
base::Time time,
VisitID referring_visit,
- PageTransition::Type transition);
+ PageTransition::Type transition,
+ VisitSource visit_source);
// Returns a redirect chain in |redirects| for the VisitID
// |cur_visit|. |cur_visit| is assumed to be valid. Assumes that
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index 24cc1cd..907b7b6 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -4,15 +4,21 @@
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/command_line.h"
#include "base/path_service.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/history/history_backend.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/in_memory_history_backend.h"
#include "chrome/browser/history/in_memory_database.h"
+#include "chrome/browser/history/top_sites.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/thumbnail_score.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
@@ -72,7 +78,7 @@ class HistoryBackendTest : public testing::Test {
scoped_refptr<history::HistoryAddPageArgs> request(
new history::HistoryAddPageArgs(
redirects.back(), Time::Now(), scope, page_id, GURL(),
- redirects, PageTransition::LINK, true));
+ redirects, PageTransition::LINK, history::SOURCE_BROWSED, true));
backend_->AddPage(request);
}
@@ -92,7 +98,8 @@ class HistoryBackendTest : public testing::Test {
redirects.push_back(url2);
scoped_refptr<HistoryAddPageArgs> request(
new HistoryAddPageArgs(url2, base::Time(), dummy_scope, 0, url1,
- redirects, PageTransition::CLIENT_REDIRECT, did_replace));
+ redirects, PageTransition::CLIENT_REDIRECT,
+ history::SOURCE_BROWSED, did_replace));
backend_->AddPage(request);
*transition1 = getTransition(url1);
@@ -109,6 +116,10 @@ class HistoryBackendTest : public testing::Test {
return visits[0].transition;
}
+ FilePath getTestDir() {
+ return test_dir_;
+ }
+
BookmarkModel bookmark_model_;
protected:
@@ -212,7 +223,7 @@ TEST_F(HistoryBackendTest, DeleteAll) {
std::vector<URLRow> rows;
rows.push_back(row2); // Reversed order for the same reason as favicons.
rows.push_back(row1);
- backend_->AddPagesWithDetails(rows);
+ backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
@@ -250,7 +261,7 @@ TEST_F(HistoryBackendTest, DeleteAll) {
// Star row1.
bookmark_model_.AddURL(
- bookmark_model_.GetBookmarkBarNode(), 0, std::wstring(), row1.url());
+ bookmark_model_.GetBookmarkBarNode(), 0, string16(), row1.url());
// Set full text index for each one.
backend_->text_database_->AddPageData(row1.url(), row1_id, visit1_id,
@@ -342,14 +353,14 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
std::vector<URLRow> rows;
rows.push_back(row2); // Reversed order for the same reason as favicons.
rows.push_back(row1);
- backend_->AddPagesWithDetails(rows);
+ backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
URLID row1_id = backend_->db_->GetRowForURL(row1.url(), NULL);
URLID row2_id = backend_->db_->GetRowForURL(row2.url(), NULL);
// Star the two URLs.
- bookmark_model_.SetURLStarred(row1.url(), std::wstring(), true);
- bookmark_model_.SetURLStarred(row2.url(), std::wstring(), true);
+ bookmark_model_.SetURLStarred(row1.url(), string16(), true);
+ bookmark_model_.SetURLStarred(row2.url(), string16(), true);
// Delete url 2. Because url 2 is starred this won't delete the URL, only
// the visits.
@@ -366,7 +377,7 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2));
// Unstar row2.
- bookmark_model_.SetURLStarred(row2.url(), std::wstring(), false);
+ bookmark_model_.SetURLStarred(row2.url(), string16(), false);
// Tell the backend it was unstarred. We have to explicitly do this as
// BookmarkModel isn't wired up to the backend during testing.
std::set<GURL> unstarred_urls;
@@ -380,7 +391,7 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
backend_->thumbnail_db_->GetFavIconIDForFavIconURL(favicon_url2));
// Unstar row 1.
- bookmark_model_.SetURLStarred(row1.url(), std::wstring(), false);
+ bookmark_model_.SetURLStarred(row1.url(), string16(), false);
// Tell the backend it was unstarred. We have to explicitly do this as
// BookmarkModel isn't wired up to the backend during testing.
unstarred_urls.clear();
@@ -402,6 +413,8 @@ TEST_F(HistoryBackendTest, URLsNoLongerBookmarked) {
TEST_F(HistoryBackendTest, GetPageThumbnailAfterRedirects) {
ASSERT_TRUE(backend_.get());
+ if (history::TopSites::IsEnabled())
+ return;
const char* base_url = "http://mail";
const char* thumbnail_url = "http://mail.google.com";
@@ -448,7 +461,8 @@ TEST_F(HistoryBackendTest, KeywordGenerated) {
scoped_refptr<HistoryAddPageArgs> request(
new HistoryAddPageArgs(url, visit_time, NULL, 0, GURL(),
history::RedirectList(),
- PageTransition::KEYWORD_GENERATED, false));
+ PageTransition::KEYWORD_GENERATED,
+ history::SOURCE_BROWSED, false));
backend_->AddPage(request);
// A row should have been added for the url.
@@ -531,7 +545,7 @@ TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
std::vector<URLRow> rows;
rows.push_back(row1);
rows.push_back(row2);
- backend_->AddPagesWithDetails(rows);
+ backend_->AddPagesWithDetails(rows, history::SOURCE_BROWSED);
URLRow url_row1, url_row2;
EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &url_row1) == 0);
EXPECT_FALSE(backend_->db_->GetRowForURL(row2.url(), &url_row2) == 0);
@@ -568,8 +582,8 @@ TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
EXPECT_TRUE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
// If the URL is bookmarked, it should get added to history with 0 visits.
- bookmark_model_.AddURL(bookmark_model_.GetBookmarkBarNode(), 0,
- std::wstring(), url3);
+ bookmark_model_.AddURL(bookmark_model_.GetBookmarkBarNode(), 0, string16(),
+ url3);
backend_->SetImportedFavicons(favicons);
EXPECT_FALSE(backend_->db_->GetRowForURL(url3, &url_row3) == 0);
EXPECT_TRUE(url_row3.visit_count() == 0);
@@ -586,7 +600,8 @@ TEST_F(HistoryBackendTest, StripUsernamePasswordTest) {
// Visit the url with username, password.
backend_->AddPageVisit(url, base::Time::Now(), 0,
- PageTransition::GetQualifier(PageTransition::TYPED));
+ PageTransition::GetQualifier(PageTransition::TYPED),
+ history::SOURCE_BROWSED);
// Fetch the row information about stripped url from history db.
VisitVector visits;
@@ -598,9 +613,222 @@ TEST_F(HistoryBackendTest, StripUsernamePasswordTest) {
}
TEST_F(HistoryBackendTest, DeleteThumbnailsDatabaseTest) {
+ if (history::TopSites::IsEnabled())
+ return;
+
EXPECT_TRUE(backend_->thumbnail_db_->NeedsMigrationToTopSites());
backend_->delegate_->StartTopSitesMigration();
EXPECT_FALSE(backend_->thumbnail_db_->NeedsMigrationToTopSites());
}
+TEST_F(HistoryBackendTest, AddPageVisitSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url("http://www.google.com");
+
+ // Clear all history.
+ backend_->DeleteAllHistory();
+
+ // Assume visiting the url from an externsion.
+ backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED,
+ history::SOURCE_EXTENSION);
+ // Assume the url is imported from Firefox.
+ backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED,
+ history::SOURCE_FIREFOX_IMPORTED);
+ // Assume this url is also synced.
+ backend_->AddPageVisit(url, base::Time::Now(), 0, PageTransition::TYPED,
+ history::SOURCE_SYNCED);
+
+ // Fetch the row information about the url from history db.
+ VisitVector visits;
+ URLID row_id = backend_->db_->GetRowForURL(url, NULL);
+ backend_->db_->GetVisitsForURL(row_id, &visits);
+
+ // Check if all the visits to the url are stored in database.
+ ASSERT_EQ(3U, visits.size());
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(3U, visit_sources.size());
+ int sources = 0;
+ for (int i = 0; i < 3; i++) {
+ switch (visit_sources[visits[i].visit_id]) {
+ case history::SOURCE_EXTENSION:
+ sources |= 0x1;
+ break;
+ case history::SOURCE_FIREFOX_IMPORTED:
+ sources |= 0x2;
+ break;
+ case history::SOURCE_SYNCED:
+ sources |= 0x4;
+ default:
+ break;
+ }
+ }
+ EXPECT_EQ(0x7, sources);
+}
+
+TEST_F(HistoryBackendTest, AddPageArgsSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url("http://testpageargs.com");
+
+ // Assume this page is browsed by user.
+ scoped_refptr<HistoryAddPageArgs> request1(
+ new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(),
+ history::RedirectList(),
+ PageTransition::KEYWORD_GENERATED,
+ history::SOURCE_BROWSED, false));
+ backend_->AddPage(request1);
+ // Assume this page is synced.
+ scoped_refptr<HistoryAddPageArgs> request2(
+ new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(),
+ history::RedirectList(),
+ PageTransition::LINK,
+ history::SOURCE_SYNCED, false));
+ backend_->AddPage(request2);
+ // Assume this page is browsed again.
+ scoped_refptr<HistoryAddPageArgs> request3(
+ new HistoryAddPageArgs(url, base::Time::Now(), NULL, 0, GURL(),
+ history::RedirectList(),
+ PageTransition::TYPED,
+ history::SOURCE_BROWSED, false));
+ backend_->AddPage(request3);
+
+ // Three visits should be added with proper sources.
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(3U, visits.size());
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(1U, visit_sources.size());
+ EXPECT_EQ(history::SOURCE_SYNCED, visit_sources.begin()->second);
+}
+
+TEST_F(HistoryBackendTest, AddVisitsSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url1("http://www.cnn.com");
+ std::vector<base::Time> visits1;
+ visits1.push_back(Time::Now() - base::TimeDelta::FromDays(5));
+ visits1.push_back(Time::Now() - base::TimeDelta::FromDays(1));
+ visits1.push_back(Time::Now());
+
+ GURL url2("http://www.example.com");
+ std::vector<base::Time> visits2;
+ visits2.push_back(Time::Now() - base::TimeDelta::FromDays(10));
+ visits2.push_back(Time::Now());
+
+ // Clear all history.
+ backend_->DeleteAllHistory();
+
+ // Add the visits.
+ backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
+ backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
+
+ // Verify the visits were added with their sources.
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url1, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(3U, visits.size());
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(3U, visit_sources.size());
+ for (int i = 0; i < 3; i++)
+ EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_sources[visits[i].visit_id]);
+ id = backend_->db()->GetRowForURL(url2, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(2U, visits.size());
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(2U, visit_sources.size());
+ for (int i = 0; i < 2; i++)
+ EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
+}
+
+TEST_F(HistoryBackendTest, RemoveVisitsSource) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url1("http://www.cnn.com");
+ std::vector<base::Time> visits1;
+ visits1.push_back(Time::Now() - base::TimeDelta::FromDays(5));
+ visits1.push_back(Time::Now());
+
+ GURL url2("http://www.example.com");
+ std::vector<base::Time> visits2;
+ visits2.push_back(Time::Now() - base::TimeDelta::FromDays(10));
+ visits2.push_back(Time::Now());
+
+ // Clear all history.
+ backend_->DeleteAllHistory();
+
+ // Add the visits.
+ backend_->AddVisits(url1, visits1, history::SOURCE_IE_IMPORTED);
+ backend_->AddVisits(url2, visits2, history::SOURCE_SYNCED);
+
+ // Verify the visits of url1 were added.
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url1, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(2U, visits.size());
+ // Remove these visits.
+ ASSERT_TRUE(backend_->RemoveVisits(visits));
+
+ // Now check only url2's source in visit_source table.
+ VisitSourceMap visit_sources;
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(0U, visit_sources.size());
+ id = backend_->db()->GetRowForURL(url2, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(2U, visits.size());
+ backend_->db_->GetVisitsSource(visits, &visit_sources);
+ ASSERT_EQ(2U, visit_sources.size());
+ for (int i = 0; i < 2; i++)
+ EXPECT_EQ(history::SOURCE_SYNCED, visit_sources[visits[i].visit_id]);
+}
+
+// Test for migration of adding visit_source table.
+TEST_F(HistoryBackendTest, MigrationVisitSource) {
+ ASSERT_TRUE(backend_.get());
+
+ FilePath old_history_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &old_history_path));
+ old_history_path = old_history_path.AppendASCII("History");
+ old_history_path = old_history_path.AppendASCII("HistoryNoSource");
+
+ // Copy history database file to current directory so that it will be deleted
+ // in Teardown.
+ FilePath new_history_path(getTestDir());
+ file_util::Delete(new_history_path, true);
+ file_util::CreateDirectory(new_history_path);
+ FilePath new_history_file = new_history_path.Append(chrome::kHistoryFilename);
+ ASSERT_TRUE(file_util::CopyFile(old_history_path, new_history_file));
+
+ backend_->Closing();
+ backend_ = new HistoryBackend(new_history_path,
+ new HistoryBackendTestDelegate(this),
+ &bookmark_model_);
+ backend_->Init(false);
+
+ // Now the database should already be migrated.
+ // Check version first.
+ int cur_version = HistoryDatabase::GetCurrentVersion();
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(new_history_file));
+ sql::Statement s(db.GetUniqueStatement(
+ "SELECT value FROM meta WHERE key = 'version'"));
+ ASSERT_TRUE(s.Step());
+ int file_version = s.ColumnInt(0);
+ EXPECT_EQ(cur_version, file_version);
+
+ // Check visit_source table is created and empty.
+ s.Assign(db.GetUniqueStatement(
+ "SELECT name FROM sqlite_master WHERE name=\"visit_source\""));
+ ASSERT_TRUE(s.Step());
+ s.Assign(db.GetUniqueStatement("SELECT * FROM visit_source LIMIT 10"));
+ EXPECT_FALSE(s.Step());
+}
+
} // namespace history
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index 26bb81a..4661814 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -26,7 +26,7 @@ namespace {
// Current version number. We write databases at the "current" version number,
// but any previous version that can read the "compatible" one can make do with
// or database without *too* many bad effects.
-static const int kCurrentVersionNumber = 18;
+static const int kCurrentVersionNumber = 19;
static const int kCompatibleVersionNumber = 16;
static const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
@@ -56,8 +56,7 @@ void ComputeDatabaseMetrics(const FilePath& history_name,
} // namespace
HistoryDatabase::HistoryDatabase()
- : needs_version_17_migration_(false),
- needs_version_18_migration_(false) {
+ : needs_version_17_migration_(false) {
}
HistoryDatabase::~HistoryDatabase() {
@@ -134,14 +133,7 @@ void HistoryDatabase::BeginExclusiveMode() {
// static
int HistoryDatabase::GetCurrentVersion() {
- // Temporary solution while TopSites is behind a flag. If there is
- // no flag, we are still using the Thumbnails file, i.e. we are at
- // version 17.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTopSites)) {
- return kCurrentVersionNumber;
- } else {
- return kCurrentVersionNumber - 1;
- }
+ return kCurrentVersionNumber;
}
void HistoryDatabase::BeginTransaction() {
@@ -283,21 +275,24 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion(
meta_table_.SetVersionNumber(cur_version);
}
- if (cur_version == 17)
- needs_version_18_migration_ = true;
+ if (cur_version == 17) {
+ // Version 17 was for thumbnails to top sites migration. We ended up
+ // disabling it though, so 17->18 does nothing.
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ }
- if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTopSites) &&
- cur_version == 18) {
- // Set DB version back to pre-top sites.
- cur_version = 17;
+ if (cur_version == 18) {
+ // This is the version prior to adding url_source column. We need to
+ // migrate the database.
+ cur_version = 19;
meta_table_.SetVersionNumber(cur_version);
}
// 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 < GetCurrentVersion() &&
- !needs_version_18_migration_)) <<
- "History database version " << cur_version << " is too old to handle.";
+ LOG_IF(WARNING, cur_version < GetCurrentVersion()) <<
+ "History database version " << cur_version << " is too old to handle.";
return sql::INIT_OK;
}
@@ -328,10 +323,7 @@ void HistoryDatabase::MigrateTimeEpoch() {
#endif
void HistoryDatabase::MigrationToTopSitesDone() {
- // We should be migrating from 17 to 18.
- DCHECK_EQ(17, meta_table_.GetVersionNumber());
- meta_table_.SetVersionNumber(18);
- needs_version_18_migration_ = false;
+ // TODO(sky): implement me.
}
} // namespace history
diff --git a/chrome/browser/history/history_database.h b/chrome/browser/history/history_database.h
index 3b3414a..fe74e89 100644
--- a/chrome/browser/history/history_database.h
+++ b/chrome/browser/history/history_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_HISTORY_DATABASE_H_
#define CHROME_BROWSER_HISTORY_HISTORY_DATABASE_H_
+#pragma once
#include "app/sql/connection.h"
#include "app/sql/init_status.h"
@@ -122,14 +123,6 @@ class HistoryDatabase : public DownloadDatabase,
return needs_version_17_migration_;
}
- // Returns true if the Thumbnails database should be renamed to
- // Favicons database. 17 -> 18 is migration to TopSites. ThumbnailsDatabase
- // doesn't store the thumbnails any more, only the favicons. Hence, its file
- // is renamed from Thumbnails to Favicons.
- bool needs_version_18_migration() const {
- return needs_version_18_migration_;
- }
-
// Update the database version after the TopSites migration.
void MigrationToTopSitesDone();
@@ -178,7 +171,6 @@ class HistoryDatabase : public DownloadDatabase,
// See the getters above.
bool needs_version_17_migration_;
- bool needs_version_18_migration_;
DISALLOW_COPY_AND_ASSIGN(HistoryDatabase);
};
diff --git a/chrome/browser/history/history_marshaling.h b/chrome/browser/history/history_marshaling.h
index 39b8983..1efd670 100644
--- a/chrome/browser/history/history_marshaling.h
+++ b/chrome/browser/history/history_marshaling.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_HISTORY_HISTORY_MARSHALING_H__
#define CHROME_BROWSER_HISTORY_HISTORY_MARSHALING_H__
+#pragma once
#include "base/scoped_vector.h"
#include "chrome/browser/cancelable_request.h"
@@ -16,49 +17,6 @@
namespace history {
-// Navigation -----------------------------------------------------------------
-
-// Marshalling structure for AddPage.
-class HistoryAddPageArgs
- : public base::RefCountedThreadSafe<HistoryAddPageArgs> {
- public:
- HistoryAddPageArgs(const GURL& arg_url,
- base::Time arg_time,
- const void* arg_id_scope,
- int32 arg_page_id,
- const GURL& arg_referrer,
- const history::RedirectList& arg_redirects,
- PageTransition::Type arg_transition,
- bool arg_did_replace_entry)
- : url(arg_url),
- time(arg_time),
- id_scope(arg_id_scope),
- page_id(arg_page_id),
- referrer(arg_referrer),
- redirects(arg_redirects),
- transition(arg_transition),
- did_replace_entry(arg_did_replace_entry) {
- }
-
- GURL url;
- base::Time time;
-
- const void* id_scope;
- int32 page_id;
-
- GURL referrer;
- history::RedirectList redirects;
- PageTransition::Type transition;
- bool did_replace_entry;
-
- private:
- friend class base::RefCountedThreadSafe<HistoryAddPageArgs>;
-
- ~HistoryAddPageArgs() {}
-
- DISALLOW_COPY_AND_ASSIGN(HistoryAddPageArgs);
-};
-
// Querying -------------------------------------------------------------------
typedef CancelableRequest1<HistoryService::QueryURLCallback,
@@ -104,10 +62,6 @@ typedef CancelableRequest1<HistoryService::DownloadQueryCallback,
typedef CancelableRequest<HistoryService::DownloadCreateCallback>
DownloadCreateRequest;
-typedef CancelableRequest1<HistoryService::DownloadSearchCallback,
- std::vector<int64> >
- DownloadSearchRequest;
-
// Deletion --------------------------------------------------------------------
typedef CancelableRequest<HistoryService::ExpireHistoryCallback>
diff --git a/chrome/browser/history/history_notifications.h b/chrome/browser/history/history_notifications.h
index 80fc9d5..3957041 100644
--- a/chrome/browser/history/history_notifications.h
+++ b/chrome/browser/history/history_notifications.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_HISTORY_HISTORY_NOTIFICATIONS_H__
#define CHROME_BROWSER_HISTORY_HISTORY_NOTIFICATIONS_H__
+#pragma once
#include <set>
#include <vector>
diff --git a/chrome/browser/history/history_publisher.h b/chrome/browser/history/history_publisher.h
index 5fafc3e..fdf94b7 100644
--- a/chrome/browser/history/history_publisher.h
+++ b/chrome/browser/history/history_publisher.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_HISTORY_HISTORY_PUBLISHER_H_
#define CHROME_BROWSER_HISTORY_HISTORY_PUBLISHER_H_
+#pragma once
#include <vector>
-#include <string>
#include "base/basictypes.h"
#include "base/string16.h"
diff --git a/chrome/browser/history/history_publisher_win.cc b/chrome/browser/history/history_publisher_win.cc
index cbde619..3a7a548 100644
--- a/chrome/browser/history/history_publisher_win.cc
+++ b/chrome/browser/history/history_publisher_win.cc
@@ -15,6 +15,7 @@
#include "base/scoped_variant_win.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
namespace {
@@ -119,7 +120,10 @@ void HistoryPublisher::PublishDataToIndexers(const PageData& page_data)
ScopedBstr url(ASCIIToWide(page_data.url.spec()).c_str());
ScopedBstr html(page_data.html);
ScopedBstr title(page_data.title);
- ScopedBstr format(ASCIIToWide(page_data.thumbnail_format).c_str());
+ // Don't send a NULL string through ASCIIToWide.
+ ScopedBstr format(page_data.thumbnail_format ?
+ ASCIIToWide(page_data.thumbnail_format).c_str() :
+ NULL);
ScopedVariant psa(thumbnail_arr.m_psa);
for (size_t i = 0; i < indexers_.size(); ++i) {
indexers_[i]->SendPageData(time, url, html, title, format, psa);
diff --git a/chrome/browser/history/history_querying_unittest.cc b/chrome/browser/history/history_querying_unittest.cc
index 7512786..c752d3f 100644
--- a/chrome/browser/history/history_querying_unittest.cc
+++ b/chrome/browser/history/history_querying_unittest.cc
@@ -7,6 +7,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/history/history.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -86,11 +87,9 @@ class HistoryQueryTest : public testing::Test {
private:
virtual void SetUp() {
- FilePath temp_dir;
- PathService::Get(base::DIR_TEMP, &temp_dir);
- history_dir_ = temp_dir.AppendASCII("HistoryTest");
- file_util::Delete(history_dir_, true);
- file_util::CreateDirectory(history_dir_);
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ history_dir_ = temp_dir_.path().AppendASCII("HistoryTest");
+ ASSERT_TRUE(file_util::CreateDirectory(history_dir_));
history_ = new HistoryService;
if (!history_->Init(history_dir_, NULL)) {
@@ -111,7 +110,7 @@ class HistoryQueryTest : public testing::Test {
history_->AddPage(url, test_entries[i].time, id_scope, page_id, GURL(),
PageTransition::LINK, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history_->SetPageTitle(url, UTF8ToUTF16(test_entries[i].title));
history_->SetPageContents(url, UTF8ToUTF16(test_entries[i].body));
}
@@ -124,7 +123,6 @@ class HistoryQueryTest : public testing::Test {
history_ = NULL;
MessageLoop::current()->Run(); // Wait for the other thread.
}
- file_util::Delete(history_dir_, true);
}
void QueryHistoryComplete(HistoryService::Handle, QueryResults* results) {
@@ -132,6 +130,8 @@ class HistoryQueryTest : public testing::Test {
MessageLoop::current()->Quit(); // Will return out to QueryHistory.
}
+ ScopedTempDir temp_dir_;
+
MessageLoop message_loop_;
FilePath history_dir_;
@@ -314,7 +314,7 @@ TEST_F(HistoryQueryTest, FTSArchived) {
row2.set_last_visit(Time::Now());
urls_to_add.push_back(row2);
- history_->AddPagesWithDetails(urls_to_add);
+ history_->AddPagesWithDetails(urls_to_add, history::SOURCE_BROWSED);
QueryOptions options;
QueryResults results;
diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc
index 50395aa..8a8ce6d 100644
--- a/chrome/browser/history/history_types.cc
+++ b/chrome/browser/history/history_types.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,11 +10,43 @@
#include "base/stl_util-inl.h"
using base::Time;
+using base::TimeDelta;
namespace history {
// URLRow ----------------------------------------------------------------------
+URLRow::URLRow() {
+ Initialize();
+}
+
+URLRow::URLRow(const GURL& url) : url_(url) {
+ // Initialize will not set the URL, so our initialization above will stay.
+ Initialize();
+}
+
+URLRow::URLRow(const GURL& url, URLID id) : url_(url) {
+ // Initialize will not set the URL, so our initialization above will stay.
+ Initialize();
+ // Initialize will zero the id_, so set it here.
+ id_ = id;
+}
+
+URLRow::~URLRow() {
+}
+
+URLRow& URLRow::operator=(const URLRow& other) {
+ id_ = other.id_;
+ url_ = other.url_;
+ title_ = other.title_;
+ visit_count_ = other.visit_count_;
+ typed_count_ = other.typed_count_;
+ last_visit_ = other.last_visit_;
+ hidden_ = other.hidden_;
+ favicon_id_ = other.favicon_id_;
+ return *this;
+}
+
void URLRow::Swap(URLRow* other) {
std::swap(id_, other->id_);
url_.Swap(&other->url_);
@@ -60,6 +92,9 @@ VisitRow::VisitRow(URLID arg_url_id,
is_indexed(false) {
}
+VisitRow::~VisitRow() {
+}
+
// StarredEntry ----------------------------------------------------------------
StarredEntry::StarredEntry()
@@ -71,6 +106,9 @@ StarredEntry::StarredEntry()
url_id(0) {
}
+StarredEntry::~StarredEntry() {
+}
+
void StarredEntry::Swap(StarredEntry* other) {
std::swap(id, other->id);
title.swap(other->title);
@@ -86,6 +124,23 @@ void StarredEntry::Swap(StarredEntry* other) {
// URLResult -------------------------------------------------------------------
+URLResult::URLResult() {
+}
+
+URLResult::URLResult(const GURL& url, base::Time visit_time)
+ : URLRow(url),
+ visit_time_(visit_time) {
+}
+
+URLResult::URLResult(const GURL& url,
+ const Snippet::MatchPositions& title_matches)
+ : URLRow(url) {
+ title_match_positions_ = title_matches;
+}
+
+URLResult::~URLResult() {
+}
+
void URLResult::Swap(URLResult* other) {
URLRow::Swap(other);
std::swap(visit_time_, other->visit_time_);
@@ -237,4 +292,34 @@ void QueryResults::AdjustResultMap(size_t begin, size_t end, ptrdiff_t delta) {
}
}
+HistoryAddPageArgs::HistoryAddPageArgs(
+ const GURL& arg_url,
+ base::Time arg_time,
+ const void* arg_id_scope,
+ int32 arg_page_id,
+ const GURL& arg_referrer,
+ const history::RedirectList& arg_redirects,
+ PageTransition::Type arg_transition,
+ VisitSource arg_source,
+ bool arg_did_replace_entry)
+ : url(arg_url),
+ time(arg_time),
+ id_scope(arg_id_scope),
+ page_id(arg_page_id),
+ referrer(arg_referrer),
+ redirects(arg_redirects),
+ transition(arg_transition),
+ visit_source(arg_source),
+ did_replace_entry(arg_did_replace_entry) {
+}
+
+HistoryAddPageArgs::~HistoryAddPageArgs() {
+}
+
+HistoryAddPageArgs* HistoryAddPageArgs::Clone() const {
+ return new HistoryAddPageArgs(
+ url, time, id_scope, page_id, referrer, redirects, transition,
+ visit_source, did_replace_entry);
+}
+
} // namespace history
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h
index f7bc7fb..8fab602 100644
--- a/chrome/browser/history/history_types.h
+++ b/chrome/browser/history/history_types.h
@@ -4,19 +4,23 @@
#ifndef CHROME_BROWSER_HISTORY_HISTORY_TYPES_H_
#define CHROME_BROWSER_HISTORY_HISTORY_TYPES_H_
+#pragma once
+#include <deque>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/ref_counted_memory.h"
#include "base/stack_container.h"
#include "base/string16.h"
#include "base/time.h"
#include "chrome/browser/history/snippet.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/ref_counted_util.h"
+#include "chrome/common/thumbnail_score.h"
#include "googleurl/src/gurl.h"
namespace history {
@@ -56,25 +60,16 @@ typedef int64 URLID;
// dirty bits will not be in sync for these copies.
class URLRow {
public:
- URLRow() {
- Initialize();
- }
+ URLRow();
- explicit URLRow(const GURL& url) : url_(url) {
- // Initialize will not set the URL, so our initialization above will stay.
- Initialize();
- }
+ explicit URLRow(const GURL& url);
// We need to be able to set the id of a URLRow that's being passed through
// an IPC message. This constructor should probably not be used otherwise.
- URLRow(const GURL& url, URLID id) : url_(url) {
- // Initialize will not set the URL, so our initialization above will stay.
- Initialize();
- // Initialize will zero the id_, so set it here.
- id_ = id;
- }
+ URLRow(const GURL& url, URLID id);
- virtual ~URLRow() {}
+ virtual ~URLRow();
+ URLRow& operator=(const URLRow& other);
URLID id() const { return id_; }
const GURL& url() const { return url_; }
@@ -172,9 +167,27 @@ class URLRow {
// We support the implicit copy constuctor and operator=.
};
-// VisitRow -------------------------------------------------------------------
+// The enumeration of all possible sources of visits is listed below.
+// The source will be propogated along with a URL or a visit item
+// and eventually be stored in the history database,
+// visit_source table specifically.
+// Different from page transition types, they describe the origins of visits.
+// (Warning): Please don't change any existing values while it is ok to add
+// new values when needed.
+typedef enum {
+ SOURCE_SYNCED = 0, // Synchronized from somewhere else.
+ SOURCE_BROWSED = 1, // User browsed.
+ SOURCE_EXTENSION = 2, // Added by an externsion.
+ SOURCE_FIREFOX_IMPORTED = 3,
+ SOURCE_IE_IMPORTED = 4,
+ SOURCE_SAFARI_IMPORTED = 5,
+} VisitSource;
typedef int64 VisitID;
+// Structure to hold the mapping between each visit's id and its source.
+typedef std::map<VisitID, VisitSource> VisitSourceMap;
+
+// VisitRow -------------------------------------------------------------------
// Holds all information associated with a specific visit. A visit holds time
// and referrer information for one time a URL is visited.
@@ -186,6 +199,7 @@ class VisitRow {
VisitID arg_referring_visit,
PageTransition::Type arg_transition,
SegmentID arg_segment_id);
+ ~VisitRow();
// ID of this row (visit ID, used a a referrer for other visits).
VisitID visit_id;
@@ -277,6 +291,7 @@ struct StarredEntry {
};
StarredEntry();
+ ~StarredEntry();
void Swap(StarredEntry* other);
@@ -310,7 +325,7 @@ struct StarredEntry {
// If type == URL, this is the ID of the URL of the primary page that was
// starred.
- history::URLID url_id;
+ URLID url_id;
// Time the entry was last modified. This is only used for groups and
// indicates the last time a URL was added as a child to the group.
@@ -321,17 +336,12 @@ struct StarredEntry {
class URLResult : public URLRow {
public:
- URLResult() {}
- URLResult(const GURL& url, base::Time visit_time)
- : URLRow(url),
- visit_time_(visit_time) {
- }
+ URLResult();
+ URLResult(const GURL& url, base::Time visit_time);
// Constructor that create a URLResult from the specified URL and title match
// positions from title_matches.
- URLResult(const GURL& url, const Snippet::MatchPositions& title_matches)
- : URLRow(url) {
- title_match_positions_ = title_matches;
- }
+ URLResult(const GURL& url, const Snippet::MatchPositions& title_matches);
+ ~URLResult();
base::Time visit_time() const { return visit_time_; }
void set_visit_time(base::Time visit_time) { visit_time_ = visit_time; }
@@ -525,8 +535,57 @@ struct MostVisitedURL {
}
};
+// Used by TopSites to store the thumbnails.
+struct Images {
+ scoped_refptr<RefCountedBytes> thumbnail;
+ ThumbnailScore thumbnail_score;
+
+ // TODO(brettw): this will eventually store the favicon.
+ // scoped_refptr<RefCountedBytes> favicon;
+};
+
typedef std::vector<MostVisitedURL> MostVisitedURLList;
-} // history
+// Navigation -----------------------------------------------------------------
+
+// Marshalling structure for AddPage.
+class HistoryAddPageArgs
+ : public base::RefCountedThreadSafe<HistoryAddPageArgs> {
+ public:
+ HistoryAddPageArgs(const GURL& arg_url,
+ base::Time arg_time,
+ const void* arg_id_scope,
+ int32 arg_page_id,
+ const GURL& arg_referrer,
+ const history::RedirectList& arg_redirects,
+ PageTransition::Type arg_transition,
+ VisitSource arg_source,
+ bool arg_did_replace_entry);
+
+ // Returns a new HistoryAddPageArgs that is a copy of this (ref count is
+ // of course reset). Ownership of returned object passes to caller.
+ HistoryAddPageArgs* Clone() const;
+
+ GURL url;
+ base::Time time;
+
+ const void* id_scope;
+ int32 page_id;
+
+ GURL referrer;
+ history::RedirectList redirects;
+ PageTransition::Type transition;
+ VisitSource visit_source;
+ bool did_replace_entry;
+
+ private:
+ friend class base::RefCountedThreadSafe<HistoryAddPageArgs>;
+
+ ~HistoryAddPageArgs();
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryAddPageArgs);
+};
+
+} // namespace history
#endif // CHROME_BROWSER_HISTORY_HISTORY_TYPES_H_
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index c8db05a..53d91c6 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -24,15 +24,19 @@
#include "app/sql/statement.h"
#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
#include "base/scoped_vector.h"
#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"
#include "chrome/browser/history/history_backend.h"
#include "chrome/browser/history/history_database.h"
@@ -40,7 +44,9 @@
#include "chrome/browser/history/in_memory_database.h"
#include "chrome/browser/history/in_memory_history_backend.h"
#include "chrome/browser/history/page_usage_data.h"
+#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/thumbnail_score.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
@@ -163,11 +169,9 @@ class HistoryTest : public testing::Test {
// testing::Test
virtual void SetUp() {
- FilePath temp_dir;
- PathService::Get(base::DIR_TEMP, &temp_dir);
- history_dir_ = temp_dir.AppendASCII("HistoryTest");
- file_util::Delete(history_dir_, true);
- file_util::CreateDirectory(history_dir_);
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ history_dir_ = temp_dir_.path().AppendASCII("HistoryTest");
+ ASSERT_TRUE(file_util::CreateDirectory(history_dir_));
}
void DeleteBackend() {
@@ -183,9 +187,6 @@ class HistoryTest : public testing::Test {
if (history_service_)
CleanupHistoryService();
- // Try to clean up the database file.
- file_util::Delete(history_dir_, true);
-
// Make sure we don't have any event pending that could disrupt the next
// test.
MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask);
@@ -261,6 +262,8 @@ class HistoryTest : public testing::Test {
MessageLoop::current()->Quit();
}
+ ScopedTempDir temp_dir_;
+
MessageLoopForUI message_loop_;
// PageUsageData vector to test segments.
@@ -413,7 +416,8 @@ TEST_F(HistoryTest, AddPage) {
const GURL test_url("http://www.google.com/");
history->AddPage(test_url, NULL, 0, GURL(),
PageTransition::MANUAL_SUBFRAME,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_EQ(0, query_url_row_.typed_count());
@@ -421,7 +425,8 @@ TEST_F(HistoryTest, AddPage) {
// Add the page once from the main frame (should unhide it).
history->AddPage(test_url, NULL, 0, GURL(), PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
EXPECT_EQ(2, query_url_row_.visit_count()); // Added twice.
EXPECT_EQ(0, query_url_row_.typed_count()); // Never typed.
@@ -444,14 +449,16 @@ TEST_F(HistoryTest, AddPageSameTimes) {
// additions have different timestamps.
history->AddPage(test_urls[0], now, NULL, 0, GURL(),
PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_urls[0]));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_TRUE(now == query_url_row_.last_visit()); // gtest doesn't like Time
history->AddPage(test_urls[1], now, NULL, 0, GURL(),
PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_urls[1]));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_TRUE(now + TimeDelta::FromMicroseconds(1) ==
@@ -461,7 +468,8 @@ TEST_F(HistoryTest, AddPageSameTimes) {
history->AddPage(test_urls[2], now + TimeDelta::FromMinutes(1),
NULL, 0, GURL(),
PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_urls[2]));
EXPECT_EQ(1, query_url_row_.visit_count());
EXPECT_TRUE(now + TimeDelta::FromMinutes(1) ==
@@ -484,7 +492,8 @@ TEST_F(HistoryTest, AddRedirect) {
// Add the sequence of pages as a server with no referrer. Note that we need
// to have a non-NULL page ID scope.
history->AddPage(first_redirects.back(), MakeFakeHost(1), 0, GURL(),
- PageTransition::LINK, first_redirects, true);
+ PageTransition::LINK, first_redirects,
+ history::SOURCE_BROWSED, true);
// The first page should be added once with a link visit type (because we set
// LINK when we added the original URL, and a referrer of nowhere (0).
@@ -522,7 +531,7 @@ TEST_F(HistoryTest, AddRedirect) {
second_redirects[0],
static_cast<PageTransition::Type>(PageTransition::LINK |
PageTransition::CLIENT_REDIRECT),
- second_redirects, true);
+ second_redirects, history::SOURCE_BROWSED, true);
// The last page (source of the client redirect) should NOT have an
// additional visit added, because it was a client redirect (normally it
@@ -547,7 +556,8 @@ TEST_F(HistoryTest, Typed) {
// Add the page once as typed.
const GURL test_url("http://www.google.com/");
history->AddPage(test_url, NULL, 0, GURL(), PageTransition::TYPED,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// We should have the same typed & visit count.
@@ -556,7 +566,8 @@ TEST_F(HistoryTest, Typed) {
// Add the page again not typed.
history->AddPage(test_url, NULL, 0, GURL(), PageTransition::LINK,
- history::RedirectList(), false);
+ history::RedirectList(),
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// The second time should not have updated the typed count.
@@ -566,7 +577,7 @@ TEST_F(HistoryTest, Typed) {
// Add the page again as a generated URL.
history->AddPage(test_url, NULL, 0, GURL(),
PageTransition::GENERATED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// This should have worked like a link click.
@@ -576,7 +587,7 @@ TEST_F(HistoryTest, Typed) {
// Add the page again as a reload.
history->AddPage(test_url, NULL, 0, GURL(),
PageTransition::RELOAD, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
EXPECT_TRUE(QueryURL(history, test_url));
// This should not have incremented any visit counts.
@@ -591,7 +602,7 @@ TEST_F(HistoryTest, SetTitle) {
// Add a URL.
const GURL existing_url("http://www.google.com/");
- history->AddPage(existing_url);
+ history->AddPage(existing_url, history::SOURCE_BROWSED);
// Set some title.
const string16 existing_title = UTF8ToUTF16("Google");
@@ -626,7 +637,7 @@ TEST_F(HistoryTest, Segments) {
const GURL existing_url("http://www.google.com/");
history->AddPage(existing_url, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
// Make sure a segment was created.
history->QuerySegmentUsageSince(
@@ -645,7 +656,7 @@ TEST_F(HistoryTest, Segments) {
const GURL link_url("http://yahoo.com/");
history->AddPage(link_url, scope, 0, GURL(),
PageTransition::LINK, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
// Query again
history->QuerySegmentUsageSince(
@@ -663,7 +674,7 @@ TEST_F(HistoryTest, Segments) {
// Add a page linked from existing_url.
history->AddPage(GURL("http://www.google.com/foo"), scope, 3, existing_url,
PageTransition::LINK, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
// Query again
history->QuerySegmentUsageSince(
@@ -685,6 +696,9 @@ TEST_F(HistoryTest, Segments) {
// This just tests history system -> thumbnail database integration, the actual
// thumbnail tests are in its own file.
TEST_F(HistoryTest, Thumbnails) {
+ if (history::TopSites::IsEnabled())
+ return; // TopSitesTest replaces this.
+
scoped_refptr<HistoryService> history(new HistoryService);
history_service_ = history;
ASSERT_TRUE(history->Init(history_dir_, NULL));
@@ -694,7 +708,8 @@ TEST_F(HistoryTest, Thumbnails) {
static const double boringness = 0.25;
const GURL url("http://www.google.com/thumbnail_test/");
- history->AddPage(url); // Must be visited before adding a thumbnail.
+ // Must be visited before adding a thumbnail.
+ history->AddPage(url, history::SOURCE_BROWSED);
history->SetPageThumbnail(url, *thumbnail,
ThumbnailScore(boringness, true, true));
@@ -761,10 +776,10 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Add two pages.
history->AddPage(url0, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->AddPage(url1, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -777,7 +792,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Add another page.
history->AddPage(url2, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -791,7 +806,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Revisit url2, making it the top URL.
history->AddPage(url2, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -805,7 +820,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Revisit url1, making it the top URL.
history->AddPage(url1, scope, 0, GURL(),
PageTransition::TYPED, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -824,7 +839,7 @@ TEST_F(HistoryTest, MostVisitedURLs) {
// Visit url4 using redirects.
history->AddPage(url4, scope, 0, GURL(),
PageTransition::TYPED, redirects,
- false);
+ history::SOURCE_BROWSED, false);
history->QueryMostVisitedURLs(20, 90, &consumer_,
NewCallback(static_cast<HistoryTest*>(this),
&HistoryTest::OnMostVisitedURLsAvailable));
@@ -882,7 +897,8 @@ HistoryAddPageArgs* MakeAddArgs(const GURL& url) {
0,
GURL(),
history::RedirectList(),
- PageTransition::TYPED, false);
+ PageTransition::TYPED,
+ history::SOURCE_BROWSED, false);
}
// Convenience version of the above to convert a char string.
diff --git a/chrome/browser/history/in_memory_database.h b/chrome/browser/history/in_memory_database.h
index 62460dd..27e1091 100644
--- a/chrome/browser/history/in_memory_database.h
+++ b/chrome/browser/history/in_memory_database.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_HISTORY_IN_MEMORY_DATABASE_H_
#define CHROME_BROWSER_HISTORY_IN_MEMORY_DATABASE_H_
-
-#include <string>
+#pragma once
#include "app/sql/connection.h"
#include "base/basictypes.h"
diff --git a/chrome/browser/history/in_memory_history_backend.cc b/chrome/browser/history/in_memory_history_backend.cc
index 9f3e7be..b3d5da9 100644
--- a/chrome/browser/history/in_memory_history_backend.cc
+++ b/chrome/browser/history/in_memory_history_backend.cc
@@ -5,13 +5,19 @@
#include "chrome/browser/history/in_memory_history_backend.h"
#include "base/command_line.h"
+#include "base/histogram.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/in_memory_database.h"
#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/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
namespace history {
@@ -26,14 +32,19 @@ InMemoryHistoryBackend::InMemoryHistoryBackend()
InMemoryHistoryBackend::~InMemoryHistoryBackend() {
}
-bool InMemoryHistoryBackend::Init(const FilePath& history_filename) {
+bool InMemoryHistoryBackend::Init(const FilePath& history_filename,
+ URLDatabase* db) {
db_.reset(new InMemoryDatabase);
bool success = db_->InitFromDisk(history_filename);
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableInMemoryURLIndex)) {
- index_.reset(new InMemoryURLIndex);
- // TODO(rohitrao): Load index.
+ index_.reset(new InMemoryURLIndex());
+ base::TimeTicks beginning_time = base::TimeTicks::Now();
+ // TODO(mrossetti): Provide languages when profile is available.
+ index_->Init(db, std::string());
+ UMA_HISTOGRAM_TIMES("Autocomplete.HistoryDatabaseIndexingTime",
+ base::TimeTicks::Now() - beginning_time);
}
return success;
diff --git a/chrome/browser/history/in_memory_history_backend.h b/chrome/browser/history/in_memory_history_backend.h
index 30026b5..bfa51d8 100644
--- a/chrome/browser/history/in_memory_history_backend.h
+++ b/chrome/browser/history/in_memory_history_backend.h
@@ -12,12 +12,12 @@
#ifndef CHROME_BROWSER_HISTORY_IN_MEMORY_HISTORY_BACKEND_H_
#define CHROME_BROWSER_HISTORY_IN_MEMORY_HISTORY_BACKEND_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class FilePath;
@@ -28,6 +28,7 @@ namespace history {
class InMemoryDatabase;
class InMemoryURLIndex;
+class URLDatabase;
struct URLsDeletedDetails;
struct URLsModifiedDetails;
@@ -37,7 +38,7 @@ class InMemoryHistoryBackend : public NotificationObserver {
~InMemoryHistoryBackend();
// Initializes with data from the given history database.
- bool Init(const FilePath& history_filename);
+ bool Init(const FilePath& history_filename, URLDatabase* db);
// Does initialization work when this object is attached to the history
// system on the main thread. The argument is the profile with which the
diff --git a/chrome/browser/history/in_memory_url_index.cc b/chrome/browser/history/in_memory_url_index.cc
index 83c401f..95afa57 100644
--- a/chrome/browser/history/in_memory_url_index.cc
+++ b/chrome/browser/history/in_memory_url_index.cc
@@ -4,10 +4,495 @@
#include "chrome/browser/history/in_memory_url_index.h"
+#include <algorithm>
+#include <limits>
+
+#include "app/l10n_util.h"
+#include "base/i18n/word_iterator.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autocomplete/history_provider_util.h"
+#include "chrome/browser/history/url_database.h"
+#include "net/base/escape.h"
+#include "net/base/net_util.h"
+
+using base::Time;
+using base::TimeDelta;
+
namespace history {
-InMemoryURLIndex::InMemoryURLIndex() {}
+ScoredHistoryMatch::ScoredHistoryMatch() : raw_score(0) {}
+
+ScoredHistoryMatch::ScoredHistoryMatch(const URLRow& url_info,
+ size_t input_location,
+ bool match_in_scheme,
+ bool innermost_match,
+ int score)
+ : HistoryMatch(url_info, input_location, match_in_scheme, innermost_match),
+ raw_score(score) {
+}
+
+InMemoryURLIndex::InMemoryURLIndex() : history_item_count_(0) {}
InMemoryURLIndex::~InMemoryURLIndex() {}
+static const int32_t kURLToLowerBufferSize = 2048;
+
+// Indexing
+
+bool InMemoryURLIndex::Init(history::URLDatabase* history_db,
+ const std::string& languages) {
+ // TODO(mrossetti): Register for profile/language change notifications.
+ languages_ = languages;
+ // Reset our indexes.
+ char_word_map_.clear();
+ word_id_history_map_.clear();
+ if (!history_db)
+ return false;
+ URLDatabase::URLEnumerator history_enum;
+ if (history_db->InitURLEnumeratorForEverything(&history_enum)) {
+ URLRow row;
+ Time recent_threshold = InMemoryURLIndex::RecentThreshold();
+ while (history_enum.GetNextURL(&row)) {
+ // Do some filtering so that we only get history items which could
+ // possibly pass the HistoryURLProvider::CullPoorMatches filter later.
+ if ((row.typed_count() > kLowQualityMatchTypedLimit) ||
+ (row.visit_count() > kLowQualityMatchVisitLimit) ||
+ (row.last_visit() >= recent_threshold)) {
+ if (!IndexRow(row))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool InMemoryURLIndex::IndexRow(URLRow row) {
+ const GURL& gurl(row.url());
+ string16 url(net::FormatUrl(gurl, languages_,
+ net::kFormatUrlOmitUsernamePassword,
+ UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS,
+ NULL, NULL, NULL));
+
+ // TODO(mrossetti): Detect row_id > std::numeric_limits<HistoryID>::max().
+ HistoryID history_id = static_cast<HistoryID>(row.id());
+
+ // Add the row for quick lookup in the history info store.
+ url = l10n_util::ToLower(url);
+ URLRow new_row(GURL(url), row.id());
+ new_row.set_visit_count(row.visit_count());
+ new_row.set_typed_count(row.typed_count());
+ new_row.set_last_visit(row.last_visit());
+ new_row.set_title(row.title());
+ history_info_map_.insert(std::make_pair(history_id, new_row));
+
+ // Split into individual, unique words.
+ String16Set words = WordSetFromString16(url);
+
+ // For each word, add a new entry into the word index referring to the
+ // associated history item.
+ for (String16Set::iterator iter = words.begin();
+ iter != words.end(); ++iter) {
+ String16Set::value_type uni_word = *iter;
+ AddWordToIndex(uni_word, history_id);
+ }
+ ++history_item_count_;
+ return true;
+}
+
+// Searching
+
+ScoredHistoryMatches InMemoryURLIndex::HistoryItemsForTerms(
+ const String16Vector& terms) {
+ ScoredHistoryMatches scored_items;
+ if (!terms.empty()) {
+ // Reset used_ flags for term_char_word_set_cache_. We use a basic mark-
+ // and-sweep approach.
+ ResetTermCharWordSetCache();
+
+ // Lowercase the terms.
+ // TODO(mrossetti): Another opportunity for a transform algorithm.
+ String16Vector lower_terms;
+ for (String16Vector::const_iterator term_iter = terms.begin();
+ term_iter != terms.end(); ++term_iter) {
+ String16Vector::value_type lower_string(*term_iter);
+ std::transform(lower_string.begin(),
+ lower_string.end(),
+ lower_string.begin(),
+ tolower);
+ lower_terms.push_back(lower_string);
+ }
+
+ String16Vector::value_type all_terms(JoinString(lower_terms, ' '));
+ HistoryIDSet history_id_set = HistoryIDSetFromWords(all_terms);
+
+ // Pass over all of the candidates filtering out any without a proper
+ // substring match, inserting those which pass in order by score.
+ scored_items = std::for_each(history_id_set.begin(), history_id_set.end(),
+ AddHistoryMatch(*this,
+ lower_terms)).ScoredMatches();
+ }
+
+ // Remove any stale TermCharWordSet's.
+ term_char_word_set_cache_.erase(
+ std::remove_if(term_char_word_set_cache_.begin(),
+ term_char_word_set_cache_.end(),
+ std::mem_fun_ref(&TermCharWordSet::IsNotUsed)),
+ term_char_word_set_cache_.end());
+ return scored_items;
+}
+
+void InMemoryURLIndex::ResetTermCharWordSetCache() {
+ // TODO(mrossetti): Consider keeping more of the cache around for possible
+ // repeat searches, except a 'shortcuts' approach might be better for that.
+ // TODO(mrossetti): Change TermCharWordSet to a class and use for_each.
+ for (TermCharWordSetVector::iterator iter =
+ term_char_word_set_cache_.begin();
+ iter != term_char_word_set_cache_.end(); ++iter)
+ iter->used_ = false;
+}
+
+InMemoryURLIndex::HistoryIDSet InMemoryURLIndex::HistoryIDSetFromWords(
+ const string16& uni_string) {
+ // Break the terms down into individual terms (words), get the candidate
+ // set for each term, and intersect each to get a final candidate list.
+ // Note that a single 'term' from the user's perspective might be
+ // a string like "http://www.somewebsite.com" which, from our perspective,
+ // is four words: 'http', 'www', 'somewebsite', and 'com'.
+ HistoryIDSet history_id_set;
+ String16Set words = WordSetFromString16(uni_string);
+ bool first_word = true;
+ for (String16Set::iterator iter = words.begin();
+ iter != words.end(); ++iter) {
+ String16Set::value_type uni_word = *iter;
+ HistoryIDSet term_history_id_set =
+ InMemoryURLIndex::HistoryIDsForTerm(uni_word);
+ if (first_word) {
+ history_id_set.swap(term_history_id_set);
+ first_word = false;
+ } else {
+ HistoryIDSet old_history_id_set(history_id_set);
+ history_id_set.clear();
+ std::set_intersection(old_history_id_set.begin(),
+ old_history_id_set.end(),
+ term_history_id_set.begin(),
+ term_history_id_set.end(),
+ std::inserter(history_id_set,
+ history_id_set.begin()));
+ }
+ }
+ return history_id_set;
+}
+
+InMemoryURLIndex::HistoryIDSet InMemoryURLIndex::HistoryIDsForTerm(
+ const string16& uni_word) {
+ InMemoryURLIndex::HistoryIDSet history_id_set;
+
+ // For each character in the word, get the char/word_id map entry and
+ // intersect with the set in an incremental manner.
+ Char16Set uni_chars = CharactersFromString16(uni_word);
+ WordIDSet word_id_set(WordIDSetForTermChars(uni_chars));
+
+ // If any words resulted then we can compose a set of history IDs by unioning
+ // the sets from each word.
+ if (!word_id_set.empty()) {
+ for (WordIDSet::iterator word_id_iter = word_id_set.begin();
+ word_id_iter != word_id_set.end(); ++word_id_iter) {
+ WordID word_id = *word_id_iter;
+ WordIDHistoryMap::iterator word_iter = word_id_history_map_.find(word_id);
+ if (word_iter != word_id_history_map_.end()) {
+ HistoryIDSet& word_history_id_set(word_iter->second);
+ history_id_set.insert(word_history_id_set.begin(),
+ word_history_id_set.end());
+ }
+ }
+ }
+
+ return history_id_set;
+}
+
+// Utility Functions
+
+// static
+InMemoryURLIndex::String16Set InMemoryURLIndex::WordSetFromString16(
+ const string16& uni_string) {
+ String16Set words;
+ WordIterator iter(&uni_string, WordIterator::BREAK_WORD);
+ if (iter.Init()) {
+ while (iter.Advance()) {
+ if (iter.IsWord())
+ words.insert(iter.GetWord());
+ }
+ }
+ return words;
+}
+
+// static
+InMemoryURLIndex::Char16Set InMemoryURLIndex::CharactersFromString16(
+ const string16& uni_word) {
+ Char16Set characters;
+ for (string16::const_iterator iter = uni_word.begin();
+ iter != uni_word.end(); ++iter)
+ characters.insert(*iter);
+ return characters;
+}
+
+void InMemoryURLIndex::AddWordToIndex(const string16& uni_word,
+ HistoryID history_id) {
+ WordMap::iterator word_pos = word_map_.find(uni_word);
+ if (word_pos != word_map_.end())
+ UpdateWordHistory(word_pos->second, history_id);
+ else
+ AddWordHistory(uni_word, history_id);
+}
+
+void InMemoryURLIndex::UpdateWordHistory(WordID word_id, HistoryID history_id) {
+ WordIDHistoryMap::iterator history_pos = word_id_history_map_.find(word_id);
+ DCHECK(history_pos != word_id_history_map_.end());
+ HistoryIDSet& history_id_set(history_pos->second);
+ history_id_set.insert(history_id);
+}
+
+// Add a new word to the word list and the word map, and then create a
+// new entry in the word/history map.
+void InMemoryURLIndex::AddWordHistory(const string16& uni_word,
+ HistoryID history_id) {
+ word_list_.push_back(uni_word);
+ WordID word_id = word_list_.size() - 1;
+ word_map_.insert(std::make_pair(uni_word, word_id));
+ HistoryIDSet history_id_set;
+ history_id_set.insert(history_id);
+ word_id_history_map_.insert(std::make_pair(word_id, history_id_set));
+ // For each character in the newly added word (i.e. a word that is not
+ // already in the word index), add the word to the character index.
+ Char16Set characters = CharactersFromString16(uni_word);
+ for (Char16Set::iterator uni_char_iter = characters.begin();
+ uni_char_iter != characters.end(); ++uni_char_iter) {
+ Char16Set::value_type uni_string = *uni_char_iter;
+ CharWordIDMap::iterator char_iter = char_word_map_.find(uni_string);
+ if (char_iter != char_word_map_.end()) {
+ // Update existing entry in the char/word index.
+ WordIDSet& word_id_set(char_iter->second);
+ word_id_set.insert(word_id);
+ } else {
+ // Create a new entry in the char/word index.
+ WordIDSet word_id_set;
+ word_id_set.insert(word_id);
+ char_word_map_.insert(std::make_pair(uni_string, word_id_set));
+ }
+ }
+}
+
+InMemoryURLIndex::WordIDSet InMemoryURLIndex::WordIDSetForTermChars(
+ InMemoryURLIndex::Char16Set const& uni_chars) {
+ TermCharWordSet* best_term_char_word_set = NULL;
+ bool set_found = false;
+ size_t outstanding_count = 0;
+ Char16Set outstanding_chars;
+ for (TermCharWordSetVector::iterator iter = term_char_word_set_cache_.begin();
+ iter != term_char_word_set_cache_.end(); ++iter) {
+ TermCharWordSetVector::value_type& term_char_word_set(*iter);
+ Char16Set& char_set(term_char_word_set.char_set_);
+ Char16Set exclusions;
+ std::set_difference(char_set.begin(), char_set.end(),
+ uni_chars.begin(), uni_chars.end(),
+ std::inserter(exclusions, exclusions.begin()));
+ if (exclusions.empty()) {
+ // Do a reverse difference so that we know which characters remain
+ // to be indexed. Then decide if this is a better match than any
+ // previous cached set.
+ std::set_difference(uni_chars.begin(), uni_chars.end(),
+ char_set.begin(), char_set.end(),
+ std::inserter(exclusions, exclusions.begin()));
+ if (!set_found || exclusions.size() < outstanding_count) {
+ outstanding_chars = exclusions;
+ best_term_char_word_set = &*iter;
+ outstanding_count = exclusions.size();
+ set_found = true;
+ }
+ }
+ }
+
+ WordIDSet word_id_set;
+ if (set_found && outstanding_count == 0) {
+ // If there were no oustanding characters then we can use the cached one.
+ best_term_char_word_set->used_ = true;
+ word_id_set = best_term_char_word_set->word_id_set_;
+ } else {
+ // Some or all of the characters remain to be indexed.
+ bool first_character = true;
+ if (set_found) {
+ first_character = false;
+ word_id_set = best_term_char_word_set->word_id_set_;
+ } else {
+ outstanding_chars = uni_chars;
+ }
+
+ for (Char16Set::iterator uni_char_iter = outstanding_chars.begin();
+ uni_char_iter != outstanding_chars.end(); ++uni_char_iter) {
+ Char16Set::value_type uni_char = *uni_char_iter;
+ CharWordIDMap::iterator char_iter = char_word_map_.find(uni_char);
+ if (char_iter == char_word_map_.end()) {
+ // The character was not found so bail.
+ word_id_set.clear();
+ break;
+ }
+ WordIDSet& char_word_id_set(char_iter->second);
+ if (first_character) {
+ word_id_set = char_word_id_set;
+ first_character = false;
+ } else {
+ WordIDSet old_word_id_set(word_id_set);
+ word_id_set.clear();
+ std::set_intersection(old_word_id_set.begin(),
+ old_word_id_set.end(),
+ char_word_id_set.begin(),
+ char_word_id_set.end(),
+ std::inserter(word_id_set,
+ word_id_set.begin()));
+ }
+ }
+ // Update the cache.
+ if (!set_found || outstanding_count) {
+ term_char_word_set_cache_.push_back(TermCharWordSet(uni_chars,
+ word_id_set, true));
+ }
+ }
+ return word_id_set;
+}
+
+// static
+int InMemoryURLIndex::RawScoreForURL(const URLRow& row,
+ const String16Vector& terms,
+ size_t* first_term_location) {
+ GURL gurl = row.url();
+ if (!gurl.is_valid())
+ return 0;
+
+ string16 url = UTF8ToUTF16(gurl.spec());
+
+ // Collect all term start positions so we can see if they appear in order.
+ std::vector<size_t> term_locations;
+ int out_of_order = 0; // Count the terms which are out of order.
+ size_t start_location_total = 0;
+ size_t term_length_total = 0;
+ for (String16Vector::const_iterator iter = terms.begin(); iter != terms.end();
+ ++iter) {
+ string16 term = *iter;
+ size_t term_location = url.find(term);
+ if (term_location == string16::npos)
+ return 0; // A term was not found. This should not happen.
+ if (iter != terms.begin()) {
+ // See if this term is out-of-order.
+ for (std::vector<size_t>::const_iterator order_iter =
+ term_locations.begin(); order_iter != term_locations.end();
+ ++order_iter) {
+ if (term_location <= *order_iter)
+ ++out_of_order;
+ }
+ } else {
+ *first_term_location = term_location;
+ }
+ term_locations.push_back(term_location);
+ start_location_total += term_location;
+ term_length_total += term.size();
+ }
+
+ // Calculate a raw score.
+ // TODO(mrossetti): This is good enough for now but must be fine-tuned.
+ const float kOrderMaxValue = 10.0;
+ float order_value = 10.0;
+ if (terms.size() > 1) {
+ int max_possible_out_of_order = (terms.size() * (terms.size() - 1)) / 2;
+ order_value =
+ (static_cast<float>(max_possible_out_of_order - out_of_order) /
+ max_possible_out_of_order) * kOrderMaxValue;
+ }
+
+ const float kStartMaxValue = 10.0;
+ const size_t kMaxSignificantStart = 20;
+ float start_value =
+ (static_cast<float>(kMaxSignificantStart -
+ std::min(kMaxSignificantStart, start_location_total / terms.size()))) /
+ static_cast<float>(kMaxSignificantStart) * kStartMaxValue;
+
+ const float kCompleteMaxValue = 10.0;
+ float complete_value =
+ (static_cast<float>(term_length_total) / static_cast<float>(url.size())) *
+ kStartMaxValue;
+
+ const float kLastVisitMaxValue = 10.0;
+ const base::TimeDelta kMaxSignificantDay = base::TimeDelta::FromDays(30);
+ int64 delta_time = (kMaxSignificantDay -
+ std::min((base::Time::Now() - row.last_visit()),
+ kMaxSignificantDay)).ToInternalValue();
+ float last_visit_value =
+ (static_cast<float>(delta_time) /
+ static_cast<float>(kMaxSignificantDay.ToInternalValue())) *
+ kLastVisitMaxValue;
+
+ const float kVisitCountMaxValue = 10.0;
+ const int kMaxSignificantVisits = 10;
+ float visit_count_value =
+ (static_cast<float>(std::min(row.visit_count(),
+ kMaxSignificantVisits))) / static_cast<float>(kMaxSignificantVisits) *
+ kVisitCountMaxValue;
+ float raw_score = order_value + start_value + complete_value +
+ last_visit_value + visit_count_value;
+
+ // Normalize the score.
+ const float kMaxNormalizedRawScore = 1000.0;
+ raw_score =
+ (raw_score / (kOrderMaxValue + kStartMaxValue + kCompleteMaxValue +
+ kLastVisitMaxValue + kVisitCountMaxValue)) *
+ kMaxNormalizedRawScore;
+ return static_cast<int>(raw_score);
+}
+
+// static
+Time InMemoryURLIndex::RecentThreshold() {
+ return Time::Now() - TimeDelta::FromDays(kLowQualityMatchAgeLimitInDays);
+}
+
+void InMemoryURLIndex::AddHistoryMatch::operator()(
+ const InMemoryURLIndex::HistoryID history_id) {
+ HistoryInfoMap::const_iterator hist_pos =
+ index_.history_info_map_.find(history_id);
+ if (hist_pos != index_.history_info_map_.end()) {
+ const URLRow& hist_item = hist_pos->second;
+ // TODO(mrossetti): Accommodate multiple term highlighting.
+ size_t input_location = 0;
+ int score = InMemoryURLIndex::RawScoreForURL(
+ hist_item, lower_terms_, &input_location);
+ if (score != 0) {
+ // We only retain the top 10 highest scoring results so
+ // see if this one fits into the top 10 and, if so, where.
+ ScoredHistoryMatches::iterator scored_iter = scored_matches_.begin();
+ while (scored_iter != scored_matches_.end() &&
+ (*scored_iter).raw_score > score)
+ ++scored_iter;
+ if ((scored_matches_.size() < 10) ||
+ (scored_iter != scored_matches_.end())) {
+ // Create and insert the new item.
+ // TODO(mrossetti): Properly set |match_in_scheme| and
+ // |innermost_match|.
+ bool match_in_scheme = false;
+ bool innermost_match = true;
+ ScoredHistoryMatch match(hist_item, input_location,
+ match_in_scheme, innermost_match, score);
+ if (!scored_matches_.empty())
+ scored_matches_.insert(scored_iter, match);
+ else
+ scored_matches_.push_back(match);
+ // Trim any entries beyond 10.
+ if (scored_matches_.size() > 10) {
+ scored_matches_.erase(scored_matches_.begin() + 10,
+ scored_matches_.end());
+ }
+ }
+ }
+ }
+}
+
} // namespace history
diff --git a/chrome/browser/history/in_memory_url_index.h b/chrome/browser/history/in_memory_url_index.h
index 7b57a4a..b5b3373 100644
--- a/chrome/browser/history/in_memory_url_index.h
+++ b/chrome/browser/history/in_memory_url_index.h
@@ -4,18 +4,238 @@
#ifndef CHROME_BROWSER_HISTORY_IN_MEMORY_URL_INDEX_H_
#define CHROME_BROWSER_HISTORY_IN_MEMORY_URL_INDEX_H_
+#pragma once
+
+#include <functional>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "app/sql/connection.h"
+#include "base/basictypes.h"
+#include "base/linked_ptr.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "chrome/browser/autocomplete/history_provider_util.h"
+#include "chrome/browser/history/history_types.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
+
+namespace base {
+class Time;
+}
namespace history {
+class URLDatabase;
+
+// Used for intermediate history result operations.
+struct ScoredHistoryMatch : public HistoryMatch {
+ // Required for STL, we don't use this directly.
+ ScoredHistoryMatch();
+
+ ScoredHistoryMatch(const URLRow& url_info,
+ size_t input_location,
+ bool match_in_scheme,
+ bool innermost_match,
+ int score);
+
+ // An interim score taking into consideration location and completeness
+ // of the match.
+ int raw_score;
+};
+typedef std::vector<ScoredHistoryMatch> ScoredHistoryMatches;
+
// The URL history source.
// Holds portions of the URL database in memory in an indexed form. Used to
// quickly look up matching URLs for a given query string. Used by
// the HistoryURLProvider for inline autocomplete and to provide URL
// matches to the omnibox.
+//
+// Note about multi-byte codepoints and the data structures in the
+// InMemoryURLIndex class: One will quickly notice that no effort is made to
+// insure that multi-byte character boundaries are detected when indexing the
+// words and characters in the URL history database except when converting
+// URL strings to lowercase. Multi-byte-edness makes no difference when
+// indexing or when searching the index as the final filtering of results
+// is dependent on the comparison of a string of bytes, not individual
+// characters. While the lookup of those bytes during a search in the
+// |char_word_map_| could serve up words in which the individual char16
+// occurs as a portion of a composite character the next filtering step
+// will eliminate such words except in the case where a single character
+// is being searched on and which character occurs as the second char16 of a
+// multi-char16 instance.
class InMemoryURLIndex {
public:
InMemoryURLIndex();
~InMemoryURLIndex();
+
+ // Convenience types
+ typedef std::vector<string16> String16Vector;
+
+ // Open and index the URL history database.
+ bool Init(URLDatabase* history_db, const std::string& languages);
+
+ // Reset the history index.
+ void Reset();
+
+ // Given a vector containing one or more words as string16s, scan the
+ // history index and return a vector with all scored, matching history items.
+ // Each term must occur somewhere in the history item for the item to
+ // qualify; however, the terms do not necessarily have to be adjacent.
+ // Results are sorted with higher scoring items first.
+ ScoredHistoryMatches HistoryItemsForTerms(const String16Vector& terms);
+
+ // Returns the date threshold for considering an history item as significant.
+ static base::Time RecentThreshold();
+
+ private:
+ friend class AddHistoryMatch;
+ friend class InMemoryURLIndexTest;
+ FRIEND_TEST(InMemoryURLIndexTest, Initialization);
+
+ // Convenience types.
+ typedef std::set<string16> String16Set;
+ typedef std::set<char16> Char16Set;
+
+ // An index into list of all of the words we have indexed.
+ typedef int16 WordID;
+
+ // A map allowing a WordID to be determined given a word.
+ typedef std::map<string16, WordID> WordMap;
+
+ // A map from character to word_ids.
+ typedef std::set<WordID> WordIDSet; // An index into the WordList.
+ typedef std::map<char16, WordIDSet> CharWordIDMap;
+
+ // A map from word_id to history item.
+ // TODO(mrossetti): URLID is 64 bit: a memory bloat and performance hit.
+ // Consider using a smaller type.
+ typedef URLID HistoryID;
+ typedef std::set<HistoryID> HistoryIDSet;
+ typedef std::map<WordID, HistoryIDSet> WordIDHistoryMap;
+
+ // Support caching of term character intersections so that we can optimize
+ // searches which build upon a previous search.
+ struct TermCharWordSet {
+ TermCharWordSet(Char16Set char_set, WordIDSet word_id_set, bool used)
+ : char_set_(char_set),
+ word_id_set_(word_id_set),
+ used_(used) {}
+
+ bool IsNotUsed() const { return !used_; }
+
+ Char16Set char_set_;
+ WordIDSet word_id_set_;
+ bool used_; // true if this set has been used for the current term search.
+ };
+ typedef std::vector<TermCharWordSet> TermCharWordSetVector;
+
+ // TODO(rohitrao): Probably replace this with QueryResults.
+ typedef std::vector<URLRow> URLRowVector;
+
+ // A map from history_id to the history's URL and title.
+ typedef std::map<HistoryID, URLRow> HistoryInfoMap;
+
+ // A helper class which performs the final filter on each candidate
+ // history URL match, inserting accepted matches into |scored_matches_|
+ // and trimming the maximum number of matches to 10.
+ class AddHistoryMatch : std::unary_function<HistoryID, void> {
+ public:
+ AddHistoryMatch(const InMemoryURLIndex& index,
+ const String16Vector& lower_terms)
+ : index_(index),
+ lower_terms_(lower_terms) {}
+
+ void operator()(const HistoryID history_id);
+
+ ScoredHistoryMatches ScoredMatches() const { return scored_matches_; }
+
+ private:
+ const InMemoryURLIndex& index_;
+ ScoredHistoryMatches scored_matches_;
+ const String16Vector& lower_terms_;
+ };
+
+ // Break a string down into individual words.
+ static String16Set WordSetFromString16(const string16& uni_string);
+
+ // Given a set of Char16s, find words containing those characters. If any
+ // existing, cached set is a proper subset then start with that cached
+ // set. Update the cache.
+ WordIDSet WordIDSetForTermChars(const Char16Set& uni_chars);
+
+ // URL History indexing support functions.
+
+ // Index one URL history item.
+ bool IndexRow(URLRow row);
+
+ // Break a string down into its individual characters.
+ // Note that this is temporarily intended to work on a single word, but
+ // _will_ work on a string of words, perhaps with unexpected results.
+ // TODO(mrossetti): Lots of optimizations possible here for not restarting
+ // a search if the user is just typing along. Also, change this to uniString
+ // and properly handle substring matches, scoring and sorting the results
+ // by score. Also, provide the metrics for where the matches occur so that
+ // the UI can highlight the matched sections.
+ Char16Set CharactersFromString16(const string16& uni_word);
+
+ // Given a single word, add a reference to the containing history item
+ // to the index.
+ void AddWordToIndex(const string16& uni_word, HistoryID history_id);
+
+ // Update an existing entry in the word/history index by adding the
+ // |history_id| to set for |word_id| in the word_id_history_map_.
+ void UpdateWordHistory(WordID word_id, HistoryID history_id);
+
+ // Create a new entry in the word/history map for |word_id| and add
+ // |history_id| as the initial element of the word's set.
+ void AddWordHistory(const string16& uni_word, HistoryID history_id);
+
+ // Clear the search term cache. This cache holds on to the intermediate
+ // word results for each previously typed character to eliminate the need
+ // to re-perform set operations for previously typed characters.
+ void ResetTermCharWordSetCache();
+
+ // Compose a set of history item IDs by intersecting the set for each word
+ // in |uni_string|.
+ HistoryIDSet HistoryIDSetFromWords(const string16& uni_string);
+
+ // Helper function to HistoryIDSetFromWords which composes a set of history
+ // ids for the given term given in |uni_word|.
+ HistoryIDSet HistoryIDsForTerm(const string16& uni_word);
+
+ // Calculate a raw score for this history item by first determining
+ // if all of the terms in |terms_vector| occur in |row| and, if so,
+ // calculating a raw score based on 1) starting position of each term
+ // in the user input, 2) completeness of each term's match, 3) ordering
+ // of the occurrence of each term (i.e. they appear in order), 4) last
+ // visit time, and 5) number of visits.
+ // This raw score allows the results to be ordered and can be used
+ // to influence the final score calculated by the client of this
+ // index. Return the starting location of the first term in
+ // |first_term_location|.
+ static int RawScoreForURL(const URLRow& row,
+ const String16Vector& terms_vector,
+ size_t* first_term_location);
+
+ // A list of all of indexed words. The index of a word in this list is the
+ // ID of the word in the word_map_. It reduces the memory overhead by
+ // replacing a potentially long and repeated string with a simple index.
+ // NOTE: A word will _never_ be removed from this vector thus insuring
+ // the immutability of the word_id throughout the session, reducing
+ // maintenance complexity.
+ String16Vector word_list_;
+
+ uint64 history_item_count_;
+ WordMap word_map_;
+ CharWordIDMap char_word_map_;
+ WordIDHistoryMap word_id_history_map_;
+ TermCharWordSetVector term_char_word_set_cache_;
+ HistoryInfoMap history_info_map_;
+ std::string languages_;
+
+ DISALLOW_COPY_AND_ASSIGN(InMemoryURLIndex);
};
} // namespace history
diff --git a/chrome/browser/history/in_memory_url_index_unittest.cc b/chrome/browser/history/in_memory_url_index_unittest.cc
index f5932ef..9306ec5 100644
--- a/chrome/browser/history/in_memory_url_index_unittest.cc
+++ b/chrome/browser/history/in_memory_url_index_unittest.cc
@@ -2,15 +2,105 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/history/in_memory_url_index.h"
+#include <stdio.h>
+
+#include <fstream>
+#include <string>
+#include <vector>
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
+#include "app/sql/transaction.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/history/in_memory_url_index.h"
+#include "chrome/browser/history/in_memory_database.h"
+#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h"
+// The test version of the history url database table ('url') is contained in
+// a database file created from a text file('url_history_provider_test.db.txt').
+// The only difference between this table and a live 'urls' table from a
+// profile is that the last_visit_time column in the test table contains a
+// number specifying the number of days relative to 'today' to which the
+// absolute time should be set during the test setup stage.
+//
+// The format of the test database text file is of a SQLite .dump file.
+// Note that only lines whose first character is an upper-case letter are
+// processed when creating the test database.
+
+using base::Time;
+using base::TimeDelta;
+
namespace history {
-class InMemoryURLIndexTest : public testing::Test {
+class InMemoryURLIndexTest : public testing::Test,
+ public InMemoryDatabase {
+ public:
+ InMemoryURLIndexTest() { InitFromScratch(); }
+
protected:
+ // Test setup.
+ virtual void SetUp() {
+ // Create and populate a working copy of the URL history database.
+ FilePath history_proto_path;
+ PathService::Get(chrome::DIR_TEST_DATA, &history_proto_path);
+ history_proto_path = history_proto_path.Append(
+ FILE_PATH_LITERAL("History"));
+ history_proto_path = history_proto_path.Append(
+ FILE_PATH_LITERAL("url_history_provider_test.db.txt"));
+ EXPECT_TRUE(file_util::PathExists(history_proto_path));
+
+ std::ifstream proto_file(history_proto_path.value().c_str());
+ static const size_t kCommandBufferMaxSize = 2048;
+ char sql_cmd_line[kCommandBufferMaxSize];
+
+ sql::Connection& db(GetDB());
+ {
+ sql::Transaction transaction(&db);
+ transaction.Begin();
+ while (!proto_file.eof()) {
+ proto_file.getline(sql_cmd_line, kCommandBufferMaxSize);
+ if (!proto_file.eof()) {
+ // We only process lines which begin with a upper-case letter.
+ // TODO(mrossetti): Can iswupper() be used here?
+ if (sql_cmd_line[0] >= 'A' && sql_cmd_line[0] <= 'Z') {
+ std::string sql_cmd(sql_cmd_line);
+ sql::Statement sql_stmt(db.GetUniqueStatement(sql_cmd_line));
+ EXPECT_TRUE(sql_stmt.Run());
+ }
+ }
+ }
+ transaction.Commit();
+ }
+ proto_file.close();
+
+ // Update the last_visit_time table column
+ // such that it represents a time relative to 'now'.
+ sql::Statement statement(db.GetUniqueStatement(
+ "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls;"));
+ EXPECT_TRUE(statement);
+ Time time_right_now = Time::NowFromSystemTime();
+ TimeDelta day_delta = TimeDelta::FromDays(1);
+ {
+ sql::Transaction transaction(&db);
+ transaction.Begin();
+ while (statement.Step()) {
+ URLRow row;
+ FillURLRow(statement, &row);
+ Time last_visit = time_right_now;
+ for (int64 i = row.last_visit().ToInternalValue(); i > 0; --i)
+ last_visit -= day_delta;
+ row.set_last_visit(last_visit);
+ UpdateURLRow(row.id(), row);
+ }
+ transaction.Commit();
+ }
+ }
+
scoped_ptr<InMemoryURLIndex> url_index_;
};
@@ -19,4 +109,76 @@ TEST_F(InMemoryURLIndexTest, Construction) {
EXPECT_TRUE(url_index_.get());
}
+// TODO(mrossetti): Write python script to calculate the validation criteria.
+TEST_F(InMemoryURLIndexTest, Initialization) {
+ // Verify that the database contains the expected number of items, which
+ // is the pre-filtered count, i.e. all of the items.
+ sql::Statement statement(GetDB().GetUniqueStatement("SELECT * FROM urls;"));
+ EXPECT_TRUE(statement);
+ uint64 row_count = 0;
+ while (statement.Step()) ++row_count;
+ EXPECT_EQ(33U, row_count);
+ url_index_.reset(new InMemoryURLIndex);
+ url_index_->Init(this, "en,ja,hi,zh");
+
+ // There should have been 27 of the 31 urls accepted during filtering.
+ EXPECT_EQ(28U, url_index_->history_item_count_);
+
+ // history_info_map_ should have the same number of items as were filtered.
+ EXPECT_EQ(28U, url_index_->history_info_map_.size());
+
+ // The resulting indexes should account for:
+ // 37 characters
+ // 88 words
+ EXPECT_EQ(37U, url_index_->char_word_map_.size());
+ EXPECT_EQ(91U, url_index_->word_map_.size());
+}
+
+TEST_F(InMemoryURLIndexTest, Retrieval) {
+ url_index_.reset(new InMemoryURLIndex);
+ std::string languages("en,ja,hi,zh");
+ url_index_->Init(this, languages);
+ InMemoryURLIndex::String16Vector terms;
+ // The term will be lowercased by the search.
+
+ // See if a very specific term gives a single result.
+ string16 term = ASCIIToUTF16("DrudgeReport");
+ terms.push_back(term);
+ ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(terms);
+ EXPECT_EQ(1U, matches.size());
+
+ // Search which should result in multiple results.
+ terms.clear();
+ term = ASCIIToUTF16("drudge");
+ terms.push_back(term);
+ matches = url_index_->HistoryItemsForTerms(terms);
+ ASSERT_EQ(2U, matches.size());
+ // The results should be in descending score order.
+ EXPECT_GT(matches[0].raw_score, matches[1].raw_score);
+
+ // Search which should result in nearly perfect result.
+ terms.clear();
+ term = ASCIIToUTF16("http");
+ terms.push_back(term);
+ term = ASCIIToUTF16("NearlyPerfectResult");
+ terms.push_back(term);
+ matches = url_index_->HistoryItemsForTerms(terms);
+ ASSERT_EQ(1U, matches.size());
+ // The results should have a very high score.
+ EXPECT_GT(matches[0].raw_score, 900);
+
+ // Search which should result in very poor result.
+ terms.clear();
+ term = ASCIIToUTF16("z");
+ terms.push_back(term);
+ term = ASCIIToUTF16("y");
+ terms.push_back(term);
+ term = ASCIIToUTF16("x");
+ terms.push_back(term);
+ matches = url_index_->HistoryItemsForTerms(terms);
+ ASSERT_EQ(1U, matches.size());
+ // The results should have a poor score.
+ EXPECT_LT(matches[0].raw_score, 200);
+}
+
} // namespace history
diff --git a/chrome/browser/history/multipart_uitest.cc b/chrome/browser/history/multipart_uitest.cc
index a8fcf4c..036cd96 100644
--- a/chrome/browser/history/multipart_uitest.cc
+++ b/chrome/browser/history/multipart_uitest.cc
@@ -6,32 +6,39 @@
#include "app/sql/connection.h"
#include "app/sql/statement.h"
+#include "base/file_util.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
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, SingleVisit) {
+TEST_F(MultipartResponseUITest, MAYBE_SingleVisit) {
// Make sure that visiting a multipart/x-mixed-replace site only
// creates one entry in the visits table.
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
scoped_refptr<TabProxy> tab_proxy(browser_proxy->GetActiveTab());
ASSERT_TRUE(tab_proxy.get());
- NavigateToURL(server->TestServerPage("multipart"));
+ NavigateToURL(test_server.GetURL("multipart"));
std::wstring title;
EXPECT_TRUE(tab_proxy->GetTabTitle(&title));
EXPECT_EQ(L"page 9", title);
@@ -47,7 +54,8 @@ TEST_F(MultipartResponseUITest, SingleVisit) {
ASSERT_TRUE(db.Open(history));
std::string query(
"SELECT COUNT(1) FROM visits, urls WHERE visits.url = urls.id"
- " AND urls.url LIKE 'http://localhost:%/multipart'");
+ " AND urls.url LIKE 'http://" +
+ test_server.host_port_pair().HostForURL() + ":%/multipart'");
{
sql::Statement statement(db.GetUniqueStatement(query.c_str()));
EXPECT_TRUE(statement);
diff --git a/chrome/browser/history/page_usage_data.h b/chrome/browser/history/page_usage_data.h
index 66a63e2..b7a689a 100644
--- a/chrome/browser/history/page_usage_data.h
+++ b/chrome/browser/history/page_usage_data.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_PAGE_USAGE_DATA_H__
#define CHROME_BROWSER_HISTORY_PAGE_USAGE_DATA_H__
+#pragma once
#include "base/string16.h"
#include "chrome/browser/history/history_types.h"
diff --git a/chrome/browser/history/query_parser.h b/chrome/browser/history/query_parser.h
index 8399abf..4b44c91 100644
--- a/chrome/browser/history/query_parser.h
+++ b/chrome/browser/history/query_parser.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_HISTORY_QUERY_PARSER_H_
#define CHROME_BROWSER_HISTORY_QUERY_PARSER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/history/redirect_uitest.cc b/chrome/browser/history/redirect_uitest.cc
index f7a1669..458c8e0 100644
--- a/chrome/browser/history/redirect_uitest.cc
+++ b/chrome/browser/history/redirect_uitest.cc
@@ -12,25 +12,35 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/view_ids.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 "net/base/net_util.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
+#include "views/event.h"
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
+class RedirectTest : public UITest {
+ public:
+ RedirectTest()
+ : test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
+ }
-typedef UITest RedirectTest;
+ protected:
+ net::TestServer test_server_;
+};
// Tests a single server redirect
TEST_F(RedirectTest, Server) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
- GURL final_url = server->TestServerPage(std::string());
- GURL first_url = server->TestServerPage(
+ GURL final_url = test_server_.GetURL(std::string());
+ GURL first_url = test_server_.GetURL(
"server-redirect?" + final_url.spec());
NavigateToURL(first_url);
@@ -46,13 +56,12 @@ TEST_F(RedirectTest, Server) {
}
// Tests a single client redirect.
-TEST_F(RedirectTest, Client) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+// Flaky: see crbug.com/55380
+TEST_F(RedirectTest, FLAKY_Client) {
+ ASSERT_TRUE(test_server_.Start());
- GURL final_url = server->TestServerPage(std::string());
- GURL first_url = server->TestServerPage(
+ GURL final_url = test_server_.GetURL(std::string());
+ GURL first_url = test_server_.GetURL(
"client-redirect?" + final_url.spec());
// The client redirect appears as two page visits in the browser.
@@ -81,11 +90,9 @@ TEST_F(RedirectTest, Client) {
}
TEST_F(RedirectTest, ClientEmptyReferer) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
- GURL final_url = server->TestServerPage(std::string());
+ GURL final_url = test_server_.GetURL(std::string());
FilePath test_file(test_data_directory_);
test_file = test_file.AppendASCII("file_client_redirect.html");
GURL first_url = net::FilePathToFileURL(test_file);
@@ -103,7 +110,17 @@ TEST_F(RedirectTest, ClientEmptyReferer) {
// Tests to make sure a location change when a pending redirect exists isn't
// flagged as a redirect.
-TEST_F(RedirectTest, ClientCancelled) {
+#if defined(OS_MACOSX)
+// SimulateOSClick is broken on the Mac: http://crbug.com/45162
+#define MAYBE_ClientCancelled DISABLED_ClientCancelled
+#elif defined(OS_WIN)
+// http://crbug.com/53091
+#define MAYBE_ClientCancelled FAILS_ClientCancelled
+#else
+#define MAYBE_ClientCancelled ClientCancelled
+#endif
+
+TEST_F(RedirectTest, MAYBE_ClientCancelled) {
FilePath first_path(test_data_directory_);
first_path = first_path.AppendASCII("cancelled_redirect_test.html");
ASSERT_TRUE(file_util::AbsolutePath(&first_path));
@@ -111,10 +128,26 @@ TEST_F(RedirectTest, ClientCancelled) {
NavigateToURLBlockUntilNavigationsComplete(first_url, 1);
- NavigateToURL(GURL("javascript:click()")); // User initiated location change.
-
+ scoped_refptr<BrowserProxy> browser = automation()->GetBrowserWindow(0);
+ ASSERT_TRUE(browser.get());
+ scoped_refptr<WindowProxy> window = browser->GetWindow();
+ ASSERT_TRUE(window.get());
scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
ASSERT_TRUE(tab_proxy.get());
+ int64 last_nav_time = 0;
+ EXPECT_TRUE(tab_proxy->GetLastNavigationTime(&last_nav_time));
+ // Simulate a click to force to make a user-initiated location change;
+ // otherwise, a non user-initiated in-page location change will be treated
+ // as client redirect and the redirect will be recoreded, which can cause
+ // this test failed.
+ gfx::Rect tab_view_bounds;
+ ASSERT_TRUE(browser->BringToFront());
+ ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_CONTAINER, &tab_view_bounds,
+ true));
+ ASSERT_TRUE(
+ window->SimulateOSClick(tab_view_bounds.CenterPoint(),
+ views::Event::EF_LEFT_BUTTON_DOWN));
+ EXPECT_TRUE(tab_proxy->WaitForNavigation(last_nav_time));
std::vector<GURL> redirects;
ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
@@ -141,16 +174,14 @@ TEST_F(RedirectTest, ClientCancelled) {
// Tests a client->server->server redirect
TEST_F(RedirectTest, ClientServerServer) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
- GURL final_url = server->TestServerPage(std::string());
- GURL next_to_last = server->TestServerPage(
+ GURL final_url = test_server_.GetURL(std::string());
+ GURL next_to_last = test_server_.GetURL(
"server-redirect?" + final_url.spec());
- GURL second_url = server->TestServerPage(
+ GURL second_url = test_server_.GetURL(
"server-redirect?" + next_to_last.spec());
- GURL first_url = server->TestServerPage(
+ GURL first_url = test_server_.GetURL(
"client-redirect?" + second_url.spec());
std::vector<GURL> redirects;
@@ -175,14 +206,12 @@ TEST_F(RedirectTest, ClientServerServer) {
// Tests that the "#reference" gets preserved across server redirects.
TEST_F(RedirectTest, ServerReference) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
const std::string ref("reference");
- GURL final_url = server->TestServerPage(std::string());
- GURL initial_url = server->TestServerPage(
+ GURL final_url = test_server_.GetURL(std::string());
+ GURL initial_url = test_server_.GetURL(
"server-redirect?" + final_url.spec() + "#" + ref);
NavigateToURL(initial_url);
@@ -195,14 +224,12 @@ TEST_F(RedirectTest, ServerReference) {
// A) does not crash the browser or confuse the redirect chain, see bug 1080873
// B) does not take place.
TEST_F(RedirectTest, NoHttpToFile) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
FilePath test_file(test_data_directory_);
test_file = test_file.AppendASCII("http_to_file.html");
GURL file_url = net::FilePathToFileURL(test_file);
- GURL initial_url = server->TestServerPage(
+ GURL initial_url = test_server_.GetURL(
"client-redirect?" + file_url.spec());
NavigateToURL(initial_url);
@@ -218,9 +245,7 @@ TEST_F(RedirectTest, NoHttpToFile) {
// Ensures that non-user initiated location changes (within page) are
// flagged as client redirects. See bug 1139823.
TEST_F(RedirectTest, ClientFragments) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
FilePath test_file(test_data_directory_);
test_file = test_file.AppendASCII("ref_redirect.html");
@@ -252,13 +277,11 @@ TEST_F(RedirectTest,
// which causes it to start a provisional load, and while it is waiting
// for the response (which means it hasn't committed the load for the client
// redirect destination page yet), we issue a new navigation request.
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
- GURL final_url = server->TestServerPage("files/title2.html");
- GURL slow = server->TestServerPage("slow?60");
- GURL first_url = server->TestServerPage(
+ GURL final_url = test_server_.GetURL("files/title2.html");
+ GURL slow = test_server_.GetURL("slow?60");
+ GURL first_url = test_server_.GetURL(
"client-redirect?" + slow.spec());
std::vector<GURL> redirects;
diff --git a/chrome/browser/history/snippet.cc b/chrome/browser/history/snippet.cc
index cb96e16..6e3e93c 100644
--- a/chrome/browser/history/snippet.cc
+++ b/chrome/browser/history/snippet.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,6 +8,7 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "unicode/brkiter.h"
diff --git a/chrome/browser/history/snippet.h b/chrome/browser/history/snippet.h
index 9e92893..ffa8fa1 100644
--- a/chrome/browser/history/snippet.h
+++ b/chrome/browser/history/snippet.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_HISTORY_SNIPPET_H__
#define CHROME_BROWSER_HISTORY_SNIPPET_H__
+#pragma once
#include <vector>
diff --git a/chrome/browser/history/snippet_unittest.cc b/chrome/browser/history/snippet_unittest.cc
index 5bc8a3b..75f627a 100644
--- a/chrome/browser/history/snippet_unittest.cc
+++ b/chrome/browser/history/snippet_unittest.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -162,11 +163,7 @@ TEST(Snippets, UTF8) {
UTF16ToUTF8(BuildSnippet(kSampleDocument, "relationship")));
}
-// Bug: 1274923
-// TODO(jungshik): Move this bug report to crbugs.com
-// Fails consistently. From the report, "Broken by latest ICU. Need new expected
-// results."
-TEST(Snippets, FAILS_ThaiUTF8) {
+TEST(Snippets, ThaiUTF8) {
// There are 3 instances of '\u0E43\u0E2B\u0E49'
// (\xE0\xB9\x83\xE0\xB8\xAB\xE0\xB9\x89) in kThaiSample.
// The 1st is more than |kSniipetContext| graphemes away from the
@@ -174,53 +171,54 @@ TEST(Snippets, FAILS_ThaiUTF8) {
// the 2nd match added, the snippet goes over the size limit so that
// the snippet ends right before the 3rd match.
ASSERT_EQ(" ... "
- " \xE0\xB8\x82\xE0\xB9\x89\xE0\xB8\xAD\xE0\xB8\xA1\xE0\xB8\xB9"
- "\xE0\xB8\xA5\xE0\xB8\xAA\xE0\xB9\x88\xE0\xB8\xA7\xE0\xB8\x99"
- "\xE0\xB8\x9A\xE0\xB8\xB8\xE0\xB8\x84\xE0\xB8\x84\xE0\xB8\xA5 "
- "\xE0\xB9\x80\xE0\xB8\xA1\xE0\xB8\xB7\xE0\xB9\x88\xE0\xB8\xAD"
- "\xE0\xB8\x84\xE0\xB8\xB8\xE0\xB8\x93\xE0\xB8\xA5\xE0\xB8\x87"
- "\xE0\xB8\x97\xE0\xB8\xB0\xE0\xB9\x80\xE0\xB8\x9A\xE0\xB8\xB5"
- "\xE0\xB8\xA2\xE0\xB8\x99\xE0\xB9\x80\xE0\xB8\x9E\xE0\xB8\xB7"
- "\xE0\xB9\x88\xE0\xB8\xAD\xE0\xB9\x83\xE0\xB8\x8A\xE0\xB9\x89"
- "\xE0\xB8\x9A\xE0\xB8\xA3\xE0\xB8\xB4\xE0\xB8\x81\xE0\xB8\xB2"
- "\xE0\xB8\xA3\xE0\xB8\x82\xE0\xB8\xAD\xE0\xB8\x87 Google "
- "\xE0\xB8\xAB\xE0\xB8\xA3\xE0\xB8\xB7\xE0\xB8\xAD**\xE0\xB9\x83"
- "\xE0\xB8\xAB\xE0\xB9\x89**\xE0\xB8\x82\xE0\xB9\x89\xE0\xB8\xAD"
- "\xE0\xB8\xA1\xE0\xB8\xB9\xE0\xB8\xA5\xE0\xB8\x94\xE0\xB8\xB1"
- "\xE0\xB8\x87\xE0\xB8\x81\xE0\xB8\xA5\xE0\xB9\x88\xE0\xB8\xB2"
- "\xE0\xB8\xA7\xE0\xB9\x82\xE0\xB8\x94\xE0\xB8\xA2\xE0\xB8\xAA"
- "\xE0\xB8\xA1\xE0\xB8\xB1\xE0\xB8\x84\xE0\xB8\xA3\xE0\xB9\x83"
- "\xE0\xB8\x88 \xE0\xB9\x80\xE0\xB8\xA3\xE0\xB8\xB2\xE0\xB8\xAD"
- "\xE0\xB8\xB2\xE0\xB8\x88\xE0\xB8\xA3\xE0\xB8\xA7\xE0\xB8\xA1"
- "\xE0\xB8\x82\xE0\xB9\x89\xE0\xB8\xAD\xE0\xB8\xA1\xE0\xB8\xB9"
- "\xE0\xB8\xA5\xE0\xB8\xAA\xE0\xB9\x88\xE0\xB8\xA7\xE0\xB8\x99"
- "\xE0\xB8\x9A\xE0\xB8\xB8\xE0\xB8\x84\xE0\xB8\x84\xE0\xB8\xA5"
- "\xE0\xB8\x97\xE0\xB8\xB5\xE0\xB9\x88\xE0\xB9\x80\xE0\xB8\x81"
- "\xE0\xB9\x87\xE0\xB8\x9A\xE0\xB8\xA3\xE0\xB8\xA7\xE0\xB8\x9A"
- "\xE0\xB8\xA3\xE0\xB8\xA7\xE0\xB8\xA1 ... ... "
+ "\xE0\xB8\xA3\xE0\xB8\xA7\xE0\xB8\x9A\xE0\xB8\xA3\xE0\xB8\xA7"
+ "\xE0\xB8\xA1 \xE0\xB8\x82\xE0\xB9\x89\xE0\xB8\xAD\xE0\xB8"
+ "\xA1\xE0\xB8\xB9\xE0\xB8\xA5\xE0\xB8\xAA\xE0\xB9\x88\xE0\xB8"
+ "\xA7\xE0\xB8\x99\xE0\xB8\x9A\xE0\xB8\xB8\xE0\xB8\x84\xE0\xB8"
+ "\x84\xE0\xB8\xA5 \xE0\xB9\x80\xE0\xB8\xA1\xE0\xB8\xB7\xE0"
+ "\xB9\x88\xE0\xB8\xAD\xE0\xB8\x84\xE0\xB8\xB8\xE0\xB8\x93\xE0"
+ "\xB8\xA5\xE0\xB8\x87\xE0\xB8\x97\xE0\xB8\xB0\xE0\xB9\x80\xE0"
+ "\xB8\x9A\xE0\xB8\xB5\xE0\xB8\xA2\xE0\xB8\x99\xE0\xB9\x80\xE0"
+ "\xB8\x9E\xE0\xB8\xB7\xE0\xB9\x88\xE0\xB8\xAD\xE0\xB9\x83\xE0"
+ "\xB8\x8A\xE0\xB9\x89\xE0\xB8\x9A\xE0\xB8\xA3\xE0\xB8\xB4\xE0"
+ "\xB8\x81\xE0\xB8\xB2\xE0\xB8\xA3\xE0\xB8\x82\xE0\xB8\xAD\xE0"
+ "\xB8\x87 Google \xE0\xB8\xAB\xE0\xB8\xA3\xE0\xB8\xB7\xE0\xB8"
+ "\xAD**\xE0\xB9\x83\xE0\xB8\xAB\xE0\xB9\x89**\xE0\xB8\x82\xE0"
+ "\xB9\x89\xE0\xB8\xAD\xE0\xB8\xA1\xE0\xB8\xB9\xE0\xB8\xA5\xE0"
+ "\xB8\x94\xE0\xB8\xB1\xE0\xB8\x87\xE0\xB8\x81\xE0\xB8\xA5\xE0"
+ "\xB9\x88\xE0\xB8\xB2\xE0\xB8\xA7\xE0\xB9\x82\xE0\xB8\x94\xE0"
+ "\xB8\xA2\xE0\xB8\xAA\xE0\xB8\xA1\xE0\xB8\xB1\xE0\xB8\x84\xE0"
+ "\xB8\xA3\xE0\xB9\x83\xE0\xB8\x88 \xE0\xB9\x80\xE0\xB8\xA3"
+ "\xE0\xB8\xB2\xE0\xB8\xAD\xE0\xB8\xB2\xE0\xB8\x88\xE0\xB8\xA3"
+ "\xE0\xB8\xA7\xE0\xB8\xA1\xE0\xB8\x82\xE0\xB9\x89\xE0\xB8\xAD"
+ "\xE0\xB8\xA1\xE0\xB8\xB9\xE0\xB8\xA5\xE0\xB8\xAA\xE0\xB9\x88"
+ "\xE0\xB8\xA7\xE0\xB8\x99\xE0\xB8\x9A\xE0\xB8\xB8\xE0\xB8\x84"
+ "\xE0\xB8\x84\xE0\xB8\xA5\xE0\xB8\x97\xE0\xB8\xB5\xE0\xB9\x88"
+ "\xE0\xB9\x80\xE0\xB8\x81\xE0\xB9\x87\xE0\xB8\x9A\xE0\xB8\xA3"
+ "\xE0\xB8\xA7\xE0\xB8\x9A\xE0\xB8\xA3\xE0\xB8\xA7\xE0\xB8\xA1"
"\xE0\xB8\x88\xE0\xB8\xB2\xE0\xB8\x81\xE0\xB8\x84\xE0\xB8\xB8"
"\xE0\xB8\x93\xE0\xB9\x80\xE0\xB8\x82\xE0\xB9\x89\xE0\xB8\xB2"
- "\xE0\xB8\x81\xE0\xB8\xB1\xE0\xB8\x9A\xE0\xB8\x82\xE0\xB9\x89"
- "\xE0\xB8\xAD\xE0\xB8\xA1\xE0\xB8\xB9\xE0\xB8\xA5\xE0\xB8\x88"
- "\xE0\xB8\xB2\xE0\xB8\x81\xE0\xB8\x9A\xE0\xB8\xA3\xE0\xB8\xB4"
- "\xE0\xB8\x81\xE0\xB8\xB2\xE0\xB8\xA3\xE0\xB8\xAD\xE0\xB8\xB7"
- "\xE0\xB9\x88\xE0\xB8\x99\xE0\xB8\x82\xE0\xB8\xAD\xE0\xB8\x87 "
- "Google \xE0\xB8\xAB\xE0\xB8\xA3\xE0\xB8\xB7\xE0\xB8\xAD"
- "\xE0\xB8\x9A\xE0\xB8\xB8\xE0\xB8\x84\xE0\xB8\x84\xE0\xB8\xA5"
- "\xE0\xB8\x97\xE0\xB8\xB5\xE0\xB9\x88\xE0\xB8\xAA\xE0\xB8\xB2"
- "\xE0\xB8\xA1 \xE0\xB9\x80\xE0\xB8\x9E\xE0\xB8\xB7\xE0\xB9\x88"
- "\xE0\xB8\xAD**\xE0\xB9\x83\xE0\xB8\xAB\xE0\xB9\x89**\xE0\xB8\x9C"
- "\xE0\xB8\xB9\xE0\xB9\x89\xE0\xB9\x83\xE0\xB8\x8A\xE0\xB9\x89"
- "\xE0\xB9\x84\xE0\xB8\x94\xE0\xB9\x89\xE0\xB8\xA3\xE0\xB8\xB1"
- "\xE0\xB8\x9A\xE0\xB8\x9B\xE0\xB8\xA3\xE0\xB8\xB0\xE0\xB8\xAA"
- "\xE0\xB8\x9A\xE0\xB8\x81\xE0\xB8\xB2\xE0\xB8\xA3\xE0\xB8\x93"
- "\xE0\xB9\x8C\xE0\xB8\x97\xE0\xB8\xB5\xE0\xB9\x88\xE0\xB8\x94"
- "\xE0\xB8\xB5\xE0\xB8\x82\xE0\xB8\xB6\xE0\xB9\x89\xE0\xB8\x99 "
- "\xE0\xB8\xA3\xE0\xB8\xA7\xE0\xB8\xA1\xE0\xB8\x97\xE0\xB8\xB1"
- "\xE0\xB9\x89\xE0\xB8\x87\xE0\xB8\x9B\xE0\xB8\xA3\xE0\xB8\xB1"
- "\xE0\xB8\x9A\xE0\xB9\x81\xE0\xB8\x95\xE0\xB9\x88\xE0\xB8\x87"
- "\xE0\xB9\x80\xE0\xB8\x99\xE0\xB8\xB7\xE0\xB9\x89\xE0\xB8\xAD"
- "\xE0\xB8\xAB\xE0\xB8\xB2",
+ "\xE0\xB8\x81\xE0\xB8\xB1\xE0\xB8\x9A ... ... \xE0\xB8\x82"
+ "\xE0\xB9\x89\xE0\xB8\xAD\xE0\xB8\xA1\xE0\xB8\xB9\xE0\xB8\xA5"
+ "\xE0\xB8\x88\xE0\xB8\xB2\xE0\xB8\x81\xE0\xB8\x9A\xE0\xB8\xA3"
+ "\xE0\xB8\xB4\xE0\xB8\x81\xE0\xB8\xB2\xE0\xB8\xA3\xE0\xB8\xAD"
+ "\xE0\xB8\xB7\xE0\xB9\x88\xE0\xB8\x99\xE0\xB8\x82\xE0\xB8\xAD"
+ "\xE0\xB8\x87 Google \xE0\xB8\xAB\xE0\xB8\xA3\xE0\xB8\xB7\xE0"
+ "\xB8\xAD\xE0\xB8\x9A\xE0\xB8\xB8\xE0\xB8\x84\xE0\xB8\x84\xE0"
+ "\xB8\xA5\xE0\xB8\x97\xE0\xB8\xB5\xE0\xB9\x88\xE0\xB8\xAA\xE0"
+ "\xB8\xB2\xE0\xB8\xA1 \xE0\xB9\x80\xE0\xB8\x9E\xE0\xB8\xB7"
+ "\xE0\xB9\x88\xE0\xB8\xAD**\xE0\xB9\x83\xE0\xB8\xAB\xE0\xB9"
+ "\x89**\xE0\xB8\x9C\xE0\xB8\xB9\xE0\xB9\x89\xE0\xB9\x83\xE0"
+ "\xB8\x8A\xE0\xB9\x89\xE0\xB9\x84\xE0\xB8\x94\xE0\xB9\x89\xE0"
+ "\xB8\xA3\xE0\xB8\xB1\xE0\xB8\x9A\xE0\xB8\x9B\xE0\xB8\xA3\xE0"
+ "\xB8\xB0\xE0\xB8\xAA\xE0\xB8\x9A\xE0\xB8\x81\xE0\xB8\xB2\xE0"
+ "\xB8\xA3\xE0\xB8\x93\xE0\xB9\x8C\xE0\xB8\x97\xE0\xB8\xB5\xE0"
+ "\xB9\x88\xE0\xB8\x94\xE0\xB8\xB5\xE0\xB8\x82\xE0\xB8\xB6\xE0"
+ "\xB9\x89\xE0\xB8\x99 \xE0\xB8\xA3\xE0\xB8\xA7\xE0\xB8\xA1"
+ "\xE0\xB8\x97\xE0\xB8\xB1\xE0\xB9\x89\xE0\xB8\x87\xE0\xB8\x9B"
+ "\xE0\xB8\xA3\xE0\xB8\xB1\xE0\xB8\x9A\xE0\xB9\x81\xE0\xB8\x95"
+ "\xE0\xB9\x88\xE0\xB8\x87\xE0\xB9\x80\xE0\xB8\x99\xE0\xB8\xB7"
+ "\xE0\xB9\x89\xE0\xB8\xAD\xE0\xB8\xAB\xE0\xB8\xB2",
UTF16ToUTF8(BuildSnippet(kThaiSample,
"\xE0\xB9\x83\xE0\xB8\xAB\xE0\xB9\x89")));
}
diff --git a/chrome/browser/history/starred_url_database.cc b/chrome/browser/history/starred_url_database.cc
index cf2a306..ba8b27d 100644
--- a/chrome/browser/history/starred_url_database.cc
+++ b/chrome/browser/history/starred_url_database.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/history/starred_url_database.h"
-#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "base/file_util.h"
#include "base/logging.h"
@@ -12,6 +11,7 @@
#include "base/scoped_vector.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
diff --git a/chrome/browser/history/starred_url_database.h b/chrome/browser/history/starred_url_database.h
index 8d327d8..aab2ae5 100644
--- a/chrome/browser/history/starred_url_database.h
+++ b/chrome/browser/history/starred_url_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_STARRED_URL_DATABASE_H_
#define CHROME_BROWSER_HISTORY_STARRED_URL_DATABASE_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/history/starred_url_database_unittest.cc b/chrome/browser/history/starred_url_database_unittest.cc
index f82e645..deb9750 100644
--- a/chrome/browser/history/starred_url_database_unittest.cc
+++ b/chrome/browser/history/starred_url_database_unittest.cc
@@ -7,6 +7,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/starred_url_database.h"
#include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/history/text_database.cc b/chrome/browser/history/text_database.cc
index 3327869..71c801f 100644
--- a/chrome/browser/history/text_database.cc
+++ b/chrome/browser/history/text_database.cc
@@ -8,12 +8,12 @@
#include "chrome/browser/history/text_database.h"
-#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
@@ -107,8 +107,9 @@ TextDatabase::DBIdent TextDatabase::FileNameToID(const FilePath& file_path) {
return 0;
}
- int year = StringToInt(suffix.substr(0, 4));
- int month = StringToInt(suffix.substr(5, 2));
+ int year, month;
+ base::StringToInt(suffix.substr(0, 4), &year);
+ base::StringToInt(suffix.substr(5, 2), &month);
return year * 100 + month;
}
@@ -127,7 +128,7 @@ bool TextDatabase::Init() {
// better performance (we're typically seek rather than bandwidth limited).
// This only has an effect before any tables have been created, otherwise
// this is a NOP. Must be a power of 2 and a max of 8192.
- db_.set_page_size(2096);
+ db_.set_page_size(4096);
// The default cache size is 2000 which give >8MB of data. Since we will often
// have 2-3 of these objects, each with their own 8MB, this adds up very fast.
diff --git a/chrome/browser/history/text_database.h b/chrome/browser/history/text_database.h
index e34c071..e881888 100644
--- a/chrome/browser/history/text_database.h
+++ b/chrome/browser/history/text_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_TEXT_DATABASE_H_
#define CHROME_BROWSER_HISTORY_TEXT_DATABASE_H_
+#pragma once
#include <set>
#include <vector>
diff --git a/chrome/browser/history/text_database_manager.h b/chrome/browser/history/text_database_manager.h
index 7f25bf7..5f8d1a3 100644
--- a/chrome/browser/history/text_database_manager.h
+++ b/chrome/browser/history/text_database_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_TEXT_DATABASE_MANAGER_H_
#define CHROME_BROWSER_HISTORY_TEXT_DATABASE_MANAGER_H_
+#pragma once
#include <set>
#include <vector>
@@ -275,7 +276,7 @@ class TextDatabaseManager {
typedef OwningMRUCache<TextDatabase::DBIdent, TextDatabase*> DBCache;
DBCache db_cache_;
- // Tells us about the existance of database files on disk. All existing
+ // Tells us about the existence of database files on disk. All existing
// databases will be in here, and non-existant ones will not, so we don't
// have to check the disk every time.
//
diff --git a/chrome/browser/history/text_database_manager_unittest.cc b/chrome/browser/history/text_database_manager_unittest.cc
index 8e7f27e..1ec7744 100644
--- a/chrome/browser/history/text_database_manager_unittest.cc
+++ b/chrome/browser/history/text_database_manager_unittest.cc
@@ -79,7 +79,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
visit_row.transition = 0;
visit_row.segment_id = 0;
visit_row.is_indexed = false;
- VisitID visit_id = visit_db->AddVisit(&visit_row);
+ VisitID visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL1), visit_row.url_id, visit_row.visit_id,
@@ -89,7 +89,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL2), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle2),
@@ -98,7 +98,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL3), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle3),
@@ -108,7 +108,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL4), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle4),
@@ -117,7 +117,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL5), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle5),
@@ -127,7 +127,7 @@ void AddAllPages(TextDatabaseManager& manager, VisitDatabase* visit_db,
exploded.day_of_month++;
visit_row.url_id = 2;
visit_row.visit_time = Time::FromUTCExploded(exploded);
- visit_id = visit_db->AddVisit(&visit_row);
+ visit_id = visit_db->AddVisit(&visit_row, SOURCE_BROWSED);
times->push_back(visit_row.visit_time);
manager.AddPageData(GURL(kURL1), visit_row.url_id, visit_row.visit_id,
visit_row.visit_time, UTF8ToUTF16(kTitle1),
@@ -242,7 +242,7 @@ TEST_F(TextDatabaseManagerTest, InsertCompleteVisit) {
visit.transition = PageTransition::LINK;
visit.segment_id = 0;
visit.is_indexed = false;
- visit_db.AddVisit(&visit);
+ visit_db.AddVisit(&visit, SOURCE_BROWSED);
// Add a full text indexed entry for that visit.
const GURL url(kURL2);
@@ -335,7 +335,7 @@ TEST_F(TextDatabaseManagerTest, PartialComplete) {
VisitRow visit_row;
visit_row.url_id = url_id;
visit_row.visit_time = added_time;
- visit_db.AddVisit(&visit_row);
+ visit_db.AddVisit(&visit_row, SOURCE_BROWSED);
// Add a URL with no title or body, and say that it expired.
manager.AddPageURL(url, 0, 0, added_time);
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index 8bf203d..36b8a20 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -8,21 +8,23 @@
#include "app/sql/transaction.h"
#include "base/command_line.h"
#include "base/file_util.h"
-#if defined(OS_MACOSX)
-#include "base/mac_util.h"
-#endif
#include "base/ref_counted_memory.h"
#include "base/time.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
#include "chrome/browser/history/history_publisher.h"
+#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/history/url_database.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/thumbnail_score.h"
#include "gfx/codec/jpeg_codec.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#if defined(OS_MACOSX)
+#include "base/mac_util.h"
+#endif
+
namespace history {
// Version number of the database.
@@ -130,7 +132,7 @@ sql::InitStatus ThumbnailDatabase::OpenDatabase(sql::Connection* db,
bool ThumbnailDatabase::InitThumbnailTable() {
if (!db_.DoesTableExist("thumbnails")) {
- if (CommandLine::ForCurrentProcess()-> HasSwitch(switches::kTopSites)) {
+ if (history::TopSites::IsEnabled()) {
use_top_sites_ = true;
return true;
}
@@ -231,8 +233,10 @@ void ThumbnailDatabase::SetPageThumbnail(
const SkBitmap& thumbnail,
const ThumbnailScore& score,
base::Time time) {
- if (use_top_sites_)
+ if (use_top_sites_) {
+ LOG(WARNING) << "Use TopSites instead.";
return; // Not possible after migration to TopSites.
+ }
if (!thumbnail.isNull()) {
bool add_thumbnail = true;
@@ -286,8 +290,10 @@ void ThumbnailDatabase::SetPageThumbnail(
bool ThumbnailDatabase::GetPageThumbnail(URLID id,
std::vector<unsigned char>* data) {
- if (use_top_sites_)
+ if (use_top_sites_) {
+ LOG(WARNING) << "Use TopSites instead.";
return false; // Not possible after migration to TopSites.
+ }
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"SELECT data FROM thumbnails WHERE url_id=?"));
@@ -303,8 +309,10 @@ bool ThumbnailDatabase::GetPageThumbnail(URLID id,
}
bool ThumbnailDatabase::DeleteThumbnail(URLID id) {
- if (use_top_sites_)
+ if (use_top_sites_) {
+ LOG(WARNING) << "Use TopSites instead.";
return true; // Not possible after migration to TopSites.
+ }
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"DELETE FROM thumbnails WHERE url_id = ?"));
@@ -317,8 +325,10 @@ bool ThumbnailDatabase::DeleteThumbnail(URLID id) {
bool ThumbnailDatabase::ThumbnailScoreForId(URLID id,
ThumbnailScore* score) {
- if (use_top_sites_)
+ if (use_top_sites_) {
+ LOG(WARNING) << "Use TopSites instead.";
return false; // Not possible after migration to TopSites.
+ }
// Fetch the current thumbnail's information to make sure we
// aren't replacing a good thumbnail with one that's worse.
@@ -491,7 +501,8 @@ bool ThumbnailDatabase::RenameAndDropThumbnails(const FilePath& old_db_file,
favicons.Close();
// Can't attach within a transaction.
- CommitTransaction();
+ if (transaction_nesting())
+ CommitTransaction();
// Attach new DB.
{
diff --git a/chrome/browser/history/thumbnail_database.h b/chrome/browser/history/thumbnail_database.h
index 81d498c..94fb043 100644
--- a/chrome/browser/history/thumbnail_database.h
+++ b/chrome/browser/history/thumbnail_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_THUMBNAIL_DATABASE_H_
#define CHROME_BROWSER_HISTORY_THUMBNAIL_DATABASE_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/history/thumbnail_database_unittest.cc b/chrome/browser/history/thumbnail_database_unittest.cc
index 4d2c2bf..23eccef 100644
--- a/chrome/browser/history/thumbnail_database_unittest.cc
+++ b/chrome/browser/history/thumbnail_database_unittest.cc
@@ -6,6 +6,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
@@ -13,6 +14,8 @@
#include "base/scoped_temp_dir.h"
#include "chrome/browser/history/thumbnail_database.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/browser/history/top_sites.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
#include "gfx/codec/jpeg_codec.h"
@@ -70,6 +73,9 @@ class ThumbnailDatabaseTest : public testing::Test {
};
TEST_F(ThumbnailDatabaseTest, AddDelete) {
+ if (history::TopSites::IsEnabled())
+ return; // TopSitesTest replaces this.
+
ThumbnailDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL));
@@ -112,6 +118,9 @@ TEST_F(ThumbnailDatabaseTest, AddDelete) {
}
TEST_F(ThumbnailDatabaseTest, UseLessBoringThumbnails) {
+ if (history::TopSites::IsEnabled())
+ return; // TopSitesTest replaces this.
+
ThumbnailDatabase db;
Time now = Time::Now();
ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL));
@@ -146,6 +155,9 @@ TEST_F(ThumbnailDatabaseTest, UseLessBoringThumbnails) {
}
TEST_F(ThumbnailDatabaseTest, UseAtTopThumbnails) {
+ if (history::TopSites::IsEnabled())
+ return; // TopSitesTest replaces this.
+
ThumbnailDatabase db;
Time now = Time::Now();
ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL));
@@ -217,6 +229,9 @@ TEST_F(ThumbnailDatabaseTest, UseAtTopThumbnails) {
}
TEST_F(ThumbnailDatabaseTest, ThumbnailTimeDegradation) {
+ if (history::TopSites::IsEnabled())
+ return; // TopSitesTest replaces this.
+
ThumbnailDatabase db;
const Time kNow = Time::Now();
const Time kThreeHoursAgo = kNow - TimeDelta::FromHours(4);
@@ -261,6 +276,9 @@ TEST_F(ThumbnailDatabaseTest, NeverAcceptTotallyBoringThumbnail) {
// should replace a thumbnail with another because of reasons other
// than straight up boringness score, still reject because the
// thumbnail is totally boring.
+ if (history::TopSites::IsEnabled())
+ return; // TopSitesTest replaces this.
+
ThumbnailDatabase db;
Time now = Time::Now();
ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL));
@@ -332,6 +350,9 @@ TEST_F(ThumbnailDatabaseTest, NeverAcceptTotallyBoringThumbnail) {
}
TEST_F(ThumbnailDatabaseTest, NeedsMigrationToTopSites) {
+ if (history::TopSites::IsEnabled())
+ return; // TopSitesTest replaces this.
+
ThumbnailDatabase db;
ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL));
db.BeginTransaction();
diff --git a/chrome/browser/history/top_sites.cc b/chrome/browser/history/top_sites.cc
index 1ef4dec..c9f4a94 100644
--- a/chrome/browser/history/top_sites.cc
+++ b/chrome/browser/history/top_sites.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.
@@ -6,22 +6,37 @@
#include <algorithm>
+#include "app/l10n_util.h"
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/md5.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/history/top_sites_database.h"
+#include "chrome/browser/dom_ui/most_visited_handler.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/history/page_usage_data.h"
+#include "chrome/browser/history/top_sites_database.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/thumbnail_score.h"
#include "gfx/codec/jpeg_codec.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace history {
// How many top sites to store in the cache.
static const size_t kTopSitesNumber = 20;
+static const size_t kTopSitesShown = 8;
static const int kDaysOfHistory = 90;
// Time from startup to first HistoryService query.
static const int64 kUpdateIntervalSecs = 15;
@@ -34,11 +49,28 @@ TopSites::TopSites(Profile* profile) : profile_(profile),
mock_history_service_(NULL),
last_num_urls_changed_(0),
migration_in_progress_(false),
- waiting_for_results_(true) {
- registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
- Source<Profile>(profile_));
- registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- NotificationService::AllSources());
+ waiting_for_results_(true),
+ blacklist_(NULL),
+ pinned_urls_(NULL) {
+ if (!profile_)
+ return;
+
+ if (NotificationService::current()) {
+ registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
+ Source<Profile>(profile_));
+ registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
+ NotificationService::AllSources());
+ }
+
+ blacklist_ = profile_->GetPrefs()->
+ GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist);
+ pinned_urls_ = profile_->GetPrefs()->
+ GetMutableDictionary(prefs::kNTPMostVisitedPinnedURLs);
+}
+
+// static
+bool TopSites::IsEnabled() {
+ return CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableTopSites);
}
TopSites::~TopSites() {
@@ -66,19 +98,18 @@ void TopSites::ReadDatabase() {
std::map<GURL, Images> thumbnails;
DCHECK(db_.get());
- {
- AutoLock lock(lock_);
- MostVisitedURLList top_urls;
- db_->GetPageThumbnails(&top_urls, &thumbnails);
- StoreMostVisited(&top_urls);
- } // Lock is released here.
+ MostVisitedURLList top_urls;
+ db_->GetPageThumbnails(&top_urls, &thumbnails);
+ MostVisitedURLList copy(top_urls); // StoreMostVisited destroys the list.
+ StoreMostVisited(&top_urls);
+ if (AddPrepopulatedPages(&copy))
+ UpdateMostVisited(copy);
+ AutoLock lock(lock_);
for (size_t i = 0; i < top_sites_.size(); i++) {
GURL url = top_sites_[i].url;
Images thumbnail = thumbnails[url];
- if (!thumbnail.thumbnail.get() || !thumbnail.thumbnail->size()) {
- LOG(INFO) << "No thumbnail for " << url.spec();
- } else {
+ if (thumbnail.thumbnail.get() && thumbnail.thumbnail->size()) {
SetPageThumbnailNoDB(url, thumbnail.thumbnail,
thumbnail.thumbnail_score);
}
@@ -90,6 +121,7 @@ void TopSites::ReadDatabase() {
bool TopSites::SetPageThumbnail(const GURL& url,
const SkBitmap& thumbnail,
const ThumbnailScore& score) {
+ AutoLock lock(lock_);
bool add_temp_thumbnail = false;
if (canonical_urls_.find(url) == canonical_urls_.end()) {
if (top_sites_.size() < kTopSitesNumber) {
@@ -118,12 +150,13 @@ bool TopSites::SetPageThumbnail(const GURL& url,
return true;
}
- return SetPageThumbnail(url, thumbnail_data, score);
+ return SetPageThumbnailEncoded(url, thumbnail_data, score);
}
-bool TopSites::SetPageThumbnail(const GURL& url,
- const RefCountedBytes* thumbnail,
- const ThumbnailScore& score) {
+bool TopSites::SetPageThumbnailEncoded(const GURL& url,
+ const RefCountedBytes* thumbnail,
+ const ThumbnailScore& score) {
+ lock_.AssertAcquired();
if (!SetPageThumbnailNoDB(url, thumbnail, score))
return false;
@@ -144,7 +177,7 @@ bool TopSites::SetPageThumbnail(const GURL& url,
void TopSites::WriteThumbnailToDB(const MostVisitedURL& url,
int url_rank,
- const TopSites::Images& thumbnail) {
+ const Images& thumbnail) {
DCHECK(db_.get());
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
db_->SetPageThumbnail(url, url_rank, thumbnail);
@@ -154,7 +187,7 @@ void TopSites::WriteThumbnailToDB(const MostVisitedURL& url,
bool TopSites::SetPageThumbnailNoDB(const GURL& url,
const RefCountedBytes* thumbnail_data,
const ThumbnailScore& score) {
- AutoLock lock(lock_);
+ lock_.AssertAcquired();
std::map<GURL, size_t>::iterator found = canonical_urls_.find(url);
if (found == canonical_urls_.end()) {
@@ -195,45 +228,180 @@ bool TopSites::SetPageThumbnailNoDB(const GURL& url,
void TopSites::GetMostVisitedURLs(CancelableRequestConsumer* consumer,
GetTopSitesCallback* callback) {
-
scoped_refptr<CancelableRequest<GetTopSitesCallback> > request(
new CancelableRequest<GetTopSitesCallback>(callback));
// This ensures cancelation of requests when either the consumer or the
// provider is deleted. Deletion of requests is also guaranteed.
AddRequest(request, consumer);
- if (waiting_for_results_) {
- // A request came in before we have any top sites.
- // We have to keep track of the requests ourselves.
- pending_callbacks_.insert(request);
- return;
+ MostVisitedURLList filtered_urls;
+ {
+ AutoLock lock(lock_);
+ if (waiting_for_results_) {
+ // A request came in before we have any top sites.
+ // We have to keep track of the requests ourselves.
+ pending_callbacks_.insert(request);
+ return;
+ }
+ if (request->canceled())
+ return;
+
+ ApplyBlacklistAndPinnedURLs(top_sites_, &filtered_urls);
}
- if (request->canceled())
- return;
- request->ForwardResult(GetTopSitesCallback::TupleType(top_sites_));
+ request->ForwardResult(GetTopSitesCallback::TupleType(filtered_urls));
}
bool TopSites::GetPageThumbnail(const GURL& url, RefCountedBytes** data) const {
- std::map<GURL, Images>::const_iterator found = top_images_.find(url);
- if (found == top_images_.end())
- return false; // No thumbnail for this URL.
+ AutoLock lock(lock_);
+ std::map<GURL, Images>::const_iterator found =
+ top_images_.find(GetCanonicalURL(url));
+ if (found == top_images_.end()) {
+ found = temp_thumbnails_map_.find(url);
+ if (found == temp_thumbnails_map_.end())
+ return false; // No thumbnail for this URL.
+ }
Images image = found->second;
*data = image.thumbnail.get();
return true;
}
+static int IndexOf(const MostVisitedURLList& urls, const GURL& url) {
+ for (size_t i = 0; i < urls.size(); i++) {
+ if (urls[i].url == url)
+ return i;
+ }
+ return -1;
+}
+
+bool TopSites::AddPrepopulatedPages(MostVisitedURLList* urls) {
+ // TODO(arv): This needs to get the data from some configurable place.
+ // http://crbug.com/17630
+ bool added = false;
+ GURL welcome_url(l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL));
+ if (urls->size() < kTopSitesNumber && IndexOf(*urls, welcome_url) == -1) {
+ MostVisitedURL url = {
+ welcome_url,
+ GURL("chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_FAVICON"),
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE)
+ };
+ url.redirects.push_back(welcome_url);
+ urls->push_back(url);
+ added = true;
+ }
+
+ GURL themes_url(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL));
+ if (urls->size() < kTopSitesNumber && IndexOf(*urls, themes_url) == -1) {
+ MostVisitedURL url = {
+ themes_url,
+ GURL("chrome://theme/IDR_NEWTAB_THEMES_GALLERY_FAVICON"),
+ l10n_util::GetStringUTF16(IDS_NEW_TAB_THEMES_GALLERY_PAGE_TITLE)
+ };
+ url.redirects.push_back(themes_url);
+ urls->push_back(url);
+ added = true;
+ }
+
+ return added;
+}
+
+void TopSites::MigratePinnedURLs() {
+ std::map<GURL, size_t> tmp_map;
+ for (DictionaryValue::key_iterator it = pinned_urls_->begin_keys();
+ it != pinned_urls_->end_keys(); ++it) {
+ Value* value;
+ if (!pinned_urls_->GetWithoutPathExpansion(*it, &value))
+ continue;
+
+ if (value->IsType(DictionaryValue::TYPE_DICTIONARY)) {
+ DictionaryValue* dict = static_cast<DictionaryValue*>(value);
+ std::string url_string;
+ int index;
+ if (dict->GetString("url", &url_string) &&
+ dict->GetInteger("index", &index))
+ tmp_map[GURL(url_string)] = index;
+ }
+ }
+ pinned_urls_->Clear();
+ for (std::map<GURL, size_t>::iterator it = tmp_map.begin();
+ it != tmp_map.end(); ++it)
+ AddPinnedURL(it->first, it->second);
+}
+
+void TopSites::ApplyBlacklistAndPinnedURLs(const MostVisitedURLList& urls,
+ MostVisitedURLList* out) {
+ lock_.AssertAcquired();
+ MostVisitedURLList urls_copy;
+ for (size_t i = 0; i < urls.size(); i++) {
+ if (!IsBlacklisted(urls[i].url))
+ urls_copy.push_back(urls[i]);
+ }
+
+ for (size_t pinned_index = 0; pinned_index < kTopSitesShown; pinned_index++) {
+ GURL url;
+ bool found = GetPinnedURLAtIndex(pinned_index, &url);
+ if (!found)
+ continue;
+
+ DCHECK(!url.is_empty());
+ int cur_index = IndexOf(urls_copy, url);
+ MostVisitedURL tmp;
+ if (cur_index < 0) {
+ // Pinned URL not in urls.
+ tmp.url = url;
+ } else {
+ tmp = urls_copy[cur_index];
+ urls_copy.erase(urls_copy.begin() + cur_index);
+ }
+ if (pinned_index > out->size())
+ out->resize(pinned_index); // Add empty URLs as fillers.
+ out->insert(out->begin() + pinned_index, tmp);
+ }
+
+ // Add non-pinned URLs in the empty spots.
+ size_t current_url = 0; // Index into the remaining URLs in urls_copy.
+ for (size_t i = 0; i < kTopSitesShown && current_url < urls_copy.size();
+ i++) {
+ if (i == out->size()) {
+ out->push_back(urls_copy[current_url]);
+ current_url++;
+ } else if (i < out->size()) {
+ if ((*out)[i].url.is_empty()) {
+ // Replace the filler
+ (*out)[i] = urls_copy[current_url];
+ current_url++;
+ }
+ } else {
+ NOTREACHED();
+ }
+ }
+}
+
+std::string TopSites::GetURLString(const GURL& url) {
+ lock_.AssertAcquired();
+ return GetCanonicalURL(url).spec();
+}
+
+std::string TopSites::GetURLHash(const GURL& url) {
+ lock_.AssertAcquired();
+ // We don't use canonical URLs here to be able to blacklist only one of
+ // the two 'duplicate' sites, e.g. 'gmail.com' and 'mail.google.com'.
+ return MD5String(url.spec());
+}
+
void TopSites::UpdateMostVisited(MostVisitedURLList most_visited) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
- // TODO(brettw) filter for blacklist!
- if (!top_sites_.empty()) {
- std::vector<size_t> added; // Indices into most_visited.
- std::vector<size_t> deleted; // Indices into top_sites_.
- std::vector<size_t> moved; // Indices into most_visited.
- DiffMostVisited(top_sites_, most_visited, &added, &deleted, &moved);
+ std::vector<size_t> added; // Indices into most_visited.
+ std::vector<size_t> deleted; // Indices into top_sites_.
+ std::vector<size_t> moved; // Indices into most_visited.
+
+ DiffMostVisited(top_sites_, most_visited, &added, &deleted, &moved);
+
+ // #added == #deleted; #added + #moved = total.
+ last_num_urls_changed_ = added.size() + moved.size();
- // #added == #deleted; #added + #moved = total.
- last_num_urls_changed_ = added.size() + moved.size();
+ {
+ AutoLock lock(lock_);
// Process the diff: delete from images and disk, add to disk.
// Delete all the thumbnails associated with URLs that were deleted.
@@ -243,22 +411,23 @@ void TopSites::UpdateMostVisited(MostVisitedURLList most_visited) {
top_images_.find(deleted_url.url);
if (found != top_images_.end())
top_images_.erase(found);
+ }
+ }
- // Delete from disk.
+ // Write the updates to the DB.
+ if (db_.get()) {
+ for (size_t i = 0; i < deleted.size(); i++) {
+ const MostVisitedURL& deleted_url = top_sites_[deleted[i]];
if (db_.get())
db_->RemoveURL(deleted_url);
}
-
- if (db_.get()) {
- // Write both added and moved urls.
- for (size_t i = 0; i < added.size(); i++) {
- MostVisitedURL& added_url = most_visited[added[i]];
- db_->SetPageThumbnail(added_url, added[i], Images());
- }
- for (size_t i = 0; i < moved.size(); i++) {
- MostVisitedURL moved_url = most_visited[moved[i]];
- db_->UpdatePageRank(moved_url, moved[i]);
- }
+ for (size_t i = 0; i < added.size(); i++) {
+ const MostVisitedURL& added_url = most_visited[added[i]];
+ db_->SetPageThumbnail(added_url, added[i], Images());
+ }
+ for (size_t i = 0; i < moved.size(); i++) {
+ const MostVisitedURL& moved_url = most_visited[moved[i]];
+ db_->UpdatePageRank(moved_url, moved[i]);
}
}
@@ -285,6 +454,9 @@ void TopSites::UpdateMostVisited(MostVisitedURLList most_visited) {
void TopSites::OnMigrationDone() {
migration_in_progress_ = false;
+ if (!profile_)
+ return;
+
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
// |hs| may be null during unit tests.
if (!hs)
@@ -302,6 +474,12 @@ void TopSites::AddTemporaryThumbnail(const GURL& url,
void TopSites::StartQueryForThumbnail(size_t index) {
DCHECK(migration_in_progress_);
+ if (top_sites_[index].url.spec() ==
+ l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL) ||
+ top_sites_[index].url.spec() ==
+ l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL))
+ return; // Don't need thumbnails for prepopulated URLs.
+
migration_pending_urls_.insert(top_sites_[index].url);
if (mock_history_service_) {
@@ -316,6 +494,9 @@ void TopSites::StartQueryForThumbnail(size_t index) {
return;
}
+ if (!profile_)
+ return;
+
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
// |hs| may be null during unit tests.
if (!hs)
@@ -327,54 +508,81 @@ void TopSites::StartQueryForThumbnail(size_t index) {
cancelable_consumer_.SetClientData(hs, handle, index);
}
-void TopSites::StoreMostVisited(MostVisitedURLList* most_visited) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
- // Take ownership of the most visited data.
- top_sites_.clear();
- top_sites_.swap(*most_visited);
- waiting_for_results_ = false;
-
- // Save the redirect information for quickly mapping to the canonical URLs.
+void TopSites::GenerateCanonicalURLs() {
+ lock_.AssertAcquired();
canonical_urls_.clear();
for (size_t i = 0; i < top_sites_.size(); i++) {
const MostVisitedURL& mv = top_sites_[i];
StoreRedirectChain(mv.redirects, i);
+ }
+}
+
+void TopSites::StoreMostVisited(MostVisitedURLList* most_visited) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
+ MostVisitedURLList filtered_urls;
+ PendingCallbackSet callbacks;
+ {
+ AutoLock lock(lock_);
+ top_sites_.clear();
+ // Take ownership of the most visited data.
+ top_sites_.swap(*most_visited);
+ waiting_for_results_ = false;
- std::map<GURL, Images>::iterator it = temp_thumbnails_map_.begin();
- GURL canonical_url = GetCanonicalURL(mv.url);
- for (; it != temp_thumbnails_map_.end(); it++) {
- // Must map all temp URLs to canonical ones.
- // temp_thumbnails_map_ contains non-canonical URLs, because
- // when we add a temp thumbnail, redirect chain is not known.
- // This is slow, but temp_thumbnails_map_ should have very few URLs.
- if (canonical_url == GetCanonicalURL(it->first)) {
- SetPageThumbnail(mv.url, it->second.thumbnail,
- it->second.thumbnail_score);
- temp_thumbnails_map_.erase(it);
- break;
+ // Save the redirect information for quickly mapping to the canonical URLs.
+ GenerateCanonicalURLs();
+
+ for (size_t i = 0; i < top_sites_.size(); i++) {
+ const MostVisitedURL& mv = top_sites_[i];
+ std::map<GURL, Images>::iterator it = temp_thumbnails_map_.begin();
+ GURL canonical_url = GetCanonicalURL(mv.url);
+ for (; it != temp_thumbnails_map_.end(); it++) {
+ // Must map all temp URLs to canonical ones.
+ // temp_thumbnails_map_ contains non-canonical URLs, because
+ // when we add a temp thumbnail, redirect chain is not known.
+ // This is slow, but temp_thumbnails_map_ should have very few URLs.
+ if (canonical_url == GetCanonicalURL(it->first)) {
+ SetPageThumbnailEncoded(mv.url, it->second.thumbnail,
+ it->second.thumbnail_score);
+ temp_thumbnails_map_.erase(it);
+ break;
+ }
}
}
- }
- if (top_sites_.size() >= kTopSitesNumber)
- temp_thumbnails_map_.clear();
+ if (top_sites_.size() >= kTopSitesNumber)
+ temp_thumbnails_map_.clear();
+
+ if (pending_callbacks_.empty())
+ return;
+
+ ApplyBlacklistAndPinnedURLs(top_sites_, &filtered_urls);
+ callbacks.swap(pending_callbacks_);
+ } // lock_ is released.
+ // Process callbacks outside the lock - ForwardResults may cause
+ // thread switches.
+ ProcessPendingCallbacks(callbacks, filtered_urls);
}
void TopSites::StoreRedirectChain(const RedirectList& redirects,
size_t destination) {
+ lock_.AssertAcquired();
if (redirects.empty()) {
NOTREACHED();
return;
}
// Map all the redirected URLs to the destination.
- for (size_t i = 0; i < redirects.size(); i++)
- canonical_urls_[redirects[i]] = destination;
+ for (size_t i = 0; i < redirects.size(); i++) {
+ // If this redirect is already known, don't replace it with a new one.
+ if (canonical_urls_.find(redirects[i]) == canonical_urls_.end())
+ canonical_urls_[redirects[i]] = destination;
+ }
}
GURL TopSites::GetCanonicalURL(const GURL& url) const {
+ lock_.AssertAcquired();
std::map<GURL, size_t>::const_iterator found = canonical_urls_.find(url);
if (found == canonical_urls_.end())
- return GURL(); // Don't know anything about this URL.
+ return url; // Unknown URL - return unchanged.
return top_sites_[found->second].url;
}
@@ -435,16 +643,19 @@ void TopSites::StartQueryForMostVisited() {
// Testing with a mockup.
// QueryMostVisitedURLs is not virtual, so we have to duplicate the code.
mock_history_service_->QueryMostVisitedURLs(
- kTopSitesNumber,
+ kTopSitesNumber + blacklist_->size(),
kDaysOfHistory,
&cancelable_consumer_,
NewCallback(this, &TopSites::OnTopSitesAvailable));
} else {
+ if (!profile_)
+ return;
+
HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
// |hs| may be null during unit tests.
if (hs) {
hs->QueryMostVisitedURLs(
- kTopSitesNumber,
+ kTopSitesNumber + blacklist_->size(),
kDaysOfHistory,
&cancelable_consumer_,
NewCallback(this, &TopSites::OnTopSitesAvailable));
@@ -455,11 +666,106 @@ void TopSites::StartQueryForMostVisited() {
}
void TopSites::StartMigration() {
+ LOG(INFO) << "Starting migration to TopSites.";
migration_in_progress_ = true;
StartQueryForMostVisited();
+ MigratePinnedURLs();
+}
+
+bool TopSites::HasBlacklistedItems() const {
+ AutoLock lock(lock_);
+ return !blacklist_->empty();
+}
+
+void TopSites::AddBlacklistedURL(const GURL& url) {
+ AutoLock lock(lock_);
+ RemovePinnedURLLocked(url);
+ Value* dummy = Value::CreateNullValue();
+ blacklist_->SetWithoutPathExpansion(GetURLHash(url), dummy);
+}
+
+bool TopSites::IsBlacklisted(const GURL& url) {
+ lock_.AssertAcquired();
+ bool result = blacklist_->HasKey(GetURLHash(url));
+ return result;
+}
+
+void TopSites::RemoveBlacklistedURL(const GURL& url) {
+ AutoLock lock(lock_);
+ blacklist_->RemoveWithoutPathExpansion(GetURLHash(url), NULL);
+}
+
+void TopSites::ClearBlacklistedURLs() {
+ blacklist_->Clear();
+}
+
+void TopSites::AddPinnedURL(const GURL& url, size_t pinned_index) {
+ GURL old;
+ if (GetPinnedURLAtIndex(pinned_index, &old)) {
+ RemovePinnedURL(old);
+ }
+
+ if (IsURLPinned(url)) {
+ RemovePinnedURL(url);
+ }
+
+ Value* index = Value::CreateIntegerValue(pinned_index);
+ AutoLock lock(lock_);
+ pinned_urls_->SetWithoutPathExpansion(GetURLString(url), index);
+}
+
+void TopSites::RemovePinnedURL(const GURL& url) {
+ AutoLock lock(lock_);
+ RemovePinnedURLLocked(url);
+}
+
+void TopSites::RemovePinnedURLLocked(const GURL& url) {
+ lock_.AssertAcquired();
+ pinned_urls_->RemoveWithoutPathExpansion(GetURLString(url), NULL);
+}
+
+bool TopSites::IsURLPinned(const GURL& url) {
+ AutoLock lock(lock_);
+ int tmp;
+ bool result = pinned_urls_->GetIntegerWithoutPathExpansion(
+ GetURLString(url), &tmp);
+ return result;
+}
+
+bool TopSites::GetPinnedURLAtIndex(size_t index, GURL* url) {
+ for (DictionaryValue::key_iterator it = pinned_urls_->begin_keys();
+ it != pinned_urls_->end_keys(); ++it) {
+ int current_index;
+ if (pinned_urls_->GetIntegerWithoutPathExpansion(*it, &current_index)) {
+ if (static_cast<size_t>(current_index) == index) {
+ *url = GURL(*it);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// static
+void TopSites::DeleteTopSites(scoped_refptr<TopSites>& ptr) {
+ if (!ptr.get() || !MessageLoop::current())
+ return;
+ if (ChromeThread::IsWellKnownThread(ChromeThread::UI)) {
+ ptr = NULL;
+ } else {
+ // Need to roll our own UI thread.
+ ChromeThread ui_loop(ChromeThread::UI, MessageLoop::current());
+ ptr = NULL;
+ MessageLoop::current()->RunAllPending();
+ }
+}
+
+void TopSites::ClearProfile() {
+ profile_ = NULL;
}
base::TimeDelta TopSites::GetUpdateDelay() {
+ AutoLock lock(lock_);
if (top_sites_.size() == 0)
return base::TimeDelta::FromSeconds(30);
@@ -472,29 +778,36 @@ base::TimeDelta TopSites::GetUpdateDelay() {
void TopSites::OnTopSitesAvailable(
CancelableRequestProvider::Handle handle,
MostVisitedURLList pages) {
- if (!pending_callbacks_.empty()) {
- PendingCallbackSet copy(pending_callbacks_);
- PendingCallbackSet::iterator i;
- for (i = pending_callbacks_.begin();
- i != pending_callbacks_.end(); ++i) {
- scoped_refptr<CancelableRequest<GetTopSitesCallback> > request = *i;
- if (!request->canceled())
- request->ForwardResult(GetTopSitesCallback::TupleType(pages));
- }
- pending_callbacks_.clear();
- }
-
+ AddPrepopulatedPages(&pages);
ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, NewRunnableMethod(
this, &TopSites::UpdateMostVisited, pages));
}
+// static
+void TopSites::ProcessPendingCallbacks(PendingCallbackSet pending_callbacks,
+ const MostVisitedURLList& urls) {
+ PendingCallbackSet::iterator i;
+ for (i = pending_callbacks.begin();
+ i != pending_callbacks.end(); ++i) {
+ scoped_refptr<CancelableRequest<GetTopSitesCallback> > request = *i;
+ if (!request->canceled())
+ request->ForwardResult(GetTopSitesCallback::TupleType(urls));
+ }
+ pending_callbacks.clear();
+}
+
void TopSites::OnThumbnailAvailable(CancelableRequestProvider::Handle handle,
scoped_refptr<RefCountedBytes> thumbnail) {
size_t index;
if (mock_history_service_) {
index = handle;
} else {
+ if (!profile_)
+ return;
+
HistoryService* hs = profile_ ->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (!hs)
+ return;
index = cancelable_consumer_.GetClientData(hs, handle);
}
DCHECK(static_cast<size_t>(index) < top_sites_.size());
@@ -504,7 +817,8 @@ void TopSites::OnThumbnailAvailable(CancelableRequestProvider::Handle handle,
if (thumbnail.get() && thumbnail->size()) {
const MostVisitedURL& url = top_sites_[index];
- SetPageThumbnail(url.url, thumbnail, ThumbnailScore());
+ AutoLock lock(lock_);
+ SetPageThumbnailEncoded(url.url, thumbnail, ThumbnailScore());
}
if (migration_in_progress_ && migration_pending_urls_.empty() &&
@@ -519,6 +833,7 @@ void TopSites::SetMockHistoryService(MockHistoryService* mhs) {
void TopSites::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
+ AutoLock lock(lock_);
if (type == NotificationType::HISTORY_URLS_DELETED) {
Details<history::URLsDeletedDetails> deleted_details(details);
if (deleted_details->all_history) {
@@ -526,25 +841,34 @@ void TopSites::Observe(NotificationType type,
ChromeThread::PostTask(ChromeThread::DB, FROM_HERE,
NewRunnableMethod(this, &TopSites::ResetDatabase));
} else {
+ std::set<size_t> indices_to_delete; // Indices into top_sites_.
std::set<GURL>::iterator it;
for (it = deleted_details->urls.begin();
it != deleted_details->urls.end(); ++it) {
- for (size_t i = 0; i < top_sites_.size(); i++) {
- if (top_sites_[i].url == *it) {
- top_sites_.erase(top_sites_.begin() + i);
- break;
- }
- }
+ std::map<GURL,size_t>::const_iterator found = canonical_urls_.find(*it);
+ if (found != canonical_urls_.end())
+ indices_to_delete.insert(found->second);
+ }
+
+ for (std::set<size_t>::reverse_iterator i = indices_to_delete.rbegin();
+ i != indices_to_delete.rend(); i++) {
+ size_t index = *i;
+ RemovePinnedURLLocked(top_sites_[index].url);
+ top_sites_.erase(top_sites_.begin() + index);
}
}
+ // Canonical URLs are not valid any more.
+ GenerateCanonicalURLs();
StartQueryForMostVisited();
} else if (type == NotificationType::NAV_ENTRY_COMMITTED) {
if (top_sites_.size() < kTopSitesNumber) {
- const NavigationController::LoadCommittedDetails& load_details =
- *Details<NavigationController::LoadCommittedDetails>(details).ptr();
- GURL url = load_details.entry->url();
+ NavigationController::LoadCommittedDetails* load_details =
+ Details<NavigationController::LoadCommittedDetails>(details).ptr();
+ if (!load_details)
+ return;
+ GURL url = load_details->entry->url();
if (canonical_urls_.find(url) == canonical_urls_.end() &&
- HistoryService::CanAddURL(url)) {
+ HistoryService::CanAddURL(url)) {
// Add this page to the known pages in case the thumbnail comes
// in before we get the results.
MostVisitedURL mv;
diff --git a/chrome/browser/history/top_sites.h b/chrome/browser/history/top_sites.h
index 4cc6059..c491066 100644
--- a/chrome/browser/history/top_sites.h
+++ b/chrome/browser/history/top_sites.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_TOP_SITES_H_
#define CHROME_BROWSER_HISTORY_TOP_SITES_H_
+#pragma once
#include <map>
#include <set>
@@ -17,6 +18,7 @@
#include "base/ref_counted.h"
#include "base/ref_counted_memory.h"
#include "chrome/browser/cancelable_request.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/page_usage_data.h"
@@ -24,6 +26,7 @@
#include "chrome/common/thumbnail_score.h"
#include "googleurl/src/gurl.h"
+class DictionaryValue;
class SkBitmap;
class Profile;
@@ -45,12 +48,17 @@ typedef std::vector<MostVisitedURL> MostVisitedURLList;
// new tab page requests on the I/O thread without proxying to the UI thread is
// a nontrivial performance win, especially when the browser is starting and
// the UI thread is busy.
-class TopSites : public NotificationObserver,
- public base::RefCountedThreadSafe<TopSites>,
- public CancelableRequestProvider {
+class TopSites :
+ public base::RefCountedThreadSafe<TopSites,
+ ChromeThread::DeleteOnUIThread>,
+ public NotificationObserver,
+ public CancelableRequestProvider {
public:
explicit TopSites(Profile* profile);
+ // Returns whether top sites is enabled.
+ static bool IsEnabled();
+
class MockHistoryService {
// A mockup of a HistoryService used for testing TopSites.
public:
@@ -66,14 +74,6 @@ class TopSites : public NotificationObserver,
size_t index) = 0;
};
- struct Images {
- scoped_refptr<RefCountedBytes> thumbnail;
- ThumbnailScore thumbnail_score;
-
- // TODO(brettw): this will eventually store the favicon.
- // scoped_refptr<RefCountedBytes> favicon;
- };
-
// Initializes TopSites.
void Init(const FilePath& db_name);
@@ -85,7 +85,9 @@ class TopSites : public NotificationObserver,
const ThumbnailScore& score);
// Callback for GetMostVisitedURLs.
- typedef Callback1<const MostVisitedURLList&>::Type GetTopSitesCallback;
+ typedef Callback1<MostVisitedURLList>::Type GetTopSitesCallback;
+ typedef std::set<scoped_refptr<CancelableRequest<GetTopSitesCallback> > >
+ PendingCallbackSet;
// Returns a list of most visited URLs via a callback.
// NOTE: the callback may be called immediately if we have the data cached.
@@ -101,18 +103,63 @@ class TopSites : public NotificationObserver,
// Start reading thumbnails from the ThumbnailDatabase.
void StartMigration();
+ // Blacklisted URLs
+
+ // Returns true if there is at least one item in the blacklist.
+ bool HasBlacklistedItems() const;
+
+ // Add a URL to the blacklist.
+ void AddBlacklistedURL(const GURL& url);
+
+ // Removes a URL from the blacklist.
+ void RemoveBlacklistedURL(const GURL& url);
+
+ // Clear the blacklist.
+ void ClearBlacklistedURLs();
+
+ // Pinned URLs
+
+ // Pin a URL at |index|.
+ void AddPinnedURL(const GURL& url, size_t index);
+
+ // Returns true if a URL is pinned.
+ bool IsURLPinned(const GURL& url);
+
+ // Unpin a URL.
+ void RemovePinnedURL(const GURL& url);
+
+ // Return a URL pinned at |index| via |out|. Returns true if there
+ // is a URL pinned at |index|.
+ bool GetPinnedURLAtIndex(size_t index, GURL* out);
+
+ // TopSites must be deleted on a UI thread. This happens
+ // automatically in a real browser, but in unit_tests we don't have
+ // a real UI thread. Use this function to delete a TopSites object.
+ static void DeleteTopSites(scoped_refptr<TopSites>& ptr);
+
+ // Sets the profile pointer to NULL. This is for the case where
+ // TopSites outlives the profile, since TopSites is refcounted.
+ void ClearProfile();
+
private:
- friend class base::RefCountedThreadSafe<TopSites>;
+ friend struct ChromeThread::DeleteOnThread<ChromeThread::UI>;
+ friend class DeleteTask<TopSites>;
friend class TopSitesTest;
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, GetMostVisited);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, RealDatabase);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, MockDatabase);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, DeleteNotifications);
+ FRIEND_TEST_ALL_PREFIXES(TopSitesTest, PinnedURLsDeleted);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, GetUpdateDelay);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, Migration);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, QueueingRequestsForTopSites);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, CancelingRequestsForTopSites);
FRIEND_TEST_ALL_PREFIXES(TopSitesTest, AddTemporaryThumbnail);
+ FRIEND_TEST_ALL_PREFIXES(TopSitesTest, Blacklisting);
+ FRIEND_TEST_ALL_PREFIXES(TopSitesTest, PinnedURLs);
+ FRIEND_TEST_ALL_PREFIXES(TopSitesTest, BlacklistingAndPinnedURLs);
+ FRIEND_TEST_ALL_PREFIXES(TopSitesTest, AddPrepopulatedPages);
+ FRIEND_TEST_ALL_PREFIXES(TopSitesTest, GetPageThumbnail);
~TopSites();
@@ -125,9 +172,9 @@ class TopSites : public NotificationObserver,
// A version of SetPageThumbnail that takes RefCountedBytes as
// returned by HistoryService.
- bool SetPageThumbnail(const GURL& url,
- const RefCountedBytes* thumbnail,
- const ThumbnailScore& score);
+ bool SetPageThumbnailEncoded(const GURL& url,
+ const RefCountedBytes* thumbnail,
+ const ThumbnailScore& score);
// Query history service for the list of available thumbnails.
void StartQueryForMostVisited();
@@ -140,10 +187,17 @@ class TopSites : public NotificationObserver,
void OnTopSitesAvailable(CancelableRequestProvider::Handle handle,
MostVisitedURLList data);
+ // Returns a list of urls to each pending callback.
+ static void ProcessPendingCallbacks(PendingCallbackSet pending_callbacks,
+ const MostVisitedURLList& urls);
+
// Called when history service returns a thumbnail.
void OnThumbnailAvailable(CancelableRequestProvider::Handle handle,
scoped_refptr<RefCountedBytes> thumbnail);
+ // Sets canonical_urls_ from top_sites_.
+ void GenerateCanonicalURLs();
+
// Saves the set of the top URLs visited by this user. The 0th item is the
// most popular.
// DANGER! This will clear all data from the input argument.
@@ -186,6 +240,12 @@ class TopSites : public NotificationObserver,
const NotificationSource& source,
const NotificationDetails& details);
+ // Returns true if the URL is blacklisted.
+ bool IsBlacklisted(const GURL& url);
+
+ // A variant of RemovePinnedURL that must be called within a lock.
+ void RemovePinnedURLLocked(const GURL& url);
+
// Returns the delay until the next update of history is needed.
// Uses num_urls_changed
base::TimeDelta GetUpdateDelay();
@@ -200,7 +260,7 @@ class TopSites : public NotificationObserver,
// Write a thumbnail to database.
void WriteThumbnailToDB(const MostVisitedURL& url,
int url_rank,
- const TopSites::Images& thumbnail);
+ const Images& thumbnail);
// Updates the top sites list and writes the difference to disk.
void UpdateMostVisited(MostVisitedURLList most_visited);
@@ -216,6 +276,25 @@ class TopSites : public NotificationObserver,
const RefCountedBytes* thumbnail,
const ThumbnailScore& score);
+ // Add prepopulated pages: 'welcome to Chrome' and themes gallery.
+ // Returns true if any pages were added.
+ bool AddPrepopulatedPages(MostVisitedURLList* urls);
+
+ // Convert pinned_urls_ dictionary to the new format. Use URLs as
+ // dictionary keys.
+ void MigratePinnedURLs();
+
+ // Takes |urls|, produces it's copy in |out| after removing
+ // blacklisted URLs and reordering pinned URLs.
+ void ApplyBlacklistAndPinnedURLs(const MostVisitedURLList& urls,
+ MostVisitedURLList* out);
+
+ // Converts a url into a canonical string representation.
+ std::string GetURLString(const GURL& url);
+
+ // Returns an MD5 hash of the URL. Hashing is required for blacklisted URLs.
+ std::string GetURLHash(const GURL& url);
+
Profile* profile_;
// A mockup to use for testing. If NULL, use the real HistoryService
// from the profile_. See SetMockHistoryService.
@@ -257,8 +336,6 @@ class TopSites : public NotificationObserver,
// The map of requests for the top sites list. Can only be
// non-empty at startup. After we read the top sites from the DB, we'll
// always have a cached list.
- typedef std::set<scoped_refptr<CancelableRequest<GetTopSitesCallback> > >
- PendingCallbackSet;
PendingCallbackSet pending_callbacks_;
// Are we waiting for the top sites from HistoryService?
@@ -270,8 +347,20 @@ class TopSites : public NotificationObserver,
// UpdateMostVisitedURLs call.
std::map<GURL, Images> temp_thumbnails_map_;
- // TODO(brettw): use the blacklist.
- // std::set<GURL> blacklist_;
+ // Blacklisted and pinned URLs are stored in Preferences.
+
+ // Blacklisted URLs. They are filtered out from the list of Top
+ // Sites when GetMostVisitedURLs is called. Note that we are still
+ // storing all URLs, but filtering on access. It is a dictionary,
+ // key is the URL, value is a dummy value. This is owned by the
+ // PrefService.
+ DictionaryValue* blacklist_;
+
+ // This is a dictionary for the pinned URLs for the the most visited
+ // part of the new tab page. Key is the URL, value is
+ // index where it is pinned at (may be the same as key). This is
+ // owned by the PrefService.
+ DictionaryValue* pinned_urls_;
DISALLOW_COPY_AND_ASSIGN(TopSites);
};
diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc
index 99f0bb4..05a588a 100644
--- a/chrome/browser/history/top_sites_database.cc
+++ b/chrome/browser/history/top_sites_database.cc
@@ -5,6 +5,7 @@
#include "app/sql/transaction.h"
#include "base/string_util.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
+#include "chrome/browser/history/history_types.h"
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/history/top_sites_database.h"
@@ -13,6 +14,9 @@ namespace history {
TopSitesDatabaseImpl::TopSitesDatabaseImpl() {
}
+TopSitesDatabaseImpl::~TopSitesDatabaseImpl() {
+}
+
bool TopSitesDatabaseImpl::Init(const FilePath& db_name) {
// Settings copied from ThumbnailDatabase.
db_.set_error_delegate(GetErrorHandlerForThumbnailDb());
@@ -48,7 +52,7 @@ bool TopSitesDatabaseImpl::InitThumbnailTable() {
void TopSitesDatabaseImpl::GetPageThumbnails(MostVisitedURLList* urls,
std::map<GURL,
- TopSites::Images>* thumbnails) {
+ Images>* thumbnails) {
sql::Statement statement(db_.GetCachedStatement(
SQL_FROM_HERE,
"SELECT url, url_rank, title, thumbnail, redirects, "
@@ -75,7 +79,7 @@ void TopSitesDatabaseImpl::GetPageThumbnails(MostVisitedURLList* urls,
std::vector<unsigned char> data;
statement.ColumnBlobAsVector(3, &data);
- TopSites::Images thumbnail;
+ Images thumbnail;
thumbnail.thumbnail = RefCountedBytes::TakeVector(&data);
thumbnail.thumbnail_score.boring_score = statement.ColumnDouble(5);
thumbnail.thumbnail_score.good_clipping = statement.ColumnBool(6);
@@ -106,7 +110,7 @@ void TopSitesDatabaseImpl::SetRedirects(const std::string& redirects,
void TopSitesDatabaseImpl::SetPageThumbnail(const MostVisitedURL& url,
int new_rank,
- const TopSites::Images& thumbnail) {
+ const Images& thumbnail) {
sql::Transaction transaction(&db_);
transaction.Begin();
@@ -122,7 +126,7 @@ void TopSitesDatabaseImpl::SetPageThumbnail(const MostVisitedURL& url,
}
void TopSitesDatabaseImpl::UpdatePageThumbnail(
- const MostVisitedURL& url, const TopSites::Images& thumbnail) {
+ const MostVisitedURL& url, const Images& thumbnail) {
sql::Statement statement(db_.GetCachedStatement(
SQL_FROM_HERE,
"UPDATE thumbnails SET "
@@ -150,7 +154,7 @@ void TopSitesDatabaseImpl::UpdatePageThumbnail(
void TopSitesDatabaseImpl::AddPageThumbnail(const MostVisitedURL& url,
int new_rank,
- const TopSites::Images& thumbnail) {
+ const Images& thumbnail) {
int count = GetRowCount();
sql::Statement statement(db_.GetCachedStatement(
@@ -194,7 +198,7 @@ void TopSitesDatabaseImpl::UpdatePageRankNoTransaction(
const MostVisitedURL& url, int new_rank) {
int prev_rank = GetURLRank(url);
if (prev_rank == -1) {
- NOTREACHED() << "Updating rank of an unknown URL: " << url.url.spec();
+ LOG(WARNING) << "Updating rank of an unknown URL: " << url.url.spec();
return;
}
@@ -236,7 +240,7 @@ void TopSitesDatabaseImpl::UpdatePageRankNoTransaction(
}
bool TopSitesDatabaseImpl::GetPageThumbnail(const GURL& url,
- TopSites::Images* thumbnail) {
+ Images* thumbnail) {
sql::Statement statement(db_.GetCachedStatement(
SQL_FROM_HERE,
"SELECT thumbnail, boring_score, good_clipping, at_top, last_updated "
diff --git a/chrome/browser/history/top_sites_database.h b/chrome/browser/history/top_sites_database.h
index cfb362c..edfb4e5 100644
--- a/chrome/browser/history/top_sites_database.h
+++ b/chrome/browser/history/top_sites_database.h
@@ -4,20 +4,19 @@
#ifndef CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_
#define CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_
+#pragma once
#include <map>
#include <string>
-#include <vector>
#include "app/sql/connection.h"
#include "base/ref_counted.h"
-#include "chrome/browser/history/history_types.h"
#include "chrome/browser/history/url_database.h" // For DBCloseScoper.
class FilePath;
class RefCountedMemory;
class SkBitmap;
-class TopSites;
+class Images;
namespace base {
class Time;
@@ -37,7 +36,7 @@ class TopSitesDatabase {
// Returns a list of all URLs currently in the table.
virtual void GetPageThumbnails(MostVisitedURLList* urls,
std::map<GURL,
- TopSites::Images>* thumbnails) = 0;
+ Images>* thumbnails) = 0;
// Set a thumbnail for a URL. |url_rank| is the position of the URL
// in the list of TopURLs, zero-based.
@@ -45,20 +44,20 @@ class TopSitesDatabase {
// thumbnail.
virtual void SetPageThumbnail(const MostVisitedURL& url,
int url_rank,
- const TopSites::Images& thumbnail) = 0;
+ const Images& thumbnail) = 0;
// Update rank of a URL that's already in the database.
virtual void UpdatePageRank(const MostVisitedURL& url, int new_rank) = 0;
// Convenience wrapper.
bool GetPageThumbnail(const MostVisitedURL& url,
- TopSites::Images* thumbnail) {
+ Images* thumbnail) {
return GetPageThumbnail(url.url, thumbnail);
}
// Get a thumbnail for a given page. Returns true iff we have the thumbnail.
virtual bool GetPageThumbnail(const GURL& url,
- TopSites::Images* thumbnail) = 0;
+ Images* thumbnail) = 0;
// Remove the record for this URL. Returns true iff removed successfully.
virtual bool RemoveURL(const MostVisitedURL& url) = 0;
@@ -67,7 +66,7 @@ class TopSitesDatabase {
class TopSitesDatabaseImpl : public TopSitesDatabase {
public:
TopSitesDatabaseImpl();
- ~TopSitesDatabaseImpl() {}
+ virtual ~TopSitesDatabaseImpl();
// Must be called after creation but before any other methods are called.
// Returns true on success. If false, no other functions should be called.
@@ -78,7 +77,7 @@ class TopSitesDatabaseImpl : public TopSitesDatabase {
// Returns a list of all URLs currently in the table.
// WARNING: clears both input arguments.
virtual void GetPageThumbnails(MostVisitedURLList* urls,
- std::map<GURL, TopSites::Images>* thumbnails);
+ std::map<GURL, Images>* thumbnails);
// Set a thumbnail for a URL. |url_rank| is the position of the URL
// in the list of TopURLs, zero-based.
@@ -86,7 +85,7 @@ class TopSitesDatabaseImpl : public TopSitesDatabase {
// thumbnail and rank. Shift the ranks of other URLs if necessary.
virtual void SetPageThumbnail(const MostVisitedURL& url,
int new_rank,
- const TopSites::Images& thumbnail);
+ const Images& thumbnail);
// Sets the rank for a given URL. The URL must be in the database.
// Use SetPageThumbnail if it's not.
@@ -94,7 +93,7 @@ class TopSitesDatabaseImpl : public TopSitesDatabase {
// Get a thumbnail for a given page. Returns true iff we have the thumbnail.
virtual bool GetPageThumbnail(const GURL& url,
- TopSites::Images* thumbnail);
+ Images* thumbnail);
// Remove the record for this URL. Returns true iff removed successfully.
virtual bool RemoveURL(const MostVisitedURL& url);
@@ -107,14 +106,14 @@ class TopSitesDatabaseImpl : public TopSitesDatabase {
// Adds a new URL to the database.
void AddPageThumbnail(const MostVisitedURL& url,
int new_rank,
- const TopSites::Images& thumbnail);
+ const Images& thumbnail);
// Sets the page rank. Should be called within an open transaction.
void UpdatePageRankNoTransaction(const MostVisitedURL& url, int new_rank);
// Updates thumbnail of a URL that's already in the database.
void UpdatePageThumbnail(const MostVisitedURL& url,
- const TopSites::Images& thumbnail);
+ const Images& thumbnail);
// Returns the URL's current rank or -1 if it is not present.
int GetURLRank(const MostVisitedURL& url);
diff --git a/chrome/browser/history/top_sites_unittest.cc b/chrome/browser/history/top_sites_unittest.cc
index a6b7e7b..c327647 100644
--- a/chrome/browser/history/top_sites_unittest.cc
+++ b/chrome/browser/history/top_sites_unittest.cc
@@ -1,18 +1,27 @@
-// 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.
+#include "app/l10n_util.h"
+#include "base/file_util.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/top_sites.h"
-#include "chrome/common/chrome_paths.h"
+#include "chrome/browser/dom_ui/most_visited_handler.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/history/top_sites_database.h"
#include "chrome/browser/history/history_notifications.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/test/testing_profile.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
#include "gfx/codec/jpeg_codec.h"
#include "googleurl/src/gurl.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -38,6 +47,13 @@ class TopSitesTest : public testing::Test {
RefCountedBytes* weewar_thumbnail() { return weewar_thumbnail_; }
CancelableRequestConsumer* consumer() { return &consumer_; }
size_t number_of_callbacks() {return number_of_callbacks_; }
+ // Prepopulated URLs - added at the back of TopSites.
+ GURL welcome_url() {
+ return GURL(l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL));
+ }
+ GURL themes_url() {
+ return GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL));
+ }
virtual void SetUp() {
profile_.reset(new TestingProfile);
@@ -61,12 +77,12 @@ class TopSitesTest : public testing::Test {
virtual void TearDown() {
profile_.reset();
- top_sites_ = NULL;
+ TopSites::DeleteTopSites(top_sites_);
EXPECT_TRUE(file_util::Delete(file_name_, false));
}
// Callback for TopSites::GetMostVisitedURLs.
- void OnTopSitesAvailable(const history::MostVisitedURLList& data) {
+ void OnTopSitesAvailable(history::MostVisitedURLList data) {
urls_ = data;
number_of_callbacks_++;
}
@@ -79,7 +95,6 @@ class TopSitesTest : public testing::Test {
}
void StoreMostVisited(std::vector<MostVisitedURL>* urls) {
- AutoLock lock(top_sites_->lock_); // The function asserts it's in the lock.
top_sites_->StoreMostVisited(urls);
}
@@ -92,6 +107,10 @@ class TopSitesTest : public testing::Test {
added_urls, deleted_urls, moved_urls);
}
+ Lock& lock() {
+ return top_sites_->lock_;
+ }
+
private:
scoped_refptr<TopSites> top_sites_;
MostVisitedURLList urls_;
@@ -108,6 +127,7 @@ class TopSitesTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(TopSitesTest);
};
+
// A mockup of a HistoryService used for testing TopSites.
class MockHistoryServiceImpl : public TopSites::MockHistoryService {
public:
@@ -151,7 +171,7 @@ class MockHistoryServiceImpl : public TopSites::MockHistoryService {
MostVisitedURLList::iterator pos = std::find(most_visited_urls_.begin(),
most_visited_urls_.end(),
mvu);
- EXPECT_TRUE(pos != most_visited_urls_.end());
+ EXPECT_TRUE(pos != most_visited_urls_.end()) << url.spec();
scoped_refptr<RefCountedBytes> thumbnail;
callback->Run(index, thumbnail);
delete callback;
@@ -175,14 +195,14 @@ class MockHistoryServiceImpl : public TopSites::MockHistoryService {
class MockTopSitesDatabaseImpl : public TopSitesDatabase {
public:
virtual void GetPageThumbnails(MostVisitedURLList* urls,
- std::map<GURL, TopSites::Images>* thumbnails) {
+ std::map<GURL, Images>* thumbnails) {
// Return a copy of the vector.
*urls = top_sites_list_;
*thumbnails = thumbnails_map_;
}
virtual void SetPageThumbnail(const MostVisitedURL& url, int url_rank,
- const TopSites::Images& thumbnail) {
+ const Images& thumbnail) {
SetPageRank(url, url_rank);
// Update thubmnail
thumbnails_map_[url.url] = thumbnail;
@@ -216,8 +236,8 @@ class MockTopSitesDatabaseImpl : public TopSitesDatabase {
// Get a thumbnail for a given page. Returns true iff we have the thumbnail.
virtual bool GetPageThumbnail(const GURL& url,
- TopSites::Images* thumbnail) {
- std::map<GURL, TopSites::Images>::const_iterator found =
+ Images* thumbnail) {
+ std::map<GURL, Images>::const_iterator found =
thumbnails_map_.find(url);
if (found == thumbnails_map_.end())
return false; // No thumbnail for this URL.
@@ -242,7 +262,7 @@ class MockTopSitesDatabaseImpl : public TopSitesDatabase {
private:
MostVisitedURLList top_sites_list_; // Keeps the URLs sorted by score (rank).
- std::map<GURL, TopSites::Images> thumbnails_map_;
+ std::map<GURL, Images> thumbnails_map_;
};
@@ -294,9 +314,9 @@ TEST_F(TopSitesTest, GetCanonicalURL) {
AppendMostVisitedURL(&most_visited, news);
StoreMostVisited(&most_visited);
- // Random URLs not in the database shouldn't be reported as being in there.
+ // Random URLs not in the database are returned unchanged.
GURL result = GetCanonicalURL(GURL("http://fark.com/"));
- EXPECT_TRUE(result.is_empty());
+ EXPECT_EQ(GURL("http://fark.com/"), result);
// Easy case, there are no redirects and the exact URL is stored.
result = GetCanonicalURL(news);
@@ -395,6 +415,50 @@ TEST_F(TopSitesTest, SetPageThumbnail) {
EXPECT_FALSE(top_sites().SetPageThumbnail(url1a, thumbnail, medium_score));
}
+TEST_F(TopSitesTest, GetPageThumbnail) {
+ ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
+ MostVisitedURLList url_list;
+ MostVisitedURL url1 = {GURL("http://asdf.com")};
+ url1.redirects.push_back(url1.url);
+ url_list.push_back(url1);
+
+ MostVisitedURL url2 = {GURL("http://gmail.com")};
+ url2.redirects.push_back(url2.url);
+ url2.redirects.push_back(GURL("http://mail.google.com"));
+ url_list.push_back(url2);
+
+ top_sites().UpdateMostVisited(url_list);
+ MessageLoop::current()->RunAllPending();
+
+ // Create a dummy thumbnail.
+ SkBitmap thumbnail;
+ thumbnail.setConfig(SkBitmap::kARGB_8888_Config, 4, 4);
+ thumbnail.allocPixels();
+ thumbnail.eraseRGB(0x00, 0x00, 0x00);
+ ThumbnailScore score(0.5, true, true, base::Time::Now());
+
+ RefCountedBytes* result = NULL;
+ EXPECT_TRUE(top_sites().SetPageThumbnail(url1.url, thumbnail, score));
+ EXPECT_TRUE(top_sites().GetPageThumbnail(url1.url, &result));
+
+ EXPECT_TRUE(top_sites().SetPageThumbnail(GURL("http://gmail.com"),
+ thumbnail, score));
+ EXPECT_TRUE(top_sites().GetPageThumbnail(GURL("http://gmail.com"),
+ &result));
+ // Get a thumbnail via a redirect.
+ EXPECT_TRUE(top_sites().GetPageThumbnail(GURL("http://mail.google.com"),
+ &result));
+
+ EXPECT_TRUE(top_sites().SetPageThumbnail(GURL("http://mail.google.com"),
+ thumbnail, score));
+ EXPECT_TRUE(top_sites().GetPageThumbnail(url2.url, &result));
+
+ scoped_ptr<SkBitmap> out_bitmap(gfx::JPEGCodec::Decode(result->front(),
+ result->size()));
+ EXPECT_EQ(0, memcmp(thumbnail.getPixels(), out_bitmap->getPixels(),
+ thumbnail.getSize()));
+}
+
TEST_F(TopSitesTest, GetMostVisited) {
ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
GURL news("http://news.google.com/");
@@ -411,9 +475,12 @@ TEST_F(TopSitesTest, GetMostVisited) {
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(2u, urls().size());
+ // 2 extra prepopulated URLs.
+ ASSERT_EQ(4u, urls().size());
EXPECT_EQ(news, urls()[0].url);
EXPECT_EQ(google, urls()[1].url);
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
}
TEST_F(TopSitesTest, MockDatabase) {
@@ -432,7 +499,7 @@ TEST_F(TopSitesTest, MockDatabase) {
url.url = asdf_url;
url.title = asdf_title;
url.redirects.push_back(url.url);
- TopSites::Images thumbnail;
+ Images thumbnail;
db->SetPageThumbnail(url, 0, thumbnail);
top_sites().ReadDatabase();
@@ -441,9 +508,11 @@ TEST_F(TopSitesTest, MockDatabase) {
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(1u, urls().size());
+ ASSERT_EQ(3u, urls().size());
EXPECT_EQ(asdf_url, urls()[0].url);
EXPECT_EQ(asdf_title, urls()[0].title);
+ EXPECT_EQ(welcome_url(), urls()[1].url);
+ EXPECT_EQ(themes_url(), urls()[2].url);
MostVisitedURL url2;
url2.url = google_url;
@@ -459,11 +528,13 @@ TEST_F(TopSitesTest, MockDatabase) {
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(2u, urls().size());
+ ASSERT_EQ(4u, urls().size());
EXPECT_EQ(google_url, urls()[0].url);
EXPECT_EQ(google_title, urls()[0].title);
EXPECT_EQ(asdf_url, urls()[1].url);
EXPECT_EQ(asdf_title, urls()[1].title);
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
MockHistoryServiceImpl hs;
// Add one old, one new URL to the history.
@@ -475,10 +546,10 @@ TEST_F(TopSitesTest, MockDatabase) {
top_sites().StartQueryForMostVisited();
MessageLoop::current()->RunAllPending();
- std::map<GURL, TopSites::Images> thumbnails;
+ std::map<GURL, Images> thumbnails;
MostVisitedURLList result;
db->GetPageThumbnails(&result, &thumbnails);
- ASSERT_EQ(2u, result.size());
+ ASSERT_EQ(4u, result.size());
EXPECT_EQ(google_title, result[0].title);
EXPECT_EQ(news_title, result[1].title);
}
@@ -500,18 +571,18 @@ TEST_F(TopSitesTest, TopSitesDB) {
url.url = asdf_url;
url.title = asdf_title;
url.redirects.push_back(url.url);
- TopSites::Images thumbnail;
+ Images thumbnail;
thumbnail.thumbnail = random_thumbnail();
// Add asdf at rank 0.
db.SetPageThumbnail(url, 0, thumbnail);
- TopSites::Images result;
+ Images result;
EXPECT_TRUE(db.GetPageThumbnail(url.url, &result));
EXPECT_EQ(thumbnail.thumbnail->data.size(), result.thumbnail->data.size());
EXPECT_TRUE(ThumbnailsAreEqual(thumbnail.thumbnail, result.thumbnail));
MostVisitedURLList urls;
- std::map<GURL, TopSites::Images> thumbnails;
+ std::map<GURL, Images> thumbnails;
db.GetPageThumbnails(&urls, &thumbnails);
ASSERT_EQ(1u, urls.size());
EXPECT_EQ(asdf_url, urls[0].url);
@@ -587,7 +658,7 @@ TEST_F(TopSitesTest, RealDatabase) {
url.url = asdf_url;
url.title = asdf_title;
url.redirects.push_back(url.url);
- TopSites::Images thumbnail;
+ Images thumbnail;
thumbnail.thumbnail = random_thumbnail();
db->SetPageThumbnail(url, 0, thumbnail);
@@ -597,11 +668,13 @@ TEST_F(TopSitesTest, RealDatabase) {
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(1u, urls().size());
+ ASSERT_EQ(3u, urls().size());
EXPECT_EQ(asdf_url, urls()[0].url);
EXPECT_EQ(asdf_title, urls()[0].title);
+ EXPECT_EQ(welcome_url(), urls()[1].url);
+ EXPECT_EQ(themes_url(), urls()[2].url);
- TopSites::Images img_result;
+ Images img_result;
db->GetPageThumbnail(asdf_url, &img_result);
EXPECT_TRUE(img_result.thumbnail != NULL);
EXPECT_TRUE(ThumbnailsAreEqual(random_thumbnail(), img_result.thumbnail));
@@ -619,7 +692,7 @@ TEST_F(TopSitesTest, RealDatabase) {
url2.redirects.push_back(google3_url);
// Add new thumbnail at rank 0 and shift the other result to 1.
- TopSites::Images g_thumbnail;
+ Images g_thumbnail;
g_thumbnail.thumbnail = google_thumbnail();
db->SetPageThumbnail(url2, 0, g_thumbnail);
@@ -629,7 +702,7 @@ TEST_F(TopSitesTest, RealDatabase) {
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(2u, urls().size());
+ ASSERT_EQ(4u, urls().size());
EXPECT_EQ(google1_url, urls()[0].url);
EXPECT_EQ(google_title, urls()[0].title);
EXPECT_TRUE(top_sites().GetPageThumbnail(google1_url, &thumbnail_result));
@@ -641,6 +714,8 @@ TEST_F(TopSitesTest, RealDatabase) {
EXPECT_EQ(asdf_url, urls()[1].url);
EXPECT_EQ(asdf_title, urls()[1].title);
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
MockHistoryServiceImpl hs;
// Add one old, one new URL to the history.
@@ -652,10 +727,10 @@ TEST_F(TopSitesTest, RealDatabase) {
top_sites().StartQueryForMostVisited();
MessageLoop::current()->RunAllPending();
- std::map<GURL, TopSites::Images> thumbnails;
+ std::map<GURL, Images> thumbnails;
MostVisitedURLList results;
db->GetPageThumbnails(&results, &thumbnails);
- ASSERT_EQ(2u, results.size());
+ ASSERT_EQ(4u, results.size());
EXPECT_EQ(google_title, results[0].title);
EXPECT_EQ(news_title, results[1].title);
@@ -673,7 +748,7 @@ TEST_F(TopSitesTest, RealDatabase) {
*weewar_bitmap,
medium_score));
RefCountedBytes* out_1;
- TopSites::Images out_2;
+ Images out_2;
EXPECT_TRUE(top_sites().GetPageThumbnail(google1_url, &out_1));
MessageLoop::current()->RunAllPending();
@@ -705,9 +780,7 @@ TEST_F(TopSitesTest, RealDatabase) {
EXPECT_TRUE(high_score.Equals(out_2.thumbnail_score));
}
-// This test has been crashing unit_tests on Mac 10.6.
-// See http://crbug.com/49799
-TEST_F(TopSitesTest, DISABLED_DeleteNotifications) {
+TEST_F(TopSitesTest, DeleteNotifications) {
ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
GURL google1_url("http://google.com");
GURL google2_url("http://google.com/redirect");
@@ -731,35 +804,116 @@ TEST_F(TopSitesTest, DISABLED_DeleteNotifications) {
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(2u, urls().size());
+ // 2 extra prepopulated URLs.
+ ASSERT_EQ(4u, urls().size());
hs.RemoveMostVisitedURL();
- history::URLsDeletedDetails details;
- details.all_history = false;
+ history::URLsDeletedDetails history_details;
+ history_details.all_history = false;
+ Details<URLsDeletedDetails> details(&history_details);
top_sites().Observe(NotificationType::HISTORY_URLS_DELETED,
Source<Profile> (&profile()),
- (const NotificationDetails&)details);
+ details);
MessageLoop::current()->RunAllPending();
top_sites().GetMostVisitedURLs(
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(1u, urls().size());
+ ASSERT_EQ(3u, urls().size());
EXPECT_EQ(google_title, urls()[0].title);
+ EXPECT_EQ(welcome_url(), urls()[1].url);
+ EXPECT_EQ(themes_url(), urls()[2].url);
+
+ hs.RemoveMostVisitedURL();
+ history_details.all_history = true;
+ details = Details<HistoryDetails>(&history_details);
+ top_sites().Observe(NotificationType::HISTORY_URLS_DELETED,
+ Source<Profile> (&profile()),
+ details);
+ MessageLoop::current()->RunAllPending();
+ top_sites().GetMostVisitedURLs(
+ consumer(),
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ ASSERT_EQ(2u, urls().size());
+ EXPECT_EQ(welcome_url(), urls()[0].url);
+ EXPECT_EQ(themes_url(), urls()[1].url);
+}
+
+TEST_F(TopSitesTest, PinnedURLsDeleted) {
+ ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
+ GURL google1_url("http://google.com");
+ GURL google2_url("http://google.com/redirect");
+ GURL google3_url("http://www.google.com");
+ string16 google_title(ASCIIToUTF16("Google"));
+ GURL news_url("http://news.google.com");
+ string16 news_title(ASCIIToUTF16("Google News"));
+
+ MockHistoryServiceImpl hs;
+
+ top_sites().Init(file_name());
+
+ hs.AppendMockPage(google1_url, google_title);
+ hs.AppendMockPage(news_url, news_title);
+ top_sites().SetMockHistoryService(&hs);
+
+ top_sites().StartQueryForMostVisited();
+ MessageLoop::current()->RunAllPending();
+ top_sites().GetMostVisitedURLs(
+ consumer(),
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(1u, number_of_callbacks());
+ // 2 extra prepopulated URLs.
+ ASSERT_EQ(4u, urls().size());
+
+ top_sites().AddPinnedURL(news_url, 3);
+ EXPECT_TRUE(top_sites().IsURLPinned(news_url));
hs.RemoveMostVisitedURL();
- details.all_history = true;
+ history::URLsDeletedDetails history_details;
+ history_details.all_history = false;
+ history_details.urls.insert(news_url);
+ Details<URLsDeletedDetails> details(&history_details);
top_sites().Observe(NotificationType::HISTORY_URLS_DELETED,
Source<Profile> (&profile()),
- (const NotificationDetails&)details);
+ details);
MessageLoop::current()->RunAllPending();
top_sites().GetMostVisitedURLs(
consumer(),
NewCallback(static_cast<TopSitesTest*>(this),
&TopSitesTest::OnTopSitesAvailable));
- ASSERT_EQ(0u, urls().size());
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(2u, number_of_callbacks());
+ ASSERT_EQ(3u, urls().size());
+ EXPECT_FALSE(top_sites().IsURLPinned(news_url));
+
+ hs.RemoveMostVisitedURL();
+ history_details.all_history = true;
+ details = Details<HistoryDetails>(&history_details);
+ top_sites().Observe(NotificationType::HISTORY_URLS_DELETED,
+ Source<Profile> (&profile()),
+ details);
+ MessageLoop::current()->RunAllPending();
+ top_sites().GetMostVisitedURLs(
+ consumer(),
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ ASSERT_EQ(2u, urls().size());
+ MessageLoop::current()->RunAllPending();
+
+ top_sites().StartQueryForMostVisited();
+ MessageLoop::current()->RunAllPending();
+ top_sites().GetMostVisitedURLs(
+ consumer(),
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ ASSERT_EQ(2u, urls().size());
+ EXPECT_EQ(welcome_url(), urls()[0].url);
+ EXPECT_EQ(themes_url(), urls()[1].url);
}
TEST_F(TopSitesTest, GetUpdateDelay) {
@@ -780,8 +934,6 @@ TEST_F(TopSitesTest, GetUpdateDelay) {
TEST_F(TopSitesTest, Migration) {
ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
GURL google1_url("http://google.com");
- GURL google2_url("http://google.com/redirect");
- GURL google3_url("http://www.google.com");
string16 google_title(ASCIIToUTF16("Google"));
GURL news_url("http://news.google.com");
string16 news_title(ASCIIToUTF16("Google News"));
@@ -793,6 +945,7 @@ TEST_F(TopSitesTest, Migration) {
hs.AppendMockPage(google1_url, google_title);
hs.AppendMockPage(news_url, news_title);
top_sites().SetMockHistoryService(&hs);
+ MessageLoop::current()->RunAllPending();
top_sites().StartMigration();
EXPECT_TRUE(top_sites().migration_in_progress_);
@@ -837,9 +990,12 @@ TEST_F(TopSitesTest, QueueingRequestsForTopSites) {
EXPECT_EQ(3u, number_of_callbacks());
- ASSERT_EQ(2u, urls().size());
+ ASSERT_EQ(4u, urls().size());
EXPECT_EQ("http://1.com/", urls()[0].url.spec());
EXPECT_EQ("http://2.com/", urls()[1].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
+
url.url = GURL("http://3.com/");
url.redirects.push_back(url.url);
@@ -854,13 +1010,17 @@ TEST_F(TopSitesTest, QueueingRequestsForTopSites) {
EXPECT_EQ(4u, number_of_callbacks());
- ASSERT_EQ(3u, urls().size());
+ ASSERT_EQ(5u, urls().size());
EXPECT_EQ("http://1.com/", urls()[0].url.spec());
EXPECT_EQ("http://2.com/", urls()[1].url.spec());
EXPECT_EQ("http://3.com/", urls()[2].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[3].url);
+ EXPECT_EQ(themes_url(), urls()[4].url);
+
}
TEST_F(TopSitesTest, CancelingRequestsForTopSites) {
+ ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
CancelableRequestConsumer c1;
CancelableRequestConsumer c2;
top_sites().GetMostVisitedURLs(
@@ -895,11 +1055,13 @@ TEST_F(TopSitesTest, CancelingRequestsForTopSites) {
pages.push_back(url);
top_sites().OnTopSitesAvailable(0, pages);
+ MessageLoop::current()->RunAllPending();
// 1 request was canceled.
EXPECT_EQ(2u, number_of_callbacks());
- ASSERT_EQ(2u, urls().size());
+ // 2 extra prepopulated URLs.
+ ASSERT_EQ(4u, urls().size());
EXPECT_EQ("http://1.com/", urls()[0].url.spec());
EXPECT_EQ("http://2.com/", urls()[1].url.spec());
}
@@ -947,4 +1109,232 @@ TEST_F(TopSitesTest, AddTemporaryThumbnail) {
thumbnail.getSize()));
}
+TEST_F(TopSitesTest, Blacklisting) {
+ ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
+ MostVisitedURLList pages;
+ MostVisitedURL url, url1;
+ url.url = GURL("http://bbc.com/");
+ url.redirects.push_back(url.url);
+ pages.push_back(url);
+ url1.url = GURL("http://google.com/");
+ url1.redirects.push_back(url1.url);
+ pages.push_back(url1);
+
+ CancelableRequestConsumer c;
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ top_sites().OnTopSitesAvailable(0, pages);
+ MessageLoop::current()->RunAllPending();
+ {
+ Lock& l = lock();
+ AutoLock lock(l); // IsBlacklisted must be in a lock.
+ EXPECT_FALSE(top_sites().IsBlacklisted(GURL("http://bbc.com/")));
+ }
+
+ EXPECT_EQ(1u, number_of_callbacks());
+
+ ASSERT_EQ(4u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ("http://google.com/", urls()[1].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
+ EXPECT_FALSE(top_sites().HasBlacklistedItems());
+
+ top_sites().AddBlacklistedURL(GURL("http://google.com/"));
+ EXPECT_TRUE(top_sites().HasBlacklistedItems());
+ {
+ Lock& l = lock();
+ AutoLock lock(l); // IsBlacklisted must be in a lock.
+ EXPECT_TRUE(top_sites().IsBlacklisted(GURL("http://google.com/")));
+ EXPECT_FALSE(top_sites().IsBlacklisted(GURL("http://bbc.com/")));
+ EXPECT_FALSE(top_sites().IsBlacklisted(welcome_url()));
+ }
+
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(2u, number_of_callbacks());
+ ASSERT_EQ(3u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[1].url);
+ EXPECT_EQ(themes_url(), urls()[2].url);
+
+ top_sites().AddBlacklistedURL(welcome_url());
+ EXPECT_TRUE(top_sites().HasBlacklistedItems());
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ ASSERT_EQ(2u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ(themes_url(), urls()[1].url);
+
+ top_sites().RemoveBlacklistedURL(GURL("http://google.com/"));
+ EXPECT_TRUE(top_sites().HasBlacklistedItems());
+ {
+ Lock& l = lock();
+ AutoLock lock(l); // IsBlacklisted must be in a lock.
+ EXPECT_FALSE(top_sites().IsBlacklisted(GURL("http://google.com/")));
+ }
+
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ ASSERT_EQ(3u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ("http://google.com/", urls()[1].url.spec());
+ EXPECT_EQ(themes_url(), urls()[2].url);
+
+ top_sites().ClearBlacklistedURLs();
+ EXPECT_FALSE(top_sites().HasBlacklistedItems());
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ ASSERT_EQ(4u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ("http://google.com/", urls()[1].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
+}
+
+TEST_F(TopSitesTest, PinnedURLs) {
+ ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
+ MostVisitedURLList pages;
+ MostVisitedURL url, url1;
+ url.url = GURL("http://bbc.com/");
+ url.redirects.push_back(url.url);
+ pages.push_back(url);
+ url1.url = GURL("http://google.com/");
+ url1.redirects.push_back(url1.url);
+ pages.push_back(url1);
+
+ CancelableRequestConsumer c;
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ top_sites().OnTopSitesAvailable(0, pages);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(top_sites().IsURLPinned(GURL("http://bbc.com/")));
+
+ ASSERT_EQ(4u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ("http://google.com/", urls()[1].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
+
+ top_sites().AddPinnedURL(GURL("http://google.com/"), 3);
+ EXPECT_FALSE(top_sites().IsURLPinned(GURL("http://bbc.com/")));
+ EXPECT_FALSE(top_sites().IsURLPinned(welcome_url()));
+
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ EXPECT_EQ(2u, number_of_callbacks());
+ ASSERT_EQ(4u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[1].url);
+ EXPECT_EQ(themes_url(), urls()[2].url);
+ EXPECT_EQ("http://google.com/", urls()[3].url.spec());
+
+ top_sites().RemovePinnedURL(GURL("http://google.com/"));
+ EXPECT_FALSE(top_sites().IsURLPinned(GURL("http://google.com/")));
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+
+ ASSERT_EQ(4u, urls().size());
+ EXPECT_EQ("http://bbc.com/", urls()[0].url.spec());
+ EXPECT_EQ("http://google.com/", urls()[1].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[2].url);
+ EXPECT_EQ(themes_url(), urls()[3].url);
+
+ top_sites().AddPinnedURL(GURL("http://bbc.com"), 1);
+ top_sites().AddPinnedURL(themes_url(), 0);
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+
+ ASSERT_EQ(4u, urls().size());
+ EXPECT_EQ(themes_url(), urls()[0].url);
+ EXPECT_EQ("http://bbc.com/", urls()[1].url.spec());
+ EXPECT_EQ("http://google.com/", urls()[2].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[3].url);
+
+ top_sites().RemovePinnedURL(GURL("http://bbc.com"));
+ top_sites().RemovePinnedURL(themes_url());
+
+ top_sites().AddPinnedURL(welcome_url(), 1);
+ top_sites().AddPinnedURL(GURL("http://bbc.com"), 3);
+
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+
+ ASSERT_EQ(4u, urls().size());
+ EXPECT_EQ("http://google.com/", urls()[0].url.spec());
+ EXPECT_EQ(welcome_url(), urls()[1].url);
+ EXPECT_EQ(themes_url(), urls()[2].url);
+ EXPECT_EQ("http://bbc.com/", urls()[3].url.spec());
+}
+
+TEST_F(TopSitesTest, BlacklistingAndPinnedURLs) {
+ ChromeThread db_loop(ChromeThread::DB, MessageLoop::current());
+ MostVisitedURLList pages;
+ CancelableRequestConsumer c;
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+ top_sites().OnTopSitesAvailable(0, pages);
+ MessageLoop::current()->RunAllPending();
+
+ ASSERT_EQ(2u, urls().size());
+ EXPECT_EQ(welcome_url(), urls()[0].url);
+ EXPECT_EQ(themes_url(), urls()[1].url);
+
+ top_sites().AddPinnedURL(themes_url(), 1);
+ top_sites().AddBlacklistedURL(welcome_url());
+
+ top_sites().GetMostVisitedURLs(
+ &c,
+ NewCallback(static_cast<TopSitesTest*>(this),
+ &TopSitesTest::OnTopSitesAvailable));
+
+ ASSERT_EQ(2u, urls().size());
+ EXPECT_EQ(GURL(), urls()[0].url);
+ EXPECT_EQ(themes_url(), urls()[1].url);
+
+}
+
+TEST_F(TopSitesTest, AddPrepopulatedPages) {
+ MostVisitedURLList pages;
+ top_sites().AddPrepopulatedPages(&pages);
+ ASSERT_EQ(2u, pages.size());
+ EXPECT_EQ(welcome_url(), pages[0].url);
+ EXPECT_EQ(themes_url(), pages[1].url);
+
+ pages.clear();
+
+ MostVisitedURL url = {themes_url()};
+ pages.push_back(url);
+
+ top_sites().AddPrepopulatedPages(&pages);
+
+ // Themes URL is already in pages; should not be added twice.
+ ASSERT_EQ(2u, pages.size());
+ EXPECT_EQ(themes_url(), pages[0].url);
+ EXPECT_EQ(welcome_url(), pages[1].url);
+}
+
} // namespace history
diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc
index 07f8881..b63d24a 100644
--- a/chrome/browser/history/url_database.cc
+++ b/chrome/browser/history/url_database.cc
@@ -10,7 +10,6 @@
#include <vector>
#include "app/l10n_util.h"
-#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/url_constants.h"
@@ -346,7 +345,7 @@ bool URLDatabase::DropKeywordSearchTermsTable() {
}
bool URLDatabase::SetKeywordSearchTermsForURL(URLID url_id,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& term) {
DCHECK(url_id && keyword_id && !term.empty());
@@ -374,7 +373,7 @@ bool URLDatabase::SetKeywordSearchTermsForURL(URLID url_id,
}
void URLDatabase::DeleteAllSearchTermsForKeyword(
- TemplateURL::IDType keyword_id) {
+ TemplateURLID keyword_id) {
DCHECK(keyword_id);
sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
"DELETE FROM keyword_search_terms WHERE keyword_id=?"));
@@ -386,7 +385,7 @@ void URLDatabase::DeleteAllSearchTermsForKeyword(
}
void URLDatabase::GetMostRecentKeywordSearchTerms(
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& prefix,
int max_count,
std::vector<KeywordSearchTermVisit>* matches) {
diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h
index 84c8dde..36bfebb 100644
--- a/chrome/browser/history/url_database.h
+++ b/chrome/browser/history/url_database.h
@@ -4,11 +4,12 @@
#ifndef CHROME_BROWSER_HISTORY_URL_DATABASE_H_
#define CHROME_BROWSER_HISTORY_URL_DATABASE_H_
+#pragma once
#include "app/sql/statement.h"
#include "base/basictypes.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_id.h"
class GURL;
@@ -159,17 +160,17 @@ class URLDatabase {
// Sets the search terms for the specified url/keyword pair.
bool SetKeywordSearchTermsForURL(URLID url_id,
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& term);
// Deletes all search terms for the specified keyword that have been added by
// way of SetKeywordSearchTermsForURL.
- void DeleteAllSearchTermsForKeyword(TemplateURL::IDType keyword_id);
+ void DeleteAllSearchTermsForKeyword(TemplateURLID keyword_id);
// Returns up to max_count of the most recent search terms for the specified
// keyword.
void GetMostRecentKeywordSearchTerms(
- TemplateURL::IDType keyword_id,
+ TemplateURLID keyword_id,
const string16& prefix,
int max_count,
std::vector<KeywordSearchTermVisit>* matches);
diff --git a/chrome/browser/history/url_database_unittest.cc b/chrome/browser/history/url_database_unittest.cc
index 32ded0c..f567844 100644
--- a/chrome/browser/history/url_database_unittest.cc
+++ b/chrome/browser/history/url_database_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.
@@ -67,9 +67,9 @@ class URLDatabaseTest : public testing::Test,
sql::Connection db_;
};
-// Test add and query for the URL table in the HistoryDatabase
+// Test add and query for the URL table in the HistoryDatabase.
TEST_F(URLDatabaseTest, AddURL) {
- // first, add two URLs
+ // First, add two URLs.
const GURL url1("http://www.google.com/");
URLRow url_info1(url1);
url_info1.set_title(UTF8ToUTF16("Google"));
@@ -88,7 +88,7 @@ TEST_F(URLDatabaseTest, AddURL) {
url_info2.set_hidden(true);
EXPECT_TRUE(AddURL(url_info2));
- // query both of them
+ // Query both of them.
URLRow info;
EXPECT_TRUE(GetRowForURL(url1, &info));
EXPECT_TRUE(IsURLRowEqual(url_info1, info));
@@ -96,7 +96,7 @@ TEST_F(URLDatabaseTest, AddURL) {
EXPECT_TRUE(id2);
EXPECT_TRUE(IsURLRowEqual(url_info2, info));
- // update the second
+ // Update the second.
url_info2.set_title(UTF8ToUTF16("Google Mail Too"));
url_info2.set_visit_count(4);
url_info2.set_typed_count(1);
@@ -104,19 +104,19 @@ TEST_F(URLDatabaseTest, AddURL) {
url_info2.set_hidden(false);
EXPECT_TRUE(UpdateURLRow(id2, url_info2));
- // make sure it got updated
+ // Make sure it got updated.
URLRow info2;
EXPECT_TRUE(GetRowForURL(url2, &info2));
EXPECT_TRUE(IsURLRowEqual(url_info2, info2));
- // query a nonexistant URL
+ // Query a nonexistent URL.
EXPECT_EQ(0, GetRowForURL(GURL("http://news.google.com/"), &info));
- // Delete all urls in the domain
+ // Delete all urls in the domain.
// TODO(acw): test the new url based delete domain
// EXPECT_TRUE(db.DeleteDomain(kDomainID));
- // Make sure the urls have been properly removed
+ // Make sure the urls have been properly removed.
// TODO(acw): commented out because remove no longer works.
// EXPECT_TRUE(db.GetURLInfo(url1, NULL) == NULL);
// EXPECT_TRUE(db.GetURLInfo(url2, NULL) == NULL);
diff --git a/chrome/browser/history/visit_database.cc b/chrome/browser/history/visit_database.cc
index 80fa8c8..d0156c2 100644
--- a/chrome/browser/history/visit_database.cc
+++ b/chrome/browser/history/visit_database.cc
@@ -9,9 +9,9 @@
#include <map>
#include <set>
-#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/history/url_database.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/url_constants.h"
@@ -51,6 +51,17 @@ bool VisitDatabase::InitVisitTable() {
return false;
}
+ // Visit source table contains the source information for all the visits. To
+ // save space, we do not record those user browsed visits which would be the
+ // majority in this table. Only other sources are recorded.
+ // Due to the tight relationship between visit_source and visits table, they
+ // should be created and dropped at the same time.
+ if (!GetDB().DoesTableExist("visit_source")) {
+ if (!GetDB().Execute("CREATE TABLE visit_source("
+ "id INTEGER PRIMARY KEY,source INTEGER NOT NULL)"))
+ return false;
+ }
+
// Index over url so we can quickly find visits for a page. This will just
// fail if it already exists and we'll ignore it.
GetDB().Execute("CREATE INDEX visits_url_index ON visits (url)");
@@ -68,6 +79,7 @@ bool VisitDatabase::InitVisitTable() {
}
bool VisitDatabase::DropVisitTable() {
+ GetDB().Execute("DROP TABLE visit_source");
// This will also drop the indices over the table.
return GetDB().Execute("DROP TABLE visits");
}
@@ -94,7 +106,7 @@ void VisitDatabase::FillVisitVector(sql::Statement& statement,
}
}
-VisitID VisitDatabase::AddVisit(VisitRow* visit) {
+VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) {
sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
"INSERT INTO visits "
"(url, visit_time, from_visit, transition, segment_id, is_indexed) "
@@ -112,6 +124,20 @@ VisitID VisitDatabase::AddVisit(VisitRow* visit) {
return 0;
visit->visit_id = GetDB().GetLastInsertRowId();
+
+ if (source != SOURCE_BROWSED) {
+ // Record the source of this visit when it is not browsed.
+ sql::Statement statement1(GetDB().GetCachedStatement(SQL_FROM_HERE,
+ "INSERT INTO visit_source (id, source) VALUES (?,?)"));
+ if (!statement1.is_valid())
+ return 0;
+
+ statement1.BindInt64(0, visit->visit_id);
+ statement1.BindInt64(1, source);
+ if (!statement1.Run())
+ return 0;
+ }
+
return visit->visit_id;
}
@@ -133,6 +159,16 @@ void VisitDatabase::DeleteVisit(const VisitRow& visit) {
return;
del.BindInt64(0, visit.visit_id);
del.Run();
+
+ // Try to delete the entry in visit_source table as well.
+ // If the visit was browsed, there is no corresponding entry in visit_source
+ // table, and nothing will be deleted.
+ del.Assign(GetDB().GetCachedStatement(SQL_FROM_HERE,
+ "DELETE FROM visit_source WHERE id=?"));
+ if (!del.is_valid())
+ return;
+ del.BindInt64(0, visit.visit_id);
+ del.Run();
}
bool VisitDatabase::GetRowForVisit(VisitID visit_id, VisitRow* out_visit) {
@@ -437,4 +473,42 @@ bool VisitDatabase::GetStartDate(base::Time* first_visit) {
return true;
}
+void VisitDatabase::GetVisitsSource(const VisitVector& visits,
+ VisitSourceMap* sources) {
+ DCHECK(sources);
+ sources->clear();
+
+ // We query the source in batch. Here defines the batch size.
+ const size_t batch_size = 500;
+ size_t visits_size = visits.size();
+
+ size_t start_index = 0, end_index = 0;
+ while (end_index < visits_size) {
+ start_index = end_index;
+ end_index = end_index + batch_size < visits_size ? end_index + batch_size
+ : visits_size;
+
+ // Compose the sql statement with a list of ids.
+ std::string sql = "SELECT id,source FROM visit_source ";
+ sql.append("WHERE id IN (");
+ // Append all the ids in the statement.
+ for (size_t j = start_index; j < end_index; j++) {
+ if (j != start_index)
+ sql.push_back(',');
+ sql.append(base::Int64ToString(visits[j].visit_id));
+ }
+ sql.append(") ORDER BY id");
+ sql::Statement statement(GetDB().GetUniqueStatement(sql.c_str()));
+ if (!statement)
+ return;
+
+ // Get the source entries out of the query result.
+ while (statement.Step()) {
+ std::pair<VisitID, VisitSource> source_entry(statement.ColumnInt64(0),
+ static_cast<VisitSource>(statement.ColumnInt(1)));
+ sources->insert(source_entry);
+ }
+ }
+}
+
} // namespace history
diff --git a/chrome/browser/history/visit_database.h b/chrome/browser/history/visit_database.h
index a6dbf3c..0e97cac 100644
--- a/chrome/browser/history/visit_database.h
+++ b/chrome/browser/history/visit_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_VISIT_DATABASE_H_
#define CHROME_BROWSER_HISTORY_VISIT_DATABASE_H_
+#pragma once
#include "chrome/browser/history/history_types.h"
@@ -33,8 +34,9 @@ class VisitDatabase {
// Adds a line to the visit database with the given information, returning
// the added row ID on success, 0 on failure. The given visit is updated with
- // the new row ID on success.
- VisitID AddVisit(VisitRow* visit);
+ // the new row ID on success. In addition, adds its source into visit_source
+ // table.
+ VisitID AddVisit(VisitRow* visit, VisitSource source);
// Deletes the given visit from the database. If a visit with the given ID
// doesn't exist, it will not do anything.
@@ -143,6 +145,10 @@ class VisitDatabase {
// Get the time of the first item in our database.
bool GetStartDate(base::Time* first_visit);
+ // Get the source information about the given visits.
+ void GetVisitsSource(const VisitVector& visits,
+ VisitSourceMap* sources);
+
protected:
// Returns the database for the functions in this interface.
virtual sql::Connection& GetDB() = 0;
diff --git a/chrome/browser/history/visit_database_unittest.cc b/chrome/browser/history/visit_database_unittest.cc
index ebc2e1b..28a0e15 100644
--- a/chrome/browser/history/visit_database_unittest.cc
+++ b/chrome/browser/history/visit_database_unittest.cc
@@ -73,19 +73,19 @@ class VisitDatabaseTest : public PlatformTest,
TEST_F(VisitDatabaseTest, Add) {
// Add one visit.
VisitRow visit_info1(1, Time::Now(), 0, PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info1));
+ EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
// Add second visit for the same page.
VisitRow visit_info2(visit_info1.url_id,
visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
PageTransition::TYPED, 0);
- EXPECT_TRUE(AddVisit(&visit_info2));
+ EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
// Add third visit for a different page.
VisitRow visit_info3(2,
visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info3));
+ EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// Query the first two.
std::vector<VisitRow> matches;
@@ -104,17 +104,17 @@ TEST_F(VisitDatabaseTest, Delete) {
static const int kTime1 = 1000;
VisitRow visit_info1(1, Time::FromInternalValue(kTime1), 0,
PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info1));
+ EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
static const int kTime2 = kTime1 + 1;
VisitRow visit_info2(1, Time::FromInternalValue(kTime2),
visit_info1.visit_id, PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info2));
+ EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
static const int kTime3 = kTime2 + 1;
VisitRow visit_info3(1, Time::FromInternalValue(kTime3),
visit_info2.visit_id, PageTransition::LINK, 0);
- EXPECT_TRUE(AddVisit(&visit_info3));
+ EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// First make sure all the visits are there.
std::vector<VisitRow> matches;
@@ -140,7 +140,7 @@ TEST_F(VisitDatabaseTest, Delete) {
TEST_F(VisitDatabaseTest, Update) {
// Make something in the database.
VisitRow original(1, Time::Now(), 23, 22, 19);
- AddVisit(&original);
+ AddVisit(&original, SOURCE_BROWSED);
// Mutate that row.
VisitRow modification(original);
@@ -167,7 +167,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info1.visit_id = 1;
- EXPECT_TRUE(AddVisit(&visit_info1));
+ EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
// Add second visit for the same page.
VisitRow visit_info2(visit_info1.url_id,
@@ -177,7 +177,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info2.visit_id = 2;
- EXPECT_TRUE(AddVisit(&visit_info2));
+ EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
// Add third visit for a different page.
VisitRow visit_info3(2,
@@ -186,7 +186,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_START),
0);
visit_info3.visit_id = 3;
- EXPECT_TRUE(AddVisit(&visit_info3));
+ EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// Add a redirect visit from the last page.
VisitRow visit_info4(3,
@@ -195,7 +195,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info4.visit_id = 4;
- EXPECT_TRUE(AddVisit(&visit_info4));
+ EXPECT_TRUE(AddVisit(&visit_info4, SOURCE_BROWSED));
// Add a subframe visit.
VisitRow visit_info5(4,
@@ -205,7 +205,7 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
PageTransition::CHAIN_END),
0);
visit_info5.visit_id = 5;
- EXPECT_TRUE(AddVisit(&visit_info5));
+ EXPECT_TRUE(AddVisit(&visit_info5, SOURCE_BROWSED));
// Query the visits for all time, we should not get the first (duplicate of
// the second) or the redirect or subframe visits.
@@ -227,4 +227,37 @@ TEST_F(VisitDatabaseTest, GetVisibleVisitsInRange) {
ASSERT_EQ(static_cast<size_t>(1), results.size());
EXPECT_TRUE(IsVisitInfoEqual(results[0], visit_info4));
}
+
+TEST_F(VisitDatabaseTest, VisitSource) {
+ // Add visits.
+ VisitRow visit_info1(111, Time::Now(), 0, PageTransition::LINK, 0);
+ ASSERT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
+
+ VisitRow visit_info2(112, Time::Now(), 1, PageTransition::TYPED, 0);
+ ASSERT_TRUE(AddVisit(&visit_info2, SOURCE_SYNCED));
+
+ VisitRow visit_info3(113, Time::Now(), 0, PageTransition::TYPED, 0);
+ ASSERT_TRUE(AddVisit(&visit_info3, SOURCE_EXTENSION));
+
+ // Query each visit.
+ std::vector<VisitRow> matches;
+ ASSERT_TRUE(GetVisitsForURL(111, &matches));
+ ASSERT_EQ(1U, matches.size());
+ VisitSourceMap sources;
+ GetVisitsSource(matches, &sources);
+ EXPECT_EQ(0U, sources.size());
+
+ ASSERT_TRUE(GetVisitsForURL(112, &matches));
+ ASSERT_EQ(1U, matches.size());
+ GetVisitsSource(matches, &sources);
+ ASSERT_EQ(1U, sources.size());
+ EXPECT_EQ(SOURCE_SYNCED, sources[matches[0].visit_id]);
+
+ ASSERT_TRUE(GetVisitsForURL(113, &matches));
+ ASSERT_EQ(1U, matches.size());
+ GetVisitsSource(matches, &sources);
+ ASSERT_EQ(1U, sources.size());
+ EXPECT_EQ(SOURCE_EXTENSION, sources[matches[0].visit_id]);
+}
+
} // namespace history
diff --git a/chrome/browser/history/visit_tracker.h b/chrome/browser/history/visit_tracker.h
index 43de7a0..281c136 100644
--- a/chrome/browser/history/visit_tracker.h
+++ b/chrome/browser/history/visit_tracker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_VISIT_TRACKER_H__
#define CHROME_BROWSER_HISTORY_VISIT_TRACKER_H__
+#pragma once
#include <map>
#include <vector>
diff --git a/chrome/browser/history/visitsegment_database.cc b/chrome/browser/history/visitsegment_database.cc
index f94d713..f4c4f9f 100644
--- a/chrome/browser/history/visitsegment_database.cc
+++ b/chrome/browser/history/visitsegment_database.cc
@@ -10,7 +10,6 @@
#include <string>
#include <vector>
-#include "app/sql/connection.h"
#include "app/sql/statement.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
diff --git a/chrome/browser/history/visitsegment_database.h b/chrome/browser/history/visitsegment_database.h
index 16f0417..7c25ef7 100644
--- a/chrome/browser/history/visitsegment_database.h
+++ b/chrome/browser/history/visitsegment_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HISTORY_VISITSEGMENT_DATABASE_H_
#define CHROME_BROWSER_HISTORY_VISITSEGMENT_DATABASE_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/history/history_types.h"
diff --git a/chrome/browser/host_content_settings_map.cc b/chrome/browser/host_content_settings_map.cc
index 8742238..4ac9f40 100644
--- a/chrome/browser/host_content_settings_map.cc
+++ b/chrome/browser/host_content_settings_map.cc
@@ -4,15 +4,18 @@
#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/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/scoped_pref_update.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"
@@ -30,6 +33,8 @@ namespace {
// - 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.
@@ -38,6 +43,62 @@ const char kDomainWildcard[] = "[*.]";
// The length of kDomainWildcard (without the trailing '\0')
const size_t kDomainWildcardLength = arraysize(kDomainWildcard) - 1;
+// 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 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::kChromeInternalScheme) ||
+ url.SchemeIs(chrome::kChromeUIScheme) ||
+ url.SchemeIs(chrome::kExtensionScheme) ||
+ url.SchemeIs(chrome::kGearsScheme) ||
+ url.SchemeIs(chrome::kUserScriptScheme);
+}
} // namespace
// static
@@ -84,30 +145,6 @@ bool HostContentSettingsMap::Pattern::Matches(const GURL& url) const {
(match + pattern_.length() - kDomainWildcardLength == host.length());
}
-// static
-const wchar_t*
- HostContentSettingsMap::kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = {
- L"cookies",
- L"images",
- L"javascript",
- L"plugins",
- L"popups",
- NULL, // Not used for Geolocation
- NULL, // Not used for Notifications
-};
-
-// static
-const ContentSetting
- HostContentSettingsMap::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
-};
-
HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
: profile_(profile),
block_third_party_cookies_(false),
@@ -138,7 +175,7 @@ HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
i != whitelist_pref->end(); ++i) {
std::string host;
(*i)->GetAsString(&host);
- SetContentSetting(Pattern(host), CONTENT_SETTINGS_TYPE_POPUPS,
+ SetContentSetting(Pattern(host), CONTENT_SETTINGS_TYPE_POPUPS, "",
CONTENT_SETTING_ALLOW);
}
prefs->ClearPref(prefs::kPopupWhitelistedHosts);
@@ -150,18 +187,19 @@ HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
prefs->GetDictionary(prefs::kPerHostContentSettings);
for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
i != all_settings_dictionary->end_keys(); ++i) {
- std::wstring wide_host(*i);
- Pattern pattern(std::string(kDomainWildcard) + WideToUTF8(wide_host));
+ const std::string& host(*i);
+ Pattern pattern(std::string(kDomainWildcard) + host);
DictionaryValue* host_settings_dictionary = NULL;
bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- wide_host, &host_settings_dictionary);
+ 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)
+ if (settings.settings[j] != CONTENT_SETTING_DEFAULT &&
+ !RequiresResourceIdentifier(ContentSettingsType(j)))
SetContentSetting(
- pattern, ContentSettingsType(j), settings.settings[j]);
+ pattern, ContentSettingsType(j), "", settings.settings[j]);
}
}
prefs->ClearPref(prefs::kPerHostContentSettings);
@@ -175,6 +213,8 @@ HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
// Read misc. global settings.
block_third_party_cookies_ =
prefs->GetBoolean(prefs::kBlockThirdPartyCookies);
+ block_nonsandboxed_plugins_ =
+ prefs->GetBoolean(prefs::kBlockNonsandboxedPlugins);
// Verify preferences version.
if (!prefs->HasPrefPath(prefs::kContentSettingsVersion)) {
@@ -190,9 +230,11 @@ HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
// Read exceptions.
ReadExceptions(false);
- prefs->AddPrefObserver(prefs::kDefaultContentSettings, this);
- prefs->AddPrefObserver(prefs::kContentSettingsPatterns, this);
- prefs->AddPrefObserver(prefs::kBlockThirdPartyCookies, this);
+ 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);
notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
Source<Profile>(profile_));
}
@@ -204,6 +246,7 @@ void HostContentSettingsMap::RegisterUserPrefs(PrefService* prefs) {
kContentSettingsPatternVersion);
prefs->RegisterDictionaryPref(prefs::kContentSettingsPatterns);
prefs->RegisterBooleanPref(prefs::kBlockThirdPartyCookies, false);
+ prefs->RegisterBooleanPref(prefs::kBlockNonsandboxedPlugins, false);
prefs->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex, 0);
// Obsolete prefs, for migration:
@@ -221,12 +264,101 @@ ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
ContentSetting HostContentSettingsMap::GetContentSetting(
const GURL& url,
- ContentSettingsType content_type) const {
- return GetContentSettings(url).settings[content_type];
+ ContentSettingsType content_type,
+ const std::string& resource_identifier) const {
+ ContentSetting setting = GetNonDefaultContentSetting(url,
+ content_type,
+ resource_identifier);
+ if (setting == CONTENT_SETTING_DEFAULT)
+ 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());
+ }
+
+ 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_);
+
+ // Make the remaining defaults explicit.
+ for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j)
+ if (output.settings[j] == CONTENT_SETTING_DEFAULT ||
+ RequiresResourceIdentifier(ContentSettingsType(j)))
+ output.settings[j] = default_content_settings_.settings[j];
+
+ return output;
+}
+
+ContentSettings HostContentSettingsMap::GetNonDefaultContentSettings(
+ const GURL& url) const {
if (ShouldAllowAllContent(url))
return ContentSettings(CONTENT_SETTING_ALLOW);
@@ -240,7 +372,7 @@ ContentSettings HostContentSettingsMap::GetContentSettings(
// Check for exact matches first.
HostContentSettings::const_iterator i(host_content_settings_.find(host));
if (i != host_content_settings_.end())
- output = i->second;
+ 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
@@ -248,8 +380,8 @@ ContentSettings HostContentSettingsMap::GetContentSettings(
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.settings[j] != CONTENT_SETTING_DEFAULT)
- output.settings[j] = i->second.settings[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.
@@ -258,14 +390,14 @@ ContentSettings HostContentSettingsMap::GetContentSettings(
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.settings[j];
+ 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.settings[j];
+ output.settings[j] = i->second.content_settings.settings[j];
}
}
const size_t next_dot = key.find('.', kDomainWildcardLength);
@@ -274,27 +406,37 @@ ContentSettings HostContentSettingsMap::GetContentSettings(
key.erase(kDomainWildcardLength, next_dot - kDomainWildcardLength + 1);
}
- // Make the remaining defaults explicit.
- for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j)
- if (output.settings[j] == CONTENT_SETTING_DEFAULT)
- output.settings[j] = default_content_settings_.settings[j];
-
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 = i->second.settings[content_type];
+ 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.
@@ -319,7 +461,7 @@ void HostContentSettingsMap::SetDefaultContentSetting(
DictionaryValue* default_settings_dictionary =
prefs->GetMutableDictionary(prefs::kDefaultContentSettings);
- std::wstring dictionary_path(kTypeNames[content_type]);
+ std::string dictionary_path(kTypeNames[content_type]);
updating_preferences_ = true;
{
AutoLock auto_lock(lock_);
@@ -338,17 +480,21 @@ void HostContentSettingsMap::SetDefaultContentSetting(
}
updating_preferences_ = false;
- NotifyObservers(ContentSettingsDetails(true));
+ NotifyObservers(ContentSettingsDetails(Pattern(), content_type, ""));
}
-void HostContentSettingsMap::SetContentSetting(const Pattern& pattern,
- ContentSettingsType content_type,
- ContentSetting setting) {
+void HostContentSettingsMap::SetContentSetting(
+ const Pattern& pattern,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier,
+ ContentSetting setting) {
DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK_NE(RequiresResourceIdentifier(content_type),
+ resource_identifier.empty());
bool early_exit = false;
- std::wstring wide_pattern(UTF8ToWide(pattern.AsString()));
+ std::string pattern_str(pattern.AsString());
PrefService* prefs = NULL;
DictionaryValue* all_settings_dictionary = NULL;
HostContentSettings* map_to_modify = &off_the_record_settings_;
@@ -361,16 +507,29 @@ void HostContentSettingsMap::SetContentSetting(const Pattern& pattern,
{
AutoLock auto_lock(lock_);
- if (!map_to_modify->count(pattern.AsString()))
- (*map_to_modify)[pattern.AsString()] = ContentSettings();
+ if (!map_to_modify->count(pattern_str))
+ (*map_to_modify)[pattern_str].content_settings = ContentSettings();
HostContentSettings::iterator
- i(map_to_modify->find(pattern.AsString()));
- ContentSettings& settings = i->second;
- settings.settings[content_type] = setting;
- if (AllDefault(settings)) {
+ 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(wide_pattern, NULL);
+ all_settings_dictionary->RemoveWithoutPathExpansion(pattern_str, NULL);
// We can't just return because |NotifyObservers()| needs to be called,
// without |lock_| being held.
@@ -379,22 +538,40 @@ void HostContentSettingsMap::SetContentSetting(const Pattern& pattern,
}
if (!early_exit && all_settings_dictionary) {
- DictionaryValue* host_settings_dictionary;
+ DictionaryValue* host_settings_dictionary = NULL;
bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- wide_pattern, &host_settings_dictionary);
+ pattern_str, &host_settings_dictionary);
if (!found) {
host_settings_dictionary = new DictionaryValue;
all_settings_dictionary->SetWithoutPathExpansion(
- wide_pattern, host_settings_dictionary);
+ pattern_str, host_settings_dictionary);
DCHECK_NE(setting, CONTENT_SETTING_DEFAULT);
}
- std::wstring dictionary_path(kTypeNames[content_type]);
- if (setting == CONTENT_SETTING_DEFAULT) {
- host_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path,
- NULL);
+ 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 {
- host_settings_dictionary->SetWithoutPathExpansion(
- dictionary_path, Value::CreateIntegerValue(setting));
+ 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));
+ }
}
}
@@ -403,19 +580,24 @@ void HostContentSettingsMap::SetContentSetting(const Pattern& pattern,
ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
updating_preferences_ = false;
- NotifyObservers(ContentSettingsDetails(pattern));
+ 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, setting);
+ SetContentSetting(Pattern::FromURL(url),
+ content_type,
+ resource_identifier,
+ setting);
}
void HostContentSettingsMap::ClearSettingsForOneType(
@@ -437,19 +619,24 @@ void HostContentSettingsMap::ClearSettingsForOneType(
AutoLock auto_lock(lock_);
for (HostContentSettings::iterator i(map_to_modify->begin());
i != map_to_modify->end(); ) {
- if (i->second.settings[content_type] != CONTENT_SETTING_DEFAULT) {
- i->second.settings[content_type] = CONTENT_SETTING_DEFAULT;
- std::wstring wide_host(UTF8ToWide(i->first));
+ 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(wide_host, NULL);
+ RemoveWithoutPathExpansion(host, NULL);
map_to_modify->erase(i++);
} else if (all_settings_dictionary) {
DictionaryValue* host_settings_dictionary;
bool found =
all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- wide_host, &host_settings_dictionary);
+ host, &host_settings_dictionary);
DCHECK(found);
host_settings_dictionary->RemoveWithoutPathExpansion(
kTypeNames[content_type], NULL);
@@ -466,7 +653,17 @@ void HostContentSettingsMap::ClearSettingsForOneType(
ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
updating_preferences_ = false;
- NotifyObservers(ContentSettingsDetails(true));
+ 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) {
@@ -491,6 +688,34 @@ void HostContentSettingsMap::SetBlockThirdPartyCookies(bool block) {
prefs->ClearPref(prefs::kBlockThirdPartyCookies);
}
+void HostContentSettingsMap::SetBlockNonsandboxedPlugins(bool block) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::UI));
@@ -501,6 +726,7 @@ void HostContentSettingsMap::ResetToDefaults() {
host_content_settings_.clear();
off_the_record_settings_.clear();
block_third_party_cookies_ = false;
+ block_nonsandboxed_plugins_ = false;
}
if (!is_off_the_record_) {
@@ -509,15 +735,13 @@ void HostContentSettingsMap::ResetToDefaults() {
prefs->ClearPref(prefs::kDefaultContentSettings);
prefs->ClearPref(prefs::kContentSettingsPatterns);
prefs->ClearPref(prefs::kBlockThirdPartyCookies);
+ prefs->ClearPref(prefs::kBlockNonsandboxedPlugins);
updating_preferences_ = false;
- NotifyObservers(ContentSettingsDetails(true));
+ NotifyObservers(
+ ContentSettingsDetails(Pattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
}
}
-bool HostContentSettingsMap::IsOffTheRecord() {
- return profile_->IsOffTheRecord();
-}
-
void HostContentSettingsMap::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -527,7 +751,7 @@ void HostContentSettingsMap::Observe(NotificationType type,
if (updating_preferences_)
return;
- std::wstring* name = Details<std::wstring>(details).ptr();
+ std::string* name = Details<std::string>(details).ptr();
if (prefs::kDefaultContentSettings == *name) {
ReadDefaultSettings(true);
} else if (prefs::kContentSettingsPatterns == *name) {
@@ -536,13 +760,19 @@ void HostContentSettingsMap::Observe(NotificationType type,
AutoLock auto_lock(lock_);
block_third_party_cookies_ = profile_->GetPrefs()->GetBoolean(
prefs::kBlockThirdPartyCookies);
+ } else if (prefs::kBlockNonsandboxedPlugins == *name) {
+ 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(true));
+ if (!is_off_the_record_) {
+ NotifyObservers(
+ ContentSettingsDetails(Pattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
+ }
} else if (NotificationType::PROFILE_DESTROYED == type) {
UnregisterObservers();
} else {
@@ -554,38 +784,60 @@ HostContentSettingsMap::~HostContentSettingsMap() {
UnregisterObservers();
}
-// static
-bool HostContentSettingsMap::ShouldAllowAllContent(const GURL& url) {
- return url.SchemeIs(chrome::kChromeInternalScheme) ||
- url.SchemeIs(chrome::kChromeUIScheme) ||
- url.SchemeIs(chrome::kExtensionScheme) ||
- url.SchemeIs(chrome::kGearsScheme) ||
- url.SchemeIs(chrome::kUserScriptScheme);
-}
-
void HostContentSettingsMap::GetSettingsFromDictionary(
const DictionaryValue* dictionary,
ContentSettings* settings) {
for (DictionaryValue::key_iterator i(dictionary->begin_keys());
i != dictionary->end_keys(); ++i) {
- std::wstring content_type(*i);
- int setting = CONTENT_SETTING_DEFAULT;
- bool found = dictionary->GetIntegerWithoutPathExpansion(content_type,
- &setting);
- DCHECK(found);
+ const std::string& content_type(*i);
for (size_t type = 0; type < arraysize(kTypeNames); ++type) {
- if ((kTypeNames[type] != NULL) &&
- (std::wstring(kTypeNames[type]) == content_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)
+ if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] ==
+ CONTENT_SETTING_ASK)
settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK;
}
+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)] =
+ ContentSetting(setting);
+ }
+
+ break;
+ }
+ }
+ }
+}
+
void HostContentSettingsMap::ForceDefaultsToBeExplicit() {
DCHECK_EQ(arraysize(kDefaultSettings),
static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
@@ -596,12 +848,13 @@ void HostContentSettingsMap::ForceDefaultsToBeExplicit() {
}
}
-bool HostContentSettingsMap::AllDefault(const ContentSettings& settings) const {
- for (size_t i = 0; i < arraysize(settings.settings); ++i) {
- if (settings.settings[i] != CONTENT_SETTING_DEFAULT)
+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 true;
+ return settings.content_settings_for_resources.empty();
}
void HostContentSettingsMap::ReadDefaultSettings(bool overwrite) {
@@ -628,16 +881,19 @@ void HostContentSettingsMap::ReadExceptions(bool overwrite) {
if (all_settings_dictionary != NULL) {
for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
i != all_settings_dictionary->end_keys(); ++i) {
- std::wstring wide_pattern(*i);
- if (!Pattern(WideToUTF8(wide_pattern)).IsValid())
+ 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(
- wide_pattern, &pattern_settings_dictionary);
+ pattern, &pattern_settings_dictionary);
DCHECK(found);
ContentSettings settings;
GetSettingsFromDictionary(pattern_settings_dictionary, &settings);
- host_content_settings_[WideToUTF8(wide_pattern)] = settings;
+ host_content_settings_[pattern].content_settings = settings;
+ GetResourceSettingsFromDictionary(
+ pattern_settings_dictionary,
+ &host_content_settings_[pattern].content_settings_for_resources);
}
}
}
@@ -654,10 +910,7 @@ void HostContentSettingsMap::UnregisterObservers() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
if (!profile_)
return;
- PrefService* prefs = profile_->GetPrefs();
- prefs->RemovePrefObserver(prefs::kDefaultContentSettings, this);
- prefs->RemovePrefObserver(prefs::kContentSettingsPatterns, this);
- prefs->RemovePrefObserver(prefs::kBlockThirdPartyCookies, this);
+ pref_change_registrar_.RemoveAll();
notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
Source<Profile>(profile_));
profile_ = NULL;
diff --git a/chrome/browser/host_content_settings_map.h b/chrome/browser/host_content_settings_map.h
index fc38afc..7afb808 100644
--- a/chrome/browser/host_content_settings_map.h
+++ b/chrome/browser/host_content_settings_map.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_HOST_CONTENT_SETTINGS_MAP_H_
#define CHROME_BROWSER_HOST_CONTENT_SETTINGS_MAP_H_
+#pragma once
#include <map>
#include <string>
@@ -17,6 +18,7 @@
#include "base/lock.h"
#include "base/ref_counted.h"
#include "chrome/browser/chrome_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"
@@ -72,21 +74,38 @@ class HostContentSettingsMap
// for each pattern.
class ContentSettingsDetails {
public:
- explicit ContentSettingsDetails(const Pattern& pattern)
- : pattern_(pattern), update_all_(false) {}
-
- explicit ContentSettingsDetails(bool update_all)
- : pattern_(), update_all_(update_all) {}
+ // 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 many settings changed at once.
- bool update_all() const { return update_all_; }
+ // 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_;
- bool update_all_;
+ ContentSettingsType type_;
+ std::string resource_identifier_;
};
@@ -105,25 +124,52 @@ class HostContentSettingsMap
ContentSettingsType content_type) const;
// Returns a single ContentSetting which applies to a given URL. Note that
- // certain internal schemes are whitelisted.
+ // 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;
-
- // Returns all ContentSettings which apply to a given URL.
+ 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.
+ // 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
@@ -134,19 +180,26 @@ class HostContentSettingsMap
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.
+ // 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.
+ // 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.
@@ -154,6 +207,10 @@ class HostContentSettingsMap
// 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_; }
@@ -163,14 +220,17 @@ class HostContentSettingsMap
// 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();
- // Whether this settings map is associated with an OTR session.
- bool IsOffTheRecord();
-
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
@@ -179,29 +239,32 @@ class HostContentSettingsMap
private:
friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
- typedef std::map<std::string, ContentSettings> HostContentSettings;
-
- // The names of the ContentSettingsType values, for use with dictionary prefs.
- static const wchar_t* kTypeNames[CONTENT_SETTINGS_NUM_TYPES];
+ typedef std::pair<ContentSettingsType, std::string>
+ ContentSettingsTypeResourceIdentifierPair;
+ typedef std::map<ContentSettingsTypeResourceIdentifierPair, ContentSetting>
+ ResourceContentSettings;
- // The default setting for each content type.
- static const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES];
+ struct ExtendedContentSettings {
+ ContentSettings content_settings;
+ ResourceContentSettings content_settings_for_resources;
+ };
- // 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);
+ 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 ContentSettings& settings) const;
+ 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.
@@ -223,6 +286,7 @@ class HostContentSettingsMap
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_;
@@ -234,6 +298,7 @@ class HostContentSettingsMap
// Misc global settings.
bool block_third_party_cookies_;
+ bool block_nonsandboxed_plugins_;
// Used around accesses to the settings objects to guarantee thread safety.
mutable Lock lock_;
diff --git a/chrome/browser/host_content_settings_map_unittest.cc b/chrome/browser/host_content_settings_map_unittest.cc
index 108d26e..4d79ffc 100644
--- a/chrome/browser/host_content_settings_map_unittest.cc
+++ b/chrome/browser/host_content_settings_map_unittest.cc
@@ -4,7 +4,11 @@
#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/pref_service.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"
@@ -42,6 +46,7 @@ class StubSettingsObserver : public NotificationObserver {
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();
// This checks that calling a Get function from an observer doesn't
// deadlock.
last_notifier->GetContentSettings(GURL("http://random-hostname.com/"));
@@ -50,6 +55,7 @@ class StubSettingsObserver : public NotificationObserver {
HostContentSettingsMap* last_notifier;
HostContentSettingsMap::Pattern last_pattern;
bool last_update_all;
+ bool last_update_all_types;
int counter;
private:
@@ -81,7 +87,7 @@ TEST_F(HostContentSettingsMapTest, DefaultValues) {
CONTENT_SETTINGS_TYPE_IMAGES));
EXPECT_EQ(CONTENT_SETTING_ALLOW, host_content_settings_map->GetContentSetting(
GURL(chrome::kChromeUINewTabURL),
- CONTENT_SETTINGS_TYPE_IMAGES));
+ CONTENT_SETTINGS_TYPE_IMAGES, ""));
host_content_settings_map->SetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_ASK);
EXPECT_EQ(CONTENT_SETTING_ASK,
@@ -102,35 +108,35 @@ TEST_F(HostContentSettingsMapTest, DefaultValues) {
HostContentSettingsMap::Pattern pattern("[*.]example.com");
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_DEFAULT);
+ 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_TYPE_IMAGES, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_PLUGINS));
+ 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);
+ 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);
+ 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);
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_ALLOW);
desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
CONTENT_SETTING_ALLOW;
desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS] =
@@ -146,41 +152,44 @@ TEST_F(HostContentSettingsMapTest, DefaultValues) {
// 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);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK);
+ 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);
+ 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);
+ 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);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
host_content_settings_map->SetContentSetting(pattern3,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ 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);
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", &host_settings);
EXPECT_EQ(1U, host_settings.size());
}
@@ -196,23 +205,23 @@ TEST_F(HostContentSettingsMapTest, Patterns) {
HostContentSettingsMap::Pattern pattern2("example.org");
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host1, CONTENT_SETTINGS_TYPE_IMAGES));
+ host1, CONTENT_SETTINGS_TYPE_IMAGES, ""));
host_content_settings_map->SetContentSetting(pattern1,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host1, CONTENT_SETTINGS_TYPE_IMAGES));
+ host1, CONTENT_SETTINGS_TYPE_IMAGES, ""));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host2, CONTENT_SETTINGS_TYPE_IMAGES));
+ host2, CONTENT_SETTINGS_TYPE_IMAGES, ""));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host3, CONTENT_SETTINGS_TYPE_IMAGES));
+ host3, CONTENT_SETTINGS_TYPE_IMAGES, ""));
host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host3, CONTENT_SETTINGS_TYPE_IMAGES));
+ host3, CONTENT_SETTINGS_TYPE_IMAGES, ""));
}
TEST_F(HostContentSettingsMapTest, PatternSupport) {
@@ -246,27 +255,31 @@ TEST_F(HostContentSettingsMapTest, Observer) {
HostContentSettingsMap::Pattern pattern("[*.]example.com");
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_ALLOW);
+ 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);
}
@@ -287,7 +300,7 @@ TEST_F(HostContentSettingsMapTest, ObserveDefaultPref) {
CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES));
+ 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(
@@ -297,13 +310,13 @@ TEST_F(HostContentSettingsMapTest, ObserveDefaultPref) {
prefs->Set(prefs::kDefaultContentSettings, *default_value);
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES));
+ 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));
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
}
TEST_F(HostContentSettingsMapTest, ObserveExceptionPref) {
@@ -321,10 +334,10 @@ TEST_F(HostContentSettingsMapTest, ObserveExceptionPref) {
GURL host("http://example.com");
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES));
+ 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(
@@ -334,13 +347,13 @@ TEST_F(HostContentSettingsMapTest, ObserveExceptionPref) {
prefs->Set(prefs::kContentSettingsPatterns, *default_value);
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES));
+ 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));
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
}
TEST_F(HostContentSettingsMapTest, HostTrimEndingDotCheck) {
@@ -353,73 +366,73 @@ TEST_F(HostContentSettingsMapTest, HostTrimEndingDotCheck) {
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES));
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_DEFAULT);
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ 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));
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_DEFAULT);
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+ 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));
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_DEFAULT);
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK);
+ 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));
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_DEFAULT);
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK);
+ 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));
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_POPUPS, CONTENT_SETTING_DEFAULT);
+ 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_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_POPUPS, CONTENT_SETTING_ALLOW);
+ 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));
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
}
TEST_F(HostContentSettingsMapTest, NestedSettings) {
@@ -433,11 +446,11 @@ TEST_F(HostContentSettingsMapTest, NestedSettings) {
HostContentSettingsMap::Pattern pattern3("a.b.example.com");
host_content_settings_map->SetContentSetting(pattern1,
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
host_content_settings_map->SetContentSetting(pattern3,
- CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK);
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
host_content_settings_map->SetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK);
@@ -487,32 +500,125 @@ TEST_F(HostContentSettingsMapTest, OffTheRecord) {
EXPECT_EQ(CONTENT_SETTING_ALLOW,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
otr_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ 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);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
otr_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ 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);
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_ALLOW);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
otr_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES));
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+}
+
+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 cl(*CommandLine::ForCurrentProcess());
+ CommandLine::ForCurrentProcess()->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));
+ *CommandLine::ForCurrentProcess() = cl;
+}
+
+TEST_F(HostContentSettingsMapTest, ResourceIdentifierPrefs) {
+ // This feature is currently behind a flag.
+ CommandLine cl(*CommandLine::ForCurrentProcess());
+ CommandLine::ForCurrentProcess()->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());
+ *CommandLine::ForCurrentProcess() = cl;
}
} // namespace
diff --git a/chrome/browser/host_zoom_map.cc b/chrome/browser/host_zoom_map.cc
index 50e1519..cb67a04 100644
--- a/chrome/browser/host_zoom_map.cc
+++ b/chrome/browser/host_zoom_map.cc
@@ -4,11 +4,12 @@
#include "chrome/browser/host_zoom_map.h"
+#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/scoped_pref_update.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
@@ -26,8 +27,10 @@ HostZoomMap::HostZoomMap(Profile* profile)
// Don't observe pref changes (e.g. from sync) in Incognito; once we create
// the incognito window it should have no further connection to the main
// profile/prefs.
- if (!profile_->IsOffTheRecord())
- profile_->GetPrefs()->AddPrefObserver(prefs::kPerHostZoomLevels, this);
+ if (!profile_->IsOffTheRecord()) {
+ pref_change_registrar_.Init(profile_->GetPrefs());
+ pref_change_registrar_.Add(prefs::kPerHostZoomLevels, this);
+ }
}
void HostZoomMap::Load() {
@@ -42,12 +45,12 @@ void HostZoomMap::Load() {
if (host_zoom_dictionary != NULL) {
for (DictionaryValue::key_iterator i(host_zoom_dictionary->begin_keys());
i != host_zoom_dictionary->end_keys(); ++i) {
- std::wstring wide_host(*i);
+ const std::string& host(*i);
int zoom_level = 0;
bool success = host_zoom_dictionary->GetIntegerWithoutPathExpansion(
- wide_host, &zoom_level);
+ host, &zoom_level);
DCHECK(success);
- host_zoom_levels_[WideToUTF8(wide_host)] = zoom_level;
+ host_zoom_levels_[host] = zoom_level;
}
}
}
@@ -94,13 +97,11 @@ void HostZoomMap::SetZoomLevel(const GURL& url, int level) {
ScopedPrefUpdate update(profile_->GetPrefs(), prefs::kPerHostZoomLevels);
DictionaryValue* host_zoom_dictionary =
profile_->GetPrefs()->GetMutableDictionary(prefs::kPerHostZoomLevels);
- std::wstring wide_host(UTF8ToWide(host));
if (level == 0) {
- host_zoom_dictionary->RemoveWithoutPathExpansion(wide_host, NULL);
+ host_zoom_dictionary->RemoveWithoutPathExpansion(host, NULL);
} else {
host_zoom_dictionary->SetWithoutPathExpansion(
- wide_host,
- Value::CreateIntegerValue(level));
+ host, Value::CreateIntegerValue(level));
}
}
updating_preferences_ = false;
@@ -129,7 +130,7 @@ void HostZoomMap::Shutdown() {
NotificationType::PROFILE_DESTROYED,
Source<Profile>(profile_));
if (!profile_->IsOffTheRecord())
- profile_->GetPrefs()->RemovePrefObserver(prefs::kPerHostZoomLevels, this);
+ pref_change_registrar_.RemoveAll();
profile_ = NULL;
}
@@ -150,7 +151,7 @@ void HostZoomMap::Observe(
if (updating_preferences_)
return;
- std::wstring* name = Details<std::wstring>(details).ptr();
+ std::string* name = Details<std::string>(details).ptr();
if (prefs::kPerHostZoomLevels == *name) {
Load();
return;
diff --git a/chrome/browser/host_zoom_map.h b/chrome/browser/host_zoom_map.h
index 648162c..3142024 100644
--- a/chrome/browser/host_zoom_map.h
+++ b/chrome/browser/host_zoom_map.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_HOST_ZOOM_MAP_H_
#define CHROME_BROWSER_HOST_ZOOM_MAP_H_
+#pragma once
#include <map>
#include <string>
@@ -14,6 +15,7 @@
#include "base/basictypes.h"
#include "base/lock.h"
#include "base/ref_counted.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -82,6 +84,7 @@ class HostZoomMap : public NotificationObserver,
bool updating_preferences_;
NotificationRegistrar registrar_;
+ PrefChangeRegistrar pref_change_registrar_;
DISALLOW_COPY_AND_ASSIGN(HostZoomMap);
};
diff --git a/chrome/browser/host_zoom_map_unittest.cc b/chrome/browser/host_zoom_map_unittest.cc
index a59a142..5d206e1 100644
--- a/chrome/browser/host_zoom_map_unittest.cc
+++ b/chrome/browser/host_zoom_map_unittest.cc
@@ -8,7 +8,7 @@
#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/host_zoom_map.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_registrar.h"
@@ -40,7 +40,7 @@ class HostZoomMapTest : public testing::Test {
pref_observer_,
Observe(NotificationType(NotificationType::PREF_CHANGED),
_,
- Property(&Details<std::wstring>::ptr,
+ Property(&Details<std::string>::ptr,
Pointee(per_host_zoom_levels_pref_))));
}
@@ -48,7 +48,7 @@ class HostZoomMapTest : public testing::Test {
ChromeThread ui_thread_;
TestingProfile profile_;
PrefService* prefs_;
- std::wstring per_host_zoom_levels_pref_; // For the observe matcher.
+ std::string per_host_zoom_levels_pref_; // For the observe matcher.
GURL url_;
std::string host_;
NotificationObserverMock pref_observer_;
@@ -63,42 +63,42 @@ TEST_F(HostZoomMapTest, LoadNoPrefs) {
TEST_F(HostZoomMapTest, Load) {
DictionaryValue* dict =
prefs_->GetMutableDictionary(prefs::kPerHostZoomLevels);
- dict->SetWithoutPathExpansion(UTF8ToWide(host_),
- Value::CreateIntegerValue(kZoomLevel));
+ dict->SetWithoutPathExpansion(host_, Value::CreateIntegerValue(kZoomLevel));
scoped_refptr<HostZoomMap> map(new HostZoomMap(&profile_));
EXPECT_EQ(kZoomLevel, map->GetZoomLevel(url_));
}
TEST_F(HostZoomMapTest, SetZoomLevel) {
scoped_refptr<HostZoomMap> map(new HostZoomMap(&profile_));
- prefs_->AddPrefObserver(prefs::kPerHostZoomLevels, &pref_observer_);
+ PrefChangeRegistrar registrar;
+ registrar.Init(prefs_);
+ registrar.Add(prefs::kPerHostZoomLevels, &pref_observer_);
SetPrefObserverExpectation();
map->SetZoomLevel(url_, kZoomLevel);
EXPECT_EQ(kZoomLevel, map->GetZoomLevel(url_));
const DictionaryValue* dict =
prefs_->GetDictionary(prefs::kPerHostZoomLevels);
int zoom_level = 0;
- EXPECT_TRUE(dict->GetIntegerWithoutPathExpansion(UTF8ToWide(host_),
- &zoom_level));
+ EXPECT_TRUE(dict->GetIntegerWithoutPathExpansion(host_, &zoom_level));
EXPECT_EQ(kZoomLevel, zoom_level);
SetPrefObserverExpectation();
map->SetZoomLevel(url_, 0);
EXPECT_EQ(0, map->GetZoomLevel(url_));
- EXPECT_FALSE(dict->HasKey(UTF8ToWide(host_)));
- prefs_->RemovePrefObserver(prefs::kPerHostZoomLevels, &pref_observer_);
+ EXPECT_FALSE(dict->HasKey(host_));
}
TEST_F(HostZoomMapTest, ResetToDefaults) {
scoped_refptr<HostZoomMap> map(new HostZoomMap(&profile_));
map->SetZoomLevel(url_, kZoomLevel);
- prefs_->AddPrefObserver(prefs::kPerHostZoomLevels, &pref_observer_);
+ PrefChangeRegistrar registrar;
+ registrar.Init(prefs_);
+ registrar.Add(prefs::kPerHostZoomLevels, &pref_observer_);
SetPrefObserverExpectation();
map->ResetToDefaults();
EXPECT_EQ(0, map->GetZoomLevel(url_));
EXPECT_EQ(NULL, prefs_->GetDictionary(prefs::kPerHostZoomLevels));
- prefs_->RemovePrefObserver(prefs::kPerHostZoomLevels, &pref_observer_);
}
TEST_F(HostZoomMapTest, ReloadOnPrefChange) {
@@ -106,8 +106,7 @@ TEST_F(HostZoomMapTest, ReloadOnPrefChange) {
map->SetZoomLevel(url_, kZoomLevel);
DictionaryValue dict;
- dict.SetWithoutPathExpansion(UTF8ToWide(host_),
- Value::CreateIntegerValue(0));
+ dict.SetWithoutPathExpansion(host_, Value::CreateIntegerValue(0));
prefs_->Set(prefs::kPerHostZoomLevels, dict);
EXPECT_EQ(0, map->GetZoomLevel(url_));
}
diff --git a/chrome/browser/hung_renderer_dialog.h b/chrome/browser/hung_renderer_dialog.h
index 6fcc33d..0351daa 100644
--- a/chrome/browser/hung_renderer_dialog.h
+++ b/chrome/browser/hung_renderer_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_HUNG_RENDERER_DIALOG_H_
#define CHROME_BROWSER_HUNG_RENDERER_DIALOG_H_
+#pragma once
class TabContents;
diff --git a/chrome/browser/icon_loader.cc b/chrome/browser/icon_loader.cc
index 19ca22d..2281b89 100644
--- a/chrome/browser/icon_loader.cc
+++ b/chrome/browser/icon_loader.cc
@@ -5,11 +5,14 @@
#include "chrome/browser/icon_loader.h"
#include "base/message_loop.h"
-#include "base/mime_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#if defined(TOOLKIT_GTK)
+#include "base/mime_util.h"
+#endif
+
IconLoader::IconLoader(const IconGroupID& group, IconSize size,
Delegate* delegate)
: target_message_loop_(NULL),
diff --git a/chrome/browser/icon_loader.h b/chrome/browser/icon_loader.h
index da15739..32b4048 100644
--- a/chrome/browser/icon_loader.h
+++ b/chrome/browser/icon_loader.h
@@ -1,14 +1,19 @@
-// 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.
#ifndef CHROME_BROWSER_ICON_LOADER_H_
#define CHROME_BROWSER_ICON_LOADER_H_
+#pragma once
+
+#include "build/build_config.h"
#include <string>
#include "base/basictypes.h"
+#if defined(TOOLKIT_USES_GTK)
#include "base/file_path.h"
+#endif
#include "base/ref_counted.h"
#if defined(OS_WIN)
diff --git a/chrome/browser/icon_manager.h b/chrome/browser/icon_manager.h
index afb1802..7ccd55a 100644
--- a/chrome/browser/icon_manager.h
+++ b/chrome/browser/icon_manager.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.
//
@@ -44,10 +44,9 @@
#ifndef CHROME_BROWSER_ICON_MANAGER_H_
#define CHROME_BROWSER_ICON_MANAGER_H_
+#pragma once
#include <map>
-#include <set>
-#include <string>
#include "base/callback.h"
#include "base/hash_tables.h"
diff --git a/chrome/browser/idbbindingutilities_browsertest.cc b/chrome/browser/idbbindingutilities_browsertest.cc
new file mode 100644
index 0000000..a408379
--- /dev/null
+++ b/chrome/browser/idbbindingutilities_browsertest.cc
@@ -0,0 +1,270 @@
+// Copyright (c) 2010 The Chromium Authors. 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/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/utility_process_host.h"
+#include "chrome/common/indexed_db_key.h"
+#include "chrome/common/serialized_script_value.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/ui_test_utils.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/idb_bindings.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSerializedScriptValue.h"
+
+using WebKit::WebSerializedScriptValue;
+
+// Sanity test, check the function call directly outside the sandbox.
+TEST(IDBKeyPathWithoutSandbox, Value) {
+ char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
+ std::vector<WebSerializedScriptValue> serialized_values;
+ serialized_values.push_back(
+ WebSerializedScriptValue::fromString(string16(data, arraysize(data))));
+ serialized_values.push_back(
+ WebSerializedScriptValue::fromString(string16()));
+
+ std::vector<WebKit::WebIDBKey> values;
+ string16 key_path(UTF8ToUTF16("foo"));
+ bool error = webkit_glue::IDBKeysFromValuesAndKeyPath(
+ serialized_values, key_path, &values);
+
+ ASSERT_EQ(size_t(2), values.size());
+ ASSERT_EQ(WebKit::WebIDBKey::StringType, values[0].type());
+ ASSERT_EQ(UTF8ToUTF16("zoo"), values[0].string());
+ ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type());
+ ASSERT_FALSE(error);
+
+ values.clear();
+ key_path = UTF8ToUTF16("PropertyNotAvailable");
+ error = webkit_glue::IDBKeysFromValuesAndKeyPath(
+ serialized_values, key_path, &values);
+
+ ASSERT_EQ(size_t(2), values.size());
+ ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[0].type());
+ ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type());
+ ASSERT_FALSE(error);
+
+ values.clear();
+ key_path = UTF8ToUTF16("!+Invalid[KeyPath[[[");
+ error = webkit_glue::IDBKeysFromValuesAndKeyPath(
+ serialized_values, key_path, &values);
+
+ ASSERT_TRUE(error);
+ ASSERT_EQ(size_t(2), values.size());
+ ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[0].type());
+ ASSERT_EQ(WebKit::WebIDBKey::InvalidType, values[1].type());
+}
+
+class IDBKeyPathHelper : public UtilityProcessHost::Client {
+ public:
+ IDBKeyPathHelper()
+ : expected_id_(0),
+ utility_process_host_(NULL),
+ value_for_key_path_failed_(false) {
+ }
+
+ void CreateUtilityProcess(ResourceDispatcherHost* resource_dispatcher_host) {
+ if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &IDBKeyPathHelper::CreateUtilityProcess,
+ resource_dispatcher_host));
+ return;
+ }
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ utility_process_host_ =
+ new UtilityProcessHost(resource_dispatcher_host, this,
+ ChromeThread::IO);
+ utility_process_host_->StartBatchMode();
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ new MessageLoop::QuitTask());
+ }
+
+ void DestroyUtilityProcess() {
+ if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &IDBKeyPathHelper::DestroyUtilityProcess));
+ return;
+ }
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ utility_process_host_->EndBatchMode();
+ utility_process_host_ = NULL;
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ new MessageLoop::QuitTask());
+ }
+
+ void SetExpected(int expected_id,
+ const std::vector<IndexedDBKey>& expected_values,
+ bool failed) {
+ expected_id_ = expected_id;
+ expected_values_ = expected_values;
+ value_for_key_path_failed_ = failed;
+ }
+
+ void CheckValuesForKeyPath(
+ int id, const std::vector<SerializedScriptValue>& serialized_values,
+ const string16& key_path) {
+ if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &IDBKeyPathHelper::CheckValuesForKeyPath,
+ id, serialized_values, key_path));
+ return;
+ }
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ bool ret =
+ utility_process_host_->StartIDBKeysFromValuesAndKeyPath(
+ id, serialized_values, key_path);
+ ASSERT_TRUE(ret);
+ }
+
+ // UtilityProcessHost::Client
+ virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
+ int id, const std::vector<IndexedDBKey>& values) {
+ EXPECT_EQ(expected_id_, id);
+ EXPECT_FALSE(value_for_key_path_failed_);
+ ASSERT_EQ(expected_values_.size(), values.size());
+ size_t pos = 0;
+ for (std::vector<IndexedDBKey>::const_iterator i(values.begin());
+ i != values.end(); ++i, ++pos) {
+ ASSERT_EQ(expected_values_[pos].type(), i->type());
+ if (i->type() == WebKit::WebIDBKey::StringType) {
+ ASSERT_EQ(expected_values_[pos].string(), i->string());
+ } else if (i->type() == WebKit::WebIDBKey::NumberType) {
+ ASSERT_EQ(expected_values_[pos].number(), i->number());
+ }
+ }
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ new MessageLoop::QuitTask());
+ }
+
+ virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id) {
+ EXPECT_TRUE(value_for_key_path_failed_);
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ new MessageLoop::QuitTask());
+ }
+
+ private:
+ int expected_id_;
+ std::vector<IndexedDBKey> expected_values_;
+ UtilityProcessHost* utility_process_host_;
+ bool value_for_key_path_failed_;
+};
+
+// This test fixture runs in the UI thread. However, most of the work done by
+// UtilityProcessHost (and wrapped by IDBKeyPathHelper above) happens on the IO
+// thread. This fixture delegates to IDBKeyPathHelper and blocks via
+// "ui_test_utils::RunMessageLoop()", until IDBKeyPathHelper posts a quit
+// message the MessageLoop.
+class ScopedIDBKeyPathHelper {
+ public:
+ ScopedIDBKeyPathHelper() {
+ key_path_helper_ = new IDBKeyPathHelper();
+ key_path_helper_->CreateUtilityProcess(
+ g_browser_process->resource_dispatcher_host());
+ ui_test_utils::RunMessageLoop();
+ }
+
+ ~ScopedIDBKeyPathHelper() {
+ key_path_helper_->DestroyUtilityProcess();
+ ui_test_utils::RunMessageLoop();
+ }
+
+ void SetExpected(int id, const std::vector<IndexedDBKey>& expected_values,
+ bool failed) {
+ key_path_helper_->SetExpected(id, expected_values, failed);
+ }
+
+ void CheckValuesForKeyPath(
+ int id,
+ const std::vector<SerializedScriptValue>& serialized_script_values,
+ const string16& key_path) {
+ key_path_helper_->CheckValuesForKeyPath(id, serialized_script_values,
+ key_path);
+ ui_test_utils::RunMessageLoop();
+ }
+
+ private:
+ scoped_refptr<IDBKeyPathHelper> key_path_helper_;
+};
+
+IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathExtract) {
+ ScopedIDBKeyPathHelper scoped_helper;
+ const int kId = 7;
+ std::vector<IndexedDBKey> expected_values;
+ IndexedDBKey value;
+ value.Set(UTF8ToUTF16("zoo"));
+ expected_values.push_back(value);
+
+ IndexedDBKey invalid_value;
+ invalid_value.SetInvalid();
+ expected_values.push_back(invalid_value);
+
+ scoped_helper.SetExpected(kId, expected_values, false);
+
+ char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
+ std::vector<SerializedScriptValue> serialized_values;
+ serialized_values.push_back(
+ SerializedScriptValue(false, false, string16(data, arraysize(data))));
+ serialized_values.push_back(
+ SerializedScriptValue(true, false, string16()));
+ scoped_helper.CheckValuesForKeyPath(
+ kId, serialized_values, UTF8ToUTF16("foo"));
+}
+
+IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathPropertyNotAvailable) {
+ ScopedIDBKeyPathHelper scoped_helper;
+ const int kId = 7;
+ std::vector<IndexedDBKey> expected_values;
+ IndexedDBKey invalid_value;
+ invalid_value.SetInvalid();
+ expected_values.push_back(invalid_value);
+ expected_values.push_back(invalid_value);
+
+ scoped_helper.SetExpected(kId, expected_values, false);
+
+ char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
+ std::vector<SerializedScriptValue> serialized_values;
+ serialized_values.push_back(
+ SerializedScriptValue(false, false, string16(data, arraysize(data))));
+ serialized_values.push_back(
+ SerializedScriptValue(true, false, string16()));
+ scoped_helper.CheckValuesForKeyPath(kId, serialized_values,
+ UTF8ToUTF16("PropertyNotAvailable"));
+}
+
+IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathMultipleCalls) {
+ ScopedIDBKeyPathHelper scoped_helper;
+ const int kId = 7;
+ std::vector<IndexedDBKey> expected_values;
+ IndexedDBKey invalid_value;
+ invalid_value.SetInvalid();
+ expected_values.push_back(invalid_value);
+ expected_values.push_back(invalid_value);
+
+ scoped_helper.SetExpected(kId, expected_values, true);
+
+ char16 data[] = {0x0353,0x6f66,0x536f,0x7a03,0x6f6f,0x017b};
+ std::vector<SerializedScriptValue> serialized_values;
+ serialized_values.push_back(
+ SerializedScriptValue(false, false, string16(data, arraysize(data))));
+ serialized_values.push_back(
+ SerializedScriptValue(true, false, string16()));
+ scoped_helper.CheckValuesForKeyPath(kId, serialized_values,
+ UTF8ToUTF16("!+Invalid[KeyPath[[["));
+
+ // Call again with the Utility process in batch mode and with valid keys.
+ expected_values.clear();
+ IndexedDBKey value;
+ value.Set(UTF8ToUTF16("zoo"));
+ expected_values.push_back(value);
+ expected_values.push_back(invalid_value);
+ scoped_helper.SetExpected(kId + 1, expected_values, false);
+ scoped_helper.CheckValuesForKeyPath(kId + 1, serialized_values,
+ UTF8ToUTF16("foo"));
+}
diff --git a/chrome/browser/idle.h b/chrome/browser/idle.h
index 4fe750f..3ea8067 100644
--- a/chrome/browser/idle.h
+++ b/chrome/browser/idle.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IDLE_H_
#define CHROME_BROWSER_IDLE_H_
+#pragma once
enum IdleState {
IDLE_STATE_ACTIVE = 0,
diff --git a/chrome/browser/ime_input.h b/chrome/browser/ime_input.h
index 184343b..e446ad3 100644
--- a/chrome/browser/ime_input.h
+++ b/chrome/browser/ime_input.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IME_INPUT_H_
#define CHROME_BROWSER_IME_INPUT_H_
+#pragma once
#include <windows.h>
@@ -223,8 +224,8 @@ class ImeInput {
// position without finishing it.
void EnableIME(HWND window_handle);
- // Disables the IME attached to the given window, i.e. prohibits any user-input
- // events from being dispatched to the IME.
+ // Disables the IME attached to the given window, i.e. prohibits any
+ // user-input events from being dispatched to the IME.
// In Chrome, this function is used when:
// * a renreder process sets its input focus to a password input.
// Parameters
diff --git a/chrome/browser/importer/firefox2_importer.cc b/chrome/browser/importer/firefox2_importer.cc
index d551105..d7932b8 100644
--- a/chrome/browser/importer/firefox2_importer.cc
+++ b/chrome/browser/importer/firefox2_importer.cc
@@ -13,6 +13,9 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/history/history_types.h"
@@ -482,7 +485,8 @@ bool Firefox2Importer::ParseBookmarkFromLine(const std::string& line,
// Add date
if (GetAttribute(attribute_list, kAddDateAttribute, &value)) {
- int64 time = StringToInt64(value);
+ int64 time;
+ base::StringToInt64(value, &time);
// Upper bound it at 32 bits.
if (0 < time && time < (1LL << 32))
*add_date = Time::FromTimeT(time);
diff --git a/chrome/browser/importer/firefox2_importer.h b/chrome/browser/importer/firefox2_importer.h
index c320e38..07a5567 100644
--- a/chrome/browser/importer/firefox2_importer.h
+++ b/chrome/browser/importer/firefox2_importer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_FIREFOX2_IMPORTER_H_
#define CHROME_BROWSER_IMPORTER_FIREFOX2_IMPORTER_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/importer/firefox3_importer.cc b/chrome/browser/importer/firefox3_importer.cc
index 2b95cc3..110f2b6 100644
--- a/chrome/browser/importer/firefox3_importer.cc
+++ b/chrome/browser/importer/firefox3_importer.cc
@@ -11,6 +11,8 @@
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/importer/firefox2_importer.h"
#include "chrome/browser/importer/firefox_importer_utils.h"
@@ -33,14 +35,26 @@ using importer::ProfileInfo;
using importer::SEARCH_ENGINES;
using webkit_glue::PasswordForm;
+Firefox3Importer::Firefox3Importer() {
+#if defined(OS_LINUX)
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ locale_ = g_browser_process->GetApplicationLocale();
+#endif
+}
+
+Firefox3Importer::~Firefox3Importer() {
+}
+
void Firefox3Importer::StartImport(importer::ProfileInfo profile_info,
uint16 items,
ImporterBridge* bridge) {
+#if defined(OS_LINUX)
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+#endif
bridge_ = bridge;
source_path_ = profile_info.source_path;
app_path_ = profile_info.app_path;
-
// The order here is important!
bridge_->NotifyStarted();
if ((items & importer::HOME_PAGE) && !cancelled())
@@ -118,7 +132,7 @@ void Firefox3Importer::ImportHistory() {
rows.push_back(row);
}
if (!rows.empty() && !cancelled()) {
- bridge_->SetHistoryItems(rows);
+ bridge_->SetHistoryItems(rows, history::SOURCE_FIREFOX_IMPORTED);
}
}
@@ -174,6 +188,7 @@ void Firefox3Importer::ImportBookmarks() {
post_keyword_ids.insert(s.column_int(0));
} else {
NOTREACHED();
+ return;
}
std::wstring firefox_folder =
@@ -349,9 +364,9 @@ void Firefox3Importer::GetSearchEnginesXMLFiles(
FilePath app_path = app_path_.AppendASCII("searchplugins");
FilePath profile_path = source_path_.AppendASCII("searchplugins");
- // Firefox doesn't store a search engine in its sqlite database unless
- // the user has changed the default definition of engine. So we get search
- // engines from sqlite db as well as from file system.
+ // Firefox doesn't store a search engine in its sqlite database unless the
+ // user has added a engine. So we get search engines from sqlite db as well
+ // as from the file system.
if (s.step() == SQLITE_ROW) {
const std::wstring kAppPrefix = L"[app]/";
const std::wstring kProfilePrefix = L"[profile]/";
@@ -380,6 +395,20 @@ void Firefox3Importer::GetSearchEnginesXMLFiles(
} while (s.step() == SQLITE_ROW && !cancelled());
}
+#if defined(OS_LINUX)
+ // Ubuntu-flavored Firefox3 supports locale-specific search engines via
+ // locale-named subdirectories. They fall back to en-US.
+ // See http://crbug.com/53899
+ // TODO(jshin): we need to make sure our locale code matches that of
+ // Firefox.
+ FilePath locale_app_path = app_path.AppendASCII(locale_);
+ FilePath default_locale_app_path = app_path.AppendASCII("en-US");
+ if (file_util::DirectoryExists(locale_app_path))
+ app_path = locale_app_path;
+ else if (file_util::DirectoryExists(default_locale_app_path))
+ app_path = default_locale_app_path;
+#endif
+
// Get search engine definition from file system.
file_util::FileEnumerator engines(app_path, false,
file_util::FileEnumerator::FILES);
diff --git a/chrome/browser/importer/firefox3_importer.h b/chrome/browser/importer/firefox3_importer.h
index f8bfa2f..592d4da 100644
--- a/chrome/browser/importer/firefox3_importer.h
+++ b/chrome/browser/importer/firefox3_importer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_FIREFOX3_IMPORTER_H_
#define CHROME_BROWSER_IMPORTER_FIREFOX3_IMPORTER_H_
+#pragma once
#include <map>
#include <set>
@@ -18,12 +19,12 @@
struct sqlite3;
-// Importer for Mozilla Firefox 3.
+// Importer for Mozilla Firefox 3 and later.
// Firefox 3 stores its persistent information in a new system called places.
// http://wiki.mozilla.org/Places
class Firefox3Importer : public Importer {
public:
- Firefox3Importer() { }
+ Firefox3Importer();
// Importer methods.
virtual void StartImport(importer::ProfileInfo profile_info,
@@ -33,7 +34,7 @@ class Firefox3Importer : public Importer {
private:
typedef std::map<int64, std::set<GURL> > FaviconMap;
- virtual ~Firefox3Importer() { }
+ virtual ~Firefox3Importer();
void ImportBookmarks();
void ImportPasswords();
@@ -81,6 +82,12 @@ class Firefox3Importer : public Importer {
FilePath source_path_;
FilePath app_path_;
+#if defined(OS_LINUX)
+ // Stored because we can only access it from the UI thread. Not usable
+ // in Mac because no access from out-of-process import.
+ std::string locale_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(Firefox3Importer);
};
diff --git a/chrome/browser/importer/firefox_importer_unittest.cc b/chrome/browser/importer/firefox_importer_unittest.cc
index 42c23ac..060015d 100644
--- a/chrome/browser/importer/firefox_importer_unittest.cc
+++ b/chrome/browser/importer/firefox_importer_unittest.cc
@@ -7,6 +7,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/importer/firefox2_importer.h"
#include "chrome/browser/importer/firefox_importer_unittest_utils.h"
diff --git a/chrome/browser/importer/firefox_importer_unittest_utils.h b/chrome/browser/importer/firefox_importer_unittest_utils.h
index 3eb12d6..9a1df8d 100644
--- a/chrome/browser/importer/firefox_importer_unittest_utils.h
+++ b/chrome/browser/importer/firefox_importer_unittest_utils.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UNITTEST_UTILS_H_
#define CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UNITTEST_UTILS_H_
+#pragma once
#include "base/basictypes.h"
#include "base/process_util.h"
diff --git a/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
index 03dddc7..f9958fb 100644
--- a/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
+++ b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/importer/firefox_importer_unittest_utils.h"
+#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug_on_start.h"
#include "base/file_path.h"
@@ -16,11 +17,16 @@
#include "ipc/ipc_switches.h"
#include "testing/multiprocess_func_list.h"
-// Definition of IPC Messages used for this test.
+// 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"
+
namespace {
// Name of IPC Channel to use for Server<-> Child Communications.
@@ -34,7 +40,7 @@ const char kTestChannelID[] = "T1";
bool LaunchNSSDecrypterChildProcess(const std::wstring& nss_path,
const IPC::Channel& channel, base::ProcessHandle* handle) {
CommandLine cl(*CommandLine::ForCurrentProcess());
- cl.AppendSwitchWithValue("client", "NSSDecrypterChildProcess");
+ cl.AppendSwitchASCII(switches::kTestChildProcess, "NSSDecrypterChildProcess");
FilePath ff_dylib_dir = FilePath::FromWStringHack(nss_path);
// Set env variable needed for FF encryption libs to load.
diff --git a/chrome/browser/importer/firefox_importer_utils.cc b/chrome/browser/importer/firefox_importer_utils.cc
index b9a7a74..6ff1798 100644
--- a/chrome/browser/importer/firefox_importer_utils.cc
+++ b/chrome/browser/importer/firefox_importer_utils.cc
@@ -10,7 +10,9 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/search_engines/template_url.h"
@@ -51,7 +53,7 @@ FilePath GetFirefoxProfilePath() {
FilePath source_path;
for (int i = 0; ; ++i) {
std::string current_profile = StringPrintf("Profile%d", i);
- if (!root.HasKeyASCII(current_profile)) {
+ if (!root.HasKey(current_profile)) {
// Profiles are continuously numbered. So we exit when we can't
// find the i-th one.
break;
@@ -132,35 +134,35 @@ void ParseProfileINI(const FilePath& file, DictionaryValue* root) {
// Parses the file.
root->Clear();
- std::wstring current_section;
+ std::string current_section;
for (size_t i = 0; i < lines.size(); ++i) {
- std::wstring line = UTF8ToWide(lines[i]);
+ std::string line = lines[i];
if (line.empty()) {
// Skips the empty line.
continue;
}
- if (line[0] == L'#' || line[0] == L';') {
+ if (line[0] == '#' || line[0] == ';') {
// This line is a comment.
continue;
}
- if (line[0] == L'[') {
+ if (line[0] == '[') {
// It is a section header.
current_section = line.substr(1);
- size_t end = current_section.rfind(L']');
- if (end != std::wstring::npos)
+ size_t end = current_section.rfind(']');
+ if (end != std::string::npos)
current_section.erase(end);
} else {
- std::wstring key, value;
- size_t equal = line.find(L'=');
- if (equal != std::wstring::npos) {
+ std::string key, value;
+ size_t equal = line.find('=');
+ if (equal != std::string::npos) {
key = line.substr(0, equal);
value = line.substr(equal + 1);
// Checks whether the section and key contain a '.' character.
// Those sections and keys break DictionaryValue's path format,
// so we discard them.
- if (current_section.find(L'.') == std::wstring::npos &&
- key.find(L'.') == std::wstring::npos)
- root->SetString(current_section + L"." + key, value);
+ if (current_section.find('.') == std::string::npos &&
+ key.find('.') == std::string::npos)
+ root->SetString(current_section + "." + key, value);
}
}
}
@@ -242,8 +244,7 @@ bool ReadPrefFile(const FilePath& path, std::string* content) {
file_util::ReadFileToString(path, content);
if (content->empty()) {
- NOTREACHED() << "Firefox preference file " << path.value()
- << " is empty.";
+ LOG(WARNING) << "Firefox preference file " << path.value() << " is empty.";
return false;
}
@@ -268,7 +269,7 @@ std::string ReadBrowserConfigProp(const FilePath& app_path,
if (start == std::string::npos ||
stop == std::string::npos || (start == stop)) {
- NOTREACHED() << "Firefox property " << pref_key << " could not be parsed.";
+ LOG(WARNING) << "Firefox property " << pref_key << " could not be parsed.";
return "";
}
@@ -281,30 +282,7 @@ std::string ReadPrefsJsValue(const FilePath& profile_path,
if (!ReadPrefFile(profile_path.AppendASCII("prefs.js"), &content))
return "";
- // This file has the syntax: user_pref("key", value);
- std::string search_for = std::string("user_pref(\"") + pref_key +
- std::string("\", ");
- size_t prop_index = content.find(search_for);
- if (prop_index == std::string::npos)
- return "";
-
- size_t start = prop_index + search_for.length();
- size_t stop = std::string::npos;
- if (start != std::string::npos)
- stop = content.find(")", start + 1);
-
- if (start == std::string::npos || stop == std::string::npos) {
- NOTREACHED() << "Firefox property " << pref_key << " could not be parsed.";
- return "";
- }
-
- // String values have double quotes we don't need to return to the caller.
- if (content[start] == '\"' && content[stop - 1] == '\"') {
- ++start;
- --stop;
- }
-
- return content.substr(start, stop - start);
+ return GetPrefsJsValue(content, pref_key);
}
int GetFirefoxDefaultSearchEngineIndex(
@@ -316,8 +294,8 @@ int GetFirefoxDefaultSearchEngineIndex(
if (search_engines.empty())
return -1;
- std::wstring default_se_name = UTF8ToWide(
- ReadPrefsJsValue(profile_path, "browser.search.selectedEngine"));
+ std::string default_se_name =
+ ReadPrefsJsValue(profile_path, "browser.search.selectedEngine");
if (default_se_name.empty()) {
// browser.search.selectedEngine does not exist if the user has not changed
@@ -330,13 +308,13 @@ int GetFirefoxDefaultSearchEngineIndex(
int default_se_index = -1;
for (std::vector<TemplateURL*>::const_iterator iter = search_engines.begin();
iter != search_engines.end(); ++iter) {
- if (default_se_name == (*iter)->short_name()) {
+ if (default_se_name == WideToUTF8((*iter)->short_name())) {
default_se_index = static_cast<int>(iter - search_engines.begin());
break;
}
}
if (default_se_index == -1) {
- NOTREACHED() <<
+ LOG(WARNING) <<
"Firefox default search engine not found in search engine list";
}
@@ -419,7 +397,7 @@ bool ParsePrefFile(const FilePath& pref_file, DictionaryValue* prefs) {
// Value could be a boolean.
bool is_value_true = LowerCaseEqualsASCII(value, "true");
if (is_value_true || LowerCaseEqualsASCII(value, "false")) {
- prefs->SetBoolean(ASCIIToWide(key), is_value_true);
+ prefs->SetBoolean(key, is_value_true);
continue;
}
@@ -430,7 +408,7 @@ bool ParsePrefFile(const FilePath& pref_file, DictionaryValue* prefs) {
// ValueString only accept valid UTF-8. Simply ignore that entry if it is
// not UTF-8.
if (IsStringUTF8(value))
- prefs->SetString(ASCIIToWide(key), value);
+ prefs->SetString(key, value);
else
LOG(INFO) << "Non UTF8 value for key " << key << ", ignored.";
continue;
@@ -438,8 +416,8 @@ bool ParsePrefFile(const FilePath& pref_file, DictionaryValue* prefs) {
// Or value could be an integer.
int int_value = 0;
- if (StringToInt(value, &int_value)) {
- prefs->SetInteger(ASCIIToWide(key), int_value);
+ if (base::StringToInt(value, &int_value)) {
+ prefs->SetInteger(key, int_value);
continue;
}
@@ -448,3 +426,35 @@ bool ParsePrefFile(const FilePath& pref_file, DictionaryValue* prefs) {
}
return true;
}
+
+std::string GetPrefsJsValue(const std::string& content,
+ const std::string& pref_key) {
+ // This file has the syntax: user_pref("key", value);
+ std::string search_for = std::string("user_pref(\"") + pref_key +
+ std::string("\", ");
+ size_t prop_index = content.find(search_for);
+ if (prop_index == std::string::npos)
+ return "";
+
+ size_t start = prop_index + search_for.length();
+ size_t stop = std::string::npos;
+ if (start != std::string::npos) {
+ // Stop at the last ')' on this line.
+ stop = content.find("\n", start + 1);
+ stop = content.rfind(")", stop);
+ }
+
+ if (start == std::string::npos || stop == std::string::npos ||
+ stop < start) {
+ LOG(WARNING) << "Firefox property " << pref_key << " could not be parsed.";
+ return "";
+ }
+
+ // String values have double quotes we don't need to return to the caller.
+ if (content[start] == '\"' && content[stop - 1] == '\"') {
+ ++start;
+ --stop;
+ }
+
+ return content.substr(start, stop - start);
+}
diff --git a/chrome/browser/importer/firefox_importer_utils.h b/chrome/browser/importer/firefox_importer_utils.h
index 1ad7ddb..b5c4d6d 100644
--- a/chrome/browser/importer/firefox_importer_utils.h
+++ b/chrome/browser/importer/firefox_importer_utils.h
@@ -1,17 +1,19 @@
-// 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.
#ifndef CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UTILS_H_
#define CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UTILS_H_
+#pragma once
+#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "build/build_config.h"
class DictionaryValue;
+class FilePath;
class GURL;
class TemplateURL;
@@ -94,4 +96,9 @@ bool IsDefaultHomepage(const GURL& homepage, const FilePath& app_path);
// key/pair is not valid UTF-8, it is ignored and will not appear in |prefs|.
bool ParsePrefFile(const FilePath& pref_file, DictionaryValue* prefs);
+// Parses the value of a particular firefox preference from a string that is
+// the contents of the prefs file.
+std::string GetPrefsJsValue(const std::string& prefs,
+ const std::string& pref_key);
+
#endif // CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UTILS_H_
diff --git a/chrome/browser/importer/firefox_importer_utils_win.cc b/chrome/browser/importer/firefox_importer_utils_win.cc
index 77e3fcb..3200eb1 100644
--- a/chrome/browser/importer/firefox_importer_utils_win.cc
+++ b/chrome/browser/importer/firefox_importer_utils_win.cc
@@ -29,7 +29,7 @@ int GetCurrentFirefoxMajorVersionFromRegistry() {
// HKCU\Mozilla.
for (int i = 0; i < arraysize(kFireFoxRegistryPaths); ++i) {
RegKey reg_key(kFireFoxRegistryPaths[i],
- L"Software\\Mozilla\\Mozilla Firefox");
+ L"Software\\Mozilla\\Mozilla Firefox", KEY_READ);
bool result = reg_key.ReadValue(L"CurrentVersion", ver_buffer,
&ver_buffer_length, NULL);
@@ -43,16 +43,16 @@ int GetCurrentFirefoxMajorVersionFromRegistry() {
std::wstring GetFirefoxInstallPathFromRegistry() {
// Detects the path that Firefox is installed in.
std::wstring registry_path = L"Software\\Mozilla\\Mozilla Firefox";
- TCHAR buffer[MAX_PATH];
+ wchar_t buffer[MAX_PATH];
DWORD buffer_length = sizeof(buffer);
- RegKey reg_key(HKEY_LOCAL_MACHINE, registry_path.c_str());
+ RegKey reg_key(HKEY_LOCAL_MACHINE, registry_path.c_str(), KEY_READ);
bool result = reg_key.ReadValue(L"CurrentVersion", buffer,
&buffer_length, NULL);
if (!result)
return std::wstring();
registry_path += L"\\" + std::wstring(buffer) + L"\\Main";
buffer_length = sizeof(buffer);
- RegKey reg_key_directory = RegKey(HKEY_LOCAL_MACHINE, registry_path.c_str());
+ RegKey reg_key_directory(HKEY_LOCAL_MACHINE, registry_path.c_str(), KEY_READ);
result = reg_key_directory.ReadValue(L"Install Directory", buffer,
&buffer_length, NULL);
if (!result)
diff --git a/chrome/browser/importer/firefox_profile_lock.h b/chrome/browser/importer/firefox_profile_lock.h
index 20b9065..9c6b687 100644
--- a/chrome/browser/importer/firefox_profile_lock.h
+++ b/chrome/browser/importer/firefox_profile_lock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_FIREFOX_PROFILE_LOCK_H__
#define CHROME_BROWSER_IMPORTER_FIREFOX_PROFILE_LOCK_H__
+#pragma once
#include "build/build_config.h"
@@ -11,8 +12,6 @@
#include <windows.h>
#endif
-#include <string>
-
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
diff --git a/chrome/browser/importer/firefox_proxy_settings.cc b/chrome/browser/importer/firefox_proxy_settings.cc
index 0f8ff39..1771b1c 100644
--- a/chrome/browser/importer/firefox_proxy_settings.cc
+++ b/chrome/browser/importer/firefox_proxy_settings.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/importer/firefox_proxy_settings.h"
+#include "base/file_path.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/values.h"
@@ -12,18 +13,18 @@
namespace {
-const wchar_t* const kNetworkProxyTypeKey = L"network.proxy.type";
+const char* const kNetworkProxyTypeKey = "network.proxy.type";
const char* const kHTTPProxyKey = "network.proxy.http";
-const wchar_t* const kHTTPProxyPortKey = L"network.proxy.http_port";
+const char* const kHTTPProxyPortKey = "network.proxy.http_port";
const char* const kSSLProxyKey = "network.proxy.ssl";
-const wchar_t* const kSSLProxyPortKey = L"network.proxy.ssl_port";
+const char* const kSSLProxyPortKey = "network.proxy.ssl_port";
const char* const kFTPProxyKey = "network.proxy.ftp";
-const wchar_t* const kFTPProxyPortKey = L"network.proxy.ftp_port";
+const char* const kFTPProxyPortKey = "network.proxy.ftp_port";
const char* const kGopherProxyKey = "network.proxy.gopher";
-const wchar_t* const kGopherProxyPortKey = L"network.proxy.gopher_port";
+const char* const kGopherProxyPortKey = "network.proxy.gopher_port";
const char* const kSOCKSHostKey = "network.proxy.socks";
-const wchar_t* const kSOCKSHostPortKey = L"network.proxy.socks_port";
-const wchar_t* const kSOCKSVersionKey = L"network.proxy.socks_version";
+const char* const kSOCKSHostPortKey = "network.proxy.socks_port";
+const char* const kSOCKSVersionKey = "network.proxy.socks_version";
const char* const kAutoconfigURL = "network.proxy.autoconfig_url";
const char* const kNoProxyListKey = "network.proxy.no_proxies_on";
const char* const kPrefFileName = "prefs.js";
@@ -127,32 +128,28 @@ bool FirefoxProxySettings::ToProxyConfig(net::ProxyConfig* config) {
if (!http_proxy().empty()) {
config->proxy_rules().proxy_for_http = net::ProxyServer(
net::ProxyServer::SCHEME_HTTP,
- http_proxy(),
- http_proxy_port());
+ net::HostPortPair(http_proxy(), http_proxy_port()));
}
if (!ftp_proxy().empty()) {
config->proxy_rules().proxy_for_ftp = net::ProxyServer(
net::ProxyServer::SCHEME_HTTP,
- ftp_proxy(),
- ftp_proxy_port());
+ net::HostPortPair(ftp_proxy(), ftp_proxy_port()));
}
if (!ssl_proxy().empty()) {
config->proxy_rules().proxy_for_https = net::ProxyServer(
net::ProxyServer::SCHEME_HTTP,
- ssl_proxy(),
- ssl_proxy_port());
+ net::HostPortPair(ssl_proxy(), ssl_proxy_port()));
}
if (!socks_host().empty()) {
net::ProxyServer::Scheme proxy_scheme = V5 == socks_version() ?
net::ProxyServer::SCHEME_SOCKS5 : net::ProxyServer::SCHEME_SOCKS4;
- config->proxy_rules().socks_proxy = net::ProxyServer(
+ config->proxy_rules().fallback_proxy = net::ProxyServer(
proxy_scheme,
- socks_host(),
- socks_port());
+ net::HostPortPair(socks_host(), socks_port()));
}
config->proxy_rules().bypass_rules.ParseFromStringUsingSuffixMatching(
diff --git a/chrome/browser/importer/firefox_proxy_settings.h b/chrome/browser/importer/firefox_proxy_settings.h
index 80e1e24..6ad3249 100644
--- a/chrome/browser/importer/firefox_proxy_settings.h
+++ b/chrome/browser/importer/firefox_proxy_settings.h
@@ -4,11 +4,12 @@
#ifndef CHROME_BROWSER_IMPORTER_FIREFOX_PROXY_SETTINGS_H_
#define CHROME_BROWSER_IMPORTER_FIREFOX_PROXY_SETTINGS_H_
+#pragma once
#include <string>
#include <vector>
-#include "base/logging.h"
+#include "base/basictypes.h"
class FilePath;
diff --git a/chrome/browser/importer/firefox_proxy_settings_unittest.cc b/chrome/browser/importer/firefox_proxy_settings_unittest.cc
index ed2a66c..3781741 100644
--- a/chrome/browser/importer/firefox_proxy_settings_unittest.cc
+++ b/chrome/browser/importer/firefox_proxy_settings_unittest.cc
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <sstream>
-
#include "testing/gtest/include/gtest/gtest.h"
#include "base/file_path.h"
@@ -56,26 +54,15 @@ TEST_F(FirefoxProxySettingsTest, TestParse) {
net::ProxyConfig config;
EXPECT_TRUE(settings.ToProxyConfig(&config));
- // Pretty-print |config| to a string (easy way to define the expectations).
- std::ostringstream stream;
- stream << config;
- std::string pretty_printed_config = stream.str();
-
- EXPECT_EQ(
- "Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: [None]\n"
- "Manual settings:\n"
- " Proxy server: \n"
- " HTTP: http_proxy:1111\n"
- " HTTPS: ssl_proxy:2222\n"
- " FTP: ftp_proxy:3333\n"
- " SOCKS: socks4://socks_host:5555\n"
- " Bypass list: \n"
- " *localhost\n"
- " 127.0.0.1\n"
- " *noproxy.com",
- pretty_printed_config);
+ {
+ net::ProxyConfig expected_config;
+ expected_config.proxy_rules().ParseFromString("http=http_proxy:1111; "
+ "https=ssl_proxy:2222; "
+ "ftp=ftp_proxy:3333; "
+ "socks=socks_host:5555");
+ expected_config.proxy_rules().bypass_rules.ParseFromString(
+ "*localhost, 127.0.0.1, *noproxy.com");
+ }
}
TEST_F(FirefoxProxySettingsTest, TestParseAutoConfigUrl) {
@@ -108,17 +95,6 @@ TEST_F(FirefoxProxySettingsTest, TestParseAutoConfigUrl) {
net::ProxyConfig config;
EXPECT_TRUE(settings.ToProxyConfig(&config));
- // Pretty-print |config| to a string (easy way to define the expectations).
- std::ostringstream stream;
- stream << config;
- std::string pretty_printed_config = stream.str();
-
- EXPECT_EQ(
- "Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: http://custom-pac-url/\n"
- "Manual settings:\n"
- " Proxy server: [None]\n"
- " Bypass list: [None]",
- pretty_printed_config);
+ EXPECT_TRUE(config.Equals(net::ProxyConfig::CreateFromCustomPacURL(
+ GURL("http://custom-pac-url/"))));
}
diff --git a/chrome/browser/importer/ie_importer.cc b/chrome/browser/importer/ie_importer.cc
index 2824b40..cbea511 100644
--- a/chrome/browser/importer/ie_importer.cc
+++ b/chrome/browser/importer/ie_importer.cc
@@ -21,13 +21,17 @@
#include "base/file_util.h"
#include "base/registry.h"
#include "base/scoped_comptr_win.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/values.h"
+#include "base/utf_string_conversions.h"
#include "base/win_util.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/importer/importer_bridge.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/password_manager/ie7_password.h"
+#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
@@ -258,11 +262,13 @@ void IEImporter::ImportPasswordsIE7() {
while (reg_iterator.Valid() && !cancelled()) {
// Get the size of the encrypted data.
DWORD value_len = 0;
- if (key.ReadValue(reg_iterator.Name(), NULL, &value_len) && value_len) {
+ if (key.ReadValue(reg_iterator.Name(), NULL, &value_len, NULL) &&
+ value_len) {
// Query the encrypted data.
std::vector<unsigned char> value;
value.resize(value_len);
- if (key.ReadValue(reg_iterator.Name(), &value.front(), &value_len)) {
+ if (key.ReadValue(reg_iterator.Name(), &value.front(), &value_len,
+ NULL)) {
IE7PasswordInfo password_info;
password_info.url_hash = reg_iterator.Name();
password_info.encrypted_data = value;
@@ -329,7 +335,7 @@ void IEImporter::ImportHistory() {
}
if (!rows.empty() && !cancelled()) {
- bridge_->SetHistoryItems(rows);
+ bridge_->SetHistoryItems(rows, history::SOURCE_IE_IMPORTED);
}
}
}
@@ -461,7 +467,8 @@ bool IEImporter::GetFavoritesInfo(IEImporter::FavoritesInfo *info) {
// The Link folder name is stored in the registry.
DWORD buffer_length = sizeof(buffer);
RegKey reg_key(HKEY_CURRENT_USER,
- L"Software\\Microsoft\\Internet Explorer\\Toolbar");
+ L"Software\\Microsoft\\Internet Explorer\\Toolbar",
+ KEY_READ);
if (!reg_key.ReadValue(L"LinksFolderName", buffer, &buffer_length, NULL))
return false;
info->links_folder = buffer;
@@ -570,7 +577,7 @@ int IEImporter::CurrentIEVersion() const {
wchar_t buffer[128];
DWORD buffer_length = sizeof(buffer);
RegKey reg_key(HKEY_LOCAL_MACHINE,
- L"Software\\Microsoft\\Internet Explorer");
+ L"Software\\Microsoft\\Internet Explorer", KEY_READ);
bool result = reg_key.ReadValue(L"Version", buffer, &buffer_length, NULL);
version = (result ? _wtoi(buffer) : 0);
}
diff --git a/chrome/browser/importer/ie_importer.h b/chrome/browser/importer/ie_importer.h
index d93405c..1acd27b 100644
--- a/chrome/browser/importer/ie_importer.h
+++ b/chrome/browser/importer/ie_importer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_IE_IMPORTER_H_
#define CHROME_BROWSER_IMPORTER_IE_IMPORTER_H_
+#pragma once
#include "base/gtest_prod_util.h"
#include "chrome/browser/importer/importer.h"
diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc
index 62376c3..2ca7425 100644
--- a/chrome/browser/importer/importer.cc
+++ b/chrome/browser/importer/importer.cc
@@ -6,14 +6,18 @@
#include "app/l10n_util.h"
#include "base/thread.h"
+#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/browsing_instance.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/importer/firefox_profile_lock.h"
#include "chrome/browser/importer/importer_bridge.h"
#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/notification_service.h"
#include "gfx/codec/png_codec.h"
@@ -100,9 +104,7 @@ void ImporterHost::Loaded(BookmarkModel* model) {
waiting_for_bookmarkbar_model_ = false;
installed_bookmark_observer_ = false;
- std::vector<GURL> starred_urls;
- model->GetBookmarks(&starred_urls);
- importer_->set_import_to_bookmark_bar(starred_urls.size() == 0);
+ importer_->set_import_to_bookmark_bar(!model->HasBookmarks());
InvokeTaskIfDone();
}
@@ -123,7 +125,7 @@ void ImporterHost::ShowWarningDialog() {
OnLockViewEnd(false);
} else {
#if defined(OS_WIN)
- views::Window::CreateChromeWindow(GetActiveWindow(), gfx::Rect(),
+ views::Window::CreateChromeWindow(NULL, gfx::Rect(),
new ImporterLockView(this))->Show();
#elif defined(TOOLKIT_USES_GTK)
ImportLockDialogGtk::Show(parent_window_, this);
@@ -202,7 +204,8 @@ void ImporterHost::StartImportSettings(
SiteInstance* site = instance->GetSiteInstanceForURL(url);
Browser* browser = BrowserList::GetLastActive();
browser->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, site, std::string());
+ TabStripModel::ADD_SELECTED, site, std::string(),
+ NULL);
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
this, &ImporterHost::OnLockViewEnd, false));
@@ -258,9 +261,7 @@ void ImporterHost::ImportEnded() {
bool ImporterHost::ShouldImportToBookmarkBar(bool first_run) {
bool import_to_bookmark_bar = first_run;
if (profile_ && profile_->GetBookmarkModel()->IsLoaded()) {
- std::vector<GURL> starred_urls;
- profile_->GetBookmarkModel()->GetBookmarks(&starred_urls);
- import_to_bookmark_bar = (starred_urls.size() == 0);
+ import_to_bookmark_bar = (!profile_->GetBookmarkModel()->HasBookmarks());
}
return import_to_bookmark_bar;
}
@@ -275,8 +276,7 @@ void ImporterHost::CheckForFirefoxLock(
// If fail to acquire the lock, we set the source unreadable and
// show a warning dialog, unless running without UI.
is_source_readable_ = false;
- if (!this->headless_)
- ShowWarningDialog();
+ ShowWarningDialog();
}
}
}
@@ -304,7 +304,9 @@ void ImporterHost::CheckForLoadedModels(uint16 items) {
}
ExternalProcessImporterHost::ExternalProcessImporterHost()
- : cancelled_(false),
+ : items_(0),
+ import_to_bookmark_bar_(false),
+ cancelled_(false),
import_process_launched_(false) {
}
@@ -314,12 +316,10 @@ void ExternalProcessImporterHost::Loaded(BookmarkModel* model) {
waiting_for_bookmarkbar_model_ = false;
installed_bookmark_observer_ = false;
- std::vector<GURL> starred_urls;
- model->GetBookmarks(&starred_urls);
// Because the import process is running externally, the decision whether
// to import to the bookmark bar must be stored here so that it can be
// passed to the importer when the import task is invoked.
- import_to_bookmark_bar_ = (starred_urls.size() == 0);
+ import_to_bookmark_bar_ = (!model->HasBookmarks());
InvokeTaskIfDone();
}
@@ -375,7 +375,12 @@ ExternalProcessImporterClient::ExternalProcessImporterClient(
int items,
InProcessImporterBridge* bridge,
bool import_to_bookmark_bar)
- : process_importer_host_(importer_host),
+ : bookmarks_options_(0),
+ total_bookmarks_count_(0),
+ total_history_rows_count_(0),
+ total_fav_icons_count_(0),
+ process_importer_host_(importer_host),
+ profile_import_process_host_(NULL),
profile_info_(profile_info),
items_(items),
import_to_bookmark_bar_(import_to_bookmark_bar),
@@ -496,14 +501,16 @@ void ExternalProcessImporterClient::OnHistoryImportStart(
}
void ExternalProcessImporterClient::OnHistoryImportGroup(
- const std::vector<history::URLRow> &history_rows_group) {
+ const std::vector<history::URLRow>& history_rows_group,
+ int visit_source) {
if (cancelled_)
return;
history_rows_.insert(history_rows_.end(), history_rows_group.begin(),
history_rows_group.end());
if (history_rows_.size() == total_history_rows_count_)
- bridge_->SetHistoryItems(history_rows_);
+ bridge_->SetHistoryItems(history_rows_,
+ static_cast<history::VisitSource>(visit_source));
}
void ExternalProcessImporterClient::OnHomePageImportReady(
diff --git a/chrome/browser/importer/importer.h b/chrome/browser/importer/importer.h
index eec498b..14be8c2 100644
--- a/chrome/browser/importer/importer.h
+++ b/chrome/browser/importer/importer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_H_
#define CHROME_BROWSER_IMPORTER_IMPORTER_H_
+#pragma once
#include <string>
#include <vector>
@@ -13,16 +14,14 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
-#include "base/time.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/importer/importer_list.h"
#include "chrome/browser/importer/profile_writer.h"
#include "chrome/browser/profile_import_process_host.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/native_widget_types.h"
-#include "googleurl/src/gurl.h"
using importer::ImportItem;
using importer::ProfileInfo;
@@ -30,6 +29,7 @@ using importer::ProfileInfo;
class ExternalProcessImporterClient;
class ImporterBridge;
class InProcessImporterBridge;
+class GURL;
class Profile;
class Task;
class TemplateURL;
@@ -345,8 +345,10 @@ class ExternalProcessImporterClient
virtual void OnHistoryImportStart(size_t total_history_rows_count);
// Called when a group of URLRows has been received.
+ // The source is passed with history::VisitSource type.
virtual void OnHistoryImportGroup(
- const std::vector<history::URLRow> &history_rows_group);
+ const std::vector<history::URLRow> &history_rows_group,
+ int visit_source);
// Called when the home page has been received.
virtual void OnHomePageImportReady(const GURL& home_page);
diff --git a/chrome/browser/importer/importer_bridge.cc b/chrome/browser/importer/importer_bridge.cc
index 72a73a6..079ebe3 100644
--- a/chrome/browser/importer/importer_bridge.cc
+++ b/chrome/browser/importer/importer_bridge.cc
@@ -6,6 +6,9 @@
#include "app/l10n_util.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_types.h"
@@ -58,10 +61,12 @@ void InProcessImporterBridge::SetFavIcons(
}
void InProcessImporterBridge::SetHistoryItems(
- const std::vector<history::URLRow> &rows) {
+ const std::vector<history::URLRow> &rows,
+ history::VisitSource visit_source) {
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(writer_, &ProfileWriter::AddHistoryPage, rows));
+ NewRunnableMethod(writer_, &ProfileWriter::AddHistoryPage,
+ rows, visit_source));
}
void InProcessImporterBridge::SetKeywords(
@@ -147,8 +152,9 @@ void ExternalProcessImporterBridge::SetFavIcons(
}
void ExternalProcessImporterBridge::SetHistoryItems(
- const std::vector<history::URLRow> &rows) {
- profile_import_thread_->NotifyHistoryImportReady(rows);
+ const std::vector<history::URLRow> &rows,
+ history::VisitSource visit_source) {
+ profile_import_thread_->NotifyHistoryImportReady(rows, visit_source);
}
void ExternalProcessImporterBridge::SetKeywords(
@@ -181,10 +187,10 @@ void ExternalProcessImporterBridge::NotifyEnded() {
// The internal process detects import end when all items have been received.
}
+// TODO(viettrungluu): convert to string16.
std::wstring ExternalProcessImporterBridge::GetLocalizedString(
int message_id) {
- std::wstring message;
- localized_strings_->GetString(IntToWString(message_id), &message);
- return message;
+ string16 message;
+ localized_strings_->GetString(base::IntToString(message_id), &message);
+ return UTF16ToWideHack(message);
}
-
diff --git a/chrome/browser/importer/importer_bridge.h b/chrome/browser/importer/importer_bridge.h
index 993ec54..8b57ab0 100644
--- a/chrome/browser/importer/importer_bridge.h
+++ b/chrome/browser/importer/importer_bridge.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_BRIDGE_H_
#define CHROME_BROWSER_IMPORTER_IMPORTER_BRIDGE_H_
+#pragma once
#include "build/build_config.h"
@@ -12,7 +13,6 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
-#include "base/string16.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/importer/importer_data_types.h"
// TODO: remove this, see friend declaration in ImporterBridge.
@@ -38,7 +38,8 @@ class ImporterBridge : public base::RefCountedThreadSafe<ImporterBridge> {
virtual void SetFavIcons(
const std::vector<history::ImportedFavIconUsage>& fav_icons) = 0;
- virtual void SetHistoryItems(const std::vector<history::URLRow> &rows) = 0;
+ virtual void SetHistoryItems(const std::vector<history::URLRow> &rows,
+ history::VisitSource visit_source) = 0;
virtual void SetKeywords(const std::vector<TemplateURL*> &template_urls,
int default_keyword_index,
bool unique_on_host_and_path) = 0;
@@ -95,7 +96,8 @@ class InProcessImporterBridge : public ImporterBridge {
virtual void SetFavIcons(
const std::vector<history::ImportedFavIconUsage>& fav_icons);
- virtual void SetHistoryItems(const std::vector<history::URLRow> &rows);
+ virtual void SetHistoryItems(const std::vector<history::URLRow> &rows,
+ history::VisitSource visit_source);
virtual void SetKeywords(const std::vector<TemplateURL*>& template_urls,
int default_keyword_index,
bool unique_on_host_and_path);
@@ -140,7 +142,8 @@ class ExternalProcessImporterBridge : public ImporterBridge {
virtual void SetFavIcons(
const std::vector<history::ImportedFavIconUsage>& fav_icons);
- virtual void SetHistoryItems(const std::vector<history::URLRow> &rows);
+ virtual void SetHistoryItems(const std::vector<history::URLRow> &rows,
+ history::VisitSource visit_source);
virtual void SetKeywords(const std::vector<TemplateURL*>& template_urls,
int default_keyword_index,
bool unique_on_host_and_path);
diff --git a/chrome/browser/importer/importer_data_types.h b/chrome/browser/importer/importer_data_types.h
index 444cc45..e4af8fb 100644
--- a/chrome/browser/importer/importer_data_types.h
+++ b/chrome/browser/importer/importer_data_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_DATA_TYPES_H_
#define CHROME_BROWSER_IMPORTER_IMPORTER_DATA_TYPES_H_
+#pragma once
#include <string>
@@ -34,7 +35,7 @@ enum ProfileType {
MS_IE = 0,
#endif
FIREFOX2 = 1,
- FIREFOX3 = 2,
+ FIREFOX3 = 2, // Firefox 3 and later.
#if defined(OS_MACOSX)
SAFARI = 3,
#endif
diff --git a/chrome/browser/importer/importer_list.cc b/chrome/browser/importer/importer_list.cc
index 0919489..ba2bf83 100644
--- a/chrome/browser/importer/importer_list.cc
+++ b/chrome/browser/importer/importer_list.cc
@@ -9,7 +9,7 @@
#include "base/stl_util-inl.h"
#include "base/values.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/first_run.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/importer/firefox2_importer.h"
#include "chrome/browser/importer/firefox3_importer.h"
#include "chrome/browser/importer/firefox_importer_utils.h"
@@ -19,7 +19,6 @@
#include "grit/generated_resources.h"
#if defined(OS_WIN)
-#include "app/win_util.h"
#include "chrome/browser/importer/ie_importer.h"
#include "chrome/browser/password_manager/ie7_password.h"
#endif
@@ -130,12 +129,12 @@ void ImporterList::DetectFirefoxProfiles() {
#if defined(OS_WIN)
version = GetCurrentFirefoxMajorVersionFromRegistry();
#endif
- if (version != 2 && version != 3)
+ if (version < 2)
GetFirefoxVersionAndPathFromProfile(profile_path, &version, &app_path);
if (version == 2) {
firefox_type = importer::FIREFOX2;
- } else if (version == 3) {
+ } else if (version >= 3) {
firefox_type = importer::FIREFOX3;
} else {
// Ignores other versions of firefox.
diff --git a/chrome/browser/importer/importer_list.h b/chrome/browser/importer/importer_list.h
index c76aab3..6f98046 100644
--- a/chrome/browser/importer/importer_list.h
+++ b/chrome/browser/importer/importer_list.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_LIST_H_
#define CHROME_BROWSER_IMPORTER_IMPORTER_LIST_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/importer/importer_messages.h b/chrome/browser/importer/importer_messages.h
index 4bbba62..fd7b1dc 100644
--- a/chrome/browser/importer/importer_messages.h
+++ b/chrome/browser/importer/importer_messages.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_IMPORTER_MESSAGES_H_
#define CHROME_BROWSER_IMPORTER_IMPORTER_MESSAGES_H_
+#pragma once
#include <string>
#include <vector>
@@ -49,18 +50,18 @@ struct ParamTraits<importer::ProfileInfo> {
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.description, l);
- l->append(L", ");
+ l->append(", ");
LogParam(static_cast<int>(p.browser_type), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.source_path, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.app_path, l);
- l->append(L", ");
+ l->append(", ");
LogParam(static_cast<int>(p.services_supported), l);
- l->append(L")");
+ l->append(")");
}
}; // ParamTraits<importer::ProfileInfo>
@@ -104,24 +105,24 @@ struct ParamTraits<history::URLRow> {
p->set_favicon_id(favicon_id);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.id(), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.url(), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.title(), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.visit_count(), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.typed_count(), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.last_visit(), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.hidden(), l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.favicon_id(), l);
- l->append(L")");
+ l->append(")");
}
}; // ParamTraits<history::URLRow>
@@ -144,18 +145,18 @@ struct ParamTraits<ProfileWriter::BookmarkEntry> {
(ReadParam(m, iter, &p->title)) &&
(ReadParam(m, iter, &p->creation_time));
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.in_toolbar, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.url, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.path, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.title, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.creation_time, l);
- l->append(L")");
+ l->append(")");
}
}; // ParamTraits<ProfileWriter::BookmarkEntry>
@@ -174,14 +175,14 @@ struct ParamTraits<history::ImportedFavIconUsage> {
ReadParam(m, iter, &p->png_data) &&
ReadParam(m, iter, &p->urls);
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.favicon_url, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.png_data, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.urls, l);
- l->append(L")");
+ l->append(")");
}
}; // ParamTraits<history::ImportedFavIconUsage
@@ -205,8 +206,8 @@ struct ParamTraits<TemplateURLRef> {
*p = TemplateURLRef(url, index_offset, page_offset);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<TemplateURLRef>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<TemplateURLRef>");
}
};
@@ -233,8 +234,8 @@ struct ParamTraits<TemplateURL::ImageRef> {
*p = TemplateURL::ImageRef(type, width, height, url); // here in
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<TemplateURL::ImageRef>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<TemplateURL::ImageRef>");
}
};
@@ -355,8 +356,8 @@ struct ParamTraits<TemplateURL> {
p->set_prepopulate_id(prepopulate_id);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<TemplateURL>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<TemplateURL>");
}
};
diff --git a/chrome/browser/importer/importer_messages_internal.h b/chrome/browser/importer/importer_messages_internal.h
index b247237..980e397 100644
--- a/chrome/browser/importer/importer_messages_internal.h
+++ b/chrome/browser/importer/importer_messages_internal.h
@@ -49,8 +49,10 @@ IPC_BEGIN_MESSAGES(ProfileImportProcessHost)
IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHistoryImportStart,
int /* total number of history::URLRow items */)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHistoryImportGroup,
- std::vector<history::URLRow>)
+ 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_CONTROL1(ProfileImportProcessHostMsg_NotifyHomePageImportReady,
GURL /* GURL of home page */)
diff --git a/chrome/browser/importer/importer_unittest.cc b/chrome/browser/importer/importer_unittest.cc
index 1dce41e..879d7cb 100644
--- a/chrome/browser/importer/importer_unittest.cc
+++ b/chrome/browser/importer/importer_unittest.cc
@@ -21,7 +21,9 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/importer/importer.h"
@@ -257,12 +259,15 @@ class TestObserver : public ProfileWriter,
++password_count_;
}
- virtual void AddHistoryPage(const std::vector<history::URLRow>& page) {
+ virtual void AddHistoryPage(const std::vector<history::URLRow>& page,
+ history::VisitSource visit_source) {
// Importer should read the specified URL.
- for (size_t i = 0; i < page.size(); ++i)
+ for (size_t i = 0; i < page.size(); ++i) {
if (page[i].title() == kIEIdentifyTitle &&
page[i].url() == GURL(kIEIdentifyUrl))
++history_count_;
+ }
+ EXPECT_EQ(history::SOURCE_IE_IMPORTED, visit_source);
}
virtual void AddBookmarkEntry(const std::vector<BookmarkEntry>& bookmark,
@@ -608,10 +613,12 @@ class FirefoxObserver : public ProfileWriter,
++password_count_;
}
- virtual void AddHistoryPage(const std::vector<history::URLRow>& page) {
+ virtual void AddHistoryPage(const std::vector<history::URLRow>& page,
+ history::VisitSource visit_source) {
ASSERT_EQ(1U, page.size());
EXPECT_EQ("http://en-us.www.mozilla.com/", page[0].url().spec());
EXPECT_EQ(ASCIIToUTF16("Firefox Updated"), page[0].title());
+ EXPECT_EQ(history::SOURCE_FIREFOX_IMPORTED, visit_source);
++history_count_;
}
@@ -804,7 +811,8 @@ class Firefox3Observer : public ProfileWriter,
++password_count_;
}
- virtual void AddHistoryPage(const std::vector<history::URLRow>& page) {
+ virtual void AddHistoryPage(const std::vector<history::URLRow>& page,
+ history::VisitSource visit_source) {
ASSERT_EQ(3U, page.size());
EXPECT_EQ("http://www.google.com/", page[0].url().spec());
EXPECT_EQ(ASCIIToUTF16("Google"), page[0].title());
@@ -813,6 +821,7 @@ class Firefox3Observer : public ProfileWriter,
EXPECT_EQ("http://www.cs.unc.edu/~jbs/resources/perl/perl-cgi/programs/form1-POST.html",
page[2].url().spec());
EXPECT_EQ(ASCIIToUTF16("example form (POST)"), page[2].title());
+ EXPECT_EQ(history::SOURCE_FIREFOX_IMPORTED, visit_source);
++history_count_;
}
diff --git a/chrome/browser/importer/mork_reader.cc b/chrome/browser/importer/mork_reader.cc
index 49dadb0..ce1ffe8 100644
--- a/chrome/browser/importer/mork_reader.cc
+++ b/chrome/browser/importer/mork_reader.cc
@@ -48,7 +48,9 @@
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/values.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/importer/firefox_importer_utils.h"
#include "chrome/browser/importer/importer.h"
@@ -530,9 +532,10 @@ void AddToHistory(MorkReader::ColumnDataList* column_values,
count = 1;
row.set_visit_count(count);
- time_t date = StringToInt64(values[kLastVisitColumn]);
+ int64 date;
+ base::StringToInt64(values[kLastVisitColumn], &date);
if (date != 0)
- row.set_last_visit(Time::FromTimeT(date/1000000));
+ row.set_last_visit(Time::FromTimeT(date / 1000000));
bool is_typed = (values[kTypedColumn] == "1");
if (is_typed)
@@ -581,5 +584,5 @@ void ImportHistoryFromFirefox2(const FilePath& file, ImporterBridge* bridge) {
for (MorkReader::iterator i = reader.begin(); i != reader.end(); ++i)
AddToHistory(i->second, data, &rows);
if (!rows.empty())
- bridge->SetHistoryItems(rows);
+ bridge->SetHistoryItems(rows, history::SOURCE_FIREFOX_IMPORTED);
}
diff --git a/chrome/browser/importer/mork_reader.h b/chrome/browser/importer/mork_reader.h
index cb61be5..6f7f8ca 100644
--- a/chrome/browser/importer/mork_reader.h
+++ b/chrome/browser/importer/mork_reader.h
@@ -41,6 +41,7 @@
#ifndef CHROME_BROWSER_IMPORTER_MORK_READER_H__
#define CHROME_BROWSER_IMPORTER_MORK_READER_H__
+#pragma once
#include <iosfwd>
#include <fstream>
diff --git a/chrome/browser/importer/nss_decryptor.cc b/chrome/browser/importer/nss_decryptor.cc
index 91149e2..98522c6 100644
--- a/chrome/browser/importer/nss_decryptor.cc
+++ b/chrome/browser/importer/nss_decryptor.cc
@@ -17,6 +17,7 @@
#endif // defined(USE_NSS)
#include "base/base64.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "webkit/glue/password_form.h"
diff --git a/chrome/browser/importer/nss_decryptor.h b/chrome/browser/importer/nss_decryptor.h
index c133665..8361d17 100644
--- a/chrome/browser/importer/nss_decryptor.h
+++ b/chrome/browser/importer/nss_decryptor.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_H_
#define CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_H_
+#pragma once
#include "build/build_config.h"
diff --git a/chrome/browser/importer/nss_decryptor_mac.h b/chrome/browser/importer/nss_decryptor_mac.h
index af1b004..5e0eeff 100644
--- a/chrome/browser/importer/nss_decryptor_mac.h
+++ b/chrome/browser/importer/nss_decryptor_mac.h
@@ -1,16 +1,18 @@
-// 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.
#ifndef CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_MAC_H_
#define CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_MAC_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/logging.h"
+#include "base/string16.h"
+
+class FilePath;
// The following declarations of functions and types are from Firefox
// NSS library.
diff --git a/chrome/browser/importer/nss_decryptor_mac.mm b/chrome/browser/importer/nss_decryptor_mac.mm
index e319c74..988ab56 100644
--- a/chrome/browser/importer/nss_decryptor_mac.mm
+++ b/chrome/browser/importer/nss_decryptor_mac.mm
@@ -6,13 +6,13 @@
#include <dlfcn.h>
+#include "base/file_path.h"
+#include "base/logging.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/importer/nss_decryptor_mac.h"
#include "chrome/browser/importer/firefox_importer_utils.h"
-#include "base/logging.h"
-
// static
const wchar_t NSSDecryptor::kNSS3Library[] = L"libnss3.dylib";
diff --git a/chrome/browser/importer/nss_decryptor_system_nss.h b/chrome/browser/importer/nss_decryptor_system_nss.h
index 7071428..c08496d 100644
--- a/chrome/browser/importer/nss_decryptor_system_nss.h
+++ b/chrome/browser/importer/nss_decryptor_system_nss.h
@@ -1,16 +1,19 @@
-// 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.
#ifndef CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_SYSTEM_NSS_H_
#define CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_SYSTEM_NSS_H_
+#pragma once
#include <secmodt.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
+#include "base/string16.h"
+
+class FilePath;
namespace webkit_glue {
struct PasswordForm;
diff --git a/chrome/browser/importer/nss_decryptor_win.h b/chrome/browser/importer/nss_decryptor_win.h
index f0b2345..0436323 100644
--- a/chrome/browser/importer/nss_decryptor_win.h
+++ b/chrome/browser/importer/nss_decryptor_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_WIN_H_
#define CHROME_BROWSER_IMPORTER_NSS_DECRYPTOR_WIN_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/importer/profile_writer.cc b/chrome/browser/importer/profile_writer.cc
index 0061efc..93d6248 100644
--- a/chrome/browser/importer/profile_writer.cc
+++ b/chrome/browser/importer/profile_writer.cc
@@ -6,11 +6,13 @@
#include "base/string_util.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.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/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -35,9 +37,10 @@ void ProfileWriter::AddIE7PasswordInfo(const IE7PasswordInfo& info) {
}
#endif
-void ProfileWriter::AddHistoryPage(const std::vector<history::URLRow>& page) {
+void ProfileWriter::AddHistoryPage(const std::vector<history::URLRow>& page,
+ history::VisitSource visit_source) {
profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->
- AddPagesWithDetails(page);
+ AddPagesWithDetails(page, visit_source);
}
void ProfileWriter::AddHomepage(const GURL& home_page) {
@@ -99,18 +102,19 @@ void ProfileWriter::AddBookmarkEntry(
const BookmarkNode* node = parent->GetChild(index);
if ((node->type() == BookmarkNode::BOOKMARK_BAR ||
node->type() == BookmarkNode::FOLDER) &&
- node->GetTitle() == folder_name) {
+ node->GetTitle() == WideToUTF16Hack(folder_name)) {
child = node;
break;
}
}
if (child == NULL)
- child = model->AddGroup(parent, parent->GetChildCount(), folder_name);
+ child = model->AddGroup(parent, parent->GetChildCount(),
+ WideToUTF16Hack(folder_name));
parent = child;
}
groups_added_to.insert(parent);
model->AddURLWithCreationTime(parent, parent->GetChildCount(),
- it->title, it->url, it->creation_time);
+ WideToUTF16Hack(it->title), it->url, it->creation_time);
// If some items are put into toolbar, it looks like the user was using
// it in their last browser. We turn on the bookmarks toolbar.
@@ -283,7 +287,7 @@ std::wstring ProfileWriter::GenerateUniqueFolderName(
for (int i = 0, child_count = other->GetChildCount(); i < child_count; ++i) {
const BookmarkNode* node = other->GetChild(i);
if (node->is_folder())
- other_folder_names.insert(node->GetTitle());
+ other_folder_names.insert(UTF16ToWideHack(node->GetTitle()));
}
if (other_folder_names.find(folder_name) == other_folder_names.end())
@@ -311,7 +315,7 @@ bool ProfileWriter::DoesBookmarkExist(
for (size_t i = 0; i < nodes_with_same_url.size(); ++i) {
const BookmarkNode* node = nodes_with_same_url[i];
- if (entry.title != node->GetTitle())
+ if (WideToUTF16Hack(entry.title) != node->GetTitle())
continue;
// Does the path match?
diff --git a/chrome/browser/importer/profile_writer.h b/chrome/browser/importer/profile_writer.h
index 38e04d8..a8571cb 100644
--- a/chrome/browser/importer/profile_writer.h
+++ b/chrome/browser/importer/profile_writer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_PROFILE_WRITER_H_
#define CHROME_BROWSER_IMPORTER_PROFILE_WRITER_H_
+#pragma once
#include <string>
#include <vector>
@@ -11,6 +12,7 @@
#include "base/ref_counted.h"
#include "base/time.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
+#include "chrome/browser/history/history_types.h"
#include "googleurl/src/gurl.h"
class Profile;
@@ -71,7 +73,8 @@ class ProfileWriter : public base::RefCountedThreadSafe<ProfileWriter> {
#if defined(OS_WIN)
virtual void AddIE7PasswordInfo(const IE7PasswordInfo& info);
#endif
- virtual void AddHistoryPage(const std::vector<history::URLRow>& page);
+ virtual void AddHistoryPage(const std::vector<history::URLRow>& page,
+ history::VisitSource visit_source);
virtual void AddHomepage(const GURL& homepage);
// Adds the bookmarks to the BookmarkModel.
// |options| is a bitmask of BookmarkOptions and dictates how and
diff --git a/chrome/browser/importer/safari_importer.h b/chrome/browser/importer/safari_importer.h
index 6b686e9..e723146 100644
--- a/chrome/browser/importer/safari_importer.h
+++ b/chrome/browser/importer/safari_importer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IMPORTER_SAFARI_IMPORTER_H_
#define CHROME_BROWSER_IMPORTER_SAFARI_IMPORTER_H_
+#pragma once
#include "chrome/browser/importer/importer.h"
diff --git a/chrome/browser/importer/safari_importer.mm b/chrome/browser/importer/safari_importer.mm
index 9a30073..3ff4676 100644
--- a/chrome/browser/importer/safari_importer.mm
+++ b/chrome/browser/importer/safari_importer.mm
@@ -15,6 +15,7 @@
#include "base/string16.h"
#include "base/sys_string_conversions.h"
#include "base/time.h"
+#include "base/values.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/importer/importer_bridge.h"
#include "chrome/browser/importer/importer_data_types.h"
@@ -316,7 +317,7 @@ void SafariImporter::ImportHistory() {
ParseHistoryItems(&rows);
if (!rows.empty() && !cancelled()) {
- bridge_->SetHistoryItems(rows);
+ bridge_->SetHistoryItems(rows, history::SOURCE_SAFARI_IMPORTED);
}
}
diff --git a/chrome/browser/importer/safari_importer_unittest.mm b/chrome/browser/importer/safari_importer_unittest.mm
index 081c26e..36f233a 100644
--- a/chrome/browser/importer/safari_importer_unittest.mm
+++ b/chrome/browser/importer/safari_importer_unittest.mm
@@ -10,6 +10,7 @@
#include "base/path_service.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/file_test_utils.h"
diff --git a/chrome/browser/importer/toolbar_importer.cc b/chrome/browser/importer/toolbar_importer.cc
index 5b0a93c..ad9ad61 100644
--- a/chrome/browser/importer/toolbar_importer.cc
+++ b/chrome/browser/importer/toolbar_importer.cc
@@ -7,9 +7,13 @@
#include <limits>
#include "base/rand_util.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/first_run.h"
+#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"
@@ -231,7 +235,7 @@ void Toolbar5Importer::GetAuthenticationFromServer() {
// Random number construction.
int random = base::RandInt(0, std::numeric_limits<int>::max());
- std::string random_string = UintToString(random);
+ std::string random_string = base::UintToString(random);
// Retrieve authorization token from the network.
std::string url_string(kT5AuthorizationTokenUrl);
@@ -264,7 +268,7 @@ void Toolbar5Importer::GetBookmarkDataFromServer(const std::string& response) {
// the xml blob. We must tag the connection string with a random number.
std::string conn_string = kT5FrontEndUrlTemplate;
int random = base::RandInt(0, std::numeric_limits<int>::max());
- std::string random_string = UintToString(random);
+ std::string random_string = base::UintToString(random);
conn_string.replace(conn_string.find(kRandomNumberToken),
arraysize(kRandomNumberToken) - 1,
random_string);
@@ -520,7 +524,7 @@ bool Toolbar5Importer::ExtractTimeFromXmlReader(
return false;
}
int64 timestamp;
- if (!StringToInt64(buffer, &timestamp)) {
+ if (!base::StringToInt64(buffer, &timestamp)) {
return false;
}
entry->creation_time = base::Time::FromTimeT(timestamp);
diff --git a/chrome/browser/importer/toolbar_importer.h b/chrome/browser/importer/toolbar_importer.h
index 0f31832..1def25d 100644
--- a/chrome/browser/importer/toolbar_importer.h
+++ b/chrome/browser/importer/toolbar_importer.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_H_
#define CHROME_BROWSER_IMPORTER_TOOLBAR_IMPORTER_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/importer/toolbar_importer_unittest.cc b/chrome/browser/importer/toolbar_importer_unittest.cc
index 0bc6ab5..6b042de 100644
--- a/chrome/browser/importer/toolbar_importer_unittest.cc
+++ b/chrome/browser/importer/toolbar_importer_unittest.cc
@@ -8,7 +8,9 @@
#include <vector>
#include "base/string16.h"
-#include "chrome/browser/first_run.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/importer/toolbar_importer.h"
#include "chrome/common/libxml_utils.h"
@@ -318,7 +320,7 @@ static const char* kBadBookmarkNoLabels =
// Test doesn't work if the importer thinks this is the first run of Chromium.
// Mark this as a subsequent run of the browser.
- FirstRun::CreateSentinel();
+ FirstRun::first_run_ = FirstRun::FIRST_RUN_FALSE;
// Test case 1 is parsing a basic bookmark with a single label.
bookmark_xml = kGoodBookmark;
diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
index 6ed0680..eb696ac 100644
--- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
+++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
@@ -7,13 +7,17 @@
#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/indexed_db_key_utility_client.h"
+#include "chrome/common/indexed_db_key.h"
+#include "chrome/common/serialized_script_value.h"
#include "third_party/WebKit/WebKit/chromium/public/WebData.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSerializedScriptValue.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "webkit/glue/webkit_glue.h"
BrowserWebKitClientImpl::BrowserWebKitClientImpl() {
- file_system_.set_sandbox_enabled(false);
+ file_utilities_.set_sandbox_enabled(false);
}
WebKit::WebClipboard* BrowserWebKitClientImpl::clipboard() {
@@ -26,8 +30,8 @@ WebKit::WebMimeRegistry* BrowserWebKitClientImpl::mimeRegistry() {
return NULL;
}
-WebKit::WebFileSystem* BrowserWebKitClientImpl::fileSystem() {
- return &file_system_;
+WebKit::WebFileUtilities* BrowserWebKitClientImpl::fileUtilities() {
+ return &file_utilities_;
}
WebKit::WebSandboxSupport* BrowserWebKitClientImpl::sandboxSupport() {
@@ -90,7 +94,8 @@ WebKit::WebURLLoader* BrowserWebKitClientImpl::createURLLoader() {
return NULL;
}
-WebKit::WebSocketStreamHandle* BrowserWebKitClientImpl::createSocketStreamHandle() {
+WebKit::WebSocketStreamHandle*
+ BrowserWebKitClientImpl::createSocketStreamHandle() {
NOTREACHED();
return NULL;
}
@@ -138,3 +143,28 @@ int BrowserWebKitClientImpl::databaseDeleteFile(
const FilePath path = webkit_glue::WebStringToFilePath(vfs_file_name);
return file_util::Delete(path, false) ? 0 : 1;
}
+
+void BrowserWebKitClientImpl::createIDBKeysFromSerializedValuesAndKeyPath(
+ const WebKit::WebVector<WebKit::WebSerializedScriptValue>& values,
+ const WebKit::WebString& keyPath,
+ WebKit::WebVector<WebKit::WebIDBKey>& keys) {
+ // TODO(bulach): we need to figure out a way to keep the utility process
+ // running for longer, and shut it down when no longer used.
+ scoped_refptr<IndexedDBKeyUtilityClient> indexed_db_key_utility_client =
+ new IndexedDBKeyUtilityClient();
+ indexed_db_key_utility_client->StartUtilityProcess();
+
+ std::vector<SerializedScriptValue> std_values;
+ size_t size = values.size();
+ std_values.reserve(size);
+ for (size_t i = 0; i < size; ++i)
+ std_values.push_back(SerializedScriptValue(values[i]));
+
+ std::vector<IndexedDBKey> std_keys;
+ indexed_db_key_utility_client->CreateIDBKeysFromSerializedValuesAndKeyPath(
+ std_values, keyPath, &std_keys);
+
+ indexed_db_key_utility_client->EndUtilityProcess();
+
+ keys = std_keys;
+}
diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
index bbd6018..dd291c8 100644
--- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
+++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.h
@@ -1,11 +1,12 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_BROWSER_WEBKITCLIENT_IMPL_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_BROWSER_WEBKITCLIENT_IMPL_H_
+#pragma once
-#include "webkit/glue/webfilesystem_impl.h"
+#include "webkit/glue/webfileutilities_impl.h"
#include "webkit/glue/webkitclient_impl.h"
class BrowserWebKitClientImpl : public webkit_glue::WebKitClientImpl {
@@ -15,7 +16,7 @@ class BrowserWebKitClientImpl : public webkit_glue::WebKitClientImpl {
// WebKitClient methods:
virtual WebKit::WebClipboard* clipboard();
virtual WebKit::WebMimeRegistry* mimeRegistry();
- virtual WebKit::WebFileSystem* fileSystem();
+ virtual WebKit::WebFileUtilities* fileUtilities();
virtual WebKit::WebSandboxSupport* sandboxSupport();
virtual bool sandboxEnabled();
virtual unsigned long long visitedLinkHash(const char* canonicalURL,
@@ -44,9 +45,13 @@ class BrowserWebKitClientImpl : public webkit_glue::WebKitClientImpl {
virtual WebKit::WebSharedWorkerRepository* sharedWorkerRepository();
virtual int databaseDeleteFile(const WebKit::WebString& vfs_file_name,
bool sync_dir);
+ virtual void createIDBKeysFromSerializedValuesAndKeyPath(
+ const WebKit::WebVector<WebKit::WebSerializedScriptValue>& values,
+ const WebKit::WebString& keyPath,
+ WebKit::WebVector<WebKit::WebIDBKey>& keys);
private:
- webkit_glue::WebFileSystemImpl file_system_;
+ webkit_glue::WebFileUtilitiesImpl file_utilities_;
};
#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_BROWSER_WEBKITCLIENT_IMPL_H_
diff --git a/chrome/browser/in_process_webkit/dom_storage_area.cc b/chrome/browser/in_process_webkit/dom_storage_area.cc
index 6aefa21..d16e99a 100644
--- a/chrome/browser/in_process_webkit/dom_storage_area.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_area.cc
@@ -4,14 +4,11 @@
#include "chrome/browser/in_process_webkit/dom_storage_area.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
#include "base/task.h"
#include "chrome/browser/chrome_thread.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/in_process_webkit/dom_storage_permission_request.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/common/render_messages.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
@@ -99,19 +96,6 @@ bool DOMStorageArea::CheckContentSetting(
DOMStorageDispatcherHost* sender) {
ContentSetting content_setting =
host_content_settings_map_->GetContentSetting(
- origin_url_, CONTENT_SETTINGS_TYPE_COOKIES);
-
- if (content_setting == CONTENT_SETTING_ASK) {
- DOMStoragePermissionRequest request(origin_url_, key, value,
- host_content_settings_map_);
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableFunction(&DOMStoragePermissionRequest::PromptUser,
- &request));
- // Tell the renderer that it needs to run a nested message loop.
- sender->Send(new ViewMsg_SignalCookiePromptEvent());
- content_setting = request.WaitOnResponse();
- }
-
+ origin_url_, CONTENT_SETTINGS_TYPE_COOKIES, "");
return (content_setting != CONTENT_SETTING_BLOCK);
}
diff --git a/chrome/browser/in_process_webkit/dom_storage_area.h b/chrome/browser/in_process_webkit/dom_storage_area.h
index f14033a..7740bb9 100644
--- a/chrome/browser/in_process_webkit/dom_storage_area.h
+++ b/chrome/browser/in_process_webkit/dom_storage_area.h
@@ -4,13 +4,13 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_AREA_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_AREA_H_
-
-#include <string>
+#pragma once
#include "base/hash_tables.h"
#include "base/nullable_string16.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "chrome/common/dom_storage_common.h"
#include "googleurl/src/gurl.h"
#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h"
@@ -46,6 +46,8 @@ class DOMStorageArea {
int64 id() const { return id_; }
+ DOMStorageNamespace* owner() const { return owner_; }
+
private:
// Creates the underlying WebStorageArea on demand.
void CreateWebStorageAreaIfNecessary();
diff --git a/chrome/browser/in_process_webkit/dom_storage_context.cc b/chrome/browser/in_process_webkit/dom_storage_context.cc
index a4cba5f..e13e203 100644
--- a/chrome/browser/in_process_webkit/dom_storage_context.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_context.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/in_process_webkit/dom_storage_context.h"
+#include <algorithm>
+
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/string_util.h"
@@ -156,7 +158,8 @@ void DOMStorageContext::PurgeMemory() {
void DOMStorageContext::DeleteDataModifiedSince(
const base::Time& cutoff,
- const char* url_scheme_to_be_skipped) {
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins) {
// Make sure that we don't delete a database that's currently being accessed
// by unloading all of the databases temporarily.
PurgeMemory();
@@ -171,6 +174,13 @@ void DOMStorageContext::DeleteDataModifiedSince(
webkit_glue::FilePathToWebString(path.BaseName()));
if (EqualsASCII(web_security_origin.protocol(), url_scheme_to_be_skipped))
continue;
+
+ std::vector<string16>::const_iterator find_iter =
+ std::find(protected_origins.begin(), protected_origins.end(),
+ web_security_origin.databaseIdentifier());
+ if (find_iter != protected_origins.end())
+ continue;
+
file_util::FileEnumerator::FindInfo find_info;
file_enumerator.GetFindInfo(&find_info);
if (file_util::HasFileBeenModifiedSince(find_info, cutoff))
@@ -185,7 +195,7 @@ void DOMStorageContext::DeleteLocalStorageFile(const FilePath& file_path) {
// by unloading all of the databases temporarily.
// TODO(bulach): both this method and DeleteDataModifiedSince could purge
// only the memory used by the specific file instead of all memory at once.
- // See http://code.google.com/p/chromium/issues/detail?id=32000
+ // See http://crbug.com/32000
PurgeMemory();
file_util::Delete(file_path, false);
}
diff --git a/chrome/browser/in_process_webkit/dom_storage_context.h b/chrome/browser/in_process_webkit/dom_storage_context.h
index 2b9e1d1..1552a91 100644
--- a/chrome/browser/in_process_webkit/dom_storage_context.h
+++ b/chrome/browser/in_process_webkit/dom_storage_context.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
+#pragma once
#include <map>
#include <set>
@@ -66,7 +67,8 @@ class DOMStorageContext {
// Delete any local storage files that have been touched since the cutoff
// date that's supplied.
void DeleteDataModifiedSince(const base::Time& cutoff,
- const char* url_scheme_to_be_skipped);
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins);
// Deletes a single local storage file.
void DeleteLocalStorageFile(const FilePath& file_path);
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
index dd01f79..17e99c4 100644
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
@@ -14,6 +14,7 @@
#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;
@@ -47,7 +48,8 @@ DOMStorageDispatcherHost::DOMStorageDispatcherHost(
WebKitContext* webkit_context)
: webkit_context_(webkit_context),
resource_message_filter_(resource_message_filter),
- process_handle_(0) {
+ process_handle_(0),
+ process_id_(0) {
DCHECK(webkit_context_.get());
DCHECK(resource_message_filter_);
}
@@ -268,7 +270,8 @@ void DOMStorageDispatcherHost::OnSetItem(
CallRenderViewHostContentSettingsDelegate(
process_id_, reply_msg->routing_id(),
&RenderViewHostDelegate::ContentSettings::OnLocalStorageAccessed,
- url, result == WebStorageArea::ResultBlockedByPolicy);
+ url, storage_area->owner()->dom_storage_type(),
+ result == WebStorageArea::ResultBlockedByPolicy);
}
ViewHostMsg_DOMStorageSetItem::WriteReplyParams(reply_msg, result, old_value);
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
index dad174e..736e55d 100644
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
+++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
@@ -1,9 +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.
+// Copyright (c) 2010 The Chromium Authors. All rights 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"
@@ -28,7 +29,7 @@ class DOMStorageDispatcherHost
public:
// Only call the constructor from the UI thread.
DOMStorageDispatcherHost(
- ResourceMessageFilter* resource_message_filter_,
+ ResourceMessageFilter* resource_message_filter,
WebKitContext* webkit_context);
// Only call from ResourceMessageFilter on the IO thread.
diff --git a/chrome/browser/in_process_webkit/dom_storage_namespace.h b/chrome/browser/in_process_webkit/dom_storage_namespace.h
index b7f10e0..be38e34 100644
--- a/chrome/browser/in_process_webkit/dom_storage_namespace.h
+++ b/chrome/browser/in_process_webkit/dom_storage_namespace.h
@@ -1,13 +1,14 @@
-// Copyright (c) 2010 The Chromium 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.
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_NAMESPACE_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_NAMESPACE_H_
+#pragma once
-#include "base/string16.h"
#include "base/hash_tables.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "chrome/common/dom_storage_common.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
diff --git a/chrome/browser/in_process_webkit/dom_storage_permission_request.cc b/chrome/browser/in_process_webkit/dom_storage_permission_request.cc
deleted file mode 100644
index 6bc84a2..0000000
--- a/chrome/browser/in_process_webkit/dom_storage_permission_request.cc
+++ /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.
-
-#include "chrome/browser/in_process_webkit/dom_storage_permission_request.h"
-
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/message_box_handler.h"
-
-DOMStoragePermissionRequest::DOMStoragePermissionRequest(
- const GURL& url,
- const string16& key,
- const string16& value,
- HostContentSettingsMap* settings)
- : url_(url),
- key_(key),
- value_(value),
- event_(true, false), // manual reset, not initially signaled
- host_content_settings_map_(settings) {
-}
-
-ContentSetting DOMStoragePermissionRequest::WaitOnResponse() {
- event_.Wait();
- return response_content_setting_;
-}
-
-// static
-void DOMStoragePermissionRequest::PromptUser(
- DOMStoragePermissionRequest* request) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-
- // Cookie settings may have changed.
- ContentSetting setting =
- request->host_content_settings_map_->GetContentSetting(
- request->url_, CONTENT_SETTINGS_TYPE_COOKIES);
- if (setting != CONTENT_SETTING_ASK) {
- request->SendResponse(setting);
- return;
- }
-
- Browser* browser = BrowserList::GetLastActive();
- if (!browser || !browser->GetSelectedTabContents()) {
- request->SendResponse(CONTENT_SETTING_BLOCK);
- return;
- }
-
- RunLocalStoragePrompt(browser->GetSelectedTabContents(),
- request->host_content_settings_map_, request->url_,
- request->key_, request->value_, request);
-}
-
-void DOMStoragePermissionRequest::AllowSiteData(bool session_expire) {
- SendResponse(CONTENT_SETTING_ALLOW);
-}
-
-void DOMStoragePermissionRequest::BlockSiteData() {
- SendResponse(CONTENT_SETTING_BLOCK);
-}
-
-void DOMStoragePermissionRequest::SendResponse(
- ContentSetting content_setting) {
- response_content_setting_ = content_setting;
- event_.Signal();
-}
diff --git a/chrome/browser/in_process_webkit/dom_storage_permission_request.h b/chrome/browser/in_process_webkit/dom_storage_permission_request.h
deleted file mode 100644
index 48f93c3..0000000
--- a/chrome/browser/in_process_webkit/dom_storage_permission_request.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_IN_PROCESS_WEBKIT_DOM_STORAGE_PERMISSION_REQUEST_H_
-#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_PERMISSION_REQUEST_H_
-
-#include <string>
-
-#include "base/ref_counted.h"
-#include "base/time.h"
-#include "base/waitable_event.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h"
-#include "chrome/common/content_settings.h"
-#include "googleurl/src/gurl.h"
-
-// This class is used to request content setting related permission for local
-// storage. It should only be used for one such event and then discarded.
-class DOMStoragePermissionRequest : public CookiePromptModalDialogDelegate {
- public:
- DOMStoragePermissionRequest(const GURL& url,
- const string16& key,
- const string16& value,
- HostContentSettingsMap* settings);
-
-
- ContentSetting WaitOnResponse();
-
- const GURL& url() const { return url_; }
- const string16& key() const { return key_; }
- const string16& value() const { return value_; }
-
- // Called on the UI thread.
- static void PromptUser(DOMStoragePermissionRequest* request);
-
- // CookiesPromptViewDelegate methods:
- virtual void AllowSiteData(bool session_expire);
- virtual void BlockSiteData();
-
- private:
- void SendResponse(ContentSetting content_setting);
-
- // The URL we need to get permission for.
- const GURL url_;
-
- // The key we're trying to set.
- const string16 key_;
-
- // The value we're trying to set.
- const string16 value_;
-
- // The response to the permission request.
- ContentSetting response_content_setting_;
-
- // One time use. Never reset.
- base::WaitableEvent event_;
-
- scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStoragePermissionRequest);
-};
-
-#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_PERMISSION_REQUEST_H_
diff --git a/chrome/browser/in_process_webkit/dom_storage_uitest.cc b/chrome/browser/in_process_webkit/dom_storage_uitest.cc
index bd8e18d..460d411 100644
--- a/chrome/browser/in_process_webkit/dom_storage_uitest.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_uitest.cc
@@ -132,60 +132,57 @@ TEST_F(DOMStorageTest, SessionStorageLayoutTests) {
class DomStorageEmptyDatabaseTest : public UITest {
protected:
- FilePath storageDir() const {
+ FilePath StorageDir() const {
FilePath storage_dir = user_data_dir();
storage_dir = storage_dir.AppendASCII("Default");
storage_dir = storage_dir.AppendASCII("Local Storage");
return storage_dir;
}
- GURL testUrl() const {
+ bool StorageDirIsEmpty() const {
+ FilePath storage_dir = StorageDir();
+ if (!file_util::DirectoryExists(storage_dir))
+ return true;
+ return file_util::IsDirectoryEmpty(storage_dir);
+ }
+
+ GURL TestUrl() const {
FilePath test_dir = test_data_directory_;
FilePath test_file = test_dir.AppendASCII("dom_storage_empty_db.html");
return net::FilePathToFileURL(test_file);
}
};
-namespace {
-
-bool dirIsEmpty(const FilePath& path) {
- if (!file_util::DirectoryExists(path))
- return true;
- return file_util::CountFilesCreatedAfter(path, base::Time()) == 0;
-}
-
-} // namespace
-
TEST_F(DomStorageEmptyDatabaseTest, EmptyDirAfterClear) {
- NavigateToURL(testUrl());
- ASSERT_TRUE(dirIsEmpty(storageDir()));
+ NavigateToURL(TestUrl());
+ ASSERT_TRUE(StorageDirIsEmpty());
NavigateToURL(GURL("javascript:set()"));
NavigateToURL(GURL("javascript:clear()"));
QuitBrowser();
- EXPECT_TRUE(dirIsEmpty(storageDir()));
+ EXPECT_TRUE(StorageDirIsEmpty());
}
TEST_F(DomStorageEmptyDatabaseTest, EmptyDirAfterGet) {
- NavigateToURL(testUrl());
- ASSERT_TRUE(dirIsEmpty(storageDir()));
+ NavigateToURL(TestUrl());
+ ASSERT_TRUE(StorageDirIsEmpty());
NavigateToURL(GURL("javascript:get()"));
QuitBrowser();
- EXPECT_TRUE(dirIsEmpty(storageDir()));
+ EXPECT_TRUE(StorageDirIsEmpty());
}
TEST_F(DomStorageEmptyDatabaseTest, NonEmptyDirAfterSet) {
- NavigateToURL(testUrl());
- ASSERT_TRUE(dirIsEmpty(storageDir()));
+ NavigateToURL(TestUrl());
+ ASSERT_TRUE(StorageDirIsEmpty());
NavigateToURL(GURL("javascript:set()"));
QuitBrowser();
- EXPECT_FALSE(dirIsEmpty(storageDir()));
+ EXPECT_FALSE(StorageDirIsEmpty());
LaunchBrowserAndServer();
- NavigateToURL(testUrl());
+ NavigateToURL(TestUrl());
NavigateToURL(GURL("javascript:clear()"));
QuitBrowser();
- EXPECT_TRUE(dirIsEmpty(storageDir()));
+ EXPECT_TRUE(StorageDirIsEmpty());
}
diff --git a/chrome/browser/in_process_webkit/indexed_db_callbacks.h b/chrome/browser/in_process_webkit/indexed_db_callbacks.h
index 126a8f6..cc90dd8 100644
--- a/chrome/browser/in_process_webkit/indexed_db_callbacks.h
+++ b/chrome/browser/in_process_webkit/indexed_db_callbacks.h
@@ -4,15 +4,17 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CALLBACKS_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CALLBACKS_H_
+#pragma once
#include "base/basictypes.h"
-#include "base/logging.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 "third_party/WebKit/WebKit/chromium/public/WebIDBCallbacks.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBCursor.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBTransactionCallbacks.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBDatabaseError.h"
// Template magic to figure out what message to send to the renderer based on
@@ -72,6 +74,31 @@ class IndexedDBCallbacks : public IndexedDBCallbacksBase {
DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
};
+// WebIDBCursor uses onSuccess(WebIDBCursor*) to indicate it has data, and
+// onSuccess() without params to indicate it does not contain any data, i.e.,
+// there is no key within the key range, or it has reached the end.
+template <>
+class IndexedDBCallbacks<WebKit::WebIDBCursor>
+ : public IndexedDBCallbacksBase {
+ public:
+ IndexedDBCallbacks(
+ IndexedDBDispatcherHost* dispatcher_host, int32 response_id)
+ : IndexedDBCallbacksBase(dispatcher_host, response_id) { }
+
+ virtual void onSuccess(WebKit::WebIDBCursor* idb_object) {
+ int32 object_id = dispatcher_host()->Add(idb_object);
+ dispatcher_host()->Send(
+ new ViewMsg_IDBCallbackSuccessOpenCursor(response_id(), object_id));
+ }
+
+ virtual void onSuccess() {
+ dispatcher_host()->Send(new ViewMsg_IDBCallbacksSuccessNull(response_id()));
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
+};
+
// WebIDBKey is implemented in WebKit as opposed to being an interface Chromium
// implements. Thus we pass a const ___& version and thus we need this
// specialization.
@@ -131,5 +158,26 @@ class IndexedDBCallbacks<void> : public IndexedDBCallbacksBase {
DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
};
-#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CALLBACKS_H_
+class IndexedDBTransactionCallbacks
+ : public WebKit::WebIDBTransactionCallbacks {
+ public:
+ IndexedDBTransactionCallbacks(
+ IndexedDBDispatcherHost* dispatcher_host, int transaction_id)
+ : dispatcher_host_(dispatcher_host), transaction_id_(transaction_id) {
+ }
+
+ virtual void onAbort() {
+ dispatcher_host_->Send(new ViewMsg_IDBTransactionCallbacksAbort(
+ transaction_id_));
+ }
+ virtual int id() const {
+ return transaction_id_;
+ }
+
+ private:
+ scoped_refptr<IndexedDBDispatcherHost> dispatcher_host_;
+ int transaction_id_;
+};
+
+#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CALLBACKS_H_
diff --git a/chrome/browser/in_process_webkit/indexed_db_context.cc b/chrome/browser/in_process_webkit/indexed_db_context.cc
index 6235833..b057861 100644
--- a/chrome/browser/in_process_webkit/indexed_db_context.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_context.cc
@@ -4,21 +4,75 @@
#include "chrome/browser/in_process_webkit/indexed_db_context.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "googleurl/src/url_util.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/WebIndexedDatabase.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBFactory.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::WebIDBDatabase;
-using WebKit::WebIndexedDatabase;
+using WebKit::WebIDBFactory;
+using WebKit::WebSecurityOrigin;
-IndexedDBContext::IndexedDBContext() {
+const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] =
+ FILE_PATH_LITERAL("IndexedDB");
+
+const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] =
+ FILE_PATH_LITERAL(".indexeddb");
+
+IndexedDBContext::IndexedDBContext(WebKitContext* webkit_context)
+ : webkit_context_(webkit_context) {
}
IndexedDBContext::~IndexedDBContext() {
}
-WebIndexedDatabase* IndexedDBContext::GetIndexedDatabase() {
- if (!indexed_database_.get())
- indexed_database_.reset(WebIndexedDatabase::create());
- DCHECK(indexed_database_.get());
- return indexed_database_.get();
+WebIDBFactory* IndexedDBContext::GetIDBFactory() {
+ if (!idb_factory_.get())
+ idb_factory_.reset(WebIDBFactory::create());
+ DCHECK(idb_factory_.get());
+ return idb_factory_.get();
+}
+
+FilePath IndexedDBContext::GetIndexedDBFilePath(
+ const string16& database_name,
+ const WebSecurityOrigin& origin) const {
+ FilePath storage_dir = webkit_context_->data_path().Append(
+ kIndexedDBDirectory);
+ FilePath::StringType id = webkit_glue::WebStringToFilePathString(
+ WebIDBFactory::databaseFileName(database_name, origin));
+ return storage_dir.Append(id);
+}
+
+// static
+bool IndexedDBContext::SplitIndexedDBFileName(
+ const FilePath& file_name,
+ std::string* database_name,
+ WebSecurityOrigin* security_origin) {
+ FilePath::StringType base_name =
+ file_name.BaseName().RemoveExtension().value();
+ size_t db_name_separator = base_name.find(FILE_PATH_LITERAL("@"));
+ if (db_name_separator == FilePath::StringType::npos ||
+ db_name_separator == 0) {
+ return false;
+ }
+
+ *security_origin =
+ WebSecurityOrigin::createFromDatabaseIdentifier(
+ webkit_glue::FilePathStringToWebString(
+ base_name.substr(0, db_name_separator)));
+#if defined(OS_POSIX)
+ std::string name = base_name.substr(db_name_separator + 1);
+#elif defined(OS_WIN)
+ std::string name = WideToUTF8(base_name.substr(db_name_separator + 1));
+#endif
+ url_canon::RawCanonOutputT<char16> output;
+ url_util::DecodeURLEscapeSequences(name.c_str(), name.length(), &output);
+ *database_name = UTF16ToUTF8(string16(output.data(), output.length()));
+ return true;
}
diff --git a/chrome/browser/in_process_webkit/indexed_db_context.h b/chrome/browser/in_process_webkit/indexed_db_context.h
index 07edd88..a8519fb 100644
--- a/chrome/browser/in_process_webkit/indexed_db_context.h
+++ b/chrome/browser/in_process_webkit/indexed_db_context.h
@@ -4,26 +4,50 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CONTEXT_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CONTEXT_H_
+#pragma once
#include "base/basictypes.h"
-#include "base/logging.h"
+#include "base/file_path.h"
#include "base/scoped_ptr.h"
+class FilePath;
+class WebKitContext;
+
namespace WebKit {
-class WebIndexedDatabase;
+class WebIDBFactory;
+class WebSecurityOrigin;
}
class IndexedDBContext {
public:
- IndexedDBContext();
+ explicit IndexedDBContext(WebKitContext* webkit_context);
~IndexedDBContext();
- // TODO(jorlow): If this is all this class ever does, then we should kill it
- // and move this variable to WebKitContext.
- WebKit::WebIndexedDatabase* GetIndexedDatabase();
+ WebKit::WebIDBFactory* GetIDBFactory();
+
+ // The indexed db directory.
+ static const FilePath::CharType kIndexedDBDirectory[];
+
+ // The indexed db file extension.
+ static const FilePath::CharType kIndexedDBExtension[];
+
+ // Get the file name of the indexed db file for the given origin and database
+ // name.
+ FilePath GetIndexedDBFilePath(const string16& database_name,
+ const WebKit::WebSecurityOrigin& origin) const;
+
+ // Splits an indexed database file name into a security origin and a
+ // database name.
+ static bool SplitIndexedDBFileName(
+ const FilePath& file_name,
+ std::string* database_name,
+ WebKit::WebSecurityOrigin* security_origin);
private:
- scoped_ptr<WebKit::WebIndexedDatabase> indexed_database_;
+ scoped_ptr<WebKit::WebIDBFactory> idb_factory_;
+
+ // We're owned by this WebKit context.
+ WebKitContext* webkit_context_;
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 f6523a1..626416c 100644
--- a/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc
@@ -5,40 +5,62 @@
#include "chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h"
#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/in_process_webkit/indexed_db_callbacks.h"
+#include "chrome/browser/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/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 "googleurl/src/gurl.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDOMStringList.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBCursor.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBDatabase.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBDatabaseError.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBKeyRange.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBIndex.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBFactory.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBObjectStore.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebIndexedDatabase.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBTransaction.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
+#include "webkit/glue/webkit_glue.h"
using WebKit::WebDOMStringList;
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBCursor;
using WebKit::WebIDBDatabase;
using WebKit::WebIDBDatabaseError;
using WebKit::WebIDBIndex;
using WebKit::WebIDBKey;
+using WebKit::WebIDBKeyRange;
using WebKit::WebIDBObjectStore;
+using WebKit::WebIDBTransaction;
using WebKit::WebSecurityOrigin;
using WebKit::WebSerializedScriptValue;
+using WebKit::WebVector;
IndexedDBDispatcherHost::IndexedDBDispatcherHost(
- IPC::Message::Sender* sender, WebKitContext* webkit_context)
+ IPC::Message::Sender* sender, Profile* profile)
: sender_(sender),
- webkit_context_(webkit_context),
+ webkit_context_(profile->GetWebKitContext()),
+ host_content_settings_map_(profile->GetHostContentSettingsMap()),
ALLOW_THIS_IN_INITIALIZER_LIST(database_dispatcher_host_(
new DatabaseDispatcherHost(this))),
ALLOW_THIS_IN_INITIALIZER_LIST(index_dispatcher_host_(
new IndexDispatcherHost(this))),
ALLOW_THIS_IN_INITIALIZER_LIST(object_store_dispatcher_host_(
new ObjectStoreDispatcherHost(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(cursor_dispatcher_host_(
+ new CursorDispatcherHost(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(transaction_dispatcher_host_(
+ new TransactionDispatcherHost(this))),
process_handle_(0) {
DCHECK(sender_);
DCHECK(webkit_context_.get());
@@ -81,7 +103,14 @@ bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
DCHECK(process_handle_);
switch (message.type()) {
- case ViewHostMsg_IndexedDatabaseOpen::ID:
+ 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_IDBDatabaseDescription::ID:
case ViewHostMsg_IDBDatabaseVersion::ID:
@@ -89,11 +118,18 @@ bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
case ViewHostMsg_IDBDatabaseCreateObjectStore::ID:
case ViewHostMsg_IDBDatabaseObjectStore::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_IDBIndexOpenCursor::ID:
+ case ViewHostMsg_IDBIndexGetObject::ID:
+ case ViewHostMsg_IDBIndexGet::ID:
case ViewHostMsg_IDBObjectStoreName::ID:
case ViewHostMsg_IDBObjectStoreKeyPath::ID:
case ViewHostMsg_IDBObjectStoreIndexNames::ID:
@@ -103,7 +139,12 @@ bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
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_IDBTransactionDestroyed::ID:
+ case ViewHostMsg_IDBTransactionDidCompleteTaskEvents::ID:
+ case ViewHostMsg_IDBTransactionObjectStore::ID:
break;
default:
return false;
@@ -147,14 +188,16 @@ void IndexedDBDispatcherHost::OnMessageReceivedWebKit(
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);
+ 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);
if (!handled) {
handled = true;
DCHECK(msg_is_ok);
IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, msg_is_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IndexedDatabaseOpen,
- OnIndexedDatabaseOpen)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBFactoryOpen,
+ OnIDBFactoryOpen)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
}
@@ -166,6 +209,10 @@ void IndexedDBDispatcherHost::OnMessageReceivedWebKit(
}
}
+int32 IndexedDBDispatcherHost::Add(WebIDBCursor* idb_cursor) {
+ return cursor_dispatcher_host_->map_.Add(idb_cursor);
+}
+
int32 IndexedDBDispatcherHost::Add(WebIDBDatabase* idb_database) {
return database_dispatcher_host_->map_.Add(idb_database);
}
@@ -178,19 +225,52 @@ int32 IndexedDBDispatcherHost::Add(WebIDBObjectStore* idb_object_store) {
return object_store_dispatcher_host_->map_.Add(idb_object_store);
}
-void IndexedDBDispatcherHost::OnIndexedDatabaseOpen(
- const ViewHostMsg_IndexedDatabaseOpen_Params& params) {
- // TODO(jorlow): Check the content settings map and use params.routing_id_
- // if it's necessary to ask the user for permission.
+void IndexedDBDispatcherHost::Add(WebIDBTransaction* idb_transaction) {
+ transaction_dispatcher_host_->map_.AddWithID(
+ idb_transaction, idb_transaction->id());
+}
+
+void IndexedDBDispatcherHost::OnIDBFactoryOpen(
+ const ViewHostMsg_IDBFactoryOpen_Params& params) {
+ FilePath base_path = webkit_context_->data_path();
+ FilePath indexed_db_path;
+ if (!base_path.empty()) {
+ indexed_db_path = base_path.Append(
+ IndexedDBContext::kIndexedDBDirectory);
+ }
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
- Context()->GetIndexedDatabase()->open(
+ GURL host(string16(WebSecurityOrigin::createFromDatabaseIdentifier(
+ params.origin_).toString()));
+
+ ContentSetting content_setting =
+ host_content_settings_map_->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, "");
+
+ CallRenderViewHostContentSettingsDelegate(
+ process_id_, params.routing_id_,
+ &RenderViewHostDelegate::ContentSettings::OnIndexedDBAccessed,
+ host, params.name_, params.description_,
+ content_setting == CONTENT_SETTING_BLOCK);
+
+ if (content_setting == CONTENT_SETTING_BLOCK) {
+ // TODO(jorlow): Change this to the proper error code once we figure out
+ // one.
+ 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));
+ return;
+ }
+
+ Context()->GetIDBFactory()->open(
params.name_, params.description_,
new IndexedDBCallbacks<WebIDBDatabase>(this, params.response_id_),
- WebSecurityOrigin::createFromDatabaseIdentifier(params.origin_), NULL);
+ WebSecurityOrigin::createFromDatabaseIdentifier(params.origin_), NULL,
+ webkit_glue::FilePathToWebString(indexed_db_path));
}
-
//////////////////////////////////////////////////////////////////////
// Helper templates.
//
@@ -262,6 +342,10 @@ bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
OnObjectStore)
IPC_MESSAGE_HANDLER(ViewHostMsg_IDBDatabaseRemoveObjectStore,
OnRemoveObjectStore)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBDatabaseSetVersion,
+ OnSetVersion)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseTransaction,
+ OnTransaction)
IPC_MESSAGE_HANDLER(ViewHostMsg_IDBDatabaseDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -306,7 +390,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnObjectStores(
std::vector<string16> object_stores;
object_stores.reserve(web_object_stores.length());
for (unsigned i = 0; i < web_object_stores.length(); ++i)
- object_stores[i] = web_object_stores.item(i);
+ object_stores.push_back(web_object_stores.item(i));
ViewHostMsg_IDBDatabaseObjectStores::WriteReplyParams(reply_msg,
object_stores);
parent_->Send(reply_msg);
@@ -350,7 +434,44 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnRemoveObjectStore(
if (!idb_database)
return;
idb_database->removeObjectStore(
- name, new IndexedDBCallbacks<WebIDBObjectStore>(parent_, response_id));
+ name, new IndexedDBCallbacks<void>(parent_, response_id));
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetVersion(
+ int32 idb_database_id, int32 response_id, const string16& version) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
+ &map_, idb_database_id, NULL,
+ ViewHostMsg_IDBDatabaseSetVersion::ID);
+ if (!idb_database)
+ return;
+ idb_database->setVersion(
+ version, new IndexedDBCallbacks<void>(parent_, response_id));
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnTransaction(
+ int32 idb_database_id, const std::vector<string16>& names,
+ int32 mode, int32 timeout, IPC::Message* reply_msg) {
+ WebIDBDatabase* database = parent_->GetOrTerminateProcess(
+ &map_, idb_database_id, reply_msg,
+ ViewHostMsg_IDBDatabaseTransaction::ID);
+ if (!database)
+ return;
+
+ WebDOMStringList object_stores;
+ for (std::vector<string16>::const_iterator it = names.begin();
+ it != names.end(); ++it) {
+ object_stores.append(*it);
+ }
+
+ WebIDBTransaction* transaction = database->transaction(
+ object_stores, mode, timeout);
+ transaction->setCallbacks(
+ new IndexedDBTransactionCallbacks(parent_, transaction->id()));
+ parent_->Add(transaction);
+ ViewHostMsg_IDBDatabaseTransaction::WriteReplyParams(
+ reply_msg, transaction->id());
+ parent_->Send(reply_msg);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
@@ -378,8 +499,14 @@ bool IndexedDBDispatcherHost::IndexDispatcherHost::OnMessageReceived(
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(ViewHostMsg_IDBIndexOpenObjectCursor,
+ OnOpenObjectCursor)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBIndexOpenCursor, OnOpenCursor)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBIndexGetObject, OnGetObject)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBIndexGet, OnGet)
IPC_MESSAGE_HANDLER(ViewHostMsg_IDBIndexDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -400,6 +527,12 @@ void IndexedDBDispatcherHost::IndexDispatcherHost::OnName(
&map_, object_id, reply_msg, &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);
+}
+
void IndexedDBDispatcherHost::IndexDispatcherHost::OnKeyPath(
int32 object_id, IPC::Message* reply_msg) {
parent_->SyncGetter<NullableString16, ViewHostMsg_IDBIndexKeyPath>(
@@ -412,6 +545,81 @@ void IndexedDBDispatcherHost::IndexDispatcherHost::OnUnique(
&map_, object_id, reply_msg, &WebIDBIndex::unique);
}
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenObjectCursor(
+ const ViewHostMsg_IDBIndexOpenCursor_Params& params) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, params.idb_index_id_, NULL,
+ ViewHostMsg_IDBIndexOpenObjectCursor::ID);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_,
+ params.transaction_id_, NULL, ViewHostMsg_IDBIndexOpenObjectCursor::ID);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id_));
+ idb_index->openObjectCursor(
+ WebIDBKeyRange(params.left_key_, params.right_key_, params.key_flags_),
+ params.direction_, callbacks.release(), *idb_transaction);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenCursor(
+ const ViewHostMsg_IDBIndexOpenCursor_Params& params) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, params.idb_index_id_, NULL, ViewHostMsg_IDBIndexOpenCursor::ID);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
+ NULL, ViewHostMsg_IDBIndexOpenCursor::ID);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id_));
+ idb_index->openCursor(
+ WebIDBKeyRange(params.left_key_, params.right_key_, params.key_flags_),
+ params.direction_, callbacks.release(), *idb_transaction);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetObject(
+ int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, idb_index_id, NULL, ViewHostMsg_IDBIndexGetObject::ID);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
+ ViewHostMsg_IDBIndexGetObject::ID);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
+ idb_index->getObject(key, callbacks.release(), *idb_transaction);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnGet(
+ int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, idb_index_id, NULL, ViewHostMsg_IDBIndexGet::ID);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
+ ViewHostMsg_IDBIndexGet::ID);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
+ idb_index->get(key, callbacks.release(), *idb_transaction);
+}
+
void IndexedDBDispatcherHost::IndexDispatcherHost::OnDestroyed(
int32 object_id) {
parent_->DestroyObject(&map_, object_id, ViewHostMsg_IDBIndexDestroyed::ID);
@@ -446,6 +654,7 @@ bool IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnMessageReceived(
IPC_MESSAGE_HANDLER(ViewHostMsg_IDBObjectStoreCreateIndex, OnCreateIndex);
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreIndex, OnIndex);
IPC_MESSAGE_HANDLER(ViewHostMsg_IDBObjectStoreRemoveIndex, OnRemoveIndex);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBObjectStoreOpenCursor, OnOpenCursor)
IPC_MESSAGE_HANDLER(ViewHostMsg_IDBObjectStoreDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -484,46 +693,66 @@ void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndexNames(
std::vector<string16> index_names;
index_names.reserve(web_index_names.length());
for (unsigned i = 0; i < web_index_names.length(); ++i)
- index_names[i] = web_index_names.item(i);
+ index_names.push_back(web_index_names.item(i));
ViewHostMsg_IDBObjectStoreIndexNames::WriteReplyParams(reply_msg,
index_names);
parent_->Send(reply_msg);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnGet(
- int idb_object_store_id, int32 response_id, const IndexedDBKey& key) {
+ int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
&map_, idb_object_store_id, NULL, ViewHostMsg_IDBObjectStoreGet::ID);
- if (!idb_object_store)
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
+ ViewHostMsg_IDBObjectStoreGet::ID);
+ if (!idb_transaction || !idb_object_store)
return;
- idb_object_store->get(key, new IndexedDBCallbacks<WebSerializedScriptValue>(
- parent_, response_id));
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
+ idb_object_store->get(key, callbacks.release(), *idb_transaction);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnPut(
- int idb_object_store_id, int32 response_id,
- const SerializedScriptValue& value, const IndexedDBKey& key,
- bool add_only) {
+ const ViewHostMsg_IDBObjectStorePut_Params& params) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, idb_object_store_id, NULL, ViewHostMsg_IDBObjectStorePut::ID);
- if (!idb_object_store)
+ &map_, params.idb_object_store_id_, NULL,
+ ViewHostMsg_IDBObjectStorePut::ID);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
+ NULL, ViewHostMsg_IDBObjectStorePut::ID);
+ if (!idb_transaction || !idb_object_store)
return;
- idb_object_store->put(
- value, key, add_only, new IndexedDBCallbacks<WebIDBKey>(
- parent_, response_id));
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBKey>(parent_, params.response_id_));
+ idb_object_store->put(params.serialized_value_, params.key_, params.add_only_,
+ callbacks.release(), *idb_transaction);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnRemove(
- int idb_object_store_id, int32 response_id, const IndexedDBKey& key) {
+ int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
&map_, idb_object_store_id, NULL, ViewHostMsg_IDBObjectStoreRemove::ID);
- if (!idb_object_store)
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
+ ViewHostMsg_IDBObjectStoreRemove::ID);
+ if (!idb_transaction || !idb_object_store)
return;
- idb_object_store->remove(key, new IndexedDBCallbacks<void>(parent_,
- response_id));
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<void>(parent_, response_id));
+ idb_object_store->remove(key, callbacks.release(), *idb_transaction);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnCreateIndex(
@@ -566,8 +795,232 @@ void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnRemoveIndex(
name, new IndexedDBCallbacks<void>(parent_, response_id));
}
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnOpenCursor(
+ const ViewHostMsg_IDBObjectStoreOpenCursor_Params& params) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &parent_->object_store_dispatcher_host_->map_,
+ params.idb_object_store_id_, NULL,
+ ViewHostMsg_IDBObjectStoreOpenCursor::ID);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
+ NULL, ViewHostMsg_IDBObjectStoreOpenCursor::ID);
+ if (!idb_transaction || !idb_object_store)
+ return;
+
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id_));
+ idb_object_store->openCursor(
+ WebIDBKeyRange(params.left_key_, params.right_key_, params.flags_),
+ params.direction_, callbacks.release(), *idb_transaction);
+}
+
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDestroyed(
int32 object_id) {
parent_->DestroyObject(
&map_, object_id, ViewHostMsg_IDBObjectStoreDestroyed::ID);
}
+
+//////////////////////////////////////////////////////////////////////
+// IndexedDBDispatcherHost::CursorDispatcherHost
+//
+
+IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
+ IndexedDBDispatcherHost* parent)
+ : parent_(parent) {
+}
+
+IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {
+}
+
+bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
+ const IPC::Message& message, bool* msg_is_ok) {
+ 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(ViewHostMsg_IDBCursorUpdate, OnUpdate)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBCursorContinue, OnContinue)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBCursorRemove, OnRemove)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBCursorDestroyed, OnDestroyed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+
+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);
+ if (!idb_cursor)
+ return;
+
+ int direction = idb_cursor->direction();
+ ViewHostMsg_IDBCursorDirection::WriteReplyParams(reply_msg, direction);
+ parent_->Send(reply_msg);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnKey(
+ int32 object_id, IPC::Message* reply_msg) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
+ &map_, object_id, reply_msg,
+ ViewHostMsg_IDBCursorKey::ID);
+ if (!idb_cursor)
+ return;
+
+ IndexedDBKey key(idb_cursor->key());
+ ViewHostMsg_IDBCursorKey::WriteReplyParams(reply_msg, key);
+ parent_->Send(reply_msg);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnValue(
+ int32 object_id, IPC::Message* reply_msg) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
+ &map_, object_id, reply_msg,
+ ViewHostMsg_IDBCursorValue::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);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnUpdate(
+ int32 cursor_id,
+ int32 response_id,
+ const SerializedScriptValue& value) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
+ &map_, cursor_id, NULL, ViewHostMsg_IDBCursorUpdate::ID);
+ if (!idb_cursor)
+ return;
+ idb_cursor->update(
+ value, new IndexedDBCallbacks<void>(parent_, response_id));
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
+ int32 cursor_id,
+ int32 response_id,
+ const IndexedDBKey& key) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
+ &map_, cursor_id, NULL, ViewHostMsg_IDBCursorContinue::ID);
+ if (!idb_cursor)
+ return;
+ idb_cursor->continueFunction(
+ key, new IndexedDBCallbacks<WebIDBCursor>(parent_, response_id));
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnRemove(
+ int32 cursor_id,
+ int32 response_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
+ &map_, cursor_id, NULL, ViewHostMsg_IDBCursorUpdate::ID);
+ if (!idb_cursor)
+ return;
+ idb_cursor->remove(new IndexedDBCallbacks<void>(parent_, response_id));
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
+ int32 object_id) {
+ parent_->DestroyObject(
+ &map_, object_id, ViewHostMsg_IDBCursorDestroyed::ID);
+}
+
+//////////////////////////////////////////////////////////////////////
+// IndexedDBDispatcherHost::TransactionDispatcherHost
+//
+
+IndexedDBDispatcherHost::TransactionDispatcherHost::TransactionDispatcherHost(
+ IndexedDBDispatcherHost* parent)
+ : parent_(parent) {
+}
+
+IndexedDBDispatcherHost::
+ TransactionDispatcherHost::~TransactionDispatcherHost() {
+}
+
+bool IndexedDBDispatcherHost::TransactionDispatcherHost::OnMessageReceived(
+ const IPC::Message& message, bool* msg_is_ok) {
+ 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_IDBTransactionObjectStore,
+ OnObjectStore)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBTransactionDidCompleteTaskEvents,
+ OnDidCompleteTaskEvents)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_IDBTransactionDestroyed, OnDestroyed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+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);
+ if (!idb_transaction)
+ return;
+
+ idb_transaction->abort();
+}
+
+void IndexedDBDispatcherHost::TransactionDispatcherHost::OnObjectStore(
+ int32 transaction_id, const string16& name, IPC::Message* reply_msg) {
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &map_, transaction_id, reply_msg,
+ ViewHostMsg_IDBTransactionObjectStore::ID);
+ if (!idb_transaction)
+ return;
+
+ WebIDBObjectStore* object_store = idb_transaction->objectStore(name);
+ int32 object_id = object_store ? parent_->Add(object_store) : 0;
+ ViewHostMsg_IDBTransactionObjectStore::WriteReplyParams(
+ reply_msg, object_id);
+ parent_->Send(reply_msg);
+}
+
+void IndexedDBDispatcherHost::
+ TransactionDispatcherHost::OnDidCompleteTaskEvents(int transaction_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &map_, transaction_id, 0,
+ ViewHostMsg_IDBTransactionDidCompleteTaskEvents::ID);
+ if (!idb_transaction)
+ return;
+
+ idb_transaction->didCompleteTaskEvents();
+}
+
+void IndexedDBDispatcherHost::TransactionDispatcherHost::OnDestroyed(
+ int32 object_id) {
+ parent_->DestroyObject(
+ &map_, object_id, ViewHostMsg_IDBTransactionDestroyed::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 cc132ae..f048cbe 100644
--- a/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h
+++ b/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_DISPATCHER_HOST_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_DISPATCHER_HOST_H_
+#pragma once
#include "base/basictypes.h"
#include "base/id_map.h"
@@ -12,16 +13,23 @@
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "ipc/ipc_message.h"
+class HostContentSettingsMap;
class IndexedDBKey;
+class Profile;
class SerializedScriptValue;
-struct ViewHostMsg_IndexedDatabaseOpen_Params;
struct ViewHostMsg_IDBDatabaseCreateObjectStore_Params;
+struct ViewHostMsg_IDBFactoryOpen_Params;
+struct ViewHostMsg_IDBIndexOpenCursor_Params;
struct ViewHostMsg_IDBObjectStoreCreateIndex_Params;
+struct ViewHostMsg_IDBObjectStoreOpenCursor_Params;
+struct ViewHostMsg_IDBObjectStorePut_Params;
namespace WebKit {
+class WebIDBCursor;
class WebIDBDatabase;
class WebIDBIndex;
class WebIDBObjectStore;
+class WebIDBTransaction;
}
// Handles all IndexedDB related messages from a particular renderer process.
@@ -29,8 +37,7 @@ class IndexedDBDispatcherHost
: public base::RefCountedThreadSafe<IndexedDBDispatcherHost> {
public:
// Only call the constructor from the UI thread.
- IndexedDBDispatcherHost(IPC::Message::Sender* sender,
- WebKitContext* webkit_context);
+ IndexedDBDispatcherHost(IPC::Message::Sender* sender, Profile* profile);
// Only call from ResourceMessageFilter on the IO thread.
void Init(int process_id, base::ProcessHandle process_handle);
@@ -53,9 +60,11 @@ class IndexedDBDispatcherHost
// The various IndexedDBCallbacks children call these methods to add the
// results into the applicable map. See below for more details.
+ int32 Add(WebKit::WebIDBCursor* idb_cursor);
int32 Add(WebKit::WebIDBDatabase* idb_database);
int32 Add(WebKit::WebIDBIndex* idb_index);
int32 Add(WebKit::WebIDBObjectStore* idb_object_store);
+ void Add(WebKit::WebIDBTransaction* idb_transaction);
private:
friend class base::RefCountedThreadSafe<IndexedDBDispatcherHost>;
@@ -64,7 +73,7 @@ class IndexedDBDispatcherHost
// Message processing. Most of the work is delegated to the dispatcher hosts
// below.
void OnMessageReceivedWebKit(const IPC::Message& message);
- void OnIndexedDatabaseOpen(const ViewHostMsg_IndexedDatabaseOpen_Params& p);
+ void OnIDBFactoryOpen(const ViewHostMsg_IDBFactoryOpen_Params& p);
// Helper templates.
template <class ReturnType>
@@ -99,6 +108,12 @@ class IndexedDBDispatcherHost
IPC::Message* reply_msg);
void OnRemoveObjectStore(int32 idb_database_id, int32 response_id,
const string16& name);
+ void OnSetVersion(int32 idb_database_id,
+ int32 response_id,
+ const string16& version);
+ void OnTransaction(int32 idb_database_id,
+ const std::vector<string16>& names,
+ int32 mode, int32 timeout, IPC::Message* reply_msg);
void OnDestroyed(int32 idb_database_id);
IndexedDBDispatcherHost* parent_;
@@ -114,8 +129,20 @@ class IndexedDBDispatcherHost
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 OnOpenObjectCursor(
+ const ViewHostMsg_IDBIndexOpenCursor_Params& params);
+ void OnOpenCursor(const ViewHostMsg_IDBIndexOpenCursor_Params& params);
+ void OnGetObject(int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id);
+ void OnGet(int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id);
void OnDestroyed(int32 idb_index_id);
IndexedDBDispatcherHost* parent_;
@@ -133,34 +160,89 @@ class IndexedDBDispatcherHost
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 OnGet(int idb_object_store_id, int32 response_id,
- const IndexedDBKey& key);
- void OnPut(int idb_object_store_id, int32 response_id,
- const SerializedScriptValue& value, const IndexedDBKey& key,
- bool add_only);
- void OnRemove(int idb_object_store_id, int32 response_id,
- const IndexedDBKey& key);
+ void OnGet(int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id);
+ void OnPut(const ViewHostMsg_IDBObjectStorePut_Params& params);
+ void OnRemove(int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int transaction_id);
void OnCreateIndex(
const ViewHostMsg_IDBObjectStoreCreateIndex_Params& params);
void OnIndex(int32 idb_object_store_id, const string16& name,
IPC::Message* reply_msg);
void OnRemoveIndex(int32 idb_object_store_id, int32 response_id,
const string16& name);
+ void OnOpenCursor(
+ const ViewHostMsg_IDBObjectStoreOpenCursor_Params& params);
void OnDestroyed(int32 idb_object_store_id);
IndexedDBDispatcherHost* parent_;
IDMap<WebKit::WebIDBObjectStore, IDMapOwnPointer> map_;
};
+
+ class CursorDispatcherHost {
+ public:
+ explicit CursorDispatcherHost(IndexedDBDispatcherHost* parent);
+ ~CursorDispatcherHost();
+
+ 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 OnUpdate(int32 idb_object_store_id,
+ int32 response_id,
+ const SerializedScriptValue& value);
+ void OnContinue(int32 idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key);
+ void OnRemove(int32 idb_object_store_id,
+ int32 response_id);
+ void OnDestroyed(int32 idb_cursor_id);
+
+ IndexedDBDispatcherHost* parent_;
+ IDMap<WebKit::WebIDBCursor, IDMapOwnPointer> map_;
+ };
+
+ class TransactionDispatcherHost {
+ public:
+ explicit TransactionDispatcherHost(IndexedDBDispatcherHost* parent);
+ ~TransactionDispatcherHost();
+
+ bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
+ void Send(IPC::Message* message);
+
+ // TODO: add the rest of the transaction methods.
+ void OnAbort(int32 transaction_id);
+ void OnObjectStore(int32 transaction_id, const string16& name,
+ IPC::Message* reply_msg);
+ void OnDidCompleteTaskEvents(int transaction_id);
+ void OnDestroyed(int32 idb_transaction_id);
+
+ IndexedDBDispatcherHost* parent_;
+ IDMap<WebKit::WebIDBTransaction, IDMapOwnPointer> 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_;
+ // Tells us whether the user wants to allow databases to be opened.
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+
// Only access on WebKit thread.
scoped_ptr<DatabaseDispatcherHost> database_dispatcher_host_;
scoped_ptr<IndexDispatcherHost> index_dispatcher_host_;
scoped_ptr<ObjectStoreDispatcherHost> object_store_dispatcher_host_;
+ 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.
diff --git a/chrome/browser/in_process_webkit/webkit_context.cc b/chrome/browser/in_process_webkit/webkit_context.cc
index a5db03f..598e5aa 100644
--- a/chrome/browser/in_process_webkit/webkit_context.cc
+++ b/chrome/browser/in_process_webkit/webkit_context.cc
@@ -4,15 +4,18 @@
#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "base/command_line.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_switches.h"
WebKitContext::WebKitContext(Profile* profile)
: data_path_(profile->IsOffTheRecord() ? FilePath() : profile->GetPath()),
is_incognito_(profile->IsOffTheRecord()),
ALLOW_THIS_IN_INITIALIZER_LIST(
dom_storage_context_(new DOMStorageContext(this))),
- indexed_db_context_(new IndexedDBContext()) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ indexed_db_context_(new IndexedDBContext(this))) {
}
WebKitContext::~WebKitContext() {
@@ -48,18 +51,19 @@ void WebKitContext::PurgeMemory() {
void WebKitContext::DeleteDataModifiedSince(
const base::Time& cutoff,
- const char* url_scheme_to_be_skipped) {
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins) {
if (!ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)) {
bool result = ChromeThread::PostTask(
ChromeThread::WEBKIT, FROM_HERE,
NewRunnableMethod(this, &WebKitContext::DeleteDataModifiedSince,
- cutoff, url_scheme_to_be_skipped));
+ cutoff, url_scheme_to_be_skipped, protected_origins));
DCHECK(result);
return;
}
- dom_storage_context_->DeleteDataModifiedSince(cutoff,
- url_scheme_to_be_skipped);
+ dom_storage_context_->DeleteDataModifiedSince(
+ cutoff, url_scheme_to_be_skipped, protected_origins);
}
diff --git a/chrome/browser/in_process_webkit/webkit_context.h b/chrome/browser/in_process_webkit/webkit_context.h
index 7f18f88..be20825 100644
--- a/chrome/browser/in_process_webkit/webkit_context.h
+++ b/chrome/browser/in_process_webkit/webkit_context.h
@@ -4,6 +4,9 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_CONTEXT_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_CONTEXT_H_
+#pragma once
+
+#include <vector>
#include "base/file_path.h"
#include "base/ref_counted.h"
@@ -50,10 +53,11 @@ class WebKitContext : public base::RefCountedThreadSafe<WebKitContext> {
// Tell all children (where applicable) to delete any objects that were
// last modified on or after the following time.
void DeleteDataModifiedSince(const base::Time& cutoff,
- const char* url_scheme_to_be_skipped);
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins);
- // Delete the session storage namespace associated with this id. Called from
- // the UI thread.
+ // Delete the session storage namespace associated with this id. Can be
+ // called from any thread.
void DeleteSessionStorageNamespace(int64 session_storage_namespace_id);
private:
diff --git a/chrome/browser/in_process_webkit/webkit_thread.h b/chrome/browser/in_process_webkit/webkit_thread.h
index 2c0a2c2..eeed43c 100644
--- a/chrome/browser/in_process_webkit/webkit_thread.h
+++ b/chrome/browser/in_process_webkit/webkit_thread.h
@@ -4,10 +4,10 @@
#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_THREAD_H_
#define CHROME_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_THREAD_H_
+#pragma once
+#include "base/basictypes.h"
#include "base/lock.h"
-#include "base/logging.h"
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "chrome/browser/chrome_thread.h"
diff --git a/chrome/browser/input_window_dialog.h b/chrome/browser/input_window_dialog.h
index 0a29cda..bb8d575 100644
--- a/chrome/browser/input_window_dialog.h
+++ b/chrome/browser/input_window_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_INPUT_WINDOW_DIALOG_H_
#define CHROME_BROWSER_INPUT_WINDOW_DIALOG_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/input_window_dialog_gtk.cc b/chrome/browser/input_window_dialog_gtk.cc
index 3e61894..136aed1 100644
--- a/chrome/browser/input_window_dialog_gtk.cc
+++ b/chrome/browser/input_window_dialog_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.
@@ -6,37 +6,32 @@
#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 GtkInputWindowDialog : public InputWindowDialog {
+class InputWindowDialogGtk : public InputWindowDialog {
public:
// Creates a dialog. Takes ownership of |delegate|.
- GtkInputWindowDialog(GtkWindow* parent,
+ InputWindowDialogGtk(GtkWindow* parent,
const std::string& window_title,
const std::string& label,
const std::string& contents,
Delegate* delegate);
- virtual ~GtkInputWindowDialog();
+ virtual ~InputWindowDialogGtk();
virtual void Show();
virtual void Close();
private:
- static void OnEntryChanged(GtkEditable* entry,
- GtkInputWindowDialog* window);
-
- static void OnResponse(GtkDialog* dialog, int response_id,
- GtkInputWindowDialog* window);
-
- static gboolean OnWindowDeleteEvent(GtkWidget* widget,
- GdkEvent* event,
- GtkInputWindowDialog* dialog);
-
- static void OnWindowDestroy(GtkWidget* widget, GtkInputWindowDialog* dialog);
+ 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_;
@@ -49,7 +44,7 @@ class GtkInputWindowDialog : public InputWindowDialog {
};
-GtkInputWindowDialog::GtkInputWindowDialog(GtkWindow* parent,
+InputWindowDialogGtk::InputWindowDialogGtk(GtkWindow* parent,
const std::string& window_title,
const std::string& label,
const std::string& contents,
@@ -75,7 +70,7 @@ GtkInputWindowDialog::GtkInputWindowDialog(GtkWindow* parent,
input_ = gtk_entry_new();
gtk_entry_set_text(GTK_ENTRY(input_), contents.c_str());
g_signal_connect(input_, "changed",
- G_CALLBACK(OnEntryChanged), this);
+ 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);
@@ -84,21 +79,21 @@ GtkInputWindowDialog::GtkInputWindowDialog(GtkWindow* parent,
gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, FALSE, 0);
g_signal_connect(dialog_, "response",
- G_CALLBACK(OnResponse), this);
+ G_CALLBACK(OnResponseThunk), this);
g_signal_connect(dialog_, "delete-event",
- G_CALLBACK(OnWindowDeleteEvent), this);
+ G_CALLBACK(OnWindowDeleteEventThunk), this);
g_signal_connect(dialog_, "destroy",
- G_CALLBACK(OnWindowDestroy), this);
+ G_CALLBACK(OnWindowDestroyThunk), this);
}
-GtkInputWindowDialog::~GtkInputWindowDialog() {
+InputWindowDialogGtk::~InputWindowDialogGtk() {
}
-void GtkInputWindowDialog::Show() {
+void InputWindowDialogGtk::Show() {
gtk_util::ShowDialog(dialog_);
}
-void GtkInputWindowDialog::Close() {
+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_) {
@@ -107,35 +102,26 @@ void GtkInputWindowDialog::Close() {
}
}
-// static
-void GtkInputWindowDialog::OnEntryChanged(GtkEditable* entry,
- GtkInputWindowDialog* window) {
+void InputWindowDialogGtk::OnEntryChanged(GtkEditable* entry) {
std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(entry))));
- gtk_dialog_set_response_sensitive(GTK_DIALOG(window->dialog_),
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_),
GTK_RESPONSE_ACCEPT,
- window->delegate_->IsValid(value));
+ delegate_->IsValid(value));
}
-// static
-void GtkInputWindowDialog::OnResponse(GtkDialog* dialog, int response_id,
- GtkInputWindowDialog* window) {
+void InputWindowDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
if (response_id == GTK_RESPONSE_ACCEPT) {
- std::wstring value(UTF8ToWide(gtk_entry_get_text(
- GTK_ENTRY(window->input_))));
- window->delegate_->InputAccepted(value);
+ std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(input_))));
+ delegate_->InputAccepted(value);
} else {
- window->delegate_->InputCanceled();
+ delegate_->InputCanceled();
}
-
- window->Close();
+ Close();
}
-// static
-gboolean GtkInputWindowDialog::OnWindowDeleteEvent(
- GtkWidget* widget,
- GdkEvent* event,
- GtkInputWindowDialog* dialog) {
- dialog->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
@@ -143,19 +129,16 @@ gboolean GtkInputWindowDialog::OnWindowDeleteEvent(
return TRUE;
}
-// static
-void GtkInputWindowDialog::OnWindowDestroy(GtkWidget* widget,
- GtkInputWindowDialog* dialog) {
- MessageLoop::current()->DeleteSoon(FROM_HERE, dialog);
+void InputWindowDialogGtk::OnWindowDestroy(GtkWidget* widget) {
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
-// static
InputWindowDialog* InputWindowDialog::Create(gfx::NativeWindow parent,
const std::wstring& window_title,
const std::wstring& label,
const std::wstring& contents,
Delegate* delegate) {
- return new GtkInputWindowDialog(parent,
+ return new InputWindowDialogGtk(parent,
WideToUTF8(window_title),
WideToUTF8(label),
WideToUTF8(contents),
diff --git a/chrome/browser/input_window_dialog_win.cc b/chrome/browser/input_window_dialog_win.cc
index 2d606df..f8c8d32 100644
--- a/chrome/browser/input_window_dialog_win.cc
+++ b/chrome/browser/input_window_dialog_win.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/input_window_dialog.h"
-#include "app/l10n_util.h"
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/task.h"
diff --git a/chrome/browser/intranet_redirect_detector.cc b/chrome/browser/intranet_redirect_detector.cc
index 16c72de..481e8cf 100644
--- a/chrome/browser/intranet_redirect_detector.cc
+++ b/chrome/browser/intranet_redirect_detector.cc
@@ -4,12 +4,14 @@
#include "chrome/browser/intranet_redirect_detector.h"
+#include "base/command_line.h"
#include "base/rand_util.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "net/base/load_flags.h"
@@ -78,6 +80,10 @@ void IntranetRedirectDetector::StartFetchesIfPossible() {
if (in_sleep_ || !request_context_available_)
return;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableBackgroundNetworking))
+ return;
+
DCHECK(fetchers_.empty() && resulting_origins_.empty());
// Start three fetchers on random hostnames.
diff --git a/chrome/browser/intranet_redirect_detector.h b/chrome/browser/intranet_redirect_detector.h
index cb10265..1861dce 100644
--- a/chrome/browser/intranet_redirect_detector.h
+++ b/chrome/browser/intranet_redirect_detector.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_INTRANET_REDIRECT_DETECTOR_H_
#define CHROME_BROWSER_INTRANET_REDIRECT_DETECTOR_H_
+#pragma once
#include <set>
#include <string>
#include <vector>
#include "chrome/common/net/url_fetcher.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
#include "net/base/host_resolver_proc.h"
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index b0e27b2..42a8a17 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -3,9 +3,13 @@
// found in the LICENSE file.
#include "chrome/browser/io_thread.h"
+
#include "base/command_line.h"
#include "base/leak_tracker.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/gpu_process_host.h"
@@ -21,11 +25,10 @@
#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_auth_handler_negotiate.h"
namespace {
-net::HostResolver* CreateGlobalHostResolver() {
+net::HostResolver* CreateGlobalHostResolver(net::NetLog* net_log) {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
size_t parallelism = net::HostResolver::kDefaultParallelism;
@@ -37,7 +40,7 @@ net::HostResolver* CreateGlobalHostResolver() {
// Parse the switch (it should be a positive integer formatted as decimal).
int n;
- if (StringToInt(s, &n) && n > 0) {
+ if (base::StringToInt(s, &n) && n > 0) {
parallelism = static_cast<size_t>(n);
} else {
LOG(ERROR) << "Invalid switch for host resolver parallelism: " << s;
@@ -45,7 +48,7 @@ net::HostResolver* CreateGlobalHostResolver() {
}
net::HostResolver* global_host_resolver =
- net::CreateSystemHostResolver(parallelism);
+ net::CreateSystemHostResolver(parallelism, net_log);
// Determine if we should disable IPv6 support.
if (!command_line.HasSwitch(switches::kEnableIPv6)) {
@@ -55,26 +58,8 @@ net::HostResolver* CreateGlobalHostResolver() {
net::HostResolverImpl* host_resolver_impl =
global_host_resolver->GetAsHostResolverImpl();
if (host_resolver_impl != NULL) {
- // (optionally) Use probe to decide if support is warranted.
- bool use_ipv6_probe = true;
-
-#if defined(OS_WIN)
- // Measure impact of probing to allow IPv6.
- // Some users report confused OS handling of IPv6, leading to large
- // latency. If we can show that IPv6 is not supported, then disabliing
- // it will work around such problems. This is the test of the probe.
- const FieldTrial::Probability kDivisor = 100;
- const FieldTrial::Probability kProbability = 50; // 50% probability.
- FieldTrial* trial = new FieldTrial("IPv6_Probe", kDivisor);
- int skip_group = trial->AppendGroup("_IPv6_probe_skipped",
- kProbability);
- trial->AppendGroup("_IPv6_probe_done",
- FieldTrial::kAllRemainingProbability);
- use_ipv6_probe = (trial->group() != skip_group);
-#endif
-
- if (use_ipv6_probe)
- host_resolver_impl->ProbeIPv6Support();
+ // Use probe to decide if support is warranted.
+ host_resolver_impl->ProbeIPv6Support();
}
}
}
@@ -108,17 +93,9 @@ class LoggingNetworkChangeObserver
virtual void OnIPAddressChanged() {
LOG(INFO) << "Observed a change to the network IP addresses";
- net::NetLog::Source global_source;
-
- // TODO(eroman): We shouldn't need to assign an ID to this source, since
- // conceptually it is the "global event stream". However
- // currently the javascript does a grouping on source id, so
- // the display will look weird if we don't give it one.
- global_source.id = net_log_->NextID();
-
- net_log_->AddEntry(net::NetLog::TYPE_NETWORK_IP_ADDRESSSES_CHANGED,
+ net_log_->AddEntry(net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED,
base::TimeTicks::Now(),
- global_source,
+ net::NetLog::Source(),
net::NetLog::PHASE_NONE,
NULL);
}
@@ -138,7 +115,6 @@ IOThread::IOThread()
: BrowserProcessSubThread(ChromeThread::IO),
globals_(NULL),
speculative_interceptor_(NULL),
- prefetch_observer_(NULL),
predictor_(NULL) {}
IOThread::~IOThread() {
@@ -193,7 +169,7 @@ void IOThread::Init() {
network_change_observer_.reset(
new LoggingNetworkChangeObserver(globals_->net_log.get()));
- globals_->host_resolver = CreateGlobalHostResolver();
+ globals_->host_resolver = CreateGlobalHostResolver(globals_->net_log.get());
globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
globals_->host_resolver));
}
@@ -222,13 +198,6 @@ void IOThread::CleanUp() {
delete speculative_interceptor_;
speculative_interceptor_ = NULL;
- // Not initialized in Init(). May not be initialized.
- if (prefetch_observer_) {
- globals_->host_resolver->RemoveObserver(prefetch_observer_);
- delete prefetch_observer_;
- prefetch_observer_ = NULL;
- }
-
// TODO(eroman): hack for http://crbug.com/15513
if (globals_->host_resolver->GetAsHostResolverImpl()) {
globals_->host_resolver.get()->GetAsHostResolverImpl()->Shutdown();
@@ -241,9 +210,6 @@ void IOThread::CleanUp() {
delete globals_;
globals_ = NULL;
- // URLRequest instances must NOT outlive the IO thread.
- base::LeakTracker<URLRequest>::CheckForLeaks();
-
BrowserProcessSubThread::CleanUp();
}
@@ -254,67 +220,50 @@ void IOThread::CleanUpAfterMessageLoopDestruction() {
// combine the two cleanups.
deferred_net_log_to_delete_.reset();
BrowserProcessSubThread::CleanUpAfterMessageLoopDestruction();
+
+ // 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::LeakTracker<URLRequest>::CheckForLeaks();
}
net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory(
net::HostResolver* resolver) {
- net::HttpAuthFilterWhitelist* auth_filter = NULL;
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
// Get the whitelist information from the command line, create an
// HttpAuthFilterWhitelist, and attach it to the HttpAuthHandlerFactory.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
+ net::HttpAuthFilterWhitelist* auth_filter_default_credentials = NULL;
if (command_line.HasSwitch(switches::kAuthServerWhitelist)) {
- std::string auth_server_whitelist =
- command_line.GetSwitchValueASCII(switches::kAuthServerWhitelist);
-
- // Create a whitelist filter.
- auth_filter = new net::HttpAuthFilterWhitelist();
- auth_filter->SetWhitelist(auth_server_whitelist);
+ auth_filter_default_credentials = new net::HttpAuthFilterWhitelist(
+ command_line.GetSwitchValueASCII(switches::kAuthServerWhitelist));
}
-
- // Set the flag that enables or disables the Negotiate auth handler.
- static const bool kNegotiateAuthEnabledDefault = true;
-
- bool negotiate_auth_enabled = kNegotiateAuthEnabledDefault;
- if (command_line.HasSwitch(switches::kExperimentalEnableNegotiateAuth)) {
- std::string enable_negotiate_auth = command_line.GetSwitchValueASCII(
- switches::kExperimentalEnableNegotiateAuth);
- // Enabled if no value, or value is 'true'. Disabled otherwise.
- negotiate_auth_enabled =
- enable_negotiate_auth.empty() ||
- (StringToLowerASCII(enable_negotiate_auth) == "true");
+ net::HttpAuthFilterWhitelist* auth_filter_delegate = NULL;
+ if (command_line.HasSwitch(switches::kAuthNegotiateDelegateWhitelist)) {
+ auth_filter_delegate = new net::HttpAuthFilterWhitelist(
+ command_line.GetSwitchValueASCII(
+ switches::kAuthNegotiateDelegateWhitelist));
}
-
- net::HttpAuthHandlerRegistryFactory* registry_factory =
- net::HttpAuthHandlerFactory::CreateDefault();
-
globals_->url_security_manager.reset(
- net::URLSecurityManager::Create(auth_filter));
-
- // Add the security manager to the auth factories that need it.
- registry_factory->SetURLSecurityManager("ntlm",
- globals_->url_security_manager.get());
- registry_factory->SetURLSecurityManager("negotiate",
- globals_->url_security_manager.get());
- if (negotiate_auth_enabled) {
- // Configure the Negotiate settings for the Kerberos SPN.
- // TODO(cbentzel): Read the related IE registry settings on Windows builds.
- // TODO(cbentzel): Ugly use of static_cast here.
- net::HttpAuthHandlerNegotiate::Factory* negotiate_factory =
- static_cast<net::HttpAuthHandlerNegotiate::Factory*>(
- registry_factory->GetSchemeFactory("negotiate"));
- DCHECK(negotiate_factory);
- negotiate_factory->set_host_resolver(resolver);
- if (command_line.HasSwitch(switches::kDisableAuthNegotiateCnameLookup))
- negotiate_factory->set_disable_cname_lookup(true);
- if (command_line.HasSwitch(switches::kEnableAuthNegotiatePort))
- negotiate_factory->set_use_port(true);
- } else {
- // Disable the Negotiate authentication handler.
- registry_factory->RegisterSchemeFactory("negotiate", NULL);
- }
- return registry_factory;
+ net::URLSecurityManager::Create(auth_filter_default_credentials,
+ auth_filter_delegate));
+
+ // Determine which schemes are supported.
+ std::string csv_auth_schemes = "basic,digest,ntlm,negotiate";
+ if (command_line.HasSwitch(switches::kAuthSchemes))
+ csv_auth_schemes = StringToLowerASCII(
+ command_line.GetSwitchValueASCII(switches::kAuthSchemes));
+ std::vector<std::string> supported_schemes;
+ SplitString(csv_auth_schemes, ',', &supported_schemes);
+
+ return net::HttpAuthHandlerRegistryFactory::Create(
+ supported_schemes,
+ globals_->url_security_manager.get(),
+ resolver,
+ command_line.HasSwitch(switches::kDisableAuthNegotiateCnameLookup),
+ command_line.HasSwitch(switches::kEnableAuthNegotiatePort));
}
void IOThread::InitNetworkPredictorOnIOThread(
@@ -336,20 +285,11 @@ void IOThread::InitNetworkPredictorOnIOThread(
preconnect_enabled);
predictor_->AddRef();
- // TODO(jar): Until connection notification and DNS observation handling are
- // properly combined into a learning model, we'll only use one observation
- // mechanism or the other.
- if (preconnect_enabled) {
- DCHECK(!speculative_interceptor_);
- speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor;
- } else {
- DCHECK(!prefetch_observer_);
- prefetch_observer_ = chrome_browser_net::CreateResolverObserver();
- globals_->host_resolver->AddObserver(prefetch_observer_);
- }
+ // Speculative_interceptor_ is used to predict subresource usage.
+ DCHECK(!speculative_interceptor_);
+ speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor;
- FinalizePredictorInitialization(
- predictor_, prefetch_observer_, startup_urls, referral_list);
+ FinalizePredictorInitialization(predictor_, startup_urls, referral_list);
}
void IOThread::ChangedToOnTheRecordOnIOThread() {
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index caa5998..f2f1310 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_IO_THREAD_H_
#define CHROME_BROWSER_IO_THREAD_H_
-
-#include <vector>
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
@@ -111,7 +110,6 @@ class IOThread : public BrowserProcessSubThread {
// these observers would be used accidentally after we have begun to tear
// down.
chrome_browser_net::ConnectInterceptor* speculative_interceptor_;
- net::HostResolver::Observer* prefetch_observer_;
chrome_browser_net::Predictor* predictor_;
DISALLOW_COPY_AND_ASSIGN(IOThread);
diff --git a/chrome/browser/jankometer.h b/chrome/browser/jankometer.h
index fe5d4f6..8d2fccc 100644
--- a/chrome/browser/jankometer.h
+++ b/chrome/browser/jankometer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_JANKOMETER_H_
#define CHROME_BROWSER_JANKOMETER_H_
+#pragma once
class CommandLine;
diff --git a/chrome/browser/js_modal_dialog.cc b/chrome/browser/js_modal_dialog.cc
index 7c42c71..8f79da2 100644
--- a/chrome/browser/js_modal_dialog.cc
+++ b/chrome/browser/js_modal_dialog.cc
@@ -7,6 +7,7 @@
#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"
@@ -30,9 +31,6 @@ JavaScriptAppModalDialog::JavaScriptAppModalDialog(
bool is_before_unload_dialog,
IPC::Message* reply_msg)
: AppModalDialog(client->AsTabContents(), title),
-#if defined(OS_MACOSX)
- dialog_(NULL),
-#endif
client_(client),
extension_host_(client->AsExtensionHost()),
dialog_flags_(dialog_flags),
@@ -52,6 +50,14 @@ JavaScriptAppModalDialog::JavaScriptAppModalDialog(
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) {
@@ -68,7 +74,7 @@ void JavaScriptAppModalDialog::Observe(NotificationType type,
// Also clear the client, since it's now invalid.
skip_this_dialog_ = true;
client_ = NULL;
- if (dialog_)
+ if (native_dialog_)
CloseModalDialog();
}
@@ -144,5 +150,4 @@ void JavaScriptAppModalDialog::Cleanup() {
NOTREACHED();
#endif
}
- AppModalDialog::Cleanup();
}
diff --git a/chrome/browser/js_modal_dialog.h b/chrome/browser/js_modal_dialog.h
index 65ed1ae..b2cccff 100644
--- a/chrome/browser/js_modal_dialog.h
+++ b/chrome/browser/js_modal_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_JS_MODAL_DIALOG_H_
#define CHROME_BROWSER_JS_MODAL_DIALOG_H_
+#pragma once
#include <string>
@@ -11,18 +12,14 @@
#include "chrome/browser/app_modal_dialog.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "net/base/cookie_monster.h"
-
-#if defined(OS_MACOSX)
-#if __OBJC__
-@class NSAlert;
-#else
-class NSAlert;
-#endif
-#endif
class ExtensionHost;
class JavaScriptMessageBoxClient;
+class NativeAppModalDialog;
+
+namespace IPC {
+class Message;
+}
// A controller+model class for JavaScript alert, confirm, prompt, and
// onbeforeunload dialog boxes.
@@ -42,41 +39,27 @@ class JavaScriptAppModalDialog : public AppModalDialog,
virtual ~JavaScriptAppModalDialog();
// AppModalDialog overrides.
-#if defined(OS_POSIX)
- virtual void CreateAndShowDialog();
-#endif
-#if defined(TOOLKIT_USES_GTK)
- virtual void HandleDialogResponse(GtkDialog* dialog, gint response_id);
-#endif
- virtual int GetDialogButtons();
- virtual void AcceptWindow();
- virtual void CancelWindow();
+ virtual NativeAppModalDialog* CreateNativeDialog();
/////////////////////////////////////////////////////////////////////////////
// Getters so NativeDialog can get information about the message box.
- JavaScriptMessageBoxClient* client() {
- return client_;
- }
- int dialog_flags() {
- return dialog_flags_;
- }
- bool is_before_unload_dialog() {
- return is_before_unload_dialog_;
- }
-
-#if defined(OS_MACOSX)
- virtual void CloseModalDialog();
-#endif
+ JavaScriptMessageBoxClient* client() const { return client_; }
// Callbacks from NativeDialog when the user accepts or cancels the dialog.
void OnCancel();
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_; }
+
protected:
// AppModalDialog overrides.
virtual void Cleanup();
- virtual NativeDialog CreateNativeDialog();
private:
// NotificationObserver implementation.
@@ -87,9 +70,7 @@ class JavaScriptAppModalDialog : public AppModalDialog,
// Initializes for notifications to listen.
void InitNotifications();
-#if defined(OS_MACOSX)
- NSAlert* dialog_;
-#endif
+ NativeAppModalDialog* native_dialog_;
NotificationRegistrar registrar_;
diff --git a/chrome/browser/js_modal_dialog_gtk.cc b/chrome/browser/js_modal_dialog_gtk.cc
deleted file mode 100644
index 29111d1..0000000
--- a/chrome/browser/js_modal_dialog_gtk.cc
+++ /dev/null
@@ -1,194 +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/js_modal_dialog.h"
-
-#include <gtk/gtk.h>
-
-#include "app/gtk_util.h"
-#include "app/l10n_util.h"
-#include "app/message_box_flags.h"
-#include "base/logging.h"
-#include "base/utf_string_conversions.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 "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-
-namespace {
-
-// We stash pointers to widgets on the gtk_dialog so we can refer to them
-// after dialog creation.
-const char kPromptTextId[] = "chrome_prompt_text";
-const char kSuppressCheckboxId[] = "chrome_suppress_checkbox";
-
-// If there's a text entry in the dialog, get the text from the first one and
-// return it.
-std::wstring GetPromptText(GtkDialog* dialog) {
- GtkWidget* widget = static_cast<GtkWidget*>(
- g_object_get_data(G_OBJECT(dialog), kPromptTextId));
- if (widget)
- return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(widget)));
- return std::wstring();
-}
-
-// If there's a toggle button in the dialog, return the toggled state.
-// Otherwise, return false.
-bool ShouldSuppressJSDialogs(GtkDialog* dialog) {
- GtkWidget* widget = static_cast<GtkWidget*>(
- g_object_get_data(G_OBJECT(dialog), kSuppressCheckboxId));
- if (widget)
- return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
- return false;
-}
-
-} // namespace
-
-void JavaScriptAppModalDialog::CreateAndShowDialog() {
- dialog_ = CreateNativeDialog();
- gtk_util::ShowModalDialogWithMinLocalizedWidth(GTK_WIDGET(dialog_),
- IDS_ALERT_DIALOG_WIDTH_CHARS);
-}
-
-void JavaScriptAppModalDialog::HandleDialogResponse(GtkDialog* dialog,
- gint 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.
- OnAccept(GetPromptText(dialog), ShouldSuppressJSDialogs(dialog));
- break;
-
- case GTK_RESPONSE_CANCEL:
- case GTK_RESPONSE_DELETE_EVENT: // User hit the X on the dialog.
- OnCancel();
- break;
-
- default:
- NOTREACHED();
- }
- gtk_widget_destroy(GTK_WIDGET(dialog));
-
- // Now that the dialog is gone, we can put all the windows into separate
- // window groups so other dialogs are no longer app modal.
- gtk_util::AppModalDismissedUngroupWindows();
- delete this;
-}
-
-int JavaScriptAppModalDialog::GetDialogButtons() {
- switch (dialog_flags_) {
- case MessageBoxFlags::kIsJavascriptAlert:
- return MessageBoxFlags::DIALOGBUTTON_OK;
-
- case MessageBoxFlags::kIsJavascriptConfirm:
- return MessageBoxFlags::DIALOGBUTTON_OK |
- MessageBoxFlags::DIALOGBUTTON_CANCEL;
-
- case MessageBoxFlags::kIsJavascriptPrompt:
- return MessageBoxFlags::DIALOGBUTTON_OK;
-
- default:
- NOTREACHED();
- return 0;
- }
-}
-
-void JavaScriptAppModalDialog::AcceptWindow() {
- HandleDialogResponse(GTK_DIALOG(dialog_), GTK_RESPONSE_OK);
-}
-
-void JavaScriptAppModalDialog::CancelWindow() {
- HandleDialogResponse(GTK_DIALOG(dialog_), GTK_RESPONSE_CANCEL);
-}
-
-NativeDialog JavaScriptAppModalDialog::CreateNativeDialog() {
- GtkButtonsType buttons = GTK_BUTTONS_NONE;
- GtkMessageType message_type = GTK_MESSAGE_OTHER;
- // We add in the OK button manually later because we want to focus it
- // explicitly.
- switch (dialog_flags_) {
- case MessageBoxFlags::kIsJavascriptAlert:
- buttons = GTK_BUTTONS_NONE;
- message_type = GTK_MESSAGE_WARNING;
- break;
-
- case MessageBoxFlags::kIsJavascriptConfirm:
- if (is_before_unload_dialog_) {
- // onbeforeunload also uses a confirm prompt, it just has custom
- // buttons. We add the buttons using gtk_dialog_add_button below.
- buttons = GTK_BUTTONS_NONE;
- } else {
- buttons = GTK_BUTTONS_CANCEL;
- }
- message_type = GTK_MESSAGE_QUESTION;
- break;
-
- case MessageBoxFlags::kIsJavascriptPrompt:
- buttons = GTK_BUTTONS_CANCEL;
- message_type = GTK_MESSAGE_QUESTION;
- break;
-
- default:
- NOTREACHED();
- }
-
- // We want the alert to be app modal so put all the browser windows into the
- // same window group.
- gtk_util::MakeAppModalWindowGroup();
-
- gfx::NativeWindow window = client_->GetMessageBoxRootWindow();
- NativeDialog dialog = gtk_message_dialog_new(window, GTK_DIALOG_MODAL,
- message_type, buttons, "%s", WideToUTF8(message_text_).c_str());
- gtk_util::ApplyMessageDialogQuirks(dialog);
- gtk_window_set_title(GTK_WINDOW(dialog), WideToUTF8(title_).c_str());
-
- // Adjust content area as needed. Set up the prompt text entry or
- // suppression check box.
- if (MessageBoxFlags::kIsJavascriptPrompt == dialog_flags_) {
- // TODO(tc): Replace with gtk_dialog_get_content_area() when using GTK 2.14+
- GtkWidget* contents_vbox = GTK_DIALOG(dialog)->vbox;
- GtkWidget* text_box = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(text_box),
- WideToUTF8(default_prompt_text_).c_str());
- gtk_box_pack_start(GTK_BOX(contents_vbox), text_box, TRUE, TRUE, 0);
- g_object_set_data(G_OBJECT(dialog), kPromptTextId, text_box);
- gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE);
- }
-
- if (display_suppress_checkbox_) {
- GtkWidget* contents_vbox = GTK_DIALOG(dialog)->vbox;
- GtkWidget* check_box = gtk_check_button_new_with_label(
- l10n_util::GetStringUTF8(
- IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION).c_str());
- gtk_box_pack_start(GTK_BOX(contents_vbox), check_box, TRUE, TRUE, 0);
- g_object_set_data(G_OBJECT(dialog), kSuppressCheckboxId, check_box);
- }
-
- // Adjust buttons/action area as needed.
- if (is_before_unload_dialog_) {
- std::string button_text = l10n_util::GetStringUTF8(
- IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
- gtk_dialog_add_button(GTK_DIALOG(dialog), button_text.c_str(),
- GTK_RESPONSE_OK);
-
- button_text = l10n_util::GetStringUTF8(
- IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL);
- gtk_dialog_add_button(GTK_DIALOG(dialog), button_text.c_str(),
- GTK_RESPONSE_CANCEL);
- } else {
- // Add the OK button and focus it.
- GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_OK, GTK_RESPONSE_OK);
- if (MessageBoxFlags::kIsJavascriptPrompt != dialog_flags_)
- gtk_widget_grab_focus(ok_button);
- }
-
- gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
- g_signal_connect(dialog, "response",
- G_CALLBACK(AppModalDialog::OnDialogResponse),
- reinterpret_cast<AppModalDialog*>(this));
- return dialog;
-}
-
diff --git a/chrome/browser/js_modal_dialog_mac.mm b/chrome/browser/js_modal_dialog_mac.mm
deleted file mode 100644
index ee9f74c..0000000
--- a/chrome/browser/js_modal_dialog_mac.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.
-
-#include "chrome/browser/js_modal_dialog.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/sys_string_conversions.h"
-#import "chrome/browser/chrome_browser_application_mac.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 bridge back to the C++ JavaScriptAppModalDialog. When
-// complete, autorelease to clean ourselves up.
-- (void)alertDidEnd:(NSAlert*)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- JavaScriptAppModalDialog* bridge =
- reinterpret_cast<JavaScriptAppModalDialog*>(contextInfo);
- std::wstring input;
- if (textField_)
- input = base::SysNSStringToWide([textField_ stringValue]);
- switch (returnCode) {
- case NSAlertFirstButtonReturn: { // OK
- bool shouldSuppress = false;
- if ([alert showsSuppressionButton])
- shouldSuppress = [[alert suppressionButton] state] == NSOnState;
- bridge->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 (bridge->is_before_unload_dialog())
- chrome_browser_application_mac::CancelTerminate();
-
- bridge->OnCancel();
- 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.
- bridge->OnCancel();
- break;
- }
- default: {
- NOTREACHED();
- }
- }
- [self autorelease];
- delete bridge; // Done with the dialog, it needs be destroyed.
-}
-@end
-
-void JavaScriptAppModalDialog::CreateAndShowDialog() {
- // 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_flags_) {
- case MessageBoxFlags::kIsJavascriptAlert:
- one_button = true;
- break;
- case MessageBoxFlags::kIsJavascriptConfirm:
- if (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.
- JavaScriptAppModalDialogHelper* helper =
- [[JavaScriptAppModalDialogHelper alloc] init];
-
- // Show the modal dialog.
- NSAlert* alert = [helper alert];
- dialog_ = alert;
- NSTextField* field = nil;
- if (text_field) {
- field = [helper textField];
- [field setStringValue:base::SysWideToNSString(default_prompt_text_)];
- }
- [alert setDelegate:helper];
- [alert setInformativeText:base::SysWideToNSString(message_text_)];
- [alert setMessageText:base::SysWideToNSString(title_)];
- [alert addButtonWithTitle:default_button];
- if (!one_button) {
- NSButton* other = [alert addButtonWithTitle:other_button];
- [other setKeyEquivalent:@"\e"];
- }
- if (display_suppress_checkbox_) {
- [alert setShowsSuppressionButton:YES];
- NSString* suppression_title = l10n_util::GetNSStringWithFixup(
- IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION);
- [[alert suppressionButton] setTitle:suppression_title];
- }
-
- [alert beginSheetModalForWindow:nil // nil here makes it app-modal
- modalDelegate:helper
- didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
- contextInfo:this];
-
- if (field)
- [[alert window] makeFirstResponder:field];
-}
-
-// The functions below are used by the automation framework.
-int JavaScriptAppModalDialog::GetDialogButtons() {
- // 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 = [[dialog_ buttons] count];
- switch (num_buttons) {
- case 1:
- return MessageBoxFlags::DIALOGBUTTON_OK;
- case 2:
- return MessageBoxFlags::DIALOGBUTTON_OK |
- MessageBoxFlags::DIALOGBUTTON_CANCEL;
- default:
- NOTREACHED();
- return 0;
- }
-}
-
-// On Mac, this is only used in testing.
-void JavaScriptAppModalDialog::AcceptWindow() {
- NSButton* first = [[dialog_ buttons] objectAtIndex:0];
- [first performClick:nil];
-}
-
-void JavaScriptAppModalDialog::CancelWindow() {
- DCHECK([[dialog_ buttons] count] >= 2);
- NSButton* second = [[dialog_ buttons] objectAtIndex:1];
- [second performClick:nil];
-}
-
-// This is only used by the app-modal dialog machinery on windows.
-NativeDialog JavaScriptAppModalDialog::CreateNativeDialog() {
- NOTIMPLEMENTED();
- return nil;
-}
-
-void JavaScriptAppModalDialog::CloseModalDialog() {
- NSAlert* alert = dialog_;
- DCHECK([alert isKindOfClass:[NSAlert class]]);
- [NSApp endSheet:[alert window]];
- dialog_ = nil;
-}
diff --git a/chrome/browser/js_modal_dialog_win.cc b/chrome/browser/js_modal_dialog_win.cc
deleted file mode 100644
index 8bb2525..0000000
--- a/chrome/browser/js_modal_dialog_win.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/js_modal_dialog.h"
-
-#include "base/logging.h"
-#include "chrome/browser/views/jsmessage_box_dialog.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "views/window/window.h"
-
-int JavaScriptAppModalDialog::GetDialogButtons() {
- return dialog_->GetDialogButtons();
-}
-
-void JavaScriptAppModalDialog::AcceptWindow() {
- views::DialogClientView* client_view =
- dialog_->window()->GetClientView()->AsDialogClientView();
- client_view->AcceptWindow();
-}
-
-void JavaScriptAppModalDialog::CancelWindow() {
- views::DialogClientView* client_view =
- dialog_->window()->GetClientView()->AsDialogClientView();
- client_view->CancelWindow();
-}
-
-NativeDialog JavaScriptAppModalDialog::CreateNativeDialog() {
- return new JavaScriptMessageBoxDialog(this, message_text_,
- default_prompt_text_, display_suppress_checkbox_);
-}
-
diff --git a/chrome/browser/jsmessage_box_client.h b/chrome/browser/jsmessage_box_client.h
index 86ee442..011a281 100644
--- a/chrome/browser/jsmessage_box_client.h
+++ b/chrome/browser/jsmessage_box_client.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_JSMESSAGE_BOX_CLIENT_H_
#define CHROME_BROWSER_JSMESSAGE_BOX_CLIENT_H_
+#pragma once
// JavaScriptMessageBoxClient
//
@@ -17,7 +18,6 @@
class ExtensionHost;
class GURL;
-class Profile;
class TabContents;
namespace IPC {
class Message;
@@ -27,10 +27,6 @@ class JavaScriptMessageBoxClient {
public:
virtual ~JavaScriptMessageBoxClient() {}
- // Returns the title to use for the message box.
- virtual std::wstring GetMessageBoxTitle(const GURL& frame_url,
- bool is_alert) = 0;
-
// Returns the root native window with which the message box is associated.
virtual gfx::NativeWindow GetMessageBoxRootWindow() = 0;
diff --git a/chrome/browser/jumplist_win.cc b/chrome/browser/jumplist_win.cc
index e77b55c..43b7bfe 100644
--- a/chrome/browser/jumplist_win.cc
+++ b/chrome/browser/jumplist_win.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.
@@ -255,7 +255,7 @@ bool CreateIconFile(const SkBitmap& bitmap,
// Create an icon file from the favicon attached to the given |page|, and
// save it as the temporary file.
- if (!IconUtil::CreateIconFileFromSkBitmap(bitmap, path.value()))
+ if (!IconUtil::CreateIconFileFromSkBitmap(bitmap, path))
return false;
// Add this icon file to the list and return its absolute path.
@@ -359,7 +359,7 @@ HRESULT UpdateTaskCategory(ScopedComPtr<ICustomDestinationList> list,
// this item.
scoped_refptr<ShellLinkItem> incognito(new ShellLinkItem);
incognito->SetArguments(
- CommandLine::PrefixedSwitchString(switches::kIncognito));
+ ASCIIToWide(std::string("--") + switches::kIncognito));
std::wstring incognito_title(l10n_util::GetString(IDS_NEW_INCOGNITO_WINDOW));
ReplaceSubstringsAfterOffset(&incognito_title, 0, L"&", L"");
incognito->SetTitle(incognito_title);
@@ -422,10 +422,10 @@ bool UpdateJumpList(const wchar_t* app_id,
// Retrieve the command-line switches of this process.
CommandLine command_line(CommandLine::ARGUMENTS_ONLY);
- std::wstring user_data_dir = CommandLine::ForCurrentProcess()->
- GetSwitchValue(switches::kUserDataDir);
+ FilePath user_data_dir = CommandLine::ForCurrentProcess()->
+ GetSwitchValuePath(switches::kUserDataDir);
if (!user_data_dir.empty())
- command_line.AppendSwitchWithValue(switches::kUserDataDir, user_data_dir);
+ command_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
std::wstring chrome_switches = command_line.command_line_string();
diff --git a/chrome/browser/jumplist_win.h b/chrome/browser/jumplist_win.h
index c25177f..58146d0 100644
--- a/chrome/browser/jumplist_win.h
+++ b/chrome/browser/jumplist_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_JUMPLIST_WIN_H_
#define CHROME_BROWSER_JUMPLIST_WIN_H_
+#pragma once
#include <list>
#include <string>
@@ -14,6 +15,7 @@
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/sessions/tab_restore_service_observer.h"
class FilePath;
class Profile;
@@ -90,7 +92,7 @@ typedef std::vector<scoped_refptr<ShellLinkItem> > ShellLinkItemList;
// * Creatng COM objects used by JumpList from PageUsageData objects;
// * Adding COM objects to JumpList, etc.
//
-// This class also implements TabRestoreService::Observer. So, once we call
+// This class also implements TabRestoreServiceObserver. So, once we call
// AddObserver() and register this class as an observer, it automatically
// updates a JumpList when a tab is added or removed.
//
@@ -98,7 +100,7 @@ typedef std::vector<scoped_refptr<ShellLinkItem> > ShellLinkItemList;
// update it in a UI thread. To solve this problem, this class posts a
// task when it actually updates a JumpList. (This task is implemented in an
// anomynous namespace in "jumplist_win.cc".)
-class JumpList : public TabRestoreService::Observer {
+class JumpList : public TabRestoreServiceObserver {
public:
JumpList();
~JumpList();
diff --git a/chrome/browser/keychain_mac.h b/chrome/browser/keychain_mac.h
index 1029343..f3c98e0 100644
--- a/chrome/browser/keychain_mac.h
+++ b/chrome/browser/keychain_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_KEYCHAIN_MAC_H_
#define CHROME_BROWSER_KEYCHAIN_MAC_H_
+#pragma once
#include <Security/Security.h>
diff --git a/chrome/browser/keychain_mock_mac.h b/chrome/browser/keychain_mock_mac.h
index 666395e..60c1711 100644
--- a/chrome/browser/keychain_mock_mac.h
+++ b/chrome/browser/keychain_mock_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
#define CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
+#pragma once
#include <set>
#include <string>
diff --git a/chrome/browser/labs.cc b/chrome/browser/labs.cc
new file mode 100644
index 0000000..f1500a7
--- /dev/null
+++ b/chrome/browser/labs.cc
@@ -0,0 +1,270 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/labs.h"
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <set>
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/values.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+
+namespace about_labs {
+
+enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 };
+
+unsigned kOsAll = kOsMac | kOsWin | kOsLinux;
+
+struct Experiment {
+ // 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 labs.
+ const char* internal_name;
+
+ // String id of the message containing the experiment's name.
+ int visible_name_id;
+
+ // String id of the message containing the experiment's description.
+ int visible_description_id;
+
+ // The platforms the experiment is available on
+ // Needs to be more than a compile-time #ifdef because of profile sync.
+ unsigned supported_platforms; // bitmask
+
+ // 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.
+ const char* command_line;
+};
+
+const Experiment kExperiments[] = {
+ {
+ "expose-for-tabs", // Do not change; see above.
+ IDS_LABS_TABPOSE_NAME,
+ IDS_LABS_TABPOSE_DESCRIPTION,
+ kOsMac,
+#if defined(OS_MACOSX)
+ // The switch exists only on OS X.
+ switches::kEnableExposeForTabs
+#else
+ ""
+#endif
+ },
+ {
+ "vertical-tabs", // Do not change; see above.
+ IDS_LABS_SIDE_TABS_NAME,
+ IDS_LABS_SIDE_TABS_DESCRIPTION,
+ kOsWin,
+ switches::kEnableVerticalTabs
+ },
+ {
+ "tabbed-options", // Do not change; see above.
+ IDS_LABS_TABBED_OPTIONS_NAME,
+ IDS_LABS_TABBED_OPTIONS_DESCRIPTION,
+ kOsAll,
+ switches::kEnableTabbedOptions
+ },
+ {
+ "match-preview", // Do not change; see above.
+ IDS_LABS_INSTANT_NAME,
+ IDS_LABS_INSTANT_DESCRIPTION,
+ kOsWin,
+ switches::kEnableMatchPreview
+ },
+ {
+ "remoting", // Do not change; see above.
+ IDS_LABS_REMOTING_NAME,
+#if defined(OS_WIN)
+ // Windows only supports host functionality at the moment.
+ IDS_LABS_REMOTING_HOST_DESCRIPTION,
+#elif defined(OS_LINUX)
+ // Linux only supports client functionality at the moment.
+ IDS_LABS_REMOTING_CLIENT_DESCRIPTION,
+#else
+ // On other platforms, this lab isn't available at all.
+ 0,
+#endif
+ kOsWin | kOsLinux,
+ switches::kEnableRemoting
+ },
+ {
+ "page-info-bubble", // Do not change; see above.
+ IDS_LABS_PAGE_INFO_BUBBLE_NAME,
+ IDS_LABS_PAGE_INFO_BUBBLE_DESCRIPTION,
+ kOsWin | kOsLinux,
+ switches::kEnableNewPageInfoBubble
+ }
+};
+
+// Extracts the list of enabled lab experiments from a profile and stores them
+// in a set.
+void GetEnabledLabs(const PrefService* prefs, std::set<std::string>* result) {
+ const ListValue* enabled_experiments = prefs->GetList(
+ prefs::kEnabledLabsExperiments);
+ if (!enabled_experiments)
+ return;
+
+ for (ListValue::const_iterator it = enabled_experiments->begin();
+ it != enabled_experiments->end();
+ ++it) {
+ std::string experiment_name;
+ if (!(*it)->GetAsString(&experiment_name)) {
+ LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
+ continue;
+ }
+ result->insert(experiment_name);
+ }
+}
+
+// Takes a set of enabled lab experiments
+void SetEnabledLabs(
+ PrefService* prefs, const std::set<std::string>& enabled_experiments) {
+ ListValue* experiments_list = prefs->GetMutableList(
+ prefs::kEnabledLabsExperiments);
+ if (!experiments_list)
+ return;
+
+ experiments_list->Clear();
+ for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
+ it != enabled_experiments.end();
+ ++it) {
+ experiments_list->Append(new StringValue(*it));
+ }
+}
+
+// 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 < arraysize(kExperiments); ++i)
+ known_experiments.insert(kExperiments[i].internal_name);
+
+ std::set<std::string> enabled_experiments;
+ GetEnabledLabs(prefs, &enabled_experiments);
+
+ std::set<std::string> new_enabled_experiments;
+ std::set_intersection(
+ known_experiments.begin(), known_experiments.end(),
+ enabled_experiments.begin(), enabled_experiments.end(),
+ std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
+
+ SetEnabledLabs(prefs, new_enabled_experiments);
+}
+
+void GetSanitizedEnabledLabs(
+ PrefService* prefs, std::set<std::string>* result) {
+ SanitizeList(prefs);
+ GetEnabledLabs(prefs, result);
+}
+
+int GetCurrentPlatform() {
+#if defined(OS_MACOSX)
+ return kOsMac;
+#elif defined(OS_WIN)
+ return kOsWin;
+#elif defined(OS_LINUX)
+ return kOsLinux;
+#else
+#error Unknown platform
+#endif
+}
+
+bool IsEnabled() {
+#if defined(OS_CHROMEOS)
+ // ChromeOS uses a different mechanism for about:labs; integrated with their
+ // dom ui options.
+ return false;
+#elif defined(GOOGLE_CHROME_BUILD)
+ // Don't enable this on the stable channel.
+ return !platform_util::GetVersionStringModifier().empty();
+#else
+ return true;
+#endif
+}
+
+void ConvertLabsToSwitches(Profile* profile, CommandLine* command_line) {
+ // Do not activate labs features on the stable channel.
+ if (!IsEnabled())
+ return;
+
+ std::set<std::string> enabled_experiments;
+ GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);
+
+ std::map<std::string, const Experiment*> experiments;
+ for (size_t i = 0; i < arraysize(kExperiments); ++i)
+ experiments[kExperiments[i].internal_name] = &kExperiments[i];
+
+ for (std::set<std::string>::iterator it = enabled_experiments.begin();
+ it != enabled_experiments.end();
+ ++it) {
+ const std::string& experiment_name = *it;
+ std::map<std::string, const Experiment*>::iterator experiment =
+ experiments.find(experiment_name);
+ DCHECK(experiment != experiments.end());
+ if (experiment == experiments.end())
+ continue;
+
+ command_line->AppendSwitch(experiment->second->command_line);
+ }
+}
+
+ListValue* GetLabsExperimentsData(Profile* profile) {
+ std::set<std::string> enabled_experiments;
+ GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);
+
+ int current_platform = GetCurrentPlatform();
+
+ ListValue* experiments_data = new ListValue();
+ for (size_t i = 0; i < arraysize(kExperiments); ++i) {
+ const Experiment& experiment = kExperiments[i];
+ if (!(experiment.supported_platforms & current_platform))
+ continue;
+
+ DictionaryValue* data = new DictionaryValue();
+ data->SetString("internal_name", experiment.internal_name);
+ data->SetString("name",
+ l10n_util::GetStringUTF16(experiment.visible_name_id));
+ data->SetString("description",
+ l10n_util::GetStringUTF16(
+ experiment.visible_description_id));
+ data->SetBoolean("enabled",
+ enabled_experiments.count(experiment.internal_name) > 0);
+
+ experiments_data->Append(data);
+ }
+ return experiments_data;
+}
+
+static bool needs_restart_ = false;
+
+bool IsRestartNeededToCommitChanges() {
+ return needs_restart_;
+}
+
+void SetExperimentEnabled(
+ Profile* profile, const std::string& internal_name, bool enable) {
+ needs_restart_ = true;
+
+ std::set<std::string> enabled_experiments;
+ GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments);
+
+ if (enable)
+ enabled_experiments.insert(internal_name);
+ else
+ enabled_experiments.erase(internal_name);
+
+ SetEnabledLabs(profile->GetPrefs(), enabled_experiments);
+}
+
+} // namespace Labs
diff --git a/chrome/browser/labs.h b/chrome/browser/labs.h
new file mode 100644
index 0000000..0c61b95
--- /dev/null
+++ b/chrome/browser/labs.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_LABS_H_
+#define CHROME_BROWSER_LABS_H_
+#pragma once
+
+#include <string>
+
+class CommandLine;
+class ListValue;
+class Profile;
+
+// Can't be called "labs", that collides with the C function |labs()|.
+namespace about_labs {
+
+// Returns if Labs is enabled (it isn't on the stable channel).
+bool IsEnabled();
+
+// Reads the Labs pref from |profile| and adds the commandline flags belonging
+// to the active experiments to |command_line|.
+void ConvertLabsToSwitches(Profile* profile, CommandLine* command_line);
+
+// Get a list of all available experiments. The caller owns the result.
+ListValue* GetLabsExperimentsData(Profile* profile);
+
+// Returns true if one of the experiment flags has been flipped since startup.
+bool IsRestartNeededToCommitChanges();
+
+// Enables or disables the experiment with id |internal_name|.
+void SetExperimentEnabled(
+ Profile* profile, const std::string& internal_name, bool enable);
+
+} // namespace Labs
+
+#endif // CHROME_BROWSER_LABS_H_
diff --git a/chrome/browser/language_combobox_model.cc b/chrome/browser/language_combobox_model.cc
index 2d16a73..747862c 100644
--- a/chrome/browser/language_combobox_model.cc
+++ b/chrome/browser/language_combobox_model.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.
@@ -6,10 +6,11 @@
#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
+#include "base/string_split.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "grit/generated_resources.h"
#include "unicode/uloc.h"
@@ -151,6 +152,14 @@ LanguageComboboxModel::LanguageComboboxModel(
profile_(profile) {
}
+int LanguageComboboxModel::GetItemCount() {
+ return get_languages_count();
+}
+
+string16 LanguageComboboxModel::GetItemAt(int index) {
+ return WideToUTF16Hack(GetLanguageNameAt(index));
+}
+
// Returns the index of the language currently specified in the user's
// preference file. Note that it's possible for language A to be picked
// while chrome is currently in language B if the user specified language B
@@ -158,7 +167,7 @@ LanguageComboboxModel::LanguageComboboxModel(
// shouldn't be reflected in this combo box. We return -1 if the value in
// the pref doesn't map to a know language (possible if the user edited the
// prefs file manually).
-int LanguageComboboxModel::GetSelectedLanguageIndex(const std::wstring& prefs) {
+int LanguageComboboxModel::GetSelectedLanguageIndex(const std::string& prefs) {
PrefService* local_state;
if (!profile_)
local_state = g_browser_process->local_state();
diff --git a/chrome/browser/language_combobox_model.h b/chrome/browser/language_combobox_model.h
index 2783b9e..469fa2b 100644
--- a/chrome/browser/language_combobox_model.h
+++ b/chrome/browser/language_combobox_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_LANGUAGE_COMBOBOX_MODEL_H_
#define CHROME_BROWSER_LANGUAGE_COMBOBOX_MODEL_H_
+#pragma once
#include <map>
#include <string>
@@ -11,6 +12,7 @@
#include "app/combobox_model.h"
#include "base/basictypes.h"
+#include "base/string16.h"
class Profile;
@@ -76,9 +78,8 @@ class LanguageComboboxModel : public LanguageList, public ComboboxModel {
virtual ~LanguageComboboxModel() {}
- virtual int GetItemCount() { return get_languages_count(); }
-
- virtual std::wstring GetItemAt(int index) { return GetLanguageNameAt(index); }
+ virtual int GetItemCount();
+ virtual string16 GetItemAt(int index);
// Returns the index of the language currently specified in the user's
// preference file. Note that it's possible for language A to be picked
@@ -87,7 +88,7 @@ class LanguageComboboxModel : public LanguageList, public ComboboxModel {
// shouldn't be reflected in this combo box. We return -1 if the value in
// the pref doesn't map to a know language (possible if the user edited the
// prefs file manually).
- int GetSelectedLanguageIndex(const std::wstring& prefs);
+ int GetSelectedLanguageIndex(const std::string& prefs);
private:
// Profile.
diff --git a/chrome/browser/language_order_table_model.cc b/chrome/browser/language_order_table_model.cc
index 2655378..0598912 100644
--- a/chrome/browser/language_order_table_model.cc
+++ b/chrome/browser/language_order_table_model.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,6 +7,8 @@
#include <set>
#include "app/l10n_util.h"
+#include "app/table_model_observer.h"
+#include "base/string_split.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/language_order_table_model.h b/chrome/browser/language_order_table_model.h
index 911d55e..1f27781 100644
--- a/chrome/browser/language_order_table_model.h
+++ b/chrome/browser/language_order_table_model.h
@@ -4,12 +4,15 @@
#ifndef CHROME_BROWSER_LANGUAGE_ORDER_TABLE_MODEL_H_
#define CHROME_BROWSER_LANGUAGE_ORDER_TABLE_MODEL_H_
+#pragma once
#include <string>
#include <vector>
#include "app/table_model.h"
-#include "app/table_model_observer.h"
+#include "base/basictypes.h"
+
+class TableModelObserver;
class LanguageOrderTableModel : public TableModel {
public:
diff --git a/chrome/browser/load_from_memory_cache_details.h b/chrome/browser/load_from_memory_cache_details.h
index 5727c64..d46684d 100644
--- a/chrome/browser/load_from_memory_cache_details.h
+++ b/chrome/browser/load_from_memory_cache_details.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_LOAD_FROM_MEMORY_CACHE_DETAILS_H__
#define CHROME_BROWSER_LOAD_FROM_MEMORY_CACHE_DETAILS_H__
+#pragma once
#include "base/basictypes.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/load_notification_details.h b/chrome/browser/load_notification_details.h
index b7f8706..dbb1df7 100644
--- a/chrome/browser/load_notification_details.h
+++ b/chrome/browser/load_notification_details.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_LOAD_NOTIFICATION_DETAILS_H__
#define CHROME_BROWSER_LOAD_NOTIFICATION_DETAILS_H__
+#pragma once
#include "base/basictypes.h"
#include "base/time.h"
diff --git a/chrome/browser/locale_tests_uitest.cc b/chrome/browser/locale_tests_uitest.cc
index b5869dc..85a9510 100644
--- a/chrome/browser/locale_tests_uitest.cc
+++ b/chrome/browser/locale_tests_uitest.cc
@@ -1,9 +1,10 @@
-// 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/test/ui/ui_test.h"
+#include "base/environment.h"
#include "build/build_config.h"
class LocaleTestsBase : public UITest {
@@ -14,10 +15,11 @@ class LocaleTestsBase : public UITest {
protected:
void RestoreLcAllEnvironment() {
#if defined(OS_LINUX)
+ scoped_ptr<base::Environment> env(base::Environment::Create());
if (old_lc_all_) {
- setenv("LC_ALL", old_lc_all_, 1);
+ env->SetVar("LC_ALL", old_lc_all_);
} else {
- unsetenv("LC_ALL");
+ env->UnSetVar("LC_ALL");
}
#endif
};
@@ -29,7 +31,7 @@ class LocaleTestsBase : public UITest {
class LocaleTestsDa : public LocaleTestsBase {
public:
LocaleTestsDa() : LocaleTestsBase() {
- launch_arguments_.AppendSwitchWithValue("lang", "da");
+ launch_arguments_.AppendSwitchASCII("lang", "da");
// Linux doesn't use --lang, it only uses environment variables to set the
// language.
@@ -43,7 +45,7 @@ class LocaleTestsDa : public LocaleTestsBase {
class LocaleTestsHe : public LocaleTestsBase {
public:
LocaleTestsHe() : LocaleTestsBase() {
- launch_arguments_.AppendSwitchWithValue("lang", "he");
+ launch_arguments_.AppendSwitchASCII("lang", "he");
#if defined(OS_LINUX)
old_lc_all_ = getenv("LC_ALL");
setenv("LC_ALL", "he_IL.UTF-8", 1);
@@ -54,7 +56,7 @@ class LocaleTestsHe : public LocaleTestsBase {
class LocaleTestsZhTw : public LocaleTestsBase {
public:
LocaleTestsZhTw() : LocaleTestsBase() {
- launch_arguments_.AppendSwitchWithValue("lang", "zh-TW");
+ launch_arguments_.AppendSwitchASCII("lang", "zh-TW");
#if defined(OS_LINUX)
old_lc_all_ = getenv("LC_ALL");
setenv("LC_ALL", "zh_TW.UTF-8", 1);
diff --git a/chrome/browser/location_bar.h b/chrome/browser/location_bar.h
index bb6484e..b6a6d0d 100644
--- a/chrome/browser/location_bar.h
+++ b/chrome/browser/location_bar.h
@@ -10,10 +10,12 @@
#ifndef CHROME_BROWSER_LOCATION_BAR_H_
#define CHROME_BROWSER_LOCATION_BAR_H_
+#pragma once
#include <string>
-#include "chrome/browser/first_run.h"
+#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"
@@ -27,6 +29,10 @@ class LocationBar {
// 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;
diff --git a/chrome/browser/location_bar_util.h b/chrome/browser/location_bar_util.h
index 2264f53..891c67f 100644
--- a/chrome/browser/location_bar_util.h
+++ b/chrome/browser/location_bar_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_LOCATION_BAR_UTIL_H_
#define CHROME_BROWSER_LOCATION_BAR_UTIL_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/login_model.h b/chrome/browser/login_model.h
index 22c50c5..4e69cad 100644
--- a/chrome/browser/login_model.h
+++ b/chrome/browser/login_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_LOGIN_MODEL_H_
#define CHROME_BROWSER_LOGIN_MODEL_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/login_prompt.cc b/chrome/browser/login_prompt.cc
index 37677b5..f8074e0 100644
--- a/chrome/browser/login_prompt.cc
+++ b/chrome/browser/login_prompt.cc
@@ -319,7 +319,7 @@ void LoginHandler::SetAuthDeferred(const std::wstring& username,
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
if (request_) {
- request_->SetAuth(username, password);
+ request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
ResetLoginHandlerForRequest(request_);
}
}
@@ -364,7 +364,10 @@ class LoginDialogTask : public Task {
void Run() {
TabContents* parent_contents = handler_->GetTabContentsForLogin();
if (!parent_contents) {
- // The request was probably cancelled.
+ // 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;
}
diff --git a/chrome/browser/login_prompt.h b/chrome/browser/login_prompt.h
index 946b27f..31bf926 100644
--- a/chrome/browser/login_prompt.h
+++ b/chrome/browser/login_prompt.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_LOGIN_PROMPT_H_
#define CHROME_BROWSER_LOGIN_PROMPT_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/login_prompt_gtk.cc b/chrome/browser/login_prompt_gtk.cc
index c3e89d0..a9cfb4b 100644
--- a/chrome/browser/login_prompt_gtk.cc
+++ b/chrome/browser/login_prompt_gtk.cc
@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include "app/l10n_util.h"
+#include "app/gtk_signal.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/gtk/constrained_window_gtk.h"
@@ -16,6 +17,7 @@
#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_view_gtk.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
@@ -89,15 +91,15 @@ class LoginHandlerGtk : public LoginHandler,
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(OnOKClicked), this);
+ 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(OnCancelClicked), this);
+ 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(OnPromptShown), this);
+ G_CALLBACK(OnPromptHierarchyChangedThunk), this);
SetModel(manager);
@@ -129,34 +131,10 @@ class LoginHandlerGtk : public LoginHandler,
private:
friend class LoginPrompt;
- static void OnOKClicked(GtkButton *button, LoginHandlerGtk* handler) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-
- handler->SetAuth(
- UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(handler->username_entry_))),
- UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(handler->password_entry_))));
- }
-
- static void OnCancelClicked(GtkButton *button, LoginHandlerGtk* handler) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-
- handler->CancelAuth();
- }
-
- static void OnPromptShown(GtkButton* root,
- GtkWidget* previous_toplevel,
- LoginHandlerGtk* handler) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-
- if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(handler->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(handler->ok_, GTK_CAN_DEFAULT);
- gtk_widget_grab_default(handler->ok_);
- gtk_widget_grab_focus(handler->username_entry_);
- }
+ 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.
@@ -170,6 +148,42 @@ class LoginHandlerGtk : public LoginHandler,
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(ChromeThread::CurrentlyOn(ChromeThread::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_);
+
+ // The user may have focused another tab. In this case do not grab focus
+ // until this tab is refocused.
+ if (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*>(GetTabContentsForLogin()->view())->
+ SetFocusedWidget(username_entry_);
+#endif
+ }
+}
+
// static
LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
URLRequest* request) {
diff --git a/chrome/browser/login_prompt_mac.h b/chrome/browser/login_prompt_mac.h
index a872690..9d052ad 100644
--- a/chrome/browser/login_prompt_mac.h
+++ b/chrome/browser/login_prompt_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_LOGIN_PROMPT_MAC_H_
#define CHROME_BROWSER_LOGIN_PROMPT_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
diff --git a/chrome/browser/login_prompt_uitest.cc b/chrome/browser/login_prompt_uitest.cc
index e1dc5af..18b9a20 100644
--- a/chrome/browser/login_prompt_uitest.cc
+++ b/chrome/browser/login_prompt_uitest.cc
@@ -10,24 +10,24 @@
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
using std::wstring;
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
} // namespace
class LoginPromptTest : public UITest {
protected:
LoginPromptTest()
- : UITest(),
- username_basic_(L"basicuser"),
+ : username_basic_(L"basicuser"),
username_digest_(L"digestuser"),
password_(L"secret"),
- password_bad_(L"denyme") {
+ password_bad_(L"denyme"),
+ test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)) {
}
void AppendTab(const GURL& url) {
@@ -41,6 +41,8 @@ class LoginPromptTest : public UITest {
wstring username_digest_;
wstring password_;
wstring password_bad_;
+
+ net::TestServer test_server_;
};
wstring ExpectedTitleFromAuth(const wstring& username,
@@ -49,14 +51,21 @@ wstring ExpectedTitleFromAuth(const wstring& username,
return username + L"/" + password;
}
+// FLAKY: http://crbug.com/56670
+#if defined(OS_WIN)
+#define MAYBE_TestBasicAuth FLAKY_TestBasicAuth
+#elif defined(OS_LINUX)
+#define MAYBE_TestBasicAuth FLAKY_TestBasicAuth
+#else
+#define MAYBE_TestBasicAuth TestBasicAuth
+#endif
// Test that "Basic" HTTP authentication works.
-TEST_F(LoginPromptTest, TestBasicAuth) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+TEST_F(LoginPromptTest, MAYBE_TestBasicAuth) {
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<TabProxy> tab(GetActiveTab());
ASSERT_TRUE(tab.get());
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
EXPECT_TRUE(tab->NeedsAuth());
EXPECT_FALSE(tab->SetAuth(username_basic_, password_bad_));
@@ -64,7 +73,7 @@ TEST_F(LoginPromptTest, TestBasicAuth) {
EXPECT_TRUE(tab->CancelAuth());
EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
EXPECT_TRUE(tab->NeedsAuth());
EXPECT_TRUE(tab->SetAuth(username_basic_, password_));
@@ -72,21 +81,21 @@ TEST_F(LoginPromptTest, TestBasicAuth) {
GetActiveTabTitle());
}
+// FLAKY: http://crbug.com/56670
// Test that "Digest" HTTP authentication works.
-TEST_F(LoginPromptTest, TestDigestAuth) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+TEST_F(LoginPromptTest, FLAKY_TestDigestAuth) {
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<TabProxy> tab(GetActiveTab());
ASSERT_TRUE(tab.get());
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-digest")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-digest")));
EXPECT_TRUE(tab->NeedsAuth());
EXPECT_FALSE(tab->SetAuth(username_digest_, password_bad_));
EXPECT_TRUE(tab->CancelAuth());
EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-digest")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-digest")));
EXPECT_TRUE(tab->NeedsAuth());
EXPECT_TRUE(tab->SetAuth(username_digest_, password_));
@@ -96,19 +105,17 @@ TEST_F(LoginPromptTest, TestDigestAuth) {
// Test that logging in on 2 tabs at once works.
TEST_F(LoginPromptTest, TestTwoAuths) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
scoped_refptr<TabProxy> basic_tab(GetActiveTab());
ASSERT_TRUE(basic_tab.get());
- ASSERT_TRUE(basic_tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(basic_tab->NavigateToURL(test_server_.GetURL("auth-basic")));
AppendTab(GURL(chrome::kAboutBlankURL));
scoped_refptr<TabProxy> digest_tab(GetActiveTab());
ASSERT_TRUE(digest_tab.get());
ASSERT_TRUE(
- digest_tab->NavigateToURL(server->TestServerPage("auth-digest")));
+ digest_tab->NavigateToURL(test_server_.GetURL("auth-digest")));
EXPECT_TRUE(basic_tab->NeedsAuth());
EXPECT_TRUE(basic_tab->SetAuth(username_basic_, password_));
@@ -123,39 +130,46 @@ TEST_F(LoginPromptTest, TestTwoAuths) {
EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_), title);
}
+// FLAKY: http://crbug.com/56670
+#if defined(OS_WIN)
+#define MAYBE_TestCancelAuth FLAKY_TestCancelAuth
+#elif defined(OS_LINUX)
+#define MAYBE_TestCancelAuth FLAKY_TestCancelAuth
+#else
+#define MAYBE_TestCancelAuth TestCancelAuth
+#endif
// Test that cancelling authentication works.
-TEST_F(LoginPromptTest, TestCancelAuth) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+TEST_F(LoginPromptTest, MAYBE_TestCancelAuth) {
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<TabProxy> tab(GetActiveTab());
ASSERT_TRUE(tab.get());
// First navigate to a test server page so we have something to go back to.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("a")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("a")));
// Navigating while auth is requested is the same as cancelling.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
EXPECT_TRUE(tab->NeedsAuth());
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("b")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("b")));
EXPECT_FALSE(tab->NeedsAuth());
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
EXPECT_TRUE(tab->NeedsAuth());
EXPECT_TRUE(tab->GoBack()); // should bring us back to 'a'
EXPECT_FALSE(tab->NeedsAuth());
// Now add a page and go back, so we have something to go forward to.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("c")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("c")));
EXPECT_TRUE(tab->GoBack()); // should bring us back to 'a'
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
EXPECT_TRUE(tab->NeedsAuth());
EXPECT_TRUE(tab->GoForward()); // should bring us to 'c'
EXPECT_FALSE(tab->NeedsAuth());
// Now test that cancelling works as expected.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server_.GetURL("auth-basic")));
EXPECT_TRUE(tab->NeedsAuth());
EXPECT_TRUE(tab->CancelAuth());
EXPECT_FALSE(tab->NeedsAuth());
@@ -163,23 +177,21 @@ TEST_F(LoginPromptTest, TestCancelAuth) {
}
// If multiple tabs are looking for the same auth, the user should only have to
-// enter it once (http://crbug.com/8914).
+// enter it once.
TEST_F(LoginPromptTest, SupplyRedundantAuths) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
ASSERT_TRUE(basic_tab1.get());
ASSERT_TRUE(
- basic_tab1->NavigateToURL(server->TestServerPage("auth-basic/1")));
+ basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
EXPECT_TRUE(basic_tab1->NeedsAuth());
AppendTab(GURL(chrome::kAboutBlankURL));
scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
ASSERT_TRUE(basic_tab2.get());
ASSERT_TRUE(
- basic_tab2->NavigateToURL(server->TestServerPage("auth-basic/2")));
+ basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
EXPECT_TRUE(basic_tab2->NeedsAuth());
// Set the auth in only one of the tabs (but wait for the other to load).
@@ -200,21 +212,19 @@ TEST_F(LoginPromptTest, SupplyRedundantAuths) {
// If multiple tabs are looking for the same auth, and one is cancelled, the
// other should be cancelled as well.
TEST_F(LoginPromptTest, CancelRedundantAuths) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
ASSERT_TRUE(basic_tab1.get());
ASSERT_TRUE(
- basic_tab1->NavigateToURL(server->TestServerPage("auth-basic/1")));
+ basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
EXPECT_TRUE(basic_tab1->NeedsAuth());
AppendTab(GURL(chrome::kAboutBlankURL));
scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
ASSERT_TRUE(basic_tab2.get());
ASSERT_TRUE(
- basic_tab2->NavigateToURL(server->TestServerPage("auth-basic/2")));
+ basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
EXPECT_TRUE(basic_tab2->NeedsAuth());
// Cancel the auth in only one of the tabs (but wait for the other to load).
diff --git a/chrome/browser/login_prompt_win.cc b/chrome/browser/login_prompt_win.cc
index 39f1497..e82899d 100644
--- a/chrome/browser/login_prompt_win.cc
+++ b/chrome/browser/login_prompt_win.cc
@@ -12,6 +12,7 @@
#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"
@@ -104,7 +105,11 @@ class LoginHandlerWin : public LoginHandler,
std::wstring explanation) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- LoginView* view = new LoginView(explanation);
+ TabContents* tab_contents = GetTabContentsForLogin();
+ bool should_focus_view = !tab_contents->delegate() ||
+ tab_contents->delegate()->ShouldFocusConstrainedWindow(tab_contents);
+
+ 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
diff --git a/chrome/browser/mach_broker_mac.cc b/chrome/browser/mach_broker_mac.cc
index 39f3fce..6c24541 100644
--- a/chrome/browser/mach_broker_mac.cc
+++ b/chrome/browser/mach_broker_mac.cc
@@ -4,13 +4,26 @@
#include "chrome/browser/mach_broker_mac.h"
+#include "base/command_line.h"
#include "base/logging.h"
+#include "base/mach_ipc_mac.h"
+#include "base/platform_thread.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/child_process_info.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
+namespace {
+// Prints a string representation of a Mach error code.
+std::string MachErrorCode(kern_return_t err) {
+ return StringPrintf("0x%x %s", err, mach_error_string(err));
+}
+} // namespace
+
// Required because notifications happen on the UI thread.
class RegisterNotificationTask : public Task {
public:
@@ -38,28 +51,124 @@ class RegisterNotificationTask : public Task {
private:
MachBroker* broker_;
+ DISALLOW_COPY_AND_ASSIGN(RegisterNotificationTask);
};
-MachBroker::MachBroker() {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE, new RegisterNotificationTask(this));
-}
+class MachListenerThreadDelegate : public PlatformThread::Delegate {
+ public:
+ MachListenerThreadDelegate(MachBroker* broker) : broker_(broker) {
+ DCHECK(broker_);
+ std::string port_name = MachBroker::GetMachPortName();
+
+ // Create the receive port in the constructor, not in ThreadMain(). It is
+ // important to create and register the receive port before starting the
+ // thread so that child processes will always have someone who's listening.
+ receive_port_.reset(new base::ReceivePort(port_name.c_str()));
+ }
+
+ // Implement |PlatformThread::Delegate|.
+ void ThreadMain() {
+ base::MachReceiveMessage message;
+ kern_return_t err;
+ while ((err = receive_port_->WaitForMessage(&message,
+ MACH_MSG_TIMEOUT_NONE)) ==
+ KERN_SUCCESS) {
+ // 0 was the secret message id. Reject any messages that don't have it.
+ if (message.GetMessageID() != 0) {
+ LOG(ERROR) << "Received message with incorrect id: "
+ << message.GetMessageID();
+ continue;
+ }
+
+ const task_t child_task = message.GetTranslatedPort(0);
+ if (child_task == MACH_PORT_NULL) {
+ LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
+ continue;
+ }
+
+ // It is possible for the child process to die after the call to
+ // |pid_for_task()| but before the call to |FinalizePid()|. To prevent
+ // leaking MachBroker map entries in this case, lock around both these
+ // calls. If the child dies, the death notification will be processed
+ // after the call to FinalizePid(), ensuring proper cleanup.
+ AutoLock lock(broker_->GetLock());
+
+ int pid;
+ err = pid_for_task(child_task, &pid);
+ if (err == KERN_SUCCESS) {
+ broker_->FinalizePid(pid,
+ MachBroker::MachInfo().SetTask(child_task));
+ } else {
+ LOG(ERROR) << "Error getting pid for task " << child_task
+ << ": " << MachErrorCode(err);
+ }
+ }
+
+ LOG(ERROR) << "Mach listener thread exiting; "
+ << "parent WaitForMessage() likely failed: "
+ << MachErrorCode(err);
+ }
+
+ private:
+ // The Mach port to listen on. Created on thread startup.
+ scoped_ptr<base::ReceivePort> receive_port_;
+
+ // The MachBroker to use when new child task rights are received. Can be
+ // NULL.
+ MachBroker* broker_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(MachListenerThreadDelegate);
+};
// Returns the global MachBroker.
MachBroker* MachBroker::instance() {
- return Singleton<MachBroker>::get();
+ return Singleton<MachBroker, LeakySingletonTraits<MachBroker> >::get();
}
-// Adds mach info for a given pid.
-void MachBroker::RegisterPid(
- base::ProcessHandle pid, const MachInfo& mach_info) {
- AutoLock lock(lock_);
+MachBroker::MachBroker() : listener_thread_started_(false) {
+}
+
+void MachBroker::PrepareForFork() {
+ if (!listener_thread_started_) {
+ listener_thread_started_ = true;
+
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE, new RegisterNotificationTask(this));
+
+ // Intentional leak. This thread is never joined or reaped.
+ PlatformThread::CreateNonJoinable(0, new MachListenerThreadDelegate(this));
+ }
+}
+
+// Adds a placeholder to the map for the given pid with MACH_PORT_NULL.
+void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid) {
+ lock_.AssertAcquired();
+
+ MachInfo mach_info;
DCHECK_EQ(0u, mach_map_.count(pid));
mach_map_[pid] = mach_info;
}
+// Updates the mapping for |pid| to include the given |mach_info|.
+void MachBroker::FinalizePid(base::ProcessHandle pid,
+ const MachInfo& mach_info) {
+ lock_.AssertAcquired();
+
+ const int count = mach_map_.count(pid);
+ if (count == 0) {
+ // Do nothing for unknown pids.
+ LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!";
+ return;
+ }
+
+ DCHECK_EQ(1, count);
+ DCHECK(mach_map_[pid].mach_task_ == MACH_PORT_NULL);
+ if (mach_map_[pid].mach_task_ == MACH_PORT_NULL)
+ mach_map_[pid] = mach_info;
+}
+
// Removes all mappings belonging to |pid| from the broker.
-void MachBroker::Invalidate(base::ProcessHandle pid) {
+void MachBroker::InvalidatePid(base::ProcessHandle pid) {
AutoLock lock(lock_);
MachBroker::MachMap::iterator it = mach_map_.find(pid);
if (it == mach_map_.end())
@@ -69,10 +178,14 @@ void MachBroker::Invalidate(base::ProcessHandle pid) {
it->second.mach_task_);
LOG_IF(WARNING, kr != KERN_SUCCESS)
<< "Failed to mach_port_deallocate mach task " << it->second.mach_task_
- << ", error " << kr;
+ << ", error " << MachErrorCode(kr);
mach_map_.erase(it);
}
+Lock& MachBroker::GetLock() {
+ return lock_;
+}
+
// Returns the mach task belonging to |pid|.
mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const {
AutoLock lock(lock_);
@@ -85,6 +198,9 @@ mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const {
void MachBroker::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
+ // TODO(rohitrao): These notifications do not always carry the proper PIDs,
+ // especially when the renderer is already gone or has crashed. Find a better
+ // way to listen for child process deaths. http://crbug.com/55734
base::ProcessHandle handle = 0;
switch (type.value) {
case NotificationType::RENDERER_PROCESS_CLOSED:
@@ -103,5 +219,23 @@ void MachBroker::Observe(NotificationType type,
NOTREACHED() << "Unexpected notification";
break;
}
- Invalidate(handle);
+ InvalidatePid(handle);
+}
+
+// static
+std::string MachBroker::GetMachPortName() {
+ static const char kFormatString[] =
+#if defined(GOOGLE_CHROME_BUILD)
+ "com.google.Chrome"
+#else
+ "org.chromium.Chromium"
+#endif
+ ".rohitfork.%d";
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const bool is_child = command_line.HasSwitch(switches::kProcessType);
+
+ // In non-browser (child) processes, use the parent's pid.
+ const pid_t pid = is_child ? getppid() : getpid();
+ return StringPrintf(kFormatString, pid);
}
diff --git a/chrome/browser/mach_broker_mac.h b/chrome/browser/mach_broker_mac.h
index 25e49fd..7b0257f 100644
--- a/chrome/browser/mach_broker_mac.h
+++ b/chrome/browser/mach_broker_mac.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_MACH_BROKER_H_
#define CHROME_BROWSER_MACH_BROKER_H_
+#pragma once
#include <map>
+#include <string>
#include <mach/mach.h>
@@ -13,6 +15,7 @@
#include "base/process.h"
#include "base/process_util.h"
#include "base/singleton.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
// On OS X, the mach_port_t of a process is required to collect metrics about
@@ -35,6 +38,10 @@ class MachBroker : public base::ProcessMetrics::PortProvider,
// Returns the global MachBroker.
static MachBroker* instance();
+ // Performs any necessary setup that cannot happen in the constructor.
+ // Clients MUST call this method before fork()ing any children.
+ void PrepareForFork();
+
struct MachInfo {
MachInfo() : mach_task_(MACH_PORT_NULL) {}
@@ -46,11 +53,28 @@ class MachBroker : public base::ProcessMetrics::PortProvider,
mach_port_t mach_task_;
};
- // Adds mach info for a given pid.
- void RegisterPid(base::ProcessHandle pid, const MachInfo& mach_info);
+ // Adds a placeholder to the map for the given pid with MACH_PORT_NULL.
+ // Callers are expected to later update the port with FinalizePid(). Callers
+ // MUST acquire the lock given by GetLock() before calling this method (and
+ // release the lock afterwards).
+ void AddPlaceholderForPid(base::ProcessHandle pid);
+
+ // Updates the mapping for |pid| to include the given |mach_info|. Does
+ // nothing if PlaceholderForPid() has not already been called for the given
+ // |pid|. Callers MUST acquire the lock given by GetLock() before calling
+ // this method (and release the lock afterwards).
+ void FinalizePid(base::ProcessHandle pid, const MachInfo& mach_info);
// Removes all mappings belonging to |pid| from the broker.
- void Invalidate(base::ProcessHandle pid);
+ void InvalidatePid(base::ProcessHandle pid);
+
+ // The lock that protects this MachBroker object. Clients MUST acquire and
+ // release this lock around calls to PlaceholderForPid() and FinalizePid().
+ Lock& GetLock();
+
+ // Returns the Mach port name to use when sending or receiving messages.
+ // Does the Right Thing in the browser and in child processes.
+ static std::string GetMachPortName();
// Implement |ProcessMetrics::PortProvider|.
virtual mach_port_t TaskForPid(base::ProcessHandle process) const;
@@ -63,13 +87,13 @@ class MachBroker : public base::ProcessMetrics::PortProvider,
// Private constructor.
MachBroker();
+ // True if the listener thread has been started.
+ bool listener_thread_started_;
+
// Used to register for notifications received by NotificationObserver.
// Accessed only on the UI thread.
NotificationRegistrar registrar_;
- friend struct DefaultSingletonTraits<MachBroker>;
- friend class MachBrokerTest;
-
// Stores mach info for every process in the broker.
typedef std::map<base::ProcessHandle, MachInfo> MachMap;
MachMap mach_map_;
@@ -77,7 +101,10 @@ class MachBroker : public base::ProcessMetrics::PortProvider,
// Mutex that guards |mach_map_|.
mutable Lock lock_;
+ friend class MachBrokerTest;
friend class RegisterNotificationTask;
+ // Needed in order to make the constructor private.
+ friend struct DefaultSingletonTraits<MachBroker>;
DISALLOW_COPY_AND_ASSIGN(MachBroker);
};
diff --git a/chrome/browser/mach_broker_mac_unittest.cc b/chrome/browser/mach_broker_mac_unittest.cc
index 56cc2ae..b0e5b05 100644
--- a/chrome/browser/mach_broker_mac_unittest.cc
+++ b/chrome/browser/mach_broker_mac_unittest.cc
@@ -4,21 +4,57 @@
#include "chrome/browser/mach_broker_mac.h"
+#include "base/lock.h"
#include "testing/gtest/include/gtest/gtest.h"
class MachBrokerTest : public testing::Test {
public:
+ // Helper function to acquire/release locks and call |PlaceholderForPid()|.
+ void AddPlaceholderForPid(base::ProcessHandle pid) {
+ AutoLock lock(broker_.GetLock());
+ broker_.AddPlaceholderForPid(pid);
+ }
+
+ // Helper function to acquire/release locks and call |FinalizePid()|.
+ void FinalizePid(base::ProcessHandle pid,
+ const MachBroker::MachInfo& mach_info) {
+ AutoLock lock(broker_.GetLock());
+ broker_.FinalizePid(pid, mach_info);
+ }
+
+ protected:
MachBroker broker_;
};
-TEST_F(MachBrokerTest, Setter) {
- broker_.RegisterPid(1u, MachBroker::MachInfo().SetTask(2u));
- EXPECT_EQ(2u, broker_.TaskForPid(1));
+TEST_F(MachBrokerTest, Locks) {
+ // Acquire and release the locks. Nothing bad should happen.
+ AutoLock lock(broker_.GetLock());
+}
+
+TEST_F(MachBrokerTest, AddPlaceholderAndFinalize) {
+ // Add a placeholder for PID 1.
+ AddPlaceholderForPid(1);
+ EXPECT_EQ(0u, broker_.TaskForPid(1));
+
+ // Finalize PID 1.
+ FinalizePid(1, MachBroker::MachInfo().SetTask(100u));
+ EXPECT_EQ(100u, broker_.TaskForPid(1));
+
+ // Should be no entry for PID 2.
EXPECT_EQ(0u, broker_.TaskForPid(2));
}
TEST_F(MachBrokerTest, Invalidate) {
- broker_.RegisterPid(1u, MachBroker::MachInfo().SetTask(2));
- broker_.Invalidate(1u);
+ AddPlaceholderForPid(1);
+ FinalizePid(1, MachBroker::MachInfo().SetTask(100u));
+
+ EXPECT_EQ(100u, broker_.TaskForPid(1));
+ broker_.InvalidatePid(1u);
EXPECT_EQ(0u, broker_.TaskForPid(1));
}
+
+TEST_F(MachBrokerTest, FinalizeUnknownPid) {
+ // Finalizing an entry for an unknown pid should not add it to the map.
+ FinalizePid(1u, MachBroker::MachInfo().SetTask(100u));
+ EXPECT_EQ(0u, broker_.TaskForPid(1u));
+}
diff --git a/chrome/browser/managed_prefs_banner_base.cc b/chrome/browser/managed_prefs_banner_base.cc
deleted file mode 100644
index 225db8d..0000000
--- a/chrome/browser/managed_prefs_banner_base.cc
+++ /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.
-
-#include "chrome/browser/managed_prefs_banner_base.h"
-
-#include "chrome/browser/pref_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"
-
-ManagedPrefsBannerBase::ManagedPrefsBannerBase(PrefService* prefs,
- OptionsPage page)
- : prefs_(prefs) {
- switch (page) {
- case OPTIONS_PAGE_GENERAL:
- AddPref(prefs::kHomePage);
- AddPref(prefs::kHomePageIsNewTabPage);
- break;
- case OPTIONS_PAGE_CONTENT:
- AddPref(prefs::kSyncManaged);
- AddPref(prefs::kPasswordManagerEnabled);
- break;
- case OPTIONS_PAGE_ADVANCED:
- AddPref(prefs::kAlternateErrorPagesEnabled);
- AddPref(prefs::kSearchSuggestEnabled);
- AddPref(prefs::kDnsPrefetchingEnabled);
- AddPref(prefs::kSafeBrowsingEnabled);
-#if defined(GOOGLE_CHROME_BUILD)
- AddPref(prefs::kMetricsReportingEnabled);
-#endif
- break;
- default:
- NOTREACHED();
- }
-}
-
-ManagedPrefsBannerBase::~ManagedPrefsBannerBase() {
- for (PrefSet::const_iterator pref(relevant_prefs_.begin());
- pref != relevant_prefs_.end(); ++pref)
- prefs_->RemovePrefObserver(pref->c_str(), this);
-}
-
-void ManagedPrefsBannerBase::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (NotificationType::PREF_CHANGED == type) {
- std::wstring* pref = Details<std::wstring>(details).ptr();
- if (pref && relevant_prefs_.count(*pref))
- OnUpdateVisibility();
- }
-}
-
-void ManagedPrefsBannerBase::AddPref(const wchar_t* pref) {
- if (!relevant_prefs_.count(pref)) {
- if (prefs_->FindPreference(pref)) {
- prefs_->AddPrefObserver(pref, this);
- relevant_prefs_.insert(pref);
- }
- }
-}
-
-void ManagedPrefsBannerBase::RemovePref(const wchar_t* pref) {
- PrefSet::iterator iter = relevant_prefs_.find(pref);
- if (iter != relevant_prefs_.end()) {
- prefs_->RemovePrefObserver(pref, this);
- relevant_prefs_.erase(iter);
- }
-}
-
-bool ManagedPrefsBannerBase::DetermineVisibility() const {
- for (PrefSet::const_iterator pref_name(relevant_prefs_.begin());
- pref_name != relevant_prefs_.end(); ++pref_name) {
- const PrefService::Preference* pref =
- prefs_->FindPreference(pref_name->c_str());
- if (pref && pref->IsManaged())
- return true;
- }
- return false;
-}
diff --git a/chrome/browser/managed_prefs_banner_base.h b/chrome/browser/managed_prefs_banner_base.h
deleted file mode 100644
index bc39189..0000000
--- a/chrome/browser/managed_prefs_banner_base.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_MANAGED_PREFS_BANNER_BASE_H_
-#define CHROME_BROWSER_MANAGED_PREFS_BANNER_BASE_H_
-
-#include <set>
-#include <string>
-
-#include "base/basictypes.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/common/notification_observer.h"
-
-class PrefService;
-
-// Common base functionality for the managed prefs warning banner displayed in
-// the preference dialogs when there are options that are controlled by
-// configuration policy and thus cannot be changed by the user.
-class ManagedPrefsBannerBase : public NotificationObserver {
- public:
- // Initialize the banner with a set of preferences suitable for the given
- // options |page|. Subclasses may change that set by calling AddPref() and
- // RemovePref() afterwards.
- ManagedPrefsBannerBase(PrefService* prefs, OptionsPage page);
- virtual ~ManagedPrefsBannerBase();
-
- // Determine whether the banner should be visible.
- bool DetermineVisibility() const;
-
- // |NotificationObserver| implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- protected:
- // Add a preference as visibility trigger.
- void AddPref(const wchar_t* pref);
- // Remove a preference from being a visibility trigger.
- void RemovePref(const wchar_t* pref);
-
- // Update banner visibility. This is called whenever a preference change is
- // observed that may lead to changed visibility of the banner. Subclasses may
- // override this in order to show/hide the banner.
- virtual void OnUpdateVisibility() { }
-
- private:
- PrefService* prefs_;
- typedef std::set<std::wstring> PrefSet;
- PrefSet relevant_prefs_;
-
- DISALLOW_COPY_AND_ASSIGN(ManagedPrefsBannerBase);
-};
-#endif // CHROME_BROWSER_MANAGED_PREFS_BANNER_BASE_H_
diff --git a/chrome/browser/managed_prefs_banner_base_unittest.cc b/chrome/browser/managed_prefs_banner_base_unittest.cc
deleted file mode 100644
index 60bad07..0000000
--- a/chrome/browser/managed_prefs_banner_base_unittest.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/dummy_pref_store.h"
-#include "chrome/browser/managed_prefs_banner_base.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"
-
-namespace {
-
-const wchar_t* kDummyPref = L"dummy";
-
-} // namespace
-
-// Tests whether managed preferences banner base functionality correctly
-// determines banner visiblity.
-class ManagedPrefsBannerBaseTest : public testing::Test {
- public:
- virtual void SetUp() {
- pref_service_.reset(new TestingPrefService);
- pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com");
- pref_service_->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, false);
- pref_service_->RegisterBooleanPref(kDummyPref, false);
- }
-
- scoped_ptr<TestingPrefService> pref_service_;
-};
-
-TEST_F(ManagedPrefsBannerBaseTest, VisibilityTest) {
- ManagedPrefsBannerBase banner(pref_service_.get(), OPTIONS_PAGE_GENERAL);
- EXPECT_FALSE(banner.DetermineVisibility());
- pref_service_->SetManagedPref(kDummyPref, Value::CreateBooleanValue(true));
- EXPECT_FALSE(banner.DetermineVisibility());
- pref_service_->SetUserPref(prefs::kHomePage,
- Value::CreateStringValue("http://foo.com"));
- EXPECT_FALSE(banner.DetermineVisibility());
- pref_service_->SetManagedPref(prefs::kHomePage,
- Value::CreateStringValue("http://bar.com"));
- EXPECT_TRUE(banner.DetermineVisibility());
-}
-
-// Mock class that allows to capture the notification callback.
-class ManagedPrefsBannerBaseMock : public ManagedPrefsBannerBase {
- public:
- ManagedPrefsBannerBaseMock(PrefService* pref_service, OptionsPage page)
- : ManagedPrefsBannerBase(pref_service, page) { }
-
- MOCK_METHOD0(OnUpdateVisibility, void());
-};
-
-TEST_F(ManagedPrefsBannerBaseTest, NotificationTest) {
- ManagedPrefsBannerBaseMock banner(pref_service_.get(), OPTIONS_PAGE_GENERAL);
- EXPECT_CALL(banner, OnUpdateVisibility()).Times(0);
- pref_service_->SetBoolean(kDummyPref, true);
- EXPECT_CALL(banner, OnUpdateVisibility()).Times(1);
- pref_service_->SetString(prefs::kHomePage, "http://foo.com");
-}
diff --git a/chrome/browser/media_uitest.cc b/chrome/browser/media_uitest.cc
index 85f5ca2..08e2579 100644
--- a/chrome/browser/media_uitest.cc
+++ b/chrome/browser/media_uitest.cc
@@ -6,6 +6,7 @@
#include "base/file_path.h"
#include "base/platform_thread.h"
#include "base/string_util.h"
+#include "chrome/test/ui/ui_layout_test.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
@@ -47,10 +48,88 @@ class MediaTest : public UITest {
}
};
-TEST_F(MediaTest, VideoBearTheora) {
+#if defined(OS_WIN)
+
+// Tests always fail on windows: http://crbug.com/55477
+#define MAYBE_VideoBearTheora DISABLED_VideoBearTheora
+#define MAYBE_VideoBearSilentTheora DISABLED_VideoBearSilentTheora
+#define MAYBE_VideoBearWebm DISABLED_VideoBearWebm
+#define MAYBE_VideoBearSilentWebm DISABLED_VideoBearSilentWebm
+#define MAYBE_VideoBearMp4 DISABLED_VideoBearMp4
+#define MAYBE_VideoBearSilentMp4 DISABLED_VideoBearSilentMp4
+#define MAYBE_MediaUILayoutTest DISABLED_MediaUILayoutTest
+
+#else
+
+#define MAYBE_VideoBearTheora VideoBearTheora
+#define MAYBE_VideoBearSilentTheora VideoBearSilentTheora
+#define MAYBE_VideoBearWebm VideoBearWebm
+#define MAYBE_VideoBearSilentWebm VideoBearSilentWebm
+#define MAYBE_VideoBearMp4 VideoBearMp4
+#define MAYBE_VideoBearSilentMp4 VideoBearSilentMp4
+
+#if defined(OS_LINUX)
+// Test fails on linux: http://crbug.com/56364
+#define MAYBE_MediaUILayoutTest DISABLED_MediaUILayoutTest
+#else
+#define MAYBE_MediaUILayoutTest MediaUILayoutTest
+#endif
+
+#endif
+
+TEST_F(MediaTest, MAYBE_VideoBearTheora) {
PlayVideo("bear.ogv");
}
-TEST_F(MediaTest, VideoBearSilentTheora) {
+TEST_F(MediaTest, MAYBE_VideoBearSilentTheora) {
PlayVideo("bear_silent.ogv");
}
+
+TEST_F(MediaTest, MAYBE_VideoBearWebm) {
+ PlayVideo("bear.webm");
+}
+
+TEST_F(MediaTest, MAYBE_VideoBearSilentWebm) {
+ PlayVideo("bear_silent.webm");
+}
+
+#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+TEST_F(MediaTest, MAYBE_VideoBearMp4) {
+ PlayVideo("bear.mp4");
+}
+
+TEST_F(MediaTest, MAYBE_VideoBearSilentMp4) {
+ PlayVideo("bear_silent.mp4");
+}
+#endif
+
+TEST_F(UILayoutTest, MAYBE_MediaUILayoutTest) {
+ static const char* kResources[] = {
+ "content",
+ "media-file.js",
+ "media-fullscreen.js",
+ "video-paint-test.js",
+ "video-played.js",
+ "video-test.js",
+ };
+
+ static const char* kMediaTests[] = {
+ "video-autoplay.html",
+ // "video-loop.html", disabled due to 52887.
+ "video-no-autoplay.html",
+ // TODO(sergeyu): Add more tests here.
+ };
+
+ FilePath test_dir;
+ FilePath media_test_dir;
+ media_test_dir = media_test_dir.AppendASCII("media");
+ InitializeForLayoutTest(test_dir, media_test_dir, kNoHttpPort);
+
+ // Copy resources first.
+ for (size_t i = 0; i < arraysize(kResources); ++i)
+ AddResourceForLayoutTest(
+ test_dir, media_test_dir.AppendASCII(kResources[i]));
+
+ for (size_t i = 0; i < arraysize(kMediaTests); ++i)
+ RunLayoutTest(kMediaTests[i], kNoHttpPort);
+}
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index 5c38d97..fa89c30 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -4,10 +4,10 @@
#include "chrome/browser/memory_details.h"
-#include "app/l10n_util.h"
#include "base/file_version_info.h"
#include "base/histogram.h"
#include "base/process_util.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/chrome_thread.h"
@@ -219,6 +219,9 @@ void MemoryDetails::UpdateHistograms() {
case ChildProcessInfo::NACL_BROKER_PROCESS:
UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample);
break;
+ case ChildProcessInfo::GPU_PROCESS:
+ UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample);
+ break;
default:
NOTREACHED();
}
diff --git a/chrome/browser/memory_details.h b/chrome/browser/memory_details.h
index 16354d5..e9ceb46 100644
--- a/chrome/browser/memory_details.h
+++ b/chrome/browser/memory_details.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_MEMORY_DETAILS_H_
#define CHROME_BROWSER_MEMORY_DETAILS_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/memory_details_linux.cc b/chrome/browser/memory_details_linux.cc
index bca8a75..232deaf 100644
--- a/chrome/browser/memory_details_linux.cc
+++ b/chrome/browser/memory_details_linux.cc
@@ -8,11 +8,11 @@
#include <fcntl.h>
#include <dirent.h>
-#include "app/l10n_util.h"
#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/chrome_thread.h"
diff --git a/chrome/browser/memory_details_mac.cc b/chrome/browser/memory_details_mac.cc
index 74a58d9..26b9fbf 100644
--- a/chrome/browser/memory_details_mac.cc
+++ b/chrome/browser/memory_details_mac.cc
@@ -15,6 +15,7 @@
#include "base/string_util.h"
#include "base/process_util.h"
#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/chrome_thread.h"
@@ -198,10 +199,10 @@ void MemoryDetails::CollectProcessDataChrome(
else
info.type = ChildProcessInfo::UNKNOWN_PROCESS;
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- if (version_info.get()) {
- info.product_name = version_info->product_name();
- info.version = version_info->product_version();
+ chrome::VersionInfo version_info;
+ if (version_info.is_valid()) {
+ info.product_name = ASCIIToWide(version_info.Name());
+ info.version = ASCIIToWide(version_info.Version());
} else {
info.product_name = process_data_[CHROME_BROWSER].name;
info.version = L"";
diff --git a/chrome/browser/memory_details_win.cc b/chrome/browser/memory_details_win.cc
index 5871687..1e6d985 100644
--- a/chrome/browser/memory_details_win.cc
+++ b/chrome/browser/memory_details_win.cc
@@ -8,6 +8,7 @@
#include "app/l10n_util.h"
#include "base/file_version_info.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/renderer_host/backing_store_manager.h"
@@ -121,10 +122,9 @@ void MemoryDetails::CollectProcessData(
// Get Version Information.
TCHAR name[MAX_PATH];
if (index2 == CHROME_BROWSER || index2 == CHROME_NACL_PROCESS) {
- scoped_ptr<FileVersionInfo> version_info(
- chrome::GetChromeVersionInfo());
- if (version_info != NULL)
- info.version = version_info->file_version();
+ chrome::VersionInfo version_info;
+ if (version_info.is_valid())
+ info.version = ASCIIToWide(version_info.Version());
// Check if this is one of the child processes whose data we collected
// on the IO thread, and if so copy over that data.
for (size_t child = 0; child < child_info.size(); child++) {
diff --git a/chrome/browser/memory_purger.h b/chrome/browser/memory_purger.h
index 2da3917..b86172d 100644
--- a/chrome/browser/memory_purger.h
+++ b/chrome/browser/memory_purger.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,11 +8,11 @@
#ifndef CHROME_BROWSER_MEMORY_PURGER_H_
#define CHROME_BROWSER_MEMORY_PURGER_H_
+#pragma once
#include "base/basictypes.h"
class RenderProcessHost;
-class SafeBrowsingService;
class MemoryPurger {
public:
diff --git a/chrome/browser/message_box_handler.cc b/chrome/browser/message_box_handler.cc
index 1350c5c..7389cc7 100644
--- a/chrome/browser/message_box_handler.cc
+++ b/chrome/browser/message_box_handler.cc
@@ -6,26 +6,71 @@
#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/browsing_data_local_storage_helper.h"
-#include "chrome/browser/cookie_modal_dialog.h"
-#include "chrome/browser/cookie_prompt_modal_dialog_delegate.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"
-void RunJavascriptMessageBox(JavaScriptMessageBoxClient* client,
+static std::wstring GetTitle(Profile* profile,
+ bool is_alert,
+ const GURL& frame_url) {
+ ExtensionsService* extensions_service = profile->GetExtensionsService();
+ if (extensions_service) {
+ 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 = WideToUTF16(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,
+ JavaScriptMessageBoxClient* client,
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) {
- std::wstring title = client->GetMessageBoxTitle(frame_url,
- (dialog_flags == MessageBoxFlags::kIsJavascriptAlert));
+ bool is_alert = dialog_flags == MessageBoxFlags::kIsJavascriptAlert;
+ std::wstring title = GetTitle(profile, is_alert, frame_url);
Singleton<AppModalDialogQueue>()->AddDialog(new JavaScriptAppModalDialog(
client, title, dialog_flags, message_text, default_prompt_text,
display_suppress_checkbox, false, reply_msg));
@@ -42,49 +87,3 @@ void RunBeforeUnloadDialog(TabContents* tab_contents,
MessageBoxFlags::kIsJavascriptConfirm, message_text, std::wstring(),
false, true, reply_msg));
}
-
-void RunCookiePrompt(TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const std::string& cookie_line,
- CookiePromptModalDialogDelegate* delegate) {
- Singleton<AppModalDialogQueue>()->AddDialog(
- new CookiePromptModalDialog(tab_contents, host_content_settings_map,
- origin, cookie_line, delegate));
-}
-
-void RunLocalStoragePrompt(
- TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const string16& key,
- const string16& value,
- CookiePromptModalDialogDelegate* delegate) {
- Singleton<AppModalDialogQueue>()->AddDialog(
- new CookiePromptModalDialog(tab_contents, host_content_settings_map,
- origin, key, value, delegate));
-}
-
-void RunDatabasePrompt(
- TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& origin,
- const string16& database_name,
- const string16& display_name,
- unsigned long estimated_size,
- CookiePromptModalDialogDelegate* delegate) {
- Singleton<AppModalDialogQueue>()->AddDialog(
- new CookiePromptModalDialog(tab_contents, host_content_settings_map,
- origin, database_name, display_name,
- estimated_size, delegate));
-}
-
-void RunAppCachePrompt(
- TabContents* tab_contents,
- HostContentSettingsMap* host_content_settings_map,
- const GURL& manifest_url,
- CookiePromptModalDialogDelegate* delegate) {
- Singleton<AppModalDialogQueue>()->AddDialog(
- new CookiePromptModalDialog(tab_contents, host_content_settings_map,
- manifest_url, delegate));
-}
diff --git a/chrome/browser/message_box_handler.h b/chrome/browser/message_box_handler.h
index 7a66902..fcb9cc9 100644
--- a/chrome/browser/message_box_handler.h
+++ b/chrome/browser/message_box_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_MESSAGE_BOX_HANDLER_H_
#define CHROME_BROWSER_MESSAGE_BOX_HANDLER_H_
+#pragma once
#include <string>
@@ -18,6 +19,7 @@ class GURL;
class HostContentSettingsMap;
class JavaScriptMessageBoxClient;
class TabContents;
+class Profile;
// Creates and runs a Javascript Message Box dialog.
// The dialog type is specified within |dialog_flags|, the
@@ -25,7 +27,8 @@ class TabContents;
// 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(JavaScriptMessageBoxClient* client,
+void RunJavascriptMessageBox(Profile* profile,
+ JavaScriptMessageBoxClient* client,
const GURL& frame_url,
int dialog_flags,
const std::wstring& message_text,
@@ -83,4 +86,3 @@ void RunAppCachePrompt(
CookiePromptModalDialogDelegate* delegate);
#endif // CHROME_BROWSER_MESSAGE_BOX_HANDLER_H_
-
diff --git a/chrome/browser/metrics/histogram_synchronizer.h b/chrome/browser/metrics/histogram_synchronizer.h
index 0ef650c..39e0e2a 100644
--- a/chrome/browser/metrics/histogram_synchronizer.h
+++ b/chrome/browser/metrics/histogram_synchronizer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_
#define CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/metrics/metric_event_duration_details.h b/chrome/browser/metrics/metric_event_duration_details.h
index 3e2feec..b100445 100644
--- a/chrome/browser/metrics/metric_event_duration_details.h
+++ b/chrome/browser/metrics/metric_event_duration_details.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_METRICS_METRIC_EVENT_DURATION_DETAILS_H_
#define CHROME_BROWSER_METRICS_METRIC_EVENT_DURATION_DETAILS_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index 7384a2a..7d602e6 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -7,11 +7,8 @@
#include <string>
#include <vector>
-#include "base/base64.h"
#include "base/basictypes.h"
#include "base/file_util.h"
-#include "base/file_version_info.h"
-#include "base/md5.h"
#include "base/perftimer.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
@@ -22,7 +19,7 @@
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/gpu_process_host.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/pref_names.h"
@@ -72,20 +69,22 @@ std::string MetricsLog::GetInstallDate() const {
// static
std::string MetricsLog::GetVersionString() {
- scoped_ptr<FileVersionInfo> version_info(
- chrome::GetChromeVersionInfo());
- if (version_info.get()) {
- std::string version = WideToUTF8(version_info->product_version());
- if (!version_extension_.empty())
- version += version_extension_;
- if (!version_info->is_official_build())
- version.append("-devel");
- return version;
- } else {
- NOTREACHED() << "Unable to retrieve version string.";
+ chrome::VersionInfo version_info;
+ if (!version_info.is_valid()) {
+ NOTREACHED() << "Unable to retrieve version info.";
+ return std::string();
}
- return std::string();
+ std::string version = version_info.Version();
+ if (!version_extension_.empty())
+ version += version_extension_;
+ if (!version_info.IsOfficialBuild())
+ version.append("-devel");
+ return version;
+}
+
+MetricsLog* MetricsLog::AsMetricsLog() {
+ return this;
}
void MetricsLog::RecordIncrementalStabilityElements() {
@@ -160,13 +159,13 @@ void MetricsLog::WritePluginStabilityElements(PrefService* pref) {
}
DictionaryValue* plugin_dict = static_cast<DictionaryValue*>(*iter);
- std::wstring plugin_name;
+ std::string plugin_name;
plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
OPEN_ELEMENT_FOR_SCOPE("pluginstability");
// Use "filename" instead of "name", otherwise we need to update the
// UMA servers.
- WriteAttribute("filename", CreateBase64Hash(WideToUTF8(plugin_name)));
+ WriteAttribute("filename", CreateBase64Hash(plugin_name));
int launches = 0;
plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
@@ -354,10 +353,10 @@ void MetricsLog::RecordEnvironment(
void MetricsLog::WriteAllProfilesMetrics(
const DictionaryValue& all_profiles_metrics) {
- const std::wstring profile_prefix(prefs::kProfilePrefix);
+ const std::string profile_prefix(prefs::kProfilePrefix);
for (DictionaryValue::key_iterator i = all_profiles_metrics.begin_keys();
i != all_profiles_metrics.end_keys(); ++i) {
- const std::wstring& key_name = *i;
+ const std::string& key_name = *i;
if (key_name.compare(0, profile_prefix.size(), profile_prefix) == 0) {
DictionaryValue* profile;
if (all_profiles_metrics.GetDictionaryWithoutPathExpansion(key_name,
@@ -367,21 +366,21 @@ void MetricsLog::WriteAllProfilesMetrics(
}
}
-void MetricsLog::WriteProfileMetrics(const std::wstring& profileidhash,
+void MetricsLog::WriteProfileMetrics(const std::string& profileidhash,
const DictionaryValue& profile_metrics) {
OPEN_ELEMENT_FOR_SCOPE("userprofile");
- WriteAttribute("profileidhash", WideToUTF8(profileidhash));
+ WriteAttribute("profileidhash", profileidhash);
for (DictionaryValue::key_iterator i = profile_metrics.begin_keys();
i != profile_metrics.end_keys(); ++i) {
Value* value;
if (profile_metrics.GetWithoutPathExpansion(*i, &value)) {
- DCHECK(*i != L"id");
+ DCHECK(*i != "id");
switch (value->GetType()) {
case Value::TYPE_STRING: {
std::string string_value;
if (value->GetAsString(&string_value)) {
OPEN_ELEMENT_FOR_SCOPE("profileparam");
- WriteAttribute("name", WideToUTF8(*i));
+ WriteAttribute("name", *i);
WriteAttribute("value", string_value);
}
break;
@@ -391,7 +390,7 @@ void MetricsLog::WriteProfileMetrics(const std::wstring& profileidhash,
bool bool_value;
if (value->GetAsBoolean(&bool_value)) {
OPEN_ELEMENT_FOR_SCOPE("profileparam");
- WriteAttribute("name", WideToUTF8(*i));
+ WriteAttribute("name", *i);
WriteIntAttribute("value", bool_value ? 1 : 0);
}
break;
@@ -401,7 +400,7 @@ void MetricsLog::WriteProfileMetrics(const std::wstring& profileidhash,
int int_value;
if (value->GetAsInteger(&int_value)) {
OPEN_ELEMENT_FOR_SCOPE("profileparam");
- WriteAttribute("name", WideToUTF8(*i));
+ WriteAttribute("name", *i);
WriteIntAttribute("value", int_value);
}
break;
diff --git a/chrome/browser/metrics/metrics_log.h b/chrome/browser/metrics/metrics_log.h
index c7ba23f..8f35705 100644
--- a/chrome/browser/metrics/metrics_log.h
+++ b/chrome/browser/metrics/metrics_log.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_METRICS_METRICS_LOG_H_
#define CHROME_BROWSER_METRICS_METRICS_LOG_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/common/metrics_helpers.h"
@@ -54,9 +55,7 @@ class MetricsLog : public MetricsLogBase {
// Get the current version of the application as a string.
static std::string GetVersionString();
- virtual MetricsLog* AsMetricsLog() {
- return this;
- }
+ virtual MetricsLog* AsMetricsLog();
private:
// Returns the date at which the current metrics client ID was created as
@@ -92,7 +91,7 @@ class MetricsLog : public MetricsLogBase {
// Writes metrics for the profile identified by key. This writes all
// key/value pairs in profile_metrics.
- void WriteProfileMetrics(const std::wstring& key,
+ void WriteProfileMetrics(const std::string& key,
const DictionaryValue& profile_metrics);
DISALLOW_COPY_AND_ASSIGN(MetricsLog);
diff --git a/chrome/browser/metrics/metrics_response.cc b/chrome/browser/metrics/metrics_response.cc
index 132582e..71787e2 100644
--- a/chrome/browser/metrics/metrics_response.cc
+++ b/chrome/browser/metrics/metrics_response.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <libxml/parser.h>
-
#include "chrome/browser/metrics/metrics_response.h"
+#include "libxml/parser.h"
+
// State to pass around during SAX parsing.
struct SAXState {
int collectors;
diff --git a/chrome/browser/metrics/metrics_response.h b/chrome/browser/metrics/metrics_response.h
index 9cd7653..1083211 100644
--- a/chrome/browser/metrics/metrics_response.h
+++ b/chrome/browser/metrics/metrics_response.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_METRICS_METRICS_RESPONSE_H_
#define CHROME_BROWSER_METRICS_METRICS_RESPONSE_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index 9a93091..b6d4c3f 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -164,9 +164,12 @@
#endif
#include "base/base64.h"
+#include "base/command_line.h"
#include "base/histogram.h"
#include "base/md5.h"
+#include "base/string_number_conversions.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_list.h"
@@ -175,7 +178,7 @@
#include "chrome/browser/memory_details.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "chrome/browser/metrics/metrics_log.h"
-#include "chrome/browser/pref_service.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/search_engines/template_url_model.h"
@@ -199,10 +202,9 @@
#endif
#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/system_library.h"
#include "chrome/browser/chromeos/external_metrics.h"
-
-static const char kHardwareClassTool[] = "/usr/bin/hardware_class";
-static const char kUnknownHardwareClass[] = "unknown";
#endif
namespace {
@@ -215,7 +217,7 @@ MetricsService::LogRecallStatus MakeRecallStatusHistogram(
// TODO(ziadh): Remove this when done with experiment.
void MakeStoreStatusHistogram(MetricsService::LogStoreStatus status) {
- UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogStore", status,
+ UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogStore2", status,
MetricsService::END_STORE_STATUS);
}
} // namespace
@@ -366,7 +368,9 @@ class MetricsService::InitTask : public Task {
NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
std::string hardware_class; // Empty string by default.
#if defined(OS_CHROMEOS)
- hardware_class = MetricsService::GetHardwareClass();
+ chromeos::SystemLibrary* system_library =
+ chromeos::CrosLibrary::Get()->GetSystemLibrary();
+ system_library->GetMachineStatistic("hardware_class", &hardware_class);
#endif // OS_CHROMEOS
callback_loop_->PostTask(FROM_HERE, new InitTaskComplete(
hardware_class, plugins));
@@ -514,7 +518,7 @@ void MetricsService::SetRecording(bool enabled) {
// Might as well make a note of how long this ID has existed
pref->SetString(prefs::kMetricsClientIDTimestamp,
- Int64ToString(Time::Now().ToTimeT()));
+ base::Int64ToString(Time::Now().ToTimeT()));
}
}
child_process_logging::SetClientId(client_id_);
@@ -653,7 +657,7 @@ void MetricsService::Observe(NotificationType type,
break;
}
default:
- LOG(DFATAL);
+ NOTREACHED();
break;
}
@@ -858,7 +862,7 @@ void MetricsService::ScheduleNextStateSave() {
void MetricsService::SaveLocalState() {
PrefService* pref = g_browser_process->local_state();
if (!pref) {
- LOG(DFATAL);
+ NOTREACHED();
return;
}
@@ -1149,7 +1153,7 @@ void MetricsService::MakePendingLog() {
break;
default:
- LOG(DFATAL);
+ NOTREACHED();
return;
}
@@ -1304,6 +1308,7 @@ void MetricsService::StoreUnsentLogsHelper(
MD5Final(&digest, &ctx);
list->Append(Value::CreateStringValue(MD5DigestToBase16(digest)));
DCHECK(list->GetSize() >= 3); // Minimum of 3 elements (size, data, hash).
+ MakeStoreStatusHistogram(STORE_SUCCESS);
}
void MetricsService::StoreUnsentLogs() {
@@ -1380,7 +1385,7 @@ static const char* StatusToString(const URLRequestStatus& status) {
return "FAILED";
default:
- LOG(DFATAL);
+ NOTREACHED();
return "Unknown";
}
}
@@ -1442,7 +1447,7 @@ void MetricsService::OnURLFetchComplete(const URLFetcher* source,
break;
default:
- LOG(DFATAL);
+ NOTREACHED();
break;
}
@@ -1684,7 +1689,7 @@ void MetricsService::LogWindowChange(NotificationType type,
break;
default:
- LOG(DFATAL);
+ NOTREACHED();
return;
}
@@ -1712,14 +1717,14 @@ void MetricsService::LogLoadComplete(NotificationType type,
load_details->load_time());
}
-void MetricsService::IncrementPrefValue(const wchar_t* path) {
+void MetricsService::IncrementPrefValue(const char* path) {
PrefService* pref = g_browser_process->local_state();
DCHECK(pref);
int value = pref->GetInteger(path);
pref->SetInteger(path, value + 1);
}
-void MetricsService::IncrementLongPrefsValue(const wchar_t* path) {
+void MetricsService::IncrementLongPrefsValue(const char* path) {
PrefService* pref = g_browser_process->local_state();
DCHECK(pref);
int64 value = pref->GetInt64(path);
@@ -1778,7 +1783,7 @@ void MetricsService::LogChildProcessChange(
break;
default:
- LOG(DFATAL) << "Unexpected notification type " << type.value;
+ NOTREACHED() << "Unexpected notification type " << type.value;
return;
}
}
@@ -1796,8 +1801,8 @@ static void CountBookmarks(const BookmarkNode* node,
}
void MetricsService::LogBookmarks(const BookmarkNode* node,
- const wchar_t* num_bookmarks_key,
- const wchar_t* num_folders_key) {
+ const char* num_bookmarks_key,
+ const char* num_folders_key) {
DCHECK(node);
int num_bookmarks = 0;
int num_folders = 0;
@@ -1838,23 +1843,25 @@ void MetricsService::RecordPluginChanges(PrefService* pref) {
for (ListValue::iterator value_iter = plugins->begin();
value_iter != plugins->end(); ++value_iter) {
if (!(*value_iter)->IsType(Value::TYPE_DICTIONARY)) {
- LOG(DFATAL);
+ NOTREACHED();
continue;
}
DictionaryValue* plugin_dict = static_cast<DictionaryValue*>(*value_iter);
- std::wstring plugin_name;
+ std::string plugin_name;
plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
if (plugin_name.empty()) {
- LOG(DFATAL);
+ NOTREACHED();
continue;
}
- if (child_process_stats_buffer_.find(plugin_name) ==
+ // TODO(viettrungluu): remove conversions
+ if (child_process_stats_buffer_.find(UTF8ToWide(plugin_name)) ==
child_process_stats_buffer_.end())
continue;
- ChildProcessStats stats = child_process_stats_buffer_[plugin_name];
+ ChildProcessStats stats =
+ child_process_stats_buffer_[UTF8ToWide(plugin_name)];
if (stats.process_launches) {
int launches = 0;
plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
@@ -1874,7 +1881,7 @@ void MetricsService::RecordPluginChanges(PrefService* pref) {
plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
}
- child_process_stats_buffer_.erase(plugin_name);
+ child_process_stats_buffer_.erase(UTF8ToWide(plugin_name));
}
// Now go through and add dictionaries for plugins that didn't already have
@@ -1888,7 +1895,8 @@ void MetricsService::RecordPluginChanges(PrefService* pref) {
if (ChildProcessInfo::PLUGIN_PROCESS != stats.process_type)
continue;
- std::wstring plugin_name = cache_iter->first;
+ // TODO(viettrungluu): remove conversion
+ std::string plugin_name = WideToUTF8(cache_iter->first);
DictionaryValue* plugin_dict = new DictionaryValue;
@@ -1913,7 +1921,7 @@ bool MetricsService::CanLogNotification(NotificationType type,
return !BrowserList::IsOffTheRecordSessionActive();
}
-void MetricsService::RecordBooleanPrefValue(const wchar_t* path, bool value) {
+void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
DCHECK(IsSingleThreaded());
PrefService* pref = g_browser_process->local_state();
@@ -1937,20 +1945,6 @@ static bool IsSingleThreaded() {
}
#if defined(OS_CHROMEOS)
-// static
-std::string MetricsService::GetHardwareClass() {
- DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::UI));
- std::string hardware_class;
- FilePath tool(kHardwareClassTool);
- CommandLine command(tool);
- if (base::GetAppOutput(command, &hardware_class)) {
- TrimWhitespaceASCII(hardware_class, TRIM_ALL, &hardware_class);
- } else {
- hardware_class = kUnknownHardwareClass;
- }
- return hardware_class;
-}
-
void MetricsService::StartExternalMetrics() {
external_metrics_ = new chromeos::ExternalMetrics;
external_metrics_->Start();
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index 9cf7831..650935a 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_METRICS_METRICS_SERVICE_H_
#define CHROME_BROWSER_METRICS_METRICS_SERVICE_H_
+#pragma once
#include <map>
#include <string>
@@ -17,6 +18,7 @@
#include "base/scoped_ptr.h"
#include "chrome/common/metrics_helpers.h"
#include "chrome/common/net/url_fetcher.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#if defined(OS_CHROMEOS)
@@ -63,6 +65,7 @@ class MetricsService : public NotificationObserver,
// TODO(ziadh): This is here temporarily for a side experiment. Remove later
// on.
enum LogStoreStatus {
+ STORE_SUCCESS, // Successfully presisted log.
ENCODE_FAIL, // Failed to encode log.
COMPRESS_FAIL, // Failed to compress log.
END_STORE_STATUS // Number of bins to use to create the histogram.
@@ -332,11 +335,11 @@ class MetricsService : public NotificationObserver,
const NotificationDetails& details);
// Reads, increments and then sets the specified integer preference.
- void IncrementPrefValue(const wchar_t* path);
+ void IncrementPrefValue(const char* path);
// Reads, increments and then sets the specified long preference that is
// stored as a string.
- void IncrementLongPrefsValue(const wchar_t* path);
+ void IncrementLongPrefsValue(const char* path);
// Records a renderer process crash.
void LogRendererCrash();
@@ -351,8 +354,8 @@ class MetricsService : public NotificationObserver,
// in node. The pref key for the number of bookmarks in num_bookmarks_key and
// the pref key for number of folders in num_folders_key.
void LogBookmarks(const BookmarkNode* node,
- const wchar_t* num_bookmarks_key,
- const wchar_t* num_folders_key);
+ const char* num_bookmarks_key,
+ const char* num_folders_key);
// Sets preferences for the number of bookmarks in model.
void LogBookmarks(BookmarkModel* model);
@@ -390,7 +393,7 @@ class MetricsService : public NotificationObserver,
const NotificationDetails& details);
// Sets the value of the specified path in prefs and schedules a save.
- void RecordBooleanPrefValue(const wchar_t* path, bool value);
+ void RecordBooleanPrefValue(const char* path, bool value);
NotificationRegistrar registrar_;
@@ -487,13 +490,13 @@ class MetricsService : public NotificationObserver,
scoped_refptr<chromeos::ExternalMetrics> external_metrics_;
#endif
- FRIEND_TEST(MetricsServiceTest, EmptyLogList);
- FRIEND_TEST(MetricsServiceTest, SingleElementLogList);
- FRIEND_TEST(MetricsServiceTest, OverLimitLogList);
- FRIEND_TEST(MetricsServiceTest, SmallRecoveredListSize);
- FRIEND_TEST(MetricsServiceTest, RemoveSizeFromLogList);
- FRIEND_TEST(MetricsServiceTest, CorruptSizeOfLogList);
- FRIEND_TEST(MetricsServiceTest, CorruptChecksumOfLogList);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, EmptyLogList);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, SingleElementLogList);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, OverLimitLogList);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, SmallRecoveredListSize);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RemoveSizeFromLogList);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, CorruptSizeOfLogList);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, CorruptChecksumOfLogList);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, ClientIdGeneratesAllZeroes);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, ClientIdGeneratesCorrectly);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, ClientIdCorrectlyFormatted);
diff --git a/chrome/browser/metrics/metrics_service_uitest.cc b/chrome/browser/metrics/metrics_service_uitest.cc
index fcadfa2..fd64a41 100644
--- a/chrome/browser/metrics/metrics_service_uitest.cc
+++ b/chrome/browser/metrics/metrics_service_uitest.cc
@@ -11,10 +11,9 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
-#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/pref_value_store.h"
+#include "chrome/browser/prefs/pref_service.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"
@@ -96,9 +95,10 @@ TEST_F(MetricsServiceTest, CrashRenderers) {
scoped_refptr<TabProxy> tab(window->GetTab(1));
ASSERT_TRUE(tab.get());
-// We should get a crash dump on Windows.
-// Also on Linux with Breakpad enabled.
-#if defined(OS_WIN) || defined(USE_LINUX_BREAKPAD)
+ // We can get crash dumps on Windows always, Linux when breakpad is
+ // enabled, and all platforms for official Google Chrome builds.
+#if defined(OS_WIN) || defined(USE_LINUX_BREAKPAD) || \
+ defined(GOOGLE_CHROME_BUILD)
expected_crashes_ = 1;
#endif
ASSERT_TRUE(tab->NavigateToURLAsync(GURL(chrome::kAboutCrashURL)));
diff --git a/chrome/browser/metrics/metrics_service_unittest.cc b/chrome/browser/metrics/metrics_service_unittest.cc
index 6a1026c..a5ec080 100644
--- a/chrome/browser/metrics/metrics_service_unittest.cc
+++ b/chrome/browser/metrics/metrics_service_unittest.cc
@@ -40,16 +40,6 @@ TEST(MetricsServiceTest, ClientIdCorrectlyFormatted) {
}
#endif
-#if defined(OS_CHROMEOS)
-TEST(MetricsServiceTest, GetHardwareClass) {
- // The assumption is that unit tests run on the build host rather
- // than on the Chrome OS device so the hardware_class tool is not
- // available.
- std::string hardware_class = MetricsService::GetHardwareClass();
- EXPECT_EQ("unknown", hardware_class);
-}
-#endif // OS_CHROMEOS
-
class MetricsServiceTest : public ::testing::Test {
};
diff --git a/chrome/browser/metrics/user_metrics.h b/chrome/browser/metrics/user_metrics.h
index 81be4b6..8fcca7a 100644
--- a/chrome/browser/metrics/user_metrics.h
+++ b/chrome/browser/metrics/user_metrics.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_METRICS_USER_METRICS_H_
#define CHROME_BROWSER_METRICS_USER_METRICS_H_
+#pragma once
#include <string>
@@ -31,9 +32,8 @@ class UserMetrics {
// not good: "SSLDialogShown", "PageLoaded", "DiskFull"
// We use this to gather anonymized information about how users are
// interacting with the browser.
- // WARNING: Call this function exactly like this, with the string literal
- // inline:
- // UserMetrics::RecordAction("foo bar", profile);
+ // WARNING: Call this function exactly like this:
+ // UserMetrics::RecordAction(UserMetricsAction("foo bar"));
// because otherwise our processing scripts won't pick up on new actions.
//
// For more complicated situations (like when there are many different
@@ -46,7 +46,8 @@ class UserMetrics {
// This function has identical input and behavior to RecordAction, but is
// not automatically found by the action-processing scripts. It can be used
// when it's a pain to enumerate all possible actions, but if you use this
- // you need to also update the rules for extracting known actions.
+ // you need to also update the rules for extracting known actions in
+ // chrome/tools/extract_actions.py.
static void RecordComputedAction(const std::string& action,
Profile* profile);
diff --git a/chrome/browser/mock_browsing_data_appcache_helper.cc b/chrome/browser/mock_browsing_data_appcache_helper.cc
index e056004..5fab6d0 100644
--- a/chrome/browser/mock_browsing_data_appcache_helper.cc
+++ b/chrome/browser/mock_browsing_data_appcache_helper.cc
@@ -1,11 +1,10 @@
-// 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.
#include "chrome/browser/mock_browsing_data_appcache_helper.h"
#include "base/callback.h"
-#include "base/logging.h"
MockBrowsingDataAppCacheHelper::MockBrowsingDataAppCacheHelper(
Profile* profile)
@@ -27,4 +26,3 @@ void MockBrowsingDataAppCacheHelper::CancelNotification() {
void MockBrowsingDataAppCacheHelper::DeleteAppCacheGroup(
const GURL& manifest_url) {
}
-
diff --git a/chrome/browser/mock_browsing_data_appcache_helper.h b/chrome/browser/mock_browsing_data_appcache_helper.h
index e5b3630..c6119b8 100644
--- a/chrome/browser/mock_browsing_data_appcache_helper.h
+++ b/chrome/browser/mock_browsing_data_appcache_helper.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_MOCK_BROWSING_DATA_APPCACHE_HELPER_H_
#define CHROME_BROWSER_MOCK_BROWSING_DATA_APPCACHE_HELPER_H_
-
-#include <map>
+#pragma once
#include "base/callback.h"
#include "chrome/browser/browsing_data_appcache_helper.h"
diff --git a/chrome/browser/mock_browsing_data_database_helper.h b/chrome/browser/mock_browsing_data_database_helper.h
index 8e075db..e925e0b 100644
--- a/chrome/browser/mock_browsing_data_database_helper.h
+++ b/chrome/browser/mock_browsing_data_database_helper.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_MOCK_BROWSING_DATA_DATABASE_HELPER_H_
#define CHROME_BROWSER_MOCK_BROWSING_DATA_DATABASE_HELPER_H_
+#pragma once
#include <map>
+#include <vector>
#include "base/callback.h"
diff --git a/chrome/browser/mock_browsing_data_indexed_db_helper.cc b/chrome/browser/mock_browsing_data_indexed_db_helper.cc
new file mode 100644
index 0000000..ed83fd3
--- /dev/null
+++ b/chrome/browser/mock_browsing_data_indexed_db_helper.cc
@@ -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.
+
+#include "chrome/browser/mock_browsing_data_indexed_db_helper.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+
+MockBrowsingDataIndexedDBHelper::MockBrowsingDataIndexedDBHelper(
+ Profile* profile)
+ : profile_(profile) {
+}
+
+MockBrowsingDataIndexedDBHelper::~MockBrowsingDataIndexedDBHelper() {
+}
+
+void MockBrowsingDataIndexedDBHelper::StartFetching(
+ Callback1<const std::vector<IndexedDBInfo>& >::Type* callback) {
+ callback_.reset(callback);
+}
+
+void MockBrowsingDataIndexedDBHelper::CancelNotification() {
+ callback_.reset(NULL);
+}
+
+void MockBrowsingDataIndexedDBHelper::DeleteIndexedDBFile(
+ const FilePath& file_path) {
+ CHECK(files_.find(file_path.value()) != files_.end());
+ last_deleted_file_ = file_path;
+ files_[file_path.value()] = false;
+}
+
+void MockBrowsingDataIndexedDBHelper::AddIndexedDBSamples() {
+ response_.push_back(
+ BrowsingDataIndexedDBHelper::IndexedDBInfo(
+ "http", "idbhost1", 1, "idb1", "http://idbhost1:1/", "name",
+ FilePath(FILE_PATH_LITERAL("file1")), 1, base::Time()));
+ files_[FILE_PATH_LITERAL("file1")] = true;
+ response_.push_back(
+ BrowsingDataIndexedDBHelper::IndexedDBInfo(
+ "http", "idbhost2", 2, "idb2", "http://idbhost2:2/", "name",
+ FilePath(FILE_PATH_LITERAL("file2")), 2, base::Time()));
+ files_[FILE_PATH_LITERAL("file2")] = true;
+}
+
+void MockBrowsingDataIndexedDBHelper::Notify() {
+ CHECK(callback_.get());
+ callback_->Run(response_);
+}
+
+void MockBrowsingDataIndexedDBHelper::Reset() {
+ for (std::map<const FilePath::StringType, bool>::iterator i = files_.begin();
+ i != files_.end(); ++i)
+ i->second = true;
+}
+
+bool MockBrowsingDataIndexedDBHelper::AllDeleted() {
+ for (std::map<const FilePath::StringType, bool>::const_iterator i =
+ files_.begin(); i != files_.end(); ++i)
+ if (i->second)
+ return false;
+ return true;
+}
diff --git a/chrome/browser/mock_browsing_data_indexed_db_helper.h b/chrome/browser/mock_browsing_data_indexed_db_helper.h
new file mode 100644
index 0000000..b4b0c1c
--- /dev/null
+++ b/chrome/browser/mock_browsing_data_indexed_db_helper.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_MOCK_BROWSING_DATA_INDEXED_DB_HELPER_H_
+#define CHROME_BROWSER_MOCK_BROWSING_DATA_INDEXED_DB_HELPER_H_
+#pragma once
+
+#include <map>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/browsing_data_indexed_db_helper.h"
+
+// Mock for BrowsingDataIndexedDBHelper.
+// Use AddIndexedDBSamples() or add directly to response_ vector, then
+// call Notify().
+class MockBrowsingDataIndexedDBHelper
+ : public BrowsingDataIndexedDBHelper {
+ public:
+ explicit MockBrowsingDataIndexedDBHelper(Profile* profile);
+
+ // Adds some IndexedDBInfo samples.
+ void AddIndexedDBSamples();
+
+ // Notifies the callback.
+ void Notify();
+
+ // Marks all indexed db files as existing.
+ void Reset();
+
+ // Returns true if all indexed db files were deleted since the last
+ // Reset() invokation.
+ bool AllDeleted();
+
+ // BrowsingDataIndexedDBHelper.
+ virtual void StartFetching(
+ Callback1<const std::vector<IndexedDBInfo>& >::Type* callback);
+ virtual void CancelNotification();
+ virtual void DeleteIndexedDBFile(const FilePath& file_path);
+
+ FilePath last_deleted_file_;
+
+ private:
+ virtual ~MockBrowsingDataIndexedDBHelper();
+
+ Profile* profile_;
+
+ scoped_ptr<Callback1<const std::vector<IndexedDBInfo>& >::Type >
+ callback_;
+
+ std::map<const FilePath::StringType, bool> files_;
+
+ std::vector<IndexedDBInfo> response_;
+};
+
+#endif // CHROME_BROWSER_MOCK_BROWSING_DATA_INDEXED_DB_HELPER_H_
diff --git a/chrome/browser/mock_browsing_data_local_storage_helper.h b/chrome/browser/mock_browsing_data_local_storage_helper.h
index 9183310..0dba0b1 100644
--- a/chrome/browser/mock_browsing_data_local_storage_helper.h
+++ b/chrome/browser/mock_browsing_data_local_storage_helper.h
@@ -4,11 +4,12 @@
#ifndef CHROME_BROWSER_MOCK_BROWSING_DATA_LOCAL_STORAGE_HELPER_H_
#define CHROME_BROWSER_MOCK_BROWSING_DATA_LOCAL_STORAGE_HELPER_H_
+#pragma once
#include <map>
+#include <vector>
#include "base/callback.h"
-
#include "chrome/browser/browsing_data_local_storage_helper.h"
// Mock for BrowsingDataLocalStorageHelper.
diff --git a/chrome/browser/mock_configuration_policy_provider.h b/chrome/browser/mock_configuration_policy_provider.h
deleted file mode 100644
index 8a78b24..0000000
--- a/chrome/browser/mock_configuration_policy_provider.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_MOCK_CONFIGURATION_POLICY_PROVIDER_H_
-#define CHROME_BROWSER_MOCK_CONFIGURATION_POLICY_PROVIDER_H_
-
-#include <map>
-
-#include "base/stl_util-inl.h"
-#include "chrome/browser/configuration_policy_provider.h"
-
-// Mock ConfigurationPolicyProvider implementation that supplies canned
-// values for polices.
-class MockConfigurationPolicyProvider : public ConfigurationPolicyProvider {
- public:
- MockConfigurationPolicyProvider() {}
- ~MockConfigurationPolicyProvider() {
- STLDeleteValues(&policy_map_);
- }
-
- typedef std::map<ConfigurationPolicyStore::PolicyType, Value*> PolicyMap;
-
- void AddPolicy(ConfigurationPolicyStore::PolicyType policy, Value* value) {
- policy_map_[policy] = value;
- }
-
- // ConfigurationPolicyProvider method overrides.
- virtual bool Provide(ConfigurationPolicyStore* store) {
- for (PolicyMap::const_iterator current = policy_map_.begin();
- current != policy_map_.end(); ++current) {
- store->Apply(current->first, current->second->DeepCopy());
- }
- return true;
- }
-
- private:
- PolicyMap policy_map_;
-};
-
-#endif // CHROME_BROWSER_MOCK_CONFIGURATION_POLICY_PROVIDER_H_
-
diff --git a/chrome/browser/mock_configuration_policy_store.h b/chrome/browser/mock_configuration_policy_store.h
deleted file mode 100644
index b1f3696..0000000
--- a/chrome/browser/mock_configuration_policy_store.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_MOCK_CONFIGURATION_POLICY_STORE_H_
-#define CHROME_BROWSER_MOCK_CONFIGURATION_POLICY_STORE_H_
-
-#include <map>
-
-#include "base/stl_util-inl.h"
-#include "chrome/browser/configuration_policy_store.h"
-
-// Mock ConfigurationPolicyStore implementation that records values for policy
-// settings as they get set.
-class MockConfigurationPolicyStore : public ConfigurationPolicyStore {
- public:
- MockConfigurationPolicyStore() {}
- ~MockConfigurationPolicyStore() {
- STLDeleteValues(&policy_map_);
- }
-
- typedef std::map<ConfigurationPolicyStore::PolicyType, Value*> PolicyMap;
- const PolicyMap& policy_map() { return policy_map_; }
-
- // ConfigurationPolicyStore implementation.
- virtual void Apply(PolicyType policy, Value* value) {
- policy_map_[policy] = value;
- }
-
- private:
- PolicyMap policy_map_;
-};
-
-#endif // CHROME_BROWSER_MOCK_CONFIGURATION_POLICY_STORE_H_
diff --git a/chrome/browser/mock_plugin_exceptions_table_model.cc b/chrome/browser/mock_plugin_exceptions_table_model.cc
new file mode 100644
index 0000000..fe5c904
--- /dev/null
+++ b/chrome/browser/mock_plugin_exceptions_table_model.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/mock_plugin_exceptions_table_model.h"
+
+#include "chrome/common/plugin_group.h"
+
+void MockPluginExceptionsTableModel::set_plugins(
+ const PluginUpdater::PluginMap& plugins) {
+ plugins_ = plugins;
+}
+
+void MockPluginExceptionsTableModel::GetPlugins(
+ PluginUpdater::PluginMap* plugins) {
+ *plugins = plugins_;
+}
diff --git a/chrome/browser/mock_plugin_exceptions_table_model.h b/chrome/browser/mock_plugin_exceptions_table_model.h
new file mode 100644
index 0000000..eea5a4d
--- /dev/null
+++ b/chrome/browser/mock_plugin_exceptions_table_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_MOCK_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
+#define CHROME_BROWSER_MOCK_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
+#pragma once
+
+#include <vector>
+
+#include "chrome/browser/plugin_exceptions_table_model.h"
+
+class MockPluginExceptionsTableModel : public PluginExceptionsTableModel {
+ public:
+ MockPluginExceptionsTableModel(HostContentSettingsMap* map,
+ HostContentSettingsMap* otr_map)
+ : PluginExceptionsTableModel(map, otr_map) {}
+ virtual ~MockPluginExceptionsTableModel() {}
+
+ void set_plugins(const PluginUpdater::PluginMap& plugins);
+
+ protected:
+ virtual void GetPlugins(PluginUpdater::PluginMap* plugins);
+
+ private:
+ PluginUpdater::PluginMap 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 d566b86..715edd9 100644
--- a/chrome/browser/modal_html_dialog_delegate.cc
+++ b/chrome/browser/modal_html_dialog_delegate.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
+#include "gfx/size.h"
ModalHtmlDialogDelegate::ModalHtmlDialogDelegate(
const GURL& url, int width, int height, const std::string& json_arguments,
diff --git a/chrome/browser/modal_html_dialog_delegate.h b/chrome/browser/modal_html_dialog_delegate.h
index 85415ea..54809ba 100644
--- a/chrome/browser/modal_html_dialog_delegate.h
+++ b/chrome/browser/modal_html_dialog_delegate.h
@@ -4,13 +4,21 @@
#ifndef CHROME_BROWSER_MODAL_HTML_DIALOG_DELEGATE_H_
#define CHROME_BROWSER_MODAL_HTML_DIALOG_DELEGATE_H_
+#pragma once
#include <vector>
#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "gfx/size.h"
-#include "ipc/ipc_message.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace IPC {
+class Message;
+}
// This class can only be used on the UI thread.
class ModalHtmlDialogDelegate
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.cc b/chrome/browser/nacl_host/nacl_broker_host_win.cc
index f479030..7cd9bf2 100644
--- a/chrome/browser/nacl_host/nacl_broker_host_win.cc
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.cc
@@ -44,11 +44,10 @@ bool NaClBrokerHost::Init() {
CommandLine* cmd_line = new CommandLine(nacl_path);
nacl::CopyNaClCommandLineArguments(cmd_line);
- cmd_line->AppendSwitchWithValue(switches::kProcessType,
- switches::kNaClBrokerProcess);
+ cmd_line->AppendSwitchASCII(switches::kProcessType,
+ switches::kNaClBrokerProcess);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
BrowserChildProcessHost::Launch(FilePath(), cmd_line);
return true;
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.h b/chrome/browser/nacl_host/nacl_broker_host_win.h
index 8668328..9e07e3e 100644
--- a/chrome/browser/nacl_host/nacl_broker_host_win.h
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NACL_HOST_NACL_BROKER_HOST_WIN_H_
#define CHROME_BROWSER_NACL_HOST_NACL_BROKER_HOST_WIN_H_
+#pragma once
#include "base/basictypes.h"
#include "base/process.h"
diff --git a/chrome/browser/nacl_host/nacl_broker_service_win.h b/chrome/browser/nacl_host/nacl_broker_service_win.h
index cb5b4c0..f4dcbca 100644
--- a/chrome/browser/nacl_host/nacl_broker_service_win.h
+++ b/chrome/browser/nacl_host/nacl_broker_service_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_WIN_H_
#define CHROME_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_WIN_H_
+#pragma once
#include <map>
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index fb844d8..1ee53b9 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -11,6 +11,7 @@
#endif
#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
@@ -25,13 +26,27 @@
#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
#endif
+namespace {
+
+#if !defined(DISABLE_NACL)
+void SetCloseOnExec(nacl::Handle fd) {
+#if defined(OS_POSIX)
+ int flags = fcntl(fd, F_GETFD);
+ CHECK(flags != -1);
+ int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ CHECK(rc == 0);
+#endif
+}
+#endif
+
+} // namespace
+
NaClProcessHost::NaClProcessHost(
ResourceDispatcherHost *resource_dispatcher_host,
const std::wstring& url)
: BrowserChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host),
resource_dispatcher_host_(resource_dispatcher_host),
reply_msg_(NULL),
- descriptor_(0),
running_on_wow64_(false) {
set_name(url);
#if defined(OS_WIN)
@@ -43,6 +58,18 @@ NaClProcessHost::~NaClProcessHost() {
if (!reply_msg_)
return;
+ // nacl::Close() is not available at link time if DISABLE_NACL is
+ // defined, but we still compile a bunch of other code from this
+ // file anyway. TODO(mseaborn): Make this less messy.
+#ifndef DISABLE_NACL
+ for (size_t i = 0; i < sockets_for_renderer_.size(); i++) {
+ nacl::Close(sockets_for_renderer_[i]);
+ }
+ for (size_t i = 0; i < sockets_for_sel_ldr_.size(); i++) {
+ nacl::Close(sockets_for_sel_ldr_[i]);
+ }
+#endif
+
// OnProcessLaunched didn't get called because the process couldn't launch.
// Don't keep the renderer hanging.
reply_msg_->set_reply_error();
@@ -50,20 +77,41 @@ NaClProcessHost::~NaClProcessHost() {
}
bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter,
- const int descriptor,
+ int socket_count,
IPC::Message* reply_msg) {
#ifdef DISABLE_NACL
NOTIMPLEMENTED() << "Native Client disabled at build time";
return false;
#else
- // Create a connected socket
- if (nacl::SocketPair(pair_) == -1)
+ // Place an arbitrary limit on the number of sockets to limit
+ // exposure in case the renderer is compromised. We can increase
+ // this if necessary.
+ if (socket_count > 8) {
return false;
+ }
+
+ // Rather than creating a socket pair in the renderer, and passing
+ // one side through the browser to sel_ldr, socket pairs are created
+ // in the browser and then passed to the renderer and sel_ldr.
+ //
+ // This is mainly for the benefit of Windows, where sockets cannot
+ // be passed in messages, but are copied via DuplicateHandle().
+ // This means the sandboxed renderer cannot send handles to the
+ // browser process.
+
+ for (int i = 0; i < socket_count; i++) {
+ nacl::Handle pair[2];
+ // Create a connected socket
+ if (nacl::SocketPair(pair) == -1)
+ return false;
+ sockets_for_renderer_.push_back(pair[0]);
+ sockets_for_sel_ldr_.push_back(pair[1]);
+ SetCloseOnExec(pair[0]);
+ SetCloseOnExec(pair[1]);
+ }
// Launch the process
- descriptor_ = descriptor;
if (!LaunchSelLdr()) {
- nacl::Close(pair_[0]);
return false;
}
@@ -86,11 +134,10 @@ bool NaClProcessHost::LaunchSelLdr() {
CommandLine* cmd_line = new CommandLine(exe_path);
nacl::CopyNaClCommandLineArguments(cmd_line);
- cmd_line->AppendSwitchWithValue(switches::kProcessType,
- switches::kNaClLoaderProcess);
+ cmd_line->AppendSwitchASCII(switches::kProcessType,
+ switches::kNaClLoaderProcess);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
// On Windows we might need to start the broker process to launch a new loader
#if defined(OS_WIN)
@@ -129,22 +176,34 @@ void NaClProcessHost::OnChildDied() {
}
void NaClProcessHost::OnProcessLaunched() {
- nacl::FileDescriptor imc_handle;
+ std::vector<nacl::FileDescriptor> handles_for_renderer;
base::ProcessHandle nacl_process_handle;
+
+ for (size_t i = 0; i < sockets_for_renderer_.size(); i++) {
#if defined(OS_WIN)
- // Duplicate the IMC handle
- // We assume the size of imc_handle has the same size as HANDLE, so the cast
- // below is safe.
- DCHECK(sizeof(HANDLE) == sizeof(imc_handle));
- DuplicateHandle(base::GetCurrentProcessHandle(),
- reinterpret_cast<HANDLE>(pair_[0]),
- resource_message_filter_->handle(),
- reinterpret_cast<HANDLE*>(&imc_handle),
- GENERIC_READ | GENERIC_WRITE,
- FALSE,
- DUPLICATE_CLOSE_SOURCE);
+ // Copy the handle into the renderer process.
+ HANDLE handle_in_renderer;
+ DuplicateHandle(base::GetCurrentProcessHandle(),
+ reinterpret_cast<HANDLE>(sockets_for_renderer_[i]),
+ resource_message_filter_->handle(),
+ &handle_in_renderer,
+ GENERIC_READ | GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_CLOSE_SOURCE);
+ handles_for_renderer.push_back(
+ reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
+#else
+ // No need to dup the imc_handle - we don't pass it anywhere else so
+ // it cannot be closed.
+ nacl::FileDescriptor imc_handle;
+ imc_handle.fd = sockets_for_renderer_[i];
+ imc_handle.auto_close = true;
+ handles_for_renderer.push_back(imc_handle);
+#endif
+ }
- // Duplicate the process handle
+#if defined(OS_WIN)
+ // Copy the process handle into the renderer process.
DuplicateHandle(base::GetCurrentProcessHandle(),
handle(),
resource_message_filter_->handle(),
@@ -153,16 +212,6 @@ void NaClProcessHost::OnProcessLaunched() {
FALSE,
0);
#else
- int flags = fcntl(pair_[0], F_GETFD);
- if (flags != -1) {
- flags |= FD_CLOEXEC;
- fcntl(pair_[0], F_SETFD, flags);
- }
- // No need to dup the imc_handle - we don't pass it anywhere else so
- // it cannot be closed.
- imc_handle.fd = pair_[0];
- imc_handle.auto_close = true;
-
// We use pid as process handle on Posix
nacl_process_handle = handle();
#endif
@@ -171,30 +220,40 @@ void NaClProcessHost::OnProcessLaunched() {
base::ProcessId nacl_process_id = base::GetProcId(handle());
ViewHostMsg_LaunchNaCl::WriteReplyParams(
- reply_msg_, imc_handle, nacl_process_handle, nacl_process_id);
+ reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
resource_message_filter_->Send(reply_msg_);
resource_message_filter_ = NULL;
reply_msg_ = NULL;
+ sockets_for_renderer_.clear();
SendStartMessage();
}
void NaClProcessHost::SendStartMessage() {
- nacl::FileDescriptor channel;
+ std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
+ for (size_t i = 0; i < sockets_for_sel_ldr_.size(); i++) {
#if defined(OS_WIN)
- if (!DuplicateHandle(GetCurrentProcess(),
- reinterpret_cast<HANDLE>(pair_[1]),
- handle(),
- reinterpret_cast<HANDLE*>(&channel),
- GENERIC_READ | GENERIC_WRITE,
- FALSE, DUPLICATE_CLOSE_SOURCE)) {
- return;
- }
+ HANDLE channel;
+ if (!DuplicateHandle(GetCurrentProcess(),
+ reinterpret_cast<HANDLE>(sockets_for_sel_ldr_[i]),
+ handle(),
+ &channel,
+ GENERIC_READ | GENERIC_WRITE,
+ FALSE, DUPLICATE_CLOSE_SOURCE)) {
+ return;
+ }
+ handles_for_sel_ldr.push_back(
+ reinterpret_cast<nacl::FileDescriptor>(channel));
#else
- channel.fd = dup(pair_[1]);
- channel.auto_close = true;
+ nacl::FileDescriptor channel;
+ channel.fd = dup(sockets_for_sel_ldr_[i]);
+ channel.auto_close = true;
+ handles_for_sel_ldr.push_back(channel);
#endif
- Send(new NaClProcessMsg_Start(descriptor_, channel));
+ }
+
+ Send(new NaClProcessMsg_Start(handles_for_sel_ldr));
+ sockets_for_sel_ldr_.clear();
}
void NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
index cae117b..618492a 100644
--- a/chrome/browser/nacl_host/nacl_process_host.h
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NACL_HOST_NACL_PROCESS_HOST_H_
#define CHROME_BROWSER_NACL_HOST_NACL_PROCESS_HOST_H_
+#pragma once
#include "build/build_config.h"
@@ -28,7 +29,7 @@ class NaClProcessHost : public BrowserChildProcessHost {
// Initialize the new NaCl process, returning true on success.
bool Launch(ResourceMessageFilter* resource_message_filter,
- const int descriptor,
+ int socket_count,
IPC::Message* reply_msg);
virtual void OnMessageReceived(const IPC::Message& msg);
@@ -68,11 +69,9 @@ class NaClProcessHost : public BrowserChildProcessHost {
// The reply message to send.
IPC::Message* reply_msg_;
- // The socket pair for the NaCl process.
- nacl::Handle pair_[2];
-
- // The NaCl specific descriptor for this process.
- int descriptor_;
+ // Socket pairs for the NaCl process and renderer.
+ std::vector<nacl::Handle> sockets_for_renderer_;
+ std::vector<nacl::Handle> sockets_for_sel_ldr_;
// Windows platform flag
bool running_on_wow64_;
diff --git a/chrome/browser/nacl_loader.sb b/chrome/browser/nacl_loader.sb
index 6c476d7..38cb29c 100644
--- a/chrome/browser/nacl_loader.sb
+++ b/chrome/browser/nacl_loader.sb
@@ -12,14 +12,3 @@
; Allow a Native Client application to use semaphores, specifically
; sem_init(), et.al.
(allow ipc-posix-sem)
-
-; Needed for the Native Client plugin and loader.
-; TODO(msneck): Refactor Native Client to use something other than Unix
-; sockets.
-; See http://code.google.com/p/nativeclient/issues/detail?id=344
-;BEFORE_10.6 (allow network-inbound (from unix-socket))
-;BEFORE_10.6 (allow network-outbound (to unix-socket))
-;10.6_ONLY (allow network-inbound (regex #"^(/private)?/tmp/nacl-"))
-;10.6_ONLY (allow network-outbound (regex #"^(/private)?/tmp/nacl-"))
-;10.6_ONLY (allow network-bind (local ip4))
-;10.6_ONLY (allow file-write* (regex #"^(/private)?/tmp/nacl-"))
diff --git a/chrome/browser/native_app_modal_dialog.h b/chrome/browser/native_app_modal_dialog.h
new file mode 100644
index 0000000..7b4c5b2
--- /dev/null
+++ b/chrome/browser/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_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/browser_url_util.cc b/chrome/browser/net/browser_url_util.cc
index 24747b2..786ab7d 100644
--- a/chrome/browser/net/browser_url_util.cc
+++ b/chrome/browser/net/browser_url_util.cc
@@ -14,7 +14,7 @@
namespace chrome_browser_net {
void WriteURLToClipboard(const GURL& url,
- const std::wstring& languages,
+ const std::string& languages,
Clipboard *clipboard) {
if (url.is_empty() || !url.is_valid() || !clipboard)
return;
@@ -23,8 +23,8 @@ void WriteURLToClipboard(const GURL& url,
// may not encode non-ASCII characters in UTF-8. See crbug.com/2820.
string16 text = url.SchemeIs(chrome::kMailToScheme) ?
ASCIIToUTF16(url.path()) :
- WideToUTF16(net::FormatUrl(url, languages, net::kFormatUrlOmitNothing,
- UnescapeRule::NONE, NULL, NULL, NULL));
+ net::FormatUrl(url, languages, net::kFormatUrlOmitNothing,
+ UnescapeRule::NONE, NULL, NULL, NULL);
ScopedClipboardWriter scw(clipboard);
scw.WriteURL(text);
diff --git a/chrome/browser/net/browser_url_util.h b/chrome/browser/net/browser_url_util.h
index 955265b..043725f 100644
--- a/chrome/browser/net/browser_url_util.h
+++ b/chrome/browser/net/browser_url_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_BROWSER_URL_UTIL_H_
#define CHROME_BROWSER_NET_BROWSER_URL_UTIL_H_
+#pragma once
#include <string>
@@ -14,7 +15,7 @@ namespace chrome_browser_net {
// Writes a string representation of |url| to the system clipboard.
void WriteURLToClipboard(const GURL& url,
- const std::wstring& languages,
+ const std::string& languages,
Clipboard *clipboard);
} // namespace chrome_browser_net
diff --git a/chrome/browser/net/chrome_cookie_notification_details.h b/chrome/browser/net/chrome_cookie_notification_details.h
index e7b71dd..42542b0 100644
--- a/chrome/browser/net/chrome_cookie_notification_details.h
+++ b/chrome/browser/net/chrome_cookie_notification_details.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_CHROME_COOKIE_NOTIFICATION_DETAILS_H_
#define CHROME_BROWSER_NET_CHROME_COOKIE_NOTIFICATION_DETAILS_H_
+#pragma once
#include "net/base/cookie_monster.h"
diff --git a/chrome/browser/net/chrome_cookie_policy.cc b/chrome/browser/net/chrome_cookie_policy.cc
index 552fec7..da700e3 100644
--- a/chrome/browser/net/chrome_cookie_policy.cc
+++ b/chrome/browser/net/chrome_cookie_policy.cc
@@ -7,9 +7,7 @@
#include "base/string_util.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h"
#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/message_box_handler.h"
#include "net/base/net_errors.h"
#include "net/base/static_cookie_policy.h"
@@ -20,45 +18,6 @@ static const size_t kMaxCompletionsPerHost = 10000;
// ----------------------------------------------------------------------------
-// ChromeCookiePolicy cannot just subclass the delegate interface because we
-// may have several prompts pending.
-class ChromeCookiePolicy::PromptDelegate
- : public CookiePromptModalDialogDelegate {
- public:
- PromptDelegate(ChromeCookiePolicy* cookie_policy, const std::string& host)
- : cookie_policy_(cookie_policy),
- host_(host) {
- }
-
- // CookiesPromptViewDelegate methods:
- virtual void AllowSiteData(bool session_expire);
- virtual void BlockSiteData();
-
- private:
- void NotifyDone(int policy);
-
- scoped_refptr<ChromeCookiePolicy> cookie_policy_;
- std::string host_;
-};
-
-void ChromeCookiePolicy::PromptDelegate::AllowSiteData(bool session_expire) {
- int policy = net::OK;
- if (session_expire)
- policy = net::OK_FOR_SESSION_ONLY;
- NotifyDone(policy);
-}
-
-void ChromeCookiePolicy::PromptDelegate::BlockSiteData() {
- NotifyDone(net::ERR_ACCESS_DENIED);
-}
-
-void ChromeCookiePolicy::PromptDelegate::NotifyDone(int policy) {
- cookie_policy_->DidPromptForSetCookie(host_, policy);
- delete this;
-}
-
-// ----------------------------------------------------------------------------
-
ChromeCookiePolicy::ChromeCookiePolicy(HostContentSettingsMap* map)
: host_content_settings_map_(map) {
}
@@ -121,10 +80,7 @@ int ChromeCookiePolicy::CanSetCookie(const GURL& url,
DCHECK(callback);
- // Else, ask the user...
-
Completions& completions = host_completions_map_[url.host()];
-
if (completions.size() >= kMaxCompletionsPerHost) {
LOG(ERROR) << "Would exceed kMaxCompletionsPerHost";
policy = net::ERR_ACCESS_DENIED;
@@ -133,13 +89,12 @@ int ChromeCookiePolicy::CanSetCookie(const GURL& url,
policy = net::ERR_IO_PENDING;
}
- PromptForSetCookie(url, cookie_line);
return policy;
}
int ChromeCookiePolicy::CheckPolicy(const GURL& url) const {
ContentSetting setting = host_content_settings_map_->GetContentSetting(
- url, CONTENT_SETTINGS_TYPE_COOKIES);
+ url, CONTENT_SETTINGS_TYPE_COOKIES, "");
if (setting == CONTENT_SETTING_BLOCK)
return net::ERR_ACCESS_DENIED;
if (setting == CONTENT_SETTING_ALLOW)
@@ -149,75 +104,3 @@ int ChromeCookiePolicy::CheckPolicy(const GURL& url) const {
return net::ERR_IO_PENDING; // Need to prompt.
}
-void ChromeCookiePolicy::PromptForSetCookie(const GURL& url,
- const std::string& cookie_line) {
- if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &ChromeCookiePolicy::PromptForSetCookie, url,
- cookie_line));
- return;
- }
-
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- const std::string& host = url.host();
-
- // The policy may have changed (due to the "remember" option)
- int policy = CheckPolicy(url);
- if (policy != net::ERR_IO_PENDING) {
- DidPromptForSetCookie(host, policy);
- return;
- }
-
- // Show the prompt on top of the current tab.
- Browser* browser = BrowserList::GetLastActive();
- if (!browser || !browser->GetSelectedTabContents()) {
- DidPromptForSetCookie(host, net::ERR_ACCESS_DENIED);
- return;
- }
-
- RunCookiePrompt(browser->GetSelectedTabContents(),
- host_content_settings_map_, url, cookie_line,
- new PromptDelegate(this, host));
-}
-
-void ChromeCookiePolicy::DidPromptForSetCookie(const std::string& host,
- int policy) {
- if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(this, &ChromeCookiePolicy::DidPromptForSetCookie,
- host, policy));
- return;
- }
-
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-
- // Notify all callbacks, starting with the first until we hit another that
- // is for a 'set-cookie'.
- HostCompletionsMap::iterator it = host_completions_map_.find(host);
- CHECK(it != host_completions_map_.end());
-
- Completions& completions = it->second;
- CHECK(!completions.empty() && completions[0].is_set_cookie_request());
-
- // Gather the list of callbacks to notify, and remove them from the
- // completions list before handing control to the callbacks (in case
- // they should call back into us to modify host_completions_map_).
-
- std::vector<net::CompletionCallback*> callbacks;
- callbacks.push_back(completions[0].callback());
- size_t i = 1;
- for (; i < completions.size(); ++i) {
- if (completions[i].is_set_cookie_request())
- break;
- callbacks.push_back(completions[i].callback());
- }
- completions.erase(completions.begin(), completions.begin() + i);
-
- if (completions.empty())
- host_completions_map_.erase(it);
-
- for (size_t j = 0; j < callbacks.size(); ++j)
- callbacks[j]->Run(policy);
-}
diff --git a/chrome/browser/net/chrome_cookie_policy.h b/chrome/browser/net/chrome_cookie_policy.h
index 92afcdb..ea63e6b 100644
--- a/chrome/browser/net/chrome_cookie_policy.h
+++ b/chrome/browser/net/chrome_cookie_policy.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_NET_CHROME_COOKIE_POLICY_H_
#define CHROME_BROWSER_NET_CHROME_COOKIE_POLICY_H_
+#pragma once
#include <map>
-#include <queue>
#include <string>
#include <vector>
@@ -38,9 +38,6 @@ class ChromeCookiePolicy
net::CompletionCallback* callback);
private:
- class PromptDelegate;
- friend class PromptDelegate;
-
class Completion {
public:
static Completion ForSetCookie(net::CompletionCallback* callback) {
@@ -67,8 +64,6 @@ class ChromeCookiePolicy
typedef std::map<std::string, Completions> HostCompletionsMap;
int CheckPolicy(const GURL& url) const;
- void PromptForSetCookie(const GURL& url, const std::string& cookie_line);
- void DidPromptForSetCookie(const std::string& host, int result);
// A map from hostname to callbacks awaiting a cookie policy response.
// This map is only accessed on the IO thread.
diff --git a/chrome/browser/net/chrome_net_log.cc b/chrome/browser/net/chrome_net_log.cc
index a696552..1003dfa 100644
--- a/chrome/browser/net/chrome_net_log.cc
+++ b/chrome/browser/net/chrome_net_log.cc
@@ -6,11 +6,16 @@
#include <algorithm>
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/browser/chrome_thread.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::ChromeNetLog()
: next_id_(1),
@@ -19,12 +24,21 @@ ChromeNetLog::ChromeNetLog()
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
AddObserver(passive_collector_.get());
AddObserver(load_timing_observer_.get());
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kLogNetLog)) {
+ net_log_logger_.reset(new NetLogLogger());
+ AddObserver(net_log_logger_.get());
+ }
}
ChromeNetLog::~ChromeNetLog() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
RemoveObserver(passive_collector_.get());
RemoveObserver(load_timing_observer_.get());
+ if (net_log_logger_.get()) {
+ RemoveObserver(net_log_logger_.get());
+ }
}
void ChromeNetLog::AddEntry(EventType type,
@@ -32,7 +46,11 @@ void ChromeNetLog::AddEntry(EventType type,
const Source& source,
EventPhase phase,
EventParameters* params) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ // 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(ChromeThread::CurrentlyOn(ChromeThread::IO) ||
+ !ChromeThread::IsMessageLoopValid(ChromeThread::IO));
// Notify all of the log observers.
FOR_EACH_OBSERVER(Observer, observers_,
@@ -44,10 +62,18 @@ uint32 ChromeNetLog::NextID() {
return next_id_++;
}
-bool ChromeNetLog::HasListener() const {
+net::NetLog::LogLevel ChromeNetLog::GetLogLevel() const {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- // (Don't count the PassiveLogCollector observer).
- return observers_.size() > 1;
+
+ // 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;
+ while ((observer = it.GetNext()) != NULL) {
+ log_level = std::min(log_level, observer->log_level());
+ }
+ return log_level;
}
void ChromeNetLog::AddObserver(Observer* observer) {
diff --git a/chrome/browser/net/chrome_net_log.h b/chrome/browser/net/chrome_net_log.h
index ee9cd22..24183bf 100644
--- a/chrome/browser/net/chrome_net_log.h
+++ b/chrome/browser/net/chrome_net_log.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_NET_CHROME_NET_LOG_H_
#define CHROME_BROWSER_NET_CHROME_NET_LOG_H_
+#pragma once
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
#include "net/base/net_log.h"
class LoadTimingObserver;
+class NetLogLogger;
class PassiveLogCollector;
// ChromeNetLog is an implementation of NetLog that dispatches network log
@@ -26,12 +28,26 @@ class ChromeNetLog : public net::NetLog {
// Interface for observing the events logged by the network stack.
class Observer {
public:
+ // Constructs an observer that wants to see network events, with
+ // the specified minimum event granularity.
+ //
+ // 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);
+
virtual ~Observer() {}
virtual void OnAddEntry(EventType type,
const base::TimeTicks& time,
const Source& source,
EventPhase phase,
EventParameters* params) = 0;
+ LogLevel log_level() const { return log_level_; }
+ private:
+ LogLevel log_level_;
+ DISALLOW_COPY_AND_ASSIGN(Observer);
};
ChromeNetLog();
@@ -44,7 +60,7 @@ class ChromeNetLog : public net::NetLog {
EventPhase phase,
EventParameters* params);
virtual uint32 NextID();
- virtual bool HasListener() const;
+ virtual LogLevel GetLogLevel() const;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
@@ -61,7 +77,11 @@ class ChromeNetLog : public net::NetLog {
uint32 next_id_;
scoped_ptr<PassiveLogCollector> passive_collector_;
scoped_ptr<LoadTimingObserver> load_timing_observer_;
- ObserverList<Observer, true> observers_;
+ 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_;
DISALLOW_COPY_AND_ASSIGN(ChromeNetLog);
};
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 0944559..a657b26 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -13,6 +13,6 @@ ChromeNetworkDelegate::~ChromeNetworkDelegate() {}
void ChromeNetworkDelegate::OnSendHttpRequest(
net::HttpRequestHeaders* headers) {
DCHECK(headers);
-
+
// TODO(willchan): Add Chrome-side hooks to listen / mutate requests here.
}
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h
index 75de4c7..55336d6 100644
--- a/chrome/browser/net/chrome_network_delegate.h
+++ b/chrome/browser/net/chrome_network_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_CHROME_NETWORK_DELEGATE_H_
#define CHROME_BROWSER_NET_CHROME_NETWORK_DELEGATE_H_
+#pragma once
#include "base/basictypes.h"
#include "net/http/http_network_delegate.h"
@@ -27,4 +28,4 @@ class ChromeNetworkDelegate : public net::HttpNetworkDelegate {
DISALLOW_COPY_AND_ASSIGN(ChromeNetworkDelegate);
};
-#endif // CHROME_BROWSER_NET_CHROME_NETWORK_DELEGATE_H_
+#endif // CHROME_BROWSER_NET_CHROME_NETWORK_DELEGATE_H_
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc
index 17197a4..88f8ee0 100644
--- a/chrome/browser/net/chrome_url_request_context.cc
+++ b/chrome/browser/net/chrome_url_request_context.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
@@ -39,6 +40,10 @@
#include "net/ocsp/nss_ocsp.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/proxy_config_service.h"
+#endif // defined(OS_CHROMEOS)
+
namespace {
// ----------------------------------------------------------------------------
@@ -57,22 +62,27 @@ void CheckCurrentlyOnMainThread() {
// Helper methods to initialize proxy
// ----------------------------------------------------------------------------
-net::ProxyConfigService* CreateProxyConfigService(
- const PrefService* pref_service) {
+net::ProxyConfigService* CreateProxyConfigService(Profile* profile) {
// The linux gconf-based proxy settings getter relies on being initialized
// from the UI thread.
CheckCurrentlyOnMainThread();
- scoped_ptr<net::ProxyConfig> proxy_config(CreateProxyConfig(pref_service));
+ scoped_ptr<net::ProxyConfig> proxy_config(CreateProxyConfig(
+ profile->GetPrefs()));
if (!proxy_config.get()) {
// Use system settings.
// TODO(port): the IO and FILE message loops are only used by Linux. Can
// that code be moved to chrome/browser instead of being in net, so that it
// can use ChromeThread instead of raw MessageLoop pointers? See bug 25354.
+#if defined(OS_CHROMEOS)
+ return new chromeos::ProxyConfigService(
+ profile->GetChromeOSProxyConfigServiceImpl());
+#else
return net::ProxyService::CreateSystemProxyConfigService(
g_browser_process->io_thread()->message_loop(),
g_browser_process->file_thread()->message_loop());
+#endif // defined(OS_CHROMEOS)
}
// Otherwise use the fixed settings from the command line.
@@ -105,7 +115,7 @@ net::ProxyService* CreateProxyService(
// Parse the switch (it should be a positive integer formatted as decimal).
int n;
- if (StringToInt(s, &n) && n > 0) {
+ if (base::StringToInt(s, &n) && n > 0) {
num_pac_threads = static_cast<size_t>(n);
} else {
LOG(ERROR) << "Invalid switch for number of PAC threads: " << s;
@@ -224,7 +234,7 @@ class FactoryForOriginal : public ChromeURLRequestContextFactory {
// We need to initialize the ProxyConfigService from the UI thread
// because on linux it relies on initializing things through gconf,
// and needs to be on the main thread.
- proxy_config_service_(CreateProxyConfigService(profile->GetPrefs())) {
+ proxy_config_service_(CreateProxyConfigService(profile)) {
}
virtual ChromeURLRequestContext* Create();
@@ -301,9 +311,7 @@ ChromeURLRequestContext* FactoryForOriginal::Create() {
context->set_cookie_policy(
new ChromeCookiePolicy(host_content_settings_map_));
- // Create a new AppCacheService.
- context->set_appcache_service(
- new ChromeAppCacheService(profile_dir_path_, context));
+ appcache_service_->set_request_context(context);
#if defined(USE_NSS)
// TODO(ukai): find a better way to set the URLRequestContext for OCSP.
@@ -317,15 +325,18 @@ ChromeURLRequestContext* FactoryForOriginal::Create() {
// Factory that creates the ChromeURLRequestContext for extensions.
class FactoryForExtensions : public ChromeURLRequestContextFactory {
public:
- FactoryForExtensions(Profile* profile, const FilePath& cookie_store_path)
+ FactoryForExtensions(Profile* profile, const FilePath& cookie_store_path,
+ bool incognito)
: ChromeURLRequestContextFactory(profile),
- cookie_store_path_(cookie_store_path) {
+ cookie_store_path_(cookie_store_path),
+ incognito_(incognito) {
}
virtual ChromeURLRequestContext* Create();
private:
FilePath cookie_store_path_;
+ bool incognito_;
};
ChromeURLRequestContext* FactoryForExtensions::Create() {
@@ -334,11 +345,14 @@ ChromeURLRequestContext* FactoryForExtensions::Create() {
IOThread::Globals* io_thread_globals = io_thread()->globals();
- // All we care about for extensions is the cookie store.
- DCHECK(!cookie_store_path_.empty());
+ // All we care about for extensions is the cookie store. For incognito, we
+ // use a non-persistent cookie store.
+ scoped_refptr<SQLitePersistentCookieStore> cookie_db = NULL;
+ if (!incognito_) {
+ DCHECK(!cookie_store_path_.empty());
+ cookie_db = new SQLitePersistentCookieStore(cookie_store_path_);
+ }
- scoped_refptr<SQLitePersistentCookieStore> cookie_db =
- new SQLitePersistentCookieStore(cookie_store_path_);
net::CookieMonster* cookie_monster =
new net::CookieMonster(cookie_db.get(), NULL);
@@ -409,9 +423,7 @@ ChromeURLRequestContext* FactoryForOffTheRecord::Create() {
context->set_ftp_transaction_factory(
new net::FtpNetworkLayer(context->host_resolver()));
- // Create a separate AppCacheService for OTR mode.
- context->set_appcache_service(
- new ChromeAppCacheService(profile_dir_path_, context));
+ appcache_service_->set_request_context(context);
context->set_net_log(io_thread_globals->net_log.get());
return context;
@@ -500,9 +512,7 @@ ChromeURLRequestContext* FactoryForMedia::Create() {
cache->set_enable_range_support(false);
context->set_http_transaction_factory(cache);
-
- // Use the same appcache service as the profile's main context.
- context->set_appcache_service(main_context->appcache_service());
+ context->set_net_log(io_thread_globals->net_log.get());
return context;
}
@@ -516,8 +526,7 @@ ChromeURLRequestContext* FactoryForMedia::Create() {
ChromeURLRequestContextGetter::ChromeURLRequestContextGetter(
Profile* profile,
ChromeURLRequestContextFactory* factory)
- : prefs_(NULL),
- factory_(factory),
+ : factory_(factory),
url_request_context_(NULL) {
DCHECK(factory);
@@ -529,7 +538,7 @@ ChromeURLRequestContextGetter::ChromeURLRequestContextGetter(
ChromeURLRequestContextGetter::~ChromeURLRequestContextGetter() {
CheckCurrentlyOnIOThread();
- DCHECK(!prefs_) << "Probably didn't call CleanupOnUIThread";
+ DCHECK(registrar_.IsEmpty()) << "Probably didn't call CleanupOnUIThread";
// Either we already transformed the factory into a URLRequestContext, or
// we still have a pending factory.
@@ -620,7 +629,7 @@ ChromeURLRequestContextGetter::CreateOriginalForExtensions(
DCHECK(!profile->IsOffTheRecord());
return new ChromeURLRequestContextGetter(
profile,
- new FactoryForExtensions(profile, cookie_store_path));
+ new FactoryForExtensions(profile, cookie_store_path, false));
}
// static
@@ -631,15 +640,19 @@ ChromeURLRequestContextGetter::CreateOffTheRecord(Profile* profile) {
profile, new FactoryForOffTheRecord(profile));
}
+// static
+ChromeURLRequestContextGetter*
+ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(
+ Profile* profile) {
+ DCHECK(profile->IsOffTheRecord());
+ return new ChromeURLRequestContextGetter(
+ profile, new FactoryForExtensions(profile, FilePath(), true));
+}
+
void ChromeURLRequestContextGetter::CleanupOnUIThread() {
CheckCurrentlyOnMainThread();
-
- if (prefs_) {
- // Unregister for pref notifications.
- prefs_->RemovePrefObserver(prefs::kAcceptLanguages, this);
- prefs_->RemovePrefObserver(prefs::kDefaultCharset, this);
- prefs_ = NULL;
- }
+ // Unregister for pref notifications.
+ registrar_.RemoveAll();
}
void ChromeURLRequestContextGetter::OnNewExtensions(
@@ -661,7 +674,7 @@ void ChromeURLRequestContextGetter::Observe(
CheckCurrentlyOnMainThread();
if (NotificationType::PREF_CHANGED == type) {
- std::wstring* pref_name_in = Details<std::wstring>(details).ptr();
+ 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::kAcceptLanguages) {
@@ -691,10 +704,9 @@ void ChromeURLRequestContextGetter::Observe(
void ChromeURLRequestContextGetter::RegisterPrefsObserver(Profile* profile) {
CheckCurrentlyOnMainThread();
- prefs_ = profile->GetPrefs();
-
- prefs_->AddPrefObserver(prefs::kAcceptLanguages, this);
- prefs_->AddPrefObserver(prefs::kDefaultCharset, this);
+ registrar_.Init(profile->GetPrefs());
+ registrar_.Add(prefs::kAcceptLanguages, this);
+ registrar_.Add(prefs::kDefaultCharset, this);
}
// static
@@ -732,7 +744,9 @@ void ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper(
// ChromeURLRequestContext
// ----------------------------------------------------------------------------
-ChromeURLRequestContext::ChromeURLRequestContext() {
+ChromeURLRequestContext::ChromeURLRequestContext()
+ : is_media_(false),
+ is_off_the_record_(false) {
CheckCurrentlyOnIOThread();
}
@@ -787,6 +801,18 @@ FilePath ChromeURLRequestContext::GetPathForExtension(const std::string& id) {
return FilePath();
}
+bool ChromeURLRequestContext::ExtensionHasWebExtent(const std::string& id) {
+ ExtensionInfoMap::iterator iter = extension_info_.find(id);
+ return iter != extension_info_.end() && !iter->second->extent.is_empty();
+}
+
+bool ChromeURLRequestContext::ExtensionCanLoadInIncognito(
+ const std::string& id) {
+ ExtensionInfoMap::iterator iter = extension_info_.find(id);
+ // Only split-mode extensions can load in incognito profiles.
+ return iter != extension_info_.end() && iter->second->incognito_split_mode;
+}
+
std::string ChromeURLRequestContext::GetDefaultLocaleForExtension(
const std::string& id) {
ExtensionInfoMap::iterator iter = extension_info_.find(id);
@@ -797,6 +823,17 @@ std::string ChromeURLRequestContext::GetDefaultLocaleForExtension(
return result;
}
+ExtensionExtent
+ ChromeURLRequestContext::GetEffectiveHostPermissionsForExtension(
+ const std::string& id) {
+ ExtensionInfoMap::iterator iter = extension_info_.find(id);
+ ExtensionExtent result;
+ if (iter != extension_info_.end())
+ result = iter->second->effective_host_permissions;
+
+ return result;
+}
+
bool ChromeURLRequestContext::CheckURLAccessToExtensionPermission(
const GURL& url,
const char* permission_name) {
@@ -817,10 +854,21 @@ bool ChromeURLRequestContext::CheckURLAccessToExtensionPermission(
if (info == extension_info_.end())
return false;
- std::vector<std::string>& api_permissions = info->second->api_permissions;
- return std::find(api_permissions.begin(),
- api_permissions.end(),
- permission_name) != api_permissions.end();
+ std::set<std::string>& api_permissions = info->second->api_permissions;
+ return api_permissions.count(permission_name) != 0;
+}
+
+bool ChromeURLRequestContext::URLIsForExtensionIcon(const GURL& url) {
+ DCHECK(url.SchemeIs(chrome::kExtensionScheme));
+
+ ExtensionInfoMap::iterator iter = extension_info_.find(url.host());
+ if (iter == extension_info_.end())
+ return false;
+
+ std::string path = url.path();
+ DCHECK(path.length() > 0 && path[0] == '/');
+ path = path.substr(1);
+ return iter->second->icons.ContainsPath(path);
}
const std::string& ChromeURLRequestContext::GetUserAgent(
@@ -830,24 +878,25 @@ const std::string& ChromeURLRequestContext::GetUserAgent(
void ChromeURLRequestContext::OnNewExtensions(const std::string& id,
ExtensionInfo* info) {
- if (!is_off_the_record_)
- extension_info_[id] = linked_ptr<ExtensionInfo>(info);
+ extension_info_[id] = linked_ptr<ExtensionInfo>(info);
}
void ChromeURLRequestContext::OnUnloadedExtension(const std::string& id) {
CheckCurrentlyOnIOThread();
- if (is_off_the_record_)
- return;
ExtensionInfoMap::iterator iter = extension_info_.find(id);
- DCHECK(iter != extension_info_.end());
- extension_info_.erase(iter);
+ if (iter != extension_info_.end()) {
+ extension_info_.erase(iter);
+ } else {
+ // NOTE: This can currently happen if we receive multiple unload
+ // notifications, e.g. setting incognito-enabled state for a
+ // disabled extension (e.g., via sync). See
+ // http://code.google.com/p/chromium/issues/detail?id=50582 .
+ NOTREACHED() << id;
+ }
}
-bool ChromeURLRequestContext::AreCookiesEnabled() const {
- ContentSetting setting =
- host_content_settings_map_->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES);
- return setting != CONTENT_SETTING_BLOCK;
+bool ChromeURLRequestContext::IsExternal() const {
+ return false;
}
ChromeURLRequestContext::ChromeURLRequestContext(
@@ -885,6 +934,8 @@ ChromeURLRequestContext::ChromeURLRequestContext(
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_;
+ file_system_host_context_ = other->file_system_host_context_;
}
void ChromeURLRequestContext::OnAcceptLanguageChange(
@@ -953,8 +1004,11 @@ ChromeURLRequestContextFactory::ChromeURLRequestContextFactory(Profile* profile)
(*iter)->name(),
(*iter)->path(),
(*iter)->default_locale(),
+ (*iter)->incognito_split_mode(),
(*iter)->web_extent(),
- (*iter)->api_permissions()));
+ (*iter)->GetEffectiveHostPermissions(),
+ (*iter)->api_permissions(),
+ (*iter)->icons()));
}
}
@@ -962,12 +1016,12 @@ ChromeURLRequestContextFactory::ChromeURLRequestContextFactory(Profile* profile)
user_script_dir_path_ = profile->GetUserScriptMaster()->user_script_dir();
ssl_config_service_ = profile->GetSSLConfigService();
-
profile_dir_path_ = profile->GetPath();
-
cookie_monster_delegate_ = new ChromeCookieMonsterDelegate(profile);
-
+ appcache_service_ = profile->GetAppCacheService();
database_tracker_ = profile->GetDatabaseTracker();
+ blob_storage_context_ = profile->GetBlobStorageContext();
+ file_system_host_context_ = profile->GetFileSystemHostContext();
}
ChromeURLRequestContextFactory::~ChromeURLRequestContextFactory() {
@@ -990,14 +1044,17 @@ void ChromeURLRequestContextFactory::ApplyProfileParametersToContext(
context->set_transport_security_state(
transport_security_state_);
context->set_ssl_config_service(ssl_config_service_);
+ context->set_appcache_service(appcache_service_);
context->set_database_tracker(database_tracker_);
+ context->set_blob_storage_context(blob_storage_context_);
+ context->set_file_system_host_context(file_system_host_context_);
}
// ----------------------------------------------------------------------------
net::ProxyConfig* CreateProxyConfig(const PrefService* pref_service) {
// Scan for all "enable" type proxy switches.
- static const wchar_t* proxy_prefs[] = {
+ static const char* proxy_prefs[] = {
prefs::kProxyPacUrl,
prefs::kProxyServer,
prefs::kProxyBypassList,
diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h
index 6964460..3141364 100644
--- a/chrome/browser/net/chrome_url_request_context.h
+++ b/chrome/browser/net/chrome_url_request_context.h
@@ -4,23 +4,29 @@
#ifndef CHROME_BROWSER_NET_CHROME_URL_REQUEST_CONTEXT_H_
#define CHROME_BROWSER_NET_CHROME_URL_REQUEST_CONTEXT_H_
+#pragma once
+#include <map>
#include <string>
#include <vector>
#include "base/file_path.h"
#include "base/linked_ptr.h"
-#include "net/base/cookie_monster.h"
-#include "net/base/cookie_policy.h"
#include "chrome/browser/appcache/chrome_appcache_service.h"
+#include "chrome/browser/chrome_blob_storage_context.h"
+#include "chrome/browser/file_system/file_system_host_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/pref_service.h"
#include "chrome/browser/net/chrome_cookie_policy.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/notification_registrar.h"
+#include "net/base/cookie_monster.h"
+#include "net/base/cookie_policy.h"
#include "net/url_request/url_request_context.h"
#include "webkit/database/database_tracker.h"
@@ -48,18 +54,31 @@ class ChromeURLRequestContext : public URLRequestContext {
// could be immutable and ref-counted so that we could use them directly from
// both threads. There is only a small amount of mutable state in Extension.
struct ExtensionInfo {
- ExtensionInfo(const std::string& name, const FilePath& path,
+ ExtensionInfo(const std::string& name,
+ const FilePath& path,
const std::string& default_locale,
+ bool incognito_split_mode,
const ExtensionExtent& extent,
- const std::vector<std::string>& api_permissions)
- : name(name), path(path), default_locale(default_locale),
- extent(extent), api_permissions(api_permissions) {
+ const ExtensionExtent& effective_host_permissions,
+ const std::set<std::string>& api_permissions,
+ const ExtensionIconSet& icons)
+ : name(name),
+ path(path),
+ default_locale(default_locale),
+ incognito_split_mode(incognito_split_mode),
+ extent(extent),
+ effective_host_permissions(effective_host_permissions),
+ api_permissions(api_permissions),
+ icons(icons) {
}
const std::string name;
- FilePath path;
- std::string default_locale;
- ExtensionExtent extent;
- std::vector<std::string> api_permissions;
+ const FilePath path;
+ const std::string default_locale;
+ const bool incognito_split_mode;
+ const ExtensionExtent extent;
+ const ExtensionExtent effective_host_permissions;
+ std::set<std::string> api_permissions;
+ ExtensionIconSet icons;
};
// Map of extension info by extension id.
@@ -73,14 +92,29 @@ class ChromeURLRequestContext : public URLRequestContext {
// Gets the path to the directory for the specified extension.
FilePath GetPathForExtension(const std::string& id);
+ // Returns true if the specified extension exists and has a non-empty web
+ // extent.
+ bool ExtensionHasWebExtent(const std::string& id);
+
+ // Returns true if the specified extension exists and can load in incognito
+ // contexts.
+ bool ExtensionCanLoadInIncognito(const std::string& id);
+
// Returns an empty string if the extension with |id| doesn't have a default
// locale.
std::string GetDefaultLocaleForExtension(const std::string& id);
+ // Gets the effective host permissions for the extension with |id|.
+ ExtensionExtent
+ GetEffectiveHostPermissionsForExtension(const std::string& id);
+
// Determine whether a URL has access to the specified extension permission.
bool CheckURLAccessToExtensionPermission(const GURL& url,
const char* permission_name);
+ // Returns true if the specified URL references the icon for an extension.
+ bool URLIsForExtensionIcon(const GURL& url);
+
// Gets the path to the directory user scripts are stored in.
FilePath user_script_dir_path() const {
return user_script_dir_path_;
@@ -97,6 +131,16 @@ class ChromeURLRequestContext : public URLRequestContext {
return database_tracker_.get();
}
+ // Gets the blob storage context associated with this context's profile.
+ ChromeBlobStorageContext* blob_storage_context() const {
+ return blob_storage_context_.get();
+ }
+
+ // Gets the file system host context with this context's profile.
+ FileSystemHostContext* file_system_host_context() const {
+ return file_system_host_context_.get();
+ }
+
bool is_off_the_record() const {
return is_off_the_record_;
}
@@ -119,14 +163,9 @@ class ChromeURLRequestContext : public URLRequestContext {
// Callback for when an extension is unloaded.
void OnUnloadedExtension(const std::string& id);
- // False only if cookies are globally blocked without exception.
- bool AreCookiesEnabled() const;
-
// Returns true if this context is an external request context, like
// ChromeFrame.
- virtual bool IsExternal() const {
- return false;
- }
+ virtual bool IsExternal() const;
protected:
// Copies the dependencies from |other| into |this|. If you use this
@@ -202,6 +241,12 @@ class ChromeURLRequestContext : public URLRequestContext {
void set_database_tracker(webkit_database::DatabaseTracker* tracker) {
database_tracker_ = tracker;
}
+ void set_blob_storage_context(ChromeBlobStorageContext* context) {
+ blob_storage_context_ = context;
+ }
+ void set_file_system_host_context(FileSystemHostContext* context) {
+ file_system_host_context_ = context;
+ }
void set_net_log(net::NetLog* net_log) {
net_log_ = net_log;
}
@@ -227,6 +272,8 @@ class ChromeURLRequestContext : public URLRequestContext {
scoped_refptr<ChromeCookiePolicy> chrome_cookie_policy_;
scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
scoped_refptr<HostZoomMap> host_zoom_map_;
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+ scoped_refptr<FileSystemHostContext> file_system_host_context_;
bool is_media_;
bool is_off_the_record_;
@@ -291,6 +338,11 @@ class ChromeURLRequestContextGetter : public URLRequestContextGetter,
// called on the UI thread.
static ChromeURLRequestContextGetter* CreateOffTheRecord(Profile* profile);
+ // Create an instance for an OTR profile for extensions. This is expected
+ // to get called on UI thread.
+ static ChromeURLRequestContextGetter* CreateOffTheRecordForExtensions(
+ Profile* profile);
+
// Clean up UI thread resources. This is expected to get called on the UI
// thread before the instance is deleted on the IO thread.
void CleanupOnUIThread();
@@ -331,8 +383,7 @@ class ChromeURLRequestContextGetter : public URLRequestContextGetter,
void GetCookieStoreAsyncHelper(base::WaitableEvent* completion,
net::CookieStore** result);
- // Access only from the UI thread.
- PrefService* prefs_;
+ PrefChangeRegistrar registrar_;
// Deferred logic for creating a ChromeURLRequestContext.
// Access only from the IO thread.
@@ -383,11 +434,14 @@ class ChromeURLRequestContextFactory {
// user scripts.
FilePath user_script_dir_path_;
scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+ scoped_refptr<ChromeAppCacheService> appcache_service_;
scoped_refptr<webkit_database::DatabaseTracker> database_tracker_;
scoped_refptr<HostZoomMap> host_zoom_map_;
scoped_refptr<net::TransportSecurityState> transport_security_state_;
scoped_refptr<net::SSLConfigService> ssl_config_service_;
scoped_refptr<net::CookieMonster::Delegate> cookie_monster_delegate_;
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+ scoped_refptr<FileSystemHostContext> file_system_host_context_;
FilePath profile_dir_path_;
diff --git a/chrome/browser/net/chrome_url_request_context_unittest.cc b/chrome/browser/net/chrome_url_request_context_unittest.cc
index 7ba2dff..906c1d1 100644
--- a/chrome/browser/net/chrome_url_request_context_unittest.cc
+++ b/chrome/browser/net/chrome_url_request_context_unittest.cc
@@ -6,9 +6,11 @@
#include "base/command_line.h"
#include "base/format_macros.h"
-#include "chrome/browser/configuration_policy_pref_store.h"
-#include "chrome/browser/pref_value_store.h"
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/prefs/default_pref_store.h"
+#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/test/testing_pref_service.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service_common_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,26 +26,25 @@ TEST(ChromeURLRequestContextTest, CreateProxyConfigTest) {
no_proxy.AppendSwitch(switches::kNoProxyServer);
CommandLine no_proxy_extra_params(unused_path);
no_proxy_extra_params.AppendSwitch(switches::kNoProxyServer);
- no_proxy_extra_params.AppendSwitchWithValue(switches::kProxyServer,
- L"http://proxy:8888");
+ no_proxy_extra_params.AppendSwitchASCII(switches::kProxyServer,
+ "http://proxy:8888");
CommandLine single_proxy(unused_path);
- single_proxy.AppendSwitchWithValue(switches::kProxyServer,
- L"http://proxy:8888");
+ single_proxy.AppendSwitchASCII(switches::kProxyServer, "http://proxy:8888");
CommandLine per_scheme_proxy(unused_path);
- per_scheme_proxy.AppendSwitchWithValue(switches::kProxyServer,
- L"http=httpproxy:8888;ftp=ftpproxy:8889");
+ per_scheme_proxy.AppendSwitchASCII(switches::kProxyServer,
+ "http=httpproxy:8888;ftp=ftpproxy:8889");
CommandLine per_scheme_proxy_bypass(unused_path);
- per_scheme_proxy_bypass.AppendSwitchWithValue(switches::kProxyServer,
- L"http=httpproxy:8888;ftp=ftpproxy:8889");
- per_scheme_proxy_bypass.AppendSwitchWithValue(
+ per_scheme_proxy_bypass.AppendSwitchASCII(
+ switches::kProxyServer,
+ "http=httpproxy:8888;ftp=ftpproxy:8889");
+ per_scheme_proxy_bypass.AppendSwitchASCII(
switches::kProxyBypassList,
- L".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8");
+ ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8");
CommandLine with_pac_url(unused_path);
- with_pac_url.AppendSwitchWithValue(switches::kProxyPacUrl,
- L"http://wpad/wpad.dat");
- with_pac_url.AppendSwitchWithValue(
+ with_pac_url.AppendSwitchASCII(switches::kProxyPacUrl, "http://wpad/wpad.dat");
+ with_pac_url.AppendSwitchASCII(
switches::kProxyBypassList,
- L".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8");
+ ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8");
CommandLine with_auto_detect(unused_path);
with_auto_detect.AppendSwitch(switches::kProxyAutoDetect);
@@ -158,9 +159,11 @@ TEST(ChromeURLRequestContextTest, CreateProxyConfigTest) {
SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
tests[i].description.c_str()));
CommandLine command_line(tests[i].command_line);
- PrefService prefs(new PrefValueStore(
- new ConfigurationPolicyPrefStore(&command_line, NULL),
- NULL, NULL, NULL, NULL)); // Only configuration-policy prefs.
+ // Only configuration-policy and default prefs are needed.
+ PrefService prefs(new TestingPrefService::TestingPrefValueStore(
+ new policy::ConfigurationPolicyPrefStore(&command_line, NULL),
+ NULL, NULL, NULL, NULL,
+ new DefaultPrefStore()));
ChromeURLRequestContextGetter::RegisterUserPrefs(&prefs);
scoped_ptr<net::ProxyConfig> config(CreateProxyConfig(&prefs));
@@ -174,4 +177,3 @@ TEST(ChromeURLRequestContextTest, CreateProxyConfigTest) {
}
}
}
-
diff --git a/chrome/browser/net/connect_interceptor.cc b/chrome/browser/net/connect_interceptor.cc
index 7415ac1..dc74172 100644
--- a/chrome/browser/net/connect_interceptor.cc
+++ b/chrome/browser/net/connect_interceptor.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/net/connect_interceptor.h"
#include "chrome/browser/net/predictor_api.h"
+#include "net/base/load_flags.h"
namespace chrome_browser_net {
@@ -17,24 +18,43 @@ ConnectInterceptor::~ConnectInterceptor() {
}
URLRequestJob* ConnectInterceptor::MaybeIntercept(URLRequest* request) {
- if (!request->referrer().empty()) {
+ // Learn what URLs are likely to be needed during next startup.
+ // Pass actual URL, rather than WithEmptyPath, as we often won't need to do
+ // the canonicalization.
+ LearnAboutInitialNavigation(request->url());
+
+ bool is_subresource = !(request->load_flags() & net::LOAD_MAIN_FRAME);
+ if (is_subresource && !request->referrer().empty()) {
// Learn about our referring URL, for use in the future.
GURL referring_url(GURL(request->referrer()).GetWithEmptyPath());
- // TODO(jar): Only call if we think this was part of a frame load, and not a
- // link navigation. For now, we'll "learn" that to preconnect when a user
- // actually does a click... which will probably waste space in our referrers
- // table (since it probably won't be that deterministic).
- LearnFromNavigation(referring_url, request->url().GetWithEmptyPath());
+ GURL request_url(request->url().GetWithEmptyPath());
+ if (referring_url == request_url) {
+ // There is nothing to learn about preconnections when the referrer is
+ // already the site needed in the request URL. Similarly, we've already
+ // made any/all predictions when we navigated to the referring_url, so we
+ // can bail out here. This will also avoid useless boosting of the number
+ // of times we navigated to this site, which was already accounted for by
+ // the navigation to the referrering_url.
+ return NULL;
+ }
+ LearnFromNavigation(referring_url, request_url);
}
- // Now we use previous learning and setup for our subresources.
- if (request->was_fetched_via_proxy())
- return NULL;
- // TODO(jar): Only call if we believe this is a frame, and might have
- // subresources. We could "guess" by looking at path extensions (such as
- // foo.jpg or goo.gif etc.), but better would be to get this info from webkit
- // and have it add the info to the request (we currently only set the
- // priority, but we could record whether it was a frame).
- PredictFrameSubresources(request->url().GetWithEmptyPath());
+
+ // Subresources for main frames usually get loaded when we detected the main
+ // frame - way back in RenderViewHost::Navigate. So only use subresource
+ // prediction here for subframes.
+ if (request->load_flags() & net::LOAD_SUB_FRAME)
+ PredictFrameSubresources(request->url().GetWithEmptyPath());
+ return NULL;
+}
+
+URLRequestJob* ConnectInterceptor::MaybeInterceptResponse(URLRequest* request) {
+ return NULL;
+}
+
+URLRequestJob* ConnectInterceptor::MaybeInterceptRedirect(
+ URLRequest* request,
+ const GURL& location) {
return NULL;
}
diff --git a/chrome/browser/net/connect_interceptor.h b/chrome/browser/net/connect_interceptor.h
index 21a6b00..1f8eb70 100644
--- a/chrome/browser/net/connect_interceptor.h
+++ b/chrome/browser/net/connect_interceptor.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_CONNECT_INTERCEPTOR_H_
#define CHROME_BROWSER_NET_CONNECT_INTERCEPTOR_H_
+#pragma once
#include "net/url_request/url_request.h"
@@ -23,13 +24,9 @@ class ConnectInterceptor : public URLRequest::Interceptor {
// URLRequest::Interceptor overrides
// Learn about referrers, and optionally preconnect based on history.
virtual URLRequestJob* MaybeIntercept(URLRequest* request);
- virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request) {
- return NULL;
- }
+ virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request);
virtual URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
- const GURL& location) {
- return NULL;
- }
+ const GURL& location);
private:
DISALLOW_COPY_AND_ASSIGN(ConnectInterceptor);
diff --git a/chrome/browser/net/connection_tester.cc b/chrome/browser/net/connection_tester.cc
index 162be2c..4f9d943 100644
--- a/chrome/browser/net/connection_tester.cc
+++ b/chrome/browser/net/connection_tester.cc
@@ -8,10 +8,12 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/importer/firefox_proxy_settings.h"
#include "chrome/common/chrome_switches.h"
#include "net/base/cookie_monster.h"
#include "net/base/host_resolver_impl.h"
+#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/ssl_config_service_defaults.h"
@@ -52,7 +54,8 @@ class ExperimentURLRequestContext : public URLRequestContext {
// experiment being run.
ftp_transaction_factory_ = new net::FtpNetworkLayer(host_resolver_);
ssl_config_service_ = new net::SSLConfigServiceDefaults;
- http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault();
+ http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault(
+ host_resolver_);
http_transaction_factory_ = new net::HttpCache(
net::HttpNetworkLayer::CreateFactory(host_resolver_, proxy_service_,
ssl_config_service_, http_auth_handler_factory_, NULL, NULL),
@@ -80,7 +83,7 @@ class ExperimentURLRequestContext : public URLRequestContext {
// Create a vanilla HostResolver that disables caching.
const size_t kMaxJobs = 50u;
scoped_refptr<net::HostResolverImpl> impl =
- new net::HostResolverImpl(NULL, NULL, kMaxJobs);
+ new net::HostResolverImpl(NULL, NULL, kMaxJobs, NULL);
*host_resolver = impl;
@@ -167,7 +170,8 @@ class ExperimentURLRequestContext : public URLRequestContext {
return net::ERR_NOT_IMPLEMENTED;
#else
config_service->reset(
- net::ProxyService::CreateSystemProxyConfigService(NULL, NULL));
+ net::ProxyService::CreateSystemProxyConfigService(
+ MessageLoop::current(), NULL));
return net::OK;
#endif
}
diff --git a/chrome/browser/net/connection_tester.h b/chrome/browser/net/connection_tester.h
index 10534f5..4118fbc 100644
--- a/chrome/browser/net/connection_tester.h
+++ b/chrome/browser/net/connection_tester.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_CONNECTION_TESTER_H_
#define CHROME_BROWSER_NET_CONNECTION_TESTER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/net/connection_tester_unittest.cc b/chrome/browser/net/connection_tester_unittest.cc
index 4b356b1..686c601 100644
--- a/chrome/browser/net/connection_tester_unittest.cc
+++ b/chrome/browser/net/connection_tester_unittest.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/net/connection_tester.h"
#include "net/base/mock_host_resolver.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -71,7 +71,10 @@ class ConnectionTesterDelegate : public ConnectionTester::Delegate {
// (so the test doesn't use any external network dependencies).
class ConnectionTesterTest : public PlatformTest {
public:
- ConnectionTesterTest() : message_loop_(MessageLoop::TYPE_IO) {
+ ConnectionTesterTest()
+ : test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))),
+ message_loop_(MessageLoop::TYPE_IO) {
scoped_refptr<net::RuleBasedHostResolverProc> catchall_resolver =
new net::RuleBasedHostResolverProc(NULL);
@@ -82,20 +85,19 @@ class ConnectionTesterTest : public PlatformTest {
protected:
net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_;
+ net::TestServer test_server_;
ConnectionTesterDelegate test_delegate_;
MessageLoop message_loop_;
};
TEST_F(ConnectionTesterTest, RunAllTests) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateForkingServer(L"net/data/url_request_unittest/");
+ ASSERT_TRUE(test_server_.Start());
ConnectionTester tester(&test_delegate_);
// Start the test suite on URL "echoall".
// TODO(eroman): Is this URL right?
- GURL url = server->TestServerPage("echoall");
- tester.RunAllTests(url);
+ tester.RunAllTests(test_server_.GetURL("echoall"));
// Wait for all the tests to complete.
MessageLoop::current()->Run();
@@ -113,15 +115,13 @@ TEST_F(ConnectionTesterTest, RunAllTests) {
}
TEST_F(ConnectionTesterTest, DeleteWhileInProgress) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateForkingServer(L"net/data/url_request_unittest/");
+ ASSERT_TRUE(test_server_.Start());
scoped_ptr<ConnectionTester> tester(new ConnectionTester(&test_delegate_));
// Start the test suite on URL "echoall".
// TODO(eroman): Is this URL right?
- GURL url = server->TestServerPage("echoall");
- tester->RunAllTests(url);
+ tester->RunAllTests(test_server_.GetURL("echoall"));
MessageLoop::current()->RunAllPending();
diff --git a/chrome/browser/net/cookie_policy_browsertest.cc b/chrome/browser/net/cookie_policy_browsertest.cc
index e43cd14..de87969 100644
--- a/chrome/browser/net/cookie_policy_browsertest.cc
+++ b/chrome/browser/net/cookie_policy_browsertest.cc
@@ -10,7 +10,9 @@
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+#include "net/base/cookie_store.h"
#include "net/base/mock_host_resolver.h"
+#include "net/test/test_server.h"
namespace {
@@ -63,13 +65,12 @@ class CookiePolicyBrowserTest : public InProcessBrowserTest {
// Visits a page that sets a first-party cookie.
IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest, AllowFirstPartyCookies) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server != NULL);
+ ASSERT_TRUE(test_server()->Start());
browser()->profile()->GetHostContentSettingsMap()->
SetBlockThirdPartyCookies(true);
- GURL url = server->TestServerPage("set-cookie?cookie1");
+ GURL url(test_server()->GetURL("set-cookie?cookie1"));
std::string cookie = GetCookies(url);
ASSERT_EQ("", cookie);
@@ -84,19 +85,18 @@ IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest, AllowFirstPartyCookies) {
// a first-party cookie.
IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest,
AllowFirstPartyCookiesRedirect) {
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server != NULL);
+ ASSERT_TRUE(test_server()->Start());
browser()->profile()->GetHostContentSettingsMap()->
SetBlockThirdPartyCookies(true);
- GURL url = server->TestServerPage("server-redirect?");
+ GURL url(test_server()->GetURL("server-redirect?"));
+ GURL redirected_url(test_server()->GetURL("set-cookie?cookie2"));
- GURL redirected_url = server->TestServerPage("set-cookie?cookie2");
- // Change the host name from localhost to www.example.com so it triggers
+ // Change the host name from 127.0.0.1 to www.example.com so it triggers
// third-party cookie blocking if the first party for cookies URL is not
// changed when we follow a redirect.
- ASSERT_EQ("localhost", redirected_url.host());
+ ASSERT_EQ("127.0.0.1", redirected_url.host());
GURL::Replacements replacements;
std::string new_host("www.example.com");
replacements.SetHostStr(new_host);
diff --git a/chrome/browser/net/ftp_browsertest.cc b/chrome/browser/net/ftp_browsertest.cc
index 3f23e00..a639918 100644
--- a/chrome/browser/net/ftp_browsertest.cc
+++ b/chrome/browser/net/ftp_browsertest.cc
@@ -4,20 +4,21 @@
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
-#include "net/url_request/url_request_unittest.h"
+#include "googleurl/src/gurl.h"
+#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
class FtpBrowserTest : public InProcessBrowserTest {
public:
- FtpBrowserTest() : server_(FTPTestServer::CreateServer(L"")) {
+ FtpBrowserTest() : ftp_server_(net::TestServer::TYPE_FTP, FilePath()) {
}
protected:
- scoped_refptr<FTPTestServer> server_;
+ net::TestServer ftp_server_;
};
IN_PROC_BROWSER_TEST_F(FtpBrowserTest, DirectoryListing) {
- ASSERT_TRUE(NULL != server_.get());
- ui_test_utils::NavigateToURL(browser(), server_->TestServerPage("/"));
+ ASSERT_TRUE(ftp_server_.Start());
+ ui_test_utils::NavigateToURL(browser(), ftp_server_.GetURL("/"));
// TODO(phajdan.jr): test more things.
}
diff --git a/chrome/browser/net/gaia/token_service.cc b/chrome/browser/net/gaia/token_service.cc
index f514bf7..0f2b1ac 100644
--- a/chrome/browser/net/gaia/token_service.cc
+++ b/chrome/browser/net/gaia/token_service.cc
@@ -4,15 +4,254 @@
#include "chrome/browser/net/gaia/token_service.h"
-void TokenService::SetClientLoginResult(
+#include "base/command_line.h"
+#include "base/string_util.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/net/gaia/gaia_authenticator2.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/notification_service.h"
+
+// Unfortunately kNumServices must be defined in the .h.
+// TODO(chron): Sync doesn't use the TalkToken anymore so we can stop
+// requesting it.
+const char* TokenService::kServices[] = {GaiaConstants::kSyncService,
+ GaiaConstants::kTalkService};
+TokenService::TokenService()
+ : token_loading_query_(0) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+}
+
+TokenService::~TokenService() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ ResetCredentialsInMemory();
+}
+
+void TokenService::Initialize(const char* const source,
+ Profile* profile) {
+
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ if (!source_.empty()) {
+ // Already initialized.
+ return;
+ }
+ getter_ = profile->GetRequestContext();
+ // Since the user can create a bookmark in incognito, sync may be running.
+ // Thus we have to go for explicit access.
+ web_data_service_ = profile->GetWebDataService(Profile::EXPLICIT_ACCESS);
+ source_ = std::string(source);
+
+#ifndef NDEBUG
+ CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ // Allow the token service to be cleared from the command line.
+ if (cmd_line->HasSwitch(switches::kClearTokenService))
+ EraseTokensFromDB();
+
+ // Allow a token to be injected from the command line.
+ if (cmd_line->HasSwitch(switches::kSetToken)) {
+ std::string value = cmd_line->GetSwitchValueASCII(switches::kSetToken);
+ int separator = value.find(':');
+ std::string service = value.substr(0, separator);
+ std::string token = value.substr(separator + 1);
+ token_map_[service] = token;
+ SaveAuthTokenToDB(service, token);
+ }
+#endif
+
+ registrar_.Add(this,
+ NotificationType::TOKEN_UPDATED,
+ NotificationService::AllSources());
+}
+
+void TokenService::ResetCredentialsInMemory() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ // Terminate any running fetchers. Callbacks will not return.
+ for (int i = 0; i < kNumServices; i++) {
+ fetchers_[i].reset();
+ }
+
+ // Cancel pending loads. Callbacks will not return.
+ if (token_loading_query_) {
+ web_data_service_->CancelRequest(token_loading_query_);
+ token_loading_query_ = 0;
+ }
+
+ token_map_.clear();
+ credentials_ = GaiaAuthConsumer::ClientLoginResult();
+}
+
+void TokenService::UpdateCredentials(
const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
credentials_ = credentials;
+
+ // Cancels any currently running requests.
+ for (int i = 0; i < kNumServices; i++) {
+ fetchers_[i].reset(new GaiaAuthenticator2(this, source_, getter_));
+ }
+}
+
+void TokenService::LoadTokensFromDB() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ token_loading_query_ = web_data_service_->GetAllTokens(this);
+}
+
+void TokenService::SaveAuthTokenToDB(const std::string& service,
+ const std::string& auth_token) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ web_data_service_->SetTokenForService(service, auth_token);
}
-bool TokenService::HasLsid() {
+void TokenService::EraseTokensFromDB() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ web_data_service_->RemoveAllTokens();
+}
+
+bool TokenService::AreCredentialsValid() const {
+ return !credentials_.lsid.empty() && !credentials_.sid.empty();
+}
+
+bool TokenService::HasLsid() const {
return !credentials_.lsid.empty();
}
-const std::string& TokenService::GetLsid() {
+const std::string& TokenService::GetLsid() const {
return credentials_.lsid;
}
+
+void TokenService::StartFetchingTokens() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(AreCredentialsValid());
+ for (int i = 0; i < kNumServices; i++) {
+ fetchers_[i]->StartIssueAuthToken(credentials_.sid,
+ credentials_.lsid,
+ kServices[i]);
+ }
+}
+
+// Services dependent on a token will check if a token is available.
+// If it isn't, they'll go to sleep until they get a token event.
+bool TokenService::HasTokenForService(const char* const service) const {
+ return token_map_.count(service) > 0;
+}
+
+const std::string& TokenService::GetTokenForService(
+ const char* const service) const {
+
+ if (token_map_.count(service) > 0) {
+ // Note map[key] is not const.
+ return (*token_map_.find(service)).second;
+ }
+ return EmptyString();
+}
+
+// Note that this can fire twice or more for any given service.
+// It can fire once from the DB read, and then once from the initial
+// fetcher. Future fetches can cause more notification firings.
+// The DB read will not however fire a notification if the fetcher
+// returned first. So it's always safe to use the latest notification.
+void TokenService::FireTokenAvailableNotification(
+ const std::string& service,
+ const std::string& auth_token) {
+
+ TokenAvailableDetails details(service, auth_token);
+ NotificationService::current()->Notify(
+ NotificationType::TOKEN_AVAILABLE,
+ Source<TokenService>(this),
+ Details<const TokenAvailableDetails>(&details));
+}
+
+void TokenService::FireTokenRequestFailedNotification(
+ const std::string& service,
+ const GoogleServiceAuthError& error) {
+
+ TokenRequestFailedDetails details(service, error);
+ NotificationService::current()->Notify(
+ NotificationType::TOKEN_REQUEST_FAILED,
+ Source<TokenService>(this),
+ Details<const TokenRequestFailedDetails>(&details));
+}
+
+void TokenService::IssueAuthTokenForTest(const std::string& service,
+ const std::string& auth_token) {
+ token_map_[service] = auth_token;
+ FireTokenAvailableNotification(service, auth_token);
+}
+
+void TokenService::OnIssueAuthTokenSuccess(const std::string& service,
+ const std::string& auth_token) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ LOG(INFO) << "Got an authorization token for " << service;
+ token_map_[service] = auth_token;
+ FireTokenAvailableNotification(service, auth_token);
+ SaveAuthTokenToDB(service, auth_token);
+}
+
+void TokenService::OnIssueAuthTokenFailure(const std::string& service,
+ const GoogleServiceAuthError& error) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ LOG(WARNING) << "Auth token issuing failed for service:" << service;
+ FireTokenRequestFailedNotification(service, error);
+}
+
+void TokenService::OnWebDataServiceRequestDone(WebDataService::Handle h,
+ const WDTypedResult* result) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(token_loading_query_);
+ token_loading_query_ = 0;
+
+ // If the fetch failed, there will be no result. In that case, we just don't
+ // load any tokens at all from the DB.
+ if (result) {
+ DCHECK(result->GetType() == TOKEN_RESULT);
+ const WDResult<std::map<std::string, std::string> > * token_result =
+ static_cast<const WDResult<std::map<std::string, std::string> > * > (
+ result);
+ LoadTokensIntoMemory(token_result->GetValue(), &token_map_);
+ }
+
+ NotificationService::current()->Notify(
+ NotificationType::TOKEN_LOADING_FINISHED,
+ Source<TokenService>(this),
+ NotificationService::NoDetails());
+}
+
+// Load tokens from the db_token map into the in memory token map.
+void TokenService::LoadTokensIntoMemory(
+ const std::map<std::string, std::string>& db_tokens,
+ std::map<std::string, std::string>* in_memory_tokens) {
+
+ for (int i = 0; i < kNumServices; i++) {
+ // OnIssueAuthTokenSuccess should come from the same thread.
+ // If a token is already present in the map, it could only have
+ // come from a DB read or from IssueAuthToken. Since we should never
+ // fetch from the DB twice in a browser session, it must be from
+ // OnIssueAuthTokenSuccess, which is a live fetcher.
+ //
+ // Network fetched tokens take priority over DB tokens, so exclude tokens
+ // which have already been loaded by the fetcher.
+ if (!in_memory_tokens->count(kServices[i]) &&
+ db_tokens.count(kServices[i])) {
+ std::string db_token = db_tokens.find(kServices[i])->second;
+ if (!db_token.empty()) {
+ LOG(INFO) << "Loading " << kServices[i] << "token from DB:"
+ << db_token;
+ (*in_memory_tokens)[kServices[i]] = db_token;
+ FireTokenAvailableNotification(kServices[i], db_token);
+ // Failures are only for network errors.
+ }
+ }
+ }
+}
+
+void TokenService::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::TOKEN_UPDATED);
+ TokenAvailableDetails* tok_details =
+ Details<TokenAvailableDetails>(details).ptr();
+ OnIssueAuthTokenSuccess(tok_details->service(), tok_details->token());
+}
diff --git a/chrome/browser/net/gaia/token_service.h b/chrome/browser/net/gaia/token_service.h
index c8b7778..b6f1b3c 100644
--- a/chrome/browser/net/gaia/token_service.h
+++ b/chrome/browser/net/gaia/token_service.h
@@ -3,29 +3,191 @@
// found in the LICENSE file.
//
// The TokenService will supply authentication tokens for any service that
-// needs it. One such service is Sync.
-// For the time being, the Token Service just supplies the LSID from the
-// ChromiumOS login. In the future, it'll have a bit more logic and supply
-// only AuthTokens from Gaia, and not LSIDs.
+// needs it, such as sync. Whenever the user logs in, a controller watching
+// the token service is expected to call ClientLogin to derive a new SID and
+// LSID. Whenever such credentials are available, the TokenService should be
+// updated with new credentials. The controller should then start fetching
+// tokens, which will be written to the database after retrieval, as well as
+// provided to listeners.
+//
+// A token service controller like the ChromiumOS login is expected to:
+//
+// Initialize() // Soon as you can
+// LoadTokensFromDB() // When it's OK to talk to the database
+// UpdateCredentials() // When user logs in
+// StartFetchingTokens() // When it's safe to start fetching
+//
+// Typically a user of the TokenService is expected just to call:
+//
+// if (token_service.HasTokenForService(servicename)) {
+// SetMyToken(token_service.GetTokenForService(servicename));
+// }
+// RegisterSomeObserver(token_service);
+//
+// Whenever a token update occurs:
+// OnTokenAvailable(...) {
+// if (IsServiceICareAbout(notification.service())) {
+// SetMyToken(notification.token())
+// }
+// }
#ifndef CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
#define CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include "base/gtest_prod_util.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/net/gaia/gaia_authenticator2.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class URLRequestContextGetter;
+class Profile;
-class TokenService {
+// The TokenService is a Profile member, so all calls are expected
+// from the UI thread.
+class TokenService : public GaiaAuthConsumer,
+ public WebDataServiceConsumer,
+ public NotificationObserver {
public:
- void SetClientLoginResult(
- const GaiaAuthConsumer::ClientLoginResult& credentials);
+ TokenService();
+ virtual ~TokenService();
+
+ // Notification classes
+ class TokenAvailableDetails {
+ public:
+ TokenAvailableDetails() {}
+ TokenAvailableDetails(const std::string& service,
+ const std::string& token)
+ : service_(service), token_(token) {}
+ const std::string& service() const { return service_; }
+ const std::string& token() const { return token_; }
+ private:
+ std::string service_;
+ std::string token_;
+ };
+
+ class TokenRequestFailedDetails {
+ public:
+ TokenRequestFailedDetails()
+ : error_(GoogleServiceAuthError::NONE) {}
+ TokenRequestFailedDetails(const std::string& service,
+ const GoogleServiceAuthError& error)
+ : service_(service), error_(error) {}
+ const std::string& service() const { return service_; }
+ const GoogleServiceAuthError& error() const { return error_; }
+ private:
+ std::string service_;
+ GoogleServiceAuthError error_;
+ };
+
+ // Initialize this token service with a request source
+ // (usually from a GaiaAuthConsumer constant), and the profile.
+ // Typically you'd then update the credentials.
+ void Initialize(const char* const source, Profile* profile);
+
+ // Update the credentials in the token service.
+ // Afterwards you can StartFetchingTokens.
+ void UpdateCredentials(
+ const GaiaAuthConsumer::ClientLoginResult& credentials);
+
+ // Terminate any running requests and reset the TokenService to a clean
+ // slate. Resets in memory structures. Does not modify the DB.
+ // When this is done, no tokens will be left in memory and no
+ // user credentials will be left. Useful if a user is logging out.
+ // Initialize doesn't need to be called again but UpdateCredentials does.
+ void ResetCredentialsInMemory();
+
+ // Async load all tokens for services we know of from the DB.
+ // You should do this at startup. Optionally you can do it again
+ // after you reset in memory credentials.
+ void LoadTokensFromDB();
+
+ // Clear all DB stored tokens for the current profile. Tokens may still be
+ // available in memory. If a DB load is pending it may still be serviced.
+ void EraseTokensFromDB();
- bool HasLsid();
- const std::string& GetLsid();
+ // For legacy services with their own auth routines, they can just read
+ // the LSID out directly. Deprecated.
+ bool HasLsid() const;
+ const std::string& GetLsid() const;
+ // Did we get a proper LSID?
+ bool AreCredentialsValid() const;
- // TODO(chron): Token broadcast will require removing a lot of auth code
- // from sync. For the time being we'll start with LSID passing.
+ // Tokens will be fetched for all services(sync, talk) in the background.
+ // Results come back via event channel. Services can also poll before events
+ // are issued.
+ void StartFetchingTokens();
+ bool HasTokenForService(const char* const service) const;
+ const std::string& GetTokenForService(const char* const service) const;
+
+ // For tests only. Doesn't save to the WebDB.
+ void IssueAuthTokenForTest(const std::string& service,
+ const std::string& auth_token);
+
+ // GaiaAuthConsumer implementation.
+ virtual void OnIssueAuthTokenSuccess(const std::string& service,
+ const std::string& auth_token);
+ virtual void OnIssueAuthTokenFailure(const std::string& service,
+ const GoogleServiceAuthError& error);
+
+ // WebDataServiceConsumer implementation.
+ virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
+ const WDTypedResult* result);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
private:
+
+ void FireTokenAvailableNotification(const std::string& service,
+ const std::string& auth_token);
+
+ void FireTokenRequestFailedNotification(const std::string& service,
+ const GoogleServiceAuthError& error);
+
+ void LoadTokensIntoMemory(const std::map<std::string, std::string>& in_toks,
+ std::map<std::string, std::string>* out_toks);
+
+ void SaveAuthTokenToDB(const std::string& service,
+ const std::string& auth_token);
+
+ // Web data service to access tokens from.
+ scoped_refptr<WebDataService> web_data_service_;
+ // Getter to use for fetchers.
+ scoped_refptr<URLRequestContextGetter> getter_;
+ // Request handle to load Gaia tokens from DB.
+ WebDataService::Handle token_loading_query_;
+
+ // Gaia request source for Gaia accounting.
+ std::string source_;
+ // Credentials from ClientLogin for Issuing auth tokens.
GaiaAuthConsumer::ClientLoginResult credentials_;
+
+ // Size of array of services (must be defined here).
+ static const int kNumServices = 2;
+ // List of services that we're performing operations for.
+ static const char* kServices[kNumServices];
+ // A bunch of fetchers suitable for token issuing. We don't care about
+ // the ordering, nor do we care which is for which service.
+ scoped_ptr<GaiaAuthenticator2> fetchers_[kNumServices];
+ // Map from service to token.
+ std::map<std::string, std::string> token_map_;
+
+ NotificationRegistrar registrar_;
+
+ FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryBasic);
+ FRIEND_TEST_ALL_PREFIXES(TokenServiceTest, LoadTokensIntoMemoryAdvanced);
+
+ DISALLOW_COPY_AND_ASSIGN(TokenService);
};
#endif // CHROME_BROWSER_NET_GAIA_TOKEN_SERVICE_H_
diff --git a/chrome/browser/net/load_timing_observer.cc b/chrome/browser/net/load_timing_observer.cc
index d0e0485..433aa9b 100644
--- a/chrome/browser/net/load_timing_observer.cc
+++ b/chrome/browser/net/load_timing_observer.cc
@@ -6,7 +6,10 @@
#include "base/compiler_specific.h"
#include "base/time.h"
+#include "chrome/browser/net/chrome_net_log.h"
+#include "chrome/common/resource_response.h"
#include "net/base/load_flags.h"
+#include "net/url_request/url_request.h"
#include "net/url_request/url_request_netlog_params.h"
using base::Time;
@@ -48,7 +51,9 @@ LoadTimingObserver::URLRequestRecord::URLRequestRecord()
socket_reused(false) {
}
-LoadTimingObserver::LoadTimingObserver() {
+LoadTimingObserver::LoadTimingObserver()
+ : Observer(net::NetLog::LOG_BASIC),
+ last_connect_job_id_(net::NetLog::Source::kInvalidId) {
}
LoadTimingObserver::~LoadTimingObserver() {
@@ -75,6 +80,28 @@ void LoadTimingObserver::OnAddEntry(net::NetLog::EventType type,
OnAddSocketEntry(type, time, source, phase, params);
}
+// static
+void LoadTimingObserver::PopulateTimingInfo(URLRequest* request,
+ ResourceResponse* response) {
+ if (!(request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING))
+ return;
+
+ ChromeNetLog* chrome_net_log = static_cast<ChromeNetLog*>(
+ request->net_log().net_log());
+ if (chrome_net_log == NULL)
+ return;
+
+ uint32 source_id = request->net_log().source().id;
+ LoadTimingObserver* observer = chrome_net_log->load_timing_observer();
+ LoadTimingObserver::URLRequestRecord* record =
+ observer->GetURLRequestRecord(source_id);
+ if (record) {
+ response->response_head.connection_id = record->socket_log_id;
+ response->response_head.connection_reused = record->socket_reused;
+ response->response_head.load_timing = record->timing;
+ }
+}
+
void LoadTimingObserver::OnAddURLRequestEntry(
net::NetLog::EventType type,
const base::TimeTicks& time,
@@ -118,7 +145,7 @@ void LoadTimingObserver::OnAddURLRequestEntry(
ResourceLoaderBridge::LoadTimingInfo& timing = record->timing;
- switch(type) {
+ switch (type) {
case net::NetLog::TYPE_PROXY_SERVICE:
if (is_begin)
timing.proxy_start = TimeTicksToOffset(time, record);
@@ -135,12 +162,12 @@ void LoadTimingObserver::OnAddURLRequestEntry(
{
uint32 connect_job_id = static_cast<net::NetLogSourceParameter*>(
params)->value().id;
- ConnectJobToRecordMap::iterator it =
- connect_job_to_record_.find(connect_job_id);
- if (it != connect_job_to_record_.end() &&
- !it->second.dns_start.is_null()) {
- timing.dns_start = TimeTicksToOffset(it->second.dns_start, record);
- timing.dns_end = TimeTicksToOffset(it->second.dns_end, record);
+ if (last_connect_job_id_ == connect_job_id &&
+ !last_connect_job_record_.dns_start.is_null()) {
+ timing.dns_start =
+ TimeTicksToOffset(last_connect_job_record_.dns_start, record);
+ timing.dns_end =
+ TimeTicksToOffset(last_connect_job_record_.dns_end, record);
}
}
break;
@@ -154,20 +181,18 @@ void LoadTimingObserver::OnAddURLRequestEntry(
SocketToRecordMap::iterator it =
socket_to_record_.find(record->socket_log_id);
if (it != socket_to_record_.end() && !it->second.ssl_start.is_null()) {
- timing.ssl_start = TimeTicksToOffset(it->second.ssl_start, record);
- timing.ssl_end = TimeTicksToOffset(it->second.ssl_end, record);
+ timing.ssl_start = TimeTicksToOffset(it->second.ssl_start, record);
+ timing.ssl_end = TimeTicksToOffset(it->second.ssl_end, record);
}
}
break;
case net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST:
- case net::NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST:
if (is_begin)
timing.send_start = TimeTicksToOffset(time, record);
else if (is_end)
timing.send_end = TimeTicksToOffset(time, record);
break;
case net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS:
- case net::NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS:
if (is_begin)
timing.receive_headers_start = TimeTicksToOffset(time, record);
else if (is_end)
@@ -201,7 +226,13 @@ void LoadTimingObserver::OnAddConnectJobEntry(
connect_job_to_record_.insert(
std::make_pair(source.id, ConnectJobRecord()));
} else if (is_end) {
- connect_job_to_record_.erase(source.id);
+ ConnectJobToRecordMap::iterator it =
+ connect_job_to_record_.find(source.id);
+ if (it != connect_job_to_record_.end()) {
+ last_connect_job_id_ = it->first;
+ last_connect_job_record_ = it->second;
+ connect_job_to_record_.erase(it);
+ }
}
} else if (type == net::NetLog::TYPE_HOST_RESOLVER_IMPL) {
ConnectJobToRecordMap::iterator it =
diff --git a/chrome/browser/net/load_timing_observer.h b/chrome/browser/net/load_timing_observer.h
index 9d9ba82..a46d6a6 100644
--- a/chrome/browser/net/load_timing_observer.h
+++ b/chrome/browser/net/load_timing_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_LOAD_TIMING_OBSERVER_H_
#define CHROME_BROWSER_NET_LOAD_TIMING_OBSERVER_H_
+#pragma once
#include "base/gtest_prod_util.h"
#include "base/hash_tables.h"
@@ -12,6 +13,9 @@
#include "net/base/net_log.h"
#include "webkit/glue/resource_loader_bridge.h"
+class URLRequest;
+struct ResourceResponse;
+
// LoadTimingObserver watches the NetLog event stream and collects the network
// timing information.
class LoadTimingObserver : public ChromeNetLog::Observer {
@@ -47,6 +51,10 @@ class LoadTimingObserver : public ChromeNetLog::Observer {
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params);
+
+ static void PopulateTimingInfo(URLRequest* request,
+ ResourceResponse* response);
+
private:
FRIEND_TEST_ALL_PREFIXES(LoadTimingObserverTest,
ConnectJobRecord);
@@ -80,6 +88,8 @@ class LoadTimingObserver : public ChromeNetLog::Observer {
URLRequestToRecordMap url_request_to_record_;
ConnectJobToRecordMap connect_job_to_record_;
SocketToRecordMap socket_to_record_;
+ uint32 last_connect_job_id_;
+ ConnectJobRecord last_connect_job_record_;
DISALLOW_COPY_AND_ASSIGN(LoadTimingObserver);
};
diff --git a/chrome/browser/net/load_timing_observer_unittest.cc b/chrome/browser/net/load_timing_observer_unittest.cc
index 318b254..8ded133 100644
--- a/chrome/browser/net/load_timing_observer_unittest.cc
+++ b/chrome/browser/net/load_timing_observer_unittest.cc
@@ -36,16 +36,18 @@ void AddEndEntry(LoadTimingObserver& observer,
void AddStartURLRequestEntries(LoadTimingObserver& observer,
uint32 id,
bool request_timing) {
+ scoped_refptr<URLRequestStartEventParameters> params(
+ new URLRequestStartEventParameters(
+ GURL(StringPrintf("http://req%d", id)),
+ "GET",
+ request_timing ? net::LOAD_ENABLE_LOAD_TIMING : 0,
+ net::LOW));
NetLog::Source source(NetLog::SOURCE_URL_REQUEST, id);
AddStartEntry(observer, source, NetLog::TYPE_REQUEST_ALIVE, NULL);
AddStartEntry(observer,
source,
NetLog::TYPE_URL_REQUEST_START_JOB,
- new URLRequestStartEventParameters(
- GURL(StringPrintf("http://req%d", id)),
- "GET",
- request_timing ? net::LOAD_ENABLE_LOAD_TIMING : 0,
- net::LOW));
+ params.get());
}
void AddEndURLRequestEntries(LoadTimingObserver& observer, uint32 id) {
@@ -221,12 +223,15 @@ TEST(LoadTimingObserverTest, DnsTime) {
NULL);
current_time += TimeDelta::FromSeconds(2);
AddEndEntry(observer, connect_source, NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
+ AddEndConnectJobEntries(observer, 1);
// Bind to connect job.
+ scoped_refptr<net::NetLogSourceParameter> params(
+ new net::NetLogSourceParameter("connect_job", connect_source));
AddStartEntry(observer,
source,
NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- new net::NetLogSourceParameter("connect_job", connect_source));
+ params.get());
LoadTimingObserver::URLRequestRecord* record =
observer.GetURLRequestRecord(0);
@@ -303,10 +308,12 @@ TEST(LoadTimingObserverTest, SslTime) {
AddEndEntry(observer, socket_source, NetLog::TYPE_SSL_CONNECT, NULL);
// Bind to connect job.
+ scoped_refptr<net::NetLogSourceParameter> params(
+ new net::NetLogSourceParameter("socket", socket_source));
AddStartEntry(observer,
source,
NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
- new net::NetLogSourceParameter("socket", socket_source));
+ params.get());
LoadTimingObserver::URLRequestRecord* record =
observer.GetURLRequestRecord(0);
diff --git a/chrome/browser/net/metadata_url_request.h b/chrome/browser/net/metadata_url_request.h
index 047fa15..a6d65fa 100644
--- a/chrome/browser/net/metadata_url_request.h
+++ b/chrome/browser/net/metadata_url_request.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_METADATA_URL_REQUEST_H_
#define CHROME_BROWSER_NET_METADATA_URL_REQUEST_H_
+#pragma once
void RegisterMetadataURLRequestHandler();
diff --git a/chrome/browser/net/passive_log_collector.cc b/chrome/browser/net/passive_log_collector.cc
index 152d332..c62c332 100644
--- a/chrome/browser/net/passive_log_collector.cc
+++ b/chrome/browser/net/passive_log_collector.cc
@@ -42,7 +42,8 @@ bool SortByOrderComparator(const PassiveLogCollector::Entry& a,
//----------------------------------------------------------------------------
PassiveLogCollector::PassiveLogCollector()
- : ALLOW_THIS_IN_INITIALIZER_LIST(connect_job_tracker_(this)),
+ : Observer(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)),
num_events_seen_(0) {
@@ -57,7 +58,9 @@ PassiveLogCollector::PassiveLogCollector()
trackers_[net::NetLog::SOURCE_INIT_PROXY_RESOLVER] =
&init_proxy_resolver_tracker_;
trackers_[net::NetLog::SOURCE_SPDY_SESSION] = &spdy_session_tracker_;
-
+ trackers_[net::NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST] =
+ &dns_request_tracker_;
+ trackers_[net::NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB] = &dns_job_tracker_;
// Make sure our mapping is up-to-date.
for (size_t i = 0; i < arraysize(trackers_); ++i)
DCHECK(trackers_[i]) << "Unhandled SourceType: " << i;
@@ -248,6 +251,8 @@ void PassiveLogCollector::SourceTracker::AddToDeletionQueue(
DCHECK_GE(sources_.find(source_id)->second.reference_count, 0);
DCHECK_LE(deletion_queue_.size(), max_graveyard_size_);
+ DCHECK(std::find(deletion_queue_.begin(), deletion_queue_.end(),
+ source_id) == deletion_queue_.end());
deletion_queue_.push_back(source_id);
// After the deletion queue has reached its maximum size, start
@@ -485,3 +490,49 @@ PassiveLogCollector::SpdySessionTracker::DoAddEntry(const Entry& entry,
return ACTION_NONE;
}
}
+
+//----------------------------------------------------------------------------
+// DNSRequestTracker
+//----------------------------------------------------------------------------
+
+const size_t PassiveLogCollector::DNSRequestTracker::kMaxNumSources = 200;
+const size_t PassiveLogCollector::DNSRequestTracker::kMaxGraveyardSize = 20;
+
+PassiveLogCollector::DNSRequestTracker::DNSRequestTracker()
+ : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
+}
+
+PassiveLogCollector::SourceTracker::Action
+PassiveLogCollector::DNSRequestTracker::DoAddEntry(const 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) {
+ return ACTION_MOVE_TO_GRAVEYARD;
+ } else {
+ return ACTION_NONE;
+ }
+}
+
+//----------------------------------------------------------------------------
+// DNSJobTracker
+//----------------------------------------------------------------------------
+
+const size_t PassiveLogCollector::DNSJobTracker::kMaxNumSources = 100;
+const size_t PassiveLogCollector::DNSJobTracker::kMaxGraveyardSize = 15;
+
+PassiveLogCollector::DNSJobTracker::DNSJobTracker()
+ : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
+}
+
+PassiveLogCollector::SourceTracker::Action
+PassiveLogCollector::DNSJobTracker::DoAddEntry(const Entry& entry,
+ SourceInfo* out_info) {
+ AddEntryToSourceInfo(entry, out_info);
+ if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_JOB &&
+ entry.phase == net::NetLog::PHASE_END) {
+ return ACTION_MOVE_TO_GRAVEYARD;
+ } else {
+ return ACTION_NONE;
+ }
+}
diff --git a/chrome/browser/net/passive_log_collector.h b/chrome/browser/net/passive_log_collector.h
index 7615b28..8ffd459 100644
--- a/chrome/browser/net/passive_log_collector.h
+++ b/chrome/browser/net/passive_log_collector.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_PASSIVE_LOG_COLLECTOR_H_
#define CHROME_BROWSER_NET_PASSIVE_LOG_COLLECTOR_H_
+#pragma once
#include <deque>
#include <string>
@@ -282,6 +283,36 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
DISALLOW_COPY_AND_ASSIGN(SpdySessionTracker);
};
+ // Tracks the log entries for the last seen SOURCE_HOST_RESOLVER_IMPL_REQUEST.
+ class DNSRequestTracker : public SourceTracker {
+ public:
+ static const size_t kMaxNumSources;
+ static const size_t kMaxGraveyardSize;
+
+ DNSRequestTracker();
+
+ protected:
+ virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DNSRequestTracker);
+ };
+
+ // Tracks the log entries for the last seen SOURCE_HOST_RESOLVER_IMPL_JOB.
+ class DNSJobTracker : public SourceTracker {
+ public:
+ static const size_t kMaxNumSources;
+ static const size_t kMaxGraveyardSize;
+
+ DNSJobTracker();
+
+ protected:
+ virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DNSJobTracker);
+ };
+
PassiveLogCollector();
~PassiveLogCollector();
@@ -316,6 +347,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
RequestTracker socket_stream_tracker_;
InitProxyResolverTracker init_proxy_resolver_tracker_;
SpdySessionTracker spdy_session_tracker_;
+ DNSRequestTracker dns_request_tracker_;
+ DNSJobTracker dns_job_tracker_;
// This array maps each NetLog::SourceType to one of the tracker instances
// defined above. Use of this array avoid duplicating the list of trackers
diff --git a/chrome/browser/net/preconnect.cc b/chrome/browser/net/preconnect.cc
index 7930a68..528a31a 100644
--- a/chrome/browser/net/preconnect.cc
+++ b/chrome/browser/net/preconnect.cc
@@ -6,11 +6,14 @@
#include "base/histogram.h"
#include "base/logging.h"
+#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/host_port_pair.h"
#include "net/http/http_network_session.h"
+#include "net/http/http_request_info.h"
+#include "net/http/http_stream.h"
#include "net/http/http_transaction_factory.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"
@@ -18,43 +21,26 @@
namespace chrome_browser_net {
// static
-bool Preconnect::preconnect_despite_proxy_ = false;
-
-// We will deliberately leak this singular instance, which is used only for
-// callbacks.
-// static
-Preconnect* Preconnect::callback_instance_;
-
-// static
-bool Preconnect::PreconnectOnUIThread(const GURL& url) {
- // Try to do connection warming for this search provider.
- URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
- if (!getter)
- return false;
+void Preconnect::PreconnectOnUIThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
// Prewarm connection to Search URL.
ChromeThread::PostTask(
ChromeThread::IO,
FROM_HERE,
- NewRunnableFunction(Preconnect::PreconnectOnIOThread, url));
- return true;
+ NewRunnableFunction(Preconnect::PreconnectOnIOThread, url, motivation));
+ return;
}
-enum ProxyStatus {
- PROXY_STATUS_IGNORED,
- PROXY_UNINITIALIZED,
- PROXY_NOT_USED,
- PROXY_PAC_RESOLVER,
- PROXY_HAS_RULES,
- PROXY_MAX,
-};
-
-static void HistogramPreconnectStatus(ProxyStatus status) {
- UMA_HISTOGRAM_ENUMERATION("Net.PreconnectProxyStatus", status, PROXY_MAX);
+// static
+void Preconnect::PreconnectOnIOThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation) {
+ Preconnect* preconnect = new Preconnect(motivation);
+ // TODO(jar): Should I use PostTask for LearnedSubresources to delay the
+ // preconnection a tad?
+ preconnect->Connect(url);
}
-// static
-void Preconnect::PreconnectOnIOThread(const GURL& url) {
- // TODO(jar): This does not handle proxies currently.
+void Preconnect::Connect(const GURL& url) {
URLRequestContextGetter* getter = Profile::GetDefaultRequestContext();
if (!getter)
return;
@@ -62,74 +48,84 @@ void Preconnect::PreconnectOnIOThread(const GURL& url) {
LOG(DFATAL) << "This must be run only on the IO thread.";
return;
}
- URLRequestContext* context = getter->GetURLRequestContext();
- if (preconnect_despite_proxy_) {
- HistogramPreconnectStatus(PROXY_STATUS_IGNORED);
- } else {
- // Currently we avoid all preconnects if there is a proxy configuration.
- net::ProxyService* proxy_service = context->proxy_service();
- if (!proxy_service->config_has_been_initialized()) {
- HistogramPreconnectStatus(PROXY_UNINITIALIZED);
- } else {
- if (proxy_service->config().MayRequirePACResolver()) {
- HistogramPreconnectStatus(PROXY_PAC_RESOLVER);
- return;
- }
- if (!proxy_service->config().proxy_rules().empty()) {
- HistogramPreconnectStatus(PROXY_HAS_RULES);
- return;
- }
- HistogramPreconnectStatus(PROXY_NOT_USED);
- }
- }
+ // We are now commited to doing the async preconnection call.
+ UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation_,
+ UrlInfo::MAX_MOTIVATED);
+ URLRequestContext* context = getter->GetURLRequestContext();
net::HttpTransactionFactory* factory = context->http_transaction_factory();
net::HttpNetworkSession* session = factory->GetSession();
- net::ClientSocketHandle handle;
- if (!callback_instance_)
- callback_instance_ = new Preconnect;
-
- scoped_refptr<net::TCPSocketParams> tcp_params =
- new net::TCPSocketParams(url.host(), url.EffectiveIntPort(), net::LOW,
- GURL(), false);
+ request_info_.reset(new net::HttpRequestInfo());
+ request_info_->url = url;
+ request_info_->method = "GET";
+ // It almost doesn't matter whether we use net::LOWEST or net::HIGHEST
+ // priority here, as we won't make a request, and will surrender the created
+ // socket to the pool as soon as we can. However, we would like to mark the
+ // speculative socket as such, and IF we use a net::LOWEST priority, and if
+ // a navigation asked for a socket (after us) then it would get our socket,
+ // and we'd get its later-arriving socket, which might make us record that
+ // the speculation didn't help :-/. By using net::HIGHEST, we ensure that
+ // a socket is given to us if "we asked first" and this allows us to mark it
+ // as speculative, and better detect stats (if it gets used).
+ // TODO(jar): histogram to see how often we accidentally use a previously-
+ // unused socket, when a previously used socket was available.
+ request_info_->priority = net::HIGHEST;
+
+ // Translate the motivation from UrlRequest motivations to HttpRequest
+ // motivations.
+ switch (motivation_) {
+ case UrlInfo::OMNIBOX_MOTIVATED:
+ request_info_->motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED;
+ break;
+ case UrlInfo::LEARNED_REFERAL_MOTIVATED:
+ request_info_->motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED;
+ break;
+ case UrlInfo::EARLY_LOAD_MOTIVATED:
+ break;
+ default:
+ // Other motivations should never happen here.
+ NOTREACHED();
+ break;
+ }
- net::HostPortPair endpoint(url.host(), url.EffectiveIntPort());
- std::string group_name = endpoint.ToString();
+ // Setup the SSL Configuration.
+ ssl_config_.reset(new net::SSLConfig());
+ session->ssl_config_service()->GetSSLConfig(ssl_config_.get());
+ if (session->http_stream_factory()->next_protos())
+ ssl_config_->next_protos = *session->http_stream_factory()->next_protos();
- if (url.SchemeIs("https")) {
- group_name = StringPrintf("ssl/%s", group_name.c_str());
+ // All preconnects should be for main pages.
+ ssl_config_->verify_ev_cert = true;
- net::SSLConfig ssl_config;
- session->ssl_config_service()->GetSSLConfig(&ssl_config);
- // All preconnects should be for main pages.
- ssl_config.verify_ev_cert = true;
+ proxy_info_.reset(new net::ProxyInfo());
+ net::StreamFactory* stream_factory = session->http_stream_factory();
+ stream_factory->RequestStream(request_info_.get(), ssl_config_.get(),
+ proxy_info_.get(), this, net_log_, session,
+ &stream_request_job_);
+}
- scoped_refptr<net::SSLSocketParams> ssl_params =
- new net::SSLSocketParams(tcp_params, NULL, NULL,
- net::ProxyServer::SCHEME_DIRECT,
- url.HostNoBrackets(), ssl_config,
- 0, false);
+void Preconnect::OnStreamReady(net::HttpStream* stream) {
+ delete stream;
+ delete this;
+}
- const scoped_refptr<net::SSLClientSocketPool>& pool =
- session->ssl_socket_pool();
+void Preconnect::OnStreamFailed(int status) {
+ delete this;
+}
- handle.Init(group_name, ssl_params, net::LOWEST, callback_instance_, pool,
- net::BoundNetLog());
- handle.Reset();
- return;
- }
+void Preconnect::OnCertificateError(int status, const net::SSLInfo& ssl_info) {
+ delete this;
+}
- const scoped_refptr<net::TCPClientSocketPool>& pool =
- session->tcp_socket_pool();
- handle.Init(group_name, tcp_params, net::LOWEST, callback_instance_, pool,
- net::BoundNetLog());
- handle.Reset();
+void Preconnect::OnNeedsProxyAuth(const net::HttpResponseInfo& proxy_response,
+ net::HttpAuthController* auth_controller) {
+ delete this;
}
-void Preconnect::RunWithParams(const Tuple1<int>& params) {
- // This will rarely be called, as we reset the connection just after creating.
- NOTREACHED();
+void Preconnect::OnNeedsClientAuth(net::SSLCertRequestInfo* cert_info) {
+ delete this;
}
+
} // chrome_browser_net
diff --git a/chrome/browser/net/preconnect.h b/chrome/browser/net/preconnect.h
index 8289625..7596f99 100644
--- a/chrome/browser/net/preconnect.h
+++ b/chrome/browser/net/preconnect.h
@@ -7,41 +7,75 @@
#ifndef CHROME_BROWSER_NET_PRECONNECT_H_
#define CHROME_BROWSER_NET_PRECONNECT_H_
+#pragma once
#include "base/ref_counted.h"
-#include "net/base/completion_callback.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/net/url_info.h"
#include "net/base/host_port_pair.h"
+#include "net/http/http_request_info.h"
+#include "net/http/stream_factory.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/tcp_client_socket_pool.h"
#include "net/url_request/url_request_context.h"
+namespace net {
+
+class ProxyInfo;
+struct SSLConfig;
+
+}
+
namespace chrome_browser_net {
-class Preconnect : public net::CompletionCallback {
+class Preconnect : public net::StreamFactory::StreamRequestDelegate {
public:
- static bool PreconnectOnUIThread(const GURL& url);
+ // Try to preconnect. Typically motivated by OMNIBOX to reach search service.
+ static void PreconnectOnUIThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation);
- static void PreconnectOnIOThread(const GURL& url);
+ // Try to preconnect. Typically used by predictor when a subresource probably
+ // needs a connection.
+ static void PreconnectOnIOThread(const GURL& url,
+ UrlInfo::ResolutionMotivation motivation);
- static void SetPreconnectDespiteProxy(bool status) {
- preconnect_despite_proxy_ = status;
- }
+ // StreamRequestDelegate interface
+ virtual void OnStreamReady(net::HttpStream* stream);
+ virtual void OnStreamFailed(int status);
+ virtual void OnCertificateError(int status, const net::SSLInfo& ssl_info);
+ virtual void OnNeedsProxyAuth(const net::HttpResponseInfo& proxy_response,
+ net::HttpAuthController* auth_controller);
+ virtual void OnNeedsClientAuth(net::SSLCertRequestInfo* cert_info);
private:
- Preconnect() {}
+ friend class base::RefCountedThreadSafe<Preconnect>;
+
+ explicit Preconnect(UrlInfo::ResolutionMotivation motivation)
+ : motivation_(motivation) {
+ }
+ virtual ~Preconnect() {}
+
+ // Request actual connection.
+ void Connect(const GURL& url);
+
+ // Generally either LEARNED_REFERAL_MOTIVATED or OMNIBOX_MOTIVATED to indicate
+ // why we were trying to do a preconnection.
+ const UrlInfo::ResolutionMotivation motivation_;
+
+ // HttpRequestInfo used for connecting.
+ scoped_ptr<net::HttpRequestInfo> request_info_;
+
+ // SSLConfig used for connecting.
+ scoped_ptr<net::SSLConfig> ssl_config_;
- // Supply an instance that could have been used in an IO callback, but will
- // never actually be used (because we reset the connection so quickly).
- static Preconnect* callback_instance_;
+ // ProxyInfo used for connecting.
+ scoped_ptr<net::ProxyInfo> proxy_info_;
- // IO Callback which whould be performed when the connection is established.
- virtual void RunWithParams(const Tuple1<int>& params);
+ // A net log to use for this preconnect.
+ net::BoundNetLog net_log_;
- // Preconnections are currently conservative, and do nothing if there is a
- // chance that a proxy may be used. This boolean allows proxy settings to
- // be ignored (presumably because a user knows that the proxy won't be doing
- // much work anway).
- static bool preconnect_despite_proxy_;
+ // Our preconnect.
+ scoped_refptr<net::StreamFactory::StreamRequestJob> stream_request_job_;
DISALLOW_COPY_AND_ASSIGN(Preconnect);
};
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index 6bb2330..c93e62e 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.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.
@@ -13,6 +13,7 @@
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/net/preconnect.h"
#include "net/base/address_list.h"
@@ -26,6 +27,14 @@ using base::TimeDelta;
namespace chrome_browser_net {
+// static
+const double Predictor::kPreconnectWorthyExpectedValue = 0.8;
+// static
+const double Predictor::kDNSPreresolutionWorthyExpectedValue = 0.1;
+// static
+const double Predictor::kPersistWorthyExpectedValue = 0.05;
+
+
class Predictor::LookupRequest {
public:
LookupRequest(Predictor* predictor,
@@ -43,8 +52,8 @@ class Predictor::LookupRequest {
// net:ERR_IO_PENDING ==> Network will callback later with result.
// anything else ==> Host was not found synchronously.
int Start() {
- net::HostResolver::RequestInfo resolve_info(url_.host(),
- url_.EffectiveIntPort());
+ net::HostResolver::RequestInfo resolve_info(
+ net::HostPortPair::FromURL(url_));
// Make a note that this is a speculative resolve request. This allows us
// to separate it from real navigations in the observer's callback, and
@@ -80,7 +89,8 @@ Predictor::Predictor(net::HostResolver* host_resolver,
max_concurrent_dns_lookups_(max_concurrent),
max_dns_queue_delay_(max_dns_queue_delay),
host_resolver_(host_resolver),
- preconnect_enabled_(preconnect_enabled) {
+ preconnect_enabled_(preconnect_enabled),
+ consecutive_omnibox_preconnect_count_(0) {
Referrer::SetUsePreconnectValuations(preconnect_enabled);
}
@@ -118,108 +128,148 @@ void Predictor::Resolve(const GURL& url,
AppendToResolutionQueue(url, motivation);
}
-bool Predictor::AccruePrefetchBenefits(const GURL& referrer,
- UrlInfo* navigation_info) {
+void Predictor::LearnFromNavigation(const GURL& referring_url,
+ const GURL& target_url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- GURL url = navigation_info->url();
- Results::iterator it = results_.find(url);
- if (it == results_.end()) {
- // Use UMA histogram to quantify potential future gains here.
- UMA_HISTOGRAM_LONG_TIMES("DNS.UnexpectedResolutionL",
- navigation_info->resolve_duration());
- navigation_info->DLogResultsStats("DNS UnexpectedResolution");
-
- LearnFromNavigation(referrer, navigation_info->url());
- return false;
- }
- UrlInfo& prefetched_host_info(it->second);
-
- // Sometimes a host is used as a subresource by several referrers, so it is
- // in our list, but was never motivated by a page-link-scan. In that case, it
- // really is an "unexpected" navigation, and we should tally it, and augment
- // our referrers_.
- bool referrer_based_prefetch = !prefetched_host_info.was_linked();
- if (referrer_based_prefetch) {
- // This wasn't the first time this host refered to *some* referrer.
- LearnFromNavigation(referrer, navigation_info->url());
+ DCHECK(referring_url == referring_url.GetWithEmptyPath());
+ DCHECK(target_url == target_url.GetWithEmptyPath());
+ DCHECK(target_url != referring_url);
+ if (referring_url.has_host()) {
+ referrers_[referring_url].SuggestHost(target_url);
}
+}
- DnsBenefit benefit = prefetched_host_info.AccruePrefetchBenefits(
- navigation_info);
- switch (benefit) {
- case PREFETCH_NAME_FOUND:
- case PREFETCH_NAME_NONEXISTANT:
- dns_cache_hits_.push_back(*navigation_info);
- if (referrer_based_prefetch) {
- if (referrer.has_host()) {
- referrers_[referrer].AccrueValue(
- navigation_info->benefits_remaining(), url);
- }
- }
- return true;
+enum SubresourceValue {
+ PRECONNECTION,
+ PRERESOLUTION,
+ TOO_NEW,
+ SUBRESOURCE_VALUE_MAX
+};
- case PREFETCH_CACHE_EVICTION:
- cache_eviction_map_[url] = *navigation_info;
- return false;
+void Predictor::AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
+ std::string host = url.HostNoBrackets();
+ bool is_new_host_request = (host != last_omnibox_host_);
+ last_omnibox_host_ = host;
+
+ UrlInfo::ResolutionMotivation motivation(UrlInfo::OMNIBOX_MOTIVATED);
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ if (preconnect_enabled()) {
+ if (preconnectable && !is_new_host_request) {
+ ++consecutive_omnibox_preconnect_count_;
+ // The omnibox suggests a search URL (for which we can preconnect) after
+ // one or two characters are typed, even though such typing often (1 in
+ // 3?) becomes a real URL. This code waits till is has more evidence of a
+ // preconnectable URL (search URL) before forming a preconnection, so as
+ // to reduce the useless preconnect rate.
+ // Perchance this logic should be pushed back into the omnibox, where the
+ // actual characters typed, such as a space, can better forcast whether
+ // we need to search/preconnect or not. By waiting for at least 4
+ // characters in a row that have lead to a search proposal, we avoid
+ // preconnections for a prefix like "www." and we also wait until we have
+ // at least a 4 letter word to search for.
+ // Each character typed appears to induce 2 calls to
+ // AnticipateOmniboxUrl(), so we double 4 characters and limit at 8
+ // requests.
+ // TODO(jar): Use an A/B test to optimize this.
+ const int kMinConsecutiveRequests = 8;
+ if (consecutive_omnibox_preconnect_count_ >= kMinConsecutiveRequests) {
+ // TODO(jar): The wild guess of 30 seconds could be tuned/tested, but it
+ // currently is just a guess that most sockets will remain open for at
+ // least 30 seconds. This avoids a lot of cross-thread posting, and
+ // exercise of the network stack in this common case.
+ const int kMaxSearchKeepaliveSeconds(30);
+ if ((now - last_omnibox_preconnect_).InSeconds() <
+ kMaxSearchKeepaliveSeconds)
+ return; // We've done a preconnect recently.
+ last_omnibox_preconnect_ = now;
+
+ Preconnect::PreconnectOnUIThread(CanonicalizeUrl(url), motivation);
+ return; // Skip pre-resolution, since we'll open a connection.
+ }
+ } else {
+ consecutive_omnibox_preconnect_count_ = 0;
+ }
+ }
- case PREFETCH_NO_BENEFIT:
- // Prefetch never hit the network. Name was pre-cached.
- return false;
+ // Fall through and consider pre-resolution.
- default:
- NOTREACHED();
- return false;
+ // Omnibox tends to call in pairs (just a few milliseconds apart), and we
+ // really don't need to keep resolving a name that often.
+ // TODO(jar): A/B tests could check for perf impact of the early returns.
+ if (!is_new_host_request) {
+ const int kMinPreresolveSeconds(10);
+ if (kMinPreresolveSeconds > (now - last_omnibox_preresolve_).InSeconds())
+ return;
}
+ last_omnibox_preresolve_ = now;
+
+ // Perform at least DNS pre-resolution.
+ ChromeThread::PostTask(
+ ChromeThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(this, &Predictor::Resolve, CanonicalizeUrl(url),
+ motivation));
}
-void Predictor::LearnFromNavigation(const GURL& referring_url,
- const GURL& target_url) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (referring_url.has_host() &&
- referring_url != target_url) {
- DCHECK(referring_url == referring_url.GetWithEmptyPath());
- referrers_[referring_url].SuggestHost(target_url);
+void Predictor::PreconnectUrlAndSubresources(const GURL& url) {
+ if (preconnect_enabled()) {
+ std::string host = url.HostNoBrackets();
+ UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED);
+ Preconnect::PreconnectOnUIThread(CanonicalizeUrl(url), motivation);
+ PredictFrameSubresources(url.GetWithEmptyPath());
}
}
-void Predictor::PredictSubresources(const GURL& url) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- Referrers::iterator it = referrers_.find(url);
- if (referrers_.end() == it)
- return;
- Referrer* referrer = &(it->second);
- referrer->IncrementUseCount();
- for (Referrer::iterator future_url = referrer->begin();
- future_url != referrer->end(); ++future_url) {
- UrlInfo* queued_info = AppendToResolutionQueue(
- future_url->first,
- UrlInfo::LEARNED_REFERAL_MOTIVATED);
- if (queued_info)
- queued_info->SetReferringHostname(url);
- }
+void Predictor::PredictFrameSubresources(const GURL& url) {
+ DCHECK(url.GetWithEmptyPath() == url);
+ // Add one pass through the message loop to allow current navigation to
+ // proceed.
+ ChromeThread::PostTask(
+ ChromeThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(this, &Predictor::PrepareFrameSubresources, url));
}
-void Predictor::PredictFrameSubresources(const GURL& url) {
+void Predictor::PrepareFrameSubresources(const GURL& url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
DCHECK(url.GetWithEmptyPath() == url);
Referrers::iterator it = referrers_.find(url);
if (referrers_.end() == it)
return;
+
Referrer* referrer = &(it->second);
referrer->IncrementUseCount();
+ const UrlInfo::ResolutionMotivation motivation =
+ UrlInfo::LEARNED_REFERAL_MOTIVATED;
for (Referrer::iterator future_url = referrer->begin();
future_url != referrer->end(); ++future_url) {
- if (future_url->second.IsPreconnectWorthDoing())
- Preconnect::PreconnectOnIOThread(future_url->first);
+ SubresourceValue evalution(TOO_NEW);
+ double connection_expectation = future_url->second.subresource_use_rate();
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation",
+ static_cast<int>(connection_expectation * 100),
+ 10, 5000, 50);
+ future_url->second.ReferrerWasObserved();
+ if (preconnect_enabled_ &&
+ kPreconnectWorthyExpectedValue < connection_expectation) {
+ evalution = PRECONNECTION;
+ future_url->second.IncrementPreconnectionCount();
+ Preconnect::PreconnectOnIOThread(future_url->first, motivation);
+ } else if (kDNSPreresolutionWorthyExpectedValue < connection_expectation) {
+ evalution = PRERESOLUTION;
+ future_url->second.preresolution_increment();
+ UrlInfo* queued_info = AppendToResolutionQueue(future_url->first,
+ motivation);
+ if (queued_info)
+ queued_info->SetReferringHostname(url);
+ }
+ UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution,
+ SUBRESOURCE_VALUE_MAX);
}
}
// Provide sort order so all .com's are together, etc.
struct RightToLeftStringSorter {
- bool operator()(const net::HostPortPair& left,
- const net::HostPortPair& right) const {
- return string_compare(left.host, right.host);
- }
bool operator()(const GURL& left,
const GURL& right) const {
return string_compare(left.host(), right.host());
@@ -301,8 +351,8 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
"<th>Page Load<br>Count</th>"
"<th>Subresource<br>Navigations</th>"
"<th>Subresource<br>PreConnects</th>"
+ "<th>Subresource<br>PreResolves</th>"
"<th>Expected<br>Connects</th>"
- "<th>DNS<br>Savings</th>"
"<th>Subresource Spec</th></tr>");
for (SortedNames::iterator it = sorted_names.begin();
@@ -320,11 +370,11 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
static_cast<int>(referrer->use_count()));
first_set_of_futures = false;
StringAppendF(output,
- "<td>%d</td><td>%d</td><td>%2.3f</td><td>%dms</td><td>%s</td></tr>",
+ "<td>%d</td><td>%d</td><td>%d</td><td>%2.3f</td><td>%s</td></tr>",
static_cast<int>(future_url->second.navigation_count()),
static_cast<int>(future_url->second.preconnection_count()),
+ static_cast<int>(future_url->second.preresolution_count()),
static_cast<double>(future_url->second.subresource_use_rate()),
- static_cast<int>(future_url->second.latency().InMilliseconds()),
future_url->first.spec().c_str());
}
}
@@ -334,53 +384,26 @@ void Predictor::GetHtmlReferrerLists(std::string* output) {
void Predictor::GetHtmlInfo(std::string* output) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
// Local lists for calling UrlInfo
- UrlInfo::DnsInfoTable cache_hits;
- UrlInfo::DnsInfoTable cache_evictions;
- UrlInfo::DnsInfoTable name_not_found;
- UrlInfo::DnsInfoTable network_hits;
- UrlInfo::DnsInfoTable already_cached;
+ UrlInfo::UrlInfoTable name_not_found;
+ UrlInfo::UrlInfoTable name_preresolved;
// Get copies of all useful data.
- typedef std::map<GURL, UrlInfo, RightToLeftStringSorter>
- Snapshot;
- Snapshot snapshot;
- {
- // UrlInfo supports value semantics, so we can do a shallow copy.
- for (Results::iterator it(results_.begin()); it != results_.end(); it++) {
- snapshot[it->first] = it->second;
- }
- for (Results::iterator it(cache_eviction_map_.begin());
- it != cache_eviction_map_.end();
- it++) {
- cache_evictions.push_back(it->second);
- }
- // Reverse list as we copy cache hits, so that new hits are at the top.
- size_t index = dns_cache_hits_.size();
- while (index > 0) {
- index--;
- cache_hits.push_back(dns_cache_hits_[index]);
- }
- }
+ typedef std::map<GURL, UrlInfo, RightToLeftStringSorter> SortedUrlInfo;
+ SortedUrlInfo snapshot;
+ // UrlInfo supports value semantics, so we can do a shallow copy.
+ for (Results::iterator it(results_.begin()); it != results_.end(); it++)
+ snapshot[it->first] = it->second;
// Partition the UrlInfo's into categories.
- for (Snapshot::iterator it(snapshot.begin()); it != snapshot.end(); it++) {
- if (it->second.was_nonexistant()) {
+ for (SortedUrlInfo::iterator it(snapshot.begin());
+ it != snapshot.end(); it++) {
+ if (it->second.was_nonexistent()) {
name_not_found.push_back(it->second);
continue;
}
if (!it->second.was_found())
continue; // Still being processed.
- if (TimeDelta() != it->second.benefits_remaining()) {
- network_hits.push_back(it->second); // With no benefit yet.
- continue;
- }
- if (UrlInfo::kMaxNonNetworkDnsLookupDuration >
- it->second.resolve_duration()) {
- already_cached.push_back(it->second);
- continue;
- }
- // Remaining case is where prefetch benefit was significant, and was used.
- // Since we shot those cases as historical hits, we won't bother here.
+ name_preresolved.push_back(it->second);
}
bool brief = false;
@@ -389,16 +412,10 @@ void Predictor::GetHtmlInfo(std::string* output) {
#endif // NDEBUG
// Call for display of each table, along with title.
- UrlInfo::GetHtmlTable(cache_hits,
- "Prefetching DNS records produced benefits for ", false, output);
- UrlInfo::GetHtmlTable(cache_evictions,
- "Cache evictions negated DNS prefetching benefits for ", brief, output);
- UrlInfo::GetHtmlTable(network_hits,
- "Prefetching DNS records was not yet beneficial for ", brief, output);
- UrlInfo::GetHtmlTable(already_cached,
- "Previously cached resolutions were found for ", brief, output);
+ UrlInfo::GetHtmlTable(name_preresolved,
+ "Preresolution DNS records performed for ", brief, output);
UrlInfo::GetHtmlTable(name_not_found,
- "Prefetching DNS records revealed non-existance for ", brief, output);
+ "Preresolving DNS records revealed non-existence for ", brief, output);
}
UrlInfo* Predictor::AppendToResolutionQueue(
@@ -507,8 +524,6 @@ void Predictor::LookupFinished(LookupRequest* request, const GURL& url,
void Predictor::DiscardAllResults() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
// Delete anything listed so far in this session that shows in about:dns.
- cache_eviction_map_.clear();
- dns_cache_hits_.clear();
referrers_.clear();
@@ -559,7 +574,7 @@ void Predictor::TrimReferrers() {
void Predictor::SerializeReferrers(ListValue* referral_list) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
referral_list->Clear();
- referral_list->Append(new FundamentalValue(DNS_REFERRER_VERSION));
+ referral_list->Append(new FundamentalValue(PREDICTOR_REFERRER_VERSION));
for (Referrers::const_iterator it = referrers_.begin();
it != referrers_.end(); ++it) {
// Serialize the list of subresource names.
@@ -579,7 +594,7 @@ void Predictor::DeserializeReferrers(const ListValue& referral_list) {
int format_version = -1;
if (referral_list.GetSize() > 0 &&
referral_list.GetInteger(0, &format_version) &&
- format_version == DNS_REFERRER_VERSION) {
+ format_version == PREDICTOR_REFERRER_VERSION) {
for (size_t i = 1; i < referral_list.GetSize(); ++i) {
ListValue* motivator;
if (!referral_list.GetList(i, &motivator)) {
@@ -640,4 +655,39 @@ GURL Predictor::HostNameQueue::Pop() {
return url;
}
+void Predictor::DeserializeReferrersThenDelete(ListValue* referral_list) {
+ DeserializeReferrers(*referral_list);
+ delete referral_list;
+}
+
+
+//------------------------------------------------------------------------------
+// Helper functions
+//------------------------------------------------------------------------------
+
+// static
+GURL Predictor::CanonicalizeUrl(const GURL& url) {
+ if (!url.has_host())
+ return GURL::EmptyGURL();
+
+ std::string scheme;
+ if (url.has_scheme()) {
+ scheme = url.scheme();
+ if (scheme != "http" && scheme != "https")
+ return GURL::EmptyGURL();
+ if (url.has_port())
+ return url.GetWithEmptyPath();
+ } else {
+ scheme = "http";
+ }
+
+ // If we omit a port, it will default to 80 or 443 as appropriate.
+ std::string colon_plus_port;
+ if (url.has_port())
+ colon_plus_port = ":" + url.port();
+
+ return GURL(scheme + "://" + url.host() + colon_plus_port);
+}
+
+
} // namespace chrome_browser_net
diff --git a/chrome/browser/net/predictor.h b/chrome/browser/net/predictor.h
index d1467a8..c840a00 100644
--- a/chrome/browser/net/predictor.h
+++ b/chrome/browser/net/predictor.h
@@ -13,17 +13,17 @@
// Subresource relationships are usually acquired from the referrer field in a
// navigation. A subresource URL may be associated with a referrer URL. Later
// navigations may, if the likelihood of needing the subresource is high enough,
-// cause this module to speculatively create a TCP/IP connection that will
-// probably be needed to fetch the subresource.
+// cause this module to speculatively create a TCP/IP connection. If there is
+// only a low likelihood, then a DNS pre-resolution operation may be performed.
#ifndef CHROME_BROWSER_NET_PREDICTOR_H_
#define CHROME_BROWSER_NET_PREDICTOR_H_
+#pragma once
#include <map>
#include <queue>
#include <set>
#include <string>
-#include <vector>
#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
@@ -32,6 +32,8 @@
#include "chrome/common/net/predictor_common.h"
#include "net/base/host_port_pair.h"
+class ListValue;
+
namespace net {
class HostResolver;
} // namespace net
@@ -48,9 +50,19 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
public:
// A version number for prefs that are saved. This should be incremented when
// we change the format so that we discard old data.
- enum { DNS_REFERRER_VERSION = 1 };
-
-// |max_concurrent| specifies how many concurrent (parallel) prefetches will
+ enum { PREDICTOR_REFERRER_VERSION = 2 };
+
+ // Depending on the expected_subresource_use_, we may either make a TCP/IP
+ // preconnection, or merely pre-resolve the hostname via DNS (or even do
+ // nothing). The following are the threasholds for taking those actions.
+ static const double kPreconnectWorthyExpectedValue;
+ static const double kDNSPreresolutionWorthyExpectedValue;
+ // Values of expected_subresource_use_ that are less than the following
+ // threshold will be discarded when we Trim() the values, such as is done when
+ // the process ends, and some values are persisted.
+ static const double kPersistWorthyExpectedValue;
+
+ // |max_concurrent| specifies how many concurrent (parallel) prefetches will
// be performed. Host lookups will be issued through |host_resolver|.
Predictor(net::HostResolver* host_resolver,
base::TimeDelta max_queue_delay_ms, size_t max_concurrent,
@@ -72,20 +84,25 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
void Resolve(const GURL& url,
UrlInfo::ResolutionMotivation motivation);
- // Get latency benefit of the prefetch that we are navigating to.
- bool AccruePrefetchBenefits(const GURL& referrer,
- UrlInfo* navigation_info);
+ // Instigate pre-connection to any URLs, or pre-resolution of related host,
+ // that we predict will be needed after this navigation (typically
+ // more-embedded resources on a page). This method will actually post a task
+ // to do the actual work, so as not to jump ahead of the frame navigation that
+ // instigated this activity.
+ void PredictFrameSubresources(const GURL& url);
- // Instigate preresolution of any domains we predict will be needed after this
- // navigation.
- void PredictSubresources(const GURL& url);
+ // The Omnibox has proposed a given url to the user, and if it is a search
+ // URL, then it also indicates that this is preconnectable (i.e., we could
+ // preconnect to the search server).
+ void AnticipateOmniboxUrl(const GURL& url, bool preconnectable);
- // Instigate pre-connection to any URLs we predict will be needed after this
- // navigation (typically more-embedded resources on a page).
- void PredictFrameSubresources(const GURL& url);
+ // Preconnect a URL and all of its subresource domains.
+ void PreconnectUrlAndSubresources(const GURL& url);
// Record details of a navigation so that we can preresolve the host name
// ahead of time the next time the users navigates to the indicated host.
+ // Should only be called when urls are distinct, and they should already be
+ // canonicalized to not have a path.
void LearnFromNavigation(const GURL& referring_url, const GURL& target_url);
// Dump HTML table containing list of referrers for about:dns.
@@ -111,10 +128,7 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// values into the current referrer list.
void DeserializeReferrers(const ListValue& referral_list);
- void DeserializeReferrersThenDelete(ListValue* referral_list) {
- DeserializeReferrers(*referral_list);
- delete referral_list;
- }
+ void DeserializeReferrersThenDelete(ListValue* referral_list);
// For unit test code only.
size_t max_concurrent_dns_lookups() const {
@@ -124,6 +138,11 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// Flag setting to use preconnection instead of just DNS pre-fetching.
bool preconnect_enabled() const { return preconnect_enabled_; }
+ // Put URL in canonical form, including a scheme, host, and port.
+ // Returns GURL::EmptyGURL() if the scheme is not http/https or if the url
+ // cannot be otherwise canonicalized.
+ static GURL CanonicalizeUrl(const GURL& url);
+
private:
friend class base::RefCountedThreadSafe<Predictor>;
FRIEND_TEST_ALL_PREFIXES(PredictorTest, BenefitLookupTest);
@@ -135,8 +154,6 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
FRIEND_TEST_ALL_PREFIXES(PredictorTest, PriorityQueueReorderTest);
friend class WaitForResolutionHelper; // For testing.
- ~Predictor();
-
class LookupRequest;
// A simple priority queue for handling host names.
@@ -171,6 +188,13 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// in a Referrer instance, which is a value in this map.
typedef std::map<GURL, Referrer> Referrers;
+ ~Predictor();
+
+ // Perform actual resolution or preconnection to subresources now. This is
+ // an internal worker method that is reached via a post task from
+ // PredictFrameSubresources().
+ void PrepareFrameSubresources(const GURL& url);
+
// Only for testing. Returns true if hostname has been successfully resolved
// (name found).
bool WasFound(const GURL& url) const {
@@ -239,12 +263,6 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// When true, we don't make new lookup requests.
bool shutdown_;
- // A list of successful events resulting from pre-fetching.
- UrlInfo::DnsInfoTable dns_cache_hits_;
- // A map of hosts that were evicted from our cache (after we prefetched them)
- // and before the HTTP stack tried to look them up.
- Results cache_eviction_map_;
-
// The number of concurrent lookups currently allowed.
const size_t max_concurrent_dns_lookups_;
@@ -259,6 +277,19 @@ class Predictor : public base::RefCountedThreadSafe<Predictor> {
// subresources and omni-box search URLs.
bool preconnect_enabled_;
+ // Most recent suggestion from Omnibox provided via AnticipateOmniboxUrl().
+ std::string last_omnibox_host_;
+
+ // The time when the last preresolve was done for last_omnibox_host_.
+ base::TimeTicks last_omnibox_preresolve_;
+
+ // The number of consecutive requests to AnticipateOmniboxUrl() that suggested
+ // preconnecting (because it was to a search service).
+ int consecutive_omnibox_preconnect_count_;
+
+ // The time when the last preconnection was requested to a search service.
+ base::TimeTicks last_omnibox_preconnect_;
+
DISALLOW_COPY_AND_ASSIGN(Predictor);
};
diff --git a/chrome/browser/net/predictor_api.cc b/chrome/browser/net/predictor_api.cc
index d5f661d..e843adc 100644
--- a/chrome/browser/net/predictor_api.cc
+++ b/chrome/browser/net/predictor_api.cc
@@ -10,20 +10,20 @@
#include "base/singleton.h"
#include "base/stats_counters.h"
#include "base/stl_util-inl.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/thread.h"
-#include "base/waitable_event.h"
#include "base/values.h"
+#include "base/waitable_event.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/io_thread.h"
-#include "chrome/browser/net/url_info.h"
#include "chrome/browser/net/preconnect.h"
#include "chrome/browser/net/referrer.h"
-#include "chrome/browser/pref_service.h"
+#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/session_startup_pref.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -35,14 +35,11 @@ using base::TimeDelta;
namespace chrome_browser_net {
-static void DnsMotivatedPrefetch(const GURL& url,
- UrlInfo::ResolutionMotivation motivation);
-
static void DnsPrefetchMotivatedList(const UrlList& urls,
- UrlInfo::ResolutionMotivation motivation);
+ UrlInfo::ResolutionMotivation motivation);
-static UrlList GetPredictedUrlListAtStartup(
- PrefService* user_prefs, PrefService* local_state);
+static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
+ PrefService* local_state);
// static
const size_t PredictorInit::kMaxPrefetchConcurrentLookups = 8;
@@ -54,43 +51,45 @@ const int PredictorInit::kMaxPrefetchQueueingDelayMs = 500;
// we change the format so that we discard old data.
static const int kPredictorStartupFormatVersion = 1;
-//------------------------------------------------------------------------------
-// Static helper functions
-//------------------------------------------------------------------------------
+// There will only be one instance ever created of the following Observer class.
+// The InitialObserver lives on the IO thread, and monitors navigations made by
+// the network stack. This is only used to identify startup time resolutions
+// (for re-resolution during our next process startup).
+// TODO(jar): Consider preconnecting at startup, which may be faster than
+// waiting for render process to start and request a connection.
+class InitialObserver {
+ public:
+ // Recording of when we observed each navigation.
+ typedef std::map<GURL, base::TimeTicks> FirstNavigations;
-// Put URL in canonical form, including a scheme, host, and port.
-// Returns GURL::EmptyGURL() if the scheme is not http/https or if the url
-// cannot be otherwise canonicalized.
-static GURL CanonicalizeUrl(const GURL& url) {
- if (!url.has_host())
- return GURL::EmptyGURL();
-
- std::string scheme;
- if (url.has_scheme()) {
- scheme = url.scheme();
- if (scheme != "http" && scheme != "https")
- return GURL::EmptyGURL();
- if (url.has_port())
- return url.GetWithEmptyPath();
- } else {
- scheme = "http";
- }
+ // Potentially add a new URL to our startup list.
+ void Append(const GURL& url);
- // If we omit a port, it will default to 80 or 443 as appropriate.
- std::string colon_plus_port;
- if (url.has_port())
- colon_plus_port = ":" + url.port();
+ // Get an HTML version of our current planned first_navigations_.
+ void GetFirstResolutionsHtml(std::string* output);
- return GURL(scheme + "://" + url.host() + colon_plus_port);
-}
+ // Persist the current first_navigations_ for storage in a list.
+ void GetInitialDnsResolutionList(ListValue* startup_list);
+
+ private:
+ // List of the first N URL resolutions observed in this run.
+ FirstNavigations first_navigations_;
+
+ // The number of URLs we'll save for pre-resolving at next startup.
+ static const size_t kStartupResolutionCount = 10;
+};
+
+// TODO(willchan): Look at killing this global.
+static InitialObserver* g_initial_observer = NULL;
//------------------------------------------------------------------------------
// This section contains all the globally accessable API entry points for the
// DNS Prefetching feature.
//------------------------------------------------------------------------------
-// Status of prefetch feature, controlling whether any prefetching is done.
-static bool dns_prefetch_enabled = true;
+// Status of speculative DNS resolution and speculative TCP/IP connection
+// feature.
+static bool predictor_enabled = true;
// Cached inverted copy of the off_the_record pref.
static bool on_the_record_switch = true;
@@ -98,7 +97,7 @@ static bool on_the_record_switch = true;
// Enable/disable Dns prefetch activity (either via command line, or via pref).
void EnablePredictor(bool enable) {
// NOTE: this is invoked on the UI thread.
- dns_prefetch_enabled = enable;
+ predictor_enabled = enable;
}
void OnTheRecord(bool enable) {
@@ -122,14 +121,15 @@ void RegisterUserPrefs(PrefService* user_prefs) {
// When enabled, we use the following instance to service all requests in the
// browser process.
// TODO(willchan): Look at killing this.
-static Predictor* predictor = NULL;
+static Predictor* g_predictor = NULL;
// This API is only used in the browser process.
// It is called from an IPC message originating in the renderer. It currently
// includes both Page-Scan, and Link-Hover prefetching.
// TODO(jar): Separate out link-hover prefetching, and page-scan results.
void DnsPrefetchList(const NameList& hostnames) {
- // TODO(jar): Push GURL transport further back into renderer.
+ // TODO(jar): Push GURL transport further back into renderer, but this will
+ // require a Webkit change in the observer :-/.
UrlList urls;
for (NameList::const_iterator it = hostnames.begin();
it < hostnames.end();
@@ -146,78 +146,41 @@ static void DnsPrefetchMotivatedList(
UrlInfo::ResolutionMotivation motivation) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI) ||
ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!dns_prefetch_enabled || NULL == predictor)
+ if (!predictor_enabled || NULL == g_predictor)
return;
if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- predictor->ResolveList(urls, motivation);
+ g_predictor->ResolveList(urls, motivation);
} else {
ChromeThread::PostTask(
ChromeThread::IO,
FROM_HERE,
- NewRunnableMethod(predictor,
+ NewRunnableMethod(g_predictor,
&Predictor::ResolveList, urls, motivation));
}
}
// This API is used by the autocomplete popup box (where URLs are typed).
-void AnticipateUrl(const GURL& url, bool preconnectable) {
+void AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- if (!dns_prefetch_enabled || NULL == predictor)
+ if (!predictor_enabled || NULL == g_predictor)
return;
- if (!url.is_valid())
+ if (!url.is_valid() || !url.has_host())
return;
- static std::string last_host;
- std::string host = url.HostNoBrackets();
- bool is_new_host_request = (host != last_host);
- last_host = host;
-
- // Omnibox tends to call in pairs (just a few milliseconds apart), and we
- // really don't need to keep resolving a name that often.
- // TODO(jar): A/B tests could check for perf impact of the early returns.
- static base::TimeTicks last_prefetch_for_host;
- base::TimeTicks now = base::TimeTicks::Now();
- if (!is_new_host_request) {
- const int kMinPreresolveSeconds(10);
- if (kMinPreresolveSeconds > (now - last_prefetch_for_host).InSeconds())
- return;
- }
- last_prefetch_for_host = now;
-
- GURL canonical_url(CanonicalizeUrl(url));
-
- if (predictor->preconnect_enabled() && preconnectable) {
- static base::TimeTicks last_keepalive;
- // TODO(jar): The wild guess of 30 seconds could be tuned/tested, but it
- // currently is just a guess that most sockets will remain open for at least
- // 30 seconds.
- const int kMaxSearchKeepaliveSeconds(30);
- if ((now - last_keepalive).InSeconds() < kMaxSearchKeepaliveSeconds)
- return;
- last_keepalive = now;
-
- if (Preconnect::PreconnectOnUIThread(canonical_url))
- return; // Skip pre-resolution, since we'll open a connection.
- }
-
- // Perform at least DNS pre-resolution.
- DnsMotivatedPrefetch(canonical_url, UrlInfo::OMNIBOX_MOTIVATED);
+ g_predictor->AnticipateOmniboxUrl(url, preconnectable);
}
-static void DnsMotivatedPrefetch(const GURL& url,
- UrlInfo::ResolutionMotivation motivation) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- if (!dns_prefetch_enabled || NULL == predictor || !url.has_host())
+void PreconnectUrlAndSubresources(const GURL& url) {
+ if (!predictor_enabled || NULL == g_predictor)
+ return;
+ if (!url.is_valid() || !url.has_host())
return;
- ChromeThread::PostTask(
- ChromeThread::IO,
- FROM_HERE,
- NewRunnableMethod(predictor,
- &Predictor::Resolve, url, motivation));
+ g_predictor->PreconnectUrlAndSubresources(url);
}
+
//------------------------------------------------------------------------------
// This section intermingles prefetch results with actual browser HTTP
// network activity. It supports calculating of the benefit of a prefetch, as
@@ -225,201 +188,75 @@ static void DnsMotivatedPrefetch(const GURL& url,
// helpful during the next chrome-startup.
//------------------------------------------------------------------------------
-// This function determines if there was a saving by prefetching the hostname
-// for which the navigation_info is supplied.
-static bool AccruePrefetchBenefits(const GURL& referrer_url,
- UrlInfo* navigation_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!dns_prefetch_enabled || NULL == predictor)
- return false;
- DCHECK(referrer_url == referrer_url.GetWithEmptyPath());
- return predictor->AccruePrefetchBenefits(referrer_url, navigation_info);
-}
-
-void PredictSubresources(const GURL& url) {
+void PredictFrameSubresources(const GURL& url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!dns_prefetch_enabled || NULL == predictor)
+ if (!predictor_enabled || NULL == g_predictor)
return;
- predictor->PredictSubresources(url);
+ g_predictor->PredictFrameSubresources(url);
}
-void PredictFrameSubresources(const GURL& url) {
+void LearnAboutInitialNavigation(const GURL& url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!dns_prefetch_enabled || NULL == predictor)
+ if (!predictor_enabled || NULL == g_initial_observer )
return;
- predictor->PredictFrameSubresources(url);
+ g_initial_observer->Append(url);
}
void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!dns_prefetch_enabled || NULL == predictor)
+ if (!predictor_enabled || NULL == g_predictor)
return;
- predictor->LearnFromNavigation(referring_url, target_url);
+ g_predictor->LearnFromNavigation(referring_url, target_url);
}
// The observer class needs to connect starts and finishes of HTTP network
// resolutions. We use the following type for that map.
typedef std::map<int, UrlInfo> ObservedResolutionMap;
-// There will only be one instance ever created of the following Observer
-// class. The PrefetchObserver lives on the IO thread, and intercepts DNS
-// resolutions made by the network stack.
-class PrefetchObserver : public net::HostResolver::Observer {
- public:
- typedef std::map<GURL, UrlInfo> FirstResolutionMap;
-
- // net::HostResolver::Observer implementation:
- virtual void OnStartResolution(
- int request_id,
- const net::HostResolver::RequestInfo& request_info);
- virtual void OnFinishResolutionWithStatus(
- int request_id,
- bool was_resolved,
- const net::HostResolver::RequestInfo& request_info);
- virtual void OnCancelResolution(
- int request_id,
- const net::HostResolver::RequestInfo& request_info);
-
- void DnsGetFirstResolutionsHtml(std::string* output);
- void GetInitialDnsResolutionList(ListValue* startup_list);
-
- private:
- void StartupListAppend(const UrlInfo& navigation_info);
-
- // Map of pending resolutions seen by observer.
- ObservedResolutionMap resolutions_;
- // List of the first N hostname resolutions observed in this run.
- FirstResolutionMap first_resolutions_;
- // The number of hostnames we'll save for prefetching at next startup.
- static const size_t kStartupResolutionCount = 10;
-};
-
-// TODO(willchan): Look at killing this global.
-static PrefetchObserver* g_prefetch_observer = NULL;
-
//------------------------------------------------------------------------------
-// Member definitions for above Observer class.
-
-void PrefetchObserver::OnStartResolution(
- int request_id,
- const net::HostResolver::RequestInfo& request_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (request_info.is_speculative())
- return; // One of our own requests.
- if (!request_info.hostname().length())
- return; // PAC scripts may create queries without a hostname.
-
- UrlInfo navigation_info;
- // TODO(jar): Remove hack which guestimates ssl via port number, and perhaps
- // have actual URL passed down in request_info instead.
- bool is_ssl(443 == request_info.port());
- std::string url_spec = is_ssl ? "https://" : "http://";
- url_spec += request_info.hostname();
- url_spec += ":";
- url_spec += IntToString(request_info.port());
- navigation_info.SetUrl(GURL(url_spec));
- navigation_info.SetStartedState();
-
- // This entry will be deleted either by OnFinishResolutionWithStatus(), or
- // by OnCancelResolution().
- resolutions_[request_id] = navigation_info;
-}
+// Member definitions for InitialObserver class.
-void PrefetchObserver::OnFinishResolutionWithStatus(
- int request_id,
- bool was_resolved,
- const net::HostResolver::RequestInfo& request_info) {
+void InitialObserver::Append(const GURL& url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (request_info.is_speculative())
- return; // One of our own requests.
- if (!request_info.hostname().length())
- return; // PAC scripts may create queries without a hostname.
- UrlInfo navigation_info;
- size_t startup_count = 0;
- {
- ObservedResolutionMap::iterator it = resolutions_.find(request_id);
- if (resolutions_.end() == it) {
- NOTREACHED();
- return;
- }
- navigation_info = it->second;
- resolutions_.erase(it);
- startup_count = first_resolutions_.size();
- }
-
- navigation_info.SetFinishedState(was_resolved); // Get timing info
- AccruePrefetchBenefits(CanonicalizeUrl(request_info.referrer()),
- &navigation_info);
- // Handle sub-resource resolutions now that the critical navigational
- // resolution has completed. This prevents us from in any way delaying that
- // navigational resolution.
- std::string url_spec;
- StringAppendF(&url_spec, "http%s://%s:%d", "",
- request_info.hostname().c_str(), request_info.port());
- PredictSubresources(GURL(url_spec));
-
- if (kStartupResolutionCount <= startup_count || !was_resolved)
+ if (!on_the_record_switch || NULL == g_predictor)
return;
- // TODO(jar): Don't add host to our list if it is a non-linked lookup, and
- // instead rely on Referrers to pull this in automatically with the enclosing
- // page load (once we start to persist elements of our referrer tree).
- StartupListAppend(navigation_info);
-}
-
-void PrefetchObserver::OnCancelResolution(
- int request_id,
- const net::HostResolver::RequestInfo& request_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (request_info.is_speculative())
- return; // One of our own requests.
- if (!request_info.hostname().length())
- return; // PAC scripts may create queries without a hostname.
-
- // Remove the entry from |resolutions| that was added by OnStartResolution().
- ObservedResolutionMap::iterator it = resolutions_.find(request_id);
- if (resolutions_.end() == it) {
- NOTREACHED();
+ if (kStartupResolutionCount <= first_navigations_.size())
return;
- }
- resolutions_.erase(it);
-}
-
-void PrefetchObserver::StartupListAppend(const UrlInfo& navigation_info) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (!on_the_record_switch || NULL == predictor)
- return;
- if (kStartupResolutionCount <= first_resolutions_.size())
- return; // Someone just added the last item.
- if (ContainsKey(first_resolutions_, navigation_info.url()))
- return; // We already have this hostname listed.
- first_resolutions_[navigation_info.url()] = navigation_info;
+ if (url.SchemeIs("http") || url.SchemeIs("https")) {
+ const GURL url_without_path(url.GetWithEmptyPath());
+ if (first_navigations_.find(url_without_path) == first_navigations_.end())
+ first_navigations_[url_without_path] = base::TimeTicks::Now();
+ }
}
-void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
+void InitialObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
DCHECK(startup_list);
startup_list->Clear();
DCHECK_EQ(0u, startup_list->GetSize());
startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion));
- for (FirstResolutionMap::iterator it = first_resolutions_.begin();
- it != first_resolutions_.end();
+ for (FirstNavigations::iterator it = first_navigations_.begin();
+ it != first_navigations_.end();
++it) {
- DCHECK(it->first == CanonicalizeUrl(it->first));
+ DCHECK(it->first == Predictor::CanonicalizeUrl(it->first));
startup_list->Append(new StringValue(it->first.spec()));
}
}
-void PrefetchObserver::DnsGetFirstResolutionsHtml(std::string* output) {
+void InitialObserver::GetFirstResolutionsHtml(std::string* output) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- UrlInfo::DnsInfoTable resolution_list;
+ UrlInfo::UrlInfoTable resolution_list;
{
- for (FirstResolutionMap::iterator it(first_resolutions_.begin());
- it != first_resolutions_.end();
+ for (FirstNavigations::iterator it(first_navigations_.begin());
+ it != first_navigations_.end();
it++) {
- resolution_list.push_back(it->second);
+ UrlInfo info;
+ info.SetUrl(it->first);
+ info.set_time(it->second);
+ resolution_list.push_back(info);
}
}
UrlInfo::GetHtmlTable(resolution_list,
@@ -491,16 +328,19 @@ void PredictorGetHtmlInfo(std::string* output) {
// We'd like the following no-cache... but it doesn't work.
// "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
"</head><body>");
- if (!dns_prefetch_enabled || NULL == predictor) {
+ if (!predictor_enabled || NULL == g_predictor) {
output->append("Dns Prefetching is disabled.");
} else {
if (!on_the_record_switch) {
output->append("Incognito mode is active in a window.");
} else {
- predictor->GetHtmlInfo(output);
- if (g_prefetch_observer)
- g_prefetch_observer->DnsGetFirstResolutionsHtml(output);
- predictor->GetHtmlReferrerLists(output);
+ // List items fetched at startup.
+ if (g_initial_observer)
+ g_initial_observer->GetFirstResolutionsHtml(output);
+ // Show list of subresource predictions and stats.
+ g_predictor->GetHtmlReferrerLists(output);
+ // Show list of prediction results.
+ g_predictor->GetHtmlInfo(output);
}
}
output->append("</body></html>");
@@ -533,31 +373,25 @@ static void InitNetworkPredictor(TimeDelta max_dns_queue_delay,
void FinalizePredictorInitialization(
Predictor* global_predictor,
- net::HostResolver::Observer* global_prefetch_observer,
const UrlList& startup_urls,
ListValue* referral_list) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- predictor = global_predictor;
- g_prefetch_observer =
- static_cast<PrefetchObserver*>(global_prefetch_observer);
+ g_predictor = global_predictor;
+ g_initial_observer = new InitialObserver();
DLOG(INFO) << "DNS Prefetch service started";
// Prefetch these hostnames on startup.
DnsPrefetchMotivatedList(startup_urls,
UrlInfo::STARTUP_LIST_MOTIVATED);
- predictor->DeserializeReferrersThenDelete(referral_list);
+ g_predictor->DeserializeReferrersThenDelete(referral_list);
}
void FreePredictorResources() {
- predictor = NULL;
- g_prefetch_observer = NULL;
-}
-
-//------------------------------------------------------------------------------
-
-net::HostResolver::Observer* CreateResolverObserver() {
- return new PrefetchObserver();
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ g_predictor = NULL; // Owned and released by io_thread.cc.
+ delete g_initial_observer;
+ g_initial_observer = NULL;
}
//------------------------------------------------------------------------------
@@ -570,20 +404,20 @@ static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
base::WaitableEvent* completion) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- if (NULL == predictor) {
+ if (NULL == g_predictor) {
completion->Signal();
return;
}
- if (g_prefetch_observer)
- g_prefetch_observer->GetInitialDnsResolutionList(startup_list);
+ if (g_initial_observer)
+ g_initial_observer->GetInitialDnsResolutionList(startup_list);
// TODO(jar): Trimming should be done more regularly, such as every 48 hours
// of physical time, or perhaps after 48 hours of running (excluding time
// between sessions possibly).
// For now, we'll just trim at shutdown.
- predictor->TrimReferrers();
- predictor->SerializeReferrers(referral_list);
+ g_predictor->TrimReferrers();
+ g_predictor->SerializeReferrers(referral_list);
completion->Signal();
}
@@ -591,7 +425,7 @@ static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
void SavePredictorStateForNextStartupAndTrim(PrefService* prefs) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- if (!dns_prefetch_enabled || predictor == NULL)
+ if (!predictor_enabled || g_predictor == NULL)
return;
base::WaitableEvent completion(true, false);
@@ -665,12 +499,12 @@ static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
//------------------------------------------------------------------------------
// Methods for the helper class that is used to startup and teardown the whole
-// predictor system (both DNS pre-resolution and TCP/IP connection prewarming).
+// g_predictor system (both DNS pre-resolution and TCP/IP connection
+// prewarming).
PredictorInit::PredictorInit(PrefService* user_prefs,
PrefService* local_state,
- bool preconnect_enabled,
- bool proconnect_despite_proxy) {
+ bool preconnect_enabled) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// Set up a field trial to see what disabling DNS pre-resolution does to
// latency of page loads.
@@ -681,7 +515,7 @@ PredictorInit::PredictorInit(PrefService* user_prefs,
trial_ = new FieldTrial("DnsImpact", kDivisor);
// First option is to disable prefetching completely.
- int disabled_prefetch = trial_->AppendGroup("_disabled_prefetch",
+ int disabled_prefetch = trial_->AppendGroup("disabled_prefetch",
kProbabilityPerGroup);
@@ -693,27 +527,27 @@ PredictorInit::PredictorInit(PrefService* user_prefs,
// Experiment 1:
// Set congestion detection at 250, 500, or 750ms, rather than the 1 second
// default.
- int max_250ms_prefetch = trial_->AppendGroup("_max_250ms_queue_prefetch",
+ int max_250ms_prefetch = trial_->AppendGroup("max_250ms_queue_prefetch",
kProbabilityPerGroup);
- int max_500ms_prefetch = trial_->AppendGroup("_max_500ms_queue_prefetch",
+ int max_500ms_prefetch = trial_->AppendGroup("max_500ms_queue_prefetch",
kProbabilityPerGroup);
- int max_750ms_prefetch = trial_->AppendGroup("_max_750ms_queue_prefetch",
+ int max_750ms_prefetch = trial_->AppendGroup("max_750ms_queue_prefetch",
kProbabilityPerGroup);
// Set congestion detection at 2 seconds instead of the 1 second default.
- int max_2s_prefetch = trial_->AppendGroup("_max_2s_queue_prefetch",
+ int max_2s_prefetch = trial_->AppendGroup("max_2s_queue_prefetch",
kProbabilityPerGroup);
// Experiment 2:
// Set max simultaneous resoultions to 2, 4, or 6, and scale the congestion
// limit proportionally (so we don't impact average probability of asserting
// congesion very much).
int max_2_concurrent_prefetch = trial_->AppendGroup(
- "_max_2 concurrent_prefetch", kProbabilityPerGroup);
+ "max_2 concurrent_prefetch", kProbabilityPerGroup);
int max_4_concurrent_prefetch = trial_->AppendGroup(
- "_max_4 concurrent_prefetch", kProbabilityPerGroup);
+ "max_4 concurrent_prefetch", kProbabilityPerGroup);
int max_6_concurrent_prefetch = trial_->AppendGroup(
- "_max_6 concurrent_prefetch", kProbabilityPerGroup);
+ "max_6 concurrent_prefetch", kProbabilityPerGroup);
- trial_->AppendGroup("_default_enabled_prefetch",
+ trial_->AppendGroup("default_enabled_prefetch",
FieldTrial::kAllRemainingProbability);
// We will register the incognito observer regardless of whether prefetching
@@ -747,9 +581,7 @@ PredictorInit::PredictorInit(PrefService* user_prefs,
TimeDelta max_queueing_delay(
TimeDelta::FromMilliseconds(max_queueing_delay_ms));
- Preconnect::SetPreconnectDespiteProxy(proconnect_despite_proxy);
-
- DCHECK(!predictor);
+ DCHECK(!g_predictor);
InitNetworkPredictor(max_queueing_delay, max_concurrent, user_prefs,
local_state, preconnect_enabled);
}
diff --git a/chrome/browser/net/predictor_api.h b/chrome/browser/net/predictor_api.h
index 204afd9..062a2a6 100644
--- a/chrome/browser/net/predictor_api.h
+++ b/chrome/browser/net/predictor_api.h
@@ -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.
@@ -10,16 +10,16 @@
#ifndef CHROME_BROWSER_NET_PREDICTOR_API_H_
#define CHROME_BROWSER_NET_PREDICTOR_API_H_
+#pragma once
#include <string>
#include <vector>
#include "base/field_trial.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/net/predictor.h"
-#include "net/base/host_resolver.h"
class PrefService;
@@ -28,7 +28,6 @@ namespace chrome_browser_net {
// Deletes |referral_list| when done.
void FinalizePredictorInitialization(
Predictor* global_predictor,
- net::HostResolver::Observer* global_prefetch_observer,
const std::vector<GURL>& urls_to_prefetch,
ListValue* referral_list);
@@ -36,9 +35,6 @@ void FinalizePredictorInitialization(
// you must not call any function from this file.
void FreePredictorResources();
-// Creates the HostResolver observer for the prefetching system.
-net::HostResolver::Observer* CreateResolverObserver();
-
//------------------------------------------------------------------------------
// Global APIs relating to predictions in browser.
void EnablePredictor(bool enable);
@@ -52,21 +48,26 @@ void DnsPrefetchList(const NameList& hostnames);
// This API is used by the autocomplete popup box (as user types).
// This will either preresolve the domain name, or possibly preconnect creating
// an open TCP/IP connection to the host.
-void AnticipateUrl(const GURL& url, bool preconnectable);
+void AnticipateOmniboxUrl(const GURL& url, bool preconnectable);
+
+// This API should only be called when we're absolutely certain that we will
+// be connecting to the URL. It will preconnect the url and it's associated
+// subresource domains immediately.
+void PreconnectUrlAndSubresources(const GURL& url);
// When displaying info in about:dns, the following API is called.
void PredictorGetHtmlInfo(std::string* output);
//------------------------------------------------------------------------------
-// When we navigate, we may know in advance some other URLs that will need to
-// be resolved. This function initiates those side effects.
-void PredictSubresources(const GURL& url);
-
// When we navigate to a frame that may contain embedded resources, we may know
// in advance some other URLs that will need to be connected to (via TCP and
// sometimes SSL). This function initiates those connections
void PredictFrameSubresources(const GURL& url);
+// During startup, we learn what the first N urls visited are, and then resolve
+// the associated hosts ASAP during our next startup.
+void LearnAboutInitialNavigation(const GURL& url);
+
// Call when we should learn from a navigation about a relationship to a
// subresource target, and its containing frame, which was loaded as a referring
// URL.
@@ -88,7 +89,7 @@ class PredictorInit {
static const int kMaxPrefetchQueueingDelayMs;
PredictorInit(PrefService* user_prefs, PrefService* local_state,
- bool preconnect_enabled, bool preconnect_despite_proxy);
+ bool preconnect_enabled);
private:
// Maintain a field trial instance when we do A/B testing.
diff --git a/chrome/browser/net/predictor_unittest.cc b/chrome/browser/net/predictor_unittest.cc
index d60961e..fd8bd9a 100644
--- a/chrome/browser/net/predictor_unittest.cc
+++ b/chrome/browser/net/predictor_unittest.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.
@@ -10,8 +10,9 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/timer.h"
+#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/url_info.h"
@@ -115,70 +116,6 @@ TEST_F(PredictorTest, StartupShutdownTest) {
testing_master->Shutdown();
}
-TEST_F(PredictorTest, BenefitLookupTest) {
- scoped_refptr<Predictor> testing_master = new Predictor(
- host_resolver_,
- default_max_queueing_delay_,
- PredictorInit::kMaxPrefetchConcurrentLookups,
- false);
-
- GURL goog("http://www.google.com:80"),
- goog2("http://gmail.google.com.com:80"),
- goog3("http://mail.google.com:80"),
- goog4("http://gmail.com:80");
- UrlInfo goog_info, goog2_info, goog3_info, goog4_info;
-
- // Simulate getting similar names from a network observer
- goog_info.SetUrl(goog);
- goog2_info.SetUrl(goog2);
- goog3_info.SetUrl(goog3);
- goog4_info.SetUrl(goog4);
-
- goog_info.SetStartedState();
- goog2_info.SetStartedState();
- goog3_info.SetStartedState();
- goog4_info.SetStartedState();
-
- goog_info.SetFinishedState(true);
- goog2_info.SetFinishedState(true);
- goog3_info.SetFinishedState(true);
- goog4_info.SetFinishedState(true);
-
- UrlList names;
- names.push_back(goog);
- names.push_back(goog2);
- names.push_back(goog3);
- names.push_back(goog4);
-
- testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
-
- WaitForResolution(testing_master, names);
-
- EXPECT_TRUE(testing_master->WasFound(goog));
- EXPECT_TRUE(testing_master->WasFound(goog2));
- EXPECT_TRUE(testing_master->WasFound(goog3));
- EXPECT_TRUE(testing_master->WasFound(goog4));
-
- // With the mock DNS, each of these should have taken some time, and hence
- // shown a benefit (i.e., prefetch cost more than network access time).
-
- GURL referer; // Null host.
-
- // Simulate actual navigation, and acrue the benefit for "helping" the DNS
- // part of the navigation.
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog_info));
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog2_info));
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog3_info));
- EXPECT_TRUE(testing_master->AccruePrefetchBenefits(referer, &goog4_info));
-
- // Benefits can ONLY be reported once (for the first navigation).
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog_info));
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog2_info));
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog3_info));
- EXPECT_FALSE(testing_master->AccruePrefetchBenefits(referer, &goog4_info));
-
- testing_master->Shutdown();
-}
TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
scoped_refptr<net::WaitingHostResolverProc> resolver_proc =
@@ -190,7 +127,7 @@ TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
PredictorInit::kMaxPrefetchConcurrentLookups,
false);
- GURL localhost("http://127.0.0.1:80");
+ GURL localhost("http://localhost:80");
UrlList names;
names.push_back(localhost);
@@ -299,7 +236,8 @@ TEST_F(PredictorTest, MassiveConcurrentLookupTest) {
UrlList names;
for (int i = 0; i < 100; i++)
- names.push_back(GURL("http://host" + IntToString(i) + ".notfound:80"));
+ names.push_back(GURL(
+ "http://host" + base::IntToString(i) + ".notfound:80"));
// Try to flood the predictor with many concurrent requests.
for (int i = 0; i < 10; i++)
@@ -327,7 +265,7 @@ static ListValue* FindSerializationMotivation(
CHECK_LT(0u, referral_list.GetSize()); // Room for version.
int format_version = -1;
CHECK(referral_list.GetInteger(0, &format_version));
- CHECK_EQ(Predictor::DNS_REFERRER_VERSION, format_version);
+ CHECK_EQ(Predictor::PREDICTOR_REFERRER_VERSION, format_version);
ListValue* motivation_list(NULL);
for (size_t i = 1; i < referral_list.GetSize(); ++i) {
referral_list.GetList(i, &motivation_list);
@@ -342,17 +280,16 @@ static ListValue* FindSerializationMotivation(
// Create a new empty serialization list.
static ListValue* NewEmptySerializationList() {
ListValue* list = new ListValue;
- list->Append(new FundamentalValue(Predictor::DNS_REFERRER_VERSION));
+ list->Append(new FundamentalValue(Predictor::PREDICTOR_REFERRER_VERSION));
return list;
}
-// Add a motivating_host and a subresource_host to a serialized list, using
+// Add a motivating_url and a subresource_url to a serialized list, using
// this given latency. This is a helper function for quickly building these
// lists.
static void AddToSerializedList(const GURL& motivation,
const GURL& subresource,
- int latency,
- double rate,
+ double use_rate,
ListValue* referral_list ) {
// Find the motivation if it is already used.
ListValue* motivation_list = FindSerializationMotivation(motivation,
@@ -377,8 +314,7 @@ static void AddToSerializedList(const GURL& motivation,
// existing value(s) will be added to the referrer.
subresource_list->Append(new StringValue(subresource.spec()));
- subresource_list->Append(new FundamentalValue(latency));
- subresource_list->Append(new FundamentalValue(rate));
+ subresource_list->Append(new FundamentalValue(use_rate));
}
static const int kLatencyNotFound = -1;
@@ -386,12 +322,11 @@ static const int kLatencyNotFound = -1;
// For a given motivation, and subresource, find what latency is currently
// listed. This assume a well formed serialization, which has at most one such
// entry for any pair of names. If no such pair is found, then return false.
-// Data is written into rate and latency arguments.
+// Data is written into use_rate arguments.
static bool GetDataFromSerialization(const GURL& motivation,
const GURL& subresource,
const ListValue& referral_list,
- double* rate,
- int* latency) {
+ double* use_rate) {
ListValue* motivation_list = FindSerializationMotivation(motivation,
referral_list);
if (!motivation_list)
@@ -401,8 +336,7 @@ static bool GetDataFromSerialization(const GURL& motivation,
for (size_t i = 0; i < subresource_list->GetSize();) {
std::string url_spec;
EXPECT_TRUE(subresource_list->GetString(i++, &url_spec));
- EXPECT_TRUE(subresource_list->GetInteger(i++, latency));
- EXPECT_TRUE(subresource_list->GetReal(i++, rate));
+ EXPECT_TRUE(subresource_list->GetReal(i++, use_rate));
if (subresource == GURL(url_spec)) {
return true;
}
@@ -423,7 +357,7 @@ TEST_F(PredictorTest, ReferrerSerializationNilTest) {
EXPECT_EQ(1U, referral_list->GetSize());
EXPECT_FALSE(GetDataFromSerialization(
GURL("http://a.com:79"), GURL("http://b.com:78"),
- *referral_list.get(), NULL, NULL));
+ *referral_list.get(), NULL));
predictor->Shutdown();
}
@@ -438,25 +372,21 @@ TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
false);
const GURL motivation_url("http://www.google.com:91");
const GURL subresource_url("http://icons.google.com:90");
- const int kLatency = 3;
- const double kRate = 23.4;
+ const double kUseRate = 23.4;
scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
AddToSerializedList(motivation_url, subresource_url,
- kLatency, kRate, referral_list.get());
+ kUseRate, referral_list.get());
predictor->DeserializeReferrers(*referral_list.get());
ListValue recovered_referral_list;
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
- int latency;
double rate;
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, subresource_url, recovered_referral_list, &rate,
- &latency));
- EXPECT_EQ(rate, kRate);
- EXPECT_EQ(latency, kLatency);
+ motivation_url, subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kUseRate);
predictor->Shutdown();
}
@@ -470,99 +400,73 @@ TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
GURL motivation_url("http://www.google.com:110");
GURL icon_subresource_url("http://icons.google.com:111");
- const int kLatencyIcon = 10;
- const double kRateIcon = 0.; // User low rate, so latency will dominate.
+ const double kRateIcon = 16.0 * Predictor::kPersistWorthyExpectedValue;
GURL img_subresource_url("http://img.google.com:118");
- const int kLatencyImg = 3;
- const double kRateImg = 0.;
+ const double kRateImg = 8.0 * Predictor::kPersistWorthyExpectedValue;
scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
AddToSerializedList(
- motivation_url, icon_subresource_url,
- kLatencyIcon, kRateIcon, referral_list.get());
+ motivation_url, icon_subresource_url, kRateIcon, referral_list.get());
AddToSerializedList(
- motivation_url, img_subresource_url,
- kLatencyImg, kRateImg, referral_list.get());
+ motivation_url, img_subresource_url, kRateImg, referral_list.get());
predictor->DeserializeReferrers(*referral_list.get());
ListValue recovered_referral_list;
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
- int latency;
double rate;
EXPECT_TRUE(GetDataFromSerialization(
motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon);
+ &rate));
EXPECT_EQ(rate, kRateIcon);
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyImg);
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
EXPECT_EQ(rate, kRateImg);
- // Each time we Trim, the latency figures should reduce by a factor of two,
- // until they both are 0, an then a trim will delete the whole entry.
+ // Each time we Trim, the user_rate figures should reduce by a factor of two,
+ // until they both are small, an then a trim will delete the whole entry.
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon / 2);
- EXPECT_EQ(rate, kRateIcon);
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateIcon / 2);
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyImg / 2);
- EXPECT_EQ(rate, kRateImg);
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateImg / 2);
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon / 4);
- EXPECT_EQ(rate, kRateIcon);
- // Img is down to zero, but we don't delete it yet.
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateIcon / 4);
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(kLatencyImg / 4, 0);
- EXPECT_EQ(latency, kLatencyImg / 4);
- EXPECT_EQ(rate, kRateImg);
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateImg / 4);
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
EXPECT_EQ(2U, recovered_referral_list.GetSize());
EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(latency, kLatencyIcon / 8);
- EXPECT_EQ(rate, kRateIcon);
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
+ EXPECT_EQ(rate, kRateIcon / 8);
- // Img is down to zero, but we don't delete it yet.
- EXPECT_TRUE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
- EXPECT_EQ(kLatencyImg / 8, 0);
- EXPECT_EQ(latency, kLatencyImg / 8);
- EXPECT_EQ(rate, kRateImg);
+ // Img is below threshold, and so it gets deleted.
+ EXPECT_FALSE(GetDataFromSerialization(
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
predictor->TrimReferrers();
predictor->SerializeReferrers(&recovered_referral_list);
// Icon is also trimmed away, so entire set gets discarded.
EXPECT_EQ(1U, recovered_referral_list.GetSize());
EXPECT_FALSE(GetDataFromSerialization(
- motivation_url, icon_subresource_url, recovered_referral_list,
- &rate, &latency));
+ motivation_url, icon_subresource_url, recovered_referral_list, &rate));
EXPECT_FALSE(GetDataFromSerialization(
- motivation_url, img_subresource_url, recovered_referral_list,
- &rate, &latency));
+ motivation_url, img_subresource_url, recovered_referral_list, &rate));
predictor->Shutdown();
}
@@ -637,4 +541,42 @@ TEST_F(PredictorTest, PriorityQueueReorderTest) {
EXPECT_TRUE(queue.IsEmpty());
}
+TEST_F(PredictorTest, CanonicalizeUrl) {
+ // Base case, only handles HTTP and HTTPS.
+ EXPECT_EQ(GURL(), Predictor::CanonicalizeUrl(GURL("ftp://anything")));
+
+ // Remove path testing.
+ GURL long_url("http://host:999/path?query=value");
+ EXPECT_EQ(Predictor::CanonicalizeUrl(long_url), long_url.GetWithEmptyPath());
+
+ // Default port cannoncalization.
+ GURL implied_port("http://test");
+ GURL explicit_port("http://test:80");
+ EXPECT_EQ(Predictor::CanonicalizeUrl(implied_port),
+ Predictor::CanonicalizeUrl(explicit_port));
+
+ // Port is still maintained.
+ GURL port_80("http://test:80");
+ GURL port_90("http://test:90");
+ EXPECT_NE(Predictor::CanonicalizeUrl(port_80),
+ Predictor::CanonicalizeUrl(port_90));
+
+ // Host is still maintained.
+ GURL host_1("http://test_1");
+ GURL host_2("http://test_2");
+ EXPECT_NE(Predictor::CanonicalizeUrl(host_1),
+ Predictor::CanonicalizeUrl(host_2));
+
+ // Scheme is maintained (mismatch identified).
+ GURL http("http://test");
+ GURL https("https://test");
+ EXPECT_NE(Predictor::CanonicalizeUrl(http),
+ Predictor::CanonicalizeUrl(https));
+
+ // Https works fine.
+ GURL long_https("https://host:999/path?query=value");
+ EXPECT_EQ(Predictor::CanonicalizeUrl(long_https),
+ long_https.GetWithEmptyPath());
+}
+
} // namespace chrome_browser_net
diff --git a/chrome/browser/net/referrer.cc b/chrome/browser/net/referrer.cc
index 936d25b..0b884d6 100644
--- a/chrome/browser/net/referrer.cc
+++ b/chrome/browser/net/referrer.cc
@@ -7,23 +7,25 @@
#include <limits.h>
#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/net/predictor.h"
namespace chrome_browser_net {
//------------------------------------------------------------------------------
// Smoothing parameter for updating subresource_use_rate_.
-// We always combine our old expected value, weighted by some factor, with the
-// new expected value Enew. The new "expected value" is the number of actual
-// connections made due to the curernt navigations.
-// This means the formula (in a concise form) is:
-// Eupdated = Eold * W + Enew * (1 - W)
+// We always combine our old expected value, weighted by some factor W (we use
+// kWeightingForOldExpectedValue), with the new expected value Enew. The new
+// "expected value" is the number of actual connections made due to the current
+// navigations.
// That means that IF we end up needing to connect, we should apply the formula:
-// Pupdated = Pold * W + Enew * (1 - W)
-// If we visit the containing url, but don't end up needing a connection:
-// Pupdated = Pold * W
-// To achive the above upating algorithm, we end up doing the multiplication
-// by W every time we contemplate doing a preconneciton (i.e., when we navigate
+// Eupdated = Eold * W + Enew * (1 - W)
+// If we visit the containing url, but don't end up needing a connection, then
+// Enew == 0, so we use the formula:
+// Eupdated = Eold * W
+// To achieve the above updating algorithm, we end up doing the multiplication
+// by W every time we contemplate doing a preconnection (i.e., when we navigate
// to the containing URL, and consider doing a preconnection), and then IFF we
// learn that we really needed a connection to the subresource, we complete the
// above algorithm by adding the (1 - W) for each connection we make.
@@ -32,13 +34,14 @@ namespace chrome_browser_net {
// 1.0.
static const double kWeightingForOldExpectedValue = 0.66;
-// The expected value needed before we actually do a preconnection.
-static const double kPreconnectWorthyExpectedValue = 0.7;
-
-// The expected value that we'll need a preconnection when we first see the
-// subresource getting fetched. Very conservative is 0.0, which will mean that
-// we have to wait for a while before using preconnection... but we do persist
-// results, so we'll have the learned answer in the long run.
+// To estimate the expected value of the number of connections that we'll need
+// when a referrer is navigated to, we start with the following rather low
+// initial value. Each time we do indeed (again) need the subresource, this
+// value will get increased. Each time we navigate to the refererrer but never
+// end up needing this subresource, the value will decrease.
+// Very conservative is 0.0, which will mean that we have to wait for a while
+// before doing much speculative acvtivity... but we do persist results, so
+// we'll save the asymptotic (correct?) learned answer in the long run.
static const double kInitialExpectedValue = 0.0;
// static
@@ -71,71 +74,43 @@ void Referrer::SuggestHost(const GURL& url) {
void Referrer::DeleteLeastUseful() {
// Find the item with the lowest value. Most important is preconnection_rate,
- // next is latency savings, and last is lifetime (age).
+ // and least is lifetime (age).
GURL least_useful_url;
double lowest_rate_seen = 0.0;
// We use longs for durations because we will use multiplication on them.
- int64 lowest_latency_seen = 0; // Duration in milliseconds.
int64 least_useful_lifetime = 0; // Duration in milliseconds.
const base::Time kNow(base::Time::Now()); // Avoid multiple calls.
for (SubresourceMap::iterator it = begin(); it != end(); ++it) {
int64 lifetime = (kNow - it->second.birth_time()).InMilliseconds();
- int64 latency = it->second.latency().InMilliseconds();
double rate = it->second.subresource_use_rate();
if (least_useful_url.has_host()) {
if (rate > lowest_rate_seen)
continue;
- if (!latency && !lowest_latency_seen) {
- // Older name is less useful.
- if (lifetime <= least_useful_lifetime)
- continue;
- } else {
- // Compare the ratios:
- // latency/lifetime
- // vs.
- // lowest_latency_seen/least_useful_lifetime
- // by cross multiplying (to avoid integer division hassles). Overflow's
- // won't happen until both latency and lifetime pass about 49 days.
- if (latency * least_useful_lifetime >
- lowest_latency_seen * lifetime) {
- continue;
- }
- }
+ if (lifetime <= least_useful_lifetime)
+ continue;
}
least_useful_url = it->first;
lowest_rate_seen = rate;
- lowest_latency_seen = latency;
least_useful_lifetime = lifetime;
}
- erase(least_useful_url);
- // Note: there is a small chance that we will discard a least_useful_url
- // that is currently being prefetched because it *was* in this referer list.
- // In that case, when a benefit appears in AccrueValue() below, we are careful
- // to check before accessing the member.
-}
-
-void Referrer::AccrueValue(const base::TimeDelta& delta,
- const GURL& url) {
- SubresourceMap::iterator it = find(url);
- // Be careful that we weren't evicted from this referrer in DeleteLeastUseful.
- if (it != end())
- it->second.AccrueValue(delta);
+ if (least_useful_url.has_host())
+ erase(least_useful_url);
}
bool Referrer::Trim() {
- bool has_some_latency_left = false;
+ std::vector<GURL> discarded_urls;
for (SubresourceMap::iterator it = begin(); it != end(); ++it)
- if (it->second.Trim())
- has_some_latency_left = true;
- return has_some_latency_left;
+ if (!it->second.Trim())
+ discarded_urls.push_back(it->first);
+ for (size_t i = 0; i < discarded_urls.size(); ++i)
+ erase(discarded_urls[i]);
+ return size() > 0;
}
bool ReferrerValue::Trim() {
- int64 latency_ms = latency_.InMilliseconds() / 2;
- latency_ = base::TimeDelta::FromMilliseconds(latency_ms);
- return latency_ms > 0 ||
- subresource_use_rate_ > kPreconnectWorthyExpectedValue / 2;
+ subresource_use_rate_ /= 2.0;
+ return subresource_use_rate_ > Predictor::kPersistWorthyExpectedValue;
}
@@ -148,22 +123,17 @@ void Referrer::Deserialize(const Value& value) {
std::string url_spec;
if (!subresource_list->GetString(index++, &url_spec))
return;
- int latency_ms;
- if (!subresource_list->GetInteger(index++, &latency_ms))
- return;
double rate;
if (!subresource_list->GetReal(index++, &rate))
return;
GURL url(url_spec);
- base::TimeDelta latency = base::TimeDelta::FromMilliseconds(latency_ms);
// TODO(jar): We could be more direct, and change birth date or similar to
// show that this is a resurrected value we're adding in. I'm not yet sure
// of how best to optimize the learning and pruning (Trim) algorithm at this
// level, so for now, we just suggest subresources, which leaves them all
// with the same birth date (typically start of process).
SuggestHost(url);
- AccrueValue(latency, url);
(*this)[url].SetSubresourceUseRate(rate);
}
}
@@ -172,21 +142,10 @@ Value* Referrer::Serialize() const {
ListValue* subresource_list(new ListValue);
for (const_iterator it = begin(); it != end(); ++it) {
StringValue* url_spec(new StringValue(it->first.spec()));
- int latency_integer = static_cast<int>(it->second.latency().
- InMilliseconds());
- // Watch out for overflow in the above static_cast! Check to see if we went
- // negative, and just use a "big" value. The value seems unimportant once
- // we get to such high latencies. Probable cause of high latency is a bug
- // in other code, so also do a DCHECK.
- DCHECK_GE(latency_integer, 0);
- if (latency_integer < 0)
- latency_integer = INT_MAX;
- FundamentalValue* latency(new FundamentalValue(latency_integer));
FundamentalValue* rate(new FundamentalValue(
it->second.subresource_use_rate()));
subresource_list->Append(url_spec);
- subresource_list->Append(latency);
subresource_list->Append(rate);
}
return subresource_list;
@@ -198,6 +157,7 @@ ReferrerValue::ReferrerValue()
: birth_time_(base::Time::Now()),
navigation_count_(0),
preconnection_count_(0),
+ preresolution_count_(0),
subresource_use_rate_(kInitialExpectedValue) {
}
@@ -208,15 +168,12 @@ void ReferrerValue::SubresourceIsNeeded() {
subresource_use_rate_ += 1 - kWeightingForOldExpectedValue;
}
-bool ReferrerValue::IsPreconnectWorthDoing() {
- bool preconnecting = kPreconnectWorthyExpectedValue < subresource_use_rate_;
- if (preconnecting)
- ++preconnection_count_;
+void ReferrerValue::ReferrerWasObserved() {
subresource_use_rate_ *= kWeightingForOldExpectedValue;
// Note: the use rate is temporarilly possibly incorect, as we need to find
// out if we really end up connecting. This will happen in a few hundred
// milliseconds (when content arrives, etc.).
- return preconnecting;
+ // Value of subresource_use_rate_ should be sampled before this call.
}
} // namespace chrome_browser_net
diff --git a/chrome/browser/net/referrer.h b/chrome/browser/net/referrer.h
index 3652e1f..2e7728e 100644
--- a/chrome/browser/net/referrer.h
+++ b/chrome/browser/net/referrer.h
@@ -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.
@@ -14,16 +14,17 @@
#ifndef CHROME_BROWSER_NET_REFERRER_H_
#define CHROME_BROWSER_NET_REFERRER_H_
+#pragma once
#include <map>
-#include <string>
#include "base/basictypes.h"
#include "base/time.h"
-#include "base/values.h"
#include "googleurl/src/gurl.h"
#include "net/base/host_port_pair.h"
+class Value;
+
namespace chrome_browser_net {
//------------------------------------------------------------------------------
@@ -37,28 +38,32 @@ class ReferrerValue {
// Used during deserialization.
void SetSubresourceUseRate(double rate) { subresource_use_rate_ = rate; }
- base::TimeDelta latency() const { return latency_; }
base::Time birth_time() const { return birth_time_; }
- void AccrueValue(const base::TimeDelta& delta) { latency_ += delta; }
- // Record the fact that we navigated to the associated subresource URL.
+ // Record the fact that we navigated to the associated subresource URL. This
+ // will increase the value of the expected subresource_use_rate_
void SubresourceIsNeeded();
- // Evaluate if it is worth making this preconnection, and return true if it
- // seems worthwhile. As a side effect, we also tally the proconnection for
- // statistical purposes only.
- bool IsPreconnectWorthDoing();
+ // Record the fact that the referrer of this subresource was observed. This
+ // will diminish the expected subresource_use_rate_ (and will only be
+ // counteracted later if we really needed this subresource as a consequence
+ // of our associated referrer.)
+ void ReferrerWasObserved();
int64 navigation_count() const { return navigation_count_; }
- int64 preconnection_count() const { return preconnection_count_; }
double subresource_use_rate() const { return subresource_use_rate_; }
- // Reduce the latency figure by a factor of 2, and return true if any latency
- // remains.
+ int64 preconnection_count() const { return preconnection_count_; }
+ void IncrementPreconnectionCount() { ++preconnection_count_; }
+
+ int64 preresolution_count() const { return preresolution_count_; }
+ void preresolution_increment() { ++preresolution_count_; }
+
+ // Reduce the latency figure by a factor of 2, and return true if it still has
+ // subresources that could potentially be used.
bool Trim();
private:
- base::TimeDelta latency_; // Accumulated DNS resolution latency savings.
const base::Time birth_time_;
// The number of times this item was navigated to with the fixed referrer.
@@ -68,7 +73,12 @@ class ReferrerValue {
// referrer.
int64 preconnection_count_;
- // A smoothed estimate of the probability that a connection will be needed.
+ // The number of times this item was pre-resolved (via DNS) as a consequence
+ // of its referrer.
+ int64 preresolution_count_;
+
+ // A smoothed estimate of the expected number of connections that will be made
+ // to this subresource.
double subresource_use_rate_;
};
@@ -98,14 +108,9 @@ class Referrer : public SubresourceMap {
// discarded to make room for this insertion.
void SuggestHost(const GURL& url);
- // Record additional usefulness of having this url in the list.
- // Value is expressed as positive latency of amount delta.
- void AccrueValue(const base::TimeDelta& delta,
- const GURL& url);
-
- // Trim the Referrer, by first diminishing (scaling down) the latency for each
- // ReferredValue.
- // Returns true if there are any referring names with some latency left.
+ // Trim the Referrer, by first diminishing (scaling down) the subresource
+ // use expectation for each ReferredValue.
+ // Returns true if there are any referring names left.
bool Trim();
// Provide methods for persisting, and restoring contents into a Value class.
diff --git a/chrome/browser/net/resolve_proxy_msg_helper.h b/chrome/browser/net/resolve_proxy_msg_helper.h
index 22be9ed..e596adc 100644
--- a/chrome/browser/net/resolve_proxy_msg_helper.h
+++ b/chrome/browser/net/resolve_proxy_msg_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_RESOLVE_PROXY_MSG_HELPER_H_
#define CHROME_BROWSER_NET_RESOLVE_PROXY_MSG_HELPER_H_
+#pragma once
#include <deque>
#include <string>
diff --git a/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc
index c84ad41..3bdb695 100644
--- a/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc
+++ b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/net/resolve_proxy_msg_helper.h"
-#include "base/waitable_event.h"
#include "net/base/net_errors.h"
#include "net/proxy/mock_proxy_resolver.h"
#include "net/proxy/proxy_config_service.h"
@@ -13,9 +12,11 @@
// This ProxyConfigService always returns "http://pac" as the PAC url to use.
class MockProxyConfigService : public net::ProxyConfigService {
public:
- virtual int GetProxyConfig(net::ProxyConfig* results) {
- results->set_pac_url(GURL("http://pac"));
- return net::OK;
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual bool GetLatestProxyConfig(net::ProxyConfig* results) {
+ *results = net::ProxyConfig::CreateFromCustomPacURL(GURL("http://pac"));
+ return true;
}
};
diff --git a/chrome/browser/net/sdch_dictionary_fetcher.cc b/chrome/browser/net/sdch_dictionary_fetcher.cc
index ed24b8b..04542a6 100644
--- a/chrome/browser/net/sdch_dictionary_fetcher.cc
+++ b/chrome/browser/net/sdch_dictionary_fetcher.cc
@@ -4,9 +4,18 @@
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
+#include "base/compiler_specific.h"
#include "chrome/browser/profile.h"
#include "net/url_request/url_request_status.h"
+SdchDictionaryFetcher::SdchDictionaryFetcher()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
+ task_is_pending_(false) {
+}
+
+SdchDictionaryFetcher::~SdchDictionaryFetcher() {
+}
+
void SdchDictionaryFetcher::Schedule(const GURL& dictionary_url) {
// Avoid pushing duplicate copy onto queue. We may fetch this url again later
// and get a different dictionary, but there is no reason to have it in the
diff --git a/chrome/browser/net/sdch_dictionary_fetcher.h b/chrome/browser/net/sdch_dictionary_fetcher.h
index 3a975ce..32bf0d7 100644
--- a/chrome/browser/net/sdch_dictionary_fetcher.h
+++ b/chrome/browser/net/sdch_dictionary_fetcher.h
@@ -8,12 +8,12 @@
#ifndef CHROME_BROWSER_NET_SDCH_DICTIONARY_FETCHER_H_
#define CHROME_BROWSER_NET_SDCH_DICTIONARY_FETCHER_H_
+#pragma once
#include <queue>
#include <set>
#include <string>
-#include "base/compiler_specific.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "chrome/common/net/url_fetcher.h"
@@ -22,10 +22,8 @@
class SdchDictionaryFetcher : public URLFetcher::Delegate,
public SdchFetcher {
public:
- SdchDictionaryFetcher() :
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
- task_is_pending_(false) {}
- virtual ~SdchDictionaryFetcher() {}
+ SdchDictionaryFetcher();
+ virtual ~SdchDictionaryFetcher();
// Implementation of SdchFetcher class.
// This method gets the requested dictionary, and then calls back into the
@@ -86,7 +84,6 @@ class SdchDictionaryFetcher : public URLFetcher::Delegate,
// TODO(jar): Try to augment the SDCH proposal to include this restiction.
std::set<GURL> attempted_load_;
-
DISALLOW_COPY_AND_ASSIGN(SdchDictionaryFetcher);
};
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.cc b/chrome/browser/net/sqlite_persistent_cookie_store.cc
index ec8eaf9..b0f932d 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.cc
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.cc
@@ -10,6 +10,7 @@
#include "app/sql/transaction.h"
#include "base/basictypes.h"
#include "base/file_util.h"
+#include "base/histogram.h"
#include "base/logging.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
@@ -59,8 +60,7 @@ class SQLitePersistentCookieStore::Backend
}
// Batch a cookie addition.
- void AddCookie(const std::string& key,
- const net::CookieMonster::CanonicalCookie& cc);
+ void AddCookie(const net::CookieMonster::CanonicalCookie& cc);
// Batch a cookie access time update.
void UpdateCookieAccessTime(const net::CookieMonster::CanonicalCookie& cc);
@@ -90,24 +90,20 @@ class SQLitePersistentCookieStore::Backend
} OperationType;
PendingOperation(OperationType op,
- const std::string& key,
const net::CookieMonster::CanonicalCookie& cc)
- : op_(op), key_(key), cc_(cc) { }
+ : op_(op), cc_(cc) { }
OperationType op() const { return op_; }
- const std::string& key() const { return key_; }
const net::CookieMonster::CanonicalCookie& cc() const { return cc_; }
private:
OperationType op_;
- std::string key_; // Only used for OP_ADD
net::CookieMonster::CanonicalCookie cc_;
};
private:
// Batch a cookie operation (add or delete)
void BatchOperation(PendingOperation::OperationType op,
- const std::string& key,
const net::CookieMonster::CanonicalCookie& cc);
// Commit our pending operations to the database.
void Commit();
@@ -125,24 +121,22 @@ class SQLitePersistentCookieStore::Backend
};
void SQLitePersistentCookieStore::Backend::AddCookie(
- const std::string& key,
const net::CookieMonster::CanonicalCookie& cc) {
- BatchOperation(PendingOperation::COOKIE_ADD, key, cc);
+ BatchOperation(PendingOperation::COOKIE_ADD, cc);
}
void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime(
const net::CookieMonster::CanonicalCookie& cc) {
- BatchOperation(PendingOperation::COOKIE_UPDATEACCESS, std::string(), cc);
+ BatchOperation(PendingOperation::COOKIE_UPDATEACCESS, cc);
}
void SQLitePersistentCookieStore::Backend::DeleteCookie(
const net::CookieMonster::CanonicalCookie& cc) {
- BatchOperation(PendingOperation::COOKIE_DELETE, std::string(), cc);
+ BatchOperation(PendingOperation::COOKIE_DELETE, cc);
}
void SQLitePersistentCookieStore::Backend::BatchOperation(
PendingOperation::OperationType op,
- const std::string& key,
const net::CookieMonster::CanonicalCookie& cc) {
// Commit every 30 seconds.
static const int kCommitIntervalMs = 30 * 1000;
@@ -153,8 +147,7 @@ void SQLitePersistentCookieStore::Backend::BatchOperation(
#endif
// We do a full copy of the cookie here, and hopefully just here.
- scoped_ptr<PendingOperation> po(new PendingOperation(op, key, cc));
- CHECK(po.get());
+ scoped_ptr<PendingOperation> po(new PendingOperation(op, cc));
PendingOperationsList::size_type num_pending;
{
@@ -241,7 +234,7 @@ void SQLitePersistentCookieStore::Backend::Commit() {
case PendingOperation::COOKIE_ADD:
add_smt.Reset();
add_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue());
- add_smt.BindString(1, po->key());
+ add_smt.BindString(1, po->cc().Domain());
add_smt.BindString(2, po->cc().Name());
add_smt.BindString(3, po->cc().Value());
add_smt.BindString(4, po->cc().Path());
@@ -276,7 +269,7 @@ void SQLitePersistentCookieStore::Backend::Commit() {
}
}
bool succeeded = transaction.Commit();
- UMA_HISTOGRAM_ENUMERATION("net.CookieBackingStoreUpdateResults",
+ UMA_HISTOGRAM_ENUMERATION("Cookie.BackingStoreUpdateResults",
succeeded ? 0 : 1, 2);
}
@@ -366,7 +359,7 @@ bool InitTable(sql::Connection* db) {
} // namespace
bool SQLitePersistentCookieStore::Load(
- std::vector<net::CookieMonster::KeyedCanonicalCookie>* cookies) {
+ std::vector<net::CookieMonster::CanonicalCookie*>* cookies) {
scoped_ptr<sql::Connection> db(new sql::Connection);
if (!db->Open(path_)) {
NOTREACHED() << "Unable to open cookie DB.";
@@ -410,9 +403,7 @@ bool SQLitePersistentCookieStore::Load(
Time::FromInternalValue(smt.ColumnInt64(5)))); // expires_utc
DLOG_IF(WARNING,
cc->CreationDate() > Time::Now()) << L"CreationDate too recent";
- cookies->push_back(
- net::CookieMonster::KeyedCanonicalCookie(smt.ColumnString(1),
- cc.release()));
+ cookies->push_back(cc.release());
}
// Create the backend, this will take ownership of the db pointer.
@@ -493,10 +484,9 @@ bool SQLitePersistentCookieStore::EnsureDatabaseVersion(sql::Connection* db) {
}
void SQLitePersistentCookieStore::AddCookie(
- const std::string& key,
const net::CookieMonster::CanonicalCookie& cc) {
if (backend_.get())
- backend_->AddCookie(key, cc);
+ backend_->AddCookie(cc);
}
void SQLitePersistentCookieStore::UpdateCookieAccessTime(
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.h b/chrome/browser/net/sqlite_persistent_cookie_store.h
index 9b12ee4..d3bdfb7 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.h
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.h
@@ -6,16 +6,20 @@
#ifndef CHROME_BROWSER_NET_SQLITE_PERSISTENT_COOKIE_STORE_H_
#define CHROME_BROWSER_NET_SQLITE_PERSISTENT_COOKIE_STORE_H_
+#pragma once
#include <string>
#include <vector>
-#include "app/sql/connection.h"
#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;
class SQLitePersistentCookieStore
@@ -24,10 +28,9 @@ class SQLitePersistentCookieStore
explicit SQLitePersistentCookieStore(const FilePath& path);
~SQLitePersistentCookieStore();
- virtual bool Load(std::vector<net::CookieMonster::KeyedCanonicalCookie>*);
+ virtual bool Load(std::vector<net::CookieMonster::CanonicalCookie*>*);
- virtual void AddCookie(const std::string&,
- const net::CookieMonster::CanonicalCookie&);
+ virtual void AddCookie(const net::CookieMonster::CanonicalCookie&);
virtual void UpdateCookieAccessTime(
const net::CookieMonster::CanonicalCookie&);
virtual void DeleteCookie(const net::CookieMonster::CanonicalCookie&);
diff --git a/chrome/browser/net/ssl_config_service_manager.h b/chrome/browser/net/ssl_config_service_manager.h
index 3a7907c..750c5d8 100644
--- a/chrome/browser/net/ssl_config_service_manager.h
+++ b/chrome/browser/net/ssl_config_service_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_SSL_CONFIG_SERVICE_MANAGER_H_
#define CHROME_BROWSER_NET_SSL_CONFIG_SERVICE_MANAGER_H_
+#pragma once
namespace net {
class SSLConfigService;
diff --git a/chrome/browser/net/ssl_config_service_manager_pref.cc b/chrome/browser/net/ssl_config_service_manager_pref.cc
index a89f025..626e40e 100644
--- a/chrome/browser/net/ssl_config_service_manager_pref.cc
+++ b/chrome/browser/net/ssl_config_service_manager_pref.cc
@@ -7,11 +7,11 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/ssl_config_service_manager.h"
-#include "chrome/browser/pref_member.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/common/pref_names.h"
-#include "chrome/browser/pref_service.h"
#include "net/base/ssl_config_service.h"
////////////////////////////////////////////////////////////////////////////////
@@ -48,7 +48,9 @@ void SSLConfigServicePref::GetSSLConfig(net::SSLConfig* config) {
void SSLConfigServicePref::SetNewSSLConfig(
const net::SSLConfig& new_config) {
+ net::SSLConfig orig_config = cached_config_;
cached_config_ = new_config;
+ ProcessConfigUpdate(orig_config, new_config);
}
////////////////////////////////////////////////////////////////////////////////
@@ -145,6 +147,7 @@ void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
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 92b69db..4b392df 100644
--- a/chrome/browser/net/url_fixer_upper.cc
+++ b/chrome/browser/net/url_fixer_upper.cc
@@ -6,7 +6,9 @@
#include <algorithm>
-#include "base/env_var.h"
+#if defined(OS_POSIX)
+#include "base/environment.h"
+#endif
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_util.h"
@@ -170,7 +172,7 @@ static std::string FixupPath(const std::string& text) {
// Here, we know the input looks like a file.
GURL file_url = net::FilePathToFileURL(FilePath(filename));
if (file_url.is_valid()) {
- return WideToUTF8(net::FormatUrl(file_url, std::wstring(),
+ return UTF16ToUTF8(net::FormatUrl(file_url, std::string(),
net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, NULL,
NULL, NULL));
}
@@ -568,7 +570,7 @@ GURL URLFixerUpper::FixupRelativeFile(const FilePath& base_dir,
if (is_file) {
GURL file_url = net::FilePathToFileURL(full_path);
if (file_url.is_valid())
- return GURL(WideToUTF8(net::FormatUrl(file_url, std::wstring(),
+ return GURL(UTF16ToUTF8(net::FormatUrl(file_url, std::string(),
net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, NULL,
NULL, NULL)));
// Invalid files fall through to regular processing.
diff --git a/chrome/browser/net/url_fixer_upper.h b/chrome/browser/net/url_fixer_upper.h
index 97bc6c0..1e5d731 100644
--- a/chrome/browser/net/url_fixer_upper.h
+++ b/chrome/browser/net/url_fixer_upper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_URL_FIXER_UPPER_H_
#define CHROME_BROWSER_NET_URL_FIXER_UPPER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/net/url_info.cc b/chrome/browser/net/url_info.cc
index fab27ad..994cfe7 100644
--- a/chrome/browser/net/url_info.cc
+++ b/chrome/browser/net/url_info.cc
@@ -64,14 +64,20 @@ const TimeDelta UrlInfo::kNullDuration(TimeDelta::FromMilliseconds(-1));
// has a TON of copies of the same domain name, so that we don't thrash the OS
// to death. Hopefully it is small enough that we're not hurting our cache hit
// rate (i.e., we could always ask the OS).
-TimeDelta UrlInfo::kCacheExpirationDuration(TimeDelta::FromSeconds(5));
+TimeDelta UrlInfo::cache_expiration_duration_(TimeDelta::FromSeconds(5));
const TimeDelta UrlInfo::kMaxNonNetworkDnsLookupDuration(
TimeDelta::FromMilliseconds(15));
// Used by test ONLY. The value is otherwise constant.
+// static
void UrlInfo::set_cache_expiration(TimeDelta time) {
- kCacheExpirationDuration = time;
+ cache_expiration_duration_ = time;
+}
+
+// static
+TimeDelta UrlInfo::get_cache_expiration() {
+ return cache_expiration_duration_;
}
void UrlInfo::SetQueuedState(ResolutionMotivation motivation) {
@@ -122,20 +128,6 @@ void UrlInfo::SetFoundState() {
if (kMaxNonNetworkDnsLookupDuration <= resolve_duration_) {
UMA_HISTOGRAM_CUSTOM_TIMES("DNS.PrefetchResolution", resolve_duration_,
kMaxNonNetworkDnsLookupDuration, TimeDelta::FromMinutes(15), 100);
-
- static bool use_ipv6_histogram(FieldTrialList::Find("IPv6_Probe") &&
- !FieldTrialList::Find("IPv6_Probe")->group_name().empty());
- if (use_ipv6_histogram) {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- FieldTrial::MakeName("DNS.PrefetchResolution", "IPv6_Probe"),
- resolve_duration_, kMaxNonNetworkDnsLookupDuration,
- TimeDelta::FromMinutes(15), 100);
- }
-
- // Record potential beneficial time, and maybe we'll get a cache hit.
- // We keep the maximum, as the warming we did earlier may still be
- // helping with a cache upstream in DNS resolution.
- benefits_remaining_ = std::max(resolve_duration_, benefits_remaining_);
}
sequence_number_ = sequence_counter++;
DLogResultsStats("DNS PrefetchFound");
@@ -147,29 +139,11 @@ void UrlInfo::SetNoSuchNameState() {
resolve_duration_ = GetDuration();
if (kMaxNonNetworkDnsLookupDuration <= resolve_duration_) {
DHISTOGRAM_TIMES("DNS.PrefetchNotFoundName", resolve_duration_);
- // Record potential beneficial time, and maybe we'll get a cache hit.
- benefits_remaining_ = std::max(resolve_duration_, benefits_remaining_);
}
sequence_number_ = sequence_counter++;
DLogResultsStats("DNS PrefetchNotFound");
}
-void UrlInfo::SetStartedState() {
- DCHECK(PENDING == state_);
- state_ = STARTED;
- queue_duration_ = resolve_duration_ = TimeDelta(); // 0ms.
- SetMotivation(NO_PREFETCH_MOTIVATION);
- GetDuration(); // Set time.
-}
-
-void UrlInfo::SetFinishedState(bool was_resolved) {
- DCHECK(STARTED == state_);
- state_ = was_resolved ? FINISHED : FINISHED_UNRESOLVED;
- resolve_duration_ = GetDuration();
- // TODO(jar): Sequence number should be incremented in prefetched HostInfo.
- DLogResultsStats("DNS HTTP Finished");
-}
-
void UrlInfo::SetUrl(const GURL& url) {
if (url_.is_empty()) // Not yet initialized.
url_ = url;
@@ -192,59 +166,7 @@ bool UrlInfo::IsStillCached() const {
TimeDelta time_since_resolution = TimeTicks::Now() - time_;
- return time_since_resolution < kCacheExpirationDuration;
-}
-
-// Compare the actual navigation DNS latency found in navigation_info, to the
-// previously prefetched info.
-DnsBenefit UrlInfo::AccruePrefetchBenefits(UrlInfo* navigation_info) {
- DCHECK(FINISHED == navigation_info->state_ ||
- FINISHED_UNRESOLVED == navigation_info->state_);
- DCHECK(navigation_info->url() == url_);
-
- if ((0 == benefits_remaining_.InMilliseconds()) ||
- (FOUND != state_ && NO_SUCH_NAME != state_)) {
- if (FINISHED == navigation_info->state_)
- UMA_HISTOGRAM_LONG_TIMES("DNS.IndependentNavigation",
- navigation_info->resolve_duration_);
- else
- UMA_HISTOGRAM_LONG_TIMES("DNS.IndependentFailedNavigation",
- navigation_info->resolve_duration_);
- return PREFETCH_NO_BENEFIT;
- }
-
- TimeDelta benefit = benefits_remaining_ - navigation_info->resolve_duration_;
- navigation_info->benefits_remaining_ = benefits_remaining_;
- benefits_remaining_ = TimeDelta(); // We used up all our benefits here.
-
- navigation_info->motivation_ = motivation_;
- if (LEARNED_REFERAL_MOTIVATED == motivation_ ||
- STATIC_REFERAL_MOTIVATED == motivation_)
- navigation_info->referring_url_ = referring_url_;
-
- if (navigation_info->resolve_duration_ > kMaxNonNetworkDnsLookupDuration) {
- // Our precache effort didn't help since HTTP stack hit the network.
- UMA_HISTOGRAM_LONG_TIMES("DNS.PrefetchCacheEvictionL", resolve_duration_);
- DLogResultsStats("DNS PrefetchCacheEviction");
- return PREFETCH_CACHE_EVICTION;
- }
-
- if (NO_SUCH_NAME == state_) {
- UMA_HISTOGRAM_LONG_TIMES("DNS.PrefetchNegativeHitL", benefit);
- DLogResultsStats("DNS PrefetchNegativeHit");
- return PREFETCH_NAME_NONEXISTANT;
- }
-
- DCHECK_EQ(FOUND, state_);
- if (LEARNED_REFERAL_MOTIVATED == motivation_ ||
- STATIC_REFERAL_MOTIVATED == motivation_) {
- UMA_HISTOGRAM_TIMES("DNS.PrefetchReferredPositiveHit", benefit);
- DLogResultsStats("DNS PrefetchReferredPositiveHit");
- } else {
- UMA_HISTOGRAM_LONG_TIMES("DNS.PrefetchPositiveHitL", benefit);
- DLogResultsStats("DNS PrefetchPositiveHit");
- }
- return PREFETCH_NAME_FOUND;
+ return time_since_resolution < cache_expiration_duration_;
}
void UrlInfo::DLogResultsStats(const char* message) const {
@@ -253,7 +175,6 @@ void UrlInfo::DLogResultsStats(const char* message) const {
DLOG(INFO) << "\t" << message << "\tq="
<< queue_duration().InMilliseconds() << "ms,\tr="
<< resolve_duration().InMilliseconds() << "ms\tp="
- << benefits_remaining_.InMilliseconds() << "ms\tseq="
<< sequence_number_
<< "\t" << url_.spec();
}
@@ -329,7 +250,7 @@ static std::string HoursMinutesSeconds(int seconds) {
}
// static
-void UrlInfo::GetHtmlTable(const DnsInfoTable host_infos,
+void UrlInfo::GetHtmlTable(const UrlInfoTable host_infos,
const char* description,
const bool brief,
std::string* output) {
@@ -344,56 +265,32 @@ void UrlInfo::GetHtmlTable(const DnsInfoTable host_infos,
return;
}
- const char* row_format = "<tr align=right><td>%s</td>"
- "<td>%d</td><td>%d</td><td>%s</td><td>%s</td></tr>";
+ output->append("<br><table border=1>"
+ "<tr><th>Host name</th>"
+ "<th>How long ago<br>(HH:MM:SS)</th>"
+ "<th>Motivation</th>"
+ "</tr>");
- output->append("<br><table border=1>");
- StringAppendF(output,
- "<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>",
- "Host name", "Applicable Prefetch<br>Time (ms)",
- "Recent Resolution<br>Time(ms)", "How long ago<br>(HH:MM:SS)",
- "Motivation");
+ const char* row_format = "<tr align=right><td>%s</td>" // Host name.
+ "<td>%s</td>" // How long ago.
+ "<td>%s</td>" // Motivation.
+ "</tr>";
// Print bulk of table, and gather stats at same time.
- MinMaxAverage queue, resolve, preresolve, when;
+ MinMaxAverage queue, when;
TimeTicks current_time = TimeTicks::Now();
- for (DnsInfoTable::const_iterator it(host_infos.begin());
+ for (UrlInfoTable::const_iterator it(host_infos.begin());
it != host_infos.end(); it++) {
queue.sample((it->queue_duration_.InMilliseconds()));
StringAppendF(output, row_format,
RemoveJs(it->url_.spec()).c_str(),
- preresolve.sample((it->benefits_remaining_.InMilliseconds())),
- resolve.sample((it->resolve_duration_.InMilliseconds())),
HoursMinutesSeconds(when.sample(
(current_time - it->time_).InSeconds())).c_str(),
it->GetAsciiMotivation().c_str());
}
- // Write min, max, and average summary lines.
- if (host_infos.size() > 2) {
- output->append("<B>");
- StringAppendF(output, row_format,
- "<b>---minimum---</b>",
- preresolve.minimum(), resolve.minimum(),
- HoursMinutesSeconds(when.minimum()).c_str(), "");
- StringAppendF(output, row_format,
- "<b>---average---</b>",
- preresolve.average(), resolve.average(),
- HoursMinutesSeconds(when.average()).c_str(), "");
- StringAppendF(output, row_format,
- "<b>standard deviation</b>",
- preresolve.standard_deviation(),
- resolve.standard_deviation(), "n/a", "");
- StringAppendF(output, row_format,
- "<b>---maximum---</b>",
- preresolve.maximum(), resolve.maximum(),
- HoursMinutesSeconds(when.maximum()).c_str(), "");
- StringAppendF(output, row_format,
- "<b>-----SUM-----</b>",
- preresolve.sum(), resolve.sum(), "n/a", "");
- }
output->append("</table>");
-#ifdef DEBUG
+#ifndef NDEBUG
StringAppendF(output,
"Prefetch Queue Durations: min=%d, avg=%d, max=%d<br><br>",
queue.minimum(), queue.average(), queue.maximum());
diff --git a/chrome/browser/net/url_info.h b/chrome/browser/net/url_info.h
index a9b56f3..6b50f42 100644
--- a/chrome/browser/net/url_info.h
+++ b/chrome/browser/net/url_info.h
@@ -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.
@@ -15,6 +15,7 @@
#ifndef CHROME_BROWSER_NET_URL_INFO_H_
#define CHROME_BROWSER_NET_URL_INFO_H_
+#pragma once
#include <string>
#include <vector>
@@ -28,14 +29,6 @@ namespace chrome_browser_net {
// Use command line switch to enable detailed logging.
void EnablePredictorDetailedLog(bool enable);
-enum DnsBenefit {
- PREFETCH_NO_BENEFIT, // Prefetch never hit the network. Name was pre-cached.
- PREFETCH_CACHE_EVICTION, // Prefetch used network, but so did HTTP stack.
- PREFETCH_NAME_NONEXISTANT, // Valuable prefetch of "name not found" was used.
- PREFETCH_NAME_FOUND, // Valuable prefetch was used.
- PREFETCH_OBLIVIOUS // No prefetch attempt was even made.
-};
-
class UrlInfo {
public:
// Reasons for a domain to be resolved.
@@ -46,6 +39,9 @@ class UrlInfo {
LINKED_MAX_MOTIVATED, // enum demarkation above motivation from links.
OMNIBOX_MOTIVATED, // Omni-box suggested resolving this.
STARTUP_LIST_MOTIVATED, // Startup list caused this resolution.
+ EARLY_LOAD_MOTIVATED, // In some cases we use the prefetcher to warm up
+ // the connection in advance of issuing the real
+ // request.
NO_PREFETCH_MOTIVATION, // Browser navigation info (not prefetch related).
@@ -54,6 +50,8 @@ class UrlInfo {
// TODO(jar): Support STATIC_REFERAL_MOTIVATED API and integration.
STATIC_REFERAL_MOTIVATED, // External database suggested this resolution.
LEARNED_REFERAL_MOTIVATED, // Prior navigation taught us this resolution.
+
+ MAX_MOTIVATED // Beyond all enums, for use in histogram bounding.
};
enum DnsProcessingState {
@@ -64,16 +62,13 @@ class UrlInfo {
ASSIGNED_BUT_MARKED, // Needs to be deleted as soon as it's resolved.
FOUND, // DNS resolution completed.
NO_SUCH_NAME, // DNS resolution completed.
- // When processed by the network stack during navigation, the states are:
- STARTED, // Resolution has begun for a navigation.
- FINISHED, // Resolution has completed for a navigation.
- FINISHED_UNRESOLVED}; // No resolution found, so navigation will fail.
+ };
static const base::TimeDelta kMaxNonNetworkDnsLookupDuration;
// The number of OS cache entries we can guarantee(?) before cache eviction
// might likely take place.
static const int kMaxGuaranteedDnsCacheSize = 50;
- typedef std::vector<UrlInfo> DnsInfoTable;
+ typedef std::vector<UrlInfo> UrlInfoTable;
static const base::TimeDelta kNullDuration;
@@ -84,7 +79,6 @@ class UrlInfo {
old_prequeue_state_(state_),
resolve_duration_(kNullDuration),
queue_duration_(kNullDuration),
- benefits_remaining_(),
sequence_number_(0),
motivation_(NO_PREFETCH_MOTIVATION),
was_linked_(false) {
@@ -98,7 +92,9 @@ class UrlInfo {
// on how recently we've done DNS prefetching for hostname.
bool NeedsDnsUpdate();
+ // FOR TEST ONLY: The following access the otherwise constant values.
static void set_cache_expiration(base::TimeDelta time);
+ static base::TimeDelta get_cache_expiration();
// The prefetching lifecycle.
void SetQueuedState(ResolutionMotivation motivation);
@@ -107,9 +103,6 @@ class UrlInfo {
void SetPendingDeleteState();
void SetFoundState();
void SetNoSuchNameState();
- // The actual browsing resolution lifecycle.
- void SetStartedState();
- void SetFinishedState(bool was_resolved);
// Finish initialization. Must only be called once.
void SetUrl(const GURL& url);
@@ -122,7 +115,7 @@ class UrlInfo {
}
bool was_found() const { return FOUND == state_; }
- bool was_nonexistant() const { return NO_SUCH_NAME == state_; }
+ bool was_nonexistent() const { return NO_SUCH_NAME == state_; }
bool is_assigned() const {
return ASSIGNED == state_ || ASSIGNED_BUT_MARKED == state_;
}
@@ -135,17 +128,19 @@ class UrlInfo {
base::TimeDelta resolve_duration() const { return resolve_duration_;}
base::TimeDelta queue_duration() const { return queue_duration_;}
- base::TimeDelta benefits_remaining() const { return benefits_remaining_; }
-
- DnsBenefit AccruePrefetchBenefits(UrlInfo* navigation_info);
void DLogResultsStats(const char* message) const;
- static void GetHtmlTable(const DnsInfoTable host_infos,
+ static void GetHtmlTable(const UrlInfoTable host_infos,
const char* description,
const bool brief,
std::string* output);
+ // For testing, and use in printing tables of info, we sometimes need to
+ // adjust the time manually. Usually, this value is maintained by state
+ // transition, and this call is not made.
+ void set_time(const base::TimeTicks& time) { time_ = time; }
+
private:
base::TimeDelta GetDuration() {
base::TimeTicks old_time = time_;
@@ -164,7 +159,7 @@ class UrlInfo {
std::string GetAsciiMotivation() const;
// The next declaration is non-const to facilitate testing.
- static base::TimeDelta kCacheExpirationDuration;
+ static base::TimeDelta cache_expiration_duration_;
// The current state of this instance.
DnsProcessingState state_;
@@ -181,8 +176,6 @@ class UrlInfo {
base::TimeDelta resolve_duration_;
// Time spent in queue.
base::TimeDelta queue_duration_;
- // Unused potential benefits of a prefetch.
- base::TimeDelta benefits_remaining_;
int sequence_number_; // Used to calculate potential of cache eviction.
static int sequence_counter; // Used to allocate sequence_number_'s.
diff --git a/chrome/browser/net/url_info_unittest.cc b/chrome/browser/net/url_info_unittest.cc
index 3126cb9..ea7d619 100644
--- a/chrome/browser/net/url_info_unittest.cc
+++ b/chrome/browser/net/url_info_unittest.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.
@@ -8,19 +8,24 @@
#include <string>
#include "base/platform_thread.h"
+#include "base/time.h"
#include "chrome/browser/net/url_info.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::TimeDelta;
+using base::TimeTicks;
namespace {
-class DnsHostInfoTest : public testing::Test {
+class UrlHostInfoTest : public testing::Test {
};
typedef chrome_browser_net::UrlInfo UrlInfo;
-TEST(DnsHostInfoTest, StateChangeTest) {
+// Cycle throught the states held by a UrlInfo instance, and check to see that
+// states look reasonable as time ticks away. If the test bots are too slow,
+// we'll just give up on this test and exit from it.
+TEST(UrlHostInfoTest, StateChangeTest) {
UrlInfo info_practice, info;
GURL url1("http://domain1.com:80"), url2("https://domain2.com:443");
@@ -31,54 +36,49 @@ TEST(DnsHostInfoTest, StateChangeTest) {
info_practice.SetQueuedState(UrlInfo::UNIT_TEST_MOTIVATED);
info_practice.SetAssignedState();
info_practice.SetFoundState();
- PlatformThread::Sleep(500); // Allow time for DLLs to fully load.
+
+ // Start test with actual (long/default) expiration time intact.
// Complete the construction of real test object.
info.SetUrl(url1);
-
EXPECT_TRUE(info.NeedsDnsUpdate()) << "error in construction state";
info.SetQueuedState(UrlInfo::UNIT_TEST_MOTIVATED);
- EXPECT_FALSE(info.NeedsDnsUpdate())
- << "update needed after being queued";
+ EXPECT_FALSE(info.NeedsDnsUpdate()) << "update needed after being queued";
info.SetAssignedState();
- EXPECT_FALSE(info.NeedsDnsUpdate());
+ EXPECT_FALSE(info.NeedsDnsUpdate()) << "update needed during resolution";
+ base::TimeTicks before_resolution_complete = TimeTicks::Now();
info.SetFoundState();
- EXPECT_FALSE(info.NeedsDnsUpdate())
- << "default expiration time is TOOOOO short";
-
- // Note that time from ASSIGNED to FOUND was VERY short (probably 0ms), so the
- // object should conclude that no network activity was needed. As a result,
- // the required time till expiration will be halved (guessing that we were
- // half way through having the cache expire when we did the lookup.
- EXPECT_LT(info.resolve_duration().InMilliseconds(),
- UrlInfo::kMaxNonNetworkDnsLookupDuration.InMilliseconds())
- << "Non-net time is set too low";
-
- info.set_cache_expiration(TimeDelta::FromMilliseconds(300));
- EXPECT_FALSE(info.NeedsDnsUpdate()) << "expiration time not honored";
- PlatformThread::Sleep(80); // Not enough time to pass our 300ms mark.
- EXPECT_FALSE(info.NeedsDnsUpdate()) << "expiration time not honored";
+ // "Immediately" check to see if we need an update yet (we shouldn't).
+ if (info.NeedsDnsUpdate()) {
+ // The test bot must be really slow, so we can verify that.
+ EXPECT_GT((TimeTicks::Now() - before_resolution_complete).InMilliseconds(),
+ UrlInfo::get_cache_expiration().InMilliseconds());
+ return; // Lets punt here, the test bot is too slow.
+ }
+
+ // Run similar test with a shortened expiration, so we can trigger it.
+ const int kMockExpirationTime(300); // Vastly reduced expiration time.
+ info.set_cache_expiration(TimeDelta::FromMilliseconds(kMockExpirationTime));
// That was a nice life when the object was found.... but next time it won't
// be found. We'll sleep for a while, and then come back with not-found.
info.SetQueuedState(UrlInfo::UNIT_TEST_MOTIVATED);
+ EXPECT_FALSE(info.NeedsDnsUpdate());
info.SetAssignedState();
EXPECT_FALSE(info.NeedsDnsUpdate());
// Greater than minimal expected network latency on DNS lookup.
PlatformThread::Sleep(25);
+ before_resolution_complete = TimeTicks::Now();
info.SetNoSuchNameState();
- EXPECT_FALSE(info.NeedsDnsUpdate())
- << "default expiration time is TOOOOO short";
-
- // Note that now we'll actually utilize an expiration of 300ms,
- // since there was detected network activity time during lookup.
- // We're assuming the caching just started with our lookup.
- PlatformThread::Sleep(80); // Not enough time to pass our 300ms mark.
- EXPECT_FALSE(info.NeedsDnsUpdate()) << "expiration time not honored";
- // Still not past our 300ms mark (only about 4+2ms)
- PlatformThread::Sleep(80);
- EXPECT_FALSE(info.NeedsDnsUpdate()) << "expiration time not honored";
- PlatformThread::Sleep(150);
+ // "Immediately" check to see if we need an update yet (we shouldn't).
+ if (info.NeedsDnsUpdate()) {
+ // The test bot must be really slow, so we can verify that.
+ EXPECT_GT((TimeTicks::Now() - before_resolution_complete).InMilliseconds(),
+ kMockExpirationTime);
+ return;
+ }
+ // Wait over 300ms, so it should definately be considered out of cache.
+ PlatformThread::Sleep(kMockExpirationTime + 20);
EXPECT_TRUE(info.NeedsDnsUpdate()) << "expiration time not honored";
}
@@ -91,7 +91,7 @@ TEST(DnsHostInfoTest, StateChangeTest) {
// getting sent to a resolver thread) and reset our state to what it was before
// the corresponding name was put in the work_queue_. This test drives through
// the state transitions used in such congestion handling.
-TEST(DnsHostInfoTest, CongestionResetStateTest) {
+TEST(UrlHostInfoTest, CongestionResetStateTest) {
UrlInfo info;
GURL url("http://domain1.com:80");
@@ -106,7 +106,7 @@ TEST(DnsHostInfoTest, CongestionResetStateTest) {
// Since this was a new info instance, and it never got resolved, we land back
// in a PENDING state rather than FOUND or NO_SUCH_NAME.
EXPECT_FALSE(info.was_found());
- EXPECT_FALSE(info.was_nonexistant());
+ EXPECT_FALSE(info.was_nonexistent());
// Make sure we're completely re-usable, by going throug a normal flow.
info.SetQueuedState(UrlInfo::UNIT_TEST_MOTIVATED);
diff --git a/chrome/browser/net/url_request_failed_dns_job.h b/chrome/browser/net/url_request_failed_dns_job.h
index 2c2e336..a0c4542 100644
--- a/chrome/browser/net/url_request_failed_dns_job.h
+++ b/chrome/browser/net/url_request_failed_dns_job.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_FAILED_DNS_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_FAILED_DNS_JOB_H_
+#pragma once
#include "net/url_request/url_request_job.h"
diff --git a/chrome/browser/net/url_request_mock_http_job.h b/chrome/browser/net/url_request_mock_http_job.h
index b54dd37..35a251c 100644
--- a/chrome/browser/net/url_request_mock_http_job.h
+++ b/chrome/browser/net/url_request_mock_http_job.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_MOCK_HTTP_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_MOCK_HTTP_JOB_H_
+#pragma once
#include <string>
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 88ef438..e34baa9 100644
--- a/chrome/browser/net/url_request_mock_link_doctor_job.cc
+++ b/chrome/browser/net/url_request_mock_link_doctor_job.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/net/url_request_mock_link_doctor_job.h"
#include "base/path_service.h"
-#include "chrome/browser/google_util.h"
+#include "chrome/browser/google/google_util.h"
#include "chrome/common/chrome_paths.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_filter.h"
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 be1367f..4af4fe7 100644
--- a/chrome/browser/net/url_request_mock_link_doctor_job.h
+++ b/chrome/browser/net/url_request_mock_link_doctor_job.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_MOCK_LINK_DOCTOR_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_MOCK_LINK_DOCTOR_JOB_H_
+#pragma once
#include "chrome/browser/net/url_request_mock_http_job.h"
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 bf31a92..a590833 100644
--- a/chrome/browser/net/url_request_mock_net_error_job.cc
+++ b/chrome/browser/net/url_request_mock_net_error_job.cc
@@ -12,6 +12,7 @@
#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/x509_certificate.h"
#include "net/url_request/url_request_filter.h"
// static
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 b972d5e..4519161 100644
--- a/chrome/browser/net/url_request_mock_net_error_job.h
+++ b/chrome/browser/net/url_request_mock_net_error_job.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_MOCK_NET_ERROR_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_MOCK_NET_ERROR_JOB_H_
+#pragma once
#include "chrome/browser/net/url_request_mock_http_job.h"
diff --git a/chrome/browser/net/url_request_mock_util.h b/chrome/browser/net/url_request_mock_util.h
index b3a81bb..16495a6 100644
--- a/chrome/browser/net/url_request_mock_util.h
+++ b/chrome/browser/net/url_request_mock_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_MOCK_UTIL_H_
#define CHROME_BROWSER_NET_URL_REQUEST_MOCK_UTIL_H_
+#pragma once
// You should use routines in this file only for test code!
diff --git a/chrome/browser/net/url_request_slow_download_job.cc b/chrome/browser/net/url_request_slow_download_job.cc
index 93768ec..138a57c 100644
--- a/chrome/browser/net/url_request_slow_download_job.cc
+++ b/chrome/browser/net/url_request_slow_download_job.cc
@@ -100,7 +100,6 @@ bool URLRequestSlowDownloadJob::ReadRawData(net::IOBuffer* buf, int buf_size,
*bytes_read = send_size;
first_download_size_remaining_ -= send_size;
- SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
DCHECK(!is_done());
return true;
}
@@ -112,6 +111,7 @@ bool URLRequestSlowDownloadJob::ReadRawData(net::IOBuffer* buf, int buf_size,
// If we make it here, the first chunk has been sent and we need to wait
// until a request is made for kFinishDownloadUrl.
+ SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
this, &URLRequestSlowDownloadJob::CheckDoneStatus), 100);
AddRef();
diff --git a/chrome/browser/net/url_request_slow_download_job.h b/chrome/browser/net/url_request_slow_download_job.h
index d0ac671..9d92338 100644
--- a/chrome/browser/net/url_request_slow_download_job.h
+++ b/chrome/browser/net/url_request_slow_download_job.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/net/url_request_slow_http_job.cc b/chrome/browser/net/url_request_slow_http_job.cc
index 3d143b0..a8205f0 100644
--- a/chrome/browser/net/url_request_slow_http_job.cc
+++ b/chrome/browser/net/url_request_slow_http_job.cc
@@ -53,6 +53,9 @@ void URLRequestSlowHTTPJob::Start() {
&URLRequestSlowHTTPJob::RealStart);
}
+URLRequestSlowHTTPJob::~URLRequestSlowHTTPJob() {
+}
+
void URLRequestSlowHTTPJob::RealStart() {
URLRequestMockHTTPJob::Start();
}
diff --git a/chrome/browser/net/url_request_slow_http_job.h b/chrome/browser/net/url_request_slow_http_job.h
index 347d55a..fab7a01 100644
--- a/chrome/browser/net/url_request_slow_http_job.h
+++ b/chrome/browser/net/url_request_slow_http_job.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,8 +6,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_SLOW_HTTP_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_SLOW_HTTP_JOB_H_
-
-#include <string>
+#pragma once
#include "base/timer.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
@@ -29,7 +28,7 @@ class URLRequestSlowHTTPJob : public URLRequestMockHTTPJob {
virtual void Start();
private:
- ~URLRequestSlowHTTPJob() {}
+ ~URLRequestSlowHTTPJob();
void RealStart();
diff --git a/chrome/browser/net/url_request_tracking.h b/chrome/browser/net/url_request_tracking.h
index c0a3e9e..4eb3dfd 100644
--- a/chrome/browser/net/url_request_tracking.h
+++ b/chrome/browser/net/url_request_tracking.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_URL_REQUEST_TRACKING_H_
#define CHROME_BROWSER_NET_URL_REQUEST_TRACKING_H_
+#pragma once
class URLRequest;
diff --git a/chrome/browser/net/view_http_cache_job_factory.cc b/chrome/browser/net/view_http_cache_job_factory.cc
index 5a3cd65..3793df3 100644
--- a/chrome/browser/net/view_http_cache_job_factory.cc
+++ b/chrome/browser/net/view_http_cache_job_factory.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/net/view_http_cache_job_factory.h"
#include "base/message_loop.h"
+#include "base/string_util.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request.h"
@@ -18,11 +19,12 @@ namespace {
class ViewHttpCacheJob : public URLRequestJob {
public:
explicit ViewHttpCacheJob(URLRequest* request)
- : URLRequestJob(request), data_offset_(0),
+ : URLRequestJob(request), data_offset_(0), cancel_(false), busy_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(
callback_(this, &ViewHttpCacheJob::OnIOComplete)) {}
virtual void Start();
+ virtual void Kill();
virtual bool GetMimeType(std::string* mime_type) const;
virtual bool GetCharset(std::string* charset);
virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
@@ -35,14 +37,18 @@ class ViewHttpCacheJob : public URLRequestJob {
std::string data_;
int data_offset_;
+ bool cancel_;
+ bool busy_;
net::ViewCacheHelper cache_helper_;
net::CompletionCallbackImpl<ViewHttpCacheJob> callback_;
};
void ViewHttpCacheJob::Start() {
- if (!request_)
+ if (!request_ || cancel_)
return;
+ busy_ = true;
+ AddRef(); // Released on OnIOComplete().
std::string cache_key =
request_->url().spec().substr(strlen(chrome::kNetworkViewCacheURL));
@@ -64,6 +70,14 @@ void ViewHttpCacheJob::Start() {
}
}
+void ViewHttpCacheJob::Kill() {
+ // We don't want to delete this object while we are busy; we'll do it when it
+ // is safe.
+ cancel_ = true;
+ if (!busy_)
+ URLRequestJob::Kill();
+}
+
bool ViewHttpCacheJob::GetMimeType(std::string* mime_type) const {
mime_type->assign("text/html");
return true;
@@ -87,7 +101,14 @@ bool ViewHttpCacheJob::ReadRawData(net::IOBuffer* buf, int buf_size,
}
void ViewHttpCacheJob::OnIOComplete(int result) {
+ // We may be holding the last reference to this job.
+ scoped_refptr<ViewHttpCacheJob> self(this);
DCHECK_EQ(net::OK, result);
+ busy_ = false;
+ Release(); // Acquired on Start().
+
+ if (cancel_)
+ return URLRequestJob::Kill();
// Notify that the headers are complete.
NotifyHeadersComplete();
diff --git a/chrome/browser/net/view_http_cache_job_factory.h b/chrome/browser/net/view_http_cache_job_factory.h
index e3fa152..6291902 100644
--- a/chrome/browser/net/view_http_cache_job_factory.h
+++ b/chrome/browser/net/view_http_cache_job_factory.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NET_VIEW_HTTP_CACHE_JOB_FACTORY_H_
#define CHROME_BROWSER_NET_VIEW_HTTP_CACHE_JOB_FACTORY_H_
+#pragma once
class GURL;
class URLRequest;
diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc
index c380af5..fa4ede8 100644
--- a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc
+++ b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.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 "base/field_trial.h"
#include "base/message_loop.h"
#include "base/task.h"
+#include "base/string_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_switches.h"
+#include "net/base/host_resolver.h"
#include "net/base/net_errors.h"
#include "net/websockets/websocket.h"
@@ -27,7 +29,7 @@ void WebSocketExperimentRunner::Start() {
DCHECK(!runner.get());
scoped_refptr<FieldTrial> trial = new FieldTrial("WebSocketExperiment", 1000);
- trial->AppendGroup("_active", 5); // 0.5% in _active group.
+ trial->AppendGroup("active", 5); // 0.5% in active group.
bool run_experiment = (trial->group() != FieldTrial::kNotParticipating);
#ifndef NDEBUG
@@ -170,7 +172,7 @@ void WebSocketExperimentRunner::InitConfig() {
void WebSocketExperimentRunner::DoLoop() {
if (next_state_ == STATE_NONE) {
if (task_.get()) {
- AddRef(); // Release in OnTaskCompleted.
+ AddRef(); // Release in OnTaskCompleted after Cancelled.
task_->Cancel();
}
return;
@@ -213,7 +215,7 @@ void WebSocketExperimentRunner::DoLoop() {
}
void WebSocketExperimentRunner::OnTaskCompleted(int result) {
- if (result == net::ERR_ABORTED) {
+ if (next_state_ == STATE_NONE) {
task_.reset();
// Task is Canceled.
DLOG(INFO) << "WebSocketExperiment Task is canceled.";
diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.h b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.h
index b41f11a..16b20f0 100644
--- a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.h
+++ b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.h
@@ -13,6 +13,7 @@
#ifndef CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_RUNNER_H_
#define CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_RUNNER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/histogram.h"
diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
index efc50c8..6cbc6cd 100644
--- a/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
+++ b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/common/net/url_request_context_getter.h"
+#include "net/base/host_resolver.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/websockets/websocket.h"
diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_task.h b/chrome/browser/net/websocket_experiment/websocket_experiment_task.h
index fc62fd7..c1fe41c 100644
--- a/chrome/browser/net/websocket_experiment/websocket_experiment_task.h
+++ b/chrome/browser/net/websocket_experiment/websocket_experiment_task.h
@@ -33,6 +33,7 @@
#ifndef CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_
#define CHROME_BROWSER_NET_WEBSOCKET_EXPERIMENT_WEBSOCKET_EXPERIMENT_TASK_H_
+#pragma once
#include <deque>
#include <string>
diff --git a/chrome/browser/notifications/balloon.cc b/chrome/browser/notifications/balloon.cc
index 969bde1..96f3fca 100644
--- a/chrome/browser/notifications/balloon.cc
+++ b/chrome/browser/notifications/balloon.cc
@@ -51,6 +51,10 @@ void Balloon::Update(const Notification& notification) {
}
}
+void Balloon::OnClick() {
+ notification_->Click();
+}
+
void Balloon::OnClose(bool by_user) {
notification_->Close(by_user);
collection_->OnBalloonClosed(this);
diff --git a/chrome/browser/notifications/balloon.h b/chrome/browser/notifications/balloon.h
index 7f3b604..3f4ba0b 100644
--- a/chrome/browser/notifications/balloon.h
+++ b/chrome/browser/notifications/balloon.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,8 +6,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOON_H_
#define CHROME_BROWSER_NOTIFICATIONS_BALLOON_H_
-
-#include <vector>
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
@@ -97,6 +96,9 @@ class Balloon {
// Notify that the content of notification has changed.
virtual void Update(const Notification& notification);
+ // Called when the balloon is clicked by the user.
+ virtual void OnClick();
+
// Called when the balloon is closed, either by user (through the UI)
// or by a script.
virtual void OnClose(bool by_user);
diff --git a/chrome/browser/notifications/balloon_collection.cc b/chrome/browser/notifications/balloon_collection.cc
index 3b66a07..ebbe566 100644
--- a/chrome/browser/notifications/balloon_collection.cc
+++ b/chrome/browser/notifications/balloon_collection.cc
@@ -62,7 +62,6 @@ void BalloonCollectionImpl::Add(const Notification& notification,
if (balloons_.size() > 0)
new_balloon->set_offset(balloons_[balloons_.size() - 1]->offset());
#endif
-
balloons_.push_back(new_balloon);
PositionBalloons(false);
@@ -151,7 +150,7 @@ void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) {
space_change_listener_->OnBalloonSpaceChanged();
}
-void BalloonCollectionImpl::PositionBalloons(bool reposition) {
+void BalloonCollectionImpl::PositionBalloonsInternal(bool reposition) {
layout_.RefreshSystemMetrics();
gfx::Point origin = layout_.GetLayoutOrigin();
for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) {
diff --git a/chrome/browser/notifications/balloon_collection.h b/chrome/browser/notifications/balloon_collection.h
index 2d868c4..7a7b081 100644
--- a/chrome/browser/notifications/balloon_collection.h
+++ b/chrome/browser/notifications/balloon_collection.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_H_
#define CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_H_
+#pragma once
#include <deque>
diff --git a/chrome/browser/notifications/balloon_collection_impl.h b/chrome/browser/notifications/balloon_collection_impl.h
index cb06230..dc9975e 100644
--- a/chrome/browser/notifications/balloon_collection_impl.h
+++ b/chrome/browser/notifications/balloon_collection_impl.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_IMPL_H_
#define CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_IMPL_H_
+#pragma once
#include <deque>
@@ -138,8 +139,12 @@ class BalloonCollectionImpl : public BalloonCollection
int count() const { return balloons_.size(); }
// Adjusts the positions of the balloons (e.g., when one is closed).
+ // Implemented by each platform for specific UI requirements.
void PositionBalloons(bool is_reposition);
+ // Cross-platform internal implementation for PositionBalloons.
+ void PositionBalloonsInternal(bool is_reposition);
+
#if defined(OS_MACOSX)
// Get the work area on Mac OS, without inverting the coordinates.
static gfx::Rect GetMacWorkArea();
diff --git a/chrome/browser/notifications/balloon_collection_linux.cc b/chrome/browser/notifications/balloon_collection_linux.cc
index a499292..f15c713 100644
--- a/chrome/browser/notifications/balloon_collection_linux.cc
+++ b/chrome/browser/notifications/balloon_collection_linux.cc
@@ -30,6 +30,10 @@ int BalloonCollectionImpl::Layout::VerticalEdgeMargin() const {
return 5;
}
+void BalloonCollectionImpl::PositionBalloons(bool reposition) {
+ PositionBalloonsInternal(reposition);
+}
+
void BalloonCollectionImpl::DidProcessEvent(GdkEvent* event) {
switch (event->type) {
case GDK_MOTION_NOTIFY:
diff --git a/chrome/browser/notifications/balloon_collection_mac.mm b/chrome/browser/notifications/balloon_collection_mac.mm
index dc4172d..e3ac179 100644
--- a/chrome/browser/notifications/balloon_collection_mac.mm
+++ b/chrome/browser/notifications/balloon_collection_mac.mm
@@ -4,6 +4,8 @@
#include "chrome/browser/notifications/balloon_collection_impl.h"
+#import <Cocoa/Cocoa.h>
+
#include "chrome/browser/cocoa/notifications/balloon_view_bridge.h"
Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification,
@@ -30,7 +32,15 @@ int BalloonCollectionImpl::Layout::HorizontalEdgeMargin() const {
}
int BalloonCollectionImpl::Layout::VerticalEdgeMargin() const {
- return 5;
+ return 0;
+}
+
+void BalloonCollectionImpl::PositionBalloons(bool reposition) {
+ // Use an animation context so that all the balloons animate together.
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:0.1f];
+ PositionBalloonsInternal(reposition);
+ [NSAnimationContext endGrouping];
}
// static
diff --git a/chrome/browser/notifications/balloon_collection_win.cc b/chrome/browser/notifications/balloon_collection_win.cc
index b5c2351..8915662 100644
--- a/chrome/browser/notifications/balloon_collection_win.cc
+++ b/chrome/browser/notifications/balloon_collection_win.cc
@@ -29,6 +29,10 @@ int BalloonCollectionImpl::Layout::VerticalEdgeMargin() const {
return 0;
}
+void BalloonCollectionImpl::PositionBalloons(bool reposition) {
+ PositionBalloonsInternal(reposition);
+}
+
void BalloonCollectionImpl::DidProcessMessage(const MSG& msg) {
switch (msg.message) {
case WM_MOUSEMOVE:
diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc
index e962f5a..4251086 100644
--- a/chrome/browser/notifications/balloon_host.cc
+++ b/chrome/browser/notifications/balloon_host.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/profile.h"
@@ -23,7 +22,8 @@ BalloonHost::BalloonHost(Balloon* balloon)
: render_view_host_(NULL),
balloon_(balloon),
initialized_(false),
- should_notify_on_disconnect_(false) {
+ should_notify_on_disconnect_(false),
+ enable_dom_ui_(false) {
DCHECK(balloon_);
// If the notification is for an extension URL, make sure to use the extension
@@ -76,14 +76,10 @@ void BalloonHost::RenderViewGone(RenderViewHost* render_view_host) {
Close(render_view_host);
}
-void BalloonHost::ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
+void BalloonHost::ProcessDOMUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {
if (extension_function_dispatcher_.get()) {
- extension_function_dispatcher_->HandleRequest(
- message, content, source_url, request_id, has_callback);
+ extension_function_dispatcher_->HandleRequest(params);
}
}
@@ -97,7 +93,8 @@ void BalloonHost::CreateNewWindow(
route_id,
balloon_->profile(),
site_instance_.get(),
- DOMUIFactory::GetDOMUIType(balloon_->notification().content_url()),
+ DOMUIFactory::GetDOMUIType(balloon_->profile(),
+ balloon_->notification().content_url()),
this,
window_container_type,
frame_name);
@@ -125,6 +122,10 @@ void BalloonHost::UpdatePreferredSize(const gfx::Size& new_size) {
balloon_->SetContentPreferredSize(new_size);
}
+void BalloonHost::HandleMouseDown() {
+ balloon_->OnClick();
+}
+
RendererPreferences BalloonHost::GetRendererPrefs(Profile* profile) const {
RendererPreferences preferences;
renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile);
@@ -133,11 +134,8 @@ RendererPreferences BalloonHost::GetRendererPrefs(Profile* profile) const {
void BalloonHost::Init() {
DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
- int64 session_storage_namespace_id = balloon_->profile()->GetWebKitContext()->
- dom_storage_context()->AllocateSessionStorageNamespaceId();
- RenderViewHost* rvh = new RenderViewHost(site_instance_.get(),
- this, MSG_ROUTING_NONE,
- session_storage_namespace_id);
+ RenderViewHost* rvh = new RenderViewHost(
+ site_instance_.get(), this, MSG_ROUTING_NONE, NULL);
if (GetProfile()->GetExtensionsService()) {
extension_function_dispatcher_.reset(
ExtensionFunctionDispatcher::Create(
@@ -146,6 +144,8 @@ void BalloonHost::Init() {
if (extension_function_dispatcher_.get()) {
rvh->AllowBindings(BindingsPolicy::EXTENSION);
rvh->set_is_extension_process(true);
+ } else if (enable_dom_ui_) {
+ rvh->AllowBindings(BindingsPolicy::DOM_UI);
}
// Do platform-specific initialization.
@@ -154,12 +154,18 @@ void BalloonHost::Init() {
DCHECK(render_widget_host_view());
rvh->set_view(render_widget_host_view());
- rvh->CreateRenderView(GetProfile()->GetRequestContext(), string16());
+ rvh->CreateRenderView(string16());
rvh->NavigateToURL(balloon_->notification().content_url());
initialized_ = true;
}
+void BalloonHost::EnableDOMUI() {
+ DCHECK(render_view_host_ == NULL) <<
+ "EnableDOMUI has to be called before a renderer is created.";
+ enable_dom_ui_ = true;
+}
+
void BalloonHost::NotifyDisconnect() {
if (!should_notify_on_disconnect_)
return;
diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h
index 07ddf3d..fde3bf5 100644
--- a/chrome/browser/notifications/balloon_host.h
+++ b/chrome/browser/notifications/balloon_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOON_HOST_H_
#define CHROME_BROWSER_NOTIFICATIONS_BALLOON_HOST_H_
+#pragma once
#include <string>
@@ -41,11 +42,11 @@ class BalloonHost : public RenderViewHostDelegate,
// TODO(aa): Should this return the native view of the BalloonView*?
return NULL;
}
- virtual TabContents* associated_tab_contents() { return NULL; }
+ virtual TabContents* associated_tab_contents() const { return NULL; }
RenderViewHost* render_view_host() const { return render_view_host_; }
- std::wstring GetSource() const {
+ const string16& GetSource() const {
return balloon_->notification().display_source();
}
@@ -73,11 +74,7 @@ class BalloonHost : public RenderViewHostDelegate,
virtual RenderViewHostDelegate::View* GetViewDelegate() {
return this;
}
- virtual void ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback);
+ virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params);
// RenderViewHostDelegate::View methods. Only the ones for opening new
// windows are currently implemented.
@@ -86,12 +83,15 @@ class BalloonHost : public RenderViewHostDelegate,
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 StartDragging(const WebDropData& drop_data,
WebKit::WebDragOperationsMask allowed_ops) {}
@@ -102,17 +102,27 @@ class BalloonHost : public RenderViewHostDelegate,
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) {
return false;
}
virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
- virtual void HandleMouseEvent() {}
+ virtual void HandleMouseMove() {}
+ virtual void HandleMouseDown();
virtual void HandleMouseLeave() {}
+ virtual void HandleMouseUp() {}
+ virtual void HandleMouseActivate() {}
virtual void UpdatePreferredSize(const gfx::Size& pref_size);
virtual RendererPreferences GetRendererPrefs(Profile* profile) const;
+ // Enable DOM UI. This has to be called before renderer is created.
+ void EnableDOMUI();
+
protected:
+ virtual ~BalloonHost() {}
// Must override in platform specific implementations.
virtual void InitRenderWidgetHostView() = 0;
virtual RenderWidgetHostView* render_widget_host_view() const = 0;
@@ -145,6 +155,9 @@ class BalloonHost : public RenderViewHostDelegate,
// Handles requests to extension APIs. Will only be non-NULL if we are
// rendering a page from an extension.
scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+
+ // A flag to enable DOM UI.
+ bool enable_dom_ui_;
};
#endif // CHROME_BROWSER_NOTIFICATIONS_BALLOON_HOST_H_
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index bc66077..1b3df09 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -6,6 +6,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/histogram.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_child_process_host.h"
@@ -15,18 +16,19 @@
#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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.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"
-#include "chrome/browser/scoped_pref_update.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/worker_host/worker_process_host.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
@@ -117,7 +119,7 @@ class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
public:
NotificationPermissionInfoBarDelegate(TabContents* contents,
const GURL& origin,
- const std::wstring& display_name,
+ const string16& display_name,
int process_id,
int route_id,
int callback_context)
@@ -144,8 +146,9 @@ class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
delete this;
}
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetStringF(IDS_NOTIFICATION_PERMISSIONS, display_name_);
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS,
+ display_name_);
}
virtual SkBitmap* GetIcon() const {
@@ -157,10 +160,10 @@ class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
}
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
return button == BUTTON_OK ?
- l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_YES) :
- l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_NO);
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_PERMISSION_YES) :
+ l10n_util::GetStringUTF16(IDS_NOTIFICATION_PERMISSION_NO);
}
virtual bool Accept() {
@@ -177,13 +180,16 @@ class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
return true;
}
+ // Overridden from InfoBarDelegate:
+ virtual Type GetInfoBarType() { return PAGE_ACTION_TYPE; }
+
private:
// The origin we are asking for permissions on.
GURL origin_;
// The display name for the origin to be displayed. Will be different from
// origin_ for extensions.
- std::wstring display_name_;
+ string16 display_name_;
// The Profile that we restore sessions from.
Profile* profile_;
@@ -204,6 +210,7 @@ DesktopNotificationService::DesktopNotificationService(Profile* profile,
NotificationUIManager* ui_manager)
: profile_(profile),
ui_manager_(ui_manager) {
+ registrar_.Init(profile_->GetPrefs());
InitPrefs();
StartObserving();
}
@@ -248,21 +255,15 @@ void DesktopNotificationService::InitPrefs() {
void DesktopNotificationService::StartObserving() {
if (!profile_->IsOffTheRecord()) {
- PrefService* prefs = profile_->GetPrefs();
- prefs->AddPrefObserver(prefs::kDesktopNotificationDefaultContentSetting,
- this);
- prefs->AddPrefObserver(prefs::kDesktopNotificationAllowedOrigins, this);
- prefs->AddPrefObserver(prefs::kDesktopNotificationDeniedOrigins, this);
+ registrar_.Add(prefs::kDesktopNotificationDefaultContentSetting, this);
+ registrar_.Add(prefs::kDesktopNotificationAllowedOrigins, this);
+ registrar_.Add(prefs::kDesktopNotificationDeniedOrigins, this);
}
}
void DesktopNotificationService::StopObserving() {
if (!profile_->IsOffTheRecord()) {
- PrefService* prefs = profile_->GetPrefs();
- prefs->RemovePrefObserver(prefs::kDesktopNotificationDefaultContentSetting,
- this);
- prefs->RemovePrefObserver(prefs::kDesktopNotificationAllowedOrigins, this);
- prefs->RemovePrefObserver(prefs::kDesktopNotificationDeniedOrigins, this);
+ registrar_.RemoveAll();
}
}
@@ -295,7 +296,7 @@ void DesktopNotificationService::Observe(NotificationType type,
const NotificationDetails& details) {
DCHECK(NotificationType::PREF_CHANGED == type);
PrefService* prefs = profile_->GetPrefs();
- std::wstring* name = Details<std::wstring>(details).ptr();
+ std::string* name = Details<std::string>(details).ptr();
if (0 == name->compare(prefs::kDesktopNotificationAllowedOrigins)) {
std::vector<GURL> allowed_origins(GetAllowedOrigins());
@@ -413,6 +414,13 @@ void DesktopNotificationService::SetDefaultContentSetting(
// The cache is updated through the notification observer.
}
+void DesktopNotificationService::ResetToDefaultContentSetting() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ PrefService* prefs = profile_->GetPrefs();
+ prefs->ClearPref(prefs::kDesktopNotificationDefaultContentSetting);
+}
+
std::vector<GURL> DesktopNotificationService::GetAllowedOrigins() {
std::vector<GURL> allowed_origins;
PrefService* prefs = profile_->GetPrefs();
@@ -514,10 +522,9 @@ void DesktopNotificationService::RequestPermission(
ContentSetting setting = GetContentSetting(origin);
if (setting == CONTENT_SETTING_ASK) {
// Show an info bar requesting permission.
- std::wstring display_name = DisplayNameForOrigin(origin);
-
tab->AddInfoBar(new NotificationPermissionInfoBarDelegate(
- tab, origin, display_name, process_id, route_id, callback_context));
+ tab, origin, DisplayNameForOrigin(origin), process_id,
+ route_id, callback_context));
} else {
// Notify renderer immediately.
ChromeThread::PostTask(
@@ -538,7 +545,7 @@ bool DesktopNotificationService::CancelDesktopNotification(
new NotificationObjectProxy(process_id, route_id, notification_id,
false));
// TODO(johnnyg): clean up this "empty" notification.
- Notification notif(GURL(), GURL(), L"", ASCIIToUTF16(""), proxy);
+ Notification notif(GURL(), GURL(), string16(), string16(), proxy);
return ui_manager_->Cancel(notif);
}
@@ -561,13 +568,14 @@ bool DesktopNotificationService::ShowDesktopNotification(
CreateDataUrl(params.icon_url, params.title, params.body,
params.direction));
}
- Notification notif(
- origin, contents, DisplayNameForOrigin(origin), params.replace_id, proxy);
- ShowNotification(notif);
+ Notification notification(
+ origin, contents, DisplayNameForOrigin(origin),
+ params.replace_id, proxy);
+ ShowNotification(notification);
return true;
}
-std::wstring DesktopNotificationService::DisplayNameForOrigin(
+string16 DesktopNotificationService::DisplayNameForOrigin(
const GURL& origin) {
// If the source is an extension, lookup the display name.
if (origin.SchemeIs(chrome::kExtensionScheme)) {
@@ -575,8 +583,8 @@ std::wstring DesktopNotificationService::DisplayNameForOrigin(
if (ext_service) {
Extension* extension = ext_service->GetExtensionByURL(origin);
if (extension)
- return UTF8ToWide(extension->name());
+ return UTF8ToUTF16(extension->name());
}
}
- return UTF8ToWide(origin.host());
+ return UTF8ToUTF16(origin.host());
}
diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h
index ae38b18..2282cd2 100644
--- a/chrome/browser/notifications/desktop_notification_service.h
+++ b/chrome/browser/notifications/desktop_notification_service.h
@@ -4,11 +4,14 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATION_SERVICE_H_
#define CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATION_SERVICE_H_
+#pragma once
-#include <set>
+#include <vector>
#include "base/basictypes.h"
+#include "base/string16.h"
#include "chrome/browser/notifications/notification.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"
@@ -85,6 +88,9 @@ class DesktopNotificationService : public NotificationObserver {
ContentSetting GetDefaultContentSetting();
void SetDefaultContentSetting(ContentSetting setting);
+ // NOTE: This should only be called on the UI thread.
+ void ResetToDefaultContentSetting();
+
// Returns all origins that explicitly have been allowed.
std::vector<GURL> GetAllowedOrigins();
@@ -101,6 +107,7 @@ class DesktopNotificationService : public NotificationObserver {
void ResetAllOrigins();
static void RegisterUserPrefs(PrefService* user_prefs);
+
private:
void InitPrefs();
void StartObserving();
@@ -115,7 +122,7 @@ class DesktopNotificationService : public NotificationObserver {
// Returns a display name for an origin, to be used in permission infobar
// or on the frame of the notification toast. Different from the origin
// itself when dealing with extensions.
- std::wstring DisplayNameForOrigin(const GURL& origin);
+ string16 DisplayNameForOrigin(const GURL& origin);
ContentSetting GetContentSetting(const GURL& origin);
@@ -130,6 +137,8 @@ class DesktopNotificationService : public NotificationObserver {
// UI for desktop toasts.
NotificationUIManager* ui_manager_;
+ PrefChangeRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(DesktopNotificationService);
};
diff --git a/chrome/browser/notifications/desktop_notification_service_unittest.cc b/chrome/browser/notifications/desktop_notification_service_unittest.cc
index 3af8b0f..f88466b 100644
--- a/chrome/browser/notifications/desktop_notification_service_unittest.cc
+++ b/chrome/browser/notifications/desktop_notification_service_unittest.cc
@@ -7,9 +7,9 @@
#include "base/ref_counted.h"
#include "base/waitable_event.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/browser/scoped_pref_update.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "grit/generated_resources.h"
@@ -24,7 +24,8 @@ class ThreadProxy : public base::RefCountedThreadSafe<ThreadProxy> {
public:
ThreadProxy()
: io_event_(false, false),
- ui_event_(false, false) {
+ ui_event_(false, false),
+ permission_(0) {
// The current message loop was already initalized by the test superclass.
ui_thread_.reset(
new ChromeThread(ChromeThread::UI, MessageLoop::current()));
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc
index 34746d1..d324b6a 100644
--- a/chrome/browser/notifications/desktop_notifications_unittest.cc
+++ b/chrome/browser/notifications/desktop_notifications_unittest.cc
@@ -6,6 +6,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/common/render_messages_params.h"
// static
const int MockBalloonCollection::kMockBalloonSpace = 5;
@@ -268,25 +269,27 @@ TEST_F(DesktopNotificationsTest, TestQueueing) {
// Cancel the notifications from the start; the balloon space should
// remain full.
- int id;
- for (id = 1;
- id <= kLotsOfToasts - balloon_collection_->max_balloon_count();
- ++id) {
- service_->CancelDesktopNotification(process_id, route_id, id);
- MessageLoopForUI::current()->RunAllPending();
- expected_log.append("notification closed by script\n");
- expected_log.append("notification displayed\n");
- EXPECT_EQ(balloon_collection_->max_balloon_count(),
- balloon_collection_->count());
- EXPECT_EQ(expected_log, log_output_);
- }
+ {
+ int id;
+ for (id = 1;
+ id <= kLotsOfToasts - balloon_collection_->max_balloon_count();
+ ++id) {
+ service_->CancelDesktopNotification(process_id, route_id, id);
+ MessageLoopForUI::current()->RunAllPending();
+ expected_log.append("notification closed by script\n");
+ expected_log.append("notification displayed\n");
+ EXPECT_EQ(balloon_collection_->max_balloon_count(),
+ balloon_collection_->count());
+ EXPECT_EQ(expected_log, log_output_);
+ }
- // Now cancel the rest. It should empty the balloon space.
- for (; id <= kLotsOfToasts; ++id) {
- service_->CancelDesktopNotification(process_id, route_id, id);
- expected_log.append("notification closed by script\n");
- MessageLoopForUI::current()->RunAllPending();
- EXPECT_EQ(expected_log, log_output_);
+ // Now cancel the rest. It should empty the balloon space.
+ for (; id <= kLotsOfToasts; ++id) {
+ service_->CancelDesktopNotification(process_id, route_id, id);
+ expected_log.append("notification closed by script\n");
+ MessageLoopForUI::current()->RunAllPending();
+ EXPECT_EQ(expected_log, log_output_);
+ }
}
// Verify that the balloon collection is now empty.
diff --git a/chrome/browser/notifications/desktop_notifications_unittest.h b/chrome/browser/notifications/desktop_notifications_unittest.h
index 56a2a6b..ab3ad63 100644
--- a/chrome/browser/notifications/desktop_notifications_unittest.h
+++ b/chrome/browser/notifications/desktop_notifications_unittest.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATIONS_UNITTEST_H_
#define CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATIONS_UNITTEST_H_
+#pragma once
#include <deque>
#include <string>
#include "base/message_loop.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/notifications/balloon_collection_impl.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h
index bdad291..f8ab903 100644
--- a/chrome/browser/notifications/notification.h
+++ b/chrome/browser/notifications/notification.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/notifications/notification_object_proxy.h"
@@ -16,9 +17,8 @@ class NotificationDelegate;
// data: URLs representing simple text+icon notifications.
class Notification {
public:
- // TODO: http://crbug.com/43899 Convert this class to string16.
Notification(const GURL& origin_url, const GURL& content_url,
- const std::wstring& display_source,
+ const string16& display_source,
const string16& replace_id,
NotificationDelegate* delegate)
: origin_url_(origin_url),
@@ -51,12 +51,13 @@ class Notification {
const GURL& origin_url() const { return origin_url_; }
// A display string for the source of the notification.
- const std::wstring& display_source() const { return display_source_; }
+ const string16& display_source() const { return display_source_; }
const string16& replace_id() const { return replace_id_; }
void Display() const { delegate()->Display(); }
void Error() const { delegate()->Error(); }
+ void Click() const { delegate()->Click(); }
void Close(bool by_user) const { delegate()->Close(by_user); }
bool IsSame(const Notification& other) const {
@@ -75,7 +76,7 @@ class Notification {
// The display string for the source of the notification. Could be
// the same as origin_url_, or the name of an extension.
- std::wstring display_source_;
+ string16 display_source_;
// The replace ID for the notification.
string16 replace_id_;
diff --git a/chrome/browser/notifications/notification_delegate.h b/chrome/browser/notifications/notification_delegate.h
index 6d69335..53226e5 100644
--- a/chrome/browser/notifications/notification_delegate.h
+++ b/chrome/browser/notifications/notification_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_DELEGATE_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_DELEGATE_H_
+#pragma once
#include <string>
@@ -15,7 +16,6 @@
class NotificationDelegate
: public base::RefCountedThreadSafe<NotificationDelegate> {
public:
-
// To be called when the desktop notification is actually shown.
virtual void Display() = 0;
@@ -27,8 +27,17 @@ class NotificationDelegate
// user explicitly (as opposed to timeout/script), |by_user| should be true.
virtual void Close(bool by_user) = 0;
+ // To be called when a desktop notification is clicked.
+ virtual void Click() = 0;
+
// Returns unique id of the notification.
virtual std::string id() const = 0;
+
+ protected:
+ virtual ~NotificationDelegate() {}
+
+ private:
+ friend class base::RefCountedThreadSafe<NotificationDelegate>;
};
#endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_DELEGATE_H_
diff --git a/chrome/browser/notifications/notification_exceptions_table_model.cc b/chrome/browser/notifications/notification_exceptions_table_model.cc
index fdb08f4..2627025 100644
--- a/chrome/browser/notifications/notification_exceptions_table_model.cc
+++ b/chrome/browser/notifications/notification_exceptions_table_model.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/notifications/notification_exceptions_table_model.h"
#include "app/l10n_util.h"
-#include "app/l10n_util_collator.h"
#include "app/table_model_observer.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/content_settings_helper.h"
diff --git a/chrome/browser/notifications/notification_exceptions_table_model.h b/chrome/browser/notifications/notification_exceptions_table_model.h
index 01137f7..bef1fee 100644
--- a/chrome/browser/notifications/notification_exceptions_table_model.h
+++ b/chrome/browser/notifications/notification_exceptions_table_model.h
@@ -4,8 +4,9 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_EXCEPTIONS_TABLE_MODEL_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_EXCEPTIONS_TABLE_MODEL_H_
+#pragma once
-#include <set>
+#include <string>
#include <vector>
#include "chrome/browser/notifications/desktop_notification_service.h"
diff --git a/chrome/browser/notifications/notification_exceptions_table_model_unittest.cc b/chrome/browser/notifications/notification_exceptions_table_model_unittest.cc
index 6919b0b..5a650ae 100644
--- a/chrome/browser/notifications/notification_exceptions_table_model_unittest.cc
+++ b/chrome/browser/notifications/notification_exceptions_table_model_unittest.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/notifications/notification_exceptions_table_model.h"
#include "app/l10n_util.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/test/testing_profile.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/notifications/notification_object_proxy.cc b/chrome/browser/notifications/notification_object_proxy.cc
index 76363e5..edf35df 100644
--- a/chrome/browser/notifications/notification_object_proxy.cc
+++ b/chrome/browser/notifications/notification_object_proxy.cc
@@ -49,6 +49,15 @@ void NotificationObjectProxy::Close(bool by_user) {
}
}
+void NotificationObjectProxy::Click() {
+ if (worker_) {
+ NOTREACHED();
+ } else {
+ DeliverMessage(new ViewMsg_PostClickToNotificationObject(
+ route_id_, notification_id_));
+ }
+}
+
std::string NotificationObjectProxy::id() const {
return StringPrintf("%d:%d:%d:%d", process_id_, route_id_,
notification_id_, worker_);
diff --git a/chrome/browser/notifications/notification_object_proxy.h b/chrome/browser/notifications/notification_object_proxy.h
index a956b3a..c3cb777 100644
--- a/chrome/browser/notifications/notification_object_proxy.h
+++ b/chrome/browser/notifications/notification_object_proxy.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OBJECT_PROXY_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OBJECT_PROXY_H_
+#pragma once
#include <string>
@@ -29,6 +30,7 @@ class NotificationObjectProxy
virtual void Display();
virtual void Error();
virtual void Close(bool by_user);
+ virtual void Click();
virtual std::string id() const;
protected:
diff --git a/chrome/browser/notifications/notification_options_menu_model.cc b/chrome/browser/notifications/notification_options_menu_model.cc
index 66379fa..209a578 100644
--- a/chrome/browser/notifications/notification_options_menu_model.cc
+++ b/chrome/browser/notifications/notification_options_menu_model.cc
@@ -7,7 +7,6 @@
#include "app/l10n_util.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
-#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
@@ -36,7 +35,7 @@ NotificationOptionsMenuModel::NotificationOptionsMenuModel(Balloon* balloon)
} else {
const string16 disable_label = l10n_util::GetStringFUTF16(
IDS_NOTIFICATION_BALLOON_REVOKE_MESSAGE,
- WideToUTF16(notification.display_source()));
+ notification.display_source());
AddItem(kRevokePermissionCommand, disable_label);
}
diff --git a/chrome/browser/notifications/notification_options_menu_model.h b/chrome/browser/notifications/notification_options_menu_model.h
index 751c799..2044da5 100644
--- a/chrome/browser/notifications/notification_options_menu_model.h
+++ b/chrome/browser/notifications/notification_options_menu_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OPTIONS_MENU_MODEL_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OPTIONS_MENU_MODEL_H_
+#pragma once
#include "app/menus/simple_menu_model.h"
#include "chrome/browser/notifications/balloon.h"
diff --git a/chrome/browser/notifications/notification_test_util.h b/chrome/browser/notifications/notification_test_util.h
index d3ad7ee..b2f0c34 100644
--- a/chrome/browser/notifications/notification_test_util.h
+++ b/chrome/browser/notifications/notification_test_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_TEST_UTIL_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_TEST_UTIL_H_
+#pragma once
#include "chrome/browser/notifications/notification_object_proxy.h"
#include "chrome/browser/notifications/balloon.h"
diff --git a/chrome/browser/notifications/notification_ui_manager.h b/chrome/browser/notifications/notification_ui_manager.h
index e510e7f..10687a9 100644
--- a/chrome/browser/notifications/notification_ui_manager.h
+++ b/chrome/browser/notifications/notification_ui_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_UI_MANAGER_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_UI_MANAGER_H_
+#pragma once
#include <deque>
diff --git a/chrome/browser/notifications/notifications_interactive_uitest.cc b/chrome/browser/notifications/notifications_interactive_uitest.cc
index d8e4b27..afd44d7 100644
--- a/chrome/browser/notifications/notifications_interactive_uitest.cc
+++ b/chrome/browser/notifications/notifications_interactive_uitest.cc
@@ -1,14 +1,13 @@
-// 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.
-#include "base/file_path.h"
#include "chrome/common/chrome_switches.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"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
class NotificationsPermissionTest : public UITest {
public:
@@ -19,17 +18,16 @@ class NotificationsPermissionTest : public UITest {
};
TEST_F(NotificationsPermissionTest, TestUserGestureInfobar) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(server.get() != NULL);
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
scoped_refptr<TabProxy> tab(browser->GetActiveTab());
ASSERT_TRUE(tab.get());
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
- tab->NavigateToURL(server->TestServerPage(
+ tab->NavigateToURL(test_server.GetURL(
"files/notifications/notifications_request_function.html")));
WaitUntilTabCount(1);
@@ -42,14 +40,13 @@ TEST_F(NotificationsPermissionTest, TestUserGestureInfobar) {
&result));
EXPECT_TRUE(result);
- EXPECT_TRUE(tab->WaitForInfoBarCount(1, action_max_timeout_ms()));
+ EXPECT_TRUE(tab->WaitForInfoBarCount(1));
}
TEST_F(NotificationsPermissionTest, TestNoUserGestureInfobar) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(server.get() != NULL);
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
@@ -59,7 +56,7 @@ TEST_F(NotificationsPermissionTest, TestNoUserGestureInfobar) {
// Load a page which just does a request; no user gesture should result
// in no infobar.
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
- tab->NavigateToURL(server->TestServerPage(
+ tab->NavigateToURL(test_server.GetURL(
"files/notifications/notifications_request_inline.html")));
WaitUntilTabCount(1);
diff --git a/chrome/browser/notifications/notifications_prefs_cache.cc b/chrome/browser/notifications/notifications_prefs_cache.cc
index 2fec1e8..8603d9e 100644
--- a/chrome/browser/notifications/notifications_prefs_cache.cc
+++ b/chrome/browser/notifications/notifications_prefs_cache.cc
@@ -7,7 +7,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "third_party/WebKit/WebKit/chromium/public/WebNotificationPresenter.h"
NotificationsPrefsCache::NotificationsPrefsCache()
@@ -55,10 +55,10 @@ void NotificationsPrefsCache::ListValueToGurlVector(
const ListValue& origin_list,
std::vector<GURL>* origin_vector) {
ListValue::const_iterator i;
- std::wstring origin;
+ std::string origin;
for (i = origin_list.begin(); i != origin_list.end(); ++i) {
(*i)->GetAsString(&origin);
- origin_vector->push_back(GURL(WideToUTF8(origin)));
+ origin_vector->push_back(GURL(origin));
}
}
diff --git a/chrome/browser/notifications/notifications_prefs_cache.h b/chrome/browser/notifications/notifications_prefs_cache.h
index 61bb983..758f0f7 100644
--- a/chrome/browser/notifications/notifications_prefs_cache.h
+++ b/chrome/browser/notifications/notifications_prefs_cache.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATIONS_PREFS_CACHE_H_
#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATIONS_PREFS_CACHE_H_
+#pragma once
#include <set>
#include <vector>
diff --git a/chrome/browser/ntp_background_util.cc b/chrome/browser/ntp_background_util.cc
index b36ce9f..b3926d5 100644
--- a/chrome/browser/ntp_background_util.cc
+++ b/chrome/browser/ntp_background_util.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/ntp_background_util.h"
#include "base/logging.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "gfx/canvas.h"
#include "gfx/rect.h"
#include "gfx/skia_util.h"
diff --git a/chrome/browser/ntp_background_util.h b/chrome/browser/ntp_background_util.h
index 9d2d656..a4fa544 100644
--- a/chrome/browser/ntp_background_util.h
+++ b/chrome/browser/ntp_background_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_NTP_BACKGROUND_UTIL_H_
#define CHROME_BROWSER_NTP_BACKGROUND_UTIL_H_
+#pragma once
class ThemeProvider;
diff --git a/chrome/browser/omnibox_search_hint.cc b/chrome/browser/omnibox_search_hint.cc
index c54794c..1a91efe 100644
--- a/chrome/browser/omnibox_search_hint.cc
+++ b/chrome/browser/omnibox_search_hint.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/omnibox_search_hint.h"
-#include "app/animation.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/command_line.h"
@@ -15,8 +14,9 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/location_bar.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.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/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -71,8 +71,8 @@ class HintInfoBar : public ConfirmInfoBarDelegate {
omnibox_hint_->DisableHint();
}
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetString(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT);
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_TEXT);
}
virtual SkBitmap* GetIcon() const {
@@ -84,13 +84,12 @@ class HintInfoBar : public ConfirmInfoBarDelegate {
return BUTTON_OK;
}
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
- return l10n_util::GetString(IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL);
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
+ return l10n_util::GetStringUTF16(
+ IDS_OMNIBOX_SEARCH_HINT_INFOBAR_BUTTON_LABEL);
}
- virtual Type GetInfoBarType() {
- return INFO_TYPE;
- }
+ virtual Type GetInfoBarType() { return PAGE_ACTION_TYPE; }
virtual bool Accept() {
action_taken_ = true;
diff --git a/chrome/browser/omnibox_search_hint.h b/chrome/browser/omnibox_search_hint.h
index 456e968..a0dd25a 100644
--- a/chrome/browser/omnibox_search_hint.h
+++ b/chrome/browser/omnibox_search_hint.h
@@ -1,14 +1,14 @@
-// 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.
#ifndef CHROME_BROWSER_OMNIBOX_SEARCH_HINT_H_
#define CHROME_BROWSER_OMNIBOX_SEARCH_HINT_H_
+#pragma once
#include <map>
#include <string>
-#include "base/scoped_ptr.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/options_page_base.cc b/chrome/browser/options_page_base.cc
index 260fb5b..6ee5610 100644
--- a/chrome/browser/options_page_base.cc
+++ b/chrome/browser/options_page_base.cc
@@ -1,11 +1,11 @@
-// 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.
#include "chrome/browser/options_page_base.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/notification_service.h"
///////////////////////////////////////////////////////////////////////////////
@@ -32,5 +32,5 @@ void OptionsPageBase::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED)
- NotifyPrefChanged(Details<std::wstring>(details).ptr());
+ NotifyPrefChanged(Details<std::string>(details).ptr());
}
diff --git a/chrome/browser/options_page_base.h b/chrome/browser/options_page_base.h
index 513b13a..0e6c756 100644
--- a/chrome/browser/options_page_base.h
+++ b/chrome/browser/options_page_base.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_OPTIONS_PAGE_BASE_H_
#define CHROME_BROWSER_OPTIONS_PAGE_BASE_H_
+#pragma once
#include <string>
@@ -49,7 +50,7 @@ class OptionsPageBase : public NotificationObserver {
// 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::wstring* pref_name) { }
+ virtual void NotifyPrefChanged(const std::string* pref_name) {}
private:
// The Profile associated with this page.
diff --git a/chrome/browser/options_util.cc b/chrome/browser/options_util.cc
index 8bcf063..97f0012 100644
--- a/chrome/browser/options_util.cc
+++ b/chrome/browser/options_util.cc
@@ -5,13 +5,15 @@
#include "chrome/browser/options_util.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profile.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/pref_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"
@@ -21,9 +23,10 @@ void OptionsUtil::ResetToDefaults(Profile* profile) {
// changes to any of the options pages doesn't require updating this list
// manually.
PrefService* prefs = profile->GetPrefs();
- const wchar_t* kUserPrefs[] = {
+ const char* kUserPrefs[] = {
prefs::kAcceptLanguages,
prefs::kAlternateErrorPagesEnabled,
+ prefs::kBackgroundModeEnabled,
prefs::kClearSiteDataOnExit,
prefs::kCookieBehavior,
prefs::kDefaultCharset,
@@ -36,8 +39,6 @@ void OptionsUtil::ResetToDefaults(Profile* profile) {
#endif
#if defined(OS_CHROMEOS)
prefs::kTapToClickEnabled,
- prefs::kVertEdgeScrollEnabled,
- prefs::kTouchpadSpeedFactor,
prefs::kTouchpadSensitivity,
#endif
prefs::kDownloadDefaultDirectory,
@@ -45,6 +46,7 @@ void OptionsUtil::ResetToDefaults(Profile* profile) {
prefs::kEnableSpellCheck,
prefs::kEnableTranslate,
prefs::kAutoFillEnabled,
+ prefs::kAutoFillAuxiliaryProfilesEnabled,
prefs::kHomePage,
prefs::kHomePageIsNewTabPage,
prefs::kPromptForDownload,
@@ -66,10 +68,11 @@ void OptionsUtil::ResetToDefaults(Profile* profile) {
prefs::kWebKitSerifFontFamily,
prefs::kWebkitTabsToLinks,
};
- profile->GetDownloadManager()->ResetAutoOpenFiles();
+ 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]);
@@ -81,7 +84,7 @@ void OptionsUtil::ResetToDefaults(Profile* profile) {
// 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 wchar_t* kLocalStatePrefs[] = {
+ const char* kLocalStatePrefs[] = {
prefs::kApplicationLocale,
};
for (size_t i = 0; i < arraysize(kLocalStatePrefs); ++i)
diff --git a/chrome/browser/options_util.h b/chrome/browser/options_util.h
index 9bfc6fc..3dd10cf 100644
--- a/chrome/browser/options_util.h
+++ b/chrome/browser/options_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_OPTIONS_UTIL_H_
#define CHROME_BROWSER_OPTIONS_UTIL_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/options_window.h b/chrome/browser/options_window.h
index a54e7b9..53292bd 100644
--- a/chrome/browser/options_window.h
+++ b/chrome/browser/options_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_OPTIONS_WINDOW_H__
#define CHROME_BROWSER_OPTIONS_WINDOW_H__
+#pragma once
class Profile;
diff --git a/chrome/browser/page_info_model.cc b/chrome/browser/page_info_model.cc
index aed8b23..6fc7443 100644
--- a/chrome/browser/page_info_model.cc
+++ b/chrome/browser/page_info_model.cc
@@ -7,13 +7,15 @@
#include <string>
#include "app/l10n_util.h"
-#include "base/callback.h"
+#include "base/command_line.h"
#include "base/i18n/time_formatting.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/cert_store.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/ssl/ssl_manager.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "net/base/cert_status_flags.h"
@@ -21,29 +23,14 @@
#include "net/base/ssl_cipher_suite_names.h"
#include "net/base/x509_certificate.h"
-namespace {
- // Returns a name that can be used to represent the issuer. It tries in this
- // order CN, O and OU and returns the first non-empty one found.
- std::string GetIssuerName(const net::CertPrincipal& issuer) {
- if (!issuer.common_name.empty())
- return issuer.common_name;
- if (!issuer.organization_names.empty())
- return issuer.organization_names[0];
- if (!issuer.organization_unit_names.empty())
- return issuer.organization_unit_names[0];
-
- return std::string();
- }
-}
-
PageInfoModel::PageInfoModel(Profile* profile,
const GURL& url,
const NavigationEntry::SSLStatus& ssl,
bool show_history,
PageInfoModelObserver* observer)
: observer_(observer) {
- bool state = true;
- string16 head_line;
+ SectionInfoState state = SECTION_STATE_OK;
+ string16 headline;
string16 description;
scoped_refptr<net::X509Certificate> cert;
@@ -55,13 +42,43 @@ PageInfoModel::PageInfoModel(Profile* profile,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
empty_subject_name = true;
}
+
+ // Some of what IsCertStatusError classifies as errors we want to show as
+ // warnings instead.
+ static const int cert_warnings =
+ net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION |
+ net::CERT_STATUS_NO_REVOCATION_MECHANISM;
+ int status_with_warnings_removed = ssl.cert_status() & ~cert_warnings;
+
if (ssl.cert_id() &&
CertStore::GetSharedInstance()->RetrieveCert(ssl.cert_id(), &cert) &&
- !net::IsCertStatusError(ssl.cert_status())) {
- // OK HTTPS page.
- if ((ssl.cert_status() & net::CERT_STATUS_IS_EV) != 0) {
+ !net::IsCertStatusError(status_with_warnings_removed)) {
+ // No error found so far, check cert_status warnings.
+ int cert_status = ssl.cert_status();
+ if (cert_status & cert_warnings) {
+ string16 issuer_name(UTF8ToUTF16(cert->issuer().GetDisplayName()));
+ if (issuer_name.empty()) {
+ issuer_name.assign(l10n_util::GetStringUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
+ }
+ description.assign(l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name));
+
+ description += ASCIIToUTF16("\n\n");
+ if (cert_status & net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) {
+ description += l10n_util::GetStringUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION);
+ } else if (cert_status & net::CERT_STATUS_NO_REVOCATION_MECHANISM) {
+ description += l10n_util::GetStringUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM);
+ } else {
+ NOTREACHED() << "Need to specify string for this warning";
+ }
+ state = SECTION_STATE_WARNING_MINOR;
+ } else if ((ssl.cert_status() & net::CERT_STATUS_IS_EV) != 0) {
+ // EV HTTPS page.
DCHECK(!cert->subject().organization_names.empty());
- head_line =
+ headline =
l10n_util::GetStringFUTF16(IDS_PAGE_INFO_EV_IDENTITY_TITLE,
UTF8ToUTF16(cert->subject().organization_names[0]),
UTF8ToUTF16(url.host()));
@@ -87,48 +104,61 @@ PageInfoModel::PageInfoModel(Profile* profile,
IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV,
UTF8ToUTF16(cert->subject().organization_names[0]),
locality,
- UTF8ToUTF16(GetIssuerName(cert->issuer()))));
+ UTF8ToUTF16(cert->issuer().GetDisplayName())));
+ } else if ((ssl.cert_status() & net::CERT_STATUS_IS_DNSSEC) != 0) {
+ // DNSSEC authenticated page.
+ if (empty_subject_name)
+ headline.clear(); // Don't display any title.
+ else
+ headline.assign(subject_name);
+ description.assign(l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, UTF8ToUTF16("DNSSEC")));
} else {
- // Non EV OK HTTPS.
+ // Non-EV OK HTTPS page.
if (empty_subject_name)
- head_line.clear(); // Don't display any title.
+ headline.clear(); // Don't display any title.
else
- head_line.assign(subject_name);
- string16 issuer_name(UTF8ToUTF16(GetIssuerName(cert->issuer())));
+ headline.assign(subject_name);
+ string16 issuer_name(UTF8ToUTF16(cert->issuer().GetDisplayName()));
if (issuer_name.empty()) {
issuer_name.assign(l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
- } else {
- description.assign(l10n_util::GetStringFUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name));
}
+ description.assign(l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name));
}
} else {
- // HTTP or bad HTTPS.
+ // HTTP or HTTPS with errors (not warnings).
description.assign(l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY));
- state = false;
+ state = ssl.security_style() == SECURITY_STYLE_UNAUTHENTICATED ?
+ SECTION_STATE_WARNING_MAJOR : SECTION_STATE_ERROR;
}
sections_.push_back(SectionInfo(
state,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_IDENTITY_TITLE),
- head_line,
- description));
+ headline,
+ description,
+ SECTION_INFO_IDENTITY));
// Connection section.
// We consider anything less than 80 bits encryption to be weak encryption.
// TODO(wtc): Bug 1198735: report mixed/unsafe content for unencrypted and
// weakly encrypted connections.
- state = true;
- head_line.clear();
+ state = SECTION_STATE_OK;
+ headline.clear();
description.clear();
- if (ssl.security_bits() <= 0) {
- state = false;
+ if (ssl.security_bits() < 0) {
+ // Security strength is unknown. Say nothing.
+ state = SECTION_STATE_ERROR;
+ } else if (ssl.security_bits() == 0) {
+ state = ssl.security_style() == SECURITY_STYLE_UNAUTHENTICATED ?
+ SECTION_STATE_WARNING_MAJOR : SECTION_STATE_ERROR;
description.assign(l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
subject_name));
} else if (ssl.security_bits() < 80) {
- state = false;
+ state = SECTION_STATE_ERROR;
description.assign(l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT,
subject_name));
@@ -136,9 +166,20 @@ PageInfoModel::PageInfoModel(Profile* profile,
description.assign(l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
subject_name,
- IntToString16(ssl.security_bits())));
+ base::IntToString16(ssl.security_bits())));
if (ssl.displayed_insecure_content() || ssl.ran_insecure_content()) {
- state = false;
+ // The old SSL dialog only had good and bad state, so for the old
+ // implementation we raise an error on finding mixed content. The new
+ // SSL info bubble has a warning state for displaying insecure content,
+ // so we check. The command line check will go away once we eliminate
+ // the old dialogs.
+ const CommandLine* command_line(CommandLine::ForCurrentProcess());
+ if (command_line->HasSwitch(switches::kEnableNewPageInfoBubble) &&
+ !ssl.ran_insecure_content()) {
+ state = SECTION_STATE_WARNING_MINOR;
+ } else {
+ state = SECTION_STATE_ERROR;
+ }
description.assign(l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK,
description,
@@ -153,8 +194,9 @@ PageInfoModel::PageInfoModel(Profile* profile,
if (ssl.security_bits() > 0 && cipher_suite) {
bool did_fallback = (ssl.connection_status() &
net::SSL_CONNECTION_SSL3_FALLBACK) != 0;
- bool no_renegotiation = (ssl.connection_status() &
- net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0;
+ bool no_renegotiation =
+ (ssl.connection_status() &
+ net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0;
const char *key_exchange, *cipher, *mac;
net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, cipher_suite);
@@ -179,7 +221,7 @@ PageInfoModel::PageInfoModel(Profile* profile,
if (did_fallback) {
// For now, only SSLv3 fallback will trigger a warning icon.
- state = false;
+ state = SECTION_STATE_ERROR;
description += ASCIIToUTF16("\n\n");
description += l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_FALLBACK_MESSAGE);
@@ -191,11 +233,14 @@ PageInfoModel::PageInfoModel(Profile* profile,
}
}
- sections_.push_back(SectionInfo(
- state,
- l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_CONNECTION_TITLE),
- head_line,
- description));
+ if (!description.empty()) {
+ sections_.push_back(SectionInfo(
+ state,
+ l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_CONNECTION_TITLE),
+ headline,
+ description,
+ SECTION_INFO_CONNECTION));
+ }
// Request the number of visits.
HistoryService* history = profile->GetHistoryService(
@@ -208,6 +253,9 @@ PageInfoModel::PageInfoModel(Profile* profile,
}
}
+PageInfoModel::~PageInfoModel() {
+}
+
int PageInfoModel::GetSectionCount() {
return sections_.size();
}
@@ -233,23 +281,31 @@ void PageInfoModel::OnGotVisitCountToHost(HistoryService::Handle handle,
visited_before_today = (first_visit_midnight < today);
}
+ // We only show the Site Information heading for the new dialogs.
+ string16 title;
+ const CommandLine* command_line(CommandLine::ForCurrentProcess());
+ if (command_line->HasSwitch(switches::kEnableNewPageInfoBubble))
+ title = l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE);
+
if (!visited_before_today) {
sections_.push_back(SectionInfo(
- false,
+ SECTION_STATE_ERROR,
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_PERSONAL_HISTORY_TITLE),
- string16(),
+ title,
l10n_util::GetStringUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY)));
+ IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY),
+ SECTION_INFO_FIRST_VISIT));
} else {
sections_.push_back(SectionInfo(
- true,
+ SECTION_STATE_OK,
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_PERSONAL_HISTORY_TITLE),
- string16(),
+ title,
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_VISITED_BEFORE_TODAY,
- WideToUTF16(base::TimeFormatShortDate(first_visit)))));
+ WideToUTF16(base::TimeFormatShortDate(first_visit))),
+ SECTION_INFO_FIRST_VISIT));
}
observer_->ModelChanged();
}
@@ -258,3 +314,6 @@ void PageInfoModel::OnGotVisitCountToHost(HistoryService::Handle handle,
void PageInfoModel::RegisterPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(prefs::kPageInfoWindowPlacement);
}
+
+PageInfoModel::PageInfoModel() {
+}
diff --git a/chrome/browser/page_info_model.h b/chrome/browser/page_info_model.h
index a3bee79..1f9942f 100644
--- a/chrome/browser/page_info_model.h
+++ b/chrome/browser/page_info_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PAGE_INFO_MODEL_H_
#define CHROME_BROWSER_PAGE_INFO_MODEL_H_
+#pragma once
#include <vector>
@@ -17,36 +18,61 @@ class PrefService;
class Profile;
// The model that provides the information that should be displayed in the page
-// info dialog.
+// info dialog/bubble.
class PageInfoModel {
public:
class PageInfoModelObserver {
- public:
- virtual void ModelChanged() = 0;
+ public:
+ virtual void ModelChanged() = 0;
+
+ protected:
+ virtual ~PageInfoModelObserver() {}
+ };
+
+ enum SectionInfoType {
+ SECTION_INFO_IDENTITY = 0,
+ SECTION_INFO_CONNECTION,
+ SECTION_INFO_FIRST_VISIT,
+ };
+
+ enum SectionInfoState {
+ SECTION_STATE_OK = 0,
+ // For example, if state is OK but contains mixed content.
+ SECTION_STATE_WARNING_MINOR,
+ // For example, if content was served over HTTP.
+ SECTION_STATE_WARNING_MAJOR,
+ // For example, unverified identity over HTTPS.
+ SECTION_STATE_ERROR,
};
struct SectionInfo {
- SectionInfo(bool state,
+ SectionInfo(SectionInfoState state,
const string16& title,
- const string16& head_line,
- const string16& description)
+ const string16& headline,
+ const string16& description,
+ SectionInfoType type)
: state(state),
title(title),
- head_line(head_line),
- description(description) {
+ headline(headline),
+ description(description),
+ type(type) {
}
- bool state; // True if state is OK, false otherwise (ex of bad states:
- // unverified identity over HTTPS).
+ // The overall state of the connection (error, warning, ok).
+ SectionInfoState state;
// The title of the section.
string16 title;
// A single line describing the section, optional.
- string16 head_line;
+ string16 headline;
// The full description of what this section is.
string16 description;
+
+ // The type of SectionInfo we are dealing with, for example: Identity,
+ // Connection, First Visit.
+ SectionInfoType type;
};
PageInfoModel(Profile* profile,
@@ -54,6 +80,7 @@ class PageInfoModel {
const NavigationEntry::SSLStatus& ssl,
bool show_history,
PageInfoModelObserver* observer);
+ ~PageInfoModel();
int GetSectionCount();
SectionInfo GetSectionInfo(int index);
@@ -68,7 +95,7 @@ class PageInfoModel {
protected:
// Testing constructor. DO NOT USE.
- PageInfoModel() {}
+ PageInfoModel();
PageInfoModelObserver* observer_;
diff --git a/chrome/browser/page_info_window.h b/chrome/browser/page_info_window.h
index 668a6e9..497f2ea 100644
--- a/chrome/browser/page_info_window.h
+++ b/chrome/browser/page_info_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PAGE_INFO_WINDOW_H_
#define CHROME_BROWSER_PAGE_INFO_WINDOW_H_
+#pragma once
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "gfx/native_widget_types.h"
@@ -23,6 +24,12 @@ void ShowPageInfo(gfx::NativeWindow parent,
const NavigationEntry::SSLStatus& ssl,
bool show_history);
+void ShowPageInfoBubble(gfx::NativeWindow parent,
+ Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history);
+
} // namespace browser
#endif // CHROME_BROWSER_PAGE_INFO_WINDOW_H_
diff --git a/chrome/browser/page_state.cc b/chrome/browser/page_state.cc
deleted file mode 100644
index bf431ca..0000000
--- a/chrome/browser/page_state.cc
+++ /dev/null
@@ -1,111 +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 <string>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/page_state.h"
-#include "chrome/common/json_value_serializer.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/escape.h"
-
-void PageState::InitWithURL(const GURL& url) {
- // Reset our state
- state_.reset(new DictionaryValue);
-
- std::string query_string = url.query();
- if (query_string.empty())
- return;
-
- url_parse::Component queryComp, keyComp, valueComp;
- queryComp.len = static_cast<int>(query_string.size());
- while (url_parse::ExtractQueryKeyValue(query_string.c_str(), &queryComp,
- &keyComp, &valueComp)) {
- if (keyComp.is_nonempty()) {
- std::string escaped = query_string.substr(valueComp.begin,
- valueComp.len);
- // We know that the query string is UTF-8 since it's an internal URL.
- std::wstring value = UTF8ToWide(
- UnescapeURLComponent(escaped, UnescapeRule::REPLACE_PLUS_WITH_SPACE));
- state_->Set(UTF8ToWide(query_string.substr(keyComp.begin, keyComp.len)),
- new StringValue(value));
- }
- }
-}
-
-void PageState::InitWithBytes(const std::string& bytes) {
- // Reset our state. We create a new empty one just in case
- // deserialization fails
- state_.reset(new DictionaryValue);
-
- JSONStringValueSerializer serializer(bytes);
- scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));
-
- if (!root.get()) {
- NOTREACHED();
- return;
- }
-
- if (root->GetType() == Value::TYPE_DICTIONARY)
- state_.reset(static_cast<DictionaryValue*>(root.release()));
-}
-
-void PageState::GetByteRepresentation(std::string* out) const {
- JSONStringValueSerializer serializer(out);
- if (!serializer.Serialize(*state_))
- NOTREACHED();
-}
-
-void PageState::SetProperty(const std::wstring& key,
- const std::wstring& value) {
- state_->Set(key, new StringValue(value));
-}
-
-bool PageState::GetProperty(const std::wstring& key,
- std::wstring* value) const {
- if (state_->HasKey(key)) {
- Value* v;
- state_->Get(key, &v);
- if (v->GetType() == Value::TYPE_STRING) {
- StringValue* sv = reinterpret_cast<StringValue*>(v);
- sv->GetAsString(value);
- return true;
- }
- }
- return false;
-}
-
-void PageState::SetInt64Property(const std::wstring& key, int64 value) {
- SetProperty(key, Int64ToWString(value));
-}
-
-bool PageState::GetInt64Property(const std::wstring& key, int64* value) const {
- std::wstring v;
- if (GetProperty(key, &v)) {
- return StringToInt64(WideToUTF16Hack(v), value);
- }
- return false;
-}
-
-void PageState::SetIntProperty(const std::wstring& key, int value) {
- SetProperty(key, IntToWString(value));
-}
-
-bool PageState::GetIntProperty(const std::wstring& key, int* value) const {
- std::wstring v;
- if (GetProperty(key, &v)) {
- return StringToInt(WideToUTF16Hack(v), value);
- }
- return false;
-}
-
-PageState* PageState::Copy() const {
- PageState* copy = new PageState();
- if (state_.get())
- copy->state_.reset(static_cast<DictionaryValue*>(state_->DeepCopy()));
- return copy;
-}
diff --git a/chrome/browser/page_state.h b/chrome/browser/page_state.h
deleted file mode 100644
index de91ed2..0000000
--- a/chrome/browser/page_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_PAGE_STATE_H__
-#define CHROME_BROWSER_PAGE_STATE_H__
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "base/values.h"
-
-class GURL;
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// PageState
-//
-// PageState represents a collection of key value pairs that can be
-// represented as an url or a byte array. It is used by synthetic pages such
-// as the destination tab to store and parse navigation states
-//
-/////////////////////////////////////////////////////////////////////////////
-class PageState {
- public:
- PageState() : state_(new DictionaryValue) {}
- ~PageState() {}
-
- // Init with the provided url
- void InitWithURL(const GURL& url);
-
- // Init with the provided bytes
- void InitWithBytes(const std::string& bytes);
-
- // Return a string representing this state
- void GetByteRepresentation(std::string* out) const;
-
- // Conveniences to set and retreive an int
- void SetIntProperty(const std::wstring& key, int value);
- bool GetIntProperty(const std::wstring& key, int* value) const;
-
- // Conveniences to set and retreive an int64.
- void SetInt64Property(const std::wstring& key, int64 value);
- bool GetInt64Property(const std::wstring& key, int64* value) const;
-
- // Set / Get string properties
- void SetProperty(const std::wstring& key, const std::wstring& value);
- bool GetProperty(const std::wstring& key, std::wstring* value) const;
-
- // Creates a copy of this page state. It is up to the caller to delete the
- // returned value.
- PageState* Copy() const;
-
- private:
-
- // our actual state collection
- scoped_ptr<DictionaryValue> state_;
-
- DISALLOW_COPY_AND_ASSIGN(PageState);
-};
-
-
-#endif // CHROME_BROWSER_PAGE_STATE_H__
diff --git a/chrome/browser/parsers/metadata_parser.h b/chrome/browser/parsers/metadata_parser.h
index 65210fa..ae623fc 100644
--- a/chrome/browser/parsers/metadata_parser.h
+++ b/chrome/browser/parsers/metadata_parser.h
@@ -1,18 +1,21 @@
-// 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.
#ifndef CHROME_BROWSER_PARSERS_METADATA_PARSER_H_
#define CHROME_BROWSER_PARSERS_METADATA_PARSER_H_
+#pragma once
#include <string>
-#include "base/file_path.h"
+class FilePath;
// Allows for Iteration on the Properties of a given file.
class MetadataPropertyIterator {
public:
MetadataPropertyIterator() {}
+ virtual ~MetadataPropertyIterator() {}
+
// Gets the next Property in the iterator. Returns false if at the end
// of the list.
@@ -29,6 +32,8 @@ class MetadataPropertyIterator {
class MetadataParser {
public:
explicit MetadataParser(const FilePath& path) {}
+ virtual ~MetadataParser() {}
+
static const char* kPropertyType;
static const char* kPropertyFilesize;
diff --git a/chrome/browser/parsers/metadata_parser_factory.h b/chrome/browser/parsers/metadata_parser_factory.h
index 2636804..0609657 100644
--- a/chrome/browser/parsers/metadata_parser_factory.h
+++ b/chrome/browser/parsers/metadata_parser_factory.h
@@ -1,17 +1,21 @@
-// 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.
#ifndef CHROME_BROWSER_PARSERS_METADATA_PARSER_FACTORY_H_
#define CHROME_BROWSER_PARSERS_METADATA_PARSER_FACTORY_H_
+#pragma once
#include "chrome/browser/parsers/metadata_parser.h"
+class FilePath;
+
// Used to check to see if a parser can parse a particular file, and allows
// for creation of a parser on a particular file.
class MetadataParserFactory {
public:
MetadataParserFactory() {}
+ virtual ~MetadataParserFactory() {}
// Used to check to see if the parser can parse the given file. This
// should not do any additional reading of the file.
diff --git a/chrome/browser/parsers/metadata_parser_filebase.cc b/chrome/browser/parsers/metadata_parser_filebase.cc
index 5b4aeff..0146f3f 100644
--- a/chrome/browser/parsers/metadata_parser_filebase.cc
+++ b/chrome/browser/parsers/metadata_parser_filebase.cc
@@ -1,11 +1,11 @@
-// 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.
#include "chrome/browser/parsers/metadata_parser_filebase.h"
#include "base/file_util.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
FileMetadataParser::FileMetadataParser(const FilePath& path)
@@ -17,7 +17,7 @@ bool FileMetadataParser::Parse() {
std::string value;
int64 size;
if (file_util::GetFileSize(path_, &size)) {
- properties_[MetadataParser::kPropertyFilesize] = Int64ToString(size);
+ properties_[MetadataParser::kPropertyFilesize] = base::Int64ToString(size);
}
#if defined(OS_WIN)
value = WideToUTF8(path_.BaseName().value());
diff --git a/chrome/browser/parsers/metadata_parser_filebase.h b/chrome/browser/parsers/metadata_parser_filebase.h
index c0ecfe4..8b232a2 100644
--- a/chrome/browser/parsers/metadata_parser_filebase.h
+++ b/chrome/browser/parsers/metadata_parser_filebase.h
@@ -4,7 +4,13 @@
#ifndef CHROME_BROWSER_PARSERS_METADATA_PARSER_FILEBASE_H_
#define CHROME_BROWSER_PARSERS_METADATA_PARSER_FILEBASE_H_
+#pragma once
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/hash_tables.h"
#include "chrome/browser/parsers/metadata_parser.h"
typedef base::hash_map<std::string, std::string> PropertyMap;
diff --git a/chrome/browser/parsers/metadata_parser_filebase_unittest.cc b/chrome/browser/parsers/metadata_parser_filebase_unittest.cc
index 0e954e6..24e1051 100644
--- a/chrome/browser/parsers/metadata_parser_filebase_unittest.cc
+++ b/chrome/browser/parsers/metadata_parser_filebase_unittest.cc
@@ -8,7 +8,8 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/scoped_temp_dir.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h" // TODO(brettw) remove when WideToASCII moves.
#include "chrome/browser/parsers/metadata_parser_filebase.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,7 +42,7 @@ class FileMetaDataParserTest : public testing::Test {
int64 size;
EXPECT_TRUE(file_util::GetFileSize(test_file_, &size));
- return Int64ToString(size);
+ return base::Int64ToString(size);
}
ScopedTempDir temp_dir_;
diff --git a/chrome/browser/parsers/metadata_parser_jpeg.h b/chrome/browser/parsers/metadata_parser_jpeg.h
index 779aa2b..cfd193a 100644
--- a/chrome/browser/parsers/metadata_parser_jpeg.h
+++ b/chrome/browser/parsers/metadata_parser_jpeg.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PARSERS_METADATA_PARSER_JPEG_H_
#define CHROME_BROWSER_PARSERS_METADATA_PARSER_JPEG_H_
+#pragma once
#include "chrome/browser/parsers/metadata_parser_filebase.h"
diff --git a/chrome/browser/parsers/metadata_parser_jpeg_factory.cc b/chrome/browser/parsers/metadata_parser_jpeg_factory.cc
index 3b60abf..5793984 100644
--- a/chrome/browser/parsers/metadata_parser_jpeg_factory.cc
+++ b/chrome/browser/parsers/metadata_parser_jpeg_factory.cc
@@ -1,12 +1,12 @@
-// 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.
#include "chrome/browser/parsers/metadata_parser_jpeg_factory.h"
-#include "chrome/browser/parsers/metadata_parser_jpeg.h"
-#include "base/logging.h"
+#include "base/file_path.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/parsers/metadata_parser_jpeg.h"
MetadataParserJpegFactory::MetadataParserJpegFactory()
: MetadataParserFactory() {
diff --git a/chrome/browser/parsers/metadata_parser_jpeg_factory.h b/chrome/browser/parsers/metadata_parser_jpeg_factory.h
index 2ac5160..9a4546a 100644
--- a/chrome/browser/parsers/metadata_parser_jpeg_factory.h
+++ b/chrome/browser/parsers/metadata_parser_jpeg_factory.h
@@ -1,12 +1,16 @@
-// 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.
#ifndef CHROME_BROWSER_PARSERS_METADATA_PARSER_JPEG_FACTORY_H_
#define CHROME_BROWSER_PARSERS_METADATA_PARSER_JPEG_FACTORY_H_
+#pragma once
+#include "base/basictypes.h"
#include "chrome/browser/parsers/metadata_parser_factory.h"
+class FilePath;
+
class MetadataParserJpegFactory : public MetadataParserFactory {
public:
MetadataParserJpegFactory();
diff --git a/chrome/browser/parsers/metadata_parser_manager.h b/chrome/browser/parsers/metadata_parser_manager.h
index 237553e..a16bdbe 100644
--- a/chrome/browser/parsers/metadata_parser_manager.h
+++ b/chrome/browser/parsers/metadata_parser_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PARSERS_METADATA_PARSER_MANAGER_H_
#define CHROME_BROWSER_PARSERS_METADATA_PARSER_MANAGER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_vector.h"
diff --git a/chrome/browser/password_manager/encryptor.h b/chrome/browser/password_manager/encryptor.h
index 480477c..f063be7 100644
--- a/chrome/browser/password_manager/encryptor.h
+++ b/chrome/browser/password_manager/encryptor.h
@@ -4,10 +4,10 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ENCRYPTOR_H__
#define CHROME_BROWSER_PASSWORD_MANAGER_ENCRYPTOR_H__
+#pragma once
#include <string>
-#include "base/values.h"
#include "base/string16.h"
// The Encryptor class gives access to simple encryption and decryption of
diff --git a/chrome/browser/password_manager/encryptor_password_mac.h b/chrome/browser/password_manager/encryptor_password_mac.h
index 73f8702..76461d1 100644
--- a/chrome/browser/password_manager/encryptor_password_mac.h
+++ b/chrome/browser/password_manager/encryptor_password_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ENCRYPTOR_PASSWORD_H__
#define CHROME_BROWSER_PASSWORD_MANAGER_ENCRYPTOR_PASSWORD_H__
+#pragma once
#include <string>
diff --git a/chrome/browser/password_manager/ie7_password.cc b/chrome/browser/password_manager/ie7_password.cc
index 053bce9..d6945d8 100644
--- a/chrome/browser/password_manager/ie7_password.cc
+++ b/chrome/browser/password_manager/ie7_password.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,6 @@
#include <string>
#include <vector>
-#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/sha1.h"
#include "base/string_util.h"
diff --git a/chrome/browser/password_manager/ie7_password.h b/chrome/browser/password_manager/ie7_password.h
index 91c81ab..a7690d9 100644
--- a/chrome/browser/password_manager/ie7_password.h
+++ b/chrome/browser/password_manager/ie7_password.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_IE7_PASSWORD_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_IE7_PASSWORD_H_
+#pragma once
#include <windows.h>
#include <string>
diff --git a/chrome/browser/password_manager/login_database.h b/chrome/browser/password_manager/login_database.h
index 9736a23..28131ed 100644
--- a/chrome/browser/password_manager/login_database.h
+++ b/chrome/browser/password_manager/login_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_LOGIN_DATABASE_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_LOGIN_DATABASE_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/password_manager/login_database_posix.cc b/chrome/browser/password_manager/login_database_posix.cc
index b33e747..cc5215d 100644
--- a/chrome/browser/password_manager/login_database_posix.cc
+++ b/chrome/browser/password_manager/login_database_posix.cc
@@ -2,17 +2,18 @@
// 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 "chrome/browser/password_manager/login_database.h"
+#include "base/utf_string_conversions.h"
+
// TODO: Actually encrypt passwords on Linux.
std::string LoginDatabase::EncryptedString(const string16& plain_text)
const {
- return UTF16ToASCII(plain_text);
+ return UTF16ToUTF8(plain_text);
}
string16 LoginDatabase::DecryptedString(const std::string& cipher_text)
const {
- return ASCIIToUTF16(cipher_text);
+ return UTF8ToUTF16(cipher_text);
}
diff --git a/chrome/browser/password_manager/login_database_unittest.cc b/chrome/browser/password_manager/login_database_unittest.cc
index e650042..ad0c2db 100644
--- a/chrome/browser/password_manager/login_database_unittest.cc
+++ b/chrome/browser/password_manager/login_database_unittest.cc
@@ -7,8 +7,9 @@
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/path_service.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/login_database.h"
#include "chrome/common/chrome_paths.h"
#include "webkit/glue/password_form.h"
@@ -21,7 +22,7 @@ class LoginDatabaseTest : public testing::Test {
PathService::Get(chrome::DIR_TEST_DATA, &file_);
const std::string test_db =
"TestMetadataStoreMacDatabase" +
- Int64ToString(base::Time::Now().ToInternalValue()) + ".db";
+ base::Int64ToString(base::Time::Now().ToInternalValue()) + ".db";
file_ = file_.AppendASCII(test_db);
file_util::Delete(file_, false);
}
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc
index 667611e..86da685 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x.cc
@@ -13,6 +13,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -165,8 +166,8 @@ PasswordForm* FormFromAttributes(GnomeKeyringAttributeList* attrs) {
form->ssl_valid = uint_attr_map["ssl_valid"];
form->preferred = uint_attr_map["preferred"];
int64 date_created = 0;
- bool date_ok = StringToInt64(string_attr_map["date_created"],
- &date_created);
+ bool date_ok = base::StringToInt64(string_attr_map["date_created"],
+ &date_created);
DCHECK(date_ok);
DCHECK_NE(date_created, 0);
form->date_created = base::Time::FromTimeT(date_created);
@@ -321,7 +322,7 @@ void GKRMethod::AddLogin(const PasswordForm& form) {
"signon_realm", form.signon_realm.c_str(),
"ssl_valid", form.ssl_valid,
"preferred", form.preferred,
- "date_created", Int64ToString(form.date_created.ToTimeT()).c_str(),
+ "date_created", base::Int64ToString(form.date_created.ToTimeT()).c_str(),
"blacklisted_by_user", form.blacklisted_by_user,
"scheme", form.scheme,
"application", GNOME_KEYRING_APPLICATION_CHROME,
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.h b/chrome/browser/password_manager/native_backend_gnome_x.h
index 406795b..99ef284 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.h
+++ b/chrome/browser/password_manager/native_backend_gnome_x.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_GNOME_X_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_GNOME_X_H_
-
-#include <vector>
+#pragma once
#include "base/basictypes.h"
#include "base/time.h"
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.cc b/chrome/browser/password_manager/native_backend_kwallet_x.cc
index 0cc4bf2..5f07bb8 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.cc
@@ -208,8 +208,10 @@ bool NativeBackendKWallet::RemoveLoginsCreatedBetween(
DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
G_TYPE_INVALID);
- if (CheckError() || !byte_array || !byte_array->len)
+ if (CheckError() || !byte_array ||
+ !CheckSerializedValue(byte_array, *realm)) {
continue;
+ }
string signon_realm(*realm);
Pickle pickle(byte_array->data, byte_array->len);
@@ -281,8 +283,12 @@ bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms,
G_TYPE_BOOLEAN, &has_entry,
G_TYPE_INVALID);
- if (CheckError() || !has_entry)
+ if (CheckError())
return false;
+ if (!has_entry) {
+ // This is not an error. There just isn't a matching entry.
+ return true;
+ }
GArray* byte_array = NULL;
dbus_g_proxy_call(proxy_, "readEntry", &error_,
@@ -294,8 +300,16 @@ bool NativeBackendKWallet::GetLoginsList(PasswordFormList* forms,
DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
G_TYPE_INVALID);
- if (CheckError() || !byte_array || !byte_array->len)
+ if (CheckError() || !byte_array)
return false;
+ if (!CheckSerializedValue(byte_array, signon_realm.c_str())) {
+ // This is weird, but we choose not to call it an error. There's an invalid
+ // entry somehow, but by pretending it just doesn't exist, we make it easier
+ // to repair without having to delete it using kwalletmanager (that is, by
+ // just saving a new password within this realm to overwrite it).
+ g_array_free(byte_array, true);
+ return true;
+ }
Pickle pickle(byte_array->data, byte_array->len);
DeserializeValue(signon_realm, pickle, forms);
@@ -370,8 +384,10 @@ bool NativeBackendKWallet::GetAllLogins(PasswordFormList* forms,
DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
G_TYPE_INVALID);
- if (CheckError() || !byte_array || !byte_array->len)
+ if (CheckError() || !byte_array ||
+ !CheckSerializedValue(byte_array, *realm)) {
continue;
+ }
Pickle pickle(byte_array->data, byte_array->len);
DeserializeValue(*realm, pickle, forms);
@@ -463,6 +479,18 @@ void NativeBackendKWallet::SerializeValue(const PasswordFormList& forms,
}
}
+bool NativeBackendKWallet::CheckSerializedValue(const GArray* byte_array,
+ const char* realm) {
+ const Pickle::Header* header =
+ reinterpret_cast<const Pickle::Header*>(byte_array->data);
+ if (byte_array->len < sizeof(*header) ||
+ header->payload_size > byte_array->len - sizeof(*header)) {
+ LOG(WARNING) << "Invalid KWallet entry detected! (realm: " << realm << ")";
+ return false;
+ }
+ return true;
+}
+
void NativeBackendKWallet::DeserializeValue(const string& signon_realm,
const Pickle& pickle,
PasswordFormList* forms) {
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.h b/chrome/browser/password_manager/native_backend_kwallet_x.h
index ad2b367..16e3c46 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.h
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_KWALLET_X_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_KWALLET_X_H_
+#pragma once
#include <dbus/dbus-glib.h>
#include <glib.h>
@@ -91,6 +92,10 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend {
// Serializes a list of PasswordForms to be stored in the wallet.
static void SerializeValue(const PasswordFormList& forms, Pickle* pickle);
+ // Checks a serialized list of PasswordForms for sanity. Returns true if OK.
+ // Note that |realm| is only used for generating a useful warning message.
+ static bool CheckSerializedValue(const GArray* byte_array, const char* realm);
+
// Deserializes a list of PasswordForms from the wallet.
static void DeserializeValue(const std::string& signon_realm,
const Pickle& pickle,
diff --git a/chrome/browser/password_manager/password_form_data.h b/chrome/browser/password_manager/password_form_data.h
index 04b78df..838c3ce 100644
--- a/chrome/browser/password_manager/password_form_data.h
+++ b/chrome/browser/password_manager/password_form_data.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_DATA_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_DATA_H_
+#pragma once
#include "testing/gmock/include/gmock/gmock.h"
#include "webkit/glue/password_form.h"
diff --git a/chrome/browser/password_manager/password_form_manager.cc b/chrome/browser/password_manager/password_form_manager.cc
index 1d7f345..81ba774 100644
--- a/chrome/browser/password_manager/password_form_manager.cc
+++ b/chrome/browser/password_manager/password_form_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 "base/histogram.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/profile.h"
@@ -142,6 +143,10 @@ bool PasswordFormManager::IsNewLogin() {
bool PasswordFormManager::HasValidPasswordForm() {
DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ // Non-HTML password forms (primarily HTTP and FTP autentication)
+ // do not contain username_element and password_element values.
+ if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
+ return true;
return !observed_form_.username_element.empty() &&
!observed_form_.password_element.empty();
}
diff --git a/chrome/browser/password_manager/password_form_manager.h b/chrome/browser/password_manager/password_form_manager.h
index a96bffc..584cc7b 100644
--- a/chrome/browser/password_manager/password_form_manager.h
+++ b/chrome/browser/password_manager/password_form_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_MANAGER_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_MANAGER_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/password_manager/password_form_manager_unittest.cc b/chrome/browser/password_manager/password_form_manager_unittest.cc
index b861466..32e42d7 100644
--- a/chrome/browser/password_manager/password_form_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_form_manager_unittest.cc
@@ -1,10 +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 "testing/gtest/include/gtest/gtest.h"
#include "base/string_util.h"
+#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"
@@ -199,32 +200,65 @@ TEST_F(PasswordFormManagerTest, TestEmptyAction) {
TEST_F(PasswordFormManagerTest, TestValidForms) {
// User submits credentials for the observed form.
PasswordForm credentials = *observed_form();
+ credentials.scheme = PasswordForm::SCHEME_HTML;
credentials.username_value = saved_match()->username_value;
credentials.password_value = saved_match()->password_value;
- credentials.preferred = true;
+ // Form with both username_element and password_element.
PasswordFormManager manager1(profile(), NULL, credentials, false);
SimulateMatchingPhase(&manager1, false);
- manager1.ProvisionallySave(credentials);
-
- // Valid form.
EXPECT_TRUE(manager1.HasValidPasswordForm());
+ // Form without a username_element but with a password_element.
credentials.username_element.clear();
PasswordFormManager manager2(profile(), NULL, credentials, false);
SimulateMatchingPhase(&manager2, false);
- manager2.ProvisionallySave(credentials);
-
- // Invalid form - no username.
EXPECT_FALSE(manager2.HasValidPasswordForm());
+ // Form without a password_element but with a username_element.
credentials.username_element = saved_match()->username_element;
credentials.password_element.clear();
PasswordFormManager manager3(profile(), NULL, credentials, false);
SimulateMatchingPhase(&manager3, false);
- manager3.ProvisionallySave(credentials);
-
- // Invalid form - no password.
EXPECT_FALSE(manager3.HasValidPasswordForm());
+
+ // Form with neither a password_element nor a username_element.
+ credentials.username_element.clear();
+ credentials.password_element.clear();
+ PasswordFormManager manager4(profile(), NULL, credentials, false);
+ SimulateMatchingPhase(&manager4, false);
+ EXPECT_FALSE(manager4.HasValidPasswordForm());
}
+TEST_F(PasswordFormManagerTest, TestValidFormsBasic) {
+ // User submits credentials for the observed form.
+ PasswordForm credentials = *observed_form();
+ credentials.scheme = PasswordForm::SCHEME_BASIC;
+ credentials.username_value = saved_match()->username_value;
+ credentials.password_value = saved_match()->password_value;
+
+ // Form with both username_element and password_element.
+ PasswordFormManager manager1(profile(), NULL, credentials, false);
+ SimulateMatchingPhase(&manager1, false);
+ EXPECT_TRUE(manager1.HasValidPasswordForm());
+
+ // Form without a username_element but with a password_element.
+ credentials.username_element.clear();
+ PasswordFormManager manager2(profile(), NULL, credentials, false);
+ SimulateMatchingPhase(&manager2, false);
+ EXPECT_TRUE(manager2.HasValidPasswordForm());
+
+ // Form without a password_element but with a username_element.
+ credentials.username_element = saved_match()->username_element;
+ credentials.password_element.clear();
+ PasswordFormManager manager3(profile(), NULL, credentials, false);
+ SimulateMatchingPhase(&manager3, false);
+ EXPECT_TRUE(manager3.HasValidPasswordForm());
+
+ // Form with neither a password_element nor a username_element.
+ credentials.username_element.clear();
+ credentials.password_element.clear();
+ PasswordFormManager manager4(profile(), NULL, credentials, false);
+ SimulateMatchingPhase(&manager4, false);
+ EXPECT_TRUE(manager4.HasValidPasswordForm());
+}
diff --git a/chrome/browser/password_manager/password_manager.cc b/chrome/browser/password_manager/password_manager.cc
index 258a254..9933f8f 100644
--- a/chrome/browser/password_manager/password_manager.cc
+++ b/chrome/browser/password_manager/password_manager.cc
@@ -6,15 +6,13 @@
#include <vector>
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/platform_thread.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/password_manager/password_form_manager.h"
#include "chrome/browser/password_manager/password_manager_delegate.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
@@ -27,6 +25,7 @@ using webkit_glue::PasswordFormMap;
// static
void PasswordManager::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(prefs::kPasswordManagerEnabled, true);
+ prefs->RegisterBooleanPref(prefs::kPasswordManagerAllowShowPasswords, true);
}
// This routine is called when PasswordManagers are constructed.
@@ -123,6 +122,10 @@ void PasswordManager::ClearProvisionalSave() {
provisional_save_manager_.reset();
}
+void PasswordManager::SetObserver(LoginModelObserver* observer) {
+ observer_ = observer;
+}
+
void PasswordManager::DidStopLoading() {
if (!provisional_save_manager_.get())
return;
diff --git a/chrome/browser/password_manager/password_manager.h b/chrome/browser/password_manager/password_manager.h
index 22447bb..017f5aa 100644
--- a/chrome/browser/password_manager/password_manager.h
+++ b/chrome/browser/password_manager/password_manager.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_H_
+#pragma once
#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/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "webkit/glue/password_form.h"
#include "webkit/glue/password_form_dom_manager.h"
@@ -61,9 +62,7 @@ class PasswordManager : public LoginModel {
void ClearProvisionalSave();
// LoginModel implementation.
- virtual void SetObserver(LoginModelObserver* observer) {
- observer_ = observer;
- }
+ virtual void SetObserver(LoginModelObserver* observer);
private:
// Note about how a PasswordFormManager can transition from
diff --git a/chrome/browser/password_manager/password_manager_delegate.h b/chrome/browser/password_manager/password_manager_delegate.h
index 830121b..087fe76 100644
--- a/chrome/browser/password_manager/password_manager_delegate.h
+++ b/chrome/browser/password_manager/password_manager_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_DELEGATE_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_DELEGATE_H_
+#pragma once
namespace webkit_glue {
struct PasswordFormFillData;
diff --git a/chrome/browser/password_manager/password_manager_unittest.cc b/chrome/browser/password_manager/password_manager_unittest.cc
index 9f5acc3..d408a64 100644
--- a/chrome/browser/password_manager/password_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_manager_unittest.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 "base/file_path.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.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"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -72,7 +72,8 @@ ACTION_P(SaveToScopedPtr, scoped) {
class PasswordManagerTest : public testing::Test {
public:
- PasswordManagerTest() {}
+ PasswordManagerTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_) {}
protected:
virtual void SetUp() {
@@ -105,6 +106,10 @@ class PasswordManagerTest : public testing::Test {
PasswordManager* manager() { return manager_.get(); }
+ // We create a UI thread to satisfy PasswordStore.
+ MessageLoopForUI message_loop_;
+ ChromeThread ui_thread_;
+
scoped_ptr<Profile> profile_;
scoped_refptr<MockPasswordStore> store_;
MockPasswordManagerDelegate delegate_; // Owned by manager_.
diff --git a/chrome/browser/password_manager/password_store.cc b/chrome/browser/password_manager/password_store.cc
index 4615e42..a02d666 100644
--- a/chrome/browser/password_manager/password_store.cc
+++ b/chrome/browser/password_manager/password_store.cc
@@ -90,6 +90,7 @@ void PasswordStore::NotifyConsumer(GetLoginsRequest* request,
void PasswordStore::NotifyConsumerImpl(PasswordStoreConsumer* consumer,
int handle,
const vector<PasswordForm*> forms) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// Don't notify the consumer if the request was canceled.
if (pending_requests_.find(handle) == pending_requests_.end()) {
// |forms| is const so we iterate rather than use STLDeleteElements().
@@ -103,12 +104,14 @@ void PasswordStore::NotifyConsumerImpl(PasswordStoreConsumer* consumer,
}
int PasswordStore::GetNewRequestHandle() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
int handle = handle_++;
pending_requests_.insert(handle);
return handle;
}
void PasswordStore::CancelLoginsQuery(int handle) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
pending_requests_.erase(handle);
}
diff --git a/chrome/browser/password_manager/password_store.h b/chrome/browser/password_manager/password_store.h
index d315e5b..6b6efa8 100644
--- a/chrome/browser/password_manager/password_store.h
+++ b/chrome/browser/password_manager/password_store.h
@@ -1,15 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_H_
+#pragma once
#include <set>
#include <vector>
#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "base/time.h"
#include "webkit/glue/password_form.h"
@@ -33,7 +33,8 @@ class PasswordStoreConsumer {
};
// Interface for storing form passwords in a platform-specific secure way.
-// The login request/manipulation API is not threadsafe.
+// The login request/manipulation API is not threadsafe and must be used
+// from the UI thread.
class PasswordStore : public base::RefCountedThreadSafe<PasswordStore> {
public:
PasswordStore();
diff --git a/chrome/browser/password_manager/password_store_change.h b/chrome/browser/password_manager/password_store_change.h
index aef99e3..885b6b7 100644
--- a/chrome/browser/password_manager/password_store_change.h
+++ b/chrome/browser/password_manager/password_store_change.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_CHANGE_H__
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_CHANGE_H__
+#pragma once
#include <vector>
diff --git a/chrome/browser/password_manager/password_store_default.cc b/chrome/browser/password_manager/password_store_default.cc
index 83909a7..012cfa1 100644
--- a/chrome/browser/password_manager/password_store_default.cc
+++ b/chrome/browser/password_manager/password_store_default.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/password_manager/password_store_change.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.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 9124182..4906ce8 100644
--- a/chrome/browser/password_manager/password_store_default.h
+++ b/chrome/browser/password_manager/password_store_default.h
@@ -4,10 +4,8 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_DEFAULT_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_DEFAULT_H_
+#pragma once
-#include <map>
-
-#include "base/file_path.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/password_manager/login_database.h"
diff --git a/chrome/browser/password_manager/password_store_default_unittest.cc b/chrome/browser/password_manager/password_store_default_unittest.cc
index f5629a4..a416d37 100644
--- a/chrome/browser/password_manager/password_store_default_unittest.cc
+++ b/chrome/browser/password_manager/password_store_default_unittest.cc
@@ -7,13 +7,16 @@
#include "base/string_util.h"
#include "base/scoped_temp_dir.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/waitable_event.h"
#include "chrome/browser/password_manager/password_store_change.h"
#include "chrome/browser/password_manager/password_store_default.h"
#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/pref_names.h"
+#include "chrome/test/signaling_task.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,17 +44,6 @@ class MockWebDataServiceConsumer : public WebDataServiceConsumer {
const WDTypedResult*));
};
-class SignalingTask : public Task {
- public:
- explicit SignalingTask(WaitableEvent* event) : event_(event) {
- }
- virtual void Run() {
- event_->Signal();
- }
- private:
- WaitableEvent* event_;
-};
-
class MockNotificationObserver : public NotificationObserver {
public:
MOCK_METHOD3(Observe, void(NotificationType,
@@ -157,6 +149,63 @@ MATCHER(EmptyWDResult, "") {
arg)->GetValue().empty();
}
+TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
+ // Prentend that the migration has already taken place.
+ profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
+ true);
+
+ // Initializing the PasswordStore shouldn't trigger a migration.
+ scoped_refptr<PasswordStoreDefault> store(
+ new PasswordStoreDefault(login_db_.release(), profile_.get(),
+ wds_.get()));
+ store->Init();
+
+ // Some non-ASCII password form data.
+ PasswordFormData form_data[] = {
+ { PasswordForm::SCHEME_HTML,
+ "http://foo.example.com",
+ "http://foo.example.com/origin",
+ "http://foo.example.com/action",
+ L"มีสีสัน",
+ L"ãŠå…ƒæ°—ã§ã™ã‹?",
+ L"盆栽",
+ L"أحب كرة",
+ L"£éä국수çà",
+ true, false, 1 },
+ };
+
+ // Build the expected forms vector and add the forms to the store.
+ VectorOfForms expected_forms;
+ for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
+ PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
+ expected_forms.push_back(form);
+ store->AddLogin(*form);
+ }
+
+ // The PasswordStore schedules tasks to run on the DB thread so we schedule
+ // yet another task to notify us that it's safe to carry on with the test.
+ WaitableEvent done(false, false);
+ ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done));
+ done.Wait();
+
+ MockPasswordStoreConsumer consumer;
+
+ // Make sure we quit the MessageLoop even if the test fails.
+ ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
+ .WillByDefault(QuitUIMessageLoop());
+
+ // We expect to get the same data back, even though it's not all ASCII.
+ EXPECT_CALL(consumer,
+ OnPasswordStoreRequestDone(_,
+ ContainsAllPasswordForms(expected_forms)))
+ .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
+
+ store->GetAutofillableLogins(&consumer);
+ MessageLoop::current()->Run();
+
+ STLDeleteElements(&expected_forms);
+}
+
TEST_F(PasswordStoreDefaultTest, Migration) {
PasswordFormData autofillable_data[] = {
{ PasswordForm::SCHEME_HTML,
@@ -213,26 +262,18 @@ TEST_F(PasswordStoreDefaultTest, Migration) {
false, false, 2 },
};
+ // Build the expected forms vectors and populate the WDS with logins.
VectorOfForms expected_autofillable;
for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(autofillable_data); ++i) {
- expected_autofillable.push_back(
- CreatePasswordFormFromData(autofillable_data[i]));
+ PasswordForm* form = CreatePasswordFormFromData(autofillable_data[i]);
+ expected_autofillable.push_back(form);
+ wds_->AddLogin(*form);
}
-
VectorOfForms expected_blacklisted;
for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(blacklisted_data); ++i) {
- expected_blacklisted.push_back(
- CreatePasswordFormFromData(blacklisted_data[i]));
- }
-
- // Populate the WDS with logins that should be migrated.
- for (VectorOfForms::iterator it = expected_autofillable.begin();
- it != expected_autofillable.end(); ++it) {
- wds_->AddLogin(**it);
- }
- for (VectorOfForms::iterator it = expected_blacklisted.begin();
- it != expected_blacklisted.end(); ++it) {
- wds_->AddLogin(**it);
+ PasswordForm* form = CreatePasswordFormFromData(blacklisted_data[i]);
+ expected_blacklisted.push_back(form);
+ wds_->AddLogin(*form);
}
// The WDS schedules tasks to run on the DB thread so we schedule yet another
@@ -243,7 +284,8 @@ TEST_F(PasswordStoreDefaultTest, Migration) {
// Initializing the PasswordStore should trigger a migration.
scoped_refptr<PasswordStoreDefault> store(
- new PasswordStoreDefault(login_db_.release(), profile_.get(), wds_.get()));
+ new PasswordStoreDefault(login_db_.release(),
+ profile_.get(), wds_.get()));
store->Init();
// Check that the migration preference has not been initialized;
@@ -333,16 +375,12 @@ TEST_F(PasswordStoreDefaultTest, MigrationAlreadyDone) {
true, false, 1 },
};
+ // Build the expected forms vector and populate the WDS with logins.
VectorOfForms unexpected_autofillable;
for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(wds_data); ++i) {
- unexpected_autofillable.push_back(
- CreatePasswordFormFromData(wds_data[i]));
- }
-
- // Populate the WDS with logins that should be migrated.
- for (VectorOfForms::iterator it = unexpected_autofillable.begin();
- it != unexpected_autofillable.end(); ++it) {
- wds_->AddLogin(**it);
+ PasswordForm* form = CreatePasswordFormFromData(wds_data[i]);
+ unexpected_autofillable.push_back(form);
+ wds_->AddLogin(*form);
}
// The WDS schedules tasks to run on the DB thread so we schedule yet another
diff --git a/chrome/browser/password_manager/password_store_mac.h b/chrome/browser/password_manager/password_store_mac.h
index fe7e2b9..aa5b144 100644
--- a/chrome/browser/password_manager/password_store_mac.h
+++ b/chrome/browser/password_manager/password_store_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_MAC_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_MAC_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/password_manager/password_store_mac_internal.h b/chrome/browser/password_manager/password_store_mac_internal.h
index 43ae5ad..7e6fb9a 100644
--- a/chrome/browser/password_manager/password_store_mac_internal.h
+++ b/chrome/browser/password_manager/password_store_mac_internal.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_MAC_INTERNAL_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_MAC_INTERNAL_H_
+#pragma once
#include <Security/Security.h>
diff --git a/chrome/browser/password_manager/password_store_win.cc b/chrome/browser/password_manager/password_store_win.cc
index a62a19a..1ae4fbf 100644
--- a/chrome/browser/password_manager/password_store_win.cc
+++ b/chrome/browser/password_manager/password_store_win.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/string_util.h"
+#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"
diff --git a/chrome/browser/password_manager/password_store_win.h b/chrome/browser/password_manager/password_store_win.h
index 6eea056..e58f717 100644
--- a/chrome/browser/password_manager/password_store_win.h
+++ b/chrome/browser/password_manager/password_store_win.h
@@ -1,15 +1,14 @@
-// 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.
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_WIN_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_WIN_H_
+#pragma once
#include <map>
#include <vector>
-#include "base/file_path.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/password_manager/password_store_default.h"
#include "chrome/browser/webdata/web_data_service.h"
diff --git a/chrome/browser/password_manager/password_store_win_unittest.cc b/chrome/browser/password_manager/password_store_win_unittest.cc
index 987c95e..aae342d 100644
--- a/chrome/browser/password_manager/password_store_win_unittest.cc
+++ b/chrome/browser/password_manager/password_store_win_unittest.cc
@@ -10,13 +10,16 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/scoped_temp_dir.h"
+#include "base/stl_util-inl.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/password_manager/password_form_data.h"
#include "chrome/browser/password_manager/password_store_win.h"
#include "chrome/browser/password_manager/ie7_password.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
+#include "chrome/test/signaling_task.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,17 +44,6 @@ public:
void(WebDataService::Handle, const WDTypedResult*));
};
-class SignalingTask : public Task {
- public:
- explicit SignalingTask(WaitableEvent* event) : event_(event) {
- }
- virtual void Run() {
- event_->Signal();
- }
- private:
- WaitableEvent* event_;
-};
-
} // anonymous namespace
typedef std::vector<PasswordForm*> VectorOfForms;
diff --git a/chrome/browser/password_manager/password_store_x.h b/chrome/browser/password_manager/password_store_x.h
index fd3fe42..5e36c08 100644
--- a/chrome/browser/password_manager/password_store_x.h
+++ b/chrome/browser/password_manager/password_store_x.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_X_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_X_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index a172503..1bb1ab3 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
+#include "chrome/test/signaling_task.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -43,17 +44,6 @@ class MockWebDataServiceConsumer : public WebDataServiceConsumer {
const WDTypedResult*));
};
-class SignalingTask : public Task {
- public:
- explicit SignalingTask(WaitableEvent* event) : event_(event) {
- }
- virtual void Run() {
- event_->Signal();
- }
- private:
- WaitableEvent* event_;
-};
-
class MockNotificationObserver : public NotificationObserver {
public:
MOCK_METHOD3(Observe, void(NotificationType,
@@ -610,7 +600,7 @@ TEST_P(PasswordStoreXTest, NativeMigration) {
// Get the initial size of the login DB file, before we populate it.
// This will be used later to make sure it gets back to this size.
const FilePath login_db_file = temp_dir_.path().Append("login_test");
- file_util::FileInfo db_file_start_info;
+ base::PlatformFileInfo db_file_start_info;
ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_start_info));
LoginDatabase* login_db = login_db_.get();
@@ -640,7 +630,7 @@ TEST_P(PasswordStoreXTest, NativeMigration) {
done.Wait();
// Get the new size of the login DB file. We expect it to be larger.
- file_util::FileInfo db_file_full_info;
+ base::PlatformFileInfo db_file_full_info;
ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_full_info));
EXPECT_GT(db_file_full_info.size, db_file_start_info.size);
@@ -727,7 +717,7 @@ TEST_P(PasswordStoreXTest, NativeMigration) {
// recreated. We approximate checking for this by checking that the file
// size is equal to the size before we populated it, even though it was
// larger after populating it.
- file_util::FileInfo db_file_end_info;
+ base::PlatformFileInfo db_file_end_info;
ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_end_info));
EXPECT_EQ(db_file_start_info.size, db_file_end_info.size);
}
diff --git a/chrome/browser/platform_util.h b/chrome/browser/platform_util.h
index 1140561..fb82b19 100644
--- a/chrome/browser/platform_util.h
+++ b/chrome/browser/platform_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PLATFORM_UTIL_H_
#define CHROME_BROWSER_PLATFORM_UTIL_H_
+#pragma once
#include "base/string16.h"
#include "gfx/native_widget_types.h"
@@ -54,7 +55,7 @@ bool SimpleYesNoBox(gfx::NativeWindow parent,
// Return a human readable modifier for the version string. For a
// branded Chrome (not Chromium), this modifier is the channel (dev,
// beta, but "" for stable).
-string16 GetVersionStringModifier();
+std::string GetVersionStringModifier();
}
diff --git a/chrome/browser/platform_util_chromeos.cc b/chrome/browser/platform_util_chromeos.cc
index 4c0d8cd..2d70ef3 100644
--- a/chrome/browser/platform_util_chromeos.cc
+++ b/chrome/browser/platform_util_chromeos.cc
@@ -7,19 +7,18 @@
#include <gtk/gtk.h>
#include "app/l10n_util.h"
-#include "app/gtk_util.h"
#include "base/file_util.h"
#include "base/process_util.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
-#include "chrome/common/process_watcher.h"
-#include "googleurl/src/gurl.h"
-#include "grit/generated_resources.h"
-
-#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/filebrowse_ui.h"
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/common/process_watcher.h"
+#include "googleurl/src/gurl.h"
+#include "grit/generated_resources.h"
class Profile;
@@ -82,7 +81,7 @@ void OpenItem(const FilePath& full_path) {
Browser* browser = BrowserList::GetLastActive();
browser->AddTabWithURL(
GURL(path), GURL(), PageTransition::LINK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(), NULL);
return;
}
if (ext == ".avi" ||
@@ -115,7 +114,7 @@ static void OpenURL(const std::string& url) {
Browser* browser = BrowserList::GetLastActive();
browser->AddTabWithURL(
GURL(url), GURL(), PageTransition::LINK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(), NULL);
}
void OpenExternal(const GURL& url) {
diff --git a/chrome/browser/platform_util_common_linux.cc b/chrome/browser/platform_util_common_linux.cc
index 40edb70..1f0ea42 100644
--- a/chrome/browser/platform_util_common_linux.cc
+++ b/chrome/browser/platform_util_common_linux.cc
@@ -10,6 +10,7 @@
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/process_util.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/process_watcher.h"
#include "chrome/browser/gtk/gtk_util.h"
@@ -107,11 +108,11 @@ bool SimpleYesNoBox(gfx::NativeWindow parent,
return g_dialog_response == GTK_RESPONSE_YES;
}
-/* Warning: this may be either Linux or ChromeOS */
-string16 GetVersionStringModifier() {
+// Warning: this may be either Linux or ChromeOS.
+std::string GetVersionStringModifier() {
char* env = getenv("CHROME_VERSION_EXTRA");
if (!env)
- return string16();
+ return std::string();
std::string modifier(env);
#if defined(GOOGLE_CHROME_BUILD)
@@ -127,7 +128,7 @@ string16 GetVersionStringModifier() {
}
#endif
- return ASCIIToUTF16(modifier);
+ return modifier;
}
} // namespace platform_util
diff --git a/chrome/browser/platform_util_linux.cc b/chrome/browser/platform_util_linux.cc
index 38ffba6..7f4627c 100644
--- a/chrome/browser/platform_util_linux.cc
+++ b/chrome/browser/platform_util_linux.cc
@@ -6,7 +6,6 @@
#include <gtk/gtk.h>
-#include "app/gtk_util.h"
#include "base/file_util.h"
#include "base/process_util.h"
#include "base/utf_string_conversions.h"
diff --git a/chrome/browser/platform_util_mac.mm b/chrome/browser/platform_util_mac.mm
index 3192fcc..3ee28b7 100644
--- a/chrome/browser/platform_util_mac.mm
+++ b/chrome/browser/platform_util_mac.mm
@@ -5,12 +5,14 @@
#include "chrome/browser/platform_util.h"
#import <Cocoa/Cocoa.h>
+#import <CoreServices/CoreServices.h>
#include "app/l10n_util.h"
#include "app/l10n_util_mac.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/mac_util.h"
+#include "base/scoped_aedesc.h"
#include "base/sys_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
@@ -25,11 +27,97 @@ void ShowItemInFolder(const FilePath& full_path) {
LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value();
}
+// This function opens a file. This doesn't use LaunchServices or NSWorkspace
+// because of two bugs:
+// 1. Incorrect app activation with com.apple.quarantine:
+// http://crbug.com/32921
+// 2. Silent no-op for unassociated file types: http://crbug.com/50263
+// Instead, an AppleEvent is constructed to tell the Finder to open the
+// document.
void OpenItem(const FilePath& full_path) {
DCHECK_EQ([NSThread currentThread], [NSThread mainThread]);
NSString* path_string = base::SysUTF8ToNSString(full_path.value());
- if (!path_string || ![[NSWorkspace sharedWorkspace] openFile:path_string])
- LOG(WARNING) << "NSWorkspace failed to open file " << full_path.value();
+ if (!path_string)
+ return;
+
+ OSErr status;
+
+ // Create the target of this AppleEvent, the Finder.
+ scoped_aedesc<AEAddressDesc> address;
+ const OSType finderCreatorCode = 'MACS';
+ status = AECreateDesc(typeApplSignature, // type
+ &finderCreatorCode, // data
+ sizeof(finderCreatorCode), // dataSize
+ address.OutPointer()); // result
+ if (status != noErr) {
+ LOG(WARNING) << "Could not create OpenItem() AE target";
+ return;
+ }
+
+ // Build the AppleEvent data structure that instructs Finder to open files.
+ scoped_aedesc<AppleEvent> theEvent;
+ status = AECreateAppleEvent(kCoreEventClass, // theAEEventClass
+ kAEOpenDocuments, // theAEEventID
+ address, // target
+ kAutoGenerateReturnID, // returnID
+ kAnyTransactionID, // transactionID
+ theEvent.OutPointer()); // result
+ if (status != noErr) {
+ LOG(WARNING) << "Could not create OpenItem() AE event";
+ return;
+ }
+
+ // Create the list of files (only ever one) to open.
+ scoped_aedesc<AEDescList> fileList;
+ status = AECreateList(NULL, // factoringPtr
+ 0, // factoredSize
+ false, // isRecord
+ fileList.OutPointer()); // resultList
+ if (status != noErr) {
+ LOG(WARNING) << "Could not create OpenItem() AE file list";
+ return;
+ }
+
+ // Add the single path to the file list. C-style cast to avoid both a
+ // static_cast and a const_cast to get across the toll-free bridge.
+ CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string];
+ FSRef pathRef;
+ if (CFURLGetFSRef(pathURLRef, &pathRef)) {
+ status = AEPutPtr(fileList.OutPointer(), // theAEDescList
+ 0, // index
+ typeFSRef, // typeCode
+ &pathRef, // dataPtr
+ sizeof(pathRef)); // dataSize
+ if (status != noErr) {
+ LOG(WARNING) << "Could not add file path to AE list in OpenItem()";
+ return;
+ }
+ } else {
+ LOG(WARNING) << "Could not get FSRef for path URL in OpenItem()";
+ return;
+ }
+
+ // Attach the file list to the AppleEvent.
+ status = AEPutParamDesc(theEvent.OutPointer(), // theAppleEvent
+ keyDirectObject, // theAEKeyword
+ fileList); // theAEDesc
+ if (status != noErr) {
+ LOG(WARNING) << "Could not put the AE file list the path in OpenItem()";
+ return;
+ }
+
+ // Send the actual event. Do not care about the reply.
+ scoped_aedesc<AppleEvent> reply;
+ status = AESend(theEvent, // theAppleEvent
+ reply.OutPointer(), // reply
+ kAENoReply + kAEAlwaysInteract, // sendMode
+ kAENormalPriority, // sendPriority
+ kAEDefaultTimeout, // timeOutInTicks
+ NULL, // idleProc
+ NULL); // filterProc
+ if (status != noErr) {
+ LOG(WARNING) << "Could not send AE to Finder in OpenItem()";
+ }
}
void OpenExternal(const GURL& url) {
@@ -88,7 +176,7 @@ bool SimpleYesNoBox(gfx::NativeWindow parent,
return result == NSAlertFirstButtonReturn;
}
-string16 GetVersionStringModifier() {
+std::string GetVersionStringModifier() {
#if defined(GOOGLE_CHROME_BUILD)
// Use the main application bundle and not the framework bundle. Keystone
// keys don't live in the framework.
@@ -108,9 +196,9 @@ string16 GetVersionStringModifier() {
channel = @"unknown";
}
- return base::SysNSStringToUTF16(channel);
+ return base::SysNSStringToUTF8(channel);
#else
- return string16();
+ return std::string();
#endif
}
diff --git a/chrome/browser/platform_util_win.cc b/chrome/browser/platform_util_win.cc
index 9b0a12c..a807a42 100644
--- a/chrome/browser/platform_util_win.cc
+++ b/chrome/browser/platform_util_win.cc
@@ -17,6 +17,7 @@
#include "base/registry.h"
#include "base/scoped_comptr_win.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"
@@ -112,10 +113,10 @@ void OpenExternal(const GURL& url) {
RegKey key;
std::wstring registry_path = ASCIIToWide(url.scheme()) +
L"\\shell\\open\\command";
- key.Open(HKEY_CLASSES_ROOT, registry_path.c_str());
+ key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ);
if (key.Valid()) {
DWORD size = 0;
- key.ReadValue(NULL, NULL, &size);
+ key.ReadValue(NULL, NULL, &size, NULL);
if (size <= 2) {
// ShellExecute crashes the process when the command is empty.
// We check for "2" because it always returns the trailing NULL.
@@ -165,7 +166,7 @@ bool SimpleYesNoBox(gfx::NativeWindow parent,
MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND) == IDYES;
}
-string16 GetVersionStringModifier() {
+std::string GetVersionStringModifier() {
#if defined(GOOGLE_CHROME_BUILD)
FilePath module;
string16 channel;
@@ -175,9 +176,9 @@ string16 GetVersionStringModifier() {
GoogleUpdateSettings::GetChromeChannel(is_system_install, &channel);
}
- return channel;
+ return UTF16ToASCII(channel);
#else
- return string16();
+ return std::string();
#endif
}
diff --git a/chrome/browser/plugin_download_helper.cc b/chrome/browser/plugin_download_helper.cc
new file mode 100644
index 0000000..5f17725
--- /dev/null
+++ b/chrome/browser/plugin_download_helper.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/plugin_download_helper.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+#include "base/file_util.h"
+#include "chrome/browser/net/url_request_tracking.h"
+#include "net/base/io_buffer.h"
+
+PluginDownloadUrlHelper::PluginDownloadUrlHelper(
+ const std::string& download_url,
+ int source_child_unique_id,
+ gfx::NativeWindow caller_window,
+ PluginDownloadUrlHelper::DownloadDelegate* delegate)
+ : download_file_request_(NULL),
+ download_file_buffer_(new net::IOBuffer(kDownloadFileBufferSize)),
+ download_file_caller_window_(caller_window),
+ download_url_(download_url),
+ download_source_child_unique_id_(source_child_unique_id),
+ delegate_(delegate) {
+ memset(download_file_buffer_->data(), 0, kDownloadFileBufferSize);
+ download_file_.reset(new net::FileStream());
+}
+
+PluginDownloadUrlHelper::~PluginDownloadUrlHelper() {
+ if (download_file_request_) {
+ delete download_file_request_;
+ download_file_request_ = NULL;
+ }
+}
+
+void PluginDownloadUrlHelper::InitiateDownload(
+ URLRequestContext* request_context) {
+ download_file_request_ = new URLRequest(GURL(download_url_), this);
+ chrome_browser_net::SetOriginProcessUniqueIDForRequest(
+ download_source_child_unique_id_, download_file_request_);
+ download_file_request_->set_context(request_context);
+ download_file_request_->Start();
+}
+
+void PluginDownloadUrlHelper::OnAuthRequired(
+ URLRequest* request,
+ net::AuthChallengeInfo* auth_info) {
+ URLRequest::Delegate::OnAuthRequired(request, auth_info);
+ DownloadCompletedHelper(false);
+}
+
+void PluginDownloadUrlHelper::OnSSLCertificateError(
+ URLRequest* request,
+ int cert_error,
+ net::X509Certificate* cert) {
+ URLRequest::Delegate::OnSSLCertificateError(request, cert_error, cert);
+ DownloadCompletedHelper(false);
+}
+
+void PluginDownloadUrlHelper::OnResponseStarted(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.
+ file_util::CreateTemporaryFile(&download_file_path_);
+ download_file_->Open(download_file_path_,
+ base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE);
+ if (!download_file_->IsOpen()) {
+ NOTREACHED();
+ OnDownloadCompleted(request);
+ return;
+ }
+ }
+ if (!request->status().is_success()) {
+ OnDownloadCompleted(request);
+ } else {
+ // Initiate a read.
+ int bytes_read = 0;
+ if (!request->Read(download_file_buffer_, kDownloadFileBufferSize,
+ &bytes_read)) {
+ // If the error is not an IO pending, then we're done
+ // reading.
+ if (!request->status().is_io_pending()) {
+ OnDownloadCompleted(request);
+ }
+ } else if (bytes_read == 0) {
+ OnDownloadCompleted(request);
+ } else {
+ OnReadCompleted(request, bytes_read);
+ }
+ }
+}
+
+void PluginDownloadUrlHelper::OnReadCompleted(URLRequest* request,
+ int bytes_read) {
+ DCHECK(download_file_->IsOpen());
+
+ if (bytes_read == 0) {
+ OnDownloadCompleted(request);
+ return;
+ }
+
+ int request_bytes_read = bytes_read;
+
+ while (request->status().is_success()) {
+ int bytes_written = download_file_->Write(download_file_buffer_->data(),
+ request_bytes_read, NULL);
+ DCHECK((bytes_written < 0) || (bytes_written == request_bytes_read));
+
+ if ((bytes_written < 0) || (bytes_written != request_bytes_read)) {
+ DownloadCompletedHelper(false);
+ break;
+ }
+
+ // Start reading
+ request_bytes_read = 0;
+ if (!request->Read(download_file_buffer_, kDownloadFileBufferSize,
+ &request_bytes_read)) {
+ if (!request->status().is_io_pending()) {
+ // If the error is not an IO pending, then we're done
+ // reading.
+ OnDownloadCompleted(request);
+ }
+ break;
+ } else if (request_bytes_read == 0) {
+ OnDownloadCompleted(request);
+ break;
+ }
+ }
+}
+
+void PluginDownloadUrlHelper::OnDownloadCompleted(URLRequest* request) {
+ bool success = true;
+ if (!request->status().is_success()) {
+ success = false;
+ } else if (!download_file_->IsOpen()) {
+ success = false;
+ }
+
+ DownloadCompletedHelper(success);
+}
+
+void PluginDownloadUrlHelper::DownloadCompletedHelper(bool success) {
+ if (download_file_->IsOpen()) {
+ download_file_.reset();
+ }
+
+ if (success) {
+ FilePath new_download_file_path =
+ download_file_path_.DirName().AppendASCII(
+ download_file_request_->url().ExtractFileName());
+
+ file_util::Delete(new_download_file_path, false);
+
+ if (!file_util::ReplaceFileW(download_file_path_,
+ new_download_file_path)) {
+ DLOG(ERROR) << "Failed to rename file:"
+ << download_file_path_.value()
+ << " to file:"
+ << new_download_file_path.value();
+ } else {
+ download_file_path_ = new_download_file_path;
+ }
+ }
+
+ if (delegate_) {
+ delegate_->OnDownloadCompleted(download_file_path_, success);
+ } else {
+ std::wstring path = download_file_path_.value();
+ COPYDATASTRUCT download_file_data = {0};
+ download_file_data.cbData =
+ static_cast<unsigned long>((path.length() + 1) * sizeof(wchar_t));
+ download_file_data.lpData = const_cast<wchar_t *>(path.c_str());
+ download_file_data.dwData = success;
+
+ if (::IsWindow(download_file_caller_window_)) {
+ ::SendMessage(download_file_caller_window_, WM_COPYDATA, NULL,
+ reinterpret_cast<LPARAM>(&download_file_data));
+ }
+ }
+
+ // Don't access any members after this.
+ delete this;
+}
+
+#endif // OS_WIN
+
+
+
+
diff --git a/chrome/browser/plugin_download_helper.h b/chrome/browser/plugin_download_helper.h
new file mode 100644
index 0000000..5d1a243
--- /dev/null
+++ b/chrome/browser/plugin_download_helper.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_PLUGIN_DOWNLOAD_HELPER_H_
+#define CHROME_BROWSER_PLUGIN_DOWNLOAD_HELPER_H_
+#pragma once
+
+#include <string>
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/file_path.h"
+#include "gfx/native_widget_types.h"
+#include "net/base/file_stream.h"
+#include "net/url_request/url_request.h"
+
+// 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 {
+ static const int kDownloadFileBufferSize = 32768;
+ public:
+ // The delegate receives notification about the status of downloads
+ // initiated.
+ class DownloadDelegate {
+ public:
+ virtual ~DownloadDelegate() {}
+
+ virtual void OnDownloadCompleted(const FilePath& download_path,
+ bool success) {}
+ };
+
+ PluginDownloadUrlHelper(const std::string& download_url,
+ int source_pid, gfx::NativeWindow caller_window,
+ PluginDownloadUrlHelper::DownloadDelegate* delegate);
+ ~PluginDownloadUrlHelper();
+
+ void InitiateDownload(URLRequestContext* request_context);
+
+ // URLRequest::Delegate
+ virtual void OnAuthRequired(URLRequest* request,
+ net::AuthChallengeInfo* auth_info);
+ virtual void OnSSLCertificateError(URLRequest* request,
+ int cert_error,
+ net::X509Certificate* cert);
+ virtual void OnResponseStarted(URLRequest* request);
+ virtual void OnReadCompleted(URLRequest* request, int bytes_read);
+
+ void OnDownloadCompleted(URLRequest* request);
+
+ protected:
+ void DownloadCompletedHelper(bool success);
+
+ // The download file request initiated by the plugin.
+ 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.
+ 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,
+ // indicating that the download completed.
+ gfx::NativeWindow download_file_caller_window_;
+
+ std::string download_url_;
+ int download_source_child_unique_id_;
+
+ PluginDownloadUrlHelper::DownloadDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginDownloadUrlHelper);
+};
+
+#endif // OS_WIN
+
+#endif // CHROME_BROWSER_PLUGIN_DOWNLOAD_HELPER_H_
+
+
diff --git a/chrome/browser/plugin_exceptions_table_model.cc b/chrome/browser/plugin_exceptions_table_model.cc
new file mode 100644
index 0000000..e9abc35
--- /dev/null
+++ b/chrome/browser/plugin_exceptions_table_model.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 "chrome/browser/plugin_exceptions_table_model.h"
+
+#include "app/l10n_util.h"
+#include "app/table_model_observer.h"
+#include "base/auto_reset.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/plugin_group.h"
+#include "grit/generated_resources.h"
+
+PluginExceptionsTableModel::PluginExceptionsTableModel(
+ HostContentSettingsMap* content_settings_map,
+ HostContentSettingsMap* otr_content_settings_map)
+ : map_(content_settings_map),
+ otr_map_(otr_content_settings_map),
+ updates_disabled_(false),
+ observer_(NULL) {
+ registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
+ NotificationService::AllSources());
+}
+
+bool PluginExceptionsTableModel::CanRemoveRows(const Rows& rows) const {
+ return !rows.empty();
+}
+
+void PluginExceptionsTableModel::RemoveRows(const Rows& rows) {
+ AutoReset<bool> tmp(&updates_disabled_, true);
+ bool reload_all = false;
+ // Iterate in reverse over the rows to get the indexes right.
+ for (Rows::const_reverse_iterator it = rows.rbegin();
+ it != rows.rend(); ++it) {
+ DCHECK_LT(*it, settings_.size());
+ SettingsEntry& entry = settings_[*it];
+ HostContentSettingsMap* map = entry.is_otr ? otr_map_ : map_;
+ map->SetContentSetting(entry.pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ resources_[entry.plugin_id],
+ CONTENT_SETTING_DEFAULT);
+ settings_.erase(settings_.begin() + *it);
+ row_counts_[entry.plugin_id]--;
+ if (!reload_all) {
+ // If we remove the last exception for a plugin, recreate all groups
+ // to get correct IDs.
+ if (row_counts_[entry.plugin_id] == 0) {
+ reload_all = true;
+ } else {
+ observer_->OnItemsRemoved(*it, 1);
+ }
+ }
+ }
+ if (reload_all) {
+ // This also notifies the observer.
+ ReloadSettings();
+ }
+}
+
+void PluginExceptionsTableModel::RemoveAll() {
+ AutoReset<bool> tmp(&updates_disabled_, true);
+ map_->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS);
+ if (otr_map_)
+ otr_map_->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS);
+
+ ClearSettings();
+ if (observer_)
+ observer_->OnModelChanged();
+}
+
+int PluginExceptionsTableModel::RowCount() {
+ return settings_.size();
+}
+
+std::wstring PluginExceptionsTableModel::GetText(int row, int column_id) {
+ DCHECK_GE(row, 0);
+ DCHECK_LT(row, static_cast<int>(settings_.size()));
+ SettingsEntry& entry = settings_[row];
+ switch (column_id) {
+ case IDS_EXCEPTIONS_PATTERN_HEADER:
+ case IDS_EXCEPTIONS_HOSTNAME_HEADER:
+ return UTF8ToWide(entry.pattern.AsString());
+
+ case IDS_EXCEPTIONS_ACTION_HEADER:
+ switch (entry.setting) {
+ case CONTENT_SETTING_ALLOW:
+ return l10n_util::GetString(IDS_EXCEPTIONS_ALLOW_BUTTON);
+ case CONTENT_SETTING_BLOCK:
+ return l10n_util::GetString(IDS_EXCEPTIONS_BLOCK_BUTTON);
+ default:
+ NOTREACHED();
+ }
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ return std::wstring();
+}
+
+void PluginExceptionsTableModel::SetObserver(TableModelObserver* observer) {
+ observer_ = observer;
+}
+
+TableModel::Groups PluginExceptionsTableModel::GetGroups() {
+ return groups_;
+}
+
+int PluginExceptionsTableModel::GetGroupID(int row) {
+ DCHECK_LT(row, static_cast<int>(settings_.size()));
+ return settings_[row].plugin_id;
+}
+
+void PluginExceptionsTableModel::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (!updates_disabled_)
+ ReloadSettings();
+}
+
+void PluginExceptionsTableModel::ClearSettings() {
+ settings_.clear();
+ groups_.clear();
+ row_counts_.clear();
+ resources_.clear();
+}
+
+void PluginExceptionsTableModel::GetPlugins(PluginUpdater::PluginMap* plugins) {
+ PluginUpdater::GetPluginUpdater()->GetPluginGroups(plugins);
+}
+
+void PluginExceptionsTableModel::LoadSettings() {
+ int group_id = 0;
+ PluginUpdater::PluginMap plugins;
+ GetPlugins(&plugins);
+ for (PluginUpdater::PluginMap::iterator it = plugins.begin();
+ it != plugins.end(); ++it) {
+ std::string plugin = it->first;
+ HostContentSettingsMap::SettingsForOneType settings;
+ map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ plugin,
+ &settings);
+ HostContentSettingsMap::SettingsForOneType otr_settings;
+ if (otr_map_) {
+ otr_map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ plugin,
+ &otr_settings);
+ }
+ std::wstring title = UTF16ToWide(it->second->GetGroupName());
+ for (HostContentSettingsMap::SettingsForOneType::iterator setting_it =
+ settings.begin(); setting_it != settings.end(); ++setting_it) {
+ SettingsEntry entry = {
+ setting_it->first,
+ group_id,
+ setting_it->second,
+ false
+ };
+ settings_.push_back(entry);
+ }
+ for (HostContentSettingsMap::SettingsForOneType::iterator setting_it =
+ otr_settings.begin();
+ setting_it != otr_settings.end(); ++setting_it) {
+ SettingsEntry entry = {
+ setting_it->first,
+ group_id,
+ setting_it->second,
+ true
+ };
+ settings_.push_back(entry);
+ }
+ int num_plugins = settings.size() + otr_settings.size();
+ if (num_plugins > 0) {
+ Group group = { title, group_id++ };
+ groups_.push_back(group);
+ resources_.push_back(plugin);
+ row_counts_.push_back(num_plugins);
+ }
+ }
+}
+
+void PluginExceptionsTableModel::ReloadSettings() {
+ ClearSettings();
+ LoadSettings();
+
+ if (observer_)
+ observer_->OnModelChanged();
+}
+
diff --git a/chrome/browser/plugin_exceptions_table_model.h b/chrome/browser/plugin_exceptions_table_model.h
new file mode 100644
index 0000000..491aab1
--- /dev/null
+++ b/chrome/browser/plugin_exceptions_table_model.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_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
+#define CHROME_BROWSER_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
+#pragma once
+
+#include <deque>
+
+#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/plugin_updater.h"
+#include "chrome/browser/remove_rows_table_model.h"
+#include "chrome/common/notification_observer.h"
+
+namespace plugin_test_internal {
+class PluginExceptionsTableModelTest;
+}
+struct WebPluginInfo;
+
+class PluginExceptionsTableModel : public RemoveRowsTableModel,
+ public NotificationObserver {
+ public:
+ PluginExceptionsTableModel(HostContentSettingsMap* content_settings_map,
+ HostContentSettingsMap* otr_content_settings_map);
+ virtual ~PluginExceptionsTableModel() {}
+
+ // Load plugin exceptions from the HostContentSettingsMaps. You should call
+ // this method after creating a new PluginExceptionsTableModel.
+ void LoadSettings();
+
+ // RemoveRowsTableModel methods:
+ virtual bool CanRemoveRows(const Rows& rows) const;
+ virtual void RemoveRows(const Rows& rows);
+ virtual void RemoveAll();
+
+ // TableModel methods:
+ virtual int RowCount();
+ virtual std::wstring GetText(int row, int column_id);
+ virtual void SetObserver(TableModelObserver* observer);
+ virtual bool HasGroups() { return true; }
+ virtual Groups GetGroups();
+ virtual int GetGroupID(int row);
+
+ // NotificationObserver methods:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ protected:
+ // Subclasses can override this method for testing.
+ virtual void GetPlugins(PluginUpdater::PluginMap* plugins);
+
+ private:
+ friend class plugin_test_internal::PluginExceptionsTableModelTest;
+
+ struct SettingsEntry {
+ HostContentSettingsMap::Pattern pattern;
+ int plugin_id;
+ ContentSetting setting;
+ bool is_otr;
+ };
+
+ void ClearSettings();
+ void ReloadSettings();
+
+ scoped_refptr<HostContentSettingsMap> map_;
+ scoped_refptr<HostContentSettingsMap> otr_map_;
+
+ std::deque<SettingsEntry> settings_;
+ std::deque<int> row_counts_;
+ std::deque<std::string> resources_;
+ TableModel::Groups groups_;
+
+ NotificationRegistrar registrar_;
+ bool updates_disabled_;
+ TableModelObserver* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginExceptionsTableModel);
+};
+
+#endif // CHROME_BROWSER_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
diff --git a/chrome/browser/plugin_exceptions_table_model_unittest.cc b/chrome/browser/plugin_exceptions_table_model_unittest.cc
new file mode 100644
index 0000000..6b508c6
--- /dev/null
+++ b/chrome/browser/plugin_exceptions_table_model_unittest.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 2010 The Chromium Authors. 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/table_model_observer.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/common/chrome_switches.h"
+#include "chrome/common/plugin_group.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/plugins/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 {
+ public:
+ explicit MockTableModelObserver(TableModel* model)
+ : model_(model) {
+ ON_CALL(*this, OnItemsRemoved(_, _))
+ .WillByDefault(
+ Invoke(this, &MockTableModelObserver::CheckOnItemsRemoved));
+ }
+
+ MOCK_METHOD0(OnModelChanged, void());
+ MOCK_METHOD2(OnItemsChanged, void(int start, int length));
+ MOCK_METHOD2(OnItemsAdded, void(int start, int length));
+ MOCK_METHOD2(OnItemsRemoved, void(int start, int length));
+
+ private:
+ void CheckOnItemsRemoved(int start, int length) {
+ if (!model_)
+ return;
+ // This method is called *after* the items have been removed, so we check if
+ // the first removed item was still inside the correct range.
+ EXPECT_LT(start, model_->RowCount() + 1);
+ }
+
+ TableModel* model_;
+};
+
+class PluginExceptionsTableModelTest : public testing::Test {
+ public:
+ PluginExceptionsTableModelTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_),
+ command_line_(CommandLine::ForCurrentProcess(),
+ *CommandLine::ForCurrentProcess()) {}
+
+ virtual void SetUp() {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableResourceContentSettings);
+
+ profile_.reset(new TestingProfile());
+
+ 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);
+
+ table_model_.reset(new MockPluginExceptionsTableModel(map, NULL));
+
+ PluginUpdater::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);
+
+ table_model_->set_plugins(plugins);
+ table_model_->ReloadSettings();
+ }
+
+ protected:
+ void CheckInvariants() {
+ typedef std::deque<PluginExceptionsTableModel::SettingsEntry> Entries;
+ Entries& settings = table_model_->settings_;
+ std::deque<int>& row_counts = table_model_->row_counts_;
+ std::deque<std::string>& resources = table_model_->resources_;
+ TableModel::Groups& groups = table_model_->groups_;
+
+ EXPECT_EQ(groups.size(), row_counts.size());
+ EXPECT_EQ(groups.size(), resources.size());
+
+ int last_plugin = 0;
+ int count = 0;
+ for (Entries::const_iterator it = settings.begin();
+ it != settings.end(); ++it) {
+ // Plugin IDs are indices into |groups|.
+ EXPECT_GE(it->plugin_id, 0);
+ EXPECT_LT(it->plugin_id, static_cast<int>(groups.size()));
+ if (it->plugin_id == last_plugin) {
+ count++;
+ } else {
+ // Plugin IDs are ascending one by one.
+ EXPECT_EQ(last_plugin+1, it->plugin_id);
+
+ // Consecutive runs of plugins with id |x| are |row_counts[x]| long.
+ EXPECT_EQ(count, row_counts[last_plugin]);
+ count = 1;
+ last_plugin = it->plugin_id;
+ }
+ }
+ if (row_counts.size() > 0)
+ EXPECT_EQ(count, row_counts[last_plugin]);
+ }
+
+ protected:
+ MessageLoop message_loop_;
+ ChromeThread ui_thread_;
+
+ scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<MockPluginExceptionsTableModel> table_model_;
+
+ private:
+ AutoReset<CommandLine> command_line_;
+};
+
+TEST_F(PluginExceptionsTableModelTest, Basic) {
+ EXPECT_EQ(3, table_model_->RowCount());
+ CheckInvariants();
+}
+
+TEST_F(PluginExceptionsTableModelTest, RemoveOneRow) {
+ MockTableModelObserver observer(table_model_.get());
+ table_model_->SetObserver(&observer);
+
+ EXPECT_CALL(observer, OnItemsRemoved(1, 1));
+ RemoveRowsTableModel::Rows rows;
+ rows.insert(1);
+ table_model_->RemoveRows(rows);
+ EXPECT_EQ(2, table_model_->RowCount());
+ EXPECT_EQ(2, static_cast<int>(table_model_->GetGroups().size()));
+ CheckInvariants();
+ table_model_->SetObserver(NULL);
+}
+
+TEST_F(PluginExceptionsTableModelTest, RemoveLastRowInGroup) {
+ MockTableModelObserver observer(table_model_.get());
+ table_model_->SetObserver(&observer);
+
+ EXPECT_CALL(observer, OnModelChanged());
+ RemoveRowsTableModel::Rows rows;
+ rows.insert(0);
+ table_model_->RemoveRows(rows);
+ EXPECT_EQ(2, table_model_->RowCount());
+ EXPECT_EQ(1, static_cast<int>(table_model_->GetGroups().size()));
+ CheckInvariants();
+
+ HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
+ EXPECT_CALL(observer, OnModelChanged());
+ map->SetContentSetting(HostContentSettingsMap::Pattern("[*.]blurp.net"),
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "b-bar",
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(3, table_model_->RowCount());
+
+ InSequence s;
+ EXPECT_CALL(observer, OnItemsRemoved(2, 1));
+ EXPECT_CALL(observer, OnItemsRemoved(0, 1));
+ rows.clear();
+ rows.insert(0);
+ rows.insert(2);
+ table_model_->RemoveRows(rows);
+ EXPECT_EQ(1, table_model_->RowCount());
+ EXPECT_EQ(1, static_cast<int>(table_model_->GetGroups().size()));
+ CheckInvariants();
+
+ table_model_->SetObserver(NULL);
+}
+
+TEST_F(PluginExceptionsTableModelTest, RemoveAllRows) {
+ MockTableModelObserver observer(table_model_.get());
+ table_model_->SetObserver(&observer);
+
+ EXPECT_CALL(observer, OnModelChanged());
+ table_model_->RemoveAll();
+ EXPECT_EQ(0, table_model_->RowCount());
+ EXPECT_EQ(0, static_cast<int>(table_model_->GetGroups().size()));
+ CheckInvariants();
+ table_model_->SetObserver(NULL);
+}
+
+} // namespace plugin_test_internal
diff --git a/chrome/browser/plugin_installer.cc b/chrome/browser/plugin_installer.cc
index 2d0e0a3..1b1d0c5 100644
--- a/chrome/browser/plugin_installer.cc
+++ b/chrome/browser/plugin_installer.cc
@@ -43,8 +43,8 @@ void PluginInstaller::OnMissingPluginStatus(int status) {
}
}
-std::wstring PluginInstaller::GetMessageText() const {
- return l10n_util::GetString(IDS_PLUGININSTALLER_MISSINGPLUGIN_PROMPT);
+string16 PluginInstaller::GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_MISSINGPLUGIN_PROMPT);
}
SkBitmap* PluginInstaller::GetIcon() const {
@@ -56,9 +56,9 @@ int PluginInstaller::GetButtons() const {
return BUTTON_OK;
}
-std::wstring PluginInstaller::GetButtonLabel(InfoBarButton button) const {
+string16 PluginInstaller::GetButtonLabel(InfoBarButton button) const {
if (button == BUTTON_OK)
- return l10n_util::GetString(IDS_PLUGININSTALLER_INSTALLPLUGIN_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_INSTALLPLUGIN_BUTTON);
return ConfirmInfoBarDelegate::GetButtonLabel(button);
}
@@ -67,8 +67,8 @@ bool PluginInstaller::Accept() {
return true;
}
-std::wstring PluginInstaller::GetLinkText() {
- return l10n_util::GetString(IDS_PLUGININSTALLER_PROBLEMSINSTALLING);
+string16 PluginInstaller::GetLinkText() {
+ return l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_PROBLEMSINSTALLING);
}
bool PluginInstaller::LinkClicked(WindowOpenDisposition disposition) {
diff --git a/chrome/browser/plugin_installer.h b/chrome/browser/plugin_installer.h
index 77f3804..b56034d 100644
--- a/chrome/browser/plugin_installer.h
+++ b/chrome/browser/plugin_installer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PLUGIN_INSTALLER_H_
#define CHROME_BROWSER_PLUGIN_INSTALLER_H_
+#pragma once
#include "chrome/browser/tab_contents/infobar_delegate.h"
@@ -22,12 +23,12 @@ class PluginInstaller : public ConfirmInfoBarDelegate {
private:
// Overridden from ConfirmInfoBarDelegate:
- virtual std::wstring GetMessageText() const;
+ virtual string16 GetMessageText() const;
virtual SkBitmap* GetIcon() const;
virtual int GetButtons() const;
- virtual std::wstring GetButtonLabel(InfoBarButton button) const;
+ virtual string16 GetButtonLabel(InfoBarButton button) const;
virtual bool Accept();
- virtual std::wstring GetLinkText();
+ virtual string16 GetLinkText();
virtual bool LinkClicked(WindowOpenDisposition disposition);
// The containing TabContents
diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc
index 7c2aeb0..093b975 100644
--- a/chrome/browser/plugin_process_host.cc
+++ b/chrome/browser/plugin_process_host.cc
@@ -19,10 +19,12 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/chrome_plugin_browsing_context.h"
#include "chrome/browser/chrome_thread.h"
#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/renderer_host/resource_dispatcher_host.h"
@@ -35,7 +37,7 @@
#include "chrome/common/render_messages.h"
#include "gfx/native_widget_types.h"
#include "ipc/ipc_switches.h"
-#include "net/base/file_stream.h"
+#include "net/base/cookie_store.h"
#include "net/base/io_buffer.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -54,203 +56,6 @@ static const char kDefaultPluginFinderURL[] =
"https://dl-ssl.google.com/edgedl/chrome/plugins/plugins2.xml";
#if defined(OS_WIN)
-
-// 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 {
- static const int kDownloadFileBufferSize = 32768;
- public:
- PluginDownloadUrlHelper(const std::string& download_url,
- int source_pid, gfx::NativeWindow caller_window);
- ~PluginDownloadUrlHelper();
-
- void InitiateDownload();
-
- // URLRequest::Delegate
- virtual void OnAuthRequired(URLRequest* request,
- net::AuthChallengeInfo* auth_info);
- virtual void OnSSLCertificateError(URLRequest* request,
- int cert_error,
- net::X509Certificate* cert);
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int bytes_read);
-
- void OnDownloadCompleted(URLRequest* request);
-
- protected:
- void DownloadCompletedHelper(bool success);
-
- // The download file request initiated by the plugin.
- 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.
- 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,
- // indicating that the download completed.
- gfx::NativeWindow download_file_caller_window_;
-
- std::string download_url_;
- int download_source_child_unique_id_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginDownloadUrlHelper);
-};
-
-PluginDownloadUrlHelper::PluginDownloadUrlHelper(
- const std::string& download_url,
- int source_child_unique_id,
- gfx::NativeWindow caller_window)
- : download_file_request_(NULL),
- download_file_buffer_(new net::IOBuffer(kDownloadFileBufferSize)),
- download_file_caller_window_(caller_window),
- download_url_(download_url),
- download_source_child_unique_id_(source_child_unique_id) {
- DCHECK(::IsWindow(caller_window));
- memset(download_file_buffer_->data(), 0, kDownloadFileBufferSize);
- download_file_.reset(new net::FileStream());
-}
-
-PluginDownloadUrlHelper::~PluginDownloadUrlHelper() {
- if (download_file_request_) {
- delete download_file_request_;
- download_file_request_ = NULL;
- }
-}
-
-void PluginDownloadUrlHelper::InitiateDownload() {
- download_file_request_ = new URLRequest(GURL(download_url_), this);
- chrome_browser_net::SetOriginProcessUniqueIDForRequest(
- download_source_child_unique_id_, download_file_request_);
- download_file_request_->set_context(
- Profile::GetDefaultRequestContext()->GetURLRequestContext());
- download_file_request_->Start();
-}
-
-void PluginDownloadUrlHelper::OnAuthRequired(
- URLRequest* request,
- net::AuthChallengeInfo* auth_info) {
- URLRequest::Delegate::OnAuthRequired(request, auth_info);
- DownloadCompletedHelper(false);
-}
-
-void PluginDownloadUrlHelper::OnSSLCertificateError(
- URLRequest* request,
- int cert_error,
- net::X509Certificate* cert) {
- URLRequest::Delegate::OnSSLCertificateError(request, cert_error, cert);
- DownloadCompletedHelper(false);
-}
-
-void PluginDownloadUrlHelper::OnResponseStarted(URLRequest* request) {
- if (!download_file_->IsOpen()) {
- file_util::GetTempDir(&download_file_path_);
-
- GURL request_url = request->url();
- download_file_path_ = download_file_path_.Append(
- UTF8ToWide(request_url.ExtractFileName()));
- download_file_->Open(download_file_path_,
- base::PLATFORM_FILE_CREATE_ALWAYS |
- base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE);
- if (!download_file_->IsOpen()) {
- NOTREACHED();
- OnDownloadCompleted(request);
- return;
- }
- }
- if (!request->status().is_success()) {
- OnDownloadCompleted(request);
- } else {
- // Initiate a read.
- int bytes_read = 0;
- if (!request->Read(download_file_buffer_, kDownloadFileBufferSize,
- &bytes_read)) {
- // If the error is not an IO pending, then we're done
- // reading.
- if (!request->status().is_io_pending()) {
- OnDownloadCompleted(request);
- }
- } else if (bytes_read == 0) {
- OnDownloadCompleted(request);
- } else {
- OnReadCompleted(request, bytes_read);
- }
- }
-}
-
-void PluginDownloadUrlHelper::OnReadCompleted(URLRequest* request,
- int bytes_read) {
- DCHECK(download_file_->IsOpen());
-
- if (bytes_read == 0) {
- OnDownloadCompleted(request);
- return;
- }
-
- int request_bytes_read = bytes_read;
-
- while (request->status().is_success()) {
- int bytes_written = download_file_->Write(download_file_buffer_->data(),
- request_bytes_read, NULL);
- DCHECK((bytes_written < 0) || (bytes_written == request_bytes_read));
-
- if ((bytes_written < 0) || (bytes_written != request_bytes_read)) {
- DownloadCompletedHelper(false);
- break;
- }
-
- // Start reading
- request_bytes_read = 0;
- if (!request->Read(download_file_buffer_, kDownloadFileBufferSize,
- &request_bytes_read)) {
- if (!request->status().is_io_pending()) {
- // If the error is not an IO pending, then we're done
- // reading.
- OnDownloadCompleted(request);
- }
- break;
- } else if (request_bytes_read == 0) {
- OnDownloadCompleted(request);
- break;
- }
- }
-}
-
-void PluginDownloadUrlHelper::OnDownloadCompleted(URLRequest* request) {
- bool success = true;
- if (!request->status().is_success()) {
- success = false;
- } else if (!download_file_->IsOpen()) {
- success = false;
- }
-
- DownloadCompletedHelper(success);
-}
-
-void PluginDownloadUrlHelper::DownloadCompletedHelper(bool success) {
- if (download_file_->IsOpen()) {
- download_file_.reset();
- }
-
- std::wstring path = download_file_path_.value();
- COPYDATASTRUCT download_file_data = {0};
- download_file_data.cbData =
- static_cast<unsigned long>((path.length() + 1) * sizeof(wchar_t));
- download_file_data.lpData = const_cast<wchar_t *>(path.c_str());
- download_file_data.dwData = success;
-
- if (::IsWindow(download_file_caller_window_)) {
- ::SendMessage(download_file_caller_window_, WM_COPYDATA, NULL,
- reinterpret_cast<LPARAM>(&download_file_data));
- }
-
- // Don't access any members after this.
- delete this;
-}
-
void PluginProcessHost::OnPluginWindowDestroyed(HWND window, HWND parent) {
// The window is destroyed at this point, we just care about its parent, which
// is the intermediate window we created.
@@ -267,8 +72,9 @@ void PluginProcessHost::OnDownloadUrl(const std::string& url,
int source_pid,
gfx::NativeWindow caller_window) {
PluginDownloadUrlHelper* download_url_helper =
- new PluginDownloadUrlHelper(url, source_pid, caller_window);
- download_url_helper->InitiateDownload();
+ new PluginDownloadUrlHelper(url, source_pid, caller_window, NULL);
+ download_url_helper->InitiateDownload(
+ Profile::GetDefaultRequestContext()->GetURLRequestContext());
}
void PluginProcessHost::AddWindow(HWND window) {
@@ -341,7 +147,7 @@ PluginProcessHost::~PluginProcessHost() {
}
bool PluginProcessHost::Init(const WebPluginInfo& info,
- const std::wstring& locale) {
+ const std::string& locale) {
info_ = info;
set_name(UTF16ToWideHack(info_.name));
set_version(UTF16ToWideHack(info_.version));
@@ -352,8 +158,8 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
// Build command line for plugin. When we have a plugin launcher, we can't
// allow "self" on linux and we need the real file path.
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- std::wstring plugin_launcher =
- browser_command_line.GetSwitchValue(switches::kPluginLauncher);
+ CommandLine::StringType plugin_launcher =
+ browser_command_line.GetSwitchValueNative(switches::kPluginLauncher);
FilePath exe_path = GetChildPath(plugin_launcher.empty());
if (exe_path.empty())
return false;
@@ -361,17 +167,15 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
CommandLine* cmd_line = new CommandLine(exe_path);
// Put the process type and plugin path first so they're easier to see
// in process listings using native process management tools.
- cmd_line->AppendSwitchWithValue(switches::kProcessType,
- switches::kPluginProcess);
- cmd_line->AppendSwitchWithValue(switches::kPluginPath,
- info.path.ToWStringHack());
+ cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kPluginProcess);
+ cmd_line->AppendSwitchPath(switches::kPluginPath, info.path);
if (logging::DialogsAreSuppressed())
cmd_line->AppendSwitch(switches::kNoErrorDialogs);
// Propagate the following switches to the plugin command line (along with
// any associated values) if present in the browser command line
- static const char* const switch_names[] = {
+ static const char* const kSwitchNames[] = {
switches::kPluginStartupDialog,
switches::kNoSandbox,
switches::kSafePlugins,
@@ -392,17 +196,12 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
switches::kEnableGPUPlugin,
switches::kUseGL,
#if defined(OS_CHROMEOS)
- switches::kProfile,
+ switches::kLoginProfile,
#endif
};
- for (size_t i = 0; i < arraysize(switch_names); ++i) {
- if (browser_command_line.HasSwitch(switch_names[i])) {
- cmd_line->AppendSwitchWithValue(
- switch_names[i],
- browser_command_line.GetSwitchValueASCII(switch_names[i]));
- }
- }
+ cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
+ arraysize(kSwitchNames));
// If specified, prepend a launcher program to the command line.
if (!plugin_launcher.empty())
@@ -411,17 +210,16 @@ bool PluginProcessHost::Init(const WebPluginInfo& info,
if (!locale.empty()) {
// Pass on the locale so the null plugin will use the right language in the
// prompt to install the desired plugin.
- cmd_line->AppendSwitchWithValue(switches::kLang, locale);
+ cmd_line->AppendSwitchASCII(switches::kLang, locale);
}
// Gears requires the data dir to be available on startup.
- std::wstring data_dir =
- PluginService::GetInstance()->GetChromePluginDataDir().ToWStringHack();
+ FilePath data_dir =
+ PluginService::GetInstance()->GetChromePluginDataDir();
DCHECK(!data_dir.empty());
- cmd_line->AppendSwitchWithValue(switches::kPluginDataDir, data_dir);
+ cmd_line->AppendSwitchPath(switches::kPluginDataDir, data_dir);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
SetCrashReporterCommandLine(cmd_line);
@@ -581,7 +379,7 @@ void PluginProcessHost::OnAccessFiles(int renderer_id,
for (size_t i = 0; i < files.size(); ++i) {
const FilePath path = FilePath::FromWStringHack(UTF8ToWide(files[i]));
- if (!policy->CanUploadFile(renderer_id, path)) {
+ if (!policy->CanReadFile(renderer_id, path)) {
LOG(INFO) << "Denied unauthorized request for file " << files[i];
*allowed = false;
return;
diff --git a/chrome/browser/plugin_process_host.h b/chrome/browser/plugin_process_host.h
index 31d4228..d7c278e 100644
--- a/chrome/browser/plugin_process_host.h
+++ b/chrome/browser/plugin_process_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PLUGIN_PROCESS_HOST_H_
#define CHROME_BROWSER_PLUGIN_PROCESS_HOST_H_
+#pragma once
#include "build/build_config.h"
@@ -13,11 +14,10 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
+#include "base/ref_counted.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/net/resolve_proxy_msg_helper.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "gfx/native_widget_types.h"
#include "ipc/ipc_channel_handle.h"
#include "webkit/glue/plugins/webplugininfo.h"
@@ -45,7 +45,7 @@ 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::wstring& locale);
+ bool Init(const WebPluginInfo& info, const std::string& locale);
// Force the plugin process to shutdown (cleanly).
void ForceShutdown();
diff --git a/chrome/browser/plugin_service.cc b/chrome/browser/plugin_service.cc
index b7f0489..c1d7e02 100644
--- a/chrome/browser/plugin_service.cc
+++ b/chrome/browser/plugin_service.cc
@@ -10,6 +10,7 @@
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
@@ -18,7 +19,7 @@
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_updater.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_plugin_lib.h"
@@ -60,7 +61,12 @@ void PluginService::InitGlobalInstance(Profile* profile) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// We first group the plugins and then figure out which groups to disable.
- plugin_updater::DisablePluginGroupsFromPrefs(profile);
+ PluginUpdater::GetPluginUpdater()->DisablePluginGroupsFromPrefs(profile);
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableOutdatedPlugins)) {
+ PluginUpdater::GetPluginUpdater()->DisableOutdatedPluginGroups();
+ }
// Have Chrome plugins write their data to the profile directory.
GetInstance()->SetChromePluginDataDir(profile->GetPath());
@@ -79,7 +85,7 @@ void PluginService::EnableChromePlugins(bool enable) {
PluginService::PluginService()
: main_message_loop_(MessageLoop::current()),
resource_dispatcher_host_(NULL),
- ui_locale_(ASCIIToWide(g_browser_process->GetApplicationLocale())) {
+ ui_locale_(g_browser_process->GetApplicationLocale()) {
RegisterPepperPlugins();
// Have the NPAPI plugin list search for Chrome plugins as well.
@@ -104,8 +110,9 @@ PluginService::PluginService()
}
#ifndef DISABLE_NACL
- if (command_line->HasSwitch(switches::kInternalNaCl))
+ if (command_line->HasSwitch(switches::kInternalNaCl)) {
RegisterInternalNaClPlugin();
+ }
#endif
chrome::RegisterInternalGPUPlugin();
@@ -173,7 +180,7 @@ const FilePath& PluginService::GetChromePluginDataDir() {
return chrome_plugin_data_dir_;
}
-const std::wstring& PluginService::GetUILocale() {
+const std::string& PluginService::GetUILocale() {
return ui_locale_;
}
@@ -226,13 +233,16 @@ void PluginService::OpenChannelToPlugin(
ResourceMessageFilter* renderer_msg_filter,
const GURL& url,
const std::string& mime_type,
- const std::wstring& locale,
+ const std::string& locale,
IPC::Message* reply_msg) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- // We don't need a policy URL here because that was already checked by a
- // previous call to GetPluginPath.
- GURL policy_url;
- FilePath plugin_path = GetPluginPath(url, policy_url, mime_type, NULL);
+ bool allow_wildcard = true;
+ WebPluginInfo info;
+ FilePath plugin_path;
+ if (NPAPI::PluginList::Singleton()->GetPluginInfo(
+ url, mime_type, allow_wildcard, &info, NULL) && info.enabled) {
+ plugin_path = info.path;
+ }
PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path);
if (plugin_host) {
plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg);
@@ -242,21 +252,6 @@ void PluginService::OpenChannelToPlugin(
}
}
-FilePath PluginService::GetPluginPath(const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- std::string* actual_mime_type) {
- bool allow_wildcard = true;
- WebPluginInfo info;
- if (NPAPI::PluginList::Singleton()->GetPluginInfo(
- url, mime_type, allow_wildcard, &info, actual_mime_type) &&
- info.enabled && PluginAllowedForURL(info.path, policy_url)) {
- return info.path;
- }
-
- return FilePath();
-}
-
static void PurgePluginListCache(bool reload_pages) {
for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
!it.IsAtEnd(); it.Advance()) {
@@ -337,8 +332,8 @@ void PluginService::Observe(NotificationType type,
}
}
-bool PluginService::PluginAllowedForURL(const FilePath& plugin_path,
- const GURL& url) {
+bool PluginService::PrivatePluginAllowedForURL(const FilePath& plugin_path,
+ const GURL& url) {
if (url.is_empty())
return true; // Caller wants all plugins.
diff --git a/chrome/browser/plugin_service.h b/chrome/browser/plugin_service.h
index 0d90bd4..3f25c25 100644
--- a/chrome/browser/plugin_service.h
+++ b/chrome/browser/plugin_service.h
@@ -7,17 +7,15 @@
#ifndef CHROME_BROWSER_PLUGIN_SERVICE_H_
#define CHROME_BROWSER_PLUGIN_SERVICE_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/hash_tables.h"
-#include "base/ref_counted.h"
#include "base/singleton.h"
#include "base/waitable_event_watcher.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
@@ -61,7 +59,7 @@ class PluginService
const FilePath& GetChromePluginDataDir();
// Gets the browser's UI locale.
- const std::wstring& GetUILocale();
+ const std::string& GetUILocale();
// Returns the plugin process host corresponding to the plugin process that
// has been started by this service. Returns NULL if no process has been
@@ -80,16 +78,12 @@ class PluginService
void OpenChannelToPlugin(ResourceMessageFilter* renderer_msg_filter,
const GURL& url,
const std::string& mime_type,
- const std::wstring& locale,
+ const std::string& locale,
IPC::Message* reply_msg);
- // Get the path to the plugin specified. policy_url is the URL of the page
- // requesting the plugin, so we can verify whether the plugin is allowed
- // on that page.
- FilePath GetPluginPath(const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- std::string* actual_mime_type);
+ // Returns true if the given plugin is allowed to be used by a page with
+ // the given URL.
+ bool PrivatePluginAllowedForURL(const FilePath& plugin_path, const GURL& url);
// The UI thread's message loop
MessageLoop* main_message_loop() { return main_message_loop_; }
@@ -115,10 +109,6 @@ class PluginService
virtual void Observe(NotificationType type, const NotificationSource& source,
const NotificationDetails& details);
- // Returns true if the given plugin is allowed to be used by a page with
- // the given URL.
- bool PluginAllowedForURL(const FilePath& plugin_path, const GURL& url);
-
void RegisterPepperPlugins();
// mapping between plugin path and PluginProcessHost
@@ -135,7 +125,7 @@ class PluginService
FilePath chrome_plugin_data_dir_;
// The browser's UI locale.
- const std::wstring ui_locale_;
+ const std::string ui_locale_;
// Map of plugin paths to the origin they are restricted to. Used for
// extension-only plugins.
diff --git a/chrome/browser/plugin_updater.cc b/chrome/browser/plugin_updater.cc
index 0691bac..3a96cee 100644
--- a/chrome/browser/plugin_updater.cc
+++ b/chrome/browser/plugin_updater.cc
@@ -7,22 +7,30 @@
#include <string>
#include <vector>
+#include "base/command_line.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
+#include "base/sys_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/pref_service.h"
+#include "base/version.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/plugin_group.h"
#include "chrome/common/pref_names.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/plugins/webplugininfo.h"
-namespace plugin_updater {
+PluginUpdater::PluginUpdater() : enable_internal_pdf_(true) {
+}
// Convert to a List of Groups
-static void GetPluginGroups(
- std::vector<linked_ptr<PluginGroup> >* plugin_groups) {
+void PluginUpdater::GetPluginGroups(PluginMap* plugin_groups) {
+ DCHECK(plugin_groups);
+
+ plugin_groups->clear();
// Read all plugins and convert them to plugin groups
std::vector<WebPluginInfo> web_plugins;
NPAPI::PluginList::Singleton()->GetPlugins(false, &web_plugins);
@@ -34,64 +42,153 @@ static void GetPluginGroups(
PluginGroup* group = PluginGroup::FindGroupMatchingPlugin(
*plugin_groups, web_plugin);
if (!group) {
- group = PluginGroup::FindHardcodedPluginGroup(web_plugin);
- plugin_groups->push_back(linked_ptr<PluginGroup>(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);
}
}
-static DictionaryValue* CreatePluginFileSummary(
+DictionaryValue* PluginUpdater::CreatePluginFileSummary(
const WebPluginInfo& plugin) {
DictionaryValue* data = new DictionaryValue();
- data->SetString(L"path", plugin.path.value());
- data->SetStringFromUTF16(L"name", plugin.name);
- data->SetStringFromUTF16(L"version", plugin.version);
- data->SetBoolean(L"enabled", plugin.enabled);
+ data->SetString("path", plugin.path.value());
+ data->SetString("name", plugin.name);
+ data->SetString("version", plugin.version);
+ data->SetBoolean("enabled", plugin.enabled);
return data;
}
-ListValue* GetPluginGroupsData() {
- std::vector<linked_ptr<PluginGroup> > plugin_groups;
+ListValue* PluginUpdater::GetPluginGroupsData() {
+ PluginMap plugin_groups;
GetPluginGroups(&plugin_groups);
// Construct DictionaryValues to return to the UI
ListValue* plugin_groups_data = new ListValue();
- for (std::vector<linked_ptr<PluginGroup> >::iterator it =
+ for (PluginMap::const_iterator it =
plugin_groups.begin();
it != plugin_groups.end();
++it) {
- plugin_groups_data->Append((*it)->GetDataForUI());
+ plugin_groups_data->Append(it->second->GetDataForUI());
}
return plugin_groups_data;
}
-void EnablePluginGroup(bool enable, const string16& group_name) {
- std::vector<linked_ptr<PluginGroup> > plugin_groups;
+void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) {
+ PluginMap plugin_groups;
GetPluginGroups(&plugin_groups);
- for (std::vector<linked_ptr<PluginGroup> >::iterator it =
+ for (PluginMap::const_iterator it =
plugin_groups.begin();
it != plugin_groups.end();
++it) {
- if ((*it)->GetGroupName() == group_name) {
- (*it)->Enable(enable);
+ if (it->second->GetGroupName() == group_name) {
+ if (PluginGroup::IsPluginNameDisabledByPolicy(group_name))
+ enable = false;
+ if (it->second->Enabled() != enable) {
+ it->second->Enable(enable);
+ NotificationService::current()->Notify(
+ NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
+ Source<PluginUpdater>(this),
+ NotificationService::NoDetails());
+ }
+ return;
}
}
}
-void EnablePluginFile(bool enable, const FilePath::StringType& path) {
+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);
else
NPAPI::PluginList::Singleton()->DisablePlugin(file_path);
+
+ NotificationService::current()->Notify(
+ NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
+ Source<PluginUpdater>(this),
+ NotificationService::NoDetails());
+}
+
+void PluginUpdater::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
+ const std::string* pref_name = Details<std::string>(details).ptr();
+ if (!pref_name) {
+ NOTREACHED();
+ return;
+ }
+ if (*pref_name == prefs::kPluginsPluginsBlacklist) {
+ PrefService* pref_service = Source<PrefService>(source).ptr();
+ const ListValue* list =
+ pref_service->GetList(prefs::kPluginsPluginsBlacklist);
+ DisablePluginsFromPolicy(list);
+ }
}
-static bool enable_internal_pdf_ = true;
+void PluginUpdater::DisablePluginsFromPolicy(const ListValue* plugin_names) {
+ // Generate the set of unique disabled plugin patterns from the disabled
+ // plugins list.
+ std::set<string16> policy_disabled_plugin_patterns;
+ if (plugin_names) {
+ ListValue::const_iterator end(plugin_names->end());
+ for (ListValue::const_iterator current(plugin_names->begin());
+ current != end; ++current) {
+ string16 plugin_name;
+ if ((*current)->GetAsString(&plugin_name)) {
+ policy_disabled_plugin_patterns.insert(plugin_name);
+ }
+ }
+ }
+ PluginGroup::SetPolicyDisabledPluginPatterns(policy_disabled_plugin_patterns);
-void DisablePluginGroupsFromPrefs(Profile* profile) {
+ // 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 grousp are only changed to a more "safe" state after a policy
+ // change, i.e. from enabled to disabled. See bug 54681.
+ std::vector<WebPluginInfo> plugins;
+ NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
+ for (std::vector<WebPluginInfo>::const_iterator plugin_iter = plugins.begin();
+ plugin_iter != plugins.end(); ++plugin_iter) {
+ if (PluginGroup::IsPluginNameDisabledByPolicy(plugin_iter->name))
+ NPAPI::PluginList::Singleton()->DisablePlugin(plugin_iter->path);
+ }
+
+ PluginMap plugin_groups;
+ GetPluginGroups(&plugin_groups);
+ PluginMap::iterator it;
+ for (it = plugin_groups.begin(); it != plugin_groups.end(); ++it) {
+ string16 current_group_name = it->second->GetGroupName();
+ if (PluginGroup::IsPluginNameDisabledByPolicy(current_group_name))
+ it->second->Enable(false);
+ }
+
+ NotificationService::current()->Notify(
+ NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
+ Source<PluginUpdater>(this),
+ NotificationService::NoDetails());
+}
+
+void PluginUpdater::DisablePluginGroupsFromPrefs(Profile* profile) {
bool update_internal_dir = false;
+ bool update_preferences = false;
FilePath last_internal_dir =
profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
FilePath cur_internal_dir;
@@ -102,8 +199,17 @@ void DisablePluginGroupsFromPrefs(Profile* profile) {
prefs::kPluginsLastInternalDirectory, cur_internal_dir);
}
+ if (!enable_internal_pdf_) {
+ // This DCHECK guards against us disabling/enabling the pdf plugin more than
+ // once without renaming the flag that tells us whether we can enable it
+ // automatically. Each time we disable the plugin by default after it was
+ // enabled by default, we need to rename that flag.
+ DCHECK(!profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF));
+ }
+
bool found_internal_pdf = false;
bool force_enable_internal_pdf = false;
+ string16 pdf_group_name;
FilePath pdf_path;
PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
FilePath::StringType pdf_path_str = pdf_path.value();
@@ -129,12 +235,12 @@ void DisablePluginGroupsFromPrefs(Profile* profile) {
DictionaryValue* plugin = static_cast<DictionaryValue*>(*it);
string16 group_name;
bool enabled = true;
- plugin->GetBoolean(L"enabled", &enabled);
+ plugin->GetBoolean("enabled", &enabled);
FilePath::StringType path;
// The plugin list constains all the plugin files in addition to the
// plugin groups.
- if (plugin->GetString(L"path", &path)) {
+ if (plugin->GetString("path", &path)) {
// Files have a path attribute, groups don't.
FilePath plugin_path(path);
if (update_internal_dir &&
@@ -144,69 +250,56 @@ void DisablePluginGroupsFromPrefs(Profile* profile) {
// looks internal, update its path in the prefs.
plugin_path = cur_internal_dir.Append(plugin_path.BaseName());
path = plugin_path.value();
- plugin->SetString(L"path", path);
+ plugin->SetString("path", path);
}
if (FilePath::CompareIgnoreCase(path, pdf_path_str) == 0) {
found_internal_pdf = true;
+ plugin->GetString("name", &pdf_group_name);
if (!enabled && force_enable_internal_pdf) {
enabled = true;
- plugin->SetBoolean(L"enabled", true);
+ plugin->SetBoolean("enabled", true);
+ update_preferences = true; // Can't modify the list during looping.
}
}
if (!enabled)
NPAPI::PluginList::Singleton()->DisablePlugin(plugin_path);
- } else if (!enabled && plugin->GetStringAsUTF16(L"name", &group_name)) {
+ } 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.
+ if (force_enable_internal_pdf && pdf_group_name == group_name)
+ continue;
+
// Otherwise this is a list of groups.
EnablePluginGroup(false, group_name);
}
}
}
- // Build the set of policy-disabled plugins once and cache it.
+ // Build the set of policy-disabled plugin patterns once and cache it.
// Don't do this in the constructor, there's no profile available there.
- std::set<string16> policy_disabled_plugins;
const ListValue* plugin_blacklist =
profile->GetPrefs()->GetList(prefs::kPluginsPluginsBlacklist);
- if (plugin_blacklist) {
- ListValue::const_iterator end(plugin_blacklist->end());
- for (ListValue::const_iterator current(plugin_blacklist->begin());
- current != end; ++current) {
- string16 plugin_name;
- if ((*current)->GetAsUTF16(&plugin_name)) {
- policy_disabled_plugins.insert(plugin_name);
- }
- }
- }
- PluginGroup::SetPolicyDisabledPluginSet(policy_disabled_plugins);
-
- // Disable all of the plugins and plugin groups that are disabled by policy.
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
- for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
- it != plugins.end();
- ++it) {
- if (PluginGroup::IsPluginNameDisabledByPolicy(it->name))
- NPAPI::PluginList::Singleton()->DisablePlugin(it->path);
- }
-
- std::vector<linked_ptr<PluginGroup> > plugin_groups;
- GetPluginGroups(&plugin_groups);
- std::vector<linked_ptr<PluginGroup> >::const_iterator it;
- for (it = plugin_groups.begin(); it != plugin_groups.end(); ++it) {
- string16 current_group_name = (*it)->GetGroupName();
- if (PluginGroup::IsPluginNameDisabledByPolicy(current_group_name))
- EnablePluginGroup(false, current_group_name);
- }
+ DisablePluginsFromPolicy(plugin_blacklist);
if (!enable_internal_pdf_ && !found_internal_pdf) {
// The internal PDF plugin is disabled by default, and the user hasn't
// overridden the default.
NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path);
}
+
+ if (update_preferences)
+ UpdatePreferences(profile);
}
-void UpdatePreferences(Profile* profile) {
+void PluginUpdater::DisableOutdatedPluginGroups() {
+ PluginMap groups;
+ GetPluginGroups(&groups);
+ for (PluginMap::iterator it = groups.begin(); it != groups.end(); ++it)
+ it->second->DisableOutdatedPlugins();
+}
+
+void PluginUpdater::UpdatePreferences(Profile* profile) {
ListValue* plugins_list = profile->GetPrefs()->GetMutableList(
prefs::kPluginsPluginsList);
plugins_list->Clear();
@@ -226,17 +319,20 @@ void UpdatePreferences(Profile* profile) {
}
// Add the groups as well.
- std::vector<linked_ptr<PluginGroup> > plugin_groups;
+ PluginMap plugin_groups;
GetPluginGroups(&plugin_groups);
- for (std::vector<linked_ptr<PluginGroup> >::iterator it =
- plugin_groups.begin();
- it != plugin_groups.end();
- ++it) {
+ for (PluginMap::iterator it = plugin_groups.begin();
+ it != plugin_groups.end(); ++it) {
// Don't save preferences for vulnerable pugins.
- if (!(*it)->IsVulnerable()) {
- plugins_list->Append((*it)->GetSummary());
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableOutdatedPlugins) ||
+ !it->second->IsVulnerable()) {
+ plugins_list->Append(it->second->GetSummary());
}
}
}
-} // namespace plugin_updater
+/*static*/
+PluginUpdater* PluginUpdater::GetPluginUpdater() {
+ return Singleton<PluginUpdater>::get();
+}
diff --git a/chrome/browser/plugin_updater.h b/chrome/browser/plugin_updater.h
index fd34b93..401ab61 100644
--- a/chrome/browser/plugin_updater.h
+++ b/chrome/browser/plugin_updater.h
@@ -4,35 +4,78 @@
#ifndef CHROME_BROWSER_PLUGIN_UPDATER_H_
#define CHROME_BROWSER_PLUGIN_UPDATER_H_
+#pragma once
-#include <set>
-#include <vector>
+#include <map>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/linked_ptr.h"
#include "base/singleton.h"
+#include "chrome/common/notification_observer.h"
+class DictionaryValue;
class ListValue;
+class NotificationDetails;
+class NotificationSource;
+class PluginGroup;
class Profile;
+struct WebPluginInfo;
-namespace plugin_updater {
+class PluginUpdater : public NotificationObserver {
+ public:
+ typedef std::map<std::string, linked_ptr<PluginGroup> > PluginMap;
-// Get a list of all the Plugin groups.
-ListValue* GetPluginGroupsData();
+ // Get a map from identifier to plugin group for all plugin groups.
+ void GetPluginGroups(PluginMap* plugin_groups);
-// Enable or disable a plugin group.
-void EnablePluginGroup(bool enable, const string16& group_name);
+ // Get a list of all the plugin groups. The caller should take ownership
+ // of the returned ListValue.
+ ListValue* GetPluginGroupsData();
-// Enable or disable a specific plugin file.
-void EnablePluginFile(bool enable, const FilePath::StringType& file_path);
+ // Enable or disable a plugin group.
+ void EnablePluginGroup(bool enable, const string16& group_name);
-// Disable all plugin groups as defined by the user's preference file.
-void DisablePluginGroupsFromPrefs(Profile* profile);
+ // Enable or disable a specific plugin file.
+ void EnablePluginFile(bool enable, const FilePath::StringType& file_path);
-// Write the enable/disable status to the user's preference file.
-void UpdatePreferences(Profile* profile);
+ // Disable all plugin groups as defined by the user's preference file.
+ void DisablePluginGroupsFromPrefs(Profile* profile);
-} // namespace plugin_updater
+ // 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();
+
+ // Write the enable/disable status to the user's preference file.
+ void UpdatePreferences(Profile* profile);
+
+ // NotificationObserver method overrides
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ static PluginUpdater* GetPluginUpdater();
+
+ private:
+ PluginUpdater();
+ virtual ~PluginUpdater() {}
+
+ // Note: if you change this to false from true, you must update
+ // kPluginsEnabledInternalPDF to be a new name (i.e. add 2, 3, 4...) at end.
+ bool enable_internal_pdf_;
+
+ DictionaryValue* CreatePluginFileSummary(const WebPluginInfo& plugin);
+
+ // Force plugins to be disabled due to policy. |plugins| contains
+ // the list of StringValues of the names of the policy-disabled plugins.
+ void DisablePluginsFromPolicy(const ListValue* plugin_names);
+
+ // Needed to allow singleton instantiation using private constructor.
+ friend struct DefaultSingletonTraits<PluginUpdater>;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginUpdater);
+};
#endif // CHROME_BROWSER_PLUGIN_UPDATER_H_
diff --git a/chrome/browser/popup_blocked_animation.h b/chrome/browser/popup_blocked_animation.h
index 7d2d59d..156a799 100644
--- a/chrome/browser/popup_blocked_animation.h
+++ b/chrome/browser/popup_blocked_animation.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_POPUP_BLOCKED_ANIMATION_H_
#define CHROME_BROWSER_POPUP_BLOCKED_ANIMATION_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/popup_blocker_browsertest.cc b/chrome/browser/popup_blocker_browsertest.cc
new file mode 100644
index 0000000..2276f5f
--- /dev/null
+++ b/chrome/browser/popup_blocker_browsertest.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 "base/command_line.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/message_loop.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/ui_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("popup_blocker");
+
+typedef InProcessBrowserTest PopupBlockerBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, PopupBlockedPostBlank) {
+ FilePath file_name(FILE_PATH_LITERAL("popup-blocked-to-post-blank.html"));
+ FilePath test_dir(kTestDir);
+ GURL url(ui_test_utils::GetTestUrl(test_dir, file_name));
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // If the popup blocker blocked the blank post, there should be only one
+ // tab in only one browser window and the URL of current tab must be equal
+ // to the original URL.
+ EXPECT_EQ(1u, BrowserList::GetBrowserCount(browser()->profile()));
+ EXPECT_EQ(1, browser()->tab_count());
+ TabContents* cur_tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(cur_tab);
+ EXPECT_EQ(url, cur_tab->GetURL());
+}
+
+} // namespace
+
diff --git a/chrome/browser/possible_url_model.cc b/chrome/browser/possible_url_model.cc
index 2240975..f419762 100644
--- a/chrome/browser/possible_url_model.cc
+++ b/chrome/browser/possible_url_model.cc
@@ -4,20 +4,22 @@
#include "chrome/browser/possible_url_model.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/table_model_observer.h"
+#include "app/text_elider.h"
#include "base/callback.h"
#include "base/i18n/rtl.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/favicon_service.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "gfx/codec/png_codec.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
using base::Time;
using base::TimeDelta;
@@ -32,6 +34,20 @@ const int kPossibleURLTimeScope = 30;
} // anonymous namespace
+// Contains the data needed to show a result.
+struct PossibleURLModel::Result {
+ Result() : index(0) {}
+
+ GURL url;
+ // Index of this Result in results_. This is used as the key into
+ // fav_icon_map_ to lookup the favicon for the url, as well as the index
+ // into results_ when the favicon is received.
+ size_t index;
+ gfx::SortedDisplayURL display_url;
+ std::wstring title;
+};
+
+
PossibleURLModel::PossibleURLModel()
: profile_(NULL),
observer_(NULL) {
@@ -41,6 +57,9 @@ PossibleURLModel::PossibleURLModel()
}
}
+PossibleURLModel::~PossibleURLModel() {
+}
+
void PossibleURLModel::Reload(Profile *profile) {
profile_ = profile;
consumer_.CancelAllRequests();
@@ -86,6 +105,10 @@ void PossibleURLModel::OnHistoryQueryComplete(HistoryService::Handle h,
observer_->OnModelChanged();
}
+int PossibleURLModel::RowCount() {
+ return static_cast<int>(results_.size());
+}
+
const GURL& PossibleURLModel::GetURL(int row) {
if (row < 0 || row >= RowCount()) {
NOTREACHED();
@@ -121,10 +144,8 @@ std::wstring PossibleURLModel::GetText(int row, int col_id) {
// TODO(brettw): this should probably pass the GURL up so the URL elider
// can be used at a higher level when we know the width.
- // Force URL to be LTR.
- std::wstring url(UTF16ToWideHack(results_[row].display_url.display_url()));
- base::i18n::GetDisplayStringInLTRDirectionality(&url);
- return url;
+ string16 url = results_[row].display_url.display_url();
+ return UTF16ToWide(base::i18n::GetDisplayStringInLTRDirectionality(url));
}
SkBitmap PossibleURLModel::GetIcon(int row) {
@@ -185,3 +206,7 @@ void PossibleURLModel::OnFavIconAvailable(
}
}
}
+
+void PossibleURLModel::SetObserver(TableModelObserver* observer) {
+ observer_ = observer;
+}
diff --git a/chrome/browser/possible_url_model.h b/chrome/browser/possible_url_model.h
index a6fa1ab..0c0b531 100644
--- a/chrome/browser/possible_url_model.h
+++ b/chrome/browser/possible_url_model.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_POSSIBLE_URL_MODEL_H_
#define CHROME_BROWSER_POSSIBLE_URL_MODEL_H_
+#pragma once
+#include <map>
#include <string>
#include <vector>
#include "app/table_model.h"
-#include "app/text_elider.h"
-#include "base/string_util.h"
#include "chrome/browser/history/history.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+
+class SkBitmap;
////////////////////////////////////////////////////////////////////////////////
//
@@ -24,18 +25,14 @@
class PossibleURLModel : public TableModel {
public:
PossibleURLModel();
-
- virtual ~PossibleURLModel() {
- }
+ virtual ~PossibleURLModel();
void Reload(Profile *profile);
void OnHistoryQueryComplete(HistoryService::Handle h,
history::QueryResults* result);
- virtual int RowCount() {
- return static_cast<int>(results_.size());
- }
+ virtual int RowCount();
const GURL& GetURL(int row);
@@ -53,24 +50,9 @@ class PossibleURLModel : public TableModel {
bool expired,
GURL icon_url);
- virtual void SetObserver(TableModelObserver* observer) {
- observer_ = observer;
- }
+ virtual void SetObserver(TableModelObserver* observer);
private:
- // Contains the data needed to show a result.
- struct Result {
- Result() : index(0) {}
-
- GURL url;
- // Index of this Result in results_. This is used as the key into
- // fav_icon_map_ to lookup the favicon for the url, as well as the index
- // into results_ when the favicon is received.
- size_t index;
- gfx::SortedDisplayURL display_url;
- std::wstring title;
- };
-
// The current profile.
Profile* profile_;
@@ -81,6 +63,7 @@ class PossibleURLModel : public TableModel {
CancelableRequestConsumerT<size_t, NULL> consumer_;
// The results we're showing.
+ struct Result;
std::vector<Result> results_;
// Map Result::index -> Favicon.
diff --git a/chrome/browser/power_save_blocker.h b/chrome/browser/power_save_blocker.h
index f362915..72ebc50 100644
--- a/chrome/browser/power_save_blocker.h
+++ b/chrome/browser/power_save_blocker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_POWER_SAVE_BLOCKER_H_
#define CHROME_BROWSER_POWER_SAVE_BLOCKER_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/power_save_blocker_stub.cc b/chrome/browser/power_save_blocker_stub.cc
index b1d695d..a509e63 100644
--- a/chrome/browser/power_save_blocker_stub.cc
+++ b/chrome/browser/power_save_blocker_stub.cc
@@ -1,11 +1,9 @@
-// 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.
#include "chrome/browser/power_save_blocker.h"
-#include "base/logging.h"
-
// Default, stub implementation, for platforms that don't have their own yet.
void PowerSaveBlocker::ApplyBlock(bool blocking) {
diff --git a/chrome/browser/pref_value_store.cc b/chrome/browser/pref_value_store.cc
deleted file mode 100644
index 0988b9c..0000000
--- a/chrome/browser/pref_value_store.cc
+++ /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.
-
-#include "chrome/browser/pref_value_store.h"
-
-PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
- PrefStore* extension_prefs,
- PrefStore* command_line_prefs,
- PrefStore* user_prefs,
- PrefStore* recommended_prefs) {
- pref_stores_[MANAGED].reset(managed_prefs);
- pref_stores_[EXTENSION].reset(extension_prefs);
- pref_stores_[COMMAND_LINE].reset(command_line_prefs);
- pref_stores_[USER].reset(user_prefs);
- pref_stores_[RECOMMENDED].reset(recommended_prefs);
-}
-
-PrefValueStore::~PrefValueStore() { }
-
-bool PrefValueStore::GetValue(const std::wstring& 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 <= PREF_STORE_TYPE_MAX; ++i) {
- if (pref_stores_[i].get() &&
- pref_stores_[i]->prefs()->Get(name.c_str(), out_value)) {
- return true;
- }
- }
- // No value found for the given preference name, set the return false.
- *out_value = NULL;
- return false;
-}
-
-bool PrefValueStore::WritePrefs() {
- bool success = true;
- for (size_t i = 0; i <= 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 <= 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 <= 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;
- }
- }
- // TODO(markusheintz): Return a better error status: maybe a struct with
- // the error status of all PrefStores.
- return result;
-}
-
-bool PrefValueStore::HasPrefPath(const wchar_t* path) const {
- Value* tmp_value = NULL;
- const std::wstring name(path);
- bool rv = GetValue(name, &tmp_value);
- return rv;
-}
-
-// Note the |DictionaryValue| referenced by the |PrefStore| user_prefs_
-// (returned by the method prefs()) takes the ownership of the Value referenced
-// by in_value.
-void PrefValueStore::SetUserPrefValue(const wchar_t* name, Value* in_value) {
- pref_stores_[USER]->prefs()->Set(name, in_value);
-}
-
-bool PrefValueStore::ReadOnly() {
- return pref_stores_[USER]->ReadOnly();
-}
-
-void PrefValueStore::RemoveUserPrefValue(const wchar_t* name) {
- if (pref_stores_[USER].get()) {
- pref_stores_[USER]->prefs()->Remove(name, NULL);
- }
-}
-
-bool PrefValueStore::PrefValueInManagedStore(const wchar_t* name) {
- return PrefValueInStore(name, MANAGED);
-}
-
-bool PrefValueStore::PrefValueInExtensionStore(const wchar_t* name) {
- return PrefValueInStore(name, EXTENSION);
-}
-
-bool PrefValueStore::PrefValueInUserStore(const wchar_t* name) {
- return PrefValueInStore(name, USER);
-}
-
-bool PrefValueStore::PrefValueFromExtensionStore(const wchar_t* name) {
- return ControllingPrefStoreForPref(name) == EXTENSION;
-}
-
-bool PrefValueStore::PrefValueFromUserStore(const wchar_t* name) {
- return ControllingPrefStoreForPref(name) == USER;
-}
-
-bool PrefValueStore::PrefValueUserModifiable(const wchar_t* name) {
- PrefStoreType effective_store = ControllingPrefStoreForPref(name);
- return effective_store >= USER || effective_store == INVALID;
-}
-
-bool PrefValueStore::PrefValueInStore(const wchar_t* name, PrefStoreType type) {
- if (pref_stores_[type].get() == NULL) {
- // No store of that type set, so this pref can't be in it.
- return false;
- }
- Value* tmp_value;
- return pref_stores_[type]->prefs()->Get(name, &tmp_value);
-}
-
-PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
- const wchar_t* name) {
- for (int i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
- if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
- return static_cast<PrefStoreType>(i);
- }
- return INVALID;
-}
diff --git a/chrome/browser/pref_value_store.h b/chrome/browser/pref_value_store.h
deleted file mode 100644
index 9dcce64..0000000
--- a/chrome/browser/pref_value_store.h
+++ /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.
-
-#ifndef CHROME_BROWSER_PREF_VALUE_STORE_H_
-#define CHROME_BROWSER_PREF_VALUE_STORE_H_
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/string16.h"
-#include "base/scoped_ptr.h"
-#include "base/values.h"
-#include "chrome/common/pref_store.h"
-
-class PrefStore;
-
-// The class PrefValueStore provides values for preferences. Each Preference
-// has a unique name. This name is used to retrieve the value of a Preference.
-// The value of a preference can be either managed, user-defined or recommended.
-// Managed preference values are set (managed) by a third person (like an
-// admin for example). They have the highest priority and can not be
-// altered by the user.
-// User-defined values are chosen by the user. If there is already
-// a managed value for a preference the user-defined value is ignored and
-// the managed value is used (returned).
-// Otherwise user-defined values have a higher precedence than recommended
-// values. Recommended preference values are set by a third person
-// (like an admin).
-class PrefValueStore {
- public:
- // In decreasing order of precedence:
- // |managed_prefs| contains all managed (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.
- PrefValueStore(PrefStore* managed_prefs,
- PrefStore* extension_prefs,
- PrefStore* command_line_prefs,
- PrefStore* user_prefs,
- PrefStore* recommended_prefs);
-
- ~PrefValueStore();
-
- // Get the preference value for the given preference name.
- // Return true if a value for the given preference name was found.
- bool GetValue(const std::wstring& name, Value** out_value) 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.
- bool HasPrefPath(const wchar_t* name) const;
-
- // Returns true if the PrefValueStore is read-only.
- // Because the managed 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.
- void SetUserPrefValue(const wchar_t* name, Value* in_value);
-
- // Removes a value from the PrefValueStore. If a preference is managed
- // or recommended this function should have no effect.
- void RemoveUserPrefValue(const wchar_t* name);
-
- // 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.
- bool PrefValueInManagedStore(const wchar_t* name);
- bool PrefValueInExtensionStore(const wchar_t* name);
- bool PrefValueInUserStore(const wchar_t* name);
-
- // 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.
- bool PrefValueFromExtensionStore(const wchar_t* name);
- bool PrefValueFromUserStore(const wchar_t* name);
-
- // Check whether a Preference value is modifiable by the user, i.e. whether
- // there is no higher-priority source controlling it.
- bool PrefValueUserModifiable(const wchar_t* name);
-
- private:
- // PrefStores must be listed here in order from highest to lowest priority.
- enum PrefStoreType {
- // Not associated with an actual PrefStore but used as invalid marker, e.g.
- // as return value.
- INVALID = -1,
- MANAGED = 0,
- EXTENSION,
- COMMAND_LINE,
- USER,
- RECOMMENDED,
- PREF_STORE_TYPE_MAX = RECOMMENDED
- };
-
- scoped_ptr<PrefStore> pref_stores_[PREF_STORE_TYPE_MAX + 1];
-
- bool PrefValueInStore(const wchar_t* name, PrefStoreType type);
-
- // Returns the pref store type identifying the source that controls the
- // Preference identified by |name|. If none of the sources has a value,
- // INVALID is returned.
- PrefStoreType ControllingPrefStoreForPref(const wchar_t* name);
-
- DISALLOW_COPY_AND_ASSIGN(PrefValueStore);
-};
-
-#endif // CHROME_BROWSER_PREF_VALUE_STORE_H_
diff --git a/chrome/browser/pref_value_store_unittest.cc b/chrome/browser/pref_value_store_unittest.cc
deleted file mode 100644
index bd10e7b..0000000
--- a/chrome/browser/pref_value_store_unittest.cc
+++ /dev/null
@@ -1,430 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. 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/test/data/resource.h"
-#include "base/scoped_ptr.h"
-#include "base/values.h"
-#include "chrome/browser/dummy_pref_store.h"
-#include "chrome/browser/pref_value_store.h"
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::Mock;
-
-// Names of the preferences used in this test program.
-namespace prefs {
- const wchar_t kCurrentThemeID[] = L"extensions.theme.id";
- const wchar_t kDeleteCache[] = L"browser.clear_data.cache";
- const wchar_t kHomepage[] = L"homepage";
- const wchar_t kMaxTabs[] = L"tabs.max_tabs";
- const wchar_t kMissingPref[] = L"this.pref.does_not_exist";
- const wchar_t kRecommendedPref[] = L"this.pref.recommended_value_only";
- const wchar_t kSampleDict[] = L"sample.dict";
- const wchar_t kSampleList[] = L"sample.list";
-
- // This must match the actual pref name so the command-line store knows about
- // it.
- const wchar_t kApplicationLocale[] = L"intl.app_locale";
-}
-
-// Potentailly expected values of all preferences used in this test program.
-// The "user" namespace is defined globally in an ARM system header, so we need
-// something different here.
-namespace user_pref {
- const int kMaxTabsValue = 31;
- const bool kDeleteCacheValue = true;
- const std::wstring kCurrentThemeIDValue = L"abcdefg";
- const std::wstring kHomepageValue = L"http://www.google.com";
- const std::wstring kApplicationLocaleValue = L"is-WRONG";
-}
-
-namespace enforced_pref {
- const std::wstring kHomepageValue = L"http://www.topeka.com";
-}
-
-namespace extension_pref {
- const std::wstring kCurrentThemeIDValue = L"set by extension";
- const std::wstring kHomepageValue = L"http://www.chromium.org";
-}
-
-namespace command_line_pref {
- const std::wstring kApplicationLocaleValue = L"hi-MOM";
- const std::wstring kCurrentThemeIDValue = L"zyxwvut";
- const std::wstring kHomepageValue = L"http://www.ferretcentral.org";
-}
-
-namespace recommended_pref {
- const int kMaxTabsValue = 10;
- const bool kRecommendedPrefValue = true;
-}
-
-class PrefValueStoreTest : public testing::Test {
- protected:
- scoped_ptr<PrefValueStore> pref_value_store_;
-
- // |PrefStore|s are owned by the |PrefValueStore|.
- DummyPrefStore* enforced_pref_store_;
- DummyPrefStore* extension_pref_store_;
- DummyPrefStore* command_line_pref_store_;
- DummyPrefStore* recommended_pref_store_;
- DummyPrefStore* user_pref_store_;
-
- // Preferences are owned by the individual |DummyPrefStores|.
- DictionaryValue* enforced_prefs_;
- DictionaryValue* extension_prefs_;
- DictionaryValue* command_line_prefs_;
- DictionaryValue* user_prefs_;
- DictionaryValue* recommended_prefs_;
-
- virtual void SetUp() {
- // Create dummy user preferences.
- enforced_prefs_= CreateEnforcedPrefs();
- extension_prefs_ = CreateExtensionPrefs();
- command_line_prefs_ = CreateCommandLinePrefs();
- user_prefs_ = CreateUserPrefs();
- recommended_prefs_ = CreateRecommendedPrefs();
-
- // Create |DummyPrefStore|s.
- enforced_pref_store_ = new DummyPrefStore();
- enforced_pref_store_->set_prefs(enforced_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_);
-
- // Create a new pref-value-store.
- pref_value_store_.reset(new PrefValueStore(enforced_pref_store_,
- extension_pref_store_,
- command_line_pref_store_,
- user_pref_store_,
- recommended_pref_store_));
- }
-
- // 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::kMaxTabs, user_pref::kMaxTabsValue);
- user_prefs->SetString(prefs::kCurrentThemeID,
- user_pref::kCurrentThemeIDValue);
- user_prefs->SetString(prefs::kApplicationLocale,
- user_pref::kApplicationLocaleValue);
- user_prefs->SetString(prefs::kHomepage, user_pref::kHomepageValue);
- return user_prefs;
- }
-
- DictionaryValue* CreateEnforcedPrefs() {
- DictionaryValue* enforced_prefs = new DictionaryValue();
- enforced_prefs->SetString(prefs::kHomepage, enforced_pref::kHomepageValue);
- return enforced_prefs;
- }
-
- DictionaryValue* CreateExtensionPrefs() {
- DictionaryValue* extension_prefs = new DictionaryValue();
- extension_prefs->SetString(prefs::kCurrentThemeID,
- extension_pref::kCurrentThemeIDValue);
- extension_prefs->SetString(prefs::kHomepage,
- extension_pref::kHomepageValue);
- return extension_prefs;
- }
-
- DictionaryValue* CreateCommandLinePrefs() {
- DictionaryValue* command_line_prefs = new DictionaryValue();
- command_line_prefs->SetString(prefs::kCurrentThemeID,
- command_line_pref::kCurrentThemeIDValue);
- command_line_prefs->SetString(prefs::kApplicationLocale,
- command_line_pref::kApplicationLocaleValue);
- command_line_prefs->SetString(prefs::kHomepage,
- command_line_pref::kHomepageValue);
- return command_line_prefs;
- }
-
- DictionaryValue* CreateRecommendedPrefs() {
- DictionaryValue* recommended_prefs = new DictionaryValue();
- recommended_prefs->SetInteger(prefs::kMaxTabs,
- recommended_pref::kMaxTabsValue);
- recommended_prefs->SetBoolean(
- prefs::kRecommendedPref,
- recommended_pref::kRecommendedPrefValue);
- return recommended_prefs; }
-
- DictionaryValue* CreateSampleDictValue() {
- DictionaryValue* sample_dict = new DictionaryValue();
- sample_dict->SetBoolean(L"issample", true);
- sample_dict->SetInteger(L"value", 4);
- sample_dict->SetString(L"descr", L"Sample Test Dictionary");
- return sample_dict;
- }
-
- ListValue* CreateSampleListValue() {
- ListValue* sample_list = new ListValue();
- sample_list->Set(0, Value::CreateIntegerValue(0));
- sample_list->Set(1, Value::CreateIntegerValue(1));
- sample_list->Set(2, Value::CreateIntegerValue(2));
- sample_list->Set(3, Value::CreateIntegerValue(3));
- return sample_list;
- }
-
- virtual void TearDown() {}
-};
-
-
-TEST_F(PrefValueStoreTest, IsReadOnly) {
- enforced_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);
- 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;
-
- // Test getting an enforced value overwriting a user-defined and
- // extension-defined value.
- value = NULL;
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomepage, &value));
- std::wstring actual_str_value;
- EXPECT_TRUE(value->GetAsString(&actual_str_value));
- EXPECT_EQ(enforced_pref::kHomepageValue, actual_str_value);
-
- // Test getting an extension value overwriting a user-defined and
- // command-line-defined value.
- value = NULL;
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kCurrentThemeID, &value));
- EXPECT_TRUE(value->GetAsString(&actual_str_value));
- EXPECT_EQ(extension_pref::kCurrentThemeIDValue, actual_str_value);
-
- // Test getting a command-line value overwriting a user-defined value.
- value = NULL;
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kApplicationLocale, &value));
- EXPECT_TRUE(value->GetAsString(&actual_str_value));
- EXPECT_EQ(command_line_pref::kApplicationLocaleValue, actual_str_value);
-
- // Test getting a user-set value.
- value = NULL;
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kDeleteCache, &value));
- bool actual_bool_value = false;
- EXPECT_TRUE(value->GetAsBoolean(&actual_bool_value));
- EXPECT_EQ(user_pref::kDeleteCacheValue, actual_bool_value);
-
- // Test getting a user set value overwriting a recommended value.
- value = NULL;
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kMaxTabs, &value));
- int actual_int_value = -1;
- EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
- EXPECT_EQ(user_pref::kMaxTabsValue, actual_int_value);
-
- // Test getting a recommended value.
- value = NULL;
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kRecommendedPref, &value));
- actual_bool_value = false;
- EXPECT_TRUE(value->GetAsBoolean(&actual_bool_value));
- EXPECT_EQ(recommended_pref::kRecommendedPrefValue, actual_bool_value);
-
- // Test getting a preference value that the |PrefValueStore|
- // does not contain.
- FundamentalValue tmp_dummy_value(true);
- Value* v_null = &tmp_dummy_value;
- ASSERT_FALSE(pref_value_store_->GetValue(prefs::kMissingPref, &v_null));
- ASSERT_TRUE(v_null == NULL);
-}
-
-TEST_F(PrefValueStoreTest, HasPrefPath) {
- // Enforced preference
- EXPECT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
- // User preference
- EXPECT_TRUE(pref_value_store_->HasPrefPath(prefs::kDeleteCache));
- // Recommended preference
- EXPECT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
- // Unknown preference
- EXPECT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
-}
-
-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));
-}
-
-TEST_F(PrefValueStoreTest, WritePrefs) {
- user_pref_store_->set_prefs_written(false);
- pref_value_store_->WritePrefs();
- ASSERT_TRUE(user_pref_store_->get_prefs_written());
-}
-
-TEST_F(PrefValueStoreTest, SetUserPrefValue) {
- Value* new_value = NULL;
- Value* actual_value = NULL;
-
- // Test that enforced values can not be set.
- ASSERT_TRUE(pref_value_store_->PrefValueInManagedStore(prefs::kHomepage));
- // The Ownership is tranfered to |PrefValueStore|.
- new_value = Value::CreateStringValue(L"http://www.youtube.com");
- pref_value_store_->SetUserPrefValue(prefs::kHomepage, new_value);
-
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomepage, &actual_value));
- std::wstring value_str;
- actual_value->GetAsString(&value_str);
- ASSERT_EQ(enforced_pref::kHomepageValue, value_str);
-
- // User preferences values can be set
- ASSERT_FALSE(pref_value_store_->PrefValueInManagedStore(prefs::kMaxTabs));
- actual_value = NULL;
- pref_value_store_->GetValue(prefs::kMaxTabs, &actual_value);
- int int_value;
- EXPECT_TRUE(actual_value->GetAsInteger(&int_value));
- EXPECT_EQ(user_pref::kMaxTabsValue, int_value);
-
- new_value = Value::CreateIntegerValue(1);
- pref_value_store_->SetUserPrefValue(prefs::kMaxTabs, new_value);
- actual_value = NULL;
- pref_value_store_->GetValue(prefs::kMaxTabs, &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::wstring 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, PrefValueInManagedStore) {
- // Test an enforced preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
- EXPECT_TRUE(pref_value_store_->PrefValueInManagedStore(prefs::kHomepage));
-
- // Test an extension preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kCurrentThemeID));
- EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
- prefs::kCurrentThemeID));
-
- // Test a command-line preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kApplicationLocale));
- EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
- prefs::kApplicationLocale));
-
- // Test a user preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kMaxTabs));
- EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(prefs::kMaxTabs));
-
- // Test a preference from the recommended pref store.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
- EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
- prefs::kRecommendedPref));
-
- // Test a preference for which the PrefValueStore does not contain a value.
- ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
- EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(prefs::kMissingPref));
-}
-
-TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) {
- // Test an enforced preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
- EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(prefs::kHomepage));
- EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
- prefs::kHomepage));
-
- // Test an extension preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kCurrentThemeID));
- EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
- prefs::kCurrentThemeID));
- EXPECT_TRUE(pref_value_store_->PrefValueFromExtensionStore(
- prefs::kCurrentThemeID));
-
- // Test a command-line preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kApplicationLocale));
- EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
- prefs::kApplicationLocale));
- EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
- prefs::kApplicationLocale));
-
- // Test a user preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kMaxTabs));
- EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(prefs::kMaxTabs));
- EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(prefs::kMaxTabs));
-
- // Test a preference from the recommended pref store.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
- EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
- prefs::kRecommendedPref));
- EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
- prefs::kRecommendedPref));
-
- // Test a preference for which the PrefValueStore does not contain a value.
- ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
- EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
- prefs::kMissingPref));
- EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
- prefs::kMissingPref));
-}
-
-TEST_F(PrefValueStoreTest, PrefValueInUserStore) {
- // Test an enforced preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
- EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(prefs::kHomepage));
- EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(prefs::kHomepage));
-
- // Test an extension preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kCurrentThemeID));
- EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
- prefs::kCurrentThemeID));
- EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
- prefs::kCurrentThemeID));
-
- // Test a command-line preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kApplicationLocale));
- EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
- prefs::kApplicationLocale));
- EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
- prefs::kApplicationLocale));
-
- // Test a user preference.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kMaxTabs));
- EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(prefs::kMaxTabs));
- EXPECT_TRUE(pref_value_store_->PrefValueFromUserStore(prefs::kMaxTabs));
-
- // Test a preference from the recommended pref store.
- ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
- EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
- prefs::kRecommendedPref));
- EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
- prefs::kRecommendedPref));
-
- // Test a preference for which the PrefValueStore does not contain a value.
- ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
- EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(prefs::kMissingPref));
- EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(prefs::kMissingPref));
-}
diff --git a/chrome/browser/preferences_mac.h b/chrome/browser/preferences_mac.h
index 8c70ea1..34675f0 100644
--- a/chrome/browser/preferences_mac.h
+++ b/chrome/browser/preferences_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PREFERENCES_MAC_H_
#define CHROME_BROWSER_PREFERENCES_MAC_H_
+#pragma once
#include <CoreFoundation/CoreFoundation.h>
diff --git a/chrome/browser/preferences_mock_mac.cc b/chrome/browser/preferences_mock_mac.cc
index aa32a93..6d0f0a0 100644
--- a/chrome/browser/preferences_mock_mac.cc
+++ b/chrome/browser/preferences_mock_mac.cc
@@ -42,4 +42,3 @@ void MockPreferences::AddTestItem(CFStringRef key,
if (is_forced)
CFSetAddValue(forced_, key);
}
-
diff --git a/chrome/browser/preferences_mock_mac.h b/chrome/browser/preferences_mock_mac.h
index 6735ad1..c804776 100644
--- a/chrome/browser/preferences_mock_mac.h
+++ b/chrome/browser/preferences_mock_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PREFERENCES_MOCK_MAC_H_
#define CHROME_BROWSER_PREFERENCES_MOCK_MAC_H_
+#pragma once
#include "base/scoped_cftyperef.h"
#include "chrome/browser/preferences_mac.h"
diff --git a/chrome/browser/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 84c42c6..c737a63 100644
--- a/chrome/browser/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -2,29 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/browser_prefs.h"
+#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/background_contents_service.h"
+#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/cookie_modal_dialog.h"
#include "chrome/browser/debugger/devtools_manager.h"
+#include "chrome/browser/dom_ui/labs_ui.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/dom_ui/plugins_ui.h"
-#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/extensions/extension_dom_ui.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extensions_ui.h"
#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_prefs.h"
-#include "chrome/browser/google_url_tracker.h"
+#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/gtk/certificate_manager.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/labs.h"
#include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/net/chrome_url_request_context.h"
@@ -32,16 +34,17 @@
#include "chrome/browser/notifications/desktop_notification_service.h"
#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/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"
#include "chrome/browser/search_engines/keyword_editor_controller.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
-#include "chrome/browser/session_startup_pref.h"
#include "chrome/browser/ssl/ssl_manager.h"
-#include "chrome/browser/tabs/pinned_tab_codec.h"
+#include "chrome/browser/sync/signin_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/task_manager.h"
+#include "chrome/browser/tabs/pinned_tab_codec.h"
+#include "chrome/browser/task_manager/task_manager.h"
#include "chrome/browser/translate/translate_prefs.h"
#include "chrome/browser/upgrade_detector.h"
@@ -55,6 +58,8 @@
#endif
#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/cros_settings_provider_user.h"
+#include "chrome/browser/chromeos/login/apply_services_customization.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/preferences.h"
@@ -91,24 +96,29 @@ void RegisterLocalState(PrefService* local_state) {
AutoFillManager::RegisterBrowserPrefs(local_state);
#if defined(OS_CHROMEOS)
chromeos::UserManager::RegisterPrefs(local_state);
+ chromeos::UserCrosSettingsProvider::RegisterPrefs(local_state);
WizardController::RegisterPrefs(local_state);
chromeos::LanguageMenuButton::RegisterPrefs(local_state);
+ chromeos::ApplyServicesCustomization::RegisterPrefs(local_state);
#endif
}
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);
chrome_browser_net::RegisterUserPrefs(user_prefs);
- DownloadManager::RegisterUserPrefs(user_prefs);
+ DownloadPrefs::RegisterUserPrefs(user_prefs);
bookmark_utils::RegisterUserPrefs(user_prefs);
TabContents::RegisterUserPrefs(user_prefs);
TemplateURLPrepopulateData::RegisterUserPrefs(user_prefs);
ExtensionDOMUI::RegisterUserPrefs(user_prefs);
ExtensionsUI::RegisterUserPrefs(user_prefs);
+ if (about_labs::IsEnabled())
+ LabsUI::RegisterUserPrefs(user_prefs);
NewTabUI::RegisterUserPrefs(user_prefs);
PluginsUI::RegisterUserPrefs(user_prefs);
HostContentSettingsMap::RegisterUserPrefs(user_prefs);
@@ -130,7 +140,7 @@ void RegisterUserPrefs(PrefService* user_prefs) {
chromeos::Preferences::RegisterUserPrefs(user_prefs);
#endif
BackgroundContentsService::RegisterUserPrefs(user_prefs);
- CookiePromptModalDialog::RegisterUserPrefs(user_prefs);
+ SigninManager::RegisterUserPrefs(user_prefs);
}
} // namespace browser
diff --git a/chrome/browser/browser_prefs.h b/chrome/browser/prefs/browser_prefs.h
index ccdd5fc..ef109a4 100644
--- a/chrome/browser/browser_prefs.h
+++ b/chrome/browser/prefs/browser_prefs.h
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_BROWSER_PREFS_H__
-#define CHROME_BROWSER_BROWSER_PREFS_H__
+#ifndef CHROME_BROWSER_PREFS_BROWSER_PREFS_H__
+#define CHROME_BROWSER_PREFS_BROWSER_PREFS_H__
+#pragma once
class PrefService;
@@ -16,4 +17,4 @@ void RegisterUserPrefs(PrefService* user_prefs);
} // namespace browser
-#endif // CHROME_BROWSER_BROWSER_PREFS_H__
+#endif // CHROME_BROWSER_PREFS_BROWSER_PREFS_H__
diff --git a/chrome/browser/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc
index 26bd0d3..3331ed5 100644
--- a/chrome/browser/command_line_pref_store.cc
+++ b/chrome/browser/prefs/command_line_pref_store.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 "chrome/browser/command_line_pref_store.h"
+#include "chrome/browser/prefs/command_line_pref_store.h"
#include "app/app_switches.h"
+#include "base/logging.h"
#include "base/values.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/command_line_pref_store.h b/chrome/browser/prefs/command_line_pref_store.h
index d13c2fe..89e49ce 100644
--- a/chrome/browser/command_line_pref_store.h
+++ b/chrome/browser/prefs/command_line_pref_store.h
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_COMMAND_LINE_PREF_STORE_H_
-#define CHROME_BROWSER_COMMAND_LINE_PREF_STORE_H_
+#ifndef CHROME_BROWSER_PREFS_COMMAND_LINE_PREF_STORE_H_
+#define CHROME_BROWSER_PREFS_COMMAND_LINE_PREF_STORE_H_
+#pragma once
#include "base/basictypes.h"
#include "base/command_line.h"
@@ -36,7 +37,7 @@ class CommandLinePrefStore : public PrefStore {
struct StringSwitchToPreferenceMapEntry {
const char* switch_name;
- const wchar_t* preference_path;
+ const char* preference_path;
};
static const StringSwitchToPreferenceMapEntry string_switch_map_[];
@@ -44,7 +45,7 @@ class CommandLinePrefStore : public PrefStore {
// is present.
struct BooleanSwitchToPreferenceMapEntry {
const char* switch_name;
- const wchar_t* preference_path;
+ const char* preference_path;
bool set_value;
};
static const BooleanSwitchToPreferenceMapEntry boolean_switch_map_[];
@@ -56,4 +57,4 @@ class CommandLinePrefStore : public PrefStore {
DISALLOW_COPY_AND_ASSIGN(CommandLinePrefStore);
};
-#endif // CHROME_BROWSER_COMMAND_LINE_PREF_STORE_H_
+#endif // CHROME_BROWSER_PREFS_COMMAND_LINE_PREF_STORE_H_
diff --git a/chrome/browser/command_line_pref_store_unittest.cc b/chrome/browser/prefs/command_line_pref_store_unittest.cc
index eb5dab4..c6d2bd2 100644
--- a/chrome/browser/command_line_pref_store_unittest.cc
+++ b/chrome/browser/prefs/command_line_pref_store_unittest.cc
@@ -8,7 +8,7 @@
#include "base/command_line.h"
#include "base/string_util.h"
#include "base/values.h"
-#include "chrome/browser/command_line_pref_store.h"
+#include "chrome/browser/prefs/command_line_pref_store.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -24,15 +24,15 @@ class TestCommandLinePrefStore : public CommandLinePrefStore {
}
};
-static const wchar_t* unknown_bool = L"unknown_switch";
-static const wchar_t* unknown_string = L"unknown_other_switch";
+const char unknown_bool[] = "unknown_switch";
+const char unknown_string[] = "unknown_other_switch";
} // namespace
// Tests a simple string pref on the command line.
TEST(CommandLinePrefStoreTest, SimpleStringPref) {
CommandLine cl(CommandLine::ARGUMENTS_ONLY);
- cl.AppendSwitchWithValue(switches::kLang, "hi-MOM");
+ cl.AppendSwitchASCII(switches::kLang, "hi-MOM");
CommandLinePrefStore store(&cl);
EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
@@ -56,8 +56,8 @@ TEST(CommandLinePrefStoreTest, SimpleBooleanPref) {
// Tests a command line with no recognized prefs.
TEST(CommandLinePrefStoreTest, NoPrefs) {
CommandLine cl(CommandLine::ARGUMENTS_ONLY);
- cl.AppendSwitch(WideToASCII(unknown_string));
- cl.AppendSwitchWithValue(WideToASCII(unknown_bool), "a value");
+ cl.AppendSwitch(unknown_string);
+ cl.AppendSwitchASCII(unknown_bool, "a value");
CommandLinePrefStore store(&cl);
EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
@@ -73,11 +73,11 @@ TEST(CommandLinePrefStoreTest, NoPrefs) {
// Tests a complex command line with multiple known and unknown switches.
TEST(CommandLinePrefStoreTest, MultipleSwitches) {
CommandLine cl(CommandLine::ARGUMENTS_ONLY);
- cl.AppendSwitch(WideToASCII(unknown_string));
+ cl.AppendSwitch(unknown_string);
cl.AppendSwitch(switches::kProxyAutoDetect);
- cl.AppendSwitchWithValue(switches::kProxyServer, "proxy");
- cl.AppendSwitchWithValue(switches::kProxyBypassList, "list");
- cl.AppendSwitchWithValue(WideToASCII(unknown_bool), "a value");
+ 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);
@@ -121,9 +121,9 @@ TEST(CommandLinePrefStoreTest, ProxySwitchValidation) {
// All proxy switches except no-proxy.
CommandLine cl2(CommandLine::ARGUMENTS_ONLY);
cl2.AppendSwitch(switches::kProxyAutoDetect);
- cl2.AppendSwitchWithValue(switches::kProxyServer, "server");
- cl2.AppendSwitchWithValue(switches::kProxyPacUrl, "url");
- cl2.AppendSwitchWithValue(switches::kProxyBypassList, "list");
+ cl2.AppendSwitchASCII(switches::kProxyServer, "server");
+ 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());
diff --git a/chrome/browser/prefs/default_pref_store.cc b/chrome/browser/prefs/default_pref_store.cc
new file mode 100644
index 0000000..6b0aa71
--- /dev/null
+++ b/chrome/browser/prefs/default_pref_store.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/prefs/default_pref_store.h"
+
+#include "base/values.h"
+
+DefaultPrefStore::DefaultPrefStore() : prefs_(new DictionaryValue()) {
+}
+
+DefaultPrefStore::~DefaultPrefStore() {
+}
+
+DictionaryValue* DefaultPrefStore::prefs() {
+ 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
new file mode 100644
index 0000000..b137936
--- /dev/null
+++ b/chrome/browser/prefs/default_pref_store.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_PREFS_DEFAULT_PREF_STORE_H_
+#define CHROME_BROWSER_PREFS_DEFAULT_PREF_STORE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/pref_store.h"
+
+// This PrefStore keeps track of default preference values set when a
+// preference is registered with the PrefService.
+class DefaultPrefStore : public PrefStore {
+ public:
+ DefaultPrefStore();
+ virtual ~DefaultPrefStore();
+
+ // PrefStore methods:
+ virtual DictionaryValue* prefs();
+ virtual PrefStore::PrefReadError ReadPrefs();
+
+ private:
+ // The default preference values.
+ scoped_ptr<DictionaryValue> prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore);
+};
+
+#endif // CHROME_BROWSER_PREFS_DEFAULT_PREF_STORE_H_
diff --git a/chrome/browser/dummy_pref_store.cc b/chrome/browser/prefs/dummy_pref_store.cc
index 7b3cd0a..3a0a81a 100644
--- a/chrome/browser/dummy_pref_store.cc
+++ b/chrome/browser/prefs/dummy_pref_store.cc
@@ -2,7 +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/dummy_pref_store.h"
+#include "chrome/browser/prefs/dummy_pref_store.h"
+
+#include "base/values.h"
DummyPrefStore::DummyPrefStore()
: prefs_(new DictionaryValue()),
@@ -18,4 +20,3 @@ bool DummyPrefStore::WritePrefs() {
prefs_written_ = true;
return prefs_written_;
}
-
diff --git a/chrome/browser/dummy_pref_store.h b/chrome/browser/prefs/dummy_pref_store.h
index 8103763..ebf92fc 100644
--- a/chrome/browser/dummy_pref_store.h
+++ b/chrome/browser/prefs/dummy_pref_store.h
@@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_DUMMY_PREF_STORE_H_
-#define CHROME_BROWSER_DUMMY_PREF_STORE_H_
+#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 "base/values.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|.
@@ -46,4 +47,4 @@ class DummyPrefStore : public PrefStore {
DISALLOW_COPY_AND_ASSIGN(DummyPrefStore);
};
-#endif // CHROME_BROWSER_DUMMY_PREF_STORE_H_
+#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
new file mode 100644
index 0000000..05372b1
--- /dev/null
+++ b/chrome/browser/prefs/pref_change_registrar.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 "chrome/browser/prefs/pref_change_registrar.h"
+
+#include "chrome/browser/prefs/pref_service.h"
+
+PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {}
+
+PrefChangeRegistrar::~PrefChangeRegistrar() {
+ RemoveAll();
+}
+
+void PrefChangeRegistrar::Init(PrefService* service) {
+ DCHECK(IsEmpty() || service_ == service);
+ service_ = service;
+}
+
+void PrefChangeRegistrar::Add(const char* path, NotificationObserver* obs) {
+ if (!service_) {
+ NOTREACHED();
+ return;
+ }
+ ObserverRegistration registration(path, obs);
+ if (observers_.find(registration) != observers_.end()) {
+ NOTREACHED();
+ return;
+ }
+ observers_.insert(registration);
+ service_->AddPrefObserver(path, obs);
+}
+
+void PrefChangeRegistrar::Remove(const char* path, NotificationObserver* obs) {
+ if (!service_) {
+ NOTREACHED();
+ return;
+ }
+ ObserverRegistration registration(path, obs);
+ std::set<ObserverRegistration>::iterator it =
+ observers_.find(registration);
+ if (it == observers_.end()) {
+ NOTREACHED();
+ return;
+ }
+ service_->RemovePrefObserver(it->first.c_str(), it->second);
+ observers_.erase(it);
+}
+
+void PrefChangeRegistrar::RemoveAll() {
+ if (service_) {
+ for (std::set<ObserverRegistration>::const_iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ service_->RemovePrefObserver(it->first.c_str(), it->second);
+ }
+ observers_.clear();
+ }
+}
+
+bool PrefChangeRegistrar::IsEmpty() const {
+ return observers_.empty();
+}
diff --git a/chrome/browser/prefs/pref_change_registrar.h b/chrome/browser/prefs/pref_change_registrar.h
new file mode 100644
index 0000000..773c556
--- /dev/null
+++ b/chrome/browser/prefs/pref_change_registrar.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_PREFS_PREF_CHANGE_REGISTRAR_H_
+#define CHROME_BROWSER_PREFS_PREF_CHANGE_REGISTRAR_H_
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+
+class PrefService;
+class NotificationObserver;
+
+// Automatically manages the registration of one or more pref change observers
+// with a PrefStore. Functions much like NotificationRegistrar, but specifically
+// manages observers of preference changes. When the Registrar is destroyed,
+// all registered observers are automatically unregistered with the PrefStore.
+class PrefChangeRegistrar {
+ public:
+ PrefChangeRegistrar();
+ virtual ~PrefChangeRegistrar();
+
+ // Must be called before adding or removing observers. Can be called more
+ // than once as long as the value of |service| doesn't change.
+ void Init(PrefService* service);
+
+ // Adds an pref observer for the specified pref |path| and |obs| observer
+ // object. All registered observers will be automatically unregistered
+ // when the registrar's destructor is called unless the observer has been
+ // explicitly removed by a call to Remove beforehand.
+ void Add(const char* path,
+ NotificationObserver* obs);
+
+ // Removes a preference observer that has previously been added with a call to
+ // Add.
+ void Remove(const char* path,
+ NotificationObserver* obs);
+
+ // Removes all observers that have been previously added with a call to Add.
+ void RemoveAll();
+
+ // Returns true if no pref observers are registered.
+ bool IsEmpty() const;
+
+ private:
+ typedef std::pair<std::string, NotificationObserver*> ObserverRegistration;
+
+ std::set<ObserverRegistration> observers_;
+ PrefService* service_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefChangeRegistrar);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_CHANGE_REGISTRAR_H_
diff --git a/chrome/browser/prefs/pref_change_registrar_unittest.cc b/chrome/browser/prefs/pref_change_registrar_unittest.cc
new file mode 100644
index 0000000..8096ee6
--- /dev/null
+++ b/chrome/browser/prefs/pref_change_registrar_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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_change_registrar.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_source.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::Mock;
+using testing::Eq;
+
+// A mock provider that allows us to capture pref observer changes.
+class MockPrefService : public TestingPrefService {
+ public:
+ MockPrefService() {}
+ virtual ~MockPrefService() {};
+
+ MOCK_METHOD2(AddPrefObserver, void(const char*, NotificationObserver*));
+ 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));
+};
+
+class PrefChangeRegistrarTest : public testing::Test {
+ public:
+ PrefChangeRegistrarTest() {}
+ virtual ~PrefChangeRegistrarTest() {}
+
+ protected:
+ virtual void SetUp();
+
+ NotificationObserver* observer() const { return observer_.get(); }
+ MockPrefService* service() const { return service_.get(); }
+
+ private:
+ scoped_ptr<MockPrefService> service_;
+ scoped_ptr<MockObserver> observer_;
+};
+
+void PrefChangeRegistrarTest::SetUp() {
+ service_.reset(new MockPrefService());
+ observer_.reset(new MockObserver());
+}
+
+TEST_F(PrefChangeRegistrarTest, AddAndRemove) {
+ PrefChangeRegistrar registrar;
+ registrar.Init(service());
+
+ // Test adding.
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.Add("test.pref.1", observer());
+ registrar.Add("test.pref.2", observer());
+ EXPECT_FALSE(registrar.IsEmpty());
+
+ // Test removing.
+ Mock::VerifyAndClearExpectations(service());
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.Remove("test.pref.1", observer());
+ registrar.Remove("test.pref.2", observer());
+ EXPECT_TRUE(registrar.IsEmpty());
+
+ // Explicitly check the expectations now to make sure that the Removes
+ // worked (rather than the registrar destructor doing the work).
+ Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(PrefChangeRegistrarTest, AutoRemove) {
+ PrefChangeRegistrar registrar;
+ registrar.Init(service());
+
+ // Setup of auto-remove.
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+ registrar.Add("test.pref.1", observer());
+ Mock::VerifyAndClearExpectations(service());
+ EXPECT_FALSE(registrar.IsEmpty());
+
+ // Test auto-removing.
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+}
+
+TEST_F(PrefChangeRegistrarTest, RemoveAll) {
+ PrefChangeRegistrar registrar;
+ registrar.Init(service());
+
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ AddPrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.Add("test.pref.1", observer());
+ registrar.Add("test.pref.2", observer());
+ Mock::VerifyAndClearExpectations(service());
+
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.1")), observer()));
+ EXPECT_CALL(*service(),
+ RemovePrefObserver(Eq(std::string("test.pref.2")), observer()));
+ registrar.RemoveAll();
+ EXPECT_TRUE(registrar.IsEmpty());
+
+ // Explicitly check the expectations now to make sure that the RemoveAll
+ // worked (rather than the registrar destructor doing the work).
+ Mock::VerifyAndClearExpectations(service());
+}
diff --git a/chrome/browser/pref_member.cc b/chrome/browser/prefs/pref_member.cc
index 9502022..cc14384 100644
--- a/chrome/browser/pref_member.cc
+++ b/chrome/browser/prefs/pref_member.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "base/logging.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/notification_type.h"
namespace subtle {
@@ -23,7 +23,7 @@ PrefMemberBase::~PrefMemberBase() {
}
-void PrefMemberBase::Init(const wchar_t* pref_name, PrefService* prefs,
+void PrefMemberBase::Init(const char* pref_name, PrefService* prefs,
NotificationObserver* observer) {
DCHECK(pref_name);
DCHECK(prefs);
@@ -37,7 +37,7 @@ void PrefMemberBase::Init(const wchar_t* pref_name, PrefService* prefs,
prefs_->AddPrefObserver(pref_name, this);
}
-bool PrefMemberBase::IsManaged() {
+bool PrefMemberBase::IsManaged() const {
DCHECK(!pref_name_.empty());
const PrefService::Preference* pref =
prefs_->FindPreference(pref_name_.c_str());
@@ -55,7 +55,7 @@ void PrefMemberBase::Observe(NotificationType type,
observer_->Observe(type, source, details);
}
-void PrefMemberBase::VerifyValuePrefName() {
+void PrefMemberBase::VerifyValuePrefName() const {
DCHECK(!pref_name_.empty());
}
@@ -67,7 +67,7 @@ BooleanPrefMember::BooleanPrefMember() : PrefMember<bool>() {
BooleanPrefMember::~BooleanPrefMember() {
}
-void BooleanPrefMember::UpdateValueFromPref() {
+void BooleanPrefMember::UpdateValueFromPref() const {
value_ = prefs()->GetBoolean(pref_name().c_str());
}
@@ -81,7 +81,7 @@ IntegerPrefMember::IntegerPrefMember() : PrefMember<int>() {
IntegerPrefMember::~IntegerPrefMember() {
}
-void IntegerPrefMember::UpdateValueFromPref() {
+void IntegerPrefMember::UpdateValueFromPref() const {
value_ = prefs()->GetInteger(pref_name().c_str());
}
@@ -95,7 +95,7 @@ RealPrefMember::RealPrefMember() : PrefMember<double>() {
RealPrefMember::~RealPrefMember() {
}
-void RealPrefMember::UpdateValueFromPref() {
+void RealPrefMember::UpdateValueFromPref() const {
value_ = prefs()->GetReal(pref_name().c_str());
}
@@ -109,7 +109,7 @@ StringPrefMember::StringPrefMember() : PrefMember<std::string>() {
StringPrefMember::~StringPrefMember() {
}
-void StringPrefMember::UpdateValueFromPref() {
+void StringPrefMember::UpdateValueFromPref() const {
value_ = prefs()->GetString(pref_name().c_str());
}
@@ -123,7 +123,7 @@ FilePathPrefMember::FilePathPrefMember() : PrefMember<FilePath>() {
FilePathPrefMember::~FilePathPrefMember() {
}
-void FilePathPrefMember::UpdateValueFromPref() {
+void FilePathPrefMember::UpdateValueFromPref() const {
value_ = prefs()->GetFilePath(pref_name().c_str());
}
diff --git a/chrome/browser/pref_member.h b/chrome/browser/prefs/pref_member.h
index 1d84b6a..f5fc008 100644
--- a/chrome/browser/pref_member.h
+++ b/chrome/browser/prefs/pref_member.h
@@ -21,8 +21,9 @@
// notify MyClass of changes. Note that if you use SetValue(), the observer
// will not be notified.
-#ifndef CHROME_BROWSER_PREF_MEMBER_H_
-#define CHROME_BROWSER_PREF_MEMBER_H_
+#ifndef CHROME_BROWSER_PREFS_PREF_MEMBER_H_
+#define CHROME_BROWSER_PREFS_PREF_MEMBER_H_
+#pragma once
#include <string>
@@ -40,33 +41,36 @@ class PrefMemberBase : public NotificationObserver {
virtual ~PrefMemberBase();
// See PrefMember<> for description.
- void Init(const wchar_t* pref_name, PrefService* prefs,
+ void Init(const char* pref_name, PrefService* prefs,
NotificationObserver* observer);
// See PrefMember<> for description.
- bool IsManaged();
+ bool IsManaged() const;
// NotificationObserver
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
- void VerifyValuePrefName();
+ void VerifyValuePrefName() const;
// This methods is used to do the actual sync with pref of the specified type.
- virtual void UpdateValueFromPref() = 0;
+ // Note: this method is logically const, because it doesn't modify the state
+ // seen by the outside world. It is just doing a lazy load behind the scenes.
+ virtual void UpdateValueFromPref() const = 0;
- const std::wstring& pref_name() const { return pref_name_; }
+ const std::string& pref_name() const { return pref_name_; }
PrefService* prefs() { return prefs_; }
+ const PrefService* prefs() const { return prefs_; }
// Ordered the members to compact the class instance.
private:
- std::wstring pref_name_;
+ std::string pref_name_;
NotificationObserver* observer_;
PrefService* prefs_;
protected:
- bool is_synced_;
+ mutable bool is_synced_;
bool setting_value_;
};
@@ -83,7 +87,7 @@ class PrefMember : public subtle::PrefMemberBase {
// Do the actual initialization of the class. |observer| may be null if you
// don't want any notifications of changes.
- void Init(const wchar_t* pref_name, PrefService* prefs,
+ void Init(const char* pref_name, PrefService* prefs,
NotificationObserver* observer) {
subtle::PrefMemberBase::Init(pref_name, prefs, observer);
}
@@ -96,7 +100,7 @@ class PrefMember : public subtle::PrefMemberBase {
}
// Retrieve the value of the member variable.
- ValueType GetValue() {
+ ValueType GetValue() const {
VerifyValuePrefName();
// We lazily fetch the value from the pref service the first time GetValue
// is called.
@@ -108,7 +112,7 @@ class PrefMember : public subtle::PrefMemberBase {
}
// Provided as a convenience.
- ValueType operator*() {
+ ValueType operator*() const {
return GetValue();
}
@@ -133,7 +137,7 @@ class PrefMember : public subtle::PrefMemberBase {
// We cache the value of the pref so we don't have to keep walking the pref
// tree.
- ValueType value_;
+ mutable ValueType value_;
};
///////////////////////////////////////////////////////////////////////////////
@@ -145,7 +149,7 @@ class BooleanPrefMember : public PrefMember<bool> {
virtual ~BooleanPrefMember();
protected:
- virtual void UpdateValueFromPref();
+ virtual void UpdateValueFromPref() const;
virtual void UpdatePref(const bool& value);
private:
@@ -158,7 +162,7 @@ class IntegerPrefMember : public PrefMember<int> {
virtual ~IntegerPrefMember();
protected:
- virtual void UpdateValueFromPref();
+ virtual void UpdateValueFromPref() const;
virtual void UpdatePref(const int& value);
private:
@@ -171,7 +175,7 @@ class RealPrefMember : public PrefMember<double> {
virtual ~RealPrefMember();
protected:
- virtual void UpdateValueFromPref();
+ virtual void UpdateValueFromPref() const;
virtual void UpdatePref(const double& value);
private:
@@ -184,7 +188,7 @@ class StringPrefMember : public PrefMember<std::string> {
virtual ~StringPrefMember();
protected:
- virtual void UpdateValueFromPref();
+ virtual void UpdateValueFromPref() const;
virtual void UpdatePref(const std::string& value);
private:
@@ -197,11 +201,11 @@ class FilePathPrefMember : public PrefMember<FilePath> {
virtual ~FilePathPrefMember();
protected:
- virtual void UpdateValueFromPref();
+ virtual void UpdateValueFromPref() const;
virtual void UpdatePref(const FilePath& value);
private:
DISALLOW_COPY_AND_ASSIGN(FilePathPrefMember);
};
-#endif // CHROME_BROWSER_PREF_MEMBER_H_
+#endif // CHROME_BROWSER_PREFS_PREF_MEMBER_H_
diff --git a/chrome/browser/pref_member_unittest.cc b/chrome/browser/prefs/pref_member_unittest.cc
index b0379d6..f59f937 100644
--- a/chrome/browser/pref_member_unittest.cc
+++ b/chrome/browser/prefs/pref_member_unittest.cc
@@ -2,20 +2,19 @@
// 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 "chrome/browser/dummy_pref_store.h"
-#include "chrome/browser/pref_member.h"
-#include "chrome/browser/pref_value_store.h"
+#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/test/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-static const wchar_t kBoolPref[] = L"bool";
-static const wchar_t kIntPref[] = L"int";
-static const wchar_t kRealPref[] = L"real";
-static const wchar_t kStringPref[] = L"string";
+static const char kBoolPref[] = "bool";
+static const char kIntPref[] = "int";
+static const char kRealPref[] = "real";
+static const char kStringPref[] = "string";
void RegisterTestPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(kBoolPref, false);
@@ -37,7 +36,7 @@ class PrefMemberTestClass : public NotificationObserver {
DCHECK(NotificationType::PREF_CHANGED == type);
PrefService* prefs_in = Source<PrefService>(source).ptr();
EXPECT_EQ(prefs_in, prefs_);
- std::wstring* pref_name_in = Details<std::wstring>(details).ptr();
+ std::string* pref_name_in = Details<std::string>(details).ptr();
EXPECT_EQ(*pref_name_in, kStringPref);
EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref));
++observe_cnt_;
diff --git a/chrome/browser/prefs/pref_notifier.cc b/chrome/browser/prefs/pref_notifier.cc
new file mode 100644
index 0000000..3bb0628
--- /dev/null
+++ b/chrome/browser/prefs/pref_notifier.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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.
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ pref_value_store_,
+ &PrefValueStore::RefreshPolicyPrefs,
+ ConfigurationPolicyPrefStore::CreateManagedPolicyPrefStore(),
+ ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore(),
+ callback));
+ }
+}
diff --git a/chrome/browser/prefs/pref_notifier.h b/chrome/browser/prefs/pref_notifier.h
new file mode 100644
index 0000000..98dc1e3
--- /dev/null
+++ b/chrome/browser/prefs/pref_notifier.h
@@ -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.
+
+#ifndef CHROME_BROWSER_PREFS_PREF_NOTIFIER_H_
+#define CHROME_BROWSER_PREFS_PREF_NOTIFIER_H_
+#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 {
+ public:
+ // PrefStores must be listed here in order from highest to lowest priority.
+ // MANAGED contains all managed (policy) preference values.
+ // 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_STORE = 0,
+ 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);
+
+ // NotificationObserver methods:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ DISALLOW_COPY_AND_ASSIGN(PrefNotifier);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_NOTIFIER_H_
diff --git a/chrome/browser/prefs/pref_notifier_unittest.cc b/chrome/browser/prefs/pref_notifier_unittest.cc
new file mode 100644
index 0000000..0af137c
--- /dev/null
+++ b/chrome/browser/prefs/pref_notifier_unittest.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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, new DefaultPrefStore()) {}
+
+ 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_service.cc b/chrome/browser/prefs/pref_service.cc
new file mode 100644
index 0000000..0668ed4
--- /dev/null
+++ b/chrome/browser/prefs/pref_service.cc
@@ -0,0 +1,632 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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.h"
+
+#include <algorithm>
+#include <string>
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/histogram.h"
+#include "base/logging.h"
+#include "base/message_loop.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 "base/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/notification_service.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+// A helper function for RegisterLocalized*Pref that creates a Value* based on
+// the string value in the locale dll. Because we control the values in a
+// locale dll, this should always return a Value of the appropriate type.
+Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) {
+ std::string resource_string = l10n_util::GetStringUTF8(message_id);
+ DCHECK(!resource_string.empty());
+ switch (type) {
+ case Value::TYPE_BOOLEAN: {
+ if ("true" == resource_string)
+ return Value::CreateBooleanValue(true);
+ if ("false" == resource_string)
+ return Value::CreateBooleanValue(false);
+ break;
+ }
+
+ case Value::TYPE_INTEGER: {
+ int val;
+ base::StringToInt(resource_string, &val);
+ return Value::CreateIntegerValue(val);
+ }
+
+ case Value::TYPE_REAL: {
+ double val;
+ base::StringToDouble(resource_string, &val);
+ return Value::CreateRealValue(val);
+ }
+
+ case Value::TYPE_STRING: {
+ return Value::CreateStringValue(resource_string);
+ }
+
+ default: {
+ NOTREACHED() <<
+ "list and dictionary types cannot have default locale values";
+ }
+ }
+ NOTREACHED();
+ return Value::CreateNullValue();
+}
+
+// Forwards a notification after a PostMessage so that we can wait for the
+// MessageLoop to run.
+void NotifyReadError(PrefService* pref, int message_id) {
+ Source<PrefService> source(pref);
+ NotificationService::current()->Notify(NotificationType::PROFILE_ERROR,
+ source, Details<int>(&message_id));
+}
+
+} // namespace
+
+// static
+PrefService* PrefService::CreatePrefService(const FilePath& pref_filename,
+ Profile* profile) {
+#if defined(OS_LINUX)
+ // 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.
+ // TODO(evanm): remove this once we've collected state.
+ file_util::FileSystemType fstype;
+ if (file_util::GetFileSystemType(pref_filename.DirName(), &fstype)) {
+ UMA_HISTOGRAM_ENUMERATION("PrefService.FileSystemType",
+ static_cast<int>(fstype),
+ file_util::FILE_SYSTEM_TYPE_COUNT);
+ }
+#endif
+
+ return new PrefService(
+ PrefValueStore::CreatePrefValueStore(pref_filename, profile, false));
+}
+
+// static
+PrefService* PrefService::CreateUserPrefService(const FilePath& pref_filename) {
+ return new PrefService(
+ PrefValueStore::CreatePrefValueStore(pref_filename, NULL, true));
+}
+
+PrefService::PrefService(PrefValueStore* pref_value_store)
+ : pref_value_store_(pref_value_store) {
+ pref_notifier_.reset(new PrefNotifier(this, pref_value_store));
+ InitFromStorage();
+}
+
+PrefService::~PrefService() {
+ DCHECK(CalledOnValidThread());
+ STLDeleteContainerPointers(prefs_.begin(), prefs_.end());
+ prefs_.clear();
+}
+
+void PrefService::InitFromStorage() {
+ PrefStore::PrefReadError error = LoadPersistentPrefs();
+ if (error == PrefStore::PREF_READ_ERROR_NONE)
+ 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) {
+ message_id = IDS_PREFERENCES_CORRUPT_ERROR;
+ } else if (error != PrefStore::PREF_READ_ERROR_NO_FILE) {
+ message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
+ }
+
+ if (message_id) {
+ ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(&NotifyReadError, this, message_id));
+ }
+ UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 20);
+}
+
+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;
+}
+
+bool PrefService::SavePersistentPrefs() {
+ DCHECK(CalledOnValidThread());
+
+ return pref_value_store_->WritePrefs();
+}
+
+void PrefService::ScheduleSavePersistentPrefs() {
+ DCHECK(CalledOnValidThread());
+
+ pref_value_store_->ScheduleWritePrefs();
+}
+
+void PrefService::RegisterBooleanPref(const char* path,
+ bool default_value) {
+ RegisterPreference(path, Value::CreateBooleanValue(default_value));
+}
+
+void PrefService::RegisterIntegerPref(const char* path, int default_value) {
+ RegisterPreference(path, Value::CreateIntegerValue(default_value));
+}
+
+void PrefService::RegisterRealPref(const char* path, double default_value) {
+ RegisterPreference(path, Value::CreateRealValue(default_value));
+}
+
+void PrefService::RegisterStringPref(const char* path,
+ const std::string& default_value) {
+ RegisterPreference(path, Value::CreateStringValue(default_value));
+}
+
+void PrefService::RegisterFilePathPref(const char* path,
+ const FilePath& default_value) {
+ RegisterPreference(path, Value::CreateStringValue(default_value.value()));
+}
+
+void PrefService::RegisterListPref(const char* path) {
+ RegisterPreference(path, new ListValue());
+}
+
+void PrefService::RegisterDictionaryPref(const char* path) {
+ RegisterPreference(path, new DictionaryValue());
+}
+
+void PrefService::RegisterLocalizedBooleanPref(const char* path,
+ int locale_default_message_id) {
+ RegisterPreference(
+ path,
+ CreateLocaleDefaultValue(Value::TYPE_BOOLEAN, locale_default_message_id));
+}
+
+void PrefService::RegisterLocalizedIntegerPref(const char* path,
+ int locale_default_message_id) {
+ RegisterPreference(
+ path,
+ CreateLocaleDefaultValue(Value::TYPE_INTEGER, locale_default_message_id));
+}
+
+void PrefService::RegisterLocalizedRealPref(const char* path,
+ int locale_default_message_id) {
+ RegisterPreference(
+ path,
+ CreateLocaleDefaultValue(Value::TYPE_REAL, locale_default_message_id));
+}
+
+void PrefService::RegisterLocalizedStringPref(const char* path,
+ int locale_default_message_id) {
+ RegisterPreference(
+ path,
+ CreateLocaleDefaultValue(Value::TYPE_STRING, locale_default_message_id));
+}
+
+bool PrefService::GetBoolean(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ bool result = false;
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return result;
+ }
+ bool rv = pref->GetValue()->GetAsBoolean(&result);
+ DCHECK(rv);
+ return result;
+}
+
+int PrefService::GetInteger(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ int result = 0;
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return result;
+ }
+ bool rv = pref->GetValue()->GetAsInteger(&result);
+ DCHECK(rv);
+ return result;
+}
+
+double PrefService::GetReal(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ double result = 0.0;
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return result;
+ }
+ bool rv = pref->GetValue()->GetAsReal(&result);
+ DCHECK(rv);
+ return result;
+}
+
+std::string PrefService::GetString(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ std::string result;
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return result;
+ }
+ bool rv = pref->GetValue()->GetAsString(&result);
+ DCHECK(rv);
+ return result;
+}
+
+FilePath PrefService::GetFilePath(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ FilePath::StringType result;
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return FilePath(result);
+ }
+ bool rv = pref->GetValue()->GetAsString(&result);
+ DCHECK(rv);
+#if defined(OS_POSIX)
+ // We store filepaths as UTF8, so convert it back to the system type.
+ result = base::SysWideToNativeMB(UTF8ToWide(result));
+#endif
+ return FilePath(result);
+}
+
+bool PrefService::HasPrefPath(const char* path) const {
+ return pref_value_store_->HasPrefPath(path);
+}
+
+const PrefService::Preference* PrefService::FindPreference(
+ const char* pref_name) const {
+ DCHECK(CalledOnValidThread());
+ Preference p(this, pref_name);
+ PreferenceSet::const_iterator it = prefs_.find(&p);
+ return it == prefs_.end() ? NULL : *it;
+}
+
+bool PrefService::IsManagedPreference(const char* pref_name) const {
+ const Preference* pref = FindPreference(pref_name);
+ if (pref && pref->IsManaged()) {
+ return true;
+ }
+ return false;
+}
+
+const DictionaryValue* PrefService::GetDictionary(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return NULL;
+ }
+ const Value* value = pref->GetValue();
+ if (value->GetType() == Value::TYPE_NULL)
+ return NULL;
+ return static_cast<const DictionaryValue*>(value);
+}
+
+const ListValue* PrefService::GetList(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return NULL;
+ }
+ const Value* value = pref->GetValue();
+ if (value->GetType() == Value::TYPE_NULL)
+ return NULL;
+ return static_cast<const ListValue*>(value);
+}
+
+void PrefService::AddPrefObserver(const char* path,
+ NotificationObserver* obs) {
+ pref_notifier_->AddPrefObserver(path, obs);
+}
+
+void PrefService::RemovePrefObserver(const char* path,
+ NotificationObserver* obs) {
+ pref_notifier_->RemovePrefObserver(path, obs);
+}
+
+void PrefService::RegisterPreference(const char* path, Value* default_value) {
+ DCHECK(CalledOnValidThread());
+
+ // The main code path takes ownership, but most don't. We'll be safe.
+ scoped_ptr<Value> scoped_value(default_value);
+
+ if (FindPreference(path)) {
+ NOTREACHED() << "Tried to register duplicate pref " << path;
+ return;
+ }
+
+ Value::ValueType orig_type = default_value->GetType();
+ DCHECK(orig_type != Value::TYPE_NULL && orig_type != Value::TYPE_BINARY) <<
+ "invalid preference type: " << orig_type;
+
+ // We set the default value of dictionaries and lists to be null so it's
+ // 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());
+ } else {
+ // Hand off ownership.
+ pref_value_store_->SetDefaultPrefValue(path, scoped_value.release());
+ }
+
+ pref_value_store_->RegisterPreferenceType(path, orig_type);
+ prefs_.insert(new Preference(this, path));
+}
+
+void PrefService::ClearPref(const char* path) {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to clear an unregistered pref: " << path;
+ return;
+ }
+ if (pref_value_store_->RemoveUserPrefValue(path))
+ pref_notifier_->OnUserPreferenceSet(path);
+}
+
+void PrefService::Set(const char* path, const Value& value) {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to write an unregistered pref: " << path;
+ return;
+ }
+
+ // 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);
+ } 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());
+ }
+
+ if (value_changed)
+ pref_notifier_->OnUserPreferenceSet(path);
+}
+
+void PrefService::SetBoolean(const char* path, bool value) {
+ SetUserPrefValue(path, Value::CreateBooleanValue(value));
+}
+
+void PrefService::SetInteger(const char* path, int value) {
+ SetUserPrefValue(path, Value::CreateIntegerValue(value));
+}
+
+void PrefService::SetReal(const char* path, double value) {
+ SetUserPrefValue(path, Value::CreateRealValue(value));
+}
+
+void PrefService::SetString(const char* path, const std::string& value) {
+ SetUserPrefValue(path, Value::CreateStringValue(value));
+}
+
+void PrefService::SetFilePath(const char* path, const FilePath& value) {
+#if defined(OS_POSIX)
+ // Value::SetString only knows about UTF8 strings, so convert the path from
+ // the system native value to UTF8.
+ std::string path_utf8 = WideToUTF8(base::SysNativeMBToWide(value.value()));
+ Value* new_value = Value::CreateStringValue(path_utf8);
+#else
+ Value* new_value = Value::CreateStringValue(value.value());
+#endif
+
+ SetUserPrefValue(path, new_value);
+}
+
+void PrefService::SetInt64(const char* path, int64 value) {
+ SetUserPrefValue(path, Value::CreateStringValue(base::Int64ToString(value)));
+}
+
+int64 PrefService::GetInt64(const char* path) const {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return 0;
+ }
+ std::string result("0");
+ bool rv = pref->GetValue()->GetAsString(&result);
+ DCHECK(rv);
+
+ int64 val;
+ base::StringToInt64(result, &val);
+ return val;
+}
+
+void PrefService::RegisterInt64Pref(const char* path, int64 default_value) {
+ RegisterPreference(
+ path, Value::CreateStringValue(base::Int64ToString(default_value)));
+}
+
+DictionaryValue* PrefService::GetMutableDictionary(const char* path) {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to get an unregistered pref: " << path;
+ return NULL;
+ }
+ if (pref->GetType() != Value::TYPE_DICTIONARY) {
+ NOTREACHED() << "Wrong type for GetMutableDictionary: " << path;
+ return NULL;
+ }
+
+ DictionaryValue* dict = NULL;
+ Value* tmp_value = NULL;
+ if (!pref_value_store_->GetValue(path, &tmp_value) ||
+ !tmp_value->IsType(Value::TYPE_DICTIONARY)) {
+ dict = new DictionaryValue;
+ pref_value_store_->SetUserPrefValue(path, dict);
+ } else {
+ dict = static_cast<DictionaryValue*>(tmp_value);
+ }
+ return dict;
+}
+
+ListValue* PrefService::GetMutableList(const char* path) {
+ DCHECK(CalledOnValidThread());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ NOTREACHED() << "Trying to get an unregistered pref: " << path;
+ return NULL;
+ }
+ if (pref->GetType() != Value::TYPE_LIST) {
+ NOTREACHED() << "Wrong type for GetMutableList: " << path;
+ return NULL;
+ }
+
+ ListValue* list = NULL;
+ Value* tmp_value = NULL;
+ if (!pref_value_store_->GetValue(path, &tmp_value) ||
+ !tmp_value->IsType(Value::TYPE_LIST)) {
+ list = new ListValue;
+ pref_value_store_->SetUserPrefValue(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());
+
+ const Preference* pref = FindPreference(path);
+ if (!pref) {
+ 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()
+ << " to value of type " << new_value->GetType();
+ return;
+ }
+
+ if (pref_value_store_->SetUserPrefValue(path, new_value))
+ pref_notifier_->OnUserPreferenceSet(path);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// PrefService::Preference
+
+PrefService::Preference::Preference(const PrefService* service,
+ const char* name)
+ : name_(name),
+ pref_service_(service) {
+ DCHECK(name);
+ DCHECK(service);
+}
+
+Value::ValueType PrefService::Preference::GetType() const {
+ return pref_service_->pref_value_store_->GetRegisteredType(name_);
+}
+
+const Value* PrefService::Preference::GetValue() const {
+ DCHECK(pref_service_->FindPreference(name_.c_str())) <<
+ "Must register pref before getting its value";
+
+ Value* found_value = NULL;
+ if (pref_service_->pref_value_store_->GetValue(name_, &found_value))
+ return found_value;
+
+ // Every registered preference has at least a default value.
+ NOTREACHED() << "no valid value found for registered pref " << name_;
+ return NULL;
+}
+
+bool PrefService::Preference::IsManaged() const {
+ return pref_service_->pref_value_store_->
+ PrefValueInManagedStore(name_.c_str());
+}
+
+bool PrefService::Preference::HasExtensionSetting() const {
+ return pref_service_->pref_value_store_->
+ PrefValueInExtensionStore(name_.c_str());
+}
+
+bool PrefService::Preference::HasUserSetting() const {
+ return pref_service_->pref_value_store_->
+ PrefValueInUserStore(name_.c_str());
+}
+
+bool PrefService::Preference::IsExtensionControlled() const {
+ return pref_service_->pref_value_store_->
+ PrefValueFromExtensionStore(name_.c_str());
+}
+
+bool PrefService::Preference::IsUserControlled() const {
+ return pref_service_->pref_value_store_->
+ PrefValueFromUserStore(name_.c_str());
+}
+
+bool PrefService::Preference::IsDefaultValue() const {
+ return pref_service_->pref_value_store_->
+ PrefValueFromDefaultStore(name_.c_str());
+}
+
+bool PrefService::Preference::IsUserModifiable() const {
+ return pref_service_->pref_value_store_->
+ PrefValueUserModifiable(name_.c_str());
+}
diff --git a/chrome/browser/prefs/pref_service.h b/chrome/browser/prefs/pref_service.h
new file mode 100644
index 0000000..3e90db6
--- /dev/null
+++ b/chrome/browser/prefs/pref_service.h
@@ -0,0 +1,277 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This provides a way to access the application's current preferences.
+
+#ifndef CHROME_BROWSER_PREFS_PREF_SERVICE_H_
+#define CHROME_BROWSER_PREFS_PREF_SERVICE_H_
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "base/non_thread_safe.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 FilePath;
+class NotificationObserver;
+class PrefChangeObserver;
+class PrefNotifier;
+class Profile;
+
+namespace subtle {
+ class PrefMemberBase;
+};
+
+class PrefService : public NonThreadSafe {
+ public:
+ // A helper class to store all the information associated with a preference.
+ class Preference {
+ public:
+
+ // The type of the preference is determined by the type with which it is
+ // registered. This type needs to be a boolean, integer, real, string,
+ // dictionary (a branch), or list. You shouldn't need to construct this on
+ // your own; use the PrefService::Register*Pref methods instead.
+ Preference(const PrefService* service,
+ const char* name);
+ ~Preference() {}
+
+ // Returns the name of the Preference (i.e., the key, e.g.,
+ // browser.window_placement).
+ const std::string name() const { return name_; }
+
+ // Returns the registered type of the preference.
+ Value::ValueType GetType() const;
+
+ // Returns the value of the Preference, falling back to the registered
+ // default value if no other has been set.
+ const Value* GetValue() const;
+
+ // Returns true if the Preference is managed, i.e. set by an admin policy.
+ // Since managed prefs have the highest priority, this also indicates
+ // whether the pref is actually being controlled by the policy setting.
+ bool IsManaged() const;
+
+ // Returns true if the Preference has a value set by an extension, even if
+ // that value is being overridden by a higher-priority source.
+ bool HasExtensionSetting() const;
+
+ // Returns true if the Preference has a user setting, even if that value is
+ // being overridden by a higher-priority source.
+ bool HasUserSetting() const;
+
+ // Returns true if the Preference value is currently being controlled by an
+ // extension, and not by any higher-priority source.
+ bool IsExtensionControlled() const;
+
+ // Returns true if the Preference value is currently being controlled by a
+ // user setting, and not by any higher-priority source.
+ bool IsUserControlled() const;
+
+ // Returns true if the Preference is currently using its default value,
+ // and has not been set by any higher-priority source (even with the same
+ // value).
+ bool IsDefaultValue() const;
+
+ // Returns true if the user can change the Preference value, which is the
+ // case if no higher-priority source than the user store controls the
+ // Preference.
+ bool IsUserModifiable() const;
+
+ private:
+ friend class PrefService;
+
+ std::string name_;
+
+ // Reference to the PrefService in which this pref was created.
+ const PrefService* pref_service_;
+
+ 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.
+ static PrefService* CreatePrefService(const FilePath& pref_filename,
+ 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
+ // is running during first run, and the main process may not change pref
+ // values while the importer process is running. Returns true on success.
+ bool ReloadPersistentPrefs();
+
+ // Returns true if the preference for the given preference name is available
+ // and is managed.
+ bool IsManagedPreference(const char* pref_name) const;
+
+ // Writes the data to disk. The return value only reflects whether
+ // serialization was successful; we don't know whether the data actually made
+ // it on disk (since it's on a different thread). This should only be used if
+ // we need to save immediately (basically, during shutdown). Otherwise, you
+ // should use ScheduleSavePersistentPrefs.
+ bool SavePersistentPrefs();
+
+ // Serializes the data and schedules save using ImportantFileWriter.
+ void ScheduleSavePersistentPrefs();
+
+ // Make the PrefService aware of a pref.
+ void RegisterBooleanPref(const char* path, bool default_value);
+ void RegisterIntegerPref(const char* path, int default_value);
+ void RegisterRealPref(const char* path, double default_value);
+ void RegisterStringPref(const char* path, const std::string& default_value);
+ void RegisterFilePathPref(const char* path, const FilePath& default_value);
+ void RegisterListPref(const char* path);
+ void RegisterDictionaryPref(const char* path);
+
+ // These varients use a default value from the locale dll instead.
+ void RegisterLocalizedBooleanPref(const char* path,
+ int locale_default_message_id);
+ void RegisterLocalizedIntegerPref(const char* path,
+ int locale_default_message_id);
+ void RegisterLocalizedRealPref(const char* path,
+ int locale_default_message_id);
+ void RegisterLocalizedStringPref(const char* path,
+ int locale_default_message_id);
+
+ // If the path is valid and the value at the end of the path matches the type
+ // specified, it will return the specified value. Otherwise, the default
+ // value (set when the pref was registered) will be returned.
+ bool GetBoolean(const char* path) const;
+ int GetInteger(const char* path) const;
+ double GetReal(const char* path) const;
+ std::string GetString(const char* path) const;
+ FilePath GetFilePath(const char* path) const;
+
+ // Returns the branch if it exists. If it's not a branch or the branch does
+ // not exist, returns NULL.
+ const DictionaryValue* GetDictionary(const char* path) const;
+ const ListValue* GetList(const char* path) const;
+
+ // Removes a user pref and restores the pref to its default value.
+ void ClearPref(const char* path);
+
+ // If the path is valid (i.e., registered), update the pref value in the user
+ // prefs. Seting a null value on a preference of List or Dictionary type is
+ // equivalent to removing the user value for that preference, allowing the
+ // default value to take effect unless another value takes precedence.
+ void Set(const char* path, const Value& value);
+ void SetBoolean(const char* path, bool value);
+ void SetInteger(const char* path, int value);
+ void SetReal(const char* path, double value);
+ void SetString(const char* path, const std::string& value);
+ void SetFilePath(const char* path, const FilePath& value);
+
+ // Int64 helper methods that actually store the given value as a string.
+ // Note that if obtaining the named value via GetDictionary or GetList, the
+ // Value type will be TYPE_STRING.
+ void SetInt64(const char* path, int64 value);
+ int64 GetInt64(const char* path) const;
+ void RegisterInt64Pref(const char* path, int64 default_value);
+
+ // Used to set the value of dictionary or list values in the pref tree. This
+ // will create a dictionary or list if one does not exist in the pref tree.
+ // This method returns NULL only if you're requesting an unregistered pref or
+ // a non-dict/non-list pref.
+ // WARNING: Changes to the dictionary or list will not automatically notify
+ // pref observers.
+ // Use a ScopedPrefUpdate to update observers on changes.
+ DictionaryValue* GetMutableDictionary(const char* path);
+ ListValue* GetMutableList(const char* path);
+
+ // Returns true if a value has been set for the specified path.
+ // NOTE: this is NOT the same as FindPreference. In particular
+ // FindPreference returns whether RegisterXXX has been invoked, where as
+ // this checks if a value exists for the path.
+ bool HasPrefPath(const char* path) const;
+
+ class PreferencePathComparator {
+ public:
+ bool operator() (Preference* lhs, Preference* rhs) const {
+ return lhs->name() < rhs->name();
+ }
+ };
+ typedef std::set<Preference*, PreferencePathComparator> PreferenceSet;
+ const PreferenceSet& preference_set() const { return prefs_; }
+
+ // A helper method to quickly look up a preference. Returns NULL if the
+ // preference is not registered.
+ const Preference* FindPreference(const char* pref_name) const;
+
+ bool read_only() const { return pref_value_store_->ReadOnly(); }
+
+ PrefNotifier* pref_notifier() const { return pref_notifier_.get(); }
+
+ PrefValueStore* pref_value_store() const { return pref_value_store_.get(); }
+
+ protected:
+ // The PrefNotifier handles registering and notifying preference observers.
+ // It is created and owned by this PrefService. Subclasses may access it for
+ // unit testing.
+ scoped_ptr<PrefNotifier> pref_notifier_;
+
+ private:
+ // 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.
+ // PrefMember registers for preferences changes notification directly to
+ // avoid the storage overhead of the registrar, so its base class must be
+ // declared as a friend, too.
+ friend class PrefChangeRegistrar;
+ friend class subtle::PrefMemberBase;
+
+ // If the pref at the given path changes, we call the observer's Observe
+ // method with PREF_CHANGED. Note that observers should not call these methods
+ // directly but rather use a PrefChangeRegistrar to make sure the observer
+ // gets cleaned up properly.
+ virtual void AddPrefObserver(const char* path, NotificationObserver* obs);
+ virtual void RemovePrefObserver(const char* path, NotificationObserver* obs);
+
+ // Add a preference to the PreferenceMap. If the pref already exists, return
+ // 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();
+
+ // The PrefValueStore provides prioritized preference values. It is created
+ // and owned by this PrefService. Subclasses may access it for unit testing.
+ scoped_refptr<PrefValueStore> pref_value_store_;
+
+ // A set of all the registered Preference objects.
+ PreferenceSet prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefService);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_SERVICE_H_
diff --git a/chrome/browser/pref_service_uitest.cc b/chrome/browser/prefs/pref_service_uitest.cc
index 87dcb2c..9712481 100644
--- a/chrome/browser/pref_service_uitest.cc
+++ b/chrome/browser/prefs/pref_service_uitest.cc
@@ -49,8 +49,7 @@ class PreferenceServiceTest : public UITest {
FILE_ATTRIBUTE_NORMAL));
#endif
- launch_arguments_.AppendSwitchWithValue(switches::kUserDataDir,
- tmp_profile_.ToWStringHack());
+ launch_arguments_.AppendSwitchPath(switches::kUserDataDir, tmp_profile_);
}
bool LaunchAppWithProfile() {
@@ -104,23 +103,23 @@ TEST_F(PreferenceServiceTest, PreservedWindowPlacementIsLoaded) {
// Retrieve the expected rect values from "Preferences"
int bottom = 0;
- std::wstring kBrowserWindowPlacement(prefs::kBrowserWindowPlacement);
- EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".bottom",
+ std::string kBrowserWindowPlacement(prefs::kBrowserWindowPlacement);
+ EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".bottom",
&bottom));
EXPECT_EQ(bottom, bounds.y() + bounds.height());
int top = 0;
- EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".top",
+ EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".top",
&top));
EXPECT_EQ(top, bounds.y());
int left = 0;
- EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".left",
+ EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".left",
&left));
EXPECT_EQ(left, bounds.x());
int right = 0;
- EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + L".right",
+ EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".right",
&right));
EXPECT_EQ(right, bounds.x() + bounds.width());
@@ -128,7 +127,7 @@ TEST_F(PreferenceServiceTest, PreservedWindowPlacementIsLoaded) {
bool is_window_maximized = false;
ASSERT_TRUE(window->IsMaximized(&is_window_maximized));
bool is_maximized = false;
- EXPECT_TRUE(root_dict->GetBoolean(kBrowserWindowPlacement + L".maximized",
+ EXPECT_TRUE(root_dict->GetBoolean(kBrowserWindowPlacement + ".maximized",
&is_maximized));
EXPECT_EQ(is_maximized, is_window_maximized);
}
diff --git a/chrome/browser/pref_service_unittest.cc b/chrome/browser/prefs/pref_service_unittest.cc
index 967c0cb..d62679d 100644
--- a/chrome/browser/pref_service_unittest.cc
+++ b/chrome/browser/prefs/pref_service_unittest.cc
@@ -7,8 +7,9 @@
#include "app/test/data/resource.h"
#include "base/scoped_ptr.h"
#include "base/values.h"
-#include "chrome/browser/dummy_pref_store.h"
-#include "chrome/browser/pref_value_store.h"
+#include "chrome/browser/prefs/dummy_pref_store.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_service.h"
@@ -26,7 +27,7 @@ using testing::Property;
class TestPrefObserver : public NotificationObserver {
public:
TestPrefObserver(const PrefService* prefs,
- const std::wstring& pref_name,
+ const std::string& pref_name,
const std::string& new_pref_value)
: observer_fired_(false),
prefs_(prefs),
@@ -41,9 +42,9 @@ class TestPrefObserver : public NotificationObserver {
EXPECT_EQ(type.value, NotificationType::PREF_CHANGED);
PrefService* prefs_in = Source<PrefService>(source).ptr();
EXPECT_EQ(prefs_in, prefs_);
- std::wstring* pref_name_in = Details<std::wstring>(details).ptr();
+ 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(L"homepage"));
+ EXPECT_EQ(new_pref_value_, prefs_in->GetString("homepage"));
observer_fired_ = true;
}
@@ -57,7 +58,7 @@ class TestPrefObserver : public NotificationObserver {
private:
bool observer_fired_;
const PrefService* prefs_;
- const std::wstring pref_name_;
+ const std::string pref_name_;
std::string new_pref_value_;
};
@@ -65,9 +66,9 @@ class TestPrefObserver : public NotificationObserver {
#if defined(OS_WIN)
TEST(PrefServiceTest, LocalizedPrefs) {
TestingPrefService prefs;
- const wchar_t kBoolean[] = L"boolean";
- const wchar_t kInteger[] = L"integer";
- const wchar_t kString[] = L"string";
+ const char kBoolean[] = "boolean";
+ const char kInteger[] = "integer";
+ const char kString[] = "string";
prefs.RegisterLocalizedBooleanPref(kBoolean, IDS_LOCALE_BOOL);
prefs.RegisterLocalizedIntegerPref(kInteger, IDS_LOCALE_INT);
prefs.RegisterLocalizedStringPref(kString, IDS_LOCALE_STRING);
@@ -89,12 +90,15 @@ TEST(PrefServiceTest, LocalizedPrefs) {
TEST(PrefServiceTest, NoObserverFire) {
TestingPrefService prefs;
- const wchar_t pref_name[] = L"homepage";
+ const char pref_name[] = "homepage";
prefs.RegisterStringPref(pref_name, "");
const std::string new_pref_value("http://www.google.com/");
TestPrefObserver obs(&prefs, pref_name, new_pref_value);
- prefs.AddPrefObserver(pref_name, &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);
@@ -116,15 +120,12 @@ TEST(PrefServiceTest, NoObserverFire) {
obs.Reset("");
prefs.ClearPref(pref_name);
EXPECT_FALSE(obs.observer_fired());
-
- // Ok, clean up.
- prefs.RemovePrefObserver(pref_name, &obs);
}
TEST(PrefServiceTest, HasPrefPath) {
TestingPrefService prefs;
- const wchar_t path[] = L"fake.path";
+ const char path[] = "fake.path";
// Shouldn't initially have a path.
EXPECT_FALSE(prefs.HasPrefPath(path));
@@ -140,15 +141,17 @@ TEST(PrefServiceTest, HasPrefPath) {
}
TEST(PrefServiceTest, Observers) {
- const wchar_t pref_name[] = L"homepage";
+ const char pref_name[] = "homepage";
TestingPrefService prefs;
- prefs.SetUserPref(pref_name, Value::CreateStringValue(L"http://www.cnn.com"));
+ prefs.SetUserPref(pref_name, Value::CreateStringValue("http://www.cnn.com"));
prefs.RegisterStringPref(pref_name, "");
const std::string new_pref_value("http://www.google.com/");
TestPrefObserver obs(&prefs, pref_name, new_pref_value);
- prefs.AddPrefObserver(pref_name, &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);
@@ -159,28 +162,25 @@ TEST(PrefServiceTest, Observers) {
const std::string new_pref_value2("http://www.youtube.com/");
obs.Reset(new_pref_value2);
TestPrefObserver obs2(&prefs, pref_name, new_pref_value2);
- prefs.AddPrefObserver(pref_name, &obs2);
+ 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());
// Make sure obs2 still works after removing obs.
- prefs.RemovePrefObserver(pref_name, &obs);
+ registrar.Remove(pref_name, &obs);
obs.Reset("");
obs2.Reset(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());
-
- // Ok, clean up.
- prefs.RemovePrefObserver(pref_name, &obs2);
}
class PrefServiceSetValueTest : public testing::Test {
protected:
- static const wchar_t name_[];
+ static const char name_[];
static const char value_[];
PrefServiceSetValueTest()
@@ -194,24 +194,33 @@ class PrefServiceSetValueTest : public testing::Test {
void SetExpectPrefChanged() {
EXPECT_CALL(observer_,
Observe(NotificationType(NotificationType::PREF_CHANGED), _,
- Property(&Details<std::wstring>::ptr,
+ Property(&Details<std::string>::ptr,
Pointee(name_string_))));
}
TestingPrefService prefs_;
- std::wstring name_string_;
+ std::string name_string_;
scoped_ptr<Value> null_value_;
NotificationObserverMock observer_;
};
-const wchar_t PrefServiceSetValueTest::name_[] = L"name";
+const char PrefServiceSetValueTest::name_[] = "name";
const char PrefServiceSetValueTest::value_[] = "value";
TEST_F(PrefServiceSetValueTest, SetStringValue) {
const char default_string[] = "default";
scoped_ptr<Value> default_value(Value::CreateStringValue(default_string));
prefs_.RegisterStringPref(name_, default_string);
- prefs_.AddPrefObserver(name_, &observer_);
+
+ PrefChangeRegistrar registrar;
+ registrar.Init(&prefs_);
+ registrar.Add(name_, &observer_);
+
+ // Changing the controlling store from default to user triggers notification.
+ SetExpectPrefChanged();
+ prefs_.Set(name_, *default_value);
+ Mock::VerifyAndClearExpectations(&observer_);
+
SetExpectNoNotification();
prefs_.Set(name_, *default_value);
Mock::VerifyAndClearExpectations(&observer_);
@@ -220,14 +229,16 @@ TEST_F(PrefServiceSetValueTest, SetStringValue) {
SetExpectPrefChanged();
prefs_.Set(name_, *new_value);
EXPECT_EQ(value_, prefs_.GetString(name_));
-
- prefs_.RemovePrefObserver(name_, &observer_);
}
TEST_F(PrefServiceSetValueTest, SetDictionaryValue) {
prefs_.RegisterDictionaryPref(name_);
- prefs_.AddPrefObserver(name_, &observer_);
+ PrefChangeRegistrar registrar;
+ registrar.Init(&prefs_);
+ registrar.Add(name_, &observer_);
+ // 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();
prefs_.Set(name_, *null_value_);
Mock::VerifyAndClearExpectations(&observer_);
@@ -252,14 +263,16 @@ TEST_F(PrefServiceSetValueTest, SetDictionaryValue) {
Mock::VerifyAndClearExpectations(&observer_);
dict = prefs_.GetMutableDictionary(name_);
EXPECT_EQ(0U, dict->size());
-
- prefs_.RemovePrefObserver(name_, &observer_);
}
TEST_F(PrefServiceSetValueTest, SetListValue) {
prefs_.RegisterListPref(name_);
- prefs_.AddPrefObserver(name_, &observer_);
+ PrefChangeRegistrar registrar;
+ registrar.Init(&prefs_);
+ registrar.Add(name_, &observer_);
+ // 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();
prefs_.Set(name_, *null_value_);
Mock::VerifyAndClearExpectations(&observer_);
@@ -284,6 +297,4 @@ TEST_F(PrefServiceSetValueTest, SetListValue) {
Mock::VerifyAndClearExpectations(&observer_);
list = prefs_.GetMutableList(name_);
EXPECT_EQ(0U, list->GetSize());
-
- prefs_.RemovePrefObserver(name_, &observer_);
}
diff --git a/chrome/browser/prefs/pref_set_observer.cc b/chrome/browser/prefs/pref_set_observer.cc
new file mode 100644
index 0000000..dd067d3
--- /dev/null
+++ b/chrome/browser/prefs/pref_set_observer.cc
@@ -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.
+
+#include "chrome/browser/prefs/pref_set_observer.h"
+
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+
+PrefSetObserver::PrefSetObserver(PrefService* pref_service,
+ NotificationObserver* observer)
+ : pref_service_(pref_service),
+ observer_(observer) {
+ registrar_.Init(pref_service);
+}
+
+void PrefSetObserver::AddPref(const std::string& pref) {
+ if (!prefs_.count(pref) && pref_service_->FindPreference(pref.c_str())) {
+ prefs_.insert(pref);
+ registrar_.Add(pref.c_str(), this);
+ }
+}
+
+void PrefSetObserver::RemovePref(const std::string& pref) {
+ if (prefs_.erase(pref))
+ registrar_.Remove(pref.c_str(), this);
+}
+
+bool PrefSetObserver::IsObserved(const std::string& pref) {
+ return prefs_.count(pref) > 0;
+}
+
+bool PrefSetObserver::IsManaged() {
+ for (PrefSet::const_iterator i(prefs_.begin()); i != prefs_.end(); ++i) {
+ const PrefService::Preference* pref =
+ pref_service_->FindPreference(i->c_str());
+ if (pref && pref->IsManaged())
+ return true;
+ }
+ return false;
+}
+
+// static
+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::kProxyServer);
+ pref_set->AddPref(prefs::kProxyPacUrl);
+ pref_set->AddPref(prefs::kProxyBypassList);
+
+ return pref_set;
+}
+
+// static
+PrefSetObserver* PrefSetObserver::CreateDefaultSearchPrefSetObserver(
+ PrefService* pref_service,
+ NotificationObserver* observer) {
+ PrefSetObserver* pref_set = new PrefSetObserver(pref_service, observer);
+ pref_set->AddPref(prefs::kDefaultSearchProviderName);
+ pref_set->AddPref(prefs::kDefaultSearchProviderKeyword);
+ pref_set->AddPref(prefs::kDefaultSearchProviderSearchURL);
+ pref_set->AddPref(prefs::kDefaultSearchProviderSuggestURL);
+ pref_set->AddPref(prefs::kDefaultSearchProviderIconURL);
+ pref_set->AddPref(prefs::kDefaultSearchProviderEncodings);
+
+ return pref_set;
+}
+
+void PrefSetObserver::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (observer_)
+ observer_->Observe(type, source, details);
+}
diff --git a/chrome/browser/prefs/pref_set_observer.h b/chrome/browser/prefs/pref_set_observer.h
new file mode 100644
index 0000000..ff350df
--- /dev/null
+++ b/chrome/browser/prefs/pref_set_observer.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_PREFS_PREF_SET_OBSERVER_H_
+#define CHROME_BROWSER_PREFS_PREF_SET_OBSERVER_H_
+#pragma once
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/common/notification_observer.h"
+
+// Observes the state of a set of preferences and allows to query their combined
+// managed bits.
+class PrefSetObserver : public NotificationObserver {
+ public:
+ // Initialize with an empty set of preferences.
+ PrefSetObserver(PrefService* pref_service,
+ NotificationObserver* observer);
+ virtual ~PrefSetObserver() {}
+
+ // Add a |pref| to the set of preferences to observe.
+ void AddPref(const std::string& pref);
+ // Remove |pref| from the set of observed peferences.
+ void RemovePref(const std::string& pref);
+
+ // Check whether |pref| is in the set of observed preferences.
+ bool IsObserved(const std::string& pref);
+ // Check whether any of the observed preferences has the managed bit set.
+ bool IsManaged();
+
+ // Create a pref set observer for all preferences relevant to proxies.
+ static PrefSetObserver* CreateProxyPrefSetObserver(
+ PrefService* pref_service,
+ NotificationObserver* observer);
+
+ // Create a pref set observer for all preferences relevant to default search.
+ static PrefSetObserver* CreateDefaultSearchPrefSetObserver(
+ PrefService* pref_service,
+ NotificationObserver* observer);
+
+ private:
+ // Overridden from NotificationObserver.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ typedef std::set<std::string> PrefSet;
+ PrefSet prefs_;
+
+ PrefService* pref_service_;
+ PrefChangeRegistrar registrar_;
+ NotificationObserver* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefSetObserver);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_SET_OBSERVER_H_
diff --git a/chrome/browser/prefs/pref_set_observer_unittest.cc b/chrome/browser/prefs/pref_set_observer_unittest.cc
new file mode 100644
index 0000000..f77bb6c
--- /dev/null
+++ b/chrome/browser/prefs/pref_set_observer_unittest.cc
@@ -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.
+
+#include "chrome/browser/prefs/pref_set_observer.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer_mock.h"
+#include "chrome/common/notification_source.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"
+
+// Unit tests for PrefSetObserver.
+class PrefSetObserverTest : public testing::Test {
+ public:
+ virtual void SetUp() {
+ pref_service_.reset(new TestingPrefService);
+ pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com");
+ pref_service_->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, false);
+ pref_service_->RegisterStringPref(prefs::kApplicationLocale, "");
+ }
+
+ PrefSetObserver* CreatePrefSetObserver(NotificationObserver* observer) {
+ PrefSetObserver* pref_set =
+ new PrefSetObserver(pref_service_.get(), observer);
+ pref_set->AddPref(prefs::kHomePage);
+ pref_set->AddPref(prefs::kHomePageIsNewTabPage);
+ return pref_set;
+ }
+
+ scoped_ptr<TestingPrefService> pref_service_;
+};
+
+TEST_F(PrefSetObserverTest, IsObserved) {
+ scoped_ptr<PrefSetObserver> pref_set(CreatePrefSetObserver(NULL));
+ EXPECT_TRUE(pref_set->IsObserved(prefs::kHomePage));
+ EXPECT_TRUE(pref_set->IsObserved(prefs::kHomePageIsNewTabPage));
+ EXPECT_FALSE(pref_set->IsObserved(prefs::kApplicationLocale));
+}
+
+TEST_F(PrefSetObserverTest, IsManaged) {
+ scoped_ptr<PrefSetObserver> pref_set(CreatePrefSetObserver(NULL));
+ EXPECT_FALSE(pref_set->IsManaged());
+ pref_service_->SetManagedPref(prefs::kHomePage,
+ Value::CreateStringValue("http://crbug.com"));
+ EXPECT_TRUE(pref_set->IsManaged());
+ pref_service_->SetManagedPref(prefs::kHomePageIsNewTabPage,
+ Value::CreateBooleanValue(true));
+ EXPECT_TRUE(pref_set->IsManaged());
+ pref_service_->RemoveManagedPref(prefs::kHomePage);
+ EXPECT_TRUE(pref_set->IsManaged());
+ pref_service_->RemoveManagedPref(prefs::kHomePageIsNewTabPage);
+ EXPECT_FALSE(pref_set->IsManaged());
+}
+
+MATCHER_P(PrefNameDetails, name, "details references named preference") {
+ std::string* pstr = reinterpret_cast<const Details<std::string>&>(arg).ptr();
+ return pstr && *pstr == name;
+}
+
+TEST_F(PrefSetObserverTest, Observe) {
+ using testing::_;
+ using testing::Mock;
+
+ NotificationObserverMock observer;
+ scoped_ptr<PrefSetObserver> pref_set(CreatePrefSetObserver(&observer));
+
+ EXPECT_CALL(observer,
+ Observe(NotificationType(NotificationType::PREF_CHANGED),
+ Source<PrefService>(pref_service_.get()),
+ PrefNameDetails(prefs::kHomePage)));
+ pref_service_->SetUserPref(prefs::kHomePage,
+ Value::CreateStringValue("http://crbug.com"));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_CALL(observer,
+ Observe(NotificationType(NotificationType::PREF_CHANGED),
+ Source<PrefService>(pref_service_.get()),
+ PrefNameDetails(prefs::kHomePageIsNewTabPage)));
+ pref_service_->SetUserPref(prefs::kHomePageIsNewTabPage,
+ Value::CreateBooleanValue(true));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_CALL(observer, Observe(_, _, _)).Times(0);
+ pref_service_->SetUserPref(prefs::kApplicationLocale,
+ Value::CreateStringValue("en_US.utf8"));
+ Mock::VerifyAndClearExpectations(&observer);
+}
diff --git a/chrome/browser/prefs/pref_value_store.cc b/chrome/browser/prefs/pref_value_store.cc
new file mode 100644
index 0000000..46c825d
--- /dev/null
+++ b/chrome/browser/prefs/pref_value_store.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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_store.h"
+
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/extensions/extension_pref_store.h"
+#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/common/json_pref_store.h"
+#include "chrome/common/notification_service.h"
+
+namespace {
+
+// 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;
+
+ // 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;
+}
+
+} // namespace
+
+// static
+PrefValueStore* PrefValueStore::CreatePrefValueStore(
+ const FilePath& pref_filename,
+ Profile* profile,
+ bool user_only) {
+ using policy::ConfigurationPolicyPrefStore;
+ ConfigurationPolicyPrefStore* managed = NULL;
+ ExtensionPrefStore* extension = NULL;
+ CommandLinePrefStore* command_line = NULL;
+ ConfigurationPolicyPrefStore* recommended = NULL;
+
+ JsonPrefStore* user = new JsonPrefStore(
+ pref_filename,
+ ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE));
+ DefaultPrefStore* default_store = new DefaultPrefStore();
+
+ if (!user_only) {
+ managed = ConfigurationPolicyPrefStore::CreateManagedPolicyPrefStore();
+ extension = new ExtensionPrefStore(profile, PrefNotifier::EXTENSION_STORE);
+ command_line = new CommandLinePrefStore(CommandLine::ForCurrentProcess());
+ recommended =
+ ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore();
+ }
+ return new PrefValueStore(managed, extension, command_line, user,
+ recommended, default_store);
+}
+
+PrefValueStore::~PrefValueStore() {}
+
+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.
+ // If the found value is not the correct type, keep looking. This allows a
+ // default value to override an outdated user-pref setting.
+ for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
+ if (pref_stores_[i].get() &&
+ pref_stores_[i]->prefs()->Get(name.c_str(), out_value) &&
+ IsValidType(GetRegisteredType(name), (*out_value)->GetType(),
+ static_cast<PrefNotifier::PrefStoreType>(i))) {
+ return true;
+ }
+ }
+ // No valid value found for the given preference name: set the return false.
+ *out_value = NULL;
+ return false;
+}
+
+void PrefValueStore::RegisterPreferenceType(const std::string& name,
+ Value::ValueType type) {
+ pref_types_[name] = type;
+}
+
+Value::ValueType PrefValueStore::GetRegisteredType(
+ const std::string& name) const {
+ PrefTypeMap::const_iterator found = pref_types_.find(name);
+ if (found == pref_types_.end())
+ return Value::TYPE_NULL;
+ 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;
+ }
+ }
+ // 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);
+ bool rv = GetValue(name, &tmp_value);
+ // Merely registering a pref doesn't count as "having" it: we require a
+ // non-default value set.
+ 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));
+
+ 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();
+}
+
+bool PrefValueStore::RemoveUserPrefValue(const char* name) {
+ if (pref_stores_[PrefNotifier::USER_STORE].get()) {
+ return pref_stores_[PrefNotifier::USER_STORE]->prefs()->Remove(name, NULL);
+ }
+ return false;
+}
+
+bool PrefValueStore::PrefValueInManagedStore(const char* name) const {
+ return PrefValueInStore(name, PrefNotifier::MANAGED_STORE);
+}
+
+bool PrefValueStore::PrefValueInExtensionStore(const char* name) const {
+ return PrefValueInStore(name, PrefNotifier::EXTENSION_STORE);
+}
+
+bool PrefValueStore::PrefValueInUserStore(const char* name) const {
+ return PrefValueInStore(name, PrefNotifier::USER_STORE);
+}
+
+bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const {
+ return ControllingPrefStoreForPref(name) == PrefNotifier::EXTENSION_STORE;
+}
+
+bool PrefValueStore::PrefValueFromUserStore(const char* name) const {
+ return ControllingPrefStoreForPref(name) == PrefNotifier::USER_STORE;
+}
+
+bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const {
+ return ControllingPrefStoreForPref(name) == PrefNotifier::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;
+}
+
+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);
+ }
+ return PrefNotifier::INVALID_STORE;
+}
+
+bool PrefValueStore::PrefValueInStore(const char* name,
+ PrefNotifier::PrefStoreType store) const {
+ if (!pref_stores_[store].get()) {
+ // No store of that type, so this pref can't be in it.
+ return false;
+ }
+ Value* tmp_value = NULL;
+ if (pref_stores_[store]->prefs()->Get(name, &tmp_value) &&
+ IsValidType(GetRegisteredType(name), tmp_value->GetType(), store)) {
+ return true;
+ }
+ return false;
+}
+
+void PrefValueStore::RefreshPolicyPrefsCompletion(
+ PrefStore* new_managed_pref_store,
+ PrefStore* new_recommended_pref_store,
+ AfterRefreshCallback* callback_pointer) {
+ scoped_ptr<AfterRefreshCallback> callback(callback_pointer);
+ DictionaryValue* managed_prefs_before(
+ pref_stores_[PrefNotifier::MANAGED_STORE]->prefs());
+ DictionaryValue* managed_prefs_after(new_managed_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_paths;
+ managed_prefs_before->GetDifferingPaths(managed_prefs_after,
+ &changed_managed_paths);
+
+ std::vector<std::string> changed_recommended_paths;
+ recommended_prefs_before->GetDifferingPaths(recommended_prefs_after,
+ &changed_recommended_paths);
+
+ std::vector<std::string> changed_paths(changed_managed_paths.size() +
+ changed_recommended_paths.size());
+ std::vector<std::string>::iterator last_insert =
+ std::merge(changed_managed_paths.begin(),
+ changed_managed_paths.end(),
+ changed_recommended_paths.begin(),
+ changed_recommended_paths.end(),
+ changed_paths.begin());
+ changed_paths.resize(last_insert - changed_paths.begin());
+
+ pref_stores_[PrefNotifier::MANAGED_STORE].reset(new_managed_pref_store);
+ pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(
+ new_recommended_pref_store);
+ callback->Run(changed_paths);
+}
+
+void PrefValueStore::RefreshPolicyPrefsOnFileThread(
+ ChromeThread::ID calling_thread_id,
+ PrefStore* new_managed_pref_store,
+ PrefStore* new_recommended_pref_store,
+ AfterRefreshCallback* callback_pointer) {
+ scoped_ptr<AfterRefreshCallback> callback(callback_pointer);
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ scoped_ptr<PrefStore> managed_pref_store(new_managed_pref_store);
+ scoped_ptr<PrefStore> recommended_pref_store(new_recommended_pref_store);
+
+ PrefStore::PrefReadError read_error = new_managed_pref_store->ReadPrefs();
+ if (read_error != PrefStore::PREF_READ_ERROR_NONE) {
+ LOG(ERROR) << "refresh of managed policy failed: PrefReadError = "
+ << read_error;
+ return;
+ }
+
+ 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;
+ }
+
+ ChromeThread::PostTask(
+ calling_thread_id, FROM_HERE,
+ NewRunnableMethod(this,
+ &PrefValueStore::RefreshPolicyPrefsCompletion,
+ managed_pref_store.release(),
+ recommended_pref_store.release(),
+ callback.release()));
+}
+
+void PrefValueStore::RefreshPolicyPrefs(
+ PrefStore* new_managed_pref_store,
+ PrefStore* new_recommended_pref_store,
+ AfterRefreshCallback* callback) {
+ ChromeThread::ID current_thread_id;
+ CHECK(ChromeThread::GetCurrentThreadIdentifier(&current_thread_id));
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(this,
+ &PrefValueStore::RefreshPolicyPrefsOnFileThread,
+ current_thread_id,
+ new_managed_pref_store,
+ new_recommended_pref_store,
+ callback));
+}
+
+PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PrefStore* user_prefs,
+ PrefStore* recommended_prefs,
+ PrefStore* default_prefs) {
+ // 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_STORE].reset(managed_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);
+}
diff --git a/chrome/browser/prefs/pref_value_store.h b/chrome/browser/prefs/pref_value_store.h
new file mode 100644
index 0000000..c361e07
--- /dev/null
+++ b/chrome/browser/prefs/pref_value_store.h
@@ -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.
+
+#ifndef CHROME_BROWSER_PREFS_PREF_VALUE_STORE_H_
+#define CHROME_BROWSER_PREFS_PREF_VALUE_STORE_H_
+#pragma once
+
+#include <map>
+#include <string>
+#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"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/prefs/pref_notifier.h"
+#include "chrome/common/pref_store.h"
+
+class FilePath;
+class PrefStore;
+class Profile;
+
+// The PrefValueStore manages various sources of values for Preferences
+// (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:
+ // 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
+ // with the local state. If |pref_filename| is empty, the user PrefStore will
+ // not be created. If |user_only| is true, no PrefStores will be created
+ // other than the user and default PrefStores. This should not normally be
+ // called directly: the usual way to create a PrefValueStore is by creating a
+ // PrefService.
+ static PrefValueStore* CreatePrefValueStore(const FilePath& pref_filename,
+ Profile* profile,
+ bool user_only);
+
+ ~PrefValueStore();
+
+ // 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
+ // default values of Dictionaries and Lists. Returns true if a valid value
+ // was found in any of the available PrefStores. Most callers should use
+ // Preference::GetValue() instead of calling this method directly.
+ bool GetValue(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);
+
+ // Gets the registered value type for the given preference name. Returns
+ // 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
+ // registered does not count as an "actively set" value, but another pref
+ // 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 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.
+ bool PrefValueInManagedStore(const char* name) const;
+ bool PrefValueInExtensionStore(const char* name) const;
+ bool PrefValueInUserStore(const char* name) const;
+
+ // 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.
+ bool PrefValueFromExtensionStore(const char* name) const;
+ bool PrefValueFromUserStore(const char* name) const;
+ bool PrefValueFromDefaultStore(const char* name) const;
+
+ // Check whether a Preference value is modifiable by the user, i.e. whether
+ // there is no higher-priority source controlling it.
+ bool PrefValueUserModifiable(const char* name) const;
+
+ // 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
+ // should always have a value for any registered preferencem, so INVALID_STORE
+ // indicates an error.
+ PrefNotifier::PrefStoreType ControllingPrefStoreForPref(
+ const char* name) const;
+
+ // Signature of callback triggered after policy refresh. Parameter is not
+ // passed as reference to prevent passing along a pointer to a set whose
+ // lifecycle is managed in another thread.
+ typedef Callback1<std::vector<std::string> >::Type AfterRefreshCallback;
+
+ // Called as a result of a notification of policy change. Triggers a
+ // reload of managed preferences from policy. Caller must pass in
+ // new, uninitialized managed and recommended PrefStores in
+ // |managed_pref_store| and |recommended_pref_store| respectively, since
+ // PrefValueStore doesn't know about policy-specific PrefStores.
+ // |callback| is called with the set of preferences changed by the policy
+ // refresh. |callback| is called on the caller's thread as a Task
+ // after RefreshPolicyPrefs has returned. RefreshPolicyPrefs takes ownership
+ // of the |callback| object.
+ void RefreshPolicyPrefs(PrefStore* managed_pref_store,
+ PrefStore* recommended_pref_store,
+ AfterRefreshCallback* callback);
+
+ protected:
+ // In decreasing order of precedence:
+ // |managed_prefs| contains all managed (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.
+ //
+ // This constructor should only be used internally, or by subclasses in
+ // testing. The usual way to create a PrefValueStore is by creating a
+ // PrefService.
+ PrefValueStore(PrefStore* managed_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PrefStore* user_prefs,
+ PrefStore* recommended_prefs,
+ PrefStore* default_prefs);
+
+ private:
+ friend class PrefValueStoreTest;
+ FRIEND_TEST_ALL_PREFIXES(PrefValueStoreTest,
+ TestRefreshPolicyPrefsCompletion);
+
+ scoped_ptr<PrefStore> pref_stores_[PrefNotifier::PREF_STORE_TYPE_MAX + 1];
+
+ // A mapping of preference names to their registered types.
+ typedef std::map<std::string, Value::ValueType> PrefTypeMap;
+ PrefTypeMap pref_types_;
+
+ // 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;
+
+ // Called during policy refresh after ReadPrefs completes on the thread
+ // that initiated the policy refresh. RefreshPolicyPrefsCompletion takes
+ // ownership of the |callback| object.
+ void RefreshPolicyPrefsCompletion(
+ PrefStore* new_managed_pref_store,
+ PrefStore* new_recommended_pref_store,
+ AfterRefreshCallback* callback);
+
+ // Called during policy refresh to do the ReadPrefs on the FILE thread.
+ // RefreshPolicyPrefsOnFileThread takes ownership of the |callback| object.
+ void RefreshPolicyPrefsOnFileThread(
+ ChromeThread::ID calling_thread_id,
+ PrefStore* new_managed_pref_store,
+ PrefStore* new_recommended_pref_store,
+ AfterRefreshCallback* callback);
+
+ DISALLOW_COPY_AND_ASSIGN(PrefValueStore);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_VALUE_STORE_H_
diff --git a/chrome/browser/prefs/pref_value_store_unittest.cc b/chrome/browser/prefs/pref_value_store_unittest.cc
new file mode 100644
index 0000000..fcb5b60
--- /dev/null
+++ b/chrome/browser/prefs/pref_value_store_unittest.cc
@@ -0,0 +1,764 @@
+// Copyright (c) 2010 The Chromium Authors. 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 "base/values.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/prefs/dummy_pref_store.h"
+#include "chrome/browser/prefs/pref_value_store.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::Mock;
+
+namespace {
+
+class MockPolicyRefreshCallback {
+ public:
+ MockPolicyRefreshCallback() {}
+ MOCK_METHOD1(DoCallback, void(const std::vector<std::string>));
+};
+
+} // namespace
+
+// Names of the preferences used in this test program.
+namespace prefs {
+ const char kCurrentThemeID[] = "extensions.theme.id";
+ const char kDeleteCache[] = "browser.clear_data.cache";
+ const char kHomepage[] = "homepage";
+ const char kMaxTabs[] = "tabs.max_tabs";
+ const char kMissingPref[] = "this.pref.does_not_exist";
+ const char kRecommendedPref[] = "this.pref.recommended_value_only";
+ const char kSampleDict[] = "sample.dict";
+ const char kSampleList[] = "sample.list";
+ const char kDefaultPref[] = "default.pref";
+
+ // This must match the actual pref name so the command-line store knows about
+ // it.
+ const char kApplicationLocale[] = "intl.app_locale";
+}
+
+// Potentially expected values of all preferences used in this test program.
+namespace enforced_pref {
+ const std::string kHomepageValue = "http://www.topeka.com";
+}
+
+namespace extension_pref {
+ const char kCurrentThemeIDValue[] = "set by extension";
+ const char kHomepageValue[] = "http://www.chromium.org";
+}
+
+namespace command_line_pref {
+ const char kApplicationLocaleValue[] = "hi-MOM";
+ const char kCurrentThemeIDValue[] = "zyxwvut";
+ const char kHomepageValue[] = "http://www.ferretcentral.org";
+}
+
+// The "user" namespace is defined globally in an ARM system header, so we need
+// something different here.
+namespace user_pref {
+ const int kMaxTabsValue = 31;
+ const bool kDeleteCacheValue = true;
+ const char kCurrentThemeIDValue[] = "abcdefg";
+ const char kHomepageValue[] = "http://www.google.com";
+ const char kApplicationLocaleValue[] = "is-WRONG";
+}
+
+namespace recommended_pref {
+ const int kMaxTabsValue = 10;
+ const bool kRecommendedPrefValue = true;
+}
+
+namespace default_pref {
+ const int kDefaultValue = 7;
+ const char kHomepageValue[] = "default homepage";
+}
+
+class PrefValueStoreTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Create dummy user preferences.
+ enforced_prefs_= CreateEnforcedPrefs();
+ extension_prefs_ = CreateExtensionPrefs();
+ command_line_prefs_ = CreateCommandLinePrefs();
+ user_prefs_ = CreateUserPrefs();
+ recommended_prefs_ = CreateRecommendedPrefs();
+ default_prefs_ = CreateDefaultPrefs();
+
+ // Create |DummyPrefStore|s.
+ enforced_pref_store_ = new DummyPrefStore();
+ enforced_pref_store_->set_prefs(enforced_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(
+ enforced_pref_store_,
+ extension_pref_store_,
+ command_line_pref_store_,
+ user_pref_store_,
+ recommended_pref_store_,
+ default_pref_store_);
+
+ // Register prefs with the PrefValueStore.
+ pref_value_store_->RegisterPreferenceType(prefs::kApplicationLocale,
+ Value::TYPE_STRING);
+ pref_value_store_->RegisterPreferenceType(prefs::kCurrentThemeID,
+ Value::TYPE_STRING);
+ pref_value_store_->RegisterPreferenceType(prefs::kDeleteCache,
+ Value::TYPE_BOOLEAN);
+ pref_value_store_->RegisterPreferenceType(prefs::kHomepage,
+ Value::TYPE_STRING);
+ pref_value_store_->RegisterPreferenceType(prefs::kMaxTabs,
+ Value::TYPE_INTEGER);
+ pref_value_store_->RegisterPreferenceType(prefs::kRecommendedPref,
+ Value::TYPE_BOOLEAN);
+ pref_value_store_->RegisterPreferenceType(prefs::kSampleDict,
+ Value::TYPE_DICTIONARY);
+ pref_value_store_->RegisterPreferenceType(prefs::kSampleList,
+ Value::TYPE_LIST);
+ pref_value_store_->RegisterPreferenceType(prefs::kDefaultPref,
+ Value::TYPE_INTEGER);
+
+ ui_thread_.reset(new ChromeThread(ChromeThread::UI, &loop_));
+ file_thread_.reset(new ChromeThread(ChromeThread::FILE, &loop_));
+ }
+
+ // 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::kMaxTabs, user_pref::kMaxTabsValue);
+ user_prefs->SetString(prefs::kCurrentThemeID,
+ user_pref::kCurrentThemeIDValue);
+ user_prefs->SetString(prefs::kApplicationLocale,
+ user_pref::kApplicationLocaleValue);
+ user_prefs->SetString(prefs::kHomepage, user_pref::kHomepageValue);
+ return user_prefs;
+ }
+
+ DictionaryValue* CreateEnforcedPrefs() {
+ DictionaryValue* enforced_prefs = new DictionaryValue();
+ enforced_prefs->SetString(prefs::kHomepage, enforced_pref::kHomepageValue);
+ expected_differing_paths_.push_back(prefs::kHomepage);
+ return enforced_prefs;
+ }
+
+ DictionaryValue* CreateExtensionPrefs() {
+ DictionaryValue* extension_prefs = new DictionaryValue();
+ extension_prefs->SetString(prefs::kCurrentThemeID,
+ extension_pref::kCurrentThemeIDValue);
+ extension_prefs->SetString(prefs::kHomepage,
+ extension_pref::kHomepageValue);
+ return extension_prefs;
+ }
+
+ DictionaryValue* CreateCommandLinePrefs() {
+ DictionaryValue* command_line_prefs = new DictionaryValue();
+ command_line_prefs->SetString(prefs::kCurrentThemeID,
+ command_line_pref::kCurrentThemeIDValue);
+ command_line_prefs->SetString(prefs::kApplicationLocale,
+ command_line_pref::kApplicationLocaleValue);
+ command_line_prefs->SetString(prefs::kHomepage,
+ command_line_pref::kHomepageValue);
+ return command_line_prefs;
+ }
+
+ DictionaryValue* CreateRecommendedPrefs() {
+ DictionaryValue* recommended_prefs = new DictionaryValue();
+ recommended_prefs->SetInteger(prefs::kMaxTabs,
+ recommended_pref::kMaxTabsValue);
+ recommended_prefs->SetBoolean(
+ prefs::kRecommendedPref,
+ recommended_pref::kRecommendedPrefValue);
+
+ // Expected differing paths must be added in lexicographic order
+ // to work properly
+ expected_differing_paths_.push_back("tabs");
+ expected_differing_paths_.push_back(prefs::kMaxTabs);
+ expected_differing_paths_.push_back("this");
+ expected_differing_paths_.push_back("this.pref");
+ expected_differing_paths_.push_back(prefs::kRecommendedPref);
+ return recommended_prefs;
+ }
+
+ DictionaryValue* CreateDefaultPrefs() {
+ DictionaryValue* default_prefs = new DictionaryValue();
+ default_prefs->SetInteger(prefs::kDefaultPref, default_pref::kDefaultValue);
+ return default_prefs;
+ }
+
+ DictionaryValue* CreateSampleDictValue() {
+ DictionaryValue* sample_dict = new DictionaryValue();
+ sample_dict->SetBoolean("issample", true);
+ sample_dict->SetInteger("value", 4);
+ sample_dict->SetString("descr", "Sample Test Dictionary");
+ return sample_dict;
+ }
+
+ ListValue* CreateSampleListValue() {
+ ListValue* sample_list = new ListValue();
+ sample_list->Set(0, Value::CreateIntegerValue(0));
+ sample_list->Set(1, Value::CreateIntegerValue(1));
+ sample_list->Set(2, Value::CreateIntegerValue(2));
+ sample_list->Set(3, Value::CreateIntegerValue(3));
+ return sample_list;
+ }
+
+ virtual void TearDown() {
+ loop_.RunAllPending();
+ }
+
+ MessageLoop loop_;
+
+ scoped_refptr<TestingPrefService::TestingPrefValueStore> pref_value_store_;
+
+ // |PrefStore|s are owned by the |PrefValueStore|.
+ DummyPrefStore* enforced_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* enforced_prefs_;
+ DictionaryValue* extension_prefs_;
+ DictionaryValue* command_line_prefs_;
+ DictionaryValue* user_prefs_;
+ DictionaryValue* recommended_prefs_;
+ DictionaryValue* default_prefs_;
+
+ private:
+ scoped_ptr<ChromeThread> ui_thread_;
+ scoped_ptr<ChromeThread> file_thread_;
+};
+
+TEST_F(PrefValueStoreTest, IsReadOnly) {
+ enforced_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;
+
+ // Test getting an enforced value overwriting a user-defined and
+ // extension-defined value.
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomepage, &value));
+ std::string actual_str_value;
+ EXPECT_TRUE(value->GetAsString(&actual_str_value));
+ EXPECT_EQ(enforced_pref::kHomepageValue, actual_str_value);
+
+ // Test getting an extension value overwriting a user-defined and
+ // command-line-defined value.
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kCurrentThemeID, &value));
+ EXPECT_TRUE(value->GetAsString(&actual_str_value));
+ EXPECT_EQ(extension_pref::kCurrentThemeIDValue, actual_str_value);
+
+ // Test getting a command-line value overwriting a user-defined value.
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kApplicationLocale, &value));
+ EXPECT_TRUE(value->GetAsString(&actual_str_value));
+ EXPECT_EQ(command_line_pref::kApplicationLocaleValue, actual_str_value);
+
+ // Test getting a user-set value.
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kDeleteCache, &value));
+ bool actual_bool_value = false;
+ EXPECT_TRUE(value->GetAsBoolean(&actual_bool_value));
+ EXPECT_EQ(user_pref::kDeleteCacheValue, actual_bool_value);
+
+ // Test getting a user set value overwriting a recommended value.
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kMaxTabs, &value));
+ int actual_int_value = -1;
+ EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+ EXPECT_EQ(user_pref::kMaxTabsValue, actual_int_value);
+
+ // Test getting a recommended value.
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kRecommendedPref, &value));
+ actual_bool_value = false;
+ EXPECT_TRUE(value->GetAsBoolean(&actual_bool_value));
+ EXPECT_EQ(recommended_pref::kRecommendedPrefValue, actual_bool_value);
+
+ // Test getting a default value.
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kDefaultPref, &value));
+ actual_int_value = -1;
+ EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+ EXPECT_EQ(default_pref::kDefaultValue, actual_int_value);
+
+ // Test getting a preference value that the |PrefValueStore|
+ // does not contain.
+ FundamentalValue tmp_dummy_value(true);
+ Value* v_null = &tmp_dummy_value;
+ ASSERT_FALSE(pref_value_store_->GetValue(prefs::kMissingPref, &v_null));
+ ASSERT_TRUE(v_null == NULL);
+}
+
+// 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) {
+ // Check falling back to a recommended value.
+ user_pref_store_->prefs()->SetString(prefs::kMaxTabs, "not an integer");
+ Value* value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kMaxTabs, &value));
+ ASSERT_TRUE(value != NULL);
+ ASSERT_EQ(Value::TYPE_INTEGER, value->GetType());
+ int actual_int_value = -1;
+ EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+ EXPECT_EQ(recommended_pref::kMaxTabsValue, actual_int_value);
+
+ // Check falling back multiple times, to a default string.
+ enforced_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);
+
+ value = NULL;
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomepage, &value));
+ ASSERT_TRUE(value != NULL);
+ ASSERT_EQ(Value::TYPE_STRING, value->GetType());
+ std::string actual_str_value;
+ EXPECT_TRUE(value->GetAsString(&actual_str_value));
+ EXPECT_EQ(default_pref::kHomepageValue, actual_str_value);
+}
+
+TEST_F(PrefValueStoreTest, HasPrefPath) {
+ // Enforced preference
+ EXPECT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
+ // User preference
+ EXPECT_TRUE(pref_value_store_->HasPrefPath(prefs::kDeleteCache));
+ // Recommended preference
+ EXPECT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
+ // Default preference
+ EXPECT_FALSE(pref_value_store_->HasPrefPath(prefs::kDefaultPref));
+ // Unknown preference
+ EXPECT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefHasChanged) {
+ // Setup.
+ const char managed_pref_path[] = "managed_pref";
+ pref_value_store_->RegisterPreferenceType(managed_pref_path,
+ Value::TYPE_STRING);
+ enforced_pref_store_->prefs()->SetString(managed_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");
+ 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");
+
+ // Check pref controlled by highest-priority store.
+ EXPECT_TRUE(pref_value_store_->PrefHasChanged(managed_pref_path,
+ static_cast<PrefNotifier::PrefStoreType>(0)));
+ EXPECT_FALSE(pref_value_store_->PrefHasChanged(managed_pref_path,
+ PrefNotifier::USER_STORE));
+
+ // 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));
+}
+
+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));
+}
+
+TEST_F(PrefValueStoreTest, WritePrefs) {
+ user_pref_store_->set_prefs_written(false);
+ pref_value_store_->WritePrefs();
+ ASSERT_TRUE(user_pref_store_->get_prefs_written());
+}
+
+TEST_F(PrefValueStoreTest, SetUserPrefValue) {
+ Value* new_value = NULL;
+ Value* actual_value = NULL;
+
+ // Test that enforced values can not be set.
+ ASSERT_TRUE(pref_value_store_->PrefValueInManagedStore(prefs::kHomepage));
+ // The Ownership is tranfered to |PrefValueStore|.
+ new_value = Value::CreateStringValue("http://www.youtube.com");
+ pref_value_store_->SetUserPrefValue(prefs::kHomepage, new_value);
+
+ ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomepage, &actual_value));
+ std::string value_str;
+ actual_value->GetAsString(&value_str);
+ ASSERT_EQ(enforced_pref::kHomepageValue, value_str);
+
+ // User preferences values can be set
+ ASSERT_FALSE(pref_value_store_->PrefValueInManagedStore(prefs::kMaxTabs));
+ actual_value = NULL;
+ pref_value_store_->GetValue(prefs::kMaxTabs, &actual_value);
+ int int_value;
+ EXPECT_TRUE(actual_value->GetAsInteger(&int_value));
+ EXPECT_EQ(user_pref::kMaxTabsValue, int_value);
+
+ new_value = Value::CreateIntegerValue(1);
+ pref_value_store_->SetUserPrefValue(prefs::kMaxTabs, new_value);
+ actual_value = NULL;
+ pref_value_store_->GetValue(prefs::kMaxTabs, &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, PrefValueInManagedStore) {
+ // Test an enforced preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
+ EXPECT_TRUE(pref_value_store_->PrefValueInManagedStore(prefs::kHomepage));
+
+ // Test an extension preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kCurrentThemeID));
+ EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+ prefs::kCurrentThemeID));
+
+ // Test a command-line preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kApplicationLocale));
+ EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+ prefs::kApplicationLocale));
+
+ // Test a user preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kMaxTabs));
+ EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(prefs::kMaxTabs));
+
+ // Test a preference from the recommended pref store.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+ prefs::kRecommendedPref));
+
+ // Test a preference from the default pref store.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kDefaultPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+ prefs::kDefaultPref));
+
+ // Test a preference for which the PrefValueStore does not contain a value.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) {
+ // Test an enforced preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
+ EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(prefs::kHomepage));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+ prefs::kHomepage));
+
+ // Test an extension preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kCurrentThemeID));
+ EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
+ prefs::kCurrentThemeID));
+ EXPECT_TRUE(pref_value_store_->PrefValueFromExtensionStore(
+ prefs::kCurrentThemeID));
+
+ // Test a command-line preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kApplicationLocale));
+ EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+ prefs::kApplicationLocale));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+ prefs::kApplicationLocale));
+
+ // Test a user preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kMaxTabs));
+ EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(prefs::kMaxTabs));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(prefs::kMaxTabs));
+
+ // Test a preference from the recommended pref store.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+ prefs::kRecommendedPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+ prefs::kRecommendedPref));
+
+ // Test a preference from the default pref store.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kDefaultPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+ prefs::kDefaultPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+ prefs::kDefaultPref));
+
+ // Test a preference for which the PrefValueStore does not contain a value.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+ prefs::kMissingPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+ prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInUserStore) {
+ // Test an enforced preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
+ EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(prefs::kHomepage));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(prefs::kHomepage));
+
+ // Test an extension preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kCurrentThemeID));
+ EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+ prefs::kCurrentThemeID));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+ prefs::kCurrentThemeID));
+
+ // Test a command-line preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kApplicationLocale));
+ EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+ prefs::kApplicationLocale));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+ prefs::kApplicationLocale));
+
+ // Test a user preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kMaxTabs));
+ EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(prefs::kMaxTabs));
+ EXPECT_TRUE(pref_value_store_->PrefValueFromUserStore(prefs::kMaxTabs));
+
+ // Test a preference from the recommended pref store.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
+ prefs::kRecommendedPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+ prefs::kRecommendedPref));
+
+ // Test a preference from the default pref store.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kDefaultPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(prefs::kDefaultPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(prefs::kDefaultPref));
+
+ // Test a preference for which the PrefValueStore does not contain a value.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(prefs::kMissingPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromDefaultStore) {
+ // Test an enforced preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomepage));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(prefs::kHomepage));
+
+ // Test an extension preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kCurrentThemeID));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+ prefs::kCurrentThemeID));
+
+ // Test a command-line preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kApplicationLocale));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+ prefs::kApplicationLocale));
+
+ // Test a user preference.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kMaxTabs));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(prefs::kMaxTabs));
+
+ // Test a preference from the recommended pref store.
+ ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kRecommendedPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+ prefs::kRecommendedPref));
+
+ // Test a preference from the default pref store.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kDefaultPref));
+ EXPECT_TRUE(
+ pref_value_store_->PrefValueFromDefaultStore(prefs::kDefaultPref));
+
+ // Test a preference for which the PrefValueStore does not contain a value.
+ ASSERT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
+ EXPECT_FALSE(
+ pref_value_store_->PrefValueFromDefaultStore(prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, TestPolicyRefresh) {
+ // pref_value_store_ is initialized by PrefValueStoreTest to have values
+ // in both it's managed and recommended store. By replacing them with
+ // dummy stores, all of the paths of the prefs originally managed and
+ // recommended stores should change.
+ MockPolicyRefreshCallback callback;
+ EXPECT_CALL(callback, DoCallback(_)).Times(0);
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ pref_value_store_.get(),
+ &PrefValueStore::RefreshPolicyPrefs,
+ new DummyPrefStore(),
+ new DummyPrefStore(),
+ 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 managed 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_store(new DummyPrefStore());
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("homepage", "some other changed homepage");
+ new_managed_store->set_prefs(dict);
+ MockPolicyRefreshCallback callback;
+ EXPECT_CALL(callback, DoCallback(expected_differing_paths_)).Times(1);
+ pref_value_store_->RefreshPolicyPrefsCompletion(
+ new_managed_store.release(),
+ new DummyPrefStore(),
+ NewCallback(&callback,
+ &MockPolicyRefreshCallback::DoCallback));
+
+ // Test properties that have been removed from the managed 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(),
+ NewCallback(&callback2,
+ &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 callback3;
+ EXPECT_CALL(callback3, DoCallback(expected_differing_paths_)).Times(1);
+ pref_value_store_->RefreshPolicyPrefsCompletion(
+ new DummyPrefStore(),
+ new_recommended_store.release(),
+ NewCallback(&callback3,
+ &MockPolicyRefreshCallback::DoCallback));
+
+ // Test adding a multi-key path.
+ new_managed_store.reset(new DummyPrefStore());
+ dict = new DictionaryValue();
+ dict->SetString("segment1.segment2", "value");
+ new_managed_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 callback4;
+ EXPECT_CALL(callback4, DoCallback(expected_differing_paths_)).Times(1);
+ pref_value_store_->RefreshPolicyPrefsCompletion(
+ new_managed_store.release(),
+ new DummyPrefStore(),
+ NewCallback(&callback4,
+ &MockPolicyRefreshCallback::DoCallback));
+}
+
+TEST_F(PrefValueStoreTest, TestConcurrentPolicyRefresh) {
+ MockPolicyRefreshCallback callback1;
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ pref_value_store_.get(),
+ &PrefValueStore::RefreshPolicyPrefs,
+ new DummyPrefStore(),
+ new DummyPrefStore(),
+ NewCallback(&callback1,
+ &MockPolicyRefreshCallback::DoCallback)));
+ EXPECT_CALL(callback1, DoCallback(_)).Times(0);
+
+ MockPolicyRefreshCallback callback2;
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ pref_value_store_.get(),
+ &PrefValueStore::RefreshPolicyPrefs,
+ new DummyPrefStore(),
+ new DummyPrefStore(),
+ NewCallback(&callback2,
+ &MockPolicyRefreshCallback::DoCallback)));
+ EXPECT_CALL(callback2, DoCallback(_)).Times(0);
+
+ MockPolicyRefreshCallback callback3;
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ pref_value_store_.get(),
+ &PrefValueStore::RefreshPolicyPrefs,
+ new DummyPrefStore(),
+ new DummyPrefStore(),
+ 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/scoped_pref_update.cc b/chrome/browser/prefs/scoped_pref_update.cc
index 36d2306..bc77b28 100644
--- a/chrome/browser/scoped_pref_update.cc
+++ b/chrome/browser/prefs/scoped_pref_update.cc
@@ -2,14 +2,14 @@
// 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/pref_service.h"
-#include "chrome/browser/scoped_pref_update.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
-ScopedPrefUpdate::ScopedPrefUpdate(PrefService* service, const wchar_t* path)
+#include "chrome/browser/prefs/pref_service.h"
+
+ScopedPrefUpdate::ScopedPrefUpdate(PrefService* service, const char* path)
: service_(service),
path_(path) {}
ScopedPrefUpdate::~ScopedPrefUpdate() {
- service_->FireObservers(path_.c_str());
+ service_->pref_notifier()->FireObservers(path_.c_str());
}
diff --git a/chrome/browser/scoped_pref_update.h b/chrome/browser/prefs/scoped_pref_update.h
index 661a99a..6a325bb 100644
--- a/chrome/browser/scoped_pref_update.h
+++ b/chrome/browser/prefs/scoped_pref_update.h
@@ -5,19 +5,20 @@
// A helper class that assists preferences in firing notifications when lists
// are changed.
-#ifndef CHROME_BROWSER_SCOPED_PREF_UPDATE_H_
-#define CHROME_BROWSER_SCOPED_PREF_UPDATE_H_
+#ifndef CHROME_BROWSER_PREFS_SCOPED_PREF_UPDATE_H_
+#define CHROME_BROWSER_PREFS_SCOPED_PREF_UPDATE_H_
+#pragma once
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
class ScopedPrefUpdate {
public:
- ScopedPrefUpdate(PrefService* service, const wchar_t* path);
+ ScopedPrefUpdate(PrefService* service, const char* path);
~ScopedPrefUpdate();
private:
PrefService* service_;
- std::wstring path_;
+ std::string path_;
};
-#endif
+#endif // CHROME_BROWSER_PREFS_SCOPED_PREF_UPDATE_H_
diff --git a/chrome/browser/session_startup_pref.cc b/chrome/browser/prefs/session_startup_pref.cc
index 1da5802..1e41f12 100644
--- a/chrome/browser/session_startup_pref.cc
+++ b/chrome/browser/prefs/session_startup_pref.cc
@@ -1,16 +1,18 @@
-// 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/session_startup_pref.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
#include <string>
+#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/defaults.h"
-#include "chrome/browser/pref_service.h"
+#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/scoped_pref_update.h"
#include "chrome/common/pref_names.h"
namespace {
@@ -60,19 +62,23 @@ void SessionStartupPref::SetStartupPref(
void SessionStartupPref::SetStartupPref(PrefService* prefs,
const SessionStartupPref& pref) {
DCHECK(prefs);
- prefs->SetInteger(prefs::kRestoreOnStartup, TypeToPrefValue(pref.type));
-
- // Always save the URLs, that way the UI can remain consistent even if the
- // user changes the startup type pref.
- // Ownership of the ListValue retains with the pref service.
- ScopedPrefUpdate update(prefs, prefs::kURLsToRestoreOnStartup);
- ListValue* url_pref_list =
- prefs->GetMutableList(prefs::kURLsToRestoreOnStartup);
- DCHECK(url_pref_list);
- url_pref_list->Clear();
- for (size_t i = 0; i < pref.urls.size(); ++i) {
- url_pref_list->Set(static_cast<int>(i),
- new StringValue(UTF8ToWide(pref.urls[i].spec())));
+
+ if (!SessionStartupPref::TypeIsManaged(prefs))
+ prefs->SetInteger(prefs::kRestoreOnStartup, TypeToPrefValue(pref.type));
+
+ if (!SessionStartupPref::URLsAreManaged(prefs)) {
+ // Always save the URLs, that way the UI can remain consistent even if the
+ // user changes the startup type pref.
+ // Ownership of the ListValue retains with the pref service.
+ ScopedPrefUpdate update(prefs, prefs::kURLsToRestoreOnStartup);
+ ListValue* url_pref_list =
+ prefs->GetMutableList(prefs::kURLsToRestoreOnStartup);
+ DCHECK(url_pref_list);
+ url_pref_list->Clear();
+ for (size_t i = 0; i < pref.urls.size(); ++i) {
+ url_pref_list->Set(static_cast<int>(i),
+ new StringValue(pref.urls[i].spec()));
+ }
}
}
@@ -97,10 +103,30 @@ SessionStartupPref SessionStartupPref::GetStartupPref(PrefService* prefs) {
Value* value = NULL;
if (url_pref_list->Get(i, &value)) {
std::string url_text;
- if (value->GetAsString(&url_text))
- pref.urls.push_back(GURL(url_text));
+ if (value->GetAsString(&url_text)) {
+ GURL fixed_url = URLFixerUpper::FixupURL(url_text, "");
+ pref.urls.push_back(fixed_url);
+ }
}
}
-
return pref;
}
+
+// static
+bool SessionStartupPref::TypeIsManaged(PrefService* prefs) {
+ DCHECK(prefs);
+ const PrefService::Preference* pref_restore =
+ prefs->FindPreference(prefs::kRestoreOnStartup);
+ DCHECK(pref_restore);
+ return pref_restore->IsManaged();
+}
+
+// static
+bool SessionStartupPref::URLsAreManaged(PrefService* prefs) {
+ DCHECK(prefs);
+ const PrefService::Preference* pref_urls =
+ prefs->FindPreference(prefs::kURLsToRestoreOnStartup);
+ DCHECK(pref_urls);
+ return pref_urls->IsManaged();
+}
+
diff --git a/chrome/browser/session_startup_pref.h b/chrome/browser/prefs/session_startup_pref.h
index 4cf8a78..d7cfaac 100644
--- a/chrome/browser/session_startup_pref.h
+++ b/chrome/browser/prefs/session_startup_pref.h
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_SESSION_STARTUP_PREF_H__
-#define CHROME_BROWSER_SESSION_STARTUP_PREF_H__
+#ifndef CHROME_BROWSER_PREFS_SESSION_STARTUP_PREF_H__
+#define CHROME_BROWSER_PREFS_SESSION_STARTUP_PREF_H__
+#pragma once
#include <vector>
@@ -36,6 +37,10 @@ struct SessionStartupPref {
static SessionStartupPref GetStartupPref(Profile* profile);
static SessionStartupPref GetStartupPref(PrefService* prefs);
+ // Whether the startup type and URLs are managed via policy.
+ static bool TypeIsManaged(PrefService* prefs);
+ static bool URLsAreManaged(PrefService* prefs);
+
SessionStartupPref() : type(DEFAULT) {}
explicit SessionStartupPref(Type type) : type(type) {}
@@ -47,4 +52,4 @@ struct SessionStartupPref {
std::vector<GURL> urls;
};
-#endif // CHROME_BROWSER_SESSION_STARTUP_PREF_H__
+#endif // CHROME_BROWSER_PREFS_SESSION_STARTUP_PREF_H__
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 87b4450..1067923 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
@@ -7,18 +7,47 @@
#include <stack>
#include <vector>
-#include "base/path_service.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/chrome_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/profile_manager.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
-#include "chrome/browser/pref_service.h"
+#include "grit/generated_resources.h"
-CloudPrintProxyService::CloudPrintProxyService(Profile* profile) {
+// TODO(sanjeevr): Localize the product name?
+const char kCloudPrintProductName[] = "Google Cloud Print";
+
+class CloudPrintProxyService::TokenExpiredNotificationDelegate
+ : public NotificationDelegate {
+ public:
+ explicit TokenExpiredNotificationDelegate(
+ CloudPrintProxyService* cloud_print_service)
+ : cloud_print_service_(cloud_print_service) {
+ }
+ void Display() {}
+ void Error() {
+ cloud_print_service_->OnTokenExpiredNotificationError();
+ }
+ void Close(bool by_user) {
+ cloud_print_service_->OnTokenExpiredNotificationClosed(by_user);
+ }
+ void Click() {
+ cloud_print_service_->OnTokenExpiredNotificationClick();
+ }
+ std::string id() const { return "cloudprint.tokenexpired"; }
+
+ private:
+ CloudPrintProxyService* cloud_print_service_;
+ DISALLOW_COPY_AND_ASSIGN(TokenExpiredNotificationDelegate);
+};
+
+CloudPrintProxyService::CloudPrintProxyService(Profile* profile)
+ : profile_(profile), token_expired_delegate_(NULL) {
}
CloudPrintProxyService::~CloudPrintProxyService() {
@@ -43,3 +72,57 @@ void CloudPrintProxyService::Shutdown() {
// running in the service process here.
}
+bool CloudPrintProxyService::ShowTokenExpiredNotification() {
+ // If we already have a pending notification, don't show another one.
+ if (token_expired_delegate_.get())
+ return false;
+
+ // TODO(sanjeevr): Get icon for this notification.
+ GURL icon_url;
+
+ string16 title = UTF8ToUTF16(kCloudPrintProductName);
+ string16 message =
+ l10n_util::GetStringUTF16(IDS_CLOUD_PRINT_TOKEN_EXPIRED_MESSAGE);
+ string16 content_url = DesktopNotificationService::CreateDataUrl(
+ icon_url, title, message, WebKit::WebTextDirectionDefault);
+ token_expired_delegate_ = new TokenExpiredNotificationDelegate(this);
+ Notification notification(GURL(), GURL(content_url), string16(), string16(),
+ token_expired_delegate_.get());
+ g_browser_process->notification_ui_manager()->Add(notification, profile_);
+ // Keep the browser alive while we are showing the notification.
+ BrowserList::StartKeepAlive();
+ return true;
+}
+
+void CloudPrintProxyService::OnTokenExpiredNotificationError() {
+ TokenExpiredNotificationDone(false);
+}
+
+void CloudPrintProxyService::OnTokenExpiredNotificationClosed(bool by_user) {
+ TokenExpiredNotificationDone(false);
+}
+
+void CloudPrintProxyService::OnTokenExpiredNotificationClick() {
+ TokenExpiredNotificationDone(true);
+ // Clear the cached cloud print email pref so that the cloud print setup
+ // flow happens.
+ profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string());
+ CloudPrintSetupFlow::OpenDialog(profile_, this, NULL);
+}
+
+void CloudPrintProxyService::TokenExpiredNotificationDone(bool keep_alive) {
+ if (token_expired_delegate_.get()) {
+ g_browser_process->notification_ui_manager()->Cancel(
+ Notification(GURL(), GURL(), string16(), string16(),
+ token_expired_delegate_.get()));
+ token_expired_delegate_ = NULL;
+ if (!keep_alive)
+ BrowserList::EndKeepAlive();
+ }
+}
+
+void CloudPrintProxyService::OnDialogClosed() {
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableFunction(&BrowserList::EndKeepAlive));
+}
+
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
index a3795b0..538da2c 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
@@ -4,23 +4,20 @@
#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_PROXY_SERVICE_H_
#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_PROXY_SERVICE_H_
+#pragma once
#include <string>
-#include <map>
-#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/observer_list.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/profile.h"
-
+#include "base/ref_counted.h"
+#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
class Profile;
// Layer between the browser user interface and the cloud print proxy code
// running in the service process.
-class CloudPrintProxyService {
+class CloudPrintProxyService : public CloudPrintSetupFlow::Delegate {
public:
explicit CloudPrintProxyService(Profile* profile);
virtual ~CloudPrintProxyService();
@@ -33,11 +30,27 @@ class CloudPrintProxyService {
virtual void EnableForUser(const std::string& auth_token);
virtual void DisableForUser();
- protected:
+ bool ShowTokenExpiredNotification();
+
+ // CloudPrintSetupFlow::Delegate implementation.
+ virtual void OnDialogClosed();
+
+ private:
+ // NotificationDelegate implementation for the token expired notification.
+ class TokenExpiredNotificationDelegate;
+ friend class TokenExpiredNotificationDelegate;
+
+ Profile* profile_;
+ scoped_refptr<TokenExpiredNotificationDelegate> token_expired_delegate_;
+
void Shutdown();
+ void OnTokenExpiredNotificationError();
+ void OnTokenExpiredNotificationClosed(bool by_user);
+ void OnTokenExpiredNotificationClick();
+ void TokenExpiredNotificationDone(bool keep_alive);
+
DISALLOW_COPY_AND_ASSIGN(CloudPrintProxyService);
};
#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_PROXY_SERVICE_H_
-
diff --git a/chrome/browser/printing/print_dialog_cloud.cc b/chrome/browser/printing/print_dialog_cloud.cc
index 8e7a839..6209038 100644
--- a/chrome/browser/printing/print_dialog_cloud.cc
+++ b/chrome/browser/printing/print_dialog_cloud.cc
@@ -7,28 +7,25 @@
#include "app/l10n_util.h"
#include "base/base64.h"
-#include "base/command_line.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
-#include "base/logging.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
-#include "chrome/browser/debugger/devtools_manager.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_source.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
+#include "webkit/glue/webpreferences.h"
#include "grit/generated_resources.h"
@@ -98,46 +95,8 @@
namespace internal_cloud_print_helpers {
-const char kDefaultCloudPrintServiceURL[] = "https://www.google.com/cloudprint";
-
-void CloudPrintService::RegisterPreferences() {
- DCHECK(profile_);
- PrefService* pref_service = profile_->GetPrefs();
- if (pref_service->FindPreference(prefs::kCloudPrintServiceURL))
- return;
- pref_service->RegisterStringPref(prefs::kCloudPrintServiceURL,
- kDefaultCloudPrintServiceURL);
-}
-
-// Returns the root service URL for the cloud print service. The
-// default is to point at the Google Cloud Print service. This can be
-// overridden by the command line or by the user preferences.
-GURL CloudPrintService::GetCloudPrintServiceURL() {
- DCHECK(profile_);
- RegisterPreferences();
-
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- GURL cloud_print_service_url = GURL(command_line.GetSwitchValueASCII(
- switches::kCloudPrintServiceURL));
- if (cloud_print_service_url.is_empty()) {
- cloud_print_service_url = GURL(
- profile_->GetPrefs()->GetString(prefs::kCloudPrintServiceURL));
- }
- return cloud_print_service_url;
-}
-
-GURL CloudPrintService::GetCloudPrintServiceDialogURL() {
- GURL cloud_print_service_url = GetCloudPrintServiceURL();
- std::string path(cloud_print_service_url.path() + "/client/dialog.html");
- GURL::Replacements replacements;
- replacements.SetPathStr(path);
- GURL cloud_print_dialog_url = cloud_print_service_url.ReplaceComponents(
- replacements);
- return cloud_print_dialog_url;
-}
-
bool GetRealOrInt(const DictionaryValue& dictionary,
- const std::wstring& path,
+ const std::string& path,
double* out_value) {
if (!dictionary.GetReal(path, out_value)) {
int int_value = 0;
@@ -161,10 +120,10 @@ bool GetPageSetupParameters(const std::string& json,
bool result = true;
DictionaryValue* params = static_cast<DictionaryValue*>(parsed_value.get());
- result &= GetRealOrInt(*params, L"dpi", &parameters.dpi);
- result &= GetRealOrInt(*params, L"min_shrink", &parameters.min_shrink);
- result &= GetRealOrInt(*params, L"max_shrink", &parameters.max_shrink);
- result &= params->GetBoolean(L"selection_only", &parameters.selection_only);
+ result &= GetRealOrInt(*params, "dpi", &parameters.dpi);
+ result &= GetRealOrInt(*params, "min_shrink", &parameters.min_shrink);
+ result &= GetRealOrInt(*params, "max_shrink", &parameters.max_shrink);
+ result &= params->GetBoolean("selection_only", &parameters.selection_only);
return result;
}
@@ -302,7 +261,7 @@ void CloudPrintFlowHandler::RegisterMessages() {
NavigationController* controller = &dom_ui_->tab_contents()->controller();
NavigationEntry* pending_entry = controller->pending_entry();
if (pending_entry)
- pending_entry->set_url(CloudPrintService(
+ pending_entry->set_url(CloudPrintURL(
dom_ui_->GetProfile()).GetCloudPrintServiceDialogURL());
registrar_.Add(this, NotificationType::LOAD_STOP,
Source<NavigationController>(controller));
@@ -323,7 +282,7 @@ void CloudPrintFlowHandler::Observe(NotificationType type,
}
}
-void CloudPrintFlowHandler::HandleShowDebugger(const Value* value) {
+void CloudPrintFlowHandler::HandleShowDebugger(const ListValue* args) {
ShowDebugger();
}
@@ -342,7 +301,7 @@ CloudPrintFlowHandler::CreateCloudPrintDataSender() {
return new CloudPrintDataSender(print_data_helper_.get(), print_job_title_);
}
-void CloudPrintFlowHandler::HandleSendPrintData(const Value* value) {
+void CloudPrintFlowHandler::HandleSendPrintData(const ListValue* args) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// This will cancel any ReadPrintDataFile() or SendPrintDataFile()
// requests in flight (this is anticipation of when setting page
@@ -359,8 +318,8 @@ void CloudPrintFlowHandler::HandleSendPrintData(const Value* value) {
}
}
-void CloudPrintFlowHandler::HandleSetPageParameters(const Value* value) {
- std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(value));
+void CloudPrintFlowHandler::HandleSetPageParameters(const ListValue* args) {
+ std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args));
if (json.empty())
return;
diff --git a/chrome/browser/printing/print_dialog_cloud.h b/chrome/browser/printing/print_dialog_cloud.h
index 6dacc66..28b2663 100644
--- a/chrome/browser/printing/print_dialog_cloud.h
+++ b/chrome/browser/printing/print_dialog_cloud.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PRINTING_PRINT_DIALOG_CLOUD_H_
#define CHROME_BROWSER_PRINTING_PRINT_DIALOG_CLOUD_H_
+#pragma once
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
diff --git a/chrome/browser/printing/print_dialog_cloud_internal.h b/chrome/browser/printing/print_dialog_cloud_internal.h
index 1cddfef..c40f301 100644
--- a/chrome/browser/printing/print_dialog_cloud_internal.h
+++ b/chrome/browser/printing/print_dialog_cloud_internal.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PRINTING_PRINT_DIALOG_CLOUD_INTERNAL_H_
#define CHROME_BROWSER_PRINTING_PRINT_DIALOG_CLOUD_INTERNAL_H_
+#pragma once
#include <string>
#include <vector>
@@ -22,20 +23,6 @@ class CloudPrintHtmlDialogDelegateTest;
namespace internal_cloud_print_helpers {
-// Centralize URL management for the cloud print service.
-class CloudPrintService {
- public:
- explicit CloudPrintService(Profile* profile) : profile_(profile) {}
-
- GURL GetCloudPrintServiceURL();
- GURL GetCloudPrintServiceDialogURL();
-
- private:
- void RegisterPreferences();
-
- Profile* profile_;
-};
-
// Small class to virtualize a few functions to aid with unit testing.
class CloudPrintDataSenderHelper {
public:
@@ -122,9 +109,9 @@ class CloudPrintFlowHandler : public DOMMessageHandler,
const NotificationDetails& details);
// Callbacks from the page.
- void HandleShowDebugger(const Value* value);
- void HandleSendPrintData(const Value* value);
- void HandleSetPageParameters(const Value* value);
+ void HandleShowDebugger(const ListValue* args);
+ void HandleSendPrintData(const ListValue* args);
+ void HandleSetPageParameters(const ListValue* args);
// Call to get the debugger loaded on our hosted dialog page
// specifically. Since we're not in an official browser tab, only
diff --git a/chrome/browser/printing/print_dialog_cloud_uitest.cc b/chrome/browser/printing/print_dialog_cloud_uitest.cc
index 4a07d8c..4b6dcb0 100644
--- a/chrome/browser/printing/print_dialog_cloud_uitest.cc
+++ b/chrome/browser/printing/print_dialog_cloud_uitest.cc
@@ -11,9 +11,11 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/singleton.h"
+#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
@@ -22,6 +24,7 @@
#include "chrome/test/ui_test_utils.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_unittest.h"
namespace {
@@ -76,7 +79,10 @@ class SimpleTestJob : public URLRequestTestJob {
class TestController {
public:
- TestController() : result_(false), use_delegate_(false) {}
+ TestController()
+ : result_(false),
+ use_delegate_(false),
+ delegate_(NULL) {}
void set_result(bool value) {
result_ = value;
}
@@ -152,7 +158,7 @@ class PrintDialogCloudTest : public InProcessBrowserTest {
if (!handler_added_) {
URLRequestFilter* filter = URLRequestFilter::GetInstance();
GURL cloud_print_service_url =
- internal_cloud_print_helpers::CloudPrintService(browser()->profile()).
+ CloudPrintURL(browser()->profile()).
GetCloudPrintServiceURL();
scheme_ = cloud_print_service_url.scheme();
host_name_ = cloud_print_service_url.host();
@@ -161,7 +167,7 @@ class PrintDialogCloudTest : public InProcessBrowserTest {
handler_added_ = true;
GURL cloud_print_dialog_url =
- internal_cloud_print_helpers::CloudPrintService(browser()->profile()).
+ CloudPrintURL(browser()->profile()).
GetCloudPrintServiceDialogURL();
Singleton<TestController>()->set_expected_url(cloud_print_dialog_url);
Singleton<TestController>()->set_delegate(&delegate_);
diff --git a/chrome/browser/printing/print_dialog_cloud_unittest.cc b/chrome/browser/printing/print_dialog_cloud_unittest.cc
index 5a1c669..5cde305 100644
--- a/chrome/browser/printing/print_dialog_cloud_unittest.cc
+++ b/chrome/browser/printing/print_dialog_cloud_unittest.cc
@@ -9,9 +9,11 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/weak_ptr.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer.h"
@@ -152,13 +154,13 @@ class CloudPrintURLTest : public testing::Test {
TEST_F(CloudPrintURLTest, CheckDefaultURLs) {
std::string service_url =
- internal_cloud_print_helpers::CloudPrintService(profile_.get()).
+ CloudPrintURL(profile_.get()).
GetCloudPrintServiceURL().spec();
EXPECT_THAT(service_url, HasSubstr("www.google.com"));
EXPECT_THAT(service_url, HasSubstr("cloudprint"));
std::string dialog_url =
- internal_cloud_print_helpers::CloudPrintService(profile_.get()).
+ CloudPrintURL(profile_.get()).
GetCloudPrintServiceDialogURL().spec();
EXPECT_THAT(dialog_url, HasSubstr("www.google.com"));
EXPECT_THAT(dialog_url, HasSubstr("/cloudprint/"));
@@ -168,7 +170,7 @@ TEST_F(CloudPrintURLTest, CheckDefaultURLs) {
// Repeat to make sure there isn't a transient glitch.
dialog_url =
- internal_cloud_print_helpers::CloudPrintService(profile_.get()).
+ CloudPrintURL(profile_.get()).
GetCloudPrintServiceDialogURL().spec();
EXPECT_THAT(dialog_url, HasSubstr("www.google.com"));
EXPECT_THAT(dialog_url, HasSubstr("/cloudprint/"));
diff --git a/chrome/browser/printing/print_dialog_gtk.cc b/chrome/browser/printing/print_dialog_gtk.cc
index 5cc203d..b8c0578 100644
--- a/chrome/browser/printing/print_dialog_gtk.cc
+++ b/chrome/browser/printing/print_dialog_gtk.cc
@@ -12,6 +12,7 @@
#include "base/lazy_instance.h"
#include "base/lock.h"
#include "base/logging.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
@@ -39,20 +40,18 @@ class PdfUnsupportedInfoBarDelegate : public LinkInfoBarDelegate {
virtual ~PdfUnsupportedInfoBarDelegate() {}
- virtual std::wstring GetMessageTextWithOffset(size_t* link_offset) const {
- std::wstring message(L"Oops! Your printer does not support PDF. Please "
- L"report this to us .");
+ virtual string16 GetMessageTextWithOffset(size_t* link_offset) const {
+ string16 message = UTF8ToUTF16("Oops! Your printer does not support PDF. "
+ "Please report this to us.");
*link_offset = message.length() - 1;
return message;
}
- virtual std::wstring GetLinkText() const {
- return std::wstring(L"here");
+ virtual string16 GetLinkText() const {
+ return UTF8ToUTF16("here");
}
- virtual Type GetInfoBarType() {
- return ERROR_TYPE;
- }
+ virtual Type GetInfoBarType() { return WARNING_TYPE; }
virtual bool LinkClicked(WindowOpenDisposition disposition) {
browser_->OpenURL(
@@ -111,7 +110,7 @@ PrintDialogGtk::~PrintDialogGtk() {
g_print_dialog = NULL;
}
-void PrintDialogGtk::OnResponse(gint response_id) {
+void PrintDialogGtk::OnResponse(GtkWidget* dialog, gint response_id) {
gtk_widget_hide(dialog_);
switch (response_id) {
@@ -154,6 +153,13 @@ void PrintDialogGtk::OnResponse(gint response_id) {
OnJobCompleted(NULL, NULL);
}
+void PrintDialogGtk::OnJobCompletedThunk(GtkPrintJob* print_job,
+ gpointer user_data,
+ GError* error) {
+ reinterpret_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job,
+ error);
+}
+
void PrintDialogGtk::OnJobCompleted(GtkPrintJob* job, GError* error) {
gtk_widget_destroy(dialog_);
diff --git a/chrome/browser/printing/print_dialog_gtk.h b/chrome/browser/printing/print_dialog_gtk.h
index 0c1087f..faeada9 100644
--- a/chrome/browser/printing/print_dialog_gtk.h
+++ b/chrome/browser/printing/print_dialog_gtk.h
@@ -4,9 +4,11 @@
#ifndef CHROME_BROWSER_PRINTING_PRINT_DIALOG_GTK_H_
#define CHROME_BROWSER_PRINTING_PRINT_DIALOG_GTK_H_
+#pragma once
#include <gtk/gtk.h>
+#include "app/gtk_signal.h"
#include "base/basictypes.h"
#include "base/file_path.h"
@@ -28,19 +30,11 @@ class PrintDialogGtk {
static void CreateDialogImpl(const FilePath& path);
- static void OnResponseThunk(GtkDialog* dialog,
- gint response_id,
- gpointer user_data) {
- reinterpret_cast<PrintDialogGtk*>(user_data)->OnResponse(response_id);
- }
- void OnResponse(gint response_id);
+ CHROMEGTK_CALLBACK_1(PrintDialogGtk, void, OnResponse, gint);
static void OnJobCompletedThunk(GtkPrintJob* print_job,
gpointer user_data,
- GError* error) {
- reinterpret_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job,
- error);
- }
+ GError* error);
void OnJobCompleted(GtkPrintJob* job, GError* error);
FilePath path_to_pdf_;
diff --git a/chrome/browser/printing/print_job.h b/chrome/browser/printing/print_job.h
index 640ffdb..b4eeb97 100644
--- a/chrome/browser/printing/print_job.h
+++ b/chrome/browser/printing/print_job.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_H_
+#pragma once
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/printing/print_job_worker_owner.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/printing/print_job_manager.h b/chrome/browser/printing/print_job_manager.h
index 2bfe2e5..59cc1ce 100644
--- a/chrome/browser/printing/print_job_manager.h
+++ b/chrome/browser/printing/print_job_manager.h
@@ -1,15 +1,16 @@
-// 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.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_
+#pragma once
-#include <string>
#include <vector>
#include "base/lock.h"
#include "base/ref_counted.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
namespace printing {
diff --git a/chrome/browser/printing/print_job_unittest.cc b/chrome/browser/printing/print_job_unittest.cc
index 87d7efa..fb737bc 100644
--- a/chrome/browser/printing/print_job_unittest.cc
+++ b/chrome/browser/printing/print_job_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/message_loop.h"
+#include "base/string16.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/common/notification_registrar.h"
@@ -15,8 +16,8 @@ namespace {
class TestSource : public printing::PrintedPagesSource {
public:
- virtual std::wstring RenderSourceName() {
- return L"";
+ virtual string16 RenderSourceName() {
+ return string16();
}
virtual GURL RenderSourceUrl() {
return GURL();
@@ -84,7 +85,13 @@ class TestPrintNotifObserv : public NotificationObserver {
} // namespace
-TEST(PrintJobTest, SimplePrint) {
+// Crashes, Bug 55181.
+#if defined(OS_WIN)
+#define MAYBE_SimplePrint DISABLED_SimplePrint
+#else
+#define MAYBE_SimplePrint SimplePrint
+#endif
+TEST(PrintJobTest, MAYBE_SimplePrint) {
// Test the multithreaded nature of PrintJob to make sure we can use it with
// known livetime.
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index 3a9ae03..20e51ea 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -78,17 +78,19 @@ void PrintJobWorker::GetSettings(bool ask_user_for_settings,
printing_context_.SetUseOverlays(use_overlays);
if (ask_user_for_settings) {
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(USE_X11)
ChromeThread::PostTask(
ChromeThread::UI, FROM_HERE,
NewRunnableMethod(this, &PrintJobWorker::GetSettingsWithUI,
parent_view, document_page_count,
has_selection));
#else
- PrintingContext::Result result = printing_context_.AskUserForSettings(
- parent_view, document_page_count, has_selection);
- GetSettingsDone(result);
-#endif
+ printing_context_.AskUserForSettings(
+ parent_view,
+ document_page_count,
+ has_selection,
+ NewCallback(this, &PrintJobWorker::GetSettingsDone));
+#endif // defined(OS_MACOSX) || defined(USE_X11)
} else {
PrintingContext::Result result = printing_context_.UseDefaultSettings();
GetSettingsDone(result);
@@ -110,18 +112,24 @@ void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
result));
}
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(USE_X11)
void PrintJobWorker::GetSettingsWithUI(gfx::NativeView parent_view,
int document_page_count,
bool has_selection) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- PrintingContext::Result result = printing_context_.AskUserForSettings(
- parent_view, document_page_count, has_selection);
+ printing_context_.AskUserForSettings(
+ parent_view,
+ document_page_count,
+ has_selection,
+ NewCallback(this, &PrintJobWorker::GetSettingsWithUIDone));
+}
+
+void PrintJobWorker::GetSettingsWithUIDone(PrintingContext::Result result) {
message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
this, &PrintJobWorker::GetSettingsDone, result));
}
-#endif
+#endif // defined(OS_MACOSX) || defined(USE_X11)
void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
DCHECK_EQ(message_loop(), MessageLoop::current());
@@ -129,9 +137,7 @@ void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
DCHECK_EQ(document_, new_document);
DCHECK(document_.get());
DCHECK(new_document->settings().Equals(printing_context_.settings()));
-#if !defined(OS_MACOSX)
- DCHECK(printing_context_.context());
-#endif
+
if (!document_.get() || page_number_ != PageNumber::npos() ||
document_ != new_document) {
return;
@@ -158,9 +164,7 @@ void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) {
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK(!new_document ||
new_document->settings().Equals(printing_context_.settings()));
-#if !defined(OS_MACOSX)
- DCHECK(printing_context_.context());
-#endif
+
if (page_number_ != PageNumber::npos())
return;
@@ -174,11 +178,6 @@ void PrintJobWorker::OnNewPage() {
}
// message_loop() could return NULL when the print job is cancelled.
DCHECK_EQ(message_loop(), MessageLoop::current());
-#if !defined(OS_MACOSX)
- DCHECK(printing_context_.context());
- if (!printing_context_.context())
- return;
-#endif
if (page_number_ == PageNumber::npos()) {
// Find first page to print.
@@ -231,9 +230,6 @@ void PrintJobWorker::OnDocumentDone() {
DCHECK_EQ(message_loop(), MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK(document_.get());
-#if !defined(OS_MACOSX)
- DCHECK(printing_context_.context());
-#endif
if (printing_context_.DocumentDone() != PrintingContext::OK) {
OnFailure();
@@ -255,9 +251,7 @@ void PrintJobWorker::OnDocumentDone() {
void PrintJobWorker::SpoolPage(PrintedPage& page) {
DCHECK_EQ(message_loop(), MessageLoop::current());
DCHECK_NE(page_number_, PageNumber::npos());
-#if !defined(OS_MACOSX)
- DCHECK(printing_context_.context());
-#endif
+
// Signal everyone that the page is about to be printed.
NotificationTask* task = new NotificationTask();
task->Init(owner_,
@@ -272,10 +266,6 @@ void PrintJobWorker::SpoolPage(PrintedPage& page) {
return;
}
-#if defined(OS_MACOSX)
- // Context is only valid between NewPage and PageDone, so we only check here.
- DCHECK(printing_context_.context());
-#endif
// Actual printing.
document_->RenderPrintedPage(page, printing_context_.context());
diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h
index ece1659..69b35e4 100644
--- a/chrome/browser/printing/print_job_worker.h
+++ b/chrome/browser/printing/print_job_worker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__
#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H__
+#pragma once
#include "base/task.h"
#include "base/thread.h"
@@ -80,12 +81,17 @@ class PrintJobWorker : public base::Thread {
// context.
void OnFailure();
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(USE_X11)
// Asks the user for print settings. Must be called on the UI thread.
- // Mac-only since Windows can display UI from non-main threads.
+ // 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);
+
+ // The callback used by PrintingContext::GetSettingsWithUI() to notify this
+ // 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
// Reports settings back to owner_.
diff --git a/chrome/browser/printing/print_job_worker_owner.h b/chrome/browser/printing/print_job_worker_owner.h
index cd600ef..eb35716 100644
--- a/chrome/browser/printing/print_job_worker_owner.h
+++ b/chrome/browser/printing/print_job_worker_owner.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__
#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__
+#pragma once
#include "base/ref_counted.h"
#include "printing/printing_context.h"
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index 1daecfb..7a838eb 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -6,6 +6,7 @@
#include "app/l10n_util.h"
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_job_manager.h"
@@ -14,7 +15,7 @@
#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/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "grit/generated_resources.h"
#include "printing/native_metafile.h"
#include "printing/printed_document.h"
@@ -56,10 +57,10 @@ bool PrintViewManager::OnRenderViewGone(RenderViewHost* render_view_host) {
return true;
}
-std::wstring PrintViewManager::RenderSourceName() {
- std::wstring name(UTF16ToWideHack(owner_.GetTitle()));
+string16 PrintViewManager::RenderSourceName() {
+ string16 name(owner_.GetTitle());
if (name.empty())
- name = l10n_util::GetString(IDS_DEFAULT_PRINT_DOCUMENT_TITLE);
+ name = l10n_util::GetStringUTF16(IDS_DEFAULT_PRINT_DOCUMENT_TITLE);
return name;
}
diff --git a/chrome/browser/printing/print_view_manager.h b/chrome/browser/printing/print_view_manager.h
index f599541..8f4b6a7 100644
--- a/chrome/browser/printing/print_view_manager.h
+++ b/chrome/browser/printing/print_view_manager.h
@@ -4,9 +4,12 @@
#ifndef CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_H_
#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_H_
+#pragma once
#include "base/ref_counted.h"
+#include "base/string16.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "printing/printed_pages_source.h"
@@ -37,7 +40,7 @@ class PrintViewManager : public NotificationObserver,
bool OnRenderViewGone(RenderViewHost* render_view_host);
// PrintedPagesSource implementation.
- virtual std::wstring RenderSourceName();
+ virtual string16 RenderSourceName();
virtual GURL RenderSourceUrl();
// RenderViewHostDelegate::Printing implementation.
diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h
index d1d054d..e55be3d 100644
--- a/chrome/browser/printing/printer_query.h
+++ b/chrome/browser/printing/printer_query.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_
#define CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "chrome/browser/printing/print_job_worker_owner.h"
diff --git a/chrome/browser/printing/printing_layout_uitest.cc b/chrome/browser/printing/printing_layout_uitest.cc
index 2392dd6..a87e239 100644
--- a/chrome/browser/printing/printing_layout_uitest.cc
+++ b/chrome/browser/printing/printing_layout_uitest.cc
@@ -6,14 +6,13 @@
#include "base/file_util.h"
#include "base/simple_thread.h"
#include "base/test/test_file_util.h"
-#include "base/win_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/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
#include "printing/image.h"
#include "printing/printing_test.h"
#include "printing/native_metafile.h"
@@ -23,15 +22,13 @@ namespace {
using printing::Image;
const char kGenerateSwitch[] = "print-layout-generate";
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
class PrintingLayoutTest : public PrintingTest<UITest> {
public:
PrintingLayoutTest() {
- emf_path_ = browser_directory_;
- emf_path_ = emf_path_.AppendASCII("metafile_dumps");
- launch_arguments_.AppendSwitchWithValue("debug-print",
- L'"' + emf_path_.value() + L'"');
+ emf_path_ = browser_directory_.AppendASCII("metafile_dumps");
+ launch_arguments_.AppendSwitchPath("debug-print", emf_path_);
show_window_ = true;
}
@@ -292,11 +289,10 @@ TEST_F(PrintingLayoutTextTest, FAILS_Complex) {
"close_printdlg_thread");
// Print a document, check its output.
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
- NavigateToURL(server->TestServerPage("files/printing/test1.html"));
+ NavigateToURL(test_server.GetURL("files/printing/test1.html"));
close_printdlg_thread.Start();
PrintNowTab();
close_printdlg_thread.Join();
@@ -324,9 +320,9 @@ TEST_F(PrintingLayoutTestHidden, DISABLED_ManyTimes) {
if (IsTestCaseDisabled())
return;
- scoped_refptr<HTTPTestServer> server(
- HTTPTestServer::CreateServer(kDocRoot, NULL));
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
DismissTheWindow dismisser(base::GetProcId(process()));
ASSERT_GT(arraysize(kTestPool), 0u);
@@ -334,7 +330,7 @@ TEST_F(PrintingLayoutTestHidden, DISABLED_ManyTimes) {
if (i)
CleanupDumpDirectory();
const TestPool& test = kTestPool[i % arraysize(kTestPool)];
- NavigateToURL(server->TestServerPage(test.source));
+ NavigateToURL(test_server.GetURL(test.source));
base::DelegateSimpleThread close_printdlg_thread1(&dismisser,
"close_printdlg_thread");
EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
@@ -375,15 +371,14 @@ TEST_F(PrintingLayoutTest, DISABLED_Delayed) {
if (IsTestCaseDisabled())
return;
- scoped_refptr<HTTPTestServer> server(
- HTTPTestServer::CreateServer(kDocRoot, NULL));
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
{
scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
ASSERT_TRUE(tab_proxy.get());
bool is_timeout = true;
- GURL url = server->TestServerPage("files/printing/popup_delayed_print.htm");
+ GURL url = test_server.GetURL("files/printing/popup_delayed_print.htm");
EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
tab_proxy->NavigateToURL(url));
@@ -394,7 +389,7 @@ TEST_F(PrintingLayoutTest, DISABLED_Delayed) {
close_printdlg_thread.Join();
// Force a navigation elsewhere to verify that it's fine with it.
- url = server->TestServerPage("files/printing/test1.html");
+ url = test_server.GetURL("files/printing/test1.html");
EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
tab_proxy->NavigateToURL(url));
}
@@ -410,14 +405,13 @@ TEST_F(PrintingLayoutTest, DISABLED_IFrame) {
if (IsTestCaseDisabled())
return;
- scoped_refptr<HTTPTestServer> server(
- HTTPTestServer::CreateServer(kDocRoot, NULL));
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
{
scoped_refptr<TabProxy> tab_proxy(GetActiveTab());
ASSERT_TRUE(tab_proxy.get());
- GURL url = server->TestServerPage("files/printing/iframe.htm");
+ GURL url = test_server.GetURL("files/printing/iframe.htm");
EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
tab_proxy->NavigateToURL(url));
@@ -428,7 +422,7 @@ TEST_F(PrintingLayoutTest, DISABLED_IFrame) {
close_printdlg_thread.Join();
// Force a navigation elsewhere to verify that it's fine with it.
- url = server->TestServerPage("files/printing/test1.html");
+ url = test_server.GetURL("files/printing/test1.html");
EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
tab_proxy->NavigateToURL(url));
}
diff --git a/chrome/browser/process_info_snapshot.h b/chrome/browser/process_info_snapshot.h
index 14e8ceb..e4e3f33 100644
--- a/chrome/browser/process_info_snapshot.h
+++ b/chrome/browser/process_info_snapshot.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_PROCESS_INFO_SNAPSHOT_H_
#define CHROME_BROWSER_PROCESS_INFO_SNAPSHOT_H_
+#pragma once
#include <sys/types.h>
diff --git a/chrome/browser/process_info_snapshot_mac.cc b/chrome/browser/process_info_snapshot_mac.cc
index 732f22e..0f20080 100644
--- a/chrome/browser/process_info_snapshot_mac.cc
+++ b/chrome/browser/process_info_snapshot_mac.cc
@@ -6,7 +6,9 @@
#include <sstream>
+#include "base/command_line.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/thread.h"
@@ -49,7 +51,7 @@ bool ProcessInfoSnapshot::Sample(std::vector<base::ProcessId> pid_list) {
for (std::vector<base::ProcessId>::iterator it = pid_list.begin();
it != pid_list.end(); ++it) {
argv.push_back("-p");
- argv.push_back(Int64ToString(static_cast<int64>(*it)));
+ argv.push_back(base::Int64ToString(static_cast<int64>(*it)));
}
std::string output;
diff --git a/chrome/browser/process_singleton.h b/chrome/browser/process_singleton.h
index d2ee14f..57dd446 100644
--- a/chrome/browser/process_singleton.h
+++ b/chrome/browser/process_singleton.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_
#define CHROME_BROWSER_PROCESS_SINGLETON_H_
+#pragma once
#include "build/build_config.h"
@@ -12,13 +13,19 @@
#endif
#include "base/basictypes.h"
+#if defined(USE_X11)
#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(USE_X11)
+#include "base/scoped_temp_dir.h"
+#endif
class CommandLine;
+class FilePath;
// ProcessSingleton ----------------------------------------------------------
//
@@ -128,13 +135,19 @@ class ProcessSingleton : public NonThreadSafe {
HWND remote_window_; // The HWND_MESSAGE of another browser.
HWND window_; // The HWND_MESSAGE window.
-#elif !defined(OS_MACOSX)
+#elif defined(USE_X11)
// Path in file system to the socket.
FilePath socket_path_;
// Path in file system to the lock.
FilePath lock_path_;
+ // Path in file system to the cookie file.
+ FilePath cookie_path_;
+
+ // Temporary directory to hold the socket.
+ ScopedTempDir socket_dir_;
+
// Helper class for linux specific messages. LinuxWatcher is ref counted
// because it posts messages between threads.
class LinuxWatcher;
diff --git a/chrome/browser/process_singleton_linux.cc b/chrome/browser/process_singleton_linux.cc
index bfd6539..da80b2b 100644
--- a/chrome/browser/process_singleton_linux.cc
+++ b/chrome/browser/process_singleton_linux.cc
@@ -8,6 +8,16 @@
// directory and second process command line flags. The second process then
// exits.
//
+// Because many networked filesystem implementations do not support unix domain
+// sockets, we create the socket in a temporary directory and create a symlink
+// in the profile. This temporary directory is no longer bound to the profile,
+// and may disappear across a reboot or login to a separate session. To bind
+// them, we store a unique cookie in the profile directory, which must also be
+// present in the remote directory to connect. The cookie is checked both before
+// and after the connection. /tmp is sticky, and different Chrome sessions use
+// different cookies. Thus, a matching cookie before and after means the
+// connection was to a directory with a valid cookie.
+//
// We also have a lock file, which is a symlink to a non-existent destination.
// The destination is a string containing the hostname and process id of
// chrome's browser process, eg. "SingletonLock -> example.com-9156". When the
@@ -33,6 +43,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <gdk/gdk.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -54,8 +65,11 @@
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
+#include "base/rand_util.h"
#include "base/safe_strerror_posix.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/time.h"
@@ -188,43 +202,56 @@ ssize_t ReadFromSocket(int fd, char *buf, size_t bufsize, int timeout) {
return bytes_read;
}
-// Set up a socket and sockaddr appropriate for messaging.
-void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) {
- *sock = socket(PF_UNIX, SOCK_STREAM, 0);
- PCHECK(*sock >= 0) << "socket() failed";
-
- int rv = SetNonBlocking(*sock);
- DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
- rv = SetCloseOnExec(*sock);
- DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket.";
-
+// Set up a sockaddr appropriate for messaging.
+void SetupSockAddr(const std::string& path, struct sockaddr_un* addr) {
addr->sun_family = AF_UNIX;
CHECK(path.length() < arraysize(addr->sun_path))
<< "Socket path too long: " << path;
base::strlcpy(addr->sun_path, path.c_str(), arraysize(addr->sun_path));
}
-// Read a symbol link, return empty string if given path is not a symbol link.
-std::string ReadLink(const std::string& path) {
- struct stat statbuf;
+// Set up a socket appropriate for messaging.
+int SetupSocketOnly() {
+ int sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ PCHECK(sock >= 0) << "socket() failed";
- if (lstat(path.c_str(), &statbuf) < 0) {
- DCHECK_EQ(errno, ENOENT);
- return std::string();
+ int rv = SetNonBlocking(sock);
+ DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
+ rv = SetCloseOnExec(sock);
+ DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket.";
+
+ return sock;
+}
+
+// Set up a socket and sockaddr appropriate for messaging.
+void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) {
+ *sock = SetupSocketOnly();
+ 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;
+}
- if (S_ISLNK(statbuf.st_mode)) {
- char buf[PATH_MAX + 1];
- ssize_t len = readlink(path.c_str(), buf, PATH_MAX);
- if (len > 0) {
- buf[len] = '\0';
- return std::string(buf);
- } else {
+// 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)) {
+ // The only errno that should occur is ENOENT.
+ if (errno != 0 && errno != ENOENT)
PLOG(ERROR) << "readlink(" << path << ") failed";
- }
}
-
- return std::string();
+ return target;
}
// Unlink a path. Return true on success.
@@ -236,6 +263,23 @@ bool UnlinkPath(const std::string& path) {
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) {
+ // Double check the value in case symlink suceeded but we got an incorrect
+ // failure due to NFS packet loss & retry.
+ int saved_errno = errno;
+ if (ReadLink(path) != target) {
+ // If we failed to create the lock, most likely another instance won the
+ // startup race.
+ errno = saved_errno;
+ PLOG(ERROR) << "Failed to create " << path;
+ return false;
+ }
+ }
+ return true;
+}
+
// Extract the hostname and pid from the lock symlink.
// Returns true if the lock existed.
bool ParseLockPath(const std::string& path,
@@ -245,7 +289,7 @@ bool ParseLockPath(const std::string& path,
if (real_path.empty())
return false;
- std::string::size_type pos = real_path.rfind('-');
+ std::string::size_type pos = real_path.rfind(kLockDelimiter);
// If the path is not a symbolic link, or doesn't contain what we expect,
// bail.
@@ -258,7 +302,7 @@ bool ParseLockPath(const std::string& path,
*hostname = real_path.substr(0, pos);
const std::string& pid_str = real_path.substr(pos + 1);
- if (!StringToInt(pid_str, pid))
+ if (!base::StringToInt(pid_str, pid))
*pid = -1;
return true;
@@ -268,7 +312,7 @@ void DisplayProfileInUseError(const std::string& lock_path,
const std::string& hostname,
int pid) {
std::wstring error = l10n_util::GetStringF(IDS_PROFILE_IN_USE_LINUX,
- IntToWString(pid),
+ UTF8ToWide(base::IntToString(pid)),
ASCIIToWide(hostname),
base::SysNativeMBToWide(lock_path),
l10n_util::GetString(IDS_PRODUCT_NAME));
@@ -334,15 +378,83 @@ bool KillProcessByLockPath(const std::string& path) {
return true;
}
-// A helper class to close a socket automatically.
-class SocketCloser {
+// A helper class to hold onto a socket.
+class ScopedSocket {
public:
- explicit SocketCloser(int fd) : fd_(fd) { }
- ~SocketCloser() { CloseSocket(fd_); }
+ ScopedSocket() : fd_(-1) { Reset(); }
+ ~ScopedSocket() { Close(); }
+ int fd() { return fd_; }
+ void Reset() {
+ Close();
+ fd_ = SetupSocketOnly();
+ }
+ void Close() {
+ if (fd_ >= 0)
+ CloseSocket(fd_);
+ fd_ = -1;
+ }
private:
int fd_;
};
+// Returns a random string for uniquifying profile connections.
+std::string GenerateCookie() {
+ return base::Uint64ToString(base::RandUint64());
+}
+
+bool CheckCookie(const FilePath& path, const std::string& cookie) {
+ return (cookie == ReadLink(path.value()));
+}
+
+bool ConnectSocket(ScopedSocket* socket,
+ const FilePath& socket_path,
+ const FilePath& cookie_path) {
+ std::string socket_target;
+ if (ReadLinkSilent(socket_path.value(), &socket_target)) {
+ // It's a symlink. Read the cookie.
+ std::string cookie = ReadLink(cookie_path.value());
+ if (cookie.empty())
+ return false;
+ FilePath remote_cookie = FilePath(socket_target).DirName().
+ Append(chrome::kSingletonCookieFilename);
+ // Verify the cookie before connecting.
+ if (!CheckCookie(remote_cookie, cookie))
+ return false;
+ // Now we know the directory was (at that point) created by the profile
+ // owner. Try to connect.
+ sockaddr_un addr;
+ SetupSockAddr(socket_path.value(), &addr);
+ int ret = HANDLE_EINTR(connect(socket->fd(),
+ reinterpret_cast<sockaddr*>(&addr),
+ sizeof(addr)));
+ if (ret != 0)
+ return false;
+ // Check the cookie again. We only link in /tmp, which is sticky, so, if the
+ // directory is still correct, it must have been correct in-between when we
+ // connected. POSIX, sadly, lacks a connectat().
+ if (!CheckCookie(remote_cookie, cookie)) {
+ socket->Reset();
+ return false;
+ }
+ // Success!
+ return true;
+ } else if (errno == EINVAL) {
+ // It exists, but is not a symlink (or some other error we detect
+ // later). Just connect to it directly; this is an older version of Chrome.
+ sockaddr_un addr;
+ SetupSockAddr(socket_path.value(), &addr);
+ int ret = HANDLE_EINTR(connect(socket->fd(),
+ reinterpret_cast<sockaddr*>(&addr),
+ sizeof(addr)));
+ return (ret == 0);
+ } else {
+ // File is missing, or other error.
+ if (errno != ENOENT)
+ PLOG(ERROR) << "readlink failed";
+ return false;
+ }
+}
+
} // namespace
///////////////////////////////////////////////////////////////////////////////
@@ -546,8 +658,7 @@ void ProcessSingleton::LinuxWatcher::HandleMessage(
// Run the browser startup sequence again, with the command line of the
// signalling process.
FilePath current_dir_file_path(current_dir);
- BrowserInit::ProcessCommandLine(parsed_command_line,
- current_dir_file_path.ToWStringHack(),
+ BrowserInit::ProcessCommandLine(parsed_command_line, current_dir_file_path,
false, profile, NULL);
}
@@ -652,6 +763,7 @@ ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) {
socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename);
+ cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename);
}
ProcessSingleton::~ProcessSingleton() {
@@ -669,19 +781,10 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
bool kill_unresponsive) {
DCHECK_GE(timeout_seconds, 0);
- int socket;
- sockaddr_un addr;
- SetupSocket(socket_path_.value(), &socket, &addr);
-
- // It'll close the socket automatically when exiting this method.
- SocketCloser socket_closer(socket);
-
+ ScopedSocket socket;
for (int retries = 0; retries <= timeout_seconds; ++retries) {
- // Connecting to the socket
- int ret = HANDLE_EINTR(connect(socket,
- reinterpret_cast<sockaddr*>(&addr),
- sizeof(addr)));
- if (ret == 0)
+ // Try to connect to the socket.
+ if (ConnectSocket(&socket, socket_path_, cookie_path_))
break;
// If we're in a race with another process, they may be in Create() and have
@@ -732,7 +835,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
}
timeval timeout = {timeout_seconds, 0};
- setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+ setsockopt(socket.fd(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
// Found another process, prepare our command line
// format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
@@ -752,21 +855,21 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
}
// Send the message
- if (!WriteToSocket(socket, to_send.data(), to_send.length())) {
+ 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()))
return PROFILE_IN_USE;
return PROCESS_NONE;
}
- if (shutdown(socket, SHUT_WR) < 0)
+ if (shutdown(socket.fd(), SHUT_WR) < 0)
PLOG(ERROR) << "shutdown() failed";
// Read ACK message from the other process. It might be blocked for a certain
// timeout, to make sure the other process has enough time to return ACK.
char buf[kMaxACKMessageLength + 1];
ssize_t len =
- ReadFromSocket(socket, buf, kMaxACKMessageLength, timeout_seconds);
+ ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout_seconds);
// Failed to read ACK, the other process might have been frozen.
if (len <= 0) {
@@ -780,6 +883,9 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
// The other process is shutting down, it's safe to start a new process.
return PROCESS_NONE;
} else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) {
+ // Notify the window manager that we've started up; if we do not open a
+ // window, GTK will not automatically call this for us.
+ gdk_notify_startup_complete();
// Assume the other process is handling the request.
return PROCESS_NOTIFIED;
}
@@ -830,25 +936,41 @@ bool ProcessSingleton::Create() {
// Create symbol link before binding the socket, to ensure only one instance
// can have the socket open.
- if (symlink(symlink_content.c_str(), lock_path_.value().c_str()) < 0) {
- // Double check the value in case symlink suceeded but we got an incorrect
- // failure due to NFS packet loss & retry.
- int saved_errno = errno;
- if (ReadLink(lock_path_.value()) != symlink_content) {
+ if (!SymlinkPath(symlink_content, lock_path_.value())) {
// If we failed to create the lock, most likely another instance won the
// startup race.
- errno = saved_errno;
- PLOG(ERROR) << "Failed to create " << lock_path_.value();
return false;
- }
}
- SetupSocket(socket_path_.value(), &sock, &addr);
-
+ // Create the socket file somewhere in /tmp which is usually mounted as a
+ // normal filesystem. Some network filesystems (notably AFS) are screwy and
+ // do not support Unix domain sockets.
+ if (!socket_dir_.CreateUniqueTempDir()) {
+ LOG(ERROR) << "Failed to create socket directory.";
+ return false;
+ }
+ // Setup the socket symlink and the two cookies.
+ FilePath socket_target_path =
+ socket_dir_.path().Append(chrome::kSingletonSocketFilename);
+ std::string 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())) {
+ // 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.";
+ socket_dir_.Delete();
+ return false;
+ }
+
+ SetupSocket(socket_target_path.value(), &sock, &addr);
if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
- PLOG(ERROR) << "Failed to bind() " << socket_path_.value();
+ PLOG(ERROR) << "Failed to bind() " << socket_target_path.value();
CloseSocket(sock);
return false;
}
@@ -870,5 +992,7 @@ bool ProcessSingleton::Create() {
}
void ProcessSingleton::Cleanup() {
+ UnlinkPath(socket_path_.value());
+ UnlinkPath(cookie_path_.value());
UnlinkPath(lock_path_.value());
}
diff --git a/chrome/browser/process_singleton_linux_uitest.cc b/chrome/browser/process_singleton_linux_uitest.cc
index 3f7ddd8..c9f72de 100644
--- a/chrome/browser/process_singleton_linux_uitest.cc
+++ b/chrome/browser/process_singleton_linux_uitest.cc
@@ -12,10 +12,10 @@
#include <string>
#include "base/eintr_wrapper.h"
-#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_constants.h"
@@ -28,7 +28,33 @@
namespace {
-typedef UITest ProcessSingletonLinuxTest;
+class ProcessSingletonLinuxTest : public UITest {
+ public:
+ virtual void SetUp() {
+ UITest::SetUp();
+ lock_path_ = user_data_dir().Append(chrome::kSingletonLockFilename);
+ socket_path_ = user_data_dir().Append(chrome::kSingletonSocketFilename);
+ cookie_path_ = user_data_dir().Append(chrome::kSingletonCookieFilename);
+ }
+
+ virtual void TearDown() {
+ UITest::TearDown();
+
+ // Check that the test cleaned up after itself.
+ struct stat statbuf;
+ bool lock_exists = lstat(lock_path_.value().c_str(), &statbuf) == 0;
+ EXPECT_FALSE(lock_exists);
+
+ if (lock_exists) {
+ // Unlink to prevent failing future tests if the lock still exists.
+ EXPECT_EQ(unlink(lock_path_.value().c_str()), 0);
+ }
+ }
+
+ FilePath lock_path_;
+ FilePath socket_path_;
+ FilePath cookie_path_;
+};
ProcessSingleton* CreateProcessSingleton() {
FilePath user_data_dir;
@@ -47,7 +73,7 @@ CommandLine CommandLineForUrl(const std::string& url) {
cmd_line->AppendSwitch(switches::kNoProcessSingletonDialog);
CommandLine new_cmd_line(*cmd_line);
- new_cmd_line.AppendLooseValue(ASCIIToWide(url));
+ new_cmd_line.AppendArg(url);
return new_cmd_line;
}
@@ -78,24 +104,32 @@ ProcessSingleton::NotifyResult NotifyOtherProcessOrCreate(
// are valid. When running this test, the ProcessSingleton object is already
// initiated by UITest. So we just test against this existing object.
TEST_F(ProcessSingletonLinuxTest, CheckSocketFile) {
- FilePath user_data_dir;
- FilePath socket_path;
- FilePath lock_path;
- PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-
- socket_path = user_data_dir.Append(chrome::kSingletonSocketFilename);
- lock_path = user_data_dir.Append(chrome::kSingletonLockFilename);
-
struct stat statbuf;
- ASSERT_EQ(0, lstat(lock_path.value().c_str(), &statbuf));
+ ASSERT_EQ(0, lstat(lock_path_.value().c_str(), &statbuf));
ASSERT_TRUE(S_ISLNK(statbuf.st_mode));
- char buf[PATH_MAX + 1];
- ssize_t len = readlink(lock_path.value().c_str(), buf, PATH_MAX);
+ char buf[PATH_MAX];
+ ssize_t len = readlink(lock_path_.value().c_str(), buf, PATH_MAX);
+ ASSERT_GT(len, 0);
+
+ ASSERT_EQ(0, lstat(socket_path_.value().c_str(), &statbuf));
+ ASSERT_TRUE(S_ISLNK(statbuf.st_mode));
+
+ len = readlink(socket_path_.value().c_str(), buf, PATH_MAX);
ASSERT_GT(len, 0);
- buf[len] = '\0';
+ FilePath socket_target_path = FilePath(std::string(buf, len));
- ASSERT_EQ(0, lstat(socket_path.value().c_str(), &statbuf));
+ ASSERT_EQ(0, lstat(socket_target_path.value().c_str(), &statbuf));
ASSERT_TRUE(S_ISSOCK(statbuf.st_mode));
+
+ len = readlink(cookie_path_.value().c_str(), buf, PATH_MAX);
+ ASSERT_GT(len, 0);
+ std::string cookie(buf, len);
+
+ FilePath remote_cookie_path = socket_target_path.DirName().
+ Append(chrome::kSingletonCookieFilename);
+ len = readlink(remote_cookie_path.value().c_str(), buf, PATH_MAX);
+ ASSERT_GT(len, 0);
+ EXPECT_EQ(cookie, std::string(buf, len));
}
#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
@@ -130,7 +164,7 @@ TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessFailure) {
// Wait to make sure the browser process is actually stopped.
// It's necessary when running with valgrind.
- HANDLE_EINTR(waitpid(pid, 0, WUNTRACED));
+ EXPECT_GE(HANDLE_EINTR(waitpid(pid, 0, WUNTRACED)), 0);
std::string url("about:blank");
EXPECT_EQ(ProcessSingleton::PROCESS_NONE,
@@ -148,20 +182,17 @@ TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessFailure) {
// would have to be duplicated or shared if this test was moved into a
// unittest.)
TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessNoSuicide) {
- FilePath lock_path = user_data_dir().Append(chrome::kSingletonLockFilename);
- FilePath socket_path = user_data_dir().Append(chrome::kSingletonSocketFilename);
-
// Replace lockfile with one containing our own pid.
- EXPECT_EQ(0, unlink(lock_path.value().c_str()));
+ EXPECT_EQ(0, unlink(lock_path_.value().c_str()));
std::string symlink_content = StringPrintf(
"%s%c%u",
net::GetHostName().c_str(),
'-',
base::GetCurrentProcId());
- EXPECT_EQ(0, symlink(symlink_content.c_str(), lock_path.value().c_str()));
+ EXPECT_EQ(0, symlink(symlink_content.c_str(), lock_path_.value().c_str()));
// Remove socket so that we will not be able to notify the existing browser.
- EXPECT_EQ(0, unlink(socket_path.value().c_str()));
+ EXPECT_EQ(0, unlink(socket_path_.value().c_str()));
std::string url("about:blank");
EXPECT_EQ(ProcessSingleton::PROCESS_NONE,
@@ -172,9 +203,8 @@ TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessNoSuicide) {
// Test that we can still notify a process on the same host even after the
// hostname changed.
TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessHostChanged) {
- FilePath lock_path = user_data_dir().Append(chrome::kSingletonLockFilename);
- EXPECT_EQ(0, unlink(lock_path.value().c_str()));
- EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path.value().c_str()));
+ EXPECT_EQ(0, unlink(lock_path_.value().c_str()));
+ EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str()));
int original_tab_count = GetTabCount();
@@ -197,13 +227,14 @@ TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessDifferingHost) {
// Wait for a while to make sure the browser process is actually killed.
EXPECT_FALSE(CrashAwareSleep(sleep_timeout_ms()));
- FilePath lock_path = user_data_dir().Append(chrome::kSingletonLockFilename);
- EXPECT_EQ(0, unlink(lock_path.value().c_str()));
- EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path.value().c_str()));
+ EXPECT_EQ(0, unlink(lock_path_.value().c_str()));
+ EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str()));
std::string url("about:blank");
EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE,
NotifyOtherProcess(url, action_timeout_ms()));
+
+ ASSERT_EQ(0, unlink(lock_path_.value().c_str()));
}
// Test that we fail when lock says process is on another host and we can't
@@ -218,13 +249,14 @@ TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessOrCreate_DifferingHost) {
// Wait for a while to make sure the browser process is actually killed.
EXPECT_FALSE(CrashAwareSleep(sleep_timeout_ms()));
- FilePath lock_path = user_data_dir().Append(chrome::kSingletonLockFilename);
- EXPECT_EQ(0, unlink(lock_path.value().c_str()));
- EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path.value().c_str()));
+ EXPECT_EQ(0, unlink(lock_path_.value().c_str()));
+ EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str()));
std::string url("about:blank");
EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE,
NotifyOtherProcessOrCreate(url, action_timeout_ms()));
+
+ ASSERT_EQ(0, unlink(lock_path_.value().c_str()));
}
// Test that Create fails when another browser is using the profile directory.
@@ -232,3 +264,37 @@ TEST_F(ProcessSingletonLinuxTest, CreateFailsWithExistingBrowser) {
scoped_ptr<ProcessSingleton> process_singleton(CreateProcessSingleton());
EXPECT_FALSE(process_singleton->Create());
}
+
+// Test that Create fails when another browser is using the profile directory
+// but with the old socket location.
+TEST_F(ProcessSingletonLinuxTest, CreateChecksCompatibilitySocket) {
+ scoped_ptr<ProcessSingleton> process_singleton(CreateProcessSingleton());
+
+ // Do some surgery so as to look like the old configuration.
+ char buf[PATH_MAX];
+ ssize_t len = readlink(socket_path_.value().c_str(), buf, sizeof(buf));
+ ASSERT_GT(len, 0);
+ FilePath socket_target_path = FilePath(std::string(buf, len));
+ ASSERT_EQ(0, unlink(socket_path_.value().c_str()));
+ ASSERT_EQ(0, rename(socket_target_path.value().c_str(),
+ socket_path_.value().c_str()));
+ ASSERT_EQ(0, unlink(cookie_path_.value().c_str()));
+
+ EXPECT_FALSE(process_singleton->Create());
+}
+
+// Test that we fail when lock says process is on another host and we can't
+// notify it over the socket before of a bad cookie.
+TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessOrCreate_BadCookie) {
+ // Change the cookie.
+ EXPECT_EQ(0, unlink(cookie_path_.value().c_str()));
+ EXPECT_EQ(0, symlink("INCORRECTCOOKIE", cookie_path_.value().c_str()));
+
+ // Also change the hostname, so the remote does not retry.
+ EXPECT_EQ(0, unlink(lock_path_.value().c_str()));
+ EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str()));
+
+ std::string url("about:blank");
+ EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE,
+ NotifyOtherProcessOrCreate(url, action_timeout_ms()));
+}
diff --git a/chrome/browser/process_singleton_uitest.cc b/chrome/browser/process_singleton_uitest.cc
index ee8756a..8b7da6b 100644
--- a/chrome/browser/process_singleton_uitest.cc
+++ b/chrome/browser/process_singleton_uitest.cc
@@ -62,8 +62,7 @@ class ChromeStarter : public base::RefCountedThreadSafe<ChromeStarter> {
FilePath user_data_directory;
PathService::Get(chrome::DIR_USER_DATA, &user_data_directory);
- command_line.AppendSwitchWithValue(switches::kUserDataDir,
- user_data_directory.ToWStringHack());
+ command_line.AppendSwitchPath(switches::kUserDataDir, user_data_directory);
if (first_run)
command_line.AppendSwitch(switches::kFirstRun);
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index 90fcf20..52c7a96 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.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.
@@ -8,6 +8,7 @@
#include "app/win_util.h"
#include "base/base_paths.h"
#include "base/command_line.h"
+#include "base/file_path.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/scoped_handle.h"
@@ -251,8 +252,8 @@ LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) {
}
// Get current directory.
- const std::wstring cur_dir =
- msg.substr(first_null + 1, second_null - first_null);
+ const FilePath cur_dir(msg.substr(first_null + 1,
+ second_null - first_null));
const std::wstring::size_type third_null =
msg.find_first_of(L'\0', second_null + 1);
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index af54776..36fabbd 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -5,65 +5,28 @@
#include "chrome/browser/profile.h"
#include "app/resource_bundle.h"
-#include "app/theme_provider.h"
#include "base/command_line.h"
-#include "base/env_var.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/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/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_prefs.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/chrome_blob_storage_context.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/dom_ui/ntp_resource_cache.h"
#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/extensions/extension_devtools_manager.h"
-#include "chrome/browser/extensions/extension_error_reporter.h"
+#include "chrome/browser/file_system/file_system_host_context.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/find_bar_state.h"
-#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/geolocation/geolocation_permission_context.h"
-#include "chrome/browser/spellcheck_host.h"
-#include "chrome/browser/transport_security_persister.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/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/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/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/ssl/ssl_host_state.h"
#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/profile_sync_factory_impl.h"
-#include "chrome/browser/tabs/pinned_tab_service.h"
-#include "chrome/browser/user_style_sheet_watcher.h"
-#include "chrome/browser/visitedlink_master.h"
-#include "chrome/browser/visitedlink_event_listener.h"
-#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/browser/web_resource/web_resource_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"
@@ -75,166 +38,38 @@
#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
-using base::Time;
-using base::TimeDelta;
-
-namespace {
-
-// 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.
- std::wstring user_path(CommandLine::ForCurrentProcess()->GetSwitchValue(
- switches::kDiskCacheDir));
-
- if (!user_path.empty()) {
- *cache_path = FilePath::FromWStringHack(user_path);
- }
-
- 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 (!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);
-}
-
-bool HasACacheSubdir(const FilePath &dir) {
- return file_util::PathExists(GetCachePath(dir)) ||
- file_util::PathExists(GetMediaCachePath(dir));
-}
-
-void PostExtensionLoadedToContextGetter(ChromeURLRequestContextGetter* getter,
- Extension* extension) {
- if (!getter)
- return;
- // Callee takes ownership of new ExtensionInfo struct.
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(getter,
- &ChromeURLRequestContextGetter::OnNewExtensions,
- extension->id(),
- new ChromeURLRequestContext::ExtensionInfo(
- extension->name(),
- extension->path(),
- extension->default_locale(),
- extension->web_extent(),
- extension->api_permissions())));
-}
-
-void PostExtensionUnloadedToContextGetter(ChromeURLRequestContextGetter* getter,
- Extension* extension) {
- if (!getter)
- return;
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(getter,
- &ChromeURLRequestContextGetter::OnUnloadedExtension,
- extension->id()));
-}
-
-// Returns true if the default apps should be loaded (so that the app panel is
-// not empty).
-bool IncludeDefaultApps() {
-#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
- return true;
+#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
- return false;
-}
-
-// 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("Thumbnails"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.ThumbnailsSize", 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
+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_;
-static void CleanupRequestContext(ChromeURLRequestContextGetter* context) {
+namespace {
+
+// FIXME: Duplicated in profile_impl.cc
+void CleanupRequestContext(ChromeURLRequestContextGetter* context) {
if (context)
context->CleanupOnUIThread();
}
+} // namespace
+
// static
const ProfileId Profile::InvalidProfileId = static_cast<ProfileId>(0);
@@ -264,11 +99,6 @@ void Profile::RegisterUserPrefs(PrefService* prefs) {
}
// static
-Profile* Profile::CreateProfile(const FilePath& path) {
- return new ProfileImpl(path);
-}
-
-// static
URLRequestContextGetter* Profile::GetDefaultRequestContext() {
return default_request_context_;
}
@@ -278,18 +108,6 @@ bool Profile::IsSyncAccessible() {
return syncService && !syncService->IsManaged();
}
-#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 "base/xdg_util.h"
-#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
-
////////////////////////////////////////////////////////////////////////////////
//
// OffTheRecordProfileImpl is a profile subclass that wraps an existing profile
@@ -303,6 +121,7 @@ class OffTheRecordProfileImpl : public Profile,
: profile_(real_profile),
start_time_(Time::Now()) {
request_context_ = ChromeURLRequestContextGetter::CreateOffTheRecord(this);
+ extension_process_manager_.reset(ExtensionProcessManager::Create(this));
// Register for browser close notifications so we can detect when the last
// off-the-record window is closed, in which case we can clean our states
@@ -318,6 +137,7 @@ class OffTheRecordProfileImpl : public Profile,
Source<Profile>(this),
NotificationService::NoDetails());
CleanupRequestContext(request_context_);
+ CleanupRequestContext(extensions_request_context_);
// Clean up all DB files/directories
ChromeThread::PostTask(
@@ -354,6 +174,19 @@ class OffTheRecordProfileImpl : public Profile,
return profile_;
}
+ virtual ChromeAppCacheService* GetAppCacheService() {
+ if (!appcache_service_) {
+ appcache_service_ = new ChromeAppCacheService;
+ ChromeThread::PostTask(
+ ChromeThread::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(
@@ -376,6 +209,10 @@ class OffTheRecordProfileImpl : public Profile,
return background_contents_service_.get();
}
+ virtual StatusTray* GetStatusTray() {
+ return GetOriginalProfile()->GetStatusTray();
+ }
+
virtual UserScriptMaster* GetUserScriptMaster() {
return GetOriginalProfile()->GetUserScriptMaster();
}
@@ -387,7 +224,7 @@ class OffTheRecordProfileImpl : public Profile,
}
virtual ExtensionProcessManager* GetExtensionProcessManager() {
- return GetOriginalProfile()->GetExtensionProcessManager();
+ return extension_process_manager_.get();
}
virtual ExtensionMessageService* GetExtensionMessageService() {
@@ -467,7 +304,8 @@ class OffTheRecordProfileImpl : public Profile,
virtual DownloadManager* GetDownloadManager() {
if (!download_manager_.get()) {
- scoped_refptr<DownloadManager> dlm(new DownloadManager);
+ scoped_refptr<DownloadManager> dlm(
+ new DownloadManager(g_browser_process->download_status_updater()));
dlm->Init(this);
download_manager_.swap(dlm);
}
@@ -482,6 +320,14 @@ class OffTheRecordProfileImpl : public Profile,
return NULL;
}
+ virtual FileSystemHostContext* GetFileSystemHostContext() {
+ if (!file_system_host_context_)
+ file_system_host_context_ = new FileSystemHostContext(
+ GetPath(), IsOffTheRecord());
+ DCHECK(file_system_host_context_.get());
+ return file_system_host_context_.get();
+ }
+
virtual void InitThemes() {
profile_->InitThemes();
}
@@ -516,7 +362,12 @@ class OffTheRecordProfileImpl : public Profile,
}
URLRequestContextGetter* GetRequestContextForExtensions() {
- return GetOriginalProfile()->GetRequestContextForExtensions();
+ if (!extensions_request_context_) {
+ extensions_request_context_ =
+ ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(this);
+ }
+
+ return extensions_request_context_;
}
virtual net::SSLConfigService* GetSSLConfigService() {
@@ -594,6 +445,11 @@ class OffTheRecordProfileImpl : public Profile,
return NULL;
}
+ virtual ProfileSyncService* GetProfileSyncService(
+ const std::string& cros_user) {
+ return NULL;
+ }
+
virtual CloudPrintProxyService* GetCloudPrintProxyService() {
return NULL;
}
@@ -660,10 +516,21 @@ class OffTheRecordProfileImpl : public Profile,
last_selected_directory_ = path;
}
+#if defined(OS_CHROMEOS)
+ virtual chromeos::ProxyConfigServiceImpl*
+ GetChromeOSProxyConfigServiceImpl() {
+ return profile_->GetChromeOSProxyConfigServiceImpl();
+ }
+#endif // defined(OS_CHROMEOS)
+
virtual void ExitedOffTheRecordMode() {
- // Drop our download manager so we forget about all the downloads made
- // in off-the-record mode.
- download_manager_ = NULL;
+ // 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 Observe(NotificationType type,
@@ -681,15 +548,32 @@ class OffTheRecordProfileImpl : public Profile,
ExitedOffTheRecordMode();
}
+ virtual ChromeBlobStorageContext* GetBlobStorageContext() {
+ if (!blob_storage_context_) {
+ blob_storage_context_ = new ChromeBlobStorageContext();
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ blob_storage_context_.get(),
+ &ChromeBlobStorageContext::InitializeOnIOThread));
+ }
+ return blob_storage_context_;
+ }
+
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_;
@@ -721,6 +605,8 @@ class OffTheRecordProfileImpl : public Profile,
// 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_;
@@ -730,941 +616,14 @@ class OffTheRecordProfileImpl : public Profile,
// Tracks all BackgroundContents running under this profile.
scoped_ptr<BackgroundContentsService> background_contents_service_;
- DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImpl);
-};
-
-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),
- 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();
- prefs->AddPrefObserver(prefs::kSpellCheckDictionary, this);
- prefs->AddPrefObserver(prefs::kEnableSpellCheck, this);
- prefs->AddPrefObserver(prefs::kEnableAutoSpellCorrect, this);
-
-#if defined(OS_MACOSX)
- // If the profile directory doesn't already have a cache directory and it
- // is under ~/Library/Application Support, use a suitable cache directory
- // under ~/Library/Caches. For example, a profile directory of
- // ~/Library/Application Support/Google/Chrome/MyProfileName that doesn't
- // have a "Cache" or "MediaCache" subdirectory would use the cache directory
- // ~/Library/Caches/Google/Chrome/MyProfileName.
- //
- // TODO(akalin): Come up with unit tests for this.
- if (!HasACacheSubdir(path_)) {
- FilePath app_data_path, user_cache_path;
- if (PathService::Get(base::DIR_APP_DATA, &app_data_path) &&
- PathService::Get(base::DIR_USER_CACHE, &user_cache_path) &&
- app_data_path.AppendRelativePath(path_, &user_cache_path)) {
- base_cache_path_ = user_cache_path;
- }
- }
-#elif defined(OS_POSIX) // Posix minus Mac.
- // See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
- // for a spec on where cache files go. The net effect for most systems is we
- // use ~/.cache/chromium/ for Chromium and ~/.cache/google-chrome/ for
- // official builds.
- if (!PathService::IsOverridden(chrome::DIR_USER_DATA)) {
-#if defined(GOOGLE_CHROME_BUILD)
- const char kCacheDir[] = "google-chrome";
-#else
- const char kCacheDir[] = "chromium";
-#endif
- PathService::Get(base::DIR_USER_CACHE, &base_cache_path_);
- base_cache_path_ = base_cache_path_.Append(kCacheDir);
- if (!file_util::PathExists(base_cache_path_))
- file_util::CreateDirectory(base_cache_path_);
- }
-#endif
- if (base_cache_path_.empty())
- base_cache_path_ = path_;
-
- // Listen for theme installation.
- registrar_.Add(this, NotificationType::THEME_INSTALLED,
- NotificationService::AllSources());
-
- // 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_.Init(prefs);
-#endif
-
- pinned_tab_service_.reset(new PinnedTabService(this));
-
- background_contents_service_.reset(
- new BackgroundContentsService(this, CommandLine::ForCurrentProcess()));
-
- // Log the profile size after a reasonable startup delay.
- ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE,
- new ProfileSizeTask(path_), 112000);
-}
-
-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(new ExtensionProcessManager(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(),
- GetPrefs(),
- GetPath().AppendASCII(ExtensionsService::kInstallDirectoryName),
- true);
-
- // 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));
-
- // Some sample apps to make our lives easier while we are developing extension
- // apps. This way we don't have to constantly install these over and over.
- if (Extension::AppsAreEnabled() && IncludeDefaultApps()) {
- component_extensions.push_back(
- std::make_pair("gmail_app", IDR_GMAIL_APP_MANIFEST));
- component_extensions.push_back(
- std::make_pair("calendar_app", IDR_CALENDAR_APP_MANIFEST));
- component_extensions.push_back(
- std::make_pair("docs_app", IDR_DOCS_APP_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));
- }
-
- extensions_service_->Init();
-
- // 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::InitWebResources() {
- if (web_resource_service_)
- return; // Already initialized.
-
- 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());
-
- 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();
-
- // The download manager queries the history system and should be deleted
- // before the history is shutdown so it can properly cancel all requests.
- download_manager_ = NULL;
-
- // The theme provider provides bitmaps to whoever wants them.
- theme_provider_.reset();
-
- // Remove pref observers.
- PrefService* prefs = GetPrefs();
- prefs->RemovePrefObserver(prefs::kSpellCheckDictionary, this);
- prefs->RemovePrefObserver(prefs::kEnableSpellCheck, this);
- prefs->RemovePrefObserver(prefs::kEnableAutoSpellCorrect, this);
-
- // Delete the NTP resource cache so we can unregister pref observers.
- ntp_resource_cache_.reset();
-
- 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 (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_->ProfileDestroyed();
-
- if (extensions_service_)
- extensions_service_->ProfileDestroyed();
-
- // 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<OffTheRecordProfileImpl> p(new OffTheRecordProfileImpl(this));
- off_the_record_profile_.swap(p);
- }
- 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;
-}
-
-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() {
- return background_contents_service_.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();
-}
-
-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()));
-
- // 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();
- }
-
- return prefs_.get();
-}
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
-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_;
- // 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_;
-}
+ // The file_system context for this profile.
+ scoped_refptr<FileSystemHostContext> file_system_host_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(
- Extension* extension) {
- // Notify the default, extension and media contexts on the IO thread.
- PostExtensionLoadedToContextGetter(
- static_cast<ChromeURLRequestContextGetter*>(GetRequestContext()),
- extension);
- PostExtensionLoadedToContextGetter(
- static_cast<ChromeURLRequestContextGetter*>(
- GetRequestContextForExtensions()),
- extension);
- PostExtensionLoadedToContextGetter(
- static_cast<ChromeURLRequestContextGetter*>(
- GetRequestContextForMedia()),
- extension);
-}
-
-void ProfileImpl::UnregisterExtensionWithRequestContexts(
- Extension* extension) {
- // Notify the default, extension and media contexts on the IO thread.
- PostExtensionUnloadedToContextGetter(
- static_cast<ChromeURLRequestContextGetter*>(GetRequestContext()),
- extension);
- PostExtensionUnloadedToContextGetter(
- static_cast<ChromeURLRequestContextGetter*>(
- GetRequestContextForExtensions()),
- extension);
- PostExtensionUnloadedToContextGetter(
- static_cast<ChromeURLRequestContextGetter*>(
- GetRequestContextForMedia()),
- extension);
-}
-
-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 (!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::DesktopEnvironment desktop_env;
- std::wstring store_type = CommandLine::ForCurrentProcess()->GetSwitchValue(
- switches::kPasswordStore);
- if (store_type == L"kwallet") {
- desktop_env = base::DESKTOP_ENVIRONMENT_KDE4;
- } else if (store_type == L"gnome") {
- desktop_env = base::DESKTOP_ENVIRONMENT_GNOME;
- } else if (store_type == L"detect") {
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
- desktop_env = base::GetDesktopEnvironment(env_getter.get());
- LOG(INFO) << "Password storage detected desktop environment: " <<
- base::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::DESKTOP_ENVIRONMENT_OTHER;
- }
-
- scoped_ptr<PasswordStoreX::NativeBackend> backend;
- if (desktop_env == base::DESKTOP_ENVIRONMENT_KDE4) {
- // KDE3 didn't use DBus, which our KWallet store uses.
- LOG(INFO) << "Trying KWallet for password storage.";
- backend.reset(new NativeBackendKWallet());
- if (backend->Init())
- LOG(INFO) << "Using KWallet for password storage.";
- else
- backend.reset();
- } else if (desktop_env == base::DESKTOP_ENVIRONMENT_GNOME ||
- desktop_env == base::DESKTOP_ENVIRONMENT_XFCE) {
- LOG(INFO) << "Trying GNOME keyring for password storage.";
- backend.reset(new NativeBackendGnome());
- if (backend->Init())
- LOG(INFO) << "Using GNOME keyring for password storage.";
- else
- backend.reset();
- }
- // TODO(mdm): this can change to a WARNING when we detect by default.
- if (!backend.get())
- LOG(INFO) << "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);
- 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();
-}
-
-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(Extension* extension) {
- InitThemes();
- theme_provider_.get()->SetTheme(extension);
-}
-
-void ProfileImpl::SetNativeTheme() {
- InitThemes();
- theme_provider_.get()->SetNativeTheme();
-}
-
-void ProfileImpl::ClearTheme() {
- InitThemes();
- theme_provider_.get()->UseDefaultTheme();
-}
-
-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::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;
- OffTheRecordProfileImpl* otr_profile = off_the_record_profile_.get();
- return otr_profile && profile == static_cast<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_;
-}
-
-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(ChromeThread::CurrentlyOn(ChromeThread::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::wstring* pref_name_in = Details<std::wstring>(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) {
- Extension* extension = Details<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 (!ProfileSyncService::IsSyncEnabled())
- return NULL;
- if (!sync_service_.get())
- InitSyncService();
- return sync_service_.get();
-}
-
-CloudPrintProxyService* ProfileImpl::GetCloudPrintProxyService() {
- if (!cloud_print_proxy_service_.get())
- InitCloudPrintProxyService();
- return cloud_print_proxy_service_.get();
-}
-
-void ProfileImpl::InitSyncService() {
- profile_sync_factory_.reset(
- new ProfileSyncFactoryImpl(this, CommandLine::ForCurrentProcess()));
- sync_service_.reset(
- profile_sync_factory_->CreateProfileSyncService());
- sync_service_->Initialize();
-}
+ DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImpl);
+};
-void ProfileImpl::InitCloudPrintProxyService() {
- cloud_print_proxy_service_.reset(new CloudPrintProxyService(this));
- cloud_print_proxy_service_->Initialize();
+Profile *Profile::CreateOffTheRecordProfile() {
+ return new OffTheRecordProfileImpl(this);
}
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index 16bea36..bbd710c 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -6,20 +6,19 @@
#ifndef CHROME_BROWSER_PROFILE_H_
#define CHROME_BROWSER_PROFILE_H_
-
-#include <set>
-#include <string>
+#pragma once
#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/timer.h"
-#include "chrome/browser/spellcheck_host_observer.h"
-#include "chrome/common/notification_registrar.h"
+#include "base/logging.h"
+
+namespace base {
+class Time;
+}
#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/preferences.h"
+namespace chromeos {
+class ProxyConfigServiceImpl;
+}
#endif
namespace history {
@@ -37,8 +36,11 @@ class DatabaseTracker;
class AutocompleteClassifier;
class BackgroundContentsService;
+class BackgroundModeManager;
class BookmarkModel;
class BrowserThemeProvider;
+class ChromeAppCacheService;
+class ChromeBlobStorageContext;
class ChromeURLRequestContextGetter;
class DesktopNotificationService;
class DownloadManager;
@@ -48,6 +50,8 @@ class ExtensionProcessManager;
class ExtensionMessageService;
class ExtensionsService;
class FaviconService;
+class FilePath;
+class FileSystemHostContext;
class FindBarState;
class GeolocationContentSettingsMap;
class GeolocationPermissionContext;
@@ -66,6 +70,7 @@ class SessionService;
class SpellCheckHost;
class SSLConfigServiceManager;
class SSLHostState;
+class StatusTray;
class TransportSecurityPersister;
class SQLitePersistentCookieStore;
class TabRestoreService;
@@ -156,6 +161,9 @@ class Profile {
// 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;
@@ -270,6 +278,9 @@ class Profile {
// Returns the PersonalDataManager associated with this profile.
virtual PersonalDataManager* GetPersonalDataManager() = 0;
+ // Returns the HTML5 FileSystemHostContext assigned to this profile.
+ virtual FileSystemHostContext* GetFileSystemHostContext() = 0;
+
// Init our themes system.
virtual void InitThemes() = 0;
@@ -366,6 +377,11 @@ class Profile {
// 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;
@@ -403,6 +419,11 @@ class Profile {
// Returns the service that manages BackgroundContents for this profile.
virtual BackgroundContentsService* GetBackgroundContentsService() = 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
@@ -411,7 +432,7 @@ class Profile {
virtual void InitExtensions() = 0;
- // Start up service that gathers data from web resource feeds.
+ // Start up service that gathers data from a web resource feed.
virtual void InitWebResources() = 0;
// Returns the new tab page resource cache.
@@ -421,6 +442,16 @@ class Profile {
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;
+
+#if defined(OS_CHROMEOS)
+ // Returns ChromeOS's ProxyConfigServiceImpl, creating if not yet created.
+ virtual chromeos::ProxyConfigServiceImpl*
+ GetChromeOSProxyConfigServiceImpl() = 0;
+#endif // defined(OS_CHROMEOS)
+
#ifdef UNIT_TEST
// Use with caution. GetDefaultRequestContext may be called on any thread!
static void set_default_request_context(URLRequestContextGetter* c) {
@@ -456,6 +487,9 @@ class Profile {
// disabled or controlled by configuration management.
bool IsSyncAccessible();
+ // Creates an OffTheRecordProfile which points to this Profile.
+ Profile* CreateOffTheRecordProfile();
+
protected:
static URLRequestContextGetter* default_request_context_;
@@ -469,214 +503,4 @@ class Profile {
int accessibility_pause_level_;
};
-class OffTheRecordProfileImpl;
-
-// The default profile implementation.
-class ProfileImpl : public Profile,
- public SpellCheckHostObserver,
- public NotificationObserver {
- public:
- virtual ~ProfileImpl();
-
- // Profile implementation.
- virtual ProfileId GetRuntimeId();
- virtual FilePath GetPath();
- virtual bool IsOffTheRecord();
- virtual Profile* GetOffTheRecordProfile();
- virtual void DestroyOffTheRecordProfile();
- virtual bool HasOffTheRecordProfile();
- virtual Profile* GetOriginalProfile();
- virtual webkit_database::DatabaseTracker* GetDatabaseTracker();
- virtual history::TopSites* GetTopSites();
- 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 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 void InitThemes();
- virtual void SetTheme(Extension* extension);
- virtual void SetNativeTheme();
- virtual void ClearTheme();
- virtual Extension* GetTheme();
- virtual BrowserThemeProvider* GetThemeProvider();
- virtual bool HasCreatedDownloadManager() const;
- virtual URLRequestContextGetter* GetRequestContext();
- virtual URLRequestContextGetter* GetRequestContextForMedia();
- virtual URLRequestContextGetter* GetRequestContextForExtensions();
- virtual void RegisterExtensionWithRequestContexts(Extension* extension);
- virtual void UnregisterExtensionWithRequestContexts(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 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();
- 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 TokenService* GetTokenService();
- void InitSyncService();
- virtual CloudPrintProxyService* GetCloudPrintProxyService();
- void InitCloudPrintProxyService();
-
- // 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();
- }
-
- NotificationRegistrar 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<SSLHostState> ssl_host_state_;
- scoped_refptr<net::TransportSecurityState>
- transport_security_state_;
- scoped_refptr<TransportSecurityPersister>
- transport_security_persister_;
- scoped_ptr<PrefService> prefs_;
- 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_ptr<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_refptr<PersonalDataManager> personal_data_manager_;
- scoped_ptr<PinnedTabService> pinned_tab_service_;
- 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<OffTheRecordProfileImpl> 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_;
-
- // Set to true when ShutdownSessionService is invoked. If true
- // GetSessionService won't recreate the SessionService.
- bool shutdown_session_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.
-
-#if defined(OS_CHROMEOS)
- chromeos::Preferences chromeos_preferences_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
-};
-
#endif // CHROME_BROWSER_PROFILE_H_
diff --git a/chrome/browser/profile_impl.cc b/chrome/browser/profile_impl.cc
new file mode 100644
index 0000000..f72a6a5
--- /dev/null
+++ b/chrome/browser/profile_impl.cc
@@ -0,0 +1,1322 @@
+// Copyright (c) 2010 The Chromium Authors. All rights 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/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/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/chrome_blob_storage_context.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/dom_ui/ntp_resource_cache.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/extensions/extension_devtools_manager.h"
+#include "chrome/browser/extensions/extension_error_reporter.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/file_system_host_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/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/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/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_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_CHROMEOS)
+#include "chrome/browser/chromeos/proxy_config_service_impl.h"
+#elif defined(OS_POSIX) && !defined(OS_CHROMEOS)
+#include "base/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);
+}
+
+bool HasACacheSubdir(const FilePath &dir) {
+ return file_util::PathExists(GetCachePath(dir)) ||
+ file_util::PathExists(GetMediaCachePath(dir));
+}
+
+void PostExtensionLoadedToContextGetter(ChromeURLRequestContextGetter* getter,
+ Extension* extension) {
+ if (!getter)
+ return;
+ // Callee takes ownership of new ExtensionInfo struct.
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(getter,
+ &ChromeURLRequestContextGetter::OnNewExtensions,
+ extension->id(),
+ new ChromeURLRequestContext::ExtensionInfo(
+ extension->name(),
+ extension->path(),
+ extension->default_locale(),
+ extension->incognito_split_mode(),
+ extension->web_extent(),
+ extension->GetEffectiveHostPermissions(),
+ extension->api_permissions(),
+ extension->icons())));
+}
+
+void PostExtensionUnloadedToContextGetter(ChromeURLRequestContextGetter* getter,
+ Extension* extension) {
+ if (!getter)
+ return;
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(getter,
+ &ChromeURLRequestContextGetter::OnUnloadedExtension,
+ extension->id()));
+}
+
+// Returns true if the default apps should be loaded (so that the app panel is
+// not empty).
+bool IncludeDefaultApps() {
+#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
+ return true;
+#endif
+ return false;
+}
+
+// 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);
+}
+
+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),
+ 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);
+
+#if defined(OS_MACOSX)
+ // If the profile directory doesn't already have a cache directory and it
+ // is under ~/Library/Application Support, use a suitable cache directory
+ // under ~/Library/Caches. For example, a profile directory of
+ // ~/Library/Application Support/Google/Chrome/MyProfileName that doesn't
+ // have a "Cache" or "MediaCache" subdirectory would use the cache directory
+ // ~/Library/Caches/Google/Chrome/MyProfileName.
+ //
+ // TODO(akalin): Come up with unit tests for this.
+ if (!HasACacheSubdir(path_)) {
+ FilePath app_data_path, user_cache_path;
+ if (PathService::Get(base::DIR_APP_DATA, &app_data_path) &&
+ PathService::Get(base::DIR_USER_CACHE, &user_cache_path) &&
+ app_data_path.AppendRelativePath(path_, &user_cache_path)) {
+ base_cache_path_ = user_cache_path;
+ }
+ }
+#elif defined(OS_POSIX) // Posix minus Mac.
+ // See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ // for a spec on where cache files go. The net effect for most systems is we
+ // use ~/.cache/chromium/ for Chromium and ~/.cache/google-chrome/ for
+ // official builds.
+#if defined(GOOGLE_CHROME_BUILD)
+ const char kCacheDir[] = "google-chrome";
+#else
+ const char kCacheDir[] = "chromium";
+#endif
+ PathService::Get(base::DIR_USER_CACHE, &base_cache_path_);
+ base_cache_path_ = base_cache_path_.Append(kCacheDir);
+ if (!file_util::PathExists(base_cache_path_))
+ file_util::CreateDirectory(base_cache_path_);
+#endif
+ if (base_cache_path_.empty())
+ base_cache_path_ = path_;
+
+ // Listen for theme installation.
+ registrar_.Add(this, NotificationType::THEME_INSTALLED,
+ NotificationService::AllSources());
+
+ // 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(this));
+ 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()));
+
+ // Log the profile size after a reasonable startup delay.
+ ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE,
+ new ProfileSizeTask(path_), 112000);
+}
+
+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_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);
+
+ // 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));
+
+ // Some sample apps to make our lives easier while we are developing extension
+ // apps. This way we don't have to constantly install these over and over.
+ if (Extension::AppsAreEnabled() && IncludeDefaultApps()) {
+ component_extensions.push_back(
+ std::make_pair("gmail_app", IDR_GMAIL_APP_MANIFEST));
+ component_extensions.push_back(
+ std::make_pair("calendar_app", IDR_CALENDAR_APP_MANIFEST));
+ component_extensions.push_back(
+ std::make_pair("docs_app", IDR_DOCS_APP_MANIFEST));
+ }
+
+#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
+ if (Extension::AppsAreEnabled()) {
+ component_extensions.push_back(
+ std::make_pair("chat_manager", IDR_TALK_APP_MANIFEST));
+ }
+#endif
+
+ 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));
+ }
+
+ extensions_service_->Init();
+
+ // 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::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());
+
+ 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_->ClearProfile();
+
+ 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();
+
+ // 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);
+ }
+ 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;
+ ChromeThread::PostTask(
+ ChromeThread::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() {
+ 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();
+}
+
+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();
+ }
+
+ 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_;
+ // 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_;
+}
+
+// TODO(mpcomplete): This is lame. 5+ copies of the extension data on the IO
+// thread. We should have 1 shared data object that all the contexts get access
+// to. Fix by M8.
+void ProfileImpl::RegisterExtensionWithRequestContexts(
+ Extension* extension) {
+ // Notify the default, extension and media contexts on the IO thread.
+ PostExtensionLoadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(GetRequestContext()),
+ extension);
+ PostExtensionLoadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ GetRequestContextForExtensions()),
+ extension);
+ PostExtensionLoadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ GetRequestContextForMedia()),
+ extension);
+
+ // Ditto for OTR if it's active, except for the media context which is the
+ // same as the regular context.
+ if (off_the_record_profile_.get()) {
+ PostExtensionLoadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ off_the_record_profile_->GetRequestContext()),
+ extension);
+ PostExtensionLoadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ off_the_record_profile_->GetRequestContextForExtensions()),
+ extension);
+ }
+}
+
+void ProfileImpl::UnregisterExtensionWithRequestContexts(
+ Extension* extension) {
+ // Notify the default, extension and media contexts on the IO thread.
+ PostExtensionUnloadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(GetRequestContext()),
+ extension);
+ PostExtensionUnloadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ GetRequestContextForExtensions()),
+ extension);
+ PostExtensionUnloadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ GetRequestContextForMedia()),
+ extension);
+
+ // Ditto for OTR if it's active, except for the media context which is the
+ // same as the regular context.
+ if (off_the_record_profile_.get()) {
+ PostExtensionUnloadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ off_the_record_profile_->GetRequestContext()),
+ extension);
+ PostExtensionUnloadedToContextGetter(
+ static_cast<ChromeURLRequestContextGetter*>(
+ off_the_record_profile_->GetRequestContextForExtensions()),
+ extension);
+ }
+}
+
+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 (!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::DesktopEnvironment desktop_env;
+ std::string store_type =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kPasswordStore);
+ if (store_type == "kwallet") {
+ desktop_env = base::DESKTOP_ENVIRONMENT_KDE4;
+ } else if (store_type == "gnome") {
+ desktop_env = base::DESKTOP_ENVIRONMENT_GNOME;
+ } else if (store_type == "detect") {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ desktop_env = base::GetDesktopEnvironment(env.get());
+ LOG(INFO) << "Password storage detected desktop environment: " <<
+ base::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::DESKTOP_ENVIRONMENT_OTHER;
+ }
+
+ scoped_ptr<PasswordStoreX::NativeBackend> backend;
+ if (desktop_env == base::DESKTOP_ENVIRONMENT_KDE4) {
+ // KDE3 didn't use DBus, which our KWallet store uses.
+ LOG(INFO) << "Trying KWallet for password storage.";
+ backend.reset(new NativeBackendKWallet());
+ if (backend->Init())
+ LOG(INFO) << "Using KWallet for password storage.";
+ else
+ backend.reset();
+ } else if (desktop_env == base::DESKTOP_ENVIRONMENT_GNOME ||
+ desktop_env == base::DESKTOP_ENVIRONMENT_XFCE) {
+#if defined(USE_GNOME_KEYRING)
+ LOG(INFO) << "Trying GNOME keyring for password storage.";
+ backend.reset(new NativeBackendGnome());
+ if (backend->Init())
+ LOG(INFO) << "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())
+ LOG(INFO) << "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();
+}
+
+FileSystemHostContext* ProfileImpl::GetFileSystemHostContext() {
+ if (!file_system_host_context_.get())
+ file_system_host_context_ = new FileSystemHostContext(
+ GetPath(), IsOffTheRecord());
+ DCHECK(file_system_host_context_.get());
+ return file_system_host_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(Extension* extension) {
+ InitThemes();
+ theme_provider_.get()->SetTheme(extension);
+}
+
+void ProfileImpl::SetNativeTheme() {
+ InitThemes();
+ theme_provider_.get()->SetNativeTheme();
+}
+
+void ProfileImpl::ClearTheme() {
+ InitThemes();
+ theme_provider_.get()->UseDefaultTheme();
+}
+
+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::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_;
+}
+
+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(ChromeThread::CurrentlyOn(ChromeThread::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) {
+ Extension* extension = Details<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();
+}
+
+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_.reset(new CloudPrintProxyService(this));
+ cloud_print_proxy_service_->Initialize();
+}
+
+ChromeBlobStorageContext* ProfileImpl::GetBlobStorageContext() {
+ if (!blob_storage_context_) {
+ blob_storage_context_ = new ChromeBlobStorageContext();
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(blob_storage_context_.get(),
+ &ChromeBlobStorageContext::InitializeOnIOThread));
+ }
+ return blob_storage_context_;
+}
+
+#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)
diff --git a/chrome/browser/profile_impl.h b/chrome/browser/profile_impl.h
new file mode 100644
index 0000000..f324fbd
--- /dev/null
+++ b/chrome/browser/profile_impl.h
@@ -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.
+
+// 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"
+
+#if defined(OS_CHROMEOS)
+namespace chromeos {
+class Preferences;
+}
+#endif
+
+// The default profile implementation.
+class ProfileImpl : public Profile,
+ public SpellCheckHostObserver,
+ public NotificationObserver {
+ public:
+ virtual ~ProfileImpl();
+
+ // 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 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 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 FileSystemHostContext* GetFileSystemHostContext();
+ virtual void InitThemes();
+ virtual void SetTheme(Extension* extension);
+ virtual void SetNativeTheme();
+ virtual void ClearTheme();
+ virtual Extension* GetTheme();
+ virtual BrowserThemeProvider* GetThemeProvider();
+ virtual bool HasCreatedDownloadManager() const;
+ virtual URLRequestContextGetter* GetRequestContext();
+ virtual URLRequestContextGetter* GetRequestContextForMedia();
+ virtual URLRequestContextGetter* GetRequestContextForExtensions();
+ virtual void RegisterExtensionWithRequestContexts(Extension* extension);
+ virtual void UnregisterExtensionWithRequestContexts(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 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();
+ 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();
+
+#if defined(OS_CHROMEOS)
+ virtual chromeos::ProxyConfigServiceImpl* GetChromeOSProxyConfigServiceImpl();
+#endif // defined(OS_CHROMEOS)
+
+ // 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();
+ }
+
+ 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<SSLHostState> ssl_host_state_;
+ scoped_refptr<net::TransportSecurityState>
+ transport_security_state_;
+ scoped_refptr<TransportSecurityPersister>
+ transport_security_persister_;
+ scoped_ptr<PrefService> prefs_;
+ 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_ptr<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<FileSystemHostContext> file_system_host_context_;
+ 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_;
+
+ // 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_;
+
+#if defined(OS_CHROMEOS)
+ scoped_ptr<chromeos::Preferences> chromeos_preferences_;
+
+ scoped_refptr<chromeos::ProxyConfigServiceImpl>
+ chromeos_proxy_config_service_impl_;
+#endif
+
+ 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 84a2684..a5b84ee 100644
--- a/chrome/browser/profile_import_process_host.cc
+++ b/chrome/browser/profile_import_process_host.cc
@@ -7,7 +7,7 @@
#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/importer/firefox_importer_utils.h"
#include "chrome/browser/importer/importer_messages.h"
@@ -35,20 +35,20 @@ bool ProfileImportProcessHost::StartProfileImportProcess(
// in the external process.
DictionaryValue localized_strings;
localized_strings.SetString(
- IntToWString(IDS_BOOKMARK_GROUP_FROM_FIREFOX),
- l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_FIREFOX));
+ base::IntToString(IDS_BOOKMARK_GROUP_FROM_FIREFOX),
+ l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP_FROM_FIREFOX));
localized_strings.SetString(
- IntToWString(IDS_BOOKMARK_GROUP_FROM_SAFARI),
- l10n_util::GetString(IDS_BOOKMARK_GROUP_FROM_SAFARI));
+ base::IntToString(IDS_BOOKMARK_GROUP_FROM_SAFARI),
+ l10n_util::GetStringUTF8(IDS_BOOKMARK_GROUP_FROM_SAFARI));
localized_strings.SetString(
- IntToWString(IDS_IMPORT_FROM_FIREFOX),
- l10n_util::GetString(IDS_IMPORT_FROM_FIREFOX));
+ base::IntToString(IDS_IMPORT_FROM_FIREFOX),
+ l10n_util::GetStringUTF8(IDS_IMPORT_FROM_FIREFOX));
localized_strings.SetString(
- IntToWString(IDS_IMPORT_FROM_GOOGLE_TOOLBAR),
- l10n_util::GetString(IDS_IMPORT_FROM_GOOGLE_TOOLBAR));
+ base::IntToString(IDS_IMPORT_FROM_GOOGLE_TOOLBAR),
+ l10n_util::GetStringUTF8(IDS_IMPORT_FROM_GOOGLE_TOOLBAR));
localized_strings.SetString(
- IntToWString(IDS_IMPORT_FROM_SAFARI),
- l10n_util::GetString(IDS_IMPORT_FROM_SAFARI));
+ base::IntToString(IDS_IMPORT_FROM_SAFARI),
+ l10n_util::GetStringUTF8(IDS_IMPORT_FROM_SAFARI));
Send(new ProfileImportProcessMsg_StartImport(
profile_info, items, localized_strings, import_to_bookmark_bar));
@@ -85,10 +85,9 @@ bool ProfileImportProcessHost::StartProcess() {
}
CommandLine* cmd_line = new CommandLine(exe_path);
- cmd_line->AppendSwitchWithValue(switches::kProcessType,
- switches::kProfileImportProcess);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchASCII(switches::kProcessType,
+ switches::kProfileImportProcess);
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
SetCrashReporterCommandLine(cmd_line);
diff --git a/chrome/browser/profile_import_process_host.h b/chrome/browser/profile_import_process_host.h
index a4b7a2a..8b0d9a3 100644
--- a/chrome/browser/profile_import_process_host.h
+++ b/chrome/browser/profile_import_process_host.h
@@ -4,13 +4,13 @@
#ifndef CHROME_BROWSER_PROFILE_IMPORT_PROCESS_HOST_H_
#define CHROME_BROWSER_PROFILE_IMPORT_PROCESS_HOST_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/ref_counted.h"
-#include "base/values.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_types.h"
@@ -51,7 +51,8 @@ class ProfileImportProcessHost : public BrowserChildProcessHost {
// the external process to the process host client.
virtual void OnHistoryImportStart(size_t total_history_rows_count) {}
virtual void OnHistoryImportGroup(
- const std::vector<history::URLRow> &history_rows_group) {}
+ const std::vector<history::URLRow> &history_rows_group,
+ int visit_source) {} // visit_source has history::VisitSource type.
virtual void OnHomePageImportReady(
const GURL& home_page) {}
diff --git a/chrome/browser/profile_manager.cc b/chrome/browser/profile_manager.cc
index 8770b1d..35aa664 100644
--- a/chrome/browser/profile_manager.cc
+++ b/chrome/browser/profile_manager.cc
@@ -6,7 +6,6 @@
#include "chrome/browser/profile_manager.h"
-#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
@@ -16,7 +15,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -72,12 +71,6 @@ ProfileManager::~ProfileManager() {
for (const_iterator i(begin()); i != end(); ++i)
delete *i;
profiles_.clear();
-
- // Get rid of available profile list
- for (AvailableProfileVector::const_iterator i(available_profiles_.begin());
- i != available_profiles_.end(); ++i)
- delete *i;
- available_profiles_.clear();
}
FilePath ProfileManager::GetDefaultProfileDir(
@@ -102,12 +95,8 @@ FilePath ProfileManager::GetCurrentProfileDir() {
if (logged_in_) {
FilePath profile_dir;
// If the user has logged in, pick up the new profile.
- // TODO(davemoore) Delete this once chromium os has started using
- // "--login-profile" instead of "--profile".
if (command_line.HasSwitch(switches::kLoginProfile)) {
profile_dir = command_line.GetSwitchValuePath(switches::kLoginProfile);
- } else if (command_line.HasSwitch(switches::kProfile)) {
- profile_dir = command_line.GetSwitchValuePath(switches::kProfile);
} else {
// We should never be logged in with no profile dir.
NOTREACHED();
diff --git a/chrome/browser/profile_manager.h b/chrome/browser/profile_manager.h
index 707024b..4d540f1 100644
--- a/chrome/browser/profile_manager.h
+++ b/chrome/browser/profile_manager.h
@@ -6,63 +6,19 @@
#ifndef CHROME_BROWSER_PROFILE_MANAGER_H__
#define CHROME_BROWSER_PROFILE_MANAGER_H__
+#pragma once
-#include <map>
-#include <string>
#include <vector>
#include "app/system_monitor.h"
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/non_thread_safe.h"
-#include "base/values.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-// This is a small storage class that simply represents some metadata about
-// profiles that are available in the current user data directory.
-// These are cached in local state so profiles don't need to be scanned
-// for their metadata on every launch.
-class AvailableProfile {
- public:
- AvailableProfile(const std::wstring& name,
- const std::wstring& id,
- const FilePath& directory)
- : name_(name), id_(id), directory_(directory) {}
-
- // Decodes a DictionaryValue into an AvailableProfile
- static AvailableProfile* FromValue(DictionaryValue* value) {
- DCHECK(value);
- std::wstring name, id;
- FilePath::StringType directory;
- value->GetString(L"name", &name);
- value->GetString(L"id", &id);
- value->GetString(L"directory", &directory);
- return new AvailableProfile(name, id, FilePath(directory));
- }
-
- // Encodes this AvailableProfile into a new DictionaryValue
- DictionaryValue* ToValue() {
- DictionaryValue* value = new DictionaryValue;
- value->SetString(L"name", name_);
- value->SetString(L"id", id_);
- value->SetString(L"directory", directory_.value());
- return value;
- }
-
- std::wstring name() const { return name_; }
- std::wstring id() const { return id_; }
- FilePath directory() const { return directory_; }
-
- private:
- std::wstring name_; // User-visible profile name
- std::wstring id_; // Profile identifier
- FilePath directory_; // Subdirectory containing profile (not full path)
-
- DISALLOW_COPY_AND_ASSIGN(AvailableProfile);
-};
+class FilePath;
class ProfileManager : public NonThreadSafe,
public SystemMonitor::PowerObserver,
@@ -111,8 +67,6 @@ class ProfileManager : public NonThreadSafe,
iterator end() { return profiles_.end(); }
const_iterator end() const { return profiles_.end(); }
- typedef std::vector<AvailableProfile*> AvailableProfileVector;
-
// PowerObserver notifications
void OnSuspend();
void OnResume();
@@ -128,7 +82,7 @@ class ProfileManager : public NonThreadSafe,
// user data directory.
static FilePath GetDefaultProfileDir(const FilePath& user_data_dir);
-// Returns the path to the preferences file given the user profile directory.
+ // 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
@@ -161,8 +115,6 @@ class ProfileManager : public NonThreadSafe,
// because we expect there to be a small number of profiles active.
ProfileVector profiles_;
- AvailableProfileVector available_profiles_;
-
NotificationRegistrar registrar_;
// Indicates that a user has logged in and that the profile specified
diff --git a/chrome/browser/profile_manager_unittest.cc b/chrome/browser/profile_manager_unittest.cc
index ca8bf0b..73219b6 100644
--- a/chrome/browser/profile_manager_unittest.cc
+++ b/chrome/browser/profile_manager_unittest.cc
@@ -9,7 +9,7 @@
#include "base/path_service.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.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"
@@ -95,7 +95,7 @@ TEST_F(ProfileManagerTest, LoggedInProfileDir) {
ProfileManager profile_manager;
std::string profile_dir("my_user");
- cl->AppendSwitchWithValue(switches::kLoginProfile, profile_dir);
+ cl->AppendSwitchASCII(switches::kLoginProfile, profile_dir);
cl->AppendSwitch(switches::kTestType);
FilePath expected_default =
diff --git a/chrome/browser/remove_rows_table_model.h b/chrome/browser/remove_rows_table_model.h
index 564d91d..fbab776 100644
--- a/chrome/browser/remove_rows_table_model.h
+++ b/chrome/browser/remove_rows_table_model.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_REMOVE_ROWS_TABLE_MODEL_H_
#define CHROME_BROWSER_REMOVE_ROWS_TABLE_MODEL_H_
+#pragma once
#include <set>
-#include <vector>
#include "app/table_model.h"
diff --git a/chrome/browser/renderer_host/accelerated_surface_container_mac.cc b/chrome/browser/renderer_host/accelerated_surface_container_mac.cc
index 87def49..fdba6ea 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_mac.cc
+++ b/chrome/browser/renderer_host/accelerated_surface_container_mac.cc
@@ -14,17 +14,17 @@ AcceleratedSurfaceContainerMac::AcceleratedSurfaceContainerMac(
bool opaque)
: manager_(manager),
opaque_(opaque),
- x_(0),
- y_(0),
surface_(NULL),
width_(0),
height_(0),
texture_(0),
- texture_needs_upload_(true) {
+ texture_needs_upload_(true),
+ texture_pending_deletion_(0),
+ visible_(false),
+ was_painted_to_(false) {
}
AcceleratedSurfaceContainerMac::~AcceleratedSurfaceContainerMac() {
- EnqueueTextureForDeletion();
ReleaseIOSurface();
}
@@ -62,20 +62,28 @@ void AcceleratedSurfaceContainerMac::SetSizeAndTransportDIB(
}
}
-void AcceleratedSurfaceContainerMac::MoveTo(
+void AcceleratedSurfaceContainerMac::SetGeometry(
const webkit_glue::WebPluginGeometry& geom) {
- x_ = geom.window_rect.x();
- y_ = geom.window_rect.y();
- // TODO(kbr): may need to pay attention to cutout rects.
- if (geom.visible)
- clipRect_ = geom.clip_rect;
- else
- clipRect_ = gfx::Rect();
+ visible_ = geom.visible;
+ clipRect_ = geom.clip_rect;
}
void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) {
IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
GLenum target = GL_TEXTURE_RECTANGLE_ARB;
+ if (texture_pending_deletion_) {
+ // Clean up an old texture object. This is essentially a pre-emptive
+ // cleanup, as the resources will be released when the OpenGL context
+ // associated with our containing NSView is destroyed. However, if we
+ // resize a plugin often, we might generate a lot of textures, so we
+ // should try to eagerly reclaim their resources. Note also that the
+ // OpenGL context must be current when performing the deletion, and it
+ // seems risky to make the OpenGL context current at an arbitrary point
+ // in time, which is why the deletion does not occur in the container's
+ // destructor.
+ glDeleteTextures(1, &texture_pending_deletion_);
+ texture_pending_deletion_ = 0;
+ }
if (!texture_) {
if ((io_surface_support && !surface_) ||
(!io_surface_support && !transport_dib_.get()))
@@ -145,8 +153,6 @@ void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) {
int clipY = clipRect_.y();
int clipWidth = clipRect_.width();
int clipHeight = clipRect_.height();
- int x = x_ + clipX;
- int y = y_ + clipY;
if (opaque_) {
// Pepper 3D's output is currently considered opaque even if the
@@ -158,10 +164,10 @@ void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) {
glColorMask(false, false, false, true);
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
- glVertex3f(x, y, 0);
- glVertex3f(x + clipWidth, y, 0);
- glVertex3f(x, y + clipHeight, 0);
- glVertex3f(x + clipWidth, y + clipHeight, 0);
+ glVertex3f(0, 0, 0);
+ glVertex3f(clipWidth, 0, 0);
+ glVertex3f(0, clipHeight, 0);
+ glVertex3f(clipWidth, clipHeight, 0);
glEnd();
// Now draw the color channels from the incoming texture.
@@ -177,14 +183,19 @@ void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) {
glBindTexture(target, texture_);
glEnable(target);
glBegin(GL_TRIANGLE_STRIP);
- glTexCoord2f(clipX, height_ - clipY);
- glVertex3f(x, y, 0);
- glTexCoord2f(clipX + clipWidth, height_ - clipY);
- glVertex3f(x + clipWidth, y, 0);
- glTexCoord2f(clipX, height_ - clipY - clipHeight);
- glVertex3f(x, y + clipHeight, 0);
- glTexCoord2f(clipX + clipWidth, height_ - clipY - clipHeight);
- glVertex3f(x + clipWidth, y + clipHeight, 0);
+
+ glTexCoord2f(clipX, height_ - clipY);
+ glVertex3f(0, 0, 0);
+
+ glTexCoord2f(clipX + clipWidth, height_ - clipY);
+ glVertex3f(clipWidth, 0, 0);
+
+ glTexCoord2f(clipX, height_ - clipY - clipHeight);
+ glVertex3f(0, clipHeight, 0);
+
+ glTexCoord2f(clipX + clipWidth, height_ - clipY - clipHeight);
+ glVertex3f(clipWidth, clipHeight, 0);
+
glEnd();
glDisable(target);
}
@@ -192,7 +203,8 @@ void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) {
void AcceleratedSurfaceContainerMac::EnqueueTextureForDeletion() {
if (texture_) {
- manager_->EnqueueTextureForDeletion(texture_);
+ DCHECK(texture_pending_deletion_ == 0);
+ texture_pending_deletion_ = texture_;
texture_ = 0;
}
}
diff --git a/chrome/browser/renderer_host/accelerated_surface_container_mac.h b/chrome/browser/renderer_host/accelerated_surface_container_mac.h
index c03c280..b0b6051 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_mac.h
+++ b/chrome/browser/renderer_host/accelerated_surface_container_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_GPU_PLUGIN_CONTAINER_MAC_H_
#define CHROME_BROWSER_RENDERER_HOST_GPU_PLUGIN_CONTAINER_MAC_H_
+#pragma once
// The "GPU plugin" is currently implemented as a special kind of
// NPAPI plugin to provide high-performance on-screen 3D rendering for
@@ -58,9 +59,12 @@ class AcceleratedSurfaceContainerMac {
int32 height,
TransportDIB::Handle transport_dib);
- // Tells the accelerated surface container that it has moved relative to the
- // origin of the window, for example because of a scroll event.
- void MoveTo(const webkit_glue::WebPluginGeometry& geom);
+ // Tells the accelerated surface container that its geometry has changed,
+ // for example because of a scroll event. (Note that the container
+ // 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);
// 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
@@ -71,6 +75,11 @@ class AcceleratedSurfaceContainerMac {
// time the drawing context has changed.
void ForceTextureReload() { texture_needs_upload_ = true; }
+ // Notifies the surface that it was painted to.
+ void set_was_painted_to() { was_painted_to_ = true; }
+
+ // Returns if the surface should be shown.
+ bool should_be_visible() const { return visible_ && was_painted_to_; }
private:
// The manager of this accelerated surface container.
AcceleratedSurfaceContainerManagerMac* manager_;
@@ -78,10 +87,6 @@ class AcceleratedSurfaceContainerMac {
// Whether this accelerated surface's content is supposed to be opaque.
bool opaque_;
- // The x and y coordinates of the plugin window on the web page.
- int x_;
- int y_;
-
// The IOSurfaceRef, if any, that has been handed from the GPU
// plugin process back to the browser process for drawing.
// This is held as a CFTypeRef because we can't refer to the
@@ -110,6 +115,17 @@ class AcceleratedSurfaceContainerMac {
// True if we need to upload the texture again during the next draw.
bool texture_needs_upload_;
+ // This may refer to an old version of the texture if the container is
+ // resized, for example.
+ GLuint texture_pending_deletion_;
+
+ // Stores if the plugin has a visible state.
+ bool visible_;
+
+ // Stores if the plugin's IOSurface has been swapped before. Used to not show
+ // it before it hasn't been painted to at least once.
+ bool was_painted_to_;
+
// Releases the IOSurface reference, if any, retained by this object.
void ReleaseIOSurface();
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 c8be132..8e8a17e 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc
+++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc
@@ -9,36 +9,61 @@
#include "webkit/glue/plugins/webplugin.h"
AcceleratedSurfaceContainerManagerMac::AcceleratedSurfaceContainerManagerMac()
- : current_id_(0) {
+ : current_id_(0),
+ root_container_(NULL),
+ root_container_handle_(gfx::kNullPluginWindow),
+ gpu_rendering_active_(false) {
}
gfx::PluginWindowHandle
AcceleratedSurfaceContainerManagerMac::AllocateFakePluginWindowHandle(
- bool opaque) {
+ bool opaque, bool root) {
+ AutoLock lock(lock_);
+
AcceleratedSurfaceContainerMac* container =
new AcceleratedSurfaceContainerMac(this, opaque);
gfx::PluginWindowHandle res =
static_cast<gfx::PluginWindowHandle>(++current_id_);
plugin_window_to_container_map_.insert(std::make_pair(res, container));
+ if (root) {
+ root_container_ = container;
+ root_container_handle_ = res;
+ }
return res;
}
void AcceleratedSurfaceContainerManagerMac::DestroyFakePluginWindowHandle(
gfx::PluginWindowHandle id) {
+ AutoLock lock(lock_);
+
AcceleratedSurfaceContainerMac* container = MapIDToContainer(id);
- if (container)
+ if (container) {
+ if (container == root_container_) {
+ root_container_ = NULL;
+ root_container_handle_ = gfx::kNullPluginWindow;
+ }
delete container;
+ }
plugin_window_to_container_map_.erase(id);
}
+bool AcceleratedSurfaceContainerManagerMac::IsRootContainer(
+ gfx::PluginWindowHandle id) const {
+ return root_container_handle_ != gfx::kNullPluginWindow &&
+ root_container_handle_ == id;
+}
+
void AcceleratedSurfaceContainerManagerMac::SetSizeAndIOSurface(
gfx::PluginWindowHandle id,
int32 width,
int32 height,
uint64 io_surface_identifier) {
+ AutoLock lock(lock_);
+
AcceleratedSurfaceContainerMac* container = MapIDToContainer(id);
- if (container)
+ if (container) {
container->SetSizeAndIOSurface(width, height, io_surface_identifier);
+ }
}
void AcceleratedSurfaceContainerManagerMac::SetSizeAndTransportDIB(
@@ -46,36 +71,25 @@ void AcceleratedSurfaceContainerManagerMac::SetSizeAndTransportDIB(
int32 width,
int32 height,
TransportDIB::Handle transport_dib) {
+ AutoLock lock(lock_);
+
AcceleratedSurfaceContainerMac* container = MapIDToContainer(id);
if (container)
container->SetSizeAndTransportDIB(width, height, transport_dib);
}
-void AcceleratedSurfaceContainerManagerMac::MovePluginContainer(
+void AcceleratedSurfaceContainerManagerMac::SetPluginContainerGeometry(
const webkit_glue::WebPluginGeometry& move) {
+ AutoLock lock(lock_);
+
AcceleratedSurfaceContainerMac* container = MapIDToContainer(move.window);
if (container)
- container->MoveTo(move);
+ container->SetGeometry(move);
}
-void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context) {
- // Clean up old texture objects. This is essentially a pre-emptive
- // cleanup, as the resources will be released when the OpenGL
- // context associated with the CAOpenGLLayer is destroyed. However,
- // if we render many plugins in the same layer, we should try to
- // eagerly reclaim their resources. Note also that the OpenGL
- // context must be current when performing the deletion, and it
- // seems risky to make the OpenGL context current at an arbitrary
- // point in time, which is why the deletion does not occur in the
- // container's destructor.
- for (std::vector<GLuint>::iterator iter =
- textures_pending_deletion_.begin();
- iter != textures_pending_deletion_.end();
- ++iter) {
- GLuint texture = *iter;
- glDeleteTextures(1, &texture);
- }
- textures_pending_deletion_.clear();
+void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context,
+ gfx::PluginWindowHandle id) {
+ AutoLock lock(lock_);
glColorMask(true, true, true, true);
glClearColor(0, 0, 0, 0);
@@ -85,12 +99,9 @@ void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context) {
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- for (PluginWindowToContainerMap::const_iterator i =
- plugin_window_to_container_map_.begin();
- i != plugin_window_to_container_map_.end(); ++i) {
- AcceleratedSurfaceContainerMac* container = i->second;
- container->Draw(context);
- }
+ AcceleratedSurfaceContainerMac* container = MapIDToContainer(id);
+ CHECK(container);
+ container->Draw(context);
// Unbind any texture from the texture target to ensure that the
// next time through we will have to re-bind the texture and thereby
@@ -102,6 +113,8 @@ void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context) {
}
void AcceleratedSurfaceContainerManagerMac::ForceTextureReload() {
+ AutoLock lock(lock_);
+
for (PluginWindowToContainerMap::const_iterator i =
plugin_window_to_container_map_.begin();
i != plugin_window_to_container_map_.end(); ++i) {
@@ -110,16 +123,29 @@ void AcceleratedSurfaceContainerManagerMac::ForceTextureReload() {
}
}
-void AcceleratedSurfaceContainerManagerMac::EnqueueTextureForDeletion(
- GLuint texture) {
- if (texture) {
- textures_pending_deletion_.push_back(texture);
- }
+void AcceleratedSurfaceContainerManagerMac::SetSurfaceWasPaintedTo(
+ gfx::PluginWindowHandle id) {
+ AutoLock lock(lock_);
+
+ AcceleratedSurfaceContainerMac* container = MapIDToContainer(id);
+ if (container)
+ container->set_was_painted_to();
+}
+
+bool AcceleratedSurfaceContainerManagerMac::SurfaceShouldBeVisible(
+ gfx::PluginWindowHandle id) const {
+ AutoLock lock(lock_);
+
+ if (IsRootContainer(id) && !gpu_rendering_active_)
+ return false;
+
+ AcceleratedSurfaceContainerMac* container = MapIDToContainer(id);
+ return container && container->should_be_visible();
}
AcceleratedSurfaceContainerMac*
AcceleratedSurfaceContainerManagerMac::MapIDToContainer(
- gfx::PluginWindowHandle id) {
+ gfx::PluginWindowHandle id) const {
PluginWindowToContainerMap::const_iterator i =
plugin_window_to_container_map_.find(id);
if (i != plugin_window_to_container_map_.end())
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 bcb3c42..0e38c11 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h
+++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h
@@ -4,13 +4,14 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_GPU_PLUGIN_CONTAINER_MANAGER_MAC_H_
#define CHROME_BROWSER_RENDERER_HOST_GPU_PLUGIN_CONTAINER_MANAGER_MAC_H_
+#pragma once
#include <OpenGL/OpenGL.h>
#include <map>
-#include <vector>
#include "app/surface/transport_dib.h"
#include "base/basictypes.h"
+#include "base/lock.h"
#include "gfx/native_widget_types.h"
namespace webkit_glue {
@@ -27,11 +28,26 @@ class AcceleratedSurfaceContainerManagerMac {
// Allocates a new "fake" PluginWindowHandle, which is used as the
// key for the other operations.
- gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque);
+ gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque,
+ bool root);
// Destroys a fake PluginWindowHandle and associated storage.
void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle id);
+ // Indicates whether the given PluginWindowHandle is "root", which
+ // means that we are using accelerated compositing and that this one
+ // contains the compositor's output.
+ bool IsRootContainer(gfx::PluginWindowHandle id) const;
+
+ // Returns the handle of the compositor surface, or kNullPluginWindow if no
+ // compositor surface is active.
+ gfx::PluginWindowHandle root_container_handle() const {
+ return root_container_handle_;
+ }
+
+ // Informs the manager if gpu rendering is active.
+ void set_gpu_rendering_active(bool active) { gpu_rendering_active_ = active; }
+
// Sets the size and backing store of the plugin instance. There are two
// versions: the IOSurface version is used on systems where the IOSurface
// API is supported (Mac OS X 10.6 and later); the TransportDIB is used on
@@ -47,33 +63,54 @@ class AcceleratedSurfaceContainerManagerMac {
// Takes an update from WebKit about a plugin's position and size and moves
// the plugin accordingly.
- void MovePluginContainer(const webkit_glue::WebPluginGeometry& move);
+ void SetPluginContainerGeometry(const webkit_glue::WebPluginGeometry& move);
- // Draws all of the managed plugin containers into the given OpenGL
- // context, which must already be current.
- void Draw(CGLContextObj context);
+ // Draws the plugin container associated with the given id into the given
+ // OpenGL context, which must already be current.
+ void Draw(CGLContextObj context, gfx::PluginWindowHandle id);
// Causes the next Draw call on each container to trigger a texture upload.
// Should be called any time the drawing context has changed.
void ForceTextureReload();
- // Called by the container to enqueue its OpenGL texture objects for
- // deletion.
- void EnqueueTextureForDeletion(GLuint texture);
+ // Notifies a surface that it has been painted to.
+ void SetSurfaceWasPaintedTo(gfx::PluginWindowHandle id);
+ // Returns if a given surface should be shown.
+ bool SurfaceShouldBeVisible(gfx::PluginWindowHandle id) const;
private:
uint32 current_id_;
// Maps a "fake" plugin window handle to the corresponding container.
- AcceleratedSurfaceContainerMac* MapIDToContainer(gfx::PluginWindowHandle id);
+ AcceleratedSurfaceContainerMac*
+ MapIDToContainer(gfx::PluginWindowHandle id) const;
// A map that associates plugin window handles with their containers.
typedef std::map<gfx::PluginWindowHandle, AcceleratedSurfaceContainerMac*>
PluginWindowToContainerMap;
PluginWindowToContainerMap plugin_window_to_container_map_;
- // A list of OpenGL textures waiting to be deleted
- std::vector<GLuint> textures_pending_deletion_;
+ // The "root" container, which is only used to draw the output of
+ // the accelerated compositor if it is active. Currently,
+ // accelerated plugins (Core Animation and Pepper 3D) are drawn on
+ // top of the page's contents rather than transformed and composited
+ // with the rest of the page. At some point we would like them to be
+ // treated uniformly with other page elements; when this is done,
+ // the separate treatment of the root container can go away because
+ // there will only be one container active when the accelerated
+ // compositor is active.
+ AcceleratedSurfaceContainerMac* root_container_;
+ gfx::PluginWindowHandle root_container_handle_;
+
+ // True if gpu rendering is active. The root container is created on demand
+ // and destroyed only when a renderer process exits. When the compositor was
+ // created, this is set to |false| while the compositor is not needed.
+ bool gpu_rendering_active_;
+
+ // Both |plugin_window_to_container_map_| and the
+ // AcceleratedSurfaceContainerMac in it are not threadsafe, but accessed from
+ // multiple threads. All these accesses are guarded by this lock.
+ mutable Lock lock_;
DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerManagerMac);
};
diff --git a/chrome/browser/renderer_host/async_resource_handler.cc b/chrome/browser/renderer_host/async_resource_handler.cc
index bbcb89e..f9517a2 100644
--- a/chrome/browser/renderer_host/async_resource_handler.cc
+++ b/chrome/browser/renderer_host/async_resource_handler.cc
@@ -9,7 +9,6 @@
#include "base/process.h"
#include "base/shared_memory.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/net/chrome_net_log.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"
@@ -47,11 +46,10 @@ class SharedIOBuffer : public net::IOBuffer {
buffer_size_(buffer_size) {}
bool Init() {
- if (shared_memory_.Create(std::wstring(), false, false, buffer_size_) &&
+ if (shared_memory_.Create(std::string(), false, false, buffer_size_) &&
shared_memory_.Map(buffer_size_)) {
data_ = reinterpret_cast<char*>(shared_memory_.memory());
- // TODO(hawk): Remove after debugging bug 16371.
- CHECK(data_);
+ DCHECK(data_);
ok_ = true;
}
return ok_;
@@ -63,8 +61,7 @@ class SharedIOBuffer : public net::IOBuffer {
private:
~SharedIOBuffer() {
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(g_spare_read_buffer != this);
+ DCHECK(g_spare_read_buffer != this);
data_ = NULL;
}
@@ -91,27 +88,6 @@ AsyncResourceHandler::AsyncResourceHandler(
AsyncResourceHandler::~AsyncResourceHandler() {
}
-void AsyncResourceHandler::PopulateTimingInfo(URLRequest* request,
- ResourceResponse* response) {
- if (!(request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING))
- return;
-
- ChromeNetLog* chrome_net_log = static_cast<ChromeNetLog*>(
- request->net_log().net_log());
- if (chrome_net_log == NULL)
- return;
-
- uint32 source_id = request->net_log().source().id;
- LoadTimingObserver* observer = chrome_net_log->load_timing_observer();
- LoadTimingObserver::URLRequestRecord* record =
- observer->GetURLRequestRecord(source_id);
- if (record) {
- response->response_head.connection_id = record->socket_log_id;
- response->response_head.connection_reused = record->socket_reused;
- response->response_head.load_timing = record->timing;
- }
-}
-
bool AsyncResourceHandler::OnUploadProgress(int request_id,
uint64 position,
uint64 size) {
@@ -127,7 +103,7 @@ bool AsyncResourceHandler::OnRequestRedirected(int request_id,
*defer = true;
URLRequest* request = rdh_->GetURLRequest(
GlobalRequestID(process_id_, request_id));
- PopulateTimingInfo(request, response);
+ LoadTimingObserver::PopulateTimingInfo(request, response);
return receiver_->Send(new ViewMsg_Resource_ReceivedRedirect(
routing_id_, request_id, new_url, response->response_head));
}
@@ -141,8 +117,7 @@ bool AsyncResourceHandler::OnResponseStarted(int request_id,
// or of having to layout the new content twice.
URLRequest* request = rdh_->GetURLRequest(
GlobalRequestID(process_id_, request_id));
-
- PopulateTimingInfo(request, response);
+ LoadTimingObserver::PopulateTimingInfo(request, response);
ResourceDispatcherHostRequestInfo* info = rdh_->InfoForRequest(request);
if (info->resource_type() == ResourceType::MAIN_FRAME) {
@@ -181,13 +156,12 @@ bool AsyncResourceHandler::OnWillStart(int request_id,
bool AsyncResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
int* buf_size, int min_size) {
- DCHECK(min_size == -1);
+ DCHECK_EQ(-1, min_size);
if (g_spare_read_buffer) {
DCHECK(!read_buffer_);
read_buffer_.swap(&g_spare_read_buffer);
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(read_buffer_->data());
+ DCHECK(read_buffer_->data());
*buf = read_buffer_.get();
*buf_size = read_buffer_->buffer_size();
@@ -198,8 +172,7 @@ bool AsyncResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
read_buffer_ = NULL;
return false;
}
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(read_buffer_->data());
+ DCHECK(read_buffer_->data());
*buf = read_buffer_.get();
*buf_size = next_buffer_size_;
}
@@ -244,21 +217,30 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
return true;
}
+void AsyncResourceHandler::OnDataDownloaded(
+ int request_id, int bytes_downloaded) {
+ receiver_->Send(new ViewMsg_Resource_DataDownloaded(
+ routing_id_, request_id, bytes_downloaded));
+}
+
bool AsyncResourceHandler::OnResponseCompleted(
int request_id,
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));
+ security_info,
+ completion_time));
// If we still have a read buffer, then see about caching it for later...
- if (g_spare_read_buffer) {
+ // Note that we have to make sure the buffer is not still being used, so we
+ // have to perform an explicit check on the status code.
+ if (g_spare_read_buffer || URLRequestStatus::SUCCESS != status.status()) {
read_buffer_ = NULL;
} else if (read_buffer_.get()) {
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(read_buffer_->data());
+ DCHECK(read_buffer_->data());
read_buffer_.swap(&g_spare_read_buffer);
}
return true;
diff --git a/chrome/browser/renderer_host/async_resource_handler.h b/chrome/browser/renderer_host/async_resource_handler.h
index 5442117..be89d87 100644
--- a/chrome/browser/renderer_host/async_resource_handler.h
+++ b/chrome/browser/renderer_host/async_resource_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_ASYNC_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_ASYNC_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
@@ -37,14 +38,13 @@ class AsyncResourceHandler : public ResourceHandler {
const URLRequestStatus& status,
const std::string& security_info);
void OnRequestClosed();
+ void OnDataDownloaded(int request_id, int bytes_downloaded);
static void GlobalCleanup();
private:
~AsyncResourceHandler();
- void PopulateTimingInfo(URLRequest* request, ResourceResponse* response);
-
scoped_refptr<SharedIOBuffer> read_buffer_;
ResourceDispatcherHost::Receiver* receiver_;
int process_id_;
diff --git a/chrome/browser/renderer_host/audio_renderer_host.cc b/chrome/browser/renderer_host/audio_renderer_host.cc
index 80be2a9..96b4999 100644
--- a/chrome/browser/renderer_host/audio_renderer_host.cc
+++ b/chrome/browser/renderer_host/audio_renderer_host.cc
@@ -9,9 +9,9 @@
#include "base/process.h"
#include "base/shared_memory.h"
#include "base/sys_info.h"
-#include "base/waitable_event.h"
#include "chrome/browser/renderer_host/audio_sync_reader.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "ipc/ipc_logging.h"
// The minimum number of samples in a hardware packet.
@@ -55,23 +55,23 @@ static size_t GetMaxAudioStreamsAllowed() {
return kMaxStreams;
}
-static uint32 SelectHardwarePacketSize(int channels, int sample_rate,
- int bits_per_sample) {
+static uint32 SelectHardwarePacketSize(AudioParameters params) {
// Select the number of samples that can provide at least
// |kMillisecondsPerHardwarePacket| worth of audio data.
int samples = kMinSamplesPerHardwarePacket;
while (samples <= kMaxSamplesPerHardwarePacket &&
samples * base::Time::kMillisecondsPerSecond <
- sample_rate * kMillisecondsPerHardwarePacket) {
+ params.sample_rate * kMillisecondsPerHardwarePacket) {
samples *= 2;
}
- return channels * samples * bits_per_sample / 8;
+ return params.channels * samples * params.bits_per_sample / 8;
}
///////////////////////////////////////////////////////////////////////////////
// AudioRendererHost implementations.
AudioRendererHost::AudioRendererHost()
- : process_handle_(0),
+ : process_id_(0),
+ process_handle_(0),
ipc_sender_(NULL) {
// Increase the ref count of this object so it is active until we do
// Release().
@@ -149,12 +149,11 @@ void AudioRendererHost::OnError(media::AudioOutputController* controller,
}
void AudioRendererHost::OnMoreData(media::AudioOutputController* controller,
- base::Time timestamp,
- uint32 pending_bytes) {
+ AudioBuffersState buffers_state) {
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
NewRunnableMethod(this, &AudioRendererHost::DoRequestMoreData,
- controller, timestamp, pending_bytes));
+ controller, buffers_state));
}
void AudioRendererHost::DoCompleteCreation(
@@ -243,8 +242,7 @@ void AudioRendererHost::DoSendPausedMessage(
void AudioRendererHost::DoRequestMoreData(
media::AudioOutputController* controller,
- base::Time timestamp,
- uint32 pending_bytes) {
+ AudioBuffersState buffers_state) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
// If we already have a pending request then return.
@@ -256,10 +254,7 @@ void AudioRendererHost::DoRequestMoreData(
entry->pending_buffer_request = true;
SendMessage(
new ViewMsg_RequestAudioPacket(
- entry->render_view_id,
- entry->stream_id,
- pending_bytes,
- timestamp.ToInternalValue()));
+ entry->render_view_id, entry->stream_id, buffers_state));
}
void AudioRendererHost::DoHandleError(media::AudioOutputController* controller,
@@ -331,13 +326,18 @@ void AudioRendererHost::OnCreateStream(
// Select the hardwaer packet size if not specified.
uint32 hardware_packet_size = params.packet_size;
if (!hardware_packet_size) {
- hardware_packet_size = SelectHardwarePacketSize(params.channels,
- params.sample_rate,
- params.bits_per_sample);
+ hardware_packet_size = SelectHardwarePacketSize(params.params);
}
scoped_ptr<AudioEntry> entry(new AudioEntry());
- scoped_refptr<media::AudioOutputController> controller = NULL;
+ // Create the shared memory and share with the renderer process.
+ if (!entry->shared_memory.Create("", false, false, hardware_packet_size) ||
+ !entry->shared_memory.Map(entry->shared_memory.max_size())) {
+ // If creation of shared memory failed then send an error message.
+ SendErrorMessage(msg.routing_id(), stream_id);
+ return;
+ }
+
if (low_latency) {
// If this is the low latency mode, we need to construct a SyncReader first.
scoped_ptr<AudioSyncReader> reader(
@@ -352,49 +352,32 @@ void AudioRendererHost::OnCreateStream(
// If we have successfully created the SyncReader then assign it to the
// entry and construct an AudioOutputController.
entry->reader.reset(reader.release());
- controller =
+ entry->controller =
media::AudioOutputController::CreateLowLatency(
- this, params.format, params.channels,
- params.sample_rate,
- params.bits_per_sample,
+ this, params.params,
hardware_packet_size,
entry->reader.get());
} else {
// The choice of buffer capacity is based on experiment.
- controller =
- media::AudioOutputController::Create(this, params.format,
- params.channels,
- params.sample_rate,
- params.bits_per_sample,
+ entry->controller =
+ media::AudioOutputController::Create(this, params.params,
hardware_packet_size,
3 * hardware_packet_size);
}
- if (!controller) {
+ if (!entry->controller) {
SendErrorMessage(msg.routing_id(), stream_id);
return;
}
// If we have created the controller successfully create a entry and add it
// to the map.
- entry->controller = controller;
entry->render_view_id = msg.routing_id();
entry->stream_id = stream_id;
- // Create the shared memory and share with the renderer process.
- if (!entry->shared_memory.Create(L"", false, false, hardware_packet_size) ||
- !entry->shared_memory.Map(entry->shared_memory.max_size())) {
- // If creation of shared memory failed then close the controller and
- // sends an error message.
- controller->Close();
- SendErrorMessage(msg.routing_id(), stream_id);
- return;
- }
-
- // If everything is successful then add it to the map.
- audio_entries_.insert(std::make_pair(
- AudioEntryId(msg.routing_id(), stream_id),
- entry.release()));
+ audio_entries_.insert(std::make_pair(
+ AudioEntryId(msg.routing_id(), stream_id),
+ entry.release()));
}
void AudioRendererHost::OnPlayStream(const IPC::Message& msg, int stream_id) {
@@ -438,10 +421,8 @@ void AudioRendererHost::OnCloseStream(const IPC::Message& msg, int stream_id) {
AudioEntry* entry = LookupById(msg.routing_id(), stream_id);
- // Note that closing an audio stream is a blocking operation. This call may
- // block the IO thread for up to 100ms.
if (entry)
- DeleteEntry(entry);
+ CloseAndDeleteStream(entry);
}
void AudioRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id,
@@ -482,12 +463,6 @@ void AudioRendererHost::OnNotifyPacketReady(
}
entry->pending_buffer_request = false;
- // If the audio packet is empty then don't enqueue to controller. This will
- // avoid excessive communication between browser and renderer when audio
- // data is depleted.
- if (!packet_size)
- return;
-
// Enqueue the data to media::AudioOutputController.
entry->controller->EnqueueData(
reinterpret_cast<uint8*>(entry->shared_memory.memory()),
@@ -526,10 +501,25 @@ void AudioRendererHost::SendErrorMessage(int32 render_view_id,
void AudioRendererHost::DeleteEntries() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- while (!audio_entries_.empty()) {
- DeleteEntry(audio_entries_.begin()->second);
+ for (AudioEntryMap::iterator i = audio_entries_.begin();
+ i != audio_entries_.end(); ++i) {
+ CloseAndDeleteStream(i->second);
}
- DCHECK(audio_entries_.empty());
+}
+
+void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
+ if (!entry->pending_close) {
+ entry->controller->Close(
+ NewRunnableMethod(this, &AudioRendererHost::OnStreamClosed, entry));
+ entry->pending_close = true;
+ }
+}
+
+void AudioRendererHost::OnStreamClosed(AudioEntry* entry) {
+ // Delete the entry after we've closed the stream.
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &AudioRendererHost::DeleteEntry, entry));
}
void AudioRendererHost::DeleteEntry(AudioEntry* entry) {
@@ -538,10 +528,7 @@ void AudioRendererHost::DeleteEntry(AudioEntry* entry) {
// Delete the entry when this method goes out of scope.
scoped_ptr<AudioEntry> entry_deleter(entry);
- // Close the audio stream then remove the entry.
- entry->controller->Close();
-
- // Entry the entry from the map.
+ // Erase the entry from the map.
audio_entries_.erase(
AudioEntryId(entry->render_view_id, entry->stream_id));
}
@@ -552,7 +539,7 @@ void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) {
// Sends the error message first before we close the stream because
// |entry| is destroyed in DeleteEntry().
SendErrorMessage(entry->render_view_id, entry->stream_id);
- DeleteEntry(entry);
+ CloseAndDeleteStream(entry);
}
AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(
diff --git a/chrome/browser/renderer_host/audio_renderer_host.h b/chrome/browser/renderer_host/audio_renderer_host.h
index cbb2ef9..105795b 100644
--- a/chrome/browser/renderer_host/audio_renderer_host.h
+++ b/chrome/browser/renderer_host/audio_renderer_host.h
@@ -56,6 +56,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_
+#pragma once
#include <map>
@@ -65,7 +66,6 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
-#include "base/waitable_event.h"
#include "chrome/browser/chrome_thread.h"
#include "ipc/ipc_message.h"
#include "media/audio/audio_io.h"
@@ -86,7 +86,8 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
AudioEntry()
: render_view_id(0),
stream_id(0),
- pending_buffer_request(false) {
+ pending_buffer_request(false),
+ pending_close(false) {
}
// The AudioOutputController that manages the audio stream.
@@ -106,6 +107,9 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
scoped_ptr<media::AudioOutputController::SyncReader> reader;
bool pending_buffer_request;
+
+ // Set to true after we called Close() for the controller.
+ bool pending_close;
};
typedef std::map<AudioEntryId, AudioEntry*> AudioEntryMap;
@@ -140,8 +144,7 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
virtual void OnError(media::AudioOutputController* controller,
int error_code);
virtual void OnMoreData(media::AudioOutputController* controller,
- base::Time timestamp,
- uint32 pending_bytes);
+ AudioBuffersState buffers_state);
private:
friend class AudioRendererHostTest;
@@ -203,8 +206,7 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
// Request more data from the renderer. This method is used only in normal
// latency mode.
void DoRequestMoreData(media::AudioOutputController* controller,
- base::Time timestamp,
- uint32 pending_bytes);
+ AudioBuffersState buffers_state);
// Handle error coming from audio stream.
void DoHandleError(media::AudioOutputController* controller, int error_code);
@@ -219,6 +221,13 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
// Delete all audio entry and all audio streams
void DeleteEntries();
+ // Closes the stream. The stream is then deleted in DeleteEntry() after it
+ // is closed.
+ void CloseAndDeleteStream(AudioEntry* entry);
+
+ // Called on the audio thread after the audio stream is closed.
+ void OnStreamClosed(AudioEntry* entry);
+
// Delete an audio entry and close the related audio stream.
void DeleteEntry(AudioEntry* entry);
diff --git a/chrome/browser/renderer_host/audio_renderer_host_unittest.cc b/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
index 0af6cd2..334f932 100644
--- a/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
+++ b/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
@@ -2,16 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/sync_socket.h"
-#include "base/waitable_event.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/renderer_host/audio_renderer_host.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "ipc/ipc_message_utils.h"
+#include "media/audio/audio_manager.h"
#include "media/audio/fake_audio_output_stream.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -29,8 +30,8 @@ static const int kRouteId = 200;
static const int kStreamId = 50;
static bool IsRunningHeadless() {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- if (env->HasEnv("CHROME_HEADLESS"))
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (env->HasVar("CHROME_HEADLESS"))
return true;
return false;
}
@@ -44,9 +45,9 @@ class MockAudioRendererHost : public AudioRendererHost {
}
// A list of mock methods.
- MOCK_METHOD4(OnRequestPacket,
+ MOCK_METHOD3(OnRequestPacket,
void(int routing_id, int stream_id,
- uint32 bytes_in_buffer, int64 message_timestamp));
+ AudioBuffersState buffers_state));
MOCK_METHOD3(OnStreamCreated,
void(int routing_id, int stream_id, int length));
MOCK_METHOD3(OnLowLatencyStreamCreated,
@@ -89,9 +90,8 @@ class MockAudioRendererHost : public AudioRendererHost {
// These handler methods do minimal things and delegate to the mock methods.
void OnRequestPacket(const IPC::Message& msg, int stream_id,
- uint32 bytes_in_buffer, int64 message_timestamp) {
- OnRequestPacket(msg.routing_id(), stream_id, bytes_in_buffer,
- message_timestamp);
+ AudioBuffersState buffers_state) {
+ OnRequestPacket(msg.routing_id(), stream_id, buffers_state);
}
void OnStreamCreated(const IPC::Message& msg, int stream_id,
@@ -192,7 +192,7 @@ class AudioRendererHostTest : public testing::Test {
host_ = NULL;
// We need to continue running message_loop_ to complete all destructions.
- message_loop_->RunAllPending();
+ SyncWithAudioThread();
io_thread_.reset();
}
@@ -204,7 +204,7 @@ class AudioRendererHostTest : public testing::Test {
OnStreamCreated(kRouteId, kStreamId, _));
// 2. First packet request will arrive.
- EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _, _))
+ EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _))
.WillOnce(QuitMessageLoop(message_loop_.get()));
IPC::Message msg;
@@ -212,12 +212,12 @@ class AudioRendererHostTest : public testing::Test {
ViewHostMsg_Audio_CreateStream_Params params;
if (mock_stream_)
- params.format = AudioManager::AUDIO_MOCK;
+ params.params.format = AudioParameters::AUDIO_MOCK;
else
- params.format = AudioManager::AUDIO_PCM_LINEAR;
- params.channels = 2;
- params.sample_rate = AudioManager::kAudioCDSampleRate;
- params.bits_per_sample = 16;
+ params.params.format = AudioParameters::AUDIO_PCM_LINEAR;
+ params.params.channels = 2;
+ params.params.sample_rate = AudioParameters::kAudioCDSampleRate;
+ params.params.bits_per_sample = 16;
params.packet_size = 0;
// Send a create stream message to the audio output stream and wait until
@@ -238,12 +238,12 @@ class AudioRendererHostTest : public testing::Test {
ViewHostMsg_Audio_CreateStream_Params params;
if (mock_stream_)
- params.format = AudioManager::AUDIO_MOCK;
+ params.params.format = AudioParameters::AUDIO_MOCK;
else
- params.format = AudioManager::AUDIO_PCM_LINEAR;
- params.channels = 2;
- params.sample_rate = AudioManager::kAudioCDSampleRate;
- params.bits_per_sample = 16;
+ params.params.format = AudioParameters::AUDIO_PCM_LINEAR;
+ params.params.channels = 2;
+ params.params.sample_rate = AudioParameters::kAudioCDSampleRate;
+ params.params.bits_per_sample = 16;
params.packet_size = 0;
// Send a create stream message to the audio output stream and wait until
@@ -289,7 +289,7 @@ class AudioRendererHostTest : public testing::Test {
}
void NotifyPacketReady() {
- EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _, _))
+ EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _))
.WillOnce(QuitMessageLoop(message_loop_.get()));
IPC::Message msg;
@@ -309,17 +309,38 @@ class AudioRendererHostTest : public testing::Test {
CHECK(controller) << "AudioOutputController not found";
// Expect an error signal sent through IPC.
- EXPECT_CALL(*host_, OnStreamError(kRouteId, kStreamId))
- .WillOnce(QuitMessageLoop(message_loop_.get()));
+ EXPECT_CALL(*host_, OnStreamError(kRouteId, kStreamId));
// Simulate an error sent from the audio device.
host_->OnError(controller, 0);
- message_loop_->Run();
+ SyncWithAudioThread();
// Expect the audio stream record is removed.
EXPECT_EQ(0u, host_->audio_entries_.size());
}
+ // Called on the audio thread.
+ static void PostQuitMessageLoop(MessageLoop* message_loop) {
+ message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ }
+
+ // Called on the main thread.
+ static void PostQuitOnAudioThread(MessageLoop* message_loop) {
+ AudioManager::GetAudioManager()->GetMessageLoop()->PostTask(
+ FROM_HERE, NewRunnableFunction(&PostQuitMessageLoop, message_loop));
+ }
+
+ // SyncWithAudioThread() waits until all pending tasks on the audio thread
+ // are executed while also processing pending task in message_loop_ on the
+ // current thread. It is used to synchronize with the audio thread when we are
+ // closing an audio stream.
+ void SyncWithAudioThread() {
+ message_loop_->PostTask(
+ FROM_HERE, NewRunnableFunction(&PostQuitOnAudioThread,
+ message_loop_.get()));
+ message_loop_->Run();
+ }
+
MessageLoop* message_loop() { return message_loop_.get(); }
MockAudioRendererHost* host() { return host_; }
void EnableRealDevice() { mock_stream_ = false; }
diff --git a/chrome/browser/renderer_host/audio_sync_reader.h b/chrome/browser/renderer_host/audio_sync_reader.h
index 490115c..65c9a1c 100644
--- a/chrome/browser/renderer_host/audio_sync_reader.h
+++ b/chrome/browser/renderer_host/audio_sync_reader.h
@@ -2,8 +2,9 @@
// 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_AUDIO_SYNC_READER_
-#define CHROME_BROWSER_RENDERER_HOST_AUDIO_SYNC_READER_
+#ifndef CHROME_BROWSER_RENDERER_HOST_AUDIO_SYNC_READER_H_
+#define CHROME_BROWSER_RENDERER_HOST_AUDIO_SYNC_READER_H_
+#pragma once
#include "base/file_descriptor_posix.h"
#include "base/process.h"
@@ -52,4 +53,4 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
DISALLOW_COPY_AND_ASSIGN(AudioSyncReader);
};
-#endif // CHROME_BROWSER_RENDERER_HOST_AUDIO_SYNC_READER_
+#endif // CHROME_BROWSER_RENDERER_HOST_AUDIO_SYNC_READER_H_
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index 34739c8..53d0288 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -4,13 +4,12 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_H_
#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_H_
+#pragma once
#include <vector>
#include "app/surface/transport_dib.h"
#include "base/basictypes.h"
-#include "base/process.h"
-#include "gfx/rect.h"
#include "gfx/size.h"
class RenderProcessHost;
diff --git a/chrome/browser/renderer_host/backing_store_mac.h b/chrome/browser/renderer_host/backing_store_mac.h
index 3d9e793..0c1e4a7 100644
--- a/chrome/browser/renderer_host/backing_store_mac.h
+++ b/chrome/browser/renderer_host/backing_store_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MAC_H_
#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MAC_H_
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_cftyperef.h"
diff --git a/chrome/browser/renderer_host/backing_store_mac.mm b/chrome/browser/renderer_host/backing_store_mac.mm
index 89ccc17..f793395 100644
--- a/chrome/browser/renderer_host/backing_store_mac.mm
+++ b/chrome/browser/renderer_host/backing_store_mac.mm
@@ -13,6 +13,7 @@
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "gfx/rect.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
diff --git a/chrome/browser/renderer_host/backing_store_manager.h b/chrome/browser/renderer_host/backing_store_manager.h
index 660b08a..1ab78cc 100644
--- a/chrome/browser/renderer_host/backing_store_manager.h
+++ b/chrome/browser/renderer_host/backing_store_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MANAGER_H_
#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_MANAGER_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/renderer_host/backing_store_proxy.h b/chrome/browser/renderer_host/backing_store_proxy.h
index 4d572b6..610f7ef 100644
--- a/chrome/browser/renderer_host/backing_store_proxy.h
+++ b/chrome/browser/renderer_host/backing_store_proxy.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_PROXY_H_
#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_PROXY_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/renderer_host/backing_store.h"
diff --git a/chrome/browser/renderer_host/backing_store_win.h b/chrome/browser/renderer_host/backing_store_win.h
index f280bca..221e0aa 100644
--- a/chrome/browser/renderer_host/backing_store_win.h
+++ b/chrome/browser/renderer_host/backing_store_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_WIN_H_
#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_WIN_H_
+#pragma once
#include <windows.h>
diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc
index b7f5408..f2704c8 100644
--- a/chrome/browser/renderer_host/backing_store_x.cc
+++ b/chrome/browser/renderer_host/backing_store_x.cc
@@ -85,6 +85,7 @@ BackingStoreX::BackingStoreX(RenderWidgetHost* widget,
x11_util::GetRenderVisualFormat(display_,
static_cast<Visual*>(visual)),
0, NULL);
+ pixmap_bpp_ = 0;
} else {
picture_ = 0;
pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display_, depth);
@@ -98,9 +99,13 @@ BackingStoreX::BackingStoreX(RenderWidgetHost* widget, const gfx::Size& size)
display_(NULL),
shared_memory_support_(x11_util::SHARED_MEMORY_NONE),
use_render_(false),
+ pixmap_bpp_(0),
visual_(NULL),
visual_depth_(-1),
- root_window_(0) {
+ root_window_(0),
+ pixmap_(0),
+ picture_(0),
+ pixmap_gc_(NULL) {
}
BackingStoreX::~BackingStoreX() {
@@ -239,7 +244,7 @@ void BackingStoreX::PaintToBackingStore(
width, height, False /* send_event */);
#endif
XDestroyImage(image);
- } else { // case SHARED_MEMORY_NONE
+ } else { // case SHARED_MEMORY_NONE
// No shared memory support, we have to copy the bitmap contents
// to the X server. Xlib wraps the underlying PutImage call
// behind several layers of functions which try to convert the
@@ -326,8 +331,8 @@ bool BackingStoreX::CopyFromBackingStore(const gfx::Rect& rect,
}
// Create the shared memory segment for the image and map it.
if (image->bytes_per_line == 0 || image->height == 0 ||
- (std::numeric_limits<size_t>::max() / image->bytes_per_line) >
- static_cast<size_t>(image->height)) {
+ static_cast<size_t>(image->height) >
+ (std::numeric_limits<size_t>::max() / image->bytes_per_line)) {
XDestroyImage(image);
return false;
}
diff --git a/chrome/browser/renderer_host/backing_store_x.h b/chrome/browser/renderer_host/backing_store_x.h
index 0570789..283c19f 100644
--- a/chrome/browser/renderer_host/backing_store_x.h
+++ b/chrome/browser/renderer_host/backing_store_x.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_X_H_
#define CHROME_BROWSER_RENDERER_HOST_BACKING_STORE_X_H_
+#pragma once
#include "app/x11_util.h"
#include "base/basictypes.h"
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index d6509e8..b6939a6 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -18,6 +18,7 @@
#include "app/app_switches.h"
#include "base/command_line.h"
#include "base/field_trial.h"
+#include "base/histogram.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
@@ -45,6 +46,8 @@
#include "chrome/browser/visitedlink_master.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/child_process_info.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/net/url_request_context_getter.h"
@@ -52,6 +55,7 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/result_codes.h"
#include "chrome/renderer/render_process_impl.h"
#include "chrome/renderer/render_thread.h"
@@ -197,6 +201,7 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_(
base::TimeDelta::FromSeconds(5),
this, &BrowserRenderProcessHost::ClearTransportDIBCache)),
+ accessibility_enabled_(false),
extension_process_(false) {
widget_helper_ = new RenderWidgetHelper();
@@ -240,20 +245,17 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() {
audio_renderer_host_->Destroy();
ClearTransportDIBCache();
-
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PORT_DELETED_DEBUG,
- Source<IPC::Message::Sender>(this),
- NotificationService::NoDetails());
}
-bool BrowserRenderProcessHost::Init(bool is_extensions_process,
- URLRequestContextGetter* request_context) {
+bool BrowserRenderProcessHost::Init(
+ bool is_accessibility_enabled, bool is_extensions_process) {
// calling Init() more than once does nothing, this makes it more convenient
// for the view host which may not be sure in some cases
if (channel_.get())
return true;
+ accessibility_enabled_ = is_accessibility_enabled;
+
// It is possible for an extension process to be reused for non-extension
// content, e.g. if an extension calls window.open.
extension_process_ = extension_process_ || is_extensions_process;
@@ -271,22 +273,21 @@ bool BrowserRenderProcessHost::Init(bool is_extensions_process,
PluginService::GetInstance(),
g_browser_process->print_job_manager(),
profile(),
- widget_helper_,
- request_context);
+ widget_helper_);
- std::wstring renderer_prefix;
+ CommandLine::StringType renderer_prefix;
#if defined(OS_POSIX)
// A command prefix is something prepended to the command line of the spawned
// process. It is supported only on POSIX systems.
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
renderer_prefix =
- browser_command_line.GetSwitchValue(switches::kRendererCmdPrefix);
+ browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
#endif // defined(OS_POSIX)
// Find the renderer before creating the channel so if this fails early we
// return without creating the channel.
- FilePath renderer_path = ChildProcessHost::GetChildPath(
- renderer_prefix.empty());
+ FilePath renderer_path =
+ ChildProcessHost::GetChildPath(renderer_prefix.empty());
if (renderer_path.empty())
return false;
@@ -313,11 +314,11 @@ bool BrowserRenderProcessHost::Init(bool is_extensions_process,
in_process_renderer_.reset(new RendererMainThread(channel_id));
base::Thread::Options options;
-#if !defined(OS_LINUX)
+#if !defined(TOOLKIT_USES_GTK)
// In-process plugins require this to be a UI message loop.
options.message_loop_type = MessageLoop::TYPE_UI;
#else
- // We can't have multiple UI loops on Linux, so we don't support
+ // We can't have multiple UI loops on GTK, so we don't support
// in-process plugins.
options.message_loop_type = MessageLoop::TYPE_DEFAULT;
#endif
@@ -331,8 +332,7 @@ bool BrowserRenderProcessHost::Init(bool is_extensions_process,
if (!renderer_prefix.empty())
cmd_line->PrependWrapper(renderer_prefix);
AppendRendererCommandLine(cmd_line);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id));
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
// Spawn the child process asynchronously to avoid blocking the UI thread.
// As long as there's no renderer prefix, we can use the zygote process
@@ -446,20 +446,23 @@ void BrowserRenderProcessHost::AppendRendererCommandLine(
// Pass the process type first, so it shows first in process listings.
// Extensions use a special pseudo-process type to make them distinguishable,
// even though they're just renderers.
- command_line->AppendSwitchWithValue(switches::kProcessType,
+ command_line->AppendSwitchASCII(switches::kProcessType,
extension_process_ ? switches::kExtensionProcess :
switches::kRendererProcess);
if (logging::DialogsAreSuppressed())
command_line->AppendSwitch(switches::kNoErrorDialogs);
+ if (accessibility_enabled_)
+ command_line->AppendSwitch(switches::kEnableAccessibility);
+
// Now send any options from our own command line we want to propogate.
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
PropagateBrowserCommandLineToRenderer(browser_command_line, command_line);
// Pass on the browser locale.
const std::string locale = g_browser_process->GetApplicationLocale();
- command_line->AppendSwitchWithValue(switches::kLang, ASCIIToWide(locale));
+ command_line->AppendSwitchASCII(switches::kLang, locale);
// If we run FieldTrials, we want to pass to their state to the renderer so
// that it can act in accordance with each state, or record histograms
@@ -467,23 +470,21 @@ void BrowserRenderProcessHost::AppendRendererCommandLine(
std::string field_trial_states;
FieldTrialList::StatesToString(&field_trial_states);
if (!field_trial_states.empty()) {
- command_line->AppendSwitchWithValue(switches::kForceFieldTestNameAndValue,
- field_trial_states);
+ command_line->AppendSwitchASCII(switches::kForceFieldTestNameAndValue,
+ field_trial_states);
}
BrowserChildProcessHost::SetCrashReporterCommandLine(command_line);
FilePath user_data_dir =
browser_command_line.GetSwitchValuePath(switches::kUserDataDir);
-
if (!user_data_dir.empty())
- command_line->AppendSwitchWithValue(switches::kUserDataDir,
- user_data_dir.value());
+ command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
#if defined(OS_CHROMEOS)
const std::string& profile =
- browser_command_line.GetSwitchValueASCII(switches::kProfile);
+ browser_command_line.GetSwitchValueASCII(switches::kLoginProfile);
if (!profile.empty())
- command_line->AppendSwitchWithValue(switches::kProfile, profile);
+ command_line->AppendSwitchASCII(switches::kLoginProfile, profile);
#endif
}
@@ -492,7 +493,7 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
CommandLine* renderer_cmd) const {
// Propagate the following switches to the renderer command line (along
// with any associated values) if present in the browser command line.
- static const char* const switch_names[] = {
+ static const char* const kSwitchNames[] = {
switches::kRendererAssertTest,
#if !defined(OFFICIAL_BUILD)
switches::kRendererCheckFalseTest,
@@ -549,7 +550,10 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
switches::kDisableSessionStorage,
switches::kDisableSharedWorkers,
switches::kDisableApplicationCache,
+ switches::kDisableDeviceOrientation,
switches::kEnableIndexedDatabase,
+ switches::kDisableSpeechInput,
+ switches::kEnableSpeechInput,
switches::kDisableGeolocation,
switches::kShowPaintRects,
switches::kEnableOpenMax,
@@ -565,9 +569,10 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
// WebGLArray constructors on the DOMWindow visible. This
// information is needed very early during bringup. We prefer to
// use the WebPreferences to set this flag on a page-by-page basis.
- switches::kEnableExperimentalWebGL,
- switches::kEnableGLSLTranslator,
+ switches::kDisableExperimentalWebGL,
+ switches::kDisableGLSLTranslator,
switches::kInProcessWebGL,
+ switches::kDisableAcceleratedCompositing,
#if defined(OS_MACOSX)
// Allow this to be set when invoking the browser and relayed along.
switches::kEnableSandboxLogging,
@@ -575,16 +580,18 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
#endif
switches::kRemoteShellPort,
switches::kEnablePepperTesting,
- switches::kEnableChromoting,
+ switches::kBlockNonSandboxedPlugins,
+ switches::kDisableOutdatedPlugins,
+ switches::kEnableRemoting,
+ switches::kDisableClickToPlay,
+ switches::kEnableResourceContentSettings,
switches::kPrelaunchGpuProcess,
+ switches::kEnableAcceleratedDecoding,
+ switches::kEnableFileSystem,
+ switches::kEnableMatchPreview
};
-
- for (size_t i = 0; i < arraysize(switch_names); ++i) {
- if (browser_cmd.HasSwitch(switch_names[i])) {
- renderer_cmd->AppendSwitchWithValue(switch_names[i],
- browser_cmd.GetSwitchValueASCII(switch_names[i]));
- }
- }
+ renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
+ arraysize(kSwitchNames));
// Disable databases in incognito mode.
if (profile()->IsOffTheRecord() &&
@@ -655,7 +662,7 @@ void BrowserRenderProcessHost::SendUserScriptsUpdate(
}
}
-void BrowserRenderProcessHost::SendExtensionExtentsUpdate() {
+void BrowserRenderProcessHost::SendExtensionInfo() {
// Check if the process is still starting and we don't have a handle for it
// yet, in which case this will happen later when InitVisitedLinks is called.
if (!run_renderer_in_process() &&
@@ -666,19 +673,24 @@ void BrowserRenderProcessHost::SendExtensionExtentsUpdate() {
ExtensionsService* service = profile()->GetExtensionsService();
if (!service)
return;
- ViewMsg_ExtensionExtentsUpdated_Params params;
+ ViewMsg_ExtensionsUpdated_Params params;
for (size_t i = 0; i < service->extensions()->size(); ++i) {
Extension* extension = service->extensions()->at(i);
- if (!extension->web_extent().is_empty()) {
- ViewMsg_ExtensionExtentInfo info;
- info.extension_id = extension->id();
- info.web_extent = extension->web_extent();
- info.browse_extent = extension->browse_extent();
- params.extension_apps.push_back(info);
- }
+ ViewMsg_ExtensionRendererInfo info;
+ info.id = extension->id();
+ info.web_extent = extension->web_extent();
+ info.name = extension->name();
+ info.location = extension->location();
+
+ // The icon in the page is 96px. We'd rather not scale up, so use 128.
+ info.icon_url = extension->GetIconURL(Extension::EXTENSION_ICON_LARGE,
+ ExtensionIconSet::MATCH_EXACTLY);
+ if (info.icon_url.is_empty())
+ info.icon_url = GURL("chrome://theme/IDR_APP_DEFAULT_ICON");
+ params.extensions.push_back(info);
}
- Send(new ViewMsg_ExtensionExtentsUpdated(params));
+ Send(new ViewMsg_ExtensionsUpdated(params));
}
bool BrowserRenderProcessHost::FastShutdownIfPossible() {
@@ -740,9 +752,9 @@ TransportDIB* BrowserRenderProcessHost::MapTransportDIB(
// On OSX, the browser allocates all DIBs and keeps a file descriptor around
// for each.
return widget_helper_->MapTransportDIB(dib_id);
-#elif defined(OS_LINUX)
+#elif defined(OS_POSIX)
return TransportDIB::Map(dib_id);
-#endif // defined(OS_LINUX)
+#endif // defined(OS_POSIX)
}
TransportDIB* BrowserRenderProcessHost::GetTransportDIB(
@@ -948,9 +960,7 @@ void BrowserRenderProcessHost::Observe(NotificationType type,
}
case NotificationType::EXTENSION_LOADED:
case NotificationType::EXTENSION_UNLOADED: {
- Extension* extension = Details<Extension>(details).ptr();
- if (!extension->web_extent().is_empty())
- SendExtensionExtentsUpdate();
+ SendExtensionInfo();
break;
}
case NotificationType::SPELLCHECK_HOST_REINITIALIZED: {
@@ -977,15 +987,23 @@ void BrowserRenderProcessHost::Observe(NotificationType type,
}
void BrowserRenderProcessHost::OnProcessLaunched() {
- // Now that the process is created, set its backgrounding accordingly.
- SetBackgrounded(backgrounded_);
+ // At this point, we used to set the process priority if it were marked as
+ // backgrounded_. We don't do that anymore because when we create a process,
+ // we really don't know how it will be used. If it is backgrounded, and not
+ // yet processed, a stray hung-cpu process (not chrome) can cause pages to
+ // not load at all. (see http://crbug.com/21884).
+ // If we could perfectly track when a process is created as visible or not,
+ // we could potentially call SetBackgrounded() properly at this point. But
+ // there are many cases, and no effective way to automate those cases.
+ // I'm choosing correctness over the feature of de-prioritizing this work.
Send(new ViewMsg_SetIsIncognitoProcess(profile()->IsOffTheRecord()));
InitVisitedLinks();
InitUserScripts();
InitExtensions();
- SendExtensionExtentsUpdate();
+ SendExtensionInfo();
+
// We don't want to initialize the spellchecker unless SpellCheckHost has been
// created. In InitSpellChecker(), we know if GetSpellCheckHost() is NULL
// then the spellchecker has been turned off, but here, we don't know if
diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h
index 2a7f8b6..9983c84 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_H_
+#pragma once
#include "build/build_config.h"
@@ -17,6 +18,7 @@
#include "base/timer.h"
#include "chrome/browser/child_process_launcher.h"
#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
@@ -59,8 +61,7 @@ class BrowserRenderProcessHost : public RenderProcessHost,
~BrowserRenderProcessHost();
// RenderProcessHost implementation (public portion).
- virtual bool Init(bool is_extensions_process,
- URLRequestContextGetter* request_context);
+ virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process);
virtual int GetNextRoutingID();
virtual void CancelResourceRequests(int render_widget_id);
virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params);
@@ -126,8 +127,9 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// Sends the renderer process a new set of user scripts.
void SendUserScriptsUpdate(base::SharedMemory* shared_memory);
- // Sends the renderer process a new set of extension extents.
- void SendExtensionExtentsUpdate();
+ // Sends the renderer process the list of all loaded extensions along with a
+ // subset of information the renderer needs about them.
+ void SendExtensionInfo();
// Generates a command line to be used to spawn a renderer and appends the
// results to |*command_line|.
@@ -196,6 +198,9 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// Buffer visited links and send them to to renderer.
scoped_ptr<VisitedLinkUpdater> visited_link_updater_;
+ // True if this prcoess should have accessibility enabled;
+ bool accessibility_enabled_;
+
// True iff this process is being used as an extension process. Not valid
// when running in single-process mode.
bool extension_process_;
diff --git a/chrome/browser/renderer_host/buffered_resource_handler.cc b/chrome/browser/renderer_host/buffered_resource_handler.cc
index 8ffa49a..1dbcd3a 100644
--- a/chrome/browser/renderer_host/buffered_resource_handler.cc
+++ b/chrome/browser/renderer_host/buffered_resource_handler.cc
@@ -112,8 +112,6 @@ bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
my_buffer_ = new net::IOBuffer(net::kMaxBytesToSniff);
*buf = my_buffer_.get();
*buf_size = net::kMaxBytesToSniff;
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK((*buf)->data());
return true;
}
@@ -124,8 +122,6 @@ bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
return false;
}
read_buffer_ = *buf;
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(read_buffer_->data());
read_buffer_size_ = *buf_size;
DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
bytes_read_ = 0;
@@ -137,7 +133,6 @@ bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
if (KeepBuffering(*bytes_read))
return true;
- LOG(INFO) << "Finished buffering " << request_->url().spec();
*bytes_read = bytes_read_;
// Done buffering, send the pending ResponseStarted event.
@@ -205,7 +200,6 @@ bool BufferedResourceHandler::DelayResponse() {
// enough data to decode the doctype in order to select the rendering
// mode.
should_buffer_ = true;
- LOG(INFO) << "To buffer: " << request_->url().spec();
return true;
}
@@ -242,6 +236,9 @@ bool BufferedResourceHandler::KeepBuffering(int bytes_read) {
DCHECK(read_buffer_);
if (my_buffer_) {
// We are using our own buffer to read, update the main buffer.
+ // TODO(darin): We should handle the case where read_buffer_size_ is small!
+ // See RedirectToFileResourceHandler::BufIsFull to see how this impairs
+ // downstream ResourceHandler implementations.
CHECK_LT(bytes_read + bytes_read_, read_buffer_size_);
memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read);
my_buffer_ = NULL;
@@ -320,7 +317,8 @@ bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
}
X509UserCertResourceHandler* x509_cert_handler =
- new X509UserCertResourceHandler(host_, request_);
+ new X509UserCertResourceHandler(host_, request_,
+ info->child_id(), info->route_id());
UseAlternateResourceHandler(request_id, x509_cert_handler);
}
diff --git a/chrome/browser/renderer_host/buffered_resource_handler.h b/chrome/browser/renderer_host/buffered_resource_handler.h
index 27aac40..26bd7f8 100644
--- a/chrome/browser/renderer_host/buffered_resource_handler.h
+++ b/chrome/browser/renderer_host/buffered_resource_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_BUFFERED_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_BUFFERED_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.cc b/chrome/browser/renderer_host/cross_site_resource_handler.cc
index 76c7b6c..cda6aed 100644
--- a/chrome/browser/renderer_host/cross_site_resource_handler.cc
+++ b/chrome/browser/renderer_host/cross_site_resource_handler.cc
@@ -88,11 +88,7 @@ bool CrossSiteResourceHandler::OnWillStart(int request_id,
bool CrossSiteResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
int* buf_size, int min_size) {
- bool rv = next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
- // TODO(willchan): Remove after debugging bug 16371.
- if (rv)
- CHECK((*buf)->data());
- return rv;
+ return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
}
bool CrossSiteResourceHandler::OnReadCompleted(int request_id,
diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.h b/chrome/browser/renderer_host/cross_site_resource_handler.h
index 1b7d4bc..aa731ca 100644
--- a/chrome/browser/renderer_host/cross_site_resource_handler.h
+++ b/chrome/browser/renderer_host/cross_site_resource_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_CROSS_SITE_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_CROSS_SITE_RESOURCE_HANDLER_H_
+#pragma once
#include "chrome/browser/renderer_host/resource_handler.h"
#include "net/url_request/url_request_status.h"
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc
index b4f0d5e..3efb836 100644
--- a/chrome/browser/renderer_host/database_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/database_dispatcher_host.cc
@@ -15,10 +15,9 @@
#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/browser/renderer_host/database_permission_request.h"
#include "chrome/common/render_messages.h"
#include "googleurl/src/gurl.h"
-#include "third_party/sqlite/preprocessed/sqlite3.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"
@@ -389,27 +388,7 @@ void DatabaseDispatcherHost::OnAllowDatabase(const std::string& origin_url,
GURL url = GURL(origin_url);
ContentSetting content_setting =
host_content_settings_map_->GetContentSetting(
- url, CONTENT_SETTINGS_TYPE_COOKIES);
- if (content_setting == CONTENT_SETTING_ASK) {
- // Create a task for each possible outcome.
- scoped_ptr<Task> on_allow(NewRunnableMethod(
- this, &DatabaseDispatcherHost::AllowDatabaseResponse,
- reply_msg, CONTENT_SETTING_ALLOW));
- scoped_ptr<Task> on_block(NewRunnableMethod(
- this, &DatabaseDispatcherHost::AllowDatabaseResponse,
- reply_msg, CONTENT_SETTING_BLOCK));
- // And then let the permission request object do the rest.
- scoped_refptr<DatabasePermissionRequest> request(
- new DatabasePermissionRequest(url, name, display_name, estimated_size,
- on_allow.release(), on_block.release(),
- host_content_settings_map_));
- request->RequestPermission();
-
- // Tell the renderer that it needs to run a nested message loop.
- Send(new ViewMsg_SignalCookiePromptEvent());
- return;
- }
-
+ url, CONTENT_SETTINGS_TYPE_COOKIES, "");
AllowDatabaseResponse(reply_msg, content_setting);
}
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.h b/chrome/browser/renderer_host/database_dispatcher_host.h
index 023e6d1..58b9b6e 100644
--- a/chrome/browser/renderer_host/database_dispatcher_host.h
+++ b/chrome/browser/renderer_host/database_dispatcher_host.h
@@ -4,6 +4,7 @@
#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"
diff --git a/chrome/browser/renderer_host/database_permission_request.cc b/chrome/browser/renderer_host/database_permission_request.cc
deleted file mode 100644
index fb417e7..0000000
--- a/chrome/browser/renderer_host/database_permission_request.cc
+++ /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.
-
-#include "chrome/browser/renderer_host/database_permission_request.h"
-
-
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/message_box_handler.h"
-
-DatabasePermissionRequest::DatabasePermissionRequest(
- const GURL& url,
- const string16& database_name,
- const string16& display_name,
- unsigned long estimated_size,
- Task* on_allow,
- Task* on_block,
- HostContentSettingsMap* settings_map)
- : url_(url),
- database_name_(database_name),
- display_name_(display_name),
- estimated_size_(estimated_size),
- on_allow_(on_allow),
- on_block_(on_block),
- host_content_settings_map_(settings_map) {
- DCHECK(on_allow_.get());
- DCHECK(on_block_.get());
-}
-
-DatabasePermissionRequest::~DatabasePermissionRequest() {
-}
-
-void DatabasePermissionRequest::RequestPermission() {
- if (ChromeThread::CurrentlyOn(ChromeThread::IO)) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE, NewRunnableMethod(
- this, &DatabasePermissionRequest::RequestPermission));
- return;
- }
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
-
- // Cookie settings may have changed.
- ContentSetting setting = host_content_settings_map_->GetContentSetting(
- url_, CONTENT_SETTINGS_TYPE_COOKIES);
- if (setting != CONTENT_SETTING_ASK) {
- SendResponse(setting);
- return;
- }
-
- Browser* browser = BrowserList::GetLastActive();
- if (!browser || !browser->GetSelectedTabContents()) {
- BlockSiteData();
- return;
- }
-
- self_ref_ = this;
- // Will call either AllowSiteData or BlockSiteData which will NULL out our
- // self reference.
- RunDatabasePrompt(browser->GetSelectedTabContents(),
- host_content_settings_map_, url_, database_name_,
- display_name_, estimated_size_, this);
-}
-
-void DatabasePermissionRequest::AllowSiteData(bool session_expire) {
- SendResponse(CONTENT_SETTING_ALLOW);
-}
-
-void DatabasePermissionRequest::BlockSiteData() {
- SendResponse(CONTENT_SETTING_BLOCK);
-}
-
-void DatabasePermissionRequest::SendResponse(ContentSetting content_setting) {
- if (content_setting == CONTENT_SETTING_ALLOW) {
- ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, on_allow_.release());
- } else {
- DCHECK(content_setting == CONTENT_SETTING_BLOCK);
- ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, on_block_.release());
- }
-
- // Release all resources.
- on_allow_.reset();
- on_block_.reset();
-
- // This seems safer than possibly being deleted while in method(s) related to
- // this object. Any thread will do, but UI is always around and can be
- // posted without locking, so we'll ask it to do the release.
- ChromeThread::ReleaseSoon(ChromeThread::UI, FROM_HERE, self_ref_.release());
-}
diff --git a/chrome/browser/renderer_host/database_permission_request.h b/chrome/browser/renderer_host/database_permission_request.h
deleted file mode 100644
index 7ad09b5..0000000
--- a/chrome/browser/renderer_host/database_permission_request.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_RENDERER_HOST_DATABASE_PERMISSION_REQUEST_H_
-#define CHROME_BROWSER_RENDERER_HOST_DATABASE_PERMISSION_REQUEST_H_
-
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/string16.h"
-#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h"
-#include "chrome/common/content_settings.h"
-#include "googleurl/src/gurl.h"
-
-class HostContentSettingsMap;
-class Task;
-
-// This class is fully threadsafe.
-class DatabasePermissionRequest
- : public base::RefCountedThreadSafe<DatabasePermissionRequest>,
- public CookiePromptModalDialogDelegate {
- public:
- DatabasePermissionRequest(const GURL& url,
- const string16& database_name,
- const string16& display_name,
- unsigned long estimated_size,
- Task* on_allow,
- Task* on_block,
- HostContentSettingsMap* settings_map);
- ~DatabasePermissionRequest();
-
- const GURL& url() const { return url_; }
- const string16& database_name() const { return database_name_; }
- const string16& display_name() const { return display_name_; }
- unsigned long estimated_size() const { return estimated_size_; }
-
- // Start the permission request process.
- void RequestPermission();
-
- // CookiesPromptViewDelegate methods:
- virtual void AllowSiteData(bool session_expire);
- virtual void BlockSiteData();
-
- private:
- void SendResponse(ContentSetting content_setting);
-
- // The URL to get permission for.
- const GURL url_;
- const string16 database_name_;
- const string16 display_name_;
- unsigned long estimated_size_;
-
- // Set on IO, possibly release()ed on UI, destroyed on IO or UI.
- scoped_ptr<Task> on_allow_;
- scoped_ptr<Task> on_block_;
-
- scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
-
- // Released once we have our answer.
- scoped_refptr<DatabasePermissionRequest> self_ref_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(DatabasePermissionRequest);
-};
-
-#endif // CHROME_BROWSER_RENDERER_HOST_DATABASE_PERMISSION_REQUEST_H_
diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc
index 735a168..5e83478 100644
--- a/chrome/browser/renderer_host/download_resource_handler.cc
+++ b/chrome/browser/renderer_host/download_resource_handler.cc
@@ -8,11 +8,12 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_file_manager.h"
-#include "chrome/browser/history/download_types.h"
+#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/common/resource_response.h"
#include "net/base/io_buffer.h"
+#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_context.h"
DownloadResourceHandler::DownloadResourceHandler(
@@ -21,7 +22,7 @@ DownloadResourceHandler::DownloadResourceHandler(
int render_view_id,
int request_id,
const GURL& url,
- DownloadFileManager* manager,
+ DownloadFileManager* download_file_manager,
URLRequest* request,
bool save_as,
const DownloadSaveInfo& save_info)
@@ -30,7 +31,7 @@ DownloadResourceHandler::DownloadResourceHandler(
render_view_id_(render_view_id),
url_(url),
content_length_(0),
- download_manager_(manager),
+ download_file_manager_(download_file_manager),
request_(request),
save_as_(save_as),
save_info_(save_info),
@@ -63,8 +64,8 @@ bool DownloadResourceHandler::OnResponseStarted(int request_id,
set_content_disposition(content_disposition);
set_content_length(response->response_head.content_length);
- download_id_ = download_manager_->GetNextId();
- // |download_manager_| consumes (deletes):
+ download_id_ = download_file_manager_->GetNextId();
+ // |download_file_manager_| consumes (deletes):
DownloadCreateInfo* info = new DownloadCreateInfo;
info->url = url_;
info->referrer_url = GURL(request_->referrer());
@@ -91,9 +92,14 @@ bool DownloadResourceHandler::OnResponseStarted(int request_id,
info->referrer_charset = request_->context()->referrer_charset();
info->save_info = save_info_;
ChromeThread::PostTask(
- ChromeThread::FILE, FROM_HERE,
+ ChromeThread::UI, FROM_HERE,
NewRunnableMethod(
- download_manager_, &DownloadFileManager::StartDownload, info));
+ download_file_manager_, &DownloadFileManager::StartDownload, info));
+
+ // We can't start saving the data before we create the file on disk.
+ // The request will be un-paused in DownloadFileManager::CreateDownloadFile.
+ rdh_->PauseRequest(global_id_.child_id, global_id_.request_id, true);
+
return true;
}
@@ -113,8 +119,6 @@ bool DownloadResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
read_buffer_ = new net::IOBuffer(*buf_size);
}
*buf = read_buffer_.get();
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(read_buffer_->data());
return true;
}
@@ -133,7 +137,7 @@ bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
if (need_update) {
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(download_manager_,
+ NewRunnableMethod(download_file_manager_,
&DownloadFileManager::UpdateDownload,
download_id_,
buffer_));
@@ -153,8 +157,8 @@ bool DownloadResourceHandler::OnResponseCompleted(
const std::string& security_info) {
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(download_manager_,
- &DownloadFileManager::DownloadFinished,
+ NewRunnableMethod(download_file_manager_,
+ &DownloadFileManager::OnResponseCompleted,
download_id_,
buffer_));
read_buffer_ = NULL;
@@ -204,6 +208,9 @@ void DownloadResourceHandler::CheckWriteProgress() {
}
}
+DownloadResourceHandler::~DownloadResourceHandler() {
+}
+
void DownloadResourceHandler::StartPauseTimer() {
if (!pause_timer_.IsRunning())
pause_timer_.Start(base::TimeDelta::FromMilliseconds(kThrottleTimeMs), this,
diff --git a/chrome/browser/renderer_host/download_resource_handler.h b/chrome/browser/renderer_host/download_resource_handler.h
index aefa4a2..1621bbc 100644
--- a/chrome/browser/renderer_host/download_resource_handler.h
+++ b/chrome/browser/renderer_host/download_resource_handler.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
-#include "base/file_path.h"
#include "base/timer.h"
#include "chrome/browser/download/download_file.h"
#include "chrome/browser/renderer_host/global_request_id.h"
@@ -26,7 +26,7 @@ class DownloadResourceHandler : public ResourceHandler {
int render_view_id,
int request_id,
const GURL& url,
- DownloadFileManager* manager,
+ DownloadFileManager* download_file_manager,
URLRequest* request,
bool save_as,
const DownloadSaveInfo& save_info);
@@ -65,7 +65,7 @@ class DownloadResourceHandler : public ResourceHandler {
void CheckWriteProgress();
private:
- ~DownloadResourceHandler() {}
+ ~DownloadResourceHandler();
void StartPauseTimer();
@@ -76,7 +76,7 @@ class DownloadResourceHandler : public ResourceHandler {
std::string content_disposition_;
GURL url_;
int64 content_length_;
- DownloadFileManager* download_manager_;
+ DownloadFileManager* download_file_manager_;
URLRequest* request_;
bool save_as_; // Request was initiated via "Save As" by the user.
DownloadSaveInfo save_info_;
diff --git a/chrome/browser/renderer_host/download_throttling_resource_handler.cc b/chrome/browser/renderer_host/download_throttling_resource_handler.cc
index f3408d4..3c0e32b 100644
--- a/chrome/browser/renderer_host/download_throttling_resource_handler.cc
+++ b/chrome/browser/renderer_host/download_throttling_resource_handler.cc
@@ -91,8 +91,6 @@ bool DownloadThrottlingResourceHandler::OnWillRead(int request_id,
min_size = 2 * net::kMaxBytesToSniff;
tmp_buffer_ = new net::IOBuffer(min_size);
*buf = tmp_buffer_.get();
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK((*buf)->data());
*buf_size = min_size;
return true;
}
diff --git a/chrome/browser/renderer_host/download_throttling_resource_handler.h b/chrome/browser/renderer_host/download_throttling_resource_handler.h
index e4f025b..308792f 100644
--- a/chrome/browser/renderer_host/download_throttling_resource_handler.h
+++ b/chrome/browser/renderer_host/download_throttling_resource_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_THROTTLING_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_DOWNLOAD_THROTTLING_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/renderer_host/global_request_id.h b/chrome/browser/renderer_host/global_request_id.h
index 89f8db5..eb9520b 100644
--- a/chrome/browser/renderer_host/global_request_id.h
+++ b/chrome/browser/renderer_host/global_request_id.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_GLOBAL_REQUEST_ID_H_
#define CHROME_BROWSER_RENDERER_HOST_GLOBAL_REQUEST_ID_H_
+#pragma once
// Uniquely identifies a URLRequest.
struct GlobalRequestID {
diff --git a/chrome/browser/renderer_host/gpu_view_host.h b/chrome/browser/renderer_host/gpu_view_host.h
index 8d19e07..c37409c 100644
--- a/chrome/browser/renderer_host/gpu_view_host.h
+++ b/chrome/browser/renderer_host/gpu_view_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_GPU_VIEW_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_GPU_VIEW_HOST_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/common/gpu_native_window_handle.h"
diff --git a/chrome/browser/renderer_host/gtk_im_context_wrapper.cc b/chrome/browser/renderer_host/gtk_im_context_wrapper.cc
index 8aa7f8c..1c07795 100644
--- a/chrome/browser/renderer_host/gtk_im_context_wrapper.cc
+++ b/chrome/browser/renderer_host/gtk_im_context_wrapper.cc
@@ -14,9 +14,12 @@
#include "base/logging.h"
#include "base/string_util.h"
#include "base/third_party/icu/icu_utf.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/gtk/gtk_util.h"
+#if !defined(TOOLKIT_VIEWS)
#include "chrome/browser/gtk/menu_gtk.h"
+#endif
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
#include "chrome/common/native_web_keyboard_event.h"
@@ -35,7 +38,8 @@ GtkIMContextWrapper::GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view)
is_in_key_event_handler_(false),
preedit_selection_start_(0),
preedit_selection_end_(0),
- is_preedit_changed_(false) {
+ is_preedit_changed_(false),
+ suppress_next_commit_(false) {
DCHECK(context_);
DCHECK(context_simple_);
@@ -82,6 +86,8 @@ GtkIMContextWrapper::~GtkIMContextWrapper() {
}
void GtkIMContextWrapper::ProcessKeyEvent(GdkEventKey* event) {
+ suppress_next_commit_ = false;
+
// Indicates preedit-changed and commit signal handlers that we are
// processing a key event.
is_in_key_event_handler_ = true;
@@ -132,6 +138,13 @@ void GtkIMContextWrapper::ProcessKeyEvent(GdkEventKey* event) {
NativeWebKeyboardEvent wke(event);
+ // If the key event was handled by the input method, then we need to prevent
+ // RenderView::UnhandledKeyboardEvent() from processing it.
+ // Otherwise unexpected result may occur. For example if it's a
+ // Backspace key event, the browser may go back to previous page.
+ if (filtered)
+ wke.skip_in_browser = true;
+
// Send filtered keydown event before sending IME result.
if (event->type == GDK_KEY_PRESS && filtered)
ProcessFilteredKeyPressEvent(&wke);
@@ -164,6 +177,8 @@ void GtkIMContextWrapper::ProcessKeyEvent(GdkEventKey* event) {
void GtkIMContextWrapper::UpdateInputMethodState(WebKit::WebTextInputType type,
const gfx::Rect& caret_rect) {
+ suppress_next_commit_ = false;
+
// The renderer has updated its IME status.
// Control the GtkIMContext object according to this status.
if (!context_ || !is_focused_)
@@ -240,6 +255,9 @@ void GtkIMContextWrapper::OnFocusOut() {
host_view_->GetRenderWidgetHost()->SetInputMethodActive(false);
}
+#if !defined(TOOLKIT_VIEWS)
+// Not defined for views because the views context menu doesn't
+// implement input methods yet.
void GtkIMContextWrapper::AppendInputMethodsContextMenu(MenuGtk* menu) {
gboolean show_input_method_menu = TRUE;
@@ -258,6 +276,7 @@ void GtkIMContextWrapper::AppendInputMethodsContextMenu(MenuGtk* menu) {
menu->AppendSeparator();
menu->AppendMenuItem(IDC_INPUT_METHODS_MENU, menuitem);
}
+#endif
void GtkIMContextWrapper::CancelComposition() {
if (!is_enabled_)
@@ -267,6 +286,7 @@ void GtkIMContextWrapper::CancelComposition() {
// To prevent any text from being committed when resetting the |context_|;
is_in_key_event_handler_ = true;
+ suppress_next_commit_ = true;
gtk_im_context_reset(context_);
gtk_im_context_reset(context_simple_);
@@ -321,10 +341,6 @@ void GtkIMContextWrapper::ProcessFilteredKeyPressEvent(
// keyidentifier must be updated accordingly, otherwise this key event may
// still be processed by webkit.
wke->setKeyIdentifierFromWindowsKeyCode();
- // Prevent RenderView::UnhandledKeyboardEvent() from processing it.
- // Otherwise unexpected result may occur. For example if it's a
- // Backspace key event, the browser may go back to previous page.
- wke->skip_in_browser = true;
}
host_view_->ForwardKeyboardEvent(*wke);
}
@@ -420,6 +436,11 @@ void GtkIMContextWrapper::ConfirmComposition() {
}
void GtkIMContextWrapper::HandleCommit(const string16& text) {
+ if (suppress_next_commit_) {
+ suppress_next_commit_ = false;
+ return;
+ }
+
// Append the text to the buffer, because commit signal might be fired
// multiple times when processing a key event.
commit_text_.append(text);
@@ -440,6 +461,7 @@ void GtkIMContextWrapper::HandlePreeditStart() {
void GtkIMContextWrapper::HandlePreeditChanged(const gchar* text,
PangoAttrList* attrs,
int cursor_position) {
+ suppress_next_commit_ = false;
// Don't set is_preedit_changed_ to false if there is no change, because
// this handler might be called multiple times with the same data.
is_preedit_changed_ = true;
diff --git a/chrome/browser/renderer_host/gtk_im_context_wrapper.h b/chrome/browser/renderer_host/gtk_im_context_wrapper.h
index c33c290..1538e26 100644
--- a/chrome/browser/renderer_host/gtk_im_context_wrapper.h
+++ b/chrome/browser/renderer_host/gtk_im_context_wrapper.h
@@ -4,14 +4,15 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_
#define CHROME_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_
+#pragma once
#include <gdk/gdk.h>
#include <pango/pango-attributes.h>
#include <vector>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/string16.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCompositionUnderline.h"
#include "third_party/WebKit/WebKit/chromium/public/WebTextInputType.h"
@@ -19,7 +20,9 @@ namespace gfx {
class Rect;
}
+#if !defined(TOOLKIT_VIEWS)
class MenuGtk;
+#endif
class RenderWidgetHostViewGtk;
struct NativeWebKeyboardEvent;
typedef struct _GtkIMContext GtkIMContext;
@@ -49,7 +52,11 @@ class GtkIMContextWrapper {
void OnFocusIn();
void OnFocusOut();
+#if !defined(TOOLKIT_VIEWS)
+ // Not defined for views because the views context menu doesn't
+ // implement input methods yet.
void AppendInputMethodsContextMenu(MenuGtk* menu);
+#endif
void CancelComposition();
@@ -58,7 +65,7 @@ class GtkIMContextWrapper {
private:
// For unit tests.
class GtkIMContextWrapperTest;
- FRIEND_TEST(GtkIMContextWrapperTest, ExtractCompositionInfo);
+ FRIEND_TEST_ALL_PREFIXES(GtkIMContextWrapperTest, ExtractCompositionInfo);
// Check if a text needs commit by forwarding a char event instead of
// by confirming as a composition text.
@@ -189,6 +196,11 @@ class GtkIMContextWrapper {
// handler.
string16 commit_text_;
+ // If it's true then the next "commit" signal will be suppressed.
+ // It's only used to workaround http://crbug.com/50485.
+ // TODO(suzhe): Remove it after input methods get fixed.
+ bool suppress_next_commit_;
+
DISALLOW_COPY_AND_ASSIGN(GtkIMContextWrapper);
};
diff --git a/chrome/browser/renderer_host/gtk_key_bindings_handler.h b/chrome/browser/renderer_host/gtk_key_bindings_handler.h
index dcd4403..4a58a4c 100644
--- a/chrome/browser/renderer_host/gtk_key_bindings_handler.h
+++ b/chrome/browser/renderer_host/gtk_key_bindings_handler.h
@@ -4,13 +4,14 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_GTK_KEY_BINDINGS_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_GTK_KEY_BINDINGS_HANDLER_H_
+#pragma once
#include <gtk/gtk.h>
#include <string>
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/common/edit_command.h"
-#include "chrome/common/owned_widget_gtk.h"
struct NativeWebKeyboardEvent;
diff --git a/chrome/browser/renderer_host/mock_render_process_host.cc b/chrome/browser/renderer_host/mock_render_process_host.cc
index 21fa34d..cdecb6f 100644
--- a/chrome/browser/renderer_host/mock_render_process_host.cc
+++ b/chrome/browser/renderer_host/mock_render_process_host.cc
@@ -9,7 +9,8 @@
MockRenderProcessHost::MockRenderProcessHost(Profile* profile)
: RenderProcessHost(profile),
transport_dib_(NULL),
- bad_msg_count_(0) {
+ bad_msg_count_(0),
+ factory_(NULL) {
// Child process security operations can't be unit tested unless we add
// ourselves as an existing child process.
ChildProcessSecurityPolicy::GetInstance()->Add(id());
@@ -18,10 +19,12 @@ MockRenderProcessHost::MockRenderProcessHost(Profile* profile)
MockRenderProcessHost::~MockRenderProcessHost() {
ChildProcessSecurityPolicy::GetInstance()->Remove(id());
delete transport_dib_;
+ if (factory_)
+ factory_->Remove(this);
}
-bool MockRenderProcessHost::Init(bool is_extensions_process,
- URLRequestContextGetter* request_context) {
+bool MockRenderProcessHost::Init(
+ bool is_accessibility_enabled, bool is_extensions_process) {
return true;
}
@@ -103,7 +106,7 @@ TransportDIB* MockRenderProcessHost::GetTransportDIB(TransportDIB::Id dib_id) {
// On Mac, TransportDIBs are always created in the browser, so we cannot map
// one from a dib_id.
transport_dib_ = TransportDIB::Create(100 * 100 * 4, 0);
-#elif defined(OS_LINUX)
+#elif defined(OS_POSIX)
transport_dib_ = TransportDIB::Map(dib_id);
#endif
@@ -115,3 +118,32 @@ void MockRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
void MockRenderProcessHost::OnChannelConnected(int32 peer_pid) {
}
+
+MockRenderProcessHostFactory::~MockRenderProcessHostFactory() {
+ // Detach this object from MockRenderProcesses to prevent STLDeleteElements()
+ // from calling MockRenderProcessHostFactory::Remove().
+ for (ScopedVector<MockRenderProcessHost>::iterator it = processes_.begin();
+ it != processes_.end(); ++it) {
+ (*it)->SetFactory(NULL);
+ }
+}
+
+RenderProcessHost* MockRenderProcessHostFactory::CreateRenderProcessHost(
+ Profile* profile) const {
+ MockRenderProcessHost* host = new MockRenderProcessHost(profile);
+ if (host) {
+ processes_.push_back(host);
+ host->SetFactory(this);
+ }
+ return host;
+}
+
+void MockRenderProcessHostFactory::Remove(MockRenderProcessHost* host) const {
+ for (ScopedVector<MockRenderProcessHost>::iterator it = processes_.begin();
+ it != processes_.end(); ++it) {
+ if (*it == host) {
+ processes_.weak_erase(it);
+ break;
+ }
+ }
+}
diff --git a/chrome/browser/renderer_host/mock_render_process_host.h b/chrome/browser/renderer_host/mock_render_process_host.h
index 70ed985..33a6516 100644
--- a/chrome/browser/renderer_host/mock_render_process_host.h
+++ b/chrome/browser/renderer_host/mock_render_process_host.h
@@ -4,11 +4,14 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_MOCK_RENDER_PROCESS_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_MOCK_RENDER_PROCESS_HOST_H_
+#pragma once
#include "base/basictypes.h"
+#include "base/scoped_vector.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/ipc_test_sink.h"
+class MockRenderProcessHostFactory;
class TransportDIB;
class URLRequestContextGetter;
@@ -30,8 +33,7 @@ class MockRenderProcessHost : public RenderProcessHost {
int bad_msg_count() const { return bad_msg_count_; }
// RenderProcessHost implementation (public portion).
- virtual bool Init(bool is_extensions_process,
- URLRequestContextGetter* request_context);
+ virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process);
virtual int GetNextRoutingID();
virtual void CancelResourceRequests(int render_widget_id);
virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params);
@@ -62,11 +64,18 @@ class MockRenderProcessHost : public RenderProcessHost {
virtual void OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelConnected(int32 peer_pid);
+ // Attaches the factory object so we can remove this object in its destructor
+ // and prevent MockRenderProcessHostFacotry from deleting it.
+ void SetFactory(const MockRenderProcessHostFactory* factory) {
+ factory_ = factory;
+ }
+
private:
// Stores IPC messages that would have been sent to the renderer.
IPC::TestSink sink_;
TransportDIB* transport_dib_;
int bad_msg_count_;
+ const MockRenderProcessHostFactory* factory_;
DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHost);
};
@@ -74,14 +83,21 @@ class MockRenderProcessHost : public RenderProcessHost {
class MockRenderProcessHostFactory : public RenderProcessHostFactory {
public:
MockRenderProcessHostFactory() {}
- virtual ~MockRenderProcessHostFactory() {}
+ virtual ~MockRenderProcessHostFactory();
- virtual RenderProcessHost* CreateRenderProcessHost(
- Profile* profile) const {
- return new MockRenderProcessHost(profile);
- }
+ virtual RenderProcessHost* CreateRenderProcessHost(Profile* profile) const;
+
+ // Removes the given MockRenderProcessHost from the MockRenderProcessHost list
+ // without deleting it. When a test deletes a MockRenderProcessHost, we need
+ // to remove it from |processes_| to prevent it from being deleted twice.
+ void Remove(MockRenderProcessHost* host) const;
private:
+ // A list of MockRenderProcessHosts created by this object. This list is used
+ // for deleting all MockRenderProcessHosts that have not deleted by a test in
+ // the destructor and prevent them from being leaked.
+ mutable ScopedVector<MockRenderProcessHost> processes_;
+
DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHostFactory);
};
diff --git a/chrome/browser/renderer_host/offline_resource_handler.h b/chrome/browser/renderer_host/offline_resource_handler.h
index 567e3a6..8c72ead 100644
--- a/chrome/browser/renderer_host/offline_resource_handler.h
+++ b/chrome/browser/renderer_host/offline_resource_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_OFFLINE_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_OFFLINE_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h
index ed8473b..19911f0 100644
--- a/chrome/browser/renderer_host/render_process_host.h
+++ b/chrome/browser/renderer_host/render_process_host.h
@@ -1,12 +1,12 @@
-// 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.
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_PROCESS_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_PROCESS_HOST_H_
+#pragma once
#include <set>
-#include <string>
#include "app/surface/transport_dib.h"
#include "base/id_map.h"
@@ -148,8 +148,8 @@ class RenderProcessHost : public IPC::Channel::Sender,
// be called once before the object can be used, but can be called after
// that with no effect. Therefore, if the caller isn't sure about whether
// the process has been created, it should just call Init().
- virtual bool Init(bool is_extensions_process,
- URLRequestContextGetter* request_context) = 0;
+ virtual bool Init(
+ bool is_accessibility_enabled, bool is_extensions_process) = 0;
// Gets the next available routing id.
virtual int GetNextRoutingID() = 0;
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
index 5824fc9..5292d95 100644
--- a/chrome/browser/renderer_host/render_sandbox_host_linux.cc
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.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.
@@ -23,6 +23,7 @@
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/unix_domain_socket_posix.h"
#include "chrome/common/sandbox_methods_linux.h"
@@ -156,13 +157,13 @@ class SandboxIPCProcess {
void HandleFontMatchRequest(int fd, const Pickle& pickle, void* iter,
std::vector<int>& fds) {
- bool fileid_valid;
- uint32_t fileid;
+ bool filefaceid_valid;
+ uint32_t filefaceid;
- if (!pickle.ReadBool(&iter, &fileid_valid))
+ if (!pickle.ReadBool(&iter, &filefaceid_valid))
return;
- if (fileid_valid) {
- if (!pickle.ReadUInt32(&iter, &fileid))
+ if (filefaceid_valid) {
+ if (!pickle.ReadUInt32(&iter, &filefaceid))
return;
}
bool is_bold, is_italic;
@@ -177,7 +178,7 @@ class SandboxIPCProcess {
const char* characters = NULL;
if (characters_bytes > 0) {
const uint32_t kMaxCharactersBytes = 1 << 10;
- if (characters_bytes % 2 == 0 || // We expect UTF-16.
+ if (characters_bytes % 2 != 0 || // We expect UTF-16.
characters_bytes > kMaxCharactersBytes ||
!pickle.ReadBytes(&iter, &characters, characters_bytes))
return;
@@ -188,17 +189,17 @@ class SandboxIPCProcess {
return;
std::string result_family;
- unsigned result_fileid;
+ unsigned result_filefaceid;
const bool r = font_config_->Match(
- &result_family, &result_fileid, fileid_valid, fileid, family,
- characters, characters_bytes, &is_bold, &is_italic);
+ &result_family, &result_filefaceid, filefaceid_valid, filefaceid,
+ family, characters, characters_bytes, &is_bold, &is_italic);
Pickle reply;
if (!r) {
reply.WriteBool(false);
} else {
reply.WriteBool(true);
- reply.WriteUInt32(result_fileid);
+ reply.WriteUInt32(result_filefaceid);
reply.WriteString(result_family);
reply.WriteBool(is_bold);
reply.WriteBool(is_italic);
@@ -208,10 +209,10 @@ class SandboxIPCProcess {
void HandleFontOpenRequest(int fd, const Pickle& pickle, void* iter,
std::vector<int>& fds) {
- uint32_t fileid;
- if (!pickle.ReadUInt32(&iter, &fileid))
+ uint32_t filefaceid;
+ if (!pickle.ReadUInt32(&iter, &filefaceid))
return;
- const int result_fd = font_config_->Open(fileid);
+ const int result_fd = font_config_->Open(filefaceid);
Pickle reply;
if (result_fd == -1) {
@@ -336,14 +337,15 @@ class SandboxIPCProcess {
std::string inode_output;
std::vector<std::string> sandbox_cmd = sandbox_cmd_;
- sandbox_cmd.push_back(Int64ToString(inode));
+ sandbox_cmd.push_back(base::Int64ToString(inode));
CommandLine get_inode_cmd(sandbox_cmd);
if (base::GetAppOutput(get_inode_cmd, &inode_output))
- StringToInt(inode_output, &pid);
+ base::StringToInt(inode_output, &pid);
if (!pid) {
+ // Even though the pid is invalid, we still need to reply to the zygote
+ // and not just return here.
LOG(ERROR) << "Could not get pid";
- return;
}
Pickle reply;
@@ -358,7 +360,7 @@ class SandboxIPCProcess {
return;
int shm_fd = -1;
base::SharedMemory shm;
- if (shm.Create(L"", false, false, shm_size))
+ if (shm.Create("", false, false, shm_size))
shm_fd = shm.handle().fd;
Pickle reply;
SendRendererReply(fds, reply, shm_fd);
@@ -495,8 +497,10 @@ class SandboxIPCProcess {
Pickle reply;
SendRendererReply(fds, reply, font_fd);
- if (font_fd >= 0)
- HANDLE_EINTR(close(font_fd));
+ if (font_fd >= 0) {
+ if (HANDLE_EINTR(close(font_fd)) < 0)
+ PLOG(ERROR) << "close";
+ }
}
// MSCharSetToFontconfig translates a Microsoft charset identifier to a
@@ -630,7 +634,10 @@ class SandboxIPCProcess {
// Runs on the main thread at startup.
RenderSandboxHostLinux::RenderSandboxHostLinux()
- : init_(false) {
+ : init_(false),
+ renderer_socket_(0),
+ childs_lifeline_fd_(0),
+ pid_(0) {
}
void RenderSandboxHostLinux::Init(const std::string& sandbox_path) {
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.h b/chrome/browser/renderer_host/render_sandbox_host_linux.h
index ef871b8..f8e1551 100644
--- a/chrome/browser/renderer_host/render_sandbox_host_linux.h
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_SANDBOX_HOST_LINUX_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index fd87831..8d31005 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -8,20 +8,22 @@
#include <utility>
#include <vector>
-#include "app/resource_bundle.h"
+#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/json/json_reader.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "base/time.h"
-#include "base/waitable_event.h"
+#include "chrome/browser/blocked_plugin_manager.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/cross_site_request_manager.h"
#include "chrome/browser/debugger/devtools_manager.h"
#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/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
@@ -30,13 +32,16 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/common/bindings_policy.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/native_web_keyboard_event.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/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/result_codes.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/common/translate_errors.h"
#include "chrome/common/url_constants.h"
@@ -44,13 +49,13 @@
#include "net/base/net_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h"
+#include "webkit/glue/context_menu.h"
+#include "webkit/glue/dom_operations.h"
#include "webkit/glue/form_data.h"
#include "webkit/glue/form_field.h"
-
-#if defined(OS_WIN)
-// TODO(port): accessibility not yet implemented. See http://crbug.com/8288.
-#include "chrome/browser/browser_accessibility_manager_win.h"
-#endif
+#include "webkit/glue/password_form_dom_manager.h"
+#include "webkit/glue/webaccessibility.h"
+#include "webkit/glue/webdropdata.h"
using base::TimeDelta;
using webkit_glue::FormData;
@@ -112,7 +117,7 @@ RenderViewHost* RenderViewHost::FromID(int render_process_id,
RenderViewHost::RenderViewHost(SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- int64 session_storage_namespace_id)
+ SessionStorageNamespace* session_storage)
: RenderWidgetHost(instance->GetProcess(), routing_id),
instance_(instance),
delegate_(delegate),
@@ -127,8 +132,14 @@ RenderViewHost::RenderViewHost(SiteInstance* instance,
unload_ack_is_for_cross_site_transition_(false),
are_javascript_messages_suppressed_(false),
sudden_termination_allowed_(false),
- session_storage_namespace_id_(session_storage_namespace_id),
- is_extension_process_(false) {
+ session_storage_namespace_(session_storage),
+ is_extension_process_(false),
+ save_accessibility_tree_for_testing_(false) {
+ if (!session_storage_namespace_) {
+ session_storage_namespace_ =
+ new SessionStorageNamespace(process()->profile());
+ }
+
DCHECK(instance_);
DCHECK(delegate_);
}
@@ -139,22 +150,16 @@ RenderViewHost::~RenderViewHost() {
// Be sure to clean up any leftover state from cross-site requests.
Singleton<CrossSiteRequestManager>()->SetHasPendingCrossSiteRequest(
process()->id(), routing_id(), false);
-
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PORT_DELETED_DEBUG,
- Source<IPC::Message::Sender>(this),
- NotificationService::NoDetails());
}
-bool RenderViewHost::CreateRenderView(
- URLRequestContextGetter* request_context, const string16& frame_name) {
+bool RenderViewHost::CreateRenderView(const string16& frame_name) {
DCHECK(!IsRenderViewLive()) << "Creating view twice";
// The process may (if we're sharing a process with another host that already
// initialized it) or may not (we have our own process or the old process
// crashed) have been initialized. Calling Init multiple times will be
// ignored, so this is safe.
- if (!process()->Init(is_extension_process_, request_context))
+ if (!process()->Init(renderer_accessible(), is_extension_process_))
return false;
DCHECK(process()->HasConnection());
DCHECK(process()->profile());
@@ -191,7 +196,7 @@ bool RenderViewHost::CreateRenderView(
delegate_->GetRendererPrefs(process()->profile());
params.web_preferences = webkit_prefs;
params.view_id = routing_id();
- params.session_storage_namespace_id = session_storage_namespace_id_;
+ params.session_storage_namespace_id = session_storage_namespace_->id();
params.frame_name = frame_name;
Send(new ViewMsg_New(params));
@@ -238,6 +243,10 @@ void RenderViewHost::Navigate(const ViewMsg_Navigate_Params& params) {
DCHECK(!suspended_nav_message_.get());
suspended_nav_message_.reset(nav_message);
} else {
+ // Unset this, otherwise if true and the hang monitor fires we'll
+ // incorrectly close the tab.
+ is_waiting_for_unload_ack_ = false;
+
Send(nav_message);
// Force the throbber to start. We do this because WebKit's "started
@@ -253,6 +262,11 @@ void RenderViewHost::Navigate(const ViewMsg_Navigate_Params& params) {
// don't want to either.
if (!params.url.SchemeIs(chrome::kJavaScriptScheme))
delegate_->DidStartLoading();
+
+ const GURL& url = params.url;
+ if (!delegate_->IsExternalTabContainer() &&
+ (url.SchemeIs("http") || url.SchemeIs("https")))
+ chrome_browser_net::PreconnectUrlAndSubresources(url);
}
}
@@ -449,7 +463,7 @@ void RenderViewHost::DragTargetDragEnter(
FilePath path = FilePath::FromWStringHack(UTF16ToWideHack(*iter));
policy->GrantRequestURL(process()->id(),
net::FilePathToFileURL(path));
- policy->GrantUploadFile(process()->id(), path);
+ policy->GrantReadFile(process()->id(), path);
}
Send(new ViewMsg_DragTargetDragEnter(routing_id(), drop_data, client_pt,
screen_pt, operations_allowed));
@@ -636,6 +650,14 @@ void RenderViewHost::GotFocus() {
view->GotFocus();
}
+void RenderViewHost::LostCapture() {
+ RenderWidgetHost::LostCapture();
+
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->LostCapture();
+}
+
void RenderViewHost::SetInitialFocus(bool reverse) {
Send(new ViewMsg_SetInitialFocus(routing_id(), reverse));
}
@@ -652,12 +674,16 @@ void RenderViewHost::InstallMissingPlugin() {
Send(new ViewMsg_InstallMissingPlugin(routing_id()));
}
+void RenderViewHost::LoadBlockedPlugins() {
+ Send(new ViewMsg_LoadBlockedPlugins(routing_id()));
+}
+
void RenderViewHost::FilesSelectedInChooser(
const std::vector<FilePath>& files) {
// Grant the security access requested to the given files.
for (std::vector<FilePath>::const_iterator file = files.begin();
file != files.end(); ++file) {
- ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile(
+ ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
process()->id(), *file);
}
Send(new ViewMsg_RunFileChooserResponse(routing_id(), files));
@@ -703,6 +729,8 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP_EX(RenderViewHost, msg, msg_is_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowView, OnMsgShowView)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnMsgShowWidget)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowFullscreenWidget,
+ OnMsgShowFullscreenWidget)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_RunModal, OnMsgRunModal)
IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnMsgRenderViewReady)
IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewGone, OnMsgRenderViewGone)
@@ -771,8 +799,6 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateDragCursor, OnUpdateDragCursor)
IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageHasOSDD, OnMsgPageHasOSDD)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetSearchProviderInstallState,
- OnMsgGetSearchProviderInstallState)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidGetPrintedPagesCount,
OnDidGetPrintedPagesCount)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidPrintPage, DidPrintPage)
@@ -789,12 +815,18 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
OnRequestDockDevToolsWindow);
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestUndockDevToolsWindow,
OnRequestUndockDevToolsWindow);
- IPC_MESSAGE_HANDLER(ViewHostMsg_DevToolsRuntimeFeatureStateChanged,
- OnDevToolsRuntimeFeatureStateChanged);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DevToolsRuntimePropertyChanged,
+ OnDevToolsRuntimePropertyChanged);
IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction,
OnUserMetricsRecordAction)
IPC_MESSAGE_HANDLER(ViewHostMsg_MissingPluginStatus, OnMissingPluginStatus);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_NonSandboxedPluginBlocked,
+ OnNonSandboxedPluginBlocked);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_BlockedPluginLoaded,
+ OnBlockedPluginLoaded);
IPC_MESSAGE_HANDLER(ViewHostMsg_CrashedPlugin, OnCrashedPlugin);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DisabledOutdatedPlugin,
+ OnDisabledOutdatedPlugin);
IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
OnReceivedSavableResourceLinksForCurrentPage);
IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData,
@@ -822,18 +854,20 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_SelectionChanged, OnMsgSelectionChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionPostMessage,
OnExtensionPostMessage)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AccessibilityFocusChange,
- OnAccessibilityFocusChange)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AccessibilityObjectStateChange,
- OnAccessibilityObjectStateChange)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AccessibilityNotifications,
+ OnAccessibilityNotifications)
IPC_MESSAGE_HANDLER(ViewHostMsg_OnCSSInserted, OnCSSInserted)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageTranslated, OnPageTranslated)
IPC_MESSAGE_HANDLER(ViewHostMsg_ContentBlocked, OnContentBlocked)
IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed)
IPC_MESSAGE_HANDLER(ViewHostMsg_WebDatabaseAccessed, OnWebDatabaseAccessed)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AccessibilityTree, OnAccessibilityTree)
IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeChanged, OnMsgFocusedNodeChanged)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetDisplayingPDFContent,
+ OnSetDisplayingPDFContent)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetSuggestResult, OnSetSuggestResult)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DetectedPhishingSite,
+ OnDetectedPhishingSite)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(RenderWidgetHost::OnMessageReceived(msg))
IPC_END_MESSAGE_MAP_EX()
@@ -877,6 +911,13 @@ void RenderViewHost::CreateNewWidget(int route_id,
view->CreateNewWidget(route_id, popup_type);
}
+void RenderViewHost::CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->CreateNewFullscreenWidget(route_id, popup_type);
+}
+
void RenderViewHost::OnMsgShowView(int route_id,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
@@ -897,6 +938,14 @@ void RenderViewHost::OnMsgShowWidget(int route_id,
}
}
+void RenderViewHost::OnMsgShowFullscreenWidget(int route_id) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view) {
+ view->ShowCreatedFullscreenWidget(route_id);
+ Send(new ViewMsg_Move_ACK(route_id));
+ }
+}
+
void RenderViewHost::OnMsgRunModal(IPC::Message* reply_msg) {
DCHECK(!run_modal_reply_msg_);
run_modal_reply_msg_ = reply_msg;
@@ -983,7 +1032,6 @@ void RenderViewHost::OnMsgNavigate(const IPC::Message& msg) {
FilterURL(policy, renderer_id, &validated_params.password_form.origin);
FilterURL(policy, renderer_id, &validated_params.password_form.action);
- SetDocumentLoaded(false);
delegate_->DidNavigate(this, validated_params);
}
@@ -1066,8 +1114,8 @@ void RenderViewHost::OnMsgDocumentAvailableInMainFrame() {
delegate_->DocumentAvailableInMainFrame(this);
}
-void RenderViewHost::OnMsgDocumentOnLoadCompletedInMainFrame() {
- delegate_->DocumentOnLoadCompletedInMainFrame(this);
+void RenderViewHost::OnMsgDocumentOnLoadCompletedInMainFrame(int32 page_id) {
+ delegate_->DocumentOnLoadCompletedInMainFrame(this, page_id);
}
void RenderViewHost::OnMsgDidLoadResourceFromMemoryCache(
@@ -1245,11 +1293,6 @@ void RenderViewHost::OnMsgDOMUISend(
return;
}
- // DOMUI doesn't use these values yet.
- // TODO(aa): When DOMUI is ported to ExtensionFunctionDispatcher, send real
- // values here.
- const int kRequestId = -1;
- const bool kHasCallback = false;
scoped_ptr<Value> value;
if (!content.empty()) {
value.reset(base::JSONReader::Read(content, false));
@@ -1261,11 +1304,18 @@ void RenderViewHost::OnMsgDOMUISend(
}
}
- delegate_->ProcessDOMUIMessage(message,
- static_cast<const ListValue*>(value.get()),
- source_url,
- kRequestId,
- kHasCallback);
+ ViewHostMsg_DomMessage_Params params;
+ params.name = message;
+ if (value.get())
+ params.arguments.Swap(static_cast<ListValue*>(value.get()));
+ params.source_url = source_url;
+ // DOMUI doesn't use these values yet.
+ // TODO(aa): When DOMUI is ported to ExtensionFunctionDispatcher, send real
+ // values here.
+ params.request_id = -1;
+ params.has_callback = false;
+ params.user_gesture = false;
+ delegate_->ProcessDOMUIMessage(params);
}
void RenderViewHost::OnMsgForwardMessageToExternalHost(
@@ -1279,7 +1329,6 @@ void RenderViewHost::OnMsgDocumentLoadedInFrame() {
delegate_->GetResourceDelegate();
if (resource_delegate)
resource_delegate->DocumentLoadedInFrame();
- SetDocumentLoaded(true);
}
void RenderViewHost::DisassociateFromPopupCount() {
@@ -1317,7 +1366,9 @@ void RenderViewHost::OnMsgSetTooltipText(
if (!tooltip_text.empty()) {
if (text_direction_hint == WebKit::WebTextDirectionLeftToRight) {
// Force the tooltip to have LTR directionality.
- base::i18n::GetDisplayStringInLTRDirectionality(&wrapped_tooltip_text);
+ wrapped_tooltip_text = UTF16ToWide(
+ base::i18n::GetDisplayStringInLTRDirectionality(
+ WideToUTF16(wrapped_tooltip_text)));
} else if (text_direction_hint == WebKit::WebTextDirectionRightToLeft &&
!base::i18n::IsRTL()) {
// Force the tooltip to have RTL directionality.
@@ -1335,7 +1386,10 @@ void RenderViewHost::OnMsgSelectionChanged(const std::string& text) {
void RenderViewHost::OnMsgRunFileChooser(
const ViewHostMsg_RunFileChooser_Params& params) {
- delegate_->RunFileChooser(params);
+ RenderViewHostDelegate::FileSelect* file_select_delegate =
+ delegate()->GetFileSelectDelegate();
+ if (file_select_delegate)
+ file_select_delegate->RunFileChooser(this, params);
}
void RenderViewHost::OnMsgRunJavaScriptMessage(
@@ -1432,14 +1486,6 @@ void RenderViewHost::OnMsgPageHasOSDD(int32 page_id, const GURL& doc_url,
delegate_->PageHasOSDD(this, page_id, doc_url, autodetected);
}
-void RenderViewHost::OnMsgGetSearchProviderInstallState(
- const GURL& url, IPC::Message* reply_msg) {
- ViewHostMsg_GetSearchProviderInstallState::WriteReplyParams(
- reply_msg,
- delegate_->GetSearchProviderInstallState(url));
- Send(reply_msg);
-}
-
void RenderViewHost::OnDidGetPrintedPagesCount(int cookie, int number_pages) {
RenderViewHostDelegate::Printing* printing_delegate =
delegate_->GetPrintingDelegate();
@@ -1487,11 +1533,11 @@ void RenderViewHost::OnRequestUndockDevToolsWindow() {
DevToolsManager::GetInstance()->RequestUndockWindow(this);
}
-void RenderViewHost::OnDevToolsRuntimeFeatureStateChanged(
- const std::string& feature,
- bool enabled) {
+void RenderViewHost::OnDevToolsRuntimePropertyChanged(
+ const std::string& name,
+ const std::string& value) {
DevToolsManager::GetInstance()->
- RuntimeFeatureStateChanged(this, feature, enabled);
+ RuntimePropertyChanged(this, name, value);
}
void RenderViewHost::OnUserMetricsRecordAction(const std::string& action) {
@@ -1525,6 +1571,23 @@ void RenderViewHost::OnMissingPluginStatus(int status) {
integration_delegate->OnMissingPluginStatus(status);
}
+void RenderViewHost::OnNonSandboxedPluginBlocked(const std::string& plugin,
+ const string16& name) {
+ RenderViewHostDelegate::BlockedPlugin* blocked_plugin_delegate =
+ delegate_->GetBlockedPluginDelegate();
+ if (blocked_plugin_delegate) {
+ blocked_plugin_delegate->OnNonSandboxedPluginBlocked(plugin, name);
+ }
+}
+
+void RenderViewHost::OnBlockedPluginLoaded() {
+ RenderViewHostDelegate::BlockedPlugin* blocked_plugin_delegate =
+ delegate_->GetBlockedPluginDelegate();
+ if (blocked_plugin_delegate) {
+ blocked_plugin_delegate->OnBlockedPluginLoaded();
+ }
+}
+
void RenderViewHost::OnCrashedPlugin(const FilePath& plugin_path) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
@@ -1532,6 +1595,14 @@ void RenderViewHost::OnCrashedPlugin(const FilePath& plugin_path) {
integration_delegate->OnCrashedPlugin(plugin_path);
}
+void RenderViewHost::OnDisabledOutdatedPlugin(const string16& name,
+ const GURL& update_url) {
+ RenderViewHostDelegate::BrowserIntegration* integration_delegate =
+ delegate_->GetBrowserIntegrationDelegate();
+ if (integration_delegate)
+ integration_delegate->OnDisabledOutdatedPlugin(name, update_url);
+}
+
void RenderViewHost::GetAllSavableResourceLinksForCurrentPage(
const GURL& page_url) {
Send(new ViewMsg_GetAllSavableResourceLinksForCurrentPage(routing_id(),
@@ -1607,6 +1678,7 @@ void RenderViewHost::OnQueryFormFieldAutoFill(
AutoFillSuggestionsReturned(query_id,
std::vector<string16>(),
std::vector<string16>(),
+ std::vector<string16>(),
std::vector<int>());
}
@@ -1630,52 +1702,47 @@ void RenderViewHost::OnRemoveAutocompleteEntry(const string16& field_name,
}
void RenderViewHost::OnShowAutoFillDialog() {
- RenderViewHostDelegate::AutoFill* autofill_delegate =
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ Browser* browser = BrowserList::GetLastActive();
+ if (!browser)
+ return;
+ browser->ShowOptionsTab(chrome::kAutoFillSubPage);
+ } else {
+ RenderViewHostDelegate::AutoFill* autofill_delegate =
delegate_->GetAutoFillDelegate();
- if (!autofill_delegate)
- return;
+ if (!autofill_delegate)
+ return;
- autofill_delegate->ShowAutoFillDialog();
+ autofill_delegate->ShowAutoFillDialog();
+ }
}
void RenderViewHost::OnFillAutoFillFormData(int query_id,
const FormData& form,
- const string16& name,
- const string16& label,
int unique_id) {
RenderViewHostDelegate::AutoFill* autofill_delegate =
delegate_->GetAutoFillDelegate();
if (!autofill_delegate)
return;
- autofill_delegate->FillAutoFillFormData(
- query_id, form, name, label, unique_id);
+ autofill_delegate->FillAutoFillFormData(query_id, form, unique_id);
}
void RenderViewHost::AutoFillSuggestionsReturned(
int query_id,
const std::vector<string16>& names,
const std::vector<string16>& labels,
+ const std::vector<string16>& icons,
const std::vector<int>& unique_ids) {
- autofill_query_id_ = query_id;
autofill_values_.assign(names.begin(), names.end());
autofill_labels_.assign(labels.begin(), labels.end());
+ autofill_icons_.assign(icons.begin(), icons.end());
autofill_unique_ids_.assign(unique_ids.begin(), unique_ids.end());
}
void RenderViewHost::AutocompleteSuggestionsReturned(
int query_id, const std::vector<string16>& suggestions) {
- // When query IDs match we are responding to an AutoFill and Autocomplete
- // combined query response.
- // Otherwise Autocomplete is canceling, so we only send suggestions (usually
- // an empty list).
- if (autofill_query_id_ != query_id) {
- // Autocomplete is canceling.
- autofill_values_.clear();
- autofill_labels_.clear();
- autofill_unique_ids_.clear();
- }
-
// Combine AutoFill and Autocomplete values into values and labels.
for (size_t i = 0; i < suggestions.size(); ++i) {
bool unique = true;
@@ -1692,6 +1759,7 @@ void RenderViewHost::AutocompleteSuggestionsReturned(
if (unique) {
autofill_values_.push_back(suggestions[i]);
autofill_labels_.push_back(string16());
+ autofill_icons_.push_back(string16());
autofill_unique_ids_.push_back(0); // 0 means no profile.
}
}
@@ -1700,6 +1768,7 @@ void RenderViewHost::AutocompleteSuggestionsReturned(
query_id,
autofill_values_,
autofill_labels_,
+ autofill_icons_,
autofill_unique_ids_));
}
@@ -1725,6 +1794,18 @@ void RenderViewHost::OnMsgFocusedNodeChanged() {
delegate_->FocusedNodeChanged();
}
+void RenderViewHost::OnMsgFocus() {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->Activate();
+}
+
+void RenderViewHost::OnMsgBlur() {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->Deactivate();
+}
+
gfx::Rect RenderViewHost::GetRootWindowResizerRect() const {
return delegate_->GetRootWindowResizerRect();
}
@@ -1741,16 +1822,20 @@ void RenderViewHost::ForwardMouseEvent(
if (view) {
switch (event_copy.type) {
case WebInputEvent::MouseMove:
- view->HandleMouseEvent();
+ view->HandleMouseMove();
break;
case WebInputEvent::MouseLeave:
view->HandleMouseLeave();
break;
case WebInputEvent::MouseDown:
+ view->HandleMouseDown();
+ break;
case WebInputEvent::MouseWheel:
if (ignore_input_events() && delegate_)
delegate_->OnIgnoredUIEvent();
break;
+ case WebInputEvent::MouseUp:
+ view->HandleMouseUp();
default:
// For now, we don't care about the rest.
break;
@@ -1758,6 +1843,12 @@ void RenderViewHost::ForwardMouseEvent(
}
}
+void RenderViewHost::OnMouseActivate() {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->HandleMouseActivate();
+}
+
void RenderViewHost::ForwardKeyboardEvent(
const NativeWebKeyboardEvent& key_event) {
if (ignore_input_events()) {
@@ -1823,21 +1914,17 @@ void RenderViewHost::OnRequestNotificationPermission(
}
}
-void RenderViewHost::OnExtensionRequest(const std::string& name,
- const ListValue& args,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
+void RenderViewHost::OnExtensionRequest(
+ const ViewHostMsg_DomMessage_Params& params) {
if (!ChildProcessSecurityPolicy::GetInstance()->
HasExtensionBindings(process()->id())) {
// This can happen if someone uses window.open() to open an extension URL
// from a non-extension context.
- BlockExtensionRequest(request_id);
+ BlockExtensionRequest(params.request_id);
return;
}
- delegate_->ProcessDOMUIMessage(name, &args, source_url, request_id,
- has_callback);
+ delegate_->ProcessDOMUIMessage(params);
}
void RenderViewHost::SendExtensionResponse(int request_id, bool success,
@@ -1852,10 +1939,6 @@ void RenderViewHost::BlockExtensionRequest(int request_id) {
"Access to extension API denied.");
}
-void RenderViewHost::ViewTypeChanged(ViewType::Type type) {
- Send(new ViewMsg_NotifyRenderViewType(routing_id(), type));
-}
-
void RenderViewHost::UpdateBrowserWindowId(int window_id) {
Send(new ViewMsg_UpdateBrowserWindowId(routing_id(), window_id));
}
@@ -1893,23 +1976,34 @@ void RenderViewHost::OnExtensionPostMessage(
}
}
-void RenderViewHost::OnAccessibilityFocusChange(int acc_obj_id) {
- view()->OnAccessibilityFocusChange(acc_obj_id);
-}
+void RenderViewHost::OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) {
+ if (view())
+ view()->OnAccessibilityNotifications(params);
-void RenderViewHost::OnAccessibilityObjectStateChange(int acc_obj_id) {
- view()->OnAccessibilityObjectStateChange(acc_obj_id);
-}
+ if (params.size() > 0) {
+ for (unsigned i = 0; i < params.size(); i++) {
+ const ViewHostMsg_AccessibilityNotification_Params& param = params[i];
-void RenderViewHost::OnAccessibilityTree(
- const webkit_glue::WebAccessibility& tree) {
- if (view())
- view()->UpdateAccessibilityTree(tree);
+ if (param.notification_type ==
+ ViewHostMsg_AccessibilityNotification_Params::
+ NOTIFICATION_TYPE_LOAD_COMPLETE) {
+ // TODO(ctguil): Remove when mac processes OnAccessibilityNotifications.
+ if (view())
+ view()->UpdateAccessibilityTree(param.acc_obj);
- NotificationService::current()->Notify(
- NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED,
- Source<RenderViewHost>(this),
- NotificationService::NoDetails());
+ if (save_accessibility_tree_for_testing_)
+ accessibility_tree_ = param.acc_obj;
+ }
+ }
+
+ NotificationService::current()->Notify(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED,
+ Source<RenderViewHost>(this),
+ NotificationService::NoDetails());
+ }
+
+ AccessibilityNotificationsAck();
}
void RenderViewHost::OnCSSInserted() {
@@ -1941,11 +2035,12 @@ void RenderViewHost::OnPageTranslated(int32 page_id,
translated_lang, error_type);
}
-void RenderViewHost::OnContentBlocked(ContentSettingsType type) {
+void RenderViewHost::OnContentBlocked(ContentSettingsType type,
+ const std::string& resource_identifier) {
RenderViewHostDelegate::ContentSettings* content_settings_delegate =
delegate_->GetContentSettingsDelegate();
if (content_settings_delegate)
- content_settings_delegate->OnContentBlocked(type);
+ content_settings_delegate->OnContentBlocked(type, resource_identifier);
}
void RenderViewHost::OnAppCacheAccessed(const GURL& manifest_url,
@@ -1968,3 +2063,23 @@ void RenderViewHost::OnWebDatabaseAccessed(const GURL& url,
content_settings_delegate->OnWebDatabaseAccessed(
url, name, display_name, estimated_size, blocked_by_policy);
}
+
+void RenderViewHost::OnSetDisplayingPDFContent() {
+ delegate_->SetDisplayingPDFContent();
+}
+
+void RenderViewHost::OnSetSuggestResult(int32 page_id,
+ const std::string& result) {
+ RenderViewHostDelegate::BrowserIntegration* integration_delegate =
+ delegate_->GetBrowserIntegrationDelegate();
+ if (!integration_delegate)
+ return;
+ integration_delegate->OnSetSuggestResult(page_id, result);
+}
+
+void RenderViewHost::OnDetectedPhishingSite(const GURL& phishing_url,
+ double phishing_score,
+ const SkBitmap& thumbnail) {
+ // TODO(noelutz): send an HTTP request to the client-side detection frontends
+ // to confirm that the URL is really phishing.
+}
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index 02a216d..82277a3 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_H_
+#pragma once
#include <string>
#include <vector>
@@ -28,6 +29,7 @@ class FilePath;
class GURL;
class ListValue;
class RenderViewHostDelegate;
+class SessionStorageNamespace;
class SiteInstance;
class SkBitmap;
class ViewMsg_Navigate;
@@ -35,7 +37,9 @@ struct ContentSettings;
struct ContextMenuParams;
struct MediaPlayerAction;
struct ThumbnailScore;
+struct ViewHostMsg_AccessibilityNotification_Params;
struct ViewHostMsg_DidPrintPage_Params;
+struct ViewHostMsg_DomMessage_Params;
struct ViewHostMsg_RunFileChooser_Params;
struct ViewHostMsg_ShowNotification_Params;
struct ViewMsg_Navigate_Params;
@@ -52,6 +56,7 @@ struct FormData;
class FormField;
struct PasswordForm;
struct PasswordFormFillData;
+struct WebAccessibility;
struct WebApplicationInfo;
} // namespace webkit_glue
@@ -96,10 +101,15 @@ class RenderViewHost : public RenderWidgetHost {
// routing_id could be a valid route id, or it could be MSG_ROUTING_NONE, in
// which case RenderWidgetHost will create a new one.
+ //
+ // The session storage namespace parameter allows multiple render views and
+ // tab contentses to share the same session storage (part of the WebStorage
+ // spec) space. This is useful when restoring tabs, but most callers should
+ // pass in NULL which will cause a new SessionStorageNamespace to be created.
RenderViewHost(SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- int64 session_storage_namespace_id);
+ SessionStorageNamespace* session_storage_namespace);
virtual ~RenderViewHost();
SiteInstance* site_instance() const { return instance_; }
@@ -108,8 +118,7 @@ class RenderViewHost : public RenderWidgetHost {
// Set up the RenderView child process. Virtual because it is overridden by
// TestRenderViewHost. If the |frame_name| parameter is non-empty, it is used
// as the name of the new top-level frame.
- virtual bool CreateRenderView(URLRequestContextGetter* request_context,
- const string16& frame_name);
+ virtual bool CreateRenderView(const string16& frame_name);
// Returns true if the RenderView is active and has not crashed. Virtual
// because it is overridden by TestRenderViewHost.
@@ -323,6 +332,7 @@ class RenderViewHost : public RenderWidgetHost {
int enabled_bindings() { return enabled_bindings_; }
// See variable comment.
+ bool is_extension_process() { return is_extension_process_; }
void set_is_extension_process(bool is_extension_process) {
is_extension_process_ = is_extension_process;
}
@@ -344,6 +354,9 @@ class RenderViewHost : public RenderWidgetHost {
// missing plugin. Called by PluginInstaller.
void InstallMissingPlugin();
+ // Load all blocked plugins in the RenderView.
+ void LoadBlockedPlugins();
+
// Get all savable resource links from current webpage, include main
// frame and sub-frame.
void GetAllSavableResourceLinksForCurrentPage(const GURL& page_url);
@@ -391,6 +404,7 @@ class RenderViewHost : public RenderWidgetHost {
int query_id,
const std::vector<string16>& values,
const std::vector<string16>& labels,
+ const std::vector<string16>& icons,
const std::vector<int>& unique_ids);
// Called by the AutocompleteHistoryManager when the list of suggestions is
@@ -411,7 +425,9 @@ class RenderViewHost : public RenderWidgetHost {
virtual bool IsRenderView() const { return true; }
virtual void OnMessageReceived(const IPC::Message& msg);
virtual void GotFocus();
+ virtual void LostCapture();
virtual void ForwardMouseEvent(const WebKit::WebMouseEvent& mouse_event);
+ virtual void OnMouseActivate();
virtual void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event);
virtual void ForwardEditCommand(const std::string& name,
const std::string& value);
@@ -428,6 +444,9 @@ class RenderViewHost : public RenderWidgetHost {
// if this widget is a popup and what kind of popup it is (select, autofill).
void CreateNewWidget(int route_id, WebKit::WebPopupType popup_type);
+ // Creates a full screen RenderWidget.
+ void CreateNewFullscreenWidget(int route_id, WebKit::WebPopupType popup_type);
+
// Sends the response to an extension api call.
void SendExtensionResponse(int request_id, bool success,
const std::string& response,
@@ -437,9 +456,6 @@ class RenderViewHost : public RenderWidgetHost {
// permission.
void BlockExtensionRequest(int request_id);
- // Notifies the renderer that its view type has changed.
- void ViewTypeChanged(ViewType::Type type);
-
// Tells the renderer which browser window it is being attached to.
void UpdateBrowserWindowId(int window_id);
@@ -468,6 +484,20 @@ class RenderViewHost : public RenderWidgetHost {
// in render_messages.h.
void EnablePreferredSizeChangedMode(int flags);
+#if defined(UNIT_TEST)
+ // These functions shouldn't be necessary outside of testing.
+
+ void set_save_accessibility_tree_for_testing(bool save) {
+ save_accessibility_tree_for_testing_ = save;
+ }
+
+ const webkit_glue::WebAccessibility& accessibility_tree() {
+ return accessibility_tree_;
+ }
+
+ bool is_waiting_for_unload_ack() { return is_waiting_for_unload_ack_; }
+#endif
+
protected:
// RenderWidgetHost protected overrides.
virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
@@ -477,6 +507,8 @@ class RenderViewHost : public RenderWidgetHost {
virtual void NotifyRendererUnresponsive();
virtual void NotifyRendererResponsive();
virtual void OnMsgFocusedNodeChanged();
+ virtual void OnMsgFocus();
+ virtual void OnMsgBlur();
// IPC message handlers.
void OnMsgShowView(int route_id,
@@ -484,6 +516,7 @@ class RenderViewHost : public RenderWidgetHost {
const gfx::Rect& initial_pos,
bool user_gesture);
void OnMsgShowWidget(int route_id, const gfx::Rect& initial_pos);
+ void OnMsgShowFullscreenWidget(int route_id);
void OnMsgRunModal(IPC::Message* reply_msg);
void OnMsgRenderViewReady();
void OnMsgRenderViewGone();
@@ -505,7 +538,7 @@ class RenderViewHost : public RenderWidgetHost {
void OnMsgDidStartLoading();
void OnMsgDidStopLoading();
void OnMsgDocumentAvailableInMainFrame();
- void OnMsgDocumentOnLoadCompletedInMainFrame();
+ void OnMsgDocumentOnLoadCompletedInMainFrame(int32 page_id);
void OnMsgDidLoadResourceFromMemoryCache(const GURL& url,
const std::string& frame_origin,
const std::string& main_frame_origin,
@@ -573,8 +606,6 @@ class RenderViewHost : public RenderWidgetHost {
void OnUpdateDragCursor(WebKit::WebDragOperation drag_operation);
void OnTakeFocus(bool reverse);
void OnMsgPageHasOSDD(int32 page_id, const GURL& doc_url, bool autodetected);
- void OnMsgGetSearchProviderInstallState(const GURL& url,
- IPC::Message* reply_msg);
void OnDidGetPrintedPagesCount(int cookie, int number_pages);
void DidPrintPage(const ViewHostMsg_DidPrintPage_Params& params);
void OnAddMessageToConsole(const std::wstring& message,
@@ -588,12 +619,16 @@ class RenderViewHost : public RenderWidgetHost {
void OnCloseDevToolsWindow();
void OnRequestDockDevToolsWindow();
void OnRequestUndockDevToolsWindow();
- void OnDevToolsRuntimeFeatureStateChanged(const std::string& feature,
- bool enabled);
+ void OnDevToolsRuntimePropertyChanged(const std::string& name,
+ const std::string& value);
void OnUserMetricsRecordAction(const std::string& action);
void OnMissingPluginStatus(int status);
+ void OnNonSandboxedPluginBlocked(const std::string& plugin,
+ const string16& name);
+ void OnBlockedPluginLoaded();
void OnCrashedPlugin(const FilePath& plugin_path);
+ void OnDisabledOutdatedPlugin(const string16& name, const GURL& update_url);
void OnReceivedSavableResourceLinksForCurrentPage(
const std::vector<GURL>& resources_list,
@@ -615,8 +650,6 @@ class RenderViewHost : public RenderWidgetHost {
void OnShowAutoFillDialog();
void OnFillAutoFillFormData(int query_id,
const webkit_glue::FormData& form,
- const string16& value,
- const string16& label,
int unique_id);
void OnShowDesktopNotification(
@@ -624,14 +657,10 @@ class RenderViewHost : public RenderWidgetHost {
void OnCancelDesktopNotification(int notification_id);
void OnRequestNotificationPermission(const GURL& origin, int callback_id);
- void OnExtensionRequest(const std::string& name, const ListValue& args,
- const GURL& source_url,
- int request_id,
- bool has_callback);
+ void OnExtensionRequest(const ViewHostMsg_DomMessage_Params& params);
void OnExtensionPostMessage(int port_id, const std::string& message);
- void OnAccessibilityFocusChange(int acc_obj_id);
- void OnAccessibilityObjectStateChange(int acc_obj_id);
- void OnAccessibilityTree(const webkit_glue::WebAccessibility& tree);
+ void OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params);
void OnCSSInserted();
void OnPageContents(const GURL& url,
int32 page_id,
@@ -642,13 +671,19 @@ class RenderViewHost : public RenderWidgetHost {
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type);
- void OnContentBlocked(ContentSettingsType type);
+ void OnContentBlocked(ContentSettingsType type,
+ const std::string& resource_identifier);
void OnAppCacheAccessed(const GURL& manifest_url, bool blocked_by_policy);
void OnWebDatabaseAccessed(const GURL& url,
const string16& name,
const string16& display_name,
unsigned long estimated_size,
bool blocked_by_policy);
+ void OnSetDisplayingPDFContent();
+ void OnSetSuggestResult(int32 page_id, const std::string& result);
+ void OnDetectedPhishingSite(const GURL& phishing_url,
+ double phishing_score,
+ const SkBitmap& thumbnail);
private:
friend class TestRenderViewHost;
@@ -714,20 +749,26 @@ class RenderViewHost : public RenderWidgetHost {
// True if the render view can be shut down suddenly.
bool sudden_termination_allowed_;
- // The session storage namespace id to be used by the associated render view.
- int64 session_storage_namespace_id_;
+ // The session storage namespace to be used by the associated render view.
+ scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
- // Whether this render view will be used for extensions. This controls
+ // Whether this render view will get extension api bindings. This controls
// what process type we use.
bool is_extension_process_;
// AutoFill and Autocomplete suggestions. We accumulate these separately and
// send them back to the renderer together.
- int autofill_query_id_;
std::vector<string16> autofill_values_;
std::vector<string16> autofill_labels_;
+ std::vector<string16> autofill_icons_;
std::vector<int> autofill_unique_ids_;
+ // Whether the accessibility tree should be saved, for unit testing.
+ bool save_accessibility_tree_for_testing_;
+
+ // The most recently received accessibility tree - for unit testing only.
+ webkit_glue::WebAccessibility accessibility_tree_;
+
DISALLOW_COPY_AND_ASSIGN(RenderViewHost);
};
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.cc b/chrome/browser/renderer_host/render_view_host_delegate.cc
index 1396368..523fd8f 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.cc
+++ b/chrome/browser/renderer_host/render_view_host_delegate.cc
@@ -6,12 +6,13 @@
#include "base/singleton.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/renderer_preferences.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/webpreferences.h"
-#if defined(OS_LINUX)
+#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/gtk_util.h"
#endif
@@ -68,11 +69,21 @@ RenderViewHostDelegate::GetBookmarkDragDelegate() {
return NULL;
}
+RenderViewHostDelegate::BlockedPlugin*
+RenderViewHostDelegate::GetBlockedPluginDelegate() {
+ return NULL;
+}
+
RenderViewHostDelegate::SSL*
RenderViewHostDelegate::GetSSLDelegate() {
return NULL;
}
+RenderViewHostDelegate::FileSelect*
+RenderViewHostDelegate::GetFileSelectDelegate() {
+ return NULL;
+}
+
AutomationResourceRoutingDelegate*
RenderViewHostDelegate::GetAutomationResourceRoutingDelegate() {
return NULL;
@@ -90,11 +101,6 @@ GURL RenderViewHostDelegate::GetAlternateErrorPageURL() const {
return GURL();
}
-ViewHostMsg_GetSearchProviderInstallState_Params
-RenderViewHostDelegate::GetSearchProviderInstallState(const GURL& url) {
- return ViewHostMsg_GetSearchProviderInstallState_Params::Denied();
-}
-
WebPreferences RenderViewHostDelegate::GetWebkitPrefs() {
return WebPreferences();
}
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
index 5817176..2f0f5b4 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.h
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_DELEGATE_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_DELEGATE_H_
+#pragma once
#include <string>
#include <vector>
@@ -12,6 +13,7 @@
#include "base/ref_counted.h"
#include "base/string16.h"
#include "chrome/common/content_settings_types.h"
+#include "chrome/common/dom_storage_common.h"
#include "chrome/common/translate_errors.h"
#include "chrome/common/view_types.h"
#include "chrome/common/window_container_type.h"
@@ -39,11 +41,12 @@ class ResourceRedirectDetails;
class ResourceRequestDetails;
class SkBitmap;
class SSLClientAuthHandler;
+class SSLAddCertHandler;
class TabContents;
struct ThumbnailScore;
struct ViewHostMsg_DidPrintPage_Params;
+struct ViewHostMsg_DomMessage_Params;
struct ViewHostMsg_FrameNavigate_Params;
-struct ViewHostMsg_GetSearchProviderInstallState_Params;
struct ViewHostMsg_RunFileChooser_Params;
struct WebDropData;
class WebKeyboardEvent;
@@ -116,6 +119,10 @@ class RenderViewHostDelegate {
virtual void CreateNewWidget(int route_id,
WebKit::WebPopupType popup_type) = 0;
+ // Creates a full screen RenderWidget. Similar to above.
+ virtual void CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type) = 0;
+
// Show a previously created page with the specified disposition and bounds.
// The window is identified by the route_id passed to CreateNewWindow.
//
@@ -131,6 +138,9 @@ class RenderViewHostDelegate {
virtual void ShowCreatedWidget(int route_id,
const gfx::Rect& initial_pos) = 0;
+ // Show the newly created full screen widget. Similar to above.
+ virtual void ShowCreatedFullscreenWidget(int route_id) = 0;
+
// A context menu should be shown, to be built using the context information
// provided in the supplied params.
virtual void ShowContextMenu(const ContextMenuParams& params) = 0;
@@ -150,10 +160,19 @@ class RenderViewHostDelegate {
// Notification that view for this delegate got the focus.
virtual void GotFocus() = 0;
- // Callback to inform the browser it should take back focus. If reverse is
- // true, it means the focus was retrieved by doing a Shift-Tab.
+ // Callback to inform the browser that the page is returning the focus to
+ // the browser's chrome. If reverse is true, it means the focus was
+ // retrieved by doing a Shift-Tab.
virtual void TakeFocus(bool reverse) = 0;
+ // Notification that the view has lost capture.
+ virtual void LostCapture() = 0;
+
+ // The page wants the hosting window to activate/deactivate itself (it
+ // called the JavaScript window.focus()/blur() method).
+ virtual void Activate() = 0;
+ virtual void Deactivate() = 0;
+
// Callback to give the browser a chance to handle the specified keyboard
// event before sending it to the renderer.
// Returns true if the |event| was handled. Otherwise, if the |event| would
@@ -169,11 +188,17 @@ class RenderViewHostDelegate {
// Notifications about mouse events in this view. This is useful for
// implementing global 'on hover' features external to the view.
- virtual void HandleMouseEvent() = 0;
+ virtual void HandleMouseMove() = 0;
+ virtual void HandleMouseDown() = 0;
virtual void HandleMouseLeave() = 0;
+ virtual void HandleMouseUp() = 0;
+ virtual void HandleMouseActivate() = 0;
// The contents' preferred size changed.
virtual void UpdatePreferredSize(const gfx::Size& pref_size) = 0;
+
+ protected:
+ virtual ~View() {}
};
// RendererManagerment -------------------------------------------------------
@@ -199,6 +224,9 @@ class RenderViewHostDelegate {
// Called the ResourceDispatcherHost's associate CrossSiteRequestHandler
// when a cross-site navigation has been canceled.
virtual void OnCrossSiteNavigationCanceled() = 0;
+
+ protected:
+ virtual ~RendererManagement() {}
};
// BrowserIntegration --------------------------------------------------------
@@ -236,6 +264,9 @@ class RenderViewHostDelegate {
// Notification that a worker process has crashed.
virtual void OnCrashedWorker() = 0;
+ virtual void OnDisabledOutdatedPlugin(const string16& name,
+ const GURL& update_url) = 0;
+
// Notification that a request for install info has completed.
virtual void OnDidGetApplicationInfo(
int32 page_id,
@@ -254,6 +285,13 @@ class RenderViewHostDelegate {
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type) = 0;
+
+ // Notification that the page has a suggest result.
+ virtual void OnSetSuggestResult(int32 page_id,
+ const std::string& result) = 0;
+
+ protected:
+ virtual ~BrowserIntegration() {}
};
// Resource ------------------------------------------------------------------
@@ -310,6 +348,9 @@ class RenderViewHostDelegate {
// Notification that a document has been loaded in a frame.
virtual void DocumentLoadedInFrame() = 0;
+
+ protected:
+ virtual ~Resource() {}
};
// ContentSettings------------------------------------------------------------
@@ -319,7 +360,8 @@ class RenderViewHostDelegate {
public:
// Called when content in the current page was blocked due to the user's
// content settings.
- virtual void OnContentBlocked(ContentSettingsType type) = 0;
+ virtual void OnContentBlocked(ContentSettingsType type,
+ const std::string& resource_identifier) = 0;
// Called when a specific cookie in the current page was accessed.
// |blocked_by_policy| should be true, if the cookie was blocked due to the
@@ -329,11 +371,21 @@ class RenderViewHostDelegate {
const std::string& cookie_line,
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,
+ // |blocked_by_policy| should be true, and this function should invoke
+ // OnContentBlocked.
+ virtual void OnIndexedDBAccessed(const GURL& url,
+ const string16& name,
+ const string16& description,
+ bool blocked_by_policy) = 0;
+
// Called when a specific local storage area in the current page was
// accessed. If access was blocked due to the user's content settings,
// |blocked_by_policy| should be true, and this function should invoke
// OnContentBlocked.
virtual void OnLocalStorageAccessed(const GURL& url,
+ DOMStorageType storage_type,
bool blocked_by_policy) = 0;
// Called when a specific Web database in the current page was accessed. If
@@ -357,6 +409,9 @@ class RenderViewHostDelegate {
// page.
virtual void OnGeolocationPermissionSet(const GURL& requesting_frame,
bool allowed) = 0;
+
+ protected:
+ virtual ~ContentSettings() {}
};
// Save ----------------------------------------------------------------------
@@ -382,6 +437,9 @@ class RenderViewHostDelegate {
virtual void OnReceivedSerializedHtmlData(const GURL& frame_url,
const std::string& data,
int32 status) = 0;
+
+ protected:
+ virtual ~Save() {}
};
// Printing ------------------------------------------------------------------
@@ -397,6 +455,9 @@ class RenderViewHostDelegate {
// EMF memory mapped data.
virtual void DidPrintPage(
const ViewHostMsg_DidPrintPage_Params& params) = 0;
+
+ protected:
+ virtual ~Printing() {}
};
// FavIcon -------------------------------------------------------------------
@@ -420,6 +481,9 @@ class RenderViewHostDelegate {
virtual void UpdateFavIconURL(RenderViewHost* render_view_host,
int32 page_id,
const GURL& icon_url) = 0;
+
+ protected:
+ virtual ~FavIcon() {}
};
// Autocomplete --------------------------------------------------------------
@@ -446,6 +510,9 @@ class RenderViewHostDelegate {
// Autocomplete suggestion from the database.
virtual void RemoveAutocompleteEntry(const string16& field_name,
const string16& value) = 0;
+
+ protected:
+ virtual ~Autocomplete() {}
};
// AutoFill ------------------------------------------------------------------
@@ -475,13 +542,14 @@ class RenderViewHostDelegate {
// RenderViewHost::AutoFillFormDataFilled has been called.
virtual bool FillAutoFillFormData(int query_id,
const webkit_glue::FormData& form,
- const string16& value,
- const string16& label,
int unique_id) = 0;
// Called when the user selects the 'AutoFill Options...' suggestions in the
// AutoFill popup.
virtual void ShowAutoFillDialog() = 0;
+
+ protected:
+ virtual ~AutoFill() {}
};
// BookmarkDrag --------------------------------------------------------------
@@ -493,6 +561,16 @@ class RenderViewHostDelegate {
virtual void OnDragOver(const BookmarkDragData& data) = 0;
virtual void OnDragLeave(const BookmarkDragData& data) = 0;
virtual void OnDrop(const BookmarkDragData& data) = 0;
+
+ protected:
+ virtual ~BookmarkDrag() {}
+ };
+
+ class BlockedPlugin {
+ public:
+ virtual void OnNonSandboxedPluginBlocked(const std::string& plugin,
+ const string16& name) = 0;
+ virtual void OnBlockedPluginLoaded() = 0;
};
// SSL -----------------------------------------------------------------------
@@ -504,6 +582,50 @@ class RenderViewHostDelegate {
// returning them to |handler|.
virtual void ShowClientCertificateRequestDialog(
scoped_refptr<SSLClientAuthHandler> handler) = 0;
+
+ // Called when |handler| encounters an error in verifying a
+ // received client certificate. Note that, because CAs often will
+ // not send us intermediate certificates, the verification we can
+ // do is minimal: we verify the certificate is parseable, that we
+ // have the corresponding private key, and that the certificate
+ // has not expired.
+ virtual void OnVerifyClientCertificateError(
+ scoped_refptr<SSLAddCertHandler> handler, int error_code) = 0;
+
+ // Called when |handler| requests the user's confirmation in adding a
+ // client certificate.
+ virtual void AskToAddClientCertificate(
+ scoped_refptr<SSLAddCertHandler> handler) = 0;
+
+ // Called when |handler| successfully adds a client certificate.
+ virtual void OnAddClientCertificateSuccess(
+ scoped_refptr<SSLAddCertHandler> handler) = 0;
+
+ // Called when |handler| encounters an error adding a client certificate.
+ virtual void OnAddClientCertificateError(
+ scoped_refptr<SSLAddCertHandler> handler, int error_code) = 0;
+
+ // Called when |handler| has completed, so the delegate may release any
+ // state accumulated.
+ virtual void OnAddClientCertificateFinished(
+ scoped_refptr<SSLAddCertHandler> handler) = 0;
+
+ protected:
+ virtual ~SSL() {}
+ };
+
+ // FileSelect ----------------------------------------------------------------
+ // Interface for handling file selection.
+
+ class FileSelect {
+ public:
+ // A file chooser should be shown.
+ virtual void RunFileChooser(
+ RenderViewHost* render_view_host,
+ const ViewHostMsg_RunFileChooser_Params& params) = 0;
+
+ protected:
+ virtual ~FileSelect() {}
};
// ---------------------------------------------------------------------------
@@ -521,7 +643,9 @@ class RenderViewHostDelegate {
virtual Autocomplete* GetAutocompleteDelegate();
virtual AutoFill* GetAutoFillDelegate();
virtual BookmarkDrag* GetBookmarkDragDelegate();
+ virtual BlockedPlugin* GetBlockedPluginDelegate();
virtual SSL* GetSSLDelegate();
+ virtual FileSelect* GetFileSelectDelegate();
// Return the delegate for registering RenderViewHosts for automation resource
// routing.
@@ -555,7 +679,7 @@ class RenderViewHostDelegate {
// The RenderView is going to be deleted. This is called when each
// RenderView is going to be destroyed
- virtual void RenderViewDeleted(RenderViewHost* render_view_host) { }
+ virtual void RenderViewDeleted(RenderViewHost* render_view_host) {}
// The RenderView was navigated to a different page.
virtual void DidNavigate(RenderViewHost* render_view_host,
@@ -609,7 +733,8 @@ class RenderViewHostDelegate {
// The onload handler in the RenderView's main frame has completed.
virtual void DocumentOnLoadCompletedInMainFrame(
- RenderViewHost* render_view_host) {}
+ RenderViewHost* render_view_host,
+ int32 page_id) {}
// The page wants to open a URL with the specified disposition.
virtual void RequestOpenURL(const GURL& url,
@@ -623,11 +748,8 @@ class RenderViewHostDelegate {
// A message was sent from HTML-based UI.
// By default we ignore such messages.
- virtual void ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback) {}
+ virtual void ProcessDOMUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {}
// A message for external host. By default we ignore such messages.
// |receiver| can be a receiving script and |message| is any
@@ -636,10 +758,6 @@ class RenderViewHostDelegate {
const std::string& origin,
const std::string& target) {}
- // A file chooser should be shown.
- virtual void RunFileChooser(
- const ViewHostMsg_RunFileChooser_Params& params) {}
-
// A javascript message, confirmation or prompt should be shown.
virtual void RunJavaScriptMessage(const std::wstring& message,
const std::wstring& default_prompt,
@@ -668,11 +786,6 @@ class RenderViewHostDelegate {
int32 page_id, const GURL& doc_url,
bool autodetected) {}
- // Returns the install state of the search provider url (not installed,
- // installed, default).
- virtual ViewHostMsg_GetSearchProviderInstallState_Params
- GetSearchProviderInstallState(const GURL& url);
-
// |url| is assigned to a server that can provide alternate error pages. If
// the returned URL is empty, the default error page built into WebKit will
// be used.
@@ -721,6 +834,12 @@ class RenderViewHostDelegate {
// A different node in the page got focused.
virtual void FocusedNodeChanged() {}
+
+ // The content being displayed is a PDF.
+ virtual void SetDisplayingPDFContent() {}
+
+ protected:
+ virtual ~RenderViewHostDelegate() {}
};
#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_DELEGATE_H_
diff --git a/chrome/browser/renderer_host/render_view_host_factory.cc b/chrome/browser/renderer_host/render_view_host_factory.cc
index 4331f2d..070fdec 100644
--- a/chrome/browser/renderer_host/render_view_host_factory.cc
+++ b/chrome/browser/renderer_host/render_view_host_factory.cc
@@ -15,13 +15,13 @@ RenderViewHost* RenderViewHostFactory::Create(
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- int64 session_storage_namespace_id) {
+ SessionStorageNamespace* session_storage_namespace) {
if (factory_) {
return factory_->CreateRenderViewHost(instance, delegate, routing_id,
- session_storage_namespace_id);
+ session_storage_namespace);
}
return new RenderViewHost(instance, delegate, routing_id,
- session_storage_namespace_id);
+ session_storage_namespace);
}
// static
diff --git a/chrome/browser/renderer_host/render_view_host_factory.h b/chrome/browser/renderer_host/render_view_host_factory.h
index 4adf23d..1a5f5a9 100644
--- a/chrome/browser/renderer_host/render_view_host_factory.h
+++ b/chrome/browser/renderer_host/render_view_host_factory.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_FACTORY_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_FACTORY_H_
+#pragma once
#include "base/basictypes.h"
class RenderViewHost;
class RenderViewHostDelegate;
+class SessionStorageNamespace;
class SiteInstance;
namespace base {
@@ -26,7 +28,7 @@ class RenderViewHostFactory {
static RenderViewHost* Create(SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- int64 session_storage_namespace_id);
+ SessionStorageNamespace* session_storage);
// Returns true if there is currently a globally-registered factory.
static bool has_factory() {
@@ -43,7 +45,7 @@ class RenderViewHostFactory {
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- int64 session_storage_namespace_id) = 0;
+ SessionStorageNamespace* session_storage_namespace) = 0;
// Registers your factory to be called when new RenderViewHosts are created.
// We have only one global factory, so there must be no factory registered
diff --git a/chrome/browser/renderer_host/render_view_host_notification_task.h b/chrome/browser/renderer_host/render_view_host_notification_task.h
index 1266922..6963341 100644
--- a/chrome/browser/renderer_host/render_view_host_notification_task.h
+++ b/chrome/browser/renderer_host/render_view_host_notification_task.h
@@ -9,6 +9,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_NOTIFICATION_TASK_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_NOTIFICATION_TASK_H_
+#pragma once
#include "base/callback.h"
#include "base/task.h"
@@ -296,6 +297,21 @@ inline void CallRenderViewHostContentSettingsDelegate(int render_process_id,
MakeTuple(a, b, c));
}
+template <typename Method, typename A, typename B, typename C, typename D>
+inline void CallRenderViewHostContentSettingsDelegate(int render_process_id,
+ int render_view_id,
+ Method method,
+ const A& a,
+ const B& b,
+ const C& c,
+ const D& d) {
+ internal::CallRenderViewHostContentSettingsDelegateHelper(
+ render_process_id,
+ render_view_id,
+ method,
+ MakeTuple(a, b, c, d));
+}
+
// ----------------------------------------------------------------------------
// Proxy calls to the specified RenderViewHost's RendererManagement delegate.
diff --git a/chrome/browser/renderer_host/render_widget_helper.cc b/chrome/browser/renderer_host/render_widget_helper.cc
index e2cd531..286fa42 100644
--- a/chrome/browser/renderer_host/render_widget_helper.cc
+++ b/chrome/browser/renderer_host/render_widget_helper.cc
@@ -10,7 +10,7 @@
#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/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
// A Task used with InvokeLater that we hold a pointer to in pending_paints_.
// Instances are deleted by MessageLoop after it calls their Run method.
@@ -250,6 +250,16 @@ void RenderWidgetHelper::CreateNewWidget(int opener_id,
popup_type));
}
+void RenderWidgetHelper::CreateNewFullscreenWidget(
+ int opener_id, WebKit::WebPopupType popup_type, int* route_id) {
+ *route_id = GetNextRoutingID();
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderWidgetHelper::OnCreateFullscreenWidgetOnUI,
+ opener_id, *route_id, popup_type));
+}
+
void RenderWidgetHelper::OnCreateWidgetOnUI(
int opener_id, int route_id, WebKit::WebPopupType popup_type) {
RenderViewHost* host = RenderViewHost::FromID(render_process_id_, opener_id);
@@ -257,6 +267,13 @@ void RenderWidgetHelper::OnCreateWidgetOnUI(
host->CreateNewWidget(route_id, popup_type);
}
+void RenderWidgetHelper::OnCreateFullscreenWidgetOnUI(
+ int opener_id, int route_id, WebKit::WebPopupType popup_type) {
+ RenderViewHost* host = RenderViewHost::FromID(render_process_id_, opener_id);
+ if (host)
+ host->CreateNewFullscreenWidget(route_id, popup_type);
+}
+
#if defined(OS_MACOSX)
TransportDIB* RenderWidgetHelper::MapTransportDIB(TransportDIB::Id dib_id) {
AutoLock locked(allocated_dibs_lock_);
@@ -273,7 +290,7 @@ TransportDIB* RenderWidgetHelper::MapTransportDIB(TransportDIB::Id dib_id) {
void RenderWidgetHelper::AllocTransportDIB(
size_t size, bool cache_in_browser, TransportDIB::Handle* result) {
scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
- if (!shared_memory->Create(L"", false /* read write */,
+ if (!shared_memory->Create("", false /* read write */,
false /* do not open existing */, size)) {
result->fd = -1;
result->auto_close = false;
diff --git a/chrome/browser/renderer_host/render_widget_helper.h b/chrome/browser/renderer_host/render_widget_helper.h
index d31bf66..6cad1dc 100644
--- a/chrome/browser/renderer_host/render_widget_helper.h
+++ b/chrome/browser/renderer_host/render_widget_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HELPER_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HELPER_H_
+#pragma once
#include <map>
@@ -129,6 +130,9 @@ class RenderWidgetHelper
void CreateNewWidget(int opener_id,
WebKit::WebPopupType popup_type,
int* route_id);
+ void CreateNewFullscreenWidget(int opener_id,
+ WebKit::WebPopupType popup_type,
+ int* route_id);
#if defined(OS_MACOSX)
// Called on the IO thread to handle the allocation of a TransportDIB. If
@@ -176,6 +180,11 @@ class RenderWidgetHelper
int route_id,
WebKit::WebPopupType popup_type);
+ // Called on the UI thread to create a full screen widget.
+ void OnCreateFullscreenWidgetOnUI(int opener_id,
+ int route_id,
+ WebKit::WebPopupType popup_type);
+
// Called on the IO thread to cancel resource requests for the render widget.
void OnCancelResourceRequests(int render_widget_id);
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index 749d4c9..eb2fc33 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -4,10 +4,10 @@
#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "app/keyboard_codes.h"
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/histogram.h"
-#include "base/keyboard_codes.h"
#include "base/message_loop.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/renderer_host/backing_store.h"
@@ -18,8 +18,12 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/video_layer.h"
#include "chrome/common/chrome_switches.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"
#if defined(TOOLKIT_VIEWS)
@@ -96,6 +100,11 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process,
// Because the widget initializes as is_hidden_ == false,
// tell the process host that we're alive.
process_->WidgetRestored();
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kForceRendererAccessibility)) {
+ EnableRendererAccessibility();
+ }
}
RenderWidgetHost::~RenderWidgetHost() {
@@ -154,12 +163,7 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) {
OnMsgImeCancelComposition)
IPC_MESSAGE_HANDLER(ViewHostMsg_GpuRenderingActivated,
OnMsgGpuRenderingActivated)
-#if defined(OS_LINUX)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer,
- OnMsgCreatePluginContainer)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyPluginContainer,
- OnMsgDestroyPluginContainer)
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnMsgShowPopup)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnMsgGetScreenInfo)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect)
@@ -174,6 +178,11 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) {
OnAcceleratedSurfaceSetTransportDIB)
IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceBuffersSwapped,
OnAcceleratedSurfaceBuffersSwapped)
+#elif defined(OS_POSIX)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer,
+ OnMsgCreatePluginContainer)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyPluginContainer,
+ OnMsgDestroyPluginContainer)
#endif
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP_EX()
@@ -222,8 +231,11 @@ void RenderWidgetHost::WasRestored() {
BackingStore* backing_store = BackingStoreManager::Lookup(this);
// If we already have a backing store for this widget, then we don't need to
// repaint on restore _unless_ we know that our backing store is invalid.
+ // When accelerated compositing is on, we must always repaint, even when
+ // the backing store exists.
bool needs_repainting;
- if (needs_repainting_on_restore_ || !backing_store) {
+ if (needs_repainting_on_restore_ || !backing_store ||
+ is_gpu_rendering_active()) {
needs_repainting = true;
needs_repainting_on_restore_ = false;
} else {
@@ -363,6 +375,11 @@ void RenderWidgetHost::DonePaintingToBackingStore() {
}
void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHangMonitor)) {
+ return;
+ }
+
// If we already have a timer that will expire at or before the given delay,
// then we have nothing more to do now. If we have set our end time to null
// by calling StopHangMonitorTimeout, though, we will need to restart the
@@ -420,6 +437,9 @@ void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) {
ForwardInputEvent(mouse_event, sizeof(WebMouseEvent), false);
}
+void RenderWidgetHost::OnMouseActivate() {
+}
+
void RenderWidgetHost::ForwardWheelEvent(
const WebMouseWheelEvent& wheel_event) {
if (ignore_input_events_ || process_->ignore_input_events())
@@ -461,8 +481,8 @@ void RenderWidgetHost::ForwardKeyboardEvent(
return;
if (key_event.type == WebKeyboardEvent::Char &&
- (key_event.windowsKeyCode == base::VKEY_RETURN ||
- key_event.windowsKeyCode == base::VKEY_SPACE)) {
+ (key_event.windowsKeyCode == app::VKEY_RETURN ||
+ key_event.windowsKeyCode == app::VKEY_SPACE)) {
OnUserGesture();
}
@@ -480,21 +500,24 @@ void RenderWidgetHost::ForwardKeyboardEvent(
suppress_next_char_events_ = false;
}
- // We need to set |suppress_next_char_events_| to true if
- // PreHandleKeyboardEvent() returns true, but |this| may already be
- // destroyed at that time. So set |suppress_next_char_events_| true here,
- // then revert it afterwards when necessary.
- if (key_event.type == WebKeyboardEvent::RawKeyDown)
- suppress_next_char_events_ = true;
-
bool is_keyboard_shortcut = false;
- // Tab switching/closing accelerators aren't sent to the renderer to avoid a
- // hung/malicious renderer from interfering.
- if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut))
- return;
+ // Only pre-handle the key event if it's not handled by the input method.
+ if (!key_event.skip_in_browser) {
+ // We need to set |suppress_next_char_events_| to true if
+ // PreHandleKeyboardEvent() returns true, but |this| may already be
+ // destroyed at that time. So set |suppress_next_char_events_| true here,
+ // then revert it afterwards when necessary.
+ if (key_event.type == WebKeyboardEvent::RawKeyDown)
+ suppress_next_char_events_ = true;
+
+ // Tab switching/closing accelerators aren't sent to the renderer to avoid
+ // a hung/malicious renderer from interfering.
+ if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut))
+ return;
- if (key_event.type == WebKeyboardEvent::RawKeyDown)
- suppress_next_char_events_ = false;
+ if (key_event.type == WebKeyboardEvent::RawKeyDown)
+ suppress_next_char_events_ = false;
+ }
// Don't add this key to the queue if we have no way to send the message...
if (!process_->HasConnection())
@@ -718,6 +741,9 @@ void RenderWidgetHost::OnMsgUpdateRect(
const ViewHostMsg_UpdateRect_Params& params) {
TimeTicks paint_start = TimeTicks::Now();
+ if (paint_observer_.get())
+ paint_observer_->RenderWidgetHostWillPaint(this);
+
// Update our knowledge of the RenderWidget's size.
current_size_ = params.view_size;
@@ -743,28 +769,33 @@ void RenderWidgetHost::OnMsgUpdateRect(
DCHECK(!params.bitmap_rect.IsEmpty());
DCHECK(!params.view_size.IsEmpty());
- const size_t size = params.bitmap_rect.height() *
- params.bitmap_rect.width() * 4;
- TransportDIB* dib = process_->GetTransportDIB(params.bitmap);
bool painted_synchronously = true; // Default to sending a paint ACK below.
- if (dib) {
- if (dib->size() < size) {
- DLOG(WARNING) << "Transport DIB too small for given rectangle";
- process()->ReceivedBadMessage(ViewHostMsg_UpdateRect__ID);
- } else {
- // Scroll the backing store.
- if (!params.scroll_rect.IsEmpty()) {
- ScrollBackingStoreRect(params.dx, params.dy,
- params.scroll_rect,
- params.view_size);
+ if (!is_gpu_rendering_active_) {
+ const size_t size = params.bitmap_rect.height() *
+ params.bitmap_rect.width() * 4;
+ TransportDIB* dib = process_->GetTransportDIB(params.bitmap);
+
+ // If gpu process does painting, scroll_rect and copy_rects are always empty
+ // and backing store is never used.
+ if (dib) {
+ if (dib->size() < size) {
+ DLOG(WARNING) << "Transport DIB too small for given rectangle";
+ process()->ReceivedBadMessage(ViewHostMsg_UpdateRect__ID);
+ } else {
+ // Scroll the backing store.
+ if (!params.scroll_rect.IsEmpty()) {
+ ScrollBackingStoreRect(params.dx, params.dy,
+ params.scroll_rect,
+ params.view_size);
+ }
+
+ // Paint the backing store. This will update it with the
+ // renderer-supplied bits. The view will read out of the backing store
+ // later to actually draw to the screen.
+ PaintBackingStoreRect(params.bitmap, params.bitmap_rect,
+ params.copy_rects, params.view_size,
+ &painted_synchronously);
}
-
- // Paint the backing store. This will update it with the renderer-supplied
- // bits. The view will read out of the backing store later to actually
- // draw to the screen.
- PaintBackingStoreRect(params.bitmap, params.bitmap_rect,
- params.copy_rects, params.view_size,
- &painted_synchronously);
}
}
@@ -882,14 +913,13 @@ void RenderWidgetHost::ProcessWheelAck() {
}
void RenderWidgetHost::OnMsgFocus() {
- // Only the user can focus a RenderWidgetHost.
+ // Only RenderViewHost can deal with that message.
process()->ReceivedBadMessage(ViewHostMsg_Focus__ID);
}
void RenderWidgetHost::OnMsgBlur() {
- if (view_) {
- view_->Blur();
- }
+ // Only RenderViewHost can deal with that message.
+ process()->ReceivedBadMessage(ViewHostMsg_Blur__ID);
}
void RenderWidgetHost::OnMsgSetCursor(const WebCursor& cursor) {
@@ -912,31 +942,17 @@ void RenderWidgetHost::OnMsgImeCancelComposition() {
}
void RenderWidgetHost::OnMsgGpuRenderingActivated(bool activated) {
+#if defined(OS_MACOSX)
+ bool old_state = is_gpu_rendering_active_;
+#endif
is_gpu_rendering_active_ = activated;
+#if defined(OS_MACOSX)
+ if (old_state != is_gpu_rendering_active_ && view_)
+ view_->GpuRenderingStateDidChange();
+#endif
}
-#if defined(OS_LINUX)
-
-void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) {
- // TODO(piman): view_ can only be NULL with delayed view creation in
- // extensions (see ExtensionHost::CreateRenderViewSoon). Figure out how to
- // support plugins in that case.
- if (view_) {
- view_->CreatePluginContainer(id);
- } else {
- NOTIMPLEMENTED();
- }
-}
-
-void RenderWidgetHost::OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id) {
- if (view_) {
- view_->DestroyPluginContainer(id);
- } else {
- NOTIMPLEMENTED();
- }
-}
-
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
void RenderWidgetHost::OnMsgShowPopup(
const ViewHostMsg_ShowPopup_Params& params) {
@@ -970,11 +986,12 @@ void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id,
void RenderWidgetHost::OnAllocateFakePluginWindowHandle(
bool opaque,
+ bool root,
gfx::PluginWindowHandle* id) {
// TODO(kbr): similar potential issue here as in OnMsgCreatePluginContainer.
// Possibly less of an issue because this is only used for the GPU plugin.
if (view_) {
- *id = view_->AllocateFakePluginWindowHandle(opaque);
+ *id = view_->AllocateFakePluginWindowHandle(opaque, root);
} else {
NOTIMPLEMENTED();
}
@@ -1016,6 +1033,27 @@ void RenderWidgetHost::OnAcceleratedSurfaceBuffersSwapped(
view_->AcceleratedSurfaceBuffersSwapped(window);
}
}
+#elif defined(OS_POSIX)
+
+void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) {
+ // TODO(piman): view_ can only be NULL with delayed view creation in
+ // extensions (see ExtensionHost::CreateRenderViewSoon). Figure out how to
+ // support plugins in that case.
+ if (view_) {
+ view_->CreatePluginContainer(id);
+ } else {
+ NOTIMPLEMENTED();
+ }
+}
+
+void RenderWidgetHost::OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id) {
+ if (view_) {
+ view_->DestroyPluginContainer(id);
+ } else {
+ NOTIMPLEMENTED();
+ }
+}
+
#endif
void RenderWidgetHost::PaintBackingStoreRect(
@@ -1103,22 +1141,6 @@ void RenderWidgetHost::AdvanceToNextMisspelling() {
Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_));
}
-void RenderWidgetHost::RequestAccessibilityTree() {
- Send(new ViewMsg_GetAccessibilityTree(routing_id()));
-}
-
-void RenderWidgetHost::SetDocumentLoaded(bool document_loaded) {
- document_loaded_ = document_loaded;
-
- if (!document_loaded_)
- requested_accessibility_tree_ = false;
-
- if (renderer_accessible_ && document_loaded_) {
- RequestAccessibilityTree();
- requested_accessibility_tree_ = true;
- }
-}
-
void RenderWidgetHost::EnableRendererAccessibility() {
if (renderer_accessible_)
return;
@@ -1130,9 +1152,9 @@ void RenderWidgetHost::EnableRendererAccessibility() {
renderer_accessible_ = true;
- if (document_loaded_ && !requested_accessibility_tree_) {
- RequestAccessibilityTree();
- requested_accessibility_tree_ = true;
+ if (process_->HasConnection()) {
+ // Renderer accessibility wasn't enabled on process launch. Enable it now.
+ Send(new ViewMsg_EnableAccessibility(routing_id()));
}
}
@@ -1144,6 +1166,10 @@ void RenderWidgetHost::AccessibilityDoDefaultAction(int acc_obj_id) {
Send(new ViewMsg_AccessibilityDoDefaultAction(routing_id(), acc_obj_id));
}
+void RenderWidgetHost::AccessibilityNotificationsAck() {
+ Send(new ViewMsg_AccessibilityNotifications_ACK(routing_id()));
+}
+
void RenderWidgetHost::ProcessKeyboardEventAck(int type, bool processed) {
if (key_queue_.size() == 0) {
LOG(ERROR) << "Got a KeyEvent back from the renderer but we "
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index 26cabbc..c34bece 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_H_
+#pragma once
#include <deque>
#include <string>
@@ -11,7 +12,6 @@
#include "app/surface/transport_dib.h"
#include "base/gtest_prod_util.h"
-#include "base/process.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/timer.h"
@@ -21,8 +21,7 @@
#include "gfx/native_widget_types.h"
#include "gfx/size.h"
#include "ipc/ipc_channel.h"
-#include "ipc/ipc_channel_handle.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/WebTextDirection.h"
#include "third_party/WebKit/WebKit/chromium/public/WebTextInputType.h"
@@ -33,7 +32,7 @@ class Rect;
namespace WebKit {
class WebInputEvent;
class WebMouseEvent;
-class WebMouseWheelEvent;
+struct WebCompositionUnderline;
struct WebScreenInfo;
}
@@ -125,11 +124,11 @@ struct ViewHostMsg_UpdateRect_Params;
class RenderWidgetHost : public IPC::Channel::Listener,
public IPC::Channel::Sender {
public:
- // An interface that gets called whenever a paint occurs.
- // Used in performance tests.
+ // An interface that gets called before and after a paint.
class PaintObserver {
public:
virtual ~PaintObserver() {}
+ virtual void RenderWidgetHostWillPaint(RenderWidgetHost* rhw) = 0;
virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh) = 0;
};
@@ -147,6 +146,7 @@ class RenderWidgetHost : public IPC::Channel::Listener,
RenderProcessHost* process() const { return process_; }
int routing_id() const { return routing_id_; }
+ static bool renderer_accessible() { return renderer_accessible_; }
// Set the PaintObserver on this object. Takes ownership.
void set_paint_observer(PaintObserver* paint_observer) {
@@ -201,7 +201,7 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// Tells the renderer it got/lost focus.
void Focus();
void Blur();
- void LostCapture();
+ virtual void LostCapture();
// Tells us whether the page is rendered directly via the GPU process.
bool is_gpu_rendering_active() { return is_gpu_rendering_active_; }
@@ -270,6 +270,8 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// Forwards the given message to the renderer. These are called by the view
// when it has received a message.
virtual void ForwardMouseEvent(const WebKit::WebMouseEvent& mouse_event);
+ // Called when a mouse click activates the renderer.
+ virtual void OnMouseActivate();
void ForwardWheelEvent(const WebKit::WebMouseWheelEvent& wheel_event);
virtual void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event);
virtual void ForwardEditCommand(const std::string& name,
@@ -291,9 +293,9 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// NotifyTextDirection();
// }
// 2. Change the text direction when pressing a set of keys.
- // Becauses of auto-repeat, we may receive the same key-press event many
+ // Because of auto-repeat, we may receive the same key-press event many
// times while we presses the keys and it is nonsense to send the same IPC
- // messsage every time when we receive a key-press event.
+ // message every time when we receive a key-press event.
// To suppress the number of IPC messages, we just update the text direction
// when receiving a key-press event and send an IPC message when we release
// the keys as listed in the following snippet.
@@ -386,6 +388,9 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// on a node with this accessibility object id.
void AccessibilityDoDefaultAction(int acc_obj_id);
+ // Acknowledges a ViewHostMsg_AccessibilityNotifications message.
+ void AccessibilityNotificationsAck();
+
// Sets the active state (i.e., control tints).
virtual void SetActive(bool active);
@@ -397,13 +402,6 @@ class RenderWidgetHost : public IPC::Channel::Listener,
}
protected:
- // Aid for determining when an accessibility tree request can be made. Set by
- // TabContents to true on document load and to false on page nativigation.
- void SetDocumentLoaded(bool document_loaded);
-
- // Requests a snapshot of an accessible DOM tree from the renderer.
- void RequestAccessibilityTree();
-
// Internal implementation of the public Forward*Event() methods.
void ForwardInputEvent(const WebKit::WebInputEvent& input_event,
int event_size, bool is_keyboard_shortcut);
@@ -480,8 +478,8 @@ class RenderWidgetHost : public IPC::Channel::Listener,
void OnMsgUpdateVideo(TransportDIB::Id bitmap, const gfx::Rect& bitmap_rect);
void OnMsgDestroyVideo();
void OnMsgInputEventAck(const IPC::Message& message);
- void OnMsgFocus();
- void OnMsgBlur();
+ virtual void OnMsgFocus();
+ virtual void OnMsgBlur();
void OnMsgSetCursor(const WebCursor& cursor);
void OnMsgImeUpdateTextInputState(WebKit::WebTextInputType type,
@@ -490,16 +488,14 @@ class RenderWidgetHost : public IPC::Channel::Listener,
void OnMsgGpuRenderingActivated(bool activated);
-#if defined(OS_LINUX)
- void OnMsgCreatePluginContainer(gfx::PluginWindowHandle id);
- void OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id);
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
void OnMsgShowPopup(const ViewHostMsg_ShowPopup_Params& params);
void OnMsgGetScreenInfo(gfx::NativeViewId view,
WebKit::WebScreenInfo* results);
void OnMsgGetWindowRect(gfx::NativeViewId window_id, gfx::Rect* results);
void OnMsgGetRootWindowRect(gfx::NativeViewId window_id, gfx::Rect* results);
void OnAllocateFakePluginWindowHandle(bool opaque,
+ bool root,
gfx::PluginWindowHandle* id);
void OnDestroyFakePluginWindowHandle(gfx::PluginWindowHandle id);
void OnAcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window,
@@ -511,6 +507,9 @@ class RenderWidgetHost : public IPC::Channel::Listener,
int32 height,
TransportDIB::Handle transport_dib);
void OnAcceleratedSurfaceBuffersSwapped(gfx::PluginWindowHandle window);
+#elif defined(OS_POSIX)
+ void OnMsgCreatePluginContainer(gfx::PluginWindowHandle id);
+ void OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id);
#endif
// Paints the given bitmap to the current backing store at the given location.
@@ -640,7 +639,7 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// Optional observer that listens for notifications of painting.
scoped_ptr<PaintObserver> paint_observer_;
- // Flag to detect recurive calls to GetBackingStore().
+ // Flag to detect recursive calls to GetBackingStore().
bool in_get_backing_store_;
// Set when we call DidPaintRect/DidScrollRect on the view.
@@ -674,7 +673,7 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// System may translate a RawKeyDown event into zero or more Char events,
// usually we send them to the renderer directly in sequence. However, If a
// RawKeyDown event was not handled by the renderer but was handled by
- // our UnhandledKeyboardEvent() method, eg. as an accelerator key, then we
+ // our UnhandledKeyboardEvent() method, e.g. as an accelerator key, then we
// shall not send the following sequence of Char events, which was generated
// by this RawKeyDown event, to the renderer. Otherwise the renderer may
// handle the Char events and cause unexpected behavior.
@@ -685,14 +684,6 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// changed.
bool suppress_next_char_events_;
- // Keep track of if we have a loaded document so that we can request an
- // accessibility tree on demand when renderer accessibility is enabled.
- bool document_loaded_;
-
- // Keep track of if we've already requested the accessibility tree so
- // we don't do it more than once.
- bool requested_accessibility_tree_;
-
// Optional video YUV layer for used for out-of-process compositing.
scoped_ptr<VideoLayer> video_layer_;
diff --git a/chrome/browser/renderer_host/render_widget_host_painting_observer.h b/chrome/browser/renderer_host/render_widget_host_painting_observer.h
index 70d96fd..3c6c867 100644
--- a/chrome/browser/renderer_host/render_widget_host_painting_observer.h
+++ b/chrome/browser/renderer_host/render_widget_host_painting_observer.h
@@ -4,12 +4,10 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_PAINTING_OBSERVER_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_PAINTING_OBSERVER_H_
-
-#include "app/surface/transport_dib.h"
+#pragma once
class BackingStore;
class RenderWidgetHost;
-class SkBitmap;
namespace gfx {
class Size;
@@ -33,6 +31,9 @@ class RenderWidgetHostPaintingObserver {
RenderWidgetHost* widget,
int tag,
const gfx::Size& size) = 0;
+
+ protected:
+ virtual ~RenderWidgetHostPaintingObserver() {}
};
#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_PAINTING_OBSERVER_H_
diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc
index e462fec..1c5bb17 100644
--- a/chrome/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc
@@ -2,8 +2,8 @@
// 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/basictypes.h"
-#include "base/keyboard_codes.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
#include "base/timer.h"
@@ -12,6 +12,8 @@
#include "chrome/browser/renderer_host/render_widget_host_painting_observer.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "chrome/test/testing_profile.h"
#include "gfx/canvas_skia.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -262,7 +264,7 @@ class RenderWidgetHostTest : public testing::Test {
void SimulateKeyboardEvent(WebInputEvent::Type type) {
NativeWebKeyboardEvent key_event;
key_event.type = type;
- key_event.windowsKeyCode = base::VKEY_L; // non-null made up value.
+ key_event.windowsKeyCode = app::VKEY_L; // non-null made up value.
host_->ForwardKeyboardEvent(key_event);
}
diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h
index 9a20af0..4258a86 100644
--- a/chrome/browser/renderer_host/render_widget_host_view.h
+++ b/chrome/browser/renderer_host/render_widget_host_view.h
@@ -4,19 +4,20 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_H_
+#pragma once
#if defined(OS_MACOSX)
#include <OpenGL/OpenGL.h>
#endif
+#include <string>
+#include <vector>
+
#include "app/surface/transport_dib.h"
-#include "base/shared_memory.h"
#include "gfx/native_widget_types.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebPopupType.h"
#include "third_party/WebKit/WebKit/chromium/public/WebTextInputType.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/webaccessibility.h"
namespace gfx {
class Rect;
@@ -31,8 +32,14 @@ class RenderProcessHost;
class RenderWidgetHost;
class VideoLayer;
class WebCursor;
+struct ViewHostMsg_AccessibilityNotification_Params;
struct WebMenuItem;
+namespace webkit_glue {
+struct WebAccessibility;
+struct WebPluginGeometry;
+}
+
// RenderWidgetHostView is an interface implemented by an object that acts as
// the "View" portion of a RenderWidgetHost. The RenderWidgetHost and its
// associated RenderProcessHost own the "Model" in this case which is the
@@ -66,6 +73,10 @@ class RenderWidgetHostView {
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) = 0;
+ // Perform all the initialization steps necessary for this object to represent
+ // a full screen window.
+ virtual void InitAsFullscreen(RenderWidgetHostView* parent_host_view) = 0;
+
// Returns the associated RenderWidgetHost.
virtual RenderWidgetHost* GetRenderWidgetHost() const = 0;
@@ -196,7 +207,7 @@ class RenderWidgetHostView {
// Methods associated with GPU-accelerated plug-in instances.
virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(
- bool opaque) = 0;
+ bool opaque, bool root) = 0;
virtual void DestroyFakePluginWindowHandle(
gfx::PluginWindowHandle window) = 0;
virtual void AcceleratedSurfaceSetIOSurface(
@@ -211,11 +222,10 @@ class RenderWidgetHostView {
TransportDIB::Handle transport_dib) = 0;
virtual void AcceleratedSurfaceBuffersSwapped(
gfx::PluginWindowHandle window) = 0;
- // Draws the current GPU-accelerated plug-in instances into the given context.
- virtual void DrawAcceleratedSurfaceInstances(CGLContextObj context) = 0;
+ virtual void GpuRenderingStateDidChange() = 0;
#endif
-#if defined(OS_LINUX)
+#if defined(TOOLKIT_USES_GTK)
virtual void CreatePluginContainer(gfx::PluginWindowHandle id) = 0;
virtual void DestroyPluginContainer(gfx::PluginWindowHandle id) = 0;
#endif
@@ -242,8 +252,9 @@ class RenderWidgetHostView {
virtual void UpdateAccessibilityTree(
const webkit_glue::WebAccessibility& tree) { }
- virtual void OnAccessibilityFocusChange(int acc_obj_id) { }
- virtual void OnAccessibilityObjectStateChange(int acc_obj_id) { }
+ virtual void OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) {
+ }
protected:
// Interface class only, do not construct.
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 693ff5e..4cf14cb 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -9,11 +9,11 @@
// badly with URLRequestStatus::Status.
#include "chrome/common/render_messages.h"
-#include <gtk/gtk.h>
+#include <cairo/cairo.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
-#include <cairo/cairo.h>
+#include <gtk/gtk.h>
#include <algorithm>
#include <string>
@@ -22,10 +22,11 @@
#include "app/x11_util.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/histogram.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
-#include "base/task.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/backing_store_x.h"
#include "chrome/browser/renderer_host/gpu_view_host.h"
@@ -37,6 +38,8 @@
#include "chrome/common/native_web_keyboard_event.h"
#include "gfx/gtk_util.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"
#if defined(OS_CHROMEOS)
@@ -225,6 +228,37 @@ class RenderWidgetHostViewGtkWidget {
static gboolean ButtonPressReleaseEvent(
GtkWidget* widget, GdkEventButton* event,
RenderWidgetHostViewGtk* host_view) {
+#if defined (OS_CHROMEOS)
+ // We support buttons 8 & 9 for scrolling with an attached USB mouse
+ // in ChromeOS. We do this separately from the builtin scrolling support
+ // because we want to support the user's expectations about the amount
+ // scrolled on each event. xorg.conf on chromeos specifies buttons
+ // 8 & 9 for the scroll wheel for the attached USB mouse.
+ if (event->type == GDK_BUTTON_RELEASE &&
+ (event->button == 8 || event->button == 9)) {
+ GdkEventScroll scroll_event;
+ scroll_event.type = GDK_SCROLL;
+ scroll_event.window = event->window;
+ scroll_event.send_event = event->send_event;
+ scroll_event.time = event->time;
+ scroll_event.x = event->x;
+ scroll_event.y = event->y;
+ scroll_event.state = event->state;
+ if (event->state & GDK_SHIFT_MASK) {
+ scroll_event.direction =
+ event->button == 8 ? GDK_SCROLL_LEFT : GDK_SCROLL_RIGHT;
+ } else {
+ scroll_event.direction =
+ event->button == 8 ? GDK_SCROLL_UP : GDK_SCROLL_DOWN;
+ }
+ scroll_event.device = event->device;
+ scroll_event.x_root = event->x_root;
+ scroll_event.y_root = event->y_root;
+ WebMouseWheelEvent web_event =
+ WebInputEventFactory::mouseWheelEvent(&scroll_event);
+ host_view->GetRenderWidgetHost()->ForwardWheelEvent(web_event);
+ }
+#endif
if (!(event->button == 1 || event->button == 2 || event->button == 3))
return FALSE; // We do not forward any other buttons to the renderer.
if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
@@ -286,6 +320,8 @@ class RenderWidgetHostViewGtkWidget {
event->x = x;
event->y = y;
}
+
+ host_view->ModifyEventForEdgeDragging(widget, event);
host_view->GetRenderWidgetHost()->ForwardMouseEvent(
WebInputEventFactory::mouseEvent(event));
return FALSE;
@@ -333,7 +369,7 @@ class RenderWidgetHostViewGtkWidget {
command_line->GetSwitchValueASCII(switches::kScrollPixels);
if (!scroll_pixels_option.empty()) {
double v;
- if (StringToDouble(scroll_pixels_option, &v))
+ if (base::StringToDouble(scroll_pixels_option, &v))
scroll_pixels = static_cast<float>(v);
}
DCHECK_GT(scroll_pixels, 0);
@@ -443,7 +479,9 @@ RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host)
parent_(NULL),
is_popup_first_mouse_release_(true),
was_focused_before_grab_(false),
- do_x_grab_(false) {
+ do_x_grab_(false),
+ dragged_at_horizontal_edge_(0),
+ dragged_at_vertical_edge_(0) {
host_->set_view(this);
// Enable experimental out-of-process GPU rendering.
@@ -473,69 +511,12 @@ void RenderWidgetHostViewGtk::InitAsChild() {
void RenderWidgetHostViewGtk::InitAsPopup(
RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
- parent_host_view_ = parent_host_view;
- parent_ = parent_host_view->GetNativeView();
- GtkWidget* popup = gtk_window_new(GTK_WINDOW_POPUP);
- view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this));
- // |im_context_| must be created after creating |view_| widget.
- im_context_.reset(new GtkIMContextWrapper(this));
- // |key_bindings_handler_| must be created after creating |view_| widget.
- key_bindings_handler_.reset(new GtkKeyBindingsHandler(view_.get()));
- plugin_container_manager_.set_host_widget(view_.get());
-
-#if defined(OS_CHROMEOS)
- tooltip_window_.reset(new views::TooltipWindowGtk(view_.get()));
-#endif // defined(OS_CHROMEOS)
-
- gtk_container_add(GTK_CONTAINER(popup), view_.get());
-
- // If we are not activatable, we don't want to grab keyboard input,
- // and webkit will manage our destruction.
- if (NeedsInputGrab()) {
- // Grab all input for the app. If a click lands outside the bounds of the
- // popup, WebKit will notice and destroy us. Before doing this we need
- // to ensure that the the popup is added to the browser's window group,
- // to allow for the grabs to work correctly.
- gtk_window_group_add_window(gtk_window_get_group(
- GTK_WINDOW(gtk_widget_get_toplevel(parent_))), GTK_WINDOW(popup));
- gtk_grab_add(view_.get());
-
- // We need for the application to do an X grab as well. However if the app
- // already has an X grab (as in the case of extension popup), an app grab
- // will suffice.
- do_x_grab_ = !gdk_pointer_is_grabbed();
-
- // Now grab all of X's input.
- if (do_x_grab_) {
- gdk_pointer_grab(
- parent_->window,
- TRUE, // Only events outside of the window are reported with respect
- // to |parent_->window|.
- static_cast<GdkEventMask>(GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK),
- NULL,
- NULL,
- GDK_CURRENT_TIME);
- // We grab keyboard events too so things like alt+tab are eaten.
- gdk_keyboard_grab(parent_->window, TRUE, GDK_CURRENT_TIME);
- }
- }
-
- requested_size_ = gfx::Size(std::min(pos.width(), kMaxWindowWidth),
- std::min(pos.height(), kMaxWindowHeight));
- host_->WasResized();
- gtk_widget_set_size_request(view_.get(), requested_size_.width(),
- requested_size_.height());
-
- gtk_window_set_default_size(GTK_WINDOW(popup), -1, -1);
- // Don't allow the window to be resized. This also forces the window to
- // shrink down to the size of its child contents.
- gtk_window_set_resizable(GTK_WINDOW(popup), FALSE);
- gtk_window_move(GTK_WINDOW(popup), pos.x(), pos.y());
- gtk_widget_show_all(popup);
+ DoInitAsPopup(parent_host_view, GTK_WINDOW_POPUP, pos, false);
+}
- // TODO(brettw) possibly enable out-of-process painting here as well
- // (see InitAsChild).
+void RenderWidgetHostViewGtk::InitAsFullscreen(
+ RenderWidgetHostView* parent_host_view) {
+ DoInitAsPopup(parent_host_view, GTK_WINDOW_TOPLEVEL, gfx::Rect(), true);
}
void RenderWidgetHostViewGtk::DidBecomeSelected() {
@@ -740,17 +721,21 @@ void RenderWidgetHostViewGtk::SetTooltipText(const std::wstring& tooltip_text) {
}
void RenderWidgetHostViewGtk::SelectionChanged(const std::string& text) {
- GtkClipboard* x_clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
- gtk_clipboard_set_text(x_clipboard, text.c_str(), text.length());
+ if (!text.empty()) {
+ GtkClipboard* x_clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
+ gtk_clipboard_set_text(x_clipboard, text.c_str(), text.length());
+ }
}
void RenderWidgetHostViewGtk::ShowingContextMenu(bool showing) {
is_showing_context_menu_ = showing;
}
+#if !defined(TOOLKIT_VIEWS)
void RenderWidgetHostViewGtk::AppendInputMethodsContextMenu(MenuGtk* menu) {
im_context_->AppendInputMethodsContextMenu(menu);
}
+#endif
bool RenderWidgetHostViewGtk::NeedsInputGrab() {
return popup_type_ == WebKit::WebPopupTypeSelect;
@@ -799,6 +784,58 @@ void RenderWidgetHostViewGtk::SetBackground(const SkBitmap& background) {
host_->Send(new ViewMsg_SetBackground(host_->routing_id(), background));
}
+void RenderWidgetHostViewGtk::ModifyEventForEdgeDragging(
+ GtkWidget* widget, GdkEventMotion* event) {
+ // If the widget is aligned with an edge of the monitor its on and the user
+ // attempts to drag past that edge we track the number of times it has
+ // occurred, so that we can force the widget to scroll when it otherwise
+ // would be unable to, by modifying the (x,y) position in the drag
+ // event that we forward on to webkit. If we get a move that's no longer a
+ // drag or a drag indicating the user is no longer at that edge we stop
+ // altering the drag events.
+ int new_dragged_at_horizontal_edge = 0;
+ int new_dragged_at_vertical_edge = 0;
+ // Used for checking the edges of the monitor. We cache the values to save
+ // roundtrips to the X server.
+ static gfx::Size drag_monitor_size;
+ if (event->state & GDK_BUTTON1_MASK) {
+ if (drag_monitor_size.IsEmpty()) {
+ // We can safely cache the monitor size for the duration of a drag.
+ GdkScreen* screen = gtk_widget_get_screen(widget);
+ int monitor =
+ gdk_screen_get_monitor_at_point(screen, event->x_root, event->y_root);
+ GdkRectangle geometry;
+ gdk_screen_get_monitor_geometry(screen, monitor, &geometry);
+ drag_monitor_size.SetSize(geometry.width, geometry.height);
+ }
+
+ // Check X and Y independently, as the user could be dragging into a corner.
+ if (event->x == 0 && event->x_root == 0) {
+ new_dragged_at_horizontal_edge = dragged_at_horizontal_edge_ - 1;
+ } else if (widget->allocation.width - 1 == static_cast<gint>(event->x) &&
+ drag_monitor_size.width() - 1 == static_cast<gint>(event->x_root)) {
+ new_dragged_at_horizontal_edge = dragged_at_horizontal_edge_ + 1;
+ }
+
+ if (event->y == 0 && event->y_root == 0) {
+ new_dragged_at_vertical_edge = dragged_at_vertical_edge_ - 1;
+ } else if (widget->allocation.height - 1 == static_cast<gint>(event->y) &&
+ drag_monitor_size.height() - 1 == static_cast<gint>(event->y_root)) {
+ new_dragged_at_vertical_edge = dragged_at_vertical_edge_ + 1;
+ }
+
+ event->x_root += new_dragged_at_horizontal_edge;
+ event->x += new_dragged_at_horizontal_edge;
+ event->y_root += new_dragged_at_vertical_edge;
+ event->y += new_dragged_at_vertical_edge;
+ } else {
+ // Clear whenever we get a non-drag mouse move.
+ drag_monitor_size.SetSize(0, 0);
+ }
+ dragged_at_horizontal_edge_ = new_dragged_at_horizontal_edge;
+ dragged_at_vertical_edge_ = new_dragged_at_vertical_edge;
+}
+
void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
if (enable_gpu_rendering_) {
// When we're proxying painting, we don't actually display the web page
@@ -937,6 +974,94 @@ void RenderWidgetHostViewGtk::ShowCurrentCursor() {
gdk_cursor_unref(gdk_cursor);
}
+void RenderWidgetHostViewGtk::DoInitAsPopup(
+ RenderWidgetHostView* parent_host_view,
+ GtkWindowType window_type,
+ const gfx::Rect& pos,
+ bool is_fullscreen) {
+ // If we are not a popup, then popup will be leaked.
+ DCHECK(IsPopup());
+
+ parent_host_view_ = parent_host_view;
+ parent_ = parent_host_view->GetNativeView();
+ GtkWidget* popup = gtk_window_new(window_type);
+ gtk_window_set_decorated(GTK_WINDOW(popup), FALSE);
+ view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this));
+ // |im_context_| must be created after creating |view_| widget.
+ im_context_.reset(new GtkIMContextWrapper(this));
+ // |key_bindings_handler_| must be created after creating |view_| widget.
+ key_bindings_handler_.reset(new GtkKeyBindingsHandler(view_.get()));
+ plugin_container_manager_.set_host_widget(view_.get());
+
+#if defined(OS_CHROMEOS)
+ tooltip_window_.reset(new views::TooltipWindowGtk(view_.get()));
+#endif // defined(OS_CHROMEOS)
+
+ gtk_container_add(GTK_CONTAINER(popup), view_.get());
+
+ if (is_fullscreen) {
+ // Set the request size to the size of the screen.
+ // TODO(boliu): Make sure this works for multi-monitor set ups and move this
+ // to some utility function.
+ GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(popup));
+ requested_size_ = gfx::Size(
+ std::min(gdk_screen_get_width(screen), kMaxWindowWidth),
+ std::min(gdk_screen_get_height(screen), kMaxWindowHeight));
+ } else {
+ requested_size_ = gfx::Size(std::min(pos.width(), kMaxWindowWidth),
+ std::min(pos.height(), kMaxWindowHeight));
+ }
+ host_->WasResized();
+
+ gtk_widget_set_size_request(view_.get(), requested_size_.width(),
+ requested_size_.height());
+ // Don't allow the window to be resized. This also forces the window to
+ // shrink down to the size of its child contents.
+ gtk_window_set_resizable(GTK_WINDOW(popup), FALSE);
+ gtk_window_set_default_size(GTK_WINDOW(popup), -1, -1);
+ gtk_window_move(GTK_WINDOW(popup), pos.x(), pos.y());
+ if (is_fullscreen) {
+ gtk_window_fullscreen(GTK_WINDOW(popup));
+ }
+
+ gtk_widget_show_all(popup);
+
+ // If we are not activatable, we don't want to grab keyboard input,
+ // and webkit will manage our destruction.
+ // For unknown reason, calling gtk_grab_add() before realizing the widget may
+ // cause an assertion failure. See http://crbug.com/51834. So we do it after
+ // showing the popup.
+ if (NeedsInputGrab()) {
+ // Grab all input for the app. If a click lands outside the bounds of the
+ // popup, WebKit will notice and destroy us. Before doing this we need
+ // to ensure that the the popup is added to the browser's window group,
+ // to allow for the grabs to work correctly.
+ gtk_window_group_add_window(gtk_window_get_group(
+ GTK_WINDOW(gtk_widget_get_toplevel(parent_))), GTK_WINDOW(popup));
+ gtk_grab_add(view_.get());
+
+ // We need for the application to do an X grab as well. However if the app
+ // already has an X grab (as in the case of extension popup), an app grab
+ // will suffice.
+ do_x_grab_ = !gdk_pointer_is_grabbed();
+
+ // Now grab all of X's input.
+ if (do_x_grab_) {
+ gdk_pointer_grab(
+ parent_->window,
+ TRUE, // Only events outside of the window are reported with respect
+ // to |parent_->window|.
+ static_cast<GdkEventMask>(GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK),
+ NULL,
+ NULL,
+ GDK_CURRENT_TIME);
+ // We grab keyboard events too so things like alt+tab are eaten.
+ gdk_keyboard_grab(parent_->window, TRUE, GDK_CURRENT_TIME);
+ }
+ }
+}
+
void RenderWidgetHostViewGtk::CreatePluginContainer(
gfx::PluginWindowHandle id) {
plugin_container_manager_.CreatePluginContainer(id);
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 f33cd55..099da46 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
@@ -4,18 +4,19 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_GTK_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_GTK_H_
+#pragma once
#include <gdk/gdk.h>
-#include <map>
#include <vector>
#include <string>
#include "base/scoped_ptr.h"
#include "base/time.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/common/owned_widget_gtk.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"
@@ -23,7 +24,9 @@ class RenderWidgetHost;
class GpuViewHost;
class GtkIMContextWrapper;
class GtkKeyBindingsHandler;
+#if !defined(TOOLKIT_VIEWS)
class MenuGtk;
+#endif
struct NativeWebKeyboardEvent;
#if defined(OS_CHROMEOS)
@@ -49,6 +52,7 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// RenderWidgetHostView implementation.
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 void DidBecomeSelected();
virtual void WasHidden();
@@ -87,6 +91,11 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
gfx::NativeView native_view() const { return view_.get(); }
+ // If the widget is aligned with an edge of the monitor its on and the user
+ // attempts to drag past that edge we track the number of times it has
+ // occurred, so that we can force the widget to scroll when it otherwise
+ // would be unable to.
+ void ModifyEventForEdgeDragging(GtkWidget* widget, GdkEventMotion* event);
void Paint(const gfx::Rect&);
// Called by GtkIMContextWrapper to forward a keyboard event to renderer.
@@ -96,9 +105,11 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// RenderWidgetHost::ForwardEditCommandsForNextKeyEvent().
void ForwardKeyboardEvent(const NativeWebKeyboardEvent& event);
+#if !defined(TOOLKIT_VIEWS)
// Appends the input methods context menu to the specified |menu| object as a
// submenu.
void AppendInputMethodsContextMenu(MenuGtk* menu);
+#endif
private:
friend class RenderWidgetHostViewGtkWidget;
@@ -114,6 +125,13 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// Update the display cursor for the render view.
void ShowCurrentCursor();
+ // Helper method for InitAsPopup() and InitAsFullscreen().
+ void DoInitAsPopup(
+ RenderWidgetHostView* parent_host_view,
+ GtkWindowType window_type,
+ const gfx::Rect& pos, // Ignored if is_fullscreen is true.
+ bool is_fullscreen);
+
// The model object.
RenderWidgetHost* host_;
@@ -189,6 +207,16 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
// variable because resizing in GTK+ is async.
gfx::Size requested_size_;
+ // The number of times the user has dragged against horizontal edge of the
+ // monitor (if the widget is aligned with that edge). Negative values
+ // indicate the left edge, positive the right.
+ int dragged_at_horizontal_edge_;
+
+ // The number of times the user has dragged against vertical edge of the
+ // monitor (if the widget is aligned with that edge). Negative values
+ // indicate the top edge, positive the bottom.
+ int dragged_at_vertical_edge_;
+
#if defined(OS_CHROMEOS)
// Custimized tooltip window.
scoped_ptr<views::TooltipWindowGtk> tooltip_window_;
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 74f2092..41b4316 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_MAC_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#import <QuartzCore/CALayer.h>
@@ -22,6 +23,7 @@
#include "webkit/glue/webcursor.h"
#include "webkit/glue/webmenuitem.h"
+@class AcceleratedPluginView;
class RenderWidgetHostViewMac;
class RWHVMEditCommandHelper;
@class ToolTip;
@@ -61,9 +63,6 @@ class RWHVMEditCommandHelper;
NSWindow* lastWindow_; // weak
- // The Core Animation layer, if any, hosting the accelerated plugins' output.
- scoped_nsobject<CALayer> acceleratedPluginLayer_;
-
// Variables used by our implementaion of the NSTextInput protocol.
// An input method of Mac calls the methods of this protocol not only to
// notify an application of its status, but also to retrieve the status of
@@ -131,12 +130,6 @@ class RWHVMEditCommandHelper;
- (void)setCanBeKeyView:(BOOL)can;
- (void)setCloseOnDeactivate:(BOOL)b;
- (void)setToolTipAtMousePoint:(NSString *)string;
-// Makes sure that the initial layer setup for accelerated plugin drawing has
-// been done. Can be called multiple times.
-- (void)ensureAcceleratedPluginLayer;
-// Triggers a refresh of the accelerated plugin layer; should be called whenever
-// the shared surface for one of the plugins is updated.
-- (void)drawAcceleratedPluginLayer;
// Set frame, then notify the RenderWidgetHost that the frame has been changed,
// but do it in a separate task, using |performSelector:withObject:afterDelay:|.
// This stops the flickering issue in http://crbug.com/31970
@@ -181,6 +174,7 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
// Implementation of RenderWidgetHostView:
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos);
+ virtual void InitAsFullscreen(RenderWidgetHostView* parent_host_view);
virtual RenderWidgetHost* GetRenderWidgetHost() const;
virtual void DidBecomeSelected();
virtual void WasHidden();
@@ -207,6 +201,7 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {};
virtual void Destroy();
virtual void SetTooltipText(const std::wstring& tooltip_text);
+ virtual void SelectionChanged(const std::string& text);
virtual BackingStore* AllocBackingStore(const gfx::Size& size);
virtual VideoLayer* AllocVideoLayer(const gfx::Size& size);
virtual void ShowPopupWithItems(gfx::Rect bounds,
@@ -224,10 +219,10 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
virtual bool ContainsNativeView(gfx::NativeView native_view) const;
virtual void UpdateAccessibilityTree(
const webkit_glue::WebAccessibility& tree);
- virtual void OnAccessibilityFocusChange(int acc_obj_id);
- virtual void OnAccessibilityObjectStateChange(int acc_obj_id);
- // Methods associated with GPU-accelerated plug-in instances.
- virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque);
+ // Methods associated with GPU-accelerated plug-in instances and the
+ // accelerated compositor.
+ virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque,
+ bool root);
virtual void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window);
virtual void AcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window,
int32 width,
@@ -239,10 +234,14 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
int32 height,
TransportDIB::Handle transport_dib);
virtual void AcceleratedSurfaceBuffersSwapped(gfx::PluginWindowHandle window);
- // Draws the current GPU-accelerated plug-in instances into the given context.
- virtual void DrawAcceleratedSurfaceInstances(CGLContextObj context);
- // Informs the plug-in instances that their drawing context has changed.
- virtual void AcceleratedSurfaceContextChanged();
+ virtual void GpuRenderingStateDidChange();
+ void DrawAcceleratedSurfaceInstance(
+ CGLContextObj context,
+ gfx::PluginWindowHandle plugin_handle,
+ NSSize size);
+ // Forces the textures associated with any accelerated plugin instances
+ // to be reloaded.
+ void ForceTextureReload();
virtual void SetVisuallyDeemphasized(bool deemphasized);
@@ -252,6 +251,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
void SetTextInputActive(bool active);
+ const std::string& selected_text() const { return selected_text_; }
+
// These member variables should be private, but the associated ObjC class
// needs access to them and can't be made a friend.
@@ -284,6 +285,13 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
// Current text input type.
WebKit::WebTextInputType text_input_type_;
+ typedef std::map<gfx::PluginWindowHandle, AcceleratedPluginView*>
+ PluginViewMap;
+ PluginViewMap plugin_views_; // Weak values.
+
+ // Helper class for managing instances of accelerated plug-ins.
+ AcceleratedSurfaceContainerManagerMac plugin_container_manager_;
+
private:
// Updates the display cursor to the current cursor if the cursor is over this
// render view.
@@ -293,6 +301,9 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
// invoke it from the message loop.
void ShutdownHost();
+ // Used to determine whether or not to enable accessibility.
+ bool IsVoiceOverRunning();
+
// The associated view. This is weak and is inserted into the view hierarchy
// to own this RenderWidgetHostViewMac object unless is_popup_menu_ is true.
// In that case, cocoa_view_ is never inserted into the view hierarchy, so
@@ -323,12 +334,12 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
// Used for positioning a popup menu.
NSView* parent_view_;
- // Helper class for managing instances of accelerated plug-ins.
- AcceleratedSurfaceContainerManagerMac plugin_container_manager_;
-
// Whether or not web accessibility is enabled.
bool renderer_accessible_;
+ // selected text on the renderer.
+ std::string selected_text_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac);
};
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 724d7bb..a878ccc 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -6,10 +6,13 @@
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#include "chrome/browser/chrome_thread.h"
#include "app/surface/io_surface_support_mac.h"
#import "base/chrome_application_mac.h"
+#include "base/command_line.h"
#include "base/histogram.h"
#include "base/logging.h"
+#import "base/scoped_nsautorelease_pool.h"
#import "base/scoped_nsobject.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
@@ -31,6 +34,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/glue/webmenurunner_mac.h"
using WebKit::WebInputEvent;
@@ -126,51 +131,245 @@ void DisablePasswordInput() {
} // namespace
-// AcceleratedPluginLayer ------------------------------------------------------
+// AcceleratedPluginView ------------------------------------------------------
-// This subclass of CAOpenGLLayer hosts the output of accelerated plugins on
+// This subclass of NSView hosts the output of accelerated plugins on
// the page.
-@interface AcceleratedPluginLayer : CAOpenGLLayer {
+// Informal protocol implemented by windows that need to be informed explicitly
+// about underlay surfaces.
+@interface NSObject (UnderlayableSurface)
+- (void)underlaySurfaceAdded;
+- (void)underlaySurfaceRemoved;
+@end
+
+@interface AcceleratedPluginView : NSView {
+ scoped_nsobject<NSOpenGLPixelFormat> glPixelFormat_;
+ CGLPixelFormatObj cglPixelFormat_; // weak, backed by |glPixelFormat_|.
+ scoped_nsobject<NSOpenGLContext> glContext_;
+ CGLContextObj cglContext_; // weak, backed by |glContext_|.
+
+ CVDisplayLinkRef displayLink_; // Owned by us.
+
RenderWidgetHostViewMac* renderWidgetHostView_; // weak
+ gfx::PluginWindowHandle pluginHandle_; // weak
+
+ // True if the backing IO surface was updated since we last painted.
+ BOOL surfaceWasSwapped_;
+
+ // Cocoa methods can only be called on the main thread, so have a copy of the
+ // view's size, since it's required on the displaylink thread.
+ NSSize cachedSize_;
+
+ // -globalFrameDidChange: can be called recursively, this counts how often it
+ // holds the CGL lock.
+ int globalFrameDidChangeCGLLockCount_;
}
-- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r;
+- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r
+ pluginHandle:(gfx::PluginWindowHandle)pluginHandle;
+- (void)drawView;
+
+// This _must_ be atomic, since it's accessed from several threads.
+@property BOOL surfaceWasSwapped;
+
+// This _must_ be atomic, since it's accessed from several threads.
+@property NSSize cachedSize;
@end
-@implementation AcceleratedPluginLayer
-- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r {
- self = [super init];
- if (self != nil) {
+@implementation AcceleratedPluginView
+@synthesize surfaceWasSwapped = surfaceWasSwapped_;
+@synthesize cachedSize = cachedSize_;
+
+- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime {
+ // There is no autorelease pool when this method is called because it will be
+ // called from a background thread.
+ base::ScopedNSAutoreleasePool pool;
+
+ if (![self surfaceWasSwapped])
+ return kCVReturnSuccess;
+
+ [self drawView];
+ [self setSurfaceWasSwapped:NO];
+ return kCVReturnSuccess;
+}
+
+// This is the renderer output callback function
+static CVReturn DrawOneAcceleratedPluginCallback(
+ CVDisplayLinkRef displayLink,
+ const CVTimeStamp* now,
+ const CVTimeStamp* outputTime,
+ CVOptionFlags flagsIn,
+ CVOptionFlags* flagsOut,
+ void* displayLinkContext) {
+ CVReturn result =
+ [(AcceleratedPluginView*)displayLinkContext getFrameForTime:outputTime];
+ return result;
+}
+
+- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r
+ pluginHandle:(gfx::PluginWindowHandle)pluginHandle {
+ if ((self = [super initWithFrame:NSZeroRect])) {
renderWidgetHostView_ = r;
+ pluginHandle_ = pluginHandle;
+ cachedSize_ = NSZeroSize;
+
+ [self setAutoresizingMask:NSViewMaxXMargin|NSViewMinYMargin];
+
+ NSOpenGLPixelFormatAttribute attributes[] =
+ { NSOpenGLPFAAccelerated, NSOpenGLPFADoubleBuffer, 0};
+
+ glPixelFormat_.reset([[NSOpenGLPixelFormat alloc]
+ initWithAttributes:attributes]);
+ glContext_.reset([[NSOpenGLContext alloc] initWithFormat:glPixelFormat_
+ shareContext:nil]);
+
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHolePunching)) {
+ // We "punch a hole" in the window, and have the WindowServer render the
+ // OpenGL surface underneath so we can draw over it.
+ GLint belowWindow = -1;
+ [glContext_ setValues:&belowWindow forParameter:NSOpenGLCPSurfaceOrder];
+ }
+
+ cglContext_ = (CGLContextObj)[glContext_ CGLContextObj];
+ cglPixelFormat_ = (CGLPixelFormatObj)[glPixelFormat_ CGLPixelFormatObj];
+
+ // Draw at beam vsync.
+ GLint swapInterval = 1;
+ [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
+
+ // Set up a display link to do OpenGL rendering on a background thread.
+ CVDisplayLinkCreateWithActiveCGDisplays(&displayLink_);
}
return self;
}
-- (void)drawInCGLContext:(CGLContextObj)glContext
- pixelFormat:(CGLPixelFormatObj)pixelFormat
- forLayerTime:(CFTimeInterval)timeInterval
- displayTime:(const CVTimeStamp *)timeStamp {
- renderWidgetHostView_->DrawAcceleratedSurfaceInstances(glContext);
- [super drawInCGLContext:glContext
- pixelFormat:pixelFormat
- forLayerTime:timeInterval
- displayTime:timeStamp];
-}
-
-- (void)setFrame:(CGRect)rect {
- // The frame we get when the superlayer resizes doesn't make sense, so ignore
- // it and just match the superlayer's size. See the email thread referenced in
- // ensureAcceleratedPluginLayer for an explanation of why the superlayer
- // isn't trustworthy.
- [CATransaction begin];
- [CATransaction setValue:[NSNumber numberWithInt:0]
- forKey:kCATransactionAnimationDuration];
- if ([self superlayer])
- [super setFrame:[[self superlayer] bounds]];
- else
- [super setFrame:rect];
- [CATransaction commit];
+- (void)dealloc {
+ CVDisplayLinkRelease(displayLink_);
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)drawView {
+ // Called on a background thread. Synchronized via the CGL context lock.
+ CGLLockContext(cglContext_);
+
+ // TODO(thakis): Pixel or view coordinates for size?
+ renderWidgetHostView_->DrawAcceleratedSurfaceInstance(
+ cglContext_, pluginHandle_, [self cachedSize]);
+
+ CGLFlushDrawable(cglContext_);
+ CGLUnlockContext(cglContext_);
+}
+
+- (void)drawRect:(NSRect)rect {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHolePunching)) {
+ const NSRect* dirtyRects;
+ int dirtyRectCount;
+ [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
+
+ // Punch a hole so that the OpenGL view shows through.
+ [[NSColor clearColor] set];
+ NSRectFillList(dirtyRects, dirtyRectCount);
+ }
+
+ [self drawView];
+}
+
+- (void)rightMouseDown:(NSEvent*)event {
+ // The NSResponder documentation: "Note: The NSView implementation of this
+ // method does not pass the message up the responder chain, it handles it
+ // directly."
+ // That's bad, we want the next responder (RWHVMac) to handle this event to
+ // dispatch it to the renderer.
+ [[self nextResponder] rightMouseDown:event];
+}
+
+- (void)globalFrameDidChange:(NSNotification*)notification {
+ globalFrameDidChangeCGLLockCount_++;
+ CGLLockContext(cglContext_);
+ // This call to -update can call -globalFrameDidChange: again, see
+ // http://crbug.com/55754 comments 22 and 24.
+ [glContext_ update];
+
+ // You would think that -update updates the viewport. You would be wrong.
+ CGLSetCurrentContext(cglContext_);
+ NSSize size = [self frame].size;
+ glViewport(0, 0, size.width, size.height);
+
+ CGLUnlockContext(cglContext_);
+ globalFrameDidChangeCGLLockCount_--;
+
+ if (globalFrameDidChangeCGLLockCount_ == 0) {
+ // Make sure the view is synchronized with the correct display.
+ CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
+ displayLink_, cglContext_, cglPixelFormat_);
+ }
+}
+
+- (void)renewGState {
+ // Synchronize with window server to avoid flashes or corrupt drawing.
+ [[self window] disableScreenUpdatesUntilFlush];
+ [self globalFrameDidChange:nil];
+ [super renewGState];
+}
+
+- (void)lockFocus {
+ [super lockFocus];
+
+ // If we're using OpenGL, make sure it is connected and that the display link
+ // is running.
+ if ([glContext_ view] != self) {
+ [glContext_ setView:self];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(globalFrameDidChange:)
+ name:NSViewGlobalFrameDidChangeNotification
+ object:self];
+ CVDisplayLinkSetOutputCallback(
+ displayLink_, &DrawOneAcceleratedPluginCallback, self);
+ CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
+ displayLink_, cglContext_, cglPixelFormat_);
+ CVDisplayLinkStart(displayLink_);
+ }
+ [glContext_ makeCurrentContext];
+}
+
+- (void)viewWillMoveToWindow:(NSWindow*)newWindow {
+ // Stop the display link thread while the view is not visible.
+ if (newWindow) {
+ if (displayLink_ && !CVDisplayLinkIsRunning(displayLink_))
+ CVDisplayLinkStart(displayLink_);
+ } else {
+ if (displayLink_ && CVDisplayLinkIsRunning(displayLink_))
+ CVDisplayLinkStop(displayLink_);
+ }
+
+ // If hole punching is enabled, inform the window hosting this accelerated
+ // view that it needs to be opaque.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHolePunching)) {
+ if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) {
+ [static_cast<id>([self window]) underlaySurfaceRemoved];
+ }
+
+ if ([newWindow respondsToSelector:@selector(underlaySurfaceAdded)]) {
+ [static_cast<id>(newWindow) underlaySurfaceAdded];
+ }
+ }
+}
+
+- (void)setFrame:(NSRect)frameRect {
+ [self setCachedSize:frameRect.size];
+ [super setFrame:frameRect];
+}
+
+- (void)setFrameSize:(NSSize)newSize {
+ [self setCachedSize:newSize];
+ [super setFrameSize:newSize];
}
@end
@@ -212,8 +411,10 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
initWithRenderWidgetHostViewMac:this] autorelease];
render_widget_host_->set_view(this);
- renderer_accessible_ = !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableRendererAccessibility);
+ // Turn on accessibility only if one or both of these flags is true.
+ renderer_accessible_ = IsVoiceOverRunning() ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kForceRendererAccessibility);
}
RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
@@ -246,6 +447,11 @@ void RenderWidgetHostViewMac::InitAsPopup(
[cocoa_view_ setFrame:initial_frame];
}
+void RenderWidgetHostViewMac::InitAsFullscreen(
+ RenderWidgetHostView* parent_host_view) {
+ NOTIMPLEMENTED() << "Full screen not implemented on Mac";
+}
+
RenderWidgetHost* RenderWidgetHostViewMac::GetRenderWidgetHost() const {
return render_widget_host_;
}
@@ -293,10 +499,11 @@ void RenderWidgetHostViewMac::SetSize(const gfx::Size& size) {
// superview is another RenderWidgetHostViewCocoa, but even if it's directly
// in a TabContentsViewCocoa, they're both BaseViews.
gfx::Rect rect =
- [(BaseView*)[cocoa_view_ superview] NSRectToRect:[cocoa_view_ frame]];
+ [(BaseView*)[cocoa_view_ superview] flipNSRectToRect:[cocoa_view_ frame]];
rect.set_width(size.width());
rect.set_height(size.height());
- [cocoa_view_ setFrame:[(BaseView*)[cocoa_view_ superview] RectToNSRect:rect]];
+ [cocoa_view_ setFrame:
+ [(BaseView*)[cocoa_view_ superview] flipRectToNSRect:rect]];
}
gfx::NativeView RenderWidgetHostViewMac::GetNativeView() {
@@ -305,23 +512,44 @@ gfx::NativeView RenderWidgetHostViewMac::GetNativeView() {
void RenderWidgetHostViewMac::MovePluginWindows(
const std::vector<webkit_glue::WebPluginGeometry>& moves) {
+ CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
// Handle movement of accelerated plugins, which are the only "windowed"
// plugins that exist on the Mac.
- if (moves.size() > 0) {
- for (std::vector<webkit_glue::WebPluginGeometry>::const_iterator iter =
- moves.begin();
- iter != moves.end();
- ++iter) {
- webkit_glue::WebPluginGeometry geom = *iter;
- // Ignore bogus moves which claim to move the plugin to (0, 0)
- // with width and height (0, 0)
- if (geom.window_rect.x() != 0 ||
- geom.window_rect.y() != 0 ||
- geom.window_rect.width() != 0 ||
- geom.window_rect.height() != 0) {
- plugin_container_manager_.MovePluginContainer(geom);
- }
+ for (std::vector<webkit_glue::WebPluginGeometry>::const_iterator iter =
+ moves.begin();
+ iter != moves.end();
+ ++iter) {
+ webkit_glue::WebPluginGeometry geom = *iter;
+ // Ignore bogus moves which claim to move the plugin to (0, 0)
+ // with width and height (0, 0)
+ if (geom.window_rect.x() == 0 &&
+ geom.window_rect.y() == 0 &&
+ geom.window_rect.IsEmpty()) {
+ continue;
+ }
+
+ gfx::Rect rect = geom.window_rect;
+ if (geom.visible) {
+ rect.set_x(rect.x() + geom.clip_rect.x());
+ rect.set_y(rect.y() + geom.clip_rect.y());
+ rect.set_width(geom.clip_rect.width());
+ rect.set_height(geom.clip_rect.height());
+ }
+
+ PluginViewMap::iterator it = plugin_views_.find(geom.window);
+ DCHECK(plugin_views_.end() != it);
+ if (plugin_views_.end() == it) {
+ continue;
}
+ NSRect new_rect([cocoa_view_ flipRectToNSRect:rect]);
+ [it->second setFrame:new_rect];
+ [it->second setNeedsDisplay:YES];
+
+ plugin_container_manager_.SetPluginContainerGeometry(geom);
+
+ BOOL visible =
+ plugin_container_manager_.SurfaceShouldBeVisible(geom.window);
+ [it->second setHidden:!visible];
}
}
@@ -354,7 +582,7 @@ bool RenderWidgetHostViewMac::IsShowing() {
}
gfx::Rect RenderWidgetHostViewMac::GetViewBounds() const {
- return [cocoa_view_ NSRectToRect:[cocoa_view_ bounds]];
+ return [cocoa_view_ flipNSRectToRect:[cocoa_view_ bounds]];
}
void RenderWidgetHostViewMac::UpdateCursor(const WebCursor& cursor) {
@@ -400,7 +628,7 @@ void RenderWidgetHostViewMac::ImeUpdateTextInputState(
// whose origin is the upper-left corner of this view. On the other hand,
// Cocoa uses a coordinate system whose origin is the lower-left corner of
// this view. So, we convert the cursor rectangle and save it.
- [cocoa_view_ setCaretRect:[cocoa_view_ RectToNSRect:caret_rect]];
+ [cocoa_view_ setCaretRect:[cocoa_view_ flipRectToNSRect:caret_rect]];
}
void RenderWidgetHostViewMac::ImeCancelComposition() {
@@ -421,7 +649,7 @@ void RenderWidgetHostViewMac::DidUpdateBackingStore(
rects.push_back(scroll_rect);
for (size_t i = 0; i < rects.size(); ++i) {
- NSRect ns_rect = [cocoa_view_ RectToNSRect:rects[i]];
+ NSRect ns_rect = [cocoa_view_ flipRectToNSRect:rects[i]];
if (about_to_validate_and_paint_) {
// As much as we'd like to use -setNeedsDisplayInRect: here, we can't.
@@ -469,8 +697,12 @@ void RenderWidgetHostViewMac::Destroy() {
if (!is_popup_menu_) {
// Depth-first destroy all popups. Use ShutdownHost() to enforce
// deepest-first ordering.
- for (RenderWidgetHostViewCocoa* subview in [cocoa_view_ subviews]) {
- [subview renderWidgetHostViewMac]->ShutdownHost();
+ for (NSView* subview in [cocoa_view_ subviews]) {
+ if (![subview isKindOfClass:[RenderWidgetHostViewCocoa class]])
+ continue; // Skip accelerated views.
+
+ [static_cast<RenderWidgetHostViewCocoa*>(subview)
+ renderWidgetHostViewMac]->ShutdownHost();
}
// We've been told to destroy.
@@ -519,6 +751,14 @@ void RenderWidgetHostViewMac::SetTooltipText(const std::wstring& tooltip_text) {
}
}
+//
+// RenderWidgetHostViewCocoa uses the stored selection text,
+// which implements NSServicesRequests protocol.
+//
+void RenderWidgetHostViewMac::SelectionChanged(const std::string& text) {
+ selected_text_ = text;
+}
+
BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
const gfx::Size& size) {
return new BackingStoreMac(render_widget_host_, size);
@@ -612,15 +852,34 @@ void RenderWidgetHostViewMac::KillSelf() {
}
gfx::PluginWindowHandle
-RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque) {
- // Make sure we have a layer for the plugin to draw into.
- [cocoa_view_ ensureAcceleratedPluginLayer];
+RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque,
+ bool root) {
+ CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ // Create an NSView to host the plugin's/compositor's pixels.
+ gfx::PluginWindowHandle handle =
+ plugin_container_manager_.AllocateFakePluginWindowHandle(opaque, root);
- return plugin_container_manager_.AllocateFakePluginWindowHandle(opaque);
+ scoped_nsobject<AcceleratedPluginView> plugin_view(
+ [[AcceleratedPluginView alloc] initWithRenderWidgetHostViewMac:this
+ pluginHandle:handle]);
+ [plugin_view setHidden:YES];
+
+ [cocoa_view_ addSubview:plugin_view];
+ plugin_views_[handle] = plugin_view;
+
+ return handle;
}
void RenderWidgetHostViewMac::DestroyFakePluginWindowHandle(
gfx::PluginWindowHandle window) {
+ CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ PluginViewMap::iterator it = plugin_views_.find(window);
+ DCHECK(plugin_views_.end() != it);
+ if (plugin_views_.end() == it) {
+ return;
+ }
+ [it->second removeFromSuperview];
+ plugin_views_.erase(it);
plugin_container_manager_.DestroyFakePluginWindowHandle(window);
}
@@ -629,10 +888,24 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetIOSurface(
int32 width,
int32 height,
uint64 io_surface_identifier) {
+ CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
plugin_container_manager_.SetSizeAndIOSurface(window,
width,
height,
io_surface_identifier);
+
+ if (plugin_container_manager_.IsRootContainer(window)) {
+ // 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;
+ gfx::Rect rect(0, 0, width, height);
+ geom.window = window;
+ geom.window_rect = rect;
+ geom.clip_rect = rect;
+ geom.visible = true;
+ MovePluginWindows(std::vector<webkit_glue::WebPluginGeometry>(1, geom));
+ }
}
void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB(
@@ -640,6 +913,7 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB(
int32 width,
int32 height,
TransportDIB::Handle transport_dib) {
+ CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
plugin_container_manager_.SetSizeAndTransportDIB(window,
width,
height,
@@ -648,25 +922,67 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB(
void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
gfx::PluginWindowHandle window) {
- [cocoa_view_ drawAcceleratedPluginLayer];
+ CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ PluginViewMap::iterator it = plugin_views_.find(window);
+ DCHECK(plugin_views_.end() != it);
+ if (plugin_views_.end() == it) {
+ return;
+ }
+ DCHECK([it->second isKindOfClass:[AcceleratedPluginView class]]);
+
+ plugin_container_manager_.SetSurfaceWasPaintedTo(window);
+ AcceleratedPluginView* view =
+ static_cast<AcceleratedPluginView*>(it->second);
+ // The surface is hidden until its first paint, to not show gargabe.
+ if (plugin_container_manager_.SurfaceShouldBeVisible(window))
+ [view setHidden:NO];
+ [view setSurfaceWasSwapped:YES];
+}
+
+void RenderWidgetHostViewMac::GpuRenderingStateDidChange() {
+ CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ // Plugins are destroyed on page navigate. The compositor layer on the other
+ // hand is created on demand and then stays alive until its renderer process
+ // dies (usually on cross-domain navigation). Instead, only a flag
+ // |is_gpu_rendering_active()| is flipped when the compositor output should be
+ // shown/hidden.
+ // Show/hide the view belonging to the compositor here.
+ plugin_container_manager_.set_gpu_rendering_active(
+ GetRenderWidgetHost()->is_gpu_rendering_active());
+
+ gfx::PluginWindowHandle root_handle =
+ plugin_container_manager_.root_container_handle();
+ if (root_handle != gfx::kNullPluginWindow) {
+ PluginViewMap::iterator it = plugin_views_.find(root_handle);
+ DCHECK(plugin_views_.end() != it);
+ if (plugin_views_.end() == it) {
+ return;
+ }
+ bool visible =
+ plugin_container_manager_.SurfaceShouldBeVisible(root_handle);
+ [it->second setHidden:!visible];
+ }
}
-void RenderWidgetHostViewMac::DrawAcceleratedSurfaceInstances(
- CGLContextObj context) {
+void RenderWidgetHostViewMac::DrawAcceleratedSurfaceInstance(
+ CGLContextObj context,
+ gfx::PluginWindowHandle plugin_handle,
+ NSSize size) {
+ // Called on the display link thread.
CGLSetCurrentContext(context);
- gfx::Rect rect = GetWindowRect();
+
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Note that we place the origin at the upper left corner with +y
// going down
- glOrtho(0, rect.width(), rect.height(), 0, -1, 1);
+ glOrtho(0, size.width, size.height, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- plugin_container_manager_.Draw(context);
+ plugin_container_manager_.Draw(context, plugin_handle);
}
-void RenderWidgetHostViewMac::AcceleratedSurfaceContextChanged() {
+void RenderWidgetHostViewMac::ForceTextureReload() {
plugin_container_manager_.ForceTextureReload();
}
@@ -680,12 +996,18 @@ void RenderWidgetHostViewMac::ShutdownHost() {
// Do not touch any members at this point, |this| has been deleted.
}
+bool RenderWidgetHostViewMac::IsVoiceOverRunning() {
+ NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults];
+ [user_defaults addSuiteNamed:@"com.apple.universalaccess"];
+ return 1 == [user_defaults integerForKey:@"voiceOverOnOffKey"];
+}
+
namespace {
// Adjusts an NSRect in Cocoa screen coordinates to have an origin in the upper
// left of the primary screen (Carbon coordinates), and stuffs it into a
// gfx::Rect.
-gfx::Rect NSRectToRect(const NSRect rect) {
+gfx::Rect FlipNSRectToRectScreen(const NSRect rect) {
gfx::Rect new_rect(NSRectToCGRect(rect));
if ([[NSScreen screens] count] > 0) {
new_rect.set_y([[[NSScreen screens] objectAtIndex:0] frame].size.height -
@@ -728,7 +1050,7 @@ gfx::Rect RenderWidgetHostViewMac::GetWindowRect() {
NSRect bounds = [cocoa_view_ bounds];
bounds = [cocoa_view_ convertRect:bounds toView:nil];
bounds.origin = [enclosing_window convertBaseToScreen:bounds.origin];
- return NSRectToRect(bounds);
+ return FlipNSRectToRectScreen(bounds);
}
gfx::Rect RenderWidgetHostViewMac::GetRootWindowRect() {
@@ -740,7 +1062,7 @@ gfx::Rect RenderWidgetHostViewMac::GetRootWindowRect() {
return gfx::Rect();
NSRect bounds = [enclosing_window frame];
- return NSRectToRect(bounds);
+ return FlipNSRectToRectScreen(bounds);
}
void RenderWidgetHostViewMac::SetActive(bool active) {
@@ -787,14 +1109,6 @@ void RenderWidgetHostViewMac::UpdateAccessibilityTree(
}
}
-void RenderWidgetHostViewMac::OnAccessibilityFocusChange(int acc_obj_id) {
- NOTIMPLEMENTED();
-}
-
-void RenderWidgetHostViewMac::OnAccessibilityObjectStateChange(int acc_obj_id) {
- NOTIMPLEMENTED();
-}
-
void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
if (active) {
if (text_input_type_ == WebKit::WebTextInputTypePassword)
@@ -916,7 +1230,7 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
[self keyEvent:theEvent wasKeyEquivalent:NO];
}
-- (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv {
+- (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv {
DCHECK([theEvent type] != NSKeyDown ||
!equiv == !([theEvent modifierFlags] & NSCommandKeyMask));
@@ -1118,8 +1432,12 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
// If this view can be the key view, it is not a popup. Therefore, if it has
// any children, they are popups that need to be canceled.
if (canBeKeyView_) {
- for (RenderWidgetHostViewCocoa* subview in [self subviews]) {
- subview->renderWidgetHostView_->KillSelf();
+ for (NSView* subview in [self subviews]) {
+ if (![subview isKindOfClass:[RenderWidgetHostViewCocoa class]])
+ continue; // Skip plugin views.
+
+ [static_cast<RenderWidgetHostViewCocoa*>(subview)
+ renderWidgetHostViewMac]->KillSelf();
}
}
}
@@ -1156,6 +1474,54 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
renderWidgetHostView_->invalid_rect_ = NSZeroRect;
}
+// Fills with white the parts of the area to the right and bottom for |rect|
+// that intersect |damagedRect|.
+- (void)fillBottomRightRemainderOfRect:(gfx::Rect)rect
+ dirtyRect:(gfx::Rect)damagedRect {
+ if (damagedRect.right() > rect.right()) {
+ int x = std::max(rect.right(), damagedRect.x());
+ int y = std::min(rect.bottom(), damagedRect.bottom());
+ int width = damagedRect.right() - x;
+ int height = damagedRect.y() - y;
+
+ // Extra fun to get around the fact that gfx::Rects can't have
+ // negative sizes.
+ if (width < 0) {
+ x += width;
+ width = -width;
+ }
+ if (height < 0) {
+ y += height;
+ height = -height;
+ }
+
+ NSRect r = [self flipRectToNSRect:gfx::Rect(x, y, width, height)];
+ [[NSColor whiteColor] set];
+ NSRectFill(r);
+ }
+ if (damagedRect.bottom() > rect.bottom()) {
+ int x = damagedRect.x();
+ int y = damagedRect.bottom();
+ int width = damagedRect.right() - x;
+ int height = std::max(rect.bottom(), damagedRect.y()) - y;
+
+ // Extra fun to get around the fact that gfx::Rects can't have
+ // negative sizes.
+ if (width < 0) {
+ x += width;
+ width = -width;
+ }
+ if (height < 0) {
+ y += height;
+ height = -height;
+ }
+
+ NSRect r = [self flipRectToNSRect:gfx::Rect(x, y, width, height)];
+ [[NSColor whiteColor] set];
+ NSRectFill(r);
+ }
+}
+
- (void)drawRect:(NSRect)dirtyRect {
if (!renderWidgetHostView_->render_widget_host_) {
// TODO(shess): Consider using something more noticable?
@@ -1164,38 +1530,58 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
return;
}
+ const gfx::Rect damagedRect([self flipNSRectToRect:dirtyRect]);
+
+ if (renderWidgetHostView_->render_widget_host_->is_gpu_rendering_active()) {
+ gfx::Rect gpuRect;
+
+ gfx::PluginWindowHandle root_handle =
+ renderWidgetHostView_->plugin_container_manager_.root_container_handle();
+ if (root_handle != gfx::kNullPluginWindow) {
+ RenderWidgetHostViewMac::PluginViewMap::iterator it =
+ renderWidgetHostView_->plugin_views_.find(root_handle);
+ DCHECK(it != renderWidgetHostView_->plugin_views_.end());
+ if (it != renderWidgetHostView_->plugin_views_.end() &&
+ ![it->second isHidden]) {
+ NSRect frame = [it->second frame];
+ frame.size = [it->second cachedSize];
+ gpuRect = [self flipNSRectToRect:frame];
+ }
+ }
+
+ [self fillBottomRightRemainderOfRect:gpuRect dirtyRect:damagedRect];
+ return;
+ }
+
DCHECK(
renderWidgetHostView_->render_widget_host_->process()->HasConnection());
DCHECK(!renderWidgetHostView_->about_to_validate_and_paint_);
renderWidgetHostView_->about_to_validate_and_paint_ = true;
- BackingStoreMac* backing_store = static_cast<BackingStoreMac*>(
+ BackingStoreMac* backingStore = static_cast<BackingStoreMac*>(
renderWidgetHostView_->render_widget_host_->GetBackingStore(true));
renderWidgetHostView_->about_to_validate_and_paint_ = false;
- if (backing_store) {
- NSRect view_bounds = [self bounds];
- gfx::Rect damaged_rect([self NSRectToRect:dirtyRect]);
-
- gfx::Rect bitmap_rect(0, 0,
- backing_store->size().width(),
- backing_store->size().height());
+ if (backingStore) {
+ gfx::Rect bitmapRect(0, 0,
+ backingStore->size().width(),
+ backingStore->size().height());
// Specify the proper y offset to ensure that the view is rooted to the
// upper left corner. This can be negative, if the window was resized
// smaller and the renderer hasn't yet repainted.
- int yOffset = NSHeight(view_bounds) - backing_store->size().height();
+ int yOffset = NSHeight([self bounds]) - backingStore->size().height();
- gfx::Rect paint_rect = bitmap_rect.Intersect(damaged_rect);
- if (!paint_rect.IsEmpty()) {
+ gfx::Rect paintRect = bitmapRect.Intersect(damagedRect);
+ if (!paintRect.IsEmpty()) {
// if we have a CGLayer, draw that into the window
- if (backing_store->cg_layer()) {
+ if (backingStore->cg_layer()) {
CGContextRef context = static_cast<CGContextRef>(
[[NSGraphicsContext currentContext] graphicsPort]);
// TODO: add clipping to dirtyRect if it improves drawing performance.
CGContextDrawLayerAtPoint(context, CGPointMake(0.0, yOffset),
- backing_store->cg_layer());
+ backingStore->cg_layer());
} else {
// if we haven't created a layer yet, draw the cached bitmap into
// the window. The CGLayer will be created the next time the renderer
@@ -1203,56 +1589,16 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
CGContextRef context = static_cast<CGContextRef>(
[[NSGraphicsContext currentContext] graphicsPort]);
scoped_cftyperef<CGImageRef> image(
- CGBitmapContextCreateImage(backing_store->cg_bitmap()));
- CGRect imageRect = bitmap_rect.ToCGRect();
+ CGBitmapContextCreateImage(backingStore->cg_bitmap()));
+ CGRect imageRect = bitmapRect.ToCGRect();
imageRect.origin.y = yOffset;
CGContextDrawImage(context, imageRect, image);
}
}
- // Fill the remaining portion of the damaged_rect with white
- if (damaged_rect.right() > bitmap_rect.right()) {
- int x = std::max(bitmap_rect.right(), damaged_rect.x());
- int y = std::min(bitmap_rect.bottom(), damaged_rect.bottom());
- int width = damaged_rect.right() - x;
- int height = damaged_rect.y() - y;
-
- // Extra fun to get around the fact that gfx::Rects can't have
- // negative sizes.
- if (width < 0) {
- x += width;
- width = -width;
- }
- if (height < 0) {
- y += height;
- height = -height;
- }
-
- NSRect r = [self RectToNSRect:gfx::Rect(x, y, width, height)];
- [[NSColor whiteColor] set];
- NSRectFill(r);
- }
- if (damaged_rect.bottom() > bitmap_rect.bottom()) {
- int x = damaged_rect.x();
- int y = damaged_rect.bottom();
- int width = damaged_rect.right() - x;
- int height = std::max(bitmap_rect.bottom(), damaged_rect.y()) - y;
-
- // Extra fun to get around the fact that gfx::Rects can't have
- // negative sizes.
- if (width < 0) {
- x += width;
- width = -width;
- }
- if (height < 0) {
- y += height;
- height = -height;
- }
+ // Fill the remaining portion of the damagedRect with white
+ [self fillBottomRightRemainderOfRect:bitmapRect dirtyRect:damagedRect];
- NSRect r = [self RectToNSRect:gfx::Rect(x, y, width, height)];
- [[NSColor whiteColor] set];
- NSRectFill(r);
- }
if (!renderWidgetHostView_->whiteout_start_time_.is_null()) {
base::TimeDelta whiteout_duration = base::TimeTicks::Now() -
renderWidgetHostView_->whiteout_start_time_;
@@ -1277,10 +1623,6 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
if (renderWidgetHostView_->whiteout_start_time_.is_null())
renderWidgetHostView_->whiteout_start_time_ = base::TimeTicks::Now();
}
-
- // This helps keep accelerated plugins' output in better sync with the
- // window as it resizes.
- [acceleratedPluginLayer_.get() setNeedsDisplay];
}
- (BOOL)canBecomeKeyView {
@@ -1950,17 +2292,20 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
}
- (void)viewDidMoveToWindow {
- // If we move into a new window, refresh the frame information. We don't need
- // to do it if it was the same window as it used to be in, since that case
- // is covered by DidBecomeSelected.
- // We only want to do this for real browser views, not popups.
if (canBeKeyView_) {
NSWindow* newWindow = [self window];
// Pointer comparison only, since we don't know if lastWindow_ is still
// valid.
- if (newWindow && (newWindow != lastWindow_)) {
- lastWindow_ = newWindow;
- renderWidgetHostView_->WindowFrameChanged();
+ if (newWindow) {
+ // If we move into a new window, refresh the frame information. We
+ // don't need to do it if it was the same window as it used to be in,
+ // since that case is covered by DidBecomeSelected. We only want to
+ // do this for real browser views, not popups.
+ if (newWindow != lastWindow_) {
+ lastWindow_ = newWindow;
+ renderWidgetHostView_->WindowFrameChanged();
+ }
+ renderWidgetHostView_->ForceTextureReload();
}
}
@@ -2026,52 +2371,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
}
}
-- (void)ensureAcceleratedPluginLayer {
- if (acceleratedPluginLayer_.get())
- return;
-
- AcceleratedPluginLayer* pluginLayer = [[AcceleratedPluginLayer alloc]
- initWithRenderWidgetHostViewMac:renderWidgetHostView_.get()];
- acceleratedPluginLayer_.reset(pluginLayer);
- // Make our layer resize to fit the superlayer
- pluginLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
- // Make the view layer-backed so that there will be a layer to hang the
- // |layer| off of. This is not the "right" way to host a sublayer in a view,
- // but the right way would require making the whole view's drawing system
- // layer-based (using setLayer:). We don't want to do that (at least not
- // yet) so instead we override setLayer: and re-bind our plugin layer each
- // time the view's layer changes. For discussion see:
- // http://lists.apple.com/archives/Cocoa-dev/2009/Feb/msg01132.html
- [self setWantsLayer:YES];
- [self attachPluginLayer];
-}
-
-- (void)attachPluginLayer {
- CALayer* pluginLayer = acceleratedPluginLayer_.get();
- if (!pluginLayer)
- return;
-
- CALayer* rootLayer = [self layer];
- DCHECK(rootLayer != nil);
- [pluginLayer setFrame:NSRectToCGRect([self bounds])];
- [rootLayer addSublayer:pluginLayer];
- renderWidgetHostView_->AcceleratedSurfaceContextChanged();
-}
-
-- (void)setLayer:(CALayer *)newLayer {
- CALayer* pluginLayer = acceleratedPluginLayer_.get();
- if (!newLayer && [pluginLayer superlayer])
- [pluginLayer removeFromSuperlayer];
-
- [super setLayer:newLayer];
- if ([self layer])
- [self attachPluginLayer];
-}
-
-- (void)drawAcceleratedPluginLayer {
- [acceleratedPluginLayer_.get() setNeedsDisplay];
-}
-
- (void)cancelComposition {
if (!hasMarkedText_)
return;
@@ -2102,4 +2401,58 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
return VIEW_ID_TAB_CONTAINER_FOCUS_VIEW;
}
+// Overriding a NSResponder method to support application services.
+
+- (id)validRequestorForSendType:(NSString*)sendType
+ returnType:(NSString*)returnType {
+ id requestor = nil;
+ BOOL sendTypeIsString = [sendType isEqual:NSStringPboardType];
+ BOOL returnTypeIsString = [returnType isEqual:NSStringPboardType];
+ BOOL hasText = !renderWidgetHostView_->selected_text().empty();
+ BOOL takesText =
+ renderWidgetHostView_->text_input_type_ != WebKit::WebTextInputTypeNone;
+
+ if (sendTypeIsString && hasText && !returnType) {
+ requestor = self;
+ } else if (!sendType && returnTypeIsString && takesText) {
+ requestor = self;
+ } else if (sendTypeIsString && returnTypeIsString && hasText && takesText) {
+ requestor = self;
+ } else {
+ requestor = [super validRequestorForSendType:sendType
+ returnType:returnType];
+ }
+ return requestor;
+}
+
+@end
+
+//
+// Supporting application services
+//
+@implementation RenderWidgetHostViewCocoa(NSServicesRequests)
+
+- (BOOL)writeSelectionToPasteboard:(NSPasteboard*)pboard
+ types:(NSArray*)types {
+ const std::string& str = renderWidgetHostView_->selected_text();
+ if (![types containsObject:NSStringPboardType] || str.empty()) return NO;
+
+ scoped_nsobject<NSString> text([[NSString alloc]
+ initWithUTF8String:str.c_str()]);
+ NSArray* toDeclare = [NSArray arrayWithObject:NSStringPboardType];
+ [pboard declareTypes:toDeclare owner:nil];
+ return [pboard setString:text forType:NSStringPboardType];
+}
+
+- (BOOL)readSelectionFromPasteboard:(NSPasteboard*)pboard {
+ NSString *string = [pboard stringForType:NSStringPboardType];
+ if (!string) return NO;
+
+ // If the user is currently using an IME, confirm the IME input,
+ // and then insert the text from the service, the same as TextEdit and Safari.
+ [self confirmComposition];
+ [self insertText:string];
+ return YES;
+}
+
@end
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 255ae63..deccc0a 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -45,6 +45,8 @@
#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"
using base::TimeDelta;
@@ -289,12 +291,6 @@ RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget)
registrar_.Add(this,
NotificationType::RENDERER_PROCESS_TERMINATED,
NotificationService::AllSources());
-
- BOOL screenreader_running = FALSE;
- if (SystemParametersInfo(SPI_GETSCREENREADER, 0, &screenreader_running, 0) &&
- screenreader_running) {
- render_widget_host_->EnableRendererAccessibility();
- }
}
RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
@@ -330,6 +326,11 @@ void RenderWidgetHostViewWin::InitAsPopup(
ShowWindow(IsActivatable() ? SW_SHOW : SW_SHOWNA);
}
+void RenderWidgetHostViewWin::InitAsFullscreen(
+ RenderWidgetHostView* parent_host_view) {
+ NOTIMPLEMENTED() << "Fullscreen not implemented on Win";
+}
+
RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const {
return render_widget_host_;
}
@@ -691,19 +692,17 @@ void RenderWidgetHostViewWin::DrawResizeCorner(const gfx::Rect& paint_rect,
canvas.getDevice()->accessBitmap(true).eraseARGB(0, 0, 0, 0);
int x = resize_corner_rect.x() + resize_corner_rect.width() -
bitmap->width();
- bool rtl_dir = base::i18n::IsRTL();
- if (rtl_dir) {
+ canvas.save();
+ if (base::i18n::IsRTL()) {
canvas.TranslateInt(bitmap->width(), 0);
canvas.ScaleInt(-1, 1);
- canvas.save();
x = 0;
}
canvas.DrawBitmapInt(*bitmap, 0, 0);
canvas.getTopPlatformDevice().drawToHDC(dc, x,
resize_corner_rect.y() + resize_corner_rect.height() -
bitmap->height(), NULL);
- if (rtl_dir)
- canvas.restore();
+ canvas.restore();
}
}
@@ -1447,7 +1446,9 @@ LRESULT RenderWidgetHostViewWin::OnWheelEvent(UINT message, WPARAM wparam,
return 0;
}
-LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT, WPARAM, LPARAM,
+LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
BOOL& handled) {
if (!IsActivatable())
return MA_NOACTIVATE;
@@ -1466,7 +1467,7 @@ LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT, WPARAM, LPARAM,
::GetCursorPos(&cursor_pos);
::ScreenToClient(m_hWnd, &cursor_pos);
HWND child_window = ::RealChildWindowFromPoint(m_hWnd, cursor_pos);
- if (::IsWindow(child_window)) {
+ if (::IsWindow(child_window) && child_window != m_hWnd) {
if (win_util::GetClassName(child_window) == kWrapperNativeWindowClassName)
child_window = ::GetWindow(child_window, GW_CHILD);
@@ -1475,35 +1476,22 @@ LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT, WPARAM, LPARAM,
}
}
handled = FALSE;
+ render_widget_host_->OnMouseActivate();
return MA_ACTIVATE;
}
-void RenderWidgetHostViewWin::UpdateAccessibilityTree(
- const webkit_glue::WebAccessibility& tree) {
- browser_accessibility_manager_.reset(
- new BrowserAccessibilityManager(m_hWnd, tree, this));
-
- BrowserAccessibility* root = browser_accessibility_manager_.get()->GetRoot();
- LONG root_id;
- if (root && SUCCEEDED(root->get_uniqueID(&root_id))) {
- ::NotifyWinEvent(
- EVENT_OBJECT_FOCUS, m_hWnd, OBJID_CLIENT, root_id);
- ::NotifyWinEvent(
- IA2_EVENT_DOCUMENT_LOAD_COMPLETE, m_hWnd, OBJID_CLIENT, root_id);
- }
-}
-
-void RenderWidgetHostViewWin::OnAccessibilityFocusChange(int acc_obj_id) {
- if (browser_accessibility_manager_.get()) {
- browser_accessibility_manager_->OnAccessibilityFocusChange(acc_obj_id);
+void RenderWidgetHostViewWin::OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) {
+ if (!browser_accessibility_manager_.get()) {
+ // Use empty document to process notifications
+ webkit_glue::WebAccessibility empty_document;
+ empty_document.role = WebAccessibility::ROLE_DOCUMENT;
+ empty_document.state = 0;
+ browser_accessibility_manager_.reset(
+ new BrowserAccessibilityManager(m_hWnd, empty_document, this));
}
-}
-void RenderWidgetHostViewWin::OnAccessibilityObjectStateChange(int acc_obj_id) {
- if (browser_accessibility_manager_.get()) {
- browser_accessibility_manager_->OnAccessibilityObjectStateChange(
- acc_obj_id);
- }
+ browser_accessibility_manager_->OnAccessibilityNotifications(params);
}
void RenderWidgetHostViewWin::Observe(NotificationType type,
@@ -1558,39 +1546,18 @@ LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam,
if (!browser_accessibility_manager_.get()) {
render_widget_host_->EnableRendererAccessibility();
- if (!loading_accessible_.get()) {
- // Create IAccessible to return while waiting for the accessibility tree
- // from the renderer.
- HRESULT hr = ::CreateStdAccessibleObject(
- m_hWnd, OBJID_CLIENT, IID_IAccessible,
- reinterpret_cast<void **>(&loading_accessible_));
-
- // Annotate with STATE_SYSTEM_BUSY to indicate that the page is loading.
- // We annotate the HWND, not the loading_accessible IAccessible, but the
- // IAccessible will reflect the state annotation.
- ScopedComPtr<IAccPropServices> pAccPropServices;
- hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
- IID_IAccPropServices, reinterpret_cast<void**>(&pAccPropServices));
- if (SUCCEEDED(hr)) {
- VARIANT var;
- var.vt = VT_I4;
- var.lVal = STATE_SYSTEM_BUSY;
- pAccPropServices->SetHwndProp(m_hWnd, OBJID_CLIENT,
- CHILDID_SELF, PROPID_ACC_STATE, var);
- }
- }
+ // Return busy document tree while renderer accessibility tree loads.
+ webkit_glue::WebAccessibility loading_tree;
+ loading_tree.role = WebAccessibility::ROLE_DOCUMENT;
+ loading_tree.state = (1 << WebAccessibility::STATE_BUSY);
+ browser_accessibility_manager_.reset(
+ new BrowserAccessibilityManager(m_hWnd, loading_tree, this));
+ }
- if (loading_accessible_.get()) {
- return LresultFromObject(
- IID_IAccessible, wparam,
- static_cast<IAccessible*>(loading_accessible_));
- }
- } else {
- BrowserAccessibility* root = browser_accessibility_manager_->GetRoot();
- if (root) {
- return LresultFromObject(IID_IAccessible, wparam,
- static_cast<IAccessible*>(root->NewReference()));
- }
+ BrowserAccessibility* root = browser_accessibility_manager_->GetRoot();
+ if (root) {
+ return LresultFromObject(IID_IAccessible, wparam,
+ static_cast<IAccessible*>(root->NewReference()));
}
handled = false;
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 e0bc712..ff9a472 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_WIN_H_
#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_WIN_H_
+#pragma once
#include <atlbase.h>
#include <atlapp.h>
@@ -18,6 +19,7 @@
#include "chrome/browser/browser_accessibility_manager_win.h"
#include "chrome/browser/ime_input.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "webkit/glue/webcursor.h"
@@ -119,6 +121,7 @@ class RenderWidgetHostViewWin
// Implementation of RenderWidgetHostView:
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos);
+ virtual void InitAsFullscreen(RenderWidgetHostView* parent_host_view);
virtual RenderWidgetHost* GetRenderWidgetHost() const;
virtual void DidBecomeSelected();
virtual void WasHidden();
@@ -150,10 +153,8 @@ class RenderWidgetHostViewWin
virtual void SetBackground(const SkBitmap& background);
virtual bool ContainsNativeView(gfx::NativeView native_view) const;
virtual void SetVisuallyDeemphasized(bool deemphasized);
- virtual void UpdateAccessibilityTree(
- const webkit_glue::WebAccessibility& tree);
- virtual void OnAccessibilityFocusChange(int acc_obj_id);
- virtual void OnAccessibilityObjectStateChange(int acc_obj_id);
+ virtual void OnAccessibilityNotifications(
+ const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params);
// Implementation of NotificationObserver:
virtual void Observe(NotificationType type,
@@ -194,7 +195,10 @@ class RenderWidgetHostViewWin
UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
LRESULT OnWheelEvent(
UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
- LRESULT OnMouseActivate(UINT, WPARAM, LPARAM, BOOL& handled);
+ LRESULT OnMouseActivate(UINT message,
+ WPARAM wparam,
+ LPARAM lparam,
+ BOOL& handled);
// Handle MSAA requests for accessibility information.
LRESULT OnGetObject(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled);
@@ -254,9 +258,6 @@ class RenderWidgetHostViewWin
// Whether the window should be activated.
bool IsActivatable() const;
- // MSAA IAccessible returned while page contents is loading.
- ScopedComPtr<IAccessible> loading_accessible_;
-
// The associated Model.
RenderWidgetHost* render_widget_host_;
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index eb826a2..9126eb9 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -8,7 +8,9 @@
#include <vector>
+#include "base/logging.h"
#include "base/command_line.h"
+#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
@@ -16,6 +18,7 @@
#include "base/time.h"
#include "chrome/browser/cert_store.h"
#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/chrome_blob_storage_context.h"
#include "chrome/browser/cross_site_request_manager.h"
#include "chrome/browser/download/download_file_manager.h"
#include "chrome/browser/download/download_manager.h"
@@ -34,6 +37,7 @@
#include "chrome/browser/renderer_host/cross_site_resource_handler.h"
#include "chrome/browser/renderer_host/download_resource_handler.h"
#include "chrome/browser/renderer_host/global_request_id.h"
+#include "chrome/browser/renderer_host/redirect_to_file_resource_handler.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"
@@ -51,6 +55,7 @@
#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"
#include "net/base/auth.h"
#include "net/base/cert_status_flags.h"
@@ -59,10 +64,14 @@
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/base/ssl_cert_request_info.h"
+#include "net/base/upload_data.h"
+#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "webkit/appcache/appcache_interceptor.h"
#include "webkit/appcache/appcache_interfaces.h"
+#include "webkit/blob/blob_storage_controller.h"
+#include "webkit/blob/deletable_file_reference.h"
// TODO(oshima): Enable this for other platforms.
#if defined(OS_CHROMEOS)
@@ -81,6 +90,7 @@
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
+using webkit_blob::DeletableFileReference;
// ----------------------------------------------------------------------------
@@ -124,6 +134,10 @@ bool ShouldServiceRequest(ChildProcessInfo::ProcessType process_type,
if (process_type == ChildProcessInfo::PLUGIN_PROCESS)
return true;
+ if (request_data.resource_type == ResourceType::PREFETCH &&
+ !ResourceDispatcherHost::is_prefetch_enabled())
+ return false;
+
ChildProcessSecurityPolicy* policy =
ChildProcessSecurityPolicy::GetInstance();
@@ -141,7 +155,7 @@ bool ShouldServiceRequest(ChildProcessInfo::ProcessType process_type,
std::vector<net::UploadData::Element>::const_iterator iter;
for (iter = uploads->begin(); iter != uploads->end(); ++iter) {
if (iter->type() == net::UploadData::TYPE_FILE &&
- !policy->CanUploadFile(child_id, iter->file_path())) {
+ !policy->CanReadFile(child_id, iter->file_path())) {
NOTREACHED() << "Denied unauthorized upload of "
<< iter->file_path().value();
return false;
@@ -309,7 +323,10 @@ bool ResourceDispatcherHost::OnMessageReceived(const IPC::Message& message,
IPC_BEGIN_MESSAGE_MAP_EX(ResourceDispatcherHost, message, *message_was_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestResource, OnRequestResource)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncLoad, OnSyncLoad)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ReleaseDownloadedFile,
+ OnReleaseDownloadedFile)
IPC_MESSAGE_HANDLER(ViewHostMsg_DataReceived_ACK, OnDataReceivedACK)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DataDownloaded_ACK, OnDataDownloadedACK)
IPC_MESSAGE_HANDLER(ViewHostMsg_UploadProgress_ACK, OnUploadProgressACK)
IPC_MESSAGE_HANDLER(ViewHostMsg_CancelRequest, OnCancelRequest)
IPC_MESSAGE_HANDLER(ViewHostMsg_FollowRedirect, OnFollowRedirect)
@@ -362,6 +379,12 @@ void ResourceDispatcherHost::BeginRequest(
}
}
+ // Might need to resolve the blob references in the upload data.
+ if (request_data.upload_data && context) {
+ context->blob_storage_context()->controller()->
+ ResolveBlobReferencesInUploadData(request_data.upload_data.get());
+ }
+
if (is_shutdown_ ||
!ShouldServiceRequest(process_type, child_id, request_data)) {
URLRequestStatus status(URLRequestStatus::FAILED, net::ERR_ABORTED);
@@ -376,8 +399,8 @@ void ResourceDispatcherHost::BeginRequest(
route_id,
request_id,
status,
- std::string())); // No security info needed, connection was not
- // established.
+ std::string(), // No security info needed, connection was not
+ base::Time())); // established.
}
return;
}
@@ -391,7 +414,11 @@ void ResourceDispatcherHost::BeginRequest(
// Construct the event handler.
scoped_refptr<ResourceHandler> handler;
if (sync_result) {
- handler = new SyncResourceHandler(receiver_, request_data.url, sync_result);
+ handler = new SyncResourceHandler(receiver_,
+ child_id,
+ request_data.url,
+ sync_result,
+ this);
} else {
handler = new AsyncResourceHandler(receiver_,
child_id,
@@ -401,6 +428,10 @@ void ResourceDispatcherHost::BeginRequest(
this);
}
+ // The RedirectToFileResourceHandler depends on being next in the chain.
+ if (request_data.download_to_file)
+ handler = new RedirectToFileResourceHandler(handler, child_id, this);
+
if (HandleExternalProtocol(request_id, child_id, route_id,
request_data.url, request_data.resource_type,
handler)) {
@@ -421,8 +452,11 @@ void ResourceDispatcherHost::BeginRequest(
// EV certificate verification could be expensive. We don't want to spend
// time performing EV certificate verification on all resources because
// EV status is irrelevant to sub-frames and sub-resources.
- if (request_data.resource_type == ResourceType::MAIN_FRAME)
- load_flags |= net::LOAD_VERIFY_EV_CERT;
+ if (request_data.resource_type == ResourceType::MAIN_FRAME) {
+ load_flags |= net::LOAD_VERIFY_EV_CERT | net::LOAD_MAIN_FRAME;
+ } else if (request_data.resource_type == ResourceType::SUB_FRAME) {
+ load_flags |= net::LOAD_SUB_FRAME;
+ }
request->set_load_flags(load_flags);
request->set_context(context);
request->set_priority(DetermineRequestPriority(request_data.resource_type));
@@ -489,6 +523,15 @@ void ResourceDispatcherHost::BeginRequest(
chrome_browser_net::SetOriginProcessUniqueIDForRequest(
request_data.origin_child_id, request);
+ if (request->url().SchemeIs(chrome::kBlobScheme) && context) {
+ // Hang on to a reference to ensure the blob is not released prior
+ // to the job being started.
+ webkit_blob::BlobStorageController* controller =
+ context->blob_storage_context()->controller();
+ extra_info->set_requested_blob_data(
+ controller->GetBlobDataFromUrl(request->url()));
+ }
+
// Have the appcache associate its extra info with the request.
appcache::AppCacheInterceptor::SetExtraRequestInfo(
request, context ? context->appcache_service() : NULL, child_id,
@@ -497,6 +540,12 @@ void ResourceDispatcherHost::BeginRequest(
BeginRequestInternal(request);
}
+void ResourceDispatcherHost::OnReleaseDownloadedFile(int request_id) {
+ DCHECK(pending_requests_.end() ==
+ pending_requests_.find(GlobalRequestID(receiver_->id(), request_id)));
+ UnregisterDownloadedTempFile(receiver_->id(), request_id);
+}
+
void ResourceDispatcherHost::OnDataReceivedACK(int request_id) {
DataReceivedACK(receiver_->id(), request_id);
}
@@ -524,6 +573,28 @@ void ResourceDispatcherHost::DataReceivedACK(int child_id,
}
}
+void ResourceDispatcherHost::OnDataDownloadedACK(int request_id) {
+ // TODO(michaeln): maybe throttle DataDownloaded messages
+}
+
+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;
+ ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
+ receiver_id, reference->path());
+}
+
+void ResourceDispatcherHost::UnregisterDownloadedTempFile(
+ int receiver_id, int request_id) {
+ DeletableFilesMap& map = registered_temp_files_[receiver_id];
+ DeletableFilesMap::iterator found = map.find(request_id);
+ if (found == map.end())
+ return;
+ map.erase(found);
+ // TODO(michaeln): Revoke access to this file.
+}
+
bool ResourceDispatcherHost::Send(IPC::Message* message) {
delete message;
return false;
@@ -819,6 +890,7 @@ int ResourceDispatcherHost::GetOutstandingRequestsMemoryCost(
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);
}
void ResourceDispatcherHost::CancelRequestsForRoute(int child_id,
@@ -1770,8 +1842,9 @@ bool ResourceDispatcherHost::IsResourceDispatcherHostMessage(
case ViewHostMsg_CancelRequest::ID:
case ViewHostMsg_FollowRedirect::ID:
case ViewHostMsg_ClosePage_ACK::ID:
+ case ViewHostMsg_ReleaseDownloadedFile::ID:
case ViewHostMsg_DataReceived_ACK::ID:
- case ViewHostMsg_DownloadProgress_ACK::ID:
+ case ViewHostMsg_DataDownloaded_ACK::ID:
case ViewHostMsg_UploadProgress_ACK::ID:
case ViewHostMsg_SyncLoad::ID:
return true;
@@ -1830,15 +1903,33 @@ net::RequestPriority ResourceDispatcherHost::DetermineRequestPriority(
case ResourceType::SHARED_WORKER:
return net::LOW;
- // Images are the lowest priority because they typically do not block
+ // Images are the "lowest" priority because they typically do not block
// downloads or rendering and most pages have some useful content without
// them.
case ResourceType::IMAGE:
return net::LOWEST;
+ // Prefetches are at a lower priority than even LOWEST, since they
+ // are not even required for rendering of the current page.
+ case ResourceType::PREFETCH:
+ return net::IDLE;
+
default:
// When new resource types are added, their priority must be considered.
NOTREACHED();
return net::LOW;
}
}
+
+// static
+bool ResourceDispatcherHost::is_prefetch_enabled() {
+ return is_prefetch_enabled_;
+}
+
+// static
+void ResourceDispatcherHost::set_is_prefetch_enabled(bool value) {
+ is_prefetch_enabled_ = value;
+}
+
+// static
+bool ResourceDispatcherHost::is_prefetch_enabled_ = false;
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h
index b00747e..95909d3 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.h
@@ -4,13 +4,14 @@
// This is the browser side of the resource dispatcher, it receives requests
// from the child process (i.e. [Renderer, Plugin, Worker]ProcessHost), and
-// dispatches them to URLRequests. It then fowards the messages from the
+// dispatches them to URLRequests. It then forwards the messages from the
// URLRequests back to the correct process for handling.
//
// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_H_
+#pragma once
#include <map>
#include <string>
@@ -18,9 +19,8 @@
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
-#include "base/logging.h"
#include "base/observer_list.h"
-#include "base/process.h"
+#include "base/scoped_ptr.h"
#include "base/timer.h"
#include "chrome/common/child_process_info.h"
#include "chrome/browser/renderer_host/resource_queue.h"
@@ -47,6 +47,10 @@ struct GlobalRequestID;
struct ViewHostMsg_Resource_Request;
struct ViewMsg_ClosePage_Params;
+namespace webkit_blob {
+class DeletableFileReference;
+}
+
class ResourceDispatcherHost : public URLRequest::Delegate {
public:
// Implemented by the client of ResourceDispatcherHost to receive messages in
@@ -264,9 +268,23 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// messages sent.
void DataReceivedACK(int process_unique_id, int request_id);
+ // Maintains a collection of temp files created in support of
+ // the download_to_file capability. Used to grant access to the
+ // child process and to defer deletion of the file until it's
+ // no longer needed.
+ void RegisterDownloadedTempFile(
+ int receiver_id, int request_id,
+ webkit_blob::DeletableFileReference* reference);
+ void UnregisterDownloadedTempFile(int receiver_id, int request_id);
+
// Needed for the sync IPC message dispatcher macros.
bool Send(IPC::Message* message);
+ // Controls if we launch or squash prefetch requests as they arrive
+ // from renderers.
+ static bool is_prefetch_enabled();
+ static void set_is_prefetch_enabled(bool value);
+
private:
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
TestBlockedRequestsProcessDies);
@@ -392,11 +410,13 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
IPC::Message* sync_result, // only valid for sync
int route_id); // only valid for async
void OnDataReceivedACK(int request_id);
+ void OnDataDownloadedACK(int request_id);
void OnUploadProgressACK(int request_id);
void OnCancelRequest(int request_id);
void OnFollowRedirect(int request_id,
bool has_new_first_party_for_cookies,
const GURL& new_first_party_for_cookies);
+ void OnReleaseDownloadedFile(int request_id);
ResourceHandler* CreateSafeBrowsingResourceHandler(
ResourceHandler* handler, int child_id, int route_id,
@@ -427,6 +447,15 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
PendingRequestList pending_requests_;
+ // Collection of temp files downloaded for child processes via
+ // the download_to_file mechanism. We avoid deleting them until
+ // the client no longer needs them.
+ typedef std::map<int, scoped_refptr<webkit_blob::DeletableFileReference> >
+ DeletableFilesMap; // key is request id
+ typedef std::map<int, DeletableFilesMap>
+ RegisteredTempFiles; // key is child process id
+ RegisteredTempFiles registered_temp_files_;
+
// A timer that periodically calls UpdateLoadStates while pending_requests_
// is not empty.
base::RepeatingTimer<ResourceDispatcherHost> update_load_states_timer_;
@@ -493,6 +522,8 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// to the source of the message.
Receiver* receiver_;
+ static bool is_prefetch_enabled_;
+
DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHost);
};
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 eeac6f0..30ca189 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/login_prompt.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
+#include "webkit/blob/blob_data.h"
ResourceDispatcherHostRequestInfo::ResourceDispatcherHostRequestInfo(
ResourceHandler* handler,
@@ -61,3 +62,8 @@ void ResourceDispatcherHostRequestInfo::set_ssl_client_auth_handler(
SSLClientAuthHandler* s) {
ssl_client_auth_handler_ = s;
}
+
+void ResourceDispatcherHostRequestInfo::set_requested_blob_data(
+ webkit_blob::BlobData* data) {
+ requested_blob_data_ = data;
+}
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 2bafd0d..9d5e386 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_REQUEST_INFO_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_DISPATCHER_HOST_REQUEST_INFO_H_
+#pragma once
#include <string>
@@ -20,6 +21,10 @@ class ResourceDispatcherHost;
class ResourceHandler;
class SSLClientAuthHandler;
+namespace webkit_blob {
+class BlobData;
+}
+
// Holds the data ResourceDispatcherHost associates with each request.
// Retrieve this data by calling ResourceDispatcherHost::InfoForRequest.
class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
@@ -127,6 +132,7 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
// When there is upload data, this is the byte count of that data. When there
// is no upload, this will be 0.
uint64 upload_size() const { return upload_size_; }
+ void set_upload_size(uint64 upload_size) { upload_size_ = upload_size; }
// When we're uploading data, this is the the byte offset into the uploaded
// data that we've uploaded that we've send an upload progress update about.
@@ -158,6 +164,13 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
int host_renderer_id() const { return host_renderer_id_; }
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.
+ webkit_blob::BlobData* requested_blob_data() const {
+ return requested_blob_data_.get();
+ }
+ void set_requested_blob_data(webkit_blob::BlobData* data);
+
private:
friend class ResourceDispatcherHost;
@@ -212,6 +225,7 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
base::TimeTicks last_upload_ticks_;
bool waiting_for_upload_progress_ack_;
int memory_cost_;
+ scoped_refptr<webkit_blob::BlobData> requested_blob_data_;
// "Private" data accessible only to ResourceDispatcherHost (use the
// accessors above for consistency).
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc
index fa022db..bc4ac2b 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_uitest.cc
@@ -17,7 +17,7 @@
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
namespace {
@@ -77,18 +77,18 @@ TEST_F(ResourceDispatcherTest, ContentDispositionInline) {
}
// Test for bug #1091358.
-TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+// Flakey due to NavigateToURL bug: see http://crbug.com/55380
+TEST_F(ResourceDispatcherTest, FLAKY_SyncXMLHttpRequest) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
scoped_refptr<TabProxy> tab(browser_proxy->GetActiveTab());
ASSERT_TRUE(tab.get());
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
- tab->NavigateToURL(server->TestServerPage(
+ tab->NavigateToURL(test_server.GetURL(
"files/sync_xmlhttprequest.html")));
// Let's check the XMLHttpRequest ran successfully.
@@ -100,17 +100,16 @@ TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest) {
}
TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest_Disallowed) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
scoped_refptr<TabProxy> tab(browser_proxy->GetActiveTab());
ASSERT_TRUE(tab.get());
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
- tab->NavigateToURL(server->TestServerPage(
+ tab->NavigateToURL(test_server.GetURL(
"files/sync_xmlhttprequest_disallowed.html")));
// Let's check the XMLHttpRequest ran successfully.
@@ -124,11 +123,11 @@ TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest_Disallowed) {
// Test for bug #1159553 -- A synchronous xhr (whose content-type is
// downloadable) would trigger download and hang the renderer process,
// if executed while navigating to a new page.
-TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest_DuringUnload) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+// Disabled -- http://code.google.com/p/chromium/issues/detail?id=56264
+TEST_F(ResourceDispatcherTest, DISABLED_SyncXMLHttpRequest_DuringUnload) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
@@ -136,7 +135,7 @@ TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest_DuringUnload) {
ASSERT_TRUE(tab.get());
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
- tab->NavigateToURL(server->TestServerPage(
+ tab->NavigateToURL(test_server.GetURL(
"files/sync_xmlhttprequest_during_unload.html")));
// Confirm that the page has loaded (since it changes its title during load).
@@ -147,7 +146,7 @@ TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest_DuringUnload) {
// Navigate to a new page, to dispatch unload event and trigger xhr.
// (the bug would make this step hang the renderer).
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
- tab->NavigateToURL(server->TestServerPage("files/title2.html")));
+ tab->NavigateToURL(test_server.GetURL("files/title2.html")));
// Check that the new page got loaded, and that no download was triggered.
EXPECT_TRUE(tab->GetTabTitle(&tab_title));
@@ -162,17 +161,16 @@ TEST_F(ResourceDispatcherTest, SyncXMLHttpRequest_DuringUnload) {
// Tests that onunload is run for cross-site requests. (Bug 1114994)
TEST_F(ResourceDispatcherTest, CrossSiteOnunloadCookie) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
scoped_refptr<TabProxy> tab(browser_proxy->GetActiveTab());
ASSERT_TRUE(tab.get());
- GURL url(server->TestServerPage("files/onunload_cookie.html"));
+ GURL url(test_server.GetURL("files/onunload_cookie.html"));
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(url));
// Confirm that the page has loaded (since it changes its title during load).
@@ -216,9 +214,7 @@ TEST_F(ResourceDispatcherTest, CrossSiteAfterCrash) {
ASSERT_TRUE(tab.get());
// Cause the renderer to crash.
- // TODO(albertb): We need to disable this on Linux since
- // crash_service.exe hasn't been ported yet.
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(USE_LINUX_BREAKPAD)
expected_crashes_ = 1;
#endif
ASSERT_TRUE(tab->NavigateToURLAsync(GURL(chrome::kAboutCrashURL)));
@@ -257,17 +253,16 @@ TEST_F(ResourceDispatcherTest, CrossSiteNavigationNonBuffered) {
// doctor page) still runs the onunload handler and can support navigations
// away from the link doctor page. (Bug 1235537)
TEST_F(ResourceDispatcherTest, CrossSiteNavigationErrorPage) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
scoped_refptr<TabProxy> tab(browser_proxy->GetActiveTab());
ASSERT_TRUE(tab.get());
- GURL url(server->TestServerPage("files/onunload_cookie.html"));
+ GURL url(test_server.GetURL("files/onunload_cookie.html"));
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(url));
// Confirm that the page has loaded (since it changes its title during load).
@@ -296,7 +291,7 @@ TEST_F(ResourceDispatcherTest, CrossSiteNavigationErrorPage) {
// TabContents was in the NORMAL state, it would ignore the attempt to run
// the onunload handler, and the navigation would fail.
// (Test by redirecting to javascript:window.location='someURL'.)
- GURL test_url(server->TestServerPage("files/title2.html"));
+ GURL test_url(test_server.GetURL("files/title2.html"));
std::string redirect_url = "javascript:window.location='" +
test_url.possibly_invalid_spec() + "'";
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
index c6a07c1..f05d111 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
@@ -14,7 +14,9 @@
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "net/base/net_errors.h"
+#include "net/base/upload_data.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
@@ -73,6 +75,7 @@ static ViewHostMsg_Resource_Request CreateResourceRequest(
request.resource_type = type;
request.request_context = 0;
request.appcache_host_id = appcache::kNoHostId;
+ request.download_to_file = false;
request.host_renderer_id = -1;
request.host_render_view_id = -1;
return request;
@@ -309,7 +312,7 @@ void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages,
//
// This function verifies that we received 4 messages and that they
// are appropriate.
- ASSERT_EQ(messages.size(), 3U);
+ ASSERT_EQ(3U, messages.size());
// The first messages should be received response
ASSERT_EQ(ViewMsg_Resource_ReceivedResponse::ID, messages[0].type());
diff --git a/chrome/browser/renderer_host/resource_handler.h b/chrome/browser/renderer_host/resource_handler.h
index ed99eaa..b6758ae 100644
--- a/chrome/browser/renderer_host/resource_handler.h
+++ b/chrome/browser/renderer_host/resource_handler.h
@@ -11,6 +11,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
@@ -79,6 +80,12 @@ class ResourceHandler
// This is a signal that the associated URLRequest isn't valid anymore.
virtual void OnRequestClosed() = 0;
+ // This notification is synthesized by the RedirectToFileResourceHandler
+ // to indicate progress of 'download_to_file' requests. OnReadCompleted
+ // calls are consumed by the RedirectToFileResourceHandler and replaced
+ // with OnDataDownloaded calls.
+ virtual void OnDataDownloaded(int request_id, int bytes_downloaded) {}
+
protected:
friend class ChromeThread;
friend class DeleteTask<ResourceHandler>;
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index ca9d668..1bfe307 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -16,16 +16,22 @@
#include "base/process_util.h"
#include "base/shared_memory.h"
#include "base/thread.h"
+#include "base/sys_string_conversions.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_about_handler.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/chrome_plugin_browsing_context.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/clipboard_dispatcher.h"
+#include "chrome/browser/device_orientation/dispatcher_host.h"
#include "chrome/browser/download/download_file.h"
#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/file_system/file_system_dispatcher_host.h"
+#include "chrome/browser/file_system/file_system_host_context.h"
#include "chrome/browser/geolocation/geolocation_permission_context.h"
#include "chrome/browser/geolocation/geolocation_dispatcher_host.h"
#include "chrome/browser/gpu_process_host.h"
@@ -38,18 +44,23 @@
#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/plugin_updater.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.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/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.h"
+#include "chrome/browser/task_manager/task_manager.h"
+#include "chrome/browser/ui_thread_helpers.h"
#include "chrome/browser/worker_host/message_port_dispatcher.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/child_process_host.h"
@@ -64,30 +75,39 @@
#include "chrome/common/font_loader_mac.h"
#endif
#include "chrome/common/notification_service.h"
+#include "chrome/common/plugin_group.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/worker_messages.h"
#include "gfx/native_widget_types.h"
#include "net/base/cookie_monster.h"
#include "net/base/file_stream.h"
+#include "net/base/io_buffer.h"
#include "net/base/keygen_handler.h"
#include "net/base/load_flags.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/http/http_transaction_factory.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_list.h"
#include "webkit/glue/plugins/webplugin.h"
+#include "webkit/glue/webcookie.h"
#include "webkit/glue/webkit_glue.h"
+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
@@ -139,7 +159,6 @@ class WriteClipboardTask : public Task {
void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
ViewMsg_Print_Params* params) {
DCHECK(params);
-#if defined(OS_WIN) || defined(OS_MACOSX)
params->page_size = settings.page_setup_device_units().physical_size();
params->printable_size.SetSize(
settings.page_setup_device_units().content_area().width(),
@@ -156,121 +175,8 @@ void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
// Always use an invalid cookie.
params->document_cookie = 0;
params->selection_only = settings.selection_only;
-#else
- NOTIMPLEMENTED();
-#endif
}
-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)
- : render_process_id_(render_process_id),
- render_view_id_(render_view_id),
- url_(url),
- cookie_line_(cookie_line),
- context_(context) {
- }
-
- virtual void RunWithParams(const Tuple1<int>& params) {
- int result = params.a;
- bool blocked_by_policy = true;
- if (result == net::OK ||
- result == net::OK_FOR_SESSION_ONLY) {
- blocked_by_policy = false;
- net::CookieOptions options;
- 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_, blocked_by_policy);
- }
- delete this;
- }
-
- 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(const GURL& url, IPC::Message* reply_msg,
- ResourceMessageFilter* filter,
- URLRequestContext* context)
- : url_(url),
- reply_msg_(reply_msg),
- filter_(filter),
- context_(context) {
- }
-
- virtual void RunWithParams(const Tuple1<int>& params) {
- int result = params.a;
- std::string cookies;
- if (result == net::OK)
- cookies = context_->cookie_store()->GetCookies(url_);
- ViewHostMsg_GetCookies::WriteReplyParams(reply_msg_, cookies);
- filter_->Send(reply_msg_);
- delete this;
- }
-
- private:
- GURL url_;
- IPC::Message* reply_msg_;
- scoped_refptr<ResourceMessageFilter> filter_;
- scoped_refptr<URLRequestContext> context_;
-};
-
-class GetRawCookiesCompletion : public net::CompletionCallback {
- public:
- GetRawCookiesCompletion(const GURL& url, IPC::Message* reply_msg,
- ResourceMessageFilter* filter,
- URLRequestContext* context)
- : url_(url),
- reply_msg_(reply_msg),
- filter_(filter),
- context_(context) {
- }
-
- virtual void RunWithParams(const Tuple1<int>& params) {
- // 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;
- }
-
- private:
- GURL url_;
- IPC::Message* reply_msg_;
- scoped_refptr<ResourceMessageFilter> filter_;
- scoped_refptr<URLRequestContext> context_;
-};
-
class ClearCacheCompletion : public net::CompletionCallback {
public:
ClearCacheCompletion(IPC::Message* reply_msg,
@@ -291,12 +197,12 @@ class ClearCacheCompletion : public net::CompletionCallback {
};
void WriteFileSize(IPC::Message* reply_msg,
- const file_util::FileInfo& file_info) {
+ const base::PlatformFileInfo& file_info) {
ViewHostMsg_GetFileSize::WriteReplyParams(reply_msg, file_info.size);
}
void WriteFileModificationTime(IPC::Message* reply_msg,
- const file_util::FileInfo& file_info) {
+ const base::PlatformFileInfo& file_info) {
ViewHostMsg_GetFileModificationTime::WriteReplyParams(
reply_msg, file_info.last_modified);
}
@@ -310,8 +216,7 @@ ResourceMessageFilter::ResourceMessageFilter(
PluginService* plugin_service,
printing::PrintJobManager* print_job_manager,
Profile* profile,
- RenderWidgetHelper* render_widget_helper,
- URLRequestContextGetter* request_context)
+ RenderWidgetHelper* render_widget_helper)
: Receiver(RENDER_PROCESS, child_id),
channel_(NULL),
resource_dispatcher_host_(resource_dispatcher_host),
@@ -319,10 +224,8 @@ ResourceMessageFilter::ResourceMessageFilter(
print_job_manager_(print_job_manager),
profile_(profile),
ALLOW_THIS_IN_INITIALIZER_LIST(resolve_proxy_msg_helper_(this, NULL)),
- request_context_(request_context),
media_request_context_(profile->GetRequestContextForMedia()),
extensions_request_context_(profile->GetRequestContextForExtensions()),
- extensions_message_service_(profile->GetExtensionMessageService()),
render_widget_helper_(render_widget_helper),
audio_renderer_host_(audio_renderer_host),
appcache_dispatcher_host_(
@@ -330,7 +233,7 @@ ResourceMessageFilter::ResourceMessageFilter(
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->GetWebKitContext()))),
+ new IndexedDBDispatcherHost(this, profile))),
ALLOW_THIS_IN_INITIALIZER_LIST(db_dispatcher_host_(
new DatabaseDispatcherHost(profile->GetDatabaseTracker(), this,
profile->GetHostContentSettingsMap()))),
@@ -340,9 +243,25 @@ ResourceMessageFilter::ResourceMessageFilter(
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_(
GeolocationDispatcherHost::New(
- this->id(), profile->GetGeolocationPermissionContext()))) {
+ 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->GetFileSystemHostContext(),
+ profile->GetHostContentSettingsMap()))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(blob_dispatcher_host_(
+ new BlobDispatcherHost(
+ this->id(), profile->GetBlobStorageContext()))) {
+ request_context_ = profile_->GetRequestContext();
DCHECK(request_context_);
DCHECK(media_request_context_);
DCHECK(audio_renderer_host_.get());
@@ -371,6 +290,12 @@ ResourceMessageFilter::~ResourceMessageFilter() {
// 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();
+
// Let interested observers know we are being deleted.
NotificationService::current()->Notify(
NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
@@ -406,6 +331,7 @@ void ResourceMessageFilter::OnChannelConnected(int32 peer_pid) {
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());
}
void ResourceMessageFilter::OnChannelError() {
@@ -440,7 +366,13 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
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);
+ 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);
if (!handled) {
DCHECK(msg_is_ok); // It should have been marked handled if it wasn't OK.
@@ -462,12 +394,13 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
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(ViewHostMsg_GetCookiesEnabled, OnGetCookiesEnabled)
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(ViewHostMsg_LoadFont, OnLoadFont)
#endif
@@ -475,7 +408,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_PreCacheFont, OnPreCacheFont)
#endif
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPlugins, OnGetPlugins)
- IPC_MESSAGE_HANDLER(ViewHostMsg_GetPluginPath, OnGetPluginPath)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_GetPluginInfo, OnGetPluginInfo)
IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl)
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ContextMenu,
OnReceiveContextMenuMsg(msg))
@@ -560,10 +493,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ResolveProxy, OnResolveProxy)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDefaultPrintSettings,
OnGetDefaultPrintSettings)
-#if defined(OS_WIN) || defined(OS_MACOSX)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ScriptedPrint,
OnScriptedPrint)
-#endif
#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB,
OnAllocTransportDIB)
@@ -579,6 +510,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
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_GetFileSize, OnGetFileSize)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileModificationTime,
OnGetFileModificationTime)
@@ -593,6 +525,7 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
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()
@@ -662,6 +595,12 @@ void ResourceMessageFilter::OnMsgCreateWidget(int opener_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,
@@ -669,16 +608,22 @@ void ResourceMessageFilter::OnSetCookie(const IPC::Message& message,
ChromeURLRequestContext* context = GetRequestContextForURL(url);
SetCookieCompletion* callback =
- new SetCookieCompletion(id(), message.routing_id(), url, cookie, context);
-
- 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;
+ 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);
}
- callback->Run(policy);
}
void ResourceMessageFilter::OnGetCookies(const GURL& url,
@@ -687,18 +632,23 @@ void ResourceMessageFilter::OnGetCookies(const GURL& url,
URLRequestContext* context = GetRequestContextForURL(url);
GetCookiesCompletion* callback =
- new GetCookiesCompletion(url, reply_msg, this, context);
-
- 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;
+ 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);
}
- callback->Run(policy);
}
void ResourceMessageFilter::OnGetRawCookies(
@@ -721,8 +671,9 @@ void ResourceMessageFilter::OnGetRawCookies(
return;
}
- GetRawCookiesCompletion* callback =
- new GetRawCookiesCompletion(url, reply_msg, this, context);
+ 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
@@ -745,13 +696,6 @@ void ResourceMessageFilter::OnDeleteCookie(const GURL& url,
context->cookie_store()->DeleteCookie(url, cookie_name);
}
-void ResourceMessageFilter::OnGetCookiesEnabled(
- const GURL& url,
- const GURL& first_party_for_cookies,
- bool* enabled) {
- *enabled = GetRequestContextForURL(url)->AreCookiesEnabled();
-}
-
#if defined(OS_MACOSX)
void ResourceMessageFilter::OnLoadFont(const FontDescriptor& font,
uint32* handle_size,
@@ -781,6 +725,22 @@ void ResourceMessageFilter::OnPreCacheFont(LOGFONT font) {
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;
+ }
+
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(
@@ -799,18 +759,41 @@ void ResourceMessageFilter::OnGetPluginsOnFileThread(
NewRunnableMethod(this, &ResourceMessageFilter::Send, reply_msg));
}
-void ResourceMessageFilter::OnGetPluginPath(const GURL& url,
+void ResourceMessageFilter::OnGetPluginInfo(const GURL& url,
const GURL& policy_url,
const std::string& mime_type,
- FilePath* filename,
- std::string* url_mime_type) {
- *filename = plugin_service_->GetPluginPath(
- url, policy_url, mime_type, url_mime_type);
+ bool* found,
+ WebPluginInfo* info,
+ ContentSetting* setting,
+ std::string* actual_mime_type) {
+ bool allow_wildcard = true;
+ *found = NPAPI::PluginList::Singleton()->GetPluginInfo(url,
+ mime_type,
+ allow_wildcard,
+ info,
+ actual_mime_type);
+ if (*found) {
+ info->enabled = info->enabled &&
+ plugin_service_->PrivatePluginAllowedForURL(info->path, policy_url);
+ HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
+ scoped_ptr<PluginGroup> group(PluginGroup::CopyOrCreatePluginGroup(*info));
+ std::string resource = group->identifier();
+ *setting = map->GetNonDefaultContentSetting(
+ policy_url, CONTENT_SETTINGS_TYPE_PLUGINS, resource);
+ if (*setting == CONTENT_SETTING_DEFAULT) {
+ ContentSetting defaultContentSetting =
+ map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ if (defaultContentSetting == CONTENT_SETTING_BLOCK ||
+ !map->GetBlockNonsandboxedPlugins()) {
+ *setting = defaultContentSetting;
+ }
+ }
+ }
}
void ResourceMessageFilter::OnOpenChannelToPlugin(const GURL& url,
const std::string& mime_type,
- const std::wstring& locale,
+ const std::string& locale,
IPC::Message* reply_msg) {
plugin_service_->OpenChannelToPlugin(
this, url, mime_type, locale, reply_msg);
@@ -1052,7 +1035,7 @@ void ResourceMessageFilter::OnAllocateSharedMemoryBuffer(
uint32 buffer_size,
base::SharedMemoryHandle* handle) {
base::SharedMemory shared_buf;
- shared_buf.Create(L"", false, false, buffer_size);
+ shared_buf.Create("", false, false, buffer_size);
if (!shared_buf.Map(buffer_size)) {
*handle = base::SharedMemory::NULLHandle();
NOTREACHED() << "Cannot map shared memory buffer";
@@ -1114,7 +1097,7 @@ void ResourceMessageFilter::OnV8HeapStatsOnUIThread(
void ResourceMessageFilter::OnDidZoomURL(const GURL& url,
int zoom_level) {
- ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
+ ui_thread_helpers::PostTaskWhileRunningMenu(FROM_HERE,
NewRunnableMethod(this,
&ResourceMessageFilter::UpdateHostZoomLevelsOnUIThread,
url, zoom_level));
@@ -1192,8 +1175,6 @@ void ResourceMessageFilter::OnGetDefaultPrintSettingsReply(
}
}
-#if defined(OS_WIN) || defined(OS_MACOSX)
-
void ResourceMessageFilter::OnScriptedPrint(
const ViewHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg) {
@@ -1244,8 +1225,6 @@ void ResourceMessageFilter::OnScriptedPrintReply(
}
}
-#endif // OS_WIN || OS_MACOSX
-
// static
Clipboard* ResourceMessageFilter::GetClipboard() {
// We have a static instance of the clipboard service for use by all message
@@ -1324,24 +1303,52 @@ 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) {
- if (extensions_message_service_.get()) {
- *port_id = extensions_message_service_->
- OpenChannelToExtension(routing_id, source_extension_id,
- target_extension_id, channel_name, this);
- } else {
- *port_id = -1;
- }
+ int port2_id;
+ ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
+
+ ChromeThread::PostTask(
+ ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::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) {
- if (extensions_message_service_.get()) {
- *port_id = extensions_message_service_->
- OpenChannelToTab(routing_id, tab_id, extension_id, channel_name, this);
- } else {
- *port_id = -1;
- }
+ int port2_id;
+ ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
+
+ ChromeThread::PostTask(
+ ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ profile_->GetExtensionMessageService()->OpenChannelToTab(
+ source_process_id, source_routing_id, receiver_port_id,
+ tab_id, extension_id, channel_name);
}
bool ResourceMessageFilter::CheckBenchmarkingEnabled() const {
@@ -1428,11 +1435,21 @@ void ResourceMessageFilter::OnCacheableMetadataAvailable(
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::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()->CanUploadFile(id(), path)) {
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path)) {
ViewHostMsg_GetFileSize::WriteReplyParams(
reply_msg, static_cast<int64>(-1));
Send(reply_msg);
@@ -1452,7 +1469,7 @@ void ResourceMessageFilter::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()->CanUploadFile(id(), path)) {
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path)) {
ViewHostMsg_GetFileModificationTime::WriteReplyParams(reply_msg,
base::Time());
Send(reply_msg);
@@ -1474,7 +1491,7 @@ void ResourceMessageFilter::OnGetFileInfoOnFileThread(
FileInfoWriteFunc write_func) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- file_util::FileInfo file_info;
+ base::PlatformFileInfo file_info;
file_info.size = 0;
file_util::GetFileInfo(path, &file_info);
@@ -1491,7 +1508,7 @@ void ResourceMessageFilter::OnOpenFile(const FilePath& path,
// 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()->CanUploadFile(id(), path)) {
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path)) {
ViewHostMsg_OpenFile::WriteReplyParams(
reply_msg,
#if defined(OS_WIN)
@@ -1523,7 +1540,7 @@ void ResourceMessageFilter::OnOpenFileOnFileThread(const FilePath& path,
(mode == 0) ? (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)
: (base::PLATFORM_FILE_CREATE_ALWAYS |
base::PLATFORM_FILE_WRITE),
- NULL);
+ NULL, NULL);
base::PlatformFile target_file_handle;
#if defined(OS_WIN)
@@ -1579,7 +1596,7 @@ void ResourceMessageFilter::OnKeygen(uint32 key_size_index,
FROM_HERE,
NewRunnableMethod(
this, &ResourceMessageFilter::OnKeygenOnWorkerThread,
- key_size_in_bits, challenge_string, reply_msg),
+ 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());
@@ -1591,13 +1608,14 @@ void ResourceMessageFilter::OnKeygen(uint32 key_size_index,
void ResourceMessageFilter::OnKeygenOnWorkerThread(
int key_size_in_bits,
const std::string& challenge_string,
+ const GURL& url,
IPC::Message* reply_msg) {
DCHECK(reply_msg);
// Verify we are on a worker thread.
DCHECK(!MessageLoop::current());
// Generate a signed public key and challenge, then send it back.
- net::KeygenHandler keygen_handler(key_size_in_bits, challenge_string);
+ net::KeygenHandler keygen_handler(key_size_in_bits, challenge_string, url);
ViewHostMsg_Keygen::WriteReplyParams(
reply_msg,
@@ -1677,3 +1695,147 @@ void ResourceMessageFilter::OnGetExtensionMessageBundleOnFileThread(
ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::IO));
+
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path)) {
+ IPC::Message* reply = new ViewMsg_AsyncOpenFile_ACK(
+ msg.routing_id(), base::PLATFORM_FILE_ERROR_ACCESS_DENIED,
+ IPC::InvalidPlatformFileForTransit(), message_id);
+ Send(reply);
+ return;
+ }
+
+ // TODO(dumi): update this check once we have a security attribute
+ // that allows renderers to modify files.
+ int allowed_flags =
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_EXCLUSIVE_READ |
+ base::PLATFORM_FILE_ASYNC;
+ if (flags & ~allowed_flags) {
+ DLOG(ERROR) << "Bad flags in ViewMsgHost_AsyncOpenFile message: " << flags;
+ BrowserRenderProcessHost::BadMessageTerminateProcess(
+ ViewHostMsg_AsyncOpenFile::ID, handle());
+ return;
+ }
+
+ ChromeThread::PostTask(
+ ChromeThread::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(ChromeThread::CurrentlyOn(ChromeThread::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);
+ ChromeThread::PostTask(
+ ChromeThread::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) {
+}
+
+void SetCookieCompletion::RunWithParams(const Tuple1<int>& params) {
+ int result = params.a;
+ bool blocked_by_policy = true;
+ if (result == net::OK ||
+ result == net::OK_FOR_SESSION_ONLY) {
+ blocked_by_policy = false;
+ net::CookieOptions options;
+ 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_, 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());
+}
+
+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;
+}
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index 72bf9b3..3dd76bb 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -4,6 +4,7 @@
#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>
@@ -23,7 +24,7 @@
#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/window_container_type.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"
@@ -31,10 +32,11 @@
class AppCacheDispatcherHost;
class AudioRendererHost;
+class BlobDispatcherHost;
class ChromeURLRequestContext;
class DatabaseDispatcherHost;
class DOMStorageDispatcherHost;
-class ExtensionMessageService;
+class FileSystemDispatcherHost;
struct FontDescriptor;
class GeolocationDispatcherHost;
class HostZoomMap;
@@ -42,17 +44,23 @@ class IndexedDBDispatcherHost;
class NotificationsPrefsCache;
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 file_util {
-struct FileInfo;
+namespace device_orientation {
+class DispatcherHost;
+}
+
+namespace net {
+class CookieStore;
}
namespace printing {
@@ -60,6 +68,10 @@ class PrinterQuery;
class PrintJobManager;
}
+namespace speech_input {
+class SpeechInputDispatcherHost;
+}
+
namespace webkit_glue {
struct WebCookie;
}
@@ -86,8 +98,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
PluginService* plugin_service,
printing::PrintJobManager* print_job_manager,
Profile* profile,
- RenderWidgetHelper* render_widget_helper,
- URLRequestContextGetter* request_context);
+ RenderWidgetHelper* render_widget_helper);
// IPC::ChannelProxy::MessageFilter methods:
virtual void OnFilterAdded(IPC::Channel* channel);
@@ -120,7 +131,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
friend class ChromeThread;
friend class DeleteTask<ResourceMessageFilter>;
typedef void (*FileInfoWriteFunc)(IPC::Message* reply_msg,
- const file_util::FileInfo& file_info);
+ const base::PlatformFileInfo& file_info);
virtual ~ResourceMessageFilter();
@@ -130,6 +141,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
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,
@@ -142,9 +156,6 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
IPC::Message* reply_msg);
void OnDeleteCookie(const GURL& url,
const std::string& cookieName);
- void OnGetCookiesEnabled(const GURL& url,
- const GURL& first_party_for_cookies,
- bool* enabled);
void OnPluginFileDialog(const IPC::Message& msg,
bool multiple_files,
const std::wstring& title,
@@ -169,14 +180,16 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
#endif
void OnGetPlugins(bool refresh, IPC::Message* reply_msg);
void OnGetPluginsOnFileThread(bool refresh, IPC::Message* reply_msg);
- void OnGetPluginPath(const GURL& url,
+ void OnGetPluginInfo(const GURL& url,
const GURL& policy_url,
const std::string& mime_type,
- FilePath* filename,
+ bool* found,
+ WebPluginInfo* info,
+ ContentSetting* setting,
std::string* actual_mime_type);
void OnOpenChannelToPlugin(const GURL& url,
const std::string& mime_type,
- const std::wstring& locale,
+ const std::string& locale,
IPC::Message* reply_msg);
void OnLaunchNaCl(const std::wstring& url,
int channel_descriptor,
@@ -290,7 +303,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnGetDefaultPrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
-#if defined(OS_WIN) || defined(OS_MACOSX)
+
// 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.
@@ -300,7 +313,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
scoped_refptr<printing::PrinterQuery> printer_query,
int routing_id,
IPC::Message* reply_msg);
-#endif
+
// Browser side transport DIB allocation
void OnAllocTransportDIB(size_t size,
bool cache_in_browser,
@@ -311,9 +324,19 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
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);
@@ -321,6 +344,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnCacheableMetadataAvailable(const GURL& url,
double expected_response_time,
const std::vector<char>& data);
+ void OnEnableSpdy(bool enable);
void OnGetFileSize(const FilePath& path, IPC::Message* reply_msg);
void OnGetFileModificationTime(const FilePath& path, IPC::Message* reply_msg);
void OnGetFileInfoOnFileThread(const FilePath& path,
@@ -335,6 +359,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
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);
@@ -346,6 +371,15 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
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);
@@ -404,9 +438,6 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
// A request context that holds a cookie store for chrome-extension URLs.
scoped_refptr<URLRequestContextGetter> extensions_request_context_;
- // Used for routing extension messages.
- scoped_refptr<ExtensionMessageService> extensions_message_service_;
-
scoped_refptr<RenderWidgetHelper> render_widget_helper_;
// Object that should take care of audio related resource requests.
@@ -436,13 +467,97 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
bool cloud_print_enabled_;
+ base::TimeTicks last_plugin_refresh_time_; // Initialized to 0.
+
// 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<GeolocationDispatcherHost> 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_;
+
DISALLOW_COPY_AND_ASSIGN(ResourceMessageFilter);
};
+// 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 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,
+ ResourceMessageFilter* filter,
+ URLRequestContext* context,
+ bool raw_cookies);
+
+ 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<ResourceMessageFilter> filter_;
+ scoped_refptr<URLRequestContext> context_;
+ int render_process_id_;
+ int render_view_id_;
+ bool raw_cookies_;
+ scoped_refptr<net::CookieStore> cookie_store_;
+};
+
#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
index dcd3d19..5562e46 100644
--- a/chrome/browser/renderer_host/resource_message_filter_gtk.cc
+++ b/chrome/browser/renderer_host/resource_message_filter_gtk.cc
@@ -8,7 +8,6 @@
#include <map>
#include "app/clipboard/clipboard.h"
-#include "app/l10n_util.h"
#include "app/x11_util.h"
#include "base/file_util.h"
#include "base/path_service.h"
diff --git a/chrome/browser/renderer_host/resource_message_filter_win.cc b/chrome/browser/renderer_host/resource_message_filter_win.cc
index aa53422..4a8c46e 100644
--- a/chrome/browser/renderer_host/resource_message_filter_win.cc
+++ b/chrome/browser/renderer_host/resource_message_filter_win.cc
@@ -4,6 +4,7 @@
#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;
diff --git a/chrome/browser/renderer_host/resource_queue.h b/chrome/browser/renderer_host/resource_queue.h
index a853d56..bd71150 100644
--- a/chrome/browser/renderer_host/resource_queue.h
+++ b/chrome/browser/renderer_host/resource_queue.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_QUEUE_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_QUEUE_H_
+#pragma once
#include <map>
#include <set>
diff --git a/chrome/browser/renderer_host/resource_queue_unittest.cc b/chrome/browser/renderer_host/resource_queue_unittest.cc
index 2a6891d..1f002d5 100644
--- a/chrome/browser/renderer_host/resource_queue_unittest.cc
+++ b/chrome/browser/renderer_host/resource_queue_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/renderer_host/global_request_id.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
diff --git a/chrome/browser/renderer_host/resource_request_details.h b/chrome/browser/renderer_host/resource_request_details.h
index 5310b5b..6af9f85 100644
--- a/chrome/browser/renderer_host/resource_request_details.h
+++ b/chrome/browser/renderer_host/resource_request_details.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_REQUEST_DETAILS_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_REQUEST_DETAILS_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
index 67d4b9f..3222ecc 100644
--- a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
#include "base/logging.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/notification_service.h"
@@ -114,11 +115,7 @@ bool SafeBrowsingResourceHandler::OnWillRead(int request_id,
int min_size) {
CHECK(state_ == STATE_NONE);
CHECK(defer_state_ == DEFERRED_NONE);
- bool rv = next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
- // TODO(willchan): Remove after debugging bug 16371.
- if (rv)
- CHECK((*buf)->data());
- return rv;
+ return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
}
bool SafeBrowsingResourceHandler::OnReadCompleted(int request_id,
@@ -173,12 +170,22 @@ void SafeBrowsingResourceHandler::StartDisplayingBlockingPage(
SafeBrowsingService::UrlCheckResult result) {
CHECK(state_ == STATE_NONE);
CHECK(defer_state_ != DEFERRED_NONE);
+ CHECK(deferred_request_id_ != -1);
state_ = STATE_DISPLAYING_BLOCKING_PAGE;
AddRef(); // Balanced in OnBlockingPageComplete().
+ // Grab the original url of this request as well.
+ GURL original_url;
+ URLRequest* request = rdh_->GetURLRequest(
+ GlobalRequestID(render_process_host_id_, deferred_request_id_));
+ if (request)
+ original_url = request->original_url();
+ else
+ original_url = url;
+
safe_browsing_->DisplayBlockingPage(
- url, resource_type_, result, this, render_process_host_id_,
+ url, original_url, resource_type_, result, this, render_process_host_id_,
render_view_id_);
}
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.h b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
index b113635..14ddd4b 100644
--- a/chrome/browser/renderer_host/safe_browsing_resource_handler.h
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_SAFE_BROWSING_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_SAFE_BROWSING_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
@@ -13,6 +14,7 @@
#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"
// SafeBrowsingResourceHandler checks that URLs are "safe" before navigating
diff --git a/chrome/browser/renderer_host/save_file_resource_handler.cc b/chrome/browser/renderer_host/save_file_resource_handler.cc
index fe8aaf9..b71181a 100644
--- a/chrome/browser/renderer_host/save_file_resource_handler.cc
+++ b/chrome/browser/renderer_host/save_file_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.
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/download/save_file_manager.h"
#include "net/base/io_buffer.h"
@@ -74,8 +74,6 @@ bool SaveFileResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
read_buffer_ = new net::IOBuffer(*buf_size);
}
*buf = read_buffer_.get();
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(read_buffer_->data());
return true;
}
@@ -115,5 +113,5 @@ void SaveFileResourceHandler::OnRequestClosed() {
void SaveFileResourceHandler::set_content_length(
const std::string& content_length) {
- content_length_ = StringToInt64(content_length);
+ base::StringToInt64(content_length, &content_length_);
}
diff --git a/chrome/browser/renderer_host/save_file_resource_handler.h b/chrome/browser/renderer_host/save_file_resource_handler.h
index 436e4df..ecd8a93 100644
--- a/chrome/browser/renderer_host/save_file_resource_handler.h
+++ b/chrome/browser/renderer_host/save_file_resource_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_SAVE_FILE_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/renderer_host/site_instance.h b/chrome/browser/renderer_host/site_instance.h
index 3be920c..df7f69c 100644
--- a/chrome/browser/renderer_host/site_instance.h
+++ b/chrome/browser/renderer_host/site_instance.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_SITE_INSTANCE_H_
#define CHROME_BROWSER_RENDERER_HOST_SITE_INSTANCE_H_
+#pragma once
#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/renderer_host/socket_stream_dispatcher_host.h b/chrome/browser/renderer_host/socket_stream_dispatcher_host.h
index 2fd8109..ed4c461 100644
--- a/chrome/browser/renderer_host/socket_stream_dispatcher_host.h
+++ b/chrome/browser/renderer_host/socket_stream_dispatcher_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_SOCKET_STREAM_DISPATCHER_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_SOCKET_STREAM_DISPATCHER_HOST_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/renderer_host/socket_stream_host.h b/chrome/browser/renderer_host/socket_stream_host.h
index b583700..48a8e1b 100644
--- a/chrome/browser/renderer_host/socket_stream_host.h
+++ b/chrome/browser/renderer_host/socket_stream_host.h
@@ -4,15 +4,20 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_SOCKET_STREAM_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_SOCKET_STREAM_HOST_H_
+#pragma once
#include <vector>
#include "base/ref_counted.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "net/socket_stream/socket_stream_job.h"
+#include "net/socket_stream/socket_stream.h"
class GURL;
+namespace net {
+class SocketStreamJob;
+}
+
// Host of SocketStreamHandle.
// Each SocketStreamHandle will have an unique socket_id assigned by
// SocketStreamHost constructor. If socket id is chrome_common_net::kNoSocketId,
diff --git a/chrome/browser/renderer_host/sync_resource_handler.cc b/chrome/browser/renderer_host/sync_resource_handler.cc
index 235a22f..16c057a 100644
--- a/chrome/browser/renderer_host/sync_resource_handler.cc
+++ b/chrome/browser/renderer_host/sync_resource_handler.cc
@@ -3,16 +3,25 @@
// found in the LICENSE file.
#include "chrome/browser/renderer_host/sync_resource_handler.h"
+
#include "base/logging.h"
+#include "chrome/browser/net/load_timing_observer.h"
+#include "chrome/browser/renderer_host/global_request_id.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,
const GURL& url,
- IPC::Message* result_message)
+ IPC::Message* result_message,
+ ResourceDispatcherHost* resource_dispatcher_host)
: read_buffer_(new net::IOBuffer(kReadBufSize)),
receiver_(receiver),
- result_message_(result_message) {
+ process_id_(process_id),
+ result_message_(result_message),
+ rdh_(resource_dispatcher_host) {
result_.final_url = url;
}
@@ -29,6 +38,10 @@ bool SyncResourceHandler::OnRequestRedirected(int request_id,
const GURL& new_url,
ResourceResponse* response,
bool* defer) {
+ URLRequest* request = rdh_->GetURLRequest(
+ GlobalRequestID(process_id_, request_id));
+ LoadTimingObserver::PopulateTimingInfo(request, response);
+
// TODO(darin): It would be much better if this could live in WebCore, but
// doing so requires API changes at all levels. Similar code exists in
// WebCore/platform/network/cf/ResourceHandleCFNet.cpp :-(
@@ -42,10 +55,20 @@ bool SyncResourceHandler::OnRequestRedirected(int request_id,
bool SyncResourceHandler::OnResponseStarted(int request_id,
ResourceResponse* response) {
+ URLRequest* request = rdh_->GetURLRequest(
+ GlobalRequestID(process_id_, request_id));
+ LoadTimingObserver::PopulateTimingInfo(request, response);
+
// We don't care about copying the status here.
result_.headers = response->response_head.headers;
result_.mime_type = response->response_head.mime_type;
result_.charset = response->response_head.charset;
+ result_.download_file_path = response->response_head.download_file_path;
+ result_.request_time = response->response_head.request_time;
+ result_.response_time = response->response_head.response_time;
+ result_.connection_id = response->response_head.connection_id;
+ result_.connection_reused = response->response_head.connection_reused;
+ result_.load_timing = response->response_head.load_timing;
return true;
}
@@ -59,8 +82,6 @@ bool SyncResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
int* buf_size, int min_size) {
DCHECK(min_size == -1);
*buf = read_buffer_.get();
- // TODO(willchan): Remove after debugging bug 16371.
- CHECK(read_buffer_->data());
*buf_size = kReadBufSize;
return true;
}
diff --git a/chrome/browser/renderer_host/sync_resource_handler.h b/chrome/browser/renderer_host/sync_resource_handler.h
index 683dd3d..6f86de7 100644
--- a/chrome/browser/renderer_host/sync_resource_handler.h
+++ b/chrome/browser/renderer_host/sync_resource_handler.h
@@ -4,21 +4,27 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_SYNC_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_SYNC_RESOURCE_HANDLER_H_
+#pragma once
#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"
-#include "net/base/io_buffer.h"
+
+namespace net {
+class IOBuffer;
+}
// Used to complete a synchronous resource request in response to resource load
// events from the resource dispatcher host.
class SyncResourceHandler : public ResourceHandler {
public:
SyncResourceHandler(ResourceDispatcherHost::Receiver* receiver,
+ int process_id,
const GURL& url,
- IPC::Message* result_message);
+ 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,
@@ -42,7 +48,9 @@ class SyncResourceHandler : public ResourceHandler {
SyncLoadResult result_;
ResourceDispatcherHost::Receiver* receiver_;
+ int process_id_;
IPC::Message* result_message_;
+ ResourceDispatcherHost* rdh_;
};
#endif // CHROME_BROWSER_RENDERER_HOST_SYNC_RESOURCE_HANDLER_H_
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 0dd81be..78409dd 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
@@ -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 "base/file_util.h"
+#include "base/path_service.h"
+#include "base/ref_counted.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
@@ -18,6 +21,7 @@
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/net_util.h"
+#include "net/test/test_server.h"
class RenderViewHostManagerTest : public InProcessBrowserTest {
public:
@@ -31,14 +35,14 @@ class RenderViewHostManagerTest : public InProcessBrowserTest {
IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
SwapProcessWithRelNoreferrerAndTargetBlank) {
// Start two servers with different sites.
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> http_server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- scoped_refptr<HTTPSTestServer> https_server =
- HTTPSTestServer::CreateGoodServer(kDocRoot);
+ ASSERT_TRUE(test_server()->Start());
+ net::TestServer https_server_(
+ net::TestServer::TYPE_HTTPS,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(https_server_.Start());
// Load a page with links that open in a new window.
- ui_test_utils::NavigateToURL(browser(), http_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(
"files/click-noreferrer-links.html"));
// Get the original SiteInstance for later comparison.
@@ -74,14 +78,14 @@ IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
DontSwapProcessWithOnlyTargetBlank) {
// Start two servers with different sites.
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> http_server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- scoped_refptr<HTTPSTestServer> https_server =
- HTTPSTestServer::CreateGoodServer(kDocRoot);
+ ASSERT_TRUE(test_server()->Start());
+ net::TestServer https_server_(
+ net::TestServer::TYPE_HTTPS,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(https_server_.Start());
// Load a page with links that open in a new window.
- ui_test_utils::NavigateToURL(browser(), http_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(
"files/click-noreferrer-links.html"));
// Get the original SiteInstance for later comparison.
@@ -117,14 +121,14 @@ IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
DontSwapProcessWithOnlyRelNoreferrer) {
// Start two servers with different sites.
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> http_server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- scoped_refptr<HTTPSTestServer> https_server =
- HTTPSTestServer::CreateGoodServer(kDocRoot);
+ ASSERT_TRUE(test_server()->Start());
+ net::TestServer https_server_(
+ net::TestServer::TYPE_HTTPS,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(https_server_.Start());
// Load a page with links that open in a new window.
- ui_test_utils::NavigateToURL(browser(), http_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(
"files/click-noreferrer-links.html"));
// Get the original SiteInstance for later comparison.
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 c281d63..2ec5b95 100644
--- a/chrome/browser/renderer_host/test/render_view_host_unittest.cc
+++ b/chrome/browser/renderer_host/test/render_view_host_unittest.cc
@@ -3,7 +3,9 @@
// found in the LICENSE file.
#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/test_tab_contents.h"
#include "chrome/common/render_messages.h"
class RenderViewHostTest : public RenderViewHostTestHarness {
@@ -17,6 +19,43 @@ TEST_F(RenderViewHostTest, FilterAbout) {
EXPECT_EQ(GURL("about:blank"), controller().GetActiveEntry()->url());
}
+// Create a full screen popup RenderWidgetHost and View.
+TEST_F(RenderViewHostTest, CreateFullscreenWidget) {
+ int routing_id = process()->GetNextRoutingID();
+ rvh()->CreateNewFullscreenWidget(routing_id, WebKit::WebPopupTypeNone);
+}
+
+// Makes sure that RenderViewHost::is_waiting_for_unload_ack_ is false when
+// reloading a page. If is_waiting_for_unload_ack_ is not false when reloading
+// the tab may get closed out even though the user pressed the reload button.
+TEST_F(RenderViewHostTest, ResetUnloadOnReload) {
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+
+ // This test is for a subtle timing bug. Here's the sequence that triggered
+ // the bug:
+ // . go to a page.
+ // . go to a new page, preferably one that takes a while to resolve, such
+ // as one on a site that doesn't exist.
+ // . After this step is_waiting_for_unload_ack_ has been set to true on
+ // the first RVH.
+ // . click stop before the page has been commited.
+ // . click reload.
+ // . is_waiting_for_unload_ack_ is still true, and the if the hang monitor
+ // fires the tab gets closed.
+
+ NavigateAndCommit(url1);
+ controller().LoadURL(url2, GURL(), 0);
+ // Simulate the ClosePage call which is normally sent by the URLRequest.
+ rvh()->ClosePage(true, 0, 0);
+ // Needed so that navigations are not suspended on the RVH. Normally handled
+ // by way of ViewHostMsg_ShouldClose_ACK.
+ contents()->render_manager()->ShouldClosePage(true, true);
+ contents()->Stop();
+ controller().Reload(false);
+ EXPECT_FALSE(rvh()->is_waiting_for_unload_ack());
+}
+
// The test that follow trigger DCHECKS in debug build.
#if defined(NDEBUG)
diff --git a/chrome/browser/renderer_host/test/site_instance_unittest.cc b/chrome/browser/renderer_host/test/site_instance_unittest.cc
index cf5c154..fb0e2da 100644
--- a/chrome/browser/renderer_host/test/site_instance_unittest.cc
+++ b/chrome/browser/renderer_host/test/site_instance_unittest.cc
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/stl_util-inl.h"
#include "base/string16.h"
#include "chrome/browser/browsing_instance.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
@@ -73,7 +75,7 @@ class TestSiteInstance : public SiteInstance {
// Test to ensure no memory leaks for SiteInstance objects.
TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
- // The existance of these factories will cause TabContents to create our test
+ // The existence of these factories will cause TabContents to create our test
// one instead of the real one.
MockRenderProcessHostFactory rph_factory;
TestRenderViewHostFactory rvh_factory(&rph_factory);
@@ -117,7 +119,7 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
&siteDeleteCounter,
&browsingDeleteCounter);
{
- TabContents contents(profile.get(), instance, MSG_ROUTING_NONE, NULL);
+ TabContents contents(profile.get(), instance, MSG_ROUTING_NONE, NULL, NULL);
EXPECT_EQ(1, siteDeleteCounter);
EXPECT_EQ(1, browsingDeleteCounter);
}
diff --git a/chrome/browser/renderer_host/test/test_backing_store.h b/chrome/browser/renderer_host/test/test_backing_store.h
index 41deb4c..f9db76e 100644
--- a/chrome/browser/renderer_host/test/test_backing_store.h
+++ b/chrome/browser/renderer_host/test/test_backing_store.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_TEST_TEST_BACKING_STORE_H_
#define CHROME_BROWSER_RENDERER_HOST_TEST_TEST_BACKING_STORE_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/renderer_host/backing_store.h"
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 ac4efda..70d6a9c 100644
--- a/chrome/browser/renderer_host/test/test_render_view_host.cc
+++ b/chrome/browser/renderer_host/test/test_render_view_host.cc
@@ -5,12 +5,17 @@
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/browser_url_handler.h"
+#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/test/test_backing_store.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/common/dom_storage_common.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "chrome/test/testing_profile.h"
#include "gfx/rect.h"
#include "webkit/glue/webpreferences.h"
+#include "webkit/glue/password_form.h"
using webkit_glue::PasswordForm;
@@ -29,6 +34,7 @@ void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params,
params->password_form = PasswordForm();
params->security_info = std::string();
params->gesture = NavigationGestureUser;
+ params->was_within_same_page = false;
params->is_post = false;
}
@@ -50,8 +56,7 @@ TestRenderViewHost::~TestRenderViewHost() {
delete view();
}
-bool TestRenderViewHost::CreateRenderView(
- URLRequestContextGetter* request_context, const string16& frame_name) {
+bool TestRenderViewHost::CreateRenderView(const string16& frame_name) {
DCHECK(!render_view_created_);
render_view_created_ = true;
process()->ViewCreated();
@@ -88,6 +93,7 @@ void TestRenderViewHost::SendNavigateWithTransition(
params.contents_mime_type = std::string();
params.is_post = false;
params.is_content_filtered = false;
+ params.was_within_same_page = false;
params.http_status_code = 0;
ViewHostMsg_FrameNavigate msg(1, params);
@@ -99,6 +105,10 @@ TestRenderWidgetHostView::TestRenderWidgetHostView(RenderWidgetHost* rwh)
is_showing_(false) {
}
+gfx::Rect TestRenderWidgetHostView::GetViewBounds() const {
+ return gfx::Rect();
+}
+
BackingStore* TestRenderWidgetHostView::AllocBackingStore(
const gfx::Size& size) {
return new TestBackingStore(rwh_, size);
@@ -111,6 +121,16 @@ VideoLayer* TestRenderWidgetHostView::AllocVideoLayer(
}
#if defined(OS_MACOSX)
+
+void TestRenderWidgetHostView::ShowPopupWithItems(
+ gfx::Rect bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<WebMenuItem>& items,
+ bool right_aligned) {
+}
+
gfx::Rect TestRenderWidgetHostView::GetWindowRect() {
return gfx::Rect();
}
@@ -124,7 +144,9 @@ void TestRenderWidgetHostView::SetActive(bool active) {
}
gfx::PluginWindowHandle
-TestRenderWidgetHostView::AllocateFakePluginWindowHandle(bool opaque) {
+TestRenderWidgetHostView::AllocateFakePluginWindowHandle(
+ bool opaque,
+ bool root) {
return NULL;
}
@@ -150,28 +172,80 @@ void TestRenderWidgetHostView::AcceleratedSurfaceBuffersSwapped(
gfx::PluginWindowHandle window) {
}
-void TestRenderWidgetHostView::DrawAcceleratedSurfaceInstances(
- CGLContextObj context) {
+void TestRenderWidgetHostView::GpuRenderingStateDidChange() {
}
#endif
-void RenderViewHostTestHarness::NavigateAndCommit(const GURL& url) {
- controller().LoadURL(url, GURL(), 0);
- GURL loaded_url(url);
- bool reverse_on_redirect = false;
- BrowserURLHandler::RewriteURLIfNecessary(
- &loaded_url, profile(), &reverse_on_redirect);
- rvh()->SendNavigate(process()->max_page_id() + 1, loaded_url);
+TestRenderViewHostFactory::TestRenderViewHostFactory(
+ RenderProcessHostFactory* rph_factory)
+ : render_process_host_factory_(rph_factory) {
+ RenderViewHostFactory::RegisterFactory(this);
}
-void RenderViewHostTestHarness::Reload() {
- NavigationEntry* entry = controller().GetLastCommittedEntry();
- DCHECK(entry);
- controller().Reload(false);
- rvh()->SendNavigate(entry->page_id(), entry->url());
+TestRenderViewHostFactory::~TestRenderViewHostFactory() {
+ RenderViewHostFactory::UnregisterFactory();
}
-void RenderViewHostTestHarness::SetUp() {
+void TestRenderViewHostFactory::set_render_process_host_factory(
+ RenderProcessHostFactory* rph_factory) {
+ render_process_host_factory_ = rph_factory;
+}
+
+RenderViewHost* TestRenderViewHostFactory::CreateRenderViewHost(
+ SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ int routing_id,
+ SessionStorageNamespace* session_storage) {
+ // See declaration of render_process_host_factory_ below.
+ instance->set_render_process_host_factory(render_process_host_factory_);
+ return new TestRenderViewHost(instance, delegate, routing_id);
+}
+
+RenderViewHostTestHarness::RenderViewHostTestHarness()
+ : rph_factory_(),
+ rvh_factory_(&rph_factory_),
+ contents_(NULL) {
+}
+
+RenderViewHostTestHarness::~RenderViewHostTestHarness() {
+}
+
+NavigationController& RenderViewHostTestHarness::controller() {
+ return contents_->controller();
+}
+
+TestTabContents* RenderViewHostTestHarness::contents() {
+ return contents_.get();
+}
+
+TestRenderViewHost* RenderViewHostTestHarness::rvh() {
+ return static_cast<TestRenderViewHost*>(contents_->render_view_host());
+}
+
+TestRenderViewHost* RenderViewHostTestHarness::pending_rvh() {
+ return static_cast<TestRenderViewHost*>(
+ contents_->render_manager()->pending_render_view_host());
+}
+
+TestRenderViewHost* RenderViewHostTestHarness::active_rvh() {
+ return pending_rvh() ? pending_rvh() : rvh();
+}
+
+TestingProfile* RenderViewHostTestHarness::profile() {
+ return profile_.get();
+}
+
+MockRenderProcessHost* RenderViewHostTestHarness::process() {
+ if (pending_rvh())
+ return static_cast<MockRenderProcessHost*>(pending_rvh()->process());
+ return static_cast<MockRenderProcessHost*>(rvh()->process());
+}
+
+void RenderViewHostTestHarness::DeleteContents() {
+ contents_.reset();
+}
+
+TestTabContents* RenderViewHostTestHarness::CreateTestTabContents() {
// See comment above profile_ decl for why we check for NULL here.
if (!profile_.get())
profile_.reset(new TestingProfile());
@@ -179,7 +253,22 @@ void RenderViewHostTestHarness::SetUp() {
// This will be deleted when the TabContents goes away.
SiteInstance* instance = SiteInstance::CreateSiteInstance(profile_.get());
- contents_.reset(new TestTabContents(profile_.get(), instance));
+ return new TestTabContents(profile_.get(), instance);
+}
+
+void RenderViewHostTestHarness::NavigateAndCommit(const GURL& url) {
+ contents()->NavigateAndCommit(url);
+}
+
+void RenderViewHostTestHarness::Reload() {
+ NavigationEntry* entry = controller().GetLastCommittedEntry();
+ DCHECK(entry);
+ controller().Reload(false);
+ rvh()->SendNavigate(entry->page_id(), entry->url());
+}
+
+void RenderViewHostTestHarness::SetUp() {
+ contents_.reset(CreateTestTabContents());
}
void RenderViewHostTestHarness::TearDown() {
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 a2b1c99..30b7e29 100644
--- a/chrome/browser/renderer_host/test/test_render_view_host.h
+++ b/chrome/browser/renderer_host/test/test_render_view_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_TEST_TEST_RENDER_VIEW_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_TEST_TEST_RENDER_VIEW_HOST_H_
+#pragma once
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
@@ -13,13 +14,19 @@
#include "chrome/browser/renderer_host/render_widget_host_view.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/site_instance.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/test/testing_profile.h"
+#include "chrome/common/page_transition_types.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace gfx {
+class Rect;
+}
+
+class NavigationController;
+class SiteInstance;
+class TestingProfile;
+class TestTabContents;
+struct ViewHostMsg_FrameNavigate_Params;
+
// Utility function to initialize ViewHostMsg_NavigateParams_Params
// with given |page_id|, |url| and |transition_type|.
void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params,
@@ -44,6 +51,7 @@ class TestRenderWidgetHostView : 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 NULL; }
virtual void DidBecomeSelected() {}
virtual void WasHidden() {}
@@ -63,7 +71,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
virtual void Show() { is_showing_ = true; }
virtual void Hide() { is_showing_ = false; }
virtual bool IsShowing() { return is_showing_; }
- virtual gfx::Rect GetViewBounds() const { return gfx::Rect(); }
+ virtual gfx::Rect GetViewBounds() const;
virtual void SetIsLoading(bool is_loading) {}
virtual void UpdateCursor(const WebCursor& cursor) {}
virtual void UpdateCursorIfOverSelf() {}
@@ -86,14 +94,15 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
double item_font_size,
int selected_item,
const std::vector<WebMenuItem>& items,
- bool right_aligned) {}
+ bool right_aligned);
virtual gfx::Rect GetWindowRect();
virtual gfx::Rect GetRootWindowRect();
virtual void SetActive(bool active);
virtual void SetWindowVisibility(bool visible) {}
virtual void WindowFrameChanged() {}
virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(
- bool opaque);
+ bool opaque,
+ bool root);
virtual void DestroyFakePluginWindowHandle(gfx::PluginWindowHandle window);
virtual void AcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window,
int32 width,
@@ -105,11 +114,11 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
int32 height,
TransportDIB::Handle transport_dib);
virtual void AcceleratedSurfaceBuffersSwapped(gfx::PluginWindowHandle window);
- virtual void DrawAcceleratedSurfaceInstances(CGLContextObj context);
+ virtual void GpuRenderingStateDidChange();
#endif
virtual void SetVisuallyDeemphasized(bool deemphasized) { }
-#if defined(OS_LINUX)
+#if defined(TOOLKIT_USES_GTK)
virtual void CreatePluginContainer(gfx::PluginWindowHandle id) { }
virtual void DestroyPluginContainer(gfx::PluginWindowHandle id) { }
#endif
@@ -175,8 +184,7 @@ class TestRenderViewHost : public RenderViewHost {
// RenderViewHost overrides --------------------------------------------------
- virtual bool CreateRenderView(URLRequestContextGetter* request_context,
- const string16& frame_name);
+ virtual bool CreateRenderView(const string16& frame_name);
virtual bool IsRenderViewLive() const;
private:
@@ -200,28 +208,16 @@ class TestRenderViewHost : public RenderViewHost {
// registered at a time, you can only have one of these objects at a time.
class TestRenderViewHostFactory : public RenderViewHostFactory {
public:
- explicit TestRenderViewHostFactory(RenderProcessHostFactory* rph_factory)
- : render_process_host_factory_(rph_factory) {
- RenderViewHostFactory::RegisterFactory(this);
- }
- virtual ~TestRenderViewHostFactory() {
- RenderViewHostFactory::UnregisterFactory();
- }
+ explicit TestRenderViewHostFactory(RenderProcessHostFactory* rph_factory);
+ virtual ~TestRenderViewHostFactory();
virtual void set_render_process_host_factory(
- RenderProcessHostFactory* rph_factory) {
- render_process_host_factory_ = rph_factory;
- }
-
+ RenderProcessHostFactory* rph_factory);
virtual RenderViewHost* CreateRenderViewHost(
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- int64 session_storage_namespace_id) {
- // See declaration of render_process_host_factory_ below.
- instance->set_render_process_host_factory(render_process_host_factory_);
- return new TestRenderViewHost(instance, delegate, routing_id);
- }
+ SessionStorageNamespace* session_storage);
private:
// This is a bit of a hack. With the current design of the site instances /
@@ -240,49 +236,25 @@ class TestRenderViewHostFactory : public RenderViewHostFactory {
class RenderViewHostTestHarness : public testing::Test {
public:
- RenderViewHostTestHarness()
- : rph_factory_(),
- rvh_factory_(&rph_factory_),
- contents_(NULL) {}
- virtual ~RenderViewHostTestHarness() {}
-
- NavigationController& controller() {
- return contents_->controller();
- }
+ RenderViewHostTestHarness();
+ virtual ~RenderViewHostTestHarness();
- TestTabContents* contents() {
- return contents_.get();
- }
-
- TestRenderViewHost* rvh() {
- return static_cast<TestRenderViewHost*>(contents_->render_view_host());
- }
-
- TestRenderViewHost* pending_rvh() {
- return static_cast<TestRenderViewHost*>(
- contents_->render_manager()->pending_render_view_host());
- }
-
- TestRenderViewHost* active_rvh() {
- return pending_rvh() ? pending_rvh() : rvh();
- }
-
- TestingProfile* profile() {
- return profile_.get();
- }
-
- MockRenderProcessHost* process() {
- return static_cast<MockRenderProcessHost*>(rvh()->process());
- }
+ NavigationController& controller();
+ TestTabContents* contents();
+ TestRenderViewHost* rvh();
+ TestRenderViewHost* pending_rvh();
+ TestRenderViewHost* active_rvh();
+ TestingProfile* profile();
+ MockRenderProcessHost* process();
// Frees the current tab contents for tests that want to test destruction.
- void DeleteContents() {
- contents_.reset();
- }
+ void DeleteContents();
+
+ // Creates a new TestTabContents. Ownership passes to the caller.
+ TestTabContents* CreateTestTabContents();
- // Creates a pending navigation to the given URL with the default parameters
- // and then commits the load with a page ID one larger than any seen. This
- // emulates what happens on a new navigation.
+ // Cover for |contents()->NavigateAndCommit(url)|. See
+ // TestTabContents::NavigateAndCommit for details.
void NavigateAndCommit(const GURL& url);
// Simulates a reload of the current page.
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 1182c7d..0779b00 100644
--- a/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc
+++ b/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc
@@ -5,6 +5,7 @@
#include <string>
#include "base/message_loop.h"
+#include "base/process_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
diff --git a/chrome/browser/renderer_host/video_layer.h b/chrome/browser/renderer_host/video_layer.h
index 69f0702..0d7d4f8 100644
--- a/chrome/browser/renderer_host/video_layer.h
+++ b/chrome/browser/renderer_host/video_layer.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_H_
#define CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_H_
+#pragma once
#include "app/surface/transport_dib.h"
-#include "base/scoped_ptr.h"
#include "gfx/size.h"
class RenderProcessHost;
diff --git a/chrome/browser/renderer_host/video_layer_proxy.h b/chrome/browser/renderer_host/video_layer_proxy.h
index 02b90ed..4a4cc71 100644
--- a/chrome/browser/renderer_host/video_layer_proxy.h
+++ b/chrome/browser/renderer_host/video_layer_proxy.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_PROXY_H_
#define CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_PROXY_H_
+#pragma once
#include "chrome/browser/renderer_host/video_layer.h"
#include "ipc/ipc_channel.h"
diff --git a/chrome/browser/renderer_host/video_layer_x.h b/chrome/browser/renderer_host/video_layer_x.h
index 24bf316..a12c7b4 100644
--- a/chrome/browser/renderer_host/video_layer_x.h
+++ b/chrome/browser/renderer_host/video_layer_x.h
@@ -4,9 +4,12 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_X_H_
#define CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_X_H_
+#pragma once
#include "app/x11_util.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/renderer_host/video_layer.h"
+#include "gfx/rect.h"
// Implements a YUV data layer using X to hold the RGB data.
class VideoLayerX : public VideoLayer {
diff --git a/chrome/browser/renderer_host/web_cache_manager.cc b/chrome/browser/renderer_host/web_cache_manager.cc
index c186821..30cf651 100644
--- a/chrome/browser/renderer_host/web_cache_manager.cc
+++ b/chrome/browser/renderer_host/web_cache_manager.cc
@@ -12,7 +12,7 @@
#include "base/sys_info.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/renderer_host/web_cache_manager.h b/chrome/browser/renderer_host/web_cache_manager.h
index 61c6c1c..1c53a76 100644
--- a/chrome/browser/renderer_host/web_cache_manager.h
+++ b/chrome/browser/renderer_host/web_cache_manager.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_WEB_CACHE_MANAGER_H_
#define CHROME_BROWSER_RENDERER_HOST_WEB_CACHE_MANAGER_H_
+#pragma once
#include <map>
#include <list>
@@ -14,7 +15,6 @@
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
-#include "base/shared_memory.h"
#include "base/task.h"
#include "base/time.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
@@ -121,7 +121,7 @@ class WebCacheManager {
// Allow each renderer to keep its current set of cached resources.
KEEP_CURRENT,
- // Allow each renderer to keep cache resources it believs are currently
+ // Allow each renderer to keep cache resources it believes are currently
// being used, with some extra allocation to store new objects.
KEEP_LIVE_WITH_HEADROOM,
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 3dcc8ee..58a4263 100644
--- a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc
+++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc
@@ -7,7 +7,7 @@
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/download/download_file.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"
#include "chrome/browser/ssl/ssl_add_cert_handler.h"
@@ -16,16 +16,22 @@
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "net/base/mime_util.h"
+#include "net/base/x509_certificate.h"
#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_status.h"
X509UserCertResourceHandler::X509UserCertResourceHandler(
- ResourceDispatcherHost* host, URLRequest* request)
+ ResourceDispatcherHost* host, URLRequest* request,
+ int render_process_host_id, int render_view_id)
: host_(host),
request_(request),
content_length_(0),
buffer_(new DownloadBuffer),
read_buffer_(NULL),
- resource_buffer_(NULL) {
+ resource_buffer_(NULL),
+ render_process_host_id_(render_process_host_id),
+ render_view_id_(render_view_id) {
}
bool X509UserCertResourceHandler::OnUploadProgress(int request_id,
@@ -101,13 +107,17 @@ bool X509UserCertResourceHandler::OnResponseCompleted(
net::X509Certificate::CreateFromBytes(resource_buffer_->data(),
content_length_);
// The handler will run the UI and delete itself when it's finished.
- new SSLAddCertHandler(request_, cert);
+ new SSLAddCertHandler(request_, cert, render_process_host_id_,
+ render_view_id_);
return true;
}
void X509UserCertResourceHandler::OnRequestClosed() {
}
+X509UserCertResourceHandler::~X509UserCertResourceHandler() {
+}
+
void X509UserCertResourceHandler::AssembleResource() {
size_t bytes_copied = 0;
resource_buffer_ = new net::IOBuffer(content_length_);
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 7f6189a..ba6afb4 100644
--- a/chrome/browser/renderer_host/x509_user_cert_resource_handler.h
+++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.h
@@ -4,12 +4,18 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_X509_USER_CERT_RESOURCE_HANDLER_H_
#define CHROME_BROWSER_RENDERER_HOST_X509_USER_CERT_RESOURCE_HANDLER_H_
+#pragma once
#include <string>
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/renderer_host/resource_handler.h"
-#include "chrome/browser/download/download_file.h"
+#include "googleurl/src/gurl.h"
+
+class ResourceDispatcherHost;
+class URLRequest;
+class URLRequestStatus;
+struct DownloadBuffer;
// This class handles the "application/x-x509-user-cert" mime-type
// which is a certificate generated by a CA after a previous
@@ -18,7 +24,8 @@
class X509UserCertResourceHandler : public ResourceHandler {
public:
X509UserCertResourceHandler(ResourceDispatcherHost* host,
- URLRequest* request);
+ URLRequest* request,
+ int render_process_host_id, int render_view_id);
bool OnUploadProgress(int request_id, uint64 position, uint64 size);
@@ -46,9 +53,8 @@ class X509UserCertResourceHandler : public ResourceHandler {
void OnRequestClosed();
-
private:
- ~X509UserCertResourceHandler() {}
+ ~X509UserCertResourceHandler();
void AssembleResource();
@@ -60,6 +66,10 @@ class X509UserCertResourceHandler : public ResourceHandler {
scoped_refptr<net::IOBuffer> read_buffer_;
scoped_refptr<net::IOBuffer> resource_buffer_; // Downloaded certificate.
static const int kReadBufSize = 32768;
+ // The id of the |RenderProcessHost| which started the download.
+ int render_process_host_id_;
+ // The id of the |RenderView| which started the download.
+ int render_view_id_;
DISALLOW_COPY_AND_ASSIGN(X509UserCertResourceHandler);
};
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc
index dd29afc..0d41cfe 100644
--- a/chrome/browser/renderer_preferences_util.cc
+++ b/chrome/browser/renderer_preferences_util.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/profile.h"
-#if defined(OS_LINUX)
+#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#endif
@@ -14,7 +14,7 @@
namespace renderer_preferences_util {
void UpdateFromSystemSettings(RendererPreferences* prefs, Profile* profile) {
-#if defined(OS_LINUX)
+#if defined(TOOLKIT_USES_GTK)
gtk_util::UpdateGtkFontSettings(prefs);
#if !defined(TOOLKIT_VIEWS)
@@ -31,7 +31,7 @@ void UpdateFromSystemSettings(RendererPreferences* prefs, Profile* profile) {
prefs->inactive_selection_fg_color =
provider->get_inactive_selection_fg_color();
#endif // !defined(TOOLKIT_VIEWS)
-#endif // defined(OS_LINUX)
+#endif // defined(TOOLKIT_USES_GTK)
}
} // renderer_preferences_util
diff --git a/chrome/browser/renderer_preferences_util.h b/chrome/browser/renderer_preferences_util.h
index 697ae2a..f1ba8c7 100644
--- a/chrome/browser/renderer_preferences_util.h
+++ b/chrome/browser/renderer_preferences_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RENDERER_PREFERENCES_UTIL_H_
#define CHROME_BROWSER_RENDERER_PREFERENCES_UTIL_H_
+#pragma once
#include "chrome/common/renderer_preferences.h"
diff --git a/chrome/browser/repost_form_warning_controller.h b/chrome/browser/repost_form_warning_controller.h
index ce22d7b..fb8cf28 100644
--- a/chrome/browser/repost_form_warning_controller.h
+++ b/chrome/browser/repost_form_warning_controller.h
@@ -4,11 +4,12 @@
#ifndef CHROME_BROWSER_REPOST_FORM_WARNING_CONTROLLER_H_
#define CHROME_BROWSER_REPOST_FORM_WARNING_CONTROLLER_H_
+#pragma once
#include "chrome/browser/tab_contents/constrained_window.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class NavigationController;
class TabContents;
// This class is used to continue or cancel a pending reload when the
diff --git a/chrome/browser/repost_form_warning_uitest.cc b/chrome/browser/repost_form_warning_uitest.cc
index 46e43cb..ed410d7 100644
--- a/chrome/browser/repost_form_warning_uitest.cc
+++ b/chrome/browser/repost_form_warning_uitest.cc
@@ -11,11 +11,11 @@
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
} // namespace
@@ -29,9 +29,9 @@ typedef UITest RepostFormWarningTest;
#endif
TEST_F(RepostFormWarningTest, MAYBE_TestDoubleReload) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
@@ -39,7 +39,7 @@ TEST_F(RepostFormWarningTest, MAYBE_TestDoubleReload) {
ASSERT_TRUE(tab.get());
// Load a form.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("files/form.html")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("files/form.html")));
// Submit it.
ASSERT_TRUE(tab->NavigateToURL(GURL(
"javascript:document.getElementById('form').submit()")));
@@ -49,20 +49,20 @@ TEST_F(RepostFormWarningTest, MAYBE_TestDoubleReload) {
tab->ReloadAsync();
// Navigate away from the page (this is when the test usually crashes).
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("bar")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("bar")));
}
-#if defined(OS_WIN)
-// http://crbug.com/47228
+#if defined(OS_WIN) || defined(OS_LINUX)
+// http://crbug.com/47228 && http://crbug.com/56401
#define MAYBE_TestLoginAfterRepost FLAKY_TestLoginAfterRepost
#else
#define MAYBE_TestLoginAfterRepost TestLoginAfterRepost
#endif
TEST_F(RepostFormWarningTest, MAYBE_TestLoginAfterRepost) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
@@ -70,7 +70,7 @@ TEST_F(RepostFormWarningTest, MAYBE_TestLoginAfterRepost) {
ASSERT_TRUE(tab.get());
// Load a form.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("files/form.html")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("files/form.html")));
// Submit it.
ASSERT_TRUE(tab->NavigateToURL(GURL(
"javascript:document.getElementById('form').submit()")));
@@ -80,11 +80,11 @@ TEST_F(RepostFormWarningTest, MAYBE_TestLoginAfterRepost) {
// Navigate to a page that requires authentication, bringing up another
// tab-modal sheet.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("auth-basic")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("auth-basic")));
// Try to reload it again.
tab->ReloadAsync();
// Navigate away from the page.
- ASSERT_TRUE(tab->NavigateToURL(server->TestServerPage("bar")));
+ ASSERT_TRUE(tab->NavigateToURL(test_server.GetURL("bar")));
}
diff --git a/chrome/browser/resources/about_memory.html b/chrome/browser/resources/about_memory.html
index 0dbc2a1..3432d0d 100644
--- a/chrome/browser/resources/about_memory.html
+++ b/chrome/browser/resources/about_memory.html
@@ -6,319 +6,32 @@ about:memory template page
<html id="t">
<head>
<title>About Memory</title>
+ <link rel="stylesheet" href="shared/css/about_memory.css">
<style>
body {
- font-size: 84%;
font-family: Helvetica, Arial, sans-serif;
- padding: 0.75em;
- margin: 0;
- min-width: 45em;
-}
-
-h1 {
- font-size: 110%;
- font-weight: bold;
- color: #4a8ee6;
- letter-spacing: -1px;
- padding: 0;
- margin: 0;
-}
-h2 {
- font-size: 110%;
- letter-spacing: -1px;
- font-weight: normal;
- color: #4a8ee6;
- padding: 0;
- margin: 0;
- padding: 0.5em 1em;
- color: #3a75bd;
- margin-left: -38px;
- padding-left: 38px;
-
- border-top: 1px solid #3a75bd;
- padding-top: 0.5em;
-
-}
-h2:first-child {
- border-top: 0;
- padding-top: 0;
-}
-span.th {
- padding-left: 0.35em;
-}
-a {
- color: black;
-}
-
-div#header {
- padding: 0.75em 1em;
- padding-top: 0.6em;
- padding-left: 0;
- margin-bottom: 0.75em;
- position: relative;
- overflow: hidden;
- background: #5296de;
- background-size: 100%;
- border: 1px solid #3a75bd;
- border-radius: 6px;
- color: white;
- text-shadow: 0 0 2px black;
-}
-div#header h1 {
- padding-left: 37px;
- margin: 0;
- display: inline;
- background: url('shared/images/gear.png') 12px 60% no-repeat;
- color: white;
-}
-div#header p {
- font-size: 84%;
- font-style: italic;
- padding: 0;
- margin: 0;
- color: white;
- padding-left: 0.4em;
- display: inline;
-}
-div#header div.navigation {
- position: absolute;
- top: 0;
- right: 1em;
- line-height: 3.5em;
- font-size: 92%;
}
div#header select {
- font-size: 100%;
font-family: Helvetica, Arial, sans-serif;
- border: 1px solid #3a75bd;
- line-height: 140%;
- color: #315d94;
-}
-div#header select option {
- padding: 0 0.2em;
-}
-
-div#sidebar {
- display: none;
- float: left;
- margin-left: 26px;
- width: 45em;
- min-height: 20em;
- padding: 0.75em;
- padding-top: 0;
-
- border-right: 1px solid #cfcfcf;
-}
-div#content {
- margin-left: 0px;
-}
-
-div.viewOptions {
- float: right;
- font-size: 92%;
- color: #5f5f5f;
- margin-top: 1em;
-}
-hr {
- visibility: hidden;
- display: inline;
- padding: 0 0.5em;
}
div.viewOptions input {
font-family: Helvetica, Arial, sans-serif;
- font-size: 100%;
- border: 1px solid #b5b5b5;
- border-radius: 6px;
- padding: 0.3em 0.4em;
-}
-div.viewOptions input:focus {
- border-color: white;
-}
-
-.k {
- opacity: 0.4;
- font-weight: normal;
- padding-left: 0.1em;
-}
-
-.legend {
- font-size: 84%;
- padding: 0;
- padding-top: 0.4em;
- margin-top: 2em;
- text-align: right;
- line-height: 140%;
- color: #7f7f7f;
-}
-.legend h3 {
- padding: 0;
- padding-right: 0.5em;
- margin: 0;
- font-weight: normal;
- color: black;
- display: inline;
- font-size: 100%;
-}
-.legend .swatch {
- opacity: 0.66;
- padding: 0 0.5em;
- display: inline-block;
- margin-right: 0.2em;
- height: 0.9em;
-}
-.legend .swatch.heavyUse {
- background: #cc0000;
-}
-
-table.list {
- width: 100%;
- line-height: 200%;
- border-collapse: collapse;
- font-size: 84%;
- table-layout: fixed;
-}
-table.list:not([class*='filtered']) tr:nth-child(odd) td {
- background: #eff3ff;
-}
-.hidden {
- display: none;
-}
-table.list th {
- padding: 0 0.5em;
- vertical-align: top;
- font-weight: bold;
- color: #315d94;
- color: black;
- white-space: nowrap;
-}
-table.list .firstRow th {
- text-align: left;
- line-height: 100%;
-}
-table.list .secondRow * {
- text-align: left;
- border-bottom: 1px solid #b5c6de;
-}
-table.list td {
- padding: 0 0.5em;
- vertical-align: top;
- line-height: 1.4em;
- padding-top: 0.35em;
-}
-table.list tr td:nth-last-child(1),
-table.list tr th:nth-last-child(1) {
- padding-right: 1em;
-}
-table.list:not([class*='filtered']) .tab .name {
- padding-left: 1.5em;
}
-
-table.list .name {
- width: 100%;
-}
-
-table.list .name div {
- height: 1.6em;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-table.list .pid {
- width: 4em;
- text-align: right;
-}
-table.list .pid .th {
- padding: 0;
-}
-table.list .type {
- width: 5em;
-}
-table.list .number {
- width: 7em;
- text-align: right;
-}
-table.list .total {
- font-weight: bold;
-}
-table.list .total .name {
- color: #315d94;
- text-align: right;
-}
-table.list .total td {
- border-top: 1px solid #b5c6de;
- background: white !important;
-}
-table.list .noResults {
- display: none;
-}
-table.list.noResults .noResults {
- display: table-row;
-}
-table.list .noResults td {
- text-align: center;
- padding: 3em 0;
- color: #3f3f3f;
-}
-
-.heavyUse {
- color: #cc0000;
- font-weight: bold;
-}
-
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
-table.list#memoryDetails tr.firstRow th:nth-child(2),
-table.list#memoryDetails tr.firstRow th:nth-child(3) {
- border-right: 1px solid #b5c6de;
+div.otherbrowsers {
+ font-family: Helvetica, Arial, sans-serif;
}
-
table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(1),
table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(4),
table.list#browserComparison tr.firstRow th:nth-child(1),
table.list#browserComparison tr.firstRow th:nth-child(2) {
border-right: 1px solid #b5c6de;
}
-table.list#browserComparison .name {
- padding-left: 25px;
- background-position: 5px center;
- background-repeat: no-repeat;
-}
-
-div.help {
- display: inline-block;
- width: 14px;
- margin: -1px 0;
- height: 14px;
- background: url('shared/images/help.gif') center bottom no-repeat;
- opacity: 0.33;
-}
-div.help:hover {
- opacity: 1;
-}
-div.help div {
- display: none;
-}
-#helpTooltip {
- z-index: 1000;
- position: absolute;
- background: #d6e8ff;
- padding: 0.3em 0.8em;
- max-width: 30em;
- -webkit-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.33);
- border: 1px solid #a8cfff;
- border-radius: 0;
- line-height: 140%;
- font-size: 92%;
-}
-#helpTooltip p {
- margin: 0.6em 0;
-}
-div.otherbrowsers {
- font-family: Helvetica, Arial, sans-serif;
- font-size: 84%;
- width: 100%;
- text-align: center;
+table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
+table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
+table.list#memoryDetails tr.firstRow th:nth-child(2),
+table.list#memoryDetails tr.firstRow th:nth-child(3) {
+ border-right: 1px solid #b5c6de;
}
</style>
<script>
diff --git a/chrome/browser/resources/about_memory_linux.html b/chrome/browser/resources/about_memory_linux.html
index 0d4c904..a3cdfe7 100644
--- a/chrome/browser/resources/about_memory_linux.html
+++ b/chrome/browser/resources/about_memory_linux.html
@@ -6,317 +6,30 @@ about:memory template page
<html id="t">
<head>
<title>About Memory</title>
+ <link rel="stylesheet" href="shared/css/about_memory.css">
<style>
body {
- font-size: 84%;
font-family: Arial, Helvetica, sans-serif;
- padding: 0.75em;
- margin: 0;
- min-width: 45em;
-}
-
-h1 {
- font-size: 110%;
- font-weight: bold;
- color: #4a8ee6;
- letter-spacing: -1px;
- padding: 0;
- margin: 0;
-}
-h2 {
- font-size: 110%;
- letter-spacing: -1px;
- font-weight: normal;
- color: #4a8ee6;
- padding: 0;
- margin: 0;
- padding: 0.5em 1em;
- color: #3a75bd;
- margin-left: -38px;
- padding-left: 38px;
-
- border-top: 1px solid #3a75bd;
- padding-top: 0.5em;
-
-}
-h2:first-child {
- border-top: 0;
- padding-top: 0;
-}
-span.th {
- padding-left: 0.35em;
-}
-a {
- color: black;
-}
-
-div#header {
- padding: 0.75em 1em;
- padding-top: 0.6em;
- padding-left: 0;
- margin-bottom: 0.75em;
- position: relative;
- overflow: hidden;
- background: #5296de;
- background-size: 100%;
- border: 1px solid #3a75bd;
- border-radius: 6px;
- color: white;
- text-shadow: 0 0 2px black;
-}
-div#header h1 {
- padding-left: 37px;
- margin: 0;
- display: inline;
- background: url('shared/images/gear.png') 12px 60% no-repeat;
- color: white;
-}
-div#header p {
- font-size: 84%;
- font-style: italic;
- padding: 0;
- margin: 0;
- color: white;
- padding-left: 0.4em;
- display: inline;
-}
-div#header div.navigation {
- position: absolute;
- top: 0;
- right: 1em;
- line-height: 3.5em;
- font-size: 92%;
}
div#header select {
- font-size: 100%;
font-family: Arial, Helvetica, sans-serif;
- border: 1px solid #3a75bd;
- line-height: 140%;
- color: #315d94;
-}
-div#header select option {
- padding: 0 0.2em;
-}
-
-div#sidebar {
- display: none;
- float: left;
- margin-left: 26px;
- width: 45em;
- min-height: 20em;
- padding: 0.75em;
- padding-top: 0;
-
- border-right: 1px solid #cfcfcf;
-}
-div#content {
- margin-left: 0px;
-}
-
-div.viewOptions {
- float: right;
- font-size: 92%;
- color: #5f5f5f;
- margin-top: 1em;
-}
-hr {
- visibility: hidden;
- display: inline;
- padding: 0 0.5em;
}
div.viewOptions input {
font-family: Arial, Helvetica, sans-serif;
- font-size: 100%;
- border: 1px solid #b5b5b5;
- border-radius: 6px;
- padding: 0.3em 0.4em;
-}
-div.viewOptions input:focus {
- border-color: white;
-}
-
-.k {
- opacity: 0.4;
- font-weight: normal;
- padding-left: 0.1em;
-}
-
-.legend {
- font-size: 84%;
- padding: 0;
- padding-top: 0.4em;
- margin-top: 2em;
- text-align: right;
- line-height: 140%;
- color: #7f7f7f;
-}
-.legend h3 {
- padding: 0;
- padding-right: 0.5em;
- margin: 0;
- font-weight: normal;
- color: black;
- display: inline;
- font-size: 100%;
-}
-.legend .swatch {
- opacity: 0.66;
- padding: 0 0.5em;
- display: inline-block;
- margin-right: 0.2em;
- height: 0.9em;
-}
-.legend .swatch.heavyUse {
- background: #cc0000;
-}
-
-table.list {
- width: 100%;
- line-height: 200%;
- border-collapse: collapse;
- font-size: 84%;
- table-layout: fixed;
-}
-table.list:not([class*='filtered']) tr:nth-child(odd) td {
- background: #eff3ff;
-}
-.hidden {
- display: none;
-}
-table.list th {
- padding: 0 0.5em;
- vertical-align: top;
- font-weight: bold;
- color: #315d94;
- color: black;
- white-space: nowrap;
-}
-table.list .firstRow th {
- text-align: left;
- line-height: 100%;
-}
-table.list .secondRow * {
- text-align: left;
- border-bottom: 1px solid #b5c6de;
-}
-table.list td {
- padding: 0 0.5em;
- vertical-align: top;
- line-height: 1.4em;
- padding-top: 0.35em;
-}
-table.list tr td:nth-last-child(1),
-table.list tr th:nth-last-child(1) {
- padding-right: 1em;
}
-table.list:not([class*='filtered']) .tab .name {
- padding-left: 1.5em;
-}
-
-table.list .name {
- width: 100%;
-}
-
-table.list .name div {
- height: 1.6em;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-table.list .pid {
- width: 4em;
- text-align: right;
-}
-table.list .pid .th {
- padding: 0;
-}
-table.list .type {
- width: 5em;
-}
-table.list .number {
- width: 7em;
- text-align: right;
-}
-table.list .total {
- font-weight: bold;
-}
-table.list .total .name {
- color: #315d94;
- text-align: right;
-}
-table.list .total td {
- border-top: 1px solid #b5c6de;
- background: white !important;
-}
-table.list .noResults {
- display: none;
-}
-table.list.noResults .noResults {
- display: table-row;
-}
-table.list .noResults td {
- text-align: center;
- padding: 3em 0;
- color: #3f3f3f;
-}
-
-.heavyUse {
- color: #cc0000;
- font-weight: bold;
-}
-
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
-table.list#memoryDetails tr.firstRow th:nth-child(2) {
- border-right: 1px solid #b5c6de;
+div.otherbrowsers {
+ font-family: Arial, Helvetica, sans-serif;
}
-
table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(1),
table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(4),
table.list#browserComparison tr.firstRow th:nth-child(1) {
border-right: 1px solid #b5c6de;
}
-table.list#browserComparison .name {
- padding-left: 25px;
- background-position: 5px center;
- background-repeat: no-repeat;
-}
-
-div.help {
- display: inline-block;
- width: 14px;
- margin: -1px 0;
- height: 14px;
- background: url('shared/images/help.gif') center bottom no-repeat;
- opacity: 0.33;
-}
-div.help:hover {
- opacity: 1;
-}
-div.help div {
- display: none;
-}
-#helpTooltip {
- z-index: 1000;
- position: absolute;
- background: #d6e8ff;
- padding: 0.3em 0.8em;
- max-width: 30em;
- -webkit-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.33);
- border: 1px solid #a8cfff;
- border-radius: 0;
- line-height: 140%;
- font-size: 92%;
-}
-#helpTooltip p {
- margin: 0.6em 0;
-}
-div.otherbrowsers {
- font-family: Arial, Helvetica, sans-serif;
- font-size: 84%;
- width: 100%;
- text-align: center;
+table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
+table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
+table.list#memoryDetails tr.firstRow th:nth-child(2) {
+ border-right: 1px solid #b5c6de;
}
</style>
<script>
diff --git a/chrome/browser/resources/about_memory_mac.html b/chrome/browser/resources/about_memory_mac.html
index 299a875..6184871 100644
--- a/chrome/browser/resources/about_memory_mac.html
+++ b/chrome/browser/resources/about_memory_mac.html
@@ -6,317 +6,30 @@ about:memory template page
<html id="t">
<head>
<title>About Memory</title>
+ <link rel="stylesheet" href="shared/css/about_memory.css">
<style>
body {
- font-size: 84%;
font-family: Helvetica, sans-serif;
- padding: 0.75em;
- margin: 0;
- min-width: 45em;
-}
-
-h1 {
- font-size: 110%;
- font-weight: bold;
- color: #4a8ee6;
- letter-spacing: -1px;
- padding: 0;
- margin: 0;
-}
-h2 {
- font-size: 110%;
- letter-spacing: -1px;
- font-weight: normal;
- color: #4a8ee6;
- padding: 0;
- margin: 0;
- padding: 0.5em 1em;
- color: #3a75bd;
- margin-left: -38px;
- padding-left: 38px;
-
- border-top: 1px solid #3a75bd;
- padding-top: 0.5em;
-
-}
-h2:first-child {
- border-top: 0;
- padding-top: 0;
-}
-span.th {
- padding-left: 0.35em;
-}
-a {
- color: black;
-}
-
-div#header {
- padding: 0.75em 1em;
- padding-top: 0.6em;
- padding-left: 0;
- margin-bottom: 0.75em;
- position: relative;
- overflow: hidden;
- background: #5296de;
- background-size: 100%;
- border: 1px solid #3a75bd;
- border-radius: 6px;
- color: white;
- text-shadow: 0 0 2px black;
-}
-div#header h1 {
- padding-left: 37px;
- margin: 0;
- display: inline;
- background: url('shared/images/gear.png') 12px 60% no-repeat;
- color: white;
-}
-div#header p {
- font-size: 84%;
- font-style: italic;
- padding: 0;
- margin: 0;
- color: white;
- padding-left: 0.4em;
- display: inline;
-}
-div#header div.navigation {
- position: absolute;
- top: 0;
- right: 1em;
- line-height: 3.5em;
- font-size: 92%;
}
div#header select {
- font-size: 100%;
font-family: Helvetica, sans-serif;
- border: 1px solid #3a75bd;
- line-height: 140%;
- color: #315d94;
-}
-div#header select option {
- padding: 0 0.2em;
-}
-
-div#sidebar {
- display: none;
- float: left;
- margin-left: 26px;
- width: 45em;
- min-height: 20em;
- padding: 0.75em;
- padding-top: 0;
-
- border-right: 1px solid #cfcfcf;
-}
-div#content {
- margin-left: 0px;
-}
-
-div.viewOptions {
- float: right;
- font-size: 92%;
- color: #5f5f5f;
- margin-top: 1em;
-}
-hr {
- visibility: hidden;
- display: inline;
- padding: 0 0.5em;
}
div.viewOptions input {
font-family: Helvetica, sans-serif;
- font-size: 100%;
- border: 1px solid #b5b5b5;
- border-radius: 6px;
- padding: 0.3em 0.4em;
-}
-div.viewOptions input:focus {
- border-color: white;
-}
-
-.k {
- opacity: 0.4;
- font-weight: normal;
- padding-left: 0.1em;
-}
-
-.legend {
- font-size: 84%;
- padding: 0;
- padding-top: 0.4em;
- margin-top: 2em;
- text-align: right;
- line-height: 140%;
- color: #7f7f7f;
-}
-.legend h3 {
- padding: 0;
- padding-right: 0.5em;
- margin: 0;
- font-weight: normal;
- color: black;
- display: inline;
- font-size: 100%;
-}
-.legend .swatch {
- opacity: 0.66;
- padding: 0 0.5em;
- display: inline-block;
- margin-right: 0.2em;
- height: 0.9em;
-}
-.legend .swatch.heavyUse {
- background: #cc0000;
-}
-
-table.list {
- width: 100%;
- line-height: 200%;
- border-collapse: collapse;
- font-size: 84%;
- table-layout: fixed;
-}
-table.list:not([class*='filtered']) tr:nth-child(odd) td {
- background: #eff3ff;
-}
-.hidden {
- display: none;
-}
-table.list th {
- padding: 0 0.5em;
- vertical-align: top;
- font-weight: bold;
- color: #315d94;
- color: black;
- white-space: nowrap;
-}
-table.list .firstRow th {
- text-align: left;
- line-height: 100%;
-}
-table.list .secondRow * {
- text-align: left;
- border-bottom: 1px solid #b5c6de;
-}
-table.list td {
- padding: 0 0.5em;
- vertical-align: top;
- line-height: 1.4em;
- padding-top: 0.35em;
-}
-table.list tr td:nth-last-child(1),
-table.list tr th:nth-last-child(1) {
- padding-right: 1em;
}
-table.list:not([class*='filtered']) .tab .name {
- padding-left: 1.5em;
-}
-
-table.list .name {
- width: 100%;
-}
-
-table.list .name div {
- height: 1.6em;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-table.list .pid {
- width: 4em;
- text-align: right;
-}
-table.list .pid .th {
- padding: 0;
-}
-table.list .type {
- width: 5em;
-}
-table.list .number {
- width: 7em;
- text-align: right;
-}
-table.list .total {
- font-weight: bold;
-}
-table.list .total .name {
- color: #315d94;
- text-align: right;
-}
-table.list .total td {
- border-top: 1px solid #b5c6de;
- background: white !important;
-}
-table.list .noResults {
- display: none;
-}
-table.list.noResults .noResults {
- display: table-row;
-}
-table.list .noResults td {
- text-align: center;
- padding: 3em 0;
- color: #3f3f3f;
-}
-
-.heavyUse {
- color: #cc0000;
- font-weight: bold;
-}
-
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
-table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
-table.list#memoryDetails tr.firstRow th:nth-child(2) {
- border-right: 1px solid #b5c6de;
+div.otherbrowsers {
+ font-family: Helvetica, sans-serif;
}
-
table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(1),
table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(4),
table.list#browserComparison tr.firstRow th:nth-child(1) {
border-right: 1px solid #b5c6de;
}
-table.list#browserComparison .name {
- padding-left: 25px;
- background-position: 5px center;
- background-repeat: no-repeat;
-}
-
-div.help {
- display: inline-block;
- width: 14px;
- margin: -1px 0;
- height: 14px;
- background: url('shared/images/help.gif') center bottom no-repeat;
- opacity: 0.33;
-}
-div.help:hover {
- opacity: 1;
-}
-div.help div {
- display: none;
-}
-#helpTooltip {
- z-index: 1000;
- position: absolute;
- background: #d6e8ff;
- padding: 0.3em 0.8em;
- max-width: 30em;
- -webkit-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.33);
- border: 1px solid #a8cfff;
- border-radius: 0;
- line-height: 140%;
- font-size: 92%;
-}
-#helpTooltip p {
- margin: 0.6em 0;
-}
-div.otherbrowsers {
- font-family: Helvetica, sans-serif;
- font-size: 84%;
- width: 100%;
- text-align: center;
+table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2),
+table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5),
+table.list#memoryDetails tr.firstRow th:nth-child(2) {
+ border-right: 1px solid #b5c6de;
}
</style>
<script>
diff --git a/chrome/browser/resources/about_sys.html b/chrome/browser/resources/about_sys.html
index dbae643..00cdf1c 100644
--- a/chrome/browser/resources/about_sys.html
+++ b/chrome/browser/resources/about_sys.html
@@ -1,8 +1,7 @@
<!DOCTYPE HTML>
-<html id="t">
-<head>
+<html i18n-values="dir:textdirection;"><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<title>About S&#121;stem</title>
+<title i18n-content="title"></title>
<style>
body {
@@ -13,11 +12,12 @@ body {
min-width: 45em;
}
-h1,h2 {
+h1, h2 {
font-size: 110%;
letter-spacing: -1px;
margin: 0;
}
+
h1 {
font-weight: bold;
color: #4a8ee6;
@@ -28,12 +28,12 @@ h2 {
font-weight: normal;
padding: 0.5em 1em;
color: #3a75bd;
- margin-left: -38px;
- padding-left: 38px;
+ -webkit-margin-start: -38px;
+ -webkit-padding-start: 38px;
border-top: 1px solid #3a75bd;
padding-top: 0.5em;
-
}
+
h2:first-child {
border-top: 0;
padding-top: 0;
@@ -51,35 +51,47 @@ h2:first-child {
color: white;
text-shadow: 0 0 2px black;
}
-div#header h1 {
- padding-left: 3em;
+
+html[dir='rtl'] #header {
+ padding: 0.6em 0 0.75em 1em;
+}
+
+#header h1 {
+ -webkit-padding-start: 3em;
margin: 0;
display: inline;
- background: url('shared/images/gear.png') 12px 60% no-repeat;
+ background: url('shared/images/gear.png') no-repeat;
+ background-position: 12px 60%;
color: white;
}
-div#header p {
+
+html[dir='rtl'] #header h1 {
+ background-position-left: auto;
+ backgroun-position-right: 12px;
+}
+
+#header p {
font-size: 84%;
font-style: italic;
padding: 0;
margin: 0;
color: white;
- padding-left: 0.4em;
+ -webkit-padding-start: 0.4em;
display: inline;
}
-table.list {
+.list {
line-height: 200%;
border-collapse: collapse;
font-size: 84%;
table-layout: fixed;
width: 100%;
}
-table.list:not([class*='filtered']) tr:nth-child(odd) td {
+.list:not(.filtered) tr:nth-child(odd) td {
background: #eff3ff;
}
-table.list td {
+.list td {
padding: 0 0.5em;
vertical-align: top;
line-height: 1.4em;
@@ -87,58 +99,164 @@ table.list td {
font-family: 'Courier New', monospace;
white-space: pre;
}
-table.list tr td:nth-last-child(1),
-table.list tr th:nth-last-child(1) {
- padding-right: 1em;
+
+.list tr td:nth-last-child(1),
+.list tr th:nth-last-child(1) {
+ -webkit-padding-end: 1em;
}
-table.list:not([class*='filtered']) .tab .name {
- padding-left: 1.5em;
+
+.list:not(.filtered) .tab .name {
+ -webkit-padding-start: 1.5em;
}
-table.list .name {
+.list .name {
width: 20%;
}
-table.list .name div {
+.list .name div {
height: 1.6em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
-table.list .number {
+.number_expanded, .number_collapsed {
text-align: left;
width: 80%;
}
-table.list#details tr:not([class*='firstRow']) > *:nth-child(1),
-table.list#details tr:not([class*='firstRow']) > *:nth-child(4),
-table.list#details tr.firstRow th:nth-child(1),
-table.list#details tr.firstRow th:nth-child(2) {
+html[dir='rtl'] .number_expanded, html[dir='rtl'] .number_collapsed {
+ text-align: right;
+}
+
+tr:not(.firstRow) > *:nth-child(1),
+tr:not(.firstRow) > *:nth-child(4),
+tr.firstRow th:nth-child(1),
+tr.firstRow th:nth-child(2) {
border-right: 1px solid #b5c6de;
}
-table.list#details .name {
- padding-left: 25px;
+
+html[dir='rtl'] tr:not(.firstRow) > *:nth-child(1),
+html[dir='rtl'] tr:not(.firstRow) > *:nth-child(4),
+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;
+}
+
+.name {
+ -webkit-padding-start: 25px;
background-position: 5em center;
background-repeat: no-repeat;
}
+
+html[dir='rtl'] #details .name {
+ background-position-left: auto;
+ background-position-right: 5em;
+}
+
+.number_collapsed .stat_value {
+ display: none;
+}
+
+.number_expanded .stat_value {
+ display: auto;
+}
+
+#anchor {
+ display: none;
+}
+
+.globalButton {
+ float: right;
+ margin: 1px 5px;
+}
+
+html[dir='rtl'] .globalButton {
+ float: left;
+}
</style>
+<script src="shared/js/local_strings.js"></script>
+<script>
+var localStrings;
+
+function changeCollapsedStatus() {
+ if (this.parentNode.className == 'number_collapsed') {
+ this.parentNode.className = 'number_expanded';
+ this.textContent = localStrings.getString('collapse_btn');
+ } else {
+ this.parentNode.className = 'number_collapsed';
+ this.textContent = localStrings.getString('expand_btn');
+ }
+}
+
+function collapseAll() {
+ var expandStatusDivs = document.getElementsByClassName('expand_status');
+ for(var i = 0; i < expandStatusDivs.length; i++) {
+ expandStatusDivs[i].textContent = localStrings.getString('expand_btn');
+ expandStatusDivs[i].parentNode.className = 'number_collapsed';
+ }
+}
+
+function expandAll() {
+ var expandStatusDivs = document.getElementsByClassName('expand_status');
+ for(var i = 0; i < expandStatusDivs.length; i++) {
+ expandStatusDivs[i].textContent = localStrings.getString('collapse_btn');
+ expandStatusDivs[i].parentNode.className = 'number_expanded';
+ }
+}
+
+document.addEventListener('DOMContentLoaded', function() {
+ localStrings = new LocalStrings();
+
+ var collapseAllBtn = document.getElementById('collapseAll');
+ collapseAllBtn.onclick = collapseAll;
+
+ var expandAllBtn = document.getElementById('expandAll');
+ expandAllBtn.onclick = expandAll;
+
+ var anchorName = document.getElementById('anchor').textContent;
+ var expandStatusDivs = document.getElementsByClassName('expand_status');
+ for(var i = 0; i < expandStatusDivs.length; i++) {
+ expandStatusDivs[i].onclick = changeCollapsedStatus;
+ if (expandStatusDivs[i].id != anchorName + 'Btn') {
+ expandStatusDivs[i].textContent = localStrings.getString('expand_btn');
+ expandStatusDivs[i].parentNode.className = 'number_collapsed';
+ } else {
+ var anchor = document.createElement('a');
+ anchor.name = anchorName;
+ expandStatusDivs[i].parentNode.insertBefore(anchor, expandStatusDivs[i]);
+ window.location.hash = anchorName;
+ expandStatusDivs[i].textContent = localStrings.getString('collapse_btn');
+ expandStatusDivs[i].parentNode.className = 'number_expanded';
+ }
+ }
+});
+</script>
</head>
-<body>
+<body id="t">
<div id="header">
- <h1>About S&#121;stem</h1>
- <p>System diagnostic data</p>
+ <h1 i18n-content="title"></h1>
+ <p i18n-content="description"></p>
</div>
<div id="content">
- <h2>Details</h2>
+ <h2 i18n-content="table_title"></h2>
+ <div id="anchor" jscontent="anchor"></div>
+ <button id="expandAll" class="globalButton" i18n-content="expand_all_btn">
+ </button>
+ <button id="collapseAll" class="globalButton"
+ i18n-content="collapse_all_btn"></button>
<table class="list" id="details">
<tr jsselect="details">
<td class="name">
+ <a jsvalues="name:anchor_value"></a>
<div jscontent="stat_name"></div>
</td>
<td class="number">
- <div jscontent="stat_value"></div>
+ <button jsvalues="id:stat_name + 'Btn'" class="expand_status">
+ </button>
+ <div class="stat_value" jscontent="stat_value"></div>
</td>
</tr>
</table>
diff --git a/chrome/browser/resources/amex.png b/chrome/browser/resources/amex.png
deleted file mode 100644
index 7cfa9cb..0000000
--- a/chrome/browser/resources/amex.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/bookmark_manager/css/bmm.css b/chrome/browser/resources/bookmark_manager/css/bmm.css
index cff6e71..d117e8a 100644
--- a/chrome/browser/resources/bookmark_manager/css/bmm.css
+++ b/chrome/browser/resources/bookmark_manager/css/bmm.css
@@ -20,16 +20,11 @@ list {
list > * {
color: hsl(0, 0%, 70%);
padding: 0 3px;
- padding-right: 20px;
+ -webkit-padding-end: 20px;
text-decoration: none;
white-space: nowrap;
}
-html[dir=rtl] list > * {
- padding-right: 3px;
- padding-left: 20px;
-}
-
list > * > * {
-webkit-box-sizing: border-box;
-webkit-padding-start: 20px;
@@ -117,17 +112,19 @@ list .url input {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
- margin: -2px 4px -2px -4px;
+ margin: 0;
+ -webkit-margin-start: -4px;
+ -webkit-margin-end: 4px;
max-width: 40%;
- padding: 1px 3px 1px 1px;
- outline: none;
+ padding: 0;
+ -webkit-padding-start: 1px;
+ -webkit-padding-end: 3px;
text-decoration: none;
}
-html[dir=rtl] list .label input,
-html[dir=rtl] list .url input {
- margin: -2px -4px -2px 4px;
- padding: 1px 1px 1px 3px;
+html:not([os=mac]) list .label input,
+html:not([os=mac]) list .url input {
+ outline: none;
}
list > [editing] {
@@ -142,7 +139,7 @@ list [editing] > * {
}
list [editing] .url {
- -webkit-padding-start: 5px;
+ -webkit-padding-start: 10px;
}
list .url form {
@@ -187,11 +184,8 @@ html[os=mac] .tree-row[selected] > .tree-label {
max-width: 50%;
overflow: auto;
-webkit-box-sizing: border-box;
- padding: 5px 5px 5px 10px;
-}
-
-html[dir=rtl] #tree-container {
- padding: 5px 10px 5px 5px;
+ padding: 5px;
+ -webkit-padding-start: 10px;
}
#tree {
@@ -287,12 +281,10 @@ html[dir=rtl] .header form {
font: inherit;
padding: 0;
background: -webkit-canvas(drop-down-arrow) 100% 50% no-repeat;
- padding-right: 11px;
+ -webkit-padding-end: 11px;
-webkit-margin-start: 10px;
}
html[dir=rtl] .summary button {
background-position: 0% 50%;
- padding-right: 0;
- padding-left: 11px;
}
diff --git a/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js b/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js
index faeb31f..9404af6 100644
--- a/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js
+++ b/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js
@@ -72,11 +72,11 @@ cr.define('bmm', function() {
this.addEventListener('mousedown', this.handleMouseDown_);
// HACK(arv): http://crbug.com/40902
- window.addEventListener('resize', cr.bind(this.redraw, this));
+ window.addEventListener('resize', this.redraw.bind(this));
// We could add the ContextMenuButton in the BookmarkListItem but it slows
// down redraws a lot so we do this on mouseovers instead.
- this.addEventListener('mouseover', cr.bind(this.handleMouseOver_, this));
+ this.addEventListener('mouseover', this.handleMouseOver_.bind(this));
},
createItem: function(bookmarkNode) {
@@ -110,7 +110,7 @@ cr.define('bmm', function() {
reload: function() {
var parentId = this.parentId;
- var callback = cr.bind(this.handleBookmarkCallback_, this);
+ var callback = this.handleBookmarkCallback_.bind(this);
this.loading_ = true;
if (!parentId) {
@@ -205,7 +205,7 @@ cr.define('bmm', function() {
var node = el.bookmarkNode;
if (!bmm.isFolder(node)) {
var event = new cr.Event('urlClicked', true, false);
- event.url = url;
+ event.url = node.url;
event.originalEvent = e;
this.dispatchEvent(event);
}
@@ -509,12 +509,16 @@ cr.define('bmm', function() {
}
} else {
-
// Check that we have a valid URL and if not we do not change the
// editing mode.
if (!isFolder) {
var urlInput = this.querySelector('.url input');
var newUrl = urlInput.value;
+ if (!newUrl) {
+ cr.dispatchSimpleEvent(this, 'canceledit', true);
+ return;
+ }
+
if (!urlInput.validity.valid) {
// WebKit does not do URL fix up so we manually test if prepending
// 'http://' would make the URL valid.
@@ -527,6 +531,12 @@ cr.define('bmm', function() {
// In case the item was removed before getting here we should
// not alert.
if (listItem.parentNode) {
+ // Select the item again.
+ var dataModel = this.parentNode.dataModel;
+ var index = dataModel.indexOf(this.bookmarkNode);
+ var sm = this.parentNode.selectionModel;
+ sm.selectedIndex = sm.leadIndex = sm.anchorIndex = index;
+
alert(localStrings.getString('invalid_url'));
}
urlInput.focus();
diff --git a/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_tree.js b/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_tree.js
index 453692c..c2ec844 100644
--- a/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_tree.js
+++ b/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_tree.js
@@ -78,7 +78,7 @@ cr.define('bmm', function() {
};
// Clean up once per session but wait until things settle down a bit.
- setTimeout(cr.bind(expandedManager.cleanUp, expandedManager), 1e4);
+ setTimeout(expandedManager.cleanUp.bind(expandedManager), 1e4);
/**
* Creates a new tree item for a bookmark node.
diff --git a/chrome/browser/resources/bookmark_manager/main.html b/chrome/browser/resources/bookmark_manager/main.html
index e6f9cbe..d3e041b 100644
--- a/chrome/browser/resources/bookmark_manager/main.html
+++ b/chrome/browser/resources/bookmark_manager/main.html
@@ -8,6 +8,8 @@ found in the LICENSE file.
-->
<head>
+<meta name="google" value="notranslate">
+
<title i18n-content="title"></title>
<link rel="stylesheet" href="chrome://resources/css/list.css">
@@ -32,6 +34,7 @@ found in the LICENSE file.
<script src="chrome://resources/js/cr/ui/context_menu_button.js"></script>
<script src="chrome://resources/js/cr/ui/context_menu_handler.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_item.js"></script>
<script src="chrome://resources/js/cr/ui/list.js"></script>
<script src="chrome://resources/js/cr/ui/tree.js"></script>
@@ -1014,21 +1017,21 @@ var dnd = {
},
init: function() {
- var boundClearData = cr.bind(this.clearDragData, this);
+ var boundClearData = this.clearDragData.bind(this);
function deferredClearData() {
setTimeout(boundClearData);
}
- document.addEventListener('dragstart', cr.bind(this.handleDragStart, this));
- document.addEventListener('dragenter', cr.bind(this.handleDragEnter, this));
- document.addEventListener('dragover', cr.bind(this.handleDragOver, this));
- document.addEventListener('dragleave', cr.bind(this.handleDragLeave, this));
- document.addEventListener('drop', cr.bind(this.handleDrop, this));
+ document.addEventListener('dragstart', this.handleDragStart.bind(this));
+ document.addEventListener('dragenter', this.handleDragEnter.bind(this));
+ document.addEventListener('dragover', this.handleDragOver.bind(this));
+ document.addEventListener('dragleave', this.handleDragLeave.bind(this));
+ document.addEventListener('drop', this.handleDrop.bind(this));
document.addEventListener('dragend', deferredClearData);
document.addEventListener('mouseup', deferredClearData);
- chrome.experimental.bookmarkManager.onDragEnter.addListener(cr.bind(
- this.handleChromeDragEnter, this));
+ chrome.experimental.bookmarkManager.onDragEnter.addListener(
+ this.handleChromeDragEnter.bind(this));
chrome.experimental.bookmarkManager.onDragLeave.addListener(
deferredClearData);
chrome.experimental.bookmarkManager.onDrop.addListener(deferredClearData);
@@ -1377,10 +1380,9 @@ list.addEventListener('canceledit', function(e) {
var item = e.target;
var bookmarkNode = item.bookmarkNode;
if (bookmarkNode.id == 'new') {
- list.remove(item);
- list.selectionModel.leadItem = list.lastChild;
- list.selectionModel.anchorItem = list.lastChild;
- list.focus();
+ var dataModel = list.dataModel;
+ var index = dataModel.findIndexById('new');
+ dataModel.splice(index, 1);
}
});
@@ -1520,8 +1522,8 @@ function newFolder() {
title: localStrings.getString('new_folder_name'),
parentId: parentId
}, function(newNode) {
- // We need to do this in a timeout to be able to focus the newly created
- // item.
+ // This callback happens before the event that triggers the tree/list to
+ // get updated so delay the work so that the tree/list gets updated first.
setTimeout(function() {
var newItem;
if (isTree) {
@@ -1536,7 +1538,7 @@ function newFolder() {
}
newItem.editing = true;
- });
+ }, 50);
});
}
diff --git a/chrome/browser/resources/cc-generic.png b/chrome/browser/resources/cc-generic.png
deleted file mode 100644
index d79734c..0000000
--- a/chrome/browser/resources/cc-generic.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chat_manager/background.html b/chrome/browser/resources/chat_manager/background.html
index 02dead5..964db68 100644
--- a/chrome/browser/resources/chat_manager/background.html
+++ b/chrome/browser/resources/chat_manager/background.html
@@ -21,11 +21,19 @@ to route both incoming and outgoing chats through this central roster.
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() {
- for (var listenerPort in centralJidListenerPorts) {
- listenerPort.postMessage({jid: centralRosterJid});
- }
+ forwardEventToPortListeners(
+ ChatBridgeEventTypes.CENTRAL_USER_UPDATE, centralRosterJid);
}
// Central roster jid changed. Notify all listeners.
@@ -53,9 +61,6 @@ to route both incoming and outgoing chats through this central roster.
}
}
});
- if (centralRosterJid) {
- port.postMessage({jid: centralRosterJid});
- }
// New central jid broadcaster.
// Add listener for jid changes, and track port for forwarding chats.
} else if (port.name == 'centralJidBroadcaster') {
@@ -79,21 +84,33 @@ to route both incoming and outgoing chats through this central roster.
});
// Listen for requests from our content scripts.
- chrome.extension.onRequest.addListener(function(request, sender) {
+ 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(
- {chatType: request.msg, jid: request.jid});
+ {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;
}
});
</script>
diff --git a/chrome/browser/resources/chat_manager/central_roster.html b/chrome/browser/resources/chat_manager/central_roster.html
index 34fd788..aa68798 100644
--- a/chrome/browser/resources/chat_manager/central_roster.html
+++ b/chrome/browser/resources/chat_manager/central_roster.html
@@ -9,7 +9,7 @@ found in the LICENSE file.
Central roster: hosting all Google Talk chats in ChromeOS.
-->
-<body>
+<head>
<style>
.talk_roster {
position: fixed;
@@ -20,11 +20,20 @@ Central roster: hosting all Google Talk chats in ChromeOS.
width: 100%;
height: 100%;
border: none;
- overflow-x: hidden;
- overflow-y: hidden;
+ overflow: hidden;
+ }
+ body {
+ text-align: center;
}
</style>
<script>
+ var MIN_RETRY_MILLISECONDS = 15 * 1000;
+ var MAX_RETRY_MILLISECONDS = 4 * 60 * 1000;
+ var retryStartTime = 0;
+ var retryTime;
+ var retryTimer;
+ var chatClient = null;
+
var args = {
'protocol': 'https',
'host': 'talkgadget.google.com',
@@ -39,66 +48,77 @@ Central roster: hosting all Google Talk chats in ChromeOS.
args[argParts[0]] = argParts[1];
}
}
- document.write('<script src="' +
+ var notifierScriptUrl =
args['protocol'] + '://' + args['host'] +
'/talkgadget/notifier-js?silent=true&host=' +
args['protocol'] + '://' + args['host'] +
'/talkgadget/notifier-js' +
- (args['jsmode'] != '' ? ('&jsmode=' + args['jsmode']) : '') +
- '"></scr' + 'ipt>');
-</script>
-<script>
- var reloadTime = 60000;
- var reloadTimer;
- function reloadPage() {
- if (reloadTimer) {
- clearTimeout(reloadTimer);
- reloadTimer = null;
+ (args['jsmode'] != '' ? ('&jsmode=' + args['jsmode']) : '');
+
+ function runGTalkScript() {
+ var script = document.createElement('script');
+ script.src = notifierScriptUrl;
+ script.onload = loadGTalk;
+ script.onerror = loadGTalk;
+ document.body.appendChild(script);
+ }
+ function retryConnection() {
+ if (retryTimer) {
+ clearTimeout(retryTimer);
+ retryTimer = null;
}
- window.location.reload(true);
+ runGTalkScript();
}
- function reloadPageCountdown() {
- document.getElementById('reloadStatus').textContent =
- 'Retrying in ' + reloadTime / 1000 + ' seconds';
- if (reloadTime <= 0) {
- reloadPage();
+ function retryConnectionCountdown() {
+ var seconds = retryTime / 1000;
+ var minutes = Math.floor(seconds / 60);
+ seconds -= minutes * 60;
+
+ document.getElementById('retryStatus').textContent =
+ 'Retrying in ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
+ if (retryTime <= 0) {
+ retryConnection();
} else {
- reloadTimer = setTimeout(reloadPageCountdown, 1000);
+ retryTimer = setTimeout(retryConnectionCountdown, 1000);
+ retryTime -= 1000;
}
- reloadTime -= 1000;
}
- var chatClient = null;
- if (window.GTalkNotifier) {
- chatClient = new GTalkNotifier(
- args['protocol'] + '://' + args['host'] + '/talkgadget/',
- 'notifierclient' +
- (args['jsmode'] != '' ? ('?jsmode=' + args['jsmode']) : ''),
- 'ifpc_relay',
- 'ifpc.js',
- 'Google Talk',
- {
- hostCallback: function(){},
- xpcRelay: 'xpc_relay',
- xpcBlank: 'xpc_blank',
- locale: args['hl'],
- isCentralRoster: true,
- hideProfileCard: true,
- isFullFrame: true
- }
- );
- } else {
- reloadTimer = setTimeout(reloadPageCountdown, 0);
- document.write(
- '<style>' +
- 'body {' +
- 'text-align: center;' +
- '}' +
- '</style>' +
- '<p>Could not connect to Google Talk</p>' +
- '<p id="reloadStatus"></p>' +
- '<input type="button" value="Retry Now" onclick="reloadPage()"/>'
- );
+ function loadGTalk() {
+ if (window.GTalkNotifier) {
+ document.getElementById('retryInfo').style.display = 'none';
+ chatClient = new window.GTalkNotifier(
+ {
+ 'clientBaseUrl':
+ args['protocol'] + '://' + args['host'] + '/talkgadget/',
+ 'clientUrl': 'notifierclient' +
+ (args['jsmode'] != '' ? ('?jsmode=' + args['jsmode']) : ''),
+ 'propertyName': 'ChromeOS',
+ 'xpcRelay': 'xpc_relay',
+ 'xpcBlank': 'xpc_blank',
+ 'locale': args['hl'],
+ 'isCentralRoster': true,
+ 'hideProfileCard': true,
+ 'isFullFrame': true
+ }
+ );
+ } else {
+ if (retryStartTime == 0) {
+ retryStartTime = MIN_RETRY_MILLISECONDS;
+ } else if (retryStartTime < MAX_RETRY_MILLISECONDS) {
+ retryStartTime = Math.min(retryStartTime * 2, MAX_RETRY_MILLISECONDS);
+ }
+ retryTime = retryStartTime;
+ document.getElementById('retryInfo').style.display = 'inline';
+ retryConnectionCountdown();
+ }
}
</script>
+</head>
+<body onload='runGTalkScript()'>
+ <div id='retryInfo' style='display:none'>
+ <p>Could not connect to Google Talk</p>
+ <p id='retryStatus'></p>
+ <input type='button' value='Retry Now' onclick='retryConnection()'/>
+ </div>
</body>
</html>
diff --git a/chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js b/chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js
index f5095f7..8607fe8 100644
--- a/chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js
+++ b/chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js
@@ -14,5 +14,9 @@ var ChatBridgeEventTypes = {
NEW_VOICE_CHAT: 'newVoiceChat',
CENTRAL_USER_SET: 'centralJidSet',
CENTRAL_USER_UPDATE: 'centralJidUpdate',
- CENTRAL_USER_WATCHER: 'getCentralJid'
+ CENTRAL_USER_WATCHER: 'getCentralJid',
+ OPENED_MOLE_INCOMING: 'onMoleOpened',
+ OPENED_MOLE_OUTGOING: 'onCentralMoleOpened',
+ CLOSED_MOLE_INCOMING: 'onMoleClosed',
+ CLOSED_MOLE_OUTGOING: 'onCentralMoleClosed'
};
diff --git a/chrome/browser/resources/chat_manager/js/chatbridgehook.js b/chrome/browser/resources/chat_manager/js/chatbridgehook.js
index d2ac63f..afbe0be 100644
--- a/chrome/browser/resources/chat_manager/js/chatbridgehook.js
+++ b/chrome/browser/resources/chat_manager/js/chatbridgehook.js
@@ -15,6 +15,10 @@ 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.
@@ -39,15 +43,33 @@ function forwardChatEvent(event) {
}
/**
+ * Triggered on opening/closing a central roster chat. Forward to extension.
+ * @param {MessageEvent} event the opened/closed event.
+ */
+function moleOpenedClosed(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} chatType the chat event type.
+ * @param {string} eventType the event type.
* @param {string} chatJid the jid to route the chat event to.
*/
-function dispatchChatEvent(chatType, chatJid) {
- var showChatEvent = document.createEvent('MessageEvent');
- showChatEvent.initMessageEvent(chatType, true, true, chatJid);
- divRosterHandler.dispatchEvent(showChatEvent);
+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);
}
/**
@@ -60,11 +82,10 @@ function centralRosterHandler(event) {
centralJidBroadcasterPort = chrome.extension.connect(
{name: 'centralJidBroadcaster'});
centralJidBroadcasterPort.onMessage.addListener(function(msg) {
- var chatJid = msg.jid;
- dispatchChatEvent(msg.chatType, chatJid);
+ dispatchChatEvent(msg.eventType, msg.jid);
});
}
- var centralRosterJid = event.data;
+ centralRosterJid = event.data;
centralJidBroadcasterPort.postMessage({jid: centralRosterJid});
}
@@ -74,30 +95,61 @@ function centralRosterHandler(event) {
*/
function setupCentralRosterJidListener(event) {
if (!centralJidListenerChatPort) {
+ if (centralRosterJid) {
+ dispatchCentralJid(centralRosterJid);
+ }
centralJidListenerChatPort = chrome.extension.connect(
{name: 'centralJidListener'});
centralJidListenerChatPort.onMessage.addListener(function(msg) {
- var centralRosterJid = msg.jid;
- var outgoingChatEvent = document.createEvent('MessageEvent');
- outgoingChatEvent.initMessageEvent(
- ChatBridgeEventTypes.CENTRAL_USER_UPDATE,
- true, true, centralRosterJid);
- divRosterHandler.dispatchEvent(outgoingChatEvent);
+ if (msg.eventType == ChatBridgeEventTypes.CENTRAL_USER_UPDATE) {
+ centralRosterJid = msg.jid;
+ }
+ dispatchChatEvent(msg.eventType, msg.jid);
});
}
}
-// Search for communication channel div.
-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);
+/**
+ * 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,
+ moleOpenedClosed, false);
+ divRosterHandler.addEventListener(
+ ChatBridgeEventTypes.CLOSED_MOLE_INCOMING,
+ moleOpenedClosed, 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
index 54b9b2f..2cb9041 100644
--- a/chrome/browser/resources/chat_manager/js/gmailbridgehook.js
+++ b/chrome/browser/resources/chat_manager/js/gmailbridgehook.js
@@ -10,6 +10,10 @@ 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.
@@ -21,33 +25,76 @@ function forwardChatEvent(event) {
}
/**
+ * @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) {
- var centralRosterJid = msg.jid;
- var outgoingChatEvent = document.createEvent('MessageEvent');
- outgoingChatEvent.initMessageEvent(
- ChatBridgeEventTypes.CENTRAL_USER_UPDATE,
- true, true, centralRosterJid);
- divGmailHandler.dispatchEvent(outgoingChatEvent);
+ if (msg.eventType == ChatBridgeEventTypes.CENTRAL_USER_UPDATE) {
+ centralRosterJid = msg.jid;
+ }
+ dispatchChatEvent(msg.eventType, msg.jid);
});
}
}
-// Search for communication channel div.
-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);
+/**
+ * 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
index ea4b743..41e6f8a 100644
--- a/chrome/browser/resources/chat_manager/manifest.json
+++ b/chrome/browser/resources/chat_manager/manifest.json
@@ -1,7 +1,7 @@
{
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDrlwvcbUtVrbQvI7EPV1BTa63N8YkbBToHzxlMl0IzSBwOV+TUOsHE8vRq0HZWuwMAGeH8WdWVC3HRNdES8lScjlzxb1TsTQJAsF+hLXgcjgCUSSSGCfFzypvuvKsRQTx0d02yfWKJa47o0Ws5wL72NVtc7c51HujwWYg+Mz01wIDAQAB",
"name": "Google Chat Manager",
- "version": "1.0.3",
+ "version": "1.0.11",
"icons": {
"128": "128.png",
"24": "24.png",
@@ -10,6 +10,7 @@
},
"description": "Google Chat Manager",
"background_page": "background.html",
+ "options_page": "options.html",
"content_scripts": [ {
"js": [
"js/chatbridgeeventtypes.js",
@@ -18,7 +19,7 @@
"matches": [
"*://talkgadget.google.com/*"
],
- "run_at": "document_end",
+ "run_at": "document_start",
"all_frames": true
},{
"js": [
@@ -28,20 +29,18 @@
"matches": [
"*://mail.google.com/*"
],
- "run_at": "document_end"
+ "run_at": "document_start"
}],
"permissions": [
"tabs",
"*://talkgadget.google.com/*"
],
- "launch": {
- "local_path": "central_roster_viewer.html",
- "container": "panel"
- },
"app": {
"launch": {
"local_path": "central_roster_viewer.html",
- "container": "panel"
+ "container": "panel",
+ "width": 225,
+ "height": 360
}
}
}
diff --git a/chrome/browser/resources/diners.png b/chrome/browser/resources/diners.png
deleted file mode 100644
index ee709d3..0000000
--- a/chrome/browser/resources/diners.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/discover.png b/chrome/browser/resources/discover.png
deleted file mode 100644
index e1fdbac..0000000
--- a/chrome/browser/resources/discover.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/downloads.html b/chrome/browser/resources/downloads.html
index 6b44d89..dd40f57 100644
--- a/chrome/browser/resources/downloads.html
+++ b/chrome/browser/resources/downloads.html
@@ -108,7 +108,7 @@ html[dir=rtl] .icon {
.download.otr > .safe,
.download.otr > .show-dangerous {
- background: url(chrome://theme/IDR_OTR_ICON_STANDALONE) no-repeat 100% 100%;
+ background: url('shared/images/otr_icon_standalone.png') no-repeat 100% 100%;
opacity: .66;
-webkit-transition: opacity .15s;
}
@@ -198,15 +198,6 @@ html[dir=rtl] .name {
// Helper functions
function $(o) {return document.getElementById(o);}
-function bind(fn, selfObj, var_args) {
- var boundArgs = Array.prototype.slice.call(arguments, 2);
- return function() {
- var args = Array.prototype.slice.call(arguments);
- args.unshift.apply(args, boundArgs);
- return fn.apply(selfObj, args);
- }
-}
-
/**
* Sets the display style of a node.
*/
@@ -385,7 +376,7 @@ function Download(download) {
// Container for all 'safe download' UI.
this.safe_ = createElementWithClassName('div', 'safe');
- this.safe_.ondragstart = bind(this.drag_, this);
+ this.safe_.ondragstart = this.drag_.bind(this);
this.node.appendChild(this.safe_);
if (download.state != Download.States.COMPLETE) {
@@ -412,7 +403,7 @@ function Download(download) {
this.nodeTitleArea_ = createElementWithClassName('div', 'title-area');
this.safe_.appendChild(this.nodeTitleArea_);
- this.nodeFileLink_ = createLink(bind(this.openFile_, this), '');
+ this.nodeFileLink_ = createLink(this.openFile_.bind(this), '');
this.nodeFileLink_.className = 'name';
this.nodeFileLink_.style.display = 'none';
this.nodeTitleArea_.appendChild(this.nodeFileLink_);
@@ -435,26 +426,26 @@ function Download(download) {
// http://code.google.com/p/chromium-os/issues/detail?id=916.
var showinfolder = localStrings.getString('control_showinfolder');
if (showinfolder) {
- this.controlShow_ = createLink(bind(this.show_, this), showinfolder);
+ this.controlShow_ = createLink(this.show_.bind(this), showinfolder);
this.nodeControls_.appendChild(this.controlShow_);
} else {
this.controlShow_ = null;
}
// Pause/Resume are a toggle.
- this.controlPause_ = createLink(bind(this.togglePause_, this),
+ this.controlPause_ = createLink(this.togglePause_.bind(this),
localStrings.getString('control_pause'));
this.nodeControls_.appendChild(this.controlPause_);
- this.controlResume_ = createLink(bind(this.togglePause_, this),
+ this.controlResume_ = createLink(this.togglePause_.bind(this),
localStrings.getString('control_resume'));
this.nodeControls_.appendChild(this.controlResume_);
- this.controlRemove_ = createLink(bind(this.remove_, this),
+ this.controlRemove_ = createLink(this.remove_.bind(this),
localStrings.getString('control_removefromlist'));
this.nodeControls_.appendChild(this.controlRemove_);
- this.controlCancel_ = createLink(bind(this.cancel_, this),
+ this.controlCancel_ = createLink(this.cancel_.bind(this),
localStrings.getString('control_cancel'));
this.nodeControls_.appendChild(this.controlCancel_);
@@ -465,11 +456,11 @@ function Download(download) {
this.dangerDesc_ = document.createElement("div");
this.danger_.appendChild(this.dangerDesc_);
- this.dangerSave_ = createButton(bind(this.saveDangerous_, this),
+ this.dangerSave_ = createButton(this.saveDangerous_.bind(this),
localStrings.getString("danger_save"));
this.danger_.appendChild(this.dangerSave_);
- this.dangerDiscard_ = createButton(bind(this.discardDangerous_, this),
+ this.dangerDiscard_ = createButton(this.discardDangerous_.bind(this),
localStrings.getString("danger_discard"));
this.danger_.appendChild(this.dangerDiscard_);
diff --git a/chrome/browser/resources/extension_default_icon.png b/chrome/browser/resources/extension_default_icon.png
deleted file mode 100644
index 31aaf05..0000000
--- a/chrome/browser/resources/extension_default_icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/extensions_infobar_mac.css b/chrome/browser/resources/extensions_infobar_mac.css
index c2a9bbe..92a130e 100644
--- a/chrome/browser/resources/extensions_infobar_mac.css
+++ b/chrome/browser/resources/extensions_infobar_mac.css
@@ -6,8 +6,8 @@ body {
background: -webkit-gradient(linear, left top, left bottom,
from(#EBEBEB), to(#CFCFCF));
font-family: 'Lucida Grande', Helvetica, sans-serif;
- font-size: 11px;
+ font-size: 12px;
height: 36px; /* Infobars are limited to 36-72px */
- margin: 0px;
+ margin: 0 38px;
overflow: hidden;
}
diff --git a/chrome/browser/resources/extensions_toolstrip.css b/chrome/browser/resources/extensions_toolstrip.css
deleted file mode 100644
index d4691fc..0000000
--- a/chrome/browser/resources/extensions_toolstrip.css
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * The following style rules affect toolstrips and moles and are affected by
- * theme changes.
- */
-
-body {
- color: $TEXT_COLOR$;
-}
diff --git a/chrome/browser/resources/extensions_ui.html b/chrome/browser/resources/extensions_ui.html
index 5e9b020..4a7c035 100644
--- a/chrome/browser/resources/extensions_ui.html
+++ b/chrome/browser/resources/extensions_ui.html
@@ -14,13 +14,16 @@ a {
font-size: 103%;
}
-#header {
+div#header {
margin-bottom: 1.05em;
+ /* 67px is the height of the header's background image. */
+ min-height: 67px;
overflow: hidden;
- padding-bottom: 1.5em;
+ padding-bottom: 20px;
padding-left: 0;
- padding-top: 1.5em;
+ padding-top: 20px;
position: relative;
+ -webkit-box-sizing: border-box;
}
html[dir=rtl] #header {
@@ -35,6 +38,7 @@ html[dir=rtl] #header {
padding-left: 75px;
padding-top: 40px;
}
+
html[dir=rtl] #header h1 {
background: url('../../app/theme/extensions_section.png') right no-repeat;
padding-right: 95px;
@@ -355,6 +359,7 @@ var extensionDataFormat = {
'wantsFileAccess': 'false',
'allowFileAccess': 'false',
'allow_reload': true,
+ 'is_hosted_app': false,
'order': 1,
'options_url': 'options.html',
'icon': 'relative-path-to-icon.png',
@@ -378,12 +383,14 @@ var extensionDataFormat = {
{
'path': 'toolstrip.html',
'renderViewId': 1,
- 'renderProcessId': 1
+ 'renderProcessId': 1,
+ 'incognito': false
},
{
'path': 'background.html',
'renderViewId': 2,
- 'renderProcessId': 1
+ 'renderProcessId': 1,
+ 'incognito': false
}
]
},
@@ -397,6 +404,7 @@ var extensionDataFormat = {
'wantsFileAccess': 'false',
'allowFileAccess': 'false',
'allow_reload': false,
+ 'is_hosted_app': false,
'order': 2,
'icon': '',
'content_scripts': [
@@ -415,7 +423,8 @@ var extensionDataFormat = {
{
'path': 'foo/bar/toolstrip.html',
'renderViewId': 3,
- 'renderProcessId': 1
+ 'renderProcessId': 1,
+ 'incognito': false
}
],
"hasPopupAction": false
@@ -856,12 +865,15 @@ document.addEventListener('DOMContentLoaded', requestExtensionsData);
</span>
<ul class="extension-views">
<li jsselect="views">
- <a jsvalues=".extensionView:$this" href="#"
- onclick="sendInspectMessage(this.extensionView); return false;">
- <span jscontent="path"></span>
- </a>
+ <span jsvalues=".extensionView:$this">
+ <a jsvalues=".extensionView:$this" href="#"
+ onclick="sendInspectMessage(this.extensionView); return false;">
+ <span jscontent="path"></span></a>
+ <span jsdisplay="incognito"
+ i18n-content="viewIncognito">(INCOGNITO)</span>
+ </span>
</li>
- <li i18n-content="inspectPopupsInstructions"
+ <li i18n-content="inspectPopupsInstructions"
class="inspectPopupNote" jsdisplay="hasPopupAction">
INSPECT POPUP INSRUCTIONS
</li>
@@ -906,8 +918,7 @@ document.addEventListener('DOMContentLoaded', requestExtensionsData);
href="javascript:void 0;"
i18n-content="options"
>OPTIONS</a>
- <label
- jsdisplay="enabled">
+ <label jsdisplay="enabled && !is_hosted_app">
<input type="checkbox"
jsvalues=".extensionId:id;.enabled:enabled"
jsdisplay="enabled"
diff --git a/chrome/browser/resources/filebrowse.html b/chrome/browser/resources/filebrowse.html
index 8b01ade..12ed9dc 100644
--- a/chrome/browser/resources/filebrowse.html
+++ b/chrome/browser/resources/filebrowse.html
@@ -29,6 +29,15 @@ div.header {
color: black;
}
+*:-khtml-drag {
+ background-color: rgba(238,238,238, 0.5);
+}
+
+*[draggable] {
+ -khtml-user-drag: element;
+ cursor: move;
+}
+
.rowlink {
height: 100%;
width: 90%;
@@ -95,7 +104,6 @@ div.header {
a.iconlink {
display: block;
-/* font-family: helvetica; */
font-weight: bold;
font-size: 11px;
color: white;
@@ -167,10 +175,12 @@ li.filebrowserow div.icon {
.rightarrow {
opacity: 0.5;
+ position: absolute;
+ right: 22px;
+ top: 8px;
}
.menuicon {
- background: url('shared/images/filebrowse_menu.png');
position: absolute;
right: 4px;
top: 5px;
@@ -184,6 +194,17 @@ li.filebrowserow div.icon {
-webkit-transition: opacity 0.2s ease-out ;
}
+.spinicon {
+ position: absolute;
+ right: 4px;
+ top: 5px;
+ height: 100%;
+ width: 15px;
+ margin-left: 0;
+ margin-top: 5px;
+ background-repeat: no-repeat;
+}
+
li.filebrowserow:hover .menuicon {
opacity: 0.75;
-webkit-transition: opacity 0.0s ease-out ;
@@ -219,9 +240,7 @@ li.filebrowserow:hover .menuicon:hover {
li.filebrowserow {
border-bottom: 1px solid #f7f7f7;
padding: 8px 5px 5px 54px;
-/* overflow: hidden; */
font-size: .8em;
-/* font-family: helvetica; */
position: relative;
background: #fff;
}
@@ -260,9 +279,12 @@ li.filebrowserow input.name {
}
li.filebrowserow span.namelink {
- margin-top: 10px;
margin-left: -22px;
position: relative;
+ display: block;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
color:#0D0052;
-webkit-transition: color 1.0s ease-out ;
}
@@ -318,7 +340,7 @@ div.column {
position: relative;
}
-div.columnlist {
+div.columnlistadv {
width: 100%;
bottom: 0;
top: 32px;
@@ -327,6 +349,15 @@ div.columnlist {
overflow-x: hidden;
}
+div.columnlist {
+ width: 100%;
+ bottom: 0;
+ top: 0;
+ position: absolute;
+ overflow-y: scroll;
+ overflow-x: hidden;
+}
+
div.iconmedia {
background: url('shared/images/icon_media.png');
}
@@ -371,10 +402,9 @@ div.scanningcontainer {
}
div.filebutton {
- width: 70px;
height: 18px;
cursor: pointer;
- padding-top: 2px;
+ padding: 3px 3px;
border: 1px solid #abb6ce;
background-color: #f5f7fc;
border-radius: 5px;
@@ -390,7 +420,7 @@ div.filebutton {
}
.filename {
- left: 80px;
+ left: 90px;
top: 5px;
right: 10px;
font-size: .8em;
@@ -405,16 +435,13 @@ div.openbutton {
div.cancelbutton {
bottom: 5px;
- left: 90px;
+ left: 100px;
position: absolute;
}
div.newfolderbutton {
bottom: 5px;
right: 10px;
- padding-left: 2px;
- padding-right: 2px;
- padding-top: 3px;
position: absolute;
}
@@ -584,6 +611,10 @@ function partial(fn, var_args) {
};
}
+function supportsPdf() {
+ return 'application/pdf' in navigator.mimeTypes;
+}
+
var currentSavedPath = '';
var currentNode = -1;
var menus = [];
@@ -615,7 +646,7 @@ function enabledResult(info) {
mediaPlayerEnabled = info.mpEnabled;
mainColumn = $('main');
if (!advancedEnabled) {
- $('back').style.display = 'none';
+ $('header').style.display = 'none';
}
if(document.documentElement.clientWidth <= 600) {
inFullMode = false;
@@ -814,6 +845,31 @@ function browseFileResult(info, results) {
}
} else if (info.functionCall == 'getChildren') {
var main = getCurrentContainer();
+ main.addEventListener('dragover', function(e) {
+ if (e.preventDefault) e.preventDefault();
+ e.dataTransfer.dropEffect = 'copy';
+ return false;
+ }, false);
+ main.addEventListener('drop', function(e) {
+ if (e.stopPropagation) e.stopPropagation();
+ var src = e.dataTransfer.getData('Text');
+ var path = getPathAndFilenameForPath(src);
+ var dest = currentSavedPath + '/' + path[2];
+ var dirId = $('list/dir/' + currentSavedPath);
+ if (dirId) {
+
+ var element = $(dest);
+ if (!element) {
+ // TODO(dhg): We probably should do some checking for
+ // existance.
+ element = createNewFakeItem(path[2], dest, false, true);
+ }
+ dirId.appendChild(element);
+ element.scrollIntoView();
+ }
+ chrome.send('copyFile', [src, dest]);
+ return false;
+ }, false);
main.id = 'dir/' + info.path;
divArray.push(main);
document.location.hash = info.path;
@@ -1014,6 +1070,7 @@ function deleteFileConfirm(path) {
no.className = 'deleteNo';
askingDiv.appendChild(yes);
askingDiv.appendChild(no);
+ yes.scrollIntoView();
var element = menus[path];
if (element) {
element.firstChild.appendChild(askingDiv);
@@ -1070,14 +1127,64 @@ function newDownload(results) {
var dirId = $('list/dir/' + extracted[1]);
if (dirId) {
element = createNewItem(extracted[2], results[x].file_path, false);
- dirId.appendChild(element);
+ downloadList.push(element);
+ if (dirId.firstChild) {
+ dirId.insertBefore(element, dirId.firstChild);
+ } else {
+ dirId.appendChild(element);
+ }
element.scrollIntoView();
}
}
}
}
+function removeDownload(element) {
+ var status = undefined;
+ var pause = undefined;
+ for (var x = 0; x < element.children.length; x++) {
+ if (element.children[x].className == 'downloadstatus') {
+ var child = element.children[x];
+ status = child;
+ } else if (element.children[x].className == 'downloadpause') {
+ var child = element.children[x];
+ pause = child;
+ }
+ }
+ if (status) {
+ element.removeChild(status);
+ }
+ if (pause) {
+ element.removeChild(pause);
+ }
+ element.className = 'filebrowserow';
+ var elementList = [];
+ for (var x = 0; x < downloadList.length; x++) {
+ if (element != downloadList[x]) {
+ elementList.push(downloadList[x]);
+ }
+ }
+ downloadList = elementList;
+}
+
function downloadUpdated(results) {
+ var removeDownloads = [];
+ for (var y = 0; y < downloadList.length; y++) {
+ var found = false;
+ for (var x = 0; x < results.length; x++) {
+ var element = $(results[x].file_path);
+ if (downloadList[y] == element) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ removeDownloads.push(downloadList[y]);
+ }
+ }
+ for (var x = 0; x < removeDownloads.length; x++) {
+ removeDownload(removeDownloads[x]);
+ }
for (var x = 0; x < results.length; x++) {
var element = $(results[x].file_path);
if (!element && results[x].state != 'CANCELLED') {
@@ -1085,7 +1192,11 @@ function downloadUpdated(results) {
var dirId = $('list/dir/' + extracted[1]);
if (dirId) {
element = createNewItem(extracted[2], results[x].file_path, false);
- dirId.appendChild(element);
+ if (dirId.firstChild) {
+ dirId.insertBefore(element, dirId.firstChild);
+ } else {
+ dirId.appendChild(element);
+ }
element.scrollIntoView();
}
}
@@ -1103,6 +1214,7 @@ function downloadUpdated(results) {
}
}
if (progressDiv == null) {
+ downloadList.push(element);
element.className = 'filebrowserow downloading';
var progressDiv = document.createElement('div');
progressDiv.className = 'downloadstatus';
@@ -1142,24 +1254,7 @@ function downloadUpdated(results) {
}
} else {
- var status = undefined;
- var pause = undefined;
- for (var x = 0; x < element.children.length; x++) {
- if (element.children[x].className == 'downloadstatus') {
- var child = element.children[x];
- status = child;
- } else if (element.children[x].className == 'downloadpause') {
- var child = element.children[x];
- pause = child;
- }
- }
- if (status) {
- element.removeChild(status);
- }
- if (pause) {
- element.removeChild(pause);
- }
- element.className = 'filebrowserow';
+ removeDownload(element);
}
}
}
@@ -1174,7 +1269,8 @@ function dialogNewFolderClick() {
var main = divArray[divArray.length - 1];
var list;
for (var x = 0; x < main.childNodes.length; x++ ) {
- if (main.childNodes[x].className == 'columnlist') {
+ if (main.childNodes[x].className == 'columnlist' ||
+ main.childNodes[x].className == 'columnlistadv') {
list = main.childNodes[x].firstChild;
break;
}
@@ -1267,7 +1363,7 @@ function showImage(path) {
}
}
-function showText(path) {
+function showPath(path) {
chrome.send('openNewFullWindow', ['file://' + path]);
}
@@ -1299,6 +1395,7 @@ function showMenu(path) {
element.firstChild.style.display = 'block';
element.style.opacity = '1';
currentMenu = element;
+ currentMenu.scrollIntoView();
}
window.event.stopPropagation();
}
@@ -1396,9 +1493,15 @@ function getFunctionForItem(path, id, isDirectory) {
}
if (pathIsHtmlFile(path)) {
return function() {
- showText(path);
+ showPath(path);
+ }
+ }
+ if (pathIsPdfFile(path) && supportsPdf()) {
+ return function() {
+ showPath(path);
}
}
+
return getUnknownFileTypeHandler();
}
@@ -1425,9 +1528,49 @@ function getDoubleClickForItem(path, id, isDirectory) {
var elementIdCounter = 0;
+function createNewFakeItem(title, path, isDirectory, hasspinner) {
+ var element = document.createElement('li');
+
+ element.className = 'filebrowserow';
+ element.id = path;
+ elementIdCounter++;
+ var link;
+ link = document.createElement('div');
+ link.className = 'rowlink';
+
+ var icon = document.createElement('div');
+ icon.className = getClassForPath(path, isDirectory);
+ link.appendChild(icon);
+
+ var span = document.createElement('span');
+ span.className = 'name';
+ span.textContent = title;
+ link.appendChild(span);
+
+ element.appendChild(link);
+
+ // Setup Menu
+ var currentPath = currentSavedPath;
+ if (hasspinner) {
+ var spinicon = document.createElement('div');
+ spinicon.align = 'right';
+ spinicon.className = 'spinicon';
+ element.appendChild(spinicon);
+ }
+ return element;
+}
+
function createNewItem(title, path, isDirectory) {
var element = document.createElement('li');
+ element.setAttribute('draggable', 'true');
+
+ element.addEventListener('dragstart', function (e) {
+ e.dataTransfer.effectAllowed = 'copy';
+ e.dataTransfer.setData('Text', this.id);
+ }, false);
+
element.className = 'filebrowserow';
+ element.title = title;
/*element.id = 'listItem' + elementIdCounter;*/
element.id = path;
elementIdCounter++;
@@ -1458,22 +1601,7 @@ function createNewItem(title, path, isDirectory) {
var menuicon = document.createElement('div');
var menu = document.createElement('div');
menu.className = 'menu';
- if (pathIsImageFile(path)) {
- var picasaitem = document.createElement('div');
- var flickritem = document.createElement('div');
- var emailitem = document.createElement('div');
- picasaitem.textContent = localStrings.getString('picasaweb');
- flickritem.textContent = localStrings.getString('flickr');
- emailitem.textContent = localStrings.getString('email');
- picasaitem.className = 'menuitem';
- flickritem.className = 'menuitemdisabled';
- emailitem.className = 'menuitemdisabled';
- picasaitem.onclick = partial(uploadImage, path);
- menu.appendChild(picasaitem);
- menu.appendChild(flickritem);
- menu.appendChild(emailitem);
- }
- if ((pathIsVideoFile(path) || pathIsAudioFile(path)) &&
+ if ((pathIsVideoFile(path) || pathIsAudioFile(path)) &&
mediaPlayerEnabled) {
var enqueueitem = document.createElement('div');
enqueueitem.textContent = localStrings.getString('enqueue');
@@ -1512,30 +1640,39 @@ function popout(path) {
}
function createNewList(title, results, main, path) {
+ downloadList = [];
clearChildren(main);
var mainList = document.createElement('div');
- mainList.className = 'columnlist';
+ if (advancedEnabled) {
+ mainList.className = 'columnlistadv';
+ } else {
+ mainList.className = 'columnlist';
+ }
+
var list = document.createElement('ul');
list.className = 'filebrowselist';
list.id = 'list/dir/' + path;
- var header = document.createElement('div');
- header.className = 'header';
- var divTitle = document.createElement('div');
- divTitle.className = 'title';
- if (inFullMode) {
- divTitle.style['text-align'] = 'center';
- }
- divTitle.innerHTML = title;
- if (inFullMode && (path.length != 0)) {
- var popOutButton = document.createElement('div');
- popOutButton.innerHTML = '&prod;';
- popOutButton.className = 'popout';
- popOutButton.onclick = partial(popout, path);
- header.appendChild(popOutButton);
+ document.title = title;
+ if (advancedEnabled) {
+ var header = document.createElement('div');
+ header.className = 'header';
+ var divTitle = document.createElement('div');
+ divTitle.className = 'title';
+ if (inFullMode) {
+ divTitle.style['text-align'] = 'center';
+ }
+ divTitle.innerHTML = title;
+ if (inFullMode && (path.length != 0)) {
+ var popOutButton = document.createElement('div');
+ popOutButton.innerHTML = '&prod;';
+ popOutButton.className = 'popout';
+ popOutButton.onclick = partial(popout, path);
+ header.appendChild(popOutButton);
+ }
+ header.appendChild(divTitle);
+ main.appendChild(header);
}
- header.appendChild(divTitle);
- main.appendChild(header);
main.appendChild(mainList);
for (var x=0; x < results.length; x++) {
var element = createNewItem(results[x].title,
@@ -1547,7 +1684,8 @@ function createNewList(title, results, main, path) {
}
</script>
-<body onload='load();' onclick='clearMenus()' onselectstart='return false'>
+<body onload='load();' onclick='clearMenus()' onselectstart='return false'
+ i18n-values=".style.fontFamily:fontfamily">
<div id='header' class=''>
<div id='back' class='backbutton controlbutton' onclick='goBackInList();return false;'>
<img src="shared/images/filebrowse_back.png" width='100%' height='100%'>
diff --git a/chrome/browser/resources/history2.html b/chrome/browser/resources/history2.html
index a2a2ca3..353deb8 100644
--- a/chrome/browser/resources/history2.html
+++ b/chrome/browser/resources/history2.html
@@ -38,7 +38,7 @@ var pageState;
var deleteQueue = [];
var deleteInFlight = false;
var selectionAnchor = -1;
-var id2checkbox = [];
+var idToCheckbox = [];
///////////////////////////////////////////////////////////////////////////////
@@ -53,6 +53,7 @@ function Page(result, continued, model, id) {
this.model_ = model;
this.title_ = result.title;
this.url_ = result.url;
+ this.domain_ = this.getDomainFromURL_(this.url_);
this.starred_ = result.starred;
this.snippet_ = result.snippet || "";
this.id_ = id;
@@ -79,51 +80,68 @@ function Page(result, continued, model, id) {
// Page, Public: --------------------------------------------------------------
/**
- * @return {DOMObject} Gets the DOM representation of the page
- * for use in browse results.
+ * Returns a dom structure for a browse page result or a search page result.
+ * @param {boolean} Flag to indicate if result is a search result.
+ * @return {Element} The dom structure.
*/
-Page.prototype.getBrowseResultDOM = function() {
- var node = createElementWithClassName('div', 'entry');
+Page.prototype.getResultDOM = function(searchResultFlag) {
+ var node = createElementWithClassName('li', 'entry');
var time = createElementWithClassName('div', 'time');
- if (this.model_.getEditMode()) {
- var checkbox = document.createElement('input');
- checkbox.type = "checkbox";
- checkbox.name = this.id_;
- checkbox.time = this.time.toString();
- checkbox.addEventListener("click", checkboxClicked, false);
- id2checkbox[this.id_] = checkbox;
- time.appendChild(checkbox);
- }
- time.appendChild(document.createTextNode(this.dateTimeOfDay));
+ var domain = createElementWithClassName('span', 'domain');
+ domain.style.backgroundImage =
+ 'url(chrome://favicon/' + encodeURIForCSS(this.url_) + ')';
+ domain.textContent = this.domain_;
node.appendChild(time);
+ node.appendChild(domain);
node.appendChild(this.getTitleDOM_());
+ if (searchResultFlag) {
+ time.textContent = this.dateShort;
+ var snippet = createElementWithClassName('div', 'snippet');
+ this.addHighlightedText_(snippet,
+ this.snippet_,
+ this.model_.getSearchText());
+ node.appendChild(snippet);
+ } else {
+ if (this.model_.getEditMode()) {
+ var checkbox = document.createElement('input');
+ checkbox.type = 'checkbox';
+ checkbox.name = this.id_;
+ checkbox.time = this.time.toString();
+ checkbox.addEventListener("click", checkboxClicked);
+ idToCheckbox[this.id_] = checkbox;
+ time.appendChild(checkbox);
+ }
+ time.appendChild(document.createTextNode(this.dateTimeOfDay));
+ }
return node;
};
+// Page, private: -------------------------------------------------------------
/**
- * @return {DOMObject} Gets the DOM representation of the page for
- * use in search results.
+ * Extracts and returns the domain (and subdomains) from a URL.
+ * @param {string} The url
+ * @return (string) The domain. An empty string is returned if no domain can
+ * be found.
*/
-Page.prototype.getSearchResultDOM = function() {
- var row = createElementWithClassName('tr', 'entry');
- var datecell = createElementWithClassName('td', 'time');
- datecell.appendChild(document.createTextNode(this.dateShort));
- row.appendChild(datecell);
-
- var titleCell = document.createElement('td');
- titleCell.valign = 'top';
- titleCell.appendChild(this.getTitleDOM_());
- var snippet = createElementWithClassName('div', 'snippet');
- this.addHighlightedText_(snippet,
- this.snippet_,
- this.model_.getSearchText());
- titleCell.appendChild(snippet);
- row.appendChild(titleCell);
-
- return row;
+Page.prototype.getDomainFromURL_ = function(url) {
+ var domain = url.replace(/^.+:\/\//, '').match(/[^/]+/);
+ return domain ? domain[0] : '';
+};
+
+/**
+ * Truncates a string to a maximum lenth (including ... if truncated)
+ * @param {string} The string to be truncated
+ * @param {number} The length to truncate the string to
+ * @return (string) The truncated string
+ */
+Page.prototype.truncateString_ = function(str, maxLength) {
+ if (str.length > maxLength) {
+ return str.substr(0, maxLength - 3) + '...';
+ } else {
+ return str;
+ }
};
-// Page, private: -------------------------------------------------------------
/**
* Add child text nodes to a node such that occurrences of the spcified text is
* highligted.
@@ -158,15 +176,19 @@ Page.prototype.addHighlightedText_ = function(node, content, highlightText) {
* @return {DOMObject} DOM representation for the title block.
*/
Page.prototype.getTitleDOM_ = function() {
- var node = document.createElement('div');
+ var node = document.createElement('span');
node.className = 'title';
var link = document.createElement('a');
link.href = this.url_;
- link.style.backgroundImage =
- 'url(chrome://favicon/' + encodeURIForCSS(this.url_) + ')';
link.id = "id-" + this.id_;
- this.addHighlightedText_(link, this.title_, this.model_.getSearchText());
+ var content = this.truncateString_(this.title_, 80);
+
+ // If we have truncated the title, add a tooltip.
+ if (content.length != this.title_.length) {
+ link.title = this.title_;
+ }
+ this.addHighlightedText_(link, content, this.model_.getSearchText());
node.appendChild(link);
if (this.starred_) {
@@ -354,7 +376,7 @@ HistoryModel.prototype.clearModel_ = function() {
this.pages_ = []; // Date-sorted list of pages.
this.last_id_ = 0;
selectionAnchor = -1;
- id2checkbox = [];
+ idToCheckbox = [];
// The page that the view wants to see - we only fetch slightly past this
// point. If the view requests a page that we don't have data for, we try
@@ -572,46 +594,57 @@ HistoryView.prototype.displayResults_ = function() {
this.pageIndex_ * RESULTS_PER_PAGE + RESULTS_PER_PAGE);
if (this.model_.getSearchText()) {
- var resultTable = createElementWithClassName('table', 'results');
- resultTable.cellSpacing = 0;
- resultTable.cellPadding = 0;
- resultTable.border = 0;
-
+ var searchResults = createElementWithClassName('ol', 'search-results');
for (var i = 0, page; page = results[i]; i++) {
if (!page.isRendered) {
- resultTable.appendChild(page.getSearchResultDOM());
+ searchResults.appendChild(page.getResultDOM(true));
this.setPageRendered_(page);
}
}
- this.resultDiv_.appendChild(resultTable);
+ this.resultDiv_.appendChild(searchResults);
} else {
+ var resultsFragment = document.createDocumentFragment();
var lastTime = Math.infinity;
+ var dayResults;
for (var i = 0, page; page = results[i]; i++) {
if (page.isRendered) {
continue;
}
// Break across day boundaries and insert gaps for browsing pauses.
+ // Create a dayResults element to contain results for each day
var thisTime = page.time.getTime();
if ((i == 0 && page.continued) || !page.continued) {
- var day = createElementWithClassName('div', 'day');
+ var day = createElementWithClassName('h2', 'day');
day.appendChild(document.createTextNode(page.dateRelativeDay));
-
if (i == 0 && page.continued) {
day.appendChild(document.createTextNode(' ' +
localStrings.getString('cont')));
}
- this.resultDiv_.appendChild(day);
+ // If there is an existing dayResults element, append it.
+ if (dayResults) {
+ resultsFragment.appendChild(dayResults);
+ }
+ resultsFragment.appendChild(day);
+ dayResults = createElementWithClassName('ol', 'day-results');
} else if (lastTime - thisTime > BROWSING_GAP_TIME) {
- this.resultDiv_.appendChild(createElementWithClassName('div', 'gap'));
+ if (dayResults) {
+ dayResults.appendChild(createElementWithClassName('li', 'gap'));
+ }
}
lastTime = thisTime;
-
// Add entry.
- this.resultDiv_.appendChild(page.getBrowseResultDOM());
- this.setPageRendered_(page);
+ if (dayResults) {
+ dayResults.appendChild(page.getResultDOM(false));
+ this.setPageRendered_(page);
+ }
}
+ // Add final dayResults element.
+ if (dayResults) {
+ resultsFragment.appendChild(dayResults);
+ }
+ this.resultDiv_.appendChild(resultsFragment);
}
this.displaySummaryBar_();
@@ -999,7 +1032,7 @@ function checkboxClicked(event) {
var begin = Math.min(this.name, selectionAnchor);
var end = Math.max(this.name, selectionAnchor);
for (var i = begin; i <= end; i++) {
- id2checkbox[i].checked = checked;
+ idToCheckbox[i].checked = checked;
}
}
selectionAnchor = this.name;
@@ -1081,11 +1114,15 @@ function historyDeleted() {
}
#results-display {
max-width:740px;
+ overflow: hidden;
+ margin: 16px 4px 0 4px;
}
.day {
- margin-top:18px;
- padding:0px 3px;
- display:inline-block;
+ color: #6a6a6a;
+ font-weight: bold;
+ margin: 0 0 4px 0;
+ text-transform: uppercase;
+ font-size: 13px;
}
.edit-button {
display: inline;
@@ -1100,72 +1137,75 @@ function historyDeleted() {
font:inherit;
}
.gap {
- margin-left:18px;
- width:15px;
- border-right:1px solid #ddd;
- height:14px;
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ width: 15px;
+ -webkit-border-end: 1px solid #ddd;
+ height: 14px;
}
.entry {
- margin-left:18px;
- margin-top:6px;
- overflow:auto;
+ margin: 0;
+ -webkit-margin-start: 90px;
+ list-style: none;
+ padding: 0;
+ position: relative;
+ line-height: 1.6em;
+}
+.search-results, .day-results {
+ margin: 0 0 24px 0;
+ padding: 0;
+}
+.snippet {
+ font-size: 11px;
+ line-height: 1.6em;
+ margin-bottom: 12px;
+}
+.entry .domain {
+ color: #282;
+ -webkit-padding-start: 20px;
+ -webkit-padding-end: 8px;
+ background-repeat: no-repeat;
+ background-position-y: center;
+ display: inline-block; /* Fixes RTL wrapping issue */
}
-table.results {
- margin-left:4px;
+html[dir='rtl'] .entry .domain {
+ background-position-x: right;
}
.entry .time {
- color:#888;
- float:left;
- min-width:56px;
- margin-right:5px;
- padding-top:1px;
+ color:#9a9a9a;
+ left: -90px;
+ width: 90px;
+ position: absolute;
+ top: 0;
white-space:nowrap;
}
html[dir='rtl'] .time {
- margin-right:0px;
- margin-left:5px;
- float:right;
-}
-.entry .title {
- max-width:600px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-.results .time, .results .title {
- margin-top:18px;
+ left: auto;
+ right: -90px;
}
.title > .starred {
background:url('shared/images/star_small.png');
background-repeat:no-repeat;
display:inline-block;
- margin-left:12px;
- margin-right:0;
+ -webkit-margin-start: 4px;
width:11px;
height:11px;
}
-html[dir='rtl'] .title > .starred {
- margin-left:0;
- margin-right:12px;
+/* Fixes RTL wrapping */
+html[dir='rtl'] .title {
+ display: inline-block;
}
.entry .title > a {
- -webkit-box-sizing: border-box;
- background-repeat:no-repeat;
- background-size:16px;
- background-position:0px 1px;
- padding:1px 0px 4px 22px;
- display:inline-block;
- overflow:hidden;
- text-overflow:ellipsis;
+ color: #11c;
+ text-decoration: none;
}
-html[dir='rtl'] .entry .title > a {
- background-position-x:right;
- padding-left:0px;
- padding-right:22px;
+.entry .title > a:hover {
+ text-decoration: underline;
}
-#results-pagination {
- padding-top:24px;
- margin-left:18px;
+/* Since all history links are visited, we can make them blue. */
+.entry .title > a:visted {
+ color: #11c;
}
</style>
@@ -1175,7 +1215,6 @@ html[dir='rtl'] .entry .title > a {
<a href="" onclick="setSearch(''); return false;">
<img src="shared/images/history_section.png"
width="67" height="67" class="logo" border="0"></a>
- Debug: this is History 2
<form method="post" action=""
onsubmit="setSearch(this.term.value); return false;"
class="form">
diff --git a/chrome/browser/resources/host_registration_page.html b/chrome/browser/resources/host_registration_page.html
index 101e812..4b7d75f 100644
--- a/chrome/browser/resources/host_registration_page.html
+++ b/chrome/browser/resources/host_registration_page.html
@@ -1,37 +1,70 @@
<!DOCTYPE HTML>
-<html id="t">
+<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Register your computer with Google</title>
-<script>
+<style>
+#form {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ overflow: hidden;
+ width: 100%;
+ height: 100%;
+ background: -webkit-gradient(linear, left top, left bottom, from(#FAFBFB), to(#CCD1D4));
+}
+</style>
+<script>
document.addEventListener('DOMContentLoaded', load);
+window.addEventListener('message', processMessage);
+var hostPageDomain = 'chrome://register';
+var registerDoneUrl = 'cros://register/success';
+var registerSkipUrl = 'cros://register/skipped';
+var registrationUrl = '';
function load() {
chrome.send('getRegistrationUrl', []);
}
-
function $(o) {
return document.getElementById(o);
}
-function setRegistrationUrl(url) {
- // TODO(nkostylev): Load URL in iframe.
+function processMessage(e) {
+ if (e.data.domain != registrationUrl){
+ skipRegistration();
+ return;
+ }
+
+ if (e.data.type == 'get_user_info') {
+ chrome.send('getUserInfo', []);
+ } else if (e.data.type == 'complete_registration') {
+ location.replace(e.data.payload.registration_status ? registerDoneUrl :
+ registerSkipUrl);
+ }
}
-// Called when document has been loaded in an iframe.
-function onFormLoaded() {
- chrome.send('getUserInfo', []);
+function setRegistrationUrl(url) {
+ registrationUrl = url;
+ $('form').contentWindow.location.href = url;
}
-function setUserInfo(data) {
- // TODO(nkostylev): Pass system/user data to registration iframe.
+function setUserInfo(userInfo) {
+ var msg = {
+ type: 'set_user_info',
+ domain: hostPageDomain,
+ payload: userInfo
+ };
+ $('form').contentWindow.postMessage(msg, registrationUrl);
}
+// Called by DOMUI handler when startup manifest is not defined.
+function skipRegistration() {
+ location.replace(registerSkipUrl);
+}
</script>
</head>
-<body>
- <!-- TODO(nkostylev): Redirect to cros://register/[success|skipped]. -->
- <!-- TODO(nkostylev): Add an iframe with an actual registration page. -->
-</body>
+<body><iframe id="form" frameborder="0"></iframe></body>
</html>
diff --git a/chrome/browser/resources/incognito_tab.html b/chrome/browser/resources/incognito_tab.html
index 3f40fe3..67846e5 100644
--- a/chrome/browser/resources/incognito_tab.html
+++ b/chrome/browser/resources/incognito_tab.html
@@ -50,10 +50,10 @@ document.write('<link id="incognitothemecss" rel="stylesheet" ' +
<div class="content" i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
<img src="shared/images/otr_icon_standalone.png" class="icon" />
<span i18n-values=".innerHTML:content"></span>
-</div>
-<div class="extensionsmessage" i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
- <img src="../../app/theme/extensions_section.png" class="extensionicon" />
- <span i18n-values=".innerHTML:extensionsmessage"></span>
+ <div style="margin-top:15px">
+ <img src="../../app/theme/extensions_section.png" class="extensionicon" />
+ <span i18n-values=".innerHTML:extensionsmessage"></span>
+ </div>
</div>
</body>
<script>
diff --git a/chrome/browser/resources/jcb.png b/chrome/browser/resources/jcb.png
deleted file mode 100644
index 7c915b3..0000000
--- a/chrome/browser/resources/jcb.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/mastercard.png b/chrome/browser/resources/mastercard.png
deleted file mode 100644
index 9d7a31f..0000000
--- a/chrome/browser/resources/mastercard.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/mediaplayer.html b/chrome/browser/resources/mediaplayer.html
index 09f7b1e..f3aae4c 100644
--- a/chrome/browser/resources/mediaplayer.html
+++ b/chrome/browser/resources/mediaplayer.html
@@ -322,6 +322,12 @@ var localStrings;
* Window onload handler, sets up the page.
*/
function load() {
+ document.body.addEventListener('dragover', function(e) {
+ if (e.preventDefault) e.preventDefault();
+ });
+ document.body.addEventListener('drop', function(e) {
+ if (e.preventDefault) e.preventDefault();
+ });
localStrings = new LocalStrings();
chrome.send('getCurrentPlaylist', []);
}
diff --git a/chrome/browser/resources/net_internals/dataview.js b/chrome/browser/resources/net_internals/dataview.js
index 18eadd7..97969c9 100644
--- a/chrome/browser/resources/net_internals/dataview.js
+++ b/chrome/browser/resources/net_internals/dataview.js
@@ -8,22 +8,73 @@
* to read format for bug reports.
*
* - Has a button to generate a text report.
- * - Has a button to generate a raw JSON dump (most useful for testing).
*
+ * - Shows how many events have been captured.
* @constructor
*/
-function DataView(mainBoxId, outputTextBoxId, exportTextButtonId) {
+function DataView(mainBoxId,
+ outputTextBoxId,
+ exportTextButtonId,
+ securityStrippingCheckboxId,
+ passivelyCapturedCountId,
+ activelyCapturedCountId,
+ deleteAllId) {
DivView.call(this, mainBoxId);
this.textPre_ = document.getElementById(outputTextBoxId);
- var exportTextButton = document.getElementById(exportTextButtonId);
+ this.securityStrippingCheckbox_ =
+ document.getElementById(securityStrippingCheckboxId);
+ var exportTextButton = document.getElementById(exportTextButtonId);
exportTextButton.onclick = this.onExportToText_.bind(this);
+
+ this.activelyCapturedCountBox_ =
+ document.getElementById(activelyCapturedCountId);
+ this.passivelyCapturedCountBox_ =
+ document.getElementById(passivelyCapturedCountId);
+ document.getElementById(deleteAllId).onclick =
+ g_browser.deleteAllEvents.bind(g_browser);
+
+ this.updateEventCounts_();
+
+ g_browser.addLogObserver(this);
}
inherits(DataView, DivView);
/**
+ * Called whenever a new event is received.
+ */
+DataView.prototype.onLogEntryAdded = function(logEntry) {
+ this.updateEventCounts_();
+};
+
+/**
+ * Called whenever some log events are deleted. |sourceIds| lists
+ * the source IDs of all deleted log entries.
+ */
+DataView.prototype.onLogEntriesDeleted = function(sourceIds) {
+ this.updateEventCounts_();
+};
+
+/**
+ * Called whenever all log events are deleted.
+ */
+DataView.prototype.onAllLogEntriesDeleted = function() {
+ this.updateEventCounts_();
+};
+
+/**
+ * Updates the counters showing how many events have been captured.
+ */
+DataView.prototype.updateEventCounts_ = function() {
+ this.activelyCapturedCountBox_.innerText =
+ g_browser.getNumActivelyCapturedEvents()
+ this.passivelyCapturedCountBox_.innerText =
+ g_browser.getNumPassivelyCapturedEvents();
+};
+
+/**
* Presents the captured data as formatted text.
*/
DataView.prototype.onExportToText_ = function() {
@@ -35,24 +86,38 @@ DataView.prototype.onExportToText_ = function() {
text.push('Data exported on: ' + (new Date()).toLocaleString());
text.push('');
text.push('Number of passively captured events: ' +
- g_browser.getAllPassivelyCapturedEvents().length);
+ g_browser.getNumPassivelyCapturedEvents());
text.push('Number of actively captured events: ' +
- g_browser.getAllActivelyCapturedEvents().length);
+ g_browser.getNumActivelyCapturedEvents());
text.push('');
text.push('Chrome version: ' + ClientInfo.version +
' (' + ClientInfo.official +
' ' + ClientInfo.cl +
') ' + ClientInfo.version_mod);
+ // Third value in first set of parentheses in user-agent string.
+ var platform = /\(.*?;.*?; (.*?);/.exec(navigator.userAgent);
+ if (platform)
+ text.push('Platform: ' + platform[1]);
text.push('Command line: ' + ClientInfo.command_line);
text.push('');
text.push('----------------------------------------------');
- text.push(' Proxy settings');
+ text.push(' Proxy settings (effective)');
+ text.push('----------------------------------------------');
+ text.push('');
+
+ text.push(proxySettingsToString(
+ g_browser.proxySettings_.currentData_.effective));
+
+ text.push('');
+ text.push('----------------------------------------------');
+ text.push(' Proxy settings (original)');
text.push('----------------------------------------------');
text.push('');
- text.push(g_browser.proxySettings_.currentData_);
+ text.push(proxySettingsToString(
+ g_browser.proxySettings_.currentData_.original));
text.push('');
text.push('----------------------------------------------');
@@ -105,6 +170,8 @@ DataView.prototype.onExportToText_ = function() {
}
text.push('Valid until: ' + this.formatExpirationTime_(e.expiration));
+ var expirationDate = g_browser.convertTimeTicksToDate(e.expiration);
+ text.push(' (' + expirationDate.toLocaleString() + ')');
}
} else {
text.push('');
@@ -113,11 +180,11 @@ DataView.prototype.onExportToText_ = function() {
text.push('');
text.push('----------------------------------------------');
- text.push(' Requests');
+ text.push(' Events');
text.push('----------------------------------------------');
text.push('');
- this.appendRequestsPrintedAsText_(text);
+ this.appendEventsPrintedAsText_(text);
text.push('');
text.push('----------------------------------------------');
@@ -129,27 +196,80 @@ DataView.prototype.onExportToText_ = function() {
for (var statName in httpCacheStats)
text.push(statName + ': ' + httpCacheStats[statName]);
+ text.push('');
+ text.push('----------------------------------------------');
+ text.push(' Socket pools');
+ text.push('----------------------------------------------');
+ text.push('');
+
+ this.appendSocketPoolsAsText_(text);
+
+ if (g_browser.isPlatformWindows()) {
+ text.push('');
+ text.push('----------------------------------------------');
+ text.push(' Winsock layered service providers');
+ text.push('----------------------------------------------');
+ text.push('');
+
+ var serviceProviders = g_browser.serviceProviders_.currentData_;
+ var layeredServiceProviders = serviceProviders.service_providers;
+ for (var i = 0; i < layeredServiceProviders.length; ++i) {
+ var provider = layeredServiceProviders[i];
+ text.push('name: ' + provider.name);
+ text.push('version: ' + provider.version);
+ text.push('type: ' +
+ ServiceProvidersView.getLayeredServiceProviderType(provider));
+ text.push('socket_type: ' +
+ ServiceProvidersView.getSocketType(provider));
+ text.push('socket_protocol: ' +
+ ServiceProvidersView.getProtocolType(provider));
+ text.push('path: ' + provider.path);
+ text.push('');
+ }
+
+ text.push('');
+ text.push('----------------------------------------------');
+ text.push(' Winsock namespace providers');
+ text.push('----------------------------------------------');
+ text.push('');
+
+ var namespaceProviders = serviceProviders.namespace_providers;
+ for (var i = 0; i < namespaceProviders.length; ++i) {
+ var provider = namespaceProviders[i];
+ text.push('name: ' + provider.name);
+ text.push('version: ' + provider.version);
+ text.push('type: ' +
+ ServiceProvidersView.getNamespaceProviderType(provider));
+ text.push('active: ' + provider.active);
+ text.push('');
+ }
+ }
+
// Open a new window to display this text.
this.setText_(text.join('\n'));
+
+ this.selectText_();
};
-DataView.prototype.appendRequestsPrintedAsText_ = function(out) {
- // Concatenate the passively captured events with the actively captured events
- // into a single array.
- var allEvents = g_browser.getAllPassivelyCapturedEvents().concat(
- g_browser.getAllActivelyCapturedEvents());
+DataView.prototype.appendEventsPrintedAsText_ = function(out) {
+ var allEvents = g_browser.getAllCapturedEvents();
// Group the events into buckets by source ID, and buckets by source type.
var sourceIds = [];
var sourceIdToEventList = {};
- var sourceTypeToSourceIdList = {}
+ var sourceTypeToSourceIdList = {};
+
+ // Lists used for actual output.
+ var eventLists = [];
for (var i = 0; i < allEvents.length; ++i) {
var e = allEvents[i];
var eventList = sourceIdToEventList[e.source.id];
if (!eventList) {
eventList = [];
- sourceIdToEventList[e.source.id] = eventList;
+ eventLists.push(eventList);
+ if (e.source.type != LogSourceType.NONE)
+ sourceIdToEventList[e.source.id] = eventList;
// Update sourceIds
sourceIds.push(e.source.id);
@@ -166,18 +286,39 @@ DataView.prototype.appendRequestsPrintedAsText_ = function(out) {
}
- // For each source (ordered by when that source was first started).
- for (var i = 0; i < sourceIds.length; ++i) {
- var sourceId = sourceIds[i];
- var eventList = sourceIdToEventList[sourceId];
+ // For each source or event without a source (ordered by when the first
+ // output event for that source happened).
+ for (var i = 0; i < eventLists.length; ++i) {
+ var eventList = eventLists[i];
+ var sourceId = eventList[0].source.id;
var sourceType = eventList[0].source.type;
- out.push('------------------------------');
+ var startDate = g_browser.convertTimeTicksToDate(eventList[0].time);
+
+ out.push('------------------------------------------');
out.push(getKeyWithValue(LogSourceType, sourceType) +
- ' (id=' + sourceId + ')');
- out.push('------------------------------');
+ ' (id=' + sourceId + ')' +
+ ' [start=' + startDate.toLocaleString() + ']');
+ out.push('------------------------------------------');
+
+ out.push(PrintSourceEntriesAsText(eventList,
+ this.securityStrippingCheckbox_.checked));
+ }
+};
+
+DataView.prototype.appendSocketPoolsAsText_ = function(text) {
+ var socketPools = SocketPoolWrapper.createArrayFrom(
+ g_browser.socketPoolInfo_.currentData_);
+ var tablePrinter = SocketPoolWrapper.createTablePrinter(socketPools);
+ text.push(tablePrinter.toText(2));
+
+ text.push('');
- out.push(PrintSourceEntriesAsText(eventList));
+ for (var i = 0; i < socketPools.length; ++i) {
+ if (socketPools[i].origPool.groups == undefined)
+ continue;
+ var groupTablePrinter = socketPools[i].createGroupTablePrinter();
+ text.push(groupTablePrinter.toText(2));
}
};
@@ -198,4 +339,14 @@ DataView.prototype.formatExpirationTime_ = function(timeTicks) {
return 't=' + d.getTime() + (isExpired ? ' [EXPIRED]' : '');
};
+/**
+ * Select all text from log dump.
+ */
+DataView.prototype.selectText_ = function() {
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ var range = document.createRange();
+ range.selectNodeContents(this.textPre_);
+ selection.addRange(range);
+};
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html
index 14e4697..b255980 100644
--- a/chrome/browser/resources/net_internals/index.html
+++ b/chrome/browser/resources/net_internals/index.html
@@ -14,7 +14,7 @@ found in the LICENSE file.
<script src="testview.js"></script>
<script src="main.js"></script>
<script src="dnsview.js"></script>
- <script src="requestsview.js"></script>
+ <script src="eventsview.js"></script>
<script src="detailsview.js"></script>
<script src="sourceentry.js"></script>
<script src="resizableverticalsplitview.js"></script>
@@ -23,6 +23,9 @@ found in the LICENSE file.
<script src="logviewpainter.js"></script>
<script src="loggrouper.js"></script>
<script src="proxyview.js"></script>
+ <script src="socketpoolwrapper.js"></script>
+ <script src="socketsview.js"></script>
+ <script src="serviceprovidersview.js"></script>
</head>
<body onload="onLoaded()">
<!-- Tab switcher for main categories. -->
@@ -30,10 +33,12 @@ found in the LICENSE file.
<ul>
<li><a href="#data" id=dataTab>Data</a></li>
<li><a href="#proxy" id=proxyTab>Proxy</a></li>
- <li><a href="#requests" id=requestsTab>Requests</a></li>
+ <li><a href="#events" id=eventsTab>Events</a></li>
<li><a href="#dns" id=dnsTab>DNS</a></li>
<li><a href="#sockets" id=socketsTab>Sockets</a></li>
<li><a href="#httpCache" id=httpCacheTab>HTTP Cache</a></li>
+ <!-- Tab is only shown on Windows -->
+ <li><a href="#serviceProviders" id=serviceProvidersTab style="display: none;">SPIs</a></li>
<li><a href="#tests" id=testTab>Tests</a></li>
</ul>
<div style="clear: both;"></div>
@@ -42,9 +47,25 @@ found in the LICENSE file.
<div id=proxyTabContent>
<h4>
Current proxy settings
- <input type=button value="Reload settings" id=proxyReloadSettings />
+ <input type=button value="Re-apply settings" id=proxyReloadSettings />
</h4>
- <pre id=proxyCurrentConfig></pre>
+
+ <table><tr>
+
+ <td valign=top>
+ <h3>Effective settings</h3>
+ <pre id=proxyEffectiveSettings></pre>
+ </pre>
+ </td>
+
+ <td style='width: 30px'>&nbsp;</td>
+
+ <td valign=top>
+ <h3>Original settings</h3>
+ <pre id=proxyOriginalSettings></pre>
+ </td>
+
+ </tr></table>
<h4>
Proxies which have failed recently, and are marked as bad
@@ -87,8 +108,13 @@ found in the LICENSE file.
</tbody>
</table>
</div>
- <!-- Sections TODO -->
- <div id=socketsTabContent>TODO: display socket information (outstanding connect jobs)</div>
+ <div id=socketsTabContent>
+ <h4>Socket pools</h4>
+ <div id=socketPoolDiv>
+ </div>
+ <div id=socketPoolGroupsDiv>
+ </div>
+ </div>
<div id=httpCacheTabContent>
<h4>Entries</h4>
<a href="chrome://view-http-cache" target=_blank>Explore cache entries</a>
@@ -96,18 +122,100 @@ found in the LICENSE file.
<h4>Statistics</h4>
<div id=httpCacheStats>Nothing loaded yet.</div>
</div>
+ <!-- Only shown on Windows -->
+ <div id=serviceProvidersTabContent style="display: none;">
+ <h4>Layered Service Providers</h4>
+ <table class="styledTable">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Version</th>
+ <th>Type</th>
+ <th>Socket Type</th>
+ <th>Protocol</th>
+ <th>Path</th>
+ </tr>
+ </thead>
+ <tbody id=serviceProvidersTbody>
+ </tbody>
+ </table>
+ <h4>Namespace Providers</h4>
+ <table class="styledTable">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Version</th>
+ <th>Namespace</th>
+ <th>Active</th>
+ </tr>
+ </thead>
+ <tbody id=namespaceProvidersTbody>
+ </tbody>
+ </table>
+ </div>
<!-- Import/Export data -->
<div id=dataTabContent>
+ <table width=100%>
+ <tr>
+ <td valign=top>
+ <h2>Dump data</h2>
+ <div style="margin: 8px">
+ <p>
+ <input id=securityStrippingCheckbox type=checkbox checked=yes>
+ Strip private information (cookies and credentials).
+ </p>
+ <p>
+ <a href="javascript:displayHelpForBugDump()">
+ Help: How to get data for bug reports?
+ </a>
+ </p>
+ <button id=exportToText class=bigButton>Dump to text</button>
+ </div>
+ </td>
+
+ <td align=right valign=top>
+ <div class="capturingBox">
+ <b>Capturing all events...</b>
+ <table style="margin: 8px">
+ <tr>
+ <td>Pasively captured:</td>
+ <td align=right id=passivelyCapturedCount></td>
+ </tr>
+ <tr>
+ <td>Actively captured:</td>
+ <td align=right id=activelyCapturedCount></td>
+ </tr>
+ </table>
+ <input type=button value="Delete all" id=dataViewDeleteAll />
+ </div>
+ </td>
+
+ </tr>
+ </table>
+
+ <pre id=exportedDataText></pre>
+ </div>
+
+<!-- START OF HELP TEXT -->
+<script>
+function displayHelpForBugDump() {
+ // We can't access the popups loaded from DOMUI pages, so we instead populate
+ // its contents using a data:URL. YUCK!
+ // TODO(eroman): do something less hacky, like exposing a new URL.
+ var helpContents =
+ document.getElementById('howtoDumpForBugsHelpContent').innerHTML;
+ window.open('data:text/html,' + encodeURIComponent(helpContents));
+}
+</script>
+<div id=howtoDumpForBugsHelpContent style="display: none">
<h2>How to get data for bug reports</h2>
<ol>
<li>Reproduce the network problem.</li>
-<li>Click this button:
- <button id=exportToText style="font-size: 110%"><b>Dump to text</b> </button>
-</li>
+<li>Click the <i>Dump to text</i> button in the <i>Data</i> tab.</li>
-<li>Copy-paste the data on this page to a text file.</li>
+<li>Copy-paste the resulting selected text to a file.</li>
<li>Email the text file to the bug investigator,
<b>along with an explanation of what went wrong.</b>
@@ -115,20 +223,6 @@ found in the LICENSE file.
</ol>
-<script>
-function toggleMoreExplanation() {
- var div = document.getElementById('moreExplanation');
- var isToggled = div.style.display == '';
- document.getElementById('moreExplanationIcon').innerText =
- isToggled ? 'Show' : 'Hide';
- setNodeDisplay(div, !isToggled);
-}
-</script>
-
-<a href="javascript:toggleMoreExplanation()">
- <span id=moreExplanationIcon>Show</span> more explanation</a>
-
-<div style="display:none; margin-left: 15px;" id=moreExplanation>
<ul>
<li>The network log <b>may contain personally identifying information</b> like
@@ -136,8 +230,10 @@ function toggleMoreExplanation() {
<ul>
<li>You can edit the log to obscure information if you like, but sometimes it
is relevant to the bug.</li>
+<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 this 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
@@ -147,22 +243,24 @@ function toggleMoreExplanation() {
<h2>How it works</h2>
<ul>
-<li>While this page is open, it will capture the network events that are
- happening in Chrome. You can view that in real-time by going to the
- <a href='#requests'>Requests</a> tab.</li>
-<li>Once you close this window, the data it had captured is discarded.</li>
-<li>Chrome keeps around a small buffer of network events for the
- <b>most recent</b> requests. That way if you open chrome://net-internals/
- <b>shortly after</b> encountering a problem, you can still find the relevant
- data. </b>
- These <b>passively captured</b> events are less accurate however, and will
+ <li>While the net-internals page is open, it will capture the network events
+ that are happening in Chrome. You can view that in real-time by going to
+ the <i>Events</i> tab.</li>
+ <li>Once you close the net-internals window, the data it had captured will be
+ discarded.</li>
+<li>Chrome keeps around a small buffer of the most recent network events
+ even when the net-internals window is not open. That way if you open
+ chrome://net-internals/ <b>shortly after</b> encountering a problem,
+ you may still find the relevant data.
+ These <i>passively captured</i> events are less accurate however, and will
be prefixed in the log with <span style="font-family: monospace;">(P)</span>.
</li>
</ul>
+
+<button onclick='window.close()'>Close this popup</button>
+<!-- END OF HELP TEXT -->
</div>
- <pre id=exportedDataText></pre>
- </div>
<!-- Connection tests -->
<div id=testTabContent>
<p>Input a URL which failed to load, and then click the button to run some
@@ -174,7 +272,7 @@ function toggleMoreExplanation() {
<div id=testSummary></div>
</div>
- <!-- ================= Requests view =================== -->
+ <!-- ================= Events view =================== -->
<!-- Filter Box: This the top bar which contains the search box. -->
<div id=filterBox>
@@ -186,25 +284,25 @@ function toggleMoreExplanation() {
</tr>
</table>
</div>
- <!-- Requests Box: This the panel on the left which lists the requests -->
- <div id=requestsBox>
- <table id=requestsListTable cellspacing=0 cellpadding=0 width=100%>
+ <!-- Events Box: This the panel on the left which lists the sources -->
+ <div id=eventsBox>
+ <table id=eventsListTable cellspacing=0 cellpadding=0 width=100%>
<thead>
<tr>
<td><input type=checkbox id=selectAll /></td>
- <td>ID</td>
- <td>Source</td>
- <td width=99%>Description</td>
+ <td id=sortById>ID</td>
+ <td id=sortBySource>Source</td>
+ <td id=sortByDescription width=99%>Description</td>
</tr>
</thead>
- <!-- Requests table body: This is where request rows go into -->
- <tbody id=requestsListTableBody></tbody>
+ <!-- Events table body: This is where request rows go into -->
+ <tbody id=eventsListTableBody></tbody>
</table>
</div>
<!-- Action Box: This is a button bar along the bottom -->
<div id=actionBox>
- <input type=button value="Stop capturing" onclick="alert('TODO')" />
<input type=button value="Delete selected" id=deleteSelected />
+ <input type=button value="Delete all" id=deleteAll />
</div>
<!-- Splitter Box: This is a handle to resize the vertical divider -->
<div id=splitterBox></div>
diff --git a/chrome/browser/resources/net_internals/loggrouper.js b/chrome/browser/resources/net_internals/loggrouper.js
index 39ff96c..8d7fb32 100644
--- a/chrome/browser/resources/net_internals/loggrouper.js
+++ b/chrome/browser/resources/net_internals/loggrouper.js
@@ -74,7 +74,7 @@ LogGroupEntry.createArrayFrom = function(origEntries) {
// Consider this as the terminator for all open BEGINs up until
// parentIndex.
- for (var j = 0; j < parentStack.length - parentIndex; ++j) {
+ while (parentIndex < parentStack.length) {
var p = parentStack.pop();
p.end = groupEntry;
}
diff --git a/chrome/browser/resources/net_internals/logviewpainter.js b/chrome/browser/resources/net_internals/logviewpainter.js
index a6fc93e..d82a027 100644
--- a/chrome/browser/resources/net_internals/logviewpainter.js
+++ b/chrome/browser/resources/net_internals/logviewpainter.js
@@ -8,8 +8,10 @@
* the old net-internals is replaced.
*/
+// TODO(eroman): these functions should use lower-case names.
var PaintLogView;
var PrintSourceEntriesAsText;
+var proxySettingsToString;
// Start of anonymous namespace.
(function() {
@@ -33,8 +35,15 @@ function addSourceEntry_(node, sourceEntry) {
addTextNode(nobr, sourceEntry.getDescription());
+ var p2 = addNode(div, 'p');
+ var nobr2 = addNode(p2, 'nobr');
+
+ var logEntries = sourceEntry.getLogEntries();
+ var startDate = g_browser.convertTimeTicksToDate(logEntries[0].time);
+ addTextNode(nobr2, 'Start Time: ' + startDate.toLocaleString());
+
var pre = addNode(div, 'pre');
- addTextNode(pre, PrintSourceEntriesAsText(sourceEntry.getLogEntries()));
+ addTextNode(pre, PrintSourceEntriesAsText(logEntries, false));
}
function canCollapseBeginWithEnd(beginEntry) {
@@ -48,8 +57,13 @@ function canCollapseBeginWithEnd(beginEntry) {
beginEntry.end.orig.wasPassivelyCaptured;
}
-PrintSourceEntriesAsText = function(sourceEntries) {
+PrintSourceEntriesAsText = function(sourceEntries, doSecurityStripping) {
var entries = LogGroupEntry.createArrayFrom(sourceEntries);
+ if (entries.length == 0)
+ return '';
+
+ var startDate = g_browser.convertTimeTicksToDate(entries[0].orig.time);
+ var startTime = startDate.getTime();
var tablePrinter = new TablePrinter();
@@ -66,10 +80,13 @@ PrintSourceEntriesAsText = function(sourceEntries) {
tablePrinter.addCell(entry.orig.wasPassivelyCaptured ? '(P) ' : '');
tablePrinter.addCell('t=');
- var tCell = tablePrinter.addCell(
- g_browser.convertTimeTicksToDate(entry.orig.time).getTime());
+ var date = g_browser.convertTimeTicksToDate(entry.orig.time) ;
+ var tCell = tablePrinter.addCell(date.getTime());
tCell.alignRight = true;
- tablePrinter.addCell(' ');
+ tablePrinter.addCell(' [st=');
+ var stCell = tablePrinter.addCell(date.getTime() - startTime);
+ stCell.alignRight = true;
+ tablePrinter.addCell('] ');
var indentationStr = makeRepeatedString(' ', entry.getDepth() * 3);
var mainCell =
@@ -95,7 +112,8 @@ PrintSourceEntriesAsText = function(sourceEntries) {
// Output the extra parameters.
if (entry.orig.params != undefined) {
// Add a continuation row for each line of text from the extra parameters.
- var extraParamsText = getTextForExtraParams(entry.orig);
+ var extraParamsText = getTextForExtraParams(entry.orig,
+ doSecurityStripping);
var extraParamsTextLines = extraParamsText.split('\n');
for (var j = 0; j < extraParamsTextLines.length; ++j) {
@@ -103,6 +121,8 @@ PrintSourceEntriesAsText = function(sourceEntries) {
tablePrinter.addCell(''); // Empty passive annotation.
tablePrinter.addCell(''); // No t=.
tablePrinter.addCell('');
+ tablePrinter.addCell(''); // No st=.
+ tablePrinter.addCell('');
tablePrinter.addCell(' ');
var mainExtraCell =
@@ -113,24 +133,32 @@ PrintSourceEntriesAsText = function(sourceEntries) {
}
// Format the table for fixed-width text.
- return tablePrinter.toText();
+ return tablePrinter.toText(0);
}
-function getTextForExtraParams(entry) {
+function getTextForExtraParams(entry, doSecurityStripping) {
// Format the extra parameters (use a custom formatter for certain types,
// but default to displaying as JSON).
switch (entry.type) {
case LogEventType.HTTP_TRANSACTION_SEND_REQUEST_HEADERS:
case LogEventType.HTTP_TRANSACTION_SEND_TUNNEL_HEADERS:
- return getTextForRequestHeadersExtraParam(entry);
+ return getTextForRequestHeadersExtraParam(entry, doSecurityStripping);
case LogEventType.HTTP_TRANSACTION_READ_RESPONSE_HEADERS:
case LogEventType.HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS:
- return getTextForResponseHeadersExtraParam(entry);
+ return getTextForResponseHeadersExtraParam(entry, doSecurityStripping);
+
+ case LogEventType.PROXY_CONFIG_CHANGED:
+ return getTextForProxyConfigChangedExtraParam(entry);
default:
var out = [];
for (var k in entry.params) {
+ if (k == 'headers' && entry.params[k] instanceof Array) {
+ out.push(getTextForResponseHeadersExtraParam(entry,
+ doSecurityStripping));
+ continue;
+ }
var value = entry.params[k];
var paramStr = ' --> ' + k + ' = ' + JSON.stringify(value);
@@ -194,17 +222,77 @@ function indentLines(start, lines) {
return start + lines.join('\n' + makeRepeatedString(' ', start.length));
}
-function getTextForRequestHeadersExtraParam(entry) {
+/**
+ * Removes a cookie or unencrypted login information from a single HTTP header
+ * line, if present, and returns the modified line. Otherwise, just returns
+ * the original line.
+ */
+function stripCookieOrLoginInfo(line) {
+ var patterns = [
+ // Cookie patterns
+ /^set-cookie:/i,
+ /^set-cookie2:/i,
+ /^cookie:/i,
+
+ // Unencrypted authentication patterns
+ /^authorization: \S*/i,
+ /^proxy-authorization: \S*/i];
+
+ for (var i = 0; i < patterns.length; i++) {
+ var match = patterns[i].exec(line);
+ if (match != null)
+ return match + " [value was stripped]";
+ }
+ return line;
+}
+
+/**
+ * Removes all cookie and unencrypted login text from a list of HTTP
+ * header lines.
+ */
+function stripCookiesAndLoginInfo(headers) {
+ return headers.map(stripCookieOrLoginInfo);
+}
+
+function getTextForRequestHeadersExtraParam(entry, doSecurityStripping) {
var params = entry.params;
// Strip the trailing CRLF that params.line contains.
var lineWithoutCRLF = params.line.replace(/\r\n$/g, '');
- return indentLines(' --> ', [lineWithoutCRLF].concat(params.headers));
+ var headers = params.headers;
+ if (doSecurityStripping)
+ headers = stripCookiesAndLoginInfo(headers);
+
+ return indentLines(' --> ', [lineWithoutCRLF].concat(headers));
+}
+
+function getTextForResponseHeadersExtraParam(entry, doSecurityStripping) {
+ var headers = entry.params.headers;
+ if (doSecurityStripping)
+ headers = stripCookiesAndLoginInfo(headers);
+ return indentLines(' --> ', headers);
}
-function getTextForResponseHeadersExtraParam(entry) {
- return indentLines(' --> ', entry.params.headers);
+function getTextForProxyConfigChangedExtraParam(entry) {
+ var params = entry.params;
+ var out = '';
+ var indentation = ' ';
+
+ if (params.old_config) {
+ var oldConfigString = proxySettingsToString(params.old_config);
+ // The previous configuration may not be present in the case of
+ // the initial proxy settings fetch.
+ out += ' --> old_config =\n' +
+ indentLines(indentation, oldConfigString.split('\n'));
+ out += '\n';
+ }
+
+ var newConfigString = proxySettingsToString(params.new_config);
+ out += ' --> new_config =\n' +
+ indentLines(indentation, newConfigString.split('\n'));
+
+ return out;
}
function getTextForEvent(entry) {
@@ -225,6 +313,72 @@ function getTextForEvent(entry) {
return text;
}
+proxySettingsToString = function(config) {
+ if (!config)
+ return '';
+
+ // The proxy settings specify up to three major fallback choices
+ // (auto-detect, custom pac url, or manual settings).
+ // We enumerate these to a list so we can later number them.
+ var modes = [];
+
+ // Output any automatic settings.
+ if (config.auto_detect)
+ modes.push(['Auto-detect']);
+ if (config.pac_url)
+ modes.push(['PAC script: ' + config.pac_url]);
+
+ // Output any manual settings.
+ if (config.single_proxy || config.proxy_per_scheme) {
+ var lines = [];
+
+ if (config.single_proxy) {
+ lines.push('Proxy server: ' + config.single_proxy);
+ } else if (config.proxy_per_scheme) {
+ for (var urlScheme in config.proxy_per_scheme) {
+ if (urlScheme != 'fallback') {
+ lines.push('Proxy server for ' + urlScheme.toUpperCase() + ': ' +
+ config.proxy_per_scheme[urlScheme]);
+ }
+ }
+ if (config.proxy_per_scheme.fallback) {
+ lines.push('Proxy server for everything else: ' +
+ config.proxy_per_scheme.fallback);
+ }
+ }
+
+ // Output any proxy bypass rules.
+ if (config.bypass_list) {
+ if (config.reverse_bypass) {
+ lines.push('Reversed bypass list: ');
+ } else {
+ lines.push('Bypass list: ');
+ }
+
+ for (var i = 0; i < config.bypass_list.length; ++i)
+ lines.push(' ' + config.bypass_list[i]);
+ }
+
+ modes.push(lines);
+ }
+
+ // If we didn't find any proxy settings modes, we are using DIRECT.
+ if (modes.length < 1)
+ return 'Use DIRECT connections.';
+
+ // If there was just one mode, don't bother numbering it.
+ if (modes.length == 1)
+ return modes[0].join('\n');
+
+ // Otherwise concatenate all of the modes into a numbered list
+ // (which correspond with the fallback order).
+ var result = [];
+ for (var i = 0; i < modes.length; ++i)
+ result.push(indentLines('(' + (i + 1) + ') ', modes[i]));
+
+ return result.join('\n');
+};
+
// End of anonymous namespace.
})();
diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css
index ecef780..f411b05 100644
--- a/chrome/browser/resources/net_internals/main.css
+++ b/chrome/browser/resources/net_internals/main.css
@@ -36,7 +36,7 @@ body {
overflow: hidden;
}
-#requestsBox {
+#eventsBox {
overflow-x: hidden;
overflow-y: auto
}
@@ -55,17 +55,17 @@ body {
user-select: none;
}
-#requestsListTable {
+#eventsListTable {
cursor: pointer;
}
-#requestsListTable thead td {
+#eventsListTable thead td {
text-align: left;
font-weight: bold;
background: rgb(229, 236, 249);
}
-#requestsListTable td {
+#eventsListTable td {
padding: 3px;
border-left: 1px solid #afafaf;
border-bottom: 1px solid #afafaf;
@@ -74,28 +74,33 @@ body {
white-space: nowrap;
}
-#requestsListTableBody .mouseover {
+#eventsListTableBody .mouseover {
background: rgb(244,244,255);
}
-#requestsListTableBody .selected,
-#requestsListTableBody .mouseover .selected {
+#eventsListTableBody .selected,
+#eventsListTableBody .mouseover .selected {
background: #C3D9FF;
}
-#requestsListTableBody .source_CONNECT_JOB {
+#eventsListTableBody .source_CONNECT_JOB {
color: blue;
}
-#requestsListTableBody .source_SOCKET {
+#eventsListTableBody .source_HOST_RESOLVER_IMPL_JOB,
+#eventsListTableBody .source_HOST_RESOLVER_IMPL_REQUEST {
+ color: #308080;
+}
+
+#eventsListTableBody .source_SOCKET {
color: purple;
}
-#requestsListTableBody .source_INIT_PROXY_RESOLVER {
+#eventsListTableBody .source_INIT_PROXY_RESOLVER {
color: green;
}
-#requestsListTableBody .source_NONE {
+#eventsListTableBody .source_NONE {
color: red;
}
@@ -196,6 +201,8 @@ body {
#proxyTabContent,
#dataTabContent,
#dnsTabContent,
+#socketsTabContent,
+#serviceProvidersTabContent,
#testTabContent {
overflow: auto;
padding: 10px;
@@ -217,9 +224,33 @@ table.styledTable,
.styledTable th,
.styledTable td {
border: 1px solid #777;
+ padding-right: 4px;
+ padding-left: 4px;
}
.styledTable th {
background: rgb(224,236,255);
}
+.styledTable th.title {
+ background: rgb(255,217,217);
+}
+
+/*
+ * This is the box in the top right of the Data tab which shows how many
+ * events have been captured so far.
+ */
+.capturingBox {
+ border: 1px dashed black;
+ display: inline-block;
+ text-align: left;
+ padding: 5px;
+}
+
+/**
+ * Styling for an emphasized button.
+ */
+.bigButton {
+ font-size: 100%;
+ font-weight: bold;
+}
diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js
index d0428fe..afcbb86 100644
--- a/chrome/browser/resources/net_internals/main.js
+++ b/chrome/browser/resources/net_internals/main.js
@@ -24,30 +24,35 @@ var g_browser = null;
function onLoaded() {
g_browser = new BrowserBridge();
- // Create the view which displays requests lists, and lets you select, filter
+ // Create the view which displays events lists, and lets you select, filter
// and delete them.
- var requestsView = new RequestsView('requestsListTableBody',
- 'filterInput',
- 'filterCount',
- 'deleteSelected',
- 'selectAll',
-
- // IDs for the details view.
- "detailsTabHandles",
- "detailsLogTab",
- "detailsTimelineTab",
- "detailsLogBox",
- "detailsTimelineBox",
-
- // IDs for the layout boxes.
- "filterBox",
- "requestsBox",
- "actionBox",
- "splitterBox");
+ var eventsView = new EventsView('eventsListTableBody',
+ 'filterInput',
+ 'filterCount',
+ 'deleteSelected',
+ 'deleteAll',
+ 'selectAll',
+ 'sortById',
+ 'sortBySource',
+ 'sortByDescription',
+
+ // IDs for the details view.
+ "detailsTabHandles",
+ "detailsLogTab",
+ "detailsTimelineTab",
+ "detailsLogBox",
+ "detailsTimelineBox",
+
+ // IDs for the layout boxes.
+ "filterBox",
+ "eventsBox",
+ "actionBox",
+ "splitterBox");
// Create a view which will display info on the proxy setup.
var proxyView = new ProxyView("proxyTabContent",
- "proxyCurrentConfig",
+ "proxyOriginalSettings",
+ "proxyEffectiveSettings",
"proxyReloadSettings",
"badProxiesTableBody",
"clearBadProxies");
@@ -63,7 +68,10 @@ function onLoaded() {
// Create a view which will display import/export options to control the
// captured data.
var dataView = new DataView("dataTabContent", "exportedDataText",
- "exportToText");
+ "exportToText", "securityStrippingCheckbox",
+ "passivelyCapturedCount",
+ "activelyCapturedCount",
+ "dataViewDeleteAll");
// Create a view which will display the results and controls for connection
// tests.
@@ -73,18 +81,32 @@ function onLoaded() {
var httpCacheView = new HttpCacheView("httpCacheTabContent",
"httpCacheStats");
+ var socketsView = new SocketsView("socketsTabContent",
+ "socketPoolDiv",
+ "socketPoolGroupsDiv");
+
+
+ var serviceView;
+ if (g_browser.isPlatformWindows()) {
+ serviceView = new ServiceProvidersView("serviceProvidersTab",
+ "serviceProvidersTabContent",
+ "serviceProvidersTbody",
+ "namespaceProvidersTbody");
+ }
+
// Create a view which lets you tab between the different sub-views.
var categoryTabSwitcher =
new TabSwitcherView(new DivView('categoryTabHandles'));
// Populate the main tabs.
- categoryTabSwitcher.addTab('requestsTab', requestsView, false);
+ categoryTabSwitcher.addTab('eventsTab', eventsView, false);
categoryTabSwitcher.addTab('proxyTab', proxyView, false);
categoryTabSwitcher.addTab('dnsTab', dnsView, false);
- categoryTabSwitcher.addTab('socketsTab', new DivView('socketsTabContent'),
- false);
+ categoryTabSwitcher.addTab('socketsTab', socketsView, false);
categoryTabSwitcher.addTab('httpCacheTab', httpCacheView, false);
categoryTabSwitcher.addTab('dataTab', dataView, false);
+ if (g_browser.isPlatformWindows())
+ categoryTabSwitcher.addTab('serviceProvidersTab', serviceView, false);
categoryTabSwitcher.addTab('testTab', testView, false);
// Build a map from the anchor name of each tab handle to its "tab ID".
@@ -132,12 +154,16 @@ function BrowserBridge() {
this.httpCacheInfo_ = new PollableDataHelper('onHttpCacheInfoChanged');
this.hostResolverCache_ =
new PollableDataHelper('onHostResolverCacheChanged');
+ this.socketPoolInfo_ = new PollableDataHelper('onSocketPoolInfoChanged');
+ this.serviceProviders_ = new PollableDataHelper('onServiceProvidersChanged');
// Cache of the data received.
- // TODO(eroman): the controls to clear data in the "Requests" tab should be
- // affecting this as well.
- this.passivelyCapturedEvents_ = [];
- this.activelyCapturedEvents_ = [];
+ this.numPassivelyCapturedEvents_ = 0;
+ this.capturedEvents_ = [];
+
+ // Next unique id to be assigned to a log entry without a source.
+ // Needed to simplify deletion, identify associated GUI elements, etc.
+ this.nextSourcelessEventId_ = -1;
}
/**
@@ -159,6 +185,10 @@ BrowserBridge.prototype.sendReady = function() {
this.doPolling_.bind(this), BrowserBridge.POLL_INTERVAL_MS);
};
+BrowserBridge.prototype.isPlatformWindows = function() {
+ return /Win/.test(navigator.platform);
+};
+
BrowserBridge.prototype.sendGetProxySettings = function() {
// The browser will call receivedProxySettings on completion.
chrome.send('getProxySettings');
@@ -194,13 +224,28 @@ BrowserBridge.prototype.sendGetHttpCacheInfo = function() {
chrome.send('getHttpCacheInfo');
};
+BrowserBridge.prototype.sendGetSocketPoolInfo = function() {
+ chrome.send('getSocketPoolInfo');
+};
+
+BrowserBridge.prototype.sendGetServiceProviders = function() {
+ chrome.send('getServiceProviders');
+};
+
//------------------------------------------------------------------------------
// Messages received from the browser
//------------------------------------------------------------------------------
BrowserBridge.prototype.receivedLogEntry = function(logEntry) {
- if (!logEntry.wasPassivelyCaptured)
- this.activelyCapturedEvents_.push(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_;
+ --this.nextSourcelessEventId_;
+ }
+ this.capturedEvents_.push(logEntry);
for (var i = 0; i < this.logObservers_.length; ++i)
this.logObservers_[i].onLogEntryAdded(logEntry);
};
@@ -249,9 +294,16 @@ function(hostResolverCache) {
this.hostResolverCache_.update(hostResolverCache);
};
+BrowserBridge.prototype.receivedSocketPoolInfo = function(socketPoolInfo) {
+ this.socketPoolInfo_.update(socketPoolInfo);
+};
+
+BrowserBridge.prototype.receivedServiceProviders = function(serviceProviders) {
+ this.serviceProviders_.update(serviceProviders);
+};
+
BrowserBridge.prototype.receivedPassiveLogEntries = function(entries) {
- this.passivelyCapturedEvents_ =
- this.passivelyCapturedEvents_.concat(entries);
+ this.numPassivelyCapturedEvents_ += entries.length;
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
entry.wasPassivelyCaptured = true;
@@ -290,6 +342,12 @@ BrowserBridge.prototype.receivedHttpCacheInfo = function(info) {
this.httpCacheInfo_.update(info);
};
+BrowserBridge.prototype.areLogTypesReady_ = function() {
+ return (LogEventType != null &&
+ LogEventPhase != null &&
+ LogSourceType != null);
+}
+
//------------------------------------------------------------------------------
/**
@@ -308,7 +366,17 @@ BrowserBridge.prototype.addLogObserver = function(observer) {
*
* observer.onProxySettingsChanged(proxySettings)
*
- * |proxySettings| is a formatted string describing the settings.
+ * |proxySettings| is a dictionary with (up to) two properties:
+ *
+ * "original" -- The settings that chrome was configured to use
+ * (i.e. system settings.)
+ * "effective" -- The "effective" proxy settings that chrome is using.
+ * (decides between the manual/automatic modes of the
+ * fetched settings).
+ *
+ * Each of these two configurations is formatted as a string, and may be
+ * omitted if not yet initialized.
+ *
* TODO(eroman): send a dictionary instead.
*/
BrowserBridge.prototype.addProxySettingsObserver = function(observer) {
@@ -341,6 +409,26 @@ BrowserBridge.prototype.addHostResolverCacheObserver = function(observer) {
};
/**
+ * Adds a listener of the socket pool. |observer| will be called back
+ * when data is received, through:
+ *
+ * observer.onSocketPoolInfoChanged(socketPoolInfo)
+ */
+BrowserBridge.prototype.addSocketPoolInfoObserver = function(observer) {
+ this.socketPoolInfo_.addObserver(observer);
+};
+
+/**
+ * Adds a listener of the service providers info. |observer| will be called
+ * back when data is received, through:
+ *
+ * observer.onServiceProvidersChanged(serviceProviders)
+ */
+BrowserBridge.prototype.addServiceProvidersObserver = function(observer) {
+ this.serviceProviders_.addObserver(observer);
+};
+
+/**
* Adds a listener for the progress of the connection tests.
* The observer will be called back with:
*
@@ -380,19 +468,60 @@ BrowserBridge.prototype.convertTimeTicksToDate = function(timeTicks) {
};
/**
- * Returns a list of all the events that were captured while we were
+ * Returns a list of all captured events.
+ */
+BrowserBridge.prototype.getAllCapturedEvents = function() {
+ return this.capturedEvents_;
+};
+
+/**
+ * Returns the number of events that were captured while we were
* listening for events.
*/
-BrowserBridge.prototype.getAllActivelyCapturedEvents = function() {
- return this.activelyCapturedEvents_;
+BrowserBridge.prototype.getNumActivelyCapturedEvents = function() {
+ return this.capturedEvents_.length - this.numPassivelyCapturedEvents_;
};
/**
- * Returns a list of all the events that were captured passively by the
+ * Returns the number of events that were captured passively by the
* browser prior to when the net-internals page was started.
*/
-BrowserBridge.prototype.getAllPassivelyCapturedEvents = function() {
- return this.passivelyCapturedEvents_;
+BrowserBridge.prototype.getNumPassivelyCapturedEvents = function() {
+ return this.numPassivelyCapturedEvents_;
+};
+
+/**
+ * Deletes captured events with source IDs in |sourceIds|.
+ */
+BrowserBridge.prototype.deleteEventsBySourceId = function(sourceIds) {
+ var sourceIdDict = {};
+ for (var i = 0; i < sourceIds.length; i++)
+ sourceIdDict[sourceIds[i]] = true;
+
+ var newEventList = [];
+ for (var i = 0; i < this.capturedEvents_.length; ++i) {
+ var id = this.capturedEvents_[i].source.id;
+ if (id in sourceIdDict) {
+ if (this.capturedEvents_[i].wasPassivelyCaptured)
+ --this.numPassivelyCapturedEvents_;
+ continue;
+ }
+ newEventList.push(this.capturedEvents_[i]);
+ }
+ this.capturedEvents_ = newEventList;
+
+ for (var i = 0; i < this.logObservers_.length; ++i)
+ this.logObservers_[i].onLogEntriesDeleted(sourceIds);
+};
+
+/**
+ * Deletes all captured events.
+ */
+BrowserBridge.prototype.deleteAllEvents = function() {
+ this.capturedEvents_ = [];
+ this.numPassivelyCapturedEvents_ = 0;
+ for (var i = 0; i < this.logObservers_.length; ++i)
+ this.logObservers_[i].onAllLogEntriesDeleted();
};
BrowserBridge.prototype.doPolling_ = function() {
@@ -403,6 +532,9 @@ BrowserBridge.prototype.doPolling_ = function() {
this.sendGetBadProxies();
this.sendGetHostResolverCache();
this.sendGetHttpCacheInfo();
+ this.sendGetSocketPoolInfo();
+ if (this.isPlatformWindows())
+ this.sendGetServiceProviders();
};
/**
diff --git a/chrome/browser/resources/net_internals/proxyview.js b/chrome/browser/resources/net_internals/proxyview.js
index 4d7d885..6814609 100644
--- a/chrome/browser/resources/net_internals/proxyview.js
+++ b/chrome/browser/resources/net_internals/proxyview.js
@@ -13,14 +13,17 @@
* @constructor
*/
function ProxyView(mainBoxId,
- currentConfigDivId,
+ originalSettingsDivId,
+ effectiveSettingsDivId,
reloadSettingsButtonId,
badProxiesTbodyId,
clearBadProxiesButtonId) {
DivView.call(this, mainBoxId);
// Hook up the UI components.
- this.currentConfigDiv_ = document.getElementById(currentConfigDivId);
+ this.originalSettingsDiv_ = document.getElementById(originalSettingsDivId);
+ this.effectiveSettingsDiv_ =
+ document.getElementById(effectiveSettingsDivId);
this.badProxiesTbody_ = document.getElementById(badProxiesTbodyId);
var reloadSettingsButton = document.getElementById(reloadSettingsButtonId);
@@ -38,9 +41,15 @@ function ProxyView(mainBoxId,
inherits(ProxyView, DivView);
ProxyView.prototype.onProxySettingsChanged = function(proxySettings) {
- // |proxySettings| is a formatted string describing the settings.
- this.currentConfigDiv_.innerHTML = ''
- addTextNode(this.currentConfigDiv_, proxySettings);
+ var original = proxySettings.original;
+ var effective = proxySettings.effective;
+
+ // Both |original| and |effective| are dictionaries describing the settings.
+ this.originalSettingsDiv_.innerHTML = ''
+ this.effectiveSettingsDiv_.innerHTML = ''
+
+ addTextNode(this.originalSettingsDiv_, proxySettingsToString(original));
+ addTextNode(this.effectiveSettingsDiv_, proxySettingsToString(effective));
};
ProxyView.prototype.onBadProxiesChanged = function(badProxies) {
diff --git a/chrome/browser/resources/net_internals/requestsview.js b/chrome/browser/resources/net_internals/requestsview.js
deleted file mode 100644
index 2d16704..0000000
--- a/chrome/browser/resources/net_internals/requestsview.js
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * RequestsView displays a filtered list of all the requests, and a details
- * pane for the selected requests.
- *
- * +----------------------++----------------+
- * | filter box || |
- * +----------------------+| |
- * | || |
- * | || |
- * | || |
- * | || |
- * | requests list || details |
- * | || view |
- * | || |
- * | || |
- * | || |
- * | || |
- * +----------------------++ |
- * | action bar || |
- * +----------------------++----------------+
- *
- * @constructor
- */
-function RequestsView(tableBodyId, filterInputId, filterCountId,
- deleteSelectedId, selectAllId,
- tabHandlesContainerId, logTabId, timelineTabId,
- detailsLogBoxId, detailsTimelineBoxId,
- topbarId, middleboxId, bottombarId, sizerId) {
- View.call(this);
-
- // Initialize the sub-views.
- var leftPane = new TopMidBottomView(new DivView(topbarId),
- new DivView(middleboxId),
- new DivView(bottombarId));
-
- this.detailsView_ = new DetailsView(tabHandlesContainerId,
- logTabId,
- timelineTabId,
- detailsLogBoxId,
- detailsTimelineBoxId);
-
- this.splitterView_ = new ResizableVerticalSplitView(
- leftPane, this.detailsView_, new DivView(sizerId));
-
- this.sourceIdToEntryMap_ = {};
- this.currentSelectedSources_ = [];
-
- g_browser.addLogObserver(this);
-
- this.tableBody_ = document.getElementById(tableBodyId);
-
- this.filterInput_ = document.getElementById(filterInputId);
- this.filterCount_ = document.getElementById(filterCountId);
-
- this.filterInput_.addEventListener("search",
- this.onFilterTextChanged_.bind(this), true);
-
- document.getElementById(deleteSelectedId).onclick =
- this.deleteSelected_.bind(this);
-
- document.getElementById(selectAllId).addEventListener(
- 'click', this.selectAll_.bind(this), true);
-
- this.currentFilter_ = '';
- this.numPrefilter_ = 0;
- this.numPostfilter_ = 0;
-
- this.invalidateFilterCounter_();
- this.invalidateDetailsView_();
-}
-
-inherits(RequestsView, View);
-
-// How soon after updating the filter list the counter should be updated.
-RequestsView.REPAINT_FILTER_COUNTER_TIMEOUT_MS = 0;
-
-RequestsView.prototype.setGeometry = function(left, top, width, height) {
- RequestsView.superClass_.setGeometry.call(this, left, top, width, height);
- this.splitterView_.setGeometry(left, top, width, height);
-};
-
-RequestsView.prototype.show = function(isVisible) {
- RequestsView.superClass_.show.call(this, isVisible);
- this.splitterView_.show(isVisible);
-};
-
-RequestsView.prototype.onFilterTextChanged_ = function() {
- this.setFilter_(this.filterInput_.value);
-};
-
-RequestsView.prototype.setFilter_ = function(filterText) {
- this.currentFilter_ = filterText;
-
- // Iterate through all of the rows and see if they match the filter.
- for (var id in this.sourceIdToEntryMap_) {
- var entry = this.sourceIdToEntryMap_[id];
- entry.setIsMatchedByFilter(entry.matchesFilter(this.currentFilter_));
- }
-};
-
-RequestsView.prototype.onLogEntryAdded = function(logEntry) {
- // Lookup the source.
- var sourceEntry = this.sourceIdToEntryMap_[logEntry.source.id];
-
- if (!sourceEntry) {
- sourceEntry = new SourceEntry(this);
- this.sourceIdToEntryMap_[logEntry.source.id] = sourceEntry;
- this.incrementPrefilterCount(1);
- }
-
- sourceEntry.update(logEntry);
-
- if (sourceEntry.isSelected())
- this.invalidateDetailsView_();
-};
-
-RequestsView.prototype.incrementPrefilterCount = function(offset) {
- this.numPrefilter_ += offset;
- this.invalidateFilterCounter_();
-};
-
-RequestsView.prototype.incrementPostfilterCount = function(offset) {
- this.numPostfilter_ += offset;
- this.invalidateFilterCounter_();
-};
-
-RequestsView.prototype.onSelectionChanged = function() {
- this.invalidateDetailsView_();
-};
-
-RequestsView.prototype.clearSelection = function() {
- var prevSelection = this.currentSelectedSources_;
- this.currentSelectedSources_ = [];
-
- // Unselect everything that is currently selected.
- for (var i = 0; i < prevSelection.length; ++i) {
- prevSelection[i].setSelected(false);
- }
-
- this.onSelectionChanged();
-};
-
-RequestsView.prototype.deleteSelected_ = function() {
- var prevSelection = this.currentSelectedSources_;
- this.currentSelectedSources_ = [];
-
- for (var i = 0; i < prevSelection.length; ++i) {
- var entry = prevSelection[i];
- entry.remove();
- delete this.sourceIdToEntryMap_[entry.getSourceId()];
- this.incrementPrefilterCount(-1);
- }
-};
-
-RequestsView.prototype.selectAll_ = function(event) {
- for (var id in this.sourceIdToEntryMap_) {
- var entry = this.sourceIdToEntryMap_[id];
- if (entry.isMatchedByFilter()) {
- entry.setSelected(true);
- }
- }
- event.preventDefault();
-};
-
-RequestsView.prototype.modifySelectionArray = function(
- sourceEntry, addToSelection) {
- // Find the index for |sourceEntry| in the current selection list.
- var index = -1;
- for (var i = 0; i < this.currentSelectedSources_.length; ++i) {
- if (this.currentSelectedSources_[i] == sourceEntry) {
- index = i;
- break;
- }
- }
-
- if (index != -1 && !addToSelection) {
- // Remove from the selection.
- this.currentSelectedSources_.splice(index, 1);
- }
-
- if (index == -1 && addToSelection) {
- this.currentSelectedSources_.push(sourceEntry);
- }
-}
-
-RequestsView.prototype.invalidateDetailsView_ = function() {
- this.detailsView_.setData(this.currentSelectedSources_);
-};
-
-RequestsView.prototype.invalidateFilterCounter_ = function() {
- if (!this.outstandingRepaintFilterCounter_) {
- this.outstandingRepaintFilterCounter_ = true;
- window.setTimeout(this.repaintFilterCounter_.bind(this),
- RequestsView.REPAINT_FILTER_COUNTER_TIMEOUT_MS);
- }
-};
-
-RequestsView.prototype.repaintFilterCounter_ = function() {
- this.outstandingRepaintFilterCounter_ = false;
- this.filterCount_.innerHTML = '';
- addTextNode(this.filterCount_,
- this.numPostfilter_ + " of " + this.numPrefilter_);
-};
diff --git a/chrome/browser/resources/net_internals/sourceentry.js b/chrome/browser/resources/net_internals/sourceentry.js
index 74313d2..582618b 100644
--- a/chrome/browser/resources/net_internals/sourceentry.js
+++ b/chrome/browser/resources/net_internals/sourceentry.js
@@ -5,15 +5,19 @@
/**
* Each row in the filtered items list is backed by a SourceEntry. This
* instance contains all of the data pertaining to that row, and notifies
- * its parent view (the RequestsView) whenever its data changes.
+ * its parent view (the EventsView) whenever its data changes.
*
* @constructor
*/
-function SourceEntry(parentView) {
+function SourceEntry(parentView, maxPreviousSourceId) {
+ this.maxPreviousSourceId_ = maxPreviousSourceId;
this.entries_ = [];
this.parentView_ = parentView;
this.isSelected_ = false;
this.isMatchedByFilter_ = false;
+ // If the first entry is a BEGIN_PHASE, set to true.
+ // Set to false when an END_PHASE matching the first entry is encountered.
+ this.isActive_ = false;
}
SourceEntry.prototype.isSelected = function() {
@@ -61,34 +65,56 @@ SourceEntry.prototype.setFilterStyles = function(isMatchedByFilter) {
};
SourceEntry.prototype.update = function(logEntry) {
+ if (logEntry.phase == LogEventPhase.PHASE_BEGIN &&
+ this.entries_.length == 0)
+ this.isActive_ = true;
+
+ // Only the last event should have the same type first event,
+ if (this.isActive_ &&
+ logEntry.phase == LogEventPhase.PHASE_END &&
+ logEntry.type == this.entries_[0].type)
+ this.isActive_ = false;
+
var prevStartEntry = this.getStartEntry_();
this.entries_.push(logEntry);
var curStartEntry = this.getStartEntry_();
// If we just got the first entry for this source.
- if (!prevStartEntry && curStartEntry) {
- this.createRow_();
-
- // Only apply the filter during the first update.
- // TODO(eroman): once filters use other data, apply it on each update.
- var matchesFilter = this.matchesFilter(this.parentView_.currentFilter_);
- this.setIsMatchedByFilter(matchesFilter);
+ if (prevStartEntry != curStartEntry) {
+ if (!prevStartEntry)
+ this.createRow_();
+ else
+ this.updateDescription_();
}
+
+ // Update filters.
+ var matchesFilter = this.matchesFilter(this.parentView_.currentFilter_);
+ this.setIsMatchedByFilter(matchesFilter);
};
SourceEntry.prototype.onCheckboxToggled_ = function() {
this.setSelected(this.getSelectionCheckbox().checked);
};
-SourceEntry.prototype.matchesFilter = function(filterText) {
+SourceEntry.prototype.matchesFilter = function(filter) {
// TODO(eroman): Support more advanced filter syntax.
- if (filterText == '')
+
+ // Safety check.
+ if (this.row_ == null)
+ return false;
+
+ if (filter.isActive && !this.isActive_)
+ return false;
+ if (filter.isInactive && this.isActive_)
+ return false;
+
+ if (filter.text == '')
return true;
- var filterText = filterText.toLowerCase();
+ var filterText = filter.text.toLowerCase();
+ var entryText = PrintSourceEntriesAsText(this.entries_).toLowerCase();
- return this.getDescription().toLowerCase().indexOf(filterText) != -1 ||
- this.getSourceTypeString().toLowerCase().indexOf(filterText) != -1;
+ return entryText.indexOf(filterText) != -1;
};
SourceEntry.prototype.setSelected = function(isSelected) {
@@ -115,9 +141,15 @@ SourceEntry.prototype.onMouseout_ = function() {
this.setMouseoverStyle(false);
};
+SourceEntry.prototype.updateDescription_ = function() {
+ this.descriptionCell_.innerHTML = '';
+ addTextNode(this.descriptionCell_, this.getDescription());
+};
+
SourceEntry.prototype.createRow_ = function() {
// Create a row.
var tr = addNode(this.parentView_.tableBody_, 'tr');
+ tr._id = this.getSourceId();
tr.style.display = 'none';
this.row_ = tr;
@@ -126,8 +158,11 @@ SourceEntry.prototype.createRow_ = function() {
checkbox.type = 'checkbox';
var idCell = addNode(tr, 'td');
+ idCell.style.textAlign = 'right';
+
var typeCell = addNode(tr, 'td');
var descriptionCell = addNode(tr, 'td');
+ this.descriptionCell_ = descriptionCell;
// Connect listeners.
checkbox.onchange = this.onCheckboxToggled_.bind(this);
@@ -141,10 +176,13 @@ SourceEntry.prototype.createRow_ = function() {
tr.onmouseout = this.onMouseout_.bind(this);
// Set the cell values to match this source's data.
- addTextNode(idCell, this.getSourceId());
+ if (this.getSourceId() >= 0)
+ addTextNode(idCell, this.getSourceId());
+ else
+ addTextNode(idCell, "-");
var sourceTypeString = this.getSourceTypeString();
addTextNode(typeCell, sourceTypeString);
- addTextNode(descriptionCell, this.getDescription());
+ this.updateDescription_();
// Add a CSS classname specific to this source type (so CSS can specify
// different stylings for different types).
@@ -176,6 +214,9 @@ SourceEntry.prototype.getDescription = function() {
return e.params.url;
case LogSourceType.CONNECT_JOB:
return e.params.group_name;
+ case LogSourceType.HOST_RESOLVER_IMPL_REQUEST:
+ case LogSourceType.HOST_RESOLVER_IMPL_JOB:
+ return e.params.host;
}
return '';
@@ -190,11 +231,12 @@ SourceEntry.prototype.getDescription = function() {
SourceEntry.prototype.getStartEntry_ = function() {
if (this.entries_.length < 1)
return undefined;
- if (this.entries_[0].type != LogEventType.REQUEST_ALIVE)
- return this.entries_[0];
- if (this.entries_.length < 2)
- return undefined;
- return this.entries_[1];
+ if (this.entries_.length >= 2) {
+ if (this.entries_[0].type == LogEventType.REQUEST_ALIVE ||
+ this.entries_[0].type == LogEventType.SOCKET_POOL_CONNECT_JOB)
+ return this.entries_[1];
+ }
+ return this.entries_[0];
};
SourceEntry.prototype.getLogEntries = function() {
@@ -213,6 +255,91 @@ SourceEntry.prototype.getSourceId = function() {
return this.entries_[0].source.id;
};
+/**
+ * Returns the largest source ID seen before this object was received.
+ * Used only for sorting SourceEntries without a source by source ID.
+ */
+SourceEntry.prototype.getMaxPreviousEntrySourceId = function() {
+ return this.maxPreviousSourceId_;
+};
+
+SourceEntry.prototype.isActive = function() {
+ return this.isActive_;
+};
+
+/**
+ * Returns time of last event if inactive. Returns current time otherwise.
+ */
+SourceEntry.prototype.getEndTime = function() {
+ if (this.isActive_) {
+ return (new Date()).getTime();
+ }
+ else {
+ var endTicks = this.entries_[this.entries_.length - 1].time;
+ return g_browser.convertTimeTicksToDate(endTicks).getTime();
+ }
+};
+
+/**
+ * Returns the time between the first and last events with a matching
+ * source ID. If source is still active, uses the current time for the
+ * last event.
+ */
+SourceEntry.prototype.getDuration = function() {
+ var startTicks = this.entries_[0].time;
+ var startTime = g_browser.convertTimeTicksToDate(startTicks).getTime();
+ var endTime = this.getEndTime();
+ return endTime - startTime;
+};
+
+/**
+ * Returns source ID of the entry whose row is currently above this one's.
+ * Returns null if no such node exists.
+ */
+SourceEntry.prototype.getPreviousNodeSourceId = function() {
+ if (!this.hasRow())
+ return null;
+ var prevNode = this.row_.previousSibling;
+ if (prevNode == null)
+ return null;
+ return prevNode._id;
+};
+
+/**
+ * Returns source ID of the entry whose row is currently below this one's.
+ * Returns null if no such node exists.
+ */
+SourceEntry.prototype.getNextNodeSourceId = function() {
+ if (!this.hasRow())
+ return null;
+ var nextNode = this.row_.nextSibling;
+ if (nextNode == null)
+ return null;
+ return nextNode._id;
+};
+
+SourceEntry.prototype.hasRow = function() {
+ return this.row_ != null;
+};
+
+/**
+ * Moves current object's row before |entry|'s row.
+ */
+SourceEntry.prototype.moveBefore = function(entry) {
+ if (this.hasRow() && entry.hasRow()) {
+ this.row_.parentNode.insertBefore(this.row_, entry.row_);
+ }
+};
+
+/**
+ * Moves current object's row after |entry|'s row.
+ */
+SourceEntry.prototype.moveAfter = function(entry) {
+ if (this.hasRow() && entry.hasRow()) {
+ this.row_.parentNode.insertBefore(this.row_, entry.row_.nextSibling);
+ }
+};
+
SourceEntry.prototype.remove = function() {
this.setSelected(false);
this.setIsMatchedByFilter(false);
diff --git a/chrome/browser/resources/net_internals/util.js b/chrome/browser/resources/net_internals/util.js
index 9190300..a6c7322 100644
--- a/chrome/browser/resources/net_internals/util.js
+++ b/chrome/browser/resources/net_internals/util.js
@@ -3,18 +3,6 @@
// found in the LICENSE file.
/**
- * Helper that binds the |this| object to a method to create a callback.
- */
-Function.prototype.bind = function(thisObj) {
- var func = this;
- var args = Array.prototype.slice.call(arguments, 1);
- return function() {
- return func.apply(thisObj,
- args.concat(Array.prototype.slice.call(arguments, 0)))
- };
-};
-
-/**
* Inherit the prototype methods from one constructor into another.
*/
function inherits(childCtor, parentCtor) {
@@ -66,7 +54,7 @@ function addNode(parentNode, tagName) {
}
/**
- * Adds text to node |parentNode|.
+ * Adds |text| to node |parentNode|.
*/
function addTextNode(parentNode, text) {
var textNode = parentNode.ownerDocument.createTextNode(text);
@@ -75,6 +63,17 @@ function addTextNode(parentNode, text) {
}
/**
+ * Adds a node to |parentNode|, of type |tagName|. Then adds
+ * |text| to the new node.
+ */
+function addNodeWithText(parentNode, tagName, text) {
+ var elem = parentNode.ownerDocument.createElement(tagName);
+ parentNode.appendChild(elem);
+ addTextNode(elem, text);
+ return elem;
+}
+
+/**
* Adds or removes a CSS class to |node|.
*/
function changeClassName(node, classNameToAddOrRemove, isAdd) {
@@ -106,6 +105,18 @@ function getKeyWithValue(map, value) {
}
/**
+ * Looks up |key| in |map|, and returns the resulting entry, if there is one.
+ * Otherwise, returns |key|. Intended primarily for use with incomplete
+ * tables, and for reasonable behavior with system enumerations that may be
+ * extended in the future.
+ */
+function tryGetValueWithKey(map, key) {
+ if (key in map)
+ return map[key];
+ return key;
+}
+
+/**
* Builds a string by repeating |str| |count| times.
*/
function makeRepeatedString(str, count) {
@@ -116,13 +127,26 @@ function makeRepeatedString(str, count) {
}
/**
- * TablePrinter is a helper to format a table as ascii art.
+ * TablePrinter is a helper to format a table as ascii art or an HTML table.
+ *
+ * Usage: call addRow() and addCell() repeatedly to specify the data.
+ *
+ * addHeaderCell() can optionally be called to specify header cells for a
+ * single header row. The header row appears at the top of an HTML formatted
+ * table, and uses thead and th tags. In ascii tables, the header is separated
+ * from the table body by a partial row of dashes.
*
- * Usage: call addRow() and addCell() repeatedly to specify the data. Ones
- * all the fields have been inputted, call toText() to format it as text.
+ * setTitle() can optionally be used to set a title that is displayed before
+ * the header row. In HTML tables, it uses the title class and in ascii tables
+ * it's between two rows of dashes.
+ *
+ * Once all the fields have been input, call toText() to format it as text or
+ * toHTML() to format it as HTML.
*/
function TablePrinter() {
this.rows_ = [];
+ this.hasHeaderRow_ = false;
+ this.title_ = null;
}
function TablePrinterCell(value) {
@@ -150,6 +174,27 @@ TablePrinter.prototype.addCell = function(cellText) {
return cell;
};
+TablePrinter.prototype.setTitle = function(title) {
+ this.title_ = title;
+};
+
+/**
+ * Adds a header row, if not already present, and adds a new column to it,
+ * setting its contents to |headerText|.
+ *
+ * @returns {!TablePrinterCell} the cell that was added.
+ */
+TablePrinter.prototype.addHeaderCell = function(headerText) {
+ // Insert empty new row at start of |rows_| if currently no header row.
+ if (!this.hasHeaderRow_) {
+ this.rows_.splice(0, 0, []);
+ this.hasHeaderRow_ = true;
+ }
+ var cell = new TablePrinterCell(headerText);
+ this.rows_[0].push(cell);
+ return cell;
+};
+
/**
* Returns the maximum number of columns this table contains.
*/
@@ -176,9 +221,10 @@ TablePrinter.prototype.getCell_ = function(rowIndex, columnIndex) {
/**
* Returns a formatted text representation of the table data.
+ * |spacing| indicates number of extra spaces, if any, to add between
+ * columns.
*/
-TablePrinter.prototype.toText = function() {
- var numRows = this.rows_.length;
+TablePrinter.prototype.toText = function(spacing) {
var numColumns = this.getNumColumns();
// Figure out the maximum width of each column.
@@ -187,6 +233,20 @@ TablePrinter.prototype.toText = function() {
for (var i = 0; i < numColumns; ++i)
columnWidths[i] = 0;
+ // If header row is present, temporarily add a spacer row to |rows_|.
+ if (this.hasHeaderRow_) {
+ var headerSpacerRow = [];
+ for (var c = 0; c < numColumns; ++c) {
+ var cell = this.getCell_(0, c);
+ if (!cell)
+ continue;
+ var spacerStr = makeRepeatedString('-', cell.text.length);
+ headerSpacerRow.push(new TablePrinterCell(spacerStr));
+ }
+ this.rows_.splice(1, 0, headerSpacerRow);
+ }
+
+ var numRows = this.rows_.length;
for (var c = 0; c < numColumns; ++c) {
for (var r = 0; r < numRows; ++r) {
var cell = this.getCell_(r, c);
@@ -196,13 +256,26 @@ TablePrinter.prototype.toText = function() {
}
}
- // Print each row.
var out = [];
+
+ // Print title, if present.
+ if (this.title_) {
+ var titleSpacerStr = makeRepeatedString('-', this.title_.length);
+ out.push(titleSpacerStr);
+ out.push('\n');
+ out.push(this.title_);
+ out.push('\n');
+ out.push(titleSpacerStr);
+ out.push('\n');
+ }
+
+ // Print each row.
+ var spacingStr = makeRepeatedString(' ', spacing);
for (var r = 0; r < numRows; ++r) {
for (var c = 0; c < numColumns; ++c) {
var cell = this.getCell_(r, c);
if (cell) {
- // Padd the cell with spaces to make it fit the maximum column width.
+ // Pad the cell with spaces to make it fit the maximum column width.
var padding = columnWidths[c] - cell.text.length;
var paddingStr = makeRepeatedString(' ', padding);
@@ -213,11 +286,65 @@ TablePrinter.prototype.toText = function() {
out.push(cell.text);
out.push(paddingStr);
}
+ out.push(spacingStr);
}
}
out.push('\n');
}
+ // Remove spacer row under the header row, if one was added.
+ if (this.hasHeaderRow_)
+ this.rows_.splice(1, 1);
+
return out.join('');
};
+/**
+ * Adds a new HTML table to the node |parent| using the specified style.
+ */
+TablePrinter.prototype.toHTML = function(parent, style) {
+ var numRows = this.rows_.length;
+ var numColumns = this.getNumColumns();
+
+ var table = addNode(parent, 'table');
+ table.setAttribute('class', style);
+
+ var thead = addNode(table, 'thead');
+ var tbody = addNode(table, 'tbody');
+
+ // Add title, if needed.
+ if (this.title_) {
+ var tableTitleRow = addNode(thead, 'tr');
+ var tableTitle = addNodeWithText(tableTitleRow, 'th', this.title_);
+ tableTitle.colSpan = numColumns;
+ changeClassName(tableTitle, 'title', true);
+ }
+
+ // Fill table body, adding header row first, if needed.
+ for (var r = 0; r < numRows; ++r) {
+ var cellType;
+ var row;
+ if (r == 0 && this.hasHeaderRow_) {
+ row = addNode(thead, 'tr');
+ cellType = 'th';
+ } else {
+ row = addNode(tbody, 'tr');
+ cellType = 'td';
+ }
+ for (var c = 0; c < numColumns; ++c) {
+ var cell = this.getCell_(r, c);
+ if (cell) {
+ var tableCell = addNodeWithText(row, cellType, cell.text);
+ if (cell.alignRight)
+ tableCell.alignRight = true;
+ // If allowing overflow on the rightmost cell of a row,
+ // make the cell span the rest of the columns. Otherwise,
+ // ignore the flag.
+ if (cell.allowOverflow && !this.getCell_(r, c + 1))
+ tableCell.colSpan = numColumns - c;
+ }
+ }
+ }
+ return table;
+};
+
diff --git a/chrome/browser/resources/new_new_tab.css b/chrome/browser/resources/new_new_tab.css
index b842877..b3bfd35 100644
--- a/chrome/browser/resources/new_new_tab.css
+++ b/chrome/browser/resources/new_new_tab.css
@@ -18,11 +18,19 @@ html[mode=app-launcher] {
#main {
-webkit-box-sizing: border-box;
-webkit-transition: width .15s;
- background: url(chrome://theme/IDR_PRODUCT_LOGO) no-repeat 0 6px;
margin: 0 auto;
min-height: 100%;
- padding-bottom: 25px; /* Make room for the bottom positioned footer. */
- position: relative;
+}
+
+body.loading #main {
+ /* We start out hidden to prevent glitchiness as the app and most visited
+ data flows in. */
+ visibility: hidden;
+}
+
+#main,
+.section,
+.maxiview {
width: 920px;
}
@@ -127,7 +135,7 @@ html[anim=false] *,
background: no-repeat 0% 50%;
padding: 2px;
padding-left: 18px;
- background-size: 16px;
+ background-size: 16px 16px;
background-color: hsla(213, 63%, 93%, 0);
display: block;
line-height: 20px;
@@ -135,7 +143,6 @@ html[anim=false] *,
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- text-decoration: none;
font-size: 100%;
}
@@ -182,7 +189,7 @@ html[dir=rtl] .item {
pointer-events: none;
border: 1px solid rgb(118, 118, 118);
border-radius: 3px;
- padding: 0px 3px;
+ padding: 0 3px;
background: -webkit-gradient(linear, left top, left bottom,
from(white),
to(rgb(228, 229, 240)));
@@ -195,47 +202,15 @@ html[dir=rtl] .item {
-webkit-box-orient: horizontal;
}
-#recently-closed {
- white-space: nowrap;
- overflow-x: hidden;
-}
-
-#recently-closed > span > span {
- display: inline-block;
- max-width: 114px; /* Selected so that we can fit 5 items in EN-US */
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- font-size: 100%;
- margin: 0 10px;
-}
-
-#recently-closed > span,
-#recently-closed .nav {
- max-width: none !important;
-}
-
-.nav > a {
- /* no icon */
- padding: 0;
-}
-
-.nav > a:after {
- content: '\00bb'; /* raque gets flipped automatically in rtl */
- font-size: 115%;
- -webkit-padding-start: 2px;
-}
-
-#sync-status {
- display: none;
+#sync-status > div {
border-radius: 6px;
padding: 5px 0;
- margin: 10px 0;
+ margin: 10px 0 20px;
white-space: nowrap;
overflow-x: hidden;
}
-#sync-status > * {
+#sync-status > div > * {
display: inline-block;
max-width: none;
white-space: nowrap;
@@ -245,111 +220,42 @@ html[dir=rtl] .item {
margin: 0 10px;
}
-#set-as-home-page {
- display: none;
- margin: 10px 0;
- text-align: center;
-}
-
-#top-bar {
- display: -webkit-box;
- -webkit-box-align: center;
- min-height: 56px;
-}
-
-#tip-line {
- -webkit-box-flex: 1;
- -webkit-transition: opacity .15s;
- -webkit-user-select: text;
- border: 0;
- cursor: text;
- display: block; /* Since we are reusing the section display logic we need
- to override the display for hidden tips. */
- margin: 10px;
- -webkit-margin-start: 50%;
- text-align: end;
-}
-
-.notification.hidden,
-#tip-line.hidden,
-.notification-shown #tip-line {
+.notification.hidden {
opacity: 0;
pointer-events: none;
}
-#tip-line a,
-#tip-line button {
- /* We do not want a trailing single word from a link on the last line */
- white-space: nowrap;
- padding: 0;
-}
-
-#option-button {
- -webkit-appearance: none;
- background-color: transparent;
- width: 19px;
- height: 17px;
- margin: 0;
- border: 0;
- padding: 0;
- vertical-align: top;
- -webkit-margin-start: 10px;
- /* Do not show focus outline */
- outline: none;
- background-image: url(chrome://theme/IDR_NEWTAB_OPTION);
-}
-
-#option-button:hover,
-#option-button:focus {
- background-image: url(chrome://theme/IDR_NEWTAB_OPTION_H);
-}
-
-#option-button:active,
-#option-button.open {
- background-image: url(chrome://theme/IDR_NEWTAB_OPTION_P);
+/**
+ * Unfortunately, there seems to be a bug in WebKit where this div doesn't
+ * immediately get layout. It still doesn't have it in 'load', but gains it
+ * sometime after.
+ *
+ * We detect this in the JS by looking for offsetWidth > 0, and when it occurs,
+ * remove the 'nolayout' class.
+ */
+#attribution.nolayout {
+ position: static;
+ visibility: hidden;
}
-#option-menu {
- right: 0;
- left: auto;
- min-width: 175px;
+#attribution {
+ position: fixed;
+ right: 5px;
+ bottom: 5px;
+ text-align: end;
}
-html[dir=rtl] #option-menu {
+html[dir=rtl] #attribution {
+ left: 5px;
right: auto;
- left: 0;
-}
-
-#option-menu > * {
- /* Work around rendering bug. */
- outline: 1px solid transparent;
-}
-
-#option-menu > [command=show]:before,
-#option-menu > [command=hide]:before {
- -webkit-margin-start: -14px;
- content: '\00a0'; /* non breaking space */
- display: inline-block;
- background-position: 0 50%;
- background-repeat: no-repeat;
- width: 14px;
-}
-
-html[dir=rtl] #option-menu > [command=show]:before,
-html[dir=rtl] #option-menu > [command=hide]:before {
- background-position-x: 100%;
-}
-
-#option-menu > [command=hide]:before {
- background-image: url('ntp/checkbox_black.png');
}
-#option-menu > [selected][command=hide]:active:before {
- background-image: url('ntp/checkbox_white.png');
+#attribution.obscured {
+ visibility: hidden;
}
-#attribution {
- margin: 10px 0;
+html[hasattribution=false] #attribution > div {
+ display: none;
}
.sync-button {
@@ -364,101 +270,131 @@ html[dir=rtl] #option-menu > [command=hide]:before {
font-family: inherit;
}
-#apps-section {
- padding: 10px 0px;
- border-top: 0;
+.section {
+ position: fixed;
+ font-size: 92%;
+}
+
+html[anim=true][enable-section-animations=true] .section {
+ -webkit-transition: top .15s;
}
-#apps-launch-control {
- margin-top: 10px;
+.section.disabled {
+ display: none !important;
}
-#apps-launch-control input {
+.section > h2 {
+ font-family: Helvetica, Arial, sans-serif;
+ font-size: 133%;
+ font-weight: normal;
+ margin: 0;
position: relative;
- top: 1px;
- margin-right: 0.2em;
- margin-left: 1em;
}
-#debug > h2 {
- color: red;
+.section:not([noexpand]) > h2 {
+ cursor: pointer;
}
-#debug > div {
- margin: 0;
+.section > h2 > .disclosure {
+ position: absolute;
+ left: -15px;
+ margin-top: 50%;
+ top: -5px;
}
-.section.disabled {
- display: none !important;
+html[dir=rtl] .section > h2 > .disclosure {
+ left: auto;
+ right: -15px;
+ -webkit-transform: rotate(180deg);
}
-.section + :not(.hidden) {
- border-top: 0;
+html[anim=true] .section > h2 > .disclosure {
+ -webkit-transition: -webkit-transform .15s;
}
-.section > div {
- margin-bottom: 10px;
+.section:not(.hidden) > h2 > .disclosure {
+ -webkit-transform:rotate(90deg);
}
-.section > h2 {
- display: inline-block;
- margin: 0;
- font-size: 100%;
- cursor: pointer;
- margin-top: 10px;
- margin-bottom: 10px;
+.section > h2 .back {
+ position: absolute;
+ left: 0;
+ top: 0.56em;
+ width: 100%;
+ height: 1.5em;
+ z-index: 1;
}
-.section > h2:hover {
- text-decoration: underline;
+.section > h2 span {
+ -webkit-padding-end: 0.30em;
+ position: relative;
+ z-index: 2;
}
-.section.hidden {
- display: inline;
- border: 0;
+.maxiview {
+ padding: 5px 0 30px;
+ position: absolute;
+ -webkit-mask-attachment: fixed;
+ opacity: 1;
}
-.section.hidden > :not(h2) {
- display: none !important;
+.maxiview.hiding {
+ opacity: 0;
}
-.section > h2 {
- margin-right: 5px;
+.maxiview.hidden {
+ display: none;
}
-.section.hidden > h2 {
- margin-right: 0px;
+html[anim=true] .maxiview {
+ -webkit-transition: opacity .15s;
+}
+
+.section > .miniview {
+ display: none;
+ margin: 10px 0 30px;
+ white-space: nowrap;
+ overflow-x: hidden;
}
-.section.hidden:last-child {
- border-right: 0;
+.section.hidden > * {
+ display: none;
}
-.section.hidden + .hidden > h2 {
- padding-left: 5px;
+.section.hidden > h2,
+.section.hidden > .miniview {
+ display: block;
}
-.section:last-child {
- border-bottom: 0;
+.section.hidden > h2 {
+ margin-right: 0;
}
-.section .nav {
+.miniview > span {
display: inline-block;
+ max-width: 114px; /* Selected so that we can fit 5 items in EN-US */
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-size: 100%;
+ margin: 0 10px;
}
-#apps {
- margin-top: 10px;
+.miniview > span:first-child {
+ margin-left: 0;
}
-.section > * {
- font-size: 12px;
+.miniview > span:last-child {
+ margin-right: 0;
}
/* small */
@media (max-width: 940px) {
- #main {
+ #main,
+ .section,
+ .maxiview {
width: 692px;
}
@@ -478,22 +414,3 @@ html[dir=rtl] #option-menu > [command=hide]:before {
margin-right: 10px;
}
}
-
-#footer {
- bottom: 0;
- padding-bottom: 5px;
- position: absolute;
- text-align: end;
- width: 100%;
-}
-
-#footer hr {
- border: 0;
- display: inline;
- margin: 0;
- padding: 0;
-}
-
-#footer hr:after {
- content: "|";
-}
diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html
index c3d7ef4..7290e32 100644
--- a/chrome/browser/resources/new_new_tab.html
+++ b/chrome/browser/resources/new_new_tab.html
@@ -5,8 +5,9 @@
hasattribution:hasattribution;
anim:anim;
syncispresent:syncispresent;
- has_3d:has_3d">
-
+ customlogo:customlogo"
+ install-animation-enabled="true">
+<head>
<meta charset="utf-8">
<title i18n-content="title"></title>
<script>
@@ -44,14 +45,11 @@ function registerCallback(name) {
chrome.send('getMostVisited');
chrome.send('getRecentlyClosedTabs');
-chrome.send('getTips');
chrome.send('getApps');
registerCallback('mostVisitedPages');
registerCallback('recentlyClosedTabs');
registerCallback('syncMessageChanged');
-registerCallback('tips');
-registerCallback('onHomePageSet');
registerCallback('getAppsCallback');
registerCallback('setShownSections');
@@ -70,11 +68,7 @@ registerCallback('setShownSections');
*/
var Section = {
THUMB: 1,
- // LIST is no longer used
- RECENT: 4,
- TIPS: 8,
- SYNC: 16,
- DEBUG: 32
+ APPS: 64
};
var shownSections = templateData['shown_sections'];
@@ -92,13 +86,6 @@ function isRtl() {
return templateData['textdirection'] == 'rtl';
}
-// This will get overridden in new_new_tab.js
-function updateSimpleSection(id, section) {
- // All sections start off shown.
- if (!(shownSections & section))
- document.getElementById(id).className += ' hidden';
-}
-
// Parse any name value pairs passed through the URL hash.
var hashParams = (function() {
var result = {};
@@ -126,89 +113,87 @@ if ('mode' in hashParams) {
<body class="loading"
i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
-<div id="main">
+<div id="attribution" class="attribution nolayout">
+ <div i18n-content="attributionintro"></div>
+ <img id="attribution-img">
+</div>
- <div id=top-bar>
- <div id="tip-line" class="section" section="TIPS"></div>
- <input type="button" id="option-button"
- i18n-values="title:pagedisplaytooltip">
- </div>
-
- <menu id="option-menu">
- <div command="hide" section="TIPS" i18n-content="tips"></div>
- <div command="hide" section="THUMB" i18n-content="mostvisited"></div>
- <div command="hide" section="RECENT" i18n-content="recentlyclosed"></div>
- <hr>
- <div command="clear-all-blacklisted"
- i18n-content="restorethumbnails"></div>
- </menu>
+<div id="main">
<div id="notification">
<span>&nbsp;</span>
<span class="link"><span class="link-color"></span></span>
</div>
+ <div class="maxiview" id="apps-maxiview"></div>
+ <div class="maxiview" id="most-visited-maxiview"></div>
+
<div class="sections">
- <div class="section disabled" id="apps-section"></div>
+ <!-- Start disabled. We only enable if we have at least one app. -->
+ <div id="apps" class="section disabled" section="APPS">
+ <h2>
+ <img class="disclosure" img src="ntp/ntp_disclosure_triangle.png">
+ <div class="back"></div>
+ <span i18n-content="apps"></span>
+ </h2>
+ <div class="miniview"></div>
+ </div>
- <div id="most-visited-section" class="section" section="THUMB">
- <h2 i18n-content="mostvisited"></h2>
- <div id="most-visited"></div>
+ <div id="most-visited" class="section" section="THUMB">
+ <h2>
+ <img class="disclosure" src="ntp/ntp_disclosure_triangle.png">
+ <div class="back"></div>
+ <span i18n-content="mostvisited"></span>
+ <button id="most-visited-settings" i18n-content="restorethumbnails">
+ </button>
+ </h2>
+ <div class="miniview"></div>
</div>
- <div id="recently-closed" class="section" section="RECENT">
- <h2 i18n-content="recentlyclosed"></h2>
- <span class="nav"></span>
+ <!-- Start this section disabled because it might not have data, and looks
+ silly without any. -->
+ <div id="recently-closed" class="section hidden disabled" section="RECENT"
+ noexpand="true">
+ <h2>
+ <div class="back"></div>
+ <span i18n-content="recentlyclosed"></span>
+ </h2>
+ <div class="miniview"></div>
</div>
- <div id="debug" class="section disabled" section="DEBUG">
- <h2>Debug</h2>
- <div id="apps-launch-control">
- Open apps in:<label
- ><input type="radio" name="launch-container-type" value=""
- checked="true">Default</label
- ><input type="radio" name="launch-container-type" value="tab"
- >Tab</label
- ><label><input type="radio" name="launch-container-type" value="window"
- >Window</label
- ><label><input type="radio" name="launch-container-type" value="panel"
- >Panel</label>
+ <div id="sync-status" class="section disabled">
+ <div>
+ <h3></h3>
+ <span></span>
</div>
</div>
</div>
-
- <script>
- updateSimpleSection('tip-line', Section.TIPS);
- updateSimpleSection('recently-closed', Section.RECENT);
- updateSimpleSection('most-visited-section', Section.THUMB);
- updateSimpleSection('debug', Section.DEBUG);
- </script>
-
- <div id="sync-status">
- <h2></h2>
- <span></span>
- </div>
-
- <div id="attribution" class="attribution">
- <div i18n-content="attributionintro"></div>
- <img id="attribution-img">
- </div>
-
- <div id="footer">
- <a href="chrome://history"><span class="link-color"
- i18n-content="history"></span></a>
- <hr>
- <a href="chrome://downloads"><span class="link-color"
- i18n-content="downloads"></span></a>
- <hr>
- <a i18n-values="href:helpurl"><span class="link-color"
- i18n-content="help"></span></a>
- </div>
-
</div> <!-- main -->
<div class="window-menu" id="window-tooltip"></div>
+<command id="clear-all-blacklisted" i18n-values=".label:restorethumbnails">
+<command id="apps-launch-command">
+<command id="apps-options-command" i18n-values=".label:appoptions">
+<command id="apps-uninstall-command" i18n-values=".label:appuninstall">
+<command id="apps-launch-type-pinned" i18n-values=".label:applaunchtypepinned"
+ launch-type="0">
+<command id="apps-launch-type-regular" i18n-values=".label:applaunchtyperegular"
+ launch-type="1">
+<command id="apps-launch-type-fullscreen"
+ i18n-values=".label:applaunchtypefullscreen" launch-type="2">
+
+<menu id="app-context-menu">
+ <button class="default" command="#apps-launch-command"></button>
+ <hr>
+ <button command="#apps-launch-type-pinned" launch-type="0"></button>
+ <button command="#apps-launch-type-regular" launch-type="1"></button>
+ <button command="#apps-launch-type-fullscreen" launch-type="2"></button>
+ <hr>
+ <button command="#apps-options-command"></button>
+ <button command="#apps-uninstall-command"></button>
+</menu>
+
</body>
<script src="shared/js/i18n_template.js"></script>
@@ -218,8 +203,31 @@ i18nTemplate.process(document, templateData);
<script src="shared/js/local_strings.js"></script>
<script src="shared/js/class_list.js"></script>
<script src="shared/js/parse_html_subset.js"></script>
+
+<script src="shared/js/cr.js"></script>
+<script src="shared/js/cr/ui.js"></script>
+<script src="shared/js/cr/ui/command.js"></script>
+<script src="shared/js/cr/ui/menu_item.js"></script>
+<script src="shared/js/cr/ui/menu.js"></script>
+<script src="shared/js/cr/ui/position_util.js"></script>
+<script src="shared/js/cr/ui/menu_button.js"></script>
+<script src="shared/js/cr/ui/context_menu_button.js"></script>
+<script src="shared/js/cr/ui/context_menu_handler.js"></script>
+
<script src="ntp/util.js"></script>
<script src="ntp/most_visited.js"></script>
<script src="new_new_tab.js"></script>
<script src="ntp/apps.js"></script>
+
+<script>
+cr.ui.decorate('menu', cr.ui.Menu);
+cr.ui.decorate('command', cr.ui.Command);
+cr.ui.decorate('button[menu]', cr.ui.MenuButton);
+</script>
+
+<script>
+ updateSimpleSection('apps', Section.APPS);
+ updateSimpleSection('most-visited', Section.THUMB);
+ layoutSections();
+</script>
</html>
diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js
index 0274b9b..99cb712 100644
--- a/chrome/browser/resources/new_new_tab.js
+++ b/chrome/browser/resources/new_new_tab.js
@@ -2,61 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-var loading = true;
+// To avoid creating tons of unnecessary nodes. We assume we cannot fit more
+// than this many items in the miniview.
+var MAX_MINIVIEW_ITEMS = 15;
+
+// Extra spacing at the top of the layout.
+var LAYOUT_SPACING_TOP = 25;
function updateSimpleSection(id, section) {
- if (shownSections & section)
+ var elm = $(id);
+ var maxiview = getSectionMaxiview(elm);
+ if (shownSections & section) {
$(id).classList.remove('hidden');
- else
+ if (maxiview)
+ maxiview.classList.remove('hidden');
+ } else {
$(id).classList.add('hidden');
-}
-
-var tipCache = {};
-
-function tips(data) {
- logEvent('received tips');
- tipCache = data;
- renderTip();
-}
-
-function createTip(data) {
- if (data.length) {
- if (data[0].set_homepage_tip) {
- var homepageButton = document.createElement('button');
- homepageButton.className = 'link';
- homepageButton.textContent = data[0].set_homepage_tip;
- homepageButton.addEventListener('click', setAsHomePageLinkClicked);
- return homepageButton;
- } else if (data[0].set_promo_tip) {
- var promoMessage = document.createElement('span');
- promoMessage.innerHTML = data[0].set_promo_tip;
- var promoButton = promoMessage.querySelector('button');
- promoButton.addEventListener('click', importBookmarksLinkClicked);
- return promoMessage;
- } else {
- try {
- return parseHtmlSubset(data[0].tip_html_text);
- } catch (parseErr) {
- console.error('Error parsing tips: ' + parseErr.message);
- }
- }
+ if (maxiview)
+ maxiview.classList.add('hidden');
}
- // Return an empty DF in case of failure.
- return document.createDocumentFragment();
-}
-
-function clearTipLine() {
- var tipElement = $('tip-line');
- // There should always be only one tip.
- tipElement.textContent = '';
- tipElement.removeEventListener('click', setAsHomePageLinkClicked);
-}
-
-function renderTip() {
- clearTipLine();
- var tipElement = $('tip-line');
- tipElement.appendChild(createTip(tipCache));
- fixLinkUnderlines(tipElement);
}
function recentlyClosedTabs(data) {
@@ -64,6 +28,7 @@ function recentlyClosedTabs(data) {
// We need to store the recent items so we can update the layout on a resize.
recentItems = data;
renderRecentlyClosed();
+ layoutSections();
}
var recentItems = [];
@@ -130,7 +95,196 @@ function handleWindowResize() {
mostVisited.useSmallGrid = b;
mostVisited.layout();
renderRecentlyClosed();
+ updateAllMiniviewClippings();
+ }
+
+ layoutSections();
+}
+
+// Stores some information about each section necessary to layout. A new
+// instance is constructed for each section on each layout.
+function SectionLayoutInfo(section) {
+ this.section = section;
+ this.header = section.getElementsByTagName('h2')[0];
+ this.miniview = section.getElementsByClassName('miniview')[0];
+ this.maxiview = getSectionMaxiview(section);
+ this.expanded = this.maxiview && !section.classList.contains('hidden');
+ this.fixedHeight = this.section.offsetHeight;
+ this.scrollingHeight = 0;
+
+ if (this.expanded)
+ this.scrollingHeight = this.maxiview.offsetHeight;
+}
+
+// Get all sections to be layed out.
+SectionLayoutInfo.getAll = function() {
+ var sections = document.querySelectorAll('.section:not(.disabled)');
+ var result = [];
+ for (var i = 0, section; section = sections[i]; i++) {
+ result.push(new SectionLayoutInfo(section));
+ }
+ return result;
+};
+
+// Ensure the miniview sections don't have any clipped items.
+function updateMiniviewClipping(miniview) {
+ var clipped = false;
+ for (var j = 0, item; item = miniview.children[j]; j++) {
+ item.style.display = '';
+ if (clipped ||
+ (item.offsetLeft + item.offsetWidth) > miniview.offsetWidth) {
+ item.style.display = 'none';
+ clipped = true;
+ } else {
+ item.style.display = '';
+ }
+ }
+}
+
+// Ensure none of the miniviews have any clipped items.
+function updateAllMiniviewClippings() {
+ var miniviews = document.querySelectorAll('.section.hidden .miniview');
+ for (var i = 0, miniview; miniview = miniviews[i]; i++) {
+ updateMiniviewClipping(miniview);
+ }
+}
+
+// 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.
+//
+// =============================
+// | collapsed section | <- Any collapsed sections are fixed position.
+// | and miniview |
+// |---------------------------|
+// | expanded section |
+// | | <- There can be one expanded section and it
+// | and maxiview | is absolutely positioned so that it can
+// | | scroll "underneath" the fixed elements.
+// | |
+// |---------------------------|
+// | another collapsed section |
+// |---------------------------|
+//
+// We want the main frame scrollbar to be the one that scrolls the expanded
+// region. To get this effect, we make the fixed elements position:fixed and the
+// scrollable element position:absolute. We also artificially increase the
+// height of the document so that it is possible to scroll down enough to
+// display the end of the document, even with any fixed elements at the bottom
+// of the viewport.
+//
+// There is a final twist: If the intrinsic height of the expanded section is
+// less than the available height (because the window is tall), any collapsed
+// sections sinch up and sit below the expanded section. This is so that we
+// don't have a bunch of dead whitespace in the case of expanded sections that
+// aren't very tall.
+function layoutSections() {
+ var sections = SectionLayoutInfo.getAll();
+ var expandedSection = null;
+ var headerHeight = LAYOUT_SPACING_TOP;
+ var footerHeight = 0;
+
+ // Calculate the height of the fixed elements above the expanded section. Also
+ // take note of the expanded section, if there is one.
+ var i;
+ var section;
+ for (i = 0; section = sections[i]; i++) {
+ headerHeight += section.fixedHeight;
+ if (section.expanded) {
+ expandedSection = section;
+ i++;
+ break;
+ }
}
+
+ // Calculate the height of the fixed elements below the expanded section, if
+ // any.
+ for (; section = sections[i]; i++) {
+ footerHeight += section.fixedHeight;
+ }
+
+ // Determine the height to use for the expanded section. If there isn't enough
+ // space to show the expanded section completely, this will be the available
+ // height. Otherwise, we use the intrinsic height of the expanded section.
+ var expandedSectionHeight;
+ if (expandedSection) {
+ var flexHeight = window.innerHeight - headerHeight - footerHeight;
+ if (flexHeight < expandedSection.scrollingHeight) {
+ expandedSectionHeight = flexHeight;
+
+ // Also, artificially expand the height of the document so that we can see
+ // the entire expanded section.
+ //
+ // TODO(aa): Where does this come from? It is the difference between what
+ // we set document.body.style.height to and what
+ // document.body.scrollHeight measures afterward. I expect them to be the
+ // same if document.body has no margins.
+ var fudge = 44;
+ document.body.style.height =
+ headerHeight +
+ expandedSection.scrollingHeight +
+ footerHeight +
+ fudge +
+ 'px';
+ } else {
+ expandedSectionHeight = expandedSection.scrollingHeight;
+ document.body.style.height = '';
+ }
+ }
+
+ // Now position all the elements.
+ var y = LAYOUT_SPACING_TOP;
+ for (i = 0, section; section = sections[i]; i++) {
+ 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 == expandedSection)
+ y += expandedSectionHeight;
+ }
+
+ updateAttributionDisplay(y);
+}
+
+function updateMask(maxiview, visibleHeightPx) {
+ // We want to end up with 10px gradients at the top and bottom of
+ // visibleHeight, but webkit-mask only supports expression in terms of
+ // percentages.
+
+ // We might not have enough room to do 10px gradients on each side. To get the
+ // right effect, we don't want to make the gradients smaller, but make them
+ // appear to mush into each other.
+ var gradientHeightPx = Math.min(10, Math.floor(visibleHeightPx / 2));
+ var gradientDestination = 'rgba(0,0,0,' + (gradientHeightPx / 10) + ')';
+
+ var bottomSpacing = 15;
+ var first = parseFloat(maxiview.style.top) / window.innerHeight;
+ var second = first + gradientHeightPx / window.innerHeight;
+ var fourth = first + (visibleHeightPx - bottomSpacing) / window.innerHeight;
+ var third = fourth - gradientHeightPx / window.innerHeight;
+
+ var gradientArguments = [
+ 'linear',
+ '0 0',
+ '0 100%',
+ 'from(transparent)',
+ getColorStopString(first, 'transparent'),
+ getColorStopString(second, gradientDestination),
+ getColorStopString(third, gradientDestination),
+ getColorStopString(fourth, 'transparent'),
+ 'to(transparent)'
+ ];
+
+ var gradient = '-webkit-gradient(' + gradientArguments.join(', ') + ')';
+ maxiview.style.WebkitMaskImage = gradient;
+}
+
+function getColorStopString(height, color) {
+ return 'color-stop(' + height + ', ' + color + ')';
}
window.addEventListener('resize', handleWindowResize);
@@ -147,21 +301,29 @@ function getSectionElement(section) {
return sectionToElementMap[section];
}
+function getSectionMaxiview(section) {
+ return $(section.id + '-maxiview');
+}
+
function showSection(section) {
if (!(section & shownSections)) {
shownSections |= section;
var el = getSectionElement(section);
- if (el)
+ if (el) {
el.classList.remove('hidden');
+ var maxiview = getSectionMaxiview(el);
+ if (maxiview) {
+ maxiview.classList.remove('hiding');
+ maxiview.classList.remove('hidden');
+ }
+ }
+
switch (section) {
case Section.THUMB:
mostVisited.visible = true;
mostVisited.layout();
break;
- case Section.RECENT:
- renderRecentlyClosed();
- break;
}
}
}
@@ -175,17 +337,32 @@ function hideSection(section) {
mostVisited.visible = false;
mostVisited.layout();
break;
- case Section.RECENT:
- renderRecentlyClosed();
- break;
}
var el = getSectionElement(section);
- if (el)
+ if (el) {
el.classList.add('hidden');
+
+ var maxiview = getSectionMaxiview(el);
+ if (maxiview)
+ maxiview.classList.add('hiding');
+
+ var miniview = el.getElementsByClassName('miniview')[0];
+ if (miniview)
+ updateMiniviewClipping(miniview);
+ }
}
}
+window.addEventListener('webkitTransitionEnd', function(e) {
+ if (e.target.classList.contains('hiding')) {
+ e.target.classList.add('hidden');
+ e.target.classList.remove('hiding');
+ }
+
+ document.documentElement.setAttribute('enable-section-animations', 'false');
+});
+
/**
* Callback when the shown sections changes in another NTP.
* @param {number} newShownSections Bitmask of the shown sections.
@@ -197,31 +374,34 @@ function setShownSections(newShownSections) {
else
hideSection(Section[key]);
}
+ layoutSections();
}
// Recently closed
function layoutRecentlyClosed() {
- var recentShown = shownSections & Section.RECENT;
-
- if (recentShown) {
- var recentElement = $('recently-closed');
- // We cannot use clientWidth here since the width has a transition.
- var availWidth = useSmallGrid() ? 692 : 920;
- var parentEl = recentElement.lastElementChild;
-
- // Now go backwards and hide as many elements as needed.
- var elementsToHide = [];
- for (var el = parentEl.lastElementChild; el;
- el = el.previousElementSibling) {
- if (el.offsetLeft + el.offsetWidth > availWidth) {
- elementsToHide.push(el);
- }
+ var recentElement = $('recently-closed');
+ // We cannot use clientWidth here since the width has a transition.
+ var availWidth = useSmallGrid() ? 692 : 920;
+ var parentEl = recentElement.lastElementChild;
+
+ // Now go backwards and hide as many elements as needed.
+ var elementsToHide = [];
+ for (var el = parentEl.lastElementChild; el;
+ el = el.previousElementSibling) {
+ if (el.offsetLeft + el.offsetWidth > availWidth) {
+ elementsToHide.push(el);
}
+ }
- elementsToHide.forEach(function(el) {
- parentEl.removeChild(el);
- });
+ elementsToHide.forEach(function(el) {
+ parentEl.removeChild(el);
+ });
+
+ if (parentEl.hasChildNodes()) {
+ recentElement.classList.remove('disabled');
+ } else {
+ recentElement.classList.add('disabled');
}
}
@@ -248,31 +428,33 @@ function layoutRecentlyClosed() {
*/
function syncMessageChanged(newMessage) {
var syncStatusElement = $('sync-status');
- var style = syncStatusElement.style;
// Hide the section if the message is emtpy.
if (!newMessage['syncsectionisvisible']) {
- style.display = 'none';
+ syncStatusElement.classList.add('disabled');
return;
}
- style.display = 'block';
+
+ syncStatusElement.classList.remove('disabled');
+
+ var content = syncStatusElement.children[0];
// Set the sync section background color based on the state.
if (newMessage.msgtype == 'error') {
- style.backgroundColor = 'tomato';
+ content.style.backgroundColor = 'tomato';
} else {
- style.backgroundColor = '';
+ content.style.backgroundColor = '';
}
// Set the text for the header and sync message.
- var titleElement = syncStatusElement.firstElementChild;
+ var titleElement = content.firstElementChild;
titleElement.textContent = newMessage.title;
var messageElement = titleElement.nextElementSibling;
messageElement.textContent = newMessage.msg;
// Remove what comes after the message
while (messageElement.nextSibling) {
- syncStatusElement.removeChild(messageElement.nextSibling);
+ content.removeChild(messageElement.nextSibling);
}
if (newMessage.linkisvisible) {
@@ -287,9 +469,11 @@ function syncMessageChanged(newMessage) {
el.addEventListener('click', syncSectionLinkClicked);
}
el.textContent = newMessage.linktext;
- syncStatusElement.appendChild(el);
+ content.appendChild(el);
fixLinkUnderline(el);
}
+
+ layoutSections();
}
/**
@@ -322,14 +506,51 @@ function formatTabsText(numTabs) {
// Theme related
-function themeChanged() {
+function themeChanged(hasAttribution) {
+ document.documentElement.setAttribute('hasattribution', hasAttribution);
$('themecss').href = 'chrome://theme/css/newtab.css?' + Date.now();
updateAttribution();
}
function updateAttribution() {
- $('attribution-img').src = 'chrome://theme/IDR_THEME_NTP_ATTRIBUTION?' +
- Date.now();
+ // Default value for standard NTP with no theme attribution or custom logo.
+ logEvent('updateAttribution called');
+ var imageId = 'IDR_PRODUCT_LOGO';
+ // Theme attribution always overrides custom logos.
+ if (document.documentElement.getAttribute('hasattribution') == 'true') {
+ logEvent('updateAttribution called with THEME ATTR');
+ imageId = 'IDR_THEME_NTP_ATTRIBUTION';
+ } else if (document.documentElement.getAttribute('customlogo') == 'true') {
+ logEvent('updateAttribution with CUSTOMLOGO');
+ imageId = 'IDR_CUSTOM_PRODUCT_LOGO';
+ }
+
+ $('attribution-img').src = 'chrome://theme/' + imageId + '?' + Date.now();
+}
+
+// If the content overlaps with the attribution, we bump its opacity down.
+function updateAttributionDisplay(contentBottom) {
+ var attribution = $('attribution');
+ var main = $('main');
+ var rtl = document.documentElement.dir == 'rtl';
+ var contentRect = main.getBoundingClientRect();
+ var attributionRect = attribution.getBoundingClientRect();
+
+ // Hack. See comments for '.haslayout' in new_new_tab.css.
+ if (attributionRect.width == 0)
+ return;
+ else
+ attribution.classList.remove('nolayout');
+
+ if (contentBottom > attribution.offsetTop) {
+ if ((!rtl && contentRect.right > attributionRect.left) ||
+ (rtl && attributionRect.right > contentRect.left)) {
+ attribution.classList.add('obscured');
+ return;
+ }
+ }
+
+ attribution.classList.remove('obscured');
}
function bookmarkBarAttached() {
@@ -351,20 +572,6 @@ function viewLog() {
console.log(lines.join('\n'));
}
-// Updates the visibility of the menu items.
-function updateOptionMenu() {
- var menuItems = $('option-menu').children;
- for (var i = 0; i < menuItems.length; i++) {
- var item = menuItems[i];
- var command = item.getAttribute('command');
- if (command == 'show' || command == 'hide') {
- var section = Section[item.getAttribute('section')];
- var visible = shownSections & section;
- item.setAttribute('command', visible ? 'hide' : 'show');
- }
- }
-}
-
// We apply the size class here so that we don't trigger layout animations
// onload.
@@ -376,7 +583,7 @@ var localStrings = new LocalStrings();
// Things we know are not needed at startup go below here
function afterTransition(f) {
- if (loading) {
+ if (!isDoneLoading()) {
// Make sure we do not use a timer during load since it slows down the UI.
f();
} else {
@@ -447,223 +654,65 @@ function hideNotification() {
actionLink.blur();
}
-/**
- * This handles the option menu.
- * @param {Element} button The button element.
- * @param {Element} menu The menu element.
- * @constructor
- */
-function OptionMenu(button, menu) {
- this.button = button;
- this.menu = menu;
- this.button.onmousedown = bind(this.handleMouseDown, this);
- this.button.onkeydown = bind(this.handleKeyDown, this);
- this.boundHideMenu_ = bind(this.hide, this);
- this.boundMaybeHide_ = bind(this.maybeHide_, this);
- this.menu.onmouseover = bind(this.handleMouseOver, this);
- this.menu.onmouseout = bind(this.handleMouseOut, this);
- this.menu.onmouseup = bind(this.handleMouseUp, this);
-}
-
-OptionMenu.prototype = {
- show: function() {
- updateOptionMenu();
- this.positionMenu_();
- this.menu.style.display = 'block';
- this.button.classList.add('open');
- this.button.focus();
-
- // Listen to document and window events so that we hide the menu when the
- // user clicks outside the menu or tabs away or the whole window is blurred.
- document.addEventListener('focus', this.boundMaybeHide_, true);
- document.addEventListener('mousedown', this.boundMaybeHide_, true);
- },
-
- positionMenu_: function() {
- this.menu.style.top = this.button.getBoundingClientRect().bottom + 'px';
- },
-
- hide: function() {
- this.menu.style.display = 'none';
- this.button.classList.remove('open');
- this.setSelectedIndex(-1);
-
- document.removeEventListener('focus', this.boundMaybeHide_, true);
- document.removeEventListener('mousedown', this.boundMaybeHide_, true);
- },
-
- isShown: function() {
- return this.menu.style.display == 'block';
- },
-
- /**
- * Callback for document mousedown and focus. It checks if the user tried to
- * navigate to a different element on the page and if so hides the menu.
- * @param {Event} e The mouse or focus event.
- * @private
- */
- maybeHide_: function(e) {
- if (!this.menu.contains(e.target) && !this.button.contains(e.target)) {
- this.hide();
- }
- },
-
- handleMouseDown: function(e) {
- if (this.isShown()) {
- this.hide();
- } else {
- this.show();
- }
- },
-
- handleMouseOver: function(e) {
- var el = e.target;
- if (!el.hasAttribute('command')) {
- this.setSelectedIndex(-1);
- } else {
- var index = Array.prototype.indexOf.call(this.menu.children, el);
- this.setSelectedIndex(index);
- }
- },
-
- handleMouseOut: function(e) {
- this.setSelectedIndex(-1);
- },
-
- handleMouseUp: function(e) {
- var item = this.getSelectedItem();
- if (item) {
- this.executeItem(item);
- }
- },
+function showFirstRunNotification() {
+ showNotification(localStrings.getString('firstrunnotification'),
+ localStrings.getString('closefirstrunnotification'),
+ null, 30000);
+ var notificationElement = $('notification');
+ notification.classList.add('first-run');
+}
- handleKeyDown: function(e) {
- var item = this.getSelectedItem();
-
- var self = this;
- function selectNextVisible(m) {
- var children = self.menu.children;
- var len = children.length;
- var i = self.selectedIndex_;
- if (i == -1 && m == -1) {
- // Edge case when we need to go the last item fisrt.
- i = 0;
- }
- while (true) {
- i = (i + m + len) % len;
- item = children[i];
- if (item && item.hasAttribute('command') &&
- item.style.display != 'none') {
- break;
- }
- }
- if (item) {
- self.setSelectedIndex(i);
- }
- }
+$('main').addEventListener('click', function(e) {
+ var p = e.target;
+ while (p && p.tagName != 'H2') {
+ // In case the user clicks on a button we do not want to expand/collapse a
+ // section.
+ if (p.tagName == 'BUTTON')
+ return;
+ p = p.parentNode;
+ }
- switch (e.keyIdentifier) {
- case 'Down':
- if (!this.isShown()) {
- this.show();
- }
- selectNextVisible(1);
- e.preventDefault();
- break;
- case 'Up':
- if (!this.isShown()) {
- this.show();
- }
- selectNextVisible(-1);
- e.preventDefault();
- break;
- case 'Esc':
- case 'U+001B': // Maybe this is remote desktop playing a prank?
- this.hide();
- break;
- case 'Enter':
- case 'U+0020': // Space
- if (this.isShown()) {
- if (item) {
- this.executeItem(item);
- } else {
- this.hide();
- }
- } else {
- this.show();
- }
- e.preventDefault();
- break;
- }
- },
+ if (!p)
+ return;
- selectedIndex_: -1,
- setSelectedIndex: function(i) {
- if (i != this.selectedIndex_) {
- var items = this.menu.children;
- var oldItem = items[this.selectedIndex_];
- if (oldItem) {
- oldItem.removeAttribute('selected');
- }
- var newItem = items[i];
- if (newItem) {
- newItem.setAttribute('selected', 'selected');
- }
- this.selectedIndex_ = i;
- }
- },
+ p = p.parentNode;
+ if (!getSectionMaxiview(p))
+ return;
- getSelectedItem: function() {
- return this.menu.children[this.selectedIndex_] || null;
- },
+ toggleSectionVisibilityAndAnimate(p.getAttribute('section'));
+});
- executeItem: function(item) {
- var command = item.getAttribute('command');
- if (command in this.commands) {
- this.commands[command].call(this, item);
- }
+$('most-visited-settings').addEventListener('click', function() {
+ $('clear-all-blacklisted').execute();
+});
- this.hide();
- }
-};
+function toggleSectionVisibilityAndAnimate(section) {
+ if (!section)
+ return;
-var optionMenu = new OptionMenu($('option-button'), $('option-menu'));
-optionMenu.commands = {
- 'clear-all-blacklisted' : function() {
- mostVisited.clearAllBlacklisted();
- chrome.send('getMostVisited');
- },
- 'show': function(item) {
- var section = Section[item.getAttribute('section')];
- showSection(section);
- saveShownSections();
- },
- 'hide': function(item) {
- var section = Section[item.getAttribute('section')];
- hideSection(section);
- saveShownSections();
- }
-};
+ // It looks better to return the scroll to the top when toggling sections.
+ document.body.scrollTop = 0;
-$('main').addEventListener('click', function(e) {
- if (e.target.tagName == 'H2') {
- var p = e.target.parentNode;
- var section = p.getAttribute('section');
- if (section) {
- if (shownSections & Section[section])
- hideSection(Section[section]);
+ // We set it back in webkitTransitionEnd.
+ document.documentElement.setAttribute('enable-section-animations', 'true');
+ if (shownSections & Section[section]) {
+ hideSection(Section[section]);
+ } else {
+ for (var p in Section) {
+ if (p == section)
+ showSection(Section[p]);
else
- showSection(Section[section]);
- saveShownSections();
+ hideSection(Section[p]);
}
}
-});
+ layoutSections();
+ saveShownSections();
+}
function handleIfEnterKey(f) {
return function(e) {
- if (e.keyIdentifier == 'Enter') {
+ if (e.keyIdentifier == 'Enter')
f(e);
- }
};
}
@@ -714,8 +763,8 @@ recentlyClosedElement.addEventListener('focus', maybeShowWindowTooltip, true);
*/
function WindowTooltip(tooltipEl) {
this.tooltipEl = tooltipEl;
- this.boundHide_ = bind(this.hide, this);
- this.boundHandleMouseOut_ = bind(this.handleMouseOut, this);
+ this.boundHide_ = this.hide.bind(this);
+ this.boundHandleMouseOut_ = this.handleMouseOut.bind(this);
}
WindowTooltip.trackMouseMove_ = function(e) {
@@ -739,7 +788,7 @@ WindowTooltip.prototype = {
} else { // focus
this.linkEl_.addEventListener('blur', this.boundHide_);
}
- this.timer = window.setTimeout(bind(this.show, this, e.type, linkEl, tabs),
+ this.timer = window.setTimeout(this.show.bind(this, e.type, linkEl, tabs),
WindowTooltip.DELAY);
},
show: function(type, linkEl, tabs) {
@@ -819,12 +868,12 @@ WindowTooltip.prototype = {
var windowTooltip = new WindowTooltip($('window-tooltip'));
-window.addEventListener('load', bind(logEvent, global, 'Tab.NewTabOnload',
- true));
+window.addEventListener('load',
+ logEvent.bind(global, 'Tab.NewTabOnload', true));
window.addEventListener('resize', handleWindowResize);
document.addEventListener('DOMContentLoaded',
- bind(logEvent, global, 'Tab.NewTabDOMContentLoaded', true));
+ logEvent.bind(global, 'Tab.NewTabDOMContentLoaded', true));
// Whether or not we should send the initial 'GetSyncMessage' to the backend
// depends on the value of the attribue 'syncispresent' which the backend sets
@@ -845,33 +894,6 @@ function callGetSyncMessageIfSyncIsPresent() {
}
}
-function setAsHomePageLinkClicked(e) {
- chrome.send('setHomePage');
- e.preventDefault();
-}
-
-function importBookmarksLinkClicked(e) {
- chrome.send('importBookmarks');
- e.preventDefault();
-}
-
-function onHomePageSet(data) {
- showNotification(data[0], data[1]);
- // Removes the "make this my home page" tip.
- clearTipLine();
-}
-
-function hideAllMenus() {
- optionMenu.hide();
-}
-
-window.addEventListener('blur', hideAllMenus);
-window.addEventListener('keydown', function(e) {
- if (e.keyIdentifier == 'Alt' || e.keyIdentifier == 'Meta') {
- hideAllMenus();
- }
-}, true);
-
// Tooltip for elements that have text that overflows.
document.addEventListener('mouseover', function(e) {
// We don't want to do this while we are dragging because it makes things very
@@ -916,33 +938,38 @@ function fixLinkUnderline(el) {
updateAttribution();
-var mostVisited = new MostVisited($('most-visited'),
- useSmallGrid(),
- shownSections & Section.THUMB);
+var mostVisited = new MostVisited(
+ $('most-visited-maxiview'),
+ document.querySelector('#most-visited .miniview'),
+ useSmallGrid(),
+ shownSections & Section.THUMB);
-function mostVisitedPages(data, firstRun) {
+function mostVisitedPages(data, firstRun, hasBlacklistedUrls) {
logEvent('received most visited pages');
+ mostVisited.updateSettingsLink(hasBlacklistedUrls);
mostVisited.data = data;
mostVisited.layout();
-
- loading = false;
+ layoutSections();
// Remove class name in a timeout so that changes done in this JS thread are
// not animated.
window.setTimeout(function() {
mostVisited.ensureSmallGridCorrect();
- document.body.classList.remove('loading');
+ maybeDoneLoading();
}, 1);
-}
-// Log clicked links from the tips section.
-document.addEventListener('click', function(e) {
- var tipLinks = document.querySelectorAll('#tip-line a');
- for (var i = 0, tipLink; tipLink = tipLinks[i]; i++) {
- if (tipLink.contains(e.target)) {
- chrome.send('metrics', ['NTPTip_' + tipLink.href]);
- break;
- }
+ // Only show the first run notification if first run.
+ if (firstRun) {
+ showFirstRunNotification();
}
-});
+}
+
+function maybeDoneLoading() {
+ if (mostVisited.data && apps.loaded)
+ document.body.classList.remove('loading');
+}
+
+function isDoneLoading() {
+ return !document.body.classList.contains('loading');
+}
diff --git a/chrome/browser/resources/new_tab_theme.css b/chrome/browser/resources/new_tab_theme.css
index ae39264..88e3fcc 100644
--- a/chrome/browser/resources/new_tab_theme.css
+++ b/chrome/browser/resources/new_tab_theme.css
@@ -1,12 +1,16 @@
-html {
- background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$1);
+html,
+.section > h2 span,
+#most-visited-settings {
+ background-attachment: fixed;
background-color: $2; /* COLOR_NTP_BACKGROUND */
+ background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$1);
background-position: $3;
background-repeat: $5;
- overflow: hidden;
}
-html[bookmarkbarattached='true'] {
+html[bookmarkbarattached='true'],
+html[bookmarkbarattached='true'] .section > h2 span,
+html[bookmarkbarattached='true'] #most-visited-settings {
background-position: $4;
}
@@ -16,17 +20,15 @@ body {
overflow: auto;
}
-#main {
- background: url(chrome://theme/IDR_PRODUCT_LOGO?$1) no-repeat 0 8px;
-}
-
+/* TODO(aa): Is this still in use? The styling may be incorrect with M7 NTP
+ rework. */
#notification.first-run {
background-color: $$1; /* COLOR_NTP_SECTION */
border-color: $$2; /* COLOR_NTP_SECTION_BORDER */
}
#notification.first-run .link {
- color: $$6; /* COLOR_NTP_LINK_UNDERLINE */
+ color: $$5; /* COLOR_NTP_LINK_UNDERLINE */
}
#notification.first-run .link-color {
@@ -68,29 +70,22 @@ body {
background-color: $$1; /* COLOR_NTP_SECTION */
}
-#option-button {
- background-color: $7; /* color_header_gradient_light */
- -webkit-mask-image: url(chrome://theme/IDR_NEWTAB_MENU_MASK);
-}
-
-#recently-closed {
+.miniview {
color: $8; /* COLOR_NTP_TEXT */
}
-#recently-closed > span > span {
- color: $$6; /* COLOR_NTP_LINK_UNDERLINE */
+.miniview > span {
+ color: $$5; /* COLOR_NTP_LINK_UNDERLINE */
text-decoration: underline;
}
-#recently-closed > span > span > .item {
+.miniview > span > .item {
color: $9; /* COLOR_NTP_LINK */
text-decoration: none;
}
#attribution {
- display: $$5;
color: $9; /* COLOR_NTP_LINK */
- text-align: right;
}
#tip-line {
@@ -104,40 +99,39 @@ body {
:link,
:visited,
.link {
- color: $$6; /* COLOR_NTP_LINK_UNDERLINE */
+ color: $$5; /* COLOR_NTP_LINK_UNDERLINE */
}
-#top-bar {
- border-bottom: 1px solid $$2; /* COLOR_NTP_SECTION_BORDER */
+.section > h2 {
+ color: $$7; /* COLOR_NTP_SECTION_HEADER_TEXT */
}
-.section {
- border-top: 1px solid $$2; /* COLOR_NTP_SECTION_BORDER */
- border-bottom: 1px solid $$2; /* COLOR_NTP_SECTION_BORDER */
+.section:not(.hidden) > h2 {
+ color: $$8; /* COLOR_NTP_SECTION_HEADER_TEXT_HOVER */
}
-.section.hidden + :not(.hidden) {
- border-top: 1px solid $$2; /* COLOR_NTP_SECTION_BORDER */;
+.section.hidden:not([noexpand]) > h2:hover {
+ color: $$8; /* COLOR_NTP_SECTION_HEADER_TEXT_HOVER */
}
-.section.hidden + .hidden > h2 {
- border-left: 1px solid $$2; /* COLOR_NTP_SECTION_BORDER */
+.section > h2 .back {
+ border-top: 1px solid $$1; /* COLOR_NTP_SECTION */
}
-.section > h2 {
- color: $8; /* COLOR_NTP_TEXT */
+.section.hidden > h2 .back {
+ background: none;
+ border-color-top: $$$1; /* COLOR_NTP_SECTION_HEADER_RULE_LIGHT */
+}
+
+.section.hidden:hover > h2 .back {
+ border-color-top: $$9; /* COLOR_NTP_SECTION_HEADER_RULE */
}
-#apps-section a {
+.app a {
color: $8; /* COLOR_NTP_TEXT */
}
-#apps-section .app:hover > .front > a,
-#apps-section .app > .back {
+.app:hover > a {
color: $$3; /* COLOR_NTP_SECTION_TEXT */
background-color: $$1; /* COLOR_NTP_SECTION */;
}
-
-#footer hr {
- color: $$2; /* COLOR_NTP_SECTION_BORDER */
-}
diff --git a/chrome/browser/resources/notification_1line.html b/chrome/browser/resources/notification_1line.html
index 242f48b..21c16a9 100644
--- a/chrome/browser/resources/notification_1line.html
+++ b/chrome/browser/resources/notification_1line.html
@@ -4,7 +4,6 @@
<title>$2</title>
<style>
body {
- margin: 6px;
font-family: helvetica, arial, sans-serif;
font-size: 13px;
}
diff --git a/chrome/browser/resources/notification_2line.html b/chrome/browser/resources/notification_2line.html
index 1361393..eeca22a 100644
--- a/chrome/browser/resources/notification_2line.html
+++ b/chrome/browser/resources/notification_2line.html
@@ -3,9 +3,6 @@
<head>
<title>$1</title>
<style type="text/css">
- body {
- margin: 6px;
- }
#title {
font-weight: bold;
font-size: 13px;
diff --git a/chrome/browser/resources/notification_icon.html b/chrome/browser/resources/notification_icon.html
index f3cfc5f..23a387a 100644
--- a/chrome/browser/resources/notification_icon.html
+++ b/chrome/browser/resources/notification_icon.html
@@ -4,8 +4,6 @@
<title>$2</title>
<style>
body {
- margin: 6px;
- height: 50px;
direction: $5;
}
#icon {
diff --git a/chrome/browser/resources/ntp/apps.css b/chrome/browser/resources/ntp/apps.css
index 67c7b70..a199154 100644
--- a/chrome/browser/resources/ntp/apps.css
+++ b/chrome/browser/resources/ntp/apps.css
@@ -1,7 +1,7 @@
/* Apps */
-#apps-section .app,
-#apps-section .app[new=installed] {
+.app,
+.app[new=installed] {
-webkit-box-sizing: border-box;
-webkit-perspective: 400;
border-radius: 10px;
@@ -13,8 +13,6 @@
width: 124px; /* 920 / 7 - margin * 2 */
}
-.app > .front,
-.app > .back,
.app a {
border-radius: 10px;
bottom: 0;
@@ -24,18 +22,13 @@
top: 0;
}
-.app > .front,
-.app > .back {
- -webkit-backface-visibility: hidden;
- -webkit-transition: -webkit-transform .15s;
-}
-
.app a {
-webkit-transition: background-color .5s;
background: rgba(255, 255, 255, 0) /* transparent white */
no-repeat center 10px;
background-size: 96px 96px;
- font-weight: bold;
+ font-family: Helvetica, Arial;
+ font-size: 107%;
overflow: hidden;
padding: 111px 10px 10px; /* 10 + 96 + 5 */
text-align: center;
@@ -44,8 +37,9 @@
white-space: nowrap;
}
-.app .flip {
+.app .app-settings {
background-color: transparent;
+ background-position: center center;
border: 0;
height: 14px;
padding: 0;
@@ -55,49 +49,24 @@
width: 14px;
}
-.app > .front > .flip {
+.app > .app-settings {
-webkit-transition: opacity .3s;
-webkit-transition-delay: 0;
background-image: url(chrome://theme/IDR_BALLOON_WRENCH);
opacity: 0;
}
-.app > .front > .flip:hover {
+.app > .app-settings:hover {
-webkit-transition: none;
- background-image: url(chrome://theme/IDR_BALLOON_WRENCH_HOVER);
+ background-image: url(chrome://theme/IDR_BALLOON_WRENCH_H);
}
-.app:hover > .front > .flip,
-.app > .front > .flip:focus {
+.app:hover > .app-settings,
+.app > .app-settings:focus {
-webkit-transition-delay: .5s;
opacity: .9;
}
-.app > .back > .flip {
- background-image: url(chrome://theme/IDR_BALLOON_CLOSE);
- opacity: .9;
-}
-
-.app > .back > .flip:hover {
- background-image: url(chrome://theme/IDR_BALLOON_CLOSE_HOVER);
-}
-
-.app > .back {
- padding: 10px;
-}
-
-.app > .back > h2 {
- font-size: 100%;
- margin: 10px 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.app > .back > button:not(.flip) {
- width: 100%;
-}
-
@-webkit-keyframes bounce {
0% {
-webkit-transform: scale(0, 0);
@@ -112,46 +81,19 @@
}
}
-#apps-section .app[new=new] {
+html[install-animation-enabled=true] .app[new=new] {
opacity: 0;
}
-#apps-section .app[new=installed] {
+html[install-animation-enabled=true] .app[new=installed] {
-webkit-animation: bounce .5s ease-in-out;
-webkit-transition: opacity .5s;
}
-#web-store-entry {
+a[app-id=web-store-entry] {
background-image: url("web_store_icon.png");
}
-/* Make items on the wrong side non focusable by hiding them. */
-.app:not(.config) > .back button,
-.app.config > .front button,
-.app.config > .front a {
- display: none;
-}
-
-html[has_3d=true] .app.config > .front {
- -webkit-transform: rotateY(180deg);
-}
-
-html[has_3d=true] .app > .back {
- -webkit-transform: rotateY(-180deg);
-}
-
-html[has_3d=true] .app.config > .back {
- -webkit-transform: rotateY(0deg);
-}
-
-html[has_3d=false] .app.config > .front {
- display: none;
-}
-
-html[has_3d=false] .app > .back {
- display: none;
-}
-
-html[has_3d=false] .app.config > .back {
- display: block;
+menu > button.default {
+ font-weight: bold;
}
diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js
index 41c2e6e..b128f05 100644
--- a/chrome/browser/resources/ntp/apps.js
+++ b/chrome/browser/resources/ntp/apps.js
@@ -3,131 +3,260 @@
// found in the LICENSE file.
function getAppsCallback(data) {
- logEvent('recieved apps');
- var appsSection = $('apps-section');
- var debugSection = $('debug');
- appsSection.textContent = '';
+ logEvent('received apps');
+ var appsSection = $('apps');
+ var appsSectionContent = $('apps-maxiview');
+ var appsMiniview = appsSection.getElementsByClassName('miniview')[0];
+ appsSectionContent.textContent = '';
+ appsMiniview.textContent = '';
- data.apps.forEach(function(app) {
- appsSection.appendChild(apps.createElement(app));
- });
+ if (data.apps.length == 0) {
+ appsSection.classList.add('disabled');
+ setShownSections(Section.THUMB);
+ } else {
+ data.apps.forEach(function(app) {
+ appsSectionContent.appendChild(apps.createElement(app));
+ });
+
+ appsSectionContent.appendChild(apps.createWebStoreElement());
+
+ data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) {
+ appsMiniview.appendChild(apps.createMiniviewElement(app));
+ });
- // TODO(aa): Figure out what to do with the debug mode when we turn apps on
- // for everyone.
- if (appsSection.hasChildNodes()) {
appsSection.classList.remove('disabled');
- if (data.showDebugLink) {
- debugSection.classList.remove('disabled');
- }
+ }
- appsSection.appendChild(apps.createWebStoreElement());
- } else {
- appsSection.classList.add('disabled');
- debugSection.classList.add('disabled');
+ apps.loaded = true;
+ maybeDoneLoading();
+
+ if (data.apps.length > 0 && isDoneLoading()) {
+ updateMiniviewClipping(appsMiniview);
+ layoutSections();
}
}
-var apps = {
- /**
- * @this {!HTMLAnchorElement}
- */
- handleClick_: function() {
- var launchType = '';
- var inputElements = document.querySelectorAll(
- '#apps-launch-control input');
- for (var i = 0, input; input = inputElements[i]; i++) {
- if (input.checked) {
- launchType = input.value;
- break;
- }
- }
+function appsPrefChangeCallback(data) {
+ // Currently the only pref that is watched is the launch type.
+ data.apps.forEach(function(app) {
+ var appLink = document.querySelector('.app a[app-id=' + app['id'] + ']');
+ if (appLink)
+ appLink.setAttribute('launch-type', app['launch_type']);
+ });
+}
+
+var apps = (function() {
+
+ function createElement(app) {
+ var div = document.createElement('div');
+ div.className = 'app';
+
+ var a = div.appendChild(document.createElement('a'));
+ a.setAttribute('app-id', app['id']);
+ a.setAttribute('launch-type', app['launch_type']);
+ a.xtitle = a.textContent = app['name'];
+ a.href = app['launch_url'];
+
+ return div;
+ }
+
+ function createContextMenu(app) {
+ var menu = new cr.ui.Menu;
+ var button = document.createElement(button);
+ }
+
+ function launchApp(appId) {
+ var appsSection = $('apps');
+ var expanded = !appsSection.classList.contains('hidden');
+ var element = document.querySelector(
+ (expanded ? '.maxiview' : '.miniview') + ' a[app-id=' + appId + ']');
// TODO(arv): Handle zoom?
- var rect = this.getBoundingClientRect();
- var cs = getComputedStyle(this);
+ var rect = element.getBoundingClientRect();
+ var cs = getComputedStyle(element);
var size = cs.backgroundSize.split(/\s+/); // background-size has the
// format '123px 456px'.
+
var width = parseInt(size[0], 10);
var height = parseInt(size[1], 10);
- // We are using background-position-x 50%.
- var left = rect.left + ((rect.width - width) >> 1); // Integer divide by 2.
- var top = rect.top + parseInt(cs.backgroundPositionY, 10);
- chrome.send('launchApp', [this.id, launchType,
+ var top, left;
+ if (expanded) {
+ // We are using background-position-x 50%.
+ top = rect.top + parseInt(cs.backgroundPositionY, 10);
+ left = rect.left + ((rect.width - width) >> 1); // Integer divide by 2.
+
+ } else {
+ // We are using background-position-y 50%.
+ top = rect.top + ((rect.height - width) >> 1); // Integer divide by 2.
+ if (getComputedStyle(element).direction == 'rtl')
+ left = rect.left + rect.width - width;
+ else
+ left = rect.left;
+ }
+
+ chrome.send('launchApp', [appId,
String(left), String(top),
String(width), String(height)]);
+ }
+
+ /**
+ * @this {!HTMLAnchorElement}
+ */
+ function handleClick(e) {
+ var appId = e.currentTarget.getAttribute('app-id');
+ launchApp(appId);
return false;
- },
+ }
- createElement_: function(app) {
- var div = document.createElement('div');
- div.className = 'app';
+ // Keep in sync with LaunchType in extension_prefs.h
+ var LaunchType = {
+ LAUNCH_PINNED: 0,
+ LAUNCH_REGULAR: 1,
+ LAUNCH_FULLSCREEN: 2
+ };
- var front = div.appendChild(document.createElement('div'));
- front.className = 'front';
+ // Keep in sync with LaunchContainer in extension.h
+ var LaunchContainer = {
+ LAUNCH_WINDOW: 0,
+ LAUNCH_PANEL: 1,
+ LAUNCH_TAB: 2
+ };
- var a = front.appendChild(document.createElement('a'));
- a.id = app['id'];
- a.xtitle = a.textContent = app['name'];
- a.href = app['launch_url'];
+ var currentApp;
- return div;
- },
-
- createElement: function(app) {
- var div = this.createElement_(app);
- var front = div.firstChild;
- var a = front.firstChild;
-
- a.onclick = apps.handleClick_;
- a.style.backgroundImage = url(app['icon']);
- if (hashParams['app-id'] == app['id']) {
- div.setAttribute('new', 'new');
- // Delay changing the attribute a bit to let the page settle down a bit.
- setTimeout(function() {
- div.setAttribute('new', 'installed');
- }, 500);
- }
+ function addContextMenu(el, app) {
+ el.addEventListener('contextmenu', cr.ui.contextMenuHandler);
+ el.addEventListener('keydown', cr.ui.contextMenuHandler);
+ el.addEventListener('keyup', cr.ui.contextMenuHandler);
- var settingsButton = front.appendChild(document.createElement('button'));
- settingsButton.className = 'flip';
- settingsButton.title = localStrings.getString('appsettings');
-
- var back = div.appendChild(document.createElement('div'));
- back.className = 'back';
-
- var header = back.appendChild(document.createElement('h2'));
- header.textContent = app['name'];
-
- var optionsButton = back.appendChild(document.createElement('button'));
- optionsButton.textContent = localStrings.getString('appoptions');
- optionsButton.disabled = !app['options_url'];
- optionsButton.onclick = function() {
- window.location = app['options_url'];
- };
-
- var uninstallButton = back.appendChild(document.createElement('button'));
- uninstallButton.textContent = uninstallButton.xtitle =
- localStrings.getString('appuninstall');
- uninstallButton.onclick = function() {
- chrome.send('uninstallApp', [app['id']]);
- };
-
- var closeButton = back.appendChild(document.createElement('button'));
- closeButton.title = localStrings.getString('close');
- closeButton.className = 'flip';
- closeButton.onclick = settingsButton.onclick = function() {
- div.classList.toggle('config');
- };
+ Object.defineProperty(el, 'contextMenu', {
+ get: function() {
+ currentApp = app;
- return div;
- },
+ $('apps-launch-command').label = app['name'];
+ $('apps-options-command').canExecuteChange();
+
+ var appLinkSel = '.app a[app-id=' + app['id'] + ']';
+ var launchType =
+ el.querySelector(appLinkSel).getAttribute('launch-type');
- createWebStoreElement: function() {
- return this.createElement_({
- 'id': 'web-store-entry',
- 'name': localStrings.getString('web_store_title'),
- 'launch_url': localStrings.getString('web_store_url')
+ var launchContainer = app['launch_container'];
+ var isPanel = launchContainer == LaunchContainer.LAUNCH_PANEL;
+
+ // Update the commands related to the launch type.
+ var launchTypeIds = ['apps-launch-type-pinned',
+ 'apps-launch-type-regular',
+ 'apps-launch-type-fullscreen'];
+ launchTypeIds.forEach(function(id) {
+ var command = $(id);
+ command.disabled = isPanel;
+ command.checked = !isPanel &&
+ launchType == command.getAttribute('launch-type');
+ });
+
+ return $('app-context-menu');
+ }
});
}
-};
+
+ document.addEventListener('command', function(e) {
+ if (!currentApp)
+ return;
+
+ var commandId = e.command.id;
+ switch (commandId) {
+ case 'apps-options-command':
+ window.location = currentApp['options_url'];
+ break;
+ case 'apps-launch-command':
+ launchApp(currentApp['id']);
+ break;
+ case 'apps-uninstall-command':
+ chrome.send('uninstallApp', [currentApp['id']]);
+ break;
+ case 'apps-launch-type-pinned':
+ case 'apps-launch-type-regular':
+ case 'apps-launch-type-fullscreen':
+ chrome.send('setLaunchType',
+ [currentApp['id'], e.command.getAttribute('launch-type')]);
+ break;
+ }
+ });
+
+ document.addEventListener('canExecute', function(e) {
+ switch (e.command.id) {
+ case 'apps-options-command':
+ e.canExecute = currentApp && currentApp['options_url'];
+ break;
+ case 'apps-launch-command':
+ case 'apps-uninstall-command':
+ e.canExecute = true;
+ break;
+ }
+ });
+
+ return {
+ loaded: false,
+
+ createElement: function(app) {
+ var div = createElement(app);
+ var a = div.firstChild;
+
+ a.onclick = handleClick;
+ a.style.backgroundImage = url(app['icon_big']);
+ if (hashParams['app-id'] == app['id']) {
+ div.setAttribute('new', 'new');
+ // Delay changing the attribute a bit to let the page settle down a bit.
+ setTimeout(function() {
+ // This will trigger the 'bounce' animation defined in apps.css.
+ div.setAttribute('new', 'installed');
+ }, 500);
+ div.addEventListener('webkitAnimationEnd', function(e) {
+ div.removeAttribute('new');
+
+ // If we get new data (eg because something installs in another tab,
+ // or because we uninstall something here), don't run the install
+ // animation again.
+ document.documentElement.setAttribute("install-animation-enabled",
+ "false");
+ });
+ if ($('apps').classList.contains('hidden'))
+ toggleSectionVisibilityAndAnimate('APPS');
+ }
+
+ var settingsButton = div.appendChild(new cr.ui.ContextMenuButton);
+ settingsButton.className = 'app-settings';
+ settingsButton.title = localStrings.getString('appsettings');
+
+ addContextMenu(div, app);
+
+ return div;
+ },
+
+ createMiniviewElement: function(app) {
+ var span = document.createElement('span');
+ var a = span.appendChild(document.createElement('a'));
+
+ a.setAttribute('app-id', app['id']);
+ a.textContent = app['name'];
+ a.href = app['launch_url'];
+ a.onclick = handleClick;
+ a.style.backgroundImage = url(app['icon_small']);
+ a.className = 'item';
+ span.appendChild(a);
+
+ addContextMenu(span, app);
+
+ return span;
+ },
+
+ createWebStoreElement: function() {
+ return createElement({
+ 'id': 'web-store-entry',
+ 'name': localStrings.getString('web_store_title'),
+ 'launch_url': localStrings.getString('web_store_url')
+ });
+ }
+ };
+})();
diff --git a/chrome/browser/resources/ntp/most_visited.css b/chrome/browser/resources/ntp/most_visited.css
index 25366b8..27f2958 100644
--- a/chrome/browser/resources/ntp/most_visited.css
+++ b/chrome/browser/resources/ntp/most_visited.css
@@ -1,10 +1,8 @@
/* Most Visited */
-#most-visited {
+#most-visited-maxiview {
position: relative;
- padding: 0;
height: 366px;
- margin-top: -10px;
-webkit-user-select: none;
}
@@ -240,7 +238,7 @@ html[dir=rtl] .thumbnail-container > .title > div {
}
@media (max-width: 940px) {
- #most-visited {
+ #most-visited-maxiview {
height: 294px;
}
@@ -258,3 +256,27 @@ html[dir=rtl] .thumbnail-container > .title > div {
background-size: 150px 93px;
}
}
+
+#most-visited-settings {
+ position: absolute;
+ top: 1px;
+ right: 0;
+ border: 0;
+ cursor: pointer;
+ font-size: 70%;
+ margin: 0;
+ padding: 0;
+ text-decoration: underline;
+ visibility: hidden;
+ -webkit-padding-start: 3px;
+ z-index: 3;
+}
+
+html[dir=rtl] #most-visited-settings {
+ left: 0;
+ right: auto;
+}
+
+#most-visited:not(.hidden) #most-visited-settings.has-blacklist {
+ visibility: visible;
+}
diff --git a/chrome/browser/resources/ntp/most_visited.js b/chrome/browser/resources/ntp/most_visited.js
index 23ea4b2..98f3317 100644
--- a/chrome/browser/resources/ntp/most_visited.js
+++ b/chrome/browser/resources/ntp/most_visited.js
@@ -41,29 +41,34 @@ var MostVisited = (function() {
return Array.prototype.indexOf.call(nodes, el);
}
- function MostVisited(el, useSmallGrid, visible) {
+ function MostVisited(el, miniview, useSmallGrid, visible) {
this.element = el;
+ this.miniview = miniview;
this.useSmallGrid_ = useSmallGrid;
this.visible_ = visible;
this.createThumbnails_();
this.applyMostVisitedRects_();
- el.addEventListener('click', bind(this.handleClick_, this));
- el.addEventListener('keydown', bind(this.handleKeyDown_, this));
+ el.addEventListener('click', this.handleClick_.bind(this));
+ el.addEventListener('keydown', this.handleKeyDown_.bind(this));
document.addEventListener('DOMContentLoaded',
- bind(this.ensureSmallGridCorrect, this));
+ this.ensureSmallGridCorrect.bind(this));
+
+ // Commands
+ document.addEventListener('command', this.handleCommand_.bind(this));
+ document.addEventListener('canExecute', this.handleCanExecute_.bind(this));
// DND
- el.addEventListener('dragstart', bind(this.handleDragStart_, this));
- el.addEventListener('dragenter', bind(this.handleDragEnter_, this));
- el.addEventListener('dragover', bind(this.handleDragOver_, this));
- el.addEventListener('dragleave', bind(this.handleDragLeave_, this));
- el.addEventListener('drop', bind(this.handleDrop_, this));
- el.addEventListener('dragend', bind(this.handleDragEnd_, this));
- el.addEventListener('drag', bind(this.handleDrag_, this));
- el.addEventListener('mousedown', bind(this.handleMouseDown_, this));
+ el.addEventListener('dragstart', this.handleDragStart_.bind(this));
+ el.addEventListener('dragenter', this.handleDragEnter_.bind(this));
+ el.addEventListener('dragover', this.handleDragOver_.bind(this));
+ el.addEventListener('dragleave', this.handleDragLeave_.bind(this));
+ el.addEventListener('drop', this.handleDrop_.bind(this));
+ el.addEventListener('dragend', this.handleDragEnd_.bind(this));
+ el.addEventListener('drag', this.handleDrag_.bind(this));
+ el.addEventListener('mousedown', this.handleMouseDown_.bind(this));
}
MostVisited.prototype = {
@@ -99,6 +104,13 @@ var MostVisited = (function() {
this.data[sourceIndex] = destinationData;
},
+ updateSettingsLink: function(hasBlacklistedUrls) {
+ if (hasBlacklistedUrls)
+ $('most-visited-settings').classList.add('has-blacklist');
+ else
+ $('most-visited-settings').classList.remove('has-blacklist');
+ },
+
blacklist: function(el) {
var self = this;
var url = el.href;
@@ -121,7 +133,11 @@ var MostVisited = (function() {
// Send 'getMostVisitedPages' with a callback since we want to find the
// new page and add that in the place of the removed page.
- chromeSend('getMostVisited', [], 'mostVisitedPages', function(data) {
+ chromeSend('getMostVisited', [], 'mostVisitedPages',
+ function(data, firstRun, hasBlacklistedUrls) {
+ // Update settings link.
+ self.updateSettingsLink(hasBlacklistedUrls);
+
// Find new item.
var newItem;
for (var i = 0; i < data.length; i++) {
@@ -254,6 +270,7 @@ var MostVisited = (function() {
var w = thumbWidth + 2 * borderWidth + 2 * marginWidth;
var h = thumbHeight + 40 + 2 * marginHeight;
var sumWidth = cols * w - 2 * marginWidth;
+ var topSpacing = 10;
var rtl = isRtl();
var rects = [];
@@ -265,7 +282,7 @@ var MostVisited = (function() {
var left = rtl ? sumWidth - col * w - thumbWidth - 2 * borderWidth :
col * w;
- var top = row * h;
+ var top = row * h + topSpacing;
rects[i] = {left: left, top: top};
}
@@ -298,6 +315,23 @@ var MostVisited = (function() {
return this.getMostVisitedLayoutRects_()[index];
},
+ // Commands
+
+ handleCommand_: function(e) {
+ var commandId = e.command.id;
+ switch (commandId) {
+ case 'clear-all-blacklisted':
+ this.clearAllBlacklisted();
+ chrome.send('getMostVisited');
+ break;
+ }
+ },
+
+ handleCanExecute_: function(e) {
+ if (e.command.id == 'clear-all-blacklisted')
+ e.canExecute = true;
+ },
+
// DND
currentOverItem_: null,
@@ -395,10 +429,10 @@ var MostVisited = (function() {
// The timeout below is to allow WebKit to see that we turned off
// pointer-event before moving the thumbnails so that we can get out of
// hover mode.
- window.setTimeout(bind(function() {
+ window.setTimeout((function() {
this.invalidate_();
this.layout();
- }, this), 10);
+ }).bind(this), 10);
e.preventDefault();
if (this.dragEndTimer_) {
window.clearTimeout(this.dragEndTimer_);
@@ -501,6 +535,7 @@ var MostVisited = (function() {
// On setting we need to update the items
this.data_ = data;
this.updateMostVisited_();
+ this.updateMiniview_();
},
updateMostVisited_: function() {
@@ -555,6 +590,25 @@ var MostVisited = (function() {
}
},
+ updateMiniview_: function() {
+ this.miniview.textContent = '';
+ var data = this.data.slice(0, MAX_MINIVIEW_ITEMS);
+ for (var i = 0, item; item = data[i]; i++) {
+ if (item.filler) {
+ continue;
+ }
+
+ var span = document.createElement('span');
+ var a = span.appendChild(document.createElement('a'));
+ a.href = item.url;
+ a.textContent = item.title;
+ a.style.backgroundImage = url('chrome://favicon/' + item.url);
+ a.className = 'item';
+ this.miniview.appendChild(span);
+ }
+ updateMiniviewClipping(this.miniview);
+ },
+
handleClick_: function(e) {
var target = e.target;
if (target.classList.contains('pin')) {
diff --git a/chrome/browser/resources/ntp/util.js b/chrome/browser/resources/ntp/util.js
index b759356..ebd1e4d 100644
--- a/chrome/browser/resources/ntp/util.js
+++ b/chrome/browser/resources/ntp/util.js
@@ -11,15 +11,6 @@ function $(id) {
return document.getElementById(id);
}
-function bind(fn, selfObj, var_args) {
- var boundArgs = Array.prototype.slice.call(arguments, 2);
- return function() {
- var args = Array.prototype.slice.call(arguments);
- args.unshift.apply(args, boundArgs);
- return fn.apply(selfObj, args);
- }
-}
-
function url(s) {
// http://www.w3.org/TR/css3-values/#uris
// Parentheses, commas, whitespace characters, single quotes (') and double
diff --git a/chrome/browser/resources/options.html b/chrome/browser/resources/options.html
index 16ee4f2..d6be2f9 100644
--- a/chrome/browser/resources/options.html
+++ b/chrome/browser/resources/options.html
@@ -1,11 +1,44 @@
<!DOCTYPE HTML>
-<html i18n-values="dir:textdirection;" id="t">
+<html
+ i18n-values="dir:textdirection;
+ enable-background-mode:enable-background-mode"
+ id="t">
<head>
<meta charset="utf-8">
<title i18n-content="title"></title>
-<!-- TODO(zelidrag) need a better icon here -->
-<link rel="icon" href="../../app/theme/history_favicon.png">
+<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/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/import_data_overlay.css">
+<link rel="stylesheet" href="options/search_engine_manager.css">
+<link rel="stylesheet" href="options/subpages_tab_controls.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">
+</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/class_list.js"></script>
<script src="chrome://resources/js/cr.js"></script>
@@ -13,108 +46,220 @@
<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/chromeos_language_hangul_options.js"></script>
+ <script src="options/about_page.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_add_user_overlay.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>
+ var CertificateManager = options.CertificateManager;
+ </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/personal_options.js"></script>
-<script src="options/content_settings_ui.js"></script>
-<script src="options/content_settings.js"></script>
+<script src="options/browser_options_startup_page_list.js"></script>
<script src="options/clear_browser_data_overlay.js"></script>
-<script src="options/font_settings_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/import_data_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/sync_options.js"></script>
<script>
-///////////////////////////////////////////////////////////////////////////////
-// Document Functions:
+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 OptionsPage = options.OptionsPage;
+var PasswordsExceptions = options.PasswordsExceptions;
+var PersonalOptions = options.PersonalOptions;
+var Preferences = options.Preferences;
+var SearchEngineManager = options.SearchEngineManager;
+var ProxyOptions = options.ProxyOptions;
+var SyncOptions = options.SyncOptions;
+
/**
* Window onload handler, sets up the page.
*/
function load() {
+ var start = new Date();
+
localStrings = new LocalStrings();
-
+
if (cr.isChromeOS) {
+ OptionsPage.registerSubPage(AboutPage.getInstance());
OptionsPage.register(SystemOptions.getInstance());
- OptionsPage.register(AccountsOptions.getInstance());
- // TODO(mazda): uncomment this once the language options is ready
- // OptionsPage.register(LanguageHangulOptions.getInstance());
+ OptionsPage.register(InternetOptions.getInstance());
}
OptionsPage.register(BrowserOptions.getInstance());
OptionsPage.register(PersonalOptions.getInstance());
OptionsPage.register(AdvancedOptions.getInstance());
+ OptionsPage.registerSubPage(AutoFillOptions.getInstance());
OptionsPage.registerSubPage(ContentSettings.getInstance());
+ OptionsPage.registerSubPage(CookiesView.getInstance());
+ OptionsPage.registerSubPage(FontSettings.getInstance());
+ OptionsPage.registerSubPage(PasswordsExceptions.getInstance());
+ OptionsPage.registerSubPage(SearchEngineManager.getInstance());
+ OptionsPage.registerSubPage(SyncOptions.getInstance());
+ if (!cr.isWindows && !cr.isMac) {
+ OptionsPage.registerSubPage(CertificateManager.getInstance());
+ }
+ OptionsPage.registerOverlay(AddStartupPageOverlay.getInstance());
+ OptionsPage.registerOverlay(AlertOverlay.getInstance());
+ OptionsPage.registerOverlay(AutoFillEditAddressOverlay.getInstance());
+ OptionsPage.registerOverlay(AutoFillEditCreditCardOverlay.getInstance());
OptionsPage.registerOverlay(ClearBrowserDataOverlay.getInstance());
- OptionsPage.registerOverlay(FontSettingsOverlay.getInstance());
+ OptionsPage.registerOverlay(EditSearchEngineOverlay.getInstance());
+ OptionsPage.registerOverlay(ImportDataOverlay.getInstance());
if (cr.isChromeOS) {
+ OptionsPage.register(AccountsOptions.getInstance());
var labsOptions = new OptionsPage('labs',
localStrings.getString('labsPage'),
'labsPage');
OptionsPage.register(labsOptions);
- var languageSettings = new OptionsPage('language',
- localStrings.getString(
- 'languagePage'),
- 'languagePage');
- OptionsPage.registerSubPage(languageSettings);
+ OptionsPage.registerSubPage(LanguageOptions.getInstance());
+ OptionsPage.registerSubPage(new OptionsPage(
+ 'languageChewing',
+ localStrings.getString('languageChewingPage'),
+ 'languageChewingPage'));
+ OptionsPage.registerSubPage(new OptionsPage(
+ 'languageHangul',
+ localStrings.getString('languageHangulPage'),
+ 'languageHangulPage'));
+ OptionsPage.registerSubPage(new OptionsPage(
+ 'languageMozc',
+ localStrings.getString('languageMozcPage'),
+ 'languageMozcPage'));
+ OptionsPage.registerSubPage(new OptionsPage(
+ 'languagePinyin',
+ localStrings.getString('languagePinyinPage'),
+ 'languagePinyinPage'));
+ OptionsPage.registerSubPage(ProxyOptions.getInstance());
+ OptionsPage.registerOverlay(new OptionsPage(
+ 'detailsInternetPage',
+ 'detailsInternetPage',
+ 'detailsInternetPage'));
}
- var syncSettings = new OptionsPage('sync',
- localStrings.getString('syncPage'),
- 'syncPage');
- OptionsPage.registerSubPage(syncSettings);
+ var languageModifierKeysOverlay = new OptionsPage(
+ 'languageCustomizeModifierKeysOverlay',
+ localStrings.getString('languageCustomizeModifierKeysOverlay'),
+ 'languageCustomizeModifierKeysOverlay')
+ OptionsPage.registerOverlay(languageModifierKeysOverlay);
Preferences.getInstance().initialize();
OptionsPage.initialize();
- // TODO(csilv): Save/restore last selected page.
- if (cr.isChromeOS) {
- OptionsPage.showPageByName(SystemOptions.getInstance().name);
+ 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 {
- OptionsPage.showPageByName(BrowserOptions.getInstance().name);
+ // 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);
+ }
}
+ var end = new Date();
+ var total = end - start;
+ console.log('time took to run load():'+ total);
}
document.addEventListener('DOMContentLoaded', load);
window.onpopstate = function(e) {
- OptionsPage.setState(e.state);
+ options.OptionsPage.setState(e.state);
};
-
</script>
-<link rel="stylesheet" href="chrome://resources/css/list.css">
-<link rel="stylesheet" href="dom_ui.css">
-<link rel="stylesheet" href="options/options_page.css">
-<link rel="stylesheet" href="options/browser_options_page.css">
-<link rel="stylesheet" href="options/content_settings_page.css">
-<if expr="pp_ifdef('chromeos')">
- <link rel="stylesheet" href="options/chromeos_accounts_options_page.css">
- <link rel="stylesheet" href="options/chromeos_language_options.css">
-</if>
+
</head>
<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
<div class="header">
</div>
<div id="overlay" class="overlay hidden">
- <div id="overlayview">
- <button id="close-overlay" onclick="OptionsPage.clearOverlays();"></button>
- <include src="options/clear_browser_data_overlay.html">
- <include src="options/font_settings_overlay.html">
- <if expr="pp_ifdef('chromeos')">
- <include src="options/chromeos_accounts_add_user_overlay.html">
- </if>
- </div>
+ <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">
+ <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>
</div>
<div id="main-content">
<div id="navbar-container">
@@ -126,30 +271,53 @@ window.onpopstate = function(e) {
</ul>
</div>
<div id="mainview">
- <if expr="pp_ifdef('chromeos')">
- <include src="options/chromeos_system_options.html">
- <include src="options/chromeos_language_options.html">
- <include src="options/chromeos_labs.html">
- <include src="options/chromeos_accounts_options.html">
- <!-- TODO(mazda): include options/chromeos_language_hangul_options.html
- once the language options dialog is ready. -->
- </if>
- <include src="options/browser_options.html">
- <include src="options/personal_options.html">
- <include src="options/advanced_options.html">
- <include src="options/content_settings.html">
- <include src="options/sync_options.html">
+ <div class="hidden" id="managed-prefs-banner">
+ <span id="managed-prefs-icon"></span>
+ <span i18n-content="managedPrefsBannerText"></span>
+ </div>
+ <div id="mainview-content">
+ <if expr="pp_ifdef('chromeos')">
+ <include src="options/about_page.html">
+ <include src="options/chromeos_system_options.html">
+ <include src="options/chromeos_internet_options.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_labs.html">
+ <include src="options/chromeos_accounts_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/advanced_options.html">
+ <include src="options/autofill_options.html">
+ <include src="options/browser_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/personal_options.html">
+ <include src="options/search_engine_manager.html">
+ <include src="options/sync_options.html">
+ </div>
</div>
</div>
<script>
// Decorate the existing elements in the document.
-cr.ui.decorate('input[pref][type=checkbox]', PrefCheckbox);
-cr.ui.decorate('input[pref][type=range]', PrefRange);
-cr.ui.decorate('select[pref]', PrefSelect);
-cr.ui.decorate('input[pref][type=url]', PrefTextField);
-cr.ui.decorate('#contentSettingsPage input[type=radio]', ContentSettingsRadio);
-// TODO(zelidrag) add other elements here when we implement them
+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);
+console.log('in bottom script');
</script>
</body>
</html>
diff --git a/chrome/browser/resources/options/advanced_options.html b/chrome/browser/resources/options/advanced_options.html
index 3cefd7c..349ed38 100644
--- a/chrome/browser/resources/options/advanced_options.html
+++ b/chrome/browser/resources/options/advanced_options.html
@@ -2,158 +2,145 @@
<h1 i18n-content="advancedPage"></h1>
<section>
<h3 i18n-content="advancedSectionTitlePrivacy"></h3>
- <table class="option-control-table">
- <tr><td>
+ <div>
+ <div>
<button id="privacyContentSettingsButton"
i18n-content="privacyContentSettingsButton"></button>
<button id="privacyClearDataButton"
i18n-content="privacyClearDataButton"></button>
- </td></tr>
- <tr><td>
- <div class="section-text"
- i18n-content="disableServices"></div>
- <div id="privacyLearnMore">
- <a target="_blank" i18n-content="privacyLearnMoreLabel"
- i18n-values="href:privacyLearnMoreURL"></a></div>
- </td></tr>
- <tr id="linkDoctorCheckbox">
- <td class="option-name"><label><input id="alternateErrorPagesEnabled"
- pref="alternate_error_pages.enabled" type="checkbox"><span
- i18n-content="linkDoctorPref"></span></label></td>
- </tr>
- <tr id="suggestCheckbox">
- <td class="option-name"><label><input id="searchSuggestEnabled"
- pref="search.suggest_enabled" type="checkbox"><span
- i18n-content="suggestPref"></span></label></td>
- </tr>
- <tr id="dnsPrefetchingCheckbox">
- <td class="option-name"><label><input id="dnsPrefetchingEnabled"
- pref="dns_prefetching.enabled" type="checkbox"><span
- i18n-content="networkDNSPrefetchEnabledDescription"></span></label>
- </td>
- </tr>
- <tr id="safeBrowsingCheckbox">
- <td class="option-name"><label><input id="safeBrowsingEnabled"
- pref="safebrowsing.enabled" type="checkbox"><span
- i18n-content="safeBrowsingEnableProtection"></span></label></td>
- </tr>
- <if expr="pp_ifdef('_google_chrome')">
- <tr id="metricsReportingCheckbox">
- <td class="option-name"><label><input id="metricsReportingEnabled"
- pref="user_experience_metrics.reporting_enabled" type="checkbox">
- <span i18n-content="enableLogging"></span></label></td>
- </tr>
- </if>
- </table>
+ </div>
+ <div i18n-content="disableServices"></div>
+ <div><a target="_blank" i18n-content="privacyLearnMoreLabel"
+ i18n-values="href:privacyLearnMoreURL"></a></div>
+ <label><input id="alternateErrorPagesEnabled"
+ pref="alternate_error_pages.enabled"
+ metric="Options_LinkDoctorCheckbox" type="checkbox"><span
+ i18n-content="linkDoctorPref"></span></label>
+ <label><input id="searchSuggestEnabled"
+ pref="search.suggest_enabled" metric="Options_UseSuggestCheckbox"
+ type="checkbox"><span i18n-content="suggestPref"></span></label>
+ <label><input id="dnsPrefetchingEnabled"
+ pref="dns_prefetching.enabled" metric="Options_DnsPrefetchCheckbox"
+ type="checkbox"><span
+ i18n-content="networkDNSPrefetchEnabledDescription"></span></label>
+ <label><input id="safeBrowsingEnabled"
+ pref="safebrowsing.enabled" metric="Options_SafeBrowsingCheckbox"
+ type="checkbox"><span i18n-content="safeBrowsingEnableProtection">
+ </span></label>
+<if expr="pp_ifdef('_google_chrome')">
+ <label><input id="metricsReportingEnabled" type="checkbox"><span
+ i18n-content="enableLogging"></span></label>
+</if>
+ </div>
</section>
<section>
<h3 i18n-content="advancedSectionTitleNetwork"></h3>
- <table class="option-control-table">
- <tr><td>
- <div class="section-text"
- i18n-content="proxiesLabel"></div>
- </td></tr>
- <tr><td>
- <button id="proxiesConfigureButton"
- i18n-content="proxiesConfigureButton"></button>
- </td></tr>
- </table>
+ <div>
+ <div id="proxiesLabel"></div>
+ <button id="proxiesConfigureButton"
+ i18n-content="proxiesConfigureButton"></button>
+ </div>
</section>
<section>
<h3 i18n-content="advancedSectionTitleTranslate"></h3>
- <table class="option-control-table">
- <tr id="enableTranslateCheckbox">
- <td class="option-name"><label><input id="enableTranslate"
- pref="translate.enabled" type="checkbox"><span
- i18n-content="translateEnableTranslate"></span></label></td>
- </tr>
- </table>
+ <div>
+ <label><input id="enableTranslate"
+ pref="translate.enabled" metric="Options_Translate" type="checkbox">
+ <span i18n-content="translateEnableTranslate"></span></label>
+ </div>
</section>
<section>
<h3 i18n-content="downloadLocationGroupName"></h3>
- <table class="option-control-table">
- <tr><td>
- <div class="section_text"
- i18n-content="downloadLocationBrowseTitle"></div>
+ <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>
- </td></tr>
- <tr id="promptForDownloadCheckbox">
- <td class="option-name"><label><input id="promptForDownload"
- pref="download.prompt_for_download" type="checkbox"><span
- i18n-content="downloadLocationAskForSaveLocation"></span></label>
- </td>
- </tr>
- <tr><td>
- <div class="section-text"
- i18n-content="autoOpenFileTypesInfo"></div>
- <button id="autoOpenFileTypesResetToDefault"
- i18n-content="autoOpenFileTypesResetToDefault"></button>
- </td></tr>
- </table>
+ </div>
+ <label><input id="promptForDownload"
+ pref="download.prompt_for_download"
+ metric="Options_AskForSaveLocation" type="checkbox"><span
+ i18n-content="downloadLocationAskForSaveLocation"></span></label>
+</if>
+ <div i18n-content="autoOpenFileTypesInfo"></div>
+ <div><button id="autoOpenFileTypesResetToDefault"
+ i18n-content="autoOpenFileTypesResetToDefault"></button></div>
+ </div>
</section>
<section>
<h3 i18n-content="advancedSectionTitleContent"></h3>
- <table class="option-control-table">
- <if expr="os == 'darwin'">
- <tr id="tabsToLinksCheckbox">
- <td class="option-name"><label><input id="tabsToLinksPref"
- pref="webkit.webprefs.tabs_to_links" type="checkbox"><span
- i18n-content="tabsToLinksPref"></span></label></td>
- </tr>
- </if>
- <tr id="fontSettingsConfigureFontsOnlyButton"><td>
- <button id="fontSettingsConfigureFontsOnlyButton"
- i18n-content="fontSettingsConfigureFontsOnlyButton"></button>
- </td></tr>
- </table>
+ <div>
+<if expr="os == 'darwin'">
+ <label><input id="tabsToLinksPref"
+ pref="webkit.webprefs.tabs_to_links" metric="Options_TabsToLinks"
+ type="checkbox"><span i18n-content="tabsToLinksPref"></span></label>
+</if>
+ <div><button id="fontSettingsConfigureFontsOnlyButton"
+ i18n-content="fontSettingsConfigureFontsOnlyButton"></button></div>
+<if expr="os == 'win32'">
+ <div>
+ <label style="display:inline;">
+ <span i18n-content="gearSettingsGroupName"></span>
+ <button id="gearSettingsConfigureGearsButton"
+ i18n-content="gearSettingsConfigureGearsButton"></button>
+ </label>
+ </div>
+</if>
+ </div>
</section>
<section>
<h3 i18n-content="advancedSectionTitleSecurity"></h3>
- <table class="option-control-table">
- <tr><td>
- <div class="section_text"
- i18n-content="certificatesLabel"></div>
- <button id="certificatesManageButton"
- i18n-content="certificatesManageButton"></button>
- </td></tr>
- <if expr="os == 'win32'">
- <!-- Configure these options for manual handling on windows -->
- <tr id="sslCheckRevocationCheckbox">
- <td class="option-name"><label><input id="sslCheckRevocation"
- type="checkbox"><span i18n-content="sslCheckRevocation"></span>
- </label></td>
- </tr>
- <tr id="sslUseSSL2Checkbox">
- <td class="option-name"><label><input id="sslUseSSL2"
- type="checkbox"><span i18n-content="sslUseSSL2"></span>
- </label></td>
- </tr>
- </if>
- <if expr="os == 'linux2' or os.find('bsd') != -1">
- <!-- Configure these options for Linux/BSD as preference keys -->
- <tr id="sslCheckRevocationCheckbox">
- <td class="option-name"><label><input id="sslCheckRevocation"
- pref="ssl.rev_checking.enabled" type="checkbox"><span
- i18n-content="sslCheckRevocation"></span></label></td>
- </tr>
- <tr id="sslUseSSL2Checkbox">
- <td class="option-name"><label><input id="sslUseSSL2"
- pref="ssl.ssl2.enabled" type="checkbox"><span
- i18n-content="sslUseSSL2"></span></label></td>
- </tr>
- <tr id="sslUseSSL3Checkbox">
- <td class="option-name"><label><input id="sslUseSSL3"
- pref="ssl.ssl3.enabled" type="checkbox"><span
- i18n-content="sslUseSSL3"></span></label></td>
- </tr>
- <tr id="sslUseTLS1Checkbox">
- <td class="option-name"><label><input id="sslUseTLS1"
- pref="ssl.tls1.enabled" type="checkbox"><span
- i18n-content="sslUseTLS1"></span></label></td>
- </tr>
- </if>
- </table>
+ <div>
+ <div i18n-content="certificatesLabel"></div>
+ <div><button id="certificatesManageButton"
+ i18n-content="certificatesManageButton"></button></div>
+<if expr="os == 'win32'">
+ <!-- Configure these options for manual handling on windows -->
+ <label><input id="sslCheckRevocation"
+ type="checkbox"><span i18n-content="sslCheckRevocation"></span>
+ </label>
+ <label><input id="sslUseSSL2"
+ type="checkbox"><span i18n-content="sslUseSSL2"></span>
+ </label>
+</if>
+<if expr="not pp_ifdef('chromeos') and (os == 'linux2' or os.find('bsd') != -1)">
+ <!-- Configure these options for Linux/BSD as preference keys -->
+ <label><input id="sslCheckRevocation"
+ pref="ssl.rev_checking.enabled" metric="Options_CheckCertRevocation"
+ type="checkbox"><span i18n-content="sslCheckRevocation"></span>
+ </label>
+ <label><input id="sslUseSSL2"
+ pref="ssl.ssl2.enabled" metric="Options_SSL2" type="checkbox"><span
+ i18n-content="sslUseSSL2"></span></label>
+ <label><input id="sslUseSSL3"
+ pref="ssl.ssl3.enabled" metric="Options_SSL3" type="checkbox"><span
+ i18n-content="sslUseSSL3"></span></label>
+ <label><input id="sslUseTLS1"
+ pref="ssl.tls1.enabled" metric="Options_TLS1" type="checkbox"><span
+ i18n-content="sslUseTLS1"></span></label>
+</if>
+ </div>
</section>
+<if expr="not pp_ifdef('chromeos')">
+ <section id="background-mode-section">
+ <h3 i18n-content="advancedSectionTitleChromeApps"></h3>
+ <div>
+ <label class="multi-line-wrap">
+ <input pref="background_mode.enabled"
+ metric="Options_BackgroundMode" type="checkbox">
+ <span i18n-content="chromeAppsEnableBackgroundMode"></span>
+ </label>
+ <div>
+ <a target="_blank"
+ i18n-content="chromeAppsLearnMoreBackgroundModeLabel"
+ i18n-values="href:chromeAppsLearnMoreBackgroundModeURL"></a>
+ </div>
+ </div>
+ </section>
+ <div class="button-strip">
+ <button id="optionsReset" i18n-content="optionsReset"></button>
+ </div>
+</if>
</div>
diff --git a/chrome/browser/resources/options/advanced_options.js b/chrome/browser/resources/options/advanced_options.js
index 0f2a3c4..dabb324 100644
--- a/chrome/browser/resources/options/advanced_options.js
+++ b/chrome/browser/resources/options/advanced_options.js
@@ -2,88 +2,169 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-//
-// AdvancedOptions class
-// Encapsulated handling of advanced options page.
-//
-function AdvancedOptions() {
- OptionsPage.call(this, 'advanced', templateData.advancedPage, 'advancedPage');
-}
-
-cr.addSingletonGetter(AdvancedOptions);
-
-AdvancedOptions.prototype = {
- // Inherit AdvancedOptions from OptionsPage.
- __proto__: OptionsPage.prototype,
-
- // Initialize AdvancedOptions page.
- initializePage: function() {
- // Call base class implementation to starts preference initialization.
- OptionsPage.prototype.initializePage.call(this);
-
- // Setup click handlers for buttons.
- $('privacyContentSettingsButton').onclick = function(event) {
- OptionsPage.showPageByName('content');
- };
- $('privacyClearDataButton').onclick = function(event) {
- OptionsPage.showOverlay('clearBrowserDataOverlay');
- };
- $('proxiesConfigureButton').onclick = function(event) {
- chrome.send('showNetworkProxySettings');
- };
- $('downloadLocationBrowseButton').onclick = function(event) {
- chrome.send('selectDownloadLocation');
- };
- $('autoOpenFileTypesResetToDefault').onclick = function(event) {
- chrome.send('autoOpenFileTypesAction');
- };
- $('fontSettingsConfigureFontsOnlyButton').onclick = function(event) {
- OptionsPage.showOverlay('fontSettingsOverlay');
- };
- $('certificatesManageButton').onclick = function(event) {
- chrome.send('showManageSSLCertificates');
- };
-
- if (cr.isWindows) {
- $('sslCheckRevocation').onclick = function(event) {
- chrome.send('checkRevocationCheckboxAction',
- [String($('sslCheckRevocation').checked)]);
+cr.define('options', function() {
+
+var OptionsPage = options.OptionsPage;
+
+ //
+ // AdvancedOptions class
+ // Encapsulated handling of advanced options page.
+ //
+ function AdvancedOptions() {
+ OptionsPage.call(this, 'advanced', templateData.advancedPage,
+ 'advancedPage');
+ }
+
+ cr.addSingletonGetter(AdvancedOptions);
+
+ AdvancedOptions.prototype = {
+ // Inherit AdvancedOptions from OptionsPage.
+ __proto__: options.OptionsPage.prototype,
+
+ /**
+ * Initializes the page.
+ */
+ initializePage: function() {
+ // Call base class implementation to starts preference initialization.
+ OptionsPage.prototype.initializePage.call(this);
+
+ // Setup click handlers for buttons.
+ $('privacyContentSettingsButton').onclick = function(event) {
+ OptionsPage.showPageByName('content');
+ OptionsPage.showTab($('cookies-nav-tab'));
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_ContentSettings']);
+ };
+ $('privacyClearDataButton').onclick = function(event) {
+ OptionsPage.showOverlay('clearBrowserDataOverlay');
+ chrome.send('coreOptionsUserMetricsAction', ['Options_ClearData']);
+ };
+ // 'metricsReportingEnabled' element is only present on Chrome branded
+ // builds.
+ if ($('metricsReportingEnabled')) {
+ $('metricsReportingEnabled').onclick = function(event) {
+ chrome.send('metricsReportingCheckboxAction',
+ [String(event.target.checked)]);
+ };
+ }
+ $('autoOpenFileTypesResetToDefault').onclick = function(event) {
+ chrome.send('autoOpenFileTypesAction');
};
- $('sslUseSSL2').onclick = function(event) {
- chrome.send('useSSL2CheckboxAction',
- [String($('sslUseSSL2').checked)]);
+ $('fontSettingsConfigureFontsOnlyButton').onclick = function(event) {
+ OptionsPage.showPageByName('fontSettings');
+ chrome.send('coreOptionsUserMetricsAction', ['Options_FontSettings']);
};
+ if (cr.isWindows || cr.isMac) {
+ $('certificatesManageButton').onclick = function(event) {
+ chrome.send('showManageSSLCertificates');
+ };
+ } else {
+ $('certificatesManageButton').onclick = function(event) {
+ OptionsPage.showPageByName('certificateManager');
+ OptionsPage.showTab($('personal-certs-nav-tab'));
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_ManageSSLCertificates']);
+ };
+ }
+ if (!cr.isChromeOS) {
+ $('optionsReset').onclick = function(event) {
+ AlertOverlay.show(undefined,
+ localStrings.getString('optionsResetMessage'),
+ localStrings.getString('optionsResetOkLabel'),
+ localStrings.getString('optionsResetCancelLabel'),
+ function() { chrome.send('resetToDefaults'); });
+ }
+ $('proxiesConfigureButton').onclick = function(event) {
+ chrome.send('showNetworkProxySettings');
+ };
+ $('downloadLocationBrowseButton').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 =
+ localStrings.getStringWithoutAccelerator(
+ 'downloadLocationBrowseButton');
+ } else {
+ $('proxiesConfigureButton').onclick = function(event) {
+ OptionsPage.showPageByName('proxy');
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_ShowProxySettings']);
+ };
+ }
+
+ if (cr.isWindows) {
+ $('sslCheckRevocation').onclick = function(event) {
+ chrome.send('checkRevocationCheckboxAction',
+ [String($('sslCheckRevocation').checked)]);
+ };
+ $('sslUseSSL2').onclick = function(event) {
+ chrome.send('useSSL2CheckboxAction',
+ [String($('sslUseSSL2').checked)]);
+ };
+ $('gearSettingsConfigureGearsButton').onclick = function(event) {
+ chrome.send('showGearsSettings');
+ };
+ }
+ },
+
+ /**
+ * Show a 'restart required' alert.
+ * @private
+ */
+ showRestartRequiredAlert_: function() {
+ AlertOverlay.show(undefined,
+ localStrings.getString('optionsRestartRequired'),
+ undefined, '', undefined);
}
+ };
+
+ //
+ // Chrome callbacks
+ //
+
+ // Set the checked state of the metrics reporting checkbox.
+ AdvancedOptions.SetMetricsReportingCheckboxState = function(checked,
+ disabled, user_changed) {
+ $('metricsReportingEnabled').checked = checked;
+ $('metricsReportingEnabled').disabled = disabled;
- // 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 =
- localStrings.getStringWithoutAccelerator(
- 'downloadLocationBrowseButton');
+ if (user_changed)
+ AdvancedOptions.getInstance().showRestartRequiredAlert_();
}
-};
-
-//
-// Chrome callbacks
-//
-
-// Set the download path.
-function advancedOptionsSetDownloadLocationPath(path) {
- $('downloadLocationPath').value = path;
-}
-
-// Set the enabled state for the autoOpenFileTypesResetToDefault button.
-function advancedOptionsSetAutoOpenFileTypesDisabledAttribute(disabled) {
- $('autoOpenFileTypesResetToDefault').disabled = disabled;
-}
-
-// Set the checked state for the sslCheckRevocation checkbox.
-function advancedOptionsSetCheckRevocationCheckboxState(checked) {
- $('sslCheckRevocation').checked = checked;
-}
-
-// Set the checked state for the sslUseSSL2 checkbox.
-function advancedOptionsSetUseSSL2CheckboxState(checked) {
- $('sslUseSSL2').checked = checked;
-}
+
+ // Set the download path.
+ AdvancedOptions.SetDownloadLocationPath = function(path) {
+ if (!cr.isChromeOS)
+ $('downloadLocationPath').value = path;
+ };
+
+ // Set the enabled state for the autoOpenFileTypesResetToDefault button.
+ AdvancedOptions.SetAutoOpenFileTypesDisabledAttribute = function(disabled) {
+ $('autoOpenFileTypesResetToDefault').disabled = disabled;
+ };
+
+ // Set the enabled state for the proxy settings button.
+ AdvancedOptions.SetupProxySettingsSection = function(disabled, label) {
+ $('proxiesConfigureButton').disabled = disabled;
+ $('proxiesLabel').textContent = label;
+ };
+
+ // Set the checked state for the sslCheckRevocation checkbox.
+ AdvancedOptions.SetCheckRevocationCheckboxState = function(checked) {
+ $('sslCheckRevocation').checked = checked;
+ };
+
+ // Set the checked state for the sslUseSSL2 checkbox.
+ AdvancedOptions.SetUseSSL2CheckboxState = function(checked) {
+ $('sslUseSSL2').checked = checked;
+ };
+
+ // Export
+ return {
+ AdvancedOptions: AdvancedOptions
+ };
+
+});
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 6d115d2..16262d2 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -4,61 +4,75 @@
<h3 i18n-content="startupGroupName"></h3>
<div>
<label><input type="radio" name="startup"
- pref="session.restore_on_startup" value="0"><span
- i18n-content="startupShowDefaultAndNewTab"></span></label><br>
+ pref="session.restore_on_startup" value="0"
+ metric="Options_Startup_Homepage">
+ <span i18n-content="startupShowDefaultAndNewTab"></span></label>
<label><input type="radio" name="startup"
- pref="session.restore_on_startup" value="1"><span
- i18n-content="startupShowLastSession"></span></label><br>
- <label><input type="radio" name="startup"
- pref="session.restore_on_startup" value="4"><span
- i18n-content="startupShowPages"></span></label>
+ pref="session.restore_on_startup" value="1"
+ metric="Options_Startup_LastSession">
+ <span i18n-content="startupShowLastSession"></span></label>
+ <label><input type="radio" name="startup" id="startupShowPagesButton"
+ pref="session.restore_on_startup" value="4"
+ metric="Options_Startup_Custom">
+ <span i18n-content="startupShowPages"></span></label>
<div class="suboption">
- <select id="startupPages" size="3">
- </select><br>
- <button id="startupAddButton" disabled
- i18n-content="startupAddButton"></button>
- <button id="startupRemoveButton" disabled
- i18n-content="startupRemoveButton"></button>
- <button id="startupUseCurrentButton" disabled
- i18n-content="startupUseCurrent"></button>
+ <div class="left-side-table">
+ <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>
+ </div>
+ </div>
</div>
</div>
</section>
<section>
<h3 i18n-content="homepageGroupName"></h3>
<div>
- <label><input type="radio" name="homepage" pref="homepage_is_newtabpage"
- value="true"><span
- i18n-content="homepageUseNewTab"></span></label><br>
- <label><input type="radio" name="homepage" pref="homepage_is_newtabpage"
- value="false"><span
- i18n-content="homepageUseURL"></span></label><br>
+ <label><input type="radio" name="homepage"
+ pref="homepage_is_newtabpage" value="true"
+ metric="Options_Homepage_IsNewTabPage">
+ <span i18n-content="homepageUseNewTab"></span></label>
+ <label><input type="radio" name="homepage" id="homepageUseURLButton"
+ pref="homepage_is_newtabpage" value="false"
+ metric="Options_Homepage_IsNewTabPage">
+ <span i18n-content="homepageUseURL"></span></label>
<div class="suboption">
<input id="homepageURL" type="url" pref="homepage">
</div>
<div class="option">
<label><input id="homepageShowButton"
- pref="browser.show_home_button" type="checkbox"><span
- i18n-content="homepageShowButton"></span></label>
+ pref="browser.show_home_button"
+ metric="Options_Homepage_HomeButton" type="checkbox">
+ <span i18n-content="homepageShowButton"></span></label>
</div>
</div>
</section>
<section>
<h3 i18n-content="defaultSearchGroupName"></h3>
- <div>
+ <div id="defaultSearchEngineGroup">
<select id="defaultSearchEngine"
- onchange="BrowserOptions.getInstance().setDefaultBrowser()">
+ onchange="BrowserOptions.getInstance().setDefaultSearchEngine()">
</select>
- <button id="defaultSearchManageEnginesButton" disabled
+ <button id="defaultSearchManageEnginesButton"
i18n-content="defaultSearchManageEnginesLink"></button>
</div>
</section>
+<if expr="not pp_ifdef('chromeos')">
<section>
<h3 i18n-content="defaultBrowserGroupName"></h3>
<div>
- <p id="defaultBrowserState" i18n-content="defaultBrowserUnknown"></p>
+ <div id="defaultBrowserState"
+ i18n-content="defaultBrowserUnknown"></div>
<button id="defaultBrowserUseAsDefaultButton"
i18n-content="defaultBrowserUseAsDefault"></button>
</div>
</section>
+</if>
</div>
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 82b8b40..bdac565 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -2,116 +2,235 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-//
-// BrowserOptions class
-// Encapsulated handling of browser options page.
-//
-function BrowserOptions() {
- OptionsPage.call(this, 'browser', templateData.browserPage, 'browserPage');
-}
-
-cr.addSingletonGetter(BrowserOptions);
-
-BrowserOptions.prototype = {
- // Inherit BrowserOptions from OptionsPage.
- __proto__: OptionsPage.prototype,
-
- /**
- * Initialize BrowserOptions page.
- */
- initializePage: function() {
- // Call base class implementation to start preference initialization.
- OptionsPage.prototype.initializePage.call(this);
-
- // Wire up buttons.
- $('startupAddButton').onclick = function(event) {
- // TODO(stuartmorgan): Spawn add sub-dialog.
- };
- $('startupRemoveButton').onclick = function(event) {
- // TODO(stuartmorgan): Remove selected element(s).
- };
- $('startupUseCurrentButton').onclick = function(event) {
- // TODO(stuartmorgan): Add all open tabs (except this one).
- };
- $('defaultSearchManageEnginesButton').onclick = function(event) {
- // TODO(stuartmorgan): Spawn search engine management sub-dialog.
- };
- $('defaultBrowserUseAsDefaultButton').onclick = function(event) {
- chrome.send('becomeDefaultBrowser');
- };
-
- // 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');
- },
-
- /**
- * Update the Default Browsers section based on the current state.
- * @param {String} statusString Description of the current default state.
- * @param {Boolean} isDefault Whether or not the browser is currently default.
- */
- updateDefaultBrowserState_: function(statusString, isDefault) {
- var label = $('defaultBrowserState');
- label.textContent = statusString;
- if (isDefault) {
- label.classList.add('current');
- } else {
- label.classList.remove('current');
- }
+cr.define('options', function() {
+ const OptionsPage = options.OptionsPage;
+ const ArrayDataModel = cr.ui.ArrayDataModel;
+ const ListSelectionModel = cr.ui.ListSelectionModel;
- $('defaultBrowserUseAsDefaultButton').disabled = isDefault;
- },
-
- /**
- * Clears the search engine popup.
- * @private
- */
- clearSearchEngines_: function() {
- $('defaultSearchEngine').textContent = '';
- },
-
- /**
- * Updates the search engine popup with the given entries.
- * @param {Array} engines List of available search engines.
- * @param {Integer} defaultValue The value of the current default engine.
- */
- updateSearchEngines_: function(engines, defaultValue) {
- this.clearSearchEngines_();
- engineSelect = $('defaultSearchEngine');
- engineCount = engines.length
- var defaultIndex = -1;
- for (var i = 0; i < engineCount; i++) {
- var engine = engines[i]
- var option = new Option(engine['name'], engine['index']);
- if (defaultValue == option.value)
- defaultIndex = i;
- engineSelect.appendChild(option);
- }
- if (defaultIndex >= 0)
- engineSelect.selectedIndex = defaultIndex;
- },
-
- /**
- * Set the default search engine based on the popup selection.
- */
- setDefaultBrowser: function() {
- var engineSelect = $('defaultSearchEngine');
- var selectedIndex = engineSelect.selectedIndex;
- if (selectedIndex >= 0) {
- var selection = engineSelect.options[selectedIndex];
- chrome.send('setDefaultSearchEngine', [String(selection.value)]);
+ //
+ // BrowserOptions class
+ // Encapsulated handling of browser options page.
+ //
+ function BrowserOptions() {
+ OptionsPage.call(this, 'browser', templateData.browserPage, 'browserPage');
+ }
+
+ cr.addSingletonGetter(BrowserOptions);
+
+ BrowserOptions.prototype = {
+ // Inherit BrowserOptions from OptionsPage.
+ __proto__: options.OptionsPage.prototype,
+
+ /**
+ * Initialize BrowserOptions page.
+ */
+ initializePage: function() {
+ // Call base class implementation to start preference initialization.
+ 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');
+ };
+ $('defaultSearchManageEnginesButton').onclick = function(event) {
+ OptionsPage.showPageByName('searchEngines');
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_ManageSearchEngines']);
+ };
+ if (!cr.isChromeOS) {
+ $('defaultBrowserUseAsDefaultButton').onclick = function(event) {
+ chrome.send('becomeDefaultBrowser');
+ };
+ }
+
+ var list = $('startupPages');
+ options.browser_options.StartupPageList.decorate(list);
+ list.selectionModel = new ListSelectionModel;
+
+ list.selectionModel.addEventListener(
+ 'change', this.updateRemoveButtonState_.bind(this));
+
+ this.addEventListener('visibleChange', function(event) {
+ $('startupPages').redraw();
+ });
+
+ // Initialize control enabled states.
+ Preferences.getInstance().addEventListener('session.restore_on_startup',
+ this.updateCustomStartupPageControlStates_.bind(this));
+ Preferences.getInstance().addEventListener('homepage_is_newtabpage',
+ this.updateHomepageFieldState_.bind(this));
+ this.updateCustomStartupPageControlStates_();
+ this.updateHomepageFieldState_();
+
+ // 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');
+ },
+
+ /**
+ * Update the Default Browsers section based on the current state.
+ * @private
+ * @param {string} statusString Description of the current default state.
+ * @param {boolean} isDefault Whether or not the browser is currently
+ * default.
+ */
+ updateDefaultBrowserState_: function(statusString, isDefault) {
+ var label = $('defaultBrowserState');
+ label.textContent = statusString;
+ if (isDefault) {
+ label.classList.add('current');
+ } else {
+ label.classList.remove('current');
+ }
+
+ $('defaultBrowserUseAsDefaultButton').disabled = isDefault;
+ },
+
+ /**
+ * Clears the search engine popup.
+ * @private
+ */
+ clearSearchEngines_: function() {
+ $('defaultSearchEngine').textContent = '';
+ },
+
+ /**
+ * Updates the search engine popup with the given entries.
+ * @param {Array} engines List of available search engines.
+ * @param {Integer} defaultValue The value of the current default engine.
+ */
+ updateSearchEngines_: function(engines, defaultValue) {
+ this.clearSearchEngines_();
+ engineSelect = $('defaultSearchEngine');
+ engineCount = engines.length;
+ var defaultIndex = -1;
+ for (var i = 0; i < engineCount; i++) {
+ var engine = engines[i];
+ var option = new Option(engine['name'], engine['index']);
+ if (defaultValue == option.value)
+ defaultIndex = i;
+ engineSelect.appendChild(option);
+ }
+ if (defaultIndex >= 0)
+ engineSelect.selectedIndex = defaultIndex;
+ },
+
+ /**
+ * Returns true if the custom startup page control block should
+ * be enabled.
+ * @private
+ * @returns {boolean} Whether the startup page controls should be
+ * enabled.
+ */
+ shouldEnableCustomStartupPageControls_: function(pages) {
+ return $('startupShowPagesButton').checked;
+ },
+
+ /**
+ * Updates the startup pages list with the given entries.
+ * @private
+ * @param {Array} pages List of startup pages.
+ */
+ updateStartupPages_: function(pages) {
+ $('startupPages').dataModel = new ArrayDataModel(pages);
+ this.updateRemoveButtonState_();
+ },
+
+ /**
+ * Sets the enabled state of the custom startup page list controls
+ * based on the current startup radio button selection.
+ * @private
+ */
+ updateCustomStartupPageControlStates_: function() {
+ var disable = !this.shouldEnableCustomStartupPageControls_();
+ $('startupAddButton').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)]);
+ },
+
+ /**
+ * Sets the enabled state of the homepage field based on the current
+ * homepage radio button selection.
+ * @private
+ */
+ updateHomepageFieldState_: function() {
+ $('homepageURL').disabled = !$('homepageUseURLButton').checked;
+ },
+
+ /**
+ * Set the default search engine based on the popup selection.
+ */
+ setDefaultSearchEngine: function() {
+ var engineSelect = $('defaultSearchEngine');
+ var selectedIndex = engineSelect.selectedIndex;
+ if (selectedIndex >= 0) {
+ var selection = engineSelect.options[selectedIndex];
+ chrome.send('setDefaultSearchEngine', [String(selection.value)]);
+ }
+ },
+ };
+
+ BrowserOptions.updateDefaultBrowserState = function(statusString, isDefault) {
+ if (!cr.isChromeOS) {
+ BrowserOptions.getInstance().updateDefaultBrowserState_(statusString,
+ isDefault);
}
- },
-};
+ };
+
+ BrowserOptions.updateSearchEngines = function(engines, defaultValue) {
+ BrowserOptions.getInstance().updateSearchEngines_(engines, defaultValue);
+ };
+
+ BrowserOptions.updateStartupPages = function(pages) {
+ BrowserOptions.getInstance().updateStartupPages_(pages);
+ };
+
+ BrowserOptions.addStartupPage = function(url) {
+ BrowserOptions.getInstance().addStartupPage_(url);
+ };
+
+ // Export
+ return {
+ BrowserOptions: BrowserOptions
+ };
-BrowserOptions.updateDefaultBrowserState = function(statusString, isDefault) {
- BrowserOptions.getInstance().updateDefaultBrowserState_(statusString,
- isDefault);
-}
+});
-BrowserOptions.updateSearchEngines = function(engines, defaultValue) {
- BrowserOptions.getInstance().updateSearchEngines_(engines, defaultValue);
-}
diff --git a/chrome/browser/resources/options/browser_options_page.css b/chrome/browser/resources/options/browser_options_page.css
index b3d5a39..b2c1f27 100644
--- a/chrome/browser/resources/options/browser_options_page.css
+++ b/chrome/browser/resources/options/browser_options_page.css
@@ -1,7 +1,26 @@
-#startupPages, #homepageURL {
+#startupPages {
+ border: solid 1px #999999;
+ height: 100px;
+}
+
+#homepageURL {
width: 100%;
}
+#defaultSearchEngineGroup {
+ display: -webkit-box;
+}
+
+#defaultSearchEngine {
+ display: block;
+ -webkit-box-flex: 1;
+}
+
+#defaultSearchManageEnginesButton {
+ margin-top: 0px;
+ -webkit-margin-start: 10px;
+}
+
#defaultBrowserState {
color: #880000;
}
diff --git a/chrome/browser/resources/options/chromeos_accounts_add_user_overlay.html b/chrome/browser/resources/options/chromeos_accounts_add_user_overlay.html
deleted file mode 100644
index ca80d2c..0000000
--- a/chrome/browser/resources/options/chromeos_accounts_add_user_overlay.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<div class="page hidden" id="addUserOverlayPage">
- <table>
- <tr><td>
- <label><span i18n-content="add_user_email"></span>
- <input type=text id=userEmailEdit>
- </label>
- </td></tr>
- <tr><td>
- <button id="addUserOkButton"
- i18n-content="ok_label"></button>
- <button id="addUserCancelButton"
- i18n-content="cancel_label"></button>
- </td></tr>
- </table>
-</div>
diff --git a/chrome/browser/resources/options/chromeos_accounts_add_user_overlay.js b/chrome/browser/resources/options/chromeos_accounts_add_user_overlay.js
deleted file mode 100644
index 056959b..0000000
--- a/chrome/browser/resources/options/chromeos_accounts_add_user_overlay.js
+++ /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.
-
-///////////////////////////////////////////////////////////////////////////////
-// AddUserOverlay class:
-
-/**
- * Encapsulated handling of ChromeOS accounts add user overlay page.
- * @constructor
- */
-function AddUserOverlay(model) {
- OptionsPage.call(this, 'addUserOverlay', localStrings.getString('add_user'),
- 'addUserOverlayPage');
-}
-
-AddUserOverlay.getInstance = function() {
- if (!AddUserOverlay.instance_) {
- AddUserOverlay.instance_ = new AddUserOverlay(null);
- }
- return AddUserOverlay.instance_;
-};
-
-AddUserOverlay.prototype = {
- // Inherit AddUserOverlay from OptionsPage.
- __proto__: OptionsPage.prototype,
-
- /**
- * Initializes AddUserOverlay page.
- * Calls base class implementation to starts preference initialization.
- */
- initializePage: function() {
- // Call base class implementation to starts preference initialization.
- OptionsPage.prototype.initializePage.call(this);
-
- // Set up the page.
- $('addUserOkButton').onclick = function(e) {
- var newUserEmail = $('userEmailEdit').value;
- if (newUserEmail)
- userList.addUser({'email': newUserEmail});
-
- OptionsPage.clearOverlays();
- };
-
- $('addUserCancelButton').onclick = function(e) {
- OptionsPage.clearOverlays();
- };
-
- this.addEventListener('visibleChange',
- cr.bind(this.handleVisibleChange_, this));
- },
-
- /**
- * Handler for OptionsPage's visible property change event.
- * @param {Event} e Property change event.
- */
- handleVisibleChange_: function() {
- $('userEmailEdit').focus();
- }
-};
diff --git a/chrome/browser/resources/options/chromeos_accounts_options.html b/chrome/browser/resources/options/chromeos_accounts_options.html
index 1369cd5..1439259 100644
--- a/chrome/browser/resources/options/chromeos_accounts_options.html
+++ b/chrome/browser/resources/options/chromeos_accounts_options.html
@@ -2,6 +2,21 @@
<h1 i18n-content="accountsPage"></h1>
<div class="option">
<table class="option-control-table">
+ <tr><td>
+ <table class="user-list-table">
+ <tr><td>
+ <list id="userList"></list>
+ </td></tr>
+ <tr><td class="user-name-edit-row">
+ <label><span i18n-content="add_users"></span><br>
+ <input id="userNameEdit" type="text"
+ i18n-values="placeholder:username_edit_hint">
+ </span>
+ </label>
+ </td></tr>
+ </table>
+ </td></tr>
+ <tr><td>&nbsp;</td></tr>
<tr>
<td class="option-name"><label><input id="allowBwsiCheck"
pref="cros.accounts.allowBWSI" type="checkbox"><span
@@ -13,17 +28,10 @@
i18n-content="allow_guest"></span></label></td>
</tr>
<tr>
- <td class="option-name" i18n-content="user_list_title"></td>
+ <td class="option-name"><label><input id="showUserNamesCheck"
+ pref="cros.accounts.showUserNamesOnSignIn" type="checkbox"><span
+ i18n-content="show_user_on_signin"></span></label></td>
</tr>
- <tr><td class="option-name">
- <list id="userList"></list>
- </td></tr>
- <tr><td class="option-name">
- <button id="addUserButton"
- i18n-content="add_user"></button>
- <button id="removeUserButton" disabled
- i18n-content="remove_user"></button>
- </td></tr>
</table>
</div>
</div>
diff --git a/chrome/browser/resources/options/chromeos_accounts_options.js b/chrome/browser/resources/options/chromeos_accounts_options.js
index 8339669..72e63e1 100644
--- a/chrome/browser/resources/options/chromeos_accounts_options.js
+++ b/chrome/browser/resources/options/chromeos_accounts_options.js
@@ -2,63 +2,83 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-///////////////////////////////////////////////////////////////////////////////
-// AccountsOptions class:
-
-/**
- * Encapsulated handling of ChromeOS accounts options page.
- * @constructor
- */
-function AccountsOptions(model) {
- OptionsPage.call(this, 'accounts', localStrings.getString('accountsPage'),
- 'accountsPage');
-}
-
-AccountsOptions.getInstance = function() {
- if (!AccountsOptions.instance_) {
- AccountsOptions.instance_ = new AccountsOptions(null);
- }
- return AccountsOptions.instance_;
-};
+cr.define('options', function() {
+
+ var OptionsPage = options.OptionsPage;
-AccountsOptions.prototype = {
- // Inherit AccountsOptions from OptionsPage.
- __proto__: OptionsPage.prototype,
+ /////////////////////////////////////////////////////////////////////////////
+ // AccountsOptions class:
/**
- * Initializes AccountsOptions page.
+ * Encapsulated handling of ChromeOS accounts options page.
+ * @constructor
*/
- initializePage: function() {
- // Call base class implementation to starts preference initialization.
- OptionsPage.prototype.initializePage.call(this);
+ function AccountsOptions(model) {
+ OptionsPage.call(this, 'accounts', localStrings.getString('accountsPage'),
+ 'accountsPage');
+ }
+
+ cr.addSingletonGetter(AccountsOptions);
+
+ AccountsOptions.prototype = {
+ // Inherit AccountsOptions from OptionsPage.
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * Initializes AccountsOptions page.
+ */
+ initializePage: function() {
+ // Call base class implementation to starts preference initialization.
+ OptionsPage.prototype.initializePage.call(this);
+
+ // Set up accounts page.
+ var userList = $('userList');
+ options.accounts.UserList.decorate(userList);
- // Set up accounts page.
- $('addUserButton').onclick = function(e) {
- OptionsPage.showOverlay('addUserOverlay');
- };
- $('removeUserButton').onclick = function(e) {
- $('userList').removeSelectedUser();
- };
+ var userNameEdit = $('userNameEdit');
+ options.accounts.UserNameEdit.decorate(userNameEdit);
+ userNameEdit.addEventListener('add', this.handleAddUser_);
- options.accounts.UserList.decorate($('userList'));
+ userList.disabled =
+ userNameEdit.disabled = !AccountsOptions.currentUserIsOwner();
- this.addEventListener('visibleChange',
- cr.bind(this.handleVisibleChange_, this));
+ this.addEventListener('visibleChange', this.handleVisibleChange_);
+ },
- // Setup add user overlay page.
- OptionsPage.registerOverlay(AddUserOverlay.getInstance());
- },
+ userListInitalized_: false,
- userListInitalized_: false,
+ /**
+ * Handler for OptionsPage's visible property change event.
+ * @private
+ * @param {Event} e Property change event.
+ */
+ handleVisibleChange_: function(e) {
+ if (!this.userListInitalized_ && this.visible) {
+ this.userListInitalized_ = true;
+ $('userList').redraw();
+ }
+ },
+
+ /**
+ * Handler for "add" event fired from userNameEdit.
+ * @private
+ * @param {Event} e Add event fired from userNameEdit.
+ */
+ handleAddUser_: function(e) {
+ $('userList').addUser(e.user);
+ }
+ };
/**
- * Handler for OptionsPage's visible property change event.
- * @param {Event} e Property change event.
+ * Returns whether the current user is owner or not.
*/
- handleVisibleChange_ : function(e) {
- if (!this.userListInitalized_ && this.visible) {
- this.userListInitalized_ = true;
- userList.redraw();
- }
- }
-};
+ AccountsOptions.currentUserIsOwner = function() {
+ return localStrings.getString('current_user_is_owner') == 'true';
+ };
+
+ // Export
+ return {
+ AccountsOptions: AccountsOptions
+ };
+
+});
diff --git a/chrome/browser/resources/options/chromeos_accounts_options_page.css b/chrome/browser/resources/options/chromeos_accounts_options_page.css
index 739e254..f92132f 100644
--- a/chrome/browser/resources/options/chromeos_accounts_options_page.css
+++ b/chrome/browser/resources/options/chromeos_accounts_options_page.css
@@ -1,6 +1,83 @@
-#userList {
+.user-list-table {
+ border: 1px solid lightgrey;
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+.user-name-edit-row {
border: 1px solid lightgrey;
+ background-color: #ebeffa;
+ padding: 5px;
+}
+
+.user-list-item {
+ line-height: 35px;
padding: 2px;
- width: 160px;
- height: 120px;
+}
+
+.user-icon {
+ border: 1px solid black;
+ width: 26px;
+ height: 26px;
+ vertical-align: middle;
+}
+
+.user-email-label {
+ -webkit-margin-start: 10px;
+}
+
+.user-name-label {
+ color: darkgray;
+ -webkit-margin-start: 10px;
+}
+
+.remove-user-button {
+ background-image: url(chrome://theme/IDR_CLOSE_BAR);
+ background-color: transparent;
+ border: 0;
+ width: 16px;
+ height: 16px;
+ margin-top: 8px;
+}
+
+html[dir=ltr] .remove-user-button {
+ float: right;
+}
+
+html[dir=rtl] .remove-user-button {
+ float: left;
+}
+
+.remove-user-button:hover {
+ background-image: url(chrome://theme/IDR_CLOSE_BAR_H);
+}
+
+#userList {
+ padding: 5px;
+ width: 366px;
+ height: 166px;
+}
+
+#userList[disabled],
+#userList[disabled] > [selected],
+#userList[disabled] > :hover {
+ border-color: hsl(0, 0%, 85%);
+}
+
+#userList[disabled] > [selected],
+#userList[disabled] > :hover {
+ background-color: hsl(0,0%,90%);
+}
+
+#userList[disabled] .remove-user-button {
+ visibility: hidden;
+}
+
+#userNameEdit {
+ border: 1px solid lightgrey;
+ width: 366px;
+}
+
+input#userNameEdit:invalid {
+ background-color: #ff6666;
}
diff --git a/chrome/browser/resources/options/chromeos_accounts_user_list.js b/chrome/browser/resources/options/chromeos_accounts_user_list.js
index 2f654cc..449a035 100644
--- a/chrome/browser/resources/options/chromeos_accounts_user_list.js
+++ b/chrome/browser/resources/options/chromeos_accounts_user_list.js
@@ -25,26 +25,40 @@ cr.define('options.accounts', function() {
List.prototype.decorate.call(this);
// HACK(arv): http://crbug.com/40902
- window.addEventListener('resize', cr.bind(this.redraw, this));
+ window.addEventListener('resize', this.redraw.bind(this));
+
+ this.addEventListener('click', this.handleClick_);
var self = this;
- if (!this.boundHandleChange_) {
- this.boundHandleChange_ =
- cr.bind(this.handleChange_, this);
- }
// Listens to pref changes.
Preferences.getInstance().addEventListener(this.pref,
function(event) {
self.load_(event.value);
});
-
- // Listens to list selection change.
- this.addEventListener('change', this.boundHandleChange_);
},
createItem: function(user) {
- return new ListItem({label: user.email});
+ return new UserListItem(user);
+ },
+
+ /**
+ * Finds the index of user by given email.
+ * @private
+ * @param {string} email The email address to look for.
+ * @return {number} The index of the found user or -1 if not found.
+ */
+ findUserByEmail_: function(email) {
+ var dataModel = this.dataModel;
+ var length = dataModel.length;
+ for (var i = 0; i < length; ++i) {
+ var user = dataModel.item(i);
+ if (user.email == email) {
+ return i;
+ }
+ }
+
+ return -1;
},
/**
@@ -52,28 +66,40 @@ cr.define('options.accounts', function() {
* @param {Object} user A user to be added to user list.
*/
addUser: function(user) {
- var dataModel = this.dataModel;
- dataModel.splice(dataModel.length, 0, user);
-
- this.updateBackend_();
+ var index = this.findUserByEmail_(user.email);
+ if (index == -1) {
+ this.dataModel.push(user);
+ chrome.send('whitelistUser', [user.email]);
+ }
},
/**
- * Removes currently selected user from model and update backend.
+ * Removes given user from model and update backend.
*/
- removeSelectedUser: function() {
- var sm = this.selectionModel;
+ removeUser: function(user) {
var dataModel = this.dataModel;
- var newUsers = [];
- for (var i = 0; i < dataModel.length; ++i) {
- if (!sm.getIndexSelected(i)) {
- newUsers.push(dataModel.item(i));
- }
+ var index = dataModel.indexOf(user);
+ if (index >= 0) {
+ dataModel.splice(index, 1);
+ chrome.send('unwhitelistUser', [user.email]);
}
- this.load_(newUsers);
+ },
- this.updateBackend_();
+ /**
+ * Handles the clicks on the list and triggers user removal if the click
+ * is on the remove user button.
+ * @private
+ * @param {!Event} e The click event object.
+ */
+ handleClick_: function(e) {
+ // Handle left button click
+ if (e.button == 0) {
+ var el = e.target;
+ if (el.className == 'remove-user-button') {
+ this.removeUser(el.parentNode.user);
+ }
+ }
},
/**
@@ -82,20 +108,70 @@ cr.define('options.accounts', function() {
*/
load_: function(users) {
this.dataModel = new ArrayDataModel(users);
- },
+ }
+ };
- /**
- * Updates backend.
- */
- updateBackend_: function() {
- Preferences.setObjectPref(this.pref, this.dataModel.slice());
- },
+ /**
+ * Whether the user list is disabled. Only used for display purpose.
+ * @type {boolean}
+ */
+ cr.defineProperty(UserList, 'disabled', cr.PropertyKind.BOOL_ATTR);
- /**
- * Handles selection change.
- */
- handleChange_: function(e) {
- $('removeUserButton').disabled = this.selectionModel.selectedIndex == -1;
+ /**
+ * Creates a new user list item.
+ * @param user The user account this represents.
+ * @constructor
+ * @extends {cr.ui.ListItem}
+ */
+ function UserListItem(user) {
+ var el = cr.doc.createElement('div');
+ el.user = user;
+ UserListItem.decorate(el);
+ return el;
+ }
+
+ /**
+ * Decorates an element as a user account item.
+ * @param {!HTMLElement} el The element to decorate.
+ */
+ UserListItem.decorate = function(el) {
+ el.__proto__ = UserListItem.prototype;
+ el.decorate();
+ };
+
+ UserListItem.prototype = {
+ __proto__: ListItem.prototype,
+
+ /** @inheritDoc */
+ decorate: function() {
+ ListItem.prototype.decorate.call(this);
+
+ this.className = 'user-list-item';
+
+ var icon = this.ownerDocument.createElement('img');
+ icon.className = 'user-icon';
+ // TODO(xiyuan): Replace this with real user picture when ready.
+ icon.src = 'chrome://theme/IDR_LOGIN_DEFAULT_USER';
+
+ var labelEmail = this.ownerDocument.createElement('span');
+ labelEmail.className = 'user-email-label';
+ labelEmail.textContent = this.user.email;
+
+ var labelName = this.ownerDocument.createElement('span');
+ labelName.className = 'user-name-label';
+ labelName.textContent = this.user.owner ?
+ localStrings.getStringF('username_format', this.user.name) :
+ this.user.name;
+
+ this.appendChild(icon);
+ this.appendChild(labelEmail);
+ this.appendChild(labelName);
+
+ if (!this.user.owner) {
+ var removeButton = this.ownerDocument.createElement('button');
+ removeButton.className = 'remove-user-button';
+ this.appendChild(removeButton);
+ }
}
};
diff --git a/chrome/browser/resources/options/chromeos_labs.html b/chrome/browser/resources/options/chromeos_labs.html
index cce03b4..9288a92 100644
--- a/chrome/browser/resources/options/chromeos_labs.html
+++ b/chrome/browser/resources/options/chromeos_labs.html
@@ -24,4 +24,17 @@
</table>
</div>
</section>
+ <section>
+ <h3 i18n-content="talk_title"></h3>
+ <div class="option">
+ <table class="option-control-table">
+ <tr>
+ <td class="option-name"><label><input id="talk-check"
+ pref="extensions.settings.ggnioahjipcehijkhpdjekioddnjoben.state"
+ type="checkbox" value-type="number"><span
+ i18n-content="talk"></span></label></td>
+ </tr>
+ </table>
+ </div>
+ </section>
</div>
diff --git a/chrome/browser/resources/options/chromeos_language_hangul_options.html b/chrome/browser/resources/options/chromeos_language_hangul_options.html
index f6506b5..140e40f 100644
--- a/chrome/browser/resources/options/chromeos_language_hangul_options.html
+++ b/chrome/browser/resources/options/chromeos_language_hangul_options.html
@@ -1,12 +1,14 @@
<div class="page hidden" id="languageHangulPage">
+ <h1 i18n-content="languageHangulPage"></h1>
<section>
<div class="option">
<table class="option-control-table">
<tr>
- <td class="option-name" i18n-content="keyboard_layout"></td>
+ <td class="option-name" i18n-content="hangul_keyboard_layout"></td>
<td class="option-value">
<select id="keyboard-layout-select" class="control"
- pref="settings.language.hangul_keyboard"></select>
+ pref="settings.language.hangul_keyboard"
+ data-values="HangulkeyboardLayoutList"></select>
</td>
</tr>
</table>
diff --git a/chrome/browser/resources/options/chromeos_language_hangul_options.js b/chrome/browser/resources/options/chromeos_language_hangul_options.js
deleted file mode 100644
index df2331c..0000000
--- a/chrome/browser/resources/options/chromeos_language_hangul_options.js
+++ /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.
-
-///////////////////////////////////////////////////////////////////////////////
-// LanguageHangulOptions class:
-
-/**
- * Encapsulated handling of ChromeOS language Hangul options page.
- * @constructor
- */
-function LanguageHangulOptions() {
- OptionsPage.call(this, 'languageHangul', templateData.languageHangulPage,
- 'languageHangulPage');
-}
-
-cr.addSingletonGetter(LanguageHangulOptions);
-
-// Inherit LanguageHangulOptions from OptionsPage.
-LanguageHangulOptions.prototype = {
- __proto__: OptionsPage.prototype,
-
- /**
- * Initializes LanguageHangulOptions page.
- * Calls base class implementation to starts preference initialization.
- */
- initializePage: function() {
- OptionsPage.prototype.initializePage.call(this);
- var keyboardLayout = $('keyboard-layout-select');
- keyboardLayout.initializeValues(templateData.keyboardLayoutList)
- }
-};
diff --git a/chrome/browser/resources/options/chromeos_language_options.css b/chrome/browser/resources/options/chromeos_language_options.css
index 24b543d..53dfdca 100644
--- a/chrome/browser/resources/options/chromeos_language_options.css
+++ b/chrome/browser/resources/options/chromeos_language_options.css
@@ -20,13 +20,18 @@
.language-options-contents {
-webkit-padding-start: 12px;
+ -webkit-padding-end: 12px;
padding-bottom: 10px;
}
+.language-options-header, .language-options-footer {
+ margin: 15px;
+}
+
.language-options-left, .language-options-right {
border: 1px solid #cccccc;
vertical-align: top;
- padding: 0px;
+ padding: 0;
height: 400px;
}
@@ -46,14 +51,30 @@
.language-options-right {
/* To share the center line with the left pane. */
-webkit-margin-start: -1px;
- min-width: 300px;
+ width: 360px;
+}
+
+.language-options-notification {
+ display: none;
+ background-color: #fff29e;
+ border-top: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ padding: 12px 30px 12px 12px;
+}
+
+#language-options-input-method-list button {
+ display: block;
+ -webkit-margin-start: 20px;
+}
+
+#language-options-input-method-list label {
+ margin: 4px 0;
}
#language-options-list {
-webkit-box-flex: 1;
- padding: 0px;
+ padding: 0;
width: 100%;
- display: block;
}
#language-options-list li {
@@ -61,3 +82,87 @@
padding-top: 2px;
padding-bottom: 2px;
}
+
+#language-options-ui-restart-button {
+ margin-top: 12px;
+}
+
+#add-language-overlay-language-list {
+ -webkit-column-count: 2;
+ -webkit-column-gap: 20px;
+}
+
+#add-language-overlay-cancel-button {
+ /* Place the button in the center. */
+ display: block;
+ margin: auto;
+ margin-top: 15px;
+}
+
+#add-language-overlay-page {
+ width: 800px;
+}
+
+#add-language-overlay-page button {
+ padding: 0;
+ text-align: left;
+}
+
+#add-language-overlay-page ul {
+ padding: 0;
+ margin: 0;
+}
+/* TODO(kochi): This is temporary copy from new_new_tab.css */
+/* Notification */
+
+#notification {
+ position: relative;
+ background-color: hsl(52, 100%, 80%);
+ border: 1px solid rgb(211, 211, 211);
+ border-radius: 6px;
+ padding: 7px 15px;
+ white-space: nowrap;
+ display: table;
+ /* Set the height and margin so that the element does not use any vertical
+ space */
+ height: 16px;
+ margin: -44px auto 12px auto;
+ font-weight: bold;
+ opacity: 0;
+ pointer-events: none;
+ -webkit-transition: opacity .15s;
+ z-index: 1;
+ color: black;
+}
+
+#notification > * {
+ display: table-cell;
+ max-width: 500px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+#notification.show {
+ opacity: 1;
+ pointer-events: all;
+ -webkit-transition: opacity 1s;
+}
+
+#notification .link {
+ cursor: pointer;
+ text-decoration: underline;
+ -webkit-appearance: none;
+ border: 0;
+ background: none;
+ color: rgba(0, 102, 204, 0.3);
+ -webkit-padding-start: 20px;
+}
+
+#notification .link-color {
+ color: rgb(0, 102, 204);
+}
+
+#chewing-max-chi-symbol-len {
+ width: 100px;
+ height: 30%;
+}
diff --git a/chrome/browser/resources/options/chromeos_language_options.html b/chrome/browser/resources/options/chromeos_language_options.html
index 7d8ef82..844b05d 100644
--- a/chrome/browser/resources/options/chromeos_language_options.html
+++ b/chrome/browser/resources/options/chromeos_language_options.html
@@ -2,36 +2,44 @@
<div class="page hidden" id="languagePage">
<h1 i18n-content="languagePage"></h1>
+ <div id="notification">
+ <span>&nbsp;</span>
+ <span class="link"><span class="link-color"></span></span>
+ </div>
+ <div class="language-options-header">
+ <div i18n-content="add_language_instructions"></div>
+ <div i18n-content="input_method_instructions"></div>
+ </div>
<div class="language-options">
<div class="language-options-left">
<h3 i18n-content="languages"></h3>
- <list id="language-options-list">
- <!-- TODO: The contents should be dynamically changed. -->
- <li>English (United States)</li>
- <li>Spanish</li>
- <li>French</li>
- <li>Japanese</li>
- </list>
+ <list id="language-options-list"></list>
<div class="language-options-lower-left">
- <button id="add-button" i18n-content="add_button"></button>
- <button id="remove-button" i18n-content="remove_button"></button>
+ <button id="language-options-add-button"
+ i18n-content="add_button"></button>
+ <button id="language-options-remove-button"
+ i18n-content="remove_button"></button>
</div>
</div>
<div class="language-options-right">
- <!-- TODO: The contents should be dynamically changed. -->
- <h3>English (United States)</h3>
+ <h3 id="language-options-language-name"></h3>
<div class="language-options-contents">
- <button id="ui-language-button"
- i18n-content="display_in_this_language"></button>
+ <button id="language-options-ui-language-button"></button>
+ </div>
+ <div id="language-options-ui-notification-bar"
+ class="language-options-notification">
+ <div i18n-content="restart_required"></div>
+ <button id="language-options-ui-restart-button"
+ i18n-content="restart_button"></button>
</div>
<h3 i18n-content="input_method"></h3>
- <div class="language-options-contents">
- <!-- TODO: The contents should be dynamically changed. -->
- <label><input type="checkbox">US English</label>
- <label><input type="checkbox">Dvorak</label>
- <label><input type="checkbox">Dvorak - Left</label>
- <label><input type="checkbox">Dvorak - Right</label>
+ <div id="language-options-input-method-list"
+ class="language-options-contents">
</div>
</div>
</div>
+ <div class="language-options-footer">
+ <div i18n-content="switch_input_methods_hint"></div>
+ <div i18n-content="select_previous_input_method_hint"></div>
+ </div>
</div>
diff --git a/chrome/browser/resources/options/chromeos_system_options.html b/chrome/browser/resources/options/chromeos_system_options.html
index 88b3956..a8fe151 100644
--- a/chrome/browser/resources/options/chromeos_system_options.html
+++ b/chrome/browser/resources/options/chromeos_system_options.html
@@ -1,20 +1,25 @@
<div class="page hidden" id="systemPage">
<h1 i18n-content="systemPage"></h1>
<section>
+ <h3 i18n-content="datetime_title"></h3>
+ <table class="option-control-table">
+ <tr>
+ <td class="option-name" i18n-content="timezone"></td>
+ <td class="option-value">
+ <select id="timezone-select" class="control"
+ pref="cros.system.timezone"></select>
+ </td>
+ </tr>
+ </table>
+ </section>
+ <section>
<h3 i18n-content="touchpad"></h3>
<table class="option-control-table">
<tr>
<td class="option-name" i18n-content="sensitivity"></td>
<td class="option-value">
- <input id="sensitivity-range" type="range" min="1" max="10"
- pref="settings.touchpad.sensitivity" class="touch-slider">
- </td>
- </tr>
- <tr>
- <td class="option-name" i18n-content="speed_factor"></td>
- <td class="option-value">
- <input id="speed-range" type="range" min="1" max="10"
- pref="settings.touchpad.speed_factor" class="touch-slider">
+ <input id="sensitivity-range" type="range" min="1" max="5"
+ pref="settings.touchpad.sensitivity2" class="touch-slider">
</td>
</tr>
<tr>
@@ -23,13 +28,6 @@
pref="settings.touchpad.enable_tap_to_click"
type="checkbox"><span i18n-content="enable_tap_to_click"></span></label></td>
</tr>
- <tr>
- <td class="option-name" colspan="2"><label><input
- id="vert-scroll-check"
- pref="settings.touchpad.enable_vert_edge_scroll"
- type="checkbox"><span
- i18n-content="enable_vert_edge_scroll"></span></label></td>
- </tr>
</table>
</section>
<section>
@@ -39,6 +37,9 @@
<td class="option-name"><button id="language-button"
i18n-content="language_customize"></button>
</td>
+ <td class="option-name"><button id="modifier-keys-button"
+ i18n-content="modifier_keys_customize"></button>
+ </td>
</tr>
</table>
</section>
diff --git a/chrome/browser/resources/options/chromeos_system_options.js b/chrome/browser/resources/options/chromeos_system_options.js
index cfabc86..cef3507 100644
--- a/chrome/browser/resources/options/chromeos_system_options.js
+++ b/chrome/browser/resources/options/chromeos_system_options.js
@@ -2,36 +2,50 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-///////////////////////////////////////////////////////////////////////////////
-// SystemOptions class:
+cr.define('options', function() {
-/**
- * Encapsulated handling of ChromeOS system options page.
- * @constructor
- */
-function SystemOptions() {
- OptionsPage.call(this, 'system', templateData.systemPage, 'systemPage');
-}
-
-cr.addSingletonGetter(SystemOptions);
-
-// Inherit SystemOptions from OptionsPage.
-SystemOptions.prototype = {
- __proto__: OptionsPage.prototype,
+ var OptionsPage = options.OptionsPage;
+ /////////////////////////////////////////////////////////////////////////////
+ // SystemOptions class:
/**
- * Initializes SystemOptions page.
- * Calls base class implementation to starts preference initialization.
+ * Encapsulated handling of ChromeOS system options page.
+ * @constructor
*/
- initializePage: function() {
- OptionsPage.prototype.initializePage.call(this);
- var timezone = $('timezone-select');
- if (timezone) {
- timezone.initializeValues(templateData.timezoneList);
- }
- $('language-button').onclick = function(event) {
- OptionsPage.showPageByName('language');
- };
+ function SystemOptions() {
+ OptionsPage.call(this, 'system', templateData.systemPage, 'systemPage');
}
-};
+
+ cr.addSingletonGetter(SystemOptions);
+
+ // Inherit SystemOptions from OptionsPage.
+ SystemOptions.prototype = {
+ __proto__: options.OptionsPage.prototype,
+
+ /**
+ * Initializes SystemOptions page.
+ * Calls base class implementation to starts preference initialization.
+ */
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+ var timezone = $('timezone-select');
+ if (timezone) {
+ timezone.initializeValues(templateData.timezoneList);
+ }
+
+ $('language-button').onclick = function(event) {
+ OptionsPage.showPageByName('language');
+ };
+ $('modifier-keys-button').onclick = function(event) {
+ OptionsPage.showOverlay('languageCustomizeModifierKeysOverlay');
+ };
+ }
+ };
+
+ // Export
+ return {
+ SystemOptions: SystemOptions
+ };
+
+});
diff --git a/chrome/browser/resources/options/clear_browser_data_overlay.html b/chrome/browser/resources/options/clear_browser_data_overlay.html
index f9a92b1..a6ae60f 100644
--- a/chrome/browser/resources/options/clear_browser_data_overlay.html
+++ b/chrome/browser/resources/options/clear_browser_data_overlay.html
@@ -1,3 +1,64 @@
<div class="page hidden" id="clearBrowserDataOverlay">
<h1 i18n-content="clearBrowsingDataTitle"></h1>
+ <h3 i18n-content="clearBrowsingDataLabel"></h3>
+ <div id="checkboxListData">
+ <div>
+ <input id="deleteBrowsingHistoryCheckbox"
+ pref="browser.clear_data.browsing_history" type="checkbox">
+ <label for="deleteBrowsingHistoryCheckbox"
+ i18n-content="deleteBrowsingHistoryCheckbox"></label>
+ </div>
+ <div>
+ <input id="deleteDownloadHistoryCheckbox"
+ pref="browser.clear_data.download_history" type="checkbox">
+ <label for="deleteDownloadHistoryCheckbox"
+ i18n-content="deleteDownloadHistoryCheckbox"></label>
+ </div>
+ <div>
+ <input id="deleteCacheCheckbox"
+ pref="browser.clear_data.cache" type="checkbox">
+ <label for="deleteCacheCheckbox"
+ i18n-content="deleteCacheCheckbox"></label>
+ </div>
+ <div>
+ <input id="deleteCookiesCheckbox"
+ pref="browser.clear_data.cookies" type="checkbox">
+ <label for="deleteCookiesCheckbox"
+ i18n-content="deleteCookiesCheckbox"></label>
+ </div>
+ <div>
+ <input id="deletePasswordsCheckbox"
+ pref="browser.clear_data.passwords" type="checkbox">
+ <label for="deletePasswordsCheckbox"
+ i18n-content="deletePasswordsCheckbox"></label>
+ </div>
+ <div>
+ <input id="deleteFormDataCheckbox"
+ pref="browser.clear_data.form_data" type="checkbox">
+ <label for="deleteFormDataCheckbox"
+ i18n-content="deleteFormDataCheckbox"></label>
+ </div>
+ </div>
+ <div>
+ <label for="" i18n-content="clearBrowsingDataTimeLabel"></label>
+ <select id="clearBrowsingDataTimePeriod"
+ pref="browser.clear_data.time_period"></select>
+ </div>
+ <div class="button-strip">
+ <span id="cbdThrobber"></span>
+ <if expr="os == 'win32'">
+ <button id="clearBrowsingDataCommit"
+ i18n-content="clearBrowsingDataCommit"></button>
+ </if>
+ <button id="clearBrowsingDataDismiss" i18n-content="cancel"
+ onclick="ClearBrowserDataOverlay.dismiss();">
+ </button>
+ <if expr="os != 'win32'">
+ <button id="clearBrowsingDataCommit"
+ i18n-content="clearBrowsingDataCommit"></button>
+ </if>
+ </div>
+ <hr>
+ <a target="_blank" i18n-content="flash_storage_settings"
+ i18n-values="href:flash_storage_url"></a>
</div>
diff --git a/chrome/browser/resources/options/clear_browser_data_overlay.js b/chrome/browser/resources/options/clear_browser_data_overlay.js
index f93a12c..501e462 100644
--- a/chrome/browser/resources/options/clear_browser_data_overlay.js
+++ b/chrome/browser/resources/options/clear_browser_data_overlay.js
@@ -2,30 +2,122 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * ClearBrowserData class
- * Encapsulated handling of the 'Clear Browser Data' overlay page.
- * @class
- */
-function ClearBrowserDataOverlay() {
- OptionsPage.call(this, 'clearBrowserDataOverlay',
- templateData.clearBrowserDataTitle,
- 'clearBrowserDataOverlay');
-}
-
-cr.addSingletonGetter(ClearBrowserDataOverlay);
-
-ClearBrowserDataOverlay.prototype = {
- // Inherit ClearBrowserDataOverlay from OptionsPage.
- __proto__: OptionsPage.prototype,
+cr.define('options', function() {
+
+ var OptionsPage = options.OptionsPage;
/**
- * Initialize the page.
+ * ClearBrowserData class
+ * Encapsulated handling of the 'Clear Browser Data' overlay page.
+ * @class
*/
- initializePage: function() {
- // Call base class implementation to starts preference initialization.
- OptionsPage.prototype.initializePage.call(this);
+ function ClearBrowserDataOverlay() {
+ OptionsPage.call(this, 'clearBrowserDataOverlay',
+ templateData.clearBrowserDataTitle,
+ 'clearBrowserDataOverlay');
+ }
+
+ ClearBrowserDataOverlay.throbIntervalId = 0;
+
+ cr.addSingletonGetter(ClearBrowserDataOverlay);
+
+ ClearBrowserDataOverlay.prototype = {
+ // Inherit ClearBrowserDataOverlay from OptionsPage.
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * Initialize the page.
+ */
+ initializePage: function() {
+ // Call base class implementation to starts preference initialization.
+ OptionsPage.prototype.initializePage.call(this);
+
+ // Setup option values for the time period select control.
+ $('clearBrowsingDataTimePeriod').initializeValues(
+ templateData.clearBrowsingDataTimeList);
+
+ var f = this.updateCommitButtonState_.bind(this);
+ var types = ['browser.clear_data.browsing_history',
+ 'browser.clear_data.download_history',
+ 'browser.clear_data.cache',
+ 'browser.clear_data.cookies',
+ 'browser.clear_data.passwords',
+ 'browser.clear_data.form_data'];
+ types.forEach(function(type) {
+ Preferences.getInstance().addEventListener(type, f);
+ });
+
+ var checkboxes = document.querySelectorAll(
+ '#checkboxListData input[type=checkbox]');
+ for (var i = 0; i < checkboxes.length; i++) {
+ checkboxes[i].onclick = f;
+ }
+ this.updateCommitButtonState_();
- // TODO(csilv): add any initialization here or delete method and/or class.
+ // Setup click handler for the clear(Ok) button.
+ $('clearBrowsingDataCommit').onclick = function(event) {
+ chrome.send('performClearBrowserData');
+ };
+ },
+
+ // Set the enabled state of the commit button.
+ updateCommitButtonState_: function() {
+ var checkboxes = document.querySelectorAll(
+ '#checkboxListData input[type=checkbox]');
+ var isChecked = false;
+ for (var i = 0; i < checkboxes.length; i++) {
+ if (checkboxes[i].checked) {
+ isChecked = true;
+ break;
+ }
+ }
+ $('clearBrowsingDataCommit').disabled = !isChecked;
+ },
+ };
+
+ //
+ // Chrome callbacks
+ //
+ ClearBrowserDataOverlay.setClearingState = function(state) {
+ $('deleteBrowsingHistoryCheckbox').disabled = state;
+ $('deleteDownloadHistoryCheckbox').disabled = state;
+ $('deleteCacheCheckbox').disabled = state;
+ $('deleteCookiesCheckbox').disabled = state;
+ $('deletePasswordsCheckbox').disabled = state;
+ $('deleteFormDataCheckbox').disabled = state;
+ $('clearBrowsingDataTimePeriod').disabled = state;
+ $('clearBrowsingDataDismiss').disabled = state;
+ $('cbdThrobber').style.visibility = state ? 'visible' : 'hidden';
+
+ if (state)
+ $('clearBrowsingDataCommit').disabled = true;
+ else
+ ClearBrowserDataOverlay.getInstance().updateCommitButtonState_();
+
+ function advanceThrobber() {
+ var throbber = $('cbdThrobber');
+ // TODO(csilv): make this smoother using time-based animation?
+ throbber.style.backgroundPositionX =
+ ((parseInt(getComputedStyle(throbber).backgroundPositionX, 10) - 16) %
+ 576) + 'px';
+ }
+ if (state) {
+ ClearBrowserDataOverlay.throbIntervalId =
+ setInterval(advanceThrobber, 30);
+ } else {
+ clearInterval(ClearBrowserDataOverlay.throbIntervalId);
+ }
}
-};
+
+ ClearBrowserDataOverlay.dismiss = function() {
+ OptionsPage.clearOverlays();
+ this.setClearingState(false);
+ }
+
+ // Export
+ return {
+ ClearBrowserDataOverlay: ClearBrowserDataOverlay
+ };
+
+});
+
diff --git a/chrome/browser/resources/options/content_settings.html b/chrome/browser/resources/options/content_settings.html
index 2e667cb..5f4673a 100644
--- a/chrome/browser/resources/options/content_settings.html
+++ b/chrome/browser/resources/options/content_settings.html
@@ -6,53 +6,57 @@
</h1>
<!-- Navigation tabs -->
- <div id="content-settings-nav-tabs">
+ <div class="subpages-nav-tabs">
<span i18n-content="cookies_tab_label" id="cookies-nav-tab"
- class="inactive-tab" tab-contents="cookiesFilterTab"></span>
- <span i18n-content="images_tab_label" id="images-nav-tab"
- class="inactive-tab" tab-contents="imagesFilterTab"></span>
- <span i18n-content="javascript_tab_label" id="javascript-nav-tab"
- class="inactive-tab" tab-contents="javascriptFilterTab"></span>
- <span i18n-content="plugins_tab_label" id="plugins-nav-tab"
- class="inactive-tab" tab-contents="pluginsFilterTab"></span>
- <span i18n-content="popups_tab_label" id="popups-nav-tab"
- class="inactive-tab" tab-contents="popupsFilterTab"></span>
- <span i18n-content="location_tab_label" id="location-nav-tab"
- class="inactive-tab" tab-contents="locationFilterTab"></span>
- <span i18n-content="notifications_tab_label" id="notifications-nav-tab"
+ class="inactive-tab" tab-contents="cookiesFilterTab"></span><span
+ i18n-content="images_tab_label" id="images-nav-tab"
+ class="inactive-tab" tab-contents="imagesFilterTab"></span><span
+ i18n-content="javascript_tab_label" id="javascript-nav-tab"
+ class="inactive-tab" tab-contents="javascriptFilterTab"></span><span
+ i18n-content="plugins_tab_label" id="plugins-nav-tab"
+ class="inactive-tab" tab-contents="pluginsFilterTab"></span><span
+ i18n-content="popups_tab_label" id="popups-nav-tab"
+ class="inactive-tab" tab-contents="popupsFilterTab"></span><span
+ i18n-content="location_tab_label" id="location-nav-tab"
+ class="inactive-tab" tab-contents="locationFilterTab"></span><span
+ i18n-content="notifications_tab_label" id="notifications-nav-tab"
class="inactive-tab" tab-contents="notificationsFilterTab"></span>
</div>
<br>
<!-- Cookie filter tab contents -->
- <div id="cookiesFilterTab" class="content-settings-tab-contents">
- <span i18n-content="cookies_modify"></span>
+ <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>
- <input type="radio" name="cookies" value="allow">
- <span i18n-content="cookies_allow"></span>
- </label></td>
- </tr>
- <tr>
- <td class="option-name"><label>
- <input type="radio" name="cookies" value="block">
- <span i18n-content="cookies_block"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="cookies" value="allow">
+ <span i18n-content="cookies_allow"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><button id="cookies-exceptions-button"
- i18n-content="content_exceptions"></button>
- </td>
+ <td class="option-name"><label>
+ <input type="radio" name="cookies" value="block">
+ <span i18n-content="cookies_block"></span>
+ </label></td>
</tr>
</table>
+ <div class="exceptionsLink" i18n-content="content_exceptions"></div>
+ <div contentType="cookies" mode="normal">
+ <list></list>
+ </div>
+ <div contentType="cookies" mode="otr">
+ <span i18n-content="otr_exceptions_explanation"></span>
+ <list></list>
+ </div>
+
<table class="option-control-table">
<tr>
- <td class="option-name"><label>
- <input id="block-third-party-cookies" type="checkbox">
- <span i18n-content="cookies_block_3rd_party"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input id="block-third-party-cookies" type="checkbox">
+ <span i18n-content="cookies_block_3rd_party"></span>
+ </label></td>
</tr>
<tr>
<td class="option-name"><label>
@@ -62,98 +66,113 @@
</label></td>
</tr>
<tr>
- <td class="option-name"><button id="show-cookies-button"
- i18n-content="cookies_show_cookies"></button>
- </td>
+ <td class="option-name"><button id="show-cookies-button"
+ i18n-content="cookies_show_cookies"></button>
+ </td>
</tr>
<tr>
- <td><a i18n-values="href:flash_storage_url">
- <span i18n-content="flash_storage_settings"></span></a>
- </td>
+ <td><a i18n-values="href:flash_storage_url"
+ i18n-content="flash_storage_settings"></a>
+ </td>
</tr>
</table>
</div>
<!-- Image filter tab contents -->
- <div id="imagesFilterTab" class="content-settings-tab-contents">
- <span i18n-content="images_setting"></span>
+ <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>
- <input type="radio" name="images" value="allow">
- <span i18n-content="images_allow"></span>
- </label></td>
- </tr>
- <tr>
- <td class="option-name"><label>
- <input type="radio" name="images" value="block">
- <span i18n-content="images_block"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="images" value="allow">
+ <span i18n-content="images_allow"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><button id="images-exceptions-button"
- i18n-content="content_exceptions"></button>
- </td>
+ <td class="option-name"><label>
+ <input type="radio" name="images" value="block">
+ <span i18n-content="images_block"></span>
+ </label></td>
</tr>
</table>
+
+ <div class="exceptionsLink" i18n-content="content_exceptions"></div>
+ <div contentType="images" mode="normal">
+ <list></list>
+ </div>
+ <div contentType="images" mode="otr">
+ <span i18n-content="otr_exceptions_explanation"></span>
+ <list></list>
+ </div>
</div>
<!-- JavaScript filter tab contents -->
- <div id="javascriptFilterTab" class="content-settings-tab-contents">
- <span i18n-content="javascript_setting"></span>
+ <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>
- <input type="radio" name="javascript" value="allow">
- <span i18n-content="javascript_allow"></span>
- </label></td>
- </tr>
- <tr>
- <td class="option-name"><label>
- <input type="radio" name="javascript" value="block">
- <span i18n-content="javascript_block"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="javascript" value="allow">
+ <span i18n-content="javascript_allow"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><button id="javascript-exceptions-button"
- i18n-content="content_exceptions"></button>
- </td>
+ <td class="option-name"><label>
+ <input type="radio" name="javascript" value="block">
+ <span i18n-content="javascript_block"></span>
+ </label></td>
</tr>
</table>
+
+ <div class="exceptionsLink" i18n-content="content_exceptions"></div>
+ <div contentType="javascript" mode="normal">
+ <list></list>
+ </div>
+ <div contentType="javascript" mode="otr">
+ <span i18n-content="otr_exceptions_explanation"></span>
+ <list></list>
+ </div>
</div>
<!-- Plug-ins filter tab contents -->
- <div id="pluginsFilterTab" class="content-settings-tab-contents">
- <span i18n-content="plugins_setting"></span>
+ <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>
- <input type="radio" name="plugins" value="allow">
- <span i18n-content="plugins_allow"></span>
- </label></td>
- </tr>
- <tr>
- <td class="option-name"><label>
- <input type="radio" name="plugins" value="block">
- <span i18n-content="plugins_block"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="plugins" value="allow">
+ <span i18n-content="plugins_allow"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><button id="plugins-exceptions-button"
- i18n-content="content_exceptions"></button>
- </td>
+ <td class="option-name"><label>
+ <input type="radio" name="plugins" value="ask">
+ <span i18n-content="plugins_allow_sandboxed"></span>
+ </label></td>
</tr>
<tr>
- <td><a i18n-values="href:chrome_plugin_url">
- <span i18n-content="disable_individual_plugins"></span></a>
- </td>
+ <td class="option-name"><label>
+ <input type="radio" name="plugins" value="block">
+ <span i18n-content="plugins_block"></span>
+ </label></td>
</tr>
</table>
+
+ <div class="exceptionsLink" i18n-content="content_exceptions"></div>
+ <div contentType="plugins" mode="normal">
+ <list></list>
+ </div>
+ <div contentType="plugins" mode="otr">
+ <span i18n-content="otr_exceptions_explanation"></span>
+ <list></list>
+ </div>
+ <a i18n-values="href:chrome_plugin_url"
+ i18n-content="disable_individual_plugins"></a>
</div>
<!-- Pop-ups filter tab contents -->
- <div id="popupsFilterTab" class="content-settings-tab-contents">
- <span i18n-content="popups_setting"></span>
+ <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>
@@ -167,71 +186,75 @@
<span i18n-content="popups_block"></span>
</label></td>
</tr>
- <tr>
- <td class="option-name"><button id="popups-exceptions-button"
- i18n-content="content_exceptions"></button>
- </td>
- </tr>
</table>
+
+ <div class="exceptionsLink" i18n-content="content_exceptions"></div>
+ <div contentType="popups" mode="normal">
+ <list></list>
+ </div>
+ <div contentType="popups" mode="otr">
+ <span i18n-content="otr_exceptions_explanation"></span>
+ <list></list>
+ </div>
</div>
<!-- Location filter tab contents -->
- <div id="locationFilterTab" class="content-settings-tab-contents">
- <span i18n-content="location_setting"></span>
+ <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>
- <input type="radio" name="location" value="allow">
- <span i18n-content="location_allow"></span>
- </label></td>
- </tr>
- <tr>
- <td class="option-name"><label>
- <input type="radio" name="location" value="ask">
- <span i18n-content="location_ask"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="location" value="allow">
+ <span i18n-content="location_allow"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><label>
- <input type="radio" name="location" value="block">
- <span i18n-content="location_block"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="location" value="ask">
+ <span i18n-content="location_ask"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><button id="location-exceptions-button"
- i18n-content="content_exceptions"></button>
- </td>
+ <td class="option-name"><label>
+ <input type="radio" name="location" value="block">
+ <span i18n-content="location_block"></span>
+ </label></td>
</tr>
</table>
+
+ <div class="exceptionsLink" i18n-content="content_exceptions"></div>
+ <div contentType="location" mode="normal">
+ <list></list>
+ </div>
</div>
<!-- Notifications filter tab contents -->
- <div id="notificationsFilterTab" class="content-settings-tab-contents">
- <span i18n-content="notifications_setting"></span>
+ <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>
- <input type="radio" name="noticiations" value="allow">
- <span i18n-content="notifications_allow"></span>
- </label></td>
- </tr>
- <tr>
- <td class="option-name"><label>
- <input type="radio" name="notifications" value="ask">
- <span i18n-content="notifications_ask"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="notifications" value="allow">
+ <span i18n-content="notifications_allow"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><label>
- <input type="radio" name="notifications" value="block">
- <span i18n-content="notifications_block"></span>
- </label></td>
+ <td class="option-name"><label>
+ <input type="radio" name="notifications" value="ask">
+ <span i18n-content="notifications_ask"></span>
+ </label></td>
</tr>
<tr>
- <td class="option-name"><button id="notifications-exceptions-button"
- i18n-content="content_exceptions"></button>
- </td>
+ <td class="option-name"><label>
+ <input type="radio" name="notifications" value="block">
+ <span i18n-content="notifications_block"></span>
+ </label></td>
</tr>
</table>
+
+ <div class="exceptionsLink" i18n-content="content_exceptions"></div>
+ <div contentType="notifications" mode="normal">
+ <list></list>
+ </div>
</div>
</div>
diff --git a/chrome/browser/resources/options/content_settings.js b/chrome/browser/resources/options/content_settings.js
index c17a84e..35676c9 100644
--- a/chrome/browser/resources/options/content_settings.js
+++ b/chrome/browser/resources/options/content_settings.js
@@ -2,91 +2,152 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-///////////////////////////////////////////////////////////////////////////////
-// ContentSettings class:
-
-/**
- * Encapsulated handling of content settings page.
- * @constructor
- */
-function ContentSettings() {
- this.activeNavTab = null;
- OptionsPage.call(this, 'content', templateData.contentSettingsPage,
- 'contentSettingsPage');
-}
-
-cr.addSingletonGetter(ContentSettings);
-
-ContentSettings.prototype = {
- __proto__: OptionsPage.prototype,
-
- initializePage: function() {
- OptionsPage.prototype.initializePage.call(this);
-
- chrome.send('getContentFilterSettings');
- this.showTab($('cookies-nav-tab'));
-
- var self = this;
- $('content-settings-nav-tabs').onclick = function(event) {
- self.showTab(event.srcElement);
- };
-
- // Cookies filter page -----------------------------------------------------
- $('cookies-exceptions-button').onclick = function(event) {
- // TODO(estade): show exceptions page.
- };
-
- $('block-third-party-cookies').onclick = function(event) {
- chrome.send('setAllowThirdPartyCookies',
- [String($('block-third-party-cookies').checked)]);
- };
-
- $('show-cookies-button').onclick = function(event) {
- // TODO(estade): show cookies and other site data page.
- };
-
- // Images filter page ------------------------------------------------------
- $('images-exceptions-button').onclick = function(event) {
- // TODO(estade): show a dialog.
- };
- },
+cr.define('options', function() {
+
+ var OptionsPage = options.OptionsPage;
+
+ //////////////////////////////////////////////////////////////////////////////
+ // ContentSettings class:
+
+ /**
+ * Encapsulated handling of content settings page.
+ * @constructor
+ */
+ function ContentSettings() {
+ this.activeNavTab = null;
+ OptionsPage.call(this, 'content', templateData.contentSettingsPage,
+ 'contentSettingsPage');
+ }
+
+ cr.addSingletonGetter(ContentSettings);
+
+ ContentSettings.prototype = {
+ __proto__: OptionsPage.prototype,
+
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+
+ chrome.send('getContentFilterSettings');
+
+ // Exceptions lists. -----------------------------------------------------
+ function handleExceptionsLinkClickEvent(event) {
+ var exceptionsArea = event.target.parentNode.
+ querySelector('div[contentType][mode=normal]');
+ exceptionsArea.classList.toggle('hidden');
+ exceptionsArea.querySelector('list').redraw();
+
+ var otrExceptionsArea = event.target.parentNode.
+ querySelector('div[contentType][mode=otr]');
+ if (otrExceptionsArea && otrExceptionsArea.otrProfileExists) {
+ otrExceptionsArea.classList.toggle('hidden');
+ otrExceptionsArea.querySelector('list').redraw();
+ }
+
+ return false;
+ }
+ var exceptionsLinks =
+ this.pageDiv.querySelectorAll('.exceptionsLink');
+ for (var i = 0; i < exceptionsLinks.length; i++) {
+ exceptionsLinks[i].onclick = handleExceptionsLinkClickEvent;
+ }
+
+ var exceptionsAreas = this.pageDiv.querySelectorAll('div[contentType]');
+ for (var i = 0; i < exceptionsAreas.length; i++) {
+ options.contentSettings.ExceptionsArea.decorate(exceptionsAreas[i]);
+ }
+
+ // Cookies filter page ---------------------------------------------------
+ $('block-third-party-cookies').onclick = function(event) {
+ chrome.send('setAllowThirdPartyCookies',
+ [String($('block-third-party-cookies').checked)]);
+ };
+
+ $('show-cookies-button').onclick = function(event) {
+ chrome.send('coreOptionsUserMetricsAction', ['Options_ShowCookies']);
+ OptionsPage.showPageByName('cookiesView');
+ };
+ },
+
+ /**
+ * 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.
+ * @param {string} hash The hash value.
+ */
+ handleHash: function(hash) {
+ OptionsPage.showTab($(hash + '-nav-tab'));
+ },
+ };
/**
- * Shows the tab contents for the given navigation tab.
- * @param {!Element} tab The tab that the user clicked.
+ * Sets the values for all the content settings radios.
+ * @param {Object} dict A mapping from radio groups to the checked value for
+ * that group.
*/
- showTab: function(tab) {
- if (!tab.classList.contains('inactive-tab'))
- return;
-
- if (this.activeNavTab != null) {
- this.activeNavTab.classList.remove('active-tab');
- $(this.activeNavTab.getAttribute('tab-contents')).classList.
- remove('active-tab-contents');
+ ContentSettings.setContentFilterSettingsValue = function(dict) {
+ for (var group in dict) {
+ document.querySelector('input[type=radio][name=' + group +
+ '][value=' + dict[group] + ']').checked = true;
}
+ };
+
+ /**
+ * Initializes an exceptions list.
+ * @param {string} type The content type that we are setting exceptions for.
+ * @param {Array} list An array of pairs, where the first element of each pair
+ * is the filter string, and the second is the setting (allow/block).
+ */
+ ContentSettings.setExceptions = function(type, list) {
+ var exceptionsList =
+ document.querySelector('div[contentType=' + type + ']' +
+ '[mode=normal] list');
+ exceptionsList.clear();
+ for (var i = 0; i < list.length; i++) {
+ exceptionsList.addException(list[i]);
+ }
+ };
+
+ ContentSettings.setOTRExceptions = function(type, list) {
+ var exceptionsArea =
+ document.querySelector('div[contentType=' + type + '][mode=otr]');
+ exceptionsArea.otrProfileExists = true;
+
+ var exceptionsList = exceptionsArea.querySelector('list');
+ exceptionsList.clear();
+ for (var i = 0; i < list.length; i++) {
+ exceptionsList.addException(list[i]);
+ }
+ };
+
+ /**
+ * Sets the initial value for the Third Party Cookies checkbox.
+ * @param {boolean=} block True if we are blocking third party cookies.
+ */
+ ContentSettings.setBlockThirdPartyCookies = function(block) {
+ $('block-third-party-cookies').checked = block;
+ };
+
+ /**
+ * The browser's response to a request to check the validity of a given URL
+ * pattern.
+ * @param {string} type The content type.
+ * @param {string} mode The browser mode.
+ * @param {string} pattern The pattern.
+ * @param {bool} valid Whether said pattern is valid in the context of
+ * a content exception setting.
+ */
+ ContentSettings.patternValidityCheckComplete =
+ function(type, mode, pattern, valid) {
+ var exceptionsList =
+ document.querySelector('div[contentType=' + type + '][mode=' + mode +
+ '] list');
+ exceptionsList.patternValidityCheckComplete(pattern, valid);
+ };
+
+ // Export
+ return {
+ ContentSettings: ContentSettings
+ };
+
+});
- tab.classList.add('active-tab');
- $(tab.getAttribute('tab-contents')).classList.add('active-tab-contents');
- this.activeNavTab = tab;
- }
-};
-
-/**
- * Sets the initial values for all the content settings radios.
- * @param {Object} dict A mapping from radio groups to the checked value for
- * that group.
- */
-ContentSettings.setInitialContentFilterSettingsValue = function(dict) {
- for (var group in dict) {
- document.querySelector('input[type=radio][name=' + group +
- '][value=' + dict[group] + ']').checked = true;
- }
-};
-
-/**
- * Sets the initial value for the Third Party Cookies checkbox.
- * @param {boolean=} block True if we are blocking third party cookies.
- */
-ContentSettings.setBlockThirdPartyCookies = function(block) {
- $('block-third-party-cookies').checked = block;
-};
diff --git a/chrome/browser/resources/options/content_settings_page.css b/chrome/browser/resources/options/content_settings_page.css
deleted file mode 100644
index 3fee4a9..0000000
--- a/chrome/browser/resources/options/content_settings_page.css
+++ /dev/null
@@ -1,16 +0,0 @@
-#content-settings-nav-tabs .inactive-tab {
- background-color: #FFFFFF;
-}
-
-#content-settings-nav-tabs .active-tab {
- background-color: #DFDFDF;
- font-weight: bold;
-}
-
-.content-settings-tab-contents {
- display: none;
-}
-
-.active-tab-contents {
- display: block;
-}
diff --git a/chrome/browser/resources/options/content_settings_ui.js b/chrome/browser/resources/options/content_settings_ui.js
index 7dda236..45ba788 100644
--- a/chrome/browser/resources/options/content_settings_ui.js
+++ b/chrome/browser/resources/options/content_settings_ui.js
@@ -2,25 +2,35 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-////////////////////////////////////////////////////////////////////////////////
-// ContentSettingsRadio class:
-
-// Define a constructor that uses an input element as its underlying element.
-var ContentSettingsRadio = cr.ui.define('input');
-
-ContentSettingsRadio.prototype = {
- __proto__: HTMLInputElement.prototype,
-
- /**
- * Initialization function for the cr.ui framework.
- */
- decorate: function() {
- this.type = 'radio';
- var self = this;
-
- this.addEventListener('change',
- function(e) {
- chrome.send('setContentFilter', [this.name, this.value]);
- });
- },
-};
+cr.define('options', function() {
+
+ //////////////////////////////////////////////////////////////////////////////
+ // ContentSettingsRadio class:
+
+ // Define a constructor that uses an input element as its underlying element.
+ var ContentSettingsRadio = cr.ui.define('input');
+
+ ContentSettingsRadio.prototype = {
+ __proto__: HTMLInputElement.prototype,
+
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ this.type = 'radio';
+ var self = this;
+
+ this.addEventListener('change',
+ function(e) {
+ chrome.send('setContentFilter', [this.name, this.value]);
+ });
+ },
+ };
+
+ // Export
+ return {
+ ContentSettingsRadio: ContentSettingsRadio
+ };
+
+});
+
diff --git a/chrome/browser/resources/options/font_settings_overlay.html b/chrome/browser/resources/options/font_settings_overlay.html
deleted file mode 100644
index 3edc53e..0000000
--- a/chrome/browser/resources/options/font_settings_overlay.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<div class="page hidden" id="fontSettingsOverlay">
- <h1 i18n-content="fontSettingsTitle"></h1>
-</div>
diff --git a/chrome/browser/resources/options/font_settings_overlay.js b/chrome/browser/resources/options/font_settings_overlay.js
deleted file mode 100644
index 14e2c6b..0000000
--- a/chrome/browser/resources/options/font_settings_overlay.js
+++ /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.
-
-/**
- * FontSettingsOverlay class
- * Encapsulated handling of the 'Font Settings' overlay page.
- * @class
- */
-function FontSettingsOverlay() {
- OptionsPage.call(this, 'fontSettingsOverlay',
- templateData.fontSettingsOverlayTitle,
- 'fontSettingsOverlay');
-}
-
-cr.addSingletonGetter(FontSettingsOverlay);
-
-FontSettingsOverlay.prototype = {
- // Inherit FontSettingsOverlay from OptionsPage.
- __proto__: OptionsPage.prototype,
-
- /**
- * Initialize the page.
- */
- initializePage: function() {
- // Call base class implementation to starts preference initialization.
- OptionsPage.prototype.initializePage.call(this);
-
- // TODO(csilv): add any initialization here or delete method and/or class.
- }
-};
diff --git a/chrome/browser/resources/options/options_page.css b/chrome/browser/resources/options/options_page.css
index c54adf7..c5836ce 100644
--- a/chrome/browser/resources/options/options_page.css
+++ b/chrome/browser/resources/options/options_page.css
@@ -1,10 +1,17 @@
+body {
+ font-size: 100%;
+ -webkit-user-select: none;
+}
+
#settings-title {
- height: 30px;
- -webkit-padding-end: 15px;
- padding-top: 20px;
+ -webkit-padding-end: 24px;
+ padding-top: 1em;
+ padding-bottom: 1em;
text-align: end;
- font-size: 140%;
- color: #c7c7c7;
+ font-size: 125%;
+ font-weight: normal;
+ color: #53627d;
+ margin: 0;
}
#main-content {
@@ -20,45 +27,82 @@
position: fixed;
left: 0;
right: 0;
- background: rgba(0, 0, 0, .5);
+ background: rgba(0, 0, 0, .2);
top: 0;
bottom: 0;
z-index: 10;
padding: 20px;
+ display: -webkit-box;
+ -webkit-box-align: center;
+ -webkit-box-pack: center;
}
#close-overlay {
- float: right;
position: relative;
- right: -20px;
top: -20px;
width: 20px;
height: 20px;
}
-#overlayview {
+html[dir='ltr'] #close-overlay {
+ float: right;
+ right: -20px;
+}
+
+html[dir='rtl'] #close-overlay {
+ float: left;
+ left: -20px;
+}
+
+.overlay .button-strip {
+ padding-top: 20px;
+ text-align: end;
+}
+
+.overlay > div {
background: white;
border-radius: 5px;
- padding: 30px;
+ padding: 15px;
+ border: 1px solid #666;
+ -webkit-box-shadow: 3px 3px 3px #666;
+}
+
+#navbar {
+ margin: 0;
}
#navbar-container {
background: -webkit-gradient(linear,
left top,
left bottom,
- from(rgba(255,255,255,0)),
- color-stop(0.7, rgba(255,255,255,0)),
- to(white)),
+ from(rgba(234, 238, 243, 0)),
+ to(#eaeef3)),
-webkit-gradient(linear,
left top,
right top,
- from(white),
- color-stop(0.8, white),
- to(#f3f3f3));
- border-right: 1px solid #dbdbdb;
+ from(#eaeef3),
+ color-stop(0.97, #eaeef3),
+ to(#d3d7db));
+ -webkit-border-end: 1px solid #c6c9ce;
cursor: pointer;
position: relative;
width: 250px;
+ z-index: 2;
+}
+
+html[dir='rtl'] #navbar-container {
+ background: -webkit-gradient(linear,
+ left top,
+ left bottom,
+ from(rgba(255, 255, 255, 0)),
+ color-stop(0.7, rgba(255, 255, 255, 0)),
+ to(white)),
+ -webkit-gradient(linear,
+ right top,
+ left top,
+ from(white),
+ color-stop(0.8, white),
+ to(#f3f3f3));
}
#navbar-container > hr {
@@ -70,16 +114,31 @@
}
.navbar-item, .navbar-item2 {
- padding-top: 10px;
- padding-bottom: 10px;
- -webkit-padding-end: 20px;
+ padding: 0.5em 0;
+ -webkit-padding-end: 24px;
text-align: end;
- display: block
+ display: block;
+ color: #426dc9;
+ outline:none;
}
.navbar-item-selected {
- background: -webkit-gradient(linear, left top, right top, from(white), to(#d6def3));
+ background: -webkit-gradient(linear,
+ left top,
+ right top,
+ from(#eaeef3),
+ color-stop(0.97, #b4c8ea),
+ to(#a2b5b4));
font-weight: bold;
+ color: black;
+}
+
+html[dir='rtl'] .navbar-item-selected {
+ background: -webkit-gradient(linear,
+ right top,
+ left top,
+ from(white),
+ to(#d6def3));
}
.navbar-item-normal {
@@ -88,49 +147,103 @@
#mainview {
-webkit-box-align: stretch;
- width: 600px;
- padding: 10px;
- position: relative;
+ -webkit-padding-start: 251px;
+ margin: 0;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 1;
+}
+
+#mainview-content {
+ width: 550px;
+ padding: 0 24px;
+}
+
+#managed-prefs-banner {
+ background: -webkit-gradient(linear,
+ left top,
+ left bottom,
+ from(#fff2b7),
+ color-stop(0.97, #fae691),
+ to(#878787));
+ height: 31px;
+ width: 100%;
+}
+
+#managed-prefs-banner, span {
+ margin: 0;
+ padding: 0;
+ vertical-align: middle;
+}
+
+#managed-prefs-icon {
+ background-image: url("chrome://theme/IDR_WARNING");
+ background-repeat: no-repeat;
+ background-position:center;
+ padding: 5px;
+ width: 24px;
+ height: 21px;
+ display: inline-block;
}
.page > h1 {
- height: 30px;
- -webkit-padding-end: 15px;
- padding-top: 12px;
- -webkit-padding-start: 15px;
- font-size: 140%;
- color: #7c90d8;
+ -webkit-padding-end: 24px;
+ padding-top: 1em;
+ padding-bottom: 1em;
+ border-bottom: 1px solid #eeeeee;
+ -webkit-padding-start: 0;
+ font-size: 125%;
+ color: #54637f;
+ margin: 0;
}
section {
- margin-top: 10px;
- border-bottom: 1px solid #ededed;
- padding-bottom: 10px;
display: -webkit-box;
-webkit-box-orient: horizontal;
+ border-bottom: 1px solid #eeeeee;
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding-bottom: 0.5em;
}
section > h3 {
- font-weight: bold;
- width: 150px;
- font-size: 75%;
- -webkit-padding-start: 15px;
- vertical-align: top;
+ width: 100px;
+ font-weight: normal;
+ -webkit-padding-start: 0;
+ vertical-align: middle;
+ margin: 0;
+ font-size: 100%;
+ padding-top: 2px;
+}
+
+section > div:only-of-type {
+ -webkit-box-flex: 1;
}
.option {
- margin-top: 5px;
+ margin-top: 0;
}
-.option-control-table {
- margin-top: 5px;
+.option-control-table, section > div:only-of-type {
-webkit-padding-start: 10px;
+ border-spacing: 0 0;
}
.suboption {
-webkit-margin-start: 18px;
}
+/* 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-bottom: 3px;
+}
+
.hidden {
display: none;
}
@@ -138,3 +251,81 @@ section > h3 {
.touch-slider {
-webkit-appearance: slider-horizontal;
}
+
+input[type="checkbox"] {
+ margin-top: 0;
+ vertical-align: middle;
+}
+
+input[type="radio"] {
+ vertical-align: top;
+ padding-top: 2px;
+}
+
+select {
+ margin: 0px;
+}
+
+.link-button {
+ background-color: transparent;
+ border: none;
+ color: blue;
+ cursor: pointer;
+ text-decoration: underline;
+}
+
+.text-button {
+ background-color: transparent;
+ border-color: transparent;
+}
+
+#contentSettingsPage :invalid {
+ background-color: pink;
+}
+
+list > .heading {
+ color: #666666;
+}
+
+list > .heading:hover {
+ background-color: transparent;
+ border-color: transparent;
+}
+
+.left-side-table {
+ display: -webkit-box;
+}
+
+.left-side-table > div:first-child {
+ -webkit-box-flex: 1;
+}
+
+.left-side-table > :last-child {
+ -webkit-padding-start: 20px;
+}
+
+.left-side-table > :last-child button {
+ width: 100%;
+}
+
+.favicon-cell {
+ background-position: left;
+ background-repeat: no-repeat;
+ -webkit-padding-start: 20px;
+}
+html[dir=rtl] .favicon-cell {
+ background-position: right;
+}
+
+html[enable-background-mode=false] #background-mode-section {
+ display: none;
+}
+
+.multi-line-wrap input {
+ position: absolute;
+}
+
+.multi-line-wrap span {
+ -webkit-margin-start: 20px;
+ display: block;
+}
diff --git a/chrome/browser/resources/options/options_page.js b/chrome/browser/resources/options/options_page.js
index 9550031..bb560f3 100644
--- a/chrome/browser/resources/options/options_page.js
+++ b/chrome/browser/resources/options/options_page.js
@@ -2,176 +2,256 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-///////////////////////////////////////////////////////////////////////////////
-// OptionsPage class:
-
-/**
- * Base class for options page.
- * @constructor
- * @param {string} name Options page name, also defines id of the div element
- * containing the options view and the name of options page navigation bar
- * item as name+'PageNav'.
- * @param {string} title Options page title, used for navigation bar
- * @extends {EventTarget}
- */
-function OptionsPage(name, title, pageDivName) {
- this.name = name;
- this.title = title;
- this.pageDivName = pageDivName;
- this.pageDiv = $(this.pageDivName);
- this.tab = null;
-}
-
-OptionsPage.registeredPages_ = {};
-
-/**
- * Pages which are meant to have an entry in the nav, but
- * not have a permanent entry.
- */
-OptionsPage.registeredSubPages_ = {};
-
-/**
- * Pages which are meant to behave like model dialogs.
- */
-OptionsPage.registeredOverlayPages_ = {};
-
-/**
- * Shows a registered page.
- * @param {string} pageName Page name.
- */
-OptionsPage.showPageByName = function(pageName) {
- for (var name in OptionsPage.registeredPages_) {
- var page = OptionsPage.registeredPages_[name];
- page.visible = name == pageName;
- }
-};
-
-/**
- * Shows a registered Overlay page.
- * @param {string} overlayName Page name.
- */
-OptionsPage.showOverlay = function(overlayName) {
- if (OptionsPage.registeredOverlayPages_[overlayName]) {
- OptionsPage.registeredOverlayPages_[overlayName].visible = true;
+cr.define('options', function() {
+ /////////////////////////////////////////////////////////////////////////////
+ // OptionsPage class:
+
+ /**
+ * Base class for options page.
+ * @constructor
+ * @param {string} name Options page name, also defines id of the div element
+ * containing the options view and the name of options page navigation bar
+ * item as name+'PageNav'.
+ * @param {string} title Options page title, used for navigation bar
+ * @extends {EventTarget}
+ */
+ function OptionsPage(name, title, pageDivName) {
+ this.name = name;
+ this.title = title;
+ this.pageDivName = pageDivName;
+ this.pageDiv = $(this.pageDivName);
+ this.tab = null;
+ this.managed = false;
}
-};
-
-OptionsPage.clearOverlays = function() {
- for (var name in OptionsPage.registeredOverlayPages_) {
- var page = OptionsPage.registeredOverlayPages_[name];
- page.visible = false;
- }
-};
-
-/**
- * Registers new options page.
- * @param {OptionsPage} page Page to register.
- */
-OptionsPage.register = function(page) {
- OptionsPage.registeredPages_[page.name] = page;
- // Create and add new page <li> element to navbar.
- var pageNav = document.createElement('li');
- pageNav.id = page.name + 'PageNav';
- pageNav.className = 'navbar-item';
- pageNav.setAttribute('pageName', page.name);
- pageNav.textContent = page.title;
- pageNav.onclick = function(event) {
- OptionsPage.showPageByName(this.getAttribute('pageName'));
- };
- var navbar = $('navbar');
- navbar.appendChild(pageNav);
- page.tab = pageNav;
- page.initializePage();
-};
-
-/**
- * Registers a new Sub tab page.
- * @param {OptionsPage} page Page to register.
- */
-OptionsPage.registerSubPage = function(page) {
- OptionsPage.registeredPages_[page.name] = page;
- var pageNav = document.createElement('li');
- pageNav.id = page.name + 'PageNav';
- pageNav.className = 'navbar-item hidden';
- pageNav.setAttribute('pageName', page.name);
- pageNav.textContent = page.title;
- var subpagesnav = $('subpagesnav');
- subpagesnav.appendChild(pageNav);
- page.tab = pageNav;
- page.initializePage();
-};
-
-/**
- * Registers a new Overlay page.
- * @param {OptionsPage} page Page to register, must be a class derviced from
- * OptionsPage.
- */
-OptionsPage.registerOverlay = function(page) {
- OptionsPage.registeredOverlayPages_[page.name] = page;
- page.tab = undefined;
- page.isOverlay = true;
- page.initializePage();
-};
-
-/**
- * Initializes the complete options page. This will cause
- * all C++ handlers to be invoked to do final setup.
- */
-OptionsPage.initialize = function() {
- chrome.send('coreOptionsInitialize');
-};
-
-OptionsPage.prototype = {
- __proto__: cr.EventTarget.prototype,
+
+ OptionsPage.registeredPages_ = {};
/**
- * Initializes page content.
+ * Pages which are meant to have an entry in the nav, but
+ * not have a permanent entry.
*/
- initializePage: function() {},
+ OptionsPage.registeredSubPages_ = {};
/**
- * Gets page visibility state.
+ * Pages which are meant to behave like model dialogs.
*/
- get visible() {
- var page = $(this.pageDivName);
- return page.ownerDocument.defaultView.getComputedStyle(
- page).display == 'block';
- },
+ OptionsPage.registeredOverlayPages_ = {};
+
+ /**
+ * Shows a registered page.
+ * @param {string} pageName Page name.
+ */
+ OptionsPage.showPageByName = function(pageName) {
+ for (var name in OptionsPage.registeredPages_) {
+ var page = OptionsPage.registeredPages_[name];
+ page.visible = name == pageName;
+ }
+ };
+
+ /**
+ * Called on load. Dispatch the URL hash to the given page's handleHash
+ * function.
+ * @param {string} pageName The string name of the (registered) options page.
+ * @param {string} hash The value of the hash component of the URL.
+ */
+ OptionsPage.handleHashForPage = function(pageName, hash) {
+ OptionsPage.registeredPages_[pageName].handleHash(hash);
+ };
/**
- * Sets page visibility.
+ * Shows a registered Overlay page.
+ * @param {string} overlayName Page name.
*/
- set visible(visible) {
- if ((this.visible && visible) || (!this.visible && !visible))
+ OptionsPage.showOverlay = function(overlayName) {
+ if (OptionsPage.registeredOverlayPages_[overlayName]) {
+ OptionsPage.registeredOverlayPages_[overlayName].visible = true;
+ }
+ };
+
+ OptionsPage.clearOverlays = function() {
+ for (var name in OptionsPage.registeredOverlayPages_) {
+ var page = OptionsPage.registeredOverlayPages_[name];
+ page.visible = false;
+ }
+ };
+
+ /**
+ * Shows the tab contents for the given navigation tab.
+ * @param {!Element} tab The tab that the user clicked.
+ */
+ OptionsPage.showTab = function(tab) {
+ if (!tab.classList.contains('inactive-tab'))
return;
- if (visible) {
- window.history.pushState({pageName: this.name},
- this.title,
- '/' + this.name);
- this.pageDiv.style.display = 'block';
- if (this.isOverlay) {
- var overlay = $('overlay');
- overlay.classList.remove('hidden');
- }
- if (this.tab) {
- this.tab.classList.add('navbar-item-selected');
- if (this.tab.parentNode && this.tab.parentNode.id == 'subpagesnav')
- this.tab.classList.remove('hidden');
+ if (this.activeNavTab != null) {
+ this.activeNavTab.classList.remove('active-tab');
+ $(this.activeNavTab.getAttribute('tab-contents')).classList.
+ remove('active-tab-contents');
+ }
+
+ tab.classList.add('active-tab');
+ $(tab.getAttribute('tab-contents')).classList.add('active-tab-contents');
+ this.activeNavTab = tab;
+ }
+
+ /**
+ * Registers new options page.
+ * @param {OptionsPage} page Page to register.
+ */
+ OptionsPage.register = function(page) {
+ OptionsPage.registeredPages_[page.name] = page;
+ // Create and add new page <li> element to navbar.
+ var pageNav = document.createElement('li');
+ pageNav.id = page.name + 'PageNav';
+ pageNav.className = 'navbar-item';
+ pageNav.setAttribute('pageName', page.name);
+ pageNav.textContent = page.title;
+ pageNav.tabIndex = 0;
+ pageNav.onclick = function(event) {
+ OptionsPage.showPageByName(this.getAttribute('pageName'));
+ };
+ pageNav.onkeypress = function(event) {
+ // Enter or space
+ if (event.keyCode == 13 || event.keyCode == 32) {
+ OptionsPage.showPageByName(this.getAttribute('pageName'));
}
- } else {
- if (this.isOverlay) {
- var overlay = $('overlay');
- overlay.classList.add('hidden');
+ };
+ var navbar = $('navbar');
+ navbar.appendChild(pageNav);
+ page.tab = pageNav;
+ page.initializePage();
+ };
+
+ /**
+ * Registers a new Sub tab page.
+ * @param {OptionsPage} page Page to register.
+ */
+ OptionsPage.registerSubPage = function(page) {
+ OptionsPage.registeredPages_[page.name] = page;
+ var pageNav = document.createElement('li');
+ pageNav.id = page.name + 'PageNav';
+ pageNav.className = 'navbar-item hidden';
+ pageNav.setAttribute('pageName', page.name);
+ pageNav.textContent = page.title;
+ var subpagesnav = $('subpagesnav');
+ subpagesnav.appendChild(pageNav);
+ page.tab = pageNav;
+ page.initializePage();
+ };
+
+ /**
+ * Registers a new Overlay page.
+ * @param {OptionsPage} page Page to register, must be a class derviced from
+ * OptionsPage.
+ */
+ OptionsPage.registerOverlay = function(page) {
+ OptionsPage.registeredOverlayPages_[page.name] = page;
+ page.tab = undefined;
+ page.isOverlay = true;
+ page.initializePage();
+ };
+
+ /**
+ * Callback for window.onpopstate.
+ * @param {Object} data State data pushed into history.
+ */
+ OptionsPage.setState = function(data) {
+ if (data && data.pageName) {
+ OptionsPage.showPageByName(data.pageName);
+ }
+ };
+
+ /**
+ * Initializes the complete options page. This will cause
+ * all C++ handlers to be invoked to do final setup.
+ */
+ OptionsPage.initialize = function() {
+ chrome.send('coreOptionsInitialize');
+ };
+
+ OptionsPage.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ /**
+ * Initializes page content.
+ */
+ initializePage: function() {},
+
+ /**
+ * Sets managed banner visibility state.
+ */
+ setManagedBannerVisibility: function(visible) {
+ this.managed = visible;
+ if (this.visible) {
+ $('managed-prefs-banner').style.display = visible ? 'block' : 'none';
}
- this.pageDiv.style.display = 'none';
- if (this.tab) {
- this.tab.classList.remove('navbar-item-selected');
- if (this.tab.parentNode && this.tab.parentNode.id == 'subpagesnav')
- this.tab.classList.add('hidden');
+ },
+
+ /**
+ * Gets page visibility state.
+ */
+ get visible() {
+ var page = $(this.pageDivName);
+ return page && page.ownerDocument.defaultView.getComputedStyle(
+ page).display == 'block';
+ },
+
+ /**
+ * Sets page visibility.
+ */
+ set visible(visible) {
+ if ((this.visible && visible) || (!this.visible && !visible))
+ return;
+
+ if (visible) {
+ this.pageDiv.style.display = 'block';
+ if (this.isOverlay) {
+ var overlay = $('overlay');
+ overlay.classList.remove('hidden');
+ } else {
+ var banner = $('managed-prefs-banner');
+ banner.style.display = this.managed ? 'block' : 'none';
+
+ // Recent webkit change no longer allows url change from "chrome://".
+ window.history.pushState({pageName: this.name},
+ this.title);
+ }
+ if (this.tab) {
+ this.tab.classList.add('navbar-item-selected');
+ if (this.tab.parentNode && this.tab.parentNode.id == 'subpagesnav')
+ this.tab.classList.remove('hidden');
+ }
+ } else {
+ if (this.isOverlay) {
+ var overlay = $('overlay');
+ overlay.classList.add('hidden');
+ }
+ this.pageDiv.style.display = 'none';
+ if (this.tab) {
+ this.tab.classList.remove('navbar-item-selected');
+ if (this.tab.parentNode && this.tab.parentNode.id == 'subpagesnav')
+ this.tab.classList.add('hidden');
+ }
}
- }
- cr.dispatchPropertyChange(this, 'visible', visible, !visible);
- }
-};
+ cr.dispatchPropertyChange(this, 'visible', visible, !visible);
+ },
+
+ /**
+ * 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
+ * OptionsPage subclasses to get other behavior.
+ * @param {string} hash The hash value.
+ */
+ handleHash: function(hash) {
+ OptionsPage.showOverlay(hash);
+ },
+ };
+
+ // Export
+ return {
+ OptionsPage: OptionsPage
+ };
+
+});
diff --git a/chrome/browser/resources/options/personal_options.html b/chrome/browser/resources/options/personal_options.html
index ffdc855..879f14e 100644
--- a/chrome/browser/resources/options/personal_options.html
+++ b/chrome/browser/resources/options/personal_options.html
@@ -1,3 +1,96 @@
<div class="page hidden" id="personalPage">
<h1 i18n-content="personalPage"></h1>
+
+ <section>
+ <h3 i18n-content="sync_section"></h3>
+ <div>
+ <div id="not-synced-controls" class="hidden">
+ <div class="section-text" id="sync_not_setup_info"
+ i18n-content="sync_not_setup_info"></div>
+ <div>
+ <button id="start-sync" i18n-content="start_sync"></button>
+ </div>
+ </div>
+ <div id="synced-controls" class="hidden">
+ <div class="section-text" id="synced_to_user_with_time"></div>
+ <div>
+<if expr="not pp_ifdef('chromeos')">
+ <button id="stop-sync" i18n-content="stop_sync"></button>
+</if>
+ <button id="sync-customize" i18n-content="sync_customize"></button>
+ </div>
+ </div>
+ </div>
+ </section>
+ <section>
+ <h3 i18n-content="passwords"></h3>
+ <div>
+ <label>
+ <input id="passwords_asktosave"
+ name="passwords_radio"
+ pref="profile.password_manager_enabled"
+ type="radio" value="true" metric="Options_PasswordManager">
+ <span i18n-content="passwords_asktosave"></span>
+ </label>
+ <label>
+ <input id="passwords_neversave"
+ name="passwords_radio"
+ pref="profile.password_manager_enabled"
+ type="radio" value="false" metric="Options_PasswordManager">
+ <span i18n-content="passwords_neversave"></span>
+ </label>
+ <div><button id="showpasswords"
+ i18n-content="showpasswords"></button></div>
+ </div>
+ </section>
+ <section>
+ <h3 i18n-content="autofill"></h3>
+ <div>
+ <button id="autofill_options" i18n-content="autofill_options"></button>
+ </div>
+ </section>
+<if expr="not pp_ifdef('chromeos')">
+ <section>
+ <h3 i18n-content="browsing_data"></h3>
+ <div>
+ <button id="import_data" i18n-content="import_data"></button>
+ </div>
+ </section>
+</if>
+<if expr="not pp_ifdef('toolkit_views') and (os == 'linux2' or os.find('bsd') != -1)">
+ <section>
+ <h3 i18n-content="appearance"></h3>
+ <div>
+ <div>
+ <button id="themes_GTK_button"
+ i18n-content="themes_GTK_button"></button>
+ <button id="themes_set_classic"
+ i18n-content="themes_set_classic"></button>
+ <a i18n-content="themes_gallery" id="themes-gallery" href=""></a>
+ </div>
+ <label>
+ <input name="decorations_radio"
+ pref="browser.custom_chrome_frame"
+ type="radio" value="false" metric="Options_CustomFrame">
+ <span i18n-content="showWindow_decorations_radio"></span>
+ </label>
+ <label>
+ <input name="decorations_radio"
+ pref="browser.custom_chrome_frame"
+ type="radio" value="true" metric="Options_CustomFrame">
+ <span i18n-content="hideWindow_decorations_radio"></span>
+ </label>
+ </div>
+ </section>
+</if>
+<if expr="pp_ifdef('toolkit_views') or os == 'win32' or os == 'darwin'">
+ <section>
+ <h3 i18n-content="themes"></h3>
+ <div>
+ <button id="themes_reset" i18n-content="themes_reset"></button>
+ <a i18n-content="themes_gallery" id="themes-gallery" href=""></a>
+ </div>
+ </section>
+</if>
+
</div>
diff --git a/chrome/browser/resources/options/personal_options.js b/chrome/browser/resources/options/personal_options.js
index b7b48c9..9ef2d4a 100644
--- a/chrome/browser/resources/options/personal_options.js
+++ b/chrome/browser/resources/options/personal_options.js
@@ -2,25 +2,132 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-//
-// PersonalOptions class
-// Encapsulated handling of personal options page.
-//
-function PersonalOptions() {
- OptionsPage.call(this, 'personal', templateData.personalPage, 'personalPage');
-}
-
-cr.addSingletonGetter(PersonalOptions);
-
-PersonalOptions.prototype = {
- // Inherit PersonalOptions from OptionsPage.
- __proto__: OptionsPage.prototype,
-
- // Initialize PersonalOptions page.
- initializePage: function() {
- // Call base class implementation to starts preference initialization.
- OptionsPage.prototype.initializePage.call(this);
-
- // TODO(csilv): add any needed initialization here or delete this method.
+cr.define('options', function() {
+
+ var OptionsPage = options.OptionsPage;
+
+ //
+ // PersonalOptions class
+ // Encapsulated handling of personal options page.
+ //
+ function PersonalOptions() {
+ OptionsPage.call(this, 'personal', templateData.personalPage,
+ 'personalPage');
}
-};
+
+ cr.addSingletonGetter(PersonalOptions);
+
+ PersonalOptions.prototype = {
+ // Inherit PersonalOptions from OptionsPage.
+ __proto__: options.OptionsPage.prototype,
+
+ // Initialize PersonalOptions page.
+ initializePage: function() {
+ // Call base class implementation to starts preference initialization.
+ OptionsPage.prototype.initializePage.call(this);
+
+ $('sync-customize').onclick = function(event) {
+ OptionsPage.showPageByName('sync');
+ };
+ $('start-sync').onclick = function(event) {
+ //TODO(sargrass): Show start-sync subpage, after dhg done.
+ };
+
+ // Listen to pref changes.
+ Preferences.getInstance().addEventListener('sync.has_setup_completed',
+ function(event) {
+ if (event.value) {
+ chrome.send('getSyncStatus');
+ $('synced-controls').classList.remove('hidden');
+ $('not-synced-controls').classList.add('hidden');
+ } else {
+ $('synced-controls').classList.add('hidden');
+ $('not-synced-controls').classList.remove('hidden');
+ }
+ });
+
+ $('showpasswords').onclick = function(event) {
+ PasswordsExceptions.load();
+ OptionsPage.showPageByName('passwordsExceptions');
+ OptionsPage.showTab($('passwords-nav-tab'));
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_ShowPasswordsExceptions']);
+ };
+
+ $('autofill_options').onclick = function(event) {
+ OptionsPage.showPageByName('autoFillOptions');
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_ShowAutoFillSettings']);
+ };
+
+ if (!cr.isChromeOS) {
+ $('stop-sync').onclick = 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'); });
+ };
+ $('import_data').onclick = function(event) {
+ OptionsPage.showOverlay('importDataOverlay');
+ chrome.send('coreOptionsUserMetricsAction', ['Import_ShowDlg']);
+ };
+ }
+
+ if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
+ $('themes_GTK_button').onclick = function(event) {
+ chrome.send('themesSetGTK');
+ };
+
+ $('themes_set_classic').onclick = function(event) {
+ chrome.send('themesReset');
+ };
+ $('themes-gallery').onclick = function(event) {
+ chrome.send('themesGallery');
+ }
+ }
+
+ if (cr.isMac || cr.isWindows || cr.isChromeOS) {
+ $('themes_reset').onclick = function(event) {
+ chrome.send('themesReset');
+ };
+ $('themes-gallery').onclick = function(event) {
+ chrome.send('themesGallery');
+ }
+ }
+ },
+
+ syncStatusCallback_: function(statusString) {
+ $('synced_to_user_with_time').textContent = statusString;
+ },
+
+ setGtkThemeButtonEnabled_: function(enabled) {
+ if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
+ $('themes_GTK_button').disabled = !enabled;
+ }
+ },
+
+ setClassicThemeButtonEnabled_: function(enabled) {
+ $('themes_set_classic').disabled = !enabled;
+ },
+ };
+
+ PersonalOptions.syncStatusCallback = function(statusString) {
+ PersonalOptions.getInstance().syncStatusCallback_(statusString);
+ };
+
+ PersonalOptions.setGtkThemeButtonEnabled = function(enabled) {
+ PersonalOptions.getInstance().setGtkThemeButtonEnabled_(enabled);
+ };
+
+ PersonalOptions.setClassicThemeButtonEnabled = function(enabled) {
+ PersonalOptions.getInstance().setClassicThemeButtonEnabled_(enabled);
+ };
+
+ // Export
+ return {
+ PersonalOptions: PersonalOptions
+ };
+
+});
+
diff --git a/chrome/browser/resources/options/pref_ui.js b/chrome/browser/resources/options/pref_ui.js
index 7439a40..a0a656a 100644
--- a/chrome/browser/resources/options/pref_ui.js
+++ b/chrome/browser/resources/options/pref_ui.js
@@ -2,175 +2,406 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-///////////////////////////////////////////////////////////////////////////////
-// PrefCheckbox class:
+cr.define('options', function() {
-// Define a constructor that uses an input element as its underlying element.
-var PrefCheckbox = cr.ui.define('input');
+ var Preferences = options.Preferences;
+ /////////////////////////////////////////////////////////////////////////////
+ // PrefCheckbox class:
-PrefCheckbox.prototype = {
- // Set up the prototype chain
- __proto__: HTMLInputElement.prototype,
+ // Define a constructor that uses an input element as its underlying element.
+ var PrefCheckbox = cr.ui.define('input');
+
+ PrefCheckbox.prototype = {
+ // Set up the prototype chain
+ __proto__: HTMLInputElement.prototype,
+
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ this.type = 'checkbox';
+ var self = this;
+
+ // Listen to pref changes.
+ Preferences.getInstance().addEventListener(this.pref,
+ function(event) {
+ var value = (event.value && event.value['value'] != undefined) ?
+ event.value['value'] : event.value;
+ self.checked = Boolean(value);
+ self.managed = (event.value && event.value['managed'] != undefined) ?
+ event.value['managed'] : false;
+ self.disabled = self.managed;
+ });
+
+ // Listen to user events.
+ this.addEventListener('click',
+ function(e) {
+ switch(self.valueType) {
+ case 'number':
+ Preferences.setIntegerPref(self.pref,
+ Number(self.checked), self.metric);
+ break;
+ case 'boolean':
+ Preferences.setBooleanPref(self.pref, self.checked,
+ self.checked, self.metric);
+ break;
+ }
+ });
+
+ // Initialize options.
+ this.ownerDocument.addEventListener('DOMContentLoaded',
+ function() {
+ self.initializeValueType(self.getAttribute('value-type'));
+ });
+ },
+
+ /**
+ * Sets up options in checkbox element.
+ * @param {String} valueType The preference type for this checkbox.
+ */
+ initializeValueType: function(valueType) {
+ this.valueType = valueType || 'boolean';
+ }
+ };
/**
- * Initialization function for the cr.ui framework.
+ * The preference name.
+ * @type {string}
*/
- decorate: function() {
- this.type = 'checkbox';
- var self = this;
-
- // Listen to pref changes.
- Preferences.getInstance().addEventListener(this.pref,
- function(event) {
- self.checked = event.value;
- });
-
- // Listen to user events.
- this.addEventListener('click',
- function(e) {
- Preferences.setBooleanPref(self.pref,
- self.checked);
- });
- }
-};
-
-/**
- * The preference name.
- * @type {string}
- */
-cr.defineProperty(PrefCheckbox, 'pref', cr.PropertyKind.ATTR);
-
-///////////////////////////////////////////////////////////////////////////////
-// PrefRange class:
-
-// Define a constructor that uses an input element as its underlying element.
-var PrefRange = cr.ui.define('input');
-
-PrefRange.prototype = {
- // Set up the prototype chain
- __proto__: HTMLInputElement.prototype,
+ cr.defineProperty(PrefCheckbox, 'pref', cr.PropertyKind.ATTR);
/**
- * Initialization function for the cr.ui framework.
+ * The user metric string.
+ * @type {string}
*/
- decorate: function() {
- this.type = 'range';
- var self = this;
-
- // Listen to pref changes.
- Preferences.getInstance().addEventListener(this.pref,
- function(event) {
- self.value = event.value;
- });
-
- // Listen to user events.
- this.addEventListener('change',
- function(e) {
- Preferences.setIntegerPref(self.pref, self.value);
- });
- }
-};
-
-/**
- * The preference name.
- * @type {string}
- */
-cr.defineProperty(PrefRange, 'pref', cr.PropertyKind.ATTR);
-
-///////////////////////////////////////////////////////////////////////////////
-// PrefSelect class:
-
-// Define a constructor that uses an select element as its underlying element.
-var PrefSelect = cr.ui.define('select');
-
-PrefSelect.prototype = {
- // Set up the prototype chain
- __proto__: HTMLSelectElement.prototype,
+ cr.defineProperty(PrefCheckbox, 'metric', cr.PropertyKind.ATTR);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PrefRadio class:
+
+ //Define a constructor that uses an input element as its underlying element.
+ var PrefRadio = cr.ui.define('input');
+
+ PrefRadio.prototype = {
+ // Set up the prototype chain
+ __proto__: HTMLInputElement.prototype,
+
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ this.type = 'radio';
+ var self = this;
+
+ // Listen to pref changes.
+ Preferences.getInstance().addEventListener(this.pref,
+ function(event) {
+ var value = (event.value && event.value['value'] != undefined) ?
+ event.value['value'] : event.value;
+ self.managed = (event.value && event.value['managed'] != undefined) ?
+ event.value['managed'] : false;
+ self.checked = String(value) == self.value;
+ self.disabled = self.managed;
+ });
+
+ // Listen to user events.
+ this.addEventListener('change',
+ function(e) {
+ if(self.value == 'true' || self.value == 'false') {
+ Preferences.setBooleanPref(self.pref,
+ self.value == 'true', self.metric);
+ } else {
+ Preferences.setIntegerPref(self.pref,
+ parseInt(self.value, 10), self.metric);
+ }
+ });
+ },
+
+ /**
+ * Getter for preference name attribute.
+ */
+ get pref() {
+ return this.getAttribute('pref');
+ },
+
+ /**
+ * Setter for preference name attribute.
+ */
+ set pref(name) {
+ this.setAttribute('pref', name);
+ }
+ };
/**
- * Initialization function for the cr.ui framework.
- */
- decorate: function() {
- var self = this;
- // Listen to pref changes.
- Preferences.getInstance().addEventListener(this.pref,
- function(event) {
- for (var i = 0; i < self.options.length; i++) {
- if (self.options[i].value == event.value) {
- self.selectedIndex = i;
- return;
+ * The user metric string.
+ * @type {string}
+ */
+ cr.defineProperty(PrefRadio, 'metric', cr.PropertyKind.ATTR);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PrefNumeric class:
+
+ // Define a constructor that uses an input element as its underlying element.
+ var PrefNumeric = function() {};
+ PrefNumeric.prototype = {
+ // Set up the prototype chain
+ __proto__: HTMLInputElement.prototype,
+
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ var self = this;
+
+ // Listen to pref changes.
+ Preferences.getInstance().addEventListener(this.pref,
+ function(event) {
+ self.value = (event.value && event.value['value'] != undefined) ?
+ event.value['value'] : event.value;
+ self.managed = (event.value && event.value['managed'] != undefined) ?
+ event.value['managed'] : false;
+ self.disabled = self.managed;
+ });
+
+ // Listen to user events.
+ this.addEventListener('change',
+ function(e) {
+ if (this.validity.valid) {
+ Preferences.setIntegerPref(self.pref, self.value, self.metric);
+ }
+ });
+ }
+ };
+
+ /**
+ * The preference name.
+ * @type {string}
+ */
+ cr.defineProperty(PrefNumeric, 'pref', cr.PropertyKind.ATTR);
+
+ /**
+ * The user metric string.
+ * @type {string}
+ */
+ cr.defineProperty(PrefNumeric, 'metric', cr.PropertyKind.ATTR);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PrefNumber class:
+
+ // Define a constructor that uses an input element as its underlying element.
+ var PrefNumber = cr.ui.define('input');
+
+ PrefNumber.prototype = {
+ // Set up the prototype chain
+ __proto__: PrefNumeric.prototype,
+
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ this.type = 'number';
+ PrefNumeric.prototype.decorate.call(this);
+
+ // Listen to user events.
+ this.addEventListener('input',
+ function(e) {
+ if (this.validity.valid) {
+ Preferences.setIntegerPref(self.pref, self.value, self.metric);
+ }
+ });
+ }
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PrefRange class:
+
+ // Define a constructor that uses an input element as its underlying element.
+ var PrefRange = cr.ui.define('input');
+
+ PrefRange.prototype = {
+ // Set up the prototype chain
+ __proto__: PrefNumeric.prototype,
+
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ this.type = 'range';
+ PrefNumeric.prototype.decorate.call(this);
+ var self = this;
+
+ // Additionally change the indicator as well.
+ Preferences.getInstance().addEventListener(this.pref,
+ function(event) {
+ self.updateIndicator();
+ });
+
+ // Listen to user events.
+ this.addEventListener('input',
+ function(e) {
+ this.updateIndicator();
+ });
+ },
+
+ updateIndicator: function() {
+ if ($(this.id + '-value')) {
+ $(this.id + '-value').textContent = this.value;
+ }
+ }
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PrefSelect class:
+
+ // Define a constructor that uses an select element as its underlying element.
+ var PrefSelect = cr.ui.define('select');
+
+ PrefSelect.prototype = {
+ // Set up the prototype chain
+ __proto__: HTMLSelectElement.prototype,
+
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ var self = this;
+ // Listen to pref changes.
+ Preferences.getInstance().addEventListener(this.pref,
+ function(event) {
+ var value = (event.value && event.value['value'] != undefined) ?
+ event.value['value'] : event.value;
+ self.managed = (event.value && event.value['managed'] != undefined) ?
+ event.value['managed'] : false;
+ self.disabled = self.managed;
+ for (var i = 0; i < self.options.length; i++) {
+ if (self.options[i].value == value) {
+ self.selectedIndex = i;
+ return;
+ }
}
- }
- self.selectedIndex = -1;
- });
-
- // Listen to user events.
- this.addEventListener('change',
- function(e) {
- Preferences.setStringPref(self.pref,
- self.options[self.selectedIndex].value);
- });
- },
+ // Item not found, select first item.
+ self.selectedIndex = 0;
+ });
+
+ // Listen to user events.
+ this.addEventListener('change',
+ function(e) {
+ switch(self.dataType) {
+ case 'number':
+ Preferences.setIntegerPref(self.pref,
+ self.options[self.selectedIndex].value, self.metric);
+ break;
+ case 'boolean':
+ Preferences.setBooleanValue(self.pref,
+ self.options[self.selectedIndex].value, self.metric);
+ break;
+ case 'string':
+ Preferences.setStringPref(self.pref,
+ self.options[self.selectedIndex].value, self.metric);
+ 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.
+ *
+ * TODO(zelidrag): move this to that i18n template classes.
+ */
+ initializeValues: function(options) {
+ options.forEach(function (values) {
+ if (this.dataType == undefined)
+ this.dataType = typeof values[0];
+ this.appendChild(new Option(values[1], values[0]));
+ }, this);
+ }
+ };
/**
- * 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.
- *
- * TODO(zelidrag): move this to that i18n template classes.
+ * The preference name.
+ * @type {string}
*/
- initializeValues: function(options) {
- options.forEach(function (values) {
- this.appendChild(new Option(values[1], values[0]));
- }, this);
- }
-};
+ cr.defineProperty(PrefSelect, 'pref', cr.PropertyKind.ATTR);
+
+ /**
+ * The user metric string.
+ * @type {string}
+ */
+ cr.defineProperty(PrefSelect, 'metric', cr.PropertyKind.ATTR);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PrefTextField class:
-/**
- * The preference name.
- * @type {string}
- */
-cr.defineProperty(PrefSelect, 'pref', cr.PropertyKind.ATTR);
+ // Define a constructor that uses an input element as its underlying element.
+ var PrefTextField = cr.ui.define('input');
-///////////////////////////////////////////////////////////////////////////////
-// PrefTextField class:
+ PrefTextField.prototype = {
+ // Set up the prototype chain
+ __proto__: HTMLInputElement.prototype,
-// Define a constructor that uses an input element as its underlying element.
-var PrefTextField = cr.ui.define('input');
+ /**
+ * Initialization function for the cr.ui framework.
+ */
+ decorate: function() {
+ var self = this;
-PrefTextField.prototype = {
- // Set up the prototype chain
- __proto__: HTMLInputElement.prototype,
+ // Listen to pref changes.
+ Preferences.getInstance().addEventListener(this.pref,
+ function(event) {
+ self.value = (event.value && event.value['value'] != undefined) ?
+ event.value['value'] : event.value;
+ self.managed = (event.value && event.value['managed'] != undefined) ?
+ event.value['managed'] : false;
+ self.disabled = self.managed;
+ });
+
+ // Listen to user events.
+ this.addEventListener('change',
+ function(e) {
+ Preferences.setStringPref(self.pref, self.value, self.metric);
+ });
+
+ window.addEventListener('unload',
+ function() {
+ if (document.activeElement == self)
+ self.blur();
+ });
+ }
+ };
/**
- * Initialization function for the cr.ui framework.
+ * The preference name.
+ * @type {string}
*/
- decorate: function() {
- var self = this;
-
- // Listen to pref changes.
- Preferences.getInstance().addEventListener(this.pref,
- function(event) {
- self.value = event.value;
- });
-
- // Listen to user events.
- this.addEventListener('change',
- function(e) {
- Preferences.setStringPref(self.pref, self.value);
- });
-
- window.addEventListener('unload',
- function() {
- if (document.activeElement == self)
- self.blur();
- });
- }
-};
-
-/**
- * The preference name.
- * @type {string}
- */
-cr.defineProperty(PrefTextField, 'pref', cr.PropertyKind.ATTR);
+ cr.defineProperty(PrefTextField, 'pref', cr.PropertyKind.ATTR);
+
+ /**
+ * The user metric string.
+ * @type {string}
+ */
+ cr.defineProperty(PrefTextField, 'metric', cr.PropertyKind.ATTR);
+
+ // Export
+ return {
+ PrefCheckbox: PrefCheckbox,
+ PrefNumber: PrefNumber,
+ PrefNumeric: PrefNumeric,
+ PrefRadio: PrefRadio,
+ PrefRange: PrefRange,
+ PrefSelect: PrefSelect,
+ PrefTextField: PrefTextField
+ };
+
+});
diff --git a/chrome/browser/resources/options/preferences.js b/chrome/browser/resources/options/preferences.js
index cb226bc..b641f37 100644
--- a/chrome/browser/resources/options/preferences.js
+++ b/chrome/browser/resources/options/preferences.js
@@ -2,145 +2,168 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-///////////////////////////////////////////////////////////////////////////////
-// Preferences class:
-
-/**
- * Preferences class manages access to Chrome profile preferences.
- * @constructor
- */
-function Preferences() {
-}
-
-cr.addSingletonGetter(Preferences);
-
-/**
- * Extracts preference value.
- * @param {Object} dict Map of preference values passed to fetchPrefs callback.
- * @param {string} name Preference name.
- * @return preference value.
- */
-Preferences.getPref = function (dict, name) {
- var parts = name.split('.');
- var cur = dict;
- for (var part; part = parts.shift(); ) {
- if (cur[part]) {
- cur = cur[part];
- } else {
- return null;
- }
- }
- return cur;
-};
-
-/**
- * Sets value of a boolean preference.
- * and signals its changed value.
- * @param {string} name Preference name.
- * @param {boolean} value New preference value.
- */
-Preferences.setBooleanPref = function (name, value) {
- chrome.send('setBooleanPref', [name, value ? 'true' : 'false']);
-};
-
-/**
- * Sets value of an integer preference.
- * and signals its changed value.
- * @param {string} name Preference name.
- * @param {number} value New preference value.
- */
-Preferences.setIntegerPref = function(name, value) {
- chrome.send('setIntegerPref', [name, String(value)]);
-};
-
-/**
- * Sets value of a string preference.
- * and signals its changed value.
- * @param {string} name Preference name.
- * @param {string} value New preference value.
- */
-Preferences.setStringPref = function(name, value) {
- chrome.send('setStringPref', [name, value]);
-};
-
-/**
- * Sets value of a JSON preference.
- * and signals its changed value.
- * @param {string} name Preference name.
- * @param {string} value New preference value.
- */
-Preferences.setObjectPref = function(name, value) {
- chrome.send('setObjectPref', [name, JSON.stringify(value)]);
-};
-
-Preferences.prototype = {
- __proto__: cr.EventTarget.prototype,
-
- // Map of registered preferences.
- registeredPreferences_: {},
+cr.define('options', function() {
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Preferences class:
/**
- * Adds an event listener to the target.
- * @param {string} type The name of the event.
- * @param {!Function|{handleEvent:Function}} handler The handler for the
- * event. This is called when the event is dispatched.
+ * Preferences class manages access to Chrome profile preferences.
+ * @constructor
*/
- addEventListener: function(type, handler) {
- cr.EventTarget.prototype.addEventListener.call(this, type, handler);
- this.registeredPreferences_[type] = true;
- },
+ function Preferences() {
+ }
+
+ cr.addSingletonGetter(Preferences);
/**
- * Initializes preference reading and change notifications.
+ * Extracts preference value.
+ * @param {Object} dict Map of preference values passed to fetchPrefs
+ * callback.
+ * @param {string} name Preference name.
+ * @return preference value.
*/
- initialize: function() {
- var params1 = ['Preferences.prefsFetchedCallback'];
- var params2 = ['Preferences.prefsChangedCallback'];
- for (var prefName in this.registeredPreferences_) {
- params1.push(prefName);
- params2.push(prefName);
+ Preferences.getPref = function (dict, name) {
+ var parts = name.split('.');
+ var cur = dict;
+ for (var part; part = parts.shift(); ) {
+ if (cur[part]) {
+ cur = cur[part];
+ } else {
+ return null;
+ }
}
- chrome.send('fetchPrefs', params1);
- chrome.send('observePrefs', params2);
- },
+ return cur;
+ };
/**
- * Helper function for flattening of dictionary passed via fetchPrefs
- * callback.
- * @param {string} prefix Preference name prefix.
- * @param {object} dict Map with preference values.
+ * Sets value of a boolean preference.
+ * and signals its changed value.
+ * @param {string} name Preference name.
+ * @param {boolean} value New preference value.
+ * @param {string} metric User metrics identifier.
*/
- flattenMapAndDispatchEvent_: function(prefix, dict) {
- for (var prefName in dict) {
- if (typeof dict[prefName] == 'object' &&
- !this.registeredPreferences_[prefix + prefName]) {
- this.flattenMapAndDispatchEvent_(prefix + prefName + '.',
- dict[prefName]);
- } else {
- var event = new cr.Event(prefix + prefName);
- event.value = dict[prefName];
- this.dispatchEvent(event);
+ Preferences.setBooleanPref = function (name, value, metric) {
+ var arguments = [name, value ? 'true' : 'false'];
+ if (metric != undefined) arguments.push(metric);
+ chrome.send('setBooleanPref', arguments);
+ };
+
+ /**
+ * Sets value of an integer preference.
+ * and signals its changed value.
+ * @param {string} name Preference name.
+ * @param {number} value New preference value.
+ * @param {string} metric User metrics identifier.
+ */
+ Preferences.setIntegerPref = function(name, value, metric) {
+ var arguments = [name, String(value)];
+ if (metric != undefined) arguments.push(metric);
+ chrome.send('setIntegerPref', arguments);
+ };
+
+ /**
+ * Sets value of a string preference.
+ * and signals its changed value.
+ * @param {string} name Preference name.
+ * @param {string} value New preference value.
+ * @param {string} metric User metrics identifier.
+ */
+ Preferences.setStringPref = function(name, value, metric) {
+ var arguments = [name, value];
+ if (metric != undefined) arguments.push(metric);
+ chrome.send('setStringPref', arguments);
+ };
+
+ /**
+ * Sets value of a JSON preference.
+ * and signals its changed value.
+ * @param {string} name Preference name.
+ * @param {string} value New preference value.
+ * @param {string} metric User metrics identifier.
+ */
+ Preferences.setObjectPref = function(name, value, metric) {
+ var arguments = [name, JSON.stringify(value)];
+ if (metric != undefined) arguments.push(metric);
+ chrome.send('setObjectPref', arguments);
+ };
+
+ Preferences.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ // Map of registered preferences.
+ registeredPreferences_: {},
+
+ /**
+ * Adds an event listener to the target.
+ * @param {string} type The name of the event.
+ * @param {!Function|{handleEvent:Function}} handler The handler for the
+ * event. This is called when the event is dispatched.
+ */
+ addEventListener: function(type, handler) {
+ cr.EventTarget.prototype.addEventListener.call(this, type, handler);
+ this.registeredPreferences_[type] = true;
+ },
+
+ /**
+ * Initializes preference reading and change notifications.
+ */
+ initialize: function() {
+ var params1 = ['Preferences.prefsFetchedCallback'];
+ var params2 = ['Preferences.prefsChangedCallback'];
+ for (var prefName in this.registeredPreferences_) {
+ params1.push(prefName);
+ params2.push(prefName);
+ }
+ chrome.send('fetchPrefs', params1);
+ chrome.send('observePrefs', params2);
+ },
+
+ /**
+ * Helper function for flattening of dictionary passed via fetchPrefs
+ * callback.
+ * @param {string} prefix Preference name prefix.
+ * @param {object} dict Map with preference values.
+ */
+ flattenMapAndDispatchEvent_: function(prefix, dict) {
+ for (var prefName in dict) {
+ if (typeof dict[prefName] == 'object' &&
+ !this.registeredPreferences_[prefix + prefName]) {
+ this.flattenMapAndDispatchEvent_(prefix + prefName + '.',
+ dict[prefName]);
+ } else {
+ var event = new cr.Event(prefix + prefName);
+ event.value = dict[prefName];
+ this.dispatchEvent(event);
+ }
}
}
- }
-};
-
-/**
- * Callback for fetchPrefs method.
- * @param {object} dict Map of fetched property values.
- */
-Preferences.prefsFetchedCallback = function(dict) {
- Preferences.getInstance().flattenMapAndDispatchEvent_('', dict);
-};
-
-/**
- * Callback for observePrefs method.
- * @param {array} notification An array defining changed preference values.
- * notification[0] contains name of the change preference while its new value
- * is stored in notification[1].
- */
-Preferences.prefsChangedCallback = function(notification) {
- var event = new cr.Event(notification[0]);
- event.value = notification[1];
- Preferences.getInstance().dispatchEvent(event);
-};
+ };
+
+ /**
+ * Callback for fetchPrefs method.
+ * @param {object} dict Map of fetched property values.
+ */
+ Preferences.prefsFetchedCallback = function(dict) {
+ Preferences.getInstance().flattenMapAndDispatchEvent_('', dict);
+ };
+
+ /**
+ * Callback for observePrefs method.
+ * @param {array} notification An array defining changed preference values.
+ * notification[0] contains name of the change preference while its new value
+ * is stored in notification[1].
+ */
+ Preferences.prefsChangedCallback = function(notification) {
+ var event = new cr.Event(notification[0]);
+ event.value = notification[1];
+ Preferences.getInstance().dispatchEvent(event);
+ };
+
+ // Export
+ return {
+ Preferences: Preferences
+ };
+
+});
+
diff --git a/chrome/browser/resources/options/sync_options.html b/chrome/browser/resources/options/sync_options.html
index b6d85fa..a503d78 100644
--- a/chrome/browser/resources/options/sync_options.html
+++ b/chrome/browser/resources/options/sync_options.html
@@ -12,14 +12,6 @@
i18n-content="syncbookmarks"></span></label></td>
</tr>
<tr>
- <td class="option-name"><label><input id="typedurls-check"
- pref="sync.typed_urls" type="checkbox"><span
- i18n-content="synctypedurls"></span></label></td>
- <td class="option-name"><label><input id="passwords-check"
- pref="sync.passwords" type="checkbox"><span
- i18n-content="syncpasswords"></span></label></td>
- </tr>
- <tr>
<td class="option-name"><label><input id="extensions-check"
pref="sync.extensions" type="checkbox"><span
i18n-content="syncextensions"></span></label></td>
@@ -31,6 +23,17 @@
<td class="option-name"><label><input id="themes-check"
pref="sync.themes" type="checkbox"><span
i18n-content="syncthemes"></span></label></td>
+ <td class="option-name"><label><input id="apps-check"
+ pref="sync.apps" type="checkbox"><span
+ i18n-content="syncapps"></span><label></td>
+ </tr>
+ <tr>
+ <td class="option-name"><label><input id="typedurls-check"
+ pref="sync.typed_urls" type="checkbox"><span
+ i18n-content="synctypedurls"></span></label></td>
+ <td class="option-name"><label><input id="passwords-check"
+ pref="sync.passwords" type="checkbox"><span
+ i18n-content="syncpasswords"></span></label></td>
</tr>
</table>
</section>
diff --git a/chrome/browser/resources/playlist.html b/chrome/browser/resources/playlist.html
index 52aa594..598844c 100644
--- a/chrome/browser/resources/playlist.html
+++ b/chrome/browser/resources/playlist.html
@@ -76,6 +76,12 @@ function pathIsAudioFile(path) {
var currentPlaylist = null;
var currentOffset = -1;
function load() {
+ document.body.addEventListener('dragover', function(e) {
+ if (e.preventDefault) e.preventDefault();
+ });
+ document.body.addEventListener('drop', function(e) {
+ if (e.preventDefault) e.preventDefault();
+ });
chrome.send("getCurrentPlaylist", []);
};
diff --git a/chrome/browser/resources/plugins.html b/chrome/browser/resources/plugins.html
index dbaf755..7cee567 100644
--- a/chrome/browser/resources/plugins.html
+++ b/chrome/browser/resources/plugins.html
@@ -4,7 +4,6 @@
<meta charset="utf-8">
<title i18n-content="pluginsTitle"></title>
<style>
-
body {
margin: 10px;
min-width: 47em;
@@ -17,11 +16,14 @@ a {
div#header {
margin-bottom: 1.05em;
+ /* 67px is the height of the header's background image. */
+ min-height: 67px;
overflow: hidden;
- padding-bottom: 1.5em;
+ padding-bottom: 20px;
padding-left: 0;
- padding-top: 1.5em;
+ padding-top: 20px;
position: relative;
+ -webkit-box-sizing: border-box;
}
html[dir=rtl] #header {
@@ -421,7 +423,6 @@ function handleEnablePlugin(node, enable, isGroup) {
// Tell the C++ PluginsDOMHandler to enable/disable the plugin.
chrome.send('enablePlugin', [String(node.path), String(enable),
String(isGroup)]);
- requestPluginsData();
}
// Keeps track of whether details have been made visible (expanded) or not.
@@ -579,28 +580,27 @@ document.addEventListener('DOMContentLoaded', requestPluginsData);
<td>
<span jsdisplay="enabledMode == 'disabledByUser'"
i18n-content="pluginDisabled">(DISABLED)</span>
- <span>
<span jsdisplay="enabledMode == 'disabledByPolicy'"
i18n-content="pluginDisabled">(DISABLED_BY_POLICY)</span>
<span>
- <a
- jsvalues=".path:name"
- jsdisplay="enabledMode == 'enabled'"
- onclick="handleEnablePlugin(this, false, false)"
- href="javascript:void(0);"
- i18n-content="disable"
- >DISABLE</a>
- <a
- jsvalues=".path:name"
- jsdisplay="enabledMode == 'disabledByUser'"
- onclick="handleEnablePlugin(this, true, false)"
- href="javascript:void(0);"
- i18n-content="enable"
- >ENABLE</a>
- <span
- jsdisplay="enabledMode == 'disabledByPolicy'"
- i18n-content="pluginCannotBeEnabledDueToPolicy"
- >CANNOT_ENABLE</span>
+ <a
+ jsvalues=".path:path"
+ jsdisplay="enabledMode == 'enabled'"
+ onclick="handleEnablePlugin(this, false, false)"
+ href="javascript:void(0);"
+ i18n-content="disable"
+ >DISABLE</a>
+ <a
+ jsvalues=".path:path"
+ jsdisplay="enabledMode == 'disabledByUser'"
+ onclick="handleEnablePlugin(this, true, false)"
+ href="javascript:void(0);"
+ i18n-content="enable"
+ >ENABLE</a>
+ <span
+ jsdisplay="enabledMode == 'disabledByPolicy'"
+ i18n-content="pluginCannotBeEnabledDueToPolicy"
+ >CANNOT_ENABLE</span>
</span>
</td>
</tr></table></div>
diff --git a/chrome/browser/resources/shared/css/list.css b/chrome/browser/resources/shared/css/list.css
index 60cad42..65b16e6 100644
--- a/chrome/browser/resources/shared/css/list.css
+++ b/chrome/browser/resources/shared/css/list.css
@@ -5,6 +5,7 @@ list {
overflow: auto;
position: relative; /* Make sure that item offsets are relative to the
list. */
+ height: 200px;
}
list > * {
diff --git a/chrome/browser/resources/shared/css/menu.css b/chrome/browser/resources/shared/css/menu.css
index 9ee83e6..19f5248 100644
--- a/chrome/browser/resources/shared/css/menu.css
+++ b/chrome/browser/resources/shared/css/menu.css
@@ -1,17 +1,17 @@
menu {
display: none;
- position: absolute;
+ position: fixed;
border: 1px solid rgba(0, 0, 0, .50);
-webkit-box-shadow: 0px 2px 4px rgba(0, 0, 0, .50);
color: black;
background: -webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#eee));
left: 0;
white-space: nowrap;
- z-index: 2;
padding: 8px 0;
margin: 0;
cursor: default;
border-radius: 3px;
+ z-index: 3;
}
menu > * {
@@ -49,11 +49,28 @@ menu > [hidden] {
display: none;
}
-menu > [selected] {
+menu > :not(hr)[selected] {
background-color: #dce5fa;
}
-menu > [selected]:active {
+menu > :not(hr)[selected]:active {
background-color: #426dc9;
color: #fff;
}
+
+menu > [checked]:before {
+ content: url("../images/checkbox_black.png");
+ width: 9px;
+ height: 9px;
+ display: inline-block;
+ vertical-align: 50%;
+ margin: 0 5px;
+}
+
+menu > [checked] {
+ -webkit-padding-start: 0;
+}
+
+menu > [selected][checked]:active:before {
+ content: url("../images/checkbox_white.png");
+} \ No newline at end of file
diff --git a/chrome/browser/resources/shared/js/cr.js b/chrome/browser/resources/shared/js/cr.js
index 3c3a37e..25ba498 100644
--- a/chrome/browser/resources/shared/js/cr.js
+++ b/chrome/browser/resources/shared/js/cr.js
@@ -248,37 +248,6 @@ const cr = (function() {
}
/**
- * Partially applies this function to a particular 'this object' and zero or
- * more arguments. The result is a new function with some arguments of the
- * first function pre-filled and the value of |this| 'pre-specified'.
- *
- * Remaining arguments specified at call-time are appended to the pre-
- * specified ones.
- *
- * Usage:
- * <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2');
- * barMethBound('arg3', 'arg4');</pre>
- *
- * @param {Function} fn A function to partially apply.
- * @param {Object|undefined} selfObj Specifies the object which |this| should
- * point to when the function is run. If the value is null or undefined,
- * it will default to the global object.
- * @param {...*} var_args Additional arguments that are partially
- * applied to the function.
- *
- * @return {!Function} A partially-applied form of the function bind() was
- * invoked as a method of.
- */
- function bind(fn, selfObj, var_args) {
- var boundArgs = Array.prototype.slice.call(arguments, 2);
- return function() {
- var args = Array.prototype.slice.call(arguments);
- args.unshift.apply(args, boundArgs);
- return fn.apply(selfObj, args);
- }
- }
-
- /**
* Dispatches a simple event on an event target.
* @param {!EventTarget} target The event target to dispatch the event on.
* @param {string} type The type of the event.
@@ -300,8 +269,14 @@ const cr = (function() {
function define(name, fun) {
var obj = exportPath(name);
var exports = fun();
- for (var key in exports) {
- obj[key] = exports[key];
+ for (var propertyName in exports) {
+ // Maybe we should check the prototype chain here? The current usage
+ // pattern is always using an object literal so we only care about own
+ // properties.
+ var propertyDescriptor = Object.getOwnPropertyDescriptor(exports,
+ propertyName);
+ if (propertyDescriptor)
+ Object.defineProperty(obj, propertyName, propertyDescriptor);
}
}
@@ -349,7 +324,6 @@ const cr = (function() {
PropertyKind: PropertyKind,
createUid: createUid,
getUid: getUid,
- bind: bind,
dispatchSimpleEvent: dispatchSimpleEvent,
dispatchPropertyChange: dispatchPropertyChange,
diff --git a/chrome/browser/resources/shared/js/cr/ui.js b/chrome/browser/resources/shared/js/cr/ui.js
index d87c04a..ea286b2 100644
--- a/chrome/browser/resources/shared/js/cr/ui.js
+++ b/chrome/browser/resources/shared/js/cr/ui.js
@@ -133,20 +133,8 @@ cr.define('cr.ui', function() {
var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) :
parseInt(parentComputedStyle.paddingRight, 10);
- // The magic number 14 comes from trial and error :'( It consists of:
- // border + padding + treeItem.paddingEnd + treeItem.borderEnd +
- // tree.paddingEnd
var max = parentEl.clientWidth - startPos - inner - parentPadding;
- var pcs = getComputedStyle(parentEl);
- console.log('pcs', 'borderLeft', pcs.borderLeftWidth,
- 'paddingLeft', pcs.paddingLeft,
- 'paddingRight', pcs.paddingRight,
- 'borderRight', pcs.borderRightWidth,
- 'width', pcs.width,
- 'clientWidth', parentEl.clientWidth,
- 'offsetWidth', parentEl.offsetWidth);
-
function limit() {
if (el.scrollWidth > max) {
el.style.width = max + 'px';
diff --git a/chrome/browser/resources/shared/js/cr/ui/array_data_model.js b/chrome/browser/resources/shared/js/cr/ui/array_data_model.js
index b70f36c..64da3be 100644
--- a/chrome/browser/resources/shared/js/cr/ui/array_data_model.js
+++ b/chrome/browser/resources/shared/js/cr/ui/array_data_model.js
@@ -88,6 +88,21 @@ cr.define('cr.ui', function() {
},
/**
+ * Appends items to the end of the model.
+ *
+ * This dispatches a splice event.
+ *
+ * @param {...*} The items to append.
+ * @return {number} The new length of the model.
+ */
+ push: function(var_args) {
+ var args = Array.prototype.slice.call(arguments);
+ args.unshift(this.length, 0);
+ this.splice.apply(this, args);
+ return this.length;
+ },
+
+ /**
* Use this to update a given item in the array. This does not remove and
* reinsert a new item.
*
diff --git a/chrome/browser/resources/shared/js/cr/ui/command.js b/chrome/browser/resources/shared/js/cr/ui/command.js
index 4df2275..61294f3 100644
--- a/chrome/browser/resources/shared/js/cr/ui/command.js
+++ b/chrome/browser/resources/shared/js/cr/ui/command.js
@@ -172,6 +172,12 @@ cr.define('cr.ui', function() {
cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR);
/**
+ * Whether the command is checked or not.
+ * @type {boolean}
+ */
+ cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR);
+
+ /**
* Dispatches a canExecute event on the target.
* @param {cr.ui.Command} command The command that we are testing for.
* @param {Element} target The target element to dispatch the event on.
@@ -194,10 +200,10 @@ cr.define('cr.ui', function() {
* @constructor
*/
function CommandManager(doc) {
- doc.addEventListener('focus', cr.bind(this.handleFocus_, this), true);
+ doc.addEventListener('focus', this.handleFocus_.bind(this), true);
// Make sure we add the listener to the bubbling phase so that elements can
// prevent the command.
- doc.addEventListener('keydown', cr.bind(this.handleKeyDown_, this), false);
+ doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false);
}
/**
@@ -282,7 +288,7 @@ cr.define('cr.ui', function() {
return this.canExecute_;
},
set canExecute(canExecute) {
- this.canExecute_ = canExecute;
+ this.canExecute_ = !!canExecute;
this.stopPropagation();
}
};
diff --git a/chrome/browser/resources/shared/js/cr/ui/context_menu_handler.js b/chrome/browser/resources/shared/js/cr/ui/context_menu_handler.js
index 50eb64a..e3e2fd5 100644
--- a/chrome/browser/resources/shared/js/cr/ui/context_menu_handler.js
+++ b/chrome/browser/resources/shared/js/cr/ui/context_menu_handler.js
@@ -5,6 +5,7 @@
cr.define('cr.ui', function() {
const positionPopupAtPoint = cr.ui.positionPopupAtPoint;
+ const Menu = cr.ui.Menu;
/**
* Handles context menus.
@@ -39,6 +40,7 @@ cr.define('cr.ui', function() {
doc.addEventListener('mousedown', this, true);
doc.addEventListener('blur', this, true);
doc.defaultView.addEventListener('resize', this);
+ menu.addEventListener('contextmenu', this);
menu.addEventListener('activate', this);
this.positionMenu_(e, menu);
},
@@ -57,6 +59,7 @@ cr.define('cr.ui', function() {
doc.removeEventListener('mousedown', this, true);
doc.removeEventListener('blur', this, true);
doc.defaultView.removeEventListener('resize', this);
+ menu.removeEventListener('contextmenu', this);
menu.removeEventListener('activate', this);
menu.selectedIndex = -1;
this.menu_ = null;
@@ -64,7 +67,7 @@ cr.define('cr.ui', function() {
// On windows we might hide the menu in a right mouse button up and if
// that is the case we wait some short period before we allow the menu
// to be shown again.
- this.hideTimestamp_ = Date.now();
+ this.hideTimestamp_ = cr.isWindows ? Date.now() : 0;
},
/**
diff --git a/chrome/browser/resources/shared/js/cr/ui/list.js b/chrome/browser/resources/shared/js/cr/ui/list.js
index 032d280..1ac2f9c 100644
--- a/chrome/browser/resources/shared/js/cr/ui/list.js
+++ b/chrome/browser/resources/shared/js/cr/ui/list.js
@@ -10,6 +10,7 @@
cr.define('cr.ui', function() {
const ListSelectionModel = cr.ui.ListSelectionModel;
+ const ListSelectionController = cr.ui.ListSelectionController;
const ArrayDataModel = cr.ui.ArrayDataModel;
/**
@@ -91,9 +92,9 @@ cr.define('cr.ui', function() {
if (this.dataModel_ != dataModel) {
if (!this.boundHandleDataModelSplice_) {
this.boundHandleDataModelSplice_ =
- cr.bind(this.handleDataModelSplice_, this);
+ this.handleDataModelSplice_.bind(this);
this.boundHandleDataModelChange_ =
- cr.bind(this.handleDataModelChange_, this);
+ this.handleDataModelChange_.bind(this);
}
if (this.dataModel_) {
@@ -138,8 +139,8 @@ cr.define('cr.ui', function() {
return;
if (!this.boundHandleOnChange_) {
- this.boundHandleOnChange_ = cr.bind(this.handleOnChange_, this);
- this.boundHandleLeadChange_ = cr.bind(this.handleLeadChange_, this);
+ this.boundHandleOnChange_ = this.handleOnChange_.bind(this);
+ this.boundHandleLeadChange_ = this.handleLeadChange_.bind(this);
}
if (oldSm) {
@@ -149,6 +150,7 @@ cr.define('cr.ui', function() {
}
this.selectionModel_ = sm;
+ this.selectionController_ = this.createSelectionController(sm);
if (sm) {
sm.addEventListener('change', this.boundHandleOnChange_);
@@ -240,7 +242,7 @@ cr.define('cr.ui', function() {
this.addEventListener('mousedown', this.handleMouseDownUp_);
this.addEventListener('mouseup', this.handleMouseDownUp_);
this.addEventListener('keydown', this.handleKeyDown);
- this.addEventListener('scroll', cr.bind(this.redraw, this));
+ this.addEventListener('scroll', this.redraw.bind(this));
// Make list focusable
if (!this.hasAttribute('tabindex'))
@@ -265,13 +267,13 @@ cr.define('cr.ui', function() {
}
if (!target) {
- this.selectionModel.handleMouseDownUp(e, -1);
+ 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.selectionModel.handleMouseDownUp(e, index);
+ this.selectionController_.handleMouseDownUp(e, index);
}
},
@@ -281,7 +283,7 @@ cr.define('cr.ui', function() {
* @return {boolean} Whether the key event was handled.
*/
handleKeyDown: function(e) {
- return this.selectionModel.handleKeyDown(e);
+ return this.selectionController_.handleKeyDown(e);
},
/**
@@ -418,6 +420,16 @@ cr.define('cr.ui', function() {
},
/**
+ * Creates the selection controller to use internally.
+ * @param {cr.ui.ListSelectionModel} sm The underlying selection model.
+ * @return {!cr.ui.ListSelectionModel} The newly created selection
+ * controller.
+ */
+ createSelectionController: function(sm) {
+ return new ListSelectionController(sm);
+ },
+
+ /**
* Redraws the viewport.
*/
redraw: function() {
diff --git a/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js b/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js
index 9ed0c0a..59485f7 100644
--- a/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js
+++ b/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js
@@ -2,18 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// TODO(arv): Refactor parts of this into a SelectionController.
-
cr.define('cr.ui', function() {
const Event = cr.Event;
const EventTarget = cr.EventTarget;
/**
- * Creates a new selection model that is to be used with lists. This is
- * implemented for vertical lists but changing the behavior for horizontal
- * lists or icon views is a matter of overriding {@code getIndexBefore},
- * {@code getIndexAfter}, {@code getIndexAbove} as well as
- * {@code getIndexBelow}.
+ * Creates a new selection model that is to be used with lists.
*
* @param {number=} opt_length The number items in the selection.
*
@@ -39,236 +33,14 @@ cr.define('cr.ui', function() {
},
/**
- * Returns the index below (y axis) the given element.
- * @param {*} index The index to get the index below.
- * @return {*} The index below or -1 if not found.
- */
- getIndexBelow: function(index) {
- if (index == this.getLastIndex())
- return -1;
- return index + 1;
- },
-
- /**
- * Returns the index above (y axis) the given element.
- * @param {*} index The index to get the index above.
- * @return {*} The index below or -1 if not found.
- */
- getIndexAbove: function(index) {
- return index - 1;
- },
-
- /**
- * Returns the index before (x axis) the given element. This returns -1
- * by default but override this for icon view and horizontal selection
- * models.
- *
- * @param {*} index The index to get the index before.
- * @return {*} The index before or -1 if not found.
- */
- getIndexBefore: function(index) {
- return -1;
- },
-
- /**
- * Returns the index after (x axis) the given element. This returns -1
- * by default but override this for icon view and horizontal selection
- * models.
- *
- * @param {*} index The index to get the index after.
- * @return {*} The index after or -1 if not found.
- */
- getIndexAfter: function(index) {
- return -1;
- },
-
- /**
- * Returns the next list index. This is the next logical and should not
- * depend on any kind of layout of the list.
- * @param {*} index The index to get the next index for.
- * @return {*} The next index or -1 if not found.
- */
- getNextIndex: function(index) {
- if (index == this.getLastIndex())
- return -1;
- return index + 1;
- },
-
- /**
- * Returns the prevous list index. This is the previous logical and should
- * not depend on any kind of layout of the list.
- * @param {*} index The index to get the previous index for.
- * @return {*} The previous index or -1 if not found.
- */
- getPreviousIndex: function(index) {
- return index - 1;
- },
-
- /**
- * @return {*} The first index.
- */
- getFirstIndex: function() {
- return 0;
- },
-
- /**
- * @return {*} The last index.
- */
- getLastIndex: function() {
- return this.length_ - 1;
- },
-
- /**
- * Called by the view when the user does a mousedown or mouseup on the list.
- * @param {!Event} e The browser mousedown event.
- * @param {*} index The index that was under the mouse pointer, -1 if none.
- */
- handleMouseDownUp: function(e, index) {
- var anchorIndex = this.anchorIndex;
- var isDown = e.type == 'mousedown';
-
- this.beginChange_();
-
- if (index == -1) {
- // On Mac we always clear the selection if the user clicks a blank area.
- // On Windows, we only clear the selection if neither Shift nor Ctrl are
- // pressed.
- if (cr.isMac) {
- this.clear_();
- } else if (!isDown && !e.shiftKey && !e.ctrlKey)
- // Keep anchor and lead indexes. Note that this is intentionally
- // different than on the Mac.
- this.clearAllSelected_();
- } else {
- if (cr.isMac ? e.metaKey : e.ctrlKey) {
- // 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
- this.setIndexSelected(index, !this.getIndexSelected(index));
- this.leadIndex = index;
- this.anchorIndex = index;
- }
- } else if (e.shiftKey && anchorIndex != -1 && anchorIndex != index) {
- // Shift is done in mousedown
- if (isDown) {
- this.clearAllSelected_();
- this.leadIndex = index;
- this.selectRange(anchorIndex, index);
- }
- } else {
- // Right click for a context menu need to not clear the selection.
- var isRightClick = e.button == 2;
-
- // If the index is selected this is handled in mouseup.
- var indexSelected = this.getIndexSelected(index);
- if ((indexSelected && !isDown || !indexSelected && isDown) &&
- !(indexSelected && isRightClick)) {
- this.clearAllSelected_();
- this.setIndexSelected(index, true);
- this.leadIndex = index;
- this.anchorIndex = index;
- }
- }
- }
-
- this.endChange_();
- },
-
- /**
- * Called by the view when it recieves a keydown event.
- * @param {Event} e The keydown event.
- */
- handleKeyDown: function(e) {
- var newIndex = -1;
- var leadIndex = this.leadIndex;
- var prevent = true;
-
- // Ctrl/Meta+A
- if (e.keyCode == 65 &&
- (cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey)) {
- this.selectAll();
- e.preventDefault();
- return;
- }
-
- // Space
- if (e.keyCode == 32) {
- if (leadIndex != -1) {
- var selected = this.getIndexSelected(leadIndex);
- if (e.ctrlKey || !selected) {
- this.beginChange_();
- this.setIndexSelected(leadIndex, !selected);
- this.endChange_();
- return;
- }
- }
- }
-
- switch (e.keyIdentifier) {
- case 'Home':
- newIndex = this.getFirstIndex();
- break;
- case 'End':
- newIndex = this.getLastIndex();
- break;
- case 'Up':
- newIndex = leadIndex == -1 ?
- this.getLastIndex() : this.getIndexAbove(leadIndex);
- break;
- case 'Down':
- newIndex = leadIndex == -1 ?
- this.getFirstIndex() : this.getIndexBelow(leadIndex);
- break;
- case 'Left':
- newIndex = leadIndex == -1 ?
- this.getLastIndex() : this.getIndexBefore(leadIndex);
- break;
- case 'Right':
- newIndex = leadIndex == -1 ?
- this.getFirstIndex() : this.getIndexAfter(leadIndex);
- break;
- default:
- prevent = false;
- }
-
- if (newIndex != -1) {
- this.beginChange_();
-
- this.leadIndex = newIndex;
- if (e.shiftKey) {
- var anchorIndex = this.anchorIndex;
- this.clearAllSelected_();
- if (anchorIndex == -1) {
- this.setIndexSelected(newIndex, true);
- this.anchorIndex = newIndex;
- } else {
- this.selectRange(anchorIndex, newIndex);
- }
- } else if (e.ctrlKey && !cr.isMac) {
- // Setting the lead index is done above
- // Mac does not allow you to change the lead.
- } else {
- this.clearAllSelected_();
- this.setIndexSelected(newIndex, true);
- this.anchorIndex = newIndex;
- }
-
- this.endChange_();
-
- if (prevent)
- e.preventDefault();
- }
- },
-
- /**
* @type {!Array} The selected indexes.
*/
get selectedIndexes() {
return Object.keys(this.selectedIndexes_).map(Number);
},
set selectedIndexes(selectedIndexes) {
- this.beginChange_();
- this.clearAllSelected_();
+ this.beginChange();
+ this.unselectAll();
for (var i = 0; i < selectedIndexes.length; i++) {
this.setIndexSelected(selectedIndexes[i], true);
}
@@ -277,12 +49,12 @@ cr.define('cr.ui', function() {
} else {
this.leadIndex = this.anchorIndex = -1;
}
- this.endChange_();
+ this.endChange();
},
/**
* Convenience getter which returns the first selected index.
- * @type {*}
+ * @type {number}
*/
get selectedIndex() {
for (var i in this.selectedIndexes_) {
@@ -291,21 +63,21 @@ cr.define('cr.ui', function() {
return -1;
},
set selectedIndex(selectedIndex) {
- this.beginChange_();
- this.clearAllSelected_();
+ this.beginChange();
+ this.unselectAll();
if (selectedIndex != -1) {
this.selectedIndexes = [selectedIndex];
} else {
this.leadIndex = this.anchorIndex = -1;
}
- this.endChange_();
+ this.endChange();
},
/**
* Selects a range of indexes, starting with {@code start} and ends with
* {@code end}.
- * @param {*} start The first index to select.
- * @param {*} end The last index to select.
+ * @param {number} start The first index to select.
+ * @param {number} end The last index to select.
*/
selectRange: function(start, end) {
// Swap if starts comes after end.
@@ -315,55 +87,48 @@ cr.define('cr.ui', function() {
end = tmp;
}
- this.beginChange_();
+ this.beginChange();
for (var index = start; index != end; index++) {
this.setIndexSelected(index, true);
}
this.setIndexSelected(end, true);
- this.endChange_();
+ this.endChange();
},
/**
* Selects all indexes.
*/
selectAll: function() {
- this.selectRange(this.getFirstIndex(), this.getLastIndex());
+ this.selectRange(0, this.length - 1);
},
/**
* Clears the selection
*/
clear: function() {
- this.beginChange_();
+ this.beginChange();
this.length_ = 0;
- this.clear_();
- this.endChange_();
- },
-
- /**
- * Clears all selected as well as the lead and anchor index.
- * @private
- */
- clear_: function() {
this.anchorIndex = this.leadIndex = -1;
- this.clearAllSelected_();
+ this.unselectAll();
+ this.endChange();
},
/**
- * Clears the selection and updates the view.
- * @private
+ * Unselects all selected items.
*/
- clearAllSelected_: function() {
+ unselectAll: function() {
+ this.beginChange();
for (var i in this.selectedIndexes_) {
this.setIndexSelected(i, false);
}
+ this.endChange();
},
/**
* Sets the selected state for an index.
- * @param {*} index The index to set the selected state for.
+ * @param {number} index The index to set the selected state for.
* @param {boolean} b Whether to select the index or not.
*/
setIndexSelected: function(index, b) {
@@ -376,7 +141,7 @@ cr.define('cr.ui', function() {
else
delete this.selectedIndexes_[index];
- this.beginChange_();
+ this.beginChange();
// Changing back?
if (index in this.changedIndexes_ && this.changedIndexes_[index] == !b) {
@@ -386,12 +151,12 @@ cr.define('cr.ui', function() {
}
// End change dispatches an event which in turn may update the view.
- this.endChange_();
+ this.endChange();
},
/**
* Whether a given index is selected or not.
- * @param {*} index The index to check.
+ * @param {number} index The index to check.
* @return {boolean} Whether an index is selected.
*/
getIndexSelected: function(index) {
@@ -399,11 +164,10 @@ cr.define('cr.ui', function() {
},
/**
- * This is used to begin batching changes. Call {@code endChange_} when you
+ * This is used to begin batching changes. Call {@code endChange} when you
* are done making changes.
- * @private
*/
- beginChange_: function() {
+ beginChange: function() {
if (!this.changeCount_) {
this.changeCount_ = 0;
this.changedIndexes_ = {};
@@ -414,9 +178,8 @@ cr.define('cr.ui', function() {
/**
* Call this after changes are done and it will dispatch a change event if
* any changes were actually done.
- * @private
*/
- endChange_: function() {
+ endChange: function() {
this.changeCount_--;
if (!this.changeCount_) {
var indexes = Object.keys(this.changedIndexes_);
@@ -430,8 +193,7 @@ cr.define('cr.ui', function() {
}, this);
this.dispatchEvent(e);
}
- delete this.changedIndexes_;
- delete this.changeCount_;
+ this.changedIndexes_ = {};
}
},
@@ -440,7 +202,7 @@ cr.define('cr.ui', function() {
/**
* The leadIndex is used with multiple selection and it is the index that
* the user is moving using the arrow keys.
- * @type {*}
+ * @type {number}
*/
get leadIndex() {
return this.leadIndex_;
@@ -458,7 +220,7 @@ cr.define('cr.ui', function() {
/**
* The anchorIndex is used with multiple selection.
- * @type {*}
+ * @type {number}
*/
get anchorIndex() {
return this.anchorIndex_;
@@ -473,6 +235,14 @@ cr.define('cr.ui', function() {
},
/**
+ * Whether the selection model supports multiple selected items.
+ * @type {boolean}
+ */
+ get multiple() {
+ return true;
+ },
+
+ /**
* Adjust the selection by adding or removing a certain numbers of items.
* This should be called by the owner of the selection model as items are
* added and removed from the underlying data model.
@@ -482,10 +252,10 @@ cr.define('cr.ui', function() {
*/
adjust: function(index, itemsRemoved, itemsAdded) {
function getNewAdjustedIndex(i) {
- if (i > index && i < index + itemsRemoved) {
+ if (i >= index && i < index + itemsRemoved) {
return index
} else if (i >= index) {
- return i + itemsAdded - itemsRemoved;
+ return i - itemsRemoved + itemsAdded;
}
return i;
}
@@ -494,12 +264,13 @@ cr.define('cr.ui', function() {
var newMap = [];
for (var i in this.selectedIndexes_) {
+ i = Number(i);
if (i < index) {
newMap[i] = true;
} else if (i < index + itemsRemoved) {
// noop
} else {
- newMap[Number(i) + itemsAdded - itemsRemoved] = true;
+ newMap[i + itemsAdded - itemsRemoved] = true;
}
}
this.selectedIndexes_ = newMap;
diff --git a/chrome/browser/resources/shared/js/cr/ui/list_selection_model_test.html b/chrome/browser/resources/shared/js/cr/ui/list_selection_model_test.html
index 9e77aa1..2484b63 100644
--- a/chrome/browser/resources/shared/js/cr/ui/list_selection_model_test.html
+++ b/chrome/browser/resources/shared/js/cr/ui/list_selection_model_test.html
@@ -120,7 +120,7 @@ function testAdjust8() {
var sm = createSelectionModel(100);
sm.leadIndex = sm.anchorIndex = 50;
- sm.selectAll(0, 99);
+ sm.selectAll();
sm.adjust(10, 80, 0);
diff --git a/chrome/browser/resources/shared/js/cr/ui/menu_item.js b/chrome/browser/resources/shared/js/cr/ui/menu_item.js
index d570f78..c3e3169 100644
--- a/chrome/browser/resources/shared/js/cr/ui/menu_item.js
+++ b/chrome/browser/resources/shared/js/cr/ui/menu_item.js
@@ -52,6 +52,7 @@ cr.define('cr.ui', function() {
this.command_.removeEventListener('labelChange', this);
this.command_.removeEventListener('disabledChange', this);
this.command_.removeEventListener('hiddenChange', this);
+ this.command_.removeEventListener('checkedChange', this);
}
if (typeof command == 'string' && command[0] == '#') {
@@ -71,6 +72,7 @@ cr.define('cr.ui', function() {
this.command_.addEventListener('labelChange', this);
this.command_.addEventListener('disabledChange', this);
this.command_.addEventListener('hiddenChange', this);
+ this.command_.addEventListener('checkedChange', this);
}
},
@@ -124,6 +126,9 @@ cr.define('cr.ui', function() {
case 'labelChange':
this.label = this.command.label;
break;
+ case 'checkedChange':
+ this.checked = this.command.checked;
+ break;
}
}
};
@@ -146,6 +151,12 @@ cr.define('cr.ui', function() {
*/
cr.defineProperty(MenuItem, 'selected', cr.PropertyKind.BOOL_ATTR);
+ /**
+ * Whether the menu item is checked or not.
+ * @type {boolean}
+ */
+ cr.defineProperty(MenuItem, 'checked', cr.PropertyKind.BOOL_ATTR);
+
// Export
return {
MenuItem: MenuItem
diff --git a/chrome/browser/resources/shared/js/cr/ui/position_util.js b/chrome/browser/resources/shared/js/cr/ui/position_util.js
index 85e86b2..380e9e1 100644
--- a/chrome/browser/resources/shared/js/cr/ui/position_util.js
+++ b/chrome/browser/resources/shared/js/cr/ui/position_util.js
@@ -57,10 +57,15 @@ cr.define('cr.ui', function() {
*/
function positionPopupAroundRect(anchorRect, popupElement, type) {
var popupRect = popupElement.getBoundingClientRect();
- var popupContainer = popupElement.offsetParent;
+ var popupContainer;
+ var cs = popupElement.ownerDocument.defaultView.
+ getComputedStyle(popupElement);
+ if (cs.position == 'fixed')
+ popupContainer = popupElement.ownerDocument.body;
+ else
+ popupContainer = popupElement.offsetParent;
var availRect = popupContainer.getBoundingClientRect();
- var rtl = popupElement.ownerDocument.defaultView.
- getComputedStyle(popupElement).direction == 'rtl';
+ var rtl = cs.direction == 'rtl';
// Flip BEFORE, AFTER based on RTL.
if (rtl) {
diff --git a/chrome/browser/resources/shared/js/cr/ui/splitter.js b/chrome/browser/resources/shared/js/cr/ui/splitter.js
index 4f9510e..3ede5ea 100644
--- a/chrome/browser/resources/shared/js/cr/ui/splitter.js
+++ b/chrome/browser/resources/shared/js/cr/ui/splitter.js
@@ -67,7 +67,7 @@ cr.define('cr.ui', function() {
* Initializes the element.
*/
decorate: function() {
- this.addEventListener('mousedown', cr.bind(this.handleMouseDown_, this),
+ this.addEventListener('mousedown', this.handleMouseDown_.bind(this),
true);
},
@@ -77,8 +77,8 @@ cr.define('cr.ui', function() {
*/
startDrag: function(e) {
if (!this.boundHandleMouseMove_) {
- this.boundHandleMouseMove_ = cr.bind(this.handleMouseMove_, this);
- this.boundHandleMouseUp_ = cr.bind(this.handleMouseUp_, this);
+ this.boundHandleMouseMove_ = this.handleMouseMove_.bind(this);
+ this.boundHandleMouseUp_ = this.handleMouseUp_.bind(this);
}
var doc = this.ownerDocument;
diff --git a/chrome/browser/resources/shared/js/cr/ui/tree.js b/chrome/browser/resources/shared/js/cr/ui/tree.js
index 1fa3352..598bfab 100644
--- a/chrome/browser/resources/shared/js/cr/ui/tree.js
+++ b/chrome/browser/resources/shared/js/cr/ui/tree.js
@@ -555,9 +555,9 @@ cr.define('cr.ui', function() {
labelEl.appendChild(input);
input.addEventListener('keydown', handleKeydown);
- input.addEventListener('blur', cr.bind(function() {
+ input.addEventListener('blur', (function() {
this.editing = false;
- }, this));
+ }).bind(this));
// Make sure that double clicks do not expand and collapse the tree
// item.
diff --git a/chrome/browser/resources/shared/js/cr_test.html b/chrome/browser/resources/shared/js/cr_test.html
index 43c3628..b20281c 100644
--- a/chrome/browser/resources/shared/js/cr_test.html
+++ b/chrome/browser/resources/shared/js/cr_test.html
@@ -244,6 +244,33 @@ function testAddSingletonGetter() {
x, z);
}
+function testWithDoc() {
+ var d = {};
+
+ assertEquals(document, cr.doc);
+
+ cr.withDoc(d, function() {
+ assertEquals(d, cr.doc);
+ });
+
+ assertEquals(document, cr.doc);
+}
+
+function testDefineWithGetter() {
+ var v = 0;
+ cr.define('foo', function() {
+ return {
+ get v() {
+ return v;
+ }
+ }
+ });
+
+ assertEquals(0, foo.v);
+
+ v = 1;
+ assertEquals(1, foo.v);
+}
</script>
diff --git a/chrome/browser/resources/shared/js/media_common.js b/chrome/browser/resources/shared/js/media_common.js
index 8528809..86b48c8 100644
--- a/chrome/browser/resources/shared/js/media_common.js
+++ b/chrome/browser/resources/shared/js/media_common.js
@@ -17,3 +17,7 @@ function pathIsImageFile(path) {
function pathIsHtmlFile(path) {
return /\.(htm|html|txt)$/i.test(path);
}
+
+function pathIsPdfFile(path) {
+ return /\.(pdf)$/i.test(path);
+}
diff --git a/chrome/browser/resources/shared_resources.grd b/chrome/browser/resources/shared_resources.grd
index 12a8b4a..2d79a05 100644
--- a/chrome/browser/resources/shared_resources.grd
+++ b/chrome/browser/resources/shared_resources.grd
@@ -12,6 +12,8 @@ without changes to the corresponding grd file. paaaae -->
</outputs>
<release seq="1">
<includes>
+ <include name="IDR_SHARED_CSS_ABOUT"
+ file="shared/css/about_memory.css" type="BINDATA" />
<include name="IDR_SHARED_CSS_BUTTON"
file="shared/css/button.css" type="BINDATA" />
<include name="IDR_SHARED_CSS_LIST"
@@ -46,8 +48,12 @@ without changes to the corresponding grd file. paaaae -->
file="shared/js/cr/ui/list.js" type="BINDATA" />
<include name="IDR_SHARED_JS_CR_UI_LIST_ITEM"
file="shared/js/cr/ui/list_item.js" type="BINDATA" />
+ <include name="IDR_SHARED_JS_CR_UI_LIST_SELECTION_CONTROLLER"
+ file="shared/js/cr/ui/list_selection_controller.js" type="BINDATA" />
<include name="IDR_SHARED_JS_CR_UI_LIST_SELECTION_MODEL"
file="shared/js/cr/ui/list_selection_model.js" type="BINDATA" />
+ <include name="IDR_SHARED_JS_CR_UI_LIST_SINGLE_SELECTION_MODEL"
+ file="shared/js/cr/ui/list_single_selection_model.js" type="BINDATA" />
<include name="IDR_SHARED_JS_CR_UI_MENU"
file="shared/js/cr/ui/menu.js" type="BINDATA" />
<include name="IDR_SHARED_JS_CR_UI_MENU_BUTTON"
diff --git a/chrome/browser/resources/solo.png b/chrome/browser/resources/solo.png
deleted file mode 100644
index 5f20eef..0000000
--- a/chrome/browser/resources/solo.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/visa.png b/chrome/browser/resources/visa.png
deleted file mode 100644
index 9518614..0000000
--- a/chrome/browser/resources/visa.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources_util.cc b/chrome/browser/resources_util.cc
index aefc4e3..ab2fe9d 100644
--- a/chrome/browser/resources_util.cc
+++ b/chrome/browser/resources_util.cc
@@ -1,16 +1,15 @@
-// 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.
#include "chrome/browser/resources_util.h"
+#include <utility>
+
#include "base/hash_tables.h"
#include "base/lazy_instance.h"
-#include "base/logging.h"
#include "grit/theme_resources_map.h"
-#include <utility>
-
namespace {
// A wrapper class that holds a hash_map between resource strings and resource
diff --git a/chrome/browser/resources_util.h b/chrome/browser/resources_util.h
index c1400d7..bb39973 100644
--- a/chrome/browser/resources_util.h
+++ b/chrome/browser/resources_util.h
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_THEME_RESOURCES_UTIL_H_
-#define CHROME_BROWSER_THEME_RESOURCES_UTIL_H_
+#ifndef CHROME_BROWSER_RESOURCES_UTIL_H_
+#define CHROME_BROWSER_RESOURCES_UTIL_H_
+#pragma once
#include <string>
@@ -19,4 +20,4 @@ class ResourcesUtil {
DISALLOW_COPY_AND_ASSIGN(ResourcesUtil);
};
-#endif // CHROME_BROWSER_THEME_RESOURCES_UTIL_H_
+#endif // CHROME_BROWSER_RESOURCES_UTIL_H_
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
index 685692d..840ce60 100644
--- a/chrome/browser/rlz/rlz.cc
+++ b/chrome/browser/rlz/rlz.cc
@@ -19,9 +19,11 @@
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.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/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"
@@ -164,8 +166,8 @@ class DelayedInitTask : public Task {
// For organic brandcodes do not use rlz at all. Empty brandcode usually
// means a chromium install. This is ok.
std::wstring brand;
- GoogleUpdateSettings::GetBrand(&brand);
- if (GoogleUpdateSettings::IsOrganic(brand))
+ if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() ||
+ GoogleUpdateSettings::IsOrganic(brand))
return;
// Do the initial event recording if is the first run or if we have an
diff --git a/chrome/browser/rlz/rlz.h b/chrome/browser/rlz/rlz.h
index 8085f4d..fae3eca 100644
--- a/chrome/browser/rlz/rlz.h
+++ b/chrome/browser/rlz/rlz.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_RLZ_RLZ_H_
#define CHROME_BROWSER_RLZ_RLZ_H_
+#pragma once
#include "build/build_config.h"
diff --git a/chrome/browser/safe_browsing/bloom_filter.cc b/chrome/browser/safe_browsing/bloom_filter.cc
index 3d9772d..62b0692 100644
--- a/chrome/browser/safe_browsing/bloom_filter.cc
+++ b/chrome/browser/safe_browsing/bloom_filter.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.
@@ -31,6 +31,14 @@ uint32 HashMix(BloomFilter::HashKey hash_key, uint32 c) {
} // namespace
+// static
+int BloomFilter::FilterSizeForKeyCount(int key_count) {
+ const int default_min = BloomFilter::kBloomFilterMinSize;
+ const int number_of_keys = std::max(key_count, default_min);
+ return std::min(number_of_keys * BloomFilter::kBloomFilterSizeRatio,
+ BloomFilter::kBloomFilterMaxSize * 8);
+}
+
BloomFilter::BloomFilter(int bit_size) {
for (int i = 0; i < kNumHashKeys; ++i)
hash_keys_.push_back(base::RandUint64());
@@ -115,7 +123,7 @@ BloomFilter* BloomFilter::LoadFile(const FilePath& filter_name) {
return new BloomFilter(data.release(), byte_size, hash_keys);
}
-bool BloomFilter::WriteFile(const FilePath& filter_name) {
+bool BloomFilter::WriteFile(const FilePath& filter_name) const {
net::FileStream filter;
if (filter.Open(filter_name,
@@ -138,7 +146,7 @@ bool BloomFilter::WriteFile(const FilePath& filter_name) {
return false;
for (int i = 0; i < num_keys; ++i) {
- bytes_written = filter.Write(reinterpret_cast<char*>(&hash_keys_[i]),
+ bytes_written = filter.Write(reinterpret_cast<const char*>(&hash_keys_[i]),
sizeof(hash_keys_[i]), NULL);
if (bytes_written != sizeof(hash_keys_[i]))
return false;
@@ -151,4 +159,3 @@ bool BloomFilter::WriteFile(const FilePath& filter_name) {
return true;
}
-
diff --git a/chrome/browser/safe_browsing/bloom_filter.h b/chrome/browser/safe_browsing/bloom_filter.h
index 519282f..094985e 100644
--- a/chrome/browser/safe_browsing/bloom_filter.h
+++ b/chrome/browser/safe_browsing/bloom_filter.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.
//
@@ -16,11 +16,13 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_BLOOM_FILTER_H_
#define CHROME_BROWSER_SAFE_BROWSING_BLOOM_FILTER_H_
+#pragma once
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
class FilePath;
@@ -45,7 +47,7 @@ class BloomFilter : public base::RefCountedThreadSafe<BloomFilter> {
// Loading and storing the filter from / to disk.
static BloomFilter* LoadFile(const FilePath& filter_name);
- bool WriteFile(const FilePath& filter_name);
+ bool WriteFile(const FilePath& filter_name) const;
// How many bits to use per item. See the design doc for more information.
static const int kBloomFilterSizeRatio = 25;
@@ -58,6 +60,13 @@ class BloomFilter : public base::RefCountedThreadSafe<BloomFilter> {
// (in bytes).
static const int kBloomFilterMaxSize = 2 * 1024 * 1024;
+ // Use the above constants to calculate an appropriate size to pass
+ // to the BloomFilter constructor based on the intended |key_count|.
+ // TODO(shess): This is very clunky. It would be cleaner to have
+ // the constructor manage this, but at this time the unit and perf
+ // tests wish to make their own calculations.
+ static int FilterSizeForKeyCount(int key_count);
+
private:
friend class base::RefCountedThreadSafe<BloomFilter>;
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBloomFilter, BloomFilterUse);
diff --git a/chrome/browser/safe_browsing/bloom_filter_unittest.cc b/chrome/browser/safe_browsing/bloom_filter_unittest.cc
index bf3a123..df44235 100644
--- a/chrome/browser/safe_browsing/bloom_filter_unittest.cc
+++ b/chrome/browser/safe_browsing/bloom_filter_unittest.cc
@@ -74,7 +74,7 @@ TEST(SafeBrowsingBloomFilter, BloomFilterUse) {
double fp_rate = found_count * 100.0 / count;
CHECK(fp_rate < 5.0);
- LOG(INFO) << "For safe browsing bloom filter of size " << count <<
+ SB_DLOG(INFO) << "For safe browsing bloom filter of size " << count <<
", the FP rate was " << fp_rate << " %";
}
@@ -114,4 +114,3 @@ TEST(SafeBrowsingBloomFilter, BloomFilterFile) {
file_util::Delete(filter_path, false);
}
-
diff --git a/chrome/browser/safe_browsing/chunk_range.cc b/chrome/browser/safe_browsing/chunk_range.cc
index 112d71a..1cb52d6 100644
--- a/chrome/browser/safe_browsing/chunk_range.cc
+++ b/chrome/browser/safe_browsing/chunk_range.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 "chrome/browser/safe_browsing/chunk_range.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
ChunkRange::ChunkRange(int start) : start_(start), stop_(start) {
@@ -61,7 +63,7 @@ void RangesToString(const std::vector<ChunkRange>& ranges,
if (!result->empty())
result->append(",");
if (it->start() == it->stop()) {
- std::string num_buf = IntToString(it->start());
+ std::string num_buf = base::IntToString(it->start());
result->append(num_buf);
} else {
result->append(StringPrintf("%d-%d", it->start(), it->stop()));
diff --git a/chrome/browser/safe_browsing/chunk_range.h b/chrome/browser/safe_browsing/chunk_range.h
index 10d97f4..ace591f 100644
--- a/chrome/browser/safe_browsing/chunk_range.h
+++ b/chrome/browser/safe_browsing/chunk_range.h
@@ -13,6 +13,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_CHUNK_RANGE_H_
#define CHROME_BROWSER_SAFE_BROWSING_CHUNK_RANGE_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/safe_browsing/filter_false_positive_perftest.cc b/chrome/browser/safe_browsing/filter_false_positive_perftest.cc
index fd58ea5..f763b51 100644
--- a/chrome/browser/safe_browsing/filter_false_positive_perftest.cc
+++ b/chrome/browser/safe_browsing/filter_false_positive_perftest.cc
@@ -63,6 +63,7 @@
#include "base/rand_util.h"
#include "base/scoped_ptr.h"
#include "base/sha2.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
#include "chrome/browser/safe_browsing/bloom_filter.h"
@@ -93,11 +94,11 @@ class ScopedPerfDatabase {
};
// Command line flags.
-const wchar_t kFilterVerbose[] = L"filter-verbose";
-const wchar_t kFilterStart[] = L"filter-start";
-const wchar_t kFilterSteps[] = L"filter-steps";
-const wchar_t kFilterCsv[] = L"filter-csv";
-const wchar_t kFilterNumChecks[] = L"filter-num-checks";
+const char kFilterVerbose[] = "filter-verbose";
+const char kFilterStart[] = "filter-start";
+const char kFilterSteps[] = "filter-steps";
+const char kFilterCsv[] = "filter-csv";
+const char kFilterNumChecks[] = "filter-num-checks";
// Number of hash checks to make during performance testing.
static const int kNumHashChecks = 10000000;
@@ -260,7 +261,7 @@ void CalculateBloomFilterFalsePositives(
if (use_weights) {
std::string::size_type pos = url.find_last_of(",");
if (pos != std::string::npos) {
- weight = StringToInt(std::string(url, pos + 1));
+ base::StringToInt(std::string(url, pos + 1), &weight);
url = url.substr(0, pos);
}
}
@@ -312,16 +313,18 @@ TEST(SafeBrowsingBloomFilter, FalsePositives) {
FilePath data_dir = GetFullDataPath();
ASSERT_TRUE(ReadDatabase(data_dir, &prefix_list));
+ const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
+
int start = BloomFilter::kBloomFilterSizeRatio;
- if (CommandLine::ForCurrentProcess()->HasSwitch(kFilterStart)) {
- start = StringToInt(
- CommandLine::ForCurrentProcess()->GetSwitchValue(kFilterStart));
+ if (cmd_line.HasSwitch(kFilterStart)) {
+ ASSERT_TRUE(base::StringToInt(cmd_line.GetSwitchValueASCII(kFilterStart),
+ &start));
}
int steps = 1;
- if (CommandLine::ForCurrentProcess()->HasSwitch(kFilterSteps)) {
- steps = StringToInt(
- CommandLine::ForCurrentProcess()->GetSwitchValue(kFilterSteps));
+ if (cmd_line.HasSwitch(kFilterSteps)) {
+ ASSERT_TRUE(base::StringToInt(cmd_line.GetSwitchValueASCII(kFilterSteps),
+ &steps));
}
int stop = start + steps;
@@ -338,10 +341,13 @@ TEST(SafeBrowsingBloomFilter, HashTime) {
FilePath data_dir = GetFullDataPath();
ASSERT_TRUE(ReadDatabase(data_dir, &prefix_list));
+ const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
+
int num_checks = kNumHashChecks;
- if (CommandLine::ForCurrentProcess()->HasSwitch(kFilterNumChecks)) {
- num_checks = StringToInt(
- CommandLine::ForCurrentProcess()->GetSwitchValue(kFilterNumChecks));
+ if (cmd_line.HasSwitch(kFilterNumChecks)) {
+ ASSERT_TRUE(
+ base::StringToInt(cmd_line.GetSwitchValueASCII(kFilterNumChecks),
+ &num_checks));
}
// Populate the bloom filter and measure the time.
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc
index 3e9d5db..aef07ae 100644
--- a/chrome/browser/safe_browsing/protocol_manager.cc
+++ b/chrome/browser/safe_browsing/protocol_manager.cc
@@ -4,9 +4,10 @@
#include "chrome/browser/safe_browsing/protocol_manager.h"
+#ifndef NDEBUG
#include "base/base64.h"
-#include "base/env_var.h"
-#include "base/file_version_info.h"
+#endif
+#include "base/environment.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/rand_util.h"
@@ -74,11 +75,11 @@ SafeBrowsingProtocolManager::SafeBrowsingProtocolManager(
// The first update must happen between 1-5 minutes of start up.
next_update_sec_ = base::RandInt(60, kSbTimerStartIntervalSec);
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- if (!version_info.get())
+ chrome::VersionInfo version_info;
+ if (!version_info.is_valid())
version_ = "0.1";
else
- version_ = WideToASCII(version_info->product_version());
+ version_ = version_info.Version();
}
SafeBrowsingProtocolManager::~SafeBrowsingProtocolManager() {
@@ -418,8 +419,8 @@ bool SafeBrowsingProtocolManager::HandleServiceResponse(const GURL& url,
void SafeBrowsingProtocolManager::Initialize() {
// Don't want to hit the safe browsing servers on build/chrome bots.
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- if (env->HasEnv(env_vars::kHeadless))
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (env->HasVar(env_vars::kHeadless))
return;
ScheduleNextUpdate(false /* no back off */);
@@ -587,8 +588,10 @@ void SafeBrowsingProtocolManager::OnChunkInserted() {
void SafeBrowsingProtocolManager::ReportMalware(const GURL& malware_url,
const GURL& page_url,
- const GURL& referrer_url) {
- GURL report_url = MalwareReportUrl(malware_url, page_url, referrer_url);
+ const GURL& referrer_url,
+ bool is_subresource) {
+ GURL report_url = MalwareReportUrl(malware_url, page_url, referrer_url,
+ is_subresource);
URLFetcher* report = new URLFetcher(report_url, URLFetcher::GET, this);
report->set_load_flags(net::LOAD_DISABLE_CACHE);
report->set_request_context(request_context_getter_);
@@ -646,6 +649,8 @@ std::string SafeBrowsingProtocolManager::ComposeUrl(
prefix.c_str(), method.c_str(),
client_name.c_str(), version.c_str());
if (!additional_query.empty()) {
+ DCHECK(url.find("?") != std::string::npos);
+ url.append("&");
url.append(additional_query);
}
return url;
@@ -678,24 +683,32 @@ GURL SafeBrowsingProtocolManager::MacKeyUrl() const {
GURL SafeBrowsingProtocolManager::MalwareReportUrl(
const GURL& malware_url, const GURL& page_url,
- const GURL& referrer_url) const {
+ const GURL& referrer_url, bool is_subresource) const {
std::string url = ComposeUrl(info_url_prefix_, "report", client_name_,
version_, additional_query_);
- return GURL(StringPrintf("%s&evts=malblhit&evtd=%s&evtr=%s&evhr=%s",
+ return GURL(StringPrintf("%s&evts=malblhit&evtd=%s&evtr=%s&evhr=%s&evtb=%d",
url.c_str(), EscapeQueryParamValue(malware_url.spec(), true).c_str(),
EscapeQueryParamValue(page_url.spec(), true).c_str(),
- EscapeQueryParamValue(referrer_url.spec(), true).c_str()));
+ EscapeQueryParamValue(referrer_url.spec(), true).c_str(),
+ is_subresource));
}
GURL SafeBrowsingProtocolManager::NextChunkUrl(const std::string& url) const {
std::string next_url;
if (!StartsWithASCII(url, "http://", false) &&
!StartsWithASCII(url, "https://", false)) {
- next_url = "http://" + url;
+ next_url.append("http://");
+ next_url.append(url);
} else {
next_url = url;
}
- if (!additional_query_.empty())
- next_url += additional_query_;
+ if (!additional_query_.empty()) {
+ if (next_url.find("?") != std::string::npos) {
+ next_url.append("&");
+ } else {
+ next_url.append("?");
+ }
+ next_url.append(additional_query_);
+ }
return GURL(next_url);
}
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h
index 01a5235..fcdc438 100644
--- a/chrome/browser/safe_browsing/protocol_manager.h
+++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_
#define CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_
+#pragma once
// A class that implements Chrome's interface with the SafeBrowsing protocol.
// The SafeBrowsingProtocolManager handles formatting and making requests of,
@@ -26,8 +27,6 @@
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "chrome/common/net/url_fetcher.h"
-class Task;
-class Timer;
class URLRequestStatus;
#if defined(COMPILER_GCC)
@@ -69,7 +68,7 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
const std::string& info_url_prefix,
const std::string& mackey_url_prefix,
bool disable_auto_update);
- ~SafeBrowsingProtocolManager();
+ virtual ~SafeBrowsingProtocolManager();
// Sets up the update schedule and internal state for making periodic requests
// of the SafeBrowsing service.
@@ -112,7 +111,8 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
// Reports a malware resource to the SafeBrowsing service.
void ReportMalware(const GURL& malware_url,
const GURL& page_url,
- const GURL& referrer_url);
+ const GURL& referrer_url,
+ bool is_subresource);
// Setter for additional_query_. To make sure the additional_query_ won't
// be changed in the middle of an update, caller (e.g.: SafeBrowsingService)
@@ -131,14 +131,15 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
// so are handled separately.
enum SafeBrowsingRequestType {
NO_REQUEST = 0, // No requests in progress
- UPDATE_REQUEST, // Request for redirect URLs
+ UPDATE_REQUEST, // Request for redirect URLs
CHUNK_REQUEST, // Request for a specific chunk
GETKEY_REQUEST // Update the client's MAC key
};
// Composes a URL using |prefix|, |method| (e.g.: gethash, download,
// newkey, report), |client_name| and |version|. When not empty,
- // |additional_query| is appended to the URL.
+ // |additional_query| is appended to the URL with an additional "&"
+ // in the front.
static std::string ComposeUrl(const std::string& prefix,
const std::string& method,
const std::string& client_name,
@@ -155,7 +156,7 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
GURL MacKeyUrl() const;
// Generates URL for reporting malware pages.
GURL MalwareReportUrl(const GURL& malware_url, const GURL& page_url,
- const GURL& referrer_url) const;
+ const GURL& referrer_url, bool is_subresource) const;
// Composes a ChunkUrl based on input string.
GURL NextChunkUrl(const std::string& input) const;
diff --git a/chrome/browser/safe_browsing/protocol_manager_unittest.cc b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
index 4f45893..a73db3e 100644
--- a/chrome/browser/safe_browsing/protocol_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
@@ -19,7 +19,7 @@ static const char kClientKey[] = "SCg9lcLHd0dfksXgYsacwQ==";
static const char kWrappedKey[] =
"AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8nNaYH47tiQ7pDe9cEErjVHGZaPPUau5h61tbXSDqA"
"BiJZnDFByc_g8B5vTwxkhBf9g==";
-static const char kAdditionalQuery[] = "&additional_query";
+static const char kAdditionalQuery[] = "additional_query";
class SafeBrowsingProtocolManagerTest : public testing::Test {
};
@@ -162,7 +162,7 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashUrl) {
"ErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf9g==",
pm.GetHashUrl(true).spec());
- pm.set_additional_query("&additional_query");
+ pm.set_additional_query(kAdditionalQuery);
EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
"pver=2.2&additional_query",
pm.GetHashUrl(false).spec());
@@ -184,7 +184,7 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestUpdateUrl) {
"ErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf9g==",
pm.UpdateUrl(true).spec());
- pm.set_additional_query("&additional_query");
+ pm.set_additional_query(kAdditionalQuery);
EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
"pver=2.2&additional_query", pm.UpdateUrl(false).spec());
EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
@@ -204,16 +204,18 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestMalwareReportUrl) {
EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
"pver=2.2&evts=malblhit&evtd=http%3A%2F%2Fmalware.url.com%2F&"
"evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
- "url.com%2F",
- pm.MalwareReportUrl(malware_url, page_url, referrer_url).spec());
+ "url.com%2F&evtb=1",
+ pm.MalwareReportUrl(malware_url, page_url, referrer_url,
+ true).spec());
- pm.set_additional_query("&additional_query");
+ pm.set_additional_query(kAdditionalQuery);
EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
"pver=2.2&additional_query&evts=malblhit&"
"evtd=http%3A%2F%2Fmalware.url.com%2F&"
"evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
- "url.com%2F",
- pm.MalwareReportUrl(malware_url, page_url, referrer_url).spec());
+ "url.com%2F&evtb=0",
+ pm.MalwareReportUrl(malware_url, page_url, referrer_url,
+ false).spec());
}
TEST_F(SafeBrowsingProtocolManagerTest, TestMacKeyUrl) {
@@ -224,7 +226,7 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestMacKeyUrl) {
EXPECT_EQ("https://key.prefix.com/bar/newkey?client=unittest&appver=1.0&"
"pver=2.2", pm.MacKeyUrl().spec());
- pm.set_additional_query("&additional_query");
+ pm.set_additional_query(kAdditionalQuery);
EXPECT_EQ("https://key.prefix.com/bar/newkey?client=unittest&appver=1.0&"
"pver=2.2&additional_query", pm.MacKeyUrl().spec());
}
@@ -237,6 +239,7 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestNextChunkUrl) {
std::string url_partial = "localhost:1234/foo/bar?foo";
std::string url_http_full = "http://localhost:1234/foo/bar?foo";
std::string url_https_full = "https://localhost:1234/foo/bar?foo";
+ std::string url_https_no_query = "https://localhost:1234/foo/bar";
EXPECT_EQ("http://localhost:1234/foo/bar?foo",
pm.NextChunkUrl(url_partial).spec());
@@ -244,12 +247,16 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestNextChunkUrl) {
pm.NextChunkUrl(url_http_full).spec());
EXPECT_EQ("https://localhost:1234/foo/bar?foo",
pm.NextChunkUrl(url_https_full).spec());
+ EXPECT_EQ("https://localhost:1234/foo/bar",
+ pm.NextChunkUrl(url_https_no_query).spec());
- pm.set_additional_query("&additional_query");
+ pm.set_additional_query(kAdditionalQuery);
EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
pm.NextChunkUrl(url_partial).spec());
EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
pm.NextChunkUrl(url_http_full).spec());
EXPECT_EQ("https://localhost:1234/foo/bar?foo&additional_query",
pm.NextChunkUrl(url_https_full).spec());
+ EXPECT_EQ("https://localhost:1234/foo/bar?additional_query",
+ pm.NextChunkUrl(url_https_no_query).spec());
}
diff --git a/chrome/browser/safe_browsing/protocol_parser.cc b/chrome/browser/safe_browsing/protocol_parser.cc
index 4590e56..c022da4 100644
--- a/chrome/browser/safe_browsing/protocol_parser.cc
+++ b/chrome/browser/safe_browsing/protocol_parser.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.
//
@@ -16,6 +16,7 @@
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/string_split.h"
#include "base/string_util.h"
namespace {
diff --git a/chrome/browser/safe_browsing/protocol_parser.h b/chrome/browser/safe_browsing/protocol_parser.h
index 097eedb..9384f07 100644
--- a/chrome/browser/safe_browsing/protocol_parser.h
+++ b/chrome/browser/safe_browsing/protocol_parser.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_PARSER_H_
#define CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_PARSER_H_
+#pragma once
// Parse the data returned from the chunk response.
//
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 0e0cf4b..bcc28cb 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.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.
//
@@ -11,12 +11,13 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
-#include "chrome/browser/google_util.h"
+#include "chrome/browser/google/google_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
@@ -145,11 +146,11 @@ void SafeBrowsingBlockingPage::PopulateStringDictionary(
const std::wstring& description1,
const std::wstring& description2,
const std::wstring& description3) {
- strings->SetString(L"title", title);
- strings->SetString(L"headLine", headline);
- strings->SetString(L"description1", description1);
- strings->SetString(L"description2", description2);
- strings->SetString(L"description3", description3);
+ strings->SetString("title", WideToUTF16Hack(title));
+ strings->SetString("headLine", WideToUTF16Hack(headline));
+ strings->SetString("description1", WideToUTF16Hack(description1));
+ strings->SetString("description2", WideToUTF16Hack(description2));
+ strings->SetString("description3", WideToUTF16Hack(description3));
}
void SafeBrowsingBlockingPage::PopulateMultipleThreatStringDictionary(
@@ -157,14 +158,14 @@ void SafeBrowsingBlockingPage::PopulateMultipleThreatStringDictionary(
bool malware = false;
bool phishing = false;
- std::wstring phishing_label =
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_LABEL);
- std::wstring phishing_link =
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR);
- std::wstring malware_label =
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_LABEL);
- std::wstring malware_link =
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE);
+ string16 malware_label =
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_LABEL);
+ string16 malware_link =
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE);
+ string16 phishing_label =
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_LABEL);
+ string16 phishing_link =
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR);
ListValue* error_strings = new ListValue;
for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
@@ -173,20 +174,20 @@ void SafeBrowsingBlockingPage::PopulateMultipleThreatStringDictionary(
DictionaryValue* current_error_strings = new DictionaryValue;
if (resource.threat_type == SafeBrowsingService::URL_MALWARE) {
malware = true;
- current_error_strings->SetString(L"type", L"malware");
- current_error_strings->SetString(L"typeLabel", malware_label);
- current_error_strings->SetString(L"errorLink", malware_link);
+ current_error_strings->SetString("type", "malware");
+ current_error_strings->SetString("typeLabel", malware_label);
+ current_error_strings->SetString("errorLink", malware_link);
} else {
DCHECK(resource.threat_type == SafeBrowsingService::URL_PHISHING);
phishing = true;
- current_error_strings->SetString(L"type", L"phishing");
- current_error_strings->SetString(L"typeLabel", phishing_label);
- current_error_strings->SetString(L"errorLink", phishing_link);
+ current_error_strings->SetString("type", "phishing");
+ current_error_strings->SetString("typeLabel", phishing_label);
+ current_error_strings->SetString("errorLink", phishing_link);
}
- current_error_strings->SetString(L"url", UTF8ToWide(resource.url.spec()));
+ current_error_strings->SetString("url", resource.url.spec());
error_strings->Append(current_error_strings);
}
- strings->Set(L"errors", error_strings);
+ strings->Set("errors", error_strings);
DCHECK(phishing || malware);
if (malware && phishing) {
@@ -220,13 +221,13 @@ void SafeBrowsingBlockingPage::PopulateMultipleThreatStringDictionary(
L"", L"");
}
- strings->SetString(L"confirm_text",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION_AGREE));
- strings->SetString(L"continue_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_PROCEED_BUTTON));
- strings->SetString(L"back_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
- strings->SetString(L"textdirection", base::i18n::IsRTL() ? L"rtl" : L"ltr");
+ strings->SetString("confirm_text",
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION_AGREE));
+ strings->SetString("continue_button",
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_PROCEED_BUTTON));
+ strings->SetString("back_button",
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
+ strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
}
void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
@@ -234,7 +235,7 @@ void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
std::wstring link = StringPrintf(kSbDiagnosticHtml,
l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE).c_str());
- strings->SetString(L"badURL", UTF8ToWide(url().host()));
+ strings->SetString("badURL", url().host());
// Check to see if we're blocking the main page, or a sub-resource on the
// main page.
std::wstring description1, description2;
@@ -260,13 +261,13 @@ void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
description1, description2,
l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION3));
- strings->SetString(L"confirm_text",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION_AGREE));
- strings->SetString(L"continue_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_PROCEED_BUTTON));
- strings->SetString(L"back_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
- strings->SetString(L"textdirection", base::i18n::IsRTL() ? L"rtl" : L"ltr");
+ strings->SetString("confirm_text",
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION_AGREE));
+ strings->SetString("continue_button",
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_PROCEED_BUTTON));
+ strings->SetString("back_button",
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
+ strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
}
void SafeBrowsingBlockingPage::PopulatePhishingStringDictionary(
@@ -281,13 +282,13 @@ void SafeBrowsingBlockingPage::PopulatePhishingStringDictionary(
UTF8ToWide(url().host())),
L"");
- strings->SetString(L"continue_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_PROCEED_BUTTON));
- strings->SetString(L"back_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_BACK_BUTTON));
- strings->SetString(L"report_error",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR));
- strings->SetString(L"textdirection", base::i18n::IsRTL() ? L"rtl" : L"ltr");
+ 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",
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR));
+ strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
}
void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
@@ -332,7 +333,7 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
DCHECK(colon_index < command.size() - 1);
std::string index_str = command.substr(colon_index + 1);
command = command.substr(0, colon_index);
- bool result = StringToInt(index_str, &element_index);
+ bool result = base::StringToInt(index_str, &element_index);
DCHECK(result);
}
@@ -442,16 +443,19 @@ void SafeBrowsingBlockingPage::RecordUserAction(BlockingPageEvent event) {
DictionaryValue strings;
PopulateMultipleThreatStringDictionary(&strings);
- std::wstring title;
- DCHECK(strings.GetString(L"title", &title));
+ string16 title;
+ DCHECK(strings.GetString("title", &title));
std::string action = "SBInterstitial";
- if (title == l10n_util::GetString(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE)) {
+ if (title ==
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE)) {
action.append("Multiple");
- } else if (title == l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_TITLE)) {
+ } else if (title ==
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE)) {
action.append("Malware");
} else {
- DCHECK_EQ(title, l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_TITLE));
+ DCHECK_EQ(title,
+ l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE));
action.append("Phishing");
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index 644e76d..96d8bca 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.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,6 +27,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_BLOCKING_PAGE_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_BLOCKING_PAGE_H_
+#pragma once
#include <map>
#include <vector>
@@ -37,7 +38,6 @@
class DictionaryValue;
class MessageLoop;
-class NavigationController;
class SafeBrowsingBlockingPageFactory;
class TabContents;
@@ -145,7 +145,7 @@ class SafeBrowsingBlockingPage : public InterstitialPage {
// Factory for creating SafeBrowsingBlockingPage. Useful for tests.
class SafeBrowsingBlockingPageFactory {
public:
- ~SafeBrowsingBlockingPageFactory() { }
+ virtual ~SafeBrowsingBlockingPageFactory() { }
virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
SafeBrowsingService* service,
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 660e8dd..db67004 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
@@ -7,6 +7,9 @@
#include "chrome/browser/chrome_thread.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/render_messages.h"
+#include "chrome/common/render_messages_params.h"
static const char* kGoogleURL = "http://www.google.com/";
static const char* kGoodURL = "http://www.goodguys.com/";
diff --git a/chrome/browser/safe_browsing/safe_browsing_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_browsertest.cc
deleted file mode 100644
index be35100..0000000
--- a/chrome/browser/safe_browsing/safe_browsing_browsertest.cc
+++ /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/command_line.h"
-#include "base/lock.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_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_service.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/test/in_process_browser_test.h"
-#include "chrome/test/ui_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// This starts the browser and keeps status of states related to SafeBrowsing.
-class SafeBrowsingServiceTest : public InProcessBrowserTest {
- public:
- SafeBrowsingServiceTest()
- : safe_browsing_service_(NULL),
- is_update_in_progress_(false),
- is_initial_request_(false),
- is_update_scheduled_(false),
- is_url_match_in_db_(false) {
- }
-
- void UpdateSafeBrowsingStatus() {
- CHECK(safe_browsing_service_);
- AutoLock lock(update_status_mutex_);
- is_update_in_progress_ = safe_browsing_service_->IsUpdateInProgress();
- is_initial_request_ =
- safe_browsing_service_->protocol_manager_->is_initial_request();
- last_update_ = safe_browsing_service_->protocol_manager_->last_update();
- is_update_scheduled_ =
- safe_browsing_service_->protocol_manager_->update_timer_.IsRunning();
- }
-
- void CheckUrl(SafeBrowsingService::Client* helper, const GURL& url) {
- CHECK(safe_browsing_service_);
- AutoLock lock(update_status_mutex_);
- if (!safe_browsing_service_->CheckUrl(url, helper)) {
- safe_browsing_service_->CancelCheck(helper);
- is_url_match_in_db_ = false;
- }
- is_url_match_in_db_ = true;
- }
-
- bool is_url_match_in_db() {
- AutoLock l(update_status_mutex_);
- return is_url_match_in_db_;
- }
-
- bool is_update_in_progress() {
- AutoLock l(update_status_mutex_);
- return is_update_in_progress_;
- }
-
- bool is_initial_request() {
- AutoLock l(update_status_mutex_);
- return is_initial_request_;
- }
-
- base::Time last_update() {
- AutoLock l(update_status_mutex_);
- return last_update_;
- }
-
- bool is_update_scheduled() {
- AutoLock l(update_status_mutex_);
- return is_update_scheduled_;
- }
-
- protected:
- void InitSafeBrowsingService() {
- safe_browsing_service_ =
- g_browser_process->resource_dispatcher_host()->safe_browsing_service();
- }
-
- virtual void SetUpCommandLine(CommandLine* command_line) {
- // Makes sure the auto update is not triggered. This test will force the
- // update when needed.
- command_line->AppendSwitch(switches::kSbDisableAutoUpdate);
- }
-
- private:
- SafeBrowsingService* safe_browsing_service_;
-
- // Protects all variables below since they are updated on IO thread but
- // read on UI thread.
- Lock update_status_mutex_;
- // States associated with safebrowsing service updates.
- bool is_update_in_progress_;
- bool is_initial_request_;
- base::Time last_update_;
- bool is_update_scheduled_;
- // Indicates if there is a match between a URL's prefix and safebrowsing
- // database (thus potentially it is a phishing url).
- bool is_url_match_in_db_;
- DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTest);
-};
-
-// A ref counted helper class that handles callbacks between IO thread and UI
-// thread.
-class SafeBrowsingServiceTestHelper
- : public base::RefCountedThreadSafe<SafeBrowsingServiceTestHelper>,
- public SafeBrowsingService::Client {
- public:
- explicit SafeBrowsingServiceTestHelper(
- SafeBrowsingServiceTest* safe_browsing_test)
- : safe_browsing_test_(safe_browsing_test) {
- }
-
- // Callbacks for SafeBrowsingService::Client. Not implemented yet.
- virtual void OnUrlCheckResult(const GURL& url,
- SafeBrowsingService::UrlCheckResult result) {
- NOTREACHED() << "Not implemented.";
- }
- virtual void OnBlockingPageComplete(bool proceed) {
- NOTREACHED() << "Not implemented.";
- }
-
- // Functions and callbacks related to CheckUrl. These are used to verify if
- // a URL is a phishing URL.
- void CheckUrl(const GURL& url) {
- ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, NewRunnableMethod(this,
- &SafeBrowsingServiceTestHelper::CheckUrlOnIOThread, url));
- }
- void CheckUrlOnIOThread(const GURL& url) {
- CHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- safe_browsing_test_->CheckUrl(this, url);
- ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, NewRunnableMethod(this,
- &SafeBrowsingServiceTestHelper::OnCheckUrlOnIOThreadDone));
- }
- void OnCheckUrlOnIOThreadDone() {
- StopUILoop();
- }
-
- // Functions and callbacks related to safebrowsing server status.
- void CheckStatusOnIOThread() {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
- safe_browsing_test_->UpdateSafeBrowsingStatus();
- ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, NewRunnableMethod(this,
- &SafeBrowsingServiceTestHelper::OnCheckStatusOnIOThreadDone));
- }
- void OnCheckStatusOnIOThreadDone() {
- StopUILoop();
- }
- void CheckStatusAfterDelay(int64 wait_time_sec) {
- ChromeThread::PostDelayedTask(
- ChromeThread::IO,
- FROM_HERE,
- NewRunnableMethod(this,
- &SafeBrowsingServiceTestHelper::CheckStatusOnIOThread),
- wait_time_sec * 1000);
- }
-
- private:
- // Stops UI loop after desired status is updated.
- void StopUILoop() {
- CHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- MessageLoopForUI::current()->Quit();
- }
-
- base::OneShotTimer<SafeBrowsingServiceTestHelper> check_update_timer_;
- SafeBrowsingServiceTest* safe_browsing_test_;
- DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTestHelper);
-};
-
-IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, SafeBrowsingSystemTest) {
- InitSafeBrowsingService();
- scoped_refptr<SafeBrowsingServiceTestHelper> safe_browsing_helper =
- new SafeBrowsingServiceTestHelper(this);
-
- // Waits for 1 sec and makes sure safebrowsing update is not happening.
- safe_browsing_helper->CheckStatusAfterDelay(1);
- // Loop will stop once OnCheckStatusOnIOThreadDone in safe_browsing_helper
- // is called and status from safe_browsing_service_ is checked.
- ui_test_utils::RunMessageLoop();
- EXPECT_FALSE(is_update_in_progress());
- EXPECT_TRUE(is_initial_request());
- EXPECT_FALSE(is_update_scheduled());
- EXPECT_TRUE(last_update().is_null());
-
- // Verify URL.
- const char test_url[] = "http://ianfette.org";
- safe_browsing_helper->CheckUrl(GURL(test_url));
- // Loop will stop once OnCheckUrlOnIOThreadDone in safe_browsing_helper
- // is called and url check is done.
- ui_test_utils::RunMessageLoop();
- EXPECT_TRUE(is_url_match_in_db());
-
- // TODO(lzheng): Add tests to launch a testing safebrowsing server
- // and issue requests repeatedly:
- // http://code.google.com/p/google-safe-browsing/wiki/ProtocolTesting
-}
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc
index 3237b30..79bec81 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database.cc
@@ -1,35 +1,664 @@
-// 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.
#include "chrome/browser/safe_browsing/safe_browsing_database.h"
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/histogram.h"
+#include "base/time.h"
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#include "base/sha2.h"
+#include "base/stats_counters.h"
#include "chrome/browser/safe_browsing/bloom_filter.h"
#include "chrome/browser/safe_browsing/safe_browsing_database_bloom.h"
+#include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
+#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h"
+#include "chrome/common/chrome_switches.h"
+#include "googleurl/src/gurl.h"
-using base::TimeTicks;
+namespace {
// Filename suffix for the bloom filter.
-static const FilePath::CharType kBloomFilterFile[] =
- FILE_PATH_LITERAL(" Filter 2");
+const FilePath::CharType kBloomFilterFile[] = FILE_PATH_LITERAL(" Filter 2");
+
+// The maximum staleness for a cached entry.
+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) {
+ 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;
+}
+
+// Generate the set of prefixes to check for |url|.
+// TODO(shess): This function is almost the same as
+// |CompareFullHashes()| in safe_browsing_util.cc, except that code
+// 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) {
+ std::vector<std::string> hosts;
+ if (url.HostIsIPAddress()) {
+ hosts.push_back(url.host());
+ } else {
+ safe_browsing_util::GenerateHostsToCheck(url, &hosts);
+ }
+
+ std::vector<std::string> paths;
+ safe_browsing_util::GeneratePathsToCheck(url, &paths);
+
+ for (size_t i = 0; i < hosts.size(); ++i) {
+ for (size_t j = 0; j < paths.size(); ++j) {
+ SBFullHash full_hash;
+ base::SHA256HashString(hosts[i] + paths[j], &full_hash,
+ sizeof(SBFullHash));
+ prefixes->push_back(full_hash.prefix);
+ }
+ }
+}
+
+// Find the entries in |full_hashes| with prefix in |prefix_hits|, and
+// add them to |full_hits| if not expired. "Not expired" is when
+// either |last_update| was recent enough, or the item has been
+// received recently enough. Expired items are not deleted because a
+// future update may make them acceptable again.
+//
+// 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) {
+ const base::Time expire_time =
+ base::Time::Now() - base::TimeDelta::FromMinutes(kMaxStalenessMinutes);
+
+ std::vector<SBPrefix>::const_iterator piter = prefix_hits.begin();
+ std::vector<SBAddFullHash>::const_iterator hiter = full_hashes.begin();
+
+ while (piter != prefix_hits.end() && hiter != full_hashes.end()) {
+ if (*piter < hiter->full_hash.prefix) {
+ ++piter;
+ } else if (hiter->full_hash.prefix < *piter) {
+ ++hiter;
+ } else {
+ 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);
+ result.add_chunk_id = DecodeChunkId(hiter->chunk_id);
+ result.hash = hiter->full_hash;
+ full_hits->push_back(result);
+ }
+
+ // Only increment |hiter|, |piter| might have multiple hits.
+ ++hiter;
+ }
+ }
+}
+
+// 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;
+
+ 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));
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ std::sort(malware_chunks.begin(), malware_chunks.end());
+ std::vector<ChunkRange> malware_ranges;
+ ChunksToRanges(malware_chunks, &malware_ranges);
+ RangesToString(malware_ranges, malware_list);
+
+ std::sort(phishing_chunks.begin(), phishing_chunks.end());
+ std::vector<ChunkRange> phishing_ranges;
+ ChunksToRanges(phishing_chunks, &phishing_ranges);
+ RangesToString(phishing_ranges, phishing_list);
+}
+
+// Order |SBAddFullHash| on the prefix part. |SBAddPrefixLess()| from
+// safe_browsing_store.h orders on both chunk-id and prefix.
+bool SBAddFullHashPrefixLess(const SBAddFullHash& a, const SBAddFullHash& b) {
+ return a.full_hash.prefix < b.full_hash.prefix;
+}
+
+} // namespace
// Factory method.
+// TODO(shess): Proposed staging of the rolling:
+// - Ship "old" to dev channel to provide a safe fallback.
+// - If that proves stable, change to "newsqlite". This changes the
+// code which manipulates the data, without changing the data
+// format. At this point all changes could be reverted without
+// having to resync everyone's database from scratch.
+// - If SafeBrowsingDatabaseNew proves stable, change the default to
+// "newfile", which will change the file format. Changing back
+// would require resync from scratch.
+// - Once enough users are converted to "newfile", remove all of the
+// redundent indirection classes and functions, perhaps leaving
+// SafeBrowsingStoreSqlite for on-the-fly conversions.
+// - Once there are few remaining SQLite-format users, remove
+// SafeBrowsingStoreSqlite. Remaining users will resync their
+// safe-browsing database from scratch. If users haven't sync'ed
+// their database in months, this probably won't be more expensive
+// than an incremental sync.
SafeBrowsingDatabase* SafeBrowsingDatabase::Create() {
- return new SafeBrowsingDatabaseBloom;
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ std::string value =
+ command_line.GetSwitchValueASCII(switches::kSafeBrowsingDatabaseStore);
+ if (!value.compare("newfile")) {
+ return new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile);
+ } else if (!value.compare("newsqlite")) {
+ return new SafeBrowsingDatabaseNew(new SafeBrowsingStoreSqlite);
+ } else if (!value.compare("old")) {
+ return new SafeBrowsingDatabaseBloom;
+ } else {
+ // Default.
+ DCHECK(value.empty());
+ return new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile);
+ }
}
SafeBrowsingDatabase::~SafeBrowsingDatabase() {
}
// static
-FilePath SafeBrowsingDatabase::BloomFilterFilename(
+FilePath SafeBrowsingDatabase::BloomFilterForFilename(
const FilePath& db_filename) {
return FilePath(db_filename.value() + kBloomFilterFile);
}
-void SafeBrowsingDatabase::LoadBloomFilter() {
+SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew(SafeBrowsingStore* store)
+ : creation_loop_(MessageLoop::current()),
+ store_(store),
+ ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)),
+ corruption_detected_(false) {
+ DCHECK(store_.get());
+}
+
+SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew()
+ : creation_loop_(MessageLoop::current()),
+ store_(new SafeBrowsingStoreSqlite),
+ ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)) {
+ DCHECK(store_.get());
+}
+
+SafeBrowsingDatabaseNew::~SafeBrowsingDatabaseNew() {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+}
+
+void SafeBrowsingDatabaseNew::Init(const FilePath& filename) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ // NOTE: There is no need to grab the lock in this function, since
+ // until it returns, there are no pointers to this class on other
+ // threads. Then again, that means there is no possibility of
+ // contention on the lock...
+ AutoLock locked(lookup_lock_);
+
+ DCHECK(filename_.empty()); // Ensure we haven't been run before.
+
+ filename_ = filename;
+ store_->Init(
+ filename_,
+ NewCallback(this, &SafeBrowsingDatabaseNew::HandleCorruptDatabase));
+
+ full_hashes_.clear();
+ pending_hashes_.clear();
+
+ bloom_filter_filename_ = BloomFilterForFilename(filename_);
+ LoadBloomFilter();
+}
+
+bool SafeBrowsingDatabaseNew::ResetDatabase() {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ // Delete files on disk.
+ // TODO(shess): Hard to see where one might want to delete without a
+ // reset. Perhaps inline |Delete()|?
+ if (!Delete())
+ return false;
+
+ // Reset objects in memory.
+ {
+ AutoLock locked(lookup_lock_);
+ full_hashes_.clear();
+ pending_hashes_.clear();
+ prefix_miss_cache_.clear();
+ // TODO(shess): This could probably be |bloom_filter_.reset()|.
+ bloom_filter_ = new BloomFilter(BloomFilter::kBloomFilterMinSize *
+ BloomFilter::kBloomFilterSizeRatio);
+ }
+
+ return true;
+}
+
+bool SafeBrowsingDatabaseNew::ContainsUrl(
+ const GURL& url,
+ std::string* matching_list,
+ std::vector<SBPrefix>* prefix_hits,
+ std::vector<SBFullHashResult>* full_hits,
+ base::Time last_update) {
+ // Clear the results first.
+ matching_list->clear();
+ prefix_hits->clear();
+ full_hits->clear();
+
+ std::vector<SBPrefix> prefixes;
+ PrefixesToCheck(url, &prefixes);
+ if (prefixes.empty())
+ return false;
+
+ // This function is called on the I/O thread, prevent changes to
+ // bloom filter and caches.
+ AutoLock locked(lookup_lock_);
+
+ if (!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])) {
+ prefix_hits->push_back(prefixes[i]);
+ if (prefix_miss_cache_.count(prefixes[i]) > 0)
+ ++miss_count;
+ }
+ }
+
+ // If all the prefixes are cached as 'misses', don't issue a GetHash.
+ 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
+ // 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);
+ return true;
+}
+
+// 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());
+
+ STATS_COUNTER("SB.HostInsert", 1);
+ const int encoded_chunk_id = EncodeChunkId(chunk_id, list_id);
+ const int count = entry->prefix_count();
+
+ DCHECK(!entry->IsSub());
+ if (!count) {
+ // No prefixes, use host instead.
+ STATS_COUNTER("SB.PrefixAdd", 1);
+ 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);
+ }
+ } else {
+ // Prefixes and hashes.
+ const base::Time receive_time = base::Time::Now();
+ for (int i = 0; i < count; ++i) {
+ const SBFullHash full_hash = entry->FullHashAt(i);
+ const SBPrefix prefix = full_hash.prefix;
+
+ STATS_COUNTER("SB.PrefixAdd", 1);
+ store_->WriteAddPrefix(encoded_chunk_id, prefix);
+
+ STATS_COUNTER("SB.PrefixAddFull", 1);
+ 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,
+ const SBChunkList& chunks) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+ for (SBChunkList::const_iterator citer = chunks.begin();
+ citer != chunks.end(); ++citer) {
+ const int chunk_id = citer->chunk_number;
+
+ // 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))
+ continue;
+
+ 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
+ // chunks would look different from inserting sub chunks.
+ InsertAdd(chunk_id, hiter->host, hiter->entry, list_id);
+ }
+ }
+}
+
+// Helper to insert entries for all of the prefixes or full hashes in
+// |entry| into the store.
+void SafeBrowsingDatabaseNew::InsertSub(int chunk_id, SBPrefix host,
+ const SBEntry* entry, int list_id) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ STATS_COUNTER("SB.HostDelete", 1);
+ const int encoded_chunk_id = EncodeChunkId(chunk_id, list_id);
+ const int count = entry->prefix_count();
+
+ DCHECK(entry->IsSub());
+ if (!count) {
+ // 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);
+ } else if (entry->IsPrefix()) {
+ // Prefixes only.
+ for (int i = 0; i < count; i++) {
+ const SBPrefix prefix = entry->PrefixAt(i);
+ const int add_chunk_id =
+ EncodeChunkId(entry->ChunkIdAtPrefix(i), list_id);
+
+ STATS_COUNTER("SB.PrefixSub", 1);
+ store_->WriteSubPrefix(encoded_chunk_id, add_chunk_id, prefix);
+ }
+ } else {
+ // Prefixes and hashes.
+ for (int i = 0; i < count; ++i) {
+ const SBFullHash full_hash = entry->FullHashAt(i);
+ const int add_chunk_id =
+ EncodeChunkId(entry->ChunkIdAtPrefix(i), list_id);
+
+ STATS_COUNTER("SB.PrefixSub", 1);
+ 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);
+ }
+ }
+}
+
+// Helper to iterate over all the entries in the hosts in |chunks| and
+// add them to the store.
+void SafeBrowsingDatabaseNew::InsertSubChunks(int list_id,
+ const SBChunkList& chunks) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+ for (SBChunkList::const_iterator citer = chunks.begin();
+ citer != chunks.end(); ++citer) {
+ const int chunk_id = citer->chunk_number;
+
+ // 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))
+ continue;
+
+ 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);
+ }
+ }
+}
+
+void SafeBrowsingDatabaseNew::InsertChunks(const std::string& list_name,
+ const SBChunkList& chunks) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ if (corruption_detected_ || chunks.empty())
+ return;
+
+ const base::Time insert_start = base::Time::Now();
+
+ const int list_id = safe_browsing_util::GetListId(list_name);
+ store_->BeginChunk();
+ if (chunks.front().is_add) {
+ InsertAddChunks(list_id, chunks);
+ } else {
+ InsertSubChunks(list_id, chunks);
+ }
+ store_->FinishChunk();
+
+ UMA_HISTOGRAM_TIMES("SB2.ChunkInsert", base::Time::Now() - insert_start);
+}
+
+void SafeBrowsingDatabaseNew::DeleteChunks(
+ const std::vector<SBChunkDelete>& chunk_deletes) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ if (corruption_detected_ || chunk_deletes.empty())
+ return;
+
+ const std::string& list_name = chunk_deletes.front().list_name;
+ const int list_id = safe_browsing_util::GetListId(list_name);
+
+ 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);
+ else
+ store_->DeleteAddChunk(encoded_chunk_id);
+ }
+ }
+}
+
+void SafeBrowsingDatabaseNew::CacheHashResults(
+ const std::vector<SBPrefix>& prefixes,
+ const std::vector<SBFullHashResult>& full_hits) {
+ // This is called on the I/O thread, lock against updates.
+ AutoLock locked(lookup_lock_);
+
+ if (full_hits.empty()) {
+ prefix_miss_cache_.insert(prefixes.begin(), prefixes.end());
+ return;
+ }
+
+ // 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();
+ 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));
+ }
+
+ // 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(),
+ SBAddFullHashPrefixLess);
+}
+
+bool SafeBrowsingDatabaseNew::UpdateStarted(
+ std::vector<SBListChunkRanges>* lists) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+ DCHECK(lists);
+
+ // If |BeginUpdate()| fails, reset the database.
+ if (!store_->BeginUpdate()) {
+ 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);
+
+ lists->push_back(malware);
+ lists->push_back(phishing);
+
+ 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();
+ return;
+ }
+
+ // Copy out the pending add hashes. Copy rather than swapping in
+ // case |ContainsURL()| 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());
+ }
+
+ std::vector<SBAddPrefix> add_prefixes;
+ std::vector<SBAddFullHash> add_full_hashes;
+ if (!store_->FinishUpdate(pending_add_hashes,
+ &add_prefixes, &add_full_hashes))
+ return;
+
+ // Measure the amount of IO during the bloom filter build.
+ base::IoCounters io_before, io_after;
+ base::ProcessHandle handle = base::Process::Current().handle();
+ scoped_ptr<base::ProcessMetrics> metric(
+#if !defined(OS_MACOSX)
+ base::ProcessMetrics::CreateProcessMetrics(handle)
+#else
+ // Getting stats only for the current process is enough, so NULL is fine.
+ base::ProcessMetrics::CreateProcessMetrics(handle, NULL)
+#endif
+ );
+
+ // IoCounters are currently not supported on Mac, and may not be
+ // available for Linux, so we check the result and only show IO
+ // stats if they are available.
+ const bool got_counters = metric->GetIOCounters(&io_before);
+
+ const base::Time before = base::Time::Now();
+
+ // Create and populate |filter| from |add_prefixes|.
+ // TODO(shess): The bloom filter doesn't need to be a
+ // scoped_refptr<> for this code. Refactor that away.
+ const int filter_size =
+ BloomFilter::FilterSizeForKeyCount(add_prefixes.size());
+ scoped_refptr<BloomFilter> filter(new BloomFilter(filter_size));
+ for (size_t i = 0; i < add_prefixes.size(); ++i) {
+ filter->Insert(add_prefixes[i].prefix);
+ }
+
+ // This needs to be in sorted order by prefix for efficient access.
+ std::sort(add_full_hashes.begin(), add_full_hashes.end(),
+ SBAddFullHashPrefixLess);
+
+ // Swap in the newly built filter and cache.
+ {
+ AutoLock locked(lookup_lock_);
+ full_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();
+
+ prefix_miss_cache_.clear();
+ 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.
+ WriteBloomFilter();
+
+ // Gather statistics.
+ if (got_counters && metric->GetIOCounters(&io_after)) {
+ UMA_HISTOGRAM_COUNTS("SB2.BuildReadBytes",
+ static_cast<int>(io_after.ReadTransferCount -
+ io_before.ReadTransferCount));
+ UMA_HISTOGRAM_COUNTS("SB2.BuildWriteBytes",
+ static_cast<int>(io_after.WriteTransferCount -
+ io_before.WriteTransferCount));
+ UMA_HISTOGRAM_COUNTS("SB2.BuildReadOperations",
+ static_cast<int>(io_after.ReadOperationCount -
+ io_before.ReadOperationCount));
+ UMA_HISTOGRAM_COUNTS("SB2.BuildWriteOperations",
+ static_cast<int>(io_after.WriteOperationCount -
+ io_before.WriteOperationCount));
+ }
+ SB_DLOG(INFO) << "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.FilterSize", bloom_filter_->size());
+ int64 size_64;
+ if (file_util::GetFileSize(filename_, &size_64))
+ UMA_HISTOGRAM_COUNTS("SB2.DatabaseBytes", static_cast<int>(size_64));
+}
+
+void SafeBrowsingDatabaseNew::HandleCorruptDatabase() {
+ // Reset the database after the current task has unwound (but only
+ // reset once within the scope of a given task).
+ if (reset_factory_.empty())
+ MessageLoop::current()->PostTask(FROM_HERE,
+ reset_factory_.NewRunnableMethod(
+ &SafeBrowsingDatabaseNew::OnHandleCorruptDatabase));
+}
+
+void SafeBrowsingDatabaseNew::OnHandleCorruptDatabase() {
+ UMA_HISTOGRAM_COUNTS("SB2.HandleCorrupt", 1);
+ corruption_detected_ = true; // Stop updating the database.
+ ResetDatabase();
+ DCHECK(false) << "SafeBrowsing database was corrupt and reset";
+}
+
+// TODO(shess): I'm not clear why this code doesn't have any
+// real error-handling.
+void SafeBrowsingDatabaseNew::LoadBloomFilter() {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
DCHECK(!bloom_filter_filename_.empty());
// If we're missing either of the database or filter files, we wait until the
@@ -46,28 +675,33 @@ void SafeBrowsingDatabase::LoadBloomFilter() {
return;
}
- // We have a bloom filter file, so use that as our filter.
- TimeTicks before = TimeTicks::Now();
+ const base::TimeTicks before = base::TimeTicks::Now();
bloom_filter_ = BloomFilter::LoadFile(bloom_filter_filename_);
- SB_DLOG(INFO) << "SafeBrowsingDatabase read bloom filter in "
- << (TimeTicks::Now() - before).InMilliseconds() << " ms";
+ SB_DLOG(INFO) << "SafeBrowsingDatabaseNew read bloom filter in "
+ << (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
if (!bloom_filter_.get())
UMA_HISTOGRAM_COUNTS("SB2.FilterReadFail", 1);
}
-void SafeBrowsingDatabase::DeleteBloomFilter() {
- file_util::Delete(bloom_filter_filename_, false);
+bool SafeBrowsingDatabaseNew::Delete() {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ const bool r1 = store_->Delete();
+ const bool r2 = file_util::Delete(bloom_filter_filename_, false);
+ return r1 && r2;
}
-void SafeBrowsingDatabase::WriteBloomFilter() {
+void SafeBrowsingDatabaseNew::WriteBloomFilter() {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+
if (!bloom_filter_.get())
return;
- TimeTicks before = TimeTicks::Now();
- bool write_ok = bloom_filter_->WriteFile(bloom_filter_filename_);
- SB_DLOG(INFO) << "SafeBrowsingDatabase wrote bloom filter in " <<
- (TimeTicks::Now() - before).InMilliseconds() << " ms";
+ const base::TimeTicks before = base::TimeTicks::Now();
+ const bool write_ok = bloom_filter_->WriteFile(bloom_filter_filename_);
+ SB_DLOG(INFO) << "SafeBrowsingDatabaseNew wrote bloom filter in " <<
+ (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
if (!write_ok)
UMA_HISTOGRAM_COUNTS("SB2.FilterWriteFail", 1);
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h
index 90723f1..4120afd 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.h
+++ b/chrome/browser/safe_browsing/safe_browsing_database.h
@@ -1,29 +1,36 @@
-// 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.
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_DATABASE_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_DATABASE_H_
+#pragma once
-#include <deque>
-#include <list>
#include <set>
#include <vector>
#include "base/file_path.h"
-#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
+#include "base/lock.h"
#include "base/scoped_ptr.h"
-#include "base/time.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 {
+ class Time;
+}
class BloomFilter;
class GURL;
+class MessageLoop;
+
+// 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 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.
class SafeBrowsingDatabase {
public:
// Factory method for obtaining a SafeBrowsingDatabase implementation.
@@ -36,26 +43,44 @@ class SafeBrowsingDatabase {
// Deletes the current database and creates a new one.
virtual bool ResetDatabase() = 0;
- // Returns false if the given url is not in the database. If it returns
- // true, then either "list" is the name of the matching list, or prefix_hits
- // contains the matching hash prefixes.
+ // Returns false if |url| is not in the 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;
- // Processes add/sub commands. Database will free the chunks when it's done.
+ // A database transaction should look like:
+ //
+ // std::vector<SBListChunkRanges> lists;
+ // if (db.UpdateStarted(&lists)) {
+ // // Do something with |lists|.
+ //
+ // // Process add/sub commands.
+ // db.InsertChunks(list_name, chunks);
+ //
+ // // Process adddel/subdel commands.
+ // db.DeleteChunks(chunks_deletes);
+ //
+ // // If passed true, processes the collected chunk info and
+ // // rebuilds the bloom filter. If passed false, rolls everything
+ // // back.
+ // db.UpdateFinished(success);
+ // }
+ //
+ // If UpdateStarted() returns true, the caller MUST eventually call
+ // UpdateFinished(). If it returns false, the caller MUST NOT call
+ // the other functions.
+ virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists) = 0;
virtual void InsertChunks(const std::string& list_name,
const SBChunkList& chunks) = 0;
-
- // Processs adddel/subdel commands. Database will free chunk_deletes when
- // it's done.
virtual void DeleteChunks(
const std::vector<SBChunkDelete>& chunk_deletes) = 0;
-
- // Returns the lists and their add/sub chunks.
- virtual void GetListsInfo(std::vector<SBListChunkRanges>* lists) = 0;
+ virtual void UpdateFinished(bool update_succeeded) = 0;
// Store the results of a GetHash response. In the case of empty results, we
// cache the prefixes until the next update so that we don't have to issue
@@ -64,52 +89,103 @@ class SafeBrowsingDatabase {
const std::vector<SBPrefix>& prefixes,
const std::vector<SBFullHashResult>& full_hits) = 0;
- // Returns true if we have successfully started the update transaction.
- virtual bool UpdateStarted() = 0;
- virtual void UpdateFinished(bool update_succeeded) = 0;
+ // The name of the bloom-filter file for the given database file.
+ static FilePath BloomFilterForFilename(const FilePath& db_filename);
+};
- virtual FilePath filename() const { return filename_; }
+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);
- protected:
- struct HashCacheEntry {
- SBFullHash full_hash;
- int list_id;
- int add_chunk_id;
- int sub_chunk_id;
- base::Time received;
- };
+ // Create a database with a default store.
+ SafeBrowsingDatabaseNew();
- typedef std::list<HashCacheEntry> HashList;
- typedef base::hash_map<SBPrefix, HashList> HashCache;
+ virtual ~SafeBrowsingDatabaseNew();
+ // 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 UpdateStarted(std::vector<SBListChunkRanges>* lists);
+ virtual void InsertChunks(const std::string& list_name,
+ const SBChunkList& chunks);
+ virtual void DeleteChunks(const std::vector<SBChunkDelete>& chunk_deletes);
+ virtual void UpdateFinished(bool update_succeeded);
+ virtual void CacheHashResults(const std::vector<SBPrefix>& prefixes,
+ const std::vector<SBFullHashResult>& full_hits);
+
+ private:
friend class SafeBrowsingDatabaseTest;
- FRIEND_TEST_ALL_PREFIXES(SafeBrowsingDatabaseTest, HashCaching);
+ FRIEND_TEST(SafeBrowsingDatabaseTest, HashCaching);
- static FilePath BloomFilterFilename(const FilePath& db_filename);
+ // Deletes the files on disk.
+ bool Delete();
// Load the bloom filter off disk, or generates one if it doesn't exist.
- virtual void LoadBloomFilter();
-
- // Deletes the on-disk bloom filter, i.e. because it's stale.
- virtual void DeleteBloomFilter();
+ void LoadBloomFilter();
// Writes the current bloom filter to disk.
- virtual void WriteBloomFilter();
-
- // Implementation specific bloom filter building.
- virtual void BuildBloomFilter() = 0;
-
- scoped_ptr<HashCache> hash_cache_;
- HashCache* hash_cache() { return hash_cache_.get(); }
-
- // Cache of prefixes that returned empty results (no full hash match).
- typedef std::set<SBPrefix> PrefixCache;
- PrefixCache prefix_miss_cache_;
- PrefixCache* prefix_miss_cache() { return &prefix_miss_cache_; }
-
+ void WriteBloomFilter();
+
+ // Helpers for handling database corruption.
+ // |OnHandleCorruptDatabase()| runs |ResetDatabase()| and sets
+ // |corruption_detected_|, |HandleCorruptDatabase()| posts
+ // |OnHandleCorruptDatabase()| to the current thread, to be run
+ // after the current task completes.
+ // TODO(shess): Wire things up to entirely abort the update
+ // transaction when this happens.
+ void HandleCorruptDatabase();
+ void OnHandleCorruptDatabase();
+
+ // Helpers for InsertChunks().
+ void InsertAdd(int chunk, SBPrefix host, const SBEntry* entry, int list_id);
+ void InsertAddChunks(int list_id, const SBChunkList& chunks);
+ void InsertSub(int chunk, SBPrefix host, const SBEntry* entry, int list_id);
+ void InsertSubChunks(int list_id, const SBChunkList& chunks);
+
+ // 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_|.
+ Lock lookup_lock_;
+
+ // Underlying persistent store for chunk data.
FilePath filename_;
+ scoped_ptr<SafeBrowsingStore> store_;
+
+ // Bloom filter generated from the add-prefixes in |store_|.
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_;
+
+ // Cache of prefixes that returned empty results (no full hash
+ // match) to |CacheHashResults()|. Cached to prevent asking for
+ // them every time. Cleared on next update.
+ std::set<SBPrefix> prefix_miss_cache_;
+
+ // Used to schedule resetting the database because of corruption.
+ ScopedRunnableMethodFactory<SafeBrowsingDatabaseNew> reset_factory_;
+
+ // Set if corruption is detected during the course of an update.
+ // Causes the update functions to fail with no side effects, until
+ // the next call to |UpdateStarted()|.
+ bool corruption_detected_;
};
#endif // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_DATABASE_H_
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_bloom.cc b/chrome/browser/safe_browsing/safe_browsing_database_bloom.cc
index 73f991d..0c636ef 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_bloom.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database_bloom.cc
@@ -11,14 +11,12 @@
#include "base/process_util.h"
#include "base/sha2.h"
#include "base/stats_counters.h"
+#include "base/string_util.h"
#include "chrome/browser/safe_browsing/bloom_filter.h"
#include "chrome/common/sqlite_compiled_statement.h"
#include "chrome/common/sqlite_utils.h"
#include "googleurl/src/gurl.h"
-using base::Time;
-using base::TimeDelta;
-
// Database version. If this is different than what's stored on disk, the
// database is reset.
static const int kDatabaseVersion = 6;
@@ -26,11 +24,6 @@ static const int kDatabaseVersion = 6;
// The maximum staleness for a cached entry.
static const int kMaxStalenessMinutes = 45;
-// The bloom filter based file name suffix.
-static const FilePath::CharType kBloomFilterFileSuffix[] =
- FILE_PATH_LITERAL(" Bloom");
-
-
// Implementation --------------------------------------------------------------
SafeBrowsingDatabaseBloom::SafeBrowsingDatabaseBloom()
@@ -47,8 +40,8 @@ SafeBrowsingDatabaseBloom::~SafeBrowsingDatabaseBloom() {
void SafeBrowsingDatabaseBloom::Init(const FilePath& filename) {
DCHECK(filename_.empty()); // Ensure we haven't been run before.
- filename_ = FilePath(filename.value() + kBloomFilterFileSuffix);
- bloom_filter_filename_ = BloomFilterFilename(filename_);
+ filename_ = FilePath(filename.value());
+ bloom_filter_filename_ = BloomFilterForFilename(filename_);
// NOTE: There is no need to grab the lock in this function, since until it
// returns, there are no pointers to this class on other threads.
@@ -92,7 +85,7 @@ bool SafeBrowsingDatabaseBloom::ContainsUrl(
std::string* matching_list,
std::vector<SBPrefix>* prefix_hits,
std::vector<SBFullHashResult>* full_hits,
- Time last_update) {
+ base::Time last_update) {
// Clear the results first.
matching_list->clear();
@@ -158,7 +151,7 @@ void SafeBrowsingDatabaseBloom::InsertChunks(const std::string& list_name,
if (chunks.empty())
return;
- base::TimeTicks insert_start = base::TimeTicks::Now();
+ const base::TimeTicks insert_start = base::TimeTicks::Now();
int list_id = safe_browsing_util::GetListId(list_name);
ChunkType chunk_type = chunks.front().is_add ? ADD_CHUNK : SUB_CHUNK;
@@ -248,7 +241,7 @@ void SafeBrowsingDatabaseBloom::CacheHashResults(
return;
}
- const Time now = Time::Now();
+ const base::Time now = base::Time::Now();
for (std::vector<SBFullHashResult>::const_iterator it = full_hits.begin();
it != full_hits.end(); ++it) {
SBPrefix prefix = it->hash.prefix;
@@ -280,6 +273,14 @@ bool SafeBrowsingDatabaseBloom::UpdateStarted() {
return true;
}
+bool SafeBrowsingDatabaseBloom::UpdateStarted(
+ std::vector<SBListChunkRanges>* lists) {
+ bool ret = UpdateStarted();
+ if (ret)
+ GetListsInfo(lists);
+ return ret;
+}
+
void SafeBrowsingDatabaseBloom::UpdateFinished(bool update_succeeded) {
if (update_succeeded)
BuildBloomFilter();
@@ -289,7 +290,10 @@ void SafeBrowsingDatabaseBloom::UpdateFinished(bool update_succeeded) {
// We won't need the chunk caches until the next update (which will read them
// from the database), so free their memory as they may contain thousands of
// entries.
- ClearUpdateCaches();
+ {
+ AutoLock lock(lookup_lock_);
+ ClearUpdateCaches();
+ }
}
bool SafeBrowsingDatabaseBloom::Open() {
@@ -481,7 +485,7 @@ void SafeBrowsingDatabaseBloom::BuildBloomFilter() {
metric->GetIOCounters(&io_before);
#endif
- Time before = Time::Now();
+ base::Time before = base::Time::Now();
// Get all the pending GetHash results and write them to disk.
HashList pending_hashes;
@@ -560,7 +564,7 @@ void SafeBrowsingDatabaseBloom::BuildBloomFilter() {
hash_cache_.swap(add_cache);
}
- TimeDelta bloom_gen = Time::Now() - before;
+ base::TimeDelta bloom_gen = base::Time::Now() - before;
// Persist the bloom filter to disk.
WriteBloomFilter();
@@ -596,10 +600,20 @@ void SafeBrowsingDatabaseBloom::BuildBloomFilter() {
int SafeBrowsingDatabaseBloom::PairCompare(const void* arg1, const void* arg2) {
const SBPair* p1 = reinterpret_cast<const SBPair*>(arg1);
const SBPair* p2 = reinterpret_cast<const SBPair*>(arg2);
- int delta = p1->chunk_id - p2->chunk_id;
- if (delta == 0)
- delta = p1->prefix - p2->prefix;
- return delta;
+
+ if (p1->chunk_id < p2->chunk_id)
+ return -1;
+
+ if (p1->chunk_id > p2->chunk_id)
+ return 1;
+
+ if (p1->prefix < p2->prefix)
+ return -1;
+
+ if (p1->prefix > p2->prefix)
+ return 1;
+
+ return 0;
}
bool SafeBrowsingDatabaseBloom::BuildAddPrefixList(SBPair* adds) {
@@ -1007,11 +1021,12 @@ void SafeBrowsingDatabaseBloom::WriteFullHashList(const HashList& hash_list,
void SafeBrowsingDatabaseBloom::GetCachedFullHashes(
const std::vector<SBPrefix>* prefix_hits,
std::vector<SBFullHashResult>* full_hits,
- Time last_update) {
+ base::Time last_update) {
DCHECK(prefix_hits && full_hits);
lookup_lock_.AssertAcquired();
- Time max_age = Time::Now() - TimeDelta::FromMinutes(kMaxStalenessMinutes);
+ const base::Time max_age =
+ base::Time::Now() - base::TimeDelta::FromMinutes(kMaxStalenessMinutes);
for (std::vector<SBPrefix>::const_iterator it = prefix_hits->begin();
it != prefix_hits->end(); ++it) {
@@ -1391,10 +1406,54 @@ bool SafeBrowsingDatabaseBloom::WriteChunkNumbers() {
}
void SafeBrowsingDatabaseBloom::ClearUpdateCaches() {
- AutoLock lock(lookup_lock_);
+ lookup_lock_.AssertAcquired();
add_del_cache_.clear();
sub_del_cache_.clear();
add_chunk_cache_.clear();
sub_chunk_cache_.clear();
prefix_miss_cache_.clear();
}
+
+void SafeBrowsingDatabaseBloom::LoadBloomFilter() {
+ DCHECK(!bloom_filter_filename_.empty());
+
+ // If we're missing either of the database or filter files, we wait until the
+ // next update to generate a new filter.
+ // 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)
+ return;
+
+ if (!file_util::GetFileSize(bloom_filter_filename_, &size_64) ||
+ size_64 == 0) {
+ UMA_HISTOGRAM_COUNTS("SB2.FilterMissing", 1);
+ return;
+ }
+
+ // We have a bloom filter file, so use that as our filter.
+ const base::TimeTicks before = base::TimeTicks::Now();
+ bloom_filter_ = BloomFilter::LoadFile(bloom_filter_filename_);
+ SB_DLOG(INFO) << "SafeBrowsingDatabase read bloom filter in "
+ << (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
+
+ if (!bloom_filter_.get())
+ UMA_HISTOGRAM_COUNTS("SB2.FilterReadFail", 1);
+}
+
+void SafeBrowsingDatabaseBloom::DeleteBloomFilter() {
+ file_util::Delete(bloom_filter_filename_, false);
+}
+
+void SafeBrowsingDatabaseBloom::WriteBloomFilter() {
+ if (!bloom_filter_.get())
+ return;
+
+ const base::TimeTicks before = base::TimeTicks::Now();
+ bool write_ok = bloom_filter_->WriteFile(bloom_filter_filename_);
+ SB_DLOG(INFO) << "SafeBrowsingDatabase wrote bloom filter in " <<
+ (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
+
+ if (!write_ok)
+ UMA_HISTOGRAM_COUNTS("SB2.FilterWriteFail", 1);
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_bloom.h b/chrome/browser/safe_browsing/safe_browsing_database_bloom.h
index 91b3b9c..df3e1a6 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_bloom.h
+++ b/chrome/browser/safe_browsing/safe_browsing_database_bloom.h
@@ -1,23 +1,24 @@
-// 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.
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_DATABASE_BLOOM_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_DATABASE_BLOOM_H_
+#pragma once
-#include <deque>
+#include <list>
#include <set>
-#include <string>
-#include <vector>
+#include "base/hash_tables.h"
#include "base/lock.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "base/task.h"
+#include "base/time.h"
#include "chrome/browser/safe_browsing/safe_browsing_database.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
-namespace base {
- class Time;
-}
-
+class BloomFilter;
struct sqlite3;
class SqliteCompiledStatement;
class SqliteStatementCache;
@@ -29,7 +30,7 @@ class SafeBrowsingDatabaseBloom : public SafeBrowsingDatabase {
SafeBrowsingDatabaseBloom();
virtual ~SafeBrowsingDatabaseBloom();
- // SafeBrowsingDatabase interface:
+ // Implement SafeBrowsingDatabase interface.
virtual void Init(const FilePath& filename);
virtual bool ResetDatabase();
virtual bool ContainsUrl(const GURL& url,
@@ -40,14 +41,36 @@ class SafeBrowsingDatabaseBloom : public SafeBrowsingDatabase {
virtual void InsertChunks(const std::string& list_name,
const SBChunkList& chunks);
virtual void DeleteChunks(const std::vector<SBChunkDelete>& chunk_deletes);
- virtual void GetListsInfo(std::vector<SBListChunkRanges>* lists);
virtual void CacheHashResults(
const std::vector<SBPrefix>& prefixes,
const std::vector<SBFullHashResult>& full_hits);
- virtual bool UpdateStarted();
+ virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists);
virtual void UpdateFinished(bool update_succeeded);
private:
+ friend class SafeBrowsingDatabaseBloomTest;
+ FRIEND_TEST(SafeBrowsingDatabaseBloomTest, HashCaching);
+
+ struct HashCacheEntry {
+ SBFullHash full_hash;
+ int list_id;
+ int add_chunk_id;
+ int sub_chunk_id;
+ base::Time received;
+ };
+
+ typedef std::list<HashCacheEntry> HashList;
+ typedef base::hash_map<SBPrefix, HashList> HashCache;
+
+ // Load the bloom filter off disk, or generates one if it doesn't exist.
+ virtual void LoadBloomFilter();
+
+ // Deletes the on-disk bloom filter, i.e. because it's stale.
+ virtual void DeleteBloomFilter();
+
+ // Writes the current bloom filter to disk.
+ virtual void WriteBloomFilter();
+
struct SBPair {
int chunk_id;
SBPrefix prefix;
@@ -85,6 +108,12 @@ class SafeBrowsingDatabaseBloom : public SafeBrowsingDatabase {
// the given list and chunk type.
void GetChunkIds(int list_id, ChunkType type, std::string* list);
+ // Old implementation methods which have been consolidated into new
+ // |UpdateStarted()| interface. Retained to minimize changes to
+ // this code.
+ void GetListsInfo(std::vector<SBListChunkRanges>* lists);
+ bool UpdateStarted();
+
// Generate a bloom filter.
virtual void BuildBloomFilter();
@@ -148,7 +177,8 @@ class SafeBrowsingDatabaseBloom : public SafeBrowsingDatabase {
void ReadChunkNumbers();
bool WriteChunkNumbers();
- // Flush in memory temporary caches.
+ // Flush in-memory temporary caches. |lookup_lock_| must be locked
+ // by caller.
void ClearUpdateCaches();
// Encode the list id in the lower bit of the chunk.
@@ -200,6 +230,18 @@ class SafeBrowsingDatabaseBloom : public SafeBrowsingDatabase {
// A store for GetHash results that have not yet been written to the database.
HashList pending_full_hashes_;
+ scoped_ptr<HashCache> hash_cache_;
+ HashCache* hash_cache() { return hash_cache_.get(); }
+
+ // Cache of prefixes that returned empty results (no full hash match).
+ typedef std::set<SBPrefix> PrefixCache;
+ PrefixCache prefix_miss_cache_;
+ PrefixCache* prefix_miss_cache() { return &prefix_miss_cache_; }
+
+ FilePath filename_;
+ FilePath bloom_filter_filename_;
+ scoped_refptr<BloomFilter> bloom_filter_;
+
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingDatabaseBloom);
};
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
index 5a94ea4..d381d55 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
@@ -4,29 +4,30 @@
//
// Unit tests for the SafeBrowsing storage system.
+#include "app/sql/connection.h"
+#include "app/sql/statement.h"
#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
+#include "base/scoped_temp_dir.h"
#include "base/sha2.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "base/time.h"
#include "chrome/browser/safe_browsing/protocol_parser.h"
#include "chrome/browser/safe_browsing/safe_browsing_database.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_store_unittest_helper.h"
-#include "chrome/test/file_test_utils.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
using base::Time;
-static const FilePath::CharType kBloomSuffix[] = FILE_PATH_LITERAL(" Bloom");
-static const FilePath::CharType kFolderPrefix[] =
- FILE_PATH_LITERAL("SafeBrowsingTestDatabase");
-
namespace {
SBPrefix Sha256Prefix(const std::string& str) {
@@ -41,6 +42,89 @@ SBFullHash Sha256Hash(const std::string& str) {
return hash;
}
+// Prevent DCHECK from killing tests.
+// TODO(shess): Pawel disputes the use of this, so the test which uses
+// it is DISABLED. http://crbug.com/56448
+class ScopedLogMessageIgnorer {
+ public:
+ ScopedLogMessageIgnorer() {
+ logging::SetLogMessageHandler(&LogMessageIgnorer);
+ }
+ ~ScopedLogMessageIgnorer() {
+ // TODO(shess): Would be better to verify whether anyone else
+ // changed it, and then restore it to the previous value.
+ logging::SetLogMessageHandler(NULL);
+ }
+
+ private:
+ static bool LogMessageIgnorer(int severity, const std::string& str) {
+ // Intercept FATAL, strip the stack backtrace, and log it without
+ // the crash part.
+ if (severity == logging::LOG_FATAL) {
+ size_t newline = str.find('\n');
+ if (newline != std::string::npos) {
+ const std::string msg = str.substr(0, newline + 1);
+ fprintf(stderr, "%s", msg.c_str());
+ fflush(stderr);
+ }
+ return true;
+ }
+
+ return false;
+ }
+};
+
+// Helper function which corrupts the root page of the indicated
+// table. After this the table can be opened successfully, and
+// queries to other tables work, and possibly queries to this table
+// which only hit an index may work, but queries which hit the table
+// itself should not. Returns |true| on success.
+bool CorruptSqliteTable(const FilePath& filename,
+ const std::string& table_name) {
+ size_t root_page; // Root page of the table.
+ size_t page_size; // Page size of the database.
+
+ sql::Connection db;
+ if (!db.Open(filename))
+ return false;
+
+ sql::Statement stmt(db.GetUniqueStatement("PRAGMA page_size"));
+ if (!stmt.Step())
+ return false;
+ page_size = stmt.ColumnInt(0);
+
+ stmt.Assign(db.GetUniqueStatement(
+ "SELECT rootpage FROM sqlite_master WHERE name = ?"));
+ stmt.BindString(0, "sub_prefix");
+ if (!stmt.Step())
+ return false;
+ root_page = stmt.ColumnInt(0);
+
+ // The page numbers are 1-based.
+ const size_t root_page_offset = (root_page - 1) * page_size;
+
+ // Corrupt the file by overwriting the table's root page.
+ FILE* fp = file_util::OpenFile(filename, "r+");
+ if (!fp)
+ return false;
+
+ file_util::ScopedFILE file_closer(fp);
+ if (fseek(fp, root_page_offset, SEEK_SET) == -1)
+ return false;
+
+ for (size_t i = 0; i < page_size; ++i) {
+ fputc('!', fp); // Character experimentally verified.
+ }
+
+ // Close the file manually because if there is an error in the
+ // close, it's likely because the data could not be flushed to the
+ // file.
+ if (!file_util::CloseFile(file_closer.release()))
+ return false;
+
+ return true;
+}
+
} // namespace
class SafeBrowsingDatabaseTest : public PlatformTest {
@@ -48,32 +132,23 @@ class SafeBrowsingDatabaseTest : public PlatformTest {
virtual void SetUp() {
PlatformTest::SetUp();
- // Temporary directory for the database files.
- FilePath temp_dir;
- ASSERT_TRUE(file_util::CreateNewTempDirectory(kFolderPrefix, &temp_dir));
- file_deleter_.reset(new FileAutoDeleter(temp_dir));
-
- FilePath filename(temp_dir);
- filename = filename.AppendASCII("SafeBrowsingTestDatabase");
-
- // In case it existed from a previous run.
- file_util::Delete(FilePath(filename.value() + kBloomSuffix), false);
- file_util::Delete(filename, false);
-
- database_.reset(SafeBrowsingDatabase::Create());
- database_->Init(filename);
+ // Setup a database in a temporary directory.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ database_.reset(new SafeBrowsingDatabaseNew);
+ database_filename_ =
+ temp_dir_.path().AppendASCII("SafeBrowsingTestDatabase");
+ database_->Init(database_filename_);
}
virtual void TearDown() {
database_.reset();
- file_deleter_.reset();
PlatformTest::TearDown();
}
void GetListsInfo(std::vector<SBListChunkRanges>* lists) {
- EXPECT_TRUE(database_->UpdateStarted());
- database_->GetListsInfo(lists);
+ lists->clear();
+ EXPECT_TRUE(database_->UpdateStarted(lists));
database_->UpdateFinished(true);
}
@@ -101,8 +176,9 @@ class SafeBrowsingDatabaseTest : public PlatformTest {
// Utility function for setting up the database for the caching test.
void PopulateDatabaseForCacheTest();
- scoped_ptr<FileAutoDeleter> file_deleter_;
- scoped_ptr<SafeBrowsingDatabase> database_;
+ scoped_ptr<SafeBrowsingDatabaseNew> database_;
+ FilePath database_filename_;
+ ScopedTempDir temp_dir_;
};
// Tests retrieving list name information.
@@ -121,7 +197,8 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
chunk.hosts.push_back(host);
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
+ std::vector<SBListChunkRanges> lists;
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
host.host = Sha256Prefix("www.foo.com/");
@@ -149,12 +226,10 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- std::vector<SBListChunkRanges> lists;
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].adds, "1-3");
EXPECT_TRUE(lists[0].subs.empty());
- lists.clear();
// Insert a malware sub chunk.
host.host = Sha256Prefix("www.subbed.com/");
@@ -169,11 +244,9 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
@@ -187,7 +260,6 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
EXPECT_TRUE(lists[1].adds.empty());
EXPECT_TRUE(lists[1].subs.empty());
}
- lists.clear();
// Add a phishing add chunk.
host.host = Sha256Prefix("www.evil.com/");
@@ -200,8 +272,7 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
chunk.hosts.push_back(host);
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
// Insert some phishing sub chunks.
@@ -231,7 +302,6 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
chunks.push_back(chunk);
database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
@@ -240,7 +310,6 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
EXPECT_TRUE(lists[1].name == safe_browsing_util::kPhishingList);
EXPECT_EQ(lists[1].adds, "47");
EXPECT_EQ(lists[1].subs, "200-201");
- lists.clear();
}
// Checks database reading and writing.
@@ -263,8 +332,7 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.clear();
chunks.push_back(chunk);
std::vector<SBListChunkRanges> lists;
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
// Add another chunk with two different hostkeys.
@@ -305,14 +373,12 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.push_back(chunk);
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
// Make sure they were added correctly.
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].adds, "1-3");
EXPECT_TRUE(lists[0].subs.empty());
- lists.clear();
const Time now = Time::Now();
std::vector<SBFullHashResult> full_hashes;
@@ -351,7 +417,7 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/"),
&matching_list, &prefix_hits,
&full_hashes, now));
- EXPECT_EQ(prefix_hits.size(), 0U);
+ EXPECT_TRUE(prefix_hits.empty());
EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/robots.txt"),
&matching_list, &prefix_hits,
@@ -374,17 +440,14 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].adds, "1-3");
EXPECT_TRUE(lists[0].subs.empty());
- lists.clear();
// Test removing a single prefix from the add chunk.
@@ -402,11 +465,9 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
&matching_list, &prefix_hits,
@@ -417,7 +478,7 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/notevil1.html"),
&matching_list, &prefix_hits,
&full_hashes, now));
- EXPECT_EQ(prefix_hits.size(), 0U);
+ EXPECT_TRUE(prefix_hits.empty());
EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"),
&matching_list, &prefix_hits,
@@ -434,7 +495,6 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].subs, "4");
- lists.clear();
// Test the same sub chunk again. This should be a no-op.
// see bug: http://code.google.com/p/chromium/issues/detail?id=4522
@@ -452,24 +512,18 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].subs, "4");
- lists.clear();
-
// Test removing all the prefixes from an add chunk.
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
AddDelChunk(safe_browsing_util::kMalwareList, 2);
database_->UpdateFinished(true);
- lists.clear();
EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"),
&matching_list, &prefix_hits,
@@ -487,7 +541,6 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].adds, "1,3");
EXPECT_EQ(lists[0].subs, "4");
- lists.clear();
// The adddel command exposed a bug in the transaction code where any
// transaction after it would fail. Add a dummy entry and remove it to
@@ -504,8 +557,7 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
// Now remove the dummy entry. If there are any problems with the
@@ -515,13 +567,11 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
// Test the subdel command.
SubDelChunk(safe_browsing_util::kMalwareList, 4);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
EXPECT_EQ(lists[0].adds, "1,3");
EXPECT_EQ(lists[0].subs, "");
- lists.clear();
// Test a sub command coming in before the add.
host.host = Sha256Prefix("www.notevilanymore.com/");
@@ -539,11 +589,9 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
EXPECT_FALSE(database_->ContainsUrl(
GURL("http://www.notevilanymore.com/index.html"),
@@ -562,11 +610,9 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
EXPECT_FALSE(database_->ContainsUrl(
GURL("http://www.notevilanymore.com/index.html"),
@@ -609,24 +655,20 @@ TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) {
chunks.push_back(chunk);
std::vector<SBListChunkRanges> lists;
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
// Add an empty ADD and SUB chunk.
GetListsInfo(&lists);
EXPECT_EQ(lists[0].adds, "1,10");
- lists.clear();
SBChunk empty_chunk;
empty_chunk.chunk_number = 19;
empty_chunk.is_add = true;
chunks.clear();
chunks.push_back(empty_chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
chunks.clear();
empty_chunk.chunk_number = 7;
@@ -634,12 +676,10 @@ TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) {
chunks.push_back(empty_chunk);
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_EQ(lists[0].adds, "1,10,19");
EXPECT_EQ(lists[0].subs, "7");
- lists.clear();
// Add an empty chunk along with a couple that contain data. This should
// result in the chunk range being reduced in size.
@@ -669,11 +709,9 @@ TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) {
empty_chunk.is_add = true;
chunks.push_back(empty_chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
const Time now = Time::Now();
std::vector<SBFullHashResult> full_hashes;
@@ -689,30 +727,23 @@ TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) {
GetListsInfo(&lists);
EXPECT_EQ(lists[0].adds, "1,10,19-22");
EXPECT_EQ(lists[0].subs, "7");
- lists.clear();
// Handle AddDel and SubDel commands for empty chunks.
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
AddDelChunk(safe_browsing_util::kMalwareList, 21);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_EQ(lists[0].adds, "1,10,19-20,22");
EXPECT_EQ(lists[0].subs, "7");
- lists.clear();
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
SubDelChunk(safe_browsing_util::kMalwareList, 7);
database_->UpdateFinished(true);
- lists.clear();
GetListsInfo(&lists);
EXPECT_EQ(lists[0].adds, "1,10,19-20,22");
EXPECT_EQ(lists[0].subs, "");
- lists.clear();
}
// Utility function for setting up the database for the caching test.
@@ -733,11 +764,9 @@ void SafeBrowsingDatabaseTest::PopulateDatabaseForCacheTest() {
SBChunkList chunks;
std::vector<SBListChunkRanges> lists;
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
// Add the GetHash results to the cache.
SBFullHashResult full_hash;
@@ -759,8 +788,7 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
PopulateDatabaseForCacheTest();
// We should have both full hashes in the cache.
- SafeBrowsingDatabase::HashCache* hash_cache = database_->hash_cache();
- EXPECT_EQ(hash_cache->size(), 2U);
+ EXPECT_EQ(database_->pending_hashes_.size(), 2U);
// Test the cache lookup for the first prefix.
std::string listname;
@@ -802,11 +830,9 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
chunks.push_back(chunk);
std::vector<SBListChunkRanges> lists;
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- lists.clear();
// This prefix should still be there.
database_->ContainsUrl(GURL("http://www.evil.com/malware.html"),
@@ -821,22 +847,21 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
// This prefix should be gone.
database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
&listname, &prefixes, &full_hashes, Time::Now());
- EXPECT_EQ(full_hashes.size(), 0U);
+ EXPECT_TRUE(full_hashes.empty());
prefixes.clear();
full_hashes.clear();
// Test that an AddDel for the original chunk removes the last cached entry.
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ 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());
- EXPECT_EQ(full_hashes.size(), 0U);
- EXPECT_EQ(database_->hash_cache()->size(), 0U);
+ EXPECT_TRUE(full_hashes.empty());
+ EXPECT_TRUE(database_->full_hashes_.empty());
+ EXPECT_TRUE(database_->pending_hashes_.empty());
- lists.clear();
prefixes.clear();
full_hashes.clear();
@@ -844,21 +869,25 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
// the cached entries' received time to make them older, since the database
// cache insert uses Time::Now(). First, store some entries.
PopulateDatabaseForCacheTest();
- hash_cache = database_->hash_cache();
+
+ std::vector<SBAddFullHash>* hash_cache = &database_->pending_hashes_;
EXPECT_EQ(hash_cache->size(), 2U);
// Now adjust one of the entries times to be in the past.
base::Time expired = base::Time::Now() - base::TimeDelta::FromMinutes(60);
const SBPrefix key = Sha256Prefix("www.evil.com/malware.html");
- SafeBrowsingDatabase::HashList& entries = (*hash_cache)[key];
- SafeBrowsingDatabase::HashCacheEntry entry = entries.front();
- entries.pop_front();
- entry.received = expired;
- entries.push_back(entry);
+ std::vector<SBAddFullHash>::iterator iter;
+ for (iter = hash_cache->begin(); iter != hash_cache->end(); ++iter) {
+ if (iter->full_hash.prefix == key) {
+ iter->received = static_cast<int32>(expired.ToTimeT());
+ break;
+ }
+ }
+ EXPECT_TRUE(iter != hash_cache->end());
database_->ContainsUrl(GURL("http://www.evil.com/malware.html"),
&listname, &prefixes, &full_hashes, expired);
- EXPECT_EQ(full_hashes.size(), 0U);
+ EXPECT_TRUE(full_hashes.empty());
// This entry should still exist.
database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
@@ -869,11 +898,9 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
// Testing prefix miss caching. First, we clear out the existing database,
// Since PopulateDatabaseForCacheTest() doesn't handle adding duplicate
// chunks.
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
AddDelChunk(safe_browsing_util::kMalwareList, 1);
database_->UpdateFinished(true);
- lists.clear();
std::vector<SBPrefix> prefix_misses;
std::vector<SBFullHashResult> empty_full_hash;
@@ -882,13 +909,13 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
database_->CacheHashResults(prefix_misses, empty_full_hash);
// Prefixes with no full results are misses.
- EXPECT_EQ(database_->prefix_miss_cache()->size(), 2U);
+ EXPECT_EQ(database_->prefix_miss_cache_.size(), 2U);
// Update the database.
PopulateDatabaseForCacheTest();
// Prefix miss cache should be cleared.
- EXPECT_EQ(database_->prefix_miss_cache()->size(), 0U);
+ EXPECT_TRUE(database_->prefix_miss_cache_.empty());
// Cache a GetHash miss for a particular prefix, and even though the prefix is
// in the database, it is flagged as a miss so looking up the associated URL
@@ -903,7 +930,6 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
&listname, &prefixes,
&full_hashes, Time::Now()));
- lists.clear();
prefixes.clear();
full_hashes.clear();
@@ -920,8 +946,7 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
chunk.hosts.push_back(host);
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
@@ -931,7 +956,6 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.fullevil.com/bad1.html")));
- lists.clear();
prefixes.clear();
full_hashes.clear();
@@ -941,7 +965,6 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.fullevil.com/bad2.html")));
- lists.clear();
prefixes.clear();
full_hashes.clear();
@@ -958,15 +981,14 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
chunk.hosts.push_back(host);
chunks.clear();
chunks.push_back(chunk);
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
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_EQ(full_hashes.size(), 0U);
+ EXPECT_TRUE(full_hashes.empty());
// There should be one remaining full add.
EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad2.html"),
@@ -975,16 +997,13 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.fullevil.com/bad2.html")));
- lists.clear();
prefixes.clear();
full_hashes.clear();
// Now test an AddDel for the remaining full add.
- database_->UpdateStarted();
- database_->GetListsInfo(&lists);
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
AddDelChunk(safe_browsing_util::kMalwareList, 20);
database_->UpdateFinished(true);
- lists.clear();
EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad1.html"),
&listname, &prefixes, &full_hashes,
@@ -994,22 +1013,176 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
Time::Now()));
}
+// Test that corrupt databases are appropriately handled, even if the
+// corruption is detected in the midst of the update.
+// TODO(shess): Disabled until ScopedLogMessageIgnorer resolved.
+// http://crbug.com/56448
+TEST_F(SafeBrowsingDatabaseTest, DISABLED_SqliteCorruptionHandling) {
+ // Re-create the database in a captive message loop so that we can
+ // influence task-posting. Database specifically needs to the
+ // SQLite-backed.
+ database_.reset();
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ SafeBrowsingStoreSqlite* store = new SafeBrowsingStoreSqlite();
+ database_.reset(new SafeBrowsingDatabaseNew(store));
+ database_->Init(database_filename_);
+
+ // This will cause an empty database to be created.
+ std::vector<SBListChunkRanges> lists;
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->UpdateFinished(true);
+
+ // Create a sub chunk to insert.
+ SBChunkList chunks;
+ SBChunk chunk;
+ SBChunkHost host;
+ host.host = Sha256Prefix("www.subbed.com/");
+ host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1);
+ host.entry->set_chunk_id(7);
+ host.entry->SetChunkIdAtPrefix(0, 19);
+ host.entry->SetPrefixAt(0, Sha256Prefix("www.subbed.com/notevil1.html"));
+ chunk.chunk_number = 7;
+ chunk.is_add = false;
+ chunk.hosts.clear();
+ chunk.hosts.push_back(host);
+ chunks.clear();
+ chunks.push_back(chunk);
+
+ // Corrupt the |sub_prefix| table.
+ ASSERT_TRUE(CorruptSqliteTable(database_filename_, "sub_prefix"));
+
+ {
+ // The following code will cause DCHECKs, so suppress the crashes.
+ ScopedLogMessageIgnorer ignorer;
+
+ // Start an update. The insert will fail due to corruption.
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ LOG(INFO) << "Expect failed check on: sqlite error 11";
+ database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
+
+ // Database file still exists until the corruption handler has run.
+ EXPECT_TRUE(file_util::PathExists(database_filename_));
+
+ // Flush through the corruption-handler task.
+ LOG(INFO) << "Expect failed check on: SafeBrowsing database reset";
+ MessageLoop::current()->RunAllPending();
+ }
+
+ // Database file should not exist.
+ EXPECT_FALSE(file_util::PathExists(database_filename_));
+
+ // Finish the transaction. This should short-circuit, so no
+ // DCHECKs.
+ database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
+ database_->UpdateFinished(true);
+
+ // Flush through any posted tasks.
+ MessageLoop::current()->RunAllPending();
+
+ // Database file should still not exist.
+ EXPECT_FALSE(file_util::PathExists(database_filename_));
+
+ // Run the update again successfully.
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
+ database_->UpdateFinished(true);
+ EXPECT_TRUE(file_util::PathExists(database_filename_));
+
+ database_.reset();
+}
+
+// Test that corrupt databases are appropriately handled, even if the
+// corruption is detected in the midst of the update.
+// TODO(shess): Disabled until ScopedLogMessageIgnorer resolved.
+// http://crbug.com/56448
+TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) {
+ // Re-create the database in a captive message loop so that we can
+ // influence task-posting. Database specifically needs to the
+ // file-backed.
+ database_.reset();
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile();
+ database_.reset(new SafeBrowsingDatabaseNew(store));
+ database_->Init(database_filename_);
+
+ // This will cause an empty database to be created.
+ std::vector<SBListChunkRanges> lists;
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->UpdateFinished(true);
+
+ // Create a sub chunk to insert.
+ SBChunkList chunks;
+ SBChunk chunk;
+ SBChunkHost host;
+ host.host = Sha256Prefix("www.subbed.com/");
+ host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1);
+ host.entry->set_chunk_id(7);
+ host.entry->SetChunkIdAtPrefix(0, 19);
+ host.entry->SetPrefixAt(0, Sha256Prefix("www.subbed.com/notevil1.html"));
+ chunk.chunk_number = 7;
+ chunk.is_add = false;
+ chunk.hosts.clear();
+ chunk.hosts.push_back(host);
+ chunks.clear();
+ chunks.push_back(chunk);
+
+ // Corrupt the file by corrupting the checksum, which is not checked
+ // until the entire table is read in |UpdateFinished()|.
+ FILE* fp = file_util::OpenFile(database_filename_, "r+");
+ ASSERT_TRUE(fp);
+ ASSERT_NE(-1, fseek(fp, -8, SEEK_END));
+ for (size_t i = 0; i < 8; ++i) {
+ fputc('!', fp);
+ }
+ fclose(fp);
+
+ {
+ // The following code will cause DCHECKs, so suppress the crashes.
+ ScopedLogMessageIgnorer ignorer;
+
+ // Start an update. The insert will fail due to corruption.
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
+ database_->UpdateFinished(true);
+
+ // Database file still exists until the corruption handler has run.
+ EXPECT_TRUE(file_util::PathExists(database_filename_));
+
+ // Flush through the corruption-handler task.
+ LOG(INFO) << "Expect failed check on: SafeBrowsing database reset";
+ MessageLoop::current()->RunAllPending();
+ }
+
+ // Database file should not exist.
+ EXPECT_FALSE(file_util::PathExists(database_filename_));
+
+ // Run the update again successfully.
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
+ database_->UpdateFinished(true);
+ EXPECT_TRUE(file_util::PathExists(database_filename_));
+
+ database_.reset();
+}
+
namespace {
void PrintStat(const char* name) {
int value = StatsTable::current()->GetCounterValue(name);
- LOG(INFO) << StringPrintf("%s %d", name, value);
+ SB_DLOG(INFO) << StringPrintf("%s %d", name, value);
}
FilePath GetFullSBDataPath(const FilePath& path) {
FilePath full_path;
- CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &full_path));
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &full_path)) {
+ ADD_FAILURE() << "Unable to find test DIR_SOURCE_ROOT for test data.";
+ return FilePath();
+ }
full_path = full_path.AppendASCII("chrome");
full_path = full_path.AppendASCII("test");
full_path = full_path.AppendASCII("data");
full_path = full_path.AppendASCII("safe_browsing");
full_path = full_path.Append(path);
- CHECK(file_util::PathExists(full_path));
return full_path;
}
@@ -1021,26 +1194,21 @@ struct ChunksInfo {
std::string listname;
};
-void PerformUpdate(const FilePath& initial_db,
+// TODO(shess): Move this into SafeBrowsingDatabaseTest.
+void PerformUpdate(SafeBrowsingDatabaseNew* database,
+ const FilePath& database_filename,
+ const FilePath& initial_db,
const std::vector<ChunksInfo>& chunks,
const std::vector<SBChunkDelete>& deletes) {
base::IoCounters before, after;
- FilePath path;
- PathService::Get(base::DIR_TEMP, &path);
- path = path.AppendASCII("SafeBrowsingTestDatabase");
-
- // In case it existed from a previous run.
- file_util::Delete(path, false);
-
if (!initial_db.empty()) {
FilePath full_initial_db = GetFullSBDataPath(initial_db);
- ASSERT_TRUE(file_util::CopyFile(full_initial_db, path));
+ ASSERT_FALSE(full_initial_db.empty());
+ ASSERT_TRUE(file_util::PathExists(full_initial_db));
+ ASSERT_TRUE(file_util::CopyFile(full_initial_db, database_filename));
}
- SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create();
- database->Init(path);
-
Time before_time = Time::Now();
base::ProcessHandle handle = base::Process::Current().handle();
scoped_ptr<base::ProcessMetrics> metric(
@@ -1056,28 +1224,26 @@ void PerformUpdate(const FilePath& initial_db,
bool gotIOCounters = metric->GetIOCounters(&before);
std::vector<SBListChunkRanges> lists;
- database->UpdateStarted();
- database->GetListsInfo(&lists);
+ EXPECT_TRUE(database->UpdateStarted(&lists));
database->DeleteChunks(deletes);
for (size_t i = 0; i < chunks.size(); ++i)
database->InsertChunks(chunks[i].listname, *chunks[i].chunks);
database->UpdateFinished(true);
- lists.clear();
gotIOCounters = gotIOCounters && metric->GetIOCounters(&after);
if (gotIOCounters) {
- LOG(INFO) << StringPrintf("I/O Read Bytes: %" PRIu64,
+ SB_DLOG(INFO) << StringPrintf("I/O Read Bytes: %" PRIu64,
after.ReadTransferCount - before.ReadTransferCount);
- LOG(INFO) << StringPrintf("I/O Write Bytes: %" PRIu64,
+ SB_DLOG(INFO) << StringPrintf("I/O Write Bytes: %" PRIu64,
after.WriteTransferCount - before.WriteTransferCount);
- LOG(INFO) << StringPrintf("I/O Reads: %" PRIu64,
+ SB_DLOG(INFO) << StringPrintf("I/O Reads: %" PRIu64,
after.ReadOperationCount - before.ReadOperationCount);
- LOG(INFO) << StringPrintf("I/O Writes: %" PRIu64,
+ SB_DLOG(INFO) << StringPrintf("I/O Writes: %" PRIu64,
after.WriteOperationCount - before.WriteOperationCount);
}
- LOG(INFO) << StringPrintf("Finished in %" PRId64 " ms",
+ SB_DLOG(INFO) << StringPrintf("Finished in %" PRId64 " ms",
(Time::Now() - before_time).InMilliseconds());
PrintStat("c:SB.HostSelect");
@@ -1089,11 +1255,11 @@ void PerformUpdate(const FilePath& initial_db,
PrintStat("c:SB.ChunkInsert");
PrintStat("c:SB.ChunkDelete");
PrintStat("c:SB.TransactionCommit");
-
- delete database;
}
-void UpdateDatabase(const FilePath& initial_db,
+void UpdateDatabase(SafeBrowsingDatabaseNew* database,
+ const FilePath& database_filename,
+ const FilePath& initial_db,
const FilePath& response_path,
const FilePath& updates_path) {
// First we read the chunks from disk, so that this isn't counted in IO bytes.
@@ -1102,6 +1268,8 @@ void UpdateDatabase(const FilePath& initial_db,
SafeBrowsingProtocolParser parser;
if (!updates_path.empty()) {
FilePath data_dir = GetFullSBDataPath(updates_path);
+ ASSERT_FALSE(data_dir.empty());
+ ASSERT_TRUE(file_util::PathExists(data_dir));
file_util::FileEnumerator file_enum(data_dir, false,
file_util::FileEnumerator::FILES);
while (true) {
@@ -1111,7 +1279,7 @@ void UpdateDatabase(const FilePath& initial_db,
int64 size64;
bool result = file_util::GetFileSize(file, &size64);
- CHECK(result);
+ ASSERT_TRUE(result);
int size = static_cast<int>(size64);
scoped_array<char> data(new char[size]);
@@ -1123,7 +1291,7 @@ void UpdateDatabase(const FilePath& initial_db,
bool re_key;
result = parser.ParseChunk(data.get(), size, "", "",
&re_key, info.chunks);
- CHECK(result);
+ ASSERT_TRUE(result);
info.listname = WideToASCII(file.BaseName().ToWStringHack());
size_t index = info.listname.find('_'); // Get rid fo the _s or _a.
@@ -1138,6 +1306,8 @@ void UpdateDatabase(const FilePath& initial_db,
if (!response_path.empty()) {
std::string update;
FilePath full_response_path = GetFullSBDataPath(response_path);
+ ASSERT_FALSE(full_response_path.empty());
+ ASSERT_TRUE(file_util::PathExists(full_response_path));
if (file_util::ReadFileToString(full_response_path, &update)) {
int next_update;
bool result, rekey, reset;
@@ -1150,13 +1320,13 @@ void UpdateDatabase(const FilePath& initial_db,
&reset,
&deletes,
&urls);
- DCHECK(result);
+ ASSERT_TRUE(result);
if (!updates_path.empty())
- DCHECK(urls.size() == chunks.size());
+ ASSERT_EQ(urls.size(), chunks.size());
}
}
- PerformUpdate(initial_db, chunks, deletes);
+ PerformUpdate(database, database_filename, initial_db, chunks, deletes);
// TODO(shess): Make ChunksInfo handle this via scoping.
for (std::vector<ChunksInfo>::iterator iter = chunks.begin();
@@ -1188,30 +1358,33 @@ FilePath GetOldUpdatesPath() {
// Counts the IO needed for the initial update of a database.
// test\data\safe_browsing\download_update.py was used to fetch the add/sub
// chunks that are read, in order to get repeatable runs.
-TEST(SafeBrowsingDatabase, DatabaseInitialIO) {
- UpdateDatabase(FilePath(), FilePath(), FilePath().AppendASCII("initial"));
+TEST_F(SafeBrowsingDatabaseTest, DatabaseInitialIO) {
+ UpdateDatabase(database_.get(), database_filename_,
+ FilePath(), FilePath(), FilePath().AppendASCII("initial"));
}
// Counts the IO needed to update a month old database.
// The data files were generated by running "..\download_update.py postdata"
// in the "safe_browsing\old" directory.
-TEST(SafeBrowsingDatabase, DatabaseOldIO) {
- UpdateDatabase(GetOldSafeBrowsingPath(), GetOldResponsePath(),
- GetOldUpdatesPath());
+TEST_F(SafeBrowsingDatabaseTest, DatabaseOldIO) {
+ UpdateDatabase(database_.get(), database_filename_, GetOldSafeBrowsingPath(),
+ GetOldResponsePath(), GetOldUpdatesPath());
}
// Like DatabaseOldIO but only the deletes.
-TEST(SafeBrowsingDatabase, DatabaseOldDeletesIO) {
- UpdateDatabase(GetOldSafeBrowsingPath(), GetOldResponsePath(), FilePath());
+TEST_F(SafeBrowsingDatabaseTest, DatabaseOldDeletesIO) {
+ UpdateDatabase(database_.get(), database_filename_,
+ GetOldSafeBrowsingPath(), GetOldResponsePath(), FilePath());
}
// Like DatabaseOldIO but only the updates.
-TEST(SafeBrowsingDatabase, DatabaseOldUpdatesIO) {
- UpdateDatabase(GetOldSafeBrowsingPath(), FilePath(), GetOldUpdatesPath());
+TEST_F(SafeBrowsingDatabaseTest, DatabaseOldUpdatesIO) {
+ UpdateDatabase(database_.get(), database_filename_,
+ GetOldSafeBrowsingPath(), FilePath(), GetOldUpdatesPath());
}
// Does a a lot of addel's on very large chunks.
-TEST(SafeBrowsingDatabase, DatabaseOldLotsofDeletesIO) {
+TEST_F(SafeBrowsingDatabaseTest, DatabaseOldLotsofDeletesIO) {
std::vector<ChunksInfo> chunks;
std::vector<SBChunkDelete> deletes;
SBChunkDelete del;
@@ -1219,5 +1392,6 @@ TEST(SafeBrowsingDatabase, DatabaseOldLotsofDeletesIO) {
del.list_name = safe_browsing_util::kMalwareList;
del.chunk_del.push_back(ChunkRange(3539, 3579));
deletes.push_back(del);
- PerformUpdate(GetOldSafeBrowsingPath(), chunks, deletes);
+ PerformUpdate(database_.get(), database_filename_,
+ GetOldSafeBrowsingPath(), chunks, deletes);
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index a5aaa12..e0ac3d7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.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.
//
@@ -11,7 +11,7 @@
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/metrics_service.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/safe_browsing/protocol_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
@@ -55,6 +55,7 @@ SafeBrowsingService::SafeBrowsingService()
protocol_manager_(NULL),
enabled_(false),
update_in_progress_(false),
+ database_update_in_progress_(false),
closing_database_(false) {
}
@@ -148,6 +149,7 @@ void SafeBrowsingService::CancelCheck(Client* client) {
}
void SafeBrowsingService::DisplayBlockingPage(const GURL& url,
+ const GURL& original_url,
ResourceType::Type resource_type,
UrlCheckResult result,
Client* client,
@@ -173,6 +175,7 @@ void SafeBrowsingService::DisplayBlockingPage(const GURL& url,
UnsafeResource resource;
resource.url = url;
+ resource.original_url = original_url;
resource.resource_type = resource_type;
resource.threat_type= result;
resource.client = client;
@@ -362,7 +365,9 @@ void SafeBrowsingService::OnIOInitialize(
#endif
#endif
CommandLine* cmdline = CommandLine::ForCurrentProcess();
- bool disable_auto_update = cmdline->HasSwitch(switches::kSbDisableAutoUpdate);
+ bool disable_auto_update =
+ cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
+ cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
std::string info_url_prefix =
cmdline->HasSwitch(switches::kSbInfoURLPrefix) ?
cmdline->GetSwitchValueASCII(switches::kSbInfoURLPrefix) :
@@ -451,7 +456,7 @@ bool SafeBrowsingService::MakeDatabaseAvailable() {
}
SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
if (database_)
return database_;
@@ -521,12 +526,14 @@ void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) {
}
void SafeBrowsingService::GetAllChunksFromDatabase() {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
+
bool database_error = true;
std::vector<SBListChunkRanges> lists;
+ DCHECK(!database_update_in_progress_);
+ database_update_in_progress_ = true;
GetDatabase(); // This guarantees that |database_| is non-NULL.
- if (database_->UpdateStarted()) {
- database_->GetListsInfo(&lists);
+ if (database_->UpdateStarted(&lists)) {
database_error = false;
} else {
database_->UpdateFinished(false);
@@ -579,7 +586,7 @@ void SafeBrowsingService::DatabaseLoadComplete() {
void SafeBrowsingService::HandleChunkForDatabase(
const std::string& list_name,
SBChunkList* chunks) {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
if (chunks) {
GetDatabase()->InsertChunks(list_name, *chunks);
delete chunks;
@@ -591,7 +598,7 @@ void SafeBrowsingService::HandleChunkForDatabase(
void SafeBrowsingService::DeleteChunks(
std::vector<SBChunkDelete>* chunk_deletes) {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
if (chunk_deletes) {
GetDatabase()->DeleteChunks(*chunk_deletes);
delete chunk_deletes;
@@ -618,8 +625,10 @@ void SafeBrowsingService::NotifyClientBlockingComplete(Client* client,
}
void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
GetDatabase()->UpdateFinished(update_succeeded);
+ DCHECK(database_update_in_progress_);
+ database_update_in_progress_ = false;
}
void SafeBrowsingService::Start() {
@@ -651,7 +660,7 @@ void SafeBrowsingService::Start() {
}
void SafeBrowsingService::OnCloseDatabase() {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
DCHECK(closing_database_);
// Because |closing_database_| is true, nothing on the IO thread will be
@@ -668,14 +677,14 @@ void SafeBrowsingService::OnCloseDatabase() {
}
void SafeBrowsingService::OnResetDatabase() {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
GetDatabase()->ResetDatabase();
}
void SafeBrowsingService::CacheHashResults(
const std::vector<SBPrefix>& prefixes,
const std::vector<SBFullHashResult>& full_hashes) {
- DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop());
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
GetDatabase()->CacheHashResults(prefixes, full_hashes);
}
@@ -744,26 +753,44 @@ void SafeBrowsingService::DoDisplayBlockingPage(
return;
}
- // Report the malware sub-resource to the SafeBrowsing servers if we have a
- // malware sub-resource on a safe page and only if the user has opted in to
+ // Report the malware resource to the SafeBrowsing servers if we have a
+ // malware resource on a safe page and only if the user has opted in to
// reporting statistics.
const MetricsService* metrics = g_browser_process->metrics_service();
DCHECK(metrics);
if (metrics && metrics->reporting_active() &&
- resource.resource_type != ResourceType::MAIN_FRAME &&
resource.threat_type == SafeBrowsingService::URL_MALWARE) {
GURL page_url = wc->GetURL();
GURL referrer_url;
NavigationEntry* entry = wc->controller().GetActiveEntry();
if (entry)
referrer_url = entry->referrer();
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(this,
- &SafeBrowsingService::ReportMalware,
- resource.url,
- page_url,
- referrer_url));
+ bool is_subresource = resource.resource_type != ResourceType::MAIN_FRAME;
+
+ // When the malicious url is on the main frame, and resource.original_url
+ // is not the same as the resource.url, that means we have a redirect from
+ // resource.original_url to resource.url.
+ // Also, at this point, page_url points to the _previous_ page that we
+ // were on. We replace page_url with resource.original_url and referrer
+ // with page_url.
+ if (!is_subresource &&
+ !resource.original_url.is_empty() &&
+ resource.original_url != resource.url) {
+ referrer_url = page_url;
+ page_url = resource.original_url;
+ }
+
+ if ((!page_url.is_empty() && resource.url != page_url) ||
+ !referrer_url.is_empty()) {
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this,
+ &SafeBrowsingService::ReportMalware,
+ resource.url,
+ page_url,
+ referrer_url,
+ is_subresource));
+ }
}
SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
@@ -771,7 +798,8 @@ void SafeBrowsingService::DoDisplayBlockingPage(
void SafeBrowsingService::ReportMalware(const GURL& malware_url,
const GURL& page_url,
- const GURL& referrer_url) {
+ const GURL& referrer_url,
+ bool is_subresource) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
if (!enabled_)
@@ -779,7 +807,8 @@ void SafeBrowsingService::ReportMalware(const GURL& malware_url,
if (DatabaseAvailable()) {
// Check if 'page_url' is already blacklisted (exists in our cache). Only
- // report if it's not there.
+ // report if it's not there. This can happen if the user has ignored
+ // the warning for page_url and is now hitting a warning for a resource.
std::string list;
std::vector<SBPrefix> prefix_hits;
std::vector<SBFullHashResult> full_hits;
@@ -789,5 +818,9 @@ void SafeBrowsingService::ReportMalware(const GURL& malware_url,
return;
}
- protocol_manager_->ReportMalware(malware_url, page_url, referrer_url);
+ DLOG(INFO) << "ReportMalware: " << malware_url << " " << page_url << " " <<
+ referrer_url << " " << is_subresource;
+
+ protocol_manager_->ReportMalware(malware_url, page_url, referrer_url,
+ is_subresource);
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index ae95362..f972395 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.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.
//
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SERVICE_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SERVICE_H_
+#pragma once
#include <deque>
#include <set>
@@ -16,14 +17,13 @@
#include "base/hash_tables.h"
#include "base/lock.h"
#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
#include "base/time.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/resource_type.h"
-class BloomFilter;
class PrefService;
-class SafeBrowsingBlockingPage;
class SafeBrowsingDatabase;
class SafeBrowsingProtocolManager;
class URLRequestContextGetter;
@@ -60,6 +60,7 @@ class SafeBrowsingService
// interacting with the blocking page.
struct UnsafeResource {
GURL url;
+ GURL original_url;
ResourceType::Type resource_type;
UrlCheckResult threat_type;
Client* client;
@@ -101,7 +102,12 @@ class SafeBrowsingService
void CancelCheck(Client* client);
// Called on the IO thread to display an interstitial page.
+ // |url| is the url of the resource that matches a safe browsing list.
+ // If the request contained a chain of redirects, |url| is the last url
+ // in the chain, and |original_url| is the first one (the root of the
+ // chain). Otherwise, |original_url| = |url|.
void DisplayBlockingPage(const GURL& url,
+ const GURL& original_url,
ResourceType::Type resource_type,
UrlCheckResult result,
Client* client,
@@ -267,7 +273,8 @@ class SafeBrowsingService
// service.
void ReportMalware(const GURL& malware_url,
const GURL& page_url,
- const GURL& referrer_url);
+ const GURL& referrer_url,
+ bool is_subresource);
CurrentChecks checks_;
@@ -300,6 +307,10 @@ class SafeBrowsingService
// Indicates if we're currently in an update cycle.
bool update_in_progress_;
+ // When true, newly fetched chunks may not in the database yet since the
+ // database is still updating.
+ bool database_update_in_progress_;
+
// Indicates if we're in the midst of trying to close the database. If this
// is true, nothing on the IO thread should access the database.
bool closing_database_;
diff --git a/chrome/browser/safe_browsing/safe_browsing_store.cc b/chrome/browser/safe_browsing/safe_browsing_store.cc
index 21fd37f..ea5d4f5 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/safe_browsing/safe_browsing_store.h"
+#include <algorithm>
+
namespace {
// Find items matching between |subs| and |adds|, and remove them,
@@ -100,12 +102,31 @@ void RemoveMatchingPrefixes(const std::vector<SBAddPrefix>& removes,
full_hashes->erase(out, hash_iter);
}
+// Remove deleted items (|chunk_id| in |del_set|) from the vector.
+template <class T>
+void RemoveDeleted(std::vector<T>* vec, const base::hash_set<int32>& del_set) {
+ DCHECK(vec);
+
+ // Scan through the items read, dropping the items in |del_set|.
+ typename std::vector<T>::iterator add_iter = vec->begin();
+ for (typename std::vector<T>::iterator iter = add_iter;
+ iter != vec->end(); ++iter) {
+ if (del_set.count(iter->chunk_id) == 0) {
+ *add_iter = *iter;
+ ++add_iter;
+ }
+ }
+ vec->erase(add_iter, vec->end());
+}
+
} // namespace
void SBProcessSubs(std::vector<SBAddPrefix>* add_prefixes,
std::vector<SBSubPrefix>* sub_prefixes,
std::vector<SBAddFullHash>* add_full_hashes,
- std::vector<SBSubFullHash>* sub_full_hashes) {
+ std::vector<SBSubFullHash>* sub_full_hashes,
+ const base::hash_set<int32>& add_chunks_deleted,
+ const base::hash_set<int32>& sub_chunks_deleted) {
// It is possible to structure templates and template
// specializations such that the following calls work without having
// to qualify things. It becomes very arbitrary, though, and less
@@ -135,6 +156,7 @@ void SBProcessSubs(std::vector<SBAddPrefix>* add_prefixes,
RemoveMatchingPrefixes(removed_adds, add_full_hashes);
RemoveMatchingPrefixes(removed_adds, sub_full_hashes);
+ // http://crbug.com/52385
// TODO(shess): AFAICT this pass is not done on the trunk. I
// believe that's a bug, but it may not matter because full-hash
// subs almost never happen (I think you'd need multiple collisions
@@ -149,4 +171,12 @@ void SBProcessSubs(std::vector<SBAddPrefix>* add_prefixes,
SBAddPrefixHashLess<SBSubFullHash,SBAddFullHash>,
&removed_full_adds);
}
+
+ // Remove items from the deleted chunks. This is done after other
+ // processing to allow subs to knock out adds (and be removed) even
+ // if the add's chunk is deleted.
+ RemoveDeleted(add_prefixes, add_chunks_deleted);
+ RemoveDeleted(sub_prefixes, sub_chunks_deleted);
+ RemoveDeleted(add_full_hashes, add_chunks_deleted);
+ RemoveDeleted(sub_full_hashes, sub_chunks_deleted);
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_store.h b/chrome/browser/safe_browsing/safe_browsing_store.h
index 9ecb535..b6b44bd 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store.h
@@ -4,17 +4,19 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_H_
+#pragma once
-#include <set>
#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
-#include "base/file_path.h"
+#include "base/hash_tables.h"
#include "base/task.h"
#include "base/time.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
+class FilePath;
+
// SafeBrowsingStore provides a storage abstraction for the
// safe-browsing data used to build the bloom filter. The items
// stored are:
@@ -123,7 +125,8 @@ bool SBAddPrefixHashLess(const T& a, const U& b) {
// Process the lists for subs which knock out adds. For any item in
// |sub_prefixes| which has a match in |add_prefixes|, knock out the
-// matched items from all vectors.
+// matched items from all vectors. Additionally remove items from
+// deleted chunks.
//
// TODO(shess): Since the prefixes are uniformly-distributed hashes,
// there aren't many ways to organize the inputs for efficient
@@ -138,7 +141,9 @@ bool SBAddPrefixHashLess(const T& a, const U& b) {
void SBProcessSubs(std::vector<SBAddPrefix>* add_prefixes,
std::vector<SBSubPrefix>* sub_prefixes,
std::vector<SBAddFullHash>* add_full_hashes,
- std::vector<SBSubFullHash>* sub_full_hashes);
+ std::vector<SBSubFullHash>* sub_full_hashes,
+ const base::hash_set<int32>& add_chunks_deleted,
+ const base::hash_set<int32>& sub_chunks_deleted);
// TODO(shess): This uses int32 rather than int because it's writing
// specifically-sized items to files. SBPrefix should likewise be
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.cc b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
index 207a607..4e4136c 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_file.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
#include "base/callback.h"
+#include "base/histogram.h"
#include "base/md5.h"
// TODO(shess): Remove after migration.
@@ -108,39 +109,6 @@ bool WriteVector(const std::vector<T>& values, FILE* fp, MD5Context* context) {
return WriteArray(ptr, values.size(), fp, context);
}
-// Remove deleted items (|chunk_id| in |del_set|) from the vector
-// starting at |offset| running to |end()|.
-template <class T>
-void RemoveDeleted(std::vector<T>* vec, size_t offset,
- const base::hash_set<int32>& del_set) {
- DCHECK(vec);
-
- // Scan through the items read, dropping the items in |del_set|.
- typename std::vector<T>::iterator add_iter = vec->begin() + offset;
- for (typename std::vector<T>::iterator iter = add_iter;
- iter != vec->end(); ++iter) {
- if (del_set.count(iter->chunk_id) == 0) {
- *add_iter = *iter;
- ++add_iter;
- }
- }
- vec->erase(add_iter, vec->end());
-}
-
-// Combine |ReadToVector()| and |RemoveDeleted()|. Returns true on
-// success.
-template <class T>
-bool ReadToVectorAndDelete(std::vector<T>* values, size_t count,
- FILE* fp, MD5Context* context,
- const base::hash_set<int32>& del_set) {
- const size_t original_size = values->size();
- if (!ReadToVector(values, count, fp, context))
- return false;
-
- RemoveDeleted(values, original_size, del_set);
- return true;
-}
-
// Read an array of |count| integers and add them to |values|.
// Returns true on success.
bool ReadToChunkSet(std::set<int32>* values, size_t count,
@@ -178,6 +146,29 @@ void DeleteChunksFromSet(const base::hash_set<int32>& deleted,
}
}
+// Sanity-check the header against the file's size to make sure our
+// vectors aren't gigantic. This doubles as a cheap way to detect
+// corruption without having to checksum the entire file.
+bool FileHeaderSanityCheck(const FilePath& filename,
+ const FileHeader& header) {
+ int64 size = 0;
+ if (!file_util::GetFileSize(filename, &size))
+ return false;
+
+ int64 expected_size = sizeof(FileHeader);
+ expected_size += header.add_chunk_count * sizeof(int32);
+ expected_size += header.sub_chunk_count * sizeof(int32);
+ expected_size += header.add_prefix_count * sizeof(SBAddPrefix);
+ expected_size += header.sub_prefix_count * sizeof(SBSubPrefix);
+ expected_size += header.add_hash_count * sizeof(SBAddFullHash);
+ expected_size += header.sub_hash_count * sizeof(SBSubFullHash);
+ expected_size += sizeof(MD5Digest);
+ if (size != expected_size)
+ return false;
+
+ return true;
+}
+
} // namespace
SafeBrowsingStoreFile::SafeBrowsingStoreFile()
@@ -229,6 +220,35 @@ void SafeBrowsingStoreFile::Init(const FilePath& filename,
corruption_callback_.reset(corruption_callback);
}
+bool SafeBrowsingStoreFile::BeginChunk() {
+ return ClearChunkBuffers();
+}
+
+bool SafeBrowsingStoreFile::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) {
+ add_prefixes_.push_back(SBAddPrefix(chunk_id, prefix));
+ return true;
+}
+
+bool SafeBrowsingStoreFile::WriteAddHash(int32 chunk_id,
+ base::Time receive_time,
+ SBFullHash full_hash) {
+ add_hashes_.push_back(SBAddFullHash(chunk_id, receive_time, full_hash));
+ return true;
+}
+
+bool SafeBrowsingStoreFile::WriteSubPrefix(int32 chunk_id,
+ int32 add_chunk_id,
+ SBPrefix prefix) {
+ sub_prefixes_.push_back(SBSubPrefix(chunk_id, add_chunk_id, prefix));
+ return true;
+}
+
+bool SafeBrowsingStoreFile::WriteSubHash(int32 chunk_id, int32 add_chunk_id,
+ SBFullHash full_hash) {
+ sub_hashes_.push_back(SBSubFullHash(chunk_id, add_chunk_id, full_hash));
+ return true;
+}
+
bool SafeBrowsingStoreFile::OnCorruptDatabase() {
if (corruption_callback_.get())
corruption_callback_->Run();
@@ -311,24 +331,9 @@ bool SafeBrowsingStoreFile::BeginUpdate() {
return true;
}
- // Check that the file size makes sense given the header. This is a
- // cheap way to protect against header corruption while deferring
- // the checksum calculation until the end of the update.
// TODO(shess): Under POSIX it is possible that this could size a
// file different from the file which was opened.
- int64 size = 0;
- if (!file_util::GetFileSize(filename_, &size))
- return OnCorruptDatabase();
-
- int64 expected_size = sizeof(FileHeader);
- expected_size += header.add_chunk_count * sizeof(int32);
- expected_size += header.sub_chunk_count * sizeof(int32);
- expected_size += header.add_prefix_count * sizeof(SBAddPrefix);
- expected_size += header.sub_prefix_count * sizeof(SBSubPrefix);
- expected_size += header.add_hash_count * sizeof(SBAddFullHash);
- expected_size += header.sub_hash_count * sizeof(SBSubFullHash);
- expected_size += sizeof(MD5Digest);
- if (size != expected_size)
+ if (!FileHeaderSanityCheck(filename_, header))
return OnCorruptDatabase();
// Pull in the chunks-seen data for purposes of implementing
@@ -422,6 +427,9 @@ bool SafeBrowsingStoreFile::DoUpdate(
if (header.magic != kFileMagic || header.version != kFileVersion)
return OnCorruptDatabase();
+ if (!FileHeaderSanityCheck(filename_, header))
+ return OnCorruptDatabase();
+
// Re-read the chunks-seen data to get to the later data in the
// file and calculate the checksum. No new elements should be
// added to the sets.
@@ -431,14 +439,14 @@ bool SafeBrowsingStoreFile::DoUpdate(
file_.get(), &context))
return OnCorruptDatabase();
- if (!ReadToVectorAndDelete(&add_prefixes, header.add_prefix_count,
- file_.get(), &context, add_del_cache_) ||
- !ReadToVectorAndDelete(&sub_prefixes, header.sub_prefix_count,
- file_.get(), &context, sub_del_cache_) ||
- !ReadToVectorAndDelete(&add_full_hashes, header.add_hash_count,
- file_.get(), &context, add_del_cache_) ||
- !ReadToVectorAndDelete(&sub_full_hashes, header.sub_hash_count,
- file_.get(), &context, sub_del_cache_))
+ if (!ReadToVector(&add_prefixes, header.add_prefix_count,
+ file_.get(), &context) ||
+ !ReadToVector(&sub_prefixes, header.sub_prefix_count,
+ file_.get(), &context) ||
+ !ReadToVector(&add_full_hashes, header.add_hash_count,
+ file_.get(), &context) ||
+ !ReadToVector(&sub_full_hashes, header.sub_hash_count,
+ file_.get(), &context))
return OnCorruptDatabase();
// Calculate the digest to this point.
@@ -461,13 +469,32 @@ bool SafeBrowsingStoreFile::DoUpdate(
if (!FileRewind(new_file_.get()))
return false;
+ // Get chunk file's size for validating counts.
+ int64 size = 0;
+ if (!file_util::GetFileSize(TemporaryFileForFilename(filename_), &size))
+ return OnCorruptDatabase();
+
// Append the accumulated chunks onto the vectors read from |file_|.
for (int i = 0; i < chunks_written_; ++i) {
ChunkHeader header;
+ int64 ofs = ftell(new_file_.get());
+ if (ofs == -1)
+ return false;
+
if (!ReadArray(&header, 1, new_file_.get(), NULL))
return false;
+ // As a safety measure, make sure that the header describes a sane
+ // chunk, given the remaining file size.
+ int64 expected_size = ofs + sizeof(ChunkHeader);
+ expected_size += header.add_prefix_count * sizeof(SBAddPrefix);
+ expected_size += header.sub_prefix_count * sizeof(SBSubPrefix);
+ expected_size += header.add_hash_count * sizeof(SBAddFullHash);
+ expected_size += header.sub_hash_count * sizeof(SBSubFullHash);
+ if (expected_size > size)
+ return false;
+
// TODO(shess): If the vectors were kept sorted, then this code
// could use std::inplace_merge() to merge everything together in
// sorted order. That might still be slower than just sorting at
@@ -475,27 +502,25 @@ bool SafeBrowsingStoreFile::DoUpdate(
// some sort of recursive binary merge might be in order (merge
// chunks pairwise, merge those chunks pairwise, and so on, then
// merge the result with the main list).
- if (!ReadToVectorAndDelete(&add_prefixes, header.add_prefix_count,
- new_file_.get(), NULL, add_del_cache_) ||
- !ReadToVectorAndDelete(&sub_prefixes, header.sub_prefix_count,
- new_file_.get(), NULL, sub_del_cache_) ||
- !ReadToVectorAndDelete(&add_full_hashes, header.add_hash_count,
- new_file_.get(), NULL, add_del_cache_) ||
- !ReadToVectorAndDelete(&sub_full_hashes, header.sub_hash_count,
- new_file_.get(), NULL, sub_del_cache_))
+ if (!ReadToVector(&add_prefixes, header.add_prefix_count,
+ new_file_.get(), NULL) ||
+ !ReadToVector(&sub_prefixes, header.sub_prefix_count,
+ new_file_.get(), NULL) ||
+ !ReadToVector(&add_full_hashes, header.add_hash_count,
+ new_file_.get(), NULL) ||
+ !ReadToVector(&sub_full_hashes, header.sub_hash_count,
+ new_file_.get(), NULL))
return false;
}
- // Append items from |pending_adds| which haven't been deleted.
- for (std::vector<SBAddFullHash>::const_iterator iter = pending_adds.begin();
- iter != pending_adds.end(); ++iter) {
- if (add_del_cache_.count(iter->chunk_id) == 0)
- add_full_hashes.push_back(*iter);
- }
+ // Append items from |pending_adds|.
+ add_full_hashes.insert(add_full_hashes.end(),
+ pending_adds.begin(), pending_adds.end());
- // Knock the subs from the adds.
+ // Knock the subs from the adds and process deleted chunks.
SBProcessSubs(&add_prefixes, &sub_prefixes,
- &add_full_hashes, &sub_full_hashes);
+ &add_full_hashes, &sub_full_hashes,
+ add_del_cache_, sub_del_cache_);
// We no longer need to track deleted chunks.
DeleteChunksFromSet(add_del_cache_, &add_chunks_cache_);
@@ -557,6 +582,10 @@ bool SafeBrowsingStoreFile::DoUpdate(
if (!file_util::Move(new_filename, filename_))
return false;
+ // Record counts before swapping to caller.
+ UMA_HISTOGRAM_COUNTS("SB2.AddPrefixes", add_prefixes.size());
+ UMA_HISTOGRAM_COUNTS("SB2.SubPrefixes", sub_prefixes.size());
+
// Pass the resulting data off to the caller.
add_prefixes_result->swap(add_prefixes);
add_full_hashes_result->swap(add_full_hashes);
@@ -587,3 +616,37 @@ bool SafeBrowsingStoreFile::CancelUpdate() {
old_store_.reset();
return Close();
}
+
+void SafeBrowsingStoreFile::SetAddChunk(int32 chunk_id) {
+ add_chunks_cache_.insert(chunk_id);
+}
+
+bool SafeBrowsingStoreFile::CheckAddChunk(int32 chunk_id) {
+ return add_chunks_cache_.count(chunk_id) > 0;
+}
+
+void SafeBrowsingStoreFile::GetAddChunks(std::vector<int32>* out) {
+ out->clear();
+ out->insert(out->end(), add_chunks_cache_.begin(), add_chunks_cache_.end());
+}
+
+void SafeBrowsingStoreFile::SetSubChunk(int32 chunk_id) {
+ sub_chunks_cache_.insert(chunk_id);
+}
+
+bool SafeBrowsingStoreFile::CheckSubChunk(int32 chunk_id) {
+ return sub_chunks_cache_.count(chunk_id) > 0;
+}
+
+void SafeBrowsingStoreFile::GetSubChunks(std::vector<int32>* out) {
+ out->clear();
+ out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end());
+}
+
+void SafeBrowsingStoreFile::DeleteAddChunk(int32 chunk_id) {
+ add_del_cache_.insert(chunk_id);
+}
+
+void SafeBrowsingStoreFile::DeleteSubChunk(int32 chunk_id) {
+ sub_del_cache_.insert(chunk_id);
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.h b/chrome/browser/safe_browsing/safe_browsing_store_file.h
index 3996442..3530e60 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_file.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store_file.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_FILE_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_FILE_H_
+#pragma once
#include <set>
#include <vector>
@@ -123,28 +124,14 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore {
// Delete any on-disk files, including the permanent storage.
virtual bool Delete();
- virtual bool BeginChunk() {
- return ClearChunkBuffers();
- }
- virtual bool WriteAddPrefix(int32 chunk_id, SBPrefix prefix) {
- add_prefixes_.push_back(SBAddPrefix(chunk_id, prefix));
- return true;
- }
+ virtual bool BeginChunk();
+ virtual bool WriteAddPrefix(int32 chunk_id, SBPrefix prefix);
virtual bool WriteAddHash(int32 chunk_id,
- base::Time receive_time, SBFullHash full_hash) {
- add_hashes_.push_back(SBAddFullHash(chunk_id, receive_time, full_hash));
- return true;
- }
+ base::Time receive_time, SBFullHash full_hash);
virtual bool WriteSubPrefix(int32 chunk_id,
- int32 add_chunk_id, SBPrefix prefix) {
- sub_prefixes_.push_back(SBSubPrefix(chunk_id, add_chunk_id, prefix));
- return true;
- }
+ int32 add_chunk_id, SBPrefix prefix);
virtual bool WriteSubHash(int32 chunk_id, int32 add_chunk_id,
- SBFullHash full_hash) {
- sub_hashes_.push_back(SBSubFullHash(chunk_id, add_chunk_id, full_hash));
- return true;
- }
+ SBFullHash full_hash);
virtual bool FinishChunk();
virtual bool BeginUpdate();
@@ -156,33 +143,15 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore {
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 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) {
- add_del_cache_.insert(chunk_id);
- }
- virtual void DeleteSubChunk(int32 chunk_id) {
- sub_del_cache_.insert(chunk_id);
- }
+ virtual void DeleteAddChunk(int32 chunk_id);
+ virtual void DeleteSubChunk(int32 chunk_id);
// Returns the name of the temporary file used to buffer data for
// |filename|. Exported for unit tests.
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc
index 0ac8ec4..486d6f2 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/file_util.h"
+#include "base/histogram.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/sqlite_compiled_statement.h"
@@ -52,11 +53,6 @@ SafeBrowsingStoreSqlite::~SafeBrowsingStoreSqlite() {
}
bool SafeBrowsingStoreSqlite::Delete() {
- // The database should not be open at this point. TODO(shess): It
- // can be open if corruption was detected while opening the
- // database. Ick.
- DCHECK(!db_);
-
// The file must be closed, both so that the journal file is deleted
// by SQLite, and because open files cannot be deleted on Windows.
if (!Close()) {
@@ -95,8 +91,12 @@ bool SafeBrowsingStoreSqlite::OnCorruptDatabase() {
}
bool SafeBrowsingStoreSqlite::Open() {
- if (db_)
+ // This case should never happen, but if it does we shouldn't leak
+ // handles.
+ if (db_) {
+ NOTREACHED() << " Database was already open in Open().";
return true;
+ }
if (sqlite_utils::OpenSqliteDb(filename_, &db_) != SQLITE_OK) {
sqlite3_close(db_);
@@ -350,9 +350,6 @@ bool SafeBrowsingStoreSqlite::ReadAddPrefixes(
int rv;
while ((rv = statement->step()) == SQLITE_ROW) {
const int32 chunk_id = statement->column_int(0);
- if (add_del_cache_.count(chunk_id) > 0)
- continue;
-
const SBPrefix prefix = statement->column_int(1);
add_prefixes->push_back(SBAddPrefix(chunk_id, prefix));
}
@@ -402,9 +399,6 @@ bool SafeBrowsingStoreSqlite::ReadSubPrefixes(
int rv;
while ((rv = statement->step()) == SQLITE_ROW) {
const int32 chunk_id = statement->column_int(0);
- if (sub_del_cache_.count(chunk_id) > 0)
- continue;
-
const int32 add_chunk_id = statement->column_int(1);
const SBPrefix add_prefix = statement->column_int(2);
sub_prefixes->push_back(SBSubPrefix(chunk_id, add_chunk_id, add_prefix));
@@ -456,9 +450,6 @@ bool SafeBrowsingStoreSqlite::ReadAddHashes(
int rv;
while ((rv = statement->step()) == SQLITE_ROW) {
const int32 chunk_id = statement->column_int(0);
- if (add_del_cache_.count(chunk_id) > 0)
- continue;
-
// NOTE: Legacy format duplicated |hash.prefix| in column 1.
const SBPrefix prefix = statement->column_int(1);
const int32 received = statement->column_int(2);
@@ -517,9 +508,6 @@ bool SafeBrowsingStoreSqlite::ReadSubHashes(
int rv;
while ((rv = statement->step()) == SQLITE_ROW) {
const int32 chunk_id = statement->column_int(0);
- if (sub_del_cache_.count(chunk_id) > 0)
- continue;
-
// NOTE: Legacy format duplicated |hash.prefix| in column 2.
const int32 add_chunk_id = statement->column_int(1);
const SBPrefix add_prefix = statement->column_int(2);
@@ -563,29 +551,15 @@ bool SafeBrowsingStoreSqlite::WriteSubHashes(
return true;
}
-bool SafeBrowsingStoreSqlite::RenameTables() {
+bool SafeBrowsingStoreSqlite::ResetTables() {
DCHECK(db_);
- if (!ExecSql("ALTER TABLE add_prefix RENAME TO add_prefix_old") ||
- !ExecSql("ALTER TABLE sub_prefix RENAME TO sub_prefix_old") ||
- !ExecSql("ALTER TABLE add_full_hash RENAME TO add_full_hash_old") ||
- !ExecSql("ALTER TABLE sub_full_hash RENAME TO sub_full_hash_old") ||
- !ExecSql("ALTER TABLE add_chunks RENAME TO add_chunks_old") ||
- !ExecSql("ALTER TABLE sub_chunks RENAME TO sub_chunks_old"))
- return false;
-
- return CreateTables();
-}
-
-bool SafeBrowsingStoreSqlite::DeleteOldTables() {
- DCHECK(db_);
-
- if (!ExecSql("DROP TABLE add_prefix_old") ||
- !ExecSql("DROP TABLE sub_prefix_old") ||
- !ExecSql("DROP TABLE add_full_hash_old") ||
- !ExecSql("DROP TABLE sub_full_hash_old") ||
- !ExecSql("DROP TABLE add_chunks_old") ||
- !ExecSql("DROP TABLE sub_chunks_old"))
+ if (!ExecSql("DELETE FROM add_prefix") ||
+ !ExecSql("DELETE FROM sub_prefix") ||
+ !ExecSql("DELETE FROM add_full_hash") ||
+ !ExecSql("DELETE FROM sub_full_hash") ||
+ !ExecSql("DELETE FROM add_chunks") ||
+ !ExecSql("DELETE FROM sub_chunks"))
return false;
return true;
@@ -627,23 +601,22 @@ bool SafeBrowsingStoreSqlite::DoUpdate(
!ReadSubHashes(&sub_full_hashes))
return false;
- // Add the pending adds which haven't since been deleted.
- for (std::vector<SBAddFullHash>::const_iterator iter = pending_adds.begin();
- iter != pending_adds.end(); ++iter) {
- if (add_del_cache_.count(iter->chunk_id) == 0)
- add_full_hashes.push_back(*iter);
- }
+ // Append items from |pending_adds|.
+ add_full_hashes.insert(add_full_hashes.end(),
+ pending_adds.begin(), pending_adds.end());
+ // Knock the subs from the adds and process deleted chunks.
SBProcessSubs(&add_prefixes, &sub_prefixes,
- &add_full_hashes, &sub_full_hashes);
-
- // Move the existing tables aside and prepare to write fresh tables.
- if (!RenameTables())
- return false;
+ &add_full_hashes, &sub_full_hashes,
+ add_del_cache_, sub_del_cache_);
DeleteChunksFromSet(add_del_cache_, &add_chunks_cache_);
DeleteChunksFromSet(sub_del_cache_, &sub_chunks_cache_);
+ // Clear the existing tables before rewriting them.
+ if (!ResetTables())
+ return false;
+
if (!WriteAddChunks() ||
!WriteSubChunks() ||
!WriteAddPrefixes(add_prefixes) ||
@@ -652,18 +625,18 @@ bool SafeBrowsingStoreSqlite::DoUpdate(
!WriteSubHashes(sub_full_hashes))
return false;
- // Delete the old tables.
- if (!DeleteOldTables())
- return false;
-
// Commit all the changes to the database.
int rv = insert_transaction_->Commit();
if (rv != SQLITE_OK) {
NOTREACHED() << "SafeBrowsing update transaction failed to commit.";
- // UMA_HISTOGRAM_COUNTS("SB2.FailedUpdate", 1);
+ UMA_HISTOGRAM_COUNTS("SB2.FailedUpdate", 1);
return false;
}
+ // Record counts before swapping to caller.
+ UMA_HISTOGRAM_COUNTS("SB2.AddPrefixes", add_prefixes.size());
+ UMA_HISTOGRAM_COUNTS("SB2.SubPrefixes", sub_prefixes.size());
+
add_prefixes_result->swap(add_prefixes);
add_full_hashes_result->swap(add_full_hashes);
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h
index e72073b..6f684c1 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h
@@ -4,16 +4,18 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_SQLITE_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_SQLITE_H_
+#pragma once
#include <set>
#include <vector>
#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/safe_browsing/safe_browsing_store.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
struct sqlite3;
-class SqliteCompiledStatement;
class SqliteStatementCache;
class SQLTransaction;
@@ -125,8 +127,9 @@ class SafeBrowsingStoreSqlite : public SafeBrowsingStore {
bool CheckCompatibleVersion();
bool CreateTables();
- bool RenameTables();
- bool DeleteOldTables();
+
+ // Clear the old safe-browsing data from the tables.
+ bool ResetTables();
// Read and write the chunks-seen data from |*_chunks_cache_|.
// Chunk deletions are not accounted for.
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_store_unittest.cc
index 76f0e91..4284625 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_unittest.cc
@@ -109,20 +109,25 @@ TEST(SafeBrowsingStoreTest, SBSubFullHashLess) {
SBSubFullHash(9, 10, one)));
}
-TEST(SafeBrowsingStoreTest, SBProcessSubs) {
+// SBProcessSubs does a lot of iteration, run through empty just to
+// make sure degenerate cases work.
+TEST(SafeBrowsingStoreTest, SBProcessSubsEmpty) {
std::vector<SBAddPrefix> add_prefixes;
std::vector<SBAddFullHash> add_hashes;
std::vector<SBSubPrefix> sub_prefixes;
std::vector<SBSubFullHash> sub_hashes;
- // SBProcessSubs does a lot of iteration, run through empty just to
- // make sure degenerate cases work.
- SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes);
+ const base::hash_set<int32> no_deletions;
+ SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
+ no_deletions, no_deletions);
EXPECT_TRUE(add_prefixes.empty());
EXPECT_TRUE(sub_prefixes.empty());
EXPECT_TRUE(add_hashes.empty());
EXPECT_TRUE(sub_hashes.empty());
+}
+// Test that subs knock out adds.
+TEST(SafeBrowsingStoreTest, SBProcessSubsKnockout) {
const base::Time kNow = base::Time::Now();
const SBFullHash kHash1(SBFullHashFromString("one"));
const SBFullHash kHash2(SBFullHashFromString("two"));
@@ -138,6 +143,11 @@ TEST(SafeBrowsingStoreTest, SBProcessSubs) {
SBFullHash kHash1mod3 = kHash1mod2;
kHash1mod3.full_hash[sizeof(kHash1mod3.full_hash) - 1] ++;
+ std::vector<SBAddPrefix> add_prefixes;
+ std::vector<SBAddFullHash> add_hashes;
+ std::vector<SBSubPrefix> sub_prefixes;
+ std::vector<SBSubFullHash> sub_hashes;
+
// An add with prefix and a couple hashes, plus a sub for the prefix
// and a couple sub hashes. The sub should knock all of them out.
add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash1.prefix));
@@ -155,7 +165,9 @@ TEST(SafeBrowsingStoreTest, SBProcessSubs) {
sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash3));
sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash3.prefix));
- SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes);
+ const base::hash_set<int32> no_deletions;
+ SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
+ no_deletions, no_deletions);
EXPECT_EQ(1U, add_prefixes.size());
EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
@@ -176,6 +188,76 @@ TEST(SafeBrowsingStoreTest, SBProcessSubs) {
EXPECT_TRUE(SBFullHashEq(kHash3, sub_hashes[0].full_hash));
}
+// Test chunk deletions, and ordering of deletions WRT subs knocking
+// out adds.
+TEST(SafeBrowsingStoreTest, SBProcessSubsDeleteChunk) {
+ const base::Time kNow = base::Time::Now();
+ const SBFullHash kHash1(SBFullHashFromString("one"));
+ const SBFullHash kHash2(SBFullHashFromString("two"));
+ const SBFullHash kHash3(SBFullHashFromString("three"));
+ const int kAddChunk1 = 1; // Use different chunk numbers just in case.
+ const int kSubChunk1 = 2;
+
+ // Construct some full hashes which share prefix with another.
+ SBFullHash kHash1mod1 = kHash1;
+ kHash1mod1.full_hash[sizeof(kHash1mod1.full_hash) - 1] ++;
+ SBFullHash kHash1mod2 = kHash1mod1;
+ kHash1mod2.full_hash[sizeof(kHash1mod2.full_hash) - 1] ++;
+ SBFullHash kHash1mod3 = kHash1mod2;
+ kHash1mod3.full_hash[sizeof(kHash1mod3.full_hash) - 1] ++;
+
+ std::vector<SBAddPrefix> add_prefixes;
+ std::vector<SBAddFullHash> add_hashes;
+ std::vector<SBSubPrefix> sub_prefixes;
+ std::vector<SBSubFullHash> sub_hashes;
+
+ // An add with prefix and a couple hashes, plus a sub for the prefix
+ // and a couple sub hashes. The sub should knock all of them out.
+ add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash1.prefix));
+ add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1));
+ add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash1mod1));
+ sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash1.prefix));
+ sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod2));
+ sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash1mod3));
+
+ // An add with no corresponding sub. Both items should be retained.
+ add_hashes.push_back(SBAddFullHash(kAddChunk1, kNow, kHash2));
+ add_prefixes.push_back(SBAddPrefix(kAddChunk1, kHash2.prefix));
+
+ // A sub with no corresponding add. Both items should be retained.
+ sub_hashes.push_back(SBSubFullHash(kSubChunk1, kAddChunk1, kHash3));
+ sub_prefixes.push_back(SBSubPrefix(kSubChunk1, kAddChunk1, kHash3.prefix));
+
+ const base::hash_set<int32> no_deletions;
+ base::hash_set<int32> add_deletions;
+ add_deletions.insert(kAddChunk1);
+ SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
+ add_deletions, no_deletions);
+
+ EXPECT_TRUE(add_prefixes.empty());
+ EXPECT_TRUE(add_hashes.empty());
+
+ EXPECT_EQ(1U, sub_prefixes.size());
+ EXPECT_EQ(kSubChunk1, sub_prefixes[0].chunk_id);
+ EXPECT_EQ(kAddChunk1, sub_prefixes[0].add_chunk_id);
+ EXPECT_EQ(kHash3.prefix, sub_prefixes[0].add_prefix);
+
+ EXPECT_EQ(1U, sub_hashes.size());
+ EXPECT_EQ(kSubChunk1, sub_hashes[0].chunk_id);
+ EXPECT_EQ(kAddChunk1, sub_hashes[0].add_chunk_id);
+ EXPECT_TRUE(SBFullHashEq(kHash3, sub_hashes[0].full_hash));
+
+ base::hash_set<int32> sub_deletions;
+ sub_deletions.insert(kSubChunk1);
+ SBProcessSubs(&add_prefixes, &sub_prefixes, &add_hashes, &sub_hashes,
+ no_deletions, sub_deletions);
+
+ EXPECT_TRUE(add_prefixes.empty());
+ EXPECT_TRUE(add_hashes.empty());
+ EXPECT_TRUE(sub_prefixes.empty());
+ EXPECT_TRUE(sub_hashes.empty());
+}
+
TEST(SafeBrowsingStoreTest, Y2K38) {
const base::Time now = base::Time::Now();
const base::Time future = now + base::TimeDelta::FromDays(3*365);
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h b/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h
index ea61b8f..5fa8ece 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_UNITTEST_HELPER_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_UNITTEST_HELPER_H_
+#pragma once
#include "chrome/browser/safe_browsing/safe_browsing_store.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_util.cc b/chrome/browser/safe_browsing/safe_browsing_util.cc
index 80c3d3a..d81260f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_util.cc
@@ -8,7 +8,7 @@
#include "base/hmac.h"
#include "base/sha2.h"
#include "base/string_util.h"
-#include "chrome/browser/google_util.h"
+#include "chrome/browser/google/google_util.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_util.h"
#include "net/base/escape.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_util.h b/chrome/browser/safe_browsing/safe_browsing_util.h
index ea95a33..b382608 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util.h
+++ b/chrome/browser/safe_browsing/safe_browsing_util.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UTIL_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UTIL_H_
+#pragma once
#include <cstring>
#include <deque>
@@ -13,7 +14,6 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/safe_browsing/chunk_range.h"
class GURL;
diff --git a/chrome/browser/sanity_uitest.cc b/chrome/browser/sanity_uitest.cc
index c2fe48c..36bc372 100644
--- a/chrome/browser/sanity_uitest.cc
+++ b/chrome/browser/sanity_uitest.cc
@@ -11,14 +11,14 @@
#include "base/file_path.h"
#include "base/platform_thread.h"
#include "chrome/common/chrome_switches.h"
+#include "net/base/net_util.h"
class GoogleTest : public UITest {
protected:
GoogleTest() : UITest() {
- FilePath test_file(test_data_directory_);
- test_file = test_file.AppendASCII("google");
- test_file = test_file.AppendASCII("google.html");
- homepage_ = test_file.ToWStringHack();
+ FilePath test_file =
+ test_data_directory_.AppendASCII("google").AppendASCII("google.html");
+ homepage_ = GURL(net::FilePathToFileURL(test_file)).spec();
}
};
@@ -34,9 +34,8 @@ TEST_F(GoogleTest, Crash) {
class ColumnLayout : public UITest {
protected:
ColumnLayout() : UITest() {
- FilePath test_file(test_data_directory_);
- test_file = test_file.AppendASCII("columns.html");
- homepage_ = test_file.ToWStringHack();
+ FilePath test_file = test_data_directory_.AppendASCII("columns.html");
+ homepage_ = GURL(net::FilePathToFileURL(test_file)).spec();
}
};
@@ -49,22 +48,23 @@ TEST_F(ColumnLayout, Crash) {
// UITest will check if this crashed.
}
-// By passing kTryChromeAgain with a magic value > 10000 we cause chrome
-// to exit fairly early. This was the cause of crashes. See bug 34799.
+// By passing kTryChromeAgain with a magic value > 10000 we cause Chrome
+// to exit fairly early.
+// Quickly exiting Chrome (regardless of this particular flag -- it
+// doesn't do anything other than cause Chrome to quit on startup on
+// non-Windows) was a cause of crashes (see bug 34799 for example) so
+// this is a useful test of the startup/quick-shutdown cycle.
class EarlyReturnTest : public UITest {
public:
EarlyReturnTest() {
- wait_for_initial_loads_ = false;
- // We don't depend on these timeouts, they are set to the minimum so
- // the automation server waits the minimun amount possible for the
- // handshake that will never come.
- set_command_execution_timeout_ms(1);
- set_action_timeout_ms(1);
- launch_arguments_.AppendSwitchWithValue(switches::kTryChromeAgain, "10001");
+ wait_for_initial_loads_ = false; // Don't wait for any pages to load.
+ launch_arguments_.AppendSwitchASCII(switches::kTryChromeAgain, "10001");
}
};
-// Flaky: http://crbug.com/45115
-TEST_F(EarlyReturnTest, FLAKY_ToastCrasher) {
+// Disabled: http://crbug.com/45115
+// Due to limitations in our test infrastructure, this test currently doesn't
+// work.
+TEST_F(EarlyReturnTest, DISABLED_ToastCrasher) {
// UITest will check if this crashed.
}
diff --git a/chrome/browser/search_engines/edit_search_engine_controller.cc b/chrome/browser/search_engines/edit_search_engine_controller.cc
index d64ec89..6c3120c 100644
--- a/chrome/browser/search_engines/edit_search_engine_controller.cc
+++ b/chrome/browser/search_engines/edit_search_engine_controller.cc
@@ -24,7 +24,7 @@ EditSearchEngineController::EditSearchEngineController(
}
bool EditSearchEngineController::IsTitleValid(
- const std::wstring& title_input) const {
+ const string16& title_input) const {
return !CollapseWhitespace(title_input, true).empty();
}
@@ -56,25 +56,26 @@ bool EditSearchEngineController::IsURLValid(
}
bool EditSearchEngineController::IsKeywordValid(
- const std::wstring& keyword_input) const {
- std::wstring keyword_input_trimmed(CollapseWhitespace(keyword_input, true));
+ const string16& keyword_input) const {
+ string16 keyword_input_trimmed(CollapseWhitespace(keyword_input, true));
if (keyword_input_trimmed.empty())
return false; // Do not allow empty keyword.
const TemplateURL* turl_with_keyword =
profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(
- keyword_input_trimmed);
+ UTF16ToWideHack(keyword_input_trimmed));
return (turl_with_keyword == NULL || turl_with_keyword == template_url_);
}
void EditSearchEngineController::AcceptAddOrEdit(
- const std::wstring& title_input,
- const std::wstring& keyword_input,
+ const string16& title_input,
+ const string16& keyword_input,
const std::string& url_input) {
std::string url_string = GetFixedUpURL(url_input);
DCHECK(!url_string.empty());
const TemplateURL* existing =
- profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_input);
+ profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(
+ UTF16ToWideHack(keyword_input));
if (existing &&
(!edit_keyword_delegate_ || existing != template_url_)) {
// An entry may have been added with the same keyword string while the
@@ -95,8 +96,8 @@ void EditSearchEngineController::AcceptAddOrEdit(
// does in a similar situation (updating an existing TemplateURL with
// data from a new one).
TemplateURL* modifiable_url = const_cast<TemplateURL*>(template_url_);
- modifiable_url->set_short_name(title_input);
- modifiable_url->set_keyword(keyword_input);
+ modifiable_url->set_short_name(UTF16ToWideHack(title_input));
+ modifiable_url->set_keyword(UTF16ToWideHack(keyword_input));
modifiable_url->SetURL(url_string, 0, 0);
// TemplateURLModel takes ownership of template_url_.
profile_->GetTemplateURLModel()->Add(modifiable_url);
diff --git a/chrome/browser/search_engines/edit_search_engine_controller.h b/chrome/browser/search_engines/edit_search_engine_controller.h
index 0ceb1d3..e2edee6 100644
--- a/chrome/browser/search_engines/edit_search_engine_controller.h
+++ b/chrome/browser/search_engines/edit_search_engine_controller.h
@@ -4,9 +4,11 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_EDIT_SEARCH_ENGINE_CONTROLLER_H_
#define CHROME_BROWSER_SEARCH_ENGINES_EDIT_SEARCH_ENGINE_CONTROLLER_H_
+#pragma once
#include <string>
+#include "base/string16.h"
#include "gfx/native_widget_types.h"
class Profile;
@@ -20,9 +22,12 @@ class EditSearchEngineControllerDelegate {
// indicates a new TemplateURL should be created rather than modifying an
// existing TemplateURL.
virtual void OnEditedKeyword(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url) = 0;
+
+ protected:
+ virtual ~EditSearchEngineControllerDelegate() {}
};
// EditSearchEngineController provides the core platform independent logic
@@ -37,7 +42,7 @@ class EditSearchEngineController {
~EditSearchEngineController() {}
// Returns true if the value of |title_input| is a valid search engine name.
- bool IsTitleValid(const std::wstring& title_input) const;
+ bool IsTitleValid(const string16& title_input) const;
// Returns true if the value of |url_input| represents a valid search engine
// URL. The URL is valid if it contains no search terms and is a valid
@@ -48,11 +53,11 @@ class EditSearchEngineController {
// Returns true if the value of |keyword_input| represents a valid keyword.
// The keyword is valid if it is non-empty and does not conflict with an
// existing entry. NOTE: this is just the keyword, not the title and url.
- bool IsKeywordValid(const std::wstring& keyword_input) const;
+ bool IsKeywordValid(const string16& keyword_input) const;
// Completes the add or edit of a search engine.
- void AcceptAddOrEdit(const std::wstring& title_input,
- const std::wstring& keyword_input,
+ void AcceptAddOrEdit(const string16& title_input,
+ const string16& keyword_input,
const std::string& url_input);
// Deletes an unused TemplateURL, if its add was cancelled and it's not
diff --git a/chrome/browser/search_engines/keyword_editor_controller.cc b/chrome/browser/search_engines/keyword_editor_controller.cc
index d4f9848..f40fdca 100644
--- a/chrome/browser/search_engines/keyword_editor_controller.cc
+++ b/chrome/browser/search_engines/keyword_editor_controller.cc
@@ -6,7 +6,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
@@ -28,8 +28,8 @@ void KeywordEditorController::RegisterPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(prefs::kKeywordEditorWindowPlacement);
}
-int KeywordEditorController::AddTemplateURL(const std::wstring& title,
- const std::wstring& keyword,
+int KeywordEditorController::AddTemplateURL(const string16& title,
+ const string16& keyword,
const std::string& url) {
DCHECK(!url.empty());
@@ -37,8 +37,8 @@ int KeywordEditorController::AddTemplateURL(const std::wstring& title,
profile_);
TemplateURL* template_url = new TemplateURL();
- template_url->set_short_name(title);
- template_url->set_keyword(keyword);
+ template_url->set_short_name(UTF16ToWideHack(title));
+ template_url->set_keyword(UTF16ToWideHack(keyword));
template_url->SetURL(url, 0, 0);
// There's a bug (1090726) in TableView with groups enabled such that newly
@@ -53,8 +53,8 @@ int KeywordEditorController::AddTemplateURL(const std::wstring& title,
}
void KeywordEditorController::ModifyTemplateURL(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url) {
const int index = table_model_->IndexOfTemplateURL(template_url);
if (index == -1) {
@@ -64,8 +64,8 @@ void KeywordEditorController::ModifyTemplateURL(const TemplateURL* template_url,
}
// Don't do anything if the entry didn't change.
- if (template_url->short_name() == title &&
- template_url->keyword() == keyword &&
+ if (template_url->short_name() == UTF16ToWideHack(title) &&
+ template_url->keyword() == UTF16ToWideHack(keyword) &&
((url.empty() && !template_url->url()) ||
(!url.empty() && template_url->url() &&
template_url->url()->url() == url))) {
@@ -78,10 +78,16 @@ void KeywordEditorController::ModifyTemplateURL(const TemplateURL* template_url,
profile_);
}
+bool KeywordEditorController::CanEdit(const TemplateURL* url) const {
+ return !url_model()->IsDefaultSearchManaged() ||
+ url != url_model()->GetDefaultSearchProvider();
+}
+
bool KeywordEditorController::CanMakeDefault(const TemplateURL* url) const {
return (url != url_model()->GetDefaultSearchProvider() &&
url->url() &&
- url->url()->SupportsReplacement());
+ url->url()->SupportsReplacement() &&
+ !url_model()->IsDefaultSearchManaged());
}
bool KeywordEditorController::CanRemove(const TemplateURL* url) const {
diff --git a/chrome/browser/search_engines/keyword_editor_controller.h b/chrome/browser/search_engines/keyword_editor_controller.h
index c358d6e..a1642e4 100644
--- a/chrome/browser/search_engines/keyword_editor_controller.h
+++ b/chrome/browser/search_engines/keyword_editor_controller.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_KEYWORD_EDITOR_CONTROLLER_H_
#define CHROME_BROWSER_SEARCH_ENGINES_KEYWORD_EDITOR_CONTROLLER_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
class PrefService;
class Profile;
@@ -26,17 +28,20 @@ class KeywordEditorController {
// Invoked when the user succesfully fills out the add keyword dialog.
// Propagates the change to the TemplateURLModel and updates the table model.
// Returns the index of the added URL.
- int AddTemplateURL(const std::wstring& title,
- const std::wstring& keyword,
+ int AddTemplateURL(const string16& title,
+ const string16& keyword,
const std::string& url);
// Invoked when the user modifies a TemplateURL. Updates the TemplateURLModel
// and table model appropriately.
void ModifyTemplateURL(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url);
+ // Return true if the given |url| can be edited.
+ bool CanEdit(const TemplateURL* url) const;
+
// Return true if the given |url| can be made the default.
bool CanMakeDefault(const TemplateURL* url) const;
diff --git a/chrome/browser/search_engines/keyword_editor_controller_unittest.cc b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
index 499f5aa..ca817ec 100644
--- a/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
+++ b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
@@ -1,32 +1,35 @@
-// 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.
#include "app/table_model_observer.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/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/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
+static const string16 kA(ASCIIToUTF16("a"));
+static const string16 kA1(ASCIIToUTF16("a1"));
+static const string16 kB(ASCIIToUTF16("b"));
+static const string16 kB1(ASCIIToUTF16("b1"));
+
// Base class for keyword editor tests. Creates a profile containing an
// empty TemplateURLModel.
class KeywordEditorControllerTest : public testing::Test,
public TableModelObserver {
public:
- virtual void SetUp() {
- model_changed_count_ = items_changed_count_ = added_count_ =
- removed_count_ = 0;
-
- profile_.reset(new TestingProfile());
- profile_->CreateTemplateURLModel();
+ // Initializes all of the state.
+ void Init(bool simulate_load_failure);
- model_ = profile_->GetTemplateURLModel();
-
- controller_.reset(new KeywordEditorController(profile_.get()));
- controller_->table_model()->SetObserver(this);
+ virtual void SetUp() {
+ Init(false);
}
virtual void OnModelChanged() {
@@ -59,6 +62,14 @@ class KeywordEditorControllerTest : public testing::Test,
removed_count_ = 0;
}
+ void SimulateDefaultSearchIsManaged(const TemplateURL* turl) {
+ ASSERT_TRUE(turl->url() != NULL);
+ model_->SetDefaultSearchProvider(turl);
+ TestingPrefService* service = profile_->GetTestingPrefService();
+ service->SetManagedPref(prefs::kDefaultSearchProviderSearchURL,
+ Value::CreateStringValue(turl->url()->url()));
+ }
+
TemplateURLTableModel* table_model() const {
return controller_->table_model();
}
@@ -75,9 +86,26 @@ class KeywordEditorControllerTest : public testing::Test,
int removed_count_;
};
+void KeywordEditorControllerTest::Init(bool simulate_load_failure) {
+ ClearChangeCount();
+
+ // If init is called twice, make sure that the controller is destroyed before
+ // the profile is.
+ controller_.reset();
+ profile_.reset(new TestingProfile());
+ profile_->CreateTemplateURLModel();
+
+ model_ = profile_->GetTemplateURLModel();
+ if (simulate_load_failure)
+ model_->OnWebDataServiceRequestDone(NULL, NULL);
+
+ controller_.reset(new KeywordEditorController(profile_.get()));
+ controller_->table_model()->SetObserver(this);
+}
+
// Tests adding a TemplateURL.
TEST_F(KeywordEditorControllerTest, Add) {
- controller_->AddTemplateURL(L"a", L"b", "http://c");
+ controller_->AddTemplateURL(kA, kB, "http://c");
// Verify the observer was notified.
VerifyChangeCount(0, 0, 1, 0);
@@ -94,39 +122,100 @@ TEST_F(KeywordEditorControllerTest, Add) {
const TemplateURL* turl = model_->GetTemplateURLs()[0];
EXPECT_EQ(L"a", turl->short_name());
EXPECT_EQ(L"b", turl->keyword());
- EXPECT_TRUE(turl->url() != NULL);
- EXPECT_TRUE(turl->url()->url() == "http://c");
+ ASSERT_TRUE(turl->url() != NULL);
+ EXPECT_EQ("http://c", turl->url()->url());
}
// Tests modifying a TemplateURL.
TEST_F(KeywordEditorControllerTest, Modify) {
- controller_->AddTemplateURL(L"a", L"b", "http://c");
+ controller_->AddTemplateURL(kA, kB, "http://c");
ClearChangeCount();
// Modify the entry.
const TemplateURL* turl = model_->GetTemplateURLs()[0];
- controller_->ModifyTemplateURL(turl, L"a1", L"b1", "http://c1");
+ controller_->ModifyTemplateURL(turl, kA1, kB1, "http://c1");
// Make sure it was updated appropriately.
VerifyChangeCount(0, 1, 0, 0);
EXPECT_EQ(L"a1", turl->short_name());
EXPECT_EQ(L"b1", turl->keyword());
- EXPECT_TRUE(turl->url() != NULL);
- EXPECT_TRUE(turl->url()->url() == "http://c1");
+ ASSERT_TRUE(turl->url() != NULL);
+ EXPECT_EQ("http://c1", turl->url()->url());
}
// Tests making a TemplateURL the default search provider.
TEST_F(KeywordEditorControllerTest, MakeDefault) {
- controller_->AddTemplateURL(L"a", L"b", "http://c{searchTerms}");
+ controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}");
ClearChangeCount();
const TemplateURL* turl = model_->GetTemplateURLs()[0];
- controller_->MakeDefaultTemplateURL(0);
+ int new_default = controller_->MakeDefaultTemplateURL(0);
+ EXPECT_EQ(0, new_default);
// Making an item the default sends a handful of changes. Which are sent isn't
// important, what is important is 'something' is sent.
ASSERT_TRUE(items_changed_count_ > 0 || added_count_ > 0 ||
removed_count_ > 0);
ASSERT_TRUE(model_->GetDefaultSearchProvider() == turl);
+
+ // Making it default a second time should fail.
+ new_default = controller_->MakeDefaultTemplateURL(0);
+ EXPECT_EQ(-1, new_default);
+}
+
+// Tests that a TemplateURL can't be made the default if the default search
+// provider is managed via policy.
+TEST_F(KeywordEditorControllerTest, CannotSetDefaultWhileManaged) {
+ controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}");
+ controller_->AddTemplateURL(kA1, kB1, "http://d{searchTerms}");
+ ClearChangeCount();
+
+ const TemplateURL* turl1 = model_->GetTemplateURLForKeyword(L"b");
+ ASSERT_TRUE(turl1 != NULL);
+ const TemplateURL* turl2 = model_->GetTemplateURLForKeyword(L"b1");
+ ASSERT_TRUE(turl2 != NULL);
+
+ EXPECT_TRUE(controller_->CanMakeDefault(turl1));
+ EXPECT_TRUE(controller_->CanMakeDefault(turl2));
+
+ SimulateDefaultSearchIsManaged(turl2);
+ EXPECT_TRUE(model_->IsDefaultSearchManaged());
+
+ EXPECT_FALSE(controller_->CanMakeDefault(turl1));
+ EXPECT_FALSE(controller_->CanMakeDefault(turl2));
+}
+
+// Tests that a TemplateURL can't be edited if it is the managed default search
+// provider.
+TEST_F(KeywordEditorControllerTest, EditManagedDefault) {
+ controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}");
+ controller_->AddTemplateURL(kA1, kB1, "http://d{searchTerms}");
+ ClearChangeCount();
+
+ const TemplateURL* turl1 = model_->GetTemplateURLForKeyword(L"b");
+ ASSERT_TRUE(turl1 != NULL);
+ const TemplateURL* turl2 = model_->GetTemplateURLForKeyword(L"b1");
+ ASSERT_TRUE(turl2 != NULL);
+
+ EXPECT_TRUE(controller_->CanEdit(turl1));
+ EXPECT_TRUE(controller_->CanEdit(turl2));
+
+ SimulateDefaultSearchIsManaged(turl2);
+ EXPECT_TRUE(model_->IsDefaultSearchManaged());
+
+ EXPECT_TRUE(controller_->CanEdit(turl1));
+ EXPECT_FALSE(controller_->CanEdit(turl2));
+}
+
+TEST_F(KeywordEditorControllerTest, MakeDefaultNoWebData) {
+ // Simulate a failure to load Web Data.
+ Init(true);
+
+ controller_->AddTemplateURL(kA, kB, "http://c{searchTerms}");
+ ClearChangeCount();
+
+ // This should not result in a crash.
+ int new_default = controller_->MakeDefaultTemplateURL(0);
+ EXPECT_EQ(0, new_default);
}
// Mutates the TemplateURLModel and make sure table model is updating
diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc
index beed6d3..015a2f3 100644
--- a/chrome/browser/search_engines/template_url.cc
+++ b/chrome/browser/search_engines/template_url.cc
@@ -8,18 +8,14 @@
#include "base/i18n/icu_string_conversions.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/google_url_tracker.h"
+#include "chrome/browser/search_engines/search_terms_data.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/url_constants.h"
#include "gfx/favicon_size.h"
#include "net/base/escape.h"
-#if defined(OS_WIN)
-#include "chrome/browser/rlz/rlz.h"
-#endif
-
// The TemplateURLRef has any number of terms that need to be replaced. Each of
// the terms is enclosed in braces. If the character preceeding the final
// brace is a ?, it indicates the term is optional and can be replaced with
@@ -70,13 +66,21 @@ static const char kDefaultCount[] = "10";
// Used if the parameter kOutputEncodingParameter is required.
static const char kOutputEncodingType[] = "UTF-8";
-// static
-std::string* TemplateURLRef::google_base_url_ = NULL;
-
TemplateURLRef::TemplateURLRef() {
Set(std::string(), 0, 0);
}
+TemplateURLRef::TemplateURLRef(const std::string& url,
+ int index_offset,
+ int page_offset)
+ : url_(url),
+ index_offset_(index_offset),
+ page_offset_(page_offset),
+ parsed_(false),
+ valid_(false),
+ supports_replacements_(false) {
+}
+
void TemplateURLRef::Set(const std::string& url,
int index_offset,
int page_offset) {
@@ -86,6 +90,9 @@ void TemplateURLRef::Set(const std::string& url,
InvalidateCachedValues();
}
+TemplateURLRef::~TemplateURLRef() {
+}
+
bool TemplateURLRef::ParseParameter(size_t start,
size_t end,
std::string* url,
@@ -109,11 +116,11 @@ bool TemplateURLRef::ParseParameter(size_t start,
url->insert(start, kDefaultCount);
} else if (parameter == kStartIndexParameter) {
if (!optional) {
- url->insert(start, IntToString(index_offset_));
+ url->insert(start, base::IntToString(index_offset_));
}
} else if (parameter == kStartPageParameter) {
if (!optional) {
- url->insert(start, IntToString(page_offset_));
+ url->insert(start, base::IntToString(page_offset_));
}
} else if (parameter == kLanguageParameter) {
replacements->push_back(Replacement(LANGUAGE, start));
@@ -178,6 +185,12 @@ std::string TemplateURLRef::ParseURL(const std::string& url,
}
void TemplateURLRef::ParseIfNecessary() const {
+ UIThreadSearchTermsData search_terms_data;
+ ParseIfNecessaryUsingTermsData(search_terms_data);
+}
+
+void TemplateURLRef::ParseIfNecessaryUsingTermsData(
+ const SearchTermsData& search_terms_data) const {
if (!parsed_) {
parsed_ = true;
parsed_url_ = ParseURL(url_, &replacements_, &valid_);
@@ -199,19 +212,20 @@ void TemplateURLRef::ParseIfNecessary() const {
// Only parse the host/key if there is one search term. Technically there
// could be more than one term, but it's uncommon; so we punt.
if (has_only_one_search_term)
- ParseHostAndSearchTermKey();
+ ParseHostAndSearchTermKey(search_terms_data);
}
}
}
-void TemplateURLRef::ParseHostAndSearchTermKey() const {
+void TemplateURLRef::ParseHostAndSearchTermKey(
+ const SearchTermsData& search_terms_data) const {
std::string url_string = url_;
ReplaceSubstringsAfterOffset(&url_string, 0,
kGoogleBaseURLParameterFull,
- GoogleBaseURLValue());
+ search_terms_data.GoogleBaseURLValue());
ReplaceSubstringsAfterOffset(&url_string, 0,
kGoogleBaseSuggestURLParameterFull,
- GoogleBaseSuggestURLValue());
+ search_terms_data.GoogleBaseSuggestURLValue());
GURL url(url_string);
if (!url.is_valid())
@@ -240,12 +254,31 @@ void TemplateURLRef::ParseHostAndSearchTermKey() const {
}
}
+// static
+void TemplateURLRef::SetGoogleBaseURL(std::string* google_base_url) {
+ UIThreadSearchTermsData::SetGoogleBaseURL(google_base_url);
+}
+
std::string TemplateURLRef::ReplaceSearchTerms(
const TemplateURL& host,
const std::wstring& terms,
int accepted_suggestion,
const std::wstring& original_query_for_suggestion) const {
- ParseIfNecessary();
+ UIThreadSearchTermsData search_terms_data;
+ return ReplaceSearchTermsUsingTermsData(host,
+ terms,
+ accepted_suggestion,
+ original_query_for_suggestion,
+ search_terms_data);
+}
+
+std::string TemplateURLRef::ReplaceSearchTermsUsingTermsData(
+ const TemplateURL& host,
+ const std::wstring& terms,
+ int accepted_suggestion,
+ const std::wstring& original_query_for_suggestion,
+ const SearchTermsData& search_terms_data) const {
+ ParseIfNecessaryUsingTermsData(search_terms_data);
if (!valid_)
return std::string();
@@ -320,11 +353,11 @@ std::string TemplateURLRef::ReplaceSearchTerms(
break;
case GOOGLE_BASE_URL:
- url.insert(i->index, GoogleBaseURLValue());
+ url.insert(i->index, search_terms_data.GoogleBaseURLValue());
break;
case GOOGLE_BASE_SUGGEST_URL:
- url.insert(i->index, GoogleBaseSuggestURLValue());
+ url.insert(i->index, search_terms_data.GoogleBaseSuggestURLValue());
break;
case GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION:
@@ -338,9 +371,8 @@ std::string TemplateURLRef::ReplaceSearchTerms(
// to happen so that we replace the RLZ template with the
// empty string. (If we don't handle this case, we hit a
// NOTREACHED below.)
-#if defined(OS_WIN)
- std::wstring rlz_string;
- RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz_string);
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+ std::wstring rlz_string = search_terms_data.GetRlzParameterValue();
if (!rlz_string.empty()) {
rlz_string = L"rlz=" + rlz_string + L"&";
url.insert(i->index, WideToUTF8(rlz_string));
@@ -360,7 +392,7 @@ std::string TemplateURLRef::ReplaceSearchTerms(
}
case LANGUAGE:
- url.insert(i->index, g_browser_process->GetApplicationLocale());
+ url.insert(i->index, search_terms_data.GetApplicationLocale());
break;
case SEARCH_TERMS:
@@ -377,12 +409,24 @@ std::string TemplateURLRef::ReplaceSearchTerms(
}
bool TemplateURLRef::SupportsReplacement() const {
- ParseIfNecessary();
+ UIThreadSearchTermsData search_terms_data;
+ return SupportsReplacementUsingTermsData(search_terms_data);
+}
+
+bool TemplateURLRef::SupportsReplacementUsingTermsData(
+ const SearchTermsData& search_terms_data) const {
+ ParseIfNecessaryUsingTermsData(search_terms_data);
return valid_ && supports_replacements_;
}
bool TemplateURLRef::IsValid() const {
- ParseIfNecessary();
+ UIThreadSearchTermsData search_terms_data;
+ return IsValidUsingTermsData(search_terms_data);
+}
+
+bool TemplateURLRef::IsValidUsingTermsData(
+ const SearchTermsData& search_terms_data) const {
+ ParseIfNecessaryUsingTermsData(search_terms_data);
return valid_;
}
@@ -477,43 +521,6 @@ void TemplateURLRef::InvalidateCachedValues() const {
replacements_.clear();
}
-// Returns the value to use for replacements of type GOOGLE_BASE_URL.
-// static
-std::string TemplateURLRef::GoogleBaseURLValue() {
- return google_base_url_ ?
- (*google_base_url_) : GoogleURLTracker::GoogleURL().spec();
-}
-
-// Returns the value to use for replacements of type GOOGLE_BASE_SUGGEST_URL.
-// static
-std::string TemplateURLRef::GoogleBaseSuggestURLValue() {
- // The suggest base URL we want at the end is something like
- // "http://clients1.google.TLD/complete/". The key bit we want from the
- // original Google base URL is the TLD.
-
- // Start with the Google base URL.
- const GURL base_url(google_base_url_ ?
- GURL(*google_base_url_) : GoogleURLTracker::GoogleURL());
- DCHECK(base_url.is_valid());
-
- // Change "www." to "clients1." in the hostname. If no "www." was found, just
- // prepend "clients1.".
- const std::string base_host(base_url.host());
- GURL::Replacements repl;
- const std::string suggest_host("clients1." +
- (base_host.compare(0, 4, "www.") ? base_host : base_host.substr(4)));
- repl.SetHostStr(suggest_host);
-
- // Replace any existing path with "/complete/".
- static const std::string suggest_path("/complete/");
- repl.SetPathStr(suggest_path);
-
- // Clear the query and ref.
- repl.ClearQuery();
- repl.ClearRef();
- return base_url.ReplaceComponents(repl).spec();
-}
-
// TemplateURL ----------------------------------------------------------------
// static
@@ -534,7 +541,33 @@ GURL TemplateURL::GenerateFaviconURL(const GURL& url) {
// static
bool TemplateURL::SupportsReplacement(const TemplateURL* turl) {
- return turl && turl->url() && turl->url()->SupportsReplacement();
+ UIThreadSearchTermsData search_terms_data;
+ return SupportsReplacementUsingTermsData(turl, search_terms_data);
+}
+
+// static
+bool TemplateURL::SupportsReplacementUsingTermsData(
+ const TemplateURL* turl,
+ const SearchTermsData& search_terms_data) {
+ return turl && turl->url() &&
+ turl->url()->SupportsReplacementUsingTermsData(search_terms_data);
+}
+
+TemplateURL::TemplateURL()
+ : autogenerate_keyword_(false),
+ keyword_generated_(false),
+ show_in_default_list_(false),
+ safe_for_autoreplace_(false),
+ id_(0),
+ date_created_(base::Time::Now()),
+ created_by_policy_(false),
+ usage_count_(0),
+ search_engine_type_(TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER),
+ logo_id_(0),
+ prepopulate_id_(0) {
+}
+
+TemplateURL::~TemplateURL() {
}
std::wstring TemplateURL::AdjustedShortNameForLocaleDirection() const {
@@ -560,18 +593,22 @@ void TemplateURL::SetURL(const std::string& url,
void TemplateURL::set_keyword(const std::wstring& keyword) {
// Case sensitive keyword matching is confusing. As such, we force all
// keywords to be lower case.
- keyword_ = l10n_util::ToLower(keyword);
+ keyword_ = UTF16ToWide(l10n_util::ToLower(WideToUTF16(keyword)));
autogenerate_keyword_ = false;
}
const std::wstring& TemplateURL::keyword() const {
+ EnsureKeyword();
+ return keyword_;
+}
+
+void TemplateURL::EnsureKeyword() const {
if (autogenerate_keyword_ && !keyword_generated_) {
// Generate a keyword and cache it.
keyword_ = TemplateURLModel::GenerateKeyword(
TemplateURLModel::GenerateSearchURL(this).GetWithEmptyPath(), true);
keyword_generated_ = true;
}
- return keyword_;
}
bool TemplateURL::ShowInDefaultList() const {
diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h
index fb8a707..7a4f12d 100644
--- a/chrome/browser/search_engines/template_url.h
+++ b/chrome/browser/search_engines/template_url.h
@@ -4,15 +4,21 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_H_
#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_H_
+#pragma once
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/time.h"
+#include "chrome/browser/search_engines/template_url_id.h"
+#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "googleurl/src/gurl.h"
+class SearchTermsData;
class TemplateURL;
+class WebDataService;
+struct WDKeywordsResult;
// TemplateURL represents the relevant portions of the Open Search Description
// Document (http://www.opensearch.org/Specifications/OpenSearch).
@@ -45,18 +51,17 @@ class TemplateURLRef {
TemplateURLRef();
- TemplateURLRef(const std::string& url, int index_offset, int page_offset)
- : url_(url),
- index_offset_(index_offset),
- page_offset_(page_offset),
- parsed_(false),
- valid_(false),
- supports_replacements_(false) {
- }
+ TemplateURLRef(const std::string& url, int index_offset, int page_offset);
+
+ ~TemplateURLRef();
// Returns true if this URL supports replacement.
bool SupportsReplacement() const;
+ // Like SupportsReplacement but usable on threads other than the UI thread.
+ bool SupportsReplacementUsingTermsData(
+ const SearchTermsData& search_terms_data) const;
+
// Returns a string that is the result of replacing the search terms in
// the url with the specified value.
//
@@ -70,6 +75,16 @@ class TemplateURLRef {
int accepted_suggestion,
const std::wstring& original_query_for_suggestion) const;
+ // Just like ReplaceSearchTerms except that it takes SearchTermsData to supply
+ // the data for some search terms. Most of the time ReplaceSearchTerms should
+ // be called.
+ std::string ReplaceSearchTermsUsingTermsData(
+ const TemplateURL& host,
+ const std::wstring& terms,
+ int accepted_suggestion,
+ const std::wstring& original_query_for_suggestion,
+ const SearchTermsData& search_terms_data) const;
+
// Returns the raw URL. None of the parameters will have been replaced.
const std::string& url() const { return url_; }
@@ -83,6 +98,9 @@ class TemplateURLRef {
// one that contains unknown terms, or invalid characters.
bool IsValid() const;
+ // Like IsValid but usable on threads other than the UI thread.
+ bool IsValidUsingTermsData(const SearchTermsData& search_terms_data) const;
+
// Returns a string representation of this TemplateURLRef suitable for
// display. The display format is the same as the format used by Firefox.
std::wstring DisplayURL() const;
@@ -110,8 +128,9 @@ class TemplateURLRef {
bool HasGoogleBaseURLs() const;
private:
+ friend class SearchHostToURLsMapTest;
friend class TemplateURL;
- friend class TemplateURLModelTest;
+ friend class TemplateURLModelTestUtil;
friend class TemplateURLTest;
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseParameterKnown);
FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseParameterUnknown);
@@ -180,14 +199,17 @@ class TemplateURLRef {
// search_offset_.
void ParseIfNecessary() const;
- // Extracts the query key and host from the url.
- void ParseHostAndSearchTermKey() const;
+ // Like ParseIfNecessary but usable on threads other than the UI thread.
+ void ParseIfNecessaryUsingTermsData(
+ const SearchTermsData& search_terms_data) const;
- // Returns the value for the GOOGLE_BASE_URL term.
- static std::string GoogleBaseURLValue();
+ // Extracts the query key and host from the url.
+ void ParseHostAndSearchTermKey(
+ const SearchTermsData& search_terms_data) const;
- // Returns the value for the GOOGLE_BASE_SUGGEST_URL term.
- static std::string GoogleBaseSuggestURLValue();
+ // Used by tests to set the value for the Google base url. This takes
+ // ownership of the given std::string.
+ static void SetGoogleBaseURL(std::string* google_base_url);
// The raw URL. Where as this contains all the terms (such as {searchTerms}),
// parsed_url_ has them all stripped out.
@@ -221,17 +243,11 @@ class TemplateURLRef {
mutable std::string host_;
mutable std::string path_;
mutable std::string search_term_key_;
-
- // For testing. If non-null this is the replacement value for GOOGLE_BASE_URL
- // terms.
- static std::string* google_base_url_;
};
// Describes the relevant portions of a single OSD document.
class TemplateURL {
public:
- typedef int64 IDType;
-
// Describes a single image reference. Each TemplateURL may have
// any number (including 0) of ImageRefs.
//
@@ -261,20 +277,17 @@ class TemplateURL {
// Generates a favicon URL from the specified url.
static GURL GenerateFaviconURL(const GURL& url);
- // Returns true if |true| is non-null and has a search URL that supports
+ // Returns true if |turl| is non-null and has a search URL that supports
// replacement.
static bool SupportsReplacement(const TemplateURL* turl);
- TemplateURL()
- : autogenerate_keyword_(false),
- keyword_generated_(false),
- show_in_default_list_(false),
- safe_for_autoreplace_(false),
- id_(0),
- date_created_(base::Time::Now()),
- usage_count_(0),
- prepopulate_id_(0) {}
- ~TemplateURL() {}
+ // Like SupportsReplacement but usable on threads other than the UI thread.
+ static bool SupportsReplacementUsingTermsData(
+ const TemplateURL* turl,
+ const SearchTermsData& search_terms_data);
+
+ TemplateURL();
+ ~TemplateURL();
// A short description of the template. This is the name we show to the user
// in various places that use keywords. For example, the location bar shows
@@ -284,6 +297,10 @@ class TemplateURL {
}
const std::wstring& short_name() const { return short_name_; }
+ // Returns true if this search engine supports showing instant results.
+ // TODO(sky): make this real.
+ bool supports_instant() const { return false; }
+
// An accessor for the short_name, but adjusted so it can be appropriately
// displayed even if it is LTR and the UI is RTL.
std::wstring AdjustedShortNameForLocaleDirection() const;
@@ -344,6 +361,11 @@ class TemplateURL {
return autogenerate_keyword_;
}
+ // Ensures that the keyword is generated. Most consumers should not need this
+ // because it is done automatically. Use this method on the UI thread, so
+ // the keyword may be accessed on another thread.
+ void EnsureKeyword() const;
+
// Whether this keyword is shown in the default list of search providers. This
// is just a property and does not indicate whether this TemplateURL has
// a TemplateURLRef that supports replacement. Use ShowInDefaultList to
@@ -393,6 +415,13 @@ class TemplateURL {
void set_date_created(base::Time time) { date_created_ = time; }
base::Time date_created() const { return date_created_; }
+ // True if this TemplateURL was automatically created by the administrator via
+ // group policy.
+ void set_created_by_policy(bool created_by_policy) {
+ created_by_policy_ = created_by_policy;
+ }
+ bool created_by_policy() const { return created_by_policy_; }
+
// Number of times this keyword has been explicitly used to load a URL. We
// don't increment this for uses as the "default search engine" since that's
// not really "explicit" usage and incrementing would result in pinning the
@@ -413,9 +442,20 @@ class TemplateURL {
return input_encodings_;
}
+ void set_search_engine_type(TemplateURLPrepopulateData::SearchEngineType
+ search_engine_type) {
+ search_engine_type_ = search_engine_type;
+ }
+ TemplateURLPrepopulateData::SearchEngineType search_engine_type() const {
+ return search_engine_type_;
+ }
+
+ void set_logo_id(int logo_id) { logo_id_ = logo_id; }
+ int logo_id() const { return logo_id_; }
+
// Returns the unique identifier of this TemplateURL. The unique ID is set
// by the TemplateURLModel when the TemplateURL is added to it.
- IDType id() const { return id_; }
+ TemplateURLID id() const { return id_; }
// If this TemplateURL comes from prepopulated data the prepopulate_id is > 0.
void set_prepopulate_id(int id) { prepopulate_id_ = id; }
@@ -425,15 +465,21 @@ class TemplateURL {
bool IsExtensionKeyword() const;
private:
+ friend void MergeEnginesFromPrepopulateData(
+ PrefService* prefs,
+ WebDataService* service,
+ std::vector<TemplateURL*>* template_urls,
+ const TemplateURL** default_search_provider);
+ friend class SearchHostToURLsMap;
+ friend class TemplateURLModel;
friend class WebDatabaseTest;
friend class WebDatabase;
- friend class TemplateURLModel;
// Invalidates cached values on this object and its child TemplateURLRefs.
void InvalidateCachedValues() const;
// Unique identifier, used when archived to the database.
- void set_id(IDType id) { id_ = id;}
+ void set_id(TemplateURLID id) { id_ = id;}
std::wstring short_name_;
std::wstring description_;
@@ -452,9 +498,12 @@ class TemplateURL {
std::vector<std::wstring> languages_;
// List of supported input encodings.
std::vector<std::string> input_encodings_;
- IDType id_;
+ TemplateURLID id_;
base::Time date_created_;
+ bool created_by_policy_;
int usage_count_;
+ TemplateURLPrepopulateData::SearchEngineType search_engine_type_;
+ int logo_id_;
int prepopulate_id_;
// TODO(sky): Add date last parsed OSD file.
diff --git a/chrome/browser/search_engines/template_url_fetcher.h b/chrome/browser/search_engines/template_url_fetcher.h
index 485a808..e773890 100644
--- a/chrome/browser/search_engines/template_url_fetcher.h
+++ b/chrome/browser/search_engines/template_url_fetcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_FETCHER_H_
#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_FETCHER_H_
+#pragma once
#include "base/scoped_vector.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/search_engines/template_url_id.h b/chrome/browser/search_engines/template_url_id.h
new file mode 100644
index 0000000..db607e2
--- /dev/null
+++ b/chrome/browser/search_engines/template_url_id.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.
+
+#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_ID_H_
+#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_ID_H_
+#pragma once
+
+typedef int64 TemplateURLID;
+
+#endif // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_ID_H_
diff --git a/chrome/browser/search_engines/template_url_model.cc b/chrome/browser/search_engines/template_url_model.cc
index ede0ea0..e4df284 100644
--- a/chrome/browser/search_engines/template_url_model.cc
+++ b/chrome/browser/search_engines/template_url_model.cc
@@ -5,17 +5,27 @@
#include "chrome/browser/search_engines/template_url_model.h"
#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/environment.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/google_url_tracker.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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/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"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
+#include "chrome/browser/search_engines/util.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/env_vars.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -23,6 +33,7 @@
#include "net/base/net_util.h"
using base::Time;
+typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
// String in the URL that is replaced by the search term.
static const char kSearchTermParameter[] = "{searchTerms}";
@@ -71,7 +82,7 @@ TemplateURLModel::TemplateURLModel(Profile* profile)
TemplateURLModel::TemplateURLModel(const Initializer* initializers,
const int count)
: profile_(NULL),
- loaded_(true),
+ loaded_(false),
load_failed_(false),
load_handle_(0),
service_(NULL),
@@ -89,51 +100,6 @@ TemplateURLModel::~TemplateURLModel() {
STLDeleteElements(&template_urls_);
}
-void TemplateURLModel::Init(const Initializer* initializers,
- int num_initializers) {
- // Register for notifications.
- if (profile_) {
- // TODO(sky): bug 1166191. The keywords should be moved into the history
- // db, which will mean we no longer need this notification and the history
- // backend can handle automatically adding the search terms as the user
- // navigates.
- registrar_.Add(this, NotificationType::HISTORY_URL_VISITED,
- Source<Profile>(profile_->GetOriginalProfile()));
- }
- registrar_.Add(this, NotificationType::GOOGLE_URL_UPDATED,
- NotificationService::AllSources());
-
- // Add specific initializers, if any.
- for (int i(0); i < num_initializers; ++i) {
- DCHECK(initializers[i].keyword);
- DCHECK(initializers[i].url);
- DCHECK(initializers[i].content);
-
- size_t template_position =
- std::string(initializers[i].url).find(kTemplateParameter);
- DCHECK(template_position != std::wstring::npos);
- std::string osd_url(initializers[i].url);
- osd_url.replace(template_position, arraysize(kTemplateParameter) - 1,
- kSearchTermParameter);
-
- // TemplateURLModel ends up owning the TemplateURL, don't try and free it.
- TemplateURL* template_url = new TemplateURL();
- template_url->set_keyword(initializers[i].keyword);
- template_url->set_short_name(initializers[i].content);
- template_url->SetURL(osd_url, 0, 0);
- Add(template_url);
- }
-
- // Request a server check for the correct Google URL if Google is the default
- // search engine.
- const TemplateURL* default_provider = GetDefaultSearchProvider();
- if (default_provider) {
- const TemplateURLRef* default_provider_ref = default_provider->url();
- if (default_provider_ref && default_provider_ref->HasGoogleBaseURLs())
- GoogleURLTracker::RequestServerCheck();
- }
-}
-
// static
std::wstring TemplateURLModel::GenerateKeyword(const GURL& url,
bool autodetected) {
@@ -153,18 +119,27 @@ std::wstring TemplateURLModel::GenerateKeyword(const GURL& url,
// Strip "www." off the front of the keyword; otherwise the keyword won't work
// properly. See http://code.google.com/p/chromium/issues/detail?id=6984 .
- return net::StripWWW(UTF8ToWide(url.host()));
+ return UTF16ToWideHack(net::StripWWW(UTF8ToUTF16(url.host())));
}
// static
std::wstring TemplateURLModel::CleanUserInputKeyword(
const std::wstring& keyword) {
// Remove the scheme.
- std::wstring result(l10n_util::ToLower(keyword));
+ std::wstring result(UTF16ToWide(l10n_util::ToLower(WideToUTF16(keyword))));
url_parse::Component scheme_component;
if (url_parse::ExtractScheme(WideToUTF8(keyword).c_str(),
static_cast<int>(keyword.length()),
&scheme_component)) {
+ // If the scheme isn't "http" or "https", bail. The user isn't trying to
+ // type a web address, but rather an FTP, file:, or other scheme URL, or a
+ // search query with some sort of initial operator (e.g. "site:").
+ if (result.compare(0, scheme_component.end(),
+ ASCIIToWide(chrome::kHttpScheme)) &&
+ result.compare(0, scheme_component.end(),
+ ASCIIToWide(chrome::kHttpsScheme)))
+ return std::wstring();
+
// Include trailing ':'.
result.erase(0, scheme_component.end() + 1);
// Many schemes usually have "//" after them, so strip it too.
@@ -174,7 +149,7 @@ std::wstring TemplateURLModel::CleanUserInputKeyword(
}
// Remove leading "www.".
- result = net::StripWWW(result);
+ result = UTF16ToWideHack(net::StripWWW(WideToUTF16(result)));
// Remove trailing "/".
return (result.length() > 0 && result[result.length() - 1] == L'/') ?
@@ -184,17 +159,27 @@ std::wstring TemplateURLModel::CleanUserInputKeyword(
// static
GURL TemplateURLModel::GenerateSearchURL(const TemplateURL* t_url) {
DCHECK(t_url);
+ UIThreadSearchTermsData search_terms_data;
+ return GenerateSearchURLUsingTermsData(t_url, search_terms_data);
+}
+
+// static
+GURL TemplateURLModel::GenerateSearchURLUsingTermsData(
+ const TemplateURL* t_url,
+ const SearchTermsData& search_terms_data) {
+ DCHECK(t_url);
const TemplateURLRef* search_ref = t_url->url();
// Extension keywords don't have host-based search URLs.
- if (!search_ref || !search_ref->IsValid() || t_url->IsExtensionKeyword())
+ if (!search_ref || !search_ref->IsValidUsingTermsData(search_terms_data) ||
+ t_url->IsExtensionKeyword())
return GURL();
- if (!search_ref->SupportsReplacement())
+ if (!search_ref->SupportsReplacementUsingTermsData(search_terms_data))
return GURL(search_ref->url());
- return GURL(search_ref->ReplaceSearchTerms(
+ return GURL(search_ref->ReplaceSearchTermsUsingTermsData(
*t_url, kReplacementTerm, TemplateURLRef::NO_SUGGESTIONS_AVAILABLE,
- std::wstring()));
+ std::wstring(), search_terms_data));
}
bool TemplateURLModel::CanReplaceKeyword(
@@ -260,10 +245,7 @@ const TemplateURL* TemplateURLModel::GetTemplateURLForKeyword(
const TemplateURL* TemplateURLModel::GetTemplateURLForHost(
const std::string& host) const {
- HostToURLsMap::const_iterator iter = host_to_urls_map_.find(host);
- if (iter == host_to_urls_map_.end() || iter->second.empty())
- return NULL;
- return *(iter->second.begin()); // Return the 1st element.
+ return provider_map_.GetTemplateURLForHost(host);
}
void TemplateURLModel::Add(TemplateURL* template_url) {
@@ -284,15 +266,6 @@ void TemplateURLModel::Add(TemplateURL* template_url) {
}
}
-void TemplateURLModel::AddToMaps(const TemplateURL* template_url) {
- if (!template_url->keyword().empty())
- keyword_to_template_map_[template_url->keyword()] = template_url;
-
- const GURL url(GenerateSearchURL(template_url));
- if (url.is_valid() && url.has_host())
- host_to_urls_map_[url.host()].insert(template_url);
-}
-
void TemplateURLModel::Remove(const TemplateURL* template_url) {
TemplateURLVector::iterator i = find(template_urls_.begin(),
template_urls_.end(),
@@ -330,36 +303,6 @@ void TemplateURLModel::Remove(const TemplateURL* template_url) {
delete template_url;
}
-void TemplateURLModel::Replace(const TemplateURL* existing_turl,
- TemplateURL* new_turl) {
- DCHECK(existing_turl && new_turl);
-
- TemplateURLVector::iterator i = find(template_urls_.begin(),
- template_urls_.end(),
- existing_turl);
- DCHECK(i != template_urls_.end());
- RemoveFromMaps(existing_turl);
- template_urls_.erase(i);
-
- new_turl->set_id(existing_turl->id());
-
- template_urls_.push_back(new_turl);
- AddToMaps(new_turl);
-
- if (service_.get())
- service_->UpdateKeyword(*new_turl);
-
- if (default_search_provider_ == existing_turl)
- SetDefaultSearchProvider(new_turl);
-
- if (loaded_) {
- FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
- OnTemplateURLModelChanged());
- }
-
- delete existing_turl;
-}
-
void TemplateURLModel::RemoveAutoGeneratedBetween(Time created_after,
Time created_before) {
for (size_t i = 0; i < template_urls_.size();) {
@@ -378,70 +321,54 @@ void TemplateURLModel::RemoveAutoGeneratedSince(Time created_after) {
RemoveAutoGeneratedBetween(created_after, Time());
}
-void TemplateURLModel::SetKeywordSearchTermsForURL(const TemplateURL* t_url,
- const GURL& url,
- const std::wstring& term) {
- HistoryService* history = profile_ ?
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) : NULL;
- if (!history)
+void TemplateURLModel::RegisterExtensionKeyword(Extension* extension) {
+ // TODO(mpcomplete): disable the keyword when the extension is disabled.
+ if (extension->omnibox_keyword().empty())
return;
- history->SetKeywordSearchTermsForURL(url, t_url->id(),
- WideToUTF16Hack(term));
-}
-void TemplateURLModel::RemoveFromMaps(const TemplateURL* template_url) {
- if (!template_url->keyword().empty()) {
- keyword_to_template_map_.erase(template_url->keyword());
+ Load();
+ if (!loaded_) {
+ pending_extension_ids_.push_back(extension->id());
+ return;
}
- const GURL url(GenerateSearchURL(template_url));
- if (url.is_valid() && url.has_host()) {
- const std::string host(url.host());
- DCHECK(host_to_urls_map_.find(host) != host_to_urls_map_.end());
- TemplateURLSet& urls = host_to_urls_map_[host];
- DCHECK(urls.find(template_url) != urls.end());
- urls.erase(urls.find(template_url));
- if (urls.empty())
- host_to_urls_map_.erase(host_to_urls_map_.find(host));
- }
-}
+ const TemplateURL* existing_url = GetTemplateURLForExtension(extension);
+ std::wstring keyword = UTF8ToWide(extension->omnibox_keyword());
-void TemplateURLModel::RemoveFromMapsByPointer(
- const TemplateURL* template_url) {
- DCHECK(template_url);
- for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin();
- i != keyword_to_template_map_.end(); ++i) {
- if (i->second == template_url) {
- keyword_to_template_map_.erase(i);
- // A given TemplateURL only occurs once in the map. As soon as we find the
- // entry, stop.
- break;
- }
- }
+ scoped_ptr<TemplateURL> template_url(new TemplateURL);
+ template_url->set_short_name(UTF8ToWide(extension->name()));
+ template_url->set_keyword(keyword);
+ // This URL is not actually used for navigation. It holds the extension's
+ // ID, as well as forcing the TemplateURL to be treated as a search keyword.
+ template_url->SetURL(
+ std::string(chrome::kExtensionScheme) + "://" +
+ extension->id() + "/?q={searchTerms}", 0, 0);
+ template_url->set_safe_for_autoreplace(false);
- for (HostToURLsMap::iterator i = host_to_urls_map_.begin();
- i != host_to_urls_map_.end(); ++i) {
- TemplateURLSet::iterator url_set_iterator = i->second.find(template_url);
- if (url_set_iterator != i->second.end()) {
- i->second.erase(url_set_iterator);
- if (i->second.empty())
- host_to_urls_map_.erase(i);
- // A given TemplateURL only occurs once in the map. As soon as we find the
- // entry, stop.
- return;
- }
+ if (existing_url) {
+ // TODO(mpcomplete): only replace if the user hasn't changed the keyword.
+ // (We don't have UI for that yet).
+ Update(existing_url, *template_url);
+ } else {
+ Add(template_url.release());
}
}
-void TemplateURLModel::SetTemplateURLs(
- const std::vector<const TemplateURL*>& urls) {
- // Add mappings for the new items.
- for (TemplateURLVector::const_iterator i = urls.begin(); i != urls.end();
- ++i) {
- next_id_ = std::max(next_id_, (*i)->id());
- AddToMaps(*i);
- template_urls_.push_back(*i);
+void TemplateURLModel::UnregisterExtensionKeyword(Extension* extension) {
+ const TemplateURL* url = GetTemplateURLForExtension(extension);
+ if (url)
+ Remove(url);
+}
+
+const TemplateURL* TemplateURLModel::GetTemplateURLForExtension(
+ Extension* extension) const {
+ for (TemplateURLVector::const_iterator i = template_urls_.begin();
+ i != template_urls_.end(); ++i) {
+ if ((*i)->IsExtensionKeyword() && (*i)->url()->GetHost() == extension->id())
+ return *i;
}
+
+ return NULL;
}
std::vector<const TemplateURL*> TemplateURLModel::GetTemplateURLs() const {
@@ -460,26 +387,18 @@ void TemplateURLModel::ResetTemplateURL(const TemplateURL* url,
const std::wstring& title,
const std::wstring& keyword,
const std::string& search_url) {
- DCHECK(url && find(template_urls_.begin(), template_urls_.end(), url) !=
- template_urls_.end());
- RemoveFromMaps(url);
- TemplateURL* modifiable_url = const_cast<TemplateURL*>(url);
- modifiable_url->set_short_name(title);
- modifiable_url->set_keyword(keyword);
- if ((modifiable_url->url() && search_url.empty()) ||
- (!modifiable_url->url() && !search_url.empty()) ||
- (modifiable_url->url() && modifiable_url->url()->url() != search_url)) {
+ TemplateURL new_url(*url);
+ new_url.set_short_name(title);
+ new_url.set_keyword(keyword);
+ if ((new_url.url() && search_url.empty()) ||
+ (!new_url.url() && !search_url.empty()) ||
+ (new_url.url() && new_url.url()->url() != search_url)) {
// The urls have changed, reset the favicon url.
- modifiable_url->SetFavIconURL(GURL());
- modifiable_url->SetURL(search_url, 0, 0);
+ new_url.SetFavIconURL(GURL());
+ new_url.SetURL(search_url, 0, 0);
}
- modifiable_url->set_safe_for_autoreplace(false);
- AddToMaps(url);
- if (service_.get())
- service_.get()->UpdateKeyword(*url);
-
- FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
- OnTemplateURLModelChanged());
+ new_url.set_safe_for_autoreplace(false);
+ Update(url, new_url);
}
void TemplateURLModel::SetDefaultSearchProvider(const TemplateURL* url) {
@@ -501,7 +420,7 @@ void TemplateURLModel::SetDefaultSearchProvider(const TemplateURL* url) {
const TemplateURLRef* url_ref = url->url();
if (url_ref && url_ref->HasGoogleBaseURLs()) {
GoogleURLTracker::RequestServerCheck();
-#if defined(OS_WIN)
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
RLZTracker::RecordProductEvent(rlz_lib::CHROME,
rlz_lib::CHROME_OMNIBOX,
rlz_lib::SET_TO_GOOGLE);
@@ -545,6 +464,15 @@ const TemplateURL* TemplateURLModel::GetDefaultSearchProvider() {
return prefs_default_search_provider_.get();
}
+bool TemplateURLModel::IsDefaultSearchManaged() {
+ PrefService* prefs = GetPrefs();
+ if (!prefs)
+ return false;
+ const PrefService::Preference* pref =
+ prefs->FindPreference(prefs::kDefaultSearchProviderSearchURL);
+ return pref && pref->IsManaged();
+}
+
void TemplateURLModel::AddObserver(TemplateURLModelObserver* observer) {
model_observers_.AddObserver(observer);
}
@@ -563,14 +491,14 @@ void TemplateURLModel::Load() {
if (service_.get()) {
load_handle_ = service_->GetKeywords(this);
} else {
- loaded_ = true;
+ ChangeToLoadedState();
NotifyLoaded();
}
}
void TemplateURLModel::OnWebDataServiceRequestDone(
- WebDataService::Handle h,
- const WDTypedResult* result) {
+ WebDataService::Handle h,
+ const WDTypedResult* result) {
// Reset the load_handle so that we don't try and cancel the load in
// the destructor.
load_handle_ = 0;
@@ -578,71 +506,56 @@ void TemplateURLModel::OnWebDataServiceRequestDone(
if (!result) {
// Results are null if the database went away or (most likely) wasn't
// loaded.
- loaded_ = true;
load_failed_ = true;
+ ChangeToLoadedState();
NotifyLoaded();
return;
}
- DCHECK(result->GetType() == KEYWORDS_RESULT);
-
- WDKeywordsResult keyword_result = reinterpret_cast<
- const WDResult<WDKeywordsResult>*>(result)->GetValue();
-
// prefs_default_search_provider_ is only needed before we've finished
// loading. Now that we've loaded we can nuke it.
prefs_default_search_provider_.reset();
- // Compiler won't implicitly convert std::vector<TemplateURL*> to
- // std::vector<const TemplateURL*>, and reinterpret_cast is unsafe,
- // so we just copy it.
- std::vector<const TemplateURL*> template_urls(keyword_result.keywords.begin(),
- keyword_result.keywords.end());
-
- const int resource_keyword_version =
- TemplateURLPrepopulateData::GetDataVersion(GetPrefs());
- if (keyword_result.builtin_keyword_version != resource_keyword_version) {
- // There should never be duplicate TemplateURLs. We had a bug such that
- // duplicate TemplateURLs existed for one locale. As such we invoke
- // RemoveDuplicatePrepopulateIDs to nuke the duplicates.
- RemoveDuplicatePrepopulateIDs(&template_urls);
+ std::vector<TemplateURL*> template_urls;
+ const TemplateURL* default_search_provider = NULL;
+ int new_resource_keyword_version = 0;
+ GetSearchProvidersUsingKeywordResult(*result,
+ service_.get(),
+ GetPrefs(),
+ &template_urls,
+ &default_search_provider,
+ &new_resource_keyword_version);
+
+ // If the default search provider existed previously, then just
+ // set the member variable. Otherwise, we'll set it using the method
+ // to ensure that it is saved properly after its id is set.
+ if (default_search_provider && default_search_provider->id() != 0) {
+ default_search_provider_ = default_search_provider;
+ default_search_provider = NULL;
}
SetTemplateURLs(template_urls);
- if (keyword_result.default_search_provider_id) {
- // See if we can find the default search provider.
- for (TemplateURLVector::iterator i = template_urls_.begin();
- i != template_urls_.end(); ++i) {
- if ((*i)->id() == keyword_result.default_search_provider_id) {
- default_search_provider_ = *i;
- break;
- }
- }
- }
-
- if (keyword_result.builtin_keyword_version != resource_keyword_version) {
- MergeEnginesFromPrepopulateData();
- service_->SetBuiltinKeywordVersion(resource_keyword_version);
+ if (default_search_provider) {
+ // Note that this saves the default search provider to prefs.
+ SetDefaultSearchProvider(default_search_provider);
+ } else {
+ // Always save the default search provider to prefs. That way we don't
+ // have to worry about it being out of sync.
+ if (default_search_provider_)
+ SaveDefaultSearchProviderToPrefs(default_search_provider_);
}
- // Always save the default search provider to prefs. That way we don't have to
- // worry about it being out of sync.
- if (default_search_provider_)
- SaveDefaultSearchProviderToPrefs(default_search_provider_);
-
- // Delete any hosts that were deleted before we finished loading.
- for (std::vector<std::wstring>::iterator i = hosts_to_delete_.begin();
- i != hosts_to_delete_.end(); ++i) {
- DeleteGeneratedKeywordsMatchingHost(*i);
- }
- hosts_to_delete_.clear();
+ // This initializes provider_map_ which should be done before
+ // calling UpdateKeywordSearchTermsForURL.
+ ChangeToLoadedState();
// Index any visits that occurred before we finished loading.
for (size_t i = 0; i < visits_to_add_.size(); ++i)
UpdateKeywordSearchTermsForURL(visits_to_add_[i]);
visits_to_add_.clear();
- loaded_ = true;
+ if (new_resource_keyword_version && service_.get())
+ service_->SetBuiltinKeywordVersion(new_resource_keyword_version);
FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
OnTemplateURLModelChanged());
@@ -650,28 +563,6 @@ void TemplateURLModel::OnWebDataServiceRequestDone(
NotifyLoaded();
}
-void TemplateURLModel::RemoveDuplicatePrepopulateIDs(
- std::vector<const TemplateURL*>* urls) {
- std::set<int> ids;
- for (std::vector<const TemplateURL*>::iterator i = urls->begin();
- i != urls->end(); ) {
- int prepopulate_id = (*i)->prepopulate_id();
- if (prepopulate_id) {
- if (ids.find(prepopulate_id) != ids.end()) {
- if (service_.get())
- service_->RemoveKeyword(**i);
- delete *i;
- i = urls->erase(i);
- } else {
- ids.insert(prepopulate_id);
- ++i;
- }
- } else {
- ++i;
- }
- }
-}
-
std::wstring TemplateURLModel::GetKeywordShortName(const std::wstring& keyword,
bool* is_extension_keyword) {
const TemplateURL* template_url = GetTemplateURLForKeyword(keyword);
@@ -704,20 +595,133 @@ void TemplateURLModel::Observe(NotificationType type,
}
}
-void TemplateURLModel::DeleteGeneratedKeywordsMatchingHost(
- const std::wstring& host) {
- const std::wstring host_slash = host + L"/";
- // Iterate backwards as we may end up removing multiple entries.
- for (int i = static_cast<int>(template_urls_.size()) - 1; i >= 0; --i) {
- if (CanReplace(template_urls_[i]) &&
- (template_urls_[i]->keyword() == host ||
- template_urls_[i]->keyword().compare(0, host_slash.length(),
- host_slash) == 0)) {
- Remove(template_urls_[i]);
+void TemplateURLModel::SetKeywordSearchTermsForURL(const TemplateURL* t_url,
+ const GURL& url,
+ const std::wstring& term) {
+ HistoryService* history = profile_ ?
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) : NULL;
+ if (!history)
+ return;
+ history->SetKeywordSearchTermsForURL(url, t_url->id(),
+ WideToUTF16Hack(term));
+}
+
+void TemplateURLModel::Init(const Initializer* initializers,
+ int num_initializers) {
+ // Register for notifications.
+ if (profile_) {
+ // TODO(sky): bug 1166191. The keywords should be moved into the history
+ // db, which will mean we no longer need this notification and the history
+ // backend can handle automatically adding the search terms as the user
+ // navigates.
+ registrar_.Add(this, NotificationType::HISTORY_URL_VISITED,
+ Source<Profile>(profile_->GetOriginalProfile()));
+ }
+ registrar_.Add(this, NotificationType::GOOGLE_URL_UPDATED,
+ NotificationService::AllSources());
+
+ if (num_initializers > 0) {
+ // This path is only hit by test code and is used to simulate a loaded
+ // TemplateURLModel.
+ ChangeToLoadedState();
+
+ // Add specific initializers, if any.
+ for (int i(0); i < num_initializers; ++i) {
+ DCHECK(initializers[i].keyword);
+ DCHECK(initializers[i].url);
+ DCHECK(initializers[i].content);
+
+ size_t template_position =
+ std::string(initializers[i].url).find(kTemplateParameter);
+ DCHECK(template_position != std::wstring::npos);
+ std::string osd_url(initializers[i].url);
+ osd_url.replace(template_position, arraysize(kTemplateParameter) - 1,
+ kSearchTermParameter);
+
+ // TemplateURLModel ends up owning the TemplateURL, don't try and free it.
+ TemplateURL* template_url = new TemplateURL();
+ template_url->set_keyword(initializers[i].keyword);
+ template_url->set_short_name(initializers[i].content);
+ template_url->SetURL(osd_url, 0, 0);
+ Add(template_url);
+ }
+ }
+
+ // Request a server check for the correct Google URL if Google is the default
+ // search engine, not in headless mode and not in Chrome Frame.
+ const TemplateURL* default_provider = GetDefaultSearchProvider();
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (default_provider && !env->HasVar(env_vars::kHeadless) &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame)) {
+ const TemplateURLRef* default_provider_ref = default_provider->url();
+ if (default_provider_ref && default_provider_ref->HasGoogleBaseURLs())
+ GoogleURLTracker::RequestServerCheck();
+ }
+}
+
+void TemplateURLModel::RemoveFromMaps(const TemplateURL* template_url) {
+ if (!template_url->keyword().empty())
+ keyword_to_template_map_.erase(template_url->keyword());
+ if (loaded_)
+ provider_map_.Remove(template_url);
+}
+
+void TemplateURLModel::RemoveFromKeywordMapByPointer(
+ const TemplateURL* template_url) {
+ DCHECK(template_url);
+ for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin();
+ i != keyword_to_template_map_.end(); ++i) {
+ if (i->second == template_url) {
+ keyword_to_template_map_.erase(i);
+ // A given TemplateURL only occurs once in the map. As soon as we find the
+ // entry, stop.
+ break;
}
}
}
+void TemplateURLModel::AddToMaps(const TemplateURL* template_url) {
+ if (!template_url->keyword().empty())
+ keyword_to_template_map_[template_url->keyword()] = template_url;
+ if (loaded_) {
+ UIThreadSearchTermsData search_terms_data;
+ provider_map_.Add(template_url, search_terms_data);
+ }
+}
+
+void TemplateURLModel::SetTemplateURLs(const std::vector<TemplateURL*>& urls) {
+ // Add mappings for the new items.
+
+ // First, add the items that already have id's, so that the next_id_
+ // gets properly set.
+ for (std::vector<TemplateURL*>::const_iterator i = urls.begin();
+ i != urls.end();
+ ++i) {
+ if ((*i)->id() == 0)
+ continue;
+ next_id_ = std::max(next_id_, (*i)->id());
+ AddToMaps(*i);
+ template_urls_.push_back(*i);
+ }
+
+ // Next add the new items that don't have id's.
+ for (std::vector<TemplateURL*>::const_iterator i = urls.begin();
+ i != urls.end();
+ ++i) {
+ if ((*i)->id() != 0)
+ continue;
+ Add(*i);
+ }
+}
+
+void TemplateURLModel::ChangeToLoadedState() {
+ DCHECK(!loaded_);
+
+ UIThreadSearchTermsData search_terms_data;
+ provider_map_.Init(template_urls_, search_terms_data);
+ loaded_ = true;
+}
+
void TemplateURLModel::NotifyLoaded() {
NotificationService::current()->Notify(
NotificationType::TEMPLATE_URL_MODEL_LOADED,
@@ -733,69 +737,6 @@ void TemplateURLModel::NotifyLoaded() {
pending_extension_ids_.clear();
}
-void TemplateURLModel::MergeEnginesFromPrepopulateData() {
- // Build a map from prepopulate id to TemplateURL of existing urls.
- typedef std::map<int, const TemplateURL*> IDMap;
- IDMap id_to_turl;
- for (TemplateURLVector::const_iterator i(template_urls_.begin());
- i != template_urls_.end(); ++i) {
- int prepopulate_id = (*i)->prepopulate_id();
- if (prepopulate_id > 0)
- id_to_turl[prepopulate_id] = *i;
- }
-
- std::vector<TemplateURL*> loaded_urls;
- size_t default_search_index;
- TemplateURLPrepopulateData::GetPrepopulatedEngines(GetPrefs(),
- &loaded_urls,
- &default_search_index);
-
- std::set<int> updated_ids;
- for (size_t i = 0; i < loaded_urls.size(); ++i) {
- // We take ownership of |t_url|.
- scoped_ptr<TemplateURL> t_url(loaded_urls[i]);
- int t_url_id = t_url->prepopulate_id();
- if (!t_url_id || updated_ids.count(t_url_id)) {
- // Prepopulate engines need a unique id.
- NOTREACHED();
- continue;
- }
-
- IDMap::iterator existing_url_iter(id_to_turl.find(t_url_id));
- if (existing_url_iter != id_to_turl.end()) {
- const TemplateURL* existing_url = existing_url_iter->second;
- if (!existing_url->safe_for_autoreplace()) {
- // User edited the entry, preserve the keyword and description.
- t_url->set_safe_for_autoreplace(false);
- t_url->set_keyword(existing_url->keyword());
- t_url->set_autogenerate_keyword(
- existing_url->autogenerate_keyword());
- t_url->set_short_name(existing_url->short_name());
- }
- Replace(existing_url, t_url.release());
- id_to_turl.erase(existing_url_iter);
- } else {
- Add(t_url.release());
- }
- if (i == default_search_index && !default_search_provider_)
- SetDefaultSearchProvider(loaded_urls[i]);
-
- updated_ids.insert(t_url_id);
- }
-
- // Remove any prepopulated engines which are no longer in the master list, as
- // long as the user hasn't modified them or made them the default engine.
- for (IDMap::iterator i(id_to_turl.begin()); i != id_to_turl.end(); ++i) {
- const TemplateURL* template_url = i->second;
- // We use default_search_provider_ instead of GetDefaultSearchProvider()
- // because we're running before |loaded_| is set, and calling
- // GetDefaultSearchProvider() will erroneously try to read the prefs.
- if ((template_url->safe_for_autoreplace()) &&
- (template_url != default_search_provider_))
- Remove(template_url);
- }
-}
-
void TemplateURLModel::SaveDefaultSearchProviderToPrefs(
const TemplateURL* t_url) {
PrefService* prefs = GetPrefs();
@@ -818,11 +759,11 @@ void TemplateURLModel::SaveDefaultSearchProviderToPrefs(
prefs->SetString(prefs::kDefaultSearchProviderName, name);
const std::string id_string =
- t_url ? Int64ToString(t_url->id()) : std::string();
+ t_url ? base::Int64ToString(t_url->id()) : std::string();
prefs->SetString(prefs::kDefaultSearchProviderID, id_string);
const std::string prepopulate_id =
- t_url ? Int64ToString(t_url->prepopulate_id()) : std::string();
+ t_url ? base::Int64ToString(t_url->prepopulate_id()) : std::string();
prefs->SetString(prefs::kDefaultSearchProviderPrepopulateID, prepopulate_id);
prefs->ScheduleSavePersistentPrefs();
@@ -862,10 +803,16 @@ bool TemplateURLModel::LoadDefaultSearchProviderFromPrefs(
(*default_provider)->set_short_name(name);
(*default_provider)->SetURL(search_url, 0, 0);
(*default_provider)->SetSuggestionsURL(suggest_url, 0, 0);
- if (!id_string.empty())
- (*default_provider)->set_id(StringToInt64(id_string));
- if (!prepopulate_id.empty())
- (*default_provider)->set_prepopulate_id(StringToInt(prepopulate_id));
+ if (!id_string.empty()) {
+ int64 value;
+ base::StringToInt64(id_string, &value);
+ (*default_provider)->set_id(value);
+ }
+ if (!prepopulate_id.empty()) {
+ int value;
+ base::StringToInt(prepopulate_id, &value);
+ (*default_provider)->set_prepopulate_id(value);
+ }
return true;
}
@@ -887,11 +834,10 @@ void TemplateURLModel::RegisterPrefs(PrefService* prefs) {
bool TemplateURLModel::CanReplaceKeywordForHost(
const std::string& host,
const TemplateURL** to_replace) {
- const HostToURLsMap::iterator matching_urls = host_to_urls_map_.find(host);
- const bool have_matching_urls = (matching_urls != host_to_urls_map_.end());
- if (have_matching_urls) {
- TemplateURLSet& urls = matching_urls->second;
- for (TemplateURLSet::iterator i = urls.begin(); i != urls.end(); ++i) {
+ const TemplateURLSet* urls = provider_map_.GetURLsForHost(host);
+ if (urls) {
+ for (TemplateURLSet::const_iterator i = urls->begin();
+ i != urls->end(); ++i) {
const TemplateURL* url = *i;
if (CanReplace(url)) {
if (to_replace)
@@ -903,7 +849,7 @@ bool TemplateURLModel::CanReplaceKeywordForHost(
if (to_replace)
*to_replace = NULL;
- return !have_matching_urls;
+ return !urls;
}
bool TemplateURLModel::CanReplace(const TemplateURL* t_url) {
@@ -911,6 +857,37 @@ bool TemplateURLModel::CanReplace(const TemplateURL* t_url) {
t_url->safe_for_autoreplace());
}
+void TemplateURLModel::Update(const TemplateURL* existing_turl,
+ const TemplateURL& new_values) {
+ DCHECK(loaded_);
+ DCHECK(existing_turl);
+ DCHECK(find(template_urls_.begin(), template_urls_.end(), existing_turl) !=
+ template_urls_.end());
+
+ if (!existing_turl->keyword().empty())
+ keyword_to_template_map_.erase(existing_turl->keyword());
+
+ // This call handles copying over the values (while retaining the id).
+ UIThreadSearchTermsData search_terms_data;
+ provider_map_.Update(existing_turl, new_values, search_terms_data);
+
+ if (!existing_turl->keyword().empty())
+ keyword_to_template_map_[existing_turl->keyword()] = existing_turl;
+
+ if (service_.get())
+ service_->UpdateKeyword(*existing_turl);
+
+ if (default_search_provider_ == existing_turl) {
+ // Force an update to happen to account for any changes
+ // that occurred during the update.
+ default_search_provider_ = NULL;
+ SetDefaultSearchProvider(existing_turl);
+ }
+
+ FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
+ OnTemplateURLModelChanged());
+}
+
PrefService* TemplateURLModel::GetPrefs() {
return profile_ ? profile_->GetPrefs() : NULL;
}
@@ -923,21 +900,18 @@ void TemplateURLModel::UpdateKeywordSearchTermsForURL(
return;
}
- HostToURLsMap::const_iterator t_urls_for_host_iterator =
- host_to_urls_map_.find(row.url().host());
- if (t_urls_for_host_iterator == host_to_urls_map_.end() ||
- t_urls_for_host_iterator->second.empty()) {
+ const TemplateURLSet* urls_for_host =
+ provider_map_.GetURLsForHost(row.url().host());
+ if (!urls_for_host)
return;
- }
- const TemplateURLSet& urls_for_host = t_urls_for_host_iterator->second;
QueryTerms query_terms;
bool built_terms = false; // Most URLs won't match a TemplateURLs host;
// so we lazily build the query_terms.
const std::string path = row.url().path();
- for (TemplateURLSet::const_iterator i = urls_for_host.begin();
- i != urls_for_host.end(); ++i) {
+ for (TemplateURLSet::const_iterator i = urls_for_host->begin();
+ i != urls_for_host->end(); ++i) {
const TemplateURLRef* search_ref = (*i)->url();
// Count the URL against a TemplateURL if the host and path of the
@@ -1002,7 +976,7 @@ void TemplateURLModel::AddTabToSearchVisit(const TemplateURL& t_url) {
// autocompleted even if the user doesn't type the url in directly.
history->AddPage(url, NULL, 0, GURL(),
PageTransition::KEYWORD_GENERATED,
- history::RedirectList(), false);
+ history::RedirectList(), history::SOURCE_BROWSED, false);
}
// static
@@ -1044,65 +1018,18 @@ void TemplateURLModel::GoogleBaseURLChanged() {
if ((t_url->url() && t_url->url()->HasGoogleBaseURLs()) ||
(t_url->suggestions_url() &&
t_url->suggestions_url()->HasGoogleBaseURLs())) {
- RemoveFromMapsByPointer(t_url);
+ RemoveFromKeywordMapByPointer(t_url);
t_url->InvalidateCachedValues();
- AddToMaps(t_url);
+ if (!t_url->keyword().empty())
+ keyword_to_template_map_[t_url->keyword()] = t_url;
something_changed = true;
}
}
if (something_changed && loaded_) {
+ UIThreadSearchTermsData search_terms_data;
+ provider_map_.UpdateGoogleBaseURLs(search_terms_data);
FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
OnTemplateURLModelChanged());
}
}
-
-void TemplateURLModel::RegisterExtensionKeyword(Extension* extension) {
- // TODO(mpcomplete): disable the keyword when the extension is disabled.
- if (extension->omnibox_keyword().empty())
- return;
-
- Load();
- if (!loaded_) {
- pending_extension_ids_.push_back(extension->id());
- return;
- }
-
- const TemplateURL* existing_url = GetTemplateURLForExtension(extension);
- std::wstring keyword = UTF8ToWide(extension->omnibox_keyword());
-
- TemplateURL* template_url = new TemplateURL;
- template_url->set_short_name(UTF8ToWide(extension->name()));
- template_url->set_keyword(keyword);
- // This URL is not actually used for navigation. It holds the extension's
- // ID, as well as forcing the TemplateURL to be treated as a search keyword.
- template_url->SetURL(
- std::string(chrome::kExtensionScheme) + "://" +
- extension->id() + "/?q={searchTerms}", 0, 0);
- template_url->set_safe_for_autoreplace(false);
-
- if (existing_url) {
- // TODO(mpcomplete): only replace if the user hasn't changed the keyword.
- // (We don't have UI for that yet).
- Replace(existing_url, template_url);
- } else {
- Add(template_url);
- }
-}
-
-void TemplateURLModel::UnregisterExtensionKeyword(Extension* extension) {
- const TemplateURL* url = GetTemplateURLForExtension(extension);
- if (url)
- Remove(url);
-}
-
-const TemplateURL* TemplateURLModel::GetTemplateURLForExtension(
- Extension* extension) const {
- for (TemplateURLVector::const_iterator i = template_urls_.begin();
- i != template_urls_.end(); ++i) {
- if ((*i)->IsExtensionKeyword() && (*i)->url()->GetHost() == extension->id())
- return *i;
- }
-
- return NULL;
-}
diff --git a/chrome/browser/search_engines/template_url_model.h b/chrome/browser/search_engines/template_url_model.h
index 95a4a8d..7dd532f 100644
--- a/chrome/browser/search_engines/template_url_model.h
+++ b/chrome/browser/search_engines/template_url_model.h
@@ -4,19 +4,26 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
+#pragma once
#include <set>
#include "base/gtest_prod_util.h"
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/search_engines/template_url_id.h"
#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/browser/search_engines/search_host_to_urls_map.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class GURL;
class Extension;
class PrefService;
class Profile;
+class SearchHostToURLsMap;
+class SearchTermsData;
+class TemplateURLModelObserver;
namespace history {
struct URLVisitedDetails;
@@ -43,14 +50,6 @@ struct URLVisitedDetails;
// is a WebDataService, deletion is handled by WebDataService, otherwise
// TemplateURLModel handles deletion.
-// TemplateURLModelObserver is notified whenever the set of TemplateURLs
-// are modified.
-class TemplateURLModelObserver {
- public:
- // Notification that the template url model has changed in some way.
- virtual void OnTemplateURLModelChanged() = 0;
-};
-
class TemplateURLModel : public WebDataServiceConsumer,
public NotificationObserver {
public:
@@ -67,8 +66,7 @@ class TemplateURLModel : public WebDataServiceConsumer,
explicit TemplateURLModel(Profile* profile);
// The following is for testing.
TemplateURLModel(const Initializer* initializers, const int count);
-
- ~TemplateURLModel();
+ virtual ~TemplateURLModel();
// Generates a suitable keyword for the specified url. Returns an empty
// string if a keyword couldn't be generated. If |autodetected| is true, we
@@ -85,6 +83,13 @@ class TemplateURLModel : public WebDataServiceConsumer,
// url().
static GURL GenerateSearchURL(const TemplateURL* t_url);
+ // Just like GenerateSearchURL except that it takes SearchTermsData to supply
+ // the data for some search terms. Most of the time GenerateSearchURL should
+ // be called.
+ static GURL GenerateSearchURLUsingTermsData(
+ const TemplateURL* t_url,
+ const SearchTermsData& search_terms_data);
+
// Returns true if there is no TemplateURL that conflicts with the
// keyword/url pair, or there is one but it can be replaced. If there is an
// existing keyword that can be replaced and template_url_to_replace is
@@ -127,13 +132,6 @@ class TemplateURLModel : public WebDataServiceConsumer,
void RemoveAutoGeneratedBetween(base::Time created_after,
base::Time created_before);
- // Replaces existing_turl with new_turl. new_turl is given the same ID as
- // existing_turl. If existing_turl was the default, new_turl is made the
- // default. After this call existing_turl is deleted. As with Add,
- // TemplateURLModel takes ownership of existing_turl.
- void Replace(const TemplateURL* existing_turl,
- TemplateURL* new_turl);
-
// Removes all auto-generated keywords that were created on or after the
// date passed in.
void RemoveAutoGeneratedSince(base::Time created_after);
@@ -176,6 +174,9 @@ class TemplateURLModel : public WebDataServiceConsumer,
// NOTE: At least in unittest mode, this may return NULL.
const TemplateURL* GetDefaultSearchProvider();
+ // Returns true if the default search is managed through group policy.
+ bool IsDefaultSearchManaged();
+
// Observers used to listen for changes to the model.
// TemplateURLModel does NOT delete the observers when deleted.
void AddObserver(TemplateURLModelObserver* observer);
@@ -184,7 +185,7 @@ class TemplateURLModel : public WebDataServiceConsumer,
// Loads the keywords. This has no effect if the keywords have already been
// loaded.
// Observers are notified when loading completes via the method
- // OnTemplateURLsReset.
+ // OnTemplateURLModelChanged.
void Load();
// Whether or not the keywords have been loaded.
@@ -196,12 +197,6 @@ class TemplateURLModel : public WebDataServiceConsumer,
virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
const WDTypedResult* result);
- // Removes (and deletes) TemplateURLs from |urls| that have duplicate
- // prepopulate ids. Duplicate prepopulate ids are not allowed, but due to a
- // bug it was possible get dups. This step is only called when the version
- // number changes.
- void RemoveDuplicatePrepopulateIDs(std::vector<const TemplateURL*>* urls);
-
// Returns the locale-direction-adjusted short name for the given keyword.
// Also sets the out param to indicate whether the keyword belongs to an
// extension.
@@ -245,12 +240,10 @@ class TemplateURLModel : public WebDataServiceConsumer,
DontUpdateKeywordSearchForNonReplaceable);
FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, ChangeGoogleBaseValue);
FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, MergeDeletesUnusedProviders);
- friend class TemplateURLModelTest;
+ friend class TemplateURLModelTestUtil;
typedef std::map<std::wstring, const TemplateURL*> KeywordToTemplateMap;
typedef std::vector<const TemplateURL*> TemplateURLVector;
- typedef std::set<const TemplateURL*> TemplateURLSet;
- typedef std::map<std::string, TemplateURLSet> HostToURLsMap;
// Helper functor for FindMatchingKeywords(), for finding the range of
// keywords which begin with a prefix.
@@ -260,27 +253,24 @@ class TemplateURLModel : public WebDataServiceConsumer,
void RemoveFromMaps(const TemplateURL* template_url);
- // Removes the supplied template_url from the maps. This searches through all
- // entries in the maps and does not generate the host or keyword.
- // This is used when the cached content of the TemplateURL changes.
- void RemoveFromMapsByPointer(const TemplateURL* template_url);
+ // Removes the supplied template_url from the keyword maps. This searches
+ // through all entries in the keyword map and does not generate the host or
+ // keyword. This is used when the cached content of the TemplateURL changes.
+ void RemoveFromKeywordMapByPointer(const TemplateURL* template_url);
void AddToMaps(const TemplateURL* template_url);
// Sets the keywords. This is used once the keywords have been loaded.
// This does NOT notify the delegate or the database.
- void SetTemplateURLs(const std::vector<const TemplateURL*>& urls);
+ void SetTemplateURLs(const std::vector<TemplateURL*>& urls);
- void DeleteGeneratedKeywordsMatchingHost(const std::wstring& host);
+ // Transitions to the loaded state.
+ void ChangeToLoadedState();
// If there is a notification service, sends TEMPLATE_URL_MODEL_LOADED
// notification.
void NotifyLoaded();
- // Loads engines from prepopulate data and merges them in with the existing
- // engines. This is invoked when the version of the prepopulate data changes.
- void MergeEnginesFromPrepopulateData();
-
// Saves enough of url to preferences so that it can be loaded from
// preferences on start up.
void SaveDefaultSearchProviderToPrefs(const TemplateURL* url);
@@ -307,6 +297,11 @@ class TemplateURLModel : public WebDataServiceConsumer,
// in the default list and is marked as safe_for_autoreplace.
bool CanReplace(const TemplateURL* t_url);
+ // Updates the information in |existing_turl| using the information from
+ // |new_values|, but the ID for |existing_turl| is retained.
+ void Update(const TemplateURL* existing_turl,
+ const TemplateURL& new_values);
+
// Returns the preferences we use.
PrefService* GetPrefs();
@@ -342,7 +337,7 @@ class TemplateURLModel : public WebDataServiceConsumer,
ObserverList<TemplateURLModelObserver> model_observers_;
// Maps from host to set of TemplateURLs whose search url host is host.
- HostToURLsMap host_to_urls_map_;
+ SearchHostToURLsMap provider_map_;
// Used to obtain the WebDataService.
// When Load is invoked, if we haven't yet loaded, the WebDataService is
@@ -361,13 +356,6 @@ class TemplateURLModel : public WebDataServiceConsumer,
// Service used to store entries.
scoped_refptr<WebDataService> service_;
- // List of hosts to feed to DeleteGeneratedKeywordsMatchingHost. When
- // we receive NOTIFY_HOST_DELETED_FROM_HISTORY if we haven't loaded yet,
- // we force a load and add the host to hosts_to_delete_. When done loading
- // we invoke DeleteGeneratedKeywordsMatchingHost with all the elements of
- // the vector.
- std::vector<std::wstring> hosts_to_delete_;
-
// All visits that occurred before we finished loading. Once loaded
// UpdateKeywordSearchTermsForURL is invoked for each element of the vector.
std::vector<history::URLVisitedDetails> visits_to_add_;
@@ -385,7 +373,7 @@ class TemplateURLModel : public WebDataServiceConsumer,
// ID assigned to next TemplateURL added to this model. This is an ever
// increasing integer that is initialized from the database.
- TemplateURL::IDType next_id_;
+ TemplateURLID next_id_;
// List of extension IDs waiting for Load to have keywords registered.
std::vector<std::string> pending_extension_ids_;
diff --git a/chrome/browser/search_engines/template_url_model_unittest.cc b/chrome/browser/search_engines/template_url_model_unittest.cc
index f393dcb..c97fb74 100644
--- a/chrome/browser/search_engines/template_url_model_unittest.cc
+++ b/chrome/browser/search_engines/template_url_model_unittest.cc
@@ -1,129 +1,116 @@
-// 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.
#include "base/callback.h"
-#include "base/path_service.h"
+#include "base/scoped_vector.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/ref_counted.h"
#include "base/thread.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_notifications.h"
+#include "chrome/browser/search_engines/search_host_to_urls_map.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_model.h"
+#include "chrome/browser/search_engines/template_url_model_test_util.h"
+#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
using base::TimeDelta;
-// A Task used to coordinate when the database has finished processing
-// requests. See note in BlockTillServiceProcessesRequests for details.
-//
-// When Run() schedules a QuitTask on the message loop it was created with.
-class QuitTask2 : public Task {
- public:
- QuitTask2() : main_loop_(MessageLoop::current()) {}
-
- virtual void Run() {
- main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- }
+#if defined(OS_LINUX)
+// Timed out on Chromium Linux. http://crbug.com/53607
+#define MAYBE_Load DISABLED_Load
+#else
+#define MAYBE_Load Load
+#endif
- private:
- MessageLoop* main_loop_;
-};
-
-// Subclass the TestingProfile so that it can return a WebDataService.
-class TemplateURLModelTestingProfile : public TestingProfile {
+// Test the GenerateSearchURL on a thread or the main thread.
+class TestGenerateSearchURL :
+ public base::RefCountedThreadSafe<TestGenerateSearchURL> {
public:
- TemplateURLModelTestingProfile() : TestingProfile() {}
-
- void SetUp() {
- db_thread_.reset(new ChromeThread(ChromeThread::DB));
- db_thread_->Start();
-
- // Name a subdirectory of the temp directory.
- ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
- test_dir_ = test_dir_.AppendASCII("TemplateURLModelTest");
-
- // Create a fresh, empty copy of this directory.
- file_util::Delete(test_dir_, true);
- file_util::CreateDirectory(test_dir_);
-
- FilePath path = test_dir_.AppendASCII("TestDataService.db");
- service_ = new WebDataService;
- EXPECT_TRUE(service_->InitWithPath(path));
+ explicit TestGenerateSearchURL(SearchTermsData* search_terms_data)
+ : search_terms_data_(search_terms_data),
+ passed_(false) {
}
- void TearDown() {
- // Clean up the test directory.
- service_->Shutdown();
- // Note that we must ensure the DB thread is stopped after WDS
- // shutdown (so it can commit pending transactions) but before
- // deleting the test profile directory, otherwise we may not be
- // able to delete it due to an open transaction.
- db_thread_->Stop();
-
- ASSERT_TRUE(file_util::Delete(test_dir_, true));
- ASSERT_FALSE(file_util::PathExists(test_dir_));
- }
+ // Run the test cases for GenerateSearchURL.
+ void RunTest();
- virtual WebDataService* GetWebDataService(ServiceAccessType access) {
- return service_.get();
- }
+ // Did the test pass?
+ bool passed() const { return passed_; }
private:
- scoped_refptr<WebDataService> service_;
- FilePath test_dir_;
- scoped_ptr<ChromeThread> db_thread_;
+ friend class base::RefCountedThreadSafe<TestGenerateSearchURL>;
+ ~TestGenerateSearchURL() {}
+
+ SearchTermsData* search_terms_data_;
+ bool passed_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestGenerateSearchURL);
};
-// Trivial subclass of TemplateURLModel that records the last invocation of
-// SetKeywordSearchTermsForURL.
-class TestingTemplateURLModel : public TemplateURLModel {
+// Simple implementation of SearchTermsData.
+class TestSearchTermsData : public SearchTermsData {
public:
- explicit TestingTemplateURLModel(Profile* profile)
- : TemplateURLModel(profile) {
+ explicit TestSearchTermsData(const char* google_base_url)
+ : google_base_url_(google_base_url) {
}
- std::wstring GetAndClearSearchTerm() {
- std::wstring search_term;
- search_term.swap(search_term_);
- return search_term;
+ virtual std::string GoogleBaseURLValue() const {
+ return google_base_url_;
}
- protected:
- virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
- const GURL& url,
- const std::wstring& term) {
- search_term_ = term;
+ virtual std::string GetApplicationLocale() const {
+ return "yy";
}
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+ // Returns the value for the Chrome Omnibox rlz.
+ virtual std::wstring GetRlzParameterValue() const {
+ return std::wstring();
+ }
+#endif
+
private:
- std::wstring search_term_;
+ std::string google_base_url_;
- DISALLOW_COPY_AND_ASSIGN(TestingTemplateURLModel);
+ DISALLOW_COPY_AND_ASSIGN(TestSearchTermsData);
};
-class TemplateURLModelTest : public testing::Test,
- public TemplateURLModelObserver {
+// Create an URL that appears to have been prepopulated, but won't be in the
+// current data. The caller owns the returned TemplateURL*.
+static TemplateURL* CreatePreloadedTemplateURL() {
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL("http://www.unittest.com/", 0, 0);
+ t_url->set_keyword(L"unittest");
+ t_url->set_short_name(L"unittest");
+ t_url->set_safe_for_autoreplace(true);
+ GURL favicon_url("http://favicon.url");
+ t_url->SetFavIconURL(favicon_url);
+ t_url->set_date_created(Time::FromTimeT(100));
+ t_url->set_prepopulate_id(999999);
+ return t_url;
+}
+
+class TemplateURLModelTest : public testing::Test {
public:
- TemplateURLModelTest() : ui_thread_(ChromeThread::UI, &message_loop_),
- changed_count_(0) {
- }
+ TemplateURLModelTest() {}
virtual void SetUp() {
- profile_.reset(new TemplateURLModelTestingProfile());
- profile_->SetUp();
- model_.reset(new TestingTemplateURLModel(profile_.get()));
- model_->AddObserver(this);
+ test_util_.SetUp();
}
virtual void TearDown() {
- profile_->TearDown();
- delete TemplateURLRef::google_base_url_;
- TemplateURLRef::google_base_url_ = NULL;
-
- // Flush the message loop to make Purify happy.
- message_loop_.RunAllPending();
+ test_util_.TearDown();
}
TemplateURL* AddKeywordWithDate(const std::wstring& keyword,
@@ -139,49 +126,11 @@ class TemplateURLModelTest : public testing::Test,
template_url->set_short_name(short_name);
template_url->set_date_created(created_date);
template_url->set_safe_for_autoreplace(safe_for_autoreplace);
- model_->Add(template_url);
+ model()->Add(template_url);
EXPECT_NE(0, template_url->id());
return template_url;
}
- virtual void OnTemplateURLModelChanged() {
- changed_count_++;
- }
-
- void VerifyObserverCount(int expected_changed_count) {
- ASSERT_EQ(expected_changed_count, changed_count_);
- changed_count_ = 0;
- }
-
- // Blocks the caller until the service has finished servicing all pending
- // requests.
- void BlockTillServiceProcessesRequests() {
- // Schedule a task on the DB thread that is processed after all
- // pending requests on the DB thread.
- ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new QuitTask2());
- // Run the current message loop. QuitTask2, when run, invokes Quit,
- // which unblocks this.
- MessageLoop::current()->Run();
- }
-
- // Makes sure the load was successful and sent the correct notification.
- void VerifyLoad() {
- ASSERT_FALSE(model_->loaded());
- model_->Load();
- BlockTillServiceProcessesRequests();
- VerifyObserverCount(1);
- changed_count_ = 0;
- }
-
- // Creates a new TemplateURLModel.
- void ResetModel(bool verify_load) {
- model_.reset(new TestingTemplateURLModel(profile_.get()));
- model_->AddObserver(this);
- changed_count_ = 0;
- if (verify_load)
- VerifyLoad();
- }
-
// Verifies the two TemplateURLs are equal.
void AssertEquals(const TemplateURL& expected, const TemplateURL& actual) {
ASSERT_EQ(expected.url()->url(), actual.url()->url());
@@ -194,32 +143,148 @@ class TemplateURLModelTest : public testing::Test,
ASSERT_TRUE(expected.date_created() == actual.date_created());
}
+ // Creates a TemplateURL with the same prepopluated id as a real prepopulated
+ // item. The input number determines which prepopulated item. The caller is
+ // responsible for owning the returned TemplateURL*.
+ TemplateURL* CreateReplaceablePreloadedTemplateURL(
+ size_t index_offset_from_default,
+ std::wstring* prepopulated_display_url);
+
+ // Verifies the behavior of when a preloaded url later gets changed.
+ // Since the input is the offset from the default, when one passes in
+ // 0, it tests the default. Passing in a number > 0 will verify what
+ // happens when a preloaded url that is not the default gets updated.
+ void TestLoadUpdatingPreloadedURL(size_t index_offset_from_default);
+
+ // 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);
+ }
+ void BlockTillServiceProcessesRequests() {
+ test_util_.BlockTillServiceProcessesRequests();
+ }
+ void VerifyLoad() { test_util_.VerifyLoad(); }
+ void ChangeModelToLoadState() { test_util_.ChangeModelToLoadState(); }
+ void ResetModel(bool verify_load) { test_util_.ResetModel(verify_load); }
std::wstring GetAndClearSearchTerm() {
- return model_->GetAndClearSearchTerm();
+ return test_util_.GetAndClearSearchTerm();
}
-
void SetGoogleBaseURL(const std::string& base_url) const {
- delete TemplateURLRef::google_base_url_;
- TemplateURLRef::google_base_url_ = new std::string(base_url);
+ test_util_.SetGoogleBaseURL(base_url);
}
+ WebDataService* GetWebDataService() { return test_util_.GetWebDataService(); }
+ TemplateURLModel* model() { return test_util_.model(); }
+ TestingProfile* profile() { return test_util_.profile(); }
+
+ protected:
+ TemplateURLModelTestUtil test_util_;
- MessageLoopForUI message_loop_;
- // Needed to make the DeleteOnUIThread trait of WebDataService work
- // properly.
- ChromeThread ui_thread_;
- scoped_ptr<TemplateURLModelTestingProfile> profile_;
- scoped_ptr<TestingTemplateURLModel> model_;
- int changed_count_;
+ DISALLOW_COPY_AND_ASSIGN(TemplateURLModelTest);
};
-TEST_F(TemplateURLModelTest, Load) {
+void TestGenerateSearchURL::RunTest() {
+ struct GenerateSearchURLCase {
+ const char* test_name;
+ const char* url;
+ const char* expected;
+ } generate_url_cases[] = {
+ { "empty TemplateURLRef", NULL, "" },
+ { "invalid URL", "foo{searchTerms}", "" },
+ { "URL with no replacements", "http://foo/", "http://foo/" },
+ { "basic functionality", "http://foo/{searchTerms}",
+ "http://foo/blah.blah.blah.blah.blah" }
+ };
+
+ // Don't use ASSERT/EXPECT since this is run on a thread in one test
+ // and those macros aren't meant for threads at this time according to
+ // gtest documentation.
+ bool everything_passed = true;
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(generate_url_cases); ++i) {
+ TemplateURL t_url;
+ if (generate_url_cases[i].url)
+ t_url.SetURL(generate_url_cases[i].url, 0, 0);
+
+ std::string result = search_terms_data_ ?
+ TemplateURLModel::GenerateSearchURLUsingTermsData(
+ &t_url, *search_terms_data_).spec() :
+ TemplateURLModel::GenerateSearchURL(&t_url).spec();
+ if (strcmp(generate_url_cases[i].expected, result.c_str())) {
+ LOG(ERROR) << generate_url_cases[i].test_name << " failed. Expected " <<
+ generate_url_cases[i].expected << " Actual " << result;
+
+ everything_passed = false;
+ }
+ }
+ passed_ = everything_passed;
+}
+
+TemplateURL* TemplateURLModelTest::CreateReplaceablePreloadedTemplateURL(
+ size_t index_offset_from_default,
+ std::wstring* prepopulated_display_url) {
+ TemplateURL* t_url = CreatePreloadedTemplateURL();
+ ScopedVector<TemplateURL> prepopulated_urls;
+ size_t default_search_provider_index = 0;
+ TemplateURLPrepopulateData::GetPrepopulatedEngines(
+ profile()->GetPrefs(),
+ &prepopulated_urls.get(),
+ &default_search_provider_index);
+ EXPECT_LT(index_offset_from_default, prepopulated_urls.size());
+ size_t prepopulated_index =
+ (default_search_provider_index + index_offset_from_default) %
+ prepopulated_urls.size();
+ t_url->set_prepopulate_id(
+ prepopulated_urls[prepopulated_index]->prepopulate_id());
+ *prepopulated_display_url =
+ prepopulated_urls[prepopulated_index]->url()->DisplayURL();
+ return t_url;
+}
+
+void TemplateURLModelTest::TestLoadUpdatingPreloadedURL(
+ size_t index_offset_from_default) {
+ std::wstring prepopulated_url;
+ TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
+ index_offset_from_default, &prepopulated_url);
+ t_url->set_safe_for_autoreplace(false);
+
+ std::wstring original_url = t_url->url()->DisplayURL();
+ ASSERT_STRNE(prepopulated_url.c_str(), original_url.c_str());
+
+ // Then add it to the model and save it all.
+ ChangeModelToLoadState();
+ model()->Add(t_url);
+ const TemplateURL* keyword_url =
+ model()->GetTemplateURLForKeyword(L"unittest");
+ ASSERT_EQ(t_url, keyword_url);
+ ASSERT_STREQ(original_url.c_str(), keyword_url->url()->DisplayURL().c_str());
+ BlockTillServiceProcessesRequests();
+
+ // Now reload the model and verify that the merge updates the url.
+ ResetModel(true);
+ keyword_url = model()->GetTemplateURLForKeyword(L"unittest");
+ ASSERT_TRUE(keyword_url != NULL);
+ ASSERT_STREQ(prepopulated_url.c_str(),
+ keyword_url->url()->DisplayURL().c_str());
+
+ // Wait for any saves to finish.
+ BlockTillServiceProcessesRequests();
+
+ // Reload the model to verify that change was saved correctly.
+ ResetModel(true);
+ keyword_url = model()->GetTemplateURLForKeyword(L"unittest");
+ ASSERT_TRUE(keyword_url != NULL);
+ ASSERT_STREQ(prepopulated_url.c_str(),
+ keyword_url->url()->DisplayURL().c_str());
+}
+
+TEST_F(TemplateURLModelTest, MAYBE_Load) {
VerifyLoad();
}
TEST_F(TemplateURLModelTest, AddUpdateRemove) {
// Add a new TemplateURL.
VerifyLoad();
- const size_t initial_count = model_->GetTemplateURLs().size();
+ const size_t initial_count = model()->GetTemplateURLs().size();
TemplateURL* t_url = new TemplateURL();
t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
@@ -229,47 +294,47 @@ TEST_F(TemplateURLModelTest, AddUpdateRemove) {
t_url->SetFavIconURL(favicon_url);
t_url->set_date_created(Time::FromTimeT(100));
t_url->set_safe_for_autoreplace(true);
- model_->Add(t_url);
- ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", GURL(), NULL));
+ model()->Add(t_url);
+ ASSERT_TRUE(model()->CanReplaceKeyword(L"keyword", GURL(), NULL));
VerifyObserverCount(1);
BlockTillServiceProcessesRequests();
// We need to clone as model takes ownership of TemplateURL and will
// delete it.
TemplateURL cloned_url(*t_url);
- ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
- ASSERT_TRUE(model_->GetTemplateURLForKeyword(t_url->keyword()) == t_url);
+ ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
+ ASSERT_TRUE(model()->GetTemplateURLForKeyword(t_url->keyword()) == t_url);
ASSERT_TRUE(t_url->date_created() == cloned_url.date_created());
// Reload the model to verify it was actually saved to the database.
ResetModel(true);
- ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
- const TemplateURL* loaded_url = model_->GetTemplateURLForKeyword(L"keyword");
+ ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
+ const TemplateURL* loaded_url = model()->GetTemplateURLForKeyword(L"keyword");
ASSERT_TRUE(loaded_url != NULL);
AssertEquals(cloned_url, *loaded_url);
- ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", GURL(), NULL));
+ ASSERT_TRUE(model()->CanReplaceKeyword(L"keyword", GURL(), NULL));
// Mutate an element and verify it succeeded.
- model_->ResetTemplateURL(loaded_url, L"a", L"b", "c");
+ model()->ResetTemplateURL(loaded_url, L"a", L"b", "c");
ASSERT_EQ(L"a", loaded_url->short_name());
ASSERT_EQ(L"b", loaded_url->keyword());
ASSERT_EQ("c", loaded_url->url()->url());
ASSERT_FALSE(loaded_url->safe_for_autoreplace());
- ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", GURL(), NULL));
- ASSERT_FALSE(model_->CanReplaceKeyword(L"b", GURL(), NULL));
+ ASSERT_TRUE(model()->CanReplaceKeyword(L"keyword", GURL(), NULL));
+ ASSERT_FALSE(model()->CanReplaceKeyword(L"b", GURL(), NULL));
cloned_url = *loaded_url;
BlockTillServiceProcessesRequests();
ResetModel(true);
- ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
- loaded_url = model_->GetTemplateURLForKeyword(L"b");
+ ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
+ loaded_url = model()->GetTemplateURLForKeyword(L"b");
ASSERT_TRUE(loaded_url != NULL);
AssertEquals(cloned_url, *loaded_url);
// Remove an element and verify it succeeded.
- model_->Remove(loaded_url);
+ model()->Remove(loaded_url);
VerifyObserverCount(1);
ResetModel(true);
- ASSERT_EQ(initial_count, model_->GetTemplateURLs().size());
- EXPECT_TRUE(model_->GetTemplateURLForKeyword(L"b") == NULL);
+ ASSERT_EQ(initial_count, model()->GetTemplateURLs().size());
+ EXPECT_TRUE(model()->GetTemplateURLForKeyword(L"b") == NULL);
}
TEST_F(TemplateURLModelTest, GenerateKeyword) {
@@ -293,13 +358,38 @@ TEST_F(TemplateURLModelTest, GenerateKeyword) {
true));
}
+TEST_F(TemplateURLModelTest, GenerateSearchURL) {
+ scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
+ new TestGenerateSearchURL(NULL));
+ test_generate_search_url->RunTest();
+ EXPECT_TRUE(test_generate_search_url->passed());
+}
+
+TEST_F(TemplateURLModelTest, GenerateSearchURLUsingTermsData) {
+ // Run the test for GenerateSearchURLUsingTermsData on the "IO" thread and
+ // wait for it to finish.
+ TestSearchTermsData search_terms_data("http://google.com/");
+ scoped_refptr<TestGenerateSearchURL> test_generate_search_url(
+ new TestGenerateSearchURL(&search_terms_data));
+
+ ChromeThread io_thread(ChromeThread::IO);
+ io_thread.Start();
+ io_thread.message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(test_generate_search_url.get(),
+ &TestGenerateSearchURL::RunTest));
+ test_util_.BlockTillIOThreadProcessesRequests();
+ EXPECT_TRUE(test_generate_search_url->passed());
+ io_thread.Stop();
+}
+
TEST_F(TemplateURLModelTest, ClearBrowsingData_Keywords) {
Time now = Time::Now();
TimeDelta one_day = TimeDelta::FromDays(1);
Time month_ago = now - TimeDelta::FromDays(30);
// Nothing has been added.
- EXPECT_EQ(0U, model_->GetTemplateURLs().size());
+ EXPECT_EQ(0U, model()->GetTemplateURLs().size());
// Create one with a 0 time.
AddKeywordWithDate(L"key1", false, "http://foo1", L"name1", true, Time());
@@ -315,42 +405,43 @@ TEST_F(TemplateURLModelTest, ClearBrowsingData_Keywords) {
month_ago);
// We just added a few items, validate them.
- EXPECT_EQ(6U, model_->GetTemplateURLs().size());
+ EXPECT_EQ(6U, model()->GetTemplateURLs().size());
// Try removing from current timestamp. This should delete the one in the
// future and one very recent one.
- model_->RemoveAutoGeneratedSince(now);
- EXPECT_EQ(4U, model_->GetTemplateURLs().size());
+ model()->RemoveAutoGeneratedSince(now);
+ EXPECT_EQ(4U, model()->GetTemplateURLs().size());
// Try removing from two months ago. This should only delete items that are
// auto-generated.
- model_->RemoveAutoGeneratedSince(now - TimeDelta::FromDays(60));
- EXPECT_EQ(3U, model_->GetTemplateURLs().size());
+ model()->RemoveAutoGeneratedSince(now - TimeDelta::FromDays(60));
+ EXPECT_EQ(3U, model()->GetTemplateURLs().size());
// Make sure the right values remain.
- EXPECT_EQ(L"key1", model_->GetTemplateURLs()[0]->keyword());
- EXPECT_TRUE(model_->GetTemplateURLs()[0]->safe_for_autoreplace());
- EXPECT_EQ(0U, model_->GetTemplateURLs()[0]->date_created().ToInternalValue());
+ EXPECT_EQ(L"key1", model()->GetTemplateURLs()[0]->keyword());
+ EXPECT_TRUE(model()->GetTemplateURLs()[0]->safe_for_autoreplace());
+ EXPECT_EQ(0U,
+ model()->GetTemplateURLs()[0]->date_created().ToInternalValue());
- EXPECT_EQ(L"key5", model_->GetTemplateURLs()[1]->keyword());
- EXPECT_FALSE(model_->GetTemplateURLs()[1]->safe_for_autoreplace());
+ EXPECT_EQ(L"key5", model()->GetTemplateURLs()[1]->keyword());
+ EXPECT_FALSE(model()->GetTemplateURLs()[1]->safe_for_autoreplace());
EXPECT_EQ(now.ToInternalValue(),
- model_->GetTemplateURLs()[1]->date_created().ToInternalValue());
+ model()->GetTemplateURLs()[1]->date_created().ToInternalValue());
- EXPECT_EQ(L"key6", model_->GetTemplateURLs()[2]->keyword());
- EXPECT_FALSE(model_->GetTemplateURLs()[2]->safe_for_autoreplace());
+ EXPECT_EQ(L"key6", model()->GetTemplateURLs()[2]->keyword());
+ EXPECT_FALSE(model()->GetTemplateURLs()[2]->safe_for_autoreplace());
EXPECT_EQ(month_ago.ToInternalValue(),
- model_->GetTemplateURLs()[2]->date_created().ToInternalValue());
+ model()->GetTemplateURLs()[2]->date_created().ToInternalValue());
// Try removing from Time=0. This should delete one more.
- model_->RemoveAutoGeneratedSince(Time());
- EXPECT_EQ(2U, model_->GetTemplateURLs().size());
+ model()->RemoveAutoGeneratedSince(Time());
+ EXPECT_EQ(2U, model()->GetTemplateURLs().size());
}
TEST_F(TemplateURLModelTest, Reset) {
// Add a new TemplateURL.
VerifyLoad();
- const size_t initial_count = model_->GetTemplateURLs().size();
+ const size_t initial_count = model()->GetTemplateURLs().size();
TemplateURL* t_url = new TemplateURL();
t_url->SetURL("http://www.google.com/foo/bar", 0, 0);
t_url->set_keyword(L"keyword");
@@ -358,7 +449,7 @@ TEST_F(TemplateURLModelTest, Reset) {
GURL favicon_url("http://favicon.url");
t_url->SetFavIconURL(favicon_url);
t_url->set_date_created(Time::FromTimeT(100));
- model_->Add(t_url);
+ model()->Add(t_url);
VerifyObserverCount(1);
BlockTillServiceProcessesRequests();
@@ -367,22 +458,22 @@ TEST_F(TemplateURLModelTest, Reset) {
const std::wstring new_short_name(L"a");
const std::wstring new_keyword(L"b");
const std::string new_url("c");
- model_->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
+ model()->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url);
ASSERT_EQ(new_short_name, t_url->short_name());
ASSERT_EQ(new_keyword, t_url->keyword());
ASSERT_EQ(new_url, t_url->url()->url());
// Make sure the mappings in the model were updated.
- ASSERT_TRUE(model_->GetTemplateURLForKeyword(new_keyword) == t_url);
- ASSERT_TRUE(model_->GetTemplateURLForKeyword(L"keyword") == NULL);
+ ASSERT_TRUE(model()->GetTemplateURLForKeyword(new_keyword) == t_url);
+ ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"keyword") == NULL);
TemplateURL last_url = *t_url;
// Reload the model from the database and make sure the change took.
ResetModel(true);
t_url = NULL;
- EXPECT_EQ(initial_count + 1, model_->GetTemplateURLs().size());
- const TemplateURL* read_url = model_->GetTemplateURLForKeyword(new_keyword);
+ EXPECT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
+ const TemplateURL* read_url = model()->GetTemplateURLForKeyword(new_keyword);
ASSERT_TRUE(read_url);
AssertEquals(last_url, *read_url);
}
@@ -390,14 +481,14 @@ TEST_F(TemplateURLModelTest, Reset) {
TEST_F(TemplateURLModelTest, DefaultSearchProvider) {
// Add a new TemplateURL.
VerifyLoad();
- const size_t initial_count = model_->GetTemplateURLs().size();
+ const size_t initial_count = model()->GetTemplateURLs().size();
TemplateURL* t_url = AddKeywordWithDate(L"key1", false, "http://foo1",
L"name1", true, Time());
- changed_count_ = 0;
- model_->SetDefaultSearchProvider(t_url);
+ test_util_.ResetObserverCount();
+ model()->SetDefaultSearchProvider(t_url);
- ASSERT_EQ(t_url, model_->GetDefaultSearchProvider());
+ ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
ASSERT_TRUE(t_url->safe_for_autoreplace());
ASSERT_TRUE(t_url->show_in_default_list());
@@ -413,30 +504,30 @@ TEST_F(TemplateURLModelTest, DefaultSearchProvider) {
t_url = NULL;
// Make sure when we reload we get a default search provider.
- EXPECT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
- ASSERT_TRUE(model_->GetDefaultSearchProvider());
- AssertEquals(cloned_url, *model_->GetDefaultSearchProvider());
+ EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
+ ASSERT_TRUE(model()->GetDefaultSearchProvider());
+ AssertEquals(cloned_url, *model()->GetDefaultSearchProvider());
}
TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) {
VerifyLoad();
- const size_t initial_count = model_->GetTemplateURLs().size();
+ const size_t initial_count = model()->GetTemplateURLs().size();
AddKeywordWithDate(std::wstring(), false, "http://foo1", L"name1", true,
Time());
// We just added a few items, validate them.
- ASSERT_EQ(initial_count + 1, model_->GetTemplateURLs().size());
+ ASSERT_EQ(initial_count + 1, model()->GetTemplateURLs().size());
// Reload the model from the database and make sure we get the url back.
ResetModel(true);
- ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size());
+ ASSERT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
bool found_keyword = false;
for (size_t i = 0; i < initial_count + 1; ++i) {
- if (model_->GetTemplateURLs()[i]->keyword().empty()) {
+ if (model()->GetTemplateURLs()[i]->keyword().empty()) {
found_keyword = true;
break;
}
@@ -445,45 +536,48 @@ TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) {
}
TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) {
- ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", GURL(), NULL));
+ ChangeModelToLoadState();
+ ASSERT_TRUE(model()->CanReplaceKeyword(L"foo", GURL(), NULL));
TemplateURL* t_url = AddKeywordWithDate(L"foo", false, "http://foo1",
L"name1", true, Time());
// Can still replace, newly added template url is marked safe to replace.
- ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", GURL("http://foo2"), NULL));
+ ASSERT_TRUE(model()->CanReplaceKeyword(L"foo", GURL("http://foo2"), NULL));
// ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
// no longer be replaceable.
- model_->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
+ model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
t_url->url()->url());
- ASSERT_FALSE(model_->CanReplaceKeyword(L"foo", GURL("http://foo2"), NULL));
+ ASSERT_FALSE(model()->CanReplaceKeyword(L"foo", GURL("http://foo2"), NULL));
}
TEST_F(TemplateURLModelTest, CantReplaceWithSameHosts) {
- ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", GURL("http://foo.com"), NULL));
+ ChangeModelToLoadState();
+ ASSERT_TRUE(model()->CanReplaceKeyword(L"foo", GURL("http://foo.com"), NULL));
TemplateURL* t_url = AddKeywordWithDate(L"foo", false, "http://foo.com",
L"name1", true, Time());
// Can still replace, newly added template url is marked safe to replace.
- ASSERT_TRUE(model_->CanReplaceKeyword(L"bar", GURL("http://foo.com"), NULL));
+ ASSERT_TRUE(model()->CanReplaceKeyword(L"bar", GURL("http://foo.com"), NULL));
// ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should
// no longer be replaceable.
- model_->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
+ model()->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(),
t_url->url()->url());
- ASSERT_FALSE(model_->CanReplaceKeyword(L"bar", GURL("http://foo.com"), NULL));
+ ASSERT_FALSE(model()->CanReplaceKeyword(L"bar",
+ GURL("http://foo.com"), NULL));
}
TEST_F(TemplateURLModelTest, HasDefaultSearchProvider) {
// We should have a default search provider even if we haven't loaded.
- ASSERT_TRUE(model_->GetDefaultSearchProvider());
+ ASSERT_TRUE(model()->GetDefaultSearchProvider());
// Now force the model to load and make sure we still have a default.
VerifyLoad();
- ASSERT_TRUE(model_->GetDefaultSearchProvider());
+ ASSERT_TRUE(model()->GetDefaultSearchProvider());
}
TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
@@ -496,11 +590,11 @@ TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
template_url->set_safe_for_autoreplace(true);
template_url->set_date_created(Time::FromTimeT(100));
- model_->Add(template_url);
+ model()->Add(template_url);
- const TemplateURL::IDType id = template_url->id();
+ const TemplateURLID id = template_url->id();
- model_->SetDefaultSearchProvider(template_url);
+ model()->SetDefaultSearchProvider(template_url);
BlockTillServiceProcessesRequests();
@@ -514,7 +608,7 @@ TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
// NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs
// value are persisted to prefs.
- const TemplateURL* default_turl = model_->GetDefaultSearchProvider();
+ const TemplateURL* default_turl = model()->GetDefaultSearchProvider();
ASSERT_TRUE(default_turl);
ASSERT_TRUE(default_turl->url());
ASSERT_EQ("http://url", default_turl->url()->url());
@@ -526,9 +620,9 @@ TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) {
// Now do a load and make sure the default search provider really takes.
VerifyLoad();
- ASSERT_TRUE(model_->GetDefaultSearchProvider());
+ ASSERT_TRUE(model()->GetDefaultSearchProvider());
AssertEquals(first_default_search_provider,
- *model_->GetDefaultSearchProvider());
+ *model()->GetDefaultSearchProvider());
}
TEST_F(TemplateURLModelTest, BuildQueryTerms) {
@@ -591,6 +685,7 @@ TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) {
{ "http://x/foo?q=b&q=xx", L"" },
};
+ ChangeModelToLoadState();
AddKeywordWithDate(L"x", false, "http://x/foo?q={searchTerms}", L"name",
false, Time());
@@ -598,7 +693,7 @@ TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) {
history::URLVisitedDetails details;
details.row = history::URLRow(GURL(data[i].url));
details.transition = 0;
- model_->UpdateKeywordSearchTermsForURL(details);
+ model()->UpdateKeywordSearchTermsForURL(details);
EXPECT_EQ(data[i].term, GetAndClearSearchTerm());
}
}
@@ -612,13 +707,14 @@ TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) {
{ "http://x/foo?y=xx" },
};
+ ChangeModelToLoadState();
AddKeywordWithDate(L"x", false, "http://x/foo", L"name", false, Time());
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
history::URLVisitedDetails details;
details.row = history::URLRow(GURL(data[i].url));
details.transition = 0;
- model_->UpdateKeywordSearchTermsForURL(details);
+ model()->UpdateKeywordSearchTermsForURL(details);
ASSERT_EQ(std::wstring(), GetAndClearSearchTerm());
}
}
@@ -627,23 +723,22 @@ TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) {
// NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data,
// which also has a {google:baseURL} keyword in it, which will confuse this
// test.
+ ChangeModelToLoadState();
SetGoogleBaseURL("http://google.com/");
const TemplateURL* t_url = AddKeywordWithDate(std::wstring(), true,
"{google:baseURL}?q={searchTerms}", L"name", false, Time());
- ASSERT_EQ(t_url, model_->GetTemplateURLForHost("google.com"));
+ ASSERT_EQ(t_url, model()->GetTemplateURLForHost("google.com"));
EXPECT_EQ("google.com", t_url->url()->GetHost());
EXPECT_EQ(L"google.com", t_url->keyword());
// Change the Google base url.
- model_->loaded_ = true; // Hack to make sure we get notified of the base URL
- // changing.
+ test_util_.ResetObserverCount();
SetGoogleBaseURL("http://foo.com/");
- model_->GoogleBaseURLChanged();
VerifyObserverCount(1);
// Make sure the host->TemplateURL map was updated appropriately.
- ASSERT_EQ(t_url, model_->GetTemplateURLForHost("foo.com"));
- EXPECT_TRUE(model_->GetTemplateURLForHost("google.com") == NULL);
+ ASSERT_EQ(t_url, model()->GetTemplateURLForHost("foo.com"));
+ EXPECT_TRUE(model()->GetTemplateURLForHost("google.com") == NULL);
EXPECT_EQ("foo.com", t_url->url()->GetHost());
EXPECT_EQ(L"foo.com", t_url->keyword());
EXPECT_EQ("http://foo.com/?q=x", t_url->url()->ReplaceSearchTerms(*t_url,
@@ -672,7 +767,7 @@ struct QueryHistoryCallbackImpl {
// KEYWORD visits.
TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
VerifyLoad();
- profile_->CreateHistoryService(true, false);
+ profile()->CreateHistoryService(true, false);
// Create a keyword.
TemplateURL* t_url = AddKeywordWithDate(
@@ -681,15 +776,15 @@ TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
// Add a visit that matches the url of the keyword.
HistoryService* history =
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
history->AddPage(
GURL(t_url->url()->ReplaceSearchTerms(*t_url, L"blah", 0,
std::wstring())),
NULL, 0, GURL(), PageTransition::KEYWORD, history::RedirectList(),
- false);
+ history::SOURCE_BROWSED, false);
// Wait for history to finish processing the request.
- profile_->BlockUntilHistoryProcessesPendingRequests();
+ profile()->BlockUntilHistoryProcessesPendingRequests();
// Query history for the generated url.
CancelableRequestConsumer consumer;
@@ -698,7 +793,7 @@ TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
NewCallback(&callback, &QueryHistoryCallbackImpl::Callback));
// Wait for the request to be processed.
- profile_->BlockUntilHistoryProcessesPendingRequests();
+ profile()->BlockUntilHistoryProcessesPendingRequests();
// And make sure the url and visit were added.
EXPECT_TRUE(callback.success);
@@ -708,52 +803,157 @@ TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
PageTransition::StripQualifier(callback.visits[0].transition));
}
-// Make sure that MergeEnginesFromPrepopulateData() deletes prepopulated engines
-// that no longer exist in the prepopulate data.
-TEST_F(TemplateURLModelTest, MergeDeletesUnusedProviders) {
- VerifyLoad();
+// Make sure that the load routine deletes prepopulated engines that no longer
+// exist in the prepopulate data.
+TEST_F(TemplateURLModelTest, LoadDeletesUnusedProvider) {
+ // Create a preloaded template url. Add it to a loaded model and wait for the
+ // saves to finish.
+ TemplateURL* t_url = CreatePreloadedTemplateURL();
+ ChangeModelToLoadState();
+ model()->Add(t_url);
+ ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") != NULL);
+ BlockTillServiceProcessesRequests();
- // Create an URL that appears to have been prepopulated but won't be in the
- // current data.
- TemplateURL* t_url = new TemplateURL();
- t_url->SetURL("http://www.unittest.com/", 0, 0);
- t_url->set_keyword(L"unittest");
- t_url->set_short_name(L"unittest");
- t_url->set_safe_for_autoreplace(true);
- GURL favicon_url("http://favicon.url");
- t_url->SetFavIconURL(favicon_url);
- t_url->set_date_created(Time::FromTimeT(100));
- t_url->set_prepopulate_id(999999);
+ // Ensure that merging clears this engine.
+ ResetModel(true);
+ ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") == NULL);
- // Make a few copies now, since as we add each to the model it takes ownership
- // of them and deletes them when finished.
- TemplateURL* t_url2 = new TemplateURL(*t_url);
- TemplateURL* t_url3 = new TemplateURL(*t_url);
+ // Wait for any saves to finish.
+ BlockTillServiceProcessesRequests();
- // Ensure that merging clears this engine.
- model_->Add(t_url);
- EXPECT_EQ(t_url, model_->GetTemplateURLForKeyword(L"unittest"));
- model_->MergeEnginesFromPrepopulateData();
- ASSERT_TRUE(model_->GetTemplateURLForKeyword(L"unittest") == NULL);
+ // Reload the model to verify that the database was updated as a result of the
+ // merge.
+ ResetModel(true);
+ ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") == NULL);
+}
+
+// Make sure that load routine doesn't delete prepopulated engines that no
+// longer exist in the prepopulate data if it has been modified by the user.
+TEST_F(TemplateURLModelTest, LoadRetainsModifiedProvider) {
+ // Create a preloaded template url and add it to a loaded model.
+ TemplateURL* t_url = CreatePreloadedTemplateURL();
+ t_url->set_safe_for_autoreplace(false);
+ ChangeModelToLoadState();
+ model()->Add(t_url);
+
+ // Do the copy after t_url is added so that the id is set.
+ TemplateURL copy_t_url = *t_url;
+ ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(L"unittest"));
+
+ // Wait for any saves to finish.
+ BlockTillServiceProcessesRequests();
// Ensure that merging won't clear it if the user has edited it.
- t_url2->set_safe_for_autoreplace(false);
- model_->Add(t_url2);
- ASSERT_EQ(t_url2, model_->GetTemplateURLForKeyword(L"unittest"));
- model_->MergeEnginesFromPrepopulateData();
- ASSERT_FALSE(model_->GetTemplateURLForKeyword(L"unittest") == NULL);
- model_->Remove(t_url2);
-
- // Ensure that merging won't clear it if it's the default engine.
- model_->Add(t_url3);
- ASSERT_EQ(t_url3, model_->GetTemplateURLForKeyword(L"unittest"));
- model_->SetDefaultSearchProvider(t_url3);
- ASSERT_EQ(t_url3, model_->GetDefaultSearchProvider());
- model_->MergeEnginesFromPrepopulateData();
- ASSERT_EQ(t_url3, model_->GetTemplateURLForKeyword(L"unittest"));
- ASSERT_EQ(t_url3, model_->GetDefaultSearchProvider());
- // Don't remove |t_url3|; we'd need to make it non-default first, and why
- // bother when the model shutdown will clean it up for us.
+ ResetModel(true);
+ const TemplateURL* url_for_unittest =
+ model()->GetTemplateURLForKeyword(L"unittest");
+ ASSERT_TRUE(url_for_unittest != NULL);
+ AssertEquals(copy_t_url, *url_for_unittest);
+
+ // Wait for any saves to finish.
+ BlockTillServiceProcessesRequests();
+
+ // Reload the model to verify that save/reload retains the item.
+ ResetModel(true);
+ ASSERT_TRUE(model()->GetTemplateURLForKeyword(L"unittest") != NULL);
+}
+
+// Make sure that load routine doesn't delete
+// prepopulated engines that no longer exist in the prepopulate data if
+// it has been modified by the user.
+TEST_F(TemplateURLModelTest, LoadSavesPrepopulatedDefaultSearchProvider) {
+ VerifyLoad();
+ // Verify that the default search provider is set to something.
+ ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
+ TemplateURL default_url = *model()->GetDefaultSearchProvider();
+
+ // Wait for any saves to finish.
+ BlockTillServiceProcessesRequests();
+
+ // Reload the model and check that the default search provider
+ // was properly saved.
+ ResetModel(true);
+ ASSERT_TRUE(model()->GetDefaultSearchProvider() != NULL);
+ AssertEquals(default_url, *model()->GetDefaultSearchProvider());
+}
+
+// Make sure that the load routine doesn't delete
+// prepopulated engines that no longer exist in the prepopulate data if
+// it is the default search provider.
+TEST_F(TemplateURLModelTest, LoadRetainsDefaultProvider) {
+ // Set the default search provider to a preloaded template url which
+ // is not in the current set of preloaded template urls and save
+ // the result.
+ TemplateURL* t_url = CreatePreloadedTemplateURL();
+ ChangeModelToLoadState();
+ model()->Add(t_url);
+ model()->SetDefaultSearchProvider(t_url);
+ // Do the copy after t_url is added and set as default so that its
+ // internal state is correct.
+ TemplateURL copy_t_url = *t_url;
+
+ ASSERT_EQ(t_url, model()->GetTemplateURLForKeyword(L"unittest"));
+ ASSERT_EQ(t_url, model()->GetDefaultSearchProvider());
+ BlockTillServiceProcessesRequests();
+
+ // Ensure that merging won't clear the prepopulated template url
+ // which is no longer present if it's the default engine.
+ ResetModel(true);
+ {
+ const TemplateURL* keyword_url =
+ model()->GetTemplateURLForKeyword(L"unittest");
+ ASSERT_TRUE(keyword_url != NULL);
+ AssertEquals(copy_t_url, *keyword_url);
+ ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
+ }
+
+ // Wait for any saves to finish.
+ BlockTillServiceProcessesRequests();
+
+ // Reload the model to verify that the update was saved.
+ ResetModel(true);
+ {
+ const TemplateURL* keyword_url =
+ model()->GetTemplateURLForKeyword(L"unittest");
+ ASSERT_TRUE(keyword_url != NULL);
+ AssertEquals(copy_t_url, *keyword_url);
+ ASSERT_EQ(keyword_url, model()->GetDefaultSearchProvider());
+ }
+}
+
+// Make sure that the load routine updates the url of a preexisting
+// default search engine provider and that the result is saved correctly.
+TEST_F(TemplateURLModelTest, LoadUpdatesDefaultSearchURL) {
+ TestLoadUpdatingPreloadedURL(0);
+}
+
+// Make sure that the load routine updates the url of a preexisting
+// non-default search engine provider and that the result is saved correctly.
+TEST_F(TemplateURLModelTest, LoadUpdatesSearchURL) {
+ TestLoadUpdatingPreloadedURL(1);
+}
+
+// Make sure that the load does update of auto-keywords correctly.
+// This test basically verifies that no asserts or crashes occur
+// during this operation.
+TEST_F(TemplateURLModelTest, LoadDoesAutoKeywordUpdate) {
+ std::wstring prepopulated_url;
+ TemplateURL* t_url = CreateReplaceablePreloadedTemplateURL(
+ 0, &prepopulated_url);
+ t_url->set_safe_for_autoreplace(false);
+ t_url->SetURL("{google:baseURL}?q={searchTerms}", 0, 0);
+ t_url->set_autogenerate_keyword(true);
+
+ // Then add it to the model and save it all.
+ ChangeModelToLoadState();
+ model()->Add(t_url);
+ BlockTillServiceProcessesRequests();
+
+ // Now reload the model and verify that the merge updates the url.
+ ResetModel(true);
+
+ // Wait for any saves to finish.
+ BlockTillServiceProcessesRequests();
}
// Simulates failing to load the webdb and makes sure the default search
@@ -761,14 +961,25 @@ TEST_F(TemplateURLModelTest, MergeDeletesUnusedProviders) {
TEST_F(TemplateURLModelTest, FailedInit) {
VerifyLoad();
- model_.reset(NULL);
-
- profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->UnloadDatabase();
- profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->set_failed_init(true);
+ test_util_.ClearModel();
+ test_util_.GetWebDataService()->UnloadDatabase();
+ test_util_.GetWebDataService()->set_failed_init(true);
ResetModel(false);
- model_->Load();
+ model()->Load();
BlockTillServiceProcessesRequests();
- ASSERT_TRUE(model_->GetDefaultSearchProvider());
+ ASSERT_TRUE(model()->GetDefaultSearchProvider());
+}
+
+// Verifies that if the default search URL preference is managed, we report
+// the default search as managed.
+TEST_F(TemplateURLModelTest, ReportDefaultSearchIsManaged) {
+ TestingPrefService* service = profile()->GetTestingPrefService();
+ service->RegisterStringPref(prefs::kDefaultSearchProviderSearchURL,
+ std::string());
+ service->SetManagedPref(prefs::kDefaultSearchProviderSearchURL,
+ Value::CreateStringValue("http://test.com/{searchTerms}"));
+ ASSERT_TRUE(model()->IsDefaultSearchManaged());
}
+
diff --git a/chrome/browser/search_engines/template_url_parser.cc b/chrome/browser/search_engines/template_url_parser.cc
index 06948cb..245ca3f 100644
--- a/chrome/browser/search_engines/template_url_parser.cc
+++ b/chrome/browser/search_engines/template_url_parser.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/search_engines/template_url.h"
@@ -313,11 +314,11 @@ void ParseURL(const xmlChar** atts, ParsingContext* context) {
} else if (name == kURLTemplateAttribute) {
template_url = XMLCharToString(value);
} else if (name == kURLIndexOffsetAttribute) {
- index_offset =
- std::max(1, StringToInt(WideToUTF16Hack(XMLCharToWide(value))));
+ base::StringToInt(XMLCharToString(value), &index_offset);
+ index_offset = std::max(1, index_offset);
} else if (name == kURLPageOffsetAttribute) {
- page_offset =
- std::max(1, StringToInt(WideToUTF16Hack(XMLCharToWide(value))));
+ base::StringToInt(XMLCharToString(value), &page_offset);
+ page_offset = std::max(1, page_offset);
} else if (name == kParamMethodAttribute) {
is_post = LowerCaseEqualsASCII(XMLCharToString(value), "post");
}
@@ -350,9 +351,9 @@ void ParseImage(const xmlChar** atts, ParsingContext* context) {
if (name == kImageTypeAttribute) {
type = XMLCharToWide(value);
} else if (name == kImageWidthAttribute) {
- width = StringToInt(WideToUTF16Hack(XMLCharToWide(value)));
+ base::StringToInt(XMLCharToString(value), &width);
} else if (name == kImageHeightAttribute) {
- height = StringToInt(WideToUTF16Hack(XMLCharToWide(value)));
+ base::StringToInt(XMLCharToString(value), &height);
}
attributes += 2;
}
diff --git a/chrome/browser/search_engines/template_url_parser.h b/chrome/browser/search_engines/template_url_parser.h
index 412544a..d978da5 100644
--- a/chrome/browser/search_engines/template_url_parser.h
+++ b/chrome/browser/search_engines/template_url_parser.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_PARSER_H_
#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_PARSER_H_
+#pragma once
#include <string>
@@ -21,6 +22,9 @@ class TemplateURLParser {
// methods returns false, the parameter is not included.
virtual bool KeepParameter(const std::string& key,
const std::string& value) = 0;
+
+ protected:
+ virtual ~ParameterFilter() {}
};
// Decodes the chunk of data representing a TemplateURL. If data does
// not describe a valid TemplateURL false is returned. Additionally, if the
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc
index 67a5342..7b745bd 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data.cc
@@ -4,17 +4,19 @@
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
-#if defined(OS_LINUX)
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
#include <locale.h>
#endif
#include "base/command_line.h"
+#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
+#include "grit/theme_resources.h"
#if defined(OS_WIN)
#undef IN // On Windows, windef.h defines this, which screws up "India" cases.
@@ -43,6 +45,9 @@ struct PrepopulatedEngine {
const char* const encoding;
const wchar_t* const suggest_url; // If NULL, this engine does not support
// suggestions.
+ // TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER if no logo is available.
+ const TemplateURLPrepopulateData::SearchEngineType search_engine_type;
+ const int logo_id; // Id for logo image in search engine dialog.
// Unique id for this prepopulate engine (corresponds to
// TemplateURL::prepopulate_id). This ID must be greater than zero and must
// remain the same for a particular site regardless of how the url changes;
@@ -76,6 +81,8 @@ const PrepopulatedEngine abcsok = {
L"http://abcsok.no/index.html?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ABCSOK,
+ IDR_SEARCH_ENGINE_LOGO_ABCSOK,
72,
};
@@ -86,6 +93,8 @@ const PrepopulatedEngine altavista = {
L"http://www.altavista.com/web/results?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ALTAVISTA,
+ IDR_SEARCH_ENGINE_LOGO_ALTAVISTA,
89,
};
@@ -96,6 +105,8 @@ const PrepopulatedEngine altavista_ar = {
L"http://ar.altavista.com/web/results?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ALTAVISTA,
+ IDR_SEARCH_ENGINE_LOGO_ALTAVISTA,
89,
};
@@ -106,6 +117,8 @@ const PrepopulatedEngine altavista_se = {
L"http://se.altavista.com/web/results?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ALTAVISTA,
+ IDR_SEARCH_ENGINE_LOGO_ALTAVISTA,
89,
};
@@ -116,6 +129,8 @@ const PrepopulatedEngine aol = {
L"http://search.aol.com/aol/search?query={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
35,
};
@@ -126,6 +141,8 @@ const PrepopulatedEngine araby = {
L"http://araby.com/?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
12,
};
@@ -136,6 +153,8 @@ const PrepopulatedEngine ask = {
L"http://www.ask.com/web?q={searchTerms}",
"UTF-8",
L"http://ss.ask.com/query?q={searchTerms}&li=ff",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ASK,
+ IDR_SEARCH_ENGINE_LOGO_ASK,
4,
};
@@ -146,6 +165,8 @@ const PrepopulatedEngine ask_de = {
L"http://de.ask.com/web?q={searchTerms}",
"UTF-8",
L"http://ss.de.ask.com/query?q={searchTerms}&li=ff",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ASK,
+ IDR_SEARCH_ENGINE_LOGO_ASK,
4,
};
@@ -156,6 +177,8 @@ const PrepopulatedEngine ask_es = {
L"http://es.ask.com/web?q={searchTerms}",
"UTF-8",
L"http://ss.es.ask.com/query?q={searchTerms}&li=ff",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ASK,
+ IDR_SEARCH_ENGINE_LOGO_ASK,
4,
};
@@ -166,6 +189,8 @@ const PrepopulatedEngine ask_it = {
L"http://it.ask.com/web?q={searchTerms}",
"UTF-8",
L"http://ss.it.ask.com/query?q={searchTerms}&li=ff",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ASK,
+ IDR_SEARCH_ENGINE_LOGO_ASK,
4,
};
@@ -176,6 +201,8 @@ const PrepopulatedEngine ask_nl = {
L"http://nl.ask.com/web?q={searchTerms}",
"UTF-8",
L"http://ss.nl.ask.com/query?q={searchTerms}&li=ff",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ASK,
+ IDR_SEARCH_ENGINE_LOGO_ASK,
4,
};
@@ -186,6 +213,8 @@ const PrepopulatedEngine ask_uk = {
L"http://uk.ask.com/web?q={searchTerms}",
"UTF-8",
L"http://ss.uk.ask.com/query?q={searchTerms}&li=ff",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ASK,
+ IDR_SEARCH_ENGINE_LOGO_ASK,
4,
};
@@ -196,6 +225,8 @@ const PrepopulatedEngine atlas_cz = {
L"http://search.atlas.cz/?q={searchTerms}",
"windows-1250",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
27,
};
@@ -206,6 +237,8 @@ const PrepopulatedEngine atlas_sk = {
L"http://hladaj.atlas.sk/fulltext/?phrase={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
27,
};
@@ -216,6 +249,8 @@ const PrepopulatedEngine baidu = {
L"http://www.baidu.com/s?wd={searchTerms}",
"GB2312",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BAIDU,
+ IDR_SEARCH_ENGINE_LOGO_BAIDU,
21,
};
@@ -226,6 +261,8 @@ const PrepopulatedEngine bing = {
L"http://www.bing.com/search?q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -236,6 +273,8 @@ const PrepopulatedEngine bing_ar_XA = {
L"http://www.bing.com/search?setmkt=ar-XA&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
7, // Can't be 3 as this has to appear in the Arabian countries' lists
// alongside bing_en_XA.
};
@@ -247,6 +286,8 @@ const PrepopulatedEngine bing_bg_BG = {
L"http://www.bing.com/search?setmkt=bg-BG&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -257,6 +298,8 @@ const PrepopulatedEngine bing_cs_CZ = {
L"http://www.bing.com/search?setmkt=cs-CZ&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -267,6 +310,8 @@ const PrepopulatedEngine bing_da_DK = {
L"http://www.bing.com/search?setmkt=da-DK&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -277,6 +322,8 @@ const PrepopulatedEngine bing_de_AT = {
L"http://www.bing.com/search?setmkt=de-AT&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -287,6 +334,8 @@ const PrepopulatedEngine bing_de_CH = {
L"http://www.bing.com/search?setmkt=de-CH&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -297,6 +346,8 @@ const PrepopulatedEngine bing_de_DE = {
L"http://www.bing.com/search?setmkt=de-DE&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -307,6 +358,8 @@ const PrepopulatedEngine bing_el_GR = {
L"http://www.bing.com/search?setmkt=el-GR&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -317,6 +370,8 @@ const PrepopulatedEngine bing_en_AU = {
L"http://www.bing.com/search?setmkt=en-AU&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -327,6 +382,8 @@ const PrepopulatedEngine bing_en_CA = {
L"http://www.bing.com/search?setmkt=en-CA&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -337,6 +394,8 @@ const PrepopulatedEngine bing_en_GB = {
L"http://www.bing.com/search?setmkt=en-GB&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -347,6 +406,8 @@ const PrepopulatedEngine bing_en_ID = {
L"http://www.bing.com/search?setmkt=en-ID&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -357,6 +418,8 @@ const PrepopulatedEngine bing_en_IE = {
L"http://www.bing.com/search?setmkt=en-IE&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -367,6 +430,8 @@ const PrepopulatedEngine bing_en_IN = {
L"http://www.bing.com/search?setmkt=en-IN&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -377,6 +442,8 @@ const PrepopulatedEngine bing_en_MY = {
L"http://www.bing.com/search?setmkt=en-MY&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -387,6 +454,8 @@ const PrepopulatedEngine bing_en_NZ = {
L"http://www.bing.com/search?setmkt=en-NZ&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -397,6 +466,8 @@ const PrepopulatedEngine bing_en_PH = {
L"http://www.bing.com/search?setmkt=en-PH&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -407,6 +478,8 @@ const PrepopulatedEngine bing_en_SG = {
L"http://www.bing.com/search?setmkt=en-SG&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -417,6 +490,8 @@ const PrepopulatedEngine bing_en_US = {
L"http://www.bing.com/search?setmkt=en-US&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -427,6 +502,8 @@ const PrepopulatedEngine bing_en_XA = {
L"http://www.bing.com/search?setmkt=en-XA&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -437,6 +514,8 @@ const PrepopulatedEngine bing_en_ZA = {
L"http://www.bing.com/search?setmkt=en-ZA&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -447,6 +526,8 @@ const PrepopulatedEngine bing_es_AR = {
L"http://www.bing.com/search?setmkt=es-AR&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -457,6 +538,8 @@ const PrepopulatedEngine bing_es_CL = {
L"http://www.bing.com/search?setmkt=es-CL&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -467,6 +550,8 @@ const PrepopulatedEngine bing_es_ES = {
L"http://www.bing.com/search?setmkt=es-ES&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -477,6 +562,8 @@ const PrepopulatedEngine bing_es_MX = {
L"http://www.bing.com/search?setmkt=es-MX&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -487,6 +574,8 @@ const PrepopulatedEngine bing_es_XL = {
L"http://www.bing.com/search?setmkt=es-XL&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -497,6 +586,8 @@ const PrepopulatedEngine bing_et_EE = {
L"http://www.bing.com/search?setmkt=et-EE&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -507,6 +598,8 @@ const PrepopulatedEngine bing_fi_FI = {
L"http://www.bing.com/search?setmkt=fi-FI&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -517,6 +610,8 @@ const PrepopulatedEngine bing_fr_BE = {
L"http://www.bing.com/search?setmkt=fr-BE&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
7,
};
@@ -527,6 +622,8 @@ const PrepopulatedEngine bing_fr_CA = {
L"http://www.bing.com/search?setmkt=fr-CA&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
7,
};
@@ -537,6 +634,8 @@ const PrepopulatedEngine bing_fr_CH = {
L"http://www.bing.com/search?setmkt=fr-CH&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
7,
};
@@ -547,6 +646,8 @@ const PrepopulatedEngine bing_fr_FR = {
L"http://www.bing.com/search?setmkt=fr-FR&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -557,6 +658,8 @@ const PrepopulatedEngine bing_he_IL = {
L"http://www.bing.com/search?setmkt=he-IL&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -567,6 +670,8 @@ const PrepopulatedEngine bing_hr_HR = {
L"http://www.bing.com/search?setmkt=hr-HR&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -577,6 +682,8 @@ const PrepopulatedEngine bing_hu_HU = {
L"http://www.bing.com/search?setmkt=hu-HU&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -587,6 +694,8 @@ const PrepopulatedEngine bing_it_IT = {
L"http://www.bing.com/search?setmkt=it-IT&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -597,6 +706,8 @@ const PrepopulatedEngine bing_ja_JP = {
L"http://www.bing.com/search?setmkt=ja-JP&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -607,6 +718,8 @@ const PrepopulatedEngine bing_ko_KR = {
L"http://www.bing.com/search?setmkt=ko-KR&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -617,6 +730,8 @@ const PrepopulatedEngine bing_lt_LT = {
L"http://www.bing.com/search?setmkt=lt-LT&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -627,6 +742,8 @@ const PrepopulatedEngine bing_lv_LV = {
L"http://www.bing.com/search?setmkt=lv-LV&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -637,6 +754,8 @@ const PrepopulatedEngine bing_nb_NO = {
L"http://www.bing.com/search?setmkt=nb-NO&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -647,6 +766,8 @@ const PrepopulatedEngine bing_nl_BE = {
L"http://www.bing.com/search?setmkt=nl-BE&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -657,6 +778,8 @@ const PrepopulatedEngine bing_nl_NL = {
L"http://www.bing.com/search?setmkt=nl-NL&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -667,6 +790,8 @@ const PrepopulatedEngine bing_pl_PL = {
L"http://www.bing.com/search?setmkt=pl-PL&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -677,6 +802,8 @@ const PrepopulatedEngine bing_pt_BR = {
L"http://www.bing.com/search?setmkt=pt-BR&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -687,6 +814,8 @@ const PrepopulatedEngine bing_pt_PT = {
L"http://www.bing.com/search?setmkt=pt-PT&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -697,6 +826,8 @@ const PrepopulatedEngine bing_ro_RO = {
L"http://www.bing.com/search?setmkt=ro-RO&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -707,6 +838,8 @@ const PrepopulatedEngine bing_ru_RU = {
L"http://www.bing.com/search?setmkt=ru-RU&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -717,6 +850,8 @@ const PrepopulatedEngine bing_sl_SI = {
L"http://www.bing.com/search?setmkt=sl-SI&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -727,6 +862,8 @@ const PrepopulatedEngine bing_sk_SK = {
L"http://www.bing.com/search?setmkt=sk-SK&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -737,6 +874,8 @@ const PrepopulatedEngine bing_sv_SE = {
L"http://www.bing.com/search?setmkt=sv-SE&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -747,6 +886,8 @@ const PrepopulatedEngine bing_th_TH = {
L"http://www.bing.com/search?setmkt=th-TH&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -757,6 +898,8 @@ const PrepopulatedEngine bing_tr_TR = {
L"http://www.bing.com/search?setmkt=tr-TR&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -767,6 +910,8 @@ const PrepopulatedEngine bing_uk_UA = {
L"http://www.bing.com/search?setmkt=uk-UA&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -777,6 +922,8 @@ const PrepopulatedEngine bing_zh_CN = {
L"http://www.bing.com/search?setmkt=zh-CN&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -787,6 +934,8 @@ const PrepopulatedEngine bing_zh_HK = {
L"http://www.bing.com/search?setmkt=zh-HK&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -797,6 +946,8 @@ const PrepopulatedEngine bing_zh_TW = {
L"http://www.bing.com/search?setmkt=zh-TW&q={searchTerms}",
"UTF-8",
L"http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
+ IDR_SEARCH_ENGINE_LOGO_BING,
3,
};
@@ -807,6 +958,8 @@ const PrepopulatedEngine centrum_cz = {
L"http://search.centrum.cz/index.php?charset={inputEncoding}&q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_CENTRUM,
+ IDR_SEARCH_ENGINE_LOGO_CENTRUM,
26,
};
@@ -817,6 +970,8 @@ const PrepopulatedEngine centrum_sk = {
L"http://search.centrum.sk/index.php?charset={inputEncoding}&q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_CENTRUM,
+ IDR_SEARCH_ENGINE_LOGO_CENTRUM,
26,
};
@@ -826,7 +981,9 @@ const PrepopulatedEngine daum = {
"http://search.daum.net/favicon.ico",
L"http://search.daum.net/search?q={searchTerms}",
"EUC-KR",
- L"http://sug.search.daum.net/search_nsuggest?mod=fxjson&q={searchTerms}",
+ L"http://sug.search.daum.net/search_nsuggest?mod=fxjson&q={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_DAUM,
+ IDR_SEARCH_ENGINE_LOGO_DAUM,
68,
};
@@ -837,6 +994,8 @@ const PrepopulatedEngine delfi_lt = {
L"http://search.delfi.lt/search.php?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_DELFI,
+ IDR_SEARCH_ENGINE_LOGO_DELFI,
45,
};
@@ -847,6 +1006,8 @@ const PrepopulatedEngine delfi_lv = {
L"http://smart.delfi.lv/i.php?enc={inputEncoding}&q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_DELFI,
+ IDR_SEARCH_ENGINE_LOGO_DELFI,
45,
};
@@ -857,6 +1018,8 @@ const PrepopulatedEngine diri = {
L"http://diri.bg/search.php?textfield={searchTerms}",
"windows-1251",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_DIRI,
+ IDR_SEARCH_ENGINE_LOGO_DIRI,
32,
};
@@ -867,6 +1030,8 @@ const PrepopulatedEngine eniro_fi = {
L"http://eniro.fi/query?search_word={searchTerms}&what=web_local",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
29,
};
@@ -877,6 +1042,8 @@ const PrepopulatedEngine eniro_se = {
L"http://eniro.se/query?search_word={searchTerms}&what=web_local",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
29,
};
@@ -887,6 +1054,8 @@ const PrepopulatedEngine fonecta_02_fi = {
L"http://www.02.fi/haku/{searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
46,
};
@@ -898,6 +1067,8 @@ const PrepopulatedEngine go = {
L"fr=hsusgo1",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
40,
};
@@ -908,6 +1079,8 @@ const PrepopulatedEngine goo = {
L"http://search.goo.ne.jp/web.jsp?MT={searchTerms}&IE={inputEncoding}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_GOO,
+ IDR_SEARCH_ENGINE_LOGO_GOO,
23,
};
@@ -920,6 +1093,8 @@ const PrepopulatedEngine google = {
L"q={searchTerms}",
"UTF-8",
L"{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_GOOGLE,
+ IDR_SEARCH_ENGINE_LOGO_GOOGLE,
1,
};
@@ -930,6 +1105,8 @@ const PrepopulatedEngine guruji = {
L"http://guruji.com/search?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
38,
};
@@ -940,6 +1117,8 @@ const PrepopulatedEngine hispavista = {
L"http://buscar.hispavista.com/?cadena={searchTerms}",
"iso-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
18,
};
@@ -947,9 +1126,11 @@ const PrepopulatedEngine in = {
L"in.gr",
L"in.gr",
"http://www.in.gr/favicon.ico",
- L"http://find.in.gr/result.asp?q={searchTerms}",
+ L"http://find.in.gr/?qs={searchTerms}",
"ISO-8859-7",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_IN,
+ IDR_SEARCH_ENGINE_LOGO_IN,
54,
};
@@ -960,6 +1141,8 @@ const PrepopulatedEngine jabse = {
L"http://www.jabse.com/searchmachine.php?query={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
19,
};
@@ -970,6 +1153,8 @@ const PrepopulatedEngine jubii = {
L"http://search.jubii.dk/cgi-bin/pursuit?query={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
28,
};
@@ -980,6 +1165,8 @@ const PrepopulatedEngine kvasir = {
L"http://www.kvasir.no/nettsok/searchResult.html?searchExpr={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
73,
};
@@ -990,6 +1177,8 @@ const PrepopulatedEngine latne = {
L"http://latne.lv/siets.php?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
71,
};
@@ -1000,6 +1189,8 @@ const PrepopulatedEngine leit = {
L"http://leit.is/query.aspx?qt={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
59,
};
@@ -1010,6 +1201,8 @@ const PrepopulatedEngine libero = {
L"http://arianna.libero.it/search/abin/integrata.cgi?query={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
63,
};
@@ -1020,6 +1213,8 @@ const PrepopulatedEngine mail_ru = {
L"http://go.mail.ru/search?q={searchTerms}",
"windows-1251",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_MAILRU,
+ IDR_SEARCH_ENGINE_LOGO_MAILRU,
83,
};
@@ -1030,6 +1225,8 @@ const PrepopulatedEngine maktoob = {
L"http://www.maktoob.com/searchResult.php?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
13,
};
@@ -1040,6 +1237,8 @@ const PrepopulatedEngine masrawy = {
L"http://masrawy.com/new/search.aspx?sr={searchTerms}",
"windows-1256",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
14,
};
@@ -1050,6 +1249,8 @@ const PrepopulatedEngine mynet = {
L"http://arama.mynet.com/search.aspx?q={searchTerms}&pg=q",
"windows-1254",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
101,
};
@@ -1060,6 +1261,8 @@ const PrepopulatedEngine najdi = {
L"http://www.najdi.si/search.jsp?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_NAJDI,
+ IDR_SEARCH_ENGINE_LOGO_NAJDI,
87,
};
@@ -1070,6 +1273,8 @@ const PrepopulatedEngine nate = {
L"http://nate.search.empas.com/search/all.html?q={searchTerms}",
"EUC-KR",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
69,
};
@@ -1082,6 +1287,8 @@ const PrepopulatedEngine naver = {
"UTF-8",
L"http://ac.search.naver.com/autocompl?m=s&ie={inputEncoding}&oe=utf-8&"
L"q={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_NAVER,
+ IDR_SEARCH_ENGINE_LOGO_NAVER,
67,
};
@@ -1092,6 +1299,8 @@ const PrepopulatedEngine neti = {
L"http://www.neti.ee/cgi-bin/otsing?query={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_NETI,
+ IDR_SEARCH_ENGINE_LOGO_NETI,
44,
};
@@ -1102,6 +1311,8 @@ const PrepopulatedEngine netsprint = {
L"http://www.netsprint.pl/serwis/search?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_NETSPRINT,
+ IDR_SEARCH_ENGINE_LOGO_NETSPRINT,
30,
};
@@ -1112,6 +1323,8 @@ const PrepopulatedEngine nur_kz = {
L"http://search.nur.kz/?encoding={inputEncoding}&query={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
20,
};
@@ -1122,6 +1335,8 @@ const PrepopulatedEngine ok = {
L"http://ok.hu/katalogus?q={searchTerms}",
"ISO-8859-2",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OK,
+ IDR_SEARCH_ENGINE_LOGO_OK,
6,
};
@@ -1132,6 +1347,8 @@ const PrepopulatedEngine onet = {
L"http://szukaj.onet.pl/query.html?qt={searchTerms}",
"ISO-8859-2",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
75,
};
@@ -1142,6 +1359,8 @@ const PrepopulatedEngine pogodak_ba = {
L"http://www.pogodak.ba/search.jsp?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_POGODAK,
+ IDR_SEARCH_ENGINE_LOGO_POGODAK,
24,
};
@@ -1152,6 +1371,8 @@ const PrepopulatedEngine pogodak_hr = {
L"http://www.pogodak.hr/search.jsp?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_POGODAK,
+ IDR_SEARCH_ENGINE_LOGO_POGODAK,
24,
};
@@ -1162,6 +1383,8 @@ const PrepopulatedEngine pogodak_rs = {
L"http://www.pogodak.rs/search.jsp?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_POGODAK,
+ IDR_SEARCH_ENGINE_LOGO_POGODAK,
24,
};
@@ -1172,6 +1395,8 @@ const PrepopulatedEngine pogodok = {
L"http://www.pogodok.com.mk/search.jsp?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_POGODOK_MK,
+ IDR_SEARCH_ENGINE_LOGO_POGODOK_MK,
24, // Really the same engine as Pogodak, just has a small name change.
};
@@ -1182,6 +1407,8 @@ const PrepopulatedEngine rambler = {
L"http://www.rambler.ru/srch?words={searchTerms}",
"windows-1251",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_RAMBLER,
+ IDR_SEARCH_ENGINE_LOGO_RAMBLER,
16,
};
@@ -1192,6 +1419,8 @@ const PrepopulatedEngine rediff = {
L"http://search1.rediff.com/dirsrch/default.asp?MT={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
37,
};
@@ -1202,6 +1431,8 @@ const PrepopulatedEngine rednano = {
L"http://rednano.sg/sfe/lwi.action?querystring={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
41,
};
@@ -1212,6 +1443,8 @@ const PrepopulatedEngine sanook = {
L"http://search.sanook.com/search.php?q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_SANOOK,
+ IDR_SEARCH_ENGINE_LOGO_SANOOK,
100,
};
@@ -1222,6 +1455,8 @@ const PrepopulatedEngine sapo = {
L"http://pesquisa.sapo.pt/?q={searchTerms}",
"UTF-8",
L"http://pesquisa.sapo.pt/livesapo?q={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_SAPO,
+ IDR_SEARCH_ENGINE_LOGO_SAPO,
77,
};
@@ -1232,6 +1467,8 @@ const PrepopulatedEngine search_de_CH = {
L"http://www.search.ch/index.de.html?q={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
51,
};
@@ -1242,6 +1479,8 @@ const PrepopulatedEngine search_fr_CH = {
L"http://www.search.ch/index.fr.html?q={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
22,
};
@@ -1253,6 +1492,8 @@ const PrepopulatedEngine seznam = {
"UTF-8",
L"http:///suggest.fulltext.seznam.cz/?dict=fulltext_ff&phrase={searchTerms}&"
L"encoding={inputEncoding}&response_encoding=utf-8",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_SEZNAM,
+ IDR_SEARCH_ENGINE_LOGO_SEZNAM,
25,
};
@@ -1263,6 +1504,8 @@ const PrepopulatedEngine spray = {
L"http://www.eniro.se/query?ax=spray&search_word={searchTerms}&what=web",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
99,
};
@@ -1273,6 +1516,8 @@ const PrepopulatedEngine terra_ar = {
L"http://buscar.terra.com.ar/Default.aspx?query={searchTerms}&source=Search",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
90,
};
@@ -1283,6 +1528,8 @@ const PrepopulatedEngine terra_es = {
L"http://buscador.terra.es/Default.aspx?query={searchTerms}&source=Search",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
90,
};
@@ -1293,6 +1540,8 @@ const PrepopulatedEngine tut = {
L"http://search.tut.by/?query={searchTerms}",
"windows-1251",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_TUT,
+ IDR_SEARCH_ENGINE_LOGO_TUT,
17,
};
@@ -1303,6 +1552,8 @@ const PrepopulatedEngine uol = {
L"http://busca.uol.com.br/www/index.html?q={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
82,
};
@@ -1313,6 +1564,8 @@ const PrepopulatedEngine virgilio = {
L"http://ricerca.alice.it/ricerca?qs={searchTerms}",
"ISO-8859-1",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_VIRGILIO,
+ IDR_SEARCH_ENGINE_LOGO_VIRGILIO,
62,
};
@@ -1323,6 +1576,8 @@ const PrepopulatedEngine walla = {
L"http://search.walla.co.il/?e=hew&q={searchTerms}",
"windows-1255",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_WALLA,
+ IDR_SEARCH_ENGINE_LOGO_WALLA,
55,
};
@@ -1333,6 +1588,8 @@ const PrepopulatedEngine wp = {
L"http://szukaj.wp.pl/szukaj.html?szukaj={searchTerms}",
"ISO-8859-2",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
76,
};
@@ -1343,6 +1600,8 @@ const PrepopulatedEngine yahoo = {
L"http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}",
"UTF-8",
L"http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1358,6 +1617,8 @@ const PrepopulatedEngine yahoo_ar = {
"UTF-8",
L"http://ar-sayt.ff.search.yahoo.com/gossip-ar-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1369,6 +1630,8 @@ const PrepopulatedEngine yahoo_at = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1381,6 +1644,8 @@ const PrepopulatedEngine yahoo_au = {
"UTF-8",
L"http://aue-sayt.ff.search.yahoo.com/gossip-au-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1393,6 +1658,8 @@ const PrepopulatedEngine yahoo_br = {
"UTF-8",
L"http://br-sayt.ff.search.yahoo.com/gossip-br-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1405,6 +1672,8 @@ const PrepopulatedEngine yahoo_ca = {
"UTF-8",
L"http://gossip.ca.yahoo.com/gossip-ca-sayt?output=fxjsonp&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1416,6 +1685,8 @@ const PrepopulatedEngine yahoo_ch = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1428,6 +1699,8 @@ const PrepopulatedEngine yahoo_cl = {
"UTF-8",
L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1441,6 +1714,8 @@ const PrepopulatedEngine yahoo_cn = {
// http://cn.yahoo.com/cnsuggestion/suggestion.inc.php?of=fxjson&query=
// returns in a proprietary format ('|' delimeted word list).
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1453,6 +1728,8 @@ const PrepopulatedEngine yahoo_co = {
"UTF-8",
L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1465,6 +1742,8 @@ const PrepopulatedEngine yahoo_de = {
"UTF-8",
L"http://de-sayt.ff.search.yahoo.com/gossip-de-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1476,6 +1755,8 @@ const PrepopulatedEngine yahoo_dk = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1488,6 +1769,8 @@ const PrepopulatedEngine yahoo_es = {
"UTF-8",
L"http://es-sayt.ff.search.yahoo.com/gossip-es-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1499,6 +1782,8 @@ const PrepopulatedEngine yahoo_fi = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1511,6 +1796,8 @@ const PrepopulatedEngine yahoo_fr = {
"UTF-8",
L"http://fr-sayt.ff.search.yahoo.com/gossip-fr-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1525,6 +1812,8 @@ const PrepopulatedEngine yahoo_hk = {
// returns a JSON with key-value pairs. Setting parameters (ot, of, output)
// to fxjson, json, or js doesn't help.
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1537,6 +1826,8 @@ const PrepopulatedEngine yahoo_id = {
"UTF-8",
L"http://id-sayt.ff.search.yahoo.com/gossip-id-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1549,6 +1840,8 @@ const PrepopulatedEngine yahoo_in = {
"UTF-8",
L"http://in-sayt.ff.search.yahoo.com/gossip-in-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1561,6 +1854,8 @@ const PrepopulatedEngine yahoo_it = {
"UTF-8",
L"http://it-sayt.ff.search.yahoo.com/gossip-it-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1572,6 +1867,8 @@ const PrepopulatedEngine yahoo_jp = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOOJP,
+ IDR_SEARCH_ENGINE_LOGO_YAHOOJP,
2,
};
@@ -1584,6 +1881,8 @@ const PrepopulatedEngine yahoo_kr = {
"UTF-8",
L"http://kr.atc.search.yahoo.com/atcx.php?property=main&ot=fxjson&"
L"ei=utf8&eo=utf8&command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1596,6 +1895,8 @@ const PrepopulatedEngine yahoo_malaysia = {
"UTF-8",
L"http://my-sayt.ff.search.yahoo.com/gossip-my-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1608,6 +1909,8 @@ const PrepopulatedEngine yahoo_mx = {
"UTF-8",
L"http://gossip.mx.yahoo.com/gossip-mx-sayt?output=fxjsonp&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1619,6 +1922,8 @@ const PrepopulatedEngine yahoo_nl = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1630,6 +1935,8 @@ const PrepopulatedEngine yahoo_no = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1642,6 +1949,8 @@ const PrepopulatedEngine yahoo_nz = {
"UTF-8",
L"http://aue-sayt.ff.search.yahoo.com/gossip-nz-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1654,6 +1963,8 @@ const PrepopulatedEngine yahoo_pe = {
"UTF-8",
L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1666,6 +1977,8 @@ const PrepopulatedEngine yahoo_ph = {
"UTF-8",
L"http://ph-sayt.ff.search.yahoo.com/gossip-ph-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1677,6 +1990,8 @@ const PrepopulatedEngine yahoo_qc = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOOQC,
+ IDR_SEARCH_ENGINE_LOGO_YAHOOQC,
5, // Can't be 2 as this has to appear in the Canada list alongside yahoo_ca.
};
@@ -1688,6 +2003,8 @@ const PrepopulatedEngine yahoo_ru = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1699,6 +2016,8 @@ const PrepopulatedEngine yahoo_se = {
L"p={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1711,6 +2030,8 @@ const PrepopulatedEngine yahoo_sg = {
"UTF-8",
L"http://sg-sayt.ff.search.yahoo.com/gossip-sg-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1722,7 +2043,9 @@ const PrepopulatedEngine yahoo_th = {
L"p={searchTerms}",
"UTF-8",
L"http://th-sayt.ff.search.yahoo.com/gossip-th-sayt?output=fxjson&"
- L"command={searchTerms}",
+ L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1736,6 +2059,8 @@ const PrepopulatedEngine yahoo_tw = {
// "http://tw.yahoo.com/ac/ac_search.php?eo=utf8&of=js&prop=web&query="
// returns a JSON file prepended with 'fxsearch=('.
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1748,6 +2073,8 @@ const PrepopulatedEngine yahoo_uk = {
"UTF-8",
L"http://uk-sayt.ff.search.yahoo.com/gossip-uk-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1760,6 +2087,8 @@ const PrepopulatedEngine yahoo_ve = {
"UTF-8",
L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1772,6 +2101,8 @@ const PrepopulatedEngine yahoo_vn = {
"UTF-8",
L"http://vn-sayt.ff.search.yahoo.com/gossip-vn-sayt?output=fxjson&"
L"command={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
+ IDR_SEARCH_ENGINE_LOGO_YAHOO,
2,
};
@@ -1782,6 +2113,8 @@ const PrepopulatedEngine yamli = {
L"http://www.yamli.com/#q={searchTerms}",
"UTF-8",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_OTHER,
+ IDR_SEARCH_ENGINE_LOGO_OTHER,
11,
};
@@ -1792,6 +2125,8 @@ const PrepopulatedEngine yandex_ru = {
L"http://yandex.ru/yandsearch?text={searchTerms}",
"UTF-8",
L"http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YANDEX,
+ IDR_SEARCH_ENGINE_LOGO_YANDEX,
15,
};
@@ -1802,6 +2137,8 @@ const PrepopulatedEngine yandex_ua = {
L"http://yandex.ua/yandsearch?text={searchTerms}",
"UTF-8",
L"http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms}",
+ TemplateURLPrepopulateData::SEARCH_ENGINE_YANDEX,
+ IDR_SEARCH_ENGINE_LOGO_YANDEX,
15,
};
@@ -1812,6 +2149,8 @@ const PrepopulatedEngine zoznam = {
L"http://zoznam.sk/hladaj.fcgi?s={searchTerms}",
"windows-1250",
NULL,
+ TemplateURLPrepopulateData::SEARCH_ENGINE_ZOZNAM,
+ IDR_SEARCH_ENGINE_LOGO_ZOZNAM,
85,
};
@@ -1850,7 +2189,7 @@ const PrepopulatedEngine* engines_BA[] =
// Belgium
const PrepopulatedEngine* engines_BE[] =
- { &google, &bing_nl_BE, &bing_fr_BE, &yahoo, };
+ { &google, &bing_nl_BE, &yahoo, &bing_fr_BE, };
// Bulgaria
const PrepopulatedEngine* engines_BG[] =
@@ -1927,7 +2266,7 @@ const PrepopulatedEngine* engines_DO[] =
// Algeria
const PrepopulatedEngine* engines_DZ[] =
- { &google, &bing_en_XA, &bing_ar_XA, &yahoo, &maktoob, };
+ { &google, &bing_en_XA, &yahoo, &bing_ar_XA, &maktoob, };
// Ecuador
const PrepopulatedEngine* engines_EC[] =
@@ -2035,7 +2374,7 @@ const PrepopulatedEngine* engines_KE[] =
// Kuwait
const PrepopulatedEngine* engines_KW[] =
- { &google, &bing_en_XA, &bing_ar_XA, &yahoo, &maktoob, &araby, };
+ { &google, &bing_en_XA, &yahoo, &bing_ar_XA, &maktoob, &araby, };
// South Korea
const PrepopulatedEngine* engines_KR[] =
@@ -2071,7 +2410,7 @@ const PrepopulatedEngine* engines_LY[] =
// Morocco
const PrepopulatedEngine* engines_MA[] =
- { &google, &bing_en_XA, &bing_ar_XA, &yahoo, };
+ { &google, &bing_en_XA, &yahoo, &bing_ar_XA, };
// Monaco
const PrepopulatedEngine* engines_MC[] =
@@ -2195,7 +2534,7 @@ const PrepopulatedEngine* engines_SV[] =
// Syria
const PrepopulatedEngine* engines_SY[] =
- { &google, &bing_en_XA, &bing_ar_XA, &yahoo, &maktoob, &yamli, };
+ { &google, &bing_en_XA, &yahoo, &bing_ar_XA, &maktoob, &yamli, };
// Thailand
const PrepopulatedEngine* engines_TH[] =
@@ -2203,7 +2542,7 @@ const PrepopulatedEngine* engines_TH[] =
// Tunisia
const PrepopulatedEngine* engines_TN[] =
- { &google, &bing_en_XA, &bing_ar_XA, &yahoo, &maktoob, &yamli };
+ { &google, &bing_en_XA, &yahoo, &bing_ar_XA, &maktoob, &yamli };
// Turkey
const PrepopulatedEngine* engines_TR[] =
@@ -2400,11 +2739,11 @@ int GetCurrentCountryID() {
int GetCountryIDFromPrefs(PrefService* prefs) {
// See if the user overrode the country on the command line.
- const std::wstring country(
- CommandLine::ForCurrentProcess()->GetSwitchValue(switches::kCountry));
+ const std::string country(
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kCountry));
if (country.length() == 2)
- return CountryCharsToCountryIDWithUpdate(static_cast<char>(country[0]),
- static_cast<char>(country[1]));
+ return CountryCharsToCountryIDWithUpdate(country[0], country[1]);
// Cache first run Country ID value in prefs, and use it afterwards. This
// ensures that just because the user moves around, we won't automatically
@@ -2802,7 +3141,7 @@ void RegisterUserPrefs(PrefService* prefs) {
int GetDataVersion(PrefService* prefs) {
// Increment this if you change the above data in ways that mean users with
// existing data should get a new version.
- const int kCurrentDataVersion = 28;
+ const int kCurrentDataVersion = 29;
if (!prefs)
return kCurrentDataVersion;
// If a version number exist in the preferences file, it overrides the
@@ -2818,6 +3157,8 @@ TemplateURL* MakePrepopulatedTemplateURL(const wchar_t* name,
const char* favicon_url,
const wchar_t* suggest_url,
const char* encoding,
+ SearchEngineType search_engine_type,
+ int logo_id,
int id) {
TemplateURL* new_turl = new TemplateURL();
new_turl->SetURL(WideToUTF8(search_url), 0, 0);
@@ -2836,23 +3177,30 @@ TemplateURL* MakePrepopulatedTemplateURL(const wchar_t* name,
std::vector<std::string> turl_encodings;
turl_encodings.push_back(encoding);
new_turl->set_input_encodings(turl_encodings);
+ new_turl->set_search_engine_type(search_engine_type);
+ new_turl->set_logo_id(logo_id);
new_turl->set_prepopulate_id(id);
return new_turl;
}
-void GetPrepopulatedTemplatefromPrefs(PrefService* prefs,
+void GetPrepopulatedTemplateFromPrefs(PrefService* prefs,
std::vector<TemplateURL*>* t_urls) {
+ if (!prefs)
+ return;
+
const ListValue* list =
prefs->GetList(prefs::kSearchProviderOverrides);
if (!list)
return;
- std::wstring name;
- std::wstring keyword;
- std::wstring search_url;
- std::wstring suggest_url;
+ string16 name;
+ string16 keyword;
+ std::string search_url;
+ std::string suggest_url;
std::string favicon_url;
std::string encoding;
+ int search_engine_type;
+ int logo_id;
int id;
size_t num_engines = list->GetSize();
@@ -2860,13 +3208,16 @@ void GetPrepopulatedTemplatefromPrefs(PrefService* prefs,
Value* val;
DictionaryValue* engine;
list->GetDictionary(i, &engine);
- if (engine->Get(L"name", &val) && val->GetAsString(&name) &&
- engine->Get(L"keyword", &val) && val->GetAsString(&keyword) &&
- engine->Get(L"search_url", &val) && val->GetAsString(&search_url) &&
- engine->Get(L"suggest_url", &val) && val->GetAsString(&suggest_url) &&
- engine->Get(L"favicon_url", &val) && val->GetAsString(&favicon_url) &&
- engine->Get(L"encoding", &val) && val->GetAsString(&encoding) &&
- engine->Get(L"id", &val) && val->GetAsInteger(&id)) {
+ if (engine->Get("name", &val) && val->GetAsString(&name) &&
+ engine->Get("keyword", &val) && val->GetAsString(&keyword) &&
+ engine->Get("search_url", &val) && val->GetAsString(&search_url) &&
+ engine->Get("suggest_url", &val) && val->GetAsString(&suggest_url) &&
+ engine->Get("favicon_url", &val) && val->GetAsString(&favicon_url) &&
+ engine->Get("encoding", &val) && val->GetAsString(&encoding) &&
+ engine->Get("search_engine_type", &val) && val->GetAsInteger(
+ &search_engine_type) &&
+ engine->Get("logo_id", &val) && val->GetAsInteger(&logo_id) &&
+ engine->Get("id", &val) && val->GetAsInteger(&id)) {
// These next fields are not allowed to be empty.
if (search_url.empty() || favicon_url.empty() || encoding.empty())
return;
@@ -2874,23 +3225,28 @@ void GetPrepopulatedTemplatefromPrefs(PrefService* prefs,
// Got a parsing error. No big deal.
continue;
}
- t_urls->push_back(MakePrepopulatedTemplateURL(name.c_str(),
- keyword.c_str(),
- search_url.c_str(),
- favicon_url.c_str(),
- suggest_url.c_str(),
- encoding.c_str(),
- id));
+ // TODO(viettrungluu): convert |MakePrepopulatedTemplateURL()| and get rid
+ // of conversions.
+ t_urls->push_back(MakePrepopulatedTemplateURL(
+ UTF16ToWideHack(name).c_str(),
+ UTF16ToWideHack(keyword).c_str(),
+ UTF8ToWide(search_url).c_str(),
+ favicon_url.c_str(),
+ UTF8ToWide(suggest_url).c_str(),
+ encoding.c_str(),
+ static_cast<SearchEngineType>(search_engine_type),
+ logo_id,
+ id));
}
}
void GetPrepopulatedEngines(PrefService* prefs,
std::vector<TemplateURL*>* t_urls,
size_t* default_search_provider_index) {
- // If there if there is a set of search engines in the preferences
- // file, it overrides the built-in set.
+ // If there is a set of search engines in the preferences file, it overrides
+ // the built-in set.
*default_search_provider_index = 0;
- GetPrepopulatedTemplatefromPrefs(prefs, t_urls);
+ GetPrepopulatedTemplateFromPrefs(prefs, t_urls);
if (!t_urls->empty())
return;
@@ -2905,38 +3261,11 @@ void GetPrepopulatedEngines(PrefService* prefs,
engines[i]->favicon_url,
engines[i]->suggest_url,
engines[i]->encoding,
+ engines[i]->search_engine_type,
+ engines[i]->logo_id,
engines[i]->id);
t_urls->push_back(turl);
}
}
-SearchEngineType GetSearchEngineType(const TemplateURL* search_engine) {
- switch (search_engine->prepopulate_id()) {
- case 1:
- return SEARCH_ENGINE_GOOGLE;
- case 2:
- // Construction of country id = 'J' << 8 | 'P' = 19024
- return (GetCountryIDFromPrefs(NULL) == 19024) ? SEARCH_ENGINE_YAHOOJP :
- SEARCH_ENGINE_YAHOO;
- case 3:
- return SEARCH_ENGINE_BING;
- case 4:
- return SEARCH_ENGINE_ASK;
- case 15:
- return SEARCH_ENGINE_YANDEX;
- case 25:
- return SEARCH_ENGINE_SEZNAM;
- case 26:
- return SEARCH_ENGINE_CENTRUM;
- case 30:
- return SEARCH_ENGINE_NETSPRINT;
- case 62:
- return SEARCH_ENGINE_VIRGILIO;
- case 83:
- return SEARCH_ENGINE_MAILRU;
- default:
- return SEARCH_ENGINE_OTHER;
- }
-}
-
} // namespace TemplateURLPrepopulateData
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.h b/chrome/browser/search_engines/template_url_prepopulate_data.h
index 4191a92..80fa584 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data.h
+++ b/chrome/browser/search_engines/template_url_prepopulate_data.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_PREPOPULATE_DATA_H_
#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_PREPOPULATE_DATA_H_
+#pragma once
#include <vector>
@@ -12,7 +13,9 @@ class TemplateURL;
namespace TemplateURLPrepopulateData {
-// Enum to record the user's default search engine choice in UMA:
+// Enum to record the user's default search engine choice in UMA. Add new
+// search engines at the bottom and do not delete from this list, so as not
+// to disrupt UMA data already recorded.
enum SearchEngineType {
SEARCH_ENGINE_OTHER = 0, // At the top in case of future list changes.
SEARCH_ENGINE_GOOGLE,
@@ -26,6 +29,27 @@ enum SearchEngineType {
SEARCH_ENGINE_NETSPRINT,
SEARCH_ENGINE_VIRGILIO,
SEARCH_ENGINE_MAILRU,
+ SEARCH_ENGINE_ABCSOK,
+ SEARCH_ENGINE_ALTAVISTA,
+ SEARCH_ENGINE_BAIDU,
+ SEARCH_ENGINE_DAUM,
+ SEARCH_ENGINE_DELFI,
+ SEARCH_ENGINE_DIRI,
+ SEARCH_ENGINE_GOO,
+ SEARCH_ENGINE_IN,
+ SEARCH_ENGINE_NAJDI,
+ SEARCH_ENGINE_NAVER,
+ SEARCH_ENGINE_NETI,
+ SEARCH_ENGINE_OK,
+ SEARCH_ENGINE_POGODAK,
+ SEARCH_ENGINE_POGODOK_MK,
+ SEARCH_ENGINE_RAMBLER,
+ SEARCH_ENGINE_SANOOK,
+ SEARCH_ENGINE_SAPO,
+ SEARCH_ENGINE_TUT,
+ SEARCH_ENGINE_WALLA,
+ SEARCH_ENGINE_ZOZNAM,
+ SEARCH_ENGINE_YAHOOQC,
SEARCH_ENGINE_MAX // Bounding max value needed for UMA histogram macro.
};
@@ -44,14 +68,6 @@ void GetPrepopulatedEngines(PrefService* prefs,
std::vector<TemplateURL*>* t_urls,
size_t* default_search_provider_index);
-// Returns the type of the search engine to be recorded in UMA. The type
-// is determined by mapping the search engine's |id| to the set of search
-// engines we are interested in. Because this is only a temporary test
-// for a small set of search engines, we use this simple switch statement
-// instead of embedding a UMA type as part of the struct of every search
-// engine.
-SearchEngineType GetSearchEngineType(const TemplateURL* search_engine);
-
} // namespace TemplateURLPrepopulateData
#endif // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_PREPOPULATE_DATA_H_
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 fb02c52..29ad50c 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
@@ -1,8 +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 "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/template_url.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/common/pref_names.h"
@@ -92,6 +95,8 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
" \"favicon_url\":\"http://foi.com/favicon.ico\","
" \"suggest_url\":\"\","
" \"encoding\":\"UTF-8\","
+ " \"search_engine_type\":1,"
+ " \"logo_id\":0,"
" \"id\":1001"
" }"
" ]"
@@ -121,4 +126,7 @@ TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
EXPECT_EQ("foi.com", t_urls[0]->GetFavIconURL().host());
EXPECT_EQ(1u, t_urls[0]->input_encodings().size());
EXPECT_EQ(1001, t_urls[0]->prepopulate_id());
+ EXPECT_EQ(TemplateURLPrepopulateData::SEARCH_ENGINE_GOOGLE,
+ t_urls[0]->search_engine_type());
+ EXPECT_EQ(0, t_urls[0]->logo_id());
}
diff --git a/chrome/browser/search_engines/template_url_table_model.cc b/chrome/browser/search_engines/template_url_table_model.cc
index 1192db0..4570b25 100644
--- a/chrome/browser/search_engines/template_url_table_model.cc
+++ b/chrome/browser/search_engines/template_url_table_model.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/search_engines/template_url_table_model.h"
+#include <string>
#include <vector>
#include "app/l10n_util.h"
@@ -15,9 +16,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/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"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
// Group IDs used by TemplateURLTableModel.
static const int kMainGroupID = 0;
@@ -160,8 +164,9 @@ void TemplateURLTableModel::Reload() {
// NOTE: we don't use ShowInDefaultList here to avoid things bouncing
// the lists while editing.
if (!template_url->show_in_default_list() &&
- !template_url->IsExtensionKeyword())
+ !template_url->IsExtensionKeyword()) {
entries_.push_back(new ModelEntry(this, *template_url));
+ }
}
if (observer_)
@@ -191,9 +196,9 @@ std::wstring TemplateURLTableModel::GetText(int row, int col_id) {
case IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN: {
// Keyword should be domain name. Force it to have LTR directionality.
- std::wstring keyword(url.keyword());
- base::i18n::GetDisplayStringInLTRDirectionality(&keyword);
- return keyword;
+ string16 keyword = WideToUTF16(url.keyword());
+ keyword = base::i18n::GetDisplayStringInLTRDirectionality(keyword);
+ return UTF16ToWide(keyword);
}
default:
@@ -244,8 +249,8 @@ void TemplateURLTableModel::Remove(int index) {
template_url_model_->RemoveObserver(this);
const TemplateURL* template_url = &GetTemplateURL(index);
- scoped_ptr<ModelEntry> entry(entries_[static_cast<int>(index)]);
- entries_.erase(entries_.begin() + static_cast<int>(index));
+ scoped_ptr<ModelEntry> entry(entries_[index]);
+ entries_.erase(entries_.begin() + index);
if (index < last_search_engine_index_)
last_search_engine_index_--;
if (observer_)
@@ -269,13 +274,14 @@ void TemplateURLTableModel::Add(int index, TemplateURL* template_url) {
}
void TemplateURLTableModel::ModifyTemplateURL(int index,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url) {
DCHECK(index >= 0 && index <= RowCount());
const TemplateURL* template_url = &GetTemplateURL(index);
template_url_model_->RemoveObserver(this);
- template_url_model_->ResetTemplateURL(template_url, title, keyword, url);
+ template_url_model_->ResetTemplateURL(template_url, UTF16ToWideHack(title),
+ UTF16ToWideHack(keyword), url);
if (template_url_model_->GetDefaultSearchProvider() == template_url &&
!TemplateURL::SupportsReplacement(template_url)) {
// The entry was the default search provider, but the url has been modified
@@ -344,8 +350,13 @@ int TemplateURLTableModel::MakeDefaultTemplateURL(int index) {
// The formatting of the default engine is different; notify the table that
// both old and new entries have changed.
- if (current_default != NULL)
- NotifyChanged(IndexOfTemplateURL(current_default));
+ if (current_default != NULL) {
+ int old_index = IndexOfTemplateURL(current_default);
+ // current_default may not be in the list of TemplateURLs if the database is
+ // corrupt and the default TemplateURL is used from preferences
+ if (old_index >= 0)
+ NotifyChanged(old_index);
+ }
const int new_index = IndexOfTemplateURL(keyword);
NotifyChanged(new_index);
@@ -354,8 +365,10 @@ int TemplateURLTableModel::MakeDefaultTemplateURL(int index) {
}
void TemplateURLTableModel::NotifyChanged(int index) {
- if (observer_)
+ if (observer_) {
+ DCHECK_GE(index, 0);
observer_->OnItemsChanged(index, 1);
+ }
}
void TemplateURLTableModel::FavIconAvailable(ModelEntry* entry) {
diff --git a/chrome/browser/search_engines/template_url_table_model.h b/chrome/browser/search_engines/template_url_table_model.h
index 1909172..03bb43a 100644
--- a/chrome/browser/search_engines/template_url_table_model.h
+++ b/chrome/browser/search_engines/template_url_table_model.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_TABLE_MODEL_H_
#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_TABLE_MODEL_H_
+#pragma once
#include "app/table_model.h"
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "base/string16.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
class ModelEntry;
class SkBitmap;
class TemplateURL;
class TemplateURLModel;
-class TemplateURLTableModel;
// TemplateURLTableModel is the TableModel implementation used by
// KeywordEditorView to show the keywords in a TableView.
@@ -52,8 +53,10 @@ class TemplateURLTableModel : public TableModel,
void Add(int index, TemplateURL* template_url);
// Update the entry at the specified index.
- void ModifyTemplateURL(int index, const std::wstring& title,
- const std::wstring& keyword, const std::string& url);
+ void ModifyTemplateURL(int index,
+ const string16& title,
+ const string16& keyword,
+ const std::string& url);
// Reloads the icon at the specified index.
void ReloadIcon(int index);
diff --git a/chrome/browser/search_engines/template_url_unittest.cc b/chrome/browser/search_engines/template_url_unittest.cc
index 16eafec..3faa2aa 100644
--- a/chrome/browser/search_engines/template_url_unittest.cc
+++ b/chrome/browser/search_engines/template_url_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2010 The Chromium 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,22 +7,49 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/rlz/rlz.h"
+#include "chrome/browser/search_engines/search_terms_data.h"
#include "chrome/browser/search_engines/template_url.h"
#include "testing/gtest/include/gtest/gtest.h"
+// Simple implementation of SearchTermsData.
+class TestSearchTermsData : public SearchTermsData {
+ public:
+ explicit TestSearchTermsData(const char* google_base_url)
+ : google_base_url_(google_base_url) {
+ }
+
+ virtual std::string GoogleBaseURLValue() const {
+ return google_base_url_;
+ }
+
+ virtual std::string GetApplicationLocale() const {
+ return "yy";
+ }
+
+#if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
+ // Returns the value for the Chrome Omnibox rlz.
+ virtual std::wstring GetRlzParameterValue() const {
+ return L"";
+ }
+#endif
+
+ private:
+ std::string google_base_url_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSearchTermsData);
+};
+
class TemplateURLTest : public testing::Test {
public:
virtual void TearDown() {
- delete TemplateURLRef::google_base_url_;
- TemplateURLRef::google_base_url_ = NULL;
+ TemplateURLRef::SetGoogleBaseURL(NULL);
}
void CheckSuggestBaseURL(const char* base_url,
const char* base_suggest_url) const {
- delete TemplateURLRef::google_base_url_;
- TemplateURLRef::google_base_url_ = new std::string(base_url);
+ TestSearchTermsData search_terms_data(base_url);
EXPECT_STREQ(base_suggest_url,
- TemplateURLRef::GoogleBaseSuggestURLValue().c_str());
+ search_terms_data.GoogleBaseSuggestURLValue().c_str());
}
};
@@ -147,6 +174,35 @@ TEST_F(TemplateURLTest, URLRefTestEncoding2) {
ASSERT_EQ("http://fooxxutf-8yutf-8a/", result.spec());
}
+TEST_F(TemplateURLTest, URLRefTestSearchTermsUsingTermsData) {
+ struct SearchTermsCase {
+ const char* url;
+ const wchar_t* terms;
+ const char* output;
+ } search_term_cases[] = {
+ { "{google:baseURL}{language}{searchTerms}", L"",
+ "http://example.com/e/yy" },
+ { "{google:baseSuggestURL}{searchTerms}", L"",
+ "http://clients1.example.com/complete/" }
+ };
+
+ TestSearchTermsData search_terms_data("http://example.com/e/");
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(search_term_cases); ++i) {
+ const SearchTermsCase& value = search_term_cases[i];
+ TemplateURL t_url;
+ TemplateURLRef ref(value.url, 0, 0);
+ ASSERT_TRUE(ref.IsValid());
+
+ ASSERT_TRUE(ref.SupportsReplacement());
+ GURL result = GURL(ref.ReplaceSearchTermsUsingTermsData(
+ t_url, value.terms,
+ TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring(),
+ search_terms_data));
+ ASSERT_TRUE(result.is_valid());
+ ASSERT_EQ(value.output, result.spec());
+ }
+}
+
TEST_F(TemplateURLTest, URLRefTermToWide) {
struct ToWideCase {
const char* encoded_search_term;
@@ -328,7 +384,9 @@ TEST_F(TemplateURLTest, Suggestions) {
#if defined(OS_WIN)
TEST_F(TemplateURLTest, RLZ) {
std::wstring rlz_string;
+#if defined(GOOGLE_CHROME_BUILD)
RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &rlz_string);
+#endif
TemplateURL t_url;
TemplateURLRef ref("http://bar/?{google:RLZ}{searchTerms}", 1, 2);
diff --git a/chrome/browser/search_engines/util.cc b/chrome/browser/search_engines/util.cc
index 28e1c93..8273800 100644
--- a/chrome/browser/search_engines/util.cc
+++ b/chrome/browser/search_engines/util.cc
@@ -4,8 +4,16 @@
#include "chrome/browser/search_engines/util.h"
+#include <set>
+#include <vector>
+
+#include "base/logging.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chrome_thread.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"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
string16 GetDefaultSearchEngineName(Profile* profile) {
@@ -23,3 +31,166 @@ string16 GetDefaultSearchEngineName(Profile* profile) {
}
return WideToUTF16(default_provider->short_name());
}
+
+// Removes (and deletes) TemplateURLs from |urls| that have duplicate
+// prepopulate ids. Duplicate prepopulate ids are not allowed, but due to a
+// bug it was possible get dups. This step is only called when the version
+// number changes. Only pass in a non-NULL value for |service| if the removed
+// items should be removed from the DB.
+static void RemoveDuplicatePrepopulateIDs(
+ std::vector<TemplateURL*>* template_urls,
+ WebDataService* service) {
+ DCHECK(template_urls);
+ DCHECK(service == NULL || ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ std::set<int> ids;
+ for (std::vector<TemplateURL*>::iterator i = template_urls->begin();
+ i != template_urls->end(); ) {
+ int prepopulate_id = (*i)->prepopulate_id();
+ if (prepopulate_id) {
+ if (ids.find(prepopulate_id) != ids.end()) {
+ if (service)
+ service->RemoveKeyword(**i);
+ delete *i;
+ i = template_urls->erase(i);
+ } else {
+ ids.insert(prepopulate_id);
+ ++i;
+ }
+ } else {
+ ++i;
+ }
+ }
+}
+
+// Loads engines from prepopulate data and merges them in with the existing
+// engines. This is invoked when the version of the prepopulate data changes.
+void MergeEnginesFromPrepopulateData(
+ PrefService* prefs,
+ WebDataService* service,
+ std::vector<TemplateURL*>* template_urls,
+ const TemplateURL** default_search_provider) {
+ DCHECK(service == NULL || ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(template_urls);
+ DCHECK(default_search_provider);
+
+ // Build a map from prepopulate id to TemplateURL of existing urls.
+ typedef std::map<int, TemplateURL*> IDMap;
+ IDMap id_to_turl;
+ for (std::vector<TemplateURL*>::iterator i(template_urls->begin());
+ i != template_urls->end(); ++i) {
+ int prepopulate_id = (*i)->prepopulate_id();
+ if (prepopulate_id > 0)
+ id_to_turl[prepopulate_id] = *i;
+ }
+
+ std::vector<TemplateURL*> loaded_urls;
+ size_t default_search_index;
+ TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs,
+ &loaded_urls,
+ &default_search_index);
+
+ std::set<int> updated_ids;
+ for (size_t i = 0; i < loaded_urls.size(); ++i) {
+ // We take ownership of |t_url|.
+ scoped_ptr<TemplateURL> t_url(loaded_urls[i]);
+ const int t_url_id = t_url->prepopulate_id();
+ if (!t_url_id || updated_ids.count(t_url_id)) {
+ // Prepopulate engines need a unique id.
+ NOTREACHED();
+ continue;
+ }
+
+ TemplateURL* current_t_url = t_url.get();
+ IDMap::iterator existing_url_iter(id_to_turl.find(t_url_id));
+ if (existing_url_iter != id_to_turl.end()) {
+ current_t_url = existing_url_iter->second;
+ if (!current_t_url->safe_for_autoreplace()) {
+ // User edited the entry, preserve the keyword and description.
+ t_url->set_safe_for_autoreplace(false);
+ t_url->set_keyword(current_t_url->keyword());
+ t_url->set_autogenerate_keyword(
+ current_t_url->autogenerate_keyword());
+ t_url->set_short_name(current_t_url->short_name());
+ }
+ t_url->set_id(current_t_url->id());
+
+ *current_t_url = *t_url;
+ if (service) {
+ service->UpdateKeyword(*current_t_url);
+ }
+ id_to_turl.erase(existing_url_iter);
+ } else {
+ template_urls->push_back(t_url.release());
+ }
+ if (i == default_search_index && !*default_search_provider)
+ *default_search_provider = current_t_url;
+
+ updated_ids.insert(t_url_id);
+ }
+
+ // Remove any prepopulated engines which are no longer in the master list, as
+ // long as the user hasn't modified them or made them the default engine.
+ for (IDMap::iterator i(id_to_turl.begin()); i != id_to_turl.end(); ++i) {
+ const TemplateURL* template_url = i->second;
+ if ((template_url->safe_for_autoreplace()) &&
+ (template_url != *default_search_provider)) {
+ std::vector<TemplateURL*>::iterator i = find(template_urls->begin(),
+ template_urls->end(),
+ template_url);
+ DCHECK(i != template_urls->end());
+ template_urls->erase(i);
+ if (service)
+ service->RemoveKeyword(*template_url);
+ delete template_url;
+ }
+ }
+}
+
+void GetSearchProvidersUsingKeywordResult(
+ const WDTypedResult& result,
+ WebDataService* service,
+ PrefService* prefs,
+ std::vector<TemplateURL*>* template_urls,
+ const TemplateURL** default_search_provider,
+ int* new_resource_keyword_version) {
+ DCHECK(service == NULL || ChromeThread::CurrentlyOn(ChromeThread::UI));
+ DCHECK(template_urls);
+ DCHECK(template_urls->empty());
+ DCHECK(default_search_provider);
+ DCHECK(*default_search_provider == NULL);
+ DCHECK(result.GetType() == KEYWORDS_RESULT);
+ DCHECK(new_resource_keyword_version);
+
+ *new_resource_keyword_version = 0;
+ WDKeywordsResult keyword_result = reinterpret_cast<
+ const WDResult<WDKeywordsResult>*>(&result)->GetValue();
+
+ template_urls->swap(keyword_result.keywords);
+
+ const int resource_keyword_version =
+ TemplateURLPrepopulateData::GetDataVersion(prefs);
+ if (keyword_result.builtin_keyword_version != resource_keyword_version) {
+ // There should never be duplicate TemplateURLs. We had a bug such that
+ // duplicate TemplateURLs existed for one locale. As such we invoke
+ // RemoveDuplicatePrepopulateIDs to nuke the duplicates.
+ RemoveDuplicatePrepopulateIDs(template_urls, service);
+ }
+
+ if (keyword_result.default_search_provider_id) {
+ // See if we can find the default search provider.
+ for (std::vector<TemplateURL*>::iterator i = template_urls->begin();
+ i != template_urls->end(); ++i) {
+ if ((*i)->id() == keyword_result.default_search_provider_id) {
+ *default_search_provider = *i;
+ break;
+ }
+ }
+ }
+
+ if (keyword_result.builtin_keyword_version != resource_keyword_version) {
+ MergeEnginesFromPrepopulateData(prefs, service, template_urls,
+ default_search_provider);
+ *new_resource_keyword_version = resource_keyword_version;
+ }
+}
diff --git a/chrome/browser/search_engines/util.h b/chrome/browser/search_engines/util.h
index 07f059c..e517ba6 100644
--- a/chrome/browser/search_engines/util.h
+++ b/chrome/browser/search_engines/util.h
@@ -4,15 +4,40 @@
#ifndef CHROME_BROWSER_SEARCH_ENGINES_UTIL_H_
#define CHROME_BROWSER_SEARCH_ENGINES_UTIL_H_
+#pragma once
// This file contains utility functions for search engine functionality.
+#include <vector>
#include "base/string16.h"
+class PrefService;
class Profile;
+class TemplateURL;
+class WDTypedResult;
+class WebDataService;
// Returns the short name of the default search engine, or the empty string if
// none is set. |profile| may be NULL.
string16 GetDefaultSearchEngineName(Profile* profile);
+// Processes the results of WebDataService::GetKeywords, combining it with
+// prepopulated search providers to result in:
+// * a set of template_urls (search providers). The caller owns the
+// TemplateURL* returned in template_urls.
+// * the default search provider (and if *default_search_provider is not NULL,
+// it is contained in template_urls).
+// * whether there is a new resource keyword version (and the value).
+// |*new_resource_keyword_version| is set to 0 if no new value. Otherwise,
+// it is the new value.
+// Only pass in a non-NULL value for service if the WebDataService should be
+// updated.
+void GetSearchProvidersUsingKeywordResult(
+ const WDTypedResult& result,
+ WebDataService* service,
+ PrefService* prefs,
+ std::vector<TemplateURL*>* template_urls,
+ const TemplateURL** default_search_provider,
+ int* new_resource_keyword_version);
+
#endif // CHROME_BROWSER_SEARCH_ENGINES_UTIL_H_
diff --git a/chrome/browser/session_history_uitest.cc b/chrome/browser/session_history_uitest.cc
index a449437..a30678a 100644
--- a/chrome/browser/session_history_uitest.cc
+++ b/chrome/browser/session_history_uitest.cc
@@ -1,9 +1,7 @@
-// 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 "app/l10n_util.h"
-#include "base/file_path.h"
#include "base/platform_thread.h"
#include "base/string_util.h"
#include "chrome/common/url_constants.h"
@@ -12,15 +10,15 @@
#include "chrome/test/ui/ui_test.h"
#include "grit/generated_resources.h"
#include "net/base/net_util.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
-
class SessionHistoryTest : public UITest {
protected:
- SessionHistoryTest() : UITest() {
+ SessionHistoryTest()
+ : test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
dom_automation_enabled_ = true;
}
@@ -78,27 +76,33 @@ class SessionHistoryTest : public UITest {
protected:
scoped_refptr<BrowserProxy> window_;
scoped_refptr<TabProxy> tab_;
+
+ net::TestServer test_server_;
};
-TEST_F(SessionHistoryTest, BasicBackForward) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+#if defined(OS_WIN) || defined(OS_LINUX)
+// http://crbug.com/55380 - NavigateToURL to making this flaky
+#define MAYBE_BasicBackForward FLAKY_BasicBackForward
+#else
+#define MAYBE_BasicBackForward BasicBackForward
+#endif
+TEST_F(SessionHistoryTest, MAYBE_BasicBackForward) {
+ ASSERT_TRUE(test_server_.Start());
// about:blank should be loaded first.
ASSERT_FALSE(tab_->GoBack());
EXPECT_EQ(L"", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot1.html")));
+ test_server_.GetURL("files/session_history/bot1.html")));
EXPECT_EQ(L"bot1", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot2.html")));
+ test_server_.GetURL("files/session_history/bot2.html")));
EXPECT_EQ(L"bot2", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot3.html")));
+ test_server_.GetURL("files/session_history/bot3.html")));
EXPECT_EQ(L"bot3", GetTabTitle());
// history is [blank, bot1, bot2, *bot3]
@@ -116,7 +120,7 @@ TEST_F(SessionHistoryTest, BasicBackForward) {
EXPECT_EQ(L"bot1", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot3.html")));
+ test_server_.GetURL("files/session_history/bot3.html")));
EXPECT_EQ(L"bot3", GetTabTitle());
// history is [blank, bot1, *bot3]
@@ -148,17 +152,15 @@ TEST_F(SessionHistoryTest, BasicBackForward) {
#define MAYBE_FrameBackForward FrameBackForward
#endif
TEST_F(SessionHistoryTest, MAYBE_FrameBackForward) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
// about:blank should be loaded first.
- GURL home(WideToUTF8(homepage_));
+ GURL home(homepage_);
ASSERT_FALSE(tab_->GoBack());
EXPECT_EQ(L"", GetTabTitle());
EXPECT_EQ(home, GetTabURL());
- GURL frames(server->TestServerPage("files/session_history/frames.html"));
+ GURL frames(test_server_.GetURL("files/session_history/frames.html"));
ASSERT_TRUE(tab_->NavigateToURL(frames));
EXPECT_EQ(L"bot1", GetTabTitle());
EXPECT_EQ(frames, GetTabURL());
@@ -214,15 +216,13 @@ TEST_F(SessionHistoryTest, MAYBE_FrameBackForward) {
// Test that back/forward preserves POST data and document state in subframes.
TEST_F(SessionHistoryTest, FrameFormBackForward) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
// about:blank should be loaded first.
ASSERT_FALSE(tab_->GoBack());
EXPECT_EQ(L"", GetTabTitle());
- GURL frames(server->TestServerPage("files/session_history/frames.html"));
+ GURL frames(test_server_.GetURL("files/session_history/frames.html"));
ASSERT_TRUE(tab_->NavigateToURL(frames));
EXPECT_EQ(L"bot1", GetTabTitle());
@@ -276,15 +276,13 @@ TEST_F(SessionHistoryTest, FrameFormBackForward) {
// across frames (ie, from frame -> nonframe).
// Hangs, see http://crbug.com/45058.
TEST_F(SessionHistoryTest, DISABLED_CrossFrameFormBackForward) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
// about:blank should be loaded first.
ASSERT_FALSE(tab_->GoBack());
EXPECT_EQ(L"", GetTabTitle());
- GURL frames(server->TestServerPage("files/session_history/frames.html"));
+ GURL frames(test_server_.GetURL("files/session_history/frames.html"));
ASSERT_TRUE(tab_->NavigateToURL(frames));
EXPECT_EQ(L"bot1", GetTabTitle());
@@ -321,16 +319,20 @@ TEST_F(SessionHistoryTest, DISABLED_CrossFrameFormBackForward) {
// Test that back/forward entries are created for reference fragment
// navigations. Bug 730379.
-TEST_F(SessionHistoryTest, FragmentBackForward) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+#if defined(OS_WIN)
+// http://crbug.com/55380 - NavigateToURL to making this flaky
+#define MAYBE_FragmentBackForward FLAKY_FragmentBackForward
+#else
+#define MAYBE_FragmentBackForward FragmentBackForward
+#endif
+TEST_F(SessionHistoryTest, MAYBE_FragmentBackForward) {
+ ASSERT_TRUE(test_server_.Start());
// about:blank should be loaded first.
ASSERT_FALSE(tab_->GoBack());
EXPECT_EQ(L"", GetTabTitle());
- GURL fragment(server->TestServerPage("files/session_history/fragment.html"));
+ GURL fragment(test_server_.GetURL("files/session_history/fragment.html"));
ASSERT_TRUE(tab_->NavigateToURL(fragment));
EXPECT_EQ(L"fragment", GetTabTitle());
EXPECT_EQ(fragment, GetTabURL());
@@ -369,7 +371,7 @@ TEST_F(SessionHistoryTest, FragmentBackForward) {
ASSERT_TRUE(tab_->GoForward());
EXPECT_EQ(fragment_a, GetTabURL());
- GURL bot3(server->TestServerPage("files/session_history/bot3.html"));
+ GURL bot3(test_server_.GetURL("files/session_history/bot3.html"));
ASSERT_TRUE(tab_->NavigateToURL(bot3));
EXPECT_EQ(L"bot3", GetTabTitle());
EXPECT_EQ(bot3, GetTabURL());
@@ -391,25 +393,26 @@ TEST_F(SessionHistoryTest, FragmentBackForward) {
// back/forward list (such as trigger our start/stop loading events). This
// means the test will hang if it attempts to navigate too far forward or back,
// since we'll be waiting forever for a load stop event.
-TEST_F(SessionHistoryTest, JavascriptHistory) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+//
+// TODO(brettw) bug 50648: fix flakyness. This test seems like it was failing
+// about 1/4 of the time on Vista by failing to execute JavascriptGo (see bug).
+TEST_F(SessionHistoryTest, FLAKY_JavascriptHistory) {
+ ASSERT_TRUE(test_server_.Start());
// about:blank should be loaded first.
ASSERT_FALSE(tab_->GoBack());
EXPECT_EQ(L"", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot1.html")));
+ test_server_.GetURL("files/session_history/bot1.html")));
EXPECT_EQ(L"bot1", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot2.html")));
+ test_server_.GetURL("files/session_history/bot2.html")));
EXPECT_EQ(L"bot2", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot3.html")));
+ test_server_.GetURL("files/session_history/bot3.html")));
EXPECT_EQ(L"bot3", GetTabTitle());
// history is [blank, bot1, bot2, *bot3]
@@ -441,7 +444,7 @@ TEST_F(SessionHistoryTest, JavascriptHistory) {
EXPECT_EQ(L"bot1", GetTabTitle());
ASSERT_TRUE(tab_->NavigateToURL(
- server->TestServerPage("files/session_history/bot3.html")));
+ test_server_.GetURL("files/session_history/bot3.html")));
EXPECT_EQ(L"bot3", GetTabTitle());
// history is [blank, bot1, *bot3]
@@ -474,13 +477,11 @@ TEST_F(SessionHistoryTest, JavascriptHistory) {
// This test is failing consistently. See http://crbug.com/22560
TEST_F(SessionHistoryTest, FAILS_LocationReplace) {
+ ASSERT_TRUE(test_server_.Start());
+
// Test that using location.replace doesn't leave the title of the old page
// visible.
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
-
- ASSERT_TRUE(tab_->NavigateToURL(server->TestServerPage(
+ ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL(
"files/session_history/replace.html?no-title.html")));
EXPECT_EQ(L"", GetTabTitle());
}
@@ -503,11 +504,9 @@ TEST_F(SessionHistoryTest, FLAKY_HistorySearchXSS) {
}
TEST_F(SessionHistoryTest, LocationChangeInSubframe) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(server.get());
+ ASSERT_TRUE(test_server_.Start());
- ASSERT_TRUE(tab_->NavigateToURL(server->TestServerPage(
+ ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL(
"files/session_history/location_redirect.html")));
EXPECT_EQ(L"Default Title", GetTabTitle());
@@ -519,28 +518,23 @@ TEST_F(SessionHistoryTest, LocationChangeInSubframe) {
EXPECT_EQ(L"Default Title", GetTabTitle());
}
-// Hangs, see http://crbug.com/38583.
-#if defined(OS_WIN)
-#define HistoryLength DISABLED_HistoryLength
-#endif // defined(OS_WIN)
-TEST_F(SessionHistoryTest, HistoryLength) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(server.get());
+// http://code.google.com/p/chromium/issues/detail?id=56267
+TEST_F(SessionHistoryTest, DISABLED_HistoryLength) {
+ ASSERT_TRUE(test_server_.Start());
int length;
ASSERT_TRUE(tab_->ExecuteAndExtractInt(
L"", L"domAutomationController.send(history.length)", &length));
EXPECT_EQ(1, length);
- ASSERT_TRUE(tab_->NavigateToURL(server->TestServerPage("files/title1.html")));
+ ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL("files/title1.html")));
ASSERT_TRUE(tab_->ExecuteAndExtractInt(
L"", L"domAutomationController.send(history.length)", &length));
EXPECT_EQ(2, length);
// Now test that history.length is updated when the navigation is committed.
- ASSERT_TRUE(tab_->NavigateToURL(server->TestServerPage(
+ ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL(
"files/session_history/record_length.html")));
ASSERT_TRUE(tab_->ExecuteAndExtractInt(
L"", L"domAutomationController.send(history.length)", &length));
@@ -553,7 +547,7 @@ TEST_F(SessionHistoryTest, HistoryLength) {
ASSERT_TRUE(tab_->GoBack());
// Ensure history.length is properly truncated.
- ASSERT_TRUE(tab_->NavigateToURL(server->TestServerPage("files/title2.html")));
+ ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL("files/title2.html")));
ASSERT_TRUE(tab_->ExecuteAndExtractInt(
L"", L"domAutomationController.send(history.length)", &length));
EXPECT_EQ(2, length);
diff --git a/chrome/browser/sessions/base_session_service.h b/chrome/browser/sessions/base_session_service.h
index a7aaa0d..cefe5d0 100644
--- a/chrome/browser/sessions/base_session_service.h
+++ b/chrome/browser/sessions/base_session_service.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_SESSIONS_BASE_SESSION_SERVICE_H_
#define CHROME_BROWSER_SESSIONS_BASE_SESSION_SERVICE_H_
+#pragma once
#include "base/basictypes.h"
#include "base/callback.h"
@@ -16,7 +17,6 @@ class NavigationEntry;
class Profile;
class SessionBackend;
class SessionCommand;
-class SessionService;
class TabNavigation;
namespace base {
diff --git a/chrome/browser/sessions/session_backend.cc b/chrome/browser/sessions/session_backend.cc
index c06f811..342c1f0 100644
--- a/chrome/browser/sessions/session_backend.cc
+++ b/chrome/browser/sessions/session_backend.cc
@@ -9,6 +9,7 @@
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/scoped_vector.h"
+#include "net/base/file_stream.h"
using base::TimeTicks;
@@ -335,6 +336,9 @@ bool SessionBackend::AppendCommandsToFile(net::FileStream* file,
return true;
}
+SessionBackend::~SessionBackend() {
+}
+
void SessionBackend::ResetFile() {
DCHECK(inited_);
if (current_session_file_.get()) {
diff --git a/chrome/browser/sessions/session_backend.h b/chrome/browser/sessions/session_backend.h
index 91c9bb7..883a58f 100644
--- a/chrome/browser/sessions/session_backend.h
+++ b/chrome/browser/sessions/session_backend.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_SESSIONS_SESSION_BACKEND_H_
#define CHROME_BROWSER_SESSIONS_SESSION_BACKEND_H_
+#pragma once
#include <vector>
@@ -11,9 +12,10 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/sessions/base_session_service.h"
#include "chrome/browser/sessions/session_command.h"
-#include "net/base/file_stream.h"
-class Pickle;
+namespace net {
+class FileStream;
+}
// SessionBackend -------------------------------------------------------------
@@ -94,7 +96,7 @@ class SessionBackend : public base::RefCountedThreadSafe<SessionBackend> {
private:
friend class base::RefCountedThreadSafe<SessionBackend>;
- ~SessionBackend() {}
+ ~SessionBackend();
// If current_session_file_ is open, it is truncated so that it is essentially
// empty (only contains the header). If current_session_file_ isn't open, it
diff --git a/chrome/browser/sessions/session_command.h b/chrome/browser/sessions/session_command.h
index beb7d85..edbf769 100644
--- a/chrome/browser/sessions/session_command.h
+++ b/chrome/browser/sessions/session_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SESSIONS_SESSION_COMMAND_H_
#define CHROME_BROWSER_SESSIONS_SESSION_COMMAND_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/sessions/session_id.h b/chrome/browser/sessions/session_id.h
index bab33c8..1731d59 100644
--- a/chrome/browser/sessions/session_id.h
+++ b/chrome/browser/sessions/session_id.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SESSIONS_SESSION_ID_H_
#define CHROME_BROWSER_SESSIONS_SESSION_ID_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index 6ec5a66..e0b49cd 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -22,6 +22,7 @@
#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/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
@@ -298,6 +299,33 @@ class SessionRestoreImpl : public NotificationObserver {
}
}
+ void RestoreForeignSession(std::vector<SessionWindow*>* windows) {
+ tab_loader_.reset(new TabLoader());
+ // Create a browser instance to put the restored tabs in.
+ bool has_tabbed_browser = false;
+ for (std::vector<SessionWindow*>::iterator i = (*windows).begin();
+ i != (*windows).end(); ++i) {
+ Browser* browser = NULL;
+ if (!has_tabbed_browser && (*i)->type == Browser::TYPE_NORMAL)
+ has_tabbed_browser = true;
+ browser = new Browser(static_cast<Browser::Type>((*i)->type),
+ profile_);
+ browser->set_override_bounds((*i)->bounds);
+ browser->set_maximized_state((*i)->is_maximized ?
+ Browser::MAXIMIZED_STATE_MAXIMIZED :
+ Browser::MAXIMIZED_STATE_UNMAXIMIZED);
+ browser->CreateBrowserWindow();
+
+ // Restore and show the browser.
+ const int initial_tab_count = browser->tab_count();
+ RestoreTabsToBrowser(*(*i), browser);
+ ShowBrowser(browser, initial_tab_count,
+ (*i)->selected_tab_index);
+ NotifySessionServiceOfRestoredTabs(browser, initial_tab_count);
+ FinishedTabCreation(true, has_tabbed_browser);
+ }
+ }
+
~SessionRestoreImpl() {
STLDeleteElements(&windows_);
restoring = false;
@@ -491,7 +519,8 @@ class SessionRestoreImpl : public NotificationObserver {
tab.extension_app_id,
false,
tab.pinned,
- true)->controller());
+ true,
+ NULL)->controller());
}
}
@@ -523,7 +552,7 @@ class SessionRestoreImpl : public NotificationObserver {
add_types |= TabStripModel::ADD_SELECTED;
int index = browser->GetIndexForInsertionDuringRestore(i);
browser->AddTabWithURL(urls[i], GURL(), PageTransition::START_PAGE, index,
- add_types, NULL, std::string());
+ add_types, NULL, std::string(), NULL);
}
}
@@ -614,6 +643,16 @@ void SessionRestore::RestoreSession(Profile* profile,
}
// static
+void SessionRestore::RestoreForeignSessionWindows(Profile* profile,
+ std::vector<SessionWindow*>* windows) {
+ // Create a SessionRestore object to eventually restore the tabs.
+ std::vector<GURL> gurls;
+ SessionRestoreImpl restorer(profile,
+ static_cast<Browser*>(NULL), true, false, true, gurls);
+ restorer.RestoreForeignSession(windows);
+}
+
+// static
void SessionRestore::RestoreSessionSynchronously(
Profile* profile,
const std::vector<GURL>& urls_to_open) {
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h
index ba09694..bb08868 100644
--- a/chrome/browser/sessions/session_restore.h
+++ b/chrome/browser/sessions/session_restore.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_H_
#define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_H_
+#pragma once
#include <vector>
#include "chrome/browser/history/history.h"
+#include "chrome/browser/sessions/session_types.h"
#include "base/basictypes.h"
class Browser;
@@ -34,6 +36,11 @@ class SessionRestore {
bool always_create_tabbed_browser,
const std::vector<GURL>& urls_to_open);
+ // Specifically used in the restoration of a foreign session. This method
+ // restores the given session windows to a browser.
+ static void RestoreForeignSessionWindows(Profile* profile,
+ std::vector<SessionWindow*>* windows);
+
// Synchronously restores the last session. At least one tabbed browser is
// created, even if there is an error in restoring.
//
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index e2752c1..19cf744 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/defaults.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"
#include "chrome/common/page_transition_types.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -75,13 +76,18 @@ IN_PROC_BROWSER_TEST_F(SessionRestoreTest, RestoreIndividualTabFromWindow) {
FilePath(FILE_PATH_LITERAL("title3.html"))));
// Add and navigate three tabs.
+ Browser* browser_used = NULL;
ui_test_utils::NavigateToURL(browser(), url1);
browser()->AddTabWithURL(url2, GURL(), PageTransition::LINK, 1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
ui_test_utils::WaitForNavigationInCurrentTab(browser());
browser()->AddTabWithURL(url3, GURL(), PageTransition::LINK, 2,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
ui_test_utils::WaitForNavigationInCurrentTab(browser());
TabRestoreService* service = browser()->profile()->GetTabRestoreService();
diff --git a/chrome/browser/sessions/session_restore_uitest.cc b/chrome/browser/sessions/session_restore_uitest.cc
index c5e5632..949bdf4 100644
--- a/chrome/browser/sessions/session_restore_uitest.cc
+++ b/chrome/browser/sessions/session_restore_uitest.cc
@@ -1,11 +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 "base/command_line.h"
#include "base/file_path.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/defaults.h"
#include "chrome/common/chrome_paths.h"
@@ -16,7 +16,7 @@
#include "chrome/test/ui/ui_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
namespace {
@@ -38,8 +38,8 @@ class SessionRestoreUITest : public UITest {
clear_profile_ = false;
- launch_arguments_.AppendSwitchWithValue(switches::kRestoreLastSession,
- IntToWString(expected_tab_count));
+ launch_arguments_.AppendSwitchASCII(switches::kRestoreLastSession,
+ base::IntToString(expected_tab_count));
UITest::SetUp();
}
@@ -144,11 +144,11 @@ TEST_F(SessionRestoreUITest, RestoresForwardAndBackwardNavs) {
// are given appropriate max page IDs, so that going back to a restored
// cross-site page and then forward again works. (Bug 1204135)
TEST_F(SessionRestoreUITest, RestoresCrossSiteForwardAndBackwardNavs) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL cross_site_url(server->TestServerPage("files/title2.html"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL cross_site_url(test_server.GetURL("files/title2.html"));
// Visit URLs on different sites.
NavigateToURL(url1_);
@@ -327,10 +327,10 @@ TEST_F(SessionRestoreUITest, NormalAndPopup) {
}
}
-#if defined(OS_MACOSX)
-// Fails an SQL assertion on Mac: http://crbug.com/45108
-#define DontRestoreWhileIncognito DISABLED_DontRestoreWhileIncognito
-#endif
+#if !defined(OS_MACOSX)
+// These tests don't apply to the Mac version; see
+// LaunchAnotherBrowserBlockUntilClosed for details.
+
// Creates a browser, goes incognito, closes browser, launches and make sure
// we don't restore.
//
@@ -376,38 +376,6 @@ TEST_F(SessionRestoreUITest, DontRestoreWhileIncognito) {
ASSERT_TRUE(url != url1_);
}
-// Creates two windows, closes one, restores, make sure only one window open.
-TEST_F(SessionRestoreUITest, TwoWindowsCloseOneRestoreOnlyOne) {
- NavigateToURL(url1_);
-
- // Make sure we have one window.
- int window_count;
- ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
- ASSERT_EQ(1, window_count);
-
- // Open a second window.
- ASSERT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_NORMAL,
- true));
- ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
- ASSERT_EQ(2, window_count);
-
- // Close it.
- CloseWindow(1, 2);
-
- // Restart and make sure we have only one window with one tab and the url
- // is url1_.
- QuitBrowserAndRestore(1);
-
- AssertOneWindowWithOneTab();
-
- ASSERT_EQ(url1_, GetActiveTabURL());
-}
-
-#if defined(OS_MACOSX)
-// Fails an SQL assertion on Mac: http://crbug.com/45108
-#define FLAKY_RestoreAfterClosingTabbedBrowserWithAppAndLaunching \
- DISABLED_RestoreAfterClosingTabbedBrowserWithAppAndLaunching
-#endif
// Launches an app window, closes tabbed browser, launches and makes sure
// we restore the tabbed browser url.
TEST_F(SessionRestoreUITest,
@@ -420,8 +388,7 @@ TEST_F(SessionRestoreUITest,
include_testing_id_ = false;
clear_profile_ = false;
CommandLine app_launch_arguments = launch_arguments_;
- app_launch_arguments.AppendSwitchWithValue(switches::kApp,
- UTF8ToWide(url2_.spec()));
+ app_launch_arguments.AppendSwitchASCII(switches::kApp, url2_.spec());
LaunchAnotherBrowserBlockUntilClosed(app_launch_arguments);
ASSERT_TRUE(automation()->WaitForWindowCountToBecome(2));
@@ -439,13 +406,48 @@ TEST_F(SessionRestoreUITest,
ASSERT_EQ(url1_, GetActiveTabURL());
}
+#endif // !OS_MACOSX
+
+// Creates two windows, closes one, restores, make sure only one window open.
+TEST_F(SessionRestoreUITest, TwoWindowsCloseOneRestoreOnlyOne) {
+ NavigateToURL(url1_);
+
+ // Make sure we have one window.
+ int window_count;
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ ASSERT_EQ(1, window_count);
+
+ // Open a second window.
+ ASSERT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_NORMAL,
+ true));
+ ASSERT_TRUE(automation()->GetBrowserWindowCount(&window_count));
+ ASSERT_EQ(2, window_count);
+
+ // Close it.
+ CloseWindow(1, 2);
+
+ // Restart and make sure we have only one window with one tab and the url
+ // is url1_.
+ QuitBrowserAndRestore(1);
+
+ AssertOneWindowWithOneTab();
+
+ ASSERT_EQ(url1_, GetActiveTabURL());
+}
+
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+// Flaky, sometimes times out: http://crbug.com/52022
+#define MAYBE_ShareProcessesOnRestore FLAKY_ShareProcessesOnRestore
+#else
+#define MAYBE_ShareProcessesOnRestore ShareProcessesOnRestore
+#endif
// Make sure after a restore the number of processes matches that of the number
// of processes running before the restore. This creates a new tab so that
// we should have two new tabs running. (This test will pass in both
// process-per-site and process-per-site-instance, because we treat the new tab
// as a special case in process-per-site-instance so that it only ever uses one
// process.)
-TEST_F(SessionRestoreUITest, ShareProcessesOnRestore) {
+TEST_F(SessionRestoreUITest, MAYBE_ShareProcessesOnRestore) {
if (in_process_renderer()) {
// No point in running this test in single process mode.
return;
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 802d88c..542d3e3 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -20,8 +20,8 @@
#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/session_startup_pref.h"
#include "chrome/browser/sessions/session_backend.h"
#include "chrome/browser/sessions/session_command.h"
#include "chrome/browser/sessions/session_restore.h"
@@ -29,6 +29,7 @@
#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/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h
index c8fa52f..96bb27c 100644
--- a/chrome/browser/sessions/session_service.h
+++ b/chrome/browser/sessions/session_service.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
#define CHROME_BROWSER_SESSIONS_SESSION_SERVICE_H_
+#pragma once
#include <map>
#include <string>
@@ -19,7 +20,6 @@
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class Browser;
class NavigationController;
class NavigationEntry;
class Profile;
diff --git a/chrome/browser/sessions/session_service_test_helper.h b/chrome/browser/sessions/session_service_test_helper.h
index 88f17c0..c0caa7e 100644
--- a/chrome/browser/sessions/session_service_test_helper.h
+++ b/chrome/browser/sessions/session_service_test_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SESSIONS_SESSION_SERVICE_TEST_HELPER_H_
#define CHROME_BROWSER_SESSIONS_SESSION_SERVICE_TEST_HELPER_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc
index 5b30328..17e41ed 100644
--- a/chrome/browser/sessions/session_service_unittest.cc
+++ b/chrome/browser/sessions/session_service_unittest.cc
@@ -7,8 +7,9 @@
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
#include "base/stl_util-inl.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/sessions/session_backend.h"
#include "chrome/browser/sessions/session_service.h"
@@ -22,6 +23,7 @@
#include "chrome/common/notification_type.h"
#include "chrome/test/browser_with_test_window_test.h"
#include "chrome/test/file_test_utils.h"
+#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
class SessionServiceTest : public BrowserWithTestWindowTest,
@@ -32,7 +34,7 @@ class SessionServiceTest : public BrowserWithTestWindowTest,
protected:
virtual void SetUp() {
BrowserWithTestWindowTest::SetUp();
- std::string b = Int64ToString(base::Time::Now().ToInternalValue());
+ std::string b = base::Int64ToString(base::Time::Now().ToInternalValue());
PathService::Get(base::DIR_TEMP, &path_);
path_ = path_.Append(FILE_PATH_LITERAL("SessionTestDirs"));
@@ -510,7 +512,7 @@ TEST_F(SessionServiceTest, PruneFromFront) {
// Add 5 navigations, with the 4th selected.
for (int i = 0; i < 5; ++i) {
- TabNavigation nav(0, GURL(base_url + IntToString(i)), GURL(),
+ TabNavigation nav(0, GURL(base_url + base::IntToString(i)), GURL(),
ASCIIToUTF16("a"), "b", PageTransition::QUALIFIER_MASK);
UpdateNavigation(window_id, tab_id, nav, i, (i == 3));
}
@@ -534,11 +536,11 @@ TEST_F(SessionServiceTest, PruneFromFront) {
SessionTab* tab = windows[0]->tabs[0];
ASSERT_EQ(1, tab->current_navigation_index);
EXPECT_EQ(3U, tab->navigations.size());
- EXPECT_TRUE(GURL(base_url + IntToString(2)) ==
+ EXPECT_TRUE(GURL(base_url + base::IntToString(2)) ==
tab->navigations[0].virtual_url());
- EXPECT_TRUE(GURL(base_url + IntToString(3)) ==
+ EXPECT_TRUE(GURL(base_url + base::IntToString(3)) ==
tab->navigations[1].virtual_url());
- EXPECT_TRUE(GURL(base_url + IntToString(4)) ==
+ EXPECT_TRUE(GURL(base_url + base::IntToString(4)) ==
tab->navigations[2].virtual_url());
}
@@ -551,7 +553,7 @@ TEST_F(SessionServiceTest, PruneToEmpty) {
// Add 5 navigations, with the 4th selected.
for (int i = 0; i < 5; ++i) {
- TabNavigation nav(0, GURL(base_url + IntToString(i)), GURL(),
+ TabNavigation nav(0, GURL(base_url + base::IntToString(i)), GURL(),
ASCIIToUTF16("a"), "b", PageTransition::QUALIFIER_MASK);
UpdateNavigation(window_id, tab_id, nav, i, (i == 3));
}
diff --git a/chrome/browser/sessions/session_types.cc b/chrome/browser/sessions/session_types.cc
index 6cf193c..995a9a2 100644
--- a/chrome/browser/sessions/session_types.cc
+++ b/chrome/browser/sessions/session_types.cc
@@ -11,6 +11,51 @@
// TabNavigation --------------------------------------------------------------
+TabNavigation::TabNavigation()
+ : transition_(PageTransition::TYPED),
+ type_mask_(0),
+ index_(-1) {
+}
+
+TabNavigation::TabNavigation(int index,
+ const GURL& virtual_url,
+ const GURL& referrer,
+ const string16& title,
+ const std::string& state,
+ PageTransition::Type transition)
+ : virtual_url_(virtual_url),
+ referrer_(referrer),
+ title_(title),
+ state_(state),
+ transition_(transition),
+ type_mask_(0),
+ index_(index) {
+}
+
+TabNavigation::TabNavigation(const TabNavigation& tab)
+ : virtual_url_(tab.virtual_url_),
+ referrer_(tab.referrer_),
+ title_(tab.title_),
+ state_(tab.state_),
+ transition_(tab.transition_),
+ type_mask_(tab.type_mask_),
+ index_(tab.index_) {
+}
+
+TabNavigation::~TabNavigation() {
+}
+
+TabNavigation& TabNavigation::operator=(const TabNavigation& tab) {
+ virtual_url_ = tab.virtual_url_;
+ referrer_ = tab.referrer_;
+ title_ = tab.title_;
+ state_ = tab.state_;
+ transition_ = tab.transition_;
+ type_mask_ = tab.type_mask_;
+ index_ = tab.index_;
+ return *this;
+}
+
// static
NavigationEntry* TabNavigation::ToNavigationEntry(int page_id,
Profile *profile) const {
@@ -39,6 +84,17 @@ void TabNavigation::SetFromNavigationEntry(const NavigationEntry& entry) {
type_mask_ = entry.has_post_data() ? TabNavigation::HAS_POST_DATA : 0;
}
+// SessionTab -----------------------------------------------------------------
+
+SessionTab::SessionTab()
+ : tab_visual_index(-1),
+ current_navigation_index(-1),
+ pinned(false) {
+}
+
+SessionTab::~SessionTab() {
+}
+
// SessionWindow ---------------------------------------------------------------
SessionWindow::SessionWindow()
@@ -51,3 +107,13 @@ SessionWindow::SessionWindow()
SessionWindow::~SessionWindow() {
STLDeleteElements(&tabs);
}
+
+// ForeignSession --------------------------------------------------------------
+
+ForeignSession::ForeignSession() : foreign_tession_tag("invalid") {
+}
+
+ForeignSession::~ForeignSession() {
+ STLDeleteElements(&windows);
+}
+
diff --git a/chrome/browser/sessions/session_types.h b/chrome/browser/sessions/session_types.h
index f7962da..119392a 100644
--- a/chrome/browser/sessions/session_types.h
+++ b/chrome/browser/sessions/session_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SESSIONS_SESSION_TYPES_H_
#define CHROME_BROWSER_SESSIONS_SESSION_TYPES_H_
+#pragma once
#include <string>
#include <vector>
@@ -30,25 +31,16 @@ class TabNavigation {
HAS_POST_DATA = 1
};
- TabNavigation()
- : transition_(PageTransition::TYPED),
- type_mask_(0),
- index_(-1) {
- }
-
+ TabNavigation();
TabNavigation(int index,
const GURL& virtual_url,
const GURL& referrer,
const string16& title,
const std::string& state,
- PageTransition::Type transition)
- : virtual_url_(virtual_url),
- referrer_(referrer),
- title_(title),
- state_(state),
- transition_(transition),
- type_mask_(0),
- index_(index) {}
+ PageTransition::Type transition);
+ TabNavigation(const TabNavigation& tab);
+ ~TabNavigation();
+ TabNavigation& operator=(const TabNavigation& tab);
// Converts this TabNavigation into a NavigationEntry with a page id of
// |page_id|. The caller owns the returned NavigationEntry.
@@ -87,7 +79,7 @@ class TabNavigation {
// This is used when determining the selected TabNavigation and only useful
// by BaseSessionService and SessionService.
void set_index(int index) { index_ = index; }
- int index() { return index_; }
+ int index() const { return index_; }
private:
friend class BaseSessionService;
@@ -106,10 +98,8 @@ class TabNavigation {
// SessionTab corresponds to a NavigationController.
struct SessionTab {
- SessionTab()
- : tab_visual_index(-1),
- current_navigation_index(-1),
- pinned(false) { }
+ SessionTab();
+ ~SessionTab();
// Unique id of the window.
SessionID window_id;
@@ -188,4 +178,16 @@ struct SessionWindow {
DISALLOW_COPY_AND_ASSIGN(SessionWindow);
};
+// Defines a foreign session for session sync. A foreign session is a session
+// on a remote chrome instance.
+struct ForeignSession {
+ ForeignSession();
+ ~ForeignSession();
+
+ // Unique tag for each session.
+ std::string foreign_tession_tag;
+ std::vector<SessionWindow*> windows;
+};
+
#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 720f3ae..5b5f59f 100644
--- a/chrome/browser/sessions/tab_restore_service.cc
+++ b/chrome/browser/sessions/tab_restore_service.cc
@@ -17,9 +17,11 @@
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_command.h"
#include "chrome/browser/sessions/session_types.h"
+#include "chrome/browser/sessions/tab_restore_service_observer.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/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
using base::Time;
@@ -182,17 +184,18 @@ TabRestoreService::~TabRestoreService() {
if (backend())
Save();
- FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceDestroyed(this));
+ FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
+ TabRestoreServiceDestroyed(this));
STLDeleteElements(&entries_);
STLDeleteElements(&staging_entries_);
time_factory_ = NULL;
}
-void TabRestoreService::AddObserver(Observer* observer) {
+void TabRestoreService::AddObserver(TabRestoreServiceObserver* observer) {
observer_list_.AddObserver(observer);
}
-void TabRestoreService::RemoveObserver(Observer* observer) {
+void TabRestoreService::RemoveObserver(TabRestoreServiceObserver* observer) {
observer_list_.RemoveObserver(observer);
}
@@ -318,6 +321,7 @@ void TabRestoreService::RestoreEntryById(Browser* browser,
if (entry->type == TAB) {
Tab* tab = static_cast<Tab*>(entry);
browser = RestoreTab(*tab, browser, replace_existing_tab);
+ browser->window()->Show();
} else if (entry->type == WINDOW) {
Browser* current_browser = browser;
Window* window = static_cast<Window*>(entry);
@@ -335,7 +339,8 @@ void TabRestoreService::RestoreEntryById(Browser* browser,
tab.extension_app_id,
(static_cast<int>(tab_i) ==
window->selected_tab_index),
- tab.pinned, tab.from_last_session);
+ tab.pinned, tab.from_last_session,
+ tab.session_storage_namespace);
if (restored_tab)
restored_tab->controller().LoadIfNecessary();
}
@@ -473,6 +478,8 @@ void TabRestoreService::PopulateTab(Tab* tab,
if (extension)
tab->extension_app_id = extension->id();
+ tab->session_storage_namespace = controller->session_storage_namespace();
+
// Browser may be NULL during unit tests.
if (browser) {
tab->browser_id = browser->session_id().id();
@@ -483,7 +490,8 @@ void TabRestoreService::PopulateTab(Tab* tab,
}
void TabRestoreService::NotifyTabsChanged() {
- FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceChanged(this));
+ FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_,
+ TabRestoreServiceChanged(this));
}
void TabRestoreService::AddEntry(Entry* entry, bool notify, bool to_front) {
@@ -862,7 +870,8 @@ Browser* TabRestoreService::RestoreTab(const Tab& tab,
browser->ReplaceRestoredTab(tab.navigations,
tab.current_navigation_index,
tab.from_last_session,
- tab.extension_app_id);
+ tab.extension_app_id,
+ tab.session_storage_namespace);
} else {
if (tab.has_browser())
browser = BrowserList::FindBrowserWithID(tab.browser_id);
@@ -885,7 +894,8 @@ Browser* TabRestoreService::RestoreTab(const Tab& tab,
tab_index,
tab.current_navigation_index,
tab.extension_app_id,
- true, tab.pinned, tab.from_last_session);
+ true, tab.pinned, tab.from_last_session,
+ tab.session_storage_namespace);
}
return browser;
}
diff --git a/chrome/browser/sessions/tab_restore_service.h b/chrome/browser/sessions/tab_restore_service.h
index 6b98d15..48c9dab 100644
--- a/chrome/browser/sessions/tab_restore_service.h
+++ b/chrome/browser/sessions/tab_restore_service.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_
#define CHROME_BROWSER_SESSIONS_TAB_RESTORE_SERVICE_H_
+#pragma once
#include <list>
#include <set>
@@ -11,6 +12,7 @@
#include "base/observer_list.h"
#include "base/time.h"
+#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
#include "chrome/browser/sessions/base_session_service.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/sessions/session_types.h"
@@ -18,6 +20,7 @@
class Browser;
class NavigationController;
class Profile;
+class TabRestoreServiceObserver;
struct SessionWindow;
// TabRestoreService is responsible for maintaining the most recently closed
@@ -33,18 +36,6 @@ struct SessionWindow;
// add an observer.
class TabRestoreService : public BaseSessionService {
public:
- // Observer is notified when the set of entries managed by TabRestoreService
- // changes in some way.
- class Observer {
- public:
- // Sent when the set of entries changes in some way.
- virtual void TabRestoreServiceChanged(TabRestoreService* service) = 0;
-
- // Sent to all remaining Observers when TabRestoreService's
- // destructor is run.
- virtual void TabRestoreServiceDestroyed(TabRestoreService* service) = 0;
- };
-
// Interface used to allow the test to provide a custom time.
class TimeFactory {
public:
@@ -104,6 +95,9 @@ class TabRestoreService : public BaseSessionService {
// If non-empty gives the id of the extension for the tab.
std::string extension_app_id;
+
+ // The associated session storage namespace (if any).
+ scoped_refptr<SessionStorageNamespace> session_storage_namespace;
};
// Represents a previously open window.
@@ -128,8 +122,8 @@ class TabRestoreService : public BaseSessionService {
// Adds/removes an observer. TabRestoreService does not take ownership of
// the observer.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
+ void AddObserver(TabRestoreServiceObserver* observer);
+ void RemoveObserver(TabRestoreServiceObserver* observer);
// Creates a Tab to represent |tab| and notifies observers the list of
// entries has changed.
@@ -171,6 +165,10 @@ class TabRestoreService : public BaseSessionService {
// Max number of entries we'll keep around.
static const size_t kMaxEntries;
+ // Creates and add entries to |entries| for each of the windows in |windows|.
+ void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows,
+ std::vector<Entry*>* entries);
+
protected:
virtual void Save();
@@ -287,11 +285,6 @@ class TabRestoreService : public BaseSessionService {
void OnGotPreviousSession(Handle handle,
std::vector<SessionWindow*>* windows);
- // Creates and add entries to |entries| for each of the windows in |windows|.
- void CreateEntriesFromWindows(
- std::vector<SessionWindow*>* windows,
- std::vector<Entry*>* entries);
-
// Converts a SessionWindow into a Window, returning true on success. We use 0
// as the timestamp here since we do not know when the window/tab was closed.
bool ConvertSessionWindowToWindow(
@@ -325,7 +318,7 @@ class TabRestoreService : public BaseSessionService {
// Number of entries we've written.
int entries_written_;
- ObserverList<Observer> observer_list_;
+ ObserverList<TabRestoreServiceObserver> observer_list_;
// Set of tabs that we've received a BrowserClosing method for but no
// corresponding BrowserClosed. We cache the set of browsers closing to
diff --git a/chrome/browser/sessions/tab_restore_service_unittest.cc b/chrome/browser/sessions/tab_restore_service_unittest.cc
deleted file mode 100644
index 742a1c6..0000000
--- a/chrome/browser/sessions/tab_restore_service_unittest.cc
+++ /dev/null
@@ -1,484 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// 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"
-#include "chrome/browser/sessions/tab_restore_service.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/test/testing_profile.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Create subclass that overrides TimeNow so that we can control the time used
-// for closed tabs and windows.
-class TabRestoreTimeFactory : public TabRestoreService::TimeFactory {
- public:
- TabRestoreTimeFactory() : time_(base::Time::Now()) {}
-
- virtual ~TabRestoreTimeFactory() {}
-
- virtual base::Time TimeNow() {
- return time_;
- }
-
- private:
- base::Time time_;
-};
-
-class TabRestoreServiceTest : public RenderViewHostTestHarness {
- public:
- TabRestoreServiceTest() {
- url1_ = GURL("http://1");
- url2_ = GURL("http://2");
- url3_ = GURL("http://3");
- }
-
- ~TabRestoreServiceTest() {
- }
-
- protected:
- // testing::Test overrides
- virtual void SetUp() {
- RenderViewHostTestHarness::SetUp();
- time_factory_ = new TabRestoreTimeFactory();
- service_ = new TabRestoreService(profile(), time_factory_);
- }
- virtual void TearDown() {
- service_ = NULL;
- delete time_factory_;
- RenderViewHostTestHarness::TearDown();
- }
-
- void AddThreeNavigations() {
- // Navigate to three URLs.
- NavigateAndCommit(url1_);
- NavigateAndCommit(url2_);
- NavigateAndCommit(url3_);
- }
-
- void NavigateToIndex(int index) {
- // Navigate back. We have to do this song and dance as NavigationController
- // isn't happy if you navigate immediately while going back.
- controller().GoToIndex(index);
- rvh()->SendNavigate(controller().pending_entry()->page_id(),
- controller().pending_entry()->url());
- }
-
- void RecreateService() {
- // Must set service to null first so that it is destroyed before the new
- // one is created.
- service_ = NULL;
- service_ = new TabRestoreService(profile(), time_factory_);
- service_->LoadTabsFromLastSession();
- }
-
- // Adds a window with one tab and url to the profile's session service.
- // If |pinned| is true, the tab is marked as pinned in the session service.
- void AddWindowWithOneTabToSessionService(bool pinned) {
- SessionService* session_service = profile()->GetSessionService();
- SessionID tab_id;
- SessionID window_id;
- session_service->SetWindowType(window_id, Browser::TYPE_NORMAL);
- session_service->SetTabWindow(window_id, tab_id);
- session_service->SetTabIndexInWindow(window_id, tab_id, 0);
- session_service->SetSelectedTabInWindow(window_id, 0);
- if (pinned)
- session_service->SetPinnedState(window_id, tab_id, true);
- NavigationEntry entry;
- entry.set_url(url1_);
- session_service->UpdateTabNavigation(window_id, tab_id, 0, entry);
- }
-
- // Creates a SessionService and assigns it to the Profile. The SessionService
- // is configured with a single window with a single tab pointing at url1_ by
- // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
- // tab is marked as pinned in the session service.
- void CreateSessionServiceWithOneWindow(bool pinned) {
- // The profile takes ownership of this.
- SessionService* session_service = new SessionService(profile());
- profile()->set_session_service(session_service);
-
- AddWindowWithOneTabToSessionService(pinned);
-
- // Set this, otherwise previous session won't be loaded.
- profile()->set_last_session_exited_cleanly(false);
- }
-
- GURL url1_;
- GURL url2_;
- GURL url3_;
- scoped_refptr<TabRestoreService> service_;
- TabRestoreTimeFactory* time_factory_;
-};
-
-TEST_F(TabRestoreServiceTest, Basic) {
- AddThreeNavigations();
-
- // Have the service record the tab.
- service_->CreateHistoricalTab(&controller());
-
- // Make sure an entry was created.
- ASSERT_EQ(1U, service_->entries().size());
-
- // Make sure the entry matches.
- TabRestoreService::Entry* entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
- EXPECT_FALSE(tab->pinned);
- EXPECT_TRUE(tab->extension_app_id.empty());
- ASSERT_EQ(3U, tab->navigations.size());
- EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
- EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
- EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
- EXPECT_EQ(2, tab->current_navigation_index);
- EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
- tab->timestamp.ToInternalValue());
-
- NavigateToIndex(1);
-
- // And check again.
- service_->CreateHistoricalTab(&controller());
-
- // There should be two entries now.
- ASSERT_EQ(2U, service_->entries().size());
-
- // Make sure the entry matches
- entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- tab = static_cast<TabRestoreService::Tab*>(entry);
- EXPECT_FALSE(tab->pinned);
- ASSERT_EQ(3U, tab->navigations.size());
- EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
- EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
- EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
- EXPECT_EQ(1, tab->current_navigation_index);
- EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
- tab->timestamp.ToInternalValue());
-}
-
-// Make sure TabRestoreService doesn't create an entry for a tab with no
-// navigations.
-TEST_F(TabRestoreServiceTest, DontCreateEmptyTab) {
- service_->CreateHistoricalTab(&controller());
- EXPECT_TRUE(service_->entries().empty());
-}
-
-// Tests restoring a single tab.
-TEST_F(TabRestoreServiceTest, Restore) {
- AddThreeNavigations();
-
- // Have the service record the tab.
- service_->CreateHistoricalTab(&controller());
-
- // Recreate the service and have it load the tabs.
- RecreateService();
-
- // One entry should be created.
- ASSERT_EQ(1U, service_->entries().size());
-
- // And verify the entry.
- TabRestoreService::Entry* entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
- EXPECT_FALSE(tab->pinned);
- ASSERT_EQ(3U, tab->navigations.size());
- EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
- EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
- EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
- EXPECT_EQ(2, tab->current_navigation_index);
- EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
- tab->timestamp.ToInternalValue());
-}
-
-// Tests restoring a single pinned tab.
-TEST_F(TabRestoreServiceTest, RestorePinnedAndApp) {
- AddThreeNavigations();
-
- // Have the service record the tab.
- service_->CreateHistoricalTab(&controller());
-
- // One entry should be created.
- ASSERT_EQ(1U, service_->entries().size());
-
- // We have to explicitly mark the tab as pinned as there is no browser for
- // these tests.
- TabRestoreService::Entry* entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
- tab->pinned = true;
- const std::string extension_app_id("test");
- tab->extension_app_id = extension_app_id;
-
- // Recreate the service and have it load the tabs.
- RecreateService();
-
- // One entry should be created.
- ASSERT_EQ(1U, service_->entries().size());
-
- // And verify the entry.
- entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- tab = static_cast<TabRestoreService::Tab*>(entry);
- EXPECT_TRUE(tab->pinned);
- ASSERT_EQ(3U, tab->navigations.size());
- EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
- EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
- EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
- EXPECT_EQ(2, tab->current_navigation_index);
- EXPECT_TRUE(extension_app_id == tab->extension_app_id);
-}
-
-// Crashes, http://crbug.com/45977.
-#if defined(OS_WIN)
-#define MAYBE_DontPersistPostData DISABLED_DontPersistPostData
-#else
-#define MAYBE_DontPersistPostData DontPersistPostData
-#endif // defined(OS_WIN)
-
-// Make sure we persist entries to disk that have post data.
-TEST_F(TabRestoreServiceTest, MAYBE_DontPersistPostData) {
- AddThreeNavigations();
- controller().GetEntryAtIndex(0)->set_has_post_data(true);
- controller().GetEntryAtIndex(1)->set_has_post_data(true);
- controller().GetEntryAtIndex(2)->set_has_post_data(true);
-
- // Have the service record the tab.
- service_->CreateHistoricalTab(&controller());
- ASSERT_EQ(1U, service_->entries().size());
-
- // Recreate the service and have it load the tabs.
- RecreateService();
-
- // One entry should be created.
- ASSERT_EQ(1U, service_->entries().size());
-
- const TabRestoreService::Entry* restored_entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
-
- const TabRestoreService::Tab* restored_tab =
- static_cast<const TabRestoreService::Tab*>(restored_entry);
- // There should be 3 navs.
- ASSERT_EQ(3U, restored_tab->navigations.size());
- EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
- restored_tab->timestamp.ToInternalValue());
-}
-
-// Make sure we don't persist entries to disk that have post data. This
-// differs from DontPersistPostData1 in that all the navigations have post
-// data, so that nothing should be persisted.
-TEST_F(TabRestoreServiceTest, DontLoadTwice) {
- AddThreeNavigations();
-
- // Have the service record the tab.
- service_->CreateHistoricalTab(&controller());
- ASSERT_EQ(1U, service_->entries().size());
-
- // Recreate the service and have it load the tabs.
- RecreateService();
-
- service_->LoadTabsFromLastSession();
-
- // There should only be one entry.
- ASSERT_EQ(1U, service_->entries().size());
-}
-
-// Makes sure we load the previous session as necessary.
-TEST_F(TabRestoreServiceTest, LoadPreviousSession) {
- CreateSessionServiceWithOneWindow(false);
-
- profile()->GetSessionService()->MoveCurrentSessionToLastSession();
-
- service_->LoadTabsFromLastSession();
-
- // Make sure we get back one entry with one tab whose url is url1.
- ASSERT_EQ(1U, service_->entries().size());
- TabRestoreService::Entry* entry2 = service_->entries().front();
- ASSERT_EQ(TabRestoreService::WINDOW, entry2->type);
- TabRestoreService::Window* window =
- static_cast<TabRestoreService::Window*>(entry2);
- ASSERT_EQ(1U, window->tabs.size());
- EXPECT_EQ(0, window->timestamp.ToInternalValue());
- EXPECT_EQ(0, window->selected_tab_index);
- ASSERT_EQ(1U, window->tabs[0].navigations.size());
- EXPECT_EQ(0, window->tabs[0].current_navigation_index);
- EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue());
- EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
-}
-
-// Makes sure we don't attempt to load previous sessions after a restore.
-TEST_F(TabRestoreServiceTest, DontLoadAfterRestore) {
- CreateSessionServiceWithOneWindow(false);
-
- profile()->GetSessionService()->MoveCurrentSessionToLastSession();
-
- profile()->set_restored_last_session(true);
-
- service_->LoadTabsFromLastSession();
-
- // Because we restored a session TabRestoreService shouldn't load the tabs.
- ASSERT_EQ(0U, service_->entries().size());
-}
-
-// Makes sure we don't attempt to load previous sessions after a clean exit.
-TEST_F(TabRestoreServiceTest, DontLoadAfterCleanExit) {
- CreateSessionServiceWithOneWindow(false);
-
- profile()->GetSessionService()->MoveCurrentSessionToLastSession();
-
- profile()->set_last_session_exited_cleanly(true);
-
- service_->LoadTabsFromLastSession();
-
- ASSERT_EQ(0U, service_->entries().size());
-}
-
-TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabs) {
- CreateSessionServiceWithOneWindow(false);
-
- profile()->GetSessionService()->MoveCurrentSessionToLastSession();
-
- AddThreeNavigations();
-
- service_->CreateHistoricalTab(&controller());
-
- RecreateService();
-
- // We should get back two entries, one from the previous session and one from
- // the tab restore service. The previous session entry should be first.
- ASSERT_EQ(2U, service_->entries().size());
- // The first entry should come from the session service.
- TabRestoreService::Entry* entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::WINDOW, entry->type);
- TabRestoreService::Window* window =
- static_cast<TabRestoreService::Window*>(entry);
- ASSERT_EQ(1U, window->tabs.size());
- EXPECT_EQ(0, window->selected_tab_index);
- EXPECT_EQ(0, window->timestamp.ToInternalValue());
- ASSERT_EQ(1U, window->tabs[0].navigations.size());
- EXPECT_EQ(0, window->tabs[0].current_navigation_index);
- EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue());
- EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
-
- // Then the closed tab.
- entry = *(++service_->entries().begin());
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
- ASSERT_FALSE(tab->pinned);
- ASSERT_EQ(3U, tab->navigations.size());
- EXPECT_EQ(2, tab->current_navigation_index);
- EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
- tab->timestamp.ToInternalValue());
- EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
- EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
- EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
-}
-
-// Make sure pinned state is correctly loaded from session service.
-TEST_F(TabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) {
- CreateSessionServiceWithOneWindow(true);
-
- profile()->GetSessionService()->MoveCurrentSessionToLastSession();
-
- AddThreeNavigations();
-
- service_->CreateHistoricalTab(&controller());
-
- RecreateService();
-
- // We should get back two entries, one from the previous session and one from
- // the tab restore service. The previous session entry should be first.
- ASSERT_EQ(2U, service_->entries().size());
- // The first entry should come from the session service.
- TabRestoreService::Entry* entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::WINDOW, entry->type);
- TabRestoreService::Window* window =
- static_cast<TabRestoreService::Window*>(entry);
- ASSERT_EQ(1U, window->tabs.size());
- EXPECT_EQ(0, window->selected_tab_index);
- EXPECT_TRUE(window->tabs[0].pinned);
- ASSERT_EQ(1U, window->tabs[0].navigations.size());
- EXPECT_EQ(0, window->tabs[0].current_navigation_index);
- EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
-
- // Then the closed tab.
- entry = *(++service_->entries().begin());
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
- ASSERT_FALSE(tab->pinned);
- ASSERT_EQ(3U, tab->navigations.size());
- EXPECT_EQ(2, tab->current_navigation_index);
- EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
- EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
- EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
-}
-
-// Creates TabRestoreService::kMaxEntries + 1 windows in the session service
-// and makes sure we only get back TabRestoreService::kMaxEntries on restore.
-TEST_F(TabRestoreServiceTest, ManyWindowsInSessionService) {
- CreateSessionServiceWithOneWindow(false);
-
- for (size_t i = 0; i < TabRestoreService::kMaxEntries; ++i)
- AddWindowWithOneTabToSessionService(false);
-
- profile()->GetSessionService()->MoveCurrentSessionToLastSession();
-
- AddThreeNavigations();
-
- service_->CreateHistoricalTab(&controller());
-
- RecreateService();
-
- // We should get back kMaxEntries entries. We added more, but
- // TabRestoreService only allows up to kMaxEntries.
- ASSERT_EQ(TabRestoreService::kMaxEntries, service_->entries().size());
-
- // The first entry should come from the session service.
- TabRestoreService::Entry* entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::WINDOW, entry->type);
- TabRestoreService::Window* window =
- static_cast<TabRestoreService::Window*>(entry);
- ASSERT_EQ(1U, window->tabs.size());
- EXPECT_EQ(0, window->selected_tab_index);
- EXPECT_EQ(0, window->timestamp.ToInternalValue());
- ASSERT_EQ(1U, window->tabs[0].navigations.size());
- EXPECT_EQ(0, window->tabs[0].current_navigation_index);
- EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue());
- EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
-}
-
-// Makes sure we restore the time stamp correctly.
-TEST_F(TabRestoreServiceTest, TimestampSurvivesRestore) {
- base::Time tab_timestamp(base::Time::FromInternalValue(123456789));
-
- AddThreeNavigations();
-
- // Have the service record the tab.
- service_->CreateHistoricalTab(&controller());
-
- // Make sure an entry was created.
- ASSERT_EQ(1U, service_->entries().size());
-
- // Make sure the entry matches.
- TabRestoreService::Entry* entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, entry->type);
- TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
- tab->timestamp = tab_timestamp;
-
- // Set this, otherwise previous session won't be loaded.
- profile()->set_last_session_exited_cleanly(false);
-
- RecreateService();
-
- // One entry should be created.
- ASSERT_EQ(1U, service_->entries().size());
-
- // And verify the entry.
- TabRestoreService::Entry* restored_entry = service_->entries().front();
- ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
- TabRestoreService::Tab* restored_tab =
- static_cast<TabRestoreService::Tab*>(restored_entry);
- EXPECT_EQ(tab_timestamp.ToInternalValue(),
- restored_tab->timestamp.ToInternalValue());
-}
diff --git a/chrome/browser/shell_dialogs.h b/chrome/browser/shell_dialogs.h
index fb6ff45..eac3f5e 100644
--- a/chrome/browser/shell_dialogs.h
+++ b/chrome/browser/shell_dialogs.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SHELL_DIALOGS_H_
#define CHROME_BROWSER_SHELL_DIALOGS_H_
+#pragma once
#include <string>
#include <vector>
@@ -33,6 +34,9 @@ class BaseShellDialog {
// Notifies the dialog box that the listener has been destroyed and it should
// no longer be sent notifications.
virtual void ListenerDestroyed() = 0;
+
+ protected:
+ virtual ~BaseShellDialog() {}
};
// Shows a dialog box for selecting a file or a folder.
@@ -68,6 +72,9 @@ class SelectFileDialog
// the user canceling or closing the selection dialog box, for example).
// |params| is contextual passed to SelectFile.
virtual void FileSelectionCanceled(void* params) {}
+
+ protected:
+ virtual ~Listener() {}
};
// Creates a dialog box helper. This object is ref-counted, but the returned
@@ -151,6 +158,9 @@ class SelectFontDialog
// canceling or closing the selection dialog box, for example). |params| is
// contextual passed to SelectFont.
virtual void FontSelectionCanceled(void* params) {}
+
+ protected:
+ virtual ~Listener() {}
};
// Creates a dialog box helper. This object is ref-counted, but the returned
diff --git a/chrome/browser/shell_integration.cc b/chrome/browser/shell_integration.cc
index 492bb06..3ed45ae 100644
--- a/chrome/browser/shell_integration.cc
+++ b/chrome/browser/shell_integration.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -30,21 +31,20 @@ std::string ShellIntegration::GetCommandLineArgumentsCommon(const GURL& url,
}
}
-#if defined (OS_CHROMEOS)
- std::wstring profile = cmd.GetSwitchValue(switches::kProfile);
+#if defined(OS_CHROMEOS)
+ FilePath profile = cmd.GetSwitchValuePath(switches::kLoginProfile);
if (!profile.empty()) {
- arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kProfile) +
- L"=\"" + profile + L"\" ";
+ arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kLoginProfile) +
+ L"=\"" + profile.ToWStringHack() + L"\" ";
}
#endif
// If |extension_app_id| is present, we use the kAppId switch rather than
// the kApp switch (the launch url will be read from the extension app
// during launch.
- if (cmd.HasSwitch(switches::kEnableApps) && !extension_app_id.empty()) {
+ if (!cmd.HasSwitch(switches::kDisableApps) && !extension_app_id.empty()) {
arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kAppId) +
- L"=\"" + ASCIIToWide(UTF16ToASCII(extension_app_id)) + L"\" --" +
- ASCIIToWide(switches::kEnableApps);
+ L"=\"" + ASCIIToWide(UTF16ToASCII(extension_app_id));
} else {
// Use '--app=url' instead of just 'url' to launch the browser with minimal
// chrome.
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h
index a468a46..68a2812 100644
--- a/chrome/browser/shell_integration.h
+++ b/chrome/browser/shell_integration.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SHELL_INTEGRATION_H_
#define CHROME_BROWSER_SHELL_INTEGRATION_H_
+#pragma once
#include <string>
@@ -17,7 +18,7 @@ class FilePath;
#if defined(USE_X11)
namespace base {
-class EnvVarGetter;
+class Environment;
}
#endif
@@ -77,7 +78,10 @@ class ShellIntegration {
const string16& extension_app_id);
#if defined(USE_X11)
- static bool GetDesktopShortcutTemplate(base::EnvVarGetter* env_getter,
+ // Returns filename of the desktop shortcut used to launch the browser.
+ static std::string GetDesktopName(base::Environment* env);
+
+ static bool GetDesktopShortcutTemplate(base::Environment* env,
std::string* output);
// Returns filename for .desktop file based on |url|, sanitized for security.
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index cf46e37..427d4ad 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -15,7 +15,7 @@
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/i18n/file_util_icu.h"
@@ -23,7 +23,9 @@
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/scoped_temp_dir.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
+#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
@@ -38,20 +40,6 @@
namespace {
-std::string GetDesktopName(base::EnvVarGetter* env_getter) {
-#if defined(GOOGLE_CHROME_BUILD)
- return "google-chrome.desktop";
-#else // CHROMIUM_BUILD
- // Allow $CHROME_DESKTOP to override the built-in value, so that development
- // versions can set themselves as the default without interfering with
- // non-official, packaged versions using the built-in value.
- std::string name;
- if (env_getter->GetEnv("CHROME_DESKTOP", &name) && !name.empty())
- return name;
- return "chromium-browser.desktop";
-#endif
-}
-
// Helper to launch xdg scripts. We don't want them to ask any questions on the
// terminal etc.
bool LaunchXdgUtility(const std::vector<std::string>& argv) {
@@ -111,7 +99,7 @@ std::string CreateShortcutIcon(
argv.push_back("user");
argv.push_back("--size");
- argv.push_back(IntToString(shortcut_info.favicon.width()));
+ argv.push_back(base::IntToString(shortcut_info.favicon.width()));
argv.push_back(temp_file_path.value());
std::string icon_name = temp_file_path.BaseName().RemoveExtension().value();
@@ -191,6 +179,21 @@ void CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename,
} // namespace
+// static
+std::string ShellIntegration::GetDesktopName(base::Environment* env) {
+#if defined(GOOGLE_CHROME_BUILD)
+ return "google-chrome.desktop";
+#else // CHROMIUM_BUILD
+ // Allow $CHROME_DESKTOP to override the built-in value, so that development
+ // versions can set themselves as the default without interfering with
+ // non-official, packaged versions using the built-in value.
+ std::string name;
+ if (env->GetVar("CHROME_DESKTOP", &name) && !name.empty())
+ return name;
+ return "chromium-browser.desktop";
+#endif
+}
+
// We delegate the difficulty of setting the default browser in Linux desktop
// environments to a new xdg utility, xdg-settings. We have to include a copy of
// it for this to work, obviously, but that's actually the suggested approach
@@ -198,13 +201,13 @@ void CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename,
// static
bool ShellIntegration::SetAsDefaultBrowser() {
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
std::vector<std::string> argv;
argv.push_back("xdg-settings");
argv.push_back("set");
argv.push_back("default-web-browser");
- argv.push_back(GetDesktopName(env_getter.get()));
+ argv.push_back(GetDesktopName(env.get()));
return LaunchXdgUtility(argv);
}
@@ -212,13 +215,13 @@ bool ShellIntegration::SetAsDefaultBrowser() {
ShellIntegration::DefaultBrowserState ShellIntegration::IsDefaultBrowser() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
std::vector<std::string> argv;
argv.push_back("xdg-settings");
argv.push_back("check");
argv.push_back("default-web-browser");
- argv.push_back(GetDesktopName(env_getter.get()));
+ argv.push_back(GetDesktopName(env.get()));
std::string reply;
if (!base::GetAppOutput(CommandLine(argv), &reply)) {
@@ -245,19 +248,19 @@ bool ShellIntegration::IsFirefoxDefaultBrowser() {
// static
bool ShellIntegration::GetDesktopShortcutTemplate(
- base::EnvVarGetter* env_getter, std::string* output) {
+ base::Environment* env, std::string* output) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
std::vector<FilePath> search_paths;
std::string xdg_data_home;
- if (env_getter->GetEnv("XDG_DATA_HOME", &xdg_data_home) &&
+ if (env->GetVar("XDG_DATA_HOME", &xdg_data_home) &&
!xdg_data_home.empty()) {
search_paths.push_back(FilePath(xdg_data_home));
}
std::string xdg_data_dirs;
- if (env_getter->GetEnv("XDG_DATA_DIRS", &xdg_data_dirs) &&
+ if (env->GetVar("XDG_DATA_DIRS", &xdg_data_dirs) &&
!xdg_data_dirs.empty()) {
StringTokenizer tokenizer(xdg_data_dirs, ":");
while (tokenizer.GetNext()) {
@@ -272,7 +275,7 @@ bool ShellIntegration::GetDesktopShortcutTemplate(
search_paths.push_back(FilePath("/usr/share/applications"));
search_paths.push_back(FilePath("/usr/local/share/applications"));
- std::string template_filename(GetDesktopName(env_getter));
+ std::string template_filename(GetDesktopName(env));
for (std::vector<FilePath>::const_iterator i = search_paths.begin();
i != search_paths.end(); ++i) {
FilePath path = (*i).Append(template_filename);
@@ -302,8 +305,8 @@ FilePath ShellIntegration::GetDesktopShortcutFilename(const GURL& url) {
FilePath alternative_filepath(filepath.value() + ".desktop");
for (size_t i = 1; i < 100; ++i) {
if (file_util::PathExists(FilePath(alternative_filepath))) {
- alternative_filepath = FilePath(filepath.value() + "_" + IntToString(i) +
- ".desktop");
+ alternative_filepath = FilePath(
+ filepath.value() + "_" + base::IntToString(i) + ".desktop");
} else {
return FilePath(alternative_filepath).BaseName();
}
diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc
index 0514781..9ea7021 100644
--- a/chrome/browser/shell_integration_unittest.cc
+++ b/chrome/browser/shell_integration_unittest.cc
@@ -12,6 +12,7 @@
#include "base/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths_internal.h"
@@ -21,7 +22,7 @@
#if defined(OS_WIN)
#include "chrome/installer/util/browser_distribution.h"
#elif defined(OS_LINUX)
-#include "base/env_var.h"
+#include "base/environment.h"
#endif // defined(OS_LINUX)
#define FPL FILE_PATH_LITERAL
@@ -30,16 +31,15 @@
namespace {
// Provides mock environment variables values based on a stored map.
-class MockEnvVarGetter : public base::EnvVarGetter {
+class MockEnvironment : public base::Environment {
public:
- MockEnvVarGetter() {
- }
+ MockEnvironment() {}
void Set(const std::string& name, const std::string& value) {
variables_[name] = value;
}
- virtual bool GetEnv(const char* variable_name, std::string* result) {
+ virtual bool GetVar(const char* variable_name, std::string* result) {
if (ContainsKey(variables_, variable_name)) {
*result = variables_[variable_name];
return true;
@@ -48,15 +48,20 @@ class MockEnvVarGetter : public base::EnvVarGetter {
return false;
}
- virtual bool SetEnv(const char* variable_name, const std::string& new_value) {
- NOTIMPLEMENTED();
+ virtual bool SetVar(const char* variable_name, const std::string& new_value) {
+ ADD_FAILURE();
+ return false;
+ }
+
+ virtual bool UnSetVar(const char* variable_name) {
+ ADD_FAILURE();
return false;
}
private:
std::map<std::string, std::string> variables_;
- DISALLOW_COPY_AND_ASSIGN(MockEnvVarGetter);
+ DISALLOW_COPY_AND_ASSIGN(MockEnvironment);
};
} // namespace
@@ -78,13 +83,13 @@ TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- MockEnvVarGetter env_getter;
- env_getter.Set("XDG_DATA_HOME", temp_dir.path().value());
+ MockEnvironment env;
+ env.Set("XDG_DATA_HOME", temp_dir.path().value());
ASSERT_TRUE(file_util::WriteFile(
temp_dir.path().AppendASCII(kTemplateFilename),
kTestData1, strlen(kTestData1)));
std::string contents;
- ASSERT_TRUE(ShellIntegration::GetDesktopShortcutTemplate(&env_getter,
+ ASSERT_TRUE(ShellIntegration::GetDesktopShortcutTemplate(&env,
&contents));
EXPECT_EQ(kTestData1, contents);
}
@@ -93,8 +98,8 @@ TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- MockEnvVarGetter env_getter;
- env_getter.Set("XDG_DATA_DIRS", temp_dir.path().value());
+ MockEnvironment env;
+ env.Set("XDG_DATA_DIRS", temp_dir.path().value());
ASSERT_TRUE(file_util::CreateDirectory(
temp_dir.path().AppendASCII("applications")));
ASSERT_TRUE(file_util::WriteFile(
@@ -102,7 +107,7 @@ TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
.AppendASCII(kTemplateFilename),
kTestData2, strlen(kTestData2)));
std::string contents;
- ASSERT_TRUE(ShellIntegration::GetDesktopShortcutTemplate(&env_getter,
+ ASSERT_TRUE(ShellIntegration::GetDesktopShortcutTemplate(&env,
&contents));
EXPECT_EQ(kTestData2, contents);
}
@@ -111,8 +116,8 @@ TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- MockEnvVarGetter env_getter;
- env_getter.Set("XDG_DATA_DIRS", temp_dir.path().value() + ":" +
+ MockEnvironment env;
+ env.Set("XDG_DATA_DIRS", temp_dir.path().value() + ":" +
temp_dir.path().AppendASCII("applications").value());
ASSERT_TRUE(file_util::CreateDirectory(
temp_dir.path().AppendASCII("applications")));
@@ -124,7 +129,7 @@ TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
.AppendASCII(kTemplateFilename),
kTestData2, strlen(kTestData2)));
std::string contents;
- ASSERT_TRUE(ShellIntegration::GetDesktopShortcutTemplate(&env_getter,
+ ASSERT_TRUE(ShellIntegration::GetDesktopShortcutTemplate(&env,
&contents));
EXPECT_EQ(kTestData1, contents);
}
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index d7aa86e..46c05a9 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -9,7 +9,6 @@
#include <shlobj.h>
#include <shobjidl.h>
-#include "app/win_util.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop.h"
@@ -18,6 +17,7 @@
#include "base/scoped_comptr_win.h"
#include "base/string_util.h"
#include "base/task.h"
+#include "base/utf_string_conversions.h"
#include "base/win_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/web_applications/web_app.h"
@@ -218,14 +218,15 @@ bool MigrateChromiumShortcutsTask::GetExpectedAppId(
FilePath profile_path;
if (command_line.HasSwitch(switches::kUserDataDir)) {
- profile_path = FilePath(command_line.GetSwitchValue(
- switches::kUserDataDir)).Append(chrome::kNotSignedInProfile);
+ profile_path =
+ command_line.GetSwitchValuePath(switches::kUserDataDir).Append(
+ chrome::kNotSignedInProfile);
}
std::wstring app_name;
if (command_line.HasSwitch(switches::kApp)) {
- app_name = web_app::GenerateApplicationNameFromURL(
- GURL(command_line.GetSwitchValueASCII(switches::kApp)));
+ app_name = UTF8ToWide(web_app::GenerateApplicationNameFromURL(
+ GURL(command_line.GetSwitchValueASCII(switches::kApp))));
} else {
app_name = BrowserDistribution::GetDistribution()->GetBrowserAppId();
}
diff --git a/chrome/browser/spellcheck_host.cc b/chrome/browser/spellcheck_host.cc
index 7ac1a3f..ceead6b 100644
--- a/chrome/browser/spellcheck_host.cc
+++ b/chrome/browser/spellcheck_host.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.
@@ -10,9 +10,10 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
+#include "base/string_split.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/pref_member.h"
#include "chrome/browser/spellcheck_host_observer.h"
#include "chrome/browser/spellchecker_platform_engine.h"
#include "chrome/common/chrome_constants.h"
@@ -31,11 +32,13 @@ FilePath GetFirstChoiceFilePath(const std::string& language) {
return SpellCheckCommon::GetVersionedFileName(language, dict_dir);
}
+#if defined(OS_WIN)
FilePath GetFallbackFilePath(const FilePath& first_choice) {
FilePath dict_dir;
PathService::Get(chrome::DIR_USER_DATA, &dict_dir);
return dict_dir.Append(first_choice.BaseName());
}
+#endif
} // namespace
@@ -164,9 +167,10 @@ void SpellCheckHost::InitializeInternal() {
if (!observer_)
return;
- file_ = base::CreatePlatformFile(bdict_file_path_,
+ file_ = base::CreatePlatformFile(
+ bdict_file_path_,
base::PLATFORM_FILE_READ | base::PLATFORM_FILE_OPEN,
- NULL);
+ NULL, NULL);
// File didn't exist. Download it.
if (file_ == base::kInvalidPlatformFileValue && !tried_to_download_ &&
@@ -220,8 +224,9 @@ void SpellCheckHost::DownloadDictionary() {
// Determine URL of file to download.
static const char kDownloadServerUrl[] =
"http://cache.pack.google.com/edgedl/chrome/dict/";
- GURL url = GURL(std::string(kDownloadServerUrl) + WideToUTF8(
- l10n_util::ToLower(bdict_file_path_.BaseName().ToWStringHack())));
+ GURL url = GURL(std::string(kDownloadServerUrl) +
+ StringToLowerASCII(WideToUTF8(
+ bdict_file_path_.BaseName().ToWStringHack())));
fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
fetcher_->set_request_context(request_context_getter_);
tried_to_download_ = true;
diff --git a/chrome/browser/spellcheck_host.h b/chrome/browser/spellcheck_host.h
index da6305d..452ea6a 100644
--- a/chrome/browser/spellcheck_host.h
+++ b/chrome/browser/spellcheck_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SPELLCHECK_HOST_H_
#define CHROME_BROWSER_SPELLCHECK_HOST_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/spellcheck_host_observer.h b/chrome/browser/spellcheck_host_observer.h
index cd324f8..91d135a 100644
--- a/chrome/browser/spellcheck_host_observer.h
+++ b/chrome/browser/spellcheck_host_observer.h
@@ -4,16 +4,23 @@
#ifndef CHROME_BROWSER_SPELLCHECK_HOST_OBSERVER_H_
#define CHROME_BROWSER_SPELLCHECK_HOST_OBSERVER_H_
+#pragma once
// Observer for the SpellCheckHost.
class SpellCheckHostObserver {
public:
// Invoked on the UI thread when SpellCheckHost is initialized.
virtual void SpellCheckHostInitialized() = 0;
+<<<<<<< HEAD
#ifdef ANDROID
// TODO: Upstream
virtual ~SpellCheckHostObserver() { }
#endif
+=======
+
+ protected:
+ virtual ~SpellCheckHostObserver() {}
+>>>>>>> Chromium at release 7.0.540.0
};
#endif // CHROME_BROWSER_SPELLCHECK_HOST_OBSERVER_H_
diff --git a/chrome/browser/spellchecker_platform_engine.h b/chrome/browser/spellchecker_platform_engine.h
index 5762ab2..edc8f31 100644
--- a/chrome/browser/spellchecker_platform_engine.h
+++ b/chrome/browser/spellchecker_platform_engine.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_SPELLCHECKER_PLATFORM_ENGINE_H_
#define CHROME_BROWSER_SPELLCHECKER_PLATFORM_ENGINE_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/browser/spellchecker_platform_engine_unittest.cc b/chrome/browser/spellchecker_platform_engine_unittest.cc
index a63bf67..7c2b9f0 100644
--- a/chrome/browser/spellchecker_platform_engine_unittest.cc
+++ b/chrome/browser/spellchecker_platform_engine_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/spellchecker_platform_engine.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/ssl/ssl_add_cert_handler.cc b/chrome/browser/ssl/ssl_add_cert_handler.cc
index 691e877..b6430a7 100644
--- a/chrome/browser/ssl/ssl_add_cert_handler.cc
+++ b/chrome/browser/ssl/ssl_add_cert_handler.cc
@@ -4,45 +4,54 @@
#include "chrome/browser/ssl/ssl_add_cert_handler.h"
-#include "app/l10n_util.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/platform_util.h"
-#include "grit/generated_resources.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_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "net/base/cert_database.h"
#include "net/base/net_errors.h"
#include "net/base/x509_certificate.h"
#include "net/url_request/url_request.h"
SSLAddCertHandler::SSLAddCertHandler(URLRequest* request,
- net::X509Certificate* cert)
- : cert_(cert) {
- // Stay alive until the UI completes and Finished() is called.
+ net::X509Certificate* cert,
+ int render_process_host_id,
+ int render_view_id)
+ : cert_(cert),
+ render_process_host_id_(render_process_host_id),
+ render_view_id_(render_view_id) {
+ ResourceDispatcherHostRequestInfo* info =
+ ResourceDispatcherHost::InfoForRequest(request);
+ network_request_id_ = info->request_id();
+ // Stay alive until the process completes and Finished() is called.
AddRef();
+ // Delay adding the certificate until the next mainloop iteration.
ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &SSLAddCertHandler::RunUI));
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &SSLAddCertHandler::Run));
}
-void SSLAddCertHandler::RunUI() {
+void SSLAddCertHandler::Run() {
int cert_error;
{
net::CertDatabase db;
cert_error = db.CheckUserCert(cert_);
}
if (cert_error != net::OK) {
- // TODO(snej): Map cert_error to a more specific error message.
- ShowError(l10n_util::GetStringFUTF16(
- IDS_ADD_CERT_ERR_INVALID_CERT,
- IntToString16(-cert_error),
- ASCIIToUTF16(net::ErrorToString(cert_error))));
+ CallRenderViewHostSSLDelegate(
+ render_process_host_id_, render_view_id_,
+ &RenderViewHostDelegate::SSL::OnVerifyClientCertificateError,
+ scoped_refptr<SSLAddCertHandler>(this), cert_error);
Finished(false);
return;
}
- AskToAddCert();
+ // TODO(davidben): Move the existing certificate dialog elsewhere, make
+ // AskToAddCert send a message to the RenderViewHostDelegate, and ask when we
+ // cannot completely verify the certificate for whatever reason.
+
+ // AskToAddCert();
+ Finished(true);
}
#if !defined(OS_MACOSX)
@@ -57,20 +66,22 @@ void SSLAddCertHandler::Finished(bool add_cert) {
net::CertDatabase db;
int cert_error = db.AddUserCert(cert_);
if (cert_error != net::OK) {
- // TODO(snej): Map cert_error to a more specific error message.
- ShowError(l10n_util::GetStringFUTF16(
- IDS_ADD_CERT_ERR_FAILED,
- IntToString16(-cert_error),
- ASCIIToUTF16(net::ErrorToString(cert_error))));
+ CallRenderViewHostSSLDelegate(
+ render_process_host_id_, render_view_id_,
+ &RenderViewHostDelegate::SSL::OnAddClientCertificateError,
+ scoped_refptr<SSLAddCertHandler>(this), cert_error);
+ } else {
+ CallRenderViewHostSSLDelegate(
+ render_process_host_id_, render_view_id_,
+ &RenderViewHostDelegate::SSL::OnAddClientCertificateSuccess,
+ scoped_refptr<SSLAddCertHandler>(this));
}
}
- Release();
-}
+ // Inform the RVH that we're finished
+ CallRenderViewHostSSLDelegate(
+ render_process_host_id_, render_view_id_,
+ &RenderViewHostDelegate::SSL::OnAddClientCertificateFinished,
+ scoped_refptr<SSLAddCertHandler>(this));
-void SSLAddCertHandler::ShowError(const string16& error) {
- Browser* browser = BrowserList::GetLastActive();
- platform_util::SimpleErrorBox(
- browser ? browser->window()->GetNativeHandle() : NULL,
- l10n_util::GetStringUTF16(IDS_ADD_CERT_FAILURE_TITLE),
- error);
+ Release();
}
diff --git a/chrome/browser/ssl/ssl_add_cert_handler.h b/chrome/browser/ssl/ssl_add_cert_handler.h
index 0680128..0c4ec22 100644
--- a/chrome/browser/ssl/ssl_add_cert_handler.h
+++ b/chrome/browser/ssl/ssl_add_cert_handler.h
@@ -4,10 +4,10 @@
#ifndef CHROME_BROWSER_SSL_SSL_ADD_CERT_HANDLER_H_
#define CHROME_BROWSER_SSL_SSL_ADD_CERT_HANDLER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
-#include "base/string16.h"
namespace net {
class X509Certificate;
@@ -20,10 +20,13 @@ class URLRequest;
// It is self-owned and deletes itself when finished.
class SSLAddCertHandler : public base::RefCountedThreadSafe<SSLAddCertHandler> {
public:
- SSLAddCertHandler(URLRequest* request, net::X509Certificate* cert);
+ SSLAddCertHandler(URLRequest* request, net::X509Certificate* cert,
+ int render_process_host_id, int render_view_id);
net::X509Certificate* cert() { return cert_; }
+ int network_request_id() const { return network_request_id_; }
+
// The platform-specific code calls this when it's done, to clean up.
// If |addCert| is true, the cert will be added to the CertDatabase.
void Finished(bool add_cert);
@@ -31,19 +34,23 @@ class SSLAddCertHandler : public base::RefCountedThreadSafe<SSLAddCertHandler> {
private:
friend class base::RefCountedThreadSafe<SSLAddCertHandler>;
- // Runs the user interface. Called on the UI thread. Calls AskToAddCert.
- void RunUI();
+ // Runs the handler. Called on the IO thread.
+ void Run();
// Platform-specific code that asks the user whether to add the cert.
// Called on the UI thread.
void AskToAddCert();
- // Utility to display an error message in a dialog box.
- void ShowError(const string16& error);
-
// The cert to add.
scoped_refptr<net::X509Certificate> cert_;
+ // The id of the request which started the process.
+ int network_request_id_;
+ // The id of the |RenderProcessHost| which started the download.
+ int render_process_host_id_;
+ // The id of the |RenderView| which started the download.
+ int render_view_id_;
+
DISALLOW_COPY_AND_ASSIGN(SSLAddCertHandler);
};
diff --git a/chrome/browser/ssl/ssl_add_cert_handler_mac.mm b/chrome/browser/ssl/ssl_add_cert_handler_mac.mm
index 75b8142..0f79a1c 100644
--- a/chrome/browser/ssl/ssl_add_cert_handler_mac.mm
+++ b/chrome/browser/ssl/ssl_add_cert_handler_mac.mm
@@ -8,6 +8,7 @@
#include <SecurityInterface/SFCertificateView.h>
#include "app/l10n_util_mac.h"
+#include "base/logging.h"
#include "base/scoped_nsobject.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/browser/browser_list.h"
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index b6be8ed..9a1ba76 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.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,11 +9,12 @@
#include "base/histogram.h"
#include "base/i18n/rtl.h"
#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/cert_store.h"
#include "chrome/browser/dom_operation_notification_details.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ssl/ssl_cert_error_handler.h"
@@ -67,30 +68,32 @@ std::string SSLBlockingPage::GetHTMLContents() {
// Let's build the html error page.
DictionaryValue strings;
SSLErrorInfo error_info = delegate_->GetSSLErrorInfo(handler_);
- strings.SetString(L"headLine", error_info.title());
- strings.SetString(L"description", error_info.details());
+ strings.SetString("headLine", WideToUTF16Hack(error_info.title()));
+ strings.SetString("description", WideToUTF16Hack(error_info.details()));
- strings.SetString(L"moreInfoTitle",
- l10n_util::GetString(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
+ strings.SetString("moreInfoTitle",
+ l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
SetExtraInfo(&strings, error_info.extra_information());
int resource_id;
if (error_level_ == ERROR_OVERRIDABLE) {
resource_id = IDR_SSL_ROAD_BLOCK_HTML;
- strings.SetString(L"title",
- l10n_util::GetString(IDS_SSL_BLOCKING_PAGE_TITLE));
- strings.SetString(L"proceed",
- l10n_util::GetString(IDS_SSL_BLOCKING_PAGE_PROCEED));
- strings.SetString(L"exit",
- l10n_util::GetString(IDS_SSL_BLOCKING_PAGE_EXIT));
+ strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
+ strings.SetString("proceed",
+ l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_PROCEED));
+ strings.SetString("exit",
+ l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_EXIT));
} else {
DCHECK_EQ(error_level_, ERROR_FATAL);
resource_id = IDR_SSL_ERROR_HTML;
- strings.SetString(L"title", l10n_util::GetString(IDS_SSL_ERROR_PAGE_TITLE));
- strings.SetString(L"back", l10n_util::GetString(IDS_SSL_ERROR_PAGE_BACK));
+ strings.SetString("title",
+ l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_TITLE));
+ strings.SetString("back",
+ l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_BACK));
}
- strings.SetString(L"textdirection", base::i18n::IsRTL() ? L"rtl" : L"ltr");
+ strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
base::StringPiece html(
ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id));
@@ -157,14 +160,14 @@ void SSLBlockingPage::SetExtraInfo(
DictionaryValue* strings,
const std::vector<std::wstring>& extra_info) {
DCHECK(extra_info.size() < 5); // We allow 5 paragraphs max.
- const std::wstring keys[5] = {
- L"moreInfo1", L"moreInfo2", L"moreInfo3", L"moreInfo4", L"moreInfo5"
+ const char* keys[5] = {
+ "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
};
int i;
for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
- strings->SetString(keys[i], extra_info[i]);
+ strings->SetString(keys[i], WideToUTF16Hack(extra_info[i]));
}
- for (;i < 5; i++) {
- strings->SetString(keys[i], L"");
+ for (; i < 5; i++) {
+ strings->SetString(keys[i], "");
}
}
diff --git a/chrome/browser/ssl/ssl_blocking_page.h b/chrome/browser/ssl/ssl_blocking_page.h
index 2f85c07..0e76152 100644
--- a/chrome/browser/ssl/ssl_blocking_page.h
+++ b/chrome/browser/ssl/ssl_blocking_page.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_BLOCKING_PAGE_H_
#define CHROME_BROWSER_SSL_SSL_BLOCKING_PAGE_H_
+#pragma once
#include <string>
@@ -31,6 +32,9 @@ class SSLBlockingPage : public InterstitialPage {
// Notification that the user chose to accept the certificate.
virtual void OnAllowCertificate(SSLCertErrorHandler* handler) = 0;
+
+ protected:
+ virtual ~Delegate() {}
};
// The severity of the certificate error.
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 10a1200..a897e1b 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -3,36 +3,34 @@
// found in the LICENSE file.
#include "base/time.h"
+#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/pref_service.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/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+#include "net/base/cert_status_flags.h"
+#include "net/test/test_server.h"
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
class SSLUITest : public InProcessBrowserTest {
public:
- SSLUITest() {
+ SSLUITest()
+ : https_server_(net::TestServer::TYPE_HTTPS, FilePath(kDocRoot)),
+ https_server_expired_(net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE,
+ FilePath(kDocRoot)),
+ https_server_mismatched_(
+ net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME,
+ FilePath(kDocRoot)) {
EnableDOMAutomation();
}
- scoped_refptr<HTTPTestServer> PlainServer() {
- return HTTPTestServer::CreateServer(kDocRoot, NULL);
- }
-
- scoped_refptr<HTTPSTestServer> GoodCertServer() {
- return HTTPSTestServer::CreateGoodServer(kDocRoot);
- }
-
- scoped_refptr<HTTPSTestServer> BadCertServer() {
- return HTTPSTestServer::CreateExpiredServer(kDocRoot);
- }
-
void CheckAuthenticatedState(TabContents* tab,
bool displayed_insecure_content) {
NavigationEntry* entry = tab->controller().GetActiveEntry();
@@ -114,17 +112,20 @@ class SSLUITest : public InProcessBrowserTest {
ui_test_utils::WaitForNavigation(&(tab->controller()));
}
+ net::TestServer https_server_;
+ net::TestServer https_server_expired_;
+ net::TestServer https_server_mismatched_;
+
private:
DISALLOW_COPY_AND_ASSIGN(SSLUITest);
};
// Visits a regular page over http.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTP) {
- scoped_refptr<HTTPTestServer> server = PlainServer();
- ASSERT_TRUE(server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
ui_test_utils::NavigateToURL(browser(),
- server->TestServerPage("files/ssl/google.html"));
+ test_server()->GetURL("files/ssl/google.html"));
CheckUnauthenticatedState(browser()->GetSelectedTabContents());
}
@@ -134,35 +135,31 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTP) {
// TODO(jcampan): test that bad HTTPS content is blocked (otherwise we'll give
// the secure cookies away!).
IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPWithBrokenHTTPSResource) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_expired_.Start());
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/page_with_unsafe_contents.html"));
+ test_server()->GetURL("files/ssl/page_with_unsafe_contents.html"));
CheckUnauthenticatedState(browser()->GetSelectedTabContents());
}
// Visits a page over OK https:
IN_PROC_BROWSER_TEST_F(SSLUITest, TestOKHTTPS) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
ui_test_utils::NavigateToURL(browser(),
- https_server->TestServerPage("files/ssl/google.html"));
+ https_server_.GetURL("files/ssl/google.html"));
CheckAuthenticatedState(browser()->GetSelectedTabContents(), false);
}
// Visits a page with https error and proceed:
IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSExpiredCertAndProceed) {
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_expired_.Start());
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/google.html"));
+ https_server_expired_.GetURL("files/ssl/google.html"));
TabContents* tab = browser()->GetSelectedTabContents();
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
@@ -186,23 +183,20 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSExpiredCertAndProceed) {
FLAKY_TestHTTPSExpiredCertAndDontProceed
#endif
IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestHTTPSExpiredCertAndDontProceed) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
// First navigate to an OK page.
ui_test_utils::NavigateToURL(browser(),
- good_https_server->TestServerPage("files/ssl/google.html"));
+ https_server_.GetURL("files/ssl/google.html"));
TabContents* tab = browser()->GetSelectedTabContents();
NavigationEntry* entry = tab->controller().GetActiveEntry();
ASSERT_TRUE(entry);
GURL cross_site_url =
- bad_https_server->TestServerPage("files/ssl/google.html");
+ https_server_expired_.GetURL("files/ssl/google.html");
// Change the host name from 127.0.0.1 to localhost so it triggers a
// cross-site navigation so we can test http://crbug.com/5800 is gone.
ASSERT_EQ("127.0.0.1", cross_site_url.host());
@@ -228,27 +222,25 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestHTTPSExpiredCertAndDontProceed) {
// Try to navigate to a new page. (to make sure bug 5800 is fixed).
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/google.html"));
+ test_server()->GetURL("files/ssl/google.html"));
CheckUnauthenticatedState(tab);
}
// Visits a page with https error and then goes back using Browser::GoBack.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSExpiredCertAndGoBackViaButton) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_expired_.Start());
// First navigate to an HTTP page.
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/google.html"));
+ test_server()->GetURL("files/ssl/google.html"));
TabContents* tab = browser()->GetSelectedTabContents();
NavigationEntry* entry = tab->controller().GetActiveEntry();
ASSERT_TRUE(entry);
// Now go to a bad HTTPS page that shows an interstitial.
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/google.html"));
+ https_server_expired_.GetURL("files/ssl/google.html"));
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
true); // Interstitial showing
@@ -263,21 +255,19 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSExpiredCertAndGoBackViaButton) {
// Visits a page with https error and then goes back using GoToOffset.
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestHTTPSExpiredCertAndGoBackViaMenu) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_expired_.Start());
// First navigate to an HTTP page.
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/google.html"));
+ test_server()->GetURL("files/ssl/google.html"));
TabContents* tab = browser()->GetSelectedTabContents();
NavigationEntry* entry = tab->controller().GetActiveEntry();
ASSERT_TRUE(entry);
// Now go to a bad HTTPS page that shows an interstitial.
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/google.html"));
+ https_server_expired_.GetURL("files/ssl/google.html"));
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
true); // Interstitial showing
@@ -292,19 +282,17 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestHTTPSExpiredCertAndGoBackViaMenu) {
// Visits a page with https error and then goes forward using GoToOffset.
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestHTTPSExpiredCertAndGoForward) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_expired_.Start());
// First navigate to two HTTP pages.
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/google.html"));
+ test_server()->GetURL("files/ssl/google.html"));
TabContents* tab = browser()->GetSelectedTabContents();
NavigationEntry* entry1 = tab->controller().GetActiveEntry();
ASSERT_TRUE(entry1);
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/blank_page.html"));
+ test_server()->GetURL("files/ssl/blank_page.html"));
NavigationEntry* entry2 = tab->controller().GetActiveEntry();
ASSERT_TRUE(entry2);
@@ -317,7 +305,7 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestHTTPSExpiredCertAndGoForward) {
// Now go to a bad HTTPS page that shows an interstitial.
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/google.html"));
+ https_server_expired_.GetURL("files/ssl/google.html"));
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
true); // Interstitial showing
@@ -338,42 +326,19 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestHTTPSExpiredCertAndGoForward) {
// does not cause any problems (it was causing a crasher, see
// http://crbug.com/19941).
IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSErrorWithNoNavEntry) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
-
- // Load a page with a link that opens a new window (therefore with no history
- // and no navigation entries).
- ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/page_with_blank_target.html"));
-
- bool success = false;
+ ASSERT_TRUE(https_server_expired_.Start());
- ui_test_utils::WindowedNotificationObserver<NavigationController>
- load_stop_signal(NotificationType::LOAD_STOP, NULL);
-
- // Simulate clicking the link (and therefore navigating to that new page).
- // This will causes a new tab to be created.
- EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
- browser()->GetSelectedTabContents()->render_view_host(), std::wstring(),
- L"window.domAutomationController.send(navigateInNewTab());",
- &success));
- EXPECT_TRUE(success);
-
- // By the time we got a response, the new tab should have been created and be
- // the selected tab.
- EXPECT_EQ(2, browser()->tab_count());
- EXPECT_EQ(1, browser()->selected_index());
+ GURL url = https_server_expired_.GetURL("files/ssl/google.htm");
+ TabContents* tab2 = browser()->AddTabWithURL(
+ url, GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED, NULL,
+ std::string(), NULL);
+ ui_test_utils::WaitForLoadStop(&(tab2->controller()));
- // Since the navigation was initiated by the renderer (when we clicked on the
- // link) and since the main page network request failed, we won't get a
- // navigation entry committed. So we'll just wait for the load to stop.
- load_stop_signal.WaitFor(
- &(browser()->GetSelectedTabContents()->controller()));
+ // Verify our assumption that there was no prior navigation.
+ EXPECT_FALSE(browser()->command_updater()->IsCommandEnabled(IDC_BACK));
// We should have an interstitial page showing.
- ASSERT_TRUE(browser()->GetSelectedTabContents()->interstitial_page());
+ ASSERT_TRUE(tab2->interstitial_page());
}
//
@@ -382,13 +347,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTPSErrorWithNoNavEntry) {
// Visits a page that displays insecure content.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysInsecureContent) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
// Load a page that displays insecure content.
- ui_test_utils::NavigateToURL(browser(), https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_displays_insecure_content.html"));
CheckAuthenticatedState(browser()->GetSelectedTabContents(), true);
@@ -398,12 +361,10 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysInsecureContent) {
// content warnings by randomizing location.hash.
// Based on http://crbug.com/8706
IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsInsecuredContentRandomizeHash) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
- ui_test_utils::NavigateToURL(browser(), https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_runs_insecure_content.html"));
CheckAuthenticationBrokenState(browser()->GetSelectedTabContents(), 0, true,
@@ -415,12 +376,10 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsInsecuredContentRandomizeHash) {
// - images and scripts are filtered out entirely
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestUnsafeContents) {
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
- ui_test_utils::NavigateToURL(browser(), good_https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_with_unsafe_contents.html"));
TabContents* tab = browser()->GetSelectedTabContents();
@@ -454,12 +413,10 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestUnsafeContents) {
// Visits a page with insecure content loaded by JS (after the initial page
// load).
IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysInsecureContentLoadedFromJS) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
- ui_test_utils::NavigateToURL(browser(), https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_with_dynamic_insecure_content.html"));
TabContents* tab = browser()->GetSelectedTabContents();
@@ -479,13 +436,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysInsecureContentLoadedFromJS) {
// one that doesn't. The test checks that we do not propagate the insecure
// content state from one to the other.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysInsecureContentTwoTabs) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
ui_test_utils::NavigateToURL(browser(),
- https_server->TestServerPage("files/ssl/blank_page.html"));
+ https_server_.GetURL("files/ssl/blank_page.html"));
TabContents* tab1 = browser()->GetSelectedTabContents();
@@ -493,11 +448,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysInsecureContentTwoTabs) {
CheckAuthenticatedState(tab1, false);
// Create a new tab.
- GURL url = https_server->TestServerPage(
+ GURL url = https_server_.GetURL(
"files/ssl/page_displays_insecure_content.html");
TabContents* tab2 = browser()->AddTabWithURL(url, GURL(),
PageTransition::TYPED, 0, TabStripModel::ADD_SELECTED,
- tab1->GetSiteInstance(), std::string());
+ tab1->GetSiteInstance(), std::string(), NULL);
ui_test_utils::WaitForNavigation(&(tab2->controller()));
// The new tab has insecure content.
@@ -511,13 +466,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysInsecureContentTwoTabs) {
// that doesn't. The test checks that we propagate the insecure content state
// from one to the other.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsInsecureContentTwoTabs) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
ui_test_utils::NavigateToURL(browser(),
- https_server->TestServerPage("files/ssl/blank_page.html"));
+ https_server_.GetURL("files/ssl/blank_page.html"));
TabContents* tab1 = browser()->GetSelectedTabContents();
@@ -526,10 +479,10 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsInsecureContentTwoTabs) {
// Create a new tab.
GURL url =
- https_server->TestServerPage("files/ssl/page_runs_insecure_content.html");
+ https_server_.GetURL("files/ssl/page_runs_insecure_content.html");
TabContents* tab2 = browser()->AddTabWithURL(url, GURL(),
PageTransition::TYPED, 0, TabStripModel::ADD_SELECTED,
- tab1->GetSiteInstance(), std::string());
+ tab1->GetSiteInstance(), std::string(), NULL);
ui_test_utils::WaitForNavigation(&(tab2->controller()));
// The new tab has insecure content.
@@ -544,19 +497,17 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsInsecureContentTwoTabs) {
// referencing that same image over http (hoping it is coming from the webcore
// memory cache).
IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysCachedInsecureContent) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
- ui_test_utils::NavigateToURL(browser(), http_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(
"files/ssl/page_displays_insecure_content.html"));
TabContents* tab = browser()->GetSelectedTabContents();
CheckUnauthenticatedState(tab);
// Load again but over SSL. It should be marked as displaying insecure
// content (even though the image comes from the WebCore memory cache).
- ui_test_utils::NavigateToURL(browser(), https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_displays_insecure_content.html"));
CheckAuthenticatedState(tab, true);
}
@@ -565,19 +516,17 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestDisplaysCachedInsecureContent) {
// referencing that same script over http (hoping it is coming from the webcore
// memory cache).
IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsCachedInsecureContent) {
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/page_runs_insecure_content.html"));
+ test_server()->GetURL("files/ssl/page_runs_insecure_content.html"));
TabContents* tab = browser()->GetSelectedTabContents();
CheckUnauthenticatedState(tab);
// Load again but over SSL. It should be marked as displaying insecure
// content (even though the image comes from the WebCore memory cache).
- ui_test_utils::NavigateToURL(browser(), https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_runs_insecure_content.html"));
CheckAuthenticationBrokenState(tab, 0, true, false);
}
@@ -592,45 +541,32 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestRunsCachedInsecureContent) {
// This test ensures the CN invalid status does not 'stick' to a certificate
// (see bug #1044942) and that it depends on the host-name.
IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestCNInvalidStickiness) {
- const std::string kLocalHost = "localhost";
- scoped_refptr<HTTPSTestServer> https_server =
- HTTPSTestServer::CreateMismatchedServer(kDocRoot);
- ASSERT_TRUE(https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_mismatched_.Start());
// First we hit the server with hostname, this generates an invalid policy
// error.
ui_test_utils::NavigateToURL(browser(),
- https_server->TestServerPage("files/ssl/google.html"));
+ https_server_mismatched_.GetURL("files/ssl/google.html"));
// We get an interstitial page as a result.
TabContents* tab = browser()->GetSelectedTabContents();
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
false, true); // Interstitial showing.
-
ProceedThroughInterstitial(tab);
-
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
false, false); // No interstitial showing.
// Now we try again with the right host name this time.
-
- // Let's change the host-name in the url.
- GURL url = https_server->TestServerPage("files/ssl/google.html");
- std::string::size_type hostname_index = url.spec().find(kLocalHost);
- ASSERT_TRUE(hostname_index != std::string::npos); // Test sanity check.
- std::string new_url;
- new_url.append(url.spec().substr(0, hostname_index));
- new_url.append(net::TestServerLauncher::kHostName);
- new_url.append(url.spec().substr(hostname_index + kLocalHost.size()));
-
- ui_test_utils::NavigateToURL(browser(), GURL(new_url));
+ GURL url(https_server_.GetURL("files/ssl/google.html"));
+ ui_test_utils::NavigateToURL(browser(), url);
// Security state should be OK.
CheckAuthenticatedState(tab, false);
// Now try again the broken one to make sure it is still broken.
ui_test_utils::NavigateToURL(browser(),
- https_server->TestServerPage("files/ssl/google.html"));
+ https_server_mismatched_.GetURL("files/ssl/google.html"));
// Since we OKed the interstitial last time, we get right to the page.
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_COMMON_NAME_INVALID,
@@ -639,11 +575,10 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestCNInvalidStickiness) {
// Test that navigating to a #ref does not change a bad security state.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestRefNavigation) {
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_expired_.Start());
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/page_with_refs.html"));
+ https_server_expired_.GetURL("files/ssl/page_with_refs.html"));
TabContents* tab = browser()->GetSelectedTabContents();
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
@@ -657,7 +592,7 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestRefNavigation) {
// Now navigate to a ref in the page, the security state should not have
// changed.
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/page_with_refs.html#jp"));
+ https_server_expired_.GetURL("files/ssl/page_with_refs.html#jp"));
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
false); // No interstitial showing.
@@ -668,13 +603,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestRefNavigation) {
// TODO(jcampan): http://crbug.com/2136 disabled because the popup is not
// opened as it is not initiated by a user gesture.
IN_PROC_BROWSER_TEST_F(SSLUITest, DISABLED_TestCloseTabWithUnsafePopup) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_expired_.Start());
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/page_with_unsafe_popup.html"));
+ test_server()->GetURL("files/ssl/page_with_unsafe_popup.html"));
TabContents* tab1 = browser()->GetSelectedTabContents();
// It is probably overkill to add a notification for a popup-opening, let's
@@ -690,12 +623,16 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, DISABLED_TestCloseTabWithUnsafePopup) {
// Let's add another tab to make sure the browser does not exit when we close
// the first tab.
- GURL url = http_server->TestServerPage("files/ssl/google.html");
+ Browser* browser_used = NULL;
+ GURL url = test_server()->GetURL("files/ssl/google.html");
TabContents* tab2 = browser()->AddTabWithURL(
url, GURL(), PageTransition::TYPED, 0, TabStripModel::ADD_SELECTED, NULL,
- std::string());
+ std::string(), &browser_used);
ui_test_utils::WaitForNavigation(&(tab2->controller()));
+ // Ensure that the tab was created in the correct browser.
+ EXPECT_EQ(browser(), browser_used);
+
// Close the first tab.
browser()->CloseTabContents(tab1);
}
@@ -703,13 +640,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, DISABLED_TestCloseTabWithUnsafePopup) {
// Visit a page over bad https that is a redirect to a page with good https.
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestRedirectBadToGoodHTTPS) {
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
- GURL url1 = bad_https_server->TestServerPage("server-redirect?");
- GURL url2 = good_https_server->TestServerPage("files/ssl/google.html");
+ GURL url1 = https_server_expired_.GetURL("server-redirect?");
+ GURL url2 = https_server_.GetURL("files/ssl/google.html");
ui_test_utils::NavigateToURL(browser(), GURL(url1.spec() + url2.spec()));
@@ -727,13 +662,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestRedirectBadToGoodHTTPS) {
// Visit a page over good https that is a redirect to a page with bad https.
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestRedirectGoodToBadHTTPS) {
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
- GURL url1 = good_https_server->TestServerPage("server-redirect?");
- GURL url2 = bad_https_server->TestServerPage("files/ssl/google.html");
+ GURL url1 = https_server_.GetURL("server-redirect?");
+ GURL url2 = https_server_expired_.GetURL("files/ssl/google.html");
ui_test_utils::NavigateToURL(browser(), GURL(url1.spec() + url2.spec()));
TabContents* tab = browser()->GetSelectedTabContents();
@@ -748,17 +681,15 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestRedirectGoodToBadHTTPS) {
// Visit a page over http that is a redirect to a page with good HTTPS.
IN_PROC_BROWSER_TEST_F(SSLUITest, TestRedirectHTTPToGoodHTTPS) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
TabContents* tab = browser()->GetSelectedTabContents();
// HTTP redirects to good HTTPS.
- GURL http_url = http_server->TestServerPage("server-redirect?");
+ GURL http_url = test_server()->GetURL("server-redirect?");
GURL good_https_url =
- good_https_server->TestServerPage("files/ssl/google.html");
+ https_server_.GetURL("files/ssl/google.html");
ui_test_utils::NavigateToURL(browser(),
GURL(http_url.spec() + good_https_url.spec()));
@@ -767,16 +698,14 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestRedirectHTTPToGoodHTTPS) {
// Visit a page over http that is a redirect to a page with bad HTTPS.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestRedirectHTTPToBadHTTPS) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_expired_.Start());
TabContents* tab = browser()->GetSelectedTabContents();
- GURL http_url = http_server->TestServerPage("server-redirect?");
+ GURL http_url = test_server()->GetURL("server-redirect?");
GURL bad_https_url =
- bad_https_server->TestServerPage("files/ssl/google.html");
+ https_server_expired_.GetURL("files/ssl/google.html");
ui_test_utils::NavigateToURL(browser(),
GURL(http_url.spec() + bad_https_url.spec()));
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
@@ -792,13 +721,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestRedirectHTTPToBadHTTPS) {
// we don't keep the secure state).
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestRedirectHTTPSToHTTP) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
- ASSERT_TRUE(https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
- GURL https_url = https_server->TestServerPage("server-redirect?");
- GURL http_url = http_server->TestServerPage("files/ssl/google.html");
+ GURL https_url = https_server_.GetURL("server-redirect?");
+ GURL http_url = test_server()->GetURL("files/ssl/google.html");
ui_test_utils::NavigateToURL(browser(),
GURL(https_url.spec() + http_url.spec()));
@@ -827,16 +754,13 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, TestConnectToBadPort) {
// - navigate to HTTP (expect insecure content), then back
// Disabled, http://crbug.com/18626.
IN_PROC_BROWSER_TEST_F(SSLUITest, DISABLED_TestGoodFrameNavigation) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
TabContents* tab = browser()->GetSelectedTabContents();
ui_test_utils::NavigateToURL(browser(),
- good_https_server->TestServerPage("files/ssl/top_frame.html"));
+ https_server_.GetURL("files/ssl/top_frame.html"));
CheckAuthenticatedState(tab, false);
@@ -899,14 +823,12 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, DISABLED_TestGoodFrameNavigation) {
// - navigate to an OK HTTPS frame (expected to be still authentication broken).
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestBadFrameNavigation) {
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
TabContents* tab = browser()->GetSelectedTabContents();
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/top_frame.html"));
+ https_server_expired_.GetURL("files/ssl/top_frame.html"));
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
true); // Interstitial showing
@@ -938,16 +860,13 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestBadFrameNavigation) {
FLAKY_TestUnauthenticatedFrameNavigation
#endif
IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestUnauthenticatedFrameNavigation) {
- scoped_refptr<HTTPTestServer> http_server = PlainServer();
- ASSERT_TRUE(http_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
TabContents* tab = browser()->GetSelectedTabContents();
ui_test_utils::NavigateToURL(browser(),
- http_server->TestServerPage("files/ssl/top_frame.html"));
+ test_server()->GetURL("files/ssl/top_frame.html"));
CheckUnauthenticatedState(tab);
// Now navigate inside the frame to a secure HTTPS frame.
@@ -986,14 +905,12 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestUnauthenticatedFrameNavigation) {
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestUnsafeContentsInWorkerFiltered) {
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
// This page will spawn a Worker which will try to load content from
// BadCertServer.
- ui_test_utils::NavigateToURL(browser(), good_https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_with_unsafe_worker.html"));
TabContents* tab = browser()->GetSelectedTabContents();
// Expect Worker not to load insecure content.
@@ -1004,15 +921,13 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestUnsafeContentsInWorkerFiltered) {
// Marked as flaky, see bug 40932.
IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestUnsafeContentsInWorker) {
- scoped_refptr<HTTPSTestServer> good_https_server = GoodCertServer();
- ASSERT_TRUE(good_https_server.get() != NULL);
- scoped_refptr<HTTPSTestServer> bad_https_server = BadCertServer();
- ASSERT_TRUE(bad_https_server.get() != NULL);
+ ASSERT_TRUE(https_server_.Start());
+ ASSERT_TRUE(https_server_expired_.Start());
// Navigate to an unsafe site. Proceed with interstitial page to indicate
// the user approves the bad certificate.
ui_test_utils::NavigateToURL(browser(),
- bad_https_server->TestServerPage("files/ssl/blank_page.html"));
+ https_server_expired_.GetURL("files/ssl/blank_page.html"));
TabContents* tab = browser()->GetSelectedTabContents();
CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID, false,
true); // Interstitial showing
@@ -1023,7 +938,7 @@ 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.
- ui_test_utils::NavigateToURL(browser(), good_https_server->TestServerPage(
+ ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
"files/ssl/page_with_unsafe_worker.html"));
CheckWorkerLoadResult(tab, true); // Worker loads insecure content
CheckAuthenticationBrokenState(tab, 0, true, false);
diff --git a/chrome/browser/ssl/ssl_cert_error_handler.h b/chrome/browser/ssl/ssl_cert_error_handler.h
index 212a585..0584e6a 100644
--- a/chrome/browser/ssl/ssl_cert_error_handler.h
+++ b/chrome/browser/ssl/ssl_cert_error_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_CERT_ERROR_HANDLER_H_
#define CHROME_BROWSER_SSL_SSL_CERT_ERROR_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/ssl/ssl_client_auth_handler.h b/chrome/browser/ssl/ssl_client_auth_handler.h
index 05148d5..de90e5a 100644
--- a/chrome/browser/ssl/ssl_client_auth_handler.h
+++ b/chrome/browser/ssl/ssl_client_auth_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_CLIENT_AUTH_HANDLER_H_
#define CHROME_BROWSER_SSL_SSL_CLIENT_AUTH_HANDLER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
diff --git a/chrome/browser/ssl/ssl_error_handler.h b/chrome/browser/ssl/ssl_error_handler.h
index 5fcc4f4..fde764b 100644
--- a/chrome/browser/ssl/ssl_error_handler.h
+++ b/chrome/browser/ssl/ssl_error_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_ERROR_HANDLER_H_
#define CHROME_BROWSER_SSL_SSL_ERROR_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/ssl/ssl_error_info.cc b/chrome/browser/ssl/ssl_error_info.cc
index 14ffa4b..674a64b 100644
--- a/chrome/browser/ssl/ssl_error_info.cc
+++ b/chrome/browser/ssl/ssl_error_info.cc
@@ -167,6 +167,14 @@ SSLErrorInfo SSLErrorInfo::CreateError(ErrorType error_type,
l10n_util::GetString(
IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_EXTRA_INFO_2));
break;
+ case CERT_NOT_IN_DNS:
+ title = l10n_util::GetString(IDS_CERT_ERROR_NOT_IN_DNS_TITLE);
+ details = l10n_util::GetString(IDS_CERT_ERROR_NOT_IN_DNS_DETAILS);
+ short_description = l10n_util::GetString(
+ IDS_CERT_ERROR_NOT_IN_DNS_DESCRIPTION);
+ extra_info.push_back(
+ l10n_util::GetString(IDS_CERT_ERROR_NOT_IN_DNS_EXTRA_INFO));
+ break;
case UNKNOWN:
title = l10n_util::GetString(IDS_CERT_ERROR_UNKNOWN_ERROR_TITLE);
details = l10n_util::GetString(IDS_CERT_ERROR_UNKNOWN_ERROR_DETAILS);
@@ -203,6 +211,8 @@ SSLErrorInfo::ErrorType SSLErrorInfo::NetErrorToErrorType(int net_error) {
return CERT_INVALID;
case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
return CERT_WEAK_SIGNATURE_ALGORITHM;
+ case net::ERR_CERT_NOT_IN_DNS:
+ return CERT_NOT_IN_DNS;
default:
NOTREACHED();
return UNKNOWN;
diff --git a/chrome/browser/ssl/ssl_error_info.h b/chrome/browser/ssl/ssl_error_info.h
index 087d8b5..225ccf6 100644
--- a/chrome/browser/ssl/ssl_error_info.h
+++ b/chrome/browser/ssl/ssl_error_info.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_ERROR_INFO_H_
#define CHROME_BROWSER_SSL_SSL_ERROR_INFO_H_
+#pragma once
#include <string>
#include <vector>
@@ -28,6 +29,7 @@ class SSLErrorInfo {
CERT_REVOKED,
CERT_INVALID,
CERT_WEAK_SIGNATURE_ALGORITHM,
+ CERT_NOT_IN_DNS,
UNKNOWN
};
diff --git a/chrome/browser/ssl/ssl_host_state.h b/chrome/browser/ssl/ssl_host_state.h
index b35cb36..43880f3 100644
--- a/chrome/browser/ssl/ssl_host_state.h
+++ b/chrome/browser/ssl/ssl_host_state.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_HOST_STATE_H_
#define CHROME_BROWSER_SSL_SSL_HOST_STATE_H_
+#pragma once
#include <string>
#include <map>
diff --git a/chrome/browser/ssl/ssl_manager.cc b/chrome/browser/ssl/ssl_manager.cc
index d328d6e..a2a34ab 100644
--- a/chrome/browser/ssl/ssl_manager.cc
+++ b/chrome/browser/ssl/ssl_manager.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/load_from_memory_cache_details.h"
#include "chrome/browser/net/url_request_tracking.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/renderer_host/resource_request_details.h"
#include "chrome/browser/ssl/ssl_cert_error_handler.h"
#include "chrome/browser/ssl/ssl_policy.h"
@@ -75,12 +75,12 @@ bool SSLManager::DeserializeSecurityInfo(const std::string& state,
int* cert_status,
int* security_bits,
int* ssl_connection_status) {
- DCHECK(cert_id && cert_status && security_bits);
+ DCHECK(cert_id && cert_status && security_bits && ssl_connection_status);
if (state.empty()) {
// No SSL used.
*cert_id = 0;
*cert_status = 0;
- *security_bits = -1;
+ *security_bits = 0; // Not encrypted.
*ssl_connection_status = 0;
return false;
}
@@ -139,7 +139,8 @@ void SSLManager::DidCommitProvisionalLoad(
if (details->is_main_frame) {
if (entry) {
// Decode the security details.
- int ssl_cert_id, ssl_cert_status, ssl_security_bits, ssl_connection_status;
+ int ssl_cert_id, ssl_cert_status, ssl_security_bits,
+ ssl_connection_status;
DeserializeSecurityInfo(details->serialized_security_info,
&ssl_cert_id,
&ssl_cert_status,
@@ -154,7 +155,6 @@ void SSLManager::DidCommitProvisionalLoad(
entry->ssl().set_security_bits(ssl_security_bits);
entry->ssl().set_connection_status(ssl_connection_status);
}
- backend_.ShowPendingMessages();
}
UpdateEntry(entry);
@@ -181,8 +181,7 @@ void SSLManager::Observe(NotificationType type,
// Dispatch by type.
switch (type.value) {
case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR:
- DidFailProvisionalLoadWithError(
- Details<ProvisionalLoadDetails>(details).ptr());
+ // Do nothing.
break;
case NotificationType::RESOURCE_RESPONSE_STARTED:
DidStartResourceResponse(Details<ResourceRequestDetails>(details).ptr());
@@ -224,18 +223,6 @@ void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) {
policy()->OnRequestStarted(info.get());
}
-void SSLManager::DidFailProvisionalLoadWithError(
- ProvisionalLoadDetails* details) {
- DCHECK(details);
-
- // Ignore in-page navigations.
- if (details->in_page_navigation())
- return;
-
- if (details->main_frame())
- backend_.ClearPendingMessages();
-}
-
void SSLManager::DidStartResourceResponse(ResourceRequestDetails* details) {
DCHECK(details);
diff --git a/chrome/browser/ssl/ssl_manager.h b/chrome/browser/ssl/ssl_manager.h
index e9916b3..6340f57 100644
--- a/chrome/browser/ssl/ssl_manager.h
+++ b/chrome/browser/ssl/ssl_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_MANAGER_H_
#define CHROME_BROWSER_SSL_SSL_MANAGER_H_
+#pragma once
#include <string>
@@ -18,14 +19,11 @@
class LoadFromMemoryCacheDetails;
class NavigationController;
class NavigationEntry;
-class PrefService;
class ProvisionalLoadDetails;
class ResourceDispatcherHost;
class ResourceRedirectDetails;
class ResourceRequestDetails;
-class SSLCertErrorHandler;
class SSLPolicy;
-class Task;
class URLRequest;
// The SSLManager SSLManager controls the SSL UI elements in a TabContents. It
@@ -99,36 +97,11 @@ class SSLManager : public NotificationObserver {
const NotificationDetails& details);
private:
- // SSLMessageInfo contains the information necessary for displaying a message
- // in an info-bar.
- struct SSLMessageInfo {
- public:
- explicit SSLMessageInfo(const std::wstring& text)
- : message(text),
- action(NULL) { }
-
- SSLMessageInfo(const std::wstring& message,
- const std::wstring& link_text,
- Task* action)
- : message(message), link_text(link_text), action(action) { }
-
- // Overridden so that std::find works.
- bool operator==(const std::wstring& other_message) const {
- // We are uniquing SSLMessageInfo by their message only.
- return message == other_message;
- }
-
- std::wstring message;
- std::wstring link_text;
- Task* action;
- };
-
// Entry points for notifications to which we subscribe. Note that
// DidCommitProvisionalLoad uses the abstract NotificationDetails type since
// the type we need is in NavigationController which would create a circular
// header file dependency.
void DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details);
- void DidFailProvisionalLoadWithError(ProvisionalLoadDetails* details);
void DidStartResourceResponse(ResourceRequestDetails* details);
void DidReceiveResourceRedirect(ResourceRedirectDetails* details);
void DidChangeSSLInternalState();
diff --git a/chrome/browser/ssl/ssl_policy.cc b/chrome/browser/ssl/ssl_policy.cc
index ea1ff71..767d743 100644
--- a/chrome/browser/ssl/ssl_policy.cc
+++ b/chrome/browser/ssl/ssl_policy.cc
@@ -4,15 +4,13 @@
#include "chrome/browser/ssl/ssl_policy.h"
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/base_switches.h"
#include "base/command_line.h"
-#include "base/i18n/rtl.h"
#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"
@@ -22,11 +20,10 @@
#include "chrome/browser/ssl/ssl_request_info.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#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/browser/pref_service.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
@@ -74,6 +71,7 @@ void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) {
case net::ERR_CERT_CONTAINS_ERRORS:
case net::ERR_CERT_REVOKED:
case net::ERR_CERT_INVALID:
+ case net::ERR_CERT_NOT_IN_DNS:
OnCertErrorInternal(handler, SSLBlockingPage::ERROR_FATAL);
break;
default:
diff --git a/chrome/browser/ssl/ssl_policy.h b/chrome/browser/ssl/ssl_policy.h
index 1f1766b..58b83a8 100644
--- a/chrome/browser/ssl/ssl_policy.h
+++ b/chrome/browser/ssl/ssl_policy.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_POLICY_H_
#define CHROME_BROWSER_SSL_SSL_POLICY_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/ssl/ssl_policy_backend.cc b/chrome/browser/ssl/ssl_policy_backend.cc
index 42fef7a..76d75ac 100644
--- a/chrome/browser/ssl/ssl_policy_backend.cc
+++ b/chrome/browser/ssl/ssl_policy_backend.cc
@@ -4,106 +4,16 @@
#include "chrome/browser/ssl/ssl_policy_backend.h"
-#include "app/resource_bundle.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/ssl/ssl_host_state.h"
-#include "chrome/browser/tab_contents/infobar_delegate.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 "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-class SSLInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
- SSLInfoBarDelegate(TabContents* contents,
- const std::wstring message,
- const std::wstring& button_label,
- Task* task)
- : ConfirmInfoBarDelegate(contents),
- message_(message),
- button_label_(button_label),
- task_(task) {
- }
- virtual ~SSLInfoBarDelegate() {}
-
- // Overridden from ConfirmInfoBarDelegate:
- virtual void InfoBarClosed() {
- delete this;
- }
- virtual std::wstring GetMessageText() const {
- return message_;
- }
- virtual SkBitmap* GetIcon() const {
- return ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_INFOBAR_SSL_WARNING);
- }
- virtual int GetButtons() const {
- return !button_label_.empty() ? BUTTON_OK : BUTTON_NONE;
- }
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
- return button_label_;
- }
- virtual bool Accept() {
- if (task_.get()) {
- task_->Run();
- task_.reset(); // Ensures we won't run the task again.
- }
- return true;
- }
-
- private:
- // Labels for the InfoBar's message and button.
- std::wstring message_;
- std::wstring button_label_;
-
- // A task to run when the InfoBar is accepted.
- scoped_ptr<Task> task_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLInfoBarDelegate);
-};
SSLPolicyBackend::SSLPolicyBackend(NavigationController* controller)
- : controller_(controller),
- ssl_host_state_(controller->profile()->GetSSLHostState()) {
- DCHECK(controller_);
+ : ssl_host_state_(controller->profile()->GetSSLHostState()) {
+ DCHECK(controller);
}
-void SSLPolicyBackend::ShowMessage(const std::wstring& msg) {
- ShowMessageWithLink(msg, std::wstring(), NULL);
-}
-
-void SSLPolicyBackend::ShowMessageWithLink(const std::wstring& msg,
- const std::wstring& link_text,
- Task* task) {
- if (controller_->pending_entry()) {
- // The main frame is currently loading, wait until the load is committed so
- // to show the error on the right page (once the location bar shows the
- // correct url).
- if (std::find(pending_messages_.begin(), pending_messages_.end(), msg) ==
- pending_messages_.end())
- pending_messages_.push_back(SSLMessageInfo(msg, link_text, task));
-
- return;
- }
-
- NavigationEntry* entry = controller_->GetActiveEntry();
- if (!entry)
- return;
-
- // Don't show the message if the user doesn't expect an authenticated session.
- if (entry->ssl().security_style() <= SECURITY_STYLE_UNAUTHENTICATED)
- return;
-
- if (controller_->tab_contents()) {
- controller_->tab_contents()->AddInfoBar(
- new SSLInfoBarDelegate(controller_->tab_contents(), msg, link_text,
- task));
- }
-}
-
-void SSLPolicyBackend::HostRanInsecureContent(const std::string& host,
- int id) {
+void SSLPolicyBackend::HostRanInsecureContent(const std::string& host, int id) {
ssl_host_state_->HostRanInsecureContent(host, id);
SSLManager::NotifySSLInternalStateChanged();
}
@@ -127,16 +37,3 @@ net::CertPolicy::Judgment SSLPolicyBackend::QueryPolicy(
net::X509Certificate* cert, const std::string& host) {
return ssl_host_state_->QueryPolicy(cert, host);
}
-
-void SSLPolicyBackend::ShowPendingMessages() {
- std::vector<SSLMessageInfo>::const_iterator iter;
- for (iter = pending_messages_.begin();
- iter != pending_messages_.end(); ++iter) {
- ShowMessageWithLink(iter->message, iter->link_text, iter->action);
- }
- ClearPendingMessages();
-}
-
-void SSLPolicyBackend::ClearPendingMessages() {
- pending_messages_.clear();
-}
diff --git a/chrome/browser/ssl/ssl_policy_backend.h b/chrome/browser/ssl/ssl_policy_backend.h
index 4059df7..813f2be 100644
--- a/chrome/browser/ssl/ssl_policy_backend.h
+++ b/chrome/browser/ssl/ssl_policy_backend.h
@@ -4,31 +4,22 @@
#ifndef CHROME_BROWSER_SSL_SSL_POLICY_BACKEND_H_
#define CHROME_BROWSER_SSL_SSL_POLICY_BACKEND_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/string16.h"
#include "net/base/x509_certificate.h"
class NavigationController;
class SSLHostState;
-class Task;
class SSLPolicyBackend {
public:
explicit SSLPolicyBackend(NavigationController* controller);
- // Ensure that the specified message is displayed to the user. This will
- // display an InfoBar at the top of the associated tab.
- void ShowMessage(const std::wstring& msg);
-
- // Same as ShowMessage but also contains a link that when clicked run the
- // specified task. The SSL Manager becomes the owner of the task.
- void ShowMessageWithLink(const std::wstring& msg,
- const std::wstring& link_text,
- Task* task);
-
// Records that a host has run insecure content.
void HostRanInsecureContent(const std::string& host, int pid);
@@ -45,48 +36,10 @@ class SSLPolicyBackend {
net::CertPolicy::Judgment QueryPolicy(
net::X509Certificate* cert, const std::string& host);
- // Shows the pending messages (in info-bars) if any.
- void ShowPendingMessages();
-
- // Clears any pending messages.
- void ClearPendingMessages();
-
private:
- // SSLMessageInfo contains the information necessary for displaying a message
- // in an info-bar.
- struct SSLMessageInfo {
- public:
- explicit SSLMessageInfo(const std::wstring& text)
- : message(text),
- action(NULL) { }
-
- SSLMessageInfo(const std::wstring& message,
- const std::wstring& link_text,
- Task* action)
- : message(message), link_text(link_text), action(action) { }
-
- // Overridden so that std::find works.
- bool operator==(const std::wstring& other_message) const {
- // We are uniquing SSLMessageInfo by their message only.
- return message == other_message;
- }
-
- std::wstring message;
- std::wstring link_text;
- Task* action;
- };
-
- // The NavigationController that owns this SSLManager. We are responsible
- // for the security UI of this tab.
- NavigationController* controller_;
-
// SSL state specific for each host.
SSLHostState* ssl_host_state_;
- // The list of messages that should be displayed (in info bars) when the page
- // currently loading had loaded.
- std::vector<SSLMessageInfo> pending_messages_;
-
DISALLOW_COPY_AND_ASSIGN(SSLPolicyBackend);
};
diff --git a/chrome/browser/ssl/ssl_request_info.h b/chrome/browser/ssl/ssl_request_info.h
index c495cd2..2ce3e88 100644
--- a/chrome/browser/ssl/ssl_request_info.h
+++ b/chrome/browser/ssl/ssl_request_info.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SSL_SSL_REQUEST_INFO_H_
#define CHROME_BROWSER_SSL_SSL_REQUEST_INFO_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/ssl_client_certificate_selector.h b/chrome/browser/ssl_client_certificate_selector.h
index 8a12a70..1886766 100644
--- a/chrome/browser/ssl_client_certificate_selector.h
+++ b/chrome/browser/ssl_client_certificate_selector.h
@@ -4,10 +4,10 @@
#ifndef CHROME_BROWSER_SSL_CLIENT_CERTIFICATE_SELECTOR_H_
#define CHROME_BROWSER_SSL_CLIENT_CERTIFICATE_SELECTOR_H_
-
-#include "gfx/native_widget_types.h"
+#pragma once
class SSLClientAuthHandler;
+class TabContents;
namespace net {
class SSLCertRequestInfo;
@@ -15,13 +15,16 @@ class SSLCertRequestInfo;
namespace browser {
-// Opens an SSL client certificate selection dialog under |parent|, offering
-// certificates from |cert_request_info|. When the user has made a selection,
-// the dialog will report back to |delegate|. |delegate| is notified when the
-// dialog closes in call cases; if the user cancels the dialog, we call with a
-// NULL certificate.
+// Opens a constrained SSL client certificate selection dialog under |parent|,
+// offering certificates from |cert_request_info|. When the user has made a
+// selection, the dialog will report back to |delegate|. |delegate| is notified
+// when the dialog closes in call cases; if the user cancels the dialog, we call
+// with a NULL certificate.
+//
+// Note: constrained dialog currently only implemented on Linux and OS X. On
+// Windows, a window-modal dialog will be used.
void ShowSSLClientCertificateSelector(
- gfx::NativeWindow parent,
+ TabContents* parent,
net::SSLCertRequestInfo* cert_request_info,
SSLClientAuthHandler* delegate);
diff --git a/chrome/browser/status_bubble.h b/chrome/browser/status_bubble.h
index 8ed364f..e7ddc15 100644
--- a/chrome/browser/status_bubble.h
+++ b/chrome/browser/status_bubble.h
@@ -4,8 +4,9 @@
#ifndef CHROME_BROWSER_STATUS_BUBBLE_H_
#define CHROME_BROWSER_STATUS_BUBBLE_H_
+#pragma once
-#include <string>
+#include "base/string16.h"
class GURL;
namespace gfx {
@@ -29,13 +30,13 @@ class StatusBubble {
// when the cursor exits a link) will set the status bubble back to its
// status text. To hide the status bubble again, either call SetStatus
// with an empty string, or call Hide().
- virtual void SetStatus(const std::wstring& status) = 0;
+ virtual void SetStatus(const string16& status) = 0;
// Sets the bubble text to a URL - if given a non-empty URL, this will cause
// the bubble to fade in and remain open until given an empty URL or until
// the Hide() method is called. languages is the value of Accept-Language
// to determine what characters are understood by a user.
- virtual void SetURL(const GURL& url, const std::wstring& languages) = 0;
+ virtual void SetURL(const GURL& url, const string16& languages) = 0;
// Skip the fade and instant-hide the bubble.
virtual void Hide() = 0;
diff --git a/chrome/browser/status_icons/status_icon.cc b/chrome/browser/status_icons/status_icon.cc
index 9fed83d..baaa6cc 100644
--- a/chrome/browser/status_icons/status_icon.cc
+++ b/chrome/browser/status_icons/status_icon.cc
@@ -4,6 +4,15 @@
#include "chrome/browser/status_icons/status_icon.h"
+#include "app/menus/menu_model.h"
+
+StatusIcon::StatusIcon()
+{
+}
+
+StatusIcon::~StatusIcon() {
+}
+
void StatusIcon::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
@@ -12,6 +21,15 @@ void StatusIcon::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
+bool StatusIcon::HasObservers() {
+ return observers_.size() > 0;
+}
+
void StatusIcon::DispatchClickEvent() {
FOR_EACH_OBSERVER(Observer, observers_, OnClicked());
}
+
+void StatusIcon::SetContextMenu(menus::MenuModel* menu) {
+ context_menu_contents_.reset(menu);
+ UpdatePlatformContextMenu(menu);
+}
diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h
index ffe0f5f..5398eb3 100644
--- a/chrome/browser/status_icons/status_icon.h
+++ b/chrome/browser/status_icons/status_icon.h
@@ -4,16 +4,22 @@
#ifndef CHROME_BROWSER_STATUS_ICONS_STATUS_ICON_H_
#define CHROME_BROWSER_STATUS_ICONS_STATUS_ICON_H_
+#pragma once
#include "base/observer_list.h"
+#include "base/scoped_ptr.h"
#include "base/string16.h"
class SkBitmap;
+namespace menus {
+class MenuModel;
+}
+
class StatusIcon {
public:
- StatusIcon() {}
- virtual ~StatusIcon() {}
+ StatusIcon();
+ virtual ~StatusIcon();
// Sets the image associated with this status icon.
virtual void SetImage(const SkBitmap& image) = 0;
@@ -24,23 +30,45 @@ class StatusIcon {
// Sets the hover text for this status icon.
virtual void SetToolTip(const string16& tool_tip) = 0;
+ // Set the context menu for this icon. The icon takes ownership of the passed
+ // context menu. Passing NULL results in no menu at all.
+ void SetContextMenu(menus::MenuModel* menu);
+
class Observer {
public:
virtual ~Observer() {}
- // Called when the user clicks on the system tray icon.
+ // Called when the user clicks on the system tray icon. Clicks that result
+ // in the context menu being displayed will not be passed to this observer
+ // (i.e. if there's a context menu set on this status icon, and the user
+ // right clicks on the icon to display the context menu, OnClicked will not
+ // be called).
virtual void OnClicked() = 0;
};
- // Adds/Removes an observer for status bar events.
+ // Adds/Removes an observer for clicks on the status icon. If an observer is
+ // registered, then left clicks on the status icon will result in the observer
+ // being called, otherwise, both left and right clicks will display the
+ // context menu (if any).
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
+ // Returns true if there are registered click observers.
+ bool HasObservers();
+
// Dispatches a click event to the observers.
void DispatchClickEvent();
+ protected:
+ // Invoked after a call to SetContextMenu() to let the platform-specific
+ // subclass update the native context menu based on the new model. If NULL is
+ // passed, subclass should destroy the native context menu.
+ virtual void UpdatePlatformContextMenu(menus::MenuModel* model) = 0;
+
private:
ObserverList<Observer> observers_;
+ // Context menu, if any.
+ scoped_ptr<menus::MenuModel> context_menu_contents_;
DISALLOW_COPY_AND_ASSIGN(StatusIcon);
};
diff --git a/chrome/browser/status_icons/status_icon_unittest.cc b/chrome/browser/status_icons/status_icon_unittest.cc
index db8c529..48fbc20 100644
--- a/chrome/browser/status_icons/status_icon_unittest.cc
+++ b/chrome/browser/status_icons/status_icon_unittest.cc
@@ -18,6 +18,7 @@ class TestStatusIcon : public StatusIcon {
virtual void SetImage(const SkBitmap& image) {}
virtual void SetPressedImage(const SkBitmap& image) {}
virtual void SetToolTip(const string16& tool_tip) {}
+ virtual void UpdatePlatformContextMenu(menus::MenuModel* menu) {}
};
TEST(StatusIconTest, ObserverAdd) {
@@ -44,4 +45,3 @@ TEST(StatusIconTest, ObserverRemove) {
icon.RemoveObserver(&observer);
icon.DispatchClickEvent();
}
-
diff --git a/chrome/browser/status_icons/status_tray.cc b/chrome/browser/status_icons/status_tray.cc
index b7ae49c..8648351 100644
--- a/chrome/browser/status_icons/status_tray.cc
+++ b/chrome/browser/status_icons/status_tray.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/status_icons/status_tray.h"
+#include <algorithm>
+
#include "base/stl_util-inl.h"
#include "chrome/browser/status_icons/status_icon.h"
@@ -16,29 +18,23 @@ StatusTray::~StatusTray() {
void StatusTray::RemoveAllIcons() {
// Walk any active status icons and delete them.
- STLDeleteContainerPairSecondPointers(status_icons_.begin(),
- status_icons_.end());
+ STLDeleteContainerPointers(status_icons_.begin(), status_icons_.end());
status_icons_.clear();
}
-StatusIcon* StatusTray::GetStatusIcon(const string16& identifier) {
- StatusIconMap::const_iterator iter = status_icons_.find(identifier);
- if (iter != status_icons_.end())
- return iter->second;
-
- // No existing StatusIcon, create a new one.
- StatusIcon* icon = CreateStatusIcon();
+StatusIcon* StatusTray::CreateStatusIcon() {
+ StatusIcon* icon = CreatePlatformStatusIcon();
if (icon)
- status_icons_[identifier] = icon;
+ status_icons_.push_back(icon);
return icon;
}
-void StatusTray::RemoveStatusIcon(const string16& identifier) {
- StatusIconMap::iterator iter = status_icons_.find(identifier);
+void StatusTray::RemoveStatusIcon(StatusIcon* icon) {
+ StatusIconList::iterator iter = std::find(
+ status_icons_.begin(), status_icons_.end(), icon);
if (iter != status_icons_.end()) {
- // Free the StatusIcon from the map (can't put scoped_ptr in a map, so we
- // have to do it manually).
- delete iter->second;
+ // Free the StatusIcon from the list.
+ delete *iter;
status_icons_.erase(iter);
}
}
diff --git a/chrome/browser/status_icons/status_tray.h b/chrome/browser/status_icons/status_tray.h
index 30a60aa..a0da771 100644
--- a/chrome/browser/status_icons/status_tray.h
+++ b/chrome/browser/status_icons/status_tray.h
@@ -4,9 +4,12 @@
#ifndef CHROME_BROWSER_STATUS_ICONS_STATUS_TRAY_H_
#define CHROME_BROWSER_STATUS_ICONS_STATUS_TRAY_H_
+#pragma once
-#include "base/hash_tables.h"
-#include "base/scoped_ptr.h"
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
class StatusIcon;
@@ -15,38 +18,37 @@ class StatusIcon;
class StatusTray {
public:
// Static factory method that is implemented separately for each platform to
- // produce the appropriate platform-specific instance.
+ // produce the appropriate platform-specific instance. Returns NULL if this
+ // platform does not support status icons.
static StatusTray* Create();
virtual ~StatusTray();
- // Gets the current status icon associated with this identifier, or creates
- // a new one if none exists. The StatusTray retains ownership of the
- // StatusIcon. Returns NULL if the status tray icon could not be created.
- StatusIcon* GetStatusIcon(const string16& identifier);
+ // Creates a new StatusIcon. The StatusTray retains ownership of the
+ // StatusIcon. Returns NULL if the StatusIcon could not be created.
+ StatusIcon* CreateStatusIcon();
// Removes the current status icon associated with this identifier, if any.
- void RemoveStatusIcon(const string16& identifier);
+ void RemoveStatusIcon(StatusIcon* icon);
protected:
StatusTray();
- // Factory method for creating a status icon.
- virtual StatusIcon* CreateStatusIcon() = 0;
+ // Factory method for creating a status icon for this platform.
+ virtual StatusIcon* CreatePlatformStatusIcon() = 0;
// Removes all StatusIcons (used by derived classes to clean up in case they
// track external state used by the StatusIcons).
void RemoveAllIcons();
- typedef base::hash_map<string16, StatusIcon*> StatusIconMap;
+ typedef std::vector<StatusIcon*> StatusIconList;
// Returns the list of active status icons so subclasses can operate on them.
- const StatusIconMap& status_icons() { return status_icons_; }
+ const StatusIconList& status_icons() { return status_icons_; }
private:
- // Map containing all active StatusIcons.
- // Key: String identifiers (passed in to GetStatusIcon)
- // Value: The StatusIcon associated with that identifier (strong pointer -
- // StatusIcons are freed when the StatusTray destructor is called).
- StatusIconMap status_icons_;
+ FRIEND_TEST_ALL_PREFIXES(StatusTrayTest, CreateRemove);
+
+ // List containing all active StatusIcons.
+ StatusIconList status_icons_;
DISALLOW_COPY_AND_ASSIGN(StatusTray);
};
diff --git a/chrome/browser/status_icons/status_tray_manager.cc b/chrome/browser/status_icons/status_tray_manager.cc
deleted file mode 100644
index 7a8a779..0000000
--- a/chrome/browser/status_icons/status_tray_manager.cc
+++ /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.
-
-#include "chrome/browser/status_icons/status_tray_manager.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/status_icons/status_tray.h"
-#include "grit/browser_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/theme_resources.h"
-
-StatusTrayManager::StatusTrayManager() {
-}
-
-StatusTrayManager::~StatusTrayManager() {
-}
-
-void StatusTrayManager::Init(Profile* profile) {
-#if !(defined(OS_LINUX) && defined(TOOLKIT_VIEWS))
- DCHECK(profile);
- profile_ = profile;
- status_tray_.reset(StatusTray::Create());
- StatusIcon* icon = status_tray_->GetStatusIcon(ASCIIToUTF16("chrome_main"));
- if (icon) {
- // Create an icon and add ourselves as a click observer on it
- SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_STATUS_TRAY_ICON);
- SkBitmap* pressed = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_STATUS_TRAY_ICON_PRESSED);
- icon->SetImage(*bitmap);
- icon->SetPressedImage(*pressed);
- icon->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- icon->AddObserver(this);
- }
-#endif
-}
-
-void StatusTrayManager::OnClicked() {
- // When the tray icon is clicked, bring up the extensions page for now.
- Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
- if (browser) {
- // Bring up the existing browser window and show the extensions tab.
- browser->window()->Activate();
- browser->ShowExtensionsTab();
- } else {
- // No windows are currently open, so open a new one.
- Browser::OpenExtensionsWindow(profile_);
- }
-}
diff --git a/chrome/browser/status_icons/status_tray_manager.h b/chrome/browser/status_icons/status_tray_manager.h
deleted file mode 100644
index 2a880e4..0000000
--- a/chrome/browser/status_icons/status_tray_manager.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_STATUS_ICONS_STATUS_TRAY_MANAGER_H_
-#define CHROME_BROWSER_STATUS_ICONS_STATUS_TRAY_MANAGER_H_
-
-#include "base/scoped_ptr.h"
-#include "chrome/browser/status_icons/status_icon.h"
-
-class Profile;
-class StatusTray;
-
-// Manages the set of status tray icons and associated UI.
-class StatusTrayManager : private StatusIcon::Observer {
- public:
- StatusTrayManager();
- virtual ~StatusTrayManager();
-
- void Init(Profile* profile);
-
- private:
- // Overriden from StatusIcon::Observer:
- virtual void OnClicked();
-
- scoped_ptr<StatusTray> status_tray_;
- Profile* profile_;
-};
-
-#endif // CHROME_BROWSER_STATUS_ICONS_STATUS_TRAY_MANAGER_H_
diff --git a/chrome/browser/status_icons/status_tray_unittest.cc b/chrome/browser/status_icons/status_tray_unittest.cc
index 9b60010..a047689 100644
--- a/chrome/browser/status_icons/status_tray_unittest.cc
+++ b/chrome/browser/status_icons/status_tray_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/status_icons/status_tray.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -14,41 +15,34 @@ class MockStatusIcon : public StatusIcon {
virtual void SetImage(const SkBitmap& image) {}
virtual void SetPressedImage(const SkBitmap& image) {}
virtual void SetToolTip(const string16& tool_tip) {}
+ virtual void UpdatePlatformContextMenu(menus::MenuModel* menu) {}
virtual void AddObserver(StatusIcon::Observer* observer) {}
virtual void RemoveObserver(StatusIcon::Observer* observer) {}
};
class TestStatusTray : public StatusTray {
public:
- MOCK_METHOD0(CreateStatusIcon, StatusIcon*());
+ MOCK_METHOD0(CreatePlatformStatusIcon, StatusIcon*());
+ MOCK_METHOD1(UpdatePlatformContextMenu, void(menus::MenuModel*));
};
TEST(StatusTrayTest, Create) {
// Check for creation and leaks.
TestStatusTray tray;
- EXPECT_CALL(tray, CreateStatusIcon()).WillOnce(Return(new MockStatusIcon()));
- tray.GetStatusIcon(ASCIIToUTF16("test"));
+ EXPECT_CALL(tray,
+ CreatePlatformStatusIcon()).WillOnce(Return(new MockStatusIcon()));
+ tray.CreateStatusIcon();
}
-TEST(StatusTrayTest, GetIconTwice) {
+// Make sure that removing an icon removes it from the list.
+TEST(StatusTrayTest, CreateRemove) {
TestStatusTray tray;
- string16 id = ASCIIToUTF16("test");
- // We should not try to create a new icon if we get the same ID twice.
- EXPECT_CALL(tray, CreateStatusIcon()).WillOnce(Return(new MockStatusIcon()));
- StatusIcon* icon = tray.GetStatusIcon(id);
- EXPECT_EQ(icon, tray.GetStatusIcon(id));
-}
-
-TEST(StatusTrayTest, GetIconAfterRemove) {
- TestStatusTray tray;
- string16 id = ASCIIToUTF16("test");
- EXPECT_CALL(tray, CreateStatusIcon()).Times(2)
- .WillOnce(Return(new MockStatusIcon()))
- .WillOnce(Return(new MockStatusIcon()));
- StatusIcon* icon = tray.GetStatusIcon(id);
- EXPECT_EQ(icon, tray.GetStatusIcon(id));
-
- // If we remove the icon, then we should create a new one the next time in.
- tray.RemoveStatusIcon(id);
- tray.GetStatusIcon(id);
+ EXPECT_CALL(tray,
+ CreatePlatformStatusIcon()).WillOnce(Return(new MockStatusIcon()));
+ StatusIcon* icon = tray.CreateStatusIcon();
+ EXPECT_EQ(1U, tray.status_icons_.size());
+ tray.RemoveStatusIcon(icon);
+ EXPECT_EQ(0U, tray.status_icons_.size());
+ // Calling again should do nothing.
+ tray.RemoveStatusIcon(icon);
}
diff --git a/chrome/browser/sync/abstract_profile_sync_service_test.h b/chrome/browser/sync/abstract_profile_sync_service_test.h
index 703962d..73d59ef 100644
--- a/chrome/browser/sync/abstract_profile_sync_service_test.h
+++ b/chrome/browser/sync/abstract_profile_sync_service_test.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
#define CHROME_BROWSER_SYNC_ABSTRACT_PROFILE_SYNC_SERVICE_TEST_H_
+#pragma once
#include <string>
@@ -11,10 +12,12 @@
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/password_model_associator.h"
#include "chrome/browser/sync/glue/preference_model_associator.h"
+#include "chrome/browser/sync/glue/session_model_associator.h"
#include "chrome/browser/sync/glue/typed_url_model_associator.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/protocol/sync.pb.h"
@@ -32,7 +35,6 @@ using sync_api::UserShare;
using syncable::BASE_VERSION;
using syncable::CREATE;
using syncable::DirectoryManager;
-using syncable::ID;
using syncable::IS_DEL;
using syncable::IS_DIR;
using syncable::IS_UNAPPLIED_UPDATE;
@@ -47,16 +49,14 @@ using syncable::UNIQUE_SERVER_TAG;
using syncable::UNITTEST;
using syncable::WriteTransaction;
-class AbstractProfileSyncServiceTest : public testing::Test {
+class ProfileSyncServiceTestHelper {
public:
- AbstractProfileSyncServiceTest()
- : ui_thread_(ChromeThread::UI, &message_loop_) {}
-
- bool CreateRoot(ModelType model_type) {
- UserShare* user_share = service_->backend()->GetUserShareHandle();
+ static bool CreateRoot(ModelType model_type, ProfileSyncService* service,
+ TestIdFactory* ids) {
+ UserShare* user_share = service->backend()->GetUserShareHandle();
DirectoryManager* dir_manager = user_share->dir_manager.get();
- ScopedDirLookup dir(dir_manager, user_share->authenticated_name);
+ ScopedDirLookup dir(dir_manager, user_share->name);
if (!dir.good())
return false;
@@ -77,6 +77,9 @@ class AbstractProfileSyncServiceTest : public testing::Test {
case syncable::TYPED_URLS:
tag_name = browser_sync::kTypedUrlTag;
break;
+ case syncable::SESSIONS:
+ tag_name = browser_sync::kSessionsTag;
+ break;
default:
return false;
}
@@ -94,19 +97,31 @@ class AbstractProfileSyncServiceTest : public testing::Test {
node.Put(SERVER_VERSION, 20);
node.Put(BASE_VERSION, 20);
node.Put(IS_DEL, false);
- node.Put(ID, ids_.MakeServer(tag_name));
+ node.Put(syncable::ID, ids->MakeServer(tag_name));
sync_pb::EntitySpecifics specifics;
syncable::AddDefaultExtensionValue(model_type, &specifics);
node.Put(SPECIFICS, specifics);
return true;
}
+};
+
+class AbstractProfileSyncServiceTest : public testing::Test {
+ public:
+ AbstractProfileSyncServiceTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_) {}
+
+ bool CreateRoot(ModelType model_type) {
+ return ProfileSyncServiceTestHelper::CreateRoot(model_type,
+ service_.get(), &ids_);
+ }
protected:
MessageLoopForUI message_loop_;
ChromeThread ui_thread_;
ProfileSyncFactoryMock factory_;
+ TokenService token_service_;
scoped_ptr<TestProfileSyncService> service_;
TestIdFactory ids_;
};
diff --git a/chrome/browser/sync/engine/all_status.cc b/chrome/browser/sync/engine/all_status.cc
index 6c48905..72e1f6d 100644
--- a/chrome/browser/sync/engine/all_status.cc
+++ b/chrome/browser/sync/engine/all_status.cc
@@ -8,8 +8,6 @@
#include "base/logging.h"
#include "base/port.h"
-#include "base/rand_util.h"
-#include "chrome/browser/sync/engine/auth_watcher.h"
#include "chrome/browser/sync/engine/net/server_connection_manager.h"
#include "chrome/browser/sync/engine/syncer.h"
#include "chrome/browser/sync/engine/syncer_thread.h"
@@ -23,11 +21,6 @@ namespace browser_sync {
static const time_t kMinSyncObserveInterval = 10; // seconds
-// Backoff interval randomization factor.
-static const int kBackoffRandomizationFactor = 2;
-
-const int AllStatus::kMaxBackoffSeconds = 60 * 60 * 4; // 4 hours.
-
const char* AllStatus::GetSyncStatusString(SyncStatus icon) {
const char* strings[] = {"OFFLINE", "OFFLINE_UNSYNCED", "SYNCING", "READY",
"CONFLICT", "OFFLINE_UNUSABLE"};
@@ -54,11 +47,6 @@ AllStatus::~AllStatus() {
delete channel_;
}
-void AllStatus::WatchConnectionManager(ServerConnectionManager* conn_mgr) {
- conn_mgr_hookup_.reset(NewEventListenerHookup(conn_mgr->channel(), this,
- &AllStatus::HandleServerConnectionEvent));
-}
-
void AllStatus::WatchSyncerThread(SyncerThread* syncer_thread) {
syncer_thread_hookup_.reset(syncer_thread == NULL ? NULL :
syncer_thread->relay_channel()->AddObserver(this));
@@ -105,10 +93,6 @@ AllStatus::Status AllStatus::CalcSyncing(const SyncerEvent &event) const {
return status;
}
-AllStatus::Status AllStatus::CalcSyncing() const {
- return CreateBlankStatus();
-}
-
int AllStatus::CalcStatusChanges(Status* old_status) {
int what_changed = 0;
@@ -159,34 +143,6 @@ int AllStatus::CalcStatusChanges(Status* old_status) {
return what_changed;
}
-void AllStatus::HandleAuthWatcherEvent(const AuthWatcherEvent& auth_event) {
- ScopedStatusLockWithNotify lock(this);
- switch (auth_event.what_happened) {
- case AuthWatcherEvent::GAIA_AUTH_FAILED:
- case AuthWatcherEvent::SERVICE_AUTH_FAILED:
- case AuthWatcherEvent::SERVICE_CONNECTION_FAILED:
- case AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START:
- status_.authenticated = false;
- break;
- case AuthWatcherEvent::AUTH_SUCCEEDED:
- // If we've already calculated that the server is reachable, since we've
- // successfully authenticated, we can be confident that the server is up.
- if (status_.server_reachable)
- status_.server_up = true;
-
- if (!status_.authenticated) {
- status_.authenticated = true;
- status_ = CalcSyncing();
- } else {
- lock.set_notify_plan(DONT_NOTIFY);
- }
- break;
- default:
- lock.set_notify_plan(DONT_NOTIFY);
- break;
- }
-}
-
void AllStatus::HandleChannelEvent(const SyncerEvent& event) {
ScopedStatusLockWithNotify lock(this);
switch (event.what_happened) {
@@ -228,6 +184,15 @@ void AllStatus::HandleServerConnectionEvent(
ScopedStatusLockWithNotify lock(this);
status_.server_up = IsGoodReplyFromServer(event.connection_code);
status_.server_reachable = event.server_reachable;
+
+ if (event.connection_code == HttpResponse::SERVER_CONNECTION_OK) {
+ if (!status_.authenticated) {
+ status_ = CreateBlankStatus();
+ }
+ status_.authenticated = true;
+ } else {
+ status_.authenticated = false;
+ }
}
}
@@ -236,31 +201,6 @@ AllStatus::Status AllStatus::status() const {
return status_;
}
-int AllStatus::GetRecommendedDelaySeconds(int base_delay_seconds) {
- if (base_delay_seconds >= kMaxBackoffSeconds)
- return kMaxBackoffSeconds;
-
- // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2
- int backoff_s = (0 == base_delay_seconds) ? 1 :
- base_delay_seconds * kBackoffRandomizationFactor;
-
- // Flip a coin to randomize backoff interval by +/- 50%.
- int rand_sign = base::RandInt(0, 1) * 2 - 1;
-
- // Truncation is adequate for rounding here.
- backoff_s = backoff_s +
- (rand_sign * (base_delay_seconds / kBackoffRandomizationFactor));
-
- // Cap the backoff interval.
- backoff_s = std::min(backoff_s, kMaxBackoffSeconds);
-
- return backoff_s;
-}
-
-int AllStatus::GetRecommendedDelay(int base_delay_ms) const {
- return GetRecommendedDelaySeconds(base_delay_ms / 1000) * 1000;
-}
-
void AllStatus::SetNotificationsEnabled(bool notifications_enabled) {
ScopedStatusLockWithNotify lock(this);
status_.notifications_enabled = notifications_enabled;
diff --git a/chrome/browser/sync/engine/all_status.h b/chrome/browser/sync/engine/all_status.h
index 63edd17..b843a1a 100644
--- a/chrome/browser/sync/engine/all_status.h
+++ b/chrome/browser/sync/engine/all_status.h
@@ -7,10 +7,10 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_ALL_STATUS_H_
#define CHROME_BROWSER_SYNC_ENGINE_ALL_STATUS_H_
+#pragma once
#include <map>
-#include "base/atomicops.h"
#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/sync/util/channel.h"
@@ -86,13 +86,9 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> {
int64 updates_received;
};
- // Maximum interval for exponential backoff.
- static const int kMaxBackoffSeconds;
-
AllStatus();
~AllStatus();
- void WatchConnectionManager(ServerConnectionManager* conn_mgr);
void HandleServerConnectionEvent(const ServerConnectionEvent& event);
void HandleAuthWatcherEvent(const AuthWatcherEvent& event);
@@ -108,12 +104,6 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> {
Status status() const;
- // DDOS avoidance function. The argument and return value is in seconds
- static int GetRecommendedDelaySeconds(int base_delay_seconds);
-
- // This uses AllStatus' max_consecutive_errors as the error count
- int GetRecommendedDelay(int base_delay) const;
-
void SetNotificationsEnabled(bool notifications_enabled);
void IncrementNotificationsSent();
@@ -125,7 +115,6 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> {
// Examines syncer to calculate syncing and the unsynced count,
// and returns a Status with new values.
- Status CalcSyncing() const;
Status CalcSyncing(const SyncerEvent& event) const;
Status CreateBlankStatus() const;
@@ -134,7 +123,6 @@ class AllStatus : public ChannelEventHandler<SyncerEvent> {
Status status_;
Channel* const channel_;
- scoped_ptr<EventListenerHookup> conn_mgr_hookup_;
scoped_ptr<ChannelHookup<SyncerEvent> > syncer_thread_hookup_;
scoped_ptr<EventListenerHookup> diskfull_hookup_;
scoped_ptr<EventListenerHookup> talk_mediator_hookup_;
diff --git a/chrome/browser/sync/engine/all_status_unittest.cc b/chrome/browser/sync/engine/all_status_unittest.cc
deleted file mode 100644
index 86829cd..0000000
--- a/chrome/browser/sync/engine/all_status_unittest.cc
+++ /dev/null
@@ -1,24 +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/sync/engine/all_status.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace browser_sync {
-
-TEST(AllStatus, GetRecommendedDelay) {
- EXPECT_LE(0, AllStatus::GetRecommendedDelaySeconds(0));
- EXPECT_LE(1, AllStatus::GetRecommendedDelaySeconds(1));
- EXPECT_LE(50, AllStatus::GetRecommendedDelaySeconds(50));
- EXPECT_LE(10, AllStatus::GetRecommendedDelaySeconds(10));
- EXPECT_EQ(AllStatus::kMaxBackoffSeconds,
- AllStatus::GetRecommendedDelaySeconds(
- AllStatus::kMaxBackoffSeconds));
- EXPECT_EQ(AllStatus::kMaxBackoffSeconds,
- AllStatus::GetRecommendedDelaySeconds(
- AllStatus::kMaxBackoffSeconds+1));
-}
-
-} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/apply_updates_command.cc b/chrome/browser/sync/engine/apply_updates_command.cc
index 1853f2c..c14dc81 100644
--- a/chrome/browser/sync/engine/apply_updates_command.cc
+++ b/chrome/browser/sync/engine/apply_updates_command.cc
@@ -8,7 +8,6 @@
#include "chrome/browser/sync/sessions/sync_session.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
-#include "chrome/browser/sync/util/sync_types.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/engine/apply_updates_command.h b/chrome/browser/sync/engine/apply_updates_command.h
index c70a517..6afe63c 100644
--- a/chrome/browser/sync/engine/apply_updates_command.h
+++ b/chrome/browser/sync/engine/apply_updates_command.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_APPLY_UPDATES_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_APPLY_UPDATES_COMMAND_H_
+#pragma once
#include "chrome/browser/sync/engine/model_changing_syncer_command.h"
-#include "chrome/browser/sync/util/sync_types.h"
namespace syncable {
class WriteTransaction;
diff --git a/chrome/browser/sync/engine/auth_watcher.cc b/chrome/browser/sync/engine/auth_watcher.cc
deleted file mode 100644
index 46b3852..0000000
--- a/chrome/browser/sync/engine/auth_watcher.cc
+++ /dev/null
@@ -1,351 +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/sync/engine/auth_watcher.h"
-
-#include "base/file_util.h"
-#include "base/string_util.h"
-#include "chrome/browser/sync/engine/all_status.h"
-#include "chrome/browser/sync/engine/authenticator.h"
-#include "chrome/browser/sync/engine/net/server_connection_manager.h"
-#include "chrome/browser/sync/syncable/directory_manager.h"
-#include "chrome/browser/sync/syncable/syncable.h"
-#include "chrome/browser/sync/util/user_settings.h"
-#include "chrome/common/deprecated/event_sys-inl.h"
-#include "chrome/common/net/gaia/gaia_authenticator.h"
-
-// How authentication happens:
-//
-// Kick Off:
-// The sync API looks to see if the user's name and
-// password are stored. If so, it calls authwatcher.Authenticate() with
-// them. Otherwise it fires an error event.
-//
-// On failed Gaia Auth:
-// The AuthWatcher attempts to use saved hashes to authenticate
-// locally, and on success opens the share.
-// On failure, fires an error event.
-//
-// On successful Gaia Auth:
-// AuthWatcher launches a thread to open the share and to get the
-// authentication token from the sync server.
-
-using std::pair;
-using std::string;
-using std::vector;
-
-namespace browser_sync {
-
-AuthWatcher::AuthWatcher(DirectoryManager* dirman,
- ServerConnectionManager* scm,
- const string& user_agent,
- const string& service_id,
- const string& gaia_url,
- UserSettings* user_settings,
- gaia::GaiaAuthenticator* gaia_auth)
- : gaia_(gaia_auth),
- dirman_(dirman),
- scm_(scm),
- status_(NOT_AUTHENTICATED),
- user_settings_(user_settings),
- auth_backend_thread_("SyncEngine_AuthWatcherThread"),
- current_attempt_trigger_(AuthWatcherEvent::USER_INITIATED) {
-
- if (!auth_backend_thread_.Start())
- NOTREACHED() << "Couldn't start SyncEngine_AuthWatcherThread";
-
- gaia_->set_message_loop(message_loop());
-
- connmgr_hookup_.reset(
- NewEventListenerHookup(scm->channel(), this,
- &AuthWatcher::HandleServerConnectionEvent));
- AuthWatcherEvent done = { AuthWatcherEvent::AUTHWATCHER_DESTROYED };
- channel_.reset(new Channel(done));
-}
-
-void AuthWatcher::PersistCredentials() {
- DCHECK_EQ(MessageLoop::current(), message_loop());
- gaia::GaiaAuthenticator::AuthResults results = gaia_->results();
-
- // We just successfully signed in again, let's clear out any residual cached
- // login data from earlier sessions.
- ClearAuthenticationData();
-
- user_settings_->StoreEmailForSignin(results.email, results.primary_email);
- results.email = results.primary_email;
- gaia_->SetUsernamePassword(results.primary_email, results.password);
- if (!user_settings_->VerifyAgainstStoredHash(results.email, results.password))
- user_settings_->StoreHashedPassword(results.email, results.password);
-
- user_settings_->SetAuthTokenForService(results.email,
- SYNC_SERVICE_NAME,
- gaia_->auth_token());
-}
-
-// TODO(chron): Full integration test suite needed. http://crbug.com/35429
-void AuthWatcher::RenewAuthToken(const std::string& updated_token) {
- message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &AuthWatcher::DoRenewAuthToken, updated_token));
-}
-
-void AuthWatcher::DoRenewAuthToken(const std::string& updated_token) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
- // TODO(chron): We should probably only store auth token in one place.
- if (scm_->auth_token() == updated_token) {
- return; // This thread is the only one writing to the SCM's auth token.
- }
- LOG(INFO) << "Updating auth token:" << updated_token;
- scm_->set_auth_token(updated_token);
- gaia_->RenewAuthToken(updated_token); // Must be on AuthWatcher thread
- user_settings_->SetAuthTokenForService(user_settings_->email(),
- SYNC_SERVICE_NAME,
- updated_token);
-
- NotifyAuthChanged(user_settings_->email(), updated_token, true);
-}
-
-void AuthWatcher::AuthenticateWithLsid(const std::string& lsid) {
- message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &AuthWatcher::DoAuthenticateWithLsid, lsid));
-}
-
-void AuthWatcher::DoAuthenticateWithLsid(const std::string& lsid) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
-
- AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START };
- NotifyListeners(&event);
-
- if (gaia_->AuthenticateWithLsid(lsid)) {
- PersistCredentials();
- DoAuthenticateWithToken(gaia_->email(), gaia_->auth_token());
- } else {
- ProcessGaiaAuthFailure();
- }
-}
-
-const char kAuthWatcher[] = "AuthWatcher";
-
-void AuthWatcher::AuthenticateWithToken(const std::string& gaia_email,
- const std::string& auth_token) {
- message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &AuthWatcher::DoAuthenticateWithToken, gaia_email, auth_token));
-}
-
-void AuthWatcher::DoAuthenticateWithToken(const std::string& gaia_email,
- const std::string& auth_token) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
-
- Authenticator auth(scm_, user_settings_);
- Authenticator::AuthenticationResult result =
- auth.AuthenticateToken(auth_token);
- string email = gaia_email;
- if (auth.display_email() && *auth.display_email()) {
- email = auth.display_email();
- LOG(INFO) << "Auth returned email " << email << " for gaia email " <<
- gaia_email;
- }
-
- AuthWatcherEvent event = {AuthWatcherEvent::ILLEGAL_VALUE , 0};
- gaia_->SetUsername(email);
- gaia_->SetAuthToken(auth_token);
- const bool was_authenticated = NOT_AUTHENTICATED != status_;
- switch (result) {
- case Authenticator::SUCCESS:
- {
- status_ = GAIA_AUTHENTICATED;
- const std::string& share_name = email;
- user_settings_->SwitchUser(email);
- scm_->set_auth_token(auth_token);
-
- if (!was_authenticated) {
- LOG(INFO) << "Opening DB for AuthenticateWithToken ("
- << share_name << ")";
- dirman_->Open(share_name);
- }
- NotifyAuthChanged(email, auth_token, false);
- return;
- }
- case Authenticator::BAD_AUTH_TOKEN:
- event.what_happened = AuthWatcherEvent::SERVICE_AUTH_FAILED;
- break;
- case Authenticator::CORRUPT_SERVER_RESPONSE:
- case Authenticator::SERVICE_DOWN:
- event.what_happened = AuthWatcherEvent::SERVICE_CONNECTION_FAILED;
- break;
- case Authenticator::USER_NOT_ACTIVATED:
- event.what_happened = AuthWatcherEvent::SERVICE_USER_NOT_SIGNED_UP;
- break;
- default:
- LOG(FATAL) << "Illegal return from AuthenticateToken";
- return;
- }
- // Always fall back to local authentication.
- if (was_authenticated || AuthenticateLocally(email)) {
- if (AuthWatcherEvent::SERVICE_CONNECTION_FAILED == event.what_happened)
- return;
- }
- DCHECK_NE(event.what_happened, AuthWatcherEvent::ILLEGAL_VALUE);
- NotifyListeners(&event);
-}
-
-bool AuthWatcher::AuthenticateLocally(string email) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
- user_settings_->GetEmailForSignin(&email);
- if (file_util::PathExists(FilePath(dirman_->GetSyncDataDatabasePath()))) {
- gaia_->SetUsername(email);
- status_ = LOCALLY_AUTHENTICATED;
- user_settings_->SwitchUser(email);
- LOG(INFO) << "Opening DB for AuthenticateLocally (" << email << ")";
- dirman_->Open(email);
- NotifyAuthChanged(email, "", false);
- return true;
- } else {
- return false;
- }
-}
-
-bool AuthWatcher::AuthenticateLocally(string email, const string& password) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
- user_settings_->GetEmailForSignin(&email);
- return user_settings_->VerifyAgainstStoredHash(email, password)
- && AuthenticateLocally(email);
-}
-
-void AuthWatcher::ProcessGaiaAuthFailure() {
- DCHECK_EQ(MessageLoop::current(), message_loop());
- gaia::GaiaAuthenticator::AuthResults results = gaia_->results();
- if (LOCALLY_AUTHENTICATED != status_ &&
- AuthenticateLocally(results.email, results.password)) {
- // TODO(chron): Do we really want a bogus token?
- const string auth_token("bogus");
- user_settings_->SetAuthTokenForService(results.email,
- SYNC_SERVICE_NAME,
- auth_token);
- }
- AuthWatcherEvent myevent = { AuthWatcherEvent::GAIA_AUTH_FAILED, &results };
- NotifyListeners(&myevent);
-}
-
-void AuthWatcher::DoAuthenticate(const AuthRequest& request) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
-
- AuthWatcherEvent event = { AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START };
- NotifyListeners(&event);
-
- current_attempt_trigger_ = request.trigger;
-
- // We let the caller be lazy and try using the last captcha token seen by
- // the gaia authenticator if they haven't provided a token but have sent
- // a challenge response. Of course, if the captcha token is specified,
- // we use that one instead.
- std::string captcha_token(request.captcha_token);
- if (!request.captcha_value.empty() && captcha_token.empty())
- captcha_token = gaia_->captcha_token();
-
- if (!request.password.empty()) {
- bool authenticated = false;
- if (!captcha_token.empty()) {
- authenticated = gaia_->Authenticate(request.email, request.password,
- captcha_token,
- request.captcha_value);
- } else {
- authenticated = gaia_->Authenticate(request.email, request.password);
- }
- if (authenticated) {
- PersistCredentials();
- DoAuthenticateWithToken(gaia_->email(), gaia_->auth_token());
- } else {
- ProcessGaiaAuthFailure();
- }
- } else if (!request.auth_token.empty()) {
- DoAuthenticateWithToken(request.email, request.auth_token);
- } else {
- LOG(ERROR) << "Attempt to authenticate with no credentials.";
- }
-}
-
-void AuthWatcher::NotifyAuthChanged(const string& email,
- const string& auth_token,
- bool renewed) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
- LOG(INFO) << "NotifyAuthSucceeded";
- AuthWatcherEvent event = {
- renewed ?
- AuthWatcherEvent::AUTH_RENEWED :
- AuthWatcherEvent::AUTH_SUCCEEDED
- };
- event.user_email = email;
- event.auth_token = auth_token;
-
- NotifyListeners(&event);
-}
-
-void AuthWatcher::HandleServerConnectionEvent(
- const ServerConnectionEvent& event) {
- message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &AuthWatcher::DoHandleServerConnectionEvent, event,
- scm_->auth_token()));
-}
-
-void AuthWatcher::DoHandleServerConnectionEvent(
- const ServerConnectionEvent& event,
- const std::string& auth_token_snapshot) {
- DCHECK_EQ(MessageLoop::current(), message_loop());
- if (event.server_reachable &&
- // If the auth_token at the time of the event differs from the current
- // one, we have authenticated since then and don't need to re-try.
- (auth_token_snapshot == gaia_->auth_token()) &&
- (event.connection_code == HttpResponse::SYNC_AUTH_ERROR ||
- status_ == LOCALLY_AUTHENTICATED)) {
- // We're either online or just got reconnected and want to try to
- // authenticate. If we've got a saved token this should just work. If not
- // the auth failure should trigger UI indications that we're not logged in.
-
- // METRIC: If we get a SYNC_AUTH_ERROR, our token expired.
- gaia::GaiaAuthenticator::AuthResults authresults = gaia_->results();
- AuthRequest request = { authresults.email, authresults.password,
- authresults.auth_token, std::string(),
- std::string(),
- AuthWatcherEvent::EXPIRED_CREDENTIALS };
- DoAuthenticate(request);
- }
-}
-
-AuthWatcher::~AuthWatcher() {
- auth_backend_thread_.Stop();
- // The gaia authenticator takes a const MessageLoop* because it only uses it
- // to ensure all methods are invoked on the given loop. Once our thread has
- // stopped, the current message loop will be NULL, and no methods should be
- // invoked on |gaia_| after this point. We could set it to NULL, but
- // abstaining allows for even more sanity checking that nothing is invoked on
- // it from now on.
-}
-
-void AuthWatcher::Authenticate(const string& email, const string& password,
- const string& captcha_token, const string& captcha_value) {
- LOG(INFO) << "AuthWatcher::Authenticate called";
-
- string empty;
- AuthRequest request = { FormatAsEmailAddress(email), password, empty,
- captcha_token, captcha_value,
- AuthWatcherEvent::USER_INITIATED };
- message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &AuthWatcher::DoAuthenticate, request));
-}
-
-void AuthWatcher::ClearAuthenticationData() {
- scm_->set_auth_token(std::string());
- user_settings_->ClearAllServiceTokens();
-}
-
-string AuthWatcher::email() const {
- return gaia_->email();
-}
-
-void AuthWatcher::NotifyListeners(AuthWatcherEvent* event) {
- event->trigger = current_attempt_trigger_;
- channel_->NotifyListeners(*event);
-}
-
-} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/auth_watcher.h b/chrome/browser/sync/engine/auth_watcher.h
deleted file mode 100644
index acce5b9..0000000
--- a/chrome/browser/sync/engine/auth_watcher.h
+++ /dev/null
@@ -1,218 +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.
-//
-// AuthWatcher watches authentication events and user open and close
-// events and accordingly opens and closes shares.
-
-#ifndef CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_
-#define CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_
-
-#include <map>
-#include <string>
-
-#include "base/atomicops.h"
-#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/thread.h"
-#include "chrome/browser/sync/protocol/service_constants.h"
-#include "chrome/browser/sync/util/sync_types.h"
-#include "chrome/common/deprecated/event_sys.h"
-#include "chrome/common/net/gaia/gaia_authenticator.h"
-
-namespace syncable {
-struct DirectoryManagerEvent;
-class DirectoryManager;
-}
-
-namespace browser_sync {
-
-class AuthWatcher;
-class ServerConnectionManager;
-class URLFactory;
-class UserSettings;
-struct ServerConnectionEvent;
-
-struct AuthWatcherEvent {
- enum WhatHappened {
- AUTHENTICATION_ATTEMPT_START,
- AUTHWATCHER_DESTROYED,
- AUTH_RENEWED, // Currently only used in testing.
- AUTH_SUCCEEDED,
- GAIA_AUTH_FAILED,
- SERVICE_USER_NOT_SIGNED_UP,
- SERVICE_AUTH_FAILED,
- SERVICE_CONNECTION_FAILED,
- // Used in a safety check in AuthWatcher::AuthenticateWithToken()
- ILLEGAL_VALUE,
- };
- WhatHappened what_happened;
- const gaia::GaiaAuthenticator::AuthResults* auth_results;
- // use AuthWatcherEvent as its own traits type in hookups.
- typedef AuthWatcherEvent EventType;
- static inline bool IsChannelShutdownEvent(const AuthWatcherEvent& event) {
- return event.what_happened == AUTHWATCHER_DESTROYED;
- }
-
- // Used for AUTH_SUCCEEDED/AUTH_RENEWED notification.
- std::string user_email;
- // May be empty if we're only locally authenticated.
- std::string auth_token;
-
- // How was this auth attempt initiated?
- enum AuthenticationTrigger {
- USER_INITIATED = 0, // default value.
- EXPIRED_CREDENTIALS,
- };
-
- AuthenticationTrigger trigger;
-};
-
-// The mother-class of Authentication for the sync backend. Handles both gaia
-// and sync service authentication via asynchronous Authenticate* methods,
-// raising AuthWatcherEvents on success/failure. The implementation currently
-// runs its own backend thread for the actual auth processing, which means
-// the AuthWatcherEvents can be raised on a different thread than the one that
-// invoked authentication.
-class AuthWatcher : public base::RefCountedThreadSafe<AuthWatcher> {
- friend class AuthWatcherTest;
- FRIEND_TEST_ALL_PREFIXES(AuthWatcherTest, Construction);
- public:
- // Normal progression is local -> gaia -> token.
- enum Status { LOCALLY_AUTHENTICATED, GAIA_AUTHENTICATED, NOT_AUTHENTICATED };
- typedef syncable::DirectoryManagerEvent DirectoryManagerEvent;
- typedef syncable::DirectoryManager DirectoryManager;
-
- AuthWatcher(DirectoryManager* dirman,
- ServerConnectionManager* scm,
- const std::string& user_agent,
- const std::string& service_id,
- const std::string& gaia_url,
- UserSettings* user_settings,
- gaia::GaiaAuthenticator* gaia_auth);
- ~AuthWatcher();
-
- typedef EventChannel<AuthWatcherEvent, Lock> Channel;
-
- inline Channel* channel() const {
- return channel_.get();
- }
-
- // The following 3 flavors of authentication routines are asynchronous and can
- // be called from any thread.
- // If |captcha_value| is specified but |captcha_token| is not, this will
- // attempt authentication using the last observed captcha token out of
- // convenience in the common case so the token doesn't have to be plumbed
- // everywhere.
- void Authenticate(const std::string& email, const std::string& password,
- const std::string& captcha_token, const std::string& captcha_value);
-
- void Authenticate(const std::string& email, const std::string& password,
- bool persist_creds_to_disk) {
- Authenticate(email, password, "", "");
- }
-
- // Use this to update only the token of the current email address.
- void RenewAuthToken(const std::string& updated_token);
-
- // Use this version when you don't need the gaia authentication step because
- // you already have a valid LSID cookie for |gaia_email|.
- void AuthenticateWithLsid(const std::string& lsid);
-
- // Use this version when you don't need the gaia authentication step because
- // you already have a valid token for |gaia_email|.
- void AuthenticateWithToken(const std::string& gaia_email,
- const std::string& auth_token);
-
- // Joins on the backend thread. The AuthWatcher is useless after this and
- // should be destroyed.
- void Shutdown() { auth_backend_thread_.Stop(); }
-
- std::string email() const;
- syncable::DirectoryManager* dirman() const { return dirman_; }
- ServerConnectionManager* scm() const { return scm_; }
- UserSettings* settings() const { return user_settings_; }
- Status status() const { return (Status)status_; }
-
- private:
- void ClearAuthenticationData();
-
- void NotifyAuthChanged(const std::string& email,
- const std::string& auth_token,
- bool renewed);
- void HandleServerConnectionEvent(const ServerConnectionEvent& event);
-
- void SaveUserSettings(const std::string& username,
- const std::string& auth_token);
-
- MessageLoop* message_loop() { return auth_backend_thread_.message_loop(); }
-
- void DoRenewAuthToken(const std::string& updated_token);
-
- // These two helpers should only be called from the auth function.
- // Called when authentication with gaia succeeds, to save credential info.
- void PersistCredentials();
- // Called when authentication with gaia fails.
- void ProcessGaiaAuthFailure();
-
- // Just checks that the user has at least one local share cache.
- bool AuthenticateLocally(std::string email);
- // Also checks the user's password against stored password hash.
- bool AuthenticateLocally(std::string email, const std::string& password);
-
- // Sets the trigger member of the event and sends the event on channel_.
- void NotifyListeners(AuthWatcherEvent* event);
-
- inline std::string FormatAsEmailAddress(const std::string& email) const {
- std::string mail(email);
- if (email.find('@') == std::string::npos) {
- mail.push_back('@');
- // TODO(chron): Should this be done only at the UI level?
- mail.append(DEFAULT_SIGNIN_DOMAIN);
- }
- return mail;
- }
-
- // A struct to marshal various data across to the auth_backend_thread_ on
- // Authenticate() and AuthenticateWithToken calls.
- struct AuthRequest {
- std::string email;
- std::string password;
- std::string auth_token;
- std::string captcha_token;
- std::string captcha_value;
- bool persist_creds_to_disk;
- AuthWatcherEvent::AuthenticationTrigger trigger;
- };
-
- // The public interface Authenticate methods are proxies to these, which
- // can only be called from |auth_backend_thread_|.
- void DoAuthenticate(const AuthRequest& request);
- void DoAuthenticateWithLsid(const std::string& lsid);
- void DoAuthenticateWithToken(const std::string& email,
- const std::string& auth_token);
-
- // The public HandleServerConnectionEvent method proxies to this method, which
- // can only be called on |auth_backend_thread_|.
- void DoHandleServerConnectionEvent(
- const ServerConnectionEvent& event,
- const std::string& auth_token_snapshot);
-
- scoped_ptr<gaia::GaiaAuthenticator> const gaia_;
- syncable::DirectoryManager* const dirman_;
- ServerConnectionManager* const scm_;
- scoped_ptr<EventListenerHookup> connmgr_hookup_;
- Status status_;
- UserSettings* const user_settings_;
- scoped_ptr<Channel> channel_;
-
- base::Thread auth_backend_thread_;
-
- AuthWatcherEvent::AuthenticationTrigger current_attempt_trigger_;
- DISALLOW_COPY_AND_ASSIGN(AuthWatcher);
-};
-
-} // namespace browser_sync
-
-#endif // CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_
diff --git a/chrome/browser/sync/engine/auth_watcher_unittest.cc b/chrome/browser/sync/engine/auth_watcher_unittest.cc
deleted file mode 100644
index a77a33b..0000000
--- a/chrome/browser/sync/engine/auth_watcher_unittest.cc
+++ /dev/null
@@ -1,234 +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 "base/scoped_temp_dir.h"
-#include "base/test/test_file_util.h"
-#include "base/waitable_event.h"
-#include "chrome/browser/password_manager/encryptor.h"
-#include "chrome/browser/sync/engine/all_status.h"
-#include "chrome/browser/sync/engine/auth_watcher.h"
-#include "chrome/browser/sync/util/user_settings.h"
-#include "chrome/common/deprecated/event_sys-inl.h"
-#include "chrome/common/net/http_return.h"
-#include "chrome/common/net/gaia/gaia_authenticator.h"
-#include "chrome/test/sync/engine/mock_connection_manager.h"
-#include "chrome/test/sync/engine/test_directory_setter_upper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-static FilePath::CharType kUserSettingsDB[] =
- FILE_PATH_LITERAL("Settings.sqlite3");
-static const char* kTestUserAgent = "useragent";
-static const char* kTestServiceId = "serviceid";
-static const char* kTestGaiaURL = "http://gaia_url";
-static const char* kUserDisplayName = "Mr. Auth Watcher";
-static const char* kUserDisplayEmail = "authwatcherdisplay@gmail.com";
-static const char* kTestEmail = "authwatchertest@gmail.com";
-static const char* kWrongPassword = "wrongpassword";
-static const char* kCorrectPassword = "correctpassword";
-static const char* kValidSID = "validSID";
-static const char* kValidLSID = "validLSID";
-static const char* kInvalidAuthToken = "invalidAuthToken";
-static const char* kValidAuthToken = "validAuthToken";
-
-namespace browser_sync {
-
-class GaiaAuthMockForAuthWatcher : public gaia::GaiaAuthenticator {
- public:
- GaiaAuthMockForAuthWatcher() : GaiaAuthenticator(
- kTestUserAgent, kTestServiceId, kTestGaiaURL),
- use_bad_auth_token_(false) {}
- virtual ~GaiaAuthMockForAuthWatcher() {}
-
- virtual int GetBackoffDelaySeconds(
- int current_backoff_delay) {
- return AllStatus::GetRecommendedDelaySeconds(current_backoff_delay);
- }
-
- void SendBadAuthTokenForNextRequest() { use_bad_auth_token_ = true; }
-
- std::string renewed_token() {
- return renewed_token_;
- }
-
- protected:
- bool PerformGaiaRequest(const AuthParams& params, AuthResults* results) {
- if (params.password == kWrongPassword) {
- results->auth_error = gaia::BadAuthentication;
- return false;
- }
- if (params.password == kCorrectPassword) {
- results->sid = kValidSID;
- results->lsid = kValidLSID;
- results->auth_token = kValidAuthToken;
- }
- if (use_bad_auth_token_) {
- results->auth_token = kInvalidAuthToken;
- use_bad_auth_token_ = false;
- }
- return true;
- }
-
- void RenewAuthToken(const std::string& auth_token) {
- renewed_token_ = auth_token;
- }
-
- private:
- // Whether we should send an invalid auth token on the next request.
- bool use_bad_auth_token_;
- std::string renewed_token_;
-};
-
-class AuthWatcherTest : public testing::Test {
- public:
- AuthWatcherTest() : metadb_(kUserDisplayEmail),
- consumer_ready(false, false),
- event_produced(false, false) {}
- virtual void SetUp() {
-#if defined(OS_MACOSX)
- // Need to mock the Keychain for unit tests on Mac to avoid possible
- // blocking UI. |SetAuthTokenForService| uses Encryptor.
- Encryptor::UseMockKeychain(true);
-#endif
- metadb_.SetUp();
- connection_.reset(new MockConnectionManager(metadb_.manager(),
- metadb_.name()));
- // Mock out data that would normally be sent back from a server.
- connection()->SetAuthenticationResponseInfo(kValidAuthToken,
- kUserDisplayName, kUserDisplayEmail, "ID");
- user_settings_.reset(new UserSettings());
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- FilePath user_settings_path = temp_dir_.path().Append(kUserSettingsDB);
- user_settings_->Init(user_settings_path);
- gaia_auth_ = new GaiaAuthMockForAuthWatcher();
- auth_watcher_ = new AuthWatcher(metadb_.manager(), connection_.get(),
- kTestUserAgent, kTestServiceId, kTestGaiaURL,
- user_settings_.get(), gaia_auth_);
- authwatcher_hookup_.reset(NewEventListenerHookup(auth_watcher_->channel(),
- this, &AuthWatcherTest::HandleAuthWatcherEvent));
- }
-
- virtual void TearDown() {
- metadb_.TearDown();
- auth_watcher_->Shutdown();
- EXPECT_FALSE(auth_watcher()->message_loop());
- }
-
- void HandleAuthWatcherEvent(const AuthWatcherEvent& event) {
- if (event.what_happened == AuthWatcherEvent::AUTHWATCHER_DESTROYED)
- return;
- consumer_ready.Wait(); // Block progress until the test is ready.
-
- last_event_reason_ = event.what_happened;
- if (event.what_happened == AuthWatcherEvent::AUTH_SUCCEEDED)
- user_email_ = event.user_email;
-
- event_produced.Signal();
- }
-
- AuthWatcherEvent::WhatHappened ConsumeNextEvent() {
- consumer_ready.Signal();
- event_produced.Wait();
- return last_event_reason_;
- }
-
- AuthWatcher* auth_watcher() { return auth_watcher_.get(); }
- MockConnectionManager* connection() { return connection_.get(); }
- GaiaAuthMockForAuthWatcher* gaia_auth() { return gaia_auth_; }
- const std::string& user_email() { return user_email_; }
-
- private:
- // Responsible for creating / deleting a temp dir containing user settings DB.
- ScopedTempDir temp_dir_;
-
- // The event listener hookup registered for HandleAuthWatcherEvent.
- scoped_ptr<EventListenerHookup> authwatcher_hookup_;
-
- // The sync engine pieces necessary to run an AuthWatcher.
- TriggeredOpenTestDirectorySetterUpper metadb_;
- scoped_ptr<MockConnectionManager> connection_;
- scoped_ptr<UserSettings> user_settings_;
- GaiaAuthMockForAuthWatcher* gaia_auth_; // Owned by auth_watcher_.
- scoped_refptr<AuthWatcher> auth_watcher_;
-
- // This is used to block the AuthWatcherThread when it raises events until we
- // are ready to read the event. It is not a manual-reset event, so it goes
- // straight back to non-signaled after one thread (the main thread) is
- // signaled (or "consumes" the signaled state).
- base::WaitableEvent consumer_ready;
-
- // This is signaled by the AuthWatcherThread after it sets last_event_reason_
- // and possibly user_email_ for us to read.
- base::WaitableEvent event_produced;
-
- // The 'WhatHappened' value from the last AuthWatcherEvent we handled.
- AuthWatcherEvent::WhatHappened last_event_reason_;
-
- // Set when we receive an AUTH_SUCCEEDED event.
- std::string user_email_;
-
- DISALLOW_COPY_AND_ASSIGN(AuthWatcherTest);
-};
-
-TEST_F(AuthWatcherTest, Construction) {
- EXPECT_TRUE(auth_watcher()->message_loop());
- EXPECT_EQ("SyncEngine_AuthWatcherThread",
- auth_watcher()->message_loop()->thread_name());
- EXPECT_TRUE(auth_watcher()->auth_backend_thread_.IsRunning());
- EXPECT_EQ(AuthWatcher::NOT_AUTHENTICATED, auth_watcher()->status());
-}
-
-TEST_F(AuthWatcherTest, AuthenticateGaiaAuthFailure) {
- auth_watcher()->Authenticate(kTestEmail, kWrongPassword,
- std::string(), // captcha_token
- std::string()); // captcha_value
-
- EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
- EXPECT_EQ(AuthWatcherEvent::GAIA_AUTH_FAILED, ConsumeNextEvent());
-}
-
-TEST_F(AuthWatcherTest, AuthenticateBadAuthToken) {
- gaia_auth()->SendBadAuthTokenForNextRequest();
- auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(),
- std::string());
- EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
- EXPECT_EQ(AuthWatcherEvent::SERVICE_AUTH_FAILED, ConsumeNextEvent());
-}
-
-TEST_F(AuthWatcherTest, AuthenticateSuccess) {
- auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(),
- std::string());
- EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
- EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent());
-
- // The server responds with a different email than what we used in the call
- // to Authenticate, and the AuthWatcher should have told us about.
- EXPECT_EQ(kUserDisplayEmail, user_email());
-}
-
-TEST_F(AuthWatcherTest, AuthenticateWithTokenBadAuthToken) {
- auth_watcher()->AuthenticateWithToken(kTestEmail, kInvalidAuthToken);
- EXPECT_EQ(AuthWatcherEvent::SERVICE_AUTH_FAILED, ConsumeNextEvent());
-}
-
-TEST_F(AuthWatcherTest, AuthenticateWithTokenSuccess) {
- auth_watcher()->AuthenticateWithToken(kTestEmail, kValidAuthToken);
- EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent());
- EXPECT_EQ(kUserDisplayEmail, user_email());
-}
-
-// Just check that the thread task was properly issued.
-TEST_F(AuthWatcherTest, RenewAuthToken) {
- auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(),
- std::string());
- EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
- EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent());
-
- auth_watcher()->RenewAuthToken("updated_token");
- EXPECT_EQ(AuthWatcherEvent::AUTH_RENEWED, ConsumeNextEvent());
- EXPECT_EQ(gaia_auth()->renewed_token(), "updated_token");
- EXPECT_EQ(connection()->auth_token(), "updated_token");
-}
-
-} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/authenticator.cc b/chrome/browser/sync/engine/authenticator.cc
deleted file mode 100644
index eec7af3..0000000
--- a/chrome/browser/sync/engine/authenticator.cc
+++ /dev/null
@@ -1,110 +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/sync/engine/authenticator.h"
-
-#include "chrome/browser/sync/engine/net/server_connection_manager.h"
-#include "chrome/browser/sync/engine/syncproto.h"
-#include "chrome/browser/sync/protocol/sync.pb.h"
-#include "chrome/browser/sync/util/user_settings.h"
-#include "chrome/common/deprecated/event_sys-inl.h"
-#include "chrome/common/net/gaia/gaia_authenticator.h"
-
-namespace browser_sync {
-
-using std::string;
-
-Authenticator::Authenticator(ServerConnectionManager* manager,
- UserSettings* settings)
- : server_connection_manager_(manager), settings_(settings) {
-}
-
-Authenticator::Authenticator(ServerConnectionManager* manager)
- : server_connection_manager_(manager), settings_(NULL) {
-}
-
-Authenticator::AuthenticationResult Authenticator::Authenticate() {
- // TODO(sync): Pull and work with saved credentials.
- return NO_SAVED_CREDENTIALS;
-}
-
-Authenticator::AuthenticationResult Authenticator::Authenticate(
- string username, string password) {
- // TODO(sync): need to figure out if this routine is used anywhere other
- // than the test code.
- gaia::GaiaAuthenticator auth_service("ChromiumBrowser", "chromiumsync",
- "https://www.google.com:443/accounts/ClientLogin");
- auth_service.set_message_loop(MessageLoop::current());
- if (!auth_service.Authenticate(username, password)) {
- return UNSPECIFIC_ERROR_RETURN;
- }
- CHECK(!auth_service.auth_token().empty());
- return AuthenticateToken(auth_service.auth_token());
-}
-
-COMPILE_ASSERT(sync_pb::ClientToServerResponse::ErrorType_MAX == 7,
- client_to_server_response_errors_changed);
-
-Authenticator::AuthenticationResult Authenticator::HandleSuccessfulTokenRequest(
- const sync_pb::UserIdentification* user) {
- display_email_ = user->has_email() ? user->email() : "";
- display_name_ = user->has_display_name() ? user->display_name() : "";
- obfuscated_id_ = user->has_obfuscated_id() ? user->obfuscated_id() : "";
- return SUCCESS;
-}
-
-Authenticator::AuthenticationResult Authenticator::AuthenticateToken(
- string auth_token) {
- ClientToServerMessage client_to_server_message;
- // Used to be required for all requests.
- client_to_server_message.set_share("");
- client_to_server_message.set_message_contents(
- ClientToServerMessage::AUTHENTICATE);
-
- string tx, rx;
- client_to_server_message.SerializeToString(&tx);
- HttpResponse http_response;
-
- ServerConnectionManager::PostBufferParams params =
- { tx, &rx, &http_response };
- ScopedServerStatusWatcher watch(server_connection_manager_, &http_response);
- if (!server_connection_manager_->PostBufferWithAuth(&params, auth_token,
- &watch)) {
- LOG(WARNING) << "Error posting from authenticator:" << http_response;
- return SERVICE_DOWN;
- }
- sync_pb::ClientToServerResponse response;
- if (!response.ParseFromString(rx))
- return CORRUPT_SERVER_RESPONSE;
-
- switch (response.error_code()) {
- case sync_pb::ClientToServerResponse::SUCCESS:
- if (response.has_authenticate() && response.authenticate().has_user())
- return HandleSuccessfulTokenRequest(&response.authenticate().user());
- // TODO:(sync) make this CORRUPT_SERVER_RESPONSE when all servers are
- // returning user identification at login time.
- return SUCCESS;
- case sync_pb::ClientToServerResponse::USER_NOT_ACTIVATED:
- return USER_NOT_ACTIVATED;
- case sync_pb::ClientToServerResponse::AUTH_INVALID:
- case sync_pb::ClientToServerResponse::AUTH_EXPIRED:
- // TODO(tim): This is an egregious layering violation (bug 35060).
- http_response.server_status = HttpResponse::SYNC_AUTH_ERROR;
- return BAD_AUTH_TOKEN;
- // should never happen (no birthday in this request).
- case sync_pb::ClientToServerResponse::NOT_MY_BIRTHDAY:
- // should never happen (auth isn't throttled).
- case sync_pb::ClientToServerResponse::THROTTLED:
- // should never happen (only for stores).
- case sync_pb::ClientToServerResponse::ACCESS_DENIED:
- // should never happen (only sent on get updates / commit)
- case sync_pb::ClientToServerResponse::CLEAR_PENDING:
- default:
- LOG(ERROR) << "Corrupt Server packet received by auth, error code " <<
- response.error_code();
- return CORRUPT_SERVER_RESPONSE;
- }
-}
-
-} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/authenticator.h b/chrome/browser/sync/engine/authenticator.h
deleted file mode 100644
index 710fad3..0000000
--- a/chrome/browser/sync/engine/authenticator.h
+++ /dev/null
@@ -1,104 +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.
-//
-// The authenticator is a cross-platform class that handles authentication for
-// the sync client.
-//
-// Current State:
-// The authenticator is currently only used to authenticate tokens using the
-// newer protocol buffer request.
-
-#ifndef CHROME_BROWSER_SYNC_ENGINE_AUTHENTICATOR_H_
-#define CHROME_BROWSER_SYNC_ENGINE_AUTHENTICATOR_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/port.h"
-
-namespace sync_pb {
-class UserIdentification;
-}
-
-namespace browser_sync {
-
-class ServerConnectionManager;
-class UserSettings;
-
-class Authenticator {
- public:
- // Single return enum.
- enum AuthenticationResult {
- SUCCESS = 0,
- // We couldn't log on because we don't have saved credentials.
- NO_SAVED_CREDENTIALS,
- // We can't reach auth server (i.e. we're offline or server's down).
- NOT_CONNECTED,
- // Server's up, but we're down.
- SERVICE_DOWN,
- // We contacted the server, but the response didn't make sense.
- CORRUPT_SERVER_RESPONSE,
- // Bad username/password.
- BAD_CREDENTIALS,
- // Credentials are fine, but the user hasn't signed up.
- USER_NOT_ACTIVATED,
-
- // Return values for internal use.
-
- // We will never return this to the user unless they call AuthenticateToken
- // directly. Other auth functions retry and then return
- // CORRUPT_SERVER_RESPONSE.
- // TODO(sync): Implement retries.
- BAD_AUTH_TOKEN,
- // We should never return this, it's a placeholder during development.
- // TODO(sync): Remove this
- UNSPECIFIC_ERROR_RETURN,
- };
-
- // Constructor. This class will keep the connection authenticated.
- // TODO(sync): Make it work as described.
- // TODO(sync): Require a UI callback mechanism.
- Authenticator(ServerConnectionManager* manager, UserSettings* settings);
-
- // Constructor for a simple authenticator used for programmatic login from
- // test programs.
- explicit Authenticator(ServerConnectionManager* manager);
-
- // This version of Authenticate tries to use saved credentials, if we have
- // any.
- AuthenticationResult Authenticate();
-
- // We save the username and password in memory (if given) so we
- // can refresh the long-lived auth token if it expires.
- // Also we save a 10-bit hash of the password to allow offline login.
- AuthenticationResult Authenticate(std::string username, std::string password);
-
- // A version of the auth token to authenticate cookie portion of
- // authentication. It uses the new proto buffer based call instead of the HTTP
- // GET based one we currently use.
- // Can return one of SUCCESS, SERVICE_DOWN, CORRUPT_SERVER_RESPONSE,
- // USER_NOT_ACTIVATED or BAD_AUTH_TOKEN. See above for the meaning of these
- // values.
- // TODO(sync): Make this function private when we're done.
- AuthenticationResult AuthenticateToken(std::string auth_token);
-
- const char* display_email() const { return display_email_.c_str(); }
- const char* display_name() const { return display_name_.c_str(); }
- private:
- // Stores the information in the UserIdentification returned from the server.
- AuthenticationResult HandleSuccessfulTokenRequest(
- const sync_pb::UserIdentification* user);
- // The server connection manager that we're looking after.
- ServerConnectionManager* server_connection_manager_;
- // Returns SUCCESS or the value that should be returned to the user.
- std::string display_email_;
- std::string display_name_;
- std::string obfuscated_id_;
- UserSettings* const settings_;
- DISALLOW_COPY_AND_ASSIGN(Authenticator);
-};
-
-} // namespace browser_sync
-
-#endif // CHROME_BROWSER_SYNC_ENGINE_AUTHENTICATOR_H_
diff --git a/chrome/browser/sync/engine/build_and_process_conflict_sets_command.cc b/chrome/browser/sync/engine/build_and_process_conflict_sets_command.cc
index ca27be0..ab4e3ff 100644
--- a/chrome/browser/sync/engine/build_and_process_conflict_sets_command.cc
+++ b/chrome/browser/sync/engine/build_and_process_conflict_sets_command.cc
@@ -10,7 +10,6 @@
#include "base/basictypes.h"
#include "base/format_macros.h"
-#include "base/rand_util.h"
#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/engine/update_applicator.h"
#include "chrome/browser/sync/sessions/sync_session.h"
@@ -227,12 +226,12 @@ void BuildAndProcessConflictSetsCommand::BuildConflictSets(
set<syncable::Id>::iterator i = conflict_progress->ConflictingItemsBegin();
while (i != conflict_progress->ConflictingItemsEnd()) {
syncable::Entry entry(trans, syncable::GET_BY_ID, *i);
- CHECK(entry.good());
- if (!entry.Get(syncable::IS_UNSYNCED) &&
- !entry.Get(syncable::IS_UNAPPLIED_UPDATE)) {
+ if (!entry.good() ||
+ (!entry.Get(syncable::IS_UNSYNCED) &&
+ !entry.Get(syncable::IS_UNAPPLIED_UPDATE))) {
// This can happen very rarely. It means we had a simply conflicting item
- // that randomly committed. We drop the entry as it's no longer
- // conflicting.
+ // that randomly committed; its ID could have changed during the commit.
+ // We drop the entry as it's no longer conflicting.
conflict_progress->EraseConflictingItemById(*(i++));
continue;
}
diff --git a/chrome/browser/sync/engine/build_and_process_conflict_sets_command.h b/chrome/browser/sync/engine/build_and_process_conflict_sets_command.h
index e2edb22..cea1d79 100644
--- a/chrome/browser/sync/engine/build_and_process_conflict_sets_command.h
+++ b/chrome/browser/sync/engine/build_and_process_conflict_sets_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_BUILD_AND_PROCESS_CONFLICT_SETS_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_BUILD_AND_PROCESS_CONFLICT_SETS_COMMAND_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/sync/engine/build_commit_command.cc b/chrome/browser/sync/engine/build_commit_command.cc
index b3767e4..79d4ef7 100644
--- a/chrome/browser/sync/engine/build_commit_command.cc
+++ b/chrome/browser/sync/engine/build_commit_command.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.
@@ -8,13 +8,13 @@
#include <string>
#include <vector>
+#include "base/string_util.h"
#include "chrome/browser/sync/engine/syncer_proto_util.h"
#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/sessions/sync_session.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/syncable/syncable_changes_version.h"
-#include "chrome/browser/sync/util/sync_types.h"
using std::set;
using std::string;
@@ -47,7 +47,7 @@ void BuildCommitCommand::AddExtensionsActivityToMessage(
session->extensions_activity();
for (ExtensionsActivityMonitor::Records::const_iterator it = records.begin();
it != records.end(); ++it) {
- sync_pb::CommitMessage_ChromiumExtensionsActivity* activity_message =
+ sync_pb::ChromiumExtensionsActivity* activity_message =
message->add_extensions_activity();
activity_message->set_extension_id(it->second.extension_id);
activity_message->set_bookmark_writes_since_last_commit(
diff --git a/chrome/browser/sync/engine/build_commit_command.h b/chrome/browser/sync/engine/build_commit_command.h
index f2f4516..5ac7477 100644
--- a/chrome/browser/sync/engine/build_commit_command.h
+++ b/chrome/browser/sync/engine/build_commit_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_BUILD_COMMIT_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_BUILD_COMMIT_COMMAND_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/syncer_command.h"
diff --git a/chrome/browser/sync/engine/change_reorder_buffer.cc b/chrome/browser/sync/engine/change_reorder_buffer.cc
index 2d68e1e..6af2399 100644
--- a/chrome/browser/sync/engine/change_reorder_buffer.cc
+++ b/chrome/browser/sync/engine/change_reorder_buffer.cc
@@ -113,6 +113,12 @@ class ChangeReorderBuffer::Traversal {
DISALLOW_COPY_AND_ASSIGN(Traversal);
};
+ChangeReorderBuffer::ChangeReorderBuffer() {
+}
+
+ChangeReorderBuffer::~ChangeReorderBuffer() {
+}
+
void ChangeReorderBuffer::GetAllChangesInTreeOrder(
const BaseTransaction* sync_trans,
vector<ChangeRecord>* changelist) {
@@ -133,6 +139,8 @@ void ChangeReorderBuffer::GetAllChangesInTreeOrder(
record.action = ChangeRecord::ACTION_DELETE;
if (specifics_.find(record.id) != specifics_.end())
record.specifics = specifics_[record.id];
+ if (extra_data_.find(record.id) != extra_data_.end())
+ record.extra = extra_data_[record.id];
changelist->push_back(record);
} else {
traversal.ExpandToInclude(trans, i->first);
@@ -164,6 +172,8 @@ void ChangeReorderBuffer::GetAllChangesInTreeOrder(
record.action = ChangeRecord::ACTION_UPDATE;
if (specifics_.find(record.id) != specifics_.end())
record.specifics = specifics_[record.id];
+ if (extra_data_.find(record.id) != extra_data_.end())
+ record.extra = extra_data_[record.id];
changelist->push_back(record);
}
diff --git a/chrome/browser/sync/engine/change_reorder_buffer.h b/chrome/browser/sync/engine/change_reorder_buffer.h
index 9da05e3..e2e091a 100644
--- a/chrome/browser/sync/engine/change_reorder_buffer.h
+++ b/chrome/browser/sync/engine/change_reorder_buffer.h
@@ -8,10 +8,12 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_CHANGE_REORDER_BUFFER_H_
#define CHROME_BROWSER_SYNC_ENGINE_CHANGE_REORDER_BUFFER_H_
+#pragma once
#include <map>
#include <vector>
+#include "base/linked_ptr.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/protocol/sync.pb.h"
@@ -37,8 +39,10 @@ namespace sync_api {
class ChangeReorderBuffer {
public:
typedef SyncManager::ChangeRecord ChangeRecord;
+ typedef SyncManager::ExtraChangeRecordData ExtraChangeRecordData;
- ChangeReorderBuffer() { }
+ ChangeReorderBuffer();
+ ~ChangeReorderBuffer();
// Insert an item, identified by the metahandle |id|, into the reorder
// buffer. This item will appear in the output list as an ACTION_ADD
@@ -64,6 +68,10 @@ class ChangeReorderBuffer {
OP_UPDATE_PROPERTIES_ONLY;
}
+ void SetExtraDataForId(int64 id, ExtraChangeRecordData* extra) {
+ extra_data_[id] = make_linked_ptr<ExtraChangeRecordData>(extra);
+ }
+
void SetSpecificsForId(int64 id, const sync_pb::EntitySpecifics& specifics) {
specifics_[id] = specifics;
}
@@ -94,6 +102,7 @@ class ChangeReorderBuffer {
};
typedef std::map<int64, Operation> OperationMap;
typedef std::map<int64, sync_pb::EntitySpecifics> SpecificsMap;
+ typedef std::map<int64, linked_ptr<ExtraChangeRecordData> > ExtraDataMap;
// Stores the items that have been pushed into the buffer, and the type of
// operation that was associated with them.
@@ -102,6 +111,9 @@ class ChangeReorderBuffer {
// Stores entity-specific ChangeRecord data per-ID.
SpecificsMap specifics_;
+ // Stores type-specific extra data per-ID.
+ ExtraDataMap extra_data_;
+
DISALLOW_COPY_AND_ASSIGN(ChangeReorderBuffer);
};
diff --git a/chrome/browser/sync/engine/cleanup_disabled_types_command.h b/chrome/browser/sync/engine/cleanup_disabled_types_command.h
index fb06724..26140b4 100644
--- a/chrome/browser/sync/engine/cleanup_disabled_types_command.h
+++ b/chrome/browser/sync/engine/cleanup_disabled_types_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_CLEANUP_DISABLED_TYPES_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_CLEANUP_DISABLED_TYPES_COMMAND_H_
+#pragma once
#include "chrome/browser/sync/engine/syncer_command.h"
diff --git a/chrome/browser/sync/engine/conflict_resolver.h b/chrome/browser/sync/engine/conflict_resolver.h
index 5157077..5880ae4 100644
--- a/chrome/browser/sync/engine/conflict_resolver.h
+++ b/chrome/browser/sync/engine/conflict_resolver.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_CONFLICT_RESOLVER_H_
#define CHROME_BROWSER_SYNC_ENGINE_CONFLICT_RESOLVER_H_
+#pragma once
#include <set>
#include <string>
diff --git a/chrome/browser/sync/engine/download_updates_command.cc b/chrome/browser/sync/engine/download_updates_command.cc
index 94ee7f1..da88447 100644
--- a/chrome/browser/sync/engine/download_updates_command.cc
+++ b/chrome/browser/sync/engine/download_updates_command.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/sessions/sync_session.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
-#include "chrome/browser/sync/util/sync_types.h"
using syncable::ScopedDirLookup;
@@ -95,7 +94,9 @@ void DownloadUpdatesCommand::ExecuteImpl(SyncSession* session) {
LOG(INFO) << "GetUpdates from ts " << get_updates->from_timestamp()
<< " returned " << update_response.get_updates().entries_size()
- << " updates.";
+ << " updates and indicated "
+ << update_response.get_updates().changes_remaining()
+ << " updates left on server.";
}
void DownloadUpdatesCommand::SetRequestedTypes(
diff --git a/chrome/browser/sync/engine/download_updates_command.h b/chrome/browser/sync/engine/download_updates_command.h
index 37c00d3..4b68531 100644
--- a/chrome/browser/sync/engine/download_updates_command.h
+++ b/chrome/browser/sync/engine/download_updates_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_DOWNLOAD_UPDATES_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_DOWNLOAD_UPDATES_COMMAND_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/model_safe_worker.h"
diff --git a/chrome/browser/sync/engine/get_commit_ids_command.cc b/chrome/browser/sync/engine/get_commit_ids_command.cc
index 5b6d228..f4e6334 100644
--- a/chrome/browser/sync/engine/get_commit_ids_command.cc
+++ b/chrome/browser/sync/engine/get_commit_ids_command.cc
@@ -10,7 +10,6 @@
#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/syncable/syncable.h"
-#include "chrome/browser/sync/util/sync_types.h"
using std::set;
using std::vector;
diff --git a/chrome/browser/sync/engine/get_commit_ids_command.h b/chrome/browser/sync/engine/get_commit_ids_command.h
index 40f8134..c730a64 100644
--- a/chrome/browser/sync/engine/get_commit_ids_command.h
+++ b/chrome/browser/sync/engine/get_commit_ids_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_GET_COMMIT_IDS_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_GET_COMMIT_IDS_COMMAND_H_
+#pragma once
#include <utility>
#include <vector>
@@ -12,7 +13,6 @@
#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/sessions/ordered_commit_set.h"
#include "chrome/browser/sync/sessions/sync_session.h"
-#include "chrome/browser/sync/util/sync_types.h"
using std::pair;
using std::vector;
diff --git a/chrome/browser/sync/engine/idle_query_linux.h b/chrome/browser/sync/engine/idle_query_linux.h
index ef7a075..ef91bdd 100644
--- a/chrome/browser/sync/engine/idle_query_linux.h
+++ b/chrome/browser/sync/engine/idle_query_linux.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_IDLE_QUERY_LINUX_H_
#define CHROME_BROWSER_SYNC_ENGINE_IDLE_QUERY_LINUX_H_
+#pragma once
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/sync/engine/mock_model_safe_workers.h b/chrome/browser/sync/engine/mock_model_safe_workers.h
index 13d66aa..3d0aa8a 100644
--- a/chrome/browser/sync/engine/mock_model_safe_workers.h
+++ b/chrome/browser/sync/engine/mock_model_safe_workers.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_MOCK_MODEL_SAFE_WORKERS_H_
#define CHROME_BROWSER_SYNC_ENGINE_MOCK_MODEL_SAFE_WORKERS_H_
+#pragma once
#include "chrome/browser/sync/engine/model_safe_worker.h"
diff --git a/chrome/browser/sync/engine/model_changing_syncer_command.h b/chrome/browser/sync/engine/model_changing_syncer_command.h
index c08ade2..ae59272 100644
--- a/chrome/browser/sync/engine/model_changing_syncer_command.h
+++ b/chrome/browser/sync/engine/model_changing_syncer_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_MODEL_CHANGING_SYNCER_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_MODEL_CHANGING_SYNCER_COMMAND_H_
+#pragma once
#include "chrome/browser/sync/engine/syncer_command.h"
diff --git a/chrome/browser/sync/engine/model_safe_worker.h b/chrome/browser/sync/engine/model_safe_worker.h
index 7b84fd3..4164ff5 100644
--- a/chrome/browser/sync/engine/model_safe_worker.h
+++ b/chrome/browser/sync/engine/model_safe_worker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_MODEL_SAFE_WORKER_H_
#define CHROME_BROWSER_SYNC_ENGINE_MODEL_SAFE_WORKER_H_
+#pragma once
#include <map>
#include <string>
@@ -12,7 +13,6 @@
#include "base/callback.h"
#include "base/ref_counted.h"
#include "chrome/browser/sync/syncable/model_type.h"
-#include "chrome/browser/sync/util/sync_types.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/engine/net/server_connection_manager.cc b/chrome/browser/sync/engine/net/server_connection_manager.cc
index 4953836..c1801c8 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.cc
+++ b/chrome/browser/sync/engine/net/server_connection_manager.cc
@@ -135,11 +135,9 @@ ServerConnectionManager::ServerConnectionManager(
const string& server,
int port,
bool use_ssl,
- const string& user_agent,
- const string& client_id)
+ const string& user_agent)
: sync_server_(server),
sync_server_port_(port),
- client_id_(client_id),
user_agent_(user_agent),
use_ssl_(use_ssl),
proto_sync_path_(kSyncServerSyncPath),
@@ -163,7 +161,6 @@ void ServerConnectionManager::NotifyStatusChanged() {
channel_->NotifyListeners(event);
}
-// Uses currently set auth token. Set by AuthWatcher.
bool ServerConnectionManager::PostBufferWithCachedAuth(
const PostBufferParams* params, ScopedServerStatusWatcher* watcher) {
string path =
@@ -171,14 +168,6 @@ bool ServerConnectionManager::PostBufferWithCachedAuth(
return PostBufferToPath(params, path, auth_token(), watcher);
}
-bool ServerConnectionManager::PostBufferWithAuth(const PostBufferParams* params,
- const string& auth_token, ScopedServerStatusWatcher* watcher) {
- string path = MakeSyncServerPath(proto_sync_path(),
- MakeSyncQueryString(client_id_));
-
- return PostBufferToPath(params, path, auth_token, watcher);
-}
-
bool ServerConnectionManager::PostBufferToPath(const PostBufferParams* params,
const string& path, const string& auth_token,
ScopedServerStatusWatcher* watcher) {
@@ -356,12 +345,11 @@ bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
return true;
}
-} // namespace browser_sync
-
-std::ostream& operator << (std::ostream& s,
- const struct browser_sync::HttpResponse& hr) {
+std::ostream& operator << (std::ostream& s, const struct HttpResponse& hr) {
s << " Response Code (bogus on error): " << hr.response_code;
s << " Content-Length (bogus on error): " << hr.content_length;
s << " Server Status: " << hr.server_status;
return s;
}
+
+} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/net/server_connection_manager.h b/chrome/browser/sync/engine/net/server_connection_manager.h
index f864702..0363993 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.h
+++ b/chrome/browser/sync/engine/net/server_connection_manager.h
@@ -1,21 +1,18 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
#define CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
+#pragma once
#include <iosfwd>
#include <string>
-#include <vector>
#include "base/atomicops.h"
#include "base/lock.h"
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "chrome/browser/sync/syncable/syncable_id.h"
-#include "chrome/browser/sync/util/sync_types.h"
#include "chrome/common/deprecated/event_sys.h"
#include "chrome/common/deprecated/event_sys-inl.h"
#include "chrome/common/net/http_return.h"
@@ -215,8 +212,7 @@ class ServerConnectionManager {
ServerConnectionManager(const std::string& server,
int port,
bool use_ssl,
- const std::string& user_agent,
- const std::string& client_id);
+ const std::string& user_agent);
virtual ~ServerConnectionManager();
@@ -227,14 +223,6 @@ class ServerConnectionManager {
virtual bool PostBufferWithCachedAuth(const PostBufferParams* params,
ScopedServerStatusWatcher* watcher);
- // POSTS buffer_in and reads a response into buffer_out. Add a specific auth
- // token to http headers.
- //
- // Returns true if executed successfully.
- virtual bool PostBufferWithAuth(const PostBufferParams* params,
- const std::string& auth_token,
- ScopedServerStatusWatcher* watcher);
-
// Checks the time on the server. Returns false if the request failed. |time|
// is an out parameter that stores the value returned from the server.
virtual bool CheckTime(int32* out_time);
@@ -291,6 +279,11 @@ class ServerConnectionManager {
return NULL; // For testing.
};
+ void set_client_id(const std::string& client_id) {
+ DCHECK(client_id_.empty());
+ client_id_.assign(client_id);
+ }
+
void set_auth_token(const std::string& auth_token) {
// TODO(chron): Consider adding a message loop check here.
AutoLock lock(auth_token_mutex_);
@@ -335,7 +328,7 @@ class ServerConnectionManager {
int sync_server_port_;
// The unique id of the user's client.
- const std::string client_id_;
+ std::string client_id_;
// The user-agent string for HTTP.
std::string user_agent_;
@@ -383,9 +376,8 @@ bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
syncable::DirectoryManager* manager,
const std::string& share);
-} // namespace browser_sync
+std::ostream& operator<<(std::ostream& s, const struct HttpResponse& hr);
-std::ostream& operator<<(std::ostream& s,
- const struct browser_sync::HttpResponse& hr);
+} // namespace browser_sync
#endif // CHROME_BROWSER_SYNC_ENGINE_NET_SERVER_CONNECTION_MANAGER_H_
diff --git a/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h b/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h
index f94799d..4108f9a 100644
--- a/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h
+++ b/chrome/browser/sync/engine/net/syncapi_server_connection_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_NET_SYNCAPI_SERVER_CONNECTION_MANAGER_H_
#define CHROME_BROWSER_SYNC_ENGINE_NET_SYNCAPI_SERVER_CONNECTION_MANAGER_H_
+#pragma once
#include <string>
@@ -50,10 +51,8 @@ class SyncAPIServerConnectionManager
int port,
bool use_ssl,
const std::string& client_version,
- const std::string& client_id,
HttpPostProviderFactory* factory)
- : ServerConnectionManager(server, port, use_ssl, client_version,
- client_id),
+ : ServerConnectionManager(server, port, use_ssl, client_version),
post_provider_factory_(factory) {
DCHECK(post_provider_factory_.get());
}
diff --git a/chrome/browser/sync/engine/net/url_translator.cc b/chrome/browser/sync/engine/net/url_translator.cc
index 6dc2754..4b91e54 100644
--- a/chrome/browser/sync/engine/net/url_translator.cc
+++ b/chrome/browser/sync/engine/net/url_translator.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.
//
@@ -8,7 +8,6 @@
#include "chrome/browser/sync/engine/net/url_translator.h"
#include "base/basictypes.h"
-#include "base/logging.h"
#include "base/port.h"
#include "net/base/escape.h"
diff --git a/chrome/browser/sync/engine/net/url_translator.h b/chrome/browser/sync/engine/net/url_translator.h
index 717e15b..c460c08 100644
--- a/chrome/browser/sync/engine/net/url_translator.h
+++ b/chrome/browser/sync/engine/net/url_translator.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_NET_URL_TRANSLATOR_H_
#define CHROME_BROWSER_SYNC_ENGINE_NET_URL_TRANSLATOR_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/engine/post_commit_message_command.cc b/chrome/browser/sync/engine/post_commit_message_command.cc
index 92a4cc4..7eff0a4 100644
--- a/chrome/browser/sync/engine/post_commit_message_command.cc
+++ b/chrome/browser/sync/engine/post_commit_message_command.cc
@@ -10,7 +10,6 @@
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/sessions/sync_session.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
-#include "chrome/browser/sync/util/sync_types.h"
using std::vector;
diff --git a/chrome/browser/sync/engine/post_commit_message_command.h b/chrome/browser/sync/engine/post_commit_message_command.h
index 4f49894..107c6e2 100644
--- a/chrome/browser/sync/engine/post_commit_message_command.h
+++ b/chrome/browser/sync/engine/post_commit_message_command.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_POST_COMMIT_MESSAGE_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_POST_COMMIT_MESSAGE_COMMAND_H_
+#pragma once
#include "chrome/browser/sync/engine/syncer_command.h"
-#include "chrome/browser/sync/util/sync_types.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/engine/process_commit_response_command.h b/chrome/browser/sync/engine/process_commit_response_command.h
index 96253d8..bbc85bf 100644
--- a/chrome/browser/sync/engine/process_commit_response_command.h
+++ b/chrome/browser/sync/engine/process_commit_response_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_PROCESS_COMMIT_RESPONSE_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_PROCESS_COMMIT_RESPONSE_COMMAND_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/sync/engine/process_updates_command.cc b/chrome/browser/sync/engine/process_updates_command.cc
index 6e42b1b..d55582e 100644
--- a/chrome/browser/sync/engine/process_updates_command.cc
+++ b/chrome/browser/sync/engine/process_updates_command.cc
@@ -124,29 +124,38 @@ ServerUpdateProcessingResult ProcessUpdatesCommand::ProcessUpdate(
// If we're repurposing an existing local entry with a new server ID,
// change the ID now, after we're sure that the update can succeed.
if (local_id != server_id) {
+ DCHECK(!update.deleted());
SyncerUtil::ChangeEntryIDAndUpdateChildren(&trans, &target_entry,
server_id);
// When IDs change, versions become irrelevant. Forcing BASE_VERSION
- // to zero would ensure that this update gets applied, but historically,
- // that's an illegal state unless the item is using the client tag.
- // Alternatively, we can force BASE_VERSION to entry.version(), but
- // this has the effect of suppressing update application.
- // TODO(nick): Make the treatment of these two cases consistent.
- int64 new_version = target_entry.Get(UNIQUE_CLIENT_TAG).empty() ?
- update.version() : 0;
- target_entry.Put(BASE_VERSION, new_version);
+ // to zero would ensure that this update gets applied, but would indicate
+ // creation or undeletion if it were committed that way. Instead, prefer
+ // forcing BASE_VERSION to entry.version() while also forcing
+ // IS_UNAPPLIED_UPDATE to true. If the item is UNSYNCED, it's committable
+ // from the new state; it may commit before the conflict resolver gets
+ // a crack at it.
+ if (target_entry.Get(IS_UNSYNCED) || target_entry.Get(BASE_VERSION) > 0) {
+ // If either of these conditions are met, then we can expect valid client
+ // fields for this entry. When BASE_VERSION is positive, consistency is
+ // enforced on the client fields at update-application time. Otherwise,
+ // we leave the BASE_VERSION field alone; it'll get updated the first time
+ // we successfully apply this update.
+ target_entry.Put(BASE_VERSION, update.version());
+ }
+ // Force application of this update, no matter what.
+ target_entry.Put(IS_UNAPPLIED_UPDATE, true);
}
SyncerUtil::UpdateServerFieldsFromUpdate(&target_entry, update, name);
if (target_entry.Get(SERVER_VERSION) == target_entry.Get(BASE_VERSION) &&
- !target_entry.Get(IS_UNSYNCED)) {
- // It's largely OK if data doesn't match exactly since a future update
- // will just clobber the data. Conflict resolution will overwrite and
- // take one side as the winner and does not try to merge, so strict
- // equality isn't necessary.
- LOG_IF(ERROR, !SyncerUtil::ServerAndLocalEntriesMatch(&target_entry))
- << target_entry;
+ !target_entry.Get(IS_UNSYNCED) &&
+ !target_entry.Get(IS_UNAPPLIED_UPDATE)) {
+ // If these don't match, it means that we have a different view of the
+ // truth from other clients. That's a sync bug, though we may be able
+ // to recover the next time this item commits.
+ LOG_IF(ERROR, !SyncerUtil::ServerAndLocalEntriesMatch(&target_entry))
+ << target_entry;
}
return SUCCESS_PROCESSED;
}
diff --git a/chrome/browser/sync/engine/process_updates_command.h b/chrome/browser/sync/engine/process_updates_command.h
index 2bcd668..f9ff968 100644
--- a/chrome/browser/sync/engine/process_updates_command.h
+++ b/chrome/browser/sync/engine/process_updates_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_PROCESS_UPDATES_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_PROCESS_UPDATES_COMMAND_H_
+#pragma once
#include "chrome/browser/sync/engine/model_changing_syncer_command.h"
#include "chrome/browser/sync/engine/syncer_types.h"
diff --git a/chrome/browser/sync/engine/resolve_conflicts_command.h b/chrome/browser/sync/engine/resolve_conflicts_command.h
index 3ac3207..7bdb734 100644
--- a/chrome/browser/sync/engine/resolve_conflicts_command.h
+++ b/chrome/browser/sync/engine/resolve_conflicts_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_RESOLVE_CONFLICTS_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_RESOLVE_CONFLICTS_COMMAND_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/model_changing_syncer_command.h"
diff --git a/chrome/browser/sync/engine/store_timestamps_command.h b/chrome/browser/sync/engine/store_timestamps_command.h
index 7d0e47f..ca8751a 100644
--- a/chrome/browser/sync/engine/store_timestamps_command.h
+++ b/chrome/browser/sync/engine/store_timestamps_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_STORE_TIMESTAMPS_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_STORE_TIMESTAMPS_COMMAND_H_
+#pragma once
#include "chrome/browser/sync/engine/syncer_command.h"
#include "chrome/browser/sync/engine/syncer_types.h"
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index d9c5a9f..4728534 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -6,6 +6,7 @@
#include "build/build_config.h"
+#include <bitset>
#include <iomanip>
#include <list>
#include <string>
@@ -25,7 +26,6 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/sync/sync_constants.h"
#include "chrome/browser/sync/engine/all_status.h"
-#include "chrome/browser/sync/engine/auth_watcher.h"
#include "chrome/browser/sync/engine/change_reorder_buffer.h"
#include "chrome/browser/sync/engine/model_safe_worker.h"
#include "chrome/browser/sync/engine/net/server_connection_manager.h"
@@ -33,12 +33,14 @@
#include "chrome/browser/sync/engine/syncer.h"
#include "chrome/browser/sync/engine/syncer_thread.h"
#include "chrome/browser/sync/notifier/server_notifier_thread.h"
+#include "chrome/browser/sync/protocol/app_specifics.pb.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#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"
#include "chrome/browser/sync/protocol/sync.pb.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
@@ -47,7 +49,6 @@
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/util/crypto_helpers.h"
-#include "chrome/browser/sync/util/user_settings.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/deprecated/event_sys.h"
#include "chrome/common/net/gaia/gaia_authenticator.h"
@@ -59,17 +60,15 @@
using browser_sync::AllStatus;
using browser_sync::AllStatusEvent;
-using browser_sync::AuthWatcher;
-using browser_sync::AuthWatcherEvent;
using browser_sync::Cryptographer;
using browser_sync::KeyParams;
using browser_sync::ModelSafeRoutingInfo;
using browser_sync::ModelSafeWorker;
using browser_sync::ModelSafeWorkerRegistrar;
+using browser_sync::ServerConnectionEvent;
using browser_sync::Syncer;
using browser_sync::SyncerEvent;
using browser_sync::SyncerThread;
-using browser_sync::UserSettings;
using browser_sync::kNigoriTag;
using browser_sync::sessions::SyncSessionContext;
using notifier::TalkMediator;
@@ -175,17 +174,27 @@ std::string BaseNode::GenerateSyncableHash(
return encode_output;
}
+sync_pb::PasswordSpecificsData* DecryptPasswordSpecifics(
+ const sync_pb::EntitySpecifics& specifics, Cryptographer* crypto) {
+ if (!specifics.HasExtension(sync_pb::password))
+ return NULL;
+ const sync_pb::EncryptedData& encrypted =
+ specifics.GetExtension(sync_pb::password).encrypted();
+ scoped_ptr<sync_pb::PasswordSpecificsData> data(
+ new sync_pb::PasswordSpecificsData);
+ if (!crypto->Decrypt(encrypted, data.get()))
+ return NULL;
+ return data.release();
+}
+
bool BaseNode::DecryptIfNecessary(Entry* entry) {
if (GetIsFolder()) return true; // Ignore the top-level password folder.
const sync_pb::EntitySpecifics& specifics =
entry->Get(syncable::SPECIFICS);
if (specifics.HasExtension(sync_pb::password)) {
- const sync_pb::EncryptedData& encrypted =
- specifics.GetExtension(sync_pb::password).encrypted();
- scoped_ptr<sync_pb::PasswordSpecificsData> data(
- new sync_pb::PasswordSpecificsData);
- if (!GetTransaction()->GetCryptographer()->Decrypt(encrypted,
- data.get()))
+ scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
+ specifics, GetTransaction()->GetCryptographer()));
+ if (!data.get())
return false;
password_data_.swap(data);
}
@@ -252,6 +261,11 @@ int64 BaseNode::GetExternalId() const {
return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
}
+const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
+ DCHECK(GetModelType() == syncable::APPS);
+ return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::app);
+}
+
const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
DCHECK(GetModelType() == syncable::AUTOFILL);
return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::autofill);
@@ -293,6 +307,11 @@ const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::extension);
}
+const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
+ DCHECK(GetModelType() == syncable::SESSIONS);
+ return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::session);
+}
+
syncable::ModelType BaseNode::GetModelType() const {
return GetEntry()->GetModelType();
}
@@ -326,6 +345,12 @@ void WriteNode::SetURL(const GURL& url) {
SetBookmarkSpecifics(new_value);
}
+void WriteNode::SetAppSpecifics(
+ const sync_pb::AppSpecifics& new_value) {
+ DCHECK(GetModelType() == syncable::APPS);
+ PutAppSpecificsAndMarkForSyncing(new_value);
+}
+
void WriteNode::SetAutofillSpecifics(
const sync_pb::AutofillSpecifics& new_value) {
DCHECK(GetModelType() == syncable::AUTOFILL);
@@ -391,6 +416,14 @@ void WriteNode::SetThemeSpecifics(
PutThemeSpecificsAndMarkForSyncing(new_value);
}
+
+void WriteNode::SetSessionSpecifics(
+ const sync_pb::SessionSpecifics& new_value) {
+ DCHECK(GetModelType() == syncable::SESSIONS);
+ PutSessionSpecificsAndMarkForSyncing(new_value);
+}
+
+
void WriteNode::PutPasswordSpecificsAndMarkForSyncing(
const sync_pb::PasswordSpecifics& new_value) {
sync_pb::EntitySpecifics entity_specifics;
@@ -417,6 +450,13 @@ void WriteNode::SetExtensionSpecifics(
PutExtensionSpecificsAndMarkForSyncing(new_value);
}
+void WriteNode::PutAppSpecificsAndMarkForSyncing(
+ const sync_pb::AppSpecifics& new_value) {
+ sync_pb::EntitySpecifics entity_specifics;
+ entity_specifics.MutableExtension(sync_pb::app)->CopyFrom(new_value);
+ PutSpecificsAndMarkForSyncing(entity_specifics);
+}
+
void WriteNode::PutThemeSpecificsAndMarkForSyncing(
const sync_pb::ThemeSpecifics& new_value) {
sync_pb::EntitySpecifics entity_specifics;
@@ -438,6 +478,15 @@ void WriteNode::PutExtensionSpecificsAndMarkForSyncing(
PutSpecificsAndMarkForSyncing(entity_specifics);
}
+
+void WriteNode::PutSessionSpecificsAndMarkForSyncing(
+ const sync_pb::SessionSpecifics& new_value) {
+ sync_pb::EntitySpecifics entity_specifics;
+ entity_specifics.MutableExtension(sync_pb::session)->CopyFrom(new_value);
+ PutSpecificsAndMarkForSyncing(entity_specifics);
+}
+
+
void WriteNode::PutSpecificsAndMarkForSyncing(
const sync_pb::EntitySpecifics& specifics) {
// Skip redundant changes.
@@ -847,7 +896,7 @@ class BridgedGaiaAuthenticator : public gaia::GaiaAuthenticator {
}
virtual int GetBackoffDelaySeconds(int current_backoff_delay) {
- return AllStatus::GetRecommendedDelaySeconds(current_backoff_delay);
+ return SyncerThread::GetRecommendedDelaySeconds(current_backoff_delay);
}
private:
const std::string gaia_source_;
@@ -868,13 +917,11 @@ class SyncManager::SyncInternal
explicit SyncInternal(SyncManager* sync_manager)
: core_message_loop_(NULL),
observer_(NULL),
- auth_problem_(AuthError::NONE),
sync_manager_(sync_manager),
registrar_(NULL),
notification_pending_(false),
initialized_(false),
- use_chrome_async_socket_(false),
- notification_method_(browser_sync::kDefaultNotificationMethod) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
}
@@ -886,38 +933,23 @@ class SyncManager::SyncInternal
bool Init(const FilePath& database_location,
const std::string& sync_server_and_path,
int port,
- const char* gaia_service_id,
- const char* gaia_source,
bool use_ssl,
HttpPostProviderFactory* post_factory,
- HttpPostProviderFactory* auth_post_factory,
ModelSafeWorkerRegistrar* model_safe_worker_registrar,
- bool attempt_last_user_authentication,
- bool invalidate_last_user_auth_token,
- bool invalidate_xmpp_auth_token,
const char* user_agent,
- const std::string& lsid,
- const bool use_chrome_async_socket,
- browser_sync::NotificationMethod notification_method);
-
- // Tell sync engine to submit credentials to GAIA for verification.
- // Successful GAIA authentication will kick off the following chain of events:
- // 1. Cause sync engine to open the syncer database.
- // 2. Trigger the AuthWatcher to create a Syncer for the directory and call
- // SyncerThread::SyncDirectory; the SyncerThread will block until (4).
- // 3. Tell the ServerConnectionManager to pass the newly received GAIA auth
- // token to a sync server to obtain a sync token.
- // 4. On receipt of this token, the ServerConnectionManager broadcasts
- // a server-reachable event, which will unblock the SyncerThread.
- // 5. When StartSyncing is called, the Syncer will begin the sync process, by
- // downloading from or uploading to the server.
- //
- // If authentication fails, an event will be broadcast all the way up to
- // the SyncManager::Observer. It may, in turn, decide to try again with new
- // credentials. Calling this method again is the appropriate course of action
- // to "retry".
- void Authenticate(const std::string& username, const std::string& password,
- const std::string& captcha);
+ const SyncCredentials& credentials,
+ const notifier::NotifierOptions& notifier_options,
+ const std::string& restored_key_for_bootstrapping,
+ bool setup_for_test_mode);
+
+ // Sign into sync with given credentials.
+ // We do not verify the tokens given. After this call, the tokens are set
+ // and the sync DB is open. True if successful, false if something
+ // went wrong.
+ bool SignIn(const SyncCredentials& credentials);
+
+ // Update tokens that we're using in Sync. Email must stay the same.
+ void UpdateCredentials(const SyncCredentials& credentials);
// Tell the sync engine to start the syncing process.
void StartSyncing();
@@ -932,6 +964,8 @@ class SyncManager::SyncInternal
// builds the list of sync-engine initiated changes that will be forwarded to
// the SyncManager's Observers.
virtual void HandleChannelEvent(const syncable::DirectoryChangeEvent& event);
+ void HandleTransactionCompleteChangeEvent(
+ const syncable::DirectoryChangeEvent& event);
void HandleTransactionEndingChangeEvent(
const syncable::DirectoryChangeEvent& event);
void HandleCalculateChangesChangeEventFromSyncApi(
@@ -942,20 +976,17 @@ class SyncManager::SyncInternal
// This listener is called by the syncer channel for all syncer events.
virtual void HandleChannelEvent(const SyncerEvent& event);
- // We have a direct hookup to the authwatcher to be notified for auth failures
- // on startup, to serve our UI needs.
- void HandleAuthWatcherEvent(const AuthWatcherEvent& event);
+ // Listens for notifications from the ServerConnectionManager
+ void HandleServerConnectionEvent(const ServerConnectionEvent& event);
- // Listen here for directory opened events.
- void HandleDirectoryManagerEvent(
- const syncable::DirectoryManagerEvent& event);
+ // Open the directory named with username_for_share
+ bool OpenDirectory();
// Login to the talk mediator with the given credentials.
void TalkMediatorLogin(
const std::string& email, const std::string& token);
// TalkMediator::Delegate implementation.
-
virtual void OnNotificationStateChange(
bool notifications_enabled);
@@ -971,14 +1002,13 @@ class SyncManager::SyncInternal
}
SyncerThread* syncer_thread() { return syncer_thread_.get(); }
TalkMediator* talk_mediator() { return talk_mediator_.get(); }
- AuthWatcher* auth_watcher() { return auth_watcher_.get(); }
void set_observer(SyncManager::Observer* observer) { observer_ = observer; }
UserShare* GetUserShare() { return &share_; }
// Return the currently active (validated) username for use with syncable
// types.
const std::string& username_for_share() const {
- return share_.authenticated_name;
+ return share_.name;
}
// Note about SyncManager::Status implementation: Status is a trimmed
@@ -992,9 +1022,6 @@ class SyncManager::SyncInternal
Status ComputeAggregatedStatus();
Status::Summary ComputeAggregatedStatusSummary();
- // See SyncManager::SetupForTestMode for information.
- void SetupForTestMode(const std::wstring& test_username);
-
// See SyncManager::Shutdown for information.
void Shutdown();
@@ -1008,6 +1035,7 @@ class SyncManager::SyncInternal
void SetExtraChangeRecordData(int64 id,
syncable::ModelType type,
ChangeReorderBuffer* buffer,
+ Cryptographer* cryptographer,
const syncable::EntryKernel& original,
bool existed_before,
bool exists_now);
@@ -1015,22 +1043,6 @@ class SyncManager::SyncInternal
// Called only by our NetworkChangeNotifier.
virtual void OnIPAddressChanged();
- private:
- // Try to authenticate using a LSID cookie.
- void AuthenticateWithLsid(const std::string& lsid);
-
- // Try to authenticate using persisted credentials from a previous successful
- // authentication. If no such credentials exist, calls OnAuthError on the
- // client to collect credentials. Otherwise, there exist local credentials
- // that were once used for a successful auth, so we'll try to re-use these.
- // Failure of that attempt will be communicated as normal using OnAuthError.
- // Since this entry point will bypass normal GAIA authentication and try to
- // authenticate directly with the sync service using a cached token,
- // authentication failure will generally occur due to expired credentials, or
- // possibly because of a password change.
- bool AuthenticateForUser(const std::string& username,
- const std::string& auth_token);
-
bool InitialSyncEndedForAllEnabledTypes() {
syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
if (!lookup.good()) {
@@ -1048,6 +1060,7 @@ class SyncManager::SyncInternal
return true;
}
+ private:
// Helper to call OnAuthError when no authentication credentials are
// available.
void RaiseAuthNeededEvent();
@@ -1113,15 +1126,19 @@ class SyncManager::SyncInternal
return true;
}
+ void CheckServerReachable() {
+ if (connection_manager()) {
+ connection_manager()->CheckServerReachable();
+ } else {
+ NOTREACHED() << "Should be valid connection manager!";
+ }
+ }
+
// We couple the DirectoryManager and username together in a UserShare member
// so we can return a handle to share_ to clients of the API for use when
// constructing any transaction type.
UserShare share_;
- // A wrapper around a sqlite store used for caching authentication data,
- // last user information, current sync-related URLs, and more.
- scoped_ptr<UserSettings> user_settings_;
-
MessageLoop* core_message_loop_;
// Observer registered via SetObserver/RemoveObserver.
@@ -1142,38 +1159,31 @@ class SyncManager::SyncInternal
// sync components.
AllStatus allstatus_;
- // AuthWatcher kicks off the authentication process and follows it through
- // phase 1 (GAIA) to phase 2 (sync engine). As part of this work it determines
- // the initial connectivity and causes the server connection event to be
- // broadcast, which signals the syncer thread to start syncing.
- // It has a heavy duty constructor requiring boilerplate so we heap allocate.
- scoped_refptr<AuthWatcher> auth_watcher_;
-
// Each element of this array is a store of change records produced by
// HandleChangeEvent during the CALCULATE_CHANGES step. The changes are
// segregated by model type, and are stored here to be processed and
// forwarded to the observer slightly later, at the TRANSACTION_ENDING
- // step by HandleTransactionEndingChangeEvent.
+ // step by HandleTransactionEndingChangeEvent. The list is cleared in the
+ // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
+ // Bit vector keeping track of which models need to have their
+ // OnChangesComplete observer set.
+ //
+ // Set by HandleTransactionEndingChangeEvent, cleared in
+ // HandleTransactionCompleteChangeEvent.
+ std::bitset<syncable::MODEL_TYPE_COUNT> model_has_change_;
+
// The event listener hookup that is registered for HandleChangeEvent.
scoped_ptr<browser_sync::ChannelHookup<syncable::DirectoryChangeEvent> >
dir_change_hookup_;
+ // Event listener hookup for the ServerConnectionManager.
+ scoped_ptr<EventListenerHookup> connection_manager_hookup_;
+
// The event listener hookup registered for HandleSyncerEvent.
scoped_ptr<browser_sync::ChannelHookup<SyncerEvent> > syncer_event_;
- // The event listener hookup registered for HandleAuthWatcherEvent.
- scoped_ptr<EventListenerHookup> authwatcher_hookup_;
-
- // The event listener hookup registered for the DirectoryManager (OPENED).
- scoped_ptr<EventListenerHookup> directory_manager_hookup_;
-
- // Our cache of a recent authentication problem. If no authentication problem
- // occurred, or if the last problem encountered has been cleared (by a
- // subsequent AuthWatcherEvent), this is set to NONE.
- AuthError::State auth_problem_;
-
// The sync dir_manager to which we belong.
SyncManager* const sync_manager_;
@@ -1193,8 +1203,13 @@ class SyncManager::SyncInternal
bool initialized_;
mutable Lock initialized_mutex_;
- bool use_chrome_async_socket_;
- browser_sync::NotificationMethod notification_method_;
+ notifier::NotifierOptions notifier_options_;
+
+ // True if the SyncManager should be running in test mode (no syncer thread
+ // actually communicating with the server).
+ bool setup_for_test_mode_;
+
+ ScopedRunnableMethodFactory<SyncManager::SyncInternal> method_factory_;
};
const int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
const int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
@@ -1206,44 +1221,37 @@ SyncManager::SyncManager() {
bool SyncManager::Init(const FilePath& database_location,
const char* sync_server_and_path,
int sync_server_port,
- const char* gaia_service_id,
- const char* gaia_source,
bool use_ssl,
HttpPostProviderFactory* post_factory,
- HttpPostProviderFactory* auth_post_factory,
ModelSafeWorkerRegistrar* registrar,
- bool attempt_last_user_authentication,
- bool invalidate_last_user_auth_token,
- bool invalidate_xmpp_auth_token,
const char* user_agent,
- const char* lsid,
- bool use_chrome_async_socket,
- browser_sync::NotificationMethod notification_method) {
+ const SyncCredentials& credentials,
+ const notifier::NotifierOptions& notifier_options,
+ const std::string& restored_key_for_bootstrapping,
+ bool setup_for_test_mode) {
DCHECK(post_factory);
LOG(INFO) << "SyncManager starting Init...";
string server_string(sync_server_and_path);
return data_->Init(database_location,
server_string,
sync_server_port,
- gaia_service_id,
- gaia_source,
use_ssl,
post_factory,
- auth_post_factory,
registrar,
- attempt_last_user_authentication,
- invalidate_last_user_auth_token,
- invalidate_xmpp_auth_token,
user_agent,
- lsid,
- use_chrome_async_socket,
- notification_method);
+ credentials,
+ notifier_options,
+ restored_key_for_bootstrapping,
+ setup_for_test_mode);
}
-void SyncManager::Authenticate(const char* username, const char* password,
- const char* captcha) {
- data_->Authenticate(std::string(username), std::string(password),
- std::string(captcha));
+void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
+ data_->UpdateCredentials(credentials);
+}
+
+
+bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
+ return data_->InitialSyncEndedForAllEnabledTypes();
}
void SyncManager::StartSyncing() {
@@ -1255,15 +1263,25 @@ void SyncManager::SetPassphrase(const std::string& passphrase) {
}
bool SyncManager::RequestPause() {
- return data_->syncer_thread()->RequestPause();
+ if (data_->syncer_thread())
+ return data_->syncer_thread()->RequestPause();
+ return false;
}
bool SyncManager::RequestResume() {
- return data_->syncer_thread()->RequestResume();
+ if (data_->syncer_thread())
+ return data_->syncer_thread()->RequestResume();
+ return false;
}
void SyncManager::RequestNudge() {
- data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kLocal);
+ if (data_->syncer_thread())
+ data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kLocal);
+}
+
+void SyncManager::RequestClearServerData() {
+ if (data_->syncer_thread())
+ data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kClearPrivateData);
}
const std::string& SyncManager::GetAuthenticatedUsername() {
@@ -1275,69 +1293,52 @@ bool SyncManager::SyncInternal::Init(
const FilePath& database_location,
const std::string& sync_server_and_path,
int port,
- const char* gaia_service_id,
- const char* gaia_source,
bool use_ssl,
HttpPostProviderFactory* post_factory,
- HttpPostProviderFactory* auth_post_factory,
ModelSafeWorkerRegistrar* model_safe_worker_registrar,
- bool attempt_last_user_authentication,
- bool invalidate_last_user_auth_token,
- bool invalidate_xmpp_auth_token,
const char* user_agent,
- const std::string& lsid,
- bool use_chrome_async_socket,
- browser_sync::NotificationMethod notification_method) {
+ const SyncCredentials& credentials,
+ const notifier::NotifierOptions& notifier_options,
+ const std::string& restored_key_for_bootstrapping,
+ bool setup_for_test_mode) {
LOG(INFO) << "Starting SyncInternal initialization.";
core_message_loop_ = MessageLoop::current();
DCHECK(core_message_loop_);
- notification_method_ = notification_method;
- // Set up UserSettings, creating the db if necessary. We need this to
- // instantiate a URLFactory to give to the Syncer.
- FilePath settings_db_file =
- database_location.Append(FilePath(kBookmarkSyncUserSettingsDatabase));
- user_settings_.reset(new UserSettings());
- if (!user_settings_->Init(settings_db_file))
- return false;
-
+ notifier_options_ = notifier_options;
registrar_ = model_safe_worker_registrar;
-
- LOG(INFO) << "Initialized sync user settings. Starting DirectoryManager.";
+ setup_for_test_mode_ = setup_for_test_mode;
share_.dir_manager.reset(new DirectoryManager(database_location));
- directory_manager_hookup_.reset(NewEventListenerHookup(
- share_.dir_manager->channel(), this,
- &SyncInternal::HandleDirectoryManagerEvent));
+ share_.dir_manager->cryptographer()->Bootstrap(
+ restored_key_for_bootstrapping);
- string client_id = user_settings_->GetClientId();
connection_manager_.reset(new SyncAPIServerConnectionManager(
- sync_server_and_path, port, use_ssl, user_agent, client_id,
- post_factory));
+ sync_server_and_path, port, use_ssl, user_agent, post_factory));
- // Watch various objects for aggregated status.
- allstatus_.WatchConnectionManager(connection_manager());
+ connection_manager_hookup_.reset(
+ NewEventListenerHookup(connection_manager()->channel(), this,
+ &SyncManager::SyncInternal::HandleServerConnectionEvent));
net::NetworkChangeNotifier::AddObserver(this);
// TODO(akalin): CheckServerReachable() can block, which may cause jank if we
// try to shut down sync. Fix this.
- connection_manager()->CheckServerReachable();
+ core_message_loop_->PostTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(&SyncInternal::CheckServerReachable));
// NOTIFICATION_SERVER uses a substantially different notification method, so
// it has its own MediatorThread implementation. Everything else just uses
// MediatorThreadImpl.
notifier::MediatorThread* mediator_thread =
- (notification_method == browser_sync::NOTIFICATION_SERVER) ?
- new sync_notifier::ServerNotifierThread(use_chrome_async_socket) :
- new notifier::MediatorThreadImpl(use_chrome_async_socket);
- const bool kInitializeSsl = true;
- const bool kConnectImmediately = false;
- talk_mediator_.reset(new TalkMediatorImpl(mediator_thread, kInitializeSsl,
- kConnectImmediately, invalidate_xmpp_auth_token));
- if (notification_method != browser_sync::NOTIFICATION_LEGACY &&
- notification_method != browser_sync::NOTIFICATION_SERVER) {
- if (notification_method == browser_sync::NOTIFICATION_TRANSITIONAL) {
+ (notifier_options_.notification_method == notifier::NOTIFICATION_SERVER) ?
+ new sync_notifier::ServerNotifierThread(notifier_options) :
+ new notifier::MediatorThreadImpl(notifier_options);
+ talk_mediator_.reset(new TalkMediatorImpl(mediator_thread, false));
+ if (notifier_options_.notification_method != notifier::NOTIFICATION_LEGACY &&
+ notifier_options_.notification_method != notifier::NOTIFICATION_SERVER) {
+ if (notifier_options_.notification_method ==
+ notifier::NOTIFICATION_TRANSITIONAL) {
talk_mediator_->AddSubscribedServiceUrl(
browser_sync::kSyncLegacyServiceUrl);
}
@@ -1347,54 +1348,22 @@ bool SyncManager::SyncInternal::Init(
// Listen to TalkMediator events ourselves
talk_mediator_->SetDelegate(this);
- std::string gaia_url = gaia::kGaiaUrl;
- const char* service_id = gaia_service_id ?
- gaia_service_id : SYNC_SERVICE_NAME;
-
- BridgedGaiaAuthenticator* gaia_auth = new BridgedGaiaAuthenticator(
- gaia_source, service_id, gaia_url, auth_post_factory);
-
- LOG(INFO) << "Sync is bringing up authwatcher and SyncSessionContext.";
-
- auth_watcher_ = new AuthWatcher(dir_manager(),
- connection_manager(),
- gaia_source,
- service_id,
- gaia_url,
- user_settings_.get(),
- gaia_auth);
-
- authwatcher_hookup_.reset(NewEventListenerHookup(auth_watcher_->channel(),
- this, &SyncInternal::HandleAuthWatcherEvent));
-
- // Build a SyncSessionContext and store the worker in it.
- SyncSessionContext* context = new SyncSessionContext(
- connection_manager_.get(), auth_watcher(),
- dir_manager(), model_safe_worker_registrar);
-
- // The SyncerThread takes ownership of |context|.
- syncer_thread_ = new SyncerThread(context, &allstatus_);
- allstatus_.WatchSyncerThread(syncer_thread());
-
- // Subscribe to the syncer thread's channel.
- syncer_event_.reset(syncer_thread()->relay_channel()->AddObserver(this));
-
- bool attempting_auth = false;
- std::string username, auth_token;
- if (attempt_last_user_authentication &&
- auth_watcher()->settings()->GetLastUserAndServiceToken(
- SYNC_SERVICE_NAME, &username, &auth_token)) {
- if (invalidate_last_user_auth_token) {
- auth_token += "bogus";
- }
- attempting_auth = AuthenticateForUser(username, auth_token);
- } else if (!lsid.empty()) {
- attempting_auth = true;
- AuthenticateWithLsid(lsid);
+ // Test mode does not use a syncer context or syncer thread.
+ if (!setup_for_test_mode) {
+ // Build a SyncSessionContext and store the worker in it.
+ LOG(INFO) << "Sync is bringing up SyncSessionContext.";
+ SyncSessionContext* context = new SyncSessionContext(
+ connection_manager_.get(), dir_manager(), model_safe_worker_registrar);
+
+ // The SyncerThread takes ownership of |context|.
+ syncer_thread_ = new SyncerThread(context);
+ allstatus_.WatchSyncerThread(syncer_thread());
+
+ // Subscribe to the syncer thread's channel.
+ syncer_event_.reset(syncer_thread()->relay_channel()->AddObserver(this));
}
- if (attempt_last_user_authentication && !attempting_auth)
- RaiseAuthNeededEvent();
- return true;
+
+ return SignIn(credentials);
}
void SyncManager::SyncInternal::StartSyncing() {
@@ -1426,7 +1395,8 @@ void SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
void SyncManager::SyncInternal::SendPendingXMPPNotification(
bool new_pending_notification) {
DCHECK_EQ(MessageLoop::current(), core_message_loop_);
- DCHECK_NE(notification_method_, browser_sync::NOTIFICATION_SERVER);
+ DCHECK_NE(notifier_options_.notification_method,
+ notifier::NOTIFICATION_SERVER);
notification_pending_ = notification_pending_ || new_pending_notification;
if (!notification_pending_) {
LOG(INFO) << "Not sending notification: no pending notification";
@@ -1439,7 +1409,7 @@ void SyncManager::SyncInternal::SendPendingXMPPNotification(
}
LOG(INFO) << "Sending XMPP notification...";
OutgoingNotificationData notification_data;
- if (notification_method_ == browser_sync::NOTIFICATION_LEGACY) {
+ if (notifier_options_.notification_method == notifier::NOTIFICATION_LEGACY) {
notification_data.service_id = browser_sync::kSyncLegacyServiceId;
notification_data.service_url = browser_sync::kSyncLegacyServiceUrl;
notification_data.send_content = false;
@@ -1449,7 +1419,7 @@ void SyncManager::SyncInternal::SendPendingXMPPNotification(
notification_data.send_content = true;
notification_data.priority = browser_sync::kSyncPriority;
notification_data.write_to_cache_only = true;
- if (notification_method_ == browser_sync::NOTIFICATION_NEW) {
+ if (notifier_options_.notification_method == notifier::NOTIFICATION_NEW) {
notification_data.service_specific_data =
browser_sync::kSyncServiceSpecificData;
notification_data.require_subscription = true;
@@ -1466,52 +1436,65 @@ void SyncManager::SyncInternal::SendPendingXMPPNotification(
}
}
-void SyncManager::SyncInternal::Authenticate(const std::string& username,
- const std::string& password,
- const std::string& captcha) {
- DCHECK(username_for_share().empty() || username == username_for_share())
- << "Username change from valid username detected";
- if (allstatus_.status().authenticated)
- return;
- if (password.empty()) {
- // TODO(timsteele): Seems like this shouldn't be needed, but auth_watcher
- // currently drops blank password attempts on the floor and doesn't update
- // state; it only LOGs an error in this case. We want to make sure we set
- // our GoogleServiceAuthError state to denote an error.
- RaiseAuthNeededEvent();
+bool SyncManager::SyncInternal::OpenDirectory() {
+ DCHECK(!initialized()) << "Should only happen once";
+
+ bool share_opened = dir_manager()->Open(username_for_share());
+ DCHECK(share_opened);
+ if (!share_opened) {
+ if (observer_) {
+ observer_->OnStopSyncingPermanently();
+ }
+
+ LOG(ERROR) << "Could not open share for:" << username_for_share();
+ return false;
}
- auth_watcher()->Authenticate(username, password, std::string(),
- captcha);
-}
-void SyncManager::SyncInternal::AuthenticateWithLsid(const string& lsid) {
- DCHECK(!lsid.empty());
- auth_watcher()->AuthenticateWithLsid(lsid);
+ // Database has to be initialized for the guid to be available.
+ syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
+ if (!lookup.good()) {
+ NOTREACHED();
+ return false;
+ }
+
+ connection_manager()->set_client_id(lookup->cache_guid());
+
+ if (syncer_thread())
+ syncer_thread()->CreateSyncer(username_for_share());
+
+ MarkAndNotifyInitializationComplete();
+ dir_change_hookup_.reset(lookup->AddChangeObserver(this));
+ return true;
}
-bool SyncManager::SyncInternal::AuthenticateForUser(
- const std::string& username, const std::string& auth_token) {
- share_.authenticated_name = username;
+bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
+ DCHECK_EQ(MessageLoop::current(), core_message_loop_);
+ DCHECK(share_.name.empty());
+ share_.name = credentials.email;
- // We optimize by opening the directory before the "fresh" authentication
- // attempt completes so that we can immediately begin processing changes.
- if (!dir_manager()->Open(username_for_share())) {
- DCHECK(false) << "Had last known user but could not open directory";
+ LOG(INFO) << "Signing in user: " << username_for_share();
+ if (!OpenDirectory()) {
return false;
}
- // Load the last-known good auth token into the connection manager and send
- // it off to the AuthWatcher for validation. The result of the validation
- // will update the connection manager if necessary.
- connection_manager()->set_auth_token(auth_token);
- auth_watcher()->AuthenticateWithToken(username, auth_token);
+ UpdateCredentials(credentials);
return true;
}
+void SyncManager::SyncInternal::UpdateCredentials(
+ const SyncCredentials& credentials) {
+ DCHECK_EQ(MessageLoop::current(), core_message_loop_);
+ DCHECK(share_.name == credentials.email);
+ connection_manager()->set_auth_token(credentials.sync_token);
+ TalkMediatorLogin(credentials.email, credentials.sync_token);
+ CheckServerReachable();
+ sync_manager_->RequestNudge();
+}
+
void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
- auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS;
- if (observer_)
- observer_->OnAuthError(AuthError(auth_problem_));
+ if (observer_) {
+ observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS));
+ }
}
void SyncManager::SyncInternal::SetPassphrase(
@@ -1540,7 +1523,10 @@ void SyncManager::SyncInternal::SetPassphrase(
cryptographer->GetKeys(specifics.mutable_encrypted());
node.SetNigoriSpecifics(specifics);
}
- observer_->OnPassphraseAccepted();
+
+ std::string bootstrap_token;
+ cryptographer->GetBootstrapToken(&bootstrap_token);
+ observer_->OnPassphraseAccepted(bootstrap_token);
}
SyncManager::~SyncManager() {
@@ -1560,22 +1546,14 @@ void SyncManager::Shutdown() {
}
void SyncManager::SyncInternal::Shutdown() {
+ method_factory_.RevokeAll();
+
// We NULL out talk_mediator_ so that any tasks pumped below do not
// trigger further XMPP actions.
//
// TODO(akalin): NULL the other member variables defensively, too.
scoped_ptr<TalkMediator> talk_mediator(talk_mediator_.release());
- // First reset the AuthWatcher in case an auth attempt is in progress so that
- // it terminates gracefully before we shutdown and close other components.
- // Otherwise the attempt can complete after we've closed the directory, for
- // example, and cause initialization to continue, which is bad.
- if (auth_watcher_) {
- auth_watcher_->Shutdown();
- auth_watcher_ = NULL;
- authwatcher_hookup_.reset();
- }
-
if (syncer_thread()) {
if (!syncer_thread()->Stop(kThreadExitTimeoutMsec)) {
LOG(FATAL) << "Unable to stop the syncer, it won't be happy...";
@@ -1595,7 +1573,7 @@ void SyncManager::SyncInternal::Shutdown() {
// Pump any messages the auth watcher, syncer thread, or talk
// mediator posted before they shut down. (See HandleSyncerEvent(),
- // HandleAuthWatcherEvent(), and HandleTalkMediatorEvent() for the
+ // and HandleTalkMediatorEvent() for the
// events that may be posted.)
{
CHECK(core_message_loop_);
@@ -1607,6 +1585,8 @@ void SyncManager::SyncInternal::Shutdown() {
net::NetworkChangeNotifier::RemoveObserver(this);
+ connection_manager_hookup_.reset();
+
if (dir_manager()) {
dir_manager()->FinalSaveChangesForAll();
dir_manager()->Close(username_for_share());
@@ -1615,7 +1595,6 @@ void SyncManager::SyncInternal::Shutdown() {
// Reset the DirectoryManager and UserSettings so they relinquish sqlite
// handles to backing files.
share_.dir_manager.reset();
- user_settings_.reset();
// We don't want to process any more events.
dir_change_hookup_.reset();
@@ -1628,15 +1607,7 @@ void SyncManager::SyncInternal::OnIPAddressChanged() {
// TODO(akalin): CheckServerReachable() can block, which may cause
// jank if we try to shut down sync. Fix this.
connection_manager()->CheckServerReachable();
-}
-
-void SyncManager::SyncInternal::HandleDirectoryManagerEvent(
- const syncable::DirectoryManagerEvent& event) {
- LOG(INFO) << "Sync internal handling a directory manager event";
- if (syncable::DirectoryManagerEvent::OPENED == event.what_happened) {
- DCHECK(!initialized()) << "Should only happen once";
- MarkAndNotifyInitializationComplete();
- }
+ sync_manager_->RequestNudge();
}
// Listen to model changes, filter out ones initiated by the sync API, and
@@ -1644,7 +1615,11 @@ void SyncManager::SyncInternal::HandleDirectoryManagerEvent(
// ApplyUpdates) to data_->changelist.
void SyncManager::SyncInternal::HandleChannelEvent(
const syncable::DirectoryChangeEvent& event) {
- if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_ENDING) {
+ if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_COMPLETE) {
+ // Safe to perform slow I/O operations now, go ahead and commit.
+ HandleTransactionCompleteChangeEvent(event);
+ return;
+ } else if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_ENDING) {
HandleTransactionEndingChangeEvent(event);
return;
} else if (event.todo == syncable::DirectoryChangeEvent::CALCULATE_CHANGES) {
@@ -1659,6 +1634,43 @@ void SyncManager::SyncInternal::HandleChannelEvent(
}
}
+void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
+ const syncable::DirectoryChangeEvent& event) {
+ // This notification happens immediately after the channel mutex is released
+ // This allows work to be performed without holding the WriteTransaction lock
+ // but before the transaction is finished.
+ DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::TRANSACTION_COMPLETE);
+ if (!observer_)
+ return;
+
+ // Call commit
+ for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
+ if (model_has_change_.test(i)) {
+ observer_->OnChangesComplete(syncable::ModelTypeFromInt(i));
+ model_has_change_.reset(i);
+ }
+ }
+}
+
+void SyncManager::SyncInternal::HandleServerConnectionEvent(
+ const ServerConnectionEvent& event) {
+ allstatus_.HandleServerConnectionEvent(event);
+ if (event.what_happened == ServerConnectionEvent::STATUS_CHANGED) {
+ if (event.connection_code ==
+ browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
+ if (observer_) {
+ observer_->OnAuthError(AuthError::None());
+ }
+ }
+
+ if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
+ if (observer_) {
+ observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS));
+ }
+ }
+ }
+}
+
void SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
const syncable::DirectoryChangeEvent& event) {
// This notification happens immediately before a syncable WriteTransaction
@@ -1683,6 +1695,7 @@ void SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
if (!ordered_changes.empty()) {
observer_->OnChangesApplied(syncable::ModelTypeFromInt(i), &trans,
&ordered_changes[0], ordered_changes.size());
+ model_has_change_.set(i, true);
}
change_buffers_[i].Clear();
}
@@ -1730,12 +1743,22 @@ void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
syncable::ModelType type, ChangeReorderBuffer* buffer,
- const syncable::EntryKernel& original, bool existed_before,
- bool exists_now) {
+ Cryptographer* cryptographer, const syncable::EntryKernel& original,
+ bool existed_before, bool exists_now) {
// If this is a deletion, attach the entity specifics as extra data
// so that the delete can be processed.
if (!exists_now && existed_before) {
buffer->SetSpecificsForId(id, original.ref(SPECIFICS));
+ if (type == syncable::PASSWORDS) {
+ // Need to dig a bit deeper as passwords are encrypted.
+ scoped_ptr<sync_pb::PasswordSpecificsData> data(
+ DecryptPasswordSpecifics(original.ref(SPECIFICS), cryptographer));
+ if (!data.get()) {
+ NOTREACHED();
+ return;
+ }
+ buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
+ }
}
}
@@ -1769,7 +1792,8 @@ void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
else if (exists_now && existed_before && VisiblePropertiesDiffer(*i, e))
change_buffers_[type].PushUpdatedItem(id, VisiblePositionsDiffer(*i, e));
- SetExtraChangeRecordData(id, type, &change_buffers_[type], *i,
+ SetExtraChangeRecordData(id, type, &change_buffers_[type],
+ dir_manager()->cryptographer(), *i,
existed_before, exists_now);
}
}
@@ -1829,7 +1853,6 @@ void SyncManager::SyncInternal::HandleChannelEvent(const SyncerEvent& event) {
// Notifications are sent at the end of every sync cycle, regardless of
// whether we should sync again.
if (event.what_happened == SyncerEvent::SYNC_CYCLE_ENDED) {
-
ModelSafeRoutingInfo enabled_types;
registrar_->GetModelSafeRoutingInfo(&enabled_types);
if (enabled_types.count(syncable::PASSWORDS) > 0) {
@@ -1844,16 +1867,14 @@ void SyncManager::SyncInternal::HandleChannelEvent(const SyncerEvent& event) {
}
const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics();
if (!nigori.encrypted().blob().empty()) {
- if (cryptographer->CanDecrypt(nigori.encrypted())) {
- cryptographer->SetKeys(nigori.encrypted());
- } else {
- cryptographer->SetPendingKeys(nigori.encrypted());
- }
+ DCHECK(!cryptographer->CanDecrypt(nigori.encrypted()));
+ cryptographer->SetPendingKeys(nigori.encrypted());
}
}
+
// If we've completed a sync cycle and the cryptographer isn't ready yet,
// prompt the user for a passphrase.
- if (!cryptographer->is_ready()) {
+ if (!cryptographer->is_ready() || cryptographer->has_pending_keys()) {
observer_->OnPassphraseRequired();
}
}
@@ -1865,7 +1886,8 @@ void SyncManager::SyncInternal::HandleChannelEvent(const SyncerEvent& event) {
observer_->OnSyncCycleCompleted(event.snapshot);
}
- if (notification_method_ != browser_sync::NOTIFICATION_SERVER) {
+ if (notifier_options_.notification_method !=
+ notifier::NOTIFICATION_SERVER) {
// TODO(chron): Consider changing this back to track has_more_to_sync
// only notify peers if a successful commit has occurred.
bool new_pending_notification =
@@ -1893,105 +1915,21 @@ void SyncManager::SyncInternal::HandleChannelEvent(const SyncerEvent& event) {
observer_->OnStopSyncingPermanently();
return;
}
-}
-void SyncManager::SyncInternal::HandleAuthWatcherEvent(
- const AuthWatcherEvent& event) {
- allstatus_.HandleAuthWatcherEvent(event);
- // We don't care about an authentication attempt starting event, and we
- // don't want to reset our state to GoogleServiceAuthError::NONE because the
- // fact that an _attempt_ is starting doesn't change the fact that we have an
- // auth problem.
- if (event.what_happened == AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START)
+ if (event.what_happened == SyncerEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
+ observer_->OnClearServerDataSucceeded();
return;
- // We clear our last auth problem cache on new auth watcher events, and only
- // set it to indicate a problem state for certain AuthWatcherEvent types.
- auth_problem_ = AuthError::NONE;
- switch (event.what_happened) {
- case AuthWatcherEvent::AUTH_SUCCEEDED:
- DCHECK(!event.user_email.empty());
- // We now know the supplied username and password were valid. If this
- // wasn't the first sync, authenticated_name should already be assigned.
- if (username_for_share().empty()) {
- share_.authenticated_name = event.user_email;
- }
-
- DCHECK(LowerCaseEqualsASCII(username_for_share(),
- StringToLowerASCII(event.user_email).c_str()))
- << "username_for_share= " << username_for_share()
- << ", event.user_email= " << event.user_email;
-
- if (observer_)
- observer_->OnAuthError(AuthError::None());
-
- // Hook up the DirectoryChangeEvent listener, HandleChangeEvent.
- {
- syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
- if (!lookup.good()) {
- DCHECK(false) << "ScopedDirLookup creation failed; unable to hook "
- << "up directory change event listener!";
- return;
- }
-
- // Note that we can end up here multiple times, for example if the
- // user had to re-login and we got a second AUTH_SUCCEEDED event. Take
- // care not to add ourselves as an observer a second time.
- if (!dir_change_hookup_.get())
- dir_change_hookup_.reset(lookup->AddChangeObserver(this));
- }
-
- if (!event.auth_token.empty()) {
- core_message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(
- this, &SyncManager::SyncInternal::TalkMediatorLogin,
- event.user_email, event.auth_token));
- }
- return;
- case AuthWatcherEvent::AUTH_RENEWED:
- DCHECK(!event.user_email.empty());
- DCHECK(!event.auth_token.empty());
- core_message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(
- this, &SyncManager::SyncInternal::TalkMediatorLogin,
- event.user_email, event.auth_token));
- return;
- // Authentication failures translate to GoogleServiceAuthError events.
- case AuthWatcherEvent::GAIA_AUTH_FAILED: // Invalid GAIA credentials.
- if (event.auth_results->auth_error == gaia::CaptchaRequired) {
- auth_problem_ = AuthError::CAPTCHA_REQUIRED;
- std::string url_string("https://www.google.com/accounts/");
- url_string += event.auth_results->captcha_url;
- GURL captcha(url_string);
- observer_->OnAuthError(AuthError::FromCaptchaChallenge(
- event.auth_results->captcha_token, captcha,
- GURL(event.auth_results->auth_error_url)));
- return;
- } else if (event.auth_results->auth_error ==
- gaia::ConnectionUnavailable) {
- auth_problem_ = AuthError::CONNECTION_FAILED;
- } else {
- auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS;
- }
- break;
- case AuthWatcherEvent::SERVICE_AUTH_FAILED: // Expired GAIA credentials.
- auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS;
- break;
- case AuthWatcherEvent::SERVICE_USER_NOT_SIGNED_UP:
- auth_problem_ = AuthError::USER_NOT_SIGNED_UP;
- break;
- case AuthWatcherEvent::SERVICE_CONNECTION_FAILED:
- auth_problem_ = AuthError::CONNECTION_FAILED;
- break;
- default: // We don't care about the many other AuthWatcherEvent types.
- return;
}
+ if (event.what_happened == SyncerEvent::CLEAR_SERVER_DATA_FAILED) {
+ observer_->OnClearServerDataFailed();
+ return;
+ }
- // Fire notification that the status changed due to an authentication error.
- if (observer_)
- observer_->OnAuthError(AuthError(auth_problem_));
+ if (event.what_happened == SyncerEvent::UPDATED_TOKEN) {
+ observer_->OnUpdatedToken(event.updated_token);
+ return;
+ }
}
void SyncManager::SyncInternal::OnNotificationStateChange(
@@ -2002,8 +1940,8 @@ void SyncManager::SyncInternal::OnNotificationStateChange(
if (syncer_thread()) {
syncer_thread()->SetNotificationsEnabled(notifications_enabled);
}
- if ((notification_method_ != browser_sync::NOTIFICATION_SERVER) &&
- notifications_enabled) {
+ if ((notifier_options_.notification_method !=
+ notifier::NOTIFICATION_SERVER) && notifications_enabled) {
// Nudge the syncer thread when notifications are enabled, in case there is
// any data that has not yet been synced. If we are listening to
// server-issued notifications, we are already guaranteed to receive a
@@ -2033,8 +1971,8 @@ void SyncManager::SyncInternal::TalkMediatorLogin(
<< "(talk_mediator_ is NULL)";
return;
}
- // TODO(akalin): Make talk_mediator automatically login on
- // auth token change.
+ LOG(INFO) << "P2P: Trying talk mediator login.";
+
talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME);
talk_mediator_->Login();
}
@@ -2044,7 +1982,8 @@ void SyncManager::SyncInternal::OnIncomingNotification(
// Check if the service url is a sync URL. An empty service URL is
// treated as a legacy sync notification. If we're listening to
// server-issued notifications, no need to check the service_url.
- if ((notification_method_ == browser_sync::NOTIFICATION_SERVER) ||
+ if ((notifier_options_.notification_method ==
+ notifier::NOTIFICATION_SERVER) ||
notification_data.service_url.empty() ||
(notification_data.service_url ==
browser_sync::kSyncLegacyServiceUrl) ||
@@ -2052,7 +1991,8 @@ void SyncManager::SyncInternal::OnIncomingNotification(
browser_sync::kSyncServiceUrl)) {
LOG(INFO) << "P2P: Updates on server, pushing syncer";
if (syncer_thread()) {
- syncer_thread()->NudgeSyncer(0, SyncerThread::kNotification);
+ // Introduce a delay to help coalesce initial notifications.
+ syncer_thread()->NudgeSyncer(250, SyncerThread::kNotification);
}
allstatus_.IncrementNotificationsReceived();
} else {
@@ -2062,7 +2002,8 @@ void SyncManager::SyncInternal::OnIncomingNotification(
}
void SyncManager::SyncInternal::OnOutgoingNotification() {
- DCHECK_NE(notification_method_, browser_sync::NOTIFICATION_SERVER);
+ DCHECK_NE(notifier_options_.notification_method,
+ notifier::NOTIFICATION_SERVER);
allstatus_.IncrementNotificationsSent();
}
@@ -2089,43 +2030,13 @@ void SyncManager::SyncInternal::SaveChanges() {
lookup->SaveChanges();
}
-void SyncManager::SetupForTestMode(const std::wstring& test_username) {
- DCHECK(data_) << "SetupForTestMode requires initialization";
- data_->SetupForTestMode(test_username);
-}
-
-void SyncManager::SyncInternal::SetupForTestMode(
- const std::wstring& test_username) {
- share_.authenticated_name = WideToUTF8(test_username);
-
- // Some tests are targeting only local db operations & integrity, and don't
- // want syncer thread interference.
- syncer_event_.reset();
- allstatus_.WatchSyncerThread(NULL);
- syncer_thread_ = NULL;
-
- if (!dir_manager()->Open(username_for_share()))
- DCHECK(false) << "Could not open directory when running in test mode";
-
- // Hook up the DirectoryChangeEvent listener, HandleChangeEvent.
- {
- syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
- if (!lookup.good()) {
- DCHECK(false) << "ScopedDirLookup creation failed; unable to hook "
- << "up directory change event listener!";
- return;
- }
- dir_change_hookup_.reset(lookup->AddChangeObserver(this));
- }
-}
-
//////////////////////////////////////////////////////////////////////////
// BaseTransaction member definitions
BaseTransaction::BaseTransaction(UserShare* share)
: lookup_(NULL) {
DCHECK(share && share->dir_manager.get());
lookup_ = new syncable::ScopedDirLookup(share->dir_manager.get(),
- share->authenticated_name);
+ share->name);
cryptographer_ = share->dir_manager->cryptographer();
if (!(lookup_->good()))
DCHECK(false) << "ScopedDirLookup failed on valid DirManager.";
@@ -2139,4 +2050,9 @@ UserShare* SyncManager::GetUserShare() const {
return data_->GetUserShare();
}
+bool SyncManager::HasUnsyncedItems() const {
+ sync_api::ReadTransaction trans(GetUserShare());
+ return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
+}
+
} // namespace sync_api
diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h
index 90e1a5c..8ffd729 100644
--- a/chrome/browser/sync/engine/syncapi.h
+++ b/chrome/browser/sync/engine/syncapi.h
@@ -37,21 +37,23 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCAPI_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCAPI_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "build/build_config.h"
-#include "chrome/browser/google_service_auth_error.h"
-#include "chrome/browser/sync/notification_method.h"
+#include "chrome/browser/sync/protocol/password_specifics.pb.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"
#include "googleurl/src/gurl.h"
+class FilePath;
+
namespace browser_sync {
class ModelSafeWorkerRegistrar;
@@ -60,6 +62,10 @@ struct SyncSessionSnapshot;
}
}
+namespace notifier {
+struct NotifierOptions;
+}
+
// Forward declarations of internal class types so that sync API objects
// may have opaque pointers to these types.
namespace syncable {
@@ -73,10 +79,12 @@ class WriteTransaction;
}
namespace sync_pb {
+class AppSpecifics;
class AutofillSpecifics;
class BookmarkSpecifics;
class EntitySpecifics;
class ExtensionSpecifics;
+class SessionSpecifics;
class NigoriSpecifics;
class PasswordSpecifics;
class PreferenceSpecifics;
@@ -103,12 +111,14 @@ struct UserShare {
// be shared across multiple threads (unlike Directory).
scoped_ptr<syncable::DirectoryManager> dir_manager;
- // The username of the sync user. This is empty until we have performed at
- // least one successful GAIA authentication with this username, which means
- // on first-run it is empty until an AUTH_SUCCEEDED event and on future runs
- // it is set as soon as the client instructs us to authenticate for the last
- // known valid user (AuthenticateForLastKnownUser()).
- std::string authenticated_name;
+ // The username of the sync user.
+ std::string name;
+};
+
+// Contains everything needed to talk to and identify a user account.
+struct SyncCredentials {
+ std::string email;
+ std::string sync_token;
};
// A valid BaseNode will never have an ID of zero.
@@ -174,6 +184,10 @@ class BaseNode {
// TODO(ncarter): Remove this datatype-specific accessor.
void GetFaviconBytes(std::vector<unsigned char>* output) const;
+ // Getter specific to the APPS datatype. Returns protobuf
+ // data. Can only be called if GetModelType() == APPS.
+ const sync_pb::AppSpecifics& GetAppSpecifics() const;
+
// Getter specific to the AUTOFILL datatype. Returns protobuf
// data. Can only be called if GetModelType() == AUTOFILL.
const sync_pb::AutofillSpecifics& GetAutofillSpecifics() const;
@@ -202,6 +216,10 @@ class BaseNode {
// data. Can only be called if GetModelType() == EXTENSIONS.
const sync_pb::ExtensionSpecifics& GetExtensionSpecifics() const;
+ // Getter specific to the SESSIONS datatype. Returns protobuf
+ // data. Can only be called if GetModelType() == SESSIONS.
+ const sync_pb::SessionSpecifics& GetSessionSpecifics() const;
+
// Returns the local external ID associated with the node.
int64 GetExternalId() const;
@@ -315,6 +333,10 @@ class WriteNode : public BaseNode {
void SetURL(const GURL& url);
void SetFaviconBytes(const std::vector<unsigned char>& bytes);
+ // Set the app specifics (id, update url, enabled state, etc).
+ // Should only be called if GetModelType() == APPS.
+ void SetAppSpecifics(const sync_pb::AppSpecifics& specifics);
+
// Set the autofill specifics (name and value).
// Should only be called if GetModelType() == AUTOFILL.
void SetAutofillSpecifics(const sync_pb::AutofillSpecifics& specifics);
@@ -343,6 +365,10 @@ class WriteNode : public BaseNode {
// Should only be called if GetModelType() == EXTENSIONS.
void SetExtensionSpecifics(const sync_pb::ExtensionSpecifics& specifics);
+ // Set the session specifics (windows, tabs, navigations etc.).
+ // Should only be called if GetModelType() == SESSIONS.
+ void SetSessionSpecifics(const sync_pb::SessionSpecifics& specifics);
+
// Implementation of BaseNode's abstract virtual accessors.
virtual const syncable::Entry* GetEntry() const;
@@ -362,6 +388,8 @@ class WriteNode : public BaseNode {
// for internal initialization (you can use them to set the modeltype).
// Additionally, they will mark for syncing if the underlying value
// changes.
+ void PutAppSpecificsAndMarkForSyncing(
+ const sync_pb::AppSpecifics& new_value);
void PutAutofillSpecificsAndMarkForSyncing(
const sync_pb::AutofillSpecifics& new_value);
void PutBookmarkSpecificsAndMarkForSyncing(
@@ -378,6 +406,8 @@ class WriteNode : public BaseNode {
const sync_pb::TypedUrlSpecifics& new_value);
void PutExtensionSpecificsAndMarkForSyncing(
const sync_pb::ExtensionSpecifics& new_value);
+ void PutSessionSpecificsAndMarkForSyncing(
+ const sync_pb::SessionSpecifics& new_value);
void PutSpecificsAndMarkForSyncing(
const sync_pb::EntitySpecifics& specifics);
@@ -525,6 +555,15 @@ class SyncManager {
// internal types from clients of the interface.
class SyncInternal;
+ // TODO(tim): Depending on how multi-type encryption pans out, maybe we
+ // should turn ChangeRecord itself into a class. Or we could template this
+ // wrapper / add a templated method to return unencrypted protobufs.
+ class ExtraChangeRecordData {
+ public:
+ ExtraChangeRecordData() {}
+ virtual ~ExtraChangeRecordData() {}
+ };
+
// ChangeRecord indicates a single item that changed as a result of a sync
// operation. This gives the sync id of the node that changed, and the type
// of change. To get the actual property values after an ADD or UPDATE, the
@@ -539,6 +578,21 @@ class SyncManager {
int64 id;
Action action;
sync_pb::EntitySpecifics specifics;
+ linked_ptr<ExtraChangeRecordData> extra;
+ };
+
+ // Since PasswordSpecifics is just an encrypted blob, we extend to provide
+ // access to unencrypted bits.
+ class ExtraPasswordChangeRecordData : public ExtraChangeRecordData {
+ public:
+ ExtraPasswordChangeRecordData(const sync_pb::PasswordSpecificsData& data)
+ : unencrypted_(data) {}
+ virtual ~ExtraPasswordChangeRecordData() {}
+ const sync_pb::PasswordSpecificsData& unencrypted() {
+ return unencrypted_;
+ }
+ private:
+ sync_pb::PasswordSpecificsData unencrypted_;
};
// Status encapsulates detailed state about the internals of the SyncManager.
@@ -637,6 +691,19 @@ class SyncManager {
const ChangeRecord* changes,
int change_count) = 0;
+ // OnChangesComplete gets called when the TransactionComplete event is
+ // posted (after OnChangesApplied finishes), after the transaction lock
+ // and the change channel mutex are released.
+ //
+ // The purpose of this function is to support processors that require
+ // split-transactions changes. For example, if a model processor wants to
+ // perform blocking I/O due to a change, it should calculate the changes
+ // while holding the transaction lock (from within OnChangesApplied), buffer
+ // those changes, let the transaction fall out of scope, and then commit
+ // those changes from within OnChangesComplete (postponing the blocking
+ // I/O to when it no longer holds any lock).
+ virtual void OnChangesComplete(syncable::ModelType model_type) = 0;
+
// A round-trip sync-cycle took place and the syncer has resolved any
// conflicts that may have arisen.
virtual void OnSyncCycleCompleted(
@@ -645,12 +712,18 @@ class SyncManager {
// Called when user interaction may be required due to an auth problem.
virtual void OnAuthError(const GoogleServiceAuthError& auth_error) = 0;
+ // Called when a new auth token is provided by the sync server.
+ virtual void OnUpdatedToken(const std::string& token) = 0;
+
// Called when user interaction is required to obtain a valid passphrase.
virtual void OnPassphraseRequired() = 0;
// Called when the passphrase provided by the user has been accepted and is
- // now used to encrypt sync data.
- virtual void OnPassphraseAccepted() = 0;
+ // now used to encrypt sync data. |bootstrap_token| is an opaque base64
+ // encoded representation of the key generated by the accepted passphrase,
+ // and is provided to the observer for persistence purposes and use in a
+ // future initialization of sync (e.g. after restart).
+ virtual void OnPassphraseAccepted(const std::string& bootstrap_token) = 0;
// Called when initialization is complete to the point that SyncManager can
// process changes. This does not necessarily mean authentication succeeded
@@ -673,6 +746,11 @@ class SyncManager {
// global stop syncing operation has wiped the store.
virtual void OnStopSyncingPermanently() = 0;
+ // After a request to clear server data, these callbacks are invoked to
+ // indicate success or failure
+ virtual void OnClearServerDataSucceeded() = 0;
+ virtual void OnClearServerDataFailed() = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(Observer);
};
@@ -688,64 +766,39 @@ class SyncManager {
// |sync_server_and_path| and |sync_server_port| represent the Chrome sync
// server to use, and |use_ssl| specifies whether to communicate securely;
// the default is false.
- // |gaia_service_id| is the service id used for GAIA authentication. If it's
- // null then default will be used.
// |post_factory| will be owned internally and used to create
// instances of an HttpPostProvider.
- // |auth_post_factory| will be owned internally and used to create
- // instances of an HttpPostProvider for communicating with GAIA.
- // TODO(timsteele): It seems like one factory should suffice, but for now to
- // avoid having to deal with threading issues since the auth code and syncer
- // code live on separate threads that run simultaneously, we just dedicate
- // one to each component. Long term we may want to reconsider the HttpBridge
- // API to take all the params in one chunk in a threadsafe manner.. which is
- // still suboptimal as there will be high contention between the two threads
- // on startup; so maybe what we have now is the best solution- it does mirror
- // the CURL implementation as each thread creates their own internet handle.
- // Investigate.
// |model_safe_worker| ownership is given to the SyncManager.
// |user_agent| is a 7-bit ASCII string suitable for use as the User-Agent
// HTTP header. Used internally when collecting stats to classify clients.
- // As a fallback when no cached auth information is available, try to
- // bootstrap authentication using |lsid|, if it isn't empty.
- //
- // |invalidate_last_user_auth_token| makes it so that any auth token
- // read from user settings is invalidated. This is used for testing
- // code paths related to authentication failures.
- //
- // |invalidate_xmpp_auth_token| makes it so that any auth token
- // used to log into XMPP is invalidated. This is used for testing
- // code paths related to authentication failures for XMPP only.
+ // |notifier_options| contains options specific to sync notifications.
bool Init(const FilePath& database_location,
const char* sync_server_and_path,
int sync_server_port,
- const char* gaia_service_id,
- const char* gaia_source,
bool use_ssl,
HttpPostProviderFactory* post_factory,
- HttpPostProviderFactory* auth_post_factory,
browser_sync::ModelSafeWorkerRegistrar* registrar,
- bool attempt_last_user_authentication,
- bool invalidate_last_user_auth_token,
- bool invalidate_xmpp_auth_token,
const char* user_agent,
- const char* lsid,
- bool use_chrome_async_socket,
- browser_sync::NotificationMethod notification_method);
+ const SyncCredentials& credentials,
+ const notifier::NotifierOptions& notifier_options,
+ const std::string& restored_key_for_bootstrapping,
+ bool setup_for_test_mode);
// Returns the username last used for a successful authentication.
// Returns empty if there is no such username.
const std::string& GetAuthenticatedUsername();
- // Submit credentials to GAIA for verification. On success, both |username|
- // and the obtained auth token are persisted on disk for future re-use.
- // If authentication fails, OnAuthProblem is called on our Observer.
- // The Observer may, in turn, decide to try again with new
- // credentials. Calling this method again is the appropriate course of action
- // to "retry".
- // |username|, |password|, and |captcha| are owned by the caller.
- void Authenticate(const char* username, const char* password,
- const char* captcha);
+ // Check if the database has been populated with a full "initial" download of
+ // sync items for each data type currently present in the routing info.
+ // Prerequisite for calling this is that OnInitializationComplete has been
+ // called.
+ bool InitialSyncEndedForAllEnabledTypes();
+
+ // Migrate tokens from user settings DB to the token service.
+ void MigrateTokens();
+
+ // Update tokens that we're using in Sync. Email must stay the same.
+ void UpdateCredentials(const SyncCredentials& credentials);
// Start the SyncerThread.
void StartSyncing();
@@ -775,6 +828,9 @@ class SyncManager {
// to run at the next available opportunity.
void RequestNudge();
+ // Request a clearing of all data on the server
+ void RequestClearServerData();
+
// Adds a listener to be notified of sync events.
// NOTE: It is OK (in fact, it's probably a good idea) to call this before
// having received OnInitializationCompleted.
@@ -798,20 +854,16 @@ class SyncManager {
// to the syncapi model.
void SaveChanges();
- // Invoking this method will result in the syncapi bypassing authentication
- // and opening a local store suitable for testing client code. When in this
- // mode, nothing will ever get synced to a server (in fact no HTTP
- // communication will take place).
- // Note: The SyncManager precondition that you must first call Init holds;
- // this will fail unless we're initialized.
- void SetupForTestMode(const std::wstring& test_username);
-
// Issue a final SaveChanges, close sqlite handles, and stop running threads.
// Must be called from the same thread that called Init().
void Shutdown();
UserShare* GetUserShare() const;
+ // Uses a read-only transaction to determine if the directory being synced has
+ // any remaining unsynced items.
+ bool HasUnsyncedItems() const;
+
private:
// An opaque pointer to the nested private class.
SyncInternal* data_;
diff --git a/chrome/browser/sync/engine/syncapi_unittest.cc b/chrome/browser/sync/engine/syncapi_unittest.cc
index a77134b..b83c501 100644
--- a/chrome/browser/sync/engine/syncapi_unittest.cc
+++ b/chrome/browser/sync/engine/syncapi_unittest.cc
@@ -25,7 +25,7 @@ class SyncApiTest : public testing::Test {
virtual void SetUp() {
setter_upper_.SetUp();
share_.dir_manager.reset(setter_upper_.manager());
- share_.authenticated_name = setter_upper_.name();
+ share_.name = setter_upper_.name();
}
virtual void TearDown() {
diff --git a/chrome/browser/sync/engine/syncer.cc b/chrome/browser/sync/engine/syncer.cc
index f64de42..112f474 100644
--- a/chrome/browser/sync/engine/syncer.cc
+++ b/chrome/browser/sync/engine/syncer.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/sync/engine/build_and_process_conflict_sets_command.h"
#include "chrome/browser/sync/engine/build_commit_command.h"
#include "chrome/browser/sync/engine/cleanup_disabled_types_command.h"
+#include "chrome/browser/sync/engine/clear_data_command.h"
#include "chrome/browser/sync/engine/conflict_resolver.h"
#include "chrome/browser/sync/engine/download_updates_command.h"
#include "chrome/browser/sync/engine/get_commit_ids_command.h"
@@ -74,6 +75,16 @@ Syncer::~Syncer() {
shutdown_channel_->Notify(SyncerShutdownEvent(this));
}
+bool Syncer::ExitRequested() {
+ AutoLock lock(early_exit_requested_lock_);
+ return early_exit_requested_;
+}
+
+void Syncer::RequestEarlyExit() {
+ AutoLock lock(early_exit_requested_lock_);
+ early_exit_requested_ = true;
+}
+
void Syncer::RequestNudge(int milliseconds) {
SyncerEvent event(SyncerEvent::REQUEST_SYNC_NUDGE);
event.nudge_delay_milliseconds = milliseconds;
@@ -86,20 +97,27 @@ bool Syncer::SyncShare(sessions::SyncSession::Delegate* delegate) {
}
bool Syncer::SyncShare(sessions::SyncSession* session) {
- session->set_source(TestAndSetUpdatesSource());
- // This isn't perfect, as we can end up bundling extensions activity
- // intended for the next session into the current one. We could do a
- // test-and-reset as with the source, but note that also falls short if
- // the commit request fails (due to lost connection, for example), as we will
- // fall all the way back to the syncer thread main loop in that case, and
- // wind up creating a new session when a connection is established, losing
- // the records set here on the original attempt. This should provide us
- // with the right data "most of the time", and we're only using this for
- // analysis purposes, so Law of Large Numbers FTW.
- context_->extensions_monitor()->GetAndClearRecords(
- session->mutable_extensions_activity());
- SyncShare(session, SYNCER_BEGIN, SYNCER_END);
- return session->HasMoreToSync();
+ sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source =
+ TestAndSetUpdatesSource();
+ session->set_source(source);
+ if (sync_pb::GetUpdatesCallerInfo::CLEAR_PRIVATE_DATA == source) {
+ SyncShare(session, CLEAR_PRIVATE_DATA, SYNCER_END);
+ return false;
+ } else {
+ // This isn't perfect, as we can end up bundling extensions activity
+ // intended for the next session into the current one. We could do a
+ // test-and-reset as with the source, but note that also falls short if
+ // the commit request fails (e.g. due to lost connection), as we will
+ // fall all the way back to the syncer thread main loop in that case, and
+ // wind up creating a new session when a connection is established, losing
+ // the records set here on the original attempt. This should provide us
+ // with the right data "most of the time", and we're only using this for
+ // analysis purposes, so Law of Large Numbers FTW.
+ context_->extensions_monitor()->GetAndClearRecords(
+ session->mutable_extensions_activity());
+ SyncShare(session, SYNCER_BEGIN, SYNCER_END);
+ return session->HasMoreToSync();
+ }
}
bool Syncer::SyncShare(SyncerStep first_step, SyncerStep last_step,
@@ -266,6 +284,12 @@ void Syncer::SyncShare(sessions::SyncSession* session,
next_step = SYNCER_END;
break;
}
+ case CLEAR_PRIVATE_DATA: {
+ LOG(INFO) << "Clear Private Data";
+ ClearDataCommand clear_data_command;
+ clear_data_command.Execute(session);
+ next_step = SYNCER_END;
+ }
case SYNCER_END: {
LOG(INFO) << "Syncer End";
SyncerEndCommand syncer_end_command;
diff --git a/chrome/browser/sync/engine/syncer.h b/chrome/browser/sync/engine/syncer.h
index 5ad6ded..9a07400 100644
--- a/chrome/browser/sync/engine/syncer.h
+++ b/chrome/browser/sync/engine/syncer.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
+#pragma once
-#include <string>
#include <utility>
#include <vector>
@@ -57,6 +57,7 @@ enum SyncerStep {
BUILD_AND_PROCESS_CONFLICT_SETS,
RESOLVE_CONFLICTS,
APPLY_UPDATES_TO_RESOLVE_CONFLICTS,
+ CLEAR_PRIVATE_DATA,
SYNCER_END
};
@@ -81,14 +82,8 @@ class Syncer {
// Called by other threads to tell the syncer to stop what it's doing
// and return early from SyncShare, if possible.
- bool ExitRequested() {
- AutoLock lock(early_exit_requested_lock_);
- return early_exit_requested_;
- }
- void RequestEarlyExit() {
- AutoLock lock(early_exit_requested_lock_);
- early_exit_requested_ = true;
- }
+ bool ExitRequested();
+ void RequestEarlyExit();
// SyncShare(...) variants cause one sync cycle to occur. The return value
// indicates whether we should sync again. If we should not sync again,
diff --git a/chrome/browser/sync/engine/syncer_command.cc b/chrome/browser/sync/engine/syncer_command.cc
index f95cf40..4e13918 100644
--- a/chrome/browser/sync/engine/syncer_command.cc
+++ b/chrome/browser/sync/engine/syncer_command.cc
@@ -7,7 +7,6 @@
#include "chrome/browser/sync/engine/net/server_connection_manager.h"
#include "chrome/browser/sync/sessions/sync_session.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
-#include "chrome/browser/sync/util/sync_types.h"
#include "chrome/common/deprecated/event_sys-inl.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/engine/syncer_command.h b/chrome/browser/sync/engine/syncer_command.h
index 5c38788..2aad653 100644
--- a/chrome/browser/sync/engine/syncer_command.h
+++ b/chrome/browser/sync/engine/syncer_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_COMMAND_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/sync/engine/syncer_end_command.cc b/chrome/browser/sync/engine/syncer_end_command.cc
index 7756d7a..0b8792d 100644
--- a/chrome/browser/sync/engine/syncer_end_command.cc
+++ b/chrome/browser/sync/engine/syncer_end_command.cc
@@ -19,6 +19,7 @@ void SyncerEndCommand::ExecuteImpl(sessions::SyncSession* session) {
status->set_syncing(false);
session->context()->set_previous_session_routing_info(
session->routing_info());
+ session->context()->set_last_snapshot(session->TakeSnapshot());
// This might be the first time we've fully completed a sync cycle, for
// some subset of the currently synced datatypes.
diff --git a/chrome/browser/sync/engine/syncer_end_command.h b/chrome/browser/sync/engine/syncer_end_command.h
index e26db5f..c4fbd85 100644
--- a/chrome/browser/sync/engine/syncer_end_command.h
+++ b/chrome/browser/sync/engine/syncer_end_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_END_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_END_COMMAND_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/syncer_command.h"
diff --git a/chrome/browser/sync/engine/syncer_proto_util.cc b/chrome/browser/sync/engine/syncer_proto_util.cc
index 17de218..2cc2300 100644
--- a/chrome/browser/sync/engine/syncer_proto_util.cc
+++ b/chrome/browser/sync/engine/syncer_proto_util.cc
@@ -6,9 +6,9 @@
#include "base/format_macros.h"
#include "base/string_util.h"
-#include "chrome/browser/sync/engine/auth_watcher.h"
#include "chrome/browser/sync/engine/net/server_connection_manager.h"
#include "chrome/browser/sync/engine/syncer.h"
+#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/protocol/service_constants.h"
#include "chrome/browser/sync/sessions/sync_session.h"
@@ -124,7 +124,7 @@ void SyncerProtoUtil::AddRequestBirthday(syncable::Directory* dir,
// static
bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm,
- AuthWatcher* auth_watcher,
+ sessions::SyncSession* session,
const ClientToServerMessage& msg,
ClientToServerResponse* response) {
@@ -144,12 +144,9 @@ bool SyncerProtoUtil::PostAndProcessHeaders(ServerConnectionManager* scm,
std::string new_token =
http_response.update_client_auth_header;
if (!new_token.empty()) {
- // We could also do this in the SCM's PostBufferWithAuth.
- // But then we could be in the middle of authentication, which seems
- // like a bad time to update the token. A consequence of this is that
- // we can't reset the cookie in response to auth attempts, but this
- // should be OK.
- auth_watcher->RenewAuthToken(new_token);
+ SyncerEvent event(SyncerEvent::UPDATED_TOKEN);
+ event.updated_token = new_token;
+ session->context()->syncer_event_channel()->Notify(event);
}
if (response->ParseFromString(rx)) {
@@ -189,7 +186,7 @@ bool SyncerProtoUtil::PostClientToServerMessage(
}
if (!PostAndProcessHeaders(session->context()->connection_manager(),
- session->context()->auth_watcher(),
+ session,
msg,
response)) {
return false;
diff --git a/chrome/browser/sync/engine/syncer_proto_util.h b/chrome/browser/sync/engine/syncer_proto_util.h
index ae668ed..ca68ec3 100644
--- a/chrome/browser/sync/engine/syncer_proto_util.h
+++ b/chrome/browser/sync/engine/syncer_proto_util.h
@@ -4,13 +4,13 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_PROTO_UTIL_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_PROTO_UTIL_H_
+#pragma once
#include <string>
#include "base/gtest_prod_util.h"
#include "chrome/browser/sync/syncable/blob.h"
#include "chrome/browser/sync/syncable/model_type.h"
-#include "chrome/browser/sync/util/sync_types.h"
namespace syncable {
class Directory;
@@ -105,7 +105,7 @@ class SyncerProtoUtil {
// Post the message using the scm, and do some processing on the returned
// headers. Decode the server response.
static bool PostAndProcessHeaders(browser_sync::ServerConnectionManager* scm,
- browser_sync::AuthWatcher* authwatcher,
+ sessions::SyncSession* session,
const ClientToServerMessage& msg,
sync_pb::ClientToServerResponse* response);
diff --git a/chrome/browser/sync/engine/syncer_proto_util_unittest.cc b/chrome/browser/sync/engine/syncer_proto_util_unittest.cc
index e6eb68b..57cae0a 100644
--- a/chrome/browser/sync/engine/syncer_proto_util_unittest.cc
+++ b/chrome/browser/sync/engine/syncer_proto_util_unittest.cc
@@ -182,7 +182,7 @@ TEST_F(SyncerProtoUtilTest, AddRequestBirthday) {
class DummyConnectionManager : public browser_sync::ServerConnectionManager {
public:
DummyConnectionManager()
- : ServerConnectionManager("unused", 0, false, "version", "id"),
+ : ServerConnectionManager("unused", 0, false, "version"),
send_error_(false),
access_denied_(false) {}
diff --git a/chrome/browser/sync/engine/syncer_thread.cc b/chrome/browser/sync/engine/syncer_thread.cc
index ffc7bcd..92322b4 100644
--- a/chrome/browser/sync/engine/syncer_thread.cc
+++ b/chrome/browser/sync/engine/syncer_thread.cc
@@ -15,12 +15,12 @@
#include <map>
#include <queue>
+#include "base/rand_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "chrome/browser/sync/engine/auth_watcher.h"
#include "chrome/browser/sync/engine/model_safe_worker.h"
#include "chrome/browser/sync/engine/net/server_connection_manager.h"
#include "chrome/browser/sync/engine/syncer.h"
-#include "chrome/browser/sync/syncable/directory_manager.h"
+#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/common/chrome_switches.h"
#include "jingle/notifier/listener/notification_constants.h"
@@ -30,9 +30,10 @@ using base::Time;
using base::TimeDelta;
using base::TimeTicks;
-
namespace browser_sync {
+using sessions::SyncSessionSnapshot;
+
// We use high values here to ensure that failure to receive poll updates from
// the server doesn't result in rapid-fire polling from the client due to low
// local limits.
@@ -47,6 +48,11 @@ const int SyncerThread::kDefaultLongPollIntervalSeconds = 3600 * 12;
// is really something we want and make sure it works, if it is.
const int SyncerThread::kDefaultMaxPollIntervalMs = 30 * 60 * 1000;
+// Backoff interval randomization factor.
+static const int kBackoffRandomizationFactor = 2;
+
+const int SyncerThread::kMaxBackoffSeconds = 60 * 60 * 4; // 4 hours.
+
void SyncerThread::NudgeSyncer(int milliseconds_from_now, NudgeSource source) {
AutoLock lock(lock_);
if (vault_.syncer_ == NULL) {
@@ -56,32 +62,23 @@ void SyncerThread::NudgeSyncer(int milliseconds_from_now, NudgeSource source) {
NudgeSyncImpl(milliseconds_from_now, source);
}
-SyncerThread::SyncerThread(sessions::SyncSessionContext* context,
- AllStatus* all_status)
+SyncerThread::SyncerThread(sessions::SyncSessionContext* context)
: thread_main_started_(false, false),
thread_("SyncEngine_SyncerThread"),
vault_field_changed_(&lock_),
p2p_authenticated_(false),
p2p_subscribed_(false),
conn_mgr_hookup_(NULL),
- allstatus_(all_status),
syncer_short_poll_interval_seconds_(kDefaultShortPollIntervalSeconds),
syncer_long_poll_interval_seconds_(kDefaultLongPollIntervalSeconds),
syncer_polling_interval_(kDefaultShortPollIntervalSeconds),
syncer_max_interval_(kDefaultMaxPollIntervalMs),
- directory_manager_hookup_(NULL),
syncer_events_(NULL),
session_context_(context),
disable_idle_detection_(false) {
DCHECK(context);
syncer_event_relay_channel_.reset(new SyncerEventChannel());
- if (context->directory_manager()) {
- directory_manager_hookup_.reset(NewEventListenerHookup(
- context->directory_manager()->channel(), this,
- &SyncerThread::HandleDirectoryManagerEvent));
- }
-
if (context->connection_manager())
WatchConnectionManager(context->connection_manager());
@@ -92,7 +89,6 @@ SyncerThread::~SyncerThread() {
syncer_event_relay_channel_->Notify(SyncerEvent(
SyncerEvent::SHUTDOWN_USE_WITH_CARE));
syncer_event_relay_channel_.reset();
- directory_manager_hookup_.reset();
syncer_events_.reset();
delete vault_.syncer_;
CHECK(!thread_.IsRunning());
@@ -298,10 +294,10 @@ void SyncerThread::ThreadMainLoop() {
WaitInterval::THROTTLED;
// If we are throttled, we must wait. Otherwise, wait until either the next
// nudge (if one exists) or the poll interval.
- const TimeTicks end_wait = throttled ? next_poll :
- !vault_.nudge_queue_.empty() &&
- vault_.nudge_queue_.top().first < next_poll ?
- vault_.nudge_queue_.top().first : next_poll;
+ TimeTicks end_wait = next_poll;
+ if (!throttled && !vault_.pending_nudge_time_.is_null()) {
+ end_wait = std::min(end_wait, vault_.pending_nudge_time_);
+ }
LOG(INFO) << "end_wait is " << end_wait.ToInternalValue();
LOG(INFO) << "next_poll is " << next_poll.ToInternalValue();
@@ -336,7 +332,6 @@ void SyncerThread::ThreadMainLoop() {
LOG(INFO) << "Updating the next polling time after SyncMain";
vault_.current_wait_interval_ = CalculatePollingWaitTime(
- allstatus_->status(),
static_cast<int>(vault_.current_wait_interval_.poll_delta.InSeconds()),
&user_idle_milliseconds, &continue_sync_cycle, nudged);
}
@@ -415,9 +410,7 @@ void SyncerThread::ExitPausedState() {
// 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.
-// TODO(timsteele): Should use Time(Delta).
SyncerThread::WaitInterval SyncerThread::CalculatePollingWaitTime(
- const AllStatus::Status& status,
int last_poll_wait, // Time in seconds.
int* user_idle_milliseconds,
bool* continue_sync_cycle,
@@ -436,15 +429,16 @@ SyncerThread::WaitInterval SyncerThread::CalculatePollingWaitTime(
bool is_continuing_sync_cyle = *continue_sync_cycle;
*continue_sync_cycle = false;
- // Determine if the syncer has unfinished work to do from allstatus_.
- const bool syncer_has_work_to_do =
- status.updates_available > status.updates_received
- || status.unsynced_count > 0;
+ // Determine if the syncer has unfinished work to do.
+ SyncSessionSnapshot* snapshot = session_context_->previous_session_snapshot();
+ const bool syncer_has_work_to_do = snapshot &&
+ (snapshot->num_server_changes_remaining > snapshot->max_local_timestamp
+ || snapshot->unsynced_count > 0);
LOG(INFO) << "syncer_has_work_to_do is " << syncer_has_work_to_do;
// First calculate the expected wait time, figuring in any backoff because of
// user idle time. next_wait is in seconds
- syncer_polling_interval_ = (!status.notifications_enabled) ?
+ syncer_polling_interval_ = (!session_context_->notifications_enabled()) ?
syncer_short_poll_interval_seconds_ :
syncer_long_poll_interval_seconds_;
int default_next_wait = syncer_polling_interval_;
@@ -464,15 +458,15 @@ SyncerThread::WaitInterval SyncerThread::CalculatePollingWaitTime(
} else {
// We weren't nudged, or we were in a NORMAL wait interval until now.
return_interval.poll_delta = TimeDelta::FromSeconds(
- AllStatus::GetRecommendedDelaySeconds(last_poll_wait));
+ GetRecommendedDelaySeconds(last_poll_wait));
}
} else {
// No consecutive error.
return_interval.poll_delta = TimeDelta::FromSeconds(
- AllStatus::GetRecommendedDelaySeconds(0));
+ GetRecommendedDelaySeconds(0));
}
*continue_sync_cycle = true;
- } else if (!status.notifications_enabled) {
+ } else if (!session_context_->notifications_enabled()) {
// Ensure that we start exponential backoff from our base polling
// interval when we are not continuing a sync cycle.
last_poll_wait = std::max(last_poll_wait, syncer_polling_interval_);
@@ -533,13 +527,17 @@ bool SyncerThread::UpdateNudgeSource(bool was_throttled,
}
// Update the nudge source if a new nudge has come through during the
// previous sync cycle.
- while (!vault_.nudge_queue_.empty() &&
- TimeTicks::Now() >= vault_.nudge_queue_.top().first) {
+ if (!vault_.pending_nudge_time_.is_null()) {
if (!was_throttled && !nudged) {
- nudge_source = vault_.nudge_queue_.top().second;
+ nudge_source = vault_.pending_nudge_source_;
nudged = true;
}
- vault_.nudge_queue_.pop();
+ LOG(INFO) << "Clearing pending nudge from "
+ << vault_.pending_nudge_source_
+ << " at tick "
+ << vault_.pending_nudge_time_.ToInternalValue();
+ vault_.pending_nudge_source_ = kUnknown;
+ vault_.pending_nudge_time_ = base::TimeTicks();
}
SetUpdatesSource(nudged, nudge_source, initial_sync);
return nudged;
@@ -565,6 +563,9 @@ void SyncerThread::SetUpdatesSource(bool nudged, NudgeSource nudge_source,
case kContinuation:
updates_source = sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION;
break;
+ case kClearPrivateData:
+ updates_source = sync_pb::GetUpdatesCallerInfo::CLEAR_PRIVATE_DATA;
+ break;
case kUnknown:
default:
updates_source = sync_pb::GetUpdatesCallerInfo::UNKNOWN;
@@ -583,22 +584,18 @@ void SyncerThread::HandleChannelEvent(const SyncerEvent& event) {
NudgeSyncImpl(event.nudge_delay_milliseconds, kUnknown);
}
-void SyncerThread::HandleDirectoryManagerEvent(
- const syncable::DirectoryManagerEvent& event) {
- LOG(INFO) << "Handling a directory manager event";
- if (syncable::DirectoryManagerEvent::OPENED == event.what_happened) {
- AutoLock lock(lock_);
- LOG(INFO) << "Syncer starting up for: " << event.dirname;
- // The underlying database structure is ready, and we should create
- // the syncer.
- CHECK(vault_.syncer_ == NULL);
- session_context_->set_account_name(event.dirname);
- vault_.syncer_ = new Syncer(session_context_.get());
-
- syncer_events_.reset(
- session_context_->syncer_event_channel()->AddObserver(this));
- vault_field_changed_.Broadcast();
- }
+void SyncerThread::CreateSyncer(const std::string& dirname) {
+ AutoLock lock(lock_);
+ LOG(INFO) << "Creating syncer up for: " << dirname;
+ // The underlying database structure is ready, and we should create
+ // the syncer.
+ CHECK(vault_.syncer_ == NULL);
+ session_context_->set_account_name(dirname);
+ vault_.syncer_ = new Syncer(session_context_.get());
+
+ syncer_events_.reset(
+ session_context_->syncer_event_channel()->AddObserver(this));
+ vault_field_changed_.Broadcast();
}
// Sets |*connected| to false if it is currently true but |code| suggests that
@@ -650,6 +647,27 @@ SyncerEventChannel* SyncerThread::relay_channel() {
return syncer_event_relay_channel_.get();
}
+int SyncerThread::GetRecommendedDelaySeconds(int base_delay_seconds) {
+ if (base_delay_seconds >= kMaxBackoffSeconds)
+ return kMaxBackoffSeconds;
+
+ // This calculates approx. base_delay_seconds * 2 +/- base_delay_seconds / 2
+ int backoff_s =
+ std::max(1, base_delay_seconds * kBackoffRandomizationFactor);
+
+ // Flip a coin to randomize backoff interval by +/- 50%.
+ int rand_sign = base::RandInt(0, 1) * 2 - 1;
+
+ // Truncation is adequate for rounding here.
+ backoff_s = backoff_s +
+ (rand_sign * (base_delay_seconds / kBackoffRandomizationFactor));
+
+ // Cap the backoff interval.
+ backoff_s = std::max(1, std::min(backoff_s, kMaxBackoffSeconds));
+
+ return backoff_s;
+}
+
// Inputs and return value in milliseconds.
int SyncerThread::CalculateSyncWaitTime(int last_interval, int user_idle_ms) {
// syncer_polling_interval_ is in seconds
@@ -664,7 +682,7 @@ int SyncerThread::CalculateSyncWaitTime(int last_interval, int user_idle_ms) {
// If the user has been idle for a while, we'll start decreasing the poll
// rate.
if (idle >= kPollBackoffThresholdMultiplier * syncer_polling_interval_ms) {
- next_wait = std::min(AllStatus::GetRecommendedDelaySeconds(
+ next_wait = std::min(GetRecommendedDelaySeconds(
last_interval / 1000), syncer_max_interval_ / 1000) * 1000;
}
@@ -686,8 +704,16 @@ void SyncerThread::NudgeSyncImpl(int milliseconds_from_now,
const TimeTicks nudge_time = TimeTicks::Now() +
TimeDelta::FromMilliseconds(milliseconds_from_now);
- NudgeObject nudge_object(nudge_time, source);
- vault_.nudge_queue_.push(nudge_object);
+ if (nudge_time <= vault_.pending_nudge_time_) {
+ LOG(INFO) << "Nudge for source " << source
+ << " dropped due to existing later pending nudge";
+ return;
+ }
+
+ LOG(INFO) << "Replacing pending nudge for source "
+ << source << " at " << nudge_time.ToInternalValue();
+ vault_.pending_nudge_source_ = source;
+ vault_.pending_nudge_time_ = nudge_time;
vault_field_changed_.Broadcast();
}
diff --git a/chrome/browser/sync/engine/syncer_thread.h b/chrome/browser/sync/engine/syncer_thread.h
index a54ff7f..3bf96c3 100644
--- a/chrome/browser/sync/engine/syncer_thread.h
+++ b/chrome/browser/sync/engine/syncer_thread.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.
//
@@ -7,10 +7,9 @@
// does not support a timeout, but is greatly simplified.
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_THREAD_H_
+#pragma once
#include <list>
-#include <map>
-#include <queue>
#include <vector>
#include "base/basictypes.h"
@@ -21,7 +20,6 @@
#include "base/thread.h"
#include "base/time.h"
#include "base/waitable_event.h"
-#include "chrome/browser/sync/engine/all_status.h"
#if defined(OS_LINUX)
#include "chrome/browser/sync/engine/idle_query_linux.h"
#endif
@@ -30,11 +28,6 @@
class EventListenerHookup;
-namespace syncable {
-class DirectoryManager;
-struct DirectoryManagerEvent;
-}
-
namespace browser_sync {
class ModelSafeWorker;
@@ -92,7 +85,8 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
kUnknown = 0,
kNotification,
kLocal,
- kContinuation
+ kContinuation,
+ kClearPrivateData
};
// Server can overwrite these values via client commands.
// Standard short poll. This is used when XMPP is off.
@@ -102,8 +96,10 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
// 30 minutes by default. If exponential backoff kicks in, this is the
// longest possible poll interval.
static const int kDefaultMaxPollIntervalMs;
+ // Maximum interval for exponential backoff.
+ static const int kMaxBackoffSeconds;
- SyncerThread(sessions::SyncSessionContext* context, AllStatus* all_status);
+ explicit SyncerThread(sessions::SyncSessionContext* context);
virtual ~SyncerThread();
virtual void WatchConnectionManager(ServerConnectionManager* conn_mgr);
@@ -137,6 +133,12 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
virtual SyncerEventChannel* relay_channel();
+ // Call this when a directory is opened
+ void CreateSyncer(const std::string& dirname);
+
+ // DDOS avoidance function. The argument and return value is in seconds
+ static int GetRecommendedDelaySeconds(int base_delay_seconds);
+
protected:
virtual void ThreadMain();
void ThreadMainLoop();
@@ -166,17 +168,6 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
// Handle of the running thread.
base::Thread thread_;
- typedef std::pair<base::TimeTicks, NudgeSource> NudgeObject;
-
- struct IsTimeTicksGreater {
- inline bool operator() (const NudgeObject& lhs, const NudgeObject& rhs) {
- return lhs.first > rhs.first;
- }
- };
-
- typedef std::priority_queue<NudgeObject, std::vector<NudgeObject>,
- IsTimeTicksGreater> NudgeQueue;
-
// Fields that are modified / accessed by multiple threads go in this struct
// for clarity and explicitness.
struct ProtectedFields {
@@ -194,9 +185,12 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
// State of the server connection.
bool connected_;
- // A queue of all scheduled nudges. One insertion for every call to
- // NudgeQueue().
- NudgeQueue nudge_queue_;
+ // kUnknown if there is no pending nudge. (Theoretically, there
+ // could be a pending nudge of type kUnknown, so it's better to
+ // check pending_nudge_time_.)
+ NudgeSource pending_nudge_source_;
+ // null iff there is no pending nudge.
+ base::TimeTicks pending_nudge_time_;
// The wait interval for to the current iteration of our main loop. This is
// only written to by the syncer thread, and since the only reader from a
@@ -210,7 +204,8 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
pause_requested_(false),
paused_(false),
syncer_(NULL),
- connected_(false) {}
+ connected_(false),
+ pending_nudge_source_(kUnknown) {}
} vault_;
// Gets signaled whenever a thread outside of the syncer thread changes a
@@ -226,8 +221,6 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
friend void* RunSyncerThread(void* syncer_thread);
void* Run();
- void HandleDirectoryManagerEvent(
- const syncable::DirectoryManagerEvent& event);
void HandleChannelEvent(const SyncerEvent& event);
// SyncSession::Delegate implementation.
@@ -253,7 +246,6 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
// in case of exponential backoff so we only allow one nudge per backoff
// interval.
WaitInterval CalculatePollingWaitTime(
- const AllStatus::Status& status,
int last_poll_wait, // in s
int* user_idle_milliseconds,
bool* continue_sync_cycle,
@@ -300,7 +292,6 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
bool p2p_subscribed_;
scoped_ptr<EventListenerHookup> conn_mgr_hookup_;
- const AllStatus* allstatus_;
// Modifiable versions of kDefaultLongPollIntervalSeconds which can be
// updated by the server.
@@ -321,7 +312,6 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
// this is called.
void NudgeSyncImpl(int milliseconds_from_now, NudgeSource source);
- scoped_ptr<EventListenerHookup> directory_manager_hookup_;
scoped_ptr<ChannelHookup<SyncerEvent> > syncer_events_;
#if defined(OS_LINUX)
diff --git a/chrome/browser/sync/engine/syncer_thread_unittest.cc b/chrome/browser/sync/engine/syncer_thread_unittest.cc
index 6ce377e..ded07f0 100644
--- a/chrome/browser/sync/engine/syncer_thread_unittest.cc
+++ b/chrome/browser/sync/engine/syncer_thread_unittest.cc
@@ -28,7 +28,10 @@ using testing::AnyNumber;
using testing::Field;
namespace browser_sync {
+using sessions::ErrorCounters;
using sessions::SyncSessionContext;
+using sessions::SyncSessionSnapshot;
+using sessions::SyncerStatus;
typedef testing::Test SyncerThreadTest;
typedef SyncerThread::WaitInterval WaitInterval;
@@ -37,6 +40,14 @@ ACTION_P(SignalEvent, event) {
event->Signal();
}
+SyncSessionSnapshot SessionSnapshotForTest(
+ int64 num_server_changes_remaining, int64 max_local_timestamp,
+ int64 unsynced_count) {
+ return SyncSessionSnapshot(SyncerStatus(), ErrorCounters(),
+ num_server_changes_remaining, max_local_timestamp, false,
+ syncable::ModelTypeBitSet(), false, false, unsynced_count, 0, false);
+}
+
class ListenerMock : public ChannelEventHandler<SyncerEvent> {
public:
MOCK_METHOD1(HandleChannelEvent, void(const SyncerEvent&));
@@ -53,14 +64,12 @@ class SyncerThreadWithSyncerTest : public testing::Test,
metadb_.SetUp();
connection_.reset(new MockConnectionManager(metadb_.manager(),
metadb_.name()));
- allstatus_.reset(new AllStatus());
worker_ = new ModelSafeWorker();
SyncSessionContext* context = new SyncSessionContext(connection_.get(),
- NULL, metadb_.manager(), this);
- syncer_thread_ = new SyncerThread(context, allstatus_.get());
+ metadb_.manager(), this);
+ syncer_thread_ = new SyncerThread(context);
syncer_event_hookup_.reset(
syncer_thread_->relay_channel()->AddObserver(this));
- allstatus_->WatchSyncerThread(syncer_thread_);
syncer_thread_->SetConnected(true);
syncable::ModelTypeBitSet expected_types;
expected_types[syncable::BOOKMARKS] = true;
@@ -68,7 +77,6 @@ class SyncerThreadWithSyncerTest : public testing::Test,
}
virtual void TearDown() {
syncer_event_hookup_.reset();
- allstatus_.reset();
syncer_thread_ = NULL;
connection_.reset();
metadb_.TearDown();
@@ -159,7 +167,6 @@ class SyncerThreadWithSyncerTest : public testing::Test,
private:
ManuallyOpenedTestDirectorySetterUpper metadb_;
scoped_ptr<MockConnectionManager> connection_;
- scoped_ptr<AllStatus> allstatus_;
scoped_refptr<SyncerThread> syncer_thread_;
scoped_refptr<ModelSafeWorker> worker_;
scoped_ptr<ChannelHookup<SyncerEvent> > syncer_event_hookup_;
@@ -210,13 +217,13 @@ class SyncShareIntercept
};
TEST_F(SyncerThreadTest, Construction) {
- SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL);
- scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context, NULL));
+ SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL);
+ scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context));
}
TEST_F(SyncerThreadTest, StartStop) {
- SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL);
- scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context, NULL));
+ SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL);
+ scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context));
EXPECT_TRUE(syncer_thread->Start());
EXPECT_TRUE(syncer_thread->Stop(2000));
@@ -226,9 +233,22 @@ TEST_F(SyncerThreadTest, StartStop) {
EXPECT_TRUE(syncer_thread->Stop(2000));
}
+TEST(SyncerThread, GetRecommendedDelay) {
+ EXPECT_LE(0, SyncerThread::GetRecommendedDelaySeconds(0));
+ EXPECT_LE(1, SyncerThread::GetRecommendedDelaySeconds(1));
+ EXPECT_LE(50, SyncerThread::GetRecommendedDelaySeconds(50));
+ EXPECT_LE(10, SyncerThread::GetRecommendedDelaySeconds(10));
+ EXPECT_EQ(SyncerThread::kMaxBackoffSeconds,
+ SyncerThread::GetRecommendedDelaySeconds(
+ SyncerThread::kMaxBackoffSeconds));
+ EXPECT_EQ(SyncerThread::kMaxBackoffSeconds,
+ SyncerThread::GetRecommendedDelaySeconds(
+ SyncerThread::kMaxBackoffSeconds+1));
+}
+
TEST_F(SyncerThreadTest, CalculateSyncWaitTime) {
- SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL);
- scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context, NULL));
+ SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL);
+ scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context));
syncer_thread->DisableIdleDetection();
// Syncer_polling_interval_ is less than max poll interval.
@@ -287,8 +307,8 @@ TEST_F(SyncerThreadTest, CalculateSyncWaitTime) {
TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// Set up the environment.
int user_idle_milliseconds_param = 0;
- SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL, NULL);
- scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context, NULL));
+ SyncSessionContext* context = new SyncSessionContext(NULL, NULL, NULL);
+ scoped_refptr<SyncerThread> syncer_thread(new SyncerThread(context));
syncer_thread->DisableIdleDetection();
// Hold the lock to appease asserts in code.
AutoLock lock(syncer_thread->lock_);
@@ -296,13 +316,11 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// Notifications disabled should result in a polling interval of
// kDefaultShortPollInterval.
{
- AllStatus::Status status = {};
- status.notifications_enabled = 0;
+ context->set_notifications_enabled(false);
bool continue_sync_cycle_param = false;
// No work and no backoff.
WaitInterval interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -317,7 +335,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// In this case the continue_sync_cycle is turned off.
continue_sync_cycle_param = true;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -333,13 +350,11 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// Notifications enabled should result in a polling interval of
// SyncerThread::kDefaultLongPollIntervalSeconds.
{
- AllStatus::Status status = {};
- status.notifications_enabled = 1;
+ context->set_notifications_enabled(true);
bool continue_sync_cycle_param = false;
// No work and no backoff.
WaitInterval interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -354,7 +369,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// In this case the continue_sync_cycle is turned off.
continue_sync_cycle_param = true;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -371,13 +385,11 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// available do not match the updates received, or the unsynced count is
// non-zero.
{
- AllStatus::Status status = {};
- status.updates_available = 1;
- status.updates_received = 0;
+ // More server changes remaining to download.
+ context->set_last_snapshot(SessionSnapshotForTest(1, 0, 0));
bool continue_sync_cycle_param = false;
WaitInterval interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -390,7 +402,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
continue_sync_cycle_param = false;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -402,7 +413,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
ASSERT_TRUE(continue_sync_cycle_param);
interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -413,7 +423,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
ASSERT_FALSE(interval.had_nudge_during_backoff);
interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -424,15 +433,15 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
ASSERT_FALSE(interval.had_nudge_during_backoff);
ASSERT_TRUE(continue_sync_cycle_param);
- status.updates_received = 1;
+ // Now simulate no more server changes remaining.
+ context->set_last_snapshot(SessionSnapshotForTest(1, 1, 0));
interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
false);
- ASSERT_EQ(SyncerThread::kDefaultShortPollIntervalSeconds,
+ ASSERT_EQ(SyncerThread::kDefaultLongPollIntervalSeconds,
interval.poll_delta.InSeconds());
ASSERT_EQ(WaitInterval::NORMAL, interval.mode);
ASSERT_FALSE(interval.had_nudge_during_backoff);
@@ -440,12 +449,12 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
}
{
- AllStatus::Status status = {};
- status.unsynced_count = 1;
+
+ // Now try with unsynced local items.
+ context->set_last_snapshot(SessionSnapshotForTest(0, 0, 1));
bool continue_sync_cycle_param = false;
WaitInterval interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -458,7 +467,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
continue_sync_cycle_param = false;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
0,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -469,15 +477,14 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
ASSERT_FALSE(interval.had_nudge_during_backoff);
ASSERT_TRUE(continue_sync_cycle_param);
- status.unsynced_count = 0;
+ context->set_last_snapshot(SessionSnapshotForTest(0, 0, 0));
interval = syncer_thread->CalculatePollingWaitTime(
- status,
4,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
false);
- ASSERT_EQ(SyncerThread::kDefaultShortPollIntervalSeconds,
+ ASSERT_EQ(SyncerThread::kDefaultLongPollIntervalSeconds,
interval.poll_delta.InSeconds());
ASSERT_EQ(WaitInterval::NORMAL, interval.mode);
ASSERT_FALSE(interval.had_nudge_during_backoff);
@@ -486,14 +493,13 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// Regression for exponential backoff reset when the syncer is nudged.
{
- AllStatus::Status status = {};
- status.unsynced_count = 1;
+
+ context->set_last_snapshot(SessionSnapshotForTest(0, 0, 1));
bool continue_sync_cycle_param = false;
// Expect move from default polling interval to exponential backoff due to
// unsynced_count != 0.
WaitInterval interval = syncer_thread->CalculatePollingWaitTime(
- status,
3600,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -506,7 +512,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
continue_sync_cycle_param = false;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
3600,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -519,7 +524,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// Expect exponential backoff.
interval = syncer_thread->CalculatePollingWaitTime(
- status,
2,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -531,7 +535,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
ASSERT_TRUE(continue_sync_cycle_param);
interval = syncer_thread->CalculatePollingWaitTime(
- status,
2,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -545,7 +548,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
syncer_thread->vault_.current_wait_interval_ = interval;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
static_cast<int>(interval.poll_delta.InSeconds()),
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -562,7 +564,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// backoff.
syncer_thread->vault_.current_wait_interval_.mode = WaitInterval::NORMAL;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
2,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -577,7 +578,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// And if another interval expires, we get a bigger backoff.
WaitInterval new_interval = syncer_thread->CalculatePollingWaitTime(
- status,
static_cast<int>(interval.poll_delta.InSeconds()),
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -593,7 +593,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
// should return to the minimum.
continue_sync_cycle_param = false;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
3600,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -606,7 +605,6 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
continue_sync_cycle_param = false;
interval = syncer_thread->CalculatePollingWaitTime(
- status,
3600,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
@@ -618,15 +616,14 @@ TEST_F(SyncerThreadTest, CalculatePollingWaitTime) {
ASSERT_TRUE(continue_sync_cycle_param);
// Setting unsynced_count = 0 returns us to the default polling interval.
- status.unsynced_count = 0;
+ context->set_last_snapshot(SessionSnapshotForTest(0, 0, 0));
interval = syncer_thread->CalculatePollingWaitTime(
- status,
4,
&user_idle_milliseconds_param,
&continue_sync_cycle_param,
true);
- ASSERT_EQ(SyncerThread::kDefaultShortPollIntervalSeconds,
+ ASSERT_EQ(SyncerThread::kDefaultLongPollIntervalSeconds,
interval.poll_delta.InSeconds());
ASSERT_EQ(WaitInterval::NORMAL, interval.mode);
ASSERT_FALSE(interval.had_nudge_during_backoff);
@@ -642,8 +639,8 @@ TEST_F(SyncerThreadWithSyncerTest, Polling) {
syncer_thread()->SetSyncerShortPollInterval(poll_interval);
EXPECT_TRUE(syncer_thread()->Start());
- // Calling Open() should cause the SyncerThread to create a Syncer.
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
TimeDelta two_polls = poll_interval + poll_interval;
// We could theoretically return immediately from the wait if the interceptor
@@ -676,6 +673,7 @@ TEST_F(SyncerThreadWithSyncerTest, Nudge) {
PreventThreadFromPolling();
EXPECT_TRUE(syncer_thread()->Start());
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
const TimeDelta poll_interval = TimeDelta::FromMinutes(5);
interceptor.WaitForSyncShare(1, poll_interval + poll_interval);
@@ -700,6 +698,7 @@ TEST_F(SyncerThreadWithSyncerTest, Throttling) {
EXPECT_TRUE(syncer_thread()->Start());
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
// Wait for some healthy syncing.
interceptor.WaitForSyncShare(4, poll_interval + poll_interval);
@@ -753,6 +752,7 @@ TEST_F(SyncerThreadWithSyncerTest, StopSyncPermanently) {
EXPECT_TRUE(syncer_thread()->Start());
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
ASSERT_TRUE(sync_cycle_ended_event.TimedWait(max_wait_time_));
connection()->set_store_birthday("NotYourLuckyDay");
@@ -768,6 +768,7 @@ TEST_F(SyncerThreadWithSyncerTest, AuthInvalid) {
syncer_thread()->SetSyncerShortPollInterval(poll_interval);
EXPECT_TRUE(syncer_thread()->Start());
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
// Wait for some healthy syncing.
interceptor.WaitForSyncShare(2, TimeDelta::FromSeconds(10));
@@ -829,6 +830,7 @@ TEST_F(SyncerThreadWithSyncerTest, FLAKY_Pause) {
Field(&SyncerEvent::what_happened, SyncerEvent::SYNCER_THREAD_EXITING)));
ASSERT_TRUE(syncer_thread()->Start());
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
ASSERT_TRUE(sync_cycle_ended_event.TimedWait(max_wait_time_));
// Request a pause.
@@ -872,6 +874,7 @@ TEST_F(SyncerThreadWithSyncerTest, StartWhenNotConnected) {
connection()->SetServerNotReachable();
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
// Syncer thread will always go through once cycle at the start,
// then it will wait for a connection.
@@ -926,6 +929,8 @@ TEST_F(SyncerThreadWithSyncerTest, DISABLED_PauseWhenNotConnected) {
Field(&SyncerEvent::what_happened, SyncerEvent::WAITING_FOR_CONNECTION))).
WillOnce(SignalEvent(&event));
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
+
ASSERT_TRUE(syncer_thread()->Start());
ASSERT_TRUE(sync_cycle_ended_event.TimedWait(max_wait_time_));
ASSERT_TRUE(event.TimedWait(max_wait_time_));
@@ -997,6 +1002,7 @@ TEST_F(SyncerThreadWithSyncerTest, PauseResumeWhenNotRunning) {
// Pause the thread then start the syncer.
ASSERT_TRUE(Pause(&listener));
metadb()->Open();
+ syncer_thread()->CreateSyncer(metadb()->name());
ASSERT_TRUE(syncer_thread()->Start());
// Resume and let the syncer cycle.
diff --git a/chrome/browser/sync/engine/syncer_types.h b/chrome/browser/sync/engine/syncer_types.h
index 734f823..7be16b0 100644
--- a/chrome/browser/sync/engine/syncer_types.h
+++ b/chrome/browser/sync/engine/syncer_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_TYPES_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_TYPES_H_
+#pragma once
#include <map>
#include <vector>
@@ -77,6 +78,8 @@ struct SyncerEvent {
STATUS_CHANGED,
+ UPDATED_TOKEN, // new token in updated_token
+
// Take care not to wait in shutdown handlers for the syncer to stop as it
// causes a race in the event system. Use SyncerShutdownEvent instead.
SHUTDOWN_USE_WITH_CARE,
@@ -114,6 +117,11 @@ struct SyncerEvent {
// data (i.e. as if the user clicked 'Stop Syncing' in the browser.
STOP_SYNCING_PERMANENTLY,
+ // These events are sent to indicate when we know the clearing of
+ // server data have failed or succeeded.
+ CLEAR_SERVER_DATA_SUCCEEDED,
+ CLEAR_SERVER_DATA_FAILED,
+
// Sent when the main syncer loop finishes.
SYNCER_THREAD_EXITING,
};
@@ -142,10 +150,13 @@ struct SyncerEvent {
// How many milliseconds later should the syncer kick in? For
// REQUEST_SYNC_NUDGE only.
int nudge_delay_milliseconds;
+
+ // Update-Client-Auth returns a new token for sync use.
+ std::string updated_token;
};
struct SyncerShutdownEvent {
- SyncerShutdownEvent(Syncer *syncer_ptr) : syncer(syncer_ptr) {}
+ explicit SyncerShutdownEvent(Syncer *syncer_ptr) : syncer(syncer_ptr) {}
Syncer* syncer;
static bool IsChannelShutdownEvent(Syncer* syncer) {
return true;
diff --git a/chrome/browser/sync/engine/syncer_unittest.cc b/chrome/browser/sync/engine/syncer_unittest.cc
index 70f25e0..74e5122 100644
--- a/chrome/browser/sync/engine/syncer_unittest.cc
+++ b/chrome/browser/sync/engine/syncer_unittest.cc
@@ -10,10 +10,9 @@
#include <set>
#include <string>
-#include "base/at_exit.h"
-
#include "base/callback.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/sync/engine/conflict_resolver.h"
#include "chrome/browser/sync/engine/get_commit_ids_command.h"
@@ -169,7 +168,7 @@ class SyncerTest : public testing::Test,
new MockConnectionManager(syncdb_.manager(), syncdb_.name()));
EnableDatatype(syncable::BOOKMARKS);
worker_ = new ModelSafeWorker();
- context_.reset(new SyncSessionContext(mock_server_.get(), NULL,
+ context_.reset(new SyncSessionContext(mock_server_.get(),
syncdb_.manager(), this));
context_->set_account_name(syncdb_.name());
ASSERT_FALSE(context_->syncer_event_channel());
@@ -4363,8 +4362,8 @@ TEST_F(SyncerTest, ClientTagClashWithinBatchOfUpdates) {
Entry tag_a(&trans, GET_BY_CLIENT_TAG, "tag a");
ASSERT_TRUE(tag_a.good());
- ASSERT_TRUE(tag_a.Get(ID).ServerKnows());
- ASSERT_TRUE(ids_.FromNumber(1) == tag_a.Get(ID));
+ EXPECT_TRUE(tag_a.Get(ID).ServerKnows());
+ EXPECT_EQ(ids_.FromNumber(1), tag_a.Get(ID));
EXPECT_FALSE(tag_a.Get(IS_DEL));
EXPECT_FALSE(tag_a.Get(IS_UNAPPLIED_UPDATE));
EXPECT_FALSE(tag_a.Get(IS_UNSYNCED));
@@ -4374,8 +4373,8 @@ TEST_F(SyncerTest, ClientTagClashWithinBatchOfUpdates) {
Entry tag_b(&trans, GET_BY_CLIENT_TAG, "tag b");
ASSERT_TRUE(tag_b.good());
- ASSERT_TRUE(tag_b.Get(ID).ServerKnows());
- ASSERT_TRUE(ids_.FromNumber(101) == tag_b.Get(ID));
+ EXPECT_TRUE(tag_b.Get(ID).ServerKnows());
+ EXPECT_EQ(ids_.FromNumber(101), tag_b.Get(ID));
EXPECT_FALSE(tag_b.Get(IS_DEL));
EXPECT_FALSE(tag_b.Get(IS_UNAPPLIED_UPDATE));
EXPECT_FALSE(tag_b.Get(IS_UNSYNCED));
@@ -4385,8 +4384,8 @@ TEST_F(SyncerTest, ClientTagClashWithinBatchOfUpdates) {
Entry tag_c(&trans, GET_BY_CLIENT_TAG, "tag c");
ASSERT_TRUE(tag_c.good());
- ASSERT_TRUE(tag_c.Get(ID).ServerKnows());
- ASSERT_TRUE(ids_.FromNumber(201) == tag_c.Get(ID));
+ EXPECT_TRUE(tag_c.Get(ID).ServerKnows());
+ EXPECT_EQ(ids_.FromNumber(201), tag_c.Get(ID));
EXPECT_FALSE(tag_c.Get(IS_DEL));
EXPECT_FALSE(tag_c.Get(IS_UNAPPLIED_UPDATE));
EXPECT_FALSE(tag_c.Get(IS_UNSYNCED));
@@ -4982,7 +4981,7 @@ class SyncerPositionUpdateTest : public SyncerTest {
}
void AddRootItemWithPosition(int64 position) {
- string id = string("ServerId") + Int64ToString(next_update_id_++);
+ string id = string("ServerId") + base::Int64ToString(next_update_id_++);
string name = "my name is my id -- " + id;
int revision = next_revision_++;
mock_server_->AddUpdateDirectory(id, kRootId, name, revision, revision);
diff --git a/chrome/browser/sync/engine/syncer_util.cc b/chrome/browser/sync/engine/syncer_util.cc
index efcb8db..c2639d6 100644
--- a/chrome/browser/sync/engine/syncer_util.cc
+++ b/chrome/browser/sync/engine/syncer_util.cc
@@ -19,7 +19,6 @@
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/syncable/syncable_changes_version.h"
-#include "chrome/browser/sync/util/sync_types.h"
using syncable::BASE_VERSION;
using syncable::Blob;
diff --git a/chrome/browser/sync/engine/syncer_util.h b/chrome/browser/sync/engine/syncer_util.h
index 3ce5c1b..d840cec 100644
--- a/chrome/browser/sync/engine/syncer_util.h
+++ b/chrome/browser/sync/engine/syncer_util.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_UTIL_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_UTIL_H_
+#pragma once
#include <set>
#include <string>
@@ -17,7 +18,6 @@
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/syncable/syncable_id.h"
-#include "chrome/browser/sync/util/sync_types.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/engine/syncproto.h b/chrome/browser/sync/engine/syncproto.h
index b8f0a75..6fca8e4 100644
--- a/chrome/browser/sync/engine/syncproto.h
+++ b/chrome/browser/sync/engine/syncproto.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCPROTO_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCPROTO_H_
+#pragma once
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/protocol/password_specifics.pb.h"
@@ -83,6 +84,7 @@ typedef sync_pb::ClientToServerResponse ClientToServerResponse;
typedef sync_pb::CommitResponse CommitResponse;
typedef sync_pb::GetUpdatesResponse GetUpdatesResponse;
typedef sync_pb::GetUpdatesMessage GetUpdatesMessage;
+typedef sync_pb::ClearUserDataRequest ClearDataRequest;
} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/update_applicator.cc b/chrome/browser/sync/engine/update_applicator.cc
index a174370..f184a93 100644
--- a/chrome/browser/sync/engine/update_applicator.cc
+++ b/chrome/browser/sync/engine/update_applicator.cc
@@ -35,6 +35,9 @@ UpdateApplicator::UpdateApplicator(ConflictResolver* resolver,
successful_ids_.reserve(item_count);
}
+UpdateApplicator::~UpdateApplicator() {
+}
+
// Returns true if there's more to do.
bool UpdateApplicator::AttemptOneApplication(
syncable::WriteTransaction* trans) {
diff --git a/chrome/browser/sync/engine/update_applicator.h b/chrome/browser/sync/engine/update_applicator.h
index eb8b97c..f0c5c0b 100644
--- a/chrome/browser/sync/engine/update_applicator.h
+++ b/chrome/browser/sync/engine/update_applicator.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.
//
@@ -10,8 +10,8 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_UPDATE_APPLICATOR_H_
#define CHROME_BROWSER_SYNC_ENGINE_UPDATE_APPLICATOR_H_
+#pragma once
-#include <set>
#include <vector>
#include "base/basictypes.h"
@@ -40,6 +40,7 @@ class UpdateApplicator {
const UpdateIterator& end,
const ModelSafeRoutingInfo& routes,
ModelSafeGroup group_filter);
+ ~UpdateApplicator();
// returns true if there's more we can do.
bool AttemptOneApplication(syncable::WriteTransaction* trans);
@@ -78,6 +79,8 @@ class UpdateApplicator {
// Track the result of the various items.
std::vector<syncable::Id> conflicting_ids_;
std::vector<syncable::Id> successful_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateApplicator);
};
} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/verify_updates_command.h b/chrome/browser/sync/engine/verify_updates_command.h
index 53c79e1..fe87a3d 100644
--- a/chrome/browser/sync/engine/verify_updates_command.h
+++ b/chrome/browser/sync/engine/verify_updates_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_ENGINE_VERIFY_UPDATES_COMMAND_H_
#define CHROME_BROWSER_SYNC_ENGINE_VERIFY_UPDATES_COMMAND_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/sync/glue/autofill_change_processor.cc b/chrome/browser/sync/glue/autofill_change_processor.cc
index 149d266..aac46c0 100644
--- a/chrome/browser/sync/glue/autofill_change_processor.cc
+++ b/chrome/browser/sync/glue/autofill_change_processor.cc
@@ -78,34 +78,45 @@ void AutofillChangeProcessor::Observe(NotificationType type,
}
}
-void AutofillChangeProcessor::HandleMoveAsideIfNeeded(
- sync_api::BaseTransaction* trans, AutoFillProfile* profile,
+void AutofillChangeProcessor::ChangeProfileLabelIfAlreadyTaken(
+ sync_api::BaseTransaction* trans,
+ const string16& pre_update_label,
+ AutoFillProfile* profile,
std::string* tag) {
DCHECK_EQ(AutofillModelAssociator::ProfileLabelToTag(profile->Label()),
*tag);
sync_api::ReadNode read_node(trans);
+ if (!pre_update_label.empty() && pre_update_label == profile->Label())
+ return;
if (read_node.InitByClientTagLookup(syncable::AUTOFILL, *tag)) {
// Handle the edge case of duplicate labels.
- string16 label(AutofillModelAssociator::MakeUniqueLabel(profile->Label(),
- trans));
- if (label.empty()) {
+ string16 new_label(AutofillModelAssociator::MakeUniqueLabel(
+ profile->Label(), pre_update_label, trans));
+ if (new_label.empty()) {
error_handler()->OnUnrecoverableError(FROM_HERE,
"No unique label; can't move aside");
return;
}
- tag->assign(AutofillModelAssociator::ProfileLabelToTag(label));
+ OverrideProfileLabel(new_label, profile, tag);
+ }
+}
- profile->set_label(label);
- if (!web_database_->UpdateAutoFillProfile(*profile)) {
- std::string err = "Failed to overwrite label for node ";
- err += UTF16ToUTF8(label);
- error_handler()->OnUnrecoverableError(FROM_HERE, err);
- return;
- }
+void AutofillChangeProcessor::OverrideProfileLabel(
+ const string16& new_label,
+ AutoFillProfile* profile_to_update,
+ std::string* tag_to_update) {
+ tag_to_update->assign(AutofillModelAssociator::ProfileLabelToTag(new_label));
- // Notify the PersonalDataManager that it's out of date.
- PostOptimisticRefreshTask();
+ profile_to_update->set_label(new_label);
+ if (!web_database_->UpdateAutoFillProfile(*profile_to_update)) {
+ std::string err = "Failed to overwrite label for node ";
+ err += UTF16ToUTF8(new_label);
+ error_handler()->OnUnrecoverableError(FROM_HERE, err);
+ return;
}
+
+ // Notify the PersonalDataManager that it's out of date.
+ PostOptimisticRefreshTask();
}
void AutofillChangeProcessor::PostOptimisticRefreshTask() {
@@ -137,24 +148,24 @@ void AutofillChangeProcessor::ObserveAutofillProfileChanged(
case AutofillProfileChange::ADD: {
scoped_ptr<AutoFillProfile> clone(
static_cast<AutoFillProfile*>(change->profile()->Clone()));
- DCHECK_EQ(AutofillModelAssociator::ProfileLabelToTag(clone->Label()),
- tag);
- HandleMoveAsideIfNeeded(trans, clone.get(), &tag);
+ DCHECK_EQ(clone->Label(), change->key());
+ ChangeProfileLabelIfAlreadyTaken(trans, string16(), clone.get(), &tag);
AddAutofillProfileSyncNode(trans, autofill_root, tag, clone.get());
break;
}
case AutofillProfileChange::UPDATE: {
scoped_ptr<AutoFillProfile> clone(
static_cast<AutoFillProfile*>(change->profile()->Clone()));
+ std::string pre_update_tag = AutofillModelAssociator::ProfileLabelToTag(
+ change->pre_update_label());
+ DCHECK_EQ(clone->Label(), change->key());
sync_api::WriteNode sync_node(trans);
- if (change->pre_update_label() != change->profile()->Label()) {
- // A re-labelling: we need to remove + add on the sync side.
- RemoveSyncNode(AutofillModelAssociator::ProfileLabelToTag(
- change->pre_update_label()), trans);
- // Watch out! Could be relabelling to an existing label!
- HandleMoveAsideIfNeeded(trans, clone.get(), &tag);
- AddAutofillProfileSyncNode(trans, autofill_root, tag,
- clone.get());
+ ChangeProfileLabelIfAlreadyTaken(trans, change->pre_update_label(),
+ clone.get(), &tag);
+ if (pre_update_tag != tag) {
+ // If the label changes, replace the node instead of updating it.
+ RemoveSyncNode(pre_update_tag, trans);
+ AddAutofillProfileSyncNode(trans, autofill_root, tag, clone.get());
return;
}
int64 sync_id = model_associator_->GetSyncIdFromChromeId(tag);
@@ -168,7 +179,7 @@ void AutofillChangeProcessor::ObserveAutofillProfileChanged(
"Autofill node lookup failed.");
return;
}
- WriteAutofillProfile(*change->profile(), &sync_node);
+ WriteAutofillProfile(*clone.get(), &sync_node);
}
break;
}
@@ -294,7 +305,6 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel(
return;
}
- std::vector<AutofillEntry> new_entries;
for (int i = 0; i < change_count; ++i) {
sync_api::SyncManager::ChangeRecord::Action action(changes[i].action);
if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == action) {
@@ -302,12 +312,13 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel(
<< "Autofill specifics data not present on delete!";
const sync_pb::AutofillSpecifics& autofill =
changes[i].specifics.GetExtension(sync_pb::autofill);
- if (autofill.has_value())
- ApplySyncAutofillEntryDelete(autofill);
- else if (autofill.has_profile())
- ApplySyncAutofillProfileDelete(autofill.profile(), changes[i].id);
- else
+ if (autofill.has_value() || autofill.has_profile()) {
+ autofill_changes_.push_back(AutofillChangeRecord(changes[i].action,
+ changes[i].id,
+ autofill));
+ } else {
NOTREACHED() << "Autofill specifics has no data!";
+ }
continue;
}
@@ -326,17 +337,59 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel(
const sync_pb::AutofillSpecifics& autofill(
sync_node.GetAutofillSpecifics());
int64 sync_id = sync_node.GetId();
- if (autofill.has_value())
- ApplySyncAutofillEntryChange(action, autofill, &new_entries, sync_id);
- else if (autofill.has_profile())
- ApplySyncAutofillProfileChange(action, autofill.profile(), sync_id);
- else
+ if (autofill.has_value() || autofill.has_profile()) {
+ autofill_changes_.push_back(AutofillChangeRecord(changes[i].action,
+ sync_id, autofill));
+ } else {
NOTREACHED() << "Autofill specifics has no data!";
+ }
+ }
+
+ StartObserving();
+}
+
+void AutofillChangeProcessor::CommitChangesFromSyncModel() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
+ if (!running())
+ return;
+ StopObserving();
+
+ std::vector<AutofillEntry> new_entries;
+ for (unsigned int i = 0; i < autofill_changes_.size(); i++) {
+ // Handle deletions.
+ if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
+ autofill_changes_[i].action_) {
+ if (autofill_changes_[i].autofill_.has_value()) {
+ ApplySyncAutofillEntryDelete(autofill_changes_[i].autofill_);
+ } else if (autofill_changes_[i].autofill_.has_profile()) {
+ ApplySyncAutofillProfileDelete(autofill_changes_[i].autofill_.profile(),
+ autofill_changes_[i].id_);
+ } else {
+ NOTREACHED() << "Autofill's CommitChanges received change with no"
+ " data!";
+ }
+ continue;
+ }
+
+ // Handle update/adds.
+ if (autofill_changes_[i].autofill_.has_value()) {
+ ApplySyncAutofillEntryChange(autofill_changes_[i].action_,
+ autofill_changes_[i].autofill_, &new_entries,
+ autofill_changes_[i].id_);
+ } else if (autofill_changes_[i].autofill_.has_profile()) {
+ ApplySyncAutofillProfileChange(autofill_changes_[i].action_,
+ autofill_changes_[i].autofill_.profile(),
+ autofill_changes_[i].id_);
+ } else {
+ NOTREACHED() << "Autofill's CommitChanges received change with no data!";
+ }
}
+ autofill_changes_.clear();
+ // Make changes
if (!web_database_->UpdateAutofillEntries(new_entries)) {
error_handler()->OnUnrecoverableError(FROM_HERE,
- "Could not update autofill entries.");
+ "Could not update autofill entries.");
return;
}
diff --git a/chrome/browser/sync/glue/autofill_change_processor.h b/chrome/browser/sync/glue/autofill_change_processor.h
index b71e535..0680d0c 100644
--- a/chrome/browser/sync/glue/autofill_change_processor.h
+++ b/chrome/browser/sync/glue/autofill_change_processor.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_CHANGE_PROCESSOR_H_
+#pragma once
+
+#include <vector>
-#include "base/scoped_ptr.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/autofill/personal_data_manager.h"
@@ -52,6 +54,10 @@ class AutofillChangeProcessor : public ChangeProcessor,
const sync_api::SyncManager::ChangeRecord* changes,
int change_count);
+ // Commit any changes from ApplyChangesFromSyncModel buffered in
+ // autofill_changes_.
+ virtual void CommitChangesFromSyncModel();
+
// Copy the properties of the given Autofill entry into the sync
// node.
static void WriteAutofillEntry(const AutofillEntry& entry,
@@ -67,6 +73,17 @@ class AutofillChangeProcessor : public ChangeProcessor,
virtual void StopImpl();
private:
+ struct AutofillChangeRecord {
+ sync_api::SyncManager::ChangeRecord::Action action_;
+ int64 id_;
+ sync_pb::AutofillSpecifics autofill_;
+ AutofillChangeRecord(sync_api::SyncManager::ChangeRecord::Action action,
+ int64 id, const sync_pb::AutofillSpecifics& autofill)
+ : action_(action),
+ id_(id),
+ autofill_(autofill) { }
+ };
+
void StartObserving();
void StopObserving();
@@ -107,10 +124,22 @@ class AutofillChangeProcessor : public ChangeProcessor,
// This method should be called on an ADD notification from the chrome model.
// |tag| contains the unique sync client tag identifier for |profile|, which
// is derived from the profile label using ProfileLabelToTag.
- void HandleMoveAsideIfNeeded(
- sync_api::BaseTransaction* trans, AutoFillProfile* profile,
+ // |existing_unique_label| is the current label of the object, if any; this
+ // is an allowed value, because it's taken by the item in question.
+ // For new items, set |existing_unique_label| to the empty string.
+ void ChangeProfileLabelIfAlreadyTaken(
+ sync_api::BaseTransaction* trans,
+ const string16& existing_unique_label,
+ AutoFillProfile* profile,
std::string* tag);
+ // Reassign the label of the profile, write this back to the web database,
+ // and update |tag| with the tag corresponding to the new label.
+ void OverrideProfileLabel(
+ const string16& new_label,
+ AutoFillProfile* profile_to_update,
+ std::string* tag_to_update);
+
// Helper to create a sync node with tag |tag|, storing |profile| as
// the node's AutofillSpecifics.
void AddAutofillProfileSyncNode(
@@ -139,6 +168,10 @@ class AutofillChangeProcessor : public ChangeProcessor,
bool observing_;
+ // Record of changes from ApplyChangesFromSyncModel. These are then processed
+ // in CommitChangesFromSyncModel.
+ std::vector<AutofillChangeRecord> autofill_changes_;
+
DISALLOW_COPY_AND_ASSIGN(AutofillChangeProcessor);
};
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.h b/chrome/browser/sync/glue/autofill_data_type_controller.h
index b21332c..3ed23d9 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.h
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_DATA_TYPE_CONTROLLER_H__
#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_DATA_TYPE_CONTROLLER_H__
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/glue/autofill_model_associator.cc b/chrome/browser/sync/glue/autofill_model_associator.cc
index a373575..2d6761f 100644
--- a/chrome/browser/sync/glue/autofill_model_associator.cc
+++ b/chrome/browser/sync/glue/autofill_model_associator.cc
@@ -8,6 +8,7 @@
#include "base/task.h"
#include "base/time.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/chrome_thread.h"
@@ -124,7 +125,7 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
int64 sync_id = node.GetId();
if (id_map_.find(tag) != id_map_.end()) {
// We just looked up something we already associated. Move aside.
- label = MakeUniqueLabel(label, write_trans);
+ label = MakeUniqueLabel(label, string16(), write_trans);
if (label.empty()) {
return false;
}
@@ -158,11 +159,18 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
// static
string16 AutofillModelAssociator::MakeUniqueLabel(
- const string16& non_unique_label, sync_api::BaseTransaction* trans) {
+ const string16& non_unique_label,
+ const string16& existing_unique_label,
+ sync_api::BaseTransaction* trans) {
+ if (!non_unique_label.empty() && non_unique_label == existing_unique_label) {
+ return existing_unique_label;
+ }
int unique_id = 1; // Priming so we start by appending "2".
while (unique_id++ < kMaxNumAttemptsToFindUniqueLabel) {
- string16 suffix(UTF8ToUTF16(IntToString(unique_id)));
+ string16 suffix(base::IntToString16(unique_id));
string16 unique_label = non_unique_label + suffix;
+ if (unique_label == existing_unique_label)
+ return unique_label; // We'll use the one we already have.
sync_api::ReadNode node(trans);
if (node.InitByClientTagLookup(syncable::AUTOFILL,
ProfileLabelToTag(unique_label))) {
diff --git a/chrome/browser/sync/glue/autofill_model_associator.h b/chrome/browser/sync/glue/autofill_model_associator.h
index 7814273..bc07bc3 100644
--- a/chrome/browser/sync/glue/autofill_model_associator.h
+++ b/chrome/browser/sync/glue/autofill_model_associator.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_MODEL_ASSOCIATOR_H_
+#pragma once
#include <map>
#include <set>
@@ -13,7 +14,6 @@
#include "base/basictypes.h"
#include "base/lock.h"
#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/sync/engine/syncapi.h"
@@ -121,7 +121,14 @@ class AutofillModelAssociator
// Returns sync service instance.
ProfileSyncService* sync_service() { return sync_service_; }
- static string16 MakeUniqueLabel(const string16& non_unique_label,
+ // Compute and apply suffix to a label so that the resulting label is
+ // unique in the sync database.
+ // |new_non_unique_label| is the colliding label which is to be uniquified.
+ // |existing_unique_label| is the current label of the object, if any; this
+ // is treated as a unique label even if colliding. If no such label is
+ // available, |existing_unique_label| may be empty.
+ static string16 MakeUniqueLabel(const string16& new_non_unique_label,
+ const string16& existing_unique_label,
sync_api::BaseTransaction* trans);
private:
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.cc b/chrome/browser/sync/glue/bookmark_change_processor.cc
index 1151ec1..42764e5 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.cc
+++ b/chrome/browser/sync/glue/bookmark_change_processor.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.
@@ -7,7 +7,9 @@
#include <stack>
#include <vector>
+#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/chrome_thread.h"
#include "chrome/browser/favicon_service.h"
@@ -49,7 +51,7 @@ void BookmarkChangeProcessor::UpdateSyncNodeProperties(
const BookmarkNode* src, BookmarkModel* model, sync_api::WriteNode* dst) {
// Set the properties of the item.
dst->SetIsFolder(src->is_folder());
- dst->SetTitle(src->GetTitle());
+ dst->SetTitle(UTF16ToWideHack(src->GetTitle()));
if (!src->is_folder())
dst->SetURL(src->GetURL());
SetSyncNodeFavicon(src, model, dst);
@@ -395,7 +397,7 @@ void BookmarkChangeProcessor::ApplyChangesFromSyncModel(
if (!foster_parent) {
foster_parent = model->AddGroup(model->other_node(),
model->other_node()->GetChildCount(),
- std::wstring());
+ string16());
}
for (int i = dst->GetChildCount() - 1; i >= 0; --i) {
model->Move(dst->GetChild(i), foster_parent,
@@ -463,7 +465,7 @@ const BookmarkNode* BookmarkChangeProcessor::CreateOrUpdateBookmarkNode(
if (!src->GetIsFolder())
model->SetURL(dst, src->GetURL());
- model->SetTitle(dst, src->GetTitle());
+ model->SetTitle(dst, WideToUTF16Hack(src->GetTitle()));
SetBookmarkFavicon(src, dst, model->profile());
}
@@ -484,10 +486,12 @@ const BookmarkNode* BookmarkChangeProcessor::CreateBookmarkNode(
const BookmarkNode* node;
if (sync_node->GetIsFolder()) {
- node = model->AddGroup(parent, index, sync_node->GetTitle());
+ node = model->AddGroup(parent, index,
+ WideToUTF16Hack(sync_node->GetTitle()));
} else {
node = model->AddURL(parent, index,
- sync_node->GetTitle(), sync_node->GetURL());
+ WideToUTF16Hack(sync_node->GetTitle()),
+ sync_node->GetURL());
SetBookmarkFavicon(sync_node, node, model->profile());
}
return node;
@@ -516,7 +520,7 @@ bool BookmarkChangeProcessor::SetBookmarkFavicon(
FaviconService* favicon_service =
profile->GetFaviconService(Profile::EXPLICIT_ACCESS);
- history->AddPage(bookmark_node->GetURL());
+ history->AddPage(bookmark_node->GetURL(), history::SOURCE_SYNCED);
favicon_service->SetFavicon(bookmark_node->GetURL(),
fake_icon_url,
icon_bytes_vector);
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.h b/chrome/browser/sync/glue/bookmark_change_processor.h
index 5e26dac..b87fcce 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.h
+++ b/chrome/browser/sync/glue/bookmark_change_processor.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_GLUE_BOOKMARK_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_BOOKMARK_CHANGE_PROCESSOR_H_
+#pragma once
#include <vector>
-#include "base/scoped_ptr.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.h b/chrome/browser/sync/glue/bookmark_data_type_controller.h
index 7a43c73..41068c8 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.h
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_BOOKMARK_DATA_TYPE_CONTROLLER_H__
#define CHROME_BROWSER_SYNC_GLUE_BOOKMARK_DATA_TYPE_CONTROLLER_H__
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.cc b/chrome/browser/sync/glue/bookmark_model_associator.cc
index fbbf8c3..ae95398 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.cc
+++ b/chrome/browser/sync/glue/bookmark_model_associator.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.
@@ -9,6 +9,7 @@
#include "base/hash_tables.h"
#include "base/message_loop.h"
#include "base/task.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
@@ -93,7 +94,7 @@ const BookmarkNode* BookmarkNodeFinder::FindBookmarkNode(
const sync_api::BaseNode& sync_node) {
// Create a bookmark node from the given sync node.
BookmarkNode temp_node(sync_node.GetURL());
- temp_node.SetTitle(sync_node.GetTitle());
+ temp_node.SetTitle(WideToUTF16Hack(sync_node.GetTitle()));
if (sync_node.GetIsFolder())
temp_node.set_type(BookmarkNode::FOLDER);
else
@@ -256,7 +257,7 @@ bool BookmarkModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
bool BookmarkModelAssociator::NodesMatch(const BookmarkNode* bookmark,
const sync_api::BaseNode* sync_node) const {
- if (bookmark->GetTitle() != sync_node->GetTitle())
+ if (bookmark->GetTitle() != WideToUTF16Hack(sync_node->GetTitle()))
return false;
if (bookmark->is_folder() != sync_node->GetIsFolder())
return false;
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.h b/chrome/browser/sync/glue/bookmark_model_associator.h
index 5c725cc..8dce287 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.h
+++ b/chrome/browser/sync/glue/bookmark_model_associator.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
+#pragma once
#include <map>
#include <set>
diff --git a/chrome/browser/sync/glue/change_processor.h b/chrome/browser/sync/glue/change_processor.h
index 7e020e6..4d6ec09 100644
--- a/chrome/browser/sync/glue/change_processor.h
+++ b/chrome/browser/sync/glue/change_processor.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_H_
+#pragma once
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
@@ -43,6 +44,13 @@ class ChangeProcessor {
const sync_api::SyncManager::ChangeRecord* changes,
int change_count) = 0;
+ // The changes found in ApplyChangesFromSyncModel may be too slow to be
+ // performed while holding a [Read/Write]Transaction lock. This function
+ // is called once the lock is released and performs any slow I/O operations
+ // without unnecessarily slowing the UI. Note that not all datatypes need
+ // this, so we provide an empty default version.
+ virtual void CommitChangesFromSyncModel() { }
+
protected:
// These methods are invoked by Start() and Stop() to do
// implementation-specific work.
diff --git a/chrome/browser/sync/glue/change_processor_mock.h b/chrome/browser/sync/glue/change_processor_mock.h
index 2860c4b..bec1369 100644
--- a/chrome/browser/sync/glue/change_processor_mock.h
+++ b/chrome/browser/sync/glue/change_processor_mock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_MOCK_H__
#define CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_MOCK_H__
+#pragma once
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
diff --git a/chrome/browser/sync/glue/data_type_controller.h b/chrome/browser/sync/glue/data_type_controller.h
index baece97..d786ddc 100644
--- a/chrome/browser/sync/glue/data_type_controller.h
+++ b/chrome/browser/sync/glue/data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_CONTROLLER_H__
#define CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_CONTROLLER_H__
+#pragma once
#include <map>
diff --git a/chrome/browser/sync/glue/data_type_controller_mock.h b/chrome/browser/sync/glue/data_type_controller_mock.h
index e9d1be6..09ec652 100644
--- a/chrome/browser/sync/glue/data_type_controller_mock.h
+++ b/chrome/browser/sync/glue/data_type_controller_mock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_CONTROLLER_MOCK_H__
#define CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_CONTROLLER_MOCK_H__
+#pragma once
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/sync/glue/data_type_manager.h b/chrome/browser/sync/glue/data_type_manager.h
index 0a0b1f1..24049f2 100644
--- a/chrome/browser/sync/glue/data_type_manager.h
+++ b/chrome/browser/sync/glue/data_type_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_MANAGER_H__
#define CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_MANAGER_H__
+#pragma once
#include <set>
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.cc b/chrome/browser/sync/glue/data_type_manager_impl.cc
index 5da617f..2266a3f 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.cc
+++ b/chrome/browser/sync/glue/data_type_manager_impl.cc
@@ -26,6 +26,7 @@ static const syncable::ModelType kStartOrder[] = {
syncable::THEMES,
syncable::TYPED_URLS,
syncable::PASSWORDS,
+ syncable::SESSIONS,
};
// Comparator used when sorting data type controllers.
@@ -411,14 +412,14 @@ void DataTypeManagerImpl::RemoveObserver(NotificationType type) {
void DataTypeManagerImpl::NotifyStart() {
NotificationService::current()->Notify(
NotificationType::SYNC_CONFIGURE_START,
- NotificationService::AllSources(),
+ Source<DataTypeManager>(this),
NotificationService::NoDetails());
}
void DataTypeManagerImpl::NotifyDone(ConfigureResult result) {
NotificationService::current()->Notify(
NotificationType::SYNC_CONFIGURE_DONE,
- NotificationService::AllSources(),
+ Source<DataTypeManager>(this),
Details<ConfigureResult>(&result));
}
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.h b/chrome/browser/sync/glue/data_type_manager_impl.h
index fd054f2..a735394 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.h
+++ b/chrome/browser/sync/glue/data_type_manager_impl.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_MANAGER_IMPL_H__
#define CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_MANAGER_IMPL_H__
+#pragma once
#include "chrome/browser/sync/glue/data_type_manager.h"
@@ -11,7 +12,6 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
#include "base/task.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/sync/glue/data_type_manager_mock.h b/chrome/browser/sync/glue/data_type_manager_mock.h
index 1d97dac..2a1705a 100644
--- a/chrome/browser/sync/glue/data_type_manager_mock.h
+++ b/chrome/browser/sync/glue/data_type_manager_mock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_MANAGER_MOCK_H__
#define CHROME_BROWSER_SYNC_GLUE_DATA_TYPE_MANAGER_MOCK_H__
+#pragma once
#include "chrome/browser/sync/glue/data_type_manager.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
@@ -12,13 +13,19 @@
#include "chrome/common/notification_type.h"
#include "testing/gmock/include/gmock/gmock.h"
-ACTION_P2(NotifyWithResult, type, result) {
+ACTION_P3(NotifyFromDataTypeManagerWithResult, dtm, type, result) {
NotificationService::current()->Notify(
type,
- NotificationService::AllSources(),
+ Source<browser_sync::DataTypeManager>(dtm),
Details<browser_sync::DataTypeManager::ConfigureResult>(result));
}
+ACTION_P2(NotifyFromDataTypeManager, dtm, type) {
+ NotificationService::current()->Notify(type,
+ Source<browser_sync::DataTypeManager>(dtm),
+ NotificationService::NoDetails());
+}
+
namespace browser_sync {
class DataTypeManagerMock : public DataTypeManager {
@@ -29,9 +36,10 @@ class DataTypeManagerMock : public DataTypeManager {
// detail.
ON_CALL(*this, Configure(testing::_)).
WillByDefault(testing::DoAll(
- Notify(NotificationType::SYNC_CONFIGURE_START),
- NotifyWithResult(NotificationType::SYNC_CONFIGURE_DONE,
- &result_)));
+ NotifyFromDataTypeManager(this,
+ NotificationType::SYNC_CONFIGURE_START),
+ NotifyFromDataTypeManagerWithResult
+ (this, NotificationType::SYNC_CONFIGURE_DONE, &result_)));
}
MOCK_METHOD1(Configure, void(const TypeSet&));
diff --git a/chrome/browser/sync/glue/database_model_worker.cc b/chrome/browser/sync/glue/database_model_worker.cc
index 13f5122..7df6abc 100644
--- a/chrome/browser/sync/glue/database_model_worker.cc
+++ b/chrome/browser/sync/glue/database_model_worker.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/sync/glue/database_model_worker.h"
+#include "base/waitable_event.h"
#include "chrome/browser/chrome_thread.h"
using base::WaitableEvent;
diff --git a/chrome/browser/sync/glue/database_model_worker.h b/chrome/browser/sync/glue/database_model_worker.h
index 1f4092d..a10e2de 100644
--- a/chrome/browser/sync/glue/database_model_worker.h
+++ b/chrome/browser/sync/glue/database_model_worker.h
@@ -4,12 +4,15 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_DATABASE_MODEL_WORKER_H_
#define CHROME_BROWSER_SYNC_GLUE_DATABASE_MODEL_WORKER_H_
+#pragma once
#include "base/callback.h"
-#include "base/ref_counted.h"
-#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/model_safe_worker.h"
+namespace base {
+class WaitableEvent;
+}
+
namespace browser_sync {
// A ModelSafeWorker for database models (eg. autofill) that accepts requests
diff --git a/chrome/browser/sync/glue/extension_change_processor.cc b/chrome/browser/sync/glue/extension_change_processor.cc
index e836b1e..589ebb2 100644
--- a/chrome/browser/sync/glue/extension_change_processor.cc
+++ b/chrome/browser/sync/glue/extension_change_processor.cc
@@ -9,9 +9,11 @@
#include "base/logging.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/sync/engine/syncapi.h"
-#include "chrome/browser/sync/glue/extension_model_associator.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extensions_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"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"
@@ -19,14 +21,13 @@
namespace browser_sync {
ExtensionChangeProcessor::ExtensionChangeProcessor(
- UnrecoverableErrorHandler* error_handler,
- ExtensionModelAssociator* extension_model_associator)
+ const ExtensionSyncTraits& traits,
+ UnrecoverableErrorHandler* error_handler)
: ChangeProcessor(error_handler),
- extension_model_associator_(extension_model_associator),
+ traits_(traits),
profile_(NULL) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
DCHECK(error_handler);
- DCHECK(extension_model_associator_);
}
ExtensionChangeProcessor::~ExtensionChangeProcessor() {
@@ -43,32 +44,45 @@ void ExtensionChangeProcessor::Observe(NotificationType type,
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
DCHECK(running());
DCHECK(profile_);
- switch (type.value) {
- case NotificationType::EXTENSION_LOADED:
- case NotificationType::EXTENSION_UPDATE_DISABLED:
- case NotificationType::EXTENSION_UNLOADED:
- case NotificationType::EXTENSION_UNLOADED_DISABLED: {
- DCHECK_EQ(Source<Profile>(source).ptr(), profile_);
- Extension* extension = Details<Extension>(details).ptr();
- CHECK(extension);
- // Ignore non-syncable extensions.
- if (!IsExtensionSyncable(*extension)) {
- return;
- }
- const std::string& id = extension->id();
- LOG(INFO) << "Got change notification of type " << type.value
- << " for extension " << id;
- if (!extension_model_associator_->OnClientUpdate(id)) {
- std::string error = std::string("Client update failed for ") + id;
- error_handler()->OnUnrecoverableError(FROM_HERE, error);
- return;
- }
- break;
+ if ((type != NotificationType::EXTENSION_LOADED) &&
+ (type != NotificationType::EXTENSION_UPDATE_DISABLED) &&
+ (type != NotificationType::EXTENSION_UNLOADED) &&
+ (type != NotificationType::EXTENSION_UNLOADED_DISABLED)) {
+ LOG(DFATAL) << "Received unexpected notification of type "
+ << type.value;
+ return;
+ }
+ DCHECK_EQ(Source<Profile>(source).ptr(), profile_);
+ const Extension* extension = Details<Extension>(details).ptr();
+ CHECK(extension);
+ // Ignore non-syncable extensions.
+ if (!IsExtensionValidAndSyncable(
+ *extension, traits_.allowed_extension_types)) {
+ return;
+ }
+ const std::string& id = extension->id();
+ LOG(INFO) << "Got notification of type " << type.value
+ << " for extension " << id;
+ ExtensionsService* extensions_service =
+ GetExtensionsServiceFromProfile(profile_);
+ // Whether an extension is loaded or not isn't an indicator of
+ // whether it's installed or not; some extension actions unload and
+ // then reload an extension to force listeners to update.
+ bool extension_installed =
+ (extensions_service->GetExtensionById(id, true) != NULL);
+ if (extension_installed) {
+ LOG(INFO) << "Extension " << id
+ << " is installed; updating server data";
+ std::string error;
+ if (!UpdateServerData(traits_, *extension,
+ profile_->GetProfileSyncService(), &error)) {
+ error_handler()->OnUnrecoverableError(FROM_HERE, error);
}
- default:
- LOG(DFATAL) << "Received unexpected notification of type "
- << type.value;
- break;
+ } else {
+ LOG(INFO) << "Extension " << id
+ << " is not installed; removing server data";
+ RemoveServerData(traits_, *extension,
+ profile_->GetProfileSyncService());
}
}
@@ -80,6 +94,8 @@ void ExtensionChangeProcessor::ApplyChangesFromSyncModel(
if (!running()) {
return;
}
+ ExtensionsService* extensions_service =
+ GetExtensionsServiceFromProfile(profile_);
for (int i = 0; i < change_count; ++i) {
const sync_api::SyncManager::ChangeRecord& change = changes[i];
switch (change.action) {
@@ -93,9 +109,9 @@ void ExtensionChangeProcessor::ApplyChangesFromSyncModel(
error_handler()->OnUnrecoverableError(FROM_HERE, error.str());
return;
}
- DCHECK_EQ(node.GetModelType(), syncable::EXTENSIONS);
+ DCHECK_EQ(node.GetModelType(), traits_.model_type);
const sync_pb::ExtensionSpecifics& specifics =
- node.GetExtensionSpecifics();
+ (*traits_.extension_specifics_getter)(node);
if (!IsExtensionSpecificsValid(specifics)) {
std::string error =
std::string("Invalid server specifics: ") +
@@ -104,15 +120,17 @@ void ExtensionChangeProcessor::ApplyChangesFromSyncModel(
return;
}
StopObserving();
- extension_model_associator_->OnServerUpdate(specifics);
+ UpdateClient(traits_, specifics, extensions_service);
StartObserving();
break;
}
case sync_api::SyncManager::ChangeRecord::ACTION_DELETE: {
- StopObserving();
- if (change.specifics.HasExtension(sync_pb::extension)) {
- extension_model_associator_->OnServerRemove(
- change.specifics.GetExtension(sync_pb::extension).id());
+ sync_pb::ExtensionSpecifics specifics;
+ if ((*traits_.extension_specifics_entity_getter)(
+ change.specifics, &specifics)) {
+ StopObserving();
+ RemoveFromClient(traits_, specifics.id(), extensions_service);
+ StartObserving();
} else {
std::stringstream error;
error << "Could not get extension ID for deleted node "
@@ -120,7 +138,6 @@ void ExtensionChangeProcessor::ApplyChangesFromSyncModel(
error_handler()->OnUnrecoverableError(FROM_HERE, error.str());
LOG(DFATAL) << error.str();
}
- StartObserving();
break;
}
}
diff --git a/chrome/browser/sync/glue/extension_change_processor.h b/chrome/browser/sync/glue/extension_change_processor.h
index 7a10f9d..89428fb 100644
--- a/chrome/browser/sync/glue/extension_change_processor.h
+++ b/chrome/browser/sync/glue/extension_change_processor.h
@@ -4,21 +4,23 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_EXTENSION_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_CHANGE_PROCESSOR_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/extension_sync_traits.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_registrar.h"
+class ExtensionsService;
class NotificationDetails;
class NotificationSource;
class Profile;
namespace browser_sync {
-class ExtensionModelAssociator;
class UnrecoverableErrorHandler;
// This class is responsible for taking changes from the
@@ -28,13 +30,10 @@ class UnrecoverableErrorHandler;
class ExtensionChangeProcessor : public ChangeProcessor,
public NotificationObserver {
public:
- // Does not take ownership of either argument.
- //
- // TODO(akalin): Create a Delegate interface and take that instead.
- // That'll enable us to unit test this class.
+ // Does not take ownership of |error_handler|.
ExtensionChangeProcessor(
- UnrecoverableErrorHandler* error_handler,
- ExtensionModelAssociator* extension_model_associator);
+ const ExtensionSyncTraits& traits,
+ UnrecoverableErrorHandler* error_handler);
virtual ~ExtensionChangeProcessor();
// NotificationObserver implementation.
@@ -59,8 +58,8 @@ class ExtensionChangeProcessor : public ChangeProcessor,
void StartObserving();
void StopObserving();
- ExtensionModelAssociator* extension_model_associator_;
NotificationRegistrar notification_registrar_;
+ const ExtensionSyncTraits traits_;
// Owner of the ExtensionService. Non-NULL iff |running()| is true.
Profile* profile_;
diff --git a/chrome/browser/sync/glue/extension_data.h b/chrome/browser/sync/glue/extension_data.h
index f67a48f..67951b9 100644
--- a/chrome/browser/sync/glue/extension_data.h
+++ b/chrome/browser/sync/glue/extension_data.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_EXTENSION_DATA_H_
#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_DATA_H_
+#pragma once
// ExtensionData is the class used to manage the client and server
// versions of the data for a particular extension.
diff --git a/chrome/browser/sync/glue/extension_data_type_controller.cc b/chrome/browser/sync/glue/extension_data_type_controller.cc
index c71ce3c..e0c92f3 100644
--- a/chrome/browser/sync/glue/extension_data_type_controller.cc
+++ b/chrome/browser/sync/glue/extension_data_type_controller.cc
@@ -2,14 +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/sync/glue/extension_data_type_controller.h"
+
#include "base/histogram.h"
#include "base/logging.h"
#include "base/time.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/sync/glue/extension_change_processor.h"
-#include "chrome/browser/sync/glue/extension_data_type_controller.h"
-#include "chrome/browser/sync/glue/extension_model_associator.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"
diff --git a/chrome/browser/sync/glue/extension_data_type_controller.h b/chrome/browser/sync/glue/extension_data_type_controller.h
index c364ac2..61f1d78 100644
--- a/chrome/browser/sync/glue/extension_data_type_controller.h
+++ b/chrome/browser/sync/glue/extension_data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_EXTENSION_DATA_TYPE_CONTROLLER_H_
#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_DATA_TYPE_CONTROLLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/glue/extension_model_associator.cc b/chrome/browser/sync/glue/extension_model_associator.cc
index 0337482..a7b1c19 100644
--- a/chrome/browser/sync/glue/extension_model_associator.cc
+++ b/chrome/browser/sync/glue/extension_model_associator.cc
@@ -4,86 +4,18 @@
#include "chrome/browser/sync/glue/extension_model_associator.h"
-#include <map>
-#include <utility>
-
#include "base/logging.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/sync/engine/syncapi.h"
-#include "chrome/browser/sync/glue/extension_util.h"
-#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/sync/glue/extension_data.h"
+#include "chrome/browser/sync/glue/extension_sync_traits.h"
+#include "chrome/browser/sync/glue/extension_sync.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
-#include "chrome/common/extensions/extension.h"
namespace browser_sync {
-namespace {
-
-static const char kExtensionsTag[] = "google_chrome_extensions";
-
-static const char kNoExtensionsFolderError[] =
- "Server did not create the top-level extensions node. We "
- "might be running against an out-of-date server.";
-
-typedef std::map<std::string, ExtensionData> ExtensionDataMap;
-
-ExtensionData* SetOrCreateData(
- ExtensionDataMap* extension_data_map,
- ExtensionData::Source source,
- bool merge_user_properties,
- const sync_pb::ExtensionSpecifics& data) {
- DcheckIsExtensionSpecificsValid(data);
- const std::string& extension_id = data.id();
- std::pair<ExtensionDataMap::iterator, bool> result =
- extension_data_map->insert(
- std::make_pair(extension_id,
- ExtensionData::FromData(source, data)));
- ExtensionData* extension_data = &result.first->second;
- if (result.second) {
- // The value was just inserted, so it shouldn't need an update
- // from source.
- DCHECK(!extension_data->NeedsUpdate(source));
- } else {
- extension_data->SetData(source, merge_user_properties, data);
- }
- return extension_data;
-}
-
-void GetSyncableExtensionsClientData(
- const ExtensionList& extensions,
- ExtensionsService* extensions_service,
- std::set<std::string>* unsyncable_extensions,
- ExtensionDataMap* extension_data_map) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- for (ExtensionList::const_iterator it = extensions.begin();
- it != extensions.end(); ++it) {
- CHECK(*it);
- const Extension& extension = **it;
- if (IsExtensionSyncable(extension)) {
- sync_pb::ExtensionSpecifics client_specifics;
- GetExtensionSpecifics(extension, extensions_service,
- &client_specifics);
- DcheckIsExtensionSpecificsValid(client_specifics);
- const ExtensionData& extension_data =
- *SetOrCreateData(extension_data_map,
- ExtensionData::CLIENT, true, client_specifics);
- DcheckIsExtensionSpecificsValid(extension_data.merged_data());
- // Assumes this is called before any server data is read.
- DCHECK(extension_data.NeedsUpdate(ExtensionData::SERVER));
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::CLIENT));
- } else {
- unsyncable_extensions->insert(extension.id());
- }
- }
-}
-
-} // namespace
-
ExtensionModelAssociator::ExtensionModelAssociator(
- ProfileSyncService* sync_service) : sync_service_(sync_service) {
+ const ExtensionSyncTraits& traits, ProfileSyncService* sync_service)
+ : traits_(traits), sync_service_(sync_service) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
DCHECK(sync_service_);
}
@@ -94,93 +26,12 @@ ExtensionModelAssociator::~ExtensionModelAssociator() {
bool ExtensionModelAssociator::AssociateModels() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- sync_api::WriteTransaction trans(
- sync_service_->backend()->GetUserShareHandle());
- sync_api::ReadNode root(&trans);
- if (!root.InitByTagLookup(kExtensionsTag)) {
- LOG(ERROR) << kNoExtensionsFolderError;
- return false;
- }
-
- std::set<std::string> unsyncable_extensions;
ExtensionDataMap extension_data_map;
-
- // Read client-side data. Do this first so server data takes
- // precedence.
- {
- ExtensionsService* extensions_service = GetExtensionsService();
-
- const ExtensionList* extensions = extensions_service->extensions();
- CHECK(extensions);
- GetSyncableExtensionsClientData(
- *extensions, extensions_service,
- &unsyncable_extensions, &extension_data_map);
-
- const ExtensionList* disabled_extensions =
- extensions_service->disabled_extensions();
- CHECK(disabled_extensions);
- GetSyncableExtensionsClientData(
- *disabled_extensions, extensions_service,
- &unsyncable_extensions, &extension_data_map);
- }
-
- // Read server-side data.
- {
- int64 id = root.GetFirstChildId();
- while (id != sync_api::kInvalidId) {
- sync_api::ReadNode sync_node(&trans);
- if (!sync_node.InitByIdLookup(id)) {
- LOG(ERROR) << "Failed to fetch sync node for id " << id;
- return false;
- }
- const sync_pb::ExtensionSpecifics& server_data =
- sync_node.GetExtensionSpecifics();
- if (!IsExtensionSpecificsValid(server_data)) {
- LOG(ERROR) << "Invalid extensions specifics for id " << id;
- return false;
- }
- // Don't process server data for extensions we know are
- // unsyncable. This doesn't catch everything, as if we don't
- // have the extension already installed we can't check, but we
- // also check at extension install time.
- if (unsyncable_extensions.find(server_data.id()) ==
- unsyncable_extensions.end()) {
- // Pass in false for merge_user_properties so client user
- // settings always take precedence.
- const ExtensionData& extension_data =
- *SetOrCreateData(&extension_data_map,
- ExtensionData::SERVER, false, server_data);
- DcheckIsExtensionSpecificsValid(extension_data.merged_data());
- }
- id = sync_node.GetSuccessorId();
- }
- }
-
- // Update server and client as necessary.
- bool should_nudge_extension_updater = false;
- for (ExtensionDataMap::iterator it = extension_data_map.begin();
- it != extension_data_map.end(); ++it) {
- ExtensionData* extension_data = &it->second;
- // Update server first.
- if (extension_data->NeedsUpdate(ExtensionData::SERVER)) {
- if (!UpdateServer(extension_data, &trans, root)) {
- LOG(ERROR) << "Could not update server data for extension "
- << it->first;
- return false;
- }
- }
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER));
- if (extension_data->NeedsUpdate(ExtensionData::CLIENT)) {
- TryUpdateClient(extension_data);
- if (extension_data->NeedsUpdate(ExtensionData::CLIENT)) {
- should_nudge_extension_updater = true;
- }
- }
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER));
+ if (!SlurpExtensionData(traits_, sync_service_, &extension_data_map)) {
+ return false;
}
-
- if (should_nudge_extension_updater) {
- NudgeExtensionUpdater();
+ if (!FlushExtensionData(traits_, extension_data_map, sync_service_)) {
+ return false;
}
return true;
@@ -194,233 +45,7 @@ bool ExtensionModelAssociator::DisassociateModels() {
bool ExtensionModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- CHECK(has_nodes);
- *has_nodes = false;
- sync_api::ReadTransaction trans(
- sync_service_->backend()->GetUserShareHandle());
- sync_api::ReadNode root(&trans);
- if (!root.InitByTagLookup(kExtensionsTag)) {
- LOG(ERROR) << kNoExtensionsFolderError;
- return false;
- }
- // The sync model has user created nodes iff the extensions folder has
- // any children.
- *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId;
- return true;
-}
-
-bool ExtensionModelAssociator::OnClientUpdate(const std::string& id) {
- sync_api::WriteTransaction trans(
- sync_service_->backend()->GetUserShareHandle());
- sync_api::ReadNode root(&trans);
- if (!root.InitByTagLookup(kExtensionsTag)) {
- LOG(ERROR) << kNoExtensionsFolderError;
- return false;
- }
- ExtensionsService* extensions_service = GetExtensionsService();
- Extension* extension = extensions_service->GetExtensionById(id, true);
- if (extension) {
- if (!IsExtensionSyncable(*extension)) {
- LOG(DFATAL) << "OnClientUpdate() called for non-syncable extension "
- << id;
- return false;
- }
- sync_pb::ExtensionSpecifics client_data;
- GetExtensionSpecifics(*extension, extensions_service, &client_data);
- DcheckIsExtensionSpecificsValid(client_data);
- ExtensionData extension_data =
- ExtensionData::FromData(ExtensionData::CLIENT, client_data);
- sync_pb::ExtensionSpecifics server_data;
- if (GetExtensionDataFromServer(id, &trans, root, &server_data)) {
- extension_data =
- ExtensionData::FromData(ExtensionData::SERVER, server_data);
- extension_data.SetData(ExtensionData::CLIENT, true, client_data);
- }
- if (extension_data.NeedsUpdate(ExtensionData::SERVER)) {
- if (!UpdateServer(&extension_data, &trans, root)) {
- LOG(ERROR) << "Could not update server data for extension " << id;
- return false;
- }
- }
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER));
- // Client may still need updating, e.g. if we disable an extension
- // while it's being auto-updated. If so, then we'll be called
- // again once the auto-update is finished.
- //
- // TODO(akalin): Figure out a way to tell when the above happens,
- // so we know exactly what NeedsUpdate(CLIENT) should return.
- } else {
- sync_api::WriteNode write_node(&trans);
- if (write_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) {
- write_node.Remove();
- } else {
- LOG(ERROR) << "Trying to remove server data for "
- << "nonexistent extension " << id;
- }
- }
- return true;
-}
-
-void ExtensionModelAssociator::OnServerUpdate(
- const sync_pb::ExtensionSpecifics& server_data) {
- DcheckIsExtensionSpecificsValid(server_data);
- ExtensionData extension_data =
- ExtensionData::FromData(ExtensionData::SERVER, server_data);
- ExtensionsService* extensions_service = GetExtensionsService();
- Extension* extension =
- extensions_service->GetExtensionById(server_data.id(), true);
- if (extension) {
- if (!IsExtensionSyncable(*extension)) {
- // Ignore updates for non-syncable extensions (we may get those
- // for extensions that were previously syncable).
- return;
- }
- sync_pb::ExtensionSpecifics client_data;
- GetExtensionSpecifics(*extension, extensions_service, &client_data);
- DcheckIsExtensionSpecificsValid(client_data);
- extension_data =
- ExtensionData::FromData(ExtensionData::CLIENT, client_data);
- extension_data.SetData(ExtensionData::SERVER, true, server_data);
- }
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER));
- if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) {
- TryUpdateClient(&extension_data);
- if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) {
- NudgeExtensionUpdater();
- }
- }
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER));
-}
-
-void ExtensionModelAssociator::OnServerRemove(const std::string& id) {
- ExtensionsService* extensions_service = GetExtensionsService();
- Extension* extension = extensions_service->GetExtensionById(id, true);
- if (extension) {
- if (IsExtensionSyncable(*extension)) {
- extensions_service->UninstallExtension(id, false);
- }
- } else {
- LOG(ERROR) << "Trying to uninstall nonexistent extension " << id;
- }
-}
-
-ExtensionsService* ExtensionModelAssociator::GetExtensionsService() {
- CHECK(sync_service_);
- Profile* profile = sync_service_->profile();
- CHECK(profile);
- ExtensionsService* extensions_service = profile->GetExtensionsService();
- CHECK(extensions_service);
- return extensions_service;
-}
-
-bool ExtensionModelAssociator::GetExtensionDataFromServer(
- const std::string& id, sync_api::WriteTransaction* trans,
- const sync_api::ReadNode& root,
- sync_pb::ExtensionSpecifics* server_data) {
- sync_api::ReadNode sync_node(trans);
- if (!sync_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) {
- LOG(ERROR) << "Failed to fetch sync node for id " << id;
- return false;
- }
- const sync_pb::ExtensionSpecifics& read_server_data =
- sync_node.GetExtensionSpecifics();
- if (!IsExtensionSpecificsValid(read_server_data)) {
- LOG(ERROR) << "Invalid extensions specifics for id " << id;
- return false;
- }
- *server_data = read_server_data;
- return true;
-}
-
-namespace {
-
-void SetNodeData(const sync_pb::ExtensionSpecifics& specifics,
- sync_api::WriteNode* node) {
- node->SetTitle(UTF8ToWide(specifics.name()));
- node->SetExtensionSpecifics(specifics);
-}
-
-} // namespace
-
-bool ExtensionModelAssociator::UpdateServer(
- ExtensionData* extension_data,
- sync_api::WriteTransaction* trans,
- const sync_api::ReadNode& root) {
- DCHECK(extension_data->NeedsUpdate(ExtensionData::SERVER));
- const sync_pb::ExtensionSpecifics& specifics =
- extension_data->merged_data();
- const std::string& id = specifics.id();
- sync_api::WriteNode write_node(trans);
- if (write_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) {
- SetNodeData(specifics, &write_node);
- } else {
- sync_api::WriteNode create_node(trans);
- if (!create_node.InitUniqueByCreation(syncable::EXTENSIONS, root, id)) {
- LOG(ERROR) << "Could not create node for extension " << id;
- return false;
- }
- SetNodeData(specifics, &create_node);
- }
- bool old_client_needs_update =
- extension_data->NeedsUpdate(ExtensionData::CLIENT);
- extension_data->ResolveData(ExtensionData::SERVER);
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER));
- DCHECK_EQ(extension_data->NeedsUpdate(ExtensionData::CLIENT),
- old_client_needs_update);
- return true;
-}
-
-void ExtensionModelAssociator::TryUpdateClient(
- ExtensionData* extension_data) {
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER));
- DCHECK(extension_data->NeedsUpdate(ExtensionData::CLIENT));
- const sync_pb::ExtensionSpecifics& specifics =
- extension_data->merged_data();
- DcheckIsExtensionSpecificsValid(specifics);
- ExtensionsService* extensions_service = GetExtensionsService();
- const std::string& id = specifics.id();
- Extension* extension = extensions_service->GetExtensionById(id, true);
- if (extension) {
- if (!IsExtensionSyncable(*extension)) {
- LOG(DFATAL) << "TryUpdateClient() called for non-syncable extension "
- << extension->id();
- return;
- }
- SetExtensionProperties(specifics, extensions_service, extension);
- {
- sync_pb::ExtensionSpecifics extension_specifics;
- GetExtensionSpecifics(*extension, extensions_service,
- &extension_specifics);
- DCHECK(AreExtensionSpecificsUserPropertiesEqual(
- specifics, extension_specifics))
- << ExtensionSpecificsToString(specifics) << ", "
- << ExtensionSpecificsToString(extension_specifics);
- }
- if (!IsExtensionOutdated(*extension, specifics)) {
- extension_data->ResolveData(ExtensionData::CLIENT);
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::CLIENT));
- }
- } else {
- GURL update_url(specifics.update_url());
- // TODO(akalin): Replace silent update with a list of enabled
- // permissions.
- extensions_service->AddPendingExtension(
- id, update_url, false, true,
- specifics.enabled(), specifics.incognito_enabled());
- }
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER));
-}
-
-void ExtensionModelAssociator::NudgeExtensionUpdater() {
- ExtensionUpdater* extension_updater = GetExtensionsService()->updater();
- // Auto-updates should now be on always (see the construction of the
- // ExtensionsService in ProfileImpl::InitExtensions()).
- if (extension_updater) {
- extension_updater->CheckNow();
- } else {
- LOG(DFATAL) << "Extension updater unexpectedly NULL; "
- << "auto-updates may be turned off";
- }
+ return RootNodeHasChildren(traits_.root_node_tag, sync_service_, has_nodes);
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/extension_model_associator.h b/chrome/browser/sync/glue/extension_model_associator.h
index a9c9d65..0063d2d 100644
--- a/chrome/browser/sync/glue/extension_model_associator.h
+++ b/chrome/browser/sync/glue/extension_model_associator.h
@@ -4,28 +4,15 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_EXTENSION_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_MODEL_ASSOCIATOR_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
-#include "chrome/browser/sync/glue/extension_data.h"
+#include "chrome/browser/sync/glue/extension_sync_traits.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/syncable/model_type.h"
-#include "chrome/common/extensions/extension.h"
-class ExtensionsService;
-class Profile;
class ProfileSyncService;
-namespace sync_api {
-class ReadNode;
-class WriteTransaction;
-} // namespace sync_api
-
-namespace sync_pb {
-class ExtensionSpecifics;
-} // namespace sync_pb
-
namespace browser_sync {
// Contains all logic for associating the Chrome extensions model and
@@ -33,7 +20,8 @@ namespace browser_sync {
class ExtensionModelAssociator : public AssociatorInterface {
public:
// Does not take ownership of sync_service.
- explicit ExtensionModelAssociator(ProfileSyncService* sync_service);
+ ExtensionModelAssociator(const ExtensionSyncTraits& traits,
+ ProfileSyncService* sync_service);
virtual ~ExtensionModelAssociator();
// Used by profile_sync_test_util.h.
@@ -48,53 +36,9 @@ class ExtensionModelAssociator : public AssociatorInterface {
// thread.
}
- // Used by ExtensionChangeProcessor.
- //
- // TODO(akalin): These functions can actually be moved to the
- // ChangeProcessor after some refactoring.
-
- // TODO(akalin): Return an error string instead of just a bool.
- bool OnClientUpdate(const std::string& id);
- void OnServerUpdate(const sync_pb::ExtensionSpecifics& server_data);
- void OnServerRemove(const std::string& id);
-
private:
- // Returns the extension service from |sync_service_|. Never
- // returns NULL.
- ExtensionsService* GetExtensionsService();
-
- bool GetExtensionDataFromServer(
- const std::string& id, sync_api::WriteTransaction* trans,
- const sync_api::ReadNode& root,
- sync_pb::ExtensionSpecifics* server_data);
-
- // Updates the server data from the given extension data.
- // extension_data->ServerNeedsUpdate() must hold before this
- // function is called. Returns whether or not the update was
- // successful. If the update was successful,
- // extension_data->ServerNeedsUpdate() will be false after this
- // function is called. This function leaves
- // extension_data->ClientNeedsUpdate() unchanged.
- bool UpdateServer(ExtensionData* extension_data,
- sync_api::WriteTransaction* trans,
- const sync_api::ReadNode& root);
-
- // Tries to update the client data from the given extension data.
- // extension_data->ServerNeedsUpdate() must not hold and
- // extension_data->ClientNeedsUpdate() must hold before this
- // function is called. If the update was successful,
- // extension_data->ClientNeedsUpdate() will be false after this
- // function is called. Otherwise, the extension needs updating to a
- // new version.
- void TryUpdateClient(ExtensionData* extension_data);
-
- // Kick off a run of the extension updater.
- //
- // TODO(akalin): Combine this with the similar function in
- // theme_util.cc.
- void NudgeExtensionUpdater();
-
- // Weak pointer.
+ const ExtensionSyncTraits traits_;
+ // Weak pointer. Always non-NULL.
ProfileSyncService* sync_service_;
DISALLOW_COPY_AND_ASSIGN(ExtensionModelAssociator);
diff --git a/chrome/browser/sync/glue/extension_util.cc b/chrome/browser/sync/glue/extension_util.cc
index 1fad37e..dfd7b04 100644
--- a/chrome/browser/sync/glue/extension_util.cc
+++ b/chrome/browser/sync/glue/extension_util.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "base/stl_util-inl.h"
#include "base/version.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
@@ -17,17 +18,28 @@
namespace browser_sync {
-bool IsExtensionSyncable(const Extension& extension) {
+ExtensionType GetExtensionType(const Extension& extension) {
if (extension.is_theme()) {
- return false;
+ return THEME;
}
// TODO(akalin): Add Extensions::is_app().
if (!extension.GetFullLaunchURL().is_empty()) {
- // We have an app.
- return false;
+ 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;
+}
+
+bool IsExtensionValid(const Extension& extension) {
// TODO(akalin): Figure out if we need to allow some other types.
if (extension.location() != Extension::INTERNAL) {
// We have a non-standard location.
@@ -57,6 +69,13 @@ bool IsExtensionSyncable(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;
@@ -167,7 +186,7 @@ void GetExtensionSpecifics(const Extension& extension,
void GetExtensionSpecificsHelper(const Extension& extension,
bool enabled, bool incognito_enabled,
sync_pb::ExtensionSpecifics* specifics) {
- DCHECK(IsExtensionSyncable(extension));
+ DCHECK(IsExtensionValid(extension));
const std::string& id = extension.id();
specifics->set_id(id);
specifics->set_version(extension.VersionString());
@@ -180,7 +199,7 @@ void GetExtensionSpecificsHelper(const Extension& extension,
bool IsExtensionOutdated(const Extension& extension,
const sync_pb::ExtensionSpecifics& specifics) {
- DCHECK(IsExtensionSyncable(extension));
+ DCHECK(IsExtensionValid(extension));
DcheckIsExtensionSpecificsValid(specifics);
scoped_ptr<Version> specifics_version(
Version::GetVersionFromString(specifics.version()));
@@ -197,7 +216,7 @@ void SetExtensionProperties(
DcheckIsExtensionSpecificsValid(specifics);
CHECK(extensions_service);
CHECK(extension);
- DCHECK(IsExtensionSyncable(*extension));
+ DCHECK(IsExtensionValid(*extension));
const std::string& id = extension->id();
GURL update_url(specifics.update_url());
if (update_url != extension->update_url()) {
diff --git a/chrome/browser/sync/glue/extension_util.h b/chrome/browser/sync/glue/extension_util.h
index 0eef52f..0f64b96 100644
--- a/chrome/browser/sync/glue/extension_util.h
+++ b/chrome/browser/sync/glue/extension_util.h
@@ -4,10 +4,16 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_EXTENSION_UTIL_H_
#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_UTIL_H_
+#pragma once
+// This file contains some low-level utility functions used by
+// extensions sync.
+
+#include <set>
#include <string>
class Extension;
+class ExtensionTypeSet;
class ExtensionsService;
namespace sync_pb {
@@ -16,8 +22,32 @@ 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);
+
+// 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 IsExtensionSyncable(const Extension& extension);
+bool IsExtensionValidAndSyncable(const Extension& extension,
+ const ExtensionTypeSet& allowed_types);
// Stringifies the given ExtensionSpecifics.
std::string ExtensionSpecificsToString(
diff --git a/chrome/browser/sync/glue/extension_util_unittest.cc b/chrome/browser/sync/glue/extension_util_unittest.cc
index 65b15c5..1396b2e 100644
--- a/chrome/browser/sync/glue/extension_util_unittest.cc
+++ b/chrome/browser/sync/glue/extension_util_unittest.cc
@@ -6,7 +6,6 @@
#include "base/file_path.h"
#include "base/values.h"
-#include "base/version.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -37,13 +36,10 @@ const char kName2[] = "MyExtension2";
class ExtensionUtilTest : public testing::Test {
};
-void MakePossiblySyncableExtension(bool is_theme,
- const GURL& update_url,
- const GURL& launch_url,
- bool converted_from_user_script,
- Extension::Location location,
- int num_plugins,
- Extension* extension) {
+void MakeExtension(bool is_theme, const GURL& update_url,
+ const GURL& launch_url, bool converted_from_user_script,
+ Extension::Location location, int num_plugins,
+ Extension* extension) {
DictionaryValue source;
source.SetString(extension_manifest_keys::kName,
"PossiblySyncableExtension");
@@ -70,74 +66,166 @@ void MakePossiblySyncableExtension(bool is_theme,
}
source.Set(extension_manifest_keys::kPlugins, plugins);
}
+
std::string error;
+#if defined(OS_CHROMEOS)
+ if (num_plugins > 0) { // plugins are illegal in extensions on chrome os.
+ EXPECT_FALSE(extension->InitFromValue(source, false, &error));
+ return;
+ }
+#endif
EXPECT_TRUE(extension->InitFromValue(source, false, &error));
EXPECT_EQ("", error);
extension->set_location(location);
}
-TEST_F(ExtensionUtilTest, IsSyncableExtension) {
+TEST_F(ExtensionUtilTest, GetExtensionType) {
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(), GURL(), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_EQ(EXTENSION, GetExtensionType(extension));
+ }
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(true, GURL(), GURL(), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_EQ(THEME, GetExtensionType(extension));
+ }
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(), GURL(), true,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_EQ(LOCAL_USER_SCRIPT, GetExtensionType(extension));
+ }
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL("http://www.google.com"), GURL(), true,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_EQ(UPDATEABLE_USER_SCRIPT, GetExtensionType(extension));
+ }
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(),
+ GURL("http://www.google.com"), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_EQ(APP, GetExtensionType(extension));
+ }
+}
+
+TEST_F(ExtensionUtilTest, IsExtensionValid) {
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(), GURL(), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_TRUE(IsExtensionValid(extension));
+ }
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(false, GURL(), GURL(), false,
- Extension::INTERNAL, 0, &extension);
- EXPECT_TRUE(IsExtensionSyncable(extension));
+ MakeExtension(false, GURL(kValidUpdateUrl1), GURL(),
+ true, Extension::INTERNAL, 0, &extension);
+ EXPECT_TRUE(IsExtensionValid(extension));
}
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(false, GURL(kValidUpdateUrl1), GURL(),
- true, Extension::INTERNAL, 0, &extension);
- EXPECT_TRUE(IsExtensionSyncable(extension));
+ MakeExtension(false, GURL(), GURL(), true,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_TRUE(IsExtensionValid(extension));
}
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(false, GURL(), GURL(), true,
- Extension::INTERNAL, 0, &extension);
- EXPECT_TRUE(IsExtensionSyncable(extension));
+ MakeExtension(true, GURL(), GURL(), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_TRUE(IsExtensionValid(extension));
}
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(true, GURL(), GURL(), false,
- Extension::INTERNAL, 0, &extension);
- EXPECT_FALSE(IsExtensionSyncable(extension));
+ MakeExtension(false, GURL(),
+ GURL("http://www.google.com"), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_TRUE(IsExtensionValid(extension));
}
- // TODO(akalin): Test with a non-empty launch_url once apps are
- // enabled by default.
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(false, GURL(), GURL(), false,
- Extension::EXTERNAL_PREF, 0, &extension);
- EXPECT_FALSE(IsExtensionSyncable(extension));
+ MakeExtension(false, GURL(), GURL(), false,
+ Extension::EXTERNAL_PREF, 0, &extension);
+ EXPECT_FALSE(IsExtensionValid(extension));
}
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(
+ MakeExtension(
false, GURL("http://third-party.update_url.com"), GURL(), true,
Extension::INTERNAL, 0, &extension);
- EXPECT_FALSE(IsExtensionSyncable(extension));
+ EXPECT_FALSE(IsExtensionValid(extension));
+ }
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(), GURL(), true,
+ Extension::INTERNAL, 1, &extension);
+ EXPECT_FALSE(IsExtensionValid(extension));
+ }
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(), GURL(), true,
+ Extension::INTERNAL, 2, &extension);
+ EXPECT_FALSE(IsExtensionValid(extension));
+ }
+}
+
+TEST_F(ExtensionUtilTest, IsExtensionValidAndSyncable) {
+ ExtensionTypeSet allowed_extension_types;
+ allowed_extension_types.insert(EXTENSION);
+ allowed_extension_types.insert(APP);
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(), GURL(), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_TRUE(IsExtensionValidAndSyncable(
+ extension, allowed_extension_types));
+ }
+ {
+ FilePath file_path(kExtensionFilePath);
+ Extension extension(file_path);
+ MakeExtension(false, GURL(),
+ GURL("http://www.google.com"), false,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_TRUE(IsExtensionValidAndSyncable(
+ extension, allowed_extension_types));
}
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(false, GURL(), GURL(), true,
- Extension::INTERNAL, 1, &extension);
- EXPECT_FALSE(IsExtensionSyncable(extension));
+ MakeExtension(false, GURL(), GURL(), true,
+ Extension::INTERNAL, 0, &extension);
+ EXPECT_FALSE(IsExtensionValidAndSyncable(
+ extension, allowed_extension_types));
}
{
FilePath file_path(kExtensionFilePath);
Extension extension(file_path);
- MakePossiblySyncableExtension(false, GURL(), GURL(), true,
- Extension::INTERNAL, 2, &extension);
- EXPECT_FALSE(IsExtensionSyncable(extension));
+ MakeExtension(false, GURL(), GURL(), false,
+ Extension::EXTERNAL_PREF, 0, &extension);
+ EXPECT_FALSE(IsExtensionValidAndSyncable(
+ extension, allowed_extension_types));
}
}
+
TEST_F(ExtensionUtilTest, IsExtensionSpecificsUnset) {
{
sync_pb::ExtensionSpecifics specifics;
diff --git a/chrome/browser/sync/glue/history_model_worker.cc b/chrome/browser/sync/glue/history_model_worker.cc
index df0187d..8c0fdb4 100644
--- a/chrome/browser/sync/glue/history_model_worker.cc
+++ b/chrome/browser/sync/glue/history_model_worker.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/sync/glue/history_model_worker.h"
-#include "base/logging.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/task.h"
@@ -42,6 +41,9 @@ HistoryModelWorker::HistoryModelWorker(HistoryService* history_service)
: history_service_(history_service) {
}
+HistoryModelWorker::~HistoryModelWorker() {
+}
+
void HistoryModelWorker::DoWorkAndWaitUntilDone(Callback0::Type* work) {
WaitableEvent done(false, false);
scoped_refptr<WorkerTask> task = new WorkerTask(work, &done);
diff --git a/chrome/browser/sync/glue/history_model_worker.h b/chrome/browser/sync/glue/history_model_worker.h
index 2882d5a..4afeead 100644
--- a/chrome/browser/sync/glue/history_model_worker.h
+++ b/chrome/browser/sync/glue/history_model_worker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_HISTORY_MODEL_WORKER_H_
#define CHROME_BROWSER_SYNC_GLUE_HISTORY_MODEL_WORKER_H_
+#pragma once
#include "chrome/browser/sync/engine/model_safe_worker.h"
@@ -26,6 +27,7 @@ class HistoryModelWorker : public browser_sync::ModelSafeWorker,
public CancelableRequestConsumerBase {
public:
explicit HistoryModelWorker(HistoryService* history_service);
+ virtual ~HistoryModelWorker();
// ModelSafeWorker implementation. Called on syncapi SyncerThread.
void DoWorkAndWaitUntilDone(Callback0::Type* work);
@@ -38,6 +40,13 @@ class HistoryModelWorker : public browser_sync::ModelSafeWorker,
virtual void OnRequestRemoved(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) {}
+
+ virtual void WillExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {}
+
+ virtual void DidExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {}
+
private:
scoped_refptr<HistoryService> history_service_;
DISALLOW_COPY_AND_ASSIGN(HistoryModelWorker);
diff --git a/chrome/browser/sync/glue/http_bridge.cc b/chrome/browser/sync/glue/http_bridge.cc
index b0ad53a..aab5f40 100644
--- a/chrome/browser/sync/glue/http_bridge.cc
+++ b/chrome/browser/sync/glue/http_bridge.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,11 +6,12 @@
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/chrome_thread.h"
#include "net/base/cookie_monster.h"
+#include "net/base/host_resolver.h"
#include "net/base/load_flags.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_layer.h"
@@ -117,6 +118,7 @@ HttpBridge::HttpBridge(HttpBridge::RequestContextGetter* context_getter)
request_completed_(false),
request_succeeded_(false),
http_response_code_(-1),
+ os_error_code_(-1),
http_post_completed_(false, false) {
}
@@ -142,7 +144,7 @@ void HttpBridge::SetURL(const char* url, int port) {
<< "HttpBridge::SetURL called more than once?!";
GURL temp(url);
GURL::Replacements replacements;
- std::string port_str = IntToString(port);
+ std::string port_str = base::IntToString(port);
replacements.SetPort(port_str.c_str(),
url_parse::Component(0, port_str.length()));
url_for_request_ = temp.ReplaceComponents(replacements);
diff --git a/chrome/browser/sync/glue/http_bridge.h b/chrome/browser/sync/glue/http_bridge.h
index 548f5d3..1951ce5 100644
--- a/chrome/browser/sync/glue/http_bridge.h
+++ b/chrome/browser/sync/glue/http_bridge.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_
#define CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/glue/http_bridge_unittest.cc b/chrome/browser/sync/glue/http_bridge_unittest.cc
index 8c28d16..db87c81 100644
--- a/chrome/browser/sync/glue/http_bridge_unittest.cc
+++ b/chrome/browser/sync/glue/http_bridge_unittest.cc
@@ -8,13 +8,14 @@
#include "chrome/browser/sync/glue/http_bridge.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
using browser_sync::HttpBridge;
namespace {
// TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
}
// Lazy getter for TestURLRequestContext instances.
@@ -38,7 +39,8 @@ class TestURLRequestContextGetter : public URLRequestContextGetter {
class HttpBridgeTest : public testing::Test {
public:
HttpBridgeTest()
- : fake_default_request_context_getter_(NULL),
+ : test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)),
+ fake_default_request_context_getter_(NULL),
io_thread_(ChromeThread::IO) {
}
@@ -87,6 +89,8 @@ class HttpBridgeTest : public testing::Test {
return fake_default_request_context_getter_;
}
+ net::TestServer test_server_;
+
private:
// A make-believe "default" request context, as would be returned by
// Profile::GetDefaultRequestContext(). Created lazily by BuildBridge.
@@ -174,14 +178,12 @@ TEST_F(HttpBridgeTest, TestMakeSynchronousPostShunted) {
// Full round-trip test of the HttpBridge, using default UA string and
// no request cookies.
TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
scoped_refptr<HttpBridge> http_bridge(BuildBridge());
std::string payload = "this should be echoed back";
- GURL echo = server->TestServerPage("echo");
+ GURL echo = test_server_.GetURL("echo");
http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
http_bridge->SetPostPayload("application/x-www-form-urlencoded",
payload.length() + 1, payload.c_str());
@@ -199,12 +201,11 @@ TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
// Full round-trip test of the HttpBridge, using custom UA string
TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<HttpBridge> http_bridge(BuildBridge());
- GURL echo_header = server->TestServerPage("echoall");
+ GURL echo_header = test_server_.GetURL("echoall");
http_bridge->SetUserAgent("bob");
http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
@@ -227,12 +228,11 @@ TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
}
TEST_F(HttpBridgeTest, TestExtraRequestHeaders) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<HttpBridge> http_bridge(BuildBridge());
- GURL echo_header = server->TestServerPage("echoall");
+ GURL echo_header = test_server_.GetURL("echoall");
http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
http_bridge->SetExtraRequestHeaders("test:fnord");
@@ -256,12 +256,11 @@ TEST_F(HttpBridgeTest, TestExtraRequestHeaders) {
}
TEST_F(HttpBridgeTest, TestResponseHeader) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<HttpBridge> http_bridge(BuildBridge());
- GURL echo_header = server->TestServerPage("echoall");
+ GURL echo_header = test_server_.GetURL("echoall");
http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
std::string test_payload = "###TEST PAYLOAD###";
diff --git a/chrome/browser/sync/glue/model_associator.h b/chrome/browser/sync/glue/model_associator.h
index 3c12659..f74129f 100644
--- a/chrome/browser/sync/glue/model_associator.h
+++ b/chrome/browser/sync/glue/model_associator.h
@@ -1,12 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_H_
-
-#include <map>
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/syncable/model_type.h"
diff --git a/chrome/browser/sync/glue/model_associator_mock.h b/chrome/browser/sync/glue/model_associator_mock.h
index 766f01b..219a204 100644
--- a/chrome/browser/sync/glue/model_associator_mock.h
+++ b/chrome/browser/sync/glue/model_associator_mock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_MOCK_H__
#define CHROME_BROWSER_SYNC_GLUE_MODEL_ASSOCIATOR_MOCK_H__
+#pragma once
#include "chrome/browser/sync/glue/model_associator.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/sync/glue/password_change_processor.cc b/chrome/browser/sync/glue/password_change_processor.cc
index 93143e6..0a42a94 100644
--- a/chrome/browser/sync/glue/password_change_processor.cc
+++ b/chrome/browser/sync/glue/password_change_processor.cc
@@ -141,6 +141,21 @@ void PasswordChangeProcessor::ApplyChangesFromSyncModel(
PasswordModelAssociator::PasswordVector deleted_passwords;
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::password))
+ << "Password specifics data not present on delete!";
+ DCHECK(changes[i].extra.get());
+ sync_api::SyncManager::ExtraPasswordChangeRecordData* extra =
+ static_cast<sync_api::SyncManager::ExtraPasswordChangeRecordData*>(
+ changes[i].extra.get());
+ const sync_pb::PasswordSpecificsData& password = extra->unencrypted();
+ webkit_glue::PasswordForm form;
+ PasswordModelAssociator::CopyPassword(password, &form);
+ deleted_passwords.push_back(form);
+ model_associator_->Disassociate(changes[i].id);
+ continue;
+ }
sync_api::ReadNode sync_node(trans);
if (!sync_node.InitByIdLookup(changes[i].id)) {
@@ -156,20 +171,19 @@ void PasswordChangeProcessor::ApplyChangesFromSyncModel(
const sync_pb::PasswordSpecificsData& password_data =
sync_node.GetPasswordSpecifics();
webkit_glue::PasswordForm password;
- PasswordModelAssociator::CopyPassword(password_data,
- &password);
+ PasswordModelAssociator::CopyPassword(password_data, &password);
if (sync_api::SyncManager::ChangeRecord::ACTION_ADD == changes[i].action) {
+ std::string tag(PasswordModelAssociator::MakeTag(password));
+ model_associator_->Associate(&tag, sync_node.GetId());
new_passwords.push_back(password);
- } else if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
- changes[i].action) {
- deleted_passwords.push_back(password);
} else {
DCHECK(sync_api::SyncManager::ChangeRecord::ACTION_UPDATE ==
changes[i].action);
updated_passwords.push_back(password);
}
}
+
if (!model_associator_->WriteToPasswordStore(&new_passwords,
&updated_passwords,
&deleted_passwords)) {
diff --git a/chrome/browser/sync/glue/password_change_processor.h b/chrome/browser/sync/glue/password_change_processor.h
index 6ca3dbb..99955bf 100644
--- a/chrome/browser/sync/glue/password_change_processor.h
+++ b/chrome/browser/sync/glue/password_change_processor.h
@@ -4,13 +4,11 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_PASSWORD_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_PASSWORD_CHANGE_PROCESSOR_H_
+#pragma once
#include "chrome/browser/sync/glue/change_processor.h"
-#include <vector>
-
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/sync/glue/password_data_type_controller.h b/chrome/browser/sync/glue/password_data_type_controller.h
index f114dcd..f619b85 100644
--- a/chrome/browser/sync/glue/password_data_type_controller.h
+++ b/chrome/browser/sync/glue/password_data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_PASSWORD_DATA_TYPE_CONTROLLER_H__
#define CHROME_BROWSER_SYNC_GLUE_PASSWORD_DATA_TYPE_CONTROLLER_H__
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/glue/password_model_associator.cc b/chrome/browser/sync/glue/password_model_associator.cc
index fa2d9eb..4b5940c 100644
--- a/chrome/browser/sync/glue/password_model_associator.cc
+++ b/chrome/browser/sync/glue/password_model_associator.cc
@@ -352,9 +352,9 @@ void PasswordModelAssociator::WriteToSyncNode(
std::string PasswordModelAssociator::MakeTag(
const webkit_glue::PasswordForm& password) {
return MakeTag(password.origin.spec(),
- UTF16ToASCII(password.username_element),
- UTF16ToASCII(password.username_value),
- UTF16ToASCII(password.password_element),
+ UTF16ToUTF8(password.username_element),
+ UTF16ToUTF8(password.username_value),
+ UTF16ToUTF8(password.password_element),
password.signon_realm);
}
diff --git a/chrome/browser/sync/glue/password_model_associator.h b/chrome/browser/sync/glue/password_model_associator.h
index bfcd105..9015e1a 100644
--- a/chrome/browser/sync/glue/password_model_associator.h
+++ b/chrome/browser/sync/glue/password_model_associator.h
@@ -4,15 +4,14 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_PASSWORD_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_PASSWORD_MODEL_ASSOCIATOR_H_
+#pragma once
#include <map>
-#include <set>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/lock.h"
-#include "base/scoped_ptr.h"
#include "base/task.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_types.h"
diff --git a/chrome/browser/sync/glue/password_model_worker.cc b/chrome/browser/sync/glue/password_model_worker.cc
index 5e7669c..9c5b0d6 100644
--- a/chrome/browser/sync/glue/password_model_worker.cc
+++ b/chrome/browser/sync/glue/password_model_worker.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/sync/glue/password_model_worker.h"
#include "base/callback.h"
-#include "base/logging.h"
#include "base/ref_counted.h"
#include "base/task.h"
#include "base/waitable_event.h"
@@ -17,6 +16,7 @@ namespace browser_sync {
PasswordModelWorker::PasswordModelWorker(PasswordStore* password_store)
: password_store_(password_store) {
+ DCHECK(password_store);
}
void PasswordModelWorker::DoWorkAndWaitUntilDone(Callback0::Type* work) {
diff --git a/chrome/browser/sync/glue/password_model_worker.h b/chrome/browser/sync/glue/password_model_worker.h
index 31637cd..cd55c79 100644
--- a/chrome/browser/sync/glue/password_model_worker.h
+++ b/chrome/browser/sync/glue/password_model_worker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_PASSWORD_MODEL_WORKER_H_
#define CHROME_BROWSER_SYNC_GLUE_PASSWORD_MODEL_WORKER_H_
+#pragma once
#include "chrome/browser/sync/engine/model_safe_worker.h"
diff --git a/chrome/browser/sync/glue/preference_change_processor.cc b/chrome/browser/sync/glue/preference_change_processor.cc
index 2b8a6fe..874f786 100644
--- a/chrome/browser/sync/glue/preference_change_processor.cc
+++ b/chrome/browser/sync/glue/preference_change_processor.cc
@@ -7,6 +7,7 @@
#include <set>
#include <string>
+#include "base/auto_reset.h"
#include "base/json/json_reader.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
@@ -25,7 +26,8 @@ PreferenceChangeProcessor::PreferenceChangeProcessor(
UnrecoverableErrorHandler* error_handler)
: ChangeProcessor(error_handler),
pref_service_(NULL),
- model_associator_(model_associator) {
+ model_associator_(model_associator),
+ processing_pref_change_(false) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
DCHECK(model_associator);
DCHECK(error_handler);
@@ -43,27 +45,31 @@ void PreferenceChangeProcessor::Observe(NotificationType type,
DCHECK(NotificationType::PREF_CHANGED == type);
DCHECK_EQ(pref_service_, Source<PrefService>(source).ptr());
- std::wstring* name = Details<std::wstring>(details).ptr();
+ // Avoid recursion.
+ if (processing_pref_change_)
+ return;
+
+ AutoReset<bool> guard(&processing_pref_change_, true);
+ std::string* name = Details<std::string>(details).ptr();
const PrefService::Preference* preference =
pref_service_->FindPreference((*name).c_str());
DCHECK(preference);
-
- // TODO(mnissler): Detect preference->IsUserControlled() state changes here
- // and call into PreferenceModelAssociator to associate/disassociate sync
- // nodes when the state changes.
-
- // Do not pollute sync data with values coming from policy, extensions or the
- // commandline.
- if (!preference->IsUserModifiable())
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(*name);
+ bool user_modifiable = preference->IsUserModifiable();
+ if (!user_modifiable) {
+ // We do not track preferences the user cannot change.
+ model_associator_->Disassociate(sync_id);
return;
+ }
sync_api::WriteTransaction trans(share_handle());
sync_api::WriteNode node(&trans);
- // Since we don't create sync nodes for preferences that still have
- // their default values, this changed preference may not have a sync
- // node yet. If not, create it.
- int64 sync_id = model_associator_->GetSyncIdFromChromeId(*name);
+ // Since we don't create sync nodes for preferences that are not under control
+ // of the user or still have their default value, this changed preference may
+ // not have a sync node yet. If so, we create a node. Similarly, a preference
+ // may become user-modifiable (e.g. due to laxer policy configuration), in
+ // which case we also need to create a sync node and associate it.
if (sync_api::kInvalidId == sync_id) {
sync_api::ReadNode root(&trans);
if (!root.InitByTagLookup(browser_sync::kPreferencesTag)) {
@@ -71,21 +77,21 @@ void PreferenceChangeProcessor::Observe(NotificationType type,
return;
}
- std::string tag = WideToUTF8(*name);
- if (!node.InitUniqueByCreation(syncable::PREFERENCES, root, tag)) {
- error_handler()->OnUnrecoverableError(
- FROM_HERE,
- "Failed to create preference sync node.");
- return;
- }
-
- model_associator_->Associate(preference, node.GetId());
- } else {
- if (!node.InitByIdLookup(sync_id)) {
+ // InitPrefNodeAndAssociate takes care of writing the value to the sync
+ // node if appropriate.
+ if (!model_associator_->InitPrefNodeAndAssociate(&trans,
+ root,
+ preference)) {
error_handler()->OnUnrecoverableError(FROM_HERE,
- "Preference node lookup failed.");
- return;
+ "Can't create sync node.");
}
+ return;
+ }
+
+ if (!node.InitByIdLookup(sync_id)) {
+ error_handler()->OnUnrecoverableError(FROM_HERE,
+ "Preference node lookup failed.");
+ return;
}
if (!PreferenceModelAssociator::WritePreferenceToNode(
@@ -127,7 +133,7 @@ void PreferenceChangeProcessor::ApplyChangesFromSyncModel(
}
DCHECK(syncable::PREFERENCES == node.GetModelType());
- std::wstring name;
+ std::string name;
scoped_ptr<Value> value(ReadPreference(&node, &name));
// Skip values we can't deserialize.
if (!value.get())
@@ -138,7 +144,7 @@ void PreferenceChangeProcessor::ApplyChangesFromSyncModel(
// client and a Windows client, the Windows client does not
// support kShowPageOptionsButtons. Ignore updates from these
// preferences.
- const wchar_t* pref_name = name.c_str();
+ const char* pref_name = name.c_str();
if (model_associator_->synced_preferences().count(pref_name) == 0)
continue;
@@ -171,7 +177,7 @@ void PreferenceChangeProcessor::ApplyChangesFromSyncModel(
Value* PreferenceChangeProcessor::ReadPreference(
sync_api::ReadNode* node,
- std::wstring* name) {
+ std::string* name) {
const sync_pb::PreferenceSpecifics& preference(
node->GetPreferenceSpecifics());
base::JSONReader reader;
@@ -182,13 +188,14 @@ Value* PreferenceChangeProcessor::ReadPreference(
error_handler()->OnUnrecoverableError(FROM_HERE, err);
return NULL;
}
- *name = UTF8ToWide(preference.name());
+ *name = preference.name();
return value.release();
}
void PreferenceChangeProcessor::StartImpl(Profile* profile) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
pref_service_ = profile->GetPrefs();
+ registrar_.Init(pref_service_);
StartObserving();
}
@@ -201,19 +208,19 @@ void PreferenceChangeProcessor::StopImpl() {
void PreferenceChangeProcessor::StartObserving() {
DCHECK(pref_service_);
- for (std::set<std::wstring>::const_iterator it =
+ for (std::set<std::string>::const_iterator it =
model_associator_->synced_preferences().begin();
it != model_associator_->synced_preferences().end(); ++it) {
- pref_service_->AddPrefObserver((*it).c_str(), this);
+ registrar_.Add((*it).c_str(), this);
}
}
void PreferenceChangeProcessor::StopObserving() {
DCHECK(pref_service_);
- for (std::set<std::wstring>::const_iterator it =
+ for (std::set<std::string>::const_iterator it =
model_associator_->synced_preferences().begin();
it != model_associator_->synced_preferences().end(); ++it) {
- pref_service_->RemovePrefObserver((*it).c_str(), this);
+ registrar_.Remove((*it).c_str(), this);
}
}
diff --git a/chrome/browser/sync/glue/preference_change_processor.h b/chrome/browser/sync/glue/preference_change_processor.h
index b604c96..1ef88da 100644
--- a/chrome/browser/sync/glue/preference_change_processor.h
+++ b/chrome/browser/sync/glue/preference_change_processor.h
@@ -1,14 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_GLUE_PREFERENCE_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_PREFERENCE_CHANGE_PROCESSOR_H_
+#pragma once
#include <string>
-#include "base/scoped_ptr.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
@@ -46,7 +47,7 @@ class PreferenceChangeProcessor : public ChangeProcessor,
virtual void StopImpl();
private:
- Value* ReadPreference(sync_api::ReadNode* node, std::wstring* name);
+ Value* ReadPreference(sync_api::ReadNode* node, std::string* name);
void StartObserving();
void StopObserving();
@@ -57,6 +58,11 @@ class PreferenceChangeProcessor : public ChangeProcessor,
// The two models should be associated according to this ModelAssociator.
PreferenceModelAssociator* model_associator_;
+ // Whether we are currently processing a preference change notification.
+ bool processing_pref_change_;
+
+ PrefChangeRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(PreferenceChangeProcessor);
};
diff --git a/chrome/browser/sync/glue/preference_data_type_controller.h b/chrome/browser/sync/glue/preference_data_type_controller.h
index d38bf36..bc2b93d 100644
--- a/chrome/browser/sync/glue/preference_data_type_controller.h
+++ b/chrome/browser/sync/glue/preference_data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_PREFERENCE_DATA_TYPE_CONTROLLER_H__
#define CHROME_BROWSER_SYNC_GLUE_PREFERENCE_DATA_TYPE_CONTROLLER_H__
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/sync/glue/preference_model_associator.cc b/chrome/browser/sync/glue/preference_model_associator.cc
index 5dad397..8efa848 100644
--- a/chrome/browser/sync/glue/preference_model_associator.cc
+++ b/chrome/browser/sync/glue/preference_model_associator.cc
@@ -9,7 +9,7 @@
#include "base/values.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/synchronized_preferences.h"
@@ -43,6 +43,68 @@ PreferenceModelAssociator::~PreferenceModelAssociator() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
}
+bool PreferenceModelAssociator::InitPrefNodeAndAssociate(
+ sync_api::WriteTransaction* trans,
+ const sync_api::BaseNode& root,
+ const PrefService::Preference* pref) {
+ DCHECK(pref);
+
+ PrefService* pref_service = sync_service_->profile()->GetPrefs();
+ base::JSONReader reader;
+ std::string tag = pref->name();
+ sync_api::WriteNode node(trans);
+ if (node.InitByClientTagLookup(syncable::PREFERENCES, tag)) {
+ // The server has a value for the preference.
+ const sync_pb::PreferenceSpecifics& preference(
+ node.GetPreferenceSpecifics());
+ DCHECK_EQ(tag, preference.name());
+
+ if (pref->IsUserModifiable()) {
+ scoped_ptr<Value> value(
+ reader.JsonToValue(preference.value(), false, false));
+ std::string pref_name = preference.name();
+ if (!value.get()) {
+ LOG(ERROR) << "Failed to deserialize preference value: "
+ << reader.GetErrorMessage();
+ return false;
+ }
+
+ // Merge the server value of this preference with the local value.
+ scoped_ptr<Value> new_value(MergePreference(*pref, *value));
+
+ // Update the local preference based on what we got from the
+ // sync server.
+ if (!pref->GetValue()->Equals(new_value.get()))
+ pref_service->Set(pref_name.c_str(), *new_value);
+
+ AfterUpdateOperations(pref_name);
+
+ // If the merge resulted in an updated value, write it back to
+ // the sync node.
+ if (!value->Equals(new_value.get()) &&
+ !WritePreferenceToNode(pref->name(), *new_value, &node))
+ return false;
+ }
+ Associate(pref, node.GetId());
+ } else if (pref->IsUserControlled()) {
+ // The server doesn't have a value, but we have a user-controlled value,
+ // so we push it to the server.
+ sync_api::WriteNode write_node(trans);
+ if (!write_node.InitUniqueByCreation(syncable::PREFERENCES, root, tag)) {
+ LOG(ERROR) << "Failed to create preference sync node.";
+ return false;
+ }
+
+ // Update the sync node with the local value for this preference.
+ if (!WritePreferenceToNode(pref->name(), *pref->GetValue(), &write_node))
+ return false;
+
+ Associate(pref, write_node.GetId());
+ }
+
+ return true;
+}
+
bool PreferenceModelAssociator::AssociateModels() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
PrefService* pref_service = sync_service_->profile()->GetPrefs();
@@ -63,63 +125,11 @@ bool PreferenceModelAssociator::AssociateModels() {
return false;
}
- base::JSONReader reader;
- for (std::set<std::wstring>::iterator it = synced_preferences_.begin();
+ for (std::set<std::string>::iterator it = synced_preferences_.begin();
it != synced_preferences_.end(); ++it) {
- std::string tag = WideToUTF8(*it);
const PrefService::Preference* pref =
pref_service->FindPreference((*it).c_str());
- DCHECK(pref);
-
- sync_api::WriteNode node(&trans);
- if (node.InitByClientTagLookup(syncable::PREFERENCES, tag)) {
- // The server has a value for the preference.
- const sync_pb::PreferenceSpecifics& preference(
- node.GetPreferenceSpecifics());
- DCHECK_EQ(tag, preference.name());
-
- if (pref->IsUserModifiable()) {
- scoped_ptr<Value> value(
- reader.JsonToValue(preference.value(), false, false));
- std::wstring pref_name = UTF8ToWide(preference.name());
- if (!value.get()) {
- LOG(ERROR) << "Failed to deserialize preference value: "
- << reader.GetErrorMessage();
- return false;
- }
-
- // Merge the server value of this preference with the local value.
- scoped_ptr<Value> new_value(MergePreference(*pref, *value));
-
- // Update the local preference based on what we got from the
- // sync server.
- if (!pref->GetValue()->Equals(new_value.get()))
- pref_service->Set(pref_name.c_str(), *new_value);
-
- AfterUpdateOperations(pref_name);
-
- // If the merge resulted in an updated value, write it back to
- // the sync node.
- if (!value->Equals(new_value.get()) &&
- !WritePreferenceToNode(pref->name(), *new_value, &node))
- return false;
- }
- Associate(pref, node.GetId());
- } else if (pref->IsUserControlled()) {
- // The server doesn't have a value, but we have a user-controlled value,
- // so we push it to the server.
- sync_api::WriteNode write_node(&trans);
- if (!write_node.InitUniqueByCreation(syncable::PREFERENCES, root, tag)) {
- LOG(ERROR) << "Failed to create preference sync node.";
- return false;
- }
-
- // Update the sync node with the local value for this preference.
- if (!WritePreferenceToNode(pref->name(), *pref->GetValue(), &write_node))
- return false;
-
- Associate(pref, write_node.GetId());
- }
+ InitPrefNodeAndAssociate(&trans, root, pref);
}
return true;
}
@@ -156,7 +166,7 @@ bool PreferenceModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
}
int64 PreferenceModelAssociator::GetSyncIdFromChromeId(
- const std::wstring 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;
@@ -195,14 +205,15 @@ bool PreferenceModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
Value* PreferenceModelAssociator::MergePreference(
const PrefService::Preference& local_pref,
const Value& server_value) {
- if (local_pref.name() == prefs::kURLsToRestoreOnStartup ||
- local_pref.name() == prefs::kDesktopNotificationAllowedOrigins ||
- local_pref.name() == prefs::kDesktopNotificationDeniedOrigins) {
+ const std::string& name(local_pref.name());
+ if (name == prefs::kURLsToRestoreOnStartup ||
+ name == prefs::kDesktopNotificationAllowedOrigins ||
+ name == prefs::kDesktopNotificationDeniedOrigins) {
return MergeListValues(*local_pref.GetValue(), server_value);
}
- if (local_pref.name() == prefs::kContentSettingsPatterns ||
- local_pref.name() == prefs::kGeolocationContentSettings) {
+ if (name == prefs::kContentSettingsPatterns ||
+ name == prefs::kGeolocationContentSettings) {
return MergeDictionaryValues(*local_pref.GetValue(), server_value);
}
@@ -211,7 +222,7 @@ Value* PreferenceModelAssociator::MergePreference(
}
bool PreferenceModelAssociator::WritePreferenceToNode(
- const std::wstring& name,
+ const std::string& name,
const Value& value,
sync_api::WriteNode* node) {
std::string serialized;
@@ -222,10 +233,11 @@ bool PreferenceModelAssociator::WritePreferenceToNode(
}
sync_pb::PreferenceSpecifics preference;
- preference.set_name(WideToUTF8(name));
+ preference.set_name(name);
preference.set_value(serialized);
node->SetPreferenceSpecifics(preference);
- node->SetTitle(name);
+ // TODO(viettrungluu): eliminate conversion (it's temporary)
+ node->SetTitle(UTF8ToWide(name));
return true;
}
@@ -290,7 +302,7 @@ Value* PreferenceModelAssociator::MergeDictionaryValues(
}
void PreferenceModelAssociator::AfterUpdateOperations(
- const std::wstring& pref_name) {
+ const std::string& pref_name) {
// The bookmark bar visibility preference requires a special
// notification to update the UI.
if (0 == pref_name.compare(prefs::kShowBookmarkBar)) {
diff --git a/chrome/browser/sync/glue/preference_model_associator.h b/chrome/browser/sync/glue/preference_model_associator.h
index e37a533..15f3001 100644
--- a/chrome/browser/sync/glue/preference_model_associator.h
+++ b/chrome/browser/sync/glue/preference_model_associator.h
@@ -1,17 +1,17 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_GLUE_PREFERENCE_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_PREFERENCE_MODEL_ASSOCIATOR_H_
+#pragma once
#include <map>
#include <set>
#include <string>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/unrecoverable_error_handler.h"
@@ -20,6 +20,7 @@ class Value;
namespace sync_api {
class WriteNode;
+class WriteTransaction;
}
namespace browser_sync {
@@ -32,7 +33,7 @@ static const char kPreferencesTag[] = "google_chrome_preferences";
// * Algorithm to associate preferences model and sync model.
class PreferenceModelAssociator
: public PerDataTypeAssociatorInterface<PrefService::Preference,
- std::wstring> {
+ std::string> {
public:
static syncable::ModelType model_type() { return syncable::PREFERENCES; }
explicit PreferenceModelAssociator(ProfileSyncService* sync_service);
@@ -41,10 +42,16 @@ class PreferenceModelAssociator
// Returns the list of preference names that should be monitored for
// changes. Only preferences that are registered will be in this
// list.
- const std::set<std::wstring>& synced_preferences() {
+ const std::set<std::string>& synced_preferences() {
return synced_preferences_;
}
+ // Create an association for a given preference. A sync node is created if
+ // necessary and the value is read from or written to the node as appropriate.
+ bool InitPrefNodeAndAssociate(sync_api::WriteTransaction* trans,
+ const sync_api::BaseNode& root,
+ const PrefService::Preference* pref);
+
// PerDataTypeAssociatorInterface implementation.
//
// Iterates through the sync model looking for matched pairs of items.
@@ -69,14 +76,14 @@ class PreferenceModelAssociator
}
// Not implemented.
- virtual bool InitSyncNodeFromChromeId(std::wstring node_id,
+ virtual bool InitSyncNodeFromChromeId(std::string node_id,
sync_api::BaseNode* sync_node) {
return false;
}
// 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::wstring node_id);
+ virtual int64 GetSyncIdFromChromeId(std::string node_id);
// Associates the given preference name with the given sync id.
virtual void Associate(const PrefService::Preference* node, int64 sync_id);
@@ -99,28 +106,28 @@ class PreferenceModelAssociator
// Writes the value of pref into the specified node. Returns true
// upon success.
- static bool WritePreferenceToNode(const std::wstring& name,
+ static bool WritePreferenceToNode(const std::string& name,
const Value& value,
sync_api::WriteNode* node);
// Perform any additional operations that need to happen after a preference
// has been updated.
- void AfterUpdateOperations(const std::wstring& pref_name);
+ void AfterUpdateOperations(const std::string& pref_name);
protected:
// Returns sync service instance.
ProfileSyncService* sync_service() { return sync_service_; }
private:
- typedef std::map<std::wstring, int64> PreferenceNameToSyncIdMap;
- typedef std::map<int64, std::wstring> SyncIdToPreferenceNameMap;
+ typedef std::map<std::string, int64> PreferenceNameToSyncIdMap;
+ typedef std::map<int64, std::string> SyncIdToPreferenceNameMap;
static Value* MergeListValues(const Value& from_value, const Value& to_value);
static Value* MergeDictionaryValues(const Value& from_value,
const Value& to_value);
ProfileSyncService* sync_service_;
- std::set<std::wstring> synced_preferences_;
+ std::set<std::string> synced_preferences_;
int64 preferences_node_id_;
PreferenceNameToSyncIdMap id_map_;
diff --git a/chrome/browser/sync/glue/preference_model_associator_unittest.cc b/chrome/browser/sync/glue/preference_model_associator_unittest.cc
index 032f0ea..b3dca08 100644
--- a/chrome/browser/sync/glue/preference_model_associator_unittest.cc
+++ b/chrome/browser/sync/glue/preference_model_associator_unittest.cc
@@ -18,8 +18,8 @@ class AbstractPreferenceMergeTest : public testing::Test {
}
void SetContentPattern(DictionaryValue* patterns_dict,
- const std::wstring& expression,
- const std::wstring& content_type,
+ const std::string& expression,
+ const std::string& content_type,
int setting) {
DictionaryValue* expression_dict;
bool found =
@@ -34,17 +34,17 @@ class AbstractPreferenceMergeTest : public testing::Test {
Value::CreateIntegerValue(setting));
}
- void SetPrefToNull(const std::wstring& pref_name) {
+ void SetPrefToNull(const std::string& pref_name) {
scoped_ptr<Value> null_value(Value::CreateNullValue());
pref_service_->Set(pref_name.c_str(), *null_value);
}
- void SetPrefToEmpty(const std::wstring& pref_name) {
+ void SetPrefToEmpty(const std::string& pref_name) {
scoped_ptr<Value> empty_value;
const PrefService::Preference* pref =
pref_service_->FindPreference(pref_name.c_str());
ASSERT_TRUE(pref);
- Value::ValueType type = pref->type();
+ Value::ValueType type = pref->GetType();
if (type == Value::TYPE_DICTIONARY)
empty_value.reset(new DictionaryValue);
else if (type == Value::TYPE_LIST)
@@ -198,11 +198,11 @@ TEST_F(ListPreferenceMergeTest, Equals) {
class DictionaryPreferenceMergeTest : public AbstractPreferenceMergeTest {
protected:
DictionaryPreferenceMergeTest() :
- expression0_(L"expression0"),
- expression1_(L"expression1"),
- expression2_(L"expression2"),
- content_type0_(L"content_type0"),
- content_type1_(L"content_type1") {}
+ expression0_("expression0"),
+ expression1_("expression1"),
+ expression2_("expression2"),
+ content_type0_("content_type0"),
+ content_type1_("content_type1") {}
virtual void SetUp() {
AbstractPreferenceMergeTest::SetUp();
@@ -211,11 +211,11 @@ class DictionaryPreferenceMergeTest : public AbstractPreferenceMergeTest {
SetContentPattern(&server_patterns_, expression1_, content_type0_, 1);
}
- std::wstring expression0_;
- std::wstring expression1_;
- std::wstring expression2_;
- std::wstring content_type0_;
- std::wstring content_type1_;
+ std::string expression0_;
+ std::string expression1_;
+ std::string expression2_;
+ std::string content_type0_;
+ std::string content_type1_;
DictionaryValue server_patterns_;
};
@@ -340,11 +340,11 @@ TEST_F(DictionaryPreferenceMergeTest, ConflictButServerWins) {
class IndividualPreferenceMergeTest : public AbstractPreferenceMergeTest {
protected:
IndividualPreferenceMergeTest() :
- url0_(L"http://example.com/server0"),
- url1_(L"http://example.com/server1"),
- expression0_(L"expression0"),
- expression1_(L"expression1"),
- content_type0_(L"content_type0") {}
+ url0_("http://example.com/server0"),
+ url1_("http://example.com/server1"),
+ expression0_("expression0"),
+ expression1_("expression1"),
+ content_type0_("content_type0") {}
virtual void SetUp() {
AbstractPreferenceMergeTest::SetUp();
@@ -352,7 +352,7 @@ class IndividualPreferenceMergeTest : public AbstractPreferenceMergeTest {
SetContentPattern(&server_patterns_, expression0_, content_type0_, 1);
}
- bool MergeListPreference(const wchar_t* pref) {
+ bool MergeListPreference(const char* pref) {
ListValue* local_list_value = pref_service_->GetMutableList(pref);
local_list_value->Append(Value::CreateStringValue(url1_));
@@ -366,7 +366,7 @@ class IndividualPreferenceMergeTest : public AbstractPreferenceMergeTest {
return merged_value->Equals(&expected);
}
- bool MergeDictionaryPreference(const wchar_t* pref) {
+ bool MergeDictionaryPreference(const char* pref) {
DictionaryValue* local_dict_value =
pref_service_->GetMutableDictionary(pref);
SetContentPattern(local_dict_value, expression1_, content_type0_, 1);
@@ -381,11 +381,11 @@ class IndividualPreferenceMergeTest : public AbstractPreferenceMergeTest {
return merged_value->Equals(&expected);
}
- std::wstring url0_;
- std::wstring url1_;
- std::wstring expression0_;
- std::wstring expression1_;
- std::wstring content_type0_;
+ std::string url0_;
+ std::string url1_;
+ std::string expression0_;
+ std::string expression1_;
+ std::string content_type0_;
ListValue server_url_list_;
DictionaryValue server_patterns_;
};
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 78cfc54..74a8c47 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -6,11 +6,13 @@
#include <algorithm>
+#include "base/command_line.h"
#include "base/file_util.h"
-#include "base/file_version_info.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_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/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
@@ -20,24 +22,27 @@
#include "chrome/browser/sync/glue/http_bridge.h"
#include "chrome/browser/sync/glue/password_model_worker.h"
#include "chrome/browser/sync/sessions/session_state.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
#include "webkit/glue/webkit_glue.h"
static const int kSaveChangesIntervalSeconds = 10;
-static const char kGaiaServiceId[] = "chromiumsync";
-static const char kGaiaSourceForChrome[] = "ChromiumBrowser";
static const FilePath::CharType kSyncDataFolderName[] =
FILE_PATH_LITERAL("Sync Data");
using browser_sync::DataTypeController;
+typedef TokenService::TokenAvailableDetails TokenAvailableDetails;
typedef GoogleServiceAuthError AuthError;
namespace browser_sync {
using sessions::SyncSessionSnapshot;
+using sync_api::SyncCredentials;
SyncBackendHost::SyncBackendHost(
SyncFrontend* frontend,
@@ -50,7 +55,8 @@ SyncBackendHost::SyncBackendHost(
frontend_(frontend),
sync_data_folder_path_(profile_path.Append(kSyncDataFolderName)),
data_type_controllers_(data_type_controllers),
- last_auth_error_(AuthError::None()) {
+ last_auth_error_(AuthError::None()),
+ syncapi_initialized_(false) {
core_ = new Core(this);
}
@@ -58,8 +64,10 @@ SyncBackendHost::SyncBackendHost(
SyncBackendHost::SyncBackendHost()
: core_thread_("Chrome_SyncCoreThread"),
frontend_loop_(MessageLoop::current()),
+ profile_(NULL),
frontend_(NULL),
- last_auth_error_(AuthError::None()) {
+ last_auth_error_(AuthError::None()),
+ syncapi_initialized_(false) {
}
SyncBackendHost::~SyncBackendHost() {
@@ -71,12 +79,9 @@ void SyncBackendHost::Initialize(
const GURL& sync_service_url,
const syncable::ModelTypeSet& types,
URLRequestContextGetter* baseline_context_getter,
- const std::string& lsid,
+ const SyncCredentials& credentials,
bool delete_sync_data_folder,
- bool invalidate_sync_login,
- bool invalidate_sync_xmpp_login,
- bool use_chrome_async_socket,
- NotificationMethod notification_method) {
+ const notifier::NotifierOptions& notifier_options) {
if (!core_thread_.Start())
return;
@@ -92,9 +97,15 @@ void SyncBackendHost::Initialize(
profile_->GetHistoryService(Profile::IMPLICIT_ACCESS));
registrar_.workers[GROUP_UI] = new UIModelWorker(frontend_loop_);
registrar_.workers[GROUP_PASSIVE] = new ModelSafeWorker();
- registrar_.workers[GROUP_PASSWORD] =
- new PasswordModelWorker(
- profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS));
+
+ PasswordStore* password_store =
+ profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS);
+ if (password_store) {
+ registrar_.workers[GROUP_PASSWORD] =
+ new PasswordModelWorker(password_store);
+ } else {
+ LOG(WARNING) << "Password store not initialized, cannot sync passwords";
+ }
// Any datatypes that we want the syncer to pull down must
// be in the routing_info map. We set them to group passive, meaning that
@@ -104,26 +115,53 @@ void SyncBackendHost::Initialize(
registrar_.routing_info[(*it)] = GROUP_PASSIVE;
}
+ // TODO(tim): This should be encryption-specific instead of passwords
+ // specific. For now we have to do this to avoid NIGORI node lookups when
+ // we haven't downloaded that node.
+ if (profile_->GetPrefs()->GetBoolean(prefs::kSyncPasswords)) {
+ registrar_.routing_info[syncable::NIGORI] = GROUP_PASSIVE;
+ }
+
+ InitCore(Core::DoInitializeOptions(
+ sync_service_url,
+ MakeHttpBridgeFactory(baseline_context_getter),
+ credentials,
+ delete_sync_data_folder,
+ notifier_options,
+ RestoreEncryptionBootstrapToken(),
+ false));
+}
+
+void SyncBackendHost::PersistEncryptionBootstrapToken(
+ const std::string& token) {
+ PrefService* prefs = profile_->GetPrefs();
+
+ prefs->SetString(prefs::kEncryptionBootstrapToken, token);
+ prefs->ScheduleSavePersistentPrefs();
+}
+
+std::string SyncBackendHost::RestoreEncryptionBootstrapToken() {
+ PrefService* prefs = profile_->GetPrefs();
+ std::string token = prefs->GetString(prefs::kEncryptionBootstrapToken);
+ return token;
+}
+
+sync_api::HttpPostProviderFactory* SyncBackendHost::MakeHttpBridgeFactory(
+ URLRequestContextGetter* getter) {
+ return new HttpBridgeFactory(getter);
+}
+
+void SyncBackendHost::InitCore(const Core::DoInitializeOptions& options) {
core_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoInitialize,
- Core::DoInitializeOptions(
- sync_service_url, lsid.empty(),
- new HttpBridgeFactory(baseline_context_getter),
- new HttpBridgeFactory(baseline_context_getter),
- lsid,
- delete_sync_data_folder,
- invalidate_sync_login,
- invalidate_sync_xmpp_login,
- use_chrome_async_socket,
- notification_method)));
-}
-
-void SyncBackendHost::Authenticate(const std::string& username,
- const std::string& password,
- const std::string& captcha) {
+ options));
+}
+
+void SyncBackendHost::UpdateCredentials(const SyncCredentials& credentials) {
core_thread_.message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoAuthenticate,
- username, password, captcha));
+ NewRunnableMethod(core_.get(),
+ &SyncBackendHost::Core::DoUpdateCredentials,
+ credentials));
}
void SyncBackendHost::StartSyncingWithServer() {
@@ -187,30 +225,31 @@ void SyncBackendHost::ConfigureDataTypes(const syncable::ModelTypeSet& types,
CancelableTask* ready_task) {
// Only one configure is allowed at a time.
DCHECK(!configure_ready_task_.get());
- AutoLock lock(registrar_lock_);
- bool has_new = false;
-
- for (DataTypeController::TypeMap::const_iterator it =
- data_type_controllers_.begin();
- it != data_type_controllers_.end(); ++it) {
- syncable::ModelType type = (*it).first;
-
- // If a type is not specified, remove it from the routing_info.
- if (types.count(type) == 0) {
- registrar_.routing_info.erase(type);
- } else {
- // Add a newly specified data type as GROUP_PASSIVE into the
- // routing_info, if it does not already exist.
- if (registrar_.routing_info.count(type) == 0) {
- registrar_.routing_info[type] = GROUP_PASSIVE;
- has_new = true;
+ DCHECK(syncapi_initialized_);
+
+ {
+ AutoLock lock(registrar_lock_);
+ for (DataTypeController::TypeMap::const_iterator it =
+ data_type_controllers_.begin();
+ it != data_type_controllers_.end(); ++it) {
+ syncable::ModelType type = (*it).first;
+
+ // If a type is not specified, remove it from the routing_info.
+ if (types.count(type) == 0) {
+ registrar_.routing_info.erase(type);
+ } else {
+ // Add a newly specified data type as GROUP_PASSIVE into the
+ // routing_info, if it does not already exist.
+ if (registrar_.routing_info.count(type) == 0) {
+ registrar_.routing_info[type] = GROUP_PASSIVE;
+ }
}
}
}
// If no new data types were added to the passive group, no need to
// wait for the syncer.
- if (!has_new) {
+ if (core_->syncapi()->InitialSyncEndedForAllEnabledTypes()) {
ready_task->Run();
delete ready_task;
return;
@@ -218,7 +257,7 @@ void SyncBackendHost::ConfigureDataTypes(const syncable::ModelTypeSet& types,
// Save the task here so we can run it when the syncer finishes
// initializing the new data types. It will be run only when the
- // set of initially sycned data types matches the types requested in
+ // set of initially synced data types matches the types requested in
// this configure.
configure_ready_task_.reset(ready_task);
configure_initial_sync_types_ = types;
@@ -228,6 +267,10 @@ void SyncBackendHost::ConfigureDataTypes(const syncable::ModelTypeSet& types,
// downloading updates for newly added data types. Once this is
// complete, the configure_ready_task_ is run via an
// OnInitializationComplete notification.
+ RequestNudge();
+}
+
+void SyncBackendHost::RequestNudge() {
core_thread_.message_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(), &SyncBackendHost::Core::DoRequestNudge));
}
@@ -278,6 +321,16 @@ bool SyncBackendHost::RequestResume() {
return true;
}
+bool SyncBackendHost::RequestClearServerData() {
+ core_thread_.message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(core_.get(),
+ &SyncBackendHost::Core::DoRequestClearServerData));
+ return true;
+}
+
+SyncBackendHost::Core::~Core() {
+}
+
void SyncBackendHost::Core::NotifyPaused() {
NotificationService::current()->Notify(NotificationType::SYNC_PAUSED,
NotificationService::AllSources(),
@@ -293,30 +346,45 @@ void SyncBackendHost::Core::NotifyResumed() {
void SyncBackendHost::Core::NotifyPassphraseRequired() {
NotificationService::current()->Notify(
NotificationType::SYNC_PASSPHRASE_REQUIRED,
- NotificationService::AllSources(),
+ Source<SyncBackendHost>(host_),
NotificationService::NoDetails());
}
-void SyncBackendHost::Core::NotifyPassphraseAccepted() {
+void SyncBackendHost::Core::NotifyPassphraseAccepted(
+ const std::string& bootstrap_token) {
+ host_->PersistEncryptionBootstrapToken(bootstrap_token);
NotificationService::current()->Notify(
NotificationType::SYNC_PASSPHRASE_ACCEPTED,
- NotificationService::AllSources(),
+ Source<SyncBackendHost>(host_),
NotificationService::NoDetails());
}
+void SyncBackendHost::Core::NotifyUpdatedToken(const std::string& token) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ TokenAvailableDetails details(GaiaConstants::kSyncService, token);
+ NotificationService::current()->Notify(
+ NotificationType::TOKEN_UPDATED,
+ NotificationService::AllSources(),
+ Details<const TokenAvailableDetails>(&details));
+}
+
SyncBackendHost::UserShareHandle SyncBackendHost::GetUserShareHandle() const {
+ DCHECK(syncapi_initialized_);
return core_->syncapi()->GetUserShare();
}
SyncBackendHost::Status SyncBackendHost::GetDetailedStatus() {
+ DCHECK(syncapi_initialized_);
return core_->syncapi()->GetDetailedStatus();
}
SyncBackendHost::StatusSummary SyncBackendHost::GetStatusSummary() {
+ DCHECK(syncapi_initialized_);
return core_->syncapi()->GetStatusSummary();
}
string16 SyncBackendHost::GetAuthenticatedUsername() const {
+ DCHECK(syncapi_initialized_);
return UTF8ToUTF16(core_->syncapi()->GetAuthenticatedUsername());
}
@@ -343,6 +411,11 @@ void SyncBackendHost::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
out->swap(copy);
}
+bool SyncBackendHost::HasUnsyncedItems() const {
+ DCHECK(syncapi_initialized_);
+ return core_->syncapi()->HasUnsyncedItems();
+}
+
SyncBackendHost::Core::Core(SyncBackendHost* backend)
: host_(backend),
syncapi_(new sync_api::SyncManager()) {
@@ -365,15 +438,15 @@ std::string MakeUserAgentForSyncapi() {
#elif defined(OS_MACOSX)
user_agent += "MAC ";
#endif
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- if (version_info == NULL) {
- DLOG(ERROR) << "Unable to create FileVersionInfo object";
+ chrome::VersionInfo version_info;
+ if (!version_info.is_valid()) {
+ DLOG(ERROR) << "Unable to create chrome::VersionInfo object";
return user_agent;
}
- user_agent += WideToASCII(version_info->product_version());
- user_agent += " (" + WideToASCII(version_info->last_change()) + ")";
- if (!version_info->is_official_build())
+ user_agent += version_info.Version();
+ user_agent += " (" + version_info.LastChange() + ")";
+ if (!version_info.IsOfficialBuild())
user_agent += "-devel";
return user_agent;
}
@@ -383,8 +456,9 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
// Blow away the partial or corrupt sync data folder before doing any more
// initialization, if necessary.
- if (options.delete_sync_data_folder)
+ if (options.delete_sync_data_folder) {
DeleteSyncDataFolder();
+ }
// Make sure that the directory exists before initializing the backend.
// If it already exists, this will do no harm.
@@ -393,30 +467,25 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) {
syncapi_->SetObserver(this);
const FilePath& path_str = host_->sync_data_folder_path();
- success = syncapi_->Init(path_str,
+ success = syncapi_->Init(
+ path_str,
(options.service_url.host() + options.service_url.path()).c_str(),
options.service_url.EffectiveIntPort(),
- kGaiaServiceId,
- kGaiaSourceForChrome,
options.service_url.SchemeIsSecure(),
options.http_bridge_factory,
- options.auth_http_bridge_factory,
host_, // ModelSafeWorkerRegistrar.
- options.attempt_last_user_authentication,
- options.invalidate_sync_login,
- options.invalidate_sync_xmpp_login,
MakeUserAgentForSyncapi().c_str(),
- options.lsid.c_str(),
- options.use_chrome_async_socket,
- options.notification_method);
+ options.credentials,
+ options.notifier_options,
+ options.restored_key_for_bootstrapping,
+ options.setup_for_test_mode);
DCHECK(success) << "Syncapi initialization failed!";
}
-void SyncBackendHost::Core::DoAuthenticate(const std::string& username,
- const std::string& password,
- const std::string& captcha) {
+void SyncBackendHost::Core::DoUpdateCredentials(
+ const SyncCredentials& credentials) {
DCHECK(MessageLoop::current() == host_->core_thread_.message_loop());
- syncapi_->Authenticate(username.c_str(), password.c_str(), captcha.c_str());
+ syncapi_->UpdateCredentials(credentials);
}
void SyncBackendHost::Core::DoStartSyncing() {
@@ -452,16 +521,8 @@ void SyncBackendHost::Core::DoShutdown(bool sync_disabled) {
host_ = NULL;
}
-void SyncBackendHost::Core::OnChangesApplied(
- syncable::ModelType model_type,
- const sync_api::BaseTransaction* trans,
- const sync_api::SyncManager::ChangeRecord* changes,
- int change_count) {
- if (!host_ || !host_->frontend_) {
- DCHECK(false) << "OnChangesApplied called after Shutdown?";
- return;
- }
-
+ChangeProcessor* SyncBackendHost::Core::GetProcessor(
+ syncable::ModelType model_type) {
std::map<syncable::ModelType, ChangeProcessor*>::const_iterator it =
host_->processors_.find(model_type);
@@ -473,11 +534,11 @@ void SyncBackendHost::Core::OnChangesApplied(
// the UI thread so we will never drop any changes after model
// association.
if (it == host_->processors_.end())
- return;
+ return NULL;
if (!IsCurrentThreadSafeForModel(model_type)) {
NOTREACHED() << "Changes applied on wrong thread.";
- return;
+ return NULL;
}
// Now that we're sure we're on the correct thread, we can access the
@@ -486,11 +547,44 @@ void SyncBackendHost::Core::OnChangesApplied(
// Ensure the change processor is willing to accept changes.
if (!processor->IsRunning())
+ return NULL;
+
+ return processor;
+}
+
+void SyncBackendHost::Core::OnChangesApplied(
+ syncable::ModelType model_type,
+ const sync_api::BaseTransaction* trans,
+ const sync_api::SyncManager::ChangeRecord* changes,
+ int change_count) {
+ if (!host_ || !host_->frontend_) {
+ DCHECK(false) << "OnChangesApplied called after Shutdown?";
+ return;
+ }
+ ChangeProcessor* processor = GetProcessor(model_type);
+ if (!processor)
return;
processor->ApplyChangesFromSyncModel(trans, changes, change_count);
}
+void SyncBackendHost::Core::OnChangesComplete(
+ syncable::ModelType model_type) {
+ if (!host_ || !host_->frontend_) {
+ DCHECK(false) << "OnChangesComplete called after Shutdown?";
+ return;
+ }
+
+ ChangeProcessor* processor = GetProcessor(model_type);
+ if (!processor)
+ return;
+
+ // This call just notifies the processor that it can commit, it already
+ // buffered any changes it plans to makes so needs no further information.
+ processor->CommitChangesFromSyncModel();
+}
+
+
void SyncBackendHost::Core::OnSyncCycleCompleted(
const SyncSessionSnapshot* snapshot) {
host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
@@ -551,6 +645,7 @@ void SyncBackendHost::Core::HandleInitalizationCompletedOnFrontendLoop() {
void SyncBackendHost::HandleInitializationCompletedOnFrontendLoop() {
if (!frontend_)
return;
+ syncapi_initialized_ = true;
frontend_->OnBackendInitialized();
}
@@ -572,8 +667,7 @@ bool SyncBackendHost::Core::IsCurrentThreadSafeForModel(
void SyncBackendHost::Core::OnAuthError(const AuthError& auth_error) {
- // We could be on SyncEngine_AuthWatcherThread. Post to our core loop so
- // we can modify state.
+ // Post to our core loop so we can modify state. Could be on another thread.
host_->frontend_loop_->PostTask(FROM_HERE,
NewRunnableMethod(this, &Core::HandleAuthErrorEventOnFrontendLoop,
auth_error));
@@ -584,9 +678,11 @@ void SyncBackendHost::Core::OnPassphraseRequired() {
NewRunnableMethod(this, &Core::NotifyPassphraseRequired));
}
-void SyncBackendHost::Core::OnPassphraseAccepted() {
+void SyncBackendHost::Core::OnPassphraseAccepted(
+ const std::string& bootstrap_token) {
host_->frontend_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &Core::NotifyPassphraseAccepted));
+ NewRunnableMethod(this, &Core::NotifyPassphraseAccepted,
+ bootstrap_token));
}
void SyncBackendHost::Core::OnPaused() {
@@ -606,12 +702,39 @@ void SyncBackendHost::Core::OnStopSyncingPermanently() {
&Core::HandleStopSyncingPermanentlyOnFrontendLoop));
}
+void SyncBackendHost::Core::OnUpdatedToken(const std::string& token) {
+ host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &Core::NotifyUpdatedToken, token));
+}
+
+void SyncBackendHost::Core::OnClearServerDataSucceeded() {
+ host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &Core::HandleClearServerDataSucceededOnFrontendLoop));
+}
+
+void SyncBackendHost::Core::OnClearServerDataFailed() {
+ host_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &Core::HandleClearServerDataFailedOnFrontendLoop));
+}
+
void SyncBackendHost::Core::HandleStopSyncingPermanentlyOnFrontendLoop() {
if (!host_ || !host_->frontend_)
return;
host_->frontend_->OnStopSyncingPermanently();
}
+void SyncBackendHost::Core::HandleClearServerDataSucceededOnFrontendLoop() {
+ if (!host_ || !host_->frontend_)
+ return;
+ host_->frontend_->OnClearServerDataSucceeded();
+}
+
+void SyncBackendHost::Core::HandleClearServerDataFailedOnFrontendLoop() {
+ if (!host_ || !host_->frontend_)
+ return;
+ host_->frontend_->OnClearServerDataFailed();
+}
+
void SyncBackendHost::Core::HandleAuthErrorEventOnFrontendLoop(
const GoogleServiceAuthError& new_auth_error) {
if (!host_ || !host_->frontend_)
@@ -633,6 +756,10 @@ void SyncBackendHost::Core::DoRequestNudge() {
syncapi_->RequestNudge();
}
+void SyncBackendHost::Core::DoRequestClearServerData() {
+ syncapi_->RequestClearServerData();
+}
+
void SyncBackendHost::Core::DoRequestResume() {
syncapi_->RequestResume();
}
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 16a9980..3da5648 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_
#define CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_H_
+#pragma once
#include <map>
-#include <set>
#include <string>
#include <vector>
@@ -16,19 +16,24 @@
#include "base/ref_counted.h"
#include "base/thread.h"
#include "base/timer.h"
-#include "chrome/browser/google_service_auth_error.h"
-#include "chrome/browser/sync/notification_method.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/engine/model_safe_worker.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/ui_model_worker.h"
#include "chrome/browser/sync/syncable/model_type.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "googleurl/src/gurl.h"
+#include "jingle/notifier/base/notifier_options.h"
class CancelableTask;
class Profile;
+namespace notifier {
+struct NotifierOptions;
+}
+
namespace browser_sync {
namespace sessions {
@@ -62,6 +67,10 @@ class SyncFrontend {
// be disabled and state cleaned up at once.
virtual void OnStopSyncingPermanently() = 0;
+ // Called to handle success/failure of clearing server data
+ virtual void OnClearServerDataSucceeded() = 0;
+ virtual void OnClearServerDataFailed() = 0;
+
protected:
// Don't delete through SyncFrontend interface.
virtual ~SyncFrontend() {
@@ -101,16 +110,12 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
void Initialize(const GURL& service_url,
const syncable::ModelTypeSet& types,
URLRequestContextGetter* baseline_context_getter,
- const std::string& lsid,
+ const sync_api::SyncCredentials& credentials,
bool delete_sync_data_folder,
- bool invalidate_sync_login,
- bool invalidate_sync_xmpp_login,
- bool use_chrome_async_socket,
- NotificationMethod notification_method);
+ const notifier::NotifierOptions& notifier_options);
- // Called on |frontend_loop_| to kick off asynchronous authentication.
- void Authenticate(const std::string& username, const std::string& password,
- const std::string& captcha);
+ // Called from |frontend_loop| to update SyncCredentials.
+ void UpdateCredentials(const sync_api::SyncCredentials& credentials);
// This starts the SyncerThread running a Syncer object to communicate with
// sync servers. Until this is called, no changes will leave or enter this
@@ -154,6 +159,9 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// notification is sent to the notification service.
virtual bool RequestResume();
+ // Asks the server to clear all data associated with ChromeSync.
+ virtual bool RequestClearServerData();
+
// Called on |frontend_loop_| to obtain a handle to the UserShare needed
// for creating transactions.
UserShareHandle GetUserShareHandle() const;
@@ -178,41 +186,12 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
virtual void GetWorkers(std::vector<browser_sync::ModelSafeWorker*>* out);
virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out);
-#if defined(UNIT_TEST)
- // Called from unit test to bypass authentication and initialize the syncapi
- // to a state suitable for testing but not production.
- void InitializeForTestMode(const std::wstring& test_user,
- sync_api::HttpPostProviderFactory* factory,
- sync_api::HttpPostProviderFactory* auth_factory,
- bool delete_sync_data_folder,
- NotificationMethod notification_method) {
- if (!core_thread_.Start())
- return;
- registrar_.workers[GROUP_UI] = new UIModelWorker(frontend_loop_);
- registrar_.routing_info[syncable::BOOKMARKS] = GROUP_PASSIVE;
- registrar_.routing_info[syncable::PREFERENCES] = GROUP_PASSIVE;
- registrar_.routing_info[syncable::AUTOFILL] = GROUP_PASSIVE;
- registrar_.routing_info[syncable::THEMES] = GROUP_PASSIVE;
- registrar_.routing_info[syncable::TYPED_URLS] = GROUP_PASSIVE;
- registrar_.routing_info[syncable::NIGORI] = GROUP_PASSIVE;
- registrar_.routing_info[syncable::PASSWORDS] = GROUP_PASSIVE;
-
- core_thread_.message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(core_.get(),
- &SyncBackendHost::Core::DoInitializeForTest,
- test_user,
- factory,
- auth_factory,
- delete_sync_data_folder,
- notification_method));
- }
-#endif
- protected:
- // InitializationComplete passes through the SyncBackendHost to forward
- // on to |frontend_|, and so that tests can intercept here if they need to
- // set up initial conditions.
- virtual void HandleInitializationCompletedOnFrontendLoop();
+ // Determines if the underlying sync engine has made any local changes to
+ // items that have not yet been synced with the server.
+ // ONLY CALL THIS IF OnInitializationComplete was called!
+ bool HasUnsyncedItems() const;
+ protected:
// The real guts of SyncBackendHost, to keep the public client API clean.
class Core : public base::RefCountedThreadSafe<SyncBackendHost::Core>,
public sync_api::SyncManager::Observer {
@@ -227,49 +206,48 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
const sync_api::BaseTransaction* trans,
const sync_api::SyncManager::ChangeRecord* changes,
int change_count);
+ virtual void OnChangesComplete(syncable::ModelType model_type);
virtual void OnSyncCycleCompleted(
const sessions::SyncSessionSnapshot* snapshot);
virtual void OnInitializationComplete();
virtual void OnAuthError(const GoogleServiceAuthError& auth_error);
virtual void OnPassphraseRequired();
- virtual void OnPassphraseAccepted();
+ virtual void OnPassphraseAccepted(const std::string& bootstrap_token);
virtual void OnPaused();
virtual void OnResumed();
virtual void OnStopSyncingPermanently();
+ virtual void OnUpdatedToken(const std::string& token);
+ virtual void OnClearServerDataFailed();
+ virtual void OnClearServerDataSucceeded();
struct DoInitializeOptions {
DoInitializeOptions(
const GURL& service_url,
- bool attempt_last_user_authentication,
sync_api::HttpPostProviderFactory* http_bridge_factory,
- sync_api::HttpPostProviderFactory* auth_http_bridge_factory,
- const std::string& lsid,
+ const sync_api::SyncCredentials& credentials,
bool delete_sync_data_folder,
- bool invalidate_sync_login,
- bool invalidate_sync_xmpp_login,
- bool use_chrome_async_socket,
- NotificationMethod notification_method)
+ const notifier::NotifierOptions& notifier_options,
+ std::string restored_key_for_bootstrapping,
+ bool setup_for_test_mode)
: service_url(service_url),
- attempt_last_user_authentication(attempt_last_user_authentication),
http_bridge_factory(http_bridge_factory),
- auth_http_bridge_factory(auth_http_bridge_factory),
- lsid(lsid),
+ credentials(credentials),
delete_sync_data_folder(delete_sync_data_folder),
- invalidate_sync_login(invalidate_sync_login),
- invalidate_sync_xmpp_login(invalidate_sync_xmpp_login),
- use_chrome_async_socket(use_chrome_async_socket),
- notification_method(notification_method) {}
+ notifier_options(notifier_options),
+ restored_key_for_bootstrapping(restored_key_for_bootstrapping),
+ setup_for_test_mode(setup_for_test_mode) {}
GURL service_url;
bool attempt_last_user_authentication;
sync_api::HttpPostProviderFactory* http_bridge_factory;
- sync_api::HttpPostProviderFactory* auth_http_bridge_factory;
+ sync_api::SyncCredentials credentials;
std::string lsid;
bool delete_sync_data_folder;
bool invalidate_sync_login;
bool invalidate_sync_xmpp_login;
- bool use_chrome_async_socket;
- NotificationMethod notification_method;
+ notifier::NotifierOptions notifier_options;
+ std::string restored_key_for_bootstrapping;
+ bool setup_for_test_mode;
};
// Note:
@@ -282,11 +260,9 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// of the syncapi on behalf of SyncBackendHost::Initialize.
void DoInitialize(const DoInitializeOptions& options);
- // Called on our SyncBackendHost's core_thread_ to perform authentication
- // on behalf of SyncBackendHost::Authenticate.
- void DoAuthenticate(const std::string& username,
- const std::string& password,
- const std::string& captcha);
+ // Called on our SyncBackendHost's core_thread_ to perform credential
+ // update on behalf of SyncBackendHost::UpdateCredentials
+ void DoUpdateCredentials(const sync_api::SyncCredentials& credentials);
// Called on the SyncBackendHost core_thread_ to tell the syncapi to start
// syncing (generally after initialization and authentication).
@@ -297,6 +273,7 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
void DoRequestNudge();
void DoRequestPause();
void DoRequestResume();
+ void DoRequestClearServerData();
// Called on our SyncBackendHost's |core_thread_| to set the passphrase
// on behalf of SyncBackendHost::SupplyPassphrase.
@@ -327,24 +304,30 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
#if defined(UNIT_TEST)
// Special form of initialization that does not try and authenticate the
// last known user (since it will fail in test mode) and does some extra
- // setup to nudge the syncapi into a useable state.
+ // setup to nudge the syncapi into a usable state.
void DoInitializeForTest(const std::wstring& test_user,
sync_api::HttpPostProviderFactory* factory,
- sync_api::HttpPostProviderFactory* auth_factory,
- bool delete_sync_data_folder,
- NotificationMethod notification_method) {
- DoInitialize(DoInitializeOptions(GURL(), false, factory, auth_factory,
- std::string(), delete_sync_data_folder,
- false, false, false,
- notification_method));
- syncapi_->SetupForTestMode(test_user);
+ bool delete_sync_data_folder) {
+
+ // Construct dummy credentials for test.
+ sync_api::SyncCredentials credentials;
+ credentials.email = WideToUTF8(test_user);
+ credentials.sync_token = "token";
+ DoInitialize(DoInitializeOptions(GURL(), factory, credentials,
+ delete_sync_data_folder,
+ notifier::NotifierOptions(), "", true));
}
#endif
private:
friend class base::RefCountedThreadSafe<SyncBackendHost::Core>;
+ friend class SyncBackendHostForProfileSyncTest;
+
+ ~Core();
+
+ // Return change processor for a particular model (return NULL on failure).
+ ChangeProcessor* GetProcessor(syncable::ModelType modeltype);
- ~Core() {}
// Sends a SYNC_PAUSED notification to the notification service on
// the UI thread.
@@ -377,7 +360,10 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
void NotifyPassphraseRequired();
// Invoked when the passphrase provided by the user has been accepted.
- void NotifyPassphraseAccepted();
+ void NotifyPassphraseAccepted(const std::string& bootstrap_token);
+
+ // Invoked when an updated token is available from the sync server.
+ void NotifyUpdatedToken(const std::string& token);
// Called from Core::OnSyncCycleCompleted to handle updating frontend
// thread components.
@@ -386,6 +372,10 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
void HandleStopSyncingPermanentlyOnFrontendLoop();
+ // Called to handle success/failure of clearing server data
+ void HandleClearServerDataSucceededOnFrontendLoop();
+ void HandleClearServerDataFailedOnFrontendLoop();
+
// Called from Core::OnInitializationComplete to handle updating
// frontend thread components.
void HandleInitalizationCompletedOnFrontendLoop();
@@ -393,6 +383,9 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// Return true if a model lives on the current thread.
bool IsCurrentThreadSafeForModel(syncable::ModelType model_type);
+ // True if credentials are ready for sync use.
+ bool CredentialsAvailable();
+
// Our parent SyncBackendHost
SyncBackendHost* host_;
@@ -405,6 +398,32 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
DISALLOW_COPY_AND_ASSIGN(Core);
};
+ // InitializationComplete passes through the SyncBackendHost to forward
+ // on to |frontend_|, and so that tests can intercept here if they need to
+ // set up initial conditions.
+ virtual void HandleInitializationCompletedOnFrontendLoop();
+
+ // Posts a nudge request on the core thread.
+ virtual void RequestNudge();
+
+ // Allows tests to perform alternate core initialization work.
+ virtual void InitCore(const Core::DoInitializeOptions& options);
+
+ // Factory method for HttpPostProviderFactories.
+ virtual sync_api::HttpPostProviderFactory* MakeHttpBridgeFactory(
+ URLRequestContextGetter* getter);
+
+ MessageLoop* core_loop() { return core_thread_.message_loop(); }
+
+ void set_syncapi_initialized() { syncapi_initialized_ = true; }
+
+ // Helpers to persist a token that can be used to bootstrap sync encryption
+ // across browser restart to avoid requiring the user to re-enter their
+ // passphrase. |token| must be valid UTF-8 as we use the PrefService for
+ // storage.
+ void PersistEncryptionBootstrapToken(const std::string& token);
+ std::string RestoreEncryptionBootstrapToken();
+
// Our core, which communicates directly to the syncapi.
scoped_refptr<Core> core_;
@@ -475,6 +494,9 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
// UI-thread cache of the last SyncSessionSnapshot received from syncapi.
scoped_ptr<sessions::SyncSessionSnapshot> last_snapshot_;
+ // Whether we've processed the initialization complete callback.
+ bool syncapi_initialized_;
+
DISALLOW_COPY_AND_ASSIGN(SyncBackendHost);
};
diff --git a/chrome/browser/sync/glue/sync_backend_host_mock.h b/chrome/browser/sync/glue/sync_backend_host_mock.h
index 3b2e3b3..4035f97 100644
--- a/chrome/browser/sync/glue/sync_backend_host_mock.h
+++ b/chrome/browser/sync/glue/sync_backend_host_mock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_MOCK_H__
#define CHROME_BROWSER_SYNC_GLUE_SYNC_BACKEND_HOST_MOCK_H__
+#pragma once
#include <set>
diff --git a/chrome/browser/sync/glue/synchronized_preferences.h b/chrome/browser/sync/glue/synchronized_preferences.h
index 3d25956..380cf81 100644
--- a/chrome/browser/sync/glue/synchronized_preferences.h
+++ b/chrome/browser/sync/glue/synchronized_preferences.h
@@ -7,13 +7,14 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_SYNCHRONIZED_PREFERENCES_H_
#define CHROME_BROWSER_SYNC_GLUE_SYNCHRONIZED_PREFERENCES_H_
+#pragma once
#include "chrome/browser/translate/translate_prefs.h"
#include "chrome/common/pref_names.h"
namespace browser_sync {
-static const wchar_t* kSynchronizedPreferences[] = {
+static const char* kSynchronizedPreferences[] = {
// Options dialog: Basics tab.
prefs::kRestoreOnStartup,
prefs::kURLsToRestoreOnStartup,
@@ -94,7 +95,9 @@ static const wchar_t* kSynchronizedPreferences[] = {
prefs::kWebKitUsesUniversalDetector,
// Autofill dialog.
+#if defined(OS_MACOSX)
prefs::kAutoFillAuxiliaryProfilesEnabled,
+#endif
// Translate preferences.
TranslatePrefs::kPrefTranslateLanguageBlacklist,
@@ -112,11 +115,42 @@ static const wchar_t* kSynchronizedPreferences[] = {
#if defined(OS_CHROMEOS)
// IME prefs
+ prefs::kLanguageChewingAddPhraseDirection,
+ prefs::kLanguageChewingAutoShiftCur,
+ prefs::kLanguageChewingCandPerPage,
+ prefs::kLanguageChewingEasySymbolInput,
+ prefs::kLanguageChewingEscCleanAllBuf,
+ prefs::kLanguageChewingForceLowercaseEnglish,
+ prefs::kLanguageChewingHsuSelKeyType,
+ prefs::kLanguageChewingKeyboardType,
+ prefs::kLanguageChewingMaxChiSymbolLen,
+ prefs::kLanguageChewingPhraseChoiceRearward,
+ prefs::kLanguageChewingPlainZhuyin,
+ prefs::kLanguageChewingSelKeys,
+ prefs::kLanguageChewingSpaceAsSelection,
prefs::kLanguageHangulKeyboard,
+ prefs::kLanguageMozcHistoryLearningLevel,
+ prefs::kLanguageMozcIncognitoMode,
+ prefs::kLanguageMozcNumpadCharacterForm,
+ prefs::kLanguageMozcPreeditMethod,
+ prefs::kLanguageMozcPunctuationMethod,
+ prefs::kLanguageMozcSessionKeymap,
+ prefs::kLanguageMozcShiftKeyModeSwitch,
+ prefs::kLanguageMozcSpaceCharacterForm,
+ prefs::kLanguageMozcSuggestionsSize,
+ prefs::kLanguageMozcSymbolMethod,
+ prefs::kLanguageMozcUseAutoImeTurnOff,
+ prefs::kLanguageMozcUseDateConversion,
+ prefs::kLanguageMozcUseDictionarySuggest,
+ prefs::kLanguageMozcUseHistorySuggest,
+ prefs::kLanguageMozcUseNumberConversion,
+ prefs::kLanguageMozcUseSingleKanjiConversion,
+ prefs::kLanguageMozcUseSymbolConversion,
prefs::kLanguagePinyinAutoCommit,
prefs::kLanguagePinyinCommaPeriodPage,
prefs::kLanguagePinyinCorrectPinyin,
prefs::kLanguagePinyinDoublePinyin,
+ prefs::kLanguagePinyinDoublePinyinSchema,
prefs::kLanguagePinyinFuzzyPinyin,
prefs::kLanguagePinyinInitChinese,
prefs::kLanguagePinyinInitFull,
@@ -127,34 +161,27 @@ static const wchar_t* kSynchronizedPreferences[] = {
prefs::kLanguagePinyinTradCandidate,
prefs::kLanguagePreferredLanguages,
prefs::kLanguagePreloadEngines,
- // TODO(yusukes): Add prefs for ibus-mozc (Japanese input method).
- // prefs::kLanguageMozcPreeditMethod,
- // prefs::kLanguageMozcSessionKeymap,
- // prefs::kLanguageMozcPunctuationMethod,
- // prefs::kLanguageMozcSymbolMethod,
- // prefs::kLanguageMozcSpaceCharacterForm;
- // prefs::kLanguageMozcHistoryLearningLevel;
- // prefs::kLanguageMozcSelectionShortcut;
- // prefs::kLanguageMozcShiftKeyModeSwitch;
- // prefs::kLanguageMozcNumpadCharacterForm;
- // prefs::kLanguageMozcIncognitoMode,
- // prefs::kLanguageMozcUseAutoImeTurnOff,
- // prefs::kLanguageMozcUseDateConversion,
- // prefs::kLanguageMozcUseSingleKanjiConversion,
- // prefs::kLanguageMozcUseSymbolConversion,
- // prefs::kLanguageMozcUseNumberConversion,
- // prefs::kLanguageMozcUseHistorySuggest,
- // prefs::kLanguageMozcUseDictionarySuggest,
- // prefs::kLanguageMozcSuggestionsSize
- //
+
// We don't sync the following IME prefs since they are not user-configurable
// (yet):
+ // prefs::kLanguageHangulHanjaKeys,
// prefs::kLanguageHotkeyNextEngineInMenu,
// prefs::kLanguageHotkeyPreviousEngine,
- // prefs::kLanguagePinyinDoublePinyinSchema,
+ // prefs::kLanguageMozcSelectionShortcut,
// prefs::kLanguagePinyinLookupTablePageSize,
//
// We don't sync prefs::kLanguageCurrentInputMethod and PreviousInputMethod.
+
+ // Keyboard prefs
+ prefs::kLanguageXkbRemapAltKeyTo,
+ prefs::kLanguageXkbRemapControlKeyTo,
+ prefs::kLanguageXkbRemapSearchKeyTo,
+
+ // We don't sync the following keyboard prefs since they are not user-
+ // configurable:
+ // prefs::kLanguageXkbAutoRepeatDelay,
+ // prefs::kLanguageXkbAutoRepeatEnabled,
+ // prefs::kLanguageXkbAutoRepeatInterval,
#endif
};
diff --git a/chrome/browser/sync/glue/theme_change_processor.cc b/chrome/browser/sync/glue/theme_change_processor.cc
index 58c3df3..bdf5e47 100644
--- a/chrome/browser/sync/glue/theme_change_processor.cc
+++ b/chrome/browser/sync/glue/theme_change_processor.cc
@@ -5,11 +5,11 @@
#include "chrome/browser/sync/glue/theme_change_processor.h"
#include "base/logging.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/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"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"
diff --git a/chrome/browser/sync/glue/theme_change_processor.h b/chrome/browser/sync/glue/theme_change_processor.h
index c9bf753..a694c0b 100644
--- a/chrome/browser/sync/glue/theme_change_processor.h
+++ b/chrome/browser/sync/glue/theme_change_processor.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_THEME_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_THEME_CHANGE_PROCESSOR_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/syncapi.h"
diff --git a/chrome/browser/sync/glue/theme_data_type_controller.h b/chrome/browser/sync/glue/theme_data_type_controller.h
index a808290..2951a2d 100644
--- a/chrome/browser/sync/glue/theme_data_type_controller.h
+++ b/chrome/browser/sync/glue/theme_data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_THEME_DATA_TYPE_CONTROLLER_H_
#define CHROME_BROWSER_SYNC_GLUE_THEME_DATA_TYPE_CONTROLLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/glue/theme_model_associator.cc b/chrome/browser/sync/glue/theme_model_associator.cc
index 3936f62..2dd02c2 100644
--- a/chrome/browser/sync/glue/theme_model_associator.cc
+++ b/chrome/browser/sync/glue/theme_model_associator.cc
@@ -7,12 +7,12 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/glue/theme_util.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/glue/theme_model_associator.h b/chrome/browser/sync/glue/theme_model_associator.h
index 54603cb..8e17724 100644
--- a/chrome/browser/sync/glue/theme_model_associator.h
+++ b/chrome/browser/sync/glue/theme_model_associator.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_THEME_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_THEME_MODEL_ASSOCIATOR_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/sync/glue/model_associator.h"
diff --git a/chrome/browser/sync/glue/theme_util.cc b/chrome/browser/sync/glue/theme_util.cc
index d4ed722..1c619a1 100644
--- a/chrome/browser/sync/glue/theme_util.cc
+++ b/chrome/browser/sync/glue/theme_util.cc
@@ -8,14 +8,13 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
-#include "base/version.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/extensions/extensions_service.h"
#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/gtk_theme_provider.h"
#endif
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
@@ -127,16 +126,17 @@ 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 bool kIsTheme = true;
+ 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.
const bool kInstallSilently = false;
const bool kEnableOnInstall = true;
const bool kEnableIncognitoOnInstall = false;
- extensions_service->AddPendingExtension(
- id, update_url, kIsTheme, kInstallSilently,
- kEnableOnInstall, kEnableIncognitoOnInstall);
+ extensions_service->AddPendingExtensionFromSync(
+ id, update_url, kExpectedCrxType,
+ 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()).
diff --git a/chrome/browser/sync/glue/theme_util.h b/chrome/browser/sync/glue/theme_util.h
index 1cc6f39..988b39d 100644
--- a/chrome/browser/sync/glue/theme_util.h
+++ b/chrome/browser/sync/glue/theme_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_THEME_UTIL_H_
#define CHROME_BROWSER_SYNC_GLUE_THEME_UTIL_H_
+#pragma once
class Extension;
class Profile;
diff --git a/chrome/browser/sync/glue/typed_url_change_processor.cc b/chrome/browser/sync/glue/typed_url_change_processor.cc
index c80426f..d6abc39 100644
--- a/chrome/browser/sync/glue/typed_url_change_processor.cc
+++ b/chrome/browser/sync/glue/typed_url_change_processor.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/sync/glue/typed_url_change_processor.h"
#include "base/string_util.h"
+#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"
diff --git a/chrome/browser/sync/glue/typed_url_change_processor.h b/chrome/browser/sync/glue/typed_url_change_processor.h
index 7fb9eb6..7c81588 100644
--- a/chrome/browser/sync/glue/typed_url_change_processor.h
+++ b/chrome/browser/sync/glue/typed_url_change_processor.h
@@ -4,11 +4,10 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_TYPED_URL_CHANGE_PROCESSOR_H_
#define CHROME_BROWSER_SYNC_GLUE_TYPED_URL_CHANGE_PROCESSOR_H_
+#pragma once
#include "chrome/browser/sync/glue/change_processor.h"
-#include <vector>
-
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
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 e8b3a31..8422bec 100644
--- a/chrome/browser/sync/glue/typed_url_data_type_controller.h
+++ b/chrome/browser/sync/glue/typed_url_data_type_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_TYPED_URL_DATA_TYPE_CONTROLLER_H__
#define CHROME_BROWSER_SYNC_GLUE_TYPED_URL_DATA_TYPE_CONTROLLER_H__
+#pragma once
#include <string>
@@ -80,6 +81,13 @@ class TypedUrlDataTypeController : public DataTypeController,
virtual void OnRequestRemoved(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) {}
+
+ virtual void WillExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {}
+
+ virtual void DidExecute(CancelableRequestProvider* provider,
+ CancelableRequestProvider::Handle handle) {}
+
private:
friend class ControlTask;
void StartImpl(history::HistoryBackend* backend);
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.cc b/chrome/browser/sync/glue/typed_url_model_associator.cc
index 3cca88a..d5bf3f1 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator.cc
+++ b/chrome/browser/sync/glue/typed_url_model_associator.cc
@@ -280,7 +280,7 @@ bool TypedUrlModelAssociator::WriteToHistoryBackend(
}
}
if (new_urls) {
- history_backend_->AddPagesWithDetails(*new_urls);
+ history_backend_->AddPagesWithDetails(*new_urls, history::SOURCE_SYNCED);
}
if (updated_urls) {
for (TypedUrlUpdateVector::const_iterator url = updated_urls->begin();
@@ -294,7 +294,8 @@ bool TypedUrlModelAssociator::WriteToHistoryBackend(
if (new_visits) {
for (TypedUrlVisitVector::const_iterator visits = new_visits->begin();
visits != new_visits->end(); ++visits) {
- if (!history_backend_->AddVisits(visits->first, visits->second)) {
+ if (!history_backend_->AddVisits(visits->first, visits->second,
+ history::SOURCE_SYNCED)) {
LOG(ERROR) << "Could not add visits.";
return false;
}
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.h b/chrome/browser/sync/glue/typed_url_model_associator.h
index dcaed25..9b25a0f 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator.h
+++ b/chrome/browser/sync/glue/typed_url_model_associator.h
@@ -4,14 +4,13 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_
+#pragma once
#include <map>
-#include <set>
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/task.h"
#include "chrome/browser/chrome_thread.h"
diff --git a/chrome/browser/sync/glue/ui_model_worker.h b/chrome/browser/sync/glue/ui_model_worker.h
index 50d4576..f1df84c 100644
--- a/chrome/browser/sync/glue/ui_model_worker.h
+++ b/chrome/browser/sync/glue/ui_model_worker.h
@@ -4,15 +4,19 @@
#ifndef CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_
#define CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_
+#pragma once
#include "base/callback.h"
#include "base/condition_variable.h"
#include "base/lock.h"
#include "base/task.h"
-#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/engine/model_safe_worker.h"
+namespace base {
+class WaitableEvent;
+}
+
class MessageLoop;
namespace browser_sync {
diff --git a/chrome/browser/sync/glue/ui_model_worker_unittest.cc b/chrome/browser/sync/glue/ui_model_worker_unittest.cc
index 79e9fb0..e71a254 100644
--- a/chrome/browser/sync/glue/ui_model_worker_unittest.cc
+++ b/chrome/browser/sync/glue/ui_model_worker_unittest.cc
@@ -6,6 +6,7 @@
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/thread.h"
+#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/ui_model_worker.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/sync/notification_method.cc b/chrome/browser/sync/notification_method.cc
deleted file mode 100644
index 2c9896a..0000000
--- a/chrome/browser/sync/notification_method.cc
+++ /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/sync/notification_method.h"
-
-#include "base/logging.h"
-
-namespace browser_sync {
-
-const NotificationMethod kDefaultNotificationMethod =
- NOTIFICATION_SERVER;
-
-std::string NotificationMethodToString(
- NotificationMethod notification_method) {
- switch (notification_method) {
- case NOTIFICATION_LEGACY:
- return "NOTIFICATION_LEGACY";
- break;
- case NOTIFICATION_TRANSITIONAL:
- return "NOTIFICATION_TRANSITIONAL";
- break;
- case NOTIFICATION_NEW:
- return "NOTIFICATION_NEW";
- break;
- case NOTIFICATION_SERVER:
- return "NOTIFICATION_SERVER";
- break;
- default:
- LOG(WARNING) << "Unknown value for notification method: "
- << notification_method;
- break;
- }
- return "<unknown notification method>";
-}
-
-NotificationMethod StringToNotificationMethod(const std::string& str) {
- if (str == "legacy") {
- return NOTIFICATION_LEGACY;
- } else if (str == "transitional") {
- return NOTIFICATION_TRANSITIONAL;
- } else if (str == "new") {
- return NOTIFICATION_NEW;
- } else if (str == "server") {
- return NOTIFICATION_SERVER;
- }
- LOG(WARNING) << "Unknown notification method \"" << str
- << "\"; using method "
- << NotificationMethodToString(kDefaultNotificationMethod);
- return kDefaultNotificationMethod;
-}
-
-} // namespace browser_sync
diff --git a/chrome/browser/sync/notification_method.h b/chrome/browser/sync/notification_method.h
deleted file mode 100644
index 4e1bcd1..0000000
--- a/chrome/browser/sync/notification_method.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_SYNC_NOTIFICATION_METHOD_H_
-#define CHROME_BROWSER_SYNC_NOTIFICATION_METHOD_H_
-
-#include <string>
-
-namespace browser_sync {
-
-// This is the matrix for the interaction between clients with
-// different notification methods (except for NOTIFICATION_SERVER):
-//
-// Listen
-// L T N
-// +-------+
-// L | E E E |
-// Send T | Y Y Y |
-// N | E Y Y |
-// +-------+
-//
-// 'Y' means a client listening with the column notification method
-// will receive notifications from a client sending with the row
-// notification method. 'E' means means that the notification will be
-// an empty one, which may be dropped by the server in the future.
-//
-// As for NOTIFICATION_SERVER, server-issued notifications will also
-// simulate a peer-issued notification, so that any client with
-// NOTIFICATION_TRANSITIONAL or NOTIFICATION_NEW will be able to
-// receive those, too. This support will be removed once everyone is
-// on NOTIFICATION_SERVER.
-
-enum NotificationMethod {
- // Old, broken notification method. Works only if notification
- // servers don't drop empty notifications.
- NOTIFICATION_LEGACY,
- // Compatible with new notifications. Also compatible with legacy
- // notifications if the notification servers don't drop empty
- // notifications.
- NOTIFICATION_TRANSITIONAL,
- // New notification method. Compatible only with transitional
- // notifications.
- //
- // NOTE: "New" is kind of a misnomer, as it refers only to
- // peer-issued notifications; the plan is to migrate everyone to
- // using NOTIFICATION_SERVER.
- NOTIFICATION_NEW,
-
- // Server-issued notifications. Compatible only with transitional
- // notifications.
- NOTIFICATION_SERVER,
-};
-
-extern const NotificationMethod kDefaultNotificationMethod;
-
-std::string NotificationMethodToString(
- NotificationMethod notification_method);
-
-// If the given string is not one of "legacy", "transitional", "new",
-// or "server", returns kDefaultNotificationMethod.
-NotificationMethod StringToNotificationMethod(const std::string& str);
-
-} // namespace browser_sync
-
-#endif // CHROME_BROWSER_SYNC_NOTIFICATION_METHOD_H_
-
diff --git a/chrome/browser/sync/notifier/cache_invalidation_packet_handler.cc b/chrome/browser/sync/notifier/cache_invalidation_packet_handler.cc
index a5d23f2..d2930f3 100644
--- a/chrome/browser/sync/notifier/cache_invalidation_packet_handler.cc
+++ b/chrome/browser/sync/notifier/cache_invalidation_packet_handler.cc
@@ -8,9 +8,10 @@
#include "base/base64.h"
#include "base/callback.h"
+#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/rand_util.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/sync/sync_constants.h"
#include "google/cacheinvalidation/invalidation-client.h"
#include "jingle/notifier/listener/xml_element_util.h"
@@ -45,17 +46,17 @@ class CacheInvalidationListenTask : public buzz::XmppTask {
virtual ~CacheInvalidationListenTask() {}
virtual int ProcessStart() {
- LOG(INFO) << "CacheInvalidationListenTask started";
+ VLOG(2) << "CacheInvalidationListenTask started";
return STATE_RESPONSE;
}
virtual int ProcessResponse() {
const buzz::XmlElement* stanza = NextStanza();
if (stanza == NULL) {
- LOG(INFO) << "CacheInvalidationListenTask blocked";
+ VLOG(2) << "CacheInvalidationListenTask blocked";
return STATE_BLOCKED;
}
- LOG(INFO) << "CacheInvalidationListenTask response received";
+ VLOG(2) << "CacheInvalidationListenTask response received";
std::string data;
if (GetCacheInvalidationIqPacketData(stanza, &data)) {
callback_->Run(data);
@@ -70,14 +71,14 @@ class CacheInvalidationListenTask : public buzz::XmppTask {
}
virtual bool HandleStanza(const buzz::XmlElement* stanza) {
- LOG(INFO) << "Stanza received: "
+ VLOG(1) << "Stanza received: "
<< notifier::XmlElementToString(*stanza);
if (IsValidCacheInvalidationIqPacket(stanza)) {
- LOG(INFO) << "Queueing stanza";
+ VLOG(2) << "Queueing stanza";
QueueStanza(stanza);
return true;
}
- LOG(INFO) << "Stanza skipped";
+ VLOG(2) << "Stanza skipped";
return false;
}
@@ -127,10 +128,10 @@ class CacheInvalidationSendMessageTask : public buzz::XmppTask {
scoped_ptr<buzz::XmlElement> stanza(
MakeCacheInvalidationIqPacket(to_jid_, task_id(), msg_,
seq_, sid_));
- LOG(INFO) << "Sending message: "
+ VLOG(1) << "Sending message: "
<< notifier::XmlElementToString(*stanza.get());
if (SendStanza(stanza.get()) != buzz::XMPP_RETURN_OK) {
- LOG(INFO) << "Error when sending message";
+ VLOG(2) << "Error when sending message";
return STATE_ERROR;
}
return STATE_RESPONSE;
@@ -139,23 +140,23 @@ class CacheInvalidationSendMessageTask : public buzz::XmppTask {
virtual int ProcessResponse() {
const buzz::XmlElement* stanza = NextStanza();
if (stanza == NULL) {
- LOG(INFO) << "CacheInvalidationSendMessageTask blocked...";
+ VLOG(2) << "CacheInvalidationSendMessageTask blocked...";
return STATE_BLOCKED;
}
- LOG(INFO) << "CacheInvalidationSendMessageTask response received: "
+ VLOG(2) << "CacheInvalidationSendMessageTask response received: "
<< notifier::XmlElementToString(*stanza);
// TODO(akalin): Handle errors here.
return STATE_DONE;
}
virtual bool HandleStanza(const buzz::XmlElement* stanza) {
- LOG(INFO) << "Stanza received: "
+ VLOG(1) << "Stanza received: "
<< notifier::XmlElementToString(*stanza);
if (!MatchResponseIq(stanza, to_jid_, task_id())) {
- LOG(INFO) << "Stanza skipped";
+ VLOG(2) << "Stanza skipped";
return false;
}
- LOG(INFO) << "Queueing stanza";
+ VLOG(2) << "Queueing stanza";
QueueStanza(stanza);
return true;
}
@@ -170,7 +171,7 @@ class CacheInvalidationSendMessageTask : public buzz::XmppTask {
buzz::XmlElement* cache_invalidation_iq_packet =
new buzz::XmlElement(kQnData, true);
iq->AddElement(cache_invalidation_iq_packet);
- cache_invalidation_iq_packet->SetAttr(kQnSeq, IntToString(seq));
+ cache_invalidation_iq_packet->SetAttr(kQnSeq, base::IntToString(seq));
cache_invalidation_iq_packet->SetAttr(kQnSid, sid);
cache_invalidation_iq_packet->SetAttr(kQnServiceUrl,
browser_sync::kSyncServiceUrl);
@@ -188,32 +189,32 @@ class CacheInvalidationSendMessageTask : public buzz::XmppTask {
std::string MakeSid() {
uint64 sid = base::RandUint64();
- return std::string("chrome-sync-") + Uint64ToString(sid);
+ return std::string("chrome-sync-") + base::Uint64ToString(sid);
}
} // namespace
CacheInvalidationPacketHandler::CacheInvalidationPacketHandler(
- buzz::XmppClient* xmpp_client,
+ talk_base::Task* base_task,
invalidation::InvalidationClient* invalidation_client)
- : xmpp_client_(xmpp_client),
+ : scoped_callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ base_task_(base_task),
invalidation_client_(invalidation_client),
seq_(0),
sid_(MakeSid()) {
- CHECK(xmpp_client_);
+ CHECK(base_task_);
CHECK(invalidation_client_);
invalidation::NetworkEndpoint* network_endpoint =
invalidation_client_->network_endpoint();
CHECK(network_endpoint);
network_endpoint->RegisterOutboundListener(
- invalidation::NewPermanentCallback(
- this,
+ scoped_callback_factory_.NewCallback(
&CacheInvalidationPacketHandler::HandleOutboundPacket));
- // Owned by xmpp_client.
+ // Owned by base_task.
CacheInvalidationListenTask* listen_task =
new CacheInvalidationListenTask(
- xmpp_client, NewCallback(
- this, &CacheInvalidationPacketHandler::HandleInboundPacket));
+ base_task, scoped_callback_factory_.NewCallback(
+ &CacheInvalidationPacketHandler::HandleInboundPacket));
listen_task->Start();
}
@@ -235,9 +236,9 @@ void CacheInvalidationPacketHandler::HandleOutboundPacket(
<< message;
return;
}
- // Owned by xmpp_client.
+ // Owned by base_task.
CacheInvalidationSendMessageTask* send_message_task =
- new CacheInvalidationSendMessageTask(xmpp_client_,
+ new CacheInvalidationSendMessageTask(base_task_,
buzz::Jid(kBotJid),
encoded_message,
seq_, sid_);
diff --git a/chrome/browser/sync/notifier/cache_invalidation_packet_handler.h b/chrome/browser/sync/notifier/cache_invalidation_packet_handler.h
index 0f5feaa..6d94c5f 100644
--- a/chrome/browser/sync/notifier/cache_invalidation_packet_handler.h
+++ b/chrome/browser/sync/notifier/cache_invalidation_packet_handler.h
@@ -7,21 +7,23 @@
#ifndef CHROME_BROWSER_SYNC_NOTIFIER_CACHE_INVALIDATION_PACKET_HANDLER_H_
#define CHROME_BROWSER_SYNC_NOTIFIER_CACHE_INVALIDATION_PACKET_HANDLER_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+#include "base/scoped_callback_factory.h"
#include "talk/xmpp/jid.h"
-namespace buzz {
-class XmppClient;
-} // namespace buzz
-
namespace invalidation {
class InvalidationClient;
class NetworkEndpoint;
} // namespace invalidation
+namespace talk_base {
+class Task;
+} // namespace
+
namespace sync_notifier {
// TODO(akalin): Add a NonThreadSafe member to this class and use it.
@@ -33,7 +35,7 @@ class CacheInvalidationPacketHandler {
// packets through something. Does not take ownership of
// |xmpp_client| or |invalidation_client|.
CacheInvalidationPacketHandler(
- buzz::XmppClient* xmpp_client,
+ talk_base::Task* base_task,
invalidation::InvalidationClient* invalidation_client);
// Makes the invalidation client passed into the constructor not
@@ -47,7 +49,10 @@ class CacheInvalidationPacketHandler {
void HandleInboundPacket(const std::string& packet);
- buzz::XmppClient* xmpp_client_;
+ base::ScopedCallbackFactory<CacheInvalidationPacketHandler>
+ scoped_callback_factory_;
+
+ talk_base::Task* base_task_;
invalidation::InvalidationClient* invalidation_client_;
// Parameters for sent messages.
diff --git a/chrome/browser/sync/notifier/chrome_invalidation_client.cc b/chrome/browser/sync/notifier/chrome_invalidation_client.cc
index f183e61..8eb02f4 100644
--- a/chrome/browser/sync/notifier/chrome_invalidation_client.cc
+++ b/chrome/browser/sync/notifier/chrome_invalidation_client.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/sync/notifier/invalidation_util.h"
#include "chrome/browser/sync/notifier/registration_manager.h"
#include "chrome/browser/sync/syncable/model_type.h"
+#include "google/cacheinvalidation/invalidation-client-impl.h"
namespace sync_notifier {
@@ -30,7 +31,7 @@ ChromeInvalidationClient::~ChromeInvalidationClient() {
void ChromeInvalidationClient::Start(
const std::string& client_id, Listener* listener,
- buzz::XmppClient* xmpp_client) {
+ talk_base::Task* base_task) {
DCHECK(non_thread_safe_.CalledOnValidThread());
Stop();
@@ -41,11 +42,19 @@ void ChromeInvalidationClient::Start(
invalidation::ClientType client_type;
client_type.set_type(invalidation::ClientType::CHROME_SYNC);
+ // TODO(akalin): Use InvalidationClient::Create() once it supports
+ // taking a ClientConfig.
+ invalidation::ClientConfig client_config;
+ // Bump up limits so that we reduce the number of registration
+ // replies we get.
+ client_config.max_registrations_per_message = 20;
+ client_config.max_ops_per_message = 40;
invalidation_client_.reset(
- invalidation::InvalidationClient::Create(
- &chrome_system_resources_, client_type, client_id, this));
+ new invalidation::InvalidationClientImpl(
+ &chrome_system_resources_, client_type, client_id, this,
+ client_config));
cache_invalidation_packet_handler_.reset(
- new CacheInvalidationPacketHandler(xmpp_client,
+ new CacheInvalidationPacketHandler(base_task,
invalidation_client_.get()));
registration_manager_.reset(
new RegistrationManager(invalidation_client_.get()));
@@ -76,6 +85,10 @@ void ChromeInvalidationClient::RegisterTypes() {
i < syncable::MODEL_TYPE_COUNT; ++i) {
registration_manager_->RegisterType(syncable::ModelTypeFromInt(i));
}
+ // 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.
+ registration_manager_->RegisterType(syncable::UNSPECIFIED);
}
void ChromeInvalidationClient::Invalidate(
@@ -83,7 +96,7 @@ void ChromeInvalidationClient::Invalidate(
invalidation::Closure* callback) {
DCHECK(non_thread_safe_.CalledOnValidThread());
DCHECK(invalidation::IsCallbackRepeatable(callback));
- LOG(INFO) << "Invalidate: " << InvalidationToString(invalidation);
+ VLOG(1) << "Invalidate: " << InvalidationToString(invalidation);
syncable::ModelType model_type;
if (ObjectIdToRealModelType(invalidation.object_id(), &model_type)) {
listener_->OnInvalidate(model_type);
@@ -99,7 +112,7 @@ void ChromeInvalidationClient::InvalidateAll(
invalidation::Closure* callback) {
DCHECK(non_thread_safe_.CalledOnValidThread());
DCHECK(invalidation::IsCallbackRepeatable(callback));
- LOG(INFO) << "InvalidateAll";
+ VLOG(1) << "InvalidateAll";
listener_->OnInvalidateAll();
RunAndDeleteClosure(callback);
}
@@ -108,7 +121,7 @@ void ChromeInvalidationClient::AllRegistrationsLost(
invalidation::Closure* callback) {
DCHECK(non_thread_safe_.CalledOnValidThread());
DCHECK(invalidation::IsCallbackRepeatable(callback));
- LOG(INFO) << "AllRegistrationsLost";
+ VLOG(1) << "AllRegistrationsLost";
registration_manager_->MarkAllRegistrationsLost();
RunAndDeleteClosure(callback);
}
@@ -118,7 +131,7 @@ void ChromeInvalidationClient::RegistrationLost(
invalidation::Closure* callback) {
DCHECK(non_thread_safe_.CalledOnValidThread());
DCHECK(invalidation::IsCallbackRepeatable(callback));
- LOG(INFO) << "RegistrationLost: " << ObjectIdToString(object_id);
+ VLOG(1) << "RegistrationLost: " << ObjectIdToString(object_id);
syncable::ModelType model_type;
if (ObjectIdToRealModelType(object_id, &model_type)) {
registration_manager_->MarkRegistrationLost(model_type);
diff --git a/chrome/browser/sync/notifier/chrome_invalidation_client.h b/chrome/browser/sync/notifier/chrome_invalidation_client.h
index 6b4f6cf..cc47ce6 100644
--- a/chrome/browser/sync/notifier/chrome_invalidation_client.h
+++ b/chrome/browser/sync/notifier/chrome_invalidation_client.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_SYNC_NOTIFIER_CHROME_INVALIDATION_CLIENT_H_
#define CHROME_BROWSER_SYNC_NOTIFIER_CHROME_INVALIDATION_CLIENT_H_
+#pragma once
#include <string>
@@ -17,8 +18,8 @@
#include "chrome/browser/sync/syncable/model_type.h"
#include "google/cacheinvalidation/invalidation-client.h"
-namespace buzz {
-class XmppClient;
+namespace talk_base {
+class Task;
} // namespace
namespace sync_notifier {
@@ -45,10 +46,10 @@ class ChromeInvalidationClient : public invalidation::InvalidationListener {
// Calls Stop().
virtual ~ChromeInvalidationClient();
- // Does not take ownership of |listener| nor |xmpp_client|.
+ // Does not take ownership of |listener| nor |base_task|.
void Start(
const std::string& client_id, Listener* listener,
- buzz::XmppClient* xmpp_client);
+ talk_base::Task* base_task);
void Stop();
diff --git a/chrome/browser/sync/notifier/chrome_system_resources.h b/chrome/browser/sync/notifier/chrome_system_resources.h
index 14d69d9..1305c7c 100644
--- a/chrome/browser/sync/notifier/chrome_system_resources.h
+++ b/chrome/browser/sync/notifier/chrome_system_resources.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_SYNC_NOTIFIER_CHROME_SYSTEM_RESOURCES_H_
#define CHROME_BROWSER_SYNC_NOTIFIER_CHROME_SYSTEM_RESOURCES_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/sync/notifier/invalidation_util.h b/chrome/browser/sync/notifier/invalidation_util.h
index 92e6a6e..75a9f6b 100644
--- a/chrome/browser/sync/notifier/invalidation_util.h
+++ b/chrome/browser/sync/notifier/invalidation_util.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_SYNC_NOTIFIER_INVALIDATION_UTIL_H_
#define CHROME_BROWSER_SYNC_NOTIFIER_INVALIDATION_UTIL_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/notifier/registration_manager.cc b/chrome/browser/sync/notifier/registration_manager.cc
index 3895c91..ccadac4 100644
--- a/chrome/browser/sync/notifier/registration_manager.cc
+++ b/chrome/browser/sync/notifier/registration_manager.cc
@@ -60,8 +60,7 @@ void RegistrationManager::MarkRegistrationLost(
RegistrationStatusMap::iterator it =
registration_status_.find(model_type);
if (it == registration_status_.end()) {
- LOG(ERROR) << "Unknown model type: "
- << syncable::ModelTypeToString(model_type);
+ LOG(ERROR) << "Unknown model type: " << model_type;
return;
}
it->second = UNREGISTERED;
diff --git a/chrome/browser/sync/notifier/registration_manager.h b/chrome/browser/sync/notifier/registration_manager.h
index 52f299b..06acc89 100644
--- a/chrome/browser/sync/notifier/registration_manager.h
+++ b/chrome/browser/sync/notifier/registration_manager.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_
#define CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_
+#pragma once
#include <map>
diff --git a/chrome/browser/sync/notifier/registration_manager_unittest.cc b/chrome/browser/sync/notifier/registration_manager_unittest.cc
index 6d73afa..e8b9a85 100644
--- a/chrome/browser/sync/notifier/registration_manager_unittest.cc
+++ b/chrome/browser/sync/notifier/registration_manager_unittest.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/logging.h"
#include "chrome/browser/sync/notifier/invalidation_util.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "google/cacheinvalidation/invalidation-client.h"
diff --git a/chrome/browser/sync/notifier/server_notifier_thread.cc b/chrome/browser/sync/notifier/server_notifier_thread.cc
index 0e5be0c..495a5e3 100644
--- a/chrome/browser/sync/notifier/server_notifier_thread.cc
+++ b/chrome/browser/sync/notifier/server_notifier_thread.cc
@@ -9,13 +9,18 @@
#include "base/logging.h"
#include "chrome/browser/sync/notifier/chrome_invalidation_client.h"
+#include "jingle/notifier/base/notifier_options.h"
#include "jingle/notifier/listener/notification_defines.h"
+#include "talk/xmpp/xmppclient.h"
namespace sync_notifier {
-ServerNotifierThread::ServerNotifierThread(bool use_chrome_async_socket)
- : notifier::MediatorThreadImpl(use_chrome_async_socket),
- state_(notifier::STATE_CLOSED) {}
+ServerNotifierThread::ServerNotifierThread(
+ const notifier::NotifierOptions& notifier_options)
+ : notifier::MediatorThreadImpl(notifier_options) {
+ DCHECK_EQ(notifier::NOTIFICATION_SERVER,
+ notifier_options.notification_method);
+}
ServerNotifierThread::~ServerNotifierThread() {}
@@ -54,7 +59,14 @@ void ServerNotifierThread::SendNotification(
void ServerNotifierThread::OnInvalidate(syncable::ModelType model_type) {
DCHECK_EQ(MessageLoop::current(), worker_message_loop());
- LOG(INFO) << "OnInvalidate: " << syncable::ModelTypeToString(model_type);
+ // 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.
+ if (model_type == syncable::UNSPECIFIED) {
+ LOG(INFO) << "OnInvalidate: UNKNOWN";
+ } else {
+ LOG(INFO) << "OnInvalidate: " << syncable::ModelTypeToString(model_type);
+ }
// TODO(akalin): Signal notification only for the invalidated types.
parent_message_loop_->PostTask(
FROM_HERE,
@@ -73,25 +85,15 @@ void ServerNotifierThread::OnInvalidateAll() {
&ServerNotifierThread::SignalIncomingNotification));
}
-void ServerNotifierThread::OnClientStateChangeMessage(
- notifier::LoginConnectionState state) {
+void ServerNotifierThread::OnDisconnect() {
DCHECK_EQ(MessageLoop::current(), worker_message_loop());
- state_ = state;
- if (state_ != notifier::STATE_OPENED) {
- // Assume anything but an opened state invalidates xmpp_client().
- StopInvalidationListener();
- }
- MediatorThreadImpl::OnClientStateChangeMessage(state);
+ StopInvalidationListener();
+ MediatorThreadImpl::OnDisconnect();
}
void ServerNotifierThread::StartInvalidationListener() {
DCHECK_EQ(MessageLoop::current(), worker_message_loop());
- if (state_ != notifier::STATE_OPENED) {
- return;
- }
- buzz::XmppClient* client = xmpp_client();
- if (client == NULL) {
- LOG(DFATAL) << "xmpp_client() unexpectedly NULL";
+ if (!base_task_.get()) {
return;
}
@@ -103,15 +105,11 @@ void ServerNotifierThread::StartInvalidationListener() {
// make it so that we won't receive any notifications that were
// generated from our own changes.
const std::string kClientId = "server_notifier_thread";
- chrome_invalidation_client_->Start(kClientId, this, client);
+ chrome_invalidation_client_->Start(kClientId, this, base_task_);
}
void ServerNotifierThread::RegisterTypesAndSignalSubscribed() {
DCHECK_EQ(MessageLoop::current(), worker_message_loop());
- if (state_ != notifier::STATE_OPENED) {
- return;
- }
-
chrome_invalidation_client_->RegisterTypes();
parent_message_loop_->PostTask(
FROM_HERE,
diff --git a/chrome/browser/sync/notifier/server_notifier_thread.h b/chrome/browser/sync/notifier/server_notifier_thread.h
index b3990a7..4d66f42 100644
--- a/chrome/browser/sync/notifier/server_notifier_thread.h
+++ b/chrome/browser/sync/notifier/server_notifier_thread.h
@@ -11,6 +11,7 @@
#ifndef CHROME_BROWSER_SYNC_NOTIFIER_SERVER_NOTIFIER_THREAD_H_
#define CHROME_BROWSER_SYNC_NOTIFIER_SERVER_NOTIFIER_THREAD_H_
+#pragma once
#include <string>
#include <vector>
@@ -20,13 +21,18 @@
#include "chrome/browser/sync/syncable/model_type.h"
#include "jingle/notifier/listener/mediator_thread_impl.h"
+namespace notifier {
+struct NotifierOptions;
+}
+
namespace sync_notifier {
class ServerNotifierThread
: public notifier::MediatorThreadImpl,
public ChromeInvalidationClient::Listener {
public:
- explicit ServerNotifierThread(bool use_chrome_async_socket);
+ explicit ServerNotifierThread(
+ const notifier::NotifierOptions& notifier_options);
virtual ~ServerNotifierThread();
@@ -52,9 +58,7 @@ class ServerNotifierThread
virtual void OnInvalidateAll();
protected:
- // Overridden to know what state we're in.
- virtual void OnClientStateChangeMessage(
- notifier::LoginConnectionState state);
+ virtual void OnDisconnect();
private:
// Posted to the worker thread by ListenForUpdates().
@@ -73,7 +77,6 @@ class ServerNotifierThread
// thread by Stop().
void StopInvalidationListener();
- notifier::LoginConnectionState state_;
scoped_ptr<ChromeInvalidationClient> chrome_invalidation_client_;
};
diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h
index f8b16e7..a4a2550 100644
--- a/chrome/browser/sync/profile_sync_factory.h
+++ b/chrome/browser/sync/profile_sync_factory.h
@@ -4,8 +4,11 @@
#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__
+#pragma once
+#include <string>
#include <utility>
+
#include "base/task.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
@@ -47,7 +50,8 @@ class ProfileSyncFactory {
// Instantiates and initializes a new ProfileSyncService. Enabled
// data types are registered with the service. The return pointer
// is owned by the caller.
- virtual ProfileSyncService* CreateProfileSyncService() = 0;
+ virtual ProfileSyncService* CreateProfileSyncService(
+ const std::string& cros_user) = 0;
// Instantiates a new DataTypeManager with a SyncBackendHost and a
// list of data type controllers. The return pointer is owned by
@@ -57,6 +61,13 @@ class ProfileSyncFactory {
const browser_sync::DataTypeController::TypeMap& controllers) = 0;
// Instantiates both a model associator and change processor for the
+ // app data type. The pointers in the return struct are
+ // owned by the caller.
+ virtual SyncComponents CreateAppSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ 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 CreateAutofillSyncComponents(
@@ -108,6 +119,13 @@ class ProfileSyncFactory {
ProfileSyncService* profile_sync_service,
history::HistoryBackend* history_backend,
browser_sync::UnrecoverableErrorHandler* error_handler) = 0;
+
+ // Instantiates both a model associator and change processor for the
+ // session data type. The pointers in the return struct are
+ // owned by the caller.
+ virtual SyncComponents CreateSessionSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ browser_sync::UnrecoverableErrorHandler* error_handler) = 0;
};
#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__
diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc
index 3a3bd46..ed8f429 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl.cc
@@ -3,9 +3,9 @@
// found in the LICENSE file.
#include "base/command_line.h"
-#include "base/logging.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/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_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
@@ -16,12 +16,16 @@
#include "chrome/browser/sync/glue/extension_change_processor.h"
#include "chrome/browser/sync/glue/extension_data_type_controller.h"
#include "chrome/browser/sync/glue/extension_model_associator.h"
+#include "chrome/browser/sync/glue/extension_sync_traits.h"
#include "chrome/browser/sync/glue/password_change_processor.h"
#include "chrome/browser/sync/glue/password_data_type_controller.h"
#include "chrome/browser/sync/glue/password_model_associator.h"
#include "chrome/browser/sync/glue/preference_change_processor.h"
#include "chrome/browser/sync/glue/preference_data_type_controller.h"
#include "chrome/browser/sync/glue/preference_model_associator.h"
+#include "chrome/browser/sync/glue/session_change_processor.h"
+#include "chrome/browser/sync/glue/session_data_type_controller.h"
+#include "chrome/browser/sync/glue/session_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/glue/theme_change_processor.h"
#include "chrome/browser/sync/glue/theme_data_type_controller.h"
@@ -34,6 +38,7 @@
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_switches.h"
+using browser_sync::AppDataTypeController;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillDataTypeController;
using browser_sync::AutofillModelAssociator;
@@ -52,6 +57,9 @@ using browser_sync::PasswordModelAssociator;
using browser_sync::PreferenceChangeProcessor;
using browser_sync::PreferenceDataTypeController;
using browser_sync::PreferenceModelAssociator;
+using browser_sync::SessionChangeProcessor;
+using browser_sync::SessionDataTypeController;
+using browser_sync::SessionModelAssociator;
using browser_sync::SyncBackendHost;
using browser_sync::ThemeChangeProcessor;
using browser_sync::ThemeDataTypeController;
@@ -67,9 +75,18 @@ ProfileSyncFactoryImpl::ProfileSyncFactoryImpl(Profile* profile,
command_line_(command_line) {
}
-ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService() {
+ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
+ const std::string& cros_user) {
+
ProfileSyncService* pss = new ProfileSyncService(
- this, profile_, browser_defaults::kBootstrapSyncAuthentication);
+ this, profile_, cros_user);
+
+ // App sync is enabled by default. Register unless explicitly
+ // disabled.
+ if (!command_line_->HasSwitch(switches::kDisableSyncApps)) {
+ pss->RegisterDataTypeController(
+ new AppDataTypeController(this, profile_, pss));
+ }
// Autofill sync is enabled by default. Register unless explicitly
// disabled.
@@ -119,6 +136,12 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService() {
new TypedUrlDataTypeController(this, profile_, pss));
}
+ // Session sync is disabled by default. Register only if explicitly
+ // enabled.
+ if (command_line_->HasSwitch(switches::kEnableSyncSessions)) {
+ pss->RegisterDataTypeController(
+ new SessionDataTypeController(this, pss));
+ }
return pss;
}
@@ -129,6 +152,21 @@ DataTypeManager* ProfileSyncFactoryImpl::CreateDataTypeManager(
}
ProfileSyncFactory::SyncComponents
+ProfileSyncFactoryImpl::CreateAppSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ UnrecoverableErrorHandler* error_handler) {
+ browser_sync::ExtensionSyncTraits traits = browser_sync::GetAppSyncTraits();
+ // For now we simply use extensions sync objects with the app sync
+ // traits. If apps become more than simply extensions, we may have
+ // to write our own apps model associator and/or change processor.
+ ExtensionModelAssociator* model_associator =
+ new ExtensionModelAssociator(traits, profile_sync_service);
+ ExtensionChangeProcessor* change_processor =
+ new ExtensionChangeProcessor(traits, error_handler);
+ return SyncComponents(model_associator, change_processor);
+}
+
+ProfileSyncFactory::SyncComponents
ProfileSyncFactoryImpl::CreateAutofillSyncComponents(
ProfileSyncService* profile_sync_service,
WebDatabase* web_database,
@@ -163,10 +201,12 @@ ProfileSyncFactory::SyncComponents
ProfileSyncFactoryImpl::CreateExtensionSyncComponents(
ProfileSyncService* profile_sync_service,
UnrecoverableErrorHandler* error_handler) {
+ browser_sync::ExtensionSyncTraits traits =
+ browser_sync::GetExtensionSyncTraits();
ExtensionModelAssociator* model_associator =
- new ExtensionModelAssociator(profile_sync_service);
+ new ExtensionModelAssociator(traits, profile_sync_service);
ExtensionChangeProcessor* change_processor =
- new ExtensionChangeProcessor(error_handler, model_associator);
+ new ExtensionChangeProcessor(traits, error_handler);
return SyncComponents(model_associator, change_processor);
}
@@ -222,3 +262,14 @@ ProfileSyncFactoryImpl::CreateTypedUrlSyncComponents(
error_handler);
return SyncComponents(model_associator, change_processor);
}
+
+ProfileSyncFactory::SyncComponents
+ProfileSyncFactoryImpl::CreateSessionSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ UnrecoverableErrorHandler* error_handler) {
+ SessionModelAssociator* model_associator =
+ new SessionModelAssociator(profile_sync_service);
+ SessionChangeProcessor* change_processor =
+ new SessionChangeProcessor(error_handler, model_associator);
+ return SyncComponents(model_associator, change_processor);
+}
diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h
index 31c0dea..233f3f1 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.h
+++ b/chrome/browser/sync/profile_sync_factory_impl.h
@@ -4,6 +4,9 @@
#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_IMPL_H__
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_IMPL_H__
+#pragma once
+
+#include <string>
#include "base/basictypes.h"
#include "chrome/browser/sync/profile_sync_factory.h"
@@ -17,12 +20,17 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory {
virtual ~ProfileSyncFactoryImpl() {}
// ProfileSyncFactory interface.
- virtual ProfileSyncService* CreateProfileSyncService();
+ virtual ProfileSyncService* CreateProfileSyncService(
+ const std::string& cros_user);
virtual browser_sync::DataTypeManager* CreateDataTypeManager(
browser_sync::SyncBackendHost* backend,
const browser_sync::DataTypeController::TypeMap& controllers);
+ virtual SyncComponents CreateAppSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ browser_sync::UnrecoverableErrorHandler* error_handler);
+
virtual SyncComponents CreateAutofillSyncComponents(
ProfileSyncService* profile_sync_service,
WebDatabase* web_database,
@@ -55,6 +63,10 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory {
history::HistoryBackend* history_backend,
browser_sync::UnrecoverableErrorHandler* error_handler);
+ virtual SyncComponents CreateSessionSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ browser_sync::UnrecoverableErrorHandler* error_handler);
+
private:
Profile* profile_;
CommandLine* command_line_;
diff --git a/chrome/browser/sync/profile_sync_factory_impl_unittest.cc b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
index d5d1e55..26f47d1 100644
--- a/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl_unittest.cc
@@ -39,89 +39,111 @@ class ProfileSyncFactoryImplTest : public testing::Test {
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDefault) {
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
- EXPECT_EQ(5U, controller_states_ptr->size());
+ EXPECT_EQ(6U, controller_states_ptr->size());
EXPECT_EQ(1U, controller_states_ptr->count(syncable::BOOKMARKS));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::PREFERENCES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::AUTOFILL));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::THEMES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::EXTENSIONS));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::APPS));
}
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableAutofill) {
command_line_->AppendSwitch(switches::kDisableSyncAutofill);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
- EXPECT_EQ(4U, controller_states_ptr->size());
+ EXPECT_EQ(5U, controller_states_ptr->size());
EXPECT_EQ(1U, controller_states_ptr->count(syncable::BOOKMARKS));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::PREFERENCES));
EXPECT_EQ(0U, controller_states_ptr->count(syncable::AUTOFILL));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::THEMES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::EXTENSIONS));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::APPS));
}
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableBookmarks) {
command_line_->AppendSwitch(switches::kDisableSyncBookmarks);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
- EXPECT_EQ(4U, controller_states_ptr->size());
+ EXPECT_EQ(5U, controller_states_ptr->size());
EXPECT_EQ(0U, controller_states_ptr->count(syncable::BOOKMARKS));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::PREFERENCES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::AUTOFILL));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::THEMES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::EXTENSIONS));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::APPS));
}
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisablePreferences) {
command_line_->AppendSwitch(switches::kDisableSyncPreferences);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
- EXPECT_EQ(4U, controller_states_ptr->size());
+ EXPECT_EQ(5U, controller_states_ptr->size());
EXPECT_EQ(1U, controller_states_ptr->count(syncable::BOOKMARKS));
EXPECT_EQ(0U, controller_states_ptr->count(syncable::PREFERENCES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::AUTOFILL));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::THEMES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::EXTENSIONS));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::APPS));
}
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableThemes) {
command_line_->AppendSwitch(switches::kDisableSyncThemes);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
- EXPECT_EQ(4U, controller_states_ptr->size());
+ EXPECT_EQ(5U, controller_states_ptr->size());
EXPECT_EQ(1U, controller_states_ptr->count(syncable::BOOKMARKS));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::PREFERENCES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::AUTOFILL));
EXPECT_EQ(0U, controller_states_ptr->count(syncable::THEMES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::EXTENSIONS));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::APPS));
}
TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableExtensions) {
command_line_->AppendSwitch(switches::kDisableSyncExtensions);
scoped_ptr<ProfileSyncService> pss;
- pss.reset(profile_sync_service_factory_->CreateProfileSyncService());
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
DataTypeController::StateMap controller_states;
DataTypeController::StateMap* controller_states_ptr = &controller_states;
pss->GetDataTypeControllerStates(controller_states_ptr);
- EXPECT_EQ(4U, controller_states_ptr->size());
+ EXPECT_EQ(5U, controller_states_ptr->size());
EXPECT_EQ(1U, controller_states_ptr->count(syncable::BOOKMARKS));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::PREFERENCES));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::AUTOFILL));
EXPECT_EQ(1U, controller_states_ptr->count(syncable::THEMES));
EXPECT_EQ(0U, controller_states_ptr->count(syncable::EXTENSIONS));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::APPS));
+}
+
+TEST_F(ProfileSyncFactoryImplTest, CreatePSSDisableApps) {
+ command_line_->AppendSwitch(switches::kDisableSyncApps);
+ scoped_ptr<ProfileSyncService> pss;
+ pss.reset(profile_sync_service_factory_->CreateProfileSyncService(""));
+ DataTypeController::StateMap controller_states;
+ DataTypeController::StateMap* controller_states_ptr = &controller_states;
+ pss->GetDataTypeControllerStates(controller_states_ptr);
+ EXPECT_EQ(5U, controller_states_ptr->size());
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::BOOKMARKS));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::PREFERENCES));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::AUTOFILL));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::THEMES));
+ EXPECT_EQ(1U, controller_states_ptr->count(syncable::EXTENSIONS));
+ EXPECT_EQ(0U, controller_states_ptr->count(syncable::APPS));
}
diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h
index a323b34..18cc30c 100644
--- a/chrome/browser/sync/profile_sync_factory_mock.h
+++ b/chrome/browser/sync/profile_sync_factory_mock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_MOCK_H__
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_MOCK_H__
+#pragma once
#include "base/scoped_ptr.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -22,12 +23,15 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory {
browser_sync::AssociatorInterface* bookmark_model_associator,
browser_sync::ChangeProcessor* bookmark_change_processor);
- MOCK_METHOD0(CreateProfileSyncService,
- ProfileSyncService*(void));
+ MOCK_METHOD1(CreateProfileSyncService,
+ ProfileSyncService*(const std::string&));
MOCK_METHOD2(CreateDataTypeManager,
browser_sync::DataTypeManager*(
browser_sync::SyncBackendHost*,
const browser_sync::DataTypeController::TypeMap&));
+ MOCK_METHOD2(CreateAppSyncComponents,
+ SyncComponents(ProfileSyncService* profile_sync_service,
+ browser_sync::UnrecoverableErrorHandler* error_handler));
MOCK_METHOD4(CreateAutofillSyncComponents,
SyncComponents(
ProfileSyncService* profile_sync_service,
@@ -48,6 +52,9 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory {
MOCK_METHOD2(CreatePreferenceSyncComponents,
SyncComponents(ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler));
+ MOCK_METHOD2(CreateSessionSyncComponents,
+ SyncComponents(ProfileSyncService* profile_sync_service,
+ browser_sync::UnrecoverableErrorHandler* error_handler));
MOCK_METHOD2(CreateThemeSyncComponents,
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 8b21a52..9788f2c 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -10,26 +10,31 @@
#include "app/l10n_util.h"
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
+#include "base/string16.h"
#include "base/string_util.h"
#include "base/task.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/sync/engine/syncapi.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"
+#include "chrome/browser/sync/glue/session_data_type_controller.h"
#include "chrome/browser/sync/profile_sync_factory.h"
+#include "chrome/browser/sync/signin_manager.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
+#include "chrome/browser/sync/token_migrator.h"
+#include "chrome/browser/sync/util/user_settings.h"
#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"
@@ -37,12 +42,14 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
+#include "jingle/notifier/communicator/const_communicator.h"
#include "net/base/cookie_monster.h"
using browser_sync::ChangeProcessor;
using browser_sync::DataTypeController;
using browser_sync::DataTypeManager;
using browser_sync::SyncBackendHost;
+using sync_api::SyncCredentials;
typedef GoogleServiceAuthError AuthError;
@@ -54,34 +61,24 @@ const char* ProfileSyncService::kDevServerUrl =
ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
Profile* profile,
- bool bootstrap_sync_authentication)
+ const std::string& cros_user)
: last_auth_error_(AuthError::None()),
factory_(factory),
profile_(profile),
- bootstrap_sync_authentication_(bootstrap_sync_authentication),
+ cros_user_(cros_user),
sync_service_url_(kDevServerUrl),
backend_initialized_(false),
- expecting_first_run_auth_needed_event_(false),
is_auth_in_progress_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(wizard_(this)),
unrecoverable_error_detected_(false),
- use_chrome_async_socket_(false),
- notification_method_(browser_sync::kDefaultNotificationMethod),
- ALLOW_THIS_IN_INITIALIZER_LIST(scoped_runnable_method_factory_(this)) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(scoped_runnable_method_factory_(this)),
+ token_migrator_(NULL),
+ clear_server_data_state_(CLEAR_NOT_STARTED) {
DCHECK(factory);
DCHECK(profile);
registrar_.Add(this,
- NotificationType::SYNC_CONFIGURE_START,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::SYNC_CONFIGURE_DONE,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::SYNC_PASSPHRASE_REQUIRED,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::SYNC_PASSPHRASE_ACCEPTED,
- NotificationService::AllSources());
+ NotificationType::SYNC_DATA_TYPES_UPDATED,
+ Source<Profile>(profile));
// By default, dev & chromium users will go to the development servers.
// Dev servers have more features than standard sync servers.
@@ -92,15 +89,10 @@ ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
// For linux Chromium builds, this could be anything depending on the
// distribution, so always direct those users to dev server urls.
// If this is an official build, it will always be one of the above.
- string16 channel = platform_util::GetVersionStringModifier();
- if (channel.empty() || channel == ASCIIToUTF16("beta")) {
- LOG(INFO) << "Detected official build, using official sync server.";
+ std::string channel = platform_util::GetVersionStringModifier();
+ if (channel.empty() || channel == "beta") {
sync_service_url_ = GURL(kSyncServerUrl);
- } else {
- LOG(INFO) << "Detected official build, but using dev channel sync server.";
}
-#else
- LOG(INFO) << "Unofficial build, using dev channel sync server.";
#endif
}
@@ -108,15 +100,11 @@ ProfileSyncService::ProfileSyncService()
: last_auth_error_(AuthError::None()),
factory_(NULL),
profile_(NULL),
- bootstrap_sync_authentication_(false),
sync_service_url_(kSyncServerUrl),
backend_initialized_(false),
- expecting_first_run_auth_needed_event_(false),
is_auth_in_progress_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(wizard_(this)),
unrecoverable_error_detected_(false),
- use_chrome_async_socket_(false),
- notification_method_(browser_sync::kDefaultNotificationMethod),
ALLOW_THIS_IN_INITIALIZER_LIST(scoped_runnable_method_factory_(this)),
expect_sync_configuration_aborted_(false) {
}
@@ -125,8 +113,38 @@ ProfileSyncService::~ProfileSyncService() {
Shutdown(false);
}
+bool ProfileSyncService::AreCredentialsAvailable() {
+ if (IsManaged()) {
+ return false;
+ }
+
+ if (profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
+ return false;
+ }
+
+ // CrOS user is always logged in. Chrome uses signin_ to check logged in.
+ if (!cros_user_.empty() || !signin_.GetUsername().empty()) {
+ // TODO(chron): Verify CrOS unit test behavior.
+ if (profile()->GetTokenService() &&
+ profile()->GetTokenService()->HasTokenForService(
+ GaiaConstants::kSyncService)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ProfileSyncService::LoadMigratedCredentials(const std::string& username,
+ const std::string& token) {
+ signin_.SetUsername(username);
+ profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username);
+ profile()->GetTokenService()->OnIssueAuthTokenSuccess(
+ GaiaConstants::kSyncService, token);
+ profile()->GetPrefs()->SetBoolean(prefs::kSyncCredentialsMigrated, true);
+ token_migrator_.reset();
+}
+
void ProfileSyncService::Initialize() {
- LOG(INFO) << "Starting ProfileSyncService.";
InitSettings();
RegisterPreferences();
@@ -140,23 +158,49 @@ void ProfileSyncService::Initialize() {
return;
}
- if (!profile()->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) {
- DisableForUser(); // Clean up in case of previous crash / setup abort.
+ RegisterAuthNotifications();
- // Automatically start sync in Chromium OS.
- if (bootstrap_sync_authentication_) {
- // If the LSID is empty, we're in a CrOS UI test that is not testing sync
- // behavior, so we don't want the sync service to start.
- if (profile()->GetTokenService() &&
- !profile()->GetTokenService()->HasLsid()) {
- LOG(WARNING) << "Skipping CrOS sync startup, no LSID present.";
- return;
- }
- StartUp();
+ // In Chrome, we integrate a SigninManager which works with the sync
+ // setup wizard to kick off the TokenService. CrOS does its own plumbing
+ // for the TokenService.
+ if (cros_user_.empty()) {
+ // Will load tokens from DB and broadcast Token events after.
+ signin_.Initialize(profile_);
+ }
+
+ if (!HasSyncSetupCompleted()) {
+ DisableForUser(); // Clean up in case of previous crash / setup abort.
+ if (!cros_user_.empty() && AreCredentialsAvailable()) {
+ StartUp(); // Under ChromeOS, just autostart it anyway if creds are here.
}
- } else {
+ } else if (AreCredentialsAvailable()) {
+ // If we have credentials and sync setup finished, autostart the backend.
+ // Note that if we haven't finished setting up sync, backend bring up will
+ // be done by the wizard.
StartUp();
+ } else {
+ // Try to migrate the tokens (if that hasn't already succeeded).
+ if (!profile()->GetPrefs()->GetBoolean(prefs::kSyncCredentialsMigrated)) {
+ token_migrator_.reset(new TokenMigrator(this, profile_->GetPath()));
+ token_migrator_->TryMigration();
+ }
}
+
+}
+
+void ProfileSyncService::RegisterAuthNotifications() {
+ registrar_.Add(this,
+ NotificationType::TOKEN_AVAILABLE,
+ Source<TokenService>(profile_->GetTokenService()));
+ registrar_.Add(this,
+ NotificationType::TOKEN_LOADING_FINISHED,
+ Source<TokenService>(profile_->GetTokenService()));
+ registrar_.Add(this,
+ NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
+ Source<SigninManager>(&signin_));
+ registrar_.Add(this,
+ NotificationType::GOOGLE_SIGNIN_FAILED,
+ Source<SigninManager>(&signin_));
}
void ProfileSyncService::RegisterDataTypeController(
@@ -166,6 +210,28 @@ void ProfileSyncService::RegisterDataTypeController(
data_type_controller;
}
+browser_sync::SessionModelAssociator*
+ ProfileSyncService::GetSessionModelAssociator() {
+ if (data_type_controllers_.find(syncable::SESSIONS) ==
+ data_type_controllers_.end() ||
+ data_type_controllers_.find(syncable::SESSIONS)->second->state() !=
+ DataTypeController::RUNNING) {
+ return NULL;
+ }
+ return static_cast<browser_sync::SessionDataTypeController*>(
+ data_type_controllers_.find(
+ syncable::SESSIONS)->second.get())->GetModelAssociator();
+}
+
+void ProfileSyncService::ResetClearServerDataState() {
+ clear_server_data_state_ = CLEAR_NOT_STARTED;
+}
+
+ProfileSyncService::ClearServerDataState
+ ProfileSyncService::GetClearServerDataState() {
+ return clear_server_data_state_;
+}
+
void ProfileSyncService::GetDataTypeControllerStates(
browser_sync::DataTypeController::StateMap* state_map) const {
browser_sync::DataTypeController::TypeMap::const_iterator iter
@@ -194,19 +260,29 @@ void ProfileSyncService::InitSettings() {
}
}
- LOG(INFO) << "Using " << sync_service_url_ << " for sync server URL.";
+ // Override the notification server host from the command-line, if provided.
+ if (command_line.HasSwitch(switches::kSyncNotificationHost)) {
+ std::string value(command_line.GetSwitchValueASCII(
+ switches::kSyncNotificationHost));
+ if (!value.empty()) {
+ notifier_options_.xmpp_host_port.set_host(value);
+ notifier_options_.xmpp_host_port.set_port(notifier::kDefaultXmppPort);
+ }
+ LOG(INFO) << "Using " << notifier_options_.xmpp_host_port.ToString()
+ << " for test sync notification server.";
+ }
- use_chrome_async_socket_ =
- command_line.HasSwitch(switches::kSyncUseChromeAsyncSocket);
- if (use_chrome_async_socket_) {
- LOG(INFO) << "Using ChromeAsyncSocket";
+ notifier_options_.try_ssltcp_first =
+ command_line.HasSwitch(switches::kSyncUseSslTcp);
+ if (notifier_options_.try_ssltcp_first) {
+ LOG(INFO) << "Trying SSL/TCP port before XMPP port for notifications.";
}
if (command_line.HasSwitch(switches::kSyncNotificationMethod)) {
const std::string notification_method_str(
command_line.GetSwitchValueASCII(switches::kSyncNotificationMethod));
- notification_method_ =
- browser_sync::StringToNotificationMethod(notification_method_str);
+ notifier_options_.notification_method =
+ notifier::StringToNotificationMethod(notification_method_str);
}
}
@@ -216,6 +292,8 @@ void ProfileSyncService::RegisterPreferences() {
return;
pref_service->RegisterInt64Pref(prefs::kSyncLastSyncedTime, 0);
pref_service->RegisterBooleanPref(prefs::kSyncHasSetupCompleted, false);
+ pref_service->RegisterBooleanPref(prefs::kSyncSuppressStart, false);
+ pref_service->RegisterBooleanPref(prefs::kSyncCredentialsMigrated, false);
// If you've never synced before, or if you're using Chrome OS, all datatypes
// are on by default.
@@ -229,61 +307,76 @@ void ProfileSyncService::RegisterPreferences() {
#endif
pref_service->RegisterBooleanPref(prefs::kSyncBookmarks, true);
- pref_service->RegisterBooleanPref(prefs::kSyncPasswords, enable_by_default);
+ pref_service->RegisterBooleanPref(prefs::kSyncPasswords, false);
pref_service->RegisterBooleanPref(prefs::kSyncPreferences, enable_by_default);
pref_service->RegisterBooleanPref(prefs::kSyncAutofill, enable_by_default);
pref_service->RegisterBooleanPref(prefs::kSyncThemes, enable_by_default);
pref_service->RegisterBooleanPref(prefs::kSyncTypedUrls, enable_by_default);
pref_service->RegisterBooleanPref(prefs::kSyncExtensions, enable_by_default);
-
+ pref_service->RegisterBooleanPref(prefs::kSyncApps, enable_by_default);
+ pref_service->RegisterBooleanPref(prefs::kSyncSessions, enable_by_default);
pref_service->RegisterBooleanPref(prefs::kKeepEverythingSynced,
enable_by_default);
-
pref_service->RegisterBooleanPref(prefs::kSyncManaged, false);
+ pref_service->RegisterStringPref(prefs::kEncryptionBootstrapToken, "");
+ pref_service->RegisterBooleanPref(prefs::kSyncUsingSecondaryPassphrase,
+ false);
}
void ProfileSyncService::ClearPreferences() {
PrefService* pref_service = profile_->GetPrefs();
pref_service->ClearPref(prefs::kSyncLastSyncedTime);
pref_service->ClearPref(prefs::kSyncHasSetupCompleted);
+ pref_service->ClearPref(prefs::kEncryptionBootstrapToken);
// TODO(nick): The current behavior does not clear e.g. prefs::kSyncBookmarks.
// Is that really what we want?
pref_service->ScheduleSavePersistentPrefs();
}
+SyncCredentials ProfileSyncService::GetCredentials() {
+ SyncCredentials credentials;
+ credentials.email = !cros_user_.empty() ? cros_user_ : signin_.GetUsername();
+ DCHECK(!credentials.email.empty());
+ TokenService* service = profile_->GetTokenService();
+ credentials.sync_token = service->GetTokenForService(
+ GaiaConstants::kSyncService);
+ return credentials;
+}
+
void ProfileSyncService::InitializeBackend(bool delete_sync_data_folder) {
if (!backend_.get()) {
NOTREACHED();
return;
}
- // TODO(akalin): Gather all the command-line-controlled switches
- // into an Options struct to make passing them down less annoying.
+ // TODO(chron): Reimplement invalidate XMPP login / Sync login
+ // command line switches. Perhaps make it a command
+ // line in the TokenService itself to pass an arbitrary
+ // token.
- bool invalidate_sync_login = false;
- bool invalidate_sync_xmpp_login = false;
-#if !defined(NDEBUG)
- invalidate_sync_login = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kInvalidateSyncLogin);
- invalidate_sync_xmpp_login = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kInvalidateSyncXmppLogin);
-#endif
syncable::ModelTypeSet types;
// If sync setup hasn't finished, we don't want to initialize routing info
// for any data types so that we don't download updates for types that the
// user chooses not to sync on the first DownloadUpdatesCommand.
- if (HasSyncSetupCompleted())
+ if (HasSyncSetupCompleted()) {
GetPreferredDataTypes(&types);
+ }
+
+ SyncCredentials credentials = GetCredentials();
+
backend_->Initialize(sync_service_url_,
types,
profile_->GetRequestContext(),
- profile_->GetTokenService()->GetLsid(),
+ credentials,
delete_sync_data_folder,
- invalidate_sync_login,
- invalidate_sync_xmpp_login,
- use_chrome_async_socket_,
- notification_method_);
+ notifier_options_);
+}
+
+void ProfileSyncService::CreateBackend() {
+ backend_.reset(
+ new SyncBackendHost(this, profile_, profile_->GetPath(),
+ data_type_controllers_));
}
void ProfileSyncService::StartUp() {
@@ -293,14 +386,19 @@ void ProfileSyncService::StartUp() {
return;
}
- LOG(INFO) << "ProfileSyncSerivce bringing up backend host.";
+ DCHECK(AreCredentialsAvailable());
last_synced_time_ = base::Time::FromInternalValue(
profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
- backend_.reset(
- new SyncBackendHost(this, profile_, profile_->GetPath(),
- data_type_controllers_));
+ CreateBackend();
+
+ registrar_.Add(this,
+ NotificationType::SYNC_PASSPHRASE_REQUIRED,
+ Source<SyncBackendHost>(backend_.get()));
+ registrar_.Add(this,
+ NotificationType::SYNC_PASSPHRASE_ACCEPTED,
+ Source<SyncBackendHost>(backend_.get()));
// Initialize the backend. Every time we start up a new SyncBackendHost,
// we'll want to start from a fresh SyncDB, so delete any old one that might
@@ -309,8 +407,7 @@ void ProfileSyncService::StartUp() {
}
void ProfileSyncService::Shutdown(bool sync_disabled) {
-
- // Stop all data type controllers, if needed.
+ // Stop all data type controllers, if needed.
if (data_type_manager_.get() &&
data_type_manager_->state() != DataTypeManager::STOPPED) {
data_type_manager_->Stop();
@@ -331,31 +428,24 @@ void ProfileSyncService::Shutdown(bool sync_disabled) {
// Clear various flags.
is_auth_in_progress_ = false;
backend_initialized_ = false;
- expecting_first_run_auth_needed_event_ = false;
last_attempted_user_email_.clear();
}
-void ProfileSyncService::EnableForUser(gfx::NativeWindow parent_window) {
- if (WizardIsVisible()) {
- wizard_.Focus();
- return;
- }
- expecting_first_run_auth_needed_event_ = true;
- DCHECK(!data_type_manager_.get());
-
- wizard_.SetParent(parent_window);
- StartUp();
- FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+void ProfileSyncService::ClearServerData() {
+ clear_server_data_state_ = CLEAR_CLEARING;
+ backend_->RequestClearServerData();
}
void ProfileSyncService::DisableForUser() {
- LOG(INFO) << "Clearing Sync DB.";
-
- // Clear prefs (including SyncSetupHasCompleted) before shutting down so
+ // Clear prefs (including SyncSetupHasCompleted) before shutting down so
// PSS clients don't think we're set up while we're shutting down.
ClearPreferences();
Shutdown(true);
+ if (cros_user_.empty()) {
+ signin_.SignOut();
+ }
+
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
@@ -366,6 +456,12 @@ bool ProfileSyncService::HasSyncSetupCompleted() const {
void ProfileSyncService::SetSyncSetupCompleted() {
PrefService* prefs = profile()->GetPrefs();
prefs->SetBoolean(prefs::kSyncHasSetupCompleted, true);
+ prefs->SetBoolean(prefs::kSyncSuppressStart, false);
+
+ // Indicate that setup has been completed on the new credentials store
+ // so that we don't try to migrate.
+ prefs->SetBoolean(prefs::kSyncCredentialsMigrated, true);
+
prefs->ScheduleSavePersistentPrefs();
}
@@ -377,7 +473,7 @@ void ProfileSyncService::UpdateLastSyncedTime() {
}
// static
-const wchar_t* ProfileSyncService::GetPrefNameForDataType(
+const char* ProfileSyncService::GetPrefNameForDataType(
syncable::ModelType data_type) {
switch (data_type) {
case syncable::BOOKMARKS:
@@ -394,6 +490,10 @@ const wchar_t* ProfileSyncService::GetPrefNameForDataType(
return prefs::kSyncTypedUrls;
case syncable::EXTENSIONS:
return prefs::kSyncExtensions;
+ case syncable::APPS:
+ return prefs::kSyncApps;
+ case syncable::SESSIONS:
+ return prefs::kSyncSessions;
default:
NOTREACHED();
return NULL;
@@ -412,29 +512,20 @@ void ProfileSyncService::OnUnrecoverableError(
from_here.file_name(),
from_here.line_number()));
- // Shut all data types down.
- if (data_type_manager_.get())
- data_type_manager_->Stop();
-
// Tell the wizard so it can inform the user only if it is already open.
wizard_.Step(SyncSetupWizard::FATAL_ERROR);
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
- LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable.";
+ LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable."
+ << message;
std::string location;
from_here.Write(true, true, &location);
LOG(ERROR) << location;
- if (SetupInProgress()) {
- // We've hit an error in the middle of a startup process- shutdown all the
- // backend stuff, and then restart it, so we're in the same state as before.
- MessageLoop::current()->PostTask(FROM_HERE,
+ // Shut all data types down.
+ MessageLoop::current()->PostTask(FROM_HERE,
scoped_runnable_method_factory_.NewRunnableMethod(
&ProfileSyncService::Shutdown, true));
- MessageLoop::current()->PostTask(FROM_HERE,
- scoped_runnable_method_factory_.NewRunnableMethod(
- &ProfileSyncService::StartUp));
- }
}
void ProfileSyncService::OnBackendInitialized() {
@@ -443,16 +534,22 @@ void ProfileSyncService::OnBackendInitialized() {
// The very first time the backend initializes is effectively the first time
// we can say we successfully "synced". last_synced_time_ will only be null
// in this case, because the pref wasn't restored on StartUp.
- if (last_synced_time_.is_null())
+ if (last_synced_time_.is_null()) {
UpdateLastSyncedTime();
+ }
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
- if (bootstrap_sync_authentication_) {
- SetSyncSetupCompleted();
+ if (!cros_user_.empty()) {
+ if (profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
+ ShowChooseDataTypes(NULL);
+ } else {
+ SetSyncSetupCompleted();
+ }
}
- if (HasSyncSetupCompleted())
+ if (HasSyncSetupCompleted()) {
ConfigureDataTypeManager();
+ }
}
void ProfileSyncService::OnSyncCycleCompleted() {
@@ -460,23 +557,17 @@ void ProfileSyncService::OnSyncCycleCompleted() {
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
-void ProfileSyncService::OnAuthError() {
- last_auth_error_ = backend_->GetAuthError();
+void ProfileSyncService::UpdateAuthErrorState(
+ const GoogleServiceAuthError& error) {
+ last_auth_error_ = error;
// Protect against the in-your-face dialogs that pop out of nowhere.
// Require the user to click somewhere to run the setup wizard in the case
// of a steady-state auth failure.
- if (WizardIsVisible() || expecting_first_run_auth_needed_event_) {
+ if (WizardIsVisible()) {
wizard_.Step(AuthError::NONE == last_auth_error_.state() ?
SyncSetupWizard::GAIA_SUCCESS : SyncSetupWizard::GAIA_LOGIN);
- }
-
- if (expecting_first_run_auth_needed_event_) {
- last_auth_error_ = AuthError::None();
- expecting_first_run_auth_needed_event_ = false;
- }
-
- if (!WizardIsVisible()) {
- auth_error_time_ == base::TimeTicks::Now();
+ } else {
+ auth_error_time_ = base::TimeTicks::Now();
}
if (!auth_start_time_.is_null()) {
@@ -490,16 +581,36 @@ void ProfileSyncService::OnAuthError() {
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
+void ProfileSyncService::OnAuthError() {
+ UpdateAuthErrorState(backend_->GetAuthError());
+}
+
void ProfileSyncService::OnStopSyncingPermanently() {
if (SetupInProgress()) {
wizard_.Step(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR);
expect_sync_configuration_aborted_ = true;
}
-
+ profile_->GetPrefs()->SetBoolean(prefs::kSyncSuppressStart, true);
DisableForUser();
}
+void ProfileSyncService::OnClearServerDataFailed() {
+ clear_server_data_state_ = CLEAR_FAILED;
+ FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+}
+
+void ProfileSyncService::OnClearServerDataSucceeded() {
+ clear_server_data_state_ = CLEAR_SUCCEEDED;
+ FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
+}
+
void ProfileSyncService::ShowLoginDialog(gfx::NativeWindow parent_window) {
+ // TODO(johnnyg): File a bug to make sure this doesn't happen.
+ if (!cros_user_.empty()) {
+ LOG(WARNING) << "ShowLoginDialog called on Chrome OS.";
+ return;
+ }
+
if (WizardIsVisible()) {
wizard_.Focus();
return;
@@ -511,10 +622,10 @@ void ProfileSyncService::ShowLoginDialog(gfx::NativeWindow parent_window) {
auth_error_time_ = base::TimeTicks(); // Reset auth_error_time_ to null.
}
- if (last_auth_error_.state() != AuthError::NONE) {
- wizard_.SetParent(parent_window);
- wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
- }
+ wizard_.SetParent(parent_window);
+ wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
+
+ FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
}
void ProfileSyncService::ShowChooseDataTypes(gfx::NativeWindow parent_window) {
@@ -527,14 +638,14 @@ void ProfileSyncService::ShowChooseDataTypes(gfx::NativeWindow parent_window) {
}
SyncBackendHost::StatusSummary ProfileSyncService::QuerySyncStatusSummary() {
- if (backend_.get())
+ if (backend_.get() && backend_initialized_)
return backend_->GetStatusSummary();
else
return SyncBackendHost::Status::OFFLINE_UNUSABLE;
}
SyncBackendHost::Status ProfileSyncService::QueryDetailedSyncStatus() {
- if (backend_.get()) {
+ if (backend_.get() && backend_initialized_) {
return backend_->GetDetailedStatus();
} else {
SyncBackendHost::Status status =
@@ -543,41 +654,45 @@ SyncBackendHost::Status ProfileSyncService::QueryDetailedSyncStatus() {
}
}
-std::wstring ProfileSyncService::BuildSyncStatusSummaryText(
+bool ProfileSyncService::SetupInProgress() const {
+ return !HasSyncSetupCompleted() && WizardIsVisible();
+}
+
+std::string ProfileSyncService::BuildSyncStatusSummaryText(
const sync_api::SyncManager::Status::Summary& summary) {
switch (summary) {
case sync_api::SyncManager::Status::OFFLINE:
- return L"OFFLINE";
+ return "OFFLINE";
case sync_api::SyncManager::Status::OFFLINE_UNSYNCED:
- return L"OFFLINE_UNSYNCED";
+ return "OFFLINE_UNSYNCED";
case sync_api::SyncManager::Status::SYNCING:
- return L"SYNCING";
+ return "SYNCING";
case sync_api::SyncManager::Status::READY:
- return L"READY";
+ return "READY";
case sync_api::SyncManager::Status::CONFLICT:
- return L"CONFLICT";
+ return "CONFLICT";
case sync_api::SyncManager::Status::OFFLINE_UNUSABLE:
- return L"OFFLINE_UNUSABLE";
+ return "OFFLINE_UNUSABLE";
case sync_api::SyncManager::Status::INVALID: // fall through
default:
- return L"UNKNOWN";
+ return "UNKNOWN";
}
}
-std::wstring ProfileSyncService::GetLastSyncedTimeString() const {
+string16 ProfileSyncService::GetLastSyncedTimeString() const {
if (last_synced_time_.is_null())
- return l10n_util::GetString(IDS_SYNC_TIME_NEVER);
+ return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
base::TimeDelta last_synced = base::Time::Now() - last_synced_time_;
if (last_synced < base::TimeDelta::FromMinutes(1))
- return l10n_util::GetString(IDS_SYNC_TIME_JUST_NOW);
+ return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
return TimeFormat::TimeElapsed(last_synced);
}
string16 ProfileSyncService::GetAuthenticatedUsername() const {
- if (backend_.get())
+ if (backend_.get() && backend_initialized_)
return backend_->GetAuthenticatedUsername();
else
return string16();
@@ -586,16 +701,26 @@ string16 ProfileSyncService::GetAuthenticatedUsername() const {
void ProfileSyncService::OnUserSubmittedAuth(
const std::string& username, const std::string& password,
const std::string& captcha) {
- if (!backend_.get()) {
- NOTREACHED();
- return;
- }
last_attempted_user_email_ = username;
is_auth_in_progress_ = true;
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
auth_start_time_ = base::TimeTicks::Now();
- backend_->Authenticate(username, password, captcha);
+
+ // TODO(chron): Mechanism for ChromeOS auth renewal?
+ // (maybe just run the dialog anyway?)
+ // or send it to the CrOS login somehow?
+ if (!cros_user_.empty()) {
+ LOG(WARNING) << "No mechanism on ChromeOS yet. See http://crbug.com/50292";
+ }
+
+ if (!signin_.GetUsername().empty()) {
+ signin_.SignOut();
+ }
+ signin_.StartSignIn(username,
+ password,
+ last_auth_error_.captcha().token,
+ captcha);
}
void ProfileSyncService::OnUserChoseDatatypes(bool sync_everything,
@@ -612,9 +737,10 @@ void ProfileSyncService::OnUserChoseDatatypes(bool sync_everything,
}
void ProfileSyncService::OnUserCancelledDialog() {
- if (!profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) {
+ if (!HasSyncSetupCompleted()) {
// A sync dialog was aborted before authentication.
// Rollback.
+ expect_sync_configuration_aborted_ = true;
DisableForUser();
}
wizard_.SetParent(NULL);
@@ -643,7 +769,7 @@ void ProfileSyncService::ChangePreferredDataTypes(
syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
if (!registered_types.count(model_type))
continue;
- const wchar_t* pref_name = GetPrefNameForDataType(model_type);
+ const char* pref_name = GetPrefNameForDataType(model_type);
if (!pref_name)
continue;
profile_->GetPrefs()->SetBoolean(pref_name,
@@ -664,15 +790,19 @@ void ProfileSyncService::GetPreferredDataTypes(
// 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;
- const wchar_t* pref_name = GetPrefNameForDataType(model_type);
- if (!pref_name)
- continue;
- if (profile_->GetPrefs()->GetBoolean(pref_name))
- preferred_types->insert(model_type);
+ if (profile_->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced)) {
+ *preferred_types = registered_types;
+ } else {
+ for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
+ syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
+ if (!registered_types.count(model_type))
+ continue;
+ const char* pref_name = GetPrefNameForDataType(model_type);
+ if (!pref_name)
+ continue;
+ if (profile_->GetPrefs()->GetBoolean(pref_name))
+ preferred_types->insert(model_type);
+ }
}
}
@@ -689,12 +819,24 @@ void ProfileSyncService::GetRegisteredDataTypes(
}
bool ProfileSyncService::IsCryptographerReady() const {
- return backend_->GetUserShareHandle()->
- dir_manager->cryptographer()->is_ready();
+ return backend_.get() && backend_initialized_ &&
+ backend_->GetUserShareHandle()->dir_manager->cryptographer()->is_ready();
}
void ProfileSyncService::SetPassphrase(const std::string& passphrase) {
- backend_->SetPassphrase(passphrase);
+ // TODO(tim): This should be encryption-specific instead of passwords
+ // specific. For now we have to do this to avoid NIGORI node lookups when
+ // we haven't downloaded that node.
+ if (!profile_->GetPrefs()->GetBoolean(prefs::kSyncPasswords)) {
+ LOG(WARNING) << "Silently dropping SetPassphrase request.";
+ return;
+ }
+
+ if (!sync_initialized()) {
+ cached_passphrase_ = passphrase;
+ } else {
+ backend_->SetPassphrase(passphrase);
+ }
}
void ProfileSyncService::ConfigureDataTypeManager() {
@@ -702,6 +844,12 @@ void ProfileSyncService::ConfigureDataTypeManager() {
data_type_manager_.reset(
factory_->CreateDataTypeManager(backend_.get(),
data_type_controllers_));
+ registrar_.Add(this,
+ NotificationType::SYNC_CONFIGURE_START,
+ Source<DataTypeManager>(data_type_manager_.get()));
+ registrar_.Add(this,
+ NotificationType::SYNC_CONFIGURE_DONE,
+ Source<DataTypeManager>(data_type_manager_.get()));
}
syncable::ModelTypeSet types;
@@ -716,6 +864,7 @@ void ProfileSyncService::ActivateDataType(
NOTREACHED();
return;
}
+ DCHECK(backend_initialized_);
change_processor->Start(profile(), backend_->GetUserShareHandle());
backend_->ActivateDataType(data_type_controller, change_processor);
}
@@ -750,6 +899,12 @@ void ProfileSyncService::Observe(NotificationType type,
return;
}
+ if (!cached_passphrase_.empty()) {
+ // Don't hold on to the passphrase in raw form longer than needed.
+ SetPassphrase(cached_passphrase_);
+ cached_passphrase_.clear();
+ }
+
// TODO(sync): Less wizard, more toast.
wizard_.Step(SyncSetupWizard::DONE);
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
@@ -757,8 +912,24 @@ void ProfileSyncService::Observe(NotificationType type,
break;
}
case NotificationType::SYNC_PASSPHRASE_REQUIRED: {
+ DCHECK(backend_.get());
+ if (!cached_passphrase_.empty()) {
+ SetPassphrase(cached_passphrase_);
+ cached_passphrase_.clear();
+ break;
+ }
+
// TODO(sync): Show the passphrase UI here.
- SetPassphrase("dummy passphrase");
+ UpdateAuthErrorState(GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ break;
+ }
+ case NotificationType::SYNC_DATA_TYPES_UPDATED: {
+ if (!HasSyncSetupCompleted()) break;
+
+ syncable::ModelTypeSet types;
+ GetPreferredDataTypes(&types);
+ OnUserChoseDatatypes(false, types);
break;
}
case NotificationType::SYNC_PASSPHRASE_ACCEPTED: {
@@ -772,13 +943,49 @@ void ProfileSyncService::Observe(NotificationType type,
break;
}
case NotificationType::PREF_CHANGED: {
- std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ std::string* pref_name = Details<std::string>(details).ptr();
if (*pref_name == prefs::kSyncManaged) {
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
- if (*pref_sync_managed_)
+ if (*pref_sync_managed_) {
DisableForUser();
- else if (HasSyncSetupCompleted())
+ } else if (HasSyncSetupCompleted() && AreCredentialsAvailable()) {
StartUp();
+ }
+ }
+ break;
+ }
+ case NotificationType::GOOGLE_SIGNIN_SUCCESSFUL: {
+ if (!profile_->GetPrefs()->GetBoolean(
+ prefs::kSyncUsingSecondaryPassphrase)) {
+ const GoogleServiceSigninSuccessDetails* successful =
+ (Details<const GoogleServiceSigninSuccessDetails>(details).ptr());
+ SetPassphrase(successful->password);
+ }
+ break;
+ }
+ case NotificationType::GOOGLE_SIGNIN_FAILED: {
+ GoogleServiceAuthError error =
+ *(Details<const GoogleServiceAuthError>(details).ptr());
+ UpdateAuthErrorState(error);
+ break;
+ }
+ case NotificationType::TOKEN_AVAILABLE: {
+ if (AreCredentialsAvailable()) {
+ if (backend_initialized_) {
+ backend_->UpdateCredentials(GetCredentials());
+ }
+
+ StartUp();
+ }
+ break;
+ }
+ case NotificationType::TOKEN_LOADING_FINISHED: {
+ // If not in Chrome OS, and we have a username without tokens,
+ // the user will need to signin again, so sign out.
+ if (cros_user_.empty() &&
+ !signin_.GetUsername().empty() &&
+ !AreCredentialsAvailable()) {
+ DisableForUser();
}
break;
}
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index 9615124..dc3e67d 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -4,34 +4,39 @@
#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
+#pragma once
#include <string>
-#include <map>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/time.h"
-#include "chrome/browser/google_service_auth_error.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/data_type_manager.h"
+#include "chrome/browser/sync/glue/session_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
-#include "chrome/browser/sync/notification_method.h"
#include "chrome/browser/sync/profile_sync_service_observer.h"
+#include "chrome/browser/sync/signin_manager.h"
#include "chrome/browser/sync/sync_setup_wizard.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/unrecoverable_error_handler.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
+#include "jingle/notifier/base/notifier_options.h"
class NotificationDetails;
class NotificationSource;
class NotificationType;
class Profile;
class ProfileSyncFactory;
+class TokenMigrator;
// ProfileSyncService is the layer between browser subsystems like bookmarks,
// and the sync backend. Each subsystem is logically thought of as being
@@ -105,6 +110,14 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
MAX_SYNC_EVENT_CODE
};
+ // Keep track of where we are when clearing server data.
+ enum ClearServerDataState {
+ CLEAR_NOT_STARTED = 1,
+ CLEAR_CLEARING = 2,
+ CLEAR_FAILED = 3,
+ CLEAR_SUCCEEDED = 4,
+ };
+
// Default sync server URL.
static const char* kSyncServerUrl;
// Sync server URL for dev channel users
@@ -112,13 +125,23 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
ProfileSyncService(ProfileSyncFactory* factory_,
Profile* profile,
- bool bootstrap_sync_authentication);
+ const std::string& cros_user);
virtual ~ProfileSyncService();
// Initializes the object. This should be called every time an object of this
// class is constructed.
void Initialize();
+ void RegisterAuthNotifications();
+
+ // Return whether all sync tokens are loaded and
+ // available for the backend to start up.
+ bool AreCredentialsAvailable();
+
+ // Loads credentials migrated from the old user settings db.
+ void LoadMigratedCredentials(const std::string& username,
+ const std::string& token);
+
// Registers a data type controller with the sync service. This
// makes the data type controller available for use, it does not
// enable or activate the synchronization of the data type (see
@@ -126,15 +149,26 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
void RegisterDataTypeController(
browser_sync::DataTypeController* data_type_controller);
+ // Returns the session model associator associated with this type, but only if
+ // the associator is running. If it is doing anything else, it will return
+ // null.
+ browser_sync::SessionModelAssociator* GetSessionModelAssociator();
+
+ // Maintain state of where we are in a server clear operation.
+ void ResetClearServerDataState();
+ ClearServerDataState GetClearServerDataState();
+
// Fills state_map with a map of current data types that are possible to
// sync, as well as their states.
void GetDataTypeControllerStates(
browser_sync::DataTypeController::StateMap* state_map) const;
- // Enables/disables sync for user.
- virtual void EnableForUser(gfx::NativeWindow parent_window);
+ // Disables sync for user. Use ShowLoginDialog to enable.
virtual void DisableForUser();
+ // Clears all Chromesync data from the server.
+ void ClearServerData();
+
// Whether sync is enabled by user or not.
virtual bool HasSyncSetupCompleted() const;
void SetSyncSetupCompleted();
@@ -144,12 +178,17 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
virtual void OnSyncCycleCompleted();
virtual void OnAuthError();
virtual void OnStopSyncingPermanently();
+ virtual void OnClearServerDataFailed();
+ virtual void OnClearServerDataSucceeded();
// Called when a user enters credentials through UI.
virtual void OnUserSubmittedAuth(const std::string& username,
const std::string& password,
const std::string& captcha);
+ // Update the last auth error and notify observers of error state.
+ void UpdateAuthErrorState(const GoogleServiceAuthError& error);
+
// Called when a user chooses which data types to sync as part of the sync
// setup wizard. |sync_everything| represents whether they chose the
// "keep everything synced" option; if true, |chosen_types| will be ignored
@@ -175,10 +214,7 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// progress, the sync system is already authenticated, or some error
// occurred preventing the action. We make it the duty of ProfileSyncService
// to open the dialog to easily ensure only one is ever showing.
- bool SetupInProgress() const {
- return !HasSyncSetupCompleted() &&
- (WizardIsVisible() || bootstrap_sync_authentication_);
- }
+ bool SetupInProgress() const;
bool WizardIsVisible() const {
return wizard_.IsVisible();
}
@@ -187,7 +223,7 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
void ShowChooseDataTypes(gfx::NativeWindow parent_window);
// Pretty-printed strings for a given StatusSummary.
- static std::wstring BuildSyncStatusSummaryText(
+ static std::string BuildSyncStatusSummaryText(
const browser_sync::SyncBackendHost::StatusSummary& summary);
// Returns true if the SyncBackendHost has told us it's ready to accept
@@ -218,7 +254,7 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
const base::Time& last_synced_time() const { return last_synced_time_; }
// Returns a user-friendly string form of last synced time (in minutes).
- std::wstring GetLastSyncedTimeString() const;
+ string16 GetLastSyncedTimeString() const;
// Returns the authenticated username of the sync user, or empty if none
// exists. It will only exist if the authentication service provider (e.g
@@ -297,6 +333,12 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// NotificationService when the outcome is known.
virtual void SetPassphrase(const std::string& passphrase);
+ // Returns whether processing changes is allowed. Check this before doing
+ // any model-modifying operations.
+ bool ShouldPushChanges();
+
+ const GURL& sync_service_url() const { return sync_service_url_; }
+
protected:
// Used by ProfileSyncServiceMock only.
//
@@ -308,10 +350,6 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// Helper to install and configure a data type manager.
void ConfigureDataTypeManager();
- // Returns whether processing changes is allowed. Check this before doing
- // any model-modifying operations.
- bool ShouldPushChanges();
-
// Starts up the backend sync components.
void StartUp();
// Shuts down the backend sync components.
@@ -322,19 +360,19 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
void RegisterPreferences();
void ClearPreferences();
- // Tests need to override this. If |delete_sync_data_folder| is true, then
- // this method will delete all previous "Sync Data" folders. (useful if the
- // folder is partial/corrupt)
- virtual void InitializeBackend(bool delete_sync_data_folder);
+ // Return SyncCredentials from the TokenService.
+ sync_api::SyncCredentials GetCredentials();
+
+ // Test need to override this to create backends that allow setting up
+ // initial conditions, such as populating sync nodes.
+ virtual void CreateBackend();
const browser_sync::DataTypeController::TypeMap& data_type_controllers() {
return data_type_controllers_;
}
- // We keep track of the last auth error observed so we can cover up the first
- // "expected" auth failure from observers.
- // TODO(timsteele): Same as expecting_first_run_auth_needed_event_. Remove
- // this!
+ // The wizard will try to read the auth state out of the profile sync
+ // service using this member. Captcha and error state are reflected.
GoogleServiceAuthError last_auth_error_;
// Our asynchronous backend to communicate with sync components living on
@@ -346,19 +384,25 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
private:
friend class ProfileSyncServiceTest;
+ friend class ProfileSyncServicePasswordTest;
friend class ProfileSyncServicePreferenceTest;
+ friend class ProfileSyncServiceSessionTest;
friend class ProfileSyncServiceTestHarness;
FRIEND_TEST_ALL_PREFIXES(ProfileSyncServiceTest, InitialState);
FRIEND_TEST_ALL_PREFIXES(ProfileSyncServiceTest,
UnrecoverableErrorSuspendsService);
+ // If |delete_sync_data_folder| is true, then this method will delete all
+ // previous "Sync Data" folders. (useful if the folder is partial/corrupt).
+ void InitializeBackend(bool delete_sync_data_folder);
+
// Initializes the various settings from the command line.
void InitSettings();
// Sets the last synced time to the current time.
void UpdateLastSyncedTime();
- static const wchar_t* GetPrefNameForDataType(syncable::ModelType data_type);
+ static const char* GetPrefNameForDataType(syncable::ModelType data_type);
// Time at which we begin an attempt a GAIA authorization.
base::TimeTicks auth_start_time_;
@@ -372,11 +416,8 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// The profile whose data we are synchronizing.
Profile* profile_;
- // True if the profile sync service should attempt to use an LSID
- // cookie for authentication. This is typically set to true in
- // ChromiumOS since we want to use the system level authentication
- // for sync.
- bool bootstrap_sync_authentication_;
+ // Email for the ChromiumOS user, if we're running under ChromiumOS.
+ std::string cros_user_;
// TODO(ncarter): Put this in a profile, once there is UI for it.
// This specifies where to find the sync server.
@@ -392,17 +433,6 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// Whether the SyncBackendHost has been initialized.
bool backend_initialized_;
- // Set to true when the user first enables sync, and we are waiting for
- // syncapi to give us the green light on providing credentials for the first
- // time. It is set back to false as soon as we get this message, and is
- // false all other times so we don't have to persist this value as it will
- // get initialized to false.
- // TODO(timsteele): Remove this by way of starting the wizard when enabling
- // sync *before* initializing the backend. syncapi will need to change, but
- // it means we don't have to wait for the first AuthError; if we ever get
- // one, it is actually an error and this bool isn't needed.
- bool expecting_first_run_auth_needed_event_;
-
// Various pieces of UI query this value to determine if they should show
// an "Authenticating.." type of message. We are the only central place
// all auth attempts funnel through, so it makes sense to provide this.
@@ -411,6 +441,9 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
SyncSetupWizard wizard_;
+ // Encapsulates user signin with TokenService.
+ SigninManager signin_;
+
// True if an unrecoverable error (e.g. violation of an assumed invariant)
// occurred during syncer operation. This value should be checked before
// doing any work that might corrupt things further.
@@ -420,12 +453,9 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
std::string unrecoverable_error_message_;
scoped_ptr<tracked_objects::Location> unrecoverable_error_location_;
- // Whether to use the (new, untested) Chrome-socket-based
- // buzz::AsyncSocket implementation for notifications.
- bool use_chrome_async_socket_;
-
- // Which peer-to-peer notification method to use.
- browser_sync::NotificationMethod notification_method_;
+ // Contains options specific to how sync clients send and listen to
+ // notifications.
+ notifier::NotifierOptions notifier_options_;
// Manages the start and stop of the various data types.
scoped_ptr<browser_sync::DataTypeManager> data_type_manager_;
@@ -446,6 +476,17 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// desist syncing immediately.
bool expect_sync_configuration_aborted_;
+ scoped_ptr<TokenMigrator> token_migrator_;
+
+ // Sometimes we need to temporarily hold on to a passphrase because we don't
+ // yet have a backend to send it to. This happens during initialization as
+ // we don't StartUp until we have a valid token, which happens after valid
+ // credentials were provided.
+ std::string cached_passphrase_;
+
+ // Keep track of where we are in a server clear operation
+ ClearServerDataState clear_server_data_state_;
+
DISALLOW_COPY_AND_ASSIGN(ProfileSyncService);
};
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index ce88900..1d5d7d4 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -8,6 +8,7 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include "base/callback.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
@@ -19,7 +20,9 @@
#include "chrome/browser/autofill/autofill_common_unittest.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
+#include "chrome/browser/sync/engine/model_changing_syncer_command.h"
#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
@@ -27,14 +30,17 @@
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
+#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/test_profile_sync_service.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/net/gaia/gaia_constants.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/profile_mock.h"
+#include "chrome/test/sync/engine/test_id_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
using base::Time;
@@ -42,6 +48,20 @@ using base::WaitableEvent;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillDataTypeController;
using browser_sync::AutofillModelAssociator;
+using browser_sync::GROUP_DB;
+using browser_sync::kAutofillTag;
+using browser_sync::SyncBackendHostForProfileSyncTest;
+using browser_sync::SyncerUtil;
+using browser_sync::UnrecoverableErrorHandler;
+using syncable::CREATE_NEW_UPDATE_ITEM;
+using syncable::AUTOFILL;
+using syncable::DirectoryChangeEvent;
+using syncable::GET_BY_SERVER_TAG;
+using syncable::INVALID;
+using syncable::SERVER_PARENT_ID;
+using syncable::SERVER_SPECIFICS;
+using syncable::OriginalEntries;
+using syncable::WriterTag;
using syncable::WriteTransaction;
using testing::_;
using testing::DoAll;
@@ -49,10 +69,15 @@ using testing::DoDefault;
using testing::ElementsAre;
using testing::Eq;
using testing::Invoke;
+using testing::Mock;
using testing::Return;
using testing::SaveArg;
using testing::SetArgumentPointee;
+namespace syncable {
+class Id;
+}
+
class WebDatabaseMock : public WebDatabase {
public:
MOCK_METHOD2(RemoveFormElement,
@@ -138,13 +163,16 @@ class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest {
void StartSyncService(Task* task, bool will_fail_association) {
if (!service_.get()) {
service_.reset(
- new TestProfileSyncService(&factory_, &profile_, false, false,
+ new TestProfileSyncService(&factory_, &profile_, "test_user", false,
task));
AutofillDataTypeController* data_type_controller =
new AutofillDataTypeController(&factory_,
&profile_,
service_.get());
+ SyncBackendHostForProfileSyncTest::
+ SetDefaultExpectationsForWorkerCreation(&profile_);
+
EXPECT_CALL(factory_, CreateAutofillSyncComponents(_, _, _, _)).
WillOnce(MakeAutofillSyncComponents(service_.get(),
&web_database_,
@@ -162,6 +190,13 @@ class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest {
EXPECT_CALL(*personal_data_manager_, IsDataLoaded()).
WillRepeatedly(Return(true));
+ // We need tokens to get the tests going
+ token_service_.IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
+
+ EXPECT_CALL(profile_, GetTokenService()).
+ WillRepeatedly(Return(&token_service_));
+
service_->set_num_expected_resumes(will_fail_association ? 0 : 1);
service_->RegisterDataTypeController(data_type_controller);
service_->Initialize();
@@ -266,6 +301,7 @@ class ProfileSyncServiceAutofillTest : public AbstractProfileSyncServiceTest {
}
friend class AddAutofillEntriesTask;
+ friend class FakeServerUpdater;
ChromeThread db_thread_;
scoped_refptr<ThreadNotificationService> notification_service_;
@@ -307,6 +343,139 @@ class AddAutofillEntriesTask : public Task {
bool success_;
};
+// Overload write transaction to use custom NotifyTransactionComplete
+static const bool kLoggingInfo = true;
+class WriteTransactionTest: public WriteTransaction {
+ public:
+ WriteTransactionTest(const ScopedDirLookup& directory,
+ WriterTag writer, const char* source_file,
+ int line,
+ scoped_ptr<WaitableEvent> *wait_for_syncapi)
+ : WriteTransaction(directory, writer, source_file, line),
+ wait_for_syncapi_(wait_for_syncapi) { }
+
+ virtual void NotifyTransactionComplete() {
+ // This is where we differ. Force a thread change here, giving another
+ // thread a chance to create a WriteTransaction
+ (*wait_for_syncapi_)->Wait();
+
+ WriteTransaction::NotifyTransactionComplete();
+ }
+
+ private:
+ scoped_ptr<WaitableEvent> *wait_for_syncapi_;
+};
+
+// Our fake server updater. Needs the RefCountedThreadSafe inheritance so we can
+// post tasks with it.
+class FakeServerUpdater: public base::RefCountedThreadSafe<FakeServerUpdater> {
+ public:
+ FakeServerUpdater(TestProfileSyncService *service,
+ scoped_ptr<WaitableEvent> *wait_for_start,
+ scoped_ptr<WaitableEvent> *wait_for_syncapi)
+ : entry_(ProfileSyncServiceAutofillTest::MakeAutofillEntry("0", "0", 0)),
+ service_(service),
+ wait_for_start_(wait_for_start),
+ wait_for_syncapi_(wait_for_syncapi),
+ is_finished_(false, false) { }
+
+ void Update() {
+ // This gets called in a modelsafeworker thread.
+ ASSERT_TRUE(ChromeThread::CurrentlyOn(ChromeThread::DB));
+
+ UserShare* user_share = service_->backend()->GetUserShareHandle();
+ DirectoryManager* dir_manager = user_share->dir_manager.get();
+ ScopedDirLookup dir(dir_manager, user_share->name);
+ ASSERT_TRUE(dir.good());
+
+ // Create autofill protobuf
+ std::string tag = AutofillModelAssociator::KeyToTag(entry_.key().name(),
+ entry_.key().value());
+ sync_pb::AutofillSpecifics new_autofill;
+ new_autofill.set_name(UTF16ToUTF8(entry_.key().name()));
+ new_autofill.set_value(UTF16ToUTF8(entry_.key().value()));
+ const std::vector<base::Time>& ts(entry_.timestamps());
+ for (std::vector<base::Time>::const_iterator timestamp = ts.begin();
+ timestamp != ts.end(); ++timestamp) {
+ new_autofill.add_usage_timestamp(timestamp->ToInternalValue());
+ }
+
+ sync_pb::EntitySpecifics entity_specifics;
+ entity_specifics.MutableExtension(sync_pb::autofill)->
+ CopyFrom(new_autofill);
+
+ {
+ // Tell main thread we've started
+ (*wait_for_start_)->Signal();
+
+ // Create write transaction.
+ WriteTransactionTest trans(dir, UNITTEST, __FILE__, __LINE__,
+ wait_for_syncapi_);
+
+ // Create actual entry based on autofill protobuf information.
+ // Simulates effects of SyncerUtil::UpdateLocalDataFromServerData
+ MutableEntry parent(&trans, GET_BY_SERVER_TAG, kAutofillTag);
+ MutableEntry item(&trans, CREATE, parent.Get(syncable::ID), tag);
+ ASSERT_TRUE(item.good());
+ item.Put(SPECIFICS, entity_specifics);
+ item.Put(SERVER_SPECIFICS, entity_specifics);
+ item.Put(BASE_VERSION, 1);
+ syncable::Id server_parent_id = ids_.NewServerId();
+ item.Put(syncable::ID, server_parent_id);
+ syncable::Id new_predecessor =
+ SyncerUtil::ComputePrevIdFromServerPosition(&trans, &item,
+ server_parent_id);
+ ASSERT_TRUE(item.PutPredecessor(new_predecessor));
+ }
+ LOG(INFO) << "FakeServerUpdater finishing.";
+ is_finished_.Signal();
+ }
+
+ void CreateNewEntry(const AutofillEntry& entry) {
+ entry_ = entry;
+ scoped_ptr<Callback0::Type> c(NewCallback((FakeServerUpdater *)this,
+ &FakeServerUpdater::Update));
+ std::vector<browser_sync::ModelSafeWorker*> workers;
+ service_->backend()->GetWorkers(&workers);
+
+ ASSERT_FALSE(ChromeThread::CurrentlyOn(ChromeThread::DB));
+ if (!ChromeThread::PostTask(ChromeThread::DB, FROM_HERE,
+ NewRunnableMethod(this, &FakeServerUpdater::Update))) {
+ NOTREACHED() << "Failed to post task to the db thread.";
+ return;
+ }
+ }
+
+ void CreateNewEntryAndWait(const AutofillEntry& entry) {
+ entry_ = entry;
+ scoped_ptr<Callback0::Type> c(NewCallback((FakeServerUpdater *)this,
+ &FakeServerUpdater::Update));
+ std::vector<browser_sync::ModelSafeWorker*> workers;
+ service_->backend()->GetWorkers(&workers);
+
+ ASSERT_FALSE(ChromeThread::CurrentlyOn(ChromeThread::DB));
+ is_finished_.Reset();
+ if (!ChromeThread::PostTask(ChromeThread::DB, FROM_HERE,
+ NewRunnableMethod(this, &FakeServerUpdater::Update))) {
+ NOTREACHED() << "Failed to post task to the db thread.";
+ return;
+ }
+ is_finished_.Wait();
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<FakeServerUpdater>;
+ ~FakeServerUpdater() { }
+
+ AutofillEntry entry_;
+ TestProfileSyncService *service_;
+ scoped_ptr<WaitableEvent> *wait_for_start_;
+ scoped_ptr<WaitableEvent> *wait_for_syncapi_;
+ WaitableEvent is_finished_;
+ syncable::Id parent_id_;
+ TestIdFactory ids_;
+};
+
// TODO(skrul): Test abort startup.
// TODO(skrul): Test processing of cloud changes.
// TODO(tim): Add autofill data type controller test, and a case to cover
@@ -831,21 +1000,19 @@ TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeUpdateProfileRelabel) {
TEST_F(ProfileSyncServiceAutofillTest,
ProcessUserChangeUpdateProfileRelabelConflict) {
- AutoFillProfile* native_profile = new AutoFillProfile(string16(), 0);
- autofill_unittest::SetProfileInfo(native_profile,
+ std::vector<AutoFillProfile*> native_profiles;
+ native_profiles.push_back(new AutoFillProfile(string16(), 0));
+ native_profiles.push_back(new AutoFillProfile(string16(), 0));
+ autofill_unittest::SetProfileInfo(native_profiles[0],
"Billing", "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
"32801", "US", "19482937549", "13502849239");
- AutoFillProfile* native_profile2 = new AutoFillProfile(string16(), 0);
- autofill_unittest::SetProfileInfo(native_profile2,
+ autofill_unittest::SetProfileInfo(native_profiles[1],
"ExistingLabel", "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
"91601", "US", "12345678910", "01987654321");
- std::vector<AutoFillProfile*> native_profiles;
- native_profiles.push_back(native_profile);
- native_profiles.push_back(native_profile2);
- AutoFillProfile marion(*native_profile2);
- AutoFillProfile josephine_update(*native_profile);
+ AutoFillProfile marion(*native_profiles[1]);
+ AutoFillProfile josephine(*native_profiles[0]);
EXPECT_CALL(web_database_, GetAllAutofillEntries(_)). WillOnce(Return(true));
EXPECT_CALL(web_database_, GetAutoFillProfiles(_)).
@@ -854,32 +1021,45 @@ TEST_F(ProfileSyncServiceAutofillTest,
CreateRootTask task(this, syncable::AUTOFILL);
StartSyncService(&task, false);
ASSERT_TRUE(task.success());
-
- josephine_update.set_label(ASCIIToUTF16("ExistingLabel"));
- AutoFillProfile relabelled_profile;
- EXPECT_CALL(web_database_, UpdateAutoFillProfile(
- ProfileMatchesExceptLabel(josephine_update))).
- WillOnce(DoAll(SaveArg<0>(&relabelled_profile), Return(true)));
- EXPECT_CALL(*personal_data_manager_, Refresh());
-
- AutofillProfileChange change(AutofillProfileChange::UPDATE,
- josephine_update.Label(), &josephine_update,
- ASCIIToUTF16("Billing"));
- scoped_refptr<ThreadNotifier> notifier = new ThreadNotifier(&db_thread_);
- notifier->Notify(NotificationType::AUTOFILL_PROFILE_CHANGED,
- Source<WebDataService>(web_data_service_.get()),
- Details<AutofillProfileChange>(&change));
-
- std::vector<AutofillEntry> new_sync_entries;
- std::vector<AutoFillProfile> new_sync_profiles;
- ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&new_sync_entries,
- &new_sync_profiles));
- ASSERT_EQ(2U, new_sync_profiles.size());
- marion.set_unique_id(0); // The sync DB doesn't store IDs.
- EXPECT_EQ(marion, new_sync_profiles[1]);
- EXPECT_TRUE(ProfilesMatchExceptLabelImpl(josephine_update,
- new_sync_profiles[0]));
- EXPECT_EQ(new_sync_profiles[0].Label(), relabelled_profile.Label());
+ MessageLoop::current()->RunAllPending();
+ Mock::VerifyAndClearExpectations(&web_database_);
+ native_profiles.clear(); // Contents freed.
+
+ // Update josephine twice with marion's label. The second time ought to be
+ // idempotent, settling on the same name and not triggering a sync upload.
+ for (int pass = 0; pass < 2; ++pass) {
+ AutoFillProfile josephine_update(josephine);
+ josephine_update.set_label(ASCIIToUTF16("ExistingLabel"));
+
+ AutoFillProfile relabelled_profile;
+ EXPECT_CALL(web_database_, UpdateAutoFillProfile(
+ ProfileMatchesExceptLabel(josephine_update))).
+ WillOnce(DoAll(SaveArg<0>(&relabelled_profile), Return(true)));
+ EXPECT_CALL(*personal_data_manager_, Refresh());
+
+ AutofillProfileChange change(AutofillProfileChange::UPDATE,
+ josephine_update.Label(), &josephine_update,
+ josephine.Label());
+ scoped_refptr<ThreadNotifier> notifier = new ThreadNotifier(&db_thread_);
+ notifier->Notify(NotificationType::AUTOFILL_PROFILE_CHANGED,
+ Source<WebDataService>(web_data_service_.get()),
+ Details<AutofillProfileChange>(&change));
+ MessageLoop::current()->RunAllPending(); // Run the Refresh task.
+ Mock::VerifyAndClearExpectations(&web_database_);
+
+ std::vector<AutofillEntry> new_sync_entries;
+ std::vector<AutoFillProfile> new_sync_profiles;
+ ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&new_sync_entries,
+ &new_sync_profiles));
+ ASSERT_EQ(2U, new_sync_profiles.size());
+ marion.set_unique_id(0); // The sync DB doesn't store IDs.
+ EXPECT_EQ(marion, new_sync_profiles[1]);
+ EXPECT_TRUE(ProfilesMatchExceptLabelImpl(josephine_update,
+ new_sync_profiles[0]));
+ EXPECT_EQ(ASCIIToUTF16("ExistingLabel2"), new_sync_profiles[0].Label());
+ EXPECT_EQ(ASCIIToUTF16("ExistingLabel2"), relabelled_profile.Label());
+ josephine = relabelled_profile;
+ }
}
TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveEntry) {
@@ -983,3 +1163,46 @@ TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeError) {
Source<WebDataService>(web_data_service_.get()),
Details<AutofillChangeList>(&changes));
}
+
+TEST_F(ProfileSyncServiceAutofillTest, ServerChangeRace) {
+ EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).WillOnce(Return(true));
+ EXPECT_CALL(web_database_, GetAutoFillProfiles(_)).WillOnce(Return(true));
+ EXPECT_CALL(web_database_, UpdateAutofillEntries(_)).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(*personal_data_manager_, Refresh()).Times(3);
+ CreateRootTask task(this, syncable::AUTOFILL);
+ StartSyncService(&task, false);
+ ASSERT_TRUE(task.success());
+
+ // (true, false) means we have to reset after |Signal|, init to unsignaled.
+ scoped_ptr<WaitableEvent> wait_for_start(new WaitableEvent(true, false));
+ scoped_ptr<WaitableEvent> wait_for_syncapi(new WaitableEvent(true, false));
+ scoped_refptr<FakeServerUpdater> updater = new FakeServerUpdater(
+ service_.get(), &wait_for_start, &wait_for_syncapi);
+
+ // This server side update will stall waiting for CommitWaiter.
+ updater->CreateNewEntry(MakeAutofillEntry("server", "entry", 1));
+ wait_for_start->Wait();
+
+ AutofillEntry syncapi_entry(MakeAutofillEntry("syncapi", "entry", 2));
+ ASSERT_TRUE(AddAutofillSyncNode(syncapi_entry));
+ LOG(INFO) << "Syncapi update finished.";
+
+ // If we reach here, it means syncapi succeeded and we didn't deadlock. Yay!
+ // Signal FakeServerUpdater that it can complete.
+ wait_for_syncapi->Signal();
+
+ // Make another entry to ensure nothing broke afterwards and wait for finish
+ // to clean up.
+ updater->CreateNewEntryAndWait(MakeAutofillEntry("server2", "entry2", 3));
+
+ std::vector<AutofillEntry> sync_entries;
+ std::vector<AutoFillProfile> sync_profiles;
+ ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
+ EXPECT_EQ(3U, sync_entries.size());
+ EXPECT_EQ(0U, sync_profiles.size());
+ for (size_t i = 0; i < sync_entries.size(); i++) {
+ LOG(INFO) << "Entry " << i << ": " << sync_entries[i].key().name() << ", "
+ << sync_entries[i].key().value();
+ }
+}
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
index ae9832f..3142baf 100644
--- a/chrome/browser/sync/profile_sync_service_mock.h
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_MOCK_H_
+#pragma once
#include <string>
#include "base/string16.h"
@@ -19,7 +20,6 @@ class ProfileSyncServiceMock : public ProfileSyncService {
ProfileSyncServiceMock() {}
virtual ~ProfileSyncServiceMock() {}
- MOCK_METHOD0(EnableForUser, void());
MOCK_METHOD0(DisableForUser, void());
MOCK_METHOD0(OnBackendInitialized, void());
MOCK_METHOD0(OnSyncCycleCompleted, void());
diff --git a/chrome/browser/sync/profile_sync_service_observer.h b/chrome/browser/sync/profile_sync_service_observer.h
index 2bd967c..5a9c0ca 100644
--- a/chrome/browser/sync/profile_sync_service_observer.h
+++ b/chrome/browser/sync/profile_sync_service_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_OBSERVER_H_
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_OBSERVER_H_
+#pragma once
// Various UI components such as the New Tab page can be driven by observing
// the ProfileSyncService through this interface.
diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc
index 7d7c7e3..d0598c5 100644
--- a/chrome/browser/sync/profile_sync_service_password_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc
@@ -9,7 +9,6 @@
#include "base/task.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
-#include "base/waitable_event.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
#include "chrome/browser/sync/engine/syncapi.h"
@@ -25,16 +24,17 @@
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
+#include "chrome/common/net/gaia/gaia_constants.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/sync/engine/test_id_factory.h"
#include "chrome/test/profile_mock.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "webkit/glue/password_form.h"
using base::Time;
-using base::WaitableEvent;
using browser_sync::PasswordChangeProcessor;
using browser_sync::PasswordDataTypeController;
using browser_sync::PasswordModelAssociator;
@@ -46,7 +46,6 @@ using sync_api::UserShare;
using syncable::BASE_VERSION;
using syncable::CREATE;
using syncable::DirectoryManager;
-using syncable::ID;
using syncable::IS_DEL;
using syncable::IS_DIR;
using syncable::IS_UNAPPLIED_UPDATE;
@@ -143,7 +142,9 @@ class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
int num_pause_expectations) {
if (!service_.get()) {
service_.reset(new TestProfileSyncService(&factory_, &profile_,
- false, false, root_task));
+ "test_user", false, root_task));
+ service_->RegisterPreferences();
+ profile_.GetPrefs()->SetBoolean(prefs::kSyncPasswords, true);
service_->set_num_expected_resumes(num_resume_expectations);
service_->set_num_expected_pauses(num_pause_expectations);
PasswordDataTypeController* data_type_controller =
@@ -158,8 +159,23 @@ class ProfileSyncServicePasswordTest : public AbstractProfileSyncServiceTest {
EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).
WillOnce(ReturnNewDataTypeManager());
+ // We need tokens to get the tests going
+ token_service_.IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
+
+ EXPECT_CALL(profile_, GetTokenService()).
+ WillRepeatedly(Return(&token_service_));
+
+ // Creating model safe workers will request the history service and
+ // password store. I couldn't manage to convince gmock that splitting up
+ // the expectations to match the class responsibilities was a good thing,
+ // so we set them all together here.
+ EXPECT_CALL(profile_, GetHistoryService(_)).
+ WillOnce(Return(static_cast<HistoryService*>(NULL)));
+
EXPECT_CALL(profile_, GetPasswordStore(_)).
- WillOnce(Return(password_store_.get()));
+ Times(2).
+ WillRepeatedly(Return(password_store_.get()));
EXPECT_CALL(observer_,
Observe(
diff --git a/chrome/browser/sync/profile_sync_service_preference_unittest.cc b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
index 94ae735..e1f3299 100644
--- a/chrome/browser/sync/profile_sync_service_preference_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
@@ -7,6 +7,7 @@
#include "base/json/json_reader.h"
#include "base/stl_util-inl.h"
+#include "base/string_piece.h"
#include "base/task.h"
#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
#include "chrome/browser/sync/engine/syncapi.h"
@@ -18,8 +19,10 @@
#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,7 +36,7 @@ using sync_api::SyncManager;
using testing::_;
using testing::Return;
-typedef std::map<const std::wstring, const Value*> PreferenceValues;
+typedef std::map<const std::string, const Value*> PreferenceValues;
class ProfileSyncServicePreferenceTest
: public AbstractProfileSyncServiceTest {
@@ -42,14 +45,14 @@ class ProfileSyncServicePreferenceTest
: example_url0_("http://example.com/0"),
example_url1_("http://example.com/1"),
example_url2_("http://example.com/2"),
- not_synced_preference_name_(L"nonsense_pref_name"),
+ not_synced_preference_name_("nonsense_pref_name"),
not_synced_preference_default_value_("default"),
non_default_charset_value_("foo") {}
virtual void SetUp() {
profile_.reset(new TestingProfile());
profile_->set_has_history_service(true);
- prefs_ = profile_->GetPrefs();
+ prefs_ = profile_->GetTestingPrefService();
prefs_->RegisterStringPref(not_synced_preference_name_.c_str(),
not_synced_preference_default_value_);
@@ -66,7 +69,7 @@ class ProfileSyncServicePreferenceTest
return false;
service_.reset(new TestProfileSyncService(
- &factory_, profile_.get(), false, false, task));
+ &factory_, profile_.get(), "test", false, task));
// Register the preference data type.
model_associator_ =
@@ -85,6 +88,8 @@ class ProfileSyncServicePreferenceTest
service_->RegisterDataTypeController(
new PreferenceDataTypeController(&factory_,
service_.get()));
+ profile_->GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
service_->Initialize();
MessageLoop::current()->Run();
return true;
@@ -92,14 +97,14 @@ class ProfileSyncServicePreferenceTest
SyncBackendHost* backend() { return service_->backend_.get(); }
- const Value& GetPreferenceValue(const std::wstring& name) {
+ const Value& GetPreferenceValue(const std::string& name) {
const PrefService::Preference* preference =
prefs_->FindPreference(name.c_str());
return *preference->GetValue();
}
// Caller gets ownership of the returned value.
- const Value* GetSyncedValue(const std::wstring& name) {
+ const Value* GetSyncedValue(const std::string& name) {
sync_api::ReadTransaction trans(service_->backend()->GetUserShareHandle());
sync_api::ReadNode node(&trans);
@@ -116,41 +121,36 @@ class ProfileSyncServicePreferenceTest
return reader.JsonToValue(specifics.value(), false, false);
}
- int64 SetSyncedValue(const std::wstring& name, const Value& value) {
+ int64 WriteSyncedValue(sync_api::WriteNode& node,
+ const std::string& name,
+ const Value& value) {
+ if (!PreferenceModelAssociator::WritePreferenceToNode(name, value, &node))
+ return sync_api::kInvalidId;
+ return node.GetId();
+ }
+
+ int64 SetSyncedValue(const std::string& name, const Value& value) {
sync_api::WriteTransaction trans(backend()->GetUserShareHandle());
sync_api::ReadNode root(&trans);
if (!root.InitByTagLookup(browser_sync::kPreferencesTag))
return sync_api::kInvalidId;
+ sync_api::WriteNode tag_node(&trans);
sync_api::WriteNode node(&trans);
int64 node_id = model_associator_->GetSyncIdFromChromeId(name);
if (node_id == sync_api::kInvalidId) {
- if (!node.InitUniqueByCreation(syncable::PREFERENCES,
- root,
- WideToUTF8(name))) {
- return sync_api::kInvalidId;
- }
- } else {
- if (!node.InitByIdLookup(node_id)) {
- return sync_api::kInvalidId;
- }
+ if (tag_node.InitByClientTagLookup(syncable::PREFERENCES, name))
+ return WriteSyncedValue(tag_node, name, value);
+ if (node.InitUniqueByCreation(syncable::PREFERENCES, root, name))
+ return WriteSyncedValue(node, name, value);
+ } else if (node.InitByIdLookup(node_id)) {
+ return WriteSyncedValue(node, name, value);
}
-
- std::string serialized;
- JSONStringValueSerializer json(&serialized);
- EXPECT_TRUE(json.Serialize(value));
-
- sync_pb::PreferenceSpecifics preference;
- preference.set_name(WideToUTF8(name));
- preference.set_value(serialized);
- node.SetPreferenceSpecifics(preference);
- node.SetTitle(name);
-
- return node.GetId();
+ return sync_api::kInvalidId;
}
- SyncManager::ChangeRecord* MakeChangeRecord(const std::wstring& name,
+ SyncManager::ChangeRecord* MakeChangeRecord(const std::string& name,
SyncManager::ChangeRecord) {
int64 node_id = model_associator_->GetSyncIdFromChromeId(name);
SyncManager::ChangeRecord* record = new SyncManager::ChangeRecord();
@@ -159,7 +159,7 @@ class ProfileSyncServicePreferenceTest
return record;
}
- bool IsSynced(const std::wstring& pref_name) {
+ bool IsSynced(const std::string& pref_name) {
return model_associator_->synced_preferences().count(pref_name) > 0;
}
@@ -180,7 +180,7 @@ class ProfileSyncServicePreferenceTest
std::string example_url0_;
std::string example_url1_;
std::string example_url2_;
- std::wstring not_synced_preference_name_;
+ std::string not_synced_preference_name_;
std::string not_synced_preference_default_value_;
std::string non_default_charset_value_;
};
@@ -222,13 +222,13 @@ TEST_F(ProfileSyncServicePreferenceTest, WritePreferenceToNode) {
sync_api::WriteTransaction trans(service_->backend()->GetUserShareHandle());
sync_api::WriteNode node(&trans);
EXPECT_TRUE(node.InitByClientTagLookup(syncable::PREFERENCES,
- WideToUTF8(prefs::kHomePage)));
+ prefs::kHomePage));
EXPECT_TRUE(PreferenceModelAssociator::WritePreferenceToNode(
pref->name(), *pref->GetValue(), &node));
- EXPECT_EQ(std::wstring(prefs::kHomePage), node.GetTitle());
+ EXPECT_EQ(UTF8ToWide(prefs::kHomePage), node.GetTitle());
const sync_pb::PreferenceSpecifics& specifics(node.GetPreferenceSpecifics());
- EXPECT_EQ(WideToUTF8(prefs::kHomePage), specifics.name());
+ EXPECT_EQ(std::string(prefs::kHomePage), specifics.name());
base::JSONReader reader;
scoped_ptr<Value> value(reader.JsonToValue(specifics.value(), false, false));
@@ -398,7 +398,7 @@ TEST_F(ProfileSyncServicePreferenceTest, UpdatedSyncNodeUnknownPreference) {
ASSERT_TRUE(task.success());
scoped_ptr<Value> expected(Value::CreateStringValue(example_url0_));
- int64 node_id = SetSyncedValue(L"unknown preference", *expected);
+ int64 node_id = SetSyncedValue("unknown preference", *expected);
ASSERT_NE(node_id, sync_api::kInvalidId);
scoped_ptr<SyncManager::ChangeRecord> record(new SyncManager::ChangeRecord);
record->action = SyncManager::ChangeRecord::ACTION_ADD;
@@ -415,7 +415,7 @@ TEST_F(ProfileSyncServicePreferenceTest, UpdatedSyncNodeUnknownPreference) {
TEST_F(ProfileSyncServicePreferenceTest, ManagedPreferences) {
// Make the homepage preference managed.
scoped_ptr<Value> managed_value(
- Value::CreateStringValue(L"http://example.com"));
+ Value::CreateStringValue("http://example.com"));
prefs_->SetManagedPref(prefs::kHomePage, managed_value->DeepCopy());
CreateRootTask task(this, syncable::PREFERENCES);
@@ -424,13 +424,13 @@ TEST_F(ProfileSyncServicePreferenceTest, ManagedPreferences) {
// Changing the homepage preference should not sync anything.
scoped_ptr<Value> user_value(
- Value::CreateStringValue(L"http://chromium..com"));
+ Value::CreateStringValue("http://chromium..com"));
prefs_->SetUserPref(prefs::kHomePage, user_value->DeepCopy());
EXPECT_EQ(NULL, GetSyncedValue(prefs::kHomePage));
// An incoming sync transaction shouldn't change the user value.
scoped_ptr<Value> sync_value(
- Value::CreateStringValue(L"http://crbug.com"));
+ Value::CreateStringValue("http://crbug.com"));
int64 node_id = SetSyncedValue(prefs::kHomePage, *sync_value);
ASSERT_NE(node_id, sync_api::kInvalidId);
scoped_ptr<SyncManager::ChangeRecord> record(new SyncManager::ChangeRecord);
@@ -440,6 +440,52 @@ TEST_F(ProfileSyncServicePreferenceTest, ManagedPreferences) {
sync_api::WriteTransaction trans(backend()->GetUserShareHandle());
change_processor_->ApplyChangesFromSyncModel(&trans, record.get(), 1);
}
- EXPECT_TRUE(managed_value->Equals(prefs_->GetManagedPref(prefs::kHomePage)));
- EXPECT_TRUE(user_value->Equals(prefs_->GetUserPref(prefs::kHomePage)));
+ EXPECT_TRUE(managed_value->Equals(
+ prefs_->GetManagedPref(prefs::kHomePage)));
+ EXPECT_TRUE(user_value->Equals(
+ prefs_->GetUserPref(prefs::kHomePage)));
+}
+
+TEST_F(ProfileSyncServicePreferenceTest, DynamicManagedPreferences) {
+ CreateRootTask task(this, syncable::PREFERENCES);
+ ASSERT_TRUE(StartSyncService(&task, false));
+ ASSERT_TRUE(task.success());
+
+ scoped_ptr<Value> initial_value(
+ Value::CreateStringValue("http://example.com/initial"));
+ profile_->GetPrefs()->Set(prefs::kHomePage, *initial_value);
+ scoped_ptr<const Value> actual(GetSyncedValue(prefs::kHomePage));
+ EXPECT_TRUE(initial_value->Equals(actual.get()));
+
+ // Switch kHomePage to managed and set a different value.
+ scoped_ptr<Value> managed_value(
+ Value::CreateStringValue("http://example.com/managed"));
+ profile_->GetTestingPrefService()->SetManagedPref(
+ prefs::kHomePage, managed_value->DeepCopy());
+
+ // Sync node should be gone.
+ EXPECT_EQ(sync_api::kInvalidId,
+ model_associator_->GetSyncIdFromChromeId(prefs::kHomePage));
+
+ // Change the sync value.
+ scoped_ptr<Value> sync_value(
+ Value::CreateStringValue("http://example.com/sync"));
+ int64 node_id = SetSyncedValue(prefs::kHomePage, *sync_value);
+ ASSERT_NE(node_id, sync_api::kInvalidId);
+ scoped_ptr<SyncManager::ChangeRecord> record(new SyncManager::ChangeRecord);
+ record->action = SyncManager::ChangeRecord::ACTION_ADD;
+ record->id = node_id;
+ {
+ sync_api::WriteTransaction trans(backend()->GetUserShareHandle());
+ change_processor_->ApplyChangesFromSyncModel(&trans, record.get(), 1);
+ }
+
+ // The pref value should still be the one dictated by policy.
+ EXPECT_TRUE(managed_value->Equals(&GetPreferenceValue(prefs::kHomePage)));
+
+ // Switch kHomePage back to unmanaged.
+ profile_->GetTestingPrefService()->RemoveManagedPref(prefs::kHomePage);
+
+ // Sync value should be picked up.
+ EXPECT_TRUE(sync_value->Equals(&GetPreferenceValue(prefs::kHomePage)));
}
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index a9d7944..e7e1a34 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -8,12 +8,14 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/sync/glue/data_type_manager.h"
#include "chrome/browser/sync/glue/data_type_manager_mock.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
@@ -39,6 +41,7 @@ ACTION_P(InvokeCallback, callback_result) {
#define SKIP_MACOSX(test) test
#endif
+// TODO(chron): Test not using cros_user flag and use signin_
class ProfileSyncServiceStartupTest : public testing::Test {
public:
ProfileSyncServiceStartupTest()
@@ -53,7 +56,7 @@ class ProfileSyncServiceStartupTest : public testing::Test {
virtual void SetUp() {
service_.reset(new TestProfileSyncService(&factory_, &profile_,
- false, true, NULL));
+ "test", true, NULL));
service_->AddObserver(&observer_);
service_->set_num_expected_resumes(0);
service_->set_num_expected_pauses(0);
@@ -98,12 +101,17 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartFirstTime)) {
Mock::VerifyAndClearExpectations(data_type_manager);
// Then start things up.
- EXPECT_CALL(*data_type_manager, Configure(_)).Times(1);
+ EXPECT_CALL(*data_type_manager, Configure(_)).Times(2);
EXPECT_CALL(*data_type_manager, state()).
WillOnce(Return(DataTypeManager::CONFIGURED));
EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(4);
- service_->EnableForUser(NULL);
+ EXPECT_CALL(observer_, OnStateChanged()).Times(5);
+
+ // Create some tokens in the token service; the service will startup when
+ // it is notified that tokens are available.
+ profile_.GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "sync_token");
+
syncable::ModelTypeSet set;
set.insert(syncable::BOOKMARKS);
service_->OnUserChoseDatatypes(false, set);
@@ -118,6 +126,9 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartNormal)) {
EXPECT_CALL(observer_, OnStateChanged()).Times(3);
+ // Pre load the tokens
+ profile_.GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
}
@@ -129,6 +140,8 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(ManagedStartup)) {
EXPECT_CALL(observer_, OnStateChanged()).Times(1);
// Service should not be started by Initialize() since it's managed.
+ profile_.GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
}
@@ -137,6 +150,8 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(SwitchManaged)) {
EXPECT_CALL(*data_type_manager, Configure(_)).Times(1);
EXPECT_CALL(observer_, OnStateChanged()).Times(3);
+ profile_.GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
// The service should stop when switching to managed mode.
@@ -160,51 +175,18 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartFailure)) {
DataTypeManager::ConfigureResult result =
DataTypeManager::ASSOCIATION_FAILED;
EXPECT_CALL(*data_type_manager, Configure(_)).
- WillOnce(DoAll(Notify(NotificationType::SYNC_CONFIGURE_START),
- NotifyWithResult(NotificationType::SYNC_CONFIGURE_DONE,
- &result)));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
+ WillOnce(DoAll(NotifyFromDataTypeManager(data_type_manager,
+ NotificationType::SYNC_CONFIGURE_START),
+ NotifyFromDataTypeManagerWithResult(data_type_manager,
+ NotificationType::SYNC_CONFIGURE_DONE,
+ &result)));
EXPECT_CALL(*data_type_manager, state()).
WillOnce(Return(DataTypeManager::STOPPED));
EXPECT_CALL(observer_, OnStateChanged()).Times(3);
+ profile_.GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "sync_token");
service_->Initialize();
EXPECT_TRUE(service_->unrecoverable_error_detected());
}
-
-class ProfileSyncServiceStartupBootstrapTest
- : public ProfileSyncServiceStartupTest {
- public:
- ProfileSyncServiceStartupBootstrapTest() {}
- virtual ~ProfileSyncServiceStartupBootstrapTest() {}
-
- virtual void SetUp() {
- service_.reset(new TestProfileSyncService(&factory_, &profile_,
- true, true, NULL));
- service_->AddObserver(&observer_);
- service_->set_num_expected_resumes(0);
- service_->set_num_expected_pauses(0);
- service_->set_synchronous_sync_configuration();
- }
-};
-
-TEST_F(ProfileSyncServiceStartupBootstrapTest, SKIP_MACOSX(StartFirstTime)) {
- DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
- EXPECT_CALL(*data_type_manager, Configure(_)).Times(1);
- EXPECT_CALL(*data_type_manager, state()).
- WillOnce(Return(DataTypeManager::CONFIGURED));
- EXPECT_CALL(*data_type_manager, Stop()).Times(1);
- EXPECT_CALL(observer_, OnStateChanged()).Times(4);
-
- profile_.GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
-
- // Pretend the login screen worked.
- GaiaAuthConsumer::ClientLoginResult result;
- result.sid = "sid";
- result.lsid = "lsid";
- profile_.GetTokenService()->SetClientLoginResult(result);
- // Will start sync even though setup hasn't been completed (since
- // setup is bypassed when bootstrapping is enabled).
- service_->Initialize();
-}
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index 60a4c20..f913433 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -27,6 +27,7 @@
#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/profile_mock.h"
#include "chrome/test/sync/engine/test_id_factory.h"
@@ -51,7 +52,6 @@ using sync_api::UserShare;
using syncable::BASE_VERSION;
using syncable::CREATE;
using syncable::DirectoryManager;
-using syncable::ID;
using syncable::IS_DEL;
using syncable::IS_DIR;
using syncable::IS_UNAPPLIED_UPDATE;
@@ -79,8 +79,9 @@ class HistoryBackendMock : public HistoryBackend {
MOCK_METHOD2(GetVisitsForURL, bool(history::URLID id,
history::VisitVector* visits));
MOCK_METHOD2(UpdateURL, bool(history::URLID id, const history::URLRow& url));
- MOCK_METHOD2(AddVisits, bool(const GURL& url,
- const std::vector<base::Time>& visits));
+ MOCK_METHOD3(AddVisits, bool(const GURL& url,
+ const std::vector<base::Time>& visits,
+ history::VisitSource visit_source));
MOCK_METHOD1(RemoveVisits, bool(const history::VisitVector& visits));
MOCK_METHOD2(GetURL, bool(const GURL& url_id, history::URLRow* url_row));
MOCK_METHOD2(SetPageTitle, void(const GURL& url, const std::wstring& title));
@@ -153,7 +154,7 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
void StartSyncService(Task* task) {
if (!service_.get()) {
service_.reset(
- new TestProfileSyncService(&factory_, &profile_, false, false,
+ new TestProfileSyncService(&factory_, &profile_, "test", false,
task));
TypedUrlDataTypeController* data_type_controller =
new TypedUrlDataTypeController(&factory_,
@@ -170,10 +171,20 @@ class ProfileSyncServiceTypedUrlTest : public AbstractProfileSyncServiceTest {
EXPECT_CALL(profile_, GetHistoryServiceWithoutCreating()).
WillRepeatedly(Return(history_service_.get()));
+ EXPECT_CALL(profile_, GetPasswordStore(_)).
+ WillOnce(Return(static_cast<PasswordStore*>(NULL)));
+
EXPECT_CALL(profile_, GetHistoryService(_)).
WillRepeatedly(Return(history_service_.get()));
+ token_service_.IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
+
+ EXPECT_CALL(profile_, GetTokenService()).
+ WillRepeatedly(Return(&token_service_));
+
service_->RegisterDataTypeController(data_type_controller);
+
service_->Initialize();
MessageLoop::current()->Run();
}
@@ -338,8 +349,8 @@ TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncNoMerge) {
WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
WillRepeatedly(DoAll(SetArgumentPointee<1>(native_visits), Return(true)));
- EXPECT_CALL((*history_backend_.get()), AddVisits(_, _)).
- WillRepeatedly(Return(true));
+ EXPECT_CALL((*history_backend_.get()),
+ AddVisits(_, _, history::SOURCE_SYNCED)).WillRepeatedly(Return(true));
std::vector<history::URLRow> sync_entries;
sync_entries.push_back(sync_entry);
@@ -383,8 +394,8 @@ TEST_F(ProfileSyncServiceTypedUrlTest, HasNativeHasSyncMerge) {
WillOnce(DoAll(SetArgumentPointee<0>(native_entries), Return(true)));
EXPECT_CALL((*history_backend_.get()), GetVisitsForURL(_, _)).
WillRepeatedly(DoAll(SetArgumentPointee<1>(native_visits), Return(true)));
- EXPECT_CALL((*history_backend_.get()), AddVisits(_, _)).
- WillRepeatedly(Return(true));
+ EXPECT_CALL((*history_backend_.get()),
+ AddVisits(_, _, history::SOURCE_SYNCED)). WillRepeatedly(Return(true));
std::vector<history::URLRow> sync_entries;
sync_entries.push_back(sync_entry);
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index 56f8585..c985e97 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.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,12 +6,17 @@
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
+#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_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/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
@@ -22,12 +27,12 @@
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/glue/sync_backend_host_mock.h"
-#include "chrome/browser/sync/notification_method.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -238,10 +243,16 @@ class ProfileSyncServiceTest : public testing::Test {
}
void StartSyncService() {
+ StartSyncServiceAndSetInitialSyncEnded(true);
+ }
+ void StartSyncServiceAndSetInitialSyncEnded(bool set_initial_sync_ended) {
if (!service_.get()) {
+ // Set bootstrap to true and it will provide a logged in user for test
service_.reset(new TestProfileSyncService(&factory_,
profile_.get(),
- false, false, NULL));
+ "test", false, NULL));
+ if (!set_initial_sync_ended)
+ service_->dont_set_initial_sync_ended_on_init();
// Register the bookmark data type.
model_associator_ = new TestBookmarkModelAssociator(service_.get(),
@@ -258,6 +269,9 @@ class ProfileSyncServiceTest : public testing::Test {
new browser_sync::BookmarkDataTypeController(&factory_,
profile_.get(),
service_.get()));
+
+ profile_->GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "token");
service_->Initialize();
MessageLoop::current()->Run();
}
@@ -290,7 +304,7 @@ class ProfileSyncServiceTest : public testing::Test {
// Non-root node titles and parents must match.
if (bnode != model_->GetBookmarkBarNode() &&
bnode != model_->other_node()) {
- EXPECT_EQ(bnode->GetTitle(), gnode.GetTitle());
+ EXPECT_EQ(bnode->GetTitle(), WideToUTF16Hack(gnode.GetTitle()));
EXPECT_EQ(associator()->GetChromeNodeFromSyncId(gnode.GetParentId()),
bnode->GetParent());
}
@@ -365,7 +379,7 @@ class ProfileSyncServiceTest : public testing::Test {
const BookmarkNode* bnode =
associator()->GetChromeNodeFromSyncId(sync_id);
ASSERT_TRUE(bnode);
- EXPECT_EQ(bnode->GetTitle(), title);
+ EXPECT_EQ(bnode->GetTitle(), WideToUTF16Hack(title));
}
void ExpectBrowserNodeURL(int64 sync_id, const std::string& url) {
@@ -458,15 +472,15 @@ TEST_F(ProfileSyncServiceTest, InitialState) {
TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
service_.reset(new TestProfileSyncService(&factory_, profile_.get(),
- false, true, NULL));
+ "test", true, NULL));
service_->set_num_expected_resumes(0);
- EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).
- WillOnce(ReturnNewDataTypeManager());
+ EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).Times(0);
EXPECT_CALL(factory_, CreateBookmarkSyncComponents(_, _)).Times(0);
service_->RegisterDataTypeController(
new browser_sync::BookmarkDataTypeController(&factory_,
profile_.get(),
service_.get()));
+
service_->Initialize();
service_.reset();
}
@@ -477,33 +491,35 @@ TEST_F(ProfileSyncServiceTest, BookmarkModelOperations) {
// Test addition.
const BookmarkNode* folder =
- model_->AddGroup(model_->other_node(), 0, L"foobar");
+ model_->AddGroup(model_->other_node(), 0, ASCIIToUTF16("foobar"));
ExpectSyncerNodeMatching(folder);
ExpectModelMatch();
- const BookmarkNode* folder2 = model_->AddGroup(folder, 0, L"nested");
+ const BookmarkNode* folder2 =
+ model_->AddGroup(folder, 0, ASCIIToUTF16("nested"));
ExpectSyncerNodeMatching(folder2);
ExpectModelMatch();
const BookmarkNode* url1 = model_->AddURL(
- folder, 0, L"Internets #1 Pies Site", GURL("http://www.easypie.com/"));
+ folder, 0, ASCIIToUTF16("Internets #1 Pies Site"),
+ GURL("http://www.easypie.com/"));
ExpectSyncerNodeMatching(url1);
ExpectModelMatch();
const BookmarkNode* url2 = model_->AddURL(
- folder, 1, L"Airplanes", GURL("http://www.easyjet.com/"));
+ folder, 1, ASCIIToUTF16("Airplanes"), GURL("http://www.easyjet.com/"));
ExpectSyncerNodeMatching(url2);
ExpectModelMatch();
// Test modification.
- model_->SetTitle(url2, L"EasyJet");
+ model_->SetTitle(url2, ASCIIToUTF16("EasyJet"));
ExpectModelMatch();
model_->Move(url1, folder2, 0);
ExpectModelMatch();
model_->Move(folder2, model_->GetBookmarkBarNode(), 0);
ExpectModelMatch();
- model_->SetTitle(folder2, L"Not Nested");
+ model_->SetTitle(folder2, ASCIIToUTF16("Not Nested"));
ExpectModelMatch();
model_->Move(folder, folder2, 0);
ExpectModelMatch();
- model_->SetTitle(folder, L"who's nested now?");
+ model_->SetTitle(folder, ASCIIToUTF16("who's nested now?"));
ExpectModelMatch();
model_->Copy(url2, model_->GetBookmarkBarNode(), 0);
ExpectModelMatch();
@@ -536,10 +552,11 @@ TEST_F(ProfileSyncServiceTest, ServerChangeProcessing) {
adds.AddURL(L"Some old site", "http://slog.thestranger.com/",
bookmark_bar_id(), u1);
// u5 tests an empty-string title.
- std::string javascript_url("javascript:(function(){var w=window.open(" \
- "'about:blank','gnotesWin','location=0,menubar=0," \
- "scrollbars=0,status=0,toolbar=0,width=300," \
- "height=300,resizable');});");
+ std::string javascript_url(
+ "javascript:(function(){var w=window.open(" \
+ "'about:blank','gnotesWin','location=0,menubar=0," \
+ "scrollbars=0,status=0,toolbar=0,width=300," \
+ "height=300,resizable');});");
adds.AddURL(L"", javascript_url, other_bookmarks_id(), 0);
vector<sync_api::SyncManager::ChangeRecord>::const_iterator it;
@@ -725,27 +742,27 @@ TEST_F(ProfileSyncServiceTest, CornerCaseNames) {
LoadBookmarkModel(DELETE_EXISTING_STORAGE, DONT_SAVE_TO_STORAGE);
StartSyncService();
- const wchar_t* names[] = {
+ const char* names[] = {
// The empty string.
- L"",
+ "",
// Illegal Windows filenames.
- L"CON", L"PRN", L"AUX", L"NUL", L"COM1", L"COM2", L"COM3", L"COM4",
- L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", L"LPT1", L"LPT2", L"LPT3",
- L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9",
+ "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4",
+ "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3",
+ "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
// Current/parent directory markers.
- L".", L"..", L"...",
+ ".", "..", "...",
// Files created automatically by the Windows shell.
- L"Thumbs.db", L".DS_Store",
+ "Thumbs.db", ".DS_Store",
// Names including Win32-illegal characters, and path separators.
- L"foo/bar", L"foo\\bar", L"foo?bar", L"foo:bar", L"foo|bar", L"foo\"bar",
- L"foo'bar", L"foo<bar", L"foo>bar", L"foo%bar", L"foo*bar", L"foo]bar",
- L"foo[bar",
+ "foo/bar", "foo\\bar", "foo?bar", "foo:bar", "foo|bar", "foo\"bar",
+ "foo'bar", "foo<bar", "foo>bar", "foo%bar", "foo*bar", "foo]bar",
+ "foo[bar",
};
// Create both folders and bookmarks using each name.
GURL url("http://www.doublemint.com");
for (size_t i = 0; i < arraysize(names); ++i) {
- model_->AddGroup(model_->other_node(), 0, names[i]);
- model_->AddURL(model_->other_node(), 0, names[i], url);
+ model_->AddGroup(model_->other_node(), 0, ASCIIToUTF16(names[i]));
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16(names[i]), url);
}
// Verify that the browser model matches the sync model.
@@ -764,14 +781,14 @@ TEST_F(ProfileSyncServiceTest, RepeatedMiddleInsertion) {
static const int kTimesToInsert = 256;
// Create two book-end nodes to insert between.
- model_->AddGroup(model_->other_node(), 0, L"Alpha");
- model_->AddGroup(model_->other_node(), 1, L"Omega");
+ model_->AddGroup(model_->other_node(), 0, ASCIIToUTF16("Alpha"));
+ model_->AddGroup(model_->other_node(), 1, ASCIIToUTF16("Omega"));
int count = 2;
// Test insertion in first half of range by repeatedly inserting in second
// position.
for (int i = 0; i < kTimesToInsert; ++i) {
- std::wstring title = std::wstring(L"Pre-insertion ") + IntToWString(i);
+ string16 title = ASCIIToUTF16("Pre-insertion ") + base::IntToString16(i);
model_->AddGroup(model_->other_node(), 1, title);
count++;
}
@@ -779,7 +796,7 @@ TEST_F(ProfileSyncServiceTest, RepeatedMiddleInsertion) {
// Test insertion in second half of range by repeatedly inserting in
// second-to-last position.
for (int i = 0; i < kTimesToInsert; ++i) {
- std::wstring title = std::wstring(L"Post-insertion ") + IntToWString(i);
+ string16 title = ASCIIToUTF16("Post-insertion ") + base::IntToString16(i);
model_->AddGroup(model_->other_node(), count - 1, title);
count++;
}
@@ -800,7 +817,7 @@ TEST_F(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService) {
// Add a node which will be the target of the consistency violation.
const BookmarkNode* node =
- model_->AddGroup(model_->other_node(), 0, L"node");
+ model_->AddGroup(model_->other_node(), 0, ASCIIToUTF16("node"));
ExpectSyncerNodeMatching(node);
// Now destroy the syncer node as if we were the ProfileSyncService without
@@ -820,13 +837,13 @@ TEST_F(ProfileSyncServiceTest, UnrecoverableErrorSuspendsService) {
// Add a child to the inconsistent node. This should cause detection of the
// problem and the syncer should stop processing changes.
- model_->AddGroup(node, 0, L"nested");
+ model_->AddGroup(node, 0, ASCIIToUTF16("nested"));
EXPECT_FALSE(service_->ShouldPushChanges());
// Try to add a node under a totally different parent. This should also
// fail -- the ProfileSyncService should stop processing changes after
// encountering a consistency violation.
- model_->AddGroup(model_->GetBookmarkBarNode(), 0, L"unrelated");
+ model_->AddGroup(model_->GetBookmarkBarNode(), 0, ASCIIToUTF16("unrelated"));
EXPECT_FALSE(service_->ShouldPushChanges());
// TODO(ncarter): We ought to test the ProfileSyncService state machine
@@ -840,8 +857,10 @@ TEST_F(ProfileSyncServiceTest, MergeDuplicates) {
LoadBookmarkModel(DELETE_EXISTING_STORAGE, SAVE_TO_STORAGE);
StartSyncService();
- model_->AddURL(model_->other_node(), 0, L"Dup", GURL("http://dup.com/"));
- model_->AddURL(model_->other_node(), 0, L"Dup", GURL("http://dup.com/"));
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("Dup"),
+ GURL("http://dup.com/"));
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("Dup"),
+ GURL("http://dup.com/"));
EXPECT_EQ(2, model_->other_node()->GetChildCount());
@@ -967,9 +986,9 @@ void ProfileSyncServiceTestWithData::PopulateFromTestData(
for (int i = 0; i < size; ++i) {
const TestData& item = data[i];
if (item.url) {
- model_->AddURL(node, i, item.title, GURL(item.url));
+ model_->AddURL(node, i, WideToUTF16Hack(item.title), GURL(item.url));
} else {
- model_->AddGroup(node, i, item.title);
+ model_->AddGroup(node, i, WideToUTF16Hack(item.title));
}
}
}
@@ -982,11 +1001,11 @@ void ProfileSyncServiceTestWithData::CompareWithTestData(
for (int i = 0; i < size; ++i) {
const BookmarkNode* child_node = node->GetChild(i);
const TestData& item = data[i];
- EXPECT_TRUE(child_node->GetTitle() == item.title);
+ EXPECT_EQ(child_node->GetTitle(), WideToUTF16Hack(item.title));
if (item.url) {
EXPECT_FALSE(child_node->is_folder());
EXPECT_TRUE(child_node->is_url());
- EXPECT_TRUE(child_node->GetURL() == GURL(item.url));
+ EXPECT_EQ(child_node->GetURL(), GURL(item.url));
} else {
EXPECT_TRUE(child_node->is_folder());
EXPECT_FALSE(child_node->is_url());
@@ -1259,7 +1278,8 @@ TEST_F(ProfileSyncServiceTestWithData, ModelAssociationInvalidPersistence) {
// the situation where bookmark model is different from sync model and
// make sure model associator correctly rebuilds associations.
const BookmarkNode* bookmark_bar_node = model_->GetBookmarkBarNode();
- model_->AddURL(bookmark_bar_node, 0, L"xtra", GURL("http://www.xtra.com"));
+ model_->AddURL(bookmark_bar_node, 0, ASCIIToUTF16("xtra"),
+ GURL("http://www.xtra.com"));
// Now restart the sync service. This time it will try to use the persistent
// associations and realize that they are invalid and hence will rebuild
// associations.
@@ -1303,8 +1323,9 @@ TEST_F(ProfileSyncServiceTestWithData, RecoverAfterDeletingSyncDataDirectory) {
// Now pretend that the user has deleted this directory from the disk.
file_util::Delete(sync_data_directory, true);
- // Restart the sync service.
- StartSyncService();
+ // Restart the sync service. Don't fake out setting initial sync ended; lets
+ // make sure the system does in fact nudge and wait for this to happen.
+ StartSyncServiceAndSetInitialSyncEnded(false);
// Make sure we're back in sync. In real life, the user would need
// to reauthenticate before this happens, but in the test, authentication
@@ -1333,7 +1354,9 @@ TEST_F(ProfileSyncServiceTestWithData, TestStartupWithOldSyncData) {
if (!service_.get()) {
service_.reset(
new TestProfileSyncService(&factory_, profile_.get(),
- false, true, NULL));
+ "test", true, NULL));
+ service_->dont_set_initial_sync_ended_on_init();
+ service_->set_synchronous_sync_configuration();
profile_->GetPrefs()->SetBoolean(prefs::kSyncHasSetupCompleted, false);
model_associator_ = new TestBookmarkModelAssociator(service_.get(),
@@ -1358,26 +1381,25 @@ TEST_F(ProfileSyncServiceTestWithData, TestStartupWithOldSyncData) {
ASSERT_FALSE(service_->backend());
ASSERT_FALSE(service_->HasSyncSetupCompleted());
- // This will actually start up the sync service.
- service_->EnableForUser(NULL);
+ // Create some tokens in the token service; the service will startup when
+ // it is notified that tokens are available.
+ profile_->GetTokenService()->IssueAuthTokenForTest(
+ GaiaConstants::kSyncService, "sync_token");
+
syncable::ModelTypeSet set;
set.insert(syncable::BOOKMARKS);
service_->OnUserChoseDatatypes(false, set);
- MessageLoop::current()->Run();
+ MessageLoop::current()->RunAllPending();
// Stop the service so we can read the new Sync Data files that were created.
service_.reset();
// This file should have been deleted when the whole directory was nuked.
ASSERT_FALSE(file_util::PathExists(sync_file3));
+ ASSERT_FALSE(file_util::PathExists(sync_file1));
- // These two will still exist, but their texts should have changed.
- ASSERT_TRUE(file_util::PathExists(sync_file1));
- std::string file1text;
- file_util::ReadFileToString(sync_file1, &file1text);
- ASSERT_FALSE(file1text.compare(nonsense1) == 0);
-
+ // This will still exist, but the text should have changed.
ASSERT_TRUE(file_util::PathExists(sync_file2));
std::string file2text;
file_util::ReadFileToString(sync_file2, &file2text);
diff --git a/chrome/browser/sync/profile_sync_test_util.h b/chrome/browser/sync/profile_sync_test_util.h
index 838c381..7482bcb 100644
--- a/chrome/browser/sync/profile_sync_test_util.h
+++ b/chrome/browser/sync/profile_sync_test_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_PROFILE_SYNC_TEST_UTIL_H_
#define CHROME_BROWSER_SYNC_PROFILE_SYNC_TEST_UTIL_H_
+#pragma once
#include <string>
@@ -14,6 +15,7 @@
#include "base/task.h"
#include "base/thread.h"
#include "base/waitable_event.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/webdata/web_database.h"
@@ -22,7 +24,6 @@
#include "chrome/browser/sync/glue/bookmark_model_associator.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/data_type_manager_impl.h"
-#include "chrome/browser/sync/notification_method.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/unrecoverable_error_handler.h"
diff --git a/chrome/browser/sync/protocol/encryption.proto b/chrome/browser/sync/protocol/encryption.proto
index 1a331f4..89aba01 100644
--- a/chrome/browser/sync/protocol/encryption.proto
+++ b/chrome/browser/sync/protocol/encryption.proto
@@ -21,9 +21,10 @@ package sync_pb;
// change their passphrase (and thus their encryption key) at any time. When
// that happens, we make a best effort to reencrypt all nodes with the new
// passphrase, but since we don't have transactions on the server-side, we
-// cannot garantee that every node will be reencrypted. As a workaround, we keep
-// track of all keys, assign each key a name (by using that key to encrypt a
-// well known string) and keep track of which key was used to encrypt each node.
+// cannot guarantee that every node will be reencrypted. As a workaround, we
+// keep track of all keys, assign each key a name (by using that key to encrypt
+// a well known string) and keep track of which key was used to encrypt each
+// node.
message EncryptedData {
optional string key_name = 1;
optional string blob = 2;
diff --git a/chrome/browser/sync/protocol/nigori_specifics.proto b/chrome/browser/sync/protocol/nigori_specifics.proto
index ed896b6..205291f 100644
--- a/chrome/browser/sync/protocol/nigori_specifics.proto
+++ b/chrome/browser/sync/protocol/nigori_specifics.proto
@@ -18,9 +18,9 @@ import "sync.proto";
message NigoriKey {
optional string name = 1;
- optional string hostname = 2;
- optional string username = 3;
- optional string password = 4;
+ optional bytes user_key = 2;
+ optional bytes encryption_key = 3;
+ optional bytes mac_key = 4;
}
message NigoriKeyBag {
diff --git a/chrome/browser/sync/protocol/service_constants.h b/chrome/browser/sync/protocol/service_constants.h
index 2aed89d..ef80043 100644
--- a/chrome/browser/sync/protocol/service_constants.h
+++ b/chrome/browser/sync/protocol/service_constants.h
@@ -4,10 +4,9 @@
//
// Product-specific constants.
-#include "chrome/browser/sync/util/sync_types.h"
-
#ifndef CHROME_BROWSER_SYNC_PROTOCOL_SERVICE_CONSTANTS_H_
#define CHROME_BROWSER_SYNC_PROTOCOL_SERVICE_CONSTANTS_H_
+#pragma once
// These fixed service names are used to obtain auth cookies for the
// corresponding services. It might be interesting to make these updateable
diff --git a/chrome/browser/sync/protocol/sync.proto b/chrome/browser/sync/protocol/sync.proto
index 4a35d87..3a9fd02 100644
--- a/chrome/browser/sync/protocol/sync.proto
+++ b/chrome/browser/sync/protocol/sync.proto
@@ -232,6 +232,20 @@ message SyncEntity {
optional string client_defined_unique_tag = 23;
};
+// This message contains diagnostic information used to correlate
+// commit-related traffic with extensions-related mutations to the
+// data models in chromium. It plays no functional role in
+// processing this CommitMessage.
+message ChromiumExtensionsActivity {
+ // The human-readable ID identifying the extension responsible
+ // for the traffic reported in this ChromiumExtensionsActivity.
+ optional string extension_id = 1;
+
+ // How many times the extension successfully invoked a write
+ // operation through the bookmarks API since the last CommitMessage.
+ optional uint32 bookmark_writes_since_last_commit = 2;
+};
+
message CommitMessage {
repeated SyncEntity entries = 1;
@@ -239,20 +253,6 @@ message CommitMessage {
// returned as originator_cache_guid for any new items.
optional string cache_guid = 2;
- // This message contains diagnostic information used to correlate
- // commit-related traffic with extensions-related mutations to the
- // data models in chromium. It plays no functional role in
- // processing this CommitMessage.
- message ChromiumExtensionsActivity {
- // The human-readable ID identifying the extension responsible
- // for the traffic reported in this ChromiumExtensionsActivity.
- optional string extension_id = 1;
-
- // How many times the extension successfully invoked a write
- // operation through the bookmarks API since the last CommitMessage.
- optional uint32 bookmark_writes_since_last_commit = 2;
- }
-
repeated ChromiumExtensionsActivity extensions_activity = 3;
};
@@ -264,8 +264,10 @@ message GetUpdatesCallerInfo {
NOTIFICATION = 3; // The source of the update was a p2p notification.
PERIODIC = 4; // The source of the update was periodic polling.
SYNC_CYCLE_CONTINUATION = 5; // The source of the update was a
- } // continuation of a previous update.
-
+ // continuation of a previous update.
+ CLEAR_PRIVATE_DATA = 6; // Source is a call to remove all private data
+ }
+
required GetUpdatesSource source = 1;
// True only if notifications were enabled for this GetUpdateMessage.
@@ -291,12 +293,37 @@ message GetUpdatesMessage {
// requested_types may contain multiple EntitySpecifics extensions -- in this
// event, the server will return items of all the indicated types.
optional EntitySpecifics requested_types = 4;
+
+ // Client-requested limit on the maximum number of updates to return at once.
+ // The server may opt to return fewer updates than this amount, but it should
+ // not return more.
+ optional int32 batch_size = 5;
};
message AuthenticateMessage {
required string auth_token = 1;
};
+enum UserDataStatus {
+ SUCCESS = 0;
+
+ // A transient error happened, e.g. network error. Clear can be called again.
+ RETRIABLE_ERROR = 1;
+
+ // An internal error happened
+ INTERNAL_SERVER_ERROR = 2;
+}
+
+// This message is sent to the server to clear data. An asynchronous
+// response is returned to the client indicating that the server has received
+// the request and has begun to clear data.
+message ClearUserDataRequest {
+}
+
+message ClearUserDataResponse {
+ optional UserDataStatus status = 1;
+}
+
message ClientToServerMessage {
required string share = 1;
optional int32 protocol_version = 2 [default = 24];
@@ -304,6 +331,7 @@ message ClientToServerMessage {
COMMIT = 1;
GET_UPDATES = 2;
AUTHENTICATE = 3;
+ CLEAR_DATA = 4;
}
required Contents message_contents = 3;
@@ -315,6 +343,9 @@ message ClientToServerMessage {
// The client sets this if it detects a sync issue. The server will tell it
// if it should perform a refresh.
optional bool sync_problem_detected = 8 [default = false];
+
+ // Request to clear all Chromium data from the server
+ optional ClearUserDataRequest clear_user_data = 9;
};
message CommitResponse {
@@ -422,7 +453,7 @@ message ClientToServerResponse {
USER_NOT_ACTIVATED = 5; // User doesn't have the Chrome bit set on that
// Google Account.
AUTH_INVALID = 6; // Auth token or cookie is otherwise invalid.
- CLEAR_PENDING = 7; // A clear of the user data is pending (e.g.
+ CLEAR_PENDING = 7; // A clear of the user data is pending (e.g.
// initiated by privacy request). Client should
// come back later.
}
@@ -437,5 +468,6 @@ message ClientToServerResponse {
optional ClientCommand client_command = 7;
optional ProfilingData profiling_data = 8;
+ optional ClearUserDataResponse clear_user_data = 9;
};
diff --git a/chrome/browser/sync/protocol/sync_proto.gyp b/chrome/browser/sync/protocol/sync_proto.gyp
index 5f381cd..05be29f 100644
--- a/chrome/browser/sync/protocol/sync_proto.gyp
+++ b/chrome/browser/sync/protocol/sync_proto.gyp
@@ -15,12 +15,15 @@
'sources': [
'sync.proto',
'encryption.proto',
+ 'app_specifics.proto',
'autofill_specifics.proto',
'bookmark_specifics.proto',
'extension_specifics.proto',
'nigori_specifics.proto',
'password_specifics.proto',
'preference_specifics.proto',
+ 'session_specifics.proto',
+ 'test.proto',
'theme_specifics.proto',
'typed_url_specifics.proto',
],
diff --git a/chrome/browser/sync/protocol/sync_proto.target.mk b/chrome/browser/sync/protocol/sync_proto.target.mk
index 95d95c3..b60e9c8 100644
--- a/chrome/browser/sync/protocol/sync_proto.target.mk
+++ b/chrome/browser/sync/protocol/sync_proto.target.mk
@@ -31,19 +31,33 @@ all_deps += $(builddir)/pyproto/sync_pb/encryption_pb2.py $(obj)/gen/protoc_out/
cmd_sync_proto_genproto_1 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./encryption$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
quiet_cmd_sync_proto_genproto_1 = RULE sync_proto_genproto_1 $@
+$(builddir)/pyproto/sync_pb/app_specifics_pb2.py: obj := $(abs_obj)
+
+$(builddir)/pyproto/sync_pb/app_specifics_pb2.py: builddir := $(abs_builddir)
+
+$(builddir)/pyproto/sync_pb/app_specifics_pb2.py: TOOLSET := $(TOOLSET)
+$(builddir)/pyproto/sync_pb/app_specifics_pb2.py: chrome/browser/sync/protocol/app_specifics.proto $(builddir)/protoc FORCE_DO_CMD
+ $(call do_cmd,sync_proto_genproto_2)
+$(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.cc: $(builddir)/pyproto/sync_pb/app_specifics_pb2.py
+$(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.cc: ;
+
+all_deps += $(builddir)/pyproto/sync_pb/app_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.cc
+cmd_sync_proto_genproto_2 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./app_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_2 = RULE sync_proto_genproto_2 $@
+
$(builddir)/pyproto/sync_pb/autofill_specifics_pb2.py: obj := $(abs_obj)
$(builddir)/pyproto/sync_pb/autofill_specifics_pb2.py: builddir := $(abs_builddir)
$(builddir)/pyproto/sync_pb/autofill_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/autofill_specifics_pb2.py: chrome/browser/sync/protocol/autofill_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_2)
+ $(call do_cmd,sync_proto_genproto_3)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.cc: $(builddir)/pyproto/sync_pb/autofill_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/autofill_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.cc
-cmd_sync_proto_genproto_2 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./autofill_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_2 = RULE sync_proto_genproto_2 $@
+cmd_sync_proto_genproto_3 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./autofill_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_3 = RULE sync_proto_genproto_3 $@
$(builddir)/pyproto/sync_pb/bookmark_specifics_pb2.py: obj := $(abs_obj)
@@ -51,13 +65,13 @@ $(builddir)/pyproto/sync_pb/bookmark_specifics_pb2.py: builddir := $(abs_builddi
$(builddir)/pyproto/sync_pb/bookmark_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/bookmark_specifics_pb2.py: chrome/browser/sync/protocol/bookmark_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_3)
+ $(call do_cmd,sync_proto_genproto_4)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/bookmark_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/bookmark_specifics.pb.cc: $(builddir)/pyproto/sync_pb/bookmark_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/bookmark_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/bookmark_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/bookmark_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/bookmark_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/bookmark_specifics.pb.cc
-cmd_sync_proto_genproto_3 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./bookmark_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_3 = RULE sync_proto_genproto_3 $@
+cmd_sync_proto_genproto_4 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./bookmark_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_4 = RULE sync_proto_genproto_4 $@
$(builddir)/pyproto/sync_pb/extension_specifics_pb2.py: obj := $(abs_obj)
@@ -65,13 +79,13 @@ $(builddir)/pyproto/sync_pb/extension_specifics_pb2.py: builddir := $(abs_buildd
$(builddir)/pyproto/sync_pb/extension_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/extension_specifics_pb2.py: chrome/browser/sync/protocol/extension_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_4)
+ $(call do_cmd,sync_proto_genproto_5)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/extension_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/extension_specifics.pb.cc: $(builddir)/pyproto/sync_pb/extension_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/extension_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/extension_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/extension_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/extension_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/extension_specifics.pb.cc
-cmd_sync_proto_genproto_4 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./extension_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_4 = RULE sync_proto_genproto_4 $@
+cmd_sync_proto_genproto_5 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./extension_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_5 = RULE sync_proto_genproto_5 $@
$(builddir)/pyproto/sync_pb/nigori_specifics_pb2.py: obj := $(abs_obj)
@@ -79,13 +93,13 @@ $(builddir)/pyproto/sync_pb/nigori_specifics_pb2.py: builddir := $(abs_builddir)
$(builddir)/pyproto/sync_pb/nigori_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/nigori_specifics_pb2.py: chrome/browser/sync/protocol/nigori_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_5)
+ $(call do_cmd,sync_proto_genproto_6)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/nigori_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/nigori_specifics.pb.cc: $(builddir)/pyproto/sync_pb/nigori_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/nigori_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/nigori_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/nigori_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/nigori_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/nigori_specifics.pb.cc
-cmd_sync_proto_genproto_5 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./nigori_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_5 = RULE sync_proto_genproto_5 $@
+cmd_sync_proto_genproto_6 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./nigori_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_6 = RULE sync_proto_genproto_6 $@
$(builddir)/pyproto/sync_pb/password_specifics_pb2.py: obj := $(abs_obj)
@@ -93,13 +107,13 @@ $(builddir)/pyproto/sync_pb/password_specifics_pb2.py: builddir := $(abs_builddi
$(builddir)/pyproto/sync_pb/password_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/password_specifics_pb2.py: chrome/browser/sync/protocol/password_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_6)
+ $(call do_cmd,sync_proto_genproto_7)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/password_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/password_specifics.pb.cc: $(builddir)/pyproto/sync_pb/password_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/password_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/password_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/password_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/password_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/password_specifics.pb.cc
-cmd_sync_proto_genproto_6 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./password_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_6 = RULE sync_proto_genproto_6 $@
+cmd_sync_proto_genproto_7 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./password_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_7 = RULE sync_proto_genproto_7 $@
$(builddir)/pyproto/sync_pb/preference_specifics_pb2.py: obj := $(abs_obj)
@@ -107,13 +121,41 @@ $(builddir)/pyproto/sync_pb/preference_specifics_pb2.py: builddir := $(abs_build
$(builddir)/pyproto/sync_pb/preference_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/preference_specifics_pb2.py: chrome/browser/sync/protocol/preference_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_7)
+ $(call do_cmd,sync_proto_genproto_8)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.cc: $(builddir)/pyproto/sync_pb/preference_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/preference_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.cc
-cmd_sync_proto_genproto_7 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./preference_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_7 = RULE sync_proto_genproto_7 $@
+cmd_sync_proto_genproto_8 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./preference_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_8 = RULE sync_proto_genproto_8 $@
+
+$(builddir)/pyproto/sync_pb/session_specifics_pb2.py: obj := $(abs_obj)
+
+$(builddir)/pyproto/sync_pb/session_specifics_pb2.py: builddir := $(abs_builddir)
+
+$(builddir)/pyproto/sync_pb/session_specifics_pb2.py: TOOLSET := $(TOOLSET)
+$(builddir)/pyproto/sync_pb/session_specifics_pb2.py: chrome/browser/sync/protocol/session_specifics.proto $(builddir)/protoc FORCE_DO_CMD
+ $(call do_cmd,sync_proto_genproto_9)
+$(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.cc: $(builddir)/pyproto/sync_pb/session_specifics_pb2.py
+$(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.cc: ;
+
+all_deps += $(builddir)/pyproto/sync_pb/session_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.cc
+cmd_sync_proto_genproto_9 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./session_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_9 = RULE sync_proto_genproto_9 $@
+
+$(builddir)/pyproto/sync_pb/test_pb2.py: obj := $(abs_obj)
+
+$(builddir)/pyproto/sync_pb/test_pb2.py: builddir := $(abs_builddir)
+
+$(builddir)/pyproto/sync_pb/test_pb2.py: TOOLSET := $(TOOLSET)
+$(builddir)/pyproto/sync_pb/test_pb2.py: chrome/browser/sync/protocol/test.proto $(builddir)/protoc FORCE_DO_CMD
+ $(call do_cmd,sync_proto_genproto_10)
+$(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.cc: $(builddir)/pyproto/sync_pb/test_pb2.py
+$(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.cc: ;
+
+all_deps += $(builddir)/pyproto/sync_pb/test_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.cc
+cmd_sync_proto_genproto_10 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./test$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_10 = RULE sync_proto_genproto_10 $@
$(builddir)/pyproto/sync_pb/theme_specifics_pb2.py: obj := $(abs_obj)
@@ -121,13 +163,13 @@ $(builddir)/pyproto/sync_pb/theme_specifics_pb2.py: builddir := $(abs_builddir)
$(builddir)/pyproto/sync_pb/theme_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/theme_specifics_pb2.py: chrome/browser/sync/protocol/theme_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_8)
+ $(call do_cmd,sync_proto_genproto_11)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.cc: $(builddir)/pyproto/sync_pb/theme_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/theme_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.cc
-cmd_sync_proto_genproto_8 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./theme_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_8 = RULE sync_proto_genproto_8 $@
+cmd_sync_proto_genproto_11 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./theme_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_11 = RULE sync_proto_genproto_11 $@
$(builddir)/pyproto/sync_pb/typed_url_specifics_pb2.py: obj := $(abs_obj)
@@ -135,13 +177,13 @@ $(builddir)/pyproto/sync_pb/typed_url_specifics_pb2.py: builddir := $(abs_buildd
$(builddir)/pyproto/sync_pb/typed_url_specifics_pb2.py: TOOLSET := $(TOOLSET)
$(builddir)/pyproto/sync_pb/typed_url_specifics_pb2.py: chrome/browser/sync/protocol/typed_url_specifics.proto $(builddir)/protoc FORCE_DO_CMD
- $(call do_cmd,sync_proto_genproto_9)
+ $(call do_cmd,sync_proto_genproto_12)
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/typed_url_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/typed_url_specifics.pb.cc: $(builddir)/pyproto/sync_pb/typed_url_specifics_pb2.py
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/typed_url_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/typed_url_specifics.pb.cc: ;
all_deps += $(builddir)/pyproto/sync_pb/typed_url_specifics_pb2.py $(obj)/gen/protoc_out/chrome/browser/sync/protocol/typed_url_specifics.pb.h $(obj)/gen/protoc_out/chrome/browser/sync/protocol/typed_url_specifics.pb.cc
-cmd_sync_proto_genproto_9 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./typed_url_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
-quiet_cmd_sync_proto_genproto_9 = RULE sync_proto_genproto_9 $@
+cmd_sync_proto_genproto_12 = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd chrome/browser/sync/protocol; mkdir -p $(obj)/gen/protoc_out/chrome/browser/sync/protocol $(builddir)/pyproto/sync_pb; "$(builddir)/protoc" "--proto_path=." "./typed_url_specifics$(suffix $<)" "--cpp_out=$(obj)/gen/protoc_out/chrome/browser/sync/protocol" "--python_out=$(builddir)/pyproto/sync_pb"
+quiet_cmd_sync_proto_genproto_12 = RULE sync_proto_genproto_12 $@
rule_sync_proto_genproto_outputs := $(builddir)/pyproto/sync_pb/sync_pb2.py \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/sync.pb.h \
@@ -149,6 +191,9 @@ rule_sync_proto_genproto_outputs := $(builddir)/pyproto/sync_pb/sync_pb2.py \
$(builddir)/pyproto/sync_pb/encryption_pb2.py \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/encryption.pb.h \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/encryption.pb.cc \
+ $(builddir)/pyproto/sync_pb/app_specifics_pb2.py \
+ $(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.h \
+ $(obj)/gen/protoc_out/chrome/browser/sync/protocol/app_specifics.pb.cc \
$(builddir)/pyproto/sync_pb/autofill_specifics_pb2.py \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.h \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/autofill_specifics.pb.cc \
@@ -167,6 +212,12 @@ rule_sync_proto_genproto_outputs := $(builddir)/pyproto/sync_pb/sync_pb2.py \
$(builddir)/pyproto/sync_pb/preference_specifics_pb2.py \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.h \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/preference_specifics.pb.cc \
+ $(builddir)/pyproto/sync_pb/session_specifics_pb2.py \
+ $(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.h \
+ $(obj)/gen/protoc_out/chrome/browser/sync/protocol/session_specifics.pb.cc \
+ $(builddir)/pyproto/sync_pb/test_pb2.py \
+ $(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.h \
+ $(obj)/gen/protoc_out/chrome/browser/sync/protocol/test.pb.cc \
$(builddir)/pyproto/sync_pb/theme_specifics_pb2.py \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.h \
$(obj)/gen/protoc_out/chrome/browser/sync/protocol/theme_specifics.pb.cc \
@@ -195,6 +246,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -227,6 +279,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
diff --git a/chrome/browser/sync/resources/about_sync.html b/chrome/browser/sync/resources/about_sync.html
index c65a7bb..6f62f5d 100644
--- a/chrome/browser/sync/resources/about_sync.html
+++ b/chrome/browser/sync/resources/about_sync.html
@@ -157,6 +157,12 @@ table.list#details .name {
</div>
</td>
</tr>
+ <tr>
+ <td colspan="2">
+ <span class="desc"><h2> Sync URL </h2></span>
+ <strong jscontent="service_url"></strong>
+ </td>
+ </tr>
</table>
<br /><br /><br />
<h2> </h2>
diff --git a/chrome/browser/sync/resources/choose_datatypes.html b/chrome/browser/sync/resources/choose_datatypes.html
index b325c55..fd1a9bf 100644
--- a/chrome/browser/sync/resources/choose_datatypes.html
+++ b/chrome/browser/sync/resources/choose_datatypes.html
@@ -3,27 +3,26 @@
<title></title>
<style type="text/css">
body {
- line-height: 1.8em;
+ line-height: 1.5em;
background: #FFFFFF;
margin: 10px 15px;
+ font-size: 11pt;
}
html[os='mac'] body {
- line-height: 1.8em;
+ line-height: 1.5em;
margin: 15px 20px;
background: #FFFFFF;
}
-html[os='mac'] form {
- font-size: 110%;
-}
-html[os='linux'] form {
- font-size: 120%;
+form {
+ -webkit-user-select: none;
}
.sync-header {
font-size: 1.2em;
font-weight: bold;
+ margin-bottom: 10px;
}
.sync-select-customization {
- margin-top: 5px;
+ margin-top: 10px;
}
#chooseDataTypesRadio {
vertical-align: top;
@@ -32,6 +31,8 @@ html[os='linux'] form {
display: inline-block;
}
#chooseDataTypesBody {
+ width: 90%;
+ -webkit-margin-start: 3ex;
}
#chooseDataTypesBody > div {
margin-top: 0px;
@@ -39,12 +40,20 @@ html[os='linux'] form {
-webkit-column-gap: 10px;
column-count: 2;
column-gap: 10px;
- width: 250px;
}
.sync-item-show {
display: block;
white-space: nowrap;
}
+
+.sync-item-show > label {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ display: inline-block;
+ width: 92%;
+}
+
.sync-item-hide {
display: none;
}
@@ -174,6 +183,13 @@ html[os='mac'] input[type='submit'] {
} else {
document.getElementById("omniboxItem").className = "sync-item-hide";
}
+ if (args.appsRegistered) {
+ document.getElementById("appsCheckbox").checked =
+ args.syncApps;
+ document.getElementById("appsItem").className = "sync-item-show";
+ } else {
+ document.getElementById("appsItem").className = "sync-item-hide";
+ }
}
function setErrorState(args) {
@@ -257,14 +273,15 @@ html[os='mac'] input[type='submit'] {
"syncPasswords": syncAll || f.passwordsCheckbox.checked,
"syncAutofill": syncAll || f.autofillCheckbox.checked,
"syncExtensions": syncAll || f.extensionsCheckbox.checked,
- "syncTypedUrls": syncAll || f.typedUrlsCheckbox.checked
+ "syncTypedUrls": syncAll || f.typedUrlsCheckbox.checked,
+ "syncApps": syncAll || f.appsCheckbox.checked
});
chrome.send("ChooseDataTypes", [result]);
}
</script>
</head>
-<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize"
+<body i18n-values=".style.fontFamily:fontfamily"
onload="initializeChooseDataTypesDialog();">
<form id="chooseDataTypesForm"
onSubmit="sendChooseDataTypesAndClose(); return false;">
@@ -283,50 +300,63 @@ html[os='mac'] input[type='submit'] {
<div id="chooseDataTypes" class="sync-choice_radio">
<input id="chooseDataTypesRadio" type="radio" name="syncChooseDataTypes"
onclick="setDataTypeCheckboxesEnabled(true)">
- <div id="chooseDataTypesBody">
<label for="chooseDataTypesRadio" i18n-content="choosedatatypes" ></label>
+ <div id="chooseDataTypesBody">
<div>
+ <!-- Apps -->
+ <div class="sync-item-show" id="appsItem">
+ <input id="appsCheckbox" name="dataTypeCheckbox" type="checkbox">
+ <label id="appsCheckboxLabel" name="dataTypeLabel"
+ for="appsCheckbox" i18n-content="apps"
+ i18n-values="title:apps"></label>
+ </div>
<!-- Autofill -->
<div class="sync-item-show" id="autofillItem">
<input id="autofillCheckbox" name="dataTypeCheckbox" type="checkbox">
<label id="autofillCheckboxLabel" name="dataTypeLabel"
- for="autofillCheckbox" i18n-content="autofill"></label>
+ for="autofillCheckbox" i18n-content="autofill"
+ i18n-values="title:autofill"></label>
</div>
<!-- Bookmarks -->
<div class="sync-item-show" id="bookmarksItem">
<input id="bookmarksCheckbox" name="dataTypeCheckbox" type="checkbox">
<label id="bookmarksCheckboxLabel" name="dataTypeLabel"
- for="bookmarksCheckbox" i18n-content="bookmarks"></label>
+ for="bookmarksCheckbox" i18n-content="bookmarks"
+ i18n-values="title:bookmarks"></label>
</div>
<!-- Extensions -->
<div class="sync-item-show" id="extensionsItem">
<input id="extensionsCheckbox" name="dataTypeCheckbox" type="checkbox">
<label id="extensionsCheckboxLabel" name="dataTypeLabel"
- for="extensionsCheckbox" i18n-content="extensions"></label>
+ for="extensionsCheckbox" i18n-content="extensions"
+ i18n-values="title:extensions"></label>
</div>
<!-- Omnibox -->
<div class="sync-item-show" id="omniboxItem">
<input id="typedUrlsCheckbox" name="dataTypeCheckbox" type="checkbox">
<label id="typedUrlsCheckboxLabel" name="dataTypeLabel"
- for="typedUrlsCheckbox" i18n-content="typedurls"></label>
+ for="typedUrlsCheckbox" i18n-content="typedurls"
+ i18n-values="title:typedurls"></label>
</div>
<!-- Passwords -->
<div class="sync-item-show" id="passwordsItem">
<input id="passwordsCheckbox" name="dataTypeCheckbox" type="checkbox">
<label id="passwordsCheckboxLabel" name="dataTypeLabel"
- for="passwordsCheckbox" i18n-content="passwords"></label>
+ for="passwordsCheckbox" i18n-content="passwords"
+ i18n-values="title:passwords"></label>
</div>
<!-- Preferences -->
<div class="sync-item-show" id="preferencesItem">
<input id="preferencesCheckbox" name="dataTypeCheckbox" type="checkbox">
<label id="preferencesCheckboxLabel" name="dataTypeLabel"
- for="preferencesCheckbox" i18n-content="preferences"></label>
+ for="preferencesCheckbox" i18n-content="preferences"
+ i18n-values="title:preferences"></label>
</div>
<!-- Themes -->
<div class="sync-item-show" id="themesItem">
<input id="themesCheckbox" name="dataTypeCheckbox" type="checkbox">
<label id="themesCheckboxLabel" name="dataTypeLabel" for="themesCheckbox"
- i18n-content="themes"></label>
+ i18n-content="themes" i18n-values="title:themes"></label>
</div>
</div>
</div>
diff --git a/chrome/browser/sync/resources/gaia_login.html b/chrome/browser/sync/resources/gaia_login.html
index f9de48a..7834942 100644
--- a/chrome/browser/sync/resources/gaia_login.html
+++ b/chrome/browser/sync/resources/gaia_login.html
@@ -2,7 +2,10 @@
<head>
<style type="text/css">
body,td,div,p,a,font,span {font-family: arial,sans-serif;}
- body { background-color:#ffffff }
+ body {
+ background-color:#ffffff;
+ -webkit-user-select: none;
+ }
A:link {color:#0000cc; }
A:visited { color:#551a8b; }
A:active { color:#ff0000; }
@@ -17,6 +20,9 @@
text-align: left;
}
#gaia_account_text { font-weight: bold; }
+ #email_readonly { font-size: 10pt;
+ font-weight: bold;
+ display: none; }
div.errorbox-good {}
div.errorbox-bad {}
div.errormsg { color: red; font-size: smaller;
@@ -76,16 +82,30 @@
height: 5px;
}
#top_blurb {
- text-align: justify;
- }
- input[type='button'] {
- min-width: 87px;
- min-height: 26px;
+ font-size: 11pt;
+ line-height: 1.5em;
}
+ input[type='button'],
input[type='submit'] {
min-width: 87px;
min-height: 26px;
}
+ #top_blurb_error {
+ display: block;
+ margin-bottom: 10px;
+ margin-right: auto;
+ margin-left: auto;
+ width: 70%;
+ text-align: center;
+ padding: 4px 10px;
+ background-color: #eeb939;
+ -webkit-border-radius: 4px;
+ font-weight: bold;
+ font-size: 11pt;
+ }
+ #content_table {
+ padding: 2px;
+ }
</style>
</head>
<body bgcolor="#ffffff" vlink="#666666"
@@ -148,6 +168,13 @@
var f = document.getElementById("gaia_loginform");
if (f) {
f.Email.value = args.user;
+ if (!args.editable_user) {
+ f.Email.style.display = 'none';
+ var span = document.getElementById('email_readonly');
+ span.appendChild(document.createTextNode(f.Email.value));
+ span.style.display = 'inline';
+ setElementDisplay("createaccountdiv", "none");
+ }
}
if (1 == args.error) {
setElementDisplay("errormsg_1_Password", 'table-row');
@@ -170,9 +197,7 @@
// The captcha takes up lots of space, so make room.
setElementDisplay("top_blurb", "none");
- setElementDisplay("top_blurb_error", "none");
setElementDisplay("createaccountdiv", "none");
- setElementDisplay("topspacer", "none");
var gaiaTable = document.getElementById('gaia_table');
gaiaTable.cellPadding = 0;
gaiaTable.cellSpacing = 1;
@@ -251,8 +276,7 @@
function setBlurbError() {
if (g_is_captcha_challenge_active)
return; // No blurb in captcha challenge mode.
- document.getElementById("top_blurb").style.display = "none";
- document.getElementById("top_blurb_error").style.display = "block";
+ document.getElementById("top_blurb_error").style.visibility = "visible";
document.getElementById('Email').disabled = false;
document.getElementById('Passwd').disabled = false;
}
@@ -296,13 +320,10 @@
font-style: italic; }
</style>
<div id="top_blurb">
- <p><font size="-1"><span i18n-content="introduction"></span></font></p>
+ <span i18n-content="introduction"></span>
</div>
- <div id="top_blurb_error" style="display:none">
- <p><font size="-1">
- <span i18n-content="settingupsync"></span><br/><br/>
- <b><span i18n-content="errorsigningin"></span></b>
- </font></p>
+ <div id="top_blurb_error" style="visibility:hidden">
+ <span i18n-content="errorsigningin"></span>
</div>
<form id="gaia_loginform" onsubmit="sendCredentialsAndClose(); return false;">
<div id="gaia_loginbox">
@@ -315,9 +336,6 @@
<table id="gaia_table" align="center" border="0" cellpadding="1"
cellspacing="0">
<tr>
- <td id="topspacer" class="toppageverticalspace" colspan="2"></td>
- </tr>
- <tr>
<td colspan="2" align="center">
<table>
<tr>
@@ -358,6 +376,7 @@
<td>
<input type="text" name="Email" id="Email" size="18"
value="" class='gaia le val' />
+ <span id="email_readonly"></span>
</td>
</tr>
<tr>
@@ -453,6 +472,9 @@
<td class="noverticalpadding">
<input id="signIn" type="submit" class="gaia le button"
name="signIn" i18n-values="value:signin"/>
+ <input type="button" name="cancel" i18n-values="value:cancel"
+ onclick="CloseDialog();" >
+
</td>
</tr>
</table>
@@ -489,12 +511,6 @@
<td class="cancelspacenocaptcha" id="cancelspacer" colspan="2">
</td>
</tr>
-<tr>
- <td class="endaligned noverticalpadding" colspan="2" style="vertical-align: bottom">
- <input type="button" name="cancel" i18n-values="value:cancel"
- onclick="CloseDialog();" style="width:85">
- </td>
-</tr>
</table>
</body>
</html>
diff --git a/chrome/browser/sync/resources/setup_done.html b/chrome/browser/sync/resources/setup_done.html
index 4e5cf34..973164b 100644
--- a/chrome/browser/sync/resources/setup_done.html
+++ b/chrome/browser/sync/resources/setup_done.html
@@ -2,61 +2,68 @@
<head>
<title></title>
<style type="text/css">
-body,td,div,p,a,font,span {
- font-family: arial,sans-serif;
- }
body {
- bgcolor:"#ffffff"
- }
-.gaia.le.button {
- font-family: Arial, Helvetica, sans-serif;
- font-size: smaller;
+ background: #FFFFFF;
+ font-size: 11pt;
+ line-height: 1.5em;
+ margin: 10px 15px;
+ -webkit-user-select: none;
}
-.endaligned {
- text-align: right;
- align: right;
+.sync-header {
+ font-size: 1.2em;
+ font-weight: bold;
}
-html[dir='rtl'] .endaligned {
+.sync-success-image {
+ text-align: center;
+ margin: 20px;
+}
+#user {
+ font-weight: bold;
+}
+.sync-footer {
+ position: fixed;
+ right: 0px;
+ bottom: 0px;
+ margin-right: 10px;
+ margin-bottom: 10px;
+}
+html[dir='rtl'] .sync-footer {
text-align: left;
- align: left;
+ left: 0px;
+ bottom: 0px;
+ margin-left: 20px;
+}
+input[type='submit'] {
+ min-width: 87px;
+ min-height: 26px;
+}
+html[os='mac'] input[type='submit'] {
+ font-size: 12pt;
}
+
</style>
<script>
function setShowFirstTimeSetupSummary() {
- document.getElementById("summary").innerHTML =
- "<p><font size='-1'>" + templateData['firsttimesetupsummary']
- + "</font></p>";
+ // TODO(hclam): Show the information for the first time setup.
}
function setSyncedToUser(synced_to) {
document.getElementById('user').innerHTML = synced_to;
}
- function onPageShown() {
+ function onPageShown() {
document.getElementById("close").focus();
}
</script>
-<body bgcolor="#ffffff" vlink="#666666
- i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize"
- style="margin: 10px">
-<table height="100%" width="100%" margin="0" cellpadding="0">
- <tr valign="top">
- <td>
- <p><font size="-1"><b><span i18n-content="success"></span></b></font></p>
- <div align="center">
- <img src="success-large.png" />
- </div>
- <br />
- <p><font size="-1"><span id="user"></span></font></p>
- <div id="summary">
- <p><font size="-1"><span i18n-content="setupsummary"></span></font></p>
- </div>
- </td>
- </tr>
- <tr valign="bottom">
- <td class="endaligned">
- <input id="close" type="submit" i18n-values="value:okay" style="width:85"
- onclick='chrome.send("DialogClose", [""])' />
- </td>
- </tr>
-</table>
+</head>
+<body i18n-values=".style.fontFamily:fontfamily">
+ <div class="sync-header" i18n-content="success"></div>
+ <div class="sync-success-image">
+ <img src="success-large.png" />
+ </div>
+ <div id="user"></div>
+ <div id="summary" i18n-content="setupsummary"></div>
+ <div class="sync-footer">
+ <input id="close" type="submit" i18n-values="value:okay"
+ onclick='chrome.send("DialogClose", [""])' />
+ </div>
</body>
</html>
diff --git a/chrome/browser/sync/resources/setup_flow.html b/chrome/browser/sync/resources/setup_flow.html
index 4b1dede..c45cf24 100644
--- a/chrome/browser/sync/resources/setup_flow.html
+++ b/chrome/browser/sync/resources/setup_flow.html
@@ -8,32 +8,40 @@
hideAllPages();
var args = JSON.parse(chrome.dialogArguments);
document.getElementById(args.iframeToShow).style.display = 'block';
+ document.getElementById(args.iframeToShow).tabIndex = 0;
}
function hideAllPages() {
document.getElementById('login').style.display = 'none';
+ document.getElementById('login').tabIndex = -1;
document.getElementById('choose_data_types').style.display = 'none';
- document.getElementById('done').style.display = 'none';
- }
+ document.getElementById('choose_data_types').tabIndex = -1;
+ document.getElementById('done').style.display = 'none';
+ document.getElementById('done').tabIndex = -1;
+ }
function showChooseDataTypes() {
hideAllPages();
document.getElementById('choose_data_types').style.display = 'block';
+ document.getElementById('choose_data_types').tabIndex = 0;
}
function showSetupDone() {
hideAllPages();
document.getElementById('done').style.display = 'block';
+ document.getElementById('done').tabIndex = 0;
}
</script>
</head>
<body style="margin:0; border:0;" onload="showTheRightIframe();">
<iframe id="login" frameborder="0" width="100%" scrolling="no" height="100%"
- src="chrome://syncresources/gaialogin" style="display:none"></iframe>
+ src="chrome://syncresources/gaialogin" style="display:none"
+ tabindex="-1"></iframe>
<iframe id="choose_data_types" frameborder="0" width="100%" scrolling="no"
height="100%" src="chrome://syncresources/choosedatatypes"
- style="display:none"></iframe>
+ style="display:none" tabindex="-1"></iframe>
<iframe id="done" frameborder="0" width="100%" scrolling="no" height="100%"
- src="chrome://syncresources/setupdone" style="display:none"></iframe>
+ src="chrome://syncresources/setupdone" style="display:none"
+ tabindex="-1"></iframe>
</body>
</html>
diff --git a/chrome/browser/sync/sessions/ordered_commit_set.cc b/chrome/browser/sync/sessions/ordered_commit_set.cc
index 5c46a35..104bafb 100644
--- a/chrome/browser/sync/sessions/ordered_commit_set.cc
+++ b/chrome/browser/sync/sessions/ordered_commit_set.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/sync/sessions/ordered_commit_set.h"
+#include <algorithm>
+
#include "base/logging.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/sessions/ordered_commit_set.h b/chrome/browser/sync/sessions/ordered_commit_set.h
index 3252826..50f3e97 100644
--- a/chrome/browser/sync/sessions/ordered_commit_set.h
+++ b/chrome/browser/sync/sessions/ordered_commit_set.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SESSIONS_ORDERED_COMMIT_SET_H_
#define CHROME_BROWSER_SYNC_SESSIONS_ORDERED_COMMIT_SET_H_
+#pragma once
#include <map>
#include <set>
diff --git a/chrome/browser/sync/sessions/session_state.h b/chrome/browser/sync/sessions/session_state.h
index 6a2fa67..3f1e721 100644
--- a/chrome/browser/sync/sessions/session_state.h
+++ b/chrome/browser/sync/sessions/session_state.h
@@ -11,6 +11,7 @@
#ifndef CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
#define CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
+#pragma once
#include <set>
#include <vector>
diff --git a/chrome/browser/sync/sessions/status_controller.cc b/chrome/browser/sync/sessions/status_controller.cc
index cb15468..21159d8 100644
--- a/chrome/browser/sync/sessions/status_controller.cc
+++ b/chrome/browser/sync/sessions/status_controller.cc
@@ -230,8 +230,14 @@ bool StatusController::ServerSaysNothingMoreToDownload() const {
return false;
}
}
- // The server indicates "you're up to date" by not sending a new
- // timestamp.
+ // Changes remaining is an estimate, but if it's estimated to be
+ // zero, that's firm and we don't have to ask again.
+ if (updates_response().get_updates().has_changes_remaining() &&
+ updates_response().get_updates().changes_remaining() == 0) {
+ return true;
+ }
+ // Otherwise, the server can also indicate "you're up to date"
+ // by not sending a new timestamp.
return !updates_response().get_updates().has_new_timestamp();
}
diff --git a/chrome/browser/sync/sessions/status_controller.h b/chrome/browser/sync/sessions/status_controller.h
index f1e4a28..f367b50 100644
--- a/chrome/browser/sync/sessions/status_controller.h
+++ b/chrome/browser/sync/sessions/status_controller.h
@@ -31,6 +31,7 @@
#ifndef CHROME_BROWSER_SYNC_SESSIONS_STATUS_CONTROLLER_H_
#define CHROME_BROWSER_SYNC_SESSIONS_STATUS_CONTROLLER_H_
+#pragma once
#include <map>
diff --git a/chrome/browser/sync/sessions/sync_session.h b/chrome/browser/sync/sessions/sync_session.h
index dd498fe..d3320ca 100644
--- a/chrome/browser/sync/sessions/sync_session.h
+++ b/chrome/browser/sync/sessions/sync_session.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.
@@ -13,8 +13,8 @@
#ifndef CHROME_BROWSER_SYNC_SESSIONS_SYNC_SESSION_H_
#define CHROME_BROWSER_SYNC_SESSIONS_SYNC_SESSION_H_
+#pragma once
-#include <string>
#include <vector>
#include "base/basictypes.h"
diff --git a/chrome/browser/sync/sessions/sync_session_context.h b/chrome/browser/sync/sessions/sync_session_context.h
index bc4ea28..4c6b63f 100644
--- a/chrome/browser/sync/sessions/sync_session_context.h
+++ b/chrome/browser/sync/sessions/sync_session_context.h
@@ -17,6 +17,7 @@
#ifndef CHROME_BROWSER_SYNC_SESSIONS_SYNC_SESSION_CONTEXT_H_
#define CHROME_BROWSER_SYNC_SESSIONS_SYNC_SESSION_CONTEXT_H_
+#pragma once
#include <string>
#include "chrome/browser/chrome_thread.h"
@@ -30,7 +31,6 @@ class DirectoryManager;
namespace browser_sync {
-class AuthWatcher;
class ConflictResolver;
class ModelSafeWorkerRegistrar;
class ServerConnectionManager;
@@ -42,13 +42,11 @@ class ScopedSessionContextSyncerEventChannel;
class SyncSessionContext {
public:
SyncSessionContext(ServerConnectionManager* connection_manager,
- AuthWatcher* auth_watcher,
syncable::DirectoryManager* directory_manager,
ModelSafeWorkerRegistrar* model_safe_worker_registrar)
: resolver_(NULL),
syncer_event_channel_(NULL),
connection_manager_(connection_manager),
- auth_watcher_(auth_watcher),
directory_manager_(directory_manager),
registrar_(model_safe_worker_registrar),
extensions_activity_monitor_(new ExtensionsActivityMonitor()),
@@ -67,9 +65,6 @@ class SyncSessionContext {
ServerConnectionManager* connection_manager() {
return connection_manager_;
}
- AuthWatcher* auth_watcher() {
- return auth_watcher_;
- }
syncable::DirectoryManager* directory_manager() {
return directory_manager_;
}
@@ -104,6 +99,14 @@ class SyncSessionContext {
previous_session_routing_info_ = info;
}
+ sessions::SyncSessionSnapshot* previous_session_snapshot() {
+ return previous_session_snapshot_.get();
+ }
+
+ void set_last_snapshot(const SyncSessionSnapshot& snapshot) {
+ previous_session_snapshot_.reset(new SyncSessionSnapshot(snapshot));
+ }
+
private:
// Rather than force clients to set and null-out various context members, we
// extend our encapsulation boundary to scoped helpers that take care of this
@@ -116,7 +119,6 @@ class SyncSessionContext {
SyncerEventChannel* syncer_event_channel_;
ServerConnectionManager* const connection_manager_;
- AuthWatcher* const auth_watcher_;
syncable::DirectoryManager* const directory_manager_;
// A registrar of workers capable of processing work closures on a thread
@@ -138,6 +140,9 @@ class SyncSessionContext {
// by the user.
ModelSafeRoutingInfo previous_session_routing_info_;
+ // Cache of last session snapshot information.
+ scoped_ptr<sessions::SyncSessionSnapshot> previous_session_snapshot_;
+
DISALLOW_COPY_AND_ASSIGN(SyncSessionContext);
};
diff --git a/chrome/browser/sync/sessions/sync_session_unittest.cc b/chrome/browser/sync/sessions/sync_session_unittest.cc
index 2bc4594..011f667 100644
--- a/chrome/browser/sync/sessions/sync_session_unittest.cc
+++ b/chrome/browser/sync/sessions/sync_session_unittest.cc
@@ -27,7 +27,7 @@ class SyncSessionTest : public testing::Test,
GetModelSafeRoutingInfo(&routes_);
}
virtual void SetUp() {
- context_.reset(new SyncSessionContext(NULL, NULL, NULL, this));
+ context_.reset(new SyncSessionContext(NULL, NULL, this));
session_.reset(new SyncSession(context_.get(), this));
}
virtual void TearDown() {
@@ -40,7 +40,7 @@ class SyncSessionTest : public testing::Test,
}
virtual bool IsSyncingCurrentlySilenced() {
FailControllerInvocationIfDisabled("IsSyncingCurrentlySilenced");
- return false;
+ return false;
}
virtual void OnReceivedLongPollIntervalUpdate(
const base::TimeDelta& new_interval) {
@@ -51,7 +51,7 @@ class SyncSessionTest : public testing::Test,
FailControllerInvocationIfDisabled("OnReceivedShortPollIntervalUpdate");
}
virtual void OnShouldStopSyncingPermanently() {
- FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently");
+ FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently");
}
// ModelSafeWorkerRegistrar implementation.
@@ -110,7 +110,7 @@ TEST_F(SyncSessionTest, SetWriteTransaction) {
TestDirectorySetterUpper db;
db.SetUp();
session_.reset(NULL);
- context_.reset(new SyncSessionContext(NULL, NULL, db.manager(), this));
+ context_.reset(new SyncSessionContext(NULL, db.manager(), this));
session_.reset(new SyncSession(context_.get(), this));
context_->set_account_name(db.name());
syncable::ScopedDirLookup dir(context_->directory_manager(),
diff --git a/chrome/browser/sync/sync_constants.h b/chrome/browser/sync/sync_constants.h
index efca382..d395d25 100644
--- a/chrome/browser/sync/sync_constants.h
+++ b/chrome/browser/sync/sync_constants.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNC_CONSTANTS_H_
#define CHROME_BROWSER_SYNC_SYNC_CONSTANTS_H_
+#pragma once
namespace browser_sync {
diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc
index 5eb62d6..0931a3f 100644
--- a/chrome/browser/sync/sync_setup_flow.cc
+++ b/chrome/browser/sync/sync_setup_flow.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.
@@ -18,14 +18,14 @@
#include "chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h"
#endif
#include "chrome/browser/dom_ui/dom_ui_util.h"
-#include "chrome/browser/google_service_auth_error.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/pref_names.h"
#include "gfx/font.h"
#include "grit/locale_settings.h"
@@ -50,9 +50,9 @@ static bool GetAuthData(const std::string& json,
return false;
DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
- if (!result->GetString(L"user", username) ||
- !result->GetString(L"pass", password) ||
- !result->GetString(L"captcha", captcha)) {
+ if (!result->GetString("user", username) ||
+ !result->GetString("pass", password) ||
+ !result->GetString("captcha", captcha)) {
return false;
}
return true;
@@ -65,58 +65,64 @@ static bool GetDataTypeChoiceData(const std::string& json,
return false;
DictionaryValue* result = static_cast<DictionaryValue*>(parsed_value.get());
- if (!result->GetBoolean(L"keepEverythingSynced", sync_everything))
+ if (!result->GetBoolean("keepEverythingSynced", sync_everything))
return false;
// These values need to be kept in sync with where they are written in
// choose_datatypes.html.
bool sync_bookmarks;
- if (!result->GetBoolean(L"syncBookmarks", &sync_bookmarks))
+ if (!result->GetBoolean("syncBookmarks", &sync_bookmarks))
return false;
if (sync_bookmarks)
data_types->insert(syncable::BOOKMARKS);
bool sync_preferences;
- if (!result->GetBoolean(L"syncPreferences", &sync_preferences))
+ if (!result->GetBoolean("syncPreferences", &sync_preferences))
return false;
if (sync_preferences)
data_types->insert(syncable::PREFERENCES);
bool sync_themes;
- if (!result->GetBoolean(L"syncThemes", &sync_themes))
+ if (!result->GetBoolean("syncThemes", &sync_themes))
return false;
if (sync_themes)
data_types->insert(syncable::THEMES);
bool sync_passwords;
- if (!result->GetBoolean(L"syncPasswords", &sync_passwords))
+ if (!result->GetBoolean("syncPasswords", &sync_passwords))
return false;
if (sync_passwords)
data_types->insert(syncable::PASSWORDS);
bool sync_autofill;
- if (!result->GetBoolean(L"syncAutofill", &sync_autofill))
+ if (!result->GetBoolean("syncAutofill", &sync_autofill))
return false;
if (sync_autofill)
data_types->insert(syncable::AUTOFILL);
bool sync_extensions;
- if (!result->GetBoolean(L"syncExtensions", &sync_extensions))
+ if (!result->GetBoolean("syncExtensions", &sync_extensions))
return false;
if (sync_extensions)
data_types->insert(syncable::EXTENSIONS);
bool sync_typed_urls;
- if (!result->GetBoolean(L"syncTypedUrls", &sync_typed_urls))
+ if (!result->GetBoolean("syncTypedUrls", &sync_typed_urls))
return false;
if (sync_typed_urls)
data_types->insert(syncable::TYPED_URLS);
+ bool sync_apps;
+ if (!result->GetBoolean("syncApps", &sync_apps))
+ return false;
+ if (sync_apps)
+ data_types->insert(syncable::APPS);
+
return true;
}
-void FlowHandler::HandleSubmitAuth(const Value* value) {
- std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(value));
+void FlowHandler::HandleSubmitAuth(const ListValue* args) {
+ std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args));
std::string username, password, captcha;
if (json.empty())
return;
@@ -132,8 +138,8 @@ void FlowHandler::HandleSubmitAuth(const Value* value) {
flow_->OnUserSubmittedAuth(username, password, captcha);
}
-void FlowHandler::HandleChooseDataTypes(const Value* value) {
- std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(value));
+void FlowHandler::HandleChooseDataTypes(const ListValue* args) {
+ std::string json(dom_ui_util::GetJsonResponseFromFirstArgumentInList(args));
bool sync_everything;
syncable::ModelTypeSet chosen_types;
if (json.empty())
@@ -182,7 +188,6 @@ void FlowHandler::ShowGaiaSuccessAndSettingUp() {
// Called by SyncSetupFlow::Advance.
void FlowHandler::ShowChooseDataTypes(const DictionaryValue& args) {
-
// If you're starting the wizard at the Choose Data Types screen (i.e. from
// "Customize Sync"), this will be redundant. However, if you're coming from
// another wizard state, this will make sure Choose Data Types is on top.
@@ -197,8 +202,8 @@ void FlowHandler::ShowChooseDataTypes(const DictionaryValue& args) {
}
void FlowHandler::ShowSetupDone(const std::wstring& user) {
- StringValue synced_to_string(WideToUTF8(l10n_util::GetStringF(
- IDS_SYNC_NTP_SYNCED_TO, user)));
+ StringValue synced_to_string(l10n_util::GetStringFUTF8(
+ IDS_SYNC_NTP_SYNCED_TO, WideToUTF16Hack(user)));
std::string json;
base::JSONWriter::Write(&synced_to_string, false, &json);
std::wstring javascript = std::wstring(L"setSyncedToUser") +
@@ -253,7 +258,7 @@ SyncSetupFlow::~SyncSetupFlow() {
void SyncSetupFlow::GetDialogSize(gfx::Size* size) const {
PrefService* prefs = service_->profile()->GetPrefs();
- gfx::Font approximate_web_font = gfx::Font::CreateFont(
+ gfx::Font approximate_web_font = gfx::Font(
UTF8ToWide(prefs->GetString(prefs::kWebKitSansSerifFontFamily)),
prefs->GetInteger(prefs::kWebKitDefaultFontSize));
@@ -318,54 +323,63 @@ void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) {
// static
void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service,
DictionaryValue* args) {
- args->SetString(L"iframeToShow", "login");
+ args->SetString("iframeToShow", "login");
const GoogleServiceAuthError& error = service->GetAuthError();
if (!service->last_attempted_user_email().empty()) {
- args->SetString(L"user", service->last_attempted_user_email());
- args->SetInteger(L"error", error.state());
+ args->SetString("user", service->last_attempted_user_email());
+ args->SetInteger("error", error.state());
+ args->SetBoolean("editable_user", true);
} else {
- std::wstring user(UTF16ToWide(service->GetAuthenticatedUsername()));
- args->SetString(L"user", user);
- args->SetInteger(L"error", user.empty() ? 0 : error.state());
+ string16 user(service->GetAuthenticatedUsername());
+ args->SetString("user", user);
+ args->SetInteger("error", 0);
+ args->SetBoolean("editable_user", user.empty());
}
- args->SetString(L"captchaUrl", error.captcha().image_url.spec());
+ args->SetString("captchaUrl", error.captcha().image_url.spec());
}
// static
void SyncSetupFlow::GetArgsForChooseDataTypes(ProfileSyncService* service,
DictionaryValue* args) {
- args->SetString(L"iframeToShow", "choose_data_types");
- args->SetBoolean(L"keepEverythingSynced",
+ args->SetString("iframeToShow", "choose_data_types");
+ args->SetBoolean("keepEverythingSynced",
service->profile()->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced));
// Bookmarks, Preferences, and Themes are launched for good, there's no
// going back now. Check if the other data types are registered though.
syncable::ModelTypeSet registered_types;
service->GetRegisteredDataTypes(&registered_types);
- args->SetBoolean(L"passwordsRegistered",
+ args->SetBoolean("passwordsRegistered",
registered_types.count(syncable::PASSWORDS) > 0);
- args->SetBoolean(L"autofillRegistered",
+ args->SetBoolean("autofillRegistered",
registered_types.count(syncable::AUTOFILL) > 0);
- args->SetBoolean(L"extensionsRegistered",
+ args->SetBoolean("extensionsRegistered",
registered_types.count(syncable::EXTENSIONS) > 0);
- args->SetBoolean(L"typedUrlsRegistered",
+ args->SetBoolean("typedUrlsRegistered",
registered_types.count(syncable::TYPED_URLS) > 0);
-
- args->SetBoolean(L"syncBookmarks",
+ args->SetBoolean("appsRegistered",
+ registered_types.count(syncable::APPS) > 0);
+ args->SetBoolean("sessionsRegistered",
+ registered_types.count(syncable::SESSIONS) > 0);
+ args->SetBoolean("syncBookmarks",
service->profile()->GetPrefs()->GetBoolean(prefs::kSyncBookmarks));
- args->SetBoolean(L"syncPreferences",
+ args->SetBoolean("syncPreferences",
service->profile()->GetPrefs()->GetBoolean(prefs::kSyncPreferences));
- args->SetBoolean(L"syncThemes",
+ args->SetBoolean("syncThemes",
service->profile()->GetPrefs()->GetBoolean(prefs::kSyncThemes));
- args->SetBoolean(L"syncPasswords",
+ args->SetBoolean("syncPasswords",
service->profile()->GetPrefs()->GetBoolean(prefs::kSyncPasswords));
- args->SetBoolean(L"syncAutofill",
+ args->SetBoolean("syncAutofill",
service->profile()->GetPrefs()->GetBoolean(prefs::kSyncAutofill));
- args->SetBoolean(L"syncExtensions",
+ args->SetBoolean("syncExtensions",
service->profile()->GetPrefs()->GetBoolean(prefs::kSyncExtensions));
- args->SetBoolean(L"syncTypedUrls",
+ args->SetBoolean("syncSessions",
+ service->profile()->GetPrefs()->GetBoolean(prefs::kSyncSessions));
+ args->SetBoolean("syncTypedUrls",
service->profile()->GetPrefs()->GetBoolean(prefs::kSyncTypedUrls));
+ args->SetBoolean("syncApps",
+ service->profile()->GetPrefs()->GetBoolean(prefs::kSyncApps));
}
void SyncSetupFlow::GetDOMMessageHandlers(
@@ -425,7 +439,7 @@ void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) {
case SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR: {
DictionaryValue args;
SyncSetupFlow::GetArgsForChooseDataTypes(service_, &args);
- args.SetBoolean(L"was_aborted", true);
+ args.SetBoolean("was_aborted", true);
flow_handler_->ShowChooseDataTypes(args);
break;
}
@@ -434,7 +448,7 @@ void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) {
// TODO(sync): Update this error messaging.
DictionaryValue args;
SyncSetupFlow::GetArgsForGaiaLogin(service_, &args);
- args.SetInteger(L"error", GoogleServiceAuthError::CONNECTION_FAILED);
+ args.SetInteger("error", GoogleServiceAuthError::CONNECTION_FAILED);
flow_handler_->ShowGaiaLogin(args);
break;
}
diff --git a/chrome/browser/sync/sync_setup_flow.h b/chrome/browser/sync/sync_setup_flow.h
index c59c91a..6766963 100644
--- a/chrome/browser/sync/sync_setup_flow.h
+++ b/chrome/browser/sync/sync_setup_flow.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_
#define CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_
+#pragma once
#include <string>
#include <vector>
@@ -178,8 +179,8 @@ class FlowHandler : public DOMMessageHandler {
virtual void RegisterMessages();
// Callbacks from the page.
- void HandleSubmitAuth(const Value* value);
- void HandleChooseDataTypes(const Value* value);
+ void HandleSubmitAuth(const ListValue* args);
+ void HandleChooseDataTypes(const ListValue* args);
// These functions control which part of the HTML is visible.
void ShowGaiaLogin(const DictionaryValue& args);
diff --git a/chrome/browser/sync/sync_setup_wizard.cc b/chrome/browser/sync/sync_setup_wizard.cc
index 5a254dc..ffca308 100644
--- a/chrome/browser/sync/sync_setup_wizard.cc
+++ b/chrome/browser/sync/sync_setup_wizard.cc
@@ -9,8 +9,8 @@
#include "base/singleton.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
-#include "chrome/browser/google_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/google/google_util.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
@@ -70,48 +70,48 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
DictionaryValue localized_strings;
// Start by setting the per-locale URLs we show on the setup wizard.
- localized_strings.SetString(L"invalidpasswordhelpurl",
+ localized_strings.SetString("invalidpasswordhelpurl",
GetLocalizedUrl(kInvalidPasswordHelpUrl));
- localized_strings.SetString(L"cannotaccessaccounturl",
+ localized_strings.SetString("cannotaccessaccounturl",
GetLocalizedUrl(kCanNotAccessAccountUrl));
- localized_strings.SetString(L"createnewaccounturl",
+ localized_strings.SetString("createnewaccounturl",
GetLocalizedUrl(kCreateNewAccountUrl));
- localized_strings.SetString(L"settingupsync",
- l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP_SYNC));
- localized_strings.SetString(L"introduction",
- l10n_util::GetStringF(IDS_SYNC_LOGIN_INTRODUCTION,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
- localized_strings.SetString(L"signinprefix",
- l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_PREFIX));
- localized_strings.SetString(L"signinsuffix",
- l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_SUFFIX));
- localized_strings.SetString(L"cannotbeblank",
- l10n_util::GetString(IDS_SYNC_CANNOT_BE_BLANK));
- localized_strings.SetString(L"emaillabel",
- l10n_util::GetString(IDS_SYNC_LOGIN_EMAIL));
- localized_strings.SetString(L"passwordlabel",
- l10n_util::GetString(IDS_SYNC_LOGIN_PASSWORD));
- localized_strings.SetString(L"invalidcredentials",
- l10n_util::GetString(IDS_SYNC_INVALID_USER_CREDENTIALS));
- localized_strings.SetString(L"signin",
- l10n_util::GetString(IDS_SYNC_SIGNIN));
- localized_strings.SetString(L"couldnotconnect",
- l10n_util::GetString(IDS_SYNC_LOGIN_COULD_NOT_CONNECT));
- localized_strings.SetString(L"cannotaccessaccount",
- l10n_util::GetString(IDS_SYNC_CANNOT_ACCESS_ACCOUNT));
- localized_strings.SetString(L"createaccount",
- l10n_util::GetString(IDS_SYNC_CREATE_ACCOUNT));
- localized_strings.SetString(L"cancel",
- l10n_util::GetString(IDS_CANCEL));
- localized_strings.SetString(L"settingup",
- l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP));
- localized_strings.SetString(L"success",
- l10n_util::GetString(IDS_SYNC_SUCCESS));
- localized_strings.SetString(L"errorsigningin",
- l10n_util::GetString(IDS_SYNC_ERROR_SIGNING_IN));
- localized_strings.SetString(L"captchainstructions",
- l10n_util::GetString(IDS_SYNC_GAIA_CAPTCHA_INSTRUCTIONS));
+ localized_strings.SetString("settingupsync",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_SETTING_UP_SYNC));
+ localized_strings.SetString("introduction",
+ l10n_util::GetStringFUTF16(IDS_SYNC_LOGIN_INTRODUCTION,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ localized_strings.SetString("signinprefix",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_SIGNIN_PREFIX));
+ localized_strings.SetString("signinsuffix",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_SIGNIN_SUFFIX));
+ localized_strings.SetString("cannotbeblank",
+ l10n_util::GetStringUTF16(IDS_SYNC_CANNOT_BE_BLANK));
+ localized_strings.SetString("emaillabel",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_EMAIL));
+ localized_strings.SetString("passwordlabel",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_PASSWORD));
+ localized_strings.SetString("invalidcredentials",
+ l10n_util::GetStringUTF16(IDS_SYNC_INVALID_USER_CREDENTIALS));
+ localized_strings.SetString("signin",
+ l10n_util::GetStringUTF16(IDS_SYNC_SIGNIN));
+ localized_strings.SetString("couldnotconnect",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_COULD_NOT_CONNECT));
+ localized_strings.SetString("cannotaccessaccount",
+ l10n_util::GetStringUTF16(IDS_SYNC_CANNOT_ACCESS_ACCOUNT));
+ localized_strings.SetString("createaccount",
+ l10n_util::GetStringUTF16(IDS_SYNC_CREATE_ACCOUNT));
+ localized_strings.SetString("cancel",
+ l10n_util::GetStringUTF16(IDS_CANCEL));
+ localized_strings.SetString("settingup",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_SETTING_UP));
+ localized_strings.SetString("success",
+ l10n_util::GetStringUTF16(IDS_SYNC_SUCCESS));
+ localized_strings.SetString("errorsigningin",
+ l10n_util::GetStringUTF16(IDS_SYNC_ERROR_SIGNING_IN));
+ localized_strings.SetString("captchainstructions",
+ l10n_util::GetStringUTF16(IDS_SYNC_GAIA_CAPTCHA_INSTRUCTIONS));
static const base::StringPiece html(ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_GAIA_LOGIN_HTML));
SetFontAndTextDirection(&localized_strings);
@@ -119,39 +119,41 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
html, &localized_strings);
} else if (path_raw == kSyncChooseDataTypesPath) {
DictionaryValue localized_strings;
- localized_strings.SetString(L"choosedatatypesheader",
- l10n_util::GetString(IDS_SYNC_CHOOSE_DATATYPES_HEADER));
- localized_strings.SetString(L"choosedatatypesinstructions",
- l10n_util::GetStringF(IDS_SYNC_CHOOSE_DATATYPES_INSTRUCTIONS,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
- localized_strings.SetString(L"keepeverythingsynced",
- l10n_util::GetString(IDS_SYNC_EVERYTHING));
- localized_strings.SetString(L"choosedatatypes",
- l10n_util::GetString(IDS_SYNC_CHOOSE_DATATYPES));
- localized_strings.SetString(L"bookmarks",
- l10n_util::GetString(IDS_SYNC_DATATYPE_BOOKMARKS));
- localized_strings.SetString(L"preferences",
- l10n_util::GetString(IDS_SYNC_DATATYPE_PREFERENCES));
- localized_strings.SetString(L"autofill",
- l10n_util::GetString(IDS_SYNC_DATATYPE_AUTOFILL));
- localized_strings.SetString(L"themes",
- l10n_util::GetString(IDS_SYNC_DATATYPE_THEMES));
- localized_strings.SetString(L"passwords",
- l10n_util::GetString(IDS_SYNC_DATATYPE_PASSWORDS));
- localized_strings.SetString(L"extensions",
- l10n_util::GetString(IDS_SYNC_DATATYPE_EXTENSIONS));
- localized_strings.SetString(L"typedurls",
- l10n_util::GetString(IDS_SYNC_DATATYPE_TYPED_URLS));
- localized_strings.SetString(L"synczerodatatypeserror",
- l10n_util::GetString(IDS_SYNC_ZERO_DATA_TYPES_ERROR));
- localized_strings.SetString(L"setupabortederror",
- l10n_util::GetString(IDS_SYNC_SETUP_ABORTED_BY_PENDING_CLEAR));
- localized_strings.SetString(L"ok",
- l10n_util::GetString(IDS_OK));
- localized_strings.SetString(L"cancel",
- l10n_util::GetString(IDS_CANCEL));
- localized_strings.SetString(L"settingup",
- l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP));
+ localized_strings.SetString("choosedatatypesheader",
+ l10n_util::GetStringUTF16(IDS_SYNC_CHOOSE_DATATYPES_HEADER));
+ localized_strings.SetString("choosedatatypesinstructions",
+ l10n_util::GetStringFUTF16(IDS_SYNC_CHOOSE_DATATYPES_INSTRUCTIONS,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ localized_strings.SetString("keepeverythingsynced",
+ l10n_util::GetStringUTF16(IDS_SYNC_EVERYTHING));
+ localized_strings.SetString("choosedatatypes",
+ l10n_util::GetStringUTF16(IDS_SYNC_CHOOSE_DATATYPES));
+ localized_strings.SetString("bookmarks",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_BOOKMARKS));
+ localized_strings.SetString("preferences",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PREFERENCES));
+ localized_strings.SetString("autofill",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_AUTOFILL));
+ localized_strings.SetString("themes",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_THEMES));
+ localized_strings.SetString("passwords",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PASSWORDS));
+ localized_strings.SetString("extensions",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_EXTENSIONS));
+ localized_strings.SetString("typedurls",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TYPED_URLS));
+ localized_strings.SetString("apps",
+ l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_APPS));
+ localized_strings.SetString("synczerodatatypeserror",
+ l10n_util::GetStringUTF16(IDS_SYNC_ZERO_DATA_TYPES_ERROR));
+ localized_strings.SetString("setupabortederror",
+ l10n_util::GetStringUTF16(IDS_SYNC_SETUP_ABORTED_BY_PENDING_CLEAR));
+ localized_strings.SetString("ok",
+ l10n_util::GetStringUTF16(IDS_OK));
+ localized_strings.SetString("cancel",
+ l10n_util::GetStringUTF16(IDS_CANCEL));
+ localized_strings.SetString("settingup",
+ l10n_util::GetStringUTF16(IDS_SYNC_LOGIN_SETTING_UP));
static const base::StringPiece html(ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_SYNC_CHOOSE_DATATYPES_HTML));
SetFontAndTextDirection(&localized_strings);
@@ -159,15 +161,15 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
html, &localized_strings);
} else if (path_raw == kSyncSetupDonePath) {
DictionaryValue localized_strings;
- localized_strings.SetString(L"success",
- l10n_util::GetString(IDS_SYNC_SUCCESS));
- localized_strings.SetString(L"setupsummary",
- l10n_util::GetStringF(IDS_SYNC_SETUP_ALL_DONE,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
- localized_strings.SetString(L"firsttimesetupsummary",
- l10n_util::GetString(IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE));
- localized_strings.SetString(L"okay",
- l10n_util::GetString(IDS_SYNC_SETUP_OK_BUTTON_LABEL));
+ localized_strings.SetString("success",
+ l10n_util::GetStringUTF16(IDS_SYNC_SUCCESS));
+ localized_strings.SetString("setupsummary",
+ l10n_util::GetStringFUTF16(IDS_SYNC_SETUP_ALL_DONE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ localized_strings.SetString("firsttimesetupsummary",
+ l10n_util::GetStringUTF16(IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE));
+ localized_strings.SetString("okay",
+ l10n_util::GetStringUTF16(IDS_SYNC_SETUP_OK_BUTTON_LABEL));
static const base::StringPiece html(ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_SYNC_SETUP_DONE_HTML));
SetFontAndTextDirection(&localized_strings);
diff --git a/chrome/browser/sync/sync_setup_wizard.h b/chrome/browser/sync/sync_setup_wizard.h
index 9bb0bb0..e7d1a82 100644
--- a/chrome/browser/sync/sync_setup_wizard.h
+++ b/chrome/browser/sync/sync_setup_wizard.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_
#define CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_
+#pragma once
#include "base/basictypes.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc
index 02dd1df..484d376 100644
--- a/chrome/browser/sync/sync_setup_wizard_unittest.cc
+++ b/chrome/browser/sync/sync_setup_wizard_unittest.cc
@@ -7,13 +7,14 @@
#include "base/json/json_writer.h"
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/google_service_auth_error.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/browser_with_test_window_test.h"
#include "chrome/test/testing_profile.h"
@@ -31,7 +32,7 @@ typedef GoogleServiceAuthError AuthError;
class ProfileSyncServiceForWizardTest : public ProfileSyncService {
public:
ProfileSyncServiceForWizardTest(ProfileSyncFactory* factory, Profile* profile)
- : ProfileSyncService(factory, profile, false),
+ : ProfileSyncService(factory, profile, ""),
user_cancelled_dialog_(false) {
RegisterPreferences();
ResetTestStats();
@@ -164,8 +165,7 @@ class TestBrowserWindowForWizardTest : public TestBrowserWindow {
class SyncSetupWizardTest : public BrowserWithTestWindowTest {
public:
SyncSetupWizardTest()
- : ui_thread_(ChromeThread::UI, MessageLoop::current()),
- file_thread_(ChromeThread::FILE, MessageLoop::current()),
+ : file_thread_(ChromeThread::FILE, MessageLoop::current()),
test_window_(NULL),
wizard_(NULL) { }
virtual ~SyncSetupWizardTest() { }
@@ -190,7 +190,6 @@ class SyncSetupWizardTest : public BrowserWithTestWindowTest {
wizard_.reset();
}
- ChromeThread ui_thread_;
ChromeThread file_thread_;
TestBrowserWindowForWizardTest* test_window_;
scoped_ptr<SyncSetupWizard> wizard_;
@@ -250,15 +249,15 @@ TEST_F(SyncSetupWizardTest, InitialStepLogin) {
EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_);
dialog_args.Clear();
SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args);
- EXPECT_EQ(4U, dialog_args.size());
+ EXPECT_EQ(5U, dialog_args.size());
std::string iframe_to_show;
- dialog_args.GetString(L"iframeToShow", &iframe_to_show);
+ dialog_args.GetString("iframeToShow", &iframe_to_show);
EXPECT_EQ("login", iframe_to_show);
std::string actual_user;
- dialog_args.GetString(L"user", &actual_user);
+ dialog_args.GetString("user", &actual_user);
EXPECT_EQ(kTestUser, actual_user);
int error = -1;
- dialog_args.GetInteger(L"error", &error);
+ dialog_args.GetInteger("error", &error);
EXPECT_EQ(static_cast<int>(AuthError::INVALID_GAIA_CREDENTIALS), error);
service_->set_auth_state(kTestUser, AuthError::None());
@@ -268,14 +267,14 @@ TEST_F(SyncSetupWizardTest, InitialStepLogin) {
service_->set_auth_state(kTestUser, captcha_error);
wizard_->Step(SyncSetupWizard::GAIA_LOGIN);
SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args);
- EXPECT_EQ(4U, dialog_args.size());
- dialog_args.GetString(L"iframeToShow", &iframe_to_show);
+ EXPECT_EQ(5U, dialog_args.size());
+ dialog_args.GetString("iframeToShow", &iframe_to_show);
EXPECT_EQ("login", iframe_to_show);
std::string captcha_url;
- dialog_args.GetString(L"captchaUrl", &captcha_url);
+ dialog_args.GetString("captchaUrl", &captcha_url);
EXPECT_EQ(kTestCaptchaUrl, GURL(captcha_url).spec());
error = -1;
- dialog_args.GetInteger(L"error", &error);
+ dialog_args.GetInteger("error", &error);
EXPECT_EQ(static_cast<int>(AuthError::CAPTCHA_REQUIRED), error);
service_->set_auth_state(kTestUser, AuthError::None());
@@ -306,11 +305,12 @@ TEST_F(SyncSetupWizardTest, ChooseDataTypesSetsPrefs) {
data_type_choices += "\"syncBookmarks\":true,\"syncPreferences\":true,";
data_type_choices += "\"syncThemes\":false,\"syncPasswords\":false,";
data_type_choices += "\"syncAutofill\":false,\"syncExtensions\":false,";
- data_type_choices += "\"syncTypedUrls\":true}";
+ data_type_choices += "\"syncTypedUrls\":true,\"syncApps\":true,";
+ data_type_choices += "\"syncSessions\":false}";
data_type_choices_value.Append(new StringValue(data_type_choices));
- // Simulate the user choosing data types; bookmarks and prefs are on, the rest
- // are off.
+ // Simulate the user choosing data types; bookmarks, prefs, typed
+ // URLS, and apps are on, the rest are off.
test_window_->flow()->flow_handler_->HandleChooseDataTypes(
&data_type_choices_value);
EXPECT_TRUE(wizard_->IsVisible());
@@ -323,6 +323,7 @@ TEST_F(SyncSetupWizardTest, ChooseDataTypesSetsPrefs) {
EXPECT_EQ(service_->chosen_data_types_.count(syncable::AUTOFILL), 0U);
EXPECT_EQ(service_->chosen_data_types_.count(syncable::EXTENSIONS), 0U);
EXPECT_EQ(service_->chosen_data_types_.count(syncable::TYPED_URLS), 1U);
+ EXPECT_EQ(service_->chosen_data_types_.count(syncable::APPS), 1U);
test_window_->CloseDialog();
}
@@ -472,15 +473,15 @@ TEST_F(SyncSetupWizardTest, DiscreteRunGaiaLogin) {
wizard_->Step(SyncSetupWizard::GAIA_LOGIN);
EXPECT_TRUE(wizard_->IsVisible());
SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args);
- EXPECT_EQ(4U, dialog_args.size());
+ EXPECT_EQ(5U, dialog_args.size());
std::string iframe_to_show;
- dialog_args.GetString(L"iframeToShow", &iframe_to_show);
+ dialog_args.GetString("iframeToShow", &iframe_to_show);
EXPECT_EQ("login", iframe_to_show);
std::string actual_user;
- dialog_args.GetString(L"user", &actual_user);
+ dialog_args.GetString("user", &actual_user);
EXPECT_EQ(kTestUser, actual_user);
int error = -1;
- dialog_args.GetInteger(L"error", &error);
+ dialog_args.GetInteger("error", &error);
EXPECT_EQ(static_cast<int>(AuthError::INVALID_GAIA_CREDENTIALS), error);
service_->set_auth_state(kTestUser, AuthError::None());
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 4e2422f..914f918 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -6,10 +6,10 @@
#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/google_service_auth_error.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/options_window.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -27,7 +27,10 @@ void GetStatusLabelsForAuthError(const AuthError& auth_error,
string16* link_label) {
if (link_label)
link_label->assign(l10n_util::GetStringUTF16(IDS_SYNC_RELOGIN_LINK_LABEL));
- if (auth_error.state() == AuthError::INVALID_GAIA_CREDENTIALS) {
+ if (auth_error.state() == AuthError::INVALID_GAIA_CREDENTIALS ||
+ auth_error.state() == AuthError::ACCOUNT_DELETED ||
+ auth_error.state() == AuthError::ACCOUNT_DISABLED ||
+ auth_error.state() == AuthError::SERVICE_UNAVAILABLE) {
// If the user name is empty then the first login failed, otherwise the
// credentials are out-of-date.
if (service->GetAuthenticatedUsername().empty())
@@ -59,10 +62,9 @@ string16 GetSyncedStateStatusLabel(ProfileSyncService* service) {
if (user_name.empty())
return label;
- return l10n_util::GetStringFUTF16(
- IDS_SYNC_ACCOUNT_SYNCED_TO_USER_WITH_TIME,
- user_name,
- WideToUTF16(service->GetLastSyncedTimeString()));
+ return l10n_util::GetStringFUTF16(IDS_SYNC_ACCOUNT_SYNCED_TO_USER_WITH_TIME,
+ user_name,
+ service->GetLastSyncedTimeString());
}
// TODO(akalin): Write unit tests for these three functions below.
@@ -189,8 +191,8 @@ void OpenSyncMyBookmarksDialog(
if (service->HasSyncSetupCompleted()) {
ShowOptionsWindow(OPTIONS_PAGE_CONTENT, OPTIONS_GROUP_NONE, profile);
} else {
- service->EnableForUser(NULL);
- ProfileSyncService::SyncEvent(code);
+ service->ShowLoginDialog(NULL);
+ ProfileSyncService::SyncEvent(code); // UMA stats
}
}
diff --git a/chrome/browser/sync/sync_ui_util.h b/chrome/browser/sync/sync_ui_util.h
index 0b9483e..ce370af 100644
--- a/chrome/browser/sync/sync_ui_util.h
+++ b/chrome/browser/sync/sync_ui_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNC_UI_UTIL_H_
#define CHROME_BROWSER_SYNC_SYNC_UI_UTIL_H_
+#pragma once
#include "base/string16.h"
#include "chrome/browser/sync/profile_sync_service.h"
diff --git a/chrome/browser/sync/sync_ui_util_mac.h b/chrome/browser/sync/sync_ui_util_mac.h
index 65fba88..3a732b8 100644
--- a/chrome/browser/sync/sync_ui_util_mac.h
+++ b/chrome/browser/sync/sync_ui_util_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNC_UI_UTIL_MAC_H_
#define CHROME_BROWSER_SYNC_SYNC_UI_UTIL_MAC_H_
+#pragma once
#include "chrome/browser/sync/sync_ui_util.h"
diff --git a/chrome/browser/sync/syncable/blob.h b/chrome/browser/sync/syncable/blob.h
index bb0665e..54d1d00 100644
--- a/chrome/browser/sync/syncable/blob.h
+++ b/chrome/browser/sync/syncable/blob.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_BLOB_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_BLOB_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/sync/syncable/dir_open_result.h b/chrome/browser/sync/syncable/dir_open_result.h
index 0090236..f64c6a6 100644
--- a/chrome/browser/sync/syncable/dir_open_result.h
+++ b/chrome/browser/sync/syncable/dir_open_result.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_DIR_OPEN_RESULT_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_DIR_OPEN_RESULT_H_
+#pragma once
namespace syncable {
enum DirOpenResult { OPENED, // success.
diff --git a/chrome/browser/sync/syncable/directory_backing_store.cc b/chrome/browser/sync/syncable/directory_backing_store.cc
index b4de3f6..62b8faa 100644
--- a/chrome/browser/sync/syncable/directory_backing_store.cc
+++ b/chrome/browser/sync/syncable/directory_backing_store.cc
@@ -14,7 +14,11 @@
#include "base/file_util.h"
#include "base/hash_tables.h"
+#include "base/histogram.h"
#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/protocol/service_constants.h"
#include "chrome/browser/sync/protocol/sync.pb.h"
@@ -22,7 +26,7 @@
#include "chrome/browser/sync/syncable/syncable_columns.h"
#include "chrome/browser/sync/util/crypto_helpers.h"
#include "chrome/common/sqlite_utils.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
// Sometimes threads contend on the DB lock itself, especially when one thread
// is calling SaveChanges. In the worst case scenario, the user can put his
@@ -183,6 +187,14 @@ bool DirectoryBackingStore::OpenAndConfigureHandleHelper(
sqlite_utils::scoped_sqlite_db_ptr scoped_handle(*handle);
sqlite3_busy_timeout(scoped_handle.get(), std::numeric_limits<int>::max());
{
+ string integrity_error;
+ bool is_ok = CheckIntegrity(scoped_handle.get(), &integrity_error);
+ if (!is_ok) {
+ LOG(ERROR) << "Integrity check failed: " << integrity_error;
+ return false;
+ }
+ }
+ {
SQLStatement statement;
statement.prepare(scoped_handle.get(), "PRAGMA fullfsync = 1");
if (SQLITE_DONE != statement.step()) {
@@ -214,35 +226,93 @@ bool DirectoryBackingStore::OpenAndConfigureHandleHelper(
return false;
}
+bool DirectoryBackingStore::CheckIntegrity(sqlite3* handle, string* error)
+ const {
+ SQLStatement statement;
+ statement.prepare(handle, "PRAGMA integrity_check(1)");
+ if (SQLITE_ROW != statement.step()) {
+ *error = sqlite3_errmsg(handle);
+ return false;
+ }
+ string integrity_result = statement.column_text(0);
+ if (integrity_result != "ok") {
+ *error = integrity_result;
+ return false;
+ }
+ return true;
+}
+
+DirOpenResult DirectoryBackingStore::DoLoad(MetahandlesIndex* entry_bucket,
+ Directory::KernelLoadInfo* kernel_load_info) {
+ {
+ DirOpenResult result = InitializeTables();
+ if (result != OPENED)
+ return result;
+ }
+
+ if (!DropDeletedEntries())
+ return FAILED_DATABASE_CORRUPT;
+ if (!LoadEntries(entry_bucket))
+ return FAILED_DATABASE_CORRUPT;
+ if (!LoadInfo(kernel_load_info))
+ return FAILED_DATABASE_CORRUPT;
+
+ return OPENED;
+}
+
DirOpenResult DirectoryBackingStore::Load(MetahandlesIndex* entry_bucket,
Directory::KernelLoadInfo* kernel_load_info) {
+
+ // Open database handle.
if (!BeginLoad())
return FAILED_OPEN_DATABASE;
- DirOpenResult result = InitializeTables();
- if (OPENED != result)
- return result;
+ // Load data from the database.
+ DirOpenResult result = DoLoad(entry_bucket, kernel_load_info);
- if (!DropDeletedEntries() ||
- !LoadEntries(entry_bucket) ||
- !LoadInfo(kernel_load_info)) {
- return FAILED_DATABASE_CORRUPT;
- }
+ // Clean up partial results after failure.
+ if (result != OPENED)
+ STLDeleteElements(entry_bucket);
+ // Close database handle.
EndLoad();
- return OPENED;
+
+ return result;
}
bool DirectoryBackingStore::BeginLoad() {
DCHECK(load_dbhandle_ == NULL);
bool ret = OpenAndConfigureHandleHelper(&load_dbhandle_);
if (ret)
- return ret;
+ return true;
// Something's gone wrong. Nuke the database and try again.
+ using ::operator<<; // For string16.
LOG(ERROR) << "Sync database " << backing_filepath_.value()
<< " corrupt. Deleting and recreating.";
file_util::Delete(backing_filepath_, false);
- return OpenAndConfigureHandleHelper(&load_dbhandle_);
+ bool failed_again = !OpenAndConfigureHandleHelper(&load_dbhandle_);
+
+ // Using failed_again here lets us distinguish from cases where corruption
+ // occurred even when re-opening a fresh directory (they'll go in a separate
+ // double weight histogram bucket). Failing twice in a row means we disable
+ // sync, so it's useful to see this number separately.
+ int bucket = failed_again ? 2 : 1;
+#if defined(OS_WIN)
+ UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedWin", bucket);
+#elif defined(OS_MACOSX)
+ UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedMac", bucket);
+#else
+ UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedNotWinMac", bucket);
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedLinux", bucket);
+#elif defined(OS_CHROMEOS)
+ UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedCros", bucket);
+#else
+ UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedOther", bucket);
+#endif // OS_LINUX && !OS_CHROMEOS
+#endif // OS_WIN
+ return !failed_again;
}
void DirectoryBackingStore::EndLoad() {
@@ -266,7 +336,7 @@ bool DirectoryBackingStore::DeleteEntries(const MetahandleSet& handles) {
++it) {
if (it != handles.begin())
query.append(",");
- query.append(Int64ToString(*it));
+ query.append(base::Int64ToString(*it));
}
query.append(")");
SQLStatement statement;
@@ -900,7 +970,7 @@ int DirectoryBackingStore::CreateTables() {
sqlite3* DirectoryBackingStore::LazyGetSaveHandle() {
if (!save_dbhandle_ && !OpenAndConfigureHandleHelper(&save_dbhandle_)) {
- DCHECK(FALSE) << "Unable to open handle for saving";
+ NOTREACHED() << "Unable to open handle for saving";
return NULL;
}
return save_dbhandle_;
diff --git a/chrome/browser/sync/syncable/directory_backing_store.h b/chrome/browser/sync/syncable/directory_backing_store.h
index 36322e8..f4c3c18 100644
--- a/chrome/browser/sync/syncable/directory_backing_store.h
+++ b/chrome/browser/sync/syncable/directory_backing_store.h
@@ -1,11 +1,11 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_BACKING_STORE_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_BACKING_STORE_H_
+#pragma once
-#include <set>
#include <string>
#include "base/file_path.h"
@@ -122,6 +122,8 @@ class DirectoryBackingStore {
// Initialize and destroy load_dbhandle_. Broken out for testing.
bool BeginLoad();
void EndLoad();
+ DirOpenResult DoLoad(MetahandlesIndex* entry_bucket,
+ Directory::KernelLoadInfo* kernel_load_info);
// Close save_dbhandle_. Broken out for testing.
void EndSave();
@@ -143,6 +145,11 @@ class DirectoryBackingStore {
static ModelType ModelIdToModelTypeEnum(const string& model_id);
static string ModelTypeEnumToModelId(ModelType model_type);
+ // Runs an integrity check on the current database. If the
+ // integrity check fails, false is returned and error is populated
+ // with an error message.
+ bool CheckIntegrity(sqlite3* handle, string* error) const;
+
// Migration utilities.
bool AddColumn(const ColumnSpec* column);
bool RefreshColumns();
diff --git a/chrome/browser/sync/syncable/directory_backing_store_unittest.cc b/chrome/browser/sync/syncable/directory_backing_store_unittest.cc
index b1f5dc9..c158f9a 100644
--- a/chrome/browser/sync/syncable/directory_backing_store_unittest.cc
+++ b/chrome/browser/sync/syncable/directory_backing_store_unittest.cc
@@ -8,12 +8,12 @@
#include "app/sql/connection.h"
#include "app/sql/statement.h"
-#include "app/sql/transaction.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/scoped_ptr.h"
#include "base/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/protocol/sync.pb.h"
#include "chrome/browser/sync/syncable/directory_backing_store.h"
@@ -773,7 +773,7 @@ TEST_F(DirectoryBackingStoreTest, MigrateVersion70To71) {
"initial_sync_ended, last_download_timestamp FROM models"));
ASSERT_TRUE(s.Step());
std::string model_id = s.ColumnString(0);
- EXPECT_EQ("C2881000", HexEncode(model_id.data(), model_id.size()))
+ EXPECT_EQ("C2881000", base::HexEncode(model_id.data(), model_id.size()))
<< "Model ID is expected to be the empty BookmarkSpecifics proto.";
EXPECT_EQ(true, s.ColumnBool(1));
EXPECT_EQ(694, s.ColumnInt64(2));
@@ -879,6 +879,7 @@ TEST_P(MigrationTest, ToCurrentVersion) {
}
MetahandlesIndex index;
+ STLElementDeleter<MetahandlesIndex> index_deleter(&index);
dbs->LoadEntries(&index);
dbs->EndLoad();
@@ -1004,8 +1005,6 @@ TEST_P(MigrationTest, ToCurrentVersion) {
ASSERT_EQ(14, (*it)->ref(META_HANDLE));
ASSERT_TRUE(++it == index.end());
-
- STLDeleteElements(&index);
}
INSTANTIATE_TEST_CASE_P(DirectoryBackingStore, MigrationTest,
@@ -1048,8 +1047,8 @@ TEST_F(DirectoryBackingStoreTest, DeleteEntries) {
scoped_ptr<DirectoryBackingStore> dbs(
new DirectoryBackingStore(GetUsername(), GetDatabasePath()));
dbs->BeginLoad();
-
MetahandlesIndex index;
+ STLElementDeleter<MetahandlesIndex> index_deleter(&index);
dbs->LoadEntries(&index);
size_t initial_size = index.size();
ASSERT_LT(0U, initial_size) << "Test requires entries to delete.";
@@ -1058,7 +1057,7 @@ TEST_F(DirectoryBackingStoreTest, DeleteEntries) {
to_delete.insert(first_to_die);
EXPECT_TRUE(dbs->DeleteEntries(to_delete));
- index.clear();
+ STLDeleteElements(&index);
dbs->LoadEntries(&index);
EXPECT_EQ(initial_size - 1, index.size());
@@ -1080,7 +1079,7 @@ TEST_F(DirectoryBackingStoreTest, DeleteEntries) {
EXPECT_TRUE(dbs->DeleteEntries(to_delete));
- index.clear();
+ STLDeleteElements(&index);
dbs->LoadEntries(&index);
EXPECT_EQ(0U, index.size());
diff --git a/chrome/browser/sync/syncable/directory_event.h b/chrome/browser/sync/syncable/directory_event.h
index fd25c88..3f91679 100644
--- a/chrome/browser/sync/syncable/directory_event.h
+++ b/chrome/browser/sync/syncable/directory_event.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_EVENT_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_EVENT_H_
+#pragma once
namespace syncable {
diff --git a/chrome/browser/sync/syncable/directory_manager.cc b/chrome/browser/sync/syncable/directory_manager.cc
index 0719c67..fbdeb46 100644
--- a/chrome/browser/sync/syncable/directory_manager.cc
+++ b/chrome/browser/sync/syncable/directory_manager.cc
@@ -54,17 +54,6 @@ bool DirectoryManager::Open(const std::string& name) {
bool was_open = false;
const DirOpenResult result = OpenImpl(name,
GetSyncDataDatabasePath(), &was_open);
- if (!was_open) {
- DirectoryManagerEvent event;
- event.dirname = name;
- if (syncable::OPENED == result) {
- event.what_happened = DirectoryManagerEvent::OPENED;
- } else {
- event.what_happened = DirectoryManagerEvent::OPEN_FAILED;
- event.error = result;
- }
- channel_->NotifyListeners(event);
- }
return syncable::OPENED == result;
}
diff --git a/chrome/browser/sync/syncable/directory_manager.h b/chrome/browser/sync/syncable/directory_manager.h
index 103ec30..0c0b55d 100644
--- a/chrome/browser/sync/syncable/directory_manager.h
+++ b/chrome/browser/sync/syncable/directory_manager.h
@@ -11,11 +11,11 @@
// Directory objects everywhere.
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_MANAGER_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_DIRECTORY_MANAGER_H_
+#pragma once
#include <string>
#include <vector>
-#include "base/atomicops.h"
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/lock.h"
@@ -23,7 +23,6 @@
#include "chrome/browser/sync/syncable/path_name_cmp.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/util/cryptographer.h"
-#include "chrome/browser/sync/util/sync_types.h"
#include "chrome/common/deprecated/event_sys.h"
namespace sync_api { class BaseTransaction; }
@@ -32,14 +31,11 @@ namespace syncable {
struct DirectoryManagerEvent {
enum {
- OPEN_FAILED,
- OPENED,
CLOSED,
CLOSED_ALL,
SHUTDOWN,
} what_happened;
std::string dirname;
- DirOpenResult error; // Only for OPEN_FAILED.
typedef DirectoryManagerEvent EventType;
static inline bool IsChannelShutdownEvent(const EventType& event) {
return SHUTDOWN == event.what_happened;
diff --git a/chrome/browser/sync/syncable/model_type.cc b/chrome/browser/sync/syncable/model_type.cc
index 4c40498..5a06be8 100644
--- a/chrome/browser/sync/syncable/model_type.cc
+++ b/chrome/browser/sync/syncable/model_type.cc
@@ -5,12 +5,14 @@
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/engine/syncproto.h"
+#include "chrome/browser/sync/protocol/app_specifics.pb.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#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/sync.pb.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
@@ -44,6 +46,12 @@ void AddDefaultExtensionValue(syncable::ModelType datatype,
case NIGORI:
specifics->MutableExtension(sync_pb::nigori);
break;
+ case SESSIONS:
+ specifics->MutableExtension(sync_pb::session);
+ break;
+ case APPS:
+ specifics->MutableExtension(sync_pb::app);
+ break;
default:
NOTREACHED() << "No known extension for model type.";
}
@@ -105,6 +113,12 @@ ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
if (specifics.HasExtension(sync_pb::nigori))
return NIGORI;
+ if (specifics.HasExtension(sync_pb::app))
+ return APPS;
+
+ if (specifics.HasExtension(sync_pb::session))
+ return SESSIONS;
+
return UNSPECIFIED;
}
@@ -126,6 +140,10 @@ std::string ModelTypeToString(ModelType model_type) {
return "Extensions";
case NIGORI:
return "Encryption keys";
+ case SESSIONS:
+ return "Sessions";
+ case APPS:
+ return "Apps";
default:
NOTREACHED() << "No known extension for model type.";
return "INVALID";
@@ -143,6 +161,12 @@ const char kThemeNotificationType[] = "THEME";
const char kTypedUrlNotificationType[] = "TYPED_URL";
const char kExtensionNotificationType[] = "EXTENSION";
const char kNigoriNotificationType[] = "NIGORI";
+const char kAppNotificationType[] = "APP";
+const char kSessionNotificationType[] = "SESSION";
+// 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.
+const char kUnknownNotificationType[] = "UNKNOWN";
} // namespace
bool RealModelTypeToNotificationType(ModelType model_type,
@@ -172,6 +196,18 @@ bool RealModelTypeToNotificationType(ModelType model_type,
case NIGORI:
*notification_type = kNigoriNotificationType;
return true;
+ case APPS:
+ *notification_type = kAppNotificationType;
+ return true;
+ case SESSIONS:
+ *notification_type = kSessionNotificationType;
+ 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
+ // anymore.
+ case UNSPECIFIED:
+ *notification_type = kUnknownNotificationType;
+ return true;
default:
break;
}
@@ -205,6 +241,19 @@ bool NotificationTypeToRealModelType(const std::string& notification_type,
} else if (notification_type == kNigoriNotificationType) {
*model_type = NIGORI;
return true;
+ } else if (notification_type == kAppNotificationType) {
+ *model_type = APPS;
+ return true;
+ } else if (notification_type == kSessionNotificationType) {
+ *model_type = SESSIONS;
+ 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
+ // anymore.
+ *model_type = UNSPECIFIED;
+ return true;
}
*model_type = UNSPECIFIED;
return false;
diff --git a/chrome/browser/sync/syncable/model_type.h b/chrome/browser/sync/syncable/model_type.h
index 5c34fb8..077d243 100644
--- a/chrome/browser/sync/syncable/model_type.h
+++ b/chrome/browser/sync/syncable/model_type.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_MODEL_TYPE_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_MODEL_TYPE_H_
+#pragma once
#include <bitset>
#include <set>
@@ -53,10 +54,14 @@ enum ModelType {
THEMES,
// A typed_url folder or a typed_url object.
TYPED_URLS,
- // A extension folder or a extension object.
+ // An extension folder or an extension object.
EXTENSIONS,
// An object represeting a set of Nigori keys.
NIGORI,
+ // An object representing a browser session.
+ SESSIONS,
+ // An app folder or an app object.
+ APPS,
MODEL_TYPE_COUNT,
};
diff --git a/chrome/browser/sync/syncable/path_name_cmp.h b/chrome/browser/sync/syncable/path_name_cmp.h
index 6c2e138..d89441e 100644
--- a/chrome/browser/sync/syncable/path_name_cmp.h
+++ b/chrome/browser/sync/syncable/path_name_cmp.h
@@ -4,11 +4,10 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_PATH_NAME_CMP_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_PATH_NAME_CMP_H_
+#pragma once
#include <string>
-#include "chrome/browser/sync/util/sync_types.h"
-
namespace syncable {
struct LessPathNames {
diff --git a/chrome/browser/sync/syncable/syncable-inl.h b/chrome/browser/sync/syncable/syncable-inl.h
index 1a34325..79845cf 100644
--- a/chrome/browser/sync/syncable/syncable-inl.h
+++ b/chrome/browser/sync/syncable/syncable-inl.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_INL_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_INL_H_
+#pragma once
#include "chrome/common/sqlite_utils.h"
diff --git a/chrome/browser/sync/syncable/syncable.cc b/chrome/browser/sync/syncable/syncable.cc
index a2a9a98..d1fd9d6 100644
--- a/chrome/browser/sync/syncable/syncable.cc
+++ b/chrome/browser/sync/syncable/syncable.cc
@@ -31,7 +31,9 @@
#include "base/logging.h"
#include "base/perftimer.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stl_util-inl.h"
#include "base/time.h"
#include "chrome/browser/sync/engine/syncer.h"
#include "chrome/browser/sync/engine/syncer_util.h"
@@ -82,7 +84,7 @@ int64 Now() {
LARGE_INTEGER n;
memcpy(&n, &filetime, sizeof(filetime));
return n.QuadPart;
-#elif defined(OS_LINUX) || defined(OS_MACOSX)
+#elif defined(OS_POSIX)
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64>(tv.tv_sec);
@@ -183,10 +185,6 @@ Directory::Kernel::Kernel(const FilePath& db_path,
next_metahandle(info.max_metahandle + 1) {
}
-inline void DeleteEntry(EntryKernel* kernel) {
- delete kernel;
-}
-
void Directory::Kernel::AddRef() {
base::subtle::NoBarrier_AtomicIncrement(&refcount, 1);
}
@@ -207,7 +205,7 @@ Directory::Kernel::~Kernel() {
delete parent_id_child_index;
delete client_tag_index;
delete ids_index;
- for_each(metahandles_index->begin(), metahandles_index->end(), DeleteEntry);
+ STLDeleteElements(metahandles_index);
delete metahandles_index;
}
@@ -339,7 +337,7 @@ EntryKernel* Directory::GetEntryByHandle(const int64 metahandle,
// Look up in memory
kernel_->needle.put(META_HANDLE, metahandle);
MetahandlesIndex::iterator found =
- kernel_->metahandles_index->find(&kernel_->needle);
+ kernel_->metahandles_index->find(&kernel_->needle);
if (found != kernel_->metahandles_index->end()) {
// Found it in memory. Easy.
return *found;
@@ -630,17 +628,19 @@ void Directory::PurgeEntriesWithTypeIn(const std::set<ModelType>& types) {
kernel_->metahandles_to_purge->insert(handle);
size_t num_erased = 0;
- num_erased = kernel_->ids_index->erase(*it);
+ EntryKernel* entry = *it;
+ num_erased = kernel_->ids_index->erase(entry);
DCHECK_EQ(1u, num_erased);
- num_erased = kernel_->client_tag_index->erase(*it);
- DCHECK_EQ((*it)->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased);
+ num_erased = kernel_->client_tag_index->erase(entry);
+ DCHECK_EQ(entry->ref(UNIQUE_CLIENT_TAG).empty(), !num_erased);
num_erased = kernel_->unsynced_metahandles->erase(handle);
- DCHECK_EQ((*it)->ref(IS_UNSYNCED), num_erased > 0);
+ DCHECK_EQ(entry->ref(IS_UNSYNCED), num_erased > 0);
num_erased = kernel_->unapplied_update_metahandles->erase(handle);
- DCHECK_EQ((*it)->ref(IS_UNAPPLIED_UPDATE), num_erased > 0);
- num_erased = kernel_->parent_id_child_index->erase(*it);
- DCHECK_EQ((*it)->ref(IS_DEL), !num_erased);
+ DCHECK_EQ(entry->ref(IS_UNAPPLIED_UPDATE), num_erased > 0);
+ num_erased = kernel_->parent_id_child_index->erase(entry);
+ DCHECK_EQ(entry->ref(IS_DEL), !num_erased);
kernel_->metahandles_index->erase(it++);
+ delete entry;
} else {
++it;
}
@@ -963,6 +963,19 @@ BaseTransaction::BaseTransaction(Directory* directory, const char* name,
BaseTransaction::~BaseTransaction() {}
void BaseTransaction::UnlockAndLog(OriginalEntries* originals_arg) {
+ // Triggers the CALCULATE_CHANGES and TRANSACTION_ENDING events while
+ // holding dir_kernel_'s transaction_mutex and changes_channel mutex.
+ // Releases all mutexes upon completion.
+ if (!NotifyTransactionChangingAndEnding(originals_arg)) {
+ return;
+ }
+
+ // Triggers the TRANSACTION_COMPLETE event (and does not hold any mutexes).
+ NotifyTransactionComplete();
+}
+
+bool BaseTransaction::NotifyTransactionChangingAndEnding(
+ OriginalEntries* originals_arg) {
dirkernel_->transaction_mutex.AssertAcquired();
scoped_ptr<OriginalEntries> originals(originals_arg);
@@ -975,26 +988,37 @@ void BaseTransaction::UnlockAndLog(OriginalEntries* originals_arg) {
if (NULL == originals.get() || originals->empty()) {
dirkernel_->transaction_mutex.Release();
- return;
+ return false;
}
- AutoLock scoped_lock(dirkernel_->changes_channel_mutex);
- // Tell listeners to calculate changes while we still have the mutex.
- DirectoryChangeEvent event = { DirectoryChangeEvent::CALCULATE_CHANGES,
- originals.get(), this, writer_ };
- dirkernel_->changes_channel.Notify(event);
- // Necessary for reads to be performed prior to transaction mutex release.
- // Allows the listener to use the current transaction to perform reads.
- DirectoryChangeEvent ending_event =
- { DirectoryChangeEvent::TRANSACTION_ENDING,
- NULL, this, INVALID };
- dirkernel_->changes_channel.Notify(ending_event);
+ {
+ // Scoped_lock is only active through the calculate_changes and
+ // transaction_ending events.
+ AutoLock scoped_lock(dirkernel_->changes_channel_mutex);
+
+ // Tell listeners to calculate changes while we still have the mutex.
+ DirectoryChangeEvent event = { DirectoryChangeEvent::CALCULATE_CHANGES,
+ originals.get(), this, writer_ };
+ dirkernel_->changes_channel.Notify(event);
+
+ // Necessary for reads to be performed prior to transaction mutex release.
+ // Allows the listener to use the current transaction to perform reads.
+ DirectoryChangeEvent ending_event =
+ { DirectoryChangeEvent::TRANSACTION_ENDING,
+ NULL, this, INVALID };
+ dirkernel_->changes_channel.Notify(ending_event);
- dirkernel_->transaction_mutex.Release();
+ dirkernel_->transaction_mutex.Release();
+ }
- // Directly after transaction mutex release, but lock on changes channel.
- // You cannot be re-entrant to a transaction in this handler.
+ return true;
+}
+
+void BaseTransaction::NotifyTransactionComplete() {
+ // Transaction is no longer holding any locks/mutexes, notify that we're
+ // complete (and commit any outstanding changes that should not be performed
+ // while holding mutexes).
DirectoryChangeEvent complete_event =
{ DirectoryChangeEvent::TRANSACTION_COMPLETE,
NULL, NULL, INVALID };
@@ -1442,7 +1466,7 @@ Id Directory::NextId() {
kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
}
DCHECK_LT(result, 0);
- return Id::CreateFromClientString(Int64ToString(result));
+ return Id::CreateFromClientString(base::Int64ToString(result));
}
Id Directory::GetChildWithNullIdField(IdField field,
@@ -1506,7 +1530,6 @@ namespace {
} separator;
class DumpColon {
} colon;
-} // namespace
inline FastDump& operator<<(FastDump& dump, const DumpSeparator&) {
dump.out_->sputn(", ", 2);
@@ -1517,26 +1540,13 @@ inline FastDump& operator<<(FastDump& dump, const DumpColon&) {
dump.out_->sputn(": ", 2);
return dump;
}
+} // namespace
+
+namespace syncable {
-std::ostream& operator<<(std::ostream& stream, const syncable::Entry& entry) {
+std::ostream& operator<<(std::ostream& stream, const Entry& entry) {
// Using ostreams directly here is dreadfully slow, because a mutex is
// acquired for every <<. Users noticed it spiking CPU.
- using syncable::BEGIN_FIELDS;
- using syncable::BIT_FIELDS_END;
- using syncable::BIT_TEMPS_BEGIN;
- using syncable::BIT_TEMPS_END;
- using syncable::BitField;
- using syncable::BitTemp;
- using syncable::EntryKernel;
- using syncable::ID_FIELDS_END;
- using syncable::INT64_FIELDS_END;
- using syncable::IdField;
- using syncable::Int64Field;
- using syncable::PROTO_FIELDS_END;
- using syncable::ProtoField;
- using syncable::STRING_FIELDS_END;
- using syncable::StringField;
- using syncable::g_metas_columns;
int i;
FastDump s(&stream);
@@ -1572,17 +1582,19 @@ std::ostream& operator<<(std::ostream& stream, const syncable::Entry& entry) {
return stream;
}
-std::ostream& operator<<(std::ostream& s, const syncable::Blob& blob) {
- for (syncable::Blob::const_iterator i = blob.begin(); i != blob.end(); ++i)
+std::ostream& operator<<(std::ostream& s, const Blob& blob) {
+ for (Blob::const_iterator i = blob.begin(); i != blob.end(); ++i)
s << std::hex << std::setw(2)
<< std::setfill('0') << static_cast<unsigned int>(*i);
return s << std::dec;
}
-FastDump& operator<<(FastDump& dump, const syncable::Blob& blob) {
+FastDump& operator<<(FastDump& dump, const Blob& blob) {
if (blob.empty())
return dump;
- string buffer(HexEncode(&blob[0], blob.size()));
+ string buffer(base::HexEncode(&blob[0], blob.size()));
dump.out_->sputn(buffer.c_str(), buffer.size());
return dump;
}
+
+} // namespace syncable
diff --git a/chrome/browser/sync/syncable/syncable.h b/chrome/browser/sync/syncable/syncable.h
index 291e798..7cdae1c 100644
--- a/chrome/browser/sync/syncable/syncable.h
+++ b/chrome/browser/sync/syncable/syncable.h
@@ -4,12 +4,12 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_
+#pragma once
#include <algorithm>
#include <bitset>
#include <iosfwd>
#include <limits>
-#include <map>
#include <set>
#include <string>
#include <vector>
@@ -29,7 +29,6 @@
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/util/channel.h"
#include "chrome/browser/sync/util/dbgq.h"
-#include "chrome/browser/sync/util/sync_types.h"
#include "chrome/common/deprecated/event_sys.h"
struct PurgeInfo;
@@ -42,11 +41,8 @@ class ReadNode;
namespace syncable {
class Entry;
-}
-
-std::ostream& operator<<(std::ostream& s, const syncable::Entry& e);
-namespace syncable {
+std::ostream& operator<<(std::ostream& s, const Entry& e);
class DirectoryBackingStore;
@@ -343,7 +339,7 @@ struct EntryKernel {
// A read-only meta entry.
class Entry {
friend class Directory;
- friend std::ostream& ::operator << (std::ostream& s, const Entry& e);
+ friend std::ostream& operator << (std::ostream& s, const Entry& e);
public:
// After constructing, you must check good() to test whether the Get
@@ -425,7 +421,9 @@ class Entry {
friend class sync_api::ReadNode;
void* operator new(size_t size) { return (::operator new)(size); }
- inline Entry(BaseTransaction* trans) : basetrans_(trans) { }
+ inline Entry(BaseTransaction* trans)
+ : basetrans_(trans),
+ kernel_(NULL) { }
protected:
@@ -1055,6 +1053,8 @@ class BaseTransaction {
const char* source_file, int line, WriterTag writer);
void UnlockAndLog(OriginalEntries* entries);
+ bool NotifyTransactionChangingAndEnding(OriginalEntries* entries);
+ virtual void NotifyTransactionComplete();
Directory* const directory_;
Directory::Kernel* const dirkernel_; // for brevity
diff --git a/chrome/browser/sync/syncable/syncable_changes_version.h b/chrome/browser/sync/syncable/syncable_changes_version.h
index 26a5eb8..51cd3f8 100644
--- a/chrome/browser/sync/syncable/syncable_changes_version.h
+++ b/chrome/browser/sync/syncable/syncable_changes_version.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_CHANGES_VERSION_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_CHANGES_VERSION_H_
+#pragma once
namespace syncable {
diff --git a/chrome/browser/sync/syncable/syncable_columns.h b/chrome/browser/sync/syncable/syncable_columns.h
index 398a00f..94bd0ac 100644
--- a/chrome/browser/sync/syncable/syncable_columns.h
+++ b/chrome/browser/sync/syncable/syncable_columns.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_COLUMNS_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_COLUMNS_H_
+#pragma once
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/syncable/syncable_changes_version.h"
diff --git a/chrome/browser/sync/syncable/syncable_id.cc b/chrome/browser/sync/syncable/syncable_id.cc
index 1aa2193..60cf8c9 100644
--- a/chrome/browser/sync/syncable/syncable_id.cc
+++ b/chrome/browser/sync/syncable/syncable_id.cc
@@ -13,21 +13,18 @@ using std::string;
namespace syncable {
const Id kNullId; // Currently == root.
-} // namespace syncable
-ostream& operator << (ostream& out, const syncable::Id& id) {
+ostream& operator<<(ostream& out, const Id& id) {
out << id.s_;
return out;
}
using browser_sync::FastDump;
-FastDump& operator << (FastDump& dump, const syncable::Id& id) {
+FastDump& operator<<(FastDump& dump, const Id& id) {
dump.out_->sputn(id.s_.data(), id.s_.size());
return dump;
}
-namespace syncable {
-
string Id::GetServerId() const {
// Currently root is the string "0". We need to decide on a true value.
// "" would be convenient here, as the IsRoot call would not be needed.
diff --git a/chrome/browser/sync/syncable/syncable_id.h b/chrome/browser/sync/syncable/syncable_id.h
index ed8a2e5..148fe21 100644
--- a/chrome/browser/sync/syncable/syncable_id.h
+++ b/chrome/browser/sync/syncable/syncable_id.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_ID_H_
#define CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_ID_H_
+#pragma once
#include <iosfwd>
#include <limits>
@@ -12,7 +13,6 @@
#include "base/hash_tables.h"
#include "chrome/browser/sync/util/fast_dump.h"
-#include "chrome/browser/sync/util/sync_types.h"
extern "C" {
struct sqlite3;
@@ -28,12 +28,11 @@ class Id;
class MockConnectionManager;
class SQLStatement;
-std::ostream& operator << (std::ostream& out, const syncable::Id& id);
-browser_sync::FastDump& operator <<
- (browser_sync::FastDump& out, const syncable::Id& id);
-
namespace syncable {
+std::ostream& operator<<(std::ostream& out, const Id& id);
+browser_sync::FastDump& operator<<(browser_sync::FastDump& out, const Id& id);
+
// For historical reasons, 3 concepts got everloaded into the Id:
// 1. A unique, opaque identifier for the object.
// 2. Flag specifing whether server know about this object.
@@ -49,10 +48,9 @@ class Id {
syncable::EntryKernel** kernel);
friend struct syncable::IdRowTraits;
friend int BindFields(const EntryKernel& entry, SQLStatement* statement);
- friend std::ostream& ::operator << (std::ostream& out,
- const syncable::Id& id);
- friend browser_sync::FastDump& ::operator <<
- (browser_sync::FastDump& out, const syncable::Id& id);
+ friend std::ostream& operator<<(std::ostream& out, const Id& id);
+ friend browser_sync::FastDump& operator<<
+ (browser_sync::FastDump& out, const Id& id);
friend class MockConnectionManager;
friend class SyncableIdTest;
public:
diff --git a/chrome/browser/sync/syncable/syncable_unittest.cc b/chrome/browser/sync/syncable/syncable_unittest.cc
index 6c5ceff..6dfe793 100644
--- a/chrome/browser/sync/syncable/syncable_unittest.cc
+++ b/chrome/browser/sync/syncable/syncable_unittest.cc
@@ -20,13 +20,13 @@
#include <sys/times.h>
#endif // !defined(OS_WIN)
-#include "base/at_exit.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/platform_thread.h"
#include "base/scoped_ptr.h"
#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/syncable/directory_backing_store.h"
@@ -35,7 +35,7 @@
#include "chrome/test/sync/engine/test_id_factory.h"
#include "chrome/test/sync/engine/test_syncable_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
using browser_sync::TestIdFactory;
using std::cout;
diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h
index 700ab4e..3cad8dc 100644
--- a/chrome/browser/sync/test_profile_sync_service.h
+++ b/chrome/browser/sync/test_profile_sync_service.h
@@ -4,20 +4,35 @@
#ifndef CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
#define CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
+#pragma once
#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"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/data_type_manager_impl.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
+#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"
+using browser_sync::ModelSafeRoutingInfo;
+using browser_sync::sessions::ErrorCounters;
+using browser_sync::sessions::SyncerStatus;
+using browser_sync::sessions::SyncSessionSnapshot;
+using sync_api::UserShare;
+using syncable::DirectoryManager;
+using syncable::ModelType;
+using syncable::ScopedDirLookup;
+
ACTION_P(CallOnPaused, core) {
core->OnPaused();
};
@@ -30,23 +45,35 @@ ACTION(ReturnNewDataTypeManager) {
return new browser_sync::DataTypeManagerImpl(arg0, arg1);
}
+namespace browser_sync {
+
// Mocks out the SyncerThread operations (Pause/Resume) since no thread is
// running in these tests, and allows tests to provide a task on construction
// to set up initial nodes to mock out an actual server initial sync
// download.
-class SyncBackendHostForProfileSyncTest :
- public browser_sync::SyncBackendHost {
+class SyncBackendHostForProfileSyncTest : public SyncBackendHost {
public:
- SyncBackendHostForProfileSyncTest(browser_sync::SyncFrontend* frontend,
+ // |initial_condition_setup_task| can be used to populate nodes before the
+ // OnBackendInitialized callback fires.
+ // |set_initial_sync_ended_on_init| determines whether we pretend that a full
+ // initial download has occurred and set bits for enabled data types. If
+ // this is false, configuring data types will require a syncer nudge.
+ // |synchronous_init| causes initialization to block until the syncapi has
+ // completed setting itself up and called us back.
+ SyncBackendHostForProfileSyncTest(SyncFrontend* frontend,
Profile* profile,
const FilePath& profile_path,
- const browser_sync::DataTypeController::TypeMap& data_type_controllers,
+ const DataTypeController::TypeMap& data_type_controllers,
Task* initial_condition_setup_task,
int num_expected_resumes,
- int num_expected_pauses)
+ int num_expected_pauses,
+ bool set_initial_sync_ended_on_init,
+ bool synchronous_init)
: browser_sync::SyncBackendHost(frontend, profile, profile_path,
data_type_controllers),
- initial_condition_setup_task_(initial_condition_setup_task) {
+ initial_condition_setup_task_(initial_condition_setup_task),
+ set_initial_sync_ended_on_init_(set_initial_sync_ended_on_init),
+ synchronous_init_(synchronous_init) {
// By default, the RequestPause and RequestResume methods will
// send the confirmation notification and return true.
ON_CALL(*this, RequestPause()).
@@ -55,65 +82,134 @@ class SyncBackendHostForProfileSyncTest :
ON_CALL(*this, RequestResume()).
WillByDefault(testing::DoAll(CallOnResumed(core_),
testing::Return(true)));
+ ON_CALL(*this, RequestNudge()).WillByDefault(testing::Invoke(this,
+ &SyncBackendHostForProfileSyncTest::
+ SimulateSyncCycleCompletedInitialSyncEnded));
+
EXPECT_CALL(*this, RequestPause()).Times(num_expected_pauses);
EXPECT_CALL(*this, RequestResume()).Times(num_expected_resumes);
+ EXPECT_CALL(*this, RequestNudge()).
+ Times(set_initial_sync_ended_on_init ? 0 : 1);
}
MOCK_METHOD0(RequestPause, bool());
MOCK_METHOD0(RequestResume, bool());
+ MOCK_METHOD0(RequestNudge, void());
+
+ void SetInitialSyncEndedForEnabledTypes() {
+ UserShare* user_share = core_->syncapi()->GetUserShare();
+ DirectoryManager* dir_manager = user_share->dir_manager.get();
+
+ ScopedDirLookup dir(dir_manager, user_share->name);
+ if (!dir.good())
+ FAIL();
+
+ ModelSafeRoutingInfo enabled_types;
+ GetModelSafeRoutingInfo(&enabled_types);
+ for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
+ i != enabled_types.end(); ++i) {
+ dir->set_initial_sync_ended_for_type(i->first, true);
+ }
+ }
virtual void HandleInitializationCompletedOnFrontendLoop() {
+ set_syncapi_initialized(); // Need to do this asap so task below works.
+
+ // Set up any nodes the test wants around before model association.
if (initial_condition_setup_task_) {
initial_condition_setup_task_->Run();
}
+ // Pretend we downloaded initial updates and set initial sync ended bits
+ // if we were asked to.
+ if (set_initial_sync_ended_on_init_)
+ SetInitialSyncEndedForEnabledTypes();
+
SyncBackendHost::HandleInitializationCompletedOnFrontendLoop();
}
+
+ // Called when a nudge comes in.
+ void SimulateSyncCycleCompletedInitialSyncEnded() {
+ syncable::ModelTypeBitSet sync_ended;
+ ModelSafeRoutingInfo enabled_types;
+ GetModelSafeRoutingInfo(&enabled_types);
+ for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
+ i != enabled_types.end(); ++i) {
+ sync_ended.set(i->first);
+ }
+ core_->HandleSyncCycleCompletedOnFrontendLoop(new SyncSessionSnapshot(
+ SyncerStatus(), ErrorCounters(), 0, 0, false,
+ sync_ended, false, false, 0, 0, false));
+ }
+
+ virtual sync_api::HttpPostProviderFactory* MakeHttpBridgeFactory(
+ URLRequestContextGetter* getter) {
+ return new browser_sync::TestHttpBridgeFactory;
+ }
+
+ virtual void InitCore(const Core::DoInitializeOptions& options) {
+ std::wstring user = L"testuser";
+ core_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(core_.get(),
+ &SyncBackendHost::Core::DoInitializeForTest,
+ user,
+ options.http_bridge_factory,
+ options.delete_sync_data_folder));
+
+ // TODO(akalin): Figure out a better way to do this.
+ if (synchronous_init_) {
+ // The SyncBackend posts a task to the current loop when
+ // initialization completes.
+ MessageLoop::current()->Run();
+ }
+ }
+
+ static void SetDefaultExpectationsForWorkerCreation(ProfileMock* profile) {
+ EXPECT_CALL(*profile, GetPasswordStore(testing::_)).
+ WillOnce(testing::Return((PasswordStore*)NULL));
+ EXPECT_CALL(*profile, GetHistoryService(testing::_)).
+ WillOnce(testing::Return((HistoryService*)NULL));
+ }
+
private:
Task* initial_condition_setup_task_;
+ bool set_initial_sync_ended_on_init_;
+ bool synchronous_init_;
};
+} // namespace browser_sync
+
class TestProfileSyncService : public ProfileSyncService {
public:
TestProfileSyncService(ProfileSyncFactory* factory,
Profile* profile,
- bool bootstrap_sync_authentication,
+ const std::string& test_user,
bool synchronous_backend_initialization,
Task* initial_condition_setup_task)
- : ProfileSyncService(factory, profile, bootstrap_sync_authentication),
+ : ProfileSyncService(factory, profile,
+ !test_user.empty() ?
+ test_user : ""),
synchronous_backend_initialization_(
synchronous_backend_initialization),
synchronous_sync_configuration_(false),
num_expected_resumes_(1),
num_expected_pauses_(1),
- initial_condition_setup_task_(initial_condition_setup_task) {
+ initial_condition_setup_task_(initial_condition_setup_task),
+ set_initial_sync_ended_on_init_(true) {
RegisterPreferences();
SetSyncSetupCompleted();
}
virtual ~TestProfileSyncService() { }
- virtual void InitializeBackend(bool delete_sync_data_folder) {
- browser_sync::TestHttpBridgeFactory* factory =
- new browser_sync::TestHttpBridgeFactory();
- browser_sync::TestHttpBridgeFactory* factory2 =
- new browser_sync::TestHttpBridgeFactory();
- backend_->Shutdown(false);
- backend_.reset(new SyncBackendHostForProfileSyncTest(this, profile(),
+ virtual void CreateBackend() {
+ backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
+ this, profile(),
profile()->GetPath(), data_type_controllers(),
initial_condition_setup_task_.release(),
- num_expected_resumes_, num_expected_pauses_));
- backend()->InitializeForTestMode(L"testuser", factory, factory2,
- delete_sync_data_folder, browser_sync::kDefaultNotificationMethod);
- // TODO(akalin): Figure out a better way to do this.
- if (synchronous_backend_initialization_) {
- // The SyncBackend posts a task to the current loop when
- // initialization completes.
- MessageLoop::current()->Run();
- // Initialization is synchronous for test mode, so we should be
- // good to go.
- DCHECK(sync_initialized());
- }
+ num_expected_resumes_, num_expected_pauses_,
+ set_initial_sync_ended_on_init_,
+ synchronous_backend_initialization_));
}
virtual void OnBackendInitialized() {
@@ -140,7 +236,9 @@ class TestProfileSyncService : public ProfileSyncService {
void set_num_expected_pauses(int num) {
num_expected_pauses_ = num;
}
-
+ void dont_set_initial_sync_ended_on_init() {
+ set_initial_sync_ended_on_init_ = false;
+ }
void set_synchronous_sync_configuration() {
synchronous_sync_configuration_ = true;
}
@@ -162,6 +260,7 @@ class TestProfileSyncService : public ProfileSyncService {
int num_expected_pauses_;
scoped_ptr<Task> initial_condition_setup_task_;
+ bool set_initial_sync_ended_on_init_;
};
#endif // CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
diff --git a/chrome/browser/sync/tools/sync_listen_notifications.cc b/chrome/browser/sync/tools/sync_listen_notifications.cc
index 69431e1..e436a81 100644
--- a/chrome/browser/sync/tools/sync_listen_notifications.cc
+++ b/chrome/browser/sync/tools/sync_listen_notifications.cc
@@ -9,31 +9,27 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
-#include "base/platform_thread.h"
+#include "base/observer_list.h"
#include "base/string_util.h"
#include "base/task.h"
-#include "chrome/browser/sync/notification_method.h"
+#include "base/weak_ptr.h"
#include "chrome/browser/sync/notifier/cache_invalidation_packet_handler.h"
#include "chrome/browser/sync/notifier/chrome_invalidation_client.h"
#include "chrome/browser/sync/notifier/chrome_system_resources.h"
#include "chrome/browser/sync/sync_constants.h"
#include "chrome/common/chrome_switches.h"
-#include "jingle/notifier/base/chrome_async_socket.h"
-#include "jingle/notifier/base/task_pump.h"
-#include "jingle/notifier/communicator/xmpp_socket_adapter.h"
+#include "jingle/notifier/base/notification_method.h"
+#include "jingle/notifier/base/xmpp_connection.h"
#include "jingle/notifier/listener/listen_task.h"
#include "jingle/notifier/listener/notification_constants.h"
#include "jingle/notifier/listener/subscribe_task.h"
+#include "jingle/notifier/listener/xml_element_util.h"
#include "net/base/ssl_config_service.h"
#include "net/socket/client_socket_factory.h"
#include "talk/base/cryptstring.h"
#include "talk/base/logging.h"
-#include "talk/base/sigslot.h"
-#include "talk/base/physicalsocketserver.h"
-#include "talk/base/ssladapter.h"
-#include "talk/base/thread.h"
+#include "talk/base/task.h"
#include "talk/xmpp/jid.h"
-#include "talk/xmpp/xmppclient.h"
#include "talk/xmpp/xmppclientsettings.h"
#include "talk/xmpp/constants.h"
#include "talk/xmpp/xmppengine.h"
@@ -44,162 +40,90 @@
namespace {
-void PumpAuxiliaryLoops() {
- talk_base::Thread* current_thread =
- talk_base::ThreadManager::CurrentThread();
- current_thread->ProcessMessages(100);
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableFunction(&PumpAuxiliaryLoops));
-}
-
// Main class that listens for and handles messages from the XMPP
// client.
-class XmppNotificationClient : public sigslot::has_slots<> {
+class XmppNotificationClient : public notifier::XmppConnection::Delegate {
public:
- // A delegate is notified when we are logged in and out of XMPP or
- // when an error occurs.
- //
- // TODO(akalin): Change Delegate to Observer so we can listen both
- // to legacy and cache invalidation notifications.
- class Delegate {
+ // An observer is notified when we are logged into XMPP or when an
+ // error occurs.
+ class Observer {
public:
- virtual ~Delegate() {}
-
- // The given xmpp_client is valid until OnLogout() or OnError() is
- // called.
- virtual void OnLogin(
- const buzz::XmppClientSettings& xmpp_client_settings,
- buzz::XmppClient* xmpp_client) = 0;
+ virtual ~Observer() {}
- virtual void OnLogout() = 0;
+ virtual void OnConnect(base::WeakPtr<talk_base::Task> base_task) = 0;
- virtual void OnError(buzz::XmppEngine::Error error, int subcode) = 0;
+ virtual void OnError() = 0;
};
- explicit XmppNotificationClient(Delegate* delegate)
- : delegate_(delegate),
- xmpp_client_(NULL) {
- CHECK(delegate_);
+ template <class T> XmppNotificationClient(T begin, T end) {
+ for (T it = begin; it != end; ++it) {
+ observer_list_.AddObserver(*it);
+ }
}
+ virtual ~XmppNotificationClient() {}
+
// Connect with the given XMPP settings and run until disconnected.
- void Run(const buzz::XmppClientSettings& xmpp_client_settings,
- bool use_chrome_async_socket) {
- CHECK(!xmpp_client_);
- xmpp_client_settings_ = xmpp_client_settings;
- xmpp_client_ = new buzz::XmppClient(&task_pump_);
- CHECK(xmpp_client_);
- xmpp_client_->SignalLogInput.connect(
- this, &XmppNotificationClient::OnXmppClientLogInput);
- xmpp_client_->SignalLogOutput.connect(
- this, &XmppNotificationClient::OnXmppClientLogOutput);
- xmpp_client_->SignalStateChange.connect(
- this, &XmppNotificationClient::OnXmppClientStateChange);
-
- net::SSLConfig ssl_config;
- buzz::AsyncSocket* buzz_async_socket =
- use_chrome_async_socket ?
- static_cast<buzz::AsyncSocket*>(
- new notifier::ChromeAsyncSocket(
- net::ClientSocketFactory::GetDefaultFactory(),
- ssl_config, 4096, 64 * 1024, NULL)) :
- static_cast<buzz::AsyncSocket*>(
- new notifier::XmppSocketAdapter(xmpp_client_settings_, false));
- CHECK(buzz_async_socket);
- // Transfers ownership of buzz_async_socket.
- buzz::XmppReturnStatus connect_status =
- xmpp_client_->Connect(xmpp_client_settings_, "",
- buzz_async_socket, NULL);
- CHECK_EQ(connect_status, buzz::XMPP_RETURN_OK);
- xmpp_client_->Start();
- if (!use_chrome_async_socket) {
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableFunction(&PumpAuxiliaryLoops));
- }
+ void Run(const buzz::XmppClientSettings& xmpp_client_settings) {
+ DCHECK(!xmpp_connection_.get());
+ xmpp_connection_.reset(
+ new notifier::XmppConnection(xmpp_client_settings, this, NULL));
MessageLoop::current()->Run();
- DCHECK(!xmpp_client_);
+ DCHECK(!xmpp_connection_.get());
}
- private:
- void OnXmppClientStateChange(buzz::XmppEngine::State state) {
- switch (state) {
- case buzz::XmppEngine::STATE_START:
- LOG(INFO) << "Starting...";
- break;
- case buzz::XmppEngine::STATE_OPENING:
- LOG(INFO) << "Opening...";
- break;
- case buzz::XmppEngine::STATE_OPEN: {
- LOG(INFO) << "Opened";
- delegate_->OnLogin(xmpp_client_settings_, xmpp_client_);
- break;
- }
- case buzz::XmppEngine::STATE_CLOSED:
- LOG(INFO) << "Closed";
- int subcode;
- buzz::XmppEngine::Error error = xmpp_client_->GetError(&subcode);
- if (error == buzz::XmppEngine::ERROR_NONE) {
- delegate_->OnLogout();
- } else {
- delegate_->OnError(error, subcode);
- }
- MessageLoop::current()->Quit();
- xmpp_client_ = NULL;
- break;
- }
+ virtual void OnConnect(base::WeakPtr<talk_base::Task> base_task) {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnConnect(base_task));
}
- void OnXmppClientLogInput(const char* data, int len) {
- LOG(INFO) << "XMPP Input: " << std::string(data, len);
+ virtual void OnError(buzz::XmppEngine::Error error, int subcode,
+ const buzz::XmlElement* stream_error) {
+ LOG(INFO) << "Error: " << error << ", subcode: " << subcode;
+ if (stream_error) {
+ LOG(INFO) << "Stream error: "
+ << notifier::XmlElementToString(*stream_error);
+ }
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnError());
+ // This has to go before the message loop quits.
+ xmpp_connection_.reset();
+ MessageLoop::current()->Quit();
}
- void OnXmppClientLogOutput(const char* data, int len) {
- LOG(INFO) << "XMPP Output: " << std::string(data, len);
- }
+ private:
+ ObserverList<Observer> observer_list_;
+ scoped_ptr<notifier::XmppConnection> xmpp_connection_;
- Delegate* delegate_;
- notifier::TaskPump task_pump_;
- buzz::XmppClientSettings xmpp_client_settings_;
- // Owned by task_pump.
- buzz::XmppClient* xmpp_client_;
+ DISALLOW_COPY_AND_ASSIGN(XmppNotificationClient);
};
// Delegate for legacy notifications.
-class LegacyNotifierDelegate : public XmppNotificationClient::Delegate {
+class LegacyNotifierDelegate : public XmppNotificationClient::Observer {
public:
virtual ~LegacyNotifierDelegate() {}
- virtual void OnLogin(
- const buzz::XmppClientSettings& xmpp_client_settings,
- buzz::XmppClient* xmpp_client) {
+ virtual void OnConnect(base::WeakPtr<talk_base::Task> base_task) {
LOG(INFO) << "Logged in";
- browser_sync::NotificationMethod notification_method =
- browser_sync::NOTIFICATION_TRANSITIONAL;
+ notifier::NotificationMethod notification_method =
+ notifier::NOTIFICATION_TRANSITIONAL;
std::vector<std::string> subscribed_services_list;
- if (notification_method != browser_sync::NOTIFICATION_LEGACY) {
- if (notification_method == browser_sync::NOTIFICATION_TRANSITIONAL) {
+ if (notification_method != notifier::NOTIFICATION_LEGACY) {
+ if (notification_method == notifier::NOTIFICATION_TRANSITIONAL) {
subscribed_services_list.push_back(
browser_sync::kSyncLegacyServiceUrl);
}
subscribed_services_list.push_back(browser_sync::kSyncServiceUrl);
}
- // Owned by xmpp_client.
+ // Owned by base_task.
notifier::SubscribeTask* subscribe_task =
- new notifier::SubscribeTask(xmpp_client, subscribed_services_list);
+ new notifier::SubscribeTask(base_task, subscribed_services_list);
subscribe_task->Start();
// Owned by xmpp_client.
notifier::ListenTask* listen_task =
- new notifier::ListenTask(xmpp_client);
+ new notifier::ListenTask(base_task);
listen_task->Start();
}
- virtual void OnLogout() {
- LOG(INFO) << "Logged out";
- }
-
- virtual void OnError(buzz::XmppEngine::Error error, int subcode) {
- LOG(INFO) << "Error: " << error << ", subcode: " << subcode;
- }
+ virtual void OnError() {}
};
// The actual listener for sync notifications.
@@ -209,7 +133,15 @@ class ChromeInvalidationListener
ChromeInvalidationListener() {}
virtual void OnInvalidate(syncable::ModelType model_type) {
- LOG(INFO) << "Invalidate: " << syncable::ModelTypeToString(model_type);
+ // 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.
+ if (model_type == syncable::UNSPECIFIED) {
+ LOG(INFO) << "OnInvalidate: UNKNOWN";
+ } else {
+ LOG(INFO) << "OnInvalidate: "
+ << syncable::ModelTypeToString(model_type);
+ }
// A real implementation would respond to the invalidation.
}
@@ -225,32 +157,24 @@ class ChromeInvalidationListener
// Delegate for server-side notifications.
class CacheInvalidationNotifierDelegate
- : public XmppNotificationClient::Delegate {
+ : public XmppNotificationClient::Observer {
public:
CacheInvalidationNotifierDelegate() {}
virtual ~CacheInvalidationNotifierDelegate() {}
- virtual void OnLogin(
- const buzz::XmppClientSettings& xmpp_client_settings,
- buzz::XmppClient* xmpp_client) {
+ virtual void OnConnect(base::WeakPtr<talk_base::Task> base_task) {
LOG(INFO) << "Logged in";
// TODO(akalin): app_name should be per-client unique.
const std::string kAppName = "cc_sync_listen_notifications";
chrome_invalidation_client_.Start(kAppName,
&chrome_invalidation_listener_,
- xmpp_client);
+ base_task);
chrome_invalidation_client_.RegisterTypes();
}
- virtual void OnLogout() {
- LOG(INFO) << "Logged out";
- chrome_invalidation_client_.Stop();
- }
-
- virtual void OnError(buzz::XmppEngine::Error error, int subcode) {
- LOG(INFO) << "Error: " << error << ", subcode: " << subcode;
+ virtual void OnError() {
chrome_invalidation_client_.Stop();
}
@@ -277,8 +201,7 @@ int main(int argc, char* argv[]) {
if (email.empty()) {
printf("Usage: %s --email=foo@bar.com [--password=mypassword] "
"[--server=talk.google.com] [--port=5222] [--allow-plain] "
- "[--disable-tls] [--use-cache-invalidation] [--use-ssl-tcp] "
- "[--use-chrome-async-socket]\n",
+ "[--disable-tls] [--use-cache-invalidation] [--use-ssl-tcp]\n",
argv[0]);
return -1;
}
@@ -330,29 +253,23 @@ int main(int argc, char* argv[]) {
}
xmpp_client_settings.set_server(addr);
- // Set up message loops and socket servers.
- talk_base::PhysicalSocketServer physical_socket_server;
- talk_base::InitializeSSL();
- talk_base::Thread main_thread(&physical_socket_server);
- talk_base::ThreadManager::SetCurrent(&main_thread);
MessageLoopForIO message_loop;
// Connect and listen.
LegacyNotifierDelegate legacy_notifier_delegate;
CacheInvalidationNotifierDelegate cache_invalidation_notifier_delegate;
- XmppNotificationClient::Delegate* delegate = NULL;
+ std::vector<XmppNotificationClient::Observer*> observers;
+ // TODO(akalin): Add switch to listen to both.
if (command_line.HasSwitch(switches::kSyncUseCacheInvalidation)) {
- delegate = &cache_invalidation_notifier_delegate;
+ observers.push_back(&cache_invalidation_notifier_delegate);
} else {
- delegate = &legacy_notifier_delegate;
+ observers.push_back(&legacy_notifier_delegate);
}
// TODO(akalin): Revert the move of all switches in this file into
// chrome_switches.h.
- bool use_chrome_async_socket =
- command_line.HasSwitch("use-chrome-async-socket");
- XmppNotificationClient xmpp_notification_client(delegate);
- xmpp_notification_client.Run(xmpp_client_settings,
- use_chrome_async_socket);
+ XmppNotificationClient xmpp_notification_client(
+ observers.begin(), observers.end());
+ xmpp_notification_client.Run(xmpp_client_settings);
return 0;
}
diff --git a/chrome/browser/sync/tools/sync_listen_notifications.target.mk b/chrome/browser/sync/tools/sync_listen_notifications.target.mk
index 149f802..0baf23f 100644
--- a/chrome/browser/sync/tools/sync_listen_notifications.target.mk
+++ b/chrome/browser/sync/tools/sync_listen_notifications.target.mk
@@ -22,6 +22,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -79,6 +80,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -151,14 +153,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -189,7 +192,8 @@ LIBS := -lrt \
-lz \
-lXss \
-lexpat \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/sync_listen_notifications: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/sync_listen_notifications: LIBS := $(LIBS)
diff --git a/chrome/browser/sync/unrecoverable_error_handler.h b/chrome/browser/sync/unrecoverable_error_handler.h
index d8950e6..c8471ef 100644
--- a/chrome/browser/sync/unrecoverable_error_handler.h
+++ b/chrome/browser/sync/unrecoverable_error_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_UNRECOVERABLE_ERROR_HANDLER_H_
#define CHROME_BROWSER_SYNC_UNRECOVERABLE_ERROR_HANDLER_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/sync/util/channel.h b/chrome/browser/sync/util/channel.h
index ba516b6..4017d9f 100644
--- a/chrome/browser/sync/util/channel.h
+++ b/chrome/browser/sync/util/channel.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_UTIL_CHANNEL_H_
#define CHROME_BROWSER_SYNC_UTIL_CHANNEL_H_
+#pragma once
///////////////////////////////////////////////////////////////////////////////
//
@@ -64,6 +65,9 @@ template <typename EventType>
class ChannelEventHandler : public EventHandler {
public:
virtual void HandleChannelEvent(const EventType& event) = 0;
+
+ protected:
+ virtual ~ChannelEventHandler() {}
};
// This class manages a connection to a channel. When it is destroyed, it
diff --git a/chrome/browser/sync/util/crypto_helpers.cc b/chrome/browser/sync/util/crypto_helpers.cc
index 801002c..b01e01f 100644
--- a/chrome/browser/sync/util/crypto_helpers.cc
+++ b/chrome/browser/sync/util/crypto_helpers.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.
@@ -11,6 +11,7 @@
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/rand_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
using std::string;
@@ -40,8 +41,8 @@ vector<uint8> MD5Calculator::GetDigest() {
std::string MD5Calculator::GetHexDigest() {
CalcDigest();
- string hex = HexEncode(reinterpret_cast<char*>(&bin_digest_.front()),
- bin_digest_.size());
+ string hex = base::HexEncode(reinterpret_cast<char*>(&bin_digest_.front()),
+ bin_digest_.size());
StringToLowerASCII(&hex);
return hex;
}
diff --git a/chrome/browser/sync/util/crypto_helpers.h b/chrome/browser/sync/util/crypto_helpers.h
index 704fed6..5660447 100644
--- a/chrome/browser/sync/util/crypto_helpers.h
+++ b/chrome/browser/sync/util/crypto_helpers.h
@@ -1,19 +1,18 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_UTIL_CRYPTO_HELPERS_H_
#define CHROME_BROWSER_SYNC_UTIL_CRYPTO_HELPERS_H_
+#pragma once
#include <string>
#include <vector>
// An object to handle calculation of MD5 sums.
#include "base/basictypes.h"
-#include "base/logging.h"
#include "base/md5.h"
#include "base/port.h"
-#include "chrome/browser/sync/util/sync_types.h"
class MD5Calculator {
protected:
diff --git a/chrome/browser/sync/util/cryptographer.cc b/chrome/browser/sync/util/cryptographer.cc
index f323d17..2a3701e 100644
--- a/chrome/browser/sync/util/cryptographer.cc
+++ b/chrome/browser/sync/util/cryptographer.cc
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/base64.h"
#include "chrome/browser/sync/util/cryptographer.h"
+#include "chrome/browser/password_manager/encryptor.h"
namespace browser_sync {
@@ -17,6 +19,17 @@ const char kNigoriKeyName[] = "nigori-key";
Cryptographer::Cryptographer() : default_nigori_(NULL) {
}
+void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) {
+ if (is_ready()) {
+ NOTREACHED();
+ return;
+ }
+
+ scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token));
+ if (nigori.get())
+ AddKeyImpl(nigori.release());
+}
+
bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const {
return nigoris_.end() != nigoris_.find(data.key_name());
}
@@ -70,9 +83,9 @@ bool Cryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const {
const Nigori& nigori = *it->second;
sync_pb::NigoriKey* key = bag.add_key();
key->set_name(it->first);
- key->set_hostname(nigori.hostname());
- key->set_username(nigori.username());
- key->set_password(nigori.password());
+ nigori.ExportKeys(key->mutable_user_key(),
+ key->mutable_encryption_key(),
+ key->mutable_mac_key());
}
// Encrypt the bag with the default Nigori.
@@ -83,11 +96,18 @@ bool Cryptographer::AddKey(const KeyParams& params) {
DCHECK(NULL == pending_keys_.get());
// Create the new Nigori and make it the default encryptor.
- scoped_ptr<Nigori> nigori(new Nigori(params.hostname));
- if (!nigori->Init(params.username, params.password)) {
+ scoped_ptr<Nigori> nigori(new Nigori);
+ if (!nigori->InitByDerivation(params.hostname,
+ params.username,
+ params.password)) {
NOTREACHED(); // Invalid username or password.
return false;
}
+ return AddKeyImpl(nigori.release());
+}
+
+bool Cryptographer::AddKeyImpl(Nigori* initialized_nigori) {
+ scoped_ptr<Nigori> nigori(initialized_nigori);
std::string name;
if (!nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) {
NOTREACHED();
@@ -115,8 +135,10 @@ void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) {
}
bool Cryptographer::DecryptPendingKeys(const KeyParams& params) {
- Nigori nigori(params.hostname);
- if (!nigori.Init(params.username, params.password)) {
+ Nigori nigori;
+ if (!nigori.InitByDerivation(params.hostname,
+ params.username,
+ params.password)) {
NOTREACHED();
return false;
}
@@ -135,6 +157,78 @@ bool Cryptographer::DecryptPendingKeys(const KeyParams& params) {
return true;
}
+bool Cryptographer::GetBootstrapToken(std::string* token) const {
+ DCHECK(token);
+ if (!is_ready())
+ return false;
+
+ return PackBootstrapToken(default_nigori_->second.get(), token);
+}
+
+bool Cryptographer::PackBootstrapToken(const Nigori* nigori,
+ std::string* pack_into) const {
+ DCHECK(pack_into);
+ DCHECK(nigori);
+
+ sync_pb::NigoriKey key;
+ if (!nigori->ExportKeys(key.mutable_user_key(),
+ key.mutable_encryption_key(),
+ key.mutable_mac_key())) {
+ NOTREACHED();
+ return false;
+ }
+
+ std::string unencrypted_token;
+ if (!key.SerializeToString(&unencrypted_token)) {
+ NOTREACHED();
+ return false;
+ }
+
+ std::string encrypted_token;
+ if (!Encryptor::EncryptString(unencrypted_token, &encrypted_token)) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (!base::Base64Encode(encrypted_token, pack_into)) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+Nigori* Cryptographer::UnpackBootstrapToken(const std::string& token) const {
+ if (token.empty())
+ return NULL;
+
+ std::string encrypted_data;
+ if (!base::Base64Decode(token, &encrypted_data)){
+ DLOG(WARNING) << "Could not decode token.";
+ return NULL;
+ }
+
+ std::string unencrypted_token;
+ if (!Encryptor::DecryptString(encrypted_data, &unencrypted_token)) {
+ DLOG(WARNING) << "Decryption of bootstrap token failed.";
+ return NULL;
+ }
+
+ sync_pb::NigoriKey key;
+ if (!key.ParseFromString(unencrypted_token)) {
+ DLOG(WARNING) << "Parsing of bootstrap token failed.";
+ return NULL;
+ }
+
+ scoped_ptr<Nigori> nigori(new Nigori);
+ if (!nigori->InitByImport(key.user_key(), key.encryption_key(),
+ key.mac_key())) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return nigori.release();
+}
+
void Cryptographer::InstallKeys(const std::string& default_key_name,
const sync_pb::NigoriKeyBag& bag) {
int key_size = bag.key_size();
@@ -142,8 +236,10 @@ void Cryptographer::InstallKeys(const std::string& default_key_name,
const sync_pb::NigoriKey key = bag.key(i);
// Only use this key if we don't already know about it.
if (nigoris_.end() == nigoris_.find(key.name())) {
- scoped_ptr<Nigori> new_nigori(new Nigori(key.hostname()));
- if (!new_nigori->Init(key.username(), key.password())) {
+ scoped_ptr<Nigori> new_nigori(new Nigori);
+ if (!new_nigori->InitByImport(key.user_key(),
+ key.encryption_key(),
+ key.mac_key())) {
NOTREACHED();
continue;
}
diff --git a/chrome/browser/sync/util/cryptographer.h b/chrome/browser/sync/util/cryptographer.h
index 0ffa84f..230ed94 100644
--- a/chrome/browser/sync/util/cryptographer.h
+++ b/chrome/browser/sync/util/cryptographer.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_SYNC_UTIL_CRYPTOGRAPHER_H_
#define CHROME_BROWSER_SYNC_UTIL_CRYPTOGRAPHER_H_
+#pragma once
#include <map>
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/linked_ptr.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
@@ -42,6 +44,17 @@ class Cryptographer {
public:
Cryptographer();
+ // |restored_bootstrap_token| can be provided via this method to bootstrap
+ // Cryptographer instance into the ready state (is_ready will be true).
+ // It must be a string that was previously built by the
+ // GetSerializedBootstrapToken function. It is possible that the token is no
+ // longer valid (due to server key change), in which case the normal
+ // decryption code paths will fail and the user will need to provide a new
+ // passphrase.
+ // It is an error to call this if is_ready() == true, though it is fair to
+ // never call Bootstrap at all.
+ void Bootstrap(const std::string& restored_bootstrap_token);
+
// Returns whether we can decrypt |encrypted| using the keys we currently know
// about.
bool CanDecrypt(const sync_pb::EncryptedData& encrypted) const;
@@ -87,15 +100,28 @@ class Cryptographer {
// Returns whether there is a pending set of keys that needs to be decrypted.
bool has_pending_keys() const { return NULL != pending_keys_.get(); }
+ // Obtain a token that can be provided on construction to a future
+ // Cryptographer instance to bootstrap itself. Returns false if such a token
+ // can't be created (i.e. if this Cryptograhper doesn't have valid keys).
+ bool GetBootstrapToken(std::string* token) const;
+
private:
+ FRIEND_TEST_ALL_PREFIXES(CryptographerTest, PackUnpack);
typedef std::map<std::string, linked_ptr<const Nigori> > NigoriMap;
- // Helper method to instancitate Nigori instances for each set of key
+ // Helper method to instantiate Nigori instances for each set of key
// parameters in |bag| and setting the default encryption key to
// |default_key_name|.
void InstallKeys(const std::string& default_key_name,
const sync_pb::NigoriKeyBag& bag);
+ bool AddKeyImpl(Nigori* nigori);
+
+ // Functions to serialize + encrypt a Nigori object in an opaque format for
+ // persistence by sync infrastructure.
+ bool PackBootstrapToken(const Nigori* nigori, std::string* pack_into) const;
+ Nigori* UnpackBootstrapToken(const std::string& token) const;
+
NigoriMap nigoris_; // The Nigoris we know about, mapped by key name.
NigoriMap::value_type* default_nigori_; // The Nigori used for encryption.
diff --git a/chrome/browser/sync/util/cryptographer_unittest.cc b/chrome/browser/sync/util/cryptographer_unittest.cc
index af5f0a2..30b3be0 100644
--- a/chrome/browser/sync/util/cryptographer_unittest.cc
+++ b/chrome/browser/sync/util/cryptographer_unittest.cc
@@ -8,11 +8,11 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/sync/protocol/password_specifics.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace browser_sync {
-namespace {
TEST(CryptographerTest, EmptyCantDecrypt) {
Cryptographer cryptographer;
@@ -91,7 +91,13 @@ TEST(CryptographerTest, AddKeySetsDefault) {
EXPECT_EQ(encrypted3.key_name(), encrypted4.key_name());
}
-TEST(CryptographerTest, EncryptExportDecrypt) {
+// Crashes, Bug 55178.
+#if defined(OS_WIN)
+#define MAYBE_EncryptExportDecrypt DISABLED_EncryptExportDecrypt
+#else
+#define MAYBE_EncryptExportDecrypt EncryptExportDecrypt
+#endif
+TEST(CryptographerTest, MAYBE_EncryptExportDecrypt) {
sync_pb::EncryptedData nigori;
sync_pb::EncryptedData encrypted;
@@ -130,5 +136,37 @@ TEST(CryptographerTest, EncryptExportDecrypt) {
}
}
-} // anonymous namespace
+// Crashes, Bug 55178.
+#if defined(OS_WIN)
+#define MAYBE_PackUnpack DISABLED_PackUnpack
+#else
+#define MAYBE_PackUnpack PackUnpack
+#endif
+TEST(CryptographerTest, MAYBE_PackUnpack) {
+#if defined(OS_MACOSX)
+ Encryptor::UseMockKeychain(true);
+#endif
+
+ Nigori nigori;
+ ASSERT_TRUE(nigori.InitByDerivation("example.com", "username", "password"));
+ std::string expected_user, expected_encryption, expected_mac;
+ ASSERT_TRUE(nigori.ExportKeys(&expected_user, &expected_encryption,
+ &expected_mac));
+
+ Cryptographer cryptographer;
+ std::string token;
+ EXPECT_TRUE(cryptographer.PackBootstrapToken(&nigori, &token));
+ EXPECT_TRUE(IsStringUTF8(token));
+
+ scoped_ptr<Nigori> unpacked(cryptographer.UnpackBootstrapToken(token));
+ EXPECT_NE(static_cast<Nigori*>(NULL), unpacked.get());
+
+ std::string user_key, encryption_key, mac_key;
+ ASSERT_TRUE(unpacked->ExportKeys(&user_key, &encryption_key, &mac_key));
+
+ EXPECT_EQ(expected_user, user_key);
+ EXPECT_EQ(expected_encryption, encryption_key);
+ EXPECT_EQ(expected_mac, mac_key);
+}
+
} // namespace browser_sync
diff --git a/chrome/browser/sync/util/data_encryption.cc b/chrome/browser/sync/util/data_encryption.cc
index 1232447..10f19ec 100644
--- a/chrome/browser/sync/util/data_encryption.cc
+++ b/chrome/browser/sync/util/data_encryption.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.
//
@@ -13,6 +13,8 @@
#include <string>
#include <vector>
+#include "base/logging.h"
+
using std::string;
using std::vector;
diff --git a/chrome/browser/sync/util/data_encryption.h b/chrome/browser/sync/util/data_encryption.h
index b62a14a..1f48afd 100644
--- a/chrome/browser/sync/util/data_encryption.h
+++ b/chrome/browser/sync/util/data_encryption.h
@@ -1,16 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_UTIL_DATA_ENCRYPTION_H_
#define CHROME_BROWSER_SYNC_UTIL_DATA_ENCRYPTION_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/logging.h"
-#include "chrome/browser/sync/util/sync_types.h"
using std::string;
using std::vector;
diff --git a/chrome/browser/sync/util/dbgq.h b/chrome/browser/sync/util/dbgq.h
index 65ebb5c..5b97fac 100644
--- a/chrome/browser/sync/util/dbgq.h
+++ b/chrome/browser/sync/util/dbgq.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_UTIL_DBGQ_H_
#define CHROME_BROWSER_SYNC_UTIL_DBGQ_H_
+#pragma once
#include "base/basictypes.h" // for COMPILE_ASSERT
diff --git a/chrome/browser/sync/util/extensions_activity_monitor.h b/chrome/browser/sync/util/extensions_activity_monitor.h
index a1e36f2..48ba090 100644
--- a/chrome/browser/sync/util/extensions_activity_monitor.h
+++ b/chrome/browser/sync/util/extensions_activity_monitor.h
@@ -1,15 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_UTIL_EXTENSIONS_ACTIVITY_MONITOR_H_
#define CHROME_BROWSER_SYNC_UTIL_EXTENSIONS_ACTIVITY_MONITOR_H_
+#pragma once
#include <map>
#include "base/lock.h"
#include "base/message_loop.h"
-#include "base/ref_counted.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/sync/util/extensions_activity_monitor_unittest.cc b/chrome/browser/sync/util/extensions_activity_monitor_unittest.cc
index f2cbf97..e532296 100644
--- a/chrome/browser/sync/util/extensions_activity_monitor_unittest.cc
+++ b/chrome/browser/sync/util/extensions_activity_monitor_unittest.cc
@@ -7,6 +7,7 @@
#include "base/file_path.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
+#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_bookmarks_module.h"
#include "chrome/common/extensions/extension.h"
diff --git a/chrome/browser/sync/util/fast_dump.h b/chrome/browser/sync/util/fast_dump.h
index 9266f0e..44e48c1 100644
--- a/chrome/browser/sync/util/fast_dump.h
+++ b/chrome/browser/sync/util/fast_dump.h
@@ -4,12 +4,13 @@
#ifndef CHROME_BROWSER_SYNC_UTIL_FAST_DUMP_H_
#define CHROME_BROWSER_SYNC_UTIL_FAST_DUMP_H_
+#pragma once
#include <ostream>
#include <streambuf>
#include <string>
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
using std::ostream;
using std::streambuf;
@@ -27,34 +28,31 @@ class FastDump {
ostream::sentry sentry_;
streambuf* const out_;
};
-} // namespace browser_sync
-inline browser_sync::FastDump& operator <<
- (browser_sync::FastDump& dump, int64 n) {
- string numbuf(Int64ToString(n));
+inline FastDump& operator << (FastDump& dump, int64 n) {
+ string numbuf(base::Int64ToString(n));
const char* number = numbuf.c_str();
dump.out_->sputn(number, numbuf.length());
return dump;
}
-inline browser_sync::FastDump& operator <<
- (browser_sync::FastDump& dump, int32 n) {
- string numbuf(IntToString(n));
+inline FastDump& operator << (FastDump& dump, int32 n) {
+ string numbuf(base::IntToString(n));
const char* number = numbuf.c_str();
dump.out_->sputn(number, numbuf.length());
return dump;
}
-inline browser_sync::FastDump& operator <<
- (browser_sync::FastDump& dump, const char* s) {
+inline FastDump& operator << (FastDump& dump, const char* s) {
dump.out_->sputn(s, strlen(s));
return dump;
}
-inline browser_sync::FastDump& operator <<
- (browser_sync::FastDump& dump, const string& s) {
+inline FastDump& operator << (FastDump& dump, const string& s) {
dump.out_->sputn(s.data(), s.size());
return dump;
}
+} // namespace browser_sync
+
#endif // CHROME_BROWSER_SYNC_UTIL_FAST_DUMP_H_
diff --git a/chrome/browser/sync/util/nigori.cc b/chrome/browser/sync/util/nigori.cc
index 01de18d..77cca2b 100644
--- a/chrome/browser/sync/util/nigori.cc
+++ b/chrome/browser/sync/util/nigori.cc
@@ -61,19 +61,17 @@ class NigoriStream {
// static
const char Nigori::kSaltSalt[] = "saltsalt";
-Nigori::Nigori(const std::string& hostname)
- : hostname_(hostname) {
+Nigori::Nigori() {
}
Nigori::~Nigori() {
}
-bool Nigori::Init(const std::string& username, const std::string& password) {
- username_ = username;
- password_ = password;
-
+bool Nigori::InitByDerivation(const std::string& hostname,
+ const std::string& username,
+ const std::string& password) {
NigoriStream salt_password;
- salt_password << username << hostname_;
+ salt_password << username << hostname;
// Suser = PBKDF2(Username || Servername, "saltsalt", Nsalt, 8)
scoped_ptr<SymmetricKey> user_salt(SymmetricKey::DeriveKeyFromPassword(
@@ -105,6 +103,22 @@ bool Nigori::Init(const std::string& username, const std::string& password) {
return true;
}
+bool Nigori::InitByImport(const std::string& user_key,
+ const std::string& encryption_key,
+ const std::string& mac_key) {
+ user_key_.reset(SymmetricKey::Import(SymmetricKey::AES, user_key));
+ DCHECK(user_key_.get());
+
+ encryption_key_.reset(SymmetricKey::Import(SymmetricKey::AES,
+ encryption_key));
+ DCHECK(encryption_key_.get());
+
+ mac_key_.reset(SymmetricKey::Import(SymmetricKey::HMAC_SHA1, mac_key));
+ DCHECK(mac_key_.get());
+
+ return user_key_.get() && encryption_key_.get() && mac_key_.get();
+}
+
// Permute[Kenc,Kmac](type || name)
bool Nigori::Permute(Type type, const std::string& name,
std::string* permuted) const {
@@ -228,4 +242,16 @@ bool Nigori::Decrypt(const std::string& encrypted, std::string* value) const {
return true;
}
+bool Nigori::ExportKeys(std::string* user_key,
+ std::string* encryption_key,
+ std::string* mac_key) const {
+ DCHECK(user_key);
+ DCHECK(encryption_key);
+ DCHECK(mac_key);
+
+ return user_key_->GetRawKey(user_key) &&
+ encryption_key_->GetRawKey(encryption_key) &&
+ mac_key_->GetRawKey(mac_key);
+}
+
} // namespace browser_sync
diff --git a/chrome/browser/sync/util/nigori.h b/chrome/browser/sync/util/nigori.h
index 0050c48..38d6fde 100644
--- a/chrome/browser/sync/util/nigori.h
+++ b/chrome/browser/sync/util/nigori.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_SYNC_UTIL_NIGORI_H_
#define CHROME_BROWSER_SYNC_UTIL_NIGORI_H_
+#pragma once
#include <string>
@@ -27,13 +28,19 @@ class Nigori {
Password = 1,
};
- // Creates a Nigori client for communicating with |hostname|. Note that
- // |hostname| is used to derive the keys used to encrypt and decrypt data.
- explicit Nigori(const std::string& hostname);
+ Nigori();
virtual ~Nigori();
- // Initialize the client with the supplied |username| and |password|.
- bool Init(const std::string& username, const std::string& password);
+ // Initialize the client with the given |hostname|, |username| and |password|.
+ bool InitByDerivation(const std::string& hostname,
+ const std::string& username,
+ const std::string& password);
+
+ // Initialize the client by importing the given keys instead of deriving new
+ // ones.
+ bool InitByImport(const std::string& user_key,
+ const std::string& encryption_key,
+ const std::string& mac_key);
// Derives a secure lookup name from |type| and |name|. If |hostname|,
// |username| and |password| are kept constant, a given |type| and |name| pair
@@ -49,12 +56,10 @@ class Nigori {
// encoded.
bool Decrypt(const std::string& value, std::string* decrypted) const;
- // The next three getters return the parameters used to initialize the keys.
- // Given the hostname, username and password, another Nigori object capable of
- // encrypting and decrypting the same data as this one could be initialized.
- const std::string& hostname() const { return hostname_; }
- const std::string& username() const { return username_; }
- const std::string& password() const { return password_; }
+ // Exports the raw derived keys.
+ bool ExportKeys(std::string* user_key,
+ std::string* encryption_key,
+ std::string* mac_key) const;
static const char kSaltSalt[]; // The salt used to derive the user salt.
static const size_t kSaltKeySizeInBits = 128;
@@ -68,10 +73,6 @@ class Nigori {
static const size_t kSigningIterations = 1004;
private:
- std::string hostname_;
- std::string username_;
- std::string password_;
-
scoped_ptr<base::SymmetricKey> user_key_;
scoped_ptr<base::SymmetricKey> encryption_key_;
scoped_ptr<base::SymmetricKey> mac_key_;
diff --git a/chrome/browser/sync/util/nigori_unittest.cc b/chrome/browser/sync/util/nigori_unittest.cc
index ec42911..8505e55 100644
--- a/chrome/browser/sync/util/nigori_unittest.cc
+++ b/chrome/browser/sync/util/nigori_unittest.cc
@@ -10,20 +10,15 @@
#include "base/string_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-TEST(NigoriTest, Parameters) {
- browser_sync::Nigori nigori("example.com");
- EXPECT_TRUE(nigori.Init("username", "password"));
- EXPECT_STREQ("example.com", nigori.hostname().c_str());
- EXPECT_STREQ("username", nigori.username().c_str());
- EXPECT_STREQ("password", nigori.password().c_str());
-}
+namespace browser_sync {
+namespace {
TEST(NigoriTest, Permute) {
- browser_sync::Nigori nigori("example.com");
- EXPECT_TRUE(nigori.Init("username", "password"));
+ Nigori nigori;
+ EXPECT_TRUE(nigori.InitByDerivation("example.com", "username", "password"));
std::string permuted;
- EXPECT_TRUE(nigori.Permute(browser_sync::Nigori::Password, "test name",
+ EXPECT_TRUE(nigori.Permute(Nigori::Password, "test name",
&permuted));
std::string expected =
@@ -33,19 +28,19 @@ TEST(NigoriTest, Permute) {
}
TEST(NigoriTest, PermuteIsConstant) {
- browser_sync::Nigori nigori1("example.com");
- EXPECT_TRUE(nigori1.Init("username", "password"));
+ Nigori nigori1;
+ EXPECT_TRUE(nigori1.InitByDerivation("example.com", "username", "password"));
std::string permuted1;
- EXPECT_TRUE(nigori1.Permute(browser_sync::Nigori::Password,
+ EXPECT_TRUE(nigori1.Permute(Nigori::Password,
"name",
&permuted1));
- browser_sync::Nigori nigori2("example.com");
- EXPECT_TRUE(nigori2.Init("username", "password"));
+ Nigori nigori2;
+ EXPECT_TRUE(nigori2.InitByDerivation("example.com", "username", "password"));
std::string permuted2;
- EXPECT_TRUE(nigori2.Permute(browser_sync::Nigori::Password,
+ EXPECT_TRUE(nigori2.Permute(Nigori::Password,
"name",
&permuted2));
@@ -54,8 +49,8 @@ TEST(NigoriTest, PermuteIsConstant) {
}
TEST(NigoriTest, EncryptDifferentIv) {
- browser_sync::Nigori nigori("example.com");
- EXPECT_TRUE(nigori.Init("username", "password"));
+ Nigori nigori;
+ EXPECT_TRUE(nigori.InitByDerivation("example.com", "username", "password"));
std::string plaintext("value");
@@ -69,8 +64,8 @@ TEST(NigoriTest, EncryptDifferentIv) {
}
TEST(NigoriTest, Decrypt) {
- browser_sync::Nigori nigori("example.com");
- EXPECT_TRUE(nigori.Init("username", "password"));
+ Nigori nigori;
+ EXPECT_TRUE(nigori.InitByDerivation("example.com", "username", "password"));
std::string encrypted =
"e7+JyS6ibj6F5qqvpseukNRTZ+oBpu5iuv2VYjOfrH1dNiFLNf7Ov0"
@@ -84,8 +79,8 @@ TEST(NigoriTest, Decrypt) {
}
TEST(NigoriTest, EncryptDecrypt) {
- browser_sync::Nigori nigori("example.com");
- EXPECT_TRUE(nigori.Init("username", "password"));
+ Nigori nigori;
+ EXPECT_TRUE(nigori.InitByDerivation("example.com", "username", "password"));
std::string plaintext("value");
@@ -99,8 +94,8 @@ TEST(NigoriTest, EncryptDecrypt) {
}
TEST(NigoriTest, CorruptedIv) {
- browser_sync::Nigori nigori("example.com");
- EXPECT_TRUE(nigori.Init("username", "password"));
+ Nigori nigori;
+ EXPECT_TRUE(nigori.InitByDerivation("example.com", "username", "password"));
std::string plaintext("test");
@@ -117,8 +112,8 @@ TEST(NigoriTest, CorruptedIv) {
}
TEST(NigoriTest, CorruptedCiphertext) {
- browser_sync::Nigori nigori("example.com");
- EXPECT_TRUE(nigori.Init("username", "password"));
+ Nigori nigori;
+ EXPECT_TRUE(nigori.InitByDerivation("example.com", "username", "password"));
std::string plaintext("test");
@@ -126,11 +121,50 @@ TEST(NigoriTest, CorruptedCiphertext) {
EXPECT_TRUE(nigori.Encrypt(plaintext, &encrypted));
// Corrput the ciphertext by changing one of its bytes.
- encrypted[browser_sync::Nigori::kIvSize + 10] =
- (encrypted[browser_sync::Nigori::kIvSize + 10] == 'a' ? 'b' : 'a');
+ encrypted[Nigori::kIvSize + 10] =
+ (encrypted[Nigori::kIvSize + 10] == 'a' ? 'b' : 'a');
std::string decrypted;
EXPECT_FALSE(nigori.Decrypt(encrypted, &decrypted));
EXPECT_NE(plaintext, decrypted);
}
+
+// Crashes, Bug 55180.
+#if defined(OS_WIN)
+#define MAYBE_ExportImport DISABLED_ExportImport
+#else
+#define MAYBE_ExportImport ExportImport
+#endif
+TEST(NigoriTest, MAYBE_ExportImport) {
+ Nigori nigori1;
+ EXPECT_TRUE(nigori1.InitByDerivation("example.com", "username", "password"));
+
+ std::string user_key;
+ std::string encryption_key;
+ std::string mac_key;
+ EXPECT_TRUE(nigori1.ExportKeys(&user_key, &encryption_key, &mac_key));
+
+ Nigori nigori2;
+ EXPECT_TRUE(nigori2.InitByImport(user_key, encryption_key, mac_key));
+
+ std::string original("test");
+ std::string plaintext;
+ std::string ciphertext;
+
+ EXPECT_TRUE(nigori1.Encrypt(original, &ciphertext));
+ EXPECT_TRUE(nigori2.Decrypt(ciphertext, &plaintext));
+ EXPECT_EQ(original, plaintext);
+
+ EXPECT_TRUE(nigori2.Encrypt(original, &ciphertext));
+ EXPECT_TRUE(nigori1.Decrypt(ciphertext, &plaintext));
+ EXPECT_EQ(original, plaintext);
+
+ std::string permuted1, permuted2;
+ EXPECT_TRUE(nigori1.Permute(Nigori::Password, original, &permuted1));
+ EXPECT_TRUE(nigori2.Permute(Nigori::Password, original, &permuted2));
+ EXPECT_EQ(permuted1, permuted2);
+}
+
+} // anonymous namespace
+} // namespace browser_sync
diff --git a/chrome/browser/sync/util/sync_types.h b/chrome/browser/sync/util/sync_types.h
deleted file mode 100644
index 14addd0..0000000
--- a/chrome/browser/sync/util/sync_types.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.
-
-#ifndef CHROME_BROWSER_SYNC_UTIL_SYNC_TYPES_H_
-#define CHROME_BROWSER_SYNC_UTIL_SYNC_TYPES_H_
-
-#include <iosfwd>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/string_util.h"
-#include "build/build_config.h"
-
-#if !defined(OS_WIN)
-// Mac OS X typedef's BOOL to signed char, so we do that on Linux too.
-typedef signed char BOOL;
-typedef int32 LONG;
-typedef uint32 DWORD;
-typedef int64 LONGLONG;
-typedef uint64 ULONGLONG;
-
-#define MAX_PATH PATH_MAX
-#if !defined(TRUE)
-const BOOL TRUE = 1;
-#endif
-#if !defined(FALSE)
-const BOOL FALSE = 0;
-#endif
-#endif
-
-inline size_t CountBytes(const std::string &s) {
- return s.size() * sizeof(std::string::value_type);
-}
-
-const size_t kSyncProtocolMaxNameLengthBytes = 255;
-
-#endif // CHROME_BROWSER_SYNC_UTIL_SYNC_TYPES_H_
diff --git a/chrome/browser/sync/util/user_settings.cc b/chrome/browser/sync/util/user_settings.cc
index 9af7fb0..9f52088 100644
--- a/chrome/browser/sync/util/user_settings.cc
+++ b/chrome/browser/sync/util/user_settings.cc
@@ -178,7 +178,10 @@ bool UserSettings::Init(const FilePath& settings_path) {
ScopedDBHandle dbhandle(this);
if (dbhandle_)
sqlite3_close(dbhandle_);
- CHECK_EQ(SQLITE_OK, sqlite_utils::OpenSqliteDb(settings_path, &dbhandle_));
+
+ if (SQLITE_OK != sqlite_utils::OpenSqliteDb(settings_path, &dbhandle_))
+ return false;
+
// In the worst case scenario, the user may hibernate his computer during
// one of our transactions.
sqlite3_busy_timeout(dbhandle_, numeric_limits<int>::max());
diff --git a/chrome/browser/sync/util/user_settings.h b/chrome/browser/sync/util/user_settings.h
index 7bfa571..5545c8c 100644
--- a/chrome/browser/sync/util/user_settings.h
+++ b/chrome/browser/sync/util/user_settings.h
@@ -1,21 +1,21 @@
-// 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.
#ifndef CHROME_BROWSER_SYNC_UTIL_USER_SETTINGS_H_
#define CHROME_BROWSER_SYNC_UTIL_USER_SETTINGS_H_
+#pragma once
#include <map>
-#include <set>
#include <string>
-#include "base/file_path.h"
#include "base/lock.h"
#include "build/build_config.h"
-#include "chrome/browser/sync/util/sync_types.h"
extern "C" struct sqlite3;
+class FilePath;
+
namespace browser_sync {
void ExecOrDie(sqlite3* dbhandle, const char *query);
diff --git a/chrome/browser/sync/util/user_settings_posix.cc b/chrome/browser/sync/util/user_settings_posix.cc
index f3f6cdc..71fda9f 100644
--- a/chrome/browser/sync/util/user_settings_posix.cc
+++ b/chrome/browser/sync/util/user_settings_posix.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/sync/util/user_settings.h"
+#include "base/logging.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/common/sqlite_utils.h"
diff --git a/chrome/browser/sync/util/user_settings_win.cc b/chrome/browser/sync/util/user_settings_win.cc
index 087fe6f..94090ac 100644
--- a/chrome/browser/sync/util/user_settings_win.cc
+++ b/chrome/browser/sync/util/user_settings_win.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.
@@ -6,6 +6,7 @@
#include <string>
+#include "base/logging.h"
#include "chrome/browser/sync/util/crypto_helpers.h"
#include "chrome/browser/sync/util/data_encryption.h"
#include "chrome/common/sqlite_utils.h"
diff --git a/chrome/browser/tab_closeable_state_watcher.cc b/chrome/browser/tab_closeable_state_watcher.cc
index eb0ac81..198dee5 100644
--- a/chrome/browser/tab_closeable_state_watcher.cc
+++ b/chrome/browser/tab_closeable_state_watcher.cc
@@ -27,4 +27,3 @@
watcher = new ::TabCloseableStateWatcher();
return watcher;
}
-
diff --git a/chrome/browser/tab_closeable_state_watcher.h b/chrome/browser/tab_closeable_state_watcher.h
index c7a3360..8ee81c3 100644
--- a/chrome/browser/tab_closeable_state_watcher.h
+++ b/chrome/browser/tab_closeable_state_watcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CLOSEABLE_STATE_WATCHER_H_
#define CHROME_BROWSER_TAB_CLOSEABLE_STATE_WATCHER_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc
index f8c466d..ee459e1 100644
--- a/chrome/browser/tab_contents/background_contents.cc
+++ b/chrome/browser/tab_contents/background_contents.cc
@@ -5,11 +5,7 @@
#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/browser/background_contents_service.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_list.h"
#include "chrome/browser/browsing_instance.h"
-#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/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
@@ -17,21 +13,20 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/view_types.h"
-#include "chrome/common/render_messages.h"
-
+#include "chrome/common/render_messages_params.h"
+#include "gfx/rect.h"
////////////////
// BackgroundContents
BackgroundContents::BackgroundContents(SiteInstance* site_instance,
- int routing_id) {
+ int routing_id,
+ Delegate* delegate)
+ : delegate_(delegate) {
Profile* profile = site_instance->browsing_instance()->profile();
// TODO(rafaelw): Implement correct session storage.
- int64 session_storage_namespace_id = profile->GetWebKitContext()->
- dom_storage_context()->AllocateSessionStorageNamespaceId();
- render_view_host_ = new RenderViewHost(site_instance, this, routing_id,
- session_storage_namespace_id);
+ render_view_host_ = new RenderViewHost(site_instance, this, routing_id, NULL);
render_view_host_->AllowScriptToClose(true);
// Close ourselves when the application is shutting down.
@@ -47,7 +42,8 @@ BackgroundContents::BackgroundContents(SiteInstance* site_instance,
// Exposed to allow creating mocks.
BackgroundContents::BackgroundContents()
- : render_view_host_(NULL) {
+ : delegate_(NULL),
+ render_view_host_(NULL) {
}
void BackgroundContents::Observe(NotificationType type,
@@ -113,12 +109,6 @@ void BackgroundContents::RunJavaScriptMessage(
*did_suppress_message = true;
}
-std::wstring BackgroundContents::GetMessageBoxTitle(const GURL& frame_url,
- bool is_alert) {
- NOTIMPLEMENTED();
- return L"";
-}
-
gfx::NativeWindow BackgroundContents::GetMessageBoxRootWindow() {
NOTIMPLEMENTED();
return NULL;
@@ -154,27 +144,25 @@ WebPreferences BackgroundContents::GetWebkitPrefs() {
false); // is_dom_ui
}
-void BackgroundContents::ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
+void BackgroundContents::ProcessDOMUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {
// TODO(rafaelw): It may make sense for extensions to be able to open
// BackgroundContents to chrome-extension://<id> pages. Consider implementing.
- render_view_host_->BlockExtensionRequest(request_id);
+ render_view_host_->BlockExtensionRequest(params.request_id);
}
void BackgroundContents::CreateNewWindow(
int route_id,
WindowContainerType window_container_type,
const string16& frame_name) {
- delegate_view_helper_.CreateNewWindow(route_id,
- render_view_host_->process()->profile(),
- render_view_host_->site_instance(),
- DOMUIFactory::GetDOMUIType(url_),
- this,
- window_container_type,
- frame_name);
+ delegate_view_helper_.CreateNewWindow(
+ route_id,
+ render_view_host_->process()->profile(),
+ render_view_host_->site_instance(),
+ DOMUIFactory::GetDOMUIType(render_view_host_->process()->profile(), url_),
+ this,
+ window_container_type,
+ frame_name);
}
void BackgroundContents::CreateNewWidget(int route_id,
@@ -182,19 +170,18 @@ void BackgroundContents::CreateNewWidget(int route_id,
NOTREACHED();
}
+void BackgroundContents::CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type) {
+ NOTREACHED();
+}
+
void BackgroundContents::ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
bool user_gesture) {
TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id);
- if (!contents)
- return;
- Browser* browser = BrowserList::GetLastActiveWithProfile(
- render_view_host_->process()->profile());
- if (!browser)
- return;
-
- browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
+ if (contents)
+ delegate_->AddTabContents(contents, disposition, initial_pos, user_gesture);
}
void BackgroundContents::ShowCreatedWidget(int route_id,
@@ -202,3 +189,6 @@ void BackgroundContents::ShowCreatedWidget(int route_id,
NOTIMPLEMENTED();
}
+void BackgroundContents::ShowCreatedFullscreenWidget(int route_id) {
+ NOTIMPLEMENTED();
+}
diff --git a/chrome/browser/tab_contents/background_contents.h b/chrome/browser/tab_contents/background_contents.h
index 6b94c82..6743291 100644
--- a/chrome/browser/tab_contents/background_contents.h
+++ b/chrome/browser/tab_contents/background_contents.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_BACKGROUND_CONTENTS_H_
#define CHROME_BROWSER_TAB_CONTENTS_BACKGROUND_CONTENTS_H_
+#pragma once
#include <string>
@@ -14,12 +15,15 @@
#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 RenderWidgetHost;
-class RenderWidgetHostView;
class TabContents;
struct WebPreferences;
+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
@@ -30,8 +34,23 @@ class BackgroundContents : public RenderViewHostDelegate,
public NotificationObserver,
public JavaScriptMessageBoxClient {
public:
+ class Delegate {
+ public:
+ // Called by ShowCreatedWindow. Asks the delegate to attach the opened
+ // TabContents to a suitable container (e.g. browser) or to show it if it's
+ // a popup window.
+ virtual void AddTabContents(TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
BackgroundContents(SiteInstance* site_instance,
- int routing_id);
+ int routing_id,
+ Delegate* delegate);
virtual ~BackgroundContents();
// Provide access to the RenderViewHost for the
@@ -50,11 +69,7 @@ class BackgroundContents : public RenderViewHostDelegate,
virtual void DidNavigate(RenderViewHost* render_view_host,
const ViewHostMsg_FrameNavigate_Params& params);
virtual WebPreferences GetWebkitPrefs();
- virtual void ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback);
+ virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params);
virtual void RunJavaScriptMessage(const std::wstring& message,
const std::wstring& default_prompt,
const GURL& frame_url,
@@ -70,12 +85,15 @@ class BackgroundContents : public RenderViewHostDelegate,
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 StartDragging(const WebDropData& drop_data,
WebKit::WebDragOperationsMask allowed_operations,
@@ -84,13 +102,19 @@ class BackgroundContents : public RenderViewHostDelegate,
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) {
return false;
}
virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
- virtual void HandleMouseEvent() {}
+ virtual void HandleMouseMove() {}
+ virtual void HandleMouseDown() {}
virtual void HandleMouseLeave() {}
+ virtual void HandleMouseUp() {}
+ virtual void HandleMouseActivate() {}
virtual void UpdatePreferredSize(const gfx::Size& new_size) {}
// NotificationObserver
@@ -99,8 +123,6 @@ class BackgroundContents : public RenderViewHostDelegate,
const NotificationDetails& details);
// JavaScriptMessageBoxClient
- virtual std::wstring GetMessageBoxTitle(const GURL& frame_url,
- bool is_alert);
virtual gfx::NativeWindow GetMessageBoxRootWindow();
virtual void OnMessageBoxClosed(IPC::Message* reply_msg,
bool success,
@@ -114,6 +136,9 @@ class BackgroundContents : public RenderViewHostDelegate,
BackgroundContents();
private:
+ // The delegate for this BackgroundContents.
+ Delegate* delegate_;
+
// The host for our HTML content.
RenderViewHost* render_view_host_;
diff --git a/chrome/browser/tab_contents/constrained_window.h b/chrome/browser/tab_contents/constrained_window.h
index 3dc6592..2143e99 100644
--- a/chrome/browser/tab_contents/constrained_window.h
+++ b/chrome/browser/tab_contents/constrained_window.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_CONSTRAINED_WINDOW_H_
#define CHROME_BROWSER_TAB_CONTENTS_CONSTRAINED_WINDOW_H_
+#pragma once
#include "build/build_config.h"
@@ -53,6 +54,9 @@ class ConstrainedWindow {
// Sets focus on the Constrained Window.
virtual void FocusConstrainedWindow() {}
+
+ protected:
+ virtual ~ConstrainedWindow() {}
};
#endif // CHROME_BROWSER_TAB_CONTENTS_CONSTRAINED_WINDOW_H_
diff --git a/chrome/browser/tab_contents/infobar_delegate.cc b/chrome/browser/tab_contents/infobar_delegate.cc
index b703c7a..aae8553 100644
--- a/chrome/browser/tab_contents/infobar_delegate.cc
+++ b/chrome/browser/tab_contents/infobar_delegate.cc
@@ -55,14 +55,14 @@ LinkInfoBarDelegate::LinkInfoBarDelegate(TabContents* contents)
// ConfirmInfoBarDelegate: -----------------------------------------------------
-std::wstring ConfirmInfoBarDelegate::GetButtonLabel(
+string16 ConfirmInfoBarDelegate::GetButtonLabel(
InfoBarButton button) const {
if (button == BUTTON_OK)
- return l10n_util::GetString(IDS_OK);
+ return l10n_util::GetStringUTF16(IDS_OK);
if (button == BUTTON_CANCEL)
- return l10n_util::GetString(IDS_CANCEL);
+ return l10n_util::GetStringUTF16(IDS_CANCEL);
NOTREACHED();
- return std::wstring();
+ return string16();
}
ConfirmInfoBarDelegate::ConfirmInfoBarDelegate(TabContents* contents)
@@ -73,7 +73,7 @@ ConfirmInfoBarDelegate::ConfirmInfoBarDelegate(TabContents* contents)
SimpleAlertInfoBarDelegate::SimpleAlertInfoBarDelegate(
TabContents* contents,
- const std::wstring& message,
+ const string16& message,
SkBitmap* icon,
bool auto_expire)
: AlertInfoBarDelegate(contents),
@@ -90,7 +90,7 @@ bool SimpleAlertInfoBarDelegate::ShouldExpire(
return false;
}
-std::wstring SimpleAlertInfoBarDelegate::GetMessageText() const {
+string16 SimpleAlertInfoBarDelegate::GetMessageText() const {
return message_;
}
diff --git a/chrome/browser/tab_contents/infobar_delegate.h b/chrome/browser/tab_contents/infobar_delegate.h
index 3c8b714..4da3510 100644
--- a/chrome/browser/tab_contents/infobar_delegate.h
+++ b/chrome/browser/tab_contents/infobar_delegate.h
@@ -4,10 +4,10 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_TAB_CONTENTS_INFOBAR_DELEGATE_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
+#include "base/string16.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "webkit/glue/window_open_disposition.h"
@@ -48,10 +48,8 @@ class InfoBarDelegate {
// The type of the infobar. It controls its appearance, such as its background
// color.
enum Type {
- INFO_TYPE,
WARNING_TYPE,
- ERROR_TYPE,
- PAGE_ACTION_TYPE
+ PAGE_ACTION_TYPE,
};
// Returns true if the supplied |delegate| is equal to this one. Equality is
@@ -156,7 +154,7 @@ class InfoBarDelegate {
class AlertInfoBarDelegate : public InfoBarDelegate {
public:
// Returns the message string to be displayed for the InfoBar.
- virtual std::wstring GetMessageText() const = 0;
+ virtual string16 GetMessageText() const = 0;
// Overridden from InfoBarDelegate.
virtual SkBitmap* GetIcon() const { return NULL; }
@@ -178,15 +176,15 @@ class LinkInfoBarDelegate : public InfoBarDelegate {
public:
// Returns the message string to be displayed in the InfoBar. |link_offset|
// is the position where the link should be inserted. If |link_offset| is set
- // to std::wstring::npos (it is by default), the link is right aligned within
+ // to string16::npos (it is by default), the link is right aligned within
// the InfoBar rather than being embedded in the message text.
- virtual std::wstring GetMessageTextWithOffset(size_t* link_offset) const {
- *link_offset = std::wstring::npos;
- return std::wstring();
+ virtual string16 GetMessageTextWithOffset(size_t* link_offset) const {
+ *link_offset = string16::npos;
+ return string16();
}
// Returns the text of the link to be displayed.
- virtual std::wstring GetLinkText() const = 0;
+ virtual string16 GetLinkText() const = 0;
// Overridden from InfoBarDelegate.
virtual SkBitmap* GetIcon() const { return NULL; }
@@ -231,7 +229,7 @@ class ConfirmInfoBarDelegate : public AlertInfoBarDelegate {
// Return the label for the specified button. The default implementation
// returns "OK" for the OK button and "Cancel" for the Cancel button.
- virtual std::wstring GetButtonLabel(InfoBarButton button) const;
+ virtual string16 GetButtonLabel(InfoBarButton button) const;
// Return whether or not the specified button needs elevation.
virtual bool NeedElevation(InfoBarButton button) const { return false; }
@@ -246,8 +244,8 @@ class ConfirmInfoBarDelegate : public AlertInfoBarDelegate {
// Returns the text of the link to be displayed, if any. Otherwise returns
// and empty string.
- virtual std::wstring GetLinkText() {
- return std::wstring();
+ virtual string16 GetLinkText() {
+ return string16();
}
// Called when the Link is clicked. The |disposition| specifies how the
@@ -278,19 +276,19 @@ class SimpleAlertInfoBarDelegate : public AlertInfoBarDelegate {
public:
// |icon| may be |NULL|.
SimpleAlertInfoBarDelegate(TabContents* contents,
- const std::wstring& message,
+ const string16& message,
SkBitmap* icon,
bool auto_expire);
// Overridden from AlertInfoBarDelegate:
virtual bool ShouldExpire(
const NavigationController::LoadCommittedDetails& details) const;
- virtual std::wstring GetMessageText() const;
+ virtual string16 GetMessageText() const;
virtual SkBitmap* GetIcon() const;
virtual void InfoBarClosed();
private:
- std::wstring message_;
+ string16 message_;
SkBitmap* icon_;
bool auto_expire_; // Should it expire automatically on navigation?
diff --git a/chrome/browser/tab_contents/interstitial_page.cc b/chrome/browser/tab_contents/interstitial_page.cc
index 10c8d7c..62afe65 100644
--- a/chrome/browser/tab_contents/interstitial_page.cc
+++ b/chrome/browser/tab_contents/interstitial_page.cc
@@ -8,6 +8,7 @@
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
@@ -93,12 +94,15 @@ class InterstitialPage::InterstitialPageRVHViewDelegate
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 StartDragging(const WebDropData& drop_data,
WebDragOperationsMask operations_allowed,
@@ -107,11 +111,17 @@ class InterstitialPage::InterstitialPageRVHViewDelegate
virtual void UpdateDragCursor(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 HandleMouseEvent();
+ virtual void HandleMouseMove();
+ virtual void HandleMouseDown();
virtual void HandleMouseLeave();
+ virtual void HandleMouseUp();
+ virtual void HandleMouseActivate();
virtual void OnFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
@@ -136,6 +146,7 @@ InterstitialPage::InterstitialPage(TabContents* tab,
url_(url),
new_navigation_(new_navigation),
should_discard_pending_nav_entry_(new_navigation),
+ reload_on_dont_proceed_(false),
enabled_(true),
action_taken_(NO_ACTION),
render_view_host_(NULL),
@@ -158,20 +169,22 @@ InterstitialPage::InterstitialPage(TabContents* tab,
InterstitialPage::~InterstitialPage() {
InterstitialPageMap::iterator iter = tab_to_interstitial_page_->find(tab_);
- DCHECK(iter != tab_to_interstitial_page_->end()) <<
- "InterstitialPage missing from map. Please add a comment to the bug "
- "http://crbug.com/9442 with the URL you were visiting";
+ DCHECK(iter != tab_to_interstitial_page_->end());
if (iter != tab_to_interstitial_page_->end())
tab_to_interstitial_page_->erase(iter);
DCHECK(!render_view_host_);
}
void InterstitialPage::Show() {
- // If an interstitial is already showing, close it before showing the new one.
+ // If an interstitial is already showing or about to be shown, close it before
+ // showing the new one.
// Be careful not to take an action on the old interstitial more than once.
- if (tab_->interstitial_page()) {
- if (tab_->interstitial_page()->action_taken_ != NO_ACTION) {
- tab_->interstitial_page()->Hide();
+ InterstitialPageMap::const_iterator iter =
+ tab_to_interstitial_page_->find(tab_);
+ if (iter != tab_to_interstitial_page_->end()) {
+ InterstitialPage* interstitial = iter->second;
+ if (interstitial->action_taken_ != NO_ACTION) {
+ interstitial->Hide();
} else {
// If we are currently showing an interstitial page for which we created
// a transient entry and a new interstitial is shown as the result of a
@@ -179,9 +192,9 @@ void InterstitialPage::Show() {
// been discarded and a new pending navigation entry created.
// So we should not discard that new pending navigation entry.
// See http://crbug.com/9791
- if (new_navigation_ && tab_->interstitial_page()->new_navigation_)
- tab_->interstitial_page()->should_discard_pending_nav_entry_= false;
- tab_->interstitial_page()->DontProceed();
+ if (new_navigation_ && interstitial->new_navigation_)
+ interstitial->should_discard_pending_nav_entry_= false;
+ interstitial->DontProceed();
}
}
@@ -196,8 +209,7 @@ void InterstitialPage::Show() {
Source<RenderWidgetHost>(tab_->render_view_host()));
// Update the tab_to_interstitial_page_ map.
- InterstitialPageMap::const_iterator iter =
- tab_to_interstitial_page_->find(tab_);
+ iter = tab_to_interstitial_page_->find(tab_);
DCHECK(iter == tab_to_interstitial_page_->end());
(*tab_to_interstitial_page_)[tab_] = this;
@@ -390,6 +402,10 @@ void InterstitialPage::DomOperationResponse(const std::string& json_string,
CommandReceived(json_string);
}
+RendererPreferences InterstitialPage::GetRendererPrefs(Profile* profile) const {
+ return renderer_preferences_;
+}
+
RenderViewHost* InterstitialPage::CreateRenderViewHost() {
RenderViewHost* render_view_host = new RenderViewHost(
SiteInstance::CreateSiteInstance(tab()->profile()),
@@ -404,12 +420,7 @@ TabContentsView* InterstitialPage::CreateTabContentsView() {
render_view_host_->set_view(view);
render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION);
- scoped_refptr<URLRequestContextGetter> request_context =
- tab()->request_context();
- if (!request_context.get())
- request_context = tab()->profile()->GetRequestContext();
-
- render_view_host_->CreateRenderView(request_context.get(), string16());
+ render_view_host_->CreateRenderView(string16());
view->SetSize(tab_contents_view->GetContainerSize());
// Don't show the interstitial until we have navigated to it.
view->Hide();
@@ -468,6 +479,9 @@ void InterstitialPage::DontProceed() {
tab_->controller().DiscardNonCommittedEntries();
}
+ if (reload_on_dont_proceed_)
+ tab_->controller().Reload(true);
+
Hide();
// WARNING: we are now deleted!
}
@@ -487,7 +501,7 @@ void InterstitialPage::CancelForNavigation() {
}
void InterstitialPage::SetSize(const gfx::Size& size) {
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if !defined(OS_MACOSX)
// When a tab is closed, we might be resized after our view was NULLed
// (typically if there was an info-bar).
if (render_view_host_->view())
@@ -572,6 +586,13 @@ void InterstitialPage::InterstitialPageRVHViewDelegate::CreateNewWidget(
NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
}
+void
+InterstitialPage::InterstitialPageRVHViewDelegate::CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type) {
+ NOTREACHED()
+ << "InterstitialPage does not support showing full screen popups.";
+}
+
void InterstitialPage::InterstitialPageRVHViewDelegate::ShowCreatedWindow(
int route_id, WindowOpenDisposition disposition,
const gfx::Rect& initial_pos, bool user_gesture) {
@@ -583,6 +604,13 @@ void InterstitialPage::InterstitialPageRVHViewDelegate::ShowCreatedWidget(
NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
}
+void
+InterstitialPage::InterstitialPageRVHViewDelegate::ShowCreatedFullscreenWidget(
+ int route_id) {
+ NOTREACHED()
+ << "InterstitialPage does not support showing full screen popups.";
+}
+
void InterstitialPage::InterstitialPageRVHViewDelegate::ShowContextMenu(
const ContextMenuParams& params) {
}
@@ -613,6 +641,19 @@ void InterstitialPage::InterstitialPageRVHViewDelegate::TakeFocus(
interstitial_page_->tab()->GetViewDelegate()->TakeFocus(reverse);
}
+void InterstitialPage::InterstitialPageRVHViewDelegate::LostCapture() {
+}
+
+void InterstitialPage::InterstitialPageRVHViewDelegate::Activate() {
+ if (interstitial_page_->tab() && interstitial_page_->tab()->GetViewDelegate())
+ interstitial_page_->tab()->GetViewDelegate()->Activate();
+}
+
+void InterstitialPage::InterstitialPageRVHViewDelegate::Deactivate() {
+ if (interstitial_page_->tab() && interstitial_page_->tab()->GetViewDelegate())
+ interstitial_page_->tab()->GetViewDelegate()->Deactivate();
+}
+
bool InterstitialPage::InterstitialPageRVHViewDelegate::PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
if (interstitial_page_->tab() && interstitial_page_->tab()->GetViewDelegate())
@@ -627,9 +668,14 @@ void InterstitialPage::InterstitialPageRVHViewDelegate::HandleKeyboardEvent(
interstitial_page_->tab()->GetViewDelegate()->HandleKeyboardEvent(event);
}
-void InterstitialPage::InterstitialPageRVHViewDelegate::HandleMouseEvent() {
+void InterstitialPage::InterstitialPageRVHViewDelegate::HandleMouseMove() {
if (interstitial_page_->tab() && interstitial_page_->tab()->GetViewDelegate())
- interstitial_page_->tab()->GetViewDelegate()->HandleMouseEvent();
+ interstitial_page_->tab()->GetViewDelegate()->HandleMouseMove();
+}
+
+void InterstitialPage::InterstitialPageRVHViewDelegate::HandleMouseDown() {
+ if (interstitial_page_->tab() && interstitial_page_->tab()->GetViewDelegate())
+ interstitial_page_->tab()->GetViewDelegate()->HandleMouseDown();
}
void InterstitialPage::InterstitialPageRVHViewDelegate::HandleMouseLeave() {
@@ -637,6 +683,12 @@ void InterstitialPage::InterstitialPageRVHViewDelegate::HandleMouseLeave() {
interstitial_page_->tab()->GetViewDelegate()->HandleMouseLeave();
}
+void InterstitialPage::InterstitialPageRVHViewDelegate::HandleMouseUp() {
+}
+
+void InterstitialPage::InterstitialPageRVHViewDelegate::HandleMouseActivate() {
+}
+
void InterstitialPage::InterstitialPageRVHViewDelegate::OnFindReply(
int request_id, int number_of_matches, const gfx::Rect& selection_rect,
int active_match_ordinal, bool final_update) {
diff --git a/chrome/browser/tab_contents/interstitial_page.h b/chrome/browser/tab_contents/interstitial_page.h
index 07ea419..097fbde 100644
--- a/chrome/browser/tab_contents/interstitial_page.h
+++ b/chrome/browser/tab_contents/interstitial_page.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_INTERSTITIAL_PAGE_H_
#define CHROME_BROWSER_TAB_CONTENTS_INTERSTITIAL_PAGE_H_
+#pragma once
#include <map>
#include <string>
#include "base/scoped_ptr.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/renderer_preferences.h"
#include "gfx/size.h"
@@ -103,6 +105,12 @@ class InterstitialPage : public NotificationObserver,
}
virtual int GetBrowserWindowID() const;
+ // See description above field.
+ void set_reload_on_dont_proceed(bool value) {
+ reload_on_dont_proceed_ = value;
+ }
+ bool reload_on_dont_proceed() const { return reload_on_dont_proceed_; }
+
protected:
// NotificationObserver method:
virtual void Observe(NotificationType type,
@@ -120,9 +128,7 @@ class InterstitialPage : public NotificationObserver,
const std::wstring& title);
virtual void DomOperationResponse(const std::string& json_string,
int automation_id);
- virtual RendererPreferences GetRendererPrefs(Profile* profile) const {
- return renderer_preferences_;
- }
+ virtual RendererPreferences GetRendererPrefs(Profile* profile) const;
// Invoked when the page sent a command through DOMAutomation.
virtual void CommandReceived(const std::string& command) {}
@@ -183,6 +189,12 @@ class InterstitialPage : public NotificationObserver,
// not discard it.
bool should_discard_pending_nav_entry_;
+ // If true and the user chooses not to proceed the target NavigationController
+ // is reloaded. This is used when two NavigationControllers are merged
+ // (CopyStateFromAndPrune).
+ // The default is false.
+ bool reload_on_dont_proceed_;
+
// Whether this interstitial is enabled. See Disable() for more info.
bool enabled_;
diff --git a/chrome/browser/tab_contents/language_state.cc b/chrome/browser/tab_contents/language_state.cc
index 2808b2a..5f78876 100644
--- a/chrome/browser/tab_contents/language_state.cc
+++ b/chrome/browser/tab_contents/language_state.cc
@@ -18,11 +18,14 @@ LanguageState::LanguageState(NavigationController* nav_controller)
LanguageState::~LanguageState() {
}
-void LanguageState::DidNavigate(bool reload, bool in_page) {
- in_page_navigation_ = in_page;
- if (in_page)
+void LanguageState::DidNavigate(
+ const NavigationController::LoadCommittedDetails& details) {
+ in_page_navigation_ = details.is_in_page;
+ if (in_page_navigation_ || !details.is_main_frame)
return; // Don't reset our states, the page has not changed.
+ bool reload = details.entry->transition_type() == PageTransition::RELOAD ||
+ details.type == NavigationType::SAME_PAGE;
if (reload) {
// We might not get a LanguageDetermined notifications on reloads. Make sure
// to keep the original language and to set current_lang_ so
diff --git a/chrome/browser/tab_contents/language_state.h b/chrome/browser/tab_contents/language_state.h
index 8cbdfd7..b3728a3 100644
--- a/chrome/browser/tab_contents/language_state.h
+++ b/chrome/browser/tab_contents/language_state.h
@@ -4,12 +4,12 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_LANGUAGE_STATE_H_
#define CHROME_BROWSER_TAB_CONTENTS_LANGUAGE_STATE_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
-
-class NavigationController;
+#include "chrome/browser/tab_contents/navigation_controller.h"
// This class holds the language state of the current page.
// There is one LanguageState instance per TabContents.
@@ -27,7 +27,7 @@ class LanguageState {
// Should be called when the page did a new navigation (whether it is a main
// frame or sub-frame navigation).
- void DidNavigate(bool reload, bool in_page_navigation);
+ void DidNavigate(const NavigationController::LoadCommittedDetails& details);
// Should be called when the language of the page has been determined.
// |page_translatable| when false indicates that the browser should not offer
diff --git a/chrome/browser/tab_contents/navigation_controller.cc b/chrome/browser/tab_contents/navigation_controller.cc
index 5b0e157..084f13e 100644
--- a/chrome/browser/tab_contents/navigation_controller.cc
+++ b/chrome/browser/tab_contents/navigation_controller.cc
@@ -1,20 +1,19 @@
-// 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.
#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "app/resource_bundle.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#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/dom_storage_context.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/pref_service.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/renderer_host/site_instance.h"
#include "chrome/browser/sessions/session_types.h"
@@ -26,7 +25,7 @@
#include "chrome/common/navigation_types.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
#include "grit/app_resources.h"
#include "net/base/escape.h"
@@ -37,8 +36,7 @@
namespace {
const int kInvalidateAllButShelves =
- 0xFFFFFFFF & ~(TabContents::INVALIDATE_BOOKMARK_BAR |
- TabContents::INVALIDATE_EXTENSION_SHELF);
+ 0xFFFFFFFF & ~TabContents::INVALIDATE_BOOKMARK_BAR;
// Invoked when entries have been pruned, or removed. For example, if the
// current entries are [google, digg, yahoo], with the current entry google,
@@ -104,12 +102,6 @@ bool AreURLsInPageNavigation(const GURL& existing_url, const GURL& new_url) {
new_url.ReplaceComponents(replacements);
}
-// Navigation within this limit since the last document load is considered to
-// be automatic (i.e., machine-initiated) rather than user-initiated unless
-// a user gesture has been observed.
-const base::TimeDelta kMaxAutoNavigationTimeDelta =
- base::TimeDelta::FromSeconds(5);
-
} // namespace
// NavigationController ---------------------------------------------------
@@ -121,8 +113,10 @@ size_t NavigationController::max_entry_count_ =
// static
bool NavigationController::check_for_repost_ = true;
-NavigationController::NavigationController(TabContents* contents,
- Profile* profile)
+NavigationController::NavigationController(
+ TabContents* contents,
+ Profile* profile,
+ SessionStorageNamespace* session_storage_namespace)
: profile_(profile),
pending_entry_(NULL),
last_committed_entry_index_(-1),
@@ -132,11 +126,11 @@ NavigationController::NavigationController(TabContents* contents,
max_restored_page_id_(-1),
ALLOW_THIS_IN_INITIALIZER_LIST(ssl_manager_(this)),
needs_reload_(false),
- user_gesture_observed_(false),
- session_storage_namespace_id_(profile->GetWebKitContext()->
- dom_storage_context()->AllocateSessionStorageNamespaceId()),
+ session_storage_namespace_(session_storage_namespace),
pending_reload_(NO_RELOAD) {
DCHECK(profile_);
+ if (!session_storage_namespace_)
+ session_storage_namespace_ = new SessionStorageNamespace(profile_);
}
NavigationController::~NavigationController() {
@@ -146,10 +140,6 @@ NavigationController::~NavigationController() {
NotificationType::TAB_CLOSED,
Source<NavigationController>(this),
NotificationService::NoDetails());
-
- // When we go away, the session storage namespace will no longer be reachable.
- profile_->GetWebKitContext()->DeleteSessionStorageNamespace(
- session_storage_namespace_id_);
}
void NavigationController::RestoreFromState(
@@ -258,9 +248,9 @@ NavigationEntry* NavigationController::CreateNavigationEntry(
// Use the filename as the title, not the full path.
// We need to call FormatUrl() to perform URL de-escaping;
// it's a bit ugly to grab the filename out of the resulting string.
- std::wstring languages = UTF8ToWide(profile->GetPrefs()->GetString(
- prefs::kAcceptLanguages));
- std::wstring formatted = net::FormatUrl(url, languages);
+ std::string languages =
+ profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
+ std::wstring formatted = UTF16ToWideHack(net::FormatUrl(url, languages));
std::wstring filename =
FilePath::FromWStringHack(formatted).BaseName().ToWStringHack();
entry->set_title(WideToUTF16Hack(filename));
@@ -360,6 +350,9 @@ void NavigationController::GoBack() {
DiscardNonCommittedEntries();
pending_entry_index_ = current_index - 1;
+ entries_[pending_entry_index_]->set_transition_type(
+ entries_[pending_entry_index_]->transition_type() |
+ PageTransition::FORWARD_BACK);
NavigateToPendingEntry(NO_RELOAD);
}
@@ -390,6 +383,9 @@ void NavigationController::GoForward() {
if (!transient)
pending_entry_index_++;
+ entries_[pending_entry_index_]->set_transition_type(
+ entries_[pending_entry_index_]->transition_type() |
+ PageTransition::FORWARD_BACK);
NavigateToPendingEntry(NO_RELOAD);
}
@@ -428,6 +424,9 @@ void NavigationController::GoToIndex(int index) {
DiscardNonCommittedEntries();
pending_entry_index_ = index;
+ entries_[pending_entry_index_]->set_transition_type(
+ entries_[pending_entry_index_]->transition_type() |
+ PageTransition::FORWARD_BACK);
NavigateToPendingEntry(NO_RELOAD);
}
@@ -482,7 +481,7 @@ void NavigationController::AddTransientEntry(NavigationEntry* entry) {
index = last_committed_entry_index_ + 1;
DiscardTransientEntry();
entries_.insert(entries_.begin() + index, linked_ptr<NavigationEntry>(entry));
- transient_entry_index_ = index;
+ transient_entry_index_ = index;
tab_contents_->NotifyNavigationStateChanged(kInvalidateAllButShelves);
}
@@ -501,14 +500,11 @@ void NavigationController::DocumentLoadedInFrame() {
last_document_loaded_ = base::TimeTicks::Now();
}
-void NavigationController::OnUserGesture() {
- user_gesture_observed_ = true;
-}
-
bool NavigationController::RendererDidNavigate(
const ViewHostMsg_FrameNavigate_Params& params,
int extra_invalidate_flags,
LoadCommittedDetails* details) {
+
// Save the previous state before we clobber it.
if (GetLastCommittedEntry()) {
details->previous_url = GetLastCommittedEntry()->url();
@@ -536,6 +532,7 @@ bool NavigationController::RendererDidNavigate(
// Do navigation-type specific actions. These will make and commit an entry.
details->type = ClassifyNavigation(params);
+
switch (details->type) {
case NavigationType::NEW_PAGE:
RendererDidNavigateToNewPage(params, &(details->did_replace_entry));
@@ -695,11 +692,6 @@ bool NavigationController::IsRedirect(
return params.redirects.size() > 1;
}
-bool NavigationController::IsLikelyAutoNavigation(base::TimeTicks now) {
- return !user_gesture_observed_ &&
- (now - last_document_loaded_) < kMaxAutoNavigationTimeDelta;
-}
-
void NavigationController::CreateNavigationEntriesFromTabNavigations(
const std::vector<TabNavigation>& navigations,
std::vector<linked_ptr<NavigationEntry> >* entries) {
@@ -740,14 +732,6 @@ void NavigationController::RendererDidNavigateToNewPage(
new_entry->set_site_instance(tab_contents_->GetSiteInstance());
new_entry->set_has_post_data(params.is_post);
- // If the current entry is a redirection source and the redirection has
- // occurred within kMaxAutoNavigationTimeDelta since the last document load,
- // this is likely to be machine-initiated redirect and the entry needs to be
- // replaced with the new entry to avoid unwanted redirections in navigating
- // backward/forward.
- // Otherwise, just insert the new entry.
- *did_replace_entry = IsRedirect(params) &&
- IsLikelyAutoNavigation(base::TimeTicks::Now());
InsertOrReplaceEntry(new_entry, *did_replace_entry);
}
@@ -953,22 +937,88 @@ void NavigationController::CopyStateFrom(const NavigationController& source) {
return; // Nothing new to do.
needs_reload_ = true;
- for (int i = 0; i < source.entry_count(); i++) {
- // When cloning a tab, copy all entries except interstitial pages
- if (source.entries_[i].get()->page_type() !=
- NavigationEntry::INTERSTITIAL_PAGE) {
- entries_.push_back(linked_ptr<NavigationEntry>(
- new NavigationEntry(*source.entries_[i])));
- }
- }
+ InsertEntriesFrom(source, source.entry_count());
- session_storage_namespace_id_ =
- profile_->GetWebKitContext()->dom_storage_context()->CloneSessionStorage(
- source.session_storage_namespace_id_);
+ session_storage_namespace_ = source.session_storage_namespace_->Clone();
FinishRestore(source.last_committed_entry_index_, false);
}
+void NavigationController::CopyStateFromAndPrune(
+ const NavigationController& source) {
+ // This code is intended for use when the last entry is the active entry.
+ DCHECK((transient_entry_index_ != -1 &&
+ transient_entry_index_ == entry_count() - 1) ||
+ (pending_entry_ && (pending_entry_index_ == -1 ||
+ pending_entry_index_ == entry_count() - 1)) ||
+ (!pending_entry_ && last_committed_entry_index_ == entry_count() - 1));
+
+ // Remove all the entries leaving the active entry.
+ PruneAllButActive();
+
+ // Insert the entries from source. Don't use source.GetCurrentEntryIndex as
+ // we don't want to copy over the transient entry.
+ int max_source_index = source.pending_entry_index_ != -1 ?
+ source.pending_entry_index_ : source.last_committed_entry_index_;
+ if (max_source_index == -1)
+ max_source_index = source.entry_count();
+ else
+ max_source_index++;
+ InsertEntriesFrom(source, max_source_index);
+
+ // Adjust indices such that the last entry and pending are at the end now.
+ last_committed_entry_index_ = entry_count() - 1;
+ if (pending_entry_index_ != -1)
+ pending_entry_index_ = entry_count() - 1;
+ if (transient_entry_index_ != -1) {
+ // There's a transient entry. In this case we want the last committed to
+ // point to the previous entry.
+ transient_entry_index_ = entry_count() - 1;
+ if (last_committed_entry_index_ != -1)
+ last_committed_entry_index_--;
+ }
+
+ // Take over the session id from source.
+ session_id_ = source.session_id_;
+}
+
+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_;
+ 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)
+ return;
+
+ prune_count--;
+ last_committed_entry_index_ = 0;
+ } else if (pending_entry_index_ != -1) {
+ DCHECK_EQ(pending_entry_index_, prune_count - 1);
+ 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;
+ }
+
+ if (tab_contents_->interstitial_page()) {
+ // Normally the interstitial page hides itself if the user doesn't proceeed.
+ // This would result in showing a NavigationEntry we just removed. Set this
+ // 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() {
bool transient = transient_entry_index_ != -1;
DiscardNonCommittedEntriesInternal();
@@ -1020,13 +1070,6 @@ void NavigationController::InsertOrReplaceEntry(NavigationEntry* entry,
// This is a new page ID, so we need everybody to know about it.
tab_contents_->UpdateMaxPageID(entry->page_id());
-
- // When an entry is inserted, clear the user gesture observed flag.
- // This is not done when replacing an entry (for example navigating within a
- // page) because once a user has interacted with a page, we never want to
- // mistake a subsequent navigation for an auto navigation.
- if (!replace)
- user_gesture_observed_ = false;
}
void NavigationController::SetWindowID(const SessionID& id) {
@@ -1041,7 +1084,7 @@ void NavigationController::NavigateToPendingEntry(ReloadType reload_type) {
// For session history navigations only the pending_entry_index_ is set.
if (!pending_entry_) {
- DCHECK(pending_entry_index_ != -1);
+ DCHECK_NE(pending_entry_index_, -1);
pending_entry_ = entries_[pending_entry_index_].get();
}
@@ -1109,7 +1152,7 @@ void NavigationController::FinishRestore(int selected_index,
DCHECK(selected_index >= 0 && selected_index < entry_count());
ConfigureEntriesForRestore(&entries_, from_last_session);
- set_max_restored_page_id(entry_count());
+ set_max_restored_page_id(static_cast<int32>(entry_count()));
last_committed_entry_index_ = selected_index;
}
@@ -1147,3 +1190,19 @@ NavigationEntry* NavigationController::GetTransientEntry() const {
return NULL;
return entries_[transient_entry_index_].get();
}
+
+void NavigationController::InsertEntriesFrom(
+ const NavigationController& source,
+ int max_index) {
+ DCHECK_LE(max_index, source.entry_count());
+ size_t insert_index = 0;
+ for (int i = 0; i < max_index; i++) {
+ // When cloning a tab, copy all entries except interstitial pages
+ if (source.entries_[i].get()->page_type() !=
+ NavigationEntry::INTERSTITIAL_PAGE) {
+ entries_.insert(entries_.begin() + insert_index++,
+ linked_ptr<NavigationEntry>(
+ new NavigationEntry(*source.entries_[i])));
+ }
+ }
+}
diff --git a/chrome/browser/tab_contents/navigation_controller.h b/chrome/browser/tab_contents/navigation_controller.h
index 71edcfc..24a206f 100644
--- a/chrome/browser/tab_contents/navigation_controller.h
+++ b/chrome/browser/tab_contents/navigation_controller.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_TAB_CONTENTS_NAVIGATION_CONTROLLER_H_
#define CHROME_BROWSER_TAB_CONTENTS_NAVIGATION_CONTROLLER_H_
+#pragma once
#include "build/build_config.h"
@@ -11,7 +12,6 @@
#include <vector>
#include "base/linked_ptr.h"
-#include "base/string16.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "chrome/browser/sessions/session_id.h"
@@ -20,13 +20,10 @@
#include "chrome/common/page_transition_types.h"
class NavigationEntry;
-class GURL;
class Profile;
-class TabContents;
+class SessionStorageNamespace;
class SiteInstance;
-class SkBitmap;
class TabContents;
-class TabContentsCollector;
class TabNavigation;
struct ViewHostMsg_FrameNavigate_Params;
@@ -141,7 +138,9 @@ class NavigationController {
// ---------------------------------------------------------------------------
- NavigationController(TabContents* tab_contents, Profile* profile);
+ NavigationController(TabContents* tab_contents,
+ Profile* profile,
+ SessionStorageNamespace* session_storage_namespace);
~NavigationController();
// Returns the profile for this controller. It can never be NULL.
@@ -316,9 +315,6 @@ class NavigationController {
// Called when a document has been loaded in a frame.
void DocumentLoadedInFrame();
- // Called when the user presses the mouse, enter key or space bar.
- void OnUserGesture();
-
// For use by TabContents ----------------------------------------------------
// Handles updating the navigation state after the renderer has navigated.
@@ -366,6 +362,22 @@ class NavigationController {
// one should be empty (just created).
void CopyStateFrom(const NavigationController& source);
+ // A variant of CopyStateFrom. Removes all entries from this except the last
+ // entry, inserts all entries from |source| before and including the active
+ // entry and resets the |session_id_| of this to match |source|. This is
+ // intended for use when you're going to throw away |source| and replace it
+ // with this. This method is intended for use when the last entry of |this|
+ // is the active entry. For example:
+ // source: A B *C* D
+ // this: E F *G* (last must be active or pending)
+ // result: A B *G*
+ // This ignores the transient index of the source and honors that of 'this'.
+ void CopyStateFromAndPrune(const NavigationController& source);
+
+ // Removes all the entries except the active entry. If there is a new pending
+ // navigation it is preserved.
+ void PruneAllButActive();
+
// Random data ---------------------------------------------------------------
// Returns the identifier used by session restore.
@@ -381,13 +393,19 @@ class NavigationController {
// invoked). This is true for session/tab restore and cloned tabs.
bool needs_reload() const { return needs_reload_; }
+ // Sets the max restored page ID this NavigationController has seen, if it
+ // was restored from a previous session.
+ void set_max_restored_page_id(int32 max_id) {
+ max_restored_page_id_ = max_id;
+ }
+
// Returns the largest restored page ID seen in this navigation controller,
// if it was restored from a previous session. (-1 otherwise)
- int max_restored_page_id() const { return max_restored_page_id_; }
+ int32 max_restored_page_id() const { return max_restored_page_id_; }
- // The session storage namespace id that all child render views should use.
- int64 session_storage_namespace_id() const {
- return session_storage_namespace_id_;
+ // The session storage namespace that all child render views should use.
+ SessionStorageNamespace* session_storage_namespace() const {
+ return session_storage_namespace_;
}
// Disables checking for a repost and prompting the user. This is used during
@@ -457,7 +475,7 @@ class NavigationController {
bool RendererDidNavigateAutoSubframe(
const ViewHostMsg_FrameNavigate_Params& params);
- // Helper function for code shared between Reload() and ReloadAll().
+ // Helper function for code shared between Reload() and ReloadIgnoringCache().
void ReloadInternal(bool check_for_repost, ReloadType reload_type);
// Actually issues the navigation held in pending_entry.
@@ -471,10 +489,6 @@ class NavigationController {
void NotifyNavigationEntryCommitted(LoadCommittedDetails* details,
int extra_invalidate_flags);
- // Sets the max restored page ID this NavigationController has seen, if it
- // was restored from a previous session.
- void set_max_restored_page_id(int max_id) { max_restored_page_id_ = max_id; }
-
// Updates the virtual URL of an entry to match a new URL, for cases where
// the real renderer URL is derived from the virtual URL, like view-source:
void UpdateVirtualURLToURL(NavigationEntry* entry, const GURL& new_url);
@@ -507,6 +521,12 @@ class NavigationController {
const std::vector<TabNavigation>& navigations,
std::vector<linked_ptr<NavigationEntry> >* entries);
+ // Inserts up to |max_index| entries from |source| into this. This does NOT
+ // adjust any of the members that reference entries_
+ // (last_committed_entry_index_, pending_entry_index_ or
+ // transient_entry_index_).
+ void InsertEntriesFrom(const NavigationController& source, int max_index);
+
// ---------------------------------------------------------------------------
// The user profile associated with this controller
@@ -535,7 +555,7 @@ class NavigationController {
// The index for the entry that is shown until a navigation occurs. This is
// used for interstitial pages. -1 if there are no such entry.
// Note that this entry really appears in the list of entries, but only
- // temporarily (until the next navigation). Any index poiting to an entry
+ // temporarily (until the next navigation). Any index pointing to an entry
// after the transient entry will become invalid if you navigate forward.
int transient_entry_index_;
@@ -546,7 +566,7 @@ class NavigationController {
// The max restored page ID in this controller, if it was restored. We must
// store this so that TabContents can tell any renderer in charge of one of
// the restored entries to update its max page ID.
- int max_restored_page_id_;
+ int32 max_restored_page_id_;
// Manages the SSL security UI
SSLManager ssl_manager_;
@@ -557,7 +577,7 @@ class NavigationController {
// Unique identifier of this controller for session restore. This id is only
// unique within the current session, and is not guaranteed to be unique
// across sessions.
- const SessionID session_id_;
+ SessionID session_id_;
// Unique identifier of the window we're in. Used by session restore.
SessionID window_id_;
@@ -565,11 +585,8 @@ class NavigationController {
// The time ticks at which the last document was loaded.
base::TimeTicks last_document_loaded_;
- // Whether a user gesture has been observed since the last navigation.
- bool user_gesture_observed_;
-
// The session storage id that any (indirectly) owned RenderView should use.
- int64 session_storage_namespace_id_;
+ scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
// Should Reload check for post data? The default is true, but is set to false
// when testing.
diff --git a/chrome/browser/tab_contents/navigation_controller_unittest.cc b/chrome/browser/tab_contents/navigation_controller_unittest.cc
index 0a8c677..67d1bc6 100644
--- a/chrome/browser/tab_contents/navigation_controller_unittest.cc
+++ b/chrome/browser/tab_contents/navigation_controller_unittest.cc
@@ -7,8 +7,10 @@
#include "base/scoped_ptr.h"
#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/history/history.h"
+#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_test_helper.h"
@@ -17,9 +19,11 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#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"
#include "chrome/test/testing_profile.h"
#include "net/base/net_util.h"
@@ -737,7 +741,7 @@ TEST_F(NavigationControllerTest, Redirect) {
EXPECT_EQ(controller().pending_entry_index(), -1);
EXPECT_EQ(url1, controller().GetActiveEntry()->url());
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0;
params.url = url2;
params.transition = PageTransition::SERVER_REDIRECT;
@@ -792,7 +796,7 @@ TEST_F(NavigationControllerTest, PostThenRedirect) {
EXPECT_EQ(controller().pending_entry_index(), -1);
EXPECT_EQ(url1, controller().GetActiveEntry()->url());
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0;
params.url = url2;
params.transition = PageTransition::SERVER_REDIRECT;
@@ -837,7 +841,7 @@ TEST_F(NavigationControllerTest, ImmediateRedirect) {
EXPECT_EQ(controller().pending_entry_index(), -1);
EXPECT_EQ(url1, controller().GetActiveEntry()->url());
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0;
params.url = url2;
params.transition = PageTransition::SERVER_REDIRECT;
@@ -878,7 +882,7 @@ TEST_F(NavigationControllerTest, NewSubframe) {
NotificationType::NAV_ENTRY_COMMITTED));
const GURL url2("http://foo2");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 1;
params.url = url2;
params.transition = PageTransition::MANUAL_SUBFRAME;
@@ -913,7 +917,7 @@ TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
// Navigation controller currently has no entries.
const GURL url("http://foo2");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 1;
params.url = url;
params.transition = PageTransition::AUTO_SUBFRAME;
@@ -938,7 +942,7 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
NotificationType::NAV_ENTRY_COMMITTED));
const GURL url2("http://foo2");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0;
params.url = url2;
params.transition = PageTransition::AUTO_SUBFRAME;
@@ -968,7 +972,7 @@ TEST_F(NavigationControllerTest, BackSubframe) {
// First manual subframe navigation.
const GURL url2("http://foo2");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 1;
params.url = url2;
params.transition = PageTransition::MANUAL_SUBFRAME;
@@ -1051,7 +1055,7 @@ TEST_F(NavigationControllerTest, InPage) {
// First navigation.
const GURL url2("http://foo#a");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 1;
params.url = url2;
params.transition = PageTransition::LINK;
@@ -1131,7 +1135,7 @@ TEST_F(NavigationControllerTest, InPage_Replace) {
// First navigation.
const GURL url2("http://foo#a");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0; // Same page_id
params.url = url2;
params.transition = PageTransition::LINK;
@@ -1180,7 +1184,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
// Navigate within the page.
{
const GURL url("http://foo2/#a");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 1; // Same page_id
params.url = url;
params.transition = PageTransition::LINK;
@@ -1191,7 +1195,6 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
// This should NOT generate a new entry.
NavigationController::LoadCommittedDetails details;
- controller().OnUserGesture();
EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
EXPECT_TRUE(notifications.Check2AndReset(
NotificationType::NAV_LIST_PRUNED,
@@ -1204,7 +1207,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
// Perform a client redirect to a new page.
{
const GURL url("http://foo3/");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 2; // New page_id
params.url = url;
params.transition = PageTransition::CLIENT_REDIRECT;
@@ -1325,7 +1328,7 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
navigations.push_back(TabNavigation(0, url, GURL(),
ASCIIToUTF16("Title"), "state",
PageTransition::LINK));
- TabContents our_contents(profile(), NULL, MSG_ROUTING_NONE, NULL);
+ TabContents our_contents(profile(), NULL, MSG_ROUTING_NONE, NULL, NULL);
NavigationController& our_controller = our_contents.controller();
our_controller.RestoreFromState(navigations, 0, true);
our_controller.GoToIndex(0);
@@ -1339,7 +1342,7 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
our_controller.GetEntryAtIndex(0)->restore_type());
// Say we navigated to that entry.
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0;
params.url = url;
params.transition = PageTransition::LINK;
@@ -1605,7 +1608,7 @@ TEST_F(NavigationControllerTest, SameSubframe) {
// Navigate a subframe that would normally count as in-page.
const GURL subframe("http://www.google.com/#");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0;
params.url = subframe;
params.transition = PageTransition::AUTO_SUBFRAME;
@@ -1630,7 +1633,7 @@ TEST_F(NavigationControllerTest, ViewSourceRedirect) {
controller().LoadURL(url, GURL(), PageTransition::TYPED);
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = 0;
params.url = result_url;
params.transition = PageTransition::SERVER_REDIRECT;
@@ -1693,7 +1696,7 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
// Send a subframe update from the first page, as if one had just
// automatically loaded. Auto subframes don't increment the page ID.
const GURL url1_sub("http://foo/subframe");
- ViewHostMsg_FrameNavigate_Params params = {0};
+ ViewHostMsg_FrameNavigate_Params params;
params.page_id = controller().GetLastCommittedEntry()->page_id();
params.url = url1_sub;
params.transition = PageTransition::AUTO_SUBFRAME;
@@ -1713,6 +1716,148 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
EXPECT_EQ(url2, controller().GetActiveEntry()->url());
}
+// Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
+TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+ const GURL url3("http://foo3");
+
+ NavigateAndCommit(url1);
+ NavigateAndCommit(url2);
+
+ scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
+ NavigationController& other_controller = other_contents->controller();
+ other_contents->NavigateAndCommit(url3);
+ other_controller.CopyStateFromAndPrune(controller());
+
+ // other_controller should now contain the 3 urls: url1, url2 and url3.
+
+ ASSERT_EQ(3, other_controller.entry_count());
+
+ ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
+
+ EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
+ EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->url());
+ EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->url());
+
+ // And the session id should have been copied.
+ EXPECT_EQ(controller().session_id().id(), other_controller.session_id().id());
+}
+
+// Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
+// the target.
+TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+ const GURL url3("http://foo3");
+
+ NavigateAndCommit(url1);
+ NavigateAndCommit(url2);
+ controller().GoBack();
+
+ scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
+ NavigationController& other_controller = other_contents->controller();
+ other_controller.CopyStateFromAndPrune(controller());
+
+ // other_controller should now contain the 1 url: url1.
+
+ ASSERT_EQ(1, other_controller.entry_count());
+
+ ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
+
+ EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
+
+ // And the session id should have been copied.
+ EXPECT_EQ(controller().session_id().id(), other_controller.session_id().id());
+}
+
+// Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
+// the target.
+TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+ const GURL url3("http://foo3");
+
+ NavigateAndCommit(url1);
+ NavigateAndCommit(url2);
+ controller().GoBack();
+
+ scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
+ NavigationController& other_controller = other_contents->controller();
+ other_controller.LoadURL(url3, GURL(), PageTransition::TYPED);
+ other_controller.CopyStateFromAndPrune(controller());
+
+ // other_controller should now contain 1 entry for url1, and a pending entry
+ // for url3.
+
+ ASSERT_EQ(1, other_controller.entry_count());
+
+ EXPECT_EQ(0, other_controller.GetCurrentEntryIndex());
+
+ EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
+
+ // And there should be a pending entry for url3.
+ ASSERT_TRUE(other_controller.pending_entry());
+
+ EXPECT_EQ(url3, other_controller.pending_entry()->url());
+
+ // And the session id should have been copied.
+ EXPECT_EQ(controller().session_id().id(), other_controller.session_id().id());
+}
+
+// Tests that navigations initiated from the page (with the history object)
+// work as expected without navigation entries.
+TEST_F(NavigationControllerTest, HistoryNavigate) {
+ 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();
+
+ // Casts the TabContents to a RenderViewHostDelegate::BrowserIntegration so we
+ // can call GoToEntryAtOffset which is private.
+ RenderViewHostDelegate::BrowserIntegration* rvh_delegate =
+ static_cast<RenderViewHostDelegate::BrowserIntegration*>(contents());
+
+ // Simulate the page calling history.back(), it should not create a pending
+ // entry.
+ rvh_delegate->GoToEntryAtOffset(-1);
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ // The actual cross-navigation is suspended until the current RVH tells us
+ // it unloaded, simulate that.
+ contents()->ProceedWithCrossSiteNavigation();
+ // Also make sure we told the page to navigate.
+ const IPC::Message* message =
+ process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
+ ASSERT_TRUE(message != NULL);
+ Tuple1<ViewMsg_Navigate_Params> nav_params;
+ ViewMsg_Navigate::Read(message, &nav_params);
+ EXPECT_EQ(url1, nav_params.a.url);
+ process()->sink().ClearMessages();
+
+ // Now test history.forward()
+ rvh_delegate->GoToEntryAtOffset(1);
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ // The actual cross-navigation is suspended until the current RVH tells us
+ // it unloaded, simulate that.
+ contents()->ProceedWithCrossSiteNavigation();
+ message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
+ ASSERT_TRUE(message != NULL);
+ ViewMsg_Navigate::Read(message, &nav_params);
+ EXPECT_EQ(url3, nav_params.a.url);
+ process()->sink().ClearMessages();
+
+ // Make sure an extravagant history.go() doesn't break.
+ rvh_delegate->GoToEntryAtOffset(120); // Out of bounds.
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
+ EXPECT_TRUE(message == NULL);
+}
+
/* 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 0fb4777..c345958 100644
--- a/chrome/browser/tab_contents/navigation_entry.cc
+++ b/chrome/browser/tab_contents/navigation_entry.cc
@@ -7,7 +7,7 @@
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
@@ -89,20 +89,20 @@ const string16& NavigationEntry::GetTitleForDisplay(
return cached_display_title_;
// Use the virtual URL first if any, and fall back on using the real URL.
- std::wstring languages;
+ std::string languages;
if (navigation_controller) {
- languages = UTF8ToWide(navigation_controller->profile()->GetPrefs()->
- GetString(prefs::kAcceptLanguages));
+ languages = navigation_controller->profile()->GetPrefs()->
+ GetString(prefs::kAcceptLanguages);
}
- std::wstring title;
+ string16 title;
std::wstring elided_title;
if (!virtual_url_.is_empty()) {
title = net::FormatUrl(virtual_url_, languages);
} else if (!url_.is_empty()) {
title = net::FormatUrl(url_, languages);
}
- ElideString(title, chrome::kMaxTitleChars, &elided_title);
+ ElideString(UTF16ToWideHack(title), chrome::kMaxTitleChars, &elided_title);
cached_display_title_ = WideToUTF16Hack(elided_title);
return cached_display_title_;
}
diff --git a/chrome/browser/tab_contents/navigation_entry.h b/chrome/browser/tab_contents/navigation_entry.h
index 341ebeb..9a5f6a5 100644
--- a/chrome/browser/tab_contents/navigation_entry.h
+++ b/chrome/browser/tab_contents/navigation_entry.h
@@ -4,12 +4,12 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_NAVIGATION_ENTRY_H_
#define CHROME_BROWSER_TAB_CONTENTS_NAVIGATION_ENTRY_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "chrome/browser/tab_contents/security_style.h"
#include "chrome/common/page_transition_types.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/tab_contents/navigation_entry_unittest.cc b/chrome/browser/tab_contents/navigation_entry_unittest.cc
index 4ecd1df..db59464 100644
--- a/chrome/browser/tab_contents/navigation_entry_unittest.cc
+++ b/chrome/browser/tab_contents/navigation_entry_unittest.cc
@@ -4,6 +4,7 @@
#include "base/string16.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -95,7 +96,7 @@ TEST_F(NavigationEntryTest, NavigationEntryFavicons) {
// Test SSLStatus inner class
TEST_F(NavigationEntryTest, NavigationEntrySSLStatus) {
- // Default (not secure)
+ // Default (unknown)
EXPECT_EQ(SECURITY_STYLE_UNKNOWN, entry1_.get()->ssl().security_style());
EXPECT_EQ(SECURITY_STYLE_UNKNOWN, entry2_.get()->ssl().security_style());
EXPECT_EQ(0, entry1_.get()->ssl().cert_id());
diff --git a/chrome/browser/tab_contents/page_navigator.h b/chrome/browser/tab_contents/page_navigator.h
index 7d203e3..8773146 100644
--- a/chrome/browser/tab_contents/page_navigator.h
+++ b/chrome/browser/tab_contents/page_navigator.h
@@ -8,6 +8,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_PAGE_NAVIGATOR_H_
#define CHROME_BROWSER_TAB_CONTENTS_PAGE_NAVIGATOR_H_
+#pragma once
#include "chrome/common/page_transition_types.h"
#include "webkit/glue/window_open_disposition.h"
@@ -21,6 +22,9 @@ class PageNavigator {
virtual void OpenURL(const GURL& url, const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition) = 0;
+
+ protected:
+ virtual ~PageNavigator() {}
};
#endif // CHROME_BROWSER_TAB_CONTENTS_PAGE_NAVIGATOR_H_
diff --git a/chrome/browser/tab_contents/provisional_load_details.cc b/chrome/browser/tab_contents/provisional_load_details.cc
index 3bea977..e1e85d2 100644
--- a/chrome/browser/tab_contents/provisional_load_details.cc
+++ b/chrome/browser/tab_contents/provisional_load_details.cc
@@ -13,6 +13,7 @@ ProvisionalLoadDetails::ProvisionalLoadDetails(bool is_main_frame,
const std::string& security_info,
bool is_content_filtered)
: error_code_(net::OK),
+ transition_type_(PageTransition::LINK),
url_(url),
is_main_frame_(is_main_frame),
is_in_page_navigation_(is_in_page_navigation),
diff --git a/chrome/browser/tab_contents/provisional_load_details.h b/chrome/browser/tab_contents/provisional_load_details.h
index 4f6abad..2073db0 100644
--- a/chrome/browser/tab_contents/provisional_load_details.h
+++ b/chrome/browser/tab_contents/provisional_load_details.h
@@ -4,10 +4,12 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_PROVISIONAL_LOAD_DETAILS_H_
#define CHROME_BROWSER_TAB_CONTENTS_PROVISIONAL_LOAD_DETAILS_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+#include "chrome/common/page_transition_types.h"
#include "googleurl/src/gurl.h"
// This class captures some of the information associated to the provisional
@@ -31,6 +33,13 @@ class ProvisionalLoadDetails {
void set_error_code(int error_code) { error_code_ = error_code; }
int error_code() const { return error_code_; }
+ void set_transition_type(PageTransition::Type transition_type) {
+ transition_type_ = transition_type;
+ }
+ PageTransition::Type transition_type() const {
+ return transition_type_;
+ }
+
const GURL& url() const { return url_; }
bool main_frame() const { return is_main_frame_; }
@@ -49,6 +58,7 @@ class ProvisionalLoadDetails {
private:
int error_code_;
+ PageTransition::Type transition_type_;
GURL url_;
bool is_main_frame_;
bool is_in_page_navigation_;
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index 62cffc8..707ca68 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -7,8 +7,6 @@
#include "chrome/browser/tab_contents/render_view_context_menu.h"
-#include "app/clipboard/clipboard.h"
-#include "app/clipboard/scoped_clipboard_writer.h"
#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/histogram.h"
@@ -30,9 +28,11 @@
#include "chrome/browser/net/browser_url_util.h"
#include "chrome/browser/page_info_window.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/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"
#include "chrome/browser/spellcheck_host.h"
#include "chrome/browser/spellchecker_platform_engine.h"
@@ -40,6 +40,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/translate/translate_prefs.h"
#include "chrome/browser/translate/translate_manager.h"
+#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -56,15 +57,22 @@ using WebKit::WebContextMenuData;
using WebKit::WebMediaPlayerAction;
// static
+const size_t RenderViewContextMenu::kMaxExtensionItemTitleLength = 75;
+// static
+const size_t RenderViewContextMenu::kMaxSelectionTextLength = 50;
+
+// static
bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
return url.SchemeIs(chrome::kChromeUIScheme) &&
url.host() == chrome::kChromeUIDevToolsHost;
}
// static
-bool RenderViewContextMenu::IsSyncResourcesURL(const GURL& url) {
- return url.SchemeIs(chrome::kChromeUIScheme) &&
- url.host() == chrome::kChromeUISyncResourcesHost;
+bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
+ if (!url.SchemeIs(chrome::kChromeUIScheme))
+ return false;
+ return url.host() == chrome::kChromeUISyncResourcesHost ||
+ url.host() == chrome::kChromeUIRemotingResourcesHost;
}
static const int kSpellcheckRadioGroup = 1;
@@ -158,8 +166,7 @@ static ExtensionMenuItem::List GetRelevantExtensionItems(
const GURL& target_url =
params.src_url.is_empty() ? params.link_url : params.src_url;
- if (!target_url.is_empty() &&
- !ExtensionPatternMatch(item->target_url_patterns(), target_url))
+ if (!ExtensionPatternMatch(item->target_url_patterns(), target_url))
continue;
result.push_back(*i);
@@ -204,7 +211,8 @@ void RenderViewContextMenu::AppendExtensionItems(
} else {
ExtensionMenuItem* item = items[0];
extension_item_map_[menu_id] = item->id();
- title = item->TitleWithReplacement(PrintableSelectionText());
+ title = item->TitleWithReplacement(PrintableSelectionText(),
+ kMaxExtensionItemTitleLength);
submenu_items = GetRelevantExtensionItems(item->children(), params_);
}
@@ -232,20 +240,20 @@ void RenderViewContextMenu::RecursivelyAppendExtensionItems(
i != items.end(); ++i) {
ExtensionMenuItem* item = *i;
- // Auto-prepend a separator, if needed, to visually group radio items
- // together.
- if (item->type() != ExtensionMenuItem::RADIO &&
- item->type() != ExtensionMenuItem::SEPARATOR &&
- last_type == ExtensionMenuItem::RADIO) {
+ // If last item was of type radio but the current one isn't, auto-insert
+ // a separator. The converse case is handled below.
+ if (last_type == ExtensionMenuItem::RADIO &&
+ item->type() != ExtensionMenuItem::RADIO) {
menu_model->AddSeparator();
- radio_group_id++;
+ last_type = ExtensionMenuItem::SEPARATOR;
}
int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST)
return;
extension_item_map_[menu_id] = item->id();
- string16 title = item->TitleWithReplacement(selection_text);
+ string16 title = item->TitleWithReplacement(selection_text,
+ kMaxExtensionItemTitleLength);
if (item->type() == ExtensionMenuItem::NORMAL) {
ExtensionMenuItem::List children =
GetRelevantExtensionItems(item->children(), params_);
@@ -260,17 +268,20 @@ void RenderViewContextMenu::RecursivelyAppendExtensionItems(
} else if (item->type() == ExtensionMenuItem::CHECKBOX) {
menu_model->AddCheckItem(menu_id, title);
} else if (item->type() == ExtensionMenuItem::RADIO) {
- // Auto-append a separator if needed to visually group radio items
- // together.
- if (*index > 0 && last_type != ExtensionMenuItem::RADIO &&
- last_type != ExtensionMenuItem::SEPARATOR) {
- menu_model->AddSeparator();
+ if (i != items.begin() &&
+ last_type != ExtensionMenuItem::RADIO) {
radio_group_id++;
+
+ // Auto-append a separator if needed.
+ if (last_type != ExtensionMenuItem::SEPARATOR)
+ menu_model->AddSeparator();
}
menu_model->AddRadioItem(menu_id, title, radio_group_id);
- } else {
- NOTREACHED();
+ } else if (item->type() == ExtensionMenuItem::SEPARATOR) {
+ if (i != items.begin() && last_type != ExtensionMenuItem::SEPARATOR) {
+ menu_model->AddSeparator();
+ }
}
last_type = item->type();
}
@@ -347,11 +358,11 @@ void RenderViewContextMenu::InitMenu() {
// If context is in subframe, show subframe options instead.
if (!params_.frame_url.is_empty()) {
is_devtools = IsDevToolsURL(params_.frame_url);
- if (!is_devtools && !IsSyncResourcesURL(params_.frame_url))
+ if (!is_devtools && !IsInternalResourcesURL(params_.frame_url))
AppendFrameItems();
} else if (!params_.page_url.is_empty()) {
is_devtools = IsDevToolsURL(params_.page_url);
- if (!is_devtools && !IsSyncResourcesURL(params_.page_url))
+ if (!is_devtools && !IsInternalResourcesURL(params_.page_url))
AppendPageItems();
}
}
@@ -390,14 +401,27 @@ void RenderViewContextMenu::InitMenu() {
AppendDeveloperItems();
}
+void RenderViewContextMenu::LookUpInDictionary() {
+ // Used only in the Mac port.
+ NOTREACHED();
+}
+
bool RenderViewContextMenu::AppendCustomItems() {
std::vector<WebMenuItem>& custom_items = params_.custom_items;
for (size_t i = 0; i < custom_items.size(); ++i) {
DCHECK(IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action <
IDC_CONTENT_CONTEXT_CUSTOM_LAST);
- menu_model_.AddItem(
- custom_items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
- custom_items[i].label);
+ if (custom_items[i].type == WebMenuItem::SEPARATOR) {
+ menu_model_.AddSeparator();
+ } else if (custom_items[i].type == WebMenuItem::CHECKABLE_OPTION) {
+ menu_model_.AddCheckItem(
+ custom_items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
+ custom_items[i].label);
+ } else {
+ menu_model_.AddItem(
+ custom_items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
+ custom_items[i].label);
+ }
}
return custom_items.size() > 0;
}
@@ -729,6 +753,18 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
return false;
}
+ // Custom WebKit items.
+ if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
+ id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
+ const std::vector<WebMenuItem>& custom_items = params_.custom_items;
+ for (size_t i = 0; i < custom_items.size(); ++i) {
+ int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action;
+ if (action_id == id)
+ return custom_items[i].enabled;
+ }
+ return true;
+ }
+
// Extension items.
if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
@@ -765,7 +801,13 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
target_lang = TranslateManager::GetLanguageCode(target_lang);
return !!(params_.edit_flags & WebContextMenuData::CanTranslate) &&
source_tab_contents_->language_state().page_translatable() &&
+ !original_lang.empty() && // Did we receive the page language yet?
original_lang != target_lang &&
+ // Only allow translating languages we explitly support and the
+ // unknown language (in which case the page language is detected on
+ // the server side).
+ (original_lang == chrome::kUnknownLanguageCode ||
+ TranslateManager::IsSupportedLanguage(original_lang)) &&
!source_tab_contents_->language_state().IsPageTranslated() &&
!source_tab_contents_->interstitial_page() &&
TranslateManager::IsTranslatableURL(params_.page_url);
@@ -791,7 +833,8 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
// in a new tab as they should. Disabling this context menu option for
// now, as a quick hack, before we resolve this issue (Issue = 2608).
// TODO(sidchat): Enable this option once this issue is resolved.
- if (params_.src_url.scheme() == chrome::kChromeUIScheme)
+ if (params_.src_url.scheme() == chrome::kChromeUIScheme ||
+ !params_.src_url.is_valid())
return false;
return true;
@@ -915,9 +958,11 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
WebContextMenuData::CheckableMenuItemEnabled;
case IDC_WRITING_DIRECTION_MENU:
return true;
-#endif // OS_MACOSX
-
-#if defined(OS_LINUX)
+ case IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY:
+ // This is OK because the menu is not shown when it isn't
+ // appropriate.
+ return true;
+#elif defined(OS_POSIX)
// TODO(suzhe): this should not be enabled for password fields.
case IDC_INPUT_METHODS_MENU:
return true;
@@ -944,6 +989,19 @@ bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
WebContextMenuData::MediaControls) != 0;
}
+ // Custom WebKit items.
+ if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
+ id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
+ const std::vector<WebMenuItem>& custom_items = params_.custom_items;
+ for (size_t i = 0; i < custom_items.size(); ++i) {
+ int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action;
+ if (action_id == id)
+ return custom_items[i].checked;
+ }
+ return false;
+ }
+
+ // Extension items.
if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
ExtensionMenuItem* item = GetExtensionMenuItem(id);
@@ -963,6 +1021,8 @@ bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
if (id == IDC_WRITING_DIRECTION_LTR)
return params_.writing_direction_left_to_right &
WebContextMenuData::CheckableMenuItemChecked;
+ if (id == IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY)
+ return false;
#endif // OS_MACOSX
// Check box for 'Check the Spelling of this field'.
@@ -1305,6 +1365,9 @@ void RenderViewContextMenu::ExecuteCommand(int id) {
source_tab_contents_->render_view_host()->NotifyTextDirection();
break;
}
+ case IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY:
+ LookUpInDictionary();
+ break;
#endif // OS_MACOSX
default:
@@ -1364,7 +1427,8 @@ bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
}
string16 RenderViewContextMenu::PrintableSelectionText() {
- return WideToUTF16(l10n_util::TruncateString(params_.selection_text, 50));
+ return WideToUTF16(l10n_util::TruncateString(params_.selection_text,
+ kMaxSelectionTextLength));
}
// Controller functions --------------------------------------------------------
@@ -1390,7 +1454,7 @@ void RenderViewContextMenu::Inspect(int x, int y) {
void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
chrome_browser_net::WriteURLToClipboard(
url,
- UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)),
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
g_browser_process->clipboard());
}
diff --git a/chrome/browser/tab_contents/render_view_context_menu.h b/chrome/browser/tab_contents/render_view_context_menu.h
index e0ce3c3..9fd3108 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.h
+++ b/chrome/browser/tab_contents/render_view_context_menu.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_H_
#define CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_H_
+#pragma once
#include <map>
#include <string>
@@ -31,6 +32,9 @@ struct WebMediaPlayerAction;
class RenderViewContextMenu : public menus::SimpleMenuModel::Delegate {
public:
+ static const size_t kMaxExtensionItemTitleLength;
+ static const size_t kMaxSelectionTextLength;
+
RenderViewContextMenu(TabContents* tab_contents,
const ContextMenuParams& params);
@@ -52,6 +56,7 @@ class RenderViewContextMenu : public menus::SimpleMenuModel::Delegate {
virtual bool GetAcceleratorForCommandId(
int command_id,
menus::Accelerator* accelerator) = 0;
+ virtual void LookUpInDictionary();
// Attempts to get an ExtensionMenuItem given the id of a context menu item.
ExtensionMenuItem* GetExtensionMenuItem(int id) const;
@@ -72,7 +77,7 @@ class RenderViewContextMenu : public menus::SimpleMenuModel::Delegate {
private:
static bool IsDevToolsURL(const GURL& url);
- static bool IsSyncResourcesURL(const GURL& url);
+ static bool IsInternalResourcesURL(const GURL& url);
bool AppendCustomItems();
void AppendDeveloperItems();
void AppendLinkItems();
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 6573ca5..08cd752 100644
--- a/chrome/browser/tab_contents/render_view_context_menu_gtk.h
+++ b/chrome/browser/tab_contents/render_view_context_menu_gtk.h
@@ -4,17 +4,13 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_GTK_H_
#define CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_GTK_H_
-
-#include <map>
-#include <string>
-#include <vector>
+#pragma once
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "gfx/point.h"
-class RenderWidgetHostView;
struct ContextMenuParams;
class RenderViewContextMenuGtk : public RenderViewContextMenu,
diff --git a/chrome/browser/tab_contents/render_view_context_menu_mac.h b/chrome/browser/tab_contents/render_view_context_menu_mac.h
index 2661ffe..72f402c 100644
--- a/chrome/browser/tab_contents/render_view_context_menu_mac.h
+++ b/chrome/browser/tab_contents/render_view_context_menu_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_MAC_H_
#define CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
@@ -32,6 +33,9 @@ class RenderViewContextMenuMac : public RenderViewContextMenu {
return false;
}
+ virtual void LookUpInDictionary();
+
+ void InitPlatformMenu();
private:
scoped_nsobject<MenuController> menuController_;
NSView* parent_view_; // parent view
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 42fe061..1e4e4c4 100644
--- a/chrome/browser/tab_contents/render_view_context_menu_mac.mm
+++ b/chrome/browser/tab_contents/render_view_context_menu_mac.mm
@@ -7,7 +7,10 @@
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_dll_resource.h"
#import "chrome/browser/cocoa/menu_controller.h"
+#include "grit/generated_resources.h"
// Obj-C bridge class that is the target of all items in the context menu.
// Relies on the tag being set to the command id.
@@ -24,6 +27,7 @@ RenderViewContextMenuMac::~RenderViewContextMenuMac() {
}
void RenderViewContextMenuMac::PlatformInit() {
+ InitPlatformMenu();
menuController_.reset(
[[MenuController alloc] initWithModel:&menu_model_
useWithPopUpButtonCell:NO]);
@@ -54,3 +58,30 @@ void RenderViewContextMenuMac::PlatformInit() {
forView:parent_view_];
}
}
+
+void RenderViewContextMenuMac::InitPlatformMenu() {
+ bool has_selection = !params_.selection_text.empty();
+
+ if (has_selection) {
+ menu_model_.AddSeparator();
+ menu_model_.AddItemWithStringId(
+ IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY,
+ IDS_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY);
+ }
+
+}
+
+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);
+ NSPasteboard* pboard = [NSPasteboard pasteboardWithUniqueName];
+ // 10.5 and earlier require declareTypes before setData.
+ // See the documentation on [NSPasteboard declareTypes].
+ NSArray* toDeclare = [NSArray arrayWithObject:NSStringPboardType];
+ [pboard declareTypes:toDeclare owner:nil];
+ BOOL ok = [pboard setString:text forType:NSStringPboardType];
+ if (ok)
+ NSPerformService(@"Look Up in Dictionary", pboard);
+}
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 a99d549..7a7f2d6 100644
--- a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
+++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
@@ -6,14 +6,15 @@
#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/browser.h"
#include "chrome/browser/character_encoding.h"
#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/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"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/site_instance.h"
@@ -61,7 +62,10 @@ RenderViewHostDelegateViewHelper::MaybeCreateBackgroundContents(
return NULL;
// Passed all the checks, so this should be created as a BackgroundContents.
- BackgroundContents* contents = new BackgroundContents(site, route_id);
+ BackgroundContents* contents = new BackgroundContents(
+ site,
+ route_id,
+ profile->GetBackgroundContentsService());
string16 appid = ASCIIToUTF16(extension->id());
BackgroundContentsOpenedDetails details = { contents, frame_name, appid };
NotificationService::current()->Notify(
@@ -99,7 +103,8 @@ TabContents* RenderViewHostDelegateViewHelper::CreateNewWindow(
new TabContents(profile,
site,
route_id,
- opener->GetAsTabContents());
+ opener->GetAsTabContents(),
+ NULL);
new_contents->set_opener_dom_ui_type(domui_type);
TabContentsView* new_view = new_contents->view();
@@ -125,6 +130,18 @@ RenderWidgetHostView* RenderViewHostDelegateViewHelper::CreateNewWidget(
return widget_view;
}
+RenderWidgetHostView*
+RenderViewHostDelegateViewHelper::CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type, RenderProcessHost* process) {
+ RenderWidgetFullscreenHost* fullscreen_widget_host =
+ new RenderWidgetFullscreenHost(process, route_id);
+ RenderWidgetHostView* widget_view =
+ RenderWidgetHostView::CreateViewForWidget(fullscreen_widget_host);
+ widget_view->set_popup_type(popup_type);
+ pending_widget_views_[route_id] = widget_view;
+ return widget_view;
+}
+
TabContents* RenderViewHostDelegateViewHelper::GetCreatedWindow(int route_id) {
PendingContents::iterator iter = pending_contents_.find(route_id);
if (iter == pending_contents_.end()) {
@@ -222,7 +239,7 @@ WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs(
std::string value;
if (inspector_settings->GetStringWithoutPathExpansion(*iter, &value))
web_prefs.inspector_settings.push_back(
- std::make_pair(WideToUTF8(*iter), value));
+ std::make_pair(*iter, value));
}
}
web_prefs.tabs_to_links = prefs->GetBoolean(prefs::kWebkitTabsToLinks);
@@ -259,7 +276,7 @@ WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs(
web_prefs.databases_enabled =
!command_line.HasSwitch(switches::kDisableDatabases);
web_prefs.experimental_webgl_enabled =
- command_line.HasSwitch(switches::kEnableExperimentalWebGL);
+ !command_line.HasSwitch(switches::kDisableExperimentalWebGL);
web_prefs.site_specific_quirks_enabled =
!command_line.HasSwitch(switches::kDisableSiteSpecificQuirks);
web_prefs.allow_file_access_from_file_urls =
@@ -267,7 +284,9 @@ WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs(
web_prefs.show_composited_layer_borders =
command_line.HasSwitch(switches::kShowCompositedLayerBorders);
web_prefs.accelerated_compositing_enabled =
- command_line.HasSwitch(switches::kEnableAcceleratedCompositing);
+ !command_line.HasSwitch(switches::kDisableAcceleratedCompositing);
+ web_prefs.accelerated_2d_canvas_enabled =
+ command_line.HasSwitch(switches::kEnableAccelerated2dCanvas);
web_prefs.memory_info_enabled =
command_line.HasSwitch(switches::kEnableMemoryInfo);
// The user stylesheet watcher may not exist in a testing profile.
diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.h b/chrome/browser/tab_contents/render_view_host_delegate_helper.h
index 5b1d99b..a1f2b9b 100644
--- a/chrome/browser/tab_contents/render_view_host_delegate_helper.h
+++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.h
@@ -1,14 +1,14 @@
-// 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.
#ifndef CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_HOST_DELEGATE_HELPER_H_
#define CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_HOST_DELEGATE_HELPER_H_
+#pragma once
#include <map>
#include "base/basictypes.h"
-#include "base/waitable_event.h"
#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/common/window_container_type.h"
#include "gfx/rect.h"
@@ -17,9 +17,6 @@
#include "webkit/glue/window_open_disposition.h"
class BackgroundContents;
-class Browser;
-class ExtensionsService;
-class PrefService;
class Profile;
class RenderProcessHost;
class RenderViewHost;
@@ -34,6 +31,7 @@ class TabContents;
class RenderViewHostDelegateViewHelper {
public:
RenderViewHostDelegateViewHelper() {}
+ virtual ~RenderViewHostDelegateViewHelper() {}
// Creates a new renderer for window.open. This will either be a
// BackgroundContents (if the window_container_type ==
@@ -54,6 +52,11 @@ class RenderViewHostDelegateViewHelper {
WebKit::WebPopupType popup_type,
RenderProcessHost* process);
+ virtual RenderWidgetHostView* CreateNewFullscreenWidget(
+ int route_id,
+ WebKit::WebPopupType popup_type,
+ RenderProcessHost* process);
+
// Finds the new RenderWidgetHost and returns it. Note that this can only be
// called once as this call also removes it from the internal map.
virtual RenderWidgetHostView* GetCreatedWidget(int route_id);
diff --git a/chrome/browser/tab_contents/render_view_host_manager.cc b/chrome/browser/tab_contents/render_view_host_manager.cc
index 4754425..8883540 100644
--- a/chrome/browser/tab_contents/render_view_host_manager.cc
+++ b/chrome/browser/tab_contents/render_view_host_manager.cc
@@ -21,6 +21,7 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
namespace base {
@@ -58,7 +59,7 @@ void RenderViewHostManager::Init(Profile* profile,
site_instance = SiteInstance::CreateSiteInstance(profile);
render_view_host_ = RenderViewHostFactory::Create(
site_instance, render_view_delegate_, routing_id, delegate_->
- GetControllerForRenderManager().session_storage_namespace_id());
+ GetControllerForRenderManager().session_storage_namespace());
NotificationService::current()->Notify(
NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
Source<RenderViewHostManager>(this),
@@ -308,8 +309,9 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation(
// For security, we should transition between processes when one is a DOM UI
// page and one isn't.
- if (DOMUIFactory::UseDOMUIForURL(cur_entry->url()) !=
- DOMUIFactory::UseDOMUIForURL(new_entry->url()))
+ Profile* profile = delegate_->GetControllerForRenderManager().profile();
+ if (DOMUIFactory::UseDOMUIForURL(profile, cur_entry->url()) !=
+ DOMUIFactory::UseDOMUIForURL(profile, new_entry->url()))
return true;
// Also, we must switch if one is an extension and the other is not the exact
@@ -446,7 +448,7 @@ bool RenderViewHostManager::CreatePendingRenderView(
pending_render_view_host_ = RenderViewHostFactory::Create(
instance, render_view_delegate_, MSG_ROUTING_NONE, delegate_->
- GetControllerForRenderManager().session_storage_namespace_id());
+ GetControllerForRenderManager().session_storage_namespace());
NotificationService::current()->Notify(
NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
Source<RenderViewHostManager>(this),
@@ -471,14 +473,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 = false;
- if (entry.url().SchemeIs(chrome::kExtensionScheme)) {
- is_extension_process = true;
- } else if (profile->GetExtensionsService() &&
- profile->GetExtensionsService()->
- GetExtensionByWebExtent(entry.url())) {
- is_extension_process = true;
- }
+ bool is_extension_process = profile->GetExtensionsService() &&
+ profile->GetExtensionsService()->ExtensionBindingsAllowed(entry.url());
render_view_host->set_is_extension_process(is_extension_process);
return delegate_->CreateRenderViewForRenderManager(render_view_host);
diff --git a/chrome/browser/tab_contents/render_view_host_manager.h b/chrome/browser/tab_contents/render_view_host_manager.h
index 0fa0f26..01a8f0d 100644
--- a/chrome/browser/tab_contents/render_view_host_manager.h
+++ b/chrome/browser/tab_contents/render_view_host_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
#define CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/logging.h"
@@ -67,6 +68,9 @@ class RenderViewHostManager
// Focuses the location bar.
virtual void SetFocusToLocationBar(bool select_all) = 0;
+
+ protected:
+ virtual ~Delegate() {}
};
// Both delegate pointers must be non-NULL and are not owned by this class.
@@ -76,7 +80,7 @@ class RenderViewHostManager
// You must call Init() before using this class.
RenderViewHostManager(RenderViewHostDelegate* render_view_delegate,
Delegate* delegate);
- ~RenderViewHostManager();
+ virtual ~RenderViewHostManager();
// For arguments, see TabContents constructor.
void Init(Profile* profile,
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 16c0c7f..f58b140 100644
--- a/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
+++ b/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
@@ -3,13 +3,18 @@
// found in the LICENSE file.
#include "chrome/browser/browser_url_handler.h"
+#include "chrome/browser/chrome_thread.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/navigation_controller.h"
#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/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/test_notification_tracker.h"
+#include "chrome/test/testing_profile.h"
#include "ipc/ipc_message.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -291,3 +296,51 @@ TEST_F(RenderViewHostManagerTest, NonDOMUIChromeURLs) {
EXPECT_TRUE(ShouldSwapProcesses(&manager, &ntp_entry, &about_entry));
}
+
+// Tests that we don't end up in an inconsistent state if a page does a back and
+// then reload. http://crbug.com/51680
+TEST_F(RenderViewHostManagerTest, PageDoesBackAndReload) {
+ GURL url1("http://www.google.com/");
+ GURL url2("http://www.evil-site.com/");
+
+ // Navigate to a safe site, then an evil site.
+ // This will switch RenderViewHosts. We cannot assert that the first and
+ // second RVHs are different, though, because the first one may be promptly
+ // deleted.
+ contents()->NavigateAndCommit(url1);
+ contents()->NavigateAndCommit(url2);
+ RenderViewHost* evil_rvh = contents()->render_view_host();
+
+ // Casts the TabContents to a RenderViewHostDelegate::BrowserIntegration so we
+ // can call GoToEntryAtOffset which is private.
+ RenderViewHostDelegate::BrowserIntegration* rvh_delegate =
+ static_cast<RenderViewHostDelegate::BrowserIntegration*>(contents());
+
+ // Now let's simulate the evil page calling history.back().
+ rvh_delegate->GoToEntryAtOffset(-1);
+ // We should have a new pending RVH.
+ // Note that in this case, the navigation has not committed, so evil_rvh will
+ // not be deleted yet.
+ EXPECT_NE(evil_rvh, contents()->render_manager()->pending_render_view_host());
+
+ // Before that RVH has committed, the evil page reloads itself.
+ ViewHostMsg_FrameNavigate_Params params;
+ params.page_id = 1;
+ params.url = url2;
+ params.transition = PageTransition::CLIENT_REDIRECT;
+ params.should_update_history = false;
+ params.gesture = NavigationGestureAuto;
+ params.was_within_same_page = false;
+ params.is_post = false;
+ contents()->TestDidNavigate(evil_rvh, params);
+
+ // That should have cancelled the pending RVH, and the evil RVH should be the
+ // current one.
+ EXPECT_TRUE(contents()->render_manager()->pending_render_view_host() == NULL);
+ EXPECT_EQ(evil_rvh, contents()->render_manager()->current_host());
+
+ // Also we should not have a pending navigation entry.
+ NavigationEntry* entry = contents()->controller().GetActiveEntry();
+ ASSERT_TRUE(entry != NULL);
+ EXPECT_EQ(url2, entry->url());
+}
diff --git a/chrome/browser/tab_contents/security_style.h b/chrome/browser/tab_contents/security_style.h
index 355401c..9694646 100644
--- a/chrome/browser/tab_contents/security_style.h
+++ b/chrome/browser/tab_contents/security_style.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_SECURITY_STYLE_H_
#define CHROME_BROWSER_TAB_CONTENTS_SECURITY_STYLE_H_
+#pragma once
// Various aspects of the UI change their appearance according to the security
// context in which they are displayed. For example, the location bar displays
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index e25fc44..a4592c1 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -11,24 +11,30 @@
#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/histogram.h"
#include "base/i18n/rtl.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 "chrome/browser/autocomplete_history_manager.h"
#include "chrome/browser/autofill/autofill_manager.h"
+#include "chrome/browser/blocked_plugin_manager.h"
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/browser.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/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"
@@ -37,12 +43,15 @@
#include "chrome/browser/download/download_request_limiter.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/favicon_service.h"
+#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/find_bar_state.h"
-#include "chrome/browser/google_util.h"
+#include "chrome/browser/google/google_util.h"
#include "chrome/browser/host_content_settings_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"
@@ -53,7 +62,7 @@
#include "chrome/browser/platform_util.h"
#include "chrome/browser/plugin_installer.h"
#include "chrome/browser/popup_blocked_animation.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/print_view_manager.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
@@ -63,6 +72,7 @@
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/renderer_preferences_util.h"
+#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_fetcher.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sessions/session_types.h"
@@ -79,6 +89,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/navigation_types.h"
@@ -86,6 +97,7 @@
#include "chrome/common/notification_service.h"
#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 "grit/chromium_strings.h"
@@ -161,7 +173,7 @@ const float kMaxHeightFactor = 0.6;
const int kJavascriptMessageExpectedDelay = 1000;
// The list of prefs we want to observe.
-const wchar_t* kPrefsToObserve[] = {
+const char* kPrefsToObserve[] = {
prefs::kAlternateErrorPagesEnabled,
prefs::kWebKitJavaEnabled,
prefs::kWebKitJavascriptEnabled,
@@ -218,12 +230,12 @@ ViewMsg_Navigate_Params::NavigationType GetNavigationType(
return ViewMsg_Navigate_Params::NORMAL;
}
-void MakeNavigateParams(const NavigationController& controller,
+void MakeNavigateParams(const NavigationEntry& entry,
+ const NavigationController& controller,
NavigationController::ReloadType reload_type,
ViewMsg_Navigate_Params* params) {
- const NavigationEntry& entry = *controller.pending_entry();
params->page_id = entry.page_id();
- params->pending_history_list_offset = controller.pending_entry_index();
+ params->pending_history_list_offset = controller.GetIndexOfEntry(&entry);
params->current_history_list_offset = controller.last_committed_entry_index();
params->current_history_list_length = controller.entry_count();
params->url = entry.url();
@@ -235,6 +247,67 @@ void MakeNavigateParams(const NavigationController& controller,
params->request_time = base::Time::Now();
}
+class DisabledPluginInfoBar : public ConfirmInfoBarDelegate {
+ public:
+ DisabledPluginInfoBar(TabContents* tab_contents,
+ const string16& name,
+ const GURL& update_url)
+ : ConfirmInfoBarDelegate(tab_contents),
+ tab_contents_(tab_contents),
+ name_(name),
+ update_url_(update_url) {
+ tab_contents->AddInfoBar(this);
+ }
+
+ virtual int GetButtons() const {
+ return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
+ }
+
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
+ if (button == BUTTON_CANCEL)
+ return l10n_util::GetStringUTF16(IDS_PLUGIN_ENABLE_TEMPORARILY);
+ if (button == BUTTON_OK)
+ return l10n_util::GetStringUTF16(IDS_PLUGIN_UPDATE);
+ return ConfirmInfoBarDelegate::GetButtonLabel(button);
+ }
+
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED_PROMPT, name_);
+ }
+
+ virtual string16 GetLinkText() {
+ return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
+ }
+
+ virtual SkBitmap* GetIcon() const {
+ return ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_INFOBAR_PLUGIN_INSTALL);
+ }
+
+ virtual bool Accept() {
+ tab_contents_->OpenURL(update_url_, GURL(),
+ CURRENT_TAB, PageTransition::LINK);
+ return false;
+ }
+
+ virtual bool Cancel() {
+ tab_contents_->OpenURL(GURL(chrome::kChromeUIPluginsURL), GURL(),
+ CURRENT_TAB, PageTransition::LINK);
+ return false;
+ }
+
+ virtual bool LinkClicked(WindowOpenDisposition disposition) {
+ // TODO(bauerb): Navigate to a help page explaining why we disabled
+ // the plugin, once we have one.
+ return false;
+ }
+
+ private:
+ TabContents* tab_contents_;
+ string16 name_;
+ GURL update_url_;
+};
+
} // namespace
// -----------------------------------------------------------------------------
@@ -246,9 +319,11 @@ int TabContents::find_request_id_counter_ = -1;
TabContents::TabContents(Profile* profile,
SiteInstance* site_instance,
int routing_id,
- const TabContents* base_tab_contents)
+ const TabContents* base_tab_contents,
+ SessionStorageNamespace* session_storage_namespace)
: delegate_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(controller_(this, profile)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(controller_(
+ this, profile, session_storage_namespace)),
ALLOW_THIS_IN_INITIALIZER_LIST(view_(
TabContentsView::Create(this))),
ALLOW_THIS_IN_INITIALIZER_LIST(render_manager_(this, this)),
@@ -263,7 +338,6 @@ TabContents::TabContents(Profile* profile,
plugin_installer_(),
bookmark_drag_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(fav_icon_helper_(this)),
- select_file_dialog_(),
is_loading_(false),
is_crashed_(false),
waiting_for_response_(false),
@@ -300,7 +374,8 @@ TabContents::TabContents(Profile* profile,
renderer_preferences_(),
opener_dom_ui_type_(DOMUIFactory::kNoDOMUI),
language_state_(&controller_),
- closed_by_user_gesture_(false) {
+ closed_by_user_gesture_(false),
+ displaying_pdf_content_(false) {
renderer_preferences_util::UpdateFromSystemSettings(
&renderer_preferences_, profile);
@@ -325,9 +400,10 @@ TabContents::TabContents(Profile* profile,
// Register for notifications about all interested prefs change.
PrefService* prefs = profile->GetPrefs();
+ pref_change_registrar_.Init(prefs);
if (prefs) {
for (int i = 0; i < kPrefsToObserveLength; ++i)
- prefs->AddPrefObserver(kPrefsToObserve[i], this);
+ pref_change_registrar_.Add(kPrefsToObserve[i], this);
}
// Register for notifications about URL starredness changing on any profile.
@@ -367,13 +443,7 @@ TabContents::~TabContents() {
// We don't want any notifications while we're running our destructor.
registrar_.RemoveAll();
-
- // Unregister the notifications of all observed prefs change.
- PrefService* prefs = profile()->GetPrefs();
- if (prefs) {
- for (int i = 0; i < kPrefsToObserveLength; ++i)
- prefs->RemovePrefObserver(kPrefsToObserve[i], this);
- }
+ pref_change_registrar_.RemoveAll();
NotifyDisconnected();
hung_renderer_dialog::HideForTabContents(this);
@@ -538,13 +608,6 @@ void TabContents::SetExtensionAppById(const std::string& extension_app_id) {
}
SkBitmap* TabContents::GetExtensionAppIcon() {
- // 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.
- Browser* browser = delegate_ ? delegate_->GetBrowser() : NULL;
- if (browser && browser->type() == Browser::TYPE_EXTENSION_APP)
- return NULL;
-
if (extension_app_icon_.empty())
return NULL;
@@ -751,6 +814,11 @@ void TabContents::Activate() {
delegate_->ActivateContents(this);
}
+void TabContents::Deactivate() {
+ if (delegate_)
+ delegate_->DeactivateContents(this);
+}
+
void TabContents::ShowContents() {
RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
if (rwhv)
@@ -776,8 +844,12 @@ void TabContents::OpenURL(const GURL& url, const GURL& referrer,
bool TabContents::NavigateToPendingEntry(
NavigationController::ReloadType reload_type) {
- const NavigationEntry& entry = *controller_.pending_entry();
+ return NavigateToEntry(*controller_.pending_entry(), reload_type);
+}
+bool TabContents::NavigateToEntry(
+ const NavigationEntry& entry,
+ NavigationController::ReloadType reload_type) {
RenderViewHost* dest_render_view_host = render_manager_.Navigate(entry);
if (!dest_render_view_host)
return false; // Unable to create the desired render view host.
@@ -791,7 +863,7 @@ bool TabContents::NavigateToPendingEntry(
// to a DOM UI renderer. Double check that here.
int enabled_bindings = dest_render_view_host->enabled_bindings();
bool is_allowed_in_dom_ui_renderer =
- DOMUIFactory::UseDOMUIForURL(entry.url()) ||
+ DOMUIFactory::UseDOMUIForURL(profile(), entry.url()) ||
entry.url() == GURL(chrome::kAboutBlankURL);
CHECK(!BindingsPolicy::is_dom_ui_enabled(enabled_bindings) ||
is_allowed_in_dom_ui_renderer);
@@ -809,7 +881,7 @@ bool TabContents::NavigateToPendingEntry(
// Navigate in the desired RenderViewHost.
ViewMsg_Navigate_Params navigate_params;
- MakeNavigateParams(controller_, reload_type, &navigate_params);
+ MakeNavigateParams(entry, controller_, reload_type, &navigate_params);
dest_render_view_host->Navigate(navigate_params);
if (entry.page_id() == -1) {
@@ -853,7 +925,7 @@ TabContents* TabContents::Clone() {
// processes for some reason.
TabContents* tc = new TabContents(profile(),
SiteInstance::CreateSiteInstance(profile()),
- MSG_ROUTING_NONE, this);
+ MSG_ROUTING_NONE, this, NULL);
tc->controller().CopyStateFrom(controller_);
tc->extension_app_ = extension_app_;
tc->extension_app_icon_ = extension_app_icon_;
@@ -955,8 +1027,6 @@ void TabContents::PopupNotificationVisibilityChanged(bool visible) {
content_settings_delegate_->SetPopupsBlocked(visible);
if (!dont_notify_render_view_)
render_view_host()->AllowScriptToClose(!visible);
- if (visible)
- PopupBlockedAnimation::Show(this);
}
gfx::NativeView TabContents::GetContentNativeView() const {
@@ -1042,12 +1112,20 @@ void TabContents::RemoveInfoBar(InfoBarDelegate* delegate) {
NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
Source<TabContents>(this),
Details<InfoBarDelegate>(delegate));
- infobar_delegates_.erase(it);
- // Remove ourselves as an observer if we are tracking no more InfoBars.
- if (infobar_delegates_.empty()) {
- registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&controller_));
+ // Just to be safe, make sure the delegate was not removed by an observer.
+ it = find(infobar_delegates_.begin(), infobar_delegates_.end(), delegate);
+ if (it != infobar_delegates_.end()) {
+ infobar_delegates_.erase(it);
+ // Remove ourselves as an observer if we are tracking no more InfoBars.
+ if (infobar_delegates_.empty()) {
+ registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(&controller_));
+ }
+ } else {
+ // If you hit this NOTREACHED, please comment in bug
+ // http://crbug.com/50428 how you got there.
+ NOTREACHED();
}
}
}
@@ -1072,10 +1150,21 @@ void TabContents::ReplaceInfoBar(InfoBarDelegate* old_delegate,
Source<TabContents>(this),
Details<std::pair<InfoBarDelegate*, InfoBarDelegate*> >(details.get()));
- // Remove the old one.
- infobar_delegates_.erase(it);
+ // Just to be safe, make sure the delegate was not removed by an observer.
+ it = find(infobar_delegates_.begin(), infobar_delegates_.end(), old_delegate);
+ if (it != infobar_delegates_.end()) {
+ // Remove the old one.
+ infobar_delegates_.erase(it);
+ } else {
+ // If you hit this NOTREACHED, please comment in bug
+ // http://crbug.com/50428 how you got there.
+ NOTREACHED();
+ }
// Add the new one.
+ DCHECK(find(infobar_delegates_.begin(),
+ infobar_delegates_.end(), new_delegate) ==
+ infobar_delegates_.end());
infobar_delegates_.push_back(new_delegate);
}
@@ -1083,6 +1172,10 @@ bool TabContents::ShouldShowBookmarkBar() {
if (showing_interstitial_page())
return false;
+ // Do not show bookmarks bar if bookmarks aren't enabled.
+ if (!browser_defaults::bookmarks_enabled)
+ return false;
+
// See GetDOMUIForCurrentState() comment for more info. This case is very
// similar, but for non-first loads, we want to use the committed entry. This
// is so the bookmarks bar disappears at the same time the page does.
@@ -1103,27 +1196,6 @@ bool TabContents::ShouldShowBookmarkBar() {
return false; // Default.
}
-bool TabContents::IsExtensionShelfAlwaysVisible() {
- // See GetDOMUIForCurrentState() comment for more info. This case is very
- // similar, but for non-first loads, we want to use the committed entry. This
- // is so the bookmarks bar disappears at the same time the page does.
- if (controller_.GetLastCommittedEntry()) {
- // Not the first load, always use the committed DOM UI.
- if (render_manager_.dom_ui())
- return render_manager_.dom_ui()->force_extension_shelf_visible();
- return false; // Default.
- }
-
- // When it's the first load, we know either the pending one or the committed
- // one will have the DOM UI in it (see GetDOMUIForCurrentState), and only one
- // of them will be valid, so we can just check both.
- if (render_manager_.pending_dom_ui())
- return render_manager_.pending_dom_ui()->force_extension_shelf_visible();
- if (render_manager_.dom_ui())
- return render_manager_.dom_ui()->force_extension_shelf_visible();
- return false; // Default.
-}
-
void TabContents::ToolbarSizeChanged(bool is_animating) {
TabContentsDelegate* d = delegate();
if (d)
@@ -1143,12 +1215,8 @@ void TabContents::OnStartDownload(DownloadItem* download) {
// Download in a constrained popup is shown in the tab that opened it.
TabContents* tab_contents = delegate()->GetConstrainingContents(this);
- if (tab_contents && tab_contents->delegate()) {
- tab_contents->delegate()->OnStartDownload(download);
- // If the download occurs in a new tab, close it
- if (controller_.IsInitialNavigation() && (tab_contents == this))
- delegate()->CloseContents(this);
- }
+ if (tab_contents && tab_contents->delegate())
+ tab_contents->delegate()->OnStartDownload(download, this);
}
void TabContents::WillClose(ConstrainedWindow* window) {
@@ -1357,15 +1425,11 @@ void TabContents::OnCloseStarted() {
tab_close_start_time_ = base::TimeTicks::Now();
}
-void TabContents::set_request_context(URLRequestContextGetter* context) {
- request_context_ = context;
-}
-
bool TabContents::ShouldAcceptDragAndDrop() const {
#if defined(OS_CHROMEOS)
// ChromeOS panels (pop-ups) do not take drag-n-drop.
// See http://crosbug.com/2413
- return delegate() && !delegate()->IsPopup(const_cast<TabContents*>(this));
+ return delegate() && !delegate()->IsPopup(this);
#else
return true;
#endif
@@ -1384,7 +1448,8 @@ TabContents* TabContents::CloneAndMakePhantom() {
navigations.push_back(tab_nav);
TabContents* new_contents =
- new TabContents(profile(), NULL, MSG_ROUTING_NONE, NULL);
+ new TabContents(profile(), NULL, MSG_ROUTING_NONE, NULL,
+ controller_.session_storage_namespace()->Clone());
new_contents->SetExtensionApp(extension_app_);
new_contents->controller().RestoreFromState(navigations, 0, false);
@@ -1394,6 +1459,26 @@ TabContents* TabContents::CloneAndMakePhantom() {
return new_contents;
}
+void TabContents::UpdateHistoryForNavigation(
+ scoped_refptr<history::HistoryAddPageArgs> add_page_args) {
+ if (profile()->IsOffTheRecord())
+ return;
+
+ // Add to history service.
+ HistoryService* hs = profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
+ if (hs)
+ hs->AddPage(*add_page_args);
+}
+
+void TabContents::UpdateHistoryPageTitle(const NavigationEntry& entry) {
+ if (profile()->IsOffTheRecord())
+ return;
+
+ HistoryService* hs = profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
+ if (hs)
+ hs->SetPageTitle(entry.virtual_url(), entry.title());
+}
+
// 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,
@@ -1441,22 +1526,19 @@ void TabContents::AddPopup(TabContents* new_contents,
if (creator.is_valid() &&
profile()->GetHostContentSettingsMap()->GetContentSetting(
- creator, CONTENT_SETTINGS_TYPE_POPUPS) == CONTENT_SETTING_ALLOW) {
+ creator, CONTENT_SETTINGS_TYPE_POPUPS, "") == CONTENT_SETTING_ALLOW) {
AddNewContents(new_contents, NEW_POPUP, initial_pos, true);
} else {
if (!blocked_popups_)
blocked_popups_ = new BlockedPopupContainer(this);
blocked_popups_->AddTabContents(new_contents, initial_pos);
- content_settings_delegate_->OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS);
+ content_settings_delegate_->OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS,
+ std::string());
+ if (!is_being_destroyed())
+ PopupBlockedAnimation::Show(this);
}
}
-namespace {
-bool TransitionIsReload(PageTransition::Type transition) {
- return PageTransition::StripQualifier(transition) == PageTransition::RELOAD;
-}
-}
-
void TabContents::ExpireInfoBars(
const NavigationController::LoadCommittedDetails& details) {
// Only hide InfoBars when the user has done something that makes the main
@@ -1467,6 +1549,13 @@ void TabContents::ExpireInfoBars(
for (int i = infobar_delegate_count() - 1; i >= 0; --i) {
InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
+ if (!delegate) {
+ // If you hit this NOTREACHED, please comment in bug
+ // http://crbug.com/50428 how you got there.
+ NOTREACHED();
+ continue;
+ }
+
if (delegate->ShouldExpire(details))
RemoveInfoBar(delegate);
}
@@ -1519,7 +1608,8 @@ void TabContents::DidNavigateMainFramePostCommit(
// If this is a window.open navigation, use the same DOMUI as the renderer
// that opened the window, as long as both renderers have the same
// privileges.
- if (opener_dom_ui_type_ == DOMUIFactory::GetDOMUIType(GetURL())) {
+ if (opener_dom_ui_type_ ==
+ DOMUIFactory::GetDOMUIType(profile(), GetURL())) {
DOMUI* dom_ui = DOMUIFactory::CreateDOMUIForURL(this, GetURL());
// dom_ui might be NULL if the URL refers to a non-existent extension.
if (dom_ui) {
@@ -1590,7 +1680,7 @@ void TabContents::DidNavigateMainFramePostCommit(
}
// Clear "blocked" flags.
- content_settings_delegate_->ClearBlockedContentSettings();
+ content_settings_delegate_->ClearBlockedContentSettingsExceptForCookies();
content_settings_delegate_->GeolocationDidNavigate(details);
// Once the main frame is navigated, we're no longer considered to have
@@ -1627,9 +1717,7 @@ void TabContents::DidNavigateAnyFramePostCommit(
GetPasswordManager()->ProvisionallySavePassword(params.password_form);
// Let the LanguageState clear its state.
- bool reload = details.entry->transition_type() == PageTransition::RELOAD ||
- details.type == NavigationType::SAME_PAGE;
- language_state_.DidNavigate(reload, details.is_in_page);
+ language_state_.DidNavigate(details);
}
void TabContents::CloseConstrainedWindows() {
@@ -1689,35 +1777,29 @@ void TabContents::UpdateMaxPageIDIfNecessary(SiteInstance* site_instance,
}
}
-void TabContents::UpdateHistoryForNavigation(
+scoped_refptr<history::HistoryAddPageArgs>
+TabContents::CreateHistoryAddPageArgs(
const GURL& virtual_url,
const NavigationController::LoadCommittedDetails& details,
const ViewHostMsg_FrameNavigate_Params& params) {
- if (profile()->IsOffTheRecord())
- return;
-
- // Add to history service.
- HistoryService* hs = profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
- if (hs) {
- if (PageTransition::IsMainFrame(params.transition) &&
- virtual_url != params.url) {
- // Hack on the "virtual" URL so that it will appear in history. For some
- // types of URLs, we will display a magic URL that is different from where
- // the page is actually navigated. We want the user to see in history
- // what they saw in the URL bar, so we add the virtual URL as a redirect.
- // This only applies to the main frame, as the virtual URL doesn't apply
- // to sub-frames.
- std::vector<GURL> redirects = params.redirects;
- if (!redirects.empty())
- redirects.back() = virtual_url;
- hs->AddPage(virtual_url, this, params.page_id, params.referrer,
- params.transition, redirects, details.did_replace_entry);
- } else {
- hs->AddPage(params.url, this, params.page_id, params.referrer,
- params.transition, params.redirects,
- details.did_replace_entry);
- }
- }
+ scoped_refptr<history::HistoryAddPageArgs> add_page_args(
+ new history::HistoryAddPageArgs(
+ params.url, base::Time::Now(), this, params.page_id, params.referrer,
+ params.redirects, params.transition, history::SOURCE_BROWSED,
+ details.did_replace_entry));
+ if (PageTransition::IsMainFrame(params.transition) &&
+ virtual_url != params.url) {
+ // Hack on the "virtual" URL so that it will appear in history. For some
+ // types of URLs, we will display a magic URL that is different from where
+ // the page is actually navigated. We want the user to see in history what
+ // they saw in the URL bar, so we add the virtual URL as a redirect. This
+ // only applies to the main frame, as the virtual URL doesn't apply to
+ // sub-frames.
+ add_page_args->url = virtual_url;
+ if (!add_page_args->redirects.empty())
+ add_page_args->redirects.back() = virtual_url;
+ }
+ return add_page_args;
}
bool TabContents::UpdateTitleForEntry(NavigationEntry* entry,
@@ -1740,14 +1822,8 @@ bool TabContents::UpdateTitleForEntry(NavigationEntry* entry,
entry->set_title(final_title);
- // Update the history system for this page.
- if (!profile()->IsOffTheRecord() && !received_page_title_) {
- HistoryService* hs =
- profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
- if (hs)
- hs->SetPageTitle(entry->virtual_url(), final_title);
-
- // Don't allow the title to be saved again for explicitly set ones.
+ if (!received_page_title_) {
+ UpdateHistoryPageTitle(*entry);
received_page_title_ = explicit_set;
}
@@ -1872,8 +1948,7 @@ void TabContents::OnUserGesture() {
g_browser_process->download_request_limiter();
if (limiter)
limiter->OnUserGesture(this);
- ExternalProtocolHandler::OnUserGesture();
- controller_.OnUserGesture();
+ ExternalProtocolHandler::PermitLaunchUrl();
}
void TabContents::OnFindReply(int request_id,
@@ -1912,8 +1987,17 @@ void TabContents::OnFindReply(int request_id,
}
void TabContents::GoToEntryAtOffset(int offset) {
- if (!delegate_ || delegate_->OnGoToEntryOffset(offset))
- controller_.GoToOffset(offset);
+ if (!delegate_ || delegate_->OnGoToEntryOffset(offset)) {
+ NavigationEntry* entry = controller_.GetEntryAtOffset(offset);
+ if (!entry)
+ return;
+ // Note that we don't call NavigationController::GotToOffset() as we don't
+ // want to create a pending navigation entry (it might end up lingering
+ // http://crbug.com/51680).
+ entry->set_transition_type(entry->transition_type() |
+ PageTransition::FORWARD_BACK);
+ NavigateToEntry(*entry, NavigationController::NO_RELOAD);
+ }
}
void TabContents::OnMissingPluginStatus(int status) {
@@ -1949,13 +2033,14 @@ void TabContents::OnCrashedPlugin(const FilePath& plugin_path) {
SkBitmap* crash_icon = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_INFOBAR_PLUGIN_CRASHED);
AddInfoBar(new SimpleAlertInfoBarDelegate(
- this, l10n_util::GetStringF(IDS_PLUGIN_CRASHED_PROMPT, plugin_name),
+ this, l10n_util::GetStringFUTF16(IDS_PLUGIN_CRASHED_PROMPT,
+ WideToUTF16Hack(plugin_name)),
crash_icon, true));
}
void TabContents::OnCrashedWorker() {
AddInfoBar(new SimpleAlertInfoBarDelegate(
- this, l10n_util::GetString(IDS_WEBWORKER_CRASHED_PROMPT),
+ this, l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT),
NULL, true));
}
@@ -1968,6 +2053,11 @@ void TabContents::OnDidGetApplicationInfo(
delegate()->OnDidGetApplicationInfo(this, page_id);
}
+void TabContents::OnDisabledOutdatedPlugin(const string16& name,
+ const GURL& update_url) {
+ new DisabledPluginInfoBar(this, name, update_url);
+}
+
void TabContents::OnPageContents(const GURL& url,
int renderer_process_id,
int32 page_id,
@@ -2015,6 +2105,11 @@ void TabContents::OnPageTranslated(int32 page_id,
Details<PageTranslatedDetails>(&details));
}
+void TabContents::OnSetSuggestResult(int32 page_id, const std::string& result) {
+ if (delegate())
+ delegate()->OnSetSuggestResult(page_id, result);
+}
+
void TabContents::DidStartProvisionalLoadForFrame(
RenderViewHost* render_view_host,
bool is_main_frame,
@@ -2026,6 +2121,10 @@ void TabContents::DidStartProvisionalLoadForFrame(
NotificationType::FRAME_PROVISIONAL_LOAD_START,
Source<NavigationController>(&controller_),
Details<ProvisionalLoadDetails>(&details));
+ if (is_main_frame) {
+ content_settings_delegate_->ClearCookieSpecificContentSettings();
+ content_settings_delegate_->ClearGeolocationContentSettings();
+ }
}
void TabContents::DidStartReceivingResourceResponse(
@@ -2050,7 +2149,7 @@ void TabContents::DidLoadResourceFromMemoryCache(
const std::string& main_frame_origin,
const std::string& security_info) {
// Send out a notification that we loaded a resource from our memory cache.
- int cert_id = 0, cert_status = 0, security_bits = 0, connection_status = 0;
+ int cert_id = 0, cert_status = 0, security_bits = -1, connection_status = 0;
SSLManager::DeserializeSecurityInfo(security_info,
&cert_id, &cert_status,
&security_bits,
@@ -2134,7 +2233,7 @@ void TabContents::DocumentLoadedInFrame() {
controller_.DocumentLoadedInFrame();
}
-void TabContents::OnContentSettingsChange() {
+void TabContents::OnContentSettingsAccessed(bool content_was_blocked) {
if (delegate_)
delegate_->OnContentSettingsChange(this);
}
@@ -2184,10 +2283,22 @@ RenderViewHostDelegate::AutoFill* TabContents::GetAutoFillDelegate() {
return GetAutoFillManager();
}
+RenderViewHostDelegate::BlockedPlugin* TabContents::GetBlockedPluginDelegate() {
+ if (blocked_plugin_manager_.get() == NULL)
+ blocked_plugin_manager_.reset(new BlockedPluginManager(this));
+ return blocked_plugin_manager_.get();
+}
+
RenderViewHostDelegate::SSL* TabContents::GetSSLDelegate() {
return GetSSLHelper();
}
+RenderViewHostDelegate::FileSelect* TabContents::GetFileSelectDelegate() {
+ if (file_select_helper_.get() == NULL)
+ file_select_helper_.reset(new FileSelectHelper(profile()));
+ return file_select_helper_.get();
+}
+
AutomationResourceRoutingDelegate*
TabContents::GetAutomationResourceRoutingDelegate() {
return delegate();
@@ -2259,8 +2370,10 @@ void TabContents::RenderViewReady(RenderViewHost* rvh) {
// Restore the focus to the tab (otherwise the focus will be on the top
// window).
- if (was_crashed && !FocusLocationBarByDefault())
+ if (was_crashed && !FocusLocationBarByDefault() &&
+ (!delegate_ || delegate_->ShouldFocusPageAfterCrash())) {
Focus();
+ }
}
void TabContents::RenderViewGone(RenderViewHost* rvh) {
@@ -2305,14 +2418,11 @@ void TabContents::DidNavigate(RenderViewHost* rvh,
if (PageTransition::IsMainFrame(params.transition)) {
bool was_bookmark_bar_visible = ShouldShowBookmarkBar();
- bool was_extension_shelf_visible = IsExtensionShelfAlwaysVisible();
render_manager_.DidNavigateMainFrame(rvh);
if (was_bookmark_bar_visible != ShouldShowBookmarkBar())
extra_invalidate_flags |= INVALIDATE_BOOKMARK_BAR;
- if (was_extension_shelf_visible != IsExtensionShelfAlwaysVisible())
- extra_invalidate_flags |= INVALIDATE_EXTENSION_SHELF;
}
// Update the site of the SiteInstance if it doesn't have one yet.
@@ -2334,15 +2444,44 @@ void TabContents::DidNavigate(RenderViewHost* rvh,
bool did_navigate = controller_.RendererDidNavigate(
params, extra_invalidate_flags, &details);
+ // Send notification about committed provisional loads. This notification is
+ // different from the NAV_ENTRY_COMMITTED notification which doesn't include
+ // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations.
+ if (details.type != NavigationType::NAV_IGNORE) {
+ ProvisionalLoadDetails load_details(details.is_main_frame,
+ details.is_in_page,
+ params.url, std::string(), false);
+ 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
+ // entry list.
+ if (did_navigate &&
+ (controller_.GetActiveEntry()->transition_type() &
+ PageTransition::FORWARD_BACK)) {
+ load_details.set_transition_type(
+ params.transition | PageTransition::FORWARD_BACK);
+ }
+ NotificationService::current()->Notify(
+ NotificationType::FRAME_PROVISIONAL_LOAD_COMMITTED,
+ Source<NavigationController>(&controller_),
+ Details<ProvisionalLoadDetails>(&load_details));
+
+ }
+
// Update history. Note that this needs to happen after the entry is complete,
// which WillNavigate[Main,Sub]Frame will do before this function is called.
- if (params.should_update_history &&
- (!delegate() || delegate()->ShouldAddNavigationsToHistory())) {
+ if (params.should_update_history) {
// Most of the time, the displayURL matches the loaded URL, but for about:
- // URLs, we use a data: URL as the real value. We actually want to save
- // the about: URL to the history db and keep the data: URL hidden. This is
- // what the TabContents' URL getter does.
- UpdateHistoryForNavigation(GetURL(), details, params);
+ // URLs, we use a data: URL as the real value. We actually want to save the
+ // about: URL to the history db and keep the data: URL hidden. This is what
+ // the TabContents' URL getter does.
+ scoped_refptr<history::HistoryAddPageArgs> add_page_args(
+ CreateHistoryAddPageArgs(GetURL(), details, params));
+ if (!delegate() ||
+ delegate()->ShouldAddNavigationToHistory(*add_page_args,
+ details.type)) {
+ UpdateHistoryForNavigation(add_page_args);
+ }
}
if (!did_navigate)
@@ -2389,8 +2528,8 @@ void TabContents::UpdateTitle(RenderViewHost* rvh,
SetNotWaitingForResponse();
DCHECK(rvh == render_view_host());
- NavigationEntry* entry = controller_.GetEntryWithPageID(GetSiteInstance(),
- page_id);
+ NavigationEntry* entry = controller_.GetEntryWithPageID(rvh->site_instance(),
+ page_id);
if (!entry || !UpdateTitleForEntry(entry, title))
return;
@@ -2413,7 +2552,7 @@ void TabContents::UpdateThumbnail(const GURL& url,
const SkBitmap& bitmap,
const ThumbnailScore& score) {
// Tell History about this thumbnail
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTopSites)) {
+ if (history::TopSites::IsEnabled()) {
if (!profile()->IsOffTheRecord())
profile()->GetTopSites()->SetPageThumbnail(url, bitmap, score);
} else {
@@ -2430,7 +2569,7 @@ void TabContents::UpdateInspectorSetting(const std::string& key,
DictionaryValue* inspector_settings =
profile()->GetPrefs()->GetMutableDictionary(
prefs::kWebKitInspectorSettings);
- inspector_settings->SetWithoutPathExpansion(UTF8ToWide(key),
+ inspector_settings->SetWithoutPathExpansion(key,
Value::CreateStringValue(value));
}
@@ -2475,6 +2614,9 @@ void TabContents::RequestMove(const gfx::Rect& new_bounds) {
}
void TabContents::DidStartLoading() {
+ // By default, we assume that the content is not PDF. The renderer
+ // will tell us if this is not the case.
+ displaying_pdf_content_ = false;
SetIsLoading(true, NULL);
}
@@ -2502,6 +2644,15 @@ void TabContents::DidStopLoading() {
SetIsLoading(false, details.get());
}
+void TabContents::DocumentOnLoadCompletedInMainFrame(
+ RenderViewHost* render_view_host,
+ int32 page_id) {
+ NotificationService::current()->Notify(
+ NotificationType::LOAD_COMPLETED_MAIN_FRAME,
+ Source<TabContents>(this),
+ Details<int>(&page_id));
+}
+
void TabContents::DidRedirectProvisionalLoad(int32 page_id,
const GURL& source_url,
const GURL& target_url) {
@@ -2537,20 +2688,15 @@ void TabContents::DomOperationResponse(const std::string& json_string,
int automation_id) {
}
-void TabContents::ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback) {
+void TabContents::ProcessDOMUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {
if (!render_manager_.dom_ui()) {
// This can happen if someone uses window.open() to open an extension URL
// from a non-extension context.
- render_view_host()->BlockExtensionRequest(request_id);
+ render_view_host()->BlockExtensionRequest(params.request_id);
return;
}
- render_manager_.dom_ui()->ProcessDOMUIMessage(message, content, source_url,
- request_id,
- has_callback);
+ render_manager_.dom_ui()->ProcessDOMUIMessage(params);
}
void TabContents::ProcessExternalHostMessage(const std::string& message,
@@ -2560,35 +2706,6 @@ void TabContents::ProcessExternalHostMessage(const std::string& message,
delegate()->ForwardMessageToExternalHost(message, origin, target);
}
-void TabContents::RunFileChooser(
- const ViewHostMsg_RunFileChooser_Params &params) {
- if (!select_file_dialog_.get())
- select_file_dialog_ = SelectFileDialog::Create(this);
-
- SelectFileDialog::Type dialog_type;
- switch (params.mode) {
- case ViewHostMsg_RunFileChooser_Params::Open:
- dialog_type = SelectFileDialog::SELECT_OPEN_FILE;
- break;
- case ViewHostMsg_RunFileChooser_Params::OpenMultiple:
- dialog_type = SelectFileDialog::SELECT_OPEN_MULTI_FILE;
- break;
- case ViewHostMsg_RunFileChooser_Params::Save:
- dialog_type = SelectFileDialog::SELECT_SAVEAS_FILE;
- break;
- default:
- dialog_type = SelectFileDialog::SELECT_OPEN_FILE; // Prevent warning.
- NOTREACHED();
- }
- FilePath default_file_name = params.default_file_name;
- if (default_file_name.empty())
- default_file_name = profile()->last_selected_directory();
- select_file_dialog_->SelectFile(dialog_type, params.title,
- default_file_name,
- NULL, 0, FILE_PATH_LITERAL(""),
- view_->GetTopLevelNativeWindow(), NULL);
-}
-
void TabContents::RunJavaScriptMessage(
const std::wstring& message,
const std::wstring& default_prompt,
@@ -2620,8 +2737,8 @@ void TabContents::RunJavaScriptMessage(
base::TimeDelta::FromMilliseconds(kJavascriptMessageExpectedDelay))
show_suppress_checkbox = true;
- RunJavascriptMessageBox(this, frame_url, flags, message, default_prompt,
- show_suppress_checkbox, reply_msg);
+ RunJavascriptMessageBox(profile(), this, frame_url, flags, message,
+ default_prompt, show_suppress_checkbox, reply_msg);
} else {
// If we are suppressing messages, just reply as is if the user immediately
// pressed "Cancel".
@@ -2728,60 +2845,6 @@ void TabContents::PageHasOSDD(RenderViewHost* render_view_host,
autodetected);
}
-// Indicates if the two inputs have the same security origin.
-// |requested_origin| should only be a security origin (no path, etc.).
-// It is ok if |template_url| is NULL.
-static bool IsSameOrigin(const GURL& requested_origin,
- const TemplateURL* template_url) {
- DCHECK(requested_origin == requested_origin.GetOrigin());
- return template_url && requested_origin ==
- TemplateURLModel::GenerateSearchURL(template_url).GetOrigin();
-}
-
-ViewHostMsg_GetSearchProviderInstallState_Params
- TabContents::GetSearchProviderInstallState(const GURL& requested_host) {
- // Get the last committed entry since that is the page executing the
- // javascript as opposed to a page being navigated to. We don't want
- // to trust the page to tell us the url to avoid using potentially
- // compromised information.
- NavigationEntry* entry = controller_.GetLastCommittedEntry();
- GURL page_origin = entry ? entry->virtual_url().GetOrigin() : GURL();
- GURL requested_origin = requested_host.GetOrigin();
- // Do the security check before any others to avoid information leaks.
- if (page_origin != 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 (profile()->IsOffTheRecord())
- return ViewHostMsg_GetSearchProviderInstallState_Params::NotInstalled();
-
- TemplateURLModel* url_model = profile()->GetTemplateURLModel();
- if (!url_model)
- return ViewHostMsg_GetSearchProviderInstallState_Params::NotInstalled();
- if (!url_model->loaded())
- url_model->Load();
-
- // First check to see if the url is the default search provider.
- if (IsSameOrigin(requested_origin, url_model->GetDefaultSearchProvider())) {
- return ViewHostMsg_GetSearchProviderInstallState_Params::
- InstalledAsDefault();
- }
-
- // Is the url any search provider?
- std::vector<const TemplateURL*> urls = url_model->GetTemplateURLs();
- for (std::vector<const TemplateURL*>::iterator i = urls.begin();
- i != urls.end(); ++i) {
- const TemplateURL* template_url = (*i);
- if (IsSameOrigin(requested_origin, template_url)) {
- return ViewHostMsg_GetSearchProviderInstallState_Params::
- InstallButNotDefault();
- }
- }
- return ViewHostMsg_GetSearchProviderInstallState_Params::NotInstalled();
-}
-
GURL TabContents::GetAlternateErrorPageURL() const {
GURL url;
// Disable alternate error pages when in OffTheRecord/Incognito mode.
@@ -2801,7 +2864,25 @@ GURL TabContents::GetAlternateErrorPageURL() const {
WebPreferences TabContents::GetWebkitPrefs() {
Profile* profile = render_view_host()->process()->profile();
bool is_dom_ui = false;
- return RenderViewHostDelegateHelper::GetWebkitPrefs(profile, is_dom_ui);
+ WebPreferences web_prefs =
+ RenderViewHostDelegateHelper::GetWebkitPrefs(profile, is_dom_ui);
+
+ // Force accelerated compositing and 2d canvas off for chrome: and
+ // chrome-extension: pages.
+ if (GetURL().SchemeIs(chrome::kChromeUIScheme) ||
+ GetURL().SchemeIs(chrome::kExtensionScheme)) {
+ web_prefs.accelerated_compositing_enabled = false;
+ web_prefs.accelerated_2d_canvas_enabled = false;
+ }
+
+#if defined(OS_MACOSX)
+ // Disable accelerated compositing if IOSurface's are not supported,
+ // as is the case in 10.5.
+ if (!IOSurfaceSupport::Initialize())
+ web_prefs.accelerated_compositing_enabled = false;
+#endif
+
+ return web_prefs;
}
void TabContents::OnIgnoredUIEvent() {
@@ -2813,7 +2894,8 @@ void TabContents::OnIgnoredUIEvent() {
void TabContents::OnJSOutOfMemory() {
AddInfoBar(new SimpleAlertInfoBarDelegate(
- this, l10n_util::GetString(IDS_JS_OUT_OF_MEMORY_PROMPT), NULL, true));
+ this, l10n_util::GetStringUTF16(IDS_JS_OUT_OF_MEMORY_PROMPT),
+ NULL, true));
}
void TabContents::OnCrossSiteResponse(int new_render_process_host_id,
@@ -2893,25 +2975,10 @@ void TabContents::FocusedNodeChanged() {
NotificationService::NoDetails());
}
-void TabContents::FileSelected(const FilePath& path,
- int index, void* params) {
- profile()->set_last_selected_directory(path.DirName());
- std::vector<FilePath> files;
- files.push_back(path);
- render_view_host()->FilesSelectedInChooser(files);
-}
-
-void TabContents::MultiFilesSelected(const std::vector<FilePath>& files,
- void* params) {
- if (!files.empty())
- profile()->set_last_selected_directory(files[0].DirName());
- render_view_host()->FilesSelectedInChooser(files);
-}
-
-void TabContents::FileSelectionCanceled(void* params) {
- // If the user cancels choosing a file to upload we pass back an
- // empty vector.
- render_view_host()->FilesSelectedInChooser(std::vector<FilePath>());
+void TabContents::SetDisplayingPDFContent() {
+ displaying_pdf_content_ = true;
+ if (delegate())
+ delegate()->ContentTypeChanged(this);
}
void TabContents::BeforeUnloadFiredFromRenderManager(
@@ -2963,11 +3030,7 @@ bool TabContents::CreateRenderViewForRenderManager(
RenderViewHost* render_view_host) {
RenderWidgetHostView* rwh_view = view_->CreateViewForWidget(render_view_host);
- scoped_refptr<URLRequestContextGetter> request_context = request_context_;
- if (!request_context.get())
- request_context = profile()->GetRequestContext();
-
- if (!render_view_host->CreateRenderView(request_context, string16()))
+ if (!render_view_host->CreateRenderView(string16()))
return false;
// Now that the RenderView has been created, we need to tell it its size.
@@ -2995,12 +3058,12 @@ void TabContents::Observe(NotificationType type,
break;
}
case NotificationType::PREF_CHANGED: {
- std::wstring* pref_name_in = Details<std::wstring>(details).ptr();
+ std::string* pref_name_in = Details<std::string>(details).ptr();
DCHECK(Source<PrefService>(source).ptr() == profile()->GetPrefs());
if (*pref_name_in == prefs::kAlternateErrorPagesEnabled) {
UpdateAlternateErrorPageURL();
} else if (*pref_name_in == prefs::kDefaultCharset ||
- StartsWithASCII(WideToUTF8(*pref_name_in), "webkit.webprefs.", true)
+ StartsWithASCII(*pref_name_in, "webkit.webprefs.", true)
) {
UpdateWebPreferences();
} else {
@@ -3069,7 +3132,8 @@ void TabContents::UpdateExtensionAppIcon(Extension* extension) {
extension_app_image_loader_.reset(new ImageLoadingTracker(this));
extension_app_image_loader_->LoadImage(
extension,
- extension->GetIconPath(Extension::EXTENSION_ICON_SMALLISH),
+ extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_EXACTLY),
gfx::Size(Extension::EXTENSION_ICON_SMALLISH,
Extension::EXTENSION_ICON_SMALLISH),
ImageLoadingTracker::CACHE);
@@ -3096,34 +3160,6 @@ void TabContents::OnImageLoaded(SkBitmap* image, ExtensionResource resource,
}
}
-std::wstring TabContents::GetMessageBoxTitle(const GURL& frame_url,
- bool is_alert) {
- if (!frame_url.has_host())
- return l10n_util::GetString(
- is_alert ? IDS_JAVASCRIPT_ALERT_DEFAULT_TITLE
- : IDS_JAVASCRIPT_MESSAGEBOX_DEFAULT_TITLE);
-
- // We really only want the scheme, hostname, and port.
- GURL::Replacements replacements;
- replacements.ClearUsername();
- replacements.ClearPassword();
- replacements.ClearPath();
- replacements.ClearQuery();
- replacements.ClearRef();
- GURL clean_url = frame_url.ReplaceComponents(replacements);
-
- // TODO(brettw) it should be easier than this to do the correct language
- // handling without getting the accept language from the profile.
- std::wstring base_address = gfx::ElideUrl(clean_url, gfx::Font(), 0,
- UTF8ToWide(profile()->GetPrefs()->GetString(prefs::kAcceptLanguages)));
- // Force URL to have LTR directionality.
- base::i18n::GetDisplayStringInLTRDirectionality(&base_address);
-
- return l10n_util::GetStringF(
- is_alert ? IDS_JAVASCRIPT_ALERT_TITLE : IDS_JAVASCRIPT_MESSAGEBOX_TITLE,
- base_address);
-}
-
gfx::NativeWindow TabContents::GetMessageBoxRootWindow() {
return view_->GetTopLevelNativeWindow();
}
@@ -3176,20 +3212,21 @@ class SavePasswordInfoBarDelegate : public ConfirmInfoBarDelegate {
PasswordFormManager* form_to_save)
: ConfirmInfoBarDelegate(tab_contents),
form_to_save_(form_to_save),
- infobar_response_(kNoResponse) {
- }
+ infobar_response_(NO_RESPONSE) {}
- virtual ~SavePasswordInfoBarDelegate() { }
+ virtual ~SavePasswordInfoBarDelegate() {}
- // Overridden from ConfirmInfoBarDelegate:
+ // Begin ConfirmInfoBarDelegate implementation.
virtual void InfoBarClosed() {
UMA_HISTOGRAM_ENUMERATION("PasswordManager.InfoBarResponse",
- infobar_response_, kNumResponseTypes);
+ infobar_response_, NUM_RESPONSE_TYPES);
delete this;
}
- virtual std::wstring GetMessageText() const {
- return l10n_util::GetString(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT);
+ virtual Type GetInfoBarType() { return PAGE_ACTION_TYPE; }
+
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT);
}
virtual SkBitmap* GetIcon() const {
@@ -3201,28 +3238,29 @@ class SavePasswordInfoBarDelegate : public ConfirmInfoBarDelegate {
return BUTTON_OK | BUTTON_CANCEL;
}
- virtual std::wstring GetButtonLabel(InfoBarButton button) const {
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
if (button == BUTTON_OK)
- return l10n_util::GetString(IDS_PASSWORD_MANAGER_SAVE_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON);
if (button == BUTTON_CANCEL)
- return l10n_util::GetString(IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON);
+ return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON);
NOTREACHED();
- return std::wstring();
+ return string16();
}
virtual bool Accept() {
DCHECK(form_to_save_.get());
form_to_save_->Save();
- infobar_response_ = kRememberPassword;
+ infobar_response_ = REMEMBER_PASSWORD;
return true;
}
virtual bool Cancel() {
DCHECK(form_to_save_.get());
form_to_save_->PermanentlyBlacklist();
- infobar_response_ = kDontRememberPassword;
+ infobar_response_ = DONT_REMEMBER_PASSWORD;
return true;
}
+ // End ConfirmInfoBarDelegate implementation.
private:
// The PasswordFormManager managing the form we're asking the user about,
@@ -3231,10 +3269,10 @@ class SavePasswordInfoBarDelegate : public ConfirmInfoBarDelegate {
// Used to track the results we get from the info bar.
enum ResponseType {
- kNoResponse = 0,
- kRememberPassword,
- kDontRememberPassword,
- kNumResponseTypes,
+ NO_RESPONSE = 0,
+ REMEMBER_PASSWORD,
+ DONT_REMEMBER_PASSWORD,
+ NUM_RESPONSE_TYPES,
};
ResponseType infobar_response_;
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index a3e5917..7493534 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_H_
+#pragma once
#ifdef ANDROID
#include "chrome/browser/profile.h"
@@ -39,7 +40,6 @@ private:
#include <deque>
#include <map>
-#include <set>
#include <string>
#include <vector>
@@ -54,8 +54,8 @@ private:
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/find_notification_details.h"
#include "chrome/browser/jsmessage_box_client.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/password_manager/password_manager_delegate.h"
-#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/constrained_window.h"
#include "chrome/browser/tab_contents/language_state.h"
@@ -75,15 +75,10 @@ private:
namespace gfx {
class Rect;
-class Size;
}
-namespace views {
-class WindowDelegate;
-}
-
-namespace base {
-class WaitableEvent;
+namespace history {
+class HistoryAddPageArgs;
}
namespace printing {
@@ -100,11 +95,12 @@ struct PasswordForm;
class AutocompleteHistoryManager;
class AutoFillManager;
+class BlockedPluginManager;
class BlockedPopupContainer;
class DOMUI;
class DownloadItem;
class Extension;
-class GeolocationSettingsState;
+class FileSelectHelper;
class InfoBarDelegate;
class LoadNotificationDetails;
class OmniboxSearchHint;
@@ -113,19 +109,17 @@ class PluginInstaller;
class Profile;
struct RendererPreferences;
class RenderViewHost;
+class SessionStorageNamespace;
class SiteInstance;
class SkBitmap;
class TabContents;
class TabContentsDelegate;
-class TabContentsFactory;
class TabContentsSSLHelper;
class TabContentsView;
class URLPattern;
-class URLRequestContextGetter;
struct ThumbnailScore;
-struct ViewHostMsg_DidPrintPage_Params;
+struct ViewHostMsg_DomMessage_Params;
struct ViewHostMsg_FrameNavigate_Params;
-struct ViewHostMsg_RunFileChooser_Params;
struct WebPreferences;
// Describes what goes in the main content area of a tab. TabContents is
@@ -136,7 +130,6 @@ class TabContents : public PageNavigator,
public RenderViewHostDelegate::BrowserIntegration,
public RenderViewHostDelegate::Resource,
public RenderViewHostManager::Delegate,
- public SelectFileDialog::Listener,
public JavaScriptMessageBoxClient,
public ImageLoadingTracker::Observer,
public PasswordManagerDelegate,
@@ -152,18 +145,21 @@ class TabContents : public PageNavigator,
INVALIDATE_PAGE_ACTIONS = 1 << 3, // Page action icons have changed.
INVALIDATE_BOOKMARK_BAR = 1 << 4, // State of ShouldShowBookmarkBar
// changed.
- INVALIDATE_EXTENSION_SHELF = 1 << 5, // State of
- // IsExtensionShelfAlwaysVisible
- // changed.
- INVALIDATE_TITLE = 1 << 6, // The title changed.
+ INVALIDATE_TITLE = 1 << 5, // The title changed.
};
// |base_tab_contents| is used if we want to size the new tab contents view
// based on an existing tab contents view. This can be NULL if not needed.
+ //
+ // The session storage namespace parameter allows multiple render views and
+ // tab contentses to share the same session storage (part of the WebStorage
+ // spec) space. This is useful when restoring tabs, but most callers should
+ // pass in NULL which will cause a new SessionStorageNamespace to be created.
TabContents(Profile* profile,
SiteInstance* site_instance,
int routing_id,
- const TabContents* base_tab_contents);
+ const TabContents* base_tab_contents,
+ SessionStorageNamespace* session_storage_namespace);
virtual ~TabContents();
static void RegisterUserPrefs(PrefService* prefs);
@@ -199,7 +195,7 @@ class TabContents : public PageNavigator,
// Returns the PluginInstaller, creating it if necessary.
PluginInstaller* GetPluginInstaller();
- // Returns the TabContentsSSLHelper, creating if it necessary.
+ // Returns the TabContentsSSLHelper, creating it if necessary.
TabContentsSSLHelper* GetSSLHelper();
// Returns the SavePackage which manages the page saving job. May be NULL.
@@ -365,6 +361,9 @@ class TabContents : public PageNavigator,
// to the foreground if necessary.
void Activate();
+ // Deactivates this contents by deactivating its containing window.
+ void Deactivate();
+
// TODO(brettw) document these.
virtual void ShowContents();
virtual void HideContents();
@@ -504,9 +503,6 @@ class TabContents : public PageNavigator,
// Returns true if a Bookmark Bar should be shown for this tab.
virtual bool ShouldShowBookmarkBar();
- // Returns whether the extension shelf should be visible.
- virtual bool IsExtensionShelfAlwaysVisible();
-
// Notifies the delegate that a download is about to be started.
// This notification is fired before a local temporary file has been created.
bool CanDownload(int request_id);
@@ -681,12 +677,6 @@ class TabContents : public PageNavigator,
// times, subsequent calls are ignored.
void OnCloseStarted();
- // Getter/Setters for the url request context to be used for this tab.
- void set_request_context(URLRequestContextGetter* context);
- URLRequestContextGetter* request_context() const {
- return request_context_.get();
- }
-
LanguageState& language_state() {
return language_state_;
}
@@ -710,9 +700,9 @@ class TabContents : public PageNavigator,
}
bool closed_by_user_gesture() const { return closed_by_user_gesture_; }
+ bool is_displaying_pdf_content() const { return displaying_pdf_content_; }
+
// JavaScriptMessageBoxClient ------------------------------------------------
- virtual std::wstring GetMessageBoxTitle(const GURL& frame_url,
- bool is_alert);
virtual gfx::NativeWindow GetMessageBoxRootWindow();
virtual void OnMessageBoxClosed(IPC::Message* reply_msg,
bool success,
@@ -742,11 +732,20 @@ class TabContents : public PageNavigator,
virtual Profile* GetProfileForPasswordManager();
virtual bool DidLastPageLoadEncounterSSLErrors();
+ // Updates history with the specified navigation. This is called by
+ // OnMsgNavigate to update history state.
+ void UpdateHistoryForNavigation(
+ scoped_refptr<history::HistoryAddPageArgs> add_page_args);
+
+ // Sends the page title to the history service. This is called when we receive
+ // the page title and we know we want to update history.
+ void UpdateHistoryPageTitle(const NavigationEntry& entry);
+
private:
friend class NavigationController;
// Used to access the child_windows_ (ConstrainedWindowList) for testing
// automation purposes.
- friend class AutomationProvider;
+ friend class TestingAutomationProvider;
FRIEND_TEST_ALL_PREFIXES(TabContentsTest, NoJSMessageOnInterstitials);
FRIEND_TEST_ALL_PREFIXES(TabContentsTest, UpdateTitle);
@@ -768,7 +767,7 @@ class TabContents : public PageNavigator,
// TODO(brettw) TestTabContents shouldn't exist!
friend class TestTabContents;
- // Used to access the UpdateHistoryForNavigation member function.
+ // Used to access the CreateHistoryAddPageArgs member function.
friend class ExternalTabContainer;
// Changes the IsLoading state and notifies delegate as needed
@@ -834,9 +833,10 @@ class TabContents : public PageNavigator,
void UpdateMaxPageIDIfNecessary(SiteInstance* site_instance,
RenderViewHost* rvh);
- // Called by OnMsgNavigate to update history state. Overridden by subclasses
- // that don't want to be added to history.
- virtual void UpdateHistoryForNavigation(const GURL& virtual_url,
+ // Returns the history::HistoryAddPageArgs to use for adding a page to
+ // history.
+ scoped_refptr<history::HistoryAddPageArgs> CreateHistoryAddPageArgs(
+ const GURL& virtual_url,
const NavigationController::LoadCommittedDetails& details,
const ViewHostMsg_FrameNavigate_Params& params);
@@ -850,6 +850,12 @@ class TabContents : public PageNavigator,
// different and was therefore updated.
bool UpdateTitleForEntry(NavigationEntry* entry, const std::wstring& title);
+ // Causes the TabContents to navigate in the right renderer to |entry|, which
+ // must be already part of the entries in the navigation controller.
+ // This does not change the NavigationController state.
+ bool NavigateToEntry(const NavigationEntry& entry,
+ NavigationController::ReloadType reload_type);
+
// Misc non-view stuff -------------------------------------------------------
// Helper functions for sending notifications.
@@ -861,8 +867,8 @@ class TabContents : public PageNavigator,
void GenerateKeywordIfNecessary(
const ViewHostMsg_FrameNavigate_Params& params);
- // ContentBlockedDelegate::Delegate implementation.
- virtual void OnContentSettingsChange();
+ // TabSpecificContentSettings::Delegate implementation.
+ virtual void OnContentSettingsAccessed(bool content_was_blocked);
// RenderViewHostDelegate ----------------------------------------------------
@@ -880,6 +886,8 @@ class TabContents : public PageNavigator,
virtual void OnDidGetApplicationInfo(
int32 page_id,
const webkit_glue::WebApplicationInfo& info);
+ virtual void OnDisabledOutdatedPlugin(const string16& name,
+ const GURL& update_url);
virtual void OnPageContents(const GURL& url,
int renderer_process_id,
int32 page_id,
@@ -890,6 +898,7 @@ class TabContents : public PageNavigator,
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type);
+ virtual void OnSetSuggestResult(int32 page_id, const std::string& result);
// RenderViewHostDelegate::Resource implementation.
virtual void DidStartProvisionalLoadForFrame(RenderViewHost* render_view_host,
@@ -930,7 +939,9 @@ class TabContents : public PageNavigator,
virtual RenderViewHostDelegate::FavIcon* GetFavIconDelegate();
virtual RenderViewHostDelegate::Autocomplete* GetAutocompleteDelegate();
virtual RenderViewHostDelegate::AutoFill* GetAutoFillDelegate();
+ virtual RenderViewHostDelegate::BlockedPlugin* GetBlockedPluginDelegate();
virtual RenderViewHostDelegate::SSL* GetSSLDelegate();
+ virtual RenderViewHostDelegate::FileSelect* GetFileSelectDelegate();
virtual AutomationResourceRoutingDelegate*
GetAutomationResourceRoutingDelegate();
virtual TabContents* GetAsTabContents();
@@ -961,19 +972,17 @@ class TabContents : public PageNavigator,
virtual void RequestMove(const gfx::Rect& new_bounds);
virtual void DidStartLoading();
virtual void DidStopLoading();
+ virtual void DocumentOnLoadCompletedInMainFrame(
+ RenderViewHost* render_view_host,
+ int32 page_id);
virtual void RequestOpenURL(const GURL& url, const GURL& referrer,
WindowOpenDisposition disposition);
virtual void DomOperationResponse(const std::string& json_string,
int automation_id);
- virtual void ProcessDOMUIMessage(const std::string& message,
- const ListValue* content,
- const GURL& source_url,
- int request_id,
- bool has_callback);
+ virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params);
virtual void ProcessExternalHostMessage(const std::string& message,
const std::string& origin,
const std::string& target);
- virtual void RunFileChooser(const ViewHostMsg_RunFileChooser_Params& params);
virtual void RunJavaScriptMessage(const std::wstring& message,
const std::wstring& default_prompt,
const GURL& frame_url,
@@ -991,8 +1000,6 @@ class TabContents : public PageNavigator,
const std::vector<webkit_glue::PasswordForm>& visible_forms);
virtual void PageHasOSDD(RenderViewHost* render_view_host,
int32 page_id, const GURL& url, bool autodetected);
- virtual ViewHostMsg_GetSearchProviderInstallState_Params
- GetSearchProviderInstallState(const GURL& url);
virtual GURL GetAlternateErrorPageURL() const;
virtual RendererPreferences GetRendererPrefs(Profile* profile) const;
virtual WebPreferences GetWebkitPrefs();
@@ -1009,13 +1016,7 @@ class TabContents : public PageNavigator,
virtual bool IsExternalTabContainer() const;
virtual void DidInsertCSS();
virtual void FocusedNodeChanged();
-
- // SelectFileDialog::Listener ------------------------------------------------
-
- virtual void FileSelected(const FilePath& path, int index, void* params);
- virtual void MultiFilesSelected(const std::vector<FilePath>& files,
- void* params);
- virtual void FileSelectionCanceled(void* params);
+ virtual void SetDisplayingPDFContent();
// RenderViewHostManager::Delegate -------------------------------------------
@@ -1087,6 +1088,9 @@ class TabContents : public PageNavigator,
// Registers and unregisters us for notifications.
NotificationRegistrar registrar_;
+ // Registers and unregisters for pref notifications.
+ PrefChangeRegistrar pref_change_registrar_;
+
// Handles print preview and print job for this contents.
scoped_ptr<printing::PrintViewManager> printing_;
@@ -1108,15 +1112,18 @@ class TabContents : public PageNavigator,
// TabContentsSSLHelper, lazily created.
scoped_ptr<TabContentsSSLHelper> ssl_helper_;
+ // BlockedPluginManager, lazily created.
+ scoped_ptr<BlockedPluginManager> blocked_plugin_manager_;
+
+ // FileSelectHelper, lazily created.
+ scoped_ptr<FileSelectHelper> file_select_helper_;
+
// Handles drag and drop event forwarding to extensions.
BookmarkDrag* bookmark_drag_;
// Handles downloading favicons.
FavIconHelper fav_icon_helper_;
- // Dialog box used for choosing files to upload from file form fields.
- scoped_refptr<SelectFileDialog> select_file_dialog_;
-
// Cached web app info data.
webkit_glue::WebApplicationInfo web_app_info_;
@@ -1291,17 +1298,15 @@ class TabContents : public PageNavigator,
// The time that we started to close the tab.
base::TimeTicks tab_close_start_time_;
- // Contextual information to be used for requests created here.
- // Can be NULL in which case we defer to the request context from the
- // profile
- scoped_refptr<URLRequestContextGetter> request_context_;
-
// Information about the language the page is in and has been translated to.
LanguageState language_state_;
// See description above setter.
bool closed_by_user_gesture_;
+ // See description in RenderViewHostDelegate::SetDisplayingPDFContent.
+ bool displaying_pdf_content_;
+
// ---------------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN(TabContents);
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.cc b/chrome/browser/tab_contents/tab_contents_delegate.cc
index 7ba80d6..5f82ead 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.cc
+++ b/chrome/browser/tab_contents/tab_contents_delegate.cc
@@ -4,13 +4,26 @@
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "gfx/rect.h"
+
void TabContentsDelegate::DetachContents(TabContents* source) {
}
+bool TabContentsDelegate::IsPopup(const TabContents* source) const {
+ return false;
+}
+
TabContents* TabContentsDelegate::GetConstrainingContents(TabContents* source) {
return source;
}
+bool TabContentsDelegate::ShouldFocusConstrainedWindow(TabContents* source) {
+ return true;
+}
+
+void TabContentsDelegate::WillShowConstrainedWindow(TabContents* source) {
+}
+
void TabContentsDelegate::ContentsMouseEvent(
TabContents* source, const gfx::Point& location, bool motion) {
}
@@ -51,6 +64,10 @@ bool TabContentsDelegate::IsExternalTabContainer() const { return false; }
void TabContentsDelegate::SetFocusToLocationBar(bool select_all) {}
+bool TabContentsDelegate::ShouldFocusPageAfterCrash() {
+ return true;
+}
+
void TabContentsDelegate::RenderWidgetShowing() {}
ExtensionFunctionDispatcher*
@@ -64,6 +81,9 @@ bool TabContentsDelegate::TakeFocus(bool reverse) {
return false;
}
+void TabContentsDelegate::LostCapture() {
+}
+
void TabContentsDelegate::SetTabContentBlocked(
TabContents* contents, bool blocked) {
}
@@ -79,7 +99,8 @@ bool TabContentsDelegate::CanDownload(int request_id) {
return true;
}
-void TabContentsDelegate::OnStartDownload(DownloadItem* download) {
+void TabContentsDelegate::OnStartDownload(DownloadItem* download,
+ TabContents* tab) {
}
bool TabContentsDelegate::HandleContextMenu(const ContextMenuParams& params) {
@@ -111,6 +132,12 @@ void TabContentsDelegate::HandleKeyboardEvent(
const NativeWebKeyboardEvent& event) {
}
+void TabContentsDelegate::HandleMouseUp() {
+}
+
+void TabContentsDelegate::HandleMouseActivate() {
+}
+
void TabContentsDelegate::ShowRepostFormWarningDialog(
TabContents* tab_contents) {
}
@@ -127,7 +154,9 @@ bool TabContentsDelegate::OnGoToEntryOffset(int offset) {
return true;
}
-bool TabContentsDelegate::ShouldAddNavigationsToHistory() const {
+bool TabContentsDelegate::ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type) {
return true;
}
@@ -135,10 +164,6 @@ void TabContentsDelegate::OnDidGetApplicationInfo(TabContents* tab_contents,
int32 page_id) {
}
-Browser* TabContentsDelegate::GetBrowser() {
- return NULL;
-}
-
gfx::NativeWindow TabContentsDelegate::GetFrameNativeWindow() {
return NULL;
}
@@ -157,5 +182,12 @@ bool TabContentsDelegate::ShouldEnablePreferredSizeNotifications() {
void TabContentsDelegate::UpdatePreferredSize(const gfx::Size& pref_size) {
}
+void TabContentsDelegate::ContentTypeChanged(TabContents* source) {
+}
+
+void TabContentsDelegate::OnSetSuggestResult(int32 page_id,
+ const std::string& result) {
+}
+
TabContentsDelegate::~TabContentsDelegate() {
}
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h
index bb2e6f8..a870cf3 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.h
+++ b/chrome/browser/tab_contents/tab_contents_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_DELEGATE_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_DELEGATE_H_
+#pragma once
#include <string>
@@ -11,26 +12,31 @@
#include "chrome/browser/automation/automation_resource_routing_delegate.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/content_settings_types.h"
-#include "chrome/common/native_web_keyboard_event.h"
+#include "chrome/common/navigation_types.h"
#include "chrome/common/page_transition_types.h"
#include "gfx/native_widget_types.h"
-#include "gfx/rect.h"
-#include "webkit/glue/context_menu.h"
#include "webkit/glue/window_open_disposition.h"
-class Browser;
+namespace gfx {
+class Point;
+class Rect;
+class Size;
+}
+
+namespace history {
+class HistoryAddPageArgs;
+}
+
class DownloadItem;
class ExtensionFunctionDispatcher;
class GURL;
class HtmlDialogUIDelegate;
+struct NativeWebKeyboardEvent;
class Profile;
class RenderViewHost;
class TabContents;
class TemplateURL;
-
-namespace webkit_glue {
-struct WebApplicationInfo;
-}
+struct ContextMenuParams;
// Objects implement this interface to get notified about changes in the
// TabContents and to provide necessary functionality.
@@ -67,6 +73,10 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// Selects the specified contents, bringing its container to the front.
virtual void ActivateContents(TabContents* contents) = 0;
+ // Deactivates the specified contents by deactivating its container and
+ // potentialy moving it to the back of the Z order.
+ virtual void DeactivateContents(TabContents* contents) = 0;
+
// Notifies the delegate that this contents is starting or is done loading
// some resource. The delegate should use this notification to represent
// loading feedback. See TabContents::is_loading()
@@ -86,12 +96,18 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
virtual void DetachContents(TabContents* source);
// Called to determine if the TabContents is contained in a popup window.
- virtual bool IsPopup(TabContents* source) = 0;
+ virtual bool IsPopup(const TabContents* source) const;
// If |source| is constrained, returns the tab containing it. Otherwise
// returns |source|.
virtual TabContents* GetConstrainingContents(TabContents* source);
+ // Returns true if constrained windows should be focused. Default is true.
+ virtual bool ShouldFocusConstrainedWindow(TabContents* source);
+
+ // Invoked prior to the TabContents showing a constrained window.
+ virtual void WillShowConstrainedWindow(TabContents* source);
+
// Notification that some of our content has changed size as
// part of an animation.
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) = 0;
@@ -162,6 +178,10 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// new tab page.
virtual void SetFocusToLocationBar(bool select_all);
+ // Returns whether the page should be focused when transitioning from crashed
+ // to live. Default is true.
+ virtual bool ShouldFocusPageAfterCrash();
+
// Called when a popup select is about to be displayed. The delegate can use
// this to disable inactive rendering for the frame in the window the select
// is opened within if necessary.
@@ -173,11 +193,14 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
RenderViewHost* render_view_host,
const std::string& extension_id);
- // This is called when webkit tells us that it is done tabbing through
+ // This is called when WebKit tells us that it is done tabbing through
// controls on the page. Provides a way for TabContentsDelegates to handle
// this. Returns true if the delegate successfully handled it.
virtual bool TakeFocus(bool reverse);
+ // Invoked when the page loses mouse capture.
+ virtual void LostCapture();
+
// Changes the blocked state of the tab at |index|. TabContents are
// considered blocked while displaying a tab modal dialog. During that time
// renderer host will ignore any UI interaction within TabContent outside of
@@ -194,7 +217,7 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
virtual bool CanDownload(int request_id);
- virtual void OnStartDownload(DownloadItem* download);
+ virtual void OnStartDownload(DownloadItem* download, TabContents* tab);
// Returns true if the context menu operation was handled by the delegate.
virtual bool HandleContextMenu(const ContextMenuParams& params);
@@ -227,6 +250,9 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// the renderer.
virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
+ virtual void HandleMouseUp();
+ virtual void HandleMouseActivate();
+
// Shows the repost form confirmation dialog box.
virtual void ShowRepostFormWarningDialog(TabContents* tab_contents);
@@ -240,16 +266,16 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// Returns true to allow TabContents to continue with the default processing.
virtual bool OnGoToEntryOffset(int offset);
- // Returns whether this tab contents should add navigations to history.
- virtual bool ShouldAddNavigationsToHistory() const;
+ // Returns whether this tab contents should add the specified navigation to
+ // history.
+ virtual bool ShouldAddNavigationToHistory(
+ const history::HistoryAddPageArgs& add_page_args,
+ NavigationType::Type navigation_type);
// Notification when web app info data is available
virtual void OnDidGetApplicationInfo(TabContents* tab_contents,
int32 page_id);
- // Returns the browser in which the tab contents is being displayed.
- virtual Browser* GetBrowser();
-
// Returns the native window framing the view containing the tab contents.
virtual gfx::NativeWindow GetFrameNativeWindow();
@@ -270,8 +296,16 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// Only called if ShouldEnablePreferredSizeNotifications() returns true.
virtual void UpdatePreferredSize(const gfx::Size& pref_size);
+ // Notifies the delegate that something has changed about what content the
+ // TabContents is displaying. Currently this is only fired when displaying
+ // PDF using the internal PDF plugin.
+ virtual void ContentTypeChanged(TabContents* source);
+
+ // Notifies the delegate that the page has a suggest result.
+ virtual void OnSetSuggestResult(int32 page_id, const std::string& result);
+
protected:
- ~TabContentsDelegate();
+ virtual ~TabContentsDelegate();
};
#endif // CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_DELEGATE_H_
diff --git a/chrome/browser/tab_contents/tab_contents_ssl_helper.cc b/chrome/browser/tab_contents/tab_contents_ssl_helper.cc
index 0f00d1e..685b6e1 100644
--- a/chrome/browser/tab_contents/tab_contents_ssl_helper.cc
+++ b/chrome/browser/tab_contents/tab_contents_ssl_helper.cc
@@ -4,9 +4,157 @@
#include "chrome/browser/tab_contents/tab_contents_ssl_helper.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/certificate_viewer.h"
+#include "chrome/browser/ssl/ssl_add_cert_handler.h"
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
#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 "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "net/base/net_errors.h"
+
+namespace {
+
+SkBitmap* GetCertIcon() {
+ // TODO(davidben): use a more appropriate icon.
+ return ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_INFOBAR_SAVE_PASSWORD);
+}
+
+class SSLCertAddedInfoBarDelegate : public ConfirmInfoBarDelegate {
+ public:
+ SSLCertAddedInfoBarDelegate(TabContents* tab_contents,
+ net::X509Certificate* cert)
+ : ConfirmInfoBarDelegate(tab_contents),
+ tab_contents_(tab_contents),
+ cert_(cert) {
+ }
+
+ virtual ~SSLCertAddedInfoBarDelegate() {
+ }
+
+ // Overridden from ConfirmInfoBarDelegate:
+ virtual string16 GetMessageText() const {
+ // TODO(evanm): GetDisplayName should return UTF-16.
+ return l10n_util::GetStringFUTF16(
+ IDS_ADD_CERT_SUCCESS_INFOBAR_LABEL,
+ UTF8ToUTF16(cert_->issuer().GetDisplayName()));
+ }
+
+ virtual SkBitmap* GetIcon() const {
+ return GetCertIcon();
+ }
+
+ virtual int GetButtons() const {
+ return BUTTON_OK;
+ }
+
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
+ switch (button) {
+ case BUTTON_OK:
+ return l10n_util::GetStringUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_BUTTON);
+ default:
+ return string16();
+ }
+ }
+
+ virtual Type GetInfoBarType() {
+ return PAGE_ACTION_TYPE;
+ }
+
+ virtual bool Accept() {
+ ShowCertificateViewer(tab_contents_->GetMessageBoxRootWindow(), cert_);
+ return false; // Hiding the infobar just as the dialog opens looks weird.
+ }
+
+ virtual void InfoBarClosed() {
+ // ConfirmInfoBarDelegate doesn't delete itself.
+ delete this;
+ }
+
+ private:
+ // The TabContents we are attached to
+ TabContents* tab_contents_;
+ // The cert we added.
+ scoped_refptr<net::X509Certificate> cert_;
+};
+
+} // namespace
+
+class TabContentsSSLHelper::SSLAddCertData : public NotificationObserver {
+ public:
+ SSLAddCertData(TabContents* tab, SSLAddCertHandler* handler)
+ : tab_(tab),
+ handler_(handler),
+ infobar_delegate_(NULL) {
+ // Listen for disappearing InfoBars.
+ Source<TabContents> tc_source(tab_);
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
+ tc_source);
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REPLACED,
+ tc_source);
+ }
+ ~SSLAddCertData() {}
+
+ // Displays |delegate| as an infobar in |tab_|, replacing our current one if
+ // still active.
+ void ShowInfoBar(InfoBarDelegate* delegate) {
+ if (infobar_delegate_) {
+ tab_->ReplaceInfoBar(infobar_delegate_, delegate);
+ } else {
+ tab_->AddInfoBar(delegate);
+ }
+ infobar_delegate_ = delegate;
+ }
+
+ void ShowErrorInfoBar(const string16& message) {
+ ShowInfoBar(
+ new SimpleAlertInfoBarDelegate(tab_, message, GetCertIcon(), true));
+ }
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::TAB_CONTENTS_INFOBAR_REMOVED:
+ InfoBarClosed(Details<InfoBarDelegate>(details).ptr());
+ break;
+ case NotificationType::TAB_CONTENTS_INFOBAR_REPLACED:
+ typedef std::pair<InfoBarDelegate*, InfoBarDelegate*>
+ InfoBarDelegatePair;
+ InfoBarClosed(Details<InfoBarDelegatePair>(details).ptr()->first);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ private:
+ void InfoBarClosed(InfoBarDelegate* delegate) {
+ if (infobar_delegate_ == delegate)
+ infobar_delegate_ = NULL;
+ }
+
+ // The TabContents we are attached to.
+ TabContents* tab_;
+ // The handler we call back to.
+ scoped_refptr<SSLAddCertHandler> handler_;
+ // The current InfoBarDelegate we're displaying.
+ InfoBarDelegate* infobar_delegate_;
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLAddCertData);
+};
TabContentsSSLHelper::TabContentsSSLHelper(TabContents* tab_contents)
: tab_contents_(tab_contents) {
@@ -17,8 +165,58 @@ TabContentsSSLHelper::~TabContentsSSLHelper() {
void TabContentsSSLHelper::ShowClientCertificateRequestDialog(
scoped_refptr<SSLClientAuthHandler> handler) {
- // Display the native certificate request dialog for each platform.
browser::ShowSSLClientCertificateSelector(
- tab_contents_->GetMessageBoxRootWindow(),
- handler->cert_request_info(), handler);
+ tab_contents_, handler->cert_request_info(), handler);
+}
+
+void TabContentsSSLHelper::OnVerifyClientCertificateError(
+ scoped_refptr<SSLAddCertHandler> handler, int error_code) {
+ SSLAddCertData* add_cert_data = GetAddCertData(handler);
+ // Display an infobar with the error message.
+ // TODO(davidben): Display a more user-friendly error string.
+ add_cert_data->ShowErrorInfoBar(
+ l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_INVALID_CERT,
+ base::IntToString16(-error_code),
+ ASCIIToUTF16(net::ErrorToString(error_code))));
+}
+
+void TabContentsSSLHelper::AskToAddClientCertificate(
+ scoped_refptr<SSLAddCertHandler> handler) {
+ NOTREACHED(); // Not implemented yet.
+}
+
+void TabContentsSSLHelper::OnAddClientCertificateSuccess(
+ scoped_refptr<SSLAddCertHandler> handler) {
+ SSLAddCertData* add_cert_data = GetAddCertData(handler);
+ // Display an infobar to inform the user.
+ add_cert_data->ShowInfoBar(
+ new SSLCertAddedInfoBarDelegate(tab_contents_, handler->cert()));
+}
+
+void TabContentsSSLHelper::OnAddClientCertificateError(
+ scoped_refptr<SSLAddCertHandler> handler, int error_code) {
+ SSLAddCertData* add_cert_data = GetAddCertData(handler);
+ // Display an infobar with the error message.
+ // TODO(davidben): Display a more user-friendly error string.
+ add_cert_data->ShowErrorInfoBar(
+ l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_FAILED,
+ base::IntToString16(-error_code),
+ ASCIIToUTF16(net::ErrorToString(error_code))));
+}
+
+void TabContentsSSLHelper::OnAddClientCertificateFinished(
+ scoped_refptr<SSLAddCertHandler> handler) {
+ // Clean up.
+ request_id_to_add_cert_data_.erase(handler->network_request_id());
+}
+
+TabContentsSSLHelper::SSLAddCertData* TabContentsSSLHelper::GetAddCertData(
+ SSLAddCertHandler* handler) {
+ // Find/create the slot.
+ linked_ptr<SSLAddCertData>& ptr_ref =
+ request_id_to_add_cert_data_[handler->network_request_id()];
+ // Fill it if necessary.
+ if (!ptr_ref.get())
+ ptr_ref.reset(new SSLAddCertData(tab_contents_, handler));
+ return ptr_ref.get();
}
diff --git a/chrome/browser/tab_contents/tab_contents_ssl_helper.h b/chrome/browser/tab_contents/tab_contents_ssl_helper.h
index bddb379..9233561 100644
--- a/chrome/browser/tab_contents/tab_contents_ssl_helper.h
+++ b/chrome/browser/tab_contents/tab_contents_ssl_helper.h
@@ -4,7 +4,11 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_SSL_HELPER_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_SSL_HELPER_H_
+#pragma once
+#include <map>
+
+#include "base/linked_ptr.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
class SSLClientAuthHandler;
@@ -18,10 +22,25 @@ class TabContentsSSLHelper : public RenderViewHostDelegate::SSL {
// RenderViewHostDelegate::SSL implementation:
virtual void ShowClientCertificateRequestDialog(
scoped_refptr<SSLClientAuthHandler> handler);
+ virtual void OnVerifyClientCertificateError(
+ scoped_refptr<SSLAddCertHandler> handler, int error_code);
+ virtual void AskToAddClientCertificate(
+ scoped_refptr<SSLAddCertHandler> handler);
+ virtual void OnAddClientCertificateSuccess(
+ scoped_refptr<SSLAddCertHandler> handler);
+ virtual void OnAddClientCertificateError(
+ scoped_refptr<SSLAddCertHandler> handler, int error_code);
+ virtual void OnAddClientCertificateFinished(
+ scoped_refptr<SSLAddCertHandler> handler);
private:
TabContents* tab_contents_;
+ class SSLAddCertData;
+ std::map<int, linked_ptr<SSLAddCertData> > request_id_to_add_cert_data_;
+
+ SSLAddCertData* GetAddCertData(SSLAddCertHandler *handler);
+
DISALLOW_COPY_AND_ASSIGN(TabContentsSSLHelper);
};
diff --git a/chrome/browser/tab_contents/tab_contents_view.cc b/chrome/browser/tab_contents/tab_contents_view.cc
index 00eaed7..c03bc35 100644
--- a/chrome/browser/tab_contents/tab_contents_view.cc
+++ b/chrome/browser/tab_contents/tab_contents_view.cc
@@ -34,7 +34,8 @@ void TabContentsView::CreateNewWindow(
route_id,
tab_contents_->profile(),
tab_contents_->GetSiteInstance(),
- DOMUIFactory::GetDOMUIType(tab_contents_->GetURL()),
+ DOMUIFactory::GetDOMUIType(tab_contents_->profile(),
+ tab_contents_->GetURL()),
tab_contents_,
window_container_type,
frame_name);
@@ -48,6 +49,11 @@ void TabContentsView::CreateNewWidget(int route_id,
CreateNewWidgetInternal(route_id, popup_type);
}
+void TabContentsView::CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type) {
+ CreateNewFullscreenWidgetInternal(route_id, popup_type);
+}
+
void TabContentsView::ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
@@ -66,6 +72,25 @@ void TabContentsView::ShowCreatedWidget(int route_id,
ShowCreatedWidgetInternal(widget_host_view, initial_pos);
}
+void TabContentsView::Activate() {
+ tab_contents_->Activate();
+}
+
+void TabContentsView::Deactivate() {
+ tab_contents_->Deactivate();
+}
+
+void TabContentsView::ShowCreatedFullscreenWidget(int route_id) {
+ RenderWidgetHostView* widget_host_view =
+ delegate_view_helper_.GetCreatedWidget(route_id);
+ ShowCreatedFullscreenWidgetInternal(widget_host_view);
+}
+
+void TabContentsView::LostCapture() {
+ if (tab_contents_->delegate())
+ tab_contents_->delegate()->LostCapture();
+}
+
bool TabContentsView::PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
return tab_contents_->delegate() &&
@@ -83,12 +108,28 @@ void TabContentsView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
tab_contents_->delegate()->HandleKeyboardEvent(event);
}
+void TabContentsView::HandleMouseUp() {
+ if (tab_contents_->delegate())
+ tab_contents_->delegate()->HandleMouseUp();
+}
+
+void TabContentsView::HandleMouseActivate() {
+ if (tab_contents_->delegate())
+ tab_contents_->delegate()->HandleMouseActivate();
+}
+
RenderWidgetHostView* TabContentsView::CreateNewWidgetInternal(
int route_id, WebKit::WebPopupType popup_type) {
return delegate_view_helper_.CreateNewWidget(route_id, popup_type,
tab_contents()->render_view_host()->process());
}
+RenderWidgetHostView* TabContentsView::CreateNewFullscreenWidgetInternal(
+ int route_id, WebKit::WebPopupType popup_type) {
+ return delegate_view_helper_.CreateNewFullscreenWidget(
+ route_id, popup_type, tab_contents()->render_view_host()->process());
+}
+
void TabContentsView::ShowCreatedWidgetInternal(
RenderWidgetHostView* widget_host_view, const gfx::Rect& initial_pos) {
if (tab_contents_->delegate())
@@ -98,3 +139,12 @@ void TabContentsView::ShowCreatedWidgetInternal(
initial_pos);
widget_host_view->GetRenderWidgetHost()->Init();
}
+
+void TabContentsView::ShowCreatedFullscreenWidgetInternal(
+ RenderWidgetHostView* widget_host_view) {
+ if (tab_contents_->delegate())
+ tab_contents_->delegate()->RenderWidgetShowing();
+
+ widget_host_view->InitAsFullscreen(tab_contents_->GetRenderWidgetHostView());
+ widget_host_view->GetRenderWidgetHost()->Init();
+}
diff --git a/chrome/browser/tab_contents/tab_contents_view.h b/chrome/browser/tab_contents/tab_contents_view.h
index 36ee76a..b2040a6 100644
--- a/chrome/browser/tab_contents/tab_contents_view.h
+++ b/chrome/browser/tab_contents/tab_contents_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_VIEW_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_VIEW_H_
+#pragma once
#include <map>
#include <string>
@@ -15,7 +16,6 @@
#include "gfx/rect.h"
#include "gfx/size.h"
-class Browser;
class RenderViewHost;
class RenderWidgetHost;
class RenderWidgetHostView;
@@ -115,6 +115,9 @@ class TabContentsView : public RenderViewHostDelegate::View {
// invoked, SetInitialFocus is invoked.
virtual void RestoreFocus() = 0;
+ // RenderViewHostDelegate::View method. Forwards to the TabContentsDelegate.
+ virtual void LostCapture();
+
// Keyboard events forwarding from the RenderViewHost.
// The default implementation just forward the events to the
// TabContentsDelegate object.
@@ -127,8 +130,11 @@ class TabContentsView : public RenderViewHostDelegate::View {
virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
// Simple mouse event forwarding from the RenderViewHost.
- virtual void HandleMouseEvent() {}
+ virtual void HandleMouseMove() {}
+ virtual void HandleMouseDown() {}
virtual void HandleMouseLeave() {}
+ virtual void HandleMouseUp();
+ virtual void HandleMouseActivate();
// Notification that the preferred size of the contents has changed.
virtual void UpdatePreferredSize(const gfx::Size& pref_size);
@@ -168,6 +174,11 @@ class TabContentsView : public RenderViewHostDelegate::View {
WebKit::WebPopupType popup_type);
virtual void ShowCreatedWidgetInternal(RenderWidgetHostView* widget_host_view,
const gfx::Rect& initial_pos);
+ virtual void ShowCreatedFullscreenWidgetInternal(
+ RenderWidgetHostView* widget_host_view);
+ virtual RenderWidgetHostView* CreateNewFullscreenWidgetInternal(
+ int route_id,
+ WebKit::WebPopupType popup_type);
// Common implementations of some RenderViewHostDelegate::View methods.
RenderViewHostDelegateViewHelper delegate_view_helper_;
@@ -181,11 +192,16 @@ class TabContentsView : public RenderViewHostDelegate::View {
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 Activate();
+ virtual void Deactivate();
+ virtual void ShowCreatedFullscreenWidget(int route_id);
// The TabContents whose contents we display.
TabContents* tab_contents_;
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
index 68243cd..d195ca8 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
@@ -8,8 +8,6 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#include "app/gtk_dnd_util.h"
-#include "base/pickle.h"
#include "base/string_util.h"
#include "build/build_config.h"
#include "chrome/browser/download/download_shelf.h"
@@ -42,25 +40,6 @@ using WebKit::WebDragOperationsMask;
namespace {
-// Called when the content view gtk widget is tabbed to, or after the call to
-// gtk_widget_child_focus() in TakeFocus(). We return true
-// and grab focus if we don't have it. The call to
-// FocusThroughTabTraversal(bool) forwards the "move focus forward" effect to
-// webkit.
-gboolean OnFocus(GtkWidget* widget, GtkDirectionType focus,
- TabContents* tab_contents) {
- // If we already have focus, let the next widget have a shot at it. We will
- // reach this situation after the call to gtk_widget_child_focus() in
- // TakeFocus().
- if (gtk_widget_is_focus(widget))
- return FALSE;
-
- gtk_widget_grab_focus(widget);
- bool reverse = focus == GTK_DIR_TAB_BACKWARD;
- tab_contents->FocusThroughTabTraversal(reverse);
- return TRUE;
-}
-
// Called when the mouse leaves the widget. We notify our delegate.
gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event,
TabContents* tab_contents) {
@@ -166,8 +145,7 @@ RenderWidgetHostView* TabContentsViewGtk::CreateViewForWidget(
new RenderWidgetHostViewGtk(render_widget_host);
view->InitAsChild();
gfx::NativeView content_view = view->native_view();
- g_signal_connect(content_view, "focus",
- G_CALLBACK(OnFocus), tab_contents());
+ g_signal_connect(content_view, "focus", G_CALLBACK(OnFocusThunk), this);
g_signal_connect(content_view, "leave-notify-event",
G_CALLBACK(OnLeaveNotify), tab_contents());
g_signal_connect(content_view, "motion-notify-event",
@@ -244,7 +222,7 @@ void TabContentsViewGtk::SizeContents(const gfx::Size& size) {
void TabContentsViewGtk::Focus() {
if (tab_contents()->showing_interstitial_page()) {
tab_contents()->interstitial_page()->Focus();
- } else {
+ } else if (!constrained_window_) {
GtkWidget* widget = GetContentNativeView();
if (widget)
gtk_widget_grab_focus(widget);
@@ -269,6 +247,10 @@ void TabContentsViewGtk::RestoreFocus() {
SetInitialFocus();
}
+void TabContentsViewGtk::SetFocusedWidget(GtkWidget* widget) {
+ focus_store_.SetWidget(widget);
+}
+
void TabContentsViewGtk::UpdateDragCursor(WebDragOperation operation) {
drag_dest_->UpdateDragStatus(operation);
}
@@ -333,6 +315,38 @@ void TabContentsViewGtk::InsertIntoContentArea(GtkWidget* widget) {
gtk_container_add(GTK_CONTAINER(expanded_), widget);
}
+// Called when the content view gtk widget is tabbed to, or after the call to
+// gtk_widget_child_focus() in TakeFocus(). We return true
+// and grab focus if we don't have it. The call to
+// FocusThroughTabTraversal(bool) forwards the "move focus forward" effect to
+// webkit.
+gboolean TabContentsViewGtk::OnFocus(GtkWidget* widget,
+ GtkDirectionType focus) {
+ // If we are showing a constrained window, don't allow the native view to take
+ // focus.
+ if (constrained_window_) {
+ // If we return false, it will revert to the default handler, which will
+ // take focus. We don't want that. But if we return true, the event will
+ // stop being propagated, leaving focus wherever it is currently. That is
+ // also bad. So we return false to let the default handler run, but take
+ // focus first so as to trick it into thinking the view was already focused
+ // and allowing the event to propagate.
+ gtk_widget_grab_focus(widget);
+ return FALSE;
+ }
+
+ // If we already have focus, let the next widget have a shot at it. We will
+ // reach this situation after the call to gtk_widget_child_focus() in
+ // TakeFocus().
+ if (gtk_widget_is_focus(widget))
+ return FALSE;
+
+ gtk_widget_grab_focus(widget);
+ bool reverse = focus == GTK_DIR_TAB_BACKWARD;
+ tab_contents()->FocusThroughTabTraversal(reverse);
+ return TRUE;
+}
+
gboolean TabContentsViewGtk::OnMouseDown(GtkWidget* widget,
GdkEventButton* event) {
last_mouse_down_ = *event;
@@ -369,28 +383,27 @@ void TabContentsViewGtk::OnSizeAllocate(GtkWidget* widget,
void TabContentsViewGtk::OnSetFloatingPosition(
GtkWidget* floating_container, GtkAllocation* allocation) {
+ if (!constrained_window_)
+ return;
+
// Place each ConstrainedWindow in the center of the view.
- int half_view_width = std::max((allocation->x + allocation->width) / 2, 0);
- int half_view_height = std::max((allocation->y + allocation->height) / 2, 0);
- if (constrained_window_) {
- GtkWidget* widget = constrained_window_->widget();
- DCHECK(widget->parent == floating_.get());
+ GtkWidget* widget = constrained_window_->widget();
+ DCHECK(widget->parent == floating_.get());
- GtkRequisition requisition;
- gtk_widget_size_request(widget, &requisition);
+ GtkRequisition requisition;
+ gtk_widget_size_request(widget, &requisition);
- GValue value = { 0, };
- g_value_init(&value, G_TYPE_INT);
+ GValue value = { 0, };
+ g_value_init(&value, G_TYPE_INT);
- int child_x = std::max(half_view_width - (requisition.width / 2), 0);
- g_value_set_int(&value, child_x);
- gtk_container_child_set_property(GTK_CONTAINER(floating_container),
- widget, "x", &value);
+ int child_x = std::max((allocation->width - requisition.width) / 2, 0);
+ g_value_set_int(&value, child_x);
+ gtk_container_child_set_property(GTK_CONTAINER(floating_container),
+ widget, "x", &value);
- int child_y = std::max(half_view_height - (requisition.height / 2), 0);
- g_value_set_int(&value, child_y);
- gtk_container_child_set_property(GTK_CONTAINER(floating_container),
- widget, "y", &value);
- g_value_unset(&value);
- }
+ int child_y = std::max((allocation->height - requisition.height) / 2, 0);
+ g_value_set_int(&value, child_y);
+ gtk_container_child_set_property(GTK_CONTAINER(floating_container),
+ widget, "y", &value);
+ g_value_unset(&value);
}
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.h b/chrome/browser/tab_contents/tab_contents_view_gtk.h
index 4329165..990ee81 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.h
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.h
@@ -4,24 +4,23 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_VIEW_GTK_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_VIEW_GTK_H_
+#pragma once
#include <gtk/gtk.h>
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/focus_store_gtk.h"
+#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/owned_widget_gtk.h"
class ConstrainedWindowGtk;
-class GtkThemeProperties;
class RenderViewContextMenuGtk;
class SadTabGtk;
class TabContentsDragSource;
class WebDragDestGtk;
-typedef struct _GtkFloatingContainer GtkFloatingContainer;
class TabContentsViewGtk : public TabContentsView,
public NotificationObserver {
@@ -37,6 +36,10 @@ class TabContentsViewGtk : public TabContentsView,
void AttachConstrainedWindow(ConstrainedWindowGtk* constrained_window);
void RemoveConstrainedWindow(ConstrainedWindowGtk* constrained_window);
+ // Override the stored focus widget. This call only makes sense when the
+ // tab contents is not focused.
+ void SetFocusedWidget(GtkWidget* widget);
+
// TabContentsView implementation --------------------------------------------
virtual void CreateView(const gfx::Size& initial_size);
@@ -80,6 +83,9 @@ class TabContentsViewGtk : public TabContentsView,
void CancelDragIfAny();
+ // Handle focus traversal on the render widget native view.
+ CHROMEGTK_CALLBACK_1(TabContentsViewGtk, gboolean, OnFocus, GtkDirectionType);
+
// We keep track of the timestamp of the latest mousedown event.
CHROMEGTK_CALLBACK_1(TabContentsViewGtk, gboolean, OnMouseDown,
GdkEventButton*);
diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.h b/chrome/browser/tab_contents/tab_contents_view_mac.h
index 91ef23d..63d29f3 100644
--- a/chrome/browser/tab_contents/tab_contents_view_mac.h
+++ b/chrome/browser/tab_contents/tab_contents_view_mac.h
@@ -1,23 +1,21 @@
-// 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.
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_VIEW_MAC_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_CONTENTS_VIEW_MAC_H_
+#pragma once
#import <Cocoa/Cocoa.h>
#include <string>
-#include "base/scoped_ptr.h"
#include "base/scoped_nsobject.h"
#include "chrome/browser/cocoa/base_view.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/size.h"
-class FilePath;
-class FindBarMac;
@class FocusTracker;
@class SadTabController;
class SkBitmap;
diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm
index 8587dec..c4af811 100644
--- a/chrome/browser/tab_contents/tab_contents_view_mac.mm
+++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm
@@ -9,9 +9,7 @@
#include <string>
#import "base/chrome_application_mac.h"
-#include "chrome/browser/browser.h" // TODO(beng): this dependency is awful.
#import "chrome/browser/cocoa/focus_tracker.h"
-#import "chrome/browser/cocoa/chrome_browser_window.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"
@@ -24,6 +22,7 @@
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
#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"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
@@ -128,7 +127,7 @@ gfx::NativeWindow TabContentsViewMac::GetTopLevelNativeWindow() const {
}
void TabContentsViewMac::GetContainerBounds(gfx::Rect* out) const {
- *out = [cocoa_view_.get() NSRectToRect:[cocoa_view_.get() bounds]];
+ *out = [cocoa_view_.get() flipNSRectToRect:[cocoa_view_.get() bounds]];
}
void TabContentsViewMac::StartDragging(
@@ -183,7 +182,7 @@ void TabContentsViewMac::SizeContents(const gfx::Size& size) {
// See tab_contents_view.h.
gfx::Rect rect(gfx::Point(), size);
TabContentsViewCocoa* view = cocoa_view_.get();
- [view setFrame:[view RectToNSRect:rect]];
+ [view setFrame:[view flipRectToNSRect:rect]];
}
void TabContentsViewMac::Focus() {
diff --git a/chrome/browser/tab_contents/tab_specific_content_settings.cc b/chrome/browser/tab_contents/tab_specific_content_settings.cc
index 57b9a2b..5e289c5 100644
--- a/chrome/browser/tab_contents/tab_specific_content_settings.cc
+++ b/chrome/browser/tab_contents/tab_specific_content_settings.cc
@@ -7,10 +7,20 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browsing_data_appcache_helper.h"
#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/cookies_tree_model.h"
#include "net/base/cookie_monster.h"
+bool TabSpecificContentSettings::LocalSharedObjectsContainer::empty() const {
+ return cookies_->GetAllCookies().empty() &&
+ appcaches_->empty() &&
+ databases_->empty() &&
+ indexed_dbs_->empty() &&
+ local_storages_->empty() &&
+ session_storages_->empty();
+}
+
bool TabSpecificContentSettings::IsContentBlocked(
ContentSettingsType content_type) const {
DCHECK(content_type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
@@ -30,12 +40,57 @@ bool TabSpecificContentSettings::IsContentBlocked(
return false;
}
-void TabSpecificContentSettings::OnContentBlocked(ContentSettingsType type) {
+bool TabSpecificContentSettings::IsContentAccessed(
+ ContentSettingsType content_type) const {
+ // This method currently only returns meaningful values for cookies.
+ if (content_type != CONTENT_SETTINGS_TYPE_COOKIES)
+ return false;
+
+ return content_accessed_[content_type];
+}
+
+const std::set<std::string>&
+ TabSpecificContentSettings::BlockedResourcesForType(
+ ContentSettingsType content_type) const {
+ if (blocked_resources_[content_type].get()) {
+ return *blocked_resources_[content_type];
+ } else {
+ static std::set<std::string> empty_set;
+ return empty_set;
+ }
+}
+
+void TabSpecificContentSettings::AddBlockedResource(
+ ContentSettingsType content_type,
+ const std::string& resource_identifier) {
+ if (!blocked_resources_[content_type].get())
+ blocked_resources_[content_type].reset(new std::set<std::string>());
+ blocked_resources_[content_type]->insert(resource_identifier);
+}
+
+void TabSpecificContentSettings::OnContentBlocked(
+ ContentSettingsType type,
+ const std::string& resource_identifier) {
DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
<< "Geolocation settings handled by OnGeolocationPermissionSet";
- content_blocked_[type] = true;
- if (delegate_)
- delegate_->OnContentSettingsChange();
+ content_accessed_[type] = true;
+ if (!content_blocked_[type]) {
+ content_blocked_[type] = true;
+ if (!resource_identifier.empty())
+ AddBlockedResource(type, resource_identifier);
+ if (delegate_)
+ delegate_->OnContentSettingsAccessed(true);
+ }
+}
+
+void TabSpecificContentSettings::OnContentAccessed(ContentSettingsType type) {
+ DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
+ << "Geolocation settings handled by OnGeolocationPermissionSet";
+ if (!content_accessed_[type]) {
+ content_accessed_[type] = true;
+ if (delegate_)
+ delegate_->OnContentSettingsAccessed(false);
+ }
}
void TabSpecificContentSettings::OnCookieAccessed(
@@ -45,23 +100,47 @@ void TabSpecificContentSettings::OnCookieAccessed(
if (blocked_by_policy) {
blocked_local_shared_objects_.cookies()->SetCookieWithOptions(
url, cookie_line, options);
- OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
+ OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES, std::string());
} else {
allowed_local_shared_objects_.cookies()->SetCookieWithOptions(
url, cookie_line, options);
+ OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES);
}
}
-void TabSpecificContentSettings::OnLocalStorageAccessed(
- const GURL& url, bool blocked_by_policy) {
+void TabSpecificContentSettings::OnIndexedDBAccessed(
+ const GURL& url,
+ const string16& name,
+ const string16& description,
+ bool blocked_by_policy) {
if (blocked_by_policy) {
- blocked_local_shared_objects_.local_storages()->AddLocalStorage(url);
- OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
- } else {
- allowed_local_shared_objects_.local_storages()->AddLocalStorage(url);
+ blocked_local_shared_objects_.indexed_dbs()->AddIndexedDB(
+ url, name, description);
+ OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES, std::string());
+ }else {
+ allowed_local_shared_objects_.indexed_dbs()->AddIndexedDB(
+ url, name, description);
+ OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES);
}
}
+void TabSpecificContentSettings::OnLocalStorageAccessed(
+ const GURL& url,
+ DOMStorageType storage_type,
+ bool blocked_by_policy) {
+ LocalSharedObjectsContainer& container = blocked_by_policy ?
+ blocked_local_shared_objects_ : allowed_local_shared_objects_;
+ CannedBrowsingDataLocalStorageHelper* helper =
+ storage_type == DOM_STORAGE_LOCAL ?
+ container.local_storages() : container.session_storages();
+ helper->AddLocalStorage(url);
+
+ if (blocked_by_policy)
+ OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES, std::string());
+ else
+ OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES);
+}
+
void TabSpecificContentSettings::OnWebDatabaseAccessed(
const GURL& url,
const string16& name,
@@ -71,10 +150,11 @@ void TabSpecificContentSettings::OnWebDatabaseAccessed(
if (blocked_by_policy) {
blocked_local_shared_objects_.databases()->AddDatabase(
url, UTF16ToUTF8(name), UTF16ToUTF8(display_name));
- OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
+ OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES, std::string());
} else {
allowed_local_shared_objects_.databases()->AddDatabase(
url, UTF16ToUTF8(name), UTF16ToUTF8(display_name));
+ OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES);
}
}
@@ -82,9 +162,10 @@ void TabSpecificContentSettings::OnAppCacheAccessed(
const GURL& manifest_url, bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_local_shared_objects_.appcaches()->AddAppCache(manifest_url);
- OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
+ OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES, std::string());
} else {
allowed_local_shared_objects_.appcaches()->AddAppCache(manifest_url);
+ OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES);
}
}
@@ -94,7 +175,7 @@ void TabSpecificContentSettings::OnGeolocationPermissionSet(
geolocation_settings_state_.OnGeolocationPermissionSet(requesting_origin,
allowed);
if (delegate_)
- delegate_->OnContentSettingsChange();
+ delegate_->OnContentSettingsAccessed(!allowed);
}
TabSpecificContentSettings::TabSpecificContentSettings(
@@ -102,24 +183,39 @@ TabSpecificContentSettings::TabSpecificContentSettings(
: allowed_local_shared_objects_(profile),
blocked_local_shared_objects_(profile),
geolocation_settings_state_(profile),
+ load_plugins_link_enabled_(true),
delegate_(NULL) {
- ClearBlockedContentSettings();
+ ClearBlockedContentSettingsExceptForCookies();
+ ClearCookieSpecificContentSettings();
delegate_ = delegate;
}
-void TabSpecificContentSettings::ClearBlockedContentSettings() {
- for (size_t i = 0; i < arraysize(content_blocked_); ++i)
+void TabSpecificContentSettings::ClearBlockedContentSettingsExceptForCookies() {
+ for (size_t i = 0; i < arraysize(content_blocked_); ++i) {
+ if (i == CONTENT_SETTINGS_TYPE_COOKIES)
+ continue;
+ blocked_resources_[i].reset();
content_blocked_[i] = false;
+ content_accessed_[i] = false;
+ }
+ load_plugins_link_enabled_ = true;
+ if (delegate_)
+ delegate_->OnContentSettingsAccessed(false);
+}
+
+void TabSpecificContentSettings::ClearCookieSpecificContentSettings() {
blocked_local_shared_objects_.Reset();
allowed_local_shared_objects_.Reset();
+ content_blocked_[CONTENT_SETTINGS_TYPE_COOKIES] = false;
+ content_accessed_[CONTENT_SETTINGS_TYPE_COOKIES] = false;
if (delegate_)
- delegate_->OnContentSettingsChange();
+ delegate_->OnContentSettingsAccessed(false);
}
void TabSpecificContentSettings::SetPopupsBlocked(bool blocked) {
content_blocked_[CONTENT_SETTINGS_TYPE_POPUPS] = blocked;
if (delegate_)
- delegate_->OnContentSettingsChange();
+ delegate_->OnContentSettingsAccessed(blocked);
}
void TabSpecificContentSettings::GeolocationDidNavigate(
@@ -127,6 +223,10 @@ void TabSpecificContentSettings::GeolocationDidNavigate(
geolocation_settings_state_.DidNavigate(details);
}
+void TabSpecificContentSettings::ClearGeolocationContentSettings() {
+ geolocation_settings_state_.ClearStateMap();
+}
+
CookiesTreeModel* TabSpecificContentSettings::GetAllowedCookiesTreeModel() {
return allowed_local_shared_objects_.GetCookiesTreeModel();
}
@@ -140,7 +240,9 @@ TabSpecificContentSettings::LocalSharedObjectsContainer::
: cookies_(new net::CookieMonster(NULL, NULL)),
appcaches_(new CannedBrowsingDataAppCacheHelper(profile)),
databases_(new CannedBrowsingDataDatabaseHelper(profile)),
- local_storages_(new CannedBrowsingDataLocalStorageHelper(profile)) {
+ indexed_dbs_(new CannedBrowsingDataIndexedDBHelper(profile)),
+ local_storages_(new CannedBrowsingDataLocalStorageHelper(profile)),
+ session_storages_(new CannedBrowsingDataLocalStorageHelper(profile)) {
}
TabSpecificContentSettings::LocalSharedObjectsContainer::
@@ -151,11 +253,17 @@ void TabSpecificContentSettings::LocalSharedObjectsContainer::Reset() {
cookies_->DeleteAll(false);
appcaches_->Reset();
databases_->Reset();
+ indexed_dbs_->Reset();
local_storages_->Reset();
+ session_storages_->Reset();
}
CookiesTreeModel*
TabSpecificContentSettings::LocalSharedObjectsContainer::GetCookiesTreeModel() {
- return new CookiesTreeModel(
- cookies_, databases_, local_storages_, appcaches_);
+ return new CookiesTreeModel(cookies_,
+ databases_,
+ local_storages_,
+ session_storages_,
+ appcaches_,
+ indexed_dbs_);
}
diff --git a/chrome/browser/tab_contents/tab_specific_content_settings.h b/chrome/browser/tab_contents/tab_specific_content_settings.h
index 12b557f..7f0aac7 100644
--- a/chrome/browser/tab_contents/tab_specific_content_settings.h
+++ b/chrome/browser/tab_contents/tab_specific_content_settings.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_SPECIFIC_CONTENT_SETTINGS_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_SPECIFIC_CONTENT_SETTINGS_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/geolocation/geolocation_settings_state.h"
@@ -14,6 +15,7 @@
class CannedBrowsingDataAppCacheHelper;
class CannedBrowsingDataDatabaseHelper;
+class CannedBrowsingDataIndexedDBHelper;
class CannedBrowsingDataLocalStorageHelper;
class CookiesTreeModel;
class Profile;
@@ -27,9 +29,12 @@ class TabSpecificContentSettings
public:
class Delegate {
public:
- // Invoked when content settings managed by the TabSpecificContentSettings
- // object change.
- virtual void OnContentSettingsChange() = 0;
+ // Invoked when content settings for resources in the tab contents
+ // associated with this TabSpecificContentSettings object were accessed.
+ // |content_was_blocked| is true, if a content settings type was blocked
+ // (as opposed to just accessed). Currently, this parameter is checked in
+ // unit tests only.
+ virtual void OnContentSettingsAccessed(bool content_was_blocked) = 0;
virtual ~Delegate() {}
};
@@ -38,8 +43,15 @@ class TabSpecificContentSettings
virtual ~TabSpecificContentSettings() {}
- // Resets the |content_blocked_| array and stored cookies.
- void ClearBlockedContentSettings();
+ // Resets the |content_blocked_| and |content_accessed_| arrays, except for
+ // CONTENT_SETTINGS_TYPE_COOKIES related information.
+ void ClearBlockedContentSettingsExceptForCookies();
+
+ // Resets all cookies related information.
+ void ClearCookieSpecificContentSettings();
+
+ // Clears the Geolocation settings.
+ void ClearGeolocationContentSettings();
// Changes the |content_blocked_| entry for popups.
void SetPopupsBlocked(bool blocked);
@@ -52,6 +64,13 @@ class TabSpecificContentSettings
// page.
bool IsContentBlocked(ContentSettingsType content_type) const;
+ // Returns whether a particular kind of content has been accessed. Currently
+ // only tracks cookies.
+ bool IsContentAccessed(ContentSettingsType content_type) const;
+
+ const std::set<std::string>& BlockedResourcesForType(
+ ContentSettingsType content_type) const;
+
// Returns the GeolocationSettingsState that controls the
// geolocation API usage on this page.
const GeolocationSettingsState& geolocation_settings_state() const {
@@ -64,12 +83,24 @@ class TabSpecificContentSettings
// Returns a CookiesTreeModel object for the recoreded blocked cookies.
CookiesTreeModel* GetBlockedCookiesTreeModel();
+ bool load_plugins_link_enabled() { return load_plugins_link_enabled_; }
+ void set_load_plugins_link_enabled(bool enabled) {
+ load_plugins_link_enabled_ = enabled;
+ }
+
// RenderViewHostDelegate::ContentSettings implementation.
- virtual void OnContentBlocked(ContentSettingsType type);
+ virtual void OnContentBlocked(ContentSettingsType type,
+ const std::string& resource_identifier);
virtual void OnCookieAccessed(const GURL& url,
const std::string& cookie_line,
bool blocked_by_policy);
- virtual void OnLocalStorageAccessed(const GURL& url, bool blocked_by_policy);
+ virtual void OnIndexedDBAccessed(const GURL& url,
+ const string16& name,
+ const string16& description,
+ bool blocked_by_policy);
+ virtual void OnLocalStorageAccessed(const GURL& url,
+ DOMStorageType storage_type,
+ bool blocked_by_policy);
virtual void OnWebDatabaseAccessed(const GURL& url,
const string16& name,
const string16& display_name,
@@ -96,24 +127,47 @@ class TabSpecificContentSettings
CannedBrowsingDataDatabaseHelper* databases() const {
return databases_;
}
+ CannedBrowsingDataIndexedDBHelper* indexed_dbs() const {
+ return indexed_dbs_;
+ }
CannedBrowsingDataLocalStorageHelper* local_storages() const {
return local_storages_;
}
+ CannedBrowsingDataLocalStorageHelper* session_storages() const {
+ return session_storages_;
+ }
CookiesTreeModel* GetCookiesTreeModel();
+ bool empty() const;
+
private:
DISALLOW_COPY_AND_ASSIGN(LocalSharedObjectsContainer);
scoped_refptr<net::CookieMonster> cookies_;
scoped_refptr<CannedBrowsingDataAppCacheHelper> appcaches_;
scoped_refptr<CannedBrowsingDataDatabaseHelper> databases_;
+ scoped_refptr<CannedBrowsingDataIndexedDBHelper> indexed_dbs_;
scoped_refptr<CannedBrowsingDataLocalStorageHelper> local_storages_;
+ scoped_refptr<CannedBrowsingDataLocalStorageHelper> session_storages_;
};
+ void AddBlockedResource(ContentSettingsType content_type,
+ const std::string& resource_identifier);
+
+ void OnContentAccessed(ContentSettingsType type);
+
// Stores which content setting types actually have blocked content.
bool content_blocked_[CONTENT_SETTINGS_NUM_TYPES];
+ // Stores which content setting types actually were accessed.
+ bool content_accessed_[CONTENT_SETTINGS_NUM_TYPES];
+
+ // Stores the blocked resources for each content type.
+ // Currently only used for plugins.
+ scoped_ptr<std::set<std::string> >
+ blocked_resources_[CONTENT_SETTINGS_NUM_TYPES];
+
// Stores the blocked/allowed cookies.
LocalSharedObjectsContainer allowed_local_shared_objects_;
LocalSharedObjectsContainer blocked_local_shared_objects_;
@@ -121,6 +175,9 @@ class TabSpecificContentSettings
// Manages information about Geolocation API usage in this page.
GeolocationSettingsState geolocation_settings_state_;
+ // Stores whether the user can load blocked plugins on this page.
+ bool load_plugins_link_enabled_;
+
Delegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(TabSpecificContentSettings);
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 b89d772..64c84e4 100644
--- a/chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc
+++ b/chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc
@@ -11,18 +11,25 @@ namespace {
class TestContentSettingsDelegate
: public TabSpecificContentSettings::Delegate {
public:
- TestContentSettingsDelegate() : settings_changed_(false) {}
+ TestContentSettingsDelegate()
+ : settings_changed_(false), content_blocked_(false) {}
virtual ~TestContentSettingsDelegate() {}
- void Reset() { settings_changed_ = false; }
+ void Reset() { settings_changed_ = content_blocked_ = false; }
bool SettingsChanged() { return settings_changed_; }
+ bool ContentBlocked() { return content_blocked_; }
+
// TabSpecificContentSettings::Delegate implementation.
- virtual void OnContentSettingsChange() { settings_changed_ = true; }
+ virtual void OnContentSettingsAccessed(bool content_was_blocked) {
+ settings_changed_ = true;
+ content_blocked_ = content_was_blocked;
+ }
private:
bool settings_changed_;
+ bool content_blocked_;
DISALLOW_COPY_AND_ASSIGN(TestContentSettingsDelegate);
};
@@ -45,13 +52,17 @@ TEST(TabSpecificContentSettingsTest, BlockedContent) {
// Set a cookie, block access to images, block a popup.
content_settings.OnCookieAccessed(GURL("http://google.com"), "A=B", false);
- EXPECT_FALSE(test_delegate.SettingsChanged());
+ EXPECT_TRUE(test_delegate.SettingsChanged());
+ EXPECT_FALSE(test_delegate.ContentBlocked());
test_delegate.Reset();
- content_settings.OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES);
+ content_settings.OnContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES,
+ std::string());
EXPECT_TRUE(test_delegate.SettingsChanged());
+ EXPECT_TRUE(test_delegate.ContentBlocked());
test_delegate.Reset();
content_settings.SetPopupsBlocked(true);
EXPECT_TRUE(test_delegate.SettingsChanged());
+ EXPECT_TRUE(test_delegate.ContentBlocked());
test_delegate.Reset();
// Check that only the respective content types are affected.
@@ -63,10 +74,29 @@ TEST(TabSpecificContentSettingsTest, BlockedContent) {
EXPECT_FALSE(
content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
EXPECT_TRUE(content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS));
+ content_settings.OnCookieAccessed(GURL("http://google.com"), "A=B", false);
+
+ // Block a cookie.
+ content_settings.OnCookieAccessed(GURL("http://google.com"), "C=D", true);
+ EXPECT_TRUE(
+ content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
// Reset blocked content settings.
- content_settings.ClearBlockedContentSettings();
+ content_settings.ClearBlockedContentSettingsExceptForCookies();
+ EXPECT_TRUE(test_delegate.SettingsChanged());
+ EXPECT_FALSE(test_delegate.ContentBlocked());
+ EXPECT_FALSE(content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES));
+ EXPECT_FALSE(
+ content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_JAVASCRIPT));
+ EXPECT_FALSE(
+ content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_PLUGINS));
+ EXPECT_TRUE(
+ content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_FALSE(content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS));
+
+ content_settings.ClearCookieSpecificContentSettings();
EXPECT_TRUE(test_delegate.SettingsChanged());
+ EXPECT_FALSE(test_delegate.ContentBlocked());
EXPECT_FALSE(content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_IMAGES));
EXPECT_FALSE(
content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_JAVASCRIPT));
@@ -76,3 +106,26 @@ TEST(TabSpecificContentSettingsTest, BlockedContent) {
content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
EXPECT_FALSE(content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS));
}
+
+TEST(TabSpecificContentSettingsTest, AllowedContent) {
+ TestContentSettingsDelegate test_delegate;
+ TestingProfile profile;
+ TabSpecificContentSettings content_settings(&test_delegate, &profile);
+
+ ASSERT_FALSE(
+ content_settings.IsContentAccessed(CONTENT_SETTINGS_TYPE_IMAGES));
+ ASSERT_FALSE(
+ content_settings.IsContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_FALSE(
+ content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
+ content_settings.OnCookieAccessed(GURL("http://google.com"), "A=B", false);
+ ASSERT_TRUE(
+ content_settings.IsContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_FALSE(
+ content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
+ content_settings.OnCookieAccessed(GURL("http://google.com"), "C=D", true);
+ ASSERT_TRUE(
+ content_settings.IsContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_TRUE(
+ content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
+}
diff --git a/chrome/browser/tab_contents/tab_util.h b/chrome/browser/tab_contents/tab_util.h
index 2a19442..896be7c 100644
--- a/chrome/browser/tab_contents/tab_util.h
+++ b/chrome/browser/tab_contents/tab_util.h
@@ -1,11 +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.
#ifndef CHROME_BROWSER_TAB_CONTENTS_TAB_UTIL_H_
#define CHROME_BROWSER_TAB_CONTENTS_TAB_UTIL_H_
+#pragma once
-class URLRequest;
class TabContents;
namespace tab_util {
diff --git a/chrome/browser/tab_contents/test_tab_contents.cc b/chrome/browser/tab_contents/test_tab_contents.cc
index 9e1cad0..ab6a325 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 "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"
TestTabContents::TestTabContents(Profile* profile, SiteInstance* instance)
- : TabContents(profile, instance, MSG_ROUTING_NONE, NULL),
+ : TabContents(profile, instance, MSG_ROUTING_NONE, NULL, NULL),
transition_cross_site(false) {
// Listen for infobar events so we can call InfoBarClosed() on the infobar
// delegates and give them an opportunity to delete themselves. (Since we
@@ -42,7 +45,7 @@ void TestTabContents::Observe(NotificationType type,
}
}
-TestRenderViewHost* TestTabContents::pending_rvh() {
+TestRenderViewHost* TestTabContents::pending_rvh() const {
return static_cast<TestRenderViewHost*>(
render_manager_.pending_render_view_host_);
}
@@ -50,8 +53,7 @@ TestRenderViewHost* TestTabContents::pending_rvh() {
bool TestTabContents::CreateRenderViewForRenderManager(
RenderViewHost* render_view_host) {
// This will go to a TestRenderViewHost.
- render_view_host->CreateRenderView(profile()->GetRequestContext(),
- string16());
+ render_view_host->CreateRenderView(string16());
return true;
}
@@ -61,3 +63,41 @@ TabContents* TestTabContents::Clone() {
tc->controller().CopyStateFrom(controller_);
return tc;
}
+
+void TestTabContents::NavigateAndCommit(const GURL& url) {
+ controller().LoadURL(url, GURL(), 0);
+ GURL loaded_url(url);
+ bool reverse_on_redirect = false;
+ BrowserURLHandler::RewriteURLIfNecessary(
+ &loaded_url, profile(), &reverse_on_redirect);
+
+ // LoadURL created a navigation entry, now simulate the RenderView sending
+ // a notification that it actually navigated.
+ CommitPendingNavigation();
+}
+
+void TestTabContents::CommitPendingNavigation() {
+ // If we are doing a cross-site navigation, this simulates the current RVH
+ // notifying that it has unloaded so the pending RVH is resumed and can
+ // navigate.
+ ProceedWithCrossSiteNavigation();
+ TestRenderViewHost* rvh = pending_rvh();
+ if (!rvh)
+ rvh = static_cast<TestRenderViewHost*>(render_manager_.current_host());
+
+ const NavigationEntry* entry = controller().pending_entry();
+ DCHECK(entry);
+ int page_id = entry->page_id();
+ if (page_id == -1) {
+ // It's a new navigation, assign a never-seen page id to it.
+ page_id =
+ static_cast<MockRenderProcessHost*>(rvh->process())->max_page_id() + 1;
+ }
+ rvh->SendNavigate(page_id, entry->url());
+}
+
+void TestTabContents::ProceedWithCrossSiteNavigation() {
+ if (!pending_rvh())
+ return;
+ render_manager_.ShouldClosePage(true, true);
+}
diff --git a/chrome/browser/tab_contents/test_tab_contents.h b/chrome/browser/tab_contents/test_tab_contents.h
index 698ef04..21bc096 100644
--- a/chrome/browser/tab_contents/test_tab_contents.h
+++ b/chrome/browser/tab_contents/test_tab_contents.h
@@ -1,16 +1,16 @@
-// 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.
#ifndef CHROME_BROWSER_TAB_CONTENTS_TEST_TAB_CONTENTS_H_
#define CHROME_BROWSER_TAB_CONTENTS_TEST_TAB_CONTENTS_H_
+#pragma once
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_registrar.h"
#include "webkit/glue/webpreferences.h"
-class RenderViewHostFactory;
+class Profile;
class TestRenderViewHost;
// Subclass TabContents to ensure it creates TestRenderViewHosts and does
@@ -20,7 +20,7 @@ class TestTabContents : public TabContents {
// The render view host factory will be passed on to the
TestTabContents(Profile* profile, SiteInstance* instance);
- TestRenderViewHost* pending_rvh();
+ TestRenderViewHost* pending_rvh() const;
// State accessor.
bool cross_navigation_pending() {
@@ -57,6 +57,20 @@ class TestTabContents : public TabContents {
// TestTabContents. The caller owns the returned object.
virtual TabContents* Clone();
+ // Creates a pending navigation to the given URL with the default parameters
+ // and then commits the load with a page ID one larger than any seen. This
+ // emulates what happens on a new navigation.
+ void NavigateAndCommit(const GURL& url);
+
+ // Simulates the appropriate RenderView (pending if any, current otherwise)
+ // sending a navigate notification for the NavigationController pending entry.
+ void CommitPendingNavigation();
+
+ // Simulates the current RVH notifying that it has unloaded so that the
+ // pending RVH navigation can proceed.
+ // Does nothing if no cross-navigation is pending.
+ void ProceedWithCrossSiteNavigation();
+
// Set by individual tests.
bool transition_cross_site;
diff --git a/chrome/browser/tab_contents/thumbnail_generator.h b/chrome/browser/tab_contents/thumbnail_generator.h
index bba224c..51fc1ff 100644
--- a/chrome/browser/tab_contents/thumbnail_generator.h
+++ b/chrome/browser/tab_contents/thumbnail_generator.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_TAB_CONTENTS_THUMBNAIL_GENERATOR_H_
#define CHROME_BROWSER_TAB_CONTENTS_THUMBNAIL_GENERATOR_H_
+#pragma once
#include <map>
#include <utility>
@@ -18,7 +19,6 @@
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class RenderViewHost;
class RenderWidgetHost;
class SkBitmap;
class TabContents;
diff --git a/chrome/browser/tab_contents/view_source_uitest.cc b/chrome/browser/tab_contents/view_source_uitest.cc
index e58a906..654b747 100644
--- a/chrome/browser/tab_contents/view_source_uitest.cc
+++ b/chrome/browser/tab_contents/view_source_uitest.cc
@@ -7,15 +7,17 @@
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const char kTestHtml[] = "files/viewsource/test.html";
class ViewSourceTest : public UITest {
protected:
- ViewSourceTest() : test_html_("files/viewsource/test.html") {
+ ViewSourceTest()
+ : test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
}
bool IsMenuCommandEnabled(int command) {
@@ -30,22 +32,21 @@ class ViewSourceTest : public UITest {
}
protected:
- std::string test_html_;
+ net::TestServer test_server_;
};
// This test renders a page in view-source and then checks to see if a cookie
// set in the html was set successfully (it shouldn't because we rendered the
// page in view source)
TEST_F(ViewSourceTest, DoesBrowserRenderInViewSource) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
std::string cookie = "viewsource_cookie";
std::string cookie_data = "foo";
// First we navigate to our view-source test page.
GURL url(chrome::kViewSourceScheme + std::string(":") +
- server->TestServerPage(test_html_).spec());
+ test_server_.GetURL(kTestHtml).spec());
scoped_refptr<TabProxy> tab(GetActiveTab());
ASSERT_TRUE(tab.get());
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(url));
@@ -62,12 +63,10 @@ TEST_F(ViewSourceTest, DoesBrowserRenderInViewSource) {
// implementation of the view-source: prefix being consumed (removed from the
// URL) if the URL was not changed (apart from adding the view-source prefix)
TEST_F(ViewSourceTest, DoesBrowserConsumeViewSourcePrefix) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
// First we navigate to google.html.
- GURL url(server->TestServerPage(test_html_));
+ GURL url(test_server_.GetURL(kTestHtml));
NavigateToURL(url);
// Then we navigate to the same url but with the "view-source:" prefix.
@@ -82,11 +81,9 @@ TEST_F(ViewSourceTest, DoesBrowserConsumeViewSourcePrefix) {
// Make sure that when looking at the actual page, we can select "View Source"
// from the menu.
TEST_F(ViewSourceTest, ViewSourceInMenuEnabledOnANormalPage) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
- GURL url(server->TestServerPage(test_html_));
+ GURL url(test_server_.GetURL(kTestHtml));
NavigateToURL(url);
EXPECT_TRUE(IsMenuCommandEnabled(IDC_VIEW_SOURCE));
@@ -95,12 +92,10 @@ TEST_F(ViewSourceTest, ViewSourceInMenuEnabledOnANormalPage) {
// Make sure that when looking at the page source, we can't select "View Source"
// from the menu.
TEST_F(ViewSourceTest, ViewSourceInMenuDisabledWhileViewingSource) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
GURL url_viewsource(chrome::kViewSourceScheme + std::string(":") +
- server->TestServerPage(test_html_).spec());
+ test_server_.GetURL(kTestHtml).spec());
NavigateToURL(url_viewsource);
EXPECT_FALSE(IsMenuCommandEnabled(IDC_VIEW_SOURCE));
diff --git a/chrome/browser/tab_contents/web_contents_unittest.cc b/chrome/browser/tab_contents/web_contents_unittest.cc
index cb3d4d4..49a0caa 100644
--- a/chrome/browser/tab_contents/web_contents_unittest.cc
+++ b/chrome/browser/tab_contents/web_contents_unittest.cc
@@ -2,12 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <vector>
+
#include "app/message_box_flags.h"
#include "base/logging.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/pref_value_store.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/pref_value_store.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/site_instance.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
@@ -17,7 +21,9 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_pref_service.h"
#include "chrome/test/testing_profile.h"
#include "ipc/ipc_channel.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -38,6 +44,7 @@ static void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params,
params->password_form = PasswordForm();
params->security_info = std::string();
params->gesture = NavigationGestureUser;
+ params->was_within_same_page = false;
params->is_post = false;
}
@@ -53,6 +60,9 @@ class TestInterstitialPage : public InterstitialPage {
public:
virtual void TestInterstitialPageDeleted(
TestInterstitialPage* interstitial) = 0;
+
+ protected:
+ virtual ~Delegate() {}
};
// IMPORTANT NOTE: if you pass stack allocated values for |state| and
@@ -184,11 +194,10 @@ class TabContentsTest : public RenderViewHostTestHarness {
// is not supposed to overwrite a profile if it's already created.
virtual void SetUp() {
TestingProfile* profile = new TestingProfile();
- profile->CreateBookmarkModel(false);
profile_.reset(profile);
// Set some (WebKit) user preferences.
- TestingPrefService* pref_services = profile->GetPrefs();
+ TestingPrefService* pref_services = profile->GetTestingPrefService();
#if defined(TOOLKIT_USES_GTK)
pref_services->SetUserPref(prefs::kUsesSystemTheme,
Value::CreateBooleanValue(false));
@@ -203,8 +212,8 @@ class TabContentsTest : public RenderViewHostTestHarness {
Value::CreateBooleanValue(true));
pref_services->SetUserPref(prefs::kWebKitStandardFontIsSerif,
Value::CreateBooleanValue(true));
- pref_services->SetUserPref(L"webkit.webprefs.foo",
- Value::CreateStringValue(L"bar"));
+ pref_services->SetUserPref("webkit.webprefs.foo",
+ Value::CreateStringValue("bar"));
RenderViewHostTestHarness::SetUp();
}
@@ -758,7 +767,7 @@ TEST_F(TabContentsTest, WebKitPrefs) {
#if defined(OS_MACOSX)
const wchar_t kDefaultFont[] = L"Times";
#elif defined(OS_CHROMEOS)
- const wchar_t kDefaultFont[] = L"Ascender Serif";
+ const wchar_t kDefaultFont[] = L"Tinos";
#else
const wchar_t kDefaultFont[] = L"Times New Roman";
#endif
@@ -1369,6 +1378,45 @@ TEST_F(TabContentsTest, NavigateBeforeInterstitialShows) {
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
}
+// Test that a new request to show an interstitial while an interstitial is
+// pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
+TEST_F(TabContentsTest, TwoQuickInterstitials) {
+ GURL interstitial_url("http://interstitial");
+
+ // Show a first interstitial.
+ TestInterstitialPage::InterstitialState state1 =
+ TestInterstitialPage::UNDECIDED;
+ bool deleted1 = false;
+ TestInterstitialPage* interstitial1 =
+ new TestInterstitialPage(contents(), true, interstitial_url,
+ &state1, &deleted1);
+ TestInterstitialPageStateGuard state_guard1(interstitial1);
+ interstitial1->Show();
+
+ // Show another interstitial on that same tab before the first one had time
+ // to load.
+ TestInterstitialPage::InterstitialState state2 =
+ TestInterstitialPage::UNDECIDED;
+ bool deleted2 = false;
+ TestInterstitialPage* interstitial2 =
+ new TestInterstitialPage(contents(), true, interstitial_url,
+ &state2, &deleted2);
+ TestInterstitialPageStateGuard state_guard2(interstitial2);
+ interstitial2->Show();
+
+ // The first interstitial should have been closed and deleted.
+ EXPECT_TRUE(deleted1);
+ EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
+
+ // The 2nd one should still be OK.
+ ASSERT_FALSE(deleted2);
+ EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
+
+ // Make the interstitial navigation commit it should be showing.
+ interstitial2->TestDidNavigate(1, interstitial_url);
+ EXPECT_EQ(interstitial2, contents()->interstitial_page());
+}
+
// Test showing an interstitial and have its renderer crash.
TEST_F(TabContentsTest, InterstitialCrasher) {
// Show an interstitial.
@@ -1474,3 +1522,92 @@ TEST_F(TabContentsTest, NoJSMessageOnInterstitials) {
&did_suppress_message);
EXPECT_TRUE(did_suppress_message);
}
+
+// Makes sure that if the source passed to CopyStateFromAndPrune has an
+// interstitial it isn't copied over to the destination.
+TEST_F(TabContentsTest, CopyStateFromAndPruneSourceInterstitial) {
+ // Navigate to a page.
+ GURL url1("http://www.google.com");
+ rvh()->SendNavigate(1, url1);
+ EXPECT_EQ(1, controller().entry_count());
+
+ // Initiate a browser navigation that will trigger the interstitial
+ controller().LoadURL(GURL("http://www.evil.com"), GURL(),
+ PageTransition::TYPED);
+
+ // Show an interstitial.
+ TestInterstitialPage::InterstitialState state =
+ TestInterstitialPage::UNDECIDED;
+ bool deleted = false;
+ GURL url2("http://interstitial");
+ TestInterstitialPage* interstitial =
+ new TestInterstitialPage(contents(), true, url2, &state, &deleted);
+ TestInterstitialPageStateGuard state_guard(interstitial);
+ interstitial->Show();
+ interstitial->TestDidNavigate(1, url2);
+ EXPECT_TRUE(interstitial->is_showing());
+ EXPECT_EQ(2, controller().entry_count());
+
+ // Create another NavigationController.
+ GURL url3("http://foo2");
+ scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
+ NavigationController& other_controller = other_contents->controller();
+ other_contents->NavigateAndCommit(url3);
+ other_controller.CopyStateFromAndPrune(controller());
+
+ // The merged controller should only have two entries: url1 and url2.
+ ASSERT_EQ(2, other_controller.entry_count());
+ EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
+ EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
+ EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->url());
+
+ // And the merged controller shouldn't be showing an interstitial.
+ EXPECT_FALSE(other_contents->showing_interstitial_page());
+}
+
+// Makes sure that CopyStateFromAndPrune does the right thing if the object
+// CopyStateFromAndPrune is invoked on is showing an interstitial.
+TEST_F(TabContentsTest, CopyStateFromAndPruneTargetInterstitial) {
+ // Navigate to a page.
+ GURL url1("http://www.google.com");
+ contents()->NavigateAndCommit(url1);
+
+ // Create another NavigationController.
+ scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
+ NavigationController& other_controller = other_contents->controller();
+
+ // Navigate it to url2.
+ GURL url2("http://foo2");
+ other_contents->NavigateAndCommit(url2);
+
+ // Show an interstitial.
+ TestInterstitialPage::InterstitialState state =
+ TestInterstitialPage::UNDECIDED;
+ bool deleted = false;
+ GURL url3("http://interstitial");
+ TestInterstitialPage* interstitial =
+ new TestInterstitialPage(other_contents.get(), true, url3, &state,
+ &deleted);
+ TestInterstitialPageStateGuard state_guard(interstitial);
+ interstitial->Show();
+ interstitial->TestDidNavigate(1, url3);
+ EXPECT_TRUE(interstitial->is_showing());
+ EXPECT_EQ(2, other_controller.entry_count());
+
+ other_controller.CopyStateFromAndPrune(controller());
+
+ // The merged controller should only have two entries: url1 and url2.
+ ASSERT_EQ(2, other_controller.entry_count());
+ EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
+ EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
+ EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->url());
+
+ // It should have a transient entry.
+ EXPECT_TRUE(other_controller.GetTransientEntry());
+
+ // And the interstitial should be showing.
+ EXPECT_TRUE(other_contents->showing_interstitial_page());
+
+ // And the interstitial should do a reload on don't proceed.
+ EXPECT_TRUE(other_contents->interstitial_page()->reload_on_dont_proceed());
+}
diff --git a/chrome/browser/tab_contents/web_drag_dest_gtk.h b/chrome/browser/tab_contents/web_drag_dest_gtk.h
index 49607b2..67d6852 100644
--- a/chrome/browser/tab_contents/web_drag_dest_gtk.h
+++ b/chrome/browser/tab_contents/web_drag_dest_gtk.h
@@ -1,12 +1,12 @@
-// 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.
#ifndef CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_DEST_GTK_H_
#define CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_DEST_GTK_H_
+#pragma once
#include <gtk/gtk.h>
-#include <vector>
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
@@ -15,7 +15,6 @@
#include "third_party/WebKit/WebKit/chromium/public/WebDragOperation.h"
#include "webkit/glue/webdropdata.h"
-class BookmarkNode;
class TabContents;
// A helper class that handles DnD for drops in the renderer. In GTK parlance,
@@ -23,7 +22,7 @@ class TabContents;
class WebDragDestGtk {
public:
WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget);
- ~WebDragDestGtk();
+ virtual ~WebDragDestGtk();
// This is called when the renderer responds to a drag motion event. We must
// update the system drag cursor.
diff --git a/chrome/browser/tab_contents/web_drag_source_win.h b/chrome/browser/tab_contents/web_drag_source_win.h
index 986d70c..2cd7583 100644
--- a/chrome/browser/tab_contents/web_drag_source_win.h
+++ b/chrome/browser/tab_contents/web_drag_source_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_SOURCE_WIN_H_
#define CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_SOURCE_WIN_H_
+#pragma once
#include "base/base_drag_source.h"
#include "base/basictypes.h"
diff --git a/chrome/browser/tab_contents/web_drag_utils_win.h b/chrome/browser/tab_contents/web_drag_utils_win.h
index 6561733..caa1875 100644
--- a/chrome/browser/tab_contents/web_drag_utils_win.h
+++ b/chrome/browser/tab_contents/web_drag_utils_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_UTILS_WIN_H_
#define CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_UTILS_WIN_H_
+#pragma once
#include "third_party/WebKit/WebKit/chromium/public/WebDragOperation.h"
diff --git a/chrome/browser/tab_contents/web_drop_target_win.h b/chrome/browser/tab_contents/web_drop_target_win.h
index c38ddac..ddb449e 100644
--- a/chrome/browser/tab_contents/web_drop_target_win.h
+++ b/chrome/browser/tab_contents/web_drop_target_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TAB_CONTENTS_WEB_DROP_TARGET_WIN_H_
#define CHROME_BROWSER_TAB_CONTENTS_WEB_DROP_TARGET_WIN_H_
+#pragma once
#include "base/base_drop_target.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/tab_menu_model.h b/chrome/browser/tab_menu_model.h
index a910983..0f7dedd 100644
--- a/chrome/browser/tab_menu_model.h
+++ b/chrome/browser/tab_menu_model.h
@@ -4,11 +4,10 @@
#ifndef CHROME_BROWSER_TAB_MENU_MODEL_H_
#define CHROME_BROWSER_TAB_MENU_MODEL_H_
+#pragma once
#include "app/menus/simple_menu_model.h"
-class Browser;
-
// 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
diff --git a/chrome/browser/tab_menu_model_unittest.cc b/chrome/browser/tab_menu_model_unittest.cc
index eaaa72e..fd39e57 100644
--- a/chrome/browser/tab_menu_model_unittest.cc
+++ b/chrome/browser/tab_menu_model_unittest.cc
@@ -1,10 +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.
+// Copyright (c) 2010 The Chromium Authors. All rights 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/logging.h"
#include "chrome/test/menu_model_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/chrome/browser/tab_restore_uitest.cc b/chrome/browser/tab_restore_uitest.cc
index ac655ea..a8a13e6 100644
--- a/chrome/browser/tab_restore_uitest.cc
+++ b/chrome/browser/tab_restore_uitest.cc
@@ -5,9 +5,6 @@
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/file_path.h"
-#if defined(OS_WIN)
-#include "base/win_util.h"
-#endif
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -19,7 +16,7 @@
#include "chrome/test/ui/ui_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
// http://code.google.com/p/chromium/issues/detail?id=14774
#if (defined(OS_WIN) || defined(OS_CHROMEOS)) && !defined(NDEBUG)
@@ -457,13 +454,19 @@ TEST_F(TabRestoreUITest, FLAKY_RestoreIntoSameWindow) {
// Tests that a duplicate history entry is not created when we restore a page
// to an existing SiteInstance. (Bug 1230446)
-TEST_F(TabRestoreUITest, RestoreWithExistingSiteInstance) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL http_url1(server->TestServerPage("files/title1.html"));
- GURL http_url2(server->TestServerPage("files/title2.html"));
+#if defined(OS_WIN)
+// http://crbug.com/55380 - NavigateToURL to making this flaky
+#define MAYBE_RestoreWithExistingSiteInstance FLAKY_RestoreWithExistingSiteInstance
+#else
+#define MAYBE_RestoreWithExistingSiteInstance RestoreWithExistingSiteInstance
+#endif
+TEST_F(TabRestoreUITest, MAYBE_RestoreWithExistingSiteInstance) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL http_url1(test_server.GetURL("files/title1.html"));
+ GURL http_url2(test_server.GetURL("files/title2.html"));
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
@@ -504,13 +507,14 @@ TEST_F(TabRestoreUITest, RestoreWithExistingSiteInstance) {
// Tests that the SiteInstances used for entries in a restored tab's history
// are given appropriate max page IDs, even if the renderer for the entry
// already exists. (Bug 1204135)
-TEST_F(TabRestoreUITest, RestoreCrossSiteWithExistingSiteInstance) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL http_url1(server->TestServerPage("files/title1.html"));
- GURL http_url2(server->TestServerPage("files/title2.html"));
+// http://crbug.com/55380 - NavigateToURL to making this flaky on all platforms
+TEST_F(TabRestoreUITest, FLAKY_RestoreCrossSiteWithExistingSiteInstance) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL http_url1(test_server.GetURL("files/title1.html"));
+ GURL http_url2(test_server.GetURL("files/title2.html"));
scoped_refptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser_proxy.get());
@@ -571,14 +575,12 @@ TEST_F(TabRestoreUITest, MAYBE_RestoreWindow) {
int initial_tab_count;
ASSERT_TRUE(browser_proxy->GetTabCount(&initial_tab_count));
ASSERT_TRUE(browser_proxy->AppendTab(url1_));
- ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(initial_tab_count + 1,
- action_max_timeout_ms()));
+ ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(initial_tab_count + 1));
scoped_refptr<TabProxy> new_tab(browser_proxy->GetTab(initial_tab_count));
ASSERT_TRUE(new_tab.get());
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, new_tab->NavigateToURL(url1_));
ASSERT_TRUE(browser_proxy->AppendTab(url2_));
- ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(initial_tab_count + 2,
- action_max_timeout_ms()));
+ ASSERT_TRUE(browser_proxy->WaitForTabCountToBecome(initial_tab_count + 2));
new_tab = browser_proxy->GetTab(initial_tab_count + 1);
ASSERT_TRUE(new_tab.get());
ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, new_tab->NavigateToURL(url2_));
@@ -647,11 +649,11 @@ TEST_F(TabRestoreUITest, RestoreTabWithSpecialURL) {
// Restore tab with special URL in its navigation history, go back to that
// entry and see that it loads properly. See http://crbug.com/31905
TEST_F(TabRestoreUITest, RestoreTabWithSpecialURLOnBack) {
- const wchar_t kDocRoot[] = L"chrome/test/data";
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(server.get());
- const GURL http_url(server->TestServerPage("files/title1.html"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
+
+ const GURL http_url(test_server.GetURL("files/title1.html"));
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
diff --git a/chrome/browser/tabs/pinned_tab_codec.cc b/chrome/browser/tabs/pinned_tab_codec.cc
index 3473343..6920bfa 100644
--- a/chrome/browser/tabs/pinned_tab_codec.cc
+++ b/chrome/browser/tabs/pinned_tab_codec.cc
@@ -7,7 +7,7 @@
#include "base/values.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/pref_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/tabs/tab_strip_model.h"
@@ -19,10 +19,10 @@
typedef BrowserInit::LaunchWithProfile::Tab Tab;
// Key used in dictionaries for the app id.
-static const wchar_t kAppID[] = L"app_id";
+static const char kAppID[] = "app_id";
// Key used in dictionaries for the url.
-static const wchar_t kURL[] = L"url";
+static const char kURL[] = "url";
// Returns true if |browser| has any pinned tabs.
static bool HasPinnedTabs(Browser* browser) {
diff --git a/chrome/browser/tabs/pinned_tab_codec.h b/chrome/browser/tabs/pinned_tab_codec.h
index 1b1aed3..55fc377 100644
--- a/chrome/browser/tabs/pinned_tab_codec.h
+++ b/chrome/browser/tabs/pinned_tab_codec.h
@@ -4,14 +4,13 @@
#ifndef CHROME_BROWSER_TABS_PINNED_TAB_CODEC_H_
#define CHROME_BROWSER_TABS_PINNED_TAB_CODEC_H_
+#pragma once
-#include <string>
#include <vector>
#include "chrome/browser/browser_init.h"
#include "googleurl/src/gurl.h"
-class Browser;
class PrefService;
class Profile;
diff --git a/chrome/browser/tabs/pinned_tab_codec_unittest.cc b/chrome/browser/tabs/pinned_tab_codec_unittest.cc
index c9461eb..6737c01 100644
--- a/chrome/browser/tabs/pinned_tab_codec_unittest.cc
+++ b/chrome/browser/tabs/pinned_tab_codec_unittest.cc
@@ -6,7 +6,9 @@
#include <vector>
#include "chrome/browser/tabs/pinned_tab_codec.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/test/browser_with_test_window_test.h"
+#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
typedef BrowserInit::LaunchWithProfile::Tab Tab;
diff --git a/chrome/browser/tabs/pinned_tab_service.h b/chrome/browser/tabs/pinned_tab_service.h
index 3437857..5425e06 100644
--- a/chrome/browser/tabs/pinned_tab_service.h
+++ b/chrome/browser/tabs/pinned_tab_service.h
@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_TABS_PINNED_TAB_SERVICE_H_
#define CHROME_BROWSER_TABS_PINNED_TAB_SERVICE_H_
+#pragma once
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class Browser;
class Profile;
// PinnedTabService is responsible for updating preferences with the set of
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index 22cea3b..f27b5a8 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/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/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -46,59 +47,6 @@ bool ShouldForgetOpenersForTransition(PageTransition::Type transition) {
} // namespace
///////////////////////////////////////////////////////////////////////////////
-// TabStripModelObserver, public:
-
-void TabStripModelObserver::TabInsertedAt(TabContents* contents,
- int index,
- bool foreground) {
-}
-
-void TabStripModelObserver::TabClosingAt(TabContents* contents, int index) {
-}
-
-void TabStripModelObserver::TabDetachedAt(TabContents* contents, int index) {
-}
-
-void TabStripModelObserver::TabDeselectedAt(TabContents* contents, int index) {
-}
-
-void TabStripModelObserver::TabSelectedAt(TabContents* old_contents,
- TabContents* new_contents,
- int index,
- bool user_gesture) {
-}
-
-void TabStripModelObserver::TabMoved(TabContents* contents,
- int from_index,
- int to_index) {
-}
-
-void TabStripModelObserver::TabChangedAt(TabContents* contents, int index,
- TabChangeType change_type) {
-}
-
-void TabStripModelObserver::TabReplacedAt(TabContents* old_contents,
- TabContents* new_contents,
- int index) {
-}
-
-void TabStripModelObserver::TabPinnedStateChanged(TabContents* contents,
- int index) {
-}
-
-void TabStripModelObserver::TabMiniStateChanged(TabContents* contents,
- int index) {
-}
-
-void TabStripModelObserver::TabBlockedStateChanged(TabContents* contents,
- int index) {
-}
-
-void TabStripModelObserver::TabStripEmpty() {}
-
-void TabStripModelObserver::TabStripModelDeleted() {}
-
-///////////////////////////////////////////////////////////////////////////////
// TabStripModelDelegate, public:
bool TabStripModelDelegate::CanCloseTab() const {
@@ -185,8 +133,9 @@ void TabStripModel::InsertTabContentsAt(int index,
TabContents* contents,
int add_types) {
bool foreground = add_types & ADD_SELECTED;
- index = ConstrainInsertionIndex(index, contents->is_app() ||
- add_types & ADD_PINNED);
+ // Force app tabs to be pinned.
+ bool pin = contents->is_app() || add_types & ADD_PINNED;
+ index = ConstrainInsertionIndex(index, pin);
// In tab dragging situations, if the last tab in the window was detached
// then the user aborted the drag, we will have the |closing_all_| member
@@ -199,7 +148,7 @@ void TabStripModel::InsertTabContentsAt(int index,
// since the old contents and the new contents will be the same...
TabContents* selected_contents = GetSelectedTabContents();
TabContentsData* data = new TabContentsData(contents);
- data->pinned = (add_types & ADD_PINNED) == ADD_PINNED;
+ data->pinned = pin;
if ((add_types & ADD_INHERIT_GROUP) && selected_contents) {
if (foreground) {
// Forget any existing relationships, we don't want to make things too
@@ -232,6 +181,23 @@ void TabStripModel::InsertTabContentsAt(int index,
ChangeSelectedContentsFrom(selected_contents, index, false);
}
+void TabStripModel::ReplaceTabContentsAt(
+ int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type) {
+ scoped_ptr<TabContents> old_contents(
+ ReplaceTabContentsAtImpl(index, new_contents, type));
+
+ // When the selected tab contents is replaced send out selected notification
+ // too. We do this as nearly all observers need to treat a replace of the
+ // selected contents as selection changing.
+ if (selected_index_ == index) {
+ FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
+ TabSelectedAt(old_contents.get(), new_contents,
+ selected_index_, false));
+ }
+}
+
void TabStripModel::ReplaceNavigationControllerAt(
int index, NavigationController* controller) {
// This appears to be OK with no flicker since no redraw event
@@ -259,13 +225,14 @@ TabContents* TabStripModel::DetachTabContentsAt(int index) {
next_selected_index = IndexOfNextNonPhantomTab(next_selected_index, -1);
if (!HasNonPhantomTabs())
closing_all_ = true;
- TabStripModelObservers::Iterator iter(observers_);
- while (TabStripModelObserver* obs = iter.GetNext()) {
- obs->TabDetachedAt(removed_contents, index);
- if (!HasNonPhantomTabs())
- obs->TabStripEmpty();
- }
- if (HasNonPhantomTabs()) {
+ FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
+ TabDetachedAt(removed_contents, index));
+ if (!HasNonPhantomTabs()) {
+ // TabDetachedAt() might unregister observers, so send |TabStripEmtpy()| in
+ // a second pass.
+ FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
+ TabStripEmpty());
+ } else {
if (index == selected_index_) {
ChangeSelectedContentsFrom(removed_contents, next_selected_index, false);
} else if (index < selected_index_) {
@@ -484,6 +451,11 @@ void TabStripModel::SetTabPinned(int index, bool pinned) {
return;
if (IsAppTab(index)) {
+ if (!pinned) {
+ // App tabs should always be pinned.
+ NOTREACHED();
+ return;
+ }
// Changing the pinned state of an app tab doesn't effect it's mini-tab
// status.
contents_data_[index]->pinned = pinned;
@@ -656,14 +628,6 @@ void TabStripModel::MoveTabPrevious() {
MoveTabContentsAt(selected_index_, new_index, true);
}
-Browser* TabStripModel::TearOffTabContents(TabContents* detached_contents,
- const gfx::Rect& window_bounds,
- const DockInfo& dock_info) {
- DCHECK(detached_contents);
- return delegate_->CreateNewStripWithContents(detached_contents, window_bounds,
- dock_info);
-}
-
// Context menu functions.
bool TabStripModel::IsContextMenuCommandEnabled(
int context_index, ContextMenuCommand command_id) const {
@@ -694,9 +658,10 @@ bool TabStripModel::IsContextMenuCommandEnabled(
case CommandRestoreTab:
return delegate_->CanRestoreTab();
case CommandTogglePinned:
- return true;
+ return !IsAppTab(context_index);
case CommandBookmarkAllTabs:
- return delegate_->CanBookmarkAllTabs();
+ return browser_defaults::bookmarks_enabled &&
+ delegate_->CanBookmarkAllTabs();
case CommandUseVerticalTabs:
return true;
default:
@@ -1045,14 +1010,10 @@ bool TabStripModel::ShouldMakePhantomOnClose(int index) {
}
void TabStripModel::MakePhantom(int index) {
- TabContents* old_contents = GetContentsAt(index);
- TabContents* new_contents = old_contents->CloneAndMakePhantom();
-
- contents_data_[index]->contents = new_contents;
-
- // And notify observers.
- FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
- TabReplacedAt(old_contents, new_contents, index));
+ // MakePhantom is called when the TabContents is being destroyed so we don't
+ // need to do anything with the returned value from ReplaceTabContentsAtImpl.
+ ReplaceTabContentsAtImpl(index, GetContentsAt(index)->CloneAndMakePhantom(),
+ TabStripModelObserver::REPLACE_MADE_PHANTOM);
if (selected_index_ == index && HasNonPhantomTabs()) {
// Change the selection, otherwise we're going to force the phantom tab
@@ -1097,3 +1058,20 @@ bool TabStripModel::OpenerMatches(const TabContentsData* data,
bool use_group) {
return data->opener == opener || (use_group && data->group == opener);
}
+
+TabContents* TabStripModel::ReplaceTabContentsAtImpl(
+ int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type) {
+ // TODO: this should reset group/opener of any tabs that point at
+ // old_contents.
+ DCHECK(ContainsIndex(index));
+
+ TabContents* old_contents = GetContentsAt(index);
+
+ contents_data_[index]->contents = new_contents;
+
+ FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
+ TabReplacedAt(old_contents, new_contents, index, type));
+ return old_contents;
+}
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index 5e43d85..003f3d6 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -4,239 +4,21 @@
#ifndef CHROME_BROWSER_TABS_TAB_STRIP_MODEL_H_
#define CHROME_BROWSER_TABS_TAB_STRIP_MODEL_H_
+#pragma once
#include <vector>
#include "base/observer_list.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/page_transition_types.h"
-namespace gfx {
-class Point;
-class Rect;
-}
-class Browser;
-class DockInfo;
-class GURL;
class NavigationController;
class Profile;
-class SiteInstance;
class TabContents;
+class TabStripModelDelegate;
class TabStripModelOrderController;
-class TabStripModel;
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// TabStripModelObserver
-//
-// Objects implement this interface when they wish to be notified of changes
-// to the TabStripModel.
-//
-// Two major implementers are the TabStrip, which uses notifications sent
-// via this interface to update the presentation of the strip, and the Browser
-// object, which updates bookkeeping and shows/hides individual TabContentses.
-//
-// Register your TabStripModelObserver with the TabStripModel using its
-// Add/RemoveObserver methods.
-//
-////////////////////////////////////////////////////////////////////////////////
-class TabStripModelObserver {
- public:
- // Enumeration of the possible values supplied to TabChangedAt.
- enum TabChangeType {
- // Only the loading state changed.
- LOADING_ONLY,
-
- // Only the title changed and page isn't loading.
- TITLE_NOT_LOADING,
-
- // Change not characterized by LOADING_ONLY or TITLE_NOT_LOADING.
- ALL
- };
-
- // A new TabContents was inserted into the TabStripModel at the specified
- // index. |foreground| is whether or not it was opened in the foreground
- // (selected).
- virtual void TabInsertedAt(TabContents* contents,
- int index,
- bool foreground);
-
- // The specified TabContents at |index| is being closed (and eventually
- // destroyed).
- virtual void TabClosingAt(TabContents* contents, int index);
-
- // The specified TabContents at |index| is being detached, perhaps to be
- // inserted in another TabStripModel. The implementer should take whatever
- // action is necessary to deal with the TabContents no longer being present.
- virtual void TabDetachedAt(TabContents* contents, int index);
-
- // The selected TabContents is about to change from |old_contents| at |index|.
- // This gives observers a chance to prepare for an impending switch before it
- // happens.
- virtual void TabDeselectedAt(TabContents* contents, int index);
-
- // The selected TabContents changed from |old_contents| to |new_contents| at
- // |index|. |user_gesture| specifies whether or not this was done by a user
- // input event (e.g. clicking on a tab, keystroke) or as a side-effect of
- // some other function.
- virtual void TabSelectedAt(TabContents* old_contents,
- TabContents* new_contents,
- int index,
- bool user_gesture);
-
- // The specified TabContents at |from_index| was moved to |to_index|.
- virtual void TabMoved(TabContents* contents,
- int from_index,
- int to_index);
-
- // The specified TabContents at |index| changed in some way. |contents| may
- // be an entirely different object and the old value is no longer available
- // by the time this message is delivered.
- //
- // See TabChangeType for a description of |change_type|.
- virtual void TabChangedAt(TabContents* contents, int index,
- TabChangeType change_type);
-
- // The tab contents was replaced at the specified index. This is invoked when
- // a tab becomes phantom. See description of phantom tabs in class description
- // of TabStripModel for details.
- virtual void TabReplacedAt(TabContents* old_contents,
- TabContents* new_contents, int index);
-
- // Invoked when the pinned state of a tab changes. This is not invoked if the
- // tab ends up moving as a result of the mini state changing.
- // See note in TabMiniStateChanged as to how this relates to
- // TabMiniStateChanged.
- virtual void TabPinnedStateChanged(TabContents* contents, int index);
-
- // Invoked if the mini state of a tab changes. This is not invoked if the
- // tab ends up moving as a result of the mini state changing.
- // NOTE: this is sent when the pinned state of a non-app tab changes and is
- // sent in addition to TabPinnedStateChanged. UI code typically need not care
- // about TabPinnedStateChanged, but instead this.
- virtual void TabMiniStateChanged(TabContents* contents, int index);
-
- // Invoked when the blocked state of a tab changes.
- // NOTE: This is invoked when a tab becomes blocked/unblocked by a tab modal
- // window.
- virtual void TabBlockedStateChanged(TabContents* contents, int index);
-
- // The TabStripModel now no longer has any phantom tabs. The implementer may
- // use this as a trigger to try and close the window containing the
- // TabStripModel, for example...
- virtual void TabStripEmpty();
-
- // Sent when the tabstrip model is about to be deleted and any reference held
- // must be dropped.
- virtual void TabStripModelDeleted();
-};
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// TabStripModelDelegate
-//
-// A delegate interface that the TabStripModel uses to perform work that it
-// can't do itself, such as obtain a container HWND for creating new
-// TabContents, creating new TabStripModels for detached tabs, etc.
-//
-// This interface is typically implemented by the controller that instantiates
-// the TabStripModel (in our case the Browser object).
-//
-///////////////////////////////////////////////////////////////////////////////
-class TabStripModelDelegate {
- public:
- // Adds what the delegate considers to be a blank tab to the model.
- virtual TabContents* AddBlankTab(bool foreground) = 0;
- virtual TabContents* AddBlankTabAt(int index, bool foreground) = 0;
-
- // Asks for a new TabStripModel to be created and the given tab contents to
- // be added to it. Its size and position are reflected in |window_bounds|.
- // If |dock_info|'s type is other than NONE, the newly created window should
- // be docked as identified by |dock_info|. Returns the Browser object
- // representing the newly created window and tab strip. This does not
- // show the window, it's up to the caller to do so.
- virtual Browser* CreateNewStripWithContents(TabContents* contents,
- const gfx::Rect& window_bounds,
- const DockInfo& dock_info) = 0;
-
- // Creates a new Browser object and window containing the specified
- // |contents|, and continues a drag operation that began within the source
- // window's tab strip. |window_bounds| are the bounds of the source window in
- // screen coordinates, used to place the new window, and |tab_bounds| are the
- // bounds of the dragged Tab view in the source window, in screen coordinates,
- // used to place the new Tab in the new window.
- virtual void ContinueDraggingDetachedTab(TabContents* contents,
- const gfx::Rect& window_bounds,
- const gfx::Rect& tab_bounds) = 0;
-
- enum {
- TAB_MOVE_ACTION = 1,
- TAB_TEAROFF_ACTION = 2
- };
-
- // Determines what drag actions are possible for the specified strip.
- virtual int GetDragActions() const = 0;
-
- // Creates an appropriate TabContents for the given URL. This is handled by
- // the delegate since the TabContents may require special circumstances to
- // exist for it to be constructed (e.g. a parent HWND).
- // If |defer_load| is true, the navigation controller doesn't load the url.
- // If |instance| is not null, its process is used to render the tab.
- virtual TabContents* CreateTabContentsForURL(
- const GURL& url,
- const GURL& referrer,
- Profile* profile,
- PageTransition::Type transition,
- bool defer_load,
- SiteInstance* instance) const = 0;
-
- // Returns whether some contents can be duplicated.
- virtual bool CanDuplicateContentsAt(int index) = 0;
-
- // Duplicates the contents at the provided index and places it into its own
- // window.
- virtual void DuplicateContentsAt(int index) = 0;
-
- // Called when a drag session has completed and the frame that initiated the
- // the session should be closed.
- virtual void CloseFrameAfterDragSession() = 0;
-
- // Creates an entry in the historical tab database for the specified
- // TabContents.
- virtual void CreateHistoricalTab(TabContents* contents) = 0;
-
- // Runs any unload listeners associated with the specified TabContents before
- // it is closed. If there are unload listeners that need to be run, this
- // function returns true and the TabStripModel will wait before closing the
- // TabContents. If it returns false, there are no unload listeners and the
- // TabStripModel can close the TabContents immediately.
- virtual bool RunUnloadListenerBeforeClosing(TabContents* contents) = 0;
-
- // Returns true if a tab can be restored.
- virtual bool CanRestoreTab() = 0;
-
- // Restores the last closed tab if CanRestoreTab would return true.
- virtual void RestoreTab() = 0;
-
- // Returns whether some contents can be closed.
- virtual bool CanCloseContentsAt(int index) = 0;
-
- // Returns true if we should allow "bookmark all tabs" in this window; this is
- // true when there is more than one bookmarkable tab open.
- virtual bool CanBookmarkAllTabs() const = 0;
-
- // Creates a bookmark folder containing a bookmark for all open tabs.
- virtual void BookmarkAllTabs() = 0;
-
- // Returns true if any of the tabs can be closed.
- virtual bool CanCloseTab() const;
-
- // Returns true if the vertical tabstrip presentation should be used.
- virtual bool UseVerticalTabs() const = 0;
-
- // Toggles the use of the vertical tabstrip.
- virtual void ToggleUseVerticalTabs() = 0;
-};
////////////////////////////////////////////////////////////////////////////////
//
@@ -257,7 +39,8 @@ class TabStripModelDelegate {
// You'll notice there is no explcit api for making a tab a mini-tab, rather
// there are two tab types that are implicitly mini-tabs:
// . App. Corresponds to an extension that wants an app tab. App tabs are
-// identified by TabContents::is_app().
+// identified by TabContents::is_app(). App tabs are always pinneded (you
+// can't unpin them).
// . Pinned. Any tab can be pinned. A pinned tab is made phantom when closed.
// Non-app tabs whose pinned state is changed are moved to be with other
// mini-tabs or non-mini tabs.
@@ -425,6 +208,12 @@ class TabStripModel : public NotificationObserver {
void ReplaceNavigationControllerAt(int index,
NavigationController* controller);
+ // Replaces the tab contents at |index| with |new_contents|. |type| is passed
+ // to the observer. This deletes the TabContents currently at |index|.
+ void ReplaceTabContentsAt(int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type);
+
// Detaches the TabContents at the specified index from this strip. The
// TabContents is not destroyed, just removed from display. The caller is
// responsible for doing something with it (e.g. stuffing it into another
@@ -603,12 +392,6 @@ class TabStripModel : public NotificationObserver {
// View API //////////////////////////////////////////////////////////////////
- // The specified contents should be opened in a new tabstrip. Returns the
- // Browser that holds it.
- Browser* TearOffTabContents(TabContents* detached_contents,
- const gfx::Rect& window_bounds,
- const DockInfo& dock_info);
-
// Context menu functions.
enum ContextMenuCommand {
CommandFirst = 0,
@@ -723,6 +506,13 @@ class TabStripModel : public NotificationObserver {
const NavigationController* opener,
bool use_group);
+ // Does the work for ReplaceTabContentsAt returning the old TabContents.
+ // The caller owns the returned TabContents.
+ TabContents* ReplaceTabContentsAtImpl(
+ int index,
+ TabContents* new_contents,
+ TabStripModelObserver::TabReplaceType type);
+
// Our delegate.
TabStripModelDelegate* delegate_;
diff --git a/chrome/browser/tabs/tab_strip_model_order_controller.h b/chrome/browser/tabs/tab_strip_model_order_controller.h
index f0ff265..b7b579c 100644
--- a/chrome/browser/tabs/tab_strip_model_order_controller.h
+++ b/chrome/browser/tabs/tab_strip_model_order_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H_
#define CHROME_BROWSER_TABS_TAB_STRIP_MODEL_ORDER_CONTROLLER_H_
+#pragma once
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/page_transition_types.h"
diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc
index 90f3012..9fabf5b 100644
--- a/chrome/browser/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/tabs/tab_strip_model_unittest.cc
@@ -6,10 +6,13 @@
#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"
@@ -19,6 +22,7 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.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/common/extensions/extension.h"
#include "chrome/common/notification_observer_mock.h"
@@ -27,6 +31,7 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/property_bag.h"
#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
@@ -47,7 +52,8 @@ class TabStripDummyDelegate : public TabStripModelDelegate {
}
virtual Browser* CreateNewStripWithContents(TabContents* contents,
const gfx::Rect& window_bounds,
- const DockInfo& dock_info) {
+ const DockInfo& dock_info,
+ bool maximize) {
return NULL;
}
virtual void ContinueDraggingDetachedTab(TabContents* contents,
@@ -78,8 +84,10 @@ class TabStripDummyDelegate : public TabStripModelDelegate {
virtual bool CanCloseContentsAt(int index) { return can_close_ ; }
virtual bool CanBookmarkAllTabs() const { return false; }
virtual void BookmarkAllTabs() {}
+ virtual bool CanCloseTab() const { return true; }
virtual bool UseVerticalTabs() const { return false; }
virtual void ToggleUseVerticalTabs() {}
+ virtual bool LargeIconsPermitted() const { return true; }
private:
// A dummy TabContents we give to callers that expect us to actually build a
@@ -98,13 +106,13 @@ class TabStripDummyDelegate : public TabStripModelDelegate {
class TabStripModelTest : public RenderViewHostTestHarness {
public:
TabContents* CreateTabContents() {
- return new TabContents(profile(), NULL, 0, NULL);
+ return new TabContents(profile(), NULL, 0, NULL, NULL);
}
TabContents* CreateTabContentsWithSharedRPH(TabContents* tab_contents) {
TabContents* retval = new TabContents(profile(),
tab_contents->render_view_host()->site_instance(), MSG_ROUTING_NONE,
- NULL);
+ NULL, NULL);
EXPECT_EQ(retval->GetRenderProcessHost(),
tab_contents->GetRenderProcessHost());
return retval;
@@ -148,7 +156,7 @@ class TabStripModelTest : public RenderViewHostTestHarness {
if (i > 0)
actual += " ";
- actual += IntToString(GetID(model.GetTabContentsAt(i)));
+ actual += base::IntToString(GetID(model.GetTabContentsAt(i)));
if (model.IsAppTab(i))
actual += "a";
@@ -171,7 +179,7 @@ class TabStripModelTest : public RenderViewHostTestHarness {
for (size_t i = 0; i < indices.size(); ++i) {
if (i != 0)
result += " ";
- result += IntToString(indices[i]);
+ result += base::IntToString(indices[i]);
}
return result;
}
@@ -1166,7 +1174,7 @@ TEST_F(TabStripModelTest, AddTabContents_ForgetOpeners) {
// Added for http://b/issue?id=958960
TEST_F(TabStripModelTest, AppendContentsReselectionTest) {
- TabContents fake_destinations_tab(profile(), NULL, 0, NULL);
+ TabContents fake_destinations_tab(profile(), NULL, 0, NULL, NULL);
TabStripDummyDelegate delegate(&fake_destinations_tab);
TabStripModel tabstrip(&delegate, profile());
EXPECT_TRUE(tabstrip.empty());
@@ -1536,7 +1544,7 @@ TEST_F(TabStripModelTest, Apps) {
EXPECT_TRUE(observer.StateEquals(0, state));
// And verify the state.
- EXPECT_EQ("1a 3", GetPinnedState(tabstrip));
+ EXPECT_EQ("1ap 3", GetPinnedState(tabstrip));
observer.ClearStates();
}
@@ -1550,7 +1558,7 @@ TEST_F(TabStripModelTest, Apps) {
EXPECT_TRUE(observer.StateEquals(0, state));
// And verify the state.
- EXPECT_EQ("1a 2a 3", GetPinnedState(tabstrip));
+ EXPECT_EQ("1ap 2ap 3", GetPinnedState(tabstrip));
observer.ClearStates();
}
@@ -1562,7 +1570,7 @@ TEST_F(TabStripModelTest, Apps) {
ASSERT_EQ(0, observer.GetStateCount());
// And verify the state didn't change.
- EXPECT_EQ("1a 2a 3", GetPinnedState(tabstrip));
+ EXPECT_EQ("1ap 2ap 3", GetPinnedState(tabstrip));
observer.ClearStates();
}
@@ -1574,7 +1582,7 @@ TEST_F(TabStripModelTest, Apps) {
ASSERT_EQ(0, observer.GetStateCount());
// And verify the state didn't change.
- EXPECT_EQ("1a 2a 3", GetPinnedState(tabstrip));
+ EXPECT_EQ("1ap 2ap 3", GetPinnedState(tabstrip));
observer.ClearStates();
}
@@ -1589,7 +1597,7 @@ TEST_F(TabStripModelTest, Apps) {
EXPECT_TRUE(observer.StateEquals(0, state));
// And verify the state didn't change.
- EXPECT_EQ("2a 1a 3", GetPinnedState(tabstrip));
+ EXPECT_EQ("2ap 1ap 3", GetPinnedState(tabstrip));
observer.ClearStates();
}
@@ -1606,7 +1614,7 @@ TEST_F(TabStripModelTest, Apps) {
EXPECT_TRUE(observer.StateEquals(0, state));
// And verify the state didn't change.
- EXPECT_EQ("2a 1a 3", GetPinnedState(tabstrip));
+ EXPECT_EQ("2ap 1ap 3", GetPinnedState(tabstrip));
observer.ClearStates();
}
@@ -1932,3 +1940,56 @@ TEST_F(TabStripModelTest, DeletePhantomTabContents) {
// And there should have been no methods sent to the TabStripModelObserver.
EXPECT_EQ(0, tabstrip_observer.GetStateCount());
}
+
+// Makes sure the TabStripModel calls the right observer methods during a
+// replace.
+TEST_F(TabStripModelTest, ReplaceSendsSelected) {
+ typedef MockTabStripModelObserver::State State;
+
+ TabStripDummyDelegate delegate(NULL);
+ TabStripModel strip(&delegate, profile());
+
+ TabContents* first_contents = CreateTabContents();
+ strip.AddTabContents(first_contents, -1, PageTransition::TYPED,
+ TabStripModel::ADD_SELECTED);
+
+ MockTabStripModelObserver tabstrip_observer;
+ strip.AddObserver(&tabstrip_observer);
+
+ TabContents* new_contents = CreateTabContents();
+ strip.ReplaceTabContentsAt(0, new_contents,
+ TabStripModelObserver::REPLACE_MATCH_PREVIEW);
+
+ ASSERT_EQ(2, tabstrip_observer.GetStateCount());
+
+ // First event should be for replaced.
+ State state(new_contents, 0, MockTabStripModelObserver::REPLACED);
+ state.src_contents = first_contents;
+ EXPECT_TRUE(tabstrip_observer.StateEquals(0, state));
+
+ // And the second for selected.
+ state = State(new_contents, 0, MockTabStripModelObserver::SELECT);
+ state.src_contents = first_contents;
+ EXPECT_TRUE(tabstrip_observer.StateEquals(1, state));
+
+ // Now add another tab and replace it, making sure we don't get a selected
+ // event this time.
+ TabContents* third_contents = CreateTabContents();
+ strip.AddTabContents(third_contents, 1, PageTransition::TYPED,
+ TabStripModel::ADD_NONE);
+
+ tabstrip_observer.ClearStates();
+
+ // And replace it.
+ new_contents = CreateTabContents();
+ strip.ReplaceTabContentsAt(1, new_contents,
+ TabStripModelObserver::REPLACE_MATCH_PREVIEW);
+
+ ASSERT_EQ(1, tabstrip_observer.GetStateCount());
+
+ state = State(new_contents, 1, MockTabStripModelObserver::REPLACED);
+ state.src_contents = third_contents;
+ EXPECT_TRUE(tabstrip_observer.StateEquals(0, state));
+
+ strip.CloseAllTabs();
+}
diff --git a/chrome/browser/task_manager.cc b/chrome/browser/task_manager.cc
deleted file mode 100644
index 1ac1410..0000000
--- a/chrome/browser/task_manager.cc
+++ /dev/null
@@ -1,981 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/task_manager.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/compiler_specific.h"
-#include "base/i18n/number_formatting.h"
-#include "base/i18n/rtl.h"
-#include "base/process_util.h"
-#include "base/string_util.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/chrome_thread.h"
-#include "chrome/browser/net/url_request_tracking.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/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_resource_providers.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "grit/app_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_job.h"
-#include "unicode/coll.h"
-
-#if defined(OS_MACOSX)
-#include "chrome/browser/mach_broker_mac.h"
-#endif
-
-namespace {
-
-// The delay between updates of the information (in ms).
-#if defined(OS_MACOSX)
-// Match Activity Monitor's default refresh rate.
-const int kUpdateTimeMs = 2000;
-#else
-const int kUpdateTimeMs = 1000;
-#endif
-
-template <class T>
-int ValueCompare(T value1, T value2) {
- if (value1 < value2)
- return -1;
- if (value1 == value2)
- return 0;
- return 1;
-}
-
-std::wstring FormatStatsSize(const WebKit::WebCache::ResourceTypeStat& stat) {
- return l10n_util::GetStringF(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
- FormatBytes(stat.size, DATA_UNITS_KIBIBYTE, false),
- FormatBytes(stat.liveSize, DATA_UNITS_KIBIBYTE, false));
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerModel class
-////////////////////////////////////////////////////////////////////////////////
-
-TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
- : update_state_(IDLE),
- goat_salt_(rand()) {
-
- TaskManagerBrowserProcessResourceProvider* browser_provider =
- new TaskManagerBrowserProcessResourceProvider(task_manager);
- browser_provider->AddRef();
- providers_.push_back(browser_provider);
- TaskManagerTabContentsResourceProvider* wc_provider =
- new TaskManagerTabContentsResourceProvider(task_manager);
- wc_provider->AddRef();
- providers_.push_back(wc_provider);
- TaskManagerChildProcessResourceProvider* child_process_provider =
- new TaskManagerChildProcessResourceProvider(task_manager);
- child_process_provider->AddRef();
- providers_.push_back(child_process_provider);
- TaskManagerExtensionProcessResourceProvider* extension_process_provider =
- new TaskManagerExtensionProcessResourceProvider(task_manager);
- extension_process_provider->AddRef();
- providers_.push_back(extension_process_provider);
- TaskManagerNotificationResourceProvider* notification_provider =
- new TaskManagerNotificationResourceProvider(task_manager);
- notification_provider->AddRef();
- providers_.push_back(notification_provider);
-}
-
-TaskManagerModel::~TaskManagerModel() {
- for (ResourceProviderList::iterator iter = providers_.begin();
- iter != providers_.end(); ++iter) {
- (*iter)->Release();
- }
-}
-
-int TaskManagerModel::ResourceCount() const {
- return resources_.size();
-}
-
-void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
- observer_list_.AddObserver(observer);
-}
-
-void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
- observer_list_.RemoveObserver(observer);
-}
-
-std::wstring TaskManagerModel::GetResourceTitle(int index) const {
- DCHECK(index < ResourceCount());
- return resources_[index]->GetTitle();
-}
-
-std::wstring TaskManagerModel::GetResourceNetworkUsage(int index) const {
- DCHECK(index < ResourceCount());
- int64 net_usage = GetNetworkUsage(resources_[index]);
- if (net_usage == -1)
- return l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT);
- if (net_usage == 0)
- return std::wstring(L"0");
- std::wstring net_byte =
- FormatSpeed(net_usage, GetByteDisplayUnits(net_usage), true);
- // Force number string to have LTR directionality.
- base::i18n::GetDisplayStringInLTRDirectionality(&net_byte);
- return net_byte;
-}
-
-std::wstring TaskManagerModel::GetResourceCPUUsage(int index) const {
- DCHECK(index < ResourceCount());
- return StringPrintf(
-#if defined(OS_MACOSX)
- // Activity Monitor shows %cpu with one decimal digit -- be
- // consistent with that.
- L"%.1f",
-#else
- L"%.0f",
-#endif
- GetCPUUsage(resources_[index]));
-}
-
-std::wstring TaskManagerModel::GetResourcePrivateMemory(int index) const {
- size_t private_mem;
- if (!GetPrivateMemory(index, &private_mem))
- return L"N/A";
- return GetMemCellText(private_mem);
-}
-
-std::wstring TaskManagerModel::GetResourceSharedMemory(int index) const {
- size_t shared_mem;
- if (!GetSharedMemory(index, &shared_mem))
- return L"N/A";
- return GetMemCellText(shared_mem);
-}
-
-std::wstring TaskManagerModel::GetResourcePhysicalMemory(int index) const {
- size_t phys_mem;
- GetPhysicalMemory(index, &phys_mem);
- return GetMemCellText(phys_mem);
-}
-
-std::wstring TaskManagerModel::GetResourceProcessId(int index) const {
- DCHECK(index < ResourceCount());
- return IntToWString(base::GetProcId(resources_[index]->GetProcess()));
-}
-
-std::wstring TaskManagerModel::GetResourceGoatsTeleported(int index) const {
- DCHECK(index < ResourceCount());
- return UTF16ToWide(base::FormatNumber(GetGoatsTeleported(index)));
-}
-
-std::wstring TaskManagerModel::GetResourceWebCoreImageCacheSize(
- int index) const {
- DCHECK(index < ResourceCount());
- if (!resources_[index]->ReportsCacheStats())
- return l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT);
- const WebKit::WebCache::ResourceTypeStats stats(
- resources_[index]->GetWebCoreCacheStats());
- return FormatStatsSize(stats.images);
-}
-
-std::wstring TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
- int index) const {
- DCHECK(index < ResourceCount());
- if (!resources_[index]->ReportsCacheStats())
- return l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT);
- const WebKit::WebCache::ResourceTypeStats stats(
- resources_[index]->GetWebCoreCacheStats());
- return FormatStatsSize(stats.scripts);
-}
-
-std::wstring TaskManagerModel::GetResourceWebCoreCSSCacheSize(
- int index) const {
- DCHECK(index < ResourceCount());
- if (!resources_[index]->ReportsCacheStats())
- return l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT);
- const WebKit::WebCache::ResourceTypeStats stats(
- resources_[index]->GetWebCoreCacheStats());
- return FormatStatsSize(stats.cssStyleSheets);
-}
-
-std::wstring TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
- DCHECK(index < ResourceCount());
- if (!resources_[index]->ReportsSqliteMemoryUsed())
- return l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT);
- return GetMemCellText(resources_[index]->SqliteMemoryUsedBytes());
-}
-
-std::wstring TaskManagerModel::GetResourceV8MemoryAllocatedSize(
- int index) const {
- if (!resources_[index]->ReportsV8MemoryStats())
- return l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT);
- return l10n_util::GetStringF(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
- FormatBytes(resources_[index]->GetV8MemoryAllocated(),
- DATA_UNITS_KIBIBYTE,
- false),
- FormatBytes(resources_[index]->GetV8MemoryUsed(),
- DATA_UNITS_KIBIBYTE,
- false));
-}
-
-bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
- DCHECK(index < ResourceCount());
- TaskManager::Resource* resource = resources_[index];
- GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
- DCHECK(iter != group_map_.end());
- const ResourceList* group = iter->second;
- return ((*group)[0] == resource);
-}
-
-SkBitmap TaskManagerModel::GetResourceIcon(int index) const {
- DCHECK(index < ResourceCount());
- SkBitmap icon = resources_[index]->GetIcon();
- if (!icon.isNull())
- return icon;
-
- static SkBitmap* default_icon = ResourceBundle::GetSharedInstance().
- GetBitmapNamed(IDR_DEFAULT_FAVICON);
- return *default_icon;
-}
-
-std::pair<int, int> TaskManagerModel::GetGroupRangeForResource(int index)
- const {
- DCHECK(index < ResourceCount());
- TaskManager::Resource* resource = resources_[index];
- GroupMap::const_iterator group_iter =
- group_map_.find(resource->GetProcess());
- DCHECK(group_iter != group_map_.end());
- ResourceList* group = group_iter->second;
- DCHECK(group);
- if (group->size() == 1) {
- return std::make_pair(index, 1);
- } else {
- for (int i = index; i >= 0; --i) {
- if (resources_[i] == (*group)[0])
- return std::make_pair(i, group->size());
- }
- NOTREACHED();
- return std::make_pair(-1, -1);
- }
-}
-
-int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
- DCHECK(row1 < ResourceCount() && row2 < ResourceCount());
- switch (col_id) {
- case IDS_TASK_MANAGER_PAGE_COLUMN: {
- // Let's do the default, string compare on the resource title.
- static icu::Collator* collator = NULL;
- if (!collator) {
- UErrorCode create_status = U_ZERO_ERROR;
- collator = icu::Collator::createInstance(create_status);
- if (!U_SUCCESS(create_status)) {
- collator = NULL;
- NOTREACHED();
- }
- }
- string16 title1 = WideToUTF16(GetResourceTitle(row1));
- string16 title2 = WideToUTF16(GetResourceTitle(row2));
- UErrorCode compare_status = U_ZERO_ERROR;
- UCollationResult compare_result = collator->compare(
- static_cast<const UChar*>(title1.c_str()),
- static_cast<int>(title1.length()),
- static_cast<const UChar*>(title2.c_str()),
- static_cast<int>(title2.length()),
- compare_status);
- DCHECK(U_SUCCESS(compare_status));
- return compare_result;
- }
-
- case IDS_TASK_MANAGER_NET_COLUMN:
- return ValueCompare<int64>(GetNetworkUsage(resources_[row1]),
- GetNetworkUsage(resources_[row2]));
-
- case IDS_TASK_MANAGER_CPU_COLUMN:
- return ValueCompare<double>(GetCPUUsage(resources_[row1]),
- GetCPUUsage(resources_[row2]));
-
- case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: {
- size_t value1;
- size_t value2;
- if (!GetPrivateMemory(row1, &value1) || !GetPrivateMemory(row2, &value2))
- return 0;
- return ValueCompare<size_t>(value1, value2);
- }
-
- case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: {
- size_t value1;
- size_t value2;
- if (!GetSharedMemory(row1, &value1) || !GetSharedMemory(row2, &value2))
- return 0;
- return ValueCompare<size_t>(value1, value2);
- }
-
- case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: {
- size_t value1;
- size_t value2;
- if (!GetPhysicalMemory(row1, &value1) ||
- !GetPhysicalMemory(row2, &value2))
- return 0;
- return ValueCompare<size_t>(value1, value2);
- }
-
- case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: {
- int proc1_id = base::GetProcId(resources_[row1]->GetProcess());
- int proc2_id = base::GetProcId(resources_[row2]->GetProcess());
- return ValueCompare<int>(proc1_id, proc2_id);
- }
-
- case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
- case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
- case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: {
- WebKit::WebCache::ResourceTypeStats stats1 = { { 0 } };
- WebKit::WebCache::ResourceTypeStats stats2 = { { 0 } };
- if (resources_[row1]->ReportsCacheStats())
- stats1 = resources_[row1]->GetWebCoreCacheStats();
- if (resources_[row2]->ReportsCacheStats())
- stats2 = resources_[row2]->GetWebCoreCacheStats();
- if (IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN == col_id)
- return ValueCompare<size_t>(stats1.images.size, stats2.images.size);
- if (IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN == col_id)
- return ValueCompare<size_t>(stats1.scripts.size, stats2.scripts.size);
- DCHECK_EQ(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, col_id);
- return ValueCompare<size_t>(stats1.cssStyleSheets.size,
- stats2.cssStyleSheets.size);
- }
-
- case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: {
- return ValueCompare<int>(GetGoatsTeleported(row1),
- GetGoatsTeleported(row2));
- }
-
- case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: {
- size_t value1;
- size_t value2;
- bool reports_v8_memory1 = GetV8Memory(row1, &value1);
- bool reports_v8_memory2 = GetV8Memory(row2, &value2);
- if (reports_v8_memory1 == reports_v8_memory2)
- return ValueCompare<size_t>(value1, value2);
- else
- return reports_v8_memory1 ? 1 : -1;
- }
-
- default:
- NOTREACHED();
- return 0;
- }
-}
-
-base::ProcessHandle TaskManagerModel::GetResourceProcessHandle(int index)
- const {
- DCHECK(index < ResourceCount());
- return resources_[index]->GetProcess();
-}
-
-TabContents* TaskManagerModel::GetResourceTabContents(int index) const {
- DCHECK(index < ResourceCount());
- return resources_[index]->GetTabContents();
-}
-
-const Extension* TaskManagerModel::GetResourceExtension(int index) const {
- DCHECK(index < ResourceCount());
- return resources_[index]->GetExtension();
-}
-
-int64 TaskManagerModel::GetNetworkUsage(TaskManager::Resource* resource)
- const {
- int64 net_usage = GetNetworkUsageForResource(resource);
- if (net_usage == 0 && !resource->SupportNetworkUsage())
- return -1;
- return net_usage;
-}
-
-double TaskManagerModel::GetCPUUsage(TaskManager::Resource* resource) const {
- CPUUsageMap::const_iterator iter =
- cpu_usage_map_.find(resource->GetProcess());
- if (iter == cpu_usage_map_.end())
- return 0;
- return iter->second;
-}
-
-bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
- base::ProcessHandle handle = resources_[index]->GetProcess();
- MemoryUsageMap::const_iterator iter = memory_usage_map_.find(handle);
- if (iter == memory_usage_map_.end()) {
- std::pair<size_t, size_t> usage;
- if (!GetAndCacheMemoryMetrics(handle, &usage))
- return false;
-
- *result = usage.first;
- } else {
- *result = iter->second.first;
- }
-
- return true;
-}
-
-bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
- base::ProcessHandle handle = resources_[index]->GetProcess();
- MemoryUsageMap::const_iterator iter = memory_usage_map_.find(handle);
- if (iter == memory_usage_map_.end()) {
- std::pair<size_t, size_t> usage;
- if (!GetAndCacheMemoryMetrics(handle, &usage))
- return false;
-
- *result = usage.second;
- } else {
- *result = iter->second.second;
- }
-
- return true;
-}
-
-bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
- *result = 0;
- base::ProcessMetrics* process_metrics;
- if (!GetProcessMetricsForRow(index, &process_metrics))
- return false;
- base::WorkingSetKBytes ws_usage;
- if (!process_metrics->GetWorkingSetKBytes(&ws_usage))
- return false;
-
- // Memory = working_set.private + working_set.shareable.
- // We exclude the shared memory.
- size_t total_bytes = process_metrics->GetWorkingSetSize();
- total_bytes -= ws_usage.shared * 1024;
- *result = total_bytes;
- return true;
-}
-
-bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
- *result = 0;
- if (!resources_[index]->ReportsV8MemoryStats())
- return false;
-
- *result = resources_[index]->GetV8MemoryAllocated();
- return true;
-}
-
-int TaskManagerModel::GetGoatsTeleported(int index) const {
- int seed = goat_salt_ * (index + 1);
- return (seed >> 16) & 255;
-}
-
-std::wstring TaskManagerModel::GetMemCellText(int64 number) const {
-#if !defined(OS_MACOSX)
- std::wstring str = UTF16ToWide(base::FormatNumber(number / 1024));
-
- // Adjust number string if necessary.
- base::i18n::AdjustStringForLocaleDirection(str, &str);
- return l10n_util::GetStringF(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
-#else
- // System expectation is to show "100 KB", "200 MB", etc.
- // TODO(thakis): Switch to metric units (as opposed to powers of two).
- return FormatBytes(
- number, GetByteDisplayUnits(number), /* show_units=*/true);
-#endif
-}
-
-void TaskManagerModel::StartUpdating() {
- DCHECK_NE(TASK_PENDING, update_state_);
-
- // If update_state_ is STOPPING, it means a task is still pending. Setting
- // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
- if (update_state_ == IDLE) {
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- NewRunnableMethod(this, &TaskManagerModel::Refresh),
- kUpdateTimeMs);
- }
- update_state_ = TASK_PENDING;
-
- // Register jobs notifications so we can compute network usage (it must be
- // done from the IO thread).
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &TaskManagerModel::RegisterForJobDoneNotifications));
-
- // Notify resource providers that we are updating.
- for (ResourceProviderList::iterator iter = providers_.begin();
- iter != providers_.end(); ++iter) {
- (*iter)->StartUpdating();
- }
-}
-
-void TaskManagerModel::StopUpdating() {
- DCHECK_EQ(TASK_PENDING, update_state_);
- update_state_ = STOPPING;
-
- // Notify resource providers that we are done updating.
- for (ResourceProviderList::const_iterator iter = providers_.begin();
- iter != providers_.end(); ++iter) {
- (*iter)->StopUpdating();
- }
-
- // Unregister jobs notification (must be done from the IO thread).
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &TaskManagerModel::UnregisterForJobDoneNotifications));
-}
-
-void TaskManagerModel::AddResourceProvider(
- TaskManager::ResourceProvider* provider) {
- DCHECK(provider);
- providers_.push_back(provider);
-}
-
-void TaskManagerModel::RemoveResourceProvider(
- TaskManager::ResourceProvider* provider) {
- DCHECK(provider);
- ResourceProviderList::iterator iter = std::find(providers_.begin(),
- providers_.end(),
- provider);
- DCHECK(iter != providers_.end());
- providers_.erase(iter);
-}
-
-void TaskManagerModel::RegisterForJobDoneNotifications() {
- g_url_request_job_tracker.AddObserver(this);
-}
-
-void TaskManagerModel::UnregisterForJobDoneNotifications() {
- g_url_request_job_tracker.RemoveObserver(this);
-}
-
-void TaskManagerModel::AddResource(TaskManager::Resource* resource) {
- base::ProcessHandle process = resource->GetProcess();
-
- ResourceList* group_entries = NULL;
- GroupMap::const_iterator group_iter = group_map_.find(process);
- int new_entry_index = 0;
- if (group_iter == group_map_.end()) {
- group_entries = new ResourceList();
- group_map_[process] = group_entries;
- group_entries->push_back(resource);
-
- // Not part of a group, just put at the end of the list.
- resources_.push_back(resource);
- new_entry_index = static_cast<int>(resources_.size() - 1);
- } else {
- group_entries = group_iter->second;
- group_entries->push_back(resource);
-
- // Insert the new entry right after the last entry of its group.
- ResourceList::iterator iter =
- std::find(resources_.begin(),
- resources_.end(),
- (*group_entries)[group_entries->size() - 2]);
- DCHECK(iter != resources_.end());
- new_entry_index = static_cast<int>(iter - resources_.begin());
- resources_.insert(++iter, resource);
- }
-
- // Create the ProcessMetrics for this process if needed (not in map).
- if (metrics_map_.find(process) == metrics_map_.end()) {
- base::ProcessMetrics* pm =
-#if !defined(OS_MACOSX)
- base::ProcessMetrics::CreateProcessMetrics(process);
-#else
- base::ProcessMetrics::CreateProcessMetrics(process,
- MachBroker::instance());
-#endif
-
- metrics_map_[process] = pm;
- }
-
- // Notify the table that the contents have changed for it to redraw.
- FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
- OnItemsAdded(new_entry_index, 1));
-}
-
-void TaskManagerModel::RemoveResource(TaskManager::Resource* resource) {
- base::ProcessHandle process = resource->GetProcess();
-
- // Find the associated group.
- GroupMap::iterator group_iter = group_map_.find(process);
- DCHECK(group_iter != group_map_.end());
- ResourceList* group_entries = group_iter->second;
-
- // Remove the entry from the group map.
- ResourceList::iterator iter = std::find(group_entries->begin(),
- group_entries->end(),
- resource);
- DCHECK(iter != group_entries->end());
- group_entries->erase(iter);
-
- // If there are no more entries for that process, do the clean-up.
- if (group_entries->empty()) {
- delete group_entries;
- group_map_.erase(process);
-
- // Nobody is using this process, we don't need the process metrics anymore.
- MetricsMap::iterator pm_iter = metrics_map_.find(process);
- DCHECK(pm_iter != metrics_map_.end());
- if (pm_iter != metrics_map_.end()) {
- delete pm_iter->second;
- metrics_map_.erase(process);
- }
- // And we don't need the CPU usage anymore either.
- CPUUsageMap::iterator cpu_iter = cpu_usage_map_.find(process);
- if (cpu_iter != cpu_usage_map_.end())
- cpu_usage_map_.erase(cpu_iter);
- }
-
- // Remove the entry from the model list.
- iter = std::find(resources_.begin(), resources_.end(), resource);
- DCHECK(iter != resources_.end());
- int index = static_cast<int>(iter - resources_.begin());
- resources_.erase(iter);
-
- // Remove the entry from the network maps.
- ResourceValueMap::iterator net_iter =
- current_byte_count_map_.find(resource);
- if (net_iter != current_byte_count_map_.end())
- current_byte_count_map_.erase(net_iter);
- net_iter = displayed_network_usage_map_.find(resource);
- if (net_iter != displayed_network_usage_map_.end())
- displayed_network_usage_map_.erase(net_iter);
-
- // Notify the table that the contents have changed.
- FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
- OnItemsRemoved(index, 1));
-}
-
-void TaskManagerModel::Clear() {
- int size = ResourceCount();
- if (size > 0) {
- resources_.clear();
-
- // Clear the groups.
- for (GroupMap::iterator iter = group_map_.begin();
- iter != group_map_.end(); ++iter) {
- delete iter->second;
- }
- group_map_.clear();
-
- // Clear the process related info.
- for (MetricsMap::iterator iter = metrics_map_.begin();
- iter != metrics_map_.end(); ++iter) {
- delete iter->second;
- }
- metrics_map_.clear();
- cpu_usage_map_.clear();
-
- // Clear the network maps.
- current_byte_count_map_.clear();
- displayed_network_usage_map_.clear();
-
- FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
- OnItemsRemoved(0, size));
- }
-}
-
-void TaskManagerModel::NotifyResourceTypeStats(
- base::ProcessId renderer_id,
- const WebKit::WebCache::ResourceTypeStats& stats) {
- for (ResourceList::iterator it = resources_.begin();
- it != resources_.end(); ++it) {
- if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
- (*it)->NotifyResourceTypeStats(stats);
- }
- }
-}
-
-void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id,
- size_t v8_memory_allocated,
- size_t v8_memory_used) {
- for (ResourceList::iterator it = resources_.begin();
- it != resources_.end(); ++it) {
- if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
- (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used);
- }
- }
-}
-
-void TaskManagerModel::Refresh() {
- DCHECK_NE(IDLE, update_state_);
-
- if (update_state_ == STOPPING) {
- // We have been asked to stop.
- update_state_ = IDLE;
- return;
- }
-
- goat_salt_ = rand();
-
- // Compute the CPU usage values.
- // Note that we compute the CPU usage for all resources (instead of doing it
- // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
- // time it was called, and not calling it everytime would skew the value the
- // next time it is retrieved (as it would be for more than 1 cycle).
- cpu_usage_map_.clear();
- for (ResourceList::iterator iter = resources_.begin();
- iter != resources_.end(); ++iter) {
- base::ProcessHandle process = (*iter)->GetProcess();
- CPUUsageMap::iterator cpu_iter = cpu_usage_map_.find(process);
- if (cpu_iter != cpu_usage_map_.end())
- continue; // Already computed.
-
- MetricsMap::iterator metrics_iter = metrics_map_.find(process);
- DCHECK(metrics_iter != metrics_map_.end());
- cpu_usage_map_[process] = metrics_iter->second->GetCPUUsage();
- }
-
- // Clear the memory values so they can be querried lazily.
- memory_usage_map_.clear();
-
- // Compute the new network usage values.
- displayed_network_usage_map_.clear();
- for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
- iter != current_byte_count_map_.end(); ++iter) {
- if (kUpdateTimeMs > 1000) {
- int divider = (kUpdateTimeMs / 1000);
- displayed_network_usage_map_[iter->first] = iter->second / divider;
- } else {
- displayed_network_usage_map_[iter->first] = iter->second *
- (1000 / kUpdateTimeMs);
- }
-
- // Then we reset the current byte count.
- iter->second = 0;
- }
-
- // Let resources update themselves if they need to.
- for (ResourceList::iterator iter = resources_.begin();
- iter != resources_.end(); ++iter) {
- (*iter)->Refresh();
- }
-
- if (!resources_.empty()) {
- FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
- OnItemsChanged(0, ResourceCount()));
- }
-
- // Schedule the next update.
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- NewRunnableMethod(this, &TaskManagerModel::Refresh),
- kUpdateTimeMs);
-}
-
-int64 TaskManagerModel::GetNetworkUsageForResource(
- TaskManager::Resource* resource) const {
- ResourceValueMap::const_iterator iter =
- displayed_network_usage_map_.find(resource);
- if (iter == displayed_network_usage_map_.end())
- return 0;
- return iter->second;
-}
-
-void TaskManagerModel::BytesRead(BytesReadParam param) {
- if (update_state_ != TASK_PENDING) {
- // A notification sneaked in while we were stopping the updating, just
- // ignore it.
- return;
- }
-
- if (param.byte_count == 0) {
- // Nothing to do if no bytes were actually read.
- return;
- }
-
- // TODO(jcampan): this should be improved once we have a better way of
- // linking a network notification back to the object that initiated it.
- TaskManager::Resource* resource = NULL;
- for (ResourceProviderList::iterator iter = providers_.begin();
- iter != providers_.end(); ++iter) {
- resource = (*iter)->GetResource(param.origin_child_id,
- param.render_process_host_child_id,
- param.routing_id);
- if (resource)
- break;
- }
- if (resource == NULL) {
- // We may not have that resource anymore (example: close a tab while a
- // a network resource is being retrieved), in which case we just ignore the
- // notification.
- return;
- }
-
- // We do support network usage, mark the resource as such so it can report 0
- // instead of N/A.
- if (!resource->SupportNetworkUsage())
- resource->SetSupportNetworkUsage();
-
- ResourceValueMap::const_iterator iter_res =
- current_byte_count_map_.find(resource);
- if (iter_res == current_byte_count_map_.end())
- current_byte_count_map_[resource] = param.byte_count;
- else
- current_byte_count_map_[resource] = iter_res->second + param.byte_count;
-}
-
-
-// In order to retrieve the network usage, we register for 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::OnJobRemoved(URLRequestJob* job) {
-}
-
-void TaskManagerModel::OnJobDone(URLRequestJob* job,
- const URLRequestStatus& status) {
-}
-
-void TaskManagerModel::OnJobRedirect(URLRequestJob* job,
- const GURL& location,
- int status_code) {
-}
-
-void TaskManagerModel::OnBytesRead(URLRequestJob* job, const char* buf,
- int byte_count) {
- int render_process_host_child_id = -1, routing_id = -1;
- ResourceDispatcherHost::RenderViewForRequest(job->request(),
- &render_process_host_child_id,
- &routing_id);
- // This happens in the IO thread, post it to the UI thread.
- int origin_child_id =
- chrome_browser_net::GetOriginProcessUniqueIDForRequest(job->request());
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- this,
- &TaskManagerModel::BytesRead,
- BytesReadParam(origin_child_id,
- render_process_host_child_id,
- routing_id, byte_count)));
-}
-
-bool TaskManagerModel::GetProcessMetricsForRow(
- int row, base::ProcessMetrics** proc_metrics) const {
- DCHECK(row < ResourceCount());
- *proc_metrics = NULL;
-
- MetricsMap::const_iterator iter =
- metrics_map_.find(resources_[row]->GetProcess());
- if (iter == metrics_map_.end())
- return false;
- *proc_metrics = iter->second;
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManager class
-////////////////////////////////////////////////////////////////////////////////
-
-// static
-void TaskManager::RegisterPrefs(PrefService* prefs) {
- prefs->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
-}
-
-TaskManager::TaskManager()
- : ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TaskManagerModel(this))) {
-}
-
-TaskManager::~TaskManager() {
-}
-
-bool TaskManager::IsBrowserProcess(int index) const {
- // If some of the selection is out of bounds, ignore. This may happen when
- // killing a process that manages several pages.
- return index < model_->ResourceCount() &&
- model_->GetResourceProcessHandle(index) ==
- base::GetCurrentProcessHandle();
-}
-
-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);
-}
-
-void TaskManager::ActivateProcess(int index) {
- // GetResourceTabContents returns a pointer to the relevant tab contents for
- // the resource. If the index doesn't correspond to a Tab (i.e. refers to
- // the Browser process or a plugin), GetTabContents will return NULL.
- TabContents* chosen_tab_contents = model_->GetResourceTabContents(index);
- if (chosen_tab_contents)
- chosen_tab_contents->Activate();
-}
-
-void TaskManager::AddResourceProvider(ResourceProvider* provider) {
- model_->AddResourceProvider(provider);
-}
-
-void TaskManager::RemoveResourceProvider(ResourceProvider* provider) {
- model_->RemoveResourceProvider(provider);
-}
-
-void TaskManager::AddResource(Resource* resource) {
- model_->AddResource(resource);
-}
-
-void TaskManager::RemoveResource(Resource* resource) {
- model_->RemoveResource(resource);
-}
-
-void TaskManager::OnWindowClosed() {
- model_->StopUpdating();
- model_->Clear();
-}
-
-// static
-TaskManager* TaskManager::GetInstance() {
- return Singleton<TaskManager>::get();
-}
-
-void TaskManager::OpenAboutMemory() {
- Browser* browser = BrowserList::GetLastActive();
-
- if (!browser) {
- // On OS X, the task manager can be open without any open browser windows.
- if (!g_browser_process ||
- !g_browser_process->profile_manager() ||
- g_browser_process->profile_manager()->begin() ==
- g_browser_process->profile_manager()->end())
- return;
- browser = Browser::Create(*g_browser_process->profile_manager()->begin());
- browser->OpenURL(GURL(chrome::kAboutMemoryURL), GURL(), NEW_WINDOW,
- PageTransition::LINK);
- } else {
- browser->OpenURL(GURL(chrome::kAboutMemoryURL), GURL(), NEW_FOREGROUND_TAB,
- PageTransition::LINK);
-
- // In case the browser window is minimzed, show it. If |browser| is a
- // non-tabbed window, the call to OpenURL above will have opened a
- // TabContents in a tabbed browser, so we need to grab it with GetLastActive
- // before the call to show().
- if (browser->type() & (Browser::TYPE_APP |
- Browser::TYPE_APP_PANEL |
- Browser::TYPE_DEVTOOLS |
- Browser::TYPE_POPUP)) {
- browser = BrowserList::GetLastActive();
- DCHECK(browser);
- }
-
- browser->window()->Show();
- }
-}
-
-bool TaskManagerModel::GetAndCacheMemoryMetrics(
- base::ProcessHandle handle,
- std::pair<size_t, size_t>* usage) const {
- MetricsMap::const_iterator iter = metrics_map_.find(handle);
- if (iter == metrics_map_.end())
- return false;
-
- if (!iter->second->GetMemoryBytes(&usage->first, &usage->second))
- return false;
-
- memory_usage_map_.insert(std::make_pair(handle, *usage));
- return true;
-}
diff --git a/chrome/browser/task_manager.h b/chrome/browser/task_manager.h
deleted file mode 100644
index 9d84c4c..0000000
--- a/chrome/browser/task_manager.h
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_TASK_MANAGER_H_
-#define CHROME_BROWSER_TASK_MANAGER_H_
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/lock.h"
-#include "base/observer_list.h"
-#include "base/process_util.h"
-#include "base/ref_counted.h"
-#include "base/singleton.h"
-#include "base/timer.h"
-#include "chrome/browser/renderer_host/web_cache_manager.h"
-#include "net/url_request/url_request_job_tracker.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
-
-class Extension;
-class SkBitmap;
-class TabContents;
-class TaskManager;
-class TaskManagerModel;
-
-struct BytesReadParam;
-
-namespace base {
-class ProcessMetrics;
-}
-
-// This class is a singleton.
-class TaskManager {
- public:
- // A resource represents one row in the task manager.
- // Resources from similar processes are grouped together by the task manager.
- class Resource {
- public:
- virtual ~Resource() {}
-
- virtual std::wstring GetTitle() const = 0;
- virtual SkBitmap GetIcon() const = 0;
- virtual base::ProcessHandle GetProcess() const = 0;
-
- virtual bool ReportsCacheStats() const { return false; }
- virtual WebKit::WebCache::ResourceTypeStats GetWebCoreCacheStats() const {
- return WebKit::WebCache::ResourceTypeStats();
- }
-
- virtual bool ReportsSqliteMemoryUsed() const { return false; }
- virtual size_t SqliteMemoryUsedBytes() const { return 0; }
-
- // Return extension associated with the resource, or NULL
- // if not applicable.
- virtual const Extension* GetExtension() const { return NULL; }
-
- virtual bool ReportsV8MemoryStats() const { return false; }
- virtual size_t GetV8MemoryAllocated() const { return 0; }
- virtual size_t GetV8MemoryUsed() const { return 0; }
-
- // A helper function for ActivateFocusedTab. Returns NULL by default
- // because not all resources have an associated tab.
- virtual TabContents* GetTabContents() const { return NULL; }
-
- // Whether this resource does report the network usage accurately.
- // This controls whether 0 or N/A is displayed when no bytes have been
- // reported as being read. This is because some plugins do not report the
- // bytes read and we don't want to display a misleading 0 value in that
- // case.
- virtual bool SupportNetworkUsage() const = 0;
-
- // Called when some bytes have been read and support_network_usage returns
- // false (meaning we do have network usage support).
- virtual void SetSupportNetworkUsage() = 0;
-
- // The TaskManagerModel periodically refreshes its data and call this
- // on all live resources.
- virtual void Refresh() {}
-
- virtual void NotifyResourceTypeStats(
- const WebKit::WebCache::ResourceTypeStats& stats) {}
- virtual void NotifyV8HeapStats(size_t v8_memory_allocated,
- size_t v8_memory_used) {}
- };
-
- // ResourceProviders are responsible for adding/removing resources to the task
- // manager. The task manager notifies the ResourceProvider that it is ready
- // to receive resource creation/termination notifications with a call to
- // StartUpdating(). At that point, the resource provider should call
- // AddResource with all the existing resources, and after that it should call
- // AddResource/RemoveResource as resources are created/terminated.
- // The provider remains the owner of the resource objects and is responsible
- // for deleting them (when StopUpdating() is called).
- // After StopUpdating() is called the provider should also stop reporting
- // notifications to the task manager.
- // Note: ResourceProviders have to be ref counted as they are used in
- // MessageLoop::InvokeLater().
- class ResourceProvider : public base::RefCountedThreadSafe<ResourceProvider> {
- public:
- // Should return the resource associated to the specified ids, or NULL if
- // the resource does not belong to this provider.
- virtual TaskManager::Resource* GetResource(int process_id,
- int render_process_host_id,
- int routing_id) = 0;
- virtual void StartUpdating() = 0;
- virtual void StopUpdating() = 0;
-
- protected:
- friend class base::RefCountedThreadSafe<ResourceProvider>;
-
- virtual ~ResourceProvider() {}
- };
-
- static void RegisterPrefs(PrefService* prefs);
-
- // Returns true if the process at the specified index is the browser process.
- bool IsBrowserProcess(int index) const;
-
- // Terminates the process at the specified index.
- void KillProcess(int index);
-
- // Activates the browser tab associated with the process in the specified
- // index.
- void ActivateProcess(int index);
-
- void AddResourceProvider(ResourceProvider* provider);
- void RemoveResourceProvider(ResourceProvider* provider);
-
- // These methods are invoked by the resource providers to add/remove resources
- // to the Task Manager. Note that the resources are owned by the
- // ResourceProviders and are not valid after StopUpdating() has been called
- // on the ResourceProviders.
- void AddResource(Resource* resource);
- void RemoveResource(Resource* resource);
-
- void OnWindowClosed();
-
- // Returns the singleton instance (and initializes it if necessary).
- static TaskManager* GetInstance();
-
- TaskManagerModel* model() const { return model_.get(); }
-
- void OpenAboutMemory();
-
- private:
- FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, Basic);
- FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, Resources);
- FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, RefreshCalled);
-
- // Obtain an instance via GetInstance().
- TaskManager();
- friend struct DefaultSingletonTraits<TaskManager>;
-
- ~TaskManager();
-
- // The model used for gathering and processing task data. It is ref counted
- // because it is passed as a parameter to MessageLoop::InvokeLater().
- scoped_refptr<TaskManagerModel> model_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManager);
-};
-
-class TaskManagerModelObserver {
- public:
- virtual ~TaskManagerModelObserver() {}
-
- // Invoked when the model has been completely changed.
- virtual void OnModelChanged() = 0;
-
- // Invoked when a range of items has changed.
- virtual void OnItemsChanged(int start, int length) = 0;
-
- // Invoked when new items are added.
- virtual void OnItemsAdded(int start, int length) = 0;
-
- // Invoked when a range of items has been removed.
- virtual void OnItemsRemoved(int start, int length) = 0;
-};
-
-// The model that the TaskManager is using.
-class TaskManagerModel : public URLRequestJobTracker::JobObserver,
- public base::RefCountedThreadSafe<TaskManagerModel> {
- public:
- explicit TaskManagerModel(TaskManager* task_manager);
-
- void AddObserver(TaskManagerModelObserver* observer);
- void RemoveObserver(TaskManagerModelObserver* observer);
-
- // Returns number of registered resources.
- int ResourceCount() const;
-
- // Methods to return formatted resource information.
- std::wstring GetResourceTitle(int index) const;
- std::wstring GetResourceNetworkUsage(int index) const;
- std::wstring GetResourceCPUUsage(int index) const;
- std::wstring GetResourcePrivateMemory(int index) const;
- std::wstring GetResourceSharedMemory(int index) const;
- std::wstring GetResourcePhysicalMemory(int index) const;
- std::wstring GetResourceProcessId(int index) const;
- std::wstring GetResourceWebCoreImageCacheSize(int index) const;
- std::wstring GetResourceWebCoreScriptsCacheSize(int index) const;
- std::wstring GetResourceWebCoreCSSCacheSize(int index) const;
- std::wstring GetResourceSqliteMemoryUsed(int index) const;
- std::wstring GetResourceGoatsTeleported(int index) const;
- std::wstring GetResourceV8MemoryAllocatedSize(int index) const;
-
- // Returns true if the resource is first in its group (resources
- // rendered by the same process are groupped together).
- bool IsResourceFirstInGroup(int index) const;
-
- // Returns icon to be used for resource (for example a favicon).
- SkBitmap GetResourceIcon(int index) const;
-
- // Returns a pair (start, length) of the group range of resource.
- std::pair<int, int> GetGroupRangeForResource(int index) const;
-
- // Compares values in column |col_id| and rows |row1|, |row2|.
- // Returns -1 if value in |row1| is less than value in |row2|,
- // 0 if they are equal, and 1 otherwise.
- int CompareValues(int row1, int row2, int col_id) const;
-
- // Returns process handle for given resource.
- base::ProcessHandle GetResourceProcessHandle(int index) const;
-
- // Returns TabContents of given resource or NULL if not applicable.
- TabContents* GetResourceTabContents(int index) const;
-
- // Returns Extension of given resource or NULL if not applicable.
- const Extension* GetResourceExtension(int index) const;
-
- // JobObserver methods:
- void OnJobAdded(URLRequestJob* job);
- void OnJobRemoved(URLRequestJob* job);
- void OnJobDone(URLRequestJob* job, const URLRequestStatus& status);
- void OnJobRedirect(URLRequestJob* job, const GURL& location, int status_code);
- void OnBytesRead(URLRequestJob* job, const char* buf, int byte_count);
-
- void AddResourceProvider(TaskManager::ResourceProvider* provider);
- void RemoveResourceProvider(TaskManager::ResourceProvider* provider);
-
- void AddResource(TaskManager::Resource* resource);
- void RemoveResource(TaskManager::Resource* resource);
-
- void StartUpdating();
- void StopUpdating();
-
- void Clear(); // Removes all items.
-
- void NotifyResourceTypeStats(
- base::ProcessId renderer_id,
- const WebKit::WebCache::ResourceTypeStats& stats);
-
- void NotifyV8HeapStats(base::ProcessId renderer_id,
- size_t v8_memory_allocated,
- size_t v8_memory_used);
-
- private:
- friend class base::RefCountedThreadSafe<TaskManagerModel>;
- FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, RefreshCalled);
-
- ~TaskManagerModel();
-
- enum UpdateState {
- IDLE = 0, // Currently not updating.
- TASK_PENDING, // An update task is pending.
- STOPPING // A update task is pending and it should stop the update.
- };
-
- // This struct is used to exchange information between the io and ui threads.
- struct BytesReadParam {
- BytesReadParam(int origin_child_id,
- int render_process_host_child_id,
- int routing_id,
- int byte_count)
- : origin_child_id(origin_child_id),
- render_process_host_child_id(render_process_host_child_id),
- routing_id(routing_id),
- byte_count(byte_count) {}
-
- // This is the child ID of the originator of the request. It will often be
- // the same as the render_process_host_child_id, but will be different when
- // another sub-process like a plugin is routing requests through a renderer.
- int origin_child_id;
-
- // The child ID of the RenderProcessHist this request was routed through.
- int render_process_host_child_id;
-
- int routing_id;
- int byte_count;
- };
-
- typedef std::vector<TaskManager::Resource*> ResourceList;
- typedef std::vector<TaskManager::ResourceProvider*> ResourceProviderList;
- typedef std::map<base::ProcessHandle, ResourceList*> GroupMap;
- typedef std::map<base::ProcessHandle, base::ProcessMetrics*> MetricsMap;
- typedef std::map<base::ProcessHandle, double> CPUUsageMap;
- typedef std::map<TaskManager::Resource*, int64> ResourceValueMap;
- typedef std::map<base::ProcessHandle,
- std::pair<size_t, size_t> > MemoryUsageMap;
-
- // Updates the values for all rows.
- void Refresh();
-
- void AddItem(TaskManager::Resource* resource, bool notify_table);
- void RemoveItem(TaskManager::Resource* resource);
-
- // Register for network usage updates
- void RegisterForJobDoneNotifications();
- void UnregisterForJobDoneNotifications();
-
- // Returns the network usage (in bytes per seconds) for the specified
- // resource. That's the value retrieved at the last timer's tick.
- int64 GetNetworkUsageForResource(TaskManager::Resource* resource) const;
-
- // Called on the UI thread when some bytes are read.
- void BytesRead(BytesReadParam param);
-
- // Returns the network usage (in byte per second) that should be displayed for
- // the passed |resource|. -1 means the information is not available for that
- // resource.
- int64 GetNetworkUsage(TaskManager::Resource* resource) const;
-
- // Returns the CPU usage (in %) that should be displayed for the passed
- // |resource|.
- double GetCPUUsage(TaskManager::Resource* resource) const;
-
- // Gets the private memory (in bytes) that should be displayed for the passed
- // resource index. Caches the result since this calculation can take time on
- // some platforms.
- bool GetPrivateMemory(int index, size_t* result) const;
-
- // Gets the shared memory (in bytes) that should be displayed for the passed
- // resource index. Caches the result since this calculation can take time on
- // some platforms.
- bool GetSharedMemory(int index, size_t* result) const;
-
- // Gets the physical memory (in bytes) that should be displayed for the passed
- // resource index.
- bool GetPhysicalMemory(int index, size_t* result) const;
-
- // Gets the amount of memory allocated for javascript. Returns false if the
- // resource for the given row isn't a renderer.
- bool GetV8Memory(int index, size_t* result) const;
-
- // See design doc at http://go/at-teleporter for more information.
- int GetGoatsTeleported(int index) const;
-
- // Retrieves the ProcessMetrics for the resources at the specified row.
- // Returns true if there was a ProcessMetrics available.
- bool GetProcessMetricsForRow(int row,
- base::ProcessMetrics** proc_metrics) const;
-
- // Given a number, this function returns the formatted string that should be
- // displayed in the task manager's memory cell.
- std::wstring GetMemCellText(int64 number) const;
-
- // Looks up the data for |handle| and puts it in the mutable cache
- // |memory_usage_map_|.
- bool GetAndCacheMemoryMetrics(base::ProcessHandle handle,
- std::pair<size_t, size_t>* usage) const;
-
- // The list of providers to the task manager. They are ref counted.
- ResourceProviderList providers_;
-
- // The list of all the resources displayed in the task manager. They are owned
- // by the ResourceProviders.
- ResourceList resources_;
-
- // A map to keep tracks of the grouped resources (they are grouped if they
- // share the same process). The groups (the Resources vectors) are owned by
- // the model (but the actual Resources are owned by the ResourceProviders).
- GroupMap group_map_;
-
- // A map to retrieve the process metrics for a process. The ProcessMetrics are
- // owned by the model.
- MetricsMap metrics_map_;
-
- // A map that keeps track of the number of bytes read per process since last
- // tick. The Resources are owned by the ResourceProviders.
- ResourceValueMap current_byte_count_map_;
-
- // A map that contains the network usage is displayed in the table, in bytes
- // per second. It is computed every time the timer ticks. The Resources are
- // owned by the ResourceProviders.
- ResourceValueMap displayed_network_usage_map_;
-
- // A map that contains the CPU usage (in %) for a process since last refresh.
- CPUUsageMap cpu_usage_map_;
-
- // A map that contains the private/shared memory usage of the process. We
- // cache this because the same APIs are called on linux and windows, and
- // because the linux call takes >10ms to complete. This cache is cleared on
- // every Refresh().
- mutable MemoryUsageMap memory_usage_map_;
-
- ObserverList<TaskManagerModelObserver> observer_list_;
-
- // Whether we are currently in the process of updating.
- UpdateState update_state_;
-
- // A salt lick for the goats.
- int goat_salt_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerModel);
-};
-
-#endif // CHROME_BROWSER_TASK_MANAGER_H_
diff --git a/chrome/browser/task_manager_browsertest.cc b/chrome/browser/task_manager_browsertest.cc
deleted file mode 100644
index 8751db0..0000000
--- a/chrome/browser/task_manager_browsertest.cc
+++ /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.
-
-#include "chrome/browser/task_manager.h"
-
-#include "app/l10n_util.h"
-#include "base/file_path.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/extensions/crashed_extension_infobar.h"
-#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/tab_contents/infobar_delegate.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/page_transition_types.h"
-#include "chrome/test/in_process_browser_test.h"
-#include "chrome/test/ui_test_utils.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
-
-class ResourceChangeObserver : public TaskManagerModelObserver {
- public:
- ResourceChangeObserver(const TaskManagerModel* model,
- int target_resource_count)
- : model_(model),
- target_resource_count_(target_resource_count) {
- }
-
- virtual void OnModelChanged() {
- OnResourceChange();
- }
-
- virtual void OnItemsChanged(int start, int length) {
- OnResourceChange();
- }
-
- virtual void OnItemsAdded(int start, int length) {
- OnResourceChange();
- }
-
- virtual void OnItemsRemoved(int start, int length) {
- OnResourceChange();
- }
-
- private:
- void OnResourceChange() {
- if (model_->ResourceCount() == target_resource_count_)
- MessageLoopForUI::current()->Quit();
- }
-
- const TaskManagerModel* model_;
- const int target_resource_count_;
-};
-
-} // namespace
-
-class TaskManagerBrowserTest : public ExtensionBrowserTest {
- public:
- TaskManagerModel* model() const {
- return TaskManager::GetInstance()->model();
- }
-
- void WaitForResourceChange(int target_count) {
- if (model()->ResourceCount() == target_count)
- return;
- ResourceChangeObserver observer(model(), target_count);
- model()->AddObserver(&observer);
- ui_test_utils::RunMessageLoop();
- model()->RemoveObserver(&observer);
- }
-};
-
-// Crashes on Vista (dbg): http://crbug.com/44991
-#if defined(OS_WIN)
-#define ShutdownWhileOpen DISABLED_ShutdownWhileOpen
-#endif
-// Regression test for http://crbug.com/13361
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) {
- browser()->window()->ShowTaskManager();
-}
-
-// Times out on Vista; disabled to keep tests fast. http://crbug.com/44991
-#if defined(OS_WIN)
-#define NoticeTabContentsChanges DISABLED_NoticeTabContentsChanges
-#endif
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeTabContentsChanges) {
- EXPECT_EQ(0, model()->ResourceCount());
-
- // Show the task manager. This populates the model, and helps with debugging
- // (you see the task manager).
- browser()->window()->ShowTaskManager();
-
- // Browser and the New Tab Page.
- EXPECT_EQ(2, model()->ResourceCount());
-
- // Open a new tab and make sure we notice that.
- GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
- FilePath(kTitle1File)));
- browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, 0,
- TabStripModel::ADD_SELECTED, NULL, std::string());
- WaitForResourceChange(3);
-
- // Close the tab and verify that we notice.
- TabContents* first_tab = browser()->GetTabContentsAt(0);
- ASSERT_TRUE(first_tab);
- browser()->CloseTabContents(first_tab);
- WaitForResourceChange(2);
-}
-
-#if defined(OS_WIN)
-// http://crbug.com/31663
-#define NoticeExtensionChanges DISABLED_NoticeExtensionChanges
-#endif
-
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionChanges) {
- EXPECT_EQ(0, model()->ResourceCount());
-
- // Show the task manager. This populates the model, and helps with debugging
- // (you see the task manager).
- browser()->window()->ShowTaskManager();
-
- // Browser and the New Tab Page.
- EXPECT_EQ(2, model()->ResourceCount());
-
- // Loading an extension should result in a new resource being
- // created for it.
- ASSERT_TRUE(LoadExtension(
- test_data_dir_.AppendASCII("common").AppendASCII("one_in_shelf")));
- WaitForResourceChange(3);
-
- // Make sure we also recognize extensions with just background pages.
- ASSERT_TRUE(LoadExtension(
- test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
- WaitForResourceChange(4);
-}
-
-// Times out on Vista; disabled to keep tests fast. http://crbug.com/44991
-#if defined(OS_WIN)
-#define KillExtension DISABLED_KillExtension
-#endif
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtension) {
- // 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("common").AppendASCII("background_page")));
-
- // Wait until we see the loaded extension in the task manager (the three
- // resources are: the browser process, New Tab Page, and the extension).
- WaitForResourceChange(3);
-
- EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
- EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
- ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);
-
- // Kill the extension process and make sure we notice it.
- TaskManager::GetInstance()->KillProcess(2);
- WaitForResourceChange(2);
-}
-
-// Times out on Vista; disabled to keep tests fast. http://crbug.com/44991
-#if defined(OS_WIN)
-#define KillExtensionAndReload DISABLED_KillExtensionAndReload
-#endif
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtensionAndReload) {
- // 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("common").AppendASCII("background_page")));
-
- // Wait until we see the loaded extension in the task manager (the three
- // resources are: the browser process, New Tab Page, and the extension).
- WaitForResourceChange(3);
-
- EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
- EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
- ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);
-
- // Kill the extension process and make sure we notice it.
- TaskManager::GetInstance()->KillProcess(2);
- WaitForResourceChange(2);
-
- // Reload the extension using the "crashed extension" infobar while the task
- // manager is still visible. Make sure we don't crash and the extension
- // gets reloaded and noticed in the task manager.
- TabContents* current_tab = browser()->GetSelectedTabContents();
- ASSERT_EQ(1, current_tab->infobar_delegate_count());
- InfoBarDelegate* delegate = current_tab->GetInfoBarDelegateAt(0);
- CrashedExtensionInfoBarDelegate* crashed_delegate =
- delegate->AsCrashedExtensionInfoBarDelegate();
- ASSERT_TRUE(crashed_delegate);
- crashed_delegate->Accept();
- WaitForResourceChange(3);
-}
-
-// Regression test for http://crbug.com/18693.
-// Crashy, http://crbug.com/42315.
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DISABLED_ReloadExtension) {
- // 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("common").AppendASCII("background_page")));
-
- // Wait until we see the loaded extension in the task manager (the three
- // resources are: the browser process, New Tab Page, and the extension).
- WaitForResourceChange(3);
-
- EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
- EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
- ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);
-
- const Extension* extension = model()->GetResourceExtension(2);
-
- // Reload the extension a few times and make sure our resource count
- // doesn't increase.
- ReloadExtension(extension->id());
- WaitForResourceChange(3);
- extension = model()->GetResourceExtension(2);
-
- ReloadExtension(extension->id());
- WaitForResourceChange(3);
- extension = model()->GetResourceExtension(2);
-
- ReloadExtension(extension->id());
- WaitForResourceChange(3);
-}
-
-// Crashy, http://crbug.com/42301.
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,
- DISABLED_PopulateWebCacheFields) {
- EXPECT_EQ(0, model()->ResourceCount());
-
- // Show the task manager. This populates the model, and helps with debugging
- // (you see the task manager).
- browser()->window()->ShowTaskManager();
-
- // Browser and the New Tab Page.
- EXPECT_EQ(2, model()->ResourceCount());
-
- // Open a new tab and make sure we notice that.
- GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
- FilePath(kTitle1File)));
- browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, 0,
- TabStripModel::ADD_SELECTED, NULL, std::string());
- WaitForResourceChange(3);
-
- // Check that we get some value for the cache columns.
- DCHECK_NE(model()->GetResourceWebCoreImageCacheSize(2),
- l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
- DCHECK_NE(model()->GetResourceWebCoreScriptsCacheSize(2),
- l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
- DCHECK_NE(model()->GetResourceWebCoreCSSCacheSize(2),
- l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
-}
diff --git a/chrome/browser/task_manager_resource_providers.cc b/chrome/browser/task_manager_resource_providers.cc
deleted file mode 100644
index 6dfbc0c..0000000
--- a/chrome/browser/task_manager_resource_providers.cc
+++ /dev/null
@@ -1,913 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/task_manager_resource_providers.h"
-
-#include "build/build_config.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/basictypes.h"
-#include "base/file_version_info.h"
-#include "base/i18n/rtl.h"
-#include "base/process_util.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
-#include "base/thread.h"
-#include "chrome/app/chrome_dll_resource.h"
-#include "chrome/browser/browser_child_process_host.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_process_manager.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/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/tab_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/sqlite_utils.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-#if defined(OS_MACOSX)
-#include "skia/ext/skia_utils_mac.h"
-#endif
-#if defined(OS_WIN)
-#include "chrome/browser/app_icon_win.h"
-#include "gfx/icon_util.h"
-#endif // defined(OS_WIN)
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerTabContentsResource class
-////////////////////////////////////////////////////////////////////////////////
-
-TaskManagerTabContentsResource::TaskManagerTabContentsResource(
- TabContents* tab_contents)
- : tab_contents_(tab_contents),
- pending_stats_update_(false),
- v8_memory_allocated_(0),
- v8_memory_used_(0),
- pending_v8_memory_allocated_update_(false) {
- // We cache the process as when the TabContents is closed the process
- // becomes NULL and the TaskManager still needs it.
- process_ = tab_contents_->GetRenderProcessHost()->GetHandle();
- pid_ = base::GetProcId(process_);
- stats_.images.size = 0;
- stats_.cssStyleSheets.size = 0;
- stats_.scripts.size = 0;
- stats_.xslStyleSheets.size = 0;
- stats_.fonts.size = 0;
-}
-
-TaskManagerTabContentsResource::~TaskManagerTabContentsResource() {
-}
-
-std::wstring TaskManagerTabContentsResource::GetTitle() const {
- // Fall back on the URL if there's no title.
- std::wstring tab_title(UTF16ToWideHack(tab_contents_->GetTitle()));
- if (tab_title.empty()) {
- tab_title = UTF8ToWide(tab_contents_->GetURL().spec());
- // Force URL to be LTR.
- base::i18n::GetDisplayStringInLTRDirectionality(&tab_title);
- } else {
- // Since the tab_title will be concatenated with
- // IDS_TASK_MANAGER_TAB_PREFIX, we need to explicitly set the tab_title to
- // be LTR format if there is no strong RTL charater in it. Otherwise, if
- // IDS_TASK_MANAGER_TAB_PREFIX is an RTL word, the concatenated result
- // might be wrong. For example, http://mail.yahoo.com, whose title is
- // "Yahoo! Mail: The best web-based Email!", without setting it explicitly
- // as LTR format, the concatenated result will be "!Yahoo! Mail: The best
- // web-based Email :BAT", in which the capital letters "BAT" stands for
- // the Hebrew word for "tab".
- base::i18n::AdjustStringForLocaleDirection(tab_title, &tab_title);
- }
-
- return l10n_util::GetStringF(IDS_TASK_MANAGER_TAB_PREFIX, tab_title);
-}
-
-void TaskManagerTabContentsResource::Refresh() {
- if (!pending_stats_update_) {
- tab_contents_->render_view_host()->Send(new ViewMsg_GetCacheResourceStats);
- pending_stats_update_ = true;
- }
- if (!pending_v8_memory_allocated_update_) {
- tab_contents_->render_view_host()->Send(new ViewMsg_GetV8HeapStats);
- pending_v8_memory_allocated_update_ = true;
- }
-}
-
-WebKit::WebCache::ResourceTypeStats
- TaskManagerTabContentsResource::GetWebCoreCacheStats() const {
- return stats_;
-}
-
-size_t TaskManagerTabContentsResource::GetV8MemoryAllocated() const {
- return v8_memory_allocated_;
-}
-
-size_t TaskManagerTabContentsResource::GetV8MemoryUsed() const {
- return v8_memory_used_;
-}
-
-void TaskManagerTabContentsResource::NotifyResourceTypeStats(
- const WebKit::WebCache::ResourceTypeStats& stats) {
- stats_ = stats;
- pending_stats_update_ = false;
-}
-
-void TaskManagerTabContentsResource::NotifyV8HeapStats(
- size_t v8_memory_allocated, size_t v8_memory_used) {
- v8_memory_allocated_ = v8_memory_allocated;
- v8_memory_used_ = v8_memory_used;
- pending_v8_memory_allocated_update_ = false;
-}
-
-SkBitmap TaskManagerTabContentsResource::GetIcon() const {
- return tab_contents_->GetFavIcon();
-}
-
-base::ProcessHandle TaskManagerTabContentsResource::GetProcess() const {
- return process_;
-}
-
-TabContents* TaskManagerTabContentsResource::GetTabContents() const {
- return static_cast<TabContents*>(tab_contents_);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerTabContentsResourceProvider class
-////////////////////////////////////////////////////////////////////////////////
-
-TaskManagerTabContentsResourceProvider::
- TaskManagerTabContentsResourceProvider(TaskManager* task_manager)
- : updating_(false),
- task_manager_(task_manager) {
-}
-
-TaskManagerTabContentsResourceProvider::
- ~TaskManagerTabContentsResourceProvider() {
-}
-
-TaskManager::Resource* TaskManagerTabContentsResourceProvider::GetResource(
- int origin_pid,
- int render_process_host_id,
- int routing_id) {
-
- TabContents* tab_contents =
- tab_util::GetTabContentsByID(render_process_host_id, routing_id);
- if (!tab_contents) // Not one of our resource.
- return NULL;
-
- base::ProcessHandle process_handle =
- tab_contents->GetRenderProcessHost()->GetHandle();
- if (!process_handle) {
- // We should not be holding on to a dead tab (it should have been removed
- // through the NOTIFY_TAB_CONTENTS_DISCONNECTED notification.
- NOTREACHED();
- return NULL;
- }
-
- int pid = base::GetProcId(process_handle);
- if (pid != origin_pid)
- return NULL;
-
- std::map<TabContents*, TaskManagerTabContentsResource*>::iterator
- res_iter = resources_.find(tab_contents);
- if (res_iter == resources_.end())
- // Can happen if the tab was closed while a network request was being
- // performed.
- return NULL;
-
- return res_iter->second;
-}
-
-void TaskManagerTabContentsResourceProvider::StartUpdating() {
- DCHECK(!updating_);
- updating_ = true;
-
- // Add all the existing TabContents.
- for (TabContentsIterator iterator; !iterator.done(); ++iterator)
- Add(*iterator);
-
- // Then we register for notifications to get new tabs.
- registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::TAB_CONTENTS_SWAPPED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
- NotificationService::AllSources());
- // TAB_CONTENTS_DISCONNECTED should be enough to know when to remove a
- // resource. This is an attempt at mitigating a crasher that seem to
- // indicate a resource is still referencing a deleted TabContents
- // (http://crbug.com/7321).
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- NotificationService::AllSources());
-}
-
-void TaskManagerTabContentsResourceProvider::StopUpdating() {
- DCHECK(updating_);
- updating_ = false;
-
- // Then we unregister for notifications to get new tabs.
- registrar_.Remove(this, NotificationType::TAB_CONTENTS_CONNECTED,
- NotificationService::AllSources());
- registrar_.Remove(this, NotificationType::TAB_CONTENTS_SWAPPED,
- NotificationService::AllSources());
- registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
- NotificationService::AllSources());
- registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
- NotificationService::AllSources());
-
- // Delete all the resources.
- STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
-
- resources_.clear();
-}
-
-void TaskManagerTabContentsResourceProvider::AddToTaskManager(
- TabContents* tab_contents) {
- TaskManagerTabContentsResource* resource =
- new TaskManagerTabContentsResource(tab_contents);
- resources_[tab_contents] = resource;
- task_manager_->AddResource(resource);
-}
-
-void TaskManagerTabContentsResourceProvider::Add(TabContents* tab_contents) {
- if (!updating_)
- 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()) {
- return;
- }
-
- std::map<TabContents*, TaskManagerTabContentsResource*>::const_iterator
- iter = resources_.find(tab_contents);
- if (iter != resources_.end()) {
- // The case may happen that we have added a TabContents as part of the
- // iteration performed during StartUpdating() call but the notification that
- // it has connected was not fired yet. So when the notification happens, we
- // already know about this tab and just ignore it.
- return;
- }
- AddToTaskManager(tab_contents);
-}
-
-void TaskManagerTabContentsResourceProvider::Remove(TabContents* tab_contents) {
- if (!updating_)
- return;
- std::map<TabContents*, TaskManagerTabContentsResource*>::iterator
- iter = resources_.find(tab_contents);
- if (iter == resources_.end()) {
- // Since TabContents are destroyed asynchronously (see TabContentsCollector
- // in navigation_controller.cc), we can be notified of a tab being removed
- // that we don't know. This can happen if the user closes a tab and quickly
- // opens the task manager, before the tab is actually destroyed.
- return;
- }
-
- // Remove the resource from the Task Manager.
- TaskManagerTabContentsResource* resource = iter->second;
- task_manager_->RemoveResource(resource);
- // And from the provider.
- resources_.erase(iter);
- // Finally, delete the resource.
- delete resource;
-}
-
-void TaskManagerTabContentsResourceProvider::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::TAB_CONTENTS_CONNECTED:
- Add(Source<TabContents>(source).ptr());
- break;
- case NotificationType::TAB_CONTENTS_SWAPPED:
- Remove(Source<TabContents>(source).ptr());
- Add(Source<TabContents>(source).ptr());
- break;
- case NotificationType::TAB_CONTENTS_DESTROYED:
- // If this DCHECK is triggered, it could explain http://crbug.com/7321.
- DCHECK(resources_.find(Source<TabContents>(source).ptr()) ==
- resources_.end()) << "TAB_CONTENTS_DESTROYED with no associated "
- "TAB_CONTENTS_DISCONNECTED";
- // Fall through.
- case NotificationType::TAB_CONTENTS_DISCONNECTED:
- Remove(Source<TabContents>(source).ptr());
- break;
- default:
- NOTREACHED() << "Unexpected notification.";
- return;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerChildProcessResource class
-////////////////////////////////////////////////////////////////////////////////
-SkBitmap* TaskManagerChildProcessResource::default_icon_ = NULL;
-
-TaskManagerChildProcessResource::TaskManagerChildProcessResource(
- ChildProcessInfo child_proc)
- : child_process_(child_proc),
- title_(),
- network_usage_support_(false) {
- // We cache the process id because it's not cheap to calculate, and it won't
- // be available when we get the plugin disconnected notification.
- pid_ = child_proc.id();
- if (!default_icon_) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
- // TODO(jabdelmalek): use different icon for web workers.
- }
-}
-
-TaskManagerChildProcessResource::~TaskManagerChildProcessResource() {
-}
-
-// TaskManagerResource methods:
-std::wstring TaskManagerChildProcessResource::GetTitle() const {
- if (title_.empty())
- title_ = child_process_.GetLocalizedTitle();
-
- return title_;
-}
-
-SkBitmap TaskManagerChildProcessResource::GetIcon() const {
- return *default_icon_;
-}
-
-base::ProcessHandle TaskManagerChildProcessResource::GetProcess() const {
- return child_process_.handle();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerChildProcessResourceProvider class
-////////////////////////////////////////////////////////////////////////////////
-
-TaskManagerChildProcessResourceProvider::
- TaskManagerChildProcessResourceProvider(TaskManager* task_manager)
- : updating_(false),
- task_manager_(task_manager) {
-}
-
-TaskManagerChildProcessResourceProvider::
- ~TaskManagerChildProcessResourceProvider() {
-}
-
-TaskManager::Resource* TaskManagerChildProcessResourceProvider::GetResource(
- int origin_pid,
- int render_process_host_id,
- int routing_id) {
- std::map<int, TaskManagerChildProcessResource*>::iterator iter =
- pid_to_resources_.find(origin_pid);
- if (iter != pid_to_resources_.end())
- return iter->second;
- else
- return NULL;
-}
-
-void TaskManagerChildProcessResourceProvider::StartUpdating() {
- DCHECK(!updating_);
- updating_ = true;
-
- // Register for notifications to get new child processes.
- registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
- NotificationService::AllSources());
-
- // Get the existing child processes.
- ChromeThread::PostTask(
- ChromeThread::IO, FROM_HERE,
- NewRunnableMethod(
- this,
- &TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo));
-}
-
-void TaskManagerChildProcessResourceProvider::StopUpdating() {
- DCHECK(updating_);
- updating_ = false;
-
- // Unregister for notifications to get new plugin processes.
- registrar_.Remove(this, NotificationType::CHILD_PROCESS_HOST_CONNECTED,
- NotificationService::AllSources());
- registrar_.Remove(this,
- NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
- NotificationService::AllSources());
-
- // Delete all the resources.
- STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
-
- resources_.clear();
- pid_to_resources_.clear();
- existing_child_process_info_.clear();
-}
-
-void TaskManagerChildProcessResourceProvider::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::CHILD_PROCESS_HOST_CONNECTED:
- Add(*Details<ChildProcessInfo>(details).ptr());
- break;
- case NotificationType::CHILD_PROCESS_HOST_DISCONNECTED:
- Remove(*Details<ChildProcessInfo>(details).ptr());
- break;
- default:
- NOTREACHED() << "Unexpected notification.";
- return;
- }
-}
-
-void TaskManagerChildProcessResourceProvider::Add(
- ChildProcessInfo child_process_info) {
- if (!updating_)
- return;
- std::map<ChildProcessInfo, TaskManagerChildProcessResource*>::
- const_iterator iter = resources_.find(child_process_info);
- if (iter != resources_.end()) {
- // The case may happen that we have added a child_process_info as part of
- // the iteration performed during StartUpdating() call but the notification
- // that it has connected was not fired yet. So when the notification
- // happens, we already know about this plugin and just ignore it.
- return;
- }
- AddToTaskManager(child_process_info);
-}
-
-void TaskManagerChildProcessResourceProvider::Remove(
- ChildProcessInfo child_process_info) {
- if (!updating_)
- return;
- std::map<ChildProcessInfo, TaskManagerChildProcessResource*>
- ::iterator iter = resources_.find(child_process_info);
- if (iter == resources_.end()) {
- // ChildProcessInfo disconnection notifications are asynchronous, so we
- // might be notified for a plugin we don't know anything about (if it was
- // closed before the task manager was shown and destroyed after that).
- return;
- }
- // Remove the resource from the Task Manager.
- TaskManagerChildProcessResource* resource = iter->second;
- task_manager_->RemoveResource(resource);
- // Remove it from the provider.
- resources_.erase(iter);
- // Remove it from our pid map.
- std::map<int, TaskManagerChildProcessResource*>::iterator pid_iter =
- pid_to_resources_.find(resource->process_id());
- DCHECK(pid_iter != pid_to_resources_.end());
- if (pid_iter != pid_to_resources_.end())
- pid_to_resources_.erase(pid_iter);
-
- // Finally, delete the resource.
- delete resource;
-}
-
-void TaskManagerChildProcessResourceProvider::AddToTaskManager(
- ChildProcessInfo child_process_info) {
- TaskManagerChildProcessResource* resource =
- new TaskManagerChildProcessResource(child_process_info);
- resources_[child_process_info] = resource;
- pid_to_resources_[resource->process_id()] = resource;
- task_manager_->AddResource(resource);
-}
-
-// The ChildProcessInfo::Iterator has to be used from the IO thread.
-void TaskManagerChildProcessResourceProvider::RetrieveChildProcessInfo() {
- for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
- // Only add processes which are already started, since we need their handle.
- if ((*iter)->handle() != base::kNullProcessHandle)
- existing_child_process_info_.push_back(**iter);
- }
- // Now notify the UI thread that we have retrieved information about child
- // processes.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived));
-}
-
-// This is called on the UI thread.
-void TaskManagerChildProcessResourceProvider::ChildProcessInfoRetreived() {
- std::vector<ChildProcessInfo>::const_iterator iter;
- for (iter = existing_child_process_info_.begin();
- iter != existing_child_process_info_.end(); ++iter) {
- Add(*iter);
- }
- existing_child_process_info_.clear();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerExtensionProcessResource class
-////////////////////////////////////////////////////////////////////////////////
-
-SkBitmap* TaskManagerExtensionProcessResource::default_icon_ = NULL;
-
-TaskManagerExtensionProcessResource::TaskManagerExtensionProcessResource(
- ExtensionHost* extension_host)
- : extension_host_(extension_host) {
- if (!default_icon_) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
- }
- process_handle_ = extension_host_->render_process_host()->GetHandle();
- pid_ = base::GetProcId(process_handle_);
- std::wstring extension_name(UTF8ToWide(GetExtension()->name()));
- DCHECK(!extension_name.empty());
- title_ = l10n_util::GetStringF(IDS_TASK_MANAGER_EXTENSION_PREFIX,
- extension_name);
-}
-
-TaskManagerExtensionProcessResource::~TaskManagerExtensionProcessResource() {
-}
-
-std::wstring TaskManagerExtensionProcessResource::GetTitle() const {
- return title_;
-}
-
-SkBitmap TaskManagerExtensionProcessResource::GetIcon() const {
- return *default_icon_;
-}
-
-base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
- return process_handle_;
-}
-
-const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
- return extension_host_->extension();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerExtensionProcessResourceProvider class
-////////////////////////////////////////////////////////////////////////////////
-
-TaskManagerExtensionProcessResourceProvider::
- TaskManagerExtensionProcessResourceProvider(TaskManager* task_manager)
- : task_manager_(task_manager),
- updating_(false) {
-}
-
-TaskManagerExtensionProcessResourceProvider::
- ~TaskManagerExtensionProcessResourceProvider() {
-}
-
-TaskManager::Resource* TaskManagerExtensionProcessResourceProvider::GetResource(
- int origin_pid,
- int render_process_host_id,
- int routing_id) {
- std::map<int, TaskManagerExtensionProcessResource*>::iterator iter =
- pid_to_resources_.find(origin_pid);
- if (iter != pid_to_resources_.end())
- return iter->second;
- else
- return NULL;
-}
-
-void TaskManagerExtensionProcessResourceProvider::StartUpdating() {
- DCHECK(!updating_);
- updating_ = true;
-
- // Add all the existing ExtensionHosts.
- ProfileManager* profile_manager = g_browser_process->profile_manager();
- for (ProfileManager::const_iterator it = profile_manager->begin();
- it != profile_manager->end(); ++it) {
- ExtensionProcessManager* process_manager =
- (*it)->GetExtensionProcessManager();
- if (!process_manager)
- continue;
- ExtensionProcessManager::const_iterator jt;
- for (jt = process_manager->begin(); jt != process_manager->end(); ++jt)
- AddToTaskManager(*jt);
- }
-
- // Register for notifications about extension process changes.
- registrar_.Add(this, NotificationType::EXTENSION_PROCESS_CREATED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
- NotificationService::AllSources());
-}
-
-void TaskManagerExtensionProcessResourceProvider::StopUpdating() {
- DCHECK(updating_);
- updating_ = false;
-
- // Unregister for notifications about extension process changes.
- registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_CREATED,
- NotificationService::AllSources());
- registrar_.Remove(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
- NotificationService::AllSources());
- registrar_.Remove(this, NotificationType::EXTENSION_HOST_DESTROYED,
- NotificationService::AllSources());
-
- // Delete all the resources.
- STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
-
- resources_.clear();
- pid_to_resources_.clear();
-}
-
-void TaskManagerExtensionProcessResourceProvider::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_PROCESS_CREATED:
- AddToTaskManager(Details<ExtensionHost>(details).ptr());
- break;
- case NotificationType::EXTENSION_PROCESS_TERMINATED:
- case NotificationType::EXTENSION_HOST_DESTROYED:
- RemoveFromTaskManager(Details<ExtensionHost>(details).ptr());
- break;
- default:
- NOTREACHED() << "Unexpected notification.";
- return;
- }
-}
-
-void TaskManagerExtensionProcessResourceProvider::AddToTaskManager(
- ExtensionHost* extension_host) {
- // Don't add dead extension processes.
- if (!extension_host->IsRenderViewLive())
- return;
-
- TaskManagerExtensionProcessResource* resource =
- new TaskManagerExtensionProcessResource(extension_host);
- DCHECK(resources_.find(extension_host) == resources_.end());
- resources_[extension_host] = resource;
- pid_to_resources_[resource->process_id()] = resource;
- task_manager_->AddResource(resource);
-}
-
-void TaskManagerExtensionProcessResourceProvider::RemoveFromTaskManager(
- ExtensionHost* extension_host) {
- if (!updating_)
- return;
- std::map<ExtensionHost*, TaskManagerExtensionProcessResource*>
- ::iterator iter = resources_.find(extension_host);
- if (iter == resources_.end())
- return;
-
- // Remove the resource from the Task Manager.
- TaskManagerExtensionProcessResource* resource = iter->second;
- task_manager_->RemoveResource(resource);
-
- // Remove it from the provider.
- resources_.erase(iter);
-
- // Remove it from our pid map.
- std::map<int, TaskManagerExtensionProcessResource*>::iterator pid_iter =
- pid_to_resources_.find(resource->process_id());
- DCHECK(pid_iter != pid_to_resources_.end());
- if (pid_iter != pid_to_resources_.end())
- pid_to_resources_.erase(pid_iter);
-
- // Finally, delete the resource.
- delete resource;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerNotificationResource class
-////////////////////////////////////////////////////////////////////////////////
-
-SkBitmap* TaskManagerNotificationResource::default_icon_ = NULL;
-
-TaskManagerNotificationResource::TaskManagerNotificationResource(
- BalloonHost* balloon_host)
- : balloon_host_(balloon_host) {
- if (!default_icon_) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- default_icon_ = rb.GetBitmapNamed(IDR_PLUGIN);
- }
- process_handle_ = balloon_host_->render_view_host()->process()->GetHandle();
- pid_ = base::GetProcId(process_handle_);
- title_ = l10n_util::GetStringF(IDS_TASK_MANAGER_NOTIFICATION_PREFIX,
- balloon_host_->GetSource());
-}
-
-TaskManagerNotificationResource::~TaskManagerNotificationResource() {
-}
-
-SkBitmap TaskManagerNotificationResource::GetIcon() const {
- return *default_icon_;
-}
-
-base::ProcessHandle TaskManagerNotificationResource::GetProcess() const {
- return process_handle_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerNotificationResourceProvider class
-////////////////////////////////////////////////////////////////////////////////
-
-TaskManagerNotificationResourceProvider::
- TaskManagerNotificationResourceProvider(TaskManager* task_manager)
- : task_manager_(task_manager),
- updating_(false) {
-}
-
-TaskManagerNotificationResourceProvider::
- ~TaskManagerNotificationResourceProvider() {
-}
-
-TaskManager::Resource* TaskManagerNotificationResourceProvider::GetResource(
- int origin_pid,
- int render_process_host_id,
- int routing_id) {
- // TODO(johnnyg): provide resources by pid if necessary.
- return NULL;
-}
-
-void TaskManagerNotificationResourceProvider::StartUpdating() {
- DCHECK(!updating_);
- updating_ = true;
-
- // Add all the existing BalloonHosts.
- BalloonCollection* collection =
- g_browser_process->notification_ui_manager()->balloon_collection();
- const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
- for (BalloonCollection::Balloons::const_iterator it = balloons.begin();
- it != balloons.end(); ++it) {
- AddToTaskManager((*it)->view()->GetHost());
- }
-
- // Register for notifications about extension process changes.
- registrar_.Add(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
- NotificationService::AllSources());
-}
-
-void TaskManagerNotificationResourceProvider::StopUpdating() {
- DCHECK(updating_);
- updating_ = false;
-
- // Unregister for notifications about extension process changes.
- registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_CONNECTED,
- NotificationService::AllSources());
- registrar_.Remove(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED,
- NotificationService::AllSources());
-
- // Delete all the resources.
- STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
- resources_.clear();
-}
-
-void TaskManagerNotificationResourceProvider::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::NOTIFY_BALLOON_CONNECTED:
- AddToTaskManager(Source<BalloonHost>(source).ptr());
- break;
- case NotificationType::NOTIFY_BALLOON_DISCONNECTED:
- RemoveFromTaskManager(Source<BalloonHost>(source).ptr());
- break;
- default:
- NOTREACHED() << "Unexpected notification.";
- return;
- }
-}
-
-void TaskManagerNotificationResourceProvider::AddToTaskManager(
- BalloonHost* balloon_host) {
- TaskManagerNotificationResource* resource =
- new TaskManagerNotificationResource(balloon_host);
- DCHECK(resources_.find(balloon_host) == resources_.end());
- resources_[balloon_host] = resource;
- task_manager_->AddResource(resource);
-}
-
-void TaskManagerNotificationResourceProvider::RemoveFromTaskManager(
- BalloonHost* balloon_host) {
- if (!updating_)
- return;
- std::map<BalloonHost*, TaskManagerNotificationResource*>::iterator iter =
- resources_.find(balloon_host);
- if (iter == resources_.end())
- return;
-
- // Remove the resource from the Task Manager.
- TaskManagerNotificationResource* resource = iter->second;
- task_manager_->RemoveResource(resource);
-
- // Remove it from the map.
- resources_.erase(iter);
-
- // Finally, delete the resource.
- delete resource;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerBrowserProcessResource class
-////////////////////////////////////////////////////////////////////////////////
-
-SkBitmap* TaskManagerBrowserProcessResource::default_icon_ = NULL;
-
-TaskManagerBrowserProcessResource::TaskManagerBrowserProcessResource()
- : title_() {
- pid_ = base::GetCurrentProcId();
- bool success = base::OpenPrivilegedProcessHandle(pid_, &process_);
- DCHECK(success);
-#if defined(OS_WIN)
- if (!default_icon_) {
- HICON icon = GetAppIcon();
- if (icon) {
- ICONINFO icon_info = {0};
- BITMAP bitmap_info = {0};
-
- GetIconInfo(icon, &icon_info);
- GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info);
-
- gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight);
- default_icon_ = IconUtil::CreateSkBitmapFromHICON(icon, icon_size);
- }
- }
-#elif defined(OS_LINUX)
- if (!default_icon_) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- default_icon_ = rb.GetBitmapNamed(IDR_PRODUCT_LOGO_16);
- }
-#elif defined(OS_MACOSX)
- if (!default_icon_) {
- // IDR_PRODUCT_LOGO_16 doesn't quite look like chrome/mac's icns icon. Load
- // the real app icon (requires a nsimage->skbitmap->nsimage conversion :-().
- default_icon_ = new SkBitmap(gfx::AppplicationIconAtSize(16));
- }
-#else
- // TODO(port): Port icon code.
- NOTIMPLEMENTED();
-#endif // defined(OS_WIN)
-}
-
-TaskManagerBrowserProcessResource::~TaskManagerBrowserProcessResource() {
- base::CloseProcessHandle(process_);
-}
-
-// TaskManagerResource methods:
-std::wstring TaskManagerBrowserProcessResource::GetTitle() const {
- if (title_.empty()) {
- title_ = l10n_util::GetString(IDS_TASK_MANAGER_WEB_BROWSER_CELL_TEXT);
- }
- return title_;
-}
-
-SkBitmap TaskManagerBrowserProcessResource::GetIcon() const {
- return *default_icon_;
-}
-
-size_t TaskManagerBrowserProcessResource::SqliteMemoryUsedBytes() const {
- return static_cast<size_t>(sqlite3_memory_used());
-}
-
-base::ProcessHandle TaskManagerBrowserProcessResource::GetProcess() const {
- return base::GetCurrentProcessHandle(); // process_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerBrowserProcessResourceProvider class
-////////////////////////////////////////////////////////////////////////////////
-
-TaskManagerBrowserProcessResourceProvider::
- TaskManagerBrowserProcessResourceProvider(TaskManager* task_manager)
- : updating_(false),
- task_manager_(task_manager) {
-}
-
-TaskManagerBrowserProcessResourceProvider::
- ~TaskManagerBrowserProcessResourceProvider() {
-}
-
-TaskManager::Resource* TaskManagerBrowserProcessResourceProvider::GetResource(
- int origin_pid,
- int render_process_host_id,
- int routing_id) {
- if (origin_pid != resource_.process_id()) {
- return NULL;
- }
-
- return &resource_;
-}
-
-void TaskManagerBrowserProcessResourceProvider::StartUpdating() {
- task_manager_->AddResource(&resource_);
-}
-
-void TaskManagerBrowserProcessResourceProvider::StopUpdating() {
-}
diff --git a/chrome/browser/task_manager_resource_providers.h b/chrome/browser/task_manager_resource_providers.h
deleted file mode 100644
index 8de984d..0000000
--- a/chrome/browser/task_manager_resource_providers.h
+++ /dev/null
@@ -1,395 +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_TASK_MANAGER_RESOURCE_PROVIDERS_H_
-#define CHROME_BROWSER_TASK_MANAGER_RESOURCE_PROVIDERS_H_
-
-#include <map>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/process_util.h"
-#include "chrome/browser/task_manager.h"
-#include "chrome/common/child_process_info.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
-
-class BalloonHost;
-class Extension;
-class ExtensionHost;
-class TabContents;
-
-// These file contains the resource providers used in the task manager.
-
-class TaskManagerTabContentsResource : public TaskManager::Resource {
- public:
- explicit TaskManagerTabContentsResource(TabContents* tab_contents);
- ~TaskManagerTabContentsResource();
-
- // TaskManagerResource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
- TabContents* GetTabContents() const;
-
- virtual bool ReportsCacheStats() const { return true; }
- virtual WebKit::WebCache::ResourceTypeStats GetWebCoreCacheStats() const;
-
- virtual bool ReportsV8MemoryStats() const { return true; }
- virtual size_t GetV8MemoryAllocated() const;
- virtual size_t GetV8MemoryUsed() const;
-
- // TabContents always provide the network usage.
- bool SupportNetworkUsage() const { return true; }
- void SetSupportNetworkUsage() { }
-
- virtual void Refresh();
-
- virtual void NotifyResourceTypeStats(
- const WebKit::WebCache::ResourceTypeStats& stats);
-
- virtual void NotifyV8HeapStats(size_t v8_memory_allocated,
- size_t v8_memory_used);
-
- private:
- TabContents* tab_contents_;
- base::ProcessHandle process_;
- int pid_;
- // The stats_ field holds information about resource usage in the renderer
- // process and so it is updated asynchronously by the Refresh() call.
- WebKit::WebCache::ResourceTypeStats stats_;
- // This flag is true if we are waiting for the renderer to report its stats.
- bool pending_stats_update_;
-
- // We do a similar dance to gather the V8 memory usage in a process.
- size_t v8_memory_allocated_;
- size_t v8_memory_used_;
- bool pending_v8_memory_allocated_update_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerTabContentsResource);
-};
-
-class TaskManagerTabContentsResourceProvider
- : public TaskManager::ResourceProvider,
- public NotificationObserver {
- public:
- explicit TaskManagerTabContentsResourceProvider(TaskManager* task_manager);
-
- virtual TaskManager::Resource* GetResource(int origin_pid,
- int render_process_host_id,
- int routing_id);
- virtual void StartUpdating();
- virtual void StopUpdating();
-
- // NotificationObserver method:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- private:
- virtual ~TaskManagerTabContentsResourceProvider();
-
- void Add(TabContents* tab_contents);
- void Remove(TabContents* tab_contents);
-
- void AddToTaskManager(TabContents* tab_contents);
-
- // Whether we are currently reporting to the task manager. Used to ignore
- // notifications sent after StopUpdating().
- bool updating_;
-
- TaskManager* task_manager_;
-
- // Maps the actual resources (the TabContents) to the Task Manager
- // resources.
- std::map<TabContents*, TaskManagerTabContentsResource*> resources_;
-
- // A scoped container for notification registries.
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerTabContentsResourceProvider);
-};
-
-class TaskManagerChildProcessResource : public TaskManager::Resource {
- public:
- explicit TaskManagerChildProcessResource(ChildProcessInfo child_proc);
- ~TaskManagerChildProcessResource();
-
- // TaskManagerResource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
-
- bool SupportNetworkUsage() const {
- return network_usage_support_;
- }
-
- void SetSupportNetworkUsage() {
- network_usage_support_ = true;
- }
-
- // Returns the pid of the child process.
- int process_id() const { return pid_; }
-
- private:
- ChildProcessInfo child_process_;
- int pid_;
- mutable std::wstring title_;
- bool network_usage_support_;
-
- // The icon painted for the child processs.
- // TODO(jcampan): we should have plugin specific icons for well-known
- // plugins.
- static SkBitmap* default_icon_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerChildProcessResource);
-};
-
-class TaskManagerChildProcessResourceProvider
- : public TaskManager::ResourceProvider,
- public NotificationObserver {
- public:
- explicit TaskManagerChildProcessResourceProvider(TaskManager* task_manager);
-
- virtual TaskManager::Resource* GetResource(int origin_pid,
- int render_process_host_id,
- int routing_id);
- virtual void StartUpdating();
- virtual void StopUpdating();
-
- // NotificationObserver method:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Retrieves the current ChildProcessInfo (performed in the IO thread).
- virtual void RetrieveChildProcessInfo();
-
- // Notifies the UI thread that the ChildProcessInfo have been retrieved.
- virtual void ChildProcessInfoRetreived();
-
- // Whether we are currently reporting to the task manager. Used to ignore
- // notifications sent after StopUpdating().
- bool updating_;
-
- // The list of ChildProcessInfo retrieved when starting the update.
- std::vector<ChildProcessInfo> existing_child_process_info_;
-
- private:
- virtual ~TaskManagerChildProcessResourceProvider();
-
- void Add(ChildProcessInfo child_process_info);
- void Remove(ChildProcessInfo child_process_info);
-
- void AddToTaskManager(ChildProcessInfo child_process_info);
-
- TaskManager* task_manager_;
-
- // Maps the actual resources (the ChildProcessInfo) to the Task Manager
- // resources.
- std::map<ChildProcessInfo, TaskManagerChildProcessResource*> resources_;
-
- // Maps the pids to the resources (used for quick access to the resource on
- // byte read notifications).
- std::map<int, TaskManagerChildProcessResource*> pid_to_resources_;
-
- // A scoped container for notification registries.
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerChildProcessResourceProvider);
-};
-
-class TaskManagerExtensionProcessResource : public TaskManager::Resource {
- public:
- explicit TaskManagerExtensionProcessResource(ExtensionHost* extension_host);
- ~TaskManagerExtensionProcessResource();
-
- // TaskManagerResource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
- bool SupportNetworkUsage() const { return true; }
- void SetSupportNetworkUsage() { NOTREACHED(); }
- const Extension* GetExtension() const;
-
- // Returns the pid of the extension process.
- int process_id() const { return pid_; }
-
- private:
- // The icon painted for the extension process.
- static SkBitmap* default_icon_;
-
- ExtensionHost* extension_host_;
-
- // Cached data about the extension.
- base::ProcessHandle process_handle_;
- int pid_;
- std::wstring title_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerExtensionProcessResource);
-};
-
-class TaskManagerExtensionProcessResourceProvider
- : public TaskManager::ResourceProvider,
- public NotificationObserver {
- public:
- explicit TaskManagerExtensionProcessResourceProvider(
- TaskManager* task_manager);
-
- virtual TaskManager::Resource* GetResource(int origin_pid,
- int render_process_host_id,
- int routing_id);
- virtual void StartUpdating();
- virtual void StopUpdating();
-
- // NotificationObserver method:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- private:
- virtual ~TaskManagerExtensionProcessResourceProvider();
-
- void AddToTaskManager(ExtensionHost* extension_host);
- void RemoveFromTaskManager(ExtensionHost* extension_host);
-
- TaskManager* task_manager_;
-
- // Maps the actual resources (ExtensionHost*) to the Task Manager resources.
- std::map<ExtensionHost*, TaskManagerExtensionProcessResource*> resources_;
-
- // Maps the pids to the resources (used for quick access to the resource on
- // byte read notifications).
- std::map<int, TaskManagerExtensionProcessResource*> pid_to_resources_;
-
- // A scoped container for notification registries.
- NotificationRegistrar registrar_;
-
- bool updating_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerExtensionProcessResourceProvider);
-};
-
-class TaskManagerNotificationResource : public TaskManager::Resource {
- public:
- explicit TaskManagerNotificationResource(BalloonHost* balloon_host);
- ~TaskManagerNotificationResource();
-
- // TaskManager::Resource interface
- std::wstring GetTitle() const { return title_; }
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
- virtual bool SupportNetworkUsage() const { return false; }
- virtual void SetSupportNetworkUsage() { }
-
- private:
- // The icon painted for notifications. .
- static SkBitmap* default_icon_;
-
- // Non-owned pointer to the balloon host.
- BalloonHost* balloon_host_;
-
- // Cached data about the balloon host.
- base::ProcessHandle process_handle_;
- int pid_;
- std::wstring title_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerNotificationResource);
-};
-
-class TaskManagerNotificationResourceProvider
- : public TaskManager::ResourceProvider,
- public NotificationObserver {
- public:
- explicit TaskManagerNotificationResourceProvider(TaskManager* task_manager);
-
- // TaskManager::ResourceProvider interface
- virtual TaskManager::Resource* GetResource(int origin_pid,
- int render_process_host_id,
- int routing_id);
- virtual void StartUpdating();
- virtual void StopUpdating();
-
- // NotificationObserver interface
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- private:
- virtual ~TaskManagerNotificationResourceProvider();
-
- void AddToTaskManager(BalloonHost* balloon_host);
- void RemoveFromTaskManager(BalloonHost* balloon_host);
-
- TaskManager* task_manager_;
-
- // Maps the actual resources (BalloonHost*) to the Task Manager resources.
- std::map<BalloonHost*, TaskManagerNotificationResource*> resources_;
-
- // A scoped container for notification registries.
- NotificationRegistrar registrar_;
-
- bool updating_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerNotificationResourceProvider);
-};
-
-class TaskManagerBrowserProcessResource : public TaskManager::Resource {
- public:
- TaskManagerBrowserProcessResource();
- ~TaskManagerBrowserProcessResource();
-
- // TaskManagerResource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
-
- bool SupportNetworkUsage() const { return true; }
- void SetSupportNetworkUsage() { NOTREACHED(); }
-
- bool ReportsSqliteMemoryUsed() const { return true; }
- size_t SqliteMemoryUsedBytes() const;
-
- // Returns the pid of the browser process.
- int process_id() const { return pid_; }
-
- private:
- base::ProcessHandle process_;
- int pid_;
- mutable std::wstring title_;
-
- static SkBitmap* default_icon_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerBrowserProcessResource);
-};
-
-class TaskManagerBrowserProcessResourceProvider
- : public TaskManager::ResourceProvider {
- public:
- explicit TaskManagerBrowserProcessResourceProvider(
- TaskManager* task_manager);
-
- virtual TaskManager::Resource* GetResource(int origin_pid,
- int render_process_host_id,
- int routing_id);
- virtual void StartUpdating();
- virtual void StopUpdating();
-
- // Whether we are currently reporting to the task manager. Used to ignore
- // notifications sent after StopUpdating().
- bool updating_;
-
- private:
- virtual ~TaskManagerBrowserProcessResourceProvider();
-
- void AddToTaskManager(ChildProcessInfo child_process_info);
-
- TaskManager* task_manager_;
- TaskManagerBrowserProcessResource resource_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerBrowserProcessResourceProvider);
-};
-
-#endif // CHROME_BROWSER_TASK_MANAGER_RESOURCE_PROVIDERS_H_
diff --git a/chrome/browser/task_manager_unittest.cc b/chrome/browser/task_manager_unittest.cc
deleted file mode 100644
index d586a5c..0000000
--- a/chrome/browser/task_manager_unittest.cc
+++ /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.
-
-#include "chrome/browser/task_manager.h"
-
-#include <string>
-
-#include "app/l10n_util.h"
-#include "base/message_loop.h"
-#include "base/process_util.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace {
-
-#if defined(OS_MACOSX)
-// From task_manager.cc:
-// Activity Monitor shows %cpu with one decimal digit -- be
-// consistent with that.
-const wchar_t *kZeroCPUUsage = L"0.0";
-#else
-const wchar_t *kZeroCPUUsage = L"0";
-#endif
-
-class TestResource : public TaskManager::Resource {
- public:
- TestResource() : refresh_called_(false) {}
-
- virtual std::wstring GetTitle() const { return L"test title"; }
- virtual SkBitmap GetIcon() const { return SkBitmap(); }
- virtual base::ProcessHandle GetProcess() const {
- return base::GetCurrentProcessHandle();
- }
- virtual bool SupportNetworkUsage() const { return false; }
- virtual void SetSupportNetworkUsage() { NOTREACHED(); }
- virtual void Refresh() { refresh_called_ = true; }
- bool refresh_called() const { return refresh_called_; }
- void set_refresh_called(bool refresh_called) {
- refresh_called_ = refresh_called;
- }
-
- private:
- bool refresh_called_;
-};
-
-} // namespace
-
-class TaskManagerTest : public testing::Test {
-};
-
-TEST_F(TaskManagerTest, Basic) {
- TaskManager task_manager;
- TaskManagerModel* model = task_manager.model_;
- EXPECT_EQ(0, model->ResourceCount());
-}
-
-TEST_F(TaskManagerTest, Resources) {
- TaskManager task_manager;
- TaskManagerModel* model = task_manager.model_;
-
- TestResource resource1, resource2;
-
- task_manager.AddResource(&resource1);
- ASSERT_EQ(1, model->ResourceCount());
- EXPECT_TRUE(model->IsResourceFirstInGroup(0));
- EXPECT_STREQ(L"test title", model->GetResourceTitle(0).c_str());
- EXPECT_STREQ(l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT).c_str(),
- model->GetResourceNetworkUsage(0).c_str());
- EXPECT_STREQ(kZeroCPUUsage, model->GetResourceCPUUsage(0).c_str());
-
- task_manager.AddResource(&resource2); // Will be in the same group.
- ASSERT_EQ(2, model->ResourceCount());
- EXPECT_TRUE(model->IsResourceFirstInGroup(0));
- EXPECT_FALSE(model->IsResourceFirstInGroup(1));
- EXPECT_STREQ(L"test title", model->GetResourceTitle(1).c_str());
- EXPECT_STREQ(l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT).c_str(),
- model->GetResourceNetworkUsage(1).c_str());
- EXPECT_STREQ(kZeroCPUUsage, model->GetResourceCPUUsage(1).c_str());
-
- task_manager.RemoveResource(&resource1);
- // Now resource2 will be first in group.
- ASSERT_EQ(1, model->ResourceCount());
- EXPECT_TRUE(model->IsResourceFirstInGroup(0));
- EXPECT_STREQ(L"test title", model->GetResourceTitle(0).c_str());
- EXPECT_STREQ(l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT).c_str(),
- model->GetResourceNetworkUsage(0).c_str());
- EXPECT_STREQ(kZeroCPUUsage, model->GetResourceCPUUsage(0).c_str());
-
- task_manager.RemoveResource(&resource2);
- EXPECT_EQ(0, model->ResourceCount());
-}
-
-// Tests that the model is calling Refresh() on its resources.
-TEST_F(TaskManagerTest, RefreshCalled) {
- MessageLoop loop;
- TaskManager task_manager;
- TaskManagerModel* model = task_manager.model_;
- TestResource resource;
-
- task_manager.AddResource(&resource);
- ASSERT_FALSE(resource.refresh_called());
- model->update_state_ = TaskManagerModel::TASK_PENDING;
- model->Refresh();
- ASSERT_TRUE(resource.refresh_called());
- task_manager.RemoveResource(&resource);
-}
diff --git a/chrome/browser/toolbar_model.cc b/chrome/browser/toolbar_model.cc
index b7a42ed..e8cdaaf 100644
--- a/chrome/browser/toolbar_model.cc
+++ b/chrome/browser/toolbar_model.cc
@@ -4,11 +4,11 @@
#include "chrome/browser/toolbar_model.h"
-#include "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/cert_store.h"
-#include "chrome/browser/pref_service.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"
@@ -33,13 +33,12 @@ ToolbarModel::~ToolbarModel() {
// ToolbarModel Implementation.
std::wstring ToolbarModel::GetText() const {
GURL url(chrome::kAboutBlankURL);
- std::wstring languages; // Empty if we don't have a |navigation_controller|.
+ std::string languages; // Empty if we don't have a |navigation_controller|.
NavigationController* navigation_controller = GetNavigationController();
if (navigation_controller) {
- languages = UTF8ToWide(
- navigation_controller->profile()->GetPrefs()->GetString(
- prefs::kAcceptLanguages));
+ 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.
@@ -54,8 +53,8 @@ std::wstring ToolbarModel::GetText() const {
// and pastes it into another program, that program may think the URL ends at
// the space.
return AutocompleteInput::FormattedStringWithEquivalentMeaning(url,
- net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
- UnescapeRule::NORMAL, NULL, NULL, NULL));
+ UTF16ToWideHack(net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
+ UnescapeRule::NORMAL, NULL, NULL, NULL)));
}
ToolbarModel::SecurityLevel ToolbarModel::GetSecurityLevel() const {
diff --git a/chrome/browser/toolbar_model.h b/chrome/browser/toolbar_model.h
index 5773e3c..06050c1 100644
--- a/chrome/browser/toolbar_model.h
+++ b/chrome/browser/toolbar_model.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TOOLBAR_MODEL_H__
#define CHROME_BROWSER_TOOLBAR_MODEL_H__
+#pragma once
#include <string>
@@ -11,7 +12,6 @@
class Browser;
class NavigationController;
-class NavigationEntry;
// This class is the model used by the toolbar, location bar and autocomplete
// edit. It populates its states from the current navigation entry retrieved
diff --git a/chrome/browser/translate/languages_menu_model.h b/chrome/browser/translate/languages_menu_model.h
index 4b12fe8..8f91076 100644
--- a/chrome/browser/translate/languages_menu_model.h
+++ b/chrome/browser/translate/languages_menu_model.h
@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_TRANSLATE_LANGUAGES_MENU_MODEL_H_
#define CHROME_BROWSER_TRANSLATE_LANGUAGES_MENU_MODEL_H_
+#pragma once
#include "app/menus/simple_menu_model.h"
class TranslateInfoBarDelegate;
-class String16;
// A menu model that builds the contents of the language menus in the translate
// infobar. This menu has only one level (no submenus).
diff --git a/chrome/browser/translate/options_menu_model.cc b/chrome/browser/translate/options_menu_model.cc
index cd1ae2e..56b707b 100644
--- a/chrome/browser/translate/options_menu_model.cc
+++ b/chrome/browser/translate/options_menu_model.cc
@@ -8,6 +8,7 @@
#include "base/histogram.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "grit/generated_resources.h"
@@ -23,17 +24,20 @@ OptionsMenuModel::OptionsMenuModel(
translate_delegate->target_language_index());
// Populate the menu.
- AddCheckItem(IDC_TRANSLATE_OPTIONS_ALWAYS,
- l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_OPTIONS_ALWAYS,
- original_language, target_language));
- AddCheckItem(IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_LANG,
- l10n_util::GetStringFUTF16(
- IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_LANG,
- original_language));
- AddCheckItem(IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_SITE,
- l10n_util::GetStringUTF16(
- IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_SITE));
- AddSeparator();
+ // Incognito mode does not get any preferences related items.
+ if (!translate_delegate->tab_contents()->profile()->IsOffTheRecord()) {
+ AddCheckItem(IDC_TRANSLATE_OPTIONS_ALWAYS,
+ l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_OPTIONS_ALWAYS,
+ original_language, target_language));
+ AddCheckItem(IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_LANG,
+ l10n_util::GetStringFUTF16(
+ IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_LANG,
+ original_language));
+ AddCheckItem(IDC_TRANSLATE_OPTIONS_NEVER_TRANSLATE_SITE,
+ l10n_util::GetStringUTF16(
+ IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_SITE));
+ AddSeparator();
+ }
AddItem(IDC_TRANSLATE_REPORT_BAD_LANGUAGE_DETECTION,
l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_OPTIONS_REPORT_ERROR,
original_language));
diff --git a/chrome/browser/translate/options_menu_model.h b/chrome/browser/translate/options_menu_model.h
index 9171057..68f9297 100644
--- a/chrome/browser/translate/options_menu_model.h
+++ b/chrome/browser/translate/options_menu_model.h
@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_TRANSLATE_OPTIONS_MENU_MODEL_H_
#define CHROME_BROWSER_TRANSLATE_OPTIONS_MENU_MODEL_H_
+#pragma once
#include "app/menus/simple_menu_model.h"
class TranslateInfoBarDelegate;
-class String16;
// A menu model that builds the contents of the options menu in the translate
// infobar. This menu has only one level (no submenus).
diff --git a/chrome/browser/translate/page_translated_details.h b/chrome/browser/translate/page_translated_details.h
index 61a43d4..0d6c18a 100644
--- a/chrome/browser/translate/page_translated_details.h
+++ b/chrome/browser/translate/page_translated_details.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TRANSLATE_PAGE_TRANSLATED_DETAILS_H_
#define CHROME_BROWSER_TRANSLATE_PAGE_TRANSLATED_DETAILS_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/translate/translate_infobar_delegate.cc b/chrome/browser/translate/translate_infobar_delegate.cc
index e1a801b..af73d11 100644
--- a/chrome/browser/translate/translate_infobar_delegate.cc
+++ b/chrome/browser/translate/translate_infobar_delegate.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/translate/translate_infobar_view.h"
#include "chrome/browser/translate/translate_manager.h"
+#include "chrome/common/chrome_constants.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -24,7 +25,13 @@ TranslateInfoBarDelegate* TranslateInfoBarDelegate::CreateDelegate(
const std::string& original_language,
const std::string& target_language) {
DCHECK(type != TRANSLATION_ERROR);
- if (!TranslateManager::IsSupportedLanguage(original_language) ||
+ // The original language can only be "unknown" for the "translating"
+ // infobar, which is the case when the user started a translation from the
+ // context menu.
+ DCHECK(type == TRANSLATING ||
+ original_language != chrome::kUnknownLanguageCode);
+ if ((original_language != chrome::kUnknownLanguageCode &&
+ !TranslateManager::IsSupportedLanguage(original_language)) ||
!TranslateManager::IsSupportedLanguage(target_language)) {
return NULL;
}
@@ -32,7 +39,6 @@ TranslateInfoBarDelegate* TranslateInfoBarDelegate::CreateDelegate(
new TranslateInfoBarDelegate(type, TranslateErrors::NONE,
tab_contents,
original_language, target_language);
- DCHECK(delegate->original_language_index() != -1);
DCHECK(delegate->target_language_index() != -1);
return delegate;
}
@@ -111,6 +117,8 @@ string16 TranslateInfoBarDelegate::GetLanguageDisplayableNameAt(
}
std::string TranslateInfoBarDelegate::GetOriginalLanguageCode() const {
+ if (original_language_index() == -1)
+ return chrome::kUnknownLanguageCode;
return GetLanguageCodeAt(original_language_index());
}
@@ -142,8 +150,10 @@ bool TranslateInfoBarDelegate::IsError() {
void TranslateInfoBarDelegate::Translate() {
const std::string& original_language_code = GetOriginalLanguageCode();
- prefs_.ResetTranslationDeniedCount(original_language_code);
- prefs_.IncrementTranslationAcceptedCount(original_language_code);
+ if (!tab_contents()->profile()->IsOffTheRecord()) {
+ prefs_.ResetTranslationDeniedCount(original_language_code);
+ prefs_.IncrementTranslationAcceptedCount(original_language_code);
+ }
Singleton<TranslateManager>::get()->TranslatePage(
tab_contents_,
@@ -163,8 +173,10 @@ void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
void TranslateInfoBarDelegate::TranslationDeclined() {
const std::string& original_language_code = GetOriginalLanguageCode();
- prefs_.ResetTranslationAcceptedCount(original_language_code);
- prefs_.IncrementTranslationDeniedCount(original_language_code);
+ if (!tab_contents()->profile()->IsOffTheRecord()) {
+ prefs_.ResetTranslationAcceptedCount(original_language_code);
+ prefs_.IncrementTranslationDeniedCount(original_language_code);
+ }
// Remember that the user declined the translation so as to prevent showing a
// translate infobar for that page again. (TranslateManager initiates
@@ -323,13 +335,21 @@ void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
tab_contents_, GetOriginalLanguageCode(), GetTargetLanguageCode());
}
+bool TranslateInfoBarDelegate::ShouldShowMessageInfoBarButton() {
+ return !GetMessageInfoBarButtonText().empty();
+}
+
bool TranslateInfoBarDelegate::ShouldShowNeverTranslateButton() {
DCHECK(type_ == BEFORE_TRANSLATE);
+ if (tab_contents()->profile()->IsOffTheRecord())
+ return false;
return prefs_.GetTranslationDeniedCount(GetOriginalLanguageCode()) >= 3;
}
bool TranslateInfoBarDelegate::ShouldShowAlwaysTranslateButton() {
DCHECK(type_ == BEFORE_TRANSLATE);
+ if (tab_contents()->profile()->IsOffTheRecord())
+ return false;
return prefs_.GetTranslationAcceptedCount(GetOriginalLanguageCode()) >= 3;
}
diff --git a/chrome/browser/translate/translate_infobar_delegate.h b/chrome/browser/translate/translate_infobar_delegate.h
index 4b1b1e9..0359caf 100644
--- a/chrome/browser/translate/translate_infobar_delegate.h
+++ b/chrome/browser/translate/translate_infobar_delegate.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_DELEGATE_H_
+#pragma once
#include <string>
#include <vector>
@@ -124,6 +125,7 @@ class TranslateInfoBarDelegate : public InfoBarDelegate {
string16 GetMessageInfoBarText();
string16 GetMessageInfoBarButtonText();
void MessageInfoBarButtonPressed();
+ bool ShouldShowMessageInfoBarButton();
// Called by the before translate infobar to figure-out if it should show
// an extra button to let the user black-list/white-list that language (based
diff --git a/chrome/browser/translate/translate_infobar_view.h b/chrome/browser/translate/translate_infobar_view.h
index c1898e7..2b4af28 100644
--- a/chrome/browser/translate/translate_infobar_view.h
+++ b/chrome/browser/translate/translate_infobar_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_VIEW_H_
#define CHROME_BROWSER_TRANSLATE_TRANSLATE_INFOBAR_VIEW_H_
+#pragma once
// This interface should be implemented by classes that are the view (in the MVC
// sense) of the TranslateInfoBarDelegate (which is the model).
diff --git a/chrome/browser/translate/translate_manager.cc b/chrome/browser/translate/translate_manager.cc
index 48b3079..1c70dd4 100644
--- a/chrome/browser/translate/translate_manager.cc
+++ b/chrome/browser/translate/translate_manager.cc
@@ -5,13 +5,15 @@
#include "chrome/browser/translate/translate_manager.h"
#include "app/resource_bundle.h"
+#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/histogram.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_service.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"
@@ -20,9 +22,11 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/translate/page_translated_details.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "chrome/browser/translate/translate_prefs.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"
@@ -187,6 +191,13 @@ void TranslateManager::Observe(NotificationType type,
NOTREACHED();
return;
}
+ if (!load_details->is_main_frame &&
+ controller->tab_contents()->language_state().translation_declined()) {
+ // Some sites (such as Google map) may trigger sub-frame navigations
+ // when the user interacts with the page. We don't want to show a new
+ // infobar if the user already dismissed one in that case.
+ return;
+ }
if (entry->transition_type() != PageTransition::RELOAD &&
load_details->type != NavigationType::SAME_PAGE) {
return;
@@ -238,11 +249,11 @@ void TranslateManager::Observe(NotificationType type,
// We should know about this profile since we are listening for
// notifications on it.
DCHECK(count > 0);
- profile->GetPrefs()->RemovePrefObserver(prefs::kAcceptLanguages, this);
+ pref_change_registrar_.Remove(prefs::kAcceptLanguages, this);
break;
}
case NotificationType::PREF_CHANGED: {
- DCHECK(*Details<std::wstring>(details).ptr() == prefs::kAcceptLanguages);
+ DCHECK(*Details<std::string>(details).ptr() == prefs::kAcceptLanguages);
PrefService* prefs = Source<PrefService>(source).ptr();
InitAcceptLanguages(prefs);
break;
@@ -331,6 +342,13 @@ void TranslateManager::InitiateTranslation(TabContents* tab,
if (!prefs->GetBoolean(prefs::kEnableTranslate))
return;
+ pref_change_registrar_.Init(prefs);
+
+ // Allow disabling of translate from the command line to assist with
+ // automated browser testing.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableTranslate))
+ return;
+
NavigationEntry* entry = tab->controller().GetActiveEntry();
if (!entry) {
// This can happen for popups created with window.open("").
@@ -403,16 +421,17 @@ void TranslateManager::TranslatePage(TabContents* tab_contents,
return;
}
- TranslateInfoBarDelegate* infobar = GetTranslateInfoBarDelegate(tab_contents);
- if (infobar) {
- // We don't show the translating infobar if no translate infobar is already
- // showing (that is the case when the translation was triggered by the
- // "always translate" for example).
- infobar = TranslateInfoBarDelegate::CreateDelegate(
- TranslateInfoBarDelegate::TRANSLATING, tab_contents,
- source_lang, target_lang);
- ShowInfoBar(tab_contents, infobar);
+ TranslateInfoBarDelegate* infobar = TranslateInfoBarDelegate::CreateDelegate(
+ TranslateInfoBarDelegate::TRANSLATING, tab_contents,
+ source_lang, target_lang);
+ if (!infobar) {
+ // This means the source or target languages are not supported, which should
+ // not happen as we won't show a translate infobar or have the translate
+ // context menu activated in such cases.
+ NOTREACHED();
+ return;
}
+ ShowInfoBar(tab_contents, infobar);
if (!translate_script_.empty()) {
DoTranslatePage(tab_contents, translate_script_, source_lang, target_lang);
@@ -462,7 +481,8 @@ void TranslateManager::ReportLanguageDetectionError(TabContents* tab_contents) {
}
browser->AddTabWithURL(GURL(report_error_url), GURL(),
PageTransition::AUTO_BOOKMARK, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ NULL);
}
void TranslateManager::DoTranslatePage(TabContents* tab,
@@ -516,7 +536,7 @@ bool TranslateManager::IsAcceptLanguage(TabContents* tab,
notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
Source<Profile>(tab->profile()));
// Also start listening for changes in the accept languages.
- tab->profile()->GetPrefs()->AddPrefObserver(prefs::kAcceptLanguages, this);
+ pref_change_registrar_.Add(prefs::kAcceptLanguages, this);
iter = accept_languages_.find(pref_service);
}
diff --git a/chrome/browser/translate/translate_manager.h b/chrome/browser/translate/translate_manager.h
index 54debf4..3ddcabf 100644
--- a/chrome/browser/translate/translate_manager.h
+++ b/chrome/browser/translate/translate_manager.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_MANAGER_H_
#define CHROME_BROWSER_TRANSLATE_TRANSLATE_MANAGER_H_
+#pragma once
#include <map>
#include <set>
@@ -13,6 +14,7 @@
#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"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -152,6 +154,7 @@ class TranslateManager : public NotificationObserver,
TabContents* tab);
NotificationRegistrar notification_registrar_;
+ PrefChangeRegistrar pref_change_registrar_;
// A map that associates a profile with its parsed "accept languages".
typedef std::set<std::string> LanguageSet;
diff --git a/chrome/browser/translate/translate_manager_unittest.cc b/chrome/browser/translate/translate_manager_unittest.cc
index 1b1598d..f578b3f 100644
--- a/chrome/browser/translate/translate_manager_unittest.cc
+++ b/chrome/browser/translate/translate_manager_unittest.cc
@@ -6,8 +6,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/renderer_host/mock_render_process_host.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "chrome/browser/translate/translate_manager.h"
#include "chrome/browser/translate/translate_prefs.h"
@@ -21,6 +25,7 @@
#include "chrome/common/render_messages.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
#include "chrome/test/testing_browser_process.h"
+#include "chrome/test/testing_profile.h"
#include "grit/generated_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/cld/languages/public/languages.h"
@@ -38,11 +43,13 @@ class TranslateManagerTest : public RenderViewHostTestHarness,
// Simluates navigating to a page and getting the page contents and language
// for that navigation.
- void SimulateNavigation(const GURL& url, int page_id,
+ void SimulateNavigation(const GURL& url,
const std::string& contents,
const std::string& lang,
bool page_translatable) {
NavigateAndCommit(url);
+ int page_id = RenderViewHostTestHarness::contents()->controller().
+ GetLastCommittedEntry()->page_id();
SimulateOnPageContents(url, page_id, contents, lang, page_translatable);
}
@@ -185,12 +192,12 @@ class TranslateManagerTest : public RenderViewHostTestHarness,
std::string());
}
- void SetPrefObserverExpectation(const wchar_t* path) {
+ void SetPrefObserverExpectation(const char* path) {
EXPECT_CALL(
pref_observer_,
Observe(NotificationType(NotificationType::PREF_CHANGED),
_,
- Property(&Details<std::wstring>::ptr, Pointee(path))));
+ Property(&Details<std::string>::ptr, Pointee(path))));
}
NotificationObserverMock pref_observer_;
@@ -276,7 +283,7 @@ class TestRenderViewContextMenu : public RenderViewContextMenu {
TEST_F(TranslateManagerTest, NormalTranslate) {
// Simulate navigating to a page.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// We should have an infobar.
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
@@ -300,7 +307,6 @@ TEST_F(TranslateManagerTest, NormalTranslate) {
int page_id = 0;
std::string original_lang, target_lang;
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(0, page_id);
EXPECT_EQ("fr", original_lang);
EXPECT_EQ("en", target_lang);
@@ -318,7 +324,6 @@ TEST_F(TranslateManagerTest, NormalTranslate) {
std::string new_original_lang = infobar->GetLanguageCodeAt(0);
infobar->SetOriginalLanguage(0);
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(0, page_id);
EXPECT_EQ(new_original_lang, original_lang);
EXPECT_EQ("en", target_lang);
// Simulate the render notifying the translation has been done.
@@ -334,7 +339,6 @@ TEST_F(TranslateManagerTest, NormalTranslate) {
std::string new_target_lang = infobar->GetLanguageCodeAt(1);
infobar->SetTargetLanguage(1);
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(0, page_id);
EXPECT_EQ(new_original_lang, original_lang);
EXPECT_EQ(new_target_lang, target_lang);
// Simulate the render notifying the translation has been done.
@@ -347,7 +351,7 @@ TEST_F(TranslateManagerTest, NormalTranslate) {
TEST_F(TranslateManagerTest, TranslateScriptNotAvailable) {
// Simulate navigating to a page.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// We should have an infobar.
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
@@ -374,7 +378,7 @@ TEST_F(TranslateManagerTest, TranslateScriptNotAvailable) {
TEST_F(TranslateManagerTest, TranslateUnknownLanguage) {
// Simulate navigating to a page ("und" is the string returned by the CLD for
// languages it does not recognize).
- SimulateNavigation(GURL("http://www.google.mys"), 0, "G00g1e", "und", true);
+ SimulateNavigation(GURL("http://www.google.mys"), "G00g1e", "und", true);
// We should not have an infobar as we don't know the language.
ASSERT_TRUE(GetTranslateInfoBar() == NULL);
@@ -384,7 +388,15 @@ TEST_F(TranslateManagerTest, TranslateUnknownLanguage) {
TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
- SimulateURLFetch(true); // Simulate receiving the translate script.
+
+ // To test that bug #49018 if fixed, make sure we deal correctly with errors.
+ SimulateURLFetch(false); // Simulate a failure to fetch the translate script.
+ TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+ ASSERT_TRUE(infobar != NULL);
+ EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
+ EXPECT_TRUE(infobar->IsError());
+ infobar->MessageInfoBarButtonPressed();
+ SimulateURLFetch(true); // This time succeed.
// Simulate the render notifying the translation has been done, the server
// having detected the page was in a known and supported language.
@@ -392,7 +404,7 @@ TEST_F(TranslateManagerTest, TranslateUnknownLanguage) {
TranslateErrors::NONE));
// The after translate infobar should be showing.
- TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+ infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
EXPECT_EQ(TranslateInfoBarDelegate::AFTER_TRANSLATE, infobar->type());
EXPECT_EQ("fr", infobar->GetOriginalLanguageCode());
@@ -400,8 +412,7 @@ TEST_F(TranslateManagerTest, TranslateUnknownLanguage) {
// Let's run the same steps but this time the server detects the page is
// already in English.
- SimulateNavigation(GURL("http://www.google.com"), 1, "The Google", "und",
- true);
+ SimulateNavigation(GURL("http://www.google.com"), "The Google", "und", true);
menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
@@ -414,8 +425,7 @@ TEST_F(TranslateManagerTest, TranslateUnknownLanguage) {
// Let's run the same steps again but this time the server fails to detect the
// page's language (it returns an empty string).
- SimulateNavigation(GURL("http://www.google.com"), 2, "The Google", "und",
- true);
+ SimulateNavigation(GURL("http://www.google.com"), "The Google", "und", true);
menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
@@ -500,7 +510,7 @@ TEST_F(TranslateManagerTest, TestAllLanguages) {
// Tests auto-translate on page.
TEST_F(TranslateManagerTest, AutoTranslateOnNavigate) {
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// Simulate the user translating.
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
@@ -513,7 +523,7 @@ TEST_F(TranslateManagerTest, AutoTranslateOnNavigate) {
// Now navigate to a new page in the same language.
process()->sink().ClearMessages();
- SimulateNavigation(GURL("http://news.google.fr"), 1, "Les news", "fr", true);
+ SimulateNavigation(GURL("http://news.google.fr"), "Les news", "fr", true);
// This should have automatically triggered a translation.
int page_id = 0;
@@ -525,7 +535,7 @@ TEST_F(TranslateManagerTest, AutoTranslateOnNavigate) {
// Now navigate to a page in a different language.
process()->sink().ClearMessages();
- SimulateNavigation(GURL("http://news.google.es"), 1, "Las news", "es", true);
+ SimulateNavigation(GURL("http://news.google.es"), "Las news", "es", true);
// This should not have triggered a translate.
EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
@@ -534,7 +544,7 @@ TEST_F(TranslateManagerTest, AutoTranslateOnNavigate) {
// Tests that multiple OnPageContents do not cause multiple infobars.
TEST_F(TranslateManagerTest, MultipleOnPageContents) {
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// Simulate clicking 'Nope' (don't translate).
EXPECT_TRUE(DenyTranslation());
@@ -546,7 +556,7 @@ TEST_F(TranslateManagerTest, MultipleOnPageContents) {
EXPECT_EQ(0, contents()->infobar_delegate_count());
// Do the same steps but simulate closing the infobar this time.
- SimulateNavigation(GURL("http://www.youtube.fr"), 1, "Le YouTube", "fr",
+ SimulateNavigation(GURL("http://www.youtube.fr"), "Le YouTube", "fr",
true);
EXPECT_TRUE(CloseTranslateInfoBar());
EXPECT_EQ(0, contents()->infobar_delegate_count());
@@ -558,7 +568,7 @@ TEST_F(TranslateManagerTest, MultipleOnPageContents) {
// Test that reloading the page brings back the infobar.
TEST_F(TranslateManagerTest, Reload) {
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// Close the infobar.
EXPECT_TRUE(CloseTranslateInfoBar());
@@ -585,7 +595,7 @@ TEST_F(TranslateManagerTest, ReloadFromLocationBar) {
GURL url("http://www.google.fr");
// Simulate navigating to a page and getting its language.
- SimulateNavigation(url, 0, "Le Google", "fr", true);
+ SimulateNavigation(url, "Le Google", "fr", true);
// Close the infobar.
EXPECT_TRUE(CloseTranslateInfoBar());
@@ -609,41 +619,68 @@ TEST_F(TranslateManagerTest, ReloadFromLocationBar) {
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}
-// Tests that a close translate infobar does not reappear when navigating
+// Tests that a closed translate infobar does not reappear when navigating
// in-page.
TEST_F(TranslateManagerTest, CloseInfoBarInPageNavigation) {
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// Close the infobar.
EXPECT_TRUE(CloseTranslateInfoBar());
// Navigate in page, no infobar should be shown.
- SimulateNavigation(GURL("http://www.google.fr/#ref1"), 0, "Le Google", "fr",
+ SimulateNavigation(GURL("http://www.google.fr/#ref1"), "Le Google", "fr",
+ true);
+ EXPECT_TRUE(GetTranslateInfoBar() == NULL);
+
+ // Navigate out of page, a new infobar should show.
+ SimulateNavigation(GURL("http://www.google.fr/foot"), "Le Google", "fr",
true);
+ EXPECT_TRUE(GetTranslateInfoBar() != NULL);
+}
+
+// Tests that a closed translate infobar does not reappear when navigating
+// in a subframe. (http://crbug.com/48215)
+TEST_F(TranslateManagerTest, CloseInfoBarInSubframeNavigation) {
+ // Simulate navigating to a page and getting its language.
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
+
+ // Close the infobar.
+ EXPECT_TRUE(CloseTranslateInfoBar());
+
+ // Simulate a sub-frame auto-navigating.
+ rvh()->SendNavigateWithTransition(1, GURL("http://pub.com"),
+ PageTransition::AUTO_SUBFRAME);
+ EXPECT_TRUE(GetTranslateInfoBar() == NULL);
+
+ // Simulate the user navigating in a sub-frame.
+ rvh()->SendNavigateWithTransition(2, GURL("http://pub.com"),
+ PageTransition::MANUAL_SUBFRAME);
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
// Navigate out of page, a new infobar should show.
- SimulateNavigation(GURL("http://www.google.fr/foot"), 0, "Le Google", "fr",
+ SimulateNavigation(GURL("http://www.google.fr/foot"), "Le Google", "fr",
true);
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}
+
+
// Tests that denying translation is sticky when navigating in page.
TEST_F(TranslateManagerTest, DenyTranslateInPageNavigation) {
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// Simulate clicking 'Nope' (don't translate).
EXPECT_TRUE(DenyTranslation());
// Navigate in page, no infobar should be shown.
- SimulateNavigation(GURL("http://www.google.fr/#ref1"), 0, "Le Google", "fr",
+ SimulateNavigation(GURL("http://www.google.fr/#ref1"), "Le Google", "fr",
true);
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
// Navigate out of page, a new infobar should show.
- SimulateNavigation(GURL("http://www.google.fr/foot"), 0, "Le Google", "fr",
+ SimulateNavigation(GURL("http://www.google.fr/foot"), "Le Google", "fr",
true);
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}
@@ -652,7 +689,7 @@ TEST_F(TranslateManagerTest, DenyTranslateInPageNavigation) {
// return when navigating in page.
TEST_F(TranslateManagerTest, TranslateCloseInfoBarInPageNavigation) {
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// Simulate the user translating.
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
@@ -666,7 +703,7 @@ TEST_F(TranslateManagerTest, TranslateCloseInfoBarInPageNavigation) {
EXPECT_TRUE(CloseTranslateInfoBar());
// Navigate in page, no infobar should be shown.
- SimulateNavigation(GURL("http://www.google.fr/#ref1"), 0, "Le Google", "fr",
+ SimulateNavigation(GURL("http://www.google.fr/#ref1"), "Le Google", "fr",
true);
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
@@ -674,7 +711,7 @@ TEST_F(TranslateManagerTest, TranslateCloseInfoBarInPageNavigation) {
// Note that we navigate to a page in a different language so we don't trigger
// the auto-translate feature (it would translate the page automatically and
// the before translate inforbar would not be shown).
- SimulateNavigation(GURL("http://www.google.de"), 0, "Das Google", "de", true);
+ SimulateNavigation(GURL("http://www.google.de"), "Das Google", "de", true);
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}
@@ -682,7 +719,7 @@ TEST_F(TranslateManagerTest, TranslateCloseInfoBarInPageNavigation) {
// in-page.
TEST_F(TranslateManagerTest, TranslateInPageNavigation) {
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// Simulate the user translating.
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
@@ -697,7 +734,7 @@ TEST_F(TranslateManagerTest, TranslateInPageNavigation) {
// Navigate in page, the same infobar should still be shown.
ClearRemovedInfoBars();
- SimulateNavigation(GURL("http://www.google.fr/#ref1"), 0, "Le Google", "fr",
+ SimulateNavigation(GURL("http://www.google.fr/#ref1"), "Le Google", "fr",
true);
EXPECT_FALSE(InfoBarRemoved());
EXPECT_EQ(infobar, GetTranslateInfoBar());
@@ -705,7 +742,7 @@ TEST_F(TranslateManagerTest, TranslateInPageNavigation) {
// Navigate out of page, a new infobar should show.
// See note in TranslateCloseInfoBarInPageNavigation test on why it is
// important to navigate to a page in a different language for this test.
- SimulateNavigation(GURL("http://www.google.de"), 0, "Das Google", "de", true);
+ SimulateNavigation(GURL("http://www.google.de"), "Das Google", "de", true);
// The old infobar is gone.
EXPECT_TRUE(CheckInfoBarRemovedAndReset(infobar));
// And there is a new one.
@@ -716,7 +753,7 @@ TEST_F(TranslateManagerTest, TranslateInPageNavigation) {
// unsupported language.
TEST_F(TranslateManagerTest, CLDReportsUnsupportedPageLanguage) {
// Simulate navigating to a page and getting an unsupported language.
- SimulateNavigation(GURL("http://www.google.com"), 0, "Google", "qbz", true);
+ SimulateNavigation(GURL("http://www.google.com"), "Google", "qbz", true);
// No info-bar should be shown.
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
@@ -727,8 +764,7 @@ TEST_F(TranslateManagerTest, CLDReportsUnsupportedPageLanguage) {
// The translation server might return a language we don't support.
TEST_F(TranslateManagerTest, ServerReportsUnsupportedLanguage) {
// Simulate navigating to a page and translating it.
- SimulateNavigation(GURL("http://mail.google.fr"), 0, "Le Google", "fr",
- true);
+ SimulateNavigation(GURL("http://mail.google.fr"), "Le Google", "fr", true);
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
process()->sink().ClearMessages();
@@ -768,7 +804,7 @@ TEST_F(TranslateManagerTest, UnsupportedUILanguage) {
// Simulate navigating to a page in a language supported by the translate
// server.
- SimulateNavigation(GURL("http://www.google.com"), 0, "Google", "en", true);
+ SimulateNavigation(GURL("http://www.google.com"), "Google", "en", true);
// No info-bar should be shown.
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
@@ -783,7 +819,7 @@ TEST_F(TranslateManagerTest, TranslateEnabledPref) {
prefs->SetBoolean(prefs::kEnableTranslate, true);
// Simulate navigating to a page and getting its language.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// An infobar should be shown.
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
@@ -809,15 +845,17 @@ TEST_F(TranslateManagerTest, TranslateEnabledPref) {
TEST_F(TranslateManagerTest, NeverTranslateLanguagePref) {
// Simulate navigating to a page and getting its language.
GURL url("http://www.google.fr");
- SimulateNavigation(url, 0, "Le Google", "fr", true);
+ SimulateNavigation(url, "Le Google", "fr", true);
// An infobar should be shown.
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
// Select never translate this language.
PrefService* prefs = contents()->profile()->GetPrefs();
- prefs->AddPrefObserver(TranslatePrefs::kPrefTranslateLanguageBlacklist,
- &pref_observer_);
+ PrefChangeRegistrar registrar;
+ registrar.Init(prefs);
+ registrar.Add(TranslatePrefs::kPrefTranslateLanguageBlacklist,
+ &pref_observer_);
TranslatePrefs translate_prefs(prefs);
EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
@@ -830,8 +868,7 @@ TEST_F(TranslateManagerTest, NeverTranslateLanguagePref) {
EXPECT_TRUE(CloseTranslateInfoBar());
// Navigate to a new page also in French.
- SimulateNavigation(GURL("http://wwww.youtube.fr"), 1, "Le YouTube", "fr",
- true);
+ SimulateNavigation(GURL("http://wwww.youtube.fr"), "Le YouTube", "fr", true);
// There should not be a translate infobar.
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
@@ -843,12 +880,10 @@ TEST_F(TranslateManagerTest, NeverTranslateLanguagePref) {
EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
// Navigate to a page in French.
- SimulateNavigation(url, 2, "Le Google", "fr", true);
+ SimulateNavigation(url, "Le Google", "fr", true);
// There should be a translate infobar.
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
- prefs->RemovePrefObserver(TranslatePrefs::kPrefTranslateLanguageBlacklist,
- &pref_observer_);
}
// Tests the "Never translate this site" pref.
@@ -856,15 +891,17 @@ TEST_F(TranslateManagerTest, NeverTranslateSitePref) {
// Simulate navigating to a page and getting its language.
GURL url("http://www.google.fr");
std::string host(url.host());
- SimulateNavigation(url, 0, "Le Google", "fr", true);
+ SimulateNavigation(url, "Le Google", "fr", true);
// An infobar should be shown.
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
// Select never translate this site.
PrefService* prefs = contents()->profile()->GetPrefs();
- prefs->AddPrefObserver(TranslatePrefs::kPrefTranslateSiteBlacklist,
- &pref_observer_);
+ PrefChangeRegistrar registrar;
+ registrar.Init(prefs);
+ registrar.Add(TranslatePrefs::kPrefTranslateSiteBlacklist,
+ &pref_observer_);
TranslatePrefs translate_prefs(prefs);
EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(host));
EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
@@ -877,8 +914,7 @@ TEST_F(TranslateManagerTest, NeverTranslateSitePref) {
EXPECT_TRUE(CloseTranslateInfoBar());
// Navigate to a new page also on the same site.
- SimulateNavigation(GURL("http://www.google.fr/hello"), 1, "Bonjour", "fr",
- true);
+ SimulateNavigation(GURL("http://www.google.fr/hello"), "Bonjour", "fr", true);
// There should not be a translate infobar.
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
@@ -890,42 +926,44 @@ TEST_F(TranslateManagerTest, NeverTranslateSitePref) {
EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
// Navigate to a page in French.
- SimulateNavigation(url, 0, "Le Google", "fr", true);
+ SimulateNavigation(url, "Le Google", "fr", true);
// There should be a translate infobar.
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
- prefs->RemovePrefObserver(TranslatePrefs::kPrefTranslateSiteBlacklist,
- &pref_observer_);
}
// Tests the "Always translate this language" pref.
TEST_F(TranslateManagerTest, AlwaysTranslateLanguagePref) {
// Select always translate French to English.
PrefService* prefs = contents()->profile()->GetPrefs();
- prefs->AddPrefObserver(TranslatePrefs::kPrefTranslateWhitelists,
- &pref_observer_);
+ PrefChangeRegistrar registrar;
+ registrar.Init(prefs);
+ registrar.Add(TranslatePrefs::kPrefTranslateWhitelists,
+ &pref_observer_);
TranslatePrefs translate_prefs(prefs);
SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateWhitelists);
translate_prefs.WhitelistLanguagePair("fr", "en");
// Load a page in French.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
// It should have triggered an automatic translation to English.
+
+ // The translating infobar should be showing.
+ TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+ ASSERT_TRUE(infobar != NULL);
+ EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());
+
SimulateURLFetch(true); // Simulate the translate script being retrieved.
int page_id = 0;
std::string original_lang, target_lang;
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(0, page_id);
EXPECT_EQ("fr", original_lang);
EXPECT_EQ("en", target_lang);
process()->sink().ClearMessages();
- // And we should have no infobar (since we don't send the page translated
- // notification, the after translate infobar is not shown).
- EXPECT_TRUE(GetTranslateInfoBar() == NULL);
// Try another language, it should not be autotranslated.
- SimulateNavigation(GURL("http://www.google.es"), 1, "El Google", "es", true);
+ SimulateNavigation(GURL("http://www.google.es"), "El Google", "es", true);
EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
EXPECT_TRUE(CloseTranslateInfoBar());
@@ -935,22 +973,21 @@ TEST_F(TranslateManagerTest, AlwaysTranslateLanguagePref) {
TestingProfile* test_profile =
static_cast<TestingProfile*>(contents()->profile());
test_profile->set_off_the_record(true);
- SimulateNavigation(GURL("http://www.youtube.fr"), 2, "Le YouTube", "fr",
- true);
+ SimulateNavigation(GURL("http://www.youtube.fr"), "Le YouTube", "fr", true);
EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
EXPECT_TRUE(GetTranslateInfoBar() != NULL);
EXPECT_TRUE(CloseTranslateInfoBar());
test_profile->set_off_the_record(false); // Get back to non incognito.
// Now revert the always translate pref and make sure we go back to expected
- // behavior, which is show an infobar.
+ // behavior, which is show a "before translate" infobar.
SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateWhitelists);
translate_prefs.RemoveLanguagePairFromWhitelist("fr", "en");
- SimulateNavigation(GURL("http://www.google.fr"), 3, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_TRUE(GetTranslateInfoBar() != NULL);
- prefs->RemovePrefObserver(TranslatePrefs::kPrefTranslateWhitelists,
- &pref_observer_);
+ infobar = GetTranslateInfoBar();
+ ASSERT_TRUE(infobar != NULL);
+ EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
}
// Context menu.
@@ -963,23 +1000,34 @@ TEST_F(TranslateManagerTest, ContextMenu) {
EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("fr"));
EXPECT_TRUE(translate_prefs.IsSiteBlacklisted(url.host()));
- // Simulate navigating to a page in French. The translate menu should show.
- SimulateNavigation(url, 0, "Le Google", "fr", true);
+ // Simulate navigating to a page in French. The translate menu should show but
+ // should only be enabled when the page language has been received.
+ NavigateAndCommit(url);
scoped_ptr<TestRenderViewContextMenu> menu(
TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
+ EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
+
+ // Simulate receiving the language.
+ SimulateOnPageContents(url, 0, "Le Google", "fr", true);
+ menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
+ menu->Init();
+ EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
// Use the menu to translate the page.
menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
// That should have triggered a translation.
+ // The "translating..." infobar should be showing.
+ TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+ ASSERT_TRUE(infobar != NULL);
+ EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());
SimulateURLFetch(true); // Simulate the translate script being retrieved.
int page_id = 0;
std::string original_lang, target_lang;
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(0, page_id);
EXPECT_EQ("fr", original_lang);
EXPECT_EQ("en", target_lang);
process()->sink().ClearMessages();
@@ -1001,12 +1049,11 @@ TEST_F(TranslateManagerTest, ContextMenu) {
// Test that selecting translate in the context menu WHILE the page is being
// translated does nothing (this could happen if autotranslate kicks-in and
// the user selects the menu while the translation is being performed).
- SimulateNavigation(GURL("http://www.google.es"), 1, "El Google", "es", true);
- TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+ SimulateNavigation(GURL("http://www.google.es"), "El Google", "es", true);
+ infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
infobar->Translate();
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(1, page_id);
process()->sink().ClearMessages();
menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
@@ -1017,12 +1064,11 @@ TEST_F(TranslateManagerTest, ContextMenu) {
// Now test that selecting translate in the context menu AFTER the page has
// been translated does nothing.
- SimulateNavigation(GURL("http://www.google.de"), 2, "Das Google", "de", true);
+ SimulateNavigation(GURL("http://www.google.de"), "Das Google", "de", true);
infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
infobar->Translate();
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(2, page_id);
process()->sink().ClearMessages();
menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
@@ -1035,23 +1081,32 @@ TEST_F(TranslateManagerTest, ContextMenu) {
// Test that the translate context menu is disabled when the page is in the
// same language as the UI.
- SimulateNavigation(url, 0, "Google", "en", true);
+ SimulateNavigation(url, "Google", "en", true);
menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
// Test that the translate context menu is enabled when the page is in an
- // unknown language as the UI.
- SimulateNavigation(url, 0, "G00g1e", "und", true);
+ // unknown language.
+ SimulateNavigation(url, "G00g1e", "und", true);
menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
menu->Init();
EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
+
+ // Test that the translate context menu is disabled when the page is in an
+ // unsupported language.
+ SimulateNavigation(url, "G00g1e", "qbz", true);
+ menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
+ menu->Init();
+ EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
+ EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
}
// Tests that an extra always/never translate button is shown on the "before
-// translate" infobar when the translation is accepted/declined 3 times.
+// translate" infobar when the translation is accepted/declined 3 times,
+// only when not in incognito mode.
TEST_F(TranslateManagerTest, BeforeTranslateExtraButtons) {
TranslatePrefs translate_prefs(contents()->profile()->GetPrefs());
translate_prefs.ResetTranslationAcceptedCount("fr");
@@ -1059,20 +1114,28 @@ TEST_F(TranslateManagerTest, BeforeTranslateExtraButtons) {
translate_prefs.ResetTranslationAcceptedCount("de");
translate_prefs.ResetTranslationDeniedCount("de");
+ // We'll do 4 times in incognito mode first to make sure the button is not
+ // shown in that case, then 4 times in normal mode.
TranslateInfoBarDelegate* infobar;
- for (int i = 0; i < 4; ++i) {
- SimulateNavigation(GURL("http://www.google.fr"), 1, "Le Google", "fr",
- true);
+ TestingProfile* test_profile =
+ static_cast<TestingProfile*>(contents()->profile());
+ test_profile->set_off_the_record(true);
+ for (int i = 0; i < 8; ++i) {
+ SCOPED_TRACE(::testing::Message::Message() << "Iteration " << i <<
+ " incognito mode=" << test_profile->IsOffTheRecord());
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
- if (i < 3) {
+ if (i < 7) {
EXPECT_FALSE(infobar->ShouldShowAlwaysTranslateButton());
infobar->Translate();
process()->sink().ClearMessages();
} else {
EXPECT_TRUE(infobar->ShouldShowAlwaysTranslateButton());
}
+ if (i == 3)
+ test_profile->set_off_the_record(false);
}
// Simulate the user pressing "Always translate French".
infobar->AlwaysTranslatePageLanguage();
@@ -1087,19 +1150,23 @@ TEST_F(TranslateManagerTest, BeforeTranslateExtraButtons) {
process()->sink().ClearMessages();
// Now test that declining the translation causes a "never translate" button
- // to be shown.
- for (int i = 0; i < 4; ++i) {
- SimulateNavigation(GURL("http://www.google.de"), 1, "Das Google", "de",
- true);
+ // to be shown (in non incognito mode only).
+ test_profile->set_off_the_record(true);
+ for (int i = 0; i < 8; ++i) {
+ SCOPED_TRACE(::testing::Message::Message() << "Iteration " << i <<
+ " incognito mode=" << test_profile->IsOffTheRecord());
+ SimulateNavigation(GURL("http://www.google.de"), "Das Google", "de", true);
infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
- if (i < 3) {
+ if (i < 7) {
EXPECT_FALSE(infobar->ShouldShowNeverTranslateButton());
infobar->TranslationDeclined();
} else {
EXPECT_TRUE(infobar->ShouldShowNeverTranslateButton());
}
+ if (i == 3)
+ test_profile->set_off_the_record(false);
}
// Simulate the user pressing "Never translate French".
infobar->NeverTranslatePageLanguage();
@@ -1114,8 +1181,7 @@ TEST_F(TranslateManagerTest, BeforeTranslateExtraButtons) {
// should not be translated.
TEST_F(TranslateManagerTest, NonTranslatablePage) {
// Simulate navigating to a page.
- SimulateNavigation(GURL("http://mail.google.fr"), 0, "Le Google", "fr",
- false);
+ SimulateNavigation(GURL("http://mail.google.fr"), "Le Google", "fr", false);
// We should not have an infobar.
EXPECT_TRUE(GetTranslateInfoBar() == NULL);
@@ -1133,7 +1199,7 @@ TEST_F(TranslateManagerTest, ScriptExpires) {
ExpireTranslateScriptImmediately();
// Simulate navigating to a page and translating it.
- SimulateNavigation(GURL("http://www.google.fr"), 0, "Le Google", "fr", true);
+ SimulateNavigation(GURL("http://www.google.fr"), "Le Google", "fr", true);
TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
process()->sink().ClearMessages();
@@ -1146,7 +1212,7 @@ TEST_F(TranslateManagerTest, ScriptExpires) {
MessageLoop::current()->RunAllPending();
// Do another navigation and translation.
- SimulateNavigation(GURL("http://www.google.es"), 1, "El Google", "es", true);
+ SimulateNavigation(GURL("http://www.google.es"), "El Google", "es", true);
infobar = GetTranslateInfoBar();
ASSERT_TRUE(infobar != NULL);
process()->sink().ClearMessages();
@@ -1162,7 +1228,6 @@ TEST_F(TranslateManagerTest, ScriptExpires) {
int page_id = 0;
std::string original_lang, target_lang;
EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
- EXPECT_EQ(1, page_id);
EXPECT_EQ("es", original_lang);
EXPECT_EQ("en", target_lang);
}
diff --git a/chrome/browser/translate/translate_prefs.cc b/chrome/browser/translate/translate_prefs.cc
index 3d72df0..5e14bd4 100644
--- a/chrome/browser/translate/translate_prefs.cc
+++ b/chrome/browser/translate/translate_prefs.cc
@@ -5,20 +5,19 @@
#include "chrome/browser/translate/translate_prefs.h"
#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/scoped_pref_update.h"
-
-const wchar_t TranslatePrefs::kPrefTranslateLanguageBlacklist[] =
- L"translate_language_blacklist";
-const wchar_t TranslatePrefs::kPrefTranslateSiteBlacklist[] =
- L"translate_site_blacklist";
-const wchar_t TranslatePrefs::kPrefTranslateWhitelists[] =
- L"translate_whitelists";
-const wchar_t TranslatePrefs::kPrefTranslateDeniedCount[] =
- L"translate_denied_count";
-const wchar_t TranslatePrefs::kPrefTranslateAcceptedCount[] =
- L"translate_accepted_count";
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
+
+const char TranslatePrefs::kPrefTranslateLanguageBlacklist[] =
+ "translate_language_blacklist";
+const char TranslatePrefs::kPrefTranslateSiteBlacklist[] =
+ "translate_site_blacklist";
+const char TranslatePrefs::kPrefTranslateWhitelists[] =
+ "translate_whitelists";
+const char TranslatePrefs::kPrefTranslateDeniedCount[] =
+ "translate_denied_count";
+const char TranslatePrefs::kPrefTranslateAcceptedCount[] =
+ "translate_accepted_count";
// TranslatePrefs: public: -----------------------------------------------------
@@ -62,7 +61,7 @@ bool TranslatePrefs::IsLanguagePairWhitelisted(
const DictionaryValue* dict = prefs_->GetDictionary(kPrefTranslateWhitelists);
if (dict && !dict->empty()) {
std::string auto_target_lang;
- if (dict->GetString(ASCIIToWide(original_language), &auto_target_lang) &&
+ if (dict->GetString(original_language, &auto_target_lang) &&
auto_target_lang == target_language)
return true;
}
@@ -79,7 +78,7 @@ void TranslatePrefs::WhitelistLanguagePair(
return;
}
ScopedPrefUpdate update(prefs_, kPrefTranslateWhitelists);
- dict->SetString(ASCIIToWide(original_language), target_language);
+ dict->SetString(original_language, target_language);
prefs_->ScheduleSavePersistentPrefs();
}
@@ -93,7 +92,7 @@ void TranslatePrefs::RemoveLanguagePairFromWhitelist(
return;
}
ScopedPrefUpdate update(prefs_, kPrefTranslateWhitelists);
- if (dict->Remove(ASCIIToWide(original_language), NULL))
+ if (dict->Remove(original_language, NULL))
prefs_->ScheduleSavePersistentPrefs();
}
@@ -101,7 +100,7 @@ int TranslatePrefs::GetTranslationDeniedCount(const std::string& language) {
DictionaryValue* dict =
prefs_->GetMutableDictionary(kPrefTranslateDeniedCount);
int count = 0;
- return dict->GetInteger(UTF8ToWide(language), &count) ? count : 0;
+ return dict->GetInteger(language, &count) ? count : 0;
}
void TranslatePrefs::IncrementTranslationDeniedCount(
@@ -109,20 +108,20 @@ void TranslatePrefs::IncrementTranslationDeniedCount(
DictionaryValue* dict =
prefs_->GetMutableDictionary(kPrefTranslateDeniedCount);
int count = 0;
- dict->GetInteger(UTF8ToWide(language), &count);
- dict->SetInteger(UTF8ToWide(language), count + 1);
+ dict->GetInteger(language, &count);
+ dict->SetInteger(language, count + 1);
}
void TranslatePrefs::ResetTranslationDeniedCount(const std::string& language) {
prefs_->GetMutableDictionary(kPrefTranslateDeniedCount)->
- SetInteger(UTF8ToWide(language), 0);
+ SetInteger(language, 0);
}
int TranslatePrefs::GetTranslationAcceptedCount(const std::string& language) {
DictionaryValue* dict =
prefs_->GetMutableDictionary(kPrefTranslateAcceptedCount);
int count = 0;
- return dict->GetInteger(UTF8ToWide(language), &count) ? count : 0;
+ return dict->GetInteger(language, &count) ? count : 0;
}
void TranslatePrefs::IncrementTranslationAcceptedCount(
@@ -130,14 +129,14 @@ void TranslatePrefs::IncrementTranslationAcceptedCount(
DictionaryValue* dict =
prefs_->GetMutableDictionary(kPrefTranslateAcceptedCount);
int count = 0;
- dict->GetInteger(UTF8ToWide(language), &count);
- dict->SetInteger(UTF8ToWide(language), count + 1);
+ dict->GetInteger(language, &count);
+ dict->SetInteger(language, count + 1);
}
void TranslatePrefs::ResetTranslationAcceptedCount(
const std::string& language) {
prefs_->GetMutableDictionary(kPrefTranslateAcceptedCount)->
- SetInteger(UTF8ToWide(language), 0);
+ SetInteger(language, 0);
}
// TranslatePrefs: public, static: ---------------------------------------------
@@ -226,13 +225,13 @@ bool TranslatePrefs::IsValueInList(const ListValue* list,
return false;
}
-bool TranslatePrefs::IsValueBlacklisted(const wchar_t* pref_id,
+bool TranslatePrefs::IsValueBlacklisted(const char* pref_id,
const std::string& value) {
const ListValue* blacklist = prefs_->GetList(pref_id);
return (blacklist && !blacklist->empty() && IsValueInList(blacklist, value));
}
-void TranslatePrefs::BlacklistValue(const wchar_t* pref_id,
+void TranslatePrefs::BlacklistValue(const char* pref_id,
const std::string& value) {
ListValue* blacklist = prefs_->GetMutableList(pref_id);
if (!blacklist) {
@@ -243,7 +242,7 @@ void TranslatePrefs::BlacklistValue(const wchar_t* pref_id,
prefs_->ScheduleSavePersistentPrefs();
}
-void TranslatePrefs::RemoveValueFromBlacklist(const wchar_t* pref_id,
+void TranslatePrefs::RemoveValueFromBlacklist(const char* pref_id,
const std::string& value) {
ListValue* blacklist = prefs_->GetMutableList(pref_id);
if (!blacklist) {
@@ -258,8 +257,7 @@ void TranslatePrefs::RemoveValueFromBlacklist(const wchar_t* pref_id,
bool TranslatePrefs::IsLanguageWhitelisted(
const std::string& original_language, std::string* target_language) {
const DictionaryValue* dict = prefs_->GetDictionary(kPrefTranslateWhitelists);
- if (dict &&
- dict->GetString(ASCIIToWide(original_language), target_language)) {
+ if (dict && dict->GetString(original_language, target_language)) {
DCHECK(!target_language->empty());
return !target_language->empty();
}
diff --git a/chrome/browser/translate/translate_prefs.h b/chrome/browser/translate/translate_prefs.h
index 9fece54..5b94df3 100644
--- a/chrome/browser/translate/translate_prefs.h
+++ b/chrome/browser/translate/translate_prefs.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_PREFS_H_
#define CHROME_BROWSER_TRANSLATE_TRANSLATE_PREFS_H_
+#pragma once
#include <string>
-#include <vector>
#include "googleurl/src/gurl.h"
@@ -16,11 +16,11 @@ class PrefService;
class TranslatePrefs {
public:
- static const wchar_t kPrefTranslateLanguageBlacklist[];
- static const wchar_t kPrefTranslateSiteBlacklist[];
- static const wchar_t kPrefTranslateWhitelists[];
- static const wchar_t kPrefTranslateDeniedCount[];
- static const wchar_t kPrefTranslateAcceptedCount[];
+ static const char kPrefTranslateLanguageBlacklist[];
+ static const char kPrefTranslateSiteBlacklist[];
+ static const char kPrefTranslateWhitelists[];
+ static const char kPrefTranslateDeniedCount[];
+ static const char kPrefTranslateAcceptedCount[];
explicit TranslatePrefs(PrefService* user_prefs);
@@ -61,10 +61,9 @@ class TranslatePrefs {
private:
static void MigrateTranslateWhitelists(PrefService* user_prefs);
- bool IsValueBlacklisted(const wchar_t* pref_id, const std::string& value);
- void BlacklistValue(const wchar_t* pref_id, const std::string& value);
- void RemoveValueFromBlacklist(const wchar_t* pref_id,
- const std::string& value);
+ bool IsValueBlacklisted(const char* pref_id, const std::string& value);
+ void BlacklistValue(const char* pref_id, const std::string& value);
+ void RemoveValueFromBlacklist(const char* pref_id, const std::string& value);
bool IsValueInList(const ListValue* list, const std::string& value);
bool IsLanguageWhitelisted(const std::string& original_language,
std::string* target_language);
diff --git a/chrome/browser/transport_security_persister.h b/chrome/browser/transport_security_persister.h
index 5e006ea..7db6b58 100644
--- a/chrome/browser/transport_security_persister.h
+++ b/chrome/browser/transport_security_persister.h
@@ -32,6 +32,7 @@
#ifndef CHROME_BROWSER_TRANSPORT_SECURITY_PERSISTER_H_
#define CHROME_BROWSER_TRANSPORT_SECURITY_PERSISTER_H_
+#pragma once
#include "base/file_path.h"
#include "base/lock.h"
diff --git a/chrome/browser/ui_thread_helpers.h b/chrome/browser/ui_thread_helpers.h
new file mode 100644
index 0000000..90e2c4e
--- /dev/null
+++ b/chrome/browser/ui_thread_helpers.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_UI_THREAD_HELPERS_H_
+#define CHROME_BROWSER_UI_THREAD_HELPERS_H_
+#pragma once
+
+class Task;
+
+namespace tracked_objects {
+class Location;
+} // namespace tracked_objects
+
+namespace ui_thread_helpers {
+
+// This can be used in place of ChromeThread::PostTask(ChromeThread::UI, ...).
+// The purpose of this function is to be able to execute Chrome work alongside
+// native work when a message loop is running nested or, in the case of Mac,
+// in a different mode. Currently this is used for updating the HostZoomMap
+// while the Wrench menu is open, allowing for the zoom display to update. See
+// http://crbug.com/48679 for the full rationale.
+//
+// CAVEAT EMPTOR: This function's implementation is different across platforms
+// and may run the Task in a way that differs from the stock MessageLoop. You
+// should check the behavior on all platforms if you use this.
+bool PostTaskWhileRunningMenu(const tracked_objects::Location& from_here,
+ Task* task);
+
+} // namespace ui_thread_helpers
+
+#endif // CHROME_BROWSER_UI_THREAD_HELPERS_H_
diff --git a/chrome/browser/ui_thread_helpers_linux.cc b/chrome/browser/ui_thread_helpers_linux.cc
new file mode 100644
index 0000000..41721c3
--- /dev/null
+++ b/chrome/browser/ui_thread_helpers_linux.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/ui_thread_helpers.h"
+
+#include "base/task.h"
+#include "chrome/browser/chrome_thread.h"
+
+namespace ui_thread_helpers {
+
+bool PostTaskWhileRunningMenu(const tracked_objects::Location& from_here,
+ Task* task) {
+ // TODO(rsesek): Implementing Linux behavior may fix http://crbug.com/48240
+ return ChromeThread::PostTask(ChromeThread::UI, from_here, task);
+}
+
+} // namespace ui_thread_helpers
diff --git a/chrome/browser/ui_thread_helpers_mac.mm b/chrome/browser/ui_thread_helpers_mac.mm
new file mode 100644
index 0000000..c6efd3c
--- /dev/null
+++ b/chrome/browser/ui_thread_helpers_mac.mm
@@ -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 "chrome/browser/ui_thread_helpers.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "chrome/browser/chrome_thread.h"
+
+// This is a wrapper for running Chrome Task objects from within a native run
+// loop. A typical use case is when Chrome work needs to get done but the main
+// message loop is blocked by a nested run loop (like an event tracking one).
+// This can run specific tasks in that nested loop. This owns the task and will
+// delete it and itself when done.
+@interface UITaskHelperMac : NSObject {
+ @private
+ scoped_ptr<Task> task_;
+}
+- (id)initWithTask:(Task*)task;
+- (void)runTask;
+@end
+
+@implementation UITaskHelperMac
+- (id)initWithTask:(Task*)task {
+ if ((self = [super init])) {
+ task_.reset(task);
+ }
+ return self;
+}
+
+- (void)runTask {
+ task_->Run();
+ [self autorelease];
+}
+@end
+
+namespace ui_thread_helpers {
+
+bool PostTaskWhileRunningMenu(const tracked_objects::Location& from_here,
+ Task* task) {
+ // This deletes itself and the task after the task runs.
+ UITaskHelperMac* runner = [[UITaskHelperMac 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 ui_thread_helpers
diff --git a/chrome/browser/ui_thread_helpers_win.cc b/chrome/browser/ui_thread_helpers_win.cc
new file mode 100644
index 0000000..170ecdb
--- /dev/null
+++ b/chrome/browser/ui_thread_helpers_win.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/ui_thread_helpers.h"
+
+#include "base/task.h"
+#include "chrome/browser/chrome_thread.h"
+
+namespace ui_thread_helpers {
+
+bool PostTaskWhileRunningMenu(const tracked_objects::Location& from_here,
+ Task* task) {
+ return ChromeThread::PostTask(ChromeThread::UI, from_here, task);
+}
+
+} // namespace ui_thread_helpers
diff --git a/chrome/browser/unload_uitest.cc b/chrome/browser/unload_uitest.cc
index b6ed109..1fb8742 100644
--- a/chrome/browser/unload_uitest.cc
+++ b/chrome/browser/unload_uitest.cc
@@ -283,7 +283,8 @@ TEST_F(UnloadTest, SKIP_LINUX(BrowserCloseNoUnloadListeners)) {
}
// Tests closing the browser on a page with an unload listener registered.
-TEST_F(UnloadTest, SKIP_LINUX(BrowserCloseUnload)) {
+// Test marked as flaky in http://crbug.com/51698
+TEST_F(UnloadTest, SKIP_LINUX(FLAKY_BrowserCloseUnload)) {
LoadUrlAndQuitBrowser(UNLOAD_HTML, L"unload");
}
@@ -407,7 +408,7 @@ TEST_F(UnloadTest, SKIP_LINUX(BrowserCloseTwoSecondBeforeUnloadAlert)) {
#elif defined(OS_WIN)
// http://crbug.com/45281
#define MAYBE_BrowserCloseTabWhenOtherTabHasListener \
- FAILS_BrowserCloseTabWhenOtherTabHasListener
+ DISABLED_BrowserCloseTabWhenOtherTabHasListener
#else
// Flaky on Linux as well. http://crbug.com/45562
#define MAYBE_BrowserCloseTabWhenOtherTabHasListener \
@@ -432,7 +433,7 @@ TEST_F(UnloadTest, MAYBE_BrowserCloseTabWhenOtherTabHasListener) {
// popup will be constrained, which isn't what we want to test.
ASSERT_TRUE(window->SimulateOSClick(tab_view_bounds.CenterPoint(),
views::Event::EF_LEFT_BUTTON_DOWN));
- ASSERT_TRUE(browser->WaitForTabCountToBecome(2, action_timeout_ms()));
+ ASSERT_TRUE(browser->WaitForTabCountToBecome(2));
scoped_refptr<TabProxy> popup_tab(browser->GetActiveTab());
ASSERT_TRUE(popup_tab.get());
@@ -441,7 +442,7 @@ TEST_F(UnloadTest, MAYBE_BrowserCloseTabWhenOtherTabHasListener) {
EXPECT_EQ(std::wstring(L"popup"), popup_title);
EXPECT_TRUE(popup_tab->Close(true));
- ASSERT_TRUE(browser->WaitForTabCountToBecome(1, action_timeout_ms()));
+ ASSERT_TRUE(browser->WaitForTabCountToBecome(1));
scoped_refptr<TabProxy> main_tab(browser->GetActiveTab());
ASSERT_TRUE(main_tab.get());
std::wstring main_title;
diff --git a/chrome/browser/upgrade_detector.cc b/chrome/browser/upgrade_detector.cc
index 38bd2cd..f19a6f6 100644
--- a/chrome/browser/upgrade_detector.cc
+++ b/chrome/browser/upgrade_detector.cc
@@ -7,14 +7,15 @@
#include <string>
#include "base/command_line.h"
-#include "base/file_version_info.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "base/task.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "base/version.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/notification_service.h"
@@ -31,16 +32,29 @@
#include "chrome/installer/util/version.h"
#endif
-// TODO(finnur): For the stable channel we want to check daily and notify
-// the user if more than 2 weeks have passed since the upgrade happened
-// (without a reboot). For the dev channel however, I want quicker feedback
-// on how the feature works so I'm checking every hour and notifying the
-// user immediately.
-
namespace {
// How often to check for an upgrade.
-const int kCheckForUpgradeEveryMs = 60 * 60 * 1000; // 1 hour.
+int GetCheckForUpgradeEveryMs() {
+ // Check for a value passed via the command line.
+ int interval_ms;
+ const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
+ std::string interval =
+ cmd_line.GetSwitchValueASCII(switches::kCheckForUpdateIntervalSec);
+ if (!interval.empty() && base::StringToInt(interval, &interval_ms))
+ return interval_ms * 1000; // Command line value is in seconds.
+
+ // Otherwise check once an hour for dev channel and once a day for all other
+ // channels/builds.
+ const std::string channel = platform_util::GetVersionStringModifier();
+ int hours;
+ if (channel == "dev")
+ hours = 1;
+ else
+ hours = 24;
+
+ return hours * 60 * 60 * 1000;
+}
// How long to wait before notifying the user about the upgrade.
const int kNotifyUserAfterMs = 0;
@@ -106,14 +120,13 @@ class DetectUpgradeTask : public Task {
#endif
// Get the version of the currently *running* instance of Chrome.
- scoped_ptr<FileVersionInfo> version(chrome::GetChromeVersionInfo());
- if (version.get() == NULL) {
+ chrome::VersionInfo version_info;
+ if (!version_info.is_valid()) {
NOTREACHED() << "Failed to get current file version";
return;
}
-
scoped_ptr<Version> running_version(
- Version::GetVersionFromString(WideToUTF16(version->file_version())));
+ Version::GetVersionFromString(ASCIIToUTF16(version_info.Version())));
if (running_version.get() == NULL) {
NOTREACHED() << "Failed to parse version info";
return;
@@ -153,7 +166,7 @@ UpgradeDetector::UpgradeDetector()
#endif
{
detect_upgrade_timer_.Start(
- base::TimeDelta::FromMilliseconds(kCheckForUpgradeEveryMs),
+ base::TimeDelta::FromMilliseconds(GetCheckForUpgradeEveryMs()),
this, &UpgradeDetector::CheckForUpgrade);
}
#endif
diff --git a/chrome/browser/upgrade_detector.h b/chrome/browser/upgrade_detector.h
index 036d43c..7c15128 100644
--- a/chrome/browser/upgrade_detector.h
+++ b/chrome/browser/upgrade_detector.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_UPGRADE_DETECTOR_H_
#define CHROME_BROWSER_UPGRADE_DETECTOR_H_
+#pragma once
#include "base/singleton.h"
#include "base/timer.h"
diff --git a/chrome/browser/user_style_sheet_watcher.cc b/chrome/browser/user_style_sheet_watcher.cc
index 2bc9568..a8789fd 100644
--- a/chrome/browser/user_style_sheet_watcher.cc
+++ b/chrome/browser/user_style_sheet_watcher.cc
@@ -18,58 +18,88 @@ const char kUserStyleSheetFile[] = "Custom.css";
} // namespace
-UserStyleSheetWatcher::UserStyleSheetWatcher(const FilePath& profile_path)
- : profile_path_(profile_path),
- has_loaded_(false) {
- // Listen for when the first render view host is created. If we load
- // too fast, the first tab won't hear the notification and won't get
- // the user style sheet.
- registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
- NotificationService::AllSources());
-}
+// UserStyleSheetLoader is responsible for loading the user style sheet on the
+// file thread and sends a notification when the style sheet is loaded. It is
+// a helper to UserStyleSheetWatcher. The reference graph is as follows:
+//
+// .-----------------------. owns .-----------------.
+// | UserStyleSheetWatcher |----------->| FilePathWatcher |
+// '-----------------------' '-----------------'
+// | |
+// V |
+// .----------------------. |
+// | UserStyleSheetLoader |<--------------------'
+// '----------------------'
+//
+// FilePathWatcher's reference to UserStyleSheetLoader is used for delivering
+// the change notifications. Since they happen asynchronously,
+// UserStyleSheetWatcher and its FilePathWatcher may be destroyed while a
+// callback to UserStyleSheetLoader is in progress, in which case the
+// UserStyleSheetLoader object outlives the watchers.
+class UserStyleSheetLoader : public FilePathWatcher::Delegate {
+ public:
+ UserStyleSheetLoader();
+ virtual ~UserStyleSheetLoader() {}
+
+ GURL user_style_sheet() const {
+ return user_style_sheet_;
+ }
-void UserStyleSheetWatcher::Observe(NotificationType type,
- const NotificationSource& source, const NotificationDetails& details) {
- DCHECK(type == NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB);
+ // Load the user style sheet on the file thread and convert it to a
+ // base64 URL. Posts the base64 URL back to the UI thread.
+ void LoadStyleSheet(const FilePath& style_sheet_file);
+
+ // Send out a notification if the stylesheet has already been loaded.
+ void NotifyLoaded();
+
+ // FilePathWatcher::Delegate interface
+ virtual void OnFilePathChanged(const FilePath& path);
+ private:
+ // Called on the UI thread after the stylesheet has loaded.
+ void SetStyleSheet(const GURL& url);
+
+ // The user style sheet as a base64 data:// URL.
+ GURL user_style_sheet_;
+
+ // Whether the stylesheet has been loaded.
+ bool has_loaded_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserStyleSheetLoader);
+};
+
+UserStyleSheetLoader::UserStyleSheetLoader()
+ : has_loaded_(false) {
+}
+
+void UserStyleSheetLoader::NotifyLoaded() {
if (has_loaded_) {
NotificationService::current()->Notify(
NotificationType::USER_STYLE_SHEET_UPDATED,
- Source<UserStyleSheetWatcher>(this),
+ Source<UserStyleSheetLoader>(this),
NotificationService::NoDetails());
}
-
- registrar_.RemoveAll();
-}
-
-void UserStyleSheetWatcher::OnFileChanged(const FilePath& path) {
- ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &UserStyleSheetWatcher::LoadStyleSheet,
- profile_path_));
}
-void UserStyleSheetWatcher::Init() {
- ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &UserStyleSheetWatcher::LoadStyleSheet,
- profile_path_));
+void UserStyleSheetLoader::OnFilePathChanged(const FilePath& path) {
+ LoadStyleSheet(path);
}
-void UserStyleSheetWatcher::LoadStyleSheet(const FilePath& profile_path) {
+void UserStyleSheetLoader::LoadStyleSheet(const FilePath& style_sheet_file) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
// We keep the user style sheet in a subdir so we can watch for changes
// to the file.
- FilePath style_sheet_dir = profile_path.AppendASCII(kStyleSheetDir);
+ FilePath style_sheet_dir = style_sheet_file.DirName();
if (!file_util::DirectoryExists(style_sheet_dir)) {
if (!file_util::CreateDirectory(style_sheet_dir))
return;
}
// Create the file if it doesn't exist.
- FilePath css_file = style_sheet_dir.AppendASCII(kUserStyleSheetFile);
- if (!file_util::PathExists(css_file))
- file_util::WriteFile(css_file, "", 0);
+ if (!file_util::PathExists(style_sheet_file))
+ file_util::WriteFile(style_sheet_file, "", 0);
std::string css;
- bool rv = file_util::ReadFileToString(css_file, &css);
+ bool rv = file_util::ReadFileToString(style_sheet_file, &css);
GURL style_sheet_url;
if (rv && !css.empty()) {
std::string css_base64;
@@ -81,23 +111,56 @@ void UserStyleSheetWatcher::LoadStyleSheet(const FilePath& profile_path) {
}
}
ChromeThread::PostTask(ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this, &UserStyleSheetWatcher::SetStyleSheet,
+ NewRunnableMethod(this, &UserStyleSheetLoader::SetStyleSheet,
style_sheet_url));
-
- if (!file_watcher_.get()) {
- file_watcher_.reset(new FileWatcher);
- file_watcher_->Watch(profile_path_.AppendASCII(kStyleSheetDir)
- .AppendASCII(kUserStyleSheetFile), this);
- }
}
-void UserStyleSheetWatcher::SetStyleSheet(const GURL& url) {
+void UserStyleSheetLoader::SetStyleSheet(const GURL& url) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
has_loaded_ = true;
user_style_sheet_ = url;
- NotificationService::current()->Notify(
- NotificationType::USER_STYLE_SHEET_UPDATED,
- Source<UserStyleSheetWatcher>(this),
- NotificationService::NoDetails());
+ NotifyLoaded();
+}
+
+UserStyleSheetWatcher::UserStyleSheetWatcher(const FilePath& profile_path)
+ : profile_path_(profile_path),
+ loader_(new UserStyleSheetLoader) {
+ // Listen for when the first render view host is created. If we load
+ // too fast, the first tab won't hear the notification and won't get
+ // the user style sheet.
+ registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB,
+ NotificationService::AllSources());
+}
+
+UserStyleSheetWatcher::~UserStyleSheetWatcher() {
+}
+
+void UserStyleSheetWatcher::Init() {
+ // Make sure we run on the file thread.
+ if (!ChromeThread::CurrentlyOn(ChromeThread::FILE)) {
+ ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &UserStyleSheetWatcher::Init));
+ return;
+ }
+
+ if (!file_watcher_.get()) {
+ file_watcher_.reset(new FilePathWatcher);
+ FilePath style_sheet_file = profile_path_.AppendASCII(kStyleSheetDir)
+ .AppendASCII(kUserStyleSheetFile);
+ if (!file_watcher_->Watch(style_sheet_file, loader_.get()))
+ LOG(ERROR) << "Failed to setup watch for " << style_sheet_file.value();
+ loader_->LoadStyleSheet(style_sheet_file);
+ }
+}
+
+GURL UserStyleSheetWatcher::user_style_sheet() const {
+ return loader_->user_style_sheet();
+}
+
+void UserStyleSheetWatcher::Observe(NotificationType type,
+ const NotificationSource& source, const NotificationDetails& details) {
+ DCHECK(type == NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB);
+ loader_->NotifyLoaded();
+ registrar_.RemoveAll();
}
diff --git a/chrome/browser/user_style_sheet_watcher.h b/chrome/browser/user_style_sheet_watcher.h
index 23bedb3..a322837 100644
--- a/chrome/browser/user_style_sheet_watcher.h
+++ b/chrome/browser/user_style_sheet_watcher.h
@@ -4,60 +4,49 @@
#ifndef CHROME_BROWSER_USER_STYLE_SHEET_WATCHER_H_
#define CHROME_BROWSER_USER_STYLE_SHEET_WATCHER_H_
+#pragma once
#include "base/file_path.h"
-#include "base/logging.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/file_watcher.h"
+#include "chrome/browser/file_path_watcher.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
-// This loads the user style sheet on the file thread and sends a notification
-// when the style sheet is loaded.
+class UserStyleSheetLoader;
+
+// Watches the user style sheet file and triggers reloads on the file thread
+// whenever the file changes.
class UserStyleSheetWatcher
: public base::RefCountedThreadSafe<UserStyleSheetWatcher,
ChromeThread::DeleteOnUIThread>,
- public NotificationObserver,
- public FileWatcher::Delegate {
+ public NotificationObserver {
public:
explicit UserStyleSheetWatcher(const FilePath& profile_path);
- virtual ~UserStyleSheetWatcher() {}
+ virtual ~UserStyleSheetWatcher();
void Init();
- GURL user_style_sheet() const {
- return user_style_sheet_;
- }
+ GURL user_style_sheet() const;
// NotificationObserver interface
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
- // FileWatcher::Delegate interface
- virtual void OnFileChanged(const FilePath& path);
-
private:
- // Load the user style sheet on the file thread and convert it to a
- // base64 URL. Posts the base64 URL back to the UI thread.
- void LoadStyleSheet(const FilePath& profile_path);
-
- void SetStyleSheet(const GURL& url);
-
// The directory containing User StyleSheets/Custom.css.
FilePath profile_path_;
- // The user style sheet as a base64 data:// URL.
- GURL user_style_sheet_;
+ // The loader object.
+ scoped_refptr<UserStyleSheetLoader> loader_;
// Watches for changes to the css file so we can reload the style sheet.
- scoped_ptr<FileWatcher> file_watcher_;
+ scoped_ptr<FilePathWatcher> file_watcher_;
NotificationRegistrar registrar_;
- bool has_loaded_;
DISALLOW_COPY_AND_ASSIGN(UserStyleSheetWatcher);
};
diff --git a/chrome/browser/userfeedback/proto/common.proto b/chrome/browser/userfeedback/proto/common.proto
index 97c60fb..291e6a1 100644
--- a/chrome/browser/userfeedback/proto/common.proto
+++ b/chrome/browser/userfeedback/proto/common.proto
@@ -16,7 +16,13 @@ message CommonData {
// Description of the problem entered by user.
optional string description = 2;
optional string description_translated = 4;
- optional string source_descripton_language = 5 [ default = "en" ];
+ optional string source_description_language = 5 [ default = "en" ];
+ optional string ui_language = 6 [ default = "en_US" ];
optional string user_email = 3;
+
+ // Unique identifier of feedback report. If set than only one report
+ // with the same identifier is stored in the system.
+ // If you are not sure how to use it leave it not set.
+ optional string unique_report_identifier = 7;
};
diff --git a/chrome/browser/userfeedback/proto/extension.proto b/chrome/browser/userfeedback/proto/extension.proto
index d600f8a..71be3dc 100644
--- a/chrome/browser/userfeedback/proto/extension.proto
+++ b/chrome/browser/userfeedback/proto/extension.proto
@@ -8,6 +8,7 @@ syntax = "proto2";
package userfeedback;
import "common.proto";
+import "chrome.proto";
import "dom.proto";
import "math.proto";
import "web.proto";
@@ -64,6 +65,8 @@ message ExternalExtensionSubmit {
optional HtmlDocument html_document_structure = 5;
optional ExtensionErrors extension_errors = 13;
+
+ optional ChromeData chrome_data = 14;
};
// Sent when user hits final submit button in internal extension.
diff --git a/chrome/browser/userfeedback/proto/web.proto b/chrome/browser/userfeedback/proto/web.proto
index fb9f6af..71b0b29 100644
--- a/chrome/browser/userfeedback/proto/web.proto
+++ b/chrome/browser/userfeedback/proto/web.proto
@@ -8,7 +8,6 @@ package userfeedback;
// Data present in Web related feedbacks
import "annotations.proto";
-import "config.proto";
import "dom.proto";
import "math.proto";
diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc
index 6a4a7fd..5091169 100644
--- a/chrome/browser/utility_process_host.cc
+++ b/chrome/browser/utility_process_host.cc
@@ -5,24 +5,28 @@
#include "chrome/browser/utility_process_host.h"
#include "app/app_switches.h"
-#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop.h"
+#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/indexed_db_key.h"
#include "chrome/common/utility_messages.h"
#include "ipc/ipc_switches.h"
+#include "third_party/skia/include/core/SkBitmap.h"
UtilityProcessHost::UtilityProcessHost(ResourceDispatcherHost* rdh,
Client* client,
ChromeThread::ID client_thread_id)
: BrowserChildProcessHost(UTILITY_PROCESS, rdh),
client_(client),
- client_thread_id_(client_thread_id) {
+ client_thread_id_(client_thread_id),
+ is_batch_mode_(false) {
}
UtilityProcessHost::~UtilityProcessHost() {
+ DCHECK(!is_batch_mode_);
}
bool UtilityProcessHost::StartExtensionUnpacker(const FilePath& extension) {
@@ -60,11 +64,37 @@ bool UtilityProcessHost::StartImageDecoding(
return true;
}
+bool UtilityProcessHost::StartIDBKeysFromValuesAndKeyPath(
+ int id, const std::vector<SerializedScriptValue>& serialized_values,
+ const string16& key_path) {
+ if (!StartProcess(FilePath()))
+ return false;
+
+ Send(new UtilityMsg_IDBKeysFromValuesAndKeyPath(
+ id, serialized_values, key_path));
+ return true;
+}
+
+bool UtilityProcessHost::StartBatchMode() {
+ CHECK(!is_batch_mode_);
+ is_batch_mode_ = StartProcess(FilePath());
+ Send(new UtilityMsg_BatchMode_Started());
+ return is_batch_mode_;
+}
+
+void UtilityProcessHost::EndBatchMode() {
+ CHECK(is_batch_mode_);
+ is_batch_mode_ = false;
+ Send(new UtilityMsg_BatchMode_Finished());
+}
+
FilePath UtilityProcessHost::GetUtilityProcessCmd() {
return GetChildPath(true);
}
bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
+ if (is_batch_mode_)
+ return true;
// Name must be set or metrics_service will crash in any test which
// launches a UtilityProcessHost.
set_name(L"utility process");
@@ -79,12 +109,11 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
}
CommandLine* cmd_line = new CommandLine(exe_path);
- cmd_line->AppendSwitchWithValue(switches::kProcessType,
- switches::kUtilityProcess);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchASCII(switches::kProcessType,
+ switches::kUtilityProcess);
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
std::string locale = g_browser_process->GetApplicationLocale();
- cmd_line->AppendSwitchWithValue(switches::kLang, locale);
+ cmd_line->AppendSwitchASCII(switches::kLang, locale);
SetCrashReporterCommandLine(cmd_line);
@@ -92,17 +121,14 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
if (browser_command_line.HasSwitch(switches::kChromeFrame))
cmd_line->AppendSwitch(switches::kChromeFrame);
- if (browser_command_line.HasSwitch(switches::kEnableApps))
- cmd_line->AppendSwitch(switches::kEnableApps);
+ if (browser_command_line.HasSwitch(switches::kDisableApps))
+ cmd_line->AppendSwitch(switches::kDisableApps);
if (browser_command_line.HasSwitch(
switches::kEnableExperimentalExtensionApis)) {
cmd_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
}
- if (browser_command_line.HasSwitch(switches::kIssue35198ExtraLogging))
- cmd_line->AppendSwitch(switches::kIssue35198ExtraLogging);
-
#if defined(OS_POSIX)
// TODO(port): Sandbox this on Linux. Also, zygote this to work with
// Linux updating.
@@ -111,12 +137,11 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
if (has_cmd_prefix) {
// launch the utility child process with some prefix (usually "xterm -e gdb
// --args").
- cmd_line->PrependWrapper(browser_command_line.GetSwitchValue(
+ cmd_line->PrependWrapper(browser_command_line.GetSwitchValueNative(
switches::kUtilityCmdPrefix));
}
- cmd_line->AppendSwitchWithValue(switches::kUtilityProcessAllowedDir,
- exposed_dir.value().c_str());
+ cmd_line->AppendSwitchPath(switches::kUtilityProcessAllowedDir, exposed_dir);
#endif
Launch(
@@ -162,5 +187,9 @@ void UtilityProcessHost::Client::OnMessageReceived(
Client::OnDecodeImageSucceeded)
IPC_MESSAGE_HANDLER(UtilityHostMsg_DecodeImage_Failed,
Client::OnDecodeImageFailed)
+ IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded,
+ Client::OnIDBKeysFromValuesAndKeyPathSucceeded)
+ IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed,
+ Client::OnIDBKeysFromValuesAndKeyPathFailed)
IPC_END_MESSAGE_MAP_EX()
}
diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h
index c21f5e5..8aadf35 100644
--- a/chrome/browser/utility_process_host.h
+++ b/chrome/browser/utility_process_host.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_UTILITY_PROCESS_HOST_H_
#define CHROME_BROWSER_UTILITY_PROCESS_HOST_H_
+#pragma once
#include <string>
#include <vector>
@@ -16,14 +17,18 @@
#include "chrome/common/extensions/update_manifest.h"
#include "ipc/ipc_channel.h"
-class CommandLine;
class DictionaryValue;
-class ListValue;
+class IndexedDBKey;
+class SerializedScriptValue;
class SkBitmap;
// This class acts as the browser-side host to a utility child process. A
// utility process is a short-lived sandboxed process that is created to run
// a specific task. This class lives solely on the IO thread.
+// If you need a single method call in the sandbox, use StartFooBar(p).
+// If you need multiple batches of work to be done in the sandboxed process,
+// use StartBatchMode(), then multiple calls to StartFooBar(p),
+// then finish with EndBatchMode().
class UtilityProcessHost : public BrowserChildProcessHost {
public:
// An interface to be implemented by consumers of the utility process to
@@ -73,6 +78,18 @@ class UtilityProcessHost : public BrowserChildProcessHost {
// Called when image data decoding failed.
virtual void OnDecodeImageFailed() {}
+ // Called when we have successfully obtained the IndexedDBKey after
+ // a call to StartIDBKeysFromValuesAndKeyPath.
+ // |id| is the corresponding identifier.
+ // |keys| the corresponding IndexedDBKey.
+ virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
+ int id, const std::vector<IndexedDBKey>& keys) {}
+
+ // Called when IDBKeyPath has failed.
+ // |id| is the corresponding identifier passed on
+ // StartIDBKeysFromValuesAndKeyPath.
+ virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id) {}
+
protected:
friend class base::RefCountedThreadSafe<Client>;
@@ -110,12 +127,26 @@ class UtilityProcessHost : public BrowserChildProcessHost {
// Start image decoding.
bool StartImageDecoding(const std::vector<unsigned char>& encoded_data);
+ // Starts extracting |key_path| from |serialized_values|, and replies with the
+ // corresponding IndexedDBKeys via OnIDBKeysFromValuesAndKeyPathSucceeded.
+ bool StartIDBKeysFromValuesAndKeyPath(
+ int id, const std::vector<SerializedScriptValue>& serialized_values,
+ const string16& key_path);
+
+ // Starts utility process in batch mode. Caller must call EndBatchMode()
+ // to finish the utility process.
+ bool StartBatchMode();
+
+ // Ends the utility process. Must be called after StartBatchMode().
+ void EndBatchMode();
+
protected:
// Allow these methods to be overridden for tests.
virtual FilePath GetUtilityProcessCmd();
private:
- // Starts a process. Returns true iff it succeeded.
+ // Starts a process if necessary. Returns true if it succeeded or a process
+ // has already been started via StartBatchMode().
bool StartProcess(const FilePath& exposed_dir);
// IPC messages:
@@ -133,6 +164,9 @@ class UtilityProcessHost : public BrowserChildProcessHost {
// A pointer to our client interface, who will be informed of progress.
scoped_refptr<Client> client_;
ChromeThread::ID client_thread_id_;
+ // True when running in batch mode, i.e., StartBatchMode() has been called
+ // and the utility process will run until EndBatchMode().
+ bool is_batch_mode_;
DISALLOW_COPY_AND_ASSIGN(UtilityProcessHost);
};
diff --git a/chrome/browser/view_ids.h b/chrome/browser/view_ids.h
index 8211ea2..c1e02a1 100644
--- a/chrome/browser/view_ids.h
+++ b/chrome/browser/view_ids.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_VIEW_IDS_H_
#define CHROME_BROWSER_VIEW_IDS_H_
+#pragma once
enum ViewID {
VIEW_ID_NONE = 0,
@@ -61,9 +62,6 @@ enum ViewID {
// Docked dev tools.
VIEW_ID_DEV_TOOLS_DOCKED,
- // Bottom extension shelf.
- VIEW_ID_DEV_EXTENSION_SHELF,
-
// The contents split.
VIEW_ID_CONTENTS_SPLIT,
@@ -73,6 +71,12 @@ enum ViewID {
// The Download shelf.
VIEW_ID_DOWNLOAD_SHELF,
+ // The Sidebar container.
+ VIEW_ID_SIDE_BAR_CONTAINER,
+
+ // The sidebar split.
+ VIEW_ID_SIDE_BAR_SPLIT,
+
// Used in chrome/browser/gtk/view_id_util_browsertests.cc
// If you add new ids, make sure the above test passes.
VIEW_ID_PREDEFINED_COUNT
diff --git a/chrome/browser/views/PRESUBMIT.py b/chrome/browser/views/PRESUBMIT.py
index 9ac9ee3..0a3657e 100755
--- a/chrome/browser/views/PRESUBMIT.py
+++ b/chrome/browser/views/PRESUBMIT.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# 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.
@@ -10,4 +10,4 @@ for more details on the presubmit API built into gcl.
"""
def GetPreferredTrySlaves():
- return ['linux_view']
+ return ['linux_view', 'linux_chromeos']
diff --git a/chrome/browser/views/about_chrome_view.cc b/chrome/browser/views/about_chrome_view.cc
index 7025bf6..03f9620 100644
--- a/chrome/browser/views/about_chrome_view.cc
+++ b/chrome/browser/views/about_chrome_view.cc
@@ -11,15 +11,18 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "base/file_version_info.h"
#include "base/i18n/rtl.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.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"
#include "chrome/browser/views/accessible_view_helper.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "gfx/canvas.h"
#include "grit/chromium_strings.h"
@@ -37,7 +40,6 @@
#if defined(OS_WIN)
#include <commdlg.h>
-#include "base/registry.h"
#include "base/win_util.h"
#include "chrome/browser/views/restart_message_box.h"
#include "chrome/installer/util/install_util.h"
@@ -105,7 +107,7 @@ AboutChromeView::AboutChromeView(Profile* profile)
chromium_url_(NULL),
open_source_url_(NULL),
terms_of_service_url_(NULL),
- check_button_status_(CHECKBUTTON_HIDDEN),
+ restart_button_visible_(false),
chromium_url_appears_first_(true),
text_direction_is_rtl_(false) {
DCHECK(profile);
@@ -139,23 +141,21 @@ void AboutChromeView::Init() {
text_direction_is_rtl_ = base::i18n::IsRTL();
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- if (version_info.get() == NULL) {
+ chrome::VersionInfo version_info;
+ if (!version_info.is_valid()) {
NOTREACHED() << L"Failed to initialize about window";
return;
}
- current_version_ = version_info->file_version();
+ current_version_ = ASCIIToWide(version_info.Version());
- string16 version_modifier = platform_util::GetVersionStringModifier();
- if (version_modifier.length()) {
- version_details_ += L" ";
- version_details_ += UTF16ToWide(version_modifier);
- }
+ std::string version_modifier = platform_util::GetVersionStringModifier();
+ if (!version_modifier.empty())
+ version_details_ += L" " + ASCIIToWide(version_modifier);
#if !defined(GOOGLE_CHROME_BUILD)
version_details_ += L" (";
- version_details_ += version_info->last_change();
+ version_details_ += ASCIIToWide(version_info.LastChange());
version_details_ += L")";
#endif
@@ -284,7 +284,7 @@ void AboutChromeView::Init() {
int height = about_background_logo->height() +
kRelatedControlVerticalSpacing +
// Copyright line.
- font.height() +
+ font.GetHeight() +
// Main label.
dummy_text.GetHeightForWidth(
dialog_dimensions_.width() - (2 * kPanelHorizMargin)) +
@@ -307,7 +307,7 @@ void AboutChromeView::Init() {
terms_of_service_url_->SetController(this);
// Add the Terms of Service line and some whitespace.
- height += font.height() + kRelatedControlVerticalSpacing;
+ height += font.GetHeight() + kRelatedControlVerticalSpacing;
#endif
// Use whichever is greater (the calculated height or the specified minimum
@@ -463,7 +463,7 @@ void AboutChromeView::Paint(gfx::Canvas* canvas) {
#if defined(GOOGLE_CHROME_BUILD)
// Insert a line break and some whitespace.
position.set_width(0);
- position.Enlarge(0, font.height() + kRelatedControlVerticalSpacing);
+ position.Enlarge(0, font.GetHeight() + kRelatedControlVerticalSpacing);
// And now the Terms of Service and position the TOS url.
view_text_utils::DrawTextAndPositionUrl(canvas, main_text_label_,
@@ -494,13 +494,13 @@ void AboutChromeView::Paint(gfx::Canvas* canvas) {
open_source_url_rect_.height());
// Save the height so we can set the bounds correctly.
- main_text_label_height_ = position.height() + font.height();
+ main_text_label_height_ = position.height() + font.GetHeight();
}
void AboutChromeView::ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) {
- // Since we want the some of the controls to show up in the same visual row
+ // Since we want some of the controls to show up in the same visual row
// as the buttons, which are provided by the framework, we must add the
// buttons to the non-client view, which is the parent of this view.
// Similarly, when we're removed from the view hierarchy, we must take care
@@ -554,10 +554,12 @@ void AboutChromeView::ViewHierarchyChanged(bool is_add,
std::wstring AboutChromeView::GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const {
if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- return l10n_util::GetString(IDS_ABOUT_CHROME_UPDATE_CHECK);
+ return l10n_util::GetString(IDS_RESTART_AND_UPDATE);
} else if (button == MessageBoxFlags::DIALOGBUTTON_CANCEL) {
+ if (restart_button_visible_)
+ return l10n_util::GetString(IDS_NOT_NOW);
// The OK button (which is the default button) has been re-purposed to be
- // 'Check for Updates' so we want the Cancel button should have the label
+ // 'Restart Now' so we want the Cancel button should have the label
// OK but act like a Cancel button in all other ways.
return l10n_util::GetString(IDS_OK);
}
@@ -572,20 +574,16 @@ std::wstring AboutChromeView::GetWindowTitle() const {
bool AboutChromeView::IsDialogButtonEnabled(
MessageBoxFlags::DialogButton button) const {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK &&
- check_button_status_ != CHECKBUTTON_ENABLED) {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK && !restart_button_visible_)
return false;
- }
return true;
}
bool AboutChromeView::IsDialogButtonVisible(
MessageBoxFlags::DialogButton button) const {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK &&
- check_button_status_ == CHECKBUTTON_HIDDEN) {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK && !restart_button_visible_)
return false;
- }
return true;
}
@@ -620,19 +618,13 @@ bool AboutChromeView::IsModal() const {
bool AboutChromeView::Accept() {
#if defined(OS_WIN) || defined(OS_CHROMEOS)
- UpdateStatus(UPGRADE_STARTED, GOOGLE_UPDATE_NO_ERROR);
-
- // The Upgrade button isn't available until we have received notification
- // that an update is available, at which point this pointer should have been
- // null-ed out.
- DCHECK(!google_updater_);
- google_updater_ = new GoogleUpdate();
- google_updater_->set_status_listener(this);
- // CheckForUpdate(true,...) means perform the upgrade if new version found.
- google_updater_->CheckForUpdate(true, window());
+ // Set the flag to restore the last session on shutdown.
+ PrefService* pref_service = g_browser_process->local_state();
+ pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
+ BrowserList::CloseAllBrowsersAndExit();
#endif
- return false; // We never allow this button to close the window.
+ return true;
}
views::View* AboutChromeView::GetContentsView() {
@@ -713,26 +705,27 @@ void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result,
switch (result) {
case UPGRADE_STARTED:
UserMetrics::RecordAction(UserMetricsAction("Upgrade_Started"), profile_);
- check_button_status_ = CHECKBUTTON_DISABLED;
show_throbber = true;
update_label_.SetText(l10n_util::GetString(IDS_UPGRADE_STARTED));
break;
case UPGRADE_CHECK_STARTED:
UserMetrics::RecordAction(UserMetricsAction("UpgradeCheck_Started"),
profile_);
- check_button_status_ = CHECKBUTTON_HIDDEN;
show_throbber = true;
update_label_.SetText(l10n_util::GetString(IDS_UPGRADE_CHECK_STARTED));
break;
case UPGRADE_IS_AVAILABLE:
UserMetrics::RecordAction(
UserMetricsAction("UpgradeCheck_UpgradeIsAvailable"), profile_);
- check_button_status_ = CHECKBUTTON_ENABLED;
- update_label_.SetText(
- l10n_util::GetStringF(IDS_UPGRADE_AVAILABLE,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
- show_update_available_indicator = true;
- break;
+ DCHECK(!google_updater_); // Should have been nulled out already.
+ google_updater_ = new GoogleUpdate();
+ google_updater_->set_status_listener(this);
+ UpdateStatus(UPGRADE_STARTED, GOOGLE_UPDATE_NO_ERROR);
+ // CheckForUpdate(true,...) means perform upgrade if new version found.
+ google_updater_->CheckForUpdate(true, window());
+ // TODO(seanparent): Need to see if this code needs to change to
+ // force a machine restart.
+ return;
case UPGRADE_ALREADY_UP_TO_DATE: {
// The extra version check is necessary on Windows because the application
// may be already up to date on disk though the running app is still
@@ -752,7 +745,6 @@ void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result,
#endif
UserMetrics::RecordAction(
UserMetricsAction("UpgradeCheck_AlreadyUpToDate"), profile_);
- check_button_status_ = CHECKBUTTON_HIDDEN;
#if defined(OS_CHROMEOS)
std::wstring update_label_text =
l10n_util::GetStringF(IDS_UPGRADE_ALREADY_UP_TO_DATE,
@@ -782,28 +774,20 @@ void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result,
else
UserMetrics::RecordAction(UserMetricsAction("UpgradeCheck_Upgraded"),
profile_);
- check_button_status_ = CHECKBUTTON_HIDDEN;
- const std::wstring& update_string = new_version_available_.empty()
- ? l10n_util::GetStringF(IDS_UPGRADE_SUCCESSFUL_NOVERSION,
- l10n_util::GetString(IDS_PRODUCT_NAME))
- : l10n_util::GetStringF(IDS_UPGRADE_SUCCESSFUL,
- l10n_util::GetString(IDS_PRODUCT_NAME),
- new_version_available_);
+ restart_button_visible_ = true;
+ const std::wstring& update_string =
+ l10n_util::GetStringF(IDS_UPGRADE_SUCCESSFUL_RESTART,
+ l10n_util::GetString(IDS_PRODUCT_NAME));
update_label_.SetText(update_string);
show_success_indicator = true;
- // TODO(seanparent): Need to see if this code needs to change to
- // force a machine restart.
-#if defined(OS_WIN)
- RestartMessageBox::ShowMessageBox(window()->GetNativeWindow());
-#endif
break;
}
case UPGRADE_ERROR:
UserMetrics::RecordAction(UserMetricsAction("UpgradeCheck_Error"),
profile_);
- check_button_status_ = CHECKBUTTON_HIDDEN;
+ restart_button_visible_ = false;
update_label_.SetText(l10n_util::GetStringF(IDS_UPGRADE_ERROR,
- IntToWString(error_code)));
+ UTF8ToWide(base::IntToString(error_code))));
show_timeout_indicator = true;
break;
default:
diff --git a/chrome/browser/views/about_chrome_view.h b/chrome/browser/views/about_chrome_view.h
index ebfa73b..828c4e6 100644
--- a/chrome/browser/views/about_chrome_view.h
+++ b/chrome/browser/views/about_chrome_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_ABOUT_CHROME_VIEW_H_
#define CHROME_BROWSER_VIEWS_ABOUT_CHROME_VIEW_H_
+#pragma once
#include "views/controls/image_view.h"
#include "views/controls/label.h"
@@ -12,7 +13,7 @@
#include "views/window/dialog_delegate.h"
#if defined(OS_WIN) || defined(OS_CHROMEOS)
-#include "chrome/browser/google_update.h"
+#include "chrome/browser/google/google_update.h"
#endif
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/version_loader.h"
@@ -83,13 +84,6 @@ class AboutChromeView : public views::View,
#endif
private:
- // The visible state of the Check For Updates button.
- enum CheckButtonStatus {
- CHECKBUTTON_HIDDEN = 0,
- CHECKBUTTON_DISABLED,
- CHECKBUTTON_ENABLED,
- };
-
#if defined(OS_WIN) || defined(OS_CHROMEOS)
// Update the UI to show the status of the upgrade.
void UpdateStatus(GoogleUpdateUpgradeResult result,
@@ -131,8 +125,8 @@ class AboutChromeView : public views::View,
// The dialog dimensions.
gfx::Size dialog_dimensions_;
- // Keeps track of the visible state of the Check For Updates button.
- CheckButtonStatus check_button_status_;
+ // Keeps track of the visible state of the Restart Now button.
+ bool restart_button_visible_;
// The text to display as the main label of the About box. We draw this text
// word for word with the help of the WordIterator, and make room for URLs
diff --git a/chrome/browser/views/about_ipc_dialog.cc b/chrome/browser/views/about_ipc_dialog.cc
index bf34905..a23b122 100644
--- a/chrome/browser/views/about_ipc_dialog.cc
+++ b/chrome/browser/views/about_ipc_dialog.cc
@@ -18,6 +18,7 @@
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_constants.h"
@@ -99,13 +100,14 @@ void CreateColumn(uint32 start, uint32 end, HWND hwnd,
control_ptr->InsertColumn(0, L"id", LVCFMT_LEFT, 230);
for (uint32 i = start; i < end; i++) {
- std::wstring name;
+ 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, name.c_str(), 0, 0, 0, i);
+ LVIF_TEXT | LVIF_PARAM, 0, wname.c_str(), 0, 0, 0, i);
- control_ptr->SetItemText(index, 0, name.c_str());
+ control_ptr->SetItemText(index, 0, wname.c_str());
if (disabled_messages.find(i) == disabled_messages.end())
control_ptr->SetCheckState(index, TRUE);
@@ -405,10 +407,12 @@ void AboutIPCDialog::Log(const IPC::LogData& data) {
message_list_.SetItemText(index, kChannelColumn,
ASCIIToWide(data.channel).c_str());
- std::wstring message_name;
+ std::string message_name;
IPC::Logging::GetMessageText(data.type, &message_name, NULL, NULL);
- message_list_.SetItemText(index, kMessageColumn, message_name.c_str());
- message_list_.SetItemText(index, kFlagsColumn, data.flags.c_str());
+ message_list_.SetItemText(index, kMessageColumn,
+ UTF8ToWide(message_name).c_str());
+ message_list_.SetItemText(index, kFlagsColumn,
+ UTF8ToWide(data.flags).c_str());
int64 time_to_send = (base::Time::FromInternalValue(data.receive) -
sent).InMilliseconds();
@@ -423,7 +427,8 @@ void AboutIPCDialog::Log(const IPC::LogData& data) {
temp = StringPrintf(L"%d", time_to_process);
message_list_.SetItemText(index, kProcessColumn, temp.c_str());
- message_list_.SetItemText(index, kParamsColumn, data.params.c_str());
+ message_list_.SetItemText(index, kParamsColumn,
+ UTF8ToWide(data.params).c_str());
message_list_.EnsureVisible(index, FALSE);
}
diff --git a/chrome/browser/views/about_ipc_dialog.h b/chrome/browser/views/about_ipc_dialog.h
index c0826b6..9594c8b 100644
--- a/chrome/browser/views/about_ipc_dialog.h
+++ b/chrome/browser/views/about_ipc_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_ABOUT_IPC_DIALOG_H_
#define CHROME_BROWSER_VIEWS_ABOUT_IPC_DIALOG_H_
+#pragma once
#if defined(OS_WIN) && defined(IPC_MESSAGE_LOG_ENABLED)
diff --git a/chrome/browser/views/accelerator_table_gtk.cc b/chrome/browser/views/accelerator_table_gtk.cc
index 584efe7..3baa65e 100644
--- a/chrome/browser/views/accelerator_table_gtk.cc
+++ b/chrome/browser/views/accelerator_table_gtk.cc
@@ -4,169 +4,150 @@
#include "chrome/browser/views/accelerator_table_gtk.h"
+#include "app/keyboard_codes.h"
#include "base/basictypes.h"
-#include "base/keyboard_codes.h"
#include "chrome/app/chrome_dll_resource.h"
namespace browser {
+// NOTE: Keep this list in the same (mostly-alphabetical) order as
+// the Windows accelerators in ../../app/chrome_dll.rc.
const AcceleratorMapping kAcceleratorMap[] = {
- // Format { keycode, shift_pressed, ctrl_pressed, alt_pressed, command_id }
-
- // Focus.
- { base::VKEY_K, false, true, false, IDC_FOCUS_SEARCH },
- { base::VKEY_E, false, true, false, IDC_FOCUS_SEARCH },
- { base::VKEY_BROWSER_SEARCH, false, false, false, IDC_FOCUS_SEARCH },
- { base::VKEY_L, false, true, false, IDC_FOCUS_LOCATION },
- { base::VKEY_D, false, false, true, IDC_FOCUS_LOCATION },
- { base::VKEY_T, true, false, true, IDC_FOCUS_TOOLBAR },
- { base::VKEY_B, true, false, true, IDC_FOCUS_BOOKMARKS },
- { base::VKEY_S, true, false, true, IDC_FOCUS_CHROMEOS_STATUS },
+ // Keycode Shift Ctrl Alt Command ID
+ { app::VKEY_A, true, true, false, IDC_AUTOFILL_DEFAULT },
+ { app::VKEY_LEFT, false, false, true, IDC_BACK },
+ { app::VKEY_BACK, false, false, false, IDC_BACK },
+#if defined(OS_CHROMEOS)
+ { app::VKEY_F1, false, false, false, IDC_BACK },
+#endif
+ { app::VKEY_D, false, true, false, IDC_BOOKMARK_PAGE },
+ { app::VKEY_D, true, true, false, IDC_BOOKMARK_ALL_TABS },
+ { app::VKEY_DELETE, true, true, false, IDC_CLEAR_BROWSING_DATA },
#if !defined(OS_CHROMEOS)
- { base::VKEY_F6, false, false, false, IDC_FOCUS_NEXT_PANE },
- { base::VKEY_F6, true, false, false, IDC_FOCUS_PREVIOUS_PANE },
- { base::VKEY_F10, false, false, false, IDC_FOCUS_MENU_BAR },
+ { app::VKEY_F4, false, true, false, IDC_CLOSE_TAB },
#endif
- { base::VKEY_MENU, false, false, false, IDC_FOCUS_MENU_BAR },
-
- // Tab/window controls.
- { base::VKEY_T, false, true, false, IDC_NEW_TAB },
- { base::VKEY_N, false, true, false, IDC_NEW_WINDOW },
- { base::VKEY_N, true, true, false, IDC_NEW_INCOGNITO_WINDOW },
- { base::VKEY_DOWN, false, true, false, IDC_SELECT_NEXT_TAB },
- { base::VKEY_UP, false, true, false, IDC_SELECT_PREVIOUS_TAB },
- { base::VKEY_W, false, true, false, IDC_CLOSE_TAB },
- { base::VKEY_T, true, true, false, IDC_RESTORE_TAB },
- { base::VKEY_W, true, true, false, IDC_CLOSE_WINDOW },
-
- { base::VKEY_TAB, false, true, false, IDC_SELECT_NEXT_TAB },
- { base::VKEY_TAB, true, true, false, IDC_SELECT_PREVIOUS_TAB },
-
- { base::VKEY_1, false, true, false, IDC_SELECT_TAB_0 },
- { base::VKEY_2, false, true, false, IDC_SELECT_TAB_1 },
- { base::VKEY_3, false, true, false, IDC_SELECT_TAB_2 },
- { base::VKEY_4, false, true, false, IDC_SELECT_TAB_3 },
- { base::VKEY_5, false, true, false, IDC_SELECT_TAB_4 },
- { base::VKEY_6, false, true, false, IDC_SELECT_TAB_5 },
- { base::VKEY_7, false, true, false, IDC_SELECT_TAB_6 },
- { base::VKEY_8, false, true, false, IDC_SELECT_TAB_7 },
- { base::VKEY_9, false, true, false, IDC_SELECT_LAST_TAB },
-
- { base::VKEY_1, false, false, true, IDC_SELECT_TAB_0 },
- { base::VKEY_2, false, false, true, IDC_SELECT_TAB_1 },
- { base::VKEY_3, false, false, true, IDC_SELECT_TAB_2 },
- { base::VKEY_4, false, false, true, IDC_SELECT_TAB_3 },
- { base::VKEY_5, false, false, true, IDC_SELECT_TAB_4 },
- { base::VKEY_6, false, false, true, IDC_SELECT_TAB_5 },
- { base::VKEY_7, false, false, true, IDC_SELECT_TAB_6 },
- { base::VKEY_8, false, false, true, IDC_SELECT_TAB_7 },
- { base::VKEY_9, false, false, true, IDC_SELECT_LAST_TAB },
-
- { base::VKEY_NUMPAD1, false, true, false, IDC_SELECT_TAB_0 },
- { base::VKEY_NUMPAD2, false, true, false, IDC_SELECT_TAB_1 },
- { base::VKEY_NUMPAD3, false, true, false, IDC_SELECT_TAB_2 },
- { base::VKEY_NUMPAD4, false, true, false, IDC_SELECT_TAB_3 },
- { base::VKEY_NUMPAD5, false, true, false, IDC_SELECT_TAB_4 },
- { base::VKEY_NUMPAD6, false, true, false, IDC_SELECT_TAB_5 },
- { base::VKEY_NUMPAD7, false, true, false, IDC_SELECT_TAB_6 },
- { base::VKEY_NUMPAD8, false, true, false, IDC_SELECT_TAB_7 },
- { base::VKEY_NUMPAD9, false, true, false, IDC_SELECT_LAST_TAB },
-
- { base::VKEY_NUMPAD1, false, false, true, IDC_SELECT_TAB_0 },
- { base::VKEY_NUMPAD2, false, false, true, IDC_SELECT_TAB_1 },
- { base::VKEY_NUMPAD3, false, false, true, IDC_SELECT_TAB_2 },
- { base::VKEY_NUMPAD4, false, false, true, IDC_SELECT_TAB_3 },
- { base::VKEY_NUMPAD5, false, false, true, IDC_SELECT_TAB_4 },
- { base::VKEY_NUMPAD6, false, false, true, IDC_SELECT_TAB_5 },
- { base::VKEY_NUMPAD7, false, false, true, IDC_SELECT_TAB_6 },
- { base::VKEY_NUMPAD8, false, false, true, IDC_SELECT_TAB_7 },
- { base::VKEY_NUMPAD9, false, false, true, IDC_SELECT_LAST_TAB },
-
+ { app::VKEY_W, false, true, false, IDC_CLOSE_TAB },
+ { app::VKEY_W, true, true, false, IDC_CLOSE_WINDOW },
#if !defined(OS_CHROMEOS)
- { base::VKEY_F4, false, true, false, IDC_CLOSE_TAB },
- { base::VKEY_F4, false, false, true, IDC_CLOSE_WINDOW },
+ { app::VKEY_F4, false, false, true, IDC_CLOSE_WINDOW },
#endif
-
- // Zoom level.
- { base::VKEY_OEM_PLUS, false, true, false, IDC_ZOOM_PLUS },
- { base::VKEY_OEM_PLUS, true, true, false, IDC_ZOOM_PLUS },
- { base::VKEY_0, false, true, false, IDC_ZOOM_NORMAL },
- { base::VKEY_OEM_MINUS, false, true, false, IDC_ZOOM_MINUS },
- { base::VKEY_OEM_MINUS, true, true, false, IDC_ZOOM_MINUS },
-
- // Find in page.
- { base::VKEY_F, false, true, false, IDC_FIND },
- { base::VKEY_G, false, true, false, IDC_FIND_NEXT },
+ { app::VKEY_Q, true, true, false, IDC_EXIT },
+ { app::VKEY_F, false, true, false, IDC_FIND },
+ { app::VKEY_G, false, true, false, IDC_FIND_NEXT },
#if !defined(OS_CHROMEOS)
- { base::VKEY_F3, false, false, false, IDC_FIND_NEXT },
+ { app::VKEY_F3, false, false, false, IDC_FIND_NEXT },
#endif
- { base::VKEY_G, true, true, false, IDC_FIND_PREVIOUS },
+ { app::VKEY_G, true, true, false, IDC_FIND_PREVIOUS },
#if !defined(OS_CHROMEOS)
- { base::VKEY_F3, true, false, false, IDC_FIND_PREVIOUS },
+ { app::VKEY_F3, true, false, false, IDC_FIND_PREVIOUS },
#endif
-
- // Navigation / toolbar buttons.
- { base::VKEY_HOME, false, false, true, IDC_HOME },
- { base::VKEY_ESCAPE, false, false, false, IDC_STOP },
- { base::VKEY_LEFT, false, false, true, IDC_BACK },
- { base::VKEY_BACK, false, false, false, IDC_BACK },
#if defined(OS_CHROMEOS)
- { base::VKEY_F1, false, false, false, IDC_BACK },
+ { app::VKEY_S, true, false, true, IDC_FOCUS_CHROMEOS_STATUS },
#endif
- { base::VKEY_RIGHT, false, false, true, IDC_FORWARD },
- { base::VKEY_BACK, true, false, false, IDC_FORWARD },
-#if defined(OS_CHROMEOS)
- { base::VKEY_F2, false, false, false, IDC_FORWARD },
+ { app::VKEY_D, false, false, true, IDC_FOCUS_LOCATION },
+ { app::VKEY_L, false, true, false, IDC_FOCUS_LOCATION },
+#if !defined(OS_CHROMEOS)
+ { app::VKEY_F10, false, false, false, IDC_FOCUS_MENU_BAR },
#endif
- { base::VKEY_R, false, true, false, IDC_RELOAD },
- { base::VKEY_R, true, true, false, IDC_RELOAD_IGNORING_CACHE },
+ { app::VKEY_MENU, false, false, false, IDC_FOCUS_MENU_BAR },
#if !defined(OS_CHROMEOS)
- { base::VKEY_F5, false, false, false, IDC_RELOAD },
- { base::VKEY_F5, false, true, false, IDC_RELOAD_IGNORING_CACHE },
- { base::VKEY_F5, true, false, false, IDC_RELOAD_IGNORING_CACHE },
+ { app::VKEY_F6, false, false, false, IDC_FOCUS_NEXT_PANE },
+#endif
+#if defined(OS_CHROMEOS)
+ { app::VKEY_F2, false, true, false, IDC_FOCUS_NEXT_PANE },
#endif
-
- // AutoFill.
- { base::VKEY_A, true, true, false, IDC_AUTOFILL_DEFAULT },
-
- // Miscellany.
- { base::VKEY_D, false, true, false, IDC_BOOKMARK_PAGE },
- { base::VKEY_D, true, true, false, IDC_BOOKMARK_ALL_TABS },
- { base::VKEY_DELETE, true, true, false, IDC_CLEAR_BROWSING_DATA },
- { base::VKEY_H, false, true, false, IDC_SHOW_HISTORY },
- { base::VKEY_J, false, true, false, IDC_SHOW_DOWNLOADS },
- { base::VKEY_O, false, true, false, IDC_OPEN_FILE },
#if !defined(OS_CHROMEOS)
- { base::VKEY_F11, false, false, false, IDC_FULLSCREEN },
+ { app::VKEY_F6, true, false, false, IDC_FOCUS_PREVIOUS_PANE },
+#endif
+#if defined(OS_CHROMEOS)
+ { app::VKEY_F1, false, true, false, IDC_FOCUS_PREVIOUS_PANE },
#endif
+ { app::VKEY_K, false, true, false, IDC_FOCUS_SEARCH },
+ { app::VKEY_E, false, true, false, IDC_FOCUS_SEARCH },
+ { app::VKEY_BROWSER_SEARCH, false, false, false, IDC_FOCUS_SEARCH },
+ { app::VKEY_T, true, false, true, IDC_FOCUS_TOOLBAR },
+ { app::VKEY_B, true, false, true, IDC_FOCUS_BOOKMARKS },
+ { app::VKEY_RIGHT, false, false, true, IDC_FORWARD },
+ { app::VKEY_BACK, true, false, false, IDC_FORWARD },
#if defined(OS_CHROMEOS)
- { base::VKEY_F4, false, false, false, IDC_FULLSCREEN },
-#endif
- { base::VKEY_U, false, true, false, IDC_VIEW_SOURCE },
- { base::VKEY_I, true, true, false, IDC_DEV_TOOLS },
- { base::VKEY_J, true, true, false, IDC_DEV_TOOLS_CONSOLE },
- { base::VKEY_C, true, true, false, IDC_DEV_TOOLS_INSPECT },
- { base::VKEY_P, false, true, false, IDC_PRINT},
- { base::VKEY_ESCAPE, true, false, false, IDC_TASK_MANAGER },
+ { app::VKEY_F2, false, false, false, IDC_FORWARD },
+#endif
#if !defined(OS_CHROMEOS)
- { base::VKEY_F11, false, true, true, IDC_FULLSCREEN },
+ { app::VKEY_F11, false, false, false, IDC_FULLSCREEN },
#endif
- { base::VKEY_DELETE, false, true, true, IDC_TASK_MANAGER },
- { base::VKEY_OEM_COMMA, false, true, false, IDC_SYSTEM_OPTIONS },
#if defined(OS_CHROMEOS)
- { base::VKEY_F5, false, false, false, IDC_SYSTEM_OPTIONS },
+ { app::VKEY_F4, false, false, false, IDC_FULLSCREEN },
+#endif
+#if !defined(OS_CHROMEOS)
+ { app::VKEY_F1, false, false, false, IDC_HELP_PAGE },
#endif
- { base::VKEY_B, true, true, false, IDC_SHOW_BOOKMARK_BAR },
+ { app::VKEY_I, true, true, false, IDC_DEV_TOOLS },
+ { app::VKEY_J, true, true, false, IDC_DEV_TOOLS_CONSOLE },
+ { app::VKEY_C, true, true, false, IDC_DEV_TOOLS_INSPECT },
+ { app::VKEY_N, true, true, false, IDC_NEW_INCOGNITO_WINDOW },
+ { app::VKEY_T, false, true, false, IDC_NEW_TAB },
+ { app::VKEY_N, false, true, false, IDC_NEW_WINDOW },
+ { app::VKEY_O, false, true, false, IDC_OPEN_FILE },
+ { app::VKEY_P, false, true, false, IDC_PRINT},
+ { app::VKEY_R, false, true, false, IDC_RELOAD },
+ { app::VKEY_R, true, true, false, IDC_RELOAD_IGNORING_CACHE },
#if !defined(OS_CHROMEOS)
- { base::VKEY_F1, false, false, false, IDC_HELP_PAGE },
+ { app::VKEY_F5, false, false, false, IDC_RELOAD },
+ { app::VKEY_F5, false, true, false, IDC_RELOAD_IGNORING_CACHE },
+ { app::VKEY_F5, true, false, false, IDC_RELOAD_IGNORING_CACHE },
+#endif
+#if defined(OS_CHROMEOS)
+ { app::VKEY_F3, false, false, false, IDC_RELOAD },
+ { app::VKEY_F3, false, true, false, IDC_RELOAD_IGNORING_CACHE },
+ { app::VKEY_F3, true, false, false, IDC_RELOAD_IGNORING_CACHE },
+#endif
+ { app::VKEY_HOME, false, false, true, IDC_HOME },
+ { app::VKEY_T, true, true, false, IDC_RESTORE_TAB },
+ { app::VKEY_S, false, true, false, IDC_SAVE_PAGE },
+#if defined(OS_CHROMEOS)
+ { app::VKEY_LWIN, false, false, false, IDC_SEARCH },
#endif
- { base::VKEY_Q, true, true, false, IDC_EXIT },
- { base::VKEY_F, false, false, true, IDC_SHOW_APP_MENU},
- { base::VKEY_E, false, false, true, IDC_SHOW_APP_MENU},
+ { app::VKEY_9, false, true, false, IDC_SELECT_LAST_TAB },
+ { app::VKEY_NUMPAD9, false, true, false, IDC_SELECT_LAST_TAB },
+ { app::VKEY_TAB, false, true, false, IDC_SELECT_NEXT_TAB },
+ { app::VKEY_NEXT, false, true, false, IDC_SELECT_NEXT_TAB },
+ { app::VKEY_TAB, true, true, false, IDC_SELECT_PREVIOUS_TAB },
+ { app::VKEY_PRIOR, false, true, false, IDC_SELECT_PREVIOUS_TAB },
+ { app::VKEY_1, false, true, false, IDC_SELECT_TAB_0 },
+ { app::VKEY_NUMPAD1, false, true, false, IDC_SELECT_TAB_0 },
+ { app::VKEY_2, false, true, false, IDC_SELECT_TAB_1 },
+ { app::VKEY_NUMPAD2, false, true, false, IDC_SELECT_TAB_1 },
+ { app::VKEY_3, false, true, false, IDC_SELECT_TAB_2 },
+ { app::VKEY_NUMPAD3, false, true, false, IDC_SELECT_TAB_2 },
+ { app::VKEY_4, false, true, false, IDC_SELECT_TAB_3 },
+ { app::VKEY_NUMPAD4, false, true, false, IDC_SELECT_TAB_3 },
+ { app::VKEY_5, false, true, false, IDC_SELECT_TAB_4 },
+ { app::VKEY_NUMPAD5, false, true, false, IDC_SELECT_TAB_4 },
+ { app::VKEY_6, false, true, false, IDC_SELECT_TAB_5 },
+ { app::VKEY_NUMPAD6, false, true, false, IDC_SELECT_TAB_5 },
+ { app::VKEY_7, false, true, false, IDC_SELECT_TAB_6 },
+ { app::VKEY_NUMPAD7, false, true, false, IDC_SELECT_TAB_6 },
+ { app::VKEY_8, false, true, false, IDC_SELECT_TAB_7 },
+ { app::VKEY_NUMPAD8, false, true, false, IDC_SELECT_TAB_7 },
+ { app::VKEY_B, true, true, false, IDC_SHOW_BOOKMARK_BAR },
+ { app::VKEY_J, false, true, false, IDC_SHOW_DOWNLOADS },
+ { app::VKEY_H, false, true, false, IDC_SHOW_HISTORY },
+ { app::VKEY_F, false, false, true, IDC_SHOW_APP_MENU},
+ { app::VKEY_E, false, false, true, IDC_SHOW_APP_MENU},
+ { app::VKEY_ESCAPE, false, false, false, IDC_STOP },
#if defined(OS_CHROMEOS)
- { base::VKEY_F, false, true, true, IDC_FULLSCREEN },
- { base::VKEY_LWIN, false, false, false, IDC_SEARCH },
+ { app::VKEY_F5, false, false, false, IDC_SYSTEM_OPTIONS },
#endif
+ { app::VKEY_ESCAPE, true, false, false, IDC_TASK_MANAGER },
+ { app::VKEY_U, false, true, false, IDC_VIEW_SOURCE },
+ { app::VKEY_OEM_MINUS, false, true, false, IDC_ZOOM_MINUS },
+ { app::VKEY_OEM_MINUS, true, true, false, IDC_ZOOM_MINUS },
+ { app::VKEY_SUBTRACT, false, true, false, IDC_ZOOM_MINUS },
+ { app::VKEY_0, false, true, false, IDC_ZOOM_NORMAL },
+ { app::VKEY_NUMPAD0, false, true, false, IDC_ZOOM_NORMAL },
+ { app::VKEY_OEM_PLUS, false, true, false, IDC_ZOOM_PLUS },
+ { app::VKEY_OEM_PLUS, true, true, false, IDC_ZOOM_PLUS },
+ { app::VKEY_ADD, false, true, false, IDC_ZOOM_PLUS },
};
const size_t kAcceleratorMapLength = arraysize(kAcceleratorMap);
diff --git a/chrome/browser/views/accelerator_table_gtk.h b/chrome/browser/views/accelerator_table_gtk.h
index 78e161f..bbab634 100644
--- a/chrome/browser/views/accelerator_table_gtk.h
+++ b/chrome/browser/views/accelerator_table_gtk.h
@@ -4,17 +4,18 @@
#ifndef CHROME_BROWSER_VIEWS_ACCELERATOR_TABLE_GTK_H_
#define CHROME_BROWSER_VIEWS_ACCELERATOR_TABLE_GTK_H_
+#pragma once
#include <stdio.h>
-#include "base/keyboard_codes.h"
+#include "app/keyboard_codes.h"
// This contains the list of accelerators for the Linux toolkit_view
// implementation.
namespace browser {
struct AcceleratorMapping {
- base::KeyboardCode keycode;
+ app::KeyboardCode keycode;
bool shift_pressed;
bool ctrl_pressed;
bool alt_pressed;
diff --git a/chrome/browser/views/accessibility_event_router_views.cc b/chrome/browser/views/accessibility_event_router_views.cc
index 32dfaeb..b8bfc25 100644
--- a/chrome/browser/views/accessibility_event_router_views.cc
+++ b/chrome/browser/views/accessibility_event_router_views.cc
@@ -11,16 +11,20 @@
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_type.h"
+#include "views/accessibility/accessibility_types.h"
#include "views/controls/button/image_button.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/button/native_button.h"
#include "views/controls/link.h"
+#include "views/controls/menu/menu_item_view.h"
+#include "views/controls/menu/submenu_view.h"
+#include "views/view.h"
using views::FocusManager;
-using views::View;
AccessibilityEventRouterViews::AccessibilityEventRouterViews()
- : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
+ : most_recent_profile_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}
AccessibilityEventRouterViews::~AccessibilityEventRouterViews() {
@@ -31,63 +35,55 @@ AccessibilityEventRouterViews* AccessibilityEventRouterViews::GetInstance() {
return Singleton<AccessibilityEventRouterViews>::get();
}
-bool AccessibilityEventRouterViews::AddViewTree(View* view, Profile* profile) {
+bool AccessibilityEventRouterViews::AddViewTree(
+ views::View* view, Profile* profile) {
if (view_tree_profile_map_[view] != NULL)
return false;
view_tree_profile_map_[view] = profile;
- FocusManager* focus_manager = view->GetFocusManager();
-
- // Add this object as a listener for this focus manager, but use a ref
- // count to ensure we only call AddFocusChangeListener on any given
- // focus manager once. Note that hash_map<FocusManager*, int>::operator[]
- // will initialize the ref count to zero if it's not already in the map.
- if (focus_manager_ref_count_[focus_manager] == 0) {
- focus_manager->AddFocusChangeListener(this);
- }
- focus_manager_ref_count_[focus_manager]++;
-
- view_info_map_[view].focus_manager = focus_manager;
return true;
}
-void AccessibilityEventRouterViews::RemoveViewTree(View* view) {
+void AccessibilityEventRouterViews::RemoveViewTree(views::View* view) {
DCHECK(view_tree_profile_map_.find(view) !=
view_tree_profile_map_.end());
view_tree_profile_map_.erase(view);
-
- // Decrement the ref count of the focus manager, and remove this object
- // as a listener if the count reaches zero.
- FocusManager* focus_manager = view_info_map_[view].focus_manager;
- DCHECK(focus_manager);
- focus_manager_ref_count_[focus_manager]--;
- if (focus_manager_ref_count_[focus_manager] == 0) {
- focus_manager->RemoveFocusChangeListener(this);
- }
}
-void AccessibilityEventRouterViews::IgnoreView(View* view) {
+void AccessibilityEventRouterViews::IgnoreView(views::View* view) {
view_info_map_[view].ignore = true;
}
-void AccessibilityEventRouterViews::SetViewName(View* view, std::string name) {
+void AccessibilityEventRouterViews::SetViewName(
+ views::View* view, std::string name) {
view_info_map_[view].name = name;
}
-void AccessibilityEventRouterViews::RemoveView(View* view) {
+void AccessibilityEventRouterViews::RemoveView(views::View* view) {
DCHECK(view_info_map_.find(view) != view_info_map_.end());
view_info_map_.erase(view);
}
-//
-// views::FocusChangeListener
-//
-
-void AccessibilityEventRouterViews::FocusWillChange(
- View* focused_before, View* focused_now) {
- if (focused_now) {
- DispatchAccessibilityNotification(
- focused_now, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
+void AccessibilityEventRouterViews::HandleAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type) {
+ switch (event_type) {
+ case AccessibilityTypes::EVENT_ALERT:
+ // TODO(dtseng): does this have any meaning in this context.
+ break;
+ case AccessibilityTypes::EVENT_FOCUS:
+ DispatchAccessibilityNotification(
+ view, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
+ break;
+ case AccessibilityTypes::EVENT_MENUSTART:
+ case AccessibilityTypes::EVENT_MENUPOPUPSTART:
+ DispatchAccessibilityNotification(
+ view, NotificationType::ACCESSIBILITY_MENU_OPENED);
+ break;
+ case AccessibilityTypes::EVENT_MENUEND:
+ case AccessibilityTypes::EVENT_MENUPOPUPEND:
+ DispatchAccessibilityNotification(
+ view, NotificationType::ACCESSIBILITY_MENU_CLOSED);
+ break;
}
}
@@ -96,11 +92,11 @@ void AccessibilityEventRouterViews::FocusWillChange(
//
void AccessibilityEventRouterViews::FindView(
- View* view, Profile** profile, bool* is_accessible) {
+ views::View* view, Profile** profile, bool* is_accessible) {
*is_accessible = false;
// First see if it's a descendant of an accessible view.
- for (base::hash_map<View*, Profile*>::const_iterator iter =
+ for (base::hash_map<views::View*, Profile*>::const_iterator iter =
view_tree_profile_map_.begin();
iter != view_tree_profile_map_.end();
++iter) {
@@ -115,17 +111,17 @@ void AccessibilityEventRouterViews::FindView(
return;
// Now make sure it's not marked as a widget to be ignored.
- base::hash_map<View*, ViewInfo>::const_iterator iter =
+ base::hash_map<views::View*, ViewInfo>::const_iterator iter =
view_info_map_.find(view);
if (iter != view_info_map_.end() && iter->second.ignore)
*is_accessible = false;
}
-std::string AccessibilityEventRouterViews::GetViewName(View* view) {
+std::string AccessibilityEventRouterViews::GetViewName(views::View* view) {
std::string name;
// First see if we have a name registered for this view.
- base::hash_map<View*, ViewInfo>::const_iterator iter =
+ base::hash_map<views::View*, ViewInfo>::const_iterator iter =
view_info_map_.find(view);
if (iter != view_info_map_.end())
name = iter->second.name;
@@ -141,38 +137,119 @@ std::string AccessibilityEventRouterViews::GetViewName(View* view) {
}
void AccessibilityEventRouterViews::DispatchAccessibilityNotification(
- View* view, NotificationType type) {
+ views::View* view, NotificationType type) {
Profile* profile = NULL;
bool is_accessible;
FindView(view, &profile, &is_accessible);
+
+ // Special case: a menu isn't associated with any particular top-level
+ // window, so menu events get routed to the profile of the most recent
+ // event that was associated with a window, which should be the window
+ // that triggered opening the menu.
+ bool is_menu_event = IsMenuEvent(view, type);
+ if (is_menu_event && !profile && most_recent_profile_) {
+ profile = most_recent_profile_;
+ is_accessible = true;
+ }
+
if (!is_accessible)
return;
- if (view->GetClassName() == views::ImageButton::kViewClassName) {
- SendButtonNotification(view, type, profile);
- } else if (view->GetClassName() == views::NativeButton::kViewClassName) {
+ most_recent_profile_ = profile;
+
+ std::string class_name = view->GetClassName();
+
+ if (class_name == views::MenuButton::kViewClassName ||
+ type == NotificationType::ACCESSIBILITY_MENU_OPENED ||
+ type == NotificationType::ACCESSIBILITY_MENU_CLOSED) {
+ SendMenuNotification(view, type, profile);
+ } else if (is_menu_event) {
+ SendMenuItemNotification(view, type, profile);
+ } else if (class_name == views::ImageButton::kViewClassName ||
+ class_name == views::NativeButton::kViewClassName ||
+ class_name == views::TextButton::kViewClassName) {
SendButtonNotification(view, type, profile);
- } else if (view->GetClassName() == views::Link::kViewClassName) {
+ } else if (class_name == views::Link::kViewClassName) {
SendLinkNotification(view, type, profile);
- } else if (view->GetClassName() == views::MenuButton::kViewClassName) {
- SendMenuNotification(view, type, profile);
}
}
void AccessibilityEventRouterViews::SendButtonNotification(
- View* view, NotificationType type, Profile* profile) {
+ views::View* view, NotificationType type, Profile* profile) {
AccessibilityButtonInfo info(profile, GetViewName(view));
SendAccessibilityNotification(type, &info);
}
void AccessibilityEventRouterViews::SendLinkNotification(
- View* view, NotificationType type, Profile* profile) {
+ views::View* view, NotificationType type, Profile* profile) {
AccessibilityLinkInfo info(profile, GetViewName(view));
SendAccessibilityNotification(type, &info);
}
void AccessibilityEventRouterViews::SendMenuNotification(
- View* view, NotificationType type, Profile* profile) {
+ views::View* view, NotificationType type, Profile* profile) {
AccessibilityMenuInfo info(profile, GetViewName(view));
SendAccessibilityNotification(type, &info);
}
+
+void AccessibilityEventRouterViews::SendMenuItemNotification(
+ views::View* view, NotificationType type, Profile* profile) {
+ std::string name = GetViewName(view);
+
+ bool has_submenu = false;
+ int index = -1;
+ int count = -1;
+
+ if (view->GetClassName() == views::MenuItemView::kViewClassName)
+ has_submenu = static_cast<views::MenuItemView*>(view)->HasSubmenu();
+
+ views::View* parent_menu = view->GetParent();
+ while (parent_menu != NULL && parent_menu->GetClassName() !=
+ views::SubmenuView::kViewClassName) {
+ parent_menu = parent_menu->GetParent();
+ }
+ if (parent_menu) {
+ count = 0;
+ RecursiveGetMenuItemIndexAndCount(parent_menu, view, &index, &count);
+ }
+
+ AccessibilityMenuItemInfo info(profile, name, has_submenu, index, count);
+ SendAccessibilityNotification(type, &info);
+}
+
+void AccessibilityEventRouterViews::RecursiveGetMenuItemIndexAndCount(
+ views::View* menu, views::View* item, int* index, int* count) {
+ for (int i = 0; i < menu->GetChildViewCount(); ++i) {
+ views::View* child = menu->GetChildViewAt(i);
+ int previous_count = *count;
+ RecursiveGetMenuItemIndexAndCount(child, item, index, count);
+ if (child->GetClassName() == views::MenuItemView::kViewClassName &&
+ *count == previous_count) {
+ if (item == child)
+ *index = *count;
+ (*count)++;
+ } else if (child->GetClassName() == views::TextButton::kViewClassName) {
+ if (item == child)
+ *index = *count;
+ (*count)++;
+ }
+ }
+}
+
+bool AccessibilityEventRouterViews::IsMenuEvent(
+ views::View* view, NotificationType type) {
+ if (type == NotificationType::ACCESSIBILITY_MENU_OPENED ||
+ type == NotificationType::ACCESSIBILITY_MENU_CLOSED)
+ return true;
+
+ while (view) {
+ AccessibilityTypes::Role role = view->GetAccessibleRole();
+ if (role == AccessibilityTypes::ROLE_MENUITEM ||
+ role == AccessibilityTypes::ROLE_MENUPOPUP) {
+ return true;
+ }
+ view = view->GetParent();
+ }
+
+ return false;
+}
diff --git a/chrome/browser/views/accessibility_event_router_views.h b/chrome/browser/views/accessibility_event_router_views.h
index 024faf1..ae79df0 100644
--- a/chrome/browser/views/accessibility_event_router_views.h
+++ b/chrome/browser/views/accessibility_event_router_views.h
@@ -4,29 +4,27 @@
#ifndef CHROME_BROWSER_VIEWS_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_
#define CHROME_BROWSER_VIEWS_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/hash_tables.h"
#include "base/singleton.h"
#include "base/task.h"
#include "chrome/browser/accessibility_events.h"
-#include "views/view.h"
-#include "views/widget/root_view.h"
+#include "views/accessibility/accessibility_types.h"
class Profile;
+namespace views {
+class View;
+}
-// Allows us to use (View*) and (FocusManager*) in a hash_map with gcc.
+// Allows us to use (View*) in a hash_map with gcc.
#if defined(COMPILER_GCC)
namespace __gnu_cxx {
template<>
-struct hash<views::FocusManager*> {
- size_t operator()(views::FocusManager* focus_manager) const {
- return reinterpret_cast<size_t>(focus_manager);
- }
-};
-template<>
struct hash<views::View*> {
size_t operator()(views::View* view) const {
return reinterpret_cast<size_t>(view);
@@ -50,23 +48,18 @@ struct hash<views::View*> {
//
// You can use Profile::PauseAccessibilityEvents to prevent a flurry
// of accessibility events when a window is being created or initialized.
-class AccessibilityEventRouterViews
- : public views::FocusChangeListener {
+class AccessibilityEventRouterViews {
public:
// Internal information about a particular view to override the
// information we get directly from the view.
struct ViewInfo {
- ViewInfo() : ignore(false), focus_manager(NULL) {}
+ ViewInfo() : ignore(false) {}
// If nonempty, will use this name instead of the view's label.
std::string name;
// If true, will ignore this widget and not send accessibility events.
bool ignore;
-
- // The focus manager that this view is part of - saved because
- // GetFocusManager may not succeed while a view is being deleted.
- views::FocusManager* focus_manager;
};
// Get the single instance of this class.
@@ -93,11 +86,18 @@ class AccessibilityEventRouterViews
// Forget all information about this view.
void RemoveView(views::View* view);
- // Implementation of views::FocusChangeListener:
- virtual void FocusWillChange(
- views::View* focused_before, views::View* focused_now);
+ // Handle an accessibility event generated by a view.
+ void HandleAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type);
private:
+ AccessibilityEventRouterViews();
+ virtual ~AccessibilityEventRouterViews();
+
+ friend struct DefaultSingletonTraits<AccessibilityEventRouterViews>;
+ FRIEND_TEST_ALL_PREFIXES(AccessibilityEventRouterViewsTest,
+ TestFocusNotification);
+
// Given a view, determine if it's part of a view tree that's mapped to
// a profile and if so, if it's marked as accessible.
void FindView(views::View* view, Profile** profile, bool* is_accessible);
@@ -118,12 +118,19 @@ class AccessibilityEventRouterViews
views::View* view, NotificationType type, Profile* profile);
void SendMenuNotification(
views::View* view, NotificationType type, Profile* profile);
+ void SendMenuItemNotification(
+ views::View* view, NotificationType type, Profile* profile);
- private:
- AccessibilityEventRouterViews();
- virtual ~AccessibilityEventRouterViews();
+ // Return true if it's an event on a menu.
+ bool IsMenuEvent(views::View* view, NotificationType type);
- friend struct DefaultSingletonTraits<AccessibilityEventRouterViews>;
+ // Recursively explore all menu items of |menu| and return in |count|
+ // the total number of items, and in |index| the 0-based index of
+ // |item|, if found. Initialize |count| to zero before calling this
+ // method. |index| will be unchanged if the item is not found, so
+ // initialize it to -1 to detect this case.
+ void RecursiveGetMenuItemIndexAndCount(
+ views::View* menu, views::View* item, int* index, int* count);
// The set of all view tree roots; only descendants of these will generate
// accessibility notifications.
@@ -132,8 +139,10 @@ class AccessibilityEventRouterViews
// Extra information about specific views.
base::hash_map<views::View*, ViewInfo> view_info_map_;
- // Count of the number of references to each focus manager.
- base::hash_map<views::FocusManager*, int> focus_manager_ref_count_;
+ // The profile associated with the most recent window event - used to
+ // figure out where to route a few events that can't be directly traced
+ // to a window with a profile (like menu events).
+ Profile* most_recent_profile_;
// Used to defer handling of some events until the next time
// through the event loop.
diff --git a/chrome/browser/views/accessibility_event_router_views_unittest.cc b/chrome/browser/views/accessibility_event_router_views_unittest.cc
index 392b0d9..700499d 100644
--- a/chrome/browser/views/accessibility_event_router_views_unittest.cc
+++ b/chrome/browser/views/accessibility_event_router_views_unittest.cc
@@ -6,6 +6,7 @@
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/views/accessibility_event_router_views.h"
#include "chrome/browser/views/accessible_view_helper.h"
@@ -15,6 +16,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/button/native_button.h"
#include "views/grid_layout.h"
+#include "views/views_delegate.h"
#include "views/widget/root_view.h"
#include "views/window/window.h"
@@ -26,10 +28,54 @@
#if defined(TOOLKIT_VIEWS)
+class AccessibilityViewsDelegate : public views::ViewsDelegate {
+ public:
+ AccessibilityViewsDelegate() {}
+ virtual ~AccessibilityViewsDelegate() {}
+
+ // Overridden from views::ViewsDelegate:
+ virtual Clipboard* GetClipboard() const { return NULL; }
+ virtual void SaveWindowPlacement(const std::wstring& window_name,
+ const gfx::Rect& bounds,
+ bool maximized) {
+ }
+ virtual bool GetSavedWindowBounds(const std::wstring& window_name,
+ gfx::Rect* bounds) const {
+ return false;
+ }
+ virtual bool GetSavedMaximizedState(const std::wstring& window_name,
+ bool* maximized) const {
+ return false;
+ }
+ virtual void NotifyAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type) {
+ AccessibilityEventRouterViews::GetInstance()->HandleAccessibilityEvent(
+ view, event_type);
+ }
+#if defined(OS_WIN)
+ virtual HICON GetDefaultWindowIcon() const {
+ return NULL;
+ }
+#endif
+ virtual void AddRef() {}
+ virtual void ReleaseRef() {}
+
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityViewsDelegate);
+};
+
class AccessibilityEventRouterViewsTest
: public testing::Test,
public NotificationObserver {
public:
+ virtual void SetUp() {
+ views::ViewsDelegate::views_delegate = new AccessibilityViewsDelegate();
+ }
+
+ virtual void TearDown() {
+ delete views::ViewsDelegate::views_delegate;
+ views::ViewsDelegate::views_delegate = NULL;
+ }
+
views::Widget* CreateWidget() {
#if defined(OS_WIN)
return new views::WidgetWin();
@@ -37,6 +83,7 @@ class AccessibilityEventRouterViewsTest
return new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
#endif
}
+
protected:
// Implement NotificationObserver::Observe and store information about a
// ACCESSIBILITY_CONTROL_FOCUSED event.
@@ -55,8 +102,7 @@ class AccessibilityEventRouterViewsTest
std::string last_control_name_;
};
-// Temporarily disabled due to http://crbug.com/48717
-TEST_F(AccessibilityEventRouterViewsTest, DISABLED_TestFocusNotification) {
+TEST_F(AccessibilityEventRouterViewsTest, TestFocusNotification) {
const char kButton1ASCII[] = "Button1";
const char kButton2ASCII[] = "Button2";
const char kButton3ASCII[] = "Button3";
diff --git a/chrome/browser/views/accessible_toolbar_view.cc b/chrome/browser/views/accessible_toolbar_view.cc
index 8c8fb88..1702214 100644
--- a/chrome/browser/views/accessible_toolbar_view.cc
+++ b/chrome/browser/views/accessible_toolbar_view.cc
@@ -18,13 +18,13 @@ AccessibleToolbarView::AccessibleToolbarView()
: toolbar_has_focus_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
focus_manager_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(focus_search_(this, true, true)),
- home_key_(base::VKEY_HOME, false, false, false),
- end_key_(base::VKEY_END, false, false, false),
- escape_key_(base::VKEY_ESCAPE, false, false, false),
- left_key_(base::VKEY_LEFT, false, false, false),
- right_key_(base::VKEY_RIGHT, false, false, false),
+ home_key_(app::VKEY_HOME, false, false, false),
+ end_key_(app::VKEY_END, false, false, false),
+ escape_key_(app::VKEY_ESCAPE, false, false, false),
+ left_key_(app::VKEY_LEFT, false, false, false),
+ right_key_(app::VKEY_RIGHT, false, false, false),
last_focused_view_storage_id_(-1) {
+ focus_search_.reset(new views::FocusSearch(this, true, true));
}
AccessibleToolbarView::~AccessibleToolbarView() {
@@ -118,7 +118,7 @@ void AccessibleToolbarView::RestoreLastFocusedView() {
views::View* AccessibleToolbarView::GetFirstFocusableChild() {
FocusTraversable* dummy_focus_traversable;
views::View* dummy_focus_traversable_view;
- return focus_search_.FindNextFocusableView(
+ return focus_search_->FindNextFocusableView(
NULL, false, views::FocusSearch::DOWN, false,
&dummy_focus_traversable, &dummy_focus_traversable_view);
}
@@ -126,7 +126,7 @@ views::View* AccessibleToolbarView::GetFirstFocusableChild() {
views::View* AccessibleToolbarView::GetLastFocusableChild() {
FocusTraversable* dummy_focus_traversable;
views::View* dummy_focus_traversable_view;
- return focus_search_.FindNextFocusableView(
+ return focus_search_->FindNextFocusableView(
this, true, views::FocusSearch::DOWN, false,
&dummy_focus_traversable, &dummy_focus_traversable_view);
}
@@ -148,27 +148,27 @@ bool AccessibleToolbarView::AcceleratorPressed(
views::View* focused_view = focus_manager_->GetFocusedView();
if ((focused_view->GetClassName() == LocationBarView::kViewClassName ||
focused_view->GetClassName() == views::NativeViewHost::kViewClassName) &&
- (accelerator.GetKeyCode() == base::VKEY_LEFT ||
- accelerator.GetKeyCode() == base::VKEY_RIGHT)) {
+ (accelerator.GetKeyCode() == app::VKEY_LEFT ||
+ accelerator.GetKeyCode() == app::VKEY_RIGHT)) {
return false;
}
switch (accelerator.GetKeyCode()) {
- case base::VKEY_ESCAPE:
+ case app::VKEY_ESCAPE:
RemoveToolbarFocus();
RestoreLastFocusedView();
return true;
- case base::VKEY_LEFT:
+ case app::VKEY_LEFT:
focus_manager_->AdvanceFocus(true);
return true;
- case base::VKEY_RIGHT:
+ case app::VKEY_RIGHT:
focus_manager_->AdvanceFocus(false);
return true;
- case base::VKEY_HOME:
+ case app::VKEY_HOME:
focus_manager_->SetFocusedViewWithReason(
GetFirstFocusableChild(), views::FocusManager::kReasonFocusTraversal);
return true;
- case base::VKEY_END:
+ case app::VKEY_END:
focus_manager_->SetFocusedViewWithReason(
GetLastFocusableChild(), views::FocusManager::kReasonFocusTraversal);
return true;
@@ -185,11 +185,8 @@ void AccessibleToolbarView::SetVisible(bool flag) {
View::SetVisible(flag);
}
-bool AccessibleToolbarView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_TOOLBAR;
- return true;
+AccessibilityTypes::Role AccessibleToolbarView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_TOOLBAR;
}
////////////////////////////////////////////////////////////////////////////////
@@ -223,7 +220,7 @@ void AccessibleToolbarView::FocusWillChange(views::View* focused_before,
views::FocusSearch* AccessibleToolbarView::GetFocusSearch() {
DCHECK(toolbar_has_focus_);
- return &focus_search_;
+ return focus_search_.get();
}
views::FocusTraversable* AccessibleToolbarView::GetFocusTraversableParent() {
diff --git a/chrome/browser/views/accessible_toolbar_view.h b/chrome/browser/views/accessible_toolbar_view.h
index 2ad93e4..e6d3d59 100644
--- a/chrome/browser/views/accessible_toolbar_view.h
+++ b/chrome/browser/views/accessible_toolbar_view.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_VIEWS_ACCESSIBLE_TOOLBAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_ACCESSIBLE_TOOLBAR_VIEW_H_
+#pragma once
#include "base/hash_tables.h"
+#include "base/scoped_ptr.h"
#include "base/task.h"
-#include "chrome/browser/views/accessibility_event_router_views.h"
#include "views/focus/focus_manager.h"
#include "views/view.h"
@@ -43,7 +44,7 @@ class AccessibleToolbarView : public views::View,
virtual FocusTraversable* GetPaneFocusTraversable();
virtual bool AcceleratorPressed(const views::Accelerator& accelerator);
virtual void SetVisible(bool flag);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
// Overridden from views::FocusChangeListener:
virtual void FocusWillChange(View* focused_before,
@@ -78,7 +79,7 @@ class AccessibleToolbarView : public views::View,
// Our custom focus search implementation that traps focus in this
// toolbar and traverses all views that are focusable for accessibility,
// not just those that are normally focusable.
- views::FocusSearch focus_search_;
+ scoped_ptr<views::FocusSearch> focus_search_;
// Registered accelerators
views::Accelerator home_key_;
diff --git a/chrome/browser/views/accessible_view_helper.cc b/chrome/browser/views/accessible_view_helper.cc
index f173761..63f381b 100644
--- a/chrome/browser/views/accessible_view_helper.cc
+++ b/chrome/browser/views/accessible_view_helper.cc
@@ -7,13 +7,13 @@
#include "app/l10n_util.h"
#include "chrome/browser/accessibility_events.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/views/accessibility_event_router_views.h"
#include "chrome/common/notification_service.h"
#include "views/widget/widget.h"
-
-using views::View;
+#include "views/view.h"
AccessibleViewHelper::AccessibleViewHelper(
- View* view_tree, Profile* profile)
+ views::View* view_tree, Profile* profile)
: accessibility_event_router_(AccessibilityEventRouterViews::GetInstance()),
profile_(profile),
view_tree_(view_tree) {
@@ -53,7 +53,7 @@ void AccessibleViewHelper::SendOpenWindowNotification(
Details<AccessibilityWindowInfo>(&info));
}
-void AccessibleViewHelper::IgnoreView(View* view) {
+void AccessibleViewHelper::IgnoreView(views::View* view) {
if (!view_tree_)
return;
@@ -61,7 +61,7 @@ void AccessibleViewHelper::IgnoreView(View* view) {
managed_views_.push_back(view);
}
-void AccessibleViewHelper::SetViewName(View* view, std::string name) {
+void AccessibleViewHelper::SetViewName(views::View* view, std::string name) {
if (!view_tree_)
return;
@@ -69,7 +69,7 @@ void AccessibleViewHelper::SetViewName(View* view, std::string name) {
managed_views_.push_back(view);
}
-void AccessibleViewHelper::SetViewName(View* view, int string_id) {
+void AccessibleViewHelper::SetViewName(views::View* view, int string_id) {
if (!view_tree_)
return;
diff --git a/chrome/browser/views/accessible_view_helper.h b/chrome/browser/views/accessible_view_helper.h
index 2d01238..2f6f434 100644
--- a/chrome/browser/views/accessible_view_helper.h
+++ b/chrome/browser/views/accessible_view_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_ACCESSIBLE_VIEW_HELPER_H_
#define CHROME_BROWSER_VIEWS_ACCESSIBLE_VIEW_HELPER_H_
+#pragma once
#include <string>
#include <vector>
@@ -12,13 +13,16 @@
#include "base/scoped_ptr.h"
#include "base/singleton.h"
#include "chrome/browser/accessibility_events.h"
-#include "chrome/browser/views/accessibility_event_router_views.h"
#if defined(OS_LINUX)
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#endif
+class AccessibilityEventRouterViews;
class Profile;
+namespace views {
+class View;
+}
// NOTE: This class is part of the Accessibility Extension API, which lets
// extensions receive accessibility events. It's distinct from code that
diff --git a/chrome/browser/views/app_launched_animation_win.cc b/chrome/browser/views/app_launched_animation_win.cc
index 5637fc5..8a23d43 100644
--- a/chrome/browser/views/app_launched_animation_win.cc
+++ b/chrome/browser/views/app_launched_animation_win.cc
@@ -8,6 +8,7 @@
#include "app/slide_animation.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "gfx/rect.h"
#include "views/controls/image_view.h"
@@ -72,7 +73,8 @@ AppLaunchedAnimationWin::AppLaunchedAnimationWin(Extension* extension,
DCHECK(extension);
app_icon_loader_.LoadImage(
extension,
- extension->GetIconPath(Extension::EXTENSION_ICON_LARGE),
+ extension->GetIconResource(Extension::EXTENSION_ICON_LARGE,
+ ExtensionIconSet::MATCH_EXACTLY),
rect_.size(),
ImageLoadingTracker::DONT_CACHE);
}
@@ -120,8 +122,6 @@ void AppLaunchedAnimationWin::OnImageLoaded(SkBitmap* image,
animation_->SetTweenType(Tween::LINEAR);
animation_->Reset(1.0);
animation_->Hide();
- } else {
- popup_->Close();
}
}
diff --git a/chrome/browser/views/app_launcher.cc b/chrome/browser/views/app_launcher.cc
index 65f2eda..c011d87 100644
--- a/chrome/browser/views/app_launcher.cc
+++ b/chrome/browser/views/app_launcher.cc
@@ -7,13 +7,13 @@
#include <string>
#include <vector>
-#include "app/resource_bundle.h"
-#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/dom_view.h"
#include "chrome/browser/views/info_bubble.h"
@@ -41,20 +41,6 @@ const double kAnimationSpeedPxPerMS = 1.5;
const SkColor kBorderColor = SkColorSetRGB(205, 201, 201);
-// Command line switch for specifying url of the page.
-// TODO: nuke when we convert to the real app page. Also nuke code in
-// AddNewContents
-const wchar_t kURLSwitch[] = L"main-menu-url";
-
-// Returns the URL of the menu.
-static GURL GetMenuURL() {
- std::wstring url_string =
- CommandLine::ForCurrentProcess()->GetSwitchValue(kURLSwitch);
- if (!url_string.empty())
- return GURL(WideToUTF8(url_string));
- return GURL(chrome::kChromeUIAppLauncherURL);
-}
-
// Returns the location bar view of |browser|.
static views::View* GetBrowserLocationBar(Browser* browser) {
BrowserView* browser_view = static_cast<BrowserView*>(browser->window());
@@ -100,6 +86,7 @@ class InfoBubbleContentsView : public views::View,
// WARNING: this is not the TabContents of the bubble! Use
// GetBubbleTabContents() to get the bubble's TabContents.
virtual TabContents* GetTabContents();
+ virtual MatchPreview* GetMatchPreview() { return NULL; }
virtual void OnInputInProgress(bool in_progress) {}
// CommandUpdater::CommandUpdaterDelegate implementation:
@@ -177,7 +164,7 @@ void InfoBubbleContentsView::ViewHierarchyChanged(
// We make the AppLauncher the TabContents delegate so we get notifications
// from the page to open links.
dom_view_->tab_contents()->set_delegate(app_launcher_);
- GURL url = GetMenuURL();
+ GURL url(chrome::kChromeUIAppLauncherURL);
std::string ref = url.ref();
if (!app_launcher_->hash_params().empty()) {
if (!ref.empty())
@@ -222,10 +209,10 @@ void InfoBubbleContentsView::Layout() {
return;
gfx::Rect bounds = GetLocalBounds(false);
- // The browser's location bar use a vertical padding that we need to take into
+ // The browser's location bar uses vertical padding that we need to take into
// account to match its height.
- int location_bar_height =
- location_bar_->GetPreferredSize().height() - LocationBarView::kVertMargin;
+ int location_bar_height = location_bar_->GetPreferredSize().height() -
+ LocationBarView::kVerticalEdgeThickness;
location_bar_->SetBounds(bounds.x(), bounds.y(), bounds.width(),
location_bar_height);
int render_y = location_bar_->bounds().bottom() + kNavigationBarBottomPadding;
@@ -323,15 +310,6 @@ void AppLauncher::AddNewContents(TabContents* source,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
bool user_gesture) {
-#if defined(OS_CHROMEOS)
- // ChromeOS uses the kURLSwitch to specify a page that opens popups. We need
- // to do this so the popups are opened when the user clicks on the page.
- // TODO: nuke when convert to the real app page.
- new_contents->set_delegate(NULL);
- browser_->GetSelectedTabContents()->AddNewContents(
- new_contents, disposition, initial_pos, user_gesture);
- Hide();
-#endif
}
void AppLauncher::UpdatePreferredSize(const gfx::Size& pref_size) {
@@ -388,7 +366,7 @@ void AppLauncher::AddTabWithURL(const GURL& url,
browser_->AddTabWithURL(
url, GURL(), transition, -1,
TabStripModel::ADD_SELECTED | TabStripModel::ADD_FORCE_INDEX, NULL,
- std::string());
+ std::string(), NULL);
}
void AppLauncher::Resize(const gfx::Size& contents_size) {
diff --git a/chrome/browser/views/app_launcher.h b/chrome/browser/views/app_launcher.h
index 3a03f9e..2f99ec8 100644
--- a/chrome/browser/views/app_launcher.h
+++ b/chrome/browser/views/app_launcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_APP_LAUNCHER_H_
#define CHROME_BROWSER_VIEWS_APP_LAUNCHER_H_
+#pragma once
#include <string>
@@ -85,10 +86,10 @@ class AppLauncher : public AnimationDelegate,
const gfx::Rect& initial_pos,
bool user_gesture);
virtual void ActivateContents(TabContents* contents) {}
+ virtual void DeactivateContents(TabContents* contents) {}
virtual void LoadingStateChanged(TabContents* source) {}
virtual void CloseContents(TabContents* source) {}
virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
- virtual bool IsPopup(TabContents* source) { return false; }
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
virtual void URLStarredChanged(TabContents* source, bool starred) {}
virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
diff --git a/chrome/browser/views/appcache_info_view.cc b/chrome/browser/views/appcache_info_view.cc
index 55973ec..03d3919 100644
--- a/chrome/browser/views/appcache_info_view.cc
+++ b/chrome/browser/views/appcache_info_view.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/views/appcache_info_view.h"
-#include "app/l10n_util.h"
#include "base/i18n/time_formatting.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/views/appcache_info_view.h b/chrome/browser/views/appcache_info_view.h
index f78162f..e943425 100644
--- a/chrome/browser/views/appcache_info_view.h
+++ b/chrome/browser/views/appcache_info_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_APPCACHE_INFO_VIEW_H_
#define CHROME_BROWSER_VIEWS_APPCACHE_INFO_VIEW_H_
+#pragma once
#include "chrome/browser/views/generic_info_view.h"
#include "chrome/browser/browsing_data_appcache_helper.h"
diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc
index 45a10bf..7db0e42 100644
--- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc
+++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h"
+#include "unicode/ubidi.h"
+
#include "app/bidi_line_iterator.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
@@ -22,7 +24,6 @@
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkShader.h"
-#include "third_party/icu/public/common/unicode/ubidi.h"
#include "views/widget/widget.h"
#if defined(OS_WIN)
@@ -33,6 +34,11 @@
#include "app/win_util.h"
#endif
+#if defined(OS_LINUX)
+#include "chrome/browser/gtk/gtk_util.h"
+#include "gfx/skia_utils_gtk.h"
+#endif
+
namespace {
enum ResultViewState {
@@ -59,6 +65,14 @@ SkColor GetColor(ResultViewState state, ColorKind kind) {
colors[SELECTED][BACKGROUND] = color_utils::GetSysSkColor(COLOR_HIGHLIGHT);
colors[NORMAL][TEXT] = color_utils::GetSysSkColor(COLOR_WINDOWTEXT);
colors[SELECTED][TEXT] = color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT);
+#elif defined(OS_LINUX)
+ GdkColor bg_color, selected_bg_color, text_color, selected_text_color;
+ gtk_util::GetTextColors(
+ &bg_color, &selected_bg_color, &text_color, &selected_text_color);
+ colors[NORMAL][BACKGROUND] = gfx::GdkColorToSkColor(bg_color);
+ colors[SELECTED][BACKGROUND] = gfx::GdkColorToSkColor(selected_bg_color);
+ colors[NORMAL][TEXT] = gfx::GdkColorToSkColor(text_color);
+ colors[SELECTED][TEXT] = gfx::GdkColorToSkColor(selected_text_color);
#else
// TODO(beng): source from theme provider.
colors[NORMAL][BACKGROUND] = SK_ColorWHITE;
@@ -109,7 +123,8 @@ class AutocompleteResultView : public views::View {
public:
AutocompleteResultView(AutocompleteResultViewModel* model,
int model_index,
- const gfx::Font& font);
+ const gfx::Font& font,
+ const gfx::Font& bold_font);
virtual ~AutocompleteResultView();
// Updates the match used to paint the contents of this result view. We copy
@@ -122,6 +137,10 @@ class AutocompleteResultView : public views::View {
virtual void Layout();
virtual gfx::Size GetPreferredSize();
+ // Returns the preferred height for a single row.
+ static int GetPreferredHeight(const gfx::Font& font,
+ const gfx::Font& bold_font);
+
private:
// Precalculated data used to draw the portion of a match classification that
// fits entirely within one run.
@@ -186,9 +205,8 @@ class AutocompleteResultView : public views::View {
AutocompleteResultViewModel* model_;
size_t model_index_;
- // The fonts used to render the text in this row.
- gfx::Font normal_font_;
- gfx::Font bold_font_;
+ const gfx::Font normal_font_;
+ const gfx::Font bold_font_;
// Width of the ellipsis in the normal font.
int ellipsis_width_;
@@ -250,11 +268,12 @@ class AutocompleteResultView::MirroringContext {
AutocompleteResultView::AutocompleteResultView(
AutocompleteResultViewModel* model,
int model_index,
- const gfx::Font& font)
+ const gfx::Font& font,
+ const gfx::Font& bold_font)
: model_(model),
model_index_(model_index),
normal_font_(font),
- bold_font_(normal_font_.DeriveFont(0, gfx::Font::BOLD)),
+ bold_font_(bold_font),
ellipsis_width_(font.GetStringWidth(kEllipsis)),
mirroring_context_(new MirroringContext()),
match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) {
@@ -305,20 +324,27 @@ void AutocompleteResultView::Paint(gfx::Canvas* canvas) {
}
void AutocompleteResultView::Layout() {
- icon_bounds_.SetRect(LocationBarView::kItemPadding,
+ icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding,
(height() - icon_size_) / 2, icon_size_, icon_size_);
int text_x = icon_bounds_.right() + LocationBarView::kItemPadding;
- int font_height = std::max(normal_font_.height(), bold_font_.height());
+ int font_height = std::max(normal_font_.GetHeight(), bold_font_.GetHeight());
text_bounds_.SetRect(text_x, std::max(0, (height() - font_height) / 2),
- std::max(0, bounds().width() - text_x - LocationBarView::kItemPadding),
- font_height);
+ std::max(bounds().width() - text_x - LocationBarView::kEdgeItemPadding,
+ 0), font_height);
}
gfx::Size AutocompleteResultView::GetPreferredSize() {
- int text_height = std::max(normal_font_.height(), bold_font_.height()) +
+ return gfx::Size(0, GetPreferredHeight(normal_font_, bold_font_));
+}
+
+// static
+int AutocompleteResultView::GetPreferredHeight(
+ const gfx::Font& font,
+ const gfx::Font& bold_font) {
+ int text_height = std::max(font.GetHeight(), bold_font.GetHeight()) +
(kTextVerticalPadding * 2);
int icon_height = icon_size_ + (kIconVerticalPadding * 2);
- return gfx::Size(0, std::max(icon_height, text_height));
+ return std::max(icon_height, text_height);
}
// static
@@ -497,7 +523,7 @@ int AutocompleteResultView::DrawString(
j != i->classifications.end(); ++j) {
int left = mirroring_context_->mirrored_left_coord(x, x + j->pixel_width);
canvas->DrawStringInt(j->text, *j->font, j->color, left, y,
- j->pixel_width, j->font->height(), flags);
+ j->pixel_width, j->font->GetHeight(), flags);
x += j->pixel_width;
}
}
@@ -602,6 +628,7 @@ AutocompletePopupContentsView::AutocompletePopupContentsView(
edit_view_(edit_view),
location_bar_(location_bar),
result_font_(font.DeriveFont(kEditFontAdjust)),
+ result_bold_font_(result_font_.DeriveFont(0, gfx::Font::BOLD)),
ignore_mouse_drag_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(size_animation_(this)) {
// The following little dance is required because set_border() requires a
@@ -666,7 +693,8 @@ void AutocompletePopupContentsView::UpdatePopupAppearance() {
for (size_t i = 0; i < model_->result().size(); ++i) {
AutocompleteResultView* result_view;
if (i >= child_view_count) {
- result_view = new AutocompleteResultView(this, i, result_font_);
+ result_view =
+ new AutocompleteResultView(this, i, result_font_, result_bold_font_);
AddChildView(result_view);
} else {
result_view = static_cast<AutocompleteResultView*>(GetChildViewAt(i));
@@ -675,26 +703,7 @@ void AutocompletePopupContentsView::UpdatePopupAppearance() {
total_child_height += result_view->GetPreferredSize().height();
}
- // Calculate desired bounds.
- gfx::Rect location_bar_bounds(gfx::Point(), location_bar_->size());
- const views::Border* border = location_bar_->border();
- if (border) {
- // Adjust for the border so that the bubble and location bar borders are
- // aligned.
- gfx::Insets insets;
- border->GetInsets(&insets);
- location_bar_bounds.Inset(insets.left(), 0, insets.right(), 0);
- } else {
- // The normal location bar is drawn using a background graphic that includes
- // the border, so we inset by enough to make the edges line up, and the
- // bubble appear at the same height as the Star bubble.
- location_bar_bounds.Inset(LocationBarView::kEdgeThickness, 0);
- }
- gfx::Point location_bar_origin(location_bar_bounds.origin());
- views::View::ConvertPointToScreen(location_bar_, &location_bar_origin);
- location_bar_bounds.set_origin(location_bar_origin);
- gfx::Rect new_target_bounds(bubble_border_->GetBounds(location_bar_bounds,
- gfx::Size(location_bar_bounds.width(), total_child_height)));
+ gfx::Rect new_target_bounds = CalculateTargetBounds(total_child_height);
// If we're animating and our target height changes, reset the animation.
// NOTE: If we just reset blindly on _every_ update, then when the user types
@@ -721,6 +730,10 @@ void AutocompletePopupContentsView::UpdatePopupAppearance() {
SchedulePaint();
}
+gfx::Rect AutocompletePopupContentsView::GetTargetBounds() {
+ return target_bounds_;
+}
+
void AutocompletePopupContentsView::PaintUpdatesNow() {
// TODO(beng): remove this from the interface.
}
@@ -733,6 +746,15 @@ AutocompletePopupModel* AutocompletePopupContentsView::GetModel() {
return model_.get();
}
+int AutocompletePopupContentsView::GetMaxYCoordinate() {
+ // Add one to kMaxMatches to account for the history shortcut that may be
+ // added.
+ return CalculateTargetBounds(
+ (static_cast<int>(AutocompleteResult::kMaxMatches) + 1) *
+ AutocompleteResultView::GetPreferredHeight(
+ result_font_, result_bold_font_)).bottom();
+}
+
////////////////////////////////////////////////////////////////////////////////
// AutocompletePopupContentsView, AutocompleteResultViewModel implementation:
@@ -982,3 +1004,26 @@ size_t AutocompletePopupContentsView::GetIndexForPoint(
}
return AutocompletePopupModel::kNoMatch;
}
+
+gfx::Rect AutocompletePopupContentsView::CalculateTargetBounds(int h) {
+ gfx::Rect location_bar_bounds(gfx::Point(), location_bar_->size());
+ const views::Border* border = location_bar_->border();
+ if (border) {
+ // Adjust for the border so that the bubble and location bar borders are
+ // aligned.
+ gfx::Insets insets;
+ border->GetInsets(&insets);
+ location_bar_bounds.Inset(insets.left(), 0, insets.right(), 0);
+ } else {
+ // The normal location bar is drawn using a background graphic that includes
+ // the border, so we inset by enough to make the edges line up, and the
+ // bubble appear at the same height as the Star bubble.
+ location_bar_bounds.Inset(LocationBarView::kNormalHorizontalEdgeThickness,
+ 0);
+ }
+ gfx::Point location_bar_origin(location_bar_bounds.origin());
+ views::View::ConvertPointToScreen(location_bar_, &location_bar_origin);
+ location_bar_bounds.set_origin(location_bar_origin);
+ return bubble_border_->GetBounds(
+ location_bar_bounds, gfx::Size(location_bar_bounds.width(), h));
+}
diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h
index 80704cd..5253004 100644
--- a/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h
+++ b/chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_CONTENTS_VIEW_H_
#define CHROME_BROWSER_VIEWS_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_CONTENTS_VIEW_H_
+#pragma once
#include "app/slide_animation.h"
#include "chrome/browser/autocomplete/autocomplete.h"
@@ -60,9 +61,11 @@ class AutocompletePopupContentsView : public views::View,
virtual bool IsOpen() const;
virtual void InvalidateLine(size_t line);
virtual void UpdatePopupAppearance();
+ virtual gfx::Rect GetTargetBounds();
virtual void PaintUpdatesNow();
virtual void OnDragCanceled();
virtual AutocompletePopupModel* GetModel();
+ virtual int GetMaxYCoordinate();
// Overridden from AutocompleteResultViewModel:
virtual bool IsSelectedIndex(size_t index) const;
@@ -118,6 +121,9 @@ class AutocompletePopupContentsView : public views::View,
// match at the specified point.
size_t GetIndexForPoint(const gfx::Point& point);
+ // Returns the target bounds given the specified content height.
+ gfx::Rect CalculateTargetBounds(int h);
+
// The popup that contains this view. We create this, but it deletes itself
// when its window is destroyed. This is a WeakPtr because it's possible for
// the OS to destroy the window and thus delete this object before we're
@@ -140,6 +146,9 @@ class AutocompletePopupContentsView : public views::View,
// by the edit that created us.
gfx::Font result_font_;
+ // The font used for portions that match the input.
+ gfx::Font result_bold_font_;
+
// If the user cancels a dragging action (i.e. by pressing ESC), we don't have
// a convenient way to release mouse capture. Instead we use this flag to
// simply ignore all remaining drag events, and the eventual mouse release
diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_gtk.h b/chrome/browser/views/autocomplete/autocomplete_popup_gtk.h
index 1117311..461420a 100644
--- a/chrome/browser/views/autocomplete/autocomplete_popup_gtk.h
+++ b/chrome/browser/views/autocomplete/autocomplete_popup_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_GTK_H_
#define CHROME_BROWSER_VIEWS_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_GTK_H_
+#pragma once
#include "base/weak_ptr.h"
#include "views/widget/widget_gtk.h"
diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_win.cc b/chrome/browser/views/autocomplete/autocomplete_popup_win.cc
index 4cb7ddc..e720108 100644
--- a/chrome/browser/views/autocomplete/autocomplete_popup_win.cc
+++ b/chrome/browser/views/autocomplete/autocomplete_popup_win.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/views/autocomplete/autocomplete_popup_win.h"
-#include "app/win_util.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view_win.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h"
diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_win.h b/chrome/browser/views/autocomplete/autocomplete_popup_win.h
index affe0a9..cf6a364 100644
--- a/chrome/browser/views/autocomplete/autocomplete_popup_win.h
+++ b/chrome/browser/views/autocomplete/autocomplete_popup_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_WIN_H_
#define CHROME_BROWSER_VIEWS_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_WIN_H_
+#pragma once
#include "base/weak_ptr.h"
#include "views/widget/widget_win.h"
diff --git a/chrome/browser/views/autofill_profiles_view_win.cc b/chrome/browser/views/autofill_profiles_view_win.cc
index 1ea9457..0c85fec 100644
--- a/chrome/browser/views/autofill_profiles_view_win.cc
+++ b/chrome/browser/views/autofill_profiles_view_win.cc
@@ -1,6 +1,7 @@
// Copyright (c) 2010 The Chromium Authors. All rights 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/autofill_profiles_view_win.h"
#include <vsstyle.h>
@@ -9,18 +10,21 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/phone_number.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/list_background.h"
#include "chrome/browser/window_sizer.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/pref_names.h"
#include "gfx/canvas.h"
#include "gfx/native_theme_win.h"
@@ -52,6 +56,23 @@ const int kDialogPadding = 7;
const int kSubViewHorizotalInsets = 18;
const int kSubViewVerticalInsets = 5;
+// This is a helper to compare items that were just created with items returned
+// from the db.
+// ProfileType could be either AutofillProfile or CreditCard.
+// The second argument could have an incomplete ID (0) - change it to first
+// argument's id for comparison and then change it back.
+template<class ProfileType> bool IsEqualDataWithIncompleteId(
+ ProfileType const * data_to_compare, ProfileType* data_with_incomplete_id) {
+ if (!data_with_incomplete_id->unique_id()) {
+ data_with_incomplete_id->set_unique_id(data_to_compare->unique_id());
+ bool are_equal = (*data_with_incomplete_id == *data_with_incomplete_id);
+ data_with_incomplete_id->set_unique_id(0);
+ return are_equal;
+ } else {
+ return (*data_with_incomplete_id == *data_with_incomplete_id);
+ }
+}
+
}; // namespace
/////////////////////////////////////////////////////////////////////////////
@@ -81,6 +102,7 @@ AutoFillProfilesView::AutoFillProfilesView(
billing_model_(true),
child_dialog_opened_(false) {
DCHECK(preferences_);
+ enable_auto_fill_.Init(prefs::kAutoFillEnabled, preferences_, this);
if (imported_profile) {
profiles_set_.push_back(EditableSetInfo(imported_profile));
}
@@ -88,6 +110,7 @@ AutoFillProfilesView::AutoFillProfilesView(
credit_card_set_.push_back(
EditableSetInfo(imported_credit_card));
}
+ personal_data_manager_->SetObserver(this);
}
AutoFillProfilesView::~AutoFillProfilesView() {
@@ -95,7 +118,6 @@ AutoFillProfilesView::~AutoFillProfilesView() {
if (scroll_view_)
scroll_view_->SetModel(NULL);
- // Removes observer if we are observing Profile load. Does nothing otherwise.
if (personal_data_manager_)
personal_data_manager_->RemoveObserver(this);
}
@@ -132,15 +154,16 @@ void AutoFillProfilesView::AddClicked(int group_type) {
profiles_set_.push_back(EditableSetInfo(&address));
added_item_index = profiles_set_.size() - 1;
it = profiles_set_.begin() + added_item_index;
+ unique_ids_to_indexes_[0] = profiles_set_.size() - 1;
} else if (group_type == ContentListTableModel::kCreditCardGroup) {
CreditCard credit_card(std::wstring(), 0);
credit_card_set_.push_back(EditableSetInfo(&credit_card));
added_item_index = profiles_set_.size() + credit_card_set_.size() - 1;
it = credit_card_set_.begin() + (credit_card_set_.size() - 1);
+ unique_ids_to_indexes_[0] = credit_card_set_.size() - 1;
} else {
NOTREACHED();
}
-
EditableSetViewContents *edit_view = new
EditableSetViewContents(this, &billing_model_, true, it);
views::Window::CreateChromeWindow(window()->GetNativeWindow(), gfx::Rect(),
@@ -149,8 +172,9 @@ void AutoFillProfilesView::AddClicked(int group_type) {
}
void AutoFillProfilesView::EditClicked() {
- DCHECK(scroll_view_);
int index = scroll_view_->FirstSelectedRow();
+ if (index == -1)
+ return; // Happens if user double clicks and the table is empty.
DCHECK(index >= 0);
DCHECK(index < static_cast<int>(profiles_set_.size() +
credit_card_set_.size()));
@@ -168,8 +192,6 @@ void AutoFillProfilesView::EditClicked() {
}
void AutoFillProfilesView::DeleteClicked() {
- DCHECK(scroll_view_);
- DCHECK(table_model_.get());
DCHECK_GT(scroll_view_->SelectedRowCount(), 0);
int last_view_row = -1;
for (views::TableView::iterator i = scroll_view_->SelectionBegin();
@@ -181,17 +203,16 @@ void AutoFillProfilesView::DeleteClicked() {
last_view_row = table_model_->RowCount() - 1;
if (last_view_row >= 0)
scroll_view_->Select(scroll_view_->ViewToModel(last_view_row));
- UpdateButtonState();
+ UpdateBillingModel();
+ UpdateWidgetState();
+ UpdateIdToIndexes();
+ SaveData();
}
-void AutoFillProfilesView::UpdateButtonState() {
- DCHECK(personal_data_manager_);
- DCHECK(scroll_view_);
- DCHECK(add_address_button_);
- DCHECK(add_credit_card_button_);
- DCHECK(edit_button_);
- DCHECK(remove_button_);
- bool autofill_enabled = preferences_->GetBoolean(prefs::kAutoFillEnabled);
+void AutoFillProfilesView::UpdateWidgetState() {
+ bool autofill_enabled = enable_auto_fill_.GetValue();
+ enable_auto_fill_button_->SetChecked(autofill_enabled);
+ enable_auto_fill_button_->SetEnabled(!enable_auto_fill_.IsManaged());
scroll_view_->SetEnabled(autofill_enabled);
add_address_button_->SetEnabled(personal_data_manager_->IsDataLoaded() &&
!child_dialog_opened_ && autofill_enabled);
@@ -215,17 +236,21 @@ void AutoFillProfilesView::UpdateProfileLabels() {
AutoFillProfile::AdjustInferredLabels(&profiles);
}
+void AutoFillProfilesView::UpdateBillingModel() {
+ billing_model_.SetAddressLabels(profiles_set_);
+}
+
void AutoFillProfilesView::ChildWindowOpened() {
child_dialog_opened_ = true;
- UpdateButtonState();
+ UpdateWidgetState();
}
void AutoFillProfilesView::ChildWindowClosed() {
child_dialog_opened_ = false;
- UpdateButtonState();
+ UpdateWidgetState();
}
-SkBitmap* AutoFillProfilesView::GetWarningBimap(bool good) {
+SkBitmap* AutoFillProfilesView::GetWarningBitmap(bool good) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
return rb.GetBitmapNamed(good ? IDR_INPUT_GOOD : IDR_INPUT_ALERT);
}
@@ -304,11 +329,10 @@ bool AutoFillProfilesView::IsDialogButtonEnabled(
std::wstring AutoFillProfilesView::GetWindowTitle() const {
- return l10n_util::GetString(IDS_AUTOFILL_OPTIONS);
+ return l10n_util::GetString(IDS_AUTOFILL_OPTIONS_TITLE);
}
void AutoFillProfilesView::WindowClosing() {
- DCHECK(focus_manager_);
focus_manager_->RemoveFocusChangeListener(this);
instance_ = NULL;
}
@@ -323,20 +347,6 @@ bool AutoFillProfilesView::Cancel() {
}
bool AutoFillProfilesView::Accept() {
- DCHECK(observer_);
- std::vector<AutoFillProfile> profiles;
- profiles.reserve(profiles_set_.size());
- std::vector<EditableSetInfo>::iterator it;
- for (it = profiles_set_.begin(); it != profiles_set_.end(); ++it) {
- profiles.push_back(it->address);
- }
- std::vector<CreditCard> credit_cards;
- credit_cards.reserve(credit_card_set_.size());
- for (it = credit_card_set_.begin(); it != credit_card_set_.end(); ++it) {
- credit_cards.push_back(it->credit_card);
- }
- DCHECK(preferences_);
- observer_->OnAutoFillDialogApply(&profiles, &credit_cards);
return true;
}
@@ -357,9 +367,9 @@ void AutoFillProfilesView::ButtonPressed(views::Button* sender,
UserMetricsAction action(enabled ? "Options_FormAutofill_Enable" :
"Options_FormAutofill_Disable");
UserMetrics::RecordAction(action, profile_);
- preferences_->SetBoolean(prefs::kAutoFillEnabled, enabled);
+ enable_auto_fill_.SetValueIfNotManaged(enabled);
preferences_->ScheduleSavePersistentPrefs();
- UpdateButtonState();
+ UpdateWidgetState();
}
}
@@ -385,7 +395,7 @@ void AutoFillProfilesView::FocusWillChange(views::View* focused_before,
/////////////////////////////////////////////////////////////////////////////
// AutoFillProfilesView, views::TableViewObserver implementations:
void AutoFillProfilesView::OnSelectionChanged() {
- UpdateButtonState();
+ UpdateWidgetState();
}
void AutoFillProfilesView::OnDoubleClick() {
@@ -395,12 +405,110 @@ void AutoFillProfilesView::OnDoubleClick() {
/////////////////////////////////////////////////////////////////////////////
-// AutoFillProfilesView, PersonalDataManager::Observer implementation.
-void AutoFillProfilesView::OnPersonalDataLoaded() {
- personal_data_manager_->RemoveObserver(this);
+// AutoFillProfilesView, PersonalDataManager::Observer implementations.
+void AutoFillProfilesView::OnPersonalDataLoaded() {
GetData();
}
+void AutoFillProfilesView::OnPersonalDataChanged() {
+ // When we get here only new or updated data could be present.
+ // The only way to delete items is from this dialog, and it completely
+ // rebuilds the map before sending the update. Thus all received profiles or
+ // credit cards should be already present (thus id match check) or new.
+ std::map<int, size_t>::const_iterator found_id;
+ std::map<int, size_t>::const_iterator not_complete_id =
+ unique_ids_to_indexes_.find(0);
+
+ AutoFillProfile *profile_with_null_id = NULL;
+ CreditCard *cc_with_null_id = NULL;
+ if (not_complete_id != unique_ids_to_indexes_.end()) {
+ if (not_complete_id->second < profiles_set_.size() &&
+ !profiles_set_[not_complete_id->second].address.unique_id()) {
+ profile_with_null_id = &profiles_set_[not_complete_id->second].address;
+ }
+ if (not_complete_id->second < credit_card_set_.size() &&
+ !credit_card_set_[not_complete_id->second].credit_card.unique_id()) {
+ cc_with_null_id = &credit_card_set_[not_complete_id->second].credit_card;
+ }
+ }
+ for (std::vector<AutoFillProfile*>::const_iterator address_it =
+ personal_data_manager_->profiles().begin();
+ address_it != personal_data_manager_->profiles().end();
+ ++address_it) {
+ found_id = unique_ids_to_indexes_.find((*address_it)->unique_id());
+ // Check if the returned data is for new item.
+ if (found_id == unique_ids_to_indexes_.end() && profile_with_null_id) {
+ if (IsEqualDataWithIncompleteId<AutoFillProfile>(*address_it,
+ profile_with_null_id))
+ found_id = not_complete_id;
+ }
+ if (found_id == unique_ids_to_indexes_.end()) {
+ // New one - add.
+ profiles_set_.push_back(EditableSetInfo(*address_it));
+ } else {
+ if (profiles_set_.size() <= found_id->second) {
+ // Should never get here.
+ DCHECK(false);
+ } else {
+ // Update current profile - verify that unique ids match.
+ DCHECK(!profiles_set_[found_id->second].address.unique_id() ||
+ profiles_set_[found_id->second].address.unique_id() ==
+ (*address_it)->unique_id());
+ profiles_set_[found_id->second] = EditableSetInfo(*address_it);
+ }
+ }
+ }
+ UpdateProfileLabels();
+
+ for (std::vector<CreditCard*>::const_iterator cc_it =
+ personal_data_manager_->credit_cards().begin();
+ cc_it != personal_data_manager_->credit_cards().end();
+ ++cc_it) {
+ found_id = unique_ids_to_indexes_.find((*cc_it)->unique_id());
+ // Check if the returned data is for new item.
+ if (found_id == unique_ids_to_indexes_.end() && cc_with_null_id) {
+ if (IsEqualDataWithIncompleteId<CreditCard>(*cc_it, cc_with_null_id))
+ found_id = not_complete_id;
+ }
+ if (found_id == unique_ids_to_indexes_.end()) {
+ // New one - add.
+ credit_card_set_.push_back(EditableSetInfo(*cc_it));
+ } else {
+ if (credit_card_set_.size() <= found_id->second) {
+ // Should never get here.
+ DCHECK(false);
+ } else {
+ // Update current credit card - verify that unique ids match.
+ DCHECK(!credit_card_set_[found_id->second].credit_card.unique_id() ||
+ credit_card_set_[found_id->second].credit_card.unique_id() ==
+ (*cc_it)->unique_id());
+ credit_card_set_[found_id->second] = EditableSetInfo(*cc_it);
+ }
+ }
+ }
+
+ UpdateIdToIndexes();
+
+ if (table_model_.get())
+ table_model_->Refresh();
+
+ // Update state only if buttons already created.
+ if (add_address_button_) {
+ UpdateWidgetState();
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// AutoFillProfilesView, NotificationObserver implementation.
+void AutoFillProfilesView::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
+ const std::string* pref_name = Details<std::string>(details).ptr();
+ if (!pref_name || *pref_name == prefs::kAutoFillEnabled)
+ UpdateWidgetState();
+}
+
/////////////////////////////////////////////////////////////////////////////
// AutoFillProfilesView, private:
void AutoFillProfilesView::Init() {
@@ -409,19 +517,13 @@ void AutoFillProfilesView::Init() {
enable_auto_fill_button_ = new views::Checkbox(
l10n_util::GetString(IDS_OPTIONS_AUTOFILL_ENABLE));
enable_auto_fill_button_->set_listener(this);
- enable_auto_fill_button_->SetChecked(
- preferences_->GetBoolean(prefs::kAutoFillEnabled));
- billing_model_.set_address_labels(&profiles_set_);
+ billing_model_.SetAddressLabels(profiles_set_);
table_model_.reset(new ContentListTableModel(&profiles_set_,
&credit_card_set_));
std::vector<TableColumn> columns;
- columns.resize(1);
- columns[0] = TableColumn(IDS_AUTOFILL_LIST_HEADER_SUMMARY,
- TableColumn::LEFT, -1, .67f);
- columns.back().sortable = false;
-
+ columns.push_back(TableColumn());
scroll_view_ = new views::TableView(table_model_.get(), columns,
views::TEXT_ONLY, false, true, true);
scroll_view_->SetObserver(this);
@@ -476,15 +578,13 @@ void AutoFillProfilesView::Init() {
focus_manager_ = GetFocusManager();
- DCHECK(focus_manager_);
focus_manager_->AddFocusChangeListener(this);
- UpdateButtonState();
+ UpdateWidgetState();
}
void AutoFillProfilesView::GetData() {
if (!personal_data_manager_->IsDataLoaded()) {
- personal_data_manager_->SetObserver(this);
return;
}
bool imported_data_present = !profiles_set_.empty() ||
@@ -509,12 +609,15 @@ void AutoFillProfilesView::GetData() {
credit_card_set_.push_back(EditableSetInfo(*cc_it));
}
}
+
+ UpdateIdToIndexes();
+
if (table_model_.get())
table_model_->Refresh();
// Update state only if buttons already created.
if (add_address_button_) {
- UpdateButtonState();
+ UpdateWidgetState();
}
}
@@ -522,6 +625,35 @@ bool AutoFillProfilesView::IsDataReady() const {
return personal_data_manager_->IsDataLoaded();
}
+void AutoFillProfilesView::SaveData() {
+ std::vector<AutoFillProfile> profiles;
+ profiles.reserve(profiles_set_.size());
+ std::vector<EditableSetInfo>::iterator it;
+ for (it = profiles_set_.begin(); it != profiles_set_.end(); ++it) {
+ profiles.push_back(it->address);
+ }
+ std::vector<CreditCard> credit_cards;
+ credit_cards.reserve(credit_card_set_.size());
+ for (it = credit_card_set_.begin(); it != credit_card_set_.end(); ++it) {
+ credit_cards.push_back(it->credit_card);
+ }
+ observer_->OnAutoFillDialogApply(&profiles, &credit_cards);
+}
+
+void AutoFillProfilesView::UpdateIdToIndexes() {
+ unique_ids_to_indexes_.clear();
+ // Unique ids are unique across both profiles and credit cards, so we can
+ // combine them into one map.
+ size_t i;
+ for (i = 0; i < profiles_set_.size(); ++i) {
+ unique_ids_to_indexes_[profiles_set_[i].address.unique_id()] = i;
+ }
+ for (i = 0; i < credit_card_set_.size(); ++i) {
+ unique_ids_to_indexes_[credit_card_set_[i].credit_card.unique_id()] = i;
+ }
+}
+
+
/////////////////////////////////////////////////////////////////////////////
// AutoFillProfilesView::PhoneSubView, public:
AutoFillProfilesView::PhoneSubView::PhoneSubView(
@@ -551,9 +683,8 @@ bool AutoFillProfilesView::PhoneSubView::IsValid() const {
return true;
// Try to parse it.
- string16 country, city, stripped_phone;
- return PhoneNumber::ParsePhoneNumber(phone, &country, &city,
- &stripped_phone);
+ string16 number, city, country;
+ return PhoneNumber::ParsePhoneNumber(phone, &number, &city, &country);
}
return false;
}
@@ -561,7 +692,7 @@ bool AutoFillProfilesView::PhoneSubView::IsValid() const {
void AutoFillProfilesView::PhoneSubView::UpdateButtons() {
if (phone_warning_button_) {
SkBitmap* image = text_phone_->text().empty() ? NULL :
- autofill_view_->GetWarningBimap(IsValid());
+ autofill_view_->GetWarningBitmap(IsValid());
phone_warning_button_->SetImage(views::CustomButton::BS_NORMAL, image);
if (last_state_ != IsValid()) {
last_state_ = IsValid();
@@ -594,7 +725,7 @@ void AutoFillProfilesView::PhoneSubView::ViewHierarchyChanged(
layout->AddView(text_phone_);
phone_warning_button_ = new views::ImageButton(this);
// Set default size of the image.
- SkBitmap* image = autofill_view_->GetWarningBimap(true);
+ SkBitmap* image = autofill_view_->GetWarningBitmap(true);
phone_warning_button_->SetPreferredSize(gfx::Size(image->width(),
image->height()));
phone_warning_button_->SetEnabled(false);
@@ -626,9 +757,9 @@ AutoFillProfilesView::EditableSetViewContents::TextFieldToAutoFill
{ AutoFillProfilesView::EditableSetViewContents::TEXT_ADDRESS_COUNTRY,
ADDRESS_HOME_COUNTRY },
{ AutoFillProfilesView::EditableSetViewContents::TEXT_PHONE_PHONE,
- PHONE_HOME_NUMBER },
+ PHONE_HOME_WHOLE_NUMBER },
{ AutoFillProfilesView::EditableSetViewContents::TEXT_FAX_PHONE,
- PHONE_FAX_NUMBER },
+ PHONE_FAX_WHOLE_NUMBER },
};
AutoFillProfilesView::EditableSetViewContents::TextFieldToAutoFill
@@ -648,6 +779,7 @@ AutoFillProfilesView::EditableSetViewContents::EditableSetViewContents(
std::vector<EditableSetInfo>::iterator field_set)
: editable_fields_set_(field_set),
temporary_info_(*editable_fields_set_),
+ has_credit_card_number_been_edited_(false),
observer_(observer),
billing_model_(billing_model),
combo_box_billing_(NULL),
@@ -717,19 +849,44 @@ AutoFillProfilesView::EditableSetViewContents::GetDialogButtonLabel(
bool AutoFillProfilesView::EditableSetViewContents::IsDialogButtonEnabled(
MessageBoxFlags::DialogButton button) const {
switch (button) {
- case MessageBoxFlags::DIALOGBUTTON_OK: {
- bool phones_are_valid = true;
- for (std::vector<PhoneSubView*>::const_iterator it =
- phone_sub_views_.begin();
- it != phone_sub_views_.end() && phones_are_valid; ++it)
- phones_are_valid = (phones_are_valid && (*it)->IsValid());
-
- return phones_are_valid;
- }
- case MessageBoxFlags::DIALOGBUTTON_CANCEL:
- return true;
- default:
- break;
+ case MessageBoxFlags::DIALOGBUTTON_OK: {
+ // Enable the ok button if at least one non-phone number field has text,
+ // or the phone numbers are valid.
+ bool valid = false;
+ TextFieldToAutoFill* fields;
+ int field_count;
+ if (temporary_info_.is_address) {
+ fields = address_fields_;
+ field_count = arraysize(address_fields_);
+ } else {
+ fields = credit_card_fields_;
+ field_count = arraysize(credit_card_fields_);
+ }
+ for (int i = 0; i < field_count; ++i) {
+ DCHECK(text_fields_[fields[i].text_field]);
+ // Phone and fax are handled separately.
+ if (fields[i].text_field != TEXT_PHONE_PHONE &&
+ fields[i].text_field != TEXT_FAX_PHONE &&
+ !text_fields_[fields[i].text_field]->text().empty()) {
+ valid = true;
+ break;
+ }
+ }
+ for (std::vector<PhoneSubView*>::const_iterator i =
+ phone_sub_views_.begin(); i != phone_sub_views_.end(); ++i) {
+ if (!(*i)->IsValid()) {
+ valid = false;
+ break;
+ } else if (!valid && !(*i)->text_phone()->text().empty()) {
+ valid = true;
+ }
+ }
+ return valid;
+ }
+ case MessageBoxFlags::DIALOGBUTTON_CANCEL:
+ return true;
+ default:
+ break;
}
NOTREACHED();
return false;
@@ -762,6 +919,7 @@ bool AutoFillProfilesView::EditableSetViewContents::Cancel() {
// Remove added item - it is last in the list.
if (temporary_info_.is_address) {
observer_->profiles_set_.pop_back();
+ observer_->UpdateBillingModel();
} else {
observer_->credit_card_set_.pop_back();
}
@@ -782,8 +940,11 @@ bool AutoFillProfilesView::EditableSetViewContents::Accept() {
observer_->table_model_->AddItem(index);
else
observer_->table_model_->UpdateItem(index);
- if (temporary_info_.is_address)
+ if (temporary_info_.is_address) {
observer_->UpdateProfileLabels();
+ observer_->UpdateBillingModel();
+ }
+ observer_->SaveData();
return true;
}
@@ -795,7 +956,6 @@ void AutoFillProfilesView::EditableSetViewContents::ButtonPressed(
NOTREACHED();
}
-
/////////////////////////////////////////////////////////////////////////////
// AutoFillProfilesView::EditableSetViewContents,
// views::Textfield::Controller implementations
@@ -805,10 +965,11 @@ void AutoFillProfilesView::EditableSetViewContents::ContentsChanged(
for (int field = 0; field < arraysize(address_fields_); ++field) {
DCHECK(text_fields_[address_fields_[field].text_field]);
if (text_fields_[address_fields_[field].text_field] == sender) {
- UpdateContentsPhoneViews(address_fields_[field].text_field,
- sender, new_contents);
- temporary_info_.address.SetInfo(
- AutoFillType(address_fields_[field].type), new_contents);
+ if (!UpdateContentsPhoneViews(address_fields_[field].text_field,
+ sender, new_contents)) {
+ temporary_info_.address.SetInfo(
+ AutoFillType(address_fields_[field].type), new_contents);
+ }
UpdateButtons();
return;
}
@@ -831,10 +992,10 @@ void AutoFillProfilesView::EditableSetViewContents::ContentsChanged(
bool AutoFillProfilesView::EditableSetViewContents::HandleKeystroke(
views::Textfield* sender, const views::Textfield::Keystroke& keystroke) {
if (sender == text_fields_[TEXT_CC_NUMBER] &&
- !temporary_info_.has_credit_card_number_been_edited) {
+ !has_credit_card_number_been_edited_) {
// You cannot edit obfuscated number, you must retype it anew.
sender->SetText(string16());
- temporary_info_.has_credit_card_number_been_edited = true;
+ has_credit_card_number_been_edited_ = true;
}
return false;
}
@@ -850,9 +1011,8 @@ void AutoFillProfilesView::EditableSetViewContents::ItemChanged(
NOTREACHED();
} else {
DCHECK(new_index < static_cast<int>(observer_->profiles_set_.size()));
- temporary_info_.credit_card.set_billing_address(
- IntToString16(
- observer_->profiles_set_[new_index].address.unique_id()));
+ temporary_info_.credit_card.set_billing_address_id(
+ observer_->profiles_set_[new_index].address.unique_id());
}
} else if (combo_box == combo_box_month_) {
if (new_index == -1) {
@@ -860,7 +1020,7 @@ void AutoFillProfilesView::EditableSetViewContents::ItemChanged(
} else {
temporary_info_.credit_card.SetInfo(
AutoFillType(CREDIT_CARD_EXP_MONTH),
- combo_box_model_month_->GetItemAt(new_index));
+ UTF16ToWideHack(combo_box_model_month_->GetItemAt(new_index)));
}
} else if (combo_box == combo_box_year_) {
if (new_index == -1) {
@@ -868,7 +1028,7 @@ void AutoFillProfilesView::EditableSetViewContents::ItemChanged(
} else {
temporary_info_.credit_card.SetInfo(
AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
- combo_box_model_year_->GetItemAt(new_index));
+ UTF16ToWideHack(combo_box_model_year_->GetItemAt(new_index)));
}
} else {
NOTREACHED();
@@ -1022,8 +1182,8 @@ void AutoFillProfilesView::EditableSetViewContents::InitCreditCardFields(
// Address combo boxes.
combo_box_billing_ = new views::Combobox(billing_model_);
combo_box_billing_->set_listener(this);
- int billing_id = -1;
- if (StringToInt(temporary_info_.credit_card.billing_address(), &billing_id))
+ int billing_id = temporary_info_.credit_card.billing_address_id();
+ if (billing_id)
combo_box_billing_->SetSelectedItem(billing_model_->GetIndex(billing_id));
billing_model_->UsedWithComboBox(combo_box_billing_);
@@ -1161,7 +1321,7 @@ void AutoFillProfilesView::EditableSetViewContents::UpdateButtons() {
GetDialogClientView()->UpdateDialogButtons();
}
-void AutoFillProfilesView::EditableSetViewContents::UpdateContentsPhoneViews(
+bool AutoFillProfilesView::EditableSetViewContents::UpdateContentsPhoneViews(
TextFields field, views::Textfield* sender, const string16& new_contents) {
switch (field) {
case TEXT_PHONE_PHONE:
@@ -1169,32 +1329,61 @@ void AutoFillProfilesView::EditableSetViewContents::UpdateContentsPhoneViews(
for (std::vector<PhoneSubView*>::iterator it = phone_sub_views_.begin();
it != phone_sub_views_.end(); ++it)
(*it)->ContentsChanged(sender, new_contents);
- } break;
+ DCHECK(temporary_info_.is_address); // Only addresses have phone numbers.
+ string16 number, city, country;
+ PhoneNumber::ParsePhoneNumber(new_contents, &number, &city, &country);
+ temporary_info_.address.SetInfo(
+ AutoFillType(field == TEXT_PHONE_PHONE ? PHONE_HOME_COUNTRY_CODE :
+ PHONE_FAX_COUNTRY_CODE), country);
+ temporary_info_.address.SetInfo(
+ AutoFillType(field == TEXT_PHONE_PHONE ? PHONE_HOME_CITY_CODE :
+ PHONE_FAX_CITY_CODE), city);
+ temporary_info_.address.SetInfo(
+ AutoFillType(field == TEXT_PHONE_PHONE ? PHONE_HOME_NUMBER :
+ PHONE_FAX_NUMBER), number);
+ return true;
+ }
}
+ return false;
}
/////////////////////////////////////////////////////////////////////////////
// AutoFillProfilesView::AddressComboBoxModel, public:
AutoFillProfilesView::AddressComboBoxModel::AddressComboBoxModel(
bool is_billing)
- : address_labels_(NULL),
- is_billing_(is_billing) {
-}
-
-void AutoFillProfilesView::AddressComboBoxModel::set_address_labels(
- const std::vector<EditableSetInfo>* address_labels) {
- DCHECK(!address_labels_);
- address_labels_ = address_labels;
+ : is_billing_(is_billing) {
+}
+
+void AutoFillProfilesView::AddressComboBoxModel::SetAddressLabels(
+ const std::vector<EditableSetInfo>& address_labels) {
+ address_labels_.clear();
+ for (size_t i = 0; i < address_labels.size(); ++i) {
+ const EditableSetInfo& item = address_labels[i];
+ DCHECK(item.is_address);
+ FieldTypeSet fields;
+ item.address.GetAvailableFieldTypes(&fields);
+ if (fields.find(ADDRESS_HOME_LINE1) == fields.end() &&
+ fields.find(ADDRESS_HOME_LINE2) == fields.end() &&
+ fields.find(ADDRESS_HOME_APT_NUM) == fields.end() &&
+ fields.find(ADDRESS_HOME_CITY) == fields.end() &&
+ fields.find(ADDRESS_HOME_STATE) == fields.end() &&
+ fields.find(ADDRESS_HOME_ZIP) == fields.end() &&
+ fields.find(ADDRESS_HOME_COUNTRY) == fields.end()) {
+ // No address information in this profile; it's useless as a billing
+ // address.
+ continue;
+ }
+ address_labels_.push_back(item);
+ }
+ NotifyChanged();
}
void AutoFillProfilesView::AddressComboBoxModel::UsedWithComboBox(
views::Combobox* combo_box) {
- DCHECK(address_labels_);
combo_boxes_.push_back(combo_box);
}
-void AutoFillProfilesView::AddressComboBoxModel::LabelChanged() {
- DCHECK(address_labels_);
+void AutoFillProfilesView::AddressComboBoxModel::NotifyChanged() {
for (std::list<views::Combobox*>::iterator it = combo_boxes_.begin();
it != combo_boxes_.end();
++it)
@@ -1203,10 +1392,8 @@ void AutoFillProfilesView::AddressComboBoxModel::LabelChanged() {
int AutoFillProfilesView::AddressComboBoxModel::GetIndex(int unique_id) {
int shift = is_billing_ ? 0 : 1;
- DCHECK(address_labels_);
- for (size_t i = 0; i < address_labels_->size(); ++i) {
- DCHECK(address_labels_->at(i).is_address);
- if (address_labels_->at(i).address.unique_id() == unique_id)
+ for (size_t i = 0; i < address_labels_.size(); ++i) {
+ if (address_labels_.at(i).address.unique_id() == unique_id)
return i + shift;
}
return -1;
@@ -1215,22 +1402,20 @@ int AutoFillProfilesView::AddressComboBoxModel::GetIndex(int unique_id) {
/////////////////////////////////////////////////////////////////////////////
// AutoFillProfilesView::AddressComboBoxModel, ComboboxModel methods
int AutoFillProfilesView::AddressComboBoxModel::GetItemCount() {
- DCHECK(address_labels_);
int shift = is_billing_ ? 0 : 1;
- return static_cast<int>(address_labels_->size()) + shift;
+ return static_cast<int>(address_labels_.size()) + shift;
}
-std::wstring AutoFillProfilesView::AddressComboBoxModel::GetItemAt(int index) {
- DCHECK(address_labels_);
+string16 AutoFillProfilesView::AddressComboBoxModel::GetItemAt(int index) {
int shift = is_billing_ ? 0 : 1;
- DCHECK(index < (static_cast<int>(address_labels_->size()) + shift));
+ DCHECK(index < (static_cast<int>(address_labels_.size()) + shift));
if (!is_billing_ && !index)
- return l10n_util::GetString(IDS_AUTOFILL_DIALOG_SAME_AS_BILLING);
- DCHECK(address_labels_->at(index - shift).is_address);
- std::wstring label =
- address_labels_->at(index - shift).address.Label();
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAME_AS_BILLING);
+ DCHECK(address_labels_.at(index - shift).is_address);
+ string16 label =
+ WideToUTF16Hack(address_labels_.at(index - shift).address.Label());
if (label.empty())
- label = l10n_util::GetString(IDS_AUTOFILL_NEW_ADDRESS);
+ label = l10n_util::GetStringUTF16(IDS_AUTOFILL_NEW_ADDRESS);
return label;
}
@@ -1243,10 +1428,9 @@ int AutoFillProfilesView::StringVectorComboboxModel::GetItemCount() {
return cb_strings_.size();
}
-std::wstring AutoFillProfilesView::StringVectorComboboxModel::GetItemAt(
- int index) {
+string16 AutoFillProfilesView::StringVectorComboboxModel::GetItemAt(int index) {
DCHECK_GT(static_cast<int>(cb_strings_.size()), index);
- return cb_strings_[index];
+ return WideToUTF16Hack(cb_strings_[index]);
}
int AutoFillProfilesView::StringVectorComboboxModel::GetIndex(
diff --git a/chrome/browser/views/autofill_profiles_view_win.h b/chrome/browser/views/autofill_profiles_view_win.h
index be54e14..c452506 100644
--- a/chrome/browser/views/autofill_profiles_view_win.h
+++ b/chrome/browser/views/autofill_profiles_view_win.h
@@ -4,15 +4,20 @@
#ifndef CHROME_BROWSER_VIEWS_AUTOFILL_PROFILES_VIEW_WIN_H_
#define CHROME_BROWSER_VIEWS_AUTOFILL_PROFILES_VIEW_WIN_H_
+#pragma once
#include <list>
+#include <map>
#include <vector>
#include "app/combobox_model.h"
#include "app/table_model.h"
+#include "base/string16.h"
#include "chrome/browser/autofill/autofill_dialog.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/common/notification_observer.h"
#include "views/controls/combobox/combobox.h"
#include "views/controls/link.h"
#include "views/controls/table/table_view_observer.h"
@@ -29,7 +34,7 @@ class Label;
class RadioButton;
class TableView;
class TextButton;
-}
+} // namespace views
class PrefService;
class SkBitmap;
@@ -54,7 +59,8 @@ class AutoFillProfilesView : public views::View,
public views::LinkController,
public views::FocusChangeListener,
public views::TableViewObserver,
- public PersonalDataManager::Observer {
+ public PersonalDataManager::Observer,
+ public NotificationObserver {
public:
virtual ~AutoFillProfilesView();
@@ -67,7 +73,7 @@ class AutoFillProfilesView : public views::View,
CreditCard* imported_credit_card);
protected:
- // forward declaration. This struct defined further down.
+ // Forward declaration. This struct defined further down.
struct EditableSetInfo;
// Called when 'Add Address' (|group_type| is
// ContentListTableModel::kAddressGroup) or 'Add Credit Card' (|group_type| is
@@ -79,11 +85,15 @@ class AutoFillProfilesView : public views::View,
void DeleteClicked();
// Updates state of the buttons.
- void UpdateButtonState();
+ void UpdateWidgetState();
// Updates inferred labels.
void UpdateProfileLabels();
+ // Updates the billing model. This is invoked any time the profile_set_
+ // changes.
+ void UpdateBillingModel();
+
// Following two functions are called from opened child dialog to
// disable/enable buttons.
void ChildWindowOpened();
@@ -92,7 +102,7 @@ class AutoFillProfilesView : public views::View,
// Returns warning bitmap to set on warning indicator. If |good| is true it
// returns the bitmap idicating validity, if false - indicating error.
// Caller owns the bitmap after the call.
- SkBitmap* GetWarningBimap(bool good);
+ SkBitmap* GetWarningBitmap(bool good);
// views::View methods:
virtual void Layout();
@@ -134,6 +144,12 @@ class AutoFillProfilesView : public views::View,
// PersonalDataManager::Observer methods:
virtual void OnPersonalDataLoaded();
+ virtual void OnPersonalDataChanged();
+
+ // NotificationObserver methods:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Helper structure to keep info on one address or credit card.
// Keeps info on one item in EditableSetViewContents.
@@ -141,7 +157,6 @@ class AutoFillProfilesView : public views::View,
// and then rebuild EditableSetViewContents.
struct EditableSetInfo {
bool is_address;
- bool has_credit_card_number_been_edited;
// If |is_address| is true |address| has some data and |credit_card|
// is empty, and vice versa
AutoFillProfile address;
@@ -149,13 +164,11 @@ class AutoFillProfilesView : public views::View,
explicit EditableSetInfo(const AutoFillProfile* input_address)
: address(*input_address),
- is_address(true),
- has_credit_card_number_been_edited(false) {
+ is_address(true) {
}
explicit EditableSetInfo(const CreditCard* input_credit_card)
: credit_card(*input_credit_card),
- is_address(false),
- has_credit_card_number_been_edited(false) {
+ is_address(false) {
}
};
@@ -181,6 +194,8 @@ class AutoFillProfilesView : public views::View,
void GetData();
bool IsDataReady() const;
+ void SaveData();
+ void UpdateIdToIndexes();
// Rebuilds the view by deleting and re-creating sub-views
void RebuildView(const FocusedItem& new_focus_index);
@@ -200,6 +215,8 @@ class AutoFillProfilesView : public views::View,
bool IsValid() const;
+ views::Textfield* text_phone() { return text_phone_; }
+
protected:
// views::View methods:
virtual void ViewHierarchyChanged(bool is_add, views::View* parent,
@@ -223,11 +240,11 @@ class AutoFillProfilesView : public views::View,
DISALLOW_COPY_AND_ASSIGN(PhoneSubView);
};
- // forward declaration
+ // Forward declaration.
class AddressComboBoxModel;
class StringVectorComboboxModel;
- // Sub-view dealing with addresses.
+ // Sub-view for editing/adding a credit card or address.
class EditableSetViewContents : public views::View,
public views::DialogDelegate,
public views::ButtonListener,
@@ -255,7 +272,7 @@ class AutoFillProfilesView : public views::View,
MessageBoxFlags::DialogButton button) const;
virtual bool CanResize() const { return false; }
virtual bool CanMaximize() const { return false; }
- virtual bool IsAlwaysOnTop() const { return false; }
+ virtual bool IsModal() const { return true; }
virtual bool HasAlwaysOnTopMenu() const { return false; }
virtual std::wstring GetWindowTitle() const;
virtual void WindowClosing();
@@ -265,7 +282,7 @@ class AutoFillProfilesView : public views::View,
// views::ButtonListener methods:
virtual void ButtonPressed(views::Button* sender,
- const views::Event& event);
+ const views::Event& event);
// views::Textfield::Controller methods:
virtual void ContentsChanged(views::Textfield* sender,
@@ -292,7 +309,7 @@ class AutoFillProfilesView : public views::View,
TEXT_FAX_PHONE,
TEXT_CC_NAME,
TEXT_CC_NUMBER,
- // must be last
+ // Must be last.
MAX_TEXT_FIELD
};
@@ -303,13 +320,17 @@ class AutoFillProfilesView : public views::View,
void UpdateButtons();
- void UpdateContentsPhoneViews(TextFields field,
+ // If |field| is a phone or fax ContentsChanged is passed to the
+ // PhoneSubView, the appropriate fields in |temporary_info_| are updated and
+ // true is returned. Otherwise false is returned.
+ bool UpdateContentsPhoneViews(TextFields field,
views::Textfield* sender,
const string16& new_contents);
views::Textfield* text_fields_[MAX_TEXT_FIELD];
std::vector<EditableSetInfo>::iterator editable_fields_set_;
EditableSetInfo temporary_info_;
+ bool has_credit_card_number_been_edited_;
AutoFillProfilesView* observer_;
AddressComboBoxModel* billing_model_;
views::Combobox* combo_box_billing_;
@@ -340,16 +361,14 @@ class AutoFillProfilesView : public views::View,
DISALLOW_COPY_AND_ASSIGN(EditableSetViewContents);
};
- // Encapsulates ComboboxModel for address
+ // Encapsulates ComboboxModel for address.
class AddressComboBoxModel : public ComboboxModel {
public:
explicit AddressComboBoxModel(bool is_billing);
virtual ~AddressComboBoxModel() {}
- // Should be called only once. No other function should be called before it.
- // Does not own |address_labels|. To update the model text,
- // update label in one of the profiles and call LabelChanged()
- void set_address_labels(const std::vector<EditableSetInfo>* address_labels);
+ // Updates address_labels_ from |address_labels|.
+ void SetAddressLabels(const std::vector<EditableSetInfo>& address_labels);
// When you add a CB view that relies on this model, call this function
// so the CB can be notified if strings change. Can be called multiple
@@ -361,18 +380,19 @@ class AutoFillProfilesView : public views::View,
void ClearComboBoxes() { combo_boxes_.clear(); }
// Call this function if one of the labels has changed
- void LabelChanged();
+ void NotifyChanged();
// Gets index of the item in the model or -1 if not found.
int GetIndex(int unique_id);
- // ComboboxModel methods, public as they used from EditableSetViewContents
+ // Overridden from ComboboxModel:
+ // Public as they are used from EditableSetViewContents.
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
private:
- std::list<views::Combobox *> combo_boxes_;
- const std::vector<EditableSetInfo>* address_labels_;
+ std::list<views::Combobox*> combo_boxes_;
+ std::vector<EditableSetInfo> address_labels_;
bool is_billing_;
DISALLOW_COPY_AND_ASSIGN(AddressComboBoxModel);
@@ -387,11 +407,9 @@ class AutoFillProfilesView : public views::View,
// |source|.
void set_cb_strings(std::vector<std::wstring> *source);
- // Return the number of items in the combo box.
+ // Overridden from ComboboxModel:
virtual int GetItemCount();
-
- // Return the string that should be used to represent a given item.
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
// Find an index of the item in the model, -1 if not present.
int GetIndex(const std::wstring& value);
@@ -402,8 +420,7 @@ class AutoFillProfilesView : public views::View,
DISALLOW_COPY_AND_ASSIGN(StringVectorComboboxModel);
};
-
- // Model for scrolling credit cards and addresses
+ // Model for scrolling credit cards and addresses.
class ContentListTableModel : public TableModel {
public:
ContentListTableModel(std::vector<EditableSetInfo>* profiles,
@@ -443,9 +460,12 @@ class AutoFillProfilesView : public views::View,
PrefService* preferences_;
std::vector<EditableSetInfo> profiles_set_;
std::vector<EditableSetInfo> credit_card_set_;
+ std::map<int, size_t> unique_ids_to_indexes_;
AddressComboBoxModel billing_model_;
+ BooleanPrefMember enable_auto_fill_;
+
views::Checkbox* enable_auto_fill_button_;
views::Button* add_address_button_;
views::Button* add_credit_card_button_;
@@ -462,4 +482,3 @@ class AutoFillProfilesView : public views::View,
};
#endif // CHROME_BROWSER_VIEWS_AUTOFILL_PROFILES_VIEW_WIN_H_
-
diff --git a/chrome/browser/views/bookmark_bar_instructions_view.cc b/chrome/browser/views/bookmark_bar_instructions_view.cc
index 4b625d9..a89eb2d 100644
--- a/chrome/browser/views/bookmark_bar_instructions_view.cc
+++ b/chrome/browser/views/bookmark_bar_instructions_view.cc
@@ -1,13 +1,12 @@
-// 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.
#include "chrome/browser/views/bookmark_bar_instructions_view.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/defaults.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "grit/generated_resources.h"
#include "views/controls/label.h"
@@ -75,7 +74,7 @@ void BookmarkBarInstructionsView::Layout() {
}
}
-void BookmarkBarInstructionsView::ThemeChanged() {
+void BookmarkBarInstructionsView::OnThemeChanged() {
UpdateColors();
}
@@ -86,14 +85,8 @@ void BookmarkBarInstructionsView::ViewHierarchyChanged(bool is_add,
UpdateColors();
}
-bool BookmarkBarInstructionsView::GetAccessibleRole(
- AccessibilityTypes::Role* role) {
- DCHECK(role);
- if (!role)
- return false;
-
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+AccessibilityTypes::Role BookmarkBarInstructionsView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
void BookmarkBarInstructionsView::LinkActivated(views::Link* source,
diff --git a/chrome/browser/views/bookmark_bar_instructions_view.h b/chrome/browser/views/bookmark_bar_instructions_view.h
index c598f10..2156bf8 100644
--- a/chrome/browser/views/bookmark_bar_instructions_view.h
+++ b/chrome/browser/views/bookmark_bar_instructions_view.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_BAR_INSTRUCTIONS_VIEW_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_BAR_INSTRUCTIONS_VIEW_H_
+#pragma once
#include "views/view.h"
#include "views/controls/link.h"
@@ -26,6 +27,9 @@ class BookmarkBarInstructionsView : public views::View,
class Delegate {
public:
virtual void ShowImportDialog() = 0;
+
+ protected:
+ virtual ~Delegate() {}
};
explicit BookmarkBarInstructionsView(Delegate* delegate);
@@ -33,11 +37,11 @@ class BookmarkBarInstructionsView : public views::View,
// View overrides.
virtual gfx::Size GetPreferredSize();
virtual void Layout();
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
virtual void ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
// LinkController.
virtual void LinkActivated(views::Link* source, int event_flags);
diff --git a/chrome/browser/views/bookmark_bar_view.cc b/chrome/browser/views/bookmark_bar_view.cc
index 26baaac..0bb9e77 100644
--- a/chrome/browser/views/bookmark_bar_view.cc
+++ b/chrome/browser/views/bookmark_bar_view.cc
@@ -15,20 +15,22 @@
#include "app/text_elider.h"
#include "base/i18n/rtl.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.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/sync/sync_ui_util.h"
#include "chrome/browser/tab_contents/page_navigator.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/bookmark_context_menu.h"
#include "chrome/browser/views/event_utils.h"
@@ -62,16 +64,17 @@ using views::View;
// How much we want the bookmark bar to overlap the toolbar when in its
// 'always shown' mode.
-static const double kToolbarOverlap = 4.0;
+static const int kToolbarOverlap = 3;
// Margins around the content.
-static const int kTopMargin = 1;
+static const int kDetachedTopMargin = 1; // When attached, we use 0 and let the
+ // toolbar above serve as the margin.
static const int kBottomMargin = 2;
static const int kLeftMargin = 1;
static const int kRightMargin = 1;
// Preferred height of the bookmarks bar.
-static const int kBarHeight = 29;
+static const int kBarHeight = 28;
// Preferred height of the bookmarks bar when only shown on the new tab page.
const int BookmarkBarView::kNewtabBarHeight = 57;
@@ -157,7 +160,8 @@ static std::wstring CreateToolTipForURLAndTitle(const gfx::Point& screen_loc,
// the Unicode BiDi algorithm puts certain characters on the left by
// default.
std::wstring elided_url(gfx::ElideUrl(url, tt_font, max_width, languages));
- base::i18n::GetDisplayStringInLTRDirectionality(&elided_url);
+ elided_url = UTF16ToWide(base::i18n::GetDisplayStringInLTRDirectionality(
+ WideToUTF16(elided_url)));
result.append(elided_url);
}
return result;
@@ -338,11 +342,8 @@ class BookmarkBarView::ButtonSeparatorView : public views::View {
return gfx::Size(kSeparatorWidth, 1);
}
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_SEPARATOR;
- return true;
+ virtual AccessibilityTypes::Role GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_SEPARATOR;
}
private:
@@ -383,6 +384,7 @@ BookmarkBarView::BookmarkBarView(Profile* profile, Browser* browser)
instructions_(NULL),
bookmarks_separator_view_(NULL),
browser_(browser),
+ infobar_visible_(false),
throbbing_view_(NULL) {
if (profile->GetProfileSyncService()) {
// Obtain a pointer to the profile sync service and add our instance as an
@@ -395,10 +397,7 @@ BookmarkBarView::BookmarkBarView(Profile* profile, Browser* browser)
Init();
SetProfile(profile);
- if (IsAlwaysShown())
- size_animation_->Reset(1);
- else
- size_animation_->Reset(0);
+ size_animation_->Reset(IsAlwaysShown() ? 1 : 0);
}
BookmarkBarView::~BookmarkBarView() {
@@ -752,9 +751,19 @@ bool BookmarkBarView::OnNewTabPage() const {
browser_->GetSelectedTabContents()->ShouldShowBookmarkBar());
}
-int BookmarkBarView::GetToolbarOverlap(bool return_max) {
- return static_cast<int>(kToolbarOverlap *
- (return_max ? 1.0 : size_animation_->GetCurrentValue()));
+int BookmarkBarView::GetToolbarOverlap(bool return_max) const {
+ // When not on the New Tab Page, always overlap by the full amount.
+ if (return_max || !OnNewTabPage())
+ return kToolbarOverlap;
+ // When on the New Tab Page with an infobar, overlap by 0 whenever the infobar
+ // is above us (i.e. when we're detached), since drawing over the infobar
+ // looks weird.
+ if (IsDetached() && infobar_visible_)
+ return 0;
+ // When on the New Tab Page with no infobar, animate the overlap between the
+ // attached and detached states.
+ return static_cast<int>(static_cast<double>(kToolbarOverlap) *
+ size_animation_->GetCurrentValue());
}
void BookmarkBarView::AnimationProgressed(const Animation* animation) {
@@ -957,9 +966,11 @@ void BookmarkBarView::Loaded(BookmarkModel* model) {
}
void BookmarkBarView::BookmarkModelBeingDeleted(BookmarkModel* model) {
- // The bookmark model should never be deleted before us. This code exists
+ // In normal shutdown The bookmark model should never be deleted before us.
+ // When X exits suddenly though, it can happen, This code exists
// to check for regressions in shutdown code and not crash.
- NOTREACHED();
+ if (!browser_shutdown::ShuttingDownWithoutClosingBrowsers())
+ NOTREACHED();
// Do minimal cleanup, presumably we'll be deleted shortly.
NotifyModelChanged();
@@ -1246,15 +1257,13 @@ void BookmarkBarView::ShowContextMenu(View* source,
views::View* BookmarkBarView::CreateBookmarkButton(const BookmarkNode* node) {
if (node->is_url()) {
- BookmarkButton* button = new BookmarkButton(this,
- node->GetURL(),
- node->GetTitle(),
- GetProfile());
+ BookmarkButton* button = new BookmarkButton(this, node->GetURL(),
+ UTF16ToWide(node->GetTitle()), GetProfile());
ConfigureButton(node, button);
return button;
} else {
- views::MenuButton* button =
- new BookmarkFolderButton(this, node->GetTitle(), this, false);
+ views::MenuButton* button = new BookmarkFolderButton(this,
+ UTF16ToWide(node->GetTitle()), this, false);
button->SetIcon(GetGroupIcon());
ConfigureButton(node, button);
return button;
@@ -1263,8 +1272,8 @@ views::View* BookmarkBarView::CreateBookmarkButton(const BookmarkNode* node) {
void BookmarkBarView::ConfigureButton(const BookmarkNode* node,
views::TextButton* button) {
- button->SetText(node->GetTitle());
- button->SetAccessibleName(node->GetTitle());
+ button->SetText(UTF16ToWide(node->GetTitle()));
+ button->SetAccessibleName(UTF16ToWide(node->GetTitle()));
button->SetID(VIEW_ID_BOOKMARK_BAR_ELEMENT);
// We don't always have a theme provider (ui tests, for example).
if (GetThemeProvider()) {
@@ -1325,7 +1334,7 @@ void BookmarkBarView::Observe(NotificationType type,
}
}
-void BookmarkBarView::ThemeChanged() {
+void BookmarkBarView::OnThemeChanged() {
UpdateColors();
}
@@ -1569,9 +1578,10 @@ gfx::Size BookmarkBarView::LayoutItems(bool compute_bounds_only) {
return prefsize;
int x = kLeftMargin;
- int y = kTopMargin;
+ int top_margin = IsDetached() ? kDetachedTopMargin : 0;
+ int y = top_margin;
int width = View::width() - kRightMargin - kLeftMargin;
- int height = View::height() - kTopMargin - kBottomMargin;
+ int height = View::height() - top_margin - kBottomMargin;
int separator_margin = kSeparatorMargin;
if (OnNewTabPage()) {
@@ -1652,9 +1662,9 @@ gfx::Size BookmarkBarView::LayoutItems(bool compute_bounds_only) {
// Separator.
if (!compute_bounds_only) {
bookmarks_separator_view_->SetBounds(x,
- y - kTopMargin,
+ y - top_margin,
bookmarks_separator_pref.width(),
- height + kTopMargin + kBottomMargin -
+ height + top_margin + kBottomMargin -
separator_margin);
}
diff --git a/chrome/browser/views/bookmark_bar_view.h b/chrome/browser/views/bookmark_bar_view.h
index b73cbe0..d667ad4 100644
--- a/chrome/browser/views/bookmark_bar_view.h
+++ b/chrome/browser/views/bookmark_bar_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_BAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_BAR_VIEW_H_
+#pragma once
#include <set>
@@ -98,12 +99,21 @@ class BookmarkBarView : public DetachableToolbarView,
// the bookmark bar.
void SetPageNavigator(PageNavigator* navigator);
+ // Sets whether the containing browser is showing an infobar. This affects
+ // layout during animation.
+ void set_infobar_visible(bool infobar_visible) {
+ infobar_visible_ = infobar_visible;
+ }
+
// DetachableToolbarView methods:
virtual bool IsDetached() const;
virtual bool IsOnTop() const;
virtual double GetAnimationValue() const {
return size_animation_->GetCurrentValue();
}
+ virtual int GetToolbarOverlap() const {
+ return GetToolbarOverlap(false);
+ }
// View methods:
virtual gfx::Size GetPreferredSize();
@@ -164,7 +174,7 @@ class BookmarkBarView : public DetachableToolbarView,
// How much we want the bookmark bar to overlap the toolbar. If |return_max|
// is true, we return the maximum overlap rather than the current overlap.
- int GetToolbarOverlap(bool return_max);
+ int GetToolbarOverlap(bool return_max) const;
// Whether or not we are animating.
bool is_animating() { return size_animation_->is_animating(); }
@@ -381,7 +391,7 @@ class BookmarkBarView : public DetachableToolbarView,
const NotificationDetails& details);
// Overridden from views::View.
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
// If the ModelChangedListener is non-null, ModelChanged is invoked on it.
void NotifyModelChanged();
@@ -477,6 +487,9 @@ class BookmarkBarView : public DetachableToolbarView,
// Owning browser. This is NULL during testing.
Browser* browser_;
+ // True if the owning browser is showing an infobar.
+ bool infobar_visible_;
+
// Animation controlling showing and hiding of the bar.
scoped_ptr<SlideAnimation> size_animation_;
diff --git a/chrome/browser/views/bookmark_bar_view_test.cc b/chrome/browser/views/bookmark_bar_view_test.cc
index 78128bb..9b7b512 100644
--- a/chrome/browser/views/bookmark_bar_view_test.cc
+++ b/chrome/browser/views/bookmark_bar_view_test.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/keyboard_codes.h"
-#include "base/string_util.h"
+#include "app/keyboard_codes.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.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/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/views/bookmark_bar_view.h"
@@ -70,6 +71,9 @@ class ViewsDelegateImpl : public views::ViewsDelegate {
return false;
}
+ virtual void NotifyAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type) {}
+
#if defined(OS_WIN)
virtual HICON GetDefaultWindowIcon() const { return 0; }
#endif
@@ -212,31 +216,34 @@ class BookmarkBarViewEventTestBase : public ViewEventTestBase {
std::string test_base = "file:///c:/tmp/";
const BookmarkNode* f1 = model_->AddGroup(
- model_->GetBookmarkBarNode(), 0, L"F1");
- model_->AddURL(f1, 0, L"f1a", GURL(test_base + "f1a"));
- const BookmarkNode* f11 = model_->AddGroup(f1, 1, L"F11");
- model_->AddURL(f11, 0, L"f11a", GURL(test_base + "f11a"));
+ model_->GetBookmarkBarNode(), 0, ASCIIToUTF16("F1"));
+ model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
+ const BookmarkNode* f11 = model_->AddGroup(f1, 1, ASCIIToUTF16("F11"));
+ model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
if (big_menu) {
for (int i = 1; i <= 100; ++i) {
- model_->AddURL(f1, i + 1, L"f" + IntToWString(i),
- GURL(test_base + "f" + IntToString(i)));
+ model_->AddURL(f1, i + 1, ASCIIToUTF16("f") + base::IntToString16(i),
+ GURL(test_base + "f" + base::IntToString(i)));
}
}
- model_->AddURL(model_->GetBookmarkBarNode(), 1, L"a",
+ model_->AddURL(model_->GetBookmarkBarNode(), 1, ASCIIToUTF16("a"),
GURL(test_base + "a"));
- model_->AddURL(model_->GetBookmarkBarNode(), 2, L"b",
+ model_->AddURL(model_->GetBookmarkBarNode(), 2, ASCIIToUTF16("b"),
GURL(test_base + "b"));
- model_->AddURL(model_->GetBookmarkBarNode(), 3, L"c",
+ model_->AddURL(model_->GetBookmarkBarNode(), 3, ASCIIToUTF16("c"),
GURL(test_base + "c"));
- model_->AddURL(model_->GetBookmarkBarNode(), 4, L"d",
+ model_->AddURL(model_->GetBookmarkBarNode(), 4, ASCIIToUTF16("d"),
GURL(test_base + "d"));
- model_->AddURL(model_->other_node(), 0, L"oa", GURL(test_base + "oa"));
- const BookmarkNode* of = model_->AddGroup(model_->other_node(), 1, L"OF");
- model_->AddURL(of, 0, L"ofa", GURL(test_base + "ofa"));
- model_->AddURL(of, 1, L"ofb", GURL(test_base + "ofb"));
- const BookmarkNode* of2 = model_->AddGroup(model_->other_node(), 2, L"OF2");
- model_->AddURL(of2, 0, L"of2a", GURL(test_base + "of2a"));
- model_->AddURL(of2, 1, L"of2b", GURL(test_base + "of2b"));
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
+ GURL(test_base + "oa"));
+ const BookmarkNode* of = model_->AddGroup(model_->other_node(), 1,
+ ASCIIToUTF16("OF"));
+ model_->AddURL(of, 0, ASCIIToUTF16("ofa"), GURL(test_base + "ofa"));
+ model_->AddURL(of, 1, ASCIIToUTF16("ofb"), GURL(test_base + "ofb"));
+ const BookmarkNode* of2 = model_->AddGroup(model_->other_node(), 2,
+ ASCIIToUTF16("OF2"));
+ model_->AddURL(of2, 0, ASCIIToUTF16("of2a"), GURL(test_base + "of2a"));
+ model_->AddURL(of2, 1, ASCIIToUTF16("of2b"), GURL(test_base + "of2b"));
}
gfx::Size bb_view_pref_;
@@ -866,7 +873,7 @@ class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
// Send a down event, which should select the first item.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_DOWN, false, false, false, false,
+ NULL, app::VKEY_DOWN, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest10::Step3));
}
@@ -879,7 +886,7 @@ class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
// Send a key down event, which should select the next item.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_DOWN, false, false, false, false,
+ NULL, app::VKEY_DOWN, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest10::Step4));
}
@@ -892,7 +899,7 @@ class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
// Send a right arrow to force the menu to open.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_RIGHT, false, false, false, false,
+ NULL, app::VKEY_RIGHT, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest10::Step5));
}
@@ -908,7 +915,7 @@ class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
// Send a left arrow to close the submenu.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_LEFT, false, false, false, false,
+ NULL, app::VKEY_LEFT, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest10::Step6));
}
@@ -923,7 +930,7 @@ class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
// Send a down arrow to wrap back to f1a
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_DOWN, false, false, false, false,
+ NULL, app::VKEY_DOWN, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest10::Step7));
}
@@ -936,7 +943,7 @@ class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
// Send enter, which should select the item.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_RETURN, false, false, false, false,
+ NULL, app::VKEY_RETURN, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest10::Step8));
}
@@ -991,7 +998,7 @@ class BookmarkBarViewTest11 : public BookmarkBarViewEventTestBase {
void Step3() {
// Send escape so that the context menu hides.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_ESCAPE, false, false, false, false,
+ NULL, app::VKEY_ESCAPE, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest11::Step4));
}
@@ -1080,7 +1087,7 @@ class BookmarkBarViewTest12 : public BookmarkBarViewEventTestBase {
void Step4() {
// Press tab to give focus to the cancel button.
- ui_controls::SendKeyPress(NULL, base::VKEY_TAB, false, false, false, false);
+ ui_controls::SendKeyPress(NULL, app::VKEY_TAB, false, false, false, false);
// For some reason return isn't processed correctly unless we delay.
MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -1090,7 +1097,7 @@ class BookmarkBarViewTest12 : public BookmarkBarViewEventTestBase {
void Step5() {
// And press enter so that the cancel button is selected.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_RETURN, false, false, false, false,
+ NULL, app::VKEY_RETURN, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest12::Step6));
}
@@ -1219,7 +1226,7 @@ class BookmarkBarViewTest14 : public BookmarkBarViewEventTestBase {
// Send escape so that the context menu hides.
ui_controls::SendKeyPressNotifyWhenDone(
- NULL, base::VKEY_ESCAPE, false, false, false, false,
+ NULL, app::VKEY_ESCAPE, false, false, false, false,
CreateEventTask(this, &BookmarkBarViewTest14::Step3));
}
diff --git a/chrome/browser/views/bookmark_bar_view_unittest.cc b/chrome/browser/views/bookmark_bar_view_unittest.cc
index 61249b6..b84e6b3 100644
--- a/chrome/browser/views/bookmark_bar_view_unittest.cc
+++ b/chrome/browser/views/bookmark_bar_view_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/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/views/bookmark_bar_view.h"
@@ -11,11 +12,9 @@
class BookmarkBarViewTest : public BrowserWithTestWindowTest {
public:
BookmarkBarViewTest()
- : ui_thread_(ChromeThread::UI, message_loop()),
- file_thread_(ChromeThread::FILE, message_loop()) {}
+ : file_thread_(ChromeThread::FILE, message_loop()) {}
private:
- ChromeThread ui_thread_;
ChromeThread file_thread_;
DISALLOW_COPY_AND_ASSIGN(BookmarkBarViewTest);
@@ -28,14 +27,14 @@ TEST_F(BookmarkBarViewTest, SwitchProfile) {
profile()->GetBookmarkModel()->AddURL(
profile()->GetBookmarkModel()->GetBookmarkBarNode(),
0,
- L"blah",
+ ASCIIToUTF16("blah"),
GURL("http://www.google.com"));
BookmarkBarView bookmark_bar(profile(), browser());
EXPECT_EQ(1, bookmark_bar.GetBookmarkButtonCount());
- TestingProfile profile2(0);
+ TestingProfile profile2;
profile2.CreateBookmarkModel(true);
profile2.BlockUntilBookmarkModelLoaded();
diff --git a/chrome/browser/views/bookmark_bubble_view.cc b/chrome/browser/views/bookmark_bubble_view.cc
index 667e033..c13f53f 100644
--- a/chrome/browser/views/bookmark_bubble_view.cc
+++ b/chrome/browser/views/bookmark_bubble_view.cc
@@ -4,9 +4,10 @@
#include "chrome/browser/views/bookmark_bubble_view.h"
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "base/keyboard_codes.h"
+#include "base/string16.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
@@ -128,7 +129,7 @@ void BookmarkBubbleView::DidChangeBounds(const gfx::Rect& previous,
void BookmarkBubbleView::BubbleShown() {
DCHECK(GetWidget());
GetFocusManager()->RegisterAccelerator(
- views::Accelerator(base::VKEY_RETURN, false, false, false), this);
+ views::Accelerator(app::VKEY_RETURN, false, false, false), this);
title_tf_->RequestFocus();
title_tf_->SelectAll();
@@ -136,7 +137,7 @@ void BookmarkBubbleView::BubbleShown() {
bool BookmarkBubbleView::AcceleratorPressed(
const views::Accelerator& accelerator) {
- if (accelerator.GetKeyCode() != base::VKEY_RETURN)
+ if (accelerator.GetKeyCode() != app::VKEY_RETURN)
return false;
if (edit_button_->HasFocus())
@@ -245,7 +246,7 @@ void BookmarkBubbleView::Init() {
layout->AddView(
new Label(l10n_util::GetString(IDS_BOOMARK_BUBBLE_TITLE_TEXT)));
title_tf_ = new views::Textfield();
- title_tf_->SetText(WideToUTF16(GetTitle()));
+ title_tf_->SetText(GetTitle());
layout->AddView(title_tf_);
layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
@@ -260,7 +261,7 @@ void BookmarkBubbleView::Init() {
layout->AddView(close_button_);
}
-std::wstring BookmarkBubbleView::GetTitle() {
+string16 BookmarkBubbleView::GetTitle() {
BookmarkModel* bookmark_model= profile_->GetBookmarkModel();
const BookmarkNode* node =
bookmark_model->GetMostRecentlyAddedNodeForURL(url_);
@@ -268,7 +269,7 @@ std::wstring BookmarkBubbleView::GetTitle() {
return node->GetTitle();
else
NOTREACHED();
- return std::wstring();
+ return string16();
}
void BookmarkBubbleView::ButtonPressed(
@@ -390,7 +391,7 @@ void BookmarkBubbleView::ApplyEdits() {
BookmarkModel* model = profile_->GetBookmarkModel();
const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
if (node) {
- const std::wstring new_title = UTF16ToWide(title_tf_->text());
+ const string16 new_title = title_tf_->text();
if (new_title != node->GetTitle()) {
model->SetTitle(node, new_title);
UserMetrics::RecordAction(
diff --git a/chrome/browser/views/bookmark_bubble_view.h b/chrome/browser/views/bookmark_bubble_view.h
index 6b88a4c..32a928f 100644
--- a/chrome/browser/views/bookmark_bubble_view.h
+++ b/chrome/browser/views/bookmark_bubble_view.h
@@ -4,10 +4,9 @@
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_BUBBLE_VIEW_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_BUBBLE_VIEW_H_
+#pragma once
-#include <vector>
-
-#include "app/combobox_model.h"
+#include "base/string16.h"
#include "chrome/browser/bookmarks/recently_used_folders_combo_model.h"
#include "chrome/browser/views/info_bubble.h"
#include "gfx/rect.h"
@@ -76,7 +75,7 @@ class BookmarkBubbleView : public views::View,
void Init();
// Returns the title to display.
- std::wstring GetTitle();
+ string16 GetTitle();
// LinkController method, either unstars the item or shows the bookmark
// editor (depending upon which link was clicked).
diff --git a/chrome/browser/views/bookmark_context_menu.h b/chrome/browser/views/bookmark_context_menu.h
index d141277..2a50195 100644
--- a/chrome/browser/views/bookmark_context_menu.h
+++ b/chrome/browser/views/bookmark_context_menu.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_CONTEXT_MENU_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_CONTEXT_MENU_H_
+#pragma once
#include "chrome/browser/views/bookmark_context_menu_controller_views.h"
#include "views/controls/menu/menu_delegate.h"
@@ -17,6 +18,9 @@ class BookmarkContextMenuObserver {
// Invoked after the items have been removed from the model.
virtual void DidRemoveBookmarks() = 0;
+
+ protected:
+ virtual ~BookmarkContextMenuObserver() {}
};
class BookmarkContextMenu : public BookmarkContextMenuControllerViewsDelegate,
diff --git a/chrome/browser/views/bookmark_context_menu_controller_views.cc b/chrome/browser/views/bookmark_context_menu_controller_views.cc
index 66dfe38..1da6310 100644
--- a/chrome/browser/views/bookmark_context_menu_controller_views.cc
+++ b/chrome/browser/views/bookmark_context_menu_controller_views.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/views/bookmark_context_menu_controller_views.h"
-#include "app/l10n_util.h"
#include "base/compiler_specific.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_folder_editor_controller.h"
@@ -13,7 +12,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/views/bookmark_context_menu_controller_views.h b/chrome/browser/views/bookmark_context_menu_controller_views.h
index 41433dc..16b3dd2 100644
--- a/chrome/browser/views/bookmark_context_menu_controller_views.h
+++ b/chrome/browser/views/bookmark_context_menu_controller_views.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_CONTEXT_MENU_CONTROLLER_VIEWS_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_CONTEXT_MENU_CONTROLLER_VIEWS_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/views/bookmark_context_menu_test.cc b/chrome/browser/views/bookmark_context_menu_test.cc
index 97a2397..48b2ce0 100644
--- a/chrome/browser/views/bookmark_context_menu_test.cc
+++ b/chrome/browser/views/bookmark_context_menu_test.cc
@@ -3,10 +3,11 @@
// found in the LICENSE file.
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/views/bookmark_context_menu.h"
@@ -90,18 +91,18 @@ class BookmarkContextMenuTest : public testing::Test {
void AddTestData() {
std::string test_base = "file:///c:/tmp/";
- model_->AddURL(model_->GetBookmarkBarNode(), 0, L"a",
+ model_->AddURL(model_->GetBookmarkBarNode(), 0, ASCIIToUTF16("a"),
GURL(test_base + "a"));
const BookmarkNode* f1 =
- model_->AddGroup(model_->GetBookmarkBarNode(), 1, L"F1");
- model_->AddURL(f1, 0, L"f1a", GURL(test_base + "f1a"));
- const BookmarkNode* f11 = model_->AddGroup(f1, 1, L"F11");
- model_->AddURL(f11, 0, L"f11a", GURL(test_base + "f11a"));
- model_->AddGroup(model_->GetBookmarkBarNode(), 2, L"F2");
- model_->AddGroup(model_->GetBookmarkBarNode(), 3, L"F3");
+ model_->AddGroup(model_->GetBookmarkBarNode(), 1, ASCIIToUTF16("F1"));
+ model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
+ const BookmarkNode* f11 = model_->AddGroup(f1, 1, ASCIIToUTF16("F11"));
+ model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 2, ASCIIToUTF16("F2"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 3, ASCIIToUTF16("F3"));
const BookmarkNode* f4 =
- model_->AddGroup(model_->GetBookmarkBarNode(), 4, L"F4");
- model_->AddURL(f4, 0, L"f4a", GURL(test_base + "f4a"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 4, ASCIIToUTF16("F4"));
+ model_->AddURL(f4, 0, ASCIIToUTF16("f4a"), GURL(test_base + "f4a"));
}
};
diff --git a/chrome/browser/views/bookmark_editor_view.cc b/chrome/browser/views/bookmark_editor_view.cc
index 35de1aa..6f892a3 100644
--- a/chrome/browser/views/bookmark_editor_view.cc
+++ b/chrome/browser/views/bookmark_editor_view.cc
@@ -8,10 +8,11 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/history/history.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/pref_names.h"
@@ -274,11 +275,11 @@ void BookmarkEditorView::Init() {
l10n_util::GetString(IDS_BOOMARK_EDITOR_NAME_LABEL));
title_tf_.SetAccessibleName(title_label_->GetText());
- std::wstring url_text;
+ string16 url_text;
if (details_.type == EditDetails::EXISTING_NODE) {
- std::wstring languages = profile_
- ? UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages))
- : std::wstring();
+ std::string languages = profile_
+ ? profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)
+ : std::string();
// Because this gets parsed by FixupURL(), it's safe to omit the scheme or
// trailing slash, and unescape most characters, but we need to not drop any
// username/password, or unescape anything that changes the meaning.
@@ -286,7 +287,7 @@ void BookmarkEditorView::Init() {
net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword,
UnescapeRule::SPACES, NULL, NULL, NULL);
}
- url_tf_.SetText(url_text);
+ url_tf_.SetText(UTF16ToWide(url_text));
url_tf_.SetController(this);
url_label_ = new views::Label(
@@ -449,7 +450,8 @@ void BookmarkEditorView::NewGroup() {
BookmarkEditorView::EditorNode* BookmarkEditorView::AddNewGroup(
EditorNode* parent) {
EditorNode* new_node = new EditorNode();
- new_node->SetTitle(l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME));
+ new_node->SetTitle(
+ l10n_util::GetStringUTF16(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME));
new_node->value = 0;
// new_node is now owned by parent.
tree_model_->Add(parent, parent->GetChildCount(), new_node);
@@ -486,8 +488,9 @@ void BookmarkEditorView::CreateNodes(const BookmarkNode* bb_node,
for (int i = 0; i < bb_node->GetChildCount(); ++i) {
const BookmarkNode* child_bb_node = bb_node->GetChild(i);
if (child_bb_node->is_folder()) {
- EditorNode* new_b_node = new EditorNode(child_bb_node->GetTitle(),
- child_bb_node->id());
+ EditorNode* new_b_node =
+ new EditorNode(WideToUTF16(child_bb_node->GetTitle()),
+ child_bb_node->id());
b_node->Add(b_node->GetChildCount(), new_b_node);
CreateNodes(child_bb_node, new_b_node);
}
@@ -528,7 +531,7 @@ void BookmarkEditorView::ApplyEdits(EditorNode* parent) {
bb_model_->RemoveObserver(this);
GURL new_url(GetInputURL());
- std::wstring new_title(GetInputTitle());
+ string16 new_title(WideToUTF16Hack(GetInputTitle()));
if (!show_tree_) {
bookmark_utils::ApplyEditsWithNoGroupChange(
diff --git a/chrome/browser/views/bookmark_editor_view.h b/chrome/browser/views/bookmark_editor_view.h
index 75a78f6..6b11439 100644
--- a/chrome/browser/views/bookmark_editor_view.h
+++ b/chrome/browser/views/bookmark_editor_view.h
@@ -4,11 +4,11 @@
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_EDITOR_VIEW_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_EDITOR_VIEW_H_
-
-#include <set>
+#pragma once
#include "app/menus/simple_menu_model.h"
#include "app/tree_node_model.h"
+#include "base/string16.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model_observer.h"
#include "views/controls/button/button.h"
@@ -60,7 +60,7 @@ class BookmarkEditorView : public BookmarkEditor,
: TreeNodeModel<EditorNode>(root) {}
virtual void SetTitle(TreeModelNode* node,
- const std::wstring& title) {
+ const string16& title) {
if (!title.empty())
TreeNodeModel::SetTitle(node, title);
}
diff --git a/chrome/browser/views/bookmark_editor_view_unittest.cc b/chrome/browser/views/bookmark_editor_view_unittest.cc
index 15b30ad..95a095a 100644
--- a/chrome/browser/views/bookmark_editor_view_unittest.cc
+++ b/chrome/browser/views/bookmark_editor_view_unittest.cc
@@ -1,12 +1,13 @@
-// 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/message_loop.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/bookmark_editor_view.h"
#include "chrome/common/pref_names.h"
@@ -104,21 +105,21 @@ class BookmarkEditorViewTest : public testing::Test {
void AddTestData() {
std::string test_base = base_path();
- model_->AddURL(model_->GetBookmarkBarNode(), 0, L"a",
+ model_->AddURL(model_->GetBookmarkBarNode(), 0, ASCIIToUTF16("a"),
GURL(test_base + "a"));
const BookmarkNode* f1 =
- model_->AddGroup(model_->GetBookmarkBarNode(), 1, L"F1");
- model_->AddURL(f1, 0, L"f1a", GURL(test_base + "f1a"));
- const BookmarkNode* f11 = model_->AddGroup(f1, 1, L"F11");
- model_->AddURL(f11, 0, L"f11a", GURL(test_base + "f11a"));
- model_->AddGroup(model_->GetBookmarkBarNode(), 2, L"F2");
+ model_->AddGroup(model_->GetBookmarkBarNode(), 1, ASCIIToUTF16("F1"));
+ model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
+ const BookmarkNode* f11 = model_->AddGroup(f1, 1, ASCIIToUTF16("F11"));
+ model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 2, ASCIIToUTF16("F2"));
// Children of the other node.
- model_->AddURL(model_->other_node(), 0, L"oa",
+ model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
GURL(test_base + "oa"));
const BookmarkNode* of1 =
- model_->AddGroup(model_->other_node(), 1, L"OF1");
- model_->AddURL(of1, 0, L"of1a", GURL(test_base + "of1a"));
+ model_->AddGroup(model_->other_node(), 1, ASCIIToUTF16("OF1"));
+ model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a"));
}
scoped_ptr<BookmarkEditorView> editor_;
@@ -138,17 +139,17 @@ TEST_F(BookmarkEditorViewTest, ModelsMatch) {
BookmarkEditorView::EditorNode* bb_node = editor_root->GetChild(0);
// The root should have 2 nodes: folder F1 and F2.
ASSERT_EQ(2, bb_node->GetChildCount());
- ASSERT_EQ(L"F1", bb_node->GetChild(0)->GetTitle());
- ASSERT_EQ(L"F2", bb_node->GetChild(1)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F1"), bb_node->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F2"), bb_node->GetChild(1)->GetTitle());
// F1 should have one child, F11
ASSERT_EQ(1, bb_node->GetChild(0)->GetChildCount());
- ASSERT_EQ(L"F11", bb_node->GetChild(0)->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F11"), bb_node->GetChild(0)->GetChild(0)->GetTitle());
BookmarkEditorView::EditorNode* other_node = editor_root->GetChild(1);
// Other node should have one child (OF1).
ASSERT_EQ(1, other_node->GetChildCount());
- ASSERT_EQ(L"OF1", other_node->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("OF1"), other_node->GetChild(0)->GetTitle());
}
// Changes the title and makes sure parent/visual order doesn't change.
@@ -161,7 +162,7 @@ TEST_F(BookmarkEditorViewTest, EditTitleKeepsPosition) {
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
- ASSERT_EQ(L"new_a", bb_node->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("new_a"), bb_node->GetChild(0)->GetTitle());
// The URL shouldn't have changed.
ASSERT_TRUE(GURL(base_path() + "a") == bb_node->GetChild(0)->GetURL());
}
@@ -179,7 +180,7 @@ TEST_F(BookmarkEditorViewTest, EditURLKeepsPosition) {
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
- ASSERT_EQ(L"a", bb_node->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), bb_node->GetChild(0)->GetTitle());
// The URL should have changed.
ASSERT_TRUE(GURL(base_path() + "new_a") == bb_node->GetChild(0)->GetURL());
ASSERT_TRUE(node_time == bb_node->GetChild(0)->date_added());
@@ -193,7 +194,7 @@ TEST_F(BookmarkEditorViewTest, ChangeParent) {
ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
- ASSERT_EQ(L"a", other_node->GetChild(2)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
ASSERT_TRUE(GURL(base_path() + "a") == other_node->GetChild(2)->GetURL());
}
@@ -209,7 +210,7 @@ TEST_F(BookmarkEditorViewTest, ChangeParentAndURL) {
ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
- ASSERT_EQ(L"a", other_node->GetChild(2)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
ASSERT_TRUE(GURL(base_path() + "new_a") == other_node->GetChild(2)->GetURL());
ASSERT_TRUE(node_time == other_node->GetChild(2)->date_added());
}
@@ -223,9 +224,9 @@ TEST_F(BookmarkEditorViewTest, MoveToNewParent) {
BookmarkEditorView::EditorNode* f2 =
editor_tree_model()->GetRoot()->GetChild(0)->GetChild(1);
BookmarkEditorView::EditorNode* f21 = AddNewGroup(f2);
- f21->SetTitle(L"F21");
+ f21->SetTitle(ASCIIToUTF16("F21"));
BookmarkEditorView::EditorNode* f211 = AddNewGroup(f21);
- f211->SetTitle(L"F211");
+ f211->SetTitle(ASCIIToUTF16("F211"));
// Parent the node to "F21".
ApplyEdits(f2);
@@ -237,14 +238,14 @@ TEST_F(BookmarkEditorViewTest, MoveToNewParent) {
// F2 in the model should have two children now: F21 and the node edited.
ASSERT_EQ(2, mf2->GetChildCount());
// F21 should be first.
- ASSERT_EQ(L"F21", mf2->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F21"), mf2->GetChild(0)->GetTitle());
// Then a.
- ASSERT_EQ(L"a", mf2->GetChild(1)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("a"), mf2->GetChild(1)->GetTitle());
// F21 should have one child, F211.
const BookmarkNode* mf21 = mf2->GetChild(0);
ASSERT_EQ(1, mf21->GetChildCount());
- ASSERT_EQ(L"F211", mf21->GetChild(0)->GetTitle());
+ ASSERT_EQ(ASCIIToUTF16("F211"), mf21->GetChild(0)->GetTitle());
}
// Brings up the editor, creating a new URL on the bookmark bar.
@@ -263,7 +264,7 @@ TEST_F(BookmarkEditorViewTest, NewURL) {
const BookmarkNode* new_node = bb_node->GetChild(3);
- EXPECT_EQ(L"new_a", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
EXPECT_TRUE(GURL(base_path() + "a") == new_node->GetURL());
}
@@ -283,7 +284,7 @@ TEST_F(BookmarkEditorViewTest, ChangeURLNoTree) {
const BookmarkNode* new_node = other_node->GetChild(0);
- EXPECT_EQ(L"new_a", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
EXPECT_TRUE(GURL(base_path() + "a") == new_node->GetURL());
}
@@ -302,13 +303,14 @@ TEST_F(BookmarkEditorViewTest, ChangeTitleNoTree) {
const BookmarkNode* new_node = other_node->GetChild(0);
- EXPECT_EQ(L"new_a", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
}
// Creates a new folder.
TEST_F(BookmarkEditorViewTest, NewFolder) {
BookmarkEditor::EditDetails details;
- details.urls.push_back(std::make_pair(GURL(base_path() + "x"), L"z"));
+ details.urls.push_back(std::make_pair(GURL(base_path() + "x"),
+ ASCIIToUTF16("z")));
details.type = BookmarkEditor::EditDetails::NEW_FOLDER;
CreateEditor(profile_.get(), model_->GetBookmarkBarNode(),
details, BookmarkEditorView::SHOW_TREE);
@@ -324,21 +326,22 @@ TEST_F(BookmarkEditorViewTest, NewFolder) {
const BookmarkNode* new_node =
model_->GetBookmarkBarNode()->GetChild(3);
EXPECT_EQ(BookmarkNode::FOLDER, new_node->type());
- EXPECT_EQ(L"new_F", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_F"), new_node->GetTitle());
// The node should have one child.
ASSERT_EQ(1, new_node->GetChildCount());
const BookmarkNode* new_child = new_node->GetChild(0);
// Make sure the child url/title match.
EXPECT_EQ(BookmarkNode::URL, new_child->type());
- EXPECT_EQ(details.urls[0].second, new_child->GetTitle());
- EXPECT_TRUE(details.urls[0].first == new_child->GetURL());
+ EXPECT_EQ(WideToUTF16Hack(details.urls[0].second), new_child->GetTitle());
+ EXPECT_EQ(details.urls[0].first, new_child->GetURL());
}
// Creates a new folder and selects a different folder for the folder to appear
// in then the editor is initially created showing.
TEST_F(BookmarkEditorViewTest, MoveFolder) {
BookmarkEditor::EditDetails details;
- details.urls.push_back(std::make_pair(GURL(base_path() + "x"), L"z"));
+ details.urls.push_back(std::make_pair(GURL(base_path() + "x"),
+ ASCIIToUTF16("z")));
details.type = BookmarkEditor::EditDetails::NEW_FOLDER;
CreateEditor(profile_.get(), model_->GetBookmarkBarNode(),
details, BookmarkEditorView::SHOW_TREE);
@@ -352,12 +355,12 @@ TEST_F(BookmarkEditorViewTest, MoveFolder) {
ASSERT_EQ(3, model_->other_node()->GetChildCount());
const BookmarkNode* new_node = model_->other_node()->GetChild(2);
EXPECT_EQ(BookmarkNode::FOLDER, new_node->type());
- EXPECT_EQ(L"new_F", new_node->GetTitle());
+ EXPECT_EQ(ASCIIToUTF16("new_F"), new_node->GetTitle());
// The node should have one child.
ASSERT_EQ(1, new_node->GetChildCount());
const BookmarkNode* new_child = new_node->GetChild(0);
// Make sure the child url/title match.
EXPECT_EQ(BookmarkNode::URL, new_child->type());
- EXPECT_EQ(details.urls[0].second, new_child->GetTitle());
- EXPECT_TRUE(details.urls[0].first == new_child->GetURL());
+ EXPECT_EQ(WideToUTF16Hack(details.urls[0].second), new_child->GetTitle());
+ EXPECT_EQ(details.urls[0].first, new_child->GetURL());
}
diff --git a/chrome/browser/views/bookmark_menu_controller_views.cc b/chrome/browser/views/bookmark_menu_controller_views.cc
index 372fa68..c86432e 100644
--- a/chrome/browser/views/bookmark_menu_controller_views.cc
+++ b/chrome/browser/views/bookmark_menu_controller_views.cc
@@ -4,10 +4,10 @@
#include "chrome/browser/views/bookmark_menu_controller_views.h"
-#include "app/l10n_util.h"
#include "app/os_exchange_data.h"
#include "app/resource_bundle.h"
#include "base/stl_util-inl.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
@@ -24,6 +24,10 @@
using views::MenuItemView;
+// Max width of a menu. There does not appear to be an OS value for this, yet
+// both IE and FF restrict the max width of a menu.
+static const int kMaxMenuWidth = 400;
+
BookmarkMenuController::BookmarkMenuController(Browser* browser,
Profile* profile,
PageNavigator* navigator,
@@ -258,6 +262,10 @@ views::MenuItemView* BookmarkMenuController::GetSiblingMenu(
return alt_menu;
}
+int BookmarkMenuController::GetMaxWidthForMenu() {
+ return kMaxMenuWidth;
+}
+
void BookmarkMenuController::BookmarkModelChanged() {
menu_->Cancel();
}
@@ -320,13 +328,13 @@ void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
icon = *ResourceBundle::GetSharedInstance().
GetBitmapNamed(IDR_DEFAULT_FAVICON);
}
- menu->AppendMenuItemWithIcon(id, node->GetTitle(), icon);
+ menu->AppendMenuItemWithIcon(id, UTF16ToWide(node->GetTitle()), icon);
node_to_menu_id_map_[node] = id;
} else if (node->is_folder()) {
SkBitmap* folder_icon = ResourceBundle::GetSharedInstance().
GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER);
- MenuItemView* submenu =
- menu->AppendSubMenuWithIcon(id, node->GetTitle(), *folder_icon);
+ MenuItemView* submenu = menu->AppendSubMenuWithIcon(id,
+ UTF16ToWide(node->GetTitle()), *folder_icon);
node_to_menu_id_map_[node] = id;
BuildMenu(node, 0, submenu, next_menu_id);
} else {
diff --git a/chrome/browser/views/bookmark_menu_controller_views.h b/chrome/browser/views/bookmark_menu_controller_views.h
index 511483a..f71196b 100644
--- a/chrome/browser/views/bookmark_menu_controller_views.h
+++ b/chrome/browser/views/bookmark_menu_controller_views.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_MENU_CONTROLLER_VIEWS_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_MENU_CONTROLLER_VIEWS_H_
+#pragma once
#include <map>
#include <set>
@@ -43,6 +44,9 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
class Observer {
public:
virtual void BookmarkMenuDeleted(BookmarkMenuController* controller) = 0;
+
+ protected:
+ virtual ~Observer() {}
};
// Creates a BookmarkMenuController showing the children of |node| starting
@@ -106,6 +110,7 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
views::MenuItemView::AnchorPosition* anchor,
bool* has_mnemonics,
views::MenuButton** button);
+ virtual int GetMaxWidthForMenu();
// BookmarkModelObserver methods.
virtual void BookmarkModelChanged();
@@ -121,7 +126,7 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
typedef std::map<const BookmarkNode*, int> NodeToMenuIDMap;
// BookmarkMenuController deletes itself as necessary.
- ~BookmarkMenuController();
+ virtual ~BookmarkMenuController();
// Creates a menu and adds it to node_to_menu_id_map_. This uses
// BuildMenu to recursively populate the menu.
diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc
index d5a8fde..f93769a 100644
--- a/chrome/browser/views/browser_actions_container.cc
+++ b/chrome/browser/views/browser_actions_container.cc
@@ -9,21 +9,23 @@
#include "app/slide_animation.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/extensions/extensions_service.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/tab_contents/tab_contents.h"
+#include "chrome/browser/themes/browser_theme_provider.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/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/notification_source.h"
@@ -44,53 +46,13 @@
#include "grit/theme_resources.h"
-namespace {
-
-// The size (both dimensions) of the buttons for page actions.
-static const int kButtonSize = 29;
-
-// The padding between the browser actions and the OmniBox/page menu.
-static const int kHorizontalPadding = 4;
-static const int kHorizontalPaddingRtl = 8;
-
-// The padding between browser action buttons. Visually, the actual number of
-// empty (non-drawing) pixels is this value + 2 when adjacent browser icons
-// use their maximum allowed size.
-static const int kBrowserActionButtonPadding = 3;
-
-// This is the same value from toolbar.cc. We position the browser actions
-// container flush with the edges of the toolbar as a special case so that we
-// can draw the badge outside the visual bounds of the container.
-static const int kControlVertOffset = 6;
+// Horizontal spacing between most items in the container, as well as after the
+// last item or chevron (if visible).
+static const int kItemSpacing = ToolbarView::kStandardSpacing;
+// Horizontal spacing before the chevron (if visible).
+static const int kChevronSpacing = kItemSpacing - 2;
-// The margin between the divider and the chrome menu buttons.
-static const int kDividerHorizontalMargin = 2;
-
-// The padding above and below the divider.
-static const int kDividerVerticalPadding = 9;
-
-// The margin above the chevron.
-static const int kChevronTopMargin = 9;
-
-// The margin to the right of the chevron.
-static const int kChevronRightMargin = 4;
-
-// Extra hit-area for the resize gripper.
-static const int kExtraResizeArea = 4;
-
-// Width of the drop indicator.
-static const int kDropIndicatorWidth = 2;
-
-// Color of the drop indicator.
-static const SkColor kDropIndicatorColor = SK_ColorBLACK;
-
-// The x offset for the drop indicator (how much we shift it by).
-static const int kDropIndicatorOffsetLtr = 3;
-static const int kDropIndicatorOffsetRtl = 9;
-
-} // namespace.
-
-// Static.
+// static
bool BrowserActionsContainer::disable_animations_during_testing_ = false;
////////////////////////////////////////////////////////////////////////////////
@@ -98,12 +60,14 @@ bool BrowserActionsContainer::disable_animations_during_testing_ = false;
BrowserActionButton::BrowserActionButton(Extension* extension,
BrowserActionsContainer* panel)
- : ALLOW_THIS_IN_INITIALIZER_LIST(MenuButton(this, L"", NULL, false)),
+ : ALLOW_THIS_IN_INITIALIZER_LIST(
+ MenuButton(this, std::wstring(), NULL, false)),
browser_action_(extension->browser_action()),
extension_(extension),
ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)),
showing_context_menu_(false),
panel_(panel) {
+ set_border(NULL);
set_alignment(TextButton::ALIGN_CENTER);
// No UpdateState() here because View hierarchy not setup yet. Our parent
@@ -138,18 +102,14 @@ void BrowserActionButton::Destroy() {
}
}
-gfx::Insets BrowserActionButton::GetInsets() const {
- static gfx::Insets zero_inset;
- return zero_inset;
-}
-
void BrowserActionButton::ButtonPressed(views::Button* sender,
- const views::Event& event) {
- panel_->OnBrowserActionExecuted(this, false); // inspect_with_devtools
+ const views::Event& event) {
+ panel_->OnBrowserActionExecuted(this, false);
}
-void BrowserActionButton::OnImageLoaded(
- SkBitmap* image, ExtensionResource resource, int index) {
+void BrowserActionButton::OnImageLoaded(SkBitmap* image,
+ ExtensionResource resource,
+ int index) {
if (image)
default_icon_ = *image;
@@ -163,11 +123,40 @@ void BrowserActionButton::UpdateState() {
if (tab_id < 0)
return;
- SkBitmap image = browser_action()->GetIcon(tab_id);
- if (!image.isNull())
- SetIcon(image);
- else if (!default_icon_.isNull())
- SetIcon(default_icon_);
+ SkBitmap icon(browser_action()->GetIcon(tab_id));
+ if (icon.isNull())
+ icon = default_icon_;
+ if (!icon.isNull()) {
+ SkPaint paint;
+ paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode));
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ SkBitmap bg;
+ rb.GetBitmapNamed(IDR_BROWSER_ACTION)->copyTo(&bg,
+ SkBitmap::kARGB_8888_Config);
+ SkCanvas bg_canvas(bg);
+ bg_canvas.drawBitmap(icon, SkIntToScalar((bg.width() - icon.width()) / 2),
+ SkIntToScalar((bg.height() - icon.height()) / 2), &paint);
+ SetIcon(bg);
+
+ SkBitmap bg_h;
+ rb.GetBitmapNamed(IDR_BROWSER_ACTION_H)->copyTo(&bg_h,
+ SkBitmap::kARGB_8888_Config);
+ SkCanvas bg_h_canvas(bg_h);
+ bg_h_canvas.drawBitmap(icon,
+ SkIntToScalar((bg_h.width() - icon.width()) / 2),
+ SkIntToScalar((bg_h.height() - icon.height()) / 2), &paint);
+ SetHoverIcon(bg_h);
+
+ SkBitmap bg_p;
+ rb.GetBitmapNamed(IDR_BROWSER_ACTION_P)->copyTo(&bg_p,
+ SkBitmap::kARGB_8888_Config);
+ SkCanvas bg_p_canvas(bg_p);
+ bg_p_canvas.drawBitmap(icon,
+ SkIntToScalar((bg_p.width() - icon.width()) / 2),
+ SkIntToScalar((bg_p.height() - icon.height()) / 2), &paint);
+ SetPushedIcon(bg_p);
+ }
// If the browser action name is empty, show the extension name instead.
std::wstring name = UTF8ToWide(browser_action()->GetTitle(tab_id));
@@ -181,66 +170,54 @@ void BrowserActionButton::UpdateState() {
void BrowserActionButton::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) {
- UpdateState();
- // The browser action may have become visible/hidden so we need to make
- // sure the state gets updated.
- panel_->OnBrowserActionVisibilityChanged();
- } else {
- NOTREACHED() << L"Received unexpected notification";
- }
+ DCHECK(type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED);
+ UpdateState();
+ // The browser action may have become visible/hidden so we need to make
+ // sure the state gets updated.
+ panel_->OnBrowserActionVisibilityChanged();
}
bool BrowserActionButton::IsPopup() {
int tab_id = panel_->GetCurrentTabId();
- if (tab_id < 0) {
- NOTREACHED() << "Button is not on a specific tab.";
- return false;
- }
- return browser_action_->HasPopup(tab_id);
+ return (tab_id < 0) ? false : browser_action_->HasPopup(tab_id);
}
GURL BrowserActionButton::GetPopupUrl() {
int tab_id = panel_->GetCurrentTabId();
- if (tab_id < 0) {
- NOTREACHED() << "Button is not on a specific tab.";
- GURL empty_url;
- return empty_url;
- }
- return browser_action_->GetPopupUrl(tab_id);
+ return (tab_id < 0) ? GURL() : browser_action_->GetPopupUrl(tab_id);
}
bool BrowserActionButton::Activate() {
- if (IsPopup()) {
- panel_->OnBrowserActionExecuted(this, false); // |inspect_with_devtools|.
+ if (!IsPopup())
+ return true;
- // TODO(erikkay): Run a nested modal loop while the mouse is down to
- // enable menu-like drag-select behavior.
+ panel_->OnBrowserActionExecuted(this, false);
- // The return value of this method is returned via OnMousePressed.
- // We need to return false here since we're handing off focus to another
- // widget/view, and true will grab it right back and try to send events
- // to us.
- return false;
- }
- return true;
+ // TODO(erikkay): Run a nested modal loop while the mouse is down to
+ // enable menu-like drag-select behavior.
+
+ // The return value of this method is returned via OnMousePressed.
+ // We need to return false here since we're handing off focus to another
+ // widget/view, and true will grab it right back and try to send events
+ // to us.
+ return false;
}
bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) {
- if (e.IsRightMouseButton()) {
- // Get the top left point of this button in screen coordinates.
- gfx::Point point = gfx::Point(0, 0);
- ConvertPointToScreen(this, &point);
-
- // Make the menu appear below the button.
- point.Offset(0, height());
-
- ShowContextMenu(point, true);
- return false;
- } else if (IsPopup()) {
- return MenuButton::OnMousePressed(e);
+ if (!e.IsRightMouseButton()) {
+ return IsPopup() ?
+ MenuButton::OnMousePressed(e) : TextButton::OnMousePressed(e);
}
- return TextButton::OnMousePressed(e);
+
+ // Get the top left point of this button in screen coordinates.
+ gfx::Point point = gfx::Point(0, 0);
+ ConvertPointToScreen(this, &point);
+
+ // Make the menu appear below the button.
+ point.Offset(0, height());
+
+ ShowContextMenu(point, true);
+ return false;
}
void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e,
@@ -255,9 +232,8 @@ void BrowserActionButton::OnMouseReleased(const views::MouseEvent& e,
}
bool BrowserActionButton::OnKeyReleased(const views::KeyEvent& e) {
- if (IsPopup())
- return MenuButton::OnKeyReleased(e);
- return TextButton::OnKeyReleased(e);
+ return IsPopup() ?
+ MenuButton::OnKeyReleased(e) : TextButton::OnKeyReleased(e);
}
void BrowserActionButton::OnMouseExited(const views::MouseEvent& e) {
@@ -273,8 +249,8 @@ void BrowserActionButton::ShowContextMenu(const gfx::Point& p,
SetButtonPushed();
// Reconstructs the menu every time because the menu's contents are dynamic.
- context_menu_contents_ = new ExtensionContextMenuModel(
- extension(), panel_->browser(), panel_);
+ context_menu_contents_ =
+ new ExtensionContextMenuModel(extension(), panel_->browser(), panel_);
context_menu_menu_.reset(new views::Menu2(context_menu_contents_.get()));
context_menu_menu_->RunContextMenuAt(p);
@@ -322,52 +298,53 @@ gfx::Canvas* BrowserActionView::GetIconWithBadge() {
if (icon.isNull())
icon = button_->default_icon();
- gfx::Canvas* canvas =
- new gfx::CanvasSkia(icon.width(), icon.height(), false);
+ gfx::Canvas* canvas = new gfx::CanvasSkia(icon.width(), icon.height(), false);
canvas->DrawBitmapInt(icon, 0, 0);
if (tab_id >= 0) {
- gfx::Rect bounds =
- gfx::Rect(icon.width(), icon.height() + kControlVertOffset);
- button_->extension()->browser_action()->PaintBadge(canvas,
- bounds, tab_id);
+ gfx::Rect bounds(icon.width(), icon.height() + ToolbarView::kVertSpacing);
+ button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id);
}
return canvas;
}
-bool BrowserActionView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+AccessibilityTypes::Role BrowserActionView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
void BrowserActionView::Layout() {
- button_->SetBounds(0, kControlVertOffset, width(), kButtonSize);
+ // We can't rely on button_->GetPreferredSize() here because that's not set
+ // correctly until the first call to
+ // BrowserActionsContainer::RefreshBrowserActionViews(), whereas this can be
+ // called before that when the initial bounds are set (and then not after,
+ // since the bounds don't change). So instead of setting the height from the
+ // button's preferred size, we use IconHeight(), since that's how big the
+ // button should be regardless of what it's displaying.
+ button_->SetBounds(0, ToolbarView::kVertSpacing, width(),
+ BrowserActionsContainer::IconHeight());
}
void BrowserActionView::PaintChildren(gfx::Canvas* canvas) {
View::PaintChildren(canvas);
ExtensionAction* action = button()->browser_action();
int tab_id = panel_->GetCurrentTabId();
- if (tab_id < 0)
- return;
-
- action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id);
+ if (tab_id >= 0)
+ action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id);
}
////////////////////////////////////////////////////////////////////////////////
// BrowserActionsContainer
-BrowserActionsContainer::BrowserActionsContainer(
- Browser* browser, View* owner_view)
+BrowserActionsContainer::BrowserActionsContainer(Browser* browser,
+ View* owner_view)
: profile_(browser->profile()),
browser_(browser),
owner_view_(owner_view),
popup_(NULL),
popup_button_(NULL),
model_(NULL),
- resize_gripper_(NULL),
+ container_width_(0),
chevron_(NULL),
overflow_menu_(NULL),
suppress_chevron_(false),
@@ -382,42 +359,20 @@ BrowserActionsContainer::BrowserActionsContainer(
model_ = profile_->GetExtensionsService()->toolbar_model();
model_->AddObserver(this);
}
+
resize_animation_.reset(new SlideAnimation(this));
- resize_gripper_ = new views::ResizeGripper(this);
- resize_gripper_->SetAccessibleName(
- l10n_util::GetString(IDS_ACCNAME_SEPARATOR));
- resize_gripper_->SetVisible(false);
- AddChildView(resize_gripper_);
-
- // TODO(glen): Come up with a new bitmap for the chevron.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- SkBitmap* chevron_image = rb.GetBitmapNamed(IDR_BOOKMARK_BAR_CHEVRONS);
+ resize_area_ = new views::ResizeArea(this);
+ resize_area_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_SEPARATOR));
+ AddChildView(resize_area_);
+
chevron_ = new views::MenuButton(NULL, std::wstring(), this, false);
- chevron_->SetVisible(false);
- chevron_->SetIcon(*chevron_image);
+ chevron_->set_border(NULL);
+ chevron_->EnableCanvasFlippingForRTLUI(true);
chevron_->SetAccessibleName(
l10n_util::GetString(IDS_ACCNAME_EXTENSIONS_CHEVRON));
- // Chevron contains >> that should point left in LTR locales.
- chevron_->EnableCanvasFlippingForRTLUI(true);
+ chevron_->SetVisible(false);
AddChildView(chevron_);
- if (!profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) {
- // Migration code to the new VisibleIconCount pref.
- // TODO(mpcomplete): remove this after users are upgraded to 5.0.
- int predefined_width =
- profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth);
- if (predefined_width != 0) {
- int icon_width = (kButtonSize + kBrowserActionButtonPadding);
- if (model_) {
- model_->SetVisibleIconCount(
- (predefined_width - WidthOfNonIconArea()) / icon_width);
- }
- }
- }
-
- if (model_ && model_->extensions_initialized())
- SetContainerWidth();
-
SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_EXTENSIONS));
}
@@ -434,23 +389,36 @@ void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0);
}
+void BrowserActionsContainer::Init() {
+ LoadImages();
+
+ // We wait to set the container width until now so that the chevron images
+ // will be loaded. The width calculation needs to know the chevron size.
+ if (model_ &&
+ !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) {
+ // Migration code to the new VisibleIconCount pref.
+ // TODO(mpcomplete): remove this after users are upgraded to 5.0.
+ int predefined_width =
+ profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth);
+ if (predefined_width != 0)
+ model_->SetVisibleIconCount(WidthToIconCount(predefined_width));
+ }
+ if (model_ && model_->extensions_initialized())
+ SetContainerWidth();
+}
+
int BrowserActionsContainer::GetCurrentTabId() const {
TabContents* tab_contents = browser_->GetSelectedTabContents();
- if (!tab_contents)
- return -1;
-
- return tab_contents->controller().session_id().id();
+ return tab_contents ? tab_contents->controller().session_id().id() : -1;
}
BrowserActionView* BrowserActionsContainer::GetBrowserActionView(
ExtensionAction* action) {
- for (BrowserActionViews::iterator iter =
- browser_action_views_.begin(); iter != browser_action_views_.end();
- ++iter) {
+ for (BrowserActionViews::iterator iter = browser_action_views_.begin();
+ iter != browser_action_views_.end(); ++iter) {
if ((*iter)->button()->browser_action() == action)
return *iter;
}
-
return NULL;
}
@@ -459,46 +427,13 @@ void BrowserActionsContainer::RefreshBrowserActionViews() {
browser_action_views_[i]->button()->UpdateState();
}
-void BrowserActionsContainer::CloseOverflowMenu() {
- if (overflow_menu_)
- overflow_menu_->CancelMenu();
-}
-
-void BrowserActionsContainer::StopShowFolderDropMenuTimer() {
- show_menu_task_factory_.RevokeAll();
-}
-
-void BrowserActionsContainer::StartShowFolderDropMenuTimer() {
- int delay = View::GetMenuShowDelay();
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- show_menu_task_factory_.NewRunnableMethod(
- &BrowserActionsContainer::ShowDropFolder),
- delay);
-}
-
-void BrowserActionsContainer::ShowDropFolder() {
- DCHECK(!overflow_menu_);
- SetDropIndicator(-1);
- overflow_menu_ = new BrowserActionOverflowMenuController(
- this, chevron_, browser_action_views_, VisibleBrowserActions());
- overflow_menu_->set_observer(this);
- overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), true);
-}
-
-void BrowserActionsContainer::SetDropIndicator(int x_pos) {
- if (drop_indicator_position_ != x_pos) {
- drop_indicator_position_ = x_pos;
- SchedulePaint();
- }
-}
-
void BrowserActionsContainer::CreateBrowserActionViews() {
DCHECK(browser_action_views_.empty());
if (!model_)
return;
- for (ExtensionList::iterator iter = model_->begin();
- iter != model_->end(); ++iter) {
+ for (ExtensionList::iterator iter = model_->begin(); iter != model_->end();
+ ++iter) {
if (!ShouldDisplayBrowserAction(*iter))
continue;
@@ -519,82 +454,66 @@ void BrowserActionsContainer::DeleteBrowserActionViews() {
}
void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
- SetVisible(browser_action_views_.size() > 0);
- resize_gripper_->SetVisible(browser_action_views_.size() > 0);
-
+ SetVisible(!browser_action_views_.empty());
owner_view_->Layout();
owner_view_->SchedulePaint();
}
-void BrowserActionsContainer::HidePopup() {
- if (popup_)
- popup_->Close();
-}
-
-void BrowserActionsContainer::TestExecuteBrowserAction(int index) {
- BrowserActionButton* button = browser_action_views_[index]->button();
- OnBrowserActionExecuted(button, false); // |inspect_with_devtools|.
-}
-
-void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
- chevron_->SetVisible(icons < browser_action_views_.size());
- container_size_.set_width(IconCountToWidth(icons));
- Layout();
- SchedulePaint();
+size_t BrowserActionsContainer::VisibleBrowserActions() const {
+ size_t visible_actions = 0;
+ for (size_t i = 0; i < browser_action_views_.size(); ++i) {
+ if (browser_action_views_[i]->IsVisible())
+ ++visible_actions;
+ }
+ return visible_actions;
}
void BrowserActionsContainer::OnBrowserActionExecuted(
- BrowserActionButton* button, bool inspect_with_devtools) {
+ BrowserActionButton* button,
+ bool inspect_with_devtools) {
ExtensionAction* browser_action = button->browser_action();
// Popups just display. No notification to the extension.
// TODO(erikkay): should there be?
- if (button->IsPopup()) {
- // If we're showing the same popup, just hide it and return.
- bool same_showing = popup_ && button == popup_button_;
-
- // Always hide the current popup, even if it's not the same.
- // Only one popup should be visible at a time.
- HidePopup();
+ if (!button->IsPopup()) {
+ ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
+ profile_, browser_action->extension_id(), browser_);
+ return;
+ }
- if (same_showing)
- return;
+ // If we're showing the same popup, just hide it and return.
+ bool same_showing = popup_ && button == popup_button_;
- // We can get the execute event for browser actions that are not visible,
- // since buttons can be activated from the overflow menu (chevron). In that
- // case we show the popup as originating from the chevron.
- View* reference_view = button->GetParent()->IsVisible() ? button : chevron_;
- gfx::Point origin;
- View::ConvertPointToScreen(reference_view, &origin);
- gfx::Rect rect = reference_view->bounds();
- rect.set_x(origin.x());
- rect.set_y(origin.y());
-
- gfx::NativeWindow frame_window =
- browser_->window()->GetNativeHandle();
- BubbleBorder::ArrowLocation arrow_location = base::i18n::IsRTL() ?
- BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT;
-
- popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_,
- browser_->profile(), frame_window, rect, arrow_location,
- true, // Activate the popup window.
- inspect_with_devtools,
- ExtensionPopup::BUBBLE_CHROME,
- this); // ExtensionPopupDelegate
- popup_button_ = button;
- popup_button_->SetButtonPushed();
+ // Always hide the current popup, even if it's not the same.
+ // Only one popup should be visible at a time.
+ HidePopup();
+ if (same_showing)
return;
- }
- // Otherwise, we send the action to the extension.
- ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
- profile_, browser_action->extension_id(), browser_);
+ // We can get the execute event for browser actions that are not visible,
+ // since buttons can be activated from the overflow menu (chevron). In that
+ // case we show the popup as originating from the chevron.
+ View* reference_view = button->GetParent()->IsVisible() ? button : chevron_;
+ gfx::Point origin;
+ View::ConvertPointToScreen(reference_view, &origin);
+ gfx::Rect rect = reference_view->bounds();
+ rect.set_origin(origin);
+
+ gfx::NativeWindow frame_window = browser_->window()->GetNativeHandle();
+ BubbleBorder::ArrowLocation arrow_location = base::i18n::IsRTL() ?
+ BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT;
+
+ popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_,
+ browser_->profile(), frame_window, rect, arrow_location, true,
+ inspect_with_devtools, ExtensionPopup::BUBBLE_CHROME, this);
+ popup_button_ = button;
+ popup_button_->SetButtonPushed();
}
gfx::Size BrowserActionsContainer::GetPreferredSize() {
if (browser_action_views_.empty())
- return gfx::Size(0, 0);
+ return gfx::Size(ToolbarView::kStandardSpacing, 0);
// We calculate the size of the view by taking the current width and
// subtracting resize_amount_ (the latter represents how far the user is
@@ -602,72 +521,44 @@ gfx::Size BrowserActionsContainer::GetPreferredSize() {
// But we also clamp it to a minimum size and the maximum size, so that the
// container can never shrink too far or take up more space than it needs. In
// other words: ContainerMinSize() < width() - resize < ClampTo(MAX).
- int width = std::max(ContainerMinSize(),
- container_size_.width() - resize_amount_);
- int max_width = ClampToNearestIconCount(-1, false); // -1 gives max width.
- width = std::min(width, max_width);
-
- return gfx::Size(width, kButtonSize);
+ int clamped_width = std::min(
+ std::max(ContainerMinSize(), container_width_ - resize_amount_),
+ IconCountToWidth(-1, false));
+ return gfx::Size(clamped_width, 0);
}
void BrowserActionsContainer::Layout() {
- if (browser_action_views_.size() == 0) {
+ if (browser_action_views_.empty()) {
SetVisible(false);
- resize_gripper_->SetVisible(false);
- chevron_->SetVisible(false);
return;
- } else {
- SetVisible(true);
- resize_gripper_->SetVisible(true);
- }
-
- int x = 0;
- if (resize_gripper_->IsVisible()) {
- // We'll draw the resize gripper a little wider, to add some invisible hit
- // target area - but we don't account for it anywhere.
- gfx::Size sz = resize_gripper_->GetPreferredSize();
- resize_gripper_->SetBounds(x, (height() - sz.height()) / 2 + 1,
- sz.width() + kExtraResizeArea, sz.height());
- x += sz.width();
}
- x += base::i18n::IsRTL() ? kHorizontalPaddingRtl : kHorizontalPadding;
+ SetVisible(true);
+ resize_area_->SetBounds(0, ToolbarView::kVertSpacing, kItemSpacing,
+ IconHeight());
- // Calculate if all icons fit without showing the chevron. We need to know
- // this beforehand, because showing the chevron will decrease the space that
- // we have to draw the visible ones (ie. if one icon is visible and another
- // doesn't have enough room).
- int last_x_of_icons = x +
- (browser_action_views_.size() * kButtonSize) +
- ((browser_action_views_.size() - 1) *
- kBrowserActionButtonPadding);
-
- gfx::Size sz = GetPreferredSize();
- int max_x = sz.width() - kDividerHorizontalMargin - kChevronRightMargin;
-
- // If they don't all fit, show the chevron (unless suppressed).
- gfx::Size chevron_size;
- if (last_x_of_icons >= max_x && !suppress_chevron_) {
+ // If the icons don't all fit, show the chevron (unless suppressed).
+ int max_x = GetPreferredSize().width();
+ if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_) {
chevron_->SetVisible(true);
- chevron_size = chevron_->GetPreferredSize();
- max_x -= chevron_size.width();
- chevron_->SetBounds(width() - chevron_size.width() - kChevronRightMargin,
- kChevronTopMargin,
- chevron_size.width(), chevron_size.height());
+ gfx::Size chevron_size(chevron_->GetPreferredSize());
+ max_x -=
+ ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing;
+ chevron_->SetBounds(
+ width() - ToolbarView::kStandardSpacing - chevron_size.width(),
+ ToolbarView::kVertSpacing, chevron_size.width(), chevron_size.height());
} else {
chevron_->SetVisible(false);
}
// Now draw the icons for the browser actions in the available space.
+ int icon_width = IconWidth(false);
for (size_t i = 0; i < browser_action_views_.size(); ++i) {
BrowserActionView* view = browser_action_views_[i];
- // Add padding between buttons if multiple buttons.
- int padding = (i > 0) ? kBrowserActionButtonPadding : 0;
- if (x + kButtonSize + padding < max_x) {
- x += padding;
- view->SetBounds(x, 0, kButtonSize, height());
+ int x = ToolbarView::kStandardSpacing + (i * IconWidth(true));
+ if (x + icon_width <= max_x) {
+ view->SetBounds(x, 0, icon_width, height());
view->SetVisible(true);
- x += kButtonSize;
} else {
view->SetVisible(false);
}
@@ -675,25 +566,17 @@ void BrowserActionsContainer::Layout() {
}
void BrowserActionsContainer::Paint(gfx::Canvas* canvas) {
- // The one-pixel themed vertical divider to the right of the browser actions.
- int x = base::i18n::IsRTL() ?
- kDividerHorizontalMargin : (width() - kDividerHorizontalMargin);
- DetachableToolbarView::PaintVerticalDivider(
- canvas, x, height(), kDividerVerticalPadding,
- DetachableToolbarView::kEdgeDividerColor,
- DetachableToolbarView::kMiddleDividerColor,
- GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR));
-
- // The two-pixel width drop indicator.
+ // TODO(sky/glen): Instead of using a drop indicator, animate the icons while
+ // dragging (like we do for tab dragging).
if (drop_indicator_position_ > -1) {
- x = drop_indicator_position_;
- int y = kDividerVerticalPadding;
- gfx::Rect indicator_bounds(x - kDropIndicatorWidth / 2,
- y,
- kDropIndicatorWidth,
- height() - (2 * kDividerVerticalPadding));
-
- // TODO(sky/glen): make me pretty!
+ // The two-pixel width drop indicator.
+ static const int kDropIndicatorWidth = 2;
+ gfx::Rect indicator_bounds(
+ drop_indicator_position_ - (kDropIndicatorWidth / 2),
+ ToolbarView::kVertSpacing, kDropIndicatorWidth, IconHeight());
+
+ // Color of the drop indicator.
+ static const SkColor kDropIndicatorColor = SK_ColorBLACK;
canvas->FillRectInt(kDropIndicatorColor, indicator_bounds.x(),
indicator_bounds.y(), indicator_bounds.width(),
indicator_bounds.height());
@@ -717,7 +600,8 @@ void BrowserActionsContainer::ViewHierarchyChanged(bool is_add,
}
bool BrowserActionsContainer::GetDropFormats(
- int* formats, std::set<OSExchangeData::CustomFormat>* custom_formats) {
+ int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats) {
custom_formats->insert(BrowserActionDragData::GetBrowserActionCustomFormat());
return true;
@@ -729,9 +613,7 @@ bool BrowserActionsContainer::AreDropTypesRequired() {
bool BrowserActionsContainer::CanDrop(const OSExchangeData& data) {
BrowserActionDragData drop_data;
- if (!drop_data.Read(data))
- return false;
- return drop_data.IsFromProfile(profile_);
+ return drop_data.Read(data) ? drop_data.IsFromProfile(profile_) : false;
}
void BrowserActionsContainer::OnDragEntered(
@@ -745,34 +627,55 @@ int BrowserActionsContainer::OnDragUpdated(
if (show_menu_task_factory_.empty() && !overflow_menu_)
StartShowFolderDropMenuTimer();
return DragDropTypes::DRAG_MOVE;
- } else {
- StopShowFolderDropMenuTimer();
}
+ StopShowFolderDropMenuTimer();
- // Modifying the x value before clamping affects how far you have to drag to
- // get the drop indicator to shift to another position. Modifying after
- // clamping affects where the drop indicator is drawn.
-
- // We add half a button size so that when you drag a button to the right and
- // you are half-way dragging across a button the drop indicator moves from the
- // left of that button to the right of that button.
- int x = event.x() + (kButtonSize / 2) + (2 * kBrowserActionButtonPadding);
- if (chevron_->IsVisible())
- x += chevron_->bounds().width();
- x = ClampToNearestIconCount(x, false);
-
- if (!base::i18n::IsRTL() && chevron_->IsVisible()) {
- // The clamping function includes the chevron width. In LTR locales, the
- // chevron is on the right and we never want to account for its width. In
- // RTL it is on the left and we always want to count the width.
- x -= chevron_->width();
- }
+ // Figure out where to display the indicator. This is a complex calculation:
+
+ // First, we figure out how much space is to the left of the icon area, so we
+ // can calculate the true offset into the icon area.
+ int width_before_icons = ToolbarView::kStandardSpacing +
+ (base::i18n::IsRTL() ?
+ (chevron_->GetPreferredSize().width() + kChevronSpacing) : 0);
+ int offset_into_icon_area = event.x() - width_before_icons;
+
+ // Next, we determine which icon to place the indicator in front of. We want
+ // to place the indicator in front of icon n when the cursor is between the
+ // midpoints of icons (n - 1) and n. To do this we take the offset into the
+ // icon area and transform it as follows:
+ //
+ // Real icon area:
+ // 0 a * b c
+ // | | | |
+ // |[IC|ON] [IC|ON] [IC|ON]
+ // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc.
+ // Here the "*" represents the offset into the icon area, and since it's
+ // between a and b, we want to return "1".
+ //
+ // Transformed "icon area":
+ // 0 a * b c
+ // | | | |
+ // |[ICON] |[ICON] |[ICON] |
+ // If we shift both our offset and our divider points later by half an icon
+ // plus one spacing unit, then it becomes very easy to calculate how many
+ // divider points we've passed, because they're the multiples of "one icon
+ // plus padding".
+ int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) +
+ kItemSpacing) / IconWidth(true);
+
+ // Because the user can drag outside the container bounds, we need to clamp to
+ // the valid range. Note that the maximum allowable value is (num icons), not
+ // (num icons - 1), because we represent the indicator being past the last
+ // icon as being "before the (last + 1) icon".
+ int before_icon = std::min(std::max(before_icon_unclamped, 0),
+ static_cast<int>(VisibleBrowserActions()));
+
+ // Now we convert back to a pixel offset into the container. We want to place
+ // the center of the drop indicator at the midpoint of the space before our
+ // chosen icon.
+ SetDropIndicator(width_before_icons + (before_icon * IconWidth(true)) -
+ (kItemSpacing / 2));
- // Clamping gives us a value where the next button will be drawn, but we want
- // to subtract the padding (and then some) to make it appear in-between the
- // buttons.
- SetDropIndicator(x - kBrowserActionButtonPadding - (base::i18n::IsRTL() ?
- kDropIndicatorOffsetRtl : kDropIndicatorOffsetLtr));
return DragDropTypes::DRAG_MOVE;
}
@@ -789,21 +692,17 @@ int BrowserActionsContainer::OnPerformDrop(
return DragDropTypes::DRAG_NONE;
// Make sure we have the same view as we started with.
- DCHECK(browser_action_views_[data.index()]->button()->extension()->id() ==
- data.id());
+ DCHECK_EQ(browser_action_views_[data.index()]->button()->extension()->id(),
+ data.id());
DCHECK(model_);
- Extension* dragging =
- browser_action_views_[data.index()]->button()->extension();
-
- int target_x = drop_indicator_position_;
-
size_t i = 0;
for (; i < browser_action_views_.size(); ++i) {
int view_x =
browser_action_views_[i]->GetBounds(APPLY_MIRRORING_TRANSFORMATION).x();
if (!browser_action_views_[i]->IsVisible() ||
- (base::i18n::IsRTL() ? view_x < target_x : view_x >= target_x)) {
+ (base::i18n::IsRTL() ? (view_x < drop_indicator_position_) :
+ (view_x >= drop_indicator_position_))) {
// We have reached the end of the visible icons or found one that has a
// higher x position than the drop point.
break;
@@ -821,27 +720,19 @@ int BrowserActionsContainer::OnPerformDrop(
if (profile_->IsOffTheRecord())
i = model_->IncognitoIndexToOriginal(i);
- model_->MoveBrowserAction(dragging, i);
+ model_->MoveBrowserAction(
+ browser_action_views_[data.index()]->button()->extension(), i);
OnDragExited(); // Perform clean up after dragging.
return DragDropTypes::DRAG_MOVE;
}
-bool BrowserActionsContainer::GetAccessibleRole(
- AccessibilityTypes::Role* role) {
- DCHECK(role);
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+void BrowserActionsContainer::OnThemeChanged() {
+ LoadImages();
}
-void BrowserActionsContainer::MoveBrowserAction(
- const std::string& extension_id, size_t new_index) {
- ExtensionsService* service = profile_->GetExtensionsService();
- if (service) {
- Extension* extension = service->GetExtensionById(extension_id, false);
- model_->MoveBrowserAction(extension, new_index);
- SchedulePaint();
- }
+AccessibilityTypes::Role BrowserActionsContainer::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) {
@@ -887,41 +778,106 @@ bool BrowserActionsContainer::CanStartDrag(View* sender,
return true;
}
-int BrowserActionsContainer::ClampToNearestIconCount(
- int pixelWidth, bool allow_shrink_to_minimum) const {
- // Calculate the width of one icon.
- int icon_width = (kButtonSize + kBrowserActionButtonPadding);
+void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) {
+ if (!done_resizing) {
+ resize_amount_ = resize_amount;
+ OnBrowserActionVisibilityChanged();
+ return;
+ }
+
+ // Up until now we've only been modifying the resize_amount, but now it is
+ // time to set the container size to the size we have resized to, and then
+ // animate to the nearest icon count size if necessary (which may be 0).
+ int max_width = IconCountToWidth(-1, false);
+ container_width_ =
+ std::min(std::max(0, container_width_ - resize_amount), max_width);
+ SaveDesiredSizeAndAnimate(Tween::EASE_OUT,
+ WidthToIconCount(container_width_));
+}
- // Calculate pixel count for the area not used by the icons.
- int extras = WidthOfNonIconArea();
+void BrowserActionsContainer::AnimationProgressed(const Animation* animation) {
+ DCHECK_EQ(resize_animation_.get(), animation);
+ resize_amount_ = static_cast<int>(resize_animation_->GetCurrentValue() *
+ (container_width_ - animation_target_size_));
+ OnBrowserActionVisibilityChanged();
+}
- size_t icon_count = 0u;
- if (pixelWidth >= 0) {
- // Caller wants to know how many icons fit within a given space so we start
- // by subtracting the padding, gripper and dividers.
- int icon_area = pixelWidth - extras;
- icon_area = std::max(0, icon_area);
+void BrowserActionsContainer::AnimationEnded(const Animation* animation) {
+ container_width_ = animation_target_size_;
+ animation_target_size_ = 0;
+ resize_amount_ = 0;
+ OnBrowserActionVisibilityChanged();
+ suppress_chevron_ = false;
+}
- // Make sure we never throw an icon into the chevron menu just because
- // there isn't enough enough space for the invisible padding around buttons.
- icon_area += kBrowserActionButtonPadding - 1;
+void BrowserActionsContainer::NotifyMenuDeleted(
+ BrowserActionOverflowMenuController* controller) {
+ DCHECK(controller == overflow_menu_);
+ overflow_menu_ = NULL;
+}
- // Count the number of icons that fit within that area.
- icon_count = icon_area / icon_width;
+void BrowserActionsContainer::InspectPopup(ExtensionAction* action) {
+ OnBrowserActionExecuted(GetBrowserActionView(action)->button(), true);
+}
- if (icon_count == 0 && allow_shrink_to_minimum) {
- extras = ContainerMinSize(); // Allow very narrow width if no icons.
- } else if (icon_count > browser_action_views_.size()) {
- // No use allowing more than what we have.
- icon_count = browser_action_views_.size();
- }
- } else {
- // A negative |pixels| count indicates caller wants to know the max width
- // that fits all icons;
- icon_count = browser_action_views_.size();
+void BrowserActionsContainer::ExtensionPopupIsClosing(ExtensionPopup* popup) {
+ // ExtensionPopup is ref-counted, so we don't need to delete it.
+ DCHECK_EQ(popup_, popup);
+ popup_ = NULL;
+ popup_button_->SetButtonNotPushed();
+ popup_button_ = NULL;
+}
+
+void BrowserActionsContainer::MoveBrowserAction(const std::string& extension_id,
+ size_t new_index) {
+ ExtensionsService* service = profile_->GetExtensionsService();
+ if (service) {
+ Extension* extension = service->GetExtensionById(extension_id, false);
+ model_->MoveBrowserAction(extension, new_index);
+ SchedulePaint();
+ }
+}
+
+void BrowserActionsContainer::HidePopup() {
+ if (popup_)
+ popup_->Close();
+}
+
+void BrowserActionsContainer::TestExecuteBrowserAction(int index) {
+ BrowserActionButton* button = browser_action_views_[index]->button();
+ OnBrowserActionExecuted(button, false);
+}
+
+void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
+ model_->SetVisibleIconCount(icons);
+ chevron_->SetVisible(icons < browser_action_views_.size());
+ container_width_ = IconCountToWidth(icons, chevron_->IsVisible());
+ Layout();
+ SchedulePaint();
+}
+
+// static
+int BrowserActionsContainer::IconWidth(bool include_padding) {
+ static bool initialized = false;
+ static int icon_width = 0;
+ if (!initialized) {
+ initialized = true;
+ icon_width = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_BROWSER_ACTION)->width();
}
+ return icon_width + (include_padding ? kItemSpacing : 0);
+}
- return extras + (icon_count * icon_width);
+// static
+int BrowserActionsContainer::IconHeight() {
+ static bool initialized = false;
+ static int icon_height = 0;
+ if (!initialized) {
+ initialized = true;
+ icon_height = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_BROWSER_ACTION)->height();
+ }
+ return icon_height;
}
void BrowserActionsContainer::BrowserActionAdded(Extension* extension,
@@ -938,13 +894,11 @@ void BrowserActionsContainer::BrowserActionAdded(Extension* extension,
if (!ShouldDisplayBrowserAction(extension))
return;
- if (profile_->IsOffTheRecord())
- index = model_->OriginalIndexToIncognito(index);
-
- // Before we change anything, determine the number of visible browser actions.
size_t visible_actions = VisibleBrowserActions();
// Add the new browser action to the vector and the view hierarchy.
+ if (profile_->IsOffTheRecord())
+ index = model_->OriginalIndexToIncognito(index);
BrowserActionView* view = new BrowserActionView(extension, this);
browser_action_views_.insert(browser_action_views_.begin() + index, view);
AddChildView(index, view);
@@ -953,23 +907,14 @@ void BrowserActionsContainer::BrowserActionAdded(Extension* extension,
if (!model_->extensions_initialized())
return;
- // For details on why we do the following see the class comments in the
- // header.
-
- // Determine if we need to increase (we only do that if the container was
- // showing all icons before the addition of this icon).
- if (model_->GetVisibleIconCount() >= 0 || extension->being_upgraded()) {
- // Some icons were hidden, don't increase the size of the container.
- OnBrowserActionVisibilityChanged();
+ // Enlarge the container if it was already at maximum size and we're not in
+ // the middle of upgrading.
+ if ((model_->GetVisibleIconCount() < 0) && !extension->being_upgraded()) {
+ suppress_chevron_ = true;
+ SaveDesiredSizeAndAnimate(Tween::LINEAR, visible_actions + 1);
} else {
- // Container was at max, increase the size of it by one icon.
- int target_size = IconCountToWidth(visible_actions + 1);
-
- // We don't want the chevron to appear while we animate. See documentation
- // in the header for why we do this.
- suppress_chevron_ = !chevron_->IsVisible();
-
- Animate(Tween::LINEAR, target_size);
+ // Just redraw the (possibly modified) visible icon set.
+ OnBrowserActionVisibilityChanged();
}
}
@@ -979,13 +924,9 @@ void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) {
if (popup_ && popup_->host()->extension() == extension)
HidePopup();
- // Before we change anything, determine the number of visible browser
- // actions.
size_t visible_actions = VisibleBrowserActions();
-
- for (BrowserActionViews::iterator iter =
- browser_action_views_.begin(); iter != browser_action_views_.end();
- ++iter) {
+ for (BrowserActionViews::iterator iter = browser_action_views_.begin();
+ iter != browser_action_views_.end(); ++iter) {
if ((*iter)->button()->extension() == extension) {
RemoveChildView(*iter);
delete *iter;
@@ -996,18 +937,19 @@ void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) {
if (extension->being_upgraded())
return;
- // For details on why we do the following see the class comments in the
- // header.
-
- // Calculate the target size we'll animate to (end state). This might be
- // the same size (if the icon we are removing is in the overflow bucket
- // and there are other icons there). We don't decrement visible_actions
- // because we want the container to stay the same size (clamping will take
- // care of shrinking the container if there aren't enough icons to show).
- int target_size =
- ClampToNearestIconCount(IconCountToWidth(visible_actions), true);
-
- Animate(Tween::EASE_OUT, target_size);
+ if (browser_action_views_.size() > visible_actions) {
+ // If we have more icons than we can show, then we must not be changing
+ // the container size (since we either removed an icon from the main
+ // area and one from the overflow list will have shifted in, or we
+ // removed an entry directly from the overflow list).
+ OnBrowserActionVisibilityChanged();
+ } else {
+ // Either we went from overflow to no-overflow, or we shrunk the no-
+ // overflow container by 1. Either way the size changed, so animate.
+ chevron_->SetVisible(false);
+ SaveDesiredSizeAndAnimate(Tween::EASE_OUT,
+ browser_action_views_.size());
+ }
return;
}
}
@@ -1033,39 +975,103 @@ void BrowserActionsContainer::ModelLoaded() {
SetContainerWidth();
}
+void BrowserActionsContainer::LoadImages() {
+ ThemeProvider* tp = GetThemeProvider();
+ chevron_->SetIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW));
+ chevron_->SetHoverIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_H));
+ chevron_->SetPushedIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_P));
+}
+
void BrowserActionsContainer::SetContainerWidth() {
int visible_actions = model_->GetVisibleIconCount();
if (visible_actions < 0) // All icons should be visible.
visible_actions = model_->size();
- else
- chevron_->SetVisible(true);
- container_size_ = gfx::Size(IconCountToWidth(visible_actions), kButtonSize);
+ chevron_->SetVisible(static_cast<size_t>(visible_actions) < model_->size());
+ container_width_ = IconCountToWidth(visible_actions, chevron_->IsVisible());
+}
+
+void BrowserActionsContainer::CloseOverflowMenu() {
+ if (overflow_menu_)
+ overflow_menu_->CancelMenu();
+}
+
+void BrowserActionsContainer::StopShowFolderDropMenuTimer() {
+ show_menu_task_factory_.RevokeAll();
}
-int BrowserActionsContainer::WidthOfNonIconArea() const {
- int chevron_size = (chevron_->IsVisible()) ?
- chevron_->GetPreferredSize().width() : 0;
- int padding = base::i18n::IsRTL() ?
- kHorizontalPaddingRtl : kHorizontalPadding;
- return resize_gripper_->GetPreferredSize().width() + padding +
- chevron_size + kChevronRightMargin + kDividerHorizontalMargin;
+void BrowserActionsContainer::StartShowFolderDropMenuTimer() {
+ int delay = View::GetMenuShowDelay();
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ show_menu_task_factory_.NewRunnableMethod(
+ &BrowserActionsContainer::ShowDropFolder),
+ delay);
}
-int BrowserActionsContainer::IconCountToWidth(int icons) const {
- DCHECK_GE(icons, 0);
- if (icons == 0)
- return ContainerMinSize();
+void BrowserActionsContainer::ShowDropFolder() {
+ DCHECK(!overflow_menu_);
+ SetDropIndicator(-1);
+ overflow_menu_ = new BrowserActionOverflowMenuController(
+ this, chevron_, browser_action_views_, VisibleBrowserActions());
+ overflow_menu_->set_observer(this);
+ overflow_menu_->RunMenu(GetWindow()->GetNativeWindow(), true);
+}
- int icon_width = kButtonSize + kBrowserActionButtonPadding;
+void BrowserActionsContainer::SetDropIndicator(int x_pos) {
+ if (drop_indicator_position_ != x_pos) {
+ drop_indicator_position_ = x_pos;
+ SchedulePaint();
+ }
+}
- return WidthOfNonIconArea() + (icons * icon_width);
+int BrowserActionsContainer::IconCountToWidth(int icons,
+ bool display_chevron) const {
+ if (icons < 0)
+ icons = browser_action_views_.size();
+ if ((icons == 0) && !display_chevron)
+ return ToolbarView::kStandardSpacing;
+ int icons_size =
+ (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing);
+ int chevron_size = display_chevron ?
+ (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0;
+ return ToolbarView::kStandardSpacing + icons_size + chevron_size +
+ ToolbarView::kStandardSpacing;
+}
+
+size_t BrowserActionsContainer::WidthToIconCount(int pixels) const {
+ // Check for widths large enough to show the entire icon set.
+ if (pixels >= IconCountToWidth(-1, false))
+ return browser_action_views_.size();
+
+ // We need to reserve space for the resize area, chevron, and the spacing on
+ // either side of the chevron.
+ int available_space = pixels - ToolbarView::kStandardSpacing -
+ chevron_->GetPreferredSize().width() - kChevronSpacing -
+ ToolbarView::kStandardSpacing;
+ // Now we add an extra between-item padding value so the space can be divided
+ // evenly by (size of icon with padding).
+ return static_cast<size_t>(
+ std::max(0, available_space + kItemSpacing) / IconWidth(true));
}
int BrowserActionsContainer::ContainerMinSize() const {
- return resize_gripper_->width() + chevron_->width() + kChevronRightMargin;
-}
+ return ToolbarView::kStandardSpacing + kChevronSpacing +
+ chevron_->GetPreferredSize().width() + ToolbarView::kStandardSpacing;
+}
+
+void BrowserActionsContainer::SaveDesiredSizeAndAnimate(
+ Tween::Type tween_type,
+ size_t num_visible_icons) {
+ // Save off the desired number of visible icons. We do this now instead of at
+ // the end of the animation so that even if the browser is shut down while
+ // animating, the right value will be restored on next run.
+ // NOTE: Don't save the icon count in incognito because there may be fewer
+ // icons in that mode. The result is that the container in a normal window is
+ // always at least as wide as in an incognito window.
+ if (!profile_->IsOffTheRecord())
+ model_->SetVisibleIconCount(num_visible_icons);
-void BrowserActionsContainer::Animate(Tween::Type tween_type, int target_size) {
+ int target_size = IconCountToWidth(num_visible_icons,
+ num_visible_icons < browser_action_views_.size());
if (!disable_animations_during_testing_) {
// Animate! We have to set the animation_target_size_ after calling Reset(),
// because that could end up calling AnimationEnded which clears the value.
@@ -1079,86 +1085,6 @@ void BrowserActionsContainer::Animate(Tween::Type tween_type, int target_size) {
}
}
-size_t BrowserActionsContainer::VisibleBrowserActions() const {
- size_t visible_actions = 0;
- for (size_t i = 0; i < browser_action_views_.size(); ++i) {
- if (browser_action_views_[i]->IsVisible())
- ++visible_actions;
- }
-
- return visible_actions;
-}
-
-void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) {
- if (!done_resizing) {
- resize_amount_ = resize_amount;
- OnBrowserActionVisibilityChanged();
- } else {
- // For details on why we do the following see the class comments in the
- // header.
-
- // Clamp lower limit to 0 and upper limit to the amount that allows enough
- // room for all icons to show.
- int new_width = std::max(0, container_size_.width() - resize_amount);
- int max_width = ClampToNearestIconCount(-1, false);
- new_width = std::min(new_width, max_width);
-
- // Up until now we've only been modifying the resize_amount, but now it is
- // time to set the container size to the size we have resized to, but then
- // animate to the nearest icon count size (or down to min size if no icon).
- container_size_.set_width(new_width);
- animation_target_size_ = ClampToNearestIconCount(new_width, true);
- resize_animation_->Reset();
- resize_animation_->SetTweenType(Tween::EASE_OUT);
- resize_animation_->Show();
- }
-}
-
-void BrowserActionsContainer::AnimationProgressed(const Animation* animation) {
- DCHECK(animation == resize_animation_.get());
-
- double e = resize_animation_->GetCurrentValue();
- int difference = container_size_.width() - animation_target_size_;
-
- resize_amount_ = static_cast<int>(e * difference);
-
- OnBrowserActionVisibilityChanged();
-}
-
-void BrowserActionsContainer::AnimationEnded(const Animation* animation) {
- container_size_.set_width(animation_target_size_);
- animation_target_size_ = 0;
- resize_amount_ = 0;
- OnBrowserActionVisibilityChanged();
- suppress_chevron_ = false;
-
- // Don't save the icon count in incognito because there may be fewer icons
- // in that mode. The result is that the container in a normal window is always
- // at least as wide as in an incognito window.
- if (!profile_->IsOffTheRecord())
- model_->SetVisibleIconCount(VisibleBrowserActions());
-}
-
-void BrowserActionsContainer::NotifyMenuDeleted(
- BrowserActionOverflowMenuController* controller) {
- DCHECK(controller == overflow_menu_);
- overflow_menu_ = NULL;
-}
-
-void BrowserActionsContainer::InspectPopup(
- ExtensionAction* action) {
- OnBrowserActionExecuted(GetBrowserActionView(action)->button(),
- true); // |inspect_with_devtools|.
-}
-
-void BrowserActionsContainer::ExtensionPopupIsClosing(ExtensionPopup* popup) {
- // ExtensionPopup is ref-counted, so we don't need to delete it.
- DCHECK_EQ(popup_, popup);
- popup_ = NULL;
- popup_button_->SetButtonNotPushed();
- popup_button_ = NULL;
-}
-
bool BrowserActionsContainer::ShouldDisplayBrowserAction(Extension* extension) {
// Only display incognito-enabled extensions while in incognito mode.
return (!profile_->IsOffTheRecord() ||
diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h
index 8fb070d..ddef35d 100644
--- a/chrome/browser/views/browser_actions_container.h
+++ b/chrome/browser/views/browser_actions_container.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BROWSER_ACTIONS_CONTAINER_H_
#define CHROME_BROWSER_VIEWS_BROWSER_ACTIONS_CONTAINER_H_
+#pragma once
#include <set>
#include <string>
@@ -21,7 +22,7 @@
#include "chrome/common/notification_registrar.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/menu/view_menu_delegate.h"
-#include "views/controls/resize_gripper.h"
+#include "views/controls/resize_area.h"
#include "views/view.h"
class Browser;
@@ -67,10 +68,6 @@ class BrowserActionButton : public views::MenuButton,
// Returns the default icon, if any.
const SkBitmap& default_icon() const { return default_icon_; }
- // Overridden from views::View. Return a 0-inset so the icon can draw all the
- // way to the edge of the view if it wants.
- virtual gfx::Insets GetInsets() const;
-
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
@@ -157,7 +154,7 @@ class BrowserActionView : public views::View {
gfx::Canvas* GetIconWithBadge();
// Accessibility accessors, overridden from View.
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
private:
virtual void Layout();
@@ -179,32 +176,32 @@ class BrowserActionView : public views::View {
// The BrowserActionsContainer is a container view, responsible for drawing the
// browser action icons (extensions that add icons to the toolbar).
//
-// The BrowserActionsContainer (when it contains one or more icons) consists of
-// the following elements, numbered as seen below the line:
-//
-// || _ Icon _ Icon _ Icon _ [chevron] _ | _
-// -----------------------------------------
-// 1 2 3 4 5 6 7 8
-//
-// 1) The ResizeGripper view.
-// 2) Padding (kHorizontalPadding).
-// 3) The browser action icon button (BrowserActionView).
-// 4) Padding to visually separate icons from one another
-// (kBrowserActionButtonPadding). Not included if only one icon visible.
-// 5) The chevron menu (MenuButton), shown when there is not enough room to show
-// all the icons.
-// 6) Padding (kDividerHorizontalMargin).
-// 7) A thin vertical divider drawn during Paint to create visual separation for
-// the container from the Page and Wrench menus.
-// 8) Padding (kChevronRightMargin).
+// The container is placed flush against the omnibox and wrench menu, and its
+// layout looks like:
+// rI_I_IcCs
+// Where the letters are as follows:
+// r: An invisible resize area. This is ToolbarView::kStandardSpacing pixels
+// wide and directly adjacent to the omnibox.
+// I: An icon. This is as wide as the IDR_BROWSER_ACTION image.
+// _: kItemSpacing pixels of empty space.
+// c: kChevronSpacing pixels of empty space. Only present if C is present.
+// C: An optional chevron, visible for overflow. As wide as the
+// IDR_BROWSER_ACTIONS_OVERFLOW image.
+// s: ToolbarView::kStandardSpacing pixels of empty space (before the wrench
+// menu).
+// The reason the container contains the trailing space "s", rather than having
+// it be handled by the parent view, is so that when the chevron is invisible
+// and the user starts dragging an icon around, we have the space to draw the
+// ultimate drop indicator. (Otherwise, we'd be trying to draw it into the
+// padding beyond our right edge, and it wouldn't appear.)
//
// The BrowserActionsContainer follows a few rules, in terms of user experience:
//
// 1) The container can never grow beyond the space needed to show all icons
// (hereby referred to as the max width).
// 2) The container can never shrink below the space needed to show just the
-// resize gripper and the chevron (ignoring the case where there are no icons to
-// show, in which case the container won't be visible anyway).
+// initial padding and the chevron (ignoring the case where there are no icons
+// to show, in which case the container won't be visible anyway).
// 3) The container snaps into place (to the pixel count that fits the visible
// icons) to make sure there is no wasted space at the edges of the container.
// 4) If the user adds or removes icons (read: installs/uninstalls browser
@@ -218,12 +215,11 @@ class BrowserActionView : public views::View {
//
// Resizing the BrowserActionsContainer:
//
-// The ResizeGripper view sends OnResize messages to the BrowserActionsContainer
-// class as the user drags the gripper. This modifies the value for
-// |resize_amount_|. That indicates to the container that a resize is in
-// progress and is used to calculate the size in GetPreferredSize(), though
-// that function never exceeds the defined minimum and maximum size of the
-// container.
+// The ResizeArea view sends OnResize messages to the BrowserActionsContainer
+// class as the user drags it. This modifies the value for |resize_amount_|.
+// That indicates to the container that a resize is in progress and is used to
+// calculate the size in GetPreferredSize(), though that function never exceeds
+// the defined minimum and maximum size of the container.
//
// When the user releases the mouse (ends the resize), we calculate a target
// size for the container (animation_target_size_), clamp that value to the
@@ -236,9 +232,9 @@ class BrowserActionView : public views::View {
// visible icons. This can be triggered when the user finishes resizing the
// container or when Browser Actions are added/removed.
//
-// We always animate from the current width (container_size_.width()) to the
-// target size (animation_target_size_), using |resize_amount| to keep track of
-// the animation progress.
+// We always animate from the current width (container_width_) to the target
+// size (animation_target_size_), using |resize_amount| to keep track of the
+// animation progress.
//
// NOTE: When adding Browser Actions to a maximum width container (no overflow)
// we make sure to suppress the chevron menu if it wasn't visible. This is
@@ -248,21 +244,23 @@ class BrowserActionView : public views::View {
//
////////////////////////////////////////////////////////////////////////////////
class BrowserActionsContainer
- : public views::View,
- public views::ViewMenuDelegate,
- public views::DragController,
- public views::ResizeGripper::ResizeGripperDelegate,
- public AnimationDelegate,
- public ExtensionToolbarModel::Observer,
- public BrowserActionOverflowMenuController::Observer,
- public ExtensionContextMenuModel::PopupDelegate,
- public ExtensionPopup::Observer {
+ : public views::View,
+ public views::ViewMenuDelegate,
+ public views::DragController,
+ public views::ResizeArea::ResizeAreaDelegate,
+ public AnimationDelegate,
+ public ExtensionToolbarModel::Observer,
+ public BrowserActionOverflowMenuController::Observer,
+ public ExtensionContextMenuModel::PopupDelegate,
+ public ExtensionPopup::Observer {
public:
BrowserActionsContainer(Browser* browser, views::View* owner_view);
virtual ~BrowserActionsContainer();
static void RegisterUserPrefs(PrefService* prefs);
+ void Init();
+
// Get the number of browser actions being displayed.
int num_browser_actions() const { return browser_action_views_.size(); }
@@ -323,7 +321,8 @@ class BrowserActionsContainer
virtual int OnDragUpdated(const views::DropTargetEvent& event);
virtual void OnDragExited();
virtual int OnPerformDrop(const views::DropTargetEvent& event);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual void OnThemeChanged();
+ virtual AccessibilityTypes::Role GetAccessibleRole();
// Overridden from views::ViewMenuDelegate:
virtual void RunMenu(View* source, const gfx::Point& pt);
@@ -337,7 +336,7 @@ class BrowserActionsContainer
const gfx::Point& press_pt,
const gfx::Point& p);
- // Overridden from ResizeGripper::ResizeGripperDelegate:
+ // Overridden from ResizeArea::ResizeAreaDelegate:
virtual void OnResize(int resize_amount, bool done_resizing);
// Overridden from AnimationDelegate:
@@ -377,16 +376,25 @@ class BrowserActionsContainer
static bool disable_animations_during_testing_;
private:
+ friend class BrowserActionView; // So it can access IconHeight().
friend class ShowFolderMenuTask;
typedef std::vector<BrowserActionView*> BrowserActionViews;
+ // Returns the width of an icon, optionally with its padding.
+ static int IconWidth(bool include_padding);
+
+ // Returns the height of an icon.
+ static int IconHeight();
+
// ExtensionToolbarModel::Observer implementation.
virtual void BrowserActionAdded(Extension* extension, int index);
virtual void BrowserActionRemoved(Extension* extension);
virtual void BrowserActionMoved(Extension* extension, int index);
virtual void ModelLoaded();
+ void LoadImages();
+
// Sets the initial container width.
void SetContainerWidth();
@@ -406,31 +414,26 @@ class BrowserActionsContainer
// changed).
void SetDropIndicator(int x_pos);
- // Takes a width in pixels, calculates how many icons fit within that space
- // (up to the maximum number of icons in our vector) and shaves off the
- // excess pixels. |allow_shrink_to_minimum| specifies whether this function
- // clamps the size down further (down to ContainerMinSize()) if there is not
- // room for even one icon. When determining how large the container should be
- // this should be |true|. When determining where to place items, such as the
- // drop indicator, this should be |false|.
- int ClampToNearestIconCount(int pixels, bool allow_shrink_to_minimum) const;
-
- // Calculates the width of the container area NOT used to show the icons (the
- // controls to the left and to the right of the icons).
- int WidthOfNonIconArea() const;
+ // Given a number of |icons| and whether to |display_chevron|, returns the
+ // amount of pixels needed to draw the entire container. For convenience,
+ // callers can set |icons| to -1 to mean "all icons".
+ int IconCountToWidth(int icons, bool display_chevron) const;
- // Given a number of |icons| return the amount of pixels needed to draw it,
- // including the controls (chevron if visible and resize gripper).
- int IconCountToWidth(int icons) const;
+ // Given a pixel width, returns the number of icons that fit. (This
+ // automatically determines whether a chevron will be needed and includes it
+ // in the calculation.)
+ size_t WidthToIconCount(int pixels) const;
// Returns the absolute minimum size you can shrink the container down to and
- // still show it. We account for the chevron and the resize gripper, but not
- // all the padding that we normally show if there are icons.
+ // still show it. This assumes a visible chevron because the only way we
+ // would not have a chevron when shrinking down this far is if there were no
+ // icons, in which case the container wouldn't be shown at all.
int ContainerMinSize() const;
- // Animate to the target value (unless testing, in which case we go straight
- // to the target size).
- void Animate(Tween::Type type, int target_size);
+ // Animate to the target size (unless testing, in which case we go straight to
+ // the target size). This also saves the target number of visible icons in
+ // the pref if we're not off the record.
+ void SaveDesiredSizeAndAnimate(Tween::Type type, size_t num_visible_icons);
// Returns true if this extension should be shown in this toolbar. This can
// return false if we are in an incognito window and the extension is disabled
@@ -460,11 +463,11 @@ class BrowserActionsContainer
// The model that tracks the order of the toolbar icons.
ExtensionToolbarModel* model_;
- // The current size of the container.
- gfx::Size container_size_;
+ // The current width of the container.
+ int container_width_;
- // The resize gripper for the container.
- views::ResizeGripper* resize_gripper_;
+ // The resize area for the container.
+ views::ResizeArea* resize_area_;
// The chevron for accessing the overflow items.
views::MenuButton* chevron_;
diff --git a/chrome/browser/views/browser_actions_container_browsertest.cc b/chrome/browser/views/browser_actions_container_browsertest.cc
index 9612314..dd9f9eb 100644
--- a/chrome/browser/views/browser_actions_container_browsertest.cc
+++ b/chrome/browser/views/browser_actions_container_browsertest.cc
@@ -62,7 +62,8 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Basic) {
}
// TODO(mpcomplete): http://code.google.com/p/chromium/issues/detail?id=38992
-IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) {
+// Disabled, http://crbug.com/38992.
+IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, DISABLED_Visibility) {
BrowserActionsContainer::disable_animations_during_testing_ = true;
// Load extension A (contains browser action).
@@ -83,7 +84,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) {
EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
std::string idB = browser_actions_bar()->GetExtensionId(1);
- EXPECT_STRNE(idA.c_str(), idB.c_str());
+ EXPECT_NE(idA, idB);
// Load extension C (contains browser action).
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
@@ -102,7 +103,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) {
DisableExtension(idA);
EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idB.c_str(), browser_actions_bar()->GetExtensionId(0).c_str());
+ EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
// Enable A again. A should get its spot in the same location and the bar
// should not grow (chevron is showing). For details: http://crbug.com/35349.
@@ -110,19 +111,19 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) {
EnableExtension(idA);
EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idA.c_str(), browser_actions_bar()->GetExtensionId(0).c_str());
+ EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
// Disable C (in overflow). State becomes: A, [B].
DisableExtension(idC);
EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idA.c_str(), browser_actions_bar()->GetExtensionId(0).c_str());
+ EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
// Enable C again. State becomes: A, [B, C].
EnableExtension(idC);
EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idA.c_str(), browser_actions_bar()->GetExtensionId(0).c_str());
+ EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
// Now we have 3 extensions. Make sure they are all visible. State: A, B, C.
browser_actions_bar()->SetIconVisibilityCount(3);
@@ -132,23 +133,23 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) {
DisableExtension(idA);
EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idB.c_str(), browser_actions_bar()->GetExtensionId(0).c_str());
+ EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
// Disable extension B (should disappear). State becomes: C.
DisableExtension(idB);
EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idC.c_str(), browser_actions_bar()->GetExtensionId(0).c_str());
+ EXPECT_EQ(idC, browser_actions_bar()->GetExtensionId(0));
// Enable B (makes B and C showing now). State becomes: B, C.
EnableExtension(idB);
EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idB.c_str(), browser_actions_bar()->GetExtensionId(0).c_str());
+ EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
// Enable A (makes A, B and C showing now). State becomes: B, C, A.
EnableExtension(idA);
EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
- EXPECT_STREQ(idA.c_str(), browser_actions_bar()->GetExtensionId(2).c_str());
+ EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(2));
}
diff --git a/chrome/browser/views/browser_bubble.cc b/chrome/browser/views/browser_bubble.cc
index c3d2268..a118852 100644
--- a/chrome/browser/views/browser_bubble.cc
+++ b/chrome/browser/views/browser_bubble.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/views/browser_bubble.h"
-#include "app/l10n_util.h"
#include "chrome/browser/views/frame/browser_view.h"
#if defined(OS_WIN)
#include "chrome/browser/external_tab_container_win.h"
diff --git a/chrome/browser/views/browser_bubble.h b/chrome/browser/views/browser_bubble.h
index 68feb99..790c677 100644
--- a/chrome/browser/views/browser_bubble.h
+++ b/chrome/browser/views/browser_bubble.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BROWSER_BUBBLE_H_
#define CHROME_BROWSER_VIEWS_BROWSER_BUBBLE_H_
+#pragma once
#include "views/view.h"
#include "views/widget/widget.h"
diff --git a/chrome/browser/views/browser_bubble_gtk.cc b/chrome/browser/views/browser_bubble_gtk.cc
index 3bbd61a..7f18070 100644
--- a/chrome/browser/views/browser_bubble_gtk.cc
+++ b/chrome/browser/views/browser_bubble_gtk.cc
@@ -19,8 +19,7 @@ class BubbleWidget : public views::WidgetGtk {
public:
explicit BubbleWidget(BrowserBubble* bubble)
: views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW),
- bubble_(bubble),
- closed_(false) {
+ bubble_(bubble) {
}
void Show(bool activate) {
@@ -29,19 +28,19 @@ class BubbleWidget : public views::WidgetGtk {
}
virtual void Close() {
- if (closed_)
- return;
- closed_ = true;
+ if (!bubble_)
+ return; // We have already been closed.
if (IsActive()) {
BrowserBubble::Delegate* delegate = bubble_->delegate();
if (delegate)
delegate->BubbleLostFocus(bubble_, false);
}
views::WidgetGtk::Close();
+ bubble_ = NULL;
}
virtual void Hide() {
- if (IsActive()) {
+ if (IsActive()&& bubble_) {
BrowserBubble::Delegate* delegate = bubble_->delegate();
if (delegate)
delegate->BubbleLostFocus(bubble_, false);
@@ -50,7 +49,7 @@ class BubbleWidget : public views::WidgetGtk {
}
virtual void IsActiveChanged() {
- if (IsActive() || closed_)
+ if (IsActive() || !bubble_)
return;
BrowserBubble::Delegate* delegate = bubble_->delegate();
if (!delegate) {
@@ -66,15 +65,13 @@ class BubbleWidget : public views::WidgetGtk {
}
virtual gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* event) {
- BrowserBubble::Delegate* delegate = bubble_->delegate();
- if (delegate)
- delegate->BubbleGotFocus(bubble_);
+ if (bubble_ && bubble_->delegate())
+ bubble_->delegate()->BubbleGotFocus(bubble_);
return views::WidgetGtk::OnFocusIn(widget, event);
}
private:
BrowserBubble* bubble_;
- bool closed_;
DISALLOW_COPY_AND_ASSIGN(BubbleWidget);
};
diff --git a/chrome/browser/views/browser_bubble_win.cc b/chrome/browser/views/browser_bubble_win.cc
index c9add4f..84985fd 100644
--- a/chrome/browser/views/browser_bubble_win.cc
+++ b/chrome/browser/views/browser_bubble_win.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/views/browser_bubble.h"
-#include "app/l10n_util_win.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_win.h"
@@ -13,8 +12,7 @@
class BubbleWidget : public views::WidgetWin {
public:
explicit BubbleWidget(BrowserBubble* bubble)
- : bubble_(bubble),
- closed_(false) {
+ : bubble_(bubble) {
set_window_style(WS_POPUP | WS_CLIPCHILDREN);
set_window_ex_style(WS_EX_TOOLWINDOW);
}
@@ -27,19 +25,19 @@ class BubbleWidget : public views::WidgetWin {
}
void Close() {
- if (closed_)
- return;
- closed_ = true;
+ if (!bubble_)
+ return; // We have already been closed.
if (IsActive()) {
BrowserBubble::Delegate* delegate = bubble_->delegate();
if (delegate)
delegate->BubbleLostFocus(bubble_, NULL);
}
views::WidgetWin::Close();
+ bubble_ = NULL;
}
void Hide() {
- if (IsActive()) {
+ if (IsActive() && bubble_) {
BrowserBubble::Delegate* delegate = bubble_->delegate();
if (delegate)
delegate->BubbleLostFocus(bubble_, NULL);
@@ -49,16 +47,19 @@ class BubbleWidget : public views::WidgetWin {
void OnActivate(UINT action, BOOL minimized, HWND window) {
WidgetWin::OnActivate(action, minimized, window);
+ if (!bubble_)
+ return;
+
BrowserBubble::Delegate* delegate = bubble_->delegate();
if (!delegate) {
- if (action == WA_INACTIVE && !closed_) {
+ if (action == WA_INACTIVE) {
bubble_->DetachFromBrowser();
delete bubble_;
}
return;
}
- if (action == WA_INACTIVE && !closed_) {
+ if (action == WA_INACTIVE) {
bool lost_focus_to_child = false;
// Are we a parent of this window?
@@ -82,14 +83,14 @@ class BubbleWidget : public views::WidgetWin {
virtual void OnSetFocus(HWND focused_window) {
WidgetWin::OnSetFocus(focused_window);
- BrowserBubble::Delegate* delegate = bubble_->delegate();
- if (delegate)
- delegate->BubbleGotFocus(bubble_);
+ if (bubble_ && bubble_->delegate())
+ bubble_->delegate()->BubbleGotFocus(bubble_);
}
private:
BrowserBubble* bubble_;
- bool closed_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleWidget);
};
void BrowserBubble::InitPopup() {
diff --git a/chrome/browser/views/browser_dialogs.h b/chrome/browser/views/browser_dialogs.h
index 2adac51..8affac9 100644
--- a/chrome/browser/views/browser_dialogs.h
+++ b/chrome/browser/views/browser_dialogs.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BROWSER_DIALOGS_H_
#define CHROME_BROWSER_VIEWS_BROWSER_DIALOGS_H_
+#pragma once
#include <string>
@@ -44,6 +45,9 @@ void ShowBugReportView(views::Window* parent,
Profile* profile,
TabContents* tab);
+// Shows the "Report a problem with this page" page in a new tab
+void ShowHtmlBugReportView(views::Window* parent, Browser* browser);
+
// Shows the "Clear browsing data" dialog box. See ClearBrowsingDataView.
void ShowClearBrowsingDataView(gfx::NativeWindow parent,
Profile* profile);
diff --git a/chrome/browser/views/browser_views_accessibility_browsertest.cc b/chrome/browser/views/browser_views_accessibility_browsertest.cc
index 49b824c..af33e2c 100644
--- a/chrome/browser/views/browser_views_accessibility_browsertest.cc
+++ b/chrome/browser/views/browser_views_accessibility_browsertest.cc
@@ -6,6 +6,7 @@
#include "app/l10n_util.h"
#include "base/scoped_comptr_win.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/view_ids.h"
diff --git a/chrome/browser/views/bubble_border.h b/chrome/browser/views/bubble_border.h
index b8c6ade..6d5191a 100644
--- a/chrome/browser/views/bubble_border.h
+++ b/chrome/browser/views/bubble_border.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_BUBBLE_BORDER_H_
#define CHROME_BROWSER_VIEWS_BUBBLE_BORDER_H_
+#pragma once
#include "third_party/skia/include/core/SkColor.h"
#include "views/background.h"
diff --git a/chrome/browser/views/bug_report_view.cc b/chrome/browser/views/bug_report_view.cc
deleted file mode 100644
index 03cbc76..0000000
--- a/chrome/browser/views/bug_report_view.cc
+++ /dev/null
@@ -1,627 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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/bug_report_view.h"
-
-#include <string>
-#include <vector>
-
-#include "app/combobox_model.h"
-#include "app/l10n_util.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/file_version_info.h"
-#include "base/path_service.h"
-#include "base/utf_string_conversions.h"
-#include "base/waitable_event.h"
-#include "chrome/browser/bug_report_util.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/safe_browsing/safe_browsing_util.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/common/chrome_paths.h"
-#include "chrome/common/chrome_version_info.h"
-#include "chrome/common/net/url_fetcher.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "net/base/escape.h"
-#include "unicode/locid.h"
-#include "views/controls/button/checkbox.h"
-#include "views/controls/label.h"
-#include "views/grid_layout.h"
-#include "views/standard_layout.h"
-#include "views/widget/widget.h"
-#include "views/window/client_view.h"
-#include "views/window/window.h"
-
-#if defined(OS_LINUX)
-#include "app/x11_util.h"
-#else
-#include "app/win_util.h"
-#endif
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/user_manager.h"
-#endif
-
-using views::ColumnSet;
-using views::GridLayout;
-
-// Report a bug data version.
-static const int kBugReportVersion = 1;
-static const int kScreenImageRadioGroup = 2;
-static const char kScreenshotsRelativePath[] = "/Screenshots";
-static const char kScreenshotPattern[] = "*.png";
-
-// Number of lines description field can display at one time.
-static const int kDescriptionLines = 5;
-
-class BugReportComboBoxModel : public ComboboxModel {
- public:
- BugReportComboBoxModel() {}
-
- // ComboboxModel interface.
- virtual int GetItemCount() {
- return BugReportUtil::OTHER_PROBLEM + 1;
- }
-
- virtual std::wstring GetItemAt(int index) {
- return GetItemAtIndex(index);
- }
-
- static std::wstring GetItemAtIndex(int index) {
-#if defined(OS_CHROMEOS)
- switch (index) {
- case BugReportUtil::CONNECTIVITY_ISSUE:
- return l10n_util::GetString(IDS_BUGREPORT_CONNECTIVITY_ISSUE);
- case BugReportUtil::SYNC_ISSUE:
- return l10n_util::GetString(IDS_BUGREPORT_SYNC_ISSUE);
- case BugReportUtil::CRASH_ISSUE:
- return l10n_util::GetString(IDS_BUGREPORT_CRASH_ISSUE);
- case BugReportUtil::PAGE_FORMATTING:
- return l10n_util::GetString(IDS_BUGREPORT_PAGE_FORMATTING);
- case BugReportUtil::EXTENSION_ISSUE:
- return l10n_util::GetString(IDS_BUGREPORT_EXTENSION_ISSUE);
- case BugReportUtil::SUSPEND_ISSUE:
- return l10n_util::GetString(IDS_BUGREPORT_SUSPEND_ISSUE);
- case BugReportUtil::PHISHING_PAGE:
- return l10n_util::GetString(IDS_BUGREPORT_PHISHING_PAGE);
- case BugReportUtil::OTHER_PROBLEM:
- return l10n_util::GetString(IDS_BUGREPORT_OTHER_PROBLEM);
- default:
- NOTREACHED();
- return std::wstring();
- }
-#else
- switch (index) {
- case BugReportUtil::PAGE_WONT_LOAD:
- return l10n_util::GetString(IDS_BUGREPORT_PAGE_WONT_LOAD);
- case BugReportUtil::PAGE_LOOKS_ODD:
- return l10n_util::GetString(IDS_BUGREPORT_PAGE_LOOKS_ODD);
- case BugReportUtil::PHISHING_PAGE:
- return l10n_util::GetString(IDS_BUGREPORT_PHISHING_PAGE);
- case BugReportUtil::CANT_SIGN_IN:
- return l10n_util::GetString(IDS_BUGREPORT_CANT_SIGN_IN);
- case BugReportUtil::CHROME_MISBEHAVES:
- return l10n_util::GetString(IDS_BUGREPORT_CHROME_MISBEHAVES);
- case BugReportUtil::SOMETHING_MISSING:
- return l10n_util::GetString(IDS_BUGREPORT_SOMETHING_MISSING);
- case BugReportUtil::BROWSER_CRASH:
- return l10n_util::GetString(IDS_BUGREPORT_BROWSER_CRASH);
- case BugReportUtil::OTHER_PROBLEM:
- return l10n_util::GetString(IDS_BUGREPORT_OTHER_PROBLEM);
- default:
- NOTREACHED();
- return std::wstring();
- }
-#endif
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BugReportComboBoxModel);
-};
-
-namespace {
-
-#if defined(OS_CHROMEOS)
-class LastScreenshotTask : public Task {
- public:
- LastScreenshotTask(std::string* image_str,
- base::WaitableEvent* task_waitable)
- : image_str_(image_str),
- task_waitable_(task_waitable) {
- }
-
- private:
- void Run() {
- FilePath fileshelf_path;
- // TODO(rkc): Change this to use FilePath.Append() once the cros
- // issue with with it is fixed
- if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS,
- &fileshelf_path)) {
- *image_str_ = "";
- task_waitable_->Signal();
- }
-
- FilePath screenshots_path(fileshelf_path.value() +
- std::string(kScreenshotsRelativePath));
- file_util::FileEnumerator screenshots(screenshots_path, false,
- file_util::FileEnumerator::FILES,
- std::string(kScreenshotPattern));
- FilePath screenshot = screenshots.Next();
- FilePath latest("");
- time_t last_mtime = 0;
- while (!screenshot.empty()) {
- file_util::FileEnumerator::FindInfo info;
- screenshots.GetFindInfo(&info);
- if (info.stat.st_mtime > last_mtime) {
- last_mtime = info.stat.st_mtime;
- latest = screenshot;
- }
- screenshot = screenshots.Next();
- }
-
- if (!file_util::ReadFileToString(latest, image_str_))
- *image_str_ = "";
- task_waitable_->Signal();
- }
- private:
- std::string* image_str_;
- base::WaitableEvent* task_waitable_;
-};
-#endif
-
-bool GetLastScreenshot(std::string* image_str) {
-#if defined(OS_CHROMEOS)
- base::WaitableEvent task_waitable(true, false);
- ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE,
- new LastScreenshotTask(image_str, &task_waitable));
- task_waitable.Wait();
- if (*image_str == "")
- return false;
- else
- return true;
-#else
- return false;
-#endif
-}
-
-} // namespace
-
-namespace browser {
-
-// Global "display this dialog" function declared in browser_dialogs.h.
-void ShowBugReportView(views::Window* parent,
- Profile* profile,
- TabContents* tab) {
- BugReportView* view = new BugReportView(profile, tab);
-
- // Get the size of the parent window to capture screenshot dimensions
- gfx::Rect screen_size = parent->GetBounds();
- view->set_screen_size(screen_size);
-
- // Grab an exact snapshot of the window that the user is seeing (i.e. as
- // rendered--do not re-render, and include windowed plugins).
- std::vector<unsigned char> *screenshot_png = new std::vector<unsigned char>;
-
-#if defined(OS_LINUX)
- x11_util::GrabWindowSnapshot(parent->GetNativeWindow(), screenshot_png);
-#else
- win_util::GrabWindowSnapshot(parent->GetNativeWindow(), screenshot_png);
-#endif
-
- // The BugReportView takes ownership of the image data, and will dispose of
- // it in its destructor
- view->set_captured_image(screenshot_png);
-
-#if defined(OS_CHROMEOS)
- // Get last screenshot taken
- std::string image_str;
- bool have_last_image = false;
- if (GetLastScreenshot(&image_str)) {
- // reuse screenshot_png; previous pointer now owned by BugReportView
- screenshot_png = new std::vector<unsigned char>(image_str.begin(),
- image_str.end());
- have_last_image = true;
- } else {
- // else set it to be an empty vector
- screenshot_png = new std::vector<unsigned char>;
- }
- view->set_last_image(screenshot_png);
-
- // Create and show the dialog
- views::Window::CreateChromeWindow(parent->GetNativeWindow(), gfx::Rect(),
- view)->Show();
- if (!have_last_image)
- view->DisableLastImageRadio();
-#endif
-}
-
-} // namespace browser
-
-// BugReportView - create and submit a bug report from the user.
-// This is separate from crash reporting, which is handled by Breakpad.
-BugReportView::BugReportView(Profile* profile, TabContents* tab)
- : include_page_source_checkbox_(NULL),
- include_page_image_checkbox_(NULL),
- profile_(profile),
- tab_(tab),
- problem_type_(0) {
- DCHECK(profile);
- SetupControl();
-
- // We want to use the URL of the current committed entry (the current URL may
- // actually be the pending one).
- if (tab->controller().GetActiveEntry()) {
- page_url_text_->SetText(UTF8ToUTF16(
- tab->controller().GetActiveEntry()->url().spec()));
- }
-
-#if defined(OS_CHROMEOS)
- // Get and set the gaia e-mail
- chromeos::UserManager* manager = chromeos::UserManager::Get();
- if (!manager) {
- user_email_text_->SetText(UTF8ToUTF16(std::string("")));
- } else {
- const std::string& email = manager->logged_in_user().email();
- user_email_text_->SetText(UTF8ToUTF16(email));
- if (!email.empty())
- user_email_text_->SetEnabled(false);
- }
-#endif
-
- // Retrieve the application version info.
- scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
- if (version_info.get()) {
- version_ = version_info->product_name() + L" - " +
- version_info->file_version() +
- L" (" + version_info->last_change() + L")";
- }
-
-
- FilePath tmpfilename;
-
-#if defined(OS_CHROMEOS)
- chromeos::SyslogsLibrary* syslogs_lib =
- chromeos::CrosLibrary::Get()->GetSyslogsLibrary();
- if (syslogs_lib) {
- sys_info_.reset(syslogs_lib->GetSyslogs(&tmpfilename));
- }
-#endif
-}
-
-BugReportView::~BugReportView() {
-}
-
-void BugReportView::SetupControl() {
- bug_type_model_.reset(new BugReportComboBoxModel);
-
- // Adds all controls.
- bug_type_label_ = new views::Label(
- l10n_util::GetString(IDS_BUGREPORT_BUG_TYPE));
- bug_type_combo_ = new views::Combobox(bug_type_model_.get());
- bug_type_combo_->set_listener(this);
- bug_type_combo_->SetAccessibleName(bug_type_label_->GetText());
-
- page_title_label_ = new views::Label(
- l10n_util::GetString(IDS_BUGREPORT_REPORT_PAGE_TITLE));
- page_title_text_ = new views::Label(UTF16ToWideHack(tab_->GetTitle()));
- page_url_label_ = new views::Label(
- l10n_util::GetString(IDS_BUGREPORT_REPORT_URL_LABEL));
- // page_url_text_'s text (if any) is filled in after dialog creation.
- page_url_text_ = new views::Textfield;
- page_url_text_->SetController(this);
- page_url_text_->SetAccessibleName(page_url_label_->GetText());
-
-#if defined(OS_CHROMEOS)
- user_email_label_ = new views::Label(
- l10n_util::GetString(IDS_BUGREPORT_USER_EMAIL_LABEL));
- // user_email_text_'s text (if any) is filled in after dialog creation.
- user_email_text_ = new views::Textfield;
- user_email_text_->SetController(this);
- user_email_text_->SetAccessibleName(user_email_label_->GetText());
-#endif
-
- description_label_ = new views::Label(
- l10n_util::GetString(IDS_BUGREPORT_DESCRIPTION_LABEL));
- description_text_ =
- new views::Textfield(views::Textfield::STYLE_MULTILINE);
- description_text_->SetHeightInLines(kDescriptionLines);
- description_text_->SetAccessibleName(description_label_->GetText());
-
- include_page_source_checkbox_ = new views::Checkbox(
- l10n_util::GetString(IDS_BUGREPORT_INCLUDE_PAGE_SOURCE_CHKBOX));
- include_page_source_checkbox_->SetChecked(true);
-
-#if defined(OS_CHROMEOS)
- include_last_screen_image_radio_ = new views::RadioButton(
- l10n_util::GetString(IDS_BUGREPORT_INCLUDE_LAST_SCREEN_IMAGE),
- kScreenImageRadioGroup);
-
- include_new_screen_image_radio_ = new views::RadioButton(
- l10n_util::GetString(IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE),
- kScreenImageRadioGroup);
-
- include_no_screen_image_radio_ = new views::RadioButton(
- l10n_util::GetString(IDS_BUGREPORT_INCLUDE_NO_SCREEN_IMAGE),
- kScreenImageRadioGroup);
-
- system_information_url_control_ = new views::Link(
- l10n_util::GetString(IDS_BUGREPORT_SYSTEM_INFORMATION_URL_TEXT));
- system_information_url_control_->SetController(this);
-
- include_new_screen_image_radio_->SetChecked(true);
-#endif
- include_page_image_checkbox_ = new views::Checkbox(
- l10n_util::GetString(IDS_BUGREPORT_INCLUDE_PAGE_IMAGE_CHKBOX));
- include_page_image_checkbox_->SetChecked(true);
-
- // Arranges controls by using GridLayout.
- const int column_set_id = 0;
- GridLayout* layout = CreatePanelGridLayout(this);
- SetLayoutManager(layout);
- ColumnSet* column_set = layout->AddColumnSet(column_set_id);
- column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
- GridLayout::USE_PREF, 0, 0);
- column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing * 2);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
-
- // Page Title and text.
- layout->StartRow(0, column_set_id);
- layout->AddView(page_title_label_);
- layout->AddView(page_title_text_, 1, 1, GridLayout::LEADING,
- GridLayout::FILL);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- // Bug type and combo box.
- layout->StartRow(0, column_set_id);
- layout->AddView(bug_type_label_, 1, 1, GridLayout::LEADING, GridLayout::FILL);
- layout->AddView(bug_type_combo_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- // Page URL and text field.
- layout->StartRow(0, column_set_id);
- layout->AddView(page_url_label_);
- layout->AddView(page_url_text_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- // Description label and text field.
- layout->StartRow(0, column_set_id);
- layout->AddView(description_label_, 1, 1, GridLayout::LEADING,
- GridLayout::LEADING);
- layout->AddView(description_text_, 1, 1, GridLayout::FILL,
- GridLayout::LEADING);
-#if defined(OS_CHROMEOS)
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- // Page URL and text field.
- layout->StartRow(0, column_set_id);
- layout->AddView(user_email_label_);
- layout->AddView(user_email_text_);
-#endif
- layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
-
- // Checkboxes.
- // The include page source checkbox is hidden until we can make it work.
- // layout->StartRow(0, column_set_id);
- // layout->SkipColumns(1);
- // layout->AddView(include_page_source_checkbox_);
- // layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, column_set_id);
- layout->SkipColumns(1);
-#if defined(OS_CHROMEOS)
- // Radio boxes to select last screen shot or,
-
- // new screenshot
- layout->AddView(include_new_screen_image_radio_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- // last screenshot taken
- layout->StartRow(0, column_set_id);
- layout->SkipColumns(1);
- layout->AddView(include_last_screen_image_radio_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- // no screenshot
- layout->StartRow(0, column_set_id);
- layout->SkipColumns(1);
- layout->AddView(include_no_screen_image_radio_);
- layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
-
- layout->StartRow(0, column_set_id);
- layout->SkipColumns(1);
- layout->AddView(system_information_url_control_, 1, 1, GridLayout::LEADING,
- GridLayout::CENTER);
-#else
- if (include_page_image_checkbox_) {
- layout->StartRow(0, column_set_id);
- layout->SkipColumns(1);
- layout->AddView(include_page_image_checkbox_);
- }
-#endif
-
- layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
-}
-
-gfx::Size BugReportView::GetPreferredSize() {
- gfx::Size size = views::Window::GetLocalizedContentsSize(
- IDS_BUGREPORT_DIALOG_WIDTH_CHARS,
-#if defined(OS_CHROMEOS)
- IDS_CHROMEOS_BUGREPORT_DIALOG_HEIGHT_LINES);
-#else
- IDS_BUGREPORT_DIALOG_HEIGHT_LINES);
-#endif
- return size;
-}
-
-void BugReportView::UpdateReportingControls(bool is_phishing_report) {
- // page source, screen/page images, system information
- // are not needed if it's a phishing report
-
- include_page_source_checkbox_->SetEnabled(!is_phishing_report);
- include_page_source_checkbox_->SetChecked(!is_phishing_report);
-
-#if defined(OS_CHROMEOS)
- include_new_screen_image_radio_->SetEnabled(!is_phishing_report);
- if (!last_image_->empty())
- include_last_screen_image_radio_->SetEnabled(!is_phishing_report);
- include_no_screen_image_radio_->SetEnabled(!is_phishing_report);
-#else
- if (include_page_image_checkbox_) {
- include_page_image_checkbox_->SetEnabled(!is_phishing_report);
- include_page_image_checkbox_->SetChecked(!is_phishing_report);
- }
-#endif
-}
-
-void BugReportView::ItemChanged(views::Combobox* combobox,
- int prev_index,
- int new_index) {
- if (new_index == prev_index)
- return;
-
- problem_type_ = new_index;
- bool is_phishing_report = new_index == BugReportUtil::PHISHING_PAGE;
-
- description_text_->SetEnabled(!is_phishing_report);
- description_text_->SetReadOnly(is_phishing_report);
- if (is_phishing_report) {
- old_report_text_ = UTF16ToWide(description_text_->text());
- description_text_->SetText(string16());
- } else if (!old_report_text_.empty()) {
- description_text_->SetText(WideToUTF16Hack(old_report_text_));
- old_report_text_.clear();
- }
-
- UpdateReportingControls(is_phishing_report);
- GetDialogClientView()->UpdateDialogButtons();
-}
-
-void BugReportView::ContentsChanged(views::Textfield* sender,
- const string16& new_contents) {
-}
-
-bool BugReportView::HandleKeystroke(views::Textfield* sender,
- const views::Textfield::Keystroke& key) {
- return false;
-}
-
-std::wstring BugReportView::GetDialogButtonLabel(
- MessageBoxFlags::DialogButton button) const {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- if (problem_type_ == BugReportUtil::PHISHING_PAGE)
- return l10n_util::GetString(IDS_BUGREPORT_SEND_PHISHING_REPORT);
- else
- return l10n_util::GetString(IDS_BUGREPORT_SEND_REPORT);
- } else {
- return std::wstring();
- }
-}
-
-int BugReportView::GetDefaultDialogButton() const {
- return MessageBoxFlags::DIALOGBUTTON_NONE;
-}
-
-bool BugReportView::CanResize() const {
- return false;
-}
-
-bool BugReportView::CanMaximize() const {
- return false;
-}
-
-bool BugReportView::IsAlwaysOnTop() const {
- return false;
-}
-
-bool BugReportView::HasAlwaysOnTopMenu() const {
- return false;
-}
-
-bool BugReportView::IsModal() const {
- return true;
-}
-
-std::wstring BugReportView::GetWindowTitle() const {
- return l10n_util::GetString(IDS_BUGREPORT_TITLE);
-}
-
-
-bool BugReportView::Accept() {
- if (IsDialogButtonEnabled(MessageBoxFlags::DIALOGBUTTON_OK)) {
- if (problem_type_ == BugReportUtil::PHISHING_PAGE) {
- BugReportUtil::ReportPhishing(tab_,
- UTF16ToUTF8(page_url_text_->text()));
- } else {
- char* image_data = NULL;
- size_t image_data_size = 0;
-#if defined(OS_CHROMEOS)
- if (include_new_screen_image_radio_->checked() &&
- !captured_image_->empty()) {
- image_data = reinterpret_cast<char *>(&captured_image_->front());
- image_data_size = captured_image_->size();
- } else if (include_last_screen_image_radio_->checked() &&
- !last_image_->empty()) {
- image_data = reinterpret_cast<char *>(&last_image_->front());
- image_data_size = last_image_->size();
- }
-#else
- if (include_page_image_checkbox_->checked() && captured_image_.get() &&
- !captured_image_->empty()) {
- image_data = reinterpret_cast<char *>(&captured_image_->front());
- image_data_size = captured_image_->size();
- }
-#endif
-#if defined(OS_CHROMEOS)
- BugReportUtil::SendReport(profile_,
- WideToUTF8(page_title_text_->GetText()),
- problem_type_,
- UTF16ToUTF8(page_url_text_->text()),
- UTF16ToUTF8(user_email_text_->text()),
- UTF16ToUTF8(description_text_->text()),
- image_data, image_data_size,
- screen_size_.width(), screen_size_.height(),
- WideToUTF8(bug_type_combo_->model()->GetItemAt(problem_type_)),
- sys_info_.get());
-#else
- BugReportUtil::SendReport(profile_,
- WideToUTF8(page_title_text_->GetText()),
- problem_type_,
- UTF16ToUTF8(page_url_text_->text()),
- std::string(),
- UTF16ToUTF8(description_text_->text()),
- image_data, image_data_size,
- screen_size_.width(), screen_size_.height());
-#endif
- }
- }
- return true;
-}
-
-#if defined(OS_CHROMEOS)
-void BugReportView::LinkActivated(views::Link* source,
- int event_flags) {
- GURL url;
- if (source == system_information_url_control_) {
- url = GURL(chrome::kAboutSystemURL);
- } else {
- NOTREACHED() << "Unknown link source";
- return;
- }
-
- Browser* browser = BrowserList::GetLastActive();
- if (browser)
- browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
-}
-#endif
-
-
-views::View* BugReportView::GetContentsView() {
- return this;
-}
diff --git a/chrome/browser/views/bug_report_view.h b/chrome/browser/views/bug_report_view.h
deleted file mode 100644
index feeb0f3..0000000
--- a/chrome/browser/views/bug_report_view.h
+++ /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.
-
-#ifndef CHROME_BROWSER_VIEWS_BUG_REPORT_VIEW_H_
-#define CHROME_BROWSER_VIEWS_BUG_REPORT_VIEW_H_
-
-#include "chrome/common/net/url_fetcher.h"
-#include "gfx/rect.h"
-#include "googleurl/src/gurl.h"
-#include "views/controls/button/radio_button.h"
-#include "views/controls/combobox/combobox.h"
-#include "views/controls/textfield/textfield.h"
-#include "views/controls/link.h"
-#include "views/controls/image_view.h"
-#include "views/view.h"
-#include "views/window/dialog_delegate.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/syslogs_library.h"
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#endif
-
-namespace views {
-class Checkbox;
-class Label;
-class Throbber;
-class Window;
-class RadioButton;
-class Link;
-}
-
-class Profile;
-class TabContents;
-class BugReportComboBoxModel;
-
-// BugReportView draws the dialog that allows the user to report a
-// bug in rendering a particular page (note: this is not a crash
-// report, which are handled separately by Breakpad). It packages
-// up the URL, a text description, system information and optionally
-// a screenshot; then it submits the info through https to the google
-// feedback chrome end-point.
-//
-// Note: This UI is being used for the Chrome OS dogfood release only
-// In the very next iteration, this will be replaced by a HTML
-// based UI, which will be common for all platforms
-class BugReportView : public views::View,
- public views::DialogDelegate,
- public views::Combobox::Listener,
-#if defined(OS_CHROMEOS)
- public views::LinkController,
-#endif
- public views::Textfield::Controller {
- public:
- BugReportView(Profile* profile, TabContents* tab);
- virtual ~BugReportView();
-
- // NOTE: set_captured_image takes ownership of the vector
- void set_captured_image(std::vector<unsigned char>* png_data) {
- captured_image_.reset(png_data);
- }
-
- void set_screen_size(const gfx::Rect& screen_size) {
- screen_size_ = screen_size;
- }
-
- // Set all additional reporting controls to disabled
- // if phishing report
- void UpdateReportingControls(bool is_phishing_report);
-
- // Overridden from views::View:
- virtual gfx::Size GetPreferredSize();
-
- // views::Textfield::Controller implementation:
- virtual void ContentsChanged(views::Textfield* sender,
- const string16& new_contents);
- virtual bool HandleKeystroke(views::Textfield* sender,
- const views::Textfield::Keystroke& key);
-
- // views::Combobox::Listener implementation:
- virtual void ItemChanged(views::Combobox* combobox, int prev_index,
- int new_index);
-
-#if defined(OS_CHROMEOS)
- // Overridden from views::LinkController:
- virtual void LinkActivated(views::Link* source, int event_flags);
-
- // Disable the include last image radio control
- void DisableLastImageRadio() {
- include_last_screen_image_radio_->SetEnabled(false);
- }
-
- // NOTE: set_last_image takes ownership of the vector
- void set_last_image(std::vector<unsigned char>* png_data) {
- last_image_.reset(png_data);
- }
-#endif
-
- // Overridden from views::DialogDelegate:
- virtual std::wstring GetDialogButtonLabel(
- MessageBoxFlags::DialogButton button) const;
- virtual int GetDefaultDialogButton() const;
- virtual bool CanResize() const;
- virtual bool CanMaximize() const;
- virtual bool IsAlwaysOnTop() const;
- virtual bool HasAlwaysOnTopMenu() const;
- virtual bool IsModal() const;
- virtual std::wstring GetWindowTitle() const;
- virtual bool Accept();
- virtual views::View* GetContentsView();
-
- private:
- class PostCleanup;
-
- // Set OS Version information in a string (maj.minor.build SP)
- void SetOSVersion(std::string *os_version);
-
- // Initializes the controls on the dialog.
- void SetupControl();
- // helper function to create a MIME part boundary string
- void CreateMimeBoundary(std::string *out);
- // Sends the data via an HTTP POST
- void SendReport();
-
- // Redirects the user to Google's phishing reporting page.
- void ReportPhishing();
-
- views::Label* bug_type_label_;
- views::Combobox* bug_type_combo_;
- views::Label* page_title_label_;
- views::Label* page_title_text_;
- views::Label* page_url_label_;
- views::Textfield* page_url_text_;
- views::Label* description_label_;
- views::Textfield* description_text_;
- views::Checkbox* include_page_source_checkbox_;
-#if defined(OS_CHROMEOS)
- views::Label* user_email_label_;
- views::Textfield* user_email_text_;
- views::RadioButton* include_new_screen_image_radio_;
- views::RadioButton* include_last_screen_image_radio_;
- views::RadioButton* include_no_screen_image_radio_;
- views::Link* system_information_url_control_;
-
- scoped_ptr<chromeos::LogDictionaryType> sys_info_;
- scoped_ptr< std::vector<unsigned char> > last_image_;
-#endif
- views::Checkbox* include_page_image_checkbox_;
-
-
- scoped_ptr<BugReportComboBoxModel> bug_type_model_;
-
- Profile* profile_;
-
- std::wstring version_;
- gfx::Rect screen_size_;
- scoped_ptr< std::vector<unsigned char> > captured_image_;
-
- TabContents* tab_;
-
- // Used to distinguish the report type: Phishing or other.
- int problem_type_;
-
- // Save the description the user types in when we clear the dialog for the
- // phishing option. If the user changes the report type back, we reinstate
- // their original text so they don't have to type it again.
- std::wstring old_report_text_;
-
- DISALLOW_COPY_AND_ASSIGN(BugReportView);
-};
-
-#endif // CHROME_BROWSER_VIEWS_BUG_REPORT_VIEW_H_
diff --git a/chrome/browser/views/chrome_views_delegate.cc b/chrome/browser/views/chrome_views_delegate.cc
index b0f8028..d872ace 100644
--- a/chrome/browser/views/chrome_views_delegate.cc
+++ b/chrome/browser/views/chrome_views_delegate.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.
@@ -6,8 +6,10 @@
#include "app/clipboard/clipboard.h"
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/views/accessibility_event_router_views.h"
#include "chrome/browser/window_sizer.h"
#include "gfx/rect.h"
@@ -30,21 +32,21 @@ void ChromeViewsDelegate::SaveWindowPlacement(const std::wstring& window_name,
DictionaryValue* window_preferences =
g_browser_process->local_state()->GetMutableDictionary(
- window_name.c_str());
- window_preferences->SetInteger(L"left", bounds.x());
- window_preferences->SetInteger(L"top", bounds.y());
- window_preferences->SetInteger(L"right", bounds.right());
- window_preferences->SetInteger(L"bottom", bounds.bottom());
- window_preferences->SetBoolean(L"maximized", maximized);
+ WideToUTF8(window_name).c_str());
+ window_preferences->SetInteger("left", bounds.x());
+ window_preferences->SetInteger("top", bounds.y());
+ window_preferences->SetInteger("right", bounds.right());
+ window_preferences->SetInteger("bottom", bounds.bottom());
+ window_preferences->SetBoolean("maximized", maximized);
scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_info_provider(
WindowSizer::CreateDefaultMonitorInfoProvider());
gfx::Rect work_area(
monitor_info_provider->GetMonitorWorkAreaMatching(bounds));
- window_preferences->SetInteger(L"work_area_left", work_area.x());
- window_preferences->SetInteger(L"work_area_top", work_area.y());
- window_preferences->SetInteger(L"work_area_right", work_area.right());
- window_preferences->SetInteger(L"work_area_bottom", work_area.bottom());
+ window_preferences->SetInteger("work_area_left", work_area.x());
+ window_preferences->SetInteger("work_area_top", work_area.y());
+ window_preferences->SetInteger("work_area_right", work_area.right());
+ window_preferences->SetInteger("work_area_bottom", work_area.bottom());
}
bool ChromeViewsDelegate::GetSavedWindowBounds(const std::wstring& window_name,
@@ -53,12 +55,13 @@ bool ChromeViewsDelegate::GetSavedWindowBounds(const std::wstring& window_name,
return false;
const DictionaryValue* dictionary =
- g_browser_process->local_state()->GetDictionary(window_name.c_str());
+ g_browser_process->local_state()->GetDictionary(
+ WideToUTF8(window_name).c_str());
int left, top, right, bottom;
- if (!dictionary || !dictionary->GetInteger(L"left", &left) ||
- !dictionary->GetInteger(L"top", &top) ||
- !dictionary->GetInteger(L"right", &right) ||
- !dictionary->GetInteger(L"bottom", &bottom))
+ if (!dictionary || !dictionary->GetInteger("left", &left) ||
+ !dictionary->GetInteger("top", &top) ||
+ !dictionary->GetInteger("right", &right) ||
+ !dictionary->GetInteger("bottom", &bottom))
return false;
bounds->SetRect(left, top, right - left, bottom - top);
@@ -72,11 +75,18 @@ bool ChromeViewsDelegate::GetSavedMaximizedState(
return false;
const DictionaryValue* dictionary =
- g_browser_process->local_state()->GetDictionary(window_name.c_str());
- return dictionary && dictionary->GetBoolean(L"maximized", maximized) &&
+ g_browser_process->local_state()->GetDictionary(
+ WideToUTF8(window_name).c_str());
+ return dictionary && dictionary->GetBoolean("maximized", maximized) &&
maximized;
}
+void ChromeViewsDelegate::NotifyAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type) {
+ AccessibilityEventRouterViews::GetInstance()->HandleAccessibilityEvent(
+ view, event_type);
+}
+
#if defined(OS_WIN)
HICON ChromeViewsDelegate::GetDefaultWindowIcon() const {
return GetAppIcon();
diff --git a/chrome/browser/views/chrome_views_delegate.h b/chrome/browser/views/chrome_views_delegate.h
index e69f4fe..af046d2 100644
--- a/chrome/browser/views/chrome_views_delegate.h
+++ b/chrome/browser/views/chrome_views_delegate.h
@@ -1,11 +1,13 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef CHROME_BROWSER_VIEWS_CHROME_VIEWS_DELEGATE_H_
#define CHROME_BROWSER_VIEWS_CHROME_VIEWS_DELEGATE_H_
+#pragma once
-#include "base/logging.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
#include "views/views_delegate.h"
class ChromeViewsDelegate : public views::ViewsDelegate {
@@ -22,6 +24,8 @@ class ChromeViewsDelegate : public views::ViewsDelegate {
gfx::Rect* bounds) const;
virtual bool GetSavedMaximizedState(const std::wstring& window_name,
bool* maximized) const;
+ virtual void NotifyAccessibilityEvent(
+ views::View* view, AccessibilityTypes::Event event_type);
#if defined(OS_WIN)
virtual HICON GetDefaultWindowIcon() const;
#endif
diff --git a/chrome/browser/views/clear_browsing_data.cc b/chrome/browser/views/clear_browsing_data.cc
index d30ce35..3eb4e5c 100644
--- a/chrome/browser/views/clear_browsing_data.cc
+++ b/chrome/browser/views/clear_browsing_data.cc
@@ -1,15 +1,20 @@
-// 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/views/clear_browsing_data.h"
#include "app/l10n_util.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
+#if defined(OS_WIN)
+#include "chrome/browser/views/clear_browsing_data_view.h"
+#endif
#include "chrome/common/pref_names.h"
#include "gfx/insets.h"
#include "grit/generated_resources.h"
@@ -35,16 +40,21 @@ using views::GridLayout;
static const int kExtraMarginForTimePeriodLabel = 3;
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
+
////////////////////////////////////////////////////////////////////////////////
// ClearBrowsingDataView, public:
@@ -239,13 +249,10 @@ int ClearBrowsingDataView::GetDefaultDialogButton() const {
std::wstring ClearBrowsingDataView::GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- return l10n_util::GetString(IDS_CLEAR_BROWSING_DATA_COMMIT);
- } else if (button == MessageBoxFlags::DIALOGBUTTON_CANCEL) {
- return l10n_util::GetString(IDS_CLOSE);
- } else {
- return std::wstring();
- }
+ DCHECK((button == MessageBoxFlags::DIALOGBUTTON_OK) ||
+ (button == MessageBoxFlags::DIALOGBUTTON_CANCEL));
+ return l10n_util::GetString((button == MessageBoxFlags::DIALOGBUTTON_OK) ?
+ IDS_CLEAR_BROWSING_DATA_COMMIT : IDS_CANCEL);
}
bool ClearBrowsingDataView::IsDialogButtonEnabled(
@@ -294,6 +301,19 @@ bool ClearBrowsingDataView::Accept() {
return false;
}
+ PrefService* prefs = profile_->GetPrefs();
+ prefs->SetBoolean(prefs::kDeleteBrowsingHistory,
+ del_history_checkbox_->checked());
+ prefs->SetBoolean(prefs::kDeleteDownloadHistory,
+ del_downloads_checkbox_->checked());
+ prefs->SetBoolean(prefs::kDeleteCache,
+ del_cache_checkbox_->checked());
+ prefs->SetBoolean(prefs::kDeleteCookies,
+ del_cookies_checkbox_->checked());
+ prefs->SetBoolean(prefs::kDeletePasswords,
+ del_passwords_checkbox_->checked());
+ prefs->SetBoolean(prefs::kDeleteFormData,
+ del_form_data_checkbox_->checked());
OnDelete();
return false; // We close the dialog in OnBrowsingDataRemoverDone().
}
@@ -337,15 +357,15 @@ int ClearBrowsingDataView::GetItemCount() {
return 5;
}
-std::wstring ClearBrowsingDataView::GetItemAt(int index) {
+string16 ClearBrowsingDataView::GetItemAt(int index) {
switch (index) {
- case 0: return l10n_util::GetString(IDS_CLEAR_DATA_HOUR);
- case 1: return l10n_util::GetString(IDS_CLEAR_DATA_DAY);
- case 2: return l10n_util::GetString(IDS_CLEAR_DATA_WEEK);
- case 3: return l10n_util::GetString(IDS_CLEAR_DATA_4WEEKS);
- case 4: return l10n_util::GetString(IDS_CLEAR_DATA_EVERYTHING);
- default: NOTREACHED() << L"Missing item";
- return L"?";
+ case 0: return l10n_util::GetStringUTF16(IDS_CLEAR_DATA_HOUR);
+ case 1: return l10n_util::GetStringUTF16(IDS_CLEAR_DATA_DAY);
+ case 2: return l10n_util::GetStringUTF16(IDS_CLEAR_DATA_WEEK);
+ case 3: return l10n_util::GetStringUTF16(IDS_CLEAR_DATA_4WEEKS);
+ case 4: return l10n_util::GetStringUTF16(IDS_CLEAR_DATA_EVERYTHING);
+ default: NOTREACHED() << "Missing item";
+ return ASCIIToUTF16("?");
}
}
@@ -361,27 +381,8 @@ void ClearBrowsingDataView::ItemChanged(views::Combobox* sender,
////////////////////////////////////////////////////////////////////////////////
// ClearBrowsingDataView, views::ButtonListener implementation:
-void ClearBrowsingDataView::ButtonPressed(
- views::Button* sender, const views::Event& event) {
- if (sender == del_history_checkbox_)
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteBrowsingHistory,
- del_history_checkbox_->checked() ? true : false);
- else if (sender == del_downloads_checkbox_)
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteDownloadHistory,
- del_downloads_checkbox_->checked() ? true : false);
- else if (sender == del_cache_checkbox_)
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteCache,
- del_cache_checkbox_->checked() ? true : false);
- else if (sender == del_cookies_checkbox_)
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteCookies,
- del_cookies_checkbox_->checked() ? true : false);
- else if (sender == del_passwords_checkbox_)
- profile_->GetPrefs()->SetBoolean(prefs::kDeletePasswords,
- del_passwords_checkbox_->checked() ? true : false);
- else if (sender == del_form_data_checkbox_)
- profile_->GetPrefs()->SetBoolean(prefs::kDeleteFormData,
- del_form_data_checkbox_->checked() ? true : false);
-
+void ClearBrowsingDataView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
// When no checkbox is checked we should not have the action button enabled.
// This forces the button to evaluate what state they should be in.
GetDialogClientView()->UpdateDialogButtons();
diff --git a/chrome/browser/views/clear_browsing_data.h b/chrome/browser/views/clear_browsing_data.h
index 9fedeaf..9a3e61a 100644
--- a/chrome/browser/views/clear_browsing_data.h
+++ b/chrome/browser/views/clear_browsing_data.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_CLEAR_BROWSING_DATA_H_
#define CHROME_BROWSER_VIEWS_CLEAR_BROWSING_DATA_H_
+#pragma once
#include "app/combobox_model.h"
#include "chrome/browser/browsing_data_remover.h"
@@ -70,7 +71,7 @@ class ClearBrowsingDataView : public views::View,
// Overridden from ComboboxModel:
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
// Overridden from views::Combobox::Listener:
virtual void ItemChanged(views::Combobox* sender, int prev_index,
diff --git a/chrome/browser/views/collected_cookies_win.cc b/chrome/browser/views/collected_cookies_win.cc
index 1a7f405..3f25992 100644
--- a/chrome/browser/views/collected_cookies_win.cc
+++ b/chrome/browser/views/collected_cookies_win.cc
@@ -5,15 +5,23 @@
#include "chrome/browser/views/collected_cookies_win.h"
#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/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
+#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
-#include "views/controls/label.h"
+#include "grit/theme_resources.h"
+#include "views/box_layout.h"
#include "views/controls/button/native_button.h"
+#include "views/controls/image_view.h"
+#include "views/controls/label.h"
+#include "views/controls/separator.h"
#include "views/standard_layout.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_win.h"
#include "views/window/window.h"
namespace browser {
@@ -27,6 +35,119 @@ void ShowCollectedCookiesDialog(gfx::NativeWindow parent_window,
} // namespace browser
+namespace {
+// Spacing between the infobar frame and its contents.
+const int kInfobarVerticalPadding = 3;
+const int kInfobarHorizontalPadding = 8;
+
+// Width of the infobar frame.
+const int kInfobarBorderSize = 1;
+
+// Dimensions of the tree views.
+const int kTreeViewWidth = 400;
+const int kTreeViewHeight = 125;
+
+} // namespace
+
+// A custom view that conditionally displays an infobar.
+class InfobarView : public views::View {
+ public:
+ InfobarView() {
+ content_ = new views::View;
+ SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
+ views::Border* border = views::Border::CreateSolidBorder(
+ kInfobarBorderSize, border_color);
+ content_->set_border(border);
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ info_image_ = new views::ImageView();
+ info_image_->SetImage(rb.GetBitmapNamed(IDR_INFO));
+ label_ = new views::Label();
+ }
+ virtual ~InfobarView() {}
+
+ // Update the visibility of the infobar. If |is_visible| is true, a rule for
+ // |setting| on |domain_name| was created.
+ void UpdateVisibility(bool is_visible,
+ ContentSetting setting,
+ const std::wstring& domain_name) {
+ if (!is_visible) {
+ SetVisible(false);
+ return;
+ }
+
+ std::wstring label;
+ switch (setting) {
+ case CONTENT_SETTING_BLOCK:
+ label = l10n_util::GetStringF(
+ IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED, domain_name);
+ break;
+
+ case CONTENT_SETTING_ALLOW:
+ label = l10n_util::GetStringF(
+ IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED, domain_name);
+ break;
+
+ case CONTENT_SETTING_SESSION_ONLY:
+ label = l10n_util::GetStringF(
+ IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED, domain_name);
+ break;
+
+ default:
+ NOTREACHED();
+ }
+ label_->SetText(label);
+ content_->Layout();
+ SetVisible(true);
+ }
+
+ private:
+ // Initialize contents and layout.
+ void Init() {
+ AddChildView(content_);
+ content_->SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kHorizontal,
+ kInfobarHorizontalPadding,
+ kInfobarVerticalPadding,
+ kRelatedControlSmallHorizontalSpacing));
+ content_->AddChildView(info_image_);
+ content_->AddChildView(label_);
+ UpdateVisibility(false, CONTENT_SETTING_BLOCK, std::wstring());
+ }
+
+ // views::View overrides.
+ virtual gfx::Size GetPreferredSize() {
+ if (!IsVisible())
+ return gfx::Size();
+
+ // Add space around the banner.
+ gfx::Size size(content_->GetPreferredSize());
+ size.Enlarge(0, 2 * kRelatedControlVerticalSpacing);
+ return size;
+ }
+
+ virtual void Layout() {
+ content_->SetBounds(
+ 0, kRelatedControlVerticalSpacing,
+ width(), height() - kRelatedControlVerticalSpacing);
+ }
+
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ if (is_add && child == this)
+ Init();
+ }
+
+ // Holds the info icon image and text label and renders the border.
+ views::View* content_;
+ // Info icon image.
+ views::ImageView* info_image_;
+ // The label responsible for rendering the text.
+ views::Label* label_;
+
+ DISALLOW_COPY_AND_ASSIGN(InfobarView);
+};
///////////////////////////////////////////////////////////////////////////////
// CollectedCookiesWin, constructor and destructor:
@@ -40,7 +161,8 @@ CollectedCookiesWin::CollectedCookiesWin(gfx::NativeWindow parent_window,
blocked_cookies_tree_(NULL),
block_allowed_button_(NULL),
allow_blocked_button_(NULL),
- for_session_blocked_button_(NULL) {
+ for_session_blocked_button_(NULL),
+ infobar_(NULL) {
TabSpecificContentSettings* content_settings =
tab_contents->GetTabSpecificContentSettings();
registrar_.Add(this, NotificationType::COLLECTED_COOKIES_SHOWN,
@@ -59,6 +181,8 @@ CollectedCookiesWin::~CollectedCookiesWin() {
void CollectedCookiesWin::Init() {
TabSpecificContentSettings* content_settings =
tab_contents_->GetTabSpecificContentSettings();
+ HostContentSettingsMap* host_content_settings_map =
+ tab_contents_->profile()->GetHostContentSettingsMap();
// Allowed Cookie list.
allowed_label_ = new views::Label(
@@ -75,7 +199,12 @@ void CollectedCookiesWin::Init() {
// Blocked Cookie list.
blocked_label_ = new views::Label(
- l10n_util::GetString(IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL));
+ l10n_util::GetString(
+ host_content_settings_map->BlockThirdPartyCookies() ?
+ IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED :
+ IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL));
+ blocked_label_->SetMultiLine(true);
+ blocked_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
blocked_cookies_tree_model_.reset(
content_settings->GetBlockedCookiesTreeModel());
blocked_cookies_tree_ = new views::TreeView();
@@ -110,7 +239,8 @@ void CollectedCookiesWin::Init() {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(1, single_column_layout_id);
layout->AddView(
- allowed_cookies_tree_, 1, 1, GridLayout::FILL, GridLayout::FILL);
+ allowed_cookies_tree_, 1, 1, GridLayout::FILL, GridLayout::FILL,
+ kTreeViewWidth, kTreeViewHeight);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, single_column_layout_id);
@@ -121,12 +251,18 @@ void CollectedCookiesWin::Init() {
layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
layout->StartRow(0, single_column_layout_id);
- layout->AddView(blocked_label_);
+ layout->AddView(
+ new views::Separator(), 1, 1, GridLayout::FILL, GridLayout::FILL);
+ layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
+
+ layout->StartRow(0, single_column_layout_id);
+ layout->AddView(blocked_label_, 1, 1, GridLayout::FILL, GridLayout::FILL);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(1, single_column_layout_id);
layout->AddView(
- blocked_cookies_tree_, 1, 1, GridLayout::FILL, GridLayout::FILL);
+ blocked_cookies_tree_, 1, 1, GridLayout::FILL, GridLayout::FILL,
+ kTreeViewWidth, kTreeViewHeight);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, three_columns_layout_id);
@@ -137,6 +273,10 @@ void CollectedCookiesWin::Init() {
this, l10n_util::GetString(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON));
layout->AddView(for_session_blocked_button_);
+ layout->StartRow(0, single_column_layout_id);
+ infobar_ = new InfobarView();
+ layout->AddView(infobar_, 1, 1, GridLayout::FILL, GridLayout::FILL);
+
EnableControls();
}
@@ -190,15 +330,6 @@ void CollectedCookiesWin::OnTreeViewSelectionChanged(
}
///////////////////////////////////////////////////////////////////////////////
-// views::View implementation.
-
-gfx::Size CollectedCookiesWin::GetPreferredSize() {
- return gfx::Size(views::Window::GetLocalizedContentsSize(
- IDS_COOKIES_DIALOG_WIDTH_CHARS,
- IDS_COOKIES_DIALOG_HEIGHT_LINES));
-}
-
-///////////////////////////////////////////////////////////////////////////////
// CollectedCookiesWin, private methods.
void CollectedCookiesWin::EnableControls() {
@@ -234,6 +365,17 @@ void CollectedCookiesWin::AddContentException(views::TreeView* tree_view,
static_cast<CookieTreeOriginNode*>(tree_view->GetSelectedNode());
origin_node->CreateContentException(
tab_contents_->profile()->GetHostContentSettingsMap(), setting);
+ infobar_->UpdateVisibility(true, setting, origin_node->GetTitle());
+ gfx::Rect bounds;
+ GetWidget()->GetBounds(&bounds, false);
+ // WidgetWin::GetBounds returns the bounds relative to the parent window,
+ // while WidgetWin::SetBounds wants screen coordinates. Do the translation
+ // here until http://crbug.com/52851 is fixed.
+ POINT topleft = {bounds.x(), bounds.y()};
+ MapWindowPoints(HWND_DESKTOP, tab_contents_->GetNativeView(), &topleft, 1);
+ gfx::Size size = GetRootView()->GetPreferredSize();
+ bounds.SetRect(topleft.x, topleft.y, size.width(), size.height());
+ GetWidget()->SetBounds(bounds);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/views/collected_cookies_win.h b/chrome/browser/views/collected_cookies_win.h
index fc33d3c..d9f3c16 100644
--- a/chrome/browser/views/collected_cookies_win.h
+++ b/chrome/browser/views/collected_cookies_win.h
@@ -6,15 +6,18 @@
#ifndef CHROME_BROWSER_VIEWS_COLLECTED_COOKIES_WIN_H_
#define CHROME_BROWSER_VIEWS_COLLECTED_COOKIES_WIN_H_
+#pragma once
#include "chrome/browser/tab_contents/constrained_window.h"
#include "chrome/common/content_settings.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "views/controls/tree/tree_view.h"
#include "views/window/dialog_delegate.h"
class ConstrainedWindow;
class CookiesTreeModel;
+class InfobarView;
class TabContents;
namespace views {
class Label;
@@ -50,9 +53,6 @@ class CollectedCookiesWin : public ConstrainedDialogDelegate,
// views::TreeViewController implementation.
virtual void OnTreeViewSelectionChanged(views::TreeView* tree_view);
- // views::View implementation.
- virtual gfx::Size GetPreferredSize();
-
private:
virtual ~CollectedCookiesWin();
@@ -88,6 +88,8 @@ class CollectedCookiesWin : public ConstrainedDialogDelegate,
scoped_ptr<CookiesTreeModel> allowed_cookies_tree_model_;
scoped_ptr<CookiesTreeModel> blocked_cookies_tree_model_;
+ InfobarView* infobar_;
+
DISALLOW_COPY_AND_ASSIGN(CollectedCookiesWin);
};
diff --git a/chrome/browser/views/confirm_message_box_dialog.h b/chrome/browser/views/confirm_message_box_dialog.h
index 3c303b7..c0c5da7 100644
--- a/chrome/browser/views/confirm_message_box_dialog.h
+++ b/chrome/browser/views/confirm_message_box_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_CONFIRM_MESSAGE_BOX_DIALOG_H_
#define CHROME_BROWSER_VIEWS_CONFIRM_MESSAGE_BOX_DIALOG_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/constrained_window_win.cc b/chrome/browser/views/constrained_window_win.cc
index c8924f0..f997c3d 100644
--- a/chrome/browser/views/constrained_window_win.cc
+++ b/chrome/browser/views/constrained_window_win.cc
@@ -4,13 +4,11 @@
#include "chrome/browser/views/constrained_window_win.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "app/text_elider.h"
#include "app/win_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_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/tab_contents/tab_contents_view.h"
@@ -46,11 +44,6 @@ class ClientView;
enum {
FRAME_PART_BITMAP_FIRST = 0, // Must be first.
- // Window Controls.
- FRAME_CLOSE_BUTTON_ICON,
- FRAME_CLOSE_BUTTON_ICON_H,
- FRAME_CLOSE_BUTTON_ICON_P,
-
// Window Frame Border.
FRAME_BOTTOM_EDGE,
FRAME_BOTTOM_LEFT_CORNER,
@@ -61,33 +54,22 @@ enum {
FRAME_TOP_LEFT_CORNER,
FRAME_TOP_RIGHT_CORNER,
- FRAME_WINDOW,
- FRAME_WINDOW_INACTIVE,
- FRAME_WINDOW_INCOGNITO,
- FRAME_WINDOW_INCOGNITO_INACTIVE,
-
FRAME_PART_BITMAP_COUNT // Must be last.
};
static const int kXPFramePartIDs[] = {
0,
- IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P,
IDR_WINDOW_BOTTOM_CENTER, IDR_WINDOW_BOTTOM_LEFT_CORNER,
IDR_WINDOW_BOTTOM_RIGHT_CORNER, IDR_WINDOW_LEFT_SIDE,
IDR_WINDOW_RIGHT_SIDE, IDR_WINDOW_TOP_CENTER,
IDR_WINDOW_TOP_LEFT_CORNER, IDR_WINDOW_TOP_RIGHT_CORNER,
- IDR_THEME_FRAME, IDR_THEME_FRAME_INACTIVE, IDR_THEME_FRAME_INCOGNITO,
- IDR_THEME_FRAME_INCOGNITO_INACTIVE,
0 };
static const int kVistaFramePartIDs[] = {
0,
- IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P,
IDR_CONSTRAINED_BOTTOM_CENTER_V, IDR_CONSTRAINED_BOTTOM_LEFT_CORNER_V,
IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER_V, IDR_CONSTRAINED_LEFT_SIDE_V,
IDR_CONSTRAINED_RIGHT_SIDE_V, IDR_CONSTRAINED_TOP_CENTER_V,
IDR_CONSTRAINED_TOP_LEFT_CORNER_V, IDR_CONSTRAINED_TOP_RIGHT_CORNER_V,
- IDR_THEME_FRAME, IDR_THEME_FRAME_INACTIVE, IDR_THEME_FRAME_INCOGNITO,
- IDR_THEME_FRAME_INCOGNITO_INACTIVE,
0 };
class XPWindowResources : public views::WindowResources {
@@ -178,7 +160,7 @@ class ConstrainedWindowFrameView
// Overridden from views::View:
virtual void Paint(gfx::Canvas* canvas);
virtual void Layout();
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
@@ -279,12 +261,13 @@ ConstrainedWindowFrameView::ConstrainedWindowFrameView(
InitClass();
InitWindowResources();
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
close_button_->SetImage(views::CustomButton::BS_NORMAL,
- resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON));
+ rb.GetBitmapNamed(IDR_CLOSE_SA));
close_button_->SetImage(views::CustomButton::BS_HOT,
- resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_H));
+ rb.GetBitmapNamed(IDR_CLOSE_SA_H));
close_button_->SetImage(views::CustomButton::BS_PUSHED,
- resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_P));
+ rb.GetBitmapNamed(IDR_CLOSE_SA_P));
close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
views::ImageButton::ALIGN_MIDDLE);
AddChildView(close_button_);
@@ -372,7 +355,7 @@ void ConstrainedWindowFrameView::Layout() {
client_view_bounds_ = CalculateClientAreaBounds(width(), height());
}
-void ConstrainedWindowFrameView::ThemeChanged() {
+void ConstrainedWindowFrameView::OnThemeChanged() {
InitWindowResources();
}
@@ -529,7 +512,7 @@ void ConstrainedWindowFrameView::LayoutTitleBar() {
// there is no icon in constrained windows.
gfx::Rect icon_bounds(IconBounds());
int title_x = icon_bounds.x();
- int title_height = title_font_->height();
+ int title_height = title_font_->GetHeight();
// We bias the title position so that when the difference between the icon and
// title heights is odd, the extra pixel of the title is above the vertical
// midline rather than below. This compensates for how the icon is already
@@ -580,15 +563,20 @@ views::NonClientFrameView* ConstrainedWindowWin::CreateFrameViewForWindow() {
}
void ConstrainedWindowWin::FocusConstrainedWindow() {
- focused_view_->RequestFocus();
+ if ((!owner_->delegate() ||
+ owner_->delegate()->ShouldFocusConstrainedWindow(owner_)) &&
+ GetDelegate() && GetDelegate()->GetInitiallyFocusedView()) {
+ GetDelegate()->GetInitiallyFocusedView()->RequestFocus();
+ }
}
void ConstrainedWindowWin::ShowConstrainedWindow() {
+ if (owner_->delegate())
+ owner_->delegate()->WillShowConstrainedWindow(owner_);
ActivateConstrainedWindow();
FocusConstrainedWindow();
}
-
void ConstrainedWindowWin::CloseConstrainedWindow() {
// Broadcast to all observers of NOTIFY_CWINDOW_CLOSED.
// One example of such an observer is AutomationCWindowTracker in the
@@ -628,9 +616,6 @@ ConstrainedWindowWin::ConstrainedWindowWin(
set_focus_on_creation(false);
WindowWin::Init(owner_->GetNativeView(), gfx::Rect());
-
- focused_view_ = window_delegate->GetContentsView();
- DCHECK(focused_view_);
}
void ConstrainedWindowWin::ActivateConstrainedWindow() {
diff --git a/chrome/browser/views/constrained_window_win.h b/chrome/browser/views/constrained_window_win.h
index 69a83dc..9b17bf6 100644
--- a/chrome/browser/views/constrained_window_win.h
+++ b/chrome/browser/views/constrained_window_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_CONSTRAINED_WINDOW_WIN_H_
#define CHROME_BROWSER_VIEWS_CONSTRAINED_WINDOW_WIN_H_
+#pragma once
#include "chrome/browser/tab_contents/constrained_window.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -70,7 +71,6 @@ class ConstrainedWindowWin : public ConstrainedWindow,
// Current display rectangle (relative to owner_'s visible area).
gfx::Rect current_bounds_;
- views::View* focused_view_;
DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowWin);
};
diff --git a/chrome/browser/views/content_blocked_bubble_contents.cc b/chrome/browser/views/content_blocked_bubble_contents.cc
deleted file mode 100644
index bef80be..0000000
--- a/chrome/browser/views/content_blocked_bubble_contents.cc
+++ /dev/null
@@ -1,323 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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/content_blocked_bubble_contents.h"
-
-#if defined(OS_LINUX)
-#include <gdk/gdk.h>
-#endif
-
-#include "app/l10n_util.h"
-#include "chrome/browser/blocked_popup_container.h"
-#include "chrome/browser/content_setting_bubble_model.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/views/browser_dialogs.h"
-#include "chrome/browser/views/info_bubble.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-#include "grit/generated_resources.h"
-#include "views/controls/button/native_button.h"
-#include "views/controls/button/radio_button.h"
-#include "views/controls/image_view.h"
-#include "views/controls/label.h"
-#include "views/controls/separator.h"
-#include "views/grid_layout.h"
-#include "views/standard_layout.h"
-
-class ContentSettingBubbleContents::Favicon : public views::ImageView {
- public:
- Favicon(const SkBitmap& image,
- ContentSettingBubbleContents* parent,
- views::Link* link);
- virtual ~Favicon();
-
- private:
-#if defined(OS_WIN)
- static HCURSOR g_hand_cursor;
-#endif
-
- // views::View overrides:
- virtual bool OnMousePressed(const views::MouseEvent& event);
- virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
- virtual gfx::NativeCursor GetCursorForPoint(
- views::Event::EventType event_type,
- const gfx::Point& p);
-
- ContentSettingBubbleContents* parent_;
- views::Link* link_;
-};
-
-#if defined(OS_WIN)
-HCURSOR ContentSettingBubbleContents::Favicon::g_hand_cursor = NULL;
-#endif
-
-ContentSettingBubbleContents::Favicon::Favicon(
- const SkBitmap& image,
- ContentSettingBubbleContents* parent,
- views::Link* link)
- : parent_(parent),
- link_(link) {
- SetImage(image);
-}
-
-ContentSettingBubbleContents::Favicon::~Favicon() {
-}
-
-bool ContentSettingBubbleContents::Favicon::OnMousePressed(
- const views::MouseEvent& event) {
- return event.IsLeftMouseButton() || event.IsMiddleMouseButton();
-}
-
-void ContentSettingBubbleContents::Favicon::OnMouseReleased(
- const views::MouseEvent& event,
- bool canceled) {
- if (!canceled &&
- (event.IsLeftMouseButton() || event.IsMiddleMouseButton()) &&
- HitTest(event.location()))
- parent_->LinkActivated(link_, event.GetFlags());
-}
-
-gfx::NativeCursor ContentSettingBubbleContents::Favicon::GetCursorForPoint(
- views::Event::EventType event_type,
- const gfx::Point& p) {
-#if defined(OS_WIN)
- if (!g_hand_cursor)
- g_hand_cursor = LoadCursor(NULL, IDC_HAND);
- return g_hand_cursor;
-#elif defined(OS_LINUX)
- return gdk_cursor_new(GDK_HAND2);
-#endif
-}
-
-ContentSettingBubbleContents::ContentSettingBubbleContents(
- ContentSettingBubbleModel* content_setting_bubble_model,
- Profile* profile,
- TabContents* tab_contents)
- : content_setting_bubble_model_(content_setting_bubble_model),
- profile_(profile),
- tab_contents_(tab_contents),
- info_bubble_(NULL),
- close_button_(NULL),
- manage_link_(NULL),
- clear_link_(NULL),
- info_link_(NULL) {
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents));
-}
-
-ContentSettingBubbleContents::~ContentSettingBubbleContents() {
-}
-
-void ContentSettingBubbleContents::ViewHierarchyChanged(bool is_add,
- View* parent,
- View* child) {
- if (is_add && (child == this))
- InitControlLayout();
-}
-
-void ContentSettingBubbleContents::ButtonPressed(views::Button* sender,
- const views::Event& event) {
- if (sender == close_button_) {
- info_bubble_->set_fade_away_on_close(true);
- info_bubble_->Close(); // CAREFUL: This deletes us.
- return;
- }
-
- for (RadioGroup::const_iterator i = radio_group_.begin();
- i != radio_group_.end(); ++i) {
- if (sender == *i) {
- content_setting_bubble_model_->OnRadioClicked(i - radio_group_.begin());
- return;
- }
- }
- NOTREACHED() << "unknown radio";
-}
-
-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();
- info_bubble_->set_fade_away_on_close(true);
- info_bubble_->Close(); // CAREFUL: This deletes us.
- return;
- }
-
- PopupLinks::const_iterator i(popup_links_.find(source));
- DCHECK(i != popup_links_.end());
- content_setting_bubble_model_->OnPopupClicked(i->second);
-}
-
-void ContentSettingBubbleContents::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
- DCHECK(source == Source<TabContents>(tab_contents_));
- tab_contents_ = NULL;
-}
-
-void ContentSettingBubbleContents::InitControlLayout() {
- using views::GridLayout;
-
- GridLayout* layout = new views::GridLayout(this);
- SetLayoutManager(layout);
-
- const int single_column_set_id = 0;
- views::ColumnSet* column_set = layout->AddColumnSet(single_column_set_id);
- column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
-
- const ContentSettingBubbleModel::BubbleContent& bubble_content =
- content_setting_bubble_model_->bubble_content();
-
- 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);
- }
-
- if (content_setting_bubble_model_->content_type() ==
- CONTENT_SETTINGS_TYPE_POPUPS) {
- const int popup_column_set_id = 2;
- views::ColumnSet* popup_column_set =
- layout->AddColumnSet(popup_column_set_id);
- popup_column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
- GridLayout::USE_PREF, 0, 0);
- popup_column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- popup_column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
-
- 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())
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, popup_column_set_id);
-
- views::Link* link = new views::Link(UTF8ToWide(i->title));
- link->SetController(this);
- popup_links_[link] = i - bubble_content.popup_items.begin();
- layout->AddView(new Favicon((*i).bitmap, this, link));
- layout->AddView(link);
- }
- 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);
- // 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);
- }
-
- gfx::Font domain_font =
- views::Label().font().DeriveFont(0, gfx::Font::BOLD);
- const int indented_single_column_set_id = 3;
- // Insert a column set to indent the domain list.
- views::ColumnSet* indented_single_column_set =
- layout->AddColumnSet(indented_single_column_set_id);
- indented_single_column_set->AddPaddingColumn(0, kPanelHorizIndentation);
- indented_single_column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL,
- 1, GridLayout::USE_PREF, 0, 0);
- for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i =
- bubble_content.domain_lists.begin();
- i != bubble_content.domain_lists.end(); ++i) {
- layout->StartRow(0, single_column_set_id);
- views::Label* section_title = new views::Label(UTF8ToWide(i->title));
- section_title->SetMultiLine(true);
- // TODO(joth): Should need to have hard coded size here, but without it
- // we get empty space at very end of bubble (as it's initially sized really
- // tall & skinny but then widens once the link/buttons are added
- // at the end of this method).
- section_title->SizeToFit(256);
- section_title->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
- layout->AddView(section_title, 1, 1, GridLayout::FILL, GridLayout::LEADING);
- for (std::set<std::string>::const_iterator j = i->hosts.begin();
- j != i->hosts.end(); ++j) {
- 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);
- }
-
- 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);
- layout->StartRow(0, single_column_set_id);
- layout->AddView(new views::Separator, 1, 1,
- GridLayout::FILL, GridLayout::FILL);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- }
-
- const int double_column_set_id = 1;
- views::ColumnSet* double_column_set =
- layout->AddColumnSet(double_column_set_id);
- double_column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
- GridLayout::USE_PREF, 0, 0);
- double_column_set->AddPaddingColumn(0, kUnrelatedControlHorizontalSpacing);
- double_column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
- GridLayout::USE_PREF, 0, 0);
-
- layout->StartRow(0, double_column_set_id);
- manage_link_ = new views::Link(UTF8ToWide(bubble_content.manage_link));
- manage_link_->SetController(this);
- layout->AddView(manage_link_);
-
- close_button_ =
- new views::NativeButton(this, l10n_util::GetString(IDS_DONE));
- layout->AddView(close_button_);
-}
diff --git a/chrome/browser/views/content_blocked_bubble_contents.h b/chrome/browser/views/content_blocked_bubble_contents.h
deleted file mode 100644
index bdbaf9e..0000000
--- a/chrome/browser/views/content_blocked_bubble_contents.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_VIEWS_CONTENT_BLOCKED_BUBBLE_CONTENTS_H_
-#define CHROME_BROWSER_VIEWS_CONTENT_BLOCKED_BUBBLE_CONTENTS_H_
-
-#include <map>
-#include <string>
-
-#include "chrome/common/content_settings_types.h"
-#include "chrome/common/notification_registrar.h"
-#include "views/controls/button/button.h"
-#include "views/controls/link.h"
-
-// ContentSettingBubbleContents is used when the user turns on different kinds
-// of content blocking (e.g. "block images"). When viewing a page with blocked
-// content, icons appear in the omnibox corresponding to the content types that
-// were blocked, and the user can click one to get a bubble hosting a few
-// controls. This class provides the content of that bubble. In general,
-// these bubbles typically have a title, a pair of radio buttons for toggling
-// the blocking settings for the current site, a close button, and a link to
-// get to a more comprehensive settings management dialog. A few types have
-// more or fewer controls than this.
-
-class ContentSettingBubbleModel;
-class InfoBubble;
-class Profile;
-class TabContents;
-
-namespace views {
-class NativeButton;
-class RadioButton;
-}
-
-// TODO(bulach): rename this file.
-class ContentSettingBubbleContents : public views::View,
- public views::ButtonListener,
- public views::LinkController,
- public NotificationObserver {
- public:
- ContentSettingBubbleContents(
- ContentSettingBubbleModel* content_setting_bubble_model,
- Profile* profile, TabContents* tab_contents);
- virtual ~ContentSettingBubbleContents();
-
- // Sets |info_bubble_|, so we can close the bubble if needed. The caller owns
- // the bubble and must keep it alive.
- void set_info_bubble(InfoBubble* info_bubble) { info_bubble_ = info_bubble; }
-
- private:
- class Favicon;
-
- typedef std::map<views::Link*, int> PopupLinks;
-
- // Overridden from views::View:
- virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
-
- // views::ButtonListener:
- virtual void ButtonPressed(views::Button* sender, const views::Event& event);
-
- // views::LinkController:
- virtual void LinkActivated(views::Link* source, int event_flags);
-
- // NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Creates the child views.
- void InitControlLayout();
-
- // Provides data for this bubble.
- scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model_;
-
- // The active profile.
- Profile* profile_;
-
- // The active tab contents.
- TabContents* tab_contents_;
-
- // A registrar for listening for TAB_CONTENTS_DESTROYED notifications.
- NotificationRegistrar registrar_;
-
- // The InfoBubble holding us.
- InfoBubble* info_bubble_;
-
- // Some of our controls, so we can tell what's been clicked when we get a
- // message.
- PopupLinks popup_links_;
- typedef std::vector<views::RadioButton*> RadioGroup;
- RadioGroup radio_group_;
- views::NativeButton* close_button_;
- views::Link* manage_link_;
- views::Link* clear_link_;
- views::Link* info_link_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(ContentSettingBubbleContents);
-};
-
-#endif // CHROME_BROWSER_VIEWS_CONTENT_BLOCKED_BUBBLE_CONTENTS_H_
diff --git a/chrome/browser/views/cookie_info_view.cc b/chrome/browser/views/cookie_info_view.cc
index 4727bd1..f2a1bb1 100644
--- a/chrome/browser/views/cookie_info_view.cc
+++ b/chrome/browser/views/cookie_info_view.cc
@@ -9,7 +9,9 @@
#include "app/l10n_util.h"
#include "base/i18n/time_formatting.h"
#include "base/message_loop.h"
+#include "base/string16.h"
#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"
@@ -149,8 +151,8 @@ int CookieInfoView::GetItemCount() {
return static_cast<int>(expire_combo_values_.size());
}
-std::wstring CookieInfoView::GetItemAt(int index) {
- return expire_combo_values_[index];
+string16 CookieInfoView::GetItemAt(int index) {
+ return WideToUTF16Hack(expire_combo_values_[index]);
}
void CookieInfoView::AddLabelRow(int layout_id, views::GridLayout* layout,
diff --git a/chrome/browser/views/cookie_info_view.h b/chrome/browser/views/cookie_info_view.h
index 8db996e..2099a00 100644
--- a/chrome/browser/views/cookie_info_view.h
+++ b/chrome/browser/views/cookie_info_view.h
@@ -4,11 +4,13 @@
#ifndef CHROME_BROWSER_VIEWS_COOKIE_INFO_VIEW_H_
#define CHROME_BROWSER_VIEWS_COOKIE_INFO_VIEW_H_
+#pragma once
#include <string>
#include <vector>
#include "app/combobox_model.h"
+#include "base/string16.h"
#include "net/base/cookie_monster.h"
#include "views/controls/combobox/combobox.h"
#include "views/view.h"
@@ -72,7 +74,7 @@ class CookieInfoView : public views::View,
// ComboboxModel overrides for expires_value_combobox_.
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
private:
// Layout helper routines.
diff --git a/chrome/browser/views/cookie_prompt_view.cc b/chrome/browser/views/cookie_prompt_view.cc
deleted file mode 100644
index 33f85af..0000000
--- a/chrome/browser/views/cookie_prompt_view.cc
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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/cookie_prompt_view.h"
-
-#include <algorithm>
-
-#include "app/l10n_util.h"
-#include "base/i18n/time_formatting.h"
-#include "base/message_loop.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/cookie_modal_dialog.h"
-#include "chrome/browser/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/browser_dialogs.h"
-#include "chrome/browser/views/cookie_info_view.h"
-#include "chrome/browser/views/database_open_info_view.h"
-#include "chrome/browser/views/generic_info_view.h"
-#include "chrome/browser/views/local_storage_set_item_info_view.h"
-#include "chrome/browser/views/options/content_settings_window_view.h"
-#include "chrome/common/pref_names.h"
-#include "gfx/canvas.h"
-#include "gfx/color_utils.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "net/base/cookie_monster.h"
-#include "views/controls/label.h"
-#include "views/controls/button/native_button.h"
-#include "views/controls/button/radio_button.h"
-#include "views/controls/textfield/textfield.h"
-#include "views/grid_layout.h"
-#include "views/standard_layout.h"
-#include "views/window/non_client_view.h"
-
-static const int kCookiePromptViewInsetSize = 5;
-
-///////////////////////////////////////////////////////////////////////////////
-// CookiePromptView, public:
-
-CookiePromptView::CookiePromptView(
- CookiePromptModalDialog* parent,
- gfx::NativeWindow root_window,
- Profile* profile)
- : remember_radio_(NULL),
- ask_radio_(NULL),
- allow_button_(NULL),
- block_button_(NULL),
- show_cookie_link_(NULL),
- info_view_(NULL),
- session_expire_(false),
- expanded_view_(false),
- signaled_(false),
- parent_(parent),
- root_window_(root_window),
- profile_(profile) {
- InitializeViewResources();
- expanded_view_ = profile_->GetPrefs()->
- GetBoolean(prefs::kCookiePromptExpanded);
-}
-
-CookiePromptView::~CookiePromptView() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CookiePromptView, views::View overrides:
-
-gfx::Size CookiePromptView::GetPreferredSize() {
- gfx::Size client_size = views::View::GetPreferredSize();
- return gfx::Size(client_size.width(),
- client_size.height() + GetExtendedViewHeight());
-}
-
-
-void CookiePromptView::ViewHierarchyChanged(bool is_add,
- views::View* parent,
- views::View* child) {
- if (is_add && child == this)
- Init();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CookiePromptView, ModalDialogDelegate implementation:
-
-gfx::NativeWindow CookiePromptView::GetDialogRootWindow() {
- return root_window_;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CookiePromptView, views::DialogDelegate implementation:
-
-std::wstring CookiePromptView::GetWindowTitle() const {
- return title_;
-}
-
-void CookiePromptView::WindowClosing() {
- if (!signaled_)
- parent_->BlockSiteData(false);
- parent_->CompleteDialog();
-}
-
-views::View* CookiePromptView::GetContentsView() {
- return this;
-}
-
-bool CookiePromptView::Accept() {
- parent_->AllowSiteData(remember_radio_->checked(), session_expire_);
- signaled_ = true;
- return true;
-}
-
-// CookieInfoViewDelegate overrides:
-void CookiePromptView::ModifyExpireDate(bool session_expire) {
- session_expire_ = session_expire;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// CookiePromptView, views::ButtonListener implementation:
-
-void CookiePromptView::ButtonPressed(views::Button* sender,
- const views::Event& event) {
- if (sender == allow_button_) {
- Accept();
- GetWindow()->Close();
- } else if (sender == block_button_) {
- parent_->BlockSiteData(remember_radio_->checked());
- signaled_ = true;
- GetWindow()->Close();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CookiePromptView, views::LinkController implementation:
-void CookiePromptView::LinkActivated(views::Link* source, int event_flags) {
- DCHECK_EQ(source, show_cookie_link_);
- ToggleDetailsViewExpand();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// CookiePromptView, private:
-
-void CookiePromptView::Init() {
- CookiePromptModalDialog::DialogType type = parent_->dialog_type();
- std::wstring display_host = UTF8ToWide(parent_->origin().host());
- views::Label* description_label = new views::Label(l10n_util::GetStringF(
- type == CookiePromptModalDialog::DIALOG_TYPE_COOKIE ?
- IDS_COOKIE_ALERT_LABEL : IDS_DATA_ALERT_LABEL,
- display_host));
- int radio_group_id = 0;
- remember_radio_ = new views::RadioButton(
- l10n_util::GetStringF(IDS_COOKIE_ALERT_REMEMBER_RADIO, display_host),
- radio_group_id);
- remember_radio_->set_listener(this);
- ask_radio_ = new views::RadioButton(
- l10n_util::GetString(IDS_COOKIE_ALERT_ASK_RADIO), radio_group_id);
- ask_radio_->set_listener(this);
- allow_button_ = new views::NativeButton(
- this, l10n_util::GetString(IDS_COOKIE_ALERT_ALLOW_BUTTON));
- block_button_ = new views::NativeButton(
- this, l10n_util::GetString(IDS_COOKIE_ALERT_BLOCK_BUTTON));
- show_cookie_link_ = new views::Link(
- l10n_util::GetString(IDS_COOKIE_SHOW_DETAILS_LABEL));
- show_cookie_link_->SetController(this);
-
- using views::GridLayout;
-
- GridLayout* layout = CreatePanelGridLayout(this);
- layout->SetInsets(kCookiePromptViewInsetSize, kCookiePromptViewInsetSize,
- kCookiePromptViewInsetSize, kCookiePromptViewInsetSize);
- SetLayoutManager(layout);
-
- const int one_column_layout_id = 0;
- views::ColumnSet* one_column_set = layout->AddColumnSet(one_column_layout_id);
- one_column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- one_column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
- GridLayout::USE_PREF, 0, 0);
- one_column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, one_column_layout_id);
- layout->AddView(description_label);
- layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
- layout->StartRow(0, one_column_layout_id);
- layout->AddView(remember_radio_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, one_column_layout_id);
- layout->AddView(ask_radio_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- View* button_container = new View();
- GridLayout* button_layout = new GridLayout(button_container);
- button_container->SetLayoutManager(button_layout);
- const int inner_column_layout_id = 1;
- views::ColumnSet* inner_column_set = button_layout->AddColumnSet(
- inner_column_layout_id);
- inner_column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
- GridLayout::USE_PREF, 0, 0);
- inner_column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- inner_column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
- GridLayout::USE_PREF, 0, 0);
- inner_column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- inner_column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
- GridLayout::USE_PREF, 0, 0);
- button_layout->StartRow(0, inner_column_layout_id);
- button_layout->AddView(show_cookie_link_, 1, 1,
- GridLayout::LEADING, GridLayout::TRAILING);
- button_layout->AddView(allow_button_);
- button_layout->AddView(block_button_);
-
- int button_column_layout_id = 2;
- views::ColumnSet* button_column_set =
- layout->AddColumnSet(button_column_layout_id);
- button_column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- button_column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
- GridLayout::USE_PREF, 0, 0);
- button_column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- layout->StartRow(0, one_column_layout_id);
- layout->AddView(button_container, 1, 1,
- GridLayout::FILL, GridLayout::CENTER);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, one_column_layout_id);
-
- if (type == CookiePromptModalDialog::DIALOG_TYPE_COOKIE) {
- CookieInfoView* cookie_info_view = new CookieInfoView(true);
- cookie_info_view->set_delegate(this);
- layout->AddView(cookie_info_view, 1, 1, GridLayout::FILL,
- GridLayout::CENTER);
-
- cookie_info_view->SetCookieString(parent_->origin(),
- parent_->cookie_line());
- info_view_ = cookie_info_view;
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_LOCAL_STORAGE) {
- LocalStorageSetItemInfoView* view = new LocalStorageSetItemInfoView();
- layout->AddView(view, 1, 1, GridLayout::FILL, GridLayout::CENTER);
- view->SetFields(parent_->origin().host(),
- parent_->local_storage_key(),
- parent_->local_storage_value());
- info_view_ = view;
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_DATABASE) {
- DatabaseOpenInfoView* view = new DatabaseOpenInfoView();
- layout->AddView(view, 1, 1, GridLayout::FILL, GridLayout::CENTER);
- view->SetFields(parent_->origin().host(),
- parent_->database_name(),
- parent_->display_name(),
- parent_->estimated_size());
- info_view_ = view;
- } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) {
- static const int kAppCacheInfoLabels[] = {
- IDS_COOKIES_APPLICATION_CACHE_MANIFEST_LABEL
- };
- GenericInfoView* view = new GenericInfoView(ARRAYSIZE(kAppCacheInfoLabels),
- kAppCacheInfoLabels);
- layout->AddView(view, 1, 1, GridLayout::FILL, GridLayout::CENTER);
- view->SetValue(0, UTF8ToUTF16(parent_->appcache_manifest_url().spec()));
- info_view_ = view;
- } else {
- NOTIMPLEMENTED();
- }
-
- info_view_->SetVisible(expanded_view_);
-
- // Set default values.
- remember_radio_->SetChecked(true);
-}
-
-int CookiePromptView::GetExtendedViewHeight() {
- DCHECK(info_view_);
- return expanded_view_ ?
- 0 : -info_view_->GetPreferredSize().height();
-}
-
-void CookiePromptView::ToggleDetailsViewExpand() {
- int old_extended_height = GetExtendedViewHeight();
-
- expanded_view_ = !expanded_view_;
- profile_->GetPrefs()->SetBoolean(prefs::kCookiePromptExpanded,
- expanded_view_);
-
- // We have to set the visbility before asking for the extended view height
- // again as there is a bug in combobox that results in preferred height
- // changing when visible and not visible.
- info_view_->SetVisible(expanded_view_);
- int extended_height_delta = GetExtendedViewHeight() - old_extended_height;
- views::Window* window = GetWindow();
- gfx::Rect bounds = window->GetBounds();
- bounds.set_height(bounds.height() + extended_height_delta);
- window->SetBounds(bounds, NULL);
-}
-
-void CookiePromptView::InitializeViewResources() {
- CookiePromptModalDialog::DialogType type = parent_->dialog_type();
- title_ = l10n_util::GetStringF(
- type == CookiePromptModalDialog::DIALOG_TYPE_COOKIE ?
- IDS_COOKIE_ALERT_TITLE : IDS_DATA_ALERT_TITLE,
- UTF8ToWide(parent_->origin().host()));
-}
diff --git a/chrome/browser/views/cookie_prompt_view.h b/chrome/browser/views/cookie_prompt_view.h
deleted file mode 100644
index 481389a..0000000
--- a/chrome/browser/views/cookie_prompt_view.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_VIEWS_COOKIE_PROMPT_VIEW_H_
-#define CHROME_BROWSER_VIEWS_COOKIE_PROMPT_VIEW_H_
-
-#include <string>
-
-#include "base/task.h"
-#include "chrome/browser/browsing_data_local_storage_helper.h"
-#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h"
-#include "chrome/browser/views/cookie_info_view.h"
-#include "chrome/browser/views/modal_dialog_delegate.h"
-#include "googleurl/src/gurl.h"
-#include "views/controls/button/button.h"
-#include "views/controls/link.h"
-#include "views/view.h"
-#include "views/window/dialog_delegate.h"
-#include "views/window/window.h"
-
-namespace views {
-class NativeButton;
-class RadioButton;
-}
-
-class CookieInfoView;
-class CookiePromptModalDialog;
-class LocalStorageInfoView;
-class Profile;
-class Timer;
-
-// Cookie alert dialog UI.
-class CookiePromptView : public views::View,
- public ModalDialogDelegate,
- public views::ButtonListener,
- public views::LinkController,
- public CookieInfoViewDelegate {
- public:
- // Creates a new CookiePromptView. We take ownership of |parent|.
- CookiePromptView(
- CookiePromptModalDialog* parent,
- gfx::NativeWindow root_window,
- Profile* profile);
-
- virtual ~CookiePromptView();
-
- protected:
- // views::View overrides.
- virtual gfx::Size GetPreferredSize();
- virtual void ViewHierarchyChanged(bool is_add,
- views::View* parent,
- views::View* child);
-
- // ModalDialogDelegate overrides.
- virtual gfx::NativeWindow GetDialogRootWindow();
-
- // views::DialogDelegate overrides.
- virtual bool CanResize() const { return false; }
- virtual std::wstring GetWindowTitle() const;
- virtual void WindowClosing();
- virtual views::View* GetContentsView();
- virtual bool IsModal() const { return true; }
- virtual bool Accept();
-
- // views::ButtonListener overrides.
- virtual void ButtonPressed(views::Button* sender, const views::Event& event);
-
- // views::LinkController overrides.
- virtual void LinkActivated(views::Link* source, int event_flags);
-
- // views::WindowDelegate overrides.
- virtual int GetDialogButtons() const {
- return MessageBoxFlags::DIALOGBUTTON_NONE;
- }
-
- // CookieInfoViewDelegate overrides:
- virtual void ModifyExpireDate(bool session_expire);
-
- private:
- // Initialize the dialog layout.
- void Init();
-
- // Shows or hides cooke info view and changes parent.
- void ToggleDetailsViewExpand();
-
- // Calculates view size offset depending on visibility of cookie details.
- int GetExtendedViewHeight();
-
- // Initializes text resources needed to display this view.
- void InitializeViewResources();
-
- views::RadioButton* remember_radio_;
- views::RadioButton* ask_radio_;
- views::NativeButton* allow_button_;
- views::NativeButton* block_button_;
- views::Link* show_cookie_link_;
- views::View* info_view_;
-
- // True if cookie should expire with this session.
- bool session_expire_;
-
- // True if cookie info view is currently shown and window expanded.
- bool expanded_view_;
-
- // True if the outcome of this dialog has been signaled to the delegate.
- bool signaled_;
-
- // Prompt window title.
- std::wstring title_;
-
- // A pointer to the AppModalDialog that created us. We own this.
- scoped_ptr<CookiePromptModalDialog> parent_;
-
- gfx::NativeWindow root_window_;
-
- Profile* profile_;
-
- DISALLOW_COPY_AND_ASSIGN(CookiePromptView);
-};
-
-#endif // CHROME_BROWSER_VIEWS_COOKIE_PROMPT_VIEW_H_
diff --git a/chrome/browser/views/create_application_shortcut_view.cc b/chrome/browser/views/create_application_shortcut_view.cc
index b0a66b3..3308315 100644
--- a/chrome/browser/views/create_application_shortcut_view.cc
+++ b/chrome/browser/views/create_application_shortcut_view.cc
@@ -7,7 +7,8 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "chrome/browser/pref_service.h"
+#include "base/utf_string_conversions.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"
diff --git a/chrome/browser/views/create_application_shortcut_view.h b/chrome/browser/views/create_application_shortcut_view.h
index 8daefd1..d3112f2 100644
--- a/chrome/browser/views/create_application_shortcut_view.h
+++ b/chrome/browser/views/create_application_shortcut_view.h
@@ -1,12 +1,12 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_CREATE_APPLICATION_SHORTCUT_VIEW_H_
#define CHROME_BROWSER_VIEWS_CREATE_APPLICATION_SHORTCUT_VIEW_H_
+#pragma once
#include <string>
-#include <vector>
#include "chrome/browser/web_applications/web_app.h"
#include "views/controls/label.h"
diff --git a/chrome/browser/views/database_info_view.h b/chrome/browser/views/database_info_view.h
index b6b6279..269d3c4 100644
--- a/chrome/browser/views/database_info_view.h
+++ b/chrome/browser/views/database_info_view.h
@@ -4,9 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_DATABASE_INFO_VIEW_H_
#define CHROME_BROWSER_VIEWS_DATABASE_INFO_VIEW_H_
-
-#include <string>
-#include <vector>
+#pragma once
#include "views/view.h"
#include "chrome/browser/browsing_data_database_helper.h"
diff --git a/chrome/browser/views/database_open_info_view.cc b/chrome/browser/views/database_open_info_view.cc
index 1e0fbc2..02e7fae 100644
--- a/chrome/browser/views/database_open_info_view.cc
+++ b/chrome/browser/views/database_open_info_view.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/views/database_open_info_view.h"
-#include "app/l10n_util.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/views/database_open_info_view.h b/chrome/browser/views/database_open_info_view.h
index 63d24e2..81926ae 100644
--- a/chrome/browser/views/database_open_info_view.h
+++ b/chrome/browser/views/database_open_info_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_DATABASE_OPEN_INFO_VIEW_H_
#define CHROME_BROWSER_VIEWS_DATABASE_OPEN_INFO_VIEW_H_
+#pragma once
#include "base/string16.h"
#include "chrome/browser/views/generic_info_view.h"
diff --git a/chrome/browser/views/detachable_toolbar_view.cc b/chrome/browser/views/detachable_toolbar_view.cc
index ba44f3d..e2aaa3a 100644
--- a/chrome/browser/views/detachable_toolbar_view.cc
+++ b/chrome/browser/views/detachable_toolbar_view.cc
@@ -1,16 +1,17 @@
-// 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.
#include "chrome/browser/views/detachable_toolbar_view.h"
#include "app/resource_bundle.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "gfx/canvas_skia.h"
#include "gfx/skia_util.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkShader.h"
+#include "views/window/non_client_view.h"
// How round the 'new tab' style bookmarks bar is.
static const int kNewtabBarRoundness = 5;
@@ -21,21 +22,18 @@ const SkColor DetachableToolbarView::kMiddleDividerColor =
SkColorSetRGB(194, 205, 212);
// static
-void DetachableToolbarView::PaintBackgroundAttachedMode(gfx::Canvas* canvas,
- views::View* view) {
- gfx::Rect bounds =
- view->GetBounds(views::View::APPLY_MIRRORING_TRANSFORMATION);
-
+void DetachableToolbarView::PaintBackgroundAttachedMode(
+ gfx::Canvas* canvas,
+ views::View* view,
+ const gfx::Point& background_origin) {
ThemeProvider* tp = view->GetThemeProvider();
SkColor theme_toolbar_color =
tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
canvas->FillRectInt(theme_toolbar_color, 0, 0,
view->width(), view->height());
-
canvas->TileImageInt(*tp->GetBitmapNamed(IDR_THEME_TOOLBAR),
- view->GetParent()->GetBounds(
- views::View::APPLY_MIRRORING_TRANSFORMATION).x() + bounds.x(),
- bounds.y(), 0, 0, view->width(), view->height());
+ background_origin.x(), background_origin.y(), 0, 0,
+ view->width(), view->height());
}
// static
@@ -57,9 +55,10 @@ void DetachableToolbarView::PaintHorizontalBorder(gfx::Canvas* canvas,
DetachableToolbarView* view) {
// Border can be at the top or at the bottom of the view depending on whether
// the view (bar/shelf) is attached or detached.
- int y = !view->IsDetached() ? view->height() - 1 : 0;
+ int thickness = views::NonClientFrameView::kClientEdgeThickness;
+ int y = view->IsDetached() ? 0 : (view->height() - thickness);
canvas->FillRectInt(ResourceBundle::toolbar_separator_color,
- 0, y, view->width(), 1);
+ 0, y, view->width(), thickness);
}
// static
@@ -98,10 +97,10 @@ void DetachableToolbarView::PaintVerticalDivider(
const SkColor& bottom_color) {
// Draw the upper half of the divider.
SkPaint paint;
- paint.setShader(gfx::CreateGradientShader(vertical_padding + 1,
- height / 2,
- top_color,
- middle_color))->safeUnref();
+ SkSafeUnref(paint.setShader(gfx::CreateGradientShader(vertical_padding + 1,
+ height / 2,
+ top_color,
+ middle_color)));
SkRect rc = { SkIntToScalar(x),
SkIntToScalar(vertical_padding + 1),
SkIntToScalar(x + 1),
@@ -110,10 +109,8 @@ void DetachableToolbarView::PaintVerticalDivider(
// Draw the lower half of the divider.
SkPaint paint_down;
- paint_down.setShader(gfx::CreateGradientShader(height / 2,
- height - vertical_padding,
- middle_color,
- bottom_color))->safeUnref();
+ SkSafeUnref(paint_down.setShader(gfx::CreateGradientShader(
+ height / 2, height - vertical_padding, middle_color, bottom_color)));
SkRect rc_down = { SkIntToScalar(x),
SkIntToScalar(height / 2),
SkIntToScalar(x + 1),
diff --git a/chrome/browser/views/detachable_toolbar_view.h b/chrome/browser/views/detachable_toolbar_view.h
index 381fcbb..0211e88 100644
--- a/chrome/browser/views/detachable_toolbar_view.h
+++ b/chrome/browser/views/detachable_toolbar_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_DETACHABLE_TOOLBAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_DETACHABLE_TOOLBAR_VIEW_H_
+#pragma once
#include "chrome/browser/views/accessible_toolbar_view.h"
@@ -28,10 +29,15 @@ class DetachableToolbarView : public AccessibleToolbarView {
// Gets the current state of the resize animation (show/hide).
virtual double GetAnimationValue() const = 0;
- // Paint the background (including the theme image behind content area) when
- // in bar/shelf is attached to the Chrome frame.
+ // Gets the current amount of overlap atop the browser toolbar.
+ virtual int GetToolbarOverlap() const = 0;
+
+ // Paints the background (including the theme image behind content area) when
+ // the bar/shelf is attached to the top toolbar. |background_origin| is the
+ // origin to use for painting the theme image.
static void PaintBackgroundAttachedMode(gfx::Canvas* canvas,
- views::View* view);
+ views::View* view,
+ const gfx::Point& background_origin);
// Calculate the rect for the content area of the bar/shelf. This is only
// needed when the bar/shelf is detached from the Chrome frame (otherwise the
diff --git a/chrome/browser/views/dom_view.cc b/chrome/browser/views/dom_view.cc
index 4725cf9..a4cc19a 100644
--- a/chrome/browser/views/dom_view.cc
+++ b/chrome/browser/views/dom_view.cc
@@ -23,13 +23,15 @@ bool DOMView::Init(Profile* profile, SiteInstance* instance) {
initialized_ = true;
tab_contents_.reset(CreateTabContents(profile, instance));
- views::NativeViewHost::Attach(tab_contents_->GetNativeView());
+ // Attach the native_view now if the view is already added to Widget.
+ if (GetWidget())
+ Attach(tab_contents_->GetNativeView());
return true;
}
TabContents* DOMView::CreateTabContents(Profile* profile,
SiteInstance* instance) {
- return new TabContents(profile, instance, MSG_ROUTING_NONE, NULL);
+ return new TabContents(profile, instance, MSG_ROUTING_NONE, NULL, NULL);
}
void DOMView::LoadURL(const GURL& url) {
@@ -47,3 +49,14 @@ bool DOMView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
void DOMView::Focus() {
tab_contents_->Focus();
}
+
+void DOMView::ViewHierarchyChanged(bool is_add, views::View* parent,
+ views::View* child) {
+ // Attach the native_view when this is added to Widget if
+ // 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());
+ else if (!is_add && child == this && native_view())
+ Detach();
+}
diff --git a/chrome/browser/views/dom_view.h b/chrome/browser/views/dom_view.h
index 38e6189..4a804f8 100644
--- a/chrome/browser/views/dom_view.h
+++ b/chrome/browser/views/dom_view.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_VIEWS_DOM_VIEW_H_
#define CHROME_BROWSER_VIEWS_DOM_VIEW_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "googleurl/src/gurl.h"
@@ -39,6 +40,8 @@ class DOMView : public views::NativeViewHost {
// Overridden from View.
virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e);
virtual void Focus();
+ virtual void ViewHierarchyChanged(bool is_add, views::View* parent,
+ views::View* child);
// Returns new allocated TabContents instance, caller is responsible deleting.
// Override in derived classes to replace TabContents with derivative.
diff --git a/chrome/browser/views/download_item_view.cc b/chrome/browser/views/download_item_view.cc
index 348c86d..1f753e9 100644
--- a/chrome/browser/views/download_item_view.cc
+++ b/chrome/browser/views/download_item_view.cc
@@ -9,17 +9,17 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/text_elider.h"
-#include "app/theme_provider.h"
#include "base/callback.h"
#include "base/file_path.h"
#include "base/histogram.h"
#include "base/i18n/rtl.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/views/download_shelf_view.h"
#include "gfx/canvas_skia.h"
#include "gfx/color_utils.h"
@@ -30,10 +30,6 @@
#include "views/widget/root_view.h"
#include "views/widget/widget.h"
-#if defined(OS_WIN)
-#include "app/win_util.h"
-#endif
-
using base::TimeDelta;
// TODO(paulg): These may need to be adjusted when download progress
@@ -132,7 +128,8 @@ DownloadItemView::DownloadItemView(DownloadItem* download,
dangerous_download_label_sized_(false),
disabled_while_opening_(false),
creation_time_(base::Time::Now()),
- ALLOW_THIS_IN_INITIALIZER_LIST(reenable_method_factory_(this)) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(reenable_method_factory_(this)),
+ deleted_(NULL) {
DCHECK(download_);
download_->AddObserver(this);
@@ -215,8 +212,8 @@ DownloadItemView::DownloadItemView(DownloadItem* download,
tooltip_text_ = download_->GetFileName().ToWStringHack();
font_ = ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
- box_height_ = std::max<int>(2 * kVerticalPadding + font_.height() +
- kVerticalTextPadding + font_.height(),
+ box_height_ = std::max<int>(2 * kVerticalPadding + font_.GetHeight() +
+ kVerticalTextPadding + font_.GetHeight(),
2 * kVerticalPadding +
normal_body_image_set_.top_left->height() +
normal_body_image_set_.bottom_left->height());
@@ -289,7 +286,8 @@ DownloadItemView::DownloadItemView(DownloadItem* download,
} else {
ElideString(rootname, kFileNameMaxLength - extension.length(), &rootname);
std::wstring filename = rootname + L"." + extension;
- base::i18n::GetDisplayStringInLTRDirectionality(&filename);
+ filename = UTF16ToWide(base::i18n::GetDisplayStringInLTRDirectionality(
+ WideToUTF16(filename)));
dangerous_download_label_ = new views::Label(
l10n_util::GetStringF(IDS_PROMPT_DANGEROUS_DOWNLOAD, filename));
}
@@ -311,6 +309,8 @@ DownloadItemView::~DownloadItemView() {
icon_consumer_.CancelAllRequests();
StopDownloadProgress();
download_->RemoveObserver(this);
+ if (deleted_)
+ *deleted_ = true;
}
// Progress animation handlers.
@@ -393,6 +393,9 @@ void DownloadItemView::OnDownloadOpened(DownloadItem* download) {
FROM_HERE,
reenable_method_factory_.NewRunnableMethod(&DownloadItemView::Reenable),
kDisabledOnOpenDuration);
+
+ // Notify our parent.
+ parent_->OpenedDownload(this);
}
// View overrides
@@ -433,7 +436,7 @@ void DownloadItemView::ButtonPressed(
UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
base::Time::Now() - creation_time_);
// This will change the state and notify us.
- download_->manager()->DangerousDownloadValidated(download_);
+ download_->DangerousDownloadValidated();
}
}
@@ -488,7 +491,7 @@ void DownloadItemView::Paint(gfx::Canvas* canvas) {
int mirrored_x = MirroredXWithWidthInsideView(
download_util::kSmallProgressIconSize, kTextWidth);
// Add font_.height() to compensate for title, which is drawn later.
- int y = box_y_ + kVerticalPadding + font_.height() +
+ int y = box_y_ + kVerticalPadding + font_.GetHeight() +
kVerticalTextPadding;
SkColor file_name_color = GetThemeProvider()->GetColor(
BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
@@ -503,20 +506,19 @@ void DownloadItemView::Paint(gfx::Canvas* canvas) {
static_cast<int>(kDownloadItemLuminanceMod *
SkColorGetB(file_name_color)));
canvas->DrawStringInt(status_text_, font_, file_name_color,
- mirrored_x, y, kTextWidth, font_.height());
+ mirrored_x, y, kTextWidth, font_.GetHeight());
}
}
// Paint the background images.
int x = kLeftPadding;
- bool rtl_ui = base::i18n::IsRTL();
- if (rtl_ui) {
+ canvas->Save();
+ if (base::i18n::IsRTL()) {
// Since we do not have the mirrored images for
// (hot_)body_image_set->top_left, (hot_)body_image_set->left,
// (hot_)body_image_set->bottom_left, and drop_down_image_set,
// for RTL UI, we flip the canvas to draw those images mirrored.
// Consequently, we do not need to mirror the x-axis of those images.
- canvas->Save();
canvas->TranslateInt(width(), 0);
canvas->ScaleInt(-1, 1);
}
@@ -558,13 +560,6 @@ void DownloadItemView::Paint(gfx::Canvas* canvas) {
x, box_y_, box_height_,
hot_body_image_set_.top_right->width());
canvas->Restore();
- if (rtl_ui) {
- canvas->Restore();
- canvas->Save();
- // Flip it for drawing drop-down images for RTL locales.
- canvas->TranslateInt(width(), 0);
- canvas->ScaleInt(-1, 1);
- }
}
x += body_image_set->top_right->width();
@@ -592,18 +587,16 @@ void DownloadItemView::Paint(gfx::Canvas* canvas) {
}
}
- if (rtl_ui) {
- // Restore the canvas to avoid file name etc. text are drawn flipped.
- // Consequently, the x-axis of following canvas->DrawXXX() method should be
- // mirrored so the text and images are down in the right positions.
- canvas->Restore();
- }
+ // Restore the canvas to avoid file name etc. text are drawn flipped.
+ // Consequently, the x-axis of following canvas->DrawXXX() method should be
+ // mirrored so the text and images are down in the right positions.
+ canvas->Restore();
// Print the text, left aligned and always print the file extension.
// Last value of x was the end of the right image, just before the button.
// Note that in dangerous mode we use a label (as the text is multi-line).
if (!IsDangerousMode()) {
- std::wstring filename;
+ string16 filename;
if (!disabled_while_opening_) {
filename = gfx::ElideFilename(download_->GetFileName(),
font_, kTextWidth);
@@ -614,26 +607,27 @@ void DownloadItemView::Paint(gfx::Canvas* canvas) {
l10n_util::GetStringF(IDS_DOWNLOAD_STATUS_OPENING, empty_string);
int status_string_width = font_.GetStringWidth(status_string);
// Then, elide the file name.
- std::wstring filename_string =
+ string16 filename_string =
gfx::ElideFilename(download_->GetFileName(), font_,
kTextWidth - status_string_width);
// Last, concat the whole string.
- filename = l10n_util::GetStringF(IDS_DOWNLOAD_STATUS_OPENING,
- filename_string);
+ filename = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING,
+ filename_string);
}
int mirrored_x = MirroredXWithWidthInsideView(
download_util::kSmallProgressIconSize, kTextWidth);
SkColor file_name_color = GetThemeProvider()->GetColor(
BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
- int y = box_y_ + (show_status_text_ ? kVerticalPadding :
- (box_height_ - font_.height()) / 2);
+ int y =
+ box_y_ + (show_status_text_ ? kVerticalPadding :
+ (box_height_ - font_.GetHeight()) / 2);
// Draw the file's name.
- canvas->DrawStringInt(filename, font_,
+ canvas->DrawStringInt(UTF16ToWide(filename), font_,
IsEnabled() ? file_name_color :
kFileNameDisabledColor,
- mirrored_x, y, kTextWidth, font_.height());
+ mirrored_x, y, kTextWidth, font_.GetHeight());
}
// Paint the icon.
@@ -740,7 +734,7 @@ gfx::Size DownloadItemView::GetPreferredSize() {
int width, height;
// First, we set the height to the height of two rows or text plus margins.
- height = 2 * kVerticalPadding + 2 * font_.height() + kVerticalTextPadding;
+ height = 2 * kVerticalPadding + 2 * font_.GetHeight() + kVerticalTextPadding;
// Then we increase the size if the progress icon doesn't fit.
height = std::max<int>(height, download_util::kSmallProgressIconSize);
@@ -819,7 +813,14 @@ bool DownloadItemView::OnMousePressed(const views::MouseEvent& event) {
if (!context_menu_.get())
context_menu_.reset(new DownloadShelfContextMenuWin(model_.get()));
+ // When we call the Run method on the menu, it runs an inner message loop
+ // that might causes us to be deleted.
+ bool deleted = false;
+ deleted_ = &deleted;
context_menu_->Run(point);
+ if (deleted)
+ return true; // We have been deleted! Don't access 'this'.
+ deleted_ = NULL;
// If the menu action was to remove the download, this view will also be
// invalid so we must not access 'this' in this case.
@@ -907,11 +908,7 @@ void DownloadItemView::OpenDownload() {
// open downloads super quickly, we should be concerned about clickjacking.
UMA_HISTOGRAM_LONG_TIMES("clickjacking.open_download",
base::Time::Now() - creation_time_);
- if (download_->state() == DownloadItem::IN_PROGRESS) {
- download_->set_open_when_complete(!download_->open_when_complete());
- } else if (download_->state() == DownloadItem::COMPLETE) {
- download_util::OpenDownload(download_);
- }
+ download_->OpenDownload();
}
void DownloadItemView::OnExtractIconComplete(IconManager::Handle handle,
diff --git a/chrome/browser/views/download_item_view.h b/chrome/browser/views/download_item_view.h
index ffede2c..91fc7f6 100644
--- a/chrome/browser/views/download_item_view.h
+++ b/chrome/browser/views/download_item_view.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.
//
@@ -15,6 +15,7 @@
#ifndef CHROME_BROWSER_VIEWS_DOWNLOAD_ITEM_VIEW_H__
#define CHROME_BROWSER_VIEWS_DOWNLOAD_ITEM_VIEW_H__
+#pragma once
#include <string>
@@ -81,7 +82,7 @@ class DownloadItemView : public views::ButtonListener,
void OnExtractIconComplete(IconManager::Handle handle, SkBitmap* icon_bitmap);
// Returns the DownloadItem model object belonging to this item.
- DownloadItem* get_download() { return download_; }
+ DownloadItem* download() const { return download_; }
private:
enum State {
@@ -255,6 +256,11 @@ class DownloadItemView : public views::ButtonListener,
// The currently running download context menu.
scoped_ptr<DownloadShelfContextMenuWin> context_menu_;
+ // If non-NULL, set to true when this object is deleted.
+ // (Used when showing the context menu as it runs an inner message loop that
+ // might delete us).
+ bool* deleted_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadItemView);
};
diff --git a/chrome/browser/views/download_shelf_view.cc b/chrome/browser/views/download_shelf_view.cc
index f0c37f1..3f9a825 100644
--- a/chrome/browser/views/download_shelf_view.cc
+++ b/chrome/browser/views/download_shelf_view.cc
@@ -10,11 +10,11 @@
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.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/tab_contents/navigation_entry.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/download_item_view.h"
#include "chrome/browser/views/frame/browser_view.h"
@@ -56,6 +56,13 @@ static const int kNewItemAnimationDurationMs = 800;
// Shelf show/hide speed.
static const int kShelfAnimationDurationMs = 120;
+// Amount of time to delay if the mouse leaves the shelf by way of entering
+// another window. This is much larger than the normal delay as openning a
+// download is most likely going to trigger a new window to appear over the
+// button. Delay the time so that the user has a chance to quickly close the
+// other app and return to chrome with the download shelf still open.
+static const int kNotifyOnExitTimeMS = 5000;
+
namespace {
// Sets size->width() to view's preferred width + size->width().s
@@ -75,7 +82,10 @@ int CenterPosition(int size, int target_size) {
DownloadShelfView::DownloadShelfView(Browser* browser, BrowserView* parent)
: browser_(browser),
- parent_(parent) {
+ parent_(parent),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ mouse_watcher_(this, this, gfx::Insets())) {
+ mouse_watcher_.set_notify_on_exit_time_ms(kNotifyOnExitTimeMS);
SetID(VIEW_ID_DOWNLOAD_SHELF);
parent->AddChildView(this);
Init();
@@ -115,6 +125,8 @@ void DownloadShelfView::Init() {
}
void DownloadShelfView::AddDownloadView(DownloadItemView* view) {
+ mouse_watcher_.Stop();
+
Show();
DCHECK(view);
@@ -133,16 +145,22 @@ void DownloadShelfView::AddDownload(BaseDownloadItemModel* download_model) {
AddDownloadView(view);
}
+void DownloadShelfView::MouseMovedOutOfView() {
+ Close();
+}
+
void DownloadShelfView::RemoveDownloadView(View* view) {
DCHECK(view);
std::vector<DownloadItemView*>::iterator i =
- find(download_views_.begin(), download_views_.end(), view);
+ find(download_views_.begin(), download_views_.end(), view);
DCHECK(i != download_views_.end());
download_views_.erase(i);
RemoveChildView(view);
delete view;
if (download_views_.empty())
Close();
+ else if (CanAutoClose())
+ mouse_watcher_.Start();
Layout();
SchedulePaint();
}
@@ -156,6 +174,11 @@ void DownloadShelfView::PaintBorder(gfx::Canvas* canvas) {
canvas->FillRectInt(kBorderColor, 0, 0, width(), 1);
}
+void DownloadShelfView::OpenedDownload(DownloadItemView* view) {
+ if (CanAutoClose())
+ mouse_watcher_.Start();
+}
+
gfx::Size DownloadShelfView::GetPreferredSize() {
gfx::Size prefsize(kRightPadding + kLeftPadding + kCloseAndLinkPadding, 0);
AdjustSize(close_button_, &prefsize);
@@ -302,7 +325,7 @@ void DownloadShelfView::UpdateButtonColors() {
}
}
-void DownloadShelfView::ThemeChanged() {
+void DownloadShelfView::OnThemeChanged() {
UpdateButtonColors();
}
@@ -336,14 +359,25 @@ void DownloadShelfView::Closed() {
// When the close animation is complete, remove all completed downloads.
size_t i = 0;
while (i < download_views_.size()) {
- DownloadItem* download = download_views_[i]->get_download();
+ DownloadItem* download = download_views_[i]->download();
bool is_transfer_done = download->state() == DownloadItem::COMPLETE ||
download->state() == DownloadItem::CANCELLED;
if (is_transfer_done &&
download->safety_state() != DownloadItem::DANGEROUS) {
RemoveDownloadView(download_views_[i]);
} 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;
}
}
}
+
+bool DownloadShelfView::CanAutoClose() {
+ for (size_t i = 0; i < download_views_.size(); ++i) {
+ if (!download_views_[i]->download()->opened())
+ return false;
+ }
+ return true;
+}
diff --git a/chrome/browser/views/download_shelf_view.h b/chrome/browser/views/download_shelf_view.h
index 2d24607..db7e53e 100644
--- a/chrome/browser/views/download_shelf_view.h
+++ b/chrome/browser/views/download_shelf_view.h
@@ -1,14 +1,16 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_DOWNLOAD_SHELF_VIEW_H_
#define CHROME_BROWSER_VIEWS_DOWNLOAD_SHELF_VIEW_H_
+#pragma once
#include "app/slide_animation.h"
#include "chrome/browser/download/download_shelf.h"
#include "views/controls/button/button.h"
#include "views/controls/link.h"
+#include "views/mouse_watcher.h"
namespace views {
class ImageButton;
@@ -27,15 +29,19 @@ class DownloadItemView;
//
// DownloadShelfView does not hold an infinite number of download views, rather
// it'll automatically remove views once a certain point is reached.
-class DownloadShelfView : public DownloadShelf,
- public views::View,
+class DownloadShelfView : public AnimationDelegate,
+ public DownloadShelf,
public views::ButtonListener,
public views::LinkController,
- public AnimationDelegate {
+ public views::MouseWatcherListener,
+ public views::View {
public:
- explicit DownloadShelfView(Browser* browser, BrowserView* parent);
+ DownloadShelfView(Browser* browser, BrowserView* parent);
virtual ~DownloadShelfView();
+ // Sent from the DownloadItemView when the user opens an item.
+ void OpenedDownload(DownloadItemView* view);
+
// Implementation of View.
virtual gfx::Size GetPreferredSize();
virtual void Layout();
@@ -62,6 +68,9 @@ class DownloadShelfView : public DownloadShelf,
virtual void Close();
virtual Browser* browser() const { return browser_; }
+ // Implementation of MouseWatcherDelegate.
+ virtual void MouseMovedOutOfView();
+
// Removes a specified download view. The supplied view is deleted after
// it's removed.
void RemoveDownloadView(views::View* view);
@@ -84,11 +93,15 @@ class DownloadShelfView : public DownloadShelf,
void UpdateButtonColors();
// Overridden from views::View.
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
// Called when the "close shelf" animation ended.
void Closed();
+ // Returns true if we can auto close. We can auto-close if all the items on
+ // the shelf have been opened.
+ bool CanAutoClose();
+
// The browser for this shelf.
Browser* browser_;
@@ -116,6 +129,8 @@ class DownloadShelfView : public DownloadShelf,
// The window this shelf belongs to.
BrowserView* parent_;
+ views::MouseWatcher mouse_watcher_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadShelfView);
};
diff --git a/chrome/browser/views/dropdown_bar_host.cc b/chrome/browser/views/dropdown_bar_host.cc
index 4878e15..e55365b 100644
--- a/chrome/browser/views/dropdown_bar_host.cc
+++ b/chrome/browser/views/dropdown_bar_host.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/views/dropdown_bar_host.h"
+#include "app/keyboard_codes.h"
#include "app/slide_animation.h"
-#include "base/keyboard_codes.h"
#include "base/scoped_handle.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
@@ -174,13 +174,6 @@ void DropdownBarHost::AnimationEnded(const Animation* animation) {
}
}
-void DropdownBarHost::GetThemePosition(gfx::Rect* bounds) {
- *bounds = GetDialogPosition(gfx::Rect());
- gfx::Rect toolbar_bounds = browser_view_->GetToolbarBounds();
- gfx::Rect tab_strip_bounds = browser_view_->GetTabStripBounds();
- bounds->Offset(-toolbar_bounds.x(), -tab_strip_bounds.y());
-}
-
////////////////////////////////////////////////////////////////////////////////
// DropdownBarHost protected:
@@ -276,7 +269,7 @@ void DropdownBarHost::UpdateWindowEdges(const gfx::Rect& new_pos) {
// TODO(brettw) this constant is evil. This is the amount of room we've added
// to the window size, when we set the region, it can change the size.
static const int kAddedWidth = 7;
- int difference = new_pos.right() - kAddedWidth - widget_bounds.width() -
+ int difference = new_pos.right() - kAddedWidth - widget_bounds.right() -
gfx::scrollbar_size() + 1;
if (difference > 0) {
Path::Point exclude[4];
@@ -304,14 +297,14 @@ void DropdownBarHost::UpdateWindowEdges(const gfx::Rect& new_pos) {
void DropdownBarHost::RegisterAccelerators() {
DCHECK(!esc_accel_target_registered_);
- views::Accelerator escape(base::VKEY_ESCAPE, false, false, false);
+ views::Accelerator escape(app::VKEY_ESCAPE, false, false, false);
focus_manager_->RegisterAccelerator(escape, this);
esc_accel_target_registered_ = true;
}
void DropdownBarHost::UnregisterAccelerators() {
DCHECK(esc_accel_target_registered_);
- views::Accelerator escape(base::VKEY_ESCAPE, false, false, false);
+ views::Accelerator escape(app::VKEY_ESCAPE, false, false, false);
focus_manager_->UnregisterAccelerator(escape, this);
esc_accel_target_registered_ = false;
}
diff --git a/chrome/browser/views/dropdown_bar_host.h b/chrome/browser/views/dropdown_bar_host.h
index 8b45f06..72b9aac 100644
--- a/chrome/browser/views/dropdown_bar_host.h
+++ b/chrome/browser/views/dropdown_bar_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_DROPDOWN_BAR_HOST_H_
#define CHROME_BROWSER_VIEWS_DROPDOWN_BAR_HOST_H_
+#pragma once
#include "app/animation.h"
#include "base/scoped_ptr.h"
@@ -77,9 +78,6 @@ class DropdownBarHost : public views::AcceleratorTarget,
virtual void AnimationProgressed(const Animation* animation);
virtual void AnimationEnded(const Animation* animation);
- // Get the offset with which to paint the theme image.
- void GetThemePosition(gfx::Rect* bounds);
-
// During testing we can disable animations by setting this flag to true,
// so that opening and closing the dropdown bar is shown instantly, instead of
// having to poll it while it animates to open/closed status.
diff --git a/chrome/browser/views/dropdown_bar_view.h b/chrome/browser/views/dropdown_bar_view.h
index dbae978..1486509 100644
--- a/chrome/browser/views/dropdown_bar_view.h
+++ b/chrome/browser/views/dropdown_bar_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_DROPDOWN_BAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_DROPDOWN_BAR_VIEW_H_
+#pragma once
#include "views/view.h"
diff --git a/chrome/browser/views/edit_search_engine_dialog.cc b/chrome/browser/views/edit_search_engine_dialog.cc
index 78dfcee..8919d9d 100644
--- a/chrome/browser/views/edit_search_engine_dialog.cc
+++ b/chrome/browser/views/edit_search_engine_dialog.cc
@@ -85,8 +85,8 @@ std::wstring EditSearchEngineDialog::GetWindowTitle() const {
bool EditSearchEngineDialog::IsDialogButtonEnabled(
MessageBoxFlags::DialogButton button) const {
if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- return (controller_->IsKeywordValid(keyword_tf_->text()) &&
- controller_->IsTitleValid(title_tf_->text()) &&
+ return (controller_->IsKeywordValid(WideToUTF16(keyword_tf_->text())) &&
+ controller_->IsTitleValid(WideToUTF16(title_tf_->text())) &&
controller_->IsURLValid(WideToUTF8(url_tf_->text())));
}
return true;
@@ -98,7 +98,8 @@ bool EditSearchEngineDialog::Cancel() {
}
bool EditSearchEngineDialog::Accept() {
- controller_->AcceptAddOrEdit(title_tf_->text(), keyword_tf_->text(),
+ controller_->AcceptAddOrEdit(WideToUTF16(title_tf_->text()),
+ WideToUTF16(keyword_tf_->text()),
WideToUTF8(url_tf_->text()));
return true;
}
@@ -238,11 +239,13 @@ Textfield* EditSearchEngineDialog::CreateTextfield(const std::wstring& text,
}
void EditSearchEngineDialog::UpdateImageViews() {
- UpdateImageView(keyword_iv_, controller_->IsKeywordValid(keyword_tf_->text()),
+ UpdateImageView(keyword_iv_,
+ controller_->IsKeywordValid(WideToUTF16(keyword_tf_->text())),
IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT);
UpdateImageView(url_iv_, controller_->IsURLValid(WideToUTF8(url_tf_->text())),
IDS_SEARCH_ENGINES_INVALID_URL_TT);
- UpdateImageView(title_iv_, controller_->IsTitleValid(title_tf_->text()),
+ UpdateImageView(title_iv_,
+ controller_->IsTitleValid(WideToUTF16(title_tf_->text())),
IDS_SEARCH_ENGINES_INVALID_TITLE_TT);
}
diff --git a/chrome/browser/views/edit_search_engine_dialog.h b/chrome/browser/views/edit_search_engine_dialog.h
index 9f12cc1..43c4dd0 100644
--- a/chrome/browser/views/edit_search_engine_dialog.h
+++ b/chrome/browser/views/edit_search_engine_dialog.h
@@ -9,6 +9,7 @@
#ifndef CHROME_BROWSER_VIEWS_EDIT_SEARCH_ENGINE_DIALOG_H_
#define CHROME_BROWSER_VIEWS_EDIT_SEARCH_ENGINE_DIALOG_H_
+#pragma once
#include <windows.h>
diff --git a/chrome/browser/views/event_utils.h b/chrome/browser/views/event_utils.h
index 0fdef8d..188041f 100644
--- a/chrome/browser/views/event_utils.h
+++ b/chrome/browser/views/event_utils.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_EVENT_UTILS_H__
#define CHROME_BROWSER_VIEWS_EVENT_UTILS_H__
+#pragma once
#include "webkit/glue/window_open_disposition.h"
diff --git a/chrome/browser/views/extensions/browser_action_drag_data.cc b/chrome/browser/views/extensions/browser_action_drag_data.cc
index 2d772ea..6ab54ce 100644
--- a/chrome/browser/views/extensions/browser_action_drag_data.cc
+++ b/chrome/browser/views/extensions/browser_action_drag_data.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/views/extensions/browser_action_drag_data.h"
-#include "base/file_path.h"
#include "base/logging.h"
#include "base/pickle.h"
#include "base/string_util.h"
diff --git a/chrome/browser/views/extensions/browser_action_drag_data.h b/chrome/browser/views/extensions/browser_action_drag_data.h
index 583185b..33995fd 100644
--- a/chrome/browser/views/extensions/browser_action_drag_data.h
+++ b/chrome/browser/views/extensions/browser_action_drag_data.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_DRAG_DATA_H_
#define CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_DRAG_DATA_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/extensions/browser_action_drag_data_unittest.cc b/chrome/browser/views/extensions/browser_action_drag_data_unittest.cc
index da4eb2c..226591f 100644
--- a/chrome/browser/views/extensions/browser_action_drag_data_unittest.cc
+++ b/chrome/browser/views/extensions/browser_action_drag_data_unittest.cc
@@ -7,6 +7,7 @@
#include "base/pickle.h"
#include "chrome/browser/views/extensions/browser_action_drag_data.h"
#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.h b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.h
index 2695bb3..08a0d55 100644
--- a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.h
+++ b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_OVERFLOW_MENU_CONTROLLER_H_
#define CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_OVERFLOW_MENU_CONTROLLER_H_
+#pragma once
#include <set>
#include <vector>
diff --git a/chrome/browser/views/extensions/extension_install_prompt.cc b/chrome/browser/views/extensions/extension_install_prompt.cc
index 3a6329f..f75b557 100644
--- a/chrome/browser/views/extensions/extension_install_prompt.cc
+++ b/chrome/browser/views/extensions/extension_install_prompt.cc
@@ -4,8 +4,8 @@
#include "app/l10n_util.h"
#include "base/file_util.h"
-#include "base/rand_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_install_ui.h"
@@ -28,34 +28,19 @@ class Profile;
namespace {
-// Since apps don't (currently) have any privilege disclosure text, the dialog
-// looks a bit empty if it is sized the same as extensions. So we scale
-// everything down a bit for apps for the time being.
-const int kRightColumnWidthApp = 210;
-const int kRightColumnWidthExtension = 270;
-const int kIconSizeApp = 69;
-const int kIconSizeExtension = 85;
+const int kRightColumnWidth = 210;
+const int kIconSize = 69;
// Implements the extension installation prompt for Windows.
class InstallDialogContent : public views::View, public views::DialogDelegate {
public:
InstallDialogContent(ExtensionInstallUI::Delegate* delegate,
- Extension* extension, SkBitmap* icon, const std::wstring& warning_text,
- ExtensionInstallUI::PromptType type)
- : delegate_(delegate), icon_(NULL), warning_(NULL),
- create_shortcut_(NULL), type_(type) {
- if (extension->GetFullLaunchURL().is_valid()) {
- icon_size_ = kIconSizeApp;
- right_column_width_ = kRightColumnWidthApp;
- } else {
- icon_size_ = kIconSizeExtension;
- right_column_width_ = kRightColumnWidthExtension;
- }
-
+ Extension* extension, SkBitmap* icon, ExtensionInstallUI::PromptType type)
+ : delegate_(delegate), icon_(NULL), type_(type) {
// Scale down to icon size, but allow smaller icons (don't scale up).
gfx::Size size(icon->width(), icon->height());
- if (size.width() > icon_size_ || size.height() > icon_size_)
- size = gfx::Size(icon_size_, icon_size_);
+ if (size.width() > kIconSize || size.height() > kIconSize)
+ size = gfx::Size(kIconSize, kIconSize);
icon_ = new views::ImageView();
icon_->SetImageSize(size);
icon_->SetImage(*icon);
@@ -64,24 +49,9 @@ class InstallDialogContent : public views::View, public views::DialogDelegate {
heading_ = new views::Label(
l10n_util::GetStringF(ExtensionInstallUI::kHeadingIds[type_],
UTF8ToWide(extension->name())));
- heading_->SetFont(heading_->font().DeriveFont(1, gfx::Font::BOLD));
heading_->SetMultiLine(true);
heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
AddChildView(heading_);
-
- if (type_ == ExtensionInstallUI::INSTALL_PROMPT &&
- extension->GetFullLaunchURL().is_valid()) {
- create_shortcut_ = new views::Checkbox(
- l10n_util::GetString(IDS_EXTENSION_PROMPT_CREATE_SHORTCUT));
- create_shortcut_->SetChecked(true);
- create_shortcut_->SetMultiLine(true);
- AddChildView(create_shortcut_);
- } else {
- warning_ = new views::Label(warning_text);
- warning_->SetMultiLine(true);
- warning_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
- AddChildView(warning_);
- }
}
private:
@@ -104,8 +74,7 @@ class InstallDialogContent : public views::View, public views::DialogDelegate {
}
virtual bool Accept() {
- delegate_->InstallUIProceed(
- create_shortcut_ && create_shortcut_->checked());
+ delegate_->InstallUIProceed();
return true;
}
@@ -114,7 +83,6 @@ class InstallDialogContent : public views::View, public views::DialogDelegate {
return true;
}
-
// WindowDelegate
virtual bool IsModal() const { return true; }
virtual std::wstring GetWindowTitle() const {
@@ -124,69 +92,47 @@ class InstallDialogContent : public views::View, public views::DialogDelegate {
// View
virtual gfx::Size GetPreferredSize() {
- int width = right_column_width_ + kPanelHorizMargin + kPanelHorizMargin;
- width += icon_size_;
- width += kPanelHorizMargin;
+ int width = kRightColumnWidth;
+ width += kIconSize;
+ width += kPanelHorizMargin * 3;
int height = kPanelVertMargin * 2;
- height += heading_->GetHeightForWidth(right_column_width_);
- height += kPanelVertMargin;
-
- if (warning_)
- height += warning_->GetHeightForWidth(right_column_width_);
- else
- height += create_shortcut_->GetPreferredSize().height();
-
- height += kPanelVertMargin;
+ height += heading_->GetHeightForWidth(kRightColumnWidth);
- return gfx::Size(width, std::max(height, icon_size_ + kPanelVertMargin * 2));
+ return gfx::Size(width,
+ std::max(height, kIconSize + kPanelVertMargin * 2));
}
virtual void Layout() {
int x = kPanelHorizMargin;
int y = kPanelVertMargin;
- icon_->SetBounds(x, y, icon_size_, icon_size_);
- x += icon_size_;
- x += kPanelHorizMargin;
-
- heading_->SizeToFit(right_column_width_);
- heading_->SetX(x);
- heading_->SetY(y);
- y += heading_->height();
-
- y += kPanelVertMargin;
-
- if (create_shortcut_) {
- create_shortcut_->SetBounds(x, y, right_column_width_, 0);
- create_shortcut_->SetBounds(x, y, right_column_width_,
- create_shortcut_->GetPreferredSize().height());
-
- int bottom_aligned = icon_->y() + icon_->height() -
- create_shortcut_->height();
- if (bottom_aligned > y) {
- create_shortcut_->SetY(bottom_aligned);
- y = bottom_aligned;
- }
- y += create_shortcut_->height();
+ heading_->SizeToFit(kRightColumnWidth);
+
+ if (heading_->height() <= kIconSize) {
+ icon_->SetBounds(x, y, kIconSize, kIconSize);
+ x += kIconSize;
+ x += kPanelHorizMargin;
+
+ heading_->SetX(x);
+ heading_->SetY(y + (kIconSize - heading_->height()) / 2);
} else {
- warning_->SizeToFit(right_column_width_);
- warning_->SetX(x);
- warning_->SetY(y);
- y += warning_->height();
+ icon_->SetBounds(x,
+ y + (heading_->height() - kIconSize) / 2,
+ kIconSize,
+ kIconSize);
+ x += kIconSize;
+ x += kPanelHorizMargin;
+
+ heading_->SetX(x);
+ heading_->SetY(y);
}
-
- y += kPanelVertMargin;
}
ExtensionInstallUI::Delegate* delegate_;
views::ImageView* icon_;
views::Label* heading_;
- views::Label* warning_;
- views::Checkbox* create_shortcut_;
ExtensionInstallUI::PromptType type_;
- int right_column_width_;
- int icon_size_;
DISALLOW_COPY_AND_ASSIGN(InstallDialogContent);
};
@@ -196,7 +142,7 @@ class InstallDialogContent : public views::View, public views::DialogDelegate {
// static
void ExtensionInstallUI::ShowExtensionInstallUIPromptImpl(
Profile* profile, Delegate* delegate, Extension* extension, SkBitmap* icon,
- const string16& warning_text, PromptType type) {
+ PromptType type) {
Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
if (!browser) {
delegate->InstallUIAbort();
@@ -211,6 +157,5 @@ void ExtensionInstallUI::ShowExtensionInstallUIPromptImpl(
views::Window::CreateChromeWindow(window->GetNativeHandle(), gfx::Rect(),
new InstallDialogContent(delegate, extension, icon,
- UTF16ToWideHack(warning_text),
type))->Show();
}
diff --git a/chrome/browser/views/extensions/extension_install_prompt2.cc b/chrome/browser/views/extensions/extension_install_prompt2.cc
index 397ade7..5b0ed3a 100644
--- a/chrome/browser/views/extensions/extension_install_prompt2.cc
+++ b/chrome/browser/views/extensions/extension_install_prompt2.cc
@@ -183,7 +183,7 @@ int InstallDialogContent2::GetDefaultDialogButton() const {
}
bool InstallDialogContent2::Accept() {
- delegate_->InstallUIProceed(false); // create shortcut
+ delegate_->InstallUIProceed();
return true;
}
diff --git a/chrome/browser/views/extensions/extension_installed_bubble.cc b/chrome/browser/views/extensions/extension_installed_bubble.cc
index 1799ee4..4997ac6 100644
--- a/chrome/browser/views/extensions/extension_installed_bubble.cc
+++ b/chrome/browser/views/extensions/extension_installed_bubble.cc
@@ -7,6 +7,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/profile.h"
@@ -26,6 +27,7 @@
#include "grit/theme_resources.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/image_button.h"
+#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/standard_layout.h"
#include "views/view.h"
diff --git a/chrome/browser/views/extensions/extension_installed_bubble.h b/chrome/browser/views/extensions/extension_installed_bubble.h
index ad93996..81c12a6 100644
--- a/chrome/browser/views/extensions/extension_installed_bubble.h
+++ b/chrome/browser/views/extensions/extension_installed_bubble.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_INSTALLED_BUBBLE_H_
#define CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_INSTALLED_BUBBLE_H_
+#pragma once
#include "base/ref_counted.h"
#include "chrome/browser/views/info_bubble.h"
diff --git a/chrome/browser/views/extensions/extension_popup.cc b/chrome/browser/views/extensions/extension_popup.cc
index f9b1a26..2f21254 100644
--- a/chrome/browser/views/extensions/extension_popup.cc
+++ b/chrome/browser/views/extensions/extension_popup.cc
@@ -341,7 +341,10 @@ gfx::Rect ExtensionPopup::GetOuterBounds() const {
if (BubbleBorder::is_arrow_on_left(anchor_position_))
x = relative_rect.x();
else
- x = relative_rect.x() - contents_size.width();
+ // Note that if the arrow is on the right, that the x position of the popup
+ // is assigned so that the rightmost edge of the popup is aligned with the
+ // rightmost edge of the relative region.
+ x = relative_rect.right() - contents_size.width();
return gfx::Rect(x, y, contents_size.width(), contents_size.height());
}
diff --git a/chrome/browser/views/extensions/extension_popup.h b/chrome/browser/views/extensions/extension_popup.h
index 2139971..9d656be 100644
--- a/chrome/browser/views/extensions/extension_popup.h
+++ b/chrome/browser/views/extensions/extension_popup.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_POPUP_H_
#define CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_POPUP_H_
+#pragma once
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/views/browser_bubble.h"
@@ -138,7 +139,7 @@ class ExtensionPopup : public BrowserBubble,
const NotificationDetails& details);
// ExtensionView::Container overrides.
- virtual void OnExtensionMouseEvent(ExtensionView* view) { }
+ virtual void OnExtensionMouseMove(ExtensionView* view) { }
virtual void OnExtensionMouseLeave(ExtensionView* view) { }
virtual void OnExtensionPreferredSizeChanged(ExtensionView* view);
diff --git a/chrome/browser/views/extensions/extension_shelf.cc b/chrome/browser/views/extensions/extension_shelf.cc
deleted file mode 100644
index 7bb5391..0000000
--- a/chrome/browser/views/extensions/extension_shelf.cc
+++ /dev/null
@@ -1,1107 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights 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/extensions/extension_shelf.h"
-
-#include <algorithm>
-
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.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/tab_contents/tab_contents.h"
-#include "chrome/browser/views/extensions/extension_view.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "gfx/canvas_skia.h"
-#include "views/controls/label.h"
-#include "views/screen.h"
-#include "views/widget/root_view.h"
-
-namespace {
-
-// This is the slight padding that is there around the edge of the browser. This
-// has been determined empirically.
-// TODO(sidchat): Compute this value from the root view of the extension shelf.
-static const int kExtensionShelfPaddingOnLeft = 4;
-
-// Margins around the content.
-static const int kTopMarginWhenExtensionsOnTop = 1;
-static const int kTopMarginWhenExtensionsOnBottom = 2;
-static const int kBottomMargin = 2;
-static const int kLeftMargin = 0;
-static const int kRightMargin = 0;
-
-// Padding on left and right side of an extension toolstrip.
-static const int kToolstripPadding = 2;
-
-// Width of the toolstrip divider.
-static const int kToolstripDividerWidth = 2;
-
-// Preferred height of the ExtensionShelf.
-static const int kShelfHeight = 29;
-
-// Preferred height of the Extension shelf when only shown on the new tab page.
-const int kNewtabShelfHeight = 58;
-
-// How inset the extension shelf is when displayed on the new tab page. This is
-// in addition to the margins above.
-static const int kNewtabHorizontalPadding = 8;
-static const int kNewtabVerticalPadding = 12;
-
-// We need an extra margin to the left of all the toolstrips in detached mode,
-// so that the first toolstrip doesn't look so squished against the rounded
-// corners of the extension shelf.
-static const int kNewtabExtraHorMargin = 2;
-static const int kNewtabExtraVerMargin = 2;
-
-// Padding for the title inside the handle.
-static const int kHandlePadding = 4;
-
-// Inset for the extension view when displayed either dragging or expanded.
-static const int kWindowInset = 1;
-
-// Delays for showing and hiding the shelf handle.
-static const int kShowDelayMs = 500;
-static const int kHideDelayMs = 300;
-
-} // namespace
-
-
-// A view that holds the place for a toolstrip in the shelf while the toolstrip
-// is being dragged or moved.
-// TODO(erikkay) this should draw a dimmed out version of the toolstrip.
-class ExtensionShelf::PlaceholderView : public views::View {
- public:
- PlaceholderView() {}
-
- void SetWidth(int width) {
- SetBounds(x(), y(), width, height());
- PreferredSizeChanged();
- }
-
- // ExtensionShelf resizes its views to their preferred size at layout,
- // so just always prefer the current size.
- gfx::Size GetPreferredSize() { return size(); }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PlaceholderView);
-};
-
-// A wrapper class for the ExtensionHost displayed as a toolstrip.
-// The class itself also acts as the View for the handle of the toolstrip
-// it represents.
-class ExtensionShelf::Toolstrip : public views::View,
- public BrowserBubble::Delegate,
- public AnimationDelegate {
- public:
- Toolstrip(ExtensionShelf* shelf, ExtensionHost* host,
- const Extension::ToolstripInfo& info);
- virtual ~Toolstrip();
-
- // Convenience to calculate just the size of the handle.
- gfx::Size GetHandlePreferredSize();
-
- // View methods:
- virtual void Paint(gfx::Canvas* canvas);
- virtual gfx::Size GetPreferredSize();
- virtual void Layout();
- virtual void OnMouseEntered(const views::MouseEvent& event);
- virtual void OnMouseExited(const views::MouseEvent& event);
- virtual bool OnMousePressed(const views::MouseEvent& event);
- virtual bool OnMouseDragged(const views::MouseEvent& event);
- virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
- virtual bool IsFocusable() const { return true; }
- virtual void ChildPreferredSizeChanged(View* child);
-
- // Adjust the size and position of the window/handle.
- void LayoutWindow();
-
- // Is the toolstrip window visible (not necessarily the handle).
- bool window_visible() { return (window_.get() && window_->visible()); }
-
- // Is the handle for this toolstrip currently visible.
- bool handle_visible() { return (window_visible() && handle_visible_); }
-
- // Is the toolstrip opened in expanded mode.
- bool expanded() { return expanded_; }
-
- // Is the toolstrip being dragged.
- bool dragging() { return dragging_; }
-
- // Accessors for the host and its view.
- ExtensionHost* host() const { return host_; }
- ExtensionView* view() const { return host_->view(); }
-
- // The view that's currently displayed in the shelf. This could be
- // either the ExtensionView or |placeholder_view_| depending on the
- // current state.
- View* GetShelfView() const {
- if (placeholder_view_)
- return placeholder_view_;
- return view();
- }
-
- // Detaching the toolstrip from the shelf means that the ExtensionView is
- // displayed inside of the BrowserBubble rather than the shelf. This may
- // still visually appear to be part of the shelf (expanded) or completely
- // separate (dragging).
- // If |browser| is true, it also will detach/attach to the browser window.
- void DetachFromShelf(bool browser);
- void AttachToShelf(bool browser);
-
- // Show / Hide the shelf handle.
- void ShowShelfHandle();
- void DoShowShelfHandle();
- void HideShelfHandle(int delay_ms);
- void DoHideShelfHandle();
- void StopHandleTimer();
- void HideWindow();
- void ShowWindow();
-
- // Expand / Collapse
- void Expand(int height, const GURL& url);
- void Collapse(const GURL& url);
-
- // BrowserBubble::Delegate
- virtual void BubbleBrowserWindowMoved(BrowserBubble* bubble);
- virtual void BubbleBrowserWindowClosing(BrowserBubble* bubble);
-
- // AnimationDelegate
- virtual void AnimationProgressed(const Animation* animation);
- virtual void AnimationEnded(const Animation* animation);
-
- private:
- // The actual renderer that this toolstrip contains.
- ExtensionHost* host_;
-
- // Manifest definition of this toolstrip.
- Extension::ToolstripInfo info_;
-
- // A window that can be logically attached to the browser window. This is
- // used for two purposes: a handle that sits above the toolstrip when it's
- // collapsed and not dragging, and as a container for the toolstrip when it's
- // dragging or expanded.
- scoped_ptr<BrowserBubble> window_;
-
- // Used for drawing the name of the extension in the handle.
- scoped_ptr<views::Label> title_;
-
- // Pointer back to the containing shelf.
- ExtensionShelf* shelf_;
-
- // When dragging, a placeholder view is put into the shelf to hold space
- // for the ExtensionView. This view is parent owned when it's in the view
- // hierarchy, so there's no ownership issues here.
- PlaceholderView* placeholder_view_;
-
- // Current state of the toolstrip, currently can't both be expanded and
- // dragging.
- // TODO(erikkay) Support dragging while expanded.
- bool dragging_;
- bool expanded_;
- bool handle_visible_;
-
- // The target expanded height of the toolstrip (used for animation).
- int expanded_height_;
-
- // If dragging, where did the drag start from.
- gfx::Point initial_drag_location_;
-
- // We have to remember the initial drag point in screen coordinates, because
- // later, when the toolstrip is being dragged around, there is no good way of
- // computing the screen coordinates given the initial drag view coordinates.
- gfx::Point initial_drag_screen_point_;
-
- // Timers for tracking mouse hovering.
- ScopedRunnableMethodFactory<ExtensionShelf::Toolstrip> timer_factory_;
-
- // Animate opening and closing the mole.
- scoped_ptr<SlideAnimation> mole_animation_;
-
- DISALLOW_COPY_AND_ASSIGN(Toolstrip);
-};
-
-ExtensionShelf::Toolstrip::Toolstrip(ExtensionShelf* shelf,
- ExtensionHost* host,
- const Extension::ToolstripInfo& info)
- : host_(host),
- info_(info),
- shelf_(shelf),
- placeholder_view_(NULL),
- dragging_(false),
- expanded_(false),
- handle_visible_(false),
- expanded_height_(0),
- ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)) {
- DCHECK(host->view());
- // We're owned by shelf_, not the bubble that we get inserted in and out of.
- set_parent_owned(false);
-
- mole_animation_.reset(new SlideAnimation(this));
-
- std::wstring name = UTF8ToWide(host_->extension()->name());
- // |title_| isn't actually put in the view hierarchy. We just use it
- // to draw in place. The reason for this is so that we can properly handle
- // the various mouse events necessary for hovering and dragging.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- title_.reset(new views::Label(name, rb.GetFont(ResourceBundle::BaseFont)));
- title_->SetBounds(kHandlePadding, kHandlePadding, 100, 100);
- title_->SizeToPreferredSize();
-
- SizeToPreferredSize();
-}
-
-ExtensionShelf::Toolstrip::~Toolstrip() {
- if (window_.get() && window_->attached())
- window_->DetachFromBrowser();
-}
-
-void ExtensionShelf::Toolstrip::Paint(gfx::Canvas* canvas) {
- // Paint the background.
- SkColor theme_toolbar_color =
- shelf_->GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
- canvas->FillRectInt(theme_toolbar_color, 0, 0, width(), height());
-
- // Paints the handle for the toolstrip (only called on mouse-hover).
- SkColor border_color = ResourceBundle::toolbar_separator_color;
- canvas->FillRectInt(border_color, 0, 0, width(), 1);
- canvas->FillRectInt(border_color, 0, 0, 1, height() - 1);
- canvas->FillRectInt(border_color, width() - 1, 0, 1, height() - 1);
- int ext_width = view()->width() + kToolstripPadding +
- kToolstripDividerWidth;
- if (ext_width < width()) {
- canvas->FillRectInt(border_color, ext_width, height() - 1,
- width() - ext_width, 1);
- }
-
- if (handle_visible_) {
- // Draw the title using a Label as a stamp.
- // See constructor for comment about this.
- title_->ProcessPaint(canvas);
-
- if (dragging_) {
- // When we're dragging, draw the bottom border.
- canvas->FillRectInt(border_color, 0, height() - 1, width(), 1);
- }
- }
-}
-
-gfx::Size ExtensionShelf::Toolstrip::GetHandlePreferredSize() {
- gfx::Size sz;
- if (handle_visible_) {
- sz = title_->GetPreferredSize();
- sz.set_width(std::max(view()->width(), sz.width()));
- sz.Enlarge(2 + kHandlePadding * 2, kHandlePadding * 2);
- }
- return sz;
-}
-
-gfx::Size ExtensionShelf::Toolstrip::GetPreferredSize() {
- gfx::Size sz;
- if (handle_visible_)
- sz = GetHandlePreferredSize();
- if (view()->GetParent() == this) {
- gfx::Size extension_size = view()->GetPreferredSize();
- sz.Enlarge(0, extension_size.height());
- sz.set_width(extension_size.width());
- }
-
- // The view is inset slightly when displayed in the window.
- sz.Enlarge(kWindowInset * 2, kWindowInset * 2);
- return sz;
-}
-
-void ExtensionShelf::Toolstrip::Layout() {
- if (view()->GetParent() == this) {
- int view_y = kWindowInset;
- if (handle_visible_)
- view_y += GetHandlePreferredSize().height();
- view()->SetBounds(kWindowInset, view_y, view()->width(), view()->height());
- }
-}
-
-void ExtensionShelf::Toolstrip::OnMouseEntered(const views::MouseEvent& event) {
- if (dragging_)
- return;
- ShowShelfHandle();
-}
-
-void ExtensionShelf::Toolstrip::OnMouseExited(const views::MouseEvent& event) {
- if (dragging_)
- return;
- HideShelfHandle(kHideDelayMs);
-}
-
-bool ExtensionShelf::Toolstrip::OnMousePressed(const views::MouseEvent& event) {
- initial_drag_location_ = event.location();
- initial_drag_screen_point_ = views::Screen::GetCursorScreenPoint();
- return true;
-}
-
-bool ExtensionShelf::Toolstrip::OnMouseDragged(const views::MouseEvent& event) {
- if (expanded_) {
- // Do nothing for now.
- } else if (!dragging_) {
- int y_delta = abs(initial_drag_location_.y() - event.location().y());
- int x_delta = abs(initial_drag_location_.x() - event.location().x());
- if (y_delta > GetVerticalDragThreshold() ||
- x_delta > GetHorizontalDragThreshold()) {
- dragging_ = true;
- StopHandleTimer();
- DetachFromShelf(true);
- }
- } else {
- // When freely dragging a window, you can really only trust the
- // actual screen point. Local coordinate conversions don't work.
- gfx::Point screen = views::Screen::GetCursorScreenPoint();
-
- // However, the handle is actually a child of the browser window
- // so we need to convert it back to local coordinates.
- gfx::Point origin(0, 0);
- views::View::ConvertPointToScreen(shelf_->GetRootView(), &origin);
- int screen_x = screen.x() - initial_drag_location_.x() - origin.x();
-
- // Restrict the horizontal and vertical motions of the toolstrip so that it
- // cannot be dragged out of the extension shelf. If the extension shelf is
- // on the top along with the bookmark bar, the toolstrip cannot be dragged
- // into the space allocated for bookmarks. The toolstrip cannot be dragged
- // out of the browser window.
- if (screen_x < kExtensionShelfPaddingOnLeft) {
- screen_x = kExtensionShelfPaddingOnLeft;
- } else if (screen_x > shelf_->width() - width() +
- kExtensionShelfPaddingOnLeft) {
- screen_x = shelf_->width() - width() + kExtensionShelfPaddingOnLeft;
- }
- screen.set_x(screen_x);
- screen.set_y(initial_drag_screen_point_.y() - origin.y() -
- initial_drag_location_.y());
-
- // TODO(erikkay) as this gets dragged around, update the placeholder view
- // on the shelf to show where it will get dropped to.
- window_->MoveTo(screen.x(), screen.y());
- }
- return true;
-}
-
-void ExtensionShelf::Toolstrip::OnMouseReleased(const views::MouseEvent& event,
- bool canceled) {
- StopHandleTimer();
- if (dragging_) {
- // Drop the toolstrip roughly where it is now.
- views::View::OnMouseReleased(event, canceled);
- dragging_ = false;
- // |this| and |shelf_| are in different view hierarchies, so we need to
- // convert to screen coordinates and back again to map locations.
- gfx::Point loc = event.location();
- View::ConvertPointToScreen(this, &loc);
- View::ConvertPointToView(NULL, shelf_, &loc);
- shelf_->DropExtension(this, loc, canceled);
- AttachToShelf(true);
- } else if (!canceled) {
- // Toggle mole to either expanded or collapsed.
- // TODO(erikkay) If there's no valid URL in the manifest, should we
- // post an event to the toolstrip in this case?
- if (expanded_) {
- if (info_.toolstrip.is_valid())
- shelf_->CollapseToolstrip(host_, info_.toolstrip);
- } else {
- if (info_.mole.is_valid())
- shelf_->ExpandToolstrip(host_, info_.mole, info_.mole_height);
- }
- }
-}
-
-void ExtensionShelf::Toolstrip::LayoutWindow() {
- if (!window_visible() && !handle_visible_ && !expanded_)
- return;
-
- if (!window_.get()) {
- window_.reset(new BrowserBubble(this, shelf_->GetWidget(),
- gfx::Point(0, 0),
- false)); // Do not add a drop-shadow.
- window_->set_delegate(this);
- }
-
- gfx::Size window_size = GetPreferredSize();
- if (mole_animation_->is_animating()) {
- // We only want to animate the body of the mole window. When we're
- // expanding, this is everything except for the handle. When we're
- // collapsing, this is everything except for the handle and the toolstrip.
- // We subtract this amount from the target height, figure out the step in
- // the animation from the rest, and then add it back in.
- int window_offset = shelf_->height();
- if (!mole_animation_->IsShowing())
- window_offset += GetPreferredSize().height();
- else
- window_offset += GetHandlePreferredSize().height();
- int h = expanded_height_ - window_offset;
- window_size.set_height(window_offset +
- static_cast<int>(h * mole_animation_->GetCurrentValue()));
- } else if (!expanded_ && !dragging_) {
- window_size.set_height(GetHandlePreferredSize().height());
- }
-
- // Now figure out where to place the window on the screen. Since it's a top-
- // level widget, we need to do some coordinate conversion to get this right.
- gfx::Point origin(-kToolstripPadding, 0);
- if (expanded_ || mole_animation_->is_animating()) {
- origin.set_y(GetShelfView()->height() - window_size.height());
- views::View::ConvertPointToView(GetShelfView(), shelf_->GetRootView(),
- &origin);
- } else {
- origin.set_y(-(window_size.height() + kToolstripPadding - 1));
- views::View::ConvertPointToWidget(view(), &origin);
- }
- SetBounds(0, 0, window_size.width(), window_size.height());
- window_->SetBounds(origin.x(), origin.y(),
- window_size.width(), window_size.height());
-}
-
-void ExtensionShelf::Toolstrip::ChildPreferredSizeChanged(View* child) {
- if (child == view()) {
- child->SizeToPreferredSize();
- Layout();
- if (window_visible())
- LayoutWindow();
- if (expanded_) {
- placeholder_view_->SetWidth(child->width());
- shelf_->Layout();
- }
- }
-}
-
-void ExtensionShelf::Toolstrip::BubbleBrowserWindowMoved(
- BrowserBubble* bubble) {
- if (!expanded_)
- HideWindow();
-}
-
-void ExtensionShelf::Toolstrip::BubbleBrowserWindowClosing(
- BrowserBubble* bubble) {
- HideWindow();
-}
-
-void ExtensionShelf::Toolstrip::AnimationProgressed(
- const Animation* animation) {
- LayoutWindow();
-}
-
-void ExtensionShelf::Toolstrip::AnimationEnded(const Animation* animation) {
- if (window_visible())
- LayoutWindow();
- if (!expanded_) {
- AttachToShelf(false);
- HideShelfHandle(kHideDelayMs);
- }
-}
-
-void ExtensionShelf::Toolstrip::DetachFromShelf(bool browserDetach) {
- DCHECK(window_.get());
- DCHECK(!placeholder_view_);
- if (browserDetach && window_->attached())
- window_->DetachFromBrowser();
-
- // Construct a placeholder view to replace the view.
- placeholder_view_ = new PlaceholderView();
- placeholder_view_->SetBounds(view()->bounds());
- shelf_->AddChildView(placeholder_view_);
-
- AddChildView(view());
- SizeToPreferredSize();
- window_->ResizeToView();
- Layout();
-}
-
-void ExtensionShelf::Toolstrip::AttachToShelf(bool browserAttach) {
- DCHECK(window_.get());
- DCHECK(placeholder_view_);
- if (browserAttach && !window_->attached())
- window_->AttachToBrowser();
-
- // Move the view back into the shelf and remove the old placeholder.
- shelf_->AddChildView(view());
-
- // The size of the view may have changed, so just set the position.
- view()->SetX(placeholder_view_->x());
- view()->SetY(placeholder_view_->y());
-
- // Remove the old placeholder.
- shelf_->RemoveChildView(placeholder_view_);
- delete placeholder_view_;
- placeholder_view_ = NULL;
-
- SizeToPreferredSize();
- Layout();
- shelf_->Layout();
-}
-
-void ExtensionShelf::Toolstrip::DoShowShelfHandle() {
- if (!handle_visible()) {
- handle_visible_ = true;
-
- // Make sure the text color for the title matches the theme colors.
- title_->SetColor(
- shelf_->GetThemeProvider()->GetColor(
- BrowserThemeProvider::COLOR_BOOKMARK_TEXT));
-
- ShowWindow();
- }
-}
-
-void ExtensionShelf::Toolstrip::HideWindow() {
- if (!window_visible())
- return;
- handle_visible_ = false;
- window_->Hide();
- if (expanded_) {
- if (info_.toolstrip.is_valid())
- shelf_->CollapseToolstrip(host_, info_.toolstrip);
- else
- shelf_->CollapseToolstrip(host_, GURL());
- }
- if (window_->attached())
- window_->DetachFromBrowser();
- window_.reset(NULL);
- shelf_->Layout();
-}
-
-void ExtensionShelf::Toolstrip::ShowWindow() {
- DCHECK(handle_visible_ || expanded_);
-
- LayoutWindow();
- if (!window_visible())
- window_->Show(false); // |false| means show, but don't activate.
-}
-
-void ExtensionShelf::Toolstrip::DoHideShelfHandle() {
- if (!handle_visible())
- return;
- handle_visible_ = false;
- if (expanded_) {
- LayoutWindow();
- Layout();
- } else {
- HideWindow();
- }
-}
-
-void ExtensionShelf::Toolstrip::StopHandleTimer() {
- if (!timer_factory_.empty())
- timer_factory_.RevokeAll();
-}
-
-void ExtensionShelf::Toolstrip::Expand(int height, const GURL& url) {
- DCHECK(!expanded_);
-
- expanded_ = true;
- ShowWindow();
-
- bool navigate = (!url.is_empty() && url != host_->GetURL());
- if (navigate)
- host_->NavigateToURL(url);
-
- StopHandleTimer();
- DetachFromShelf(false);
-
- mole_animation_->Show();
-
- gfx::Size extension_size = view()->GetPreferredSize();
- extension_size.set_height(height);
- view()->SetPreferredSize(extension_size);
- expanded_height_ = GetPreferredSize().height();
-
- // This is to prevent flickering as the page loads and lays out.
- // Once the navigation is finished, ExtensionView will wind up setting
- // visibility to true.
- if (navigate)
- view()->SetVisible(false);
-}
-
-void ExtensionShelf::Toolstrip::Collapse(const GURL& url) {
- DCHECK(expanded_);
- expanded_ = false;
-
- if (window_visible())
- mole_animation_->Hide();
-
- gfx::Size extension_size = view()->GetPreferredSize();
- extension_size.set_height(
- kShelfHeight - (shelf_->top_margin() + kBottomMargin));
- view()->SetPreferredSize(extension_size);
-
- if (!url.is_empty() && url != host_->GetURL()) {
- host_->NavigateToURL(url);
-
- // This is to prevent flickering as the page loads and lays out.
- // Once the navigation is finished, ExtensionView will wind up setting
- // visibility to true.
- view()->SetVisible(false);
- }
-
- if (!window_visible())
- AnimationEnded(NULL);
-}
-
-void ExtensionShelf::Toolstrip::ShowShelfHandle() {
- StopHandleTimer();
- if (handle_visible())
- return;
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- timer_factory_.NewRunnableMethod(
- &ExtensionShelf::Toolstrip::DoShowShelfHandle),
- kShowDelayMs);
-}
-
-void ExtensionShelf::Toolstrip::HideShelfHandle(int delay_ms) {
- StopHandleTimer();
- if (!handle_visible() || dragging_ || mole_animation_->is_animating())
- return;
- if (delay_ms) {
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- timer_factory_.NewRunnableMethod(
- &ExtensionShelf::Toolstrip::DoHideShelfHandle),
- delay_ms);
- } else {
- DoHideShelfHandle();
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-ExtensionShelf::ExtensionShelf(Browser* browser)
- : background_needs_repaint_(true),
- browser_(browser),
- model_(browser->extension_shelf_model()),
- fullscreen_(false) {
- SetID(VIEW_ID_DEV_EXTENSION_SHELF);
-
- top_margin_ = kTopMarginWhenExtensionsOnBottom;
-
- model_->AddObserver(this);
- LoadFromModel();
- EnableCanvasFlippingForRTLUI(true);
- registrar_.Add(this,
- NotificationType::EXTENSION_SHELF_VISIBILITY_PREF_CHANGED,
- NotificationService::AllSources());
-
- size_animation_.reset(new SlideAnimation(this));
- if (IsAlwaysShown())
- size_animation_->Reset(1);
- else
- size_animation_->Reset(0);
-}
-
-ExtensionShelf::~ExtensionShelf() {
- if (model_) {
- int count = model_->count();
- for (int i = 0; i < count; ++i) {
- delete ToolstripAtIndex(i);
- model_->SetToolstripDataAt(i, NULL);
- }
- model_->RemoveObserver(this);
- }
-}
-
-void ExtensionShelf::PaintChildren(gfx::Canvas* canvas) {
- InitBackground(canvas);
-
- int max_x = width();
- if (IsDetached())
- max_x -= 2 * kNewtabHorizontalPadding;
-
- // Draw vertical dividers between Toolstrip items in the Extension shelf.
- int count = GetChildViewCount();
- for (int i = 0; i < count; ++i) {
- int right = GetChildViewAt(i)->bounds().right() + kToolstripPadding;
- if (right >= max_x)
- break;
- int vertical_padding = IsDetached() ? (height() - kShelfHeight) / 2 : 1;
-
- DetachableToolbarView::PaintVerticalDivider(
- canvas, right, height(), vertical_padding,
- DetachableToolbarView::kEdgeDividerColor,
- DetachableToolbarView::kMiddleDividerColor,
- GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR));
- }
-}
-
-// static
-void ExtensionShelf::ToggleWhenExtensionShelfVisible(Profile* profile) {
- PrefService* prefs = profile->GetPrefs();
- const bool always_show = !prefs->GetBoolean(prefs::kShowExtensionShelf);
-
- // The user changed when the Extension Shelf is shown, update the
- // preferences.
- prefs->SetBoolean(prefs::kShowExtensionShelf, always_show);
- prefs->ScheduleSavePersistentPrefs();
-
- // And notify the notification service.
- Source<Profile> source(profile);
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_SHELF_VISIBILITY_PREF_CHANGED,
- source,
- NotificationService::NoDetails());
-}
-
-gfx::Size ExtensionShelf::GetPreferredSize() {
- return LayoutItems(true);
-}
-
-void ExtensionShelf::ChildPreferredSizeChanged(View* child) {
- PreferredSizeChanged();
-}
-
-void ExtensionShelf::Layout() {
- LayoutItems(false);
-}
-
-void ExtensionShelf::OnMouseEntered(const views::MouseEvent& event) {
-}
-
-void ExtensionShelf::OnMouseExited(const views::MouseEvent& event) {
-}
-
-bool ExtensionShelf::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_TOOLBAR;
- return true;
-}
-
-void ExtensionShelf::ThemeChanged() {
- // Refresh the CSS to update toolstrip text colors from theme.
- int count = model_->count();
- for (int i = 0; i < count; ++i)
- ToolstripAtIndex(i)->view()->host()->InsertThemedToolstripCSS();
-
- Layout();
-}
-
-void ExtensionShelf::ToolstripInsertedAt(ExtensionHost* host,
- int index) {
- model_->SetToolstripDataAt(index,
- new Toolstrip(this, host, model_->ToolstripAt(index).info));
-
- bool had_views = GetChildViewCount() > 0;
- ExtensionView* view = host->view();
- AddChildView(view);
- view->SetContainer(this);
- if (!had_views)
- PreferredSizeChanged();
- Layout();
-}
-
-void ExtensionShelf::ToolstripRemovingAt(ExtensionHost* host, int index) {
- // Delete the Toolstrip view and remove it from the model.
- Toolstrip* toolstrip = ToolstripAtIndex(index);
- View* view = toolstrip->GetShelfView();
- RemoveChildView(view);
- delete toolstrip;
- model_->SetToolstripDataAt(index, NULL);
-
- // Technically, the toolstrip is still in the model at this point, but
- // the Layout code handles this case.
- Layout();
-}
-
-void ExtensionShelf::ToolstripDraggingFrom(ExtensionHost* host, int index) {
-}
-
-void ExtensionShelf::ToolstripMoved(ExtensionHost* host, int from_index,
- int to_index) {
- Layout();
-}
-
-void ExtensionShelf::ToolstripChanged(ExtensionShelfModel::iterator toolstrip) {
- Toolstrip* t = static_cast<Toolstrip*>(toolstrip->data);
- if (toolstrip->height > 0) {
- if (!t->expanded()) {
- t->Expand(toolstrip->height, toolstrip->url);
- }
- } else if (t->expanded()) {
- t->Collapse(toolstrip->url);
- }
-}
-
-void ExtensionShelf::ExtensionShelfEmpty() {
- PreferredSizeChanged();
-}
-
-void ExtensionShelf::ShelfModelReloaded() {
- // None of the child views are parent owned, so nothing is being leaked here.
- RemoveAllChildViews(false);
- LoadFromModel();
-}
-
-void ExtensionShelf::ShelfModelDeleting() {
- int count = model_->count();
- for (int i = 0; i < count; ++i) {
- delete ToolstripAtIndex(i);
- model_->SetToolstripDataAt(i, NULL);
- }
- model_->RemoveObserver(this);
- model_ = NULL;
-}
-
-void ExtensionShelf::AnimationProgressed(const Animation* animation) {
- if (browser_)
- browser_->ExtensionShelfSizeChanged();
-}
-
-void ExtensionShelf::AnimationEnded(const Animation* animation) {
- if (browser_)
- browser_->ExtensionShelfSizeChanged();
-
- Layout();
-}
-
-void ExtensionShelf::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_SHELF_VISIBILITY_PREF_CHANGED: {
- if (fullscreen_)
- break;
- if (IsAlwaysShown())
- size_animation_->Show();
- else
- size_animation_->Hide();
- break;
- }
- default:
- NOTREACHED();
- break;
- }
-}
-
-void ExtensionShelf::OnExtensionMouseEvent(ExtensionView* view) {
- Toolstrip *toolstrip = ToolstripForView(view);
- if (toolstrip)
- toolstrip->ShowShelfHandle();
-}
-
-void ExtensionShelf::OnExtensionMouseLeave(ExtensionView* view) {
- Toolstrip *toolstrip = ToolstripForView(view);
- if (toolstrip)
- toolstrip->HideShelfHandle(kHideDelayMs);
-}
-
-void ExtensionShelf::DropExtension(Toolstrip* toolstrip, const gfx::Point& pt,
- bool cancel) {
- Toolstrip* dest_toolstrip = ToolstripAtX(pt.x());
- if (!dest_toolstrip) {
- if (pt.x() > 0)
- dest_toolstrip = ToolstripAtIndex(model_->count() - 1);
- else
- dest_toolstrip = ToolstripAtIndex(0);
- }
- if (toolstrip == dest_toolstrip)
- return;
- int from = model_->IndexOfHost(toolstrip->host());
- int to = model_->IndexOfHost(dest_toolstrip->host());
- DCHECK(from != to);
- model_->MoveToolstripAt(from, to);
-}
-
-void ExtensionShelf::ExpandToolstrip(ExtensionHost* host, const GURL& url,
- int height) {
- ExtensionShelfModel::iterator toolstrip = model_->ToolstripForHost(host);
- model_->ExpandToolstrip(toolstrip, url, height);
-}
-
-void ExtensionShelf::CollapseToolstrip(ExtensionHost* host, const GURL& url) {
- ExtensionShelfModel::iterator toolstrip = model_->ToolstripForHost(host);
- model_->CollapseToolstrip(toolstrip, url);
-}
-
-void ExtensionShelf::InitBackground(gfx::Canvas* canvas) {
- if (!background_needs_repaint_)
- return;
-
- // Capture a background bitmap to give to the toolstrips.
- SkRect background_rect = {
- SkIntToScalar(0),
- SkIntToScalar(0),
- SkIntToScalar(width()),
- SkIntToScalar(height())
- };
-
- // Tell all extension views about the new background.
- int count = model_->count();
- for (int i = 0; i < count; ++i) {
- ExtensionView* view = ToolstripAtIndex(i)->view();
-
- const SkBitmap& background =
- canvas->AsCanvasSkia()->getDevice()->accessBitmap(false);
-
- SkRect mapped_subset = background_rect;
- gfx::Rect view_bounds = view->bounds();
- mapped_subset.offset(SkIntToScalar(view_bounds.x()),
- SkIntToScalar(view_bounds.y()));
- bool result =
- canvas->AsCanvasSkia()->getTotalMatrix().mapRect(&mapped_subset);
- DCHECK(result);
-
- SkIRect isubset;
- mapped_subset.round(&isubset);
- SkBitmap subset_bitmap;
- // This will create another bitmap that just references pixels in the
- // actual bitmap.
- result = background.extractSubset(&subset_bitmap, isubset);
- if (!result)
- return;
-
- // We do a deep copy because extractSubset() returns a bitmap that
- // references pixels in the original one and we want to actually make a
- // smaller copy that will have a long lifetime.
- SkBitmap smaller_copy;
- if (!subset_bitmap.copyTo(&smaller_copy, SkBitmap::kARGB_8888_Config))
- return;
- DCHECK(smaller_copy.readyToDraw());
-
- view->SetBackground(smaller_copy);
- }
-
- background_needs_repaint_ = false;
-}
-
-ExtensionShelf::Toolstrip* ExtensionShelf::ToolstripAtX(int x) {
- int count = model_->count();
- if (count == 0)
- return NULL;
-
- if (x < 0)
- return NULL;
-
- for (int i = 0; i < count; ++i) {
- Toolstrip* toolstrip = ToolstripAtIndex(i);
- View* view = toolstrip->GetShelfView();
- int x_mirrored = view->GetRootView()->MirroredXCoordinateInsideView(x);
- if (x_mirrored > view->x() + view->width() + kToolstripPadding)
- continue;
- return toolstrip;
- }
-
- return NULL;
-}
-
-ExtensionShelf::Toolstrip* ExtensionShelf::ToolstripAtIndex(int index) {
- return static_cast<Toolstrip*>(model_->ToolstripAt(index).data);
-}
-
-ExtensionShelf::Toolstrip* ExtensionShelf::ToolstripForView(
- ExtensionView* view) {
- int count = model_->count();
- for (int i = 0; i < count; ++i) {
- Toolstrip* toolstrip = ToolstripAtIndex(i);
- if (view == toolstrip->view())
- return toolstrip;
- }
- return NULL;
-}
-
-void ExtensionShelf::LoadFromModel() {
- int count = model_->count();
- for (int i = 0; i < count; ++i)
- ToolstripInsertedAt(model_->ToolstripAt(i).host, i);
-}
-
-gfx::Size ExtensionShelf::LayoutItems(bool compute_bounds_only) {
- if (!GetParent() || !model_ || !model_->count())
- return gfx::Size(0, 0);
-
- gfx::Size prefsize;
- int x = kLeftMargin;
- int y = top_margin_;
- int content_height = kShelfHeight - top_margin_ - kBottomMargin;
- int max_x = width() - kRightMargin;
-
- if (OnNewTabPage()) {
- double current_state = 1 - size_animation_->GetCurrentValue();
- x += static_cast<int>(static_cast<double>
- (kNewtabHorizontalPadding + kNewtabExtraHorMargin) * current_state);
- y += static_cast<int>(static_cast<double>
- (kNewtabVerticalPadding + kNewtabExtraVerMargin) * current_state);
- max_x -= static_cast<int>(static_cast<double>
- (2 * kNewtabHorizontalPadding) * current_state);
- }
-
- int count = model_->count();
- for (int i = 0; i < count; ++i) {
- x += kToolstripPadding; // Left padding.
- Toolstrip* toolstrip = ToolstripAtIndex(i);
- if (!toolstrip) // Can be NULL while in the process of removing.
- continue;
- View* view = toolstrip->GetShelfView();
- gfx::Size pref = view->GetPreferredSize();
-
- // |next_x| is the x value for where the next toolstrip in the list will be.
- int next_x = x + pref.width() + kToolstripPadding; // Right padding.
- if (!compute_bounds_only) {
- bool clipped = next_x >= max_x;
- if (clipped)
- pref.set_width(std::max(0, max_x - x));
- if (view == toolstrip->view())
- toolstrip->view()->SetIsClipped(clipped);
- view->SetBounds(x, y, pref.width(), content_height);
- view->Layout();
- if (toolstrip->window_visible())
- toolstrip->LayoutWindow();
- }
- x = next_x + kToolstripDividerWidth;
- }
-
- if (!compute_bounds_only) {
- background_needs_repaint_ = true;
- SchedulePaint();
- } else {
- if (OnNewTabPage()) {
- prefsize.set_height(kShelfHeight + static_cast<int>(static_cast<double>
- (kNewtabShelfHeight - kShelfHeight) *
- (1 - size_animation_->GetCurrentValue())));
- } else {
- prefsize.set_height(static_cast<int>(static_cast<double>(kShelfHeight) *
- size_animation_->GetCurrentValue()));
- }
-
- x += kRightMargin;
- prefsize.set_width(x);
- }
-
- return prefsize;
-}
-
-bool ExtensionShelf::IsDetached() const {
- return OnNewTabPage() && (size_animation_->GetCurrentValue() != 1);
-}
-
-bool ExtensionShelf::IsAlwaysShown() const {
- Profile* profile = browser_->profile();
- return profile->GetPrefs()->GetBoolean(prefs::kShowExtensionShelf);
-}
-
-bool ExtensionShelf::OnNewTabPage() const {
- return (browser_ && browser_->GetSelectedTabContents() &&
- browser_->GetSelectedTabContents()->IsExtensionShelfAlwaysVisible());
-}
-
-void ExtensionShelf::OnFullscreenToggled(bool fullscreen) {
- if (fullscreen == fullscreen_)
- return;
- fullscreen_ = fullscreen;
- if (!IsAlwaysShown())
- return;
- size_animation_->Reset(fullscreen ? 0 : 1);
-}
diff --git a/chrome/browser/views/extensions/extension_shelf.h b/chrome/browser/views/extensions/extension_shelf.h
deleted file mode 100644
index b13b79c..0000000
--- a/chrome/browser/views/extensions/extension_shelf.h
+++ /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 CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_SHELF_H_
-#define CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_SHELF_H_
-
-#include "app/slide_animation.h"
-#include "base/task.h"
-#include "chrome/browser/extensions/extension_shelf_model.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/views/browser_bubble.h"
-#include "chrome/browser/views/detachable_toolbar_view.h"
-#include "gfx/canvas.h"
-#include "views/view.h"
-
-class Browser;
-namespace views {
- class Label;
- class MouseEvent;
-}
-
-// A shelf that contains Extension toolstrips.
-class ExtensionShelf : public DetachableToolbarView,
- public ExtensionView::Container,
- public ExtensionShelfModelObserver,
- public AnimationDelegate,
- public NotificationObserver {
- public:
- explicit ExtensionShelf(Browser* browser);
- virtual ~ExtensionShelf();
-
- // Get the current model.
- ExtensionShelfModel* model() { return model_; }
-
- // Toggles a preference for whether to always show the extension shelf.
- static void ToggleWhenExtensionShelfVisible(Profile* profile);
-
- int top_margin() { return top_margin_; }
-
- // DetachableToolbarView methods:
- virtual bool IsDetached() const;
- virtual double GetAnimationValue() const {
- return size_animation_->GetCurrentValue();
- }
-
- // View methods:
- virtual void PaintChildren(gfx::Canvas* canvas);
- virtual gfx::Size GetPreferredSize();
- virtual void Layout();
- virtual void OnMouseExited(const views::MouseEvent& event);
- virtual void OnMouseEntered(const views::MouseEvent& event);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
- virtual void ThemeChanged();
-
- // ExtensionContainer methods:
- virtual void OnExtensionMouseEvent(ExtensionView* view);
- virtual void OnExtensionMouseLeave(ExtensionView* view);
-
- // ExtensionShelfModelObserver methods:
- virtual void ToolstripInsertedAt(ExtensionHost* toolstrip, int index);
- virtual void ToolstripRemovingAt(ExtensionHost* toolstrip, int index);
- virtual void ToolstripDraggingFrom(ExtensionHost* toolstrip, int index);
- virtual void ToolstripMoved(ExtensionHost* toolstrip,
- int from_index,
- int to_index);
- virtual void ToolstripChanged(ExtensionShelfModel::iterator toolstrip);
- virtual void ExtensionShelfEmpty();
- virtual void ShelfModelReloaded();
- virtual void ShelfModelDeleting();
-
- // AnimationDelegate methods:
- virtual void AnimationProgressed(const Animation* animation);
- virtual void AnimationEnded(const Animation* animation);
-
- // NotificationObserver methods:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Toggle fullscreen mode.
- void OnFullscreenToggled(bool fullscreen);
-
- protected:
- // View methods:
- virtual void ChildPreferredSizeChanged(View* child);
-
- private:
- class Toolstrip;
- friend class Toolstrip;
- class PlaceholderView;
-
- // Dragging toolstrips
- void DropExtension(Toolstrip* handle, const gfx::Point& pt, bool cancel);
-
- // Expand the specified toolstrip, navigating to |url| if non-empty,
- // and setting the |height|.
- void ExpandToolstrip(ExtensionHost* host, const GURL& url, int height);
-
- // Collapse the specified toolstrip, navigating to |url| if non-empty.
- void CollapseToolstrip(ExtensionHost* host, const GURL& url);
-
- // Initializes the background bitmaps for all views.
- void InitBackground(gfx::Canvas* canvas);
-
- // Returns the Toolstrip at |x| coordinate. If |x| is out of bounds, returns
- // NULL.
- Toolstrip* ToolstripAtX(int x);
-
- // Returns the Toolstrip at |index|.
- Toolstrip* ToolstripAtIndex(int index);
-
- // Returns the toolstrip associated with |view|.
- Toolstrip* ToolstripForView(ExtensionView* view);
-
- // Loads initial state from |model_|.
- void LoadFromModel();
-
- // This method computes the bounds for the extension shelf items. If
- // |compute_bounds_only| = TRUE, the bounds for the items are just computed,
- // but are not set. This mode is used by GetPreferredSize() to obtain the
- // desired bounds. If |compute_bounds_only| = FALSE, the bounds are set.
- gfx::Size LayoutItems(bool compute_bounds_only);
-
- // Returns whether the extension shelf always shown (checks pref value).
- bool IsAlwaysShown() const;
-
- // Returns whether the extension shelf is being displayed over the new tab
- // page.
- bool OnNewTabPage() const;
-
- int top_margin_;
-
- NotificationRegistrar registrar_;
-
- // Background bitmap to draw under extension views.
- bool background_needs_repaint_;
-
- // The browser this extension shelf belongs to.
- Browser* browser_;
-
- // The model representing the toolstrips on the shelf.
- ExtensionShelfModel* model_;
-
- // Animation controlling showing and hiding of the shelf.
- scoped_ptr<SlideAnimation> size_animation_;
-
- // Are we in fullscreen mode or not.
- bool fullscreen_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionShelf);
-};
-
-#endif // CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_SHELF_H_
diff --git a/chrome/browser/views/extensions/extension_view.cc b/chrome/browser/views/extensions/extension_view.cc
index 0090bda..062bc00 100644
--- a/chrome/browser/views/extensions/extension_view.cc
+++ b/chrome/browser/views/extensions/extension_view.cc
@@ -120,13 +120,7 @@ void ExtensionView::ShowIfCompletelyLoaded() {
// We wait to show the ExtensionView until it has loaded, and the view has
// actually been created. These can happen in different orders.
if (host_->did_stop_loading()) {
- // For toolstrips, also wait until our parent has given us a background.
- if (host_->GetRenderViewType() == ViewType::EXTENSION_TOOLSTRIP &&
- render_view_host()->view()->background().empty()) {
- return;
- }
SetVisible(true);
-
UpdatePreferredSize(pending_preferred_size_);
}
}
@@ -179,12 +173,12 @@ void ExtensionView::PreferredSizeChanged() {
bool ExtensionView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
// Let the tab key event be processed by the renderer (instead of moving the
// focus to the next focusable view).
- return (e.GetKeyCode() == base::VKEY_TAB);
+ return (e.GetKeyCode() == app::VKEY_TAB);
}
-void ExtensionView::HandleMouseEvent() {
+void ExtensionView::HandleMouseMove() {
if (container_)
- container_->OnExtensionMouseEvent(this);
+ container_->OnExtensionMouseMove(this);
}
void ExtensionView::HandleMouseLeave() {
diff --git a/chrome/browser/views/extensions/extension_view.h b/chrome/browser/views/extensions/extension_view.h
index 3b379b1..6eded74 100644
--- a/chrome/browser/views/extensions/extension_view.h
+++ b/chrome/browser/views/extensions/extension_view.h
@@ -1,13 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_VIEW_H_
#define CHROME_BROWSER_VIEWS_EXTENSIONS_EXTENSION_VIEW_H_
+#pragma once
#include "build/build_config.h"
-#include "base/scoped_ptr.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "views/controls/native/native_view_host.h"
@@ -29,7 +29,7 @@ class ExtensionView : public views::NativeViewHost {
public:
virtual ~Container() {}
// Mouse event notifications from the view. (useful for hover UI).
- virtual void OnExtensionMouseEvent(ExtensionView* view) = 0;
+ virtual void OnExtensionMouseMove(ExtensionView* view) = 0;
virtual void OnExtensionMouseLeave(ExtensionView* view) = 0;
virtual void OnExtensionPreferredSizeChanged(ExtensionView* view) {}
};
@@ -43,7 +43,7 @@ class ExtensionView : public views::NativeViewHost {
// Notification from ExtensionHost.
void UpdatePreferredSize(const gfx::Size& new_size);
- void HandleMouseEvent();
+ void HandleMouseMove();
void HandleMouseLeave();
// Method for the ExtensionHost to notify us when the RenderViewHost has a
diff --git a/chrome/browser/views/external_protocol_dialog.cc b/chrome/browser/views/external_protocol_dialog.cc
index afaba70..9546f25 100644
--- a/chrome/browser/views/external_protocol_dialog.cc
+++ b/chrome/browser/views/external_protocol_dialog.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.
@@ -81,7 +81,7 @@ bool ExternalProtocolDialog::Cancel() {
// button.
if (message_box_view_->IsCheckBoxSelected()) {
ExternalProtocolHandler::SetBlockState(
- UTF8ToWide(url_.scheme()), ExternalProtocolHandler::BLOCK);
+ url_.scheme(), ExternalProtocolHandler::BLOCK);
}
// Returning true closes the dialog.
@@ -97,7 +97,7 @@ bool ExternalProtocolDialog::Accept() {
if (message_box_view_->IsCheckBoxSelected()) {
ExternalProtocolHandler::SetBlockState(
- UTF8ToWide(url_.scheme()), ExternalProtocolHandler::DONT_BLOCK);
+ url_.scheme(), ExternalProtocolHandler::DONT_BLOCK);
}
ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url_);
diff --git a/chrome/browser/views/external_protocol_dialog.h b/chrome/browser/views/external_protocol_dialog.h
index b32582f..3932f58 100644
--- a/chrome/browser/views/external_protocol_dialog.h
+++ b/chrome/browser/views/external_protocol_dialog.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_EXTERNAL_PROTOCOL_DIALOG_H_
#define CHROME_BROWSER_VIEWS_EXTERNAL_PROTOCOL_DIALOG_H_
+#pragma once
#include "base/time.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/views/find_bar_host.cc b/chrome/browser/views/find_bar_host.cc
index 5ff60ad..3926e70 100644
--- a/chrome/browser/views/find_bar_host.cc
+++ b/chrome/browser/views/find_bar_host.cc
@@ -4,8 +4,7 @@
#include "chrome/browser/views/find_bar_host.h"
-#include "app/slide_animation.h"
-#include "base/keyboard_codes.h"
+#include "app/keyboard_codes.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/find_bar_controller.h"
@@ -41,18 +40,62 @@ FindBarHost::FindBarHost(BrowserView* browser_view)
FindBarHost::~FindBarHost() {
}
-void FindBarHost::Show(bool animate) {
- DropdownBarHost::Show(animate);
+bool FindBarHost::MaybeForwardKeystrokeToWebpage(
+ const views::Textfield::Keystroke& key_stroke) {
+ if (!ShouldForwardKeystrokeToWebpageNative(key_stroke)) {
+ // Native implementation says not to forward these events.
+ return false;
+ }
+
+ switch (key_stroke.GetKeyboardCode()) {
+ case app::VKEY_DOWN:
+ case app::VKEY_UP:
+ case app::VKEY_PRIOR:
+ case app::VKEY_NEXT:
+ break;
+ case app::VKEY_HOME:
+ case app::VKEY_END:
+ if (key_stroke.IsControlHeld())
+ break;
+ // Fall through.
+ default:
+ return false;
+ }
+
+ TabContents* contents = find_bar_controller_->tab_contents();
+ if (!contents)
+ return false;
+
+ RenderViewHost* render_view_host = contents->render_view_host();
+
+ // Make sure we don't have a text field element interfering with keyboard
+ // input. Otherwise Up and Down arrow key strokes get eaten. "Nom Nom Nom".
+ render_view_host->ClearFocusedNode();
+ NativeWebKeyboardEvent event = GetKeyboardEvent(contents, key_stroke);
+ render_view_host->ForwardKeyboardEvent(event);
+ return true;
}
-void FindBarHost::SetFocusAndSelection() {
- DropdownBarHost::SetFocusAndSelection();
+FindBarController* FindBarHost::GetFindBarController() const {
+ return find_bar_controller_;
+}
+
+void FindBarHost::SetFindBarController(FindBarController* find_bar_controller) {
+ find_bar_controller_ = find_bar_controller;
+}
+
+void FindBarHost::Show(bool animate) {
+ DropdownBarHost::Show(animate);
}
void FindBarHost::Hide(bool animate) {
DropdownBarHost::Hide(animate);
}
+void FindBarHost::SetFocusAndSelection() {
+ DropdownBarHost::SetFocusAndSelection();
+}
+
void FindBarHost::ClearResults(const FindNotificationDetails& results) {
find_bar_view()->UpdateForResult(results, string16());
}
@@ -61,14 +104,6 @@ void FindBarHost::StopAnimation() {
DropdownBarHost::StopAnimation();
}
-void FindBarHost::SetFindText(const string16& find_text) {
- find_bar_view()->SetFindText(find_text);
-}
-
-bool FindBarHost::IsFindBarVisible() {
- return DropdownBarHost::IsVisible();
-}
-
void FindBarHost::MoveWindowIfNecessary(const gfx::Rect& selection_rect,
bool no_redraw) {
// We only move the window if one is active for the current TabContents. If we
@@ -86,15 +121,51 @@ void FindBarHost::MoveWindowIfNecessary(const gfx::Rect& selection_rect,
view()->SchedulePaint();
}
+void FindBarHost::SetFindText(const string16& find_text) {
+ find_bar_view()->SetFindText(find_text);
+}
+
+void FindBarHost::UpdateUIForFindResult(const FindNotificationDetails& result,
+ const string16& find_text) {
+ if (!find_text.empty())
+ find_bar_view()->UpdateForResult(result, find_text);
+
+ // We now need to check if the window is obscuring the search results.
+ if (!result.selection_rect().IsEmpty())
+ MoveWindowIfNecessary(result.selection_rect(), false);
+
+ // Once we find a match we no longer want to keep track of what had
+ // focus. EndFindSession will then set the focus to the page content.
+ if (result.number_of_matches() > 0)
+ ResetFocusTracker();
+}
+
+bool FindBarHost::IsFindBarVisible() {
+ return DropdownBarHost::IsVisible();
+}
+
+void FindBarHost::RestoreSavedFocus() {
+ if (focus_tracker() == NULL) {
+ // TODO(brettw) Focus() should be on TabContentsView.
+ find_bar_controller_->tab_contents()->Focus();
+ } else {
+ focus_tracker()->FocusLastFocusedExternalView();
+ }
+}
+
+FindBarTesting* FindBarHost::GetFindBarTesting() {
+ return this;
+}
+
////////////////////////////////////////////////////////////////////////////////
// FindBarWin, views::AcceleratorTarget implementation:
bool FindBarHost::AcceleratorPressed(const views::Accelerator& accelerator) {
- base::KeyboardCode key = accelerator.GetKeyCode();
- if (key == base::VKEY_RETURN && accelerator.IsCtrlDown()) {
+ app::KeyboardCode key = accelerator.GetKeyCode();
+ if (key == app::VKEY_RETURN && accelerator.IsCtrlDown()) {
// Ctrl+Enter closes the Find session and navigates any link that is active.
find_bar_controller_->EndFindSession(FindBarController::kActivateSelection);
- } else if (key == base::VKEY_ESCAPE) {
+ } else if (key == app::VKEY_ESCAPE) {
// This will end the Find session and hide the window, causing it to loose
// focus and in the process unregister us as the handler for the Escape
// accelerator through the FocusWillChange event.
@@ -140,6 +211,9 @@ string16 FindBarHost::GetFindText() {
return find_bar_view()->GetFindText();
}
+////////////////////////////////////////////////////////////////////////////////
+// Overridden from DropdownBarHost:
+
gfx::Rect FindBarHost::GetDialogPosition(gfx::Rect avoid_overlapping_rect) {
// Find the area we have to work with (after accounting for scrollbars, etc).
gfx::Rect widget_bounds;
@@ -153,8 +227,9 @@ gfx::Rect FindBarHost::GetDialogPosition(gfx::Rect avoid_overlapping_rect) {
// Place the view in the top right corner of the widget boundaries (top left
// for RTL languages).
gfx::Rect view_location;
- int x = base::i18n::IsRTL() ?
- widget_bounds.x() : widget_bounds.width() - prefsize.width();
+ int x = widget_bounds.x();
+ if (!base::i18n::IsRTL())
+ x += widget_bounds.width() - prefsize.width();
int y = widget_bounds.y();
view_location.SetRect(x, y, prefsize.width(), prefsize.height());
@@ -202,82 +277,20 @@ void FindBarHost::RegisterAccelerators() {
DropdownBarHost::RegisterAccelerators();
// Register for Ctrl+Return.
- views::Accelerator escape(base::VKEY_RETURN, false, true, false);
+ views::Accelerator escape(app::VKEY_RETURN, false, true, false);
focus_manager()->RegisterAccelerator(escape, this);
}
void FindBarHost::UnregisterAccelerators() {
// Unregister Ctrl+Return.
- views::Accelerator escape(base::VKEY_RETURN, false, true, false);
+ views::Accelerator escape(app::VKEY_RETURN, false, true, false);
focus_manager()->UnregisterAccelerator(escape, this);
DropdownBarHost::UnregisterAccelerators();
}
-void FindBarHost::RestoreSavedFocus() {
- if (focus_tracker() == NULL) {
- // TODO(brettw) Focus() should be on TabContentsView.
- find_bar_controller_->tab_contents()->Focus();
- } else {
- focus_tracker()->FocusLastFocusedExternalView();
- }
-}
-
-FindBarTesting* FindBarHost::GetFindBarTesting() {
- return this;
-}
-
-void FindBarHost::UpdateUIForFindResult(const FindNotificationDetails& result,
- const string16& find_text) {
- if (!find_text.empty())
- find_bar_view()->UpdateForResult(result, find_text);
-
- // We now need to check if the window is obscuring the search results.
- if (!result.selection_rect().IsEmpty())
- MoveWindowIfNecessary(result.selection_rect(), false);
-
- // Once we find a match we no longer want to keep track of what had
- // focus. EndFindSession will then set the focus to the page content.
- if (result.number_of_matches() > 0)
- ResetFocusTracker();
-}
-
-
-bool FindBarHost::MaybeForwardKeystrokeToWebpage(
- const views::Textfield::Keystroke& key_stroke) {
- if (!ShouldForwardKeystrokeToWebpageNative(key_stroke)) {
- // Native implementation says not to forward these events.
- return false;
- }
-
- switch (key_stroke.GetKeyboardCode()) {
- case base::VKEY_DOWN:
- case base::VKEY_UP:
- case base::VKEY_PRIOR:
- case base::VKEY_NEXT:
- break;
- case base::VKEY_HOME:
- case base::VKEY_END:
- if (key_stroke.IsControlHeld())
- break;
- // Fall through.
- default:
- return false;
- }
-
- TabContents* contents = find_bar_controller_->tab_contents();
- if (!contents)
- return false;
-
- RenderViewHost* render_view_host = contents->render_view_host();
-
- // Make sure we don't have a text field element interfering with keyboard
- // input. Otherwise Up and Down arrow key strokes get eaten. "Nom Nom Nom".
- render_view_host->ClearFocusedNode();
- NativeWebKeyboardEvent event = GetKeyboardEvent(contents, key_stroke);
- render_view_host->ForwardKeyboardEvent(event);
- return true;
-}
+////////////////////////////////////////////////////////////////////////////////
+// private:
FindBarView* FindBarHost::find_bar_view() {
return static_cast<FindBarView*>(view());
diff --git a/chrome/browser/views/find_bar_host.h b/chrome/browser/views/find_bar_host.h
index d0a946e..d675b3c 100644
--- a/chrome/browser/views/find_bar_host.h
+++ b/chrome/browser/views/find_bar_host.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_VIEWS_FIND_BAR_HOST_H_
#define CHROME_BROWSER_VIEWS_FIND_BAR_HOST_H_
+#pragma once
-#include "app/animation.h"
#include "chrome/browser/find_bar.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/views/dropdown_bar_host.h"
@@ -48,12 +48,8 @@ class FindBarHost : public DropdownBarHost,
const views::Textfield::Keystroke& key_stroke);
// FindBar implementation:
- virtual FindBarController* GetFindBarController() const {
- return find_bar_controller_;
- }
- virtual void SetFindBarController(FindBarController* find_bar_controller) {
- find_bar_controller_ = find_bar_controller;
- }
+ virtual FindBarController* GetFindBarController() const;
+ virtual void SetFindBarController(FindBarController* find_bar_controller);
virtual void Show(bool animate);
virtual void Hide(bool animate);
virtual void SetFocusAndSelection();
diff --git a/chrome/browser/views/find_bar_host_interactive_uitest.cc b/chrome/browser/views/find_bar_host_interactive_uitest.cc
index 51080bf..d0b5e2e 100644
--- a/chrome/browser/views/find_bar_host_interactive_uitest.cc
+++ b/chrome/browser/views/find_bar_host_interactive_uitest.cc
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/keyboard_codes.h"
-#include "base/message_loop.h"
-#include "chrome/browser/automation/ui_controls.h"
+#include "app/keyboard_codes.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_window.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/views/find_bar_host.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/view_ids.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
#include "views/focus/focus_manager.h"
#include "views/view.h"
@@ -22,7 +22,6 @@ namespace {
// The delay waited after sending an OS simulated event.
static const int kActionDelayMs = 500;
-static const wchar_t kDocRoot[] = L"chrome/test/data";
static const char kSimplePage[] = "files/find_in_page/simple.html";
class FindInPageTest : public InProcessBrowserTest {
@@ -32,51 +31,6 @@ class FindInPageTest : public InProcessBrowserTest {
FindBarHost::disable_animations_during_testing_ = true;
}
- void ClickOnView(ViewID view_id) {
- BrowserWindow* browser_window = browser()->window();
- ASSERT_TRUE(browser_window);
-#if defined(TOOLKIT_VIEWS)
- views::View* view =
- reinterpret_cast<BrowserView*>(browser_window)->GetViewByID(view_id);
-#elif defined(OS_LINUX)
- gfx::NativeWindow window = browser_window->GetNativeHandle();
- ASSERT_TRUE(window);
- GtkWidget* view = ViewIDUtil::GetWidget(GTK_WIDGET(window), view_id);
-#endif
- ASSERT_TRUE(view);
- ui_controls::MoveMouseToCenterAndPress(view,
- ui_controls::LEFT,
- ui_controls::DOWN | ui_controls::UP,
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
- }
-
- int GetFocusedViewID() {
-#if defined(TOOLKIT_VIEWS)
-#if defined(OS_LINUX)
- // See http://crbug.com/26873 .
- views::FocusManager* focus_manager =
- views::FocusManager::GetFocusManagerForNativeView(
- GTK_WIDGET(browser()->window()->GetNativeHandle()));
-#else
- views::FocusManager* focus_manager =
- views::FocusManager::GetFocusManagerForNativeView(
- browser()->window()->GetNativeHandle());
-#endif
-
- if (!focus_manager) {
- NOTREACHED();
- return -1;
- }
- views::View* focused_view = focus_manager->GetFocusedView();
- if (!focused_view)
- return -1;
- return focused_view->GetID();
-#else
- return -1;
-#endif
- }
-
string16 GetFindBarText() {
FindBarTesting* find_bar =
browser()->GetFindBarController()->find_bar()->GetFindBarTesting();
@@ -87,22 +41,24 @@ class FindInPageTest : public InProcessBrowserTest {
} // namespace
IN_PROC_BROWSER_TEST_F(FindInPageTest, CrashEscHandlers) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to our test page (tab A).
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
browser()->Find();
// Open another tab (tab B).
+ Browser* browser_used = NULL;
browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, -1,
- TabStripModel::ADD_SELECTED, NULL, std::string());
+ TabStripModel::ADD_SELECTED, NULL, std::string(),
+ &browser_used);
+ EXPECT_EQ(browser(), browser_used);
browser()->Find();
- EXPECT_EQ(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
// Select tab A.
browser()->SelectTabContentsAt(0, true);
@@ -111,59 +67,60 @@ IN_PROC_BROWSER_TEST_F(FindInPageTest, CrashEscHandlers) {
browser()->CloseTabContents(browser()->GetTabContentsAt(1));
// Click on the location bar so that Find box loses focus.
- ClickOnView(VIEW_ID_LOCATION_BAR);
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::ClickOnView(browser(),
+ VIEW_ID_LOCATION_BAR));
#if defined(TOOLKIT_VIEWS) || defined(OS_WIN)
// Check the location bar is focused.
- EXPECT_EQ(VIEW_ID_LOCATION_BAR, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
#endif
// This used to crash until bug 1303709 was fixed.
- ui_controls::SendKeyPressNotifyWhenDone(
- browser()->window()->GetNativeHandle(), base::VKEY_ESCAPE,
- false, false, false, false, new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_ESCAPE, false, false, false, false));
}
IN_PROC_BROWSER_TEST_F(FindInPageTest, FocusRestore) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server()->Start());
- GURL url = server->TestServerPage("title1.html");
+ GURL url = test_server()->GetURL("title1.html");
ui_test_utils::NavigateToURL(browser(), url);
// Focus the location bar, open and close the find-in-page, focus should
// return to the location bar.
browser()->FocusLocationBar();
- EXPECT_EQ(VIEW_ID_LOCATION_BAR, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
// Ensure the creation of the find bar controller.
browser()->GetFindBarController()->Show();
- EXPECT_EQ(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
browser()->GetFindBarController()->EndFindSession(
FindBarController::kKeepSelection);
- EXPECT_EQ(VIEW_ID_LOCATION_BAR, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
// Focus the location bar, find something on the page, close the find box,
// focus should go to the page.
browser()->FocusLocationBar();
browser()->Find();
- EXPECT_EQ(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
ui_test_utils::FindInPage(browser()->GetSelectedTabContents(),
ASCIIToUTF16("a"), true, false, NULL);
browser()->GetFindBarController()->EndFindSession(
FindBarController::kKeepSelection);
- EXPECT_EQ(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
// Focus the location bar, open and close the find box, focus should return to
// the location bar (same as before, just checking that http://crbug.com/23599
// is fixed).
browser()->FocusLocationBar();
- EXPECT_EQ(VIEW_ID_LOCATION_BAR, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
browser()->GetFindBarController()->Show();
- EXPECT_EQ(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD, GetFocusedViewID());
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
browser()->GetFindBarController()->EndFindSession(
FindBarController::kKeepSelection);
- EXPECT_EQ(VIEW_ID_LOCATION_BAR, GetFocusedViewID());
+ 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
@@ -175,41 +132,32 @@ IN_PROC_BROWSER_TEST_F(FindInPageTest, PrepopulateRespectBlank) {
return;
#endif
- HTTPTestServer* server = StartHTTPServer();
- ASSERT_TRUE(server);
+ ASSERT_TRUE(test_server()->Start());
// First we navigate to any page.
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
- gfx::NativeWindow window = browser()->window()->GetNativeHandle();
-
// Show the Find bar.
browser()->GetFindBarController()->Show();
// Search for "a".
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_A,
- false, false, false, false, // No modifiers.
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_A, false, false, false, false));
// We should find "a" here.
EXPECT_EQ(ASCIIToUTF16("a"), GetFindBarText());
// Delete "a".
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_BACK,
- false, false, false, false, // No modifiers.
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_BACK, false, false, false, false));
// Validate we have cleared the text.
EXPECT_EQ(string16(), GetFindBarText());
// Close the Find box.
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_ESCAPE,
- false, false, false, false, // No modifiers.
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_ESCAPE, false, false, false, false));
// Show the Find bar.
browser()->GetFindBarController()->Show();
@@ -219,16 +167,12 @@ IN_PROC_BROWSER_TEST_F(FindInPageTest, PrepopulateRespectBlank) {
EXPECT_EQ(string16(), GetFindBarText());
// Close the Find box.
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_ESCAPE,
- false, false, false, false, // No modifiers.
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_ESCAPE, false, false, false, false));
// Press F3 to trigger FindNext.
- ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F3,
- false, false, false, false, // No modifiers.
- new MessageLoop::QuitTask());
- ui_test_utils::RunMessageLoop();
+ 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.
diff --git a/chrome/browser/views/find_bar_host_uitest.cc b/chrome/browser/views/find_bar_host_uitest.cc
index fa54871..df4ea0e 100644
--- a/chrome/browser/views/find_bar_host_uitest.cc
+++ b/chrome/browser/views/find_bar_host_uitest.cc
@@ -6,7 +6,7 @@
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
class FindInPageControllerTest : public UITest {
public:
@@ -25,11 +25,11 @@ const std::string kSimplePage = "404_is_enough_for_us.html";
// The find window should not change its location just because we open and close
// a new tab.
TEST_F(FindInPageControllerTest, FindMovesOnTabClose_Issue1343052) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+ ASSERT_TRUE(test_server.Start());
- GURL url = server->TestServerPage(kSimplePage);
+ GURL url = test_server.GetURL(kSimplePage);
scoped_refptr<TabProxy> tabA(GetActiveTab());
ASSERT_TRUE(tabA.get());
ASSERT_TRUE(tabA->NavigateToURL(url));
diff --git a/chrome/browser/views/find_bar_view.cc b/chrome/browser/views/find_bar_view.cc
index ae78c3c..7132553 100644
--- a/chrome/browser/views/find_bar_view.cc
+++ b/chrome/browser/views/find_bar_view.cc
@@ -8,14 +8,17 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
-#include "chrome/browser/browser_theme_provider.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/tab_contents/tab_contents.h"
-#include "chrome/browser/views/find_bar_host.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 "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -23,6 +26,7 @@
#include "views/background.h"
#include "views/controls/button/image_button.h"
#include "views/controls/label.h"
+#include "views/widget/widget.h"
// The amount of whitespace to have before the find button.
static const int kWhiteSpaceAfterMatchCountLabel = 1;
@@ -161,8 +165,7 @@ FindBarView::FindBarView(FindBarHost* host)
// Background images for the Find edit box.
kBackground = rb.GetBitmapNamed(IDR_FIND_BOX_BACKGROUND);
- kBackground_left = rb.GetBitmapNamed(base::i18n::IsRTL() ?
- IDR_FIND_BOX_BACKGROUND_LEFT_RTL : IDR_FIND_BOX_BACKGROUND_LEFT);
+ kBackground_left = rb.GetBitmapNamed(IDR_FIND_BOX_BACKGROUND_LEFT);
}
}
@@ -199,8 +202,8 @@ void FindBarView::UpdateForResult(const FindNotificationDetails& result,
if (!find_text.empty() && have_valid_range) {
match_count_text_->SetText(
l10n_util::GetStringF(IDS_FIND_IN_PAGE_COUNT,
- IntToWString(result.active_match_ordinal()),
- IntToWString(result.number_of_matches())));
+ UTF8ToWide(base::IntToString(result.active_match_ordinal())),
+ UTF8ToWide(base::IntToString(result.number_of_matches()))));
UpdateMatchCountAppearance(result.number_of_matches() == 0 &&
result.final_update());
@@ -231,8 +234,17 @@ void FindBarView::SetFocusAndSelection(bool select_all) {
void FindBarView::Paint(gfx::Canvas* canvas) {
SkPaint paint;
- // Get the local bounds so that we now how much to stretch the background.
- gfx::Rect lb = GetLocalBounds(true);
+ // Determine the find bar size as well as the offset from which to tile the
+ // toolbar background image. First, get the widget bounds.
+ gfx::Rect bounds;
+ GetWidget()->GetBounds(&bounds, true);
+ // Now convert from screen to parent coordinates.
+ gfx::Point origin(bounds.origin());
+ BrowserView* browser_view = host()->browser_view();
+ ConvertPointToView(NULL, browser_view, &origin);
+ bounds.set_origin(origin);
+ // Finally, calculate the background image tiling offset.
+ origin = browser_view->OffsetPointForToolbarBackgroundImage(origin);
// First, we draw the background image for the whole dialog (3 images: left,
// middle and right). Note, that the window region has been set by the
@@ -240,76 +252,54 @@ void FindBarView::Paint(gfx::Canvas* canvas) {
// actually outside the window region and is therefore not drawn. See
// FindInPageWidgetWin::CreateRoundedWindowEdges() for details.
ThemeProvider* tp = GetThemeProvider();
- gfx::Rect bounds;
- host()->GetThemePosition(&bounds);
- canvas->TileImageInt(*tp->GetBitmapNamed(IDR_THEME_TOOLBAR),
- bounds.x(), bounds.y(), 0, 0, lb.width(), lb.height());
+ canvas->TileImageInt(*tp->GetBitmapNamed(IDR_THEME_TOOLBAR), origin.x(),
+ origin.y(), 0, 0, bounds.width(), bounds.height());
+
+ // Now flip the canvas for the rest of the graphics if in RTL mode.
+ canvas->Save();
+ if (base::i18n::IsRTL()) {
+ canvas->TranslateInt(width(), 0);
+ canvas->ScaleInt(-1, 1);
+ }
canvas->DrawBitmapInt(*kDialog_left, 0, 0);
// Stretch the middle background to cover all of the area between the two
// other images.
- canvas->TileImageInt(*kDialog_middle,
- kDialog_left->width(),
- 0,
- lb.width() -
- kDialog_left->width() -
- kDialog_right->width(),
- kDialog_middle->height());
+ canvas->TileImageInt(*kDialog_middle, kDialog_left->width(), 0,
+ bounds.width() - kDialog_left->width() - kDialog_right->width(),
+ kDialog_middle->height());
- canvas->DrawBitmapInt(*kDialog_right, lb.right() - kDialog_right->width(), 0);
+ canvas->DrawBitmapInt(*kDialog_right, bounds.width() - kDialog_right->width(),
+ 0);
// Then we draw the background image for the Find Textfield. We start by
// calculating the position of background images for the Find text box.
- gfx::Rect find_text_rect;
- gfx::Rect back_button_rect;
- int x = 0; // x coordinate of the curved edge background image.
- int w = 0; // width of the background image for the text field.
- if (base::i18n::IsRTL()) {
- find_text_rect = find_text_->GetBounds(APPLY_MIRRORING_TRANSFORMATION);
- back_button_rect =
- find_previous_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION);
- x = find_text_rect.right();
- w = find_text_rect.right() - back_button_rect.right();
- } else {
- find_text_rect = find_text_->bounds();
- back_button_rect = find_previous_button_->bounds();
- x = find_text_rect.x() - kBackground_left->width();
- w = back_button_rect.x() - find_text_rect.x();
- }
+ int find_text_x = find_text_->x();
+ gfx::Point back_button_origin = find_previous_button_->bounds().origin();
- // Draw the image to the left that creates a curved left edge for the box
- // (drawn on the right for RTL languages).
+ // Draw the image to the left that creates a curved left edge for the box.
canvas->TileImageInt(*kBackground_left,
- x,
- back_button_rect.y(),
- kBackground_left->width(),
- kBackground_left->height());
+ find_text_x - kBackground_left->width(), back_button_origin.y(),
+ kBackground_left->width(), kBackground_left->height());
// Draw the top and bottom border for whole text box (encompasses both the
// find_text_ edit box and the match_count_text_ label).
- int background_height = kBackground->height();
- canvas->TileImageInt(*kBackground,
- base::i18n::IsRTL() ?
- back_button_rect.right() : find_text_rect.x(),
- back_button_rect.y(),
- w,
- background_height);
+ canvas->TileImageInt(*kBackground, find_text_x, back_button_origin.y(),
+ back_button_origin.x() - find_text_x,
+ kBackground->height());
if (animation_offset() > 0) {
// While animating we draw the curved edges at the point where the
// controller told us the top of the window is: |animation_offset()|.
- canvas->TileImageInt(*kDialog_left,
- lb.x(),
- animation_offset(),
- kDialog_left->width(),
- kAnimatingEdgeHeight);
+ canvas->TileImageInt(*kDialog_left, bounds.x(), animation_offset(),
+ kDialog_left->width(), kAnimatingEdgeHeight);
canvas->TileImageInt(*kDialog_right,
- lb.right() - kDialog_right->width(),
- animation_offset(),
- kDialog_right->width(),
- kAnimatingEdgeHeight);
+ bounds.width() - kDialog_right->width(), animation_offset(),
+ kDialog_right->width(), kAnimatingEdgeHeight);
}
+
+ canvas->Restore();
}
void FindBarView::Layout() {
@@ -323,7 +313,7 @@ void FindBarView::Layout() {
sz.width(),
sz.height());
// Set the color.
- ThemeChanged();
+ OnThemeChanged();
// Next, the FindNext button to the left the close button.
sz = find_next_button_->GetPreferredSize();
@@ -485,7 +475,7 @@ bool FindBarView::HandleKeystroke(views::Textfield* sender,
if (find_bar_host()->MaybeForwardKeystrokeToWebpage(key))
return true; // Handled, we are done!
- if (key.GetKeyboardCode() == base::VKEY_RETURN) {
+ if (key.GetKeyboardCode() == app::VKEY_RETURN) {
// Pressing Return/Enter starts the search (unless text box is empty).
string16 find_string = find_text_->text();
if (!find_string.empty()) {
@@ -525,7 +515,7 @@ FindBarHost* FindBarView::find_bar_host() const {
return static_cast<FindBarHost*>(host());
}
-void FindBarView::ThemeChanged() {
+void FindBarView::OnThemeChanged() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
if (GetThemeProvider()) {
close_button_->SetBackground(
diff --git a/chrome/browser/views/find_bar_view.h b/chrome/browser/views/find_bar_view.h
index efedc94..ab119b9 100644
--- a/chrome/browser/views/find_bar_view.h
+++ b/chrome/browser/views/find_bar_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_FIND_BAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_FIND_BAR_VIEW_H_
+#pragma once
#include "base/string16.h"
#include "chrome/browser/find_notification_details.h"
@@ -76,7 +77,7 @@ class FindBarView : public DropdownBarView,
void UpdateMatchCountAppearance(bool no_match);
// Overridden from views::View.
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
// We use a hidden view to grab mouse clicks and bring focus to the find
// text box. This is because although the find text box may look like it
diff --git a/chrome/browser/views/first_run_bubble.cc b/chrome/browser/views/first_run_bubble.cc
index 0ebc0c7..fae2cfa 100644
--- a/chrome/browser/views/first_run_bubble.cc
+++ b/chrome/browser/views/first_run_bubble.cc
@@ -9,12 +9,10 @@
#include "app/resource_bundle.h"
#include "app/win_util.h"
#include "base/utf_string_conversions.h"
-#include "base/win_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/first_run.h"
-#include "chrome/browser/options_window.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/search_engines/util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "grit/chromium_strings.h"
@@ -150,10 +148,10 @@ void FirstRunBubbleView::ButtonPressed(views::Button* sender,
UserMetrics::RecordAction(
UserMetricsAction("FirstRunBubbleView_ChangeButton"),
profile_);
+
Browser* browser = BrowserList::GetLastActive();
if (browser) {
- ShowOptionsWindow(OPTIONS_PAGE_GENERAL, OPTIONS_GROUP_DEFAULT_SEARCH,
- browser->profile());
+ browser->OpenSearchEngineOptionsDialog();
}
}
}
@@ -469,13 +467,13 @@ FirstRunBubble* FirstRunBubble::Show(Profile* profile,
FirstRunBubbleViewBase* view = NULL;
switch (bubble_type) {
- case FirstRun::OEMBUBBLE:
+ case FirstRun::OEM_BUBBLE:
view = new FirstRunOEMBubbleView(window, profile);
break;
- case FirstRun::LARGEBUBBLE:
+ case FirstRun::LARGE_BUBBLE:
view = new FirstRunBubbleView(window, profile);
break;
- case FirstRun::MINIMALBUBBLE:
+ case FirstRun::MINIMAL_BUBBLE:
view = new FirstRunMinimalBubbleView(window, profile);
break;
default:
@@ -495,9 +493,8 @@ FirstRunBubble::FirstRunBubble()
}
FirstRunBubble::~FirstRunBubble() {
- // We should have called RevokeAll on the method factory already.
- DCHECK(enable_window_method_factory_.empty());
enable_window_method_factory_.RevokeAll();
+ GetFocusManager()->RemoveFocusChangeListener(view_);
}
void FirstRunBubble::EnableParent() {
@@ -510,7 +507,7 @@ void FirstRunBubble::EnableParent() {
void FirstRunBubble::OnActivate(UINT action, BOOL minimized, HWND window) {
// Keep the bubble around for kLingerTime milliseconds, to prevent accidental
// closure.
- const int kLingerTime = 1000;
+ const int kLingerTime = 3000;
// We might get re-enabled right before we are closed (sequence is: we get
// deactivated, we call close, before we are actually closed we get
@@ -524,6 +521,7 @@ void FirstRunBubble::OnActivate(UINT action, BOOL minimized, HWND window) {
enable_window_method_factory_.NewRunnableMethod(
&FirstRunBubble::EnableParent),
kLingerTime);
+ return;
}
// Keep window from automatically closing until kLingerTime has passed.
@@ -536,6 +534,4 @@ void FirstRunBubble::InfoBubbleClosing(InfoBubble* info_bubble,
// Make sure our parent window is re-enabled.
if (!IsWindowEnabled(GetParent()))
::EnableWindow(GetParent(), true);
- enable_window_method_factory_.RevokeAll();
- GetFocusManager()->RemoveFocusChangeListener(view_);
}
diff --git a/chrome/browser/views/first_run_bubble.h b/chrome/browser/views/first_run_bubble.h
index adee35a..7de3969 100644
--- a/chrome/browser/views/first_run_bubble.h
+++ b/chrome/browser/views/first_run_bubble.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_VIEWS_FIRST_RUN_BUBBLE_H_
#define CHROME_BROWSER_VIEWS_FIRST_RUN_BUBBLE_H_
+#pragma once
#include "base/compiler_specific.h"
#include "base/task.h"
-#include "chrome/browser/first_run.h"
+#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/views/info_bubble.h"
class FirstRunBubbleViewBase;
diff --git a/chrome/browser/views/first_run_search_engine_view.cc b/chrome/browser/views/first_run_search_engine_view.cc
index 174f830..3b7b137 100644
--- a/chrome/browser/views/first_run_search_engine_view.cc
+++ b/chrome/browser/views/first_run_search_engine_view.cc
@@ -6,15 +6,19 @@
#include <algorithm>
#include <map>
+#include <vector>
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#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/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
+#include "gfx/canvas.h"
#include "gfx/font.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
@@ -35,9 +39,6 @@ using TemplateURLPrepopulateData::SearchEngineType;
namespace {
-// Represents an id for which we have no logo.
-const int kNoLogo = -1;
-
// Size to scale logos down to if showing 4 instead of 3 choices. Logo images
// are all originally sized at 180 x 120 pixels, with the logo text baseline
// located 74 pixels beneath the top of the image.
@@ -47,54 +48,6 @@ const int kSmallLogoHeight = 88;
// Used to pad text label height so it fits nicely in view.
const int kLabelPadding = 25;
-int GetSearchEngineLogo(const TemplateURL* template_url) {
- typedef std::map<SearchEngineType, int> LogoMap;
- static LogoMap type_to_logo;
- if (type_to_logo.empty()) {
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_GOOGLE,
- IDR_SEARCH_ENGINE_LOGO_GOOGLE));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOO,
- IDR_SEARCH_ENGINE_LOGO_YAHOO));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_YAHOOJP,
- IDR_SEARCH_ENGINE_LOGO_YAHOOJP));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_BING,
- IDR_SEARCH_ENGINE_LOGO_BING));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_ASK,
- IDR_SEARCH_ENGINE_LOGO_ASK));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_YANDEX,
- IDR_SEARCH_ENGINE_LOGO_YANDEX));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_SEZNAM,
- IDR_SEARCH_ENGINE_LOGO_SEZNAM));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_CENTRUM,
- IDR_SEARCH_ENGINE_LOGO_CENTRUMCZ));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_NETSPRINT,
- IDR_SEARCH_ENGINE_LOGO_NETSPRINT));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_VIRGILIO,
- IDR_SEARCH_ENGINE_LOGO_VIRGILIO));
- type_to_logo.insert(std::make_pair<SearchEngineType, int>(
- TemplateURLPrepopulateData::SEARCH_ENGINE_MAILRU,
- IDR_SEARCH_ENGINE_LOGO_MAILRU));
- }
-
- LogoMap::iterator logo = type_to_logo.find(
- TemplateURLPrepopulateData::GetSearchEngineType(template_url));
- if (logo != type_to_logo.end())
- return logo->second;
-
- // Logo does not exist:
- return kNoLogo;
-}
-
} // namespace
SearchEngineChoice::SearchEngineChoice(views::ButtonListener* listener,
@@ -102,13 +55,14 @@ SearchEngineChoice::SearchEngineChoice(views::ButtonListener* listener,
bool use_small_logos)
: NativeButton(listener, l10n_util::GetString(IDS_FR_SEARCH_CHOOSE)),
is_image_label_(false),
- search_engine_(search_engine) {
+ search_engine_(search_engine),
+ slot_(0) {
bool use_images = false;
#if defined(GOOGLE_CHROME_BUILD)
use_images = true;
#endif
- int logo_id = GetSearchEngineLogo(search_engine_);
- if (use_images && logo_id != kNoLogo) {
+ int logo_id = search_engine_->logo_id();
+ if (use_images && logo_id > 0) {
is_image_label_ = true;
views::ImageView* logo_image = new views::ImageView();
SkBitmap* logo_bmp =
@@ -192,6 +146,16 @@ void FirstRunSearchEngineView::ButtonPressed(views::Button* sender,
MessageLoop::current()->Quit();
}
+void FirstRunSearchEngineView::Paint(gfx::Canvas* canvas) {
+ // Fill in behind the background image with the standard gray toolbar color.
+ canvas->FillRectInt(SkColorSetRGB(237, 238, 237), 0, 0, width(),
+ background_image_->height());
+ // The rest of the dialog background should be white.
+ DCHECK(height() > background_image_->height());
+ canvas->FillRectInt(SK_ColorWHITE, 0, background_image_->height(), width(),
+ height() - background_image_->height());
+}
+
void FirstRunSearchEngineView::OnTemplateURLModelChanged() {
using views::ImageView;
@@ -204,10 +168,12 @@ void FirstRunSearchEngineView::OnTemplateURLModelChanged() {
std::vector<const TemplateURL*> template_urls =
search_engines_model_->GetTemplateURLs();
- // If we have fewer than three search engines, signal that the search engine
- // experiment is over, leaving imported default search engine setting intact.
- if (template_urls.size() < 3)
+ // If we have fewer than two search engines, end search engine dialog
+ // immediately, leaving imported default search engine setting intact.
+ if (template_urls.size() < 2) {
+ MessageLoop::current()->Quit();
return;
+ }
std::vector<const TemplateURL*>::iterator search_engine_iter;
@@ -235,9 +201,12 @@ void FirstRunSearchEngineView::OnTemplateURLModelChanged() {
}
// Now that we know what size the logos should be, create new search engine
- // choices for the view:
+ // choices for the view. If there are 2 search engines, only show 2
+ // choices; for 3 or more, show 3 (unless the default is not one of the
+ // top 3, in which case show 4).
for (search_engine_iter = template_urls.begin();
- search_engine_iter < template_urls.begin() + 3;
+ search_engine_iter < template_urls.begin() +
+ (template_urls.size() < 3 ? 2 : 3);
++search_engine_iter) {
// Push first three engines into buttons:
SearchEngineChoice* choice = new SearchEngineChoice(this,
@@ -255,10 +224,9 @@ void FirstRunSearchEngineView::OnTemplateURLModelChanged() {
// Randomize order of logos if option has been set.
if (randomize_) {
- int seed = static_cast<int>(Time::Now().ToInternalValue());
- srand(seed);
std::random_shuffle(search_engine_choices_.begin(),
- search_engine_choices_.end());
+ search_engine_choices_.end(),
+ base::RandGenerator);
// Assign to each choice the position in which it is shown on the screen.
std::vector<SearchEngineChoice*>::iterator it;
int slot = 0;
@@ -290,13 +258,17 @@ void FirstRunSearchEngineView::SetupControls() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
background_image_ = new views::ImageView();
background_image_->SetImage(rb.GetBitmapNamed(IDR_SEARCH_ENGINE_DIALOG_TOP));
- background_image_->SetHorizontalAlignment(ImageView::TRAILING);
+ background_image_->EnableCanvasFlippingForRTLUI(true);
+ if (text_direction_is_rtl_) {
+ background_image_->SetHorizontalAlignment(ImageView::LEADING);
+ } else {
+ background_image_->SetHorizontalAlignment(ImageView::TRAILING);
+ }
+
AddChildView(background_image_);
int label_width = GetPreferredSize().width() - 2 * kPanelHorizMargin;
- set_background(Background::CreateSolidBackground(SK_ColorWHITE));
-
// Add title and text asking the user to choose a search engine:
title_label_ = new Label(l10n_util::GetString(
IDS_FR_SEARCH_MAIN_LABEL));
@@ -386,8 +358,10 @@ void FirstRunSearchEngineView::Layout() {
next_h_space = search_engine_choices_[1]->GetView()->x() + logo_width +
logo_padding;
- search_engine_choices_[2]->SetChoiceViewBounds(
- next_h_space, next_v_space, logo_width, logo_height);
+ if (num_choices > 2) {
+ search_engine_choices_[2]->SetChoiceViewBounds(
+ next_h_space, next_v_space, logo_width, logo_height);
+ }
if (num_choices > 3) {
next_h_space = search_engine_choices_[2]->GetView()->x() + logo_width +
@@ -410,8 +384,10 @@ void FirstRunSearchEngineView::Layout() {
search_engine_choices_[1]->SetBounds(next_h_space, next_v_space,
button_width, button_height);
next_h_space = search_engine_choices_[1]->x() + logo_width + logo_padding;
- search_engine_choices_[2]->SetBounds(next_h_space, next_v_space,
- button_width, button_height);
+ if (num_choices > 2) {
+ search_engine_choices_[2]->SetBounds(next_h_space, next_v_space,
+ button_width, button_height);
+ }
if (num_choices > 3) {
next_h_space = search_engine_choices_[2]->x() + logo_width +
diff --git a/chrome/browser/views/first_run_search_engine_view.h b/chrome/browser/views/first_run_search_engine_view.h
index 6e162a7..8ce3448 100644
--- a/chrome/browser/views/first_run_search_engine_view.h
+++ b/chrome/browser/views/first_run_search_engine_view.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_VIEWS_FIRST_RUN_SEARCH_ENGINE_VIEW_H_
#define CHROME_BROWSER_VIEWS_FIRST_RUN_SEARCH_ENGINE_VIEW_H_
+#pragma once
#include <vector>
-#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
#include "gfx/size.h"
#include "views/controls/button/native_button.h"
#include "views/view.h"
@@ -96,12 +97,15 @@ class FirstRunSearchEngineView
views::View* GetContentsView() { return this; }
bool CanResize() const { return false; }
bool CanMaximize() const { return false; }
- bool IsAlwaysOnTop() const { return false; }
+ bool IsAlwaysOnTop() const { return true; }
bool HasAlwaysOnTopMenu() const { return false; }
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+ // Override from View so we can draw the gray background at dialog top.
+ virtual void Paint(gfx::Canvas* canvas);
+
// Overridden from TemplateURLModelObserver. When the search engines have
// loaded from the profile, we can populate the logos in the dialog box
// to present to the user.
diff --git a/chrome/browser/views/frame/app_panel_browser_frame_view.cc b/chrome/browser/views/frame/app_panel_browser_frame_view.cc
index 16ebec3..d7efbe9 100644
--- a/chrome/browser/views/frame/app_panel_browser_frame_view.cc
+++ b/chrome/browser/views/frame/app_panel_browser_frame_view.cc
@@ -93,6 +93,12 @@ gfx::Rect AppPanelBrowserFrameView::GetBoundsForTabStrip(
return gfx::Rect();
}
+int AppPanelBrowserFrameView::GetHorizontalTabStripVerticalOffset(
+ bool restored) const {
+ // App panels are not themed and don't need this.
+ return 0;
+}
+
void AppPanelBrowserFrameView::UpdateThrobber(bool running) {
window_icon_->Update();
}
@@ -477,7 +483,7 @@ void AppPanelBrowserFrameView::LayoutTitleBar() {
// Size the title.
int title_x = icon_bounds.right() + kIconTitleSpacing;
- int title_height = BrowserFrame::GetTitleFont().height();
+ int title_height = BrowserFrame::GetTitleFont().GetHeight();
// We bias the title position so that when the difference between the icon
// and title heights is odd, the extra pixel of the title is above the
// vertical midline rather than below. This compensates for how the icon is
diff --git a/chrome/browser/views/frame/app_panel_browser_frame_view.h b/chrome/browser/views/frame/app_panel_browser_frame_view.h
index 0f8bd3a..eae6d9b 100644
--- a/chrome/browser/views/frame/app_panel_browser_frame_view.h
+++ b/chrome/browser/views/frame/app_panel_browser_frame_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_FRAME_APP_PANEL_BROWSER_FRAME_VIEW_H_
#define CHROME_BROWSER_VIEWS_FRAME_APP_PANEL_BROWSER_FRAME_VIEW_H_
+#pragma once
#include "chrome/browser/views/frame/browser_frame.h"
#include "chrome/browser/views/frame/browser_non_client_frame_view.h"
@@ -34,6 +35,7 @@ class AppPanelBrowserFrameView : public BrowserNonClientFrameView,
// Overridden from BrowserNonClientFrameView:
virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const;
+ virtual int GetHorizontalTabStripVerticalOffset(bool restored) const;
virtual void UpdateThrobber(bool running);
virtual gfx::Size GetMinimumSize();
diff --git a/chrome/browser/views/frame/browser_bubble_host.h b/chrome/browser/views/frame/browser_bubble_host.h
index 4763a50..99b8058 100644
--- a/chrome/browser/views/frame/browser_bubble_host.h
+++ b/chrome/browser/views/frame/browser_bubble_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_BUBBLE_HOST_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_BUBBLE_HOST_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/views/frame/browser_frame.h b/chrome/browser/views/frame/browser_frame.h
index 31b489f..0e3b9b2 100644
--- a/chrome/browser/views/frame/browser_frame.h
+++ b/chrome/browser/views/frame/browser_frame.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_H_
+#pragma once
#include "build/build_config.h"
#include "views/window/non_client_view.h"
@@ -49,6 +50,11 @@ class BrowserFrame {
// TabStrip.
virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const = 0;
+ // Returns the y coordinate within the window at which the horizontal TabStrip
+ // begins (or would begin). If |restored| is true, this is calculated as if
+ // we were in restored mode regardless of the current mode.
+ virtual int GetHorizontalTabStripVerticalOffset(bool restored) const = 0;
+
// Tells the frame to update the throbber.
virtual void UpdateThrobber(bool running) = 0;
diff --git a/chrome/browser/views/frame/browser_frame_gtk.cc b/chrome/browser/views/frame/browser_frame_gtk.cc
index a1302ee..0b529b7 100644
--- a/chrome/browser/views/frame/browser_frame_gtk.cc
+++ b/chrome/browser/views/frame/browser_frame_gtk.cc
@@ -5,57 +5,18 @@
#include "chrome/browser/views/frame/browser_frame_gtk.h"
#include "base/logging.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/status_bubble.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 "gfx/font.h"
#include "views/widget/root_view.h"
#include "views/window/hit_test.h"
-namespace {
-
-// BrowserNonClientFrameView implementation for popups. We let the window
-// manager implementation render the decorations for popups, so this draws
-// nothing.
-class PopupNonClientFrameView : public BrowserNonClientFrameView {
- public:
- PopupNonClientFrameView() {
- }
-
- // NonClientFrameView:
- virtual gfx::Rect GetBoundsForClientView() const {
- return gfx::Rect(0, 0, width(), height());
- }
- virtual bool AlwaysUseCustomFrame() const { return false; }
- virtual bool AlwaysUseNativeFrame() const { return true; }
- virtual gfx::Rect GetWindowBoundsForClientBounds(
- const gfx::Rect& client_bounds) const {
- return client_bounds;
- }
- virtual int NonClientHitTest(const gfx::Point& point) {
- return bounds().Contains(point) ? HTCLIENT : HTNOWHERE;
- }
- virtual void GetWindowMask(const gfx::Size& size,
- gfx::Path* window_mask) {}
- virtual void EnableClose(bool enable) {}
- virtual void ResetWindowControls() {}
-
- // BrowserNonClientFrameView:
- virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const {
- return gfx::Rect(0, 0, width(), tabstrip->GetPreferredHeight());
- }
- virtual void UpdateThrobber(bool running) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PopupNonClientFrameView);
-};
-
-}
-
#if !defined(OS_CHROMEOS)
// static (Factory method.)
BrowserFrame* BrowserFrame::Create(BrowserView* browser_view,
@@ -86,7 +47,8 @@ BrowserFrameGtk::~BrowserFrameGtk() {
void BrowserFrameGtk::Init() {
if (browser_frame_view_ == NULL) {
- if (browser_view_->browser()->type() == Browser::TYPE_POPUP)
+ if (browser_view_->browser()->type() == Browser::TYPE_POPUP ||
+ browser_view_->browser()->type() == Browser::TYPE_APP_PANEL)
browser_frame_view_ = new PopupNonClientFrameView();
else
browser_frame_view_ = new OpaqueBrowserFrameView(this, browser_view_);
@@ -109,6 +71,10 @@ gfx::Rect BrowserFrameGtk::GetBoundsForTabStrip(BaseTabStrip* tabstrip) const {
return browser_frame_view_->GetBoundsForTabStrip(tabstrip);
}
+int BrowserFrameGtk::GetHorizontalTabStripVerticalOffset(bool restored) const {
+ return browser_frame_view_->GetHorizontalTabStripVerticalOffset(restored);
+}
+
void BrowserFrameGtk::UpdateThrobber(bool running) {
browser_frame_view_->UpdateThrobber(running);
}
@@ -132,6 +98,10 @@ views::View* BrowserFrameGtk::GetFrameView() const {
}
void BrowserFrameGtk::TabStripDisplayModeChanged() {
+ if (GetRootView()->GetChildViewCount() > 0) {
+ // Make sure the child of the root view gets Layout again.
+ GetRootView()->GetChildViewAt(0)->InvalidateLayout();
+ }
GetRootView()->Layout();
}
diff --git a/chrome/browser/views/frame/browser_frame_gtk.h b/chrome/browser/views/frame/browser_frame_gtk.h
index 10904dd..742eea5 100644
--- a/chrome/browser/views/frame/browser_frame_gtk.h
+++ b/chrome/browser/views/frame/browser_frame_gtk.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_GTK_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_GTK_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/views/frame/browser_frame.h"
@@ -30,6 +31,7 @@ class BrowserFrameGtk : public BrowserFrame,
virtual views::Window* GetWindow();
virtual int GetMinimizeButtonOffset() const;
virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const;
+ virtual int GetHorizontalTabStripVerticalOffset(bool restored) const;
virtual void UpdateThrobber(bool running);
virtual void ContinueDraggingDetachedTab();
virtual ThemeProvider* GetThemeProviderForFrame() const;
diff --git a/chrome/browser/views/frame/browser_frame_win.cc b/chrome/browser/views/frame/browser_frame_win.cc
index 7ddd92f..5aad9a5 100644
--- a/chrome/browser/views/frame/browser_frame_win.cc
+++ b/chrome/browser/views/frame/browser_frame_win.cc
@@ -9,13 +9,11 @@
#include <set>
-#include "app/resource_bundle.h"
-#include "app/theme_provider.h"
#include "app/win_util.h"
#include "base/win_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_theme_provider.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"
@@ -69,15 +67,6 @@ void BrowserFrameWin::Init() {
BrowserFrameWin::~BrowserFrameWin() {
}
-int BrowserFrameWin::GetTitleBarHeight() {
- RECT caption = { 0 };
- if (DwmGetWindowAttribute(GetNativeView(), DWMWA_CAPTION_BUTTON_BOUNDS,
- &caption, sizeof(RECT)) == S_OK) {
- return caption.bottom;
- }
- return GetSystemMetrics(SM_CYCAPTION);
-}
-
views::Window* BrowserFrameWin::GetWindow() {
return this;
}
@@ -98,6 +87,10 @@ gfx::Rect BrowserFrameWin::GetBoundsForTabStrip(BaseTabStrip* tabstrip) const {
return browser_frame_view_->GetBoundsForTabStrip(tabstrip);
}
+int BrowserFrameWin::GetHorizontalTabStripVerticalOffset(bool restored) const {
+ return browser_frame_view_->GetHorizontalTabStripVerticalOffset(restored);
+}
+
void BrowserFrameWin::UpdateThrobber(bool running) {
browser_frame_view_->UpdateThrobber(running);
}
@@ -137,9 +130,13 @@ views::View* BrowserFrameWin::GetFrameView() const {
}
void BrowserFrameWin::TabStripDisplayModeChanged() {
+ if (GetRootView()->GetChildViewCount() > 0) {
+ // Make sure the child of the root view gets Layout again.
+ GetRootView()->GetChildViewAt(0)->InvalidateLayout();
+ }
GetRootView()->Layout();
+
UpdateDWMFrame();
- GetRootView()->Layout();
}
///////////////////////////////////////////////////////////////////////////////
@@ -220,13 +217,15 @@ LRESULT BrowserFrameWin::OnNCHitTest(const CPoint& pt) {
}
void BrowserFrameWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
+ WindowWin::OnWindowPosChanged(window_pos);
+ UpdateDWMFrame();
+
// Windows lies to us about the position of the minimize button before a
- // window is visible. We use the position of the minimize button to place the
- // distributor logo in official builds. When the window is shown, we need to
- // re-layout and schedule a paint for the non-client frame view so that the
- // distributor logo has the correct position when the window becomes visible.
- // This fixes bugs where the distributor logo appears to overlay the minimize
- // button. http://crbug.com/15520
+ // window is visible. We use this position to place the OTR avatar in RTL
+ // mode, so when the window is shown, we need to re-layout and schedule a
+ // paint for the non-client frame view so that the icon top has the correct
+ // position when the window becomes visible. This fixes bugs where the icon
+ // appears to overlay the minimize button.
// Note that we will call Layout every time SetWindowPos is called with
// SWP_SHOWWINDOW, however callers typically are careful about not specifying
// this flag unless necessary to avoid flicker.
@@ -234,11 +233,6 @@ void BrowserFrameWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
GetNonClientView()->Layout();
GetNonClientView()->SchedulePaint();
}
-
- UpdateDWMFrame();
-
- // Let the default window procedure handle - IMPORTANT!
- WindowWin::OnWindowPosChanged(window_pos);
}
ThemeProvider* BrowserFrameWin::GetThemeProvider() const {
@@ -312,13 +306,10 @@ void BrowserFrameWin::UpdateDWMFrame() {
// In maximized mode, we only have a titlebar strip of glass, no side/bottom
// borders.
if (!browser_view_->IsFullscreen()) {
- if (browser_view_->UseVerticalTabs()) {
- margins.cyTopHeight = GetTitleBarHeight();
- } else {
- margins.cyTopHeight =
- GetBoundsForTabStrip(browser_view_->tabstrip()).bottom() +
- kDWMFrameTopOffset;
- }
+ gfx::Rect tabstrip_bounds(
+ GetBoundsForTabStrip(browser_view_->tabstrip()));
+ margins.cyTopHeight = (browser_view_->UseVerticalTabs() ?
+ tabstrip_bounds.y() : tabstrip_bounds.bottom()) + kDWMFrameTopOffset;
}
} else {
// For popup and app windows we want to use the default margins.
diff --git a/chrome/browser/views/frame/browser_frame_win.h b/chrome/browser/views/frame/browser_frame_win.h
index 365497b..fdc5d62 100644
--- a/chrome/browser/views/frame/browser_frame_win.h
+++ b/chrome/browser/views/frame/browser_frame_win.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_WIN_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_WIN_H_
+#pragma once
#include "base/basictypes.h"
#include "chrome/browser/views/frame/browser_frame.h"
@@ -35,13 +36,11 @@ class BrowserFrameWin : public BrowserFrame, public views::WindowWin {
BrowserView* browser_view() const { return browser_view_; }
- // Returns the height of the title bar.
- int GetTitleBarHeight();
-
// BrowserFrame implementation.
virtual views::Window* GetWindow();
virtual int GetMinimizeButtonOffset() const;
virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const;
+ virtual int GetHorizontalTabStripVerticalOffset(bool restored) const;
virtual void UpdateThrobber(bool running);
virtual void ContinueDraggingDetachedTab();
virtual ThemeProvider* GetThemeProviderForFrame() const;
diff --git a/chrome/browser/views/frame/browser_non_client_frame_view.h b/chrome/browser/views/frame/browser_non_client_frame_view.h
index e891f0b..ba8ba40 100644
--- a/chrome/browser/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/views/frame/browser_non_client_frame_view.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
+#pragma once
#include "views/window/non_client_view.h"
@@ -19,6 +20,12 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
// Returns the bounds within which the TabStrip should be laid out.
virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const = 0;
+ // Returns the y coordinate within the window at which the horizontal TabStrip
+ // begins, or (in vertical tabs mode) would begin. If |restored| is true,
+ // this is calculated as if we were in restored mode regardless of the current
+ // mode. This is used to correctly align theme images.
+ virtual int GetHorizontalTabStripVerticalOffset(bool restored) const = 0;
+
// Updates the throbber.
virtual void UpdateThrobber(bool running) = 0;
};
diff --git a/chrome/browser/views/frame/browser_root_view.h b/chrome/browser/views/frame/browser_root_view.h
index cafbefd..4ae382a 100644
--- a/chrome/browser/views/frame/browser_root_view.h
+++ b/chrome/browser/views/frame/browser_root_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_ROOT_VIEW_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_ROOT_VIEW_H_
+#pragma once
#include "views/widget/root_view.h"
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index b3f4180..0b668bf 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -10,30 +10,41 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/command_line.h"
#include "base/i18n/rtl.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.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.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/debugger/devtools_window.h"
+#include "chrome/browser/dom_ui/bug_report_ui.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/ntp_background_util.h"
#include "chrome/browser/page_info_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.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/match_preview.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/themes/browser_theme_provider.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/download_shelf_view.h"
-#include "chrome/browser/views/extensions/extension_shelf.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"
@@ -49,6 +60,7 @@
#include "chrome/common/native_window_notification_source.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
#include "gfx/canvas_skia.h"
#include "grit/app_resources.h"
#include "grit/chromium_strings.h"
@@ -71,6 +83,7 @@
#elif defined(OS_LINUX)
#include "chrome/browser/views/accelerator_table_gtk.h"
#include "views/window/hit_test.h"
+#include "views/window/window_gtk.h"
#endif
using base::TimeDelta;
@@ -160,6 +173,10 @@ BookmarkExtensionBackground::BookmarkExtensionBackground(
void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas,
views::View* view) const {
ThemeProvider* tp = host_view_->GetThemeProvider();
+ int toolbar_overlap = host_view_->GetToolbarOverlap();
+ // The client edge is drawn below the toolbar bounds.
+ if (toolbar_overlap)
+ toolbar_overlap += views::NonClientFrameView::kClientEdgeThickness;
if (host_view_->IsDetached()) {
// Draw the background to match the new tab page.
int height = 0;
@@ -168,32 +185,35 @@ void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas,
height = contents->view()->GetContainerSize().height();
NtpBackgroundUtil::PaintBackgroundDetachedMode(
host_view_->GetThemeProvider(), canvas,
- gfx::Rect(0, 0, host_view_->width(), host_view_->height()),
- height);
-
- SkRect rect;
+ gfx::Rect(0, toolbar_overlap, host_view_->width(),
+ host_view_->height() - toolbar_overlap), height);
// As 'hidden' according to the animation is the full in-tab state,
// we invert the value - when current_state is at '0', we expect the
// bar to be docked.
double current_state = 1 - host_view_->GetAnimationValue();
+ double h_padding =
+ static_cast<double>(BookmarkBarView::kNewtabHorizontalPadding) *
+ current_state;
+ double v_padding =
+ static_cast<double>(BookmarkBarView::kNewtabVerticalPadding) *
+ current_state;
- double h_padding = static_cast<double>
- (BookmarkBarView::kNewtabHorizontalPadding) * current_state;
- double v_padding = static_cast<double>
- (BookmarkBarView::kNewtabVerticalPadding) * current_state;
+ SkRect rect;
double roundness = 0;
-
- DetachableToolbarView::CalculateContentArea(current_state,
- h_padding, v_padding,
- &rect, &roundness, host_view_);
- DetachableToolbarView::PaintContentAreaBackground(
- canvas, tp, rect, roundness);
+ DetachableToolbarView::CalculateContentArea(current_state, h_padding,
+ v_padding, &rect, &roundness, host_view_);
+ DetachableToolbarView::PaintContentAreaBackground(canvas, tp, rect,
+ roundness);
DetachableToolbarView::PaintContentAreaBorder(canvas, tp, rect, roundness);
- DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_);
+ if (!toolbar_overlap)
+ DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_);
} else {
- DetachableToolbarView::PaintBackgroundAttachedMode(canvas, host_view_);
- DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_);
+ DetachableToolbarView::PaintBackgroundAttachedMode(canvas, host_view_,
+ browser_view_->OffsetPointForToolbarBackgroundImage(
+ gfx::Point(host_view_->MirroredX(), host_view_->y())));
+ if (host_view_->height() >= toolbar_overlap)
+ DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_);
}
}
@@ -202,7 +222,9 @@ void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas,
class ResizeCorner : public views::View {
public:
- ResizeCorner() { }
+ ResizeCorner() {
+ EnableCanvasFlippingForRTLUI(true);
+ }
virtual void Paint(gfx::Canvas* canvas) {
views::Window* window = GetWindow();
@@ -212,16 +234,8 @@ class ResizeCorner : public views::View {
SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_TEXTAREA_RESIZER);
bitmap->buildMipMap(false);
- bool rtl_dir = base::i18n::IsRTL();
- if (rtl_dir) {
- canvas->TranslateInt(width(), 0);
- canvas->ScaleInt(-1, 1);
- canvas->Save();
- }
canvas->DrawBitmapInt(*bitmap, width() - bitmap->width(),
height() - bitmap->height());
- if (rtl_dir)
- canvas->Restore();
}
static gfx::Size GetSize() {
@@ -288,7 +302,8 @@ class DownloadInProgressConfirmDialogDelegate : public views::DialogDelegate,
} else {
warning_text =
l10n_util::GetStringF(IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_WARNING,
- product_name_, IntToWString(download_count));
+ product_name_,
+ UTF8ToWide(base::IntToString(download_count)));
explanation_text =
l10n_util::GetStringF(
IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_EXPLANATION, product_name_);
@@ -410,17 +425,25 @@ BrowserView::BrowserView(Browser* browser)
tabstrip_(NULL),
toolbar_(NULL),
infobar_container_(NULL),
+ sidebar_container_(NULL),
+ sidebar_split_(NULL),
contents_container_(NULL),
devtools_container_(NULL),
+ preview_container_(NULL),
+ contents_(NULL),
contents_split_(NULL),
initialized_(false),
- ignore_layout_(true),
+ ignore_layout_(true)
#if defined(OS_WIN)
- hung_window_detector_(&hung_plugin_action_),
- ticker_(0),
+ , hung_window_detector_(&hung_plugin_action_),
+ ticker_(0)
#endif
- extension_shelf_(NULL) {
+ {
browser_->tabstrip_model()->AddObserver(this);
+
+ registrar_.Add(this,
+ NotificationType::SIDEBAR_CHANGED,
+ Source<SidebarManager>(SidebarManager::GetInstance()));
}
BrowserView::~BrowserView() {
@@ -510,11 +533,20 @@ void BrowserView::WindowMoveOrResizeStarted() {
}
gfx::Rect BrowserView::GetToolbarBounds() const {
- return toolbar_->bounds();
+ gfx::Rect toolbar_bounds(toolbar_->bounds());
+ if (toolbar_bounds.IsEmpty())
+ return toolbar_bounds;
+ // When using vertical tabs, the toolbar appears to extend behind the tab
+ // column.
+ if (UseVerticalTabs())
+ toolbar_bounds.Inset(tabstrip_->x() - toolbar_bounds.x(), 0, 0, 0);
+ // The apparent toolbar edges are outside the "real" toolbar edges.
+ toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0);
+ return toolbar_bounds;
}
gfx::Rect BrowserView::GetClientAreaBounds() const {
- gfx::Rect container_bounds = contents_container_->bounds();
+ gfx::Rect container_bounds = contents_->bounds();
gfx::Point container_origin = container_bounds.origin();
ConvertPointToView(this, GetParent(), &container_origin);
container_bounds.set_origin(container_origin);
@@ -538,8 +570,20 @@ int BrowserView::GetTabStripHeight() const {
return IsTabStripVisible() ? tabstrip_->GetPreferredSize().height() : 0;
}
-gfx::Rect BrowserView::GetTabStripBounds() const {
- return frame_->GetBoundsForTabStrip(tabstrip_);
+gfx::Point BrowserView::OffsetPointForToolbarBackgroundImage(
+ const gfx::Point& point) const {
+ // The background image starts tiling horizontally at the window left edge and
+ // vertically at the top edge of the horizontal tab strip (or where it would
+ // be). We expect our parent's origin to be the window origin.
+ gfx::Point window_point(point.Add(gfx::Point(MirroredX(), y())));
+ window_point.Offset(0, -frame_->GetHorizontalTabStripVerticalOffset(false));
+ return window_point;
+}
+
+int BrowserView::GetSidebarWidth() const {
+ if (!sidebar_container_ || !sidebar_container_->IsVisible())
+ return 0;
+ return sidebar_split_->divider_offset();
}
bool BrowserView::IsTabStripVisible() const {
@@ -577,13 +621,13 @@ bool BrowserView::GetAccelerator(int cmd_id, menus::Accelerator* accelerator) {
// anywhere so we need to check for them explicitly here.
switch (cmd_id) {
case IDC_CUT:
- *accelerator = views::Accelerator(base::VKEY_X, false, true, false);
+ *accelerator = views::Accelerator(app::VKEY_X, false, true, false);
return true;
case IDC_COPY:
- *accelerator = views::Accelerator(base::VKEY_C, false, true, false);
+ *accelerator = views::Accelerator(app::VKEY_C, false, true, false);
return true;
case IDC_PASTE:
- *accelerator = views::Accelerator(base::VKEY_V, false, true, false);
+ *accelerator = views::Accelerator(app::VKEY_V, false, true, false);
return true;
}
// Else, we retrieve the accelerator information from the accelerator table.
@@ -688,6 +732,10 @@ void BrowserView::Activate() {
frame_->GetWindow()->Activate();
}
+void BrowserView::Deactivate() {
+ frame_->GetWindow()->Deactivate();
+}
+
bool BrowserView::IsActive() const {
return frame_->GetWindow()->IsActive();
}
@@ -725,14 +773,15 @@ void BrowserView::SelectedTabToolbarSizeChanged(bool is_animating) {
contents_container_->SetFastResize(false);
} else {
UpdateUIForContents(browser_->GetSelectedTabContents());
+ // When transitioning from animating to not animating we need to make sure
+ // the contents_container_ gets layed out. If we don't do this and the
+ // bounds haven't changed contents_container_ won't get a Layout out and
+ // we'll end up with a gray rect because the clip wasn't updated.
+ contents_container_->InvalidateLayout();
contents_split_->Layout();
}
}
-void BrowserView::SelectedTabExtensionShelfSizeChanged() {
- Layout();
-}
-
void BrowserView::UpdateTitleBar() {
frame_->GetWindow()->UpdateWindowTitle();
if (ShouldShowWindowIcon() && !loading_animation_timer_.IsRunning())
@@ -875,18 +924,24 @@ void BrowserView::RotatePaneFocus(bool forwards) {
// focusable children it will be automatically skipped.
std::vector<AccessibleToolbarView*> accessible_toolbars;
GetAccessibleToolbars(&accessible_toolbars);
- // Add NULL, which represents the tab contents getting focus
- accessible_toolbars.push_back(NULL);
-
- // Figure out which toolbar (if any) currently has the focus.
- AccessibleToolbarView* current_toolbar = NULL;
+ int toolbars_count = static_cast<int>(accessible_toolbars.size());
+
+ std::vector<views::View*> accessible_views(
+ accessible_toolbars.begin(), accessible_toolbars.end());
+ accessible_views.push_back(GetTabContentsContainerView());
+ if (sidebar_container_ && sidebar_container_->IsVisible())
+ accessible_views.push_back(GetSidebarContainerView());
+ if (devtools_container_->IsVisible())
+ accessible_views.push_back(devtools_container_->GetFocusView());
+ int count = static_cast<int>(accessible_views.size());
+
+ // Figure out which view (if any) currently has the focus.
views::View* focused_view = GetRootView()->GetFocusedView();
int index = -1;
- int count = static_cast<int>(accessible_toolbars.size());
if (focused_view) {
- for (int i = 0; i < count; i++) {
- if (accessible_toolbars[i]->IsParentOf(focused_view)) {
- current_toolbar = accessible_toolbars[i];
+ for (int i = 0; i < count; ++i) {
+ if (accessible_views[i] == focused_view ||
+ accessible_views[i]->IsParentOf(focused_view)) {
index = i;
break;
}
@@ -895,7 +950,7 @@ void BrowserView::RotatePaneFocus(bool forwards) {
// If the focus isn't currently in a toolbar, save the focus so we
// can restore it if the user presses Escape.
- if (focused_view && !current_toolbar)
+ if (focused_view && index >= toolbars_count)
SaveFocusedView();
// Try to focus the next pane; if SetToolbarFocusAndFocusDefault returns
@@ -905,16 +960,15 @@ void BrowserView::RotatePaneFocus(bool forwards) {
if (forwards)
index = (index + 1) % count;
else
- index = ((index - 1) + count + count) % count;
- AccessibleToolbarView* next_toolbar = accessible_toolbars[index];
+ index = ((index - 1) + count) % count;
- if (next_toolbar) {
- if (next_toolbar->SetToolbarFocusAndFocusDefault(
+ if (index < toolbars_count) {
+ if (accessible_toolbars[index]->SetToolbarFocusAndFocusDefault(
last_focused_view_storage_id_)) {
break;
}
} else {
- GetTabContentsContainerView()->RequestFocus();
+ accessible_views[index]->RequestFocus();
break;
}
}
@@ -990,10 +1044,6 @@ void BrowserView::ToggleBookmarkBar() {
bookmark_utils::ToggleWhenVisible(browser_->profile());
}
-void BrowserView::ToggleExtensionShelf() {
- ExtensionShelf::ToggleWhenExtensionShelfVisible(browser_->profile());
-}
-
views::Window* BrowserView::ShowAboutChromeDialog() {
return browser::ShowAboutChromeView(GetWindow()->GetNativeWindow(),
browser_->profile());
@@ -1046,11 +1096,7 @@ DownloadShelf* BrowserView::GetDownloadShelf() {
}
void BrowserView::ShowReportBugDialog() {
- // Retrieve the URL for the current tab (if any) and tell the BugReportView
- TabContents* current_tab = browser_->GetSelectedTabContents();
- if (!current_tab)
- return;
- browser::ShowBugReportView(GetWindow(), browser_->profile(), current_tab);
+ browser::ShowHtmlBugReportView(GetWindow(), browser_.get());
}
void BrowserView::ShowClearBrowsingDataDialog() {
@@ -1161,7 +1207,11 @@ void BrowserView::ShowPageInfo(Profile* profile,
parent = GetNormalBrowserWindowForBrowser(browser(), profile);
#endif // defined(OS_CHROMEOS)
- browser::ShowPageInfo(parent, profile, url, ssl, show_history);
+ const CommandLine* command_line(CommandLine::ForCurrentProcess());
+ if (command_line->HasSwitch(switches::kEnableNewPageInfoBubble))
+ browser::ShowPageInfoBubble(parent, profile, url, ssl, show_history);
+ else
+ browser::ShowPageInfo(parent, profile, url, ssl, show_history);
}
void BrowserView::ShowAppMenu() {
@@ -1176,7 +1226,7 @@ bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
#if defined(OS_WIN)
// As Alt+F4 is the close-app keyboard shortcut, it needs processing
// immediately.
- if (event.windowsKeyCode == base::VKEY_F4 &&
+ if (event.windowsKeyCode == app::VKEY_F4 &&
event.modifiers == NativeWebKeyboardEvent::AltKey) {
DefWindowProc(event.os_event.hwnd, event.os_event.message,
event.os_event.wParam, event.os_event.lParam);
@@ -1187,14 +1237,28 @@ bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
views::FocusManager* focus_manager = GetFocusManager();
DCHECK(focus_manager);
+#if defined(OS_LINUX)
+ // Views and WebKit use different tables for GdkEventKey -> views::KeyEvent
+ // conversion. We need to use View's conversion table here to keep consistent
+ // behavior with views::FocusManager::OnKeyEvent() method.
+ // TODO(suzhe): We need to check if Windows code also has this issue, and
+ // it'll be best if we can unify these conversion tables.
+ // See http://crbug.com/54315
+ views::KeyEvent views_event(event.os_event);
+ views::Accelerator accelerator(views_event.GetKeyCode(),
+ views_event.IsShiftDown(),
+ views_event.IsControlDown(),
+ views_event.IsAltDown());
+#else
views::Accelerator accelerator(
- static_cast<base::KeyboardCode>(event.windowsKeyCode),
+ static_cast<app::KeyboardCode>(event.windowsKeyCode),
(event.modifiers & NativeWebKeyboardEvent::ShiftKey) ==
NativeWebKeyboardEvent::ShiftKey,
(event.modifiers & NativeWebKeyboardEvent::ControlKey) ==
NativeWebKeyboardEvent::ControlKey,
(event.modifiers & NativeWebKeyboardEvent::AltKey) ==
NativeWebKeyboardEvent::AltKey);
+#endif
// We first find out the browser command associated to the |event|.
// Then if the command is a reserved one, and should be processed
@@ -1235,8 +1299,14 @@ bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
}
void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
+#if defined(OS_LINUX)
+ views::Window* window = GetWidget()->GetWindow();
+ if (window && event.os_event && !event.skip_in_browser)
+ static_cast<views::WindowGtk*>(window)->HandleKeyboardEvent(event.os_event);
+#else
unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
GetFocusManager());
+#endif
}
// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
@@ -1248,34 +1318,34 @@ void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
// manager to do that.
#if !defined(OS_MACOSX)
void BrowserView::Cut() {
- ui_controls::SendKeyPress(GetNativeHandle(), base::VKEY_X,
+ ui_controls::SendKeyPress(GetNativeHandle(), app::VKEY_X,
true, false, false, false);
}
void BrowserView::Copy() {
- ui_controls::SendKeyPress(GetNativeHandle(), base::VKEY_C,
+ ui_controls::SendKeyPress(GetNativeHandle(), app::VKEY_C,
true, false, false, false);
}
void BrowserView::Paste() {
- ui_controls::SendKeyPress(GetNativeHandle(), base::VKEY_V,
+ ui_controls::SendKeyPress(GetNativeHandle(), app::VKEY_V,
true, false, false, false);
}
#else
// Mac versions. Not tested by antyhing yet;
// don't assume written == works.
void BrowserView::Cut() {
- ui_controls::SendKeyPress(GetNativeHandle(), base::VKEY_X,
+ ui_controls::SendKeyPress(GetNativeHandle(), app::VKEY_X,
false, false, false, true);
}
void BrowserView::Copy() {
- ui_controls::SendKeyPress(GetNativeHandle(), base::VKEY_C,
+ ui_controls::SendKeyPress(GetNativeHandle(), app::VKEY_C,
false, false, false, true);
}
void BrowserView::Paste() {
- ui_controls::SendKeyPress(GetNativeHandle(), base::VKEY_V,
+ ui_controls::SendKeyPress(GetNativeHandle(), app::VKEY_V,
false, false, false, true);
}
#endif
@@ -1285,6 +1355,30 @@ void BrowserView::ToggleTabStripMode() {
frame_->TabStripDisplayModeChanged();
}
+void BrowserView::ShowMatchPreview() {
+ if (!preview_container_)
+ preview_container_ = new TabContentsContainer();
+ TabContents* preview_tab_contents =
+ browser_->match_preview()->preview_contents();
+ contents_->SetPreview(preview_container_, preview_tab_contents);
+ preview_container_->ChangeTabContents(preview_tab_contents);
+}
+
+void BrowserView::HideMatchPreview() {
+ if (!preview_container_)
+ return;
+
+ // The contents must be changed before SetPreview is invoked.
+ preview_container_->ChangeTabContents(NULL);
+ contents_->SetPreview(NULL, NULL);
+ delete preview_container_;
+ preview_container_ = NULL;
+}
+
+gfx::Rect BrowserView::GetMatchPreviewBounds() {
+ return contents_->GetPreviewBounds();
+}
+
///////////////////////////////////////////////////////////////////////////////
// BrowserView, BrowserWindowTesting implementation:
@@ -1300,6 +1394,12 @@ views::View* BrowserView::GetTabContentsContainerView() const {
return contents_container_->GetFocusView();
}
+views::View* BrowserView::GetSidebarContainerView() const {
+ if (!sidebar_container_)
+ return NULL;
+ return sidebar_container_->GetFocusView();
+}
+
ToolbarView* BrowserView::GetToolbarView() const {
return toolbar_;
}
@@ -1310,12 +1410,24 @@ ToolbarView* BrowserView::GetToolbarView() const {
void BrowserView::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type == NotificationType::PREF_CHANGED &&
- *Details<std::wstring>(details).ptr() == prefs::kShowBookmarkBar) {
- if (MaybeShowBookmarkBar(browser_->GetSelectedTabContents()))
- Layout();
- } else {
- NOTREACHED() << "Got a notification we didn't register for!";
+ switch (type.value) {
+ case NotificationType::PREF_CHANGED:
+ if (*Details<std::string>(details).ptr() == prefs::kShowBookmarkBar &&
+ MaybeShowBookmarkBar(browser_->GetSelectedTabContents())) {
+ Layout();
+ }
+ break;
+
+ case NotificationType::SIDEBAR_CHANGED:
+ if (Details<SidebarContainer>(details)->tab_contents() ==
+ browser_->GetSelectedTabContents()) {
+ UpdateSidebar();
+ }
+ break;
+
+ default:
+ NOTREACHED() << "Got a notification we didn't register for!";
+ break;
}
}
@@ -1332,6 +1444,7 @@ void BrowserView::TabDetachedAt(TabContents* contents, int index) {
// on the selected TabContents when it is removed.
contents_container_->ChangeTabContents(NULL);
infobar_container_->ChangeTabContents(NULL);
+ UpdateSidebarForContents(NULL);
UpdateDevToolsForContents(NULL);
}
}
@@ -1350,34 +1463,29 @@ void BrowserView::TabSelectedAt(TabContents* old_contents,
bool user_gesture) {
DCHECK(old_contents != new_contents);
- // Update various elements that are interested in knowing the current
- // TabContents.
-
- // When we toggle the NTP floating bookmarks bar and/or the info bar,
- // we don't want any TabContents to be attached, so that we
- // avoid an unnecessary resize and re-layout of a TabContents.
- contents_container_->ChangeTabContents(NULL);
- infobar_container_->ChangeTabContents(new_contents);
- UpdateUIForContents(new_contents);
- contents_container_->ChangeTabContents(new_contents);
+ ProcessTabSelected(new_contents, true);
+}
- UpdateDevToolsForContents(new_contents);
- // TODO(beng): This should be called automatically by ChangeTabContents, but I
- // am striving for parity now rather than cleanliness. This is
- // required to make features like Duplicate Tab, Undo Close Tab,
- // etc not result in sad tab.
- new_contents->DidBecomeSelected();
- if (BrowserList::GetLastActive() == browser_ &&
- !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) {
- // We only restore focus if our window is visible, to avoid invoking blur
- // handlers when we are eventually shown.
- new_contents->view()->RestoreFocus();
+void BrowserView::TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ TabStripModelObserver::TabReplaceType type) {
+ if (type != TabStripModelObserver::REPLACE_MATCH_PREVIEW ||
+ index != browser_->tabstrip_model()->selected_index()) {
+ return;
}
- // Update all the UI bits.
- UpdateTitleBar();
- UpdateToolbar(new_contents, true);
- UpdateUIForContents(new_contents);
+ // Swap the 'active' and 'preview' and delete what was the active.
+ contents_->MakePreviewContentsActiveContents();
+ TabContentsContainer* old_container = contents_container_;
+ contents_container_ = preview_container_;
+ old_container->ChangeTabContents(NULL);
+ delete old_container;
+ preview_container_ = NULL;
+
+ // Update the UI for what was the preview contents and is now active. Pass in
+ // false to ProcessTabSelected as new_contents is already parented correctly.
+ ProcessTabSelected(new_contents, false);
}
void BrowserView::TabStripEmpty() {
@@ -1445,6 +1553,14 @@ std::wstring BrowserView::GetWindowTitle() const {
return UTF16ToWideHack(browser_->GetWindowTitleForCurrentTab());
}
+std::wstring BrowserView::GetAccessibleWindowTitle() const {
+ if (IsOffTheRecord()) {
+ return l10n_util::GetStringF(
+ IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT, GetWindowTitle());
+ }
+ return GetWindowTitle();
+}
+
views::View* BrowserView::GetInitiallyFocusedView() {
// We set the frame not focus on creation so this should never be called.
NOTREACHED();
@@ -1493,7 +1609,7 @@ bool BrowserView::ExecuteWindowsCommand(int command_id) {
}
std::wstring BrowserView::GetWindowName() const {
- return browser_->GetWindowPlacementKey();
+ return UTF8ToWide(browser_->GetWindowPlacementKey());
}
void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds,
@@ -1651,11 +1767,12 @@ void BrowserView::Layout() {
// Send the margins of the "user-perceived content area" of this
// browser window so AeroPeekManager can render a background-tab image in
// the area.
+ // TODO(pkasting) correct content inset??
if (aeropeek_manager_.get()) {
gfx::Insets insets(GetFindBarBoundingBox().y() + 1,
- GetTabStripBounds().x(),
- GetTabStripBounds().x(),
- GetTabStripBounds().x());
+ 0,
+ 0,
+ 0);
aeropeek_manager_->SetContentInsets(insets);
}
#endif
@@ -1675,11 +1792,8 @@ void BrowserView::ChildPreferredSizeChanged(View* child) {
Layout();
}
-bool BrowserView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_CLIENT;
- return true;
+AccessibilityTypes::Role BrowserView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_CLIENT;
}
void BrowserView::InfoBarSizeChanged(bool is_animating) {
@@ -1698,7 +1812,7 @@ void BrowserView::InitTabStrip(TabStripModel* model) {
}
BrowserTabStripController* tabstrip_controller =
- new BrowserTabStripController(model);
+ new BrowserTabStripController(browser_.get(), model);
if (UseVerticalTabs())
tabstrip_ = new SideTabStrip(tabstrip_controller);
@@ -1749,34 +1863,49 @@ void BrowserView::Init() {
AddChildView(infobar_container_);
contents_container_ = new TabContentsContainer;
+ contents_ = new ContentsContainer(this, contents_container_);
+
+ SkColor bg_color = GetWidget()->GetThemeProvider()->
+ GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
+
+ bool sidebar_allowed = SidebarManager::IsSidebarAllowed();
+ if (sidebar_allowed) {
+ sidebar_container_ = new TabContentsContainer;
+ sidebar_container_->SetID(VIEW_ID_SIDE_BAR_CONTAINER);
+ sidebar_container_->SetVisible(false);
+
+ sidebar_split_ = new views::SingleSplitView(
+ contents_,
+ sidebar_container_,
+ views::SingleSplitView::HORIZONTAL_SPLIT);
+ sidebar_split_->SetID(VIEW_ID_SIDE_BAR_SPLIT);
+ sidebar_split_->
+ SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_SIDE_BAR));
+ sidebar_split_->set_background(
+ views::Background::CreateSolidBackground(bg_color));
+ }
+
devtools_container_ = new TabContentsContainer;
devtools_container_->SetID(VIEW_ID_DEV_TOOLS_DOCKED);
devtools_container_->SetVisible(false);
+
+ views::View* contents_view = contents_;
+ if (sidebar_allowed)
+ contents_view = sidebar_split_;
+
contents_split_ = new views::SingleSplitView(
- contents_container_,
+ contents_view,
devtools_container_,
views::SingleSplitView::VERTICAL_SPLIT);
contents_split_->SetID(VIEW_ID_CONTENTS_SPLIT);
contents_split_->
SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_WEB_CONTENTS));
- SkColor bg_color = GetWidget()->GetThemeProvider()->
- GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
contents_split_->set_background(
views::Background::CreateSolidBackground(bg_color));
AddChildView(contents_split_);
set_contents_view(contents_split_);
- status_bubble_.reset(new StatusBubbleViews(GetWidget()));
-
- if (browser_->SupportsWindowFeature(Browser::FEATURE_EXTENSIONSHELF)) {
- extension_shelf_ = new ExtensionShelf(browser_.get());
- extension_shelf_->set_background(
- new BookmarkExtensionBackground(this, extension_shelf_,
- browser_.get()));
- extension_shelf_->
- SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_EXTENSIONS));
- AddChildView(extension_shelf_);
- }
+ status_bubble_.reset(new StatusBubbleViews(contents_));
#if defined(OS_WIN)
InitSystemMenu();
@@ -1789,7 +1918,6 @@ void BrowserView::Init() {
}
if (AeroPeekManager::Enabled()) {
- gfx::Rect bounds(frame_->GetBoundsForTabStrip(tabstrip()));
aeropeek_manager_.reset(new AeroPeekManager(
frame_->GetWindow()->GetNativeWindow()));
browser_->tabstrip_model()->AddObserver(aeropeek_manager_.get());
@@ -1829,8 +1957,8 @@ void BrowserView::LayoutStatusBubble(int top) {
if (UseVerticalTabs() && IsTabStripVisible())
x += tabstrip_->bounds().right();
int height = status_bubble_->GetPreferredSize().height();
- gfx::Point origin(x, top - height + overlap);
- ConvertPointToView(this, GetParent(), &origin);
+ gfx::Point origin(
+ -overlap, contents_container_->bounds().height() - height + overlap);
status_bubble_->SetBounds(origin.x(), origin.y(), width() / 3, height);
}
@@ -1863,6 +1991,67 @@ bool BrowserView::MaybeShowInfoBar(TabContents* contents) {
return true;
}
+void BrowserView::UpdateSidebar() {
+ UpdateSidebarForContents(GetSelectedTabContents());
+ Layout();
+}
+
+void BrowserView::UpdateSidebarForContents(TabContents* tab_contents) {
+ if (!sidebar_container_)
+ return; // Happens when sidebar is not allowed.
+ if (!SidebarManager::GetInstance())
+ return; // Happens only in tests.
+
+ TabContents* sidebar_contents = NULL;
+ if (tab_contents) {
+ SidebarContainer* client_host = SidebarManager::GetInstance()->
+ GetActiveSidebarContainerFor(tab_contents);
+ if (client_host)
+ sidebar_contents = client_host->sidebar_contents();
+ }
+
+ bool visible = NULL != sidebar_contents &&
+ browser_->SupportsWindowFeature(Browser::FEATURE_SIDEBAR);
+
+ bool should_show = visible && !sidebar_container_->IsVisible();
+ bool should_hide = !visible && sidebar_container_->IsVisible();
+
+ // Update sidebar content.
+ TabContents* old_contents = sidebar_container_->tab_contents();
+ sidebar_container_->ChangeTabContents(sidebar_contents);
+ SidebarManager::GetInstance()->
+ NotifyStateChanges(old_contents, sidebar_contents);
+
+ // Update sidebar UI width.
+ if (should_show) {
+ // Restore split offset.
+ int sidebar_width = g_browser_process->local_state()->GetInteger(
+ prefs::kExtensionSidebarWidth);
+ if (sidebar_width < 0) {
+ // Initial load, set to default value.
+ sidebar_width = sidebar_split_->width() / 7;
+ }
+ // Make sure user can see both panes.
+ int min_sidebar_width = sidebar_split_->GetMinimumSize().width();
+ sidebar_width = std::min(sidebar_split_->width() - min_sidebar_width,
+ std::max(min_sidebar_width, sidebar_width));
+
+ sidebar_split_->set_divider_offset(
+ sidebar_split_->width() - sidebar_width);
+
+ sidebar_container_->SetVisible(true);
+ sidebar_split_->Layout();
+ } else if (should_hide) {
+ // Store split offset when hiding sidebar only.
+ g_browser_process->local_state()->SetInteger(
+ prefs::kExtensionSidebarWidth,
+ sidebar_split_->width() - sidebar_split_->divider_offset());
+
+ sidebar_container_->SetVisible(false);
+ sidebar_split_->Layout();
+ }
+}
+
void BrowserView::UpdateDevToolsForContents(TabContents* tab_contents) {
TabContents* devtools_contents =
DevToolsWindow::GetDevToolsContents(tab_contents);
@@ -2002,11 +2191,6 @@ void BrowserView::ProcessFullscreen(bool fullscreen) {
if (bookmark_bar_view_.get())
bookmark_bar_view_->OnFullscreenToggled(fullscreen);
- // Notify extension shelf, so it can set itself to the appropriate drawing
- // state.
- if (extension_shelf_)
- extension_shelf_->OnFullscreenToggled(fullscreen);
-
// Toggle fullscreen mode.
#if defined(OS_WIN)
frame_->GetWindow()->SetFullscreen(fullscreen);
@@ -2070,7 +2254,7 @@ void BrowserView::LoadAccelerators() {
bool ctrl_down = (accelerators[i].fVirt & FCONTROL) == FCONTROL;
bool shift_down = (accelerators[i].fVirt & FSHIFT) == FSHIFT;
views::Accelerator accelerator(
- static_cast<base::KeyboardCode>(accelerators[i].key),
+ static_cast<app::KeyboardCode>(accelerators[i].key),
shift_down, ctrl_down, alt_down);
accelerator_table_[accelerator] = accelerators[i].cmd;
@@ -2224,6 +2408,41 @@ void BrowserView::InitHangMonitor() {
#endif
}
+void BrowserView::ProcessTabSelected(TabContents* new_contents,
+ bool change_tab_contents) {
+ // Update various elements that are interested in knowing the current
+ // TabContents.
+
+ // When we toggle the NTP floating bookmarks bar and/or the info bar,
+ // we don't want any TabContents to be attached, so that we
+ // avoid an unnecessary resize and re-layout of a TabContents.
+ if (change_tab_contents)
+ contents_container_->ChangeTabContents(NULL);
+ infobar_container_->ChangeTabContents(new_contents);
+ UpdateUIForContents(new_contents);
+ if (change_tab_contents)
+ contents_container_->ChangeTabContents(new_contents);
+ UpdateSidebarForContents(new_contents);
+
+ UpdateDevToolsForContents(new_contents);
+ // TODO(beng): This should be called automatically by ChangeTabContents, but I
+ // am striving for parity now rather than cleanliness. This is
+ // required to make features like Duplicate Tab, Undo Close Tab,
+ // etc not result in sad tab.
+ new_contents->DidBecomeSelected();
+ if (BrowserList::GetLastActive() == browser_ &&
+ !browser_->tabstrip_model()->closing_all() && GetWindow()->IsVisible()) {
+ // We only restore focus if our window is visible, to avoid invoking blur
+ // handlers when we are eventually shown.
+ new_contents->view()->RestoreFocus();
+ }
+
+ // Update all the UI bits.
+ UpdateTitleBar();
+ UpdateToolbar(new_contents, true);
+ UpdateUIForContents(new_contents);
+}
+
#if !defined(OS_CHROMEOS)
// static
BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h
index 8c00550..142c520 100644
--- a/chrome/browser/views/frame/browser_view.h
+++ b/chrome/browser/views/frame/browser_view.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW_H_
+#pragma once
#include <map>
-#include <set>
#include <string>
#include <vector>
@@ -16,13 +16,14 @@
#include "build/build_config.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
#include "chrome/browser/views/frame/browser_bubble_host.h"
#include "chrome/browser/views/frame/browser_frame.h"
#include "chrome/browser/views/infobars/infobar_container.h"
#include "chrome/browser/views/tabs/tab_strip.h"
#include "chrome/browser/views/tabs/base_tab_strip.h"
#include "chrome/browser/views/unhandled_keyboard_event_handler.h"
+#include "chrome/common/notification_registrar.h"
#include "gfx/native_widget_types.h"
#include "views/window/client_view.h"
#include "views/window/window_delegate.h"
@@ -42,9 +43,9 @@ class BookmarkBarView;
class Browser;
class BrowserBubble;
class BrowserViewLayout;
+class ContentsContainer;
class DownloadShelfView;
class EncodingMenuModel;
-class ExtensionShelf;
class FullscreenExitBubble;
class HtmlDialogUIDelegate;
class InfoBarContainer;
@@ -52,6 +53,7 @@ class LocationBarView;
class SideTabStrip;
class StatusBubbleViews;
class TabContentsContainer;
+class TabStripModel;
class ToolbarView;
class ZoomMenuModel;
@@ -116,7 +118,10 @@ class BrowserView : public BrowserBubbleHost,
// initiated.
void WindowMoveOrResizeStarted();
- // Returns the bounds of the toolbar, in BrowserView coordinates.
+ // Returns the apparent bounds of the toolbar, in BrowserView coordinates.
+ // These differ from |toolbar_.bounds()| in that they match where the toolbar
+ // background image is drawn -- slightly outside the "true" bounds
+ // horizontally, and, when using vertical tabs, behind the tab column.
gfx::Rect GetToolbarBounds() const;
// Returns the bounds of the content area, in the coordinates of the
@@ -140,9 +145,14 @@ class BrowserView : public BrowserBubbleHost,
// avatar icon.
int GetTabStripHeight() const;
- // Returns the bounds of the TabStrip. Used by themed views to determine the
- // offset of IDR_THEME_TOOLBAR.
- gfx::Rect GetTabStripBounds() const;
+ // Takes some view's origin (relative to this BrowserView) and offsets it such
+ // that it can be used as the source origin for seamlessly tiling the toolbar
+ // background image over that view.
+ gfx::Point OffsetPointForToolbarBackgroundImage(
+ const gfx::Point& point) const;
+
+ // Returns the width of the currently displayed sidebar or 0.
+ int GetSidebarWidth() const;
// Accessor for the TabStrip.
BaseTabStrip* tabstrip() const { return tabstrip_; }
@@ -150,9 +160,6 @@ class BrowserView : public BrowserBubbleHost,
// Accessor for the Toolbar.
ToolbarView* toolbar() const { return toolbar_; }
- // Accessor for the ExtensionShelf.
- ExtensionShelf* extension_shelf() const { return extension_shelf_; }
-
// Returns true if various window components are visible.
bool IsTabStripVisible() const;
@@ -242,13 +249,13 @@ class BrowserView : public BrowserBubbleHost,
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 SelectedTabExtensionShelfSizeChanged();
virtual void UpdateTitleBar();
virtual void ShelfVisibilityChanged();
virtual void UpdateDevTools();
@@ -276,7 +283,6 @@ class BrowserView : public BrowserBubbleHost,
virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
Profile* profile);
virtual void ToggleBookmarkBar();
- virtual void ToggleExtensionShelf();
virtual views::Window* ShowAboutChromeDialog();
virtual void ShowUpdateChromeDialog();
virtual void ShowTaskManager();
@@ -315,11 +321,15 @@ class BrowserView : public BrowserBubbleHost,
virtual void Copy();
virtual void Paste();
virtual void ToggleTabStripMode();
+ virtual void ShowMatchPreview();
+ virtual void HideMatchPreview();
+ virtual gfx::Rect GetMatchPreviewBounds();
// Overridden from BrowserWindowTesting:
virtual BookmarkBarView* GetBookmarkBarView() const;
virtual LocationBarView* GetLocationBarView() const;
virtual views::View* GetTabContentsContainerView() const;
+ virtual views::View* GetSidebarContainerView() const;
virtual ToolbarView* GetToolbarView() const;
// Overridden from NotificationObserver:
@@ -334,6 +344,10 @@ class BrowserView : public BrowserBubbleHost,
TabContents* new_contents,
int index,
bool user_gesture);
+ virtual void TabReplacedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ TabStripModelObserver::TabReplaceType type);
virtual void TabStripEmpty();
// Overridden from menus::SimpleMenuModel::Delegate:
@@ -350,6 +364,7 @@ class BrowserView : public BrowserBubbleHost,
virtual bool CanMaximize() const;
virtual bool IsModal() const;
virtual std::wstring GetWindowTitle() const;
+ virtual std::wstring GetAccessibleWindowTitle() const;
virtual views::View* GetInitiallyFocusedView();
virtual bool ShouldShowWindowTitle() const;
virtual SkBitmap GetWindowAppIcon();
@@ -393,7 +408,7 @@ class BrowserView : public BrowserBubbleHost,
views::View* parent,
views::View* child);
virtual void ChildPreferredSizeChanged(View* child);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
// Factory Methods.
// Returns a new LayoutManager for this browser view. A subclass may
@@ -434,6 +449,12 @@ class BrowserView : public BrowserBubbleHost,
// |contents| can be NULL.
bool MaybeShowInfoBar(TabContents* contents);
+ // Updates sidebar UI according to the current tab and sidebar state.
+ void UpdateSidebar();
+ // Displays active sidebar linked to the |tab_contents| or hides sidebar UI,
+ // if there's no such sidebar.
+ void UpdateSidebarForContents(TabContents* tab_contents);
+
// Updated devtools window for given contents.
void UpdateDevToolsForContents(TabContents* tab_contents);
@@ -476,8 +497,11 @@ class BrowserView : public BrowserBubbleHost,
// Initialize the hung plugin detector.
void InitHangMonitor();
- // Initialize class statics.
- static void InitClass();
+ // Invoked from TabSelectedAt or when the match preview is made active. Is
+ // |change_tab_contents| is true, |new_contents| is added to the view
+ // hierarchy, if |change_tab_contents| is false, it's assumed |new_contents|
+ // has already been added to the view hierarchy.
+ void ProcessTabSelected(TabContents* new_contents, bool change_tab_contents);
// Last focused view that issued a tab traversal.
int last_focused_view_storage_id_;
@@ -488,6 +512,47 @@ class BrowserView : public BrowserBubbleHost,
// The Browser object we are associated with.
scoped_ptr<Browser> browser_;
+ // BrowserView layout (LTR one is pictured here).
+ //
+ // --------------------------------------------------------------------------
+ // | | Tabs (1) |
+ // | |--------------------------------------------------------------|
+ // | | Navigation buttons, menus and the address bar (toolbar_) |
+ // | |--------------------------------------------------------------|
+ // | | All infobars (infobar_container_) * |
+ // | |--------------------------------------------------------------|
+ // | | Bookmarks (bookmark_bar_view_) * |
+ // | |--------------------------------------------------------------|
+ // | |Page content (contents_) || |
+ // | |--------------------------------------|| Sidebar content |
+ // | || contents_container_ and/or ||| (sidebar_container_) |
+ // | || preview_container_ ||| |
+ // | || |(3) |
+ // | Tabs (2)|| ||| |
+ // | || ||| |
+ // | || ||| |
+ // | || ||| |
+ // | |--------------------------------------|| |
+ // | |==(4)=========================================================|
+ // | | |
+ // | | |
+ // | | Debugger (devtools_container_) |
+ // | | |
+ // | | |
+ // | |--------------------------------------------------------------|
+ // | | Active downloads (download_shelf_) |
+ // --------------------------------------------------------------------------
+ //
+ // (1) - tabstrip_, default position
+ // (2) - tabstrip_, position when side tabs are enabled
+ // (3) - sidebar_split_
+ // (4) - contents_split_
+ //
+ // * - The bookmark bar and info bar are swapped when on the new tab page.
+ // Additionally contents_ is positioned on top of the bookmark bar when
+ // the bookmark bar is detached. This is done to allow the
+ // preview_container_ to appear over the bookmark bar.
+
// Tool/Info bars that we are currently showing. Used for layout.
// active_bookmark_bar_ is either NULL, if the bookmark bar isn't showing,
// or is bookmark_bar_view_ if the bookmark bar is showing.
@@ -508,12 +573,24 @@ class BrowserView : public BrowserBubbleHost,
// The InfoBarContainer that contains InfoBars for the current tab.
InfoBarContainer* infobar_container_;
+ // The view that contains sidebar for the current tab.
+ TabContentsContainer* sidebar_container_;
+
+ // Split view containing the contents container and sidebar container.
+ views::SingleSplitView* sidebar_split_;
+
// The view that contains the selected TabContents.
TabContentsContainer* contents_container_;
// The view that contains devtools window for the selected TabContents.
TabContentsContainer* devtools_container_;
+ // The view that contains the match preview TabContents.
+ TabContentsContainer* preview_container_;
+
+ // The view managing both the contents_container_ and preview_container_.
+ ContentsContainer* contents_;
+
// Split view containing the contents container and devtools container.
views::SingleSplitView* contents_split_;
@@ -568,13 +645,12 @@ class BrowserView : public BrowserBubbleHost,
// The timer used to update frames for the Loading Animation.
base::RepeatingTimer<BrowserView> loading_animation_timer_;
- // A bottom bar for showing extensions.
- ExtensionShelf* extension_shelf_;
-
UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
scoped_ptr<AccessibleViewHelper> accessible_view_helper_;
+ NotificationRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserView);
};
diff --git a/chrome/browser/views/frame/browser_view_layout.cc b/chrome/browser/views/frame/browser_view_layout.cc
index e7d807b..7167dad 100644
--- a/chrome/browser/views/frame/browser_view_layout.cc
+++ b/chrome/browser/views/frame/browser_view_layout.cc
@@ -6,12 +6,13 @@
#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/extensions/extension_shelf.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"
@@ -45,7 +46,6 @@ BrowserViewLayout::BrowserViewLayout()
contents_container_(NULL),
infobar_container_(NULL),
download_shelf_(NULL),
- extension_shelf_(NULL),
active_bookmark_bar_(NULL),
browser_view_(NULL),
find_bar_y_(0) {
@@ -67,10 +67,8 @@ gfx::Size BrowserViewLayout::GetMinimumSize() {
if (active_bookmark_bar_ &&
browser()->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR)) {
bookmark_bar_size = active_bookmark_bar_->GetMinimumSize();
- bookmark_bar_size.Enlarge(
- 0,
- -kSeparationLineHeight -
- active_bookmark_bar_->GetToolbarOverlap(true));
+ bookmark_bar_size.Enlarge(0, -(kSeparationLineHeight +
+ active_bookmark_bar_->GetToolbarOverlap(true)));
}
gfx::Size contents_size(contents_split_->GetMinimumSize());
@@ -199,7 +197,6 @@ void BrowserViewLayout::Installed(views::View* host) {
contents_container_ = NULL;
infobar_container_ = NULL;
download_shelf_ = NULL;
- extension_shelf_ = NULL;
active_bookmark_bar_ = NULL;
tabstrip_ = NULL;
browser_view_ = static_cast<BrowserView*>(host);
@@ -209,19 +206,20 @@ void BrowserViewLayout::Uninstalled(views::View* host) {}
void BrowserViewLayout::ViewAdded(views::View* host, views::View* view) {
switch (view->GetID()) {
- case VIEW_ID_CONTENTS_SPLIT:
+ case VIEW_ID_CONTENTS_SPLIT: {
contents_split_ = view;
- contents_container_ = contents_split_->GetChildViewAt(0);
+ // We're installed as the LayoutManager before BrowserView creates the
+ // contents, so we have to set contents_container_ here rather than
+ // Installed.
+ contents_container_ = browser_view_->contents_;
break;
+ }
case VIEW_ID_INFO_BAR_CONTAINER:
infobar_container_ = view;
break;
case VIEW_ID_DOWNLOAD_SHELF:
download_shelf_ = static_cast<DownloadShelfView*>(view);
break;
- case VIEW_ID_DEV_EXTENSION_SHELF:
- extension_shelf_ = static_cast<ExtensionShelf*>(view);
- break;
case VIEW_ID_BOOKMARK_BAR:
active_bookmark_bar_ = static_cast<BookmarkBarView*>(view);
break;
@@ -245,9 +243,18 @@ void BrowserViewLayout::ViewRemoved(views::View* host, views::View* view) {
void BrowserViewLayout::Layout(views::View* host) {
vertical_layout_rect_ = browser_view_->GetLocalBounds(true);
int top = LayoutTabStrip();
+ if (browser_view_->IsTabStripVisible() && !browser_view_->UseVerticalTabs()) {
+ tabstrip_->SetBackgroundOffset(gfx::Point(
+ tabstrip_->MirroredX() + browser_view_->MirroredX(),
+ browser_view_->frame()->GetHorizontalTabStripVerticalOffset(false)));
+ }
top = LayoutToolbar(top);
top = LayoutBookmarkAndInfoBars(top);
- int bottom = LayoutExtensionAndDownloadShelves();
+ int bottom = LayoutDownloadShelf(browser_view_->height());
+ int active_top_margin = GetTopMarginForActiveContent();
+ top -= active_top_margin;
+ bottom += active_top_margin;
+ contents_container_->SetActiveTopMargin(active_top_margin);
LayoutTabContents(top, bottom);
// This must be done _after_ we lay out the TabContents since this
// code calls back into us to find the bounding box the find bar
@@ -272,33 +279,35 @@ gfx::Size BrowserViewLayout::GetPreferredSize(views::View* host) {
//////////////////////////////////////////////////////////////////////////////
// BrowserViewLayout, private:
+Browser* BrowserViewLayout::browser() {
+ return browser_view_->browser();
+}
+
+const Browser* BrowserViewLayout::browser() const {
+ return browser_view_->browser();
+}
+
int BrowserViewLayout::LayoutTabStrip() {
if (!browser_view_->IsTabStripVisible()) {
tabstrip_->SetVisible(false);
tabstrip_->SetBounds(0, 0, 0, 0);
return 0;
}
- gfx::Rect layout_bounds =
- browser_view_->frame()->GetBoundsForTabStrip(tabstrip_);
-
- if (browser_view_->UseVerticalTabs()) {
- vertical_layout_rect_.Inset(
- layout_bounds.width(), 0, 0, 0);
- } else {
- gfx::Rect toolbar_bounds = browser_view_->GetToolbarBounds();
- tabstrip_->SetBackgroundOffset(
- gfx::Point(layout_bounds.x() - toolbar_bounds.x(),
- layout_bounds.y()));
- }
- gfx::Point tabstrip_origin = layout_bounds.origin();
+ gfx::Rect tabstrip_bounds(
+ browser_view_->frame()->GetBoundsForTabStrip(tabstrip_));
+ gfx::Point tabstrip_origin(tabstrip_bounds.origin());
views::View::ConvertPointToView(browser_view_->GetParent(), browser_view_,
&tabstrip_origin);
- layout_bounds.set_origin(tabstrip_origin);
+ tabstrip_bounds.set_origin(tabstrip_origin);
+
+ if (browser_view_->UseVerticalTabs())
+ vertical_layout_rect_.Inset(tabstrip_bounds.width(), 0, 0, 0);
+
tabstrip_->SetVisible(true);
- tabstrip_->SetBounds(layout_bounds);
+ tabstrip_->SetBounds(tabstrip_bounds);
return browser_view_->UseVerticalTabs() ?
- layout_bounds.y() : layout_bounds.bottom();
+ tabstrip_bounds.y() : tabstrip_bounds.bottom();
}
int BrowserViewLayout::LayoutToolbar(int top) {
@@ -325,7 +334,7 @@ int BrowserViewLayout::LayoutBookmarkAndInfoBars(int top) {
if (active_bookmark_bar_->IsDetached())
return LayoutBookmarkBar(LayoutInfoBar(top));
// Otherwise, Bookmark bar first, Info bar second.
- top = LayoutBookmarkBar(top);
+ top = std::max(toolbar_->bounds().bottom(), LayoutBookmarkBar(top));
}
find_bar_y_ = top + browser_view_->y() - 1;
return LayoutInfoBar(top);
@@ -340,11 +349,9 @@ int BrowserViewLayout::LayoutBookmarkBar(int top) {
return y;
}
+ active_bookmark_bar_->set_infobar_visible(InfobarVisible());
int bookmark_bar_height = active_bookmark_bar_->GetPreferredSize().height();
- y -= kSeparationLineHeight + (
- active_bookmark_bar_->IsDetached() ?
- 0 : active_bookmark_bar_->GetToolbarOverlap(false));
-
+ y -= kSeparationLineHeight + active_bookmark_bar_->GetToolbarOverlap(false);
active_bookmark_bar_->SetVisible(true);
active_bookmark_bar_->SetBounds(vertical_layout_rect_.x(), y,
vertical_layout_rect_.width(),
@@ -353,7 +360,7 @@ int BrowserViewLayout::LayoutBookmarkBar(int top) {
}
int BrowserViewLayout::LayoutInfoBar(int top) {
- bool visible = browser()->SupportsWindowFeature(Browser::FEATURE_INFOBAR);
+ bool visible = InfobarVisible();
int height = visible ? infobar_container_->GetPreferredSize().height() : 0;
infobar_container_->SetVisible(visible);
infobar_container_->SetBounds(vertical_layout_rect_.x(), top,
@@ -361,29 +368,30 @@ int BrowserViewLayout::LayoutInfoBar(int top) {
return top + height;
}
-// Layout the TabContents container, between the coordinates |top| and
-// |bottom|.
void BrowserViewLayout::LayoutTabContents(int top, int bottom) {
contents_split_->SetBounds(vertical_layout_rect_.x(), top,
vertical_layout_rect_.width(), bottom - top);
}
-int BrowserViewLayout::LayoutExtensionAndDownloadShelves() {
- // If we're showing the Extension bar in detached style, then we
- // need to show Download shelf _above_ the Extension bar, since
- // the Extension bar is styled to look like it's part of the page.
- //
- // TODO(Oshima): confirm this comment.
- int bottom = browser_view_->height();
- if (extension_shelf_) {
- if (extension_shelf_->IsDetached()) {
- bottom = LayoutDownloadShelf(bottom);
- return LayoutExtensionShelf(bottom);
- }
- // Otherwise, Extension shelf first, Download shelf second.
- bottom = LayoutExtensionShelf(bottom);
+int BrowserViewLayout::GetTopMarginForActiveContent() {
+ if (!active_bookmark_bar_ || !browser_view_->IsBookmarkBarVisible() ||
+ !active_bookmark_bar_->IsDetached()) {
+ return 0;
+ }
+
+ if (contents_split_->GetChildViewAt(1) &&
+ contents_split_->GetChildViewAt(1)->IsVisible())
+ return 0;
+
+ if (SidebarManager::IsSidebarAllowed()) {
+ views::View* sidebar_split = contents_split_->GetChildViewAt(0);
+ if (sidebar_split->GetChildViewAt(1) &&
+ sidebar_split->GetChildViewAt(1)->IsVisible())
+ return 0;
}
- return LayoutDownloadShelf(bottom);
+
+ // Adjust for separator.
+ return active_bookmark_bar_->height() - kSeparationLineHeight;
}
int BrowserViewLayout::LayoutDownloadShelf(int bottom) {
@@ -404,17 +412,8 @@ int BrowserViewLayout::LayoutDownloadShelf(int bottom) {
return bottom;
}
-int BrowserViewLayout::LayoutExtensionShelf(int bottom) {
- if (extension_shelf_) {
- bool visible = browser()->SupportsWindowFeature(
- Browser::FEATURE_EXTENSIONSHELF);
- int height =
- visible ? extension_shelf_->GetPreferredSize().height() : 0;
- extension_shelf_->SetVisible(visible && height != 0);
- extension_shelf_->SetBounds(vertical_layout_rect_.x(), bottom - height,
- vertical_layout_rect_.width(), height);
- extension_shelf_->Layout();
- bottom -= height;
- }
- return bottom;
+bool BrowserViewLayout::InfobarVisible() const {
+ // NOTE: Can't check if the size IsEmpty() since it's always 0-width.
+ return browser()->SupportsWindowFeature(Browser::FEATURE_INFOBAR) &&
+ (infobar_container_->GetPreferredSize().height() != 0);
}
diff --git a/chrome/browser/views/frame/browser_view_layout.h b/chrome/browser/views/frame/browser_view_layout.h
index 7291e1b..42652ef 100644
--- a/chrome/browser/views/frame/browser_view_layout.h
+++ b/chrome/browser/views/frame/browser_view_layout.h
@@ -4,10 +4,18 @@
#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW_LAYOUT_H_
#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_VIEW_LAYOUT_H_
+#pragma once
-#include "chrome/browser/views/frame/browser_view.h"
#include "views/layout_manager.h"
+class BaseTabStrip;
+class BookmarkBarView;
+class Browser;
+class BrowserView;
+class ContentsContainer;
+class DownloadShelfView;
+class ToolbarView;
+
// The layout manager used in chrome browser.
class BrowserViewLayout : public views::LayoutManager {
public:
@@ -39,9 +47,8 @@ class BrowserViewLayout : public views::LayoutManager {
virtual gfx::Size GetPreferredSize(views::View* host);
protected:
- Browser* browser() {
- return browser_view_->browser();
- }
+ Browser* browser();
+ const Browser* browser() const;
// Layout the TabStrip, returns the coordinate of the bottom of the TabStrip,
// for laying out subsequent controls.
@@ -57,15 +64,18 @@ class BrowserViewLayout : public views::LayoutManager {
// Layout the TabContents container, between the coordinates |top| and
// |bottom|.
void LayoutTabContents(int top, int bottom);
- int LayoutExtensionAndDownloadShelves();
+
+ // Returns the top margin to adjust the contents_container_ by. This is used
+ // to make the bookmark bar and contents_container_ overlap so that the
+ // preview contents hides the bookmark bar.
+ int GetTopMarginForActiveContent();
// Layout the Download Shelf, returns the coordinate of the top of the
// control, for laying out the previous control.
int LayoutDownloadShelf(int bottom);
- // Layout the Extension Shelf, returns the coordinate of the top of the
- // control, for laying out the previous control.
- int LayoutExtensionShelf(int bottom);
+ // Returns true if an infobar is showing.
+ bool InfobarVisible() const;
// See description above vertical_layout_rect_ for details.
void set_vertical_layout_rect(const gfx::Rect& bounds) {
@@ -79,10 +89,9 @@ class BrowserViewLayout : public views::LayoutManager {
BaseTabStrip* tabstrip_;
ToolbarView* toolbar_;
views::View* contents_split_;
- views::View* contents_container_;
+ ContentsContainer* contents_container_;
views::View* infobar_container_;
DownloadShelfView* download_shelf_;
- ExtensionShelf* extension_shelf_;
BookmarkBarView* active_bookmark_bar_;
BrowserView* browser_view_;
diff --git a/chrome/browser/views/frame/glass_browser_frame_view.cc b/chrome/browser/views/frame/glass_browser_frame_view.cc
index 90e41b9..b532273 100644
--- a/chrome/browser/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/views/frame/glass_browser_frame_view.cc
@@ -7,7 +7,7 @@
#include "app/resource_bundle.h"
#include "app/theme_provider.h"
#include "chrome/app/chrome_dll_resource.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/tabs/side_tab_strip.h"
#include "chrome/browser/views/tabs/tab.h"
@@ -33,9 +33,6 @@ const int kNonClientRestoredExtraThickness = 11;
// In the window corners, the resize areas don't actually expand bigger, but the
// 16 px at the end of the top and bottom edges triggers diagonal resizing.
const int kResizeAreaCornerSize = 16;
-// In maximized mode, the OTR avatar starts 2 px below the top of the screen, so
-// that it doesn't extend into the "3D edge" portion of the titlebar.
-const int kOTRMaximizedTopSpacing = 2;
// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the
// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
// user).
@@ -82,8 +79,9 @@ gfx::Rect GlassBrowserFrameView::GetBoundsForTabStrip(
BaseTabStrip* tabstrip) const {
if (browser_view_->UseVerticalTabs()) {
gfx::Size ps = tabstrip->GetPreferredSize();
- return gfx::Rect(NonClientBorderThickness(), NonClientTopBorderHeight(),
- ps.width(), browser_view_->height());
+ return gfx::Rect(NonClientBorderThickness(),
+ NonClientTopBorderHeight(false, false), ps.width(),
+ browser_view_->height());
}
int minimize_button_offset = frame_->GetMinimizeButtonOffset();
int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ?
@@ -103,11 +101,16 @@ gfx::Rect GlassBrowserFrameView::GetBoundsForTabStrip(
int tabstrip_width = minimize_button_offset - tabstrip_x -
(frame_->GetWindow()->IsMaximized() ?
kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing);
- return gfx::Rect(tabstrip_x, NonClientTopBorderHeight(),
+ return gfx::Rect(tabstrip_x, GetHorizontalTabStripVerticalOffset(false),
std::max(0, tabstrip_width),
tabstrip->GetPreferredHeight());
}
+int GlassBrowserFrameView::GetHorizontalTabStripVerticalOffset(
+ bool restored) const {
+ return NonClientTopBorderHeight(restored, true);
+}
+
void GlassBrowserFrameView::UpdateThrobber(bool running) {
if (throbber_running_) {
if (running) {
@@ -145,7 +148,7 @@ gfx::Rect GlassBrowserFrameView::GetWindowBoundsForClientBounds(
return gfx::Rect(rect);
}
- int top_height = NonClientTopBorderHeight();
+ int top_height = NonClientTopBorderHeight(false, false);
int border_thickness = NonClientBorderThickness();
return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
std::max(0, client_bounds.y() - top_height),
@@ -192,7 +195,8 @@ void GlassBrowserFrameView::Paint(gfx::Canvas* canvas) {
return; // Nothing is visible, so don't bother to paint.
PaintToolbarBackground(canvas);
- PaintOTRAvatar(canvas);
+ if (browser_view_->ShouldShowOffTheRecordAvatar())
+ PaintOTRAvatar(canvas);
if (!frame_->GetWindow()->IsMaximized())
PaintRestoredClientEdge(canvas);
}
@@ -221,15 +225,19 @@ int GlassBrowserFrameView::NonClientBorderThickness() const {
kNonClientBorderThickness;
}
-int GlassBrowserFrameView::NonClientTopBorderHeight() const {
- if (frame_->GetWindow()->IsFullscreen())
+int GlassBrowserFrameView::NonClientTopBorderHeight(
+ bool restored,
+ bool ignore_vertical_tabs) const {
+ if (!restored && frame_->GetWindow()->IsFullscreen())
return 0;
- if (browser_view_->UseVerticalTabs())
- return static_cast<BrowserFrameWin*>(frame_)->GetTitleBarHeight();
// We'd like to use FrameBorderThickness() here, but the maximized Aero glass
- // frame has a 0 frame border around most edges and a CXSIZEFRAME-thick border
+ // frame has a 0 frame border around most edges and a CYSIZEFRAME-thick border
// at the top (see AeroGlassFrame::OnGetMinMaxInfo()).
- return GetSystemMetrics(SM_CXSIZEFRAME) + (browser_view_->IsMaximized() ?
+ if (browser_view_->IsTabStripVisible() && !ignore_vertical_tabs &&
+ browser_view_->UseVerticalTabs())
+ return GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
+ return GetSystemMetrics(SM_CYSIZEFRAME) +
+ ((!restored && browser_view_->IsMaximized()) ?
-kTabstripTopShadowThickness : kNonClientRestoredExtraThickness);
}
@@ -238,62 +246,59 @@ void GlassBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds());
gfx::Point toolbar_origin(toolbar_bounds.origin());
- View::ConvertPointToView(frame_->GetWindow()->GetClientView(),
- this, &toolbar_origin);
+ View::ConvertPointToView(browser_view_, this, &toolbar_origin);
toolbar_bounds.set_origin(toolbar_origin);
+ int x = toolbar_bounds.x();
+ int w = toolbar_bounds.width();
+ int left_x = x - kContentEdgeShadowThickness;
SkBitmap* theme_toolbar = tp->GetBitmapNamed(IDR_THEME_TOOLBAR);
SkBitmap* toolbar_left = tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER);
SkBitmap* toolbar_center = tp->GetBitmapNamed(IDR_CONTENT_TOP_CENTER);
if (browser_view_->UseVerticalTabs()) {
- gfx::Rect tabstrip_bounds(browser_view_->tabstrip()->bounds());
- gfx::Point tabstrip_origin(tabstrip_bounds.origin());
- View::ConvertPointToView(frame_->GetWindow()->GetClientView(),
- this, &tabstrip_origin);
- tabstrip_bounds.set_origin(tabstrip_origin);
-
- int x = tabstrip_bounds.x();
- int y = tabstrip_bounds.y();
- int w = toolbar_bounds.right() - x;
-
- int src_y = Tab::GetMinimumUnselectedSize().height();
- canvas->TileImageInt(*theme_toolbar, 0, src_y,
- MirroredLeftPointForRect(toolbar_bounds), y,
- toolbar_bounds.width(), theme_toolbar->height());
-
- // Draw left edge. We explicitly set a clip as the image is bigger than just
- // the corner.
- canvas->Save();
- canvas->ClipRectInt(x - kNonClientBorderThickness,
- y - kNonClientBorderThickness,
- kNonClientBorderThickness,
- kNonClientBorderThickness);
- canvas->DrawBitmapInt(*toolbar_left, x - kNonClientBorderThickness,
- y - kNonClientBorderThickness);
- canvas->Restore();
+ gfx::Point tabstrip_origin(browser_view_->tabstrip()->bounds().origin());
+ View::ConvertPointToView(browser_view_, this, &tabstrip_origin);
+ int y = tabstrip_origin.y();
+
+ // Tile the toolbar image starting at the frame edge on the left and where
+ // the horizontal tabstrip would be on the top.
+ canvas->TileImageInt(*theme_toolbar, x,
+ y - GetHorizontalTabStripVerticalOffset(false), x, y,
+ w, theme_toolbar->height());
+
+ // Draw left edge.
+ int dest_y = y - kNonClientBorderThickness;
+ canvas->DrawBitmapInt(*toolbar_left, 0, 0, kNonClientBorderThickness,
+ kNonClientBorderThickness, left_x, dest_y,
+ kNonClientBorderThickness, kNonClientBorderThickness,
+ false);
// Draw center edge. We need to draw a while line above the toolbar for the
// image to overlay nicely.
- canvas->FillRectInt(SK_ColorWHITE, x, y - 1, w, 1);
- canvas->TileImageInt(*toolbar_center, x, y - kNonClientBorderThickness, w,
- toolbar_center->height());
- // Right edge. Again, we have to clip because of image size.
- canvas->Save();
- canvas->ClipRectInt(x + w - kNonClientBorderThickness,
- y - kNonClientBorderThickness,
- kNonClientBorderThickness,
- kNonClientBorderThickness);
- canvas->DrawBitmapInt(*tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER),
- x + w, y);
- canvas->Restore();
+ int center_offset =
+ -kContentEdgeShadowThickness + kNonClientBorderThickness;
+ canvas->FillRectInt(SK_ColorWHITE, x + center_offset, y - 1,
+ w - (2 * center_offset), 1);
+ canvas->TileImageInt(*toolbar_center, x + center_offset, dest_y,
+ w - (2 * center_offset), toolbar_center->height());
+
+ // Right edge.
+ SkBitmap* toolbar_right = tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER);
+ canvas->DrawBitmapInt(*toolbar_right,
+ toolbar_right->width() - kNonClientBorderThickness, 0,
+ kNonClientBorderThickness, kNonClientBorderThickness,
+ x + w - center_offset, dest_y, kNonClientBorderThickness,
+ kNonClientBorderThickness, false);
} else {
- // Draw the toolbar background, setting src_y of the paint to the tab
- // strip height as the toolbar background begins at the top of the tabs.
- int src_y = browser_view_->GetTabStripHeight() - 1;
- canvas->TileImageInt(*theme_toolbar, 0, src_y,
- toolbar_bounds.x() - 1, toolbar_bounds.y() + 2,
- toolbar_bounds.width() + 2, theme_toolbar->height());
+ // Tile the toolbar image starting at the frame edge on the left and where
+ // the tabstrip is on the top.
+ int y = toolbar_bounds.y();
+ int dest_y = y + (kFrameShadowThickness * 2);
+ canvas->TileImageInt(*theme_toolbar, x,
+ dest_y - GetHorizontalTabStripVerticalOffset(false), x,
+ dest_y, w, theme_toolbar->height());
+
// Draw rounded corners for the tab.
SkBitmap* toolbar_left_mask =
tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK);
@@ -307,122 +312,100 @@ void GlassBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
// Mask out the top left corner.
- int left_x = toolbar_bounds.x() - kContentEdgeShadowThickness -
- kClientEdgeThickness;
- canvas->DrawBitmapInt(*toolbar_left_mask,
- left_x, toolbar_bounds.y(), paint);
+ canvas->DrawBitmapInt(*toolbar_left_mask, left_x, y, paint);
// Mask out the top right corner.
- int right_x = toolbar_bounds.right() - toolbar_right_mask->width() +
- kContentEdgeShadowThickness + kClientEdgeThickness;
- canvas->DrawBitmapInt(*toolbar_right_mask,
- right_x, toolbar_bounds.y(),
- paint);
+ int right_x =
+ x + w + kContentEdgeShadowThickness - toolbar_right_mask->width();
+ canvas->DrawBitmapInt(*toolbar_right_mask, right_x, y, paint);
// Draw left edge.
- canvas->DrawBitmapInt(*toolbar_left, left_x, toolbar_bounds.y());
+ canvas->DrawBitmapInt(*toolbar_left, left_x, y);
// Draw center edge.
- canvas->TileImageInt(*toolbar_center, left_x + toolbar_left->width(),
- toolbar_bounds.y(),
- right_x - (left_x + toolbar_left->width()),
- toolbar_center->height());
+ canvas->TileImageInt(*toolbar_center, left_x + toolbar_left->width(), y,
+ right_x - (left_x + toolbar_left->width()), toolbar_center->height());
// Right edge.
canvas->DrawBitmapInt(*tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER),
- right_x, toolbar_bounds.y());
+ right_x, y);
}
// Draw the content/toolbar separator.
- canvas->DrawLineInt(ResourceBundle::toolbar_separator_color,
- toolbar_bounds.x(), toolbar_bounds.bottom() - 1,
- toolbar_bounds.right() - 1, toolbar_bounds.bottom() - 1);
+ canvas->FillRectInt(ResourceBundle::toolbar_separator_color,
+ x + kClientEdgeThickness, toolbar_bounds.bottom() - kClientEdgeThickness,
+ w - (2 * kClientEdgeThickness), kClientEdgeThickness);
}
void GlassBrowserFrameView::PaintOTRAvatar(gfx::Canvas* canvas) {
- if (!browser_view_->ShouldShowOffTheRecordAvatar())
- return;
+ // In RTL mode, the avatar icon should be looking the opposite direction.
+ canvas->Save();
+ if (base::i18n::IsRTL()) {
+ canvas->TranslateInt(width(), 0);
+ canvas->ScaleInt(-1, 1);
+ }
SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon();
- int src_x = 0;
- int src_y = (otr_avatar_icon.height() - otr_avatar_bounds_.height()) / 2;
- int dst_x = MirroredLeftPointForRect(otr_avatar_bounds_);
- int dst_y = otr_avatar_bounds_.y();
int w = otr_avatar_bounds_.width();
int h = otr_avatar_bounds_.height();
- if (browser_view_->UseVerticalTabs()) {
- // Only a portion of the otr icon is visible for vertical tabs. Clip it
- // so that it doesn't overlap shadows.
- gfx::Point tabstrip_origin(browser_view_->tabstrip()->bounds().origin());
- View::ConvertPointToView(frame_->GetWindow()->GetClientView(), this,
- &tabstrip_origin);
- canvas->Save();
- canvas->ClipRectInt(dst_x, 2, w, tabstrip_origin.y() - 4);
- canvas->DrawBitmapInt(otr_avatar_icon, src_x, src_y, w, h, dst_x, dst_y,
- w, h, false);
- canvas->Restore();
- } else {
- canvas->DrawBitmapInt(otr_avatar_icon, src_x, src_y, w, h, dst_x, dst_y,
- w, h, false);
- }
+ canvas->DrawBitmapInt(otr_avatar_icon, 0,
+ // Bias the rounding to select a region that's lower rather than higher,
+ // as the shadows at the image top mean the apparent center is below the
+ // real center.
+ ((otr_avatar_icon.height() - otr_avatar_bounds_.height()) + 1) / 2, w, h,
+ otr_avatar_bounds_.x(), otr_avatar_bounds_.y(), w, h, false);
+
+ canvas->Restore();
}
void GlassBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
ThemeProvider* tp = GetThemeProvider();
-
gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height());
// The client edges start below the toolbar upper corner images regardless
// of how tall the toolbar itself is.
int client_area_top = browser_view_->UseVerticalTabs() ?
client_area_bounds.y() :
- frame_->GetWindow()->GetClientView()->y() +
+ (frame_->GetWindow()->GetClientView()->y() +
browser_view_->GetToolbarBounds().y() +
- tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height();
-
+ tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height());
int client_area_bottom =
std::max(client_area_top, height() - NonClientBorderThickness());
int client_area_height = client_area_bottom - client_area_top;
+
+ // Draw the client edge images.
SkBitmap* right = tp->GetBitmapNamed(IDR_CONTENT_RIGHT_SIDE);
canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top,
right->width(), client_area_height);
-
- // Draw the toolbar color so that the one pixel areas down the sides
- // show the right color even if not covered by the toolbar image.
- SkColor toolbar_color = tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
- canvas->DrawLineInt(toolbar_color,
- client_area_bounds.x() - kClientEdgeThickness,
- client_area_top,
- client_area_bounds.x() - kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness);
- canvas->DrawLineInt(toolbar_color,
- client_area_bounds.x() - kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness,
- client_area_bounds.right() + kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness);
- canvas->DrawLineInt(toolbar_color,
- client_area_bounds.right() - 1 + kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness,
- client_area_bounds.right() - 1 + kClientEdgeThickness,
- client_area_top);
-
canvas->DrawBitmapInt(
*tp->GetBitmapNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER),
client_area_bounds.right(), client_area_bottom);
-
SkBitmap* bottom = tp->GetBitmapNamed(IDR_CONTENT_BOTTOM_CENTER);
canvas->TileImageInt(*bottom, client_area_bounds.x(),
client_area_bottom, client_area_bounds.width(),
bottom->height());
-
SkBitmap* bottom_left =
tp->GetBitmapNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
canvas->DrawBitmapInt(*bottom_left,
client_area_bounds.x() - bottom_left->width(), client_area_bottom);
-
SkBitmap* left = tp->GetBitmapNamed(IDR_CONTENT_LEFT_SIDE);
canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
client_area_top, left->width(), client_area_height);
+
+ // Draw the toolbar color so that the client edges show the right color even
+ // where not covered by the toolbar image. NOTE: We do this after drawing the
+ // images because the images are meant to alpha-blend atop the frame whereas
+ // these rects are meant to be fully opaque, without anything overlaid.
+ SkColor toolbar_color = tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
+ canvas->FillRectInt(toolbar_color,
+ client_area_bounds.x() - kClientEdgeThickness, client_area_top,
+ kClientEdgeThickness,
+ client_area_bottom + kClientEdgeThickness - client_area_top);
+ canvas->FillRectInt(toolbar_color, client_area_bounds.x(), client_area_bottom,
+ client_area_bounds.width(), kClientEdgeThickness);
+ canvas->FillRectInt(toolbar_color, client_area_bounds.right(),
+ client_area_top, kClientEdgeThickness,
+ client_area_bottom + kClientEdgeThickness - client_area_top);
}
void GlassBrowserFrameView::LayoutOTRAvatar() {
@@ -433,21 +416,22 @@ void GlassBrowserFrameView::LayoutOTRAvatar() {
// comment in GetBoundsForTabStrip().)
if (base::i18n::IsRTL())
otr_x += width() - frame_->GetMinimizeButtonOffset();
+
SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon();
- int otr_height = browser_view_->IsTabStripVisible() ?
- otr_avatar_icon.height() : 0;
- int otr_y = 0;
+ int otr_bottom, otr_restored_y;
if (browser_view_->UseVerticalTabs()) {
- otr_y = NonClientTopBorderHeight() - otr_avatar_icon.height();
- } else if (browser_view_->IsTabStripVisible()) {
- int top_height = NonClientTopBorderHeight();
- int tabstrip_height =
+ otr_bottom = NonClientTopBorderHeight(false, false) - kOTRBottomSpacing;
+ otr_restored_y = kFrameShadowThickness;
+ } else {
+ otr_bottom = GetHorizontalTabStripVerticalOffset(false) +
browser_view_->GetTabStripHeight() - kOTRBottomSpacing;
- otr_height = frame_->GetWindow()->IsMaximized() ?
- (tabstrip_height - kOTRMaximizedTopSpacing) : otr_avatar_icon.height();
- otr_y = top_height + tabstrip_height - otr_height;
+ otr_restored_y = otr_bottom - otr_avatar_icon.height();
}
- otr_avatar_bounds_.SetRect(otr_x, otr_y, otr_avatar_icon.width(), otr_height);
+ int otr_y = frame_->GetWindow()->IsMaximized() ?
+ (NonClientTopBorderHeight(false, true) + kTabstripTopShadowThickness) :
+ otr_restored_y;
+ otr_avatar_bounds_.SetRect(otr_x, otr_y, otr_avatar_icon.width(),
+ browser_view_->ShouldShowOffTheRecordAvatar() ? (otr_bottom - otr_y) : 0);
}
void GlassBrowserFrameView::LayoutClientView() {
@@ -459,7 +443,7 @@ gfx::Rect GlassBrowserFrameView::CalculateClientAreaBounds(int width,
if (!browser_view_->IsTabStripVisible())
return gfx::Rect(0, 0, this->width(), this->height());
- int top_height = NonClientTopBorderHeight();
+ int top_height = NonClientTopBorderHeight(false, false);
int border_thickness = NonClientBorderThickness();
return gfx::Rect(border_thickness, top_height,
std::max(0, width - (2 * border_thickness)),
diff --git a/chrome/browser/views/frame/glass_browser_frame_view.h b/chrome/browser/views/frame/glass_browser_frame_view.h
index 66f9abf..0a39da1 100644
--- a/chrome/browser/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/views/frame/glass_browser_frame_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_FRAME_GLASS_BROWSER_FRAME_VIEW_H_
#define CHROME_BROWSER_VIEWS_FRAME_GLASS_BROWSER_FRAME_VIEW_H_
+#pragma once
#include "chrome/browser/views/frame/browser_frame_win.h"
#include "chrome/browser/views/frame/browser_non_client_frame_view.h"
@@ -21,6 +22,7 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView {
// Overridden from BrowserNonClientFrameView:
virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const;
+ virtual int GetHorizontalTabStripVerticalOffset(bool restored) const;
virtual void UpdateThrobber(bool running);
// Overridden from views::NonClientFrameView:
@@ -48,8 +50,11 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView {
int NonClientBorderThickness() const;
// Returns the height of the entire nonclient top border, including the window
- // frame, any title area, and any connected client edge.
- int NonClientTopBorderHeight() const;
+ // frame, any title area, and any connected client edge. If |restored| is
+ // true, acts as if the window is restored regardless of the real mode. If
+ // |ignore_vertical_tabs| is true, acts as if vertical tabs are off regardless
+ // of the real state.
+ int NonClientTopBorderHeight(bool restored, bool ignore_vertical_tabs) const;
// Paint various sub-components of this view.
void PaintToolbarBackground(gfx::Canvas* canvas);
@@ -70,9 +75,6 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView {
// Displays the next throbber frame.
void DisplayNextThrobberFrame();
- // The layout rect of the distributor logo, if visible.
- gfx::Rect logo_bounds_;
-
// The layout rect of the OTR avatar icon, if visible.
gfx::Rect otr_avatar_bounds_;
diff --git a/chrome/browser/views/frame/opaque_browser_frame_view.cc b/chrome/browser/views/frame/opaque_browser_frame_view.cc
index 16a51fe..c3c1a0a 100644
--- a/chrome/browser/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/views/frame/opaque_browser_frame_view.cc
@@ -8,8 +8,8 @@
#include "app/resource_bundle.h"
#include "app/theme_provider.h"
#include "base/compiler_specific.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/views/frame/browser_frame.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/tabs/tab_strip.h"
@@ -28,18 +28,10 @@
#include "views/window/window_resources.h"
#include "views/window/window_shape.h"
-#if defined(OS_WIN)
-#include "app/win_util.h"
-#endif
-
#if defined(OS_LINUX)
#include "views/window/hit_test.h"
#endif
-#if defined(OS_CHROMEOS)
-const int kCustomFrameBackgroundVerticalOffset = 15;
-#endif
-
namespace {
// The frame border is only visible in restored mode and is hardcoded to 4 px on
// each side regardless of the system window border size.
@@ -71,9 +63,6 @@ const int kIconMinimumSize = 16;
const int kIconTitleSpacing = 4;
// There is a 5 px gap between the title text and the caption buttons.
const int kTitleLogoSpacing = 5;
-// In maximized mode, the OTR avatar starts 2 px below the top of the screen, so
-// that it doesn't extend into the "3D edge" portion of the titlebar.
-const int kOTRMaximizedTopSpacing = 2;
// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the
// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
// user).
@@ -95,8 +84,6 @@ const int kNewTabCaptionMaximizedSpacing = 16;
// How far to indent the tabstrip from the left side of the screen when there
// is no OTR icon.
const int kTabStripIndent = 1;
-// Padding between the caption and start of vertical tabs.
-const int kVerticalTabPadding = 6;
// Inset from the top of the toolbar/tabstrip to the shadow. Used only for
// vertical tabs.
const int kVerticalTabBorderInset = 3;
@@ -108,7 +95,6 @@ const int kVerticalTabBorderInset = 3;
OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame,
BrowserView* browser_view)
: BrowserNonClientFrameView(),
- otr_avatar_icon_(new views::ImageView()),
ALLOW_THIS_IN_INITIALIZER_LIST(
minimize_button_(new views::ImageButton(this))),
ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -178,8 +164,6 @@ OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame,
close_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
AddChildView(close_button_);
- otr_avatar_icon_->SetImage(browser_view_->GetOTRAvatarIcon());
- AddChildView(otr_avatar_icon_);
// Initializing the TabIconView is expensive, so only do it if we need to.
if (browser_view_->ShouldShowWindowIcon()) {
window_icon_ = new TabIconView(this);
@@ -199,26 +183,28 @@ gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip(
BaseTabStrip* tabstrip) const {
if (browser_view_->UseVerticalTabs()) {
gfx::Size ps = tabstrip->GetPreferredSize();
- return gfx::Rect(NonClientBorderThickness(), NonClientTopBorderHeight(),
- ps.width(), browser_view_->height());
- }
-
- int tabstrip_y = NonClientTopBorderHeight();
- if (!frame_->GetWindow()->IsMaximized() &&
- !frame_->GetWindow()->IsFullscreen()) {
- tabstrip_y += kNonClientRestoredExtraThickness;
+ return gfx::Rect(NonClientBorderThickness(),
+ NonClientTopBorderHeight(false, false), ps.width(),
+ browser_view_->height());
}
int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ?
- (otr_avatar_icon_->bounds().right() + kOTRSideSpacing) :
+ (otr_avatar_bounds_.right() + kOTRSideSpacing) :
NonClientBorderThickness() + kTabStripIndent;
int tabstrip_width = minimize_button_->x() - tabstrip_x -
(frame_->GetWindow()->IsMaximized() ?
kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing);
- return gfx::Rect(tabstrip_x, tabstrip_y,
- std::max(0, tabstrip_width),
- tabstrip->GetPreferredHeight());
+ return gfx::Rect(tabstrip_x, GetHorizontalTabStripVerticalOffset(false),
+ std::max(0, tabstrip_width), tabstrip->GetPreferredHeight());
+}
+
+int OpaqueBrowserFrameView::GetHorizontalTabStripVerticalOffset(
+ bool restored) const {
+ return NonClientTopBorderHeight(restored, true) + ((!restored &&
+ (frame_->GetWindow()->IsMaximized() ||
+ frame_->GetWindow()->IsFullscreen())) ?
+ 0 : kNonClientRestoredExtraThickness);
}
void OpaqueBrowserFrameView::UpdateThrobber(bool running) {
@@ -230,11 +216,12 @@ gfx::Size OpaqueBrowserFrameView::GetMinimumSize() {
gfx::Size min_size(browser_view_->GetMinimumSize());
int border_thickness = NonClientBorderThickness();
min_size.Enlarge(2 * border_thickness,
- NonClientTopBorderHeight() + border_thickness);
+ NonClientTopBorderHeight(false, false) + border_thickness);
views::WindowDelegate* d = frame_->GetWindow()->GetDelegate();
- int min_titlebar_width = (2 * FrameBorderThickness()) + kIconLeftSpacing +
- (d->ShouldShowWindowIcon() ? (IconSize() + kTitleLogoSpacing) : 0);
+ int min_titlebar_width = (2 * FrameBorderThickness(false)) +
+ kIconLeftSpacing +
+ (d->ShouldShowWindowIcon() ? (IconSize() + kTitleLogoSpacing) : 0);
#if !defined(OS_CHROMEOS)
min_titlebar_width +=
minimize_button_->GetMinimumSize().width() +
@@ -262,7 +249,7 @@ bool OpaqueBrowserFrameView::AlwaysUseCustomFrame() const {
gfx::Rect OpaqueBrowserFrameView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
- int top_height = NonClientTopBorderHeight();
+ int top_height = NonClientTopBorderHeight(false, false);
int border_thickness = NonClientBorderThickness();
return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
std::max(0, client_bounds.y() - top_height),
@@ -351,34 +338,12 @@ void OpaqueBrowserFrameView::Paint(gfx::Canvas* canvas) {
PaintTitleBar(canvas);
if (browser_view_->IsToolbarVisible())
PaintToolbarBackground(canvas);
+ if (browser_view_->ShouldShowOffTheRecordAvatar())
+ PaintOTRAvatar(canvas);
if (!window->IsMaximized())
PaintRestoredClientEdge(canvas);
}
-void OpaqueBrowserFrameView::PaintChildren(gfx::Canvas* canvas) {
- if (!browser_view_->UseVerticalTabs() || !otr_avatar_icon_->IsVisible()) {
- View::PaintChildren(canvas);
- return;
- }
-
- // The otr icon is clipped for side tabs.
- for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
- View* child = GetChildViewAt(i);
- if (!child) {
- NOTREACHED() << "Should not have a NULL child View for index in bounds";
- continue;
- }
- if (child == otr_avatar_icon_) {
- canvas->Save();
- canvas->ClipRectInt(0, 2, width(), otr_avatar_icon_->height() - 10);
- child->ProcessPaint(canvas);
- canvas->Restore();
- } else {
- child->ProcessPaint(canvas);
- }
- }
-}
-
void OpaqueBrowserFrameView::Layout() {
LayoutWindowControls();
LayoutTitleBar();
@@ -412,11 +377,8 @@ bool OpaqueBrowserFrameView::HitTest(const gfx::Point& l) const {
return browser_view_->IsPositionInWindowCaption(browser_view_point);
}
-bool OpaqueBrowserFrameView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_TITLEBAR;
- return true;
+AccessibilityTypes::Role OpaqueBrowserFrameView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_TITLEBAR;
}
///////////////////////////////////////////////////////////////////////////////
@@ -453,57 +415,52 @@ SkBitmap OpaqueBrowserFrameView::GetFavIconForTabIconView() {
///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, private:
-int OpaqueBrowserFrameView::FrameBorderThickness() const {
+int OpaqueBrowserFrameView::FrameBorderThickness(bool restored) const {
views::Window* window = frame_->GetWindow();
- return (window->IsMaximized() || window->IsFullscreen()) ?
+ return (!restored && (window->IsMaximized() || window->IsFullscreen())) ?
0 : kFrameBorderThickness;
}
int OpaqueBrowserFrameView::TopResizeHeight() const {
- return FrameBorderThickness() - kTopResizeAdjust;
+ return FrameBorderThickness(false) - kTopResizeAdjust;
}
int OpaqueBrowserFrameView::NonClientBorderThickness() const {
// When we fill the screen, we don't show a client edge.
views::Window* window = frame_->GetWindow();
- return FrameBorderThickness() +
+ return FrameBorderThickness(false) +
((window->IsMaximized() || window->IsFullscreen()) ?
0 : kClientEdgeThickness);
}
-int OpaqueBrowserFrameView::NonClientTopBorderHeight() const {
+int OpaqueBrowserFrameView::NonClientTopBorderHeight(
+ bool restored,
+ bool ignore_vertical_tabs) const {
views::Window* window = frame_->GetWindow();
- if (window->GetDelegate()->ShouldShowWindowTitle()) {
- return std::max(FrameBorderThickness() + IconSize(),
- CaptionButtonY() + kCaptionButtonHeightWithPadding) +
- TitlebarBottomThickness();
- }
-
- if (browser_view_->IsTabStripVisible() && browser_view_->UseVerticalTabs()) {
- return CaptionButtonY() + minimize_button_->GetPreferredSize().height() +
- kVerticalTabPadding;
+ if (window->GetDelegate()->ShouldShowWindowTitle() ||
+ (browser_view_->IsTabStripVisible() && !ignore_vertical_tabs &&
+ browser_view_->UseVerticalTabs())) {
+ return std::max(FrameBorderThickness(restored) + IconSize(),
+ CaptionButtonY(restored) + kCaptionButtonHeightWithPadding) +
+ TitlebarBottomThickness(restored);
}
- if (browser_view_->IsTabStripVisible() && window->IsMaximized())
- return FrameBorderThickness() - kTabstripTopShadowThickness;
-
- return FrameBorderThickness();
+ return FrameBorderThickness(restored) -
+ ((browser_view_->IsTabStripVisible() && !restored &&
+ window->IsMaximized()) ? kTabstripTopShadowThickness : 0);
}
-int OpaqueBrowserFrameView::CaptionButtonY() const {
+int OpaqueBrowserFrameView::CaptionButtonY(bool restored) const {
// Maximized buttons start at window top so that even if their images aren't
// drawn flush with the screen edge, they still obey Fitts' Law.
- return frame_->GetWindow()->IsMaximized() ?
- FrameBorderThickness() : kFrameShadowThickness;
+ return (!restored && frame_->GetWindow()->IsMaximized()) ?
+ FrameBorderThickness(false) : kFrameShadowThickness;
}
-int OpaqueBrowserFrameView::TitlebarBottomThickness() const {
- // When a toolbar is edging the titlebar, it draws its own bottom edge.
- if (browser_view_->IsToolbarVisible())
- return 0;
-
+int OpaqueBrowserFrameView::TitlebarBottomThickness(bool restored) const {
return kTitlebarTopAndBottomEdgeThickness +
- (frame_->GetWindow()->IsMaximized() ? 0 : kClientEdgeThickness);
+ ((!restored && frame_->GetWindow()->IsMaximized()) ?
+ 0 : kClientEdgeThickness);
}
int OpaqueBrowserFrameView::IconSize() const {
@@ -512,13 +469,13 @@ int OpaqueBrowserFrameView::IconSize() const {
// size are increased.
return GetSystemMetrics(SM_CYSMICON);
#else
- return std::max(BrowserFrame::GetTitleFont().height(), kIconMinimumSize);
+ return std::max(BrowserFrame::GetTitleFont().GetHeight(), kIconMinimumSize);
#endif
}
gfx::Rect OpaqueBrowserFrameView::IconBounds() const {
int size = IconSize();
- int frame_thickness = FrameBorderThickness();
+ int frame_thickness = FrameBorderThickness(false);
int y;
views::WindowDelegate* d = frame_->GetWindow()->GetDelegate();
if (d->ShouldShowWindowIcon() || d->ShouldShowWindowTitle()) {
@@ -538,8 +495,8 @@ gfx::Rect OpaqueBrowserFrameView::IconBounds() const {
// restored windows) below looks (to the eye) more like additional space
// than does the 3D edge (or nothing at all, for maximized windows) above;
// hence the +1.
- y = unavailable_px_at_top + (NonClientTopBorderHeight() -
- unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
+ y = unavailable_px_at_top + (NonClientTopBorderHeight(false, false) -
+ unavailable_px_at_top - size - TitlebarBottomThickness(false) + 1) / 2;
} else {
// For "browser mode" windows, we use the native positioning, which is just
// below the top frame border.
@@ -672,7 +629,6 @@ void OpaqueBrowserFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
// Window frame mode and color
SkBitmap* theme_frame;
- int y = 0;
// Never theme app and popup windows.
if (!browser_view_->IsBrowserTypeNormal()) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
@@ -681,30 +637,24 @@ void OpaqueBrowserFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
} else if (!browser_view_->IsOffTheRecord()) {
theme_frame = tp->GetBitmapNamed(ShouldPaintAsActive() ?
IDR_THEME_FRAME : IDR_THEME_FRAME_INACTIVE);
-#if defined(OS_CHROMEOS)
- // TODO:(oshima): gtk based CHROMEOS is using non custom frame
- // mode which does this adjustment. This should be removed
- // once it's fully migrated to views. -1 is due to the layout
- // difference between views and gtk and will be removed.
- // See http://crbug.com/28580.
- y = -kCustomFrameBackgroundVerticalOffset - 1;
-#endif
} else {
theme_frame = tp->GetBitmapNamed(ShouldPaintAsActive() ?
IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME_INCOGNITO_INACTIVE);
-#if defined(OS_CHROMEOS)
- y = -kCustomFrameBackgroundVerticalOffset - 1;
-#endif
}
- // Draw the theme frame.
- canvas->TileImageInt(*theme_frame, 0, y, width(), theme_frame->height());
+ // Draw the theme frame. It must be aligned with the tabstrip as if we were
+ // in restored mode. Note that the top of the tabstrip is
+ // kTabstripTopShadowThickness px off the top of the screen.
+ int theme_background_y = -(GetHorizontalTabStripVerticalOffset(true) +
+ kTabstripTopShadowThickness);
+ canvas->TileImageInt(*theme_frame, 0, theme_background_y, width(),
+ theme_frame->height());
// Draw the theme frame overlay
if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
browser_view_->IsBrowserTypeNormal()) {
SkBitmap* theme_overlay = tp->GetBitmapNamed(ShouldPaintAsActive() ?
IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE);
- canvas->DrawBitmapInt(*theme_overlay, 0, 0);
+ canvas->DrawBitmapInt(*theme_overlay, 0, theme_background_y);
}
if (!browser_view_->IsToolbarVisible()) {
@@ -723,10 +673,9 @@ void OpaqueBrowserFrameView::PaintTitleBar(gfx::Canvas* canvas) {
// The window icon is painted by the TabIconView.
views::WindowDelegate* d = frame_->GetWindow()->GetDelegate();
if (d->ShouldShowWindowTitle()) {
- canvas->DrawStringInt(
- d->GetWindowTitle(), BrowserFrame::GetTitleFont(), SK_ColorWHITE,
- MirroredLeftPointForRect(title_bounds_), title_bounds_.y(),
- title_bounds_.width(), title_bounds_.height());
+ canvas->DrawStringInt(d->GetWindowTitle(), BrowserFrame::GetTitleFont(),
+ SK_ColorWHITE, MirroredLeftPointForRect(title_bounds_),
+ title_bounds_.y(), title_bounds_.width(), title_bounds_.height());
/* TODO(pkasting): If this window is active, we should also draw a drop
* shadow on the title. This is tricky, because we don't want to hardcode a
* shadow color (since we want to work with various themes), but we can't
@@ -737,22 +686,22 @@ void OpaqueBrowserFrameView::PaintTitleBar(gfx::Canvas* canvas) {
}
void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
- gfx::Rect toolbar_bounds = GetViewBounds(browser_view_->toolbar(), this);
+ gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds());
if (toolbar_bounds.IsEmpty())
return;
+ gfx::Point toolbar_origin(toolbar_bounds.origin());
+ ConvertPointToView(browser_view_, this, &toolbar_origin);
+ toolbar_bounds.set_origin(toolbar_origin);
- ThemeProvider* tp = GetThemeProvider();
-
- int x, y, w, h;
+ int x = toolbar_bounds.x();
+ int w = toolbar_bounds.width();
+ int y, h;
if (browser_view_->UseVerticalTabs()) {
- gfx::Rect tabstrip_bounds = GetViewBounds(browser_view_->tabstrip(), this);
- x = tabstrip_bounds.x();
- w = toolbar_bounds.right() - x;
- y = tabstrip_bounds.y() - kVerticalTabBorderInset;
+ gfx::Point tabstrip_origin(browser_view_->tabstrip()->bounds().origin());
+ ConvertPointToView(browser_view_, this, &tabstrip_origin);
+ y = tabstrip_origin.y() - kVerticalTabBorderInset;
h = toolbar_bounds.bottom() - y;
} else {
- x = toolbar_bounds.x();
- w = toolbar_bounds.width();
y = toolbar_bounds.y();
h = toolbar_bounds.bottom();
}
@@ -763,6 +712,7 @@ void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
// section so that we never break the gradient.
int split_point = kFrameShadowThickness * 2;
int bottom_y = y + split_point;
+ ThemeProvider* tp = GetThemeProvider();
SkBitmap* toolbar_left = tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER);
int bottom_edge_height = std::min(toolbar_left->height(), h) - split_point;
@@ -777,15 +727,12 @@ void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
canvas->FillRectInt(theme_toolbar_color, x, bottom_y, w, bottom_edge_height);
- int strip_height = browser_view_->GetTabStripHeight();
+ // Tile the toolbar image starting at the frame edge on the left and where the
+ // horizontal tabstrip is (or would be) on the top.
SkBitmap* theme_toolbar = tp->GetBitmapNamed(IDR_THEME_TOOLBAR);
-
- canvas->TileImageInt(*theme_toolbar,
- x - kClientEdgeThickness,
- strip_height - kFrameShadowThickness,
- x - kClientEdgeThickness, bottom_y,
- w + (2 * kClientEdgeThickness),
- theme_toolbar->height());
+ canvas->TileImageInt(*theme_toolbar, x,
+ bottom_y - GetHorizontalTabStripVerticalOffset(false), x,
+ bottom_y, w, theme_toolbar->height());
// Draw rounded corners for the tab.
SkBitmap* toolbar_left_mask =
@@ -799,24 +746,22 @@ void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
- // Make the left edge.
- int left_x = x - kClientEdgeThickness - kContentEdgeShadowThickness;
- canvas->DrawBitmapInt(*toolbar_left_mask, 0, 0,
- toolbar_left_mask->width(), split_point,
- left_x, y,
- toolbar_left_mask->width(), split_point, false, paint);
+ // Mask the left edge.
+ int left_x = x - kContentEdgeShadowThickness;
+ canvas->DrawBitmapInt(*toolbar_left_mask, 0, 0, toolbar_left_mask->width(),
+ split_point, left_x, y, toolbar_left_mask->width(),
+ split_point, false, paint);
canvas->DrawBitmapInt(*toolbar_left_mask, 0,
toolbar_left_mask->height() - bottom_edge_height,
- toolbar_left_mask->width(), bottom_edge_height,
- left_x, bottom_y,
+ toolbar_left_mask->width(), bottom_edge_height, left_x, bottom_y,
toolbar_left_mask->width(), bottom_edge_height, false, paint);
// Mask the right edge.
- int right_x = x + w - toolbar_right_mask->width() + kClientEdgeThickness +
- kContentEdgeShadowThickness;
- canvas->DrawBitmapInt(*toolbar_right_mask, 0, 0,
- toolbar_right_mask->width(), split_point, right_x, y,
- toolbar_right_mask->width(), split_point, false, paint);
+ int right_x =
+ x + w - toolbar_right_mask->width() + kContentEdgeShadowThickness;
+ canvas->DrawBitmapInt(*toolbar_right_mask, 0, 0, toolbar_right_mask->width(),
+ split_point, right_x, y, toolbar_right_mask->width(),
+ split_point, false, paint);
canvas->DrawBitmapInt(*toolbar_right_mask, 0,
toolbar_right_mask->height() - bottom_edge_height,
toolbar_right_mask->width(), bottom_edge_height, right_x, bottom_y,
@@ -824,12 +769,11 @@ void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
canvas->Restore();
canvas->DrawBitmapInt(*toolbar_left, 0, 0, toolbar_left->width(), split_point,
- left_x, y,
- toolbar_left->width(), split_point, false);
+ left_x, y, toolbar_left->width(), split_point, false);
canvas->DrawBitmapInt(*toolbar_left, 0,
toolbar_left->height() - bottom_edge_height, toolbar_left->width(),
- bottom_edge_height, left_x, bottom_y,
- toolbar_left->width(), bottom_edge_height, false);
+ bottom_edge_height, left_x, bottom_y, toolbar_left->width(),
+ bottom_edge_height, false);
SkBitmap* toolbar_center =
tp->GetBitmapNamed(IDR_CONTENT_TOP_CENTER);
@@ -839,37 +783,60 @@ void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
SkBitmap* toolbar_right = tp->GetBitmapNamed(IDR_CONTENT_TOP_RIGHT_CORNER);
canvas->DrawBitmapInt(*toolbar_right, 0, 0, toolbar_right->width(),
- split_point, right_x, y,
- toolbar_right->width(), split_point, false);
+ split_point, right_x, y, toolbar_right->width(), split_point, false);
canvas->DrawBitmapInt(*toolbar_right, 0,
toolbar_right->height() - bottom_edge_height, toolbar_right->width(),
- bottom_edge_height, right_x, bottom_y,
- toolbar_right->width(), bottom_edge_height, false);
+ bottom_edge_height, right_x, bottom_y, toolbar_right->width(),
+ bottom_edge_height, false);
// Draw the content/toolbar separator.
- canvas->DrawLineInt(ResourceBundle::toolbar_separator_color,
- MirroredLeftPointForRect(toolbar_bounds),
- toolbar_bounds.bottom() - kClientEdgeThickness,
- toolbar_bounds.width() - kClientEdgeThickness,
- toolbar_bounds.bottom() - kClientEdgeThickness);
+ canvas->FillRectInt(ResourceBundle::toolbar_separator_color,
+ x + kClientEdgeThickness, toolbar_bounds.bottom() - kClientEdgeThickness,
+ w - (2 * kClientEdgeThickness), kClientEdgeThickness);
+}
+
+void OpaqueBrowserFrameView::PaintOTRAvatar(gfx::Canvas* canvas) {
+ // In RTL mode, the avatar icon should be looking the opposite direction.
+ canvas->Save();
+ if (base::i18n::IsRTL()) {
+ canvas->TranslateInt(width(), 0);
+ canvas->ScaleInt(-1, 1);
+ }
+
+ SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon();
+ int w = otr_avatar_bounds_.width();
+ int h = otr_avatar_bounds_.height();
+ canvas->DrawBitmapInt(otr_avatar_icon, 0,
+ // Bias the rounding to select a region that's lower rather than higher,
+ // as the shadows at the image top mean the apparent center is below the
+ // real center.
+ ((otr_avatar_icon.height() - otr_avatar_bounds_.height()) + 1) / 2, w, h,
+ otr_avatar_bounds_.x(), otr_avatar_bounds_.y(), w, h, false);
+
+ canvas->Restore();
}
void OpaqueBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
ThemeProvider* tp = GetThemeProvider();
int client_area_top = frame_->GetWindow()->GetClientView()->y();
+ int image_top = client_area_top;
gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height());
SkColor toolbar_color = tp->GetColor(BrowserThemeProvider::COLOR_TOOLBAR);
if (browser_view_->IsToolbarVisible()) {
- // The client edges start below the toolbar or its corner images, whichever
- // is shorter.
+ // The client edge images always start below the toolbar corner images. The
+ // client edge filled rects start there or at the bottom of the tooolbar,
+ // whichever is shorter.
gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds());
- client_area_top += browser_view_->GetToolbarBounds().y() +
- std::min(tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height(),
- toolbar_bounds.height());
- if (browser_view_->UseVerticalTabs())
+ image_top += toolbar_bounds.y() +
+ tp->GetBitmapNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height();
+ client_area_top = std::min(image_top,
+ client_area_top + toolbar_bounds.bottom() - kClientEdgeThickness);
+ if (browser_view_->UseVerticalTabs()) {
client_area_top -= kVerticalTabBorderInset;
+ image_top -= kVerticalTabBorderInset;
+ }
} else if (!browser_view_->IsTabStripVisible()) {
// The toolbar isn't going to draw a client edge for us, so draw one
// ourselves.
@@ -889,92 +856,90 @@ void OpaqueBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
top_right->width(), height, false);
// Draw the toolbar color across the top edge.
- canvas->DrawLineInt(toolbar_color,
+ canvas->FillRectInt(toolbar_color,
client_area_bounds.x() - kClientEdgeThickness,
client_area_top - kClientEdgeThickness,
- client_area_bounds.right() + kClientEdgeThickness,
- client_area_top - kClientEdgeThickness);
+ client_area_bounds.width() + (2 * kClientEdgeThickness),
+ kClientEdgeThickness);
}
int client_area_bottom =
std::max(client_area_top, height() - NonClientBorderThickness());
- int client_area_height = client_area_bottom - client_area_top;
-
- // Draw the toolbar color so that the one pixel areas down the sides
- // show the right color even if not covered by the toolbar image.
- canvas->DrawLineInt(toolbar_color,
- client_area_bounds.x() - kClientEdgeThickness,
- client_area_top,
- client_area_bounds.x() - kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness);
- canvas->DrawLineInt(toolbar_color,
- client_area_bounds.x() - kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness,
- client_area_bounds.right() + kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness);
- canvas->DrawLineInt(toolbar_color,
- client_area_bounds.right() - 1 + kClientEdgeThickness,
- client_area_bottom - 1 + kClientEdgeThickness,
- client_area_bounds.right() - 1 + kClientEdgeThickness,
- client_area_top);
+ int image_height = client_area_bottom - image_top;
+ // Draw the client edge images.
+ // Draw the client edge images.
SkBitmap* right = tp->GetBitmapNamed(IDR_CONTENT_RIGHT_SIDE);
- canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top,
- right->width(), client_area_height);
+ canvas->TileImageInt(*right, client_area_bounds.right(), image_top,
+ right->width(), image_height);
canvas->DrawBitmapInt(
*tp->GetBitmapNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER),
client_area_bounds.right(), client_area_bottom);
-
SkBitmap* bottom = tp->GetBitmapNamed(IDR_CONTENT_BOTTOM_CENTER);
canvas->TileImageInt(*bottom, client_area_bounds.x(),
client_area_bottom, client_area_bounds.width(),
bottom->height());
-
SkBitmap* bottom_left =
tp->GetBitmapNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
canvas->DrawBitmapInt(*bottom_left,
client_area_bounds.x() - bottom_left->width(), client_area_bottom);
-
SkBitmap* left = tp->GetBitmapNamed(IDR_CONTENT_LEFT_SIDE);
canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
- client_area_top, left->width(), client_area_height);
+ image_top, left->width(), image_height);
+
+ // Draw the toolbar color so that the client edges show the right color even
+ // where not covered by the toolbar image. NOTE: We do this after drawing the
+ // images because the images are meant to alpha-blend atop the frame whereas
+ // these rects are meant to be fully opaque, without anything overlaid.
+ canvas->FillRectInt(toolbar_color,
+ client_area_bounds.x() - kClientEdgeThickness, client_area_top,
+ kClientEdgeThickness,
+ client_area_bottom + kClientEdgeThickness - client_area_top);
+ canvas->FillRectInt(toolbar_color, client_area_bounds.x(), client_area_bottom,
+ client_area_bounds.width(), kClientEdgeThickness);
+ canvas->FillRectInt(toolbar_color, client_area_bounds.right(),
+ client_area_top, kClientEdgeThickness,
+ client_area_bottom + kClientEdgeThickness - client_area_top);
}
void OpaqueBrowserFrameView::LayoutWindowControls() {
bool is_maximized = frame_->GetWindow()->IsMaximized();
close_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
views::ImageButton::ALIGN_BOTTOM);
- int caption_y = CaptionButtonY();
+ int caption_y = CaptionButtonY(false);
// There should always be the same number of non-shadow pixels visible to the
// side of the caption buttons. In maximized mode we extend the rightmost
// button to the screen corner to obey Fitts' Law.
int right_extra_width = is_maximized ?
(kFrameBorderThickness - kFrameShadowThickness) : 0;
gfx::Size close_button_size = close_button_->GetPreferredSize();
- close_button_->SetBounds(width() - FrameBorderThickness() -
+ close_button_->SetBounds(width() - FrameBorderThickness(false) -
right_extra_width - close_button_size.width(), caption_y,
close_button_size.width() + right_extra_width,
close_button_size.height());
#if defined(OS_CHROMEOS)
- minimize_button_->SetVisible(!is_maximized);
- restore_button_->SetVisible(!is_maximized);
- maximize_button_->SetVisible(!is_maximized);
+ if (is_maximized) {
+ minimize_button_->SetVisible(false);
+ restore_button_->SetVisible(false);
+ maximize_button_->SetVisible(false);
- if (browser_view_->browser()->type() == Browser::TYPE_DEVTOOLS)
- close_button_->SetVisible(true);
- else
- close_button_->SetVisible(!is_maximized);
+ if (browser_view_->browser()->type() == Browser::TYPE_DEVTOOLS) {
+ close_button_->SetVisible(true);
+ minimize_button_->SetBounds(close_button_->bounds().x(), 0, 0, 0);
+ } else {
+ close_button_->SetVisible(false);
+ // Set the bounds of the minimize button so that we don't have to change
+ // other places that rely on the bounds. Put it slightly to the right
+ // of the edge of the view, so that when we remove the spacing it lines
+ // up with the edge.
+ minimize_button_->SetBounds(width() - FrameBorderThickness(false) +
+ kNewTabCaptionMaximizedSpacing, 0, 0, 0);
+ }
- if (is_maximized) {
- // Set the bounds of the minimize button so that we don't have to change
- // other places that rely on the bounds. Put it slightly to the right
- // of the edge of the view, so that when we remove the spacing it lines
- // up with the edge.
- minimize_button_->SetBounds(
- width() - FrameBorderThickness() + kNewTabCaptionMaximizedSpacing, 0, 0,
- 0);
return;
+ } else {
+ close_button_->SetVisible(true);
}
#endif
@@ -1017,7 +982,7 @@ void OpaqueBrowserFrameView::LayoutTitleBar() {
if (d->ShouldShowWindowTitle()) {
int title_x = d->ShouldShowWindowIcon() ?
icon_bounds.right() + kIconTitleSpacing : icon_bounds.x();
- int title_height = BrowserFrame::GetTitleFont().height();
+ int title_height = BrowserFrame::GetTitleFont().GetHeight();
// We bias the title position so that when the difference between the icon
// and title heights is odd, the extra pixel of the title is above the
// vertical midline rather than below. This compensates for how the icon is
@@ -1031,50 +996,29 @@ void OpaqueBrowserFrameView::LayoutTitleBar() {
}
void OpaqueBrowserFrameView::LayoutOTRAvatar() {
- int otr_y = NonClientTopBorderHeight();
- if (!frame_->GetWindow()->IsMaximized() &&
- !frame_->GetWindow()->IsFullscreen()) {
- otr_y += kNonClientRestoredExtraThickness;
- }
- bool visible = browser_view_->ShouldShowOffTheRecordAvatar();
- gfx::Size preferred_size = otr_avatar_icon_->GetPreferredSize();
- int otr_height = 0;
- if (browser_view_->IsTabStripVisible()) {
- if (browser_view_->UseVerticalTabs()) {
- otr_height = preferred_size.height();
- otr_y = -2;
- } else {
- int tabstrip_height =
- browser_view_->GetTabStripHeight() - kOTRBottomSpacing;
- otr_height = frame_->GetWindow()->IsMaximized() ?
- (tabstrip_height - kOTRMaximizedTopSpacing) :
- preferred_size.height();
- otr_y += tabstrip_height - otr_height;
- }
+ SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon();
+ int otr_bottom, otr_restored_y;
+ if (browser_view_->UseVerticalTabs()) {
+ otr_bottom = NonClientTopBorderHeight(false, false) - kOTRBottomSpacing;
+ otr_restored_y = kFrameShadowThickness;
} else {
- visible = false;
+ otr_bottom = GetHorizontalTabStripVerticalOffset(false) +
+ browser_view_->GetTabStripHeight() - kOTRBottomSpacing;
+ otr_restored_y = otr_bottom - otr_avatar_icon.height();
}
- otr_avatar_icon_->SetVisible(visible);
- otr_avatar_icon_->SetBounds(NonClientBorderThickness() + kOTRSideSpacing,
- otr_y, preferred_size.width(), otr_height);
+ int otr_y = frame_->GetWindow()->IsMaximized() ?
+ (NonClientTopBorderHeight(false, true) + kTabstripTopShadowThickness) :
+ otr_restored_y;
+ otr_avatar_bounds_.SetRect(NonClientBorderThickness() + kOTRSideSpacing,
+ otr_y, otr_avatar_icon.width(),
+ browser_view_->ShouldShowOffTheRecordAvatar() ? (otr_bottom - otr_y) : 0);
}
gfx::Rect OpaqueBrowserFrameView::CalculateClientAreaBounds(int width,
int height) const {
- int top_height = NonClientTopBorderHeight();
+ int top_height = NonClientTopBorderHeight(false, false);
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));
}
-
-// static
-gfx::Rect OpaqueBrowserFrameView::GetViewBounds(views::View* src,
- views::View* dst) {
- gfx::Rect bounds(src->bounds());
-
- gfx::Point origin_in_dst(bounds.origin());
- View::ConvertPointToView(src->GetParent(), dst, &origin_in_dst);
- bounds.set_origin(origin_in_dst);
- return bounds;
-}
diff --git a/chrome/browser/views/frame/opaque_browser_frame_view.h b/chrome/browser/views/frame/opaque_browser_frame_view.h
index 9493bd8..483693e 100644
--- a/chrome/browser/views/frame/opaque_browser_frame_view.h
+++ b/chrome/browser/views/frame/opaque_browser_frame_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_FRAME_OPAQUE_BROWSER_FRAME_VIEW_H_
#define CHROME_BROWSER_VIEWS_FRAME_OPAQUE_BROWSER_FRAME_VIEW_H_
+#pragma once
#include "chrome/browser/views/frame/browser_frame.h"
#include "chrome/browser/views/frame/browser_non_client_frame_view.h"
@@ -32,6 +33,7 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
// Overridden from BrowserNonClientFrameView:
virtual gfx::Rect GetBoundsForTabStrip(BaseTabStrip* tabstrip) const;
+ virtual int GetHorizontalTabStripVerticalOffset(bool restored) const;
virtual void UpdateThrobber(bool running);
virtual gfx::Size GetMinimumSize();
@@ -49,10 +51,9 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
// Overridden from views::View:
virtual void Paint(gfx::Canvas* canvas);
- virtual void PaintChildren(gfx::Canvas* canvas);
virtual void Layout();
virtual bool HitTest(const gfx::Point& l) const;
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
@@ -63,8 +64,9 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
private:
// Returns the thickness of the border that makes up the window frame edges.
- // This does not include any client edge.
- int FrameBorderThickness() const;
+ // This does not include any client edge. If |restored| is true, acts as if
+ // the window is restored regardless of the real mode.
+ int FrameBorderThickness(bool restored) const;
// Returns the height of the top resize area. This is smaller than the frame
// border height in order to increase the window draggable area.
@@ -75,15 +77,20 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
int NonClientBorderThickness() const;
// Returns the height of the entire nonclient top border, including the window
- // frame, any title area, and any connected client edge.
- int NonClientTopBorderHeight() const;
+ // frame, any title area, and any connected client edge. If |restored| is
+ // true, acts as if the window is restored regardless of the real mode. If
+ // |ignore_vertical_tabs| is true, acts as if vertical tabs are off regardless
+ // of the real state.
+ int NonClientTopBorderHeight(bool restored, bool ignore_vertical_tabs) const;
- // Returns the y-coordinate of the caption buttons.
- int CaptionButtonY() const;
+ // Returns the y-coordinate of the caption buttons. If |restored| is true,
+ // acts as if the window is restored regardless of the real mode.
+ int CaptionButtonY(bool restored) const;
- // Returns the thickness of the nonclient portion of the 3D edge along the
- // bottom of the titlebar.
- int TitlebarBottomThickness() const;
+ // Returns the thickness of the 3D edge along the bottom of the titlebar. If
+ // |restored| is true, acts as if the window is restored regardless of the
+ // real mode.
+ int TitlebarBottomThickness(bool restored) const;
// Returns the size of the titlebar icon. This is used even when the icon is
// not shown, e.g. to set the titlebar height.
@@ -100,6 +107,7 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
void PaintMaximizedFrameBorder(gfx::Canvas* canvas);
void PaintTitleBar(gfx::Canvas* canvas);
void PaintToolbarBackground(gfx::Canvas* canvas);
+ void PaintOTRAvatar(gfx::Canvas* canvas);
void PaintRestoredClientEdge(gfx::Canvas* canvas);
// Layout various sub-components of this view.
@@ -110,15 +118,11 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
// Returns the bounds of the client area for the specified view size.
gfx::Rect CalculateClientAreaBounds(int width, int height) const;
- // Returns the bounds of |src| in the coordinate system of |dst|.
- // TODO(sky): promote this to view.
- static gfx::Rect GetViewBounds(views::View* src, views::View* dst);
-
// The layout rect of the title, if visible.
gfx::Rect title_bounds_;
- // Off the record avatar icon.
- views::ImageView* otr_avatar_icon_;
+ // The layout rect of the OTR avatar icon, if visible.
+ gfx::Rect otr_avatar_bounds_;
// Window controls.
views::ImageButton* minimize_button_;
diff --git a/chrome/browser/views/fullscreen_exit_bubble.cc b/chrome/browser/views/fullscreen_exit_bubble.cc
index e216bd2..4777f51 100644
--- a/chrome/browser/views/fullscreen_exit_bubble.cc
+++ b/chrome/browser/views/fullscreen_exit_bubble.cc
@@ -4,9 +4,9 @@
#include "chrome/browser/views/fullscreen_exit_bubble.h"
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "base/keyboard_codes.h"
#include "chrome/app/chrome_dll_resource.h"
#include "gfx/canvas_skia.h"
#include "grit/generated_resources.h"
@@ -49,7 +49,11 @@ FullscreenExitBubble::FullscreenExitView::FullscreenExitView(
FullscreenExitBubble* bubble,
const std::wstring& accelerator) {
link_.set_parent_owned(false);
+#if !defined(OS_CHROMEOS)
link_.SetText(l10n_util::GetStringF(IDS_EXIT_FULLSCREEN_MODE, accelerator));
+#else
+ link_.SetText(l10n_util::GetString(IDS_EXIT_FULLSCREEN_MODE));
+#endif
link_.SetController(bubble);
link_.SetFont(ResourceBundle::GetSharedInstance().GetFont(
ResourceBundle::LargeFont));
@@ -138,7 +142,7 @@ FullscreenExitBubble::FullscreenExitBubble(
size_animation_->Reset(1);
// Create the contents view.
- views::Accelerator accelerator(base::VKEY_UNKNOWN, false, false, false);
+ views::Accelerator accelerator(app::VKEY_UNKNOWN, false, false, false);
bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator);
DCHECK(got_accelerator);
view_ = new FullscreenExitView(this, accelerator.GetShortcutText());
diff --git a/chrome/browser/views/fullscreen_exit_bubble.h b/chrome/browser/views/fullscreen_exit_bubble.h
index c9db5bb..c2ebd5a 100644
--- a/chrome/browser/views/fullscreen_exit_bubble.h
+++ b/chrome/browser/views/fullscreen_exit_bubble.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_FULLSCREEN_EXIT_BUBBLE_H__
#define CHROME_BROWSER_VIEWS_FULLSCREEN_EXIT_BUBBLE_H__
+#pragma once
#include "app/slide_animation.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/views/generic_info_view.h b/chrome/browser/views/generic_info_view.h
index f237e57..4c0318c 100644
--- a/chrome/browser/views/generic_info_view.h
+++ b/chrome/browser/views/generic_info_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_GENERIC_INFO_VIEW_H_
#define CHROME_BROWSER_VIEWS_GENERIC_INFO_VIEW_H_
+#pragma once
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/views/generic_info_view_unittest.cc b/chrome/browser/views/generic_info_view_unittest.cc
index ca0a030..2fa0e9d 100644
--- a/chrome/browser/views/generic_info_view_unittest.cc
+++ b/chrome/browser/views/generic_info_view_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/views/generic_info_view.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/views/html_dialog_view.cc b/chrome/browser/views/html_dialog_view.cc
index 0da1cf9..d2f4c04 100644
--- a/chrome/browser/views/html_dialog_view.cc
+++ b/chrome/browser/views/html_dialog_view.cc
@@ -4,13 +4,18 @@
#include "chrome/browser/views/html_dialog_view.h"
-#include "base/keyboard_codes.h"
+#include "app/keyboard_codes.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/native_web_keyboard_event.h"
#include "views/widget/root_view.h"
#include "views/widget/widget.h"
#include "views/window/window.h"
+#if defined(OS_LINUX)
+#include "views/window/window_gtk.h"
+#endif
+
namespace browser {
// Declared in browser_dialogs.h so that others don't need to depend on our .h.
@@ -50,7 +55,7 @@ gfx::Size HtmlDialogView::GetPreferredSize() {
bool HtmlDialogView::AcceleratorPressed(const views::Accelerator& accelerator) {
// Pressing ESC closes the dialog.
- DCHECK_EQ(base::VKEY_ESCAPE, accelerator.GetKeyCode());
+ DCHECK_EQ(app::VKEY_ESCAPE, accelerator.GetKeyCode());
OnDialogClosed(std::string());
return true;
}
@@ -129,10 +134,12 @@ std::string HtmlDialogView::GetDialogArgs() const {
}
void HtmlDialogView::OnDialogClosed(const std::string& json_retval) {
- HtmlDialogUIDelegate* dialog_delegate = delegate_;
- delegate_ = NULL; // We will not communicate further with the delegate.
HtmlDialogTabContentsDelegate::Detach();
- dialog_delegate->OnDialogClosed(json_retval);
+ if (delegate_) {
+ HtmlDialogUIDelegate* dialog_delegate = delegate_;
+ delegate_ = NULL; // We will not communicate further with the delegate.
+ dialog_delegate->OnDialogClosed(json_retval);
+ }
window()->Close();
}
@@ -165,6 +172,10 @@ void HtmlDialogView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
// This allows stuff like F10, etc to work correctly.
DefWindowProc(event.os_event.hwnd, event.os_event.message,
event.os_event.wParam, event.os_event.lParam);
+#elif defined(OS_LINUX)
+ views::WindowGtk* window_gtk = static_cast<views::WindowGtk*>(window());
+ if (event.os_event && !event.skip_in_browser)
+ window_gtk->HandleKeyboardEvent(event.os_event);
#endif
}
@@ -190,7 +201,7 @@ void HtmlDialogView::InitDialog() {
this);
// Pressing the ESC key will close the dialog.
- AddAccelerator(views::Accelerator(base::VKEY_ESCAPE, false, false, false));
+ AddAccelerator(views::Accelerator(app::VKEY_ESCAPE, false, false, false));
DOMView::LoadURL(GetDialogContentURL());
}
diff --git a/chrome/browser/views/html_dialog_view.h b/chrome/browser/views/html_dialog_view.h
index e7d0275..9c05291 100644
--- a/chrome/browser/views/html_dialog_view.h
+++ b/chrome/browser/views/html_dialog_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_HTML_DIALOG_VIEW_H_
#define CHROME_BROWSER_VIEWS_HTML_DIALOG_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/hung_renderer_view.cc b/chrome/browser/views/hung_renderer_view.cc
index 7d0e44b..775623e 100644
--- a/chrome/browser/views/hung_renderer_view.cc
+++ b/chrome/browser/views/hung_renderer_view.cc
@@ -7,6 +7,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -266,7 +267,7 @@ void HungRendererDialogView::EndForTabContents(TabContents* contents) {
// HungRendererDialogView, views::DialogDelegate implementation:
std::wstring HungRendererDialogView::GetWindowTitle() const {
- return l10n_util::GetString(IDS_PRODUCT_NAME);
+ return l10n_util::GetString(IDS_BROWSER_HANGMONITOR_RENDERER_TITLE);
}
void HungRendererDialogView::WindowClosing() {
@@ -317,9 +318,11 @@ views::View* HungRendererDialogView::GetContentsView() {
void HungRendererDialogView::ButtonPressed(
views::Button* sender, const views::Event& event) {
if (sender == kill_button_) {
- // Kill the process.
- TerminateProcess(contents_->GetRenderProcessHost()->GetHandle(),
- ResultCodes::HUNG);
+ if (contents_ && contents_->GetRenderProcessHost()) {
+ // Kill the process.
+ TerminateProcess(contents_->GetRenderProcessHost()->GetHandle(),
+ ResultCodes::HUNG);
+ }
}
}
diff --git a/chrome/browser/views/importer_lock_view.cc b/chrome/browser/views/importer_lock_view.cc
index 11d08b3..8fc1c9a 100644
--- a/chrome/browser/views/importer_lock_view.cc
+++ b/chrome/browser/views/importer_lock_view.cc
@@ -54,7 +54,7 @@ std::wstring ImporterLockView::GetDialogButtonLabel(
}
bool ImporterLockView::IsModal() const {
- return true;
+ return false;
}
std::wstring ImporterLockView::GetWindowTitle() const {
diff --git a/chrome/browser/views/importer_lock_view.h b/chrome/browser/views/importer_lock_view.h
index 866d96e..d974f38 100644
--- a/chrome/browser/views/importer_lock_view.h
+++ b/chrome/browser/views/importer_lock_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_IMPORTER_LOCK_VIEW_H__
#define CHROME_BROWSER_VIEWS_IMPORTER_LOCK_VIEW_H__
+#pragma once
#include "views/view.h"
#include "views/window/dialog_delegate.h"
diff --git a/chrome/browser/views/importer_view.cc b/chrome/browser/views/importer_view.cc
index 151badf..4ef686f 100644
--- a/chrome/browser/views/importer_view.cc
+++ b/chrome/browser/views/importer_view.cc
@@ -5,6 +5,8 @@
#include "chrome/browser/views/importer_view.h"
#include "app/l10n_util.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/importer/importer_data_types.h"
@@ -183,9 +185,9 @@ int ImporterView::GetItemCount() {
return item_count;
}
-std::wstring ImporterView::GetItemAt(int index) {
+string16 ImporterView::GetItemAt(int index) {
DCHECK(importer_host_.get());
- return importer_host_->GetSourceProfileNameAt(index);
+ return WideToUTF16Hack(importer_host_->GetSourceProfileNameAt(index));
}
void ImporterView::ItemChanged(views::Combobox* combobox,
diff --git a/chrome/browser/views/importer_view.h b/chrome/browser/views/importer_view.h
index ae62820..51044e5 100644
--- a/chrome/browser/views/importer_view.h
+++ b/chrome/browser/views/importer_view.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_VIEWS_IMPORTER_VIEW_H_
#define CHROME_BROWSER_VIEWS_IMPORTER_VIEW_H_
+#pragma once
#include "app/combobox_model.h"
+#include "base/string16.h"
#include "chrome/browser/importer/importer.h"
#include "views/controls/button/native_button.h"
#include "views/controls/combobox/combobox.h"
@@ -55,7 +57,7 @@ class ImporterView : public views::View,
// Overridden from ComboboxModel:
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
// Overridden from ChromeViews::Combobox::Listener:
virtual void ItemChanged(views::Combobox* combobox,
diff --git a/chrome/browser/views/importing_progress_view.cc b/chrome/browser/views/importing_progress_view.cc
index 70e71f0..f3c2627 100644
--- a/chrome/browser/views/importing_progress_view.cc
+++ b/chrome/browser/views/importing_progress_view.cc
@@ -303,9 +303,7 @@ void StartImportingWithUI(HWND parent_window,
views::Window* window =
views::Window::CreateChromeWindow(parent_window, gfx::Rect(), v);
- // In headless mode it means that we don't show the progress window, but it
- // still need it to exist. No user interaction will be required.
- if (!coordinator->is_headless())
+ if (!coordinator->is_headless() && !first_run)
window->Show();
coordinator->StartImportSettings(source_profile, target_profile, items,
diff --git a/chrome/browser/views/importing_progress_view.h b/chrome/browser/views/importing_progress_view.h
index 5f70eb1..ec842e7 100644
--- a/chrome/browser/views/importing_progress_view.h
+++ b/chrome/browser/views/importing_progress_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_IMPORTING_PROGRESS_VIEW_H_
#define CHROME_BROWSER_VIEWS_IMPORTING_PROGRESS_VIEW_H_
+#pragma once
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/importer/importer_data_types.h"
diff --git a/chrome/browser/views/info_bubble.cc b/chrome/browser/views/info_bubble.cc
index 48b7626..3ee1317 100644
--- a/chrome/browser/views/info_bubble.cc
+++ b/chrome/browser/views/info_bubble.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/views/info_bubble.h"
-#include "base/keyboard_codes.h"
+#include "app/keyboard_codes.h"
#include "chrome/browser/window_sizer.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas_skia.h"
@@ -426,7 +426,7 @@ void InfoBubble::Init(views::Widget* parent,
// Register the Escape accelerator for closing.
GetFocusManager()->RegisterAccelerator(
- views::Accelerator(base::VKEY_ESCAPE, false, false, false), this);
+ views::Accelerator(app::VKEY_ESCAPE, false, false, false), this);
// Done creating the bubble.
NotificationService::current()->Notify(NotificationType::INFO_BUBBLE_CREATED,
@@ -491,7 +491,7 @@ void InfoBubble::DoClose(bool closed_by_escape) {
return;
GetFocusManager()->UnregisterAccelerator(
- views::Accelerator(base::VKEY_ESCAPE, false, false, false), this);
+ views::Accelerator(app::VKEY_ESCAPE, false, false, false), this);
if (delegate_)
delegate_->InfoBubbleClosing(this, closed_by_escape);
show_status_ = kClosed;
diff --git a/chrome/browser/views/info_bubble.h b/chrome/browser/views/info_bubble.h
index 30b3719..52bffe4 100644
--- a/chrome/browser/views/info_bubble.h
+++ b/chrome/browser/views/info_bubble.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_INFO_BUBBLE_H_
#define CHROME_BROWSER_VIEWS_INFO_BUBBLE_H_
+#pragma once
#include "app/slide_animation.h"
#include "third_party/skia/include/core/SkColor.h"
diff --git a/chrome/browser/views/infobars/after_translate_infobar.cc b/chrome/browser/views/infobars/after_translate_infobar.cc
index 95c73bd..63b6c8a 100644
--- a/chrome/browser/views/infobars/after_translate_infobar.cc
+++ b/chrome/browser/views/infobars/after_translate_infobar.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/views/infobars/after_translate_infobar.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/translate/options_menu_model.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
diff --git a/chrome/browser/views/infobars/after_translate_infobar.h b/chrome/browser/views/infobars/after_translate_infobar.h
index 7144e1b..1b94ec8 100644
--- a/chrome/browser/views/infobars/after_translate_infobar.h
+++ b/chrome/browser/views/infobars/after_translate_infobar.h
@@ -4,10 +4,8 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_AFTER_TRANSLATE_INFOBAR_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_AFTER_TRANSLATE_INFOBAR_H_
+#pragma once
-#include <string>
-
-#include "app/menus/simple_menu_model.h"
#include "chrome/browser/translate/languages_menu_model.h"
#include "chrome/browser/translate/options_menu_model.h"
#include "chrome/browser/translate/translate_infobar_view.h"
@@ -24,9 +22,8 @@ class Menu2;
class MenuButton;
}
-class AfterTranslateInfoBar :
- public TranslateInfoBarBase,
- public views::ViewMenuDelegate {
+class AfterTranslateInfoBar : public TranslateInfoBarBase,
+ public views::ViewMenuDelegate {
public:
explicit AfterTranslateInfoBar(TranslateInfoBarDelegate* delegate);
virtual ~AfterTranslateInfoBar();
diff --git a/chrome/browser/views/infobars/before_translate_infobar.cc b/chrome/browser/views/infobars/before_translate_infobar.cc
index 12c2907..f4d636a 100644
--- a/chrome/browser/views/infobars/before_translate_infobar.cc
+++ b/chrome/browser/views/infobars/before_translate_infobar.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/views/infobars/before_translate_infobar.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/translate/options_menu_model.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
diff --git a/chrome/browser/views/infobars/before_translate_infobar.h b/chrome/browser/views/infobars/before_translate_infobar.h
index c233626..7ac6208 100644
--- a/chrome/browser/views/infobars/before_translate_infobar.h
+++ b/chrome/browser/views/infobars/before_translate_infobar.h
@@ -4,10 +4,8 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_BEFORE_TRANSLATE_INFOBAR_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_BEFORE_TRANSLATE_INFOBAR_H_
+#pragma once
-#include <string>
-
-#include "app/menus/simple_menu_model.h"
#include "chrome/browser/translate/languages_menu_model.h"
#include "chrome/browser/translate/options_menu_model.h"
#include "chrome/browser/translate/translate_infobar_view.h"
diff --git a/chrome/browser/views/infobars/extension_infobar.cc b/chrome/browser/views/infobars/extension_infobar.cc
index f3e6dd3..441a95e 100644
--- a/chrome/browser/views/infobars/extension_infobar.cc
+++ b/chrome/browser/views/infobars/extension_infobar.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/platform_util.h"
#include "chrome/browser/views/frame/browser_view.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"
@@ -67,7 +68,7 @@ ExtensionInfoBar::~ExtensionInfoBar() {
void ExtensionInfoBar::OnExtensionPreferredSizeChanged(ExtensionView* view) {
DCHECK(view == delegate_->extension_host()->view());
-
+
// When the infobar is closed, it animates to 0 vertical height. We'll
// continue to get size changed notifications from the ExtensionView, but we
// need to ignore them otherwise we'll try to re-animate open (and leak the
@@ -163,14 +164,14 @@ void ExtensionInfoBar::SetupIconAndMenu() {
menu_->SetVisible(false);
AddChildView(menu_);
- ExtensionResource icon_resource;
Extension* extension = delegate_->extension_host()->extension();
- Extension::Icons size =
- extension->GetIconPathAllowLargerSize(&icon_resource,
- Extension::EXTENSION_ICON_BITTY);
+ ExtensionResource icon_resource = extension->GetIconResource(
+ Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_EXACTLY);
if (!icon_resource.relative_path().empty()) {
// Create a tracker to load the image. It will report back on OnImageLoaded.
- tracker_.LoadImage(extension, icon_resource, gfx::Size(size, size),
+ tracker_.LoadImage(extension, icon_resource,
+ gfx::Size(Extension::EXTENSION_ICON_BITTY,
+ Extension::EXTENSION_ICON_BITTY),
ImageLoadingTracker::DONT_CACHE);
} else {
OnImageLoaded(NULL, icon_resource, 0); // |image|, |index|.
diff --git a/chrome/browser/views/infobars/extension_infobar.h b/chrome/browser/views/infobars/extension_infobar.h
index 9b9b987..b4bab7e 100644
--- a/chrome/browser/views/infobars/extension_infobar.h
+++ b/chrome/browser/views/infobars/extension_infobar.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_EXTENSION_INFOBAR_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_EXTENSION_INFOBAR_H_
+#pragma once
#include "chrome/browser/views/infobars/infobars.h"
@@ -31,7 +32,7 @@ class ExtensionInfoBar : public InfoBar,
virtual ~ExtensionInfoBar();
// Overridden from ExtensionView::Container:
- virtual void OnExtensionMouseEvent(ExtensionView* view) {}
+ virtual void OnExtensionMouseMove(ExtensionView* view) {}
virtual void OnExtensionMouseLeave(ExtensionView* view) {}
virtual void OnExtensionPreferredSizeChanged(ExtensionView* view);
diff --git a/chrome/browser/views/infobars/infobar_button_border.cc b/chrome/browser/views/infobars/infobar_button_border.cc
index 7a0ad9d..ed65885 100644
--- a/chrome/browser/views/infobars/infobar_button_border.cc
+++ b/chrome/browser/views/infobars/infobar_button_border.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/views/infobars/infobar_button_border.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "gfx/canvas.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/views/infobars/infobar_button_border.h b/chrome/browser/views/infobars/infobar_button_border.h
index 303fc4b..865e4f8 100644
--- a/chrome/browser/views/infobars/infobar_button_border.h
+++ b/chrome/browser/views/infobars/infobar_button_border.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_BUTTON_BORDER_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_BUTTON_BORDER_H_
+#pragma once
#include "views/border.h"
diff --git a/chrome/browser/views/infobars/infobar_container.cc b/chrome/browser/views/infobars/infobar_container.cc
index 4301132..5779fde 100644
--- a/chrome/browser/views/infobars/infobar_container.cc
+++ b/chrome/browser/views/infobars/infobar_container.cc
@@ -78,11 +78,8 @@ void InfoBarContainer::Layout() {
}
}
-bool InfoBarContainer::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+AccessibilityTypes::Role InfoBarContainer::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
void InfoBarContainer::ViewHierarchyChanged(bool is_add,
diff --git a/chrome/browser/views/infobars/infobar_container.h b/chrome/browser/views/infobars/infobar_container.h
index 7480c7b..8efa6b5 100644
--- a/chrome/browser/views/infobars/infobar_container.h
+++ b/chrome/browser/views/infobars/infobar_container.h
@@ -4,7 +4,9 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_CONTAINER_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_CONTAINER_H_
+#pragma once
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "views/view.h"
@@ -44,7 +46,7 @@ class InfoBarContainer : public views::View,
// Overridden from views::View:
virtual gfx::Size GetPreferredSize();
virtual void Layout();
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
protected:
virtual void ViewHierarchyChanged(bool is_add,
diff --git a/chrome/browser/views/infobars/infobar_text_button.h b/chrome/browser/views/infobars/infobar_text_button.h
index 221b5de..35f16a1 100644
--- a/chrome/browser/views/infobars/infobar_text_button.h
+++ b/chrome/browser/views/infobars/infobar_text_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_TEXT_BUTTON_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_INFOBAR_TEXT_BUTTON_H_
+#pragma once
#include "views/controls/button/text_button.h"
diff --git a/chrome/browser/views/infobars/infobars.cc b/chrome/browser/views/infobars/infobars.cc
index b36e183..c96f72f 100644
--- a/chrome/browser/views/infobars/infobars.cc
+++ b/chrome/browser/views/infobars/infobars.cc
@@ -11,6 +11,7 @@
#include "app/win_util.h"
#endif // defined(OS_WIN)
#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/views/event_utils.h"
#include "chrome/browser/views/infobars/infobar_container.h"
#include "gfx/canvas.h"
@@ -33,17 +34,10 @@ const int InfoBar::kEndOfLabelSpacing = 16;
const int InfoBar::kCloseButtonSpacing = 12;
const int InfoBar::kButtonInLabelSpacing = 5;
-static const SkColor kInfoBackgroundColorTop = SkColorSetRGB(170, 214, 112);
-static const SkColor kInfoBackgroundColorBottom = SkColorSetRGB(146, 205, 114);
-
static const SkColor kWarningBackgroundColorTop = SkColorSetRGB(255, 242, 183);
static const SkColor kWarningBackgroundColorBottom =
SkColorSetRGB(250, 230, 145);
-static const SkColor kErrorBackgroundColorTop = kWarningBackgroundColorTop;
-static const SkColor kErrorBackgroundColorBottom =
- kWarningBackgroundColorBottom;
-
static const SkColor kPageActionBackgroundColorTop =
SkColorSetRGB(218, 231, 249);
static const SkColor kPageActionBackgroundColorBottom =
@@ -57,18 +51,10 @@ InfoBarBackground::InfoBarBackground(InfoBarDelegate::Type infobar_type) {
SkColor top_color;
SkColor bottom_color;
switch (infobar_type) {
- case InfoBarDelegate::INFO_TYPE:
- top_color = kInfoBackgroundColorTop;
- bottom_color = kInfoBackgroundColorBottom;
- break;
case InfoBarDelegate::WARNING_TYPE:
top_color = kWarningBackgroundColorTop;
bottom_color = kWarningBackgroundColorBottom;
break;
- case InfoBarDelegate::ERROR_TYPE:
- top_color = kErrorBackgroundColorTop;
- bottom_color = kErrorBackgroundColorBottom;
- break;
case InfoBarDelegate::PAGE_ACTION_TYPE:
top_color = kPageActionBackgroundColorTop;
bottom_color = kPageActionBackgroundColorBottom;
@@ -108,15 +94,9 @@ InfoBar::InfoBar(InfoBarDelegate* delegate)
set_background(new InfoBarBackground(delegate->GetInfoBarType()));
switch (delegate->GetInfoBarType()) {
- case InfoBarDelegate::INFO_TYPE:
- SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_INFOBAR_INFO));
- break;
case InfoBarDelegate::WARNING_TYPE:
SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_INFOBAR_WARNING));
break;
- case InfoBarDelegate::ERROR_TYPE:
- SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_INFOBAR_ERROR));
- break;
case InfoBarDelegate::PAGE_ACTION_TYPE:
SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_INFOBAR_PAGE_ACTION));
break;
@@ -144,11 +124,8 @@ InfoBar::~InfoBar() {
// InfoBar, views::View overrides: ---------------------------------------------
-bool InfoBar::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_PANE;
- return true;
+AccessibilityTypes::Role InfoBar::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_ALERT;
}
gfx::Size InfoBar::GetPreferredSize() {
@@ -172,6 +149,19 @@ void InfoBar::ViewHierarchyChanged(bool is_add, views::View* parent,
InfoBarRemoved();
}
}
+
+ if (GetWidget() && GetWidget()->IsAccessibleWidget()) {
+ // For accessibility, make the close button the last child view.
+ if (parent == this && child != close_button_ &&
+ HasChildView(close_button_) &&
+ GetChildViewAt(GetChildViewCount() - 1) != close_button_) {
+ RemoveChildView(close_button_);
+ AddChildView(close_button_);
+ }
+
+ // Allow screen reader users to focus the close button.
+ close_button_->SetFocusable(true);
+ }
}
// InfoBar, protected: ---------------------------------------------------------
@@ -205,6 +195,17 @@ void InfoBar::ButtonPressed(views::Button* sender, const views::Event& event) {
}
}
+// InfoBar, views::FocusChangeListener implementation: ------------------
+
+void InfoBar::FocusWillChange(View* focused_before, View* focused_now) {
+ // This will trigger some screen readers to read the entire contents of this
+ // infobar.
+ if (focused_before && focused_now &&
+ !this->IsParentOf(focused_before) && this->IsParentOf(focused_now)) {
+ NotifyAccessibilityEvent(AccessibilityTypes::EVENT_ALERT);
+ }
+}
+
// InfoBar, AnimationDelegate implementation: ----------------------------------
void InfoBar::AnimationProgressed(const Animation* animation) {
@@ -273,6 +274,11 @@ void InfoBar::InfoBarAdded() {
GetFocusManager()));
}
#endif
+
+ if (GetFocusManager())
+ GetFocusManager()->AddFocusChangeListener(this);
+
+ NotifyAccessibilityEvent(AccessibilityTypes::EVENT_ALERT);
}
void InfoBar::InfoBarRemoved() {
@@ -285,6 +291,9 @@ void InfoBar::InfoBarRemoved() {
// since no-one refers to us now.
MessageLoop::current()->PostTask(FROM_HERE,
delete_factory_.NewRunnableMethod(&InfoBar::DeleteSelf));
+
+ if (GetFocusManager())
+ GetFocusManager()->RemoveFocusChangeListener(this);
}
void InfoBar::DestroyFocusTracker(bool restore_focus) {
@@ -305,7 +314,7 @@ void InfoBar::DeleteSelf() {
AlertInfoBar::AlertInfoBar(AlertInfoBarDelegate* delegate)
: InfoBar(delegate) {
label_ = new views::Label(
- delegate->GetMessageText(),
+ UTF16ToWideHack(delegate->GetMessageText()),
ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont));
label_->SetColor(SK_ColorBLACK);
label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
@@ -360,12 +369,12 @@ LinkInfoBar::LinkInfoBar(LinkInfoBarDelegate* delegate)
// Set up the labels.
size_t offset;
- std::wstring message_text = delegate->GetMessageTextWithOffset(&offset);
- if (offset != std::wstring::npos) {
- label_1_->SetText(message_text.substr(0, offset));
- label_2_->SetText(message_text.substr(offset));
+ string16 message_text = delegate->GetMessageTextWithOffset(&offset);
+ if (offset != string16::npos) {
+ label_1_->SetText(UTF16ToWideHack(message_text.substr(0, offset)));
+ label_2_->SetText(UTF16ToWideHack(message_text.substr(offset)));
} else {
- label_1_->SetText(message_text);
+ label_1_->SetText(UTF16ToWideHack(message_text));
}
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
label_1_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
@@ -378,7 +387,7 @@ LinkInfoBar::LinkInfoBar(LinkInfoBarDelegate* delegate)
AddChildView(label_2_);
// Set up the link.
- link_->SetText(delegate->GetLinkText());
+ link_->SetText(UTF16ToWideHack(delegate->GetLinkText()));
link_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
link_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
link_->SetController(this);
@@ -456,20 +465,22 @@ ConfirmInfoBar::ConfirmInfoBar(ConfirmInfoBarDelegate* delegate)
cancel_button_(NULL),
link_(NULL),
initialized_(false) {
- ok_button_ = new views::NativeButton(
- this, delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK));
+ ok_button_ = new views::NativeButton(this,
+ UTF16ToWideHack(delegate->GetButtonLabel(
+ ConfirmInfoBarDelegate::BUTTON_OK)));
ok_button_->SetAccessibleName(ok_button_->label());
if (delegate->GetButtons() & ConfirmInfoBarDelegate::BUTTON_OK_DEFAULT)
ok_button_->SetAppearsAsDefault(true);
if (delegate->NeedElevation(ConfirmInfoBarDelegate::BUTTON_OK))
ok_button_->SetNeedElevation(true);
cancel_button_ = new views::NativeButton(
- this, delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL));
+ this, UTF16ToWideHack(
+ delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL)));
cancel_button_->SetAccessibleName(cancel_button_->label());
// Set up the link.
link_ = new views::Link;
- link_->SetText(delegate->GetLinkText());
+ link_->SetText(UTF16ToWideHack(delegate->GetLinkText()));
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
link_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
link_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
@@ -545,11 +556,11 @@ void ConfirmInfoBar::Layout() {
void ConfirmInfoBar::ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) {
- InfoBar::ViewHierarchyChanged(is_add, parent, child);
if (is_add && child == this && !initialized_) {
Init();
initialized_ = true;
}
+ InfoBar::ViewHierarchyChanged(is_add, parent, child);
}
// ConfirmInfoBar, views::ButtonListener implementation: ---------------
diff --git a/chrome/browser/views/infobars/infobars.h b/chrome/browser/views/infobars/infobars.h
index a494beb..ec270d5 100644
--- a/chrome/browser/views/infobars/infobars.h
+++ b/chrome/browser/views/infobars/infobars.h
@@ -4,12 +4,14 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_INFOBARS_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_INFOBARS_H_
+#pragma once
#include "app/animation.h"
#include "base/task.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "views/controls/button/button.h"
#include "views/controls/link.h"
+#include "views/focus/focus_manager.h"
class InfoBarContainer;
class SlideAnimation;
@@ -40,6 +42,7 @@ class InfoBarBackground : public views::Background {
class InfoBar : public views::View,
public views::ButtonListener,
+ public views::FocusChangeListener,
public AnimationDelegate {
public:
explicit InfoBar(InfoBarDelegate* delegate);
@@ -63,7 +66,7 @@ class InfoBar : public views::View,
static const int kButtonInLabelSpacing;
// Overridden from views::View:
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual gfx::Size GetPreferredSize();
virtual void Layout();
@@ -98,6 +101,9 @@ class InfoBar : public views::View,
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+ // Overridden from views::FocusChangeListener:
+ virtual void FocusWillChange(View* focused_before, View* focused_now);
+
// Overridden from AnimationDelegate:
virtual void AnimationProgressed(const Animation* animation);
virtual void AnimationEnded(const Animation* animation);
diff --git a/chrome/browser/views/infobars/translate_infobar_base.cc b/chrome/browser/views/infobars/translate_infobar_base.cc
index 50c7120..4eb0bdd 100644
--- a/chrome/browser/views/infobars/translate_infobar_base.cc
+++ b/chrome/browser/views/infobars/translate_infobar_base.cc
@@ -21,7 +21,7 @@ TranslateInfoBarBase::TranslateInfoBarBase(
TranslateInfoBarDelegate* delegate)
: InfoBar(delegate),
normal_background_(InfoBarDelegate::PAGE_ACTION_TYPE),
- error_background_(InfoBarDelegate::ERROR_TYPE) {
+ error_background_(InfoBarDelegate::WARNING_TYPE) {
icon_ = new views::ImageView;
SkBitmap* image = delegate->GetIcon();
if (image)
diff --git a/chrome/browser/views/infobars/translate_infobar_base.h b/chrome/browser/views/infobars/translate_infobar_base.h
index 173742d..a16d1ca 100644
--- a/chrome/browser/views/infobars/translate_infobar_base.h
+++ b/chrome/browser/views/infobars/translate_infobar_base.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_TRANSLATE_INFOBAR_BASE_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_TRANSLATE_INFOBAR_BASE_H_
+#pragma once
#include "chrome/browser/translate/translate_infobar_view.h"
#include "chrome/browser/views/infobars/infobars.h"
diff --git a/chrome/browser/views/infobars/translate_message_infobar.h b/chrome/browser/views/infobars/translate_message_infobar.h
index f4cb896..e77bcf2 100644
--- a/chrome/browser/views/infobars/translate_message_infobar.h
+++ b/chrome/browser/views/infobars/translate_message_infobar.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_INFOBARS_TRANSLATE_MESSAGE_INFOBAR_H_
#define CHROME_BROWSER_VIEWS_INFOBARS_TRANSLATE_MESSAGE_INFOBAR_H_
+#pragma once
#include "chrome/browser/views/infobars/translate_infobar_base.h"
diff --git a/chrome/browser/views/jsmessage_box_dialog.cc b/chrome/browser/views/jsmessage_box_dialog.cc
deleted file mode 100644
index 5d8049a..0000000
--- a/chrome/browser/views/jsmessage_box_dialog.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 "chrome/browser/views/jsmessage_box_dialog.h"
-
-#include "app/l10n_util.h"
-#include "app/message_box_flags.h"
-#include "base/keyboard_codes.h"
-#include "chrome/browser/app_modal_dialog.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "grit/generated_resources.h"
-#include "views/controls/message_box_view.h"
-#include "views/window/window.h"
-
-JavaScriptMessageBoxDialog::JavaScriptMessageBoxDialog(
- JavaScriptAppModalDialog* parent,
- const std::wstring& message_text,
- const std::wstring& default_prompt_text,
- bool display_suppress_checkbox)
- : parent_(parent),
- message_box_view_(new MessageBoxView(
- parent->dialog_flags() | MessageBoxFlags::kAutoDetectAlignment,
- message_text, default_prompt_text)) {
- DCHECK(message_box_view_);
-
- message_box_view_->AddAccelerator(
- views::Accelerator(base::VKEY_C, false, true, false));
- if (display_suppress_checkbox) {
- message_box_view_->SetCheckBoxLabel(
- l10n_util::GetString(IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION));
- }
-}
-
-JavaScriptMessageBoxDialog::~JavaScriptMessageBoxDialog() {
-}
-
-gfx::NativeWindow JavaScriptMessageBoxDialog::GetDialogRootWindow() {
- return client()->GetMessageBoxRootWindow();
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// JavaScriptMessageBoxDialog, views::DialogDelegate implementation:
-
-int JavaScriptMessageBoxDialog::GetDefaultDialogButton() const {
- if (parent_->dialog_flags() & MessageBoxFlags::kFlagHasOKButton)
- return MessageBoxFlags::DIALOGBUTTON_OK;
-
- if (parent_->dialog_flags() & MessageBoxFlags::kFlagHasCancelButton)
- return MessageBoxFlags::DIALOGBUTTON_CANCEL;
-
- return MessageBoxFlags::DIALOGBUTTON_NONE;
-}
-
-int JavaScriptMessageBoxDialog::GetDialogButtons() const {
- int dialog_buttons = 0;
- if (parent_->dialog_flags() & MessageBoxFlags::kFlagHasOKButton)
- dialog_buttons = MessageBoxFlags::DIALOGBUTTON_OK;
-
- if (parent_->dialog_flags() & MessageBoxFlags::kFlagHasCancelButton)
- dialog_buttons |= MessageBoxFlags::DIALOGBUTTON_CANCEL;
-
- return dialog_buttons;
-}
-
-std::wstring JavaScriptMessageBoxDialog::GetWindowTitle() const {
- return parent_->title();
-}
-
-
-void JavaScriptMessageBoxDialog::WindowClosing() {
-}
-
-void JavaScriptMessageBoxDialog::DeleteDelegate() {
- delete parent_;
- delete this;
-}
-
-bool JavaScriptMessageBoxDialog::Cancel() {
- parent_->OnCancel();
- return true;
-}
-
-bool JavaScriptMessageBoxDialog::Accept() {
- parent_->OnAccept(message_box_view_->GetInputText(),
- message_box_view_->IsCheckBoxSelected());
- return true;
-}
-
-void JavaScriptMessageBoxDialog::OnClose() {
- parent_->OnClose();
-}
-
-std::wstring JavaScriptMessageBoxDialog::GetDialogButtonLabel(
- MessageBoxFlags::DialogButton button) const {
- if (parent_->is_before_unload_dialog()) {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- return l10n_util::GetString(IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
- } else if (button == MessageBoxFlags::DIALOGBUTTON_CANCEL) {
- return l10n_util::GetString(
- IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL);
- }
- }
- return DialogDelegate::GetDialogButtonLabel(button);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// JavaScriptMessageBoxDialog, views::WindowDelegate implementation:
-
-views::View* JavaScriptMessageBoxDialog::GetContentsView() {
- return message_box_view_;
-}
-
-views::View* JavaScriptMessageBoxDialog::GetInitiallyFocusedView() {
- if (message_box_view_->text_box())
- return message_box_view_->text_box();
- return views::DialogDelegate::GetInitiallyFocusedView();
-}
diff --git a/chrome/browser/views/jsmessage_box_dialog.h b/chrome/browser/views/jsmessage_box_dialog.h
deleted file mode 100644
index c142a67..0000000
--- a/chrome/browser/views/jsmessage_box_dialog.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_VIEWS_JSMESSAGE_BOX_DIALOG_H_
-#define CHROME_BROWSER_VIEWS_JSMESSAGE_BOX_DIALOG_H_
-
-#include "chrome/browser/js_modal_dialog.h"
-
-#include <string>
-
-#include "app/message_box_flags.h"
-#include "chrome/browser/jsmessage_box_client.h"
-#include "chrome/browser/views/modal_dialog_delegate.h"
-
-class MessageBoxView;
-class JavaScriptMessageBoxClient;
-
-class JavaScriptMessageBoxDialog : public ModalDialogDelegate {
- public:
- JavaScriptMessageBoxDialog(JavaScriptAppModalDialog* parent,
- const std::wstring& message_text,
- const std::wstring& default_prompt_text,
- bool display_suppress_checkbox);
-
- virtual ~JavaScriptMessageBoxDialog();
-
- // Overriden from ModalDialogDelegate:
- virtual gfx::NativeWindow GetDialogRootWindow();
-
- // Overriden from views::DialogDelegate:
- virtual int GetDefaultDialogButton() const;
- virtual int GetDialogButtons() const;
- virtual std::wstring GetWindowTitle() const;
- virtual void WindowClosing();
- virtual void DeleteDelegate();
- virtual bool Cancel();
- virtual bool Accept();
- virtual std::wstring GetDialogButtonLabel(
- MessageBoxFlags::DialogButton button) const;
-
- // Overriden from views::WindowDelegate:
- virtual bool IsModal() const { return true; }
- virtual views::View* GetContentsView();
- virtual views::View* GetInitiallyFocusedView();
- virtual void OnClose();
-
- private:
- JavaScriptMessageBoxClient* client() {
- return parent_->client();
- }
-
- // A pointer to the AppModalDialog that owns us.
- JavaScriptAppModalDialog* parent_;
-
- // The message box view whose commands we handle.
- MessageBoxView* message_box_view_;
-
- DISALLOW_COPY_AND_ASSIGN(JavaScriptMessageBoxDialog);
-};
-
-#endif // CHROME_BROWSER_VIEWS_JSMESSAGE_BOX_DIALOG_H_
diff --git a/chrome/browser/views/keyword_editor_view.cc b/chrome/browser/views/keyword_editor_view.cc
index e40a704..b3b4974 100644
--- a/chrome/browser/views/keyword_editor_view.cc
+++ b/chrome/browser/views/keyword_editor_view.cc
@@ -9,7 +9,8 @@
#include "app/l10n_util.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
-#include "chrome/browser/pref_service.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
@@ -100,8 +101,8 @@ KeywordEditorView::~KeywordEditorView() {
}
void KeywordEditorView::OnEditedKeyword(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url) {
if (template_url) {
controller_->ModifyTemplateURL(template_url, title, keyword, url);
@@ -129,7 +130,7 @@ std::wstring KeywordEditorView::GetWindowTitle() const {
}
std::wstring KeywordEditorView::GetWindowName() const {
- return prefs::kKeywordEditorWindowPlacement;
+ return UTF8ToWide(prefs::kKeywordEditorWindowPlacement);
}
int KeywordEditorView::GetDialogButtons() const {
@@ -168,7 +169,7 @@ void KeywordEditorView::Init() {
this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_NEW_BUTTON));
add_button_->SetEnabled(controller_->loaded());
add_button_->AddAccelerator(
- views::Accelerator(base::VKEY_A, false, false, true));
+ views::Accelerator(app::VKEY_A, false, false, true));
add_button_->SetAccessibleKeyboardShortcut(L"A");
edit_button_ = new views::NativeButton(
@@ -179,7 +180,7 @@ void KeywordEditorView::Init() {
this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_REMOVE_BUTTON));
remove_button_->SetEnabled(false);
remove_button_->AddAccelerator(
- views::Accelerator(base::VKEY_R, false, false, true));
+ views::Accelerator(app::VKEY_R, false, false, true));
remove_button_->SetAccessibleKeyboardShortcut(L"R");
make_default_button_ = new views::NativeButton(
diff --git a/chrome/browser/views/keyword_editor_view.h b/chrome/browser/views/keyword_editor_view.h
index 34cd39b..b4e7736 100644
--- a/chrome/browser/views/keyword_editor_view.h
+++ b/chrome/browser/views/keyword_editor_view.h
@@ -4,14 +4,14 @@
#ifndef CHROME_BROWSER_VIEWS_KEYWORD_EDITOR_VIEW_H_
#define CHROME_BROWSER_VIEWS_KEYWORD_EDITOR_VIEW_H_
+#pragma once
#include <Windows.h>
-#include <map>
-#include "app/table_model.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.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
#include "views/controls/button/button.h"
#include "views/controls/table/table_view_observer.h"
#include "views/view.h"
@@ -28,8 +28,7 @@ class BorderView;
class SearchEngineSelectionObserver;
class SkBitmap;
-class TemplateURLModel;
-class TemplateURLTableModel;
+class TemplateURL;
// KeywordEditorView allows the user to edit keywords.
@@ -57,8 +56,8 @@ class KeywordEditorView : public views::View,
// Overridden from EditSearchEngineControllerDelegate.
// Calls AddTemplateURL or ModifyTemplateURL as appropriate.
virtual void OnEditedKeyword(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
+ const string16& title,
+ const string16& keyword,
const std::string& url);
// Overridden to invoke Layout.
diff --git a/chrome/browser/views/list_background.h b/chrome/browser/views/list_background.h
index 5c54f6e..4f29a34 100644
--- a/chrome/browser/views/list_background.h
+++ b/chrome/browser/views/list_background.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LIST_BACKGROUND_H_
#define CHROME_BROWSER_VIEWS_LIST_BACKGROUND_H_
+#pragma once
#include "gfx/canvas_skia.h"
#include "gfx/native_theme_win.h"
diff --git a/chrome/browser/views/local_storage_info_view.h b/chrome/browser/views/local_storage_info_view.h
index 83b6155..aa3e14f 100644
--- a/chrome/browser/views/local_storage_info_view.h
+++ b/chrome/browser/views/local_storage_info_view.h
@@ -4,9 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCAL_STORAGE_INFO_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCAL_STORAGE_INFO_VIEW_H_
-
-#include <string>
-#include <vector>
+#pragma once
#include "views/view.h"
#include "chrome/browser/browsing_data_local_storage_helper.h"
diff --git a/chrome/browser/views/local_storage_set_item_info_view.cc b/chrome/browser/views/local_storage_set_item_info_view.cc
index d2bb286..8df4de4 100644
--- a/chrome/browser/views/local_storage_set_item_info_view.cc
+++ b/chrome/browser/views/local_storage_set_item_info_view.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "app/l10n_util.h"
-#include "base/i18n/time_formatting.h"
#include "base/utf_string_conversions.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
@@ -126,4 +125,3 @@ void LocalStorageSetItemInfoView::Init() {
value_value_field_->RemoveBorder();
value_value_field_->SetBackgroundColor(text_area_background);
}
-
diff --git a/chrome/browser/views/local_storage_set_item_info_view.h b/chrome/browser/views/local_storage_set_item_info_view.h
index 7ab2118..9b555b6 100644
--- a/chrome/browser/views/local_storage_set_item_info_view.h
+++ b/chrome/browser/views/local_storage_set_item_info_view.h
@@ -4,9 +4,9 @@
#ifndef CHROME_BROWSER_VIEWS_LOCAL_STORAGE_SET_ITEM_INFO_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCAL_STORAGE_SET_ITEM_INFO_VIEW_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/string16.h"
#include "views/view.h"
diff --git a/chrome/browser/views/location_bar/click_handler.h b/chrome/browser/views/location_bar/click_handler.h
index e477e94..dc8c917 100644
--- a/chrome/browser/views/location_bar/click_handler.h
+++ b/chrome/browser/views/location_bar/click_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_CLICK_HANDLER_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_CLICK_HANDLER_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/browser/views/location_bar/content_setting_image_view.cc b/chrome/browser/views/location_bar/content_setting_image_view.cc
index fa087fa..baeed23 100644
--- a/chrome/browser/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/views/location_bar/content_setting_image_view.cc
@@ -9,7 +9,7 @@
#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/views/content_blocked_bubble_contents.h"
+#include "chrome/browser/views/content_setting_bubble_contents.h"
#include "chrome/browser/views/location_bar/location_bar_view.h"
ContentSettingImageView::ContentSettingImageView(
diff --git a/chrome/browser/views/location_bar/content_setting_image_view.h b/chrome/browser/views/location_bar/content_setting_image_view.h
index c641daa..366ed48 100644
--- a/chrome/browser/views/location_bar/content_setting_image_view.h
+++ b/chrome/browser/views/location_bar/content_setting_image_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_CONTENT_SETTING_IMAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_CONTENT_SETTING_IMAGE_VIEW_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "chrome/browser/views/info_bubble.h"
diff --git a/chrome/browser/views/location_bar/ev_bubble_view.h b/chrome/browser/views/location_bar/ev_bubble_view.h
index 4b92944..058c8a2 100644
--- a/chrome/browser/views/location_bar/ev_bubble_view.h
+++ b/chrome/browser/views/location_bar/ev_bubble_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_EV_BUBBLE_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_EV_BUBBLE_VIEW_H_
+#pragma once
#include "chrome/browser/views/location_bar/click_handler.h"
#include "chrome/browser/views/location_bar/icon_label_bubble_view.h"
diff --git a/chrome/browser/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/views/location_bar/icon_label_bubble_view.cc
index 4e92ac0..1e0159b 100644
--- a/chrome/browser/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/views/location_bar/icon_label_bubble_view.cc
@@ -10,19 +10,18 @@
#include "views/controls/image_view.h"
#include "views/controls/label.h"
-// Amount to offset the image.
-static const int kImageOffset = 1;
-
-// Amount to offset the label from the image.
-static const int kLabelOffset = 3;
+// Amount of padding at the edges of the bubble.
+static const int kBubbleOuterPadding =
+ LocationBarView::kEdgeItemPadding - LocationBarView::kBubblePadding;
// Amount of padding after the label.
-static const int kLabelPadding = 4;
+static const int kLabelPadding = 5;
IconLabelBubbleView::IconLabelBubbleView(const int background_images[],
int contained_image,
const SkColor& color)
- : background_painter_(background_images) {
+ : background_painter_(background_images),
+ item_padding_(LocationBarView::kItemPadding) {
image_ = new views::ImageView();
AddChildView(image_);
image_->SetImage(
@@ -48,10 +47,7 @@ void IconLabelBubbleView::SetImage(const SkBitmap& bitmap) {
}
void IconLabelBubbleView::Paint(gfx::Canvas* canvas) {
- int y_offset = (GetParent()->height() - height()) / 2;
- canvas->TranslateInt(0, y_offset);
background_painter_.Paint(width(), height(), canvas);
- canvas->TranslateInt(0, -y_offset);
}
gfx::Size IconLabelBubbleView::GetPreferredSize() {
@@ -61,12 +57,12 @@ gfx::Size IconLabelBubbleView::GetPreferredSize() {
}
void IconLabelBubbleView::Layout() {
- image_->SetBounds(kImageOffset, 0, image_->GetPreferredSize().width(),
+ image_->SetBounds(kBubbleOuterPadding, 0, image_->GetPreferredSize().width(),
height());
const int label_height = label_->GetPreferredSize().height();
- label_->SetBounds(image_->x() + image_->width() + kLabelOffset,
- (height() - label_height) / 2, width() - GetNonLabelWidth(),
- label_height);
+ label_->SetBounds(image_->x() + image_->width() +
+ item_padding_ , (height() - label_height) / 2,
+ width() - GetNonLabelWidth(), label_height);
}
void IconLabelBubbleView::SetElideInMiddle(bool elide_in_middle) {
@@ -78,6 +74,6 @@ gfx::Size IconLabelBubbleView::GetNonLabelSize() {
}
int IconLabelBubbleView::GetNonLabelWidth() {
- return kImageOffset + image_->GetPreferredSize().width() + kLabelOffset +
- kLabelPadding;
+ return kBubbleOuterPadding + image_->GetPreferredSize().width() +
+ item_padding_ + kBubbleOuterPadding;
}
diff --git a/chrome/browser/views/location_bar/icon_label_bubble_view.h b/chrome/browser/views/location_bar/icon_label_bubble_view.h
index dd5b196..d2e4b78 100644
--- a/chrome/browser/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/views/location_bar/icon_label_bubble_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_ICON_LABEL_BUBBLE_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_ICON_LABEL_BUBBLE_VIEW_H_
+#pragma once
#include <string>
@@ -35,6 +36,7 @@ class IconLabelBubbleView : public views::View {
void SetFont(const gfx::Font& font);
void SetLabel(const std::wstring& label);
void SetImage(const SkBitmap& bitmap);
+ void SetItemPadding(int padding) { item_padding_ = padding; }
virtual void Paint(gfx::Canvas* canvas);
virtual gfx::Size GetPreferredSize();
@@ -54,6 +56,8 @@ class IconLabelBubbleView : public views::View {
views::ImageView* image_;
views::Label* label_;
+ int item_padding_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(IconLabelBubbleView);
};
diff --git a/chrome/browser/views/location_bar/keyword_hint_view.h b/chrome/browser/views/location_bar/keyword_hint_view.h
index 75388df..af11a84 100644
--- a/chrome/browser/views/location_bar/keyword_hint_view.h
+++ b/chrome/browser/views/location_bar/keyword_hint_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_KEYWORD_HINT_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_KEYWORD_HINT_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/location_bar/location_bar_view.cc b/chrome/browser/views/location_bar/location_bar_view.cc
index 4072c58..474679b 100644
--- a/chrome/browser/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/views/location_bar/location_bar_view.cc
@@ -12,12 +12,19 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/theme_provider.h"
+#include "base/stl_util-inl.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/alternate_nav_url_fetcher.h"
+#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/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/match_preview.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"
@@ -33,6 +40,7 @@
#include "gfx/skia_util.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#include "views/controls/label.h"
#include "views/drag_utils.h"
#if defined(OS_WIN)
@@ -42,25 +50,15 @@
using views::View;
// static
-const int LocationBarView::kVertMargin = 2;
-const int LocationBarView::kEdgeThickness = 2;
+const int LocationBarView::kNormalHorizontalEdgeThickness = 1;
+const int LocationBarView::kVerticalEdgeThickness = 2;
const int LocationBarView::kItemPadding = 3;
+const int LocationBarView::kExtensionItemPadding = 5;
+const int LocationBarView::kEdgeItemPadding = kItemPadding;
+const int LocationBarView::kBubblePadding = 1;
const char LocationBarView::kViewClassName[] =
"browser/views/location_bar/LocationBarView";
-// Convenience: Total space at the edges of the bar.
-const int kEdgePadding =
- LocationBarView::kEdgeThickness + LocationBarView::kItemPadding;
-
-// Padding before the start of a bubble.
-static const int kBubblePadding = kEdgePadding - 1;
-
-// Padding between the location icon and the edit, if they're adjacent.
-static const int kLocationIconEditPadding = LocationBarView::kItemPadding - 1;
-
-// Padding after the star.
-static const int kStarPadding = kEdgePadding + 1;
-
static const int kEVBubbleBackgroundImages[] = {
IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_L,
IDR_OMNIBOX_EV_BUBBLE_BACKGROUND_C,
@@ -91,15 +89,19 @@ LocationBarView::LocationBarView(Profile* profile,
model_(model),
delegate_(delegate),
disposition_(CURRENT_TAB),
+ transition_(PageTransition::LINK),
location_icon_view_(NULL),
ev_bubble_view_(NULL),
location_entry_view_(NULL),
selected_keyword_view_(NULL),
+ suggested_text_view_(NULL),
keyword_hint_view_(NULL),
star_view_(NULL),
mode_(mode),
show_focus_rect_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(first_run_bubble_(this)) {
+ bubble_type_(FirstRun::MINIMAL_BUBBLE),
+ template_url_model_(NULL),
+ update_match_preview_(true) {
DCHECK(profile_);
SetID(VIEW_ID_LOCATION_BAR);
SetFocusable(true);
@@ -109,6 +111,8 @@ LocationBarView::LocationBarView(Profile* profile,
}
LocationBarView::~LocationBarView() {
+ if (template_url_model_)
+ template_url_model_->RemoveObserver(this);
}
void LocationBarView::Init() {
@@ -122,8 +126,8 @@ void LocationBarView::Init() {
// If this makes the font too big, try to make it smaller so it will fit.
const int height =
- std::max(GetPreferredSize().height() - TopMargin() - kVertMargin, 0);
- while ((font_.height() > height) && (font_.FontSize() > 1))
+ std::max(GetPreferredSize().height() - (kVerticalEdgeThickness * 2), 0);
+ while ((font_.GetHeight() > height) && (font_.GetFontSize() > 1))
font_ = font_.DeriveFont(-1);
location_icon_view_ = new LocationIconView(this);
@@ -170,9 +174,9 @@ void LocationBarView::Init() {
location_entry_view_->SetAccessibleName(
l10n_util::GetString(IDS_ACCNAME_LOCATION));
- selected_keyword_view_ =
- new SelectedKeywordView(kSelectedKeywordBackgroundImages,
- IDR_OMNIBOX_SEARCH, SK_ColorBLACK, profile_),
+ selected_keyword_view_ = new SelectedKeywordView(
+ kSelectedKeywordBackgroundImages, IDR_KEYWORD_SEARCH_MAGNIFIER,
+ GetColor(ToolbarModel::NONE, TEXT), profile_),
AddChildView(selected_keyword_view_);
selected_keyword_view_->SetFont(font_);
selected_keyword_view_->SetVisible(false);
@@ -194,7 +198,7 @@ void LocationBarView::Init() {
}
// The star is not visible in popups and in the app launcher.
- if (mode_ == NORMAL) {
+ if (browser_defaults::bookmarks_enabled && (mode_ == NORMAL)) {
star_view_ = new StarView(command_updater_);
AddChildView(star_view_);
star_view_->SetVisible(true);
@@ -265,6 +269,10 @@ SkColor LocationBarView::GetColor(ToolbarModel::SecurityLevel security_level,
}
void LocationBarView::Update(const TabContents* tab_for_state_restoring) {
+ bool star_enabled = star_view_ && !model_->input_in_progress();
+ command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
+ if (star_view_)
+ star_view_->SetVisible(star_enabled);
RefreshContentSettingViews();
RefreshPageActionViews();
// Don't Update in app launcher mode so that the location entry does not show
@@ -386,7 +394,29 @@ void LocationBarView::Layout() {
if (!location_entry_.get())
return;
- int entry_width = width() - (star_view_ ? kStarPadding : kEdgePadding);
+ // TODO(sky): baseline layout.
+ int location_y = kVerticalEdgeThickness;
+ // In some cases (e.g. fullscreen mode) we may have 0 height. We still want
+ // to position our child views in this case, because other things may be
+ // positioned relative to them (e.g. the "bookmark added" bubble if the user
+ // hits ctrl-d).
+ int location_height = std::max(height() - (kVerticalEdgeThickness * 2), 0);
+
+ // The edge stroke is 1 px thick. In popup mode, the edges are drawn by the
+ // omnibox' parent, so there isn't any edge to account for at all.
+ const int kEdgeThickness = (mode_ == NORMAL) ?
+ kNormalHorizontalEdgeThickness : 0;
+ // The edit has 1 px of horizontal whitespace inside it before the text.
+ const int kEditInternalSpace = 1;
+ // The space between an item and the edit is the normal item space, minus the
+ // edit's built-in space (so the apparent space will be the same).
+ const int kItemEditPadding =
+ LocationBarView::kItemPadding - kEditInternalSpace;
+ const int kEdgeEditPadding =
+ LocationBarView::kEdgeItemPadding - kEditInternalSpace;
+
+ // Start by reserving the padding at the right edge.
+ int entry_width = width() - kEdgeThickness - kEdgeItemPadding;
// |location_icon_view_| is visible except when |ev_bubble_view_| or
// |selected_keyword_view_| are visible.
@@ -398,7 +428,8 @@ void LocationBarView::Layout() {
const bool is_keyword_hint(location_entry_->model()->is_keyword_hint());
const bool show_selected_keyword = !keyword.empty() && !is_keyword_hint;
if (show_selected_keyword) {
- entry_width -= kEdgePadding; // Assume the keyword might be hidden.
+ // Assume the keyword might be hidden.
+ entry_width -= (kEdgeThickness + kEdgeEditPadding);
} else if (model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
ev_bubble_view_->SetVisible(true);
ev_bubble_view_->SetLabel(model_->GetEVCertName());
@@ -407,22 +438,24 @@ void LocationBarView::Layout() {
} else {
location_icon_view_->SetVisible(true);
location_icon_width = location_icon_view_->GetPreferredSize().width();
- entry_width -=
- kEdgePadding + location_icon_width + kLocationIconEditPadding;
+ entry_width -= (kEdgeThickness + kEdgeItemPadding + location_icon_width +
+ kItemEditPadding);
}
- if (star_view_)
+ if (star_view_ && star_view_->IsVisible())
entry_width -= star_view_->GetPreferredSize().width() + kItemPadding;
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i) {
if ((*i)->IsVisible())
- entry_width -= (*i)->GetPreferredSize().width() + kItemPadding;
+ entry_width -= ((*i)->GetPreferredSize().width() + kItemPadding);
}
for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
i != content_setting_views_.end(); ++i) {
if ((*i)->IsVisible())
- entry_width -= (*i)->GetPreferredSize().width() + kItemPadding;
+ entry_width -= ((*i)->GetPreferredSize().width() + kItemPadding);
}
+ // The gap between the edit and whatever is to its right is shortened.
+ entry_width += kEditInternalSpace;
// Size the EV bubble. We do this after taking the star/page actions/content
// settings out of |entry_width| so we won't take too much space.
@@ -431,11 +464,11 @@ void LocationBarView::Layout() {
// space, but never elide it any smaller than 150 px.
static const int kMinElidedBubbleWidth = 150;
static const double kMaxBubbleFraction = 0.5;
+ const int total_padding =
+ kEdgeThickness + kBubblePadding + kItemEditPadding;
ev_bubble_width = std::min(ev_bubble_width, std::max(kMinElidedBubbleWidth,
- static_cast<int>((entry_width - kBubblePadding - kItemPadding) *
- kMaxBubbleFraction)));
-
- entry_width -= kBubblePadding + ev_bubble_width + kItemPadding;
+ static_cast<int>((entry_width - total_padding) * kMaxBubbleFraction)));
+ entry_width -= (total_padding + ev_bubble_width);
}
#if defined(OS_WIN)
@@ -459,16 +492,17 @@ void LocationBarView::Layout() {
if (show_selected_keyword) {
if (selected_keyword_view_->keyword() != keyword) {
selected_keyword_view_->SetKeyword(keyword);
-
const TemplateURL* template_url =
profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
if (template_url && template_url->IsExtensionKeyword()) {
const SkBitmap& bitmap = profile_->GetExtensionsService()->
GetOmniboxIcon(template_url->GetExtensionId());
selected_keyword_view_->SetImage(bitmap);
+ selected_keyword_view_->SetItemPadding(kExtensionItemPadding);
} else {
selected_keyword_view_->SetImage(*ResourceBundle::GetSharedInstance().
GetBitmapNamed(IDR_OMNIBOX_SEARCH));
+ selected_keyword_view_->SetItemPadding(kItemPadding);
}
}
} else if (show_keyword_hint) {
@@ -476,20 +510,13 @@ void LocationBarView::Layout() {
keyword_hint_view_->SetKeyword(keyword);
}
- // TODO(sky): baseline layout.
- int location_y = TopMargin();
- int location_height = std::max(height() - location_y - kVertMargin, 0);
-
// Lay out items to the right of the edit field.
- int offset = width();
- if (star_view_) {
- offset -= kStarPadding;
+ int offset = width() - kEdgeThickness - kEdgeItemPadding;
+ if (star_view_ && star_view_->IsVisible()) {
int star_width = star_view_->GetPreferredSize().width();
offset -= star_width;
star_view_->SetBounds(offset, location_y, star_width, location_height);
offset -= kItemPadding;
- } else {
- offset -= kEdgePadding;
}
for (PageActionViews::const_iterator i(page_action_views_.begin());
@@ -517,28 +544,72 @@ void LocationBarView::Layout() {
// Now lay out items to the left of the edit field.
if (location_icon_view_->IsVisible()) {
- location_icon_view_->SetBounds(kEdgePadding, location_y,
- location_icon_width, location_height);
- offset = location_icon_view_->bounds().right() + kLocationIconEditPadding;
+ location_icon_view_->SetBounds(kEdgeThickness + kEdgeItemPadding,
+ location_y, location_icon_width, location_height);
+ offset = location_icon_view_->bounds().right() + kItemEditPadding;
} else if (ev_bubble_view_->IsVisible()) {
- ev_bubble_view_->SetBounds(kBubblePadding, location_y, ev_bubble_width,
- location_height);
- offset = ev_bubble_view_->bounds().right() + kItemPadding;
+ ev_bubble_view_->SetBounds(kEdgeThickness + kBubblePadding,
+ location_y + kBubblePadding, ev_bubble_width,
+ ev_bubble_view_->GetPreferredSize().height());
+ offset = ev_bubble_view_->bounds().right() + kItemEditPadding;
} else {
- offset = show_selected_keyword ? kBubblePadding : kEdgePadding;
+ offset = kEdgeThickness +
+ (show_selected_keyword ? kBubblePadding : kEdgeEditPadding);
}
// Now lay out the edit field and views that autocollapse to give it more
// room.
gfx::Rect location_bounds(offset, location_y, entry_width, location_height);
if (show_selected_keyword) {
- LayoutView(true, selected_keyword_view_, available_width, &location_bounds);
- if (!selected_keyword_view_->IsVisible()) {
- location_bounds.set_x(
- location_bounds.x() + kEdgePadding - kBubblePadding);
- }
+ selected_keyword_view_->SetBounds(0, location_y + kBubblePadding, 0,
+ selected_keyword_view_->GetPreferredSize().height());
+ LayoutView(selected_keyword_view_, kItemEditPadding, available_width,
+ true, &location_bounds);
+ location_bounds.set_x(selected_keyword_view_->IsVisible() ?
+ (offset + selected_keyword_view_->width() + kItemEditPadding) :
+ (kEdgeThickness + kEdgeEditPadding));
} else if (show_keyword_hint) {
- LayoutView(false, keyword_hint_view_, available_width, &location_bounds);
+ keyword_hint_view_->SetBounds(0, location_y, 0, location_height);
+ // Tricky: |entry_width| has already been enlarged by |kEditInternalSpace|.
+ // But if we add a trailing view, it needs to have that enlargement be to
+ // its left. So we undo the enlargement, then include it in the padding for
+ // the added view.
+ location_bounds.Inset(0, 0, kEditInternalSpace, 0);
+ LayoutView(keyword_hint_view_, kItemEditPadding, available_width, false,
+ &location_bounds);
+ if (!keyword_hint_view_->IsVisible()) {
+ // Put back the enlargement that we undid above.
+ location_bounds.Inset(0, 0, -kEditInternalSpace, 0);
+ }
+ }
+
+ // 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
+ // suggested text. If we can't it means either the suggested text is too big,
+ // or the user has scrolled.
+
+ // TODO(sky): We could potentially combine this with the previous step to
+ // force using minimum size if necessary, but currently the chance of showing
+ // keyword hints and suggested text is minimal and we're not confident this
+ // is the right approach for suggested text.
+ if (suggested_text_view_) {
+ // TODO(sky): need to layout when the user changes caret position.
+ int suggested_text_width = suggested_text_view_->GetPreferredSize().width();
+ int vis_text_width = location_entry_->WidthOfTextAfterCursor();
+ if (vis_text_width + suggested_text_width > entry_width) {
+ // Hide the suggested text if the user has scrolled or we can't fit all
+ // the suggested text.
+ suggested_text_view_->SetBounds(0, 0, 0, 0);
+ } else {
+ int location_needed_width = location_entry_->TextWidth();
+ location_bounds.set_width(std::min(location_needed_width,
+ entry_width - suggested_text_width));
+ suggested_text_view_->SetBounds(location_bounds.right(),
+ location_bounds.y(),
+ suggested_text_width,
+ location_bounds.height());
+ }
}
location_entry_view_->SetBounds(location_bounds);
@@ -564,7 +635,7 @@ void LocationBarView::Paint(gfx::Canvas* canvas) {
// reverse; this antialiases better (see comments in
// AutocompletePopupContentsView::Paint()).
gfx::Rect bounds(GetLocalBounds(false));
- bounds.Inset(0, TopMargin(), 0, kVertMargin);
+ bounds.Inset(0, kVerticalEdgeThickness);
SkColor color(GetColor(ToolbarModel::NONE, BACKGROUND));
if (mode_ == NORMAL) {
SkPaint paint;
@@ -574,7 +645,7 @@ void LocationBarView::Paint(gfx::Canvas* canvas) {
// The round corners of the omnibox match the round corners of the dropdown
// below, and all our other bubbles.
const SkScalar radius(SkIntToScalar(BubbleBorder::GetCornerRadius()));
- bounds.Inset(kEdgeThickness, 0);
+ bounds.Inset(kNormalHorizontalEdgeThickness, 0);
canvas->AsCanvasSkia()->drawRoundRect(gfx::RectToSkRect(bounds), radius,
radius, paint);
} else {
@@ -645,39 +716,102 @@ void LocationBarView::OnMouseReleased(const views::MouseEvent& event,
}
#endif
+void LocationBarView::OnAutocompleteWillClosePopup() {
+ if (!update_match_preview_)
+ return;
+
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ if (match_preview && !match_preview->commit_on_mouse_up())
+ match_preview->DestroyPreviewContents();
+}
+
+void LocationBarView::OnAutocompleteLosingFocus(
+ gfx::NativeView view_gaining_focus) {
+ SetSuggestedText(string16());
+
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ if (!match_preview)
+ return;
+
+ if (!match_preview->is_active() || !match_preview->preview_contents())
+ return;
+
+ switch (GetCommitType(view_gaining_focus)) {
+ case COMMIT_MATCH_PREVIEW_IMMEDIATELY:
+ match_preview->CommitCurrentPreview(MatchPreview::COMMIT_FOCUS_LOST);
+ break;
+ case COMMIT_MATCH_PREVIEW_ON_MOUSE_UP:
+ match_preview->SetCommitOnMouseUp();
+ break;
+ case REVERT_MATCH_PREVIEW:
+ match_preview->DestroyPreviewContents();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void LocationBarView::OnAutocompleteWillAccept() {
+ update_match_preview_ = false;
+}
+
+bool LocationBarView::OnCommitSuggestedText(const std::wstring& typed_text) {
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ if (!match_preview || !suggested_text_view_ ||
+ suggested_text_view_->size().IsEmpty() ||
+ suggested_text_view_->GetText().empty()) {
+ return false;
+ }
+ // TODO(sky): I may need to route this through MatchPreview so that we don't
+ // fetch suggestions for the new combined text.
+ location_entry_->SetUserText(typed_text + suggested_text_view_->GetText());
+ return true;
+}
+
+void LocationBarView::OnPopupBoundsChanged(const gfx::Rect& bounds) {
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ if (match_preview)
+ match_preview->SetOmniboxBounds(bounds);
+}
+
void LocationBarView::OnAutocompleteAccept(
const GURL& url,
WindowOpenDisposition disposition,
PageTransition::Type transition,
const GURL& alternate_nav_url) {
- if (!url.is_valid())
- return;
-
- 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);
- return;
- }
-
- 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.
+ // 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 (delegate_->GetMatchPreview())
+ delegate_->GetMatchPreview()->DestroyPreviewContents();
+
+ update_match_preview_ = true;
}
void LocationBarView::OnChanged() {
@@ -686,6 +820,22 @@ void LocationBarView::OnChanged() {
location_entry_->GetIcon()));
Layout();
SchedulePaint();
+
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ string16 suggested_text;
+ if (update_match_preview_ && match_preview && GetTabContents()) {
+ if (location_entry_->model()->user_input_in_progress() &&
+ location_entry_->model()->popup_model()->IsOpen()) {
+ match_preview->Update(GetTabContents(),
+ location_entry_->model()->CurrentMatch(),
+ WideToUTF16(location_entry_->GetText()),
+ &suggested_text);
+ } else {
+ match_preview->DestroyPreviewContents();
+ }
+ }
+
+ SetSuggestedText(suggested_text);
}
void LocationBarView::OnInputInProgress(bool in_progress) {
@@ -716,49 +866,27 @@ std::wstring LocationBarView::GetTitle() const {
return UTF16ToWideHack(delegate_->GetTabContents()->GetTitle());
}
-int LocationBarView::TopMargin() const {
- return std::min(kVertMargin, height());
-}
-
int LocationBarView::AvailableWidth(int location_bar_width) {
-#if defined(OS_WIN)
- // Use font_.GetStringWidth() instead of
- // PosFromChar(location_entry_->GetTextLength()) because PosFromChar() is
- // apparently buggy. In both LTR UI and RTL UI with left-to-right layout,
- // PosFromChar(i) might return 0 when i is greater than 1.
- return std::max(
- location_bar_width - font_.GetStringWidth(location_entry_->GetText()), 0);
-#else
return location_bar_width - location_entry_->TextWidth();
-#endif
}
-bool LocationBarView::UsePref(int pref_width, int available_width) {
- return (pref_width + kItemPadding <= available_width);
-}
-
-void LocationBarView::LayoutView(bool leading,
- views::View* view,
+void LocationBarView::LayoutView(views::View* view,
+ int padding,
int available_width,
+ bool leading,
gfx::Rect* bounds) {
DCHECK(view && bounds);
gfx::Size view_size = view->GetPreferredSize();
- if (!UsePref(view_size.width(), available_width))
+ if ((view_size.width() + padding) > available_width)
view_size = view->GetMinimumSize();
- if (view_size.width() + kItemPadding >= bounds->width()) {
- view->SetVisible(false);
- return;
+ int desired_width = view_size.width() + padding;
+ view->SetVisible(desired_width < bounds->width());
+ if (view->IsVisible()) {
+ view->SetBounds(
+ leading ? bounds->x() : (bounds->right() - view_size.width()),
+ view->y(), view_size.width(), view->height());
+ bounds->set_width(bounds->width() - desired_width);
}
- if (leading) {
- view->SetBounds(bounds->x(), bounds->y(), view_size.width(),
- bounds->height());
- bounds->Offset(view_size.width() + kItemPadding, 0);
- } else {
- view->SetBounds(bounds->right() - view_size.width(), bounds->y(),
- view_size.width(), bounds->height());
- }
- bounds->set_width(bounds->width() - view_size.width() - kItemPadding);
- view->SetVisible(true);
}
void LocationBarView::RefreshContentSettingViews() {
@@ -821,7 +949,8 @@ void LocationBarView::RefreshPageActionViews() {
for (PageActionViews::const_iterator i(page_action_views_.begin());
i != page_action_views_.end(); ++i) {
- (*i)->UpdateVisibility(contents, url);
+ (*i)->UpdateVisibility(model_->input_in_progress() ? NULL : contents,
+ url);
// Check if the visibility of the action changed and notify if it did.
ExtensionAction* action = (*i)->image_view()->page_action();
@@ -865,8 +994,10 @@ void LocationBarView::ShowFirstRunBubbleInternal(
return;
// Point at the start of the edit control; adjust to look as good as possible.
- const int kXOffset = 6; // Text looks like it actually starts 6 px in.
- const int kYOffset = -4; // Point into the omnibox, not just at its edge.
+ const int kXOffset = kNormalHorizontalEdgeThickness + kEdgeItemPadding +
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_OMNIBOX_HTTP)->width() + kItemPadding;
+ const int kYOffset = -(kVerticalEdgeThickness + 2);
gfx::Point origin(location_entry_view_->bounds().x() + kXOffset,
y() + height() + kYOffset);
// If the UI layout is RTL, the coordinate system is not transformed and
@@ -899,21 +1030,17 @@ bool LocationBarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
// 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() == base::VKEY_BACK ||
+ if (e.GetKeyCode() == app::VKEY_BACK ||
views::FocusManager::IsTabTraversalKeyEvent(e))
return true;
return false;
#endif
}
-bool LocationBarView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+AccessibilityTypes::Role LocationBarView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
-
void LocationBarView::WriteDragData(views::View* sender,
const gfx::Point& press_pt,
OSExchangeData* data) {
@@ -946,10 +1073,42 @@ bool LocationBarView::CanStartDrag(View* sender,
// LocationBarView, LocationBar implementation:
void LocationBarView::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
- // We wait 30 milliseconds to open. It allows less flicker.
- Task* task = first_run_bubble_.NewRunnableMethod(
- &LocationBarView::ShowFirstRunBubbleInternal, bubble_type);
- MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 30);
+ // Wait until search engines have loaded to show the first run bubble.
+ if (!profile_->GetTemplateURLModel()->loaded()) {
+ bubble_type_ = bubble_type;
+ template_url_model_ = profile_->GetTemplateURLModel();
+ template_url_model_->AddObserver(this);
+ template_url_model_->Load();
+ return;
+ }
+ ShowFirstRunBubbleInternal(bubble_type);
+}
+
+void LocationBarView::SetSuggestedText(const string16& text) {
+ if (!text.empty()) {
+ if (!suggested_text_view_) {
+ suggested_text_view_ = new views::Label();
+ suggested_text_view_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ suggested_text_view_->SetColor(
+ GetColor(ToolbarModel::NONE,
+ LocationBarView::DEEMPHASIZED_TEXT));
+ suggested_text_view_->SetText(UTF16ToWide(text));
+ suggested_text_view_->SetFont(location_entry_->GetFont());
+ AddChildView(suggested_text_view_);
+ } else if (suggested_text_view_->GetText() == UTF16ToWide(text)) {
+ return;
+ } else {
+ suggested_text_view_->SetText(UTF16ToWide(text));
+ }
+ } else if (suggested_text_view_) {
+ delete suggested_text_view_;
+ suggested_text_view_ = NULL;
+ } else {
+ return;
+ }
+
+ Layout();
+ SchedulePaint();
}
std::wstring LocationBarView::GetInputString() const {
@@ -1035,3 +1194,51 @@ void LocationBarView::TestPageActionPressed(size_t index) {
NOTREACHED();
}
+
+void LocationBarView::OnTemplateURLModelChanged() {
+ template_url_model_->RemoveObserver(this);
+ template_url_model_ = NULL;
+ ShowFirstRunBubble(bubble_type_);
+}
+
+LocationBarView::MatchPreviewCommitType LocationBarView::GetCommitType(
+ gfx::NativeView view_gaining_focus) {
+ // The MatchPreview is active. Destroy it if the user didn't click on the
+ // TabContents (or one of its children).
+#if defined(OS_WIN)
+ MatchPreview* match_preview = delegate_->GetMatchPreview();
+ RenderWidgetHostView* rwhv =
+ match_preview->preview_contents()->GetRenderWidgetHostView();
+ if (!view_gaining_focus || !rwhv)
+ return REVERT_MATCH_PREVIEW;
+
+ gfx::NativeView tab_view = match_preview->preview_contents()->GetNativeView();
+ if (rwhv->GetNativeView() == view_gaining_focus ||
+ tab_view == view_gaining_focus) {
+ // Focus is going to the renderer. Only commit the match preview if the
+ // mouse is down. If the mouse isn't down it means someone else moved focus
+ // and we shouldn't commit.
+ if (match_preview->IsMouseDownFromActivate()) {
+ if (match_preview->is_showing_instant()) {
+ // We're showing instant results. As instant results may shift when
+ // committing we commit on the mouse up. This way a slow click still
+ // works fine.
+ return COMMIT_MATCH_PREVIEW_ON_MOUSE_UP;
+ }
+ return COMMIT_MATCH_PREVIEW_IMMEDIATELY;
+ }
+ return REVERT_MATCH_PREVIEW;
+ }
+ gfx::NativeView view_gaining_focus_ancestor = view_gaining_focus;
+ while (view_gaining_focus_ancestor &&
+ view_gaining_focus_ancestor != tab_view) {
+ view_gaining_focus_ancestor = ::GetParent(view_gaining_focus_ancestor);
+ }
+ return view_gaining_focus_ancestor != NULL ?
+ COMMIT_MATCH_PREVIEW_IMMEDIATELY : REVERT_MATCH_PREVIEW;
+#else
+ // TODO: implement me.
+ NOTIMPLEMENTED();
+ return REVERT_MATCH_PREVIEW;
+#endif
+}
diff --git a/chrome/browser/views/location_bar/location_bar_view.h b/chrome/browser/views/location_bar/location_bar_view.h
index ca092bd..1b8762d 100644
--- a/chrome/browser/views/location_bar/location_bar_view.h
+++ b/chrome/browser/views/location_bar/location_bar_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_LOCATION_BAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_LOCATION_BAR_VIEW_H_
+#pragma once
#include <string>
#include <vector>
@@ -11,8 +12,9 @@
#include "base/task.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
-#include "chrome/browser/first_run.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/views/extensions/extension_popup.h"
@@ -29,7 +31,6 @@
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#endif
-class Browser;
class CommandUpdater;
class ContentSettingImageView;
class EVBubbleView;
@@ -37,13 +38,16 @@ class ExtensionAction;
class GURL;
class KeywordHintView;
class LocationIconView;
+class MatchPreview;
class PageActionWithBadgeView;
class Profile;
class SelectedKeywordView;
class StarView;
+class TemplateURLModel;
namespace views {
class HorizontalPainter;
+class Label;
};
/////////////////////////////////////////////////////////////////////////////
@@ -58,7 +62,8 @@ class LocationBarView : public LocationBar,
public LocationBarTesting,
public views::View,
public views::DragController,
- public AutocompleteEditController {
+ public AutocompleteEditController,
+ public TemplateURLModelObserver {
public:
// The location bar view's class name.
static const char kViewClassName[];
@@ -68,6 +73,9 @@ class LocationBarView : public LocationBar,
// Should return the current tab contents.
virtual TabContents* GetTabContents() = 0;
+ // Returns the MatchPreview, or NULL if there isn't one.
+ virtual MatchPreview* GetMatchPreview() = 0;
+
// Called by the location bar view when the user starts typing in the edit.
// This forces our security style to be UNKNOWN for the duration of the
// editing.
@@ -103,8 +111,8 @@ class LocationBarView : public LocationBar,
void Init();
- // Returns whether this instance has been initialized by callin Init. Init can
- // only be called when the receiving instance is attached to a view container.
+ // True if this instance has been initialized by calling Init, which can only
+ // be called when the receiving instance is attached to a view container.
bool IsInitialized() const;
// Returns the appropriate color for the desired kind, based on the user's
@@ -167,6 +175,11 @@ class LocationBarView : public LocationBar,
#endif
// AutocompleteEditController
+ virtual void OnAutocompleteWillClosePopup();
+ virtual void OnAutocompleteLosingFocus(gfx::NativeView view_gaining_focus);
+ virtual void OnAutocompleteWillAccept();
+ virtual bool OnCommitSuggestedText(const std::wstring& typed_text);
+ virtual void OnPopupBoundsChanged(const gfx::Rect& bounds);
virtual void OnAutocompleteAccept(const GURL& url,
WindowOpenDisposition disposition,
PageTransition::Type transition,
@@ -181,7 +194,7 @@ class LocationBarView : public LocationBar,
// Overridden from views::View:
virtual std::string GetClassName() const;
virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
// Overridden from views::DragController:
virtual void WriteDragData(View* sender,
@@ -194,6 +207,7 @@ class LocationBarView : public LocationBar,
// 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;
@@ -220,9 +234,22 @@ class LocationBarView : public LocationBar,
virtual ExtensionAction* GetVisiblePageAction(size_t index);
virtual void TestPageActionPressed(size_t index);
- static const int kVertMargin; // Space above and below the edit.
- static const int kEdgeThickness; // Unavailable space at horizontal edges.
- static const int kItemPadding; // Space between items within the bar.
+ // Overridden from TemplateURLModelObserver
+ virtual void OnTemplateURLModelChanged();
+
+ // Thickness of the left and right edges of the omnibox, in normal mode.
+ static const int kNormalHorizontalEdgeThickness;
+ // Thickness of the top and bottom edges of the omnibox.
+ static const int kVerticalEdgeThickness;
+ // Space between items in the location bar.
+ static const int kItemPadding;
+ // Space between items in the location bar when an extension keyword is
+ // showing.
+ static const int kExtensionItemPadding;
+ // Space between the edges and the items next to them.
+ static const int kEdgeItemPadding;
+ // Space between the edge and a bubble.
+ static const int kBubblePadding;
protected:
void Focus();
@@ -230,28 +257,36 @@ class LocationBarView : public LocationBar,
private:
typedef std::vector<ContentSettingImageView*> ContentSettingViews;
+ // Enumeration of what should happen to the match preview on focus lost.
+ enum MatchPreviewCommitType {
+ // The match preview should be committed immediately.
+ COMMIT_MATCH_PREVIEW_IMMEDIATELY,
+
+ // The match preview should be committed on mouse up.
+ COMMIT_MATCH_PREVIEW_ON_MOUSE_UP,
+
+ // The match preview should be reverted.
+ REVERT_MATCH_PREVIEW
+ };
+
friend class PageActionImageView;
friend class PageActionWithBadgeView;
typedef std::vector<PageActionWithBadgeView*> PageActionViews;
- // Returns the height in pixels of the margin at the top of the bar.
- int TopMargin() const;
-
// Returns the amount of horizontal space (in pixels) out of
// |location_bar_width| that is not taken up by the actual text in
// location_entry_.
int AvailableWidth(int location_bar_width);
- // Returns whether the |available_width| is large enough to contain a view
- // with preferred width |pref_width| at its preferred size. If this returns
- // true, the preferred size should be used. If this returns false, the
- // minimum size of the view should be used.
- bool UsePref(int pref_width, int available_width);
-
- // If View fits in the specified region, it is made visible and the
- // bounds are adjusted appropriately. If the View does not fit, it is
- // made invisible.
- void LayoutView(bool leading, views::View* view, int available_width,
+ // If |view| fits in |available_width|, it is made visible and positioned at
+ // the leading or trailing end of |bounds|, which are then shrunk
+ // appropriately. Otherwise |view| is made invisible.
+ // Note: |view| is expected to have already been positioned and sized
+ // vertically.
+ void LayoutView(views::View* view,
+ int padding,
+ int available_width,
+ bool leading,
gfx::Rect* bounds);
// Update the visibility state of the Content Blocked icons to reflect what is
@@ -276,8 +311,9 @@ class LocationBarView : public LocationBar,
// Helper to show the first run info bubble.
void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type);
- // Current browser. Not owned by us.
- Browser* browser_;
+ // Returns what should happen to the MatchPreview as a result of focus being
+ // lost.
+ MatchPreviewCommitType GetCommitType(gfx::NativeView view_gaining_focus);
// Current profile. Not owned by us.
Profile* profile_;
@@ -332,6 +368,10 @@ class LocationBarView : public LocationBar,
// Shown if the user has selected a keyword.
SelectedKeywordView* selected_keyword_view_;
+ // View responsible for showing suggested text. This is NULL when there is no
+ // suggested text.
+ views::Label* suggested_text_view_;
+
// Shown if the selected url has a corresponding keyword.
KeywordHintView* keyword_hint_view_;
@@ -351,12 +391,23 @@ class LocationBarView : public LocationBar,
// focused. Used when the toolbar is in full keyboard accessibility mode.
bool show_focus_rect_;
+ // Whether bubble text is short or long.
+ FirstRun::BubbleType bubble_type_;
+
+ // This is in case we're destroyed before the model loads. We store the model
+ // because calling profile_->GetTemplateURLModel() in the destructor causes a
+ // crash.
+ TemplateURLModel* template_url_model_;
+
#if defined(OS_LINUX)
scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;
#endif
- // Used to schedule a task for the first run info bubble.
- ScopedRunnableMethodFactory<LocationBarView> first_run_bubble_;
+ // Should the match preview be updated? This is set to false in
+ // OnAutocompleteWillAccept and true in OnAutocompleteAccept. This is needed
+ // as prior to accepting an autocomplete suggestion the model is reverted
+ // which triggers resetting the match preview.
+ bool update_match_preview_;
DISALLOW_IMPLICIT_CONSTRUCTORS(LocationBarView);
};
diff --git a/chrome/browser/views/location_bar/location_icon_view.h b/chrome/browser/views/location_bar/location_icon_view.h
index dd2c3e5..524da4e 100644
--- a/chrome/browser/views/location_bar/location_icon_view.h
+++ b/chrome/browser/views/location_bar/location_icon_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_LOCATION_ICON_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_LOCATION_ICON_VIEW_H_
+#pragma once
#include "chrome/browser/views/location_bar/click_handler.h"
#include "views/controls/image_view.h"
diff --git a/chrome/browser/views/location_bar/page_action_image_view.cc b/chrome/browser/views/location_bar/page_action_image_view.cc
index e954da7..015ee56 100644
--- a/chrome/browser/views/location_bar/page_action_image_view.cc
+++ b/chrome/browser/views/location_bar/page_action_image_view.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/views/location_bar/page_action_image_view.h"
+#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"
@@ -100,9 +101,8 @@ void PageActionImageView::ExecuteAction(int button,
}
}
-bool PageActionImageView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- *role = AccessibilityTypes::ROLE_PUSHBUTTON;
- return true;
+AccessibilityTypes::Role PageActionImageView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_PUSHBUTTON;
}
bool PageActionImageView::OnMousePressed(const views::MouseEvent& event) {
@@ -136,8 +136,8 @@ void PageActionImageView::OnMouseReleased(const views::MouseEvent& event,
}
bool PageActionImageView::OnKeyPressed(const views::KeyEvent& e) {
- if (e.GetKeyCode() == base::VKEY_SPACE ||
- e.GetKeyCode() == base::VKEY_RETURN) {
+ if (e.GetKeyCode() == app::VKEY_SPACE ||
+ e.GetKeyCode() == app::VKEY_RETURN) {
ExecuteAction(1, false);
return true;
}
@@ -181,46 +181,45 @@ void PageActionImageView::UpdateVisibility(TabContents* contents,
const GURL& url) {
// Save this off so we can pass it back to the extension when the action gets
// executed. See PageActionImageView::OnMousePressed.
- current_tab_id_ = ExtensionTabUtil::GetTabId(contents);
+ current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1;
current_url_ = url;
- bool visible =
- preview_enabled_ || page_action_->GetIsVisible(current_tab_id_);
- if (visible) {
- // Set the tooltip.
- tooltip_ = page_action_->GetTitle(current_tab_id_);
- SetTooltipText(UTF8ToWide(tooltip_));
-
- // 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 icon = page_action_->GetIcon(current_tab_id_);
- if (icon.isNull()) {
- int icon_index = page_action_->GetIconIndex(current_tab_id_);
- std::string icon_path;
- if (icon_index >= 0)
- icon_path = page_action_->icon_paths()->at(icon_index);
- else
- icon_path = page_action_->default_icon_path();
-
- if (!icon_path.empty()) {
- PageActionMap::iterator iter = page_action_icons_.find(icon_path);
- if (iter != page_action_icons_.end())
- icon = iter->second;
- }
- }
+ if (!contents ||
+ (!preview_enabled_ && !page_action_->GetIsVisible(current_tab_id_))) {
+ SetVisible(false);
+ return;
+ }
- if (!icon.isNull())
- SetImage(&icon);
+ // Set the tooltip.
+ tooltip_ = page_action_->GetTitle(current_tab_id_);
+ SetTooltipText(UTF8ToWide(tooltip_));
+
+ // 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 icon = page_action_->GetIcon(current_tab_id_);
+ if (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())
+ icon = iter->second;
+ }
}
- SetVisible(visible);
+ if (!icon.isNull())
+ SetImage(&icon);
+
+ SetVisible(true);
}
void PageActionImageView::InspectPopup(ExtensionAction* action) {
diff --git a/chrome/browser/views/location_bar/page_action_image_view.h b/chrome/browser/views/location_bar/page_action_image_view.h
index e61cb3e..71ee6c3 100644
--- a/chrome/browser/views/location_bar/page_action_image_view.h
+++ b/chrome/browser/views/location_bar/page_action_image_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_PAGE_ACTION_IMAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_PAGE_ACTION_IMAGE_VIEW_H_
+#pragma once
#include <map>
#include <string>
@@ -40,7 +41,7 @@ class PageActionImageView : public views::ImageView,
}
// Overridden from view.
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual bool OnMousePressed(const views::MouseEvent& event);
virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
virtual bool OnKeyPressed(const views::KeyEvent& e);
diff --git a/chrome/browser/views/location_bar/page_action_with_badge_view.cc b/chrome/browser/views/location_bar/page_action_with_badge_view.cc
index 603b4f9..fd2204e 100644
--- a/chrome/browser/views/location_bar/page_action_with_badge_view.cc
+++ b/chrome/browser/views/location_bar/page_action_with_badge_view.cc
@@ -13,10 +13,8 @@ PageActionWithBadgeView::PageActionWithBadgeView(
AddChildView(image_view_);
}
-bool PageActionWithBadgeView::GetAccessibleRole(
- AccessibilityTypes::Role* role) {
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+AccessibilityTypes::Role PageActionWithBadgeView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
gfx::Size PageActionWithBadgeView::GetPreferredSize() {
diff --git a/chrome/browser/views/location_bar/page_action_with_badge_view.h b/chrome/browser/views/location_bar/page_action_with_badge_view.h
index c54573e..69d0c36 100644
--- a/chrome/browser/views/location_bar/page_action_with_badge_view.h
+++ b/chrome/browser/views/location_bar/page_action_with_badge_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_PAGE_ACTION_WITH_BADGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_PAGE_ACTION_WITH_BADGE_VIEW_H_
+#pragma once
#include "gfx/size.h"
#include "views/view.h"
@@ -19,7 +20,7 @@ class PageActionWithBadgeView : public views::View {
PageActionImageView* image_view() { return image_view_; }
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual gfx::Size GetPreferredSize();
void UpdateVisibility(TabContents* contents, const GURL& url);
diff --git a/chrome/browser/views/location_bar/selected_keyword_view.cc b/chrome/browser/views/location_bar/selected_keyword_view.cc
index aeead05..182015b 100644
--- a/chrome/browser/views/location_bar/selected_keyword_view.cc
+++ b/chrome/browser/views/location_bar/selected_keyword_view.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/views/location_bar/selected_keyword_view.h"
#include "app/l10n_util.h"
-#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/location_bar_util.h"
diff --git a/chrome/browser/views/location_bar/selected_keyword_view.h b/chrome/browser/views/location_bar/selected_keyword_view.h
index 143025f..0199cea 100644
--- a/chrome/browser/views/location_bar/selected_keyword_view.h
+++ b/chrome/browser/views/location_bar/selected_keyword_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_SELECTED_KEYWORD_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_SELECTED_KEYWORD_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/location_bar/star_view.cc b/chrome/browser/views/location_bar/star_view.cc
index 9dfaf62..88360ec 100644
--- a/chrome/browser/views/location_bar/star_view.cc
+++ b/chrome/browser/views/location_bar/star_view.cc
@@ -31,12 +31,11 @@ void StarView::SetToggled(bool on) {
// name right after we modify the tooltip text for this view.
SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_STAR));
SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed(
- on ? IDR_OMNIBOX_STAR_LIT : IDR_OMNIBOX_STAR));
+ on ? IDR_STAR_LIT : IDR_STAR));
}
-bool StarView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- *role = AccessibilityTypes::ROLE_PUSHBUTTON;
- return true;
+AccessibilityTypes::Role StarView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_PUSHBUTTON;
}
bool StarView::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
@@ -59,8 +58,8 @@ void StarView::OnMouseReleased(const views::MouseEvent& event, bool canceled) {
}
bool StarView::OnKeyPressed(const views::KeyEvent& e) {
- if (e.GetKeyCode() == base::VKEY_SPACE ||
- e.GetKeyCode() == base::VKEY_RETURN) {
+ if (e.GetKeyCode() == app::VKEY_SPACE ||
+ e.GetKeyCode() == app::VKEY_RETURN) {
command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE);
return true;
}
diff --git a/chrome/browser/views/location_bar/star_view.h b/chrome/browser/views/location_bar/star_view.h
index ddc3749..8e8794c 100644
--- a/chrome/browser/views/location_bar/star_view.h
+++ b/chrome/browser/views/location_bar/star_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOCATION_BAR_STAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOCATION_BAR_STAR_VIEW_H_
+#pragma once
#include "chrome/browser/views/info_bubble.h"
#include "views/controls/image_view.h"
@@ -26,7 +27,7 @@ class StarView : public views::ImageView, public InfoBubbleDelegate {
private:
// views::ImageView overrides:
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual bool GetTooltipText(const gfx::Point& p, std::wstring* tooltip);
virtual bool OnMousePressed(const views::MouseEvent& event);
virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
diff --git a/chrome/browser/views/login_view.cc b/chrome/browser/views/login_view.cc
index 819de41..3bf2403 100644
--- a/chrome/browser/views/login_view.cc
+++ b/chrome/browser/views/login_view.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.
@@ -24,7 +24,8 @@ using views::GridLayout;
///////////////////////////////////////////////////////////////////////////////
// LoginView, public:
-LoginView::LoginView(const std::wstring& explanation)
+LoginView::LoginView(const std::wstring& explanation,
+ bool focus_view)
: username_field_(new views::Textfield),
password_field_(new views::Textfield(views::Textfield::STYLE_PASSWORD)),
username_label_(new views::Label(
@@ -34,7 +35,8 @@ LoginView::LoginView(const std::wstring& explanation)
message_label_(new views::Label(explanation)),
ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)),
login_model_(NULL),
- focus_delayed_(false) {
+ focus_delayed_(false),
+ focus_view_(focus_view) {
message_label_->SetMultiLine(true);
message_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
message_label_->SetAllowCharacterBreak(true);
@@ -100,6 +102,9 @@ void LoginView::SetModel(LoginModel* model) {
}
void LoginView::RequestFocus() {
+ if (!focus_view_)
+ return;
+
MessageLoop::current()->PostTask(FROM_HERE,
focus_grabber_factory_.NewRunnableMethod(&LoginView::FocusFirstField));
}
@@ -108,7 +113,7 @@ void LoginView::RequestFocus() {
// LoginView, views::View, views::LoginModelObserver overrides:
void LoginView::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
- if (is_add && child == this) {
+ if (is_add && child == this && focus_view_) {
MessageLoop::current()->PostTask(FROM_HERE,
focus_grabber_factory_.NewRunnableMethod(&LoginView::FocusFirstField));
}
@@ -117,7 +122,7 @@ void LoginView::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
void LoginView::NativeViewHierarchyChanged(bool attached,
gfx::NativeView native_view,
views::RootView* root_view) {
- if (focus_delayed_ && attached) {
+ if (focus_delayed_ && attached && focus_view_) {
focus_delayed_ = false;
MessageLoop::current()->PostTask(FROM_HERE,
focus_grabber_factory_.NewRunnableMethod(&LoginView::FocusFirstField));
@@ -137,6 +142,7 @@ void LoginView::OnAutofillDataAvailable(const std::wstring& username,
// LoginView, private:
void LoginView::FocusFirstField() {
+ DCHECK(focus_view_);
if (GetFocusManager()) {
username_field_->RequestFocus();
} else {
diff --git a/chrome/browser/views/login_view.h b/chrome/browser/views/login_view.h
index 01b1b7c..b4c133a 100644
--- a/chrome/browser/views/login_view.h
+++ b/chrome/browser/views/login_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_LOGIN_VIEW_H_
#define CHROME_BROWSER_VIEWS_LOGIN_VIEW_H_
+#pragma once
#include "base/task.h"
#include "chrome/browser/login_model.h"
@@ -19,7 +20,8 @@ class LoginModel;
// for HTTP/FTP authentication.
class LoginView : public views::View, public LoginModelObserver {
public:
- explicit LoginView(const std::wstring& explanation);
+ // |focus_view| indicates if the view can be focused.
+ LoginView(const std::wstring& explanation, bool focus_view);
virtual ~LoginView();
// Access the data in the username/password text fields.
@@ -67,8 +69,11 @@ class LoginView : public views::View, public LoginModelObserver {
ScopedRunnableMethodFactory<LoginView> focus_grabber_factory_;
+ // See description above constructor.
+ const bool focus_view_;
+
// Indicates that this view was created when focus manager was unavailable
- // (on the hidden tab, for example).
+ // (on the hidden tab, for example). This is only used if focus_view_ is true.
bool focus_delayed_;
DISALLOW_COPY_AND_ASSIGN(LoginView);
diff --git a/chrome/browser/views/modal_dialog_delegate.h b/chrome/browser/views/modal_dialog_delegate.h
index 4fe2c1d..ad7125e 100644
--- a/chrome/browser/views/modal_dialog_delegate.h
+++ b/chrome/browser/views/modal_dialog_delegate.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_MODAL_DIALOG_DELEGATE_H_
#define CHROME_BROWSER_VIEWS_MODAL_DIALOG_DELEGATE_H_
-
-#include <string>
+#pragma once
#include "views/window/dialog_delegate.h"
diff --git a/chrome/browser/views/notifications/balloon_view.cc b/chrome/browser/views/notifications/balloon_view.cc
index fd7f99c..cf0442b 100644
--- a/chrome/browser/views/notifications/balloon_view.cc
+++ b/chrome/browser/views/notifications/balloon_view.cc
@@ -10,7 +10,6 @@
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
@@ -18,6 +17,7 @@
#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"
#include "chrome/browser/views/bubble_border.h"
#include "chrome/browser/views/notifications/balloon_view_host.h"
#include "chrome/common/notification_details.h"
@@ -55,15 +55,18 @@ const int kShelfBorderTopOverlap = 0;
// Properties of the dismiss button.
const int kDismissButtonWidth = 14;
const int kDismissButtonHeight = 14;
-const int kDismissButtonRightMargin = 10;
+const int kDismissButtonTopMargin = 6;
+const int kDismissButtonRightMargin = 6;
// Properties of the options menu.
-const int kOptionsButtonWidth = 26;
+const int kOptionsButtonWidth = 21;
const int kOptionsButtonHeight = 14;
-const int kOptionsButtonRightMargin = 10;
+const int kOptionsButtonTopMargin = 5;
+const int kOptionsButtonRightMargin = 4;
// Properties of the origin label.
-const int kLeftLabelMargin = 10;
+const int kLabelLeftMargin = 10;
+const int kLabelTopMargin = 6;
// Size of the drop shadow. The shadow is provided by BubbleBorder,
// not this class.
@@ -78,7 +81,6 @@ const bool kAnimateEnabled = true;
// The shelf height for the system default font size. It is scaled
// with changes in the default font size.
const int kDefaultShelfHeight = 22;
-const int kShelfTopMargin = 6;
// Menu commands
const int kRevokePermissionCommand = 0;
@@ -247,7 +249,7 @@ gfx::Rect BalloonViewImpl::GetCloseButtonBounds() const {
return gfx::Rect(
width() - kDismissButtonWidth -
kDismissButtonRightMargin - kRightShadowWidth,
- kShelfTopMargin,
+ kDismissButtonTopMargin,
kDismissButtonWidth,
kDismissButtonHeight);
}
@@ -257,15 +259,15 @@ gfx::Rect BalloonViewImpl::GetOptionsButtonBounds() const {
return gfx::Rect(
close_rect.x() - kOptionsButtonWidth - kOptionsButtonRightMargin,
- kShelfTopMargin,
+ kOptionsButtonTopMargin,
kOptionsButtonWidth,
kOptionsButtonHeight);
}
gfx::Rect BalloonViewImpl::GetLabelBounds() const {
return gfx::Rect(
- kLeftShadowWidth + kLeftLabelMargin,
- kShelfTopMargin,
+ kLeftShadowWidth + kLabelLeftMargin,
+ kLabelTopMargin,
std::max(0, width() - kOptionsButtonWidth -
kRightMargin),
kOptionsButtonHeight);
@@ -274,22 +276,22 @@ gfx::Rect BalloonViewImpl::GetLabelBounds() const {
void BalloonViewImpl::Show(Balloon* balloon) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- const std::wstring source_label_text = l10n_util::GetStringF(
- IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
- balloon->notification().display_source());
- const std::wstring dismiss_text =
- l10n_util::GetString(IDS_NOTIFICATION_BALLOON_DISMISS_LABEL);
-
balloon_ = balloon;
SetBounds(balloon_->GetPosition().x(), balloon_->GetPosition().y(),
GetTotalWidth(), GetTotalHeight());
- source_label_ = new views::Label(source_label_text);
+ const string16 source_label_text = l10n_util::GetStringFUTF16(
+ IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
+ balloon->notification().display_source());
+
+ source_label_ = new views::Label(UTF16ToWide(source_label_text));
AddChildView(source_label_);
options_menu_button_ = new views::MenuButton(NULL, L"", this, false);
AddChildView(options_menu_button_);
close_button_ = new views::ImageButton(this);
+ close_button_->SetTooltipText(l10n_util::GetString(
+ IDS_NOTIFICATION_BALLOON_DISMISS_LABEL));
AddChildView(close_button_);
// We have to create two windows: one for the contents and one for the
@@ -330,16 +332,21 @@ void BalloonViewImpl::Show(Balloon* balloon) {
frame_container_->MoveAbove(html_container_);
close_button_->SetImage(views::CustomButton::BS_NORMAL,
- rb.GetBitmapNamed(IDR_BALLOON_CLOSE));
+ rb.GetBitmapNamed(IDR_TAB_CLOSE));
close_button_->SetImage(views::CustomButton::BS_HOT,
- rb.GetBitmapNamed(IDR_BALLOON_CLOSE_HOVER));
+ rb.GetBitmapNamed(IDR_TAB_CLOSE_H));
close_button_->SetImage(views::CustomButton::BS_PUSHED,
- rb.GetBitmapNamed(IDR_BALLOON_CLOSE_HOVER));
+ rb.GetBitmapNamed(IDR_TAB_CLOSE_P));
close_button_->SetBounds(GetCloseButtonBounds());
+ close_button_->SetBackground(SK_ColorBLACK,
+ rb.GetBitmapNamed(IDR_TAB_CLOSE),
+ rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK));
options_menu_button_->SetIcon(*rb.GetBitmapNamed(IDR_BALLOON_WRENCH));
- options_menu_button_->SetHoverIcon(*rb.GetBitmapNamed(IDR_BALLOON_WRENCH));
+ options_menu_button_->SetHoverIcon(*rb.GetBitmapNamed(IDR_BALLOON_WRENCH_H));
+ options_menu_button_->SetPushedIcon(*rb.GetBitmapNamed(IDR_BALLOON_WRENCH_P));
options_menu_button_->set_alignment(views::TextButton::ALIGN_CENTER);
+ options_menu_button_->set_border(NULL);
options_menu_button_->SetBounds(GetOptionsButtonBounds());
source_label_->SetFont(rb.GetFont(ResourceBundle::SmallFont));
diff --git a/chrome/browser/views/notifications/balloon_view.h b/chrome/browser/views/notifications/balloon_view.h
index 40fc68d..ad4380e 100644
--- a/chrome/browser/views/notifications/balloon_view.h
+++ b/chrome/browser/views/notifications/balloon_view.h
@@ -6,6 +6,7 @@
#ifndef CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_H_
#define CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_H_
+#pragma once
#include "app/slide_animation.h"
#include "base/basictypes.h"
@@ -38,7 +39,6 @@ class BalloonCollection;
class NotificationDetails;
class NotificationOptionsMenuModel;
class NotificationSource;
-class SlideAnimation;
// A balloon view is the UI component for a desktop notification toasts.
// It draws a border, and within the border an HTML renderer.
diff --git a/chrome/browser/views/notifications/balloon_view_host.h b/chrome/browser/views/notifications/balloon_view_host.h
index 19fdffc..94e47e4 100644
--- a/chrome/browser/views/notifications/balloon_view_host.h
+++ b/chrome/browser/views/notifications/balloon_view_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_HOST_H_
#define CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_HOST_H_
+#pragma once
#include "chrome/browser/notifications/balloon_host.h"
#include "views/controls/native/native_view_host.h"
@@ -16,7 +17,7 @@ class BalloonViewHost : public BalloonHost {
public:
explicit BalloonViewHost(Balloon* balloon);
- ~BalloonViewHost() {
+ virtual ~BalloonViewHost() {
Shutdown();
}
diff --git a/chrome/browser/views/options/advanced_contents_view.cc b/chrome/browser/views/options/advanced_contents_view.cc
index bbe232f..9472b5e 100644
--- a/chrome/browser/views/options/advanced_contents_view.cc
+++ b/chrome/browser/views/options/advanced_contents_view.cc
@@ -12,33 +12,39 @@
#include <vsstyle.h>
#include <vssym32.h>
-#include "app/combobox_model.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/path_service.h"
+#include "base/scoped_callback_factory.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/gears_integration.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/options_util.h"
-#include "chrome/browser/pref_member.h"
-#include "chrome/browser/pref_service.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_setup_flow.h"
#include "chrome/browser/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/views/browser_dialogs.h"
-#include "chrome/browser/views/clear_browsing_data.h"
+#include "chrome/browser/views/clear_data_view.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/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "gfx/canvas_skia.h"
#include "gfx/native_theme_win.h"
@@ -436,7 +442,7 @@ class PrivacySection : public AdvancedSection,
protected:
// OptionsPageView overrides:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
// Controls for this section:
@@ -531,7 +537,7 @@ void PrivacySection::ButtonPressed(
views::Window::CreateChromeWindow(
GetWindow()->GetNativeWindow(),
gfx::Rect(),
- new ClearBrowsingDataView(profile()))->Show();
+ new ClearDataView(profile()))->Show();
}
}
@@ -630,36 +636,34 @@ void PrivacySection::InitControlLayout() {
safe_browsing_.Init(prefs::kSafeBrowsingEnabled, profile()->GetPrefs(), this);
enable_metrics_recording_.Init(prefs::kMetricsReportingEnabled,
g_browser_process->local_state(), this);
-
-
- enable_link_doctor_checkbox_->SetEnabled(!alternate_error_pages_.IsManaged());
- enable_suggest_checkbox_->SetEnabled(!use_suggest_.IsManaged());
- enable_dns_prefetching_checkbox_->SetEnabled(
- !dns_prefetch_enabled_.IsManaged());
- enable_safe_browsing_checkbox_->SetEnabled(!safe_browsing_.IsManaged());
-#if defined(GOOGLE_CHROME_BUILD)
- reporting_enabled_checkbox_->SetEnabled(
- !enable_metrics_recording_.IsManaged());
-#endif
}
-void PrivacySection::NotifyPrefChanged(const std::wstring* pref_name) {
+void PrivacySection::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kAlternateErrorPagesEnabled) {
+ enable_link_doctor_checkbox_->SetEnabled(
+ !alternate_error_pages_.IsManaged());
enable_link_doctor_checkbox_->SetChecked(
alternate_error_pages_.GetValue());
}
if (!pref_name || *pref_name == prefs::kSearchSuggestEnabled) {
+ enable_suggest_checkbox_->SetEnabled(!use_suggest_.IsManaged());
enable_suggest_checkbox_->SetChecked(use_suggest_.GetValue());
}
if (!pref_name || *pref_name == prefs::kDnsPrefetchingEnabled) {
+ enable_dns_prefetching_checkbox_->SetEnabled(
+ !dns_prefetch_enabled_.IsManaged());
bool enabled = dns_prefetch_enabled_.GetValue();
enable_dns_prefetching_checkbox_->SetChecked(enabled);
chrome_browser_net::EnablePredictor(enabled);
}
- if (!pref_name || *pref_name == prefs::kSafeBrowsingEnabled)
+ if (!pref_name || *pref_name == prefs::kSafeBrowsingEnabled) {
+ enable_safe_browsing_checkbox_->SetEnabled(!safe_browsing_.IsManaged());
enable_safe_browsing_checkbox_->SetChecked(safe_browsing_.GetValue());
+ }
if (reporting_enabled_checkbox_ &&
(!pref_name || *pref_name == prefs::kMetricsReportingEnabled)) {
+ reporting_enabled_checkbox_->SetEnabled(
+ !enable_metrics_recording_.IsManaged());
reporting_enabled_checkbox_->SetChecked(
enable_metrics_recording_.GetValue());
ResolveMetricsReportingEnabled();
@@ -786,7 +790,7 @@ class SecuritySection : public AdvancedSection,
protected:
// OptionsPageView overrides:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
// Controls for this section:
@@ -882,7 +886,7 @@ void SecuritySection::InitControlLayout() {
}
// This method is called with a null pref_name when the dialog is initialized.
-void SecuritySection::NotifyPrefChanged(const std::wstring* pref_name) {
+void SecuritySection::NotifyPrefChanged(const std::string* pref_name) {
// These SSL options are system settings and stored in the OS.
if (!pref_name) {
net::SSLConfig config;
@@ -946,13 +950,16 @@ class NetworkSection : public AdvancedSection,
protected:
// OptionsPageView overrides:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
// Controls for this section:
views::Label* change_proxies_label_;
views::NativeButton* change_proxies_button_;
+ // Tracks the proxy preferences.
+ scoped_ptr<PrefSetObserver> proxy_prefs_;
+
DISALLOW_COPY_AND_ASSIGN(NetworkSection);
};
@@ -998,9 +1005,16 @@ void NetworkSection::InitControlLayout() {
true);
AddLeadingControl(layout, change_proxies_button_, indented_view_set_id,
false);
+
+ proxy_prefs_.reset(PrefSetObserver::CreateProxyPrefSetObserver(
+ profile()->GetPrefs(), this));
+ NotifyPrefChanged(NULL);
}
-void NetworkSection::NotifyPrefChanged(const std::wstring* pref_name) {
+void NetworkSection::NotifyPrefChanged(const std::string* pref_name) {
+ if (!pref_name || proxy_prefs_->IsObserved(*pref_name)) {
+ change_proxies_button_->SetEnabled(!proxy_prefs_->IsManaged());
+ }
}
} // namespace
@@ -1029,7 +1043,7 @@ class DownloadSection : public AdvancedSection,
protected:
// OptionsPageView overrides.
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
// Controls for this section.
@@ -1092,7 +1106,7 @@ void DownloadSection::ButtonPressed(
}
ask_for_save_location_.SetValue(enabled);
} else if (sender == reset_file_handlers_button_) {
- profile()->GetDownloadManager()->ResetAutoOpenFiles();
+ profile()->GetDownloadManager()->download_prefs()->ResetAutoOpen();
UserMetricsRecordAction(UserMetricsAction("Options_ResetAutoOpenFiles"),
profile()->GetPrefs());
}
@@ -1178,7 +1192,7 @@ void DownloadSection::InitControlLayout() {
this);
}
-void DownloadSection::NotifyPrefChanged(const std::wstring* pref_name) {
+void DownloadSection::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kDownloadDefaultDirectory)
UpdateDownloadDirectoryDisplay();
@@ -1189,7 +1203,7 @@ void DownloadSection::NotifyPrefChanged(const std::wstring* pref_name) {
if (!pref_name || *pref_name == prefs::kDownloadExtensionsToOpen) {
bool enabled =
- profile()->GetDownloadManager()->HasAutoOpenFileTypesRegistered();
+ profile()->GetDownloadManager()->download_prefs()->IsAutoOpenUsed();
reset_file_handlers_label_->SetEnabled(enabled);
reset_file_handlers_button_->SetEnabled(enabled);
}
@@ -1215,7 +1229,7 @@ class TranslateSection : public AdvancedSection,
protected:
// OptionsPageView overrides:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
// Control for this section:
@@ -1261,12 +1275,274 @@ void TranslateSection::InitControlLayout() {
enable_translate_.Init(prefs::kEnableTranslate, profile()->GetPrefs(), this);
}
-void TranslateSection::NotifyPrefChanged(const std::wstring* pref_name) {
+void TranslateSection::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kEnableTranslate)
enable_translate_checkbox_->SetChecked(enable_translate_.GetValue());
}
////////////////////////////////////////////////////////////////////////////////
+// ChromeAppsSection
+
+class ChromeAppsSection : public AdvancedSection,
+ public views::ButtonListener,
+ public views::LinkController {
+ public:
+ explicit ChromeAppsSection(Profile* profile);
+ virtual ~ChromeAppsSection() {}
+
+ // Overridden from views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+ // Overridden from views::LinkController:
+ virtual void LinkActivated(views::Link* source, int event_flags);
+
+ protected:
+ // OptionsPageView overrides:
+ virtual void InitControlLayout();
+ virtual void NotifyPrefChanged(const std::string* pref_name);
+
+ private:
+ // Controls for this section:
+ views::Checkbox* enable_background_mode_checkbox_;
+ views::Link* learn_more_link_;
+
+ // Preferences for this section:
+ BooleanPrefMember enable_background_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeAppsSection);
+};
+
+ChromeAppsSection::ChromeAppsSection(Profile* profile)
+ : enable_background_mode_checkbox_(NULL),
+ learn_more_link_(NULL),
+ AdvancedSection(profile, l10n_util::GetString(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_CHROME_APPS)) {
+}
+
+void ChromeAppsSection::ButtonPressed(
+ views::Button* sender, const views::Event& event) {
+ DCHECK(sender == enable_background_mode_checkbox_);
+ bool enabled = enable_background_mode_checkbox_->checked();
+ UserMetricsRecordAction(enabled ?
+ UserMetricsAction("Options_BackgroundMode_Enable") :
+ UserMetricsAction("Options_BackgroundMode_Disable"),
+ profile()->GetPrefs());
+ enable_background_mode_.SetValue(enabled);
+}
+
+void ChromeAppsSection::LinkActivated(views::Link* source, int event_flags) {
+ DCHECK(source == learn_more_link_);
+ Browser::Create(profile())->OpenURL(
+ GURL(l10n_util::GetString(IDS_LEARN_MORE_BACKGROUND_MODE_URL)), GURL(),
+ NEW_WINDOW, PageTransition::LINK);
+}
+
+void ChromeAppsSection::InitControlLayout() {
+ AdvancedSection::InitControlLayout();
+
+ GridLayout* layout = new GridLayout(contents_);
+ contents_->SetLayoutManager(layout);
+
+ AddIndentedColumnSet(layout, 0);
+
+ enable_background_mode_checkbox_ = new views::Checkbox(
+ l10n_util::GetString(IDS_OPTIONS_CHROME_APPS_ENABLE_BACKGROUND_MODE));
+ enable_background_mode_checkbox_->set_listener(this);
+ AddWrappingCheckboxRow(layout, enable_background_mode_checkbox_, 0, true);
+
+ // Init member pref so we can update the controls if prefs change.
+ enable_background_mode_.Init(prefs::kBackgroundModeEnabled,
+ profile()->GetPrefs(), this);
+
+ // Add our link to the help center page for this feature.
+ learn_more_link_ = new views::Link(l10n_util::GetString(IDS_LEARN_MORE));
+ learn_more_link_->SetController(this);
+ AddLeadingControl(layout, learn_more_link_, 0, false);
+}
+
+void ChromeAppsSection::NotifyPrefChanged(const std::string* pref_name) {
+ if (!pref_name || *pref_name == prefs::kBackgroundModeEnabled) {
+ enable_background_mode_checkbox_->SetChecked(
+ enable_background_mode_.GetValue());
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CloudPrintProxySection
+
+class CloudPrintProxySection : public AdvancedSection,
+ public views::ButtonListener,
+ public CloudPrintSetupFlow::Delegate {
+ public:
+ explicit CloudPrintProxySection(Profile* profile);
+ virtual ~CloudPrintProxySection() {}
+
+ // Overridden from views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+
+ // Callback that gets the cloud print proxy status.
+ void StatusCallback(bool enabled, std::string email);
+
+ // CloudPrintSetupFlow::Delegate implementation.
+ virtual void OnDialogClosed();
+
+ protected:
+ // OptionsPageView overrides:
+ virtual void InitControlLayout();
+ virtual void NotifyPrefChanged(const std::string* pref_name);
+
+ private:
+ bool Enabled() const;
+
+ // Controls for this section:
+ views::Label* section_description_label_;
+ views::NativeButton* enable_disable_button_;
+ views::NativeButton* manage_printer_button_;
+
+ // Preferences we tie things to.
+ StringPrefMember cloud_print_proxy_email_;
+
+ base::ScopedCallbackFactory<CloudPrintProxySection> factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CloudPrintProxySection);
+};
+
+CloudPrintProxySection::CloudPrintProxySection(Profile* profile)
+ : section_description_label_(NULL),
+ enable_disable_button_(NULL),
+ manage_printer_button_(NULL),
+ factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ AdvancedSection(profile,
+ l10n_util::GetString(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_CLOUD_PRINT)) {
+}
+
+void CloudPrintProxySection::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ if (sender == enable_disable_button_) {
+ if (Enabled()) {
+ // Enabled, we must be the disable button.
+ UserMetricsRecordAction(
+ UserMetricsAction("Options_DisableCloudPrintProxy"), NULL);
+ CloudPrintSetupFlow::DisableCloudPrintProxy(profile());
+ } else {
+ UserMetricsRecordAction(
+ UserMetricsAction("Options_EnableCloudPrintProxy"), NULL);
+ // We open a new browser window so the Options dialog doesn't
+ // get lost behind other windows.
+ enable_disable_button_->SetEnabled(false);
+ enable_disable_button_->SetLabel(
+ l10n_util::GetString(IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLING_BUTTON));
+ CloudPrintSetupFlow::OpenDialog(profile(), this,
+ GetWindow()->GetNativeWindow());
+ }
+ } else if (sender == manage_printer_button_) {
+ UserMetricsRecordAction(
+ UserMetricsAction("Options_ManageCloudPrinters"), NULL);
+ // Open a new browser window for the management tab. The browser
+ // will go away when the user closes that tab.
+ Browser* browser = Browser::Create(profile());
+ // FIXME(scottbyer): Refactor Cloud Print URL creation.
+ // http://code.google.com/p/chromium/issues/detail?id=56850
+ browser->OpenURL(GURL("https://www.google.com/cloudprint/manage.html"),
+ GURL(), NEW_WINDOW, PageTransition::LINK);
+ }
+}
+
+void CloudPrintProxySection::StatusCallback(bool enabled, std::string email) {
+ profile()->GetPrefs()->SetString(prefs::kCloudPrintEmail,
+ enabled ? email : std::string());
+}
+
+void CloudPrintProxySection::OnDialogClosed() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ enable_disable_button_->SetEnabled(true);
+ // If the dialog is canceled, the preference won't change, and so we
+ // have to revert the button text back to the disabled state.
+ if (!Enabled()) {
+ enable_disable_button_->SetLabel(
+ l10n_util::GetString(IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_BUTTON));
+ }
+}
+
+void CloudPrintProxySection::InitControlLayout() {
+ AdvancedSection::InitControlLayout();
+
+ section_description_label_ = new views::Label(
+ l10n_util::GetString(IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_LABEL));
+ enable_disable_button_ = new views::NativeButton(this,
+ l10n_util::GetString(IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_BUTTON));
+ manage_printer_button_ = new views::NativeButton(this,
+ l10n_util::GetString(
+ IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLED_MANAGE_BUTTON));
+
+ GridLayout* layout = new GridLayout(contents_);
+ contents_->SetLayoutManager(layout);
+
+ const int single_column_view_set_id = 0;
+ AddWrappingColumnSet(layout, single_column_view_set_id);
+ const int control_view_set_id = 1;
+ AddDependentTwoColumnSet(layout, control_view_set_id);
+
+ // The description label at the top and label.
+ section_description_label_->SetMultiLine(true);
+ AddWrappingLabelRow(layout, section_description_label_,
+ single_column_view_set_id, true);
+
+ // The enable / disable button and manage button.
+ AddTwoColumnRow(layout, enable_disable_button_, manage_printer_button_, false,
+ control_view_set_id, kRelatedControlVerticalSpacing);
+
+ // Attach the preferences so we can flip things appropriately.
+ cloud_print_proxy_email_.Init(prefs::kCloudPrintEmail,
+ profile()->GetPrefs(), this);
+
+ // Start the UI off in the state we think it should be in.
+ std::string pref_string(prefs::kCloudPrintEmail);
+ NotifyPrefChanged(&pref_string);
+
+ // Kick off a task to ask the background service what the real
+ // answer is.
+ CloudPrintSetupFlow::RefreshPreferencesFromService(
+ profile(),
+ factory_.NewCallback(&CloudPrintProxySection::StatusCallback));
+}
+
+void CloudPrintProxySection::NotifyPrefChanged(const std::string* pref_name) {
+ if (pref_name == NULL)
+ return;
+
+ if (*pref_name == prefs::kCloudPrintEmail) {
+ if (Enabled()) {
+ std::string email;
+ if (profile()->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail))
+ email = profile()->GetPrefs()->GetString(prefs::kCloudPrintEmail);
+
+ section_description_label_->SetText(
+ l10n_util::GetStringF(IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLED_LABEL,
+ UTF8ToWide(email)));
+ enable_disable_button_->SetLabel(
+ l10n_util::GetString(IDS_OPTIONS_CLOUD_PRINT_PROXY_ENABLED_BUTTON));
+ enable_disable_button_->InvalidateLayout();
+ manage_printer_button_->SetVisible(true);
+ manage_printer_button_->InvalidateLayout();
+ } else {
+ section_description_label_->SetText(
+ l10n_util::GetString(IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_LABEL));
+ enable_disable_button_->SetLabel(
+ l10n_util::GetString(IDS_OPTIONS_CLOUD_PRINT_PROXY_DISABLED_BUTTON));
+ enable_disable_button_->InvalidateLayout();
+ manage_printer_button_->SetVisible(false);
+ }
+ Layout();
+ }
+}
+
+bool CloudPrintProxySection::Enabled() const {
+ return profile()->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
+ !profile()->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty();
+}
+
+////////////////////////////////////////////////////////////////////////////////
// AdvancedContentsView
class AdvancedContentsView : public OptionsPageView {
@@ -1363,6 +1639,16 @@ void AdvancedContentsView::InitControlLayout() {
layout->AddView(new WebContentSection(profile()));
layout->StartRow(0, single_column_view_set_id);
layout->AddView(new SecuritySection(profile()));
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableCloudPrintProxy)) {
+ layout->StartRow(0, single_column_view_set_id);
+ layout->AddView(new CloudPrintProxySection(profile()));
+ }
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBackgroundMode)) {
+ layout->StartRow(0, single_column_view_set_id);
+ layout->AddView(new ChromeAppsSection(profile()));
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -1372,7 +1658,7 @@ void AdvancedContentsView::InitClass() {
static bool initialized = false;
if (!initialized) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- line_height_ = rb.GetFont(ResourceBundle::BaseFont).height();
+ line_height_ = rb.GetFont(ResourceBundle::BaseFont).GetHeight();
initialized = true;
}
}
diff --git a/chrome/browser/views/options/advanced_contents_view.h b/chrome/browser/views/options/advanced_contents_view.h
index a27acb9..5adf493 100644
--- a/chrome/browser/views/options/advanced_contents_view.h
+++ b/chrome/browser/views/options/advanced_contents_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_ADVANCED_CONTENTS_VIEW_H__
#define CHROME_BROWSER_VIEWS_OPTIONS_ADVANCED_CONTENTS_VIEW_H__
+#pragma once
#include "chrome/browser/views/options/options_page_view.h"
diff --git a/chrome/browser/views/options/advanced_page_view.cc b/chrome/browser/views/options/advanced_page_view.cc
index 9c75994..712955c 100644
--- a/chrome/browser/views/options/advanced_page_view.cc
+++ b/chrome/browser/views/options/advanced_page_view.cc
@@ -7,7 +7,6 @@
#include "app/l10n_util.h"
#include "app/message_box_flags.h"
#include "base/string_util.h"
-#include "base/values.h"
#include "chrome/browser/options_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/options/advanced_contents_view.h"
diff --git a/chrome/browser/views/options/advanced_page_view.h b/chrome/browser/views/options/advanced_page_view.h
index 4c02f15..8075021 100644
--- a/chrome/browser/views/options/advanced_page_view.h
+++ b/chrome/browser/views/options/advanced_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_ADVANCED_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_ADVANCED_PAGE_VIEW_H_
+#pragma once
#include "chrome/browser/views/options/options_page_view.h"
#include "views/controls/button/button.h"
diff --git a/chrome/browser/views/options/content_exceptions_table_view.cc b/chrome/browser/views/options/content_exceptions_table_view.cc
index 0f7fa6a..1b81aa1 100644
--- a/chrome/browser/views/options/content_exceptions_table_view.cc
+++ b/chrome/browser/views/options/content_exceptions_table_view.cc
@@ -27,7 +27,7 @@ bool ContentExceptionsTableView::GetCellColors(int model_row,
gfx::Font font;
font = font.DeriveFont(0, gfx::Font::ITALIC);
- HFONT hf = font.hfont();
+ HFONT hf = font.GetNativeFont();
GetObject(hf, sizeof(LOGFONT), logfont);
return true;
}
diff --git a/chrome/browser/views/options/content_exceptions_table_view.h b/chrome/browser/views/options/content_exceptions_table_view.h
index 57c4ab0..ac5511f 100644
--- a/chrome/browser/views/options/content_exceptions_table_view.h
+++ b/chrome/browser/views/options/content_exceptions_table_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_EXCEPTIONS_TABLE_VIEW_H_
+#pragma once
#include "chrome/browser/content_exceptions_table_model.h"
#include "views/controls/table/table_view.h"
diff --git a/chrome/browser/views/options/content_filter_page_view.cc b/chrome/browser/views/options/content_filter_page_view.cc
index 299d6b3..5ea47e5 100644
--- a/chrome/browser/views/options/content_filter_page_view.cc
+++ b/chrome/browser/views/options/content_filter_page_view.cc
@@ -5,13 +5,16 @@
#include "chrome/browser/views/options/content_filter_page_view.h"
#include "app/l10n_util.h"
+#include "base/command_line.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/views/options/exceptions_view.h"
#include "chrome/browser/views/options/simple_content_exceptions_view.h"
+#include "chrome/common/chrome_switches.h"
#include "grit/generated_resources.h"
#include "views/controls/button/radio_button.h"
#include "views/grid_layout.h"
@@ -88,10 +91,10 @@ void ContentFilterPageView::InitControlLayout() {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
static const int kAskIDs[] = {
+ IDS_COOKIES_ASK_EVERY_TIME_RADIO,
0,
0,
- 0,
- 0,
+ IDS_PLUGIN_LOAD_SANDBOXED_RADIO,
0,
IDS_GEOLOCATION_ASK_RADIO,
IDS_NOTIFICATIONS_ASK_RADIO,
@@ -100,14 +103,16 @@ void ContentFilterPageView::InitControlLayout() {
Need_a_setting_for_every_content_settings_type);
DCHECK_EQ(arraysize(kAskIDs),
static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
- if (kAskIDs[content_type_] != 0) {
- ask_radio_ = new views::RadioButton(
- l10n_util::GetString(kAskIDs[content_type_]), radio_button_group);
- ask_radio_->set_listener(this);
- ask_radio_->SetMultiLine(true);
- layout->StartRow(0, single_column_set_id);
- layout->AddView(ask_radio_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ if (content_type_ != CONTENT_SETTINGS_TYPE_COOKIES) {
+ if (kAskIDs[content_type_] != 0) {
+ ask_radio_ = new views::RadioButton(
+ l10n_util::GetString(kAskIDs[content_type_]), radio_button_group);
+ ask_radio_->set_listener(this);
+ ask_radio_->SetMultiLine(true);
+ layout->StartRow(0, single_column_set_id);
+ layout->AddView(ask_radio_);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ }
}
static const int kBlockIDs[] = {
@@ -130,7 +135,12 @@ void ContentFilterPageView::InitControlLayout() {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
ContentSetting default_setting;
- if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ default_setting = profile()->GetHostContentSettingsMap()->
+ GetDefaultContentSetting(content_type_);
+ if (profile()->GetHostContentSettingsMap()->GetBlockNonsandboxedPlugins())
+ default_setting = CONTENT_SETTING_ASK;
+ } else if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
default_setting = profile()->GetGeolocationContentSettingsMap()->
GetDefaultContentSetting();
} else if (content_type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
@@ -179,12 +189,27 @@ void ContentFilterPageView::ButtonPressed(views::Button* sender,
profile()->GetDesktopNotificationService()),
IDS_NOTIFICATIONS_EXCEPTION_TITLE);
} else {
- ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
- profile()->GetHostContentSettingsMap(),
+ HostContentSettingsMap* settings = profile()->GetHostContentSettingsMap();
+ HostContentSettingsMap* otr_settings =
profile()->HasOffTheRecordProfile() ?
profile()->GetOffTheRecordProfile()->GetHostContentSettingsMap() :
- NULL,
- content_type_);
+ NULL;
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS &&
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings)) {
+ PluginExceptionsTableModel* model =
+ new PluginExceptionsTableModel(settings, otr_settings);
+ model->LoadSettings();
+ SimpleContentExceptionsView::ShowExceptionsWindow(
+ GetWindow()->GetNativeWindow(),
+ model,
+ IDS_PLUGINS_EXCEPTION_TITLE);
+ } else {
+ ExceptionsView::ShowExceptionsWindow(GetWindow()->GetNativeWindow(),
+ settings,
+ otr_settings,
+ content_type_);
+ }
}
return;
}
@@ -194,7 +219,17 @@ void ContentFilterPageView::ButtonPressed(views::Button* sender,
ContentSetting default_setting = allow_radio_->checked() ?
CONTENT_SETTING_ALLOW :
(block_radio_->checked() ? CONTENT_SETTING_BLOCK : CONTENT_SETTING_ASK);
- if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ if (default_setting == CONTENT_SETTING_ASK) {
+ default_setting = CONTENT_SETTING_ALLOW;
+ profile()->GetHostContentSettingsMap()->SetBlockNonsandboxedPlugins(true);
+ } else {
+ profile()->GetHostContentSettingsMap()->
+ SetBlockNonsandboxedPlugins(false);
+ }
+ profile()->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ content_type_, default_setting);
+ } else if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
profile()->GetGeolocationContentSettingsMap()->SetDefaultContentSetting(
default_setting);
} else if (content_type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
diff --git a/chrome/browser/views/options/content_filter_page_view.h b/chrome/browser/views/options/content_filter_page_view.h
index eaf6e33..8c9bd99 100644
--- a/chrome/browser/views/options/content_filter_page_view.h
+++ b/chrome/browser/views/options/content_filter_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_FILTER_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_FILTER_PAGE_VIEW_H_
+#pragma once
#include "chrome/browser/views/options/options_page_view.h"
#include "chrome/common/content_settings_types.h"
diff --git a/chrome/browser/views/options/content_page_view.cc b/chrome/browser/views/options/content_page_view.cc
index aca4e7a..541a362 100644
--- a/chrome/browser/views/options/content_page_view.cc
+++ b/chrome/browser/views/options/content_page_view.cc
@@ -10,7 +10,6 @@
#include <vssym32.h>
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "base/string_util.h"
#include "chrome/browser/autofill/autofill_dialog.h"
@@ -140,7 +139,7 @@ void ContentPageView::ButtonPressed(
IDS_CONFIRM_STOP_SYNCING_DIALOG_HEIGHT_LINES)));
return;
} else {
- sync_service_->EnableForUser(GetWindow()->GetNativeWindow());
+ sync_service_->ShowLoginDialog(GetWindow()->GetNativeWindow());
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
}
} else if (sender == sync_customize_button_) {
@@ -219,23 +218,32 @@ void ContentPageView::InitControlLayout() {
// Init member prefs so we can update the controls if prefs change.
ask_to_save_passwords_.Init(prefs::kPasswordManagerEnabled,
profile()->GetPrefs(), this);
+ form_autofill_enabled_.Init(prefs::kAutoFillEnabled,
+ profile()->GetPrefs(), this);
is_using_default_theme_.Init(prefs::kCurrentThemeID,
profile()->GetPrefs(), this);
-
- // Disable UI elements that are managed via policy.
- bool enablePasswordManagerElements = !ask_to_save_passwords_.IsManaged();
- passwords_asktosave_radio_->SetEnabled(enablePasswordManagerElements);
- passwords_neversave_radio_->SetEnabled(enablePasswordManagerElements);
- show_passwords_button_->SetEnabled(enablePasswordManagerElements);
}
-void ContentPageView::NotifyPrefChanged(const std::wstring* pref_name) {
+void ContentPageView::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kPasswordManagerEnabled) {
if (ask_to_save_passwords_.GetValue()) {
passwords_asktosave_radio_->SetChecked(true);
} else {
passwords_neversave_radio_->SetChecked(true);
}
+
+ // Disable UI elements that are managed via policy.
+ bool enablePasswordManagerElements = !ask_to_save_passwords_.IsManaged();
+ passwords_asktosave_radio_->SetEnabled(enablePasswordManagerElements);
+ passwords_neversave_radio_->SetEnabled(enablePasswordManagerElements);
+ show_passwords_button_->SetEnabled(enablePasswordManagerElements ||
+ ask_to_save_passwords_.GetValue());
+ }
+ if (!pref_name || *pref_name == prefs::kAutoFillEnabled) {
+ bool disabled_by_policy = form_autofill_enabled_.IsManaged() &&
+ !form_autofill_enabled_.GetValue();
+ change_autofill_settings_button_->SetEnabled(
+ !disabled_by_policy && profile()->GetPersonalDataManager());
}
if (!pref_name || *pref_name == prefs::kCurrentThemeID) {
themes_reset_button_->SetEnabled(
@@ -312,9 +320,6 @@ void ContentPageView::InitPasswordSavingGroup() {
void ContentPageView::InitFormAutofillGroup() {
change_autofill_settings_button_ = new views::NativeButton(
this, l10n_util::GetString(IDS_AUTOFILL_OPTIONS));
- if (!profile()->GetPersonalDataManager())
- change_autofill_settings_button_->SetEnabled(false);
-
using views::GridLayout;
using views::ColumnSet;
@@ -414,9 +419,6 @@ void ContentPageView::InitSyncGroup() {
privacy_dashboard_link_->SetController(this);
privacy_dashboard_link_->SetText(
l10n_util::GetString(IDS_SYNC_PRIVACY_DASHBOARD_LINK_LABEL));
- privacy_dashboard_link_->SetVisible(
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kShowPrivacyDashboardLink));
sync_start_stop_button_ = new views::NativeButton(this, std::wstring());
sync_customize_button_ = new views::NativeButton(this, std::wstring());
diff --git a/chrome/browser/views/options/content_page_view.h b/chrome/browser/views/options/content_page_view.h
index 91b9c07..181f8a1 100644
--- a/chrome/browser/views/options/content_page_view.h
+++ b/chrome/browser/views/options/content_page_view.h
@@ -4,9 +4,10 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_PAGE_VIEW_H_
+#pragma once
#include "chrome/browser/autofill/personal_data_manager.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "chrome/browser/views/confirm_message_box_dialog.h"
@@ -51,7 +52,7 @@ class ContentPageView : public OptionsPageView,
protected:
// OptionsPageView implementation:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// views::View overrides:
virtual void Layout();
@@ -103,6 +104,7 @@ class ContentPageView : public OptionsPageView,
views::Link* privacy_dashboard_link_;
BooleanPrefMember ask_to_save_passwords_;
+ BooleanPrefMember form_autofill_enabled_;
StringPrefMember is_using_default_theme_;
// Cached pointer to ProfileSyncService, if it exists. Kept up to date
diff --git a/chrome/browser/views/options/content_settings_window_view.cc b/chrome/browser/views/options/content_settings_window_view.cc
index f763e9e..2a2146c 100644
--- a/chrome/browser/views/options/content_settings_window_view.cc
+++ b/chrome/browser/views/options/content_settings_window_view.cc
@@ -5,10 +5,9 @@
#include "chrome/browser/views/options/content_settings_window_view.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_service.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_filter_page_view.h"
diff --git a/chrome/browser/views/options/content_settings_window_view.h b/chrome/browser/views/options/content_settings_window_view.h
index f97f219..2b843b4 100644
--- a/chrome/browser/views/options/content_settings_window_view.h
+++ b/chrome/browser/views/options/content_settings_window_view.h
@@ -4,8 +4,9 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_SETTINGS_WINDOW_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_CONTENT_SETTINGS_WINDOW_VIEW_H_
+#pragma once
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/common/content_settings_types.h"
#include "views/controls/listbox/listbox.h"
#include "views/view.h"
diff --git a/chrome/browser/views/options/cookie_filter_page_view.cc b/chrome/browser/views/options/cookie_filter_page_view.cc
index 7aaa7c8..320445c 100644
--- a/chrome/browser/views/options/cookie_filter_page_view.cc
+++ b/chrome/browser/views/options/cookie_filter_page_view.cc
@@ -83,7 +83,7 @@ void CookieFilterPageView::InitControlLayout() {
///////////////////////////////////////////////////////////////////////////////
// CookieFilterPageView, OptionsPageView implementation:
-void CookieFilterPageView::NotifyPrefChanged(const std::wstring* pref_name) {
+void CookieFilterPageView::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kClearSiteDataOnExit) {
clear_on_close_check_->SetChecked(
clear_site_data_on_exit_.GetValue());
diff --git a/chrome/browser/views/options/cookie_filter_page_view.h b/chrome/browser/views/options/cookie_filter_page_view.h
index 2710cfc..0b9b9f7 100644
--- a/chrome/browser/views/options/cookie_filter_page_view.h
+++ b/chrome/browser/views/options/cookie_filter_page_view.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_COOKIE_FILTER_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_COOKIE_FILTER_PAGE_VIEW_H_
+#pragma once
#include "chrome/browser/views/options/content_filter_page_view.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
namespace views {
class Checkbox;
@@ -27,7 +28,7 @@ class CookieFilterPageView : public ContentFilterPageView,
virtual void InitControlLayout();
// OptionsPageView implementation:
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// views::ButtonListener implementation:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
diff --git a/chrome/browser/views/options/cookies_view.cc b/chrome/browser/views/options/cookies_view.cc
index ef730dd..5e2b6d0 100644
--- a/chrome/browser/views/options/cookies_view.cc
+++ b/chrome/browser/views/options/cookies_view.cc
@@ -7,13 +7,13 @@
#include <algorithm>
#include "app/l10n_util.h"
-#include "base/i18n/time_formatting.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/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"
+#include "chrome/browser/views/indexed_db_info_view.h"
#include "chrome/browser/views/local_storage_info_view.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
@@ -146,9 +146,9 @@ void CookiesView::ContentsChanged(views::Textfield* sender,
bool CookiesView::HandleKeystroke(views::Textfield* sender,
const views::Textfield::Keystroke& key) {
- if (key.GetKeyboardCode() == base::VKEY_ESCAPE) {
+ if (key.GetKeyboardCode() == app::VKEY_ESCAPE) {
ResetSearchQuery();
- } else if (key.GetKeyboardCode() == base::VKEY_RETURN) {
+ } else if (key.GetKeyboardCode() == app::VKEY_RETURN) {
search_update_factory_.RevokeAll();
UpdateSearchResults();
}
@@ -230,14 +230,18 @@ void CookiesView::OnTreeViewSelectionChanged(views::TreeView* tree_view) {
CookieTreeNode::DetailedInfo::TYPE_APPCACHE) {
UpdateVisibleDetailedInfo(appcache_info_view_);
appcache_info_view_->SetAppCacheInfo(detailed_info.appcache_info);
+ } else if (detailed_info.node_type ==
+ CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB) {
+ UpdateVisibleDetailedInfo(indexed_db_info_view_);
+ indexed_db_info_view_->SetIndexedDBInfo(*detailed_info.indexed_db_info);
} else {
UpdateVisibleDetailedInfo(cookie_info_view_);
cookie_info_view_->ClearCookieDisplay();
}
}
-void CookiesView::OnTreeViewKeyDown(base::KeyboardCode keycode) {
- if (keycode == base::VKEY_DELETE)
+void CookiesView::OnTreeViewKeyDown(app::KeyboardCode keycode) {
+ if (keycode == app::VKEY_DELETE)
cookies_tree_->RemoveSelectedItems();
}
@@ -264,6 +268,7 @@ CookiesView::CookiesView(Profile* profile)
database_info_view_(NULL),
local_storage_info_view_(NULL),
appcache_info_view_(NULL),
+ indexed_db_info_view_(NULL),
remove_button_(NULL),
remove_all_button_(NULL),
profile_(profile),
@@ -285,7 +290,9 @@ void CookiesView::Init() {
profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(),
new BrowsingDataDatabaseHelper(profile_),
new BrowsingDataLocalStorageHelper(profile_),
- new BrowsingDataAppCacheHelper(profile_)));
+ NULL,
+ new BrowsingDataAppCacheHelper(profile_),
+ BrowsingDataIndexedDBHelper::Create(profile_)));
cookies_tree_model_->AddObserver(this);
info_panel_ = new InfoPanelView;
@@ -293,10 +300,12 @@ void CookiesView::Init() {
database_info_view_ = new DatabaseInfoView;
local_storage_info_view_ = new LocalStorageInfoView;
appcache_info_view_ = new AppCacheInfoView;
+ indexed_db_info_view_ = new IndexedDBInfoView;
info_panel_->AddChildView(cookie_info_view_);
info_panel_->AddChildView(database_info_view_);
info_panel_->AddChildView(local_storage_info_view_);
info_panel_->AddChildView(appcache_info_view_);
+ info_panel_->AddChildView(indexed_db_info_view_);
cookies_tree_ = new CookiesTreeView(cookies_tree_model_.get());
remove_button_ = new views::NativeButton(
@@ -384,4 +393,5 @@ void CookiesView::UpdateVisibleDetailedInfo(views::View* view) {
database_info_view_->SetVisible(view == database_info_view_);
local_storage_info_view_->SetVisible(view == local_storage_info_view_);
appcache_info_view_->SetVisible(view == appcache_info_view_);
+ indexed_db_info_view_->SetVisible(view == indexed_db_info_view_);
}
diff --git a/chrome/browser/views/options/cookies_view.h b/chrome/browser/views/options/cookies_view.h
index 64ca05d..dc6b9ff 100644
--- a/chrome/browser/views/options/cookies_view.h
+++ b/chrome/browser/views/options/cookies_view.h
@@ -4,10 +4,10 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_COOKIES_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_COOKIES_VIEW_H_
+#pragma once
#include <string>
-#include "app/tree_model.h"
#include "base/task.h"
#include "chrome/browser/cookies_tree_model.h"
#include "net/base/cookie_monster.h"
@@ -30,9 +30,12 @@ class AppCacheInfoView;
class CookieInfoView;
class CookiesTreeView;
class DatabaseInfoView;
+class IndexedDBInfoView;
class LocalStorageInfoView;
class Profile;
class Timer;
+class TreeModel;
+class TreeModelNode;
class CookiesView : public CookiesTreeModel::Observer,
@@ -50,24 +53,17 @@ class CookiesView : public CookiesTreeModel::Observer,
// Updates the display to show only the search results.
void UpdateSearchResults();
- // TreeModelObserver implementation.
+ // Begin TreeModelObserver implementation.
virtual void TreeNodesAdded(TreeModel* model,
TreeModelNode* parent,
int start,
int count);
-
- // TreeModelObserver implementation.
virtual void TreeNodesRemoved(TreeModel* model,
TreeModelNode* parent,
int start,
int count) {}
-
- // TreeModelObserver implementation.
- virtual void TreeNodeChildrenReordered(TreeModel* model,
- TreeModelNode* parent) {}
-
- // TreeModelObserver implementation.
virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node) {}
+ // End TreeModelObserver implementation.
// views::ButtonListener implementation.
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
@@ -76,7 +72,7 @@ class CookiesView : public CookiesTreeModel::Observer,
virtual void OnTreeViewSelectionChanged(views::TreeView* tree_view);
// views::TreeViewController implementation.
- virtual void OnTreeViewKeyDown(base::KeyboardCode keycode);
+ virtual void OnTreeViewKeyDown(app::KeyboardCode keycode);
// views::Textfield::Controller implementation.
virtual void ContentsChanged(views::Textfield* sender,
@@ -139,6 +135,7 @@ class CookiesView : public CookiesTreeModel::Observer,
DatabaseInfoView* database_info_view_;
LocalStorageInfoView* local_storage_info_view_;
AppCacheInfoView* appcache_info_view_;
+ IndexedDBInfoView* indexed_db_info_view_;
views::NativeButton* remove_button_;
views::NativeButton* remove_all_button_;
diff --git a/chrome/browser/views/options/exception_editor_view.h b/chrome/browser/views/options/exception_editor_view.h
index 3c815db..3dfab19 100644
--- a/chrome/browser/views/options/exception_editor_view.h
+++ b/chrome/browser/views/options/exception_editor_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTION_EDITOR_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTION_EDITOR_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/options/exceptions_page_view.cc b/chrome/browser/views/options/exceptions_page_view.cc
index 762c58d..7788c5c 100644
--- a/chrome/browser/views/options/exceptions_page_view.cc
+++ b/chrome/browser/views/options/exceptions_page_view.cc
@@ -7,7 +7,7 @@
#include "app/l10n_util.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/views/options/exceptions_page_view.h b/chrome/browser/views/options/exceptions_page_view.h
index 10756d9..9417118 100644
--- a/chrome/browser/views/options/exceptions_page_view.h
+++ b/chrome/browser/views/options/exceptions_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_PAGE_VIEW_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/views/options/exceptions_view.h b/chrome/browser/views/options/exceptions_view.h
index ceb9bcb..4e66e6d 100644
--- a/chrome/browser/views/options/exceptions_view.h
+++ b/chrome/browser/views/options/exceptions_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_EXCEPTIONS_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/options/fonts_languages_window_view.cc b/chrome/browser/views/options/fonts_languages_window_view.cc
index 4837582..ff6a998 100644
--- a/chrome/browser/views/options/fonts_languages_window_view.cc
+++ b/chrome/browser/views/options/fonts_languages_window_view.cc
@@ -5,8 +5,7 @@
#include "chrome/browser/views/options/fonts_languages_window_view.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/options/fonts_page_view.h"
#include "chrome/browser/views/options/languages_page_view.h"
diff --git a/chrome/browser/views/options/fonts_languages_window_view.h b/chrome/browser/views/options/fonts_languages_window_view.h
index 55a4405..4af9d01 100644
--- a/chrome/browser/views/options/fonts_languages_window_view.h
+++ b/chrome/browser/views/options/fonts_languages_window_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_FONTS_LANGUAGES_WINDOW_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_FONTS_LANGUAGES_WINDOW_VIEW_H_
+#pragma once
#include "chrome/browser/fonts_languages_window.h"
#include "views/view.h"
diff --git a/chrome/browser/views/options/fonts_page_view.cc b/chrome/browser/views/options/fonts_page_view.cc
index 0b1ab97..3a98b15 100644
--- a/chrome/browser/views/options/fonts_page_view.cc
+++ b/chrome/browser/views/options/fonts_page_view.cc
@@ -12,12 +12,12 @@
#include <vector>
#include "app/l10n_util.h"
-#include "app/l10n_util_collator.h"
#include "app/resource_bundle.h"
#include "base/file_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/default_encoding_combo_model.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/common/pref_names.h"
@@ -90,7 +90,7 @@ void FontDisplayView::SetFontType(const std::wstring& font_name,
displayed_text += UTF8ToWide(::StringPrintf("%d", font_size_));
HDC hdc = GetDC(NULL);
int font_size_point = MulDiv(font_size, 72, GetDeviceCaps(hdc, LOGPIXELSY));
- gfx::Font font = gfx::Font::CreateFont(font_name, font_size_point);
+ gfx::Font font = gfx::Font(font_name, font_size_point);
font_text_label_->SetFont(font);
font_text_label_->SetText(displayed_text);
}
@@ -206,18 +206,17 @@ void FontsPageView::ItemChanged(views::Combobox* combo_box,
}
}
-void FontsPageView::FontSelected(const gfx::Font& const_font, void* params) {
- gfx::Font font(const_font);
- if (gfx::Font(font).FontName().empty())
+void FontsPageView::FontSelected(const gfx::Font& font, void* params) {
+ if (font.GetFontName().empty())
return;
- int font_size = gfx::Font(font).FontSize();
+ int font_size = font.GetFontSize();
// Currently we do not have separate font sizes for Serif and Sans Serif.
// Therefore, when Serif font size is changed, Sans-Serif font size changes,
// and vice versa.
if (font_type_being_changed_ == SERIF) {
sans_serif_font_size_pixel_ = serif_font_size_pixel_ = font_size;
serif_font_display_view_->SetFontType(
- font.FontName(),
+ font.GetFontName(),
serif_font_size_pixel_);
sans_serif_font_display_view_->SetFontType(
sans_serif_font_display_view_->font_name(),
@@ -225,14 +224,14 @@ void FontsPageView::FontSelected(const gfx::Font& const_font, void* params) {
} else if (font_type_being_changed_ == SANS_SERIF) {
sans_serif_font_size_pixel_ = serif_font_size_pixel_ = font_size;
sans_serif_font_display_view_->SetFontType(
- font.FontName(),
+ font.GetFontName(),
sans_serif_font_size_pixel_);
serif_font_display_view_->SetFontType(
serif_font_display_view_->font_name(),
sans_serif_font_size_pixel_);
} else if (font_type_being_changed_ == FIXED_WIDTH) {
fixed_width_font_size_pixel_ = font_size;
- fixed_width_font_display_view_->SetFontType(font.FontName(), font_size);
+ fixed_width_font_display_view_->SetFontType(font.GetFontName(), font_size);
}
font_changed_ = true;
}
@@ -294,7 +293,7 @@ void FontsPageView::InitControlLayout() {
layout->AddView(encoding_contents_);
}
-void FontsPageView::NotifyPrefChanged(const std::wstring* pref_name) {
+void FontsPageView::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kWebKitFixedFontFamily) {
fixed_width_font_size_pixel_ = fixed_width_size_.GetValue();
fixed_width_font_display_view_->SetFontType(
diff --git a/chrome/browser/views/options/fonts_page_view.h b/chrome/browser/views/options/fonts_page_view.h
index 8f9ee0b..477bf91 100644
--- a/chrome/browser/views/options/fonts_page_view.h
+++ b/chrome/browser/views/options/fonts_page_view.h
@@ -4,10 +4,11 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_FONTS_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_FONTS_PAGE_VIEW_H_
+#pragma once
#include <string>
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "views/controls/combobox/combobox.h"
@@ -54,7 +55,7 @@ class FontsPageView : public OptionsPageView,
protected:
// OptionsPageView implementation:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
private:
enum FontTypeBeingChanged {
diff --git a/chrome/browser/views/options/general_page_view.cc b/chrome/browser/views/options/general_page_view.cc
index afe4ae7..d618770 100644
--- a/chrome/browser/views/options/general_page_view.cc
+++ b/chrome/browser/views/options/general_page_view.cc
@@ -8,16 +8,18 @@
#include "app/l10n_util.h"
#include "base/callback.h"
#include "base/message_loop.h"
+#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/custom_home_pages_table_model.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/session_startup_pref.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/views/keyword_editor_view.h"
#include "chrome/browser/views/options/managed_prefs_banner_view.h"
#include "chrome/browser/views/options/options_group_view.h"
@@ -50,6 +52,21 @@ bool IsNewTabUIURLString(const GURL& url) {
} // namespace
///////////////////////////////////////////////////////////////////////////////
+// OptionsGroupContents
+class OptionsGroupContents : public views::View {
+ public:
+ OptionsGroupContents() { }
+
+ // views::View overrides:
+ virtual AccessibilityTypes::Role GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OptionsGroupContents);
+};
+
+///////////////////////////////////////////////////////////////////////////////
// SearchEngineListModel
class SearchEngineListModel : public ComboboxModel,
@@ -64,7 +81,7 @@ class SearchEngineListModel : public ComboboxModel,
// ComboboxModel overrides:
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
// Returns the TemplateURL at the specified index.
const TemplateURL* GetTemplateURLAt(int index);
@@ -121,9 +138,9 @@ int SearchEngineListModel::GetItemCount() {
return static_cast<int>(template_urls_.size());
}
-std::wstring SearchEngineListModel::GetItemAt(int index) {
+string16 SearchEngineListModel::GetItemAt(int index) {
DCHECK(index < GetItemCount());
- return template_urls_[index]->short_name();
+ return WideToUTF16Hack(template_urls_[index]->short_name());
}
const TemplateURL* SearchEngineListModel::GetTemplateURLAt(int index) {
@@ -200,9 +217,6 @@ GeneralPageView::GeneralPageView(Profile* profile)
}
GeneralPageView::~GeneralPageView() {
- profile()->GetPrefs()->RemovePrefObserver(prefs::kRestoreOnStartup, this);
- profile()->GetPrefs()->RemovePrefObserver(
- prefs::kURLsToRestoreOnStartup, this);
if (startup_custom_pages_table_)
startup_custom_pages_table_->SetModel(NULL);
default_browser_worker_->ObserverDestroyed();
@@ -339,8 +353,9 @@ void GeneralPageView::InitControlLayout() {
#endif
// Register pref observers that update the controls when a pref changes.
- profile()->GetPrefs()->AddPrefObserver(prefs::kRestoreOnStartup, this);
- profile()->GetPrefs()->AddPrefObserver(prefs::kURLsToRestoreOnStartup, this);
+ registrar_.Init(profile()->GetPrefs());
+ registrar_.Add(prefs::kRestoreOnStartup, this);
+ registrar_.Add(prefs::kURLsToRestoreOnStartup, this);
new_tab_page_is_home_page_.Init(prefs::kHomePageIsNewTabPage,
profile()->GetPrefs(), this);
@@ -348,39 +363,34 @@ void GeneralPageView::InitControlLayout() {
show_home_button_.Init(prefs::kShowHomeButton, profile()->GetPrefs(), this);
}
-void GeneralPageView::NotifyPrefChanged(const std::wstring* pref_name) {
- if (!pref_name || *pref_name == prefs::kRestoreOnStartup) {
+void GeneralPageView::NotifyPrefChanged(const std::string* pref_name) {
+ if (!pref_name ||
+ *pref_name == prefs::kRestoreOnStartup ||
+ *pref_name == prefs::kURLsToRestoreOnStartup) {
PrefService* prefs = profile()->GetPrefs();
const SessionStartupPref startup_pref =
SessionStartupPref::GetStartupPref(prefs);
+ bool radio_buttons_enabled = !SessionStartupPref::TypeIsManaged(prefs);
+ bool restore_urls_enabled = !SessionStartupPref::URLsAreManaged(prefs);
switch (startup_pref.type) {
case SessionStartupPref::DEFAULT:
startup_homepage_radio_->SetChecked(true);
- EnableCustomHomepagesControls(false);
+ restore_urls_enabled = false;
break;
case SessionStartupPref::LAST:
startup_last_session_radio_->SetChecked(true);
- EnableCustomHomepagesControls(false);
+ restore_urls_enabled = false;
break;
case SessionStartupPref::URLS:
startup_custom_radio_->SetChecked(true);
- EnableCustomHomepagesControls(true);
break;
}
- }
-
- // TODO(beng): Note that the kURLsToRestoreOnStartup pref is a mutable list,
- // and changes to mutable lists aren't broadcast through the
- // observer system, so the second half of this condition will
- // never match. Once support for broadcasting such updates is
- // added, this will automagically start to work, and this comment
- // can be removed.
- if (!pref_name || *pref_name == prefs::kURLsToRestoreOnStartup) {
- PrefService* prefs = profile()->GetPrefs();
- const SessionStartupPref startup_pref =
- SessionStartupPref::GetStartupPref(prefs);
+ startup_homepage_radio_->SetEnabled(radio_buttons_enabled);
+ startup_last_session_radio_->SetEnabled(radio_buttons_enabled);
+ startup_custom_radio_->SetEnabled(radio_buttons_enabled);
+ EnableCustomHomepagesControls(restore_urls_enabled);
startup_custom_pages_table_model_->SetURLs(startup_pref.urls);
}
@@ -409,6 +419,8 @@ void GeneralPageView::NotifyPrefChanged(const std::wstring* pref_name) {
if (!pref_name || *pref_name == prefs::kShowHomeButton) {
homepage_show_home_button_checkbox_->SetChecked(
show_home_button_.GetValue());
+ homepage_show_home_button_checkbox_->SetEnabled(
+ !show_home_button_.IsManaged());
}
}
@@ -489,7 +501,7 @@ void GeneralPageView::InitStartupGroup() {
using views::GridLayout;
using views::ColumnSet;
- views::View* contents = new views::View;
+ views::View* contents = new OptionsGroupContents;
GridLayout* layout = new GridLayout(contents);
contents->SetLayoutManager(layout);
@@ -732,6 +744,11 @@ void GeneralPageView::EnableCustomHomepagesControls(bool enable) {
void GeneralPageView::AddBookmark(UrlPicker* dialog,
const std::wstring& title,
const GURL& url) {
+ // The restore URLs policy might have become managed while the dialog is
+ // displayed. While the model makes sure that no changes are made in this
+ // condition, we should still avoid changing the graphic elements.
+ if (SessionStartupPref::URLsAreManaged(profile()->GetPrefs()))
+ return;
int index = startup_custom_pages_table_->FirstSelectedRow();
if (index == -1)
index = startup_custom_pages_table_model_->RowCount();
diff --git a/chrome/browser/views/options/general_page_view.h b/chrome/browser/views/options/general_page_view.h
index e827ecf..f2b126f 100644
--- a/chrome/browser/views/options/general_page_view.h
+++ b/chrome/browser/views/options/general_page_view.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_GENERAL_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_GENERAL_PAGE_VIEW_H_
+#pragma once
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "chrome/browser/views/url_picker.h"
@@ -59,7 +61,7 @@ class GeneralPageView : public OptionsPageView,
// OptionsPageView implementation:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
virtual void HighlightGroup(OptionsGroup highlight_group);
private:
@@ -155,6 +157,8 @@ class GeneralPageView : public OptionsPageView,
// The helper object that performs default browser set/check tasks.
scoped_refptr<ShellIntegration::DefaultBrowserWorker> default_browser_worker_;
+ PrefChangeRegistrar registrar_;
+
DISALLOW_COPY_AND_ASSIGN(GeneralPageView);
};
diff --git a/chrome/browser/views/options/languages_page_view.cc b/chrome/browser/views/options/languages_page_view.cc
index 0a2bc58..207841c 100644
--- a/chrome/browser/views/options/languages_page_view.cc
+++ b/chrome/browser/views/options/languages_page_view.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.
@@ -14,11 +14,11 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/string_util.h"
-#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/language_combobox_model.h"
#include "chrome/browser/language_order_table_model.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/views/restart_message_box.h"
@@ -142,8 +142,8 @@ void AddLanguageWindowView::Layout() {
gfx::Size AddLanguageWindowView::GetPreferredSize() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont);
- return gfx::Size(font.ave_char_width() * kDefaultWindowWidthChars,
- font.height() * kDefaultWindowHeightLines);
+ return gfx::Size(font.GetAverageCharacterWidth() * kDefaultWindowWidthChars,
+ font.GetHeight() * kDefaultWindowHeightLines);
}
void AddLanguageWindowView::ViewHierarchyChanged(bool is_add,
@@ -398,7 +398,7 @@ void LanguagesPageView::InitControlLayout() {
profile()->GetPrefs(), this);
}
-void LanguagesPageView::NotifyPrefChanged(const std::wstring* pref_name) {
+void LanguagesPageView::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name || *pref_name == prefs::kAcceptLanguages) {
language_order_table_model_->SetAcceptLanguagesString(
accept_languages_.GetValue());
diff --git a/chrome/browser/views/options/languages_page_view.h b/chrome/browser/views/options/languages_page_view.h
index 7342ad1..ace044e 100644
--- a/chrome/browser/views/options/languages_page_view.h
+++ b/chrome/browser/views/options/languages_page_view.h
@@ -4,8 +4,9 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_LANGUAGES_PAGE_VIEW_H__
#define CHROME_BROWSER_VIEWS_OPTIONS_LANGUAGES_PAGE_VIEW_H__
+#pragma once
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "views/controls/combobox/combobox.h"
#include "views/controls/button/button.h"
@@ -51,7 +52,7 @@ class LanguagesPageView : public OptionsPageView,
protected:
// OptionsPageView implementation:
virtual void InitControlLayout();
- virtual void NotifyPrefChanged(const std::wstring* pref_name);
+ virtual void NotifyPrefChanged(const std::string* pref_name);
// views::Combobox::Listener implementation:
virtual void ItemChanged(views::Combobox* sender,
diff --git a/chrome/browser/views/options/managed_prefs_banner_view.cc b/chrome/browser/views/options/managed_prefs_banner_view.cc
index 09febc4..e063d14 100644
--- a/chrome/browser/views/options/managed_prefs_banner_view.cc
+++ b/chrome/browser/views/options/managed_prefs_banner_view.cc
@@ -20,7 +20,7 @@ static const int kPrefsBannerBorderSize = 1;
ManagedPrefsBannerView::ManagedPrefsBannerView(PrefService* prefs,
OptionsPage page)
- : ManagedPrefsBannerBase(prefs, page) {
+ : policy::ManagedPrefsBannerBase(prefs, page) {
content_ = new views::View;
SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
views::Border* border = views::Border::CreateSolidBorder(
@@ -38,6 +38,7 @@ void ManagedPrefsBannerView::Init() {
content_->SetLayoutManager(
new views::BoxLayout(views::BoxLayout::kHorizontal,
kPrefsBannerPadding,
+ kPrefsBannerPadding,
kRelatedControlSmallHorizontalSpacing));
content_->AddChildView(warning_image_);
content_->AddChildView(label_);
diff --git a/chrome/browser/views/options/managed_prefs_banner_view.h b/chrome/browser/views/options/managed_prefs_banner_view.h
index 6002ada..f34ab30 100644
--- a/chrome/browser/views/options/managed_prefs_banner_view.h
+++ b/chrome/browser/views/options/managed_prefs_banner_view.h
@@ -4,8 +4,9 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_MANAGED_PREFS_BANNER_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_MANAGED_PREFS_BANNER_VIEW_H_
+#pragma once
-#include "chrome/browser/managed_prefs_banner_base.h"
+#include "chrome/browser/policy/managed_prefs_banner_base.h"
#include "views/view.h"
namespace views {
@@ -16,7 +17,7 @@ class Label;
// Displays a banner showing a warning message that tells the user some options
// cannot be changed because the relevant preferences are managed by their
// system administrator.
-class ManagedPrefsBannerView : public ManagedPrefsBannerBase,
+class ManagedPrefsBannerView : public policy::ManagedPrefsBannerBase,
public views::View {
public:
// Initialize the banner. |page| is used to determine the names of the
diff --git a/chrome/browser/views/options/options_group_view.cc b/chrome/browser/views/options/options_group_view.cc
index 1e742b4..14131b7 100644
--- a/chrome/browser/views/options/options_group_view.cc
+++ b/chrome/browser/views/options/options_group_view.cc
@@ -51,7 +51,6 @@ OptionsGroupView::OptionsGroupView(views::View* contents,
SetAccessibleName(title);
contents->SetAccessibleName(title);
- contents->SetAccessibleRole(AccessibilityTypes::ROLE_GROUPING);
}
void OptionsGroupView::SetHighlighted(bool highlighted) {
@@ -66,9 +65,8 @@ int OptionsGroupView::GetContentsWidth() const {
///////////////////////////////////////////////////////////////////////////////
// OptionsGroupView, views::View overrides:
-bool OptionsGroupView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+AccessibilityTypes::Role OptionsGroupView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
void OptionsGroupView::Paint(gfx::Canvas* canvas) {
diff --git a/chrome/browser/views/options/options_group_view.h b/chrome/browser/views/options/options_group_view.h
index 83a638f..69b4efa 100644
--- a/chrome/browser/views/options/options_group_view.h
+++ b/chrome/browser/views/options/options_group_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_OPTIONS_GROUP_VIEW_H__
#define CHROME_BROWSER_VIEWS_OPTIONS_OPTIONS_GROUP_VIEW_H__
+#pragma once
#include "views/view.h"
@@ -34,7 +35,7 @@ class OptionsGroupView : public views::View {
protected:
// views::View overrides:
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual void Paint(gfx::Canvas* canvas);
virtual void ViewHierarchyChanged(bool is_add,
views::View* parent,
diff --git a/chrome/browser/views/options/options_page_view.cc b/chrome/browser/views/options/options_page_view.cc
index 933ee9a..6073442 100644
--- a/chrome/browser/views/options/options_page_view.cc
+++ b/chrome/browser/views/options/options_page_view.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/notification_service.h"
#include "views/widget/widget.h"
@@ -36,8 +36,7 @@ void OptionsPageView::ViewHierarchyChanged(bool is_add,
}
}
-bool OptionsPageView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- *role = AccessibilityTypes::ROLE_PAGETAB;
- return true;
+AccessibilityTypes::Role OptionsPageView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_PAGETAB;
}
diff --git a/chrome/browser/views/options/options_page_view.h b/chrome/browser/views/options/options_page_view.h
index 289b00a..698cb99 100644
--- a/chrome/browser/views/options/options_page_view.h
+++ b/chrome/browser/views/options/options_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_OPTIONS_PAGE_VIEW_H__
#define CHROME_BROWSER_VIEWS_OPTIONS_OPTIONS_PAGE_VIEW_H__
+#pragma once
#include "chrome/browser/options_page_base.h"
#include "views/controls/link.h"
@@ -39,8 +40,7 @@ class OptionsPageView : public views::View,
virtual void ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child);
-
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
private:
// Whether or not the control layout has been initialized for this page.
diff --git a/chrome/browser/views/options/options_window_view.cc b/chrome/browser/views/options/options_window_view.cc
index 70a043d..d2cb8e2 100644
--- a/chrome/browser/views/options/options_window_view.cc
+++ b/chrome/browser/views/options/options_window_view.cc
@@ -5,11 +5,11 @@
#include "chrome/browser/options_window.h"
#include "app/l10n_util.h"
-#include "app/resource_bundle.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/pref_service.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"
@@ -45,6 +45,7 @@ class OptionsWindowView : public views::View,
return MessageBoxFlags::DIALOGBUTTON_CANCEL;
}
virtual std::wstring GetWindowTitle() const;
+ virtual std::wstring GetWindowName() const;
virtual void WindowClosing();
virtual bool Cancel();
virtual views::View* GetContentsView();
@@ -53,7 +54,7 @@ class OptionsWindowView : public views::View,
virtual void TabSelectedAt(int index);
// views::View overrides:
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual void Layout();
virtual gfx::Size GetPreferredSize();
@@ -103,23 +104,7 @@ OptionsWindowView::~OptionsWindowView() {
void OptionsWindowView::ShowOptionsPage(OptionsPage page,
OptionsGroup highlight_group) {
- if (Browser* b = BrowserList::GetLastActive()) {
- // Move dialog to user expected position.
- gfx::Rect frame_bounds = b->window()->GetRestoredBounds();
- if (b->window()->IsMaximized()) {
- // For maximized window get monitor size as a bounding box.
- WindowSizer::MonitorInfoProvider* provider =
- WindowSizer::CreateDefaultMonitorInfoProvider();
- frame_bounds = provider->GetMonitorWorkAreaMatching(frame_bounds);
- delete provider;
- }
- gfx::Point origin = frame_bounds.origin();
- origin.Offset(
- (frame_bounds.width() - window()->GetBounds().width()) / 2,
- (frame_bounds.height() - window()->GetBounds().height()) / 2);
- window()->SetBounds(gfx::Rect(origin, window()->GetBounds().size()), NULL);
- }
-
+ // Positioning is handled by window_delegate. we just need to show the window.
// This will show invisible windows and bring visible windows to the front.
window()->Show();
@@ -146,6 +131,10 @@ std::wstring OptionsWindowView::GetWindowTitle() const {
l10n_util::GetString(IDS_PRODUCT_NAME));
}
+std::wstring OptionsWindowView::GetWindowName() const {
+ return UTF8ToWide(prefs::kPreferencesWindowPlacement);
+}
+
void OptionsWindowView::WindowClosing() {
// Clear the static instance so that the next time ShowOptionsWindow() is
// called a new window is opened.
@@ -171,9 +160,8 @@ void OptionsWindowView::TabSelectedAt(int index) {
///////////////////////////////////////////////////////////////////////////////
// OptionsWindowView, views::View overrides:
-bool OptionsWindowView::GetAccessibleRole(AccessibilityTypes::Role* role) {
- *role = AccessibilityTypes::ROLE_CLIENT;
- return true;
+AccessibilityTypes::Role OptionsWindowView::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_CLIENT;
}
void OptionsWindowView::Layout() {
diff --git a/chrome/browser/views/options/passwords_exceptions_window_view.h b/chrome/browser/views/options/passwords_exceptions_window_view.h
index fc6a49c..df98697 100644
--- a/chrome/browser/views/options/passwords_exceptions_window_view.h
+++ b/chrome/browser/views/options/passwords_exceptions_window_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_EXCEPTIONS_WINDOW_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_EXCEPTIONS_WINDOW_VIEW_H_
+#pragma once
#include "views/view.h"
#include "views/window/dialog_delegate.h"
diff --git a/chrome/browser/views/options/passwords_page_view.cc b/chrome/browser/views/options/passwords_page_view.cc
index a339683..6d22d5e 100644
--- a/chrome/browser/views/options/passwords_page_view.cc
+++ b/chrome/browser/views/options/passwords_page_view.cc
@@ -9,7 +9,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
@@ -33,6 +33,9 @@ MultiLabelButtons::MultiLabelButtons(views::ButtonListener* listener,
}
gfx::Size MultiLabelButtons::GetPreferredSize() {
+ if (!IsVisible())
+ return gfx::Size();
+
if (pref_size_.IsEmpty()) {
// Let's compute our preferred size.
std::wstring current_label = label();
@@ -73,7 +76,8 @@ std::wstring PasswordsTableModel::GetText(int row,
case IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN: { // Site.
// Force URL to have LTR directionality.
std::wstring url(saved_signons_[row]->display_url.display_url());
- base::i18n::GetDisplayStringInLTRDirectionality(&url);
+ url = UTF16ToWide(base::i18n::GetDisplayStringInLTRDirectionality(
+ WideToUTF16(url)));
return url;
}
case IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN: { // Username.
@@ -184,6 +188,9 @@ PasswordsPageView::PasswordsPageView(Profile* profile)
table_model_(profile),
table_view_(NULL),
current_selected_password_(NULL) {
+ allow_show_passwords_.Init(prefs::kPasswordManagerAllowShowPasswords,
+ profile->GetPrefs(),
+ this);
}
PasswordsPageView::~PasswordsPageView() {
@@ -237,14 +244,13 @@ void PasswordsPageView::ButtonPressed(
if (sender == &remove_button_) {
table_model_.ForgetAndRemoveSignon(row);
} else if (sender == &show_button_) {
- if (password_label_.GetText().length() == 0) {
+ if (password_label_.GetText().length() == 0 &&
+ allow_show_passwords_.GetValue()) {
password_label_.SetText(selected->password_value);
show_button_.SetLabel(
l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON));
} else {
- password_label_.SetText(L"");
- show_button_.SetLabel(
- l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON));
+ HidePassword();
}
} else {
NOTREACHED() << "Invalid button.";
@@ -340,3 +346,22 @@ void PasswordsPageView::SetupTable() {
table_view_->SetSortDescriptors(sort);
table_view_->SetObserver(this);
}
+
+void PasswordsPageView::HidePassword() {
+ password_label_.SetText(L"");
+ show_button_.SetLabel(
+ l10n_util::GetString(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON));
+}
+
+void PasswordsPageView::NotifyPrefChanged(const std::string* pref_name) {
+ if (!pref_name || *pref_name == prefs::kPasswordManagerAllowShowPasswords) {
+ bool show = allow_show_passwords_.GetValue();
+ if (!show)
+ HidePassword();
+ show_button_.SetVisible(show);
+ password_label_.SetVisible(show);
+ // Update the layout (it may depend on the button size).
+ show_button_.InvalidateLayout();
+ Layout();
+ }
+}
diff --git a/chrome/browser/views/options/passwords_page_view.h b/chrome/browser/views/options/passwords_page_view.h
index 2f065b3..418fcbe 100644
--- a/chrome/browser/views/options/passwords_page_view.h
+++ b/chrome/browser/views/options/passwords_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_PASSWORDS_PAGE_VIEW_H_
+#pragma once
#include <vector>
@@ -13,6 +14,7 @@
#include "base/stl_util-inl.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/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"
#include "views/controls/button/native_button.h"
@@ -173,6 +175,12 @@ class PasswordsPageView : public OptionsPageView,
// Helper to configure our table view.
void SetupTable();
+ // Helper that hides the password.
+ void HidePassword();
+
+ // Handles changes to the observed preferences and updates the UI.
+ void NotifyPrefChanged(const std::string* pref_name);
+
PasswordsTableModel table_model_;
views::TableView* table_view_;
@@ -183,6 +191,9 @@ class PasswordsPageView : public OptionsPageView,
views::Label password_label_;
webkit_glue::PasswordForm* current_selected_password_;
+ // Tracks the preference that controls whether showing passwords is allowed.
+ BooleanPrefMember allow_show_passwords_;
+
DISALLOW_COPY_AND_ASSIGN(PasswordsPageView);
};
diff --git a/chrome/browser/views/options/plugin_filter_page_view.h b/chrome/browser/views/options/plugin_filter_page_view.h
index 47faa8a..6dc6af9 100644
--- a/chrome/browser/views/options/plugin_filter_page_view.h
+++ b/chrome/browser/views/options/plugin_filter_page_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_PLUGIN_FILTER_PAGE_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_PLUGIN_FILTER_PAGE_VIEW_H_
+#pragma once
#include "chrome/browser/views/options/content_filter_page_view.h"
diff --git a/chrome/browser/views/options/simple_content_exceptions_view.h b/chrome/browser/views/options/simple_content_exceptions_view.h
index 5124532..b0ab00a 100644
--- a/chrome/browser/views/options/simple_content_exceptions_view.h
+++ b/chrome/browser/views/options/simple_content_exceptions_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_OPTIONS_SIMPLE_CONTENT_EXCEPTIONS_VIEW_H_
#define CHROME_BROWSER_VIEWS_OPTIONS_SIMPLE_CONTENT_EXCEPTIONS_VIEW_H_
+#pragma once
#include <string>
diff --git a/chrome/browser/views/page_info_window_view.cc b/chrome/browser/views/page_info_window_view.cc
index ea573d8..aa833ab 100644
--- a/chrome/browser/views/page_info_window_view.cc
+++ b/chrome/browser/views/page_info_window_view.cc
@@ -82,7 +82,7 @@ class PageInfoWindowView : public views::View,
virtual void ModelChanged();
private:
- // This retreives the sections from the model and lay them out.
+ // This retrieves the sections from the model and lays them out.
void LayoutSections();
// Offsets the specified rectangle so it is showing on the screen and shifted
@@ -217,8 +217,9 @@ void PageInfoWindowView::LayoutSections() {
for (int i = 0; i < model_.GetSectionCount(); ++i) {
PageInfoModel::SectionInfo info = model_.GetSectionInfo(i);
layout->StartRow(0, 0);
- layout->AddView(new Section(info.title, info.state, info.head_line,
- info.description));
+ layout->AddView(new Section(
+ info.title, info.state == PageInfoModel::SECTION_STATE_OK,
+ info.headline, info.description));
layout->AddPaddingRow(0, kVerticalPadding);
}
layout->AddPaddingRow(1, kVerticalPadding);
@@ -240,7 +241,7 @@ std::wstring PageInfoWindowView::GetWindowTitle() const {
}
std::wstring PageInfoWindowView::GetWindowName() const {
- return prefs::kPageInfoWindowPlacement;
+ return UTF8ToWide(prefs::kPageInfoWindowPlacement);
}
views::View* PageInfoWindowView::GetContentsView() {
@@ -343,7 +344,9 @@ Section::Section(const string16& title,
if (!good_state_icon_) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
good_state_icon_ = rb.GetBitmapNamed(IDR_PAGEINFO_GOOD);
- bad_state_icon_ = rb.GetBitmapNamed(IDR_PAGEINFO_BAD);
+ // The exclamation point has been re-purposed as a warning
+ // signal in the new code.
+ bad_state_icon_ = rb.GetBitmapNamed(IDR_PAGEINFO_WARNING_MAJOR);
}
title_label_ = new views::Label(UTF16ToWideHack(title));
title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
diff --git a/chrome/browser/views/pinned_contents_info_bubble.h b/chrome/browser/views/pinned_contents_info_bubble.h
index 8033b39..29cd597 100644
--- a/chrome/browser/views/pinned_contents_info_bubble.h
+++ b/chrome/browser/views/pinned_contents_info_bubble.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_
#define CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_
+#pragma once
#include "chrome/browser/views/info_bubble.h"
diff --git a/chrome/browser/views/reload_button.cc b/chrome/browser/views/reload_button.cc
index 5ebd9bd..71dc5b1 100644
--- a/chrome/browser/views/reload_button.cc
+++ b/chrome/browser/views/reload_button.cc
@@ -32,11 +32,18 @@ void ReloadButton::ChangeMode(Mode mode, bool force) {
// If the change is forced, or the user isn't hovering the icon, or it's safe
// to change it to the other image type, make the change immediately;
// otherwise we'll let it happen later.
- if (force || (state() != BS_HOT) || ((mode == MODE_STOP) ?
+ if (force || !IsMouseHovered() || ((mode == MODE_STOP) ?
!timer_.IsRunning() : (visible_mode_ != MODE_STOP))) {
timer_.Stop();
SetToggled(mode == MODE_STOP);
visible_mode_ = mode;
+ SetEnabled(true);
+
+ // We want to disable the button if we're preventing a change from stop to
+ // reload due to hovering, but not if we're preventing a change from reload to
+ // stop due to the timer running. (There is no disabled reload state.)
+ } else if (visible_mode_ != MODE_RELOAD) {
+ SetEnabled(false);
}
}
@@ -59,8 +66,7 @@ void ReloadButton::ButtonPressed(views::Button* button,
int flags = mouse_event_flags();
if (event.IsShiftDown() || event.IsControlDown()) {
command = IDC_RELOAD_IGNORING_CACHE;
- // Mask off shift/ctrl so they aren't interpreted as affecting the
- // disposition below.
+ // Mask off Shift and Control so they don't affect the disposition below.
flags &= ~(views::Event::EF_SHIFT_DOWN | views::Event::EF_CONTROL_DOWN);
} else {
command = IDC_RELOAD;
@@ -75,17 +81,16 @@ void ReloadButton::ButtonPressed(views::Button* button,
location_bar_->Revert();
}
- browser_->ExecuteCommandWithDisposition(command, disposition);
-
- // Stop the timer.
- timer_.Stop();
-
// Start a timer - while this timer is running, the reload button cannot be
// changed to a stop button. We do not set |intended_mode_| to MODE_STOP
- // here as we want to wait for the browser to tell us that it has started
- // loading (and this may occur only after some delay).
+ // here as the browser will do that when it actually starts loading (which
+ // may happen synchronously, thus the need to do this before telling the
+ // browser to execute the reload command).
+ timer_.Stop();
timer_.Start(base::TimeDelta::FromMilliseconds(GetDoubleClickTimeMS()),
this, &ReloadButton::OnButtonTimer);
+
+ browser_->ExecuteCommandWithDisposition(command, disposition);
}
}
@@ -108,5 +113,5 @@ bool ReloadButton::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
// ReloadButton, private:
void ReloadButton::OnButtonTimer() {
- ChangeMode(intended_mode_, true);
+ ChangeMode(intended_mode_, false);
}
diff --git a/chrome/browser/views/reload_button.h b/chrome/browser/views/reload_button.h
index 20991f9..6a8c29c 100644
--- a/chrome/browser/views/reload_button.h
+++ b/chrome/browser/views/reload_button.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_RELOAD_BUTTON_H__
#define CHROME_BROWSER_VIEWS_RELOAD_BUTTON_H__
+#pragma once
#include "base/basictypes.h"
#include "base/timer.h"
diff --git a/chrome/browser/views/repost_form_warning_view.h b/chrome/browser/views/repost_form_warning_view.h
index a6932af..b4e56a6 100644
--- a/chrome/browser/views/repost_form_warning_view.h
+++ b/chrome/browser/views/repost_form_warning_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_REPOST_FORM_WARNING_VIEW_H_
#define CHROME_BROWSER_VIEWS_REPOST_FORM_WARNING_VIEW_H_
+#pragma once
#include "chrome/browser/tab_contents/constrained_window.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/views/restart_message_box.h b/chrome/browser/views/restart_message_box.h
index 895937c..816fe6c 100644
--- a/chrome/browser/views/restart_message_box.h
+++ b/chrome/browser/views/restart_message_box.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_RESTART_MESSAGE_BOX_H_
#define CHROME_BROWSER_VIEWS_RESTART_MESSAGE_BOX_H_
+#pragma once
#include "base/basictypes.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/views/sad_tab_view.cc b/chrome/browser/views/sad_tab_view.cc
index e02d975..31f45fd 100644
--- a/chrome/browser/views/sad_tab_view.cc
+++ b/chrome/browser/views/sad_tab_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/browser/tab_contents/tab_contents_delegate.h"
#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
#include "gfx/size.h"
@@ -53,9 +54,9 @@ SadTabView::SadTabView(TabContents* tab_contents)
void SadTabView::Paint(gfx::Canvas* canvas) {
SkPaint paint;
- paint.setShader(gfx::CreateGradientShader(0, height(),
- kBackgroundColor,
- kBackgroundEndColor))->safeUnref();
+ SkSafeUnref(paint.setShader(gfx::CreateGradientShader(0, height(),
+ kBackgroundColor,
+ kBackgroundEndColor)));
paint.setStyle(SkPaint::kFill_Style);
canvas->AsCanvasSkia()->drawRectCoords(
0, 0, SkIntToScalar(width()), SkIntToScalar(height()), paint);
@@ -86,7 +87,7 @@ void SadTabView::Layout() {
int title_x = (width() - title_width_) / 2;
int title_y = icon_bounds_.bottom() + kIconTitleSpacing;
- int title_height = title_font_->height();
+ int title_height = title_font_->GetHeight();
title_bounds_.SetRect(title_x, title_y, title_width_, title_height);
gfx::CanvasSkia cc(0, 0, true);
@@ -110,7 +111,16 @@ void SadTabView::Layout() {
void SadTabView::LinkActivated(views::Link* source, int event_flags) {
if (tab_contents_ != NULL && source == learn_more_link_) {
string16 url = l10n_util::GetStringUTF16(IDS_CRASH_REASON_URL);
- tab_contents_->OpenURL(GURL(url), GURL(), CURRENT_TAB,
+ WindowOpenDisposition disposition(CURRENT_TAB);
+#if defined(OS_CHROMEOS)
+ if (tab_contents_->delegate() &&
+ tab_contents_->delegate()->IsPopup(tab_contents_)) {
+ // Popup windows are generally too small to effectively show help,
+ // so open the help content in a new foregreound tab.
+ disposition = NEW_FOREGROUND_TAB;
+ }
+#endif
+ tab_contents_->OpenURL(GURL(url), GURL(), disposition,
PageTransition::LINK);
}
}
diff --git a/chrome/browser/views/sad_tab_view.h b/chrome/browser/views/sad_tab_view.h
index fff7213..11f2626 100644
--- a/chrome/browser/views/sad_tab_view.h
+++ b/chrome/browser/views/sad_tab_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_SAD_TAB_VIEW_H_
#define CHROME_BROWSER_VIEWS_SAD_TAB_VIEW_H_
+#pragma once
#include "base/basictypes.h"
#include "gfx/font.h"
diff --git a/chrome/browser/views/select_file_dialog.cc b/chrome/browser/views/select_file_dialog.cc
index 0d523a8..523f817 100644
--- a/chrome/browser/views/select_file_dialog.cc
+++ b/chrome/browser/views/select_file_dialog.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/browser/profile_manager.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/browser_dialogs.h"
@@ -25,14 +26,12 @@
#include "views/window/non_client_view.h"
#include "views/window/window.h"
-#include "chrome/browser/profile_manager.h"
-
namespace {
-static const wchar_t* kKeyNamePath = L"path";
-static const int kSaveCompletePageIndex = 2;
+const char kKeyNamePath[] = "path";
+const int kSaveCompletePageIndex = 2;
-}; // namespace
+} // namespace
// Implementation of SelectFileDialog that shows an UI for choosing a file
// or folder using FileBrowseUI.
@@ -128,7 +127,7 @@ class SelectFileDialogImpl : public SelectFileDialog {
virtual void RegisterMessages();
// Callback for the "setDialogTitle" message.
- void HandleSetDialogTitle(const Value* value);
+ void HandleSetDialogTitle(const ListValue* args);
private:
FileBrowseDelegate* delegate_;
@@ -257,10 +256,10 @@ void SelectFileDialogImpl::OnDialogClosed(FileBrowseDelegate* delegate,
if (delegate->type_ == SELECT_OPEN_FILE ||
delegate->type_ == SELECT_SAVEAS_FILE ||
delegate->type_ == SELECT_FOLDER) {
- std::wstring path_string;
+ std::string path_string;
if (dict->HasKey(kKeyNamePath) &&
dict->GetString(kKeyNamePath, &path_string)) {
- FilePath path = FilePath::FromWStringHack(path_string);
+ FilePath path = FilePath::FromWStringHack(UTF8ToWide(path_string));
listener_->FileSelected(path, kSaveCompletePageIndex,
delegate->params_);
@@ -274,10 +273,11 @@ void SelectFileDialogImpl::OnDialogClosed(FileBrowseDelegate* delegate,
std::vector<FilePath> paths;
paths.reserve(paths_value->GetSize());
for (size_t i = 0; i < paths_value->GetSize(); ++i) {
- std::wstring path_string;
+ std::string path_string;
if (paths_value->GetString(i, &path_string) &&
!path_string.empty()) {
- paths.push_back(FilePath::FromWStringHack(path_string));
+ paths.push_back(FilePath::FromWStringHack(
+ UTF8ToWide(path_string)));
}
}
@@ -460,8 +460,8 @@ void SelectFileDialogImpl::FileBrowseDelegateHandler::RegisterMessages() {
}
void SelectFileDialogImpl::FileBrowseDelegateHandler::HandleSetDialogTitle(
- const Value* value) {
- std::wstring new_title = ExtractStringValue(value);
+ const ListValue* args) {
+ std::wstring new_title = ExtractStringValue(args);
if (new_title != delegate_->title_) {
delegate_->title_ = new_title;
diff --git a/chrome/browser/views/shell_dialogs_win.cc b/chrome/browser/views/shell_dialogs_win.cc
index aa82167..71e2918 100644
--- a/chrome/browser/views/shell_dialogs_win.cc
+++ b/chrome/browser/views/shell_dialogs_win.cc
@@ -12,11 +12,11 @@
#include <set>
#include "app/l10n_util.h"
-#include "app/win_util.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/registry.h"
#include "base/scoped_comptr_win.h"
+#include "base/string_split.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
#include "base/win_util.h"
@@ -24,7 +24,6 @@
#include "gfx/font.h"
#include "grit/app_strings.h"
#include "grit/generated_resources.h"
-#include "net/base/mime_util.h"
// This function takes the output of a SaveAs dialog: a filename, a filter and
// the extension originally suggested to the user (shown in the dialog box) and
@@ -42,11 +41,16 @@ std::wstring AppendExtensionIfNeeded(const std::wstring& filename,
DCHECK(!filename.empty());
std::wstring return_value = filename;
- // If the user didn't give us a known extension, and we wanted one, add it.
- std::string selected_mime_type;
+ // If we wanted a specific extension, but the user's filename deleted it or
+ // changed it to something that the system doesn't understand, re-append.
+ // Careful: Checking net::GetMimeTypeFromExtension() will only find
+ // extensions with a known MIME type, which many "known" extensions on Windows
+ // don't have. So we check directly for the "known extension" registry key.
+ std::wstring file_extension(file_util::GetFileExtensionFromPath(filename));
+ std::wstring key(L"." + file_extension);
if (!(filter_selected.empty() || filter_selected == L"*.*") &&
- !net::GetMimeTypeFromExtension(
- file_util::GetFileExtensionFromPath(filename), &selected_mime_type)) {
+ !RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
+ file_extension != suggested_ext) {
if (return_value[return_value.length() - 1] != L'.')
return_value.append(L".");
return_value.append(suggested_ext);
@@ -843,7 +847,7 @@ bool SelectFileDialogImpl::RunOpenFileDialog(
// Use lpstrInitialDir to specify the initial directory
if (!path->empty()) {
bool is_dir;
- file_util::FileInfo file_info;
+ base::PlatformFileInfo file_info;
if (file_util::GetFileInfo(*path, &file_info))
is_dir = file_info.is_directory;
else
@@ -1104,7 +1108,7 @@ void SelectFontDialogImpl::FontSelected(LOGFONT logfont,
if (listener_) {
HFONT font = CreateFontIndirect(&logfont);
if (font) {
- listener_->FontSelected(gfx::Font::CreateFont(font), params);
+ listener_->FontSelected(gfx::Font(font), params);
DeleteObject(font);
} else {
listener_->FontSelectionCanceled(params);
diff --git a/chrome/browser/views/shell_dialogs_win_unittest.cc b/chrome/browser/views/shell_dialogs_win_unittest.cc
index b267e16..0c2cad5 100644
--- a/chrome/browser/views/shell_dialogs_win_unittest.cc
+++ b/chrome/browser/views/shell_dialogs_win_unittest.cc
@@ -5,68 +5,40 @@
#include "chrome/browser/shell_dialogs.h"
#include "testing/gtest/include/gtest/gtest.h"
-TEST(AppendExtensionIfNeeded, EndingInPeriod_ExtensionAppended) {
- const std::wstring filename = L"sample.txt.";
- const std::wstring filter_selected = L"*.txt";
- const std::wstring suggested_ext = L"txt";
-
- const std::wstring actual_filename = AppendExtensionIfNeeded(filename,
- filter_selected, suggested_ext);
-
- ASSERT_EQ(L"sample.txt.txt", actual_filename);
-}
-
-TEST(AppendExtensionIfNeeded, UnknownMimeType_ExtensionAppended) {
- const std::wstring filename = L"sample.unknown-mime-type";
- const std::wstring filter_selected = L"*.txt";
- const std::wstring suggested_ext = L"txt";
-
- const std::wstring actual_filename = AppendExtensionIfNeeded(filename,
- filter_selected, suggested_ext);
-
- ASSERT_EQ(L"sample.unknown-mime-type.txt", actual_filename);
-}
-
-TEST(AppendExtensionIfNeeded, RecognizableMimeType_NoExtensionAppended) {
- const std::wstring filename = L"sample.html";
- const std::wstring filter_selected = L"*.txt";
- const std::wstring suggested_ext = L"txt";
-
- const std::wstring actual_filename = AppendExtensionIfNeeded(filename,
- filter_selected, suggested_ext);
-
- ASSERT_EQ(L"sample.html", actual_filename);
-}
-
-TEST(AppendExtensionIfNeeded, OnlyPeriods_ExtensionAppended) {
- const std::wstring filename = L"...";
- const std::wstring filter_selected = L"*.txt";
- const std::wstring suggested_ext = L"txt";
-
- const std::wstring actual_filename = AppendExtensionIfNeeded(filename,
- filter_selected, suggested_ext);
-
- ASSERT_EQ(L"...txt", actual_filename);
-}
-
-TEST(AppendExtensionIfNeeded, EqualToExtension_ExtensionAppended) {
- const std::wstring filename = L"txt";
- const std::wstring filter_selected = L"*.txt";
- const std::wstring suggested_ext = L"txt";
-
- const std::wstring actual_filename = AppendExtensionIfNeeded(filename,
- filter_selected, suggested_ext);
-
- ASSERT_EQ(L"txt.txt", actual_filename);
-}
-
-TEST(AppendExtensionIfNeeded, AllFilesFilter_NoExtensionAppended) {
- const std::wstring filename = L"sample.unknown-mime-type";
- const std::wstring filter_selected = L"*.*";
- const std::wstring suggested_ext;
-
- const std::wstring actual_filename = AppendExtensionIfNeeded(filename,
- filter_selected, suggested_ext);
-
- ASSERT_EQ(L"sample.unknown-mime-type", actual_filename);
+TEST(ShellDialogsWin, AppendExtensionIfNeeded) {
+ struct AppendExtensionTestCase {
+ wchar_t* filename;
+ wchar_t* filter_selected;
+ wchar_t* suggested_ext;
+ wchar_t* expected_filename;
+ } test_cases[] = {
+ // Known extensions, with or without associated MIME types, should not get
+ // an extension appended.
+ { L"sample.html", L"*.txt", L"txt", L"sample.html" },
+ { L"sample.reg", L"*.txt", L"txt", L"sample.reg" },
+
+ // An unknown extension, or no extension, should get the default extension
+ // appended.
+ { L"sample.unknown", L"*.txt", L"txt", L"sample.unknown.txt" },
+ { L"sample", L"*.txt", L"txt", L"sample.txt" },
+ // ...unless the unknown and default extensions match.
+ { L"sample.unknown", L"*.unknown", L"unknown", L"sample.unknown" },
+
+ // The extension alone should be treated like a filename with no extension.
+ { L"txt", L"*.txt", L"txt", L"txt.txt" },
+
+ // Trailing dots should cause us to append an extension.
+ { L"sample.txt.", L"*.txt", L"txt", L"sample.txt.txt" },
+ { L"...", L"*.txt", L"txt", L"...txt" },
+
+ // If the filter is changed to "All files", we allow any filename.
+ { L"sample.unknown", L"*.*", L"", L"sample.unknown" },
+ };
+
+ for (size_t i = 0; i < arraysize(test_cases); ++i) {
+ EXPECT_EQ(std::wstring(test_cases[i].expected_filename),
+ AppendExtensionIfNeeded(test_cases[i].filename,
+ test_cases[i].filter_selected,
+ test_cases[i].suggested_ext));
+ }
}
diff --git a/chrome/browser/views/ssl_client_certificate_selector_win.cc b/chrome/browser/views/ssl_client_certificate_selector_win.cc
index cf5ad4f..d78151d 100644
--- a/chrome/browser/views/ssl_client_certificate_selector_win.cc
+++ b/chrome/browser/views/ssl_client_certificate_selector_win.cc
@@ -4,29 +4,34 @@
#include "chrome/browser/ssl_client_certificate_selector.h"
+#include <windows.h>
#include <cryptuiapi.h>
#pragma comment(lib, "cryptui.lib")
#include "app/l10n_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chrome_thread.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/url_request/url_request.h"
namespace browser {
void ShowSSLClientCertificateSelector(
- gfx::NativeWindow parent,
+ TabContents* parent,
net::SSLCertRequestInfo* cert_request_info,
SSLClientAuthHandler* delegate) {
- net::X509Certificate* cert = NULL;
// TODO(jcampan): replace this with our own cert selection dialog.
// CryptUIDlgSelectCertificateFromStore is blocking (but still processes
// Windows messages), which is scary.
+ //
+ // TODO(davidben): Make this dialog tab-modal to the
+ // TabContents. This depends on the above TODO.
HCERTSTORE client_certs = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL,
0, NULL);
BOOL ok;
@@ -42,13 +47,20 @@ void ShowSSLClientCertificateSelector(
IDS_CLIENT_CERT_DIALOG_TEXT,
ASCIIToWide(cert_request_info->host_and_port));
PCCERT_CONTEXT cert_context = CryptUIDlgSelectCertificateFromStore(
- client_certs, parent, title.c_str(), text.c_str(), 0, 0, NULL);
+ client_certs, parent->GetMessageBoxRootWindow(),
+ title.c_str(), text.c_str(), 0, 0, NULL);
+ net::X509Certificate* cert = NULL;
if (cert_context) {
- cert = net::X509Certificate::CreateFromHandle(
- cert_context,
- net::X509Certificate::SOURCE_LONE_CERT_IMPORT,
- net::X509Certificate::OSCertHandles());
+ for (size_t i = 0; i < cert_request_info->client_certs.size(); ++i) {
+ net::X509Certificate* client_cert = cert_request_info->client_certs[i];
+ if (net::X509Certificate::IsSameOSCert(cert_context,
+ client_cert->os_cert_handle())) {
+ cert = client_cert;
+ break;
+ }
+ }
+ DCHECK(cert != NULL);
net::X509Certificate::FreeOSCertHandle(cert_context);
}
diff --git a/chrome/browser/views/status_bubble_views.cc b/chrome/browser/views/status_bubble_views.cc
index 71be04d..2f92daf 100644
--- a/chrome/browser/views/status_bubble_views.cc
+++ b/chrome/browser/views/status_bubble_views.cc
@@ -7,13 +7,13 @@
#include <algorithm>
#include "app/linear_animation.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/text_elider.h"
#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/string_util.h"
-#include "chrome/browser/browser_theme_provider.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "gfx/canvas_skia.h"
#include "gfx/point.h"
#include "googleurl/src/gurl.h"
@@ -112,7 +112,7 @@ class StatusBubbleViews::StatusView : public views::Label,
// Set the bubble text to a certain value, hides the bubble if text is
// an empty string. Trigger animation sequence to display if
// |should_animate_open|.
- void SetText(const std::wstring& text, bool should_animate_open);
+ void SetText(const string16& text, bool should_animate_open);
BubbleStage GetState() const { return stage_; }
@@ -164,7 +164,7 @@ class StatusBubbleViews::StatusView : public views::Label,
views::Widget* popup_;
// The currently-displayed text.
- std::wstring text_;
+ string16 text_;
// Start and end opacities for the current transition - note that as a
// fade-in can easily turn into a fade out, opacity_start_ is sometimes
@@ -176,8 +176,8 @@ class StatusBubbleViews::StatusView : public views::Label,
ThemeProvider* theme_provider_;
};
-void StatusBubbleViews::StatusView::SetText(
- const std::wstring& text, bool should_animate_open) {
+void StatusBubbleViews::StatusView::SetText(const string16& text,
+ bool should_animate_open) {
if (text.empty()) {
// The string was empty.
StartHiding();
@@ -428,7 +428,8 @@ void StatusBubbleViews::StatusView::Paint(gfx::Canvas* canvas) {
// Draw highlight text and then the text body. In order to make sure the text
// is aligned to the right on RTL UIs, we mirror the text bounds if the
// locale is RTL.
- int text_width = std::min(views::Label::font().GetStringWidth(text_),
+ int text_width = std::min(
+ views::Label::font().GetStringWidth(UTF16ToWide(text_)),
width - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding);
int text_height = height - (kShadowThickness * 2);
gfx::Rect body_bounds(kShadowThickness + kTextPositionX,
@@ -445,7 +446,7 @@ void StatusBubbleViews::StatusView::Paint(gfx::Canvas* canvas) {
(SkColorGetR(text_color) + SkColorGetR(toolbar_color)) / 2,
(SkColorGetG(text_color) + SkColorGetR(toolbar_color)) / 2,
(SkColorGetB(text_color) + SkColorGetR(toolbar_color)) / 2);
- canvas->DrawStringInt(text_,
+ canvas->DrawStringInt(UTF16ToWide(text_),
views::Label::font(),
text_color,
body_bounds.x(),
@@ -471,7 +472,7 @@ class StatusBubbleViews::StatusViewExpander : public LinearAnimation,
}
// Manage the expansion of the bubble.
- void StartExpansion(std::wstring expanded_text, int current_width,
+ void StartExpansion(string16 expanded_text, int current_width,
int expansion_end);
// Set width of fully expanded bubble.
@@ -491,7 +492,7 @@ class StatusBubbleViews::StatusViewExpander : public LinearAnimation,
StatusView* status_view_;
// Text elided (if needed) to fit maximum status bar width.
- std::wstring expanded_text_;
+ string16 expanded_text_;
// Widths at expansion start and end.
int expansion_start_;
@@ -509,7 +510,7 @@ void StatusBubbleViews::StatusViewExpander::AnimationEnded(
}
void StatusBubbleViews::StatusViewExpander::StartExpansion(
- std::wstring expanded_text, int expansion_start,
+ string16 expanded_text, int expansion_start,
int expansion_end) {
expanded_text_ = expanded_text;
expansion_start_ = expansion_start;
@@ -535,11 +536,11 @@ void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) {
const int StatusBubbleViews::kShadowThickness = 1;
-StatusBubbleViews::StatusBubbleViews(views::Widget* frame)
+StatusBubbleViews::StatusBubbleViews(views::View* base_view)
: offset_(0),
popup_(NULL),
opacity_(0),
- frame_(frame),
+ base_view_(base_view),
view_(NULL),
download_shelf_is_visible_(false),
is_expanded_(false),
@@ -559,12 +560,13 @@ void StatusBubbleViews::Init() {
Widget::NotAcceptEvents,
Widget::NotDeleteOnDestroy,
Widget::MirrorOriginInRTL));
+ views::Widget* frame = base_view_->GetWidget();
if (!view_)
- view_ = new StatusView(this, popup_.get(), frame_->GetThemeProvider());
+ view_ = new StatusView(this, popup_.get(), frame->GetThemeProvider());
if (!expand_view_.get())
expand_view_.reset(new StatusViewExpander(this, view_));
popup_->SetOpacity(0x00);
- popup_->Init(frame_->GetNativeView(), gfx::Rect());
+ popup_->Init(frame->GetNativeView(), gfx::Rect());
popup_->SetContentsView(view_);
Reposition();
popup_->Show();
@@ -574,7 +576,7 @@ void StatusBubbleViews::Init() {
void StatusBubbleViews::Reposition() {
if (popup_.get()) {
gfx::Point top_left;
- views::View::ConvertPointToScreen(frame_->GetRootView(), &top_left);
+ views::View::ConvertPointToScreen(base_view_, &top_left);
popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(),
top_left.y() + position_.y(),
@@ -584,26 +586,17 @@ void StatusBubbleViews::Reposition() {
gfx::Size StatusBubbleViews::GetPreferredSize() {
return gfx::Size(0, ResourceBundle::GetSharedInstance().GetFont(
- ResourceBundle::BaseFont).height() + kTotalVerticalPadding);
+ ResourceBundle::BaseFont).GetHeight() + kTotalVerticalPadding);
}
void StatusBubbleViews::SetBounds(int x, int y, int w, int h) {
- // If the UI layout is RTL, we need to mirror the position of the bubble
- // relative to the parent.
- if (base::i18n::IsRTL()) {
- gfx::Rect frame_bounds;
- frame_->GetBounds(&frame_bounds, false);
- int mirrored_x = frame_bounds.width() - x - w;
- position_.SetPoint(mirrored_x, y);
- } else {
- position_.SetPoint(x, y);
- }
-
+ original_position_.SetPoint(x, y);
+ position_.SetPoint(base_view_->MirroredXWithWidthInsideView(x, w), y);
size_.SetSize(w, h);
Reposition();
}
-void StatusBubbleViews::SetStatus(const std::wstring& status_text) {
+void StatusBubbleViews::SetStatus(const string16& status_text) {
if (size_.IsEmpty())
return; // We have no bounds, don't attempt to show the popup.
@@ -621,11 +614,11 @@ void StatusBubbleViews::SetStatus(const std::wstring& status_text) {
} else if (!url_text_.empty()) {
view_->SetText(url_text_, true);
} else {
- view_->SetText(std::wstring(), true);
+ view_->SetText(string16(), true);
}
}
-void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) {
+void StatusBubbleViews::SetURL(const GURL& url, const string16& languages) {
languages_ = languages;
url_ = url;
if (size_.IsEmpty())
@@ -636,7 +629,7 @@ void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) {
// If we want to clear a displayed URL but there is a status still to
// display, display that status instead.
if (url.is_empty() && !status_text_.empty()) {
- url_text_ = std::wstring();
+ url_text_ = string16();
if (IsFrameVisible())
view_->SetText(status_text_, true);
return;
@@ -653,15 +646,16 @@ void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) {
popup_->GetBounds(&popup_bounds, true);
int text_width = static_cast<int>(popup_bounds.width() -
(kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1);
- url_text_ = gfx::ElideUrl(url, view_->Label::font(), text_width,
- languages);
+ url_text_ = WideToUTF16(gfx::ElideUrl(url, view_->Label::font(),
+ text_width, UTF16ToWide(languages)));
- std::wstring original_url_text = net::FormatUrl(url, languages);
+ std::wstring original_url_text =
+ UTF16ToWideHack(net::FormatUrl(url, UTF16ToUTF8(languages)));
// An URL is always treated as a left-to-right string. On right-to-left UIs
// we need to explicitly mark the URL as LTR to make sure it is displayed
// correctly.
- base::i18n::GetDisplayStringInLTRDirectionality(&url_text_);
+ url_text_ = base::i18n::GetDisplayStringInLTRDirectionality(url_text_);
if (IsFrameVisible()) {
view_->SetText(url_text_, true);
@@ -680,8 +674,8 @@ void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) {
}
void StatusBubbleViews::Hide() {
- status_text_ = std::wstring();
- url_text_ = std::wstring();
+ status_text_ = string16();
+ url_text_ = string16();
if (view_)
view_->Hide();
}
@@ -709,9 +703,9 @@ void StatusBubbleViews::UpdateDownloadShelfVisibility(bool visible) {
void StatusBubbleViews::AvoidMouse(const gfx::Point& location) {
// Get the position of the frame.
gfx::Point top_left;
- views::RootView* root = frame_->GetRootView();
- views::View::ConvertPointToScreen(root, &top_left);
- int window_width = root->GetLocalBounds(true).width(); // border included.
+ views::View::ConvertPointToScreen(base_view_, &top_left);
+ // Border included.
+ int window_width = base_view_->GetLocalBounds(true).width();
// Get the cursor position relative to the popup.
gfx::Point relative_location = location;
@@ -757,7 +751,7 @@ void StatusBubbleViews::AvoidMouse(const gfx::Point& location) {
// Check if the bubble sticks out from the monitor or will obscure
// download shelf.
- gfx::NativeView widget = frame_->GetNativeView();
+ gfx::NativeView widget = base_view_->GetWidget()->GetNativeView();
gfx::Rect monitor_rect =
views::Screen::GetMonitorWorkAreaNearestWindow(widget);
const int bubble_bottom_y = top_left.y() + position_.y() + size_.height();
@@ -793,10 +787,11 @@ void StatusBubbleViews::AvoidMouse(const gfx::Point& location) {
}
bool StatusBubbleViews::IsFrameVisible() {
- if (!frame_->IsVisible())
+ views::Widget* frame = base_view_->GetWidget();
+ if (!frame->IsVisible())
return false;
- views::Window* window = frame_->GetWindow();
+ views::Window* window = frame->GetWindow();
return !window || !window->IsMinimized();
}
@@ -806,36 +801,32 @@ void StatusBubbleViews::ExpandBubble() {
gfx::Rect popup_bounds;
popup_->GetBounds(&popup_bounds, true);
int max_status_bubble_width = GetMaxStatusBubbleWidth();
- url_text_ = gfx::ElideUrl(url_, view_->Label::font(),
- max_status_bubble_width, languages_);
- int expanded_bubble_width =
- std::max(GetStandardStatusBubbleWidth(),
- std::min(view_->Label::font().GetStringWidth(url_text_) +
- (kShadowThickness * 2) + kTextPositionX +
- kTextHorizPadding + 1,
- max_status_bubble_width));
+ url_text_ = WideToUTF16(gfx::ElideUrl(url_, view_->Label::font(),
+ max_status_bubble_width, UTF16ToWideHack(languages_)));
+ int expanded_bubble_width =std::max(GetStandardStatusBubbleWidth(),
+ std::min(view_->Label::font().GetStringWidth(UTF16ToWide(url_text_)) +
+ (kShadowThickness * 2) + kTextPositionX +
+ kTextHorizPadding + 1,
+ max_status_bubble_width));
is_expanded_ = true;
expand_view_->StartExpansion(url_text_, popup_bounds.width(),
expanded_bubble_width);
}
int StatusBubbleViews::GetStandardStatusBubbleWidth() {
- gfx::Rect frame_bounds;
- frame_->GetBounds(&frame_bounds, false);
- return frame_bounds.width() / 3;
+ return base_view_->bounds().width() / 3;
}
int StatusBubbleViews::GetMaxStatusBubbleWidth() {
- gfx::Rect frame_bounds;
- frame_->GetBounds(&frame_bounds, false);
- return static_cast<int>(frame_bounds.width() - (kShadowThickness * 2) -
- kTextPositionX - kTextHorizPadding - 1 -
- views::NativeScrollBar::GetVerticalScrollBarWidth());
+ return static_cast<int>(std::max(0, base_view_->bounds().width() -
+ (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1 -
+ views::NativeScrollBar::GetVerticalScrollBarWidth()));
}
void StatusBubbleViews::SetBubbleWidth(int width) {
size_.set_width(width);
- SetBounds(position_.x(), position_.y(), size_.width(), size_.height());
+ SetBounds(original_position_.x(), original_position_.y(),
+ size_.width(), size_.height());
}
void StatusBubbleViews::CancelExpandTimer() {
diff --git a/chrome/browser/views/status_bubble_views.h b/chrome/browser/views/status_bubble_views.h
index 4e0b414..85c1bb2 100644
--- a/chrome/browser/views/status_bubble_views.h
+++ b/chrome/browser/views/status_bubble_views.h
@@ -1,12 +1,14 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_STATUS_BUBBLE_VIEWS_H_
#define CHROME_BROWSER_VIEWS_STATUS_BUBBLE_VIEWS_H_
+#pragma once
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/task.h"
#include "chrome/browser/status_bubble.h"
#include "googleurl/src/gurl.h"
@@ -17,6 +19,7 @@ namespace gfx {
class Point;
}
namespace views {
+class View;
class Widget;
}
@@ -31,7 +34,7 @@ class StatusBubbleViews : public StatusBubble {
// The combined vertical padding above and below the text.
static const int kTotalVerticalPadding = 7;
- explicit StatusBubbleViews(views::Widget* frame);
+ explicit StatusBubbleViews(views::View* base_view);
~StatusBubbleViews();
// Reposition the bubble - as we are using a WS_POPUP for the bubble,
@@ -49,8 +52,8 @@ class StatusBubbleViews : public StatusBubble {
void SetBubbleWidth(int width);
// Overridden from StatusBubble:
- virtual void SetStatus(const std::wstring& status);
- virtual void SetURL(const GURL& url, const std::wstring& languages);
+ 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);
@@ -66,7 +69,7 @@ class StatusBubbleViews : public StatusBubble {
// users to see links in the region normally occupied by the status bubble.
void AvoidMouse(const gfx::Point& location);
- // Returns true if the frame_ is visible and not minimized.
+ // Returns true if the base_view_'s widget is visible and not minimized.
bool IsFrameVisible();
// Expand bubble size to accommodate a long URL.
@@ -83,18 +86,20 @@ class StatusBubbleViews : public StatusBubble {
int GetMaxStatusBubbleWidth();
// The status text we want to display when there are no URLs to display.
- std::wstring status_text_;
+ string16 status_text_;
// The url we want to display when there is no status text to display.
- std::wstring url_text_;
+ string16 url_text_;
// The original, non-elided URL.
GURL url_;
// Used to elide the original URL again when we expand it.
- std::wstring languages_;
+ string16 languages_;
- // Position relative to the parent window.
+ // Position relative to the base_view_.
+ gfx::Point original_position_;
+ // original_position_ adjusted according to the current RTL.
gfx::Point position_;
gfx::Size size_;
@@ -106,7 +111,7 @@ class StatusBubbleViews : public StatusBubble {
scoped_ptr<views::Widget> popup_;
double opacity_;
- views::Widget* frame_;
+ views::View* base_view_;
StatusView* view_;
// Manages the expansion of a status bubble to fit a long URL.
diff --git a/chrome/browser/views/status_icons/status_icon_win.cc b/chrome/browser/views/status_icons/status_icon_win.cc
index 53cfcad..5545560 100644
--- a/chrome/browser/views/status_icons/status_icon_win.cc
+++ b/chrome/browser/views/status_icons/status_icon_win.cc
@@ -4,9 +4,11 @@
#include "chrome/browser/views/status_icons/status_icon_win.h"
-#include "gfx/icon_util.h"
#include "base/sys_string_conversions.h"
+#include "gfx/icon_util.h"
+#include "gfx/point.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "views/controls/menu/menu_2.h"
StatusIconWin::StatusIconWin(UINT id, HWND window, UINT message)
: icon_id_(id),
@@ -58,3 +60,30 @@ void StatusIconWin::InitIconData(NOTIFYICONDATA* icon_data) {
icon_data->hWnd = window_;
icon_data->uID = icon_id_;
}
+
+void StatusIconWin::UpdatePlatformContextMenu(menus::MenuModel* menu) {
+ // If no items are passed, blow away our context menu.
+ if (!menu) {
+ context_menu_.reset();
+ return;
+ }
+
+ // Create context menu with the new contents.
+ context_menu_.reset(new views::Menu2(menu));
+}
+
+void StatusIconWin::HandleClickEvent(int x, int y, bool left_mouse_click) {
+ // Pass to the observer if appropriate.
+ if (left_mouse_click && HasObservers()) {
+ DispatchClickEvent();
+ return;
+ }
+
+ // Event not sent to the observer, so display the context menu if one exists.
+ if (context_menu_.get()) {
+ // Set our window as the foreground window, so the context menu closes when
+ // we click away from it.
+ SetForegroundWindow(window_);
+ context_menu_->RunContextMenuAt(gfx::Point(x, y));
+ }
+}
diff --git a/chrome/browser/views/status_icons/status_icon_win.h b/chrome/browser/views/status_icons/status_icon_win.h
index 46be5ae..08545ac 100644
--- a/chrome/browser/views/status_icons/status_icon_win.h
+++ b/chrome/browser/views/status_icons/status_icon_win.h
@@ -4,13 +4,19 @@
#ifndef CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_ICON_WIN_H_
#define CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_ICON_WIN_H_
+#pragma once
#include <windows.h>
#include <shellapi.h>
#include "base/scoped_handle_win.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/status_icons/status_icon.h"
+namespace views {
+class Menu2;
+}
+
class StatusIconWin : public StatusIcon {
public:
// Constructor which provides this icon's unique ID and messaging window.
@@ -26,6 +32,15 @@ class StatusIconWin : public StatusIcon {
UINT message_id() const { return message_id_; }
+ // Handles a click event from the user - if |left_button_click| is true and
+ // there is a registered observer, passes the click event to the observer,
+ // otherwise displays the context menu if there is one.
+ void HandleClickEvent(int x, int y, bool left_button_click);
+
+ protected:
+ // Overridden from StatusIcon.
+ virtual void UpdatePlatformContextMenu(menus::MenuModel* menu);
+
private:
void InitIconData(NOTIFYICONDATA* icon_data);
@@ -41,6 +56,9 @@ class StatusIconWin : public StatusIcon {
// The currently-displayed icon for the window.
ScopedHICON icon_;
+ // Context menu associated with this icon (if any).
+ scoped_ptr<views::Menu2> context_menu_;
+
DISALLOW_COPY_AND_ASSIGN(StatusIconWin);
};
diff --git a/chrome/browser/views/status_icons/status_tray_win.cc b/chrome/browser/views/status_icons/status_tray_win.cc
index 8c1a998..29ed025 100644
--- a/chrome/browser/views/status_icons/status_tray_win.cc
+++ b/chrome/browser/views/status_icons/status_tray_win.cc
@@ -41,21 +41,23 @@ LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
- // TODO(atwilson): Add support for right clicks and context menu messages
- // (tracked in http://crbug.com/37375).
switch (message) {
case kStatusIconMessage:
switch (lparam) {
case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_CONTEXTMENU:
// Walk our icons, find which one was clicked on, and invoke its
- // DispatchClickEvent() method.
- for (StatusIconMap::const_iterator iter = status_icons().begin();
+ // HandleClickEvent() method.
+ for (StatusIconList::const_iterator iter = status_icons().begin();
iter != status_icons().end();
++iter) {
- StatusIconWin* win_icon =
- static_cast<StatusIconWin*>(iter->second);
- if (win_icon->icon_id() == wparam)
- win_icon->DispatchClickEvent();
+ StatusIconWin* win_icon = static_cast<StatusIconWin*>(*iter);
+ if (win_icon->icon_id() == wparam) {
+ POINT p;
+ GetCursorPos(&p);
+ win_icon->HandleClickEvent(p.x, p.y, lparam == WM_LBUTTONDOWN);
+ }
}
return TRUE;
}
@@ -70,7 +72,7 @@ StatusTrayWin::~StatusTrayWin() {
UnregisterClass(chrome::kStatusTrayWindowClass, GetModuleHandle(NULL));
}
-StatusIcon* StatusTrayWin::CreateStatusIcon() {
+StatusIcon* StatusTrayWin::CreatePlatformStatusIcon() {
return new StatusIconWin(next_icon_id_++, window_, kStatusIconMessage);
}
diff --git a/chrome/browser/views/status_icons/status_tray_win.h b/chrome/browser/views/status_icons/status_tray_win.h
index f3aa9d1..a2e322c 100644
--- a/chrome/browser/views/status_icons/status_tray_win.h
+++ b/chrome/browser/views/status_icons/status_tray_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_TRAY_WIN_H_
#define CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_TRAY_WIN_H_
+#pragma once
#include <windows.h>
@@ -21,7 +22,7 @@ class StatusTrayWin : public StatusTray {
LPARAM lparam);
protected:
// Overriden from StatusTray:
- virtual StatusIcon* CreateStatusIcon();
+ virtual StatusIcon* CreatePlatformStatusIcon();
private:
// Static callback invoked when a message comes in to our messaging window.
diff --git a/chrome/browser/views/status_icons/status_tray_win_unittest.cc b/chrome/browser/views/status_icons/status_tray_win_unittest.cc
index 073e50b..c824755 100644
--- a/chrome/browser/views/status_icons/status_tray_win_unittest.cc
+++ b/chrome/browser/views/status_icons/status_tray_win_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 "app/menus/simple_menu_model.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/views/status_icons/status_icon_win.h"
#include "chrome/browser/views/status_icons/status_tray_win.h"
#include "grit/browser_resources.h"
@@ -23,26 +25,31 @@ TEST(StatusTrayWinTest, CreateTray) {
StatusTrayWin tray;
}
-TEST(StatusTrayWinTest, CreateIcon) {
- // Create an icon, set the images and tooltip, then shut it down.
+TEST(StatusTrayWinTest, CreateIconAndMenu) {
+ // Create an icon, set the images, tooltip, and context menu, then shut it
+ // down.
StatusTrayWin tray;
- StatusIcon* icon = tray.GetStatusIcon(ASCIIToUTF16("test"));
+ StatusIcon* icon = tray.CreateStatusIcon();
SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_STATUS_TRAY_ICON);
icon->SetImage(*bitmap);
icon->SetPressedImage(*bitmap);
icon->SetToolTip(ASCIIToUTF16("tool tip"));
+ menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(NULL);
+ menu->AddItem(0, L"foo");
+ icon->SetContextMenu(menu);
}
TEST(StatusTrayWinTest, ClickOnIcon) {
// Create an icon, send a fake click event, make sure observer is called.
StatusTrayWin tray;
- StatusIconWin* icon = static_cast<StatusIconWin*>(
- tray.GetStatusIcon(ASCIIToUTF16("test")));
+ StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon());
MockStatusIconObserver observer;
icon->AddObserver(&observer);
EXPECT_CALL(observer, OnClicked());
// Mimic a click.
tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_LBUTTONDOWN);
+ // Mimic a right-click - observer should not be called.
+ tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_RBUTTONDOWN);
icon->RemoveObserver(&observer);
}
diff --git a/chrome/browser/views/tab_contents/native_tab_contents_container.h b/chrome/browser/views/tab_contents/native_tab_contents_container.h
index 9c540b9..51e08af 100644
--- a/chrome/browser/views/tab_contents/native_tab_contents_container.h
+++ b/chrome/browser/views/tab_contents/native_tab_contents_container.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_H_
+#pragma once
class RenderViewHost;
class TabContents;
@@ -40,6 +41,8 @@ class NativeTabContentsContainer {
// Retrieves the views::View that hosts the TabContents.
virtual views::View* GetView() = 0;
+ protected:
+ virtual ~NativeTabContentsContainer() {}
};
#endif // CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_H_
diff --git a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc
index 241ca35..d9c26c5 100644
--- a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc
+++ b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc
@@ -134,15 +134,8 @@ void NativeTabContentsContainerGtk::AboutToRequestFocusFromTabTraversal(
container_->tab_contents()->FocusThroughTabTraversal(reverse);
}
-bool NativeTabContentsContainerGtk::GetAccessibleRole(
- AccessibilityTypes::Role* role) {
- // TODO(port): figure out a11y
-#if defined(OS_WIN)
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_GROUPING;
-#endif
- return true;
+AccessibilityTypes::Role NativeTabContentsContainerGtk::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h
index e30c11f..7de9e26 100644
--- a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h
+++ b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_GTK_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_GTK_H_
+#pragma once
#include <gtk/gtk.h>
@@ -32,7 +33,7 @@ class NativeTabContentsContainerGtk : public NativeTabContentsContainer,
virtual void Focus();
virtual void RequestFocus();
virtual void AboutToRequestFocusFromTabTraversal(bool reverse);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
private:
TabContentsContainer* container_;
diff --git a/chrome/browser/views/tab_contents/native_tab_contents_container_win.cc b/chrome/browser/views/tab_contents/native_tab_contents_container_win.cc
index 355d776..eba411f 100644
--- a/chrome/browser/views/tab_contents/native_tab_contents_container_win.cc
+++ b/chrome/browser/views/tab_contents/native_tab_contents_container_win.cc
@@ -129,12 +129,8 @@ void NativeTabContentsContainerWin::AboutToRequestFocusFromTabTraversal(
container_->tab_contents()->FocusThroughTabTraversal(reverse);
}
-bool NativeTabContentsContainerWin::GetAccessibleRole(
- AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_GROUPING;
- return true;
+AccessibilityTypes::Role NativeTabContentsContainerWin::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_GROUPING;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/views/tab_contents/native_tab_contents_container_win.h b/chrome/browser/views/tab_contents/native_tab_contents_container_win.h
index 5fb5700..916ce0f 100644
--- a/chrome/browser/views/tab_contents/native_tab_contents_container_win.h
+++ b/chrome/browser/views/tab_contents/native_tab_contents_container_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_WIN_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_WIN_H_
+#pragma once
#include "chrome/browser/views/tab_contents/native_tab_contents_container.h"
#include "views/controls/native/native_view_host.h"
@@ -29,7 +30,7 @@ class NativeTabContentsContainerWin : public NativeTabContentsContainer,
virtual void Focus();
virtual void RequestFocus();
virtual void AboutToRequestFocusFromTabTraversal(bool reverse);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
private:
TabContentsContainer* container_;
diff --git a/chrome/browser/views/tab_contents/render_view_context_menu_views.cc b/chrome/browser/views/tab_contents/render_view_context_menu_views.cc
index 3fb8f28..8efb30b 100644
--- a/chrome/browser/views/tab_contents/render_view_context_menu_views.cc
+++ b/chrome/browser/views/tab_contents/render_view_context_menu_views.cc
@@ -4,9 +4,8 @@
#include "chrome/browser/views/tab_contents/render_view_context_menu_views.h"
-#include "app/l10n_util.h"
+#include "app/keyboard_codes.h"
#include "base/compiler_specific.h"
-#include "base/keyboard_codes.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/profile.h"
#include "grit/generated_resources.h"
@@ -69,28 +68,28 @@ bool RenderViewContextMenuViews::GetAcceleratorForCommandId(
// that Ctrl+C, Ctrl+V, Ctrl+X, Ctrl-A, etc do what they normally do.
switch (command_id) {
case IDC_CONTENT_CONTEXT_UNDO:
- *accel = views::Accelerator(base::VKEY_Z, false, true, false);
+ *accel = views::Accelerator(app::VKEY_Z, false, true, false);
return true;
case IDC_CONTENT_CONTEXT_REDO:
// TODO(jcampan): should it be Ctrl-Y?
- *accel = views::Accelerator(base::VKEY_Z, true, true, false);
+ *accel = views::Accelerator(app::VKEY_Z, true, true, false);
return true;
case IDC_CONTENT_CONTEXT_CUT:
- *accel = views::Accelerator(base::VKEY_X, false, true, false);
+ *accel = views::Accelerator(app::VKEY_X, false, true, false);
return true;
case IDC_CONTENT_CONTEXT_COPY:
- *accel = views::Accelerator(base::VKEY_C, false, true, false);
+ *accel = views::Accelerator(app::VKEY_C, false, true, false);
return true;
case IDC_CONTENT_CONTEXT_PASTE:
- *accel = views::Accelerator(base::VKEY_V, false, true, false);
+ *accel = views::Accelerator(app::VKEY_V, false, true, false);
return true;
case IDC_CONTENT_CONTEXT_SELECTALL:
- *accel = views::Accelerator(base::VKEY_A, false, true, false);
+ *accel = views::Accelerator(app::VKEY_A, false, true, false);
return true;
default:
diff --git a/chrome/browser/views/tab_contents/render_view_context_menu_views.h b/chrome/browser/views/tab_contents/render_view_context_menu_views.h
index cb58698..048dfa9 100644
--- a/chrome/browser/views/tab_contents/render_view_context_menu_views.h
+++ b/chrome/browser/views/tab_contents/render_view_context_menu_views.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_VIEWS_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_VIEWS_H_
+#pragma once
-#include "app/menus/simple_menu_model.h"
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
@@ -38,9 +38,6 @@ class RenderViewContextMenuViews : public RenderViewContextMenu {
virtual bool GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator);
private:
- // The current radio group for radio menu items.
- int current_radio_group_id_;
-
// The context menu itself and its contents.
scoped_ptr<views::Menu2> menu_;
diff --git a/chrome/browser/views/tab_contents/tab_contents_container.cc b/chrome/browser/views/tab_contents/tab_contents_container.cc
index fcffce2..a75743d 100644
--- a/chrome/browser/views/tab_contents/tab_contents_container.cc
+++ b/chrome/browser/views/tab_contents/tab_contents_container.cc
@@ -75,11 +75,8 @@ void TabContentsContainer::Layout() {
}
}
-bool TabContentsContainer::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_WINDOW;
- return true;
+AccessibilityTypes::Role TabContentsContainer::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_WINDOW;
}
void TabContentsContainer::ViewHierarchyChanged(bool is_add,
diff --git a/chrome/browser/views/tab_contents/tab_contents_container.h b/chrome/browser/views/tab_contents/tab_contents_container.h
index 18e69ff..c5c2f1f 100644
--- a/chrome/browser/views/tab_contents/tab_contents_container.h
+++ b/chrome/browser/views/tab_contents/tab_contents_container.h
@@ -4,8 +4,10 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_CONTAINER_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_CONTAINER_H_
+#pragma once
#include "chrome/browser/views/tab_contents/native_tab_contents_container.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "views/view.h"
@@ -41,7 +43,7 @@ class TabContentsContainer : public views::View,
// Overridden from views::View:
virtual void Layout();
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
protected:
// Overridden from views::View:
diff --git a/chrome/browser/views/tab_contents/tab_contents_drag_win.cc b/chrome/browser/views/tab_contents/tab_contents_drag_win.cc
index d52134a..6501120 100644
--- a/chrome/browser/views/tab_contents/tab_contents_drag_win.cc
+++ b/chrome/browser/views/tab_contents/tab_contents_drag_win.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.
@@ -6,14 +6,16 @@
#include <windows.h>
+#include <string>
+
#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
-#include "base/win_util.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/chrome_thread.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/profile.h"
@@ -197,11 +199,11 @@ void TabContentsDragWin::PrepareDragForDownload(
std::string content_disposition =
"attachment; filename=" + UTF16ToUTF8(file_name.value());
FilePath generated_file_name;
- DownloadManager::GenerateFileName(download_url,
- content_disposition,
- std::string(),
- UTF16ToUTF8(mime_type),
- &generated_file_name);
+ download_util::GenerateFileName(download_url,
+ content_disposition,
+ std::string(),
+ UTF16ToUTF8(mime_type),
+ &generated_file_name);
// Provide the data as file (CF_HDROP). A temporary download file with the
// Zone.Identifier ADS (Alternate Data Stream) attached will be created.
diff --git a/chrome/browser/views/tab_contents/tab_contents_drag_win.h b/chrome/browser/views/tab_contents/tab_contents_drag_win.h
index bfa2b12..2fd29e8 100644
--- a/chrome/browser/views/tab_contents/tab_contents_drag_win.h
+++ b/chrome/browser/views/tab_contents/tab_contents_drag_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_DRAG_WIN_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_DRAG_WIN_H_
+#pragma once
#include "app/os_exchange_data_provider_win.h"
#include "base/platform_thread.h"
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
index e8265cb..c261600 100644
--- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
@@ -213,14 +213,13 @@ gfx::NativeWindow TabContentsViewGtk::GetTopLevelNativeWindow() const {
}
void TabContentsViewGtk::GetContainerBounds(gfx::Rect* out) const {
- GetBounds(out, false);
-
// Callers expect the requested bounds not the actual bounds. For example,
// during init callers expect 0x0, but Gtk layout enforces a min size of 1x1.
- GtkRequisition requisition;
- gtk_widget_get_child_requisition(GetNativeView(), &requisition);
- out->set_width(requisition.width);
- out->set_height(requisition.height);
+ GetBounds(out, false);
+
+ gfx::Size size;
+ WidgetGtk::GetRequestedSize(&size);
+ out->set_size(size);
}
void TabContentsViewGtk::StartDragging(const WebDropData& drop_data,
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.h b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
index b4788c8..a46c4a3 100644
--- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
+++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_VIEW_GTK_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_VIEW_GTK_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_win.cc b/chrome/browser/views/tab_contents/tab_contents_view_win.cc
index 4ac40ac..91e2036 100644
--- a/chrome/browser/views/tab_contents/tab_contents_view_win.cc
+++ b/chrome/browser/views/tab_contents/tab_contents_view_win.cc
@@ -6,11 +6,7 @@
#include <windows.h>
-#include "app/os_exchange_data.h"
-#include "base/file_path.h"
-#include "base/keyboard_codes.h"
#include "base/time.h"
-#include "base/win_util.h"
#include "chrome/browser/browser.h" // TODO(beng): this dependency is awful.
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_request_limiter.h"
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_win.h b/chrome/browser/views/tab_contents/tab_contents_view_win.h
index 2c080c1..471869c 100644
--- a/chrome/browser/views/tab_contents/tab_contents_view_win.h
+++ b/chrome/browser/views/tab_contents/tab_contents_view_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_VIEW_WIN_H_
#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_VIEW_WIN_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "base/timer.h"
diff --git a/chrome/browser/views/tab_icon_view.cc b/chrome/browser/views/tab_icon_view.cc
index a43e0ac..db8a8e8 100644
--- a/chrome/browser/views/tab_icon_view.cc
+++ b/chrome/browser/views/tab_icon_view.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,7 @@
#endif
#include "app/resource_bundle.h"
+#include "app/theme_provider.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "chrome/app/chrome_dll_resource.h"
@@ -26,14 +27,11 @@
static bool g_initialized = false;
static SkBitmap* g_default_fav_icon = NULL;
-static SkBitmap* g_throbber_frames = NULL;
-static SkBitmap* g_throbber_frames_light = NULL;
-static int g_throbber_frame_count;
// static
void TabIconView::InitializeIfNeeded() {
if (!g_initialized) {
- ResourceBundle &rb = ResourceBundle::GetSharedInstance();
+ g_initialized = true;
#if defined(OS_WIN)
// The default window icon is the application icon, not the default
@@ -43,18 +41,9 @@ void TabIconView::InitializeIfNeeded() {
IconUtil::CreateSkBitmapFromHICON(app_icon, gfx::Size(16, 16));
DestroyIcon(app_icon);
#else
- g_default_fav_icon = rb.GetBitmapNamed(IDR_PRODUCT_LOGO_16);
+ g_default_fav_icon =
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_PRODUCT_LOGO_16);
#endif
-
- g_throbber_frames = rb.GetBitmapNamed(IDR_THROBBER);
- g_throbber_frames_light = rb.GetBitmapNamed(IDR_THROBBER_LIGHT);
- g_throbber_frame_count = g_throbber_frames->width() /
- g_throbber_frames->height();
-
- // Verify that our light and dark styles have the same number of frames.
- DCHECK(g_throbber_frame_count ==
- g_throbber_frames_light->width() / g_throbber_frames_light->height());
- g_initialized = true;
}
}
@@ -70,6 +59,15 @@ TabIconView::~TabIconView() {
}
void TabIconView::Update() {
+ static bool initialized = false;
+ static int throbber_frame_count = 0;
+ if (!initialized) {
+ initialized = true;
+ SkBitmap throbber(
+ *ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_THROBBER));
+ throbber_frame_count = throbber.width() / throbber.height();
+ }
+
if (throbber_running_) {
// We think the tab is loading.
if (!model_->ShouldTabIconViewAnimate()) {
@@ -79,7 +77,7 @@ void TabIconView::Update() {
SchedulePaint();
} else {
// The tab is still loading, increment the frame.
- throbber_frame_ = (throbber_frame_ + 1) % g_throbber_frame_count;
+ throbber_frame_ = (throbber_frame_ + 1) % throbber_frame_count;
SchedulePaint();
}
} else if (model_->ShouldTabIconViewAnimate()) {
@@ -92,9 +90,11 @@ void TabIconView::Update() {
}
void TabIconView::PaintThrobber(gfx::Canvas* canvas) {
- int image_size = g_throbber_frames->height();
- PaintIcon(canvas, is_light_ ? *g_throbber_frames_light : *g_throbber_frames,
- throbber_frame_ * image_size, 0, image_size, image_size, false);
+ SkBitmap throbber(*GetThemeProvider()->GetBitmapNamed(
+ is_light_ ? IDR_THROBBER_LIGHT : IDR_THROBBER));
+ int image_size = throbber.height();
+ PaintIcon(canvas, throbber, throbber_frame_ * image_size, 0, image_size,
+ image_size, false);
}
void TabIconView::PaintFavIcon(gfx::Canvas* canvas, const SkBitmap& bitmap) {
diff --git a/chrome/browser/views/tab_icon_view.h b/chrome/browser/views/tab_icon_view.h
index 6813e32..ef42477 100644
--- a/chrome/browser/views/tab_icon_view.h
+++ b/chrome/browser/views/tab_icon_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TAB_ICON_VIEW_H_
#define CHROME_BROWSER_VIEWS_TAB_ICON_VIEW_H_
+#pragma once
#include "views/view.h"
diff --git a/chrome/browser/views/tabs/base_tab.cc b/chrome/browser/views/tabs/base_tab.cc
index fb8e525..7520a33 100644
--- a/chrome/browser/views/tabs/base_tab.cc
+++ b/chrome/browser/views/tabs/base_tab.cc
@@ -6,10 +6,10 @@
#include <limits>
-#include "app/animation_container.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/slide_animation.h"
+#include "app/theme_provider.h"
#include "app/throb_animation.h"
#include "base/command_line.h"
#include "base/utf_string_conversions.h"
@@ -36,19 +36,6 @@ static const int kPulseDurationMs = 200;
// How long the hover state takes.
static const int kHoverDurationMs = 90;
-static SkBitmap* waiting_animation_frames = NULL;
-static SkBitmap* loading_animation_frames = NULL;
-static int loading_animation_frame_count = 0;
-static int waiting_animation_frame_count = 0;
-static int waiting_to_loading_frame_count_ratio = 0;
-
-// Close button images.
-static SkBitmap* close_button_n = NULL;
-static SkBitmap* close_button_h = NULL;
-static SkBitmap* close_button_p = NULL;
-
-static SkBitmap* crashed_fav_icon = NULL;
-
namespace {
////////////////////////////////////////////////////////////////////////////////
@@ -90,13 +77,6 @@ class TabCloseButton : public views::ImageButton {
} // namespace
// static
-int BaseTab::close_button_width_ = 0;
-// static
-int BaseTab::close_button_height_ = 0;
-// static
-int BaseTab::loading_animation_size_ = 0;
-
-// static
gfx::Font* BaseTab::font_ = NULL;
// static
int BaseTab::font_height_ = 0;
@@ -154,17 +134,20 @@ BaseTab::BaseTab(TabController* controller)
SetID(VIEW_ID_TAB);
// Add the Close Button.
- TabCloseButton* close_button = new TabCloseButton(this);
- close_button_ = close_button;
- close_button->SetImage(views::CustomButton::BS_NORMAL, close_button_n);
- close_button->SetImage(views::CustomButton::BS_HOT, close_button_h);
- close_button->SetImage(views::CustomButton::BS_PUSHED, close_button_p);
- close_button->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_CLOSE_TAB));
- close_button->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
+ close_button_ = new TabCloseButton(this);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ close_button_->SetImage(views::CustomButton::BS_NORMAL,
+ rb.GetBitmapNamed(IDR_TAB_CLOSE));
+ close_button_->SetImage(views::CustomButton::BS_HOT,
+ rb.GetBitmapNamed(IDR_TAB_CLOSE_H));
+ close_button_->SetImage(views::CustomButton::BS_PUSHED,
+ rb.GetBitmapNamed(IDR_TAB_CLOSE_P));
+ close_button_->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_CLOSE_TAB));
+ close_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
// Disable animation so that the red danger sign shows up immediately
// to help avoid mis-clicks.
- close_button->SetAnimationDuration(0);
- AddChildView(close_button);
+ close_button_->SetAnimationDuration(0);
+ AddChildView(close_button_);
SetContextMenuController(this);
}
@@ -321,11 +304,8 @@ bool BaseTab::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) {
return false;
}
-bool BaseTab::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_PAGETAB;
- return true;
+AccessibilityTypes::Role BaseTab::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_PAGETAB;
}
ThemeProvider* BaseTab::GetThemeProvider() {
@@ -335,6 +315,23 @@ ThemeProvider* BaseTab::GetThemeProvider() {
void BaseTab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
TabRendererData::NetworkState state) {
+ static bool initialized = false;
+ static int loading_animation_frame_count = 0;
+ static int waiting_animation_frame_count = 0;
+ static int waiting_to_loading_frame_count_ratio = 0;
+ if (!initialized) {
+ initialized = true;
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SkBitmap loading_animation(*rb.GetBitmapNamed(IDR_THROBBER));
+ loading_animation_frame_count =
+ loading_animation.width() / loading_animation.height();
+ SkBitmap waiting_animation(*rb.GetBitmapNamed(IDR_THROBBER_WAITING));
+ waiting_animation_frame_count =
+ waiting_animation.width() / waiting_animation.height();
+ waiting_to_loading_frame_count_ratio =
+ waiting_animation_frame_count / loading_animation_frame_count;
+ }
+
// The waiting animation is the reverse of the loading animation, but at a
// different rate - the following reverses and scales the animation_frame_
// so that the frame is at an equivalent position when going from one
@@ -356,10 +353,8 @@ void BaseTab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
void BaseTab::PaintIcon(gfx::Canvas* canvas, int x, int y) {
if (base::i18n::IsRTL()) {
- if (!data().favicon.isNull())
- x = width() - x - data().favicon.width();
- else
- x = width() - x - kFavIconSize;
+ x = width() - x -
+ (data().favicon.isNull() ? kFavIconSize : data().favicon.width());
}
int favicon_x = x;
@@ -367,27 +362,26 @@ void BaseTab::PaintIcon(gfx::Canvas* canvas, int x, int y) {
favicon_x += (data().favicon.width() - kFavIconSize) / 2;
if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
- SkBitmap* frames =
+ ThemeProvider* tp = GetThemeProvider();
+ SkBitmap frames(*tp->GetBitmapNamed(
(data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
- waiting_animation_frames : loading_animation_frames;
- int image_size = frames->height();
+ IDR_THROBBER_WAITING : IDR_THROBBER));
+ int image_size = frames.height();
int image_offset = loading_animation_frame_ * image_size;
int dst_y = (height() - image_size) / 2;
- canvas->DrawBitmapInt(*frames, image_offset, 0, image_size,
+ canvas->DrawBitmapInt(frames, image_offset, 0, image_size,
image_size, favicon_x, dst_y, image_size, image_size,
false);
} else {
canvas->Save();
canvas->ClipRectInt(0, 0, width(), height());
if (should_display_crashed_favicon_) {
- canvas->DrawBitmapInt(*crashed_fav_icon, 0, 0,
- crashed_fav_icon->width(),
- crashed_fav_icon->height(),
- favicon_x,
- (height() - crashed_fav_icon->height()) / 2 +
- fav_icon_hiding_offset_,
- kFavIconSize, kFavIconSize,
- true);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SkBitmap crashed_fav_icon(*rb.GetBitmapNamed(IDR_SAD_FAVICON));
+ canvas->DrawBitmapInt(crashed_fav_icon, 0, 0, crashed_fav_icon.width(),
+ crashed_fav_icon.height(), favicon_x,
+ (height() - crashed_fav_icon.height()) / 2 + fav_icon_hiding_offset_,
+ kFavIconSize, kFavIconSize, true);
} else {
if (!data().favicon.isNull()) {
// TODO(pkasting): Use code in tab_icon_view.cc:PaintIcon() (or switch
@@ -444,11 +438,6 @@ void BaseTab::ShowContextMenu(views::View* source,
controller()->ShowContextMenu(this, p);
}
-void BaseTab::ThemeChanged() {
- views::View::ThemeChanged();
- LoadThemeImages();
-}
-
void BaseTab::SetFavIconHidingOffset(int offset) {
fav_icon_hiding_offset_ = offset;
SchedulePaint();
@@ -482,77 +471,10 @@ bool BaseTab::IsPerformingCrashAnimation() const {
// static
void BaseTab::InitResources() {
static bool initialized = false;
- if (initialized)
- return;
-
- initialized = true;
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-
- crashed_fav_icon = rb.GetBitmapNamed(IDR_SAD_FAVICON);
-
- close_button_n = rb.GetBitmapNamed(IDR_TAB_CLOSE);
- close_button_h = rb.GetBitmapNamed(IDR_TAB_CLOSE_H);
- close_button_p = rb.GetBitmapNamed(IDR_TAB_CLOSE_P);
-
- close_button_width_ = close_button_n->width();
- close_button_height_ = close_button_n->height();
-
- // The loading animation image is a strip of states. Each state must be
- // square, so the height must divide the width evenly.
- loading_animation_frames = rb.GetBitmapNamed(IDR_THROBBER);
- loading_animation_size_ = loading_animation_frames->height();
- DCHECK(loading_animation_frames);
- DCHECK(loading_animation_frames->width() %
- loading_animation_frames->height() == 0);
- loading_animation_frame_count =
- loading_animation_frames->width() / loading_animation_frames->height();
-
- // We get a DIV0 further down when the throbber is replaced by an image which
- // is taller than wide. In this case we cannot deduce an animation sequence
- // from it since we assume that each animation frame has the width of the
- // image's height.
- if (loading_animation_frame_count == 0) {
-#ifdef WIN32
- // TODO(idanan): Remove this when we have a way to handle theme errors.
- // See: http://code.google.com/p/chromium/issues/detail?id=12531 For now,
- // this is Windows-specific because some users have downloaded a DLL from
- // outside of Google to override the theme.
- std::wstring text = l10n_util::GetString(IDS_RESOURCE_ERROR);
- std::wstring caption = l10n_util::GetString(IDS_RESOURCE_ERROR_CAPTION);
- UINT flags = MB_OK | MB_ICONWARNING | MB_TOPMOST;
- win_util::MessageBox(NULL, text, caption, flags);
-#endif
- CHECK(loading_animation_frame_count) <<
- "Invalid throbber size. Width = " <<
- loading_animation_frames->width() << ", height = " <<
- loading_animation_frames->height();
+ if (!initialized) {
+ initialized = true;
+ font_ = new gfx::Font(
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont));
+ font_height_ = font_->GetHeight();
}
-
- waiting_animation_frames = rb.GetBitmapNamed(IDR_THROBBER_WAITING);
- DCHECK(waiting_animation_frames);
- DCHECK(waiting_animation_frames->width() %
- waiting_animation_frames->height() == 0);
- waiting_animation_frame_count =
- waiting_animation_frames->width() / waiting_animation_frames->height();
-
- waiting_to_loading_frame_count_ratio =
- waiting_animation_frame_count / loading_animation_frame_count;
- // TODO(beng): eventually remove this when we have a proper themeing system.
- // themes not supporting IDR_THROBBER_WAITING are causing this
- // value to be 0 which causes DIV0 crashes. The value of 5
- // matches the current bitmaps in our source.
- if (waiting_to_loading_frame_count_ratio == 0)
- waiting_to_loading_frame_count_ratio = 5;
-
- font_ = new gfx::Font(rb.GetFont(ResourceBundle::BaseFont));
- font_height_ = font_->height();
-}
-
-// static
-void BaseTab::LoadThemeImages() {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- loading_animation_frames = rb.GetBitmapNamed(IDR_THROBBER);
- waiting_animation_frames = rb.GetBitmapNamed(IDR_THROBBER_WAITING);
- loading_animation_size_ = loading_animation_frames->height();
}
diff --git a/chrome/browser/views/tabs/base_tab.h b/chrome/browser/views/tabs/base_tab.h
index 0cc56c4..9d6567b 100644
--- a/chrome/browser/views/tabs/base_tab.h
+++ b/chrome/browser/views/tabs/base_tab.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_BASE_TAB_H_
#define CHROME_BROWSER_VIEWS_TABS_BASE_TAB_H_
+#pragma once
#include "app/animation.h"
#include "base/ref_counted.h"
@@ -33,7 +34,7 @@ class BaseTab : public AnimationDelegate,
public views::View {
public:
explicit BaseTab(TabController* controller);
- ~BaseTab();
+ virtual ~BaseTab();
// Sets the data this tabs displays. Invokes DataChanged for subclasses to
// update themselves appropriately.
@@ -85,7 +86,7 @@ class BaseTab : public AnimationDelegate,
virtual void OnMouseReleased(const views::MouseEvent& event,
bool canceled);
virtual bool GetTooltipText(const gfx::Point& p, std::wstring* tooltip);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual ThemeProvider* GetThemeProvider();
protected:
@@ -109,7 +110,7 @@ class BaseTab : public AnimationDelegate,
views::ImageButton* close_button() const { return close_button_; }
- // Paints the icon at the specified x-coordinate.
+ // Paints the icon at the specified coordinates, mirrored for RTL if needed.
void PaintIcon(gfx::Canvas* canvas, int x, int y);
void PaintTitle(gfx::Canvas* canvas, SkColor title_color);
@@ -127,19 +128,9 @@ class BaseTab : public AnimationDelegate,
const gfx::Point& p,
bool is_mouse_gesture);
- // views::View overrides:
- virtual void ThemeChanged();
-
// Returns the bounds of the title.
virtual const gfx::Rect& title_bounds() const = 0;
- // Close button size.
- static int close_button_height() { return close_button_height_; }
- static int close_button_width() { return close_button_width_; }
-
- // Size (width/height) of the loading animation.
- static int loading_animation_size() { return loading_animation_size_; }
-
static gfx::Font* font() { return font_; }
static int font_height() { return font_height_; }
@@ -163,9 +154,6 @@ class BaseTab : public AnimationDelegate,
static void InitResources();
- // Invoked when the theme changes to reload theme images.
- static void LoadThemeImages();
-
// The controller.
// WARNING: this is null during detached tab dragging.
TabController* controller_;
@@ -207,13 +195,6 @@ class BaseTab : public AnimationDelegate,
bool should_display_crashed_favicon_;
- // Size of the close button.
- static int close_button_width_;
- static int close_button_height_;
-
- // Size of the loading animation frames.
- static int loading_animation_size_;
-
static gfx::Font* font_;
static int font_height_;
diff --git a/chrome/browser/views/tabs/base_tab_strip.h b/chrome/browser/views/tabs/base_tab_strip.h
index a2e62c0..91f5e6c 100644
--- a/chrome/browser/views/tabs/base_tab_strip.h
+++ b/chrome/browser/views/tabs/base_tab_strip.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_BASE_TAB_STRIP_H_
#define CHROME_BROWSER_VIEWS_TABS_BASE_TAB_STRIP_H_
+#pragma once
#include <vector>
diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/views/tabs/browser_tab_strip_controller.cc
index 1221133..76de3ae 100644
--- a/chrome/browser/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/views/tabs/browser_tab_strip_controller.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_menu_model.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/views/app_launcher.h"
#include "chrome/browser/views/tabs/base_tab_strip.h"
#include "chrome/browser/views/tabs/tab_renderer_data.h"
@@ -112,9 +113,11 @@ class BrowserTabStripController::TabContextMenuContents
////////////////////////////////////////////////////////////////////////////////
// BrowserTabStripController, public:
-BrowserTabStripController::BrowserTabStripController(TabStripModel* model)
+BrowserTabStripController::BrowserTabStripController(Browser* browser,
+ TabStripModel* model)
: model_(model),
- tabstrip_(NULL) {
+ tabstrip_(NULL),
+ browser_(browser) {
model_->AddObserver(this);
notification_registrar_.Add(this,
@@ -269,12 +272,7 @@ void BrowserTabStripController::CreateNewTab() {
UserMetrics::RecordAction(UserMetricsAction("NewTab_Button"),
model_->profile());
- TabContents* selected_tab = model_->GetSelectedTabContents();
- if (!selected_tab)
- return;
-
- Browser* browser = selected_tab->delegate()->GetBrowser();
- if (browser->OpenAppsPanelAsNewTab())
+ if (browser_ && browser_->OpenAppsPanelAsNewTab())
return;
model_->delegate()->AddBlankTab(true);
@@ -368,7 +366,13 @@ void BrowserTabStripController::SetTabRendererDataFromModel(
TabContents* contents,
int model_index,
TabRendererData* data) {
- SkBitmap* app_icon = contents->GetExtensionAppIcon();
+ SkBitmap* app_icon = NULL;
+
+ // Extension App icons are slightly larger than favicons, so only allow
+ // them if permitted by the model.
+ if (model_->delegate()->LargeIconsPermitted())
+ app_icon = contents->GetExtensionAppIcon();
+
if (app_icon)
data->favicon = *app_icon;
else
diff --git a/chrome/browser/views/tabs/browser_tab_strip_controller.h b/chrome/browser/views/tabs/browser_tab_strip_controller.h
index 9f0a7a5..bbf1121 100644
--- a/chrome/browser/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/views/tabs/browser_tab_strip_controller.h
@@ -4,14 +4,17 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_BROWSER_TAB_STRIP_CONTROLLER_H_
#define CHROME_BROWSER_VIEWS_TABS_BROWSER_TAB_STRIP_CONTROLLER_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/views/tabs/tab_strip_controller.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class BaseTab;
class BaseTabStrip;
+class Browser;
struct TabRendererData;
@@ -21,7 +24,7 @@ class BrowserTabStripController : public TabStripController,
public TabStripModelObserver,
public NotificationObserver {
public:
- explicit BrowserTabStripController(TabStripModel* model);
+ BrowserTabStripController(Browser* browser, TabStripModel* model);
virtual ~BrowserTabStripController();
void InitFromModel(BaseTabStrip* tabstrip);
@@ -103,6 +106,9 @@ class BrowserTabStripController : public TabStripController,
BaseTabStrip* tabstrip_;
+ // Non-owning pointer to the browser which is using this controller.
+ Browser* browser_;
+
// If non-NULL it means we're showing a menu for the tab.
scoped_ptr<TabContextMenuContents> context_menu_contents_;
diff --git a/chrome/browser/views/tabs/dragged_tab_controller.cc b/chrome/browser/views/tabs/dragged_tab_controller.cc
index d6514bf..b0dc9e3 100644
--- a/chrome/browser/views/tabs/dragged_tab_controller.cc
+++ b/chrome/browser/views/tabs/dragged_tab_controller.cc
@@ -9,11 +9,9 @@
#include "app/animation.h"
#include "app/slide_animation.h"
-#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
#include "base/i18n/rtl.h"
-#include "base/keyboard_codes.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -97,27 +95,20 @@ class DockView : public views::View {
SkBitmap* high_icon = rb.GetBitmapNamed(IDR_DOCK_HIGH);
SkBitmap* wide_icon = rb.GetBitmapNamed(IDR_DOCK_WIDE);
+ canvas->Save();
bool rtl_ui = base::i18n::IsRTL();
if (rtl_ui) {
// Flip canvas to draw the mirrored tab images for RTL UI.
- canvas->Save();
canvas->TranslateInt(width(), 0);
canvas->ScaleInt(-1, 1);
}
- int x_of_active_tab = -1;
- int x_of_inactive_tab = -1;
+ int x_of_active_tab = width() / 2 + kTabSpacing / 2;
+ int x_of_inactive_tab = width() / 2 - high_icon->width() - kTabSpacing / 2;
switch (type_) {
case DockInfo::LEFT_OF_WINDOW:
case DockInfo::LEFT_HALF:
- if (!rtl_ui) {
- x_of_active_tab = width() / 2 - high_icon->width() - kTabSpacing / 2;
- x_of_inactive_tab = width() / 2 + kTabSpacing / 2;
- } else {
- // Adjust x axis for RTL UI after flippping canvas.
- x_of_active_tab = width() / 2 + kTabSpacing / 2;
- x_of_inactive_tab = width() / 2 - high_icon->width() -
- kTabSpacing / 2;
- }
+ if (!rtl_ui)
+ std::swap(x_of_active_tab, x_of_inactive_tab);
canvas->DrawBitmapInt(*high_icon, x_of_active_tab,
(height() - high_icon->height()) / 2);
if (type_ == DockInfo::LEFT_OF_WINDOW) {
@@ -129,15 +120,8 @@ class DockView : public views::View {
case DockInfo::RIGHT_OF_WINDOW:
case DockInfo::RIGHT_HALF:
- if (!rtl_ui) {
- x_of_active_tab = width() / 2 + kTabSpacing / 2;
- x_of_inactive_tab = width() / 2 - high_icon->width() -
- kTabSpacing / 2;
- } else {
- // Adjust x axis for RTL UI after flippping canvas.
- x_of_active_tab = width() / 2 - high_icon->width() - kTabSpacing / 2;
- x_of_inactive_tab = width() / 2 + kTabSpacing / 2;
- }
+ if (rtl_ui)
+ std::swap(x_of_active_tab, x_of_inactive_tab);
canvas->DrawBitmapInt(*high_icon, x_of_active_tab,
(height() - high_icon->height()) / 2);
if (type_ == DockInfo::RIGHT_OF_WINDOW) {
@@ -173,8 +157,7 @@ class DockView : public views::View {
NOTREACHED();
break;
}
- if (rtl_ui)
- canvas->Restore();
+ canvas->Restore();
}
private:
@@ -446,6 +429,10 @@ void DraggedTabController::ActivateContents(TabContents* contents) {
// Ignored.
}
+void DraggedTabController::DeactivateContents(TabContents* contents) {
+ // Ignored.
+}
+
void DraggedTabController::LoadingStateChanged(TabContents* source) {
// It would be nice to respond to this message by changing the
// screen shot in the dragged tab.
@@ -465,10 +452,6 @@ void DraggedTabController::MoveContents(TabContents* source,
// own window. Should be ignored since we're moving the window...
}
-bool DraggedTabController::IsPopup(TabContents* source) {
- return false;
-}
-
void DraggedTabController::ToolbarSizeChanged(TabContents* source,
bool finished) {
// Dragged tabs don't care about this.
@@ -725,6 +708,8 @@ void DraggedTabController::MoveAttachedTab(const gfx::Point& screen_point) {
attached_tab_->SchedulePaint();
attached_tab_->SetX(dragged_view_point.x());
+ attached_tab_->SetX(
+ attached_tabstrip_->MirroredLeftPointForRect(attached_tab_->bounds()));
attached_tab_->SetY(dragged_view_point.y());
attached_tab_->SchedulePaint();
}
@@ -1215,10 +1200,9 @@ void DraggedTabController::CompleteDrag() {
}
}
// Compel the model to construct a new window for the detached TabContents.
- gfx::Rect browser_rect = source_tabstrip_->GetWindow()->GetBounds();
- gfx::Rect window_bounds(
- GetWindowCreatePoint(),
- gfx::Size(browser_rect.width(), browser_rect.height()));
+ views::Window* window = source_tabstrip_->GetWindow();
+ gfx::Rect window_bounds(window->GetNormalBounds());
+ window_bounds.set_origin(GetWindowCreatePoint());
// When modifying the following if statement, please make sure not to
// introduce issue listed in http://crbug.com/6223 comment #11.
bool rtl_ui = base::i18n::IsRTL();
@@ -1230,7 +1214,7 @@ void DraggedTabController::CompleteDrag() {
}
Browser* new_browser =
GetModel(source_tabstrip_)->delegate()->CreateNewStripWithContents(
- dragged_contents_, window_bounds, dock_info_);
+ dragged_contents_, window_bounds, dock_info_, window->IsMaximized());
TabStripModel* new_model = new_browser->tabstrip_model();
new_model->SetTabPinned(new_model->GetIndexOfTabContents(dragged_contents_),
pinned_);
diff --git a/chrome/browser/views/tabs/dragged_tab_controller.h b/chrome/browser/views/tabs/dragged_tab_controller.h
index 66f4ced..5c9c619 100644
--- a/chrome/browser/views/tabs/dragged_tab_controller.h
+++ b/chrome/browser/views/tabs/dragged_tab_controller.h
@@ -1,14 +1,17 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_
#define CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_CONTROLLER_H_
+#pragma once
#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/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/rect.h"
@@ -101,10 +104,10 @@ class DraggedTabController : public TabContentsDelegate,
const gfx::Rect& initial_pos,
bool user_gesture);
virtual void ActivateContents(TabContents* contents);
+ virtual void DeactivateContents(TabContents* contents);
virtual void LoadingStateChanged(TabContents* source);
virtual void CloseContents(TabContents* source);
virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
- virtual bool IsPopup(TabContents* source);
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating);
virtual void URLStarredChanged(TabContents* source, bool starred);
virtual void UpdateTargetURL(TabContents* source, const GURL& url);
diff --git a/chrome/browser/views/tabs/dragged_tab_view.cc b/chrome/browser/views/tabs/dragged_tab_view.cc
index 5ee2626..8f77a87 100644
--- a/chrome/browser/views/tabs/dragged_tab_view.cc
+++ b/chrome/browser/views/tabs/dragged_tab_view.cc
@@ -163,8 +163,7 @@ void DraggedTabView::PaintDetachedView(gfx::Canvas* canvas) {
int image_x = kDragFrameBorderSize;
int image_y = tab_size_.height();
int image_w = ps.width() - kTwiceDragFrameBorderSize;
- int image_h =
- ps.height() - kTwiceDragFrameBorderSize - tab_size_.height();
+ int image_h = contents_size_.height();
scale_canvas.FillRectInt(SK_ColorBLACK, image_x, image_y, image_w, image_h);
photobooth_->PaintScreenshotIntoCanvas(
&scale_canvas,
diff --git a/chrome/browser/views/tabs/dragged_tab_view.h b/chrome/browser/views/tabs/dragged_tab_view.h
index f2ded5a..0432d46 100644
--- a/chrome/browser/views/tabs/dragged_tab_view.h
+++ b/chrome/browser/views/tabs/dragged_tab_view.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_VIEW_H_
#define CHROME_BROWSER_VIEWS_TABS_DRAGGED_TAB_VIEW_H_
+#pragma once
#include "build/build_config.h"
#include "gfx/point.h"
diff --git a/chrome/browser/views/tabs/native_view_photobooth.h b/chrome/browser/views/tabs/native_view_photobooth.h
index 804983c..0eba321 100644
--- a/chrome/browser/views/tabs/native_view_photobooth.h
+++ b/chrome/browser/views/tabs/native_view_photobooth.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_NATIVE_VIEW_PHOTOBOOTH_H_
#define CHROME_BROWSER_VIEWS_TABS_NATIVE_VIEW_PHOTOBOOTH_H_
+#pragma once
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/views/tabs/native_view_photobooth_gtk.h b/chrome/browser/views/tabs/native_view_photobooth_gtk.h
index 791b8c5..8bc7406 100644
--- a/chrome/browser/views/tabs/native_view_photobooth_gtk.h
+++ b/chrome/browser/views/tabs/native_view_photobooth_gtk.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_NATIVE_VIEW_PHOTOBOOTH_GTK_H_
#define CHROME_BROWSER_VIEWS_TABS_NATIVE_VIEW_PHOTOBOOTH_GTK_H_
+#pragma once
#include "chrome/browser/views/tabs/native_view_photobooth.h"
diff --git a/chrome/browser/views/tabs/native_view_photobooth_win.h b/chrome/browser/views/tabs/native_view_photobooth_win.h
index fd59afa..4ed4016 100644
--- a/chrome/browser/views/tabs/native_view_photobooth_win.h
+++ b/chrome/browser/views/tabs/native_view_photobooth_win.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_NATIVE_VIEW_PHOTOBOOTH_WIN_H_
#define CHROME_BROWSER_VIEWS_TABS_NATIVE_VIEW_PHOTOBOOTH_WIN_H_
+#pragma once
#include "chrome/browser/views/tabs/native_view_photobooth.h"
diff --git a/chrome/browser/views/tabs/side_tab.cc b/chrome/browser/views/tabs/side_tab.cc
index f57a32b..a73bdee 100644
--- a/chrome/browser/views/tabs/side_tab.cc
+++ b/chrome/browser/views/tabs/side_tab.cc
@@ -5,8 +5,6 @@
#include "chrome/browser/views/tabs/side_tab.h"
#include "app/resource_bundle.h"
-#include "app/theme_provider.h"
-#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "gfx/canvas_skia.h"
#include "gfx/favicon_size.h"
diff --git a/chrome/browser/views/tabs/side_tab.h b/chrome/browser/views/tabs/side_tab.h
index 9bc9631..6cff764 100644
--- a/chrome/browser/views/tabs/side_tab.h
+++ b/chrome/browser/views/tabs/side_tab.h
@@ -4,8 +4,8 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_H_
#define CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_H_
+#pragma once
-#include "app/slide_animation.h"
#include "chrome/browser/views/tabs/base_tab.h"
#include "gfx/font.h"
diff --git a/chrome/browser/views/tabs/side_tab_strip.h b/chrome/browser/views/tabs/side_tab_strip.h
index 6e52e70..d5f0ffa 100644
--- a/chrome/browser/views/tabs/side_tab_strip.h
+++ b/chrome/browser/views/tabs/side_tab_strip.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_STRIP_H_
#define CHROME_BROWSER_VIEWS_TABS_SIDE_TAB_STRIP_H_
+#pragma once
#include "chrome/browser/views/tabs/base_tab_strip.h"
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc
index b519ab2..1f58245 100644
--- a/chrome/browser/views/tabs/tab.cc
+++ b/chrome/browser/views/tabs/tab.cc
@@ -11,8 +11,8 @@
#include "app/slide_animation.h"
#include "app/throb_animation.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/defaults.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "gfx/canvas_skia.h"
#include "gfx/favicon_size.h"
#include "gfx/font.h"
@@ -235,7 +235,8 @@ void Tab::Layout() {
// The height of the content of the Tab is the largest of the favicon,
// the title text and the close button graphic.
int content_height = std::max(kFavIconSize, font_height());
- content_height = std::max(content_height, close_button_height());
+ gfx::Size close_button_size(close_button()->GetPreferredSize());
+ content_height = std::max(content_height, close_button_size.height());
// Size the Favicon.
showing_icon_ = ShouldShowIcon();
@@ -272,13 +273,12 @@ void Tab::Layout() {
// Size the Close button.
showing_close_button_ = ShouldShowCloseBox();
if (showing_close_button_) {
- int close_button_top =
- kTopPadding + kCloseButtonVertFuzz +
- (content_height - close_button_height()) / 2;
+ int close_button_top = kTopPadding + kCloseButtonVertFuzz +
+ (content_height - close_button_size.height()) / 2;
// If the ratio of the close button size to tab width exceeds the maximum.
close_button()->SetBounds(lb.width() + kCloseButtonHorzFuzz,
- close_button_top, close_button_width(),
- close_button_height());
+ close_button_top, close_button_size.width(),
+ close_button_size.height());
close_button()->SetVisible(true);
} else {
close_button()->SetBounds(0, 0, 0, 0);
@@ -319,8 +319,7 @@ void Tab::Layout() {
title_bounds_.set_x(MirroredLeftPointForRect(title_bounds_));
}
-void Tab::ThemeChanged() {
- BaseTab::ThemeChanged();
+void Tab::OnThemeChanged() {
Tab::LoadTabImages();
}
@@ -419,7 +418,7 @@ void Tab::PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas) {
SkShader::kClamp_TileMode);
paint.setShader(shader);
shader->unref();
- hover_canvas.FillRectInt(x - radius, -radius, radius * 2, radius * 2, paint);
+ hover_canvas.DrawRectInt(x - radius, -radius, radius * 2, radius * 2, paint);
// Draw the radial gradient clipped to the background into hover_image.
SkBitmap hover_image = SkBitmapOperations::CreateMaskedBitmap(
diff --git a/chrome/browser/views/tabs/tab.h b/chrome/browser/views/tabs/tab.h
index bbcf2b6..e99a8fd 100644
--- a/chrome/browser/views/tabs/tab.h
+++ b/chrome/browser/views/tabs/tab.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_H_
#define CHROME_BROWSER_VIEWS_TABS_TAB_H_
+#pragma once
#include <string>
@@ -69,7 +70,7 @@ class Tab : public BaseTab {
// Overridden from views::View:
virtual void Paint(gfx::Canvas* canvas);
virtual void Layout();
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
virtual std::string GetClassName() const { return kViewClassName; }
virtual bool HasHitTestMask() const;
virtual void GetHitTestMask(gfx::Path* path) const;
diff --git a/chrome/browser/views/tabs/tab_controller.h b/chrome/browser/views/tabs/tab_controller.h
index e1db77e..abaaf0f 100644
--- a/chrome/browser/views/tabs/tab_controller.h
+++ b/chrome/browser/views/tabs/tab_controller.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_CONTROLLER_H_
#define CHROME_BROWSER_VIEWS_TABS_TAB_CONTROLLER_H_
+#pragma once
class BaseTab;
diff --git a/chrome/browser/views/tabs/tab_dragging_test.cc b/chrome/browser/views/tabs/tab_dragging_test.cc
index 67ba21c..6e4c369 100644
--- a/chrome/browser/views/tabs/tab_dragging_test.cc
+++ b/chrome/browser/views/tabs/tab_dragging_test.cc
@@ -30,14 +30,14 @@
// Disabled on Toolkit views bot. See http://crbug.com/42614
#define MAYBE_Tab1Tab3Escape DISABLED_Tab1Tab3Escape
#else
-// Flaky, see http://crbug.com/21092.
-#define MAYBE_Tab1Tab3Escape FLAKY_Tab1Tab3Escape
+#define MAYBE_Tab1Tab3Escape Tab1Tab3Escape
#endif
-// These tests fail on Linux. See http://crbug.com/10941
+// These tests fail on Linux because we haven't implemented all of tab dragging
+// (it's not needed on chromeos). See http://crbug.com/10941
#if defined(OS_LINUX)
-#define MAYBE_Tab1Tab2 FAILS_Tab1Tab2
-#define MAYBE_Tab1Tab3 FAILS_Tab1Tab3
+#define MAYBE_Tab1Tab2 DISABLED_Tab1Tab2
+#define MAYBE_Tab1Tab3 DISABLED_Tab1Tab3
#else
#define MAYBE_Tab1Tab2 Tab1Tab2
#define MAYBE_Tab1Tab3 Tab1Tab3
@@ -82,8 +82,7 @@ TEST_F(TabDraggingTest, MAYBE_Tab1Tab2) {
ASSERT_TRUE(tab3.get());
// Make sure 3 tabs are open.
- ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2,
- 10000));
+ ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2));
// Get bounds for the tabs.
gfx::Rect bounds1;
@@ -181,8 +180,7 @@ TEST_F(TabDraggingTest, MAYBE_Tab1Tab3) {
ASSERT_TRUE(tab3.get());
// Make sure 3 tabs are open.
- ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2,
- 10000));
+ ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2));
// Get bounds for the tabs.
gfx::Rect bounds1;
@@ -289,8 +287,7 @@ TEST_F(TabDraggingTest, MAYBE_Tab1Tab3Escape) {
ASSERT_TRUE(tab3.get());
// Make sure 3 tabs are open.
- ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2,
- 10000));
+ ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2));
// Get bounds for the tabs.
gfx::Rect bounds1;
@@ -400,8 +397,7 @@ TEST_F(TabDraggingTest, MAYBE_Tab2OutOfTabStrip) {
ASSERT_TRUE(tab3.get());
// Make sure 3 tabs are opened.
- ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2,
- 10000));
+ ASSERT_TRUE(browser->WaitForTabCountToBecome(initial_tab_count + 2));
// Make sure all the tab URL specs are different.
ASSERT_TRUE(tab1_url != tab2_url);
diff --git a/chrome/browser/views/tabs/tab_renderer_data.h b/chrome/browser/views/tabs/tab_renderer_data.h
index 7cbaa18..f91a3f9 100644
--- a/chrome/browser/views/tabs/tab_renderer_data.h
+++ b/chrome/browser/views/tabs/tab_renderer_data.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_DATA_H_
#define CHROME_BROWSER_VIEWS_TABS_TAB_RENDERER_DATA_H_
-
-#include <string>
+#pragma once
#include "base/string16.h"
#include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc
index 4712bd1..c408585 100644
--- a/chrome/browser/views/tabs/tab_strip.cc
+++ b/chrome/browser/views/tabs/tab_strip.cc
@@ -8,12 +8,11 @@
#include "app/drag_drop_types.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "app/slide_animation.h"
#include "base/compiler_specific.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/defaults.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/tabs/tab.h"
#include "chrome/browser/views/tabs/tab_strip_controller.h"
@@ -48,7 +47,6 @@ using views::DropTargetEvent;
static const int kNewTabButtonHOffset = -5;
static const int kNewTabButtonVOffset = 5;
-static const int kResizeTabsTimeMs = 300;
static const int kSuspendAnimationsTimeMs = 200;
static const int kTabHOffset = -16;
static const int kTabStripAnimationVSlop = 40;
@@ -123,8 +121,6 @@ const int TabStrip::mini_to_non_mini_gap_ = 3;
TabStrip::TabStrip(TabStripController* controller)
: BaseTabStrip(controller, BaseTabStrip::HORIZONTAL_TAB_STRIP),
- resize_layout_factory_(this),
- added_as_message_loop_observer_(false),
current_unselected_width_(Tab::GetStandardSize().width()),
current_selected_width_(Tab::GetStandardSize().width()),
available_width_for_tabs_(-1),
@@ -165,6 +161,10 @@ gfx::Rect TabStrip::GetNewTabButtonBounds() {
return newtab_button_->bounds();
}
+void TabStrip::MouseMovedOutOfView() {
+ ResizeLayoutTabs();
+}
+
////////////////////////////////////////////////////////////////////////////////
// TabStrip, BaseTabStrip implementation:
@@ -335,8 +335,7 @@ void TabStrip::PaintChildren(gfx::Canvas* canvas) {
paint.setColor(SkColorSetARGB(200, 255, 255, 255));
paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
paint.setStyle(SkPaint::kFill_Style);
- canvas->FillRectInt(
- 0, 0, width(),
+ canvas->DrawRectInt(0, 0, width(),
height() - 2, // Visible region that overlaps the toolbar.
paint);
}
@@ -419,11 +418,8 @@ int TabStrip::OnPerformDrop(const DropTargetEvent& event) {
return GetDropEffect(event);
}
-bool TabStrip::GetAccessibleRole(AccessibilityTypes::Role* role) {
- DCHECK(role);
-
- *role = AccessibilityTypes::ROLE_PAGETABLIST;
- return true;
+AccessibilityTypes::Role TabStrip::GetAccessibleRole() {
+ return AccessibilityTypes::ROLE_PAGETABLIST;
}
views::View* TabStrip::GetViewForPoint(const gfx::Point& point) {
@@ -450,7 +446,7 @@ views::View* TabStrip::GetViewForPoint(const gfx::Point& point) {
return this;
}
-void TabStrip::ThemeChanged() {
+void TabStrip::OnThemeChanged() {
LoadNewTabButtonImage();
}
@@ -529,62 +525,6 @@ void TabStrip::ButtonPressed(views::Button* sender, const views::Event& event) {
}
///////////////////////////////////////////////////////////////////////////////
-// TabStrip, MessageLoop::Observer implementation:
-
-#if defined(OS_WIN)
-void TabStrip::WillProcessMessage(const MSG& msg) {
-}
-
-void TabStrip::DidProcessMessage(const MSG& msg) {
- // We spy on three different Windows messages here to see if the mouse has
- // moved out of the bounds of the tabstrip, which we use as our cue to kick
- // of the resize animation. The messages are:
- //
- // WM_MOUSEMOVE:
- // For when the mouse moves from the tabstrip over into the rest of the
- // browser UI, i.e. within the bounds of the same windows HWND.
- // WM_MOUSELEAVE:
- // For when the mouse moves very rapidly from a tab closed in the middle of
- // the tabstrip (_not_ the end) out of the bounds of the browser's HWND and
- // over some other HWND.
- // WM_NCMOUSELEAVE:
- // For when the mouse moves very rapidly from the end of the tabstrip (when
- // the last tab is closed and the mouse is left floating over the title
- // bar). Because the empty area of the tabstrip at the end of the title bar
- // is registered by the ChromeFrame as part of the "caption" area of the
- // window (the frame's OnNCHitTest method returns HTCAPTION for this
- // region), the frame's HWND receives a WM_MOUSEMOVE message immediately,
- // because as far as it is concerned the mouse has _left_ the client area
- // of the window (and is now over the non-client area). To be notified
- // again when the mouse leaves the _non-client_ area, we use the
- // WM_NCMOUSELEAVE message, which causes us to re-evaluate the cursor
- // position and correctly resize the tabstrip.
- //
- switch (msg.message) {
- case WM_MOUSEMOVE:
- case WM_MOUSELEAVE:
- case WM_NCMOUSELEAVE:
- HandleGlobalMouseMoveEvent();
- break;
- }
-}
-#else
-void TabStrip::WillProcessEvent(GdkEvent* event) {
-}
-
-void TabStrip::DidProcessEvent(GdkEvent* event) {
- switch (event->type) {
- case GDK_MOTION_NOTIFY:
- case GDK_LEAVE_NOTIFY:
- HandleGlobalMouseMoveEvent();
- break;
- default:
- break;
- }
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
// TabStrip, private:
void TabStrip::Init() {
@@ -730,8 +670,6 @@ void TabStrip::ResizeLayoutTabs() {
if (tab_count() == 0)
return;
- resize_layout_factory_.RevokeAll();
-
// It is critically important that this is unhooked here, otherwise we will
// keep spying on messages forever.
RemoveMessageLoopObserver();
@@ -755,40 +693,17 @@ void TabStrip::ResizeLayoutTabs() {
StartResizeLayoutAnimation();
}
-bool TabStrip::IsCursorInTabStripZone() const {
- gfx::Rect bounds = GetLocalBounds(true);
- gfx::Point tabstrip_topleft(bounds.origin());
- View::ConvertPointToScreen(this, &tabstrip_topleft);
- bounds.set_origin(tabstrip_topleft);
- bounds.set_height(bounds.height() + kTabStripAnimationVSlop);
-
-#if defined(OS_WIN)
- DWORD pos = GetMessagePos();
- gfx::Point cursor_point(pos);
-#elif defined(OS_LINUX)
- // TODO(sky): make sure this is right with multiple monitors.
- GdkScreen* screen = gdk_screen_get_default();
- GdkDisplay* display = gdk_screen_get_display(screen);
- gint x, y;
- gdk_display_get_pointer(display, NULL, &x, &y, NULL);
- gfx::Point cursor_point(x, y);
-#endif
-
- return bounds.Contains(cursor_point.x(), cursor_point.y());
-}
-
void TabStrip::AddMessageLoopObserver() {
- if (!added_as_message_loop_observer_) {
- MessageLoopForUI::current()->AddObserver(this);
- added_as_message_loop_observer_ = true;
+ if (!mouse_watcher_.get()) {
+ mouse_watcher_.reset(
+ new views::MouseWatcher(this, this,
+ gfx::Insets(0, 0, kTabStripAnimationVSlop, 0)));
}
+ mouse_watcher_->Start();
}
void TabStrip::RemoveMessageLoopObserver() {
- if (added_as_message_loop_observer_) {
- MessageLoopForUI::current()->RemoveObserver(this);
- added_as_message_loop_observer_ = false;
- }
+ mouse_watcher_.reset(NULL);
}
gfx::Rect TabStrip::GetDropBounds(int drop_index,
@@ -1106,24 +1021,6 @@ bool TabStrip::IsPointInTab(Tab* tab,
return tab->HitTest(point_in_tab_coords);
}
-void TabStrip::HandleGlobalMouseMoveEvent() {
- if (!IsCursorInTabStripZone()) {
- // Mouse moved outside the tab slop zone, start a timer to do a resize
- // layout after a short while...
- if (resize_layout_factory_.empty()) {
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- resize_layout_factory_.NewRunnableMethod(
- &TabStrip::ResizeLayoutTabs),
- kResizeTabsTimeMs);
- }
- } else {
- // Mouse moved quickly out of the tab strip and then into it again, so
- // cancel the timer so that the strip doesn't move when the mouse moves
- // back over it.
- resize_layout_factory_.RevokeAll();
- }
-}
-
bool TabStrip::HasPhantomTabs() const {
for (int i = 0; i < tab_count(); ++i) {
if (GetTabAtTabDataIndex(i)->data().phantom)
diff --git a/chrome/browser/views/tabs/tab_strip.h b/chrome/browser/views/tabs/tab_strip.h
index 2620f22..64c23fe 100644
--- a/chrome/browser/views/tabs/tab_strip.h
+++ b/chrome/browser/views/tabs/tab_strip.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_H_
#define CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_H_
+#pragma once
#include "app/animation_container.h"
-#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/timer.h"
#include "chrome/browser/views/tabs/base_tab_strip.h"
#include "gfx/point.h"
#include "gfx/rect.h"
#include "views/controls/button/image_button.h"
+#include "views/mouse_watcher.h"
class Tab;
@@ -40,7 +41,7 @@ class WidgetWin;
///////////////////////////////////////////////////////////////////////////////
class TabStrip : public BaseTabStrip,
public views::ButtonListener,
- public MessageLoopForUI::Observer {
+ public views::MouseWatcherListener {
public:
explicit TabStrip(TabStripController* controller);
virtual ~TabStrip();
@@ -51,6 +52,9 @@ class TabStrip : public BaseTabStrip,
// Returns the bounds of the new tab button.
gfx::Rect GetNewTabButtonBounds();
+ // MouseWatcherListener overrides:
+ virtual void MouseMovedOutOfView();
+
// BaseTabStrip implementation:
virtual int GetPreferredHeight();
virtual void SetBackgroundOffset(const gfx::Point& offset);
@@ -77,9 +81,9 @@ class TabStrip : public BaseTabStrip,
virtual int OnDragUpdated(const views::DropTargetEvent& event);
virtual void OnDragExited();
virtual int OnPerformDrop(const views::DropTargetEvent& event);
- virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual AccessibilityTypes::Role GetAccessibleRole();
virtual views::View* GetViewForPoint(const gfx::Point& point);
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
protected:
// BaseTabStrip overrides:
@@ -100,15 +104,6 @@ class TabStrip : public BaseTabStrip,
// views::ButtonListener implementation:
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
- // MessageLoop::Observer implementation:
-#if defined(OS_WIN)
- virtual void WillProcessMessage(const MSG& msg);
- virtual void DidProcessMessage(const MSG& msg);
-#else
- virtual void WillProcessEvent(GdkEvent* event);
- virtual void DidProcessEvent(GdkEvent* event);
-#endif
-
// Horizontal gap between mini and non-mini-tabs.
static const int mini_to_non_mini_gap_;
@@ -187,10 +182,6 @@ class TabStrip : public BaseTabStrip,
// Perform an animated resize-relayout of the TabStrip immediately.
void ResizeLayoutTabs();
- // Returns whether or not the cursor is currently in the "tab strip zone"
- // which is defined as the region above the TabStrip and a bit below it.
- bool IsCursorInTabStripZone() const;
-
// Ensure that the message loop observer used for event spying is added and
// removed appropriately so we can tell when to resize layout the tab strip.
void AddMessageLoopObserver();
@@ -243,22 +234,11 @@ class TabStrip : public BaseTabStrip,
// hit-test region of the specified Tab.
bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords);
- // Called from the message loop observer when a mouse movement has occurred
- // anywhere over our containing window.
- void HandleGlobalMouseMoveEvent();
-
// Returns true if any of the tabs are phantom.
bool HasPhantomTabs() const;
// -- Member Variables ------------------------------------------------------
- // A factory that is used to construct a delayed callback to the
- // ResizeLayoutTabsNow method.
- ScopedRunnableMethodFactory<TabStrip> resize_layout_factory_;
-
- // True if the TabStrip has already been added as a MessageLoop observer.
- bool added_as_message_loop_observer_;
-
// The "New Tab" button.
views::ImageButton* newtab_button_;
@@ -302,6 +282,8 @@ class TabStrip : public BaseTabStrip,
// Used for stage 1 of new tab animation.
base::OneShotTimer<TabStrip> new_tab_timer_;
+ scoped_ptr<views::MouseWatcher> mouse_watcher_;
+
DISALLOW_COPY_AND_ASSIGN(TabStrip);
};
diff --git a/chrome/browser/views/tabs/tab_strip_controller.h b/chrome/browser/views/tabs/tab_strip_controller.h
index 12b21ea..bd52452 100644
--- a/chrome/browser/views/tabs/tab_strip_controller.h
+++ b/chrome/browser/views/tabs/tab_strip_controller.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_CONTROLLER_H_
#define CHROME_BROWSER_VIEWS_TABS_TAB_STRIP_CONTROLLER_H_
-
-#include <vector>
+#pragma once
class BaseTab;
class BaseTabStrip;
diff --git a/chrome/browser/views/task_manager_view.cc b/chrome/browser/views/task_manager_view.cc
index 04590f1..452c5d9 100644
--- a/chrome/browser/views/task_manager_view.cc
+++ b/chrome/browser/views/task_manager_view.cc
@@ -2,17 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/task_manager.h"
+#include "chrome/browser/task_manager/task_manager.h"
#include "app/l10n_util.h"
#include "app/table_model_observer.h"
+#include "base/command_line.h"
#include "base/stats_table.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/memory_purger.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -80,63 +82,63 @@ int TaskManagerTableModel::RowCount() {
std::wstring TaskManagerTableModel::GetText(int row, int col_id) {
switch (col_id) {
case IDS_TASK_MANAGER_PAGE_COLUMN: // Process
- return model_->GetResourceTitle(row);
+ return UTF16ToWide(model_->GetResourceTitle(row));
case IDS_TASK_MANAGER_NET_COLUMN: // Net
- return model_->GetResourceNetworkUsage(row);
+ return UTF16ToWide(model_->GetResourceNetworkUsage(row));
case IDS_TASK_MANAGER_CPU_COLUMN: // CPU
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceCPUUsage(row);
+ return UTF16ToWide(model_->GetResourceCPUUsage(row));
case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourcePrivateMemory(row);
+ return UTF16ToWide(model_->GetResourcePrivateMemory(row));
case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceSharedMemory(row);
+ return UTF16ToWide(model_->GetResourceSharedMemory(row));
case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: // Memory
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourcePhysicalMemory(row);
+ return UTF16ToWide(model_->GetResourcePhysicalMemory(row));
case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceProcessId(row);
+ return UTF16ToWide(model_->GetResourceProcessId(row));
case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: // Goats Teleported!
- return model_->GetResourceGoatsTeleported(row);
+ return UTF16ToWide(model_->GetResourceGoatsTeleported(row));
case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceWebCoreImageCacheSize(row);
+ return UTF16ToWide(model_->GetResourceWebCoreImageCacheSize(row));
case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceWebCoreScriptsCacheSize(row);
+ return UTF16ToWide(model_->GetResourceWebCoreScriptsCacheSize(row));
case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceWebCoreCSSCacheSize(row);
+ return UTF16ToWide(model_->GetResourceWebCoreCSSCacheSize(row));
case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceSqliteMemoryUsed(row);
+ return UTF16ToWide(model_->GetResourceSqliteMemoryUsed(row));
case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
if (!model_->IsResourceFirstInGroup(row))
return std::wstring();
- return model_->GetResourceV8MemoryAllocatedSize(row);
+ return UTF16ToWide(model_->GetResourceV8MemoryAllocatedSize(row));
default:
NOTREACHED();
@@ -220,7 +222,7 @@ class TaskManagerView : public views::View,
// views::TableViewObserver implementation.
virtual void OnSelectionChanged();
virtual void OnDoubleClick();
- virtual void OnKeyDown(base::KeyboardCode keycode);
+ virtual void OnKeyDown(app::KeyboardCode keycode);
// views::LinkController implementation.
virtual void LinkActivated(views::Link* source, int event_flags);
@@ -370,7 +372,7 @@ void TaskManagerView::Init() {
}
kill_button_ = new views::NativeButton(
this, l10n_util::GetString(IDS_TASK_MANAGER_KILL));
- kill_button_->AddAccelerator(views::Accelerator(base::VKEY_E,
+ kill_button_->AddAccelerator(views::Accelerator(app::VKEY_E,
false, false, false));
kill_button_->SetAccessibleKeyboardShortcut(L"E");
about_memory_link_ = new views::Link(
@@ -484,6 +486,11 @@ void TaskManagerView::Show() {
instance_->InitAlwaysOnTopState();
instance_->model_->StartUpdating();
instance_->window()->Show();
+
+ // Set the initial focus to the list of tasks.
+ views::FocusManager* focus_manager = instance_->GetFocusManager();
+ if (focus_manager)
+ focus_manager->SetFocusedView(instance_->tab_table_);
}
}
@@ -533,8 +540,8 @@ bool TaskManagerView::ExecuteWindowsCommand(int command_id) {
if (g_browser_process->local_state()) {
DictionaryValue* window_preferences =
g_browser_process->local_state()->GetMutableDictionary(
- GetWindowName().c_str());
- window_preferences->SetBoolean(L"always_on_top", is_always_on_top_);
+ WideToUTF8(GetWindowName()).c_str());
+ window_preferences->SetBoolean("always_on_top", is_always_on_top_);
}
return true;
}
@@ -546,7 +553,7 @@ std::wstring TaskManagerView::GetWindowTitle() const {
}
std::wstring TaskManagerView::GetWindowName() const {
- return prefs::kTaskManagerWindowPlacement;
+ return UTF8ToWide(prefs::kTaskManagerWindowPlacement);
}
int TaskManagerView::GetDialogButtons() const {
@@ -581,8 +588,8 @@ void TaskManagerView::OnDoubleClick() {
ActivateFocusedTab();
}
-void TaskManagerView::OnKeyDown(base::KeyboardCode keycode) {
- if (keycode == base::VKEY_RETURN)
+void TaskManagerView::OnKeyDown(app::KeyboardCode keycode) {
+ if (keycode == app::VKEY_RETURN)
ActivateFocusedTab();
}
@@ -666,9 +673,10 @@ bool TaskManagerView::GetSavedAlwaysOnTopState(bool* always_on_top) const {
return false;
const DictionaryValue* dictionary =
- g_browser_process->local_state()->GetDictionary(GetWindowName().c_str());
+ g_browser_process->local_state()->GetDictionary(
+ WideToUTF8(GetWindowName()).c_str());
return dictionary &&
- dictionary->GetBoolean(L"always_on_top", always_on_top) && always_on_top;
+ dictionary->GetBoolean("always_on_top", always_on_top) && always_on_top;
}
} // namespace
diff --git a/chrome/browser/views/theme_background.cc b/chrome/browser/views/theme_background.cc
index 06f0f6f..ad8d2ed 100644
--- a/chrome/browser/views/theme_background.cc
+++ b/chrome/browser/views/theme_background.cc
@@ -5,8 +5,8 @@
#include "chrome/browser/views/theme_background.h"
#include "app/resource_bundle.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "gfx/canvas.h"
#include "grit/app_resources.h"
diff --git a/chrome/browser/views/theme_background.h b/chrome/browser/views/theme_background.h
index 31f568e..b904a71 100644
--- a/chrome/browser/views/theme_background.h
+++ b/chrome/browser/views/theme_background.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_THEME_BACKGROUND_H_
#define CHROME_BROWSER_VIEWS_THEME_BACKGROUND_H_
+#pragma once
#include "views/background.h"
diff --git a/chrome/browser/views/theme_helpers.h b/chrome/browser/views/theme_helpers.h
index 02107e2..68ea077 100644
--- a/chrome/browser/views/theme_helpers.h
+++ b/chrome/browser/views/theme_helpers.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_THEME_HELPERS_H__
#define CHROME_BROWSER_VIEWS_THEME_HELPERS_H__
+#pragma once
#include <windows.h>
diff --git a/chrome/browser/views/theme_install_bubble_view.cc b/chrome/browser/views/theme_install_bubble_view.cc
index 4e54812..7593fc7 100644
--- a/chrome/browser/views/theme_install_bubble_view.cc
+++ b/chrome/browser/views/theme_install_bubble_view.cc
@@ -90,7 +90,7 @@ gfx::Size ThemeInstallBubbleView::GetPreferredSize() {
return gfx::Size(views::Label::font().GetStringWidth(text_) +
kTextHorizPadding,
ResourceBundle::GetSharedInstance().GetFont(
- ResourceBundle::LargeFont).height() + kTextVertPadding);
+ ResourceBundle::LargeFont).GetHeight() + kTextVertPadding);
}
void ThemeInstallBubbleView::Reposition() {
diff --git a/chrome/browser/views/theme_install_bubble_view.h b/chrome/browser/views/theme_install_bubble_view.h
index baf80b3..dfe9dc4 100644
--- a/chrome/browser/views/theme_install_bubble_view.h
+++ b/chrome/browser/views/theme_install_bubble_view.h
@@ -4,9 +4,11 @@
#ifndef CHROME_BROWSER_VIEWS_THEME_INSTALL_BUBBLE_VIEW_H_
#define CHROME_BROWSER_VIEWS_THEME_INSTALL_BUBBLE_VIEW_H_
+#pragma once
#include <string>
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas.h"
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index b287bda..d1ad65b 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -8,10 +8,10 @@
#include "app/resource_bundle.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/browser_actions_container.h"
@@ -23,9 +23,9 @@
#include "chrome/common/pref_names.h"
#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
+#include "gfx/skbitmap_operations.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
-#include "gfx/skbitmap_operations.h"
#include "grit/theme_resources.h"
#include "views/controls/button/button_dropdown.h"
#include "views/focus/view_storage.h"
@@ -33,9 +33,17 @@
#include "views/window/non_client_view.h"
#include "views/window/window.h"
-static const int kControlHorizOffset = 4;
-static const int kControlVertOffset = 6;
-static const int kControlIndent = 3;
+// The space between items is 4 px in general.
+const int ToolbarView::kStandardSpacing = 4;
+// The top of the toolbar has an edge we have to skip over in addition to the 4
+// px of spacing.
+const int ToolbarView::kVertSpacing = kStandardSpacing + 1;
+// The edge graphics have some built-in spacing/shadowing, so we have to adjust
+// our spacing to make it still appear to be 4 px.
+static const int kEdgeSpacing = ToolbarView::kStandardSpacing - 1;
+// The buttons to the left of the omnibox are close together.
+static const int kButtonSpacing = 1;
+
static const int kStatusBubbleWidth = 480;
// The length of time to run the upgrade notification animation (the time it
@@ -45,15 +53,6 @@ static const int kPulseDuration = 2000;
// How long to wait between pulsating the upgrade notifier.
static const int kPulsateEveryMs = 8000;
-// The offset in pixels of the upgrade dot on the app menu.
-static const int kUpgradeDotOffset = 11;
-
-// Separation between the location bar and the menus.
-static const int kMenuButtonOffset = 3;
-
-// Padding to the right of the location bar
-static const int kPaddingRight = 2;
-
static const int kPopupTopSpacingNonGlass = 3;
static const int kPopupBottomSpacingNonGlass = 2;
static const int kPopupBottomSpacingGlass = 1;
@@ -67,8 +66,8 @@ ToolbarView::ToolbarView(Browser* browser)
: model_(browser->toolbar_model()),
back_(NULL),
forward_(NULL),
- home_(NULL),
reload_(NULL),
+ home_(NULL),
location_bar_(NULL),
browser_actions_(NULL),
app_menu_(NULL),
@@ -111,7 +110,7 @@ void ToolbarView::Init(Profile* profile) {
browser_, BackForwardMenuModel::BACKWARD_MENU));
forward_menu_model_.reset(new BackForwardMenuModel(
browser_, BackForwardMenuModel::FORWARD_MENU));
- app_menu_model_.reset(new WrenchMenuModel(this, browser_));
+ wrench_menu_model_.reset(new WrenchMenuModel(this, browser_));
back_ = new views::ButtonDropDown(this, back_menu_model_.get());
back_->set_triggerable_event_flags(views::Event::EF_LEFT_BUTTON_DOWN |
@@ -131,14 +130,6 @@ void ToolbarView::Init(Profile* profile) {
forward_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_FORWARD));
forward_->SetID(VIEW_ID_FORWARD_BUTTON);
- home_ = new views::ImageButton(this);
- home_->set_triggerable_event_flags(views::Event::EF_LEFT_BUTTON_DOWN |
- views::Event::EF_MIDDLE_BUTTON_DOWN);
- home_->set_tag(IDC_HOME);
- home_->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_HOME));
- home_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_HOME));
- home_->SetID(VIEW_ID_HOME_BUTTON);
-
// Have to create this before |reload_| as |reload_|'s constructor needs it.
location_bar_ = new LocationBarView(profile, browser_->command_updater(),
model_, this, (display_mode_ == DISPLAYMODE_LOCATION) ?
@@ -152,9 +143,18 @@ void ToolbarView::Init(Profile* profile) {
reload_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_RELOAD));
reload_->SetID(VIEW_ID_RELOAD_BUTTON);
+ home_ = new views::ImageButton(this);
+ home_->set_triggerable_event_flags(views::Event::EF_LEFT_BUTTON_DOWN |
+ views::Event::EF_MIDDLE_BUTTON_DOWN);
+ home_->set_tag(IDC_HOME);
+ home_->SetTooltipText(l10n_util::GetString(IDS_TOOLTIP_HOME));
+ home_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_HOME));
+ home_->SetID(VIEW_ID_HOME_BUTTON);
+
browser_actions_ = new BrowserActionsContainer(browser_, this);
app_menu_ = new views::MenuButton(NULL, std::wstring(), this, false);
+ app_menu_->set_border(NULL);
app_menu_->EnableCanvasFlippingForRTLUI(true);
app_menu_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_APP));
app_menu_->SetTooltipText(l10n_util::GetStringF(IDS_APPMENU_TOOLTIP,
@@ -170,14 +170,15 @@ void ToolbarView::Init(Profile* profile) {
// Always add children in order from left to right, for accessibility.
AddChildView(back_);
AddChildView(forward_);
- AddChildView(home_);
AddChildView(reload_);
+ AddChildView(home_);
AddChildView(location_bar_);
AddChildView(browser_actions_);
AddChildView(app_menu_);
location_bar_->Init();
show_home_button_.Init(prefs::kShowHomeButton, profile->GetPrefs(), this);
+ browser_actions_->Init();
SetProfile(profile);
}
@@ -247,7 +248,7 @@ void ToolbarView::RunMenu(views::View* source, const gfx::Point& /*pt*/) {
bool destroyed_flag = false;
destroyed_flag_ = &destroyed_flag;
wrench_menu_.reset(new WrenchMenu(browser_));
- wrench_menu_->Init(app_menu_model_.get());
+ wrench_menu_->Init(wrench_menu_model_.get());
for (size_t i = 0; i < menu_listeners_.size(); ++i)
menu_listeners_[i]->OnMenuOpened();
@@ -269,6 +270,10 @@ TabContents* ToolbarView::GetTabContents() {
return browser_->GetSelectedTabContents();
}
+MatchPreview* ToolbarView::GetMatchPreview() {
+ return browser_->match_preview();
+}
+
void ToolbarView::OnInputInProgress(bool in_progress) {
// The edit should make sure we're only notified when something changes.
DCHECK(model_->input_in_progress() != in_progress);
@@ -281,7 +286,9 @@ void ToolbarView::OnInputInProgress(bool in_progress) {
// ToolbarView, AnimationDelegate implementation:
void ToolbarView::AnimationProgressed(const Animation* animation) {
- app_menu_->SetIcon(GetAppMenuIcon());
+ app_menu_->SetIcon(GetAppMenuIcon(views::CustomButton::BS_NORMAL));
+ app_menu_->SetHoverIcon(GetAppMenuIcon(views::CustomButton::BS_HOT));
+ app_menu_->SetPushedIcon(GetAppMenuIcon(views::CustomButton::BS_PUSHED));
SchedulePaint();
}
@@ -330,7 +337,7 @@ void ToolbarView::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::PREF_CHANGED) {
- std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ std::string* pref_name = Details<std::string>(details).ptr();
if (*pref_name == prefs::kShowHomeButton) {
Layout();
SchedulePaint();
@@ -341,21 +348,7 @@ void ToolbarView::Observe(NotificationType type,
}
////////////////////////////////////////////////////////////////////////////////
-// ToolbarView, menus::SimpleMenuModel::Delegate implementation:
-
-bool ToolbarView::IsCommandIdChecked(int command_id) const {
-#if defined(OS_CHROMEOS)
- if (command_id == IDC_TOGGLE_VERTICAL_TABS) {
- return browser_->UseVerticalTabs();
- }
-#endif
- return (command_id == IDC_SHOW_BOOKMARK_BAR) &&
- profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
-}
-
-bool ToolbarView::IsCommandIdEnabled(int command_id) const {
- return browser_->command_updater()->IsCommandEnabled(command_id);
-}
+// ToolbarView, menus::AcceleratorProvider implementation:
bool ToolbarView::GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator) {
@@ -364,36 +357,32 @@ bool ToolbarView::GetAcceleratorForCommandId(int command_id,
// TODO(cpu) Bug 1109102. Query WebKit land for the actual bindings.
switch (command_id) {
case IDC_CUT:
- *accelerator = views::Accelerator(base::VKEY_X, false, true, false);
+ *accelerator = views::Accelerator(app::VKEY_X, false, true, false);
return true;
case IDC_COPY:
- *accelerator = views::Accelerator(base::VKEY_C, false, true, false);
+ *accelerator = views::Accelerator(app::VKEY_C, false, true, false);
return true;
case IDC_PASTE:
- *accelerator = views::Accelerator(base::VKEY_V, false, true, false);
+ *accelerator = views::Accelerator(app::VKEY_V, false, true, false);
return true;
}
// Else, we retrieve the accelerator information from the frame.
return GetWidget()->GetAccelerator(command_id, accelerator);
}
-void ToolbarView::ExecuteCommand(int command_id) {
- browser_->ExecuteCommand(command_id);
-}
-
////////////////////////////////////////////////////////////////////////////////
// ToolbarView, views::View overrides:
gfx::Size ToolbarView::GetPreferredSize() {
if (IsDisplayModeNormal()) {
- int min_width = kControlIndent + back_->GetPreferredSize().width() +
- forward_->GetPreferredSize().width() + kControlHorizOffset +
+ int min_width = kEdgeSpacing +
+ back_->GetPreferredSize().width() + kButtonSpacing +
+ forward_->GetPreferredSize().width() + kButtonSpacing +
+ reload_->GetPreferredSize().width() + kStandardSpacing +
(show_home_button_.GetValue() ?
- (home_->GetPreferredSize().width() + kControlHorizOffset) : 0) +
- reload_->GetPreferredSize().width() + kControlHorizOffset +
+ (home_->GetPreferredSize().width() + kButtonSpacing) : 0) +
browser_actions_->GetPreferredSize().width() +
- kMenuButtonOffset +
- app_menu_->GetPreferredSize().width() + kPaddingRight;
+ app_menu_->GetPreferredSize().width() + kEdgeSpacing;
static SkBitmap normal_background;
if (normal_background.isNull()) {
@@ -424,7 +413,7 @@ void ToolbarView::Layout() {
return;
}
- int child_y = std::min(kControlVertOffset, height());
+ int child_y = std::min(kVertSpacing, height());
// We assume all child elements are the same height.
int child_height =
std::min(back_->GetPreferredSize().height(), height() - child_y);
@@ -438,38 +427,36 @@ void ToolbarView::Layout() {
// http://crbug.com/5540
int back_width = back_->GetPreferredSize().width();
if (browser_->window() && browser_->window()->IsMaximized())
- back_->SetBounds(0, child_y, back_width + kControlIndent, child_height);
+ back_->SetBounds(0, child_y, back_width + kEdgeSpacing, child_height);
else
- back_->SetBounds(kControlIndent, child_y, back_width, child_height);
+ back_->SetBounds(kEdgeSpacing, child_y, back_width, child_height);
+
+ forward_->SetBounds(back_->x() + back_->width() + kButtonSpacing,
+ child_y, forward_->GetPreferredSize().width(), child_height);
- forward_->SetBounds(back_->x() + back_->width(), child_y,
- forward_->GetPreferredSize().width(), child_height);
+ reload_->SetBounds(forward_->x() + forward_->width() + kButtonSpacing,
+ child_y, reload_->GetPreferredSize().width(), child_height);
if (show_home_button_.GetValue()) {
home_->SetVisible(true);
- home_->SetBounds(forward_->x() + forward_->width() + kControlHorizOffset,
- child_y, home_->GetPreferredSize().width(), child_height);
+ home_->SetBounds(reload_->x() + reload_->width() + kButtonSpacing, child_y,
+ home_->GetPreferredSize().width(), child_height);
} else {
home_->SetVisible(false);
- home_->SetBounds(forward_->x() + forward_->width(), child_y, 0,
- child_height);
+ home_->SetBounds(reload_->x() + reload_->width(), child_y, 0, child_height);
}
- reload_->SetBounds(home_->x() + home_->width() + kControlHorizOffset, child_y,
- reload_->GetPreferredSize().width(), child_height);
-
int browser_actions_width = browser_actions_->GetPreferredSize().width();
int app_menu_width = app_menu_->GetPreferredSize().width();
- int location_x = reload_->x() + reload_->width() + kControlHorizOffset;
- int available_width = width() - kPaddingRight - app_menu_width -
- browser_actions_width - kMenuButtonOffset - location_x;
+ int location_x = home_->x() + home_->width() + kStandardSpacing;
+ int available_width = width() - kEdgeSpacing - app_menu_width -
+ browser_actions_width - location_x;
location_bar_->SetBounds(location_x, child_y, std::max(available_width, 0),
child_height);
- int next_menu_x =
- location_bar_->x() + location_bar_->width() + kMenuButtonOffset;
- browser_actions_->SetBounds(next_menu_x, 0, browser_actions_width, height());
+ browser_actions_->SetBounds(location_bar_->x() + location_bar_->width(), 0,
+ browser_actions_width, height());
// The browser actions need to do a layout explicitly, because when an
// extension is loaded/unloaded/changed, BrowserActionContainer removes and
// re-adds everything, regardless of whether it has a page action. For a
@@ -478,9 +465,9 @@ void ToolbarView::Layout() {
// TODO(sidchat): Rework the above behavior so that explicit layout is not
// required.
browser_actions_->Layout();
- next_menu_x += browser_actions_width;
- app_menu_->SetBounds(next_menu_x, child_y, app_menu_width, child_height);
+ app_menu_->SetBounds(browser_actions_->x() + browser_actions_width, child_y,
+ app_menu_width, child_height);
}
void ToolbarView::Paint(gfx::Canvas* canvas) {
@@ -505,7 +492,7 @@ void ToolbarView::Paint(gfx::Canvas* canvas) {
canvas->FillRectInt(SK_ColorBLACK, 0, height() - 1, width(), 1);
}
-void ToolbarView::ThemeChanged() {
+void ToolbarView::OnThemeChanged() {
LoadImages();
}
@@ -534,17 +521,12 @@ int ToolbarView::PopupTopSpacing() const {
void ToolbarView::LoadImages() {
ThemeProvider* tp = GetThemeProvider();
- SkColor color = tp->GetColor(BrowserThemeProvider::COLOR_BUTTON_BACKGROUND);
- SkBitmap* background = tp->GetBitmapNamed(IDR_THEME_BUTTON_BACKGROUND);
-
back_->SetImage(views::CustomButton::BS_NORMAL, tp->GetBitmapNamed(IDR_BACK));
back_->SetImage(views::CustomButton::BS_HOT, tp->GetBitmapNamed(IDR_BACK_H));
back_->SetImage(views::CustomButton::BS_PUSHED,
tp->GetBitmapNamed(IDR_BACK_P));
back_->SetImage(views::CustomButton::BS_DISABLED,
tp->GetBitmapNamed(IDR_BACK_D));
- back_->SetBackground(color, background,
- tp->GetBitmapNamed(IDR_BACK_MASK));
forward_->SetImage(views::CustomButton::BS_NORMAL,
tp->GetBitmapNamed(IDR_FORWARD));
@@ -554,15 +536,6 @@ void ToolbarView::LoadImages() {
tp->GetBitmapNamed(IDR_FORWARD_P));
forward_->SetImage(views::CustomButton::BS_DISABLED,
tp->GetBitmapNamed(IDR_FORWARD_D));
- forward_->SetBackground(color, background,
- tp->GetBitmapNamed(IDR_FORWARD_MASK));
-
- home_->SetImage(views::CustomButton::BS_NORMAL, tp->GetBitmapNamed(IDR_HOME));
- home_->SetImage(views::CustomButton::BS_HOT, tp->GetBitmapNamed(IDR_HOME_H));
- home_->SetImage(views::CustomButton::BS_PUSHED,
- tp->GetBitmapNamed(IDR_HOME_P));
- home_->SetBackground(color, background,
- tp->GetBitmapNamed(IDR_BUTTON_MASK));
reload_->SetImage(views::CustomButton::BS_NORMAL,
tp->GetBitmapNamed(IDR_RELOAD));
@@ -576,10 +549,17 @@ void ToolbarView::LoadImages() {
tp->GetBitmapNamed(IDR_STOP_H));
reload_->SetToggledImage(views::CustomButton::BS_PUSHED,
tp->GetBitmapNamed(IDR_STOP_P));
- reload_->SetBackground(color, background,
- tp->GetBitmapNamed(IDR_BUTTON_MASK));
+ reload_->SetToggledImage(views::CustomButton::BS_DISABLED,
+ tp->GetBitmapNamed(IDR_STOP_D));
+
+ home_->SetImage(views::CustomButton::BS_NORMAL, tp->GetBitmapNamed(IDR_HOME));
+ home_->SetImage(views::CustomButton::BS_HOT, tp->GetBitmapNamed(IDR_HOME_H));
+ home_->SetImage(views::CustomButton::BS_PUSHED,
+ tp->GetBitmapNamed(IDR_HOME_P));
- app_menu_->SetIcon(GetAppMenuIcon());
+ app_menu_->SetIcon(GetAppMenuIcon(views::CustomButton::BS_NORMAL));
+ app_menu_->SetHoverIcon(GetAppMenuIcon(views::CustomButton::BS_HOT));
+ app_menu_->SetPushedIcon(GetAppMenuIcon(views::CustomButton::BS_PUSHED));
}
void ToolbarView::ShowUpgradeReminder() {
@@ -598,10 +578,17 @@ void ToolbarView::PulsateUpgradeNotifier() {
update_reminder_animation_->Show();
}
-SkBitmap ToolbarView::GetAppMenuIcon() {
+SkBitmap ToolbarView::GetAppMenuIcon(views::CustomButton::ButtonState state) {
ThemeProvider* tp = GetThemeProvider();
- SkBitmap icon = *tp->GetBitmapNamed(IDR_TOOLS);
+ int id = 0;
+ switch (state) {
+ case views::CustomButton::BS_NORMAL: id = IDR_TOOLS; break;
+ case views::CustomButton::BS_HOT: id = IDR_TOOLS_H; break;
+ case views::CustomButton::BS_PUSHED: id = IDR_TOOLS_P; break;
+ default: NOTREACHED(); break;
+ }
+ SkBitmap icon = *tp->GetBitmapNamed(id);
if (!Singleton<UpgradeDetector>::get()->notify_upgrade())
return icon;
@@ -627,9 +614,8 @@ SkBitmap ToolbarView::GetAppMenuIcon() {
// Convert animation values that start from 0.0 and incrementally go
// up to 1.0 into values that start in 0.0, go to 1.0 and then back
// to 0.0 (to create a pulsing effect).
- double value = 1.0 -
- abs(2.0 * update_reminder_animation_->GetCurrentValue() -
- 1.0);
+ double value =
+ 1.0 - abs(2.0 * update_reminder_animation_->GetCurrentValue() - 1.0);
// Add the badge to it.
badge = SkBitmapOperations::CreateBlendedBitmap(
@@ -638,34 +624,9 @@ SkBitmap ToolbarView::GetAppMenuIcon() {
value);
}
- canvas->DrawBitmapInt(badge, kUpgradeDotOffset,
- icon.height() - badge.height());
+ static const int kBadgeLeftSpacing = 8;
+ static const int kBadgeTopSpacing = 18;
+ canvas->DrawBitmapInt(badge, kBadgeLeftSpacing, kBadgeTopSpacing);
return canvas->ExtractBitmap();
}
-
-void ToolbarView::ActivateMenuButton(views::MenuButton* menu_button) {
-#if defined(OS_WIN)
- // On Windows, we have to explicitly clear the focus before opening
- // the pop-up menu, then set the focus again when it closes.
- GetFocusManager()->ClearFocus();
-#elif defined(OS_LINUX)
- // Under GTK, opening a pop-up menu causes the main window to lose focus.
- // Focus is automatically returned when the menu closes.
- //
- // Make sure that the menu button being activated has focus, so that
- // when the user escapes from the menu without selecting anything, focus
- // will be returned here.
- if (!menu_button->HasFocus()) {
- menu_button->RequestFocus();
- GetFocusManager()->StoreFocusedView();
- }
-#endif
-
- // Tell the menu button to activate, opening its pop-up menu.
- menu_button->Activate();
-
-#if defined(OS_WIN)
- SetToolbarFocus(NULL, menu_button);
-#endif
-}
diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h
index 83e28f6..d95111b 100644
--- a/chrome/browser/views/toolbar_view.h
+++ b/chrome/browser/views/toolbar_view.h
@@ -4,15 +4,16 @@
#ifndef CHROME_BROWSER_VIEWS_TOOLBAR_VIEW_H_
#define CHROME_BROWSER_VIEWS_TOOLBAR_VIEW_H_
+#pragma once
#include <vector>
-#include "app/menus/simple_menu_model.h"
+#include "app/menus/accelerator.h"
#include "app/slide_animation.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/back_forward_menu_model.h"
#include "chrome/browser/command_updater.h"
-#include "chrome/browser/pref_member.h"
+#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/views/accessible_toolbar_view.h"
#include "chrome/browser/views/location_bar/location_bar_view.h"
#include "chrome/browser/views/reload_button.h"
@@ -27,14 +28,10 @@ class Browser;
class Profile;
class WrenchMenu;
-namespace views {
-class Menu2;
-}
-
// The Browser Window's toolbar.
class ToolbarView : public AccessibleToolbarView,
public views::ViewMenuDelegate,
- public menus::SimpleMenuModel::Delegate,
+ public menus::AcceleratorProvider,
public LocationBarView::Delegate,
public AnimationDelegate,
public NotificationObserver,
@@ -91,6 +88,7 @@ class ToolbarView : public AccessibleToolbarView,
// Overridden from LocationBarView::Delegate:
virtual TabContents* GetTabContents();
+ virtual MatchPreview* GetMatchPreview();
virtual void OnInputInProgress(bool in_progress);
// Overridden from AnimationDelegate:
@@ -107,18 +105,22 @@ class ToolbarView : public AccessibleToolbarView,
const NotificationSource& source,
const NotificationDetails& details);
- // Overridden from menus::SimpleMenuModel::Delegate:
- virtual bool IsCommandIdChecked(int command_id) const;
- virtual bool IsCommandIdEnabled(int command_id) const;
+ // Overridden from menus::AcceleratorProvider:
virtual bool GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator);
- virtual void ExecuteCommand(int command_id);
// Overridden from views::View:
virtual gfx::Size GetPreferredSize();
virtual void Layout();
virtual void Paint(gfx::Canvas* canvas);
- virtual void ThemeChanged();
+ virtual void OnThemeChanged();
+
+ // The apparent horizontal space between most items, and the vertical padding
+ // above and below them.
+ static const int kStandardSpacing;
+ // The top of the toolbar has an edge we have to skip over in addition to the
+ // standard spacing.
+ static const int kVertSpacing;
protected:
@@ -133,13 +135,6 @@ class ToolbarView : public AccessibleToolbarView,
// Loads the images for all the child views.
void LoadImages();
- // Check if the menu exited with a code indicating the user wants to
- // switch to the other menu, and then switch to that other menu.
- void SwitchToOtherMenuIfNeeded(views::Menu2* previous_menu,
- views::MenuButton* next_menu_button);
-
- void ActivateMenuButton(views::MenuButton* menu_button);
-
// Types of display mode this toolbar can have.
enum DisplayMode {
DISPLAYMODE_NORMAL, // Normal toolbar with buttons, etc.
@@ -159,7 +154,7 @@ class ToolbarView : public AccessibleToolbarView,
// Gets a canvas with the icon for the app menu. It will possibly contain
// an overlaid badge if an update is recommended.
- SkBitmap GetAppMenuIcon();
+ SkBitmap GetAppMenuIcon(views::CustomButton::ButtonState state);
scoped_ptr<BackForwardMenuModel> back_menu_model_;
scoped_ptr<BackForwardMenuModel> forward_menu_model_;
@@ -170,8 +165,8 @@ class ToolbarView : public AccessibleToolbarView,
// Controls
views::ImageButton* back_;
views::ImageButton* forward_;
- views::ImageButton* home_;
ReloadButton* reload_;
+ views::ImageButton* home_;
LocationBarView* location_bar_;
BrowserActionsContainer* browser_actions_;
views::MenuButton* app_menu_;
@@ -187,8 +182,8 @@ class ToolbarView : public AccessibleToolbarView,
// The display mode used when laying out the toolbar.
DisplayMode display_mode_;
- // The contents of the app menu.
- scoped_ptr<menus::SimpleMenuModel> app_menu_model_;
+ // The contents of the wrench menu.
+ scoped_ptr<menus::SimpleMenuModel> wrench_menu_model_;
// Wrench menu.
scoped_ptr<WrenchMenu> wrench_menu_;
diff --git a/chrome/browser/views/unhandled_keyboard_event_handler.cc b/chrome/browser/views/unhandled_keyboard_event_handler.cc
index cc29354..9da60ee 100644
--- a/chrome/browser/views/unhandled_keyboard_event_handler.cc
+++ b/chrome/browser/views/unhandled_keyboard_event_handler.cc
@@ -38,7 +38,7 @@ void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
if (event.type == WebKit::WebInputEvent::RawKeyDown) {
views::Accelerator accelerator(
- static_cast<base::KeyboardCode>(event.windowsKeyCode),
+ static_cast<app::KeyboardCode>(event.windowsKeyCode),
(event.modifiers & NativeWebKeyboardEvent::ShiftKey) ==
NativeWebKeyboardEvent::ShiftKey,
(event.modifiers & NativeWebKeyboardEvent::ControlKey) ==
diff --git a/chrome/browser/views/unhandled_keyboard_event_handler.h b/chrome/browser/views/unhandled_keyboard_event_handler.h
index 4873bcd..13ac26d 100644
--- a/chrome/browser/views/unhandled_keyboard_event_handler.h
+++ b/chrome/browser/views/unhandled_keyboard_event_handler.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_UNHANDLED_KEYBOARD_EVENT_HANDLER_H_
#define CHROME_BROWSER_VIEWS_UNHANDLED_KEYBOARD_EVENT_HANDLER_H_
+#pragma once
#include "views/view.h"
#include "chrome/common/native_web_keyboard_event.h"
diff --git a/chrome/browser/views/uninstall_view.cc b/chrome/browser/views/uninstall_view.cc
index 2ecbc43..a7535b0 100644
--- a/chrome/browser/views/uninstall_view.cc
+++ b/chrome/browser/views/uninstall_view.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,6 +7,8 @@
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/process_util.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/browser_distribution.h"
@@ -142,9 +144,9 @@ int UninstallView::GetItemCount() {
return browsers_->size();
}
-std::wstring UninstallView::GetItemAt(int index) {
+string16 UninstallView::GetItemAt(int index) {
DCHECK(index < (int) browsers_->size());
BrowsersMap::const_iterator it = browsers_->begin();
std::advance(it, index);
- return (*it).first;
+ return WideToUTF16Hack((*it).first);
}
diff --git a/chrome/browser/views/uninstall_view.h b/chrome/browser/views/uninstall_view.h
index 9782da4..30a6268 100644
--- a/chrome/browser/views/uninstall_view.h
+++ b/chrome/browser/views/uninstall_view.h
@@ -1,11 +1,13 @@
-// 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.
#ifndef CHROME_BROWSER_VIEWS_UNINSTALL_VIEW_H_
#define CHROME_BROWSER_VIEWS_UNINSTALL_VIEW_H_
+#pragma once
#include "app/combobox_model.h"
+#include "base/string16.h"
#include "views/controls/combobox/combobox.h"
#include "views/window/dialog_delegate.h"
@@ -40,7 +42,7 @@ class UninstallView : public views::View,
// Overridden from views::Combobox::Model.
virtual int GetItemCount();
- virtual std::wstring GetItemAt(int index);
+ virtual string16 GetItemAt(int index);
private:
// Initializes the controls on the dialog.
diff --git a/chrome/browser/views/update_recommended_message_box.cc b/chrome/browser/views/update_recommended_message_box.cc
index 5e66b72..99ecbbd 100644
--- a/chrome/browser/views/update_recommended_message_box.cc
+++ b/chrome/browser/views/update_recommended_message_box.cc
@@ -8,7 +8,7 @@
#include "app/message_box_flags.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/views/update_recommended_message_box.h b/chrome/browser/views/update_recommended_message_box.h
index e5e39e2..033dc01 100644
--- a/chrome/browser/views/update_recommended_message_box.h
+++ b/chrome/browser/views/update_recommended_message_box.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_UPDATE_RECOMMENDED_MESSAGE_BOX_H_
#define CHROME_BROWSER_VIEWS_UPDATE_RECOMMENDED_MESSAGE_BOX_H_
+#pragma once
#include "base/basictypes.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/browser/views/url_picker.cc b/chrome/browser/views/url_picker.cc
index aa749e8..4051e63 100644
--- a/chrome/browser/views/url_picker.cc
+++ b/chrome/browser/views/url_picker.cc
@@ -4,16 +4,16 @@
#include "chrome/browser/views/url_picker.h"
+#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/table_model.h"
-#include "app/table_model_observer.h"
-#include "base/keyboard_codes.h"
#include "base/stl_util-inl.h"
+#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/possible_url_model.h"
-#include "chrome/browser/pref_service.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"
@@ -113,7 +113,7 @@ UrlPicker::UrlPicker(UrlPickerDelegate* delegate,
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- AddAccelerator(views::Accelerator(base::VKEY_RETURN, false, false, false));
+ AddAccelerator(views::Accelerator(app::VKEY_RETURN, false, false, false));
}
UrlPicker::~UrlPicker() {
@@ -219,16 +219,16 @@ bool UrlPicker::AcceleratorPressed(
void UrlPicker::OnSelectionChanged() {
int selection = url_table_->FirstSelectedRow();
if (selection >= 0 && selection < url_table_model_->RowCount()) {
- std::wstring languages = UTF8ToWide(
- profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ std::string languages =
+ profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
// Because this gets parsed by FixupURL(), it's safe to omit the scheme or
// trailing slash, and unescape most characters, but we need to not drop any
// username/password, or unescape anything that changes the meaning.
- std::wstring formatted = net::FormatUrl(url_table_model_->GetURL(selection),
+ string16 formatted = net::FormatUrl(url_table_model_->GetURL(selection),
languages,
net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword,
UnescapeRule::SPACES, NULL, NULL, NULL);
- url_field_->SetText(formatted);
+ url_field_->SetText(UTF16ToWide(formatted));
GetDialogClientView()->UpdateDialogButtons();
}
}
diff --git a/chrome/browser/views/url_picker.h b/chrome/browser/views/url_picker.h
index 14975e2..e08892e 100644
--- a/chrome/browser/views/url_picker.h
+++ b/chrome/browser/views/url_picker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_URL_PICKER_H_
#define CHROME_BROWSER_VIEWS_URL_PICKER_H_
+#pragma once
#include "views/controls/button/native_button.h"
#include "views/controls/table/table_view_observer.h"
diff --git a/chrome/browser/views/user_data_dir_dialog.h b/chrome/browser/views/user_data_dir_dialog.h
index 5634e96..2ada803 100644
--- a/chrome/browser/views/user_data_dir_dialog.h
+++ b/chrome/browser/views/user_data_dir_dialog.h
@@ -7,6 +7,7 @@
#ifndef CHROME_BROWSER_VIEWS_USER_DATA_DIR_DIALOG_H_
#define CHROME_BROWSER_VIEWS_USER_DATA_DIR_DIALOG_H_
+#pragma once
#include "base/basictypes.h"
#include "base/message_loop.h"
diff --git a/chrome/browser/views/wrench_menu.cc b/chrome/browser/views/wrench_menu.cc
index aa2a05b..bc7ee5a 100644
--- a/chrome/browser/views/wrench_menu.cc
+++ b/chrome/browser/views/wrench_menu.cc
@@ -8,6 +8,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
@@ -21,6 +22,7 @@
#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
#include "gfx/skia_util.h"
+#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkPaint.h"
@@ -60,7 +62,8 @@ const int kHorizontalPadding = 6;
// Subclass of ImageButton whose preferred size includes the size of the border.
class FullscreenButton : public ImageButton {
public:
- FullscreenButton(views::ButtonListener* listener) : ImageButton(listener) {}
+ explicit FullscreenButton(views::ButtonListener* listener)
+ : ImageButton(listener) { }
virtual gfx::Size GetPreferredSize() {
gfx::Size pref = ImageButton::GetPreferredSize();
@@ -86,9 +89,9 @@ class MenuButtonBorder : public views::Border {
}
virtual void GetInsets(gfx::Insets* insets) const {
- insets->Set(MenuConfig::instance().item_no_icon_top_margin,
+ insets->Set(MenuConfig::instance().item_top_margin,
kHorizontalPadding,
- MenuConfig::instance().item_no_icon_bottom_margin,
+ MenuConfig::instance().item_bottom_margin,
kHorizontalPadding);
}
@@ -116,8 +119,13 @@ class MenuButtonBackground : public views::Background {
// Used when the type is CENTER_BUTTON to determine if the left/right edge
// needs to be rendered selected.
void SetOtherButtons(CustomButton* left_button, CustomButton* right_button) {
- left_button_ = left_button;
- right_button_ = right_button;
+ if (base::i18n::IsRTL()) {
+ left_button_ = right_button;
+ right_button_ = left_button;
+ } else {
+ left_button_ = left_button;
+ right_button_ = right_button;
+ }
}
virtual void Paint(gfx::Canvas* canvas, View* view) const {
@@ -258,7 +266,6 @@ TextButton* CreateAndConfigureButton(View* parent,
*background = bg;
button->set_border(new MenuButtonBorder());
button->set_alignment(TextButton::ALIGN_CENTER);
- button->SetShowHighlighted(true);
button->SetNormalHasBorder(true);
button->SetFont(views::MenuConfig::instance().font);
button->ClearMaxTextSize();
@@ -358,6 +365,8 @@ class WrenchMenu::ZoomView : public ScheduleAllView,
decrement_button_ = CreateAndConfigureButton(
this, this, IDS_ZOOM_MINUS2, MenuButtonBackground::LEFT_BUTTON,
menu_model, decrement_index, NULL);
+ decrement_button_->SetAccessibleName(
+ l10n_util::GetString(IDS_ACCNAME_ZOOM_MINUS2));
zoom_label_ = new Label(l10n_util::GetStringF(IDS_ZOOM_PERCENT, L"100"));
zoom_label_->SetColor(MenuConfig::instance().text_color);
@@ -373,8 +382,10 @@ class WrenchMenu::ZoomView : public ScheduleAllView,
increment_button_ = CreateAndConfigureButton(
this, this, IDS_ZOOM_PLUS2, MenuButtonBackground::RIGHT_BUTTON,
menu_model, increment_index, NULL);
+ increment_button_->SetAccessibleName(
+ l10n_util::GetString(IDS_ACCNAME_ZOOM_PLUS2));
- center_bg->SetOtherButtons(increment_button_, decrement_button_);
+ center_bg->SetOtherButtons(decrement_button_, increment_button_);
fullscreen_button_ = new FullscreenButton(this);
fullscreen_button_->SetImage(
@@ -390,6 +401,8 @@ class WrenchMenu::ZoomView : public ScheduleAllView,
0, kHorizontalPadding, 0, kHorizontalPadding));
fullscreen_button_->set_background(
new MenuButtonBackground(MenuButtonBackground::SINGLE_BUTTON));
+ fullscreen_button_->SetAccessibleName(
+ l10n_util::GetString(IDS_ACCNAME_FULLSCREEN));
AddChildView(fullscreen_button_);
UpdateZoomControls();
@@ -463,14 +476,15 @@ class WrenchMenu::ZoomView : public ScheduleAllView,
increment_button_->SetEnabled(enable_increment);
decrement_button_->SetEnabled(enable_decrement);
zoom_label_->SetText(l10n_util::GetStringF(
- IDS_ZOOM_PERCENT, IntToWString(zoom_percent)));
+ IDS_ZOOM_PERCENT,
+ UTF8ToWide(base::IntToString(zoom_percent))));
// If both increment and decrement are disabled, then we disable the zoom
// label too.
zoom_label_->SetEnabled(enable_increment || enable_decrement);
}
double GetZoom(bool* enable_increment, bool* enable_decrement) {
- // TODO: move this somewhere it can be shared.
+ // TODO(sky): move this somewhere it can be shared.
TabContents* selected_tab = menu_->browser_->GetSelectedTabContents();
*enable_decrement = *enable_increment = false;
if (!selected_tab)
@@ -550,6 +564,7 @@ WrenchMenu::~WrenchMenu() {
void WrenchMenu::Init(menus::MenuModel* model) {
DCHECK(!root_.get());
root_.reset(new MenuItemView(this));
+ root_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_APP));
root_->set_has_icons(true); // We have checks, radios and icons, set this
// so we get the taller menu style.
int next_id = 1;
@@ -559,11 +574,10 @@ void WrenchMenu::Init(menus::MenuModel* model) {
void WrenchMenu::RunMenu(views::MenuButton* host) {
gfx::Point screen_loc;
views::View::ConvertPointToScreen(host, &screen_loc);
- // Subtract 1 from the height to make the popup flush with the button border.
- gfx::Rect bounds(screen_loc.x(), screen_loc.y(), host->width(),
- host->height() - 1);
+ gfx::Rect bounds(screen_loc, host->size());
root_->RunMenuAt(host->GetWindow()->GetNativeWindow(), host, bounds,
- MenuItemView::TOPRIGHT, true);
+ base::i18n::IsRTL() ? MenuItemView::TOPLEFT : MenuItemView::TOPRIGHT,
+ true);
if (selected_menu_model_)
selected_menu_model_->ActivatedAt(selected_index_);
}
@@ -692,6 +706,9 @@ MenuItemView* WrenchMenu::AppendMenuItem(MenuItemView* parent,
MenuItemView* menu_item = parent->AppendMenuItemImpl(id, label, icon, type);
+ if (menu_item)
+ menu_item->SetVisible(model->IsVisibleAt(index));
+
if (menu_type == MenuModel::TYPE_COMMAND && model->HasIcons()) {
SkBitmap icon;
if (model->GetIconAt(index, &icon))
diff --git a/chrome/browser/views/wrench_menu.h b/chrome/browser/views/wrench_menu.h
index 377dcf8..73653cc 100644
--- a/chrome/browser/views/wrench_menu.h
+++ b/chrome/browser/views/wrench_menu.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_VIEWS_WRENCH_MENU_H_
#define CHROME_BROWSER_VIEWS_WRENCH_MENU_H_
+#pragma once
#include <map>
#include <utility>
diff --git a/chrome/browser/visitedlink_event_listener.cc b/chrome/browser/visitedlink_event_listener.cc
index 9003fcc..3c06608 100644
--- a/chrome/browser/visitedlink_event_listener.cc
+++ b/chrome/browser/visitedlink_event_listener.cc
@@ -6,7 +6,6 @@
#include "base/shared_memory.h"
#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/common/render_messages.h"
using base::Time;
using base::TimeDelta;
@@ -14,6 +13,12 @@ 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;
diff --git a/chrome/browser/visitedlink_event_listener.h b/chrome/browser/visitedlink_event_listener.h
index 7c4eda3..00a7392 100644
--- a/chrome/browser/visitedlink_event_listener.h
+++ b/chrome/browser/visitedlink_event_listener.h
@@ -8,6 +8,7 @@
#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"
@@ -18,8 +19,8 @@ class SharedMemory;
class VisitedLinkEventListener : public VisitedLinkMaster::Listener {
public:
- VisitedLinkEventListener() {}
- virtual ~VisitedLinkEventListener() {}
+ VisitedLinkEventListener();
+ virtual ~VisitedLinkEventListener();
virtual void NewTable(base::SharedMemory* table_memory);
virtual void Add(VisitedLinkMaster::Fingerprint fingerprint);
diff --git a/chrome/browser/visitedlink_master.cc b/chrome/browser/visitedlink_master.cc
index 606261f..6eec909 100644
--- a/chrome/browser/visitedlink_master.cc
+++ b/chrome/browser/visitedlink_master.cc
@@ -13,9 +13,6 @@
#include <algorithm>
-#if defined(OS_WIN)
-#include "app/win_util.h"
-#endif
#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
@@ -673,7 +670,7 @@ bool VisitedLinkMaster::CreateURLTable(int32 num_entries, bool init_to_empty) {
if (!shared_memory_)
return false;
- if (!shared_memory_->Create(std::wstring() /* anonymous */,
+ if (!shared_memory_->Create(std::string() /* anonymous */,
false /* read-write */, false /* create */,
alloc_size)) {
return false;
diff --git a/chrome/browser/visitedlink_master.h b/chrome/browser/visitedlink_master.h
index 24b6499..55d260b 100644
--- a/chrome/browser/visitedlink_master.h
+++ b/chrome/browser/visitedlink_master.h
@@ -4,12 +4,12 @@
#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 <string>
#include <vector>
#include "base/file_path.h"
@@ -20,7 +20,6 @@
#include "chrome/common/visitedlink_common.h"
class GURL;
-class MessageLoop;
class Profile;
// Controls the link coloring database. The master controls all writing to the
diff --git a/chrome/browser/visitedlink_unittest.cc b/chrome/browser/visitedlink_unittest.cc
index 64d30bb..f07e80f 100644
--- a/chrome/browser/visitedlink_unittest.cc
+++ b/chrome/browser/visitedlink_unittest.cc
@@ -19,6 +19,7 @@
#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"
@@ -160,10 +161,10 @@ class VisitedLinkTest : public testing::Test {
// testing::Test
virtual void SetUp() {
- PathService::Get(base::DIR_TEMP, &history_dir_);
- history_dir_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinkTest"));
- file_util::Delete(history_dir_, true);
- file_util::CreateDirectory(history_dir_);
+ 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();
@@ -171,9 +172,10 @@ class VisitedLinkTest : public testing::Test {
virtual void TearDown() {
ClearDB();
- file_util::Delete(history_dir_, true);
}
+ ScopedTempDir temp_dir_;
+
MessageLoop message_loop_;
ChromeThread ui_thread_;
ChromeThread file_thread_;
@@ -371,7 +373,7 @@ TEST_F(VisitedLinkTest, Rebuild) {
// 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_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.
@@ -676,7 +678,7 @@ TEST_F(VisitedLinkEventsTest, Coalescense) {
TEST_F(VisitedLinkRelayTest, Basics) {
VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
- rvh()->CreateRenderView(profile_->GetRequestContext(), string16());
+ rvh()->CreateRenderView(string16());
// Add a few URLs.
master->AddURL(GURL("http://acidtests.org/"));
@@ -700,7 +702,7 @@ TEST_F(VisitedLinkRelayTest, Basics) {
TEST_F(VisitedLinkRelayTest, TabVisibility) {
VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
- rvh()->CreateRenderView(profile_->GetRequestContext(), string16());
+ rvh()->CreateRenderView(string16());
// Simulate tab becoming inactive.
rvh()->WasHidden();
@@ -763,7 +765,7 @@ TEST_F(VisitedLinkRelayTest, WebViewReadiness) {
EXPECT_EQ(0, profile()->add_event_count());
EXPECT_EQ(0, profile()->reset_event_count());
- rvh()->CreateRenderView(profile_->GetRequestContext(), string16());
+ rvh()->CreateRenderView(string16());
// We should now have just a reset event: adds are eaten up by a reset
// that followed.
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index 97a2329..99e004b 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -6,6 +6,7 @@
#if defined(OS_WIN)
#include <shellapi.h>
+#include <shlobj.h>
#endif // defined(OS_WIN)
#include <algorithm>
@@ -33,7 +34,7 @@
#include "webkit/glue/dom_operations.h"
#if defined(OS_LINUX)
-#include "base/env_var.h"
+#include "base/environment.h"
#endif // defined(OS_LINUX)
#if defined(OS_WIN)
@@ -110,13 +111,16 @@ FilePath GetWebAppDataDirectory(const FilePath& root_dir,
return root_dir.Append(GetWebAppDir(url));
}
+#if defined(TOOLKIT_VIEWS)
// Predicator for sorting images from largest to smallest.
bool IconPrecedes(
const webkit_glue::WebApplicationInfo::IconInfo& left,
const webkit_glue::WebApplicationInfo::IconInfo& right) {
return left.width < right.width;
}
+#endif
+#if defined(OS_WIN)
// Calculates image checksum using MD5.
void GetImageCheckSum(const SkBitmap& image, MD5Digest* digest) {
DCHECK(digest);
@@ -125,10 +129,9 @@ void GetImageCheckSum(const SkBitmap& image, MD5Digest* digest) {
MD5Sum(image.getPixels(), image.getSize(), digest);
}
-#if defined(OS_WIN)
// Saves |image| as an |icon_file| with the checksum.
bool SaveIconWithCheckSum(const FilePath& icon_file, const SkBitmap& image) {
- if (!IconUtil::CreateIconFileFromSkBitmap(image, icon_file.value()))
+ if (!IconUtil::CreateIconFileFromSkBitmap(image, icon_file))
return false;
MD5Digest digest;
@@ -259,10 +262,10 @@ bool CreateShortcutTask::CreateShortcut() {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
#if defined(OS_LINUX)
- scoped_ptr<base::EnvVarGetter> env_getter(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
std::string shortcut_template;
- if (!ShellIntegration::GetDesktopShortcutTemplate(env_getter.get(),
+ if (!ShellIntegration::GetDesktopShortcutTemplate(env.get(),
&shortcut_template)) {
return false;
}
@@ -373,7 +376,7 @@ bool CreateShortcutTask::CreateShortcut() {
// Generates app id from web app url and profile path.
std::wstring app_id = ShellIntegration::GetAppId(
- web_app::GenerateApplicationNameFromURL(shortcut_info_.url),
+ UTF8ToWide(web_app::GenerateApplicationNameFromURL(shortcut_info_.url)),
profile_path_);
FilePath shortcut_to_pin;
@@ -630,7 +633,7 @@ void UpdateShortcutWorker::UpdateShortcutsOnFileThread() {
if (!shortcut_files_.empty()) {
// Generates app id from web app url and profile path.
std::wstring app_id = ShellIntegration::GetAppId(
- web_app::GenerateApplicationNameFromURL(shortcut_info_.url),
+ UTF8ToWide(web_app::GenerateApplicationNameFromURL(shortcut_info_.url)),
profile_path_);
// Sanitize description
@@ -681,12 +684,12 @@ DISABLE_RUNNABLE_METHOD_REFCOUNT(UpdateShortcutWorker);
namespace web_app {
-std::wstring GenerateApplicationNameFromURL(const GURL& url) {
+std::string GenerateApplicationNameFromURL(const GURL& url) {
std::string t;
t.append(url.host());
t.append("_");
t.append(url.path());
- return UTF8ToWide(t);
+ return t;
}
void CreateShortcut(
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index abe5b93..c451e85 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_H_
+#pragma once
#include <vector>
@@ -21,7 +22,7 @@ namespace web_app {
// Compute a deterministic name based on the URL. We use this pseudo name
// as a key to store window location per application URLs in Browser and
// as app id for BrowserWindow, shortcut and jump list.
-std::wstring GenerateApplicationNameFromURL(const GURL& url);
+std::string GenerateApplicationNameFromURL(const GURL& url);
// Callback after user dismisses CreateShortcutView. "true" indicates
// shortcut is created successfully. Otherwise, it is false.
diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc
index c1a487f..33e42b8 100644
--- a/chrome/browser/web_applications/web_app_unittest.cc
+++ b/chrome/browser/web_applications/web_app_unittest.cc
@@ -6,7 +6,10 @@
#include "base/file_path.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/common/render_messages.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc
index 930c933..94c89d8 100644
--- a/chrome/browser/web_resource/web_resource_service.cc
+++ b/chrome/browser/web_resource/web_resource_service.cc
@@ -1,9 +1,13 @@
-// 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.
+
#include "chrome/browser/web_resource/web_resource_service.h"
#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
@@ -12,13 +16,15 @@
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/url_fetcher.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_status.h"
-const wchar_t* WebResourceService::kCurrentTipPrefName = L"current_tip";
-const wchar_t* WebResourceService::kTipCachePrefName = L"tips";
+const char* WebResourceService::kCurrentTipPrefName = "current_tip";
+const char* WebResourceService::kTipCachePrefName = "tips";
class WebResourceService::WebResourceFetcher
: public URLFetcher::Delegate {
@@ -39,6 +45,8 @@ class WebResourceService::WebResourceFetcher
// Initializes the fetching of data from the resource server. Data
// load calls OnURLFetchComplete.
void StartFetch() {
+ // Balanced in OnURLFetchComplete.
+ web_resource_service_->AddRef();
// First, put our next cache load on the MessageLoop.
MessageLoop::current()->PostDelayedTask(FROM_HERE,
fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
@@ -76,6 +84,7 @@ class WebResourceService::WebResourceFetcher
return;
web_resource_service_->UpdateResourceCache(data);
+ web_resource_service_->Release();
}
private:
@@ -86,8 +95,8 @@ class WebResourceService::WebResourceFetcher
// The tool that fetches the url data from the server.
scoped_ptr<URLFetcher> url_fetcher_;
- // Our owner and creator.
- scoped_refptr<WebResourceService> web_resource_service_;
+ // Our owner and creator. Ref counted.
+ WebResourceService* web_resource_service_;
};
// This class coordinates a web resource unpack and parse task which is run in
@@ -178,22 +187,12 @@ class WebResourceService::UnpackerClient
bool got_response_;
};
-// TODO(mirandac): replace these servers tomorrow!
+// Server for custom logo signals.
const char* WebResourceService::kDefaultResourceServer =
-#if defined(OS_MACOSX)
- "https://clients2.google.com/tools/service/npredir?r=chrometips_mac&hl=";
-#elif defined(OS_LINUX)
- "https://clients2.google.com/tools/service/npredir?r=chrometips_linux&hl=";
-#else
- "https://clients2.google.com/tools/service/npredir?r=chrometips_win&hl=";
-#endif
-
-const char* WebResourceService::kResourceDirectoryName =
- "Resources";
+ "https://www.google.com/support/chrome/bin/topic/30248/inproduct";
WebResourceService::WebResourceService(Profile* profile)
: prefs_(profile->GetPrefs()),
- web_resource_dir_(profile->GetPath().AppendASCII(kResourceDirectoryName)),
in_fetch_(false) {
Init();
}
@@ -202,22 +201,19 @@ WebResourceService::~WebResourceService() { }
void WebResourceService::Init() {
resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host();
- web_resource_fetcher_ = new WebResourceFetcher(this);
- prefs_->RegisterStringPref(prefs::kNTPTipsCacheUpdate, "0");
- std::string locale = g_browser_process->GetApplicationLocale();
-
- if (prefs_->HasPrefPath(prefs::kNTPTipsServer)) {
- web_resource_server_ = prefs_->GetString(prefs::kNTPTipsServer);
- // If we are in the correct locale, initialization is done.
- if (EndsWith(web_resource_server_, locale, false))
- return;
+ web_resource_fetcher_.reset(new WebResourceFetcher(this));
+ prefs_->RegisterStringPref(prefs::kNTPWebResourceCacheUpdate, "0");
+ prefs_->RegisterRealPref(prefs::kNTPCustomLogoStart, 0);
+ prefs_->RegisterRealPref(prefs::kNTPCustomLogoEnd, 0);
+
+ if (prefs_->HasPrefPath(prefs::kNTPLogoResourceServer)) {
+ web_resource_server_ = prefs_->GetString(prefs::kNTPLogoResourceServer);
+ return;
}
- // If we have not yet set a server, or if the tips server is set to the wrong
- // locale, reset the server and force an immediate update of tips.
+ // If we have not yet set a server, reset and force an immediate update.
web_resource_server_ = kDefaultResourceServer;
- web_resource_server_.append(locale);
- prefs_->SetString(prefs::kNTPTipsCacheUpdate, "");
+ prefs_->SetString(prefs::kNTPWebResourceCacheUpdate, "");
}
void WebResourceService::EndFetch() {
@@ -226,9 +222,48 @@ void WebResourceService::EndFetch() {
void WebResourceService::OnWebResourceUnpacked(
const DictionaryValue& parsed_json) {
+ UnpackLogoSignal(parsed_json);
+ EndFetch();
+}
+
+void WebResourceService::StartAfterDelay() {
+ int delay = kStartResourceFetchDelay;
+ // Check whether we have ever put a value in the web resource cache;
+ // if so, pull it out and see if it's time to update again.
+ if (prefs_->HasPrefPath(prefs::kNTPWebResourceCacheUpdate)) {
+ std::string last_update_pref =
+ prefs_->GetString(prefs::kNTPWebResourceCacheUpdate);
+ if (!last_update_pref.empty()) {
+ double last_update_value;
+ base::StringToDouble(last_update_pref, &last_update_value);
+ int ms_until_update = kCacheUpdateDelay -
+ static_cast<int>((base::Time::Now() - base::Time::FromDoubleT(
+ last_update_value)).InMilliseconds());
+
+ delay = ms_until_update > kCacheUpdateDelay ?
+ kCacheUpdateDelay : (ms_until_update < kStartResourceFetchDelay ?
+ kStartResourceFetchDelay : ms_until_update);
+ }
+ }
+
+ // Start fetch and wait for UpdateResourceCache.
+ web_resource_fetcher_->StartAfterDelay(static_cast<int>(delay));
+}
+
+void WebResourceService::UpdateResourceCache(const std::string& json_data) {
+ UnpackerClient* client = new UnpackerClient(this, json_data);
+ client->Start();
+
+ // Update resource server and cache update time in preferences.
+ prefs_->SetString(prefs::kNTPWebResourceCacheUpdate,
+ base::DoubleToString(base::Time::Now().ToDoubleT()));
+ prefs_->SetString(prefs::kNTPLogoResourceServer, web_resource_server_);
+}
+
+void WebResourceService::UnpackTips(const DictionaryValue& parsed_json) {
// Get dictionary of cached preferences.
web_resource_cache_ =
- prefs_->GetMutableDictionary(prefs::kNTPTipsCache);
+ prefs_->GetMutableDictionary(prefs::kNTPWebResourceCache);
// The list of individual tips.
ListValue* tip_holder = new ListValue();
@@ -236,62 +271,98 @@ void WebResourceService::OnWebResourceUnpacked(
DictionaryValue* topic_dict;
ListValue* answer_list;
- std::wstring topic_id;
- std::wstring inproduct;
+ std::string topic_id;
+ std::string answer_id;
+ std::string inproduct;
int tip_counter = 0;
- if (parsed_json.GetDictionary(L"topic", &topic_dict)) {
- if (topic_dict->GetString(L"topic_id", &topic_id))
- web_resource_cache_->SetString(L"topic_id", topic_id);
- if (topic_dict->GetList(L"answers", &answer_list)) {
+ if (parsed_json.GetDictionary("topic", &topic_dict)) {
+ if (topic_dict->GetString("topic_id", &topic_id))
+ web_resource_cache_->SetString("topic_id", topic_id);
+ if (topic_dict->GetList("answers", &answer_list)) {
for (ListValue::const_iterator tip_iter = answer_list->begin();
tip_iter != answer_list->end(); ++tip_iter) {
if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
continue;
DictionaryValue* a_dic =
static_cast<DictionaryValue*>(*tip_iter);
- if (a_dic->GetString(L"inproduct", &inproduct)) {
+ if (a_dic->GetString("inproduct", &inproduct)) {
tip_holder->Append(Value::CreateStringValue(inproduct));
}
tip_counter++;
}
- // If we have tips, set current tip to zero.
- if (!inproduct.empty())
+ // If tips exist, set current index to 0.
+ if (!inproduct.empty()) {
web_resource_cache_->SetInteger(
WebResourceService::kCurrentTipPrefName, 0);
+ }
}
}
- EndFetch();
}
-void WebResourceService::StartAfterDelay() {
- int delay = kStartResourceFetchDelay;
- // Check whether we have ever put a value in the web resource cache;
- // if so, pull it out and see if it's time to update again.
- if (prefs_->HasPrefPath(prefs::kNTPTipsCacheUpdate)) {
- std::string last_update_pref =
- prefs_->GetString(prefs::kNTPTipsCacheUpdate);
- if (!last_update_pref.empty()) {
- int ms_until_update = kCacheUpdateDelay -
- static_cast<int>((base::Time::Now() - base::Time::FromDoubleT(
- StringToDouble(last_update_pref))).InMilliseconds());
+void WebResourceService::UnpackLogoSignal(const DictionaryValue& parsed_json) {
+ DictionaryValue* topic_dict;
+ ListValue* answer_list;
+ double old_logo_start = 0;
+ double old_logo_end = 0;
+ double logo_start = 0;
+ double logo_end = 0;
+
+ // Check for preexisting start and end values.
+ if (prefs_->HasPrefPath(prefs::kNTPCustomLogoStart) &&
+ prefs_->HasPrefPath(prefs::kNTPCustomLogoEnd)) {
+ old_logo_start = prefs_->GetReal(prefs::kNTPCustomLogoStart);
+ old_logo_end = prefs_->GetReal(prefs::kNTPCustomLogoEnd);
+ }
- delay = ms_until_update > kCacheUpdateDelay ?
- kCacheUpdateDelay : (ms_until_update < kStartResourceFetchDelay ?
- kStartResourceFetchDelay : ms_until_update);
+ // Check for newly received start and end values.
+ if (parsed_json.GetDictionary("topic", &topic_dict)) {
+ if (topic_dict->GetList("answers", &answer_list)) {
+ std::string logo_start_string = "";
+ std::string logo_end_string = "";
+ for (ListValue::const_iterator tip_iter = answer_list->begin();
+ tip_iter != answer_list->end(); ++tip_iter) {
+ if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
+ continue;
+ DictionaryValue* a_dic =
+ static_cast<DictionaryValue*>(*tip_iter);
+ std::string logo_signal;
+ if (a_dic->GetString("name", &logo_signal)) {
+ if (logo_signal == "custom_logo_start") {
+ a_dic->GetString("inproduct", &logo_start_string);
+ } else if (logo_signal == "custom_logo_end") {
+ a_dic->GetString("inproduct", &logo_end_string);
+ }
+ }
+ }
+ if (!logo_start_string.empty() &&
+ logo_start_string.length() > 0 &&
+ !logo_end_string.empty() &&
+ logo_end_string.length() > 0) {
+ base::Time start_time;
+ base::Time end_time;
+ if (base::Time::FromString(
+ ASCIIToWide(logo_start_string).c_str(), &start_time) &&
+ base::Time::FromString(
+ ASCIIToWide(logo_end_string).c_str(), &end_time)) {
+ logo_start = start_time.ToDoubleT();
+ logo_end = end_time.ToDoubleT();
+ }
+ }
}
}
- // Start fetch and wait for UpdateResourceCache.
- web_resource_fetcher_->StartAfterDelay(static_cast<int>(delay));
-}
-
-void WebResourceService::UpdateResourceCache(const std::string& json_data) {
- UnpackerClient* client = new UnpackerClient(this, json_data);
- client->Start();
-
- // Update resource server and cache update time in preferences.
- prefs_->SetString(prefs::kNTPTipsCacheUpdate,
- DoubleToString(base::Time::Now().ToDoubleT()));
- prefs_->SetString(prefs::kNTPTipsServer, web_resource_server_);
+ // If logo start or end times have changed, trigger a theme change so that
+ // the logo on the NTP is updated. This check is outside the reading of the
+ // web resource data, because the absence of dates counts as a triggering
+ // change if there were dates before.
+ if (!(old_logo_start == logo_start) ||
+ !(old_logo_end == logo_end)) {
+ prefs_->SetReal(prefs::kNTPCustomLogoStart, logo_start);
+ prefs_->SetReal(prefs::kNTPCustomLogoEnd, logo_end);
+ NotificationService* service = NotificationService::current();
+ service->Notify(NotificationType::BROWSER_THEME_CHANGED,
+ Source<WebResourceService>(this),
+ NotificationService::NoDetails());
+ }
}
diff --git a/chrome/browser/web_resource/web_resource_service.h b/chrome/browser/web_resource/web_resource_service.h
index 6e26cd3..333f814 100644
--- a/chrome/browser/web_resource/web_resource_service.h
+++ b/chrome/browser/web_resource/web_resource_service.h
@@ -1,13 +1,15 @@
-// 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.
#ifndef CHROME_BROWSER_WEB_RESOURCE_WEB_RESOURCE_SERVICE_H_
#define CHROME_BROWSER_WEB_RESOURCE_WEB_RESOURCE_SERVICE_H_
+#pragma once
#include <string>
-#include "chrome/browser/pref_service.h"
+#include "base/file_path.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/utility_process_host.h"
#include "chrome/common/web_resource/web_resource_unpacker.h"
@@ -26,9 +28,45 @@ class WebResourceService
// the process that will parse the JSON, and then update the cache.
void UpdateResourceCache(const std::string& json_data);
- static const wchar_t* kTipDictionaryPrefName;
- static const wchar_t* kCurrentTipPrefName;
- static const wchar_t* kTipCachePrefName;
+ // Unpack the web resource as a set of tips. Expects json in the form of:
+ // {
+ // "lang": "en",
+ // "topic": {
+ // "topid_id": "24013",
+ // "topics": [
+ // ],
+ // "answers": [
+ // {
+ // "answer_id": "18625",
+ // "inproduct": "Text here will be shown as a tip",
+ // },
+ // ...
+ // ]
+ // }
+ // }
+ //
+ // Public for unit testing.
+ void UnpackTips(const DictionaryValue& parsed_json);
+
+ // Unpack the web resource as a custom logo signal. Expects json in the form
+ // of:
+ // {
+ // "topic": {
+ // "answers": [
+ // {
+ // "custom_logo_start": "31/12/10 01:00",
+ // "custom_logo_end": "31/01/11 01:00"
+ // },
+ // ...
+ // ]
+ // }
+ // }
+ //
+ // Public for unit testing.
+ void UnpackLogoSignal(const DictionaryValue& parsed_json);
+
+ static const char* kCurrentTipPrefName;
+ static const char* kTipCachePrefName;
// Default server from which to gather resources.
static const char* kDefaultResourceServer;
@@ -53,12 +91,10 @@ class WebResourceService
// and get proper install directory.
PrefService* prefs_;
- FilePath web_resource_dir_;
-
// Server from which we are currently pulling web resource data.
std::string web_resource_server_;
- WebResourceFetcher* web_resource_fetcher_;
+ scoped_ptr<WebResourceFetcher> web_resource_fetcher_;
ResourceDispatcherHost* resource_dispatcher_host_;
@@ -71,21 +107,13 @@ class WebResourceService
// kCacheUpdateDelay time, and silently exit.
bool in_fetch_;
- // Maximum number of cached resources available.
- static const int kMaxResourceCacheSize = 6;
-
// Delay on first fetch so we don't interfere with startup.
static const int kStartResourceFetchDelay = 5000;
// Delay between calls to update the cache (48 hours).
static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000;
- // Name of directory inside the profile where we will store resource-related
- // data (for now, thumbnail images).
- static const char* kResourceDirectoryName;
-
DISALLOW_COPY_AND_ASSIGN(WebResourceService);
};
#endif // CHROME_BROWSER_WEB_RESOURCE_WEB_RESOURCE_SERVICE_H_
-
diff --git a/chrome/browser/webdata/autofill_change.h b/chrome/browser/webdata/autofill_change.h
index b1108ad..de433cc 100644
--- a/chrome/browser/webdata/autofill_change.h
+++ b/chrome/browser/webdata/autofill_change.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
#define CHROME_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
+#pragma once
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
diff --git a/chrome/browser/webdata/autofill_entry.h b/chrome/browser/webdata/autofill_entry.h
index cb310c3..4917b29 100644
--- a/chrome/browser/webdata/autofill_entry.h
+++ b/chrome/browser/webdata/autofill_entry.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WEBDATA_AUTOFILL_ENTRY_H__
#define CHROME_BROWSER_WEBDATA_AUTOFILL_ENTRY_H__
+#pragma once
#include <vector>
#include "base/string16.h"
diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc
index 4b7f93e..16cceac 100644
--- a/chrome/browser/webdata/web_data_service.cc
+++ b/chrome/browser/webdata/web_data_service.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.
@@ -10,6 +10,7 @@
#include "base/thread.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
+#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
@@ -20,6 +21,7 @@
#include "chrome/common/notification_type.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/glue/password_form.h"
////////////////////////////////////////////////////////////////////////////////
@@ -32,6 +34,12 @@ using base::Time;
using webkit_glue::FormField;
using webkit_glue::PasswordForm;
+WDAppImagesResult::WDAppImagesResult() : has_all_images(false) {
+}
+
+WDAppImagesResult::~WDAppImagesResult() {
+}
+
WebDataService::WebDataService()
: is_running_(false),
db_(NULL),
@@ -63,7 +71,7 @@ void WebDataService::CancelRequest(Handle h) {
AutoLock l(pending_lock_);
RequestMap::iterator i = pending_requests_.find(h);
if (i == pending_requests_.end()) {
- NOTREACHED() << "Canceling a nonexistant web data service request";
+ NOTREACHED() << "Canceling a nonexistent web data service request";
return;
}
i->second->Cancel();
@@ -85,6 +93,9 @@ WebDatabase* WebDataService::GetDatabase() {
//////////////////////////////////////////////////////////////////////////////
void WebDataService::AddKeyword(const TemplateURL& url) {
+ // Ensure that the keyword is already generated (and cached) before caching
+ // the TemplateURL for use on another keyword.
+ url.EnsureKeyword();
GenericRequest<TemplateURL>* request =
new GenericRequest<TemplateURL>(this, GetNextRequestHandle(), NULL, url);
RegisterRequest(request);
@@ -93,15 +104,18 @@ void WebDataService::AddKeyword(const TemplateURL& url) {
}
void WebDataService::RemoveKeyword(const TemplateURL& url) {
- GenericRequest<TemplateURL::IDType>* request =
- new GenericRequest<TemplateURL::IDType>(this, GetNextRequestHandle(),
- NULL, url.id());
+ GenericRequest<TemplateURLID>* request =
+ new GenericRequest<TemplateURLID>(this, GetNextRequestHandle(),
+ NULL, url.id());
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this, &WebDataService::RemoveKeywordImpl, request));
}
void WebDataService::UpdateKeyword(const TemplateURL& url) {
+ // Ensure that the keyword is already generated (and cached) before caching
+ // the TemplateURL for use on another keyword.
+ url.EnsureKeyword();
GenericRequest<TemplateURL>* request =
new GenericRequest<TemplateURL>(this, GetNextRequestHandle(), NULL, url);
RegisterRequest(request);
@@ -122,11 +136,11 @@ WebDataService::Handle WebDataService::GetKeywords(
}
void WebDataService::SetDefaultSearchProvider(const TemplateURL* url) {
- GenericRequest<TemplateURL::IDType>* request =
- new GenericRequest<TemplateURL::IDType>(this,
- GetNextRequestHandle(),
- NULL,
- url ? url->id() : 0);
+ GenericRequest<TemplateURLID>* request =
+ new GenericRequest<TemplateURLID>(this,
+ GetNextRequestHandle(),
+ NULL,
+ url ? url->id() : 0);
RegisterRequest(request);
ScheduleTask(
NewRunnableMethod(this, &WebDataService::SetDefaultSearchProviderImpl,
@@ -190,6 +204,46 @@ WebDataService::Handle WebDataService::GetWebAppImages(
////////////////////////////////////////////////////////////////////////////////
//
+// Token Service
+//
+////////////////////////////////////////////////////////////////////////////////
+
+void WebDataService::SetTokenForService(const std::string& service,
+ const std::string& token) {
+ GenericRequest2<std::string, std::string>* request =
+ new GenericRequest2<std::string, std::string>(
+ this, GetNextRequestHandle(), NULL, service, token);
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this, &WebDataService::SetTokenForServiceImpl,
+ request));
+}
+
+void WebDataService::RemoveAllTokens() {
+ GenericRequest<std::string>* request =
+ new GenericRequest<std::string>(
+ this, GetNextRequestHandle(), NULL, std::string());
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this,
+ &WebDataService::RemoveAllTokensImpl,
+ request));
+}
+
+// Null on failure. Success is WDResult<std::string>
+WebDataService::Handle WebDataService::GetAllTokens(
+ WebDataServiceConsumer* consumer) {
+
+ GenericRequest<std::string>* request =
+ new GenericRequest<std::string>(
+ this, GetNextRequestHandle(), consumer, std::string());
+ RegisterRequest(request);
+ ScheduleTask(NewRunnableMethod(this,
+ &WebDataService::GetAllTokensImpl,
+ request));
+ return request->GetHandle();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
// Password manager.
//
////////////////////////////////////////////////////////////////////////////////
@@ -495,13 +549,13 @@ void WebDataService::InitializeDatabaseIfNecessary() {
return;
// In the rare case where the db fails to initialize a dialog may get shown
- // the blocks the caller, yet allows other messages through. For this reason
+ // that blocks the caller, yet allows other messages through. For this reason
// we only set db_ to the created database if creation is successful. That
// way other methods won't do anything as db_ is still NULL.
WebDatabase* db = new WebDatabase();
sql::InitStatus init_status = db->Init(path_);
if (init_status != sql::INIT_OK) {
- NOTREACHED() << "Cannot initialize the web database";
+ LOG(ERROR) << "Cannot initialize the web database: " << init_status;
failed_init_ = true;
delete db;
if (main_loop_) {
@@ -582,7 +636,7 @@ void WebDataService::AddKeywordImpl(GenericRequest<TemplateURL>* request) {
}
void WebDataService::RemoveKeywordImpl(
- GenericRequest<TemplateURL::IDType>* request) {
+ GenericRequest<TemplateURLID>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
DCHECK(request->GetArgument());
@@ -616,7 +670,7 @@ void WebDataService::GetKeywordsImpl(WebDataRequest* request) {
}
void WebDataService::SetDefaultSearchProviderImpl(
- GenericRequest<TemplateURL::IDType>* request) {
+ GenericRequest<TemplateURLID>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
if (!db_->SetDefaultSearchProviderID(request->GetArgument()))
@@ -687,6 +741,49 @@ void WebDataService::GetWebAppImagesImpl(GenericRequest<GURL>* request) {
////////////////////////////////////////////////////////////////////////////////
//
+// Token Service implementation.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// argument std::string is unused
+void WebDataService::RemoveAllTokensImpl(
+ GenericRequest<std::string>* request) {
+ InitializeDatabaseIfNecessary();
+ if (db_ && !request->IsCancelled()) {
+ if (db_->RemoveAllTokens()) {
+ ScheduleCommit();
+ }
+ }
+ request->RequestComplete();
+}
+
+void WebDataService::SetTokenForServiceImpl(
+ GenericRequest2<std::string, std::string>* request) {
+ InitializeDatabaseIfNecessary();
+ if (db_ && !request->IsCancelled()) {
+ if (db_->SetTokenForService(request->GetArgument1(),
+ request->GetArgument2())) {
+ ScheduleCommit();
+ }
+ }
+ request->RequestComplete();
+}
+
+// argument is unused
+void WebDataService::GetAllTokensImpl(
+ GenericRequest<std::string>* request) {
+ InitializeDatabaseIfNecessary();
+ if (db_ && !request->IsCancelled()) {
+ std::map<std::string, std::string> map;
+ db_->GetAllTokens(&map);
+ request->SetResult(
+ new WDResult<std::map<std::string, std::string> >(TOKEN_RESULT, map));
+ }
+ request->RequestComplete();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
// Password manager implementation.
//
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/webdata/web_data_service.h b/chrome/browser/webdata/web_data_service.h
index abf254c..c140951 100644
--- a/chrome/browser/webdata/web_data_service.h
+++ b/chrome/browser/webdata/web_data_service.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WEBDATA_WEB_DATA_SERVICE_H__
#define CHROME_BROWSER_WEBDATA_WEB_DATA_SERVICE_H__
+#pragma once
#include <map>
#include <vector>
@@ -13,22 +14,29 @@
#include "base/lock.h"
#include "base/ref_counted.h"
#include "chrome/browser/chrome_thread.h"
+<<<<<<< HEAD
#include "chrome/browser/search_engines/template_url.h"
#include "third_party/skia/include/core/SkBitmap.h"
#ifdef ANDROID
#include <WebCoreSupport/autofill/FormFieldAndroid.h>
#else
+=======
+#include "chrome/browser/search_engines/template_url_id.h"
+>>>>>>> Chromium at release 7.0.540.0
#include "webkit/glue/form_field.h"
#endif
class AutofillChange;
class AutoFillProfile;
class CreditCard;
+class GURL;
#if defined(OS_WIN)
struct IE7PasswordInfo;
#endif
class MessageLoop;
+class SkBitmap;
class Task;
+class TemplateURL;
class WebDatabase;
namespace base {
@@ -67,6 +75,7 @@ typedef enum {
PASSWORD_IE7_RESULT, // WDResult<IE7PasswordInfo>
#endif
WEB_APP_IMAGES, // WDResult<WDAppImagesResult>
+ TOKEN_RESULT, // WDResult<std::vector<std::string>>
AUTOFILL_VALUE_RESULT, // WDResult<std::vector<string16>>
AUTOFILL_CHANGES, // WDResult<std::vector<AutofillChange>>
AUTOFILL_PROFILE_RESULT, // WDResult<AutoFillProfile>
@@ -79,7 +88,8 @@ typedef std::vector<AutofillChange> AutofillChangeList;
// Result from GetWebAppImages.
struct WDAppImagesResult {
- WDAppImagesResult() : has_all_images(false) {}
+ WDAppImagesResult();
+ ~WDAppImagesResult();
// True if SetWebAppHasAllImages(true) was invoked.
bool has_all_images;
@@ -334,6 +344,22 @@ class WebDataService
//////////////////////////////////////////////////////////////////////////////
//
+ // Token Service
+ //
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Set a token to use for a specified service.
+ void SetTokenForService(const std::string& service,
+ const std::string& token);
+
+ // Remove all tokens stored in the web database.
+ void RemoveAllTokens();
+
+ // Null on failure. Success is WDResult<std::vector<std::string> >
+ Handle GetAllTokens(WebDataServiceConsumer* consumer);
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
// Password manager
// NOTE: These methods are all deprecated; new clients should use
// PasswordStore. These are only still here because Windows is (temporarily)
@@ -514,10 +540,10 @@ class WebDataService
//
//////////////////////////////////////////////////////////////////////////////
void AddKeywordImpl(GenericRequest<TemplateURL>* request);
- void RemoveKeywordImpl(GenericRequest<TemplateURL::IDType>* request);
+ void RemoveKeywordImpl(GenericRequest<TemplateURLID>* request);
void UpdateKeywordImpl(GenericRequest<TemplateURL>* request);
void GetKeywordsImpl(WebDataRequest* request);
- void SetDefaultSearchProviderImpl(GenericRequest<TemplateURL::IDType>* r);
+ void SetDefaultSearchProviderImpl(GenericRequest<TemplateURLID>* r);
void SetBuiltinKeywordVersionImpl(GenericRequest<int>* r);
//////////////////////////////////////////////////////////////////////////////
@@ -532,6 +558,17 @@ class WebDataService
//////////////////////////////////////////////////////////////////////////////
//
+ // Token Service.
+ //
+ //////////////////////////////////////////////////////////////////////////////
+
+ void RemoveAllTokensImpl(GenericRequest<std::string>* request);
+ void SetTokenForServiceImpl(
+ GenericRequest2<std::string, std::string>* request);
+ void GetAllTokensImpl(GenericRequest<std::string>* request);
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
// Password manager.
//
//////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/webdata/web_data_service_test_util.h b/chrome/browser/webdata/web_data_service_test_util.h
index dba6fc3..2ff1e09 100644
--- a/chrome/browser/webdata/web_data_service_test_util.h
+++ b/chrome/browser/webdata/web_data_service_test_util.h
@@ -4,8 +4,7 @@
#ifndef CHROME_BROWSER_WEBDATA_WEB_DATA_SERVICE_TEST_UTIL_H__
#define CHROME_BROWSER_WEBDATA_WEB_DATA_SERVICE_TEST_UTIL_H__
-
-#include <vector>
+#pragma once
#include "base/basictypes.h"
#include "base/message_loop.h"
diff --git a/chrome/browser/webdata/web_data_service_unittest.cc b/chrome/browser/webdata/web_data_service_unittest.cc
index 224a76a..263578a 100644
--- a/chrome/browser/webdata/web_data_service_unittest.cc
+++ b/chrome/browser/webdata/web_data_service_unittest.cc
@@ -14,6 +14,7 @@
#include "base/string16.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/waitable_event.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index 55da6ff..dccf6d7 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -12,6 +12,9 @@
#include "app/l10n_util.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
#include "base/tuple.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_profile.h"
@@ -19,9 +22,13 @@
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.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/notification_service.h"
#include "gfx/codec/png_codec.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"
// Encryptor is now in place for Windows and Mac. The Linux implementation
@@ -30,7 +37,6 @@
// details.
// For details on the Linux work see:
// http://crbug.com/25404
-#include "chrome/browser/password_manager/encryptor.h"
using webkit_glue::FormField;
using webkit_glue::PasswordForm;
@@ -38,6 +44,7 @@ using webkit_glue::PasswordForm;
////////////////////////////////////////////////////////////////////////////////
//
// Schema
+// Note: The database stores time in seconds, UTC.
//
// keywords Most of the columns mirror that of a field in
// TemplateURL. See TemplateURL for more details.
@@ -56,8 +63,11 @@ using webkit_glue::PasswordForm;
// input_encodings Semicolon separated list of supported input
// encodings, may be empty.
// suggest_url
-// prepopulate_id See TemplateURL::prepoulate_id.
+// prepopulate_id See TemplateURL::prepopulate_id.
// autogenerate_keyword
+// logo_id See TemplateURL::logo_id
+// created_by_policy See TemplateURL::created_by_policy. This was added
+// in version 26.
//
// logins
// origin_url
@@ -156,9 +166,12 @@ namespace {
typedef std::vector<Tuple3<int64, string16, string16> > AutofillElementList;
-// Current version number.
-const int kCurrentVersionNumber = 24;
-const int kCompatibleVersionNumber = 21;
+// Current version number. Note: when changing the current version number,
+// corresponding changes must happen in the unit tests, and new migration test
+// added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
+const int kCurrentVersionNumber = 27;
+const int kCompatibleVersionNumber = 27;
+const int kUrlIdPosition = 15;
// Keys used in the meta table.
const char* kDefaultSearchProviderKey = "Default Search Provider ID";
@@ -167,17 +180,6 @@ const char* kBuiltinKeywordVersion = "Builtin Keyword Version";
// The maximum length allowed for form data.
const size_t kMaxDataLength = 1024;
-std::string JoinStrings(const std::string& separator,
- const std::vector<std::string>& strings) {
- if (strings.empty())
- return std::string();
- std::vector<std::string>::const_iterator i(strings.begin());
- std::string result(*i);
- while (++i != strings.end())
- result += separator + *i;
- return result;
-}
-
void BindURLToStatement(const TemplateURL& url, sql::Statement* s) {
s->BindString(0, WideToUTF8(url.short_name()));
s->BindString(1, WideToUTF8(url.keyword()));
@@ -201,7 +203,7 @@ void BindURLToStatement(const TemplateURL& url, sql::Statement* s) {
}
s->BindInt64(6, url.date_created().ToTimeT());
s->BindInt(7, url.usage_count());
- s->BindString(8, JoinStrings(";", url.input_encodings()));
+ s->BindString(8, JoinString(url.input_encodings(), ';'));
s->BindInt(9, url.show_in_default_list() ? 1 : 0);
if (url.suggestions_url())
s->BindString(10, url.suggestions_url()->url());
@@ -209,6 +211,8 @@ void BindURLToStatement(const TemplateURL& url, sql::Statement* s) {
s->BindString(10, std::string());
s->BindInt(11, url.prepopulate_id());
s->BindInt(12, url.autogenerate_keyword() ? 1 : 0);
+ s->BindInt(13, url.logo_id());
+ s->BindBool(14, url.created_by_policy());
}
void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) {
@@ -249,7 +253,7 @@ void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) {
// See http://crbug.com/49332.
string16 LimitDataSize(const string16& data) {
if (data.size() > kMaxDataLength)
- return data.substr(kMaxDataLength);
+ return data.substr(0, kMaxDataLength);
return data;
}
@@ -337,7 +341,7 @@ void BindCreditCardToStatement(const CreditCard& credit_card,
s->BindString16(6, LimitDataSize(text));
text.clear();
s->BindString16(7, LimitDataSize(text));
- s->BindString16(8, credit_card.billing_address());
+ s->BindInt(8, credit_card.billing_address_id());
// We don't store the shipping address anymore.
text.clear();
s->BindString16(9, LimitDataSize(text));
@@ -378,7 +382,7 @@ CreditCard* CreditCardFromStatement(const sql::Statement& s) {
string16 credit_card_verification_code = s.ColumnString16(7);
// We don't store the CVV anymore.
- credit_card->set_billing_address(s.ColumnString16(8));
+ credit_card->set_billing_address_id(s.ColumnInt(8));
// We don't store the shipping address anymore.
// Column 10 is processed above.
// Column 11 is processed above.
@@ -444,7 +448,7 @@ sql::InitStatus WebDatabase::Init(const FilePath& db_name) {
if (!InitKeywordsTable() || !InitLoginsTable() || !InitWebAppIconsTable() ||
!InitWebAppsTable() || !InitAutofillTable() ||
!InitAutofillDatesTable() || !InitAutoFillProfilesTable() ||
- !InitCreditCardsTable()) {
+ !InitCreditCardsTable() || !InitTokenServiceTable()) {
LOG(WARNING) << "Unable to initialize the web database.";
return sql::INIT_FAILURE;
}
@@ -545,6 +549,68 @@ bool WebDatabase::RemoveWebApp(const GURL& url) {
return delete_s2.Run();
}
+bool WebDatabase::RemoveAllTokens() {
+ sql::Statement s(db_.GetUniqueStatement(
+ "DELETE FROM token_service"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ return s.Run();
+}
+
+bool WebDatabase::SetTokenForService(const std::string& service,
+ const std::string& token) {
+ // Don't bother with a cached statement since this will be a relatively
+ // infrequent operation.
+ sql::Statement s(db_.GetUniqueStatement(
+ "INSERT OR REPLACE INTO token_service "
+ "(service, encrypted_token) VALUES (?, ?)"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ std::string encrypted_token;
+
+ bool encrypted = Encryptor::EncryptString(token, &encrypted_token);
+ if (!encrypted) {
+ return false;
+ }
+
+ s.BindString(0, service);
+ s.BindBlob(1, encrypted_token.data(),
+ static_cast<int>(encrypted_token.length()));
+ return s.Run();
+}
+
+bool WebDatabase::GetAllTokens(std::map<std::string, std::string>* tokens) {
+ sql::Statement s(db_.GetUniqueStatement(
+ "SELECT service, encrypted_token FROM token_service"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ while (s.Step()) {
+ std::string encrypted_token;
+ std::string decrypted_token;
+ std::string service;
+ service = s.ColumnString(0);
+ bool entry_ok = !service.empty() &&
+ s.ColumnBlobAsString(1, &encrypted_token);
+ if (entry_ok) {
+ Encryptor::DecryptString(encrypted_token, &decrypted_token);
+ (*tokens)[service] = decrypted_token;
+ } else {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
bool WebDatabase::InitKeywordsTable() {
if (!db_.DoesTableExist("keywords")) {
if (!db_.Execute("CREATE TABLE keywords ("
@@ -561,7 +627,9 @@ bool WebDatabase::InitKeywordsTable() {
"input_encodings VARCHAR,"
"suggest_url VARCHAR,"
"prepopulate_id INTEGER DEFAULT 0,"
- "autogenerate_keyword INTEGER DEFAULT 0)")) {
+ "autogenerate_keyword INTEGER DEFAULT 0,"
+ "logo_id INTEGER DEFAULT 0,"
+ "created_by_policy INTEGER DEFAULT 0)")) {
NOTREACHED();
return false;
}
@@ -748,21 +816,34 @@ bool WebDatabase::InitWebAppsTable() {
return true;
}
+bool WebDatabase::InitTokenServiceTable() {
+ if (!db_.DoesTableExist("token_service")) {
+ if (!db_.Execute("CREATE TABLE token_service ("
+ "service VARCHAR PRIMARY KEY NOT NULL,"
+ "encrypted_token BLOB)")) {
+ NOTREACHED();
+ return false;
+ }
+ }
+ return true;
+}
+
bool WebDatabase::AddKeyword(const TemplateURL& url) {
DCHECK(url.id());
+ // Be sure to change kUrlIdPosition if you add columns
sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
"INSERT INTO keywords "
"(short_name, keyword, favicon_url, url, safe_for_autoreplace, "
"originating_url, date_created, usage_count, input_encodings, "
"show_in_default_list, suggest_url, prepopulate_id, "
- "autogenerate_keyword, id) VALUES "
- "(?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ "autogenerate_keyword, logo_id, created_by_policy, id) VALUES "
+ "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
if (!s) {
NOTREACHED() << "Statement prepare failed";
return false;
}
BindURLToStatement(url, &s);
- s.BindInt64(13, url.id());
+ s.BindInt64(kUrlIdPosition, url.id());
if (!s.Run()) {
NOTREACHED();
return false;
@@ -770,7 +851,7 @@ bool WebDatabase::AddKeyword(const TemplateURL& url) {
return true;
}
-bool WebDatabase::RemoveKeyword(TemplateURL::IDType id) {
+bool WebDatabase::RemoveKeyword(TemplateURLID id) {
DCHECK(id);
sql::Statement s(db_.GetUniqueStatement("DELETE FROM keywords WHERE id = ?"));
if (!s) {
@@ -786,7 +867,8 @@ bool WebDatabase::GetKeywords(std::vector<TemplateURL*>* urls) {
"SELECT id, short_name, keyword, favicon_url, url, "
"safe_for_autoreplace, originating_url, date_created, "
"usage_count, input_encodings, show_in_default_list, "
- "suggest_url, prepopulate_id, autogenerate_keyword "
+ "suggest_url, prepopulate_id, autogenerate_keyword, logo_id, "
+ "created_by_policy "
"FROM keywords ORDER BY id ASC"));
if (!s) {
NOTREACHED() << "Statement prepare failed";
@@ -834,6 +916,10 @@ bool WebDatabase::GetKeywords(std::vector<TemplateURL*>* urls) {
template_url->set_autogenerate_keyword(s.ColumnInt(13) == 1);
+ template_url->set_logo_id(s.ColumnInt(14));
+
+ template_url->set_created_by_policy(s.ColumnBool(15));
+
urls->push_back(template_url);
}
return s.Succeeded();
@@ -841,19 +927,20 @@ bool WebDatabase::GetKeywords(std::vector<TemplateURL*>* urls) {
bool WebDatabase::UpdateKeyword(const TemplateURL& url) {
DCHECK(url.id());
+ // Be sure to change kUrlIdPosition if you add columns
sql::Statement s(db_.GetUniqueStatement(
"UPDATE keywords "
"SET short_name=?, keyword=?, favicon_url=?, url=?, "
"safe_for_autoreplace=?, originating_url=?, date_created=?, "
"usage_count=?, input_encodings=?, show_in_default_list=?, "
- "suggest_url=?, prepopulate_id=?, autogenerate_keyword=? "
- "WHERE id=?"));
+ "suggest_url=?, prepopulate_id=?, autogenerate_keyword=?, "
+ "logo_id=?, created_by_policy=? WHERE id=?"));
if (!s) {
NOTREACHED() << "Statement prepare failed";
return false;
}
BindURLToStatement(url, &s);
- s.BindInt64(13, url.id());
+ s.BindInt64(kUrlIdPosition, url.id());
return s.Run();
}
@@ -1075,12 +1162,21 @@ bool WebDatabase::AddFormFieldValues(const std::vector<FormField>& elements,
bool WebDatabase::AddFormFieldValuesTime(const std::vector<FormField>& elements,
std::vector<AutofillChange>* changes,
base::Time time) {
+ // Only add one new entry for each unique element name. Use |seen_names| to
+ // track this. Add up to |kMaximumUniqueNames| unique entries per form.
+ const size_t kMaximumUniqueNames = 256;
+ std::set<string16> seen_names;
bool result = true;
for (std::vector<FormField>::const_iterator
itr = elements.begin();
itr != elements.end();
itr++) {
+ if (seen_names.size() >= kMaximumUniqueNames)
+ break;
+ if (seen_names.find(itr->name()) != seen_names.end())
+ continue;
result = result && AddFormFieldValueTime(*itr, changes, time);
+ seen_names.insert(itr->name());
}
return result;
}
@@ -1779,7 +1875,7 @@ bool WebDatabase::RemoveFormElementForID(int64 pair_id) {
return false;
}
-void WebDatabase::MigrateOldVersionsAsNeeded() {
+void WebDatabase::MigrateOldVersionsAsNeeded(){
// Migrate if necessary.
int current_version = meta_table_.GetVersionNumber();
switch (current_version) {
@@ -1816,21 +1912,54 @@ void WebDatabase::MigrateOldVersionsAsNeeded() {
// FALL THROUGH
case 22:
- // Add the card_number_encrypted column.
+ // Add the card_number_encrypted column if credit card table was not
+ // created in this build (otherwise the column already exists).
+ // WARNING: Do not change the order of the execution of the SQL
+ // statements in this case! Profile corruption and data migration
+ // issues WILL OCCUR. (see http://crbug.com/10913)
+ //
+ // The problem is that if a user has a profile which was created before
+ // r37036, when the credit_cards table was added, and then failed to
+ // update this profile between the credit card addition and the addition
+ // of the "encrypted" columns (44963), the next data migration will put
+ // the user's profile in an incoherent state: The user will update from
+ // a data profile set to be earlier than 22, and therefore pass through
+ // this update case. But because the user did not have a credit_cards
+ // table before starting Chrome, it will have just been initialized
+ // above, and so already have these columns -- and thus this data
+ // update step will have failed.
+ //
+ // The false assumption in this case is that at this step in the
+ // migration, the user has a credit card table, and that this
+ // table does not include encrypted columns!
+ // Because this case does not roll back the complete set of SQL
+ // transactions properly in case of failure (that is, it does not
+ // roll back the table initialization done above), the incoherent
+ // profile will now see itself as being at version 22 -- but include a
+ // fully initialized credit_cards table. Every time Chrome runs, it
+ // will try to update the web database and fail at this step, unless
+ // we allow for the faulty assumption described above by checking for
+ // the existence of the columns only AFTER we've executed the commands
+ // to add them.
if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN "
"card_number_encrypted BLOB DEFAULT NULL")) {
- NOTREACHED();
- LOG(WARNING) << "Unable to update web database to version 23.";
- return;
+ LOG(WARNING) << "Could not add card_number_encrypted to "
+ "credit_cards table.";
}
if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN "
"verification_code_encrypted BLOB DEFAULT NULL")) {
- NOTREACHED();
- LOG(WARNING) << "Unable to update web database to version 23.";
- return;
+ LOG(WARNING) << "Could not add verification_code_encrypted to "
+ "credit_cards table.";
+ }
+ if (!db_.Execute(
+ "SELECT card_number_encrypted FROM credit_cards limit 1") ||
+ !db_.Execute(
+ "SELECT verification_code_encrypted FROM credit_cards limit 1")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 23.";
+ return;
}
meta_table_.SetVersionNumber(23);
-
// FALL THROUGH
case 23: {
@@ -1891,6 +2020,144 @@ void WebDatabase::MigrateOldVersionsAsNeeded() {
// FALL THROUGH
}
+ case 24:
+ // Add the logo_id column if keyword table was not created in this build.
+ if (!db_.Execute("ALTER TABLE keywords ADD COLUMN logo_id "
+ "INTEGER DEFAULT 0")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 25.";
+ return;
+ }
+ meta_table_.SetVersionNumber(25);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(25, kCompatibleVersionNumber));
+ // FALL THROUGH
+
+ case 25:
+ // Add the created_by_policy column.
+ if (!db_.Execute("ALTER TABLE keywords ADD COLUMN created_by_policy "
+ "INTEGER DEFAULT 0")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 26.";
+ return;
+ }
+
+ meta_table_.SetVersionNumber(26);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(26, kCompatibleVersionNumber));
+ // FALL THROUGH
+
+ case 26: {
+ // Change the credit_cards.billing_address column from a string to an int.
+ // The stored string is the label of an address, so we have to select the
+ // unique ID of this address using the label as a foreign key into the
+ // |autofill_profiles| table.
+ std::string stmt =
+ "SELECT credit_cards.unique_id, autofill_profiles.unique_id "
+ "FROM autofill_profiles, credit_cards "
+ "WHERE credit_cards.billing_address = autofill_profiles.label";
+ sql::Statement s(db_.GetUniqueStatement(stmt.c_str()));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return;
+ }
+
+ std::map<int, int> cc_billing_map;
+ while (s.Step())
+ cc_billing_map[s.ColumnInt(0)] = s.ColumnInt(1);
+
+ // Windows already stores the IDs as strings in |billing_address|. Try to
+ // convert those.
+ if (cc_billing_map.empty()) {
+ std::string stmt =
+ "SELECT unique_id,billing_address FROM credit_cards";
+ sql::Statement s(db_.GetUniqueStatement(stmt.c_str()));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return;
+ }
+
+ while (s.Step()) {
+ int id = 0;
+ if (base::StringToInt(s.ColumnString(1), &id))
+ cc_billing_map[s.ColumnInt(0)] = id;
+ }
+ }
+
+ if (!db_.Execute("CREATE TABLE credit_cards_temp ( "
+ "label VARCHAR, "
+ "unique_id INTEGER PRIMARY KEY, "
+ "name_on_card VARCHAR, "
+ "type VARCHAR, "
+ "card_number VARCHAR, "
+ "expiration_month INTEGER, "
+ "expiration_year INTEGER, "
+ "verification_code VARCHAR, "
+ "billing_address INTEGER, "
+ "shipping_address VARCHAR, "
+ "card_number_encrypted BLOB, "
+ "verification_code_encrypted BLOB)")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
+ if (!db_.Execute(
+ "INSERT INTO credit_cards_temp "
+ "SELECT label,unique_id,name_on_card,type,card_number,"
+ "expiration_month,expiration_year,verification_code,0,"
+ "shipping_address,card_number_encrypted,verification_code_encrypted "
+ "FROM credit_cards")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
+ if (!db_.Execute("DROP TABLE credit_cards")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
+ if (!db_.Execute(
+ "ALTER TABLE credit_cards_temp RENAME TO credit_cards")) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+
+ meta_table_.SetVersionNumber(26);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(26, kCompatibleVersionNumber));
+ // FALL THROUGH
+
+ for (std::map<int, int>::const_iterator iter = cc_billing_map.begin();
+ iter != cc_billing_map.end(); ++iter) {
+ sql::Statement s(db_.GetCachedStatement(
+ SQL_FROM_HERE,
+ "UPDATE credit_cards SET billing_address=? WHERE unique_id=?"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return;
+ }
+
+ s.BindInt(0, (*iter).second);
+ s.BindInt(1, (*iter).first);
+
+ if (!s.Run()) {
+ NOTREACHED();
+ LOG(WARNING) << "Unable to update web database to version 27.";
+ return;
+ }
+ }
+
+ meta_table_.SetVersionNumber(27);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(27, kCompatibleVersionNumber));
+
+ // FALL THROUGH
+ }
+
// Add successive versions here. Each should set the version number and
// compatible version number as appropriate, then fall through to the next
// case.
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index b379c29..9358533 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WEBDATA_WEB_DATABASE_H_
#define CHROME_BROWSER_WEBDATA_WEB_DATABASE_H_
+#pragma once
#include <vector>
@@ -12,16 +13,18 @@
#include "app/sql/meta_table.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/glue/form_field.h"
+#include "base/string16.h"
+#include "chrome/browser/search_engines/template_url_id.h"
class AutofillChange;
class AutofillEntry;
class AutoFillProfile;
class CreditCard;
class FilePath;
+class GURL;
class NotificationService;
+class SkBitmap;
+class TemplateURL;
class WebDatabaseTest;
namespace base {
@@ -29,6 +32,7 @@ class Time;
}
namespace webkit_glue {
+class FormField;
struct PasswordForm;
}
@@ -66,7 +70,7 @@ class WebDatabase {
// Removes the specified keyword.
// Returns true if successful.
- bool RemoveKeyword(TemplateURL::IDType id);
+ bool RemoveKeyword(TemplateURLID id);
// Loads the keywords into the specified vector. It's up to the caller to
// delete the returned objects.
@@ -125,14 +129,14 @@ class WebDatabase {
// Loads the complete list of password forms into the specified vector |forms|
// if include_blacklisted is true, otherwise only loads those which are
- // actually autofillable; i.e haven't been blacklisted by the user selecting
+ // actually autofill-able; i.e haven't been blacklisted by the user selecting
// the 'Never for this site' button.
bool GetAllLogins(std::vector<webkit_glue::PasswordForm*>* forms,
bool include_blacklisted);
//////////////////////////////////////////////////////////////////////////////
//
- // Autofill
+ // AutoFill
//
//////////////////////////////////////////////////////////////////////////////
@@ -272,6 +276,26 @@ class WebDatabase {
bool RemoveWebApp(const GURL& url);
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // Token Service
+ //
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Remove all tokens previously set with SetTokenForService.
+ bool RemoveAllTokens();
+
+ // Retrieves all tokens previously set with SetTokenForService.
+ // Returns true if there were tokens and we decrypted them,
+ // false if there was a failure somehow
+ bool GetAllTokens(std::map<std::string, std::string>* tokens);
+
+ // Store a token in the token_service table. Stored encrypted. May cause
+ // a mac keychain popup.
+ // True if we encrypted a token and stored it, false otherwise.
+ bool SetTokenForService(const std::string& service,
+ const std::string& token);
+
private:
FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill);
FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill_AddChanges);
@@ -283,6 +307,8 @@ class WebDatabase {
FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest,
Autofill_GetAllAutofillEntries_TwoSame);
FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill_UpdateDontReplace);
+ FRIEND_TEST_ALL_PREFIXES(WebDatabaseTest, Autofill_AddFormFieldValues);
+
// Methods for adding autofill entries at a specified time. For
// testing only.
bool AddFormFieldValuesTime(
@@ -308,6 +334,7 @@ class WebDatabase {
bool InitAutofillDatesTable();
bool InitAutoFillProfilesTable();
bool InitCreditCardsTable();
+ bool InitTokenServiceTable();
bool InitWebAppIconsTable();
bool InitWebAppsTable();
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index ce13dbf..4bfa827 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -9,12 +9,15 @@
#include <utility>
#include <vector>
+#include "app/sql/statement.h"
#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/string16.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/autofill_type.h"
@@ -88,6 +91,10 @@ bool CompareAutofillEntries(const AutofillEntry& a, const AutofillEntry& b) {
}
class WebDatabaseTest : public testing::Test {
+ public:
+ WebDatabaseTest() {}
+ virtual ~WebDatabaseTest() {}
+
protected:
typedef std::vector<AutofillChange> AutofillChangeList;
typedef std::set<AutofillEntry,
@@ -100,7 +107,7 @@ class WebDatabaseTest : public testing::Test {
#endif
PathService::Get(chrome::DIR_TEST_DATA, &file_);
const std::string test_db = "TestWebDatabase" +
- Int64ToString(base::Time::Now().ToInternalValue()) +
+ base::Int64ToString(base::Time::Now().ToInternalValue()) +
".db";
file_ = file_.AppendASCII(test_db);
file_util::Delete(file_, false);
@@ -128,7 +135,7 @@ class WebDatabaseTest : public testing::Test {
int b_count = GetKeyCount(b);
DictionaryValue::key_iterator i(a.begin_keys());
DictionaryValue::key_iterator e(a.end_keys());
- std::wstring av, bv;
+ std::string av, bv;
while (i != e) {
if (!(a.GetStringWithoutPathExpansion(*i, &av)) ||
!(b.GetStringWithoutPathExpansion(*i, &bv)) ||
@@ -154,6 +161,10 @@ class WebDatabaseTest : public testing::Test {
url->set_prepopulate_id(id);
}
+ static void set_logo_id(TemplateURL* url, int id) {
+ url->set_logo_id(id);
+ }
+
static AutofillEntry MakeAutofillEntry(const char* name,
const char* value,
time_t timestamp0,
@@ -168,6 +179,9 @@ class WebDatabaseTest : public testing::Test {
}
FilePath file_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebDatabaseTest);
};
TEST_F(WebDatabaseTest, Keywords) {
@@ -183,11 +197,16 @@ TEST_F(WebDatabaseTest, Keywords) {
template_url.SetFavIconURL(favicon_url);
template_url.SetURL("http://url/", 0, 0);
template_url.set_safe_for_autoreplace(true);
+ base::Time created_time = Time::Now();
+ template_url.set_date_created(created_time);
template_url.set_show_in_default_list(true);
template_url.set_originating_url(originating_url);
template_url.set_usage_count(32);
template_url.add_input_encoding("UTF-8");
+ template_url.add_input_encoding("UTF-16");
set_prepopulate_id(&template_url, 10);
+ set_logo_id(&template_url, 1000);
+ template_url.set_created_by_policy(true);
SetID(1, &template_url);
EXPECT_TRUE(db.AddKeyword(template_url));
@@ -208,6 +227,9 @@ TEST_F(WebDatabaseTest, Keywords) {
EXPECT_TRUE(restored_url->safe_for_autoreplace());
+ // The database stores time only at the resolution of a second.
+ EXPECT_EQ(created_time.ToTimeT(), restored_url->date_created().ToTimeT());
+
EXPECT_TRUE(restored_url->show_in_default_list());
EXPECT_EQ(GetID(&template_url), GetID(restored_url));
@@ -216,11 +238,16 @@ TEST_F(WebDatabaseTest, Keywords) {
EXPECT_EQ(32, restored_url->usage_count());
- ASSERT_EQ(1U, restored_url->input_encodings().size());
+ ASSERT_EQ(2U, restored_url->input_encodings().size());
EXPECT_EQ("UTF-8", restored_url->input_encodings()[0]);
+ EXPECT_EQ("UTF-16", restored_url->input_encodings()[1]);
EXPECT_EQ(10, restored_url->prepopulate_id());
+ EXPECT_EQ(1000, restored_url->logo_id());
+
+ EXPECT_TRUE(restored_url->created_by_policy());
+
EXPECT_TRUE(db.RemoveKeyword(restored_url->id()));
template_urls.clear();
@@ -271,6 +298,7 @@ TEST_F(WebDatabaseTest, UpdateKeyword) {
EXPECT_EQ(L"url", template_url.keyword());
template_url.add_input_encoding("Shift_JIS");
set_prepopulate_id(&template_url, 5);
+ set_logo_id(&template_url, 2000);
EXPECT_TRUE(db.UpdateKeyword(template_url));
std::vector<TemplateURL*> template_urls;
@@ -305,6 +333,8 @@ TEST_F(WebDatabaseTest, UpdateKeyword) {
EXPECT_EQ(template_url.prepopulate_id(), restored_url->prepopulate_id());
+ EXPECT_EQ(template_url.logo_id(), restored_url->logo_id());
+
delete restored_url;
}
@@ -905,6 +935,53 @@ TEST_F(WebDatabaseTest, Autofill_UpdateDontReplace) {
EXPECT_EQ(1U, expected_entries.count(entry));
}
+TEST_F(WebDatabaseTest, Autofill_AddFormFieldValues) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ Time t = Time::Now();
+
+ // Add multiple values for "firstname" and "lastname" names. Test that only
+ // first value of each gets added. Related to security issue:
+ // http://crbug.com/51727.
+ std::vector<FormField> elements;
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("firstname"),
+ ASCIIToUTF16("Joe"),
+ string16(),
+ 0));
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("firstname"),
+ ASCIIToUTF16("Jane"),
+ string16(),
+ 0));
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("lastname"),
+ ASCIIToUTF16("Smith"),
+ string16(),
+ 0));
+ elements.push_back(FormField(string16(),
+ ASCIIToUTF16("lastname"),
+ ASCIIToUTF16("Jones"),
+ string16(),
+ 0));
+
+ std::vector<AutofillChange> changes;
+ db.AddFormFieldValuesTime(elements, &changes, t);
+
+ ASSERT_EQ(2U, changes.size());
+ EXPECT_EQ(changes[0], AutofillChange(AutofillChange::ADD,
+ AutofillKey(ASCIIToUTF16("firstname"),
+ ASCIIToUTF16("Joe"))));
+ EXPECT_EQ(changes[1], AutofillChange(AutofillChange::ADD,
+ AutofillKey(ASCIIToUTF16("lastname"),
+ ASCIIToUTF16("Smith"))));
+
+ std::vector<AutofillEntry> all_entries;
+ ASSERT_TRUE(db.GetAllAutofillEntries(&all_entries));
+ ASSERT_EQ(2U, all_entries.size());
+}
+
static bool AddTimestampedLogin(WebDatabase* db, std::string url,
const std::string& unique_string,
const Time& time) {
@@ -1100,6 +1177,66 @@ TEST_F(WebDatabaseTest, WebAppImages) {
}
}
+TEST_F(WebDatabaseTest, TokenServiceGetAllRemoveAll) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::map<std::string, std::string> out_map;
+ std::string service;
+ std::string service2;
+ service = "testservice";
+ service2 = "othertestservice";
+
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_TRUE(out_map.empty());
+
+ // Check that get all tokens works
+ EXPECT_TRUE(db.SetTokenForService(service, "pepperoni"));
+ EXPECT_TRUE(db.SetTokenForService(service2, "steak"));
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "pepperoni");
+ EXPECT_EQ(out_map.find(service2)->second, "steak");
+ out_map.clear();
+
+ // Purge
+ EXPECT_TRUE(db.RemoveAllTokens());
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_TRUE(out_map.empty());
+
+ // Check that you can still add it back in
+ EXPECT_TRUE(db.SetTokenForService(service, "cheese"));
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "cheese");
+}
+
+TEST_F(WebDatabaseTest, TokenServiceGetSet) {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(file_));
+
+ std::map<std::string, std::string> out_map;
+ std::string service;
+ service = "testservice";
+
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_TRUE(out_map.empty());
+
+ EXPECT_TRUE(db.SetTokenForService(service, "pepperoni"));
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "pepperoni");
+ out_map.clear();
+
+ // try blanking it - won't remove it from the db though!
+ EXPECT_TRUE(db.SetTokenForService(service, ""));
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "");
+ out_map.clear();
+
+ // try mutating it
+ EXPECT_TRUE(db.SetTokenForService(service, "ham"));
+ EXPECT_TRUE(db.GetAllTokens(&out_map));
+ EXPECT_EQ(out_map.find(service)->second, "ham");
+}
+
TEST_F(WebDatabaseTest, AutoFillProfile) {
WebDatabase db;
@@ -1181,7 +1318,7 @@ TEST_F(WebDatabaseTest, CreditCard) {
ASCIIToUTF16("04"));
work_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2013"));
- work_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel"));
+ work_creditcard.set_billing_address_id(1);
EXPECT_TRUE(db.AddCreditCard(work_creditcard));
@@ -1203,7 +1340,7 @@ TEST_F(WebDatabaseTest, CreditCard) {
ASCIIToUTF16("06"));
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
ASCIIToUTF16("2012"));
- target_creditcard.set_billing_address(ASCIIToUTF16("Overlook Hotel"));
+ target_creditcard.set_billing_address_id(1);
EXPECT_TRUE(db.AddCreditCard(target_creditcard));
ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"),
@@ -1213,7 +1350,7 @@ TEST_F(WebDatabaseTest, CreditCard) {
// Update the 'Target' profile.
target_creditcard.SetInfo(AutoFillType(CREDIT_CARD_NAME),
- ASCIIToUTF16("Charles Grady"));
+ ASCIIToUTF16("Charles Grady"));
EXPECT_TRUE(db.UpdateCreditCard(target_creditcard));
ASSERT_TRUE(db.GetCreditCardForLabel(ASCIIToUTF16("Target"), &db_creditcard));
EXPECT_EQ(target_creditcard, *db_creditcard);
@@ -1389,3 +1526,757 @@ TEST_F(WebDatabaseTest, Autofill_GetAllAutofillEntries_TwoSame) {
EXPECT_EQ(0U, expected_entries.size());
}
+
+// The WebDatabaseMigrationTest encapsulates testing of database migrations.
+// Specifically, these tests are intended to exercise any schema changes in
+// the WebDatabase and data migrations that occur in
+// |WebDatabase::MigrateOldVersionsAsNeeded()|.
+class WebDatabaseMigrationTest : public testing::Test {
+ public:
+ WebDatabaseMigrationTest() {}
+ virtual ~WebDatabaseMigrationTest() {}
+
+ virtual void SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ }
+
+ protected:
+ // Current tested version number. When adding a migration in
+ // |WebDatabase::MigrateOldVersionsAsNeeded()| and changing the version number
+ // |kCurrentVersionNumber| this value should change to reflect the new version
+ // number and a new migration test added below.
+ static const int kCurrentTestedVersionNumber;
+
+ FilePath GetDatabasePath() {
+ const FilePath::CharType kWebDatabaseFilename[] =
+ FILE_PATH_LITERAL("TestWebDatabase.sqlite3");
+ return temp_dir_.path().Append(FilePath(kWebDatabaseFilename));
+ }
+
+ static int VersionFromConnection(sql::Connection* connection) {
+ // Get version.
+ sql::Statement s(connection->GetUniqueStatement(
+ "SELECT value FROM meta WHERE key='version'"));
+ if (!s.Step())
+ return 0;
+ return s.ColumnInt(0);
+ }
+
+ // The tables in these "Setup" routines were generated by launching the
+ // Chromium application prior to schema change, then using the sqlite
+ // command-line application to dump the contents of the "Web Data" database.
+ // Like this:
+ // > .output foo_dump.sql
+ // > .dump
+ void SetUpVersion22Database();
+ void SetUpVersion22CorruptDatabase();
+ void SetUpVersion24Database();
+ void SetUpVersion25Database();
+ void SetUpVersion26Database();
+
+ private:
+ ScopedTempDir temp_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
+};
+
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 27;
+
+// This schema is taken from a build prior to the addition of the |credit_card|
+// table. Version 22 of the schema. Contrast this with the corrupt version
+// below.
+void WebDatabaseMigrationTest::SetUpVersion22Database() {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute(
+ "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+ "value LONGVARCHAR);"
+ "INSERT INTO \"meta\" VALUES('version','22');"
+ "INSERT INTO \"meta\" VALUES('last_compatible_version','21');"
+ "INSERT INTO \"meta\" VALUES('Builtin Keyword Version','27');"
+ "INSERT INTO \"meta\" VALUES('Default Search Provider ID','7');"
+ "CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,"
+ "keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,"
+ "url VARCHAR NOT NULL,show_in_default_list INTEGER,"
+ "safe_for_autoreplace INTEGER,originating_url VARCHAR,"
+ "date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,"
+ "input_encodings VARCHAR,suggest_url VARCHAR,"
+ "prepopulate_id INTEGER DEFAULT 0,"
+ "autogenerate_keyword INTEGER DEFAULT 0);"
+ "INSERT INTO \"keywords\" VALUES(2,'Google','google.com',"
+ "'http://www.google.com/favicon.ico',"
+ "'{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}"
+ "{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}"
+ "&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?"
+ "client=chrome&hl={language}&q={searchTerms}',1,1);"
+ "INSERT INTO \"keywords\" VALUES(3,'Yahoo!','yahoo.com',"
+ "'http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?"
+ "ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8',"
+ "'http://ff.search.yahoo.com/gossip?output=fxjson&"
+ "command={searchTerms}',2,0);"
+ "INSERT INTO \"keywords\" VALUES(4,'Bing','bing.com',"
+ "'http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?"
+ "setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8',"
+ "'http://api.bing.com/osjson.aspx?query={searchTerms}&"
+ "language={language}',3,0);"
+ "INSERT INTO \"keywords\" VALUES(5,'Wikipedia (en)','en.wikipedia.org','',"
+ "'http://en.wikipedia.org/w/index.php?title=Special:Search&"
+ "search={searchTerms}',1,0,'',1283287335,0,'','',0,0);"
+ "INSERT INTO \"keywords\" VALUES(6,'NYTimes','query.nytimes.com','',"
+ "'http://query.nytimes.com/gst/handler.html?query={searchTerms}&"
+ "opensearch=1',1,0,'',1283287335,0,'','',0,0);"
+ "INSERT INTO \"keywords\" VALUES(7,'eBay','rover.ebay.com','',"
+ "'http://rover.ebay.com/rover/1/711-43047-14818-1/4?"
+ "satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0);"
+ "INSERT INTO \"keywords\" VALUES(8,'ff','ff','','http://ff{searchTerms}',"
+ "0,0,'',1283287356,0,'','',0,0);"
+ "CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, "
+ "username_element VARCHAR, username_value VARCHAR, "
+ "password_element VARCHAR, password_value BLOB, submit_element VARCHAR,"
+ "signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,"
+ "preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,"
+ "blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,"
+ "UNIQUE (origin_url, username_element, username_value, "
+ "password_element, submit_element, signon_realm));"
+ "CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, "
+ "date_created INTEGER NOT NULL,UNIQUE (url_hash));"
+ "CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,"
+ "image BLOB, UNIQUE (url, width, height));"
+ "CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,"
+ "has_all_images INTEGER NOT NULL);"
+ "CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, "
+ "pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);"
+ "CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,"
+ "date_created INTEGER DEFAULT 0);"
+ "CREATE INDEX logins_signon ON logins (signon_realm);"
+ "CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);"
+ "CREATE INDEX web_apps_url_index ON web_apps (url);"
+ "CREATE INDEX autofill_name ON autofill (name);"
+ "CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);"
+ "CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);"));
+ ASSERT_TRUE(connection.CommitTransaction());
+}
+
+// This schema is taken from a build after the addition of the |credit_card|
+// table. Due to a bug in the migration logic the version is set incorrectly to
+// 22 (it should have been updated to 23 at least).
+void WebDatabaseMigrationTest::SetUpVersion22CorruptDatabase() {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute(
+ "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+ "value LONGVARCHAR);"
+ "INSERT INTO \"meta\" VALUES('version','22');"
+ "INSERT INTO \"meta\" VALUES('last_compatible_version','21');"
+ "INSERT INTO \"meta\" VALUES('Default Search Provider ID','2');"
+ "INSERT INTO \"meta\" VALUES('Builtin Keyword Version','29');"
+ "CREATE TABLE keywords (id INTEGER PRIMARY KEY,"
+ "short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,"
+ "favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,"
+ "show_in_default_list INTEGER,safe_for_autoreplace INTEGER,"
+ "originating_url VARCHAR,date_created INTEGER DEFAULT 0,"
+ "usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,"
+ "suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,"
+ "autogenerate_keyword INTEGER DEFAULT 0);"
+ "INSERT INTO \"keywords\" VALUES(2,'Google','google.com',"
+ "'http://www.google.com/favicon.ico','{google:baseURL}search?"
+ "{google:RLZ}{google:acceptedSuggestion}"
+ "{google:originalQueryForSuggestion}sourceid=chrome&"
+ "ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8',"
+ "'{google:baseSuggestURL}search?client=chrome&hl={language}&"
+ "q={searchTerms}',1,1);"
+ "INSERT INTO \"keywords\" VALUES(3,'Yahoo!','yahoo.com',"
+ "'http://search.yahoo.com/favicon.ico',"
+ "'http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&"
+ "p={searchTerms}',1,1,'',0,0,'UTF-8',"
+ "'http://ff.search.yahoo.com/gossip?output=fxjson&"
+ "command={searchTerms}',2,0);"
+ "INSERT INTO \"keywords\" VALUES(4,'Bing','bing.com',"
+ "'http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?"
+ "setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8',"
+ "'http://api.bing.com/osjson.aspx?query={searchTerms}&"
+ "language={language}',3,0);"
+ "INSERT INTO \"keywords\" VALUES(5,'Wikipedia (en)','en.wikipedia.org',"
+ "'','http://en.wikipedia.org/w/index.php?title=Special:Search&"
+ "search={searchTerms}',1,0,'',1283287335,0,'','',0,0);"
+ "INSERT INTO \"keywords\" VALUES(6,'NYTimes','query.nytimes.com','',"
+ "'http://query.nytimes.com/gst/handler.html?query={searchTerms}&"
+ "opensearch=1',1,0,'',1283287335,0,'','',0,0);"
+ "INSERT INTO \"keywords\" VALUES(7,'eBay','rover.ebay.com','',"
+ "'http://rover.ebay.com/rover/1/711-43047-14818-1/4?"
+ "satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0);"
+ "INSERT INTO \"keywords\" VALUES(8,'ff','ff','','http://ff{searchTerms}'"
+ ",0,0,'',1283287356,0,'','',0,0);"
+ "CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, "
+ "username_element VARCHAR, username_value VARCHAR, "
+ "password_element VARCHAR, password_value BLOB, "
+ "submit_element VARCHAR, signon_realm VARCHAR NOT NULL,"
+ "ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,"
+ "date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,"
+ "scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, "
+ "username_value, password_element, submit_element, signon_realm));"
+ "CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB,"
+ "date_created INTEGER NOT NULL,UNIQUE (url_hash));"
+ "CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,"
+ "image BLOB, UNIQUE (url, width, height));"
+ "CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,"
+ "has_all_images INTEGER NOT NULL);"
+ "CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,"
+ "pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);"
+ "CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,"
+ "date_created INTEGER DEFAULT 0);"
+ "CREATE TABLE autofill_profiles ( label VARCHAR, "
+ "unique_id INTEGER PRIMARY KEY, first_name VARCHAR, "
+ "middle_name VARCHAR, last_name VARCHAR, email VARCHAR, "
+ "company_name VARCHAR, address_line_1 VARCHAR, "
+ "address_line_2 VARCHAR, city VARCHAR, state VARCHAR, "
+ "zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR);"
+ "CREATE TABLE credit_cards ( label VARCHAR, "
+ "unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR,"
+ "card_number VARCHAR, expiration_month INTEGER, "
+ "expiration_year INTEGER, verification_code VARCHAR, "
+ "billing_address VARCHAR, shipping_address VARCHAR, "
+ "card_number_encrypted BLOB, verification_code_encrypted BLOB);"
+ "CREATE INDEX logins_signon ON logins (signon_realm);"
+ "CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);"
+ "CREATE INDEX web_apps_url_index ON web_apps (url);"
+ "CREATE INDEX autofill_name ON autofill (name);"
+ "CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);"
+ "CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);"
+ "CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);"
+ "CREATE INDEX credit_cards_label_index ON credit_cards (label);"));
+ ASSERT_TRUE(connection.CommitTransaction());
+}
+
+// This schema is taken from a build prior to the addition of the |keywords|
+// |logo_id| column.
+void WebDatabaseMigrationTest::SetUpVersion24Database() {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute(
+ "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+ "value LONGVARCHAR);"
+ "INSERT INTO \"meta\" VALUES('version','24');"
+ "INSERT INTO \"meta\" VALUES('last_compatible_version','24');"
+ "CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,"
+ "keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,"
+ "url VARCHAR NOT NULL,show_in_default_list INTEGER,"
+ "safe_for_autoreplace INTEGER,originating_url VARCHAR,"
+ "date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,"
+ "input_encodings VARCHAR,suggest_url VARCHAR,"
+ "prepopulate_id INTEGER DEFAULT 0,"
+ "autogenerate_keyword INTEGER DEFAULT 0);"
+ "CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,"
+ "username_element VARCHAR, username_value VARCHAR,"
+ "password_element VARCHAR, password_value BLOB, submit_element VARCHAR,"
+ "signon_realm VARCHAR NOT NULL,"
+ "ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,"
+ "date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,"
+ "scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,"
+ "username_value, password_element, submit_element, signon_realm));"
+ "CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,"
+ "image BLOB, UNIQUE (url, width, height));"
+ "CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,"
+ "has_all_images INTEGER NOT NULL);"
+ "CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,"
+ "pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);"
+ "CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,"
+ "date_created INTEGER DEFAULT 0);"
+ "CREATE TABLE autofill_profiles ( label VARCHAR,"
+ "unique_id INTEGER PRIMARY KEY, first_name VARCHAR,"
+ "middle_name VARCHAR, last_name VARCHAR, email VARCHAR,"
+ "company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,"
+ "city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,"
+ "phone VARCHAR, fax VARCHAR);"
+ "CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,"
+ "name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,"
+ "expiration_month INTEGER, expiration_year INTEGER,"
+ "verification_code VARCHAR, billing_address VARCHAR,"
+ "shipping_address VARCHAR, card_number_encrypted BLOB,"
+ "verification_code_encrypted BLOB);"
+ "CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,"
+ "encrypted_token BLOB);"
+ "CREATE INDEX logins_signon ON logins (signon_realm);"
+ "CREATE INDEX web_apps_url_index ON web_apps (url);"
+ "CREATE INDEX autofill_name ON autofill (name);"
+ "CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);"
+ "CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);"
+ "CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);"
+ "CREATE INDEX credit_cards_label_index ON credit_cards (label);"));
+ ASSERT_TRUE(connection.CommitTransaction());
+}
+
+// This schema is taken from a build prior to the addition of the |keywords|
+// |created_by_policy| column.
+void WebDatabaseMigrationTest::SetUpVersion25Database() {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute(
+ "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+ "value LONGVARCHAR);"
+ "INSERT INTO \"meta\" VALUES('version','25');"
+ "INSERT INTO \"meta\" VALUES('last_compatible_version','25');"
+ "CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,"
+ "keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,"
+ "url VARCHAR NOT NULL,show_in_default_list INTEGER,"
+ "safe_for_autoreplace INTEGER,originating_url VARCHAR,"
+ "date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,"
+ "input_encodings VARCHAR,suggest_url VARCHAR,"
+ "prepopulate_id INTEGER DEFAULT 0,"
+ "autogenerate_keyword INTEGER DEFAULT 0,"
+ "logo_id INTEGER DEFAULT 0);"
+ "CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,"
+ "username_element VARCHAR, username_value VARCHAR,"
+ "password_element VARCHAR, password_value BLOB, submit_element VARCHAR,"
+ "signon_realm VARCHAR NOT NULL,"
+ "ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,"
+ "date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,"
+ "scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,"
+ "username_value, password_element, submit_element, signon_realm));"
+ "CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,"
+ "image BLOB, UNIQUE (url, width, height));"
+ "CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,"
+ "has_all_images INTEGER NOT NULL);"
+ "CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,"
+ "pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);"
+ "CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,"
+ "date_created INTEGER DEFAULT 0);"
+ "CREATE TABLE autofill_profiles ( label VARCHAR,"
+ "unique_id INTEGER PRIMARY KEY, first_name VARCHAR,"
+ "middle_name VARCHAR, last_name VARCHAR, email VARCHAR,"
+ "company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,"
+ "city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,"
+ "phone VARCHAR, fax VARCHAR);"
+ "CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,"
+ "name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,"
+ "expiration_month INTEGER, expiration_year INTEGER,"
+ "verification_code VARCHAR, billing_address VARCHAR,"
+ "shipping_address VARCHAR, card_number_encrypted BLOB,"
+ "verification_code_encrypted BLOB);"
+ "CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,"
+ "encrypted_token BLOB);"
+ "CREATE INDEX logins_signon ON logins (signon_realm);"
+ "CREATE INDEX web_apps_url_index ON web_apps (url);"
+ "CREATE INDEX autofill_name ON autofill (name);"
+ "CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);"
+ "CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);"
+ "CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);"
+ "CREATE INDEX credit_cards_label_index ON credit_cards (label);"));
+ ASSERT_TRUE(connection.CommitTransaction());
+}
+
+// This schema is taken from a build prior to the change of column type for
+// credit_cards.billing_address from string to int.
+void WebDatabaseMigrationTest::SetUpVersion26Database() {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute(
+ "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+ "value LONGVARCHAR);"
+ "INSERT INTO \"meta\" VALUES('version','25');"
+ "INSERT INTO \"meta\" VALUES('last_compatible_version','25');"
+ "CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,"
+ "keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,"
+ "url VARCHAR NOT NULL,show_in_default_list INTEGER,"
+ "safe_for_autoreplace INTEGER,originating_url VARCHAR,"
+ "date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,"
+ "input_encodings VARCHAR,suggest_url VARCHAR,"
+ "prepopulate_id INTEGER DEFAULT 0,"
+ "autogenerate_keyword INTEGER DEFAULT 0,"
+ "logo_id INTEGER DEFAULT 0,"
+ "created_by_policy INTEGER DEFAULT 0);"
+ "CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,"
+ "username_element VARCHAR, username_value VARCHAR,"
+ "password_element VARCHAR, password_value BLOB, submit_element VARCHAR,"
+ "signon_realm VARCHAR NOT NULL,"
+ "ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,"
+ "date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,"
+ "scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,"
+ "username_value, password_element, submit_element, signon_realm));"
+ "CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,"
+ "image BLOB, UNIQUE (url, width, height));"
+ "CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,"
+ "has_all_images INTEGER NOT NULL);"
+ "CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,"
+ "pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);"
+ "CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,"
+ "date_created INTEGER DEFAULT 0);"
+ "CREATE TABLE autofill_profiles ( label VARCHAR,"
+ "unique_id INTEGER PRIMARY KEY, first_name VARCHAR,"
+ "middle_name VARCHAR, last_name VARCHAR, email VARCHAR,"
+ "company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,"
+ "city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,"
+ "phone VARCHAR, fax VARCHAR);"
+ "CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,"
+ "name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,"
+ "expiration_month INTEGER, expiration_year INTEGER,"
+ "verification_code VARCHAR, billing_address VARCHAR,"
+ "shipping_address VARCHAR, card_number_encrypted BLOB,"
+ "verification_code_encrypted BLOB);"
+ "CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,"
+ "encrypted_token BLOB);"
+ "CREATE INDEX logins_signon ON logins (signon_realm);"
+ "CREATE INDEX web_apps_url_index ON web_apps (url);"
+ "CREATE INDEX autofill_name ON autofill (name);"
+ "CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);"
+ "CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);"
+ "CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);"
+ "CREATE INDEX credit_cards_label_index ON credit_cards (label);"));
+ ASSERT_TRUE(connection.CommitTransaction());
+}
+
+// Tests that the all migrations from an empty database succeed.
+TEST_F(WebDatabaseMigrationTest, MigrateEmptyToCurrent) {
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ // Check that expected tables are present.
+ EXPECT_TRUE(connection.DoesTableExist("meta"));
+ EXPECT_TRUE(connection.DoesTableExist("keywords"));
+ EXPECT_TRUE(connection.DoesTableExist("logins"));
+ EXPECT_TRUE(connection.DoesTableExist("web_app_icons"));
+ EXPECT_TRUE(connection.DoesTableExist("web_apps"));
+ EXPECT_TRUE(connection.DoesTableExist("autofill"));
+ EXPECT_TRUE(connection.DoesTableExist("autofill_dates"));
+ EXPECT_TRUE(connection.DoesTableExist("autofill_profiles"));
+ EXPECT_TRUE(connection.DoesTableExist("credit_cards"));
+ EXPECT_TRUE(connection.DoesTableExist("token_service"));
+ }
+}
+
+// Tests that the |credit_card| table gets added to the schema for a version 22
+// database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion22ToCurrent) {
+ // Initialize the database.
+ SetUpVersion22Database();
+
+ // Verify pre-conditions.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // No |credit_card| table prior to version 23.
+ ASSERT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id"));
+ ASSERT_FALSE(
+ connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
+ }
+
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ // |credit_card| table now exists.
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
+ EXPECT_TRUE(
+ connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
+ }
+}
+
+// Tests that the |credit_card| table gets added to the schema for a corrupt
+// version 22 database. The corruption is that the |credit_cards| table exists
+// but the schema version number was not set correctly to 23 or later. This
+// test exercises code introduced to fix bug http://crbug.com/50699 that
+// resulted from the corruption.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion22CorruptedToCurrent) {
+ // Initialize the database.
+ SetUpVersion22CorruptDatabase();
+
+ // Verify pre-conditions. These are expectations for corrupt version 22 of
+ // the database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Columns existing and not existing before current version.
+ ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
+ ASSERT_TRUE(
+ connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
+ ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ ASSERT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
+ }
+
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+
+ // Columns existing and not existing before version 25.
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
+ EXPECT_TRUE(
+ connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
+ }
+}
+
+// Tests that the |keywords| |logo_id| column gets added to the schema for a
+// version 24 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion24ToCurrent) {
+ // Initialize the database.
+ SetUpVersion24Database();
+
+ // Verify pre-conditions. These are expectations for version 24 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Columns existing and not existing before current version.
+ ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ ASSERT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
+ }
+
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ // |keywords| |logo_id| column should have been added.
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
+ }
+}
+
+// Tests that the |keywords| |created_by_policy| column gets added to the schema
+// for a version 25 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) {
+ // Initialize the database.
+ SetUpVersion25Database();
+
+ // Verify pre-conditions. These are expectations for version 25 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ }
+
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ // |keywords| |logo_id| column should have been added.
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
+ }
+}
+
+// Tests that the credit_cards.billing_address column is changed from a string
+// to an int whilst preserving the associated billing address. This version of
+// the test makes sure a stored label is converted to an ID.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringLabels) {
+ // Initialize the database.
+ SetUpVersion25Database();
+
+ // Verify pre-conditions. These are expectations for version 25 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Columns existing and not existing before current version.
+ ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ ASSERT_FALSE(connection.DoesColumnExist("keywords", "created_by_policy"));
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
+
+ std::string stmt = "INSERT INTO autofill_profiles"
+ "(label, unique_id, first_name, middle_name, last_name, email,"
+ " company_name, address_line_1, address_line_2, city, state, zipcode,"
+ " country, phone, fax)"
+ "VALUES ('Home',1,'','','','','','','','','','','','','')";
+ sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
+ ASSERT_TRUE(s.Run());
+
+ // Insert a CC linked to an existing address.
+ std::string stmt2 = "INSERT INTO credit_cards"
+ "(label, unique_id, name_on_card, type, card_number,"
+ " expiration_month, expiration_year, verification_code, billing_address,"
+ " shipping_address, card_number_encrypted, verification_code_encrypted)"
+ "VALUES ('label',2,'Jack','Visa','1234',2,2012,'','Home','','','')";
+ sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str()));
+ ASSERT_TRUE(s2.Run());
+
+ // |billing_address| is a string.
+ std::string stmt3 = "SELECT billing_address FROM credit_cards";
+ sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str()));
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT);
+ }
+
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
+
+ // |billing_address| is an integer. Also Verify the credit card data is
+ // converted.
+ std::string stmt = "SELECT * FROM credit_cards";
+ sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
+ ASSERT_TRUE(s.Step());
+ EXPECT_EQ(s.ColumnType(8), sql::COLUMN_TYPE_INTEGER);
+ EXPECT_EQ("label", s.ColumnString(0));
+ EXPECT_EQ(2, s.ColumnInt(1));
+ EXPECT_EQ("Jack", s.ColumnString(2));
+ EXPECT_EQ("Visa", s.ColumnString(3));
+ EXPECT_EQ("1234", s.ColumnString(4));
+ EXPECT_EQ(2, s.ColumnInt(5));
+ EXPECT_EQ(2012, s.ColumnInt(6));
+ EXPECT_EQ(std::string(), s.ColumnString(7));
+ EXPECT_EQ(1, s.ColumnInt(8));
+ // The remaining columns are unused or blobs.
+ }
+}
+
+// Tests that the credit_cards.billing_address column is changed from a string
+// to an int whilst preserving the associated billing address. This version of
+// the test makes sure a stored string ID is converted to an integer ID.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringIDs) {
+ // Initialize the database.
+ SetUpVersion25Database();
+
+ // Verify pre-conditions. These are expectations for version 25 of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
+
+ std::string stmt = "INSERT INTO autofill_profiles"
+ "(label, unique_id, first_name, middle_name, last_name, email,"
+ " company_name, address_line_1, address_line_2, city, state, zipcode,"
+ " country, phone, fax)"
+ "VALUES ('Home',1,'','','','','','','','','','','','','')";
+ sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
+ ASSERT_TRUE(s.Run());
+
+ // Insert a CC linked to an existing address.
+ std::string stmt2 = "INSERT INTO credit_cards"
+ "(label, unique_id, name_on_card, type, card_number,"
+ " expiration_month, expiration_year, verification_code, billing_address,"
+ " shipping_address, card_number_encrypted, verification_code_encrypted)"
+ "VALUES ('label',2,'Jack','Visa','1234',2,2012,'','1','','','')";
+ sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str()));
+ ASSERT_TRUE(s2.Run());
+
+ // |billing_address| is a string.
+ std::string stmt3 = "SELECT billing_address FROM credit_cards";
+ sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str()));
+ ASSERT_TRUE(s3.Step());
+ EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT);
+ }
+
+ // Load the database via the WebDatabase class and migrate the database to
+ // the current version.
+ {
+ WebDatabase db;
+ ASSERT_EQ(sql::INIT_OK, db.Init(GetDatabasePath()));
+ }
+
+ // Verify post-conditions. These are expectations for current version of the
+ // database.
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ // |keywords| |logo_id| column should have been added.
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
+ EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
+ EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
+
+ // |billing_address| is an integer. Also Verify the credit card data is
+ // converted.
+ std::string stmt = "SELECT * FROM credit_cards";
+ sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
+ ASSERT_TRUE(s.Step());
+ EXPECT_EQ(s.ColumnType(8), sql::COLUMN_TYPE_INTEGER);
+ EXPECT_EQ("label", s.ColumnString(0));
+ EXPECT_EQ(2, s.ColumnInt(1));
+ EXPECT_EQ("Jack", s.ColumnString(2));
+ EXPECT_EQ("Visa", s.ColumnString(3));
+ EXPECT_EQ("1234", s.ColumnString(4));
+ EXPECT_EQ(2, s.ColumnInt(5));
+ EXPECT_EQ(2012, s.ColumnInt(6));
+ EXPECT_EQ(std::string(), s.ColumnString(7));
+ EXPECT_EQ(1, s.ColumnInt(8));
+ // The remaining columns are unused or blobs.
+ }
+}
diff --git a/chrome/browser/window_sizer.cc b/chrome/browser/window_sizer.cc
index 74e1af4..dee1221 100644
--- a/chrome/browser/window_sizer.cc
+++ b/chrome/browser/window_sizer.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/pref_service.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
///////////////////////////////////////////////////////////////////////////////
@@ -16,7 +16,7 @@
// and persistent state from the browser window and the user's profile.
class DefaultStateProvider : public WindowSizer::StateProvider {
public:
- explicit DefaultStateProvider(const std::wstring& app_name, Browser* browser)
+ explicit DefaultStateProvider(const std::string& app_name, Browser* browser)
: app_name_(app_name),
browser_(browser) {
}
@@ -27,9 +27,9 @@ class DefaultStateProvider : public WindowSizer::StateProvider {
gfx::Rect* work_area) const {
DCHECK(bounds && maximized);
- std::wstring key(prefs::kBrowserWindowPlacement);
+ std::string key(prefs::kBrowserWindowPlacement);
if (!app_name_.empty()) {
- key.append(L"_");
+ key.append("_");
key.append(app_name_);
}
@@ -41,11 +41,11 @@ class DefaultStateProvider : public WindowSizer::StateProvider {
int top = 0, left = 0, bottom = 0, right = 0;
bool has_prefs =
wp_pref &&
- wp_pref->GetInteger(L"top", &top) &&
- wp_pref->GetInteger(L"left", &left) &&
- wp_pref->GetInteger(L"bottom", &bottom) &&
- wp_pref->GetInteger(L"right", &right) &&
- wp_pref->GetBoolean(L"maximized", maximized);
+ 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));
@@ -54,10 +54,10 @@ class DefaultStateProvider : public WindowSizer::StateProvider {
int work_area_bottom = 0;
int work_area_right = 0;
if (wp_pref) {
- wp_pref->GetInteger(L"work_area_top", &work_area_top);
- wp_pref->GetInteger(L"work_area_left", &work_area_left);
- wp_pref->GetInteger(L"work_area_bottom", &work_area_bottom);
- wp_pref->GetInteger(L"work_area_right", &work_area_right);
+ 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),
@@ -99,7 +99,7 @@ class DefaultStateProvider : public WindowSizer::StateProvider {
}
private:
- std::wstring app_name_;
+ std::string app_name_;
// If set, is used as the reference browser for GetLastActiveWindowState.
Browser* browser_;
@@ -123,7 +123,7 @@ WindowSizer::~WindowSizer() {
}
// static
-void WindowSizer::GetBrowserWindowBounds(const std::wstring& app_name,
+void WindowSizer::GetBrowserWindowBounds(const std::string& app_name,
const gfx::Rect& specified_bounds,
Browser* browser,
gfx::Rect* window_bounds,
@@ -136,7 +136,7 @@ void WindowSizer::GetBrowserWindowBounds(const std::wstring& app_name,
///////////////////////////////////////////////////////////////////////////////
// WindowSizer, private:
-WindowSizer::WindowSizer(const std::wstring& app_name) {
+WindowSizer::WindowSizer(const std::string& app_name) {
Init(new DefaultStateProvider(app_name, NULL),
CreateDefaultMonitorInfoProvider());
}
diff --git a/chrome/browser/window_sizer.h b/chrome/browser/window_sizer.h
index 33d4574..16958e2 100644
--- a/chrome/browser/window_sizer.h
+++ b/chrome/browser/window_sizer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WINDOW_SIZER_H_
#define CHROME_BROWSER_WINDOW_SIZER_H_
+#pragma once
#include <vector>
@@ -117,7 +118,7 @@ class WindowSizer {
// |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::wstring& app_name,
+ static void GetBrowserWindowBounds(const std::string& app_name,
const gfx::Rect& specified_bounds,
Browser* browser,
gfx::Rect* window_bounds,
@@ -134,7 +135,7 @@ class WindowSizer {
// The edge of the screen to check for out-of-bounds.
enum Edge { TOP, LEFT, BOTTOM, RIGHT };
- explicit WindowSizer(const std::wstring& app_name);
+ explicit WindowSizer(const std::string& app_name);
void Init(StateProvider* state_provider,
MonitorInfoProvider* monitor_info_provider);
diff --git a/chrome/browser/worker_host/message_port_dispatcher.cc b/chrome/browser/worker_host/message_port_dispatcher.cc
index 070ea3d..52300f4 100644
--- a/chrome/browser/worker_host/message_port_dispatcher.cc
+++ b/chrome/browser/worker_host/message_port_dispatcher.cc
@@ -65,7 +65,6 @@ void MessagePortDispatcher::UpdateMessagePort(
IPC::Message::Sender* sender,
int routing_id,
CallbackWithReturnValue<int>::Type* next_routing_id) {
- DCHECK(CheckMessagePortMap(true));
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
@@ -75,17 +74,14 @@ void MessagePortDispatcher::UpdateMessagePort(
port.sender = sender;
port.route_id = routing_id;
port.next_routing_id = next_routing_id;
- DCHECK(CheckMessagePortMap(true));
}
bool MessagePortDispatcher::Send(IPC::Message* message) {
- DCHECK(CheckMessagePortMap(true));
return sender_->Send(message);
}
void MessagePortDispatcher::OnCreate(int *route_id,
int* message_port_id) {
- DCHECK(CheckMessagePortMap(true));
*message_port_id = ++next_message_port_id_;
*route_id = next_routing_id_->Run();
@@ -97,11 +93,9 @@ void MessagePortDispatcher::OnCreate(int *route_id,
port.entangled_message_port_id = MSG_ROUTING_NONE;
port.queue_messages = false;
message_ports_[*message_port_id] = port;
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::OnDestroy(int message_port_id) {
- DCHECK(CheckMessagePortMap(true));
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
@@ -109,12 +103,10 @@ void MessagePortDispatcher::OnDestroy(int message_port_id) {
DCHECK(message_ports_[message_port_id].queued_messages.empty());
Erase(message_port_id);
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::OnEntangle(int local_message_port_id,
int remote_message_port_id) {
- DCHECK(CheckMessagePortMap(false));
if (!message_ports_.count(local_message_port_id) ||
!message_ports_.count(remote_message_port_id)) {
NOTREACHED();
@@ -125,14 +117,12 @@ void MessagePortDispatcher::OnEntangle(int local_message_port_id,
MSG_ROUTING_NONE);
message_ports_[remote_message_port_id].entangled_message_port_id =
local_message_port_id;
- DCHECK(CheckMessagePortMap(false));
}
void MessagePortDispatcher::OnPostMessage(
int sender_message_port_id,
const string16& message,
const std::vector<int>& sent_message_port_ids) {
- DCHECK(CheckMessagePortMap(true));
if (!message_ports_.count(sender_message_port_id)) {
NOTREACHED();
return;
@@ -149,14 +139,12 @@ void MessagePortDispatcher::OnPostMessage(
}
PostMessageTo(entangled_message_port_id, message, sent_message_port_ids);
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::PostMessageTo(
int message_port_id,
const string16& message,
const std::vector<int>& sent_message_port_ids) {
- DCHECK(CheckMessagePortMap(true));
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
@@ -198,11 +186,9 @@ void MessagePortDispatcher::PostMessageTo(
new_routing_ids);
entangled_port.sender->Send(ipc_msg);
}
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::OnQueueMessages(int message_port_id) {
- DCHECK(CheckMessagePortMap(true));
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
@@ -212,13 +198,11 @@ void MessagePortDispatcher::OnQueueMessages(int message_port_id) {
port.sender->Send(new WorkerProcessMsg_MessagesQueued(port.route_id));
port.queue_messages = true;
port.sender = NULL;
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::OnSendQueuedMessages(
int message_port_id,
const QueuedMessages& queued_messages) {
- DCHECK(CheckMessagePortMap(true));
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
@@ -232,11 +216,9 @@ void MessagePortDispatcher::OnSendQueuedMessages(
queued_messages.begin(),
queued_messages.end());
SendQueuedMessagesIfPossible(message_port_id);
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::SendQueuedMessagesIfPossible(int message_port_id) {
- DCHECK(CheckMessagePortMap(true));
if (!message_ports_.count(message_port_id)) {
NOTREACHED();
return;
@@ -251,14 +233,11 @@ void MessagePortDispatcher::SendQueuedMessagesIfPossible(int message_port_id) {
PostMessageTo(message_port_id, iter->first, iter->second);
}
port.queued_messages.clear();
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(CheckMessagePortMap(true));
-
IPC::Message::Sender* sender = NULL;
if (type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN) {
sender = Source<ResourceMessageFilter>(source).ptr();
@@ -276,8 +255,6 @@ void MessagePortDispatcher::Observe(NotificationType type,
Erase(cur_item->first);
}
}
-
- DCHECK(CheckMessagePortMap(true));
}
void MessagePortDispatcher::Erase(int message_port_id) {
@@ -294,23 +271,3 @@ void MessagePortDispatcher::Erase(int message_port_id) {
}
message_ports_.erase(erase_item);
}
-
-#ifndef NDEBUG
-bool MessagePortDispatcher::CheckMessagePortMap(bool check_entanglements) {
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
-
- for (MessagePorts::iterator iter = message_ports_.begin();
- iter != message_ports_.end(); iter++) {
- DCHECK(iter->first <= next_message_port_id_);
- DCHECK(iter->first == iter->second.message_port_id);
-
- int entangled_id = iter->second.entangled_message_port_id;
- if (check_entanglements && entangled_id != MSG_ROUTING_NONE) {
- MessagePorts::iterator entangled_item = message_ports_.find(entangled_id);
- DCHECK(entangled_item != message_ports_.end());
- DCHECK(entangled_item->second.entangled_message_port_id == iter->first);
- }
- }
- return true;
-}
-#endif // NDEBUG
diff --git a/chrome/browser/worker_host/message_port_dispatcher.h b/chrome/browser/worker_host/message_port_dispatcher.h
index a6cff2a..b8f7021 100644
--- a/chrome/browser/worker_host/message_port_dispatcher.h
+++ b/chrome/browser/worker_host/message_port_dispatcher.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
#define CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
+#pragma once
#include <map>
#include <utility>
@@ -14,6 +15,7 @@
#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"
@@ -72,12 +74,6 @@ class MessagePortDispatcher : public NotificationObserver {
// verify that the message port id exists.
void Erase(int message_port_id);
-#ifdef NDEBUG
- bool CheckMessagePortMap(bool check_entanglements) { return true; }
-#else
- bool CheckMessagePortMap(bool check_entanglements);
-#endif
-
struct MessagePort {
// sender and route_id are what we need to send messages to the port.
IPC::Message::Sender* sender;
diff --git a/chrome/browser/worker_host/worker_document_set.h b/chrome/browser/worker_host/worker_document_set.h
index 57c1669..be3fff3 100644
--- a/chrome/browser/worker_host/worker_document_set.h
+++ b/chrome/browser/worker_host/worker_document_set.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WORKER_HOST_WORKER_DOCUMENT_SET_H_
#define CHROME_BROWSER_WORKER_HOST_WORKER_DOCUMENT_SET_H_
+#pragma once
#include <set>
diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc
index 762a0c5..868ba6c 100644
--- a/chrome/browser/worker_host/worker_process_host.cc
+++ b/chrome/browser/worker_host/worker_process_host.cc
@@ -12,11 +12,14 @@
#include "base/debug_util.h"
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/appcache/appcache_dispatcher_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/file_system/file_system_dispatcher_host.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/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
@@ -27,6 +30,7 @@
#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"
#include "chrome/common/worker_messages.h"
#include "ipc/ipc_switches.h"
@@ -61,7 +65,14 @@ WorkerProcessHost::WorkerProcessHost(
: BrowserChildProcessHost(WORKER_PROCESS, resource_dispatcher_host),
request_context_(request_context),
appcache_dispatcher_host_(
- new AppCacheDispatcherHost(request_context)) {
+ 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->file_system_host_context(),
+ request_context->host_content_settings_map()))) {
next_route_id_callback_.reset(NewCallbackWithReturnValue(
WorkerService::GetInstance(), &WorkerService::next_worker_route_id));
db_dispatcher_host_ = new DatabaseDispatcherHost(
@@ -74,6 +85,12 @@ 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();
+
// Let interested observers know we are being deleted.
NotificationService::current()->Notify(
NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
@@ -105,58 +122,29 @@ bool WorkerProcessHost::Init() {
return false;
CommandLine* cmd_line = new CommandLine(exe_path);
- cmd_line->AppendSwitchWithValue(switches::kProcessType,
- switches::kWorkerProcess);
- cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
- ASCIIToWide(channel_id()));
+ cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kWorkerProcess);
+ cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
SetCrashReporterCommandLine(cmd_line);
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableNativeWebWorkers)) {
- cmd_line->AppendSwitch(switches::kEnableNativeWebWorkers);
- }
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kWebWorkerShareProcesses)) {
- cmd_line->AppendSwitch(switches::kWebWorkerShareProcesses);
- }
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableApplicationCache)) {
- cmd_line->AppendSwitch(switches::kDisableApplicationCache);
- }
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableDatabases)) {
- cmd_line->AppendSwitch(switches::kDisableDatabases);
- }
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableLogging)) {
- cmd_line->AppendSwitch(switches::kEnableLogging);
- }
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kLoggingLevel)) {
- const std::wstring level =
- CommandLine::ForCurrentProcess()->GetSwitchValue(
- switches::kLoggingLevel);
- cmd_line->AppendSwitchWithValue(
- switches::kLoggingLevel, level);
- }
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableWebSockets)) {
- cmd_line->AppendSwitch(switches::kDisableWebSockets);
- }
-
+ static const char* const kSwitchNames[] = {
+ switches::kEnableNativeWebWorkers,
+ switches::kWebWorkerShareProcesses,
+ switches::kDisableApplicationCache,
+ switches::kDisableDatabases,
+ switches::kEnableLogging,
+ switches::kLoggingLevel,
+ switches::kDisableWebSockets,
#if defined(OS_WIN)
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableDesktopNotifications)) {
- cmd_line->AppendSwitch(switches::kDisableDesktopNotifications);
- }
+ switches::kDisableDesktopNotifications,
#endif
+ switches::kEnableFileSystem,
+ };
+ cmd_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), kSwitchNames,
+ arraysize(kSwitchNames));
#if defined(OS_POSIX)
+ bool use_zygote = true;
+
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kWaitForDebuggerChildren)) {
// Look to pass-on the kWaitForDebugger flag.
@@ -164,6 +152,7 @@ bool WorkerProcessHost::Init() {
switches::kWaitForDebuggerChildren);
if (value.empty() || value == switches::kWorkerProcess) {
cmd_line->AppendSwitch(switches::kWaitForDebugger);
+ use_zygote = false;
}
}
@@ -174,24 +163,17 @@ bool WorkerProcessHost::Init() {
if (value.empty() || value == switches::kWorkerProcess) {
// launches a new xterm, and runs the worker process in gdb, reading
// optional commands from gdb_chrome file in the working directory.
- cmd_line->PrependWrapper(L"xterm -e gdb -x gdb_chrome --args");
+ cmd_line->PrependWrapper("xterm -e gdb -x gdb_chrome --args");
+ use_zygote = false;
}
}
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kRendererCmdPrefix)) {
- const std::wstring prefix =
- CommandLine::ForCurrentProcess()->GetSwitchValue(
- switches::kRendererCmdPrefix);
- cmd_line->PrependWrapper(prefix);
- }
#endif
Launch(
#if defined(OS_WIN)
FilePath(),
#elif defined(OS_POSIX)
- false,
+ use_zygote,
base::environment_vector(),
#endif
cmd_line);
@@ -267,6 +249,8 @@ void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
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) ||
MessagePortDispatcher::GetInstance()->OnMessageReceived(
message, this, next_route_id_callback_.get(), &msg_is_ok);
@@ -315,6 +299,7 @@ void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
void WorkerProcessHost::OnProcessLaunched() {
db_dispatcher_host_->Init(handle());
+ file_system_dispatcher_host_->Init(handle());
}
CallbackWithReturnValue<int>::Type* WorkerProcessHost::GetNextRouteIdCallback(
@@ -505,8 +490,7 @@ void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) {
}
void WorkerProcessHost::DocumentDetached(IPC::Message::Sender* parent,
- unsigned long long document_id)
-{
+ 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()) {
@@ -549,6 +533,9 @@ WorkerProcessHost::WorkerInstance::WorkerInstance(
(off_the_record == request_context->is_off_the_record()));
}
+WorkerProcessHost::WorkerInstance::~WorkerInstance() {
+}
+
// Compares an instance based on the algorithm in the WebWorkers spec - an
// instance matches if the origins of the URLs match, and:
// a) the names are non-empty and equal
diff --git a/chrome/browser/worker_host/worker_process_host.h b/chrome/browser/worker_host/worker_process_host.h
index 6e95b3f..0bdc4ef 100644
--- a/chrome/browser/worker_host/worker_process_host.h
+++ b/chrome/browser/worker_host/worker_process_host.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WORKER_HOST_WORKER_PROCESS_HOST_H_
#define CHROME_BROWSER_WORKER_HOST_WORKER_PROCESS_HOST_H_
+#pragma once
#include <list>
@@ -17,9 +18,11 @@
#include "ipc/ipc_channel.h"
class AppCacheDispatcherHost;
+class BlobDispatcherHost;
class ChromeURLRequestContext;
class ChromeURLRequestContextGetter;
class DatabaseDispatcherHost;
+class FileSystemDispatcherHost;
namespace webkit_database {
class DatabaseTracker;
} // namespace webkit_database
@@ -47,6 +50,7 @@ class WorkerProcessHost : public BrowserChildProcessHost {
int parent_appcache_host_id,
int64 main_resource_appcache_id,
ChromeURLRequestContext* request_context);
+ ~WorkerInstance();
// Unique identifier for a worker client.
typedef std::pair<IPC::Message::Sender*, int> SenderInfo;
@@ -193,6 +197,8 @@ class WorkerProcessHost : public BrowserChildProcessHost {
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_;
// A callback to create a routing id for the associated worker process.
scoped_ptr<CallbackWithReturnValue<int>::Type> next_route_id_callback_;
diff --git a/chrome/browser/worker_host/worker_service.h b/chrome/browser/worker_host/worker_service.h
index fb1c0ca..744f116 100644
--- a/chrome/browser/worker_host/worker_service.h
+++ b/chrome/browser/worker_host/worker_service.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_WORKER_HOST_WORKER_SERVICE_H_
#define CHROME_BROWSER_WORKER_HOST_WORKER_SERVICE_H_
+#pragma once
#include <list>
diff --git a/chrome/browser/wrench_menu_model.cc b/chrome/browser/wrench_menu_model.cc
index c48b973..e18c4ce 100644
--- a/chrome/browser/wrench_menu_model.cc
+++ b/chrome/browser/wrench_menu_model.cc
@@ -10,6 +10,10 @@
#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/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
@@ -17,17 +21,30 @@
#include "chrome/browser/encoding_menu_controller.h"
#include "chrome/browser/host_zoom_map.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/upgrade_detector.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
+
////////////////////////////////////////////////////////////////////////////////
// EncodingMenuModel
@@ -37,6 +54,9 @@ EncodingMenuModel::EncodingMenuModel(Browser* browser)
Build();
}
+EncodingMenuModel::~EncodingMenuModel() {
+}
+
void EncodingMenuModel::Build() {
EncodingMenuController::EncodingMenuItemList encoding_menu_items;
EncodingMenuController encoding_menu_controller;
@@ -102,6 +122,9 @@ ZoomMenuModel::ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate)
Build();
}
+ZoomMenuModel::~ZoomMenuModel() {
+}
+
void ZoomMenuModel::Build() {
AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
@@ -138,6 +161,10 @@ void ToolsMenuModel::Build(Browser* browser) {
AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
AddSeparator();
+#if defined(OS_CHROMEOS)
+ AddItemWithStringId(IDC_REPORT_BUG, IDS_REPORT_BUG);
+ AddSeparator();
+#endif
encoding_menu_model_.reset(new EncodingMenuModel(browser));
AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
@@ -152,10 +179,10 @@ void ToolsMenuModel::Build(Browser* browser) {
////////////////////////////////////////////////////////////////////////////////
// WrenchMenuModel
-WrenchMenuModel::WrenchMenuModel(menus::SimpleMenuModel::Delegate* delegate,
+WrenchMenuModel::WrenchMenuModel(menus::AcceleratorProvider* provider,
Browser* browser)
- : menus::SimpleMenuModel(delegate),
- delegate_(delegate),
+ : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
+ provider_(provider),
browser_(browser),
tabstrip_model_(browser_->tabstrip_model()) {
Build();
@@ -174,50 +201,79 @@ WrenchMenuModel::~WrenchMenuModel() {
tabstrip_model_->RemoveObserver(this);
}
-bool WrenchMenuModel::IsLabelDynamicAt(int index) const {
- return IsDynamicItem(index) || SimpleMenuModel::IsLabelDynamicAt(index);
+bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
+ return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
}
-string16 WrenchMenuModel::GetLabelAt(int index) const {
- if (!IsDynamicItem(index))
- return SimpleMenuModel::GetLabelAt(index);
-
- int command_id = GetCommandIdAt(index);
+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;
+}
+string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
switch (command_id) {
- case IDC_ABOUT:
- return GetAboutEntryMenuLabel();
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
default:
NOTREACHED();
return string16();
}
}
-bool WrenchMenuModel::GetIconAt(int index, SkBitmap* icon) const {
- if (GetCommandIdAt(index) == IDC_ABOUT &&
- Singleton<UpgradeDetector>::get()->notify_upgrade()) {
- // Show the exclamation point next to the menu item.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- *icon = *rb.GetBitmapNamed(IDR_UPDATE_AVAILABLE);
- return true;
+void WrenchMenuModel::ExecuteCommand(int command_id) {
+ browser_->ExecuteCommand(command_id);
+}
+
+bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
+#if defined(OS_CHROMEOS)
+ if (command_id == IDC_TOGGLE_VERTICAL_TABS) {
+ return browser_->UseVerticalTabs();
}
+#endif
+
+ if (command_id == IDC_SHOW_BOOKMARK_BAR) {
+ return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
+ }
+
return false;
}
-bool WrenchMenuModel::IsLabelForCommandIdDynamic(int command_id) const {
- return command_id == IDC_ZOOM_PERCENT_DISPLAY;
+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::kBWSI))
+ return false;
+#endif
+
+ return browser_->command_updater()->IsCommandEnabled(command_id);
}
-string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
- DCHECK_EQ(IDC_ZOOM_PERCENT_DISPLAY, command_id);
- return zoom_label_;
+bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
+ if (command_id == IDC_UPGRADE_DIALOG)
+ return Singleton<UpgradeDetector>::get()->notify_upgrade();
+ return true;
}
-void WrenchMenuModel::ExecuteCommand(int command_id) {
- if (delegate_)
- delegate_->ExecuteCommand(command_id);
+bool WrenchMenuModel::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ return provider_->GetAcceleratorForCommandId(command_id, accelerator);
}
void WrenchMenuModel::TabSelectedAt(TabContents* old_contents,
@@ -247,10 +303,19 @@ void WrenchMenuModel::Observe(NotificationType type,
UpdateZoomControls();
}
+// 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);
+ AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW,
+ IDS_NEW_INCOGNITO_WINDOW);
AddSeparator();
#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(TOOLKIT_VIEWS))
@@ -292,41 +357,65 @@ void WrenchMenuModel::Build() {
AddItemWithStringId(IDC_FIND, IDS_FIND);
AddItemWithStringId(IDC_PRINT, IDS_PRINT);
- tools_menu_model_.reset(new ToolsMenuModel(delegate(), browser_));
+ 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 (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableTabbedOptions)) {
+ AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
+ } else {
#if defined(OS_MACOSX)
- AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES_MAC);
+ AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES_MAC);
+#elif defined(OS_LINUX)
+ string16 preferences = gtk_util::GetStockPreferencesMenuLabel();
+ if (!preferences.empty())
+ AddItem(IDC_OPTIONS, preferences);
+ else
+ AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
#else
- AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
+ AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
#endif
+ }
#if defined(OS_CHROMEOS)
AddCheckItemWithStringId(IDC_TOGGLE_VERTICAL_TABS,
IDS_TAB_CXMENU_USE_VERTICAL_TABS);
#endif
- // On Mac, there is no About item unless it is replaced with the update
- // available notification.
- if (browser_defaults::kShowAboutMenuItem ||
- Singleton<UpgradeDetector>::get()->notify_upgrade()) {
- AddItem(IDC_ABOUT,
- l10n_util::GetStringFUTF16(
- IDS_ABOUT,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ // On Mac, there is no About item.
+ if (browser_defaults::kShowAboutMenuItem) {
+ AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(
+ IDS_ABOUT, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
}
+
+ AddItem(IDC_UPGRADE_DIALOG, l10n_util::GetStringFUTF16(
+ IDS_UPDATE_NOW, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SetIcon(GetIndexOfCommandId(IDC_UPGRADE_DIALOG),
+ *rb.GetBitmapNamed(IDR_UPDATE_AVAILABLE));
+
AddItemWithStringId(IDC_HELP_PAGE, IDS_HELP_PAGE);
if (browser_defaults::kShowExitMenuItem) {
AddSeparator();
#if defined(OS_CHROMEOS)
- AddItemWithStringId(IDC_EXIT, IDS_SIGN_OUT);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kBWSI)) {
+ AddItemWithStringId(IDC_EXIT, IDS_EXIT_GUEST_MODE);
+ } else {
+ AddItemWithStringId(IDC_EXIT, IDS_SIGN_OUT);
+ }
#else
AddItemWithStringId(IDC_EXIT, IDS_EXIT);
#endif
@@ -354,7 +443,7 @@ void WrenchMenuModel::UpdateZoomControls() {
int zoom_percent =
static_cast<int>(GetZoom(&enable_increment, &enable_decrement) * 100);
zoom_label_ = l10n_util::GetStringFUTF16(
- IDS_ZOOM_PERCENT, IntToString16(zoom_percent));
+ IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
}
double WrenchMenuModel::GetZoom(bool* enable_increment,
@@ -381,18 +470,3 @@ string16 WrenchMenuModel::GetSyncMenuLabel() const {
return sync_ui_util::GetSyncMenuLabel(
browser_->profile()->GetOriginalProfile()->GetProfileSyncService());
}
-
-string16 WrenchMenuModel::GetAboutEntryMenuLabel() const {
- if (Singleton<UpgradeDetector>::get()->notify_upgrade()) {
- return l10n_util::GetStringFUTF16(
- IDS_UPDATE_NOW, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- }
- return l10n_util::GetStringFUTF16(
- IDS_ABOUT, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
-}
-
-bool WrenchMenuModel::IsDynamicItem(int index) const {
- int command_id = GetCommandIdAt(index);
- return command_id == IDC_SYNC_BOOKMARKS ||
- command_id == IDC_ABOUT;
-}
diff --git a/chrome/browser/wrench_menu_model.h b/chrome/browser/wrench_menu_model.h
index 161e2c0..8011be1 100644
--- a/chrome/browser/wrench_menu_model.h
+++ b/chrome/browser/wrench_menu_model.h
@@ -4,23 +4,18 @@
#ifndef CHROME_BROWSER_WRENCH_MENU_MODEL_H_
#define CHROME_BROWSER_WRENCH_MENU_MODEL_H_
+#pragma once
-#include <set>
-#include <vector>
-
+#include "app/menus/accelerator.h"
#include "app/menus/button_menu_item_model.h"
#include "app/menus/simple_menu_model.h"
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class Browser;
-
-namespace menus {
-class ButtonMenuItemModel;
-} // namespace menus
+class TabStripModel;
namespace {
class MockWrenchMenuModel;
@@ -31,7 +26,7 @@ class EncodingMenuModel : public menus::SimpleMenuModel,
public menus::SimpleMenuModel::Delegate {
public:
explicit EncodingMenuModel(Browser* browser);
- virtual ~EncodingMenuModel() {}
+ virtual ~EncodingMenuModel();
// Overridden from menus::SimpleMenuModel::Delegate:
virtual bool IsCommandIdChecked(int command_id) const;
@@ -52,7 +47,7 @@ class EncodingMenuModel : public menus::SimpleMenuModel,
class ZoomMenuModel : public menus::SimpleMenuModel {
public:
explicit ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate);
- virtual ~ZoomMenuModel() {}
+ virtual ~ZoomMenuModel();
private:
void Build();
@@ -75,24 +70,27 @@ class ToolsMenuModel : public menus::SimpleMenuModel {
// 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::SimpleMenuModel::Delegate* delegate,
- Browser* browser);
+ WrenchMenuModel(menus::AcceleratorProvider* provider, Browser* browser);
virtual ~WrenchMenuModel();
- // Overridden from menus::SimpleMenuModel:
- virtual bool IsLabelDynamicAt(int index) const;
- virtual string16 GetLabelAt(int index) const;
- virtual bool HasIcons() const { return true; }
- virtual bool GetIconAt(int index, SkBitmap* icon) const;
+ // Overridden for ButtonMenuItemModel::Delegate:
+ virtual bool DoesCommandIdDismissMenu(int command_id) const;
- // Overridden from menus::ButtonMenuItemModel::Delegate:
+ // 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(TabContents* old_contents,
@@ -111,10 +109,13 @@ class WrenchMenuModel : public menus::SimpleMenuModel,
// 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() : menus::SimpleMenuModel(NULL) {}
+ WrenchMenuModel();
void Build();
@@ -123,13 +124,10 @@ class WrenchMenuModel : public menus::SimpleMenuModel,
void CreateCutCopyPaste();
void CreateZoomFullscreen();
- // Calculates |zoom_label_| in response to a zoom change.
- void UpdateZoomControls();
+ // Gets the current zoom information from the renderer.
double GetZoom(bool* enable_increment, bool* enable_decrement);
string16 GetSyncMenuLabel() const;
- string16 GetAboutEntryMenuLabel() const;
- bool IsDynamicItem(int index) const;
// Models for the special menu items with buttons.
scoped_ptr<menus::ButtonMenuItemModel> edit_menu_item_model_;
@@ -141,7 +139,7 @@ class WrenchMenuModel : public menus::SimpleMenuModel,
// Tools menu.
scoped_ptr<ToolsMenuModel> tools_menu_model_;
- menus::SimpleMenuModel::Delegate* delegate_; // weak
+ menus::AcceleratorProvider* provider_; // weak
Browser* browser_; // weak
TabStripModel* tabstrip_model_; // weak
diff --git a/chrome/browser/wrench_menu_model_unittest.cc b/chrome/browser/wrench_menu_model_unittest.cc
index 2b50bb0..c539cee 100644
--- a/chrome/browser/wrench_menu_model_unittest.cc
+++ b/chrome/browser/wrench_menu_model_unittest.cc
@@ -4,19 +4,57 @@
#include "chrome/browser/wrench_menu_model.h"
-#include "base/logging.h"
#include "chrome/app/chrome_dll_resource.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 MenuModelTest {
+ 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) {
- WrenchMenuModel model(&delegate_, browser());
+ TestWrenchMenuModel model(this, browser());
int itemCount = model.GetItemCount();
// Verify it has items. The number varies by platform, so we don't check
@@ -31,11 +69,11 @@ TEST_F(WrenchMenuModelTest, Basics) {
// Make sure to use the index that is not separator in all configurations.
model.ActivatedAt(2);
EXPECT_TRUE(model.IsEnabledAt(2));
- EXPECT_EQ(delegate_.execute_count_, 2);
- EXPECT_EQ(delegate_.enable_count_, 2);
+ EXPECT_EQ(model.execute_count_, 2);
+ EXPECT_EQ(model.enable_count_, 2);
- delegate_.execute_count_ = 0;
- delegate_.enable_count_ = 0;
+ 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.
@@ -52,8 +90,8 @@ TEST_F(WrenchMenuModelTest, Basics) {
EXPECT_GT(toolsModel->GetItemCount(), 2);
toolsModel->ActivatedAt(2);
EXPECT_TRUE(toolsModel->IsEnabledAt(2));
- EXPECT_EQ(delegate_.execute_count_, 1);
- EXPECT_EQ(delegate_.enable_count_, 1);
+ EXPECT_EQ(model.execute_count_, 1);
+ EXPECT_EQ(model.enable_count_, 1);
}
class EncodingMenuModelTest : public BrowserWithTestWindowTest,
diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc
index 9423598..5ef002f 100644
--- a/chrome/browser/zygote_host_linux.cc
+++ b/chrome/browser/zygote_host_linux.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.
@@ -11,13 +11,17 @@
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
+#include "base/environment.h"
#include "base/linux_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/process_util.h"
+#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"
@@ -37,11 +41,12 @@ static void SaveSUIDUnsafeEnvironmentVariables() {
if (!saved_envvar)
continue;
- const char* const value = getenv(envvar);
- if (value)
- setenv(saved_envvar, value, 1 /* overwrite */);
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ std::string value;
+ if (env->GetVar(envvar, &value))
+ env->SetVar(saved_envvar, value);
else
- unsetenv(saved_envvar);
+ env->UnSetVar(saved_envvar);
free(saved_envvar);
}
@@ -67,8 +72,7 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
CommandLine cmd_line(chrome_path);
- cmd_line.AppendSwitchWithValue(switches::kProcessType,
- switches::kZygoteProcess);
+ cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess);
int fds[2];
CHECK(socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
@@ -77,40 +81,27 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
if (browser_command_line.HasSwitch(switches::kZygoteCmdPrefix)) {
- const std::wstring prefix =
- browser_command_line.GetSwitchValue(switches::kZygoteCmdPrefix);
- cmd_line.PrependWrapper(prefix);
+ cmd_line.PrependWrapper(
+ browser_command_line.GetSwitchValueNative(switches::kZygoteCmdPrefix));
}
// Append any switches from the browser process that need to be forwarded on
// to the zygote/renderers.
// Should this list be obtained from browser_render_process_host.cc?
- if (browser_command_line.HasSwitch(switches::kAllowSandboxDebugging)) {
- cmd_line.AppendSwitch(switches::kAllowSandboxDebugging);
- }
- if (browser_command_line.HasSwitch(switches::kLoggingLevel)) {
- cmd_line.AppendSwitchWithValue(switches::kLoggingLevel,
- browser_command_line.GetSwitchValueASCII(
- switches::kLoggingLevel));
- }
- if (browser_command_line.HasSwitch(switches::kEnableLogging)) {
- // Append with value to support --enable-logging=stderr.
- cmd_line.AppendSwitchWithValue(switches::kEnableLogging,
- browser_command_line.GetSwitchValueASCII(
- switches::kEnableLogging));
- }
- if (browser_command_line.HasSwitch(switches::kUserDataDir)) {
- // Append with value so logs go to the right file.
- cmd_line.AppendSwitchWithValue(switches::kUserDataDir,
- browser_command_line.GetSwitchValueASCII(
- switches::kUserDataDir));
- }
+ static const char* kForwardSwitches[] = {
+ switches::kAllowSandboxDebugging,
+ switches::kLoggingLevel,
+ switches::kEnableLogging, // Support, e.g., --enable-logging=stderr.
+ 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)
- if (browser_command_line.HasSwitch(switches::kDisableSeccompSandbox))
- cmd_line.AppendSwitch(switches::kDisableSeccompSandbox);
+ switches::kDisableSeccompSandbox,
#else
- if (browser_command_line.HasSwitch(switches::kEnableSeccompSandbox))
- cmd_line.AppendSwitch(switches::kEnableSeccompSandbox);
+ switches::kEnableSeccompSandbox,
#endif
+ };
+ cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches,
+ arraysize(kForwardSwitches));
sandbox_binary_ = sandbox_cmd.c_str();
struct stat st;
@@ -121,7 +112,7 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
(st.st_mode & S_ISUID) &&
(st.st_mode & S_IXOTH)) {
using_suid_sandbox_ = true;
- cmd_line.PrependWrapper(ASCIIToWide(sandbox_binary_.c_str()));
+ cmd_line.PrependWrapper(sandbox_binary_);
SaveSUIDUnsafeEnvironmentVariables();
} else {
@@ -169,10 +160,10 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
std::vector<std::string> get_inode_cmdline;
get_inode_cmdline.push_back(sandbox_binary_);
get_inode_cmdline.push_back(base::kFindInodeSwitch);
- get_inode_cmdline.push_back(Int64ToString(inode));
+ get_inode_cmdline.push_back(base::Int64ToString(inode));
CommandLine get_inode_cmd(get_inode_cmdline);
if (base::GetAppOutput(get_inode_cmd, &inode_output)) {
- StringToInt(inode_output, &pid_);
+ base::StringToInt(inode_output, &pid_);
}
}
CHECK(pid_ > 0) << "Did not find zygote process (using sandbox binary "
@@ -243,6 +234,8 @@ pid_t ZygoteHost::ForkRenderer(
if (ReadReply(&pid, sizeof(pid)) != sizeof(pid))
return base::kNullProcessHandle;
+ if (pid <= 0)
+ return base::kNullProcessHandle;
}
// 1) You can't change the oom_adj of a non-dumpable process (EPERM) unless
@@ -285,8 +278,8 @@ pid_t ZygoteHost::ForkRenderer(
adj_oom_score_cmdline.push_back(sandbox_binary_);
adj_oom_score_cmdline.push_back(base::kAdjustOOMScoreSwitch);
- adj_oom_score_cmdline.push_back(Int64ToString(pid));
- adj_oom_score_cmdline.push_back(IntToString(kRendererScore));
+ adj_oom_score_cmdline.push_back(base::Int64ToString(pid));
+ adj_oom_score_cmdline.push_back(base::IntToString(kRendererScore));
CommandLine adj_oom_score_cmd(adj_oom_score_cmdline);
if (base::LaunchApp(adj_oom_score_cmdline, dummy_map, false,
&sandbox_helper_process)) {
diff --git a/chrome/browser/zygote_host_linux.h b/chrome/browser/zygote_host_linux.h
index 545df8d..dd00336 100644
--- a/chrome/browser/zygote_host_linux.h
+++ b/chrome/browser/zygote_host_linux.h
@@ -4,6 +4,7 @@
#ifndef CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
#define CHROME_BROWSER_ZYGOTE_HOST_LINUX_H_
+#pragma once
#include <unistd.h>
diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc
index 51a658e..65a44ae 100644
--- a/chrome/browser/zygote_main_linux.cc
+++ b/chrome/browser/zygote_main_linux.cc
@@ -1,9 +1,10 @@
-// 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.
#include <dlfcn.h>
#include <fcntl.h>
+#include <pthread.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
#include <sys/signal.h>
@@ -21,11 +22,13 @@
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
#include "base/global_descriptors_posix.h"
#include "base/hash_tables.h"
#include "base/linux_util.h"
#include "base/path_service.h"
#include "base/pickle.h"
+#include "base/process_util.h"
#include "base/rand_util.h"
#include "base/scoped_ptr.h"
#include "base/sys_info.h"
@@ -36,6 +39,7 @@
#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/main_function_params.h"
+#include "chrome/common/pepper_plugin_registry.h"
#include "chrome/common/process_watcher.h"
#include "chrome/common/sandbox_methods_linux.h"
@@ -43,13 +47,14 @@
#include "skia/ext/SkFontHost_fontconfig_control.h"
-#include "sandbox/linux/seccomp/sandbox.h"
+#include "seccompsandbox/sandbox.h"
#include "unicode/timezone.h"
-#if defined(ARCH_CPU_X86_FAMILY) && !defined(CHROMIUM_SELINUX)
+#if defined(ARCH_CPU_X86_FAMILY) && !defined(CHROMIUM_SELINUX) && \
+ !defined(__clang__)
// The seccomp sandbox is enabled on all ia32 and x86-64 processor as long as
-// we aren't using SELinux.
+// we aren't using SELinux or clang.
#define SECCOMP_SANDBOX
#endif
@@ -136,17 +141,18 @@ class Zygote {
static const unsigned kMaxMessageLength = 1024;
char buf[kMaxMessageLength];
const ssize_t len = base::RecvMsg(fd, buf, sizeof(buf), &fds);
- if (len == -1) {
- LOG(WARNING) << "Error reading message from browser: " << errno;
- return false;
- }
- if (len == 0) {
+ if (len == 0 || (len == -1 && errno == ECONNRESET)) {
// EOF from the browser. We should die.
_exit(0);
return false;
}
+ if (len == -1) {
+ PLOG(ERROR) << "Error reading message from browser";
+ return false;
+ }
+
Pickle pickle(buf, len);
void* iter = NULL;
@@ -229,6 +235,101 @@ class Zygote {
}
}
+ // This is equivalent to fork(), except that, when using the SUID
+ // sandbox, it returns the real PID of the child process as it
+ // appears outside the sandbox, rather than returning the PID inside
+ // the sandbox.
+ int ForkWithRealPid() {
+ if (!g_suid_sandbox_active)
+ return fork();
+
+ int dummy_fd;
+ ino_t dummy_inode;
+ int pipe_fds[2] = { -1, -1 };
+ base::ProcessId pid = 0;
+
+ dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (dummy_fd < 0) {
+ LOG(ERROR) << "Failed to create dummy FD";
+ goto error;
+ }
+ if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) {
+ LOG(ERROR) << "Failed to get inode for dummy FD";
+ goto error;
+ }
+ if (pipe(pipe_fds) != 0) {
+ LOG(ERROR) << "Failed to create pipe";
+ goto error;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ goto error;
+ } else if (pid == 0) {
+ // In the child process.
+ close(pipe_fds[1]);
+ char buffer[1];
+ // Wait until the parent process has discovered our PID. We
+ // should not fork any child processes (which the seccomp
+ // sandbox does) until then, because that can interfere with the
+ // parent's discovery of our PID.
+ if (HANDLE_EINTR(read(pipe_fds[0], buffer, 1)) != 1 ||
+ buffer[0] != 'x') {
+ LOG(FATAL) << "Failed to synchronise with parent zygote process";
+ }
+ close(pipe_fds[0]);
+ close(dummy_fd);
+ return 0;
+ } else {
+ // In the parent process.
+ close(dummy_fd);
+ dummy_fd = -1;
+ close(pipe_fds[0]);
+ pipe_fds[0] = -1;
+ uint8_t reply_buf[512];
+ Pickle request;
+ 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);
+ if (r == -1) {
+ LOG(ERROR) << "Failed to get child process's real PID";
+ goto error;
+ }
+
+ base::ProcessId real_pid;
+ Pickle reply(reinterpret_cast<char*>(reply_buf), r);
+ void* iter2 = NULL;
+ if (!reply.ReadInt(&iter2, &real_pid))
+ goto error;
+ if (real_pid <= 0) {
+ // METHOD_GET_CHILD_WITH_INODE failed. Did the child die already?
+ LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed";
+ goto error;
+ }
+ real_pids_to_sandbox_pids[real_pid] = pid;
+ if (HANDLE_EINTR(write(pipe_fds[1], "x", 1)) != 1) {
+ LOG(ERROR) << "Failed to synchronise with child process";
+ goto error;
+ }
+ close(pipe_fds[1]);
+ return real_pid;
+ }
+
+ error:
+ if (pid > 0)
+ waitpid(pid, NULL, WNOHANG);
+ if (dummy_fd >= 0)
+ close(dummy_fd);
+ if (pipe_fds[0] >= 0)
+ close(pipe_fds[0]);
+ if (pipe_fds[1] >= 0)
+ close(pipe_fds[1]);
+ return -1;
+ }
+
// Handle a 'fork' request from the browser: this means that the browser
// wishes to start a new renderer.
bool HandleForkRequest(int fd, const Pickle& pickle, void* iter,
@@ -237,8 +338,6 @@ class Zygote {
int argc, numfds;
base::GlobalDescriptors::Mapping mapping;
base::ProcessId child;
- uint64_t dummy_inode = 0;
- int dummy_fd = -1;
if (!pickle.ReadInt(&iter, &argc))
goto error;
@@ -265,16 +364,7 @@ class Zygote {
mapping.push_back(std::make_pair(
static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
- if (g_suid_sandbox_active) {
- dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (dummy_fd < 0)
- goto error;
-
- if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd))
- goto error;
- }
-
- child = fork();
+ child = ForkWithRealPid();
if (!child) {
#if defined(SECCOMP_SANDBOX)
@@ -310,47 +400,19 @@ class Zygote {
goto error;
}
- {
- base::ProcessId proc_id;
- if (g_suid_sandbox_active) {
- close(dummy_fd);
- dummy_fd = -1;
- uint8_t reply_buf[512];
- Pickle request;
- 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);
- if (r == -1)
- goto error;
-
- Pickle reply(reinterpret_cast<char*>(reply_buf), r);
- void* iter2 = NULL;
- if (!reply.ReadInt(&iter2, &proc_id))
- goto error;
- real_pids_to_sandbox_pids[proc_id] = child;
- } else {
- proc_id = child;
- }
-
- for (std::vector<int>::const_iterator
- i = fds.begin(); i != fds.end(); ++i)
- close(*i);
+ for (std::vector<int>::const_iterator
+ i = fds.begin(); i != fds.end(); ++i)
+ close(*i);
- if (HANDLE_EINTR(write(fd, &proc_id, sizeof(proc_id))) < 0)
- PLOG(ERROR) << "write";
- return false;
- }
+ if (HANDLE_EINTR(write(fd, &child, sizeof(child))) < 0)
+ PLOG(ERROR) << "write";
+ return false;
error:
LOG(ERROR) << "Error parsing fork request from browser";
for (std::vector<int>::const_iterator
i = fds.begin(); i != fds.end(); ++i)
close(*i);
- if (dummy_fd >= 0)
- close(dummy_fd);
return false;
}
@@ -451,7 +513,37 @@ static bool g_am_zygote_or_renderer = false;
// We also considered patching the function in place, but this would again by
// platform specific and the above technique seems to work well enough.
-static void WarnOnceAboutBrokenDlsym();
+typedef struct tm* (*LocaltimeFunction)(const time_t* timep);
+typedef struct tm* (*LocaltimeRFunction)(const time_t* timep,
+ struct tm* result);
+
+static pthread_once_t g_libc_localtime_funcs_guard = PTHREAD_ONCE_INIT;
+static LocaltimeFunction g_libc_localtime;
+static LocaltimeRFunction g_libc_localtime_r;
+
+static void InitLibcLocaltimeFunctions() {
+ g_libc_localtime = reinterpret_cast<LocaltimeFunction>(
+ dlsym(RTLD_NEXT, "localtime"));
+ g_libc_localtime_r = reinterpret_cast<LocaltimeRFunction>(
+ dlsym(RTLD_NEXT, "localtime_r"));
+
+ if (!g_libc_localtime || !g_libc_localtime_r) {
+ // http://code.google.com/p/chromium/issues/detail?id=16800
+ //
+ // Nvidia's libGL.so overrides dlsym for an unknown reason and replaces
+ // it with a version which doesn't work. In this case we'll get a NULL
+ // result. There's not a lot we can do at this point, so we just bodge it!
+ LOG(ERROR) << "Your system is broken: dlsym doesn't work! This has been "
+ "reported to be caused by Nvidia's libGL. You should expect"
+ " time related functions to misbehave. "
+ "http://code.google.com/p/chromium/issues/detail?id=16800";
+ }
+
+ if (!g_libc_localtime)
+ g_libc_localtime = gmtime;
+ if (!g_libc_localtime_r)
+ g_libc_localtime_r = gmtime_r;
+}
struct tm* localtime(const time_t* timep) {
if (g_am_zygote_or_renderer) {
@@ -461,26 +553,9 @@ struct tm* localtime(const time_t* timep) {
sizeof(timezone_string));
return &time_struct;
} else {
- typedef struct tm* (*LocaltimeFunction)(const time_t* timep);
- static LocaltimeFunction libc_localtime;
- static bool have_libc_localtime = false;
- if (!have_libc_localtime) {
- libc_localtime = (LocaltimeFunction) dlsym(RTLD_NEXT, "localtime");
- have_libc_localtime = true;
- }
-
- if (!libc_localtime) {
- // http://code.google.com/p/chromium/issues/detail?id=16800
- //
- // Nvidia's libGL.so overrides dlsym for an unknown reason and replaces
- // it with a version which doesn't work. In this case we'll get a NULL
- // result. There's not a lot we can do at this point, so we just bodge it!
- WarnOnceAboutBrokenDlsym();
-
- return gmtime(timep);
- }
-
- return libc_localtime(timep);
+ CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard,
+ InitLibcLocaltimeFunctions));
+ return g_libc_localtime(timep);
}
}
@@ -489,37 +564,12 @@ struct tm* localtime_r(const time_t* timep, struct tm* result) {
ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0);
return result;
} else {
- typedef struct tm* (*LocaltimeRFunction)(const time_t* timep,
- struct tm* result);
- static LocaltimeRFunction libc_localtime_r;
- static bool have_libc_localtime_r = false;
- if (!have_libc_localtime_r) {
- libc_localtime_r = (LocaltimeRFunction) dlsym(RTLD_NEXT, "localtime_r");
- have_libc_localtime_r = true;
- }
-
- if (!libc_localtime_r) {
- // See |localtime|, above.
- WarnOnceAboutBrokenDlsym();
-
- return gmtime_r(timep, result);
- }
-
- return libc_localtime_r(timep, result);
+ CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard,
+ InitLibcLocaltimeFunctions));
+ return g_libc_localtime_r(timep, result);
}
}
-// See the comments at the callsite in |localtime| about this function.
-static void WarnOnceAboutBrokenDlsym() {
- static bool have_shown_warning = false;
- if (!have_shown_warning) {
- LOG(ERROR) << "Your system is broken: dlsym doesn't work! This has been "
- "reported to be caused by Nvidia's libGL. You should expect "
- "time related functions to misbehave. "
- "http://code.google.com/p/chromium/issues/detail?id=16800";
- have_shown_warning = true;
- }
-}
#endif // !CHROMIUM_SELINUX
// This function triggers the static and lazy construction of objects that need
@@ -546,6 +596,9 @@ static void PreSandboxInit() {
FilePath module_path;
if (PathService::Get(base::DIR_MODULE, &module_path))
media::InitializeMediaLibrary(module_path);
+
+ // Ensure access to the Pepper plugins before the sandbox is turned on.
+ PepperPluginRegistry::PreloadModules();
}
#if !defined(CHROMIUM_SELINUX)
@@ -555,10 +608,9 @@ static bool EnterSandbox() {
// chrooted.
const char* const sandbox_fd_string = getenv("SBX_D");
- if (switches::SeccompSandboxEnabled()) {
- PreSandboxInit();
- SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor);
- } else if (sandbox_fd_string) { // Use the SUID sandbox.
+ if (sandbox_fd_string) {
+ // Use the SUID sandbox. This still allows the seccomp sandbox to
+ // be enabled by the process later.
g_suid_sandbox_active = true;
char* endptr;
@@ -618,6 +670,9 @@ static bool EnterSandbox() {
return false;
}
}
+ } else if (switches::SeccompSandboxEnabled()) {
+ PreSandboxInit();
+ SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor);
} else {
SkiaFontConfigUseDirectImplementation();
}
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index 2f3b9b0..93d6fc0 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -4,6 +4,7 @@ include_rules = [
"+grit", # For generated headers
"+libxml",
"+media/audio",
+ "+media/base",
"+remoting/client/plugin",
"+sandbox/src",
"+skia/include",
@@ -17,6 +18,5 @@ include_rules = [
"+third_party/zlib",
# FIXME - refactor code and remove these dependencies
- "+chrome/app",
"+chrome/installer",
]
diff --git a/chrome/common/about_handler.cc b/chrome/common/about_handler.cc
index 84658a0..d2121b8 100644
--- a/chrome/common/about_handler.cc
+++ b/chrome/common/about_handler.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "chrome/common/about_handler.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
namespace chrome_about_handler {
diff --git a/chrome/common/about_handler.h b/chrome/common/about_handler.h
index f5d0818..49b16ad 100644
--- a/chrome/common/about_handler.h
+++ b/chrome/common/about_handler.h
@@ -4,9 +4,11 @@
#ifndef CHROME_COMMON_ABOUT_HANDLER_H__
#define CHROME_COMMON_ABOUT_HANDLER_H__
+#pragma once
-#include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
+#include <stddef.h>
+
+class GURL;
namespace chrome_about_handler {
diff --git a/chrome/common/app_mode_common_mac.h b/chrome/common/app_mode_common_mac.h
index 046324a..130fe8a 100644
--- a/chrome/common/app_mode_common_mac.h
+++ b/chrome/common/app_mode_common_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_APP_MODE_COMMON_MAC_H_
#define CHROME_COMMON_APP_MODE_COMMON_MAC_H_
+#pragma once
#include <CoreFoundation/CoreFoundation.h>
diff --git a/chrome/common/appcache/appcache_backend_proxy.cc b/chrome/common/appcache/appcache_backend_proxy.cc
index e1776db..16e0ff4 100644
--- a/chrome/common/appcache/appcache_backend_proxy.cc
+++ b/chrome/common/appcache/appcache_backend_proxy.cc
@@ -63,3 +63,8 @@ bool AppCacheBackendProxy::SwapCache(int host_id) {
sender_->Send(new AppCacheMsg_SwapCache(host_id, &result));
return result;
}
+
+void AppCacheBackendProxy::GetResourceList(
+ int host_id, std::vector<appcache::AppCacheResourceInfo>* resource_infos) {
+ sender_->Send(new AppCacheMsg_GetResourceList(host_id, resource_infos));
+}
diff --git a/chrome/common/appcache/appcache_backend_proxy.h b/chrome/common/appcache/appcache_backend_proxy.h
index 2ef2660..8d9de2b 100644
--- a/chrome/common/appcache/appcache_backend_proxy.h
+++ b/chrome/common/appcache/appcache_backend_proxy.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_APPCACHE_APPCACHE_BACKEND_PROXY_H_
#define CHROME_COMMON_APPCACHE_APPCACHE_BACKEND_PROXY_H_
+#pragma once
#include "ipc/ipc_message.h"
#include "webkit/appcache/appcache_interfaces.h"
@@ -35,6 +36,9 @@ class AppCacheBackendProxy : public appcache::AppCacheBackend {
virtual appcache::Status GetStatus(int host_id);
virtual bool StartUpdate(int host_id);
virtual bool SwapCache(int host_id);
+ virtual void GetResourceList(
+ int host_id,
+ std::vector<appcache::AppCacheResourceInfo>* resource_infos);
private:
IPC::Message::Sender* sender_;
diff --git a/chrome/common/appcache/appcache_dispatcher.cc b/chrome/common/appcache/appcache_dispatcher.cc
index 6cf40cc..b32b48e 100644
--- a/chrome/common/appcache/appcache_dispatcher.cc
+++ b/chrome/common/appcache/appcache_dispatcher.cc
@@ -22,9 +22,9 @@ bool AppCacheDispatcher::OnMessageReceived(const IPC::Message& msg) {
return handled;
}
-void AppCacheDispatcher::OnCacheSelected(int host_id, int64 cache_id,
- appcache::Status status) {
- frontend_impl_.OnCacheSelected(host_id, cache_id, status);
+void AppCacheDispatcher::OnCacheSelected(
+ int host_id, const appcache::AppCacheInfo& info) {
+ frontend_impl_.OnCacheSelected(host_id, info);
}
void AppCacheDispatcher::OnStatusChanged(const std::vector<int>& host_ids,
diff --git a/chrome/common/appcache/appcache_dispatcher.h b/chrome/common/appcache/appcache_dispatcher.h
index d21be54..f099183 100644
--- a/chrome/common/appcache/appcache_dispatcher.h
+++ b/chrome/common/appcache/appcache_dispatcher.h
@@ -4,7 +4,9 @@
#ifndef CHROME_COMMON_APPCACHE_APPCACHE_DISPATCHER_H_
#define CHROME_COMMON_APPCACHE_APPCACHE_DISPATCHER_H_
+#pragma once
+#include <string>
#include <vector>
#include "chrome/common/appcache/appcache_backend_proxy.h"
#include "ipc/ipc_message.h"
@@ -25,8 +27,7 @@ class AppCacheDispatcher {
private:
// Ipc message handlers
- void OnCacheSelected(int host_id, int64 cache_id,
- appcache::Status status);
+ void OnCacheSelected(int host_id, const appcache::AppCacheInfo& info);
void OnStatusChanged(const std::vector<int>& host_ids,
appcache::Status status);
void OnEventRaised(const std::vector<int>& host_ids,
diff --git a/chrome/common/automation_constants.cc b/chrome/common/automation_constants.cc
index 185d57b..c253871 100644
--- a/chrome/common/automation_constants.cc
+++ b/chrome/common/automation_constants.cc
@@ -7,9 +7,9 @@
namespace automation {
// JSON value labels for proxy settings that are passed in via
// AutomationMsg_SetProxyConfig.
-const wchar_t kJSONProxyAutoconfig[] = L"proxy.autoconfig";
-const wchar_t kJSONProxyNoProxy[] = L"proxy.no_proxy";
-const wchar_t kJSONProxyPacUrl[] = L"proxy.pac_url";
-const wchar_t kJSONProxyBypassList[] = L"proxy.bypass_list";
-const wchar_t kJSONProxyServer[] = L"proxy.server";
+const char kJSONProxyAutoconfig[] = "proxy.autoconfig";
+const char kJSONProxyNoProxy[] = "proxy.no_proxy";
+const char kJSONProxyPacUrl[] = "proxy.pac_url";
+const char kJSONProxyBypassList[] = "proxy.bypass_list";
+const char kJSONProxyServer[] = "proxy.server";
}
diff --git a/chrome/common/automation_constants.h b/chrome/common/automation_constants.h
index 9c31bd1..6959af7 100644
--- a/chrome/common/automation_constants.h
+++ b/chrome/common/automation_constants.h
@@ -4,16 +4,17 @@
#ifndef CHROME_COMMON_AUTOMATION_CONSTANTS_H__
#define CHROME_COMMON_AUTOMATION_CONSTANTS_H__
+#pragma once
namespace automation {
// JSON value labels for proxy settings that are passed in via
// AutomationMsg_SetProxyConfig. These are here since they are used by both
// AutomationProvider and AutomationProxy.
-extern const wchar_t kJSONProxyAutoconfig[];
-extern const wchar_t kJSONProxyNoProxy[];
-extern const wchar_t kJSONProxyPacUrl[];
-extern const wchar_t kJSONProxyBypassList[];
-extern const wchar_t kJSONProxyServer[];
+extern const char kJSONProxyAutoconfig[];
+extern const char kJSONProxyNoProxy[];
+extern const char kJSONProxyPacUrl[];
+extern const char kJSONProxyBypassList[];
+extern const char kJSONProxyServer[];
}
#endif // CHROME_COMMON_AUTOMATION_CONSTANTS_H__
diff --git a/chrome/common/bindings_policy.h b/chrome/common/bindings_policy.h
index eccce17..0df8371 100644
--- a/chrome/common/bindings_policy.h
+++ b/chrome/common/bindings_policy.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_BINDINGS_POLICY_H__
#define CHROME_COMMON_BINDINGS_POLICY_H__
+#pragma once
// This is a utility class that specifies flag values for the types of
// JavaScript bindings exposed to renderers.
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc
index 328ca14..dd6fd40 100644
--- a/chrome/common/child_process.cc
+++ b/chrome/common/child_process.cc
@@ -1,19 +1,22 @@
-// 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/common/child_process.h"
-#include "app/l10n_util.h"
+#if defined(OS_POSIX)
+#include <signal.h> // For SigUSR1Handler below.
+#endif
+
#include "base/message_loop.h"
#include "base/process_util.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "chrome/common/child_thread.h"
#include "grit/chromium_strings.h"
#if defined(OS_POSIX)
-#include <signal.h>
-
static void SigUSR1Handler(int signal) { }
#endif
@@ -45,6 +48,14 @@ ChildProcess::~ChildProcess() {
child_process_ = NULL;
}
+ChildThread* ChildProcess::main_thread() {
+ return main_thread_.get();
+}
+
+void ChildProcess::set_main_thread(ChildThread* thread) {
+ main_thread_.reset(thread);
+}
+
void ChildProcess::AddRefProcess() {
DCHECK(!main_thread_.get() || // null in unittests.
MessageLoop::current() == main_thread_->message_loop());
@@ -70,28 +81,32 @@ base::WaitableEvent* ChildProcess::GetShutDownEvent() {
void ChildProcess::WaitForDebugger(const std::wstring& label) {
#if defined(OS_WIN)
- std::wstring title = l10n_util::GetString(IDS_PRODUCT_NAME);
- std::wstring message = label;
- message += L" starting with pid: ";
- message += IntToWString(base::GetCurrentProcId());
- title += L" ";
- title += label; // makes attaching to process easier
- ::MessageBox(NULL, message.c_str(), title.c_str(),
- MB_OK | MB_SETFOREGROUND);
+#if defined(GOOGLE_CHROME_BUILD)
+ std::wstring title = L"Google Chrome";
+#else // CHROMIUM_BUILD
+ std::wstring title = L"Chromium";
+#endif // CHROMIUM_BUILD
+ title += L" ";
+ title += label; // makes attaching to process easier
+ std::wstring message = label;
+ message += L" starting with pid: ";
+ message += UTF8ToWide(base::IntToString(base::GetCurrentProcId()));
+ ::MessageBox(NULL, message.c_str(), title.c_str(),
+ MB_OK | MB_SETFOREGROUND);
#elif defined(OS_POSIX)
- // 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";
- // Install a signal handler so that pause can be woken.
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SigUSR1Handler;
- sigaction(SIGUSR1, &sa, NULL);
-
- pause();
+ // 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";
+ // Install a signal handler so that pause can be woken.
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SigUSR1Handler;
+ sigaction(SIGUSR1, &sa, NULL);
+
+ pause();
#endif // defined(OS_POSIX)
}
diff --git a/chrome/common/child_process.h b/chrome/common/child_process.h
index fb2c660..bc878de 100644
--- a/chrome/common/child_process.h
+++ b/chrome/common/child_process.h
@@ -4,12 +4,14 @@
#ifndef CHROME_COMMON_CHILD_PROCESS_H__
#define CHROME_COMMON_CHILD_PROCESS_H__
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/thread.h"
#include "base/waitable_event.h"
-#include "chrome/common/child_thread.h"
+
+class ChildThread;
// Base class for child processes of the browser process (i.e. renderer and
// plugin host). This is a singleton object for each child process.
@@ -20,8 +22,8 @@ class ChildProcess {
virtual ~ChildProcess();
// Getter for the child process' main thread.
- ChildThread* main_thread() { return main_thread_.get(); }
- void set_main_thread(ChildThread* thread) { main_thread_.reset(thread); }
+ ChildThread* main_thread();
+ void set_main_thread(ChildThread* thread);
MessageLoop* io_message_loop() { return io_thread_.message_loop(); }
diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc
index bcd0c3d..9626976 100644
--- a/chrome/common/child_process_host.cc
+++ b/chrome/common/child_process_host.cc
@@ -12,6 +12,8 @@
#include "chrome/common/chrome_paths_internal.h"
#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"
diff --git a/chrome/common/child_process_host.h b/chrome/common/child_process_host.h
index 865a1ac..8eb050b 100644
--- a/chrome/common/child_process_host.h
+++ b/chrome/common/child_process_host.h
@@ -4,26 +4,27 @@
#ifndef CHROME_COMMON_CHILD_PROCESS_HOST_H_
#define CHROME_COMMON_CHILD_PROCESS_HOST_H_
+#pragma once
-#include <list>
#include <string>
-// Must be included early (e.g. before chrome/common/plugin_messages.h)
-#include "ipc/ipc_logging.h"
+#include "build/build_config.h"
-// Putting this before ipc_logging.h does not work (OS_WIN isn't defined)
#if defined(OS_WIN)
#include <windows.h>
#endif // defined(OS_WIN)
#include "base/basictypes.h"
-#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "chrome/common/notification_type.h"
#include "ipc/ipc_channel.h"
-
class CommandLine;
+class FilePath;
+
+namespace IPC {
+class Message;
+}
// Provides common functionality for hosting a child process and processing IPC
// messages between the host and the child process. Subclasses are responsible
@@ -117,7 +118,8 @@ class ChildProcessHost : public IPC::Channel::Listener {
bool opening_channel_; // True while we're waiting the channel to be opened.
scoped_ptr<IPC::Channel> channel_;
std::string channel_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildProcessHost);
};
#endif // CHROME_COMMON_CHILD_PROCESS_HOST_H_
-
diff --git a/chrome/common/child_process_info.cc b/chrome/common/child_process_info.cc
index f08cb55..a94b89d 100644
--- a/chrome/common/child_process_info.cc
+++ b/chrome/common/child_process_info.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.
@@ -13,6 +13,7 @@
#include "base/process_util.h"
#include "base/rand_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "grit/generated_resources.h"
ChildProcessInfo::ChildProcessInfo(const ChildProcessInfo& original)
@@ -38,42 +39,42 @@ ChildProcessInfo& ChildProcessInfo::operator=(
return *this;
}
-std::wstring ChildProcessInfo::GetTypeNameInEnglish(
+std::string ChildProcessInfo::GetTypeNameInEnglish(
ChildProcessInfo::ProcessType type) {
switch (type) {
case BROWSER_PROCESS:
- return L"Browser";
+ return "Browser";
case RENDER_PROCESS:
- return L"Tab";
+ return "Tab";
case PLUGIN_PROCESS:
- return L"Plug-in";
+ return "Plug-in";
case WORKER_PROCESS:
- return L"Web Worker";
+ return "Web Worker";
case UTILITY_PROCESS:
- return L"Utility";
+ return "Utility";
case PROFILE_IMPORT_PROCESS:
- return L"Profile Import helper";
+ return "Profile Import helper";
case ZYGOTE_PROCESS:
- return L"Zygote";
+ return "Zygote";
case SANDBOX_HELPER_PROCESS:
- return L"Sandbox helper";
+ return "Sandbox helper";
case NACL_LOADER_PROCESS:
- return L"Native Client module";
+ return "Native Client module";
case NACL_BROKER_PROCESS:
- return L"Native Client broker";
+ return "Native Client broker";
case GPU_PROCESS:
- return L"GPU";
+ return "GPU";
case UNKNOWN_PROCESS:
- default:
+ default:
DCHECK(false) << "Unknown child process type!";
- return L"Unknown";
- }
+ return "Unknown";
+ }
}
-std::wstring ChildProcessInfo::GetLocalizedTitle() const {
- std::wstring title = name_;
+string16 ChildProcessInfo::GetLocalizedTitle() const {
+ string16 title = WideToUTF16Hack(name_);
if (type_ == ChildProcessInfo::PLUGIN_PROCESS && title.empty())
- title = l10n_util::GetString(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME);
+ title = l10n_util::GetStringUTF16(IDS_TASK_MANAGER_UNKNOWN_PLUGIN_NAME);
// Explicitly mark name as LTR if there is no strong RTL character,
// to avoid the wrong concatenation result similar to "!Yahoo! Mail: the
@@ -84,7 +85,8 @@ std::wstring ChildProcessInfo::GetLocalizedTitle() const {
int message_id;
if (type_ == ChildProcessInfo::PLUGIN_PROCESS) {
message_id = IDS_TASK_MANAGER_PLUGIN_PREFIX;
- return l10n_util::GetStringF(message_id, title, version_.c_str());
+ return l10n_util::GetStringFUTF16(message_id, title,
+ WideToUTF16Hack(version_.c_str()));
} else if (type_ == ChildProcessInfo::WORKER_PROCESS) {
message_id = IDS_TASK_MANAGER_WORKER_PREFIX;
} else if (type_ == ChildProcessInfo::UTILITY_PROCESS) {
@@ -95,12 +97,14 @@ std::wstring ChildProcessInfo::GetLocalizedTitle() const {
message_id = IDS_TASK_MANAGER_NACL_PREFIX;
} else if (type_ == ChildProcessInfo::NACL_BROKER_PROCESS) {
message_id = IDS_TASK_MANAGER_NACL_BROKER_PREFIX;
+ } else if (type_ == ChildProcessInfo::GPU_PROCESS) {
+ message_id = IDS_TASK_MANAGER_GPU_PREFIX;
} else {
DCHECK(false) << "Need localized name for child process type.";
return title;
}
- return l10n_util::GetStringF(message_id, title);
+ return l10n_util::GetStringFUTF16(message_id, title);
}
ChildProcessInfo::ChildProcessInfo(ProcessType type, int id) : type_(type) {
diff --git a/chrome/common/child_process_info.h b/chrome/common/child_process_info.h
index bc36c18..78b0a2a 100644
--- a/chrome/common/child_process_info.h
+++ b/chrome/common/child_process_info.h
@@ -1,13 +1,15 @@
-// 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.
#ifndef CHROME_COMMON_CHILD_PROCESS_INFO_H_
#define CHROME_COMMON_CHILD_PROCESS_INFO_H_
+#pragma once
#include <string>
#include "base/process.h"
+#include "base/string16.h"
// Holds information about a child process.
class ChildProcessInfo {
@@ -57,11 +59,11 @@ class ChildProcessInfo {
// Returns an English name of the process type, should only be used for non
// user-visible strings, or debugging pages like about:memory.
- static std::wstring GetTypeNameInEnglish(ProcessType type);
+ static std::string GetTypeNameInEnglish(ProcessType type);
// Returns a localized title for the child process. For example, a plugin
// process would be "Plug-in: Flash" when name is "Flash".
- std::wstring GetLocalizedTitle() const;
+ string16 GetLocalizedTitle() const;
// We define the < operator so that the ChildProcessInfo can be used as a key
// in a std::map.
diff --git a/chrome/common/child_process_logging.h b/chrome/common/child_process_logging.h
index 84a288c..bcc5ecd 100644
--- a/chrome/common/child_process_logging.h
+++ b/chrome/common/child_process_logging.h
@@ -4,14 +4,16 @@
#ifndef CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
#define CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
+#pragma once
#include <set>
#include <string>
#include "base/basictypes.h"
-#include "chrome/common/gpu_info.h"
#include "googleurl/src/gurl.h"
+class GPUInfo;
+
#if defined(OS_WIN)
// The maximum number of active extensions we will report.
// Also used in chrome/app, but we define it here to avoid a common->app
@@ -21,6 +23,13 @@ static const int kMaxReportedActiveExtensions = 10;
namespace child_process_logging {
+#if defined(OS_LINUX)
+// These are declared here so the crash reporter can access them directly in
+// compromised context without going through the standard library.
+extern char g_active_url[];
+extern char g_client_id[];
+#endif
+
// Sets the URL that is logged if the child process crashes. Use GURL() to clear
// the URL.
void SetActiveURL(const GURL& url);
@@ -28,6 +37,10 @@ void SetActiveURL(const GURL& url);
// Sets the Client ID that is used as GUID if a Chrome process crashes.
void SetClientId(const std::string& client_id);
+// Gets the Client ID to be used as GUID for crash reporting. Returns the client
+// id in |client_id| if it's known, an empty string otherwise.
+std::string GetClientId();
+
// Sets the list of "active" extensions in this process. We overload "active" to
// mean different things depending on the process type:
// - browser: all enabled extensions
@@ -36,6 +49,9 @@ void SetClientId(const std::string& client_id);
// multiple because of process collapsing).
void SetActiveExtensions(const std::set<std::string>& extension_ids);
+// Sets a number of views/tabs opened in this process.
+void SetNumberOfViews(int number_of_views);
+
// Sets the data on the gpu to send along with crash reports.
void SetGpuInfo(const GPUInfo& gpu_info);
diff --git a/chrome/common/child_process_logging_linux.cc b/chrome/common/child_process_logging_linux.cc
index 94cb34b..e81fcc3 100644
--- a/chrome/common/child_process_logging_linux.cc
+++ b/chrome/common/child_process_logging_linux.cc
@@ -4,20 +4,28 @@
#include "chrome/common/child_process_logging.h"
-#include "base/logging.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/common/gpu_info.h"
#include "chrome/installer/util/google_update_settings.h"
#include "googleurl/src/gurl.h"
namespace child_process_logging {
-// We use a static string to hold the most recent active url. If we crash, the
-// crash handler code will send the contents of this string to the browser.
-std::string active_url;
+// Account for the terminating null character.
+static const size_t kMaxActiveURLSize = 1024 + 1;
+static const size_t kClientIdSize = 32 + 1;
+
+// We use static strings to hold the most recent active url and the client
+// identifier. If we crash, the crash handler code will send the contents of
+// these strings to the browser.
+char g_active_url[kMaxActiveURLSize];
+char g_client_id[kClientIdSize];
void SetActiveURL(const GURL& url) {
- active_url = url.possibly_invalid_spec();
+ base::strlcpy(g_active_url,
+ url.possibly_invalid_spec().c_str(),
+ kMaxActiveURLSize);
}
void SetClientId(const std::string& client_id) {
@@ -27,10 +35,15 @@ void SetClientId(const std::string& client_id) {
if (str.empty())
return;
+ base::strlcpy(g_client_id, str.c_str(), kClientIdSize);
std::wstring wstr = ASCIIToWide(str);
GoogleUpdateSettings::SetMetricsId(wstr);
}
+std::string GetClientId() {
+ return std::string(g_client_id);
+}
+
void SetActiveExtensions(const std::set<std::string>& extension_ids) {
// TODO(port)
}
@@ -39,4 +52,8 @@ void SetGpuInfo(const GPUInfo& gpu_info) {
// TODO(rlp): Bug 38737.
}
+void SetNumberOfViews(int number_of_views) {
+ // TODO(port)
+}
+
} // namespace child_process_logging
diff --git a/chrome/common/child_process_logging_mac.mm b/chrome/common/child_process_logging_mac.mm
index f0356cd..62cb122 100644
--- a/chrome/common/child_process_logging_mac.mm
+++ b/chrome/common/child_process_logging_mac.mm
@@ -6,7 +6,9 @@
#import <Foundation/Foundation.h>
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/common/gpu_info.h"
#include "chrome/installer/util/google_update_settings.h"
#include "googleurl/src/gurl.h"
@@ -22,10 +24,15 @@ const char *kGPUDeviceIdParamName = "devid";
const char *kGPUDriverVersionParamName = "driver";
const char *kGPUPixelShaderVersionParamName = "psver";
const char *kGPUVertexShaderVersionParamName = "vsver";
+const char *kNumberOfViews = "num-views";
static SetCrashKeyValueFuncPtr g_set_key_func;
static ClearCrashKeyValueFuncPtr g_clear_key_func;
+// Account for the terminating null character.
+static const size_t kClientIdSize = 32 + 1;
+static char g_client_id[kClientIdSize];
+
void SetCrashKeyFunctions(SetCrashKeyValueFuncPtr set_key_func,
ClearCrashKeyValueFuncPtr clear_key_func) {
g_set_key_func = set_key_func;
@@ -91,6 +98,7 @@ void SetClientId(const std::string& client_id) {
std::string str(client_id);
ReplaceSubstringsAfterOffset(&str, 0, "-", "");
+ base::strlcpy(g_client_id, str.c_str(), kClientIdSize);
if (g_set_key_func)
SetClientIdImpl(str, g_set_key_func);
@@ -98,6 +106,10 @@ void SetClientId(const std::string& client_id) {
GoogleUpdateSettings::SetMetricsId(wstr);
}
+std::string GetClientId() {
+ return std::string(g_client_id);
+}
+
void SetActiveExtensions(const std::set<std::string>& extension_ids) {
// TODO(port)
}
@@ -112,19 +124,19 @@ void SetGpuKeyValue(const char* param_name, const std::string& value_str,
void SetGpuInfoImpl(const GPUInfo& gpu_info,
SetCrashKeyValueFuncPtr set_key_func) {
SetGpuKeyValue(kGPUVendorIdParamName,
- UintToString(gpu_info.vendor_id()),
+ base::UintToString(gpu_info.vendor_id()),
set_key_func);
SetGpuKeyValue(kGPUDeviceIdParamName,
- UintToString(gpu_info.device_id()),
+ base::UintToString(gpu_info.device_id()),
set_key_func);
SetGpuKeyValue(kGPUDriverVersionParamName,
- WideToASCII(gpu_info.driver_version()),
+ WideToUTF8(gpu_info.driver_version()),
set_key_func);
SetGpuKeyValue(kGPUPixelShaderVersionParamName,
- UintToString(gpu_info.pixel_shader_version()),
+ base::UintToString(gpu_info.pixel_shader_version()),
set_key_func);
SetGpuKeyValue(kGPUVertexShaderVersionParamName,
- UintToString(gpu_info.vertex_shader_version()),
+ base::UintToString(gpu_info.vertex_shader_version()),
set_key_func);
}
@@ -133,4 +145,17 @@ void SetGpuInfo(const GPUInfo& gpu_info) {
SetGpuInfoImpl(gpu_info, g_set_key_func);
}
+
+void SetNumberOfViewsImpl(int number_of_views,
+ SetCrashKeyValueFuncPtr set_key_func) {
+ NSString *key = [NSString stringWithUTF8String:kNumberOfViews];
+ NSString *value = [NSString stringWithFormat:@"%d", number_of_views];
+ set_key_func(key, value);
+}
+
+void SetNumberOfViews(int number_of_views) {
+ if (g_set_key_func)
+ SetNumberOfViewsImpl(number_of_views, g_set_key_func);
+}
+
} // namespace child_process_logging
diff --git a/chrome/common/child_process_logging_win.cc b/chrome/common/child_process_logging_win.cc
index 1b18e6e..419caa8 100644
--- a/chrome/common/child_process_logging_win.cc
+++ b/chrome/common/child_process_logging_win.cc
@@ -7,8 +7,10 @@
#include <windows.h>
#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_constants.h"
+#include "chrome/common/gpu_info.h"
#include "chrome/installer/util/google_update_settings.h"
#include "googleurl/src/gurl.h"
@@ -28,6 +30,10 @@ typedef void (__cdecl *MainSetGpuInfo)(const wchar_t*, const wchar_t*,
const wchar_t*, const wchar_t*,
const wchar_t*);
+// exported in breakpad_win.cc:
+// void __declspec(dllexport) __cdecl SetNumberOfViews.
+typedef void (__cdecl *MainSetNumberOfViews)(int);
+
void SetActiveURL(const GURL& url) {
static MainSetActiveURL set_active_url = NULL;
// note: benign race condition on set_active_url.
@@ -71,6 +77,14 @@ void SetClientId(const std::string& client_id) {
(set_client_id)(wstr.c_str());
}
+std::string GetClientId() {
+ std::wstring wstr_client_id;
+ if (GoogleUpdateSettings::GetMetricsId(&wstr_client_id))
+ return WideToASCII(wstr_client_id);
+ else
+ return std::string();
+}
+
void SetActiveExtensions(const std::set<std::string>& extension_ids) {
static MainSetExtensionID set_extension_id = NULL;
if (!set_extension_id) {
@@ -105,11 +119,26 @@ void SetGpuInfo(const GPUInfo& gpu_info) {
if (!set_gpu_info)
return;
}
- (set_gpu_info)(UintToWString(gpu_info.vendor_id()).c_str(),
- UintToWString(gpu_info.device_id()).c_str(),
- gpu_info.driver_version().c_str(),
- UintToWString(gpu_info.pixel_shader_version()).c_str(),
- UintToWString(gpu_info.vertex_shader_version()).c_str());
+ (set_gpu_info)(
+ base::UintToString16(gpu_info.vendor_id()).c_str(),
+ base::UintToString16(gpu_info.device_id()).c_str(),
+ gpu_info.driver_version().c_str(),
+ base::UintToString16(gpu_info.pixel_shader_version()).c_str(),
+ base::UintToString16(gpu_info.vertex_shader_version()).c_str());
+}
+
+void SetNumberOfViews(int number_of_views) {
+ static MainSetNumberOfViews set_number_of_views = NULL;
+ if (!set_number_of_views) {
+ HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
+ if (!exe_module)
+ return;
+ set_number_of_views = reinterpret_cast<MainSetNumberOfViews>(
+ GetProcAddress(exe_module, "SetNumberOfViews"));
+ if (!set_number_of_views)
+ return;
+ }
+ (set_number_of_views)(number_of_views);
}
} // namespace child_process_logging
diff --git a/chrome/common/child_thread.cc b/chrome/common/child_thread.cc
index 91d276e..8e6fbce 100644
--- a/chrome/common/child_thread.cc
+++ b/chrome/common/child_thread.cc
@@ -4,20 +4,23 @@
#include "chrome/common/child_thread.h"
+#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/command_line.h"
#include "chrome/common/child_process.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/file_system/file_system_dispatcher.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/plugin_messages.h"
+#include "chrome/common/resource_dispatcher.h"
#include "chrome/common/socket_stream_dispatcher.h"
#include "ipc/ipc_logging.h"
#include "ipc/ipc_message.h"
+#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message_filter.h"
#include "ipc/ipc_switches.h"
#include "webkit/glue/webkit_glue.h"
-
ChildThread::ChildThread() {
channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kProcessChannelID);
@@ -49,6 +52,7 @@ void ChildThread::Init() {
resource_dispatcher_.reset(new ResourceDispatcher(this));
socket_stream_dispatcher_.reset(new SocketStreamDispatcher());
+ file_system_dispatcher_.reset(new FileSystemDispatcher());
sync_message_filter_ =
new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent());
@@ -118,6 +122,17 @@ webkit_glue::ResourceLoaderBridge* ChildThread::CreateBridge(
CreateBridge(request_info, host_renderer_id, host_render_view_id);
}
+ResourceDispatcher* ChildThread::resource_dispatcher() {
+ return resource_dispatcher_.get();
+}
+
+IPC::SyncMessageFilter* ChildThread::sync_message_filter() {
+ return sync_message_filter_;
+}
+
+MessageLoop* ChildThread::message_loop() {
+ return message_loop_;
+}
void ChildThread::OnMessageReceived(const IPC::Message& msg) {
// Resource responses are sent to the resource dispatcher.
@@ -125,6 +140,8 @@ void ChildThread::OnMessageReceived(const IPC::Message& msg) {
return;
if (socket_stream_dispatcher_->OnMessageReceived(msg))
return;
+ if (file_system_dispatcher_->OnMessageReceived(msg))
+ return;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ChildThread, msg)
diff --git a/chrome/common/child_thread.h b/chrome/common/child_thread.h
index 72af5aa..337a7f8 100644
--- a/chrome/common/child_thread.h
+++ b/chrome/common/child_thread.h
@@ -4,18 +4,22 @@
#ifndef CHROME_COMMON_CHILD_THREAD_H_
#define CHROME_COMMON_CHILD_THREAD_H_
+#pragma once
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "chrome/common/message_router.h"
-#include "chrome/common/resource_dispatcher.h"
-#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_message.h"
+#include "webkit/glue/resource_loader_bridge.h"
+class FileSystemDispatcher;
+class MessageLoop;
class NotificationService;
+class ResourceDispatcher;
class SocketStreamDispatcher;
namespace IPC {
+class SyncChannel;
class SyncMessageFilter;
}
@@ -45,19 +49,21 @@ class ChildThread : public IPC::Channel::Listener,
int host_renderer_id,
int host_render_view_id);
- ResourceDispatcher* resource_dispatcher() {
- return resource_dispatcher_.get();
- }
+ ResourceDispatcher* resource_dispatcher();
SocketStreamDispatcher* socket_stream_dispatcher() {
return socket_stream_dispatcher_.get();
}
+ FileSystemDispatcher* file_system_dispatcher() const {
+ return file_system_dispatcher_.get();
+ }
+
// Safe to call on any thread, as long as it's guaranteed that the thread's
// lifetime is less than the main thread.
- IPC::SyncMessageFilter* sync_message_filter() { return sync_message_filter_; }
+ IPC::SyncMessageFilter* sync_message_filter();
- MessageLoop* message_loop() { return message_loop_; }
+ MessageLoop* message_loop();
// Returns the one child thread.
static ChildThread* current();
@@ -117,6 +123,8 @@ class ChildThread : public IPC::Channel::Listener,
scoped_ptr<NotificationService> notification_service_;
+ scoped_ptr<FileSystemDispatcher> file_system_dispatcher_;
+
DISALLOW_COPY_AND_ASSIGN(ChildThread);
};
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 47f0d52..2047798 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -71,7 +71,8 @@ const wchar_t kTestingInterfaceDLL[] = L"testing_interface.dll";
const wchar_t kNotSignedInProfile[] = L"Default";
const wchar_t kNotSignedInID[] = L"not-signed-in";
const wchar_t kBrowserResourcesDll[] = L"chrome.dll";
-const FilePath::CharType kExtensionFileExtension[] = FPL("crx");
+const FilePath::CharType kExtensionFileExtension[] = FPL(".crx");
+const FilePath::CharType kExtensionKeyFileExtension[] = FPL(".pem");
// filenames
const FilePath::CharType kArchivedHistoryFilename[] = FPL("Archived History");
@@ -88,9 +89,8 @@ 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");
-// WARNING: SingletonSocket can't contain spaces, because otherwise
-// chrome_process_util_linux would be broken.
+const FilePath::CharType kSafeBrowsingFilename[] = FPL("Safe Browsing Bloom");
+const FilePath::CharType kSingletonCookieFilename[] = FPL("SingletonCookie");
const FilePath::CharType kSingletonSocketFilename[] = FPL("SingletonSocket");
const FilePath::CharType kSingletonLockFilename[] = FPL("SingletonLock");
const FilePath::CharType kThumbnailsFilename[] = FPL("Thumbnails");
@@ -134,6 +134,8 @@ const int kMaxSessionHistoryEntries = 50;
const wchar_t kChromiumRendererIdProperty[] = L"ChromiumRendererId";
+const char* const kUnknownLanguageCode = "und";
+
} // namespace chrome
#undef FPL
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index a1efdbf..6510409 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -6,6 +6,7 @@
#ifndef CHROME_COMMON_CHROME_CONSTANTS_H_
#define CHROME_COMMON_CHROME_CONSTANTS_H_
+#pragma once
#include "base/file_path.h"
@@ -33,6 +34,7 @@ extern const char kStatsFilename[];
extern const wchar_t kBrowserResourcesDll[];
extern const wchar_t kNaClAppName[];
extern const FilePath::CharType kExtensionFileExtension[];
+extern const FilePath::CharType kExtensionKeyFileExtension[];
// filenames
extern const FilePath::CharType kArchivedHistoryFilename[];
@@ -49,6 +51,7 @@ extern const FilePath::CharType kHistoryFilename[];
extern const FilePath::CharType kLocalStateFilename[];
extern const FilePath::CharType kPreferencesFilename[];
extern const FilePath::CharType kSafeBrowsingFilename[];
+extern const FilePath::CharType kSingletonCookieFilename[];
extern const FilePath::CharType kSingletonSocketFilename[];
extern const FilePath::CharType kSingletonLockFilename[];
extern const FilePath::CharType kThumbnailsFilename[];
@@ -90,6 +93,10 @@ extern const int kMaxSessionHistoryEntries;
extern const wchar_t kChromiumRendererIdProperty[];
+// The language code used when the language of a page could not be detected.
+// (Matches what the CLD -Compact Language Detection- library reports.)
+extern const char* const kUnknownLanguageCode;
+
} // namespace chrome
#endif // CHROME_COMMON_CHROME_CONSTANTS_H_
diff --git a/chrome/common/chrome_counters.h b/chrome/common/chrome_counters.h
index 14cfa21..e655b83 100644
--- a/chrome/common/chrome_counters.h
+++ b/chrome/common/chrome_counters.h
@@ -6,6 +6,7 @@
#ifndef CHROME_COMMON_CHROME_COUNTERS_H_
#define CHROME_COMMON_CHROME_COUNTERS_H_
+#pragma once
class StatsCounter;
class StatsCounterTimer;
diff --git a/chrome/common/chrome_descriptors.h b/chrome/common/chrome_descriptors.h
index 8a4f6ee..d83a017 100644
--- a/chrome/common/chrome_descriptors.h
+++ b/chrome/common/chrome_descriptors.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_CHROME_DESCRIPTORS_H_
#define CHROME_COMMON_CHROME_DESCRIPTORS_H_
+#pragma once
#include "ipc/ipc_descriptors.h"
// This is a list of global descriptor keys to be used with the
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 2d90e0a..65538a7 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_CHROME_PATHS_H__
#define CHROME_COMMON_CHROME_PATHS_H__
+#pragma once
#include "build/build_config.h"
diff --git a/chrome/common/chrome_paths_internal.h b/chrome/common/chrome_paths_internal.h
index 7d731e1..38fbac2 100644
--- a/chrome/common/chrome_paths_internal.h
+++ b/chrome/common/chrome_paths_internal.h
@@ -1,12 +1,14 @@
-// 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.
#ifndef CHROME_COMMON_CHROME_PATHS_INTERNAL_H_
#define CHROME_COMMON_CHROME_PATHS_INTERNAL_H_
+#pragma once
#include "build/build_config.h"
-#include "base/file_path.h"
+
+class FilePath;
namespace chrome {
diff --git a/chrome/common/chrome_paths_linux.cc b/chrome/common/chrome_paths_linux.cc
index 32a9925..f0ff3fb 100644
--- a/chrome/common/chrome_paths_linux.cc
+++ b/chrome/common/chrome_paths_linux.cc
@@ -4,7 +4,7 @@
#include "chrome/common/chrome_paths_internal.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/file_util.h"
#include "base/scoped_ptr.h"
#include "base/xdg_util.h"
@@ -17,7 +17,7 @@ namespace chrome {
// ~/.config/google-chrome/ for official builds.
// (This also helps us sidestep issues with other apps grabbing ~/.chromium .)
bool GetDefaultUserDataDirectory(FilePath* result) {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
FilePath config_dir(
base::GetXDGDirectory(env.get(), "XDG_CONFIG_HOME", ".config"));
#if defined(GOOGLE_CHROME_BUILD)
@@ -29,7 +29,7 @@ bool GetDefaultUserDataDirectory(FilePath* result) {
}
bool GetChromeFrameUserDataDirectory(FilePath* result) {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
FilePath config_dir(
base::GetXDGDirectory(env.get(), "XDG_CONFIG_HOME", ".config"));
#if defined(GOOGLE_CHROME_BUILD)
@@ -41,7 +41,7 @@ bool GetChromeFrameUserDataDirectory(FilePath* result) {
}
bool GetUserDocumentsDirectory(FilePath* result) {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
*result = base::GetXDGUserDirectory(env.get(), "DOCUMENTS", "Documents");
return true;
}
@@ -49,7 +49,7 @@ bool GetUserDocumentsDirectory(FilePath* result) {
// We respect the user's preferred download location, unless it is
// ~ or their desktop directory, in which case we default to ~/Downloads.
bool GetUserDownloadsDirectory(FilePath* result) {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
*result = base::GetXDGUserDirectory(env.get(), "DOWNLOAD", "Downloads");
FilePath home = file_util::GetHomeDir();
@@ -68,7 +68,7 @@ bool GetUserDownloadsDirectory(FilePath* result) {
}
bool GetUserDesktop(FilePath* result) {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
+ scoped_ptr<base::Environment> env(base::Environment::Create());
*result = base::GetXDGUserDirectory(env.get(), "DESKTOP", "Desktop");
return true;
}
diff --git a/chrome/common/chrome_paths_win.cc b/chrome/common/chrome_paths_win.cc
index 4d7709d..c9fee0f 100644
--- a/chrome/common/chrome_paths_win.cc
+++ b/chrome/common/chrome_paths_win.cc
@@ -13,7 +13,6 @@
#include "app/win_util.h"
#include "base/file_path.h"
#include "base/path_service.h"
-#include "base/scoped_comptr_win.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/installer/util/browser_distribution.h"
diff --git a/chrome/common/chrome_plugin_api.h b/chrome/common/chrome_plugin_api.h
index e5230cd..2b3da55 100644
--- a/chrome/common/chrome_plugin_api.h
+++ b/chrome/common/chrome_plugin_api.h
@@ -12,6 +12,7 @@
#ifndef CHROME_COMMON_CHROME_PLUGIN_API_H__
#define CHROME_COMMON_CHROME_PLUGIN_API_H__
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/common/chrome_plugin_lib.cc b/chrome/common/chrome_plugin_lib.cc
index daf6bb7..1e74f4c 100644
--- a/chrome/common/chrome_plugin_lib.cc
+++ b/chrome/common/chrome_plugin_lib.cc
@@ -25,10 +25,10 @@ using base::TimeDelta;
// TODO(port): revisit when plugins happier
#if defined(OS_WIN)
-const TCHAR ChromePluginLib::kRegistryChromePlugins[] =
- _T("Software\\Google\\Chrome\\Plugins");
-static const TCHAR kRegistryLoadOnStartup[] = _T("LoadOnStartup");
-static const TCHAR kRegistryPath[] = _T("Path");
+const wchar_t ChromePluginLib::kRegistryChromePlugins[] =
+ L"Software\\Google\\Chrome\\Plugins";
+static const wchar_t kRegistryLoadOnStartup[] = L"LoadOnStartup";
+static const wchar_t kRegistryPath[] = L"Path";
#endif
typedef base::hash_map<FilePath, scoped_refptr<ChromePluginLib> >
diff --git a/chrome/common/chrome_plugin_lib.h b/chrome/common/chrome_plugin_lib.h
index 5027cfc..b8e447b 100644
--- a/chrome/common/chrome_plugin_lib.h
+++ b/chrome/common/chrome_plugin_lib.h
@@ -4,8 +4,7 @@
#ifndef CHROME_COMMON_CHROME_PLUGIN_LIB_H_
#define CHROME_COMMON_CHROME_PLUGIN_LIB_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "base/file_path.h"
diff --git a/chrome/common/chrome_plugin_util.cc b/chrome/common/chrome_plugin_util.cc
index 08be12b..649975f 100644
--- a/chrome/common/chrome_plugin_util.cc
+++ b/chrome/common/chrome_plugin_util.cc
@@ -9,6 +9,7 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/message_loop.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_switches.h"
@@ -140,11 +141,11 @@ CPError CPB_GetCommandLineArgumentsCommon(const char* url,
}
}
-#if defined (OS_CHROMEOS)
- std::wstring profile = cmd.GetSwitchValue(switches::kProfile);
+#if defined(OS_CHROMEOS)
+ FilePath profile = cmd.GetSwitchValuePath(switches::kLoginProfile);
if (!profile.empty()) {
- arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kProfile) +
- L"=\"" + profile + L"\" ";
+ arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kLoginProfile) +
+ L"=\"" + profile.ToWStringHack() + L"\" ";
}
#endif
diff --git a/chrome/common/chrome_plugin_util.h b/chrome/common/chrome_plugin_util.h
index 7714a53..5e78245 100644
--- a/chrome/common/chrome_plugin_util.h
+++ b/chrome/common/chrome_plugin_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_CHROME_PLUGIN_UTIL_H_
#define CHROME_COMMON_CHROME_PLUGIN_UTIL_H_
+#pragma once
#include <string>
@@ -11,6 +12,7 @@
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
#include "chrome/common/chrome_plugin_api.h"
+#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
class ChromePluginLib;
@@ -38,7 +40,8 @@ struct ScopableCPRequest : public CPRequest {
// This is a base class for plugin-related objects that need to go away when
// the plugin unloads. This object also verifies that it is created and
// destroyed on the same thread.
-class PluginHelper : public NotificationObserver, public NonThreadSafe {
+class PluginHelper : public NotificationObserver,
+ public NonThreadSafe {
public:
static void DestroyAllHelpersForPlugin(ChromePluginLib* plugin);
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 3c4255a..4d9d14f 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -22,6 +22,12 @@ const char kActivateOnLaunch[] = "activate-on-launch";
// override for developers who need the old behavior for testing.
const char kAllowFileAccessFromFiles[] = "allow-file-access-from-files";
+// 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
+// connections.
+const char kAllowSSLMITMProxies[] = "allow-ssl-mitm-proxies";
+
// Allows debugging of sandboxed processes (see zygote_main_linux.cc).
const char kAllowSandboxDebugging[] = "allow-sandbox-debugging";
@@ -57,13 +63,28 @@ const char kAppsNoThrob[] = "apps-no-throb";
// Whether to display the "Debug" link for app launch behavior.
const char kAppsDebug[] = "apps-debug";
-// Authentication white list for servers
-const char kAuthServerWhitelist[] = "auth-server-whitelist";
+// Whitelist of servers that Negotiate will generate delegated Kerberos tickets
+// for.
+const char kAuthNegotiateDelegateWhitelist[] =
+ "auth-negotiate-delegate-whitelist";
+
+// HTTP authentication schemes to enable. This is a comma separated list
+// of authentication schemes (basic, digest, ntlm, and negotiate). By default
+// all schemes are enabled. The primary use of this command line flag is to help
+// triage autentication-related issues reported by end-users.
+const char kAuthSchemes[] = "auth-schemes";
+
+// Whitelist of servers which NTLM and Negotiate can automatically authenticate
+// with using the default credentials of the currently logged in user.
+const char kAuthServerWhitelist[] = "auth-server-whitelist";
// The value of this switch tells the app to listen for and broadcast
// 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";
@@ -73,6 +94,10 @@ const char kBrowserCrashTest[] = "crash-test";
// Path to the exe to run for the renderer and plugin subprocesses.
const char kBrowserSubprocessPath[] = "browser-subprocess-path";
+// How often (in seconds) to check for updates. Should only be used for
+// testing purposes.
+const char kCheckForUpdateIntervalSec[] = "check-for-update-interval";
+
// Run Chrome in Chrome Frame mode. This means that Chrome expects to be run
// as a dependent process of the Chrome Frame plugin.
const char kChromeFrame[] = "chrome-frame";
@@ -96,12 +121,19 @@ const char kDebugPrint[] = "debug-print";
// Triggers a pletora of diagnostic modes.
const char kDiagnostics[] = "diagnostics";
+// Disables accelerated compositing.
+const char kDisableAcceleratedCompositing[] =
+ "disable-accelerated-compositing";
+
// Disables the alternate window station for the renderer.
const char kDisableAltWinstation[] = "disable-winsta";
// Disable the ApplicationCache.
const char kDisableApplicationCache[] = "disable-application-cache";
+// Disable extension apps.
+const char kDisableApps[] = "disable-apps";
+
// Replaces the audio IPC layer for <audio> and <video> with a mock audio
// device, useful when using remote desktop or machines without sound cards.
// This is temporary until we fix the underlying problem.
@@ -116,6 +148,11 @@ const char kDisableAudio[] = "disable-audio";
const char kDisableAuthNegotiateCnameLookup[] =
"disable-auth-negotiate-cname-lookup";
+// Disable several subsystems which run network requests in the background.
+// This is for use when doing network performance testing to avoid noise
+// in the measurements.
+const char kDisableBackgroundNetworking[] = "disable-background-networking";
+
// Disable limits on the number of backing stores. Can prevent blinking for
// users with many windows/tabs and lots of memory.
const char kDisableBackingStoreLimit[] = "disable-backing-store-limit";
@@ -123,6 +160,18 @@ const char kDisableBackingStoreLimit[] = "disable-backing-store-limit";
// Disable support for cached byte-ranges.
const char kDisableByteRangeSupport[] = "disable-byte-range-support";
+// Disable click-to-play for blocked plug-ins.
+const char kDisableClickToPlay[] = "disable-click-to-play";
+
+// Disables establishing a backup TCP connection if a specified timeout is
+// exceeded.
+const char kDisableConnectBackupJobs[] = "disable-connect-backup-jobs";
+
+// Disable requests that webkit labels TargetIsPrefetch. As of
+// writing only <link rel=prefetch...> but also eventually
+// Link: headers.
+const char kDisableContentPrefetch[] = "disable-content-prefetch";
+
// Disables the custom JumpList on Windows 7.
const char kDisableCustomJumpList[] = "disable-custom-jumplist";
@@ -135,6 +184,12 @@ const char kDisableDesktopNotifications[] = "disable-desktop-notifications";
// Browser flag to disable the web inspector for all renderers.
const char kDisableDevTools[] = "disable-dev-tools";
+// Disables device orientation events.
+const char kDisableDeviceOrientation[] = "disable-device-orientation";
+
+// Disable experimental WebGL support.
+const char kDisableExperimentalWebGL[] = "disable-webgl";
+
// Disable extensions.
const char kDisableExtensions[] = "disable-extensions";
@@ -146,7 +201,12 @@ const char kDisableExtensionsFileAccessCheck[] =
// Suppresses support for the Geolocation javascript API.
const char kDisableGeolocation[] = "disable-geolocation";
-// Suppresses hang monitor dialogs in renderer processes.
+// Disable the GLSL translator.
+const char kDisableGLSLTranslator[] = "disable-glsl-translator";
+
+// Suppresses hang monitor dialogs in renderer processes. This may allow slow
+// unload handlers on a page to prevent the tab from closing, but the Task
+// Manager can be used to terminate the offending process in this case.
const char kDisableHangMonitor[] = "disable-hang-monitor";
// Disable the internal Flash Player.
@@ -158,6 +218,9 @@ const char kDisableInternalFlash[] = "disable-internal-flash";
// This flag can be overidden by the "enable-ipv6" flag.
const char kDisableIPv6[] = "disable-ipv6";
+// Disable speculative TCP/IP preconnection.
+const char kDisablePreconnect[] = "disable-preconnect";
+
// Don't execute JavaScript (browser JS like the new tab page still runs).
const char kDisableJavaScript[] = "disable-javascript";
@@ -175,6 +238,9 @@ 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";
@@ -193,6 +259,11 @@ const char kDisableRemoteFonts[] = "disable-remote-fonts";
// Turns off the accessibility in the renderer.
const char kDisableRendererAccessibility[] = "disable-renderer-accessibility";
+// Prevents the URLs of BackgroundContents from being remembered and re-launched
+// when the browser restarts.
+const char kDisableRestoreBackgroundContents[] =
+ "disable-restore-background-contents";
+
// Disable session storage.
const char kDisableSessionStorage[] = "disable-session-storage";
@@ -202,9 +273,18 @@ const char kDisableSharedWorkers[] = "disable-shared-workers";
// Disable site-specific tailoring to compatibility issues in WebKit.
const char kDisableSiteSpecificQuirks[] = "disable-site-specific-quirks";
+// Disables speech input.
+const char kDisableSpeechInput[] = "disable-speech-input";
+
+// Disable False Start in SSL and TLS connections.
+const char kDisableSSLFalseStart[] = "disable-ssl-false-start";
+
// Disable syncing browser data to a Google Account.
const char kDisableSync[] = "disable-sync";
+// Disable syncing of apps.
+const char kDisableSyncApps[] = "disable-sync-apps";
+
// Disable syncing of autofill.
const char kDisableSyncAutofill[] = "disable-sync-autofill";
@@ -220,6 +300,9 @@ const char kDisableSyncPasswords[] = "disable-sync-passwords";
// Disable syncing of preferences.
const char kDisableSyncPreferences[] = "disable-sync-preferences";
+// Disable syncing of sessions.
+const char kDisableSyncSessions[] = "disable-sync-sessions";
+
// Disable syncing of themes.
const char kDisableSyncThemes[] = "disable-sync-themes";
@@ -232,6 +315,11 @@ const char kDisableSyncTypedUrls[] = "disable-sync-typed-urls";
const char kDisableTabCloseableStateWatcher[] =
"disable-tab-closeable-state-watcher";
+// Allow disabling of translate from the command line to assist with
+// automated browser testing (e.g. Selenium/WebDriver). Normal
+// browser users should disable translate with the preference.
+const char kDisableTranslate[] = "disable-translate";
+
// Enables the backend service for web resources, used in the new tab page for
// loading tips and recommendations from a JSON feed.
const char kDisableWebResources[] = "disable-web-resources";
@@ -265,26 +353,37 @@ const char kDomAutomationController[] = "dom-automation";
// scripts.
const char kDumpHistogramsOnExit[] = "dump-histograms-on-exit";
-// Enable gpu-accelerated compositing.
-const char kEnableAcceleratedCompositing[] = "enable-accelerated-compositing";
+// Enable displaying net log events on the command line.
+extern const char kLogNetLog[] = "log-net-log";
+
+// Enable gpu-accelerated 2d canvas.
+const char kEnableAccelerated2dCanvas[] = "enable-accelerated-2d-canvas";
+
+// Enables WebKit accessibility within the renderer process.
+const char kEnableAccessibility[] = "enable-accessibility";
// Enables AeroPeek for each tab. (This switch only works on Windows 7).
const char kEnableAeroPeekTabs[] = "enable-aero-peek-tabs";
-// Enable experimental extension apps.
-const char kEnableApps[] = "enable-apps";
-
// Enable the inclusion of non-standard ports when generating the Kerberos SPN
// in response to a Negotiate challenge. See HttpAuthHandlerNegotiate::CreateSPN
// for more background.
const char kEnableAuthNegotiatePort[] = "enable-auth-negotiate-port";
+// Enable background mode (background apps will keep chrome running in the
+// background and allow chrome to launch on startup).
+const char kEnableBackgroundMode[] = "enable-background-mode";
+
// Enables the benchmarking extensions.
const char kEnableBenchmarking[] = "enable-benchmarking";
// This applies only when the process type is "service". Enables the
// Chromoting Host Process within the service process.
-const char kEnableChromoting[] = "enable-chromoting";
+const char kEnableRemoting[] = "enable-remoting";
+
+// This flag enables UI for clearing server data. Temporarily in place
+// until there's a server endpoint deployed.
+const char kEnableClearServerData[] = "enable-clear-server-data";
// This applies only when the process type is "service". Enables the
// Cloud Print Proxy component within the service process.
@@ -293,19 +392,27 @@ const char kEnableCloudPrintProxy[] = "enable-cloud-print-proxy";
// Enables the Cloud Print dialog hosting code.
const char kEnableCloudPrint[] = "enable-cloud-print";
+// Enables establishing a backup TCP connection if a specified timeout is
+// exceeded.
+const char kEnableConnectBackupJobs[] = "enable-connect-backup-jobs";
+
+// Enable requests that webkit labels TargetIsPrefetch. As of
+// writing only <link rel=prefetch...> but also eventually
+// Link: headers.
+const char kEnableContentPrefetch[] = "enable-content-prefetch";
+
+// Enables device motion events.
+const char kEnableDeviceMotion[] = "enable-device-motion";
+
+const char kEnableDNSSECCerts[] = "enable-dnssec-certs";
+
// Enables extension APIs that are in development.
const char kEnableExperimentalExtensionApis[] =
"enable-experimental-extension-apis";
-// Enable experimental WebGL support.
-const char kEnableExperimentalWebGL[] = "enable-webgl";
-
// Enable experimental timeline API.
const char kEnableExtensionTimelineApi[] = "enable-extension-timeline-api";
-// Enable extension toolstrips (deprecated API - will be removed).
-const char kEnableExtensionToolstrips[] = "enable-extension-toolstrips";
-
// Enable the fastback page cache.
const char kEnableFastback[] = "enable-fastback";
@@ -313,6 +420,9 @@ const char kEnableFastback[] = "enable-fastback";
// testing, for example page cycler and layout tests. See bug 1157243.
const char kEnableFileCookies[] = "enable-file-cookies";
+// Enable the FileSystem API.
+const char kEnableFileSystem[] = "enable-file-system";
+
// Enable the Indexed Database API.
const char kEnableIndexedDatabase[] = "enable-indexed-database";
@@ -326,9 +436,6 @@ const char kEnableInMemoryURLIndex[] = "enable-in-memory-url-index";
// This flag overrides "disable-ipv6" which appears elswhere in this file.
const char kEnableIPv6[] = "enable-ipv6";
-// Enable the GLSL translator.
-const char kEnableGLSLTranslator[] = "enable-glsl-translator";
-
// Enable the GPU plugin and Pepper 3D rendering.
const char kEnableGPUPlugin[] = "enable-gpu-plugin";
@@ -339,6 +446,9 @@ const char kEnableGPURendering[] = "enable-gpu-rendering";
// builds.
const char kEnableLogging[] = "enable-logging";
+// Is match preview enabled?
+const char kEnableMatchPreview[] = "enable-match-preview";
+
// Allows reporting memory info (JS heap size) to page.
const char kEnableMemoryInfo[] = "enable-memory-info";
@@ -351,9 +461,19 @@ const char kEnableMonitorProfile[] = "enable-monitor-profile";
// (internally adds kInternalNaCl and lEnableGpuPlugin to the command line).
const char kEnableNaCl[] = "enable-nacl";
+// Enables debugging via RSP over a socket.
+const char kEnableNaClDebug[] = "enable-nacl-debug";
+
// Enable Native Web Worker support.
const char kEnableNativeWebWorkers[] = "enable-native-web-workers";
+// Enables the Page Info SSL dialog as a bubble, rather than a separate window.
+const char kEnableNewPageInfoBubble[] = "enable-new-page-info-bubble";
+
+// Enable content settings based on host *and* plug-in.
+const char kEnableResourceContentSettings[] =
+ "enable-resource-content-settings";
+
// Enable speculative TCP/IP preconnection.
const char kEnablePreconnect[] = "enable-preconnect";
@@ -367,12 +487,18 @@ const char kEnablePrintPreview[] = "enable-print-preview";
// parameter to indicate if the provider should be the default.
const char kEnableSearchProviderApiV2[] = "enable-search-provider-api-v2";
+// Enables speech input.
+const char kEnableSpeechInput[] = "enable-speech-input";
+
// Enables StatsTable, logging statistics to a global named shared memory table.
const char kEnableStatsTable[] = "enable-stats-table";
// Enable syncing browser data to a Google Account.
const char kEnableSync[] = "enable-sync";
+// Enable syncing browser apps.
+const char kEnableSyncApps[] = "enable-sync-apps";
+
// Enable syncing browser autofill.
const char kEnableSyncAutofill[] = "enable-sync-autofill";
@@ -388,6 +514,9 @@ const char kEnableSyncPasswords[] = "enable-sync-passwords";
// Enable syncing browser preferences.
const char kEnableSyncPreferences[] = "enable-sync-preferences";
+// Enable syncing browser sessions.
+const char kEnableSyncSessions[] = "enable-sync-sessions";
+
// Enable syncing browser themes.
const char kEnableSyncThemes[] = "enable-sync-themes";
@@ -397,6 +526,9 @@ const char kEnableSyncTypedUrls[] = "enable-sync-typed-urls";
// Enable tabbed options, ie: dom-ui version of options window.
const char kEnableTabbedOptions[] = "enable-tabbed-options";
+// Enables TopSites.
+const char kEnableTopSites[] = "enable-top-sites";
+
// Whether or not the touch events API is exposed.
const char kEnableTouch[] = "enable-touch";
@@ -425,9 +557,12 @@ const char kEnableWatchdog[] = "enable-watchdog";
// Disable WebKit's XSSAuditor. The XSSAuditor mitigates reflective XSS.
const char kEnableXSSAuditor[] = "enable-xss-auditor";
-// Enables the experimental Negotiate authentication protocol.
-const char kExperimentalEnableNegotiateAuth[] =
- "experimental-enable-negotiate-auth";
+// Enables experimental features for the geolocation API.
+// Current features:
+// - CoreLocation support for Mac OS X 10.6
+// - Gateway location for Windows
+// - Location platform support for Windows 7
+const char kExperimentalLocationFeatures[] = "experimental-location-features";
// Enables experimental features for Spellchecker. Right now, the first
// experimental feature is auto spell correct, which corrects words which are
@@ -449,6 +584,9 @@ const char kExtensionProcess[] = "extension";
// Frequency in seconds for Extensions auto-update.
const char kExtensionsUpdateFrequency[] = "extensions-update-frequency";
+// Alternative feedback server to use when submitting user feedback
+const char kFeedbackServer[] = "feedback-server";
+
// The file descriptor limit is set to the value of this switch, subject to the
// OS hard limits. Useful for testing that file descriptor exhaustion is handled
// gracefully.
@@ -470,6 +608,11 @@ const char kFirstRun[] = "first-run";
// current details.
const char kForceFieldTestNameAndValue[] = "force-fieldtest";
+// Force renderer accessibility to be on instead of enabling it on demand when
+// a screen reader is detected. The disable-renderer-accessibility switch
+// overrides this if present.
+const char kForceRendererAccessibility[] = "force-renderer-accessibility";
+
// Extra command line options for launching the GPU process (normally used
// for debugging). Use like renderer-cmd-prefix.
const char kGpuLauncher[] = "gpu-launcher";
@@ -536,31 +679,12 @@ const char kInProcessWebGL[] = "in-process-webgl";
// Causes the browser to launch directly in incognito mode.
const char kIncognito[] = "incognito";
-// Back up the profile.
-const char kInstallerTestBackup[] = "backup";
-
-// Control the build under test.
-const char kInstallerTestBuild[] = "build";
-
-// Uninstall before running the tests.
-const char kInstallerTestClean[] = "clean";
-
-// Force the installer tests to run, regardless of the current platform.
-const char kInstallerTestForce[] = "force";
-
// Runs the Native Client inside the renderer process.
const char kInternalNaCl[] = "internal-nacl";
// Runs a trusted Pepper plugin inside the renderer process.
const char kInternalPepper[] = "internal-pepper";
-// The following flags allow users who can reproduce crbug/35198
-// to enable extra logging and behaviors. They will be removed once
-// the issue is fixed.
-const char kIssue35198CrxDirBrowser[] = "issue35198-crxdir-browser";
-const char kIssue35198ExtraLogging[] = "issue35198-logging";
-const char kIssue35198Permission[] = "issue35198-permission";
-
// Specifies the flags passed to JS engine
const char kJavaScriptFlags[] = "js-flags";
@@ -609,6 +733,12 @@ const char kMessageLoopHistogrammer[] = "message-loop-histogrammer";
// and performance tests.
const char kMetricsRecordingOnly[] = "metrics-recording-only";
+// Sets the default IP address (interface) for the stub (normally 127.0.0.1).
+const char kNaClDebugIP[] = "nacl-debug-ip";
+
+// Sets the default port range for debugging.
+const char kNaClDebugPorts[] = "nacl-debug-ports";
+
// Causes the process to run as a NativeClient broker
// (used for launching NaCl loader processes on 64-bit Windows).
const char kNaClBrokerProcess[] = "nacl-broker";
@@ -648,6 +778,14 @@ const char kNoProxyServer[] = "no-proxy-server";
// Runs the renderer outside the sandbox.
const char kNoSandbox[] = "no-sandbox";
+// Does not automatically open a browser window on startup (used when launching
+// Chrome for the purpose of hosting background apps).
+const char kNoStartupWindow[] = "no-startup-window";
+
+// Show a desktop notification that the cloud print token has expired and
+// that user needs to re-authenticate.
+const char kNotifyCloudPrintTokenExpired[] = "notify-cp-token-expired";
+
// Specifies the maximum number of threads to use for running the Proxy
// Autoconfig (PAC) script.
const char kNumPacThreads[] = "num-pac-threads";
@@ -655,6 +793,9 @@ const char kNumPacThreads[] = "num-pac-threads";
// Launch URL in new browser window.
const char kOpenInNewWindow[] = "new-window";
+// Simulate an organic Chrome install.
+const char kOrganicInstall[] = "organic";
+
// Package an extension to a .crx installable file from a given directory.
const char kPackExtension[] = "pack-extension";
@@ -686,10 +827,6 @@ const char kPluginProcess[] = "plugin";
// Causes the plugin process to display a dialog on launch.
const char kPluginStartupDialog[] = "plugin-startup-dialog";
-// Enable TCP/IP preconnection, and DNS preresolution, even if a proxy might
-// possibly be used for connections.
-const char kPreconnectDespiteProxy[] = "preconnect-despite-proxy";
-
// Establishes a channel to the GPU process asynchronously and (re)launches it
// if necessary when a renderer process starts.
const char kPrelaunchGpuProcess[] = "prelaunch-gpu-process";
@@ -709,6 +846,10 @@ const char kProcessPerSite[] = "process-per-site";
// script connections to each other).
const char kProcessPerTab[] = "process-per-tab";
+// The value of this switch determines whether the process is started as a
+// renderer or plugin host. If it's empty, it's the browser.
+const char kProcessType[] = "type";
+
// Output the product version information and quit. Used as an internal api to
// detect the installed version of Chrome on Linux.
const char kProductVersion[] = "product-version";
@@ -776,10 +917,6 @@ const char kRendererProcess[] = "renderer";
// Causes the renderer process to display a dialog on launch.
const char kRendererStartupDialog[] = "renderer-startup-dialog";
-// Causes the URLs of BackgroundContents to be remembered and re-launched when
-// the browser restarts.
-const char kRestoreBackgroundContents[] = "restore-background-contents";
-
// Indicates the last session should be restored on startup. This overrides
// the preferences value and is primarily intended for testing. The value of
// this switch is the number of tabs to wait until loaded before
@@ -789,11 +926,19 @@ const char kRestoreLastSession[] = "restore-last-session";
// Runs the plugin processes inside the sandbox.
const char kSafePlugins[] = "safe-plugins";
+// Select the safe-browsing database storage. "old" for the original
+// SQLite-based SafeBrowsingDatabaseBloom, "newsqlite" for the new
+// SQLite-based SafeBrowsingDatabase+SafeBrowsingStoreSQLite, and
+// "newfile" for SafeBrowsingDatabase+SafeBrowsingStoreFile.
+const char kSafeBrowsingDatabaseStore[] = "safe-browsing-database-store";
+
// URL prefix used by safebrowsing to fetch hash, download data and
// report malware.
const char kSbInfoURLPrefix[] = "safebrowsing-info-url-prefix";
+
// URL prefix used by safebrowsing to get MAC key.
const char kSbMacKeyURLPrefix[] = "safebrowsing-mackey-url-prefix";
+
// If present, safebrowsing only performs update when
// SafeBrowsingProtocolManager::ForceScheduleNextUpdate() is explicitly called.
// This is used for testing only.
@@ -827,10 +972,6 @@ const char kShowCompositedLayerBorders[] = "show-composited-layer-borders";
// and study painting behavior.
const char kShowPaintRects[] = "show-paint-rects";
-// Whether to show the link to the Google Privacy Dashboard on the Sync options
-// panel.
-const char kShowPrivacyDashboardLink[] = "show-privacy-dashboard-link";
-
// Change the DCHECKS to dump memory and continue instead of displaying error
// dialog. This is valid only in Release mode when --enable-dcheck is
// specified.
@@ -867,6 +1008,9 @@ const char kSyncerThreadTimedStop[] = "syncer-thread-timed-stop";
// Override the default notification method for sync.
const char kSyncNotificationMethod[] = "sync-notification-method";
+// Override the default host used for sync notifications.
+const char kSyncNotificationHost[] = "sync-notification-host";
+
// Password used for sync.
const char kSyncPassword[] = "password";
@@ -879,10 +1023,6 @@ const char kSyncServer[] = "server";
// Override the default server used for profile sync.
const char kSyncServiceURL[] = "sync-url";
-// Use the (new, untested) Chrome-socket-based buzz::AsyncSocket
-// implementation for notifications.
-const char kSyncUseChromeAsyncSocket[] = "sync-use-chrome-async-socket";
-
// Control Sync XMPP client settings.
const char kSyncUseSslTcp[] = "use-ssl-tcp";
@@ -905,10 +1045,6 @@ const char kTestType[] = "test-type";
// testing-related messages on IPC channel with the given ID.
const char kTestingChannelID[] = "testing-channel";
-// Enables using TopSites instead of ThumbnailDatabase (and
-// ThumbnailStore) for getting thumbnails for the new tab page.
-const char kTopSites[] = "top-sites";
-
// Excludes these plugins from the plugin sandbox.
// This is a comma-separated list of plugin library names.
const char kTrustedPlugins[] = "trusted-plugins";
@@ -924,10 +1060,6 @@ const char kUninstall[] = "uninstall";
// This is a temporary testing flag.
const char kUseSpdy[] = "use-spdy";
-// These two flags are used to force http and https requests to fixed ports.
-const char kFixedHttpPort[] = "testing-fixed-http-port";
-const char kFixedHttpsPort[] = "testing-fixed-https-port";
-
// Ignore certificate related errors.
const char kIgnoreCertificateErrors[] = "ignore-certificate-errors";
@@ -997,12 +1129,14 @@ const char kEnableLoginImages[] = "enable-login-images";
// Enable Chrome-as-a-login-manager behavior.
const char kLoginManager[] = "login-manager";
+
// Allows to override the first login screen. The value should be the name
// of the first login screen to show (see
// chrome/browser/chromeos/login/login_wizard_view.cc for actual names).
// Ignored if kLoginManager is not specified.
// TODO(avayvod): Remove when the switch is no longer needed for testing.
const char kLoginScreen[] = "login-screen";
+
// Allows control over the initial login screen size. Pass width,height.
const char kLoginScreenSize[] = "login-screen-size";
@@ -1010,30 +1144,30 @@ const char kLoginScreenSize[] = "login-screen-size";
// means the library could not be loaded correctly.
const char kTestLoadLibcros[] = "test-load-libcros";
-// TODO(davemoore) Delete this once chromeos has started using
-// login-profile as its arg.
-const char kProfile[] = "profile";
-
// Specifies the profile to use once a chromeos user is logged in.
const char kLoginProfile[] = "login-profile";
// Specifies the user which is already logged in.
const char kLoginUser[] = "login-user";
+// Specifies a password to be used to login (along with login-user).
+const char kLoginPassword[] = "login-password";
// Use the frame layout used in chromeos.
const char kChromeosFrame[] = "chromeos-frame";
-// Set logging output to the given file.
-const char kChromeosLogToFile[] = "logtofile";
+// Use the given language for UI in the input method candidate window.
+const char kCandidateWindowLang[] = "lang";
-// Specify startup customization manifest.
-// TODO(denisromanov): delete this when not needed for testing.
-const char kStartupManifest[] = "startup-manifest";
+// Indicates that the browser is in "browse without sign-in" mode.
+// Should completely disable extensions, sync and bookmarks.
+const char kBWSI[] = "bwsi";
-// Specify services customization manifest.
-// TODO(denisromanov): delete this when not needed for testing.
-const char kServicesManifest[] = "services-manifest";
+// Indicates that stub implementations of the libcros library should be used.
+// This is typically used to test the chromeos build of chrome on the desktop.
+const char kStubCros[] = "stub-cros";
+// URL of the html page for Screen Saver.
+const char kScreenSaverUrl[] = "screen-saver-url";
#endif
#if defined(OS_LINUX)
@@ -1048,7 +1182,6 @@ const char kUseSystemSSL[] = "use-system-ssl";
#endif
#if defined(OS_POSIX)
-// Bypass the error dialog when the profile lock couldn't be attained.
// A flag, generated internally by Chrome for renderer and other helper process
// command lines on Linux and Mac. It tells the helper process to enable crash
// dumping and reporting, because helpers cannot access the profile or other
@@ -1057,6 +1190,7 @@ const char kUseSystemSSL[] = "use-system-ssl";
// as well, thereby force-enabling the crash reporter.
const char kEnableCrashReporter[] = "enable-crash-reporter";
+// Bypass the error dialog when the profile lock couldn't be attained.
// This switch is used during automated testing.
const char kNoProcessSingletonDialog[] = "no-process-singleton-dialog";
@@ -1067,29 +1201,36 @@ const char kPasswordStore[] = "password-store";
#endif
#if defined(OS_MACOSX)
-// 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 prevent Flash from negotiating the Core Animation drawing
// model. This will be removed once the last issues have been resolved.
const char kDisableFlashCoreAnimation[] = "disable-flash-core-animation";
+
+// Temporary flag to disable hole punching for accelerated surfaces. This is
+// here to aid debugging eventual problems, it can be removed once hole punching
+// has been out there for a few dev channel releases without problems.
+const char kDisableHolePunching[] = "disable-hole-punching";
+
+// Enables the tabs expose feature ( http://crbug.com/50307 ).
+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";
#else
// Enable Kiosk mode.
const char kKioskMode[] = "kiosk";
#endif
#ifndef NDEBUG
+// Clear the token service before using it. This allows simulating
+// the expiration of credentials during testing.
+const char kClearTokenService[] = "clear-token-service";
+
// Debug only switch to specify which gears plugin dll to load.
const char kGearsPluginPathOverride[] = "gears-plugin-path";
-// Makes sure any sync login attempt will fail with an error. (Only
-// used for testing.)
-const char kInvalidateSyncLogin[] = "invalidate-sync-login";
-
-// Makes sure any sync xmpp login attempt will fail with an error. (Only
-// used for testing.)
-const char kInvalidateSyncXmppLogin[] = "invalidate-sync-xmpp-login";
+// Sets a token in the token service, for testing.
+const char kSetToken[] = "set-token";
// Debug only switch to specify which websocket live experiment host to be used.
// If host is specified, it also makes initial delay shorter (5 min to 5 sec)
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 70a8268..14800a5 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -6,6 +6,7 @@
#ifndef CHROME_COMMON_CHROME_SWITCHES_H_
#define CHROME_COMMON_CHROME_SWITCHES_H_
+#pragma once
#include "build/build_config.h"
#include "base/base_switches.h"
@@ -21,6 +22,7 @@ namespace switches {
// alongside the definition of their values in the .cc file.
extern const char kActivateOnLaunch[];
extern const char kAllowFileAccessFromFiles[];
+extern const char kAllowSSLMITMProxies[];
extern const char kAllowSandboxDebugging[];
extern const char kAllowScriptingGallery[];
extern const char kAlwaysEnableDevTools[];
@@ -31,30 +33,43 @@ extern const char kAppsDebug[];
extern const char kAppsPanel[];
extern const char kAppsGalleryURL[];
extern const char kAppsNoThrob[];
+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[];
+extern const char kCheckForUpdateIntervalSec[];
extern const char kChromeFrame[];
extern const char kCloudPrintProxyId[];
extern const char kCloudPrintServiceURL[];
extern const char kCountry[];
extern const char kDebugPrint[];
extern const char kDiagnostics[];
+extern const char kDisableAcceleratedCompositing[];
extern const char kDisableAltWinstation[];
extern const char kDisableApplicationCache[];
+extern const char kDisableApps[];
extern const char kDisableAudio[];
extern const char kDisableAuthNegotiateCnameLookup[];
+extern const char kDisableBackgroundNetworking[];
extern const char kDisableBackingStoreLimit[];
extern const char kDisableByteRangeSupport[];
+extern const char kDisableClickToPlay[];
+extern const char kDisableConnectBackupJobs[];
+extern const char kDisableContentPrefetch[];
extern const char kDisableCustomJumpList[];
extern const char kDisableDatabases[];
extern const char kDisableDesktopNotifications[];
extern const char kDisableDevTools[];
+extern const char kDisableDeviceOrientation[];
+extern const char kDisableExperimentalWebGL[];
extern const char kDisableExtensions[];
extern const char kDisableExtensionsFileAccessCheck[];
extern const char kDisableGeolocation[];
+extern const char kDisableGLSLTranslator[];
extern const char kDisableHangMonitor[];
extern const char kDisableInternalFlash[];
extern const char kDisableIPv6[];
@@ -63,15 +78,21 @@ 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[];
extern const char kDisablePromptOnRepost[];
extern const char kDisableRemoteFonts[];
extern const char kDisableRendererAccessibility[];
+extern const char kDisableRestoreBackgroundContents[];
extern const char kDisableSessionStorage[];
extern const char kDisableSharedWorkers[];
extern const char kDisableSiteSpecificQuirks[];
+extern const char kDisableSpeechInput[];
+extern const char kDisableSSLFalseStart[];
extern const char kDisableSync[];
+extern const char kDisableSyncApps[];
extern const char kDisableSyncAutofill[];
extern const char kDisableSyncBookmarks[];
extern const char kDisableSyncExtensions[];
@@ -79,7 +100,9 @@ extern const char kDisableSyncPasswords[];
extern const char kDisableSyncPreferences[];
extern const char kDisableSyncThemes[];
extern const char kDisableSyncTypedUrls[];
+extern const char kDisableSyncSessions[];
extern const char kDisableTabCloseableStateWatcher[];
+extern const char kDisableTranslate[];
extern const char kDisableWebResources[];
extern const char kDisableWebSecurity[];
extern const char kDisableWebSockets[];
@@ -89,45 +112,57 @@ extern const char kDnsLogDetails[];
extern const char kDnsPrefetchDisable[];
extern const char kDomAutomationController[];
extern const char kDumpHistogramsOnExit[];
-extern const char kEnableAcceleratedCompositing[];
+extern const char kEnableAccelerated2dCanvas[];
+extern const char kEnableAccessibility[];
extern const char kEnableAeroPeekTabs[];
-extern const char kEnableApps[];
extern const char kEnableAuthNegotiatePort[];
+extern const char kEnableBackgroundMode[];
extern const char kEnableBenchmarking[];
-extern const char kEnableChromoting[];
+extern const char kEnableRemoting[];
+extern const char kEnableClearServerData[];
extern const char kEnableCloudPrintProxy[];
extern const char kEnableCloudPrint[];
+extern const char kEnableConnectBackupJobs[];
+extern const char kEnableContentPrefetch[];
+extern const char kEnableDeviceMotion[];
+extern const char kEnableDNSSECCerts[];
extern const char kEnableExperimentalExtensionApis[];
-extern const char kEnableExperimentalWebGL[];
extern const char kEnableExtensionTimelineApi[];
-extern const char kEnableExtensionToolstrips[];
extern const char kEnableFastback[];
extern const char kEnableFileCookies[];
-extern const char kEnableGLSLTranslator[];
+extern const char kEnableFileSystem[];
extern const char kEnableGPUPlugin[];
extern const char kEnableGPURendering[];
extern const char kEnableIndexedDatabase[];
extern const char kEnableInMemoryURLIndex[];
extern const char kEnableIPv6[];
extern const char kEnableLogging[];
+extern const char kEnableMatchPreview[];
extern const char kEnableMemoryInfo[];
extern const char kEnableMonitorProfile[];
extern const char kEnableNaCl[];
+extern const char kEnableNaClDebug[];
extern const char kEnableNativeWebWorkers[];
-extern const char kEnablePreparsedJsCaching[];
+extern const char kEnableNewPageInfoBubble[];
extern const char kEnablePreconnect[];
+extern const char kEnablePreparsedJsCaching[];
extern const char kEnablePrintPreview[];
+extern const char kEnableResourceContentSettings[];
extern const char kEnableSearchProviderApiV2[];
+extern const char kEnableSpeechInput[];
extern const char kEnableStatsTable[];
extern const char kEnableSync[];
+extern const char kEnableSyncApps[];
extern const char kEnableSyncAutofill[];
extern const char kEnableSyncBookmarks[];
extern const char kEnableSyncExtensions[];
extern const char kEnableSyncPasswords[];
extern const char kEnableSyncPreferences[];
+extern const char kEnableSyncSessions[];
extern const char kEnableSyncThemes[];
extern const char kEnableSyncTypedUrls[];
extern const char kEnableTabbedOptions[];
+extern const char kEnableTopSites[];
extern const char kEnableTouch[];
extern const char kEnableVerticalTabs[];
extern const char kEnableVideoFullscreen[];
@@ -136,15 +171,17 @@ extern const char kEnableVideoLogging[];
extern const char kEnableWatchdog[];
extern const char kEnableXSSAuditor[];
// Experimental features.
-extern const char kExperimentalEnableNegotiateAuth[];
+extern const char kExperimentalLocationFeatures[];
extern const char kExperimentalSpellcheckerFeatures[];
// End experimental features.
extern const char kExplicitlyAllowedPorts[];
extern const char kExtensionProcess[];
extern const char kExtensionsUpdateFrequency[];
+extern const char kFeedbackServer[];
extern const char kFileDescriptorLimit[];
extern const char kFirstRun[];
extern const char kForceFieldTestNameAndValue[];
+extern const char kForceRendererAccessibility[];
extern const char kGpuLauncher[];
extern const char kGpuProcess[];
extern const char kGpuStartupDialog[];
@@ -160,21 +197,15 @@ extern const char kImportFromFile[];
extern const char kInProcessPlugins[];
extern const char kInProcessWebGL[];
extern const char kIncognito[];
-extern const char kInstallerTestBackup[];
-extern const char kInstallerTestBuild[];
-extern const char kInstallerTestClean[];
-extern const char kInstallerTestForce[];
extern const char kInternalNaCl[];
extern const char kInternalPepper[];
-extern const char kIssue35198CrxDirBrowser[];
-extern const char kIssue35198ExtraLogging[];
-extern const char kIssue35198Permission[];
extern const char kJavaScriptFlags[];
extern const char kKeepAliveForTest[];
extern const char kLoadExtension[];
extern const char kLoadPlugin[];
extern const char kExtraPluginDir[];
extern const char kLogFilterPrefix[];
+extern const char kLogNetLog[];
extern const char kLogPluginMessages[];
extern const char kLoggingLevel[];
extern const char kMakeDefaultBrowser[];
@@ -182,6 +213,8 @@ extern const char kMediaCacheSize[];
extern const char kMemoryProfiling[];
extern const char kMessageLoopHistogrammer[];
extern const char kMetricsRecordingOnly[];
+extern const char kNaClDebugIP[];
+extern const char kNaClDebugPorts[];
extern const char kNaClBrokerProcess[];
extern const char kNaClLoaderProcess[];
extern const char kNaClStartupDialog[];
@@ -192,8 +225,11 @@ extern const char kNoJsRandomness[];
extern const char kNoProxyServer[];
extern const char kNoReferrers[];
extern const char kNoSandbox[];
+extern const char kNoStartupWindow[];
+extern const char kNotifyCloudPrintTokenExpired[];
extern const char kNumPacThreads[];
extern const char kOpenInNewWindow[];
+extern const char kOrganicInstall[];
extern const char kPackExtension[];
extern const char kPackExtensionKey[];
extern const char kParentProfile[];
@@ -203,11 +239,11 @@ extern const char kPluginLauncher[];
extern const char kPluginPath[];
extern const char kPluginProcess[];
extern const char kPluginStartupDialog[];
-extern const char kPreconnectDespiteProxy[];
extern const char kPrelaunchGpuProcess[];
extern const char kPrint[];
extern const char kProcessPerSite[];
extern const char kProcessPerTab[];
+extern const char kProcessType[];
extern const char kProductVersion[];
extern const char kProfileImportProcess[];
extern const char kProxyAutoDetect[];
@@ -224,9 +260,9 @@ extern const char kRendererCmdPrefix[];
extern const char kRendererCrashTest[];
extern const char kRendererProcess[];
extern const char kRendererStartupDialog[];
-extern const char kRestoreBackgroundContents[];
extern const char kRestoreLastSession[];
extern const char kSafePlugins[];
+extern const char kSafeBrowsingDatabaseStore[];
extern const char kSbInfoURLPrefix[];
extern const char kSbMacKeyURLPrefix[];
extern const char kSbDisableAutoUpdate[];
@@ -237,7 +273,6 @@ extern const char kServiceAccountLsid[];
extern const char kShowCompositedLayerBorders[];
extern const char kShowIcons[];
extern const char kShowPaintRects[];
-extern const char kShowPrivacyDashboardLink[];
extern const char kSilentDumpOnDCHECK[];
extern const char kSimpleDataSource[];
extern const char kSingleProcess[];
@@ -247,11 +282,11 @@ extern const char kSyncDisableTls[];
extern const char kSyncEmail[];
extern const char kSyncerThreadTimedStop[];
extern const char kSyncNotificationMethod[];
+extern const char kSyncNotificationHost[];
extern const char kSyncPassword[];
extern const char kSyncPort[];
extern const char kSyncServer[];
extern const char kSyncServiceURL[];
-extern const char kSyncUseChromeAsyncSocket[];
extern const char kSyncUseSslTcp[];
extern const char kSyncUseCacheInvalidation[];
extern const char kTestNaClSandbox[];
@@ -259,13 +294,10 @@ extern const char kTestName[];
extern const char kTestSandbox[];
extern const char kTestType[];
extern const char kTestingChannelID[];
-extern const char kTopSites[];
extern const char kTrustedPlugins[];
extern const char kTryChromeAgain[];
extern const char kUninstall[];
extern const char kUseSpdy[];
-extern const char kFixedHttpPort[];
-extern const char kFixedHttpsPort[];
extern const char kIgnoreCertificateErrors[];
extern const char kMaxSpdySessionsPerDomain[];
extern const char kUseLowFragHeapCrt[];
@@ -293,15 +325,14 @@ extern const char kLoginManager[];
extern const char kLoginScreen[];
extern const char kLoginScreenSize[];
extern const char kTestLoadLibcros[];
-extern const char kProfile[];
extern const char kLoginProfile[];
extern const char kLoginUser[];
+extern const char kLoginPassword[];
extern const char kChromeosFrame[];
-extern const char kChromeosLogToFile[];
-// TODO(denisromanov): Remove this flag when it is not needed for testing.
-extern const char kStartupManifest[];
-// TODO(denisromanov): Remove this flag when it is not needed for testing, too.
-extern const char kServicesManifest[];
+extern const char kCandidateWindowLang[];
+extern const char kBWSI[];
+extern const char kStubCros[];
+extern const char kScreenSaverUrl[];
#endif
#if defined(OS_LINUX)
@@ -322,15 +353,17 @@ extern const char kPasswordStore[];
#if defined(OS_MACOSX)
extern const char kDisableFlashCoreAnimation[];
+extern const char kDisableHolePunching[];
+extern const char kEnableExposeForTabs[];
extern const char kEnableSandboxLogging[];
#else
extern const char kKioskMode[];
#endif
#ifndef NDEBUG
+extern const char kClearTokenService[];
extern const char kGearsPluginPathOverride[];
-extern const char kInvalidateSyncLogin[];
-extern const char kInvalidateSyncXmppLogin[];
+extern const char kSetToken[];
extern const char kWebSocketLiveExperimentHost[];
#endif
diff --git a/chrome/common/chrome_version_info.cc b/chrome/common/chrome_version_info.cc
index 1b1d479..a26f81f 100644
--- a/chrome/common/chrome_version_info.cc
+++ b/chrome/common/chrome_version_info.cc
@@ -6,47 +6,82 @@
#include "base/basictypes.h"
#include "base/file_version_info.h"
+#include "base/string_util.h"
#include "build/build_config.h"
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-#include "chrome/common/chrome_version_info_posix.h"
-
-// Posix files don't have per-file version information, so we get chrome
-// version information from chrome_version_info_posix.h, a generated header.
-class ChromeVersionInfoPosix : public FileVersionInfo {
- public:
- ChromeVersionInfoPosix() {}
-
- virtual std::wstring company_name() { return COMPANY_NAME; }
- virtual std::wstring company_short_name() { return COMPANY_SHORT_NAME; }
- virtual std::wstring product_name() { return PRODUCT_NAME; }
- virtual std::wstring product_short_name() { return PRODUCT_SHORT_NAME; }
- virtual std::wstring internal_name() { return INTERNAL_NAME; }
- virtual std::wstring product_version() { return PRODUCT_VERSION; }
- virtual std::wstring private_build() { return PRIVATE_BUILD; }
- virtual std::wstring special_build() { return SPECIAL_BUILD; }
- virtual std::wstring comments() { return COMMENTS; }
- virtual std::wstring original_filename() { return ORIGINAL_FILENAME; }
- virtual std::wstring file_description() { return FILE_DESCRIPTION; }
- virtual std::wstring file_version() { return FILE_VERSION; }
- virtual std::wstring legal_copyright() { return LEGAL_COPYRIGHT; }
- virtual std::wstring legal_trademarks() { return LEGAL_TRADEMARKS; }
- virtual std::wstring last_change() { return LAST_CHANGE; }
- virtual bool is_official_build() { return OFFICIAL_BUILD; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ChromeVersionInfoPosix);
-};
-#endif
-
namespace chrome {
-FileVersionInfo* GetChromeVersionInfo() {
#if defined(OS_WIN) || defined(OS_MACOSX)
- return FileVersionInfo::CreateFileVersionInfoForCurrentModule();
+// On Windows and Mac, we get the Chrome version info by querying
+// FileVersionInfo for the current module.
+
+VersionInfo::VersionInfo() {
+ version_info_.reset(FileVersionInfo::CreateFileVersionInfoForCurrentModule());
+}
+
+VersionInfo::~VersionInfo() {
+}
+
+bool VersionInfo::is_valid() const {
+ return version_info_.get() != NULL;
+}
+
+std::string VersionInfo::Name() const {
+ if (!is_valid())
+ return std::string();
+ return WideToASCII(version_info_->product_name());
+}
+
+std::string VersionInfo::Version() const {
+ if (!is_valid())
+ return std::string();
+ return WideToASCII(version_info_->product_version());
+}
+
+std::string VersionInfo::LastChange() const {
+ if (!is_valid())
+ return std::string();
+ return WideToASCII(version_info_->last_change());
+}
+
+bool VersionInfo::IsOfficialBuild() const {
+ if (!is_valid())
+ return false;
+ return version_info_->is_official_build();
+}
+
#elif defined(OS_POSIX)
- return new ChromeVersionInfoPosix();
-#endif
+// We get chrome version information from chrome_version_info_posix.h,
+// a generated header.
+
+#include "chrome/common/chrome_version_info_posix.h"
+
+VersionInfo::VersionInfo() {
+}
+
+VersionInfo::~VersionInfo() {
+}
+
+bool VersionInfo::is_valid() const {
+ return true;
+}
+
+std::string VersionInfo::Name() const {
+ return PRODUCT_NAME;
+}
+
+std::string VersionInfo::Version() const {
+ return PRODUCT_VERSION;
+}
+
+std::string VersionInfo::LastChange() const {
+ return LAST_CHANGE;
}
+bool VersionInfo::IsOfficialBuild() const {
+ return OFFICIAL_BUILD;
+}
+
+#endif
+
} // namespace chrome
diff --git a/chrome/common/chrome_version_info.h b/chrome/common/chrome_version_info.h
index e3bfad7..0ec911e 100644
--- a/chrome/common/chrome_version_info.h
+++ b/chrome/common/chrome_version_info.h
@@ -4,14 +4,51 @@
#ifndef CHROME_COMMON_CHROME_VERSION_INFO_H_
#define CHROME_COMMON_CHROME_VERSION_INFO_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
class FileVersionInfo;
namespace chrome {
-// Creates a FileVersionInfo for the app, Chrome. Returns NULL in case of
-// error. The returned object should be deleted when you are done with it.
-FileVersionInfo* GetChromeVersionInfo();
+// An instance of chrome::VersionInfo has information about the
+// current running build of Chrome.
+class VersionInfo {
+ public:
+ VersionInfo();
+ ~VersionInfo();
+
+ // In the rare case where we fail to get the version info,
+ // is_valid() will return false. The other functions will return
+ // the empty string in this case, so it's not harmful if you don't
+ // check is_valid().
+ bool is_valid() const;
+
+ // E.g. "Chromium" or "Google Chrome".
+ std::string Name() const;
+
+ // Version number, e.g. "6.0.490.1".
+ std::string Version() const;
+
+ // The SVN revision of this release. E.g. "55800".
+ std::string LastChange() const;
+
+ // Whether this is an "official" release of the current Version():
+ // whether knowing Version() is enough to completely determine what
+ // LastChange() is.
+ bool IsOfficialBuild() const;
+
+ private:
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ scoped_ptr<FileVersionInfo> version_info_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(VersionInfo);
+};
} // namespace chrome
diff --git a/chrome/common/chrome_version_info_posix.h.version b/chrome/common/chrome_version_info_posix.h.version
index 56a8fea..670dc8c 100644
--- a/chrome/common/chrome_version_info_posix.h.version
+++ b/chrome/common/chrome_version_info_posix.h.version
@@ -5,22 +5,9 @@
#ifndef CHROME_COMMON_CHROME_VERSION_INFO_POSIX_H_
#define CHROME_COMMON_CHROME_VERSION_INFO_POSIX_H_
-#define COMPANY_NAME L"@COMPANY_FULLNAME@"
-#define FILE_DESCRIPTION L"@PRODUCT_FULLNAME@"
-#define FILE_VERSION L"@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
-#define LEGAL_COPYRIGHT L"@COPYRIGHT@"
-#define PRODUCT_NAME L"@PRODUCT_FULLNAME@"
-#define PRODUCT_VERSION L"@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
-#define COMPANY_SHORT_NAME L"@COMPANY_SHORTNAME@"
-#define PRODUCT_SHORT_NAME L"@PRODUCT_SHORTNAME@"
-#define LAST_CHANGE L"@LASTCHANGE@"
+#define PRODUCT_NAME "@PRODUCT_FULLNAME@"
+#define PRODUCT_VERSION "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+#define LAST_CHANGE "@LASTCHANGE@"
#define OFFICIAL_BUILD @OFFICIAL_BUILD@
-// TODO(mmoss) Do these have values for Linux?
-#define INTERNAL_NAME L""
-#define ORIGINAL_FILENAME L""
-#define PRIVATE_BUILD L""
-#define SPECIAL_BUILD L""
-#define COMMENTS L""
-#define LEGAL_TRADEMARKS L""
#endif // CHROME_COMMON_CHROME_VERSION_INFO_POSIX_H_
diff --git a/chrome/common/common.sb b/chrome/common/common.sb
index 71c73cf..f8d4f1c 100644
--- a/chrome/common/common.sb
+++ b/chrome/common/common.sb
@@ -3,10 +3,15 @@
;; Use of this source code is governed by a BSD-style license that can be
;; found in the LICENSE file.
;;
-; This configuration file isn't used on it's own, but instead implicity included
-; at the start of all other sandbox configuration files in Chrome.
+; This configuration file isn't used on it's own, but instead implicitly
+; included at the start of all other sandbox configuration files in Chrome.
(version 1)
-(deny default)
+
+; DISABLE_SANDBOX_DENIAL_LOGGING expands to syntax that turns off log message
+; printing on sandbox exceptions; this functionality only exists on 10.6. The
+; --enable-sandbox-logging flag or system versions <10.6 cause this flag to
+; expand to an empty string. http://crbug.com/26621
+(deny default DISABLE_SANDBOX_DENIAL_LOGGING)
; Support for programmatically enabling verbose debugging.
;ENABLE_LOGGING (debug deny)
diff --git a/chrome/common/common_glue.cc b/chrome/common/common_glue.cc
index 95417ab..5fe6094 100644
--- a/chrome/common/common_glue.cc
+++ b/chrome/common/common_glue.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.
@@ -29,13 +29,13 @@ bool IsPluginRunningInRendererProcess() {
return !IsPluginProcess();
}
-std::wstring GetWebKitLocale() {
+std::string GetWebKitLocale() {
// The browser process should have passed the locale to the renderer via the
// --lang command line flag. In single process mode, this will return the
// wrong value. TODO(tc): Fix this for single process mode.
const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
- const std::wstring& lang =
- parsed_command_line.GetSwitchValue(switches::kLang);
+ const std::string& lang =
+ parsed_command_line.GetSwitchValueASCII(switches::kLang);
DCHECK(!lang.empty() ||
(!parsed_command_line.HasSwitch(switches::kRendererProcess) &&
!parsed_command_line.HasSwitch(switches::kPluginProcess)));
@@ -43,7 +43,7 @@ std::wstring GetWebKitLocale() {
}
string16 GetLocalizedString(int message_id) {
- return WideToUTF16(l10n_util::GetString(message_id));
+ return l10n_util::GetStringUTF16(message_id);
}
} // namespace webkit_glue
diff --git a/chrome/common/common_param_traits.cc b/chrome/common/common_param_traits.cc
index e655435..41a3e2f 100644
--- a/chrome/common/common_param_traits.cc
+++ b/chrome/common/common_param_traits.cc
@@ -4,17 +4,21 @@
#include "chrome/common/common_param_traits.h"
+#include "base/time.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/content_settings.h"
+#include "chrome/common/geoposition.h"
#include "chrome/common/thumbnail_score.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
+#include "net/base/upload_data.h"
#include "printing/native_metafile.h"
#include "printing/page_range.h"
#ifndef EXCLUDE_SKIA_DEPENDENCIES
#include "third_party/skia/include/core/SkBitmap.h"
#endif
+#include "webkit/blob/blob_data.h"
#include "webkit/glue/dom_operations.h"
#include "webkit/glue/password_form.h"
@@ -93,8 +97,8 @@ bool ParamTraits<SkBitmap>::Read(const Message* m, void** iter, SkBitmap* r) {
return bmp_data->InitSkBitmapFromData(r, variable_data, variable_data_size);
}
-void ParamTraits<SkBitmap>::Log(const SkBitmap& p, std::wstring* l) {
- l->append(StringPrintf(L"<SkBitmap>"));
+void ParamTraits<SkBitmap>::Log(const SkBitmap& p, std::string* l) {
+ l->append("<SkBitmap>");
}
#endif // EXCLUDE_SKIA_DEPENDENCIES
@@ -114,8 +118,8 @@ bool ParamTraits<GURL>::Read(const Message* m, void** iter, GURL* p) {
return true;
}
-void ParamTraits<GURL>::Log(const GURL& p, std::wstring* l) {
- l->append(UTF8ToWide(p.spec()));
+void ParamTraits<GURL>::Log(const GURL& p, std::string* l) {
+ l->append(p.spec());
}
void ParamTraits<gfx::Point>::Write(Message* m, const gfx::Point& p) {
@@ -134,8 +138,8 @@ bool ParamTraits<gfx::Point>::Read(const Message* m, void** iter,
return true;
}
-void ParamTraits<gfx::Point>::Log(const gfx::Point& p, std::wstring* l) {
- l->append(StringPrintf(L"(%d, %d)", p.x(), p.y()));
+void ParamTraits<gfx::Point>::Log(const gfx::Point& p, std::string* l) {
+ l->append(StringPrintf("(%d, %d)", p.x(), p.y()));
}
@@ -160,8 +164,8 @@ bool ParamTraits<gfx::Rect>::Read(const Message* m, void** iter, gfx::Rect* r) {
return true;
}
-void ParamTraits<gfx::Rect>::Log(const gfx::Rect& p, std::wstring* l) {
- l->append(StringPrintf(L"(%d, %d, %d, %d)", p.x(), p.y(),
+void ParamTraits<gfx::Rect>::Log(const gfx::Rect& p, std::string* l) {
+ l->append(StringPrintf("(%d, %d, %d, %d)", p.x(), p.y(),
p.width(), p.height()));
}
@@ -181,8 +185,8 @@ bool ParamTraits<gfx::Size>::Read(const Message* m, void** iter, gfx::Size* r) {
return true;
}
-void ParamTraits<gfx::Size>::Log(const gfx::Size& p, std::wstring* l) {
- l->append(StringPrintf(L"(%d, %d)", p.width(), p.height()));
+void ParamTraits<gfx::Size>::Log(const gfx::Size& p, std::string* l) {
+ l->append(StringPrintf("(%d, %d)", p.width(), p.height()));
}
void ParamTraits<ContentSetting>::Write(Message* m, const param_type& p) {
@@ -200,7 +204,7 @@ bool ParamTraits<ContentSetting>::Read(const Message* m, void** iter,
return true;
}
-void ParamTraits<ContentSetting>::Log(const param_type& p, std::wstring* l) {
+void ParamTraits<ContentSetting>::Log(const param_type& p, std::string* l) {
LogParam(static_cast<int>(p), l);
}
@@ -220,8 +224,8 @@ bool ParamTraits<ContentSettings>::Read(
}
void ParamTraits<ContentSettings>::Log(
- const ContentSettings& p, std::wstring* l) {
- l->append(StringPrintf(L"<ContentSettings>"));
+ const ContentSettings& p, std::string* l) {
+ l->append("<ContentSettings>");
}
void ParamTraits<webkit_glue::WebApplicationInfo>::Write(
@@ -261,8 +265,8 @@ bool ParamTraits<webkit_glue::WebApplicationInfo>::Read(
}
void ParamTraits<webkit_glue::WebApplicationInfo>::Log(
- const webkit_glue::WebApplicationInfo& p, std::wstring* l) {
- l->append(L"<WebApplicationInfo>");
+ const webkit_glue::WebApplicationInfo& p, std::string* l) {
+ l->append("<WebApplicationInfo>");
}
void ParamTraits<URLRequestStatus>::Write(Message* m, const param_type& p) {
@@ -281,40 +285,231 @@ bool ParamTraits<URLRequestStatus>::Read(const Message* m, void** iter,
return true;
}
-void ParamTraits<URLRequestStatus>::Log(const param_type& p, std::wstring* l) {
- std::wstring status;
+void ParamTraits<URLRequestStatus>::Log(const param_type& p, std::string* l) {
+ std::string status;
switch (p.status()) {
case URLRequestStatus::SUCCESS:
- status = L"SUCCESS";
+ status = "SUCCESS";
break;
case URLRequestStatus::IO_PENDING:
- status = L"IO_PENDING ";
+ status = "IO_PENDING ";
break;
case URLRequestStatus::HANDLED_EXTERNALLY:
- status = L"HANDLED_EXTERNALLY";
+ status = "HANDLED_EXTERNALLY";
break;
case URLRequestStatus::CANCELED:
- status = L"CANCELED";
+ status = "CANCELED";
break;
case URLRequestStatus::FAILED:
- status = L"FAILED";
+ status = "FAILED";
break;
default:
- status = L"UNKNOWN";
+ status = "UNKNOWN";
break;
}
if (p.status() == URLRequestStatus::FAILED)
- l->append(L"(");
+ l->append("(");
LogParam(status, l);
if (p.status() == URLRequestStatus::FAILED) {
- l->append(L", ");
+ l->append(", ");
LogParam(p.os_error(), l);
- l->append(L")");
+ l->append(")");
}
}
+// Only the net::UploadData ParamTraits<> definition needs this definition, so
+// keep this in the implementation file so we can forward declare UploadData in
+// the header.
+template <>
+struct ParamTraits<net::UploadData::Element> {
+ typedef net::UploadData::Element param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.type()));
+ if (p.type() == net::UploadData::TYPE_BYTES) {
+ m->WriteData(&p.bytes()[0], static_cast<int>(p.bytes().size()));
+ } else if (p.type() == net::UploadData::TYPE_FILE) {
+ WriteParam(m, p.file_path());
+ WriteParam(m, p.file_range_offset());
+ WriteParam(m, p.file_range_length());
+ WriteParam(m, p.expected_file_modification_time());
+ } else {
+ WriteParam(m, p.blob_url());
+ }
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type))
+ return false;
+ if (type == net::UploadData::TYPE_BYTES) {
+ const char* data;
+ int len;
+ if (!m->ReadData(iter, &data, &len))
+ return false;
+ r->SetToBytes(data, len);
+ } else if (type == net::UploadData::TYPE_FILE) {
+ FilePath file_path;
+ uint64 offset, length;
+ base::Time expected_modification_time;
+ if (!ReadParam(m, iter, &file_path))
+ return false;
+ if (!ReadParam(m, iter, &offset))
+ return false;
+ if (!ReadParam(m, iter, &length))
+ return false;
+ if (!ReadParam(m, iter, &expected_modification_time))
+ return false;
+ r->SetToFilePathRange(file_path, offset, length,
+ expected_modification_time);
+ } else {
+ DCHECK(type == net::UploadData::TYPE_BLOB);
+ GURL blob_url;
+ if (!ReadParam(m, iter, &blob_url))
+ return false;
+ r->SetToBlobUrl(blob_url);
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<net::UploadData::Element>");
+ }
+};
+
+void ParamTraits<scoped_refptr<net::UploadData> >::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.get() != NULL);
+ if (p) {
+ WriteParam(m, *p->elements());
+ WriteParam(m, p->identifier());
+ }
+}
+
+bool ParamTraits<scoped_refptr<net::UploadData> >::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ bool has_object;
+ if (!ReadParam(m, iter, &has_object))
+ return false;
+ if (!has_object)
+ return true;
+ std::vector<net::UploadData::Element> elements;
+ if (!ReadParam(m, iter, &elements))
+ return false;
+ int64 identifier;
+ if (!ReadParam(m, iter, &identifier))
+ return false;
+ *r = new net::UploadData;
+ (*r)->swap_elements(&elements);
+ (*r)->set_identifier(identifier);
+ return true;
+}
+
+void ParamTraits<scoped_refptr<net::UploadData> >::Log(const param_type& p,
+ std::string* l) {
+ l->append("<net::UploadData>");
+}
+
+// Only the webkit_blob::BlobData ParamTraits<> definition needs this
+// definition, so keep this in the implementation file so we can forward declare
+// BlobData in the header.
+template <>
+struct ParamTraits<webkit_blob::BlobData::Item> {
+ typedef webkit_blob::BlobData::Item param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.type()));
+ if (p.type() == webkit_blob::BlobData::TYPE_DATA) {
+ WriteParam(m, p.data());
+ } else if (p.type() == webkit_blob::BlobData::TYPE_FILE) {
+ WriteParam(m, p.file_path());
+ WriteParam(m, p.offset());
+ WriteParam(m, p.length());
+ WriteParam(m, p.expected_modification_time());
+ } else {
+ WriteParam(m, p.blob_url());
+ WriteParam(m, p.offset());
+ WriteParam(m, p.length());
+ }
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type))
+ return false;
+ if (type == webkit_blob::BlobData::TYPE_DATA) {
+ std::string data;
+ if (!ReadParam(m, iter, &data))
+ return false;
+ r->SetToData(data);
+ } else if (type == webkit_blob::BlobData::TYPE_FILE) {
+ FilePath file_path;
+ uint64 offset, length;
+ base::Time expected_modification_time;
+ if (!ReadParam(m, iter, &file_path))
+ return false;
+ if (!ReadParam(m, iter, &offset))
+ return false;
+ if (!ReadParam(m, iter, &length))
+ return false;
+ if (!ReadParam(m, iter, &expected_modification_time))
+ return false;
+ r->SetToFile(file_path, offset, length, expected_modification_time);
+ } else {
+ DCHECK(type == webkit_blob::BlobData::TYPE_BLOB);
+ GURL blob_url;
+ uint64 offset, length;
+ if (!ReadParam(m, iter, &blob_url))
+ return false;
+ if (!ReadParam(m, iter, &offset))
+ return false;
+ if (!ReadParam(m, iter, &length))
+ return false;
+ r->SetToBlob(blob_url, offset, length);
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<BlobData::Item>");
+ }
+};
+
+void ParamTraits<scoped_refptr<webkit_blob::BlobData> >::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.get() != NULL);
+ if (p) {
+ WriteParam(m, p->items());
+ WriteParam(m, p->content_type());
+ WriteParam(m, p->content_disposition());
+ }
+}
+
+bool ParamTraits<scoped_refptr<webkit_blob::BlobData> >::Read(
+ const Message* m, void** iter, param_type* r) {
+ bool has_object;
+ if (!ReadParam(m, iter, &has_object))
+ return false;
+ if (!has_object)
+ return true;
+ std::vector<webkit_blob::BlobData::Item> items;
+ if (!ReadParam(m, iter, &items))
+ return false;
+ std::string content_type;
+ if (!ReadParam(m, iter, &content_type))
+ return false;
+ std::string content_disposition;
+ if (!ReadParam(m, iter, &content_disposition))
+ return false;
+ *r = new webkit_blob::BlobData;
+ (*r)->swap_items(&items);
+ (*r)->set_content_type(content_type);
+ (*r)->set_content_disposition(content_disposition);
+ return true;
+}
+
+void ParamTraits<scoped_refptr<webkit_blob::BlobData> >::Log(
+ const param_type& p, std::string* l) {
+ l->append("<webkit_blob::BlobData>");
+}
+
void ParamTraits<ThumbnailScore>::Write(Message* m, const param_type& p) {
IPC::ParamTraits<double>::Write(m, p.boring_score);
IPC::ParamTraits<bool>::Write(m, p.good_clipping);
@@ -340,30 +535,29 @@ bool ParamTraits<ThumbnailScore>::Read(const Message* m, void** iter,
return true;
}
-void ParamTraits<ThumbnailScore>::Log(const param_type& p, std::wstring* l) {
- l->append(StringPrintf(L"(%f, %d, %d)",
+void ParamTraits<ThumbnailScore>::Log(const param_type& p, std::string* l) {
+ l->append(StringPrintf("(%f, %d, %d)",
p.boring_score, p.good_clipping, p.at_top));
}
-void ParamTraits<Geoposition::ErrorCode>::Write(
- Message* m, const Geoposition::ErrorCode& p) {
- int error_code = p;
- WriteParam(m, error_code);
-}
-
-bool ParamTraits<Geoposition::ErrorCode>::Read(
- const Message* m, void** iter, Geoposition::ErrorCode* p) {
- int error_code_param = 0;
- bool ret = ReadParam(m, iter, &error_code_param);
- *p = static_cast<Geoposition::ErrorCode>(error_code_param);
- return ret;
-}
-
-void ParamTraits<Geoposition::ErrorCode>::Log(
- const Geoposition::ErrorCode& p, std::wstring* l) {
- int error_code = p;
- l->append(StringPrintf(L"<Geoposition::ErrorCode>%d", error_code));
-}
+template <>
+struct ParamTraits<Geoposition::ErrorCode> {
+ typedef Geoposition::ErrorCode param_type;
+ static void Write(Message* m, const param_type& p) {
+ int error_code = p;
+ WriteParam(m, error_code);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ int error_code_param = 0;
+ bool ret = ReadParam(m, iter, &error_code_param);
+ *p = static_cast<Geoposition::ErrorCode>(error_code_param);
+ return ret;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ int error_code = p;
+ l->append(StringPrintf("<Geoposition::ErrorCode>%d", error_code));
+ }
+};
void ParamTraits<Geoposition>::Write(Message* m, const Geoposition& p) {
WriteParam(m, p.latitude);
@@ -393,20 +587,59 @@ bool ParamTraits<Geoposition>::Read(
return ret;
}
-void ParamTraits<Geoposition>::Log(const Geoposition& p, std::wstring* l) {
+void ParamTraits<Geoposition>::Log(const Geoposition& p, std::string* l) {
l->append(
StringPrintf(
- L"<Geoposition>"
- L"%.6f %.6f %.6f %.6f "
- L"%.6f %.6f %.6f ",
+ "<Geoposition>"
+ "%.6f %.6f %.6f %.6f "
+ "%.6f %.6f %.6f ",
p.latitude, p.longitude, p.accuracy, p.altitude,
p.altitude_accuracy, p.speed, p.heading));
LogParam(p.timestamp, l);
- l->append(L" ");
- l->append(UTF8ToWide(p.error_message));
+ l->append(" ");
+ l->append(p.error_message);
LogParam(p.error_code, l);
}
+void ParamTraits<webkit_glue::PasswordForm>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.signon_realm);
+ WriteParam(m, p.origin);
+ WriteParam(m, p.action);
+ WriteParam(m, p.submit_element);
+ WriteParam(m, p.username_element);
+ WriteParam(m, p.username_value);
+ WriteParam(m, p.password_element);
+ WriteParam(m, p.password_value);
+ WriteParam(m, p.old_password_element);
+ WriteParam(m, p.old_password_value);
+ WriteParam(m, p.ssl_valid);
+ WriteParam(m, p.preferred);
+ WriteParam(m, p.blacklisted_by_user);
+}
+
+bool ParamTraits<webkit_glue::PasswordForm>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->signon_realm) &&
+ ReadParam(m, iter, &p->origin) &&
+ ReadParam(m, iter, &p->action) &&
+ ReadParam(m, iter, &p->submit_element) &&
+ ReadParam(m, iter, &p->username_element) &&
+ ReadParam(m, iter, &p->username_value) &&
+ ReadParam(m, iter, &p->password_element) &&
+ ReadParam(m, iter, &p->password_value) &&
+ ReadParam(m, iter, &p->old_password_element) &&
+ ReadParam(m, iter, &p->old_password_value) &&
+ ReadParam(m, iter, &p->ssl_valid) &&
+ ReadParam(m, iter, &p->preferred) &&
+ ReadParam(m, iter, &p->blacklisted_by_user);
+}
+void ParamTraits<webkit_glue::PasswordForm>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<PasswordForm>");
+}
+
void ParamTraits<printing::PageRange>::Write(Message* m, const param_type& p) {
WriteParam(m, p.from);
WriteParam(m, p.to);
@@ -419,12 +652,12 @@ bool ParamTraits<printing::PageRange>::Read(
}
void ParamTraits<printing::PageRange>::Log(
- const param_type& p, std::wstring* l) {
- l->append(L"(");
+ const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.to, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.from, l);
- l->append(L")");
+ l->append(")");
}
void ParamTraits<printing::NativeMetafile>::Write(
@@ -451,8 +684,51 @@ bool ParamTraits<printing::NativeMetafile>::Read(
}
void ParamTraits<printing::NativeMetafile>::Log(
- const param_type& p, std::wstring* l) {
- l->append(StringPrintf(L"<printing::NativeMetafile>"));
+ const param_type& p, std::string* l) {
+ l->append("<printing::NativeMetafile>");
+}
+
+void ParamTraits<base::PlatformFileInfo>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.size);
+ WriteParam(m, p.is_directory);
+ WriteParam(m, p.last_modified.ToDoubleT());
+ WriteParam(m, p.last_accessed.ToDoubleT());
+ WriteParam(m, p.creation_time.ToDoubleT());
+}
+
+bool ParamTraits<base::PlatformFileInfo>::Read(
+ const Message* m, void** iter, param_type* p) {
+ double last_modified;
+ double last_accessed;
+ double creation_time;
+ bool result =
+ ReadParam(m, iter, &p->size) &&
+ ReadParam(m, iter, &p->is_directory) &&
+ ReadParam(m, iter, &last_modified) &&
+ ReadParam(m, iter, &last_accessed) &&
+ ReadParam(m, iter, &creation_time);
+ if (result) {
+ p->last_modified = base::Time::FromDoubleT(last_modified);
+ p->last_accessed = base::Time::FromDoubleT(last_accessed);
+ p->creation_time = base::Time::FromDoubleT(creation_time);
+ }
+ return result;
+}
+
+void ParamTraits<base::PlatformFileInfo>::Log(
+ const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.size, l);
+ l->append(",");
+ LogParam(p.is_directory, l);
+ l->append(",");
+ LogParam(p.last_modified.ToDoubleT(), l);
+ l->append(",");
+ LogParam(p.last_accessed.ToDoubleT(), l);
+ l->append(",");
+ LogParam(p.creation_time.ToDoubleT(), l);
+ l->append(")");
}
} // namespace IPC
diff --git a/chrome/common/common_param_traits.h b/chrome/common/common_param_traits.h
index b4ec78e..a2c5dca 100644
--- a/chrome/common/common_param_traits.h
+++ b/chrome/common/common_param_traits.h
@@ -10,29 +10,31 @@
#ifndef CHROME_COMMON_COMMON_PARAM_TRAITS_H_
#define CHROME_COMMON_COMMON_PARAM_TRAITS_H_
+#pragma once
#include <vector>
#include "app/surface/transport_dib.h"
+#include "base/file_util.h"
+#include "base/ref_counted.h"
#include "chrome/common/content_settings.h"
-#include "chrome/common/geoposition.h"
#include "chrome/common/page_zoom.h"
#include "gfx/native_widget_types.h"
#include "ipc/ipc_message_utils.h"
-#include "net/base/upload_data.h"
#include "net/url_request/url_request_status.h"
#include "printing/native_metafile.h"
-#include "webkit/glue/password_form.h"
#include "webkit/glue/webcursor.h"
#include "webkit/glue/window_open_disposition.h"
// Forward declarations.
+struct Geoposition;
class GURL;
class SkBitmap;
class DictionaryValue;
class ListValue;
struct ThumbnailScore;
class URLRequestStatus;
+class WebCursor;
namespace gfx {
class Point;
@@ -40,10 +42,18 @@ class Rect;
class Size;
} // namespace gfx
+namespace net {
+class UploadData;
+}
+
namespace printing {
struct PageRange;
} // namespace printing
+namespace webkit_blob {
+class BlobData;
+}
+
namespace webkit_glue {
struct PasswordForm;
struct WebApplicationInfo;
@@ -60,7 +70,7 @@ struct ParamTraits<SkBitmap> {
// r->SetConfig() and r->SetPixels() are called.
static bool Read(const Message* m, void** iter, param_type* r);
- static void Log(const param_type& p, std::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
@@ -69,7 +79,7 @@ struct ParamTraits<GURL> {
typedef GURL 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
@@ -78,7 +88,7 @@ struct ParamTraits<gfx::Point> {
typedef gfx::Point 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
@@ -86,7 +96,7 @@ struct ParamTraits<gfx::Rect> {
typedef gfx::Rect 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
@@ -94,7 +104,7 @@ struct ParamTraits<gfx::Size> {
typedef gfx::Size 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
@@ -102,7 +112,7 @@ struct ParamTraits<ContentSetting> {
typedef ContentSetting 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
@@ -120,7 +130,7 @@ struct ParamTraits<ContentSettingsType> {
*r = static_cast<param_type>(value);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
+ static void Log(const param_type& p, std::string* l) {
LogParam(static_cast<int>(p), l);
}
};
@@ -130,7 +140,7 @@ struct ParamTraits<ContentSettings> {
typedef ContentSettings 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
@@ -160,8 +170,8 @@ struct ParamTraits<gfx::NativeWindow> {
return result;
#endif
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<gfx::NativeWindow>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<gfx::NativeWindow>");
}
};
@@ -178,7 +188,7 @@ struct ParamTraits<PageZoom::Function> {
*r = static_cast<param_type>(value);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
+ static void Log(const param_type& p, std::string* l) {
LogParam(static_cast<int>(p), l);
}
};
@@ -197,7 +207,7 @@ struct ParamTraits<WindowOpenDisposition> {
*r = static_cast<param_type>(value);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
+ static void Log(const param_type& p, std::string* l) {
LogParam(static_cast<int>(p), l);
}
};
@@ -209,11 +219,11 @@ struct ParamTraits<WebCursor> {
static void Write(Message* m, const param_type& p) {
p.Serialize(m);
}
- static bool Read(const Message* m, void** iter, param_type* r) {
+ static bool Read(const Message* m, void** iter, param_type* r) {
return r->Deserialize(m, iter);
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<WebCursor>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<WebCursor>");
}
};
@@ -223,7 +233,7 @@ struct ParamTraits<webkit_glue::WebApplicationInfo> {
typedef webkit_glue::WebApplicationInfo 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
@@ -239,12 +249,12 @@ struct ParamTraits<TransportDIB::Id> {
return (ReadParam(m, iter, &r->handle) &&
ReadParam(m, iter, &r->sequence_num));
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"TransportDIB(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("TransportDIB(");
LogParam(p.handle, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.sequence_num, l);
- l->append(L")");
+ l->append(")");
}
};
#endif
@@ -255,89 +265,25 @@ struct ParamTraits<URLRequestStatus> {
typedef URLRequestStatus 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::wstring* l);
-};
-
-
-// Traits for net::UploadData::Element.
-template <>
-struct ParamTraits<net::UploadData::Element> {
- typedef net::UploadData::Element param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, static_cast<int>(p.type()));
- if (p.type() == net::UploadData::TYPE_BYTES) {
- m->WriteData(&p.bytes()[0], static_cast<int>(p.bytes().size()));
- } else {
- WriteParam(m, p.file_path());
- WriteParam(m, p.file_range_offset());
- WriteParam(m, p.file_range_length());
- WriteParam(m, p.expected_file_modification_time());
- }
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int type;
- if (!ReadParam(m, iter, &type))
- return false;
- if (type == net::UploadData::TYPE_BYTES) {
- const char* data;
- int len;
- if (!m->ReadData(iter, &data, &len))
- return false;
- r->SetToBytes(data, len);
- } else {
- DCHECK(type == net::UploadData::TYPE_FILE);
- FilePath file_path;
- uint64 offset, length;
- base::Time expected_modification_time;
- if (!ReadParam(m, iter, &file_path))
- return false;
- if (!ReadParam(m, iter, &offset))
- return false;
- if (!ReadParam(m, iter, &length))
- return false;
- if (!ReadParam(m, iter, &expected_modification_time))
- return false;
- r->SetToFilePathRange(file_path, offset, length,
- expected_modification_time);
- }
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<net::UploadData::Element>");
- }
+ static void Log(const param_type& p, std::string* l);
};
// Traits for net::UploadData.
template <>
struct ParamTraits<scoped_refptr<net::UploadData> > {
typedef scoped_refptr<net::UploadData> param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.get() != NULL);
- if (p) {
- WriteParam(m, *p->elements());
- WriteParam(m, p->identifier());
- }
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- bool has_object;
- if (!ReadParam(m, iter, &has_object))
- return false;
- if (!has_object)
- return true;
- std::vector<net::UploadData::Element> elements;
- if (!ReadParam(m, iter, &elements))
- return false;
- int64 identifier;
- if (!ReadParam(m, iter, &identifier))
- return false;
- *r = new net::UploadData;
- (*r)->swap_elements(&elements);
- (*r)->set_identifier(identifier);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<net::UploadData>");
- }
+ 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);
+};
+
+// Traits for webkit_blob::BlobData.
+template <>
+struct ParamTraits<scoped_refptr<webkit_blob::BlobData> > {
+ typedef scoped_refptr<webkit_blob::BlobData> 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<>
@@ -345,7 +291,7 @@ struct ParamTraits<ThumbnailScore> {
typedef ThumbnailScore 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
@@ -353,74 +299,39 @@ struct ParamTraits<Geoposition> {
typedef Geoposition 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::wstring* l);
-};
-
-template <>
-struct ParamTraits<Geoposition::ErrorCode> {
- typedef Geoposition::ErrorCode 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<webkit_glue::PasswordForm> {
typedef webkit_glue::PasswordForm param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.signon_realm);
- WriteParam(m, p.origin);
- WriteParam(m, p.action);
- WriteParam(m, p.submit_element);
- WriteParam(m, p.username_element);
- WriteParam(m, p.username_value);
- WriteParam(m, p.password_element);
- WriteParam(m, p.password_value);
- WriteParam(m, p.old_password_element);
- WriteParam(m, p.old_password_value);
- WriteParam(m, p.ssl_valid);
- WriteParam(m, p.preferred);
- WriteParam(m, p.blacklisted_by_user);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->signon_realm) &&
- ReadParam(m, iter, &p->origin) &&
- ReadParam(m, iter, &p->action) &&
- ReadParam(m, iter, &p->submit_element) &&
- ReadParam(m, iter, &p->username_element) &&
- ReadParam(m, iter, &p->username_value) &&
- ReadParam(m, iter, &p->password_element) &&
- ReadParam(m, iter, &p->password_value) &&
- ReadParam(m, iter, &p->old_password_element) &&
- ReadParam(m, iter, &p->old_password_value) &&
- ReadParam(m, iter, &p->ssl_valid) &&
- ReadParam(m, iter, &p->preferred) &&
- ReadParam(m, iter, &p->blacklisted_by_user);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<PasswordForm>");
- }
+ 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<printing::PageRange> {
typedef printing::PageRange 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::wstring* l);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<printing::NativeMetafile> {
typedef printing::NativeMetafile 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);
+};
- static void Log(const param_type& p, std::wstring* l);
+template <>
+struct ParamTraits<base::PlatformFileInfo> {
+ typedef base::PlatformFileInfo 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
diff --git a/chrome/common/common_param_traits_unittest.cc b/chrome/common/common_param_traits_unittest.cc
index 032f471..aed1c36 100644
--- a/chrome/common/common_param_traits_unittest.cc
+++ b/chrome/common/common_param_traits_unittest.cc
@@ -8,6 +8,7 @@
#include "base/scoped_ptr.h"
#include "base/values.h"
#include "chrome/common/common_param_traits.h"
+#include "chrome/common/geoposition.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message.h"
@@ -146,21 +147,21 @@ TEST(IPCMessageTest, ListValue) {
TEST(IPCMessageTest, DictionaryValue) {
DictionaryValue input;
- input.Set(L"null", Value::CreateNullValue());
- input.Set(L"bool", Value::CreateBooleanValue(true));
- input.Set(L"int", Value::CreateIntegerValue(42));
+ input.Set("null", Value::CreateNullValue());
+ input.Set("bool", Value::CreateBooleanValue(true));
+ input.Set("int", Value::CreateIntegerValue(42));
scoped_ptr<DictionaryValue> subdict(new DictionaryValue());
- subdict->Set(L"str", Value::CreateStringValue("forty two"));
- subdict->Set(L"bool", Value::CreateBooleanValue(false));
+ subdict->Set("str", Value::CreateStringValue("forty two"));
+ subdict->Set("bool", Value::CreateBooleanValue(false));
scoped_ptr<ListValue> sublist(new ListValue());
sublist->Set(0, Value::CreateRealValue(42.42));
sublist->Set(1, Value::CreateStringValue("forty"));
sublist->Set(2, Value::CreateStringValue("two"));
- subdict->Set(L"list", sublist.release());
+ subdict->Set("list", sublist.release());
- input.Set(L"dict", subdict.release());
+ input.Set("dict", subdict.release());
IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
IPC::WriteParam(&msg, input);
@@ -207,13 +208,13 @@ TEST(IPCMessageTest, Geoposition) {
EXPECT_EQ(input.error_code, output.error_code);
EXPECT_EQ(input.error_message, output.error_message);
- std::wstring log_message;
+ std::string log_message;
IPC::LogParam(output, &log_message);
- EXPECT_STREQ(L"<Geoposition>"
- L"0.100000 51.300000 13.700000 42.240000 "
- L"9.300000 55.000000 120.000000 "
- L"1977 unittest error message for geoposition"
- L"<Geoposition::ErrorCode>2",
+ EXPECT_STREQ("<Geoposition>"
+ "0.100000 51.300000 13.700000 42.240000 "
+ "9.300000 55.000000 120.000000 "
+ "1977 unittest error message for geoposition"
+ "<Geoposition::ErrorCode>2",
log_message.c_str());
}
@@ -232,8 +233,9 @@ TEST(IPCMessageTest, PageRange) {
EXPECT_TRUE(input == output);
}
+// Enabling this test breaks assert handling for test suite. Bug 55177.
// Tests printing::NativeMetafile serialization.
-TEST(IPCMessageTest, Metafile) {
+TEST(IPCMessageTest, DISABLED_Metafile) {
// TODO(sanjeevr): Make this test meaningful for non-Windows platforms. We
// need to initialize the metafile using alternate means on the other OSes.
#if defined(OS_WIN)
diff --git a/chrome/common/content_settings.h b/chrome/common/content_settings.h
index 10fdcb5..4731263 100644
--- a/chrome/common/content_settings.h
+++ b/chrome/common/content_settings.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_CONTENT_SETTINGS_H_
#define CHROME_COMMON_CONTENT_SETTINGS_H_
+#pragma once
#include "chrome/common/content_settings_types.h"
diff --git a/chrome/common/content_settings_helper.h b/chrome/common/content_settings_helper.h
index 0aa2947..58fb85e 100644
--- a/chrome/common/content_settings_helper.h
+++ b/chrome/common/content_settings_helper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_CONTENT_SETTINGS_HELPER_H_
#define CHROME_COMMON_CONTENT_SETTINGS_HELPER_H_
+#pragma once
#include <string>
diff --git a/chrome/common/content_settings_types.h b/chrome/common/content_settings_types.h
index 2e2a563..938adbf 100644
--- a/chrome/common/content_settings_types.h
+++ b/chrome/common/content_settings_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_CONTENT_SETTINGS_TYPES_H_
#define CHROME_COMMON_CONTENT_SETTINGS_TYPES_H_
+#pragma once
// A particular type of content to care about. We give the user various types
// of controls over each of these.
diff --git a/chrome/common/css_colors.h b/chrome/common/css_colors.h
index d952e98..9ba36ba 100644
--- a/chrome/common/css_colors.h
+++ b/chrome/common/css_colors.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_CSS_COLORS_H_
#define CHROME_COMMON_CSS_COLORS_H_
+#pragma once
#include <utility>
diff --git a/chrome/common/database_util.cc b/chrome/common/database_util.cc
index c62e5fa..412debc 100644
--- a/chrome/common/database_util.cc
+++ b/chrome/common/database_util.cc
@@ -7,7 +7,7 @@
#include "chrome/common/child_thread.h"
#include "chrome/common/render_messages.h"
#include "ipc/ipc_sync_message_filter.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
using WebKit::WebKitClient;
diff --git a/chrome/common/database_util.h b/chrome/common/database_util.h
index 9c263af..b297044 100644
--- a/chrome/common/database_util.h
+++ b/chrome/common/database_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_DATABASE_UTIL_H_
#define CHROME_COMMON_DATABASE_UTIL_H_
+#pragma once
#include "webkit/glue/webkitclient_impl.h"
diff --git a/chrome/common/db_message_filter.h b/chrome/common/db_message_filter.h
index 1cb07d8..1eb0d5c 100644
--- a/chrome/common/db_message_filter.h
+++ b/chrome/common/db_message_filter.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_DB_MESSAGE_FILTER_H_
#define CHROME_COMMON_DB_MESSAGE_FILTER_H_
+#pragma once
#include "ipc/ipc_channel_proxy.h"
diff --git a/chrome/common/debug_flags.cc b/chrome/common/debug_flags.cc
index dd2eaee..31c6c0a 100644
--- a/chrome/common/debug_flags.cc
+++ b/chrome/common/debug_flags.cc
@@ -29,7 +29,7 @@ bool DebugFlags::ProcessDebugFlags(CommandLine* command_line,
command_line->AppendSwitch(switches::kDebugOnStart);
should_help_child = true;
}
- command_line->AppendSwitchWithValue(switches::kDebugChildren, value);
+ command_line->AppendSwitchASCII(switches::kDebugChildren, value);
} else if (current_cmd_line.HasSwitch(switches::kWaitForDebuggerChildren)) {
// Look to pass-on the kWaitForDebugger flag.
std::string value = current_cmd_line.GetSwitchValueASCII(
@@ -43,8 +43,7 @@ bool DebugFlags::ProcessDebugFlags(CommandLine* command_line,
value == switches::kPluginProcess)) {
command_line->AppendSwitch(switches::kWaitForDebugger);
}
- command_line->AppendSwitchWithValue(switches::kWaitForDebuggerChildren,
- value);
+ command_line->AppendSwitchASCII(switches::kWaitForDebuggerChildren, value);
}
return should_help_child;
}
diff --git a/chrome/common/debug_flags.h b/chrome/common/debug_flags.h
index 231d2ca..9671e47 100644
--- a/chrome/common/debug_flags.h
+++ b/chrome/common/debug_flags.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_DEBUG_FLAGS_H__
#define CHROME_COMMON_DEBUG_FLAGS_H__
+#pragma once
#include "chrome/common/child_process_info.h"
diff --git a/chrome/common/default_plugin.h b/chrome/common/default_plugin.h
index e3394e8..6cc8348 100644
--- a/chrome/common/default_plugin.h
+++ b/chrome/common/default_plugin.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_DEFAULT_PLUGIN_H_
#define CHROME_COMMON_DEFAULT_PLUGIN_H_
+#pragma once
namespace chrome {
diff --git a/chrome/common/deprecated/event_sys-inl.h b/chrome/common/deprecated/event_sys-inl.h
index 62fa350..2699a58 100644
--- a/chrome/common/deprecated/event_sys-inl.h
+++ b/chrome/common/deprecated/event_sys-inl.h
@@ -4,10 +4,10 @@
#ifndef CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_
#define CHROME_COMMON_DEPRECATED_EVENT_SYS_INL_H_
+#pragma once
#include <map>
-#include "base/atomicops.h"
#include "base/basictypes.h"
#include "base/condition_variable.h"
#include "base/lock.h"
diff --git a/chrome/common/deprecated/event_sys.h b/chrome/common/deprecated/event_sys.h
index bec8144..6e34eb7 100644
--- a/chrome/common/deprecated/event_sys.h
+++ b/chrome/common/deprecated/event_sys.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_DEPRECATED_EVENT_SYS_H_
#define CHROME_COMMON_DEPRECATED_EVENT_SYS_H_
+#pragma once
// TODO: This class should be removed or moved to Notifier code.
// See Bug 42450 (http://code.google.com/p/chromium/issues/detail?id=42450).
@@ -19,6 +20,9 @@ template <typename EventType>
class EventListener {
public:
virtual void HandleEvent(const EventType& event) = 0;
+
+ protected:
+ virtual ~EventListener() {}
};
// See the -inl.h for details about the following.
diff --git a/chrome/common/deprecated/event_sys_unittest.cc b/chrome/common/deprecated/event_sys_unittest.cc
index c70d3f7..2c55038 100644
--- a/chrome/common/deprecated/event_sys_unittest.cc
+++ b/chrome/common/deprecated/event_sys_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.
@@ -8,7 +8,6 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/logging.h"
#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "base/port.h"
diff --git a/chrome/common/desktop_notifications/active_notification_tracker.cc b/chrome/common/desktop_notifications/active_notification_tracker.cc
index 9822711..01f39dd 100644
--- a/chrome/common/desktop_notifications/active_notification_tracker.cc
+++ b/chrome/common/desktop_notifications/active_notification_tracker.cc
@@ -55,6 +55,16 @@ void ActiveNotificationTracker::Clear() {
}
}
+void ActiveNotificationTracker::DetachAll() {
+ ReverseTable::iterator iter;
+ for (iter = reverse_notification_table_.begin();
+ iter != reverse_notification_table_.end();
+ ++iter) {
+ WebNotification notification(iter->first);
+ notification.detachPresenter();
+ }
+}
+
WebNotificationPermissionCallback* ActiveNotificationTracker::GetCallback(
int id) {
return callback_table_.Lookup(id);
diff --git a/chrome/common/desktop_notifications/active_notification_tracker.h b/chrome/common/desktop_notifications/active_notification_tracker.h
index 1676f32..07f2d72 100644
--- a/chrome/common/desktop_notifications/active_notification_tracker.h
+++ b/chrome/common/desktop_notifications/active_notification_tracker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_
#define CHROME_COMMON_DESKTOP_NOTIFICATIONS_ACTIVE_NOTIFICATION_TRACKER_H_
+#pragma once
#include <map>
@@ -38,6 +39,10 @@ class ActiveNotificationTracker {
// Clears out all active notifications. Useful on page navigation.
void Clear();
+ // Detaches all active notifications from their presenter. Necessary
+ // when the Presenter is destroyed.
+ void DetachAll();
+
private:
typedef std::map<WebKit::WebNotification, int> ReverseTable;
diff --git a/chrome/common/devtools_messages.cc b/chrome/common/devtools_messages.cc
new file mode 100644
index 0000000..8ea923e
--- /dev/null
+++ b/chrome/common/devtools_messages.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/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 a46d72b..060c4d9 100644
--- a/chrome/common/devtools_messages.h
+++ b/chrome/common/devtools_messages.h
@@ -4,33 +4,13 @@
#ifndef CHROME_COMMON_DEVTOOLS_MESSAGES_H_
#define CHROME_COMMON_DEVTOOLS_MESSAGES_H_
+#pragma once
-#include "ipc/ipc_message_utils.h"
-#include "webkit/glue/devtools_message_data.h"
-
-namespace IPC {
+#include <map>
-// Traits for DevToolsMessageData structure to pack/unpack.
-template <>
-struct ParamTraits<DevToolsMessageData> {
- typedef DevToolsMessageData param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.class_name);
- WriteParam(m, p.method_name);
- WriteParam(m, p.arguments);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->class_name) &&
- ReadParam(m, iter, &p->method_name) &&
- ReadParam(m, iter, &p->arguments);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<DevToolsMessageData>");
- }
-};
+#include "ipc/ipc_message_utils.h"
-} // namespace IPC
+typedef std::map<std::string, std::string> DevToolsRuntimeProperties;
#define MESSAGES_INTERNAL_FILE "chrome/common/devtools_messages_internal.h"
#include "ipc/ipc_message_macros.h"
diff --git a/chrome/common/devtools_messages_internal.h b/chrome/common/devtools_messages_internal.h
index dcc8eee..ac8dbce 100644
--- a/chrome/common/devtools_messages_internal.h
+++ b/chrome/common/devtools_messages_internal.h
@@ -43,15 +43,22 @@
// This file describes developer tools message types.
#include "ipc/ipc_message_macros.h"
-#include "webkit/glue/devtools_message_data.h"
// These are messages sent from DevToolsAgent to DevToolsClient through the
// browser.
IPC_BEGIN_MESSAGES(DevToolsClient)
- // Sends glue-level Rpc message to the client.
- IPC_MESSAGE_CONTROL1(DevToolsClientMsg_RpcMessage,
- DevToolsMessageData /* message data */)
+ // WebKit-level transport.
+ IPC_MESSAGE_CONTROL1(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ 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)
@@ -63,14 +70,17 @@ IPC_BEGIN_MESSAGES(DevToolsAgent)
// Tells agent that there is a client host connected to it.
IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_Attach,
- std::vector<std::string> /* runtime_features */)
+ DevToolsRuntimeProperties /* properties */)
// Tells agent that there is no longer a client host connected to it.
IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_Detach)
- // Sends glue-level Rpc message to the agent.
- IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_RpcMessage,
- DevToolsMessageData /* message data */)
+ // 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
@@ -79,12 +89,6 @@ IPC_BEGIN_MESSAGES(DevToolsAgent)
IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_DebuggerCommand,
std::string /* command */)
- // This command is sent to debugger when user wants to pause script execution
- // immediately. This message should be processed on the IO thread so that it
- // can have effect even if the Renderer thread is busy with JavaScript
- // execution.
- IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_DebuggerPauseScript)
-
// Inspect element with the given coordinates.
IPC_MESSAGE_CONTROL2(DevToolsAgentMsg_InspectElement,
int /* x */,
diff --git a/chrome/common/dom_storage_common.h b/chrome/common/dom_storage_common.h
index 96fc508..21ba19c 100644
--- a/chrome/common/dom_storage_common.h
+++ b/chrome/common/dom_storage_common.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef CHROME_COMMON_DOM_STORAGE_COMMON_H_
#define CHROME_COMMON_DOM_STORAGE_COMMON_H_
+#pragma once
const int64 kLocalStorageNamespaceId = 0;
const int64 kInvalidSessionStorageNamespaceId = kLocalStorageNamespaceId;
diff --git a/chrome/common/edit_command.h b/chrome/common/edit_command.h
index 4fc373e..f9acb14 100644
--- a/chrome/common/edit_command.h
+++ b/chrome/common/edit_command.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_EDIT_COMMAND_H_
#define CHROME_COMMON_EDIT_COMMAND_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/common/env_vars.h b/chrome/common/env_vars.h
index 1c5bc5d..e9984d2 100644
--- a/chrome/common/env_vars.h
+++ b/chrome/common/env_vars.h
@@ -6,6 +6,7 @@
#ifndef CHROME_COMMON_ENV_VARS_H__
#define CHROME_COMMON_ENV_VARS_H__
+#pragma once
namespace env_vars {
diff --git a/chrome/common/font_descriptor_mac.h b/chrome/common/font_descriptor_mac.h
index 25ae9db..37b963e 100644
--- a/chrome/common/font_descriptor_mac.h
+++ b/chrome/common/font_descriptor_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_
#define CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_
+#pragma once
#include "base/string16.h"
@@ -18,13 +19,13 @@ struct FontDescriptor {
explicit FontDescriptor(NSFont* font);
FontDescriptor() : font_point_size(0) {}
-
+
// Return an autoreleased NSFont corresponding to the font description.
NSFont* nsFont() const;
// Name of the font.
string16 font_name;
-
+
// Size in points.
float font_point_size;
};
diff --git a/chrome/common/font_loader_mac.h b/chrome/common/font_loader_mac.h
index 2ec42bc..d25ec43 100644
--- a/chrome/common/font_loader_mac.h
+++ b/chrome/common/font_loader_mac.h
@@ -4,11 +4,11 @@
#ifndef CHROME_COMMON_FONT_LOADER_MAC_H_
#define CHROME_COMMON_FONT_LOADER_MAC_H_
+#pragma once
#include <ApplicationServices/ApplicationServices.h>
#include "base/shared_memory.h"
-#include "base/string16.h"
#ifdef __OBJC__
@class NSFont;
diff --git a/chrome/common/font_loader_mac.mm b/chrome/common/font_loader_mac.mm
index 849ae87..b88bffe 100644
--- a/chrome/common/font_loader_mac.mm
+++ b/chrome/common/font_loader_mac.mm
@@ -66,7 +66,7 @@ bool FontLoader::LoadFontIntoBuffer(NSFont* font_to_encode,
}
int32 font_file_size_32 = static_cast<int32>(font_file_size_64);
- if (!font_data->Create(L"", false, false, font_file_size_32)) {
+ if (!font_data->Create("", false, false, font_file_size_32)) {
LOG(ERROR) << "Failed to create shmem area for " << font_name;
return false;
}
diff --git a/chrome/common/gears_api.h b/chrome/common/gears_api.h
index 9aba014..2b2f425 100644
--- a/chrome/common/gears_api.h
+++ b/chrome/common/gears_api.h
@@ -6,6 +6,7 @@
#ifndef CHROME_COMMON_GEARS_API_H__
#define CHROME_COMMON_GEARS_API_H__
+#pragma once
#include "chrome/common/chrome_plugin_api.h"
diff --git a/chrome/common/geoposition.h b/chrome/common/geoposition.h
index f2db64c..6b19275 100644
--- a/chrome/common/geoposition.h
+++ b/chrome/common/geoposition.h
@@ -8,6 +8,7 @@
#ifndef CHROME_COMMON_GEOPOSITION_H_
#define CHROME_COMMON_GEOPOSITION_H_
+#pragma once
#include <string>
#include "base/time.h"
diff --git a/chrome/common/gpu_info.cc b/chrome/common/gpu_info.cc
index b1add77..9f16bdb 100644
--- a/chrome/common/gpu_info.cc
+++ b/chrome/common/gpu_info.cc
@@ -5,8 +5,15 @@
#include "chrome/common/gpu_info.h"
GPUInfo::GPUInfo()
- : vendor_id_(0), device_id_(0), driver_version_(L""),
- pixel_shader_version_(0), vertex_shader_version_(0) {
+ : initialized_(false), vendor_id_(0), device_id_(0), driver_version_(L""),
+ pixel_shader_version_(0),
+ vertex_shader_version_(0),
+ gl_version_(0),
+ can_lose_context_(false) {
+}
+
+bool GPUInfo::initialized() const {
+ return initialized_;
}
uint32 GPUInfo::vendor_id() const {
@@ -29,13 +36,27 @@ uint32 GPUInfo::vertex_shader_version() const {
return vertex_shader_version_;
}
+uint32 GPUInfo::gl_version() const {
+ return gl_version_;
+}
+
+
+bool GPUInfo::can_lose_context() const {
+ return can_lose_context_;
+}
+
void GPUInfo::SetGraphicsInfo(uint32 vendor_id, uint32 device_id,
const std::wstring& driver_version,
uint32 pixel_shader_version,
- uint32 vertex_shader_version) {
+ uint32 vertex_shader_version,
+ uint32 gl_version,
+ bool can_lose_context) {
vendor_id_ = vendor_id;
device_id_ = device_id;
driver_version_ = driver_version;
pixel_shader_version_ = pixel_shader_version;
vertex_shader_version_ = vertex_shader_version;
+ gl_version_ = gl_version;
+ can_lose_context_ = can_lose_context;
+ initialized_ = true;
}
diff --git a/chrome/common/gpu_info.h b/chrome/common/gpu_info.h
index 65b5075..2f8f9da 100644
--- a/chrome/common/gpu_info.h
+++ b/chrome/common/gpu_info.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_GPU_INFO_H__
#define CHROME_COMMON_GPU_INFO_H__
+#pragma once
// Provides access to the GPU information for the system
// on which chrome is currently running.
@@ -17,6 +18,9 @@ class GPUInfo {
GPUInfo();
~GPUInfo() {}
+ // Returns whether this GPUInfo has been initialized with information
+ bool initialized() const;
+
// Return the DWORD (uint32) representing the graphics card vendor id.
uint32 vendor_id() const;
@@ -38,17 +42,33 @@ class GPUInfo {
// should be okay.
uint32 vertex_shader_version() const;
+ // Return the version of OpenGL we are using.
+ // Major version in the high word, minor in the low word, eg version 2.5
+ // would be 0x00020005.
+ // Returns 0 if we're not using OpenGL, say because we're going through
+ // D3D instead.
+ uint32 gl_version() const;
+
+ // Return the device semantics, i.e. whether the Vista and Windows 7 specific
+ // semantics are available.
+ bool can_lose_context() const;
+
// Populate variables with passed in values
void SetGraphicsInfo(uint32 vendor_id, uint32 device_id,
const std::wstring& driver_version,
uint32 pixel_shader_version,
- uint32 vertex_shader_version);
+ uint32 vertex_shader_version,
+ uint32 gl_version,
+ bool can_lose_context);
private:
+ bool initialized_;
uint32 vendor_id_;
uint32 device_id_;
std::wstring driver_version_;
uint32 pixel_shader_version_;
uint32 vertex_shader_version_;
+ uint32 gl_version_;
+ bool can_lose_context_;
};
#endif // CHROME_COMMON_GPU_INFO_H__
diff --git a/chrome/common/gpu_info_unittest.cc b/chrome/common/gpu_info_unittest.cc
index 4d469f6..a209aa9 100644
--- a/chrome/common/gpu_info_unittest.cc
+++ b/chrome/common/gpu_info_unittest.cc
@@ -1,8 +1,7 @@
-// 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.
-#include "base/logging.h"
#include "chrome/common/gpu_info.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/common/gpu_messages.cc b/chrome/common/gpu_messages.cc
new file mode 100644
index 0000000..34f051c
--- /dev/null
+++ b/chrome/common/gpu_messages.cc
@@ -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/common/gpu_messages.h"
+
+#include "chrome/common/gpu_info.h"
+#include "gfx/rect.h"
+#include "gfx/size.h"
+#include "ipc/ipc_channel_handle.h"
+
+#define MESSAGES_INTERNAL_IMPL_FILE \
+ "chrome/common/gpu_messages_internal.h"
+#include "ipc/ipc_message_impl_macros.h"
+
+#if defined(OS_MACOSX)
+
+// Parameters for the GpuHostMsg_AcceleratedSurfaceSetIOSurface
+// message, which has too many parameters to be sent with the
+// predefined IPC macros.
+GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params::
+ GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params()
+ : renderer_id(0),
+ render_view_id(0),
+ window(NULL),
+ width(0),
+ height(0),
+ identifier(0) {
+}
+
+#endif
+
+namespace IPC {
+
+#if defined(OS_MACOSX)
+
+void ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> ::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.renderer_id);
+ WriteParam(m, p.render_view_id);
+ WriteParam(m, p.window);
+ WriteParam(m, p.width);
+ WriteParam(m, p.height);
+ WriteParam(m, p.identifier);
+}
+
+bool ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> ::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->renderer_id) &&
+ ReadParam(m, iter, &p->render_view_id) &&
+ ReadParam(m, iter, &p->window) &&
+ ReadParam(m, iter, &p->width) &&
+ ReadParam(m, iter, &p->height) &&
+ ReadParam(m, iter, &p->identifier);
+}
+
+void ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> ::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.renderer_id, l);
+ l->append(", ");
+ LogParam(p.render_view_id, l);
+ l->append(", ");
+ LogParam(p.window, l);
+ l->append(", ");
+ LogParam(p.width, l);
+ l->append(", ");
+ LogParam(p.height, l);
+ l->append(", ");
+ LogParam(p.identifier, l);
+ l->append(")");
+}
+
+#endif // if defined(OS_MACOSX)
+
+void ParamTraits<GPUInfo> ::Write(Message* m, const param_type& p) {
+ m->WriteUInt32(p.vendor_id());
+ m->WriteUInt32(p.device_id());
+ m->WriteWString(p.driver_version());
+ m->WriteUInt32(p.pixel_shader_version());
+ m->WriteUInt32(p.vertex_shader_version());
+ m->WriteUInt32(p.gl_version());
+ m->WriteBool(p.can_lose_context());
+}
+
+bool ParamTraits<GPUInfo> ::Read(const Message* m, void** iter, param_type* p) {
+ uint32 vendor_id;
+ uint32 device_id;
+ std::wstring driver_version;
+ uint32 pixel_shader_version;
+ uint32 vertex_shader_version;
+ uint32 gl_version;
+ bool can_lose_context;
+ bool ret = m->ReadUInt32(iter, &vendor_id);
+ ret = ret && m->ReadUInt32(iter, &device_id);
+ ret = ret && m->ReadWString(iter, &driver_version);
+ ret = ret && m->ReadUInt32(iter, &pixel_shader_version);
+ ret = ret && m->ReadUInt32(iter, &vertex_shader_version);
+ ret = ret && m->ReadUInt32(iter, &gl_version);
+ ret = ret && m->ReadBool(iter, &can_lose_context);
+ p->SetGraphicsInfo(vendor_id,
+ device_id,
+ driver_version,
+ pixel_shader_version,
+ vertex_shader_version,
+ gl_version,
+ can_lose_context);
+ return ret;
+}
+
+void ParamTraits<GPUInfo> ::Log(const param_type& p, std::string* l) {
+ l->append(StringPrintf("<GPUInfo> %x %x %ls %d",
+ p.vendor_id(),
+ p.device_id(),
+ p.driver_version().c_str(),
+ p.can_lose_context()));
+}
+
+void ParamTraits<gpu::CommandBuffer::State> ::Write(Message* m,
+ const param_type& p) {
+ m->WriteInt(p.num_entries);
+ m->WriteInt(p.get_offset);
+ m->WriteInt(p.put_offset);
+ m->WriteInt(p.token);
+ m->WriteInt(p.error);
+}
+
+bool ParamTraits<gpu::CommandBuffer::State> ::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int32 temp;
+ if (m->ReadInt(iter, &p->num_entries) &&
+ m->ReadInt(iter, &p->get_offset) &&
+ m->ReadInt(iter, &p->put_offset) &&
+ m->ReadInt(iter, &p->token) &&
+ m->ReadInt(iter, &temp)) {
+ p->error = static_cast<gpu::error::Error>(temp);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void ParamTraits<gpu::CommandBuffer::State> ::Log(const param_type& p,
+ std::string* l) {
+ l->append("<CommandBuffer::State>");
+}
+
+} // namespace IPC
diff --git a/chrome/common/gpu_messages.h b/chrome/common/gpu_messages.h
index 16f2860..799bc98 100644
--- a/chrome/common/gpu_messages.h
+++ b/chrome/common/gpu_messages.h
@@ -4,84 +4,18 @@
#ifndef CHROME_COMMON_GPU_MESSAGES_H_
#define CHROME_COMMON_GPU_MESSAGES_H_
+#pragma once
-#include <vector>
-
-#include "app/surface/transport_dib.h"
#include "base/basictypes.h"
#include "base/process.h"
#include "chrome/common/common_param_traits.h"
-#include "chrome/common/gpu_info.h"
#include "chrome/common/gpu_native_window_handle.h"
+#include "chrome/common/gpu_param_traits.h"
#include "gfx/native_widget_types.h"
-#include "gfx/rect.h"
-#include "gfx/size.h"
#include "gpu/command_buffer/common/command_buffer.h"
-namespace IPC {
-template <>
-struct ParamTraits<GPUInfo> {
- typedef GPUInfo param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteUInt32(p.vendor_id());
- m->WriteUInt32(p.device_id());
- m->WriteWString(p.driver_version());
- m->WriteUInt32(p.pixel_shader_version());
- m->WriteUInt32(p.vertex_shader_version());
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- uint32 vendor_id;
- uint32 device_id;
- std::wstring driver_version;
- uint32 pixel_shader_version;
- uint32 vertex_shader_version;
- bool ret = m->ReadUInt32(iter, &vendor_id);
- ret = ret && m->ReadUInt32(iter, &device_id);
- ret = ret && m->ReadWString(iter, &driver_version);
- ret = ret && m->ReadUInt32(iter, &pixel_shader_version);
- ret = ret && m->ReadUInt32(iter, &vertex_shader_version);
- p->SetGraphicsInfo(vendor_id, device_id, driver_version,
- pixel_shader_version, vertex_shader_version);
- return ret;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(StringPrintf(L"<GPUInfo> %x %x %ls",
- p.vendor_id(), p.device_id(), p.driver_version().c_str()));
- }
-};
-
-template <>
-struct ParamTraits<gpu::CommandBuffer::State> {
- typedef gpu::CommandBuffer::State param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p.num_entries);
- m->WriteInt(p.get_offset);
- m->WriteInt(p.put_offset);
- m->WriteInt(p.token);
- m->WriteInt(p.error);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int32 temp;
- if (m->ReadInt(iter, &p->num_entries) &&
- m->ReadInt(iter, &p->get_offset) &&
- m->ReadInt(iter, &p->put_offset) &&
- m->ReadInt(iter, &p->token) &&
- m->ReadInt(iter, &temp)) {
- p->error = static_cast<gpu::error::Error>(temp);
- return true;
- } else {
- return false;
- }
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<CommandBuffer::State>");
- }
-};
-} // namespace IPC
-
#define MESSAGES_INTERNAL_FILE \
"chrome/common/gpu_messages_internal.h"
#include "ipc/ipc_message_macros.h"
#endif // CHROME_COMMON_GPU_MESSAGES_H_
-
diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h
index fa9a83f..7b2c44a 100644
--- a/chrome/common/gpu_messages_internal.h
+++ b/chrome/common/gpu_messages_internal.h
@@ -9,11 +9,19 @@
// This file needs to be included again, even though we're actually included
// from it via utility_messages.h.
#include "base/shared_memory.h"
-#include "chrome/common/gpu_info.h"
-#include "gfx/size.h"
-#include "ipc/ipc_channel_handle.h"
+#include "chrome/common/gpu_video_common.h"
#include "ipc/ipc_message_macros.h"
+namespace gfx {
+class Size;
+}
+
+namespace IPC {
+struct ChannelHandle;
+}
+
+class GPUInfo;
+
//------------------------------------------------------------------------------
// GPU Messages
// These are messages from the browser to the GPU process.
@@ -38,6 +46,16 @@ IPC_BEGIN_MESSAGES(Gpu)
GpuNativeWindowHandle, /* parent window */
int32 /* view_id */)
+ // Tells the GPU process to create a context for collecting graphics card
+ // information.
+ IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo)
+
+ // Tells the GPU process to crash.
+ IPC_MESSAGE_CONTROL0(GpuMsg_Crash)
+
+ // Tells the GPU process to hang.
+ IPC_MESSAGE_CONTROL0(GpuMsg_Hang)
+
// Creates a new backing store.
IPC_MESSAGE_ROUTED2(GpuMsg_NewBackingStore,
int32, /* backing_store_routing_id */
@@ -98,11 +116,31 @@ IPC_BEGIN_MESSAGES(GpuHost)
// 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 */)
+
#if defined(OS_LINUX)
// Get the XID for a view ID.
IPC_SYNC_MESSAGE_CONTROL1_1(GpuHostMsg_GetViewXID,
gfx::NativeViewId, /* view */
unsigned long /* xid */)
+#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_CONTROL3(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
+ int32, /* renderer_id */
+ int32, /* render_view_id */
+ gfx::PluginWindowHandle /* window */)
#endif
IPC_END_MESSAGES(GpuHost)
@@ -113,9 +151,12 @@ IPC_END_MESSAGES(GpuHost)
IPC_BEGIN_MESSAGES(GpuChannel)
// Tells the GPU process to create a new command buffer that renders directly
- // to a native view. A corresponding GpuCommandBufferStub is created.
- IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_CreateViewCommandBuffer,
+ // 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_CONTROL2_1(GpuChannelMsg_CreateViewCommandBuffer,
gfx::NativeViewId, /* view */
+ int32, /* render_view_id */
int32 /* route_id */)
// Tells the GPU process to create a new command buffer that renders to an
@@ -130,18 +171,33 @@ IPC_BEGIN_MESSAGES(GpuChannel)
int32 /* route_id */)
// The CommandBufferProxy sends this to the GpuCommandBufferStub in its
- // destructor, so that the stub deletes the actual WebPluginDelegateImpl
+ // destructor, so that the stub deletes the actual CommandBufferService
// object that it's hosting.
// TODO(apatrick): Implement this.
- IPC_MESSAGE_CONTROL1(GpuChannelMsg_DestroyCommandBuffer,
- int32 /* instance_id */)
+ IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyCommandBuffer,
+ int32 /* instance_id */)
+
+ // Get hardware video service routing id.
+ IPC_SYNC_MESSAGE_CONTROL0_1(GpuChannelMsg_GetVideoService,
+ GpuVideoServiceInfoParam)
+
+ // 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_SYNC_MESSAGE_CONTROL0_1(GpuChannelMsg_CreateVideoDecoder,
+ GpuVideoDecoderInfoParam)
+
+ // Release all resource of the hardware video decoder which was assocaited
+ // with the input |decoder_id|.
+ IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyVideoDecoder,
+ int32 /* decoder_id */)
IPC_END_MESSAGES(GpuChannel)
//------------------------------------------------------------------------------
// GPU Command Buffer Messages
-// These are messages from a renderer process to the GPU process relating to a
-// single OpenGL context.
+// 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
@@ -171,10 +227,14 @@ IPC_BEGIN_MESSAGES(GpuCommandBuffer)
int32 /* put_offset */)
// Return the current state of the command buffer following a request via
- // an AsyncGetState or AsyncFlush message.
+ // 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,
@@ -208,6 +268,90 @@ IPC_BEGIN_MESSAGES(GpuCommandBuffer)
// browser. This message is currently used only on 10.6 and later.
IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetWindowSize,
gfx::Size /* size */)
+
+ // This message is sent from the GPU process to the renderer process (and
+ // from there the browser process) that the buffers associated with the
+ // given "window" were swapped, which should cause the browser to redraw
+ // the various accelerated surfaces.
+ IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_AcceleratedSurfaceBuffersSwapped,
+ gfx::PluginWindowHandle /* window */)
#endif
IPC_END_MESSAGES(GpuCommandBuffer)
+
+//------------------------------------------------------------------------------
+
+// GpuVideoDecoderMsgs : send 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)
+
+ // Start decoder flushing operation.
+ IPC_MESSAGE_ROUTED0(GpuVideoDecoderMsg_Flush)
+
+ // Send input buffer to GpuVideoDecoder.
+ IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_EmptyThisBuffer,
+ GpuVideoDecoderInputBufferParam)
+
+ // Ask the GPU process to produce a video frame with the ID.
+ IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_ProduceVideoFrame,
+ int32) /* Video Frame ID */
+
+ // 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 */
+
+IPC_END_MESSAGES(GpuVideoDecoder)
+
+//------------------------------------------------------------------------------
+
+// GpuVideoDecoderMsgs : send from gpu process to renderer process.
+IPC_BEGIN_MESSAGES(GpuVideoDecoderHost)
+ // Confirm GpuVideoDecoder had been initialized or failed to initialize.
+ IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_InitializeACK,
+ GpuVideoDecoderInitDoneParam)
+
+ // Confrim GpuVideoDecoder had been destroyed properly.
+ IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_DestroyACK)
+
+ // Confirm decoder had been flushed.
+ IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_FlushACK)
+
+ // GpuVideoDecoder has consumed input buffer from transfer buffer.
+ 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 ms */
+ int64, /* Duration in ms */
+ int32) /* Flags */
+
+ // Allocate video frames for output of the hardware video decoder.
+ IPC_MESSAGE_ROUTED4(GpuVideoDecoderHostMsg_AllocateVideoFrames,
+ int32, /* Numer 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)
diff --git a/chrome/common/gpu_messages_unittest.cc b/chrome/common/gpu_messages_unittest.cc
index 5215949..455458f 100644
--- a/chrome/common/gpu_messages_unittest.cc
+++ b/chrome/common/gpu_messages_unittest.cc
@@ -1,8 +1,7 @@
-// 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.
-#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "chrome/common/gpu_info.h"
#include "chrome/common/gpu_messages.h"
@@ -15,7 +14,10 @@ TEST(GPUIPCMessageTest, GPUInfo) {
GPUInfo input;
// Test variables taken from Lenovo T61
input.SetGraphicsInfo(0x10de, 0x429, L"6.14.11.7715",
- 0xffff0300, 0xfffe0300);
+ 0xffff0300,
+ 0xfffe0300,
+ 0x00010005,
+ true);
IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
IPC::WriteParam(&msg, input);
@@ -28,8 +30,10 @@ TEST(GPUIPCMessageTest, GPUInfo) {
EXPECT_EQ(input.driver_version(), output.driver_version());
EXPECT_EQ(input.pixel_shader_version(), output.pixel_shader_version());
EXPECT_EQ(input.vertex_shader_version(), output.vertex_shader_version());
+ EXPECT_EQ(input.gl_version(), output.gl_version());
+ EXPECT_EQ(input.can_lose_context(), output.can_lose_context());
- std::wstring log_message;
+ std::string log_message;
IPC::LogParam(output, &log_message);
- EXPECT_STREQ(L"<GPUInfo> 10de 429 6.14.11.7715", log_message.c_str());
+ EXPECT_STREQ("<GPUInfo> 10de 429 6.14.11.7715 1", log_message.c_str());
}
diff --git a/chrome/common/gpu_native_window_handle.h b/chrome/common/gpu_native_window_handle.h
index 11e8cda..cdc89f7 100644
--- a/chrome/common/gpu_native_window_handle.h
+++ b/chrome/common/gpu_native_window_handle.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_GPU_NATIVE_WINDOW_HANDLE_H_
#define CHROME_COMMON_GPU_NATIVE_WINDOW_HANDLE_H_
+#pragma once
#include "build/build_config.h"
diff --git a/chrome/common/gpu_param_traits.h b/chrome/common/gpu_param_traits.h
new file mode 100644
index 0000000..d8ca851
--- /dev/null
+++ b/chrome/common/gpu_param_traits.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_COMMON_GPU_PARAM_TRAITS_H_
+#define CHROME_COMMON_GPU_PARAM_TRAITS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "chrome/common/common_param_traits.h"
+#include "chrome/common/gpu_info.h"
+#include "chrome/common/gpu_native_window_handle.h"
+#include "gfx/native_widget_types.h"
+#include "gfx/rect.h"
+#include "gfx/size.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+
+#if defined(OS_MACOSX)
+// Parameters for the GpuHostMsg_AcceleratedSurfaceSetIOSurface
+// message, which has too many parameters to be sent with the
+// predefined IPC macros.
+struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params {
+ int32 renderer_id;
+ int32 render_view_id;
+ gfx::PluginWindowHandle window;
+ int32 width;
+ int32 height;
+ uint64 identifier;
+
+ GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params();
+};
+#endif
+
+namespace IPC {
+#if defined(OS_MACOSX)
+template <>
+struct ParamTraits<GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params> {
+ typedef GpuHostMsg_AcceleratedSurfaceSetIOSurface_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);
+};
+#endif
+
+template <>
+struct ParamTraits<GPUInfo> {
+ typedef GPUInfo 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<gpu::CommandBuffer::State> {
+ typedef gpu::CommandBuffer::State 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_GPU_PARAM_TRAITS_H_
diff --git a/chrome/common/gpu_plugin.cc b/chrome/common/gpu_plugin.cc
index af009f9..84ab339 100644
--- a/chrome/common/gpu_plugin.cc
+++ b/chrome/common/gpu_plugin.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/string_util.h"
+#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"
diff --git a/chrome/common/gpu_plugin.h b/chrome/common/gpu_plugin.h
index 3fd609e..938cbc2 100644
--- a/chrome/common/gpu_plugin.h
+++ b/chrome/common/gpu_plugin.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_GPU_PLUGIN_H_
#define CHROME_COMMON_GPU_PLUGIN_H_
+#pragma once
namespace chrome {
diff --git a/chrome/common/gpu_video_common.cc b/chrome/common/gpu_video_common.cc
new file mode 100644
index 0000000..556e385
--- /dev/null
+++ b/chrome/common/gpu_video_common.cc
@@ -0,0 +1,231 @@
+// Copyright (c) 2010 The Chromium Authors. All 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/gpu_video_common.h"
+
+namespace IPC {
+
+void ParamTraits<GpuVideoServiceInfoParam>::Write(
+ Message* m, const GpuVideoServiceInfoParam& p) {
+ WriteParam(m, p.video_service_route_id);
+ WriteParam(m, p.video_service_host_route_id);
+ WriteParam(m, p.service_available);
+}
+
+bool ParamTraits<GpuVideoServiceInfoParam>::Read(
+ const Message* m, void** iter, GpuVideoServiceInfoParam* r) {
+ if (!ReadParam(m, iter, &r->video_service_route_id) ||
+ !ReadParam(m, iter, &r->video_service_host_route_id) ||
+ !ReadParam(m, iter, &r->service_available))
+ return false;
+ return true;
+}
+
+void ParamTraits<GpuVideoServiceInfoParam>::Log(
+ const GpuVideoServiceInfoParam& p, std::string* l) {
+ l->append(StringPrintf("(%d, %d, %d)",
+ p.video_service_route_id,
+ p.video_service_host_route_id,
+ p.service_available));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ParamTraits<GpuVideoDecoderInfoParam>::Write(
+ Message* m, const GpuVideoDecoderInfoParam& p) {
+ WriteParam(m, p.context_id);
+ WriteParam(m, p.decoder_id);
+ WriteParam(m, p.decoder_route_id);
+ WriteParam(m, p.decoder_host_route_id);
+}
+
+bool ParamTraits<GpuVideoDecoderInfoParam>::Read(
+ const Message* m, void** iter, GpuVideoDecoderInfoParam* r) {
+ if (!ReadParam(m, iter, &r->context_id) ||
+ !ReadParam(m, iter, &r->decoder_id) ||
+ !ReadParam(m, iter, &r->decoder_route_id) ||
+ !ReadParam(m, iter, &r->decoder_host_route_id))
+ return false;
+ return true;
+}
+
+void ParamTraits<GpuVideoDecoderInfoParam>::Log(
+ const GpuVideoDecoderInfoParam& p, std::string* l) {
+ l->append(StringPrintf("(%d, %d, %d)",
+ p.decoder_id,
+ p.decoder_route_id,
+ p.decoder_host_route_id));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ParamTraits<GpuVideoDecoderInitParam>::Write(
+ Message* m, const GpuVideoDecoderInitParam& p) {
+ WriteParam(m, p.codec_id);
+ WriteParam(m, p.width);
+ WriteParam(m, p.height);
+}
+
+bool ParamTraits<GpuVideoDecoderInitParam>::Read(
+ const Message* m, void** iter, GpuVideoDecoderInitParam* r) {
+ if (!ReadParam(m, iter, &r->codec_id) ||
+ !ReadParam(m, iter, &r->width) ||
+ !ReadParam(m, iter, &r->height))
+ return false;
+ return true;
+}
+
+void ParamTraits<GpuVideoDecoderInitParam>::Log(
+ const GpuVideoDecoderInitParam& p, std::string* l) {
+ l->append(StringPrintf("(%d, %d %d)", p.codec_id, p.width, p.height));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ParamTraits<GpuVideoDecoderInitDoneParam>::Write(
+ Message* m, const GpuVideoDecoderInitDoneParam& p) {
+ WriteParam(m, p.success);
+ WriteParam(m, p.input_buffer_size);
+ WriteParam(m, p.input_buffer_handle);
+}
+
+bool ParamTraits<GpuVideoDecoderInitDoneParam>::Read(
+ const Message* m, void** iter, GpuVideoDecoderInitDoneParam* r) {
+ if (!ReadParam(m, iter, &r->success) ||
+ !ReadParam(m, iter, &r->input_buffer_size) ||
+ !ReadParam(m, iter, &r->input_buffer_handle))
+ return false;
+ return true;
+}
+
+void ParamTraits<GpuVideoDecoderInitDoneParam>::Log(
+ const GpuVideoDecoderInitDoneParam& p, std::string* l) {
+ l->append(StringPrintf("(%d %d)", p.success, p.input_buffer_size));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ParamTraits<GpuVideoDecoderInputBufferParam>::Write(
+ Message* m, const GpuVideoDecoderInputBufferParam& p) {
+ WriteParam(m, p.timestamp);
+ WriteParam(m, p.offset);
+ WriteParam(m, p.size);
+}
+
+bool ParamTraits<GpuVideoDecoderInputBufferParam>::Read(
+ const Message* m, void** iter, GpuVideoDecoderInputBufferParam* r) {
+ if (!ReadParam(m, iter, &r->timestamp) ||
+ !ReadParam(m, iter, &r->offset) ||
+ !ReadParam(m, iter, &r->size))
+ return false;
+ return true;
+}
+
+void ParamTraits<GpuVideoDecoderInputBufferParam>::Log(
+ const GpuVideoDecoderInputBufferParam& p, std::string* l) {
+ l->append(StringPrintf("(%d %d %d)",
+ static_cast<int>(p.timestamp),
+ p.offset, p.size));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ParamTraits<GpuVideoDecoderErrorInfoParam>::Write(
+ Message* m, const GpuVideoDecoderErrorInfoParam& p) {
+ WriteParam(m, p.error_id);
+}
+
+bool ParamTraits<GpuVideoDecoderErrorInfoParam>::Read(
+ const Message* m, void** iter, GpuVideoDecoderErrorInfoParam* r) {
+ if (!ReadParam(m, iter, &r->error_id))
+ return false;
+ return true;
+}
+
+void ParamTraits<GpuVideoDecoderErrorInfoParam>::Log(
+ const GpuVideoDecoderErrorInfoParam& p, std::string* l) {
+ l->append(StringPrintf("(%d)", p.error_id));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ParamTraits<GpuVideoDecoderFormatChangeParam>::Write(
+ Message* m, const GpuVideoDecoderFormatChangeParam& p) {
+ WriteParam(m, p.input_buffer_size);
+}
+
+bool ParamTraits<GpuVideoDecoderFormatChangeParam>::Read(
+ const Message* m, void** iter, GpuVideoDecoderFormatChangeParam* r) {
+ if (!ReadParam(m, iter, &r->input_buffer_size))
+ return false;
+ return true;
+}
+
+void ParamTraits<GpuVideoDecoderFormatChangeParam>::Log(
+ const GpuVideoDecoderFormatChangeParam& p, std::string* l) {
+ l->append(StringPrintf("%d", p.input_buffer_size));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Traits for media::VideoFrame::Format
+void ParamTraits<media::VideoFrame::Format>::Write(
+ Message* m, const param_type& p) {
+ m->WriteInt(p);
+}
+
+bool ParamTraits<media::VideoFrame::Format>::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<media::VideoFrame::Format>::Log(
+ const param_type& p, std::string* l) {
+ std::string s;
+ switch (p) {
+ case media::VideoFrame::RGB555:
+ s = "RGB555";
+ break;
+ case media::VideoFrame::RGB565:
+ s = "RGB565";
+ break;
+ case media::VideoFrame::RGB24:
+ s = "RGB24";
+ break;
+ case media::VideoFrame::RGB32:
+ s = "RGB32";
+ break;
+ case media::VideoFrame::RGBA:
+ s = "RGBA";
+ break;
+ case media::VideoFrame::YV12:
+ s = "YV12";
+ break;
+ case media::VideoFrame::YV16:
+ s = "YV16";
+ break;
+ case media::VideoFrame::NV12:
+ s = "NV12";
+ break;
+ case media::VideoFrame::EMPTY:
+ s = "EMPTY";
+ break;
+ case media::VideoFrame::ASCII:
+ s = "ASCII";
+ break;
+ case media::VideoFrame::INVALID:
+ s = "INVALID";
+ break;
+ default:
+ NOTIMPLEMENTED();
+ s = "UNKNOWN";
+ break;
+ }
+ LogParam(s, l);
+}
+
+} // namespace IPC
diff --git a/chrome/common/gpu_video_common.h b/chrome/common/gpu_video_common.h
new file mode 100644
index 0000000..30a94be
--- /dev/null
+++ b/chrome/common/gpu_video_common.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.
+
+#ifndef CHROME_COMMON_GPU_VIDEO_COMMON_H_
+#define CHROME_COMMON_GPU_VIDEO_COMMON_H_
+
+#include "base/basictypes.h"
+#include "base/shared_memory.h"
+#include "chrome/common/common_param_traits.h"
+#include "media/base/video_frame.h"
+
+// Flags assigned to a video buffer for both input and output.
+enum GpuVideoBufferFlag {
+ kGpuVideoEndOfStream = 1 << 0,
+ kGpuVideoDiscontinuous = 1 << 1,
+};
+
+struct GpuVideoServiceInfoParam {
+ // route id for GpuVideoService on GPU process side for this channel.
+ int32 video_service_route_id;
+ // route id for GpuVideoServiceHost on Render process side for this channel.
+ int32 video_service_host_route_id;
+ // TODO(jiesun): define capabilities of video service.
+ int32 service_available;
+};
+
+struct GpuVideoDecoderInfoParam {
+ // Context ID of the GLES2 context what this decoder should assicate with.
+ int context_id;
+
+ // Global decoder id.
+ int32 decoder_id;
+
+ // Route id for GpuVideoDecoder on GPU process side for this channel.
+ int32 decoder_route_id;
+
+ // TODO(hclam): Merge this ID with |decoder_route_id_|.
+ // Route id for GpuVideoServiceHost on Render process side for this channel.
+ int32 decoder_host_route_id;
+};
+
+struct GpuVideoDecoderInitParam {
+ int32 codec_id;
+ int32 width;
+ int32 height;
+ int32 profile;
+ int32 level;
+ int32 frame_rate_den;
+ int32 frame_rate_num;
+ int32 aspect_ratio_den;
+ int32 aspect_ratio_num;
+};
+
+struct GpuVideoDecoderInitDoneParam {
+ int32 success; // other parameter is only meaningful when this is true.
+ int32 input_buffer_size;
+ base::SharedMemoryHandle input_buffer_handle;
+};
+
+struct GpuVideoDecoderInputBufferParam {
+ int64 timestamp; // In unit of microseconds.
+ int32 offset;
+ int32 size;
+ int32 flags; // Miscellaneous flag bit mask.
+};
+
+struct GpuVideoDecoderErrorInfoParam {
+ int32 error_id; // TODO(jiesun): define enum.
+};
+
+// TODO(jiesun): define this.
+struct GpuVideoDecoderFormatChangeParam {
+ int32 input_buffer_size;
+ base::SharedMemoryHandle input_buffer_handle;
+};
+
+namespace IPC {
+
+template <>
+struct ParamTraits<GpuVideoServiceInfoParam> {
+ typedef GpuVideoServiceInfoParam 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<GpuVideoDecoderInfoParam> {
+ typedef GpuVideoDecoderInfoParam 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<GpuVideoDecoderInitParam> {
+ typedef GpuVideoDecoderInitParam 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<GpuVideoDecoderInitDoneParam> {
+ typedef GpuVideoDecoderInitDoneParam 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<GpuVideoDecoderInputBufferParam> {
+ typedef GpuVideoDecoderInputBufferParam 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<GpuVideoDecoderErrorInfoParam> {
+ typedef GpuVideoDecoderErrorInfoParam 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<GpuVideoDecoderFormatChangeParam> {
+ typedef GpuVideoDecoderFormatChangeParam 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<media::VideoFrame::Format> {
+ typedef media::VideoFrame::Format 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_GPU_VIDEO_COMMON_H_
diff --git a/chrome/common/important_file_writer.cc b/chrome/common/important_file_writer.cc
index 3466958..2d9503d 100644
--- a/chrome/common/important_file_writer.cc
+++ b/chrome/common/important_file_writer.cc
@@ -13,7 +13,7 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/task.h"
#include "base/thread.h"
#include "base/time.h"
@@ -52,25 +52,19 @@ class WriteToDiskTask : public Task {
}
if (bytes_written < data_.length()) {
file_util::Delete(tmp_file_path, false);
- LogFailure("error writing, bytes_written=" + UintToString(
- static_cast<unsigned int>(bytes_written)));
+ LogFailure("error writing, bytes_written=" +
+ base::Uint64ToString(bytes_written));
return;
}
- if (file_util::ReplaceFile(tmp_file_path, path_)) {
- LogSuccess();
+ if (!file_util::ReplaceFile(tmp_file_path, path_)) {
+ file_util::Delete(tmp_file_path, false);
+ LogFailure("could not rename temporary file");
return;
}
-
- file_util::Delete(tmp_file_path, false);
- LogFailure("could not rename temporary file");
}
private:
- void LogSuccess() {
- LOG(INFO) << "successfully saved " << path_.value();
- }
-
void LogFailure(const std::string& message) {
LOG(WARNING) << "failed to write " << path_.value()
<< ": " << message;
diff --git a/chrome/common/important_file_writer.h b/chrome/common/important_file_writer.h
index d4f57a0..5fdabce 100644
--- a/chrome/common/important_file_writer.h
+++ b/chrome/common/important_file_writer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_IMPORTANT_FILE_WRITER_H_
#define CHROME_COMMON_IMPORTANT_FILE_WRITER_H_
+#pragma once
#include <string>
@@ -61,7 +62,7 @@ class ImportantFileWriter : public NonThreadSafe {
// of destruction.
~ImportantFileWriter();
- FilePath path() const { return path_; }
+ const FilePath& path() const { return path_; }
// Returns true if there is a scheduled write pending which has not yet
// been started.
diff --git a/chrome/common/indexed_db_key.cc b/chrome/common/indexed_db_key.cc
index 1c09ea2..315e5b2 100644
--- a/chrome/common/indexed_db_key.cc
+++ b/chrome/common/indexed_db_key.cc
@@ -10,14 +10,12 @@
using WebKit::WebIDBKey;
IndexedDBKey::IndexedDBKey()
- : type_(WebIDBKey::InvalidType) {
+ : type_(WebIDBKey::InvalidType),
+ number_(0) {
}
-IndexedDBKey::IndexedDBKey(const WebIDBKey& key)
- : type_(key.type()),
- string_(key.type() == WebIDBKey::StringType
- ? static_cast<string16>(key.string()) : string16()),
- number_(key.type() == WebIDBKey::NumberType ? key.number() : 0) {
+IndexedDBKey::IndexedDBKey(const WebIDBKey& key) {
+ Set(key);
}
void IndexedDBKey::SetNull() {
@@ -38,6 +36,13 @@ void IndexedDBKey::Set(int32_t number) {
number_ = number;
}
+void IndexedDBKey::Set(const WebIDBKey& key) {
+ type_ = key.type();
+ string_ = key.type() == WebIDBKey::StringType ?
+ static_cast<string16>(key.string()) : string16();
+ number_ = key.type() == WebIDBKey::NumberType ? key.number() : 0;
+}
+
IndexedDBKey::operator WebIDBKey() const {
switch (type_) {
case WebIDBKey::NullType:
diff --git a/chrome/common/indexed_db_key.h b/chrome/common/indexed_db_key.h
index 13bfae3..41fb10b 100644
--- a/chrome/common/indexed_db_key.h
+++ b/chrome/common/indexed_db_key.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_INDEXED_DB_KEY_H_
#define CHROME_COMMON_INDEXED_DB_KEY_H_
+#pragma once
#include "base/basictypes.h"
#include "base/string16.h"
@@ -18,6 +19,7 @@ class IndexedDBKey {
void SetInvalid();
void Set(const string16& string);
void Set(int32_t number);
+ void Set(const WebKit::WebIDBKey& key);
WebKit::WebIDBKey::Type type() const { return type_; }
const string16& string() const { return string_; }
diff --git a/chrome/common/indexed_db_param_traits.cc b/chrome/common/indexed_db_param_traits.cc
new file mode 100644
index 0000000..fd47ecf
--- /dev/null
+++ b/chrome/common/indexed_db_param_traits.cc
@@ -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.
+
+#include "chrome/common/indexed_db_param_traits.h"
+
+#include "chrome/common/indexed_db_key.h"
+#include "chrome/common/serialized_script_value.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace IPC {
+
+void ParamTraits<SerializedScriptValue>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.is_null());
+ WriteParam(m, p.is_invalid());
+ WriteParam(m, p.data());
+}
+
+bool ParamTraits<SerializedScriptValue>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ bool is_null;
+ bool is_invalid;
+ string16 data;
+ bool ok =
+ ReadParam(m, iter, &is_null) &&
+ ReadParam(m, iter, &is_invalid) &&
+ ReadParam(m, iter, &data);
+ if (!ok)
+ return false;
+ r->set_is_null(is_null);
+ r->set_is_invalid(is_invalid);
+ r->set_data(data);
+ return true;
+}
+
+void ParamTraits<SerializedScriptValue>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<SerializedScriptValue>(");
+ LogParam(p.is_null(), l);
+ l->append(", ");
+ LogParam(p.is_invalid(), l);
+ l->append(", ");
+ LogParam(p.data(), l);
+ l->append(")");
+}
+
+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.number());
+}
+
+bool ParamTraits<IndexedDBKey>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ int type;
+ string16 string;
+ int32 number;
+ bool ok =
+ ReadParam(m, iter, &type) &&
+ ReadParam(m, iter, &string) &&
+ ReadParam(m, iter, &number);
+ if (!ok)
+ return false;
+ switch (type) {
+ case WebKit::WebIDBKey::NullType:
+ r->SetNull();
+ return true;
+ case WebKit::WebIDBKey::StringType:
+ r->Set(string);
+ return true;
+ case WebKit::WebIDBKey::NumberType:
+ r->Set(number);
+ return true;
+ case WebKit::WebIDBKey::InvalidType:
+ r->SetInvalid();
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+void ParamTraits<IndexedDBKey>::Log(const param_type& p, std::string* l) {
+ l->append("<IndexedDBKey>(");
+ LogParam(int(p.type()), l);
+ l->append(", ");
+ LogParam(p.string(), l);
+ l->append(", ");
+ LogParam(p.number(), l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/indexed_db_param_traits.h b/chrome/common/indexed_db_param_traits.h
new file mode 100644
index 0000000..2e43f3e
--- /dev/null
+++ b/chrome/common/indexed_db_param_traits.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_INDEXED_DB_PARAM_TRAITS_H_
+#define CHROME_COMMON_INDEXED_DB_PARAM_TRAITS_H_
+#pragma once
+
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_param_traits.h"
+
+class IndexedDBKey;
+class SerializedScriptValue;
+
+namespace IPC {
+
+// These datatypes are used by utility_messages.h and render_messages.h.
+// Unfortunately we can't move it to common: MSVC linker complains about
+// WebKit datatypes that are not linked on npchrome_frame (even though it's
+// never actually used by that target).
+
+template <>
+struct ParamTraits<SerializedScriptValue> {
+ typedef SerializedScriptValue 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<IndexedDBKey> {
+ typedef IndexedDBKey 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_INDEXED_DB_PARAM_TRAITS_H_
diff --git a/chrome/common/ipc_test_sink.cc b/chrome/common/ipc_test_sink.cc
index 04fd065..45db8f5 100644
--- a/chrome/common/ipc_test_sink.cc
+++ b/chrome/common/ipc_test_sink.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "chrome/common/ipc_test_sink.h"
+#include "ipc/ipc_message.h"
namespace IPC {
diff --git a/chrome/common/ipc_test_sink.h b/chrome/common/ipc_test_sink.h
index 96e91c0..caf6276 100644
--- a/chrome/common/ipc_test_sink.h
+++ b/chrome/common/ipc_test_sink.h
@@ -4,16 +4,18 @@
#ifndef CHROME_COMMON_IPC_TEST_SINK_H_
#define CHROME_COMMON_IPC_TEST_SINK_H_
+#pragma once
#include <utility>
#include <vector>
#include "base/basictypes.h"
#include "ipc/ipc_channel.h"
-#include "ipc/ipc_message.h"
namespace IPC {
+class Message;
+
// This test sink provides a "sink" for IPC messages that are sent. It allows
// the caller to query messages received in various different ways. It is
// designed for tests for objects that use the IPC system.
diff --git a/chrome/common/json_pref_store.cc b/chrome/common/json_pref_store.cc
index 9acfcb2..d68307f 100644
--- a/chrome/common/json_pref_store.cc
+++ b/chrome/common/json_pref_store.cc
@@ -31,6 +31,10 @@ JsonPrefStore::~JsonPrefStore() {
}
PrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
+ if (path_.empty()) {
+ read_only_ = true;
+ return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
+ }
JSONFileValueSerializer serializer(path_);
int error_code = 0;
@@ -127,4 +131,3 @@ bool JsonPrefStore::SerializeData(std::string* output) {
scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren());
return serializer.Serialize(*(copy.get()));
}
-
diff --git a/chrome/common/json_pref_store.h b/chrome/common/json_pref_store.h
index 70f5dee..ed17bbe 100644
--- a/chrome/common/json_pref_store.h
+++ b/chrome/common/json_pref_store.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_JSON_PREF_STORE_H_
#define CHROME_COMMON_JSON_PREF_STORE_H_
+#pragma once
#include <string>
diff --git a/chrome/common/json_pref_store_unittest.cc b/chrome/common/json_pref_store_unittest.cc
index 7d00030..e38aba2 100644
--- a/chrome/common/json_pref_store_unittest.cc
+++ b/chrome/common/json_pref_store_unittest.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 "app/test/data/resource.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
@@ -99,17 +99,17 @@ TEST_F(JsonPrefStoreTest, Basic) {
// }
// }
- const wchar_t kNewWindowsInTabs[] = L"tabs.new_windows_in_tabs";
- const wchar_t kMaxTabs[] = L"tabs.max_tabs";
- const wchar_t kLongIntPref[] = L"long_int.pref";
+ const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
+ const char kMaxTabs[] = "tabs.max_tabs";
+ const char kLongIntPref[] = "long_int.pref";
- std::wstring cnn(L"http://www.cnn.com");
+ std::string cnn("http://www.cnn.com");
- std::wstring string_value;
+ std::string string_value;
EXPECT_TRUE(prefs->GetString(prefs::kHomePage, &string_value));
EXPECT_EQ(cnn, string_value);
- const wchar_t kSomeDirectory[] = L"some_directory";
+ const char kSomeDirectory[] = "some_directory";
FilePath::StringType path;
EXPECT_TRUE(prefs->GetString(kSomeDirectory, &path));
@@ -135,9 +135,11 @@ TEST_F(JsonPrefStoreTest, Basic) {
EXPECT_TRUE(prefs->GetInteger(kMaxTabs, &integer));
EXPECT_EQ(10, integer);
- prefs->SetString(kLongIntPref, Int64ToWString(214748364842LL));
+ prefs->SetString(kLongIntPref, base::Int64ToString(214748364842LL));
EXPECT_TRUE(prefs->GetString(kLongIntPref, &string_value));
- EXPECT_EQ(214748364842LL, StringToInt64(WideToUTF16Hack(string_value)));
+ int64 value;
+ base::StringToInt64(string_value, &value);
+ EXPECT_EQ(214748364842LL, value);
// Serialize and compare to expected output.
FilePath output_file = input_file;
diff --git a/chrome/common/json_value_serializer.h b/chrome/common/json_value_serializer.h
index 7919cfe..11b7b7a 100644
--- a/chrome/common/json_value_serializer.h
+++ b/chrome/common/json_value_serializer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_JSON_VALUE_SERIALIZER_H_
#define CHROME_COMMON_JSON_VALUE_SERIALIZER_H_
+#pragma once
#include <string>
diff --git a/chrome/common/json_value_serializer_unittest.cc b/chrome/common/json_value_serializer_unittest.cc
index 3f40dcc..b3f3e0d 100644
--- a/chrome/common/json_value_serializer_unittest.cc
+++ b/chrome/common/json_value_serializer_unittest.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,7 +7,9 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/path_service.h"
+#include "base/string16.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/json_value_serializer.h"
@@ -24,20 +26,20 @@ TEST(JSONValueSerializerTest, Roundtrip) {
DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
Value* null_value = NULL;
- ASSERT_TRUE(root_dict->Get(L"null", &null_value));
+ ASSERT_TRUE(root_dict->Get("null", &null_value));
ASSERT_TRUE(null_value);
ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL));
bool bool_value = false;
- ASSERT_TRUE(root_dict->GetBoolean(L"bool", &bool_value));
+ ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
ASSERT_TRUE(bool_value);
int int_value = 0;
- ASSERT_TRUE(root_dict->GetInteger(L"int", &int_value));
+ ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
ASSERT_EQ(42, int_value);
double real_value = 0.0;
- ASSERT_TRUE(root_dict->GetReal(L"real", &real_value));
+ ASSERT_TRUE(root_dict->GetReal("real", &real_value));
ASSERT_DOUBLE_EQ(3.14, real_value);
// We shouldn't be able to write using this serializer, since it was
@@ -71,9 +73,9 @@ TEST(JSONValueSerializerTest, Roundtrip) {
}
TEST(JSONValueSerializerTest, StringEscape) {
- std::wstring all_chars;
+ string16 all_chars;
for (int i = 1; i < 256; ++i) {
- all_chars += static_cast<wchar_t>(i);
+ all_chars += static_cast<char16>(i);
}
// Generated in in Firefox using the following js (with an extra backslash for
// double quote):
@@ -105,7 +107,7 @@ TEST(JSONValueSerializerTest, StringEscape) {
// Test JSONWriter interface
std::string output_js;
DictionaryValue valueRoot;
- valueRoot.SetString(L"all_chars", all_chars);
+ valueRoot.SetString("all_chars", all_chars);
base::JSONWriter::Write(&valueRoot, false, &output_js);
ASSERT_EQ(expected_output, output_js);
@@ -118,8 +120,8 @@ TEST(JSONValueSerializerTest, StringEscape) {
TEST(JSONValueSerializerTest, UnicodeStrings) {
// unicode string json -> escaped ascii text
DictionaryValue root;
- std::wstring test(L"\x7F51\x9875");
- root.SetString(L"web", test);
+ string16 test(WideToUTF16(L"\x7F51\x9875"));
+ root.SetString("web", test);
std::string expected = "{\"web\":\"\\u7F51\\u9875\"}";
@@ -134,16 +136,16 @@ TEST(JSONValueSerializerTest, UnicodeStrings) {
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
static_cast<DictionaryValue*>(deserial_root.get());
- std::wstring web_value;
- ASSERT_TRUE(dict_root->GetString(L"web", &web_value));
+ string16 web_value;
+ ASSERT_TRUE(dict_root->GetString("web", &web_value));
ASSERT_EQ(test, web_value);
}
TEST(JSONValueSerializerTest, HexStrings) {
// hex string json -> escaped ascii text
DictionaryValue root;
- std::wstring test(L"\x01\x02");
- root.SetString(L"test", test);
+ string16 test(WideToUTF16(L"\x01\x02"));
+ root.SetString("test", test);
std::string expected = "{\"test\":\"\\u0001\\u0002\"}";
@@ -158,8 +160,8 @@ TEST(JSONValueSerializerTest, HexStrings) {
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
static_cast<DictionaryValue*>(deserial_root.get());
- std::wstring test_value;
- ASSERT_TRUE(dict_root->GetString(L"test", &test_value));
+ string16 test_value;
+ ASSERT_TRUE(dict_root->GetString("test", &test_value));
ASSERT_EQ(test, test_value);
// Test converting escaped regular chars
@@ -168,8 +170,8 @@ TEST(JSONValueSerializerTest, HexStrings) {
deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
ASSERT_TRUE(deserial_root.get());
dict_root = static_cast<DictionaryValue*>(deserial_root.get());
- ASSERT_TRUE(dict_root->GetString(L"test", &test_value));
- ASSERT_EQ(std::wstring(L"go"), test_value);
+ ASSERT_TRUE(dict_root->GetString("test", &test_value));
+ ASSERT_EQ(ASCIIToUTF16("go"), test_value);
}
TEST(JSONValueSerializerTest, AllowTrailingComma) {
@@ -221,9 +223,9 @@ TEST(JSONValueSerializerTest, JSONReaderComments) {
ASSERT_EQ(1U, list->GetSize());
Value* elt = NULL;
ASSERT_TRUE(list->Get(0, &elt));
- std::wstring value;
+ std::string value;
ASSERT_TRUE(elt && elt->GetAsString(&value));
- ASSERT_EQ(L"// ok\n /* foo */ ", value);
+ ASSERT_EQ("// ok\n /* foo */ ", value);
// You can't nest comments.
root.reset(base::JSONReader::Read("/* /* inner */ outer */ [ 1 ]", false));
@@ -275,21 +277,21 @@ TEST_F(JSONFileValueSerializerTest, Roundtrip) {
DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
Value* null_value = NULL;
- ASSERT_TRUE(root_dict->Get(L"null", &null_value));
+ ASSERT_TRUE(root_dict->Get("null", &null_value));
ASSERT_TRUE(null_value);
ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL));
bool bool_value = false;
- ASSERT_TRUE(root_dict->GetBoolean(L"bool", &bool_value));
+ ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
ASSERT_TRUE(bool_value);
int int_value = 0;
- ASSERT_TRUE(root_dict->GetInteger(L"int", &int_value));
+ ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
ASSERT_EQ(42, int_value);
- std::wstring string_value;
- ASSERT_TRUE(root_dict->GetString(L"string", &string_value));
- ASSERT_EQ(L"hello", string_value);
+ std::string string_value;
+ ASSERT_TRUE(root_dict->GetString("string", &string_value));
+ ASSERT_EQ("hello", string_value);
// Now try writing.
const FilePath written_file_path =
diff --git a/chrome/common/jstemplate_builder.h b/chrome/common/jstemplate_builder.h
index ac8285f..3eda5a6 100644
--- a/chrome/common/jstemplate_builder.h
+++ b/chrome/common/jstemplate_builder.h
@@ -12,6 +12,7 @@
#ifndef CHROME_COMMON_JSTEMPLATE_BUILDER_H_
#define CHROME_COMMON_JSTEMPLATE_BUILDER_H_
+#pragma once
#include <string>
diff --git a/chrome/common/libxml_utils.h b/chrome/common/libxml_utils.h
index 1484139..55a935c 100644
--- a/chrome/common/libxml_utils.h
+++ b/chrome/common/libxml_utils.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_LIBXML_UTILS_H__
#define CHROME_COMMON_LIBXML_UTILS_H__
+#pragma once
#include <string>
diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc
index c3bdb77..5b0987b 100644
--- a/chrome/common/logging_chrome.cc
+++ b/chrome/common/logging_chrome.cc
@@ -33,11 +33,13 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/debug_util.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
@@ -56,6 +58,10 @@ static bool dialogs_are_suppressed_ = false;
// InitChromeLogging() and the beginning of CleanupChromeLogging().
static bool chrome_logging_initialized_ = false;
+// This should be true for exactly the period between the end of
+// InitChromeLogging() and the beginning of CleanupChromeLogging().
+static bool chrome_logging_redirected_ = false;
+
#if defined(OS_WIN)
// {7FE69228-633E-4f06-80C1-527FEA23E3A7}
DEFINE_GUID(kChromeTraceProviderName,
@@ -159,6 +165,8 @@ FilePath TimestampLog(const FilePath& new_log_file, base::Time timestamp) {
void RedirectChromeLogging(const FilePath& new_log_dir,
const CommandLine& command_line,
OldFileDeletionState delete_old_log_file) {
+ DCHECK(!chrome_logging_redirected_) <<
+ "Attempted to redirect logging when it was already initialized.";
FilePath log_file_name = GetLogFileName().BaseName();
FilePath new_log_path =
TimestampLog(new_log_dir.Append(log_file_name), base::Time::Now());
@@ -166,6 +174,7 @@ void RedirectChromeLogging(const FilePath& new_log_dir,
DetermineLogMode(command_line),
logging::LOCK_LOG_FILE,
delete_old_log_file);
+ chrome_logging_redirected_ = true;
}
#endif
@@ -188,6 +197,10 @@ void InitChromeLogging(const CommandLine& command_line,
logging::LOCK_LOG_FILE,
delete_old_log_file);
+ // Default to showing error dialogs.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoErrorDialogs))
+ logging::SetShowErrorDialogs(true);
+
// we want process and thread IDs because we have a lot of things running
logging::SetLogItems(true, true, false, true);
@@ -195,8 +208,8 @@ void InitChromeLogging(const CommandLine& command_line,
// headless mode to be configured either by the Environment
// Variable or by the Command Line Switch. This is for
// automated test purposes.
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- if (env->HasEnv(env_vars::kHeadless) ||
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (env->HasVar(env_vars::kHeadless) ||
command_line.HasSwitch(switches::kNoErrorDialogs))
SuppressDialogs();
@@ -209,7 +222,7 @@ void InitChromeLogging(const CommandLine& command_line,
std::string log_level = command_line.GetSwitchValueASCII(
switches::kLoggingLevel);
int level = 0;
- if (StringToInt(log_level, &level)) {
+ if (base::StringToInt(log_level, &level)) {
if ((level >= 0) && (level < LOG_NUM_SEVERITIES))
logging::SetMinLogLevel(level);
} else {
@@ -218,7 +231,7 @@ void InitChromeLogging(const CommandLine& command_line,
#if defined(OS_WIN)
// Enable trace control and transport through event tracing for Windows.
- if (env->HasEnv(env_vars::kEtwLogging))
+ if (env->HasVar(env_vars::kEtwLogging))
logging::LogEventProvider::Initialize(kChromeTraceProviderName);
#endif
@@ -234,12 +247,13 @@ void CleanupChromeLogging() {
CloseLogFile();
chrome_logging_initialized_ = false;
+ chrome_logging_redirected_ = false;
}
FilePath GetLogFileName() {
std::string filename;
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- if (env->GetEnv(env_vars::kLogFileName, &filename) && !filename.empty()) {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (env->GetVar(env_vars::kLogFileName, &filename) && !filename.empty()) {
#if defined(OS_WIN)
return FilePath(UTF8ToWide(filename).c_str());
#elif defined(OS_POSIX)
diff --git a/chrome/common/logging_chrome.h b/chrome/common/logging_chrome.h
index 57c3906..a2d62d5 100644
--- a/chrome/common/logging_chrome.h
+++ b/chrome/common/logging_chrome.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_LOGGING_CHROME_H__
#define CHROME_COMMON_LOGGING_CHROME_H__
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/common/logging_chrome_uitest.cc b/chrome/common/logging_chrome_uitest.cc
index f92525e..0dc44d9 100644
--- a/chrome/common/logging_chrome_uitest.cc
+++ b/chrome/common/logging_chrome_uitest.cc
@@ -12,7 +12,7 @@
#include "base/basictypes.h"
#include "base/command_line.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/logging_chrome.h"
@@ -25,18 +25,18 @@ class ChromeLoggingTest : public testing::Test {
// Stores the current value of the log file name environment
// variable and sets the variable to new_value.
void SaveEnvironmentVariable(std::string new_value) {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- if (!env->GetEnv(env_vars::kLogFileName, &environment_filename_))
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (!env->GetVar(env_vars::kLogFileName, &environment_filename_))
environment_filename_ = "";
- env->SetEnv(env_vars::kLogFileName, new_value);
+ env->SetVar(env_vars::kLogFileName, new_value);
}
// Restores the value of the log file nave environment variable
// previously saved by SaveEnvironmentVariable().
void RestoreEnvironmentVariable() {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- env->SetEnv(env_vars::kLogFileName, environment_filename_);
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ env->SetVar(env_vars::kLogFileName, environment_filename_);
}
private:
@@ -130,9 +130,6 @@ class CheckFalseTest : public UITest {
#elif defined(OS_MACOSX)
// Crash service doesn't exist for the Mac yet: http://crbug.com/45243
#define CheckFails DISABLED_CheckFails
-#elif defined(OS_LINUX)
-// TODO(phajdan) Fix this - http://crbug.com/49838
-#define CheckFails FAILS_CheckFails
#endif
// Launch the app in assertion test mode, then close the app.
TEST_F(CheckFalseTest, CheckFails) {
@@ -183,7 +180,7 @@ TEST_F(RendererCrashTest, Crash) {
} else {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
ASSERT_TRUE(browser.get());
- ASSERT_TRUE(browser->WaitForTabCountToBecome(1, action_max_timeout_ms()));
+ ASSERT_TRUE(browser->WaitForTabCountToBecome(1));
expected_crashes_ = EXPECTED_CRASH_CRASHES;
}
}
diff --git a/chrome/common/mach_message_source_mac.h b/chrome/common/mach_message_source_mac.h
index f57539d..5ad8329 100644
--- a/chrome/common/mach_message_source_mac.h
+++ b/chrome/common/mach_message_source_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_
#define CHROME_COMMON_MACH_MESSAGE_SOURCE_MAC_H_
+#pragma once
#include <CoreServices/CoreServices.h>
@@ -38,6 +39,9 @@ class MachMessageSource {
class MachPortListener {
public:
virtual void OnMachMessageReceived(void* mach_msg, size_t size) = 0;
+
+ protected:
+ virtual ~OnMachMessageReceived() {}
};
// |listener| is a week reference passed to CF, it needs to remain in
diff --git a/chrome/common/main_function_params.h b/chrome/common/main_function_params.h
index b224892..0f0ed37 100644
--- a/chrome/common/main_function_params.h
+++ b/chrome/common/main_function_params.h
@@ -8,6 +8,7 @@
#ifndef CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_
#define CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_
+#pragma once
#include "base/command_line.h"
#include "chrome/common/sandbox_init_wrapper.h"
@@ -15,6 +16,7 @@
namespace base {
class ScopedNSAutoreleasePool;
};
+
class Task;
struct MainFunctionParams {
diff --git a/chrome/common/message_router.cc b/chrome/common/message_router.cc
index b73f2d0..6bd6e95 100644
--- a/chrome/common/message_router.cc
+++ b/chrome/common/message_router.cc
@@ -4,6 +4,12 @@
#include "chrome/common/message_router.h"
+MessageRouter::MessageRouter() {
+}
+
+MessageRouter::~MessageRouter() {
+}
+
void MessageRouter::OnControlMessageReceived(const IPC::Message& msg) {
NOTREACHED() <<
"should override in subclass if you care about control messages";
diff --git a/chrome/common/message_router.h b/chrome/common/message_router.h
index 35d2a5d..6a61091 100644
--- a/chrome/common/message_router.h
+++ b/chrome/common/message_router.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_MESSAGE_ROUTER_H__
#define CHROME_COMMON_MESSAGE_ROUTER_H__
+#pragma once
#include "base/id_map.h"
#include "ipc/ipc_channel.h"
@@ -29,8 +30,8 @@
class MessageRouter : public IPC::Channel::Listener,
public IPC::Message::Sender {
public:
- MessageRouter() {}
- virtual ~MessageRouter() {}
+ MessageRouter();
+ virtual ~MessageRouter();
// Implemented by subclasses to handle control messages
virtual void OnControlMessageReceived(const IPC::Message& msg);
diff --git a/chrome/common/metrics_helpers.cc b/chrome/common/metrics_helpers.cc
index 3bbaf3b..b0fdac1 100644
--- a/chrome/common/metrics_helpers.cc
+++ b/chrome/common/metrics_helpers.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,7 @@
#include "base/md5.h"
#include "base/perftimer.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "base/sys_info.h"
#include "base/utf_string_conversions.h"
#include "base/third_party/nspr/prtime.h"
@@ -100,7 +100,7 @@ MetricsLogBase::MetricsLogBase(const std::string& client_id, int session_id,
const std::string& version_string)
: start_time_(Time::Now()),
client_id_(client_id),
- session_id_(IntToString(session_id)),
+ session_id_(base::IntToString(session_id)),
locked_(false),
xml_wrapper_(new XmlWrapper),
num_events_(0) {
@@ -238,7 +238,7 @@ void MetricsLogBase::RecordLoadEvent(int window_id,
WriteAttribute("action", "load");
WriteIntAttribute("docid", session_index);
WriteIntAttribute("window", window_id);
- WriteAttribute("loadtime", Int64ToString(load_time.InMilliseconds()));
+ WriteAttribute("loadtime", base::Int64ToString(load_time.InMilliseconds()));
std::string origin_string;
@@ -295,16 +295,16 @@ void MetricsLogBase::RecordWindowEvent(WindowEventType type,
OPEN_ELEMENT_FOR_SCOPE("window");
WriteAttribute("action", WindowEventTypeToString(type));
- WriteAttribute("windowid", IntToString(window_id));
+ WriteAttribute("windowid", base::IntToString(window_id));
if (parent_id >= 0)
- WriteAttribute("parent", IntToString(parent_id));
+ WriteAttribute("parent", base::IntToString(parent_id));
WriteCommonEventAttributes();
++num_events_;
}
std::string MetricsLogBase::GetCurrentTimeString() {
- return Uint64ToString(Time::Now().ToTimeT());
+ return base::Uint64ToString(Time::Now().ToTimeT());
}
// These are the attributes that are common to every event.
@@ -325,11 +325,11 @@ void MetricsLogBase::WriteAttribute(const std::string& name,
}
void MetricsLogBase::WriteIntAttribute(const std::string& name, int value) {
- WriteAttribute(name, IntToString(value));
+ WriteAttribute(name, base::IntToString(value));
}
void MetricsLogBase::WriteInt64Attribute(const std::string& name, int64 value) {
- WriteAttribute(name, Int64ToString(value));
+ WriteAttribute(name, base::Int64ToString(value));
}
// static
diff --git a/chrome/common/metrics_helpers.h b/chrome/common/metrics_helpers.h
index 8051273..990a9fe 100644
--- a/chrome/common/metrics_helpers.h
+++ b/chrome/common/metrics_helpers.h
@@ -7,6 +7,7 @@
#ifndef CHROME_COMMON_METRICS_HELPERS_H_
#define CHROME_COMMON_METRICS_HELPERS_H_
+#pragma once
#include <map>
#include <string>
@@ -218,6 +219,8 @@ class MetricsServiceBase {
// For histograms, record what we've already logged (as a sample for each
// histogram) so that we can send only the delta with the next log.
LoggedSampleMap logged_samples_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsServiceBase);
};
#endif // CHROME_COMMON_METRICS_HELPERS_H_
diff --git a/chrome/common/mru_cache.h b/chrome/common/mru_cache.h
index b2643f8..b9b72d4 100644
--- a/chrome/common/mru_cache.h
+++ b/chrome/common/mru_cache.h
@@ -15,6 +15,7 @@
#ifndef CHROME_COMMON_MRU_CACHE_H__
#define CHROME_COMMON_MRU_CACHE_H__
+#pragma once
#include <list>
#include <map>
diff --git a/chrome/common/nacl_cmd_line.cc b/chrome/common/nacl_cmd_line.cc
index a54f196..4c2f19f 100644
--- a/chrome/common/nacl_cmd_line.cc
+++ b/chrome/common/nacl_cmd_line.cc
@@ -8,33 +8,32 @@
#include "chrome/common/logging_chrome.h"
namespace nacl {
- void CopyNaClCommandLineArguments(CommandLine* cmd_line) {
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- if (logging::DialogsAreSuppressed())
- cmd_line->AppendSwitch(switches::kNoErrorDialogs);
- // Propagate the following switches to the NaCl loader command line (along
- // with any associated values) if present in the browser command line.
- // TODO(gregoryd): check which flags of those below can be supported.
- static const char* const switch_names[] = {
- switches::kNoSandbox,
- switches::kTestNaClSandbox,
- switches::kDisableBreakpad,
- switches::kFullMemoryCrashReport,
- switches::kEnableLogging,
- switches::kDisableLogging,
- switches::kLoggingLevel,
- switches::kEnableDCHECK,
- switches::kSilentDumpOnDCHECK,
- switches::kMemoryProfiling,
- };
+void CopyNaClCommandLineArguments(CommandLine* cmd_line) {
+ const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ if (logging::DialogsAreSuppressed())
+ cmd_line->AppendSwitch(switches::kNoErrorDialogs);
+
+ // Propagate the following switches to the NaCl loader command line (along
+ // with any associated values) if present in the browser command line.
+ // TODO(gregoryd): check which flags of those below can be supported.
+ static const char* const kSwitchNames[] = {
+ switches::kNoSandbox,
+ switches::kTestNaClSandbox,
+ switches::kDisableBreakpad,
+ switches::kFullMemoryCrashReport,
+ switches::kEnableLogging,
+ switches::kDisableLogging,
+ switches::kLoggingLevel,
+ switches::kEnableDCHECK,
+ switches::kSilentDumpOnDCHECK,
+ switches::kMemoryProfiling,
+ switches::kEnableNaClDebug,
+ switches::kNaClDebugPorts,
+ switches::kNaClDebugIP,
+ };
+ cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
+ arraysize(kSwitchNames));
+}
- for (size_t i = 0; i < arraysize(switch_names); ++i) {
- if (browser_command_line.HasSwitch(switch_names[i])) {
- cmd_line->AppendSwitchWithValue(
- switch_names[i],
- browser_command_line.GetSwitchValueASCII(switch_names[i]));
- }
- }
- }
}
diff --git a/chrome/common/nacl_cmd_line.h b/chrome/common/nacl_cmd_line.h
index 1091e11..e2edccc 100644
--- a/chrome/common/nacl_cmd_line.h
+++ b/chrome/common/nacl_cmd_line.h
@@ -4,8 +4,9 @@
#ifndef CHROME_COMMON_NACL_CMD_LINE_H_
#define CHROME_COMMON_NACL_CMD_LINE_H_
+#pragma once
-#include "base/command_line.h"
+class CommandLine;
namespace nacl {
// Copy all the relevant arguments from the command line of the current
diff --git a/chrome/common/nacl_messages.cc b/chrome/common/nacl_messages.cc
new file mode 100644
index 0000000..291ed5a
--- /dev/null
+++ b/chrome/common/nacl_messages.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/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 8d360dd..11abf19 100644
--- a/chrome/common/nacl_messages.h
+++ b/chrome/common/nacl_messages.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,8 +6,7 @@
#ifndef CHROME_COMMON_NACL_MESSAGES_H_
#define CHROME_COMMON_NACL_MESSAGES_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "ipc/ipc_message_utils.h"
diff --git a/chrome/common/nacl_messages_internal.h b/chrome/common/nacl_messages_internal.h
index abde832..e302118 100644
--- a/chrome/common/nacl_messages_internal.h
+++ b/chrome/common/nacl_messages_internal.h
@@ -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/process.h"
#include "chrome/common/nacl_types.h"
#include "ipc/ipc_message_macros.h"
@@ -10,9 +11,8 @@
// These are messages sent from the browser to the NaCl process.
IPC_BEGIN_MESSAGES(NaClProcess)
// Tells the NaCl process to start.
- IPC_MESSAGE_CONTROL2(NaClProcessMsg_Start,
- int /* descriptor id */,
- nacl::FileDescriptor /* handle value */)
+ 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,
diff --git a/chrome/common/nacl_types.h b/chrome/common/nacl_types.h
index 5c5f5dc..b61d9ef 100644
--- a/chrome/common/nacl_types.h
+++ b/chrome/common/nacl_types.h
@@ -5,6 +5,7 @@
// Handle passing definitions for NaCl
#ifndef CHROME_COMMON_NACL_TYPES_H_
#define CHROME_COMMON_NACL_TYPES_H_
+#pragma once
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
diff --git a/chrome/common/native_web_keyboard_event.h b/chrome/common/native_web_keyboard_event.h
index 381ad31..4f6548d 100644
--- a/chrome/common/native_web_keyboard_event.h
+++ b/chrome/common/native_web_keyboard_event.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NATIVE_WEB_KEYBOARD_EVENT_H_
#define CHROME_COMMON_NATIVE_WEB_KEYBOARD_EVENT_H_
+#pragma once
#include "base/basictypes.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
@@ -32,7 +33,7 @@ struct NativeWebKeyboardEvent : public WebKit::WebKeyboardEvent {
NativeWebKeyboardEvent(wchar_t character,
int state,
double time_stamp_seconds);
-#elif defined(OS_LINUX)
+#elif defined(TOOLKIT_USES_GTK)
explicit NativeWebKeyboardEvent(const GdkEventKey* event);
NativeWebKeyboardEvent(wchar_t character,
int state,
@@ -48,7 +49,7 @@ struct NativeWebKeyboardEvent : public WebKit::WebKeyboardEvent {
MSG os_event;
#elif defined(OS_MACOSX)
NSEvent* os_event;
-#elif defined(OS_LINUX)
+#elif defined(TOOLKIT_USES_GTK)
GdkEventKey* os_event;
#endif
diff --git a/chrome/common/native_window_notification_source.h b/chrome/common/native_window_notification_source.h
index 4cc75b8..a8e5cae 100644
--- a/chrome/common/native_window_notification_source.h
+++ b/chrome/common/native_window_notification_source.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NATIVE_WINDOW_NOTIFICATION_SOURCE_H_
#define CHROME_COMMON_NATIVE_WINDOW_NOTIFICATION_SOURCE_H_
+#pragma once
#include "chrome/common/notification_source.h"
#include "gfx/native_widget_types.h"
diff --git a/chrome/common/navigation_gesture.h b/chrome/common/navigation_gesture.h
index bb99497..e27ea4c 100644
--- a/chrome/common/navigation_gesture.h
+++ b/chrome/common/navigation_gesture.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NAVIGATION_GESTURE_H_
#define CHROME_COMMON_NAVIGATION_GESTURE_H_
+#pragma once
enum NavigationGesture {
NavigationGestureUser, // User initiated navigation/load. This is not
diff --git a/chrome/common/navigation_types.h b/chrome/common/navigation_types.h
index c871201..39c2a98 100644
--- a/chrome/common/navigation_types.h
+++ b/chrome/common/navigation_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NAVIGATION_TYPES_H_
#define CHROME_COMMON_NAVIGATION_TYPES_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/common/net/gaia/gaia_auth_consumer.h b/chrome/common/net/gaia/gaia_auth_consumer.h
index b7b215c..429ab7f 100644
--- a/chrome/common/net/gaia/gaia_auth_consumer.h
+++ b/chrome/common/net/gaia/gaia_auth_consumer.h
@@ -4,9 +4,12 @@
#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTH_CONSUMER_H_
#define CHROME_COMMON_NET_GAIA_GAIA_AUTH_CONSUMER_H_
+#pragma once
#include <string>
+class GoogleServiceAuthError;
+
// An interface that defines the callbacks for objects that
// GaiaAuthenticator2 can return data to.
class GaiaAuthConsumer {
@@ -36,38 +39,20 @@ class GaiaAuthConsumer {
std::string data; // Full contents of ClientLogin return.
};
- enum GaiaAuthErrorCode {
- NETWORK_ERROR,
- REQUEST_CANCELED,
- TWO_FACTOR, // Callers can treat this as a success.
- PERMISSION_DENIED
- };
-
- struct GaiaAuthError {
- inline bool operator==(const GaiaAuthError &b) const {
- if (code != b.code) {
- return false;
- }
- if (code == NETWORK_ERROR) {
- return network_error == b.network_error;
- }
- return true;
- }
-
- GaiaAuthErrorCode code;
- int network_error; // This field is only valid if NETWORK_ERROR occured.
- std::string data; // TODO(chron): Remove this field. Should preparse data.
- };
-
virtual ~GaiaAuthConsumer() {}
virtual void OnClientLoginSuccess(const ClientLoginResult& result) {}
- virtual void OnClientLoginFailure(const GaiaAuthError& error) {}
+ virtual void OnClientLoginFailure(const GoogleServiceAuthError& error) {}
virtual void OnIssueAuthTokenSuccess(const std::string& service,
const std::string& auth_token) {}
virtual void OnIssueAuthTokenFailure(const std::string& service,
- const GaiaAuthError& error) {}
+ const GoogleServiceAuthError& error) {}
+
+ virtual void OnGetUserInfoSuccess(const std::string& key,
+ const std::string& value) {}
+ virtual void OnGetUserInfoKeyNotFound(const std::string& key) {}
+ virtual void OnGetUserInfoFailure(const GoogleServiceAuthError& error) {}
};
#endif // CHROME_COMMON_NET_GAIA_GAIA_AUTH_CONSUMER_H_
diff --git a/chrome/common/net/gaia/gaia_authenticator.h b/chrome/common/net/gaia/gaia_authenticator.h
index d34af2d..696f403 100644
--- a/chrome/common/net/gaia/gaia_authenticator.h
+++ b/chrome/common/net/gaia/gaia_authenticator.h
@@ -27,14 +27,15 @@
// artifacts of the sync code which needs to be cleaned up.
#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/message_loop.h"
#include "chrome/common/deprecated/event_sys.h"
#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST
namespace gaia {
@@ -80,7 +81,8 @@ struct GaiaAuthEvent {
// GaiaAuthenticator can be used to pass user credentials to Gaia and obtain
// cookies set by the Gaia servers.
class GaiaAuthenticator {
- FRIEND_TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved);
+ FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticatorTest,
+ TestNewlineAtEndOfAuthTokenRemoved);
public:
// Since GaiaAuthenticator can be used for any service, or by any client, you
diff --git a/chrome/common/net/gaia/gaia_authenticator2.cc b/chrome/common/net/gaia/gaia_authenticator2.cc
index abc0efe..479aa28 100644
--- a/chrome/common/net/gaia/gaia_authenticator2.cc
+++ b/chrome/common/net/gaia/gaia_authenticator2.cc
@@ -5,10 +5,13 @@
#include "chrome/common/net/gaia/gaia_authenticator2.h"
#include <string>
+#include <utility>
+#include <vector>
#include "base/string_split.h"
#include "base/string_util.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/net/http_return.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/load_flags.h"
@@ -40,16 +43,37 @@ const char GaiaAuthenticator2::kIssueAuthTokenFormat[] =
"LSID=%s&"
"service=%s&"
"Session=true";
+// static
+const char GaiaAuthenticator2::kGetUserInfoFormat[] =
+ "LSID=%s";
// static
-const char GaiaAuthenticator2::kCookiePersistence[] = "true";
+const char GaiaAuthenticator2::kAccountDeletedError[] = "AccountDeleted";
+// static
+const char GaiaAuthenticator2::kAccountDisabledError[] = "AccountDisabled";
+// static
+const char GaiaAuthenticator2::kCaptchaError[] = "CaptchaRequired";
+// static
+const char GaiaAuthenticator2::kServiceUnavailableError[] =
+ "ServiceUnavailable";
+// static
+const char GaiaAuthenticator2::kErrorParam[] = "Error";
+// static
+const char GaiaAuthenticator2::kErrorUrlParam[] = "Url";
// static
-const char GaiaAuthenticator2::kAccountType[] = "HOSTED_OR_GOOGLE";
+const char GaiaAuthenticator2::kCaptchaUrlParam[] = "CaptchaUrl";
// static
-const char GaiaAuthenticator2::kChromeOSSource[] = "chromeos";
+const char GaiaAuthenticator2::kCaptchaTokenParam[] = "CaptchaToken";
// static
-// Service name for Gaia Contacts API. API is used to get user's image.
-const char GaiaAuthenticator2::kContactsService[] = "cp";
+const char GaiaAuthenticator2::kCaptchaUrlPrefix[] =
+ "http://www.google.com/accounts/";
+
+// static
+const char GaiaAuthenticator2::kCookiePersistence[] = "true";
+// static
+// TODO(johnnyg): When hosted accounts are supported, this can become
+// "HOSTED_OR_GOOGLE". http://crbug.com/19589
+const char GaiaAuthenticator2::kAccountType[] = "GOOGLE";
// static
const char GaiaAuthenticator2::kSecondFactor[] = "Info=InvalidSecondFactor";
@@ -59,6 +83,8 @@ const char GaiaAuthenticator2::kClientLoginUrl[] =
"https://www.google.com/accounts/ClientLogin";
const char GaiaAuthenticator2::kIssueAuthTokenUrl[] =
"https://www.google.com/accounts/IssueAuthToken";
+const char GaiaAuthenticator2::kGetUserInfoUrl[] =
+ "https://www.google.com/accounts/GetUserInfo";
GaiaAuthenticator2::GaiaAuthenticator2(GaiaAuthConsumer* consumer,
const std::string& source,
@@ -68,6 +94,7 @@ GaiaAuthenticator2::GaiaAuthenticator2(GaiaAuthConsumer* consumer,
source_(source),
client_login_gurl_(kClientLoginUrl),
issue_auth_token_gurl_(kIssueAuthTokenUrl),
+ get_user_info_gurl_(kGetUserInfoUrl),
fetch_pending_(false) {}
GaiaAuthenticator2::~GaiaAuthenticator2() {}
@@ -107,11 +134,15 @@ std::string GaiaAuthenticator2::MakeClientLoginBody(
const char* service,
const std::string& login_token,
const std::string& login_captcha) {
+ std::string encoded_username = UrlEncodeString(username);
+ std::string encoded_password = UrlEncodeString(password);
+ std::string encoded_login_token = UrlEncodeString(login_token);
+ std::string encoded_login_captcha = UrlEncodeString(login_captcha);
if (login_token.empty() || login_captcha.empty()) {
return StringPrintf(kClientLoginFormat,
- UrlEncodeString(username).c_str(),
- UrlEncodeString(password).c_str(),
+ encoded_username.c_str(),
+ encoded_password.c_str(),
kCookiePersistence,
kAccountType,
source.c_str(),
@@ -119,14 +150,14 @@ std::string GaiaAuthenticator2::MakeClientLoginBody(
}
return StringPrintf(kClientLoginCaptchaFormat,
- UrlEncodeString(username).c_str(),
- UrlEncodeString(password).c_str(),
+ encoded_username.c_str(),
+ encoded_password.c_str(),
kCookiePersistence,
kAccountType,
source.c_str(),
service,
- UrlEncodeString(login_token).c_str(),
- UrlEncodeString(login_captcha).c_str());
+ encoded_login_token.c_str(),
+ encoded_login_captcha.c_str());
}
@@ -135,13 +166,21 @@ std::string GaiaAuthenticator2::MakeIssueAuthTokenBody(
const std::string& sid,
const std::string& lsid,
const char* const service) {
+ std::string encoded_sid = UrlEncodeString(sid);
+ std::string encoded_lsid = UrlEncodeString(lsid);
return StringPrintf(kIssueAuthTokenFormat,
- UrlEncodeString(sid).c_str(),
- UrlEncodeString(lsid).c_str(),
+ encoded_sid.c_str(),
+ encoded_lsid.c_str(),
service);
}
+// static
+std::string GaiaAuthenticator2::MakeGetUserInfoBody(const std::string& lsid) {
+ std::string encoded_lsid = UrlEncodeString(lsid);
+ return StringPrintf(kGetUserInfoFormat, encoded_lsid.c_str());
+}
+
// Helper method that extracts tokens from a successful reply.
// static
void GaiaAuthenticator2::ParseClientLoginResponse(const std::string& data,
@@ -166,6 +205,32 @@ void GaiaAuthenticator2::ParseClientLoginResponse(const std::string& data,
}
}
+// static
+void GaiaAuthenticator2::ParseClientLoginFailure(const std::string& data,
+ std::string* error,
+ std::string* error_url,
+ std::string* captcha_url,
+ std::string* captcha_token) {
+ using std::vector;
+ using std::pair;
+ using std::string;
+
+ vector<pair<string, string> > tokens;
+ base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
+ for (vector<pair<string, string> >::iterator i = tokens.begin();
+ i != tokens.end(); ++i) {
+ if (i->first == kErrorParam) {
+ error->assign(i->second);
+ } else if (i->first == kErrorUrlParam) {
+ error_url->assign(i->second);
+ } else if (i->first == kCaptchaUrlParam) {
+ captcha_url->assign(i->second);
+ } else if (i->first == kCaptchaTokenParam) {
+ captcha_token->assign(i->second);
+ }
+ }
+}
+
void GaiaAuthenticator2::StartClientLogin(const std::string& username,
const std::string& password,
const char* const service,
@@ -210,31 +275,65 @@ void GaiaAuthenticator2::StartIssueAuthToken(const std::string& sid,
fetcher_->Start();
}
-GaiaAuthConsumer::GaiaAuthError GaiaAuthenticator2::GenerateAuthError(
+void GaiaAuthenticator2::StartGetUserInfo(const std::string& lsid,
+ const std::string& info_key) {
+ DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
+
+ LOG(INFO) << "Starting GetUserInfo for lsid=" << lsid;
+ request_body_ = MakeGetUserInfoBody(lsid);
+ fetcher_.reset(CreateGaiaFetcher(getter_,
+ request_body_,
+ get_user_info_gurl_,
+ this));
+ fetch_pending_ = true;
+ requested_info_key_ = info_key;
+ fetcher_->Start();
+}
+
+// static
+GoogleServiceAuthError GaiaAuthenticator2::GenerateAuthError(
const std::string& data,
const URLRequestStatus& status) {
- GaiaAuthConsumer::GaiaAuthError error;
- error.data = data;
-
if (!status.is_success()) {
if (status.status() == URLRequestStatus::CANCELED) {
- error.code = GaiaAuthConsumer::REQUEST_CANCELED;
+ return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
} else {
- error.code = GaiaAuthConsumer::NETWORK_ERROR;
- error.network_error = status.os_error();
LOG(WARNING) << "Could not reach Google Accounts servers: errno "
- << status.os_error();
+ << status.os_error();
+ return GoogleServiceAuthError::FromConnectionError(status.os_error());
}
} else {
if (IsSecondFactorSuccess(data)) {
- error.code = GaiaAuthConsumer::TWO_FACTOR;
- } else {
- error.code = GaiaAuthConsumer::PERMISSION_DENIED;
+ return GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR);
}
+
+ std::string error;
+ std::string url;
+ std::string captcha_url;
+ std::string captcha_token;
+ ParseClientLoginFailure(data, &error, &url, &captcha_url, &captcha_token);
+ LOG(WARNING) << "ClientLogin failed with " << error;
+
+ if (error == kCaptchaError) {
+ GURL image_url(kCaptchaUrlPrefix + captcha_url);
+ GURL unlock_url(url);
+ return GoogleServiceAuthError::FromCaptchaChallenge(
+ captcha_token, image_url, unlock_url);
+ } else if (error == kAccountDeletedError) {
+ return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED);
+ } else if (error == kAccountDisabledError) {
+ return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
+ } else if (error == kServiceUnavailableError) {
+ return GoogleServiceAuthError(
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+ }
+
+ return GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
}
- return error;
+ NOTREACHED();
}
void GaiaAuthenticator2::OnClientLoginFetched(const std::string& data,
@@ -268,6 +367,30 @@ void GaiaAuthenticator2::OnIssueAuthTokenFetched(
}
}
+void GaiaAuthenticator2::OnGetUserInfoFetched(
+ const std::string& data,
+ const URLRequestStatus& status,
+ int response_code) {
+ using std::vector;
+ using std::string;
+ using std::pair;
+
+ if (status.is_success() && response_code == RC_REQUEST_OK) {
+ vector<pair<string, string> > tokens;
+ base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
+ for (vector<pair<string, string> >::iterator i = tokens.begin();
+ i != tokens.end(); ++i) {
+ if (i->first == requested_info_key_) {
+ consumer_->OnGetUserInfoSuccess(i->first, i->second);
+ return;
+ }
+ }
+ consumer_->OnGetUserInfoKeyNotFound(requested_info_key_);
+ } else {
+ consumer_->OnGetUserInfoFailure(GenerateAuthError(data, status));
+ }
+}
+
void GaiaAuthenticator2::OnURLFetchComplete(const URLFetcher* source,
const GURL& url,
const URLRequestStatus& status,
@@ -279,6 +402,8 @@ void GaiaAuthenticator2::OnURLFetchComplete(const URLFetcher* source,
OnClientLoginFetched(data, status, response_code);
} else if (url == issue_auth_token_gurl_) {
OnIssueAuthTokenFetched(data, status, response_code);
+ } else if (url == get_user_info_gurl_) {
+ OnGetUserInfoFetched(data, status, response_code);
} else {
NOTREACHED();
}
diff --git a/chrome/common/net/gaia/gaia_authenticator2.h b/chrome/common/net/gaia/gaia_authenticator2.h
index 0e6c203..7c01b40 100644
--- a/chrome/common/net/gaia/gaia_authenticator2.h
+++ b/chrome/common/net/gaia/gaia_authenticator2.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_H_
#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_H_
+#pragma once
#include <string>
@@ -25,15 +26,13 @@
class GaiaAuthenticator2Test;
+// TODO(chron): Rename this to GaiaAuthFetcher or something.
class GaiaAuthenticator2 : public URLFetcher::Delegate {
public:
- // Constants to use in the ClientLogin request POST body.
- static const char kChromeOSSource[];
- static const char kContactsService[];
-
// The URLs for different calls in the Google Accounts programmatic login API.
static const char kClientLoginUrl[];
static const char kIssueAuthTokenUrl[];
+ static const char kGetUserInfoUrl[];
// Magic string indicating that, while a second factor is still
// needed to complete authentication, the user provided the right password.
@@ -62,6 +61,13 @@ class GaiaAuthenticator2 : public URLFetcher::Delegate {
const std::string& lsid,
const char* const service);
+ // Start a request to get a particular key from user info.
+ // GaiaAuthConsumer will be called back on the same thread when
+ // results come back.
+ // You can't make more than one request at a time.
+ void StartGetUserInfo(const std::string& lsid,
+ const std::string& info_key);
+
// Implementation of URLFetcher::Delegate
void OnURLFetchComplete(const URLFetcher* source,
const GURL& url,
@@ -87,6 +93,19 @@ class GaiaAuthenticator2 : public URLFetcher::Delegate {
static const char kClientLoginCaptchaFormat[];
// The format of the POST body for IssueAuthToken.
static const char kIssueAuthTokenFormat[];
+ // The format of the POSt body for GetUserInfo.
+ static const char kGetUserInfoFormat[];
+
+ // Constants for parsing ClientLogin errors.
+ static const char kAccountDeletedError[];
+ static const char kAccountDisabledError[];
+ static const char kCaptchaError[];
+ static const char kServiceUnavailableError[];
+ static const char kErrorParam[];
+ static const char kErrorUrlParam[];
+ static const char kCaptchaUrlParam[];
+ static const char kCaptchaTokenParam[];
+ static const char kCaptchaUrlPrefix[];
// Process the results of a ClientLogin fetch.
void OnClientLoginFetched(const std::string& data,
@@ -97,16 +116,26 @@ class GaiaAuthenticator2 : public URLFetcher::Delegate {
const URLRequestStatus& status,
int response_code);
+ void OnGetUserInfoFetched(const std::string& data,
+ const URLRequestStatus& status,
+ int response_code);
+
// Tokenize the results of a ClientLogin fetch.
static void ParseClientLoginResponse(const std::string& data,
std::string* sid,
std::string* lsid,
std::string* token);
- // From a URLFetcher result, generate an appropriate GaiaAuthError.
+ static void ParseClientLoginFailure(const std::string& data,
+ std::string* error,
+ std::string* error_url,
+ std::string* captcha_url,
+ std::string* captcha_token);
+
+ // From a URLFetcher result, generate an appropriate error.
// From the API documentation, both IssueAuthToken and ClientLogin have
// the same error returns.
- static GaiaAuthConsumer::GaiaAuthError GenerateAuthError(
+ static GoogleServiceAuthError GenerateAuthError(
const std::string& data,
const URLRequestStatus& status);
@@ -125,6 +154,9 @@ class GaiaAuthenticator2 : public URLFetcher::Delegate {
static std::string MakeIssueAuthTokenBody(const std::string& sid,
const std::string& lsid,
const char* const service);
+ // Supply the lsid returned from ClientLogin in order to fetch
+ // user information.
+ static std::string MakeGetUserInfoBody(const std::string& lsid);
// Create a fetcher useable for making any Gaia request.
static URLFetcher* CreateGaiaFetcher(URLRequestContextGetter* getter,
@@ -139,17 +171,23 @@ class GaiaAuthenticator2 : public URLFetcher::Delegate {
std::string source_;
const GURL client_login_gurl_;
const GURL issue_auth_token_gurl_;
+ const GURL get_user_info_gurl_;
// While a fetch is going on:
scoped_ptr<URLFetcher> fetcher_;
std::string request_body_;
- std::string requested_service_; // Currently tracked for IssueAuthToken only
+ std::string requested_service_; // Currently tracked for IssueAuthToken only
+ std::string requested_info_key_; // Currently tracked for GetUserInfo only
bool fetch_pending_;
friend class GaiaAuthenticator2Test;
- FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, LoginNetFailure);
+ FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, CaptchaParse);
+ FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, AccountDeletedError);
+ FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, AccountDisabledError);
+ FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, ServiceUnavailableError);
FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, CheckNormalErrorCode);
FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, CheckTwoFactorResponse);
+ FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticator2Test, LoginNetFailure);
DISALLOW_COPY_AND_ASSIGN(GaiaAuthenticator2);
};
diff --git a/chrome/common/net/gaia/gaia_authenticator2_unittest.cc b/chrome/common/net/gaia/gaia_authenticator2_unittest.cc
index 4e4dc82..ea17325 100644
--- a/chrome/common/net/gaia/gaia_authenticator2_unittest.cc
+++ b/chrome/common/net/gaia/gaia_authenticator2_unittest.cc
@@ -12,6 +12,7 @@
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "chrome/common/net/gaia/gaia_authenticator2.h"
#include "chrome/common/net/gaia/gaia_authenticator2_unittest.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/net/http_return.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
#include "chrome/common/net/url_fetcher.h"
@@ -47,6 +48,27 @@ class GaiaAuthenticator2Test : public testing::Test {
EXPECT_EQ(token, out_token);
}
+ void RunErrorParsingTest(const std::string& data,
+ const std::string& error,
+ const std::string& error_url,
+ const std::string& captcha_url,
+ const std::string& captcha_token) {
+ std::string out_error;
+ std::string out_error_url;
+ std::string out_captcha_url;
+ std::string out_captcha_token;
+
+ GaiaAuthenticator2::ParseClientLoginFailure(data,
+ &out_error,
+ &out_error_url,
+ &out_captcha_url,
+ &out_captcha_token);
+ EXPECT_EQ(error, out_error);
+ EXPECT_EQ(error_url, out_error_url);
+ EXPECT_EQ(captcha_url, out_captcha_url);
+ EXPECT_EQ(captcha_token, out_captcha_token);
+ }
+
ResponseCookies cookies_;
GURL client_login_source_;
GURL issue_auth_token_source_;
@@ -61,28 +83,30 @@ class MockGaiaConsumer : public GaiaAuthConsumer {
MOCK_METHOD1(OnClientLoginSuccess, void(const ClientLoginResult& result));
MOCK_METHOD2(OnIssueAuthTokenSuccess, void(const std::string& service,
const std::string& token));
- MOCK_METHOD1(OnClientLoginFailure, void(const GaiaAuthError& error));
+ MOCK_METHOD1(OnClientLoginFailure,
+ void(const GoogleServiceAuthError& error));
MOCK_METHOD2(OnIssueAuthTokenFailure, void(const std::string& service,
- const GaiaAuthError& error));
+ const GoogleServiceAuthError& error));
};
TEST_F(GaiaAuthenticator2Test, ErrorComparator) {
- GaiaAuthConsumer::GaiaAuthError expected_error;
- expected_error.code = GaiaAuthConsumer::NETWORK_ERROR;
- expected_error.network_error = -101;
+ GoogleServiceAuthError expected_error =
+ GoogleServiceAuthError::FromConnectionError(-101);
- GaiaAuthConsumer::GaiaAuthError matching_error;
- matching_error.code = GaiaAuthConsumer::NETWORK_ERROR;
- matching_error.network_error = -101;
+ GoogleServiceAuthError matching_error =
+ GoogleServiceAuthError::FromConnectionError(-101);
EXPECT_TRUE(expected_error == matching_error);
- expected_error.network_error = 6;
+ expected_error = GoogleServiceAuthError::FromConnectionError(6);
+
+ EXPECT_FALSE(expected_error == matching_error);
+
+ expected_error = GoogleServiceAuthError(GoogleServiceAuthError::NONE);
EXPECT_FALSE(expected_error == matching_error);
- expected_error.code = GaiaAuthConsumer::PERMISSION_DENIED;
- matching_error.code = GaiaAuthConsumer::PERMISSION_DENIED;
+ matching_error = GoogleServiceAuthError(GoogleServiceAuthError::NONE);
EXPECT_TRUE(expected_error == matching_error);
}
@@ -91,9 +115,8 @@ TEST_F(GaiaAuthenticator2Test, LoginNetFailure) {
int error_no = net::ERR_CONNECTION_RESET;
URLRequestStatus status(URLRequestStatus::FAILED, error_no);
- GaiaAuthConsumer::GaiaAuthError expected_error;
- expected_error.code = GaiaAuthConsumer::NETWORK_ERROR;
- expected_error.network_error = error_no;
+ GoogleServiceAuthError expected_error =
+ GoogleServiceAuthError::FromConnectionError(error_no);
MockGaiaConsumer consumer;
EXPECT_CALL(consumer, OnClientLoginFailure(expected_error))
@@ -114,9 +137,8 @@ TEST_F(GaiaAuthenticator2Test, TokenNetFailure) {
int error_no = net::ERR_CONNECTION_RESET;
URLRequestStatus status(URLRequestStatus::FAILED, error_no);
- GaiaAuthConsumer::GaiaAuthError expected_error;
- expected_error.code = GaiaAuthConsumer::NETWORK_ERROR;
- expected_error.network_error = error_no;
+ GoogleServiceAuthError expected_error =
+ GoogleServiceAuthError::FromConnectionError(error_no);
MockGaiaConsumer consumer;
EXPECT_CALL(consumer, OnIssueAuthTokenFailure(_, expected_error))
@@ -138,8 +160,8 @@ TEST_F(GaiaAuthenticator2Test, LoginDenied) {
std::string data("Error: NO!");
URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
- GaiaAuthConsumer::GaiaAuthError expected_error;
- expected_error.code = GaiaAuthConsumer::PERMISSION_DENIED;
+ GoogleServiceAuthError expected_error(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
MockGaiaConsumer consumer;
EXPECT_CALL(consumer, OnClientLoginFailure(expected_error))
@@ -165,6 +187,22 @@ TEST_F(GaiaAuthenticator2Test, ParseRequest) {
RunParsingTest("SID=sid", "sid", "", "");
}
+TEST_F(GaiaAuthenticator2Test, ParseErrorRequest) {
+ RunErrorParsingTest("Url=U\n"
+ "Error=E\n"
+ "CaptchaToken=T\n"
+ "CaptchaUrl=C\n", "E", "U", "C", "T");
+ RunErrorParsingTest("CaptchaToken=T\n"
+ "Error=E\n"
+ "Url=U\n"
+ "CaptchaUrl=C\n", "E", "U", "C", "T");
+ RunErrorParsingTest("\n\n\nCaptchaToken=T\n"
+ "\nError=E\n"
+ "\nUrl=U\n"
+ "CaptchaUrl=C\n", "E", "U", "C", "T");
+}
+
+
TEST_F(GaiaAuthenticator2Test, OnlineLogin) {
std::string data("SID=sid\nLSID=lsid\nAuth=auth\n");
@@ -218,12 +256,11 @@ TEST_F(GaiaAuthenticator2Test, CheckNormalErrorCode) {
}
TEST_F(GaiaAuthenticator2Test, TwoFactorLogin) {
- std::string response =
- StringPrintf("Error=BadAuthentication\n%s\n",
- GaiaAuthenticator2::kSecondFactor);
+ std::string response = StringPrintf("Error=BadAuthentication\n%s\n",
+ GaiaAuthenticator2::kSecondFactor);
- GaiaAuthConsumer::GaiaAuthError error;
- error.code = GaiaAuthConsumer::TWO_FACTOR;
+ GoogleServiceAuthError error =
+ GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR);
MockGaiaConsumer consumer;
EXPECT_CALL(consumer, OnClientLoginFailure(error))
@@ -240,6 +277,49 @@ TEST_F(GaiaAuthenticator2Test, TwoFactorLogin) {
response);
}
+TEST_F(GaiaAuthenticator2Test, CaptchaParse) {
+ URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+ std::string data = "Url=http://www.google.com/login/captcha\n"
+ "Error=CaptchaRequired\n"
+ "CaptchaToken=CCTOKEN\n"
+ "CaptchaUrl=Captcha?ctoken=CCTOKEN\n";
+ GoogleServiceAuthError error =
+ GaiaAuthenticator2::GenerateAuthError(data, status);
+
+ std::string token = "CCTOKEN";
+ GURL image_url("http://www.google.com/accounts/Captcha?ctoken=CCTOKEN");
+ GURL unlock_url("http://www.google.com/login/captcha");
+
+ EXPECT_EQ(error.state(), GoogleServiceAuthError::CAPTCHA_REQUIRED);
+ EXPECT_EQ(error.captcha().token, token);
+ EXPECT_EQ(error.captcha().image_url, image_url);
+ EXPECT_EQ(error.captcha().unlock_url, unlock_url);
+}
+
+TEST_F(GaiaAuthenticator2Test, AccountDeletedError) {
+ URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+ std::string data = "Error=AccountDeleted\n";
+ GoogleServiceAuthError error =
+ GaiaAuthenticator2::GenerateAuthError(data, status);
+ EXPECT_EQ(error.state(), GoogleServiceAuthError::ACCOUNT_DELETED);
+}
+
+TEST_F(GaiaAuthenticator2Test, AccountDisabledError) {
+ URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+ std::string data = "Error=AccountDisabled\n";
+ GoogleServiceAuthError error =
+ GaiaAuthenticator2::GenerateAuthError(data, status);
+ EXPECT_EQ(error.state(), GoogleServiceAuthError::ACCOUNT_DISABLED);
+}
+
+TEST_F(GaiaAuthenticator2Test,ServiceUnavailableError) {
+ URLRequestStatus status(URLRequestStatus::SUCCESS, 0);
+ std::string data = "Error=ServiceUnavailable\n";
+ GoogleServiceAuthError error =
+ GaiaAuthenticator2::GenerateAuthError(data, status);
+ EXPECT_EQ(error.state(), GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+}
+
TEST_F(GaiaAuthenticator2Test, FullLogin) {
MockGaiaConsumer consumer;
EXPECT_CALL(consumer, OnClientLoginSuccess(_))
@@ -247,7 +327,7 @@ TEST_F(GaiaAuthenticator2Test, FullLogin) {
TestingProfile profile;
- MockFactory factory;
+ MockFactory<MockFetcher> factory;
URLFetcher::set_factory(&factory);
GaiaAuthenticator2 auth(&consumer, std::string(),
@@ -268,7 +348,7 @@ TEST_F(GaiaAuthenticator2Test, FullLoginFailure) {
TestingProfile profile;
- MockFactory factory;
+ MockFactory<MockFetcher> factory;
URLFetcher::set_factory(&factory);
factory.set_success(false);
diff --git a/chrome/common/net/gaia/gaia_authenticator2_unittest.h b/chrome/common/net/gaia/gaia_authenticator2_unittest.h
index d392ee8..3c6f22c 100644
--- a/chrome/common/net/gaia/gaia_authenticator2_unittest.h
+++ b/chrome/common/net/gaia/gaia_authenticator2_unittest.h
@@ -7,6 +7,9 @@
#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_UNITTEST_H_
#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR2_UNITTEST_H_
+#pragma once
+
+#include <string>
#include "chrome/common/net/gaia/gaia_authenticator2.h"
#include "chrome/common/net/url_fetcher.h"
@@ -18,12 +21,16 @@ class MockFetcher : public URLFetcher {
public:
MockFetcher(bool success,
const GURL& url,
+ const std::string& results,
URLFetcher::RequestType request_type,
URLFetcher::Delegate* d)
: URLFetcher(url, request_type, d),
success_(success),
- url_(url) {}
+ url_(url),
+ results_(results) {}
+
~MockFetcher() {}
+
void Start() {
URLRequestStatus::Status code;
int http_code;
@@ -41,14 +48,16 @@ class MockFetcher : public URLFetcher {
status,
http_code,
ResponseCookies(),
- std::string());
+ results_);
}
private:
bool success_;
GURL url_;
+ std::string results_;
DISALLOW_COPY_AND_ASSIGN(MockFetcher);
};
+template<typename T>
class MockFactory : public URLFetcher::Factory {
public:
MockFactory()
@@ -58,13 +67,17 @@ class MockFactory : public URLFetcher::Factory {
const GURL& url,
URLFetcher::RequestType request_type,
URLFetcher::Delegate* d) {
- return new MockFetcher(success_, url, request_type, d);
+ return new T(success_, url, results_, request_type, d);
}
void set_success(bool success) {
success_ = success;
}
+ void set_results(const std::string& results) {
+ results_ = results;
+ }
private:
bool success_;
+ std::string results_;
DISALLOW_COPY_AND_ASSIGN(MockFactory);
};
diff --git a/chrome/common/net/http_return.h b/chrome/common/net/http_return.h
index f47d1bb..7cb7731 100644
--- a/chrome/common/net/http_return.h
+++ b/chrome/common/net/http_return.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NET_HTTP_RETURN_H_
#define CHROME_COMMON_NET_HTTP_RETURN_H_
+#pragma once
// TODO(sanjeevr): This has been moved from the sync library so it only
// contains a few HTTP return codes. Add more HTTP return codes.
diff --git a/chrome/common/net/net_resource_provider.cc b/chrome/common/net/net_resource_provider.cc
index 6992470..c64c81d 100644
--- a/chrome/common/net/net_resource_provider.cc
+++ b/chrome/common/net/net_resource_provider.cc
@@ -25,19 +25,19 @@ namespace {
struct LazyDirectoryListerCacher {
LazyDirectoryListerCacher() {
DictionaryValue value;
- value.SetString(L"header",
- l10n_util::GetString(IDS_DIRECTORY_LISTING_HEADER));
- value.SetString(L"parentDirText",
- l10n_util::GetString(IDS_DIRECTORY_LISTING_PARENT));
- value.SetString(L"headerName",
- l10n_util::GetString(IDS_DIRECTORY_LISTING_NAME));
- value.SetString(L"headerSize",
- l10n_util::GetString(IDS_DIRECTORY_LISTING_SIZE));
- value.SetString(L"headerDateModified",
- l10n_util::GetString(IDS_DIRECTORY_LISTING_DATE_MODIFIED));
- value.SetString(L"listingParsingErrorBoxText",
- l10n_util::GetStringF(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT,
- l10n_util::GetString(IDS_PRODUCT_NAME)));
+ value.SetString("header",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_HEADER));
+ value.SetString("parentDirText",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_PARENT));
+ value.SetString("headerName",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_NAME));
+ value.SetString("headerSize",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_SIZE));
+ value.SetString("headerDateModified",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_DATE_MODIFIED));
+ value.SetString("listingParsingErrorBoxText",
+ l10n_util::GetStringFUTF16(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
html_data = jstemplate_builder::GetI18nTemplateHtml(
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_DIR_HEADER_HTML),
diff --git a/chrome/common/net/net_resource_provider.h b/chrome/common/net/net_resource_provider.h
index 4965adf..c577075 100644
--- a/chrome/common/net/net_resource_provider.h
+++ b/chrome/common/net/net_resource_provider.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_
#define CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_
+#pragma once
namespace base {
class StringPiece;
diff --git a/chrome/common/net/predictor_common.h b/chrome/common/net/predictor_common.h
index c1d995f..55653bb 100644
--- a/chrome/common/net/predictor_common.h
+++ b/chrome/common/net/predictor_common.h
@@ -7,6 +7,7 @@
#ifndef CHROME_COMMON_NET_PREDICTOR_COMMON_H_
#define CHROME_COMMON_NET_PREDICTOR_COMMON_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/common/net/socket_stream.h b/chrome/common/net/socket_stream.h
index 6c1ad92..6999842 100644
--- a/chrome/common/net/socket_stream.h
+++ b/chrome/common/net/socket_stream.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NET_SOCKET_STREAM_H_
#define CHROME_COMMON_NET_SOCKET_STREAM_H_
+#pragma once
namespace chrome_common_net {
diff --git a/chrome/common/net/test_url_fetcher_factory.h b/chrome/common/net/test_url_fetcher_factory.h
index 2e4ea45..b34c0a1 100644
--- a/chrome/common/net/test_url_fetcher_factory.h
+++ b/chrome/common/net/test_url_fetcher_factory.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NET_TEST_URL_FETCHER_FACTORY_H_
#define CHROME_COMMON_NET_TEST_URL_FETCHER_FACTORY_H_
+#pragma once
#include <map>
#include <string>
@@ -20,6 +21,8 @@
// Typical usage:
// // TestURLFetcher requires a MessageLoop:
// MessageLoopForUI message_loop;
+// // And io_thread to release URLRequestContextGetter in URLFetcher::Core.
+// ChromeThread io_thread(ChromeThread::IO, &message_loop);
// // Create and register factory.
// TestURLFetcherFactory factory;
// URLFetcher::set_factory(&factory);
diff --git a/chrome/common/net/url_fetcher.cc b/chrome/common/net/url_fetcher.cc
index 8f8f6aa..10c9e96 100644
--- a/chrome/common/net/url_fetcher.cc
+++ b/chrome/common/net/url_fetcher.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.
@@ -365,7 +365,7 @@ void URLFetcher::set_request_context(
core_->request_context_getter_ = request_context_getter;
}
-void URLFetcher::set_automatcally_retry_on_5xx(bool retry) {
+void URLFetcher::set_automatically_retry_on_5xx(bool retry) {
automatically_retry_on_5xx_ = retry;
}
diff --git a/chrome/common/net/url_fetcher.h b/chrome/common/net/url_fetcher.h
index 7a8fd32..fbdd36f 100644
--- a/chrome/common/net/url_fetcher.h
+++ b/chrome/common/net/url_fetcher.h
@@ -9,6 +9,7 @@
#ifndef CHROME_COMMON_NET_URL_FETCHER_H_
#define CHROME_COMMON_NET_URL_FETCHER_H_
+#pragma once
#include <string>
@@ -73,11 +74,17 @@ class URLFetcher {
int response_code,
const ResponseCookies& cookies,
const std::string& data) = 0;
+<<<<<<< HEAD
#ifdef ANDROID
// TODO: Upstream.
virtual
#endif
~Delegate() { }
+=======
+
+ protected:
+ virtual ~Delegate() {}
+>>>>>>> Chromium at release 7.0.540.0
};
// URLFetcher::Create uses the currently registered Factory to create the
@@ -88,11 +95,17 @@ class URLFetcher {
const GURL& url,
RequestType request_type,
Delegate* d) = 0;
+<<<<<<< HEAD
#ifdef ANDROID
// TODO: Upstream
virtual
#endif
~Factory() { }
+=======
+
+ protected:
+ virtual ~Factory() {}
+>>>>>>> Chromium at release 7.0.540.0
};
// |url| is the URL to send the request to.
@@ -147,20 +160,29 @@ class URLFetcher {
// Set the URLRequestContext on the request. Must be called before the
// request is started.
+<<<<<<< HEAD
#ifdef ANDROID
// TODO: Upstream.
virtual
#endif
void set_request_context(URLRequestContextGetter* request_context_getter);
+=======
+ void set_request_context(
+ URLRequestContextGetter* request_context_getter);
+>>>>>>> Chromium at release 7.0.540.0
// If |retry| is false, 5xx responses will be propagated to the observer,
// if it is true URLFetcher will automatically re-execute the request,
// after backoff_delay() elapses. URLFetcher has it set to true by default.
+<<<<<<< HEAD
#ifdef ANDROID
// TODO: Upstream.
virtual
#endif
void set_automatcally_retry_on_5xx(bool retry);
+=======
+ void set_automatically_retry_on_5xx(bool retry);
+>>>>>>> Chromium at release 7.0.540.0
// Returns the back-off delay before the request will be retried,
// when a 5xx response was received.
diff --git a/chrome/common/net/url_fetcher_protect.h b/chrome/common/net/url_fetcher_protect.h
index 0b9c624..980353c 100644
--- a/chrome/common/net/url_fetcher_protect.h
+++ b/chrome/common/net/url_fetcher_protect.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.
//
@@ -7,6 +7,7 @@
#ifndef CHROME_COMMON_NET_URL_FETCHER_PROTECT_H_
#define CHROME_COMMON_NET_URL_FETCHER_PROTECT_H_
+#pragma once
#include <map>
#include <queue>
@@ -60,6 +61,11 @@ class URLFetcherProtectEntry {
return max_retries_;
}
+ // Sets the max retries.
+ void SetMaxRetries(int max_retries) {
+ max_retries_ = max_retries;
+ }
+
private:
// When a request comes, calculate the release time for it.
// Returns the backoff time before sending.
diff --git a/chrome/common/net/url_fetcher_unittest.cc b/chrome/common/net/url_fetcher_unittest.cc
index 5e39c2a..3fc8469 100644
--- a/chrome/common/net/url_fetcher_unittest.cc
+++ b/chrome/common/net/url_fetcher_unittest.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,8 +10,8 @@
#include "chrome/common/net/url_fetcher_protect.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/http/http_response_headers.h"
-#include "net/test/test_server.h"
#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
@@ -21,7 +21,7 @@ using base::TimeDelta;
namespace {
-const wchar_t kDocRoot[] = L"chrome/test/data";
+const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
class TestURLRequestContextGetter : public URLRequestContextGetter {
public:
@@ -336,7 +336,7 @@ void URLFetcherProtectTestPassedThrough::CreateFetcher(const GURL& url) {
fetcher_ = new URLFetcher(url, URLFetcher::GET, this);
fetcher_->set_request_context(new TestURLRequestContextGetter(
io_message_loop_proxy()));
- fetcher_->set_automatcally_retry_on_5xx(false);
+ fetcher_->set_automatically_retry_on_5xx(false);
start_time_ = Time::Now();
fetcher_->Start();
}
@@ -358,12 +358,13 @@ void URLFetcherProtectTestPassedThrough::OnURLFetchComplete(
// Check that suggested back off time is bigger than 0.
EXPECT_GT(fetcher_->backoff_delay().InMicroseconds(), 0);
EXPECT_FALSE(data.empty());
- delete fetcher_;
- io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
} else {
// We should not get here!
- FAIL();
+ ADD_FAILURE();
}
+
+ delete fetcher_;
+ io_message_loop_proxy()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
@@ -431,22 +432,21 @@ void URLFetcherCancelTest::CancelRequest() {
}
TEST_F(URLFetcherTest, SameThreadsTest) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
// Create the fetcher on the main thread. Since IO will happen on the main
// thread, this will test URLFetcher's ability to do everything on one
// thread.
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
-
- CreateFetcher(GURL(server->TestServerPage("defaultresponse")));
+ CreateFetcher(test_server.GetURL("defaultresponse"));
MessageLoop::current()->Run();
}
TEST_F(URLFetcherTest, DifferentThreadsTest) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
// Create a separate thread that will create the URLFetcher. The current
// (main) thread will do the IO, and when the fetch is complete it will
// terminate the main thread's message loop; then the other thread's
@@ -455,33 +455,34 @@ TEST_F(URLFetcherTest, DifferentThreadsTest) {
base::Thread t("URLFetcher test thread");
ASSERT_TRUE(t.Start());
t.message_loop()->PostTask(FROM_HERE, new FetcherWrapperTask(this,
- GURL(server->TestServerPage("defaultresponse"))));
+ test_server.GetURL("defaultresponse")));
MessageLoop::current()->Run();
}
TEST_F(URLFetcherPostTest, Basic) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
- CreateFetcher(GURL(server->TestServerPage("echo")));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
+ CreateFetcher(test_server.GetURL("echo"));
MessageLoop::current()->Run();
}
TEST_F(URLFetcherHeadersTest, Headers) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"net/data/url_request_unittest", NULL);
- ASSERT_TRUE(NULL != server.get());
- CreateFetcher(GURL(server->TestServerPage("files/with-headers.html")));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest")));
+ ASSERT_TRUE(test_server.Start());
+
+ CreateFetcher(test_server.GetURL("files/with-headers.html"));
MessageLoop::current()->Run();
// The actual tests are in the URLFetcherHeadersTest fixture.
}
TEST_F(URLFetcherProtectTest, Overload) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL url = GURL(server->TestServerPage("defaultresponse"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL url(test_server.GetURL("defaultresponse"));
// Registers an entry for test url. It only allows 3 requests to be sent
// in 200 milliseconds.
@@ -496,10 +497,10 @@ TEST_F(URLFetcherProtectTest, Overload) {
}
TEST_F(URLFetcherProtectTest, ServerUnavailable) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL url = GURL(server->TestServerPage("files/server-unavailable.html"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL url(test_server.GetURL("files/server-unavailable.html"));
// Registers an entry for test url. The backoff time is calculated by:
// new_backoff = 2.0 * old_backoff + 0
@@ -516,10 +517,10 @@ TEST_F(URLFetcherProtectTest, ServerUnavailable) {
}
TEST_F(URLFetcherProtectTestPassedThrough, ServerUnavailablePropagateResponse) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL url = GURL(server->TestServerPage("files/server-unavailable.html"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL url(test_server.GetURL("files/server-unavailable.html"));
// Registers an entry for test url. The backoff time is calculated by:
// new_backoff = 2.0 * old_backoff + 0
@@ -539,20 +540,19 @@ TEST_F(URLFetcherProtectTestPassedThrough, ServerUnavailablePropagateResponse) {
TEST_F(URLFetcherBadHTTPSTest, BadHTTPSTest) {
- scoped_refptr<HTTPSTestServer> server =
- HTTPSTestServer::CreateExpiredServer(kDocRoot);
- ASSERT_TRUE(NULL != server.get());
-
- CreateFetcher(GURL(server->TestServerPage("defaultresponse")));
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE,
+ FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+ CreateFetcher(test_server.GetURL("defaultresponse"));
MessageLoop::current()->Run();
}
TEST_F(URLFetcherCancelTest, ReleasesContext) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL url = GURL(server->TestServerPage("files/server-unavailable.html"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL url(test_server.GetURL("files/server-unavailable.html"));
// Registers an entry for test url. The backoff time is calculated by:
// new_backoff = 2.0 * old_backoff + 0
@@ -576,10 +576,10 @@ TEST_F(URLFetcherCancelTest, ReleasesContext) {
}
TEST_F(URLFetcherCancelTest, CancelWhileDelayedStartTaskPending) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"chrome/test/data", NULL);
- ASSERT_TRUE(NULL != server.get());
- GURL url = GURL(server->TestServerPage("files/server-unavailable.html"));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot));
+ ASSERT_TRUE(test_server.Start());
+
+ GURL url(test_server.GetURL("files/server-unavailable.html"));
// Register an entry for test url.
//
diff --git a/chrome/common/net/url_request_context_getter.h b/chrome/common/net/url_request_context_getter.h
index dcc77b3..34aa668 100644
--- a/chrome/common/net/url_request_context_getter.h
+++ b/chrome/common/net/url_request_context_getter.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NET_URL_REQUEST_CONTEXT_GETTER_H_
#define CHROME_COMMON_NET_URL_REQUEST_CONTEXT_GETTER_H_
+#pragma once
#include "base/ref_counted.h"
#include "base/task.h"
diff --git a/chrome/common/net/url_request_intercept_job.cc b/chrome/common/net/url_request_intercept_job.cc
index ed68fcd..242b7c1 100644
--- a/chrome/common/net/url_request_intercept_job.cc
+++ b/chrome/common/net/url_request_intercept_job.cc
@@ -14,6 +14,7 @@
#include "chrome/common/notification_service.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/base/x509_certificate.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
@@ -134,7 +135,8 @@ void URLRequestInterceptJob::GetResponseInfo(net::HttpResponseInfo* info) {
WriteInto(&raw_headers, size+1), size);
if (rv != CPERR_SUCCESS) {
// TODO(mpcomplete): what should we do here?
- raw_headers = "HTTP/1.1 404 Not Found" + '\0';
+ raw_headers = "HTTP/1.1 404 Not Found";
+ raw_headers.push_back('\0');
}
info->headers = new net::HttpResponseHeaders(raw_headers);
diff --git a/chrome/common/net/url_request_intercept_job.h b/chrome/common/net/url_request_intercept_job.h
index 3b7058b..3835fe5 100644
--- a/chrome/common/net/url_request_intercept_job.h
+++ b/chrome/common/net/url_request_intercept_job.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NET_URL_REQUEST_INTERCEPT_JOB_H_
#define CHROME_COMMON_NET_URL_REQUEST_INTERCEPT_JOB_H_
+#pragma once
#include <string>
diff --git a/chrome/common/notification_details.h b/chrome/common/notification_details.h
index 92c1906..4d243cf 100644
--- a/chrome/common/notification_details.h
+++ b/chrome/common/notification_details.h
@@ -7,6 +7,7 @@
#ifndef CHROME_COMMON_NOTIFICATION_DETAILS_H__
#define CHROME_COMMON_NOTIFICATION_DETAILS_H__
+#pragma once
#include "base/basictypes.h"
diff --git a/chrome/common/notification_observer.h b/chrome/common/notification_observer.h
index 8ad4d4a..b0af25e 100644
--- a/chrome/common/notification_observer.h
+++ b/chrome/common/notification_observer.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NOTIFICATION_OBSERVER_H_
#define CHROME_COMMON_NOTIFICATION_OBSERVER_H_
+#pragma once
class NotificationDetails;
class NotificationSource;
diff --git a/chrome/common/notification_observer_mock.h b/chrome/common/notification_observer_mock.h
index 9eeb665..0385f26 100644
--- a/chrome/common/notification_observer_mock.h
+++ b/chrome/common/notification_observer_mock.h
@@ -4,13 +4,15 @@
#ifndef CHROME_COMMON_NOTIFICATION_OBSERVER_MOCK_H_
#define CHROME_COMMON_NOTIFICATION_OBSERVER_MOCK_H_
+#pragma once
-#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"
+class NotificationDetails;
+class NotificationSource;
+
class NotificationObserverMock : public NotificationObserver {
public:
NotificationObserverMock() {}
diff --git a/chrome/common/notification_registrar.h b/chrome/common/notification_registrar.h
index f8dd743..1207d99 100644
--- a/chrome/common/notification_registrar.h
+++ b/chrome/common/notification_registrar.h
@@ -4,11 +4,15 @@
#ifndef CHROME_COMMON_NOTIFICATION_REGISTRAR_H_
#define CHROME_COMMON_NOTIFICATION_REGISTRAR_H_
+#pragma once
#include <vector>
#include "base/basictypes.h"
-#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_type.h"
+
+class NotificationObserver;
+class NotificationSource;
// Aids in registering for notifications and ensures that all registered
// notifications are unregistered when the class is destroyed.
diff --git a/chrome/common/notification_service.cc b/chrome/common/notification_service.cc
index e127ccf..cd92bb3 100644
--- a/chrome/common/notification_service.cc
+++ b/chrome/common/notification_service.cc
@@ -6,6 +6,7 @@
#include "base/lazy_instance.h"
#include "base/thread_local.h"
+#include "chrome/common/notification_observer.h"
static base::LazyInstance<base::ThreadLocalPointer<NotificationService> >
lazy_tls_ptr(base::LINKER_INITIALIZED);
@@ -131,9 +132,12 @@ NotificationService::~NotificationService() {
if (observer_counts_[i] > 0) {
// This may not be completely fixable -- see
// http://code.google.com/p/chromium/issues/detail?id=11010 .
- // But any new leaks should be fixed.
- LOG(INFO) << observer_counts_[i] << " notification observer(s) leaked"
- << " of notification type " << i;
+
+ // It would be nice to track new leaks, but this currently
+ // spams the console too much to be useful, making it hard to track
+ // down other problems.
+ // LOG(INFO) << observer_counts_[i] << " notification observer(s) leaked"
+ // << " of notification type " << i;
}
}
#endif
diff --git a/chrome/common/notification_service.h b/chrome/common/notification_service.h
index fefc09c..c20b98d 100644
--- a/chrome/common/notification_service.h
+++ b/chrome/common/notification_service.h
@@ -8,12 +8,12 @@
#ifndef CHROME_COMMON_NOTIFICATION_SERVICE_H_
#define CHROME_COMMON_NOTIFICATION_SERVICE_H_
+#pragma once
#include <map>
#include "base/observer_list.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"
diff --git a/chrome/common/notification_service_unittest.cc b/chrome/common/notification_service_unittest.cc
index d65f6e5..8578eb9 100644
--- a/chrome/common/notification_service_unittest.cc
+++ b/chrome/common/notification_service_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 "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/common/notification_source.h b/chrome/common/notification_source.h
index 1813c2e..81ed1c1 100644
--- a/chrome/common/notification_source.h
+++ b/chrome/common/notification_source.h
@@ -7,6 +7,7 @@
#ifndef CHROME_COMMON_NOTIFICATION_SOURCE_H__
#define CHROME_COMMON_NOTIFICATION_SOURCE_H__
+#pragma once
#include "base/basictypes.h"
@@ -42,7 +43,7 @@ template <class T>
class Source : public NotificationSource {
public:
// TODO(erg): Our code hard relies on implicit conversion
- Source(T* ptr) : NotificationSource(ptr) {} // NOLINT
+ Source(const T* ptr) : NotificationSource(ptr) {} // NOLINT
Source(const NotificationSource& other) // NOLINT
: NotificationSource(other) {}
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index 9f75bb4..541aaa9 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_NOTIFICATION_TYPE_H_
#define CHROME_COMMON_NOTIFICATION_TYPE_H_
+#pragma once
// This file describes various types used to describe and filter notifications
// that pass through the NotificationService.
@@ -85,6 +86,10 @@ class NotificationType {
// Other load-related (not from NavigationController) ----------------------
+ // Corresponds to ViewHostMsg_DocumentOnLoadCompletedInMainFrame. The source
+ // is the TabContents and the details the page_id.
+ LOAD_COMPLETED_MAIN_FRAME,
+
// A content load is starting. The source will be a
// Source<NavigationController> corresponding to the tab in which the load
// is occurring. No details are expected for this notification.
@@ -98,10 +103,17 @@ class NotificationType {
// A frame is staring a provisional load. The source is a
// Source<NavigationController> corresponding to the tab in which the load
- // occurs. Details is a bool specifying if the load occurs in the main
- // frame (or a sub-frame if false).
+ // occurs. Details is a ProvisionalLoadDetails object.
FRAME_PROVISIONAL_LOAD_START,
+ // The provisional load for a frame was committed. The source is a
+ // NavigationController corresponding to the tab in which the load occured.
+ // Details is a ProvisionalLoadDetails object. In contrast to
+ // NAV_ENTRY_COMMITTED, this notification is sent when the load was
+ // committed, even if no navigation entry was committed (such as
+ // AUTO_SUBFRAME navigations).
+ FRAME_PROVISIONAL_LOAD_COMMITTED,
+
// Content was loaded from an in-memory cache. The source will be a
// Source<NavigationController> corresponding to the tab in which the load
// occurred. Details in the form of a LoadFromMemoryCacheDetails object
@@ -282,10 +294,6 @@ class NotificationType {
// is the dialog.
APP_MODAL_DIALOG_SHOWN,
- // Sent after an application-modal dialog has been closed. The source
- // is the dialog.
- APP_MODAL_DIALOG_CLOSED,
-
// Tabs --------------------------------------------------------------------
// Sent when a tab is added to a TabContentsDelegate. The source is the
@@ -426,9 +434,9 @@ class NotificationType {
// first RenderViewHost is set).
RENDER_VIEW_HOST_CHANGED,
- // Indicates that the render view host has received a new accessibility tree
- // from the render view. The source is the RenderViewHost, the details
- // are not used.
+ // Indicates that the render view host has received an accessibility tree
+ // update, either partial or full, from the render view. The source is the
+ // RenderViewHost, the details are not used.
RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED,
// This is sent when a RenderWidgetHost is being destroyed. The source is
@@ -471,11 +479,6 @@ class NotificationType {
// NoDetails.
BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
- // This is sent when the user's preference (for when the extension shelf
- // should be shown) changes. The source is the profile, and the details are
- // NoDetails.
- EXTENSION_SHELF_VISIBILITY_PREF_CHANGED,
-
// Sent just before the installation confirm dialog is shown. The source
// is the ExtensionInstallUI, the details are NoDetails.
EXTENSION_WILL_SHOW_CONFIRM_DIALOG,
@@ -548,6 +551,14 @@ class NotificationType {
// interception. No details are expected.
CHROME_PLUGIN_UNLOADED,
+ // This is sent in the RenderView when previously blocked plugins on a page
+ // should be loaded. The source is the RenderView. No details are expected.
+ SHOULD_LOAD_PLUGINS,
+
+ // Sent by the PluginUpdater when there is a change of plugin
+ // enable/disable status.
+ PLUGIN_ENABLE_STATUS_CHANGED,
+
// This is sent when a login prompt is shown. The source is the
// Source<NavigationController> for the tab in which the prompt is shown.
// Details are a LoginNotificationDetails which provide the LoginHandler
@@ -678,7 +689,7 @@ class NotificationType {
WEB_APP_INSTALL_CHANGED,
// This is sent to a pref observer when a pref is changed. The source is the
- // PrefService and the details a std::wstring of the changed path.
+ // PrefService and the details a std::string of the changed path.
PREF_CHANGED,
// Sent when a default request context has been created, so calling
@@ -709,6 +720,9 @@ class NotificationType {
// Sent by the autocomplete edit when it is destroyed.
AUTOCOMPLETE_EDIT_DESTROYED,
+ // Sent by the autocomplete edit when it is focused.
+ AUTOCOMPLETE_EDIT_FOCUSED,
+
// Sent when the main Google URL has been updated. Some services cache
// this value and need to update themselves when it changes. See
// google_util::GetGoogleURLAndUpdateIfNecessary().
@@ -783,6 +797,13 @@ class NotificationType {
// details about why the install failed.
EXTENSION_INSTALL_ERROR,
+ // Sent when a new extension is being uninstalled. When this notification
+ // is sent, the ExtensionsService still is tracking this extension (it has
+ // not been unloaded yet). This will be followed by an EXTENSION_UNLOADED
+ // or EXTENSION_UNLOADED_DISABLED when the extension is actually unloaded.
+ // The details are an Extension and the source is a Profile.
+ 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.
@@ -836,9 +857,6 @@ class NotificationType {
// during browser shutdown.
EXTENSION_PROCESS_TERMINATED,
- // Sent when the contents or order of toolstrips in the shelf model change.
- EXTENSION_SHELF_MODEL_CHANGED,
-
// Sent when a background page is ready so other components can load.
EXTENSION_BACKGROUND_PAGE_READY,
@@ -867,6 +885,12 @@ class NotificationType {
EXTENSION_TEST_PASSED,
EXTENSION_TEST_FAILED,
+ // Sent by extension test javascript code, typically in a browser test. The
+ // sender is a std::string representing the extension id, and the details
+ // are a std::string with some message. This is particularly useful when you
+ // want to have C++ code wait for javascript code to do something.
+ EXTENSION_TEST_MESSAGE,
+
// Sent when an bookmarks extensions API function was successfully invoked.
// The source is the id of the extension that invoked the function, and the
// details are a pointer to the const BookmarksFunction in question.
@@ -881,11 +905,10 @@ class NotificationType {
// session. The source is the profile.
EXTENSION_OMNIBOX_INPUT_ENTERED,
- // Debugging ---------------------------------------------------------------
-
- // TODO(mpcomplete): Sent to diagnose a bug. Remove when fixed.
- // http://code.google.com/p/chromium/issues/detail?id=21201
- EXTENSION_PORT_DELETED_DEBUG,
+ // Sent when an extension changes a preference value. The source is the
+ // profile, and the details are an ExtensionPrefStore::ExtensionPrefDetails
+ // object.
+ EXTENSION_PREF_CHANGED,
// Desktop Notifications ---------------------------------------------------
@@ -1005,23 +1028,81 @@ class NotificationType {
// operations.
SESSION_SERVICE_SAVED,
+ // A foreign session has been updated. If a new tab page is open, the
+ // foreign session handler needs to update the new tab page's foreign
+ // session data.
+ FOREIGN_SESSION_UPDATED,
+
+ // A foreign session has been deleted. If a new tab page is open, the
+ // foreign session handler needs to update the new tab page's foreign
+ // session data.
+ FOREIGN_SESSION_DELETED,
+
// The syncer requires a passphrase to decrypt sensitive updates. This
// notification is sent when the first sensitive data type is setup by the
// user as well as anytime any the passphrase is changed in another synced
- // client.
+ // client. The source is the SyncBackendHost wanting a passphrase. No
+ // details.
SYNC_PASSPHRASE_REQUIRED,
// Sent when the passphrase provided by the user is accepted. After this
// notification is sent, updates to sensitive nodes are encrypted using the
- // accepted passphrase.
+ // accepted passphrase. The source is the SyncBackendHost that accepted
+ // the passphrase. No details.
SYNC_PASSPHRASE_ACCEPTED,
+ // Sent when the set of data types that should be synced has been modified
+ // externally (eg. by the dom_ui options screen).
+ // The source is the Profile, there are no details.
+ SYNC_DATA_TYPES_UPDATED,
+
// Cookies -----------------------------------------------------------------
// Sent when a cookie changes. The source is a Profile object, the details
// are a ChromeCookieDetails object.
COOKIE_CHANGED,
+ // Sidebar -----------------------------------------------------------------
+
+ // Sent when the sidebar state is changed.
+ // The source is a SidebarManager instance, the details are the changed
+ // SidebarContainer object.
+ SIDEBAR_CHANGED,
+
+ // Token Service -----------------------------------------------------------
+
+ // When the token service has a new token available for a service, one of
+ // these notifications is issued per new token.
+ // The source is a TokenService on the Profile. The details are a
+ // TokenAvailableDetails object.
+ TOKEN_AVAILABLE,
+
+ // When there aren't any additional tokens left to load, this notification
+ // is sent.
+ // The source is a TokenService on the profile. There are no details.
+ TOKEN_LOADING_FINISHED,
+
+ // If a token request failed, one of these is issued per failed request.
+ // The source is a TokenService on the Profile. The details are a
+ // TokenRequestFailedDetails object.
+ TOKEN_REQUEST_FAILED,
+
+ // When a service has a new token they got from a frontend that the
+ // TokenService should know about, fire this notification. The details
+ // are a TokenAvailableDetails object.
+ TOKEN_UPDATED,
+
+ // Sent when a user signs into Google services such as sync.
+ // The source is the SigninManager instance. The details are a
+ // GoogleServiceSignin object.
+ GOOGLE_SIGNIN_SUCCESSFUL,
+
+ // Sent when a user fails to sign into Google services such as sync.
+ // The source is the SigninManager instance. The details are a
+ // GoogleServiceAuthError object.
+ GOOGLE_SIGNIN_FAILED,
+
+
// Misc --------------------------------------------------------------------
#if defined(OS_CHROMEOS)
@@ -1054,6 +1135,19 @@ class NotificationType {
// in chrome/browser/chromeos/network_state_notifier.h.
// TODO(oshima): Port this to all platforms.
NETWORK_STATE_CHANGED,
+
+ // Sent when an attempt to acquire the public key of the owner of a chromium
+ // os device has succeeded.
+ OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED,
+
+ // Sent when an attempt to acquire the public key of the owner of a chromium
+ // os device has failed.
+ OWNER_KEY_FETCH_ATTEMPT_FAILED,
+
+ // 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.
+ SYSTEM_SETTING_CHANGED,
#endif
// Sent before the repost form warning is brought up.
@@ -1085,6 +1179,11 @@ 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,
+
// 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/owned_widget_gtk.cc b/chrome/common/owned_widget_gtk.cc
deleted file mode 100644
index f9b8bef..0000000
--- a/chrome/common/owned_widget_gtk.cc
+++ /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.
-
-#include "chrome/common/owned_widget_gtk.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-
-OwnedWidgetGtk::~OwnedWidgetGtk() {
- DCHECK(!widget_) << "You must explicitly call OwnerWidgetGtk::Destroy().";
-}
-
-void OwnedWidgetGtk::Own(GtkWidget* widget) {
- DCHECK(!widget_);
- // We want to make sure that Own() was called properly, right after the
- // widget was created. There should be a floating reference.
- DCHECK(g_object_is_floating(widget));
-
- // Sink the floating reference, we should now own this reference.
- g_object_ref_sink(widget);
- widget_ = widget;
-}
-
-void OwnedWidgetGtk::Destroy() {
- if (!widget_)
- return;
-
- GtkWidget* widget = widget_;
- widget_ = NULL;
- gtk_widget_destroy(widget);
-
- DCHECK(!g_object_is_floating(widget));
- // NOTE: Assumes some implementation details about glib internals.
- DCHECK_EQ(G_OBJECT(widget)->ref_count, 1U);
- g_object_unref(widget);
-}
diff --git a/chrome/common/owned_widget_gtk.h b/chrome/common/owned_widget_gtk.h
deleted file mode 100644
index 72fadd5..0000000
--- a/chrome/common/owned_widget_gtk.h
+++ /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.
-
-// This class assists you in dealing with a specific situation when managing
-// ownership between a C++ object and a GTK widget. It is common to have a
-// C++ object which encapsulates a GtkWidget, and that widget is exposed from
-// the object for use outside of the class. In this situation, you commonly
-// want the GtkWidget's lifetime to match its C++ object's lifetime. Using an
-// OwnedWigetGtk will take ownership over the initial reference of the
-// GtkWidget, so that it is "owned" by the C++ object. Example usage:
-//
-// class FooViewGtk() {
-// public:
-// FooViewGtk() { }
-// ~FooViewGtk() { widget_.Destroy(); }
-// void Init() { vbox_.Own(gtk_vbox_new()); }
-// GtkWidget* widget() { return vbox_.get() }; // Host my widget!
-// private:
-// OwnedWidgetGtk vbox_;
-// };
-//
-// This design will ensure that the widget stays alive from the call to Own()
-// until the call to Destroy().
-//
-// - Details of the problem and OwnedWidgetGtk's solution:
-// In order to make passing ownership more convenient for newly created
-// widgets, GTK has a concept of a "floating" reference. All GtkObjects (and
-// thus GtkWidgets) inherit from GInitiallyUnowned. When they are created, the
-// object starts with a reference count of 1, but has its floating flag set.
-// When it is put into a container for the first time, that container will
-// "sink" the floating reference, and the count will still be 1. Now the
-// container owns the widget, and if we remove the widget from the container,
-// the widget is destroyed. This style of ownership often causes problems when
-// you have an object encapsulating the widget. If we just use a raw
-// GtkObject* with no specific ownership management, we push the widget's
-// ownership onto the user of the class. Now the C++ object can't depend on
-// the widget being valid, since it doesn't manage its lifetime. If the widget
-// was removed from a container, removing its only reference, it would be
-// destroyed (from the C++ object's perspective) unexpectantly destroyed. The
-// solution is fairly simple, make sure that the C++ object owns the widget,
-// and thus it is also responsible for destroying it. This boils down to:
-// GtkWidget* widget = gtk_widget_new();
-// g_object_ref_sink(widget); // Claim the initial floating reference.
-// ...
-// gtk_destroy_widget(widget); // Ask all code to destroy their references.
-// g_object_unref(widget); // Destroy the initial reference we had claimed.
-
-#ifndef CHROME_COMMON_OWNED_WIDGET_GTK_H_
-#define CHROME_COMMON_OWNED_WIDGET_GTK_H_
-
-#include "base/basictypes.h"
-
-typedef struct _GtkWidget GtkWidget;
-
-class OwnedWidgetGtk {
- public:
- // Create an instance that isn't managing any ownership.
- OwnedWidgetGtk() : widget_(NULL) { }
- // Create an instance that owns |widget|.
- explicit OwnedWidgetGtk(GtkWidget* widget) : widget_(NULL) { Own(widget); }
-
- ~OwnedWidgetGtk();
-
- // Return the currently owned widget, or NULL if no widget is owned.
- GtkWidget* get() const { return widget_; }
- GtkWidget* operator->() const { return widget_; }
-
- // Takes ownership of a widget, by taking the initial floating reference of
- // the GtkWidget. It is expected that Own() is called right after the widget
- // has been created, and before any other references to the widget might have
- // been added. It is valid to never call Own(), in which case Destroy() will
- // do nothing. If Own() has been called, you must explicitly call Destroy().
- void Own(GtkWidget* widget);
-
- // You must call Destroy() after you have called Own(). Calling Destroy()
- // will call gtk_widget_destroy(), and drop our reference to the widget.
- // After a call to Destroy(), you may call Own() again. NOTE: It is expected
- // that after gtk_widget_destroy we will be holding the only reference left
- // on the object. We assert this in debug mode to help catch any leaks.
- void Destroy();
-
- private:
- GtkWidget* widget_;
-
- DISALLOW_COPY_AND_ASSIGN(OwnedWidgetGtk);
-};
-
-#endif // CHROME_COMMON_OWNED_WIDGET_GTK_H_
diff --git a/chrome/common/page_transition_types.cc b/chrome/common/page_transition_types.cc
index bf686f9..1079ea0 100644
--- a/chrome/common/page_transition_types.cc
+++ b/chrome/common/page_transition_types.cc
@@ -34,3 +34,20 @@ const char* PageTransition::CoreTransitionString(Type type) {
}
return NULL;
}
+
+// static
+const char* PageTransition::QualifierString(Type type) {
+ DCHECK_NE((int)(type & (CLIENT_REDIRECT | SERVER_REDIRECT)),
+ (int)(CLIENT_REDIRECT | SERVER_REDIRECT));
+
+ switch (type & (CLIENT_REDIRECT | SERVER_REDIRECT | FORWARD_BACK)) {
+ case CLIENT_REDIRECT: return "client_redirect";
+ case SERVER_REDIRECT: return "server_redirect";
+ case FORWARD_BACK: return "forward_back";
+ case (CLIENT_REDIRECT | FORWARD_BACK):
+ return "client_redirect|forward_back";
+ case (SERVER_REDIRECT | FORWARD_BACK):
+ return "server_redirect|forward_back";
+ }
+ return "";
+}
diff --git a/chrome/common/page_transition_types.h b/chrome/common/page_transition_types.h
index 592fc29..8ca7042 100644
--- a/chrome/common/page_transition_types.h
+++ b/chrome/common/page_transition_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_PAGE_TRANSITION_TYPES_H__
#define CHROME_COMMON_PAGE_TRANSITION_TYPES_H__
+#pragma once
#include "base/basictypes.h"
@@ -101,6 +102,9 @@ class PageTransition {
// Any of the core values above can be augmented by one or more qualifiers.
// These qualifiers further define the transition.
+ // User used the Forward or Back button to navigate among browsing history.
+ FORWARD_BACK = 0x01000000,
+
// The beginning of a navigation chain.
CHAIN_START = 0x10000000,
@@ -156,6 +160,9 @@ class PageTransition {
// Return a string version of the core type values.
static const char* CoreTransitionString(Type type);
+
+ // Return a string version of the qualifier type values.
+ static const char* QualifierString(Type type);
};
#endif // CHROME_COMMON_PAGE_TRANSITION_TYPES_H__
diff --git a/chrome/common/page_zoom.h b/chrome/common/page_zoom.h
index fa2f5bb..25fd388 100644
--- a/chrome/common/page_zoom.h
+++ b/chrome/common/page_zoom.h
@@ -4,6 +4,9 @@
#ifndef CHROME_COMMON_PAGE_ZOOM_H_
#define CHROME_COMMON_PAGE_ZOOM_H_
+#pragma once
+
+#include "base/basictypes.h"
class PageZoom {
public:
diff --git a/chrome/common/pepper_plugin_registry.cc b/chrome/common/pepper_plugin_registry.cc
index 2ed484e..cda5809 100644
--- a/chrome/common/pepper_plugin_registry.cc
+++ b/chrome/common/pepper_plugin_registry.cc
@@ -6,13 +6,18 @@
#include "base/command_line.h"
#include "base/file_util.h"
+#include "base/native_library.h"
#include "base/path_service.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "remoting/client/plugin/pepper_entrypoints.h"
+PepperPluginInfo::PepperPluginInfo() : is_internal(false) {
+}
+
// static
PepperPluginRegistry* PepperPluginRegistry::GetInstance() {
static PepperPluginRegistry registry;
@@ -35,10 +40,24 @@ void PepperPluginRegistry::GetList(std::vector<PepperPluginInfo>* plugins) {
}
// static
+void PepperPluginRegistry::PreloadModules() {
+ std::vector<PepperPluginInfo> plugins;
+ GetList(&plugins);
+ for (size_t i = 0; i < plugins.size(); ++i) {
+ if (!plugins[i].is_internal) {
+ base::NativeLibrary library = base::LoadNativeLibrary(plugins[i].path);
+ LOG_IF(WARNING, !library) << "Unable to load plugin "
+ << plugins[i].path.value();
+ }
+ }
+}
+
+// static
void PepperPluginRegistry::GetPluginInfoFromSwitch(
std::vector<PepperPluginInfo>* plugins) {
- const std::wstring& value = CommandLine::ForCurrentProcess()->GetSwitchValue(
- switches::kRegisterPepperPlugins);
+ const std::string value =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kRegisterPepperPlugins);
if (value.empty())
return;
@@ -47,27 +66,34 @@ void PepperPluginRegistry::GetPluginInfoFromSwitch(
// plugin-entry = <file-path> + ["#" + <name> + ["#" + <description>]] +
// *1( LWS + ";" + LWS + <mime-type> )
- std::vector<std::wstring> modules;
+ std::vector<std::string> modules;
SplitString(value, ',', &modules);
for (size_t i = 0; i < modules.size(); ++i) {
- std::vector<std::wstring> parts;
+ std::vector<std::string> parts;
SplitString(modules[i], ';', &parts);
if (parts.size() < 2) {
DLOG(ERROR) << "Required mime-type not found";
continue;
}
- std::vector<std::wstring> name_parts;
+ std::vector<std::string> name_parts;
SplitString(parts[0], '#', &name_parts);
PepperPluginInfo plugin;
- plugin.path = FilePath::FromWStringHack(name_parts[0]);
+#if defined(OS_WIN)
+ // This means we can't provide plugins from non-ASCII paths, but
+ // since this switch is only for development I don't think that's
+ // too awful.
+ plugin.path = FilePath(ASCIIToUTF16(name_parts[0]));
+#else
+ plugin.path = FilePath(name_parts[0]);
+#endif
if (name_parts.size() > 1)
- plugin.name = WideToUTF8(name_parts[1]);
+ plugin.name = name_parts[1];
if (name_parts.size() > 2)
- plugin.type_descriptions = WideToUTF8(name_parts[2]);
+ plugin.type_descriptions = name_parts[2];
for (size_t j = 1; j < parts.size(); ++j)
- plugin.mime_types.push_back(WideToASCII(parts[j]));
+ plugin.mime_types.push_back(parts[j]);
plugins->push_back(plugin);
}
@@ -76,19 +102,32 @@ void PepperPluginRegistry::GetPluginInfoFromSwitch(
// static
void PepperPluginRegistry::GetExtraPlugins(
std::vector<PepperPluginInfo>* plugins) {
+ // Once we're sandboxed, we can't know if the PDF plugin is
+ // available or not; but (on Linux) this function is always called
+ // once before we're sandboxed. So the first time through test if
+ // the file is available and then skip the check on subsequent calls
+ // if yes.
+ static bool skip_pdf_file_check = false;
FilePath path;
- if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path) &&
- file_util::PathExists(path)) {
- PepperPluginInfo pdf;
- pdf.path = path;
- pdf.name = "Chrome PDF Viewer";
- pdf.mime_types.push_back("application/pdf");
- pdf.file_extensions = "pdf";
- pdf.type_descriptions = "Portable Document Format";
- plugins->push_back(pdf);
+ if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path)) {
+ if (skip_pdf_file_check || file_util::PathExists(path)) {
+ PepperPluginInfo pdf;
+ pdf.path = path;
+ pdf.name = "Chrome PDF Viewer";
+ pdf.mime_types.push_back("application/pdf");
+ pdf.file_extensions = "pdf";
+ pdf.type_descriptions = "Portable Document Format";
+ plugins->push_back(pdf);
+
+ skip_pdf_file_check = true;
+ }
}
}
+PepperPluginRegistry::InternalPluginInfo::InternalPluginInfo() {
+ is_internal = true;
+}
+
// static
void PepperPluginRegistry::GetInternalPluginInfo(
InternalPluginInfoList* plugin_info) {
@@ -105,9 +144,10 @@ void PepperPluginRegistry::GetInternalPluginInfo(
#if defined(ENABLE_REMOTING)
if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableChromoting)) {
+ switches::kEnableRemoting)) {
InternalPluginInfo info;
// Add the chromoting plugin.
+ DCHECK(info.is_internal);
info.path =
FilePath(FILE_PATH_LITERAL("internal-chromoting"));
info.mime_types.push_back("pepper-application/x-chromoting");
diff --git a/chrome/common/pepper_plugin_registry.h b/chrome/common/pepper_plugin_registry.h
index a728381..9b12f7e 100644
--- a/chrome/common/pepper_plugin_registry.h
+++ b/chrome/common/pepper_plugin_registry.h
@@ -4,15 +4,20 @@
#ifndef CHROME_COMMON_PEPPER_PLUGIN_REGISTRY_H_
#define CHROME_COMMON_PEPPER_PLUGIN_REGISTRY_H_
+#pragma once
-#include <string>
#include <map>
+#include <string>
#include <vector>
+#include "base/file_path.h"
#include "webkit/glue/plugins/pepper_plugin_module.h"
struct PepperPluginInfo {
- FilePath path; // Internal plugins are of the form "internal-[name]".
+ PepperPluginInfo(); // Needed to initialize |is_internal|.
+
+ bool is_internal; // Defaults to false (see constructor).
+ FilePath path; // Internal plugins have "internal-[name]" as path.
std::vector<std::string> mime_types;
std::string name;
std::string description;
@@ -30,6 +35,11 @@ class PepperPluginRegistry {
// pepper plugin modules.
static void GetList(std::vector<PepperPluginInfo>* plugins);
+ // Loads the (native) libraries but does not initialize them (i.e., does not
+ // call PPP_InitializeModule). This is needed by the zygote on Linux to get
+ // access to the plugins before entering the sandbox.
+ static void PreloadModules();
+
pepper::PluginModule* GetModule(const FilePath& path) const;
private:
@@ -37,6 +47,7 @@ class PepperPluginRegistry {
static void GetExtraPlugins(std::vector<PepperPluginInfo>* plugins);
struct InternalPluginInfo : public PepperPluginInfo {
+ InternalPluginInfo(); // Sets |is_internal|.
pepper::PluginModule::EntryPoints entry_points;
};
typedef std::vector<InternalPluginInfo> InternalPluginInfoList;
diff --git a/chrome/common/plugin_carbon_interpose_constants_mac.h b/chrome/common/plugin_carbon_interpose_constants_mac.h
index 321dd84..967da77 100644
--- a/chrome/common/plugin_carbon_interpose_constants_mac.h
+++ b/chrome/common/plugin_carbon_interpose_constants_mac.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_PLUGIN_CARBON_INTERPOSE_CONSTANTS_MAC_H_
#define CHROME_COMMON_PLUGIN_CARBON_INTERPOSE_CONSTANTS_MAC_H_
+#pragma once
#if !defined(__LP64__)
diff --git a/chrome/common/plugin_group.cc b/chrome/common/plugin_group.cc
index 5df39b3..a493014 100644
--- a/chrome/common/plugin_group.cc
+++ b/chrome/common/plugin_group.cc
@@ -4,30 +4,34 @@
#include "chrome/common/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"
#if defined(OS_MACOSX)
// Plugin Groups for Mac.
// Plugins are listed here as soon as vulnerabilities and solutions
// (new versions) are published.
-// TODO(panayiotis): Track Java as soon as it's supported on Chrome Mac.
// TODO(panayiotis): Get the Real Player version on Mac, somehow.
static const PluginGroupDefinition kGroupDefinitions[] = {
- { "Quicktime", "QuickTime Plug-in", "", "", "7.6.6",
+ { "apple-quicktime", "Quicktime", "QuickTime Plug-in", "", "", "7.6.6",
"http://www.apple.com/quicktime/download/" },
- { "Flash", "Shockwave Flash", "", "", "10.1.53",
+ { "java-runtime-environment", "Java", "Java", "", "", "",
+ "http://support.apple.com/kb/HT1338" },
+ { "adobe-flash-player", "Flash", "Shockwave Flash", "", "", "10.1.82",
"http://get.adobe.com/flashplayer/" },
- { "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0",
+ { "silverlight-3", "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0",
"http://go.microsoft.com/fwlink/?LinkID=185927" },
- { "Silverlight 4", "Silverlight", "4", "5", "",
+ { "silverlight-4", "Silverlight 4", "Silverlight", "4", "5", "",
"http://go.microsoft.com/fwlink/?LinkID=185927" },
- { "Flip4Mac", "Flip4Mac", "", "", "2.2.1",
+ { "flip4mac", "Flip4Mac", "Flip4Mac", "", "", "2.2.1",
"http://www.telestream.net/flip4mac-wmv/overview.htm" },
- { "Shockwave", "Shockwave for Director", "", "", "11.5.7.609",
+ { "shockwave", "Shockwave", "Shockwave for Director", "", "", "11.5.8.612",
"http://www.adobe.com/shockwave/download/" }
};
@@ -35,31 +39,34 @@ static const PluginGroupDefinition kGroupDefinitions[] = {
// TODO(panayiotis): We should group "RealJukebox NS Plugin" with the rest of
// the RealPlayer files.
static const PluginGroupDefinition kGroupDefinitions[] = {
- { "Quicktime", "QuickTime Plug-in", "", "", "7.6.6",
+ { "apple-quicktime", "Quicktime", "QuickTime Plug-in", "", "", "7.6.7",
"http://www.apple.com/quicktime/download/" },
- { "Java 6", "Java", "", "6", "6.0.200",
+ { "java-runtime-environment", "Java 6", "Java", "", "6", "6.0.200",
"http://www.java.com/" },
- { "Adobe Reader 9", "Adobe Acrobat", "9", "10", "9.3.3",
+ { "adobe-reader", "Adobe Reader 9", "Adobe Acrobat", "9", "10", "9.3.3",
"http://get.adobe.com/reader/" },
- { "Adobe Reader 8", "Adobe Acrobat", "0", "9", "8.2.3",
+ { "adobe-reader-8", "Adobe Reader 8", "Adobe Acrobat", "0", "9", "8.2.3",
"http://get.adobe.com/reader/" },
- { "Flash", "Shockwave Flash", "", "", "10.1.53",
+ { "adobe-flash-player", "Flash", "Shockwave Flash", "", "", "10.1.82",
"http://get.adobe.com/flashplayer/" },
- { "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0",
+ { "silverlight-3", "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0",
"http://go.microsoft.com/fwlink/?LinkID=185927" },
- { "Silverlight 4", "Silverlight", "4", "5", "",
+ { "silverlight-4", "Silverlight 4", "Silverlight", "4", "5", "",
"http://go.microsoft.com/fwlink/?LinkID=185927" },
- { "Shockwave", "Shockwave for Director", "", "", "11.5.7.609",
+ { "shockwave", "Shockwave", "Shockwave for Director", "", "", "11.5.8.612",
"http://www.adobe.com/shockwave/download/" },
- { "DivX Player", "DivX Web Player", "", "", "1.4.3.4",
- "http://download.divx.com/divx/autoupdate/player/DivXWebPlayerInstaller.exe" },
+ { "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", "", "", "", "" },
- { "Microsoft Office", "Microsoft Office", "", "", "", "" },
+ { "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", "RealPlayer", "RealPlayer", "", "", "",
"http://www.adobe.com/shockwave/download/" },
};
@@ -68,7 +75,7 @@ static const PluginGroupDefinition kGroupDefinitions[] = {};
#endif
/*static*/
-std::set<string16>* PluginGroup::policy_disabled_puglins_;
+std::set<string16>* PluginGroup::policy_disabled_plugin_patterns_;
/*static*/
const PluginGroupDefinition* PluginGroup::GetPluginGroupDefinitions() {
@@ -82,18 +89,28 @@ size_t PluginGroup::GetPluginGroupDefinitionsSize() {
}
/*static*/
-void PluginGroup::SetPolicyDisabledPluginSet(const std::set<string16>& set) {
- if (!policy_disabled_puglins_) {
- policy_disabled_puglins_ = new std::set<string16>();
- *policy_disabled_puglins_ = set;
- }
+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) {
- return policy_disabled_puglins_ &&
- policy_disabled_puglins_->find(plugin_name) !=
- policy_disabled_puglins_->end();
+ 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*/
@@ -116,26 +133,25 @@ PluginGroup::PluginGroup(const string16& group_name,
const std::string& version_range_low,
const std::string& version_range_high,
const std::string& min_version,
- const std::string& update_url) {
- group_name_ = group_name;
- name_matcher_ = name_matcher;
- version_range_low_str_ = version_range_low;
- if (!version_range_low.empty()) {
- version_range_low_.reset(
- Version::GetVersionFromString(version_range_low));
- }
- version_range_high_str_ = version_range_high;
+ 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));
}
- min_version_str_ = min_version;
- if (!min_version.empty()) {
+ if (!min_version.empty())
min_version_.reset(Version::GetVersionFromString(min_version));
- }
- update_url_ = update_url;
- enabled_ = false;
- max_version_.reset(Version::GetVersionFromString("0"));
}
PluginGroup* PluginGroup::FromPluginGroupDefinition(
@@ -145,25 +161,35 @@ PluginGroup* PluginGroup::FromPluginGroupDefinition(
definition.version_matcher_low,
definition.version_matcher_high,
definition.min_version,
- definition.update_url);
+ definition.update_url,
+ definition.identifier);
}
+PluginGroup::~PluginGroup() { }
+
PluginGroup* PluginGroup::FromWebPluginInfo(const WebPluginInfo& wpi) {
// Create a matcher from the name of this plugin.
- return new PluginGroup(wpi.name, wpi.name,
- "", "", "", "");
+#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::FindHardcodedPluginGroup(const WebPluginInfo& info) {
- static std::vector<linked_ptr<PluginGroup> >* hardcoded_plugin_groups = NULL;
+PluginGroup* PluginGroup::CopyOrCreatePluginGroup(
+ const WebPluginInfo& info) {
+ static PluginMap* hardcoded_plugin_groups = NULL;
if (!hardcoded_plugin_groups) {
- std::vector<linked_ptr<PluginGroup> >* groups =
- new std::vector<linked_ptr<PluginGroup> >();
+ PluginMap* groups = new PluginMap();
const PluginGroupDefinition* definitions = GetPluginGroupDefinitions();
for (size_t i = 0; i < GetPluginGroupDefinitionsSize(); ++i) {
PluginGroup* definition_group = PluginGroup::FromPluginGroupDefinition(
definitions[i]);
- groups->push_back(linked_ptr<PluginGroup>(definition_group));
+ std::string identifier = definition_group->identifier();
+ DCHECK(groups->find(identifier) == groups->end());
+ (*groups)[identifier] = linked_ptr<PluginGroup>(definition_group);
}
hardcoded_plugin_groups = groups;
}
@@ -181,15 +207,14 @@ PluginGroup* PluginGroup::FindHardcodedPluginGroup(const WebPluginInfo& info) {
}
PluginGroup* PluginGroup::FindGroupMatchingPlugin(
- std::vector<linked_ptr<PluginGroup> >& plugin_groups,
+ const PluginMap& plugin_groups,
const WebPluginInfo& plugin) {
- for (std::vector<linked_ptr<PluginGroup> >::iterator it =
+ for (std::map<std::string, linked_ptr<PluginGroup> >::const_iterator it =
plugin_groups.begin();
it != plugin_groups.end();
++it) {
- if ((*it)->Match(plugin)) {
- return it->get();
- }
+ if (it->second->Match(plugin))
+ return it->second.get();
}
return NULL;
}
@@ -222,75 +247,99 @@ bool PluginGroup::Match(const WebPluginInfo& plugin) const {
version_range_high_->CompareTo(*plugin_version) > 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);
- description_ = plugin.desc;
-
- // A group is enabled if any of the files are enabled.
- if (plugin.enabled) {
- enabled_ = true;
- }
-
- // update max_version_. Remove spaces and ')' from the version string,
+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(plugin.version);
+ 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(), '(', '.');
- scoped_ptr<Version> plugin_version(
- Version::GetVersionFromString(version));
- if (plugin_version.get() != NULL) {
- if (plugin_version->CompareTo(*(max_version_)) > 0) {
- max_version_.reset(plugin_version.release());
+ 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->SetStringFromUTF16(L"name", group_name_);
- result->SetBoolean(L"enabled", enabled_);
+ result->SetString("name", GetGroupName());
+ result->SetBoolean("enabled", enabled_);
return result;
}
DictionaryValue* PluginGroup::GetDataForUI() const {
+ string16 name = GetGroupName();
DictionaryValue* result = new DictionaryValue();
- result->SetStringFromUTF16(L"name", group_name_);
- result->SetStringFromUTF16(L"description", description_);
- result->SetString(L"version", max_version_->GetString());
- result->SetString(L"update_url", update_url_);
- result->SetBoolean(L"critical", IsVulnerable());
-
- bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(group_name_);
- if (group_disabled_by_policy) {
- result->SetString(L"enabledMode", L"disabledByPolicy");
- } else {
- result->SetString(L"enabledMode",
- enabled_ ? L"enabled" : L"disabledByUser");
- }
+ 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->SetStringFromUTF16(L"name", web_plugin.name);
- plugin_file->SetStringFromUTF16(L"description", web_plugin.desc);
- plugin_file->SetString(L"path", web_plugin.path.value());
- plugin_file->SetStringFromUTF16(L"version", web_plugin.version);
+ 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) {
- result->SetString(L"enabledMode", L"disabledByPolicy");
+ plugin_file->SetString("enabledMode", "disabledByPolicy");
} else {
- result->SetString(L"enabledMode",
- web_plugin.enabled ? L"enabled" : L"disabledByUser");
+ all_plugins_disabled_by_policy = false;
+ plugin_file->SetString("enabledMode",
+ web_plugin.enabled ? "enabled" : "disabledByUser");
}
- plugin_file->SetInteger(L"priority", priority);
+ plugin_file->SetInteger("priority", priority);
ListValue* mime_types = new ListValue();
for (std::vector<WebPluginMimeType>::const_iterator type_it =
@@ -298,8 +347,8 @@ DictionaryValue* PluginGroup::GetDataForUI() const {
type_it != web_plugin.mime_types.end();
++type_it) {
DictionaryValue* mime_type = new DictionaryValue();
- mime_type->SetString(L"mimeType", type_it->mime_type);
- mime_type->SetStringFromUTF16(L"description", type_it->description);
+ 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 =
@@ -308,25 +357,50 @@ DictionaryValue* PluginGroup::GetDataForUI() const {
++ext_it) {
file_extensions->Append(new StringValue(*ext_it));
}
- mime_type->Set(L"fileExtensions", file_extensions);
+ mime_type->Set("fileExtensions", file_extensions);
mime_types->Append(mime_type);
}
- plugin_file->Set(L"mimeTypes", mime_types);
+ plugin_file->Set("mimeTypes", mime_types);
plugin_files->Append(plugin_file);
}
- result->Set(L"plugin_files", plugin_files);
+
+ 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 || max_version_->GetString() == "0") {
+ if (min_version_.get() == NULL || version_->GetString() == "0") {
return false;
}
- return max_version_->CompareTo(*min_version_) < 0;
+ 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) {
@@ -334,10 +408,9 @@ void PluginGroup::Enable(bool enable) {
web_plugin_infos_.begin();
it != web_plugin_infos_.end(); ++it) {
if (enable && !IsPluginNameDisabledByPolicy(it->name)) {
- NPAPI::PluginList::Singleton()->EnablePlugin(FilePath(it->path));
+ NPAPI::PluginList::Singleton()->EnablePlugin(it->path);
} else {
- NPAPI::PluginList::Singleton()->DisablePlugin(FilePath(it->path));
+ NPAPI::PluginList::Singleton()->DisablePlugin(it->path);
}
}
}
-
diff --git a/chrome/common/plugin_group.h b/chrome/common/plugin_group.h
index f9f6ce3..9691dd7 100644
--- a/chrome/common/plugin_group.h
+++ b/chrome/common/plugin_group.h
@@ -4,20 +4,27 @@
#ifndef CHROME_COMMON_PLUGIN_GROUP_H_
#define CHROME_COMMON_PLUGIN_GROUP_H_
+#pragma once
+#include <map>
#include <set>
#include <vector>
-#include "base/linked_ptr.h"
+#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
-#include "base/version.h"
-#include "webkit/glue/plugins/webplugininfo.h"
class DictionaryValue;
+class FilePath;
+class Version;
+struct WebPluginInfo;
+
+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.
@@ -26,24 +33,36 @@ struct PluginGroupDefinition {
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.
-// A PluginGroup contains at least one WebPluginInfo.
-// In addition, it knows if the plugin is critically vulnerable.
class PluginGroup {
public:
+ 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.
- static PluginGroup* FindHardcodedPluginGroup(const WebPluginInfo& info);
+ // 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 names that are disabled by policy.
- static void SetPolicyDisabledPluginSet(const std::set<string16>& set);
+ // 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.
@@ -56,14 +75,14 @@ class PluginGroup {
// Find the PluginGroup matching a Plugin in a list of plugin groups. Returns
// NULL if no matching PluginGroup is found.
static PluginGroup* FindGroupMatchingPlugin(
- std::vector<linked_ptr<PluginGroup> >& plugin_groups,
+ 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_);
+ update_url_, identifier_);
}
// Returns true if the given plugin matches this group.
@@ -77,8 +96,19 @@ class PluginGroup {
// group.
void Enable(bool enable);
- // Returns this group's name
- const string16 GetGroupName() const { return group_name_; }
+ // 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;
@@ -89,10 +119,14 @@ class PluginGroup {
// Returns the update URL.
std::string GetUpdateURL() const { return update_url_; }
- // Returns true if the latest plugin in this group has known
+ // 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);
@@ -104,10 +138,22 @@ class PluginGroup {
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& 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_puglins_;
+ static std::set<string16>* policy_disabled_plugin_patterns_;
+ std::string identifier_;
string16 group_name_;
string16 name_matcher_;
std::string version_range_low_str_;
@@ -119,7 +165,7 @@ class PluginGroup {
bool enabled_;
std::string min_version_str_;
scoped_ptr<Version> min_version_;
- scoped_ptr<Version> max_version_;
+ scoped_ptr<Version> version_;
std::vector<WebPluginInfo> web_plugin_infos_;
std::vector<int> web_plugin_positions_;
diff --git a/chrome/common/plugin_group_unittest.cc b/chrome/common/plugin_group_unittest.cc
index 7def7c6..a42cbaf 100644
--- a/chrome/common/plugin_group_unittest.cc
+++ b/chrome/common/plugin_group_unittest.cc
@@ -9,38 +9,48 @@
#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", "", "", "3.0.44", "http://latest/" };
+ "myplugin", "MyPlugin", "MyPlugin", "", "", "3.0.44", "http://latest/" };
static const PluginGroupDefinition kPluginDef3 = {
- "MyPlugin 3", "MyPlugin", "0", "4", "3.0.44", "http://latest" };
+ "myplugin-3", "MyPlugin 3", "MyPlugin", "0", "4", "3.0.44", "http://latest" };
static const PluginGroupDefinition kPluginDef4 = {
- "MyPlugin 4", "MyPlugin", "4", "5", "4.0.44", "http://latest" };
+ "myplugin-4", "MyPlugin 4", "MyPlugin", "4", "5", "4.0.44", "http://latest" };
static const PluginGroupDefinition kPluginDefNotVulnerable = {
- "MyPlugin", "MyPlugin", "", "", "", "http://latest" };
+ "myplugin-latest", "MyPlugin", "MyPlugin", "", "", "", "http://latest" };
// name, path, version, desc, mime_types, enabled.
static WebPluginInfo kPlugin2043 = {
- ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("2.0.43"), string16(),
+ ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("2.0.43"),
+ ASCIIToUTF16("MyPlugin version 2.0.43"),
std::vector<WebPluginMimeType>(), true };
static WebPluginInfo kPlugin3043 = {
- ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.43"), string16(),
+ ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.43"),
+ ASCIIToUTF16("MyPlugin version 3.0.43"),
std::vector<WebPluginMimeType>(), true };
static WebPluginInfo kPlugin3044 = {
- ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.44"), string16(),
+ ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.44"),
+ ASCIIToUTF16("MyPlugin version 3.0.44"),
std::vector<WebPluginMimeType>(), true };
static WebPluginInfo kPlugin3045 = {
- ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.45"), string16(),
+ ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("3.0.45"),
+ ASCIIToUTF16("MyPlugin version 3.0.45"),
std::vector<WebPluginMimeType>(), true };
static WebPluginInfo kPlugin4043 = {
- ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("4.0.43"), string16(),
+ ASCIIToUTF16("MyPlugin"), FilePath(), ASCIIToUTF16("4.0.43"),
+ ASCIIToUTF16("MyPlugin version 4.0.43"),
std::vector<WebPluginMimeType>(), true };
class PluginGroupTest : public testing::Test {
+ protected:
+ virtual void TearDown() {
+ PluginGroup::SetPolicyDisabledPluginPatterns(std::set<string16>());
+ }
};
TEST(PluginGroupTest, PluginGroupMatch) {
@@ -51,18 +61,6 @@ TEST(PluginGroupTest, PluginGroupMatch) {
EXPECT_FALSE(group->IsVulnerable());
}
-TEST(PluginGroupTest, PluginGroupMatchMultipleFiles) {
- scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
- kPluginDef3));
- EXPECT_TRUE(group->Match(kPlugin3043));
- group->AddPlugin(kPlugin3043, 0);
- EXPECT_TRUE(group->IsVulnerable());
-
- EXPECT_TRUE(group->Match(kPlugin3045));
- group->AddPlugin(kPlugin3045, 1);
- EXPECT_FALSE(group->IsVulnerable());
-}
-
TEST(PluginGroupTest, PluginGroupMatchCorrectVersion) {
scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
kPluginDef3));
@@ -76,6 +74,56 @@ TEST(PluginGroupTest, PluginGroupMatchCorrectVersion) {
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();
@@ -87,6 +135,19 @@ TEST(PluginGroupTest, PluginGroupDefinition) {
}
}
+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] = {
@@ -107,7 +168,20 @@ TEST(PluginGroupTest, VersionExtraction) {
group->AddPlugin(plugin, 0);
scoped_ptr<DictionaryValue> data(group->GetDataForUI());
std::string version;
- data->GetString(L"version", &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/chrome/common/plugin_messages.cc b/chrome/common/plugin_messages.cc
new file mode 100644
index 0000000..ab80827
--- /dev/null
+++ b/chrome/common/plugin_messages.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 "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"
+
+PluginMsg_Init_Params::PluginMsg_Init_Params()
+ : load_manually(false),
+ host_render_view_routing_id(-1) {
+}
+
+PluginMsg_Init_Params::~PluginMsg_Init_Params() {
+}
+
+PluginHostMsg_URLRequest_Params::PluginHostMsg_URLRequest_Params()
+ : notify_id(-1),
+ popups_allowed(false) {
+}
+
+PluginHostMsg_URLRequest_Params::~PluginHostMsg_URLRequest_Params() {
+}
+
+PluginMsg_DidReceiveResponseParams::PluginMsg_DidReceiveResponseParams()
+ : id(-1),
+ expected_length(0),
+ last_modified(0),
+ request_is_seekable(false) {
+}
+
+PluginMsg_DidReceiveResponseParams::~PluginMsg_DidReceiveResponseParams() {
+}
+
+NPIdentifier_Param::NPIdentifier_Param()
+ : identifier() {
+}
+
+NPIdentifier_Param::~NPIdentifier_Param() {
+}
+
+NPVariant_Param::NPVariant_Param()
+ : type(NPVARIANT_PARAM_VOID),
+ bool_value(false),
+ int_value(0),
+ double_value(0),
+ npobject_routing_id(-1) {
+}
+
+NPVariant_Param::~NPVariant_Param() {
+}
+
+PluginMsg_UpdateGeometry_Param::PluginMsg_UpdateGeometry_Param()
+ : transparent(false)
+#if defined(OS_MACOSX)
+ , ack_key(-1)
+#endif
+{
+}
+
+PluginMsg_UpdateGeometry_Param::~PluginMsg_UpdateGeometry_Param() {
+}
+
+namespace IPC {
+
+void ParamTraits<PluginMsg_Init_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.containing_window);
+ WriteParam(m, p.url);
+ WriteParam(m, p.page_url);
+ DCHECK(p.arg_names.size() == p.arg_values.size());
+ WriteParam(m, p.arg_names);
+ WriteParam(m, p.arg_values);
+ WriteParam(m, p.load_manually);
+ WriteParam(m, p.host_render_view_routing_id);
+}
+
+bool ParamTraits<PluginMsg_Init_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->containing_window) &&
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->page_url) &&
+ ReadParam(m, iter, &p->arg_names) &&
+ ReadParam(m, iter, &p->arg_values) &&
+ ReadParam(m, iter, &p->load_manually) &&
+ ReadParam(m, iter, &p->host_render_view_routing_id);
+}
+
+void ParamTraits<PluginMsg_Init_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.containing_window, l);
+ l->append(", ");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.page_url, l);
+ l->append(", ");
+ LogParam(p.arg_names, l);
+ l->append(", ");
+ LogParam(p.arg_values, l);
+ l->append(", ");
+ LogParam(p.load_manually, l);
+ l->append(", ");
+ LogParam(p.host_render_view_routing_id, l);
+ l->append(")");
+}
+
+void ParamTraits<PluginHostMsg_URLRequest_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.url);
+ WriteParam(m, p.method);
+ WriteParam(m, p.target);
+ WriteParam(m, p.buffer);
+ WriteParam(m, p.notify_id);
+ WriteParam(m, p.popups_allowed);
+}
+
+bool ParamTraits<PluginHostMsg_URLRequest_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->method) &&
+ ReadParam(m, iter, &p->target) &&
+ ReadParam(m, iter, &p->buffer) &&
+ ReadParam(m, iter, &p->notify_id) &&
+ ReadParam(m, iter, &p->popups_allowed);
+}
+
+void ParamTraits<PluginHostMsg_URLRequest_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.method, l);
+ l->append(", ");
+ LogParam(p.target, l);
+ l->append(", ");
+ LogParam(p.buffer, l);
+ l->append(", ");
+ LogParam(p.notify_id, l);
+ l->append(", ");
+ LogParam(p.popups_allowed, l);
+ l->append(")");
+}
+
+
+void ParamTraits<PluginMsg_DidReceiveResponseParams>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.id);
+ WriteParam(m, p.mime_type);
+ WriteParam(m, p.headers);
+ WriteParam(m, p.expected_length);
+ WriteParam(m, p.last_modified);
+ WriteParam(m, p.request_is_seekable);
+}
+
+bool ParamTraits<PluginMsg_DidReceiveResponseParams>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ return
+ ReadParam(m, iter, &r->id) &&
+ ReadParam(m, iter, &r->mime_type) &&
+ ReadParam(m, iter, &r->headers) &&
+ ReadParam(m, iter, &r->expected_length) &&
+ ReadParam(m, iter, &r->last_modified) &&
+ ReadParam(m, iter, &r->request_is_seekable);
+}
+
+void ParamTraits<PluginMsg_DidReceiveResponseParams>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.id, l);
+ l->append(", ");
+ LogParam(p.mime_type, l);
+ l->append(", ");
+ LogParam(p.headers, l);
+ l->append(", ");
+ LogParam(p.expected_length, l);
+ l->append(", ");
+ LogParam(p.last_modified, l);
+ l->append(", ");
+ LogParam(p.request_is_seekable, l);
+ l->append(")");
+}
+
+
+void ParamTraits<NPVariant_Param>::Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.type));
+ if (p.type == NPVARIANT_PARAM_BOOL) {
+ WriteParam(m, p.bool_value);
+ } else if (p.type == NPVARIANT_PARAM_INT) {
+ WriteParam(m, p.int_value);
+ } else if (p.type == NPVARIANT_PARAM_DOUBLE) {
+ WriteParam(m, p.double_value);
+ } else if (p.type == NPVARIANT_PARAM_STRING) {
+ WriteParam(m, p.string_value);
+ } else if (p.type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
+ p.type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
+ // This is the routing id used to connect NPObjectProxy in the other
+ // process with NPObjectStub in this process or to identify the raw
+ // npobject pointer to be used in the callee process.
+ WriteParam(m, p.npobject_routing_id);
+ } else {
+ DCHECK(p.type == NPVARIANT_PARAM_VOID || p.type == NPVARIANT_PARAM_NULL);
+ }
+}
+
+bool ParamTraits<NPVariant_Param>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type))
+ return false;
+
+ bool result = false;
+ r->type = static_cast<NPVariant_ParamEnum>(type);
+ if (r->type == NPVARIANT_PARAM_BOOL) {
+ result = ReadParam(m, iter, &r->bool_value);
+ } else if (r->type == NPVARIANT_PARAM_INT) {
+ result = ReadParam(m, iter, &r->int_value);
+ } else if (r->type == NPVARIANT_PARAM_DOUBLE) {
+ result = ReadParam(m, iter, &r->double_value);
+ } else if (r->type == NPVARIANT_PARAM_STRING) {
+ result = ReadParam(m, iter, &r->string_value);
+ } else if (r->type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
+ r->type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
+ result = ReadParam(m, iter, &r->npobject_routing_id);
+ } else if ((r->type == NPVARIANT_PARAM_VOID) ||
+ (r->type == NPVARIANT_PARAM_NULL)) {
+ result = true;
+ } else {
+ NOTREACHED();
+ }
+
+ return result;
+}
+
+void ParamTraits<NPVariant_Param>::Log(const param_type& p, std::string* l) {
+ if (p.type == NPVARIANT_PARAM_BOOL) {
+ LogParam(p.bool_value, l);
+ } else if (p.type == NPVARIANT_PARAM_INT) {
+ LogParam(p.int_value, l);
+ } else if (p.type == NPVARIANT_PARAM_DOUBLE) {
+ LogParam(p.double_value, l);
+ } else if (p.type == NPVARIANT_PARAM_STRING) {
+ LogParam(p.string_value, l);
+ } else if (p.type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
+ p.type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
+ LogParam(p.npobject_routing_id, l);
+ }
+}
+
+void ParamTraits<PluginMsg_UpdateGeometry_Param>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.window_rect);
+ WriteParam(m, p.clip_rect);
+ WriteParam(m, p.windowless_buffer);
+ WriteParam(m, p.background_buffer);
+ WriteParam(m, p.transparent);
+#if defined(OS_MACOSX)
+ WriteParam(m, p.ack_key);
+#endif
+}
+
+bool ParamTraits<PluginMsg_UpdateGeometry_Param>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ return
+ ReadParam(m, iter, &r->window_rect) &&
+ ReadParam(m, iter, &r->clip_rect) &&
+ ReadParam(m, iter, &r->windowless_buffer) &&
+ ReadParam(m, iter, &r->background_buffer) &&
+ ReadParam(m, iter, &r->transparent)
+#if defined(OS_MACOSX)
+ &&
+ ReadParam(m, iter, &r->ack_key)
+#endif
+ ;
+}
+
+void ParamTraits<PluginMsg_UpdateGeometry_Param>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.window_rect, l);
+ l->append(", ");
+ LogParam(p.clip_rect, l);
+ l->append(", ");
+ LogParam(p.windowless_buffer, l);
+ l->append(", ");
+ LogParam(p.background_buffer, l);
+ l->append(", ");
+ LogParam(p.transparent, l);
+#if defined(OS_MACOSX)
+ l->append(", ");
+ LogParam(p.ack_key, l);
+#endif
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h
index 82116d8..638462f 100644
--- a/chrome/common/plugin_messages.h
+++ b/chrome/common/plugin_messages.h
@@ -9,11 +9,13 @@
#ifndef CHROME_COMMON_PLUGIN_MESSAGES_H_
#define CHROME_COMMON_PLUGIN_MESSAGES_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
#include "chrome/common/common_param_traits.h"
#include "chrome/common/webkit_param_traits.h"
#include "gfx/native_widget_types.h"
@@ -32,6 +34,9 @@
// predefined IPC message.
struct PluginMsg_Init_Params {
+ PluginMsg_Init_Params();
+ ~PluginMsg_Init_Params();
+
gfx::NativeViewId containing_window;
GURL url;
GURL page_url;
@@ -39,14 +44,12 @@ struct PluginMsg_Init_Params {
std::vector<std::string> arg_values;
bool load_manually;
int host_render_view_routing_id;
-#if defined(OS_MACOSX)
- gfx::Rect containing_window_frame;
- gfx::Rect containing_content_frame;
- bool containing_window_has_focus;
-#endif
};
struct PluginHostMsg_URLRequest_Params {
+ PluginHostMsg_URLRequest_Params();
+ ~PluginHostMsg_URLRequest_Params();
+
std::string url;
std::string method;
std::string target;
@@ -56,6 +59,9 @@ struct PluginHostMsg_URLRequest_Params {
};
struct PluginMsg_DidReceiveResponseParams {
+ PluginMsg_DidReceiveResponseParams();
+ ~PluginMsg_DidReceiveResponseParams();
+
unsigned long id;
std::string mime_type;
std::string headers;
@@ -65,6 +71,9 @@ struct PluginMsg_DidReceiveResponseParams {
};
struct NPIdentifier_Param {
+ NPIdentifier_Param();
+ ~NPIdentifier_Param();
+
NPIdentifier identifier;
};
@@ -85,6 +94,9 @@ enum NPVariant_ParamEnum {
};
struct NPVariant_Param {
+ NPVariant_Param();
+ ~NPVariant_Param();
+
NPVariant_ParamEnum type;
bool bool_value;
int int_value;
@@ -94,6 +106,9 @@ struct NPVariant_Param {
};
struct PluginMsg_UpdateGeometry_Param {
+ PluginMsg_UpdateGeometry_Param();
+ ~PluginMsg_UpdateGeometry_Param();
+
gfx::Rect window_rect;
gfx::Rect clip_rect;
TransportDIB::Handle windowless_buffer;
@@ -116,136 +131,25 @@ namespace IPC {
template <>
struct ParamTraits<PluginMsg_Init_Params> {
typedef PluginMsg_Init_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.containing_window);
- WriteParam(m, p.url);
- WriteParam(m, p.page_url);
- DCHECK(p.arg_names.size() == p.arg_values.size());
- WriteParam(m, p.arg_names);
- WriteParam(m, p.arg_values);
- WriteParam(m, p.load_manually);
- WriteParam(m, p.host_render_view_routing_id);
-#if defined(OS_MACOSX)
- WriteParam(m, p.containing_window_frame);
- WriteParam(m, p.containing_content_frame);
- WriteParam(m, p.containing_window_has_focus);
-#endif
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->containing_window) &&
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->page_url) &&
- ReadParam(m, iter, &p->arg_names) &&
- ReadParam(m, iter, &p->arg_values) &&
- ReadParam(m, iter, &p->load_manually) &&
- ReadParam(m, iter, &p->host_render_view_routing_id)
-#if defined(OS_MACOSX)
- &&
- ReadParam(m, iter, &p->containing_window_frame) &&
- ReadParam(m, iter, &p->containing_content_frame) &&
- ReadParam(m, iter, &p->containing_window_has_focus)
-#endif
- ;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.containing_window, l);
- l->append(L", ");
- LogParam(p.url, l);
- l->append(L", ");
- LogParam(p.page_url, l);
- l->append(L", ");
- LogParam(p.arg_names, l);
- l->append(L", ");
- LogParam(p.arg_values, l);
- l->append(L", ");
- LogParam(p.load_manually, l);
- l->append(L", ");
- LogParam(p.host_render_view_routing_id, l);
-#if defined(OS_MACOSX)
- l->append(L", ");
- LogParam(p.containing_window_frame, l);
- l->append(L", ");
- LogParam(p.containing_content_frame, l);
- l->append(L", ");
- LogParam(p.containing_window_has_focus, l);
-#endif
- l->append(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<PluginHostMsg_URLRequest_Params> {
typedef PluginHostMsg_URLRequest_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.url);
- WriteParam(m, p.method);
- WriteParam(m, p.target);
- WriteParam(m, p.buffer);
- WriteParam(m, p.notify_id);
- WriteParam(m, p.popups_allowed);
- }
- 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->target) &&
- ReadParam(m, iter, &p->buffer) &&
- ReadParam(m, iter, &p->notify_id) &&
- ReadParam(m, iter, &p->popups_allowed);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.url, l);
- l->append(L", ");
- LogParam(p.method, l);
- l->append(L", ");
- LogParam(p.target, l);
- l->append(L", ");
- LogParam(p.buffer, l);
- l->append(L", ");
- LogParam(p.notify_id, l);
- l->append(L", ");
- LogParam(p.popups_allowed, l);
- l->append(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<PluginMsg_DidReceiveResponseParams> {
typedef PluginMsg_DidReceiveResponseParams param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.id);
- WriteParam(m, p.mime_type);
- WriteParam(m, p.headers);
- WriteParam(m, p.expected_length);
- WriteParam(m, p.last_modified);
- WriteParam(m, p.request_is_seekable);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- return
- ReadParam(m, iter, &r->id) &&
- ReadParam(m, iter, &r->mime_type) &&
- ReadParam(m, iter, &r->headers) &&
- ReadParam(m, iter, &r->expected_length) &&
- ReadParam(m, iter, &r->last_modified) &&
- ReadParam(m, iter, &r->request_is_seekable);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.id, l);
- l->append(L", ");
- LogParam(p.mime_type, l);
- l->append(L", ");
- LogParam(p.headers, l);
- l->append(L", ");
- LogParam(p.expected_length, l);
- l->append(L", ");
- LogParam(p.last_modified, l);
- l->append(L", ");
- LogParam(p.request_is_seekable, l);
- l->append(L")");
- }
+ 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);
};
typedef const WebKit::WebInputEvent* WebInputEventPointer;
@@ -277,14 +181,14 @@ struct ParamTraits<WebInputEventPointer> {
*r = event;
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p->size, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p->type, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p->timeStampSeconds, l);
- l->append(L")");
+ l->append(")");
}
};
@@ -297,13 +201,13 @@ struct ParamTraits<NPIdentifier_Param> {
static bool Read(const Message* m, void** iter, param_type* r) {
return webkit_glue::DeserializeNPIdentifier(*m, iter, &r->identifier);
}
- static void Log(const param_type& p, std::wstring* l) {
+ static void Log(const param_type& p, std::string* l) {
if (WebKit::WebBindings::identifierIsString(p.identifier)) {
NPUTF8* str = WebKit::WebBindings::utf8FromIdentifier(p.identifier);
- l->append(UTF8ToWide(str));
+ l->append(str);
NPN_MemFree(str);
} else {
- l->append(IntToWString(
+ l->append(base::IntToString(
WebKit::WebBindings::intFromIdentifier(p.identifier)));
}
}
@@ -312,67 +216,9 @@ struct ParamTraits<NPIdentifier_Param> {
template <>
struct ParamTraits<NPVariant_Param> {
typedef NPVariant_Param param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, static_cast<int>(p.type));
- if (p.type == NPVARIANT_PARAM_BOOL) {
- WriteParam(m, p.bool_value);
- } else if (p.type == NPVARIANT_PARAM_INT) {
- WriteParam(m, p.int_value);
- } else if (p.type == NPVARIANT_PARAM_DOUBLE) {
- WriteParam(m, p.double_value);
- } else if (p.type == NPVARIANT_PARAM_STRING) {
- WriteParam(m, p.string_value);
- } else if (p.type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
- p.type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
- // This is the routing id used to connect NPObjectProxy in the other
- // process with NPObjectStub in this process or to identify the raw
- // npobject pointer to be used in the callee process.
- WriteParam(m, p.npobject_routing_id);
- } else {
- DCHECK(p.type == NPVARIANT_PARAM_VOID || p.type == NPVARIANT_PARAM_NULL);
- }
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int type;
- if (!ReadParam(m, iter, &type))
- return false;
-
- bool result = false;
- r->type = static_cast<NPVariant_ParamEnum>(type);
- if (r->type == NPVARIANT_PARAM_BOOL) {
- result = ReadParam(m, iter, &r->bool_value);
- } else if (r->type == NPVARIANT_PARAM_INT) {
- result = ReadParam(m, iter, &r->int_value);
- } else if (r->type == NPVARIANT_PARAM_DOUBLE) {
- result = ReadParam(m, iter, &r->double_value);
- } else if (r->type == NPVARIANT_PARAM_STRING) {
- result = ReadParam(m, iter, &r->string_value);
- } else if (r->type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
- r->type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
- result = ReadParam(m, iter, &r->npobject_routing_id);
- } else if ((r->type == NPVARIANT_PARAM_VOID) ||
- (r->type == NPVARIANT_PARAM_NULL)) {
- result = true;
- } else {
- NOTREACHED();
- }
-
- return result;
- }
- static void Log(const param_type& p, std::wstring* l) {
- if (p.type == NPVARIANT_PARAM_BOOL) {
- LogParam(p.bool_value, l);
- } else if (p.type == NPVARIANT_PARAM_INT) {
- LogParam(p.int_value, l);
- } else if (p.type == NPVARIANT_PARAM_DOUBLE) {
- LogParam(p.double_value, l);
- } else if (p.type == NPVARIANT_PARAM_STRING) {
- LogParam(p.string_value, l);
- } else if (p.type == NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID ||
- p.type == NPVARIANT_PARAM_RECEIVER_OBJECT_ROUTING_ID) {
- LogParam(p.npobject_routing_id, l);
- }
- }
+ 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);
};
// For windowless plugins, windowless_buffer
@@ -382,46 +228,9 @@ struct ParamTraits<NPVariant_Param> {
template <>
struct ParamTraits<PluginMsg_UpdateGeometry_Param> {
typedef PluginMsg_UpdateGeometry_Param param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.window_rect);
- WriteParam(m, p.clip_rect);
- WriteParam(m, p.windowless_buffer);
- WriteParam(m, p.background_buffer);
- WriteParam(m, p.transparent);
-#if defined(OS_MACOSX)
- WriteParam(m, p.ack_key);
-#endif
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- return
- ReadParam(m, iter, &r->window_rect) &&
- ReadParam(m, iter, &r->clip_rect) &&
- ReadParam(m, iter, &r->windowless_buffer) &&
- ReadParam(m, iter, &r->background_buffer) &&
- ReadParam(m, iter, &r->transparent)
-#if defined(OS_MACOSX)
- &&
- ReadParam(m, iter, &r->ack_key)
-#endif
- ;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.window_rect, l);
- l->append(L", ");
- LogParam(p.clip_rect, l);
- l->append(L", ");
- LogParam(p.windowless_buffer, l);
- l->append(L", ");
- LogParam(p.background_buffer, l);
- l->append(L", ");
- LogParam(p.transparent, l);
-#if defined(OS_MACOSX)
- l->append(L", ");
- LogParam(p.ack_key, l);
-#endif
- l->append(L")");
- }
+ 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
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index 29388a4..99e265a 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -221,11 +221,11 @@ IPC_BEGIN_MESSAGES(Plugin)
bool /* handled */,
WebCursor /* cursor type*/)
-#if defined(OS_MACOSX)
- IPC_MESSAGE_ROUTED1(PluginMsg_SetWindowFocus,
+ IPC_MESSAGE_ROUTED1(PluginMsg_SetContentAreaFocus,
bool /* has_focus */)
- IPC_MESSAGE_ROUTED1(PluginMsg_SetContentAreaFocus,
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_ROUTED1(PluginMsg_SetWindowFocus,
bool /* has_focus */)
IPC_MESSAGE_ROUTED0(PluginMsg_ContainerHidden)
diff --git a/chrome/common/policy_constants.cc b/chrome/common/policy_constants.cc
new file mode 100644
index 0000000..6ab9a32
--- /dev/null
+++ b/chrome/common/policy_constants.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 "chrome/common/policy_constants.h"
+
+namespace policy {
+
+#if defined(OS_WIN)
+#if defined(GOOGLE_CHROME_BUILD)
+const wchar_t kRegistrySubKey[] = L"SOFTWARE\\Policies\\Google\\Chrome";
+#else
+const wchar_t kRegistrySubKey[] = L"SOFTWARE\\Policies\\Chromium";
+#endif
+#endif
+
+namespace key {
+
+const char kHomepageLocation[] = "HomepageLocation";
+const char kHomepageIsNewTabPage[] = "HomepageIsNewTabPage";
+const char kRestoreOnStartup[] = "RestoreOnStartup";
+const char kURLsToRestoreOnStartup[] = "RestoreOnStartupURLs";
+const char kDefaultSearchProviderName[] = "DefaultSearchProviderName";
+const char kDefaultSearchProviderKeyword[] = "DefaultSearchProviderKeyword";
+const char kDefaultSearchProviderSearchURL[] =
+ "DefaultSearchProviderSearchURL";
+const char kDefaultSearchProviderSuggestURL[] =
+ "DefaultSearchProviderSuggestURL";
+const char kDefaultSearchProviderIconURL[] =
+ "DefaultSearchProviderIconURL";
+const char kDefaultSearchProviderEncodings[] =
+ "DefaultSearchProviderEncodings";
+const char kProxyServerMode[] = "ProxyServerMode";
+const char kProxyServer[] = "ProxyServer";
+const char kProxyPacUrl[] = "ProxyPacUrl";
+const char kProxyBypassList[] = "ProxyBypassList";
+const char kAlternateErrorPagesEnabled[] = "AlternateErrorPagesEnabled";
+const char kSearchSuggestEnabled[] = "SearchSuggestEnabled";
+const char kDnsPrefetchingEnabled[] = "DnsPrefetchingEnabled";
+const char kSafeBrowsingEnabled[] = "SafeBrowsingEnabled";
+const char kMetricsReportingEnabled[] = "MetricsReportingEnabled";
+const char kPasswordManagerEnabled[] = "PasswordManagerEnabled";
+const char kPasswordManagerAllowShowPasswords[] =
+ "PasswordManagerAllowShowPasswords";
+const char kDisabledPlugins[] = "DisabledPlugins";
+const char kAutoFillEnabled[] = "AutoFillEnabled";
+const char kApplicationLocaleValue[] = "ApplicationLocaleValue";
+const char kSyncDisabled[] = "SyncDisabled";
+const char kExtensionInstallAllowList[] = "ExtensionInstallWhitelist";
+const char kExtensionInstallDenyList[] = "ExtensionInstallBlacklist";
+const char kShowHomeButton[] = "ShowHomeButton";
+const char kPrintingEnabled[] = "PrintingEnabled";
+const char kJavascriptEnabled[] = "JavascriptEnabled";
+
+// Chrome Frame specific policy constants
+const char kChromeFrameRendererSettings[] = "ChromeFrameRendererSettings";
+const char kRenderInChromeFrameList[] = "RenderInChromeFrameList";
+const char kRenderInHostList[] = "RenderInHostList";
+
+} // namespace key
+
+} // namespace policy
diff --git a/chrome/common/policy_constants.h b/chrome/common/policy_constants.h
new file mode 100644
index 0000000..783cfe9
--- /dev/null
+++ b/chrome/common/policy_constants.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_COMMON_POLICY_CONSTANTS_H_
+#define CHROME_COMMON_POLICY_CONSTANTS_H_
+#pragma once
+
+#include "build/build_config.h"
+
+namespace policy {
+
+#if defined(OS_WIN)
+// The windows registry path we read the policy configuration from.
+extern const wchar_t kRegistrySubKey[];
+#endif
+
+// Key names for the policy settings.
+namespace key {
+
+extern const char kHomepageLocation[];
+extern const char kHomepageIsNewTabPage[];
+extern const char kRestoreOnStartup[];
+extern const char kURLsToRestoreOnStartup[];
+extern const char kDefaultSearchProviderName[];
+extern const char kDefaultSearchProviderKeyword[];
+extern const char kDefaultSearchProviderSearchURL[];
+extern const char kDefaultSearchProviderSuggestURL[];
+extern const char kDefaultSearchProviderIconURL[];
+extern const char kDefaultSearchProviderEncodings[];
+extern const char kProxyServerMode[];
+extern const char kProxyServer[];
+extern const char kProxyPacUrl[];
+extern const char kProxyBypassList[];
+extern const char kAlternateErrorPagesEnabled[];
+extern const char kSearchSuggestEnabled[];
+extern const char kDnsPrefetchingEnabled[];
+extern const char kSafeBrowsingEnabled[];
+extern const char kMetricsReportingEnabled[];
+extern const char kPasswordManagerEnabled[];
+extern const char kPasswordManagerAllowShowPasswords[];
+extern const char kDisabledPlugins[];
+extern const char kAutoFillEnabled[];
+extern const char kApplicationLocaleValue[];
+extern const char kSyncDisabled[];
+extern const char kExtensionInstallAllowList[];
+extern const char kExtensionInstallDenyList[];
+extern const char kShowHomeButton[];
+extern const char kPrintingEnabled[];
+extern const char kJavascriptEnabled[];
+
+// Chrome Frame specific policy constants
+extern const char kChromeFrameRendererSettings[];
+extern const char kRenderInChromeFrameList[];
+extern const char kRenderInHostList[];
+
+} // namespace key
+
+} // namespace policy
+
+#endif // CHROME_COMMON_POLICY_CONSTANTS_H_
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index e04994f..dcaa943 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -10,15 +10,15 @@ namespace prefs {
// These are attached to the user profile
// A boolean specifying whether the New Tab page is the home page or not.
-const wchar_t kHomePageIsNewTabPage[] = L"homepage_is_newtabpage";
+const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage";
// This is the URL of the page to load when opening new tabs.
-const wchar_t kHomePage[] = L"homepage";
+const char kHomePage[] = "homepage";
// Used to determine if the last session exited cleanly. Set to false when
// first opened, and to true when closing. On startup if the value is false,
// it means the profile didn't exit cleanly.
-const wchar_t kSessionExitedCleanly[] = L"profile.exited_cleanly";
+const char kSessionExitedCleanly[] = "profile.exited_cleanly";
// An integer pref. Holds one of several values:
// 0: (or empty) don't do anything special on startup.
@@ -27,32 +27,31 @@ const wchar_t kSessionExitedCleanly[] = L"profile.exited_cleanly";
// no longer used, but saved to avoid conflict with old preferences.
// 3: unused, previously indicated the user wants to restore a saved session.
// 4: restore the URLs defined in kURLsToRestoreOnStartup.
-const wchar_t kRestoreOnStartup[] = L"session.restore_on_startup";
+const char kRestoreOnStartup[] = "session.restore_on_startup";
// The URLs to restore on startup or when the home button is pressed. The URLs
// are only restored on startup if kRestoreOnStartup is 4.
-const wchar_t kURLsToRestoreOnStartup[] =
- L"session.urls_to_restore_on_startup";
+const char kURLsToRestoreOnStartup[] = "session.urls_to_restore_on_startup";
// The application locale.
-const wchar_t kApplicationLocale[] = L"intl.app_locale";
+const char kApplicationLocale[] = "intl.app_locale";
// The default character encoding to assume for a web page in the
// absence of MIME charset specification
-const wchar_t kDefaultCharset[] = L"intl.charset_default";
+const char kDefaultCharset[] = "intl.charset_default";
// The value to use for Accept-Languages HTTP header when making an HTTP
// request.
-const wchar_t kAcceptLanguages[] = L"intl.accept_languages";
+const char kAcceptLanguages[] = "intl.accept_languages";
// The value to use for showing locale-dependent encoding list for different
// locale, it's initialized from the corresponding string resource that is
// stored in non-translatable part of the resource bundle.
-const wchar_t kStaticEncodings[] = L"intl.static_encodings";
+const char kStaticEncodings[] = "intl.static_encodings";
// OBSOLETE. The list of hostnames for which we whitelist popups (rather than
// blocking).
-const wchar_t kPopupWhitelistedHosts[] = L"profile.popup_whitelisted_sites";
+const char kPopupWhitelistedHosts[] = "profile.popup_whitelisted_sites";
// WebKit preferences.
// A boolean flag to indicate whether WebKit standard font family is
@@ -60,62 +59,61 @@ const wchar_t kPopupWhitelistedHosts[] = L"profile.popup_whitelisted_sites";
// Instead, we use this pref to map either serif or sans_serif to WebKit
// standard font family. At the moment, we don't have a UI for this
// flag, either.
-const wchar_t kWebKitStandardFontIsSerif[] =
- L"webkit.webprefs.standard_font_is_serif";
-const wchar_t kWebKitFixedFontFamily[] = L"webkit.webprefs.fixed_font_family";
-const wchar_t kWebKitSerifFontFamily[] = L"webkit.webprefs.serif_font_family";
-const wchar_t kWebKitSansSerifFontFamily[] =
- L"webkit.webprefs.sansserif_font_family";
-const wchar_t kWebKitCursiveFontFamily[] =
- L"webkit.webprefs.cursive_font_family";
-const wchar_t kWebKitFantasyFontFamily[] =
- L"webkit.webprefs.fantasy_font_family";
-const wchar_t kWebKitDefaultFontSize[] = L"webkit.webprefs.default_font_size";
-const wchar_t kWebKitDefaultFixedFontSize[] =
- L"webkit.webprefs.default_fixed_font_size";
-const wchar_t kWebKitMinimumFontSize[] = L"webkit.webprefs.minimum_font_size";
-const wchar_t kWebKitMinimumLogicalFontSize[] =
- L"webkit.webprefs.minimum_logical_font_size";
-const wchar_t kWebKitJavascriptEnabled[] =
- L"webkit.webprefs.javascript_enabled";
-const wchar_t kWebKitWebSecurityEnabled[] =
- L"webkit.webprefs.web_security_enabled";
-const wchar_t kWebKitJavascriptCanOpenWindowsAutomatically[] =
- L"webkit.webprefs.javascript_can_open_windows_automatically";
-const wchar_t kWebKitLoadsImagesAutomatically[] =
- L"webkit.webprefs.loads_images_automatically";
-const wchar_t kWebKitPluginsEnabled[] = L"webkit.webprefs.plugins_enabled";
-const wchar_t kWebKitDomPasteEnabled[] = L"webkit.webprefs.dom_paste_enabled";
-const wchar_t kWebKitShrinksStandaloneImagesToFit[] =
- L"webkit.webprefs.shrinks_standalone_images_to_fit";
-const wchar_t kWebKitInspectorSettings[] =
- L"webkit.webprefs.inspector_settings";
-const wchar_t kWebKitUsesUniversalDetector[] =
- L"webkit.webprefs.uses_universal_detector";
-const wchar_t kWebKitTextAreasAreResizable[] =
- L"webkit.webprefs.text_areas_are_resizable";
-const wchar_t kWebKitJavaEnabled[] =
- L"webkit.webprefs.java_enabled";
-const wchar_t kWebkitTabsToLinks[] = L"webkit.webprefs.tabs_to_links";
+const char kWebKitStandardFontIsSerif[] =
+ "webkit.webprefs.standard_font_is_serif";
+const char kWebKitFixedFontFamily[] = "webkit.webprefs.fixed_font_family";
+const char kWebKitSerifFontFamily[] = "webkit.webprefs.serif_font_family";
+const char kWebKitSansSerifFontFamily[] =
+ "webkit.webprefs.sansserif_font_family";
+const char kWebKitCursiveFontFamily[] = "webkit.webprefs.cursive_font_family";
+const char kWebKitFantasyFontFamily[] = "webkit.webprefs.fantasy_font_family";
+const char kWebKitDefaultFontSize[] = "webkit.webprefs.default_font_size";
+const char kWebKitDefaultFixedFontSize[] =
+ "webkit.webprefs.default_fixed_font_size";
+const char kWebKitMinimumFontSize[] = "webkit.webprefs.minimum_font_size";
+const char kWebKitMinimumLogicalFontSize[] =
+ "webkit.webprefs.minimum_logical_font_size";
+const char kWebKitJavascriptEnabled[] = "webkit.webprefs.javascript_enabled";
+const char kWebKitWebSecurityEnabled[] = "webkit.webprefs.web_security_enabled";
+const char kWebKitJavascriptCanOpenWindowsAutomatically[] =
+ "webkit.webprefs.javascript_can_open_windows_automatically";
+const char kWebKitLoadsImagesAutomatically[] =
+ "webkit.webprefs.loads_images_automatically";
+const char kWebKitPluginsEnabled[] = "webkit.webprefs.plugins_enabled";
+const char kWebKitDomPasteEnabled[] = "webkit.webprefs.dom_paste_enabled";
+const char kWebKitShrinksStandaloneImagesToFit[] =
+ "webkit.webprefs.shrinks_standalone_images_to_fit";
+const char kWebKitInspectorSettings[] = "webkit.webprefs.inspector_settings";
+const char kWebKitUsesUniversalDetector[] =
+ "webkit.webprefs.uses_universal_detector";
+const char kWebKitTextAreasAreResizable[] =
+ "webkit.webprefs.text_areas_are_resizable";
+const char kWebKitJavaEnabled[] = "webkit.webprefs.java_enabled";
+const char kWebkitTabsToLinks[] = "webkit.webprefs.tabs_to_links";
// Boolean which specifies whether the bookmark bar is visible on all tabs.
-const wchar_t kShowBookmarkBar[] = L"bookmark_bar.show_on_all_tabs";
+const char kShowBookmarkBar[] = "bookmark_bar.show_on_all_tabs";
// Boolean that is true if the password manager is on (will record new
// passwords and fill in known passwords).
-const wchar_t kPasswordManagerEnabled[] = L"profile.password_manager_enabled";
+const char kPasswordManagerEnabled[] = "profile.password_manager_enabled";
+
+// Boolean controlling whether the password manager allows to retrieve passwords
+// in clear text.
+const char kPasswordManagerAllowShowPasswords[] =
+ "profile.password_manager_allow_show_passwords";
// OBSOLETE. Boolean that is true if the form AutoFill is on (will record
// values entered in text inputs in forms and shows them in a popup when user
// type in a text input with the same name later on). This has been superseded
// by kAutoFillEnabled.
-const wchar_t kFormAutofillEnabled[] = L"profile.form_autofill_enabled";
+const char kFormAutofillEnabled[] = "profile.form_autofill_enabled";
// Boolean that is true when SafeBrowsing is enabled.
-const wchar_t kSafeBrowsingEnabled[] = L"safebrowsing.enabled";
+const char kSafeBrowsingEnabled[] = "safebrowsing.enabled";
// Boolean that is true when Suggest support is enabled.
-const wchar_t kSearchSuggestEnabled[] = L"search.suggest_enabled";
+const char kSearchSuggestEnabled[] = "search.suggest_enabled";
// OBSOLETE. Enum that specifies whether to enforce a third-party cookie
// blocking policy. This has been superseded by kDefaultContentSettings +
@@ -123,823 +121,900 @@ const wchar_t kSearchSuggestEnabled[] = L"search.suggest_enabled";
// 0 - allow all cookies.
// 1 - block third-party cookies
// 2 - block all cookies
-const wchar_t kCookieBehavior[] = L"security.cookie_behavior";
+const char kCookieBehavior[] = "security.cookie_behavior";
// The URL (as understood by TemplateURLRef) the default search provider uses
// for searches.
-const wchar_t kDefaultSearchProviderSearchURL[] =
- L"default_search_provider.search_url";
+const char kDefaultSearchProviderSearchURL[] =
+ "default_search_provider.search_url";
// The URL (as understood by TemplateURLRef) the default search provider uses
// for suggestions.
-const wchar_t kDefaultSearchProviderSuggestURL[] =
- L"default_search_provider.suggest_url";
+const char kDefaultSearchProviderSuggestURL[] =
+ "default_search_provider.suggest_url";
+
+// The Fav Icon URL (as understood by TemplateURLRef) of the default search
+// provider.
+const char kDefaultSearchProviderIconURL[] =
+ "default_search_provider.icon_url";
+
+// The input encoding (as understood by TemplateURLRef) supported by the default
+// search provider. The various encodings are separated by ';'
+const char kDefaultSearchProviderEncodings[] =
+ "default_search_provider.encodings";
// The name of the default search provider.
-const wchar_t kDefaultSearchProviderName[] = L"default_search_provider.name";
+const char kDefaultSearchProviderName[] = "default_search_provider.name";
+
+// The keyword of the default search provider.
+const char kDefaultSearchProviderKeyword[] = "default_search_provider.keyword";
// The id of the default search provider.
-const wchar_t kDefaultSearchProviderID[] = L"default_search_provider.id";
+const char kDefaultSearchProviderID[] = "default_search_provider.id";
// The prepopulate id of the default search provider.
-const wchar_t kDefaultSearchProviderPrepopulateID[] =
- L"default_search_provider.prepopulate_id";
+const char kDefaultSearchProviderPrepopulateID[] =
+ "default_search_provider.prepopulate_id";
// The dictionary key used when the default search providers are given
// in the preferences file. Normally they are copied from the master
// preferences file.
-const wchar_t kSearchProviderOverrides[] =
- L"search_provider_overrides";
+const char kSearchProviderOverrides[] = "search_provider_overrides";
// The format version for the dictionary above.
-const wchar_t kSearchProviderOverridesVersion[] =
- L"search_provider_overrides_version";
+const char kSearchProviderOverridesVersion[] =
+ "search_provider_overrides_version";
// Boolean which specifies whether we should ask the user if we should download
// a file (true) or just download it automatically.
-const wchar_t kPromptForDownload[] = L"download.prompt_for_download";
+const char kPromptForDownload[] = "download.prompt_for_download";
// A boolean pref set to true if we're using Link Doctor error pages.
-const wchar_t kAlternateErrorPagesEnabled[] = L"alternate_error_pages.enabled";
+const char kAlternateErrorPagesEnabled[] = "alternate_error_pages.enabled";
// A boolean pref set to true if DNS pre-fetching is being done in browser.
-const wchar_t kDnsPrefetchingEnabled[] = L"dns_prefetching.enabled";
+const char kDnsPrefetchingEnabled[] = "dns_prefetching.enabled";
// 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 wchar_t kDnsStartupPrefetchList[] = L"StartupDNSPrefetchList";
+const char kDnsStartupPrefetchList[] = "StartupDNSPrefetchList";
// 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 wchar_t kDnsHostReferralList[] = L"HostReferralList";
+const char kDnsHostReferralList[] = "HostReferralList";
// Is the cookie prompt expanded?
-const wchar_t kCookiePromptExpanded[] = L"cookieprompt.expanded";
+const char kCookiePromptExpanded[] = "cookieprompt.expanded";
#if defined(USE_NSS)
// Prefs for SSLConfigServicePref. Currently, these are only present on
// and used by NSS-using OSes.
-const wchar_t kCertRevocationCheckingEnabled[] = L"ssl.rev_checking.enabled";
-const wchar_t kSSL2Enabled[] = L"ssl.ssl2.enabled";
-const wchar_t kSSL3Enabled[] = L"ssl.ssl3.enabled";
-const wchar_t kTLS1Enabled[] = L"ssl.tls1.enabled";
+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
#if defined(OS_CHROMEOS)
// A boolean pref set to true if TapToClick is being done in browser.
-const wchar_t kTapToClickEnabled[] = L"settings.touchpad.enable_tap_to_click";
-
-// A boolean pref set to true if VertEdgeScroll is being done in browser.
-const wchar_t kVertEdgeScrollEnabled[] =
- L"settings.touchpad.enable_vert_edge_scroll";
-
-// A integer pref for the touchpad speed factor.
-const wchar_t kTouchpadSpeedFactor[] = L"settings.touchpad.speed_factor";
+const char kTapToClickEnabled[] = "settings.touchpad.enable_tap_to_click";
// A integer pref for the touchpad sensitivity.
-const wchar_t kTouchpadSensitivity[] = L"settings.touchpad.sensitivity";
+const char kTouchpadSensitivity[] = "settings.touchpad.sensitivity2";
// A string pref set to the current input method.
-const wchar_t kLanguageCurrentInputMethod[] =
- L"settings.language.current_input_method";
+const char kLanguageCurrentInputMethod[] =
+ "settings.language.current_input_method";
// A string pref set to the previous input method.
-const wchar_t kLanguagePreviousInputMethod[] =
- L"settings.language.previous_input_method";
+const char kLanguagePreviousInputMethod[] =
+ "settings.language.previous_input_method";
// A string pref (comma-separated list) set to the "next engine in menu"
// hot-key lists.
-const wchar_t kLanguageHotkeyNextEngineInMenu[] =
- L"settings.language.hotkey_next_engine_in_menu";
+const char kLanguageHotkeyNextEngineInMenu[] =
+ "settings.language.hotkey_next_engine_in_menu";
// A string pref (comma-separated list) set to the "previous engine"
// hot-key lists.
-const wchar_t kLanguageHotkeyPreviousEngine[] =
- L"settings.language.hotkey_previous_engine";
+const char kLanguageHotkeyPreviousEngine[] =
+ "settings.language.hotkey_previous_engine";
// A string pref (comma-separated list) set to the preferred language IDs
// (ex. "en-US,fr,ko").
-const wchar_t kLanguagePreferredLanguages[] =
- L"settings.language.preferred_languages";
+const char kLanguagePreferredLanguages[] =
+ "settings.language.preferred_languages";
// A string pref (comma-separated list) set to the preloaded (active) input
// method IDs (ex. "pinyin,mozc").
-const wchar_t kLanguagePreloadEngines[] = L"settings.language.preload_engines";
+const char kLanguagePreloadEngines[] = "settings.language.preload_engines";
// Boolean prefs for ibus-chewing Chinese input method.
-const wchar_t kLanguageChewingAutoShiftCur[] =
- L"settings.language.chewing_auto_shift_cur";
-const wchar_t kLanguageChewingAddPhraseDirection[] =
- L"settings.language.chewing_add_phrase_direction";
-const wchar_t kLanguageChewingEasySymbolInput[] =
- L"settings.language.chewing_easy_symbol_input";
-const wchar_t kLanguageChewingEscCleanAllBuf[] =
- L"settings.language.chewing_esc_clean_all_buf";
-const wchar_t kLanguageChewingForceLowercaseEnglish[] =
- L"settings.language.chewing_force_lowercase_english";
-const wchar_t kLanguageChewingPlainZhuyin[] =
- L"settings.language.chewing_plain_zhuyin";
-const wchar_t kLanguageChewingPhraseChoiceRearward[] =
- L"settings.language.chewing_phrase_choice_rearward";
-const wchar_t kLanguageChewingSpaceAsSelection[] =
- L"settings.language.chewing_space_as_selection";
+const char kLanguageChewingAutoShiftCur[] =
+ "settings.language.chewing_auto_shift_cur";
+const char kLanguageChewingAddPhraseDirection[] =
+ "settings.language.chewing_add_phrase_direction";
+const char kLanguageChewingEasySymbolInput[] =
+ "settings.language.chewing_easy_symbol_input";
+const char kLanguageChewingEscCleanAllBuf[] =
+ "settings.language.chewing_esc_clean_all_buf";
+const char kLanguageChewingForceLowercaseEnglish[] =
+ "settings.language.chewing_force_lowercase_english";
+const char kLanguageChewingPlainZhuyin[] =
+ "settings.language.chewing_plain_zhuyin";
+const char kLanguageChewingPhraseChoiceRearward[] =
+ "settings.language.chewing_phrase_choice_rearward";
+const char kLanguageChewingSpaceAsSelection[] =
+ "settings.language.chewing_space_as_selection";
// Integer prefs for ibus-chewing Chinese input method.
-const wchar_t kLanguageChewingMaxChiSymbolLen[] =
- L"settings.language.chewing_max_chi_symbol_len";
-const wchar_t kLanguageChewingCandPerPage[] =
- L"settings.language.chewing_cand_per_page";
+const char kLanguageChewingMaxChiSymbolLen[] =
+ "settings.language.chewing_max_chi_symbol_len";
+const char kLanguageChewingCandPerPage[] =
+ "settings.language.chewing_cand_per_page";
// String prefs for ibus-chewing Chinese input method.
-const wchar_t kLanguageChewingKeyboardType[] =
- L"settings.language.chewing_keyboard_type";
-const wchar_t kLanguageChewingSelKeys[] =
- L"settings.language.chewing_sel_keys";
+const char kLanguageChewingKeyboardType[] =
+ "settings.language.chewing_keyboard_type";
+const char kLanguageChewingSelKeys[] =
+ "settings.language.chewing_sel_keys";
-const wchar_t kLanguageChewingHsuSelKeyType[] =
- L"settings.language.chewing_hsu_sel_key_type";
+const char kLanguageChewingHsuSelKeyType[] =
+ "settings.language.chewing_hsu_sel_key_type";
// A string pref which determines the keyboard layout for Hangul input method.
-const wchar_t kLanguageHangulKeyboard[] = L"settings.language.hangul_keyboard";
-const wchar_t kLanguageHangulHanjaKeys[] =
- L"settings.language.hangul_hanja_keys";
+const char kLanguageHangulKeyboard[] = "settings.language.hangul_keyboard";
+const char kLanguageHangulHanjaKeys[] = "settings.language.hangul_hanja_keys";
// A boolean prefs for ibus-pinyin Chinese input method.
-const wchar_t kLanguagePinyinCorrectPinyin[] =
- L"settings.language.pinyin_correct_pinyin";
-const wchar_t kLanguagePinyinFuzzyPinyin[] =
- L"settings.language.pinyin_fuzzy_pinyin";
-const wchar_t kLanguagePinyinShiftSelectCandidate[] =
- L"settings.language.pinyin_shift_select_candidate";
-const wchar_t kLanguagePinyinMinusEqualPage[] =
- L"settings.language.pinyin_minus_equal_page";
-const wchar_t kLanguagePinyinCommaPeriodPage[] =
- L"settings.language.pinyin_comma_period_page";
-const wchar_t kLanguagePinyinAutoCommit[] =
- L"settings.language.pinyin_auto_commit";
-const wchar_t kLanguagePinyinDoublePinyin[] =
- L"settings.language.pinyin_double_pinyin";
-const wchar_t kLanguagePinyinInitChinese[] =
- L"settings.language.pinyin_init_chinese";
-const wchar_t kLanguagePinyinInitFull[] =
- L"settings.language.pinyin_init_full";
-const wchar_t kLanguagePinyinInitFullPunct[] =
- L"settings.language.pinyin_init_full_punct";
-const wchar_t kLanguagePinyinInitSimplifiedChinese[] =
- L"settings.language.pinyin_init_simplified_chinese";
-const wchar_t kLanguagePinyinTradCandidate[] =
- L"settings.language.pinyin_trad_candidate";
+const char kLanguagePinyinCorrectPinyin[] =
+ "settings.language.pinyin_correct_pinyin";
+const char kLanguagePinyinFuzzyPinyin[] =
+ "settings.language.pinyin_fuzzy_pinyin";
+const char kLanguagePinyinShiftSelectCandidate[] =
+ "settings.language.pinyin_shift_select_candidate";
+const char kLanguagePinyinMinusEqualPage[] =
+ "settings.language.pinyin_minus_equal_page";
+const char kLanguagePinyinCommaPeriodPage[] =
+ "settings.language.pinyin_comma_period_page";
+const char kLanguagePinyinAutoCommit[] =
+ "settings.language.pinyin_auto_commit";
+const char kLanguagePinyinDoublePinyin[] =
+ "settings.language.pinyin_double_pinyin";
+const char kLanguagePinyinInitChinese[] =
+ "settings.language.pinyin_init_chinese";
+const char kLanguagePinyinInitFull[] =
+ "settings.language.pinyin_init_full";
+const char kLanguagePinyinInitFullPunct[] =
+ "settings.language.pinyin_init_full_punct";
+const char kLanguagePinyinInitSimplifiedChinese[] =
+ "settings.language.pinyin_init_simplified_chinese";
+const char kLanguagePinyinTradCandidate[] =
+ "settings.language.pinyin_trad_candidate";
// A integer prefs for ibus-pinyin Chinese input method.
-const wchar_t kLanguagePinyinDoublePinyinSchema[] =
- L"settings.language.pinyin_double_pinyin_schema";
-const wchar_t kLanguagePinyinLookupTablePageSize[] =
- L"settings.language.pinyin_lookup_table_page_size";
+const char kLanguagePinyinDoublePinyinSchema[] =
+ "settings.language.pinyin_double_pinyin_schema";
+const char kLanguagePinyinLookupTablePageSize[] =
+ "settings.language.pinyin_lookup_table_page_size";
// A string prefs for ibus-mozc Japanese input method.
// ibus-mozc converts the string values to protobuf enum values defined in
// third_party/ibus-mozc/files/src/session/config.proto.
-const wchar_t kLanguageMozcPreeditMethod[] =
- L"settings.language.mozc_preedit_method";
-const wchar_t kLanguageMozcSessionKeymap[] =
- L"settings.language.mozc_sessoin_keymap";
-const wchar_t kLanguageMozcPunctuationMethod[] =
- L"settings.language.mozc_punctuation_method";
-const wchar_t kLanguageMozcSymbolMethod[] =
- L"settings.language.mozc_symbol_method";
-const wchar_t kLanguageMozcSpaceCharacterForm[] =
- L"settings.language.mozc_space_character_form";
-const wchar_t kLanguageMozcHistoryLearningLevel[] =
- L"settings.language.mozc_history_learning_level";
-const wchar_t kLanguageMozcSelectionShortcut[] =
- L"settings.language.mozc_selection_shortcut";
-const wchar_t kLanguageMozcShiftKeyModeSwitch[] =
- L"settings.language.mozc_shift_key_mode_switch";
-const wchar_t kLanguageMozcNumpadCharacterForm[] =
- L"settings.language.mozc_numpad_character_form";
-const wchar_t kLanguageMozcIncognitoMode[] =
- L"settings.language.mozc_incognito_mode";
-const wchar_t kLanguageMozcUseAutoImeTurnOff[] =
- L"settings.language.mozc_use_auto_ime_turn_off";
-const wchar_t kLanguageMozcUseDateConversion[] =
- L"settings.language.mozc_use_date_conversion";
-const wchar_t kLanguageMozcUseSingleKanjiConversion[] =
- L"settings.language.mozc_use_single_kanji_conversion";
-const wchar_t kLanguageMozcUseSymbolConversion[] =
- L"settings.language.mozc_use_symbol_conversion";
-const wchar_t kLanguageMozcUseNumberConversion[] =
- L"settings.language.mozc_use_number_conversion";
-const wchar_t kLanguageMozcUseHistorySuggest[] =
- L"settings.language.mozc_use_history_suggest";
-const wchar_t kLanguageMozcUseDictionarySuggest[] =
- L"settings.language.mozc_use_dictionary_suggest";
-const wchar_t kLanguageMozcSuggestionsSize[] =
- L"settings.language.mozc_suggestions_size";
+const char kLanguageMozcPreeditMethod[] =
+ "settings.language.mozc_preedit_method";
+const char kLanguageMozcSessionKeymap[] =
+ "settings.language.mozc_session_keymap";
+const char kLanguageMozcPunctuationMethod[] =
+ "settings.language.mozc_punctuation_method";
+const char kLanguageMozcSymbolMethod[] =
+ "settings.language.mozc_symbol_method";
+const char kLanguageMozcSpaceCharacterForm[] =
+ "settings.language.mozc_space_character_form";
+const char kLanguageMozcHistoryLearningLevel[] =
+ "settings.language.mozc_history_learning_level";
+const char kLanguageMozcSelectionShortcut[] =
+ "settings.language.mozc_selection_shortcut";
+const char kLanguageMozcShiftKeyModeSwitch[] =
+ "settings.language.mozc_shift_key_mode_switch";
+const char kLanguageMozcNumpadCharacterForm[] =
+ "settings.language.mozc_numpad_character_form";
+const char kLanguageMozcIncognitoMode[] =
+ "settings.language.mozc_incognito_mode";
+const char kLanguageMozcUseAutoImeTurnOff[] =
+ "settings.language.mozc_use_auto_ime_turn_off";
+const char kLanguageMozcUseDateConversion[] =
+ "settings.language.mozc_use_date_conversion";
+const char kLanguageMozcUseSingleKanjiConversion[] =
+ "settings.language.mozc_use_single_kanji_conversion";
+const char kLanguageMozcUseSymbolConversion[] =
+ "settings.language.mozc_use_symbol_conversion";
+const char kLanguageMozcUseNumberConversion[] =
+ "settings.language.mozc_use_number_conversion";
+const char kLanguageMozcUseHistorySuggest[] =
+ "settings.language.mozc_use_history_suggest";
+const char kLanguageMozcUseDictionarySuggest[] =
+ "settings.language.mozc_use_dictionary_suggest";
+const char kLanguageMozcSuggestionsSize[] =
+ "settings.language.mozc_suggestions_size";
+
+// A integer prefs which determine how we remap modifier keys (e.g. swap Alt-L
+// and Control-L.) Possible values for these prefs are 0-4. See ModifierKey enum
+// in src/third_party/cros/chrome_keyboard.h for details.
+const char kLanguageXkbRemapSearchKeyTo[] =
+ "settings.language.xkb_remap_search_key_to";
+const char kLanguageXkbRemapControlKeyTo[] =
+ "settings.language.xkb_remap_control_key_to";
+const char kLanguageXkbRemapAltKeyTo[] =
+ "settings.language.xkb_remap_alt_key_to";
+
+// A boolean pref which determines whether key repeat is enabled.
+const char kLanguageXkbAutoRepeatEnabled[] =
+ "settings.language.xkb_auto_repeat_enabled_r2";
+// A integer pref which determines key repeat delay (in ms).
+const char kLanguageXkbAutoRepeatDelay[] =
+ "settings.language.xkb_auto_repeat_delay_r2";
+// A integer pref which determines key repeat interval (in ms).
+const char kLanguageXkbAutoRepeatInterval[] =
+ "settings.language.xkb_auto_repeat_interval_r2";
+// "_r2" suffixes are added to the three prefs above when we change the
+// preferences not user-configurable, not to sync them with cloud.
// A boolean pref which determines whether accessibility is enabled.
-const wchar_t kAccessibilityEnabled[] = L"settings.accessibility";
+const char kAccessibilityEnabled[] = "settings.accessibility";
// A boolean pref which turns on Advanced Filesystem
// (USB support, SD card, etc).
-const wchar_t kLabsAdvancedFilesystemEnabled[] =
- L"settings.labs.advanced_filesystem";
+const char kLabsAdvancedFilesystemEnabled[] =
+ "settings.labs.advanced_filesystem";
// A boolean pref which turns on the mediaplayer.
-const wchar_t kLabsMediaplayerEnabled[] = L"settings.labs.mediaplayer";
+const char kLabsMediaplayerEnabled[] = "settings.labs.mediaplayer";
+
+// An integer pref which maps to the extension state for Talk.
+const char kLabsTalkEnabled[] =
+ "extensions.settings.ggnioahjipcehijkhpdjekioddnjoben.state";
#endif // defined(OS_CHROMEOS)
// The disabled messages in IPC logging.
-const wchar_t kIpcDisabledMessages[] = L"ipc_log_disabled_messages";
+const char kIpcDisabledMessages[] = "ipc_log_disabled_messages";
// A boolean pref set to true if a Home button to open the Home pages should be
// visible on the toolbar.
-const wchar_t kShowHomeButton[] = L"browser.show_home_button";
+const char kShowHomeButton[] = "browser.show_home_button";
// A boolean pref set to true if the Page and Options menu buttons should be
// visible on the toolbar. This is only used for Mac where the default is to
// have these menu in the main menubar, not as buttons on the toolbar.
-const wchar_t kShowPageOptionsButtons[] = L"browser.show_page_options_buttons";
+const char kShowPageOptionsButtons[] = "browser.show_page_options_buttons";
// A string value which saves short list of recently user selected encodings
// separated with comma punctuation mark.
-const wchar_t kRecentlySelectedEncoding[] =
- L"profile.recently_selected_encodings";
+const char kRecentlySelectedEncoding[] = "profile.recently_selected_encodings";
// Clear Browsing Data dialog preferences.
-const wchar_t kDeleteBrowsingHistory[] = L"browser.clear_data.browsing_history";
-const wchar_t kDeleteDownloadHistory[] =
- L"browser.clear_data.download_history";
-const wchar_t kDeleteCache[] = L"browser.clear_data.cache";
-const wchar_t kDeleteCookies[] = L"browser.clear_data.cookies";
-const wchar_t kDeletePasswords[] = L"browser.clear_data.passwords";
-const wchar_t kDeleteFormData[] = L"browser.clear_data.form_data";
-const wchar_t kDeleteTimePeriod[] = L"browser.clear_data.time_period";
+const char kDeleteBrowsingHistory[] = "browser.clear_data.browsing_history";
+const char kDeleteDownloadHistory[] = "browser.clear_data.download_history";
+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 kDeleteTimePeriod[] = "browser.clear_data.time_period";
// Boolean pref to define the default values for using spellchecker.
-const wchar_t kEnableSpellCheck[] = L"browser.enable_spellchecking";
+const char kEnableSpellCheck[] = "browser.enable_spellchecking";
+
+// List of names of the enabled labs experiments (see chrome/browser/labs.cc).
+const char kEnabledLabsExperiments[] = "browser.enabled_labs_experiments";
// Boolean pref to define the default values for using auto spell correct.
-const wchar_t kEnableAutoSpellCorrect[] = L"browser.enable_autospellcorrect";
+const char kEnableAutoSpellCorrect[] = "browser.enable_autospellcorrect";
+
+// Boolean controlling whether printing is enabled.
+const char kPrintingEnabled[] = "printing.enabled";
// String pref to define the default values for print overlays.
-const wchar_t kPrintingPageHeaderLeft[] = L"printing.page.header.left";
-const wchar_t kPrintingPageHeaderCenter[] = L"printing.page.header.center";
-const wchar_t kPrintingPageHeaderRight[] = L"printing.page.header.right";
-const wchar_t kPrintingPageFooterLeft[] = L"printing.page.footer.left";
-const wchar_t kPrintingPageFooterCenter[] = L"printing.page.footer.center";
-const wchar_t kPrintingPageFooterRight[] = L"printing.page.footer.right";
+const char kPrintingPageHeaderLeft[] = "printing.page.header.left";
+const char kPrintingPageHeaderCenter[] = "printing.page.header.center";
+const char kPrintingPageHeaderRight[] = "printing.page.header.right";
+const char kPrintingPageFooterLeft[] = "printing.page.footer.left";
+const char kPrintingPageFooterCenter[] = "printing.page.footer.center";
+const char kPrintingPageFooterRight[] = "printing.page.footer.right";
#if defined(TOOLKIT_USES_GTK)
// GTK specific preference on whether we should match the system GTK theme.
-const wchar_t kUsesSystemTheme[] = L"extensions.theme.use_system";
+const char kUsesSystemTheme[] = "extensions.theme.use_system";
#endif
-const wchar_t kCurrentThemePackFilename[] = L"extensions.theme.pack";
-const wchar_t kCurrentThemeID[] = L"extensions.theme.id";
-const wchar_t kCurrentThemeImages[] = L"extensions.theme.images";
-const wchar_t kCurrentThemeColors[] = L"extensions.theme.colors";
-const wchar_t kCurrentThemeTints[] = L"extensions.theme.tints";
-const wchar_t kCurrentThemeDisplayProperties[] =
- L"extensions.theme.properties";
+const char kCurrentThemePackFilename[] = "extensions.theme.pack";
+const char kCurrentThemeID[] = "extensions.theme.id";
+const char kCurrentThemeImages[] = "extensions.theme.images";
+const char kCurrentThemeColors[] = "extensions.theme.colors";
+const char kCurrentThemeTints[] = "extensions.theme.tints";
+const char kCurrentThemeDisplayProperties[] = "extensions.theme.properties";
// Boolean pref which persists whether the extensions_ui is in developer mode
// (showing developer packing tools and extensions details)
-const wchar_t kExtensionsUIDeveloperMode[] = L"extensions.ui.developer_mode";
+const char kExtensionsUIDeveloperMode[] = "extensions.ui.developer_mode";
// Integer pref that tracks the number of browser actions visible in the browser
// actions toolbar.
-const wchar_t kExtensionToolbarSize[] = L"extensions.toolbarsize";
+const char kExtensionToolbarSize[] = "extensions.toolbarsize";
// Pref containing the directory for internal plugins as written to the plugins
// list (below).
-const wchar_t kPluginsLastInternalDirectory[] =
- L"plugins.last_internal_directory";
+const char kPluginsLastInternalDirectory[] = "plugins.last_internal_directory";
// List pref containing information (dictionaries) on plugins.
-const wchar_t kPluginsPluginsList[] = L"plugins.plugins_list";
+const char kPluginsPluginsList[] = "plugins.plugins_list";
// List pref containing names of plugins that are disabled by policy.
-const wchar_t kPluginsPluginsBlacklist[] = L"plugins.plugins_blacklist";
+const char kPluginsPluginsBlacklist[] = "plugins.plugins_blacklist";
// When first shipped, the pdf plugin will be disabled by default. When we
// enable it by default, we'll want to do so only once.
-const wchar_t kPluginsEnabledInternalPDF[] = L"plugins.enabled_internal_pdf";
+const char kPluginsEnabledInternalPDF[] = "plugins.enabled_internal_pdf2";
// Boolean that indicates whether we should check if we are the default browser
// on start-up.
-const wchar_t kCheckDefaultBrowser[] = L"browser.check_default_browser";
+const char kCheckDefaultBrowser[] = "browser.check_default_browser";
#if defined(OS_MACOSX)
// Boolean that indicates whether the application should show the info bar
// asking the user to set up automatic updates when Keystone promotion is
// required.
-const wchar_t kShowUpdatePromotionInfoBar[] =
- L"browser.show_update_promotion_info_bar";
+const char kShowUpdatePromotionInfoBar[] =
+ "browser.show_update_promotion_info_bar";
#endif
// Boolean that is false if we should show window manager decorations. If
// true, we draw a custom chrome frame (thicker title bar and blue border).
-const wchar_t kUseCustomChromeFrame[] = L"browser.custom_chrome_frame";
+const char kUseCustomChromeFrame[] = "browser.custom_chrome_frame";
// Boolean that indicates whether the infobar explaining that search can be
// done directly from the omnibox should be shown.
-const wchar_t kShowOmniboxSearchHint[] = L"browser.show_omnibox_search_hint";
-
-// Int which specifies how many times left to show a promotional message on the
-// NTP. This value decrements each time the NTP is shown for the first time
-// in a session.
-const wchar_t kNTPPromoViewsRemaining[] = L"browser.ntp.promo_remaining";
+const char kShowOmniboxSearchHint[] = "browser.show_omnibox_search_hint";
// The list of origins which are allowed|denied to show desktop notifications.
-const wchar_t kDesktopNotificationDefaultContentSetting[] =
- L"profile.notifications_default_content_setting";
-const wchar_t kDesktopNotificationAllowedOrigins[] =
- L"profile.notification_allowed_sites";
-const wchar_t kDesktopNotificationDeniedOrigins[] =
- L"profile.notification_denied_sites";
+const char kDesktopNotificationDefaultContentSetting[] =
+ "profile.notifications_default_content_setting";
+const char kDesktopNotificationAllowedOrigins[] =
+ "profile.notification_allowed_sites";
+const char kDesktopNotificationDeniedOrigins[] =
+ "profile.notification_denied_sites";
// Dictionary of content settings applied to all hosts by default.
-const wchar_t kDefaultContentSettings[] = L"profile.default_content_settings";
+const char kDefaultContentSettings[] = "profile.default_content_settings";
// OBSOLETE. Dictionary that maps hostnames to content related settings.
// Default settings will be applied to hosts not in this pref.
-const wchar_t kPerHostContentSettings[] = L"profile.per_host_content_settings";
+const char kPerHostContentSettings[] = "profile.per_host_content_settings";
// Version of the pattern format used to define content settings.
-const wchar_t kContentSettingsVersion[] =
- L"profile.content_settings.pref_version";
+const char kContentSettingsVersion[] = "profile.content_settings.pref_version";
// Patterns for mapping hostnames to content related settings. Default settings
// will be applied to hosts that don't match any of the patterns. Replaces
// kPerHostContentSettings. The pattern format used is defined by
// kContentSettingsVersion.
-const wchar_t kContentSettingsPatterns[] =
- L"profile.content_settings.patterns";
+const char kContentSettingsPatterns[] = "profile.content_settings.patterns";
// Boolean that is true if we should unconditionally block third-party cookies,
// regardless of other content settings.
-const wchar_t kBlockThirdPartyCookies[] = L"profile.block_third_party_cookies";
+const char kBlockThirdPartyCookies[] = "profile.block_third_party_cookies";
+
+// Boolean that is true if non-sandboxed plug-ins should be blocked.
+const char kBlockNonsandboxedPlugins[] = "profile.block_nonsandboxed_plugins";
// Boolean that is true when all locally stored site data (e.g. cookies, local
// storage, etc..) should be deleted on exit.
-const wchar_t kClearSiteDataOnExit[] = L"profile.clear_site_data_on_exit";
+const char kClearSiteDataOnExit[] = "profile.clear_site_data_on_exit";
// Dictionary that maps hostnames to zoom levels. Hosts not in this pref will
// be displayed at the default zoom level.
-const wchar_t kPerHostZoomLevels[] = L"profile.per_host_zoom_levels";
+const char kPerHostZoomLevels[] = "profile.per_host_zoom_levels";
// Boolean that is true if AutoFill is enabled and allowed to save profile data.
-const wchar_t kAutoFillEnabled[] = L"autofill.enabled";
+const char kAutoFillEnabled[] = "autofill.enabled";
// Boolean that is true when auxiliary AutoFill profiles are enabled.
// Currently applies to Address Book "me" card on Mac. False on Win and Linux.
-const wchar_t kAutoFillAuxiliaryProfilesEnabled[] =
- L"autofill.auxiliary_profiles_enabled";
+const char kAutoFillAuxiliaryProfilesEnabled[] =
+ "autofill.auxiliary_profiles_enabled";
// Position and size of the AutoFill dialog.
-const wchar_t kAutoFillDialogPlacement[] = L"autofill.dialog_placement";
+const char kAutoFillDialogPlacement[] = "autofill.dialog_placement";
// Double that indicates positive (for matched forms) upload rate.
-const wchar_t kAutoFillPositiveUploadRate[] = L"autofill.positive_upload_rate";
+const char kAutoFillPositiveUploadRate[] = "autofill.positive_upload_rate";
// Double that indicates negative (for not matched forms) upload rate.
-const wchar_t kAutoFillNegativeUploadRate[] = L"autofill.negative_upload_rate";
+const char kAutoFillNegativeUploadRate[] = "autofill.negative_upload_rate";
// Boolean that is true when the tabstrip is to be laid out vertically down the
// side of the browser window.
-const wchar_t kUseVerticalTabs[] = L"tabs.use_vertical_tabs";
+const char kUseVerticalTabs[] = "tabs.use_vertical_tabs";
// Boolean that is true when the translate feature is enabled.
-const wchar_t kEnableTranslate[] = L"translate.enabled";
+const char kEnableTranslate[] = "translate.enabled";
-const wchar_t kPinnedTabs[] = L"pinned_tabs";
+const char kPinnedTabs[] = "pinned_tabs";
// Integer containing the default Geolocation content setting.
-const wchar_t kGeolocationDefaultContentSetting[] =
- L"geolocation.default_content_setting";
+const char kGeolocationDefaultContentSetting[] =
+ "geolocation.default_content_setting";
// Dictionary that maps [frame, toplevel] to their Geolocation content setting.
-const wchar_t kGeolocationContentSettings[] = L"geolocation.content_settings";
+const char kGeolocationContentSettings[] = "geolocation.content_settings";
// *************** LOCAL STATE ***************
// These are attached to the machine/installation
// The metrics client GUID and session ID.
-const wchar_t kMetricsClientID[] = L"user_experience_metrics.client_id";
-const wchar_t kMetricsSessionID[] = L"user_experience_metrics.session_id";
+const char kMetricsClientID[] = "user_experience_metrics.client_id";
+const char kMetricsSessionID[] = "user_experience_metrics.session_id";
// Date/time when the current metrics profile ID was created
// (which hopefully corresponds to first run).
-const wchar_t kMetricsClientIDTimestamp[] =
- L"user_experience_metrics.client_id_timestamp";
+const char kMetricsClientIDTimestamp[] =
+ "user_experience_metrics.client_id_timestamp";
// Boolean that specifies whether or not crash reporting and metrics reporting
// are sent over the network for analysis.
-const wchar_t kMetricsReportingEnabled[] =
- L"user_experience_metrics.reporting_enabled";
+const char kMetricsReportingEnabled[] =
+ "user_experience_metrics.reporting_enabled";
// Array of strings that are each UMA logs that were supposed to be sent in the
// first minute of a browser session. These logs include things like crash count
// info, etc.
-const wchar_t kMetricsInitialLogs[] =
- L"user_experience_metrics.initial_logs";
+const char kMetricsInitialLogs[] =
+ "user_experience_metrics.initial_logs";
// Array of strings that are each UMA logs that were not sent because the
// browser terminated before these accumulated metrics could be sent. These
// logs typically include histograms and memory reports, as well as ongoing
// user activities.
-const wchar_t kMetricsOngoingLogs[] =
- L"user_experience_metrics.ongoing_logs";
+const char kMetricsOngoingLogs[] =
+ "user_experience_metrics.ongoing_logs";
// Where profile specific metrics are placed.
-const wchar_t kProfileMetrics[] = L"user_experience_metrics.profiles";
+const char kProfileMetrics[] = "user_experience_metrics.profiles";
// The metrics for a profile are stored as dictionary values under the
// path kProfileMetrics. The individual metrics are placed under the path
// kProfileMetrics.kProfilePrefix<hashed-profile-id>.
-const wchar_t kProfilePrefix[] = L"profile-";
+const char kProfilePrefix[] = "profile-";
// True if the previous run of the program exited cleanly.
-const wchar_t kStabilityExitedCleanly[] =
- L"user_experience_metrics.stability.exited_cleanly";
+const char kStabilityExitedCleanly[] =
+ "user_experience_metrics.stability.exited_cleanly";
// Version string of previous run, which is used to assure that stability
// metrics reported under current version reflect stability of the same version.
-const wchar_t kStabilityStatsVersion[] =
- L"user_experience_metrics.stability.stats_version";
+const char kStabilityStatsVersion[] =
+ "user_experience_metrics.stability.stats_version";
// Build time, in seconds since an epoch, which is used to assure that stability
// metrics reported reflect stability of the same build.
-const wchar_t kStabilityStatsBuildTime[] =
- L"user_experience_metrics.stability.stats_buildtime";
+const char kStabilityStatsBuildTime[] =
+ "user_experience_metrics.stability.stats_buildtime";
// False if we received a session end and either we crashed during processing
// the session end or ran out of time and windows terminated us.
-const wchar_t kStabilitySessionEndCompleted[] =
- L"user_experience_metrics.stability.session_end_completed";
+const char kStabilitySessionEndCompleted[] =
+ "user_experience_metrics.stability.session_end_completed";
// Number of times the application was launched since last report.
-const wchar_t kStabilityLaunchCount[] =
- L"user_experience_metrics.stability.launch_count";
+const char kStabilityLaunchCount[] =
+ "user_experience_metrics.stability.launch_count";
// Number of times the application exited uncleanly since the last report.
-const wchar_t kStabilityCrashCount[] =
- L"user_experience_metrics.stability.crash_count";
+const char kStabilityCrashCount[] =
+ "user_experience_metrics.stability.crash_count";
// Number of times the session end did not complete.
-const wchar_t kStabilityIncompleteSessionEndCount[] =
- L"user_experience_metrics.stability.incomplete_session_end_count";
+const char kStabilityIncompleteSessionEndCount[] =
+ "user_experience_metrics.stability.incomplete_session_end_count";
// Number of times a page load event occurred since the last report.
-const wchar_t kStabilityPageLoadCount[] =
- L"user_experience_metrics.stability.page_load_count";
+const char kStabilityPageLoadCount[] =
+ "user_experience_metrics.stability.page_load_count";
// Number of times a renderer process crashed since the last report.
-const wchar_t kStabilityRendererCrashCount[] =
- L"user_experience_metrics.stability.renderer_crash_count";
+const char kStabilityRendererCrashCount[] =
+ "user_experience_metrics.stability.renderer_crash_count";
// Number of times an extension renderer process crashed since the last report.
-const wchar_t kStabilityExtensionRendererCrashCount[] =
- L"user_experience_metrics.stability.extension_renderer_crash_count";
+const char kStabilityExtensionRendererCrashCount[] =
+ "user_experience_metrics.stability.extension_renderer_crash_count";
// Time when the app was last launched, in seconds since the epoch.
-const wchar_t kStabilityLaunchTimeSec[] =
- L"user_experience_metrics.stability.launch_time_sec";
+const char kStabilityLaunchTimeSec[] =
+ "user_experience_metrics.stability.launch_time_sec";
// Time when the app was last known to be running, in seconds since
// the epoch.
-const wchar_t kStabilityLastTimestampSec[] =
- L"user_experience_metrics.stability.last_timestamp_sec";
+const char kStabilityLastTimestampSec[] =
+ "user_experience_metrics.stability.last_timestamp_sec";
// This is the location of a list of dictionaries of plugin stability stats.
-const wchar_t kStabilityPluginStats[] =
- L"user_experience_metrics.stability.plugin_stats2";
+const char kStabilityPluginStats[] =
+ "user_experience_metrics.stability.plugin_stats2";
// Number of times the renderer has become non-responsive since the last
// report.
-const wchar_t kStabilityRendererHangCount[] =
- L"user_experience_metrics.stability.renderer_hang_count";
+const char kStabilityRendererHangCount[] =
+ "user_experience_metrics.stability.renderer_hang_count";
// Total number of child process crashes (other than renderer / extension
// renderer ones, and plugin children, which are counted separately) since the
// last report.
-const wchar_t kStabilityChildProcessCrashCount[] =
- L"user_experience_metrics.stability.child_process_crash_count";
+const char kStabilityChildProcessCrashCount[] =
+ "user_experience_metrics.stability.child_process_crash_count";
// Number of times the browser has been able to register crash reporting.
-const wchar_t kStabilityBreakpadRegistrationSuccess[] =
- L"user_experience_metrics.stability.breakpad_registration_ok";
+const char kStabilityBreakpadRegistrationSuccess[] =
+ "user_experience_metrics.stability.breakpad_registration_ok";
// Number of times the browser has failed to register crash reporting.
-const wchar_t kStabilityBreakpadRegistrationFail[] =
- L"user_experience_metrics.stability.breakpad_registration_fail";
+const char kStabilityBreakpadRegistrationFail[] =
+ "user_experience_metrics.stability.breakpad_registration_fail";
// Number of times the browser has been run under a debugger.
-const wchar_t kStabilityDebuggerPresent[] =
- L"user_experience_metrics.stability.debugger_present";
+const char kStabilityDebuggerPresent[] =
+ "user_experience_metrics.stability.debugger_present";
// Number of times the browser has not been run under a debugger.
-const wchar_t kStabilityDebuggerNotPresent[] =
- L"user_experience_metrics.stability.debugger_not_present";
+const char kStabilityDebuggerNotPresent[] =
+ "user_experience_metrics.stability.debugger_not_present";
// The keys below are used for the dictionaries in the
// kStabilityPluginStats list.
-const wchar_t kStabilityPluginName[] = L"name";
-const wchar_t kStabilityPluginLaunches[] = L"launches";
-const wchar_t kStabilityPluginInstances[] = L"instances";
-const wchar_t kStabilityPluginCrashes[] = L"crashes";
+const char kStabilityPluginName[] = "name";
+const char kStabilityPluginLaunches[] = "launches";
+const char kStabilityPluginInstances[] = "instances";
+const char kStabilityPluginCrashes[] = "crashes";
// The keys below are strictly increasing counters over the lifetime of
// a chrome installation. They are (optionally) sent up to the uninstall
// survey in the event of uninstallation.
-const wchar_t kUninstallMetricsPageLoadCount[] =
- L"uninstall_metrics.page_load_count";
-const wchar_t kUninstallLaunchCount[] = L"uninstall_metrics.launch_count";
-const wchar_t kUninstallMetricsInstallDate[] =
- L"uninstall_metrics.installation_date2";
-const wchar_t kUninstallMetricsUptimeSec[] = L"uninstall_metrics.uptime_sec";
-const wchar_t kUninstallLastLaunchTimeSec[] =
- L"uninstall_metrics.last_launch_time_sec";
-const wchar_t kUninstallLastObservedRunTimeSec[] =
- L"uninstall_metrics.last_observed_running_time_sec";
+const char kUninstallMetricsPageLoadCount[] =
+ "uninstall_metrics.page_load_count";
+const char kUninstallLaunchCount[] = "uninstall_metrics.launch_count";
+const char kUninstallMetricsInstallDate[] =
+ "uninstall_metrics.installation_date2";
+const char kUninstallMetricsUptimeSec[] = "uninstall_metrics.uptime_sec";
+const char kUninstallLastLaunchTimeSec[] =
+ "uninstall_metrics.last_launch_time_sec";
+const char kUninstallLastObservedRunTimeSec[] =
+ "uninstall_metrics.last_observed_running_time_sec";
// A collection of position, size, and other data relating to the browser
// window to restore on startup.
-const wchar_t kBrowserWindowPlacement[] = L"browser.window_placement";
+const char kBrowserWindowPlacement[] = "browser.window_placement";
// A collection of position, size, and other data relating to the task
// manager window to restore on startup.
-const wchar_t kTaskManagerWindowPlacement[] = L"task_manager.window_placement";
+const char kTaskManagerWindowPlacement[] = "task_manager.window_placement";
// A collection of position, size, and other data relating to the page info
// window to restore on startup.
-const wchar_t kPageInfoWindowPlacement[] = L"page_info.window_placement";
+const char kPageInfoWindowPlacement[] = "page_info.window_placement";
// A collection of position, size, and other data relating to the keyword
// editor window to restore on startup.
-const wchar_t kKeywordEditorWindowPlacement[] =
- L"keyword_editor.window_placement";
+const char kKeywordEditorWindowPlacement[] = "keyword_editor.window_placement";
// A collection of position, size, and other data relating to the preferences
// window to restore on startup.
-const wchar_t kPreferencesWindowPlacement[] = L"preferences.window_placement";
+const char kPreferencesWindowPlacement[] = "preferences.window_placement";
// An integer specifying the total number of bytes to be used by the
// renderer's in-memory cache of objects.
-const wchar_t kMemoryCacheSize[] = L"renderer.memory_cache.size";
+const char kMemoryCacheSize[] = "renderer.memory_cache.size";
+
+// Boolean that records if chrome should run in background mode when background
+// apps are installed.
+const char kBackgroundModeEnabled[] = "background_mode.enabled";
+
+// 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 wchar_t kDownloadDefaultDirectory[] = L"download.default_directory";
+const char kDownloadDefaultDirectory[] = "download.default_directory";
// Boolean that records if the download directory was changed by an
// upgrade a unsafe location to a safe location.
-const wchar_t kDownloadDirUpgraded[] = L"download.directory_upgrade";
+const char kDownloadDirUpgraded[] = "download.directory_upgrade";
// String which specifies where to save html files to by default.
-const wchar_t kSaveFileDefaultDirectory[] = L"savefile.default_directory";
+const char kSaveFileDefaultDirectory[] = "savefile.default_directory";
// String which specifies the last directory that was chosen for uploading
// or opening a file.
-extern const wchar_t kSelectFileLastDirectory[] = L"selectfile.last_directory";
+extern const char kSelectFileLastDirectory[] = "selectfile.last_directory";
// Extensions which should be opened upon completion.
-const wchar_t kDownloadExtensionsToOpen[] = L"download.extensions_to_open";
+const char kDownloadExtensionsToOpen[] = "download.extensions_to_open";
// Integer which specifies the frequency in milliseconds for detecting whether
// plugin windows are hung.
-const wchar_t kHungPluginDetectFrequency[] =
- L"browser.hung_plugin_detect_freq";
+const char kHungPluginDetectFrequency[] = "browser.hung_plugin_detect_freq";
// Integer which specifies the timeout value to be used for SendMessageTimeout
// to detect a hung plugin window.
-const wchar_t kPluginMessageResponseTimeout[] =
- L"browser.plugin_message_response_timeout";
+const char kPluginMessageResponseTimeout[] =
+ "browser.plugin_message_response_timeout";
// String which represents the dictionary name for our spell-checker.
-const wchar_t kSpellCheckDictionary[] = L"spellcheck.dictionary";
+const char kSpellCheckDictionary[] = "spellcheck.dictionary";
// Dictionary of schemes used by the external protocol handler.
// The value is true if the scheme must be ignored.
-const wchar_t kExcludedSchemes[] = L"protocol_handler.excluded_schemes";
+const char kExcludedSchemes[] = "protocol_handler.excluded_schemes";
// Keys used for MAC handling of SafeBrowsing requests.
-const wchar_t kSafeBrowsingClientKey[] = L"safe_browsing.client_key";
-const wchar_t kSafeBrowsingWrappedKey[] = L"safe_browsing.wrapped_key";
+const char kSafeBrowsingClientKey[] = "safe_browsing.client_key";
+const char kSafeBrowsingWrappedKey[] = "safe_browsing.wrapped_key";
// Integer that specifies the index of the tab the user was on when they
// last visited the options window.
-const wchar_t kOptionsWindowLastTabIndex[] = L"options_window.last_tab_index";
+const char kOptionsWindowLastTabIndex[] = "options_window.last_tab_index";
// Integer that specifies the index of the tab the user was on when they
// last visited the content settings window.
-const wchar_t kContentSettingsWindowLastTabIndex[] =
- L"content_settings_window.last_tab_index";
+const char kContentSettingsWindowLastTabIndex[] =
+ "content_settings_window.last_tab_index";
// Integer that specifies the index of the tab the user was on when they
// last visited the Certificate Manager window.
-const wchar_t kCertificateManagerWindowLastTabIndex[] =
- L"certificate_manager_window.last_tab_index";
+const char kCertificateManagerWindowLastTabIndex[] =
+ "certificate_manager_window.last_tab_index";
// The mere fact that this pref is registered signals that we should show the
// First Run Search Information bubble when the first browser window appears.
// This preference is only registered by the first-run procedure.
-const wchar_t kShouldShowFirstRunBubble[] = L"show-first-run-bubble";
+const char kShouldShowFirstRunBubble[] = "show-first-run-bubble";
// The mere fact that this pref is registered signals that we should show the
// smaller OEM First Run Search Information bubble when the first
// browser window appears.
// This preference is only registered by the first-run procedure.
-const wchar_t kShouldUseOEMFirstRunBubble[] = L"show-OEM-first-run-bubble";
+const char kShouldUseOEMFirstRunBubble[] = "show-OEM-first-run-bubble";
// The mere fact that this pref is registered signals that we should show the
// minimal First Run omnibox information bubble when the first
// browser window appears.
// This preference is only registered by the first-run procedure.
-const wchar_t kShouldUseMinimalFirstRunBubble[] =
- L"show-minimal-first-run-bubble";
+const char kShouldUseMinimalFirstRunBubble[] = "show-minimal-first-run-bubble";
// Signal that we should show the welcome page when we launch Chrome.
-const wchar_t kShouldShowWelcomePage[] = L"show-welcome-page";
+const char kShouldShowWelcomePage[] = "show-welcome-page";
// String containing the last known Google URL. We re-detect this on startup in
// most cases, and use it to send traffic to the correct Google host or with the
// correct Google domain/country code for whatever location the user is in.
-const wchar_t kLastKnownGoogleURL[] = L"browser.last_known_google_url";
+const char kLastKnownGoogleURL[] = "browser.last_known_google_url";
+
+// String containing the last prompted Google URL to the user.
+// If the user is using .x TLD for Google URL and gets prompted about .y TLD
+// for Google URL, and says "no", we should leave the search engine set to .x
+// but not prompt again until the domain changes away from .y.
+const char kLastPromptedGoogleURL[] = "browser.last_prompted_google_url";
// String containing the last known intranet redirect URL, if any. See
// intranet_redirect_detector.h for more information.
-const wchar_t kLastKnownIntranetRedirectOrigin[] = L"";
+const char kLastKnownIntranetRedirectOrigin[] = "";
// Integer containing the system Country ID the first time we checked the
// template URL prepopulate data. This is used to avoid adding a whole bunch of
// new search engine choices if prepopulation runs when the user's Country ID
// differs from their previous Country ID. This pref does not exist until
// prepopulation has been run at least once.
-const wchar_t kCountryIDAtInstall[] = L"countryid_at_install";
+const char kCountryIDAtInstall[] = "countryid_at_install";
// OBSOLETE. Same as above, but uses the Windows-specific GeoID value instead.
// Updated if found to the above key.
-const wchar_t kGeoIDAtInstall[] = L"geoid_at_install";
+const char kGeoIDAtInstall[] = "geoid_at_install";
// An enum value of how the browser was shut down (see browser_shutdown.h).
-const wchar_t kShutdownType[] = L"shutdown.type";
+const char kShutdownType[] = "shutdown.type";
// Number of processes that were open when the user shut down.
-const wchar_t kShutdownNumProcesses[] = L"shutdown.num_processes";
+const char kShutdownNumProcesses[] = "shutdown.num_processes";
// Number of processes that were shut down using the slow path.
-const wchar_t kShutdownNumProcessesSlow[] = L"shutdown.num_processes_slow";
+const char kShutdownNumProcessesSlow[] = "shutdown.num_processes_slow";
// Whether to restart the current Chrome session automatically as the last thing
// before shutting everything down.
-const wchar_t kRestartLastSessionOnShutdown[] =
- L"restart.last.session.on.shutdown";
+const char kRestartLastSessionOnShutdown[] = "restart.last.session.on.shutdown";
// Number of bookmarks/folders on the bookmark bar/other bookmark folder.
-const wchar_t kNumBookmarksOnBookmarkBar[] =
- L"user_experience_metrics.num_bookmarks_on_bookmark_bar";
-const wchar_t kNumFoldersOnBookmarkBar[] =
- L"user_experience_metrics.num_folders_on_bookmark_bar";
-const wchar_t kNumBookmarksInOtherBookmarkFolder[] =
- L"user_experience_metrics.num_bookmarks_in_other_bookmark_folder";
-const wchar_t kNumFoldersInOtherBookmarkFolder[] =
- L"user_experience_metrics.num_folders_in_other_bookmark_folder";
+const char kNumBookmarksOnBookmarkBar[] =
+ "user_experience_metrics.num_bookmarks_on_bookmark_bar";
+const char kNumFoldersOnBookmarkBar[] =
+ "user_experience_metrics.num_folders_on_bookmark_bar";
+const char kNumBookmarksInOtherBookmarkFolder[] =
+ "user_experience_metrics.num_bookmarks_in_other_bookmark_folder";
+const char kNumFoldersInOtherBookmarkFolder[] =
+ "user_experience_metrics.num_folders_in_other_bookmark_folder";
// Number of keywords.
-const wchar_t kNumKeywords[] = L"user_experience_metrics.num_keywords";
+const char kNumKeywords[] = "user_experience_metrics.num_keywords";
// Placeholder preference for disabling voice / video chat if it is ever added.
// Currently, this does not change any behavior.
-const wchar_t kDisableVideoAndChat[] = L"disable_video_chat";
+const char kDisableVideoAndChat[] = "disable_video_chat";
// Whether Extensions are enabled.
-const wchar_t kDisableExtensions[] = L"extensions.disabled";
-
-// Boolean which specifies whether the Extension Shelf is visible on all tabs.
-const wchar_t kShowExtensionShelf[] = L"extensions.shelf.show_on_all_tabs";
+const char kDisableExtensions[] = "extensions.disabled";
// Integer boolean representing the width (in pixels) of the container for
// browser actions.
-const wchar_t kBrowserActionContainerWidth[] =
- L"extensions.browseractions.container.width";
+const char kBrowserActionContainerWidth[] =
+ "extensions.browseractions.container.width";
+
+// A whitelist of extension the user can install. This is controlled by the
+// administrator.
+const char kExtensionInstallAllowList[] = "extensions.install.allowlist";
+// A blacklist, containing extensions the user cannot install. This is
+// controlled by the administrator. This list should not be confused with
+// the extension blacklist, which is Google controlled.
+const char kExtensionInstallDenyList[] = "extensions.install.denylist";
// Time of the last, and next scheduled, extensions auto-update checks.
-const wchar_t kLastExtensionsUpdateCheck[] =
- L"extensions.autoupdate.last_check";
-const wchar_t kNextExtensionsUpdateCheck[] =
- L"extensions.autoupdate.next_check";
+const char kLastExtensionsUpdateCheck[] = "extensions.autoupdate.last_check";
+const char kNextExtensionsUpdateCheck[] = "extensions.autoupdate.next_check";
// Version number of last blacklist check
-const wchar_t kExtensionBlacklistUpdateVersion[] =
- L"extensions.blacklistupdate.version";
+const char kExtensionBlacklistUpdateVersion[] =
+ "extensions.blacklistupdate.version";
+
+const char kExtensionSidebarWidth[] = "extensions.sidebar.width";
// New Tab Page URLs that should not be shown as most visited thumbnails.
-const wchar_t kNTPMostVisitedURLsBlacklist[] = L"ntp.most_visited_blacklist";
+const char kNTPMostVisitedURLsBlacklist[] = "ntp.most_visited_blacklist";
// The URLs that have been pinned to the Most Visited section of the New Tab
// Page.
-const wchar_t kNTPMostVisitedPinnedURLs[] = L"ntp.pinned_urls";
+const char kNTPMostVisitedPinnedURLs[] = "ntp.pinned_urls";
-// Data downloaded from resource pages (JSON, RSS) to be displayed in the
-// recommendations portion of the NTP.
-const wchar_t kNTPTipsCache[] = L"ntp.tips_cache";
+// Data downloaded from resource pages (JSON, RSS) to be used to dynamically
+// deliver data for the new tab page.
+const char kNTPWebResourceCache[] = "ntp.web_resource_cache";
-// Last time of update of tips_cache.
-const wchar_t kNTPTipsCacheUpdate[] = L"ntp.tips_cache_update";
+// Last time of update of web_resource_cache.
+const char kNTPWebResourceCacheUpdate[] = "ntp.web_resource_cache_update";
-// Last server used to fill tips_cache.
-const wchar_t kNTPTipsServer[] = L"ntp.tips_server";
+// Last server used to fill tips.
+const char kNTPTipsResourceServer[] = "ntp.tips_resource_server";
+
+// Last server used to fill logo_resource_cache.
+const char kNTPLogoResourceServer[] = "ntp.logo_resource_server";
// Which sections should be visible on the new tab page
// 1 - Show the most visited sites in a grid
// 2 - Show the most visited sites as a list
// 4 - Show the recent section
-// 8 - Show tips
-// 16 - show sync status
-const wchar_t kNTPShownSections[] = L"ntp.shown_sections";
+// 8 - (Show tips -- DEPRECATED)
+// 16 - Show sync status
+const char kNTPShownSections[] = "ntp.shown_sections";
// This pref is used for migrating the prefs for the NTP
-const wchar_t kNTPPrefVersion[] = L"ntp.pref_version";
+const char kNTPPrefVersion[] = "ntp.pref_version";
+
+// Dates between which the NTP should show a custom logo rather than the
+// standard one.
+const char kNTPCustomLogoStart[] = "ntp.custom_logo_start";
+const char kNTPCustomLogoEnd[] = "ntp.custom_logo_end";
// A boolean specifying whether dev tools window should be opened docked.
-const wchar_t kDevToolsOpenDocked[] = L"devtools.open_docked";
+const char kDevToolsOpenDocked[] = "devtools.open_docked";
// Integer location of the split bar in the browser view.
-const wchar_t kDevToolsSplitLocation[] = L"devtools.split_location";
+const char kDevToolsSplitLocation[] = "devtools.split_location";
// 64-bit integer serialization of the base::Time when the last sync occurred.
-const wchar_t kSyncLastSyncedTime[] = L"sync.last_synced_time";
+const char kSyncLastSyncedTime[] = "sync.last_synced_time";
// Boolean specifying whether the user finished setting up sync.
-const wchar_t kSyncHasSetupCompleted[] = L"sync.has_setup_completed";
+const char kSyncHasSetupCompleted[] = "sync.has_setup_completed";
// Boolean specifying whether to automatically sync all data types (including
// future ones, as they're added). If this is true, the following preferences
// (kSyncBookmarks, kSyncPasswords, etc.) can all be ignored.
-const wchar_t kKeepEverythingSynced[] = L"sync.keep_everything_synced";
+const char kKeepEverythingSynced[] = "sync.keep_everything_synced";
// Booleans specifying whether the user has selected to sync the following
// datatypes.
-const wchar_t kSyncBookmarks[] = L"sync.bookmarks";
-const wchar_t kSyncPasswords[] = L"sync.passwords";
-const wchar_t kSyncPreferences[] = L"sync.preferences";
-const wchar_t kSyncAutofill[] = L"sync.autofill";
-const wchar_t kSyncThemes[] = L"sync.themes";
-const wchar_t kSyncTypedUrls[] = L"sync.typed_urls";
-const wchar_t kSyncExtensions[] = L"sync.extensions";
+const char kSyncBookmarks[] = "sync.bookmarks";
+const char kSyncPasswords[] = "sync.passwords";
+const char kSyncPreferences[] = "sync.preferences";
+const char kSyncApps[] = "sync.apps";
+const char kSyncAutofill[] = "sync.autofill";
+const char kSyncThemes[] = "sync.themes";
+const char kSyncTypedUrls[] = "sync.typed_urls";
+const char kSyncExtensions[] = "sync.extensions";
+const char kSyncSessions[] = "sync.sessions";
// Boolean used by enterprise configuration management in order to lock down
// sync.
-const wchar_t kSyncManaged[] = L"sync.managed";
+const char kSyncManaged[] = "sync.managed";
+
+// Boolean to prevent sync from automatically starting up. This is
+// used when sync is disabled by the user via the privacy dashboard.
+const char kSyncSuppressStart[] = "sync.suppress_start";
+
+// Boolean to reperesent if sync credentials have been migrated from the
+// user settings DB to the token service.
+const char kSyncCredentialsMigrated[] = "sync.credentials_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";
+
+// Boolean tracking whether the user chose to specify a secondary encryption
+// passphrase.
+const char kSyncUsingSecondaryPassphrase[] = "sync.using_secondary_passphrase";
+
+// String that identifies the user logged into sync and other google services.
+const char kGoogleServicesUsername[] = "google.services.username";
// Create web application shortcut dialog preferences.
-const wchar_t kWebAppCreateOnDesktop[] = L"browser.web_app.create_on_desktop";
-const wchar_t kWebAppCreateInAppsMenu[] =
- L"browser.web_app.create_in_apps_menu";
-const wchar_t kWebAppCreateInQuickLaunchBar[] =
- L"browser.web_app.create_in_quick_launch_bar";
+const char kWebAppCreateOnDesktop[] = "browser.web_app.create_on_desktop";
+const char kWebAppCreateInAppsMenu[] = "browser.web_app.create_in_apps_menu";
+const char kWebAppCreateInQuickLaunchBar[] =
+ "browser.web_app.create_in_quick_launch_bar";
// Dictionary that maps Geolocation network provider server URLs to
// corresponding access token.
-const wchar_t kGeolocationAccessToken[] = L"geolocation.access_token";
+const char kGeolocationAccessToken[] = "geolocation.access_token";
// Whether PasswordForms have been migrated from the WedDataService to the
// LoginDatabase.
-const wchar_t kLoginDatabaseMigrated[] = L"login_database.migrated";
+const char kLoginDatabaseMigrated[] = "login_database.migrated";
// The root URL of the cloud print service.
-const wchar_t kCloudPrintServiceURL[] = L"cloud_print.service_url";
+const char kCloudPrintServiceURL[] = "cloud_print.service_url";
+
+const char kRemotingHasSetupCompleted[] = "remoting.has_setup_completed";
// The list of BackgroundContents that should be loaded when the browser
// launches.
-const wchar_t kRegisteredBackgroundContents[] =
- L"background_contents.registered";
+const char kRegisteredBackgroundContents[] = "background_contents.registered";
// *************** SERVICE PREFS ***************
// These are attached to the service process.
+const char kCloudPrintProxyEnabled[] = "cloud_print.enabled";
// The unique id for this instance of the cloud print proxy.
-const wchar_t kCloudPrintProxyId[] = L"cloud_print.proxy_id";
+const char kCloudPrintProxyId[] = "cloud_print.proxy_id";
// The GAIA auth token for Cloud Print
-const wchar_t kCloudPrintAuthToken[] = L"cloud_print.auth_token";
+const char kCloudPrintAuthToken[] = "cloud_print.auth_token";
// The GAIA auth token used by Cloud Print to authenticate with the XMPP server
// This should eventually go away because the above token should work for both.
-const wchar_t kCloudPrintXMPPAuthToken[] = L"cloud_print.xmpp_auth_token";
+const char kCloudPrintXMPPAuthToken[] = "cloud_print.xmpp_auth_token";
// The email address of the account used to authenticate with the Cloud Print
// server.
-extern const wchar_t kCloudPrintEmail[] = L"cloud_print.email";
+extern const char kCloudPrintEmail[] = "cloud_print.email";
// Settings specific to underlying print system.
-extern const wchar_t kCloudPrintPrintSystemSettings[] =
- L"cloud_print.print_system_settings";
+extern const char kCloudPrintPrintSystemSettings[] =
+ "cloud_print.print_system_settings";
+
+// 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 wchar_t kNoProxyServer[] = L"proxy.disabled";
+const char kNoProxyServer[] = "proxy.disabled";
// Boolean specifying if proxy should be auto-detected.
-const wchar_t kProxyAutoDetect[] = L"proxy.auto_detect";
+const char kProxyAutoDetect[] = "proxy.auto_detect";
// String specifying the proxy server. For a specification of the expected
// syntax see net::ProxyConfig::ProxyRules::ParseFromString().
-const wchar_t kProxyServer[] = L"proxy.server";
+const char kProxyServer[] = "proxy.server";
// URL to the proxy .pac file.
-const wchar_t kProxyPacUrl[] = L"proxy.pac_url";
+const char kProxyPacUrl[] = "proxy.pac_url";
// String containing proxy bypass rules. For a specification of the
// expected syntax see net::ProxyBypassRules::ParseFromString().
-const wchar_t kProxyBypassList[] = L"proxy.bypass_list";
+const char kProxyBypassList[] = "proxy.bypass_list";
} // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 9897ec0..ea7c959 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -6,347 +6,381 @@
#ifndef CHROME_COMMON_PREF_NAMES_H_
#define CHROME_COMMON_PREF_NAMES_H_
+#pragma once
#include "build/build_config.h"
namespace prefs {
// Profile prefs
-extern const wchar_t kHomePageIsNewTabPage[];
-extern const wchar_t kHomePage[];
-extern const wchar_t kSessionExitedCleanly[];
-extern const wchar_t kRestoreOnStartup[];
-extern const wchar_t kURLsToRestoreOnStartup[];
-extern const wchar_t kApplicationLocale[];
-extern const wchar_t kDefaultCharset[];
-extern const wchar_t kAcceptLanguages[];
-extern const wchar_t kStaticEncodings[];
-extern const wchar_t kPopupWhitelistedHosts[];
-extern const wchar_t kShowBookmarkBar[];
-extern const wchar_t kWebKitStandardFontIsSerif[];
-extern const wchar_t kWebKitFixedFontFamily[];
-extern const wchar_t kWebKitSerifFontFamily[];
-extern const wchar_t kWebKitSansSerifFontFamily[];
-extern const wchar_t kWebKitCursiveFontFamily[];
-extern const wchar_t kWebKitFantasyFontFamily[];
-extern const wchar_t kWebKitDefaultFontSize[];
-extern const wchar_t kWebKitDefaultFixedFontSize[];
-extern const wchar_t kWebKitMinimumFontSize[];
-extern const wchar_t kWebKitMinimumLogicalFontSize[];
-extern const wchar_t kWebKitJavascriptEnabled[];
-extern const wchar_t kWebKitWebSecurityEnabled[];
-extern const wchar_t kWebKitJavascriptCanOpenWindowsAutomatically[];
-extern const wchar_t kWebKitLoadsImagesAutomatically[];
-extern const wchar_t kWebKitPluginsEnabled[];
-extern const wchar_t kWebKitDomPasteEnabled[];
-extern const wchar_t kWebKitShrinksStandaloneImagesToFit[];
-extern const wchar_t kWebKitInspectorSettings[];
-extern const wchar_t kWebKitUsesUniversalDetector[];
-extern const wchar_t kWebKitTextAreasAreResizable[];
-extern const wchar_t kWebKitJavaEnabled[];
-extern const wchar_t kWebkitTabsToLinks[];
-extern const wchar_t kPasswordManagerEnabled[];
-extern const wchar_t kFormAutofillEnabled[]; // OBSOLETE
-extern const wchar_t kSafeBrowsingEnabled[];
-extern const wchar_t kSearchSuggestEnabled[];
-extern const wchar_t kCookieBehavior[]; // OBSOLETE
-extern const wchar_t kDefaultSearchProviderSearchURL[];
-extern const wchar_t kDefaultSearchProviderSuggestURL[];
-extern const wchar_t kDefaultSearchProviderName[];
-extern const wchar_t kDefaultSearchProviderID[];
-extern const wchar_t kDefaultSearchProviderPrepopulateID[];
-extern const wchar_t kSearchProviderOverrides[];
-extern const wchar_t kSearchProviderOverridesVersion[];
-extern const wchar_t kPromptForDownload[];
-extern const wchar_t kAlternateErrorPagesEnabled[];
-extern const wchar_t kDnsPrefetchingEnabled[];
-extern const wchar_t kDnsStartupPrefetchList[];
-extern const wchar_t kDnsHostReferralList[];
-extern const wchar_t kCookiePromptExpanded[];
+extern const char kHomePageIsNewTabPage[];
+extern const char kHomePage[];
+extern const char kSessionExitedCleanly[];
+extern const char kRestoreOnStartup[];
+extern const char kURLsToRestoreOnStartup[];
+extern const char kApplicationLocale[];
+extern const char kDefaultCharset[];
+extern const char kAcceptLanguages[];
+extern const char kStaticEncodings[];
+extern const char kPopupWhitelistedHosts[];
+extern const char kShowBookmarkBar[];
+extern const char kWebKitStandardFontIsSerif[];
+extern const char kWebKitFixedFontFamily[];
+extern const char kWebKitSerifFontFamily[];
+extern const char kWebKitSansSerifFontFamily[];
+extern const char kWebKitCursiveFontFamily[];
+extern const char kWebKitFantasyFontFamily[];
+extern const char kWebKitDefaultFontSize[];
+extern const char kWebKitDefaultFixedFontSize[];
+extern const char kWebKitMinimumFontSize[];
+extern const char kWebKitMinimumLogicalFontSize[];
+extern const char kWebKitJavascriptEnabled[];
+extern const char kWebKitWebSecurityEnabled[];
+extern const char kWebKitJavascriptCanOpenWindowsAutomatically[];
+extern const char kWebKitLoadsImagesAutomatically[];
+extern const char kWebKitPluginsEnabled[];
+extern const char kWebKitDomPasteEnabled[];
+extern const char kWebKitShrinksStandaloneImagesToFit[];
+extern const char kWebKitInspectorSettings[];
+extern const char kWebKitUsesUniversalDetector[];
+extern const char kWebKitTextAreasAreResizable[];
+extern const char kWebKitJavaEnabled[];
+extern const char kWebkitTabsToLinks[];
+extern const char kPasswordManagerEnabled[];
+extern const char kPasswordManagerAllowShowPasswords[];
+extern const char kFormAutofillEnabled[]; // OBSOLETE
+extern const char kSafeBrowsingEnabled[];
+extern const char kSearchSuggestEnabled[];
+extern const char kCookieBehavior[]; // OBSOLETE
+extern const char kDefaultSearchProviderSearchURL[];
+extern const char kDefaultSearchProviderSuggestURL[];
+extern const char kDefaultSearchProviderIconURL[];
+extern const char kDefaultSearchProviderEncodings[];
+extern const char kDefaultSearchProviderName[];
+extern const char kDefaultSearchProviderKeyword[];
+extern const char kDefaultSearchProviderID[];
+extern const char kDefaultSearchProviderPrepopulateID[];
+extern const char kSearchProviderOverrides[];
+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 kCookiePromptExpanded[];
#if defined(USE_NSS)
-extern const wchar_t kCertRevocationCheckingEnabled[];
-extern const wchar_t kSSL2Enabled[];
-extern const wchar_t kSSL3Enabled[];
-extern const wchar_t kTLS1Enabled[];
+extern const char kCertRevocationCheckingEnabled[];
+extern const char kSSL2Enabled[];
+extern const char kSSL3Enabled[];
+extern const char kTLS1Enabled[];
#endif
#if defined(OS_CHROMEOS)
-extern const wchar_t kTapToClickEnabled[];
-extern const wchar_t kVertEdgeScrollEnabled[];
-extern const wchar_t kTouchpadSpeedFactor[];
-extern const wchar_t kTouchpadSensitivity[];
-extern const wchar_t kLanguageCurrentInputMethod[];
-extern const wchar_t kLanguagePreviousInputMethod[];
-extern const wchar_t kLanguageHotkeyNextEngineInMenu[];
-extern const wchar_t kLanguageHotkeyPreviousEngine[];
-extern const wchar_t kLanguagePreferredLanguages[];
-extern const wchar_t kLanguagePreloadEngines[];
-extern const wchar_t kLanguageChewingAutoShiftCur[];
-extern const wchar_t kLanguageChewingAddPhraseDirection[];
-extern const wchar_t kLanguageChewingEasySymbolInput[];
-extern const wchar_t kLanguageChewingEscCleanAllBuf[];
-extern const wchar_t kLanguageChewingForceLowercaseEnglish[];
-extern const wchar_t kLanguageChewingPlainZhuyin[];
-extern const wchar_t kLanguageChewingPhraseChoiceRearward[];
-extern const wchar_t kLanguageChewingSpaceAsSelection[];
-extern const wchar_t kLanguageChewingMaxChiSymbolLen[];
-extern const wchar_t kLanguageChewingCandPerPage[];
-extern const wchar_t kLanguageChewingKeyboardType[];
-extern const wchar_t kLanguageChewingSelKeys[];
-extern const wchar_t kLanguageChewingHsuSelKeyType[];
-extern const wchar_t kLanguageHangulKeyboard[];
-extern const wchar_t kLanguageHangulHanjaKeys[];
-extern const wchar_t kLanguagePinyinCorrectPinyin[];
-extern const wchar_t kLanguagePinyinFuzzyPinyin[];
-extern const wchar_t kLanguagePinyinLookupTablePageSize[];
-extern const wchar_t kLanguagePinyinShiftSelectCandidate[];
-extern const wchar_t kLanguagePinyinMinusEqualPage[];
-extern const wchar_t kLanguagePinyinCommaPeriodPage[];
-extern const wchar_t kLanguagePinyinAutoCommit[];
-extern const wchar_t kLanguagePinyinDoublePinyin[];
-extern const wchar_t kLanguagePinyinDoublePinyinSchema[];
-extern const wchar_t kLanguagePinyinInitChinese[];
-extern const wchar_t kLanguagePinyinInitFull[];
-extern const wchar_t kLanguagePinyinInitFullPunct[];
-extern const wchar_t kLanguagePinyinInitSimplifiedChinese[];
-extern const wchar_t kLanguagePinyinTradCandidate[];
-extern const wchar_t kLanguageMozcPreeditMethod[];
-extern const wchar_t kLanguageMozcSessionKeymap[];
-extern const wchar_t kLanguageMozcPunctuationMethod[];
-extern const wchar_t kLanguageMozcSymbolMethod[];
-extern const wchar_t kLanguageMozcSpaceCharacterForm[];
-extern const wchar_t kLanguageMozcHistoryLearningLevel[];
-extern const wchar_t kLanguageMozcSelectionShortcut[];
-extern const wchar_t kLanguageMozcShiftKeyModeSwitch[];
-extern const wchar_t kLanguageMozcNumpadCharacterForm[];
-extern const wchar_t kLanguageMozcIncognitoMode[];
-extern const wchar_t kLanguageMozcUseAutoImeTurnOff[];
-extern const wchar_t kLanguageMozcUseDateConversion[];
-extern const wchar_t kLanguageMozcUseSingleKanjiConversion[];
-extern const wchar_t kLanguageMozcUseSymbolConversion[];
-extern const wchar_t kLanguageMozcUseNumberConversion[];
-extern const wchar_t kLanguageMozcUseHistorySuggest[];
-extern const wchar_t kLanguageMozcUseDictionarySuggest[];
-extern const wchar_t kLanguageMozcSuggestionsSize[];
-extern const wchar_t kAccessibilityEnabled[];
-extern const wchar_t kLabsAdvancedFilesystemEnabled[];
-extern const wchar_t kLabsMediaplayerEnabled[];
+extern const char kTapToClickEnabled[];
+extern const char kTouchpadSensitivity[];
+extern const char kLanguageCurrentInputMethod[];
+extern const char kLanguagePreviousInputMethod[];
+extern const char kLanguageHotkeyNextEngineInMenu[];
+extern const char kLanguageHotkeyPreviousEngine[];
+extern const char kLanguagePreferredLanguages[];
+extern const char kLanguagePreloadEngines[];
+extern const char kLanguageChewingAutoShiftCur[];
+extern const char kLanguageChewingAddPhraseDirection[];
+extern const char kLanguageChewingEasySymbolInput[];
+extern const char kLanguageChewingEscCleanAllBuf[];
+extern const char kLanguageChewingForceLowercaseEnglish[];
+extern const char kLanguageChewingPlainZhuyin[];
+extern const char kLanguageChewingPhraseChoiceRearward[];
+extern const char kLanguageChewingSpaceAsSelection[];
+extern const char kLanguageChewingMaxChiSymbolLen[];
+extern const char kLanguageChewingCandPerPage[];
+extern const char kLanguageChewingKeyboardType[];
+extern const char kLanguageChewingSelKeys[];
+extern const char kLanguageChewingHsuSelKeyType[];
+extern const char kLanguageHangulKeyboard[];
+extern const char kLanguageHangulHanjaKeys[];
+extern const char kLanguagePinyinCorrectPinyin[];
+extern const char kLanguagePinyinFuzzyPinyin[];
+extern const char kLanguagePinyinLookupTablePageSize[];
+extern const char kLanguagePinyinShiftSelectCandidate[];
+extern const char kLanguagePinyinMinusEqualPage[];
+extern const char kLanguagePinyinCommaPeriodPage[];
+extern const char kLanguagePinyinAutoCommit[];
+extern const char kLanguagePinyinDoublePinyin[];
+extern const char kLanguagePinyinDoublePinyinSchema[];
+extern const char kLanguagePinyinInitChinese[];
+extern const char kLanguagePinyinInitFull[];
+extern const char kLanguagePinyinInitFullPunct[];
+extern const char kLanguagePinyinInitSimplifiedChinese[];
+extern const char kLanguagePinyinTradCandidate[];
+extern const char kLanguageMozcPreeditMethod[];
+extern const char kLanguageMozcSessionKeymap[];
+extern const char kLanguageMozcPunctuationMethod[];
+extern const char kLanguageMozcSymbolMethod[];
+extern const char kLanguageMozcSpaceCharacterForm[];
+extern const char kLanguageMozcHistoryLearningLevel[];
+extern const char kLanguageMozcSelectionShortcut[];
+extern const char kLanguageMozcShiftKeyModeSwitch[];
+extern const char kLanguageMozcNumpadCharacterForm[];
+extern const char kLanguageMozcIncognitoMode[];
+extern const char kLanguageMozcUseAutoImeTurnOff[];
+extern const char kLanguageMozcUseDateConversion[];
+extern const char kLanguageMozcUseSingleKanjiConversion[];
+extern const char kLanguageMozcUseSymbolConversion[];
+extern const char kLanguageMozcUseNumberConversion[];
+extern const char kLanguageMozcUseHistorySuggest[];
+extern const char kLanguageMozcUseDictionarySuggest[];
+extern const char kLanguageMozcSuggestionsSize[];
+extern const char kLanguageXkbRemapSearchKeyTo[];
+extern const char kLanguageXkbRemapControlKeyTo[];
+extern const char kLanguageXkbRemapAltKeyTo[];
+extern const char kLanguageXkbAutoRepeatEnabled[];
+extern const char kLanguageXkbAutoRepeatDelay[];
+extern const char kLanguageXkbAutoRepeatInterval[];
+extern const char kAccessibilityEnabled[];
+extern const char kLabsAdvancedFilesystemEnabled[];
+extern const char kLabsMediaplayerEnabled[];
+extern const char kLabsTalkEnabled[];
#endif
-extern const wchar_t kIpcDisabledMessages[];
-extern const wchar_t kShowHomeButton[];
-extern const wchar_t kShowPageOptionsButtons[];
-extern const wchar_t kRecentlySelectedEncoding[];
-extern const wchar_t kDeleteBrowsingHistory[];
-extern const wchar_t kDeleteDownloadHistory[];
-extern const wchar_t kDeleteCache[];
-extern const wchar_t kDeleteCookies[];
-extern const wchar_t kDeletePasswords[];
-extern const wchar_t kDeleteFormData[];
-extern const wchar_t kEnableSpellCheck[];
-extern const wchar_t kEnableAutoSpellCorrect[];
-extern const wchar_t kDeleteTimePeriod[];
-extern const wchar_t kPrintingPageHeaderLeft[];
-extern const wchar_t kPrintingPageHeaderCenter[];
-extern const wchar_t kPrintingPageHeaderRight[];
-extern const wchar_t kPrintingPageFooterLeft[];
-extern const wchar_t kPrintingPageFooterCenter[];
-extern const wchar_t kPrintingPageFooterRight[];
+extern const char kIpcDisabledMessages[];
+extern const char kShowHomeButton[];
+extern const char kShowPageOptionsButtons[];
+extern const char kRecentlySelectedEncoding[];
+extern const char kDeleteBrowsingHistory[];
+extern const char kDeleteDownloadHistory[];
+extern const char kDeleteCache[];
+extern const char kDeleteCookies[];
+extern const char kDeletePasswords[];
+extern const char kDeleteFormData[];
+extern const char kEnableSpellCheck[];
+extern const char kEnabledLabsExperiments[];
+extern const char kEnableAutoSpellCorrect[];
+extern const char kDeleteTimePeriod[];
+extern const char kPrintingEnabled[];
+extern const char kPrintingPageHeaderLeft[];
+extern const char kPrintingPageHeaderCenter[];
+extern const char kPrintingPageHeaderRight[];
+extern const char kPrintingPageFooterLeft[];
+extern const char kPrintingPageFooterCenter[];
+extern const char kPrintingPageFooterRight[];
#if defined(TOOLKIT_USES_GTK)
-extern const wchar_t kUsesSystemTheme[];
+extern const char kUsesSystemTheme[];
#endif
-extern const wchar_t kCurrentThemePackFilename[];
-extern const wchar_t kCurrentThemeID[];
-extern const wchar_t kCurrentThemeImages[];
-extern const wchar_t kCurrentThemeColors[];
-extern const wchar_t kCurrentThemeTints[];
-extern const wchar_t kCurrentThemeDisplayProperties[];
-extern const wchar_t kExtensionsUIDeveloperMode[];
-extern const wchar_t kExtensionToolbarSize[];
-extern const wchar_t kPluginsLastInternalDirectory[];
-extern const wchar_t kPluginsPluginsList[];
-extern const wchar_t kPluginsPluginsBlacklist[];
-extern const wchar_t kPluginsEnabledInternalPDF[];
-extern const wchar_t kCheckDefaultBrowser[];
+extern const char kCurrentThemePackFilename[];
+extern const char kCurrentThemeID[];
+extern const char kCurrentThemeImages[];
+extern const char kCurrentThemeColors[];
+extern const char kCurrentThemeTints[];
+extern const char kCurrentThemeDisplayProperties[];
+extern const char kExtensionsUIDeveloperMode[];
+extern const char kExtensionToolbarSize[];
+extern const char kPluginsLastInternalDirectory[];
+extern const char kPluginsPluginsList[];
+extern const char kPluginsPluginsBlacklist[];
+extern const char kPluginsEnabledInternalPDF[];
+extern const char kCheckDefaultBrowser[];
#if defined(OS_MACOSX)
-extern const wchar_t kShowUpdatePromotionInfoBar[];
+extern const char kShowUpdatePromotionInfoBar[];
#endif
-extern const wchar_t kUseCustomChromeFrame[];
-extern const wchar_t kShowOmniboxSearchHint[];
-extern const wchar_t kNTPPromoViewsRemaining[];
-extern const wchar_t kDesktopNotificationDefaultContentSetting[];
-extern const wchar_t kDesktopNotificationAllowedOrigins[];
-extern const wchar_t kDesktopNotificationDeniedOrigins[];
-extern const wchar_t kDefaultContentSettings[];
-extern const wchar_t kPerHostContentSettings[]; // OBSOLETE
-extern const wchar_t kContentSettingsVersion[];
-extern const wchar_t kContentSettingsPatterns[];
-extern const wchar_t kBlockThirdPartyCookies[];
-extern const wchar_t kClearSiteDataOnExit[];
-extern const wchar_t kPerHostZoomLevels[];
-extern const wchar_t kAutoFillEnabled[];
-extern const wchar_t kAutoFillAuxiliaryProfilesEnabled[];
-extern const wchar_t kAutoFillDialogPlacement[];
-extern const wchar_t kAutoFillPositiveUploadRate[];
-extern const wchar_t kAutoFillNegativeUploadRate[];
-
-extern const wchar_t kUseVerticalTabs[];
-extern const wchar_t kEnableTranslate[];
-extern const wchar_t kPinnedTabs[];
+extern const char kUseCustomChromeFrame[];
+extern const char kShowOmniboxSearchHint[];
+extern const char kDesktopNotificationDefaultContentSetting[];
+extern const char kDesktopNotificationAllowedOrigins[];
+extern const char kDesktopNotificationDeniedOrigins[];
+extern const char kDefaultContentSettings[];
+extern const char kPerHostContentSettings[]; // OBSOLETE
+extern const char kContentSettingsVersion[];
+extern const char kContentSettingsPatterns[];
+extern const char kBlockThirdPartyCookies[];
+extern const char kBlockNonsandboxedPlugins[];
+extern const char kClearSiteDataOnExit[];
+extern const char kPerHostZoomLevels[];
+extern const char kAutoFillEnabled[];
+extern const char kAutoFillAuxiliaryProfilesEnabled[];
+extern const char kAutoFillDialogPlacement[];
+extern const char kAutoFillPositiveUploadRate[];
+extern const char kAutoFillNegativeUploadRate[];
+
+extern const char kUseVerticalTabs[];
+extern const char kEnableTranslate[];
+extern const char kPinnedTabs[];
// Local state
-extern const wchar_t kMetricsClientID[];
-extern const wchar_t kMetricsSessionID[];
-extern const wchar_t kMetricsClientIDTimestamp[];
-extern const wchar_t kMetricsReportingEnabled[];
-extern const wchar_t kMetricsInitialLogs[];
-extern const wchar_t kMetricsOngoingLogs[];
+extern const char kMetricsClientID[];
+extern const char kMetricsSessionID[];
+extern const char kMetricsClientIDTimestamp[];
+extern const char kMetricsReportingEnabled[];
+extern const char kMetricsInitialLogs[];
+extern const char kMetricsOngoingLogs[];
+
+extern const char kProfileMetrics[];
+extern const char kProfilePrefix[];
+
+extern const char kStabilityExitedCleanly[];
+extern const char kStabilityStatsVersion[];
+extern const char kStabilityStatsBuildTime[];
+extern const char kStabilitySessionEndCompleted[];
+extern const char kStabilityLaunchCount[];
+extern const char kStabilityCrashCount[];
+extern const char kStabilityIncompleteSessionEndCount[];
+extern const char kStabilityPageLoadCount[];
+extern const char kStabilityRendererCrashCount[];
+extern const char kStabilityExtensionRendererCrashCount[];
+extern const char kStabilityLaunchTimeSec[];
+extern const char kStabilityLastTimestampSec[];
+extern const char kStabilityRendererHangCount[];
+extern const char kStabilityChildProcessCrashCount[];
+
+extern const char kStabilityBreakpadRegistrationSuccess[];
+extern const char kStabilityBreakpadRegistrationFail[];
+extern const char kStabilityDebuggerPresent[];
+extern const char kStabilityDebuggerNotPresent[];
+
+extern const char kStabilityPluginStats[];
+extern const char kStabilityPluginName[];
+extern const char kStabilityPluginLaunches[];
+extern const char kStabilityPluginInstances[];
+extern const char kStabilityPluginCrashes[];
+
+extern const char kUninstallMetricsPageLoadCount[];
+extern const char kUninstallLaunchCount[];
+
+extern const char kUninstallMetricsInstallDate[];
+extern const char kUninstallMetricsUptimeSec[];
+extern const char kUninstallLastLaunchTimeSec[];
+extern const char kUninstallLastObservedRunTimeSec[];
+
+extern const char kBrowserWindowPlacement[];
+extern const char kTaskManagerWindowPlacement[];
+extern const char kPageInfoWindowPlacement[];
+extern const char kKeywordEditorWindowPlacement[];
+extern const char kPreferencesWindowPlacement[];
+extern const char kMemoryCacheSize[];
+
+extern const char kBackgroundModeEnabled[];
+extern const char kLaunchOnStartupResetAllowed[];
+
+extern const char kDownloadDefaultDirectory[];
+extern const char kDownloadExtensionsToOpen[];
+extern const char kDownloadDirUpgraded[];
+
+extern const char kSaveFileDefaultDirectory[];
+
+extern const char kSelectFileLastDirectory[];
+
+extern const char kHungPluginDetectFrequency[];
+extern const char kPluginMessageResponseTimeout[];
+
+extern const char kSpellCheckDictionary[];
+
+extern const char kExcludedSchemes[];
+
+extern const char kSafeBrowsingClientKey[];
+extern const char kSafeBrowsingWrappedKey[];
+
+extern const char kOptionsWindowLastTabIndex[];
+extern const char kContentSettingsWindowLastTabIndex[];
+extern const char kCertificateManagerWindowLastTabIndex[];
+extern const char kShouldShowFirstRunBubble[];
+extern const char kShouldUseOEMFirstRunBubble[];
+extern const char kShouldUseMinimalFirstRunBubble[];
+extern const char kShouldShowWelcomePage[];
+
+extern const char kLastKnownGoogleURL[];
+extern const char kLastPromptedGoogleURL[];
+extern const char kLastKnownIntranetRedirectOrigin[];
+
+extern const char kCountryIDAtInstall[];
+extern const char kGeoIDAtInstall[]; // OBSOLETE
+
+extern const char kShutdownType[];
+extern const char kShutdownNumProcesses[];
+extern const char kShutdownNumProcessesSlow[];
+
+extern const char kRestartLastSessionOnShutdown[];
+
+extern const char kNumBookmarksOnBookmarkBar[];
+extern const char kNumFoldersOnBookmarkBar[];
+extern const char kNumBookmarksInOtherBookmarkFolder[];
+extern const char kNumFoldersInOtherBookmarkFolder[];
+
+extern const char kNumKeywords[];
+
+extern const char kDisableVideoAndChat[];
+
+extern const char kDisableExtensions[];
+extern const char kBrowserActionContainerWidth[];
+
+extern const char kLastExtensionsUpdateCheck[];
+extern const char kNextExtensionsUpdateCheck[];
+
+extern const char kExtensionInstallAllowList[];
+extern const char kExtensionInstallDenyList[];
+
+extern const char kExtensionBlacklistUpdateVersion[];
+
+extern const char kExtensionSidebarWidth[];
+
+extern const char kNTPMostVisitedURLsBlacklist[];
+extern const char kNTPMostVisitedPinnedURLs[];
+extern const char kNTPWebResourceCache[];
+extern const char kNTPWebResourceCacheUpdate[];
+extern const char kNTPTipsResourceServer[];
+extern const char kNTPLogoResourceServer[];
+extern const char kNTPShownSections[];
+extern const char kNTPPrefVersion[];
+extern const char kNTPCustomLogoStart[];
+extern const char kNTPCustomLogoEnd[];
+
+extern const char kDevToolsOpenDocked[];
+extern const char kDevToolsSplitLocation[];
+extern const char kSyncSessions[];
+
+extern const char kSyncLastSyncedTime[];
+extern const char kSyncHasSetupCompleted[];
+extern const char kKeepEverythingSynced[];
+extern const char kSyncBookmarks[];
+extern const char kSyncPasswords[];
+extern const char kSyncPreferences[];
+extern const char kSyncApps[];
+extern const char kSyncAutofill[];
+extern const char kSyncThemes[];
+extern const char kSyncTypedUrls[];
+extern const char kSyncExtensions[];
+extern const char kSyncManaged[];
+extern const char kSyncSuppressStart[];
+extern const char kGoogleServicesUsername[];
+extern const char kSyncCredentialsMigrated[];
+extern const char kSyncUsingSecondaryPassphrase[];
+extern const char kEncryptionBootstrapToken[];
+
+extern const char kWebAppCreateOnDesktop[];
+extern const char kWebAppCreateInAppsMenu[];
+extern const char kWebAppCreateInQuickLaunchBar[];
+
+extern const char kGeolocationAccessToken[];
+extern const char kGeolocationDefaultContentSetting[];
+extern const char kGeolocationContentSettings[];
+
+extern const char kLoginDatabaseMigrated[];
-extern const wchar_t kProfileMetrics[];
-extern const wchar_t kProfilePrefix[];
-
-extern const wchar_t kStabilityExitedCleanly[];
-extern const wchar_t kStabilityStatsVersion[];
-extern const wchar_t kStabilityStatsBuildTime[];
-extern const wchar_t kStabilitySessionEndCompleted[];
-extern const wchar_t kStabilityLaunchCount[];
-extern const wchar_t kStabilityCrashCount[];
-extern const wchar_t kStabilityIncompleteSessionEndCount[];
-extern const wchar_t kStabilityPageLoadCount[];
-extern const wchar_t kStabilityRendererCrashCount[];
-extern const wchar_t kStabilityExtensionRendererCrashCount[];
-extern const wchar_t kStabilityLaunchTimeSec[];
-extern const wchar_t kStabilityLastTimestampSec[];
-extern const wchar_t kStabilityRendererHangCount[];
-extern const wchar_t kStabilityChildProcessCrashCount[];
-
-extern const wchar_t kStabilityBreakpadRegistrationSuccess[];
-extern const wchar_t kStabilityBreakpadRegistrationFail[];
-extern const wchar_t kStabilityDebuggerPresent[];
-extern const wchar_t kStabilityDebuggerNotPresent[];
-
-extern const wchar_t kStabilityPluginStats[];
-extern const wchar_t kStabilityPluginName[];
-extern const wchar_t kStabilityPluginLaunches[];
-extern const wchar_t kStabilityPluginInstances[];
-extern const wchar_t kStabilityPluginCrashes[];
-
-extern const wchar_t kUninstallMetricsPageLoadCount[];
-extern const wchar_t kUninstallLaunchCount[];
-
-extern const wchar_t kUninstallMetricsInstallDate[];
-extern const wchar_t kUninstallMetricsUptimeSec[];
-extern const wchar_t kUninstallLastLaunchTimeSec[];
-extern const wchar_t kUninstallLastObservedRunTimeSec[];
-
-extern const wchar_t kBrowserWindowPlacement[];
-extern const wchar_t kTaskManagerWindowPlacement[];
-extern const wchar_t kPageInfoWindowPlacement[];
-extern const wchar_t kKeywordEditorWindowPlacement[];
-extern const wchar_t kPreferencesWindowPlacement[];
-extern const wchar_t kMemoryCacheSize[];
-
-extern const wchar_t kDownloadDefaultDirectory[];
-extern const wchar_t kDownloadExtensionsToOpen[];
-extern const wchar_t kDownloadDirUpgraded[];
-
-extern const wchar_t kSaveFileDefaultDirectory[];
-
-extern const wchar_t kSelectFileLastDirectory[];
-
-extern const wchar_t kHungPluginDetectFrequency[];
-extern const wchar_t kPluginMessageResponseTimeout[];
-
-extern const wchar_t kSpellCheckDictionary[];
-
-extern const wchar_t kExcludedSchemes[];
-
-extern const wchar_t kSafeBrowsingClientKey[];
-extern const wchar_t kSafeBrowsingWrappedKey[];
-
-extern const wchar_t kOptionsWindowLastTabIndex[];
-extern const wchar_t kContentSettingsWindowLastTabIndex[];
-extern const wchar_t kCertificateManagerWindowLastTabIndex[];
-extern const wchar_t kShouldShowFirstRunBubble[];
-extern const wchar_t kShouldUseOEMFirstRunBubble[];
-extern const wchar_t kShouldUseMinimalFirstRunBubble[];
-extern const wchar_t kShouldShowWelcomePage[];
-
-extern const wchar_t kLastKnownGoogleURL[];
-extern const wchar_t kLastKnownIntranetRedirectOrigin[];
-
-extern const wchar_t kCountryIDAtInstall[];
-extern const wchar_t kGeoIDAtInstall[]; // OBSOLETE
-
-extern const wchar_t kShutdownType[];
-extern const wchar_t kShutdownNumProcesses[];
-extern const wchar_t kShutdownNumProcessesSlow[];
-
-extern const wchar_t kRestartLastSessionOnShutdown[];
-
-extern const wchar_t kNumBookmarksOnBookmarkBar[];
-extern const wchar_t kNumFoldersOnBookmarkBar[];
-extern const wchar_t kNumBookmarksInOtherBookmarkFolder[];
-extern const wchar_t kNumFoldersInOtherBookmarkFolder[];
-
-extern const wchar_t kNumKeywords[];
-
-extern const wchar_t kDisableVideoAndChat[];
-
-extern const wchar_t kDisableExtensions[];
-extern const wchar_t kShowExtensionShelf[];
-extern const wchar_t kBrowserActionContainerWidth[];
-
-extern const wchar_t kLastExtensionsUpdateCheck[];
-extern const wchar_t kNextExtensionsUpdateCheck[];
-
-extern const wchar_t kExtensionBlacklistUpdateVersion[];
-
-extern const wchar_t kNTPMostVisitedURLsBlacklist[];
-extern const wchar_t kNTPMostVisitedPinnedURLs[];
-extern const wchar_t kNTPTipsCache[];
-extern const wchar_t kNTPTipsCacheUpdate[];
-extern const wchar_t kNTPTipsServer[];
-extern const wchar_t kNTPShownSections[];
-extern const wchar_t kNTPPrefVersion[];
-
-extern const wchar_t kDevToolsOpenDocked[];
-extern const wchar_t kDevToolsSplitLocation[];
-
-extern const wchar_t kSyncLastSyncedTime[];
-extern const wchar_t kSyncHasSetupCompleted[];
-extern const wchar_t kKeepEverythingSynced[];
-extern const wchar_t kSyncBookmarks[];
-extern const wchar_t kSyncPasswords[];
-extern const wchar_t kSyncPreferences[];
-extern const wchar_t kSyncAutofill[];
-extern const wchar_t kSyncThemes[];
-extern const wchar_t kSyncTypedUrls[];
-extern const wchar_t kSyncExtensions[];
-extern const wchar_t kSyncManaged[];
-
-extern const wchar_t kWebAppCreateOnDesktop[];
-extern const wchar_t kWebAppCreateInAppsMenu[];
-extern const wchar_t kWebAppCreateInQuickLaunchBar[];
-
-extern const wchar_t kGeolocationAccessToken[];
-extern const wchar_t kGeolocationDefaultContentSetting[];
-extern const wchar_t kGeolocationContentSettings[];
-
-extern const wchar_t kLoginDatabaseMigrated[];
-
-extern const wchar_t kCloudPrintServiceURL[];
-extern const wchar_t kCloudPrintProxyId[];
-extern const wchar_t kCloudPrintAuthToken[];
-extern const wchar_t kCloudPrintXMPPAuthToken[];
-extern const wchar_t kCloudPrintEmail[];
-extern const wchar_t kCloudPrintPrintSystemSettings[];
-
-extern const wchar_t kNoProxyServer[];
-extern const wchar_t kProxyAutoDetect[];
-extern const wchar_t kProxyServer[];
-extern const wchar_t kProxyPacUrl[];
-extern const wchar_t kProxyBypassList[];
-
-extern const wchar_t kRegisteredBackgroundContents[];
+extern const char kCloudPrintProxyEnabled[];
+extern const char kCloudPrintServiceURL[];
+extern const char kCloudPrintProxyId[];
+extern const char kCloudPrintAuthToken[];
+extern const char kCloudPrintXMPPAuthToken[];
+extern const char kCloudPrintEmail[];
+extern const char kCloudPrintPrintSystemSettings[];
+
+extern const char kRemotingHasSetupCompleted[];
+extern const char kRemotingHostEnabled[];
+
+extern const char kNoProxyServer[];
+extern const char kProxyAutoDetect[];
+extern const char kProxyServer[];
+extern const char kProxyPacUrl[];
+extern const char kProxyBypassList[];
+
+extern const char kRegisteredBackgroundContents[];
} // namespace prefs
diff --git a/chrome/common/pref_store.h b/chrome/common/pref_store.h
index 959c412..727c020 100644
--- a/chrome/common/pref_store.h
+++ b/chrome/common/pref_store.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_PREF_STORE_H_
#define CHROME_COMMON_PREF_STORE_H_
+#pragma once
class DictionaryValue;
@@ -26,7 +27,8 @@ class PrefStore {
PREF_READ_ERROR_FILE_LOCKED,
PREF_READ_ERROR_NO_FILE,
PREF_READ_ERROR_JSON_REPEAT,
- PREF_READ_ERROR_OTHER
+ PREF_READ_ERROR_OTHER,
+ PREF_READ_ERROR_FILE_NOT_SPECIFIED
};
virtual ~PrefStore() { }
@@ -46,4 +48,3 @@ class PrefStore {
};
#endif // CHROME_COMMON_PREF_STORE_H_
-
diff --git a/chrome/common/process_watcher.h b/chrome/common/process_watcher.h
index f764c4f..54550aa 100644
--- a/chrome/common/process_watcher.h
+++ b/chrome/common/process_watcher.h
@@ -4,11 +4,12 @@
#ifndef CHROME_COMMON_PROCESS_WATCHER_H_
#define CHROME_COMMON_PROCESS_WATCHER_H_
+#pragma once
#include "build/build_config.h"
#include "base/basictypes.h"
-#include "base/process_util.h"
+#include "base/process.h"
class ProcessWatcher {
public:
diff --git a/chrome/common/process_watcher_unittest.cc b/chrome/common/process_watcher_unittest.cc
index af4aaa2..9bde1ac 100644
--- a/chrome/common/process_watcher_unittest.cc
+++ b/chrome/common/process_watcher_unittest.cc
@@ -8,11 +8,12 @@
#include <sys/wait.h>
#include "base/eintr_wrapper.h"
-#include "base/multiprocess_test.h"
#include "base/process_util.h"
+#include "base/test/multiprocess_test.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
-class ProcessWatcherTest : public MultiProcessTest {
+class ProcessWatcherTest : public base::MultiProcessTest {
};
namespace {
@@ -29,7 +30,7 @@ bool IsProcessDead(base::ProcessHandle child) {
TEST_F(ProcessWatcherTest, DelayedTermination) {
base::ProcessHandle child_process =
- SpawnChild(L"process_watcher_test_never_die");
+ SpawnChild("process_watcher_test_never_die", false);
ProcessWatcher::EnsureProcessTerminated(child_process);
base::WaitForSingleProcess(child_process, 5000);
@@ -47,7 +48,7 @@ MULTIPROCESS_TEST_MAIN(process_watcher_test_never_die) {
TEST_F(ProcessWatcherTest, ImmediateTermination) {
base::ProcessHandle child_process =
- SpawnChild(L"process_watcher_test_die_immediately");
+ SpawnChild("process_watcher_test_die_immediately", false);
// Give it time to die.
sleep(2);
ProcessWatcher::EnsureProcessTerminated(child_process);
diff --git a/chrome/common/process_watcher_win.cc b/chrome/common/process_watcher_win.cc
index ed99780..210b3d5 100644
--- a/chrome/common/process_watcher_win.cc
+++ b/chrome/common/process_watcher_win.cc
@@ -5,7 +5,7 @@
#include "chrome/common/process_watcher.h"
#include "base/scoped_ptr.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/message_loop.h"
#include "base/object_watcher.h"
#include "chrome/common/env_vars.h"
@@ -49,8 +49,8 @@ class TimerExpiredTask : public Task, public base::ObjectWatcher::Delegate {
private:
void KillProcess() {
- scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
- if (env->HasEnv(env_vars::kHeadless)) {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ if (env->HasVar(env_vars::kHeadless)) {
// If running the distributed tests, give the renderer a little time
// to figure out that the channel is shutdown and unwind.
if (WaitForSingleObject(process_, kWaitInterval) == WAIT_OBJECT_0) {
diff --git a/chrome/common/property_bag.cc b/chrome/common/property_bag.cc
index dc25961..6974f3c 100644
--- a/chrome/common/property_bag.cc
+++ b/chrome/common/property_bag.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/linked_ptr.h"
#include "chrome/common/property_bag.h"
PropertyBag::PropertyBag() {
diff --git a/chrome/common/property_bag.h b/chrome/common/property_bag.h
index 778d0b9..d0d7c89 100644
--- a/chrome/common/property_bag.h
+++ b/chrome/common/property_bag.h
@@ -4,12 +4,14 @@
#ifndef CHROME_COMMON_PROPERTY_BAG_H_
#define CHROME_COMMON_PROPERTY_BAG_H_
+#pragma once
#include <map>
#include "base/basictypes.h"
-#include "base/linked_ptr.h"
+template <typename T>
+class linked_ptr;
class PropertyAccessorBase;
// A property bag holds a generalized list of arbitrary metadata called
diff --git a/chrome/common/ref_counted_util.h b/chrome/common/ref_counted_util.h
index b04580e..38d913b 100644
--- a/chrome/common/ref_counted_util.h
+++ b/chrome/common/ref_counted_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_REF_COUNTED_UTIL_H__
#define CHROME_COMMON_REF_COUNTED_UTIL_H__
+#pragma once
#include "base/ref_counted.h"
#include <vector>
diff --git a/chrome/common/render_messages.cc b/chrome/common/render_messages.cc
new file mode 100644
index 0000000..c7975ce
--- /dev/null
+++ b/chrome/common/render_messages.cc
@@ -0,0 +1,873 @@
+// Copyright (c) 2010 The Chromium Authors. All 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/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/serialized_script_value.h"
+#include "chrome/common/thumbnail_score.h"
+#include "gfx/rect.h"
+#include "ipc/ipc_channel_handle.h"
+#include "net/base/upload_data.h"
+#include "net/http/http_response_headers.h"
+#include "third_party/skia/include/core/SkBitmap.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 "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_dom_manager.h"
+#include "webkit/glue/password_form.h"
+#include "webkit/glue/webaccessibility.h"
+#include "webkit/glue/webcookie.h"
+#include "webkit/glue/webcursor.h"
+#include "webkit/glue/webdropdata.h"
+#include "webkit/glue/plugins/webplugin.h"
+#include "webkit/glue/plugins/webplugininfo.h"
+#include "webkit/glue/dom_operations.h"
+#include "webkit/glue/webmenuitem.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"
+
+namespace IPC {
+
+
+template<>
+struct ParamTraits<WebMenuItem::Type> {
+ typedef WebMenuItem::Type 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<WebMenuItem::Type>(type);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ std::string type;
+ switch (p) {
+ case WebMenuItem::OPTION:
+ type = "OPTION";
+ break;
+ case WebMenuItem::GROUP:
+ type = "GROUP";
+ break;
+ case WebMenuItem::SEPARATOR:
+ type = "SEPARATOR";
+ break;
+ default:
+ type = "UNKNOWN";
+ break;
+ }
+ LogParam(type, l);
+ }
+};
+
+
+void ParamTraits<webkit_glue::FormField>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.label());
+ WriteParam(m, p.name());
+ WriteParam(m, p.value());
+ WriteParam(m, p.form_control_type());
+ WriteParam(m, p.size());
+ WriteParam(m, p.option_strings());
+}
+
+bool ParamTraits<webkit_glue::FormField>::Read(const Message* m, void** iter,
+ param_type* p) {
+ string16 label, name, value, form_control_type;
+ int size = 0;
+ std::vector<string16> options;
+ bool result = ReadParam(m, iter, &label);
+ result = result && ReadParam(m, iter, &name);
+ result = result && ReadParam(m, iter, &value);
+ result = result && ReadParam(m, iter, &form_control_type);
+ result = result && ReadParam(m, iter, &size);
+ result = result && ReadParam(m, iter, &options);
+ if (!result)
+ return false;
+
+ p->set_label(label);
+ p->set_name(name);
+ p->set_value(value);
+ p->set_form_control_type(form_control_type);
+ p->set_size(size);
+ p->set_option_strings(options);
+ return true;
+}
+
+void ParamTraits<webkit_glue::FormField>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<FormField>");
+}
+
+#if defined(OS_MACOSX)
+void ParamTraits<FontDescriptor>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.font_name);
+ WriteParam(m, p.font_point_size);
+}
+
+bool ParamTraits<FontDescriptor>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return(
+ ReadParam(m, iter, &p->font_name) &&
+ ReadParam(m, iter, &p->font_point_size));
+}
+
+void ParamTraits<FontDescriptor>::Log(const param_type& p, std::string* l) {
+ l->append("<FontDescriptor>");
+}
+#endif
+
+void ParamTraits<ContextMenuParams>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.media_type);
+ WriteParam(m, p.x);
+ WriteParam(m, p.y);
+ WriteParam(m, p.link_url);
+ WriteParam(m, p.unfiltered_link_url);
+ WriteParam(m, p.src_url);
+ WriteParam(m, p.is_image_blocked);
+ WriteParam(m, p.page_url);
+ WriteParam(m, p.frame_url);
+ WriteParam(m, p.media_flags);
+ WriteParam(m, p.selection_text);
+ WriteParam(m, p.misspelled_word);
+ WriteParam(m, p.dictionary_suggestions);
+ WriteParam(m, p.spellcheck_enabled);
+ WriteParam(m, p.is_editable);
+#if defined(OS_MACOSX)
+ WriteParam(m, p.writing_direction_default);
+ WriteParam(m, p.writing_direction_left_to_right);
+ WriteParam(m, p.writing_direction_right_to_left);
+#endif // OS_MACOSX
+ WriteParam(m, p.edit_flags);
+ WriteParam(m, p.security_info);
+ WriteParam(m, p.frame_charset);
+ WriteParam(m, p.custom_items);
+}
+
+bool ParamTraits<ContextMenuParams>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->media_type) &&
+ ReadParam(m, iter, &p->x) &&
+ ReadParam(m, iter, &p->y) &&
+ ReadParam(m, iter, &p->link_url) &&
+ ReadParam(m, iter, &p->unfiltered_link_url) &&
+ ReadParam(m, iter, &p->src_url) &&
+ ReadParam(m, iter, &p->is_image_blocked) &&
+ ReadParam(m, iter, &p->page_url) &&
+ ReadParam(m, iter, &p->frame_url) &&
+ ReadParam(m, iter, &p->media_flags) &&
+ ReadParam(m, iter, &p->selection_text) &&
+ ReadParam(m, iter, &p->misspelled_word) &&
+ ReadParam(m, iter, &p->dictionary_suggestions) &&
+ ReadParam(m, iter, &p->spellcheck_enabled) &&
+ ReadParam(m, iter, &p->is_editable) &&
+#if defined(OS_MACOSX)
+ ReadParam(m, iter, &p->writing_direction_default) &&
+ ReadParam(m, iter, &p->writing_direction_left_to_right) &&
+ ReadParam(m, iter, &p->writing_direction_right_to_left) &&
+#endif // OS_MACOSX
+ ReadParam(m, iter, &p->edit_flags) &&
+ ReadParam(m, iter, &p->security_info) &&
+ ReadParam(m, iter, &p->frame_charset) &&
+ ReadParam(m, iter, &p->custom_items);
+}
+
+void ParamTraits<ContextMenuParams>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<ContextMenuParams>");
+}
+
+void ParamTraits<webkit_glue::WebPluginGeometry>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.window);
+ WriteParam(m, p.window_rect);
+ WriteParam(m, p.clip_rect);
+ WriteParam(m, p.cutout_rects);
+ WriteParam(m, p.rects_valid);
+ WriteParam(m, p.visible);
+}
+
+bool ParamTraits<webkit_glue::WebPluginGeometry>::Read(
+ const Message* m, void** iter, param_type* p) {
+ return
+ ReadParam(m, iter, &p->window) &&
+ ReadParam(m, iter, &p->window_rect) &&
+ ReadParam(m, iter, &p->clip_rect) &&
+ ReadParam(m, iter, &p->cutout_rects) &&
+ ReadParam(m, iter, &p->rects_valid) &&
+ ReadParam(m, iter, &p->visible);
+}
+
+void ParamTraits<webkit_glue::WebPluginGeometry>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.window, l);
+ l->append(", ");
+ LogParam(p.window_rect, l);
+ l->append(", ");
+ LogParam(p.clip_rect, l);
+ l->append(", ");
+ LogParam(p.cutout_rects, l);
+ l->append(", ");
+ LogParam(p.rects_valid, l);
+ l->append(", ");
+ LogParam(p.visible, l);
+ l->append(")");
+}
+
+void ParamTraits<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) {
+ 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) {
+ l->append("(");
+ LogParam(p.mime_type, l);
+ l->append(", ");
+ LogParam(p.file_extensions, l);
+ l->append(", ");
+ LogParam(p.description, l);
+ l->append(")");
+}
+
+void ParamTraits<WebPluginInfo>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.path);
+ WriteParam(m, p.version);
+ WriteParam(m, p.desc);
+ WriteParam(m, p.mime_types);
+ WriteParam(m, p.enabled);
+}
+
+bool ParamTraits<WebPluginInfo>::Read(const Message* m, void** iter,
+ param_type* r) {
+ return
+ ReadParam(m, iter, &r->name) &&
+ ReadParam(m, iter, &r->path) &&
+ ReadParam(m, iter, &r->version) &&
+ ReadParam(m, iter, &r->desc) &&
+ ReadParam(m, iter, &r->mime_types) &&
+ ReadParam(m, iter, &r->enabled);
+}
+
+void ParamTraits<WebPluginInfo>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.name, l);
+ l->append(", ");
+ l->append(", ");
+ LogParam(p.path, l);
+ l->append(", ");
+ LogParam(p.version, l);
+ l->append(", ");
+ LogParam(p.desc, l);
+ l->append(", ");
+ LogParam(p.mime_types, l);
+ l->append(", ");
+ LogParam(p.enabled, l);
+ l->append(")");
+}
+
+void ParamTraits<webkit_glue::PasswordFormFillData>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.basic_data);
+ WriteParam(m, p.additional_logins);
+ WriteParam(m, p.wait_for_username);
+}
+
+bool ParamTraits<webkit_glue::PasswordFormFillData>::Read(
+ const Message* m, void** iter, param_type* r) {
+ return
+ ReadParam(m, iter, &r->basic_data) &&
+ ReadParam(m, iter, &r->additional_logins) &&
+ ReadParam(m, iter, &r->wait_for_username);
+}
+
+void ParamTraits<webkit_glue::PasswordFormFillData>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<PasswordFormFillData>");
+}
+
+void ParamTraits<scoped_refptr<net::HttpResponseHeaders> >::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.get() != NULL);
+ if (p) {
+ // Do not disclose Set-Cookie headers over IPC.
+ p->Persist(m, net::HttpResponseHeaders::PERSIST_SANS_COOKIES);
+ }
+}
+
+bool ParamTraits<scoped_refptr<net::HttpResponseHeaders> >::Read(
+ const Message* m, void** iter, param_type* r) {
+ bool has_object;
+ if (!ReadParam(m, iter, &has_object))
+ return false;
+ if (has_object)
+ *r = new net::HttpResponseHeaders(*m, iter);
+ return true;
+}
+
+void ParamTraits<scoped_refptr<net::HttpResponseHeaders> >::Log(
+ const param_type& p, std::string* l) {
+ l->append("<HttpResponseHeaders>");
+}
+
+void ParamTraits<webkit_glue::FormData>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.method);
+ WriteParam(m, p.origin);
+ WriteParam(m, p.action);
+ WriteParam(m, p.user_submitted);
+ WriteParam(m, p.fields);
+}
+
+bool ParamTraits<webkit_glue::FormData>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->method) &&
+ ReadParam(m, iter, &p->origin) &&
+ ReadParam(m, iter, &p->action) &&
+ ReadParam(m, iter, &p->user_submitted) &&
+ ReadParam(m, iter, &p->fields);
+}
+
+void ParamTraits<webkit_glue::FormData>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<FormData>");
+}
+
+void ParamTraits<RendererPreferences>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.can_accept_load_drops);
+ WriteParam(m, p.should_antialias_text);
+ WriteParam(m, static_cast<int>(p.hinting));
+ WriteParam(m, static_cast<int>(p.subpixel_rendering));
+ WriteParam(m, p.focus_ring_color);
+ WriteParam(m, p.thumb_active_color);
+ WriteParam(m, p.thumb_inactive_color);
+ WriteParam(m, p.track_color);
+ WriteParam(m, p.active_selection_bg_color);
+ WriteParam(m, p.active_selection_fg_color);
+ WriteParam(m, p.inactive_selection_bg_color);
+ WriteParam(m, p.inactive_selection_fg_color);
+ WriteParam(m, p.browser_handles_top_level_requests);
+ WriteParam(m, p.caret_blink_interval);
+}
+
+bool ParamTraits<RendererPreferences>::Read(const Message* m, void** iter,
+ param_type* p) {
+ if (!ReadParam(m, iter, &p->can_accept_load_drops))
+ return false;
+ if (!ReadParam(m, iter, &p->should_antialias_text))
+ return false;
+
+ int hinting = 0;
+ if (!ReadParam(m, iter, &hinting))
+ return false;
+ p->hinting = static_cast<RendererPreferencesHintingEnum>(hinting);
+
+ int subpixel_rendering = 0;
+ if (!ReadParam(m, iter, &subpixel_rendering))
+ return false;
+ p->subpixel_rendering =
+ static_cast<RendererPreferencesSubpixelRenderingEnum>(
+ subpixel_rendering);
+
+ int focus_ring_color;
+ if (!ReadParam(m, iter, &focus_ring_color))
+ return false;
+ p->focus_ring_color = focus_ring_color;
+
+ int thumb_active_color, thumb_inactive_color, track_color;
+ int active_selection_bg_color, active_selection_fg_color;
+ int inactive_selection_bg_color, inactive_selection_fg_color;
+ if (!ReadParam(m, iter, &thumb_active_color) ||
+ !ReadParam(m, iter, &thumb_inactive_color) ||
+ !ReadParam(m, iter, &track_color) ||
+ !ReadParam(m, iter, &active_selection_bg_color) ||
+ !ReadParam(m, iter, &active_selection_fg_color) ||
+ !ReadParam(m, iter, &inactive_selection_bg_color) ||
+ !ReadParam(m, iter, &inactive_selection_fg_color))
+ return false;
+ p->thumb_active_color = thumb_active_color;
+ p->thumb_inactive_color = thumb_inactive_color;
+ p->track_color = track_color;
+ p->active_selection_bg_color = active_selection_bg_color;
+ p->active_selection_fg_color = active_selection_fg_color;
+ p->inactive_selection_bg_color = inactive_selection_bg_color;
+ p->inactive_selection_fg_color = inactive_selection_fg_color;
+
+ if (!ReadParam(m, iter, &p->browser_handles_top_level_requests))
+ return false;
+
+ if (!ReadParam(m, iter, &p->caret_blink_interval))
+ return false;
+
+ return true;
+}
+
+void ParamTraits<RendererPreferences>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<RendererPreferences>");
+}
+
+void ParamTraits<WebPreferences>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.standard_font_family);
+ WriteParam(m, p.fixed_font_family);
+ WriteParam(m, p.serif_font_family);
+ WriteParam(m, p.sans_serif_font_family);
+ WriteParam(m, p.cursive_font_family);
+ WriteParam(m, p.fantasy_font_family);
+ WriteParam(m, p.default_font_size);
+ WriteParam(m, p.default_fixed_font_size);
+ WriteParam(m, p.minimum_font_size);
+ WriteParam(m, p.minimum_logical_font_size);
+ WriteParam(m, p.default_encoding);
+ WriteParam(m, p.javascript_enabled);
+ WriteParam(m, p.web_security_enabled);
+ WriteParam(m, p.javascript_can_open_windows_automatically);
+ WriteParam(m, p.loads_images_automatically);
+ WriteParam(m, p.plugins_enabled);
+ WriteParam(m, p.dom_paste_enabled);
+ WriteParam(m, p.developer_extras_enabled);
+ WriteParam(m, p.inspector_settings);
+ WriteParam(m, p.site_specific_quirks_enabled);
+ WriteParam(m, p.shrinks_standalone_images_to_fit);
+ WriteParam(m, p.uses_universal_detector);
+ WriteParam(m, p.text_areas_are_resizable);
+ WriteParam(m, p.java_enabled);
+ WriteParam(m, p.allow_scripts_to_close_windows);
+ WriteParam(m, p.uses_page_cache);
+ WriteParam(m, p.remote_fonts_enabled);
+ WriteParam(m, p.javascript_can_access_clipboard);
+ WriteParam(m, p.xss_auditor_enabled);
+ WriteParam(m, p.local_storage_enabled);
+ WriteParam(m, p.databases_enabled);
+ WriteParam(m, p.application_cache_enabled);
+ WriteParam(m, p.tabs_to_links);
+ WriteParam(m, p.user_style_sheet_enabled);
+ WriteParam(m, p.user_style_sheet_location);
+ WriteParam(m, p.author_and_user_styles_enabled);
+ WriteParam(m, p.allow_universal_access_from_file_urls);
+ WriteParam(m, p.allow_file_access_from_file_urls);
+ WriteParam(m, p.experimental_webgl_enabled);
+ WriteParam(m, p.show_composited_layer_borders);
+ WriteParam(m, p.accelerated_compositing_enabled);
+ WriteParam(m, p.accelerated_2d_canvas_enabled);
+ WriteParam(m, p.memory_info_enabled);
+}
+
+bool ParamTraits<WebPreferences>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->standard_font_family) &&
+ ReadParam(m, iter, &p->fixed_font_family) &&
+ ReadParam(m, iter, &p->serif_font_family) &&
+ ReadParam(m, iter, &p->sans_serif_font_family) &&
+ ReadParam(m, iter, &p->cursive_font_family) &&
+ ReadParam(m, iter, &p->fantasy_font_family) &&
+ ReadParam(m, iter, &p->default_font_size) &&
+ ReadParam(m, iter, &p->default_fixed_font_size) &&
+ ReadParam(m, iter, &p->minimum_font_size) &&
+ ReadParam(m, iter, &p->minimum_logical_font_size) &&
+ ReadParam(m, iter, &p->default_encoding) &&
+ ReadParam(m, iter, &p->javascript_enabled) &&
+ ReadParam(m, iter, &p->web_security_enabled) &&
+ ReadParam(m, iter, &p->javascript_can_open_windows_automatically) &&
+ ReadParam(m, iter, &p->loads_images_automatically) &&
+ ReadParam(m, iter, &p->plugins_enabled) &&
+ ReadParam(m, iter, &p->dom_paste_enabled) &&
+ ReadParam(m, iter, &p->developer_extras_enabled) &&
+ ReadParam(m, iter, &p->inspector_settings) &&
+ ReadParam(m, iter, &p->site_specific_quirks_enabled) &&
+ ReadParam(m, iter, &p->shrinks_standalone_images_to_fit) &&
+ ReadParam(m, iter, &p->uses_universal_detector) &&
+ ReadParam(m, iter, &p->text_areas_are_resizable) &&
+ ReadParam(m, iter, &p->java_enabled) &&
+ ReadParam(m, iter, &p->allow_scripts_to_close_windows) &&
+ ReadParam(m, iter, &p->uses_page_cache) &&
+ ReadParam(m, iter, &p->remote_fonts_enabled) &&
+ ReadParam(m, iter, &p->javascript_can_access_clipboard) &&
+ ReadParam(m, iter, &p->xss_auditor_enabled) &&
+ ReadParam(m, iter, &p->local_storage_enabled) &&
+ ReadParam(m, iter, &p->databases_enabled) &&
+ ReadParam(m, iter, &p->application_cache_enabled) &&
+ ReadParam(m, iter, &p->tabs_to_links) &&
+ ReadParam(m, iter, &p->user_style_sheet_enabled) &&
+ ReadParam(m, iter, &p->user_style_sheet_location) &&
+ ReadParam(m, iter, &p->author_and_user_styles_enabled) &&
+ ReadParam(m, iter, &p->allow_universal_access_from_file_urls) &&
+ ReadParam(m, iter, &p->allow_file_access_from_file_urls) &&
+ ReadParam(m, iter, &p->experimental_webgl_enabled) &&
+ ReadParam(m, iter, &p->show_composited_layer_borders) &&
+ ReadParam(m, iter, &p->accelerated_compositing_enabled) &&
+ ReadParam(m, iter, &p->accelerated_2d_canvas_enabled) &&
+ ReadParam(m, iter, &p->memory_info_enabled);
+}
+
+void ParamTraits<WebPreferences>::Log(const param_type& p, std::string* l) {
+ l->append("<WebPreferences>");
+}
+
+void ParamTraits<WebDropData>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.identity);
+ WriteParam(m, p.url);
+ WriteParam(m, p.url_title);
+ WriteParam(m, p.download_metadata);
+ WriteParam(m, p.file_extension);
+ WriteParam(m, p.filenames);
+ WriteParam(m, p.plain_text);
+ WriteParam(m, p.text_html);
+ WriteParam(m, p.html_base_url);
+ WriteParam(m, p.file_description_filename);
+ WriteParam(m, p.file_contents);
+}
+
+bool ParamTraits<WebDropData>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->identity) &&
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->url_title) &&
+ ReadParam(m, iter, &p->download_metadata) &&
+ ReadParam(m, iter, &p->file_extension) &&
+ ReadParam(m, iter, &p->filenames) &&
+ ReadParam(m, iter, &p->plain_text) &&
+ ReadParam(m, iter, &p->text_html) &&
+ ReadParam(m, iter, &p->html_base_url) &&
+ ReadParam(m, iter, &p->file_description_filename) &&
+ ReadParam(m, iter, &p->file_contents);
+}
+
+void ParamTraits<WebDropData>::Log(const param_type& p, std::string* l) {
+ l->append("<WebDropData>");
+}
+
+void ParamTraits<WebMenuItem>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.label);
+ WriteParam(m, p.type);
+ WriteParam(m, p.enabled);
+ WriteParam(m, p.checked);
+ WriteParam(m, p.action);
+}
+
+bool ParamTraits<WebMenuItem>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->label) &&
+ ReadParam(m, iter, &p->type) &&
+ ReadParam(m, iter, &p->enabled) &&
+ ReadParam(m, iter, &p->checked) &&
+ ReadParam(m, iter, &p->action);
+}
+
+void ParamTraits<WebMenuItem>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.label, l);
+ l->append(", ");
+ LogParam(p.type, l);
+ l->append(", ");
+ LogParam(p.enabled, l);
+ l->append(", ");
+ LogParam(p.checked, l);
+ l->append(", ");
+ LogParam(p.action, l);
+ l->append(")");
+}
+
+void ParamTraits<URLPattern>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.valid_schemes());
+ WriteParam(m, p.GetAsString());
+}
+
+bool ParamTraits<URLPattern>::Read(const Message* m, void** iter,
+ param_type* p) {
+ int valid_schemes;
+ std::string spec;
+ if (!ReadParam(m, iter, &valid_schemes) ||
+ !ReadParam(m, iter, &spec))
+ return false;
+
+ p->set_valid_schemes(valid_schemes);
+ return p->Parse(spec);
+}
+
+void ParamTraits<URLPattern>::Log(const param_type& p, std::string* l) {
+ LogParam(p.GetAsString(), l);
+}
+
+void ParamTraits<EditCommand>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.value);
+}
+
+bool ParamTraits<EditCommand>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->name) && ReadParam(m, iter, &p->value);
+}
+
+void ParamTraits<EditCommand>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.name, l);
+ l->append(":");
+ LogParam(p.value, l);
+ l->append(")");
+}
+
+void ParamTraits<webkit_glue::WebCookie>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.value);
+ WriteParam(m, p.domain);
+ WriteParam(m, p.path);
+ WriteParam(m, p.expires);
+ WriteParam(m, p.http_only);
+ WriteParam(m, p.secure);
+ WriteParam(m, p.session);
+}
+
+bool ParamTraits<webkit_glue::WebCookie>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->value) &&
+ ReadParam(m, iter, &p->domain) &&
+ ReadParam(m, iter, &p->path) &&
+ ReadParam(m, iter, &p->expires) &&
+ ReadParam(m, iter, &p->http_only) &&
+ ReadParam(m, iter, &p->secure) &&
+ ReadParam(m, iter, &p->session);
+}
+
+void ParamTraits<webkit_glue::WebCookie>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<WebCookie>");
+}
+
+void ParamTraits<ExtensionExtent>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.patterns());
+}
+
+bool ParamTraits<ExtensionExtent>::Read(const Message* m, void** iter,
+ param_type* p) {
+ std::vector<URLPattern> patterns;
+ bool success =
+ ReadParam(m, iter, &patterns);
+ if (!success)
+ return false;
+
+ for (size_t i = 0; i < patterns.size(); ++i)
+ p->AddPattern(patterns[i]);
+ return true;
+}
+
+void ParamTraits<ExtensionExtent>::Log(const param_type& p, std::string* l) {
+ LogParam(p.patterns(), l);
+}
+
+void ParamTraits<appcache::AppCacheResourceInfo>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.url);
+ WriteParam(m, p.size);
+ WriteParam(m, p.is_manifest);
+ WriteParam(m, p.is_master);
+ WriteParam(m, p.is_fallback);
+ WriteParam(m, p.is_foreign);
+ WriteParam(m, p.is_explicit);
+}
+
+bool ParamTraits<appcache::AppCacheResourceInfo>::Read(
+ const Message* m, void** iter, param_type* p) {
+ return ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->size) &&
+ ReadParam(m, iter, &p->is_manifest) &&
+ ReadParam(m, iter, &p->is_master) &&
+ ReadParam(m, iter, &p->is_fallback) &&
+ ReadParam(m, iter, &p->is_foreign) &&
+ ReadParam(m, iter, &p->is_explicit);
+}
+
+void ParamTraits<appcache::AppCacheResourceInfo>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.size, l);
+ l->append(", ");
+ LogParam(p.is_manifest, l);
+ l->append(", ");
+ LogParam(p.is_master, l);
+ l->append(", ");
+ LogParam(p.is_fallback, l);
+ l->append(", ");
+ LogParam(p.is_foreign, l);
+ l->append(", ");
+ LogParam(p.is_explicit, l);
+ l->append(")");
+}
+
+void ParamTraits<appcache::AppCacheInfo>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.manifest_url);
+ WriteParam(m, p.creation_time);
+ WriteParam(m, p.last_update_time);
+ WriteParam(m, p.last_access_time);
+ WriteParam(m, p.cache_id);
+ WriteParam(m, p.status);
+ WriteParam(m, p.size);
+ WriteParam(m, p.is_complete);
+}
+
+bool ParamTraits<appcache::AppCacheInfo>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->manifest_url) &&
+ ReadParam(m, iter, &p->creation_time) &&
+ ReadParam(m, iter, &p->last_update_time) &&
+ ReadParam(m, iter, &p->last_access_time) &&
+ ReadParam(m, iter, &p->cache_id) &&
+ ReadParam(m, iter, &p->status) &&
+ ReadParam(m, iter, &p->size) &&
+ ReadParam(m, iter, &p->is_complete);
+}
+
+void ParamTraits<appcache::AppCacheInfo>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.manifest_url, l);
+ l->append(", ");
+ LogParam(p.creation_time, l);
+ l->append(", ");
+ LogParam(p.last_update_time, l);
+ l->append(", ");
+ LogParam(p.last_access_time, l);
+ l->append(", ");
+ LogParam(p.cache_id, l);
+ l->append(", ");
+ LogParam(p.status, l);
+ l->append(", ");
+ LogParam(p.size, l);
+ l->append(")");
+ LogParam(p.is_complete, l);
+ l->append(", ");
+}
+
+void ParamTraits<webkit_glue::WebAccessibility>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.id);
+ WriteParam(m, p.name);
+ WriteParam(m, p.value);
+ WriteParam(m, static_cast<int>(p.role));
+ WriteParam(m, static_cast<int>(p.state));
+ WriteParam(m, p.location);
+ WriteParam(m, p.attributes);
+ WriteParam(m, p.children);
+ WriteParam(m, p.html_attributes);
+}
+
+bool ParamTraits<webkit_glue::WebAccessibility>::Read(
+ const Message* m, void** iter, param_type* p) {
+ bool ret = ReadParam(m, iter, &p->id);
+ ret = ret && ReadParam(m, iter, &p->name);
+ ret = ret && ReadParam(m, iter, &p->value);
+ int role = -1;
+ ret = ret && ReadParam(m, iter, &role);
+ if (role >= webkit_glue::WebAccessibility::ROLE_NONE &&
+ role < webkit_glue::WebAccessibility::NUM_ROLES) {
+ p->role = static_cast<webkit_glue::WebAccessibility::Role>(role);
+ } else {
+ p->role = webkit_glue::WebAccessibility::ROLE_NONE;
+ }
+ int state = 0;
+ ret = ret && ReadParam(m, iter, &state);
+ p->state = static_cast<webkit_glue::WebAccessibility::State>(state);
+ ret = ret && ReadParam(m, iter, &p->location);
+ ret = ret && ReadParam(m, iter, &p->attributes);
+ ret = ret && ReadParam(m, iter, &p->children);
+ ret = ret && ReadParam(m, iter, &p->html_attributes);
+ return ret;
+}
+
+void ParamTraits<webkit_glue::WebAccessibility>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.id, l);
+ l->append(", ");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.value, l);
+ l->append(", ");
+ LogParam(static_cast<int>(p.role), l);
+ l->append(", ");
+ LogParam(static_cast<int>(p.state), l);
+ l->append(", ");
+ LogParam(p.location, l);
+ l->append(", ");
+ LogParam(p.attributes, l);
+ l->append(", ");
+ LogParam(p.children, l);
+ l->append(", ");
+ LogParam(p.html_attributes, l);
+ l->append(")");
+}
+
+void ParamTraits<AudioBuffersState>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.pending_bytes);
+ WriteParam(m, p.hardware_delay_bytes);
+ WriteParam(m, p.timestamp);
+}
+
+bool ParamTraits<AudioBuffersState>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->pending_bytes) &&
+ ReadParam(m, iter, &p->hardware_delay_bytes) &&
+ ReadParam(m, iter, &p->timestamp);
+}
+
+void ParamTraits<AudioBuffersState>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.pending_bytes, l);
+ l->append(", ");
+ LogParam(p.hardware_delay_bytes, l);
+ l->append(", ");
+ LogParam(p.timestamp, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index e1ec6b3..3d838d6 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -4,811 +4,111 @@
#ifndef CHROME_COMMON_RENDER_MESSAGES_H_
#define CHROME_COMMON_RENDER_MESSAGES_H_
+#pragma once
-#include <map>
#include <string>
#include <vector>
-#include "app/clipboard/clipboard.h"
-#include "app/surface/transport_dib.h"
+// TODO(erg): This list has been temporarily annotated by erg while doing work
+// on which headers to pull out.
+#include "app/clipboard/clipboard.h" // enum
#include "base/basictypes.h"
-#include "base/platform_file.h"
#include "base/ref_counted.h"
-#include "base/shared_memory.h"
#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/edit_command.h"
-#include "chrome/common/extensions/extension_extent.h"
-#include "chrome/common/extensions/url_pattern.h"
-#include "chrome/common/font_descriptor_mac.h"
-#include "chrome/common/indexed_db_key.h"
-#include "chrome/common/navigation_gesture.h"
+#include "chrome/common/indexed_db_param_traits.h"
#include "chrome/common/page_transition_types.h"
-#include "chrome/common/renderer_preferences.h"
#include "chrome/common/resource_response.h"
#include "chrome/common/translate_errors.h"
#include "chrome/common/view_types.h"
-#include "chrome/common/serialized_script_value.h"
#include "chrome/common/webkit_param_traits.h"
-#include "chrome/common/window_container_type.h"
#include "gfx/native_widget_types.h"
-#include "googleurl/src/gurl.h"
#include "ipc/ipc_message_utils.h"
-#include "ipc/ipc_platform_file.h"
-#include "media/audio/audio_io.h"
-#include "net/base/upload_data.h"
-#include "net/http/http_response_headers.h"
+#include "ipc/ipc_platform_file.h" // ifdefed typedef.
+#include "media/audio/audio_buffers_state.h"
#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h"
-#include "webkit/appcache/appcache_interfaces.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/webdropdata.h"
-#include "webkit/glue/webmenuitem.h"
-#include "webkit/glue/webpreferences.h"
+#include "webkit/appcache/appcache_interfaces.h" // enum appcache::Status
+#include "webkit/fileapi/file_system_types.h" // enum fileapi::FileSystemType
+#include "webkit/glue/resource_loader_bridge.h" // nested classes
+
+#if defined(OS_MACOSX)
+struct FontDescriptor;
+#endif
+
+namespace appcache {
+struct AppCacheInfo;
+struct AppCacheResourceInfo;
+}
namespace base {
class Time;
}
-class SkBitmap;
-
-// Parameters structure for ViewMsg_Navigate, which has too many data
-// parameters to be reasonably put in a predefined IPC message.
-struct ViewMsg_Navigate_Params {
- enum NavigationType {
- // Reload the page.
- RELOAD,
-
- // Reload the page, ignoring any cache entries.
- RELOAD_IGNORING_CACHE,
-
- // The navigation is the result of session restore and should honor the
- // page's cache policy while restoring form state. This is set to true if
- // restoring a tab/session from the previous session and the previous
- // session did not crash. If this is not set and the page was restored then
- // the page's cache policy is ignored and we load from the cache.
- RESTORE,
-
- // Navigation type not categorized by the other types.
- NORMAL
- };
-
- // The page_id for this navigation, or -1 if it is a new navigation. Back,
- // Forward, and Reload navigations should have a valid page_id. If the load
- // succeeds, then this page_id will be reflected in the resultant
- // ViewHostMsg_FrameNavigate message.
- int32 page_id;
-
- // If page_id is -1, then pending_history_list_offset will also be -1.
- // Otherwise, it contains the offset into the history list corresponding to
- // the current navigation.
- int pending_history_list_offset;
-
- // Informs the RenderView of where its current page contents reside in
- // session history and the total size of the session history list.
- int current_history_list_offset;
- int current_history_list_length;
-
- // The URL to load.
- GURL url;
-
- // The URL to send in the "Referer" header field. Can be empty if there is
- // no referrer.
- GURL referrer;
-
- // The type of transition.
- PageTransition::Type transition;
-
- // Opaque history state (received by ViewHostMsg_UpdateState).
- std::string state;
-
- // Type of navigation.
- NavigationType navigation_type;
-
- // The time the request was created
- base::Time request_time;
-};
-
-// Current status of the audio output stream in the browser process. Browser
-// sends information about the current playback state and error to the
-// renderer process using this type.
-struct ViewMsg_AudioStreamState_Params {
- enum State {
- kPlaying,
- kPaused,
- kError
- };
-
- // Carries the current playback state.
- State state;
-};
-
-// The user has completed a find-in-page; this type defines what actions the
-// renderer should take next.
-struct ViewMsg_StopFinding_Params {
- enum Action {
- kClearSelection,
- kKeepSelection,
- kActivateSelection
- };
-
- // The action that should be taken when the find is completed.
- Action action;
-};
-
-// The install state of the search provider (not installed, installed, default).
-struct ViewHostMsg_GetSearchProviderInstallState_Params {
- enum State {
- // Equates to an access denied error.
- DENIED = -1,
-
- // DON'T CHANGE THE VALUES BELOW.
- // All of the following values are manidated by the
- // spec for window.external.IsSearchProviderInstalled.
-
- // The search provider is not installed.
- NOT_INSTALLED = 0,
-
- // The search provider is in the user's set but is not
- INSTALLED_BUT_NOT_DEFAULT = 1,
-
- // The search provider is set as the user's default.
- INSTALLED_AS_DEFAULT = 2
- };
- State state;
-
- ViewHostMsg_GetSearchProviderInstallState_Params()
- : state(DENIED) {
- }
-
- explicit ViewHostMsg_GetSearchProviderInstallState_Params(State s)
- : state(s) {
- }
-
- static ViewHostMsg_GetSearchProviderInstallState_Params Denied() {
- return ViewHostMsg_GetSearchProviderInstallState_Params(DENIED);
- }
-
- static ViewHostMsg_GetSearchProviderInstallState_Params NotInstalled() {
- return ViewHostMsg_GetSearchProviderInstallState_Params(NOT_INSTALLED);
- }
-
- static ViewHostMsg_GetSearchProviderInstallState_Params
- InstallButNotDefault() {
- return ViewHostMsg_GetSearchProviderInstallState_Params(
- INSTALLED_BUT_NOT_DEFAULT);
- }
-
- static ViewHostMsg_GetSearchProviderInstallState_Params InstalledAsDefault() {
- return ViewHostMsg_GetSearchProviderInstallState_Params(
- INSTALLED_AS_DEFAULT);
- }
-};
-
-
-// Parameters structure for ViewHostMsg_FrameNavigate, which has too many data
-// parameters to be reasonably put in a predefined IPC message.
-struct ViewHostMsg_FrameNavigate_Params {
- // Page ID of this navigation. The renderer creates a new unique page ID
- // anytime a new session history entry is created. This means you'll get new
- // page IDs for user actions, and the old page IDs will be reloaded when
- // iframes are loaded automatically.
- int32 page_id;
-
- // URL of the page being loaded.
- GURL url;
-
- // URL of the referrer of this load. WebKit generates this based on the
- // source of the event that caused the load.
- GURL referrer;
-
- // The type of transition.
- PageTransition::Type transition;
-
- // Lists the redirects that occurred on the way to the current page. This
- // vector has the same format as reported by the WebDataSource in the glue,
- // with the current page being the last one in the list (so even when
- // there's no redirect, there will be one entry in the list.
- std::vector<GURL> redirects;
-
- // Set to false if we want to update the session history but not update
- // the browser history. E.g., on unreachable urls.
- bool should_update_history;
-
- // See SearchableFormData for a description of these.
- GURL searchable_form_url;
- std::string searchable_form_encoding;
-
- // See password_form.h.
- webkit_glue::PasswordForm password_form;
-
- // Information regarding the security of the connection (empty if the
- // connection was not secure).
- std::string security_info;
-
- // The gesture that initiated this navigation.
- NavigationGesture gesture;
-
- // Contents MIME type of main frame.
- std::string contents_mime_type;
-
- // True if this was a post request.
- bool is_post;
-
- // Whether the content of the frame was replaced with some alternate content
- // (this can happen if the resource was insecure).
- bool is_content_filtered;
-
- // The status code of the HTTP request.
- int http_status_code;
-};
-
-// Values that may be OR'd together to form the 'flags' parameter of a
-// ViewHostMsg_UpdateRect_Params structure.
-struct ViewHostMsg_UpdateRect_Flags {
- enum {
- IS_RESIZE_ACK = 1 << 0,
- IS_RESTORE_ACK = 1 << 1,
- IS_REPAINT_ACK = 1 << 2,
- };
- static bool is_resize_ack(int flags) {
- return (flags & IS_RESIZE_ACK) != 0;
- }
- static bool is_restore_ack(int flags) {
- return (flags & IS_RESTORE_ACK) != 0;
- }
- static bool is_repaint_ack(int flags) {
- return (flags & IS_REPAINT_ACK) != 0;
- }
-};
-
-struct ViewHostMsg_UpdateRect_Params {
- // The bitmap to be painted into the view at the locations specified by
- // update_rects.
- TransportDIB::Id bitmap;
-
- // The position and size of the bitmap.
- gfx::Rect bitmap_rect;
-
- // The scroll offset. Only one of these can be non-zero, and if they are
- // both zero, then it means there is no scrolling and the scroll_rect is
- // ignored.
- int dx;
- int dy;
-
- // The rectangular region to scroll.
- gfx::Rect scroll_rect;
-
- // The regions of the bitmap (in view coords) that contain updated pixels.
- // In the case of scrolling, this includes the scroll damage rect.
- std::vector<gfx::Rect> copy_rects;
-
- // The size of the RenderView when this message was generated. This is
- // included so the host knows how large the view is from the perspective of
- // the renderer process. This is necessary in case a resize operation is in
- // progress.
- gfx::Size view_size;
-
- // New window locations for plugin child windows.
- std::vector<webkit_glue::WebPluginGeometry> plugin_window_moves;
-
- // The following describes the various bits that may be set in flags:
- //
- // ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK
- // Indicates that this is a response to a ViewMsg_Resize message.
- //
- // ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK
- // Indicates that this is a response to a ViewMsg_WasRestored message.
- //
- // ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK
- // Indicates that this is a response to a ViewMsg_Repaint message.
- //
- // If flags is zero, then this message corresponds to an unsoliticed paint
- // request by the render view. Any of the above bits may be set in flags,
- // which would indicate that this paint message is an ACK for multiple
- // request messages.
- int flags;
-};
-
-// Information on closing a tab. This is used both for ViewMsg_ClosePage, and
-// the corresponding ViewHostMsg_ClosePage_ACK.
-struct ViewMsg_ClosePage_Params {
- // The identifier of the RenderProcessHost for the currently closing view.
- //
- // These first two parameters are technically redundant since they are
- // needed only when processing the ACK message, and the processor
- // theoretically knows both the process and route ID. However, this is
- // difficult to figure out with our current implementation, so this
- // information is duplicate here.
- int closing_process_id;
-
- // The route identifier for the currently closing RenderView.
- int closing_route_id;
-
- // True when this close is for the first (closing) tab of a cross-site
- // transition where we switch processes. False indicates the close is for the
- // entire tab.
- //
- // When true, the new_* variables below must be filled in. Otherwise they must
- // both be -1.
- bool for_cross_site_transition;
-
- // The identifier of the RenderProcessHost for the new view attempting to
- // replace the closing one above. This must be valid when
- // for_cross_site_transition is set, and must be -1 otherwise.
- int new_render_process_host_id;
-
- // The identifier of the *request* the new view made that is causing the
- // cross-site transition. This is *not* a route_id, but the request that we
- // will resume once the ACK from the closing view has been received. This
- // must be valid when for_cross_site_transition is set, and must be -1
- // otherwise.
- int new_request_id;
-};
-
-// Parameters for a resource request.
-struct ViewHostMsg_Resource_Request {
- // The request method: GET, POST, etc.
- std::string method;
-
- // The requested URL.
- GURL url;
-
- // Usually the URL of the document in the top-level window, which may be
- // checked by the third-party cookie blocking policy. Leaving it empty may
- // lead to undesired cookie blocking. Third-party cookie blocking can be
- // bypassed by setting first_party_for_cookies = url, but this should ideally
- // only be done if there really is no way to determine the correct value.
- GURL first_party_for_cookies;
-
- // The referrer to use (may be empty).
- GURL referrer;
-
- // The origin of the frame that is associated with this request. This is used
- // to update our insecure content state.
- std::string frame_origin;
-
- // The origin of the main frame (top-level frame) that is associated with this
- // request. This is used to update our insecure content state.
- std::string main_frame_origin;
-
- // Additional HTTP request headers.
- std::string headers;
-
- // URLRequest load flags (0 by default).
- int load_flags;
-
- // Unique ID of process that originated this request. For normal renderer
- // requests, this will be the ID of the renderer. For plugin requests routed
- // through the renderer, this will be the plugin's ID.
- int origin_child_id;
-
- // What this resource load is for (main frame, sub-frame, sub-resource,
- // object).
- ResourceType::Type resource_type;
-
- // Used by plugin->browser requests to get the correct URLRequestContext.
- uint32 request_context;
-
- // Indicates which frame (or worker context) the request is being loaded into,
- // or kNoHostId.
- int appcache_host_id;
-
- // Optional upload data (may be null).
- scoped_refptr<net::UploadData> upload_data;
-
- // The following two members are specified if the request is initiated by
- // a plugin like Gears.
-
- // Contains the id of the host renderer.
- int host_renderer_id;
-
- // Contains the id of the host render view.
- int host_render_view_id;
-};
-
-// Parameters for a render request.
-struct ViewMsg_Print_Params {
- // Physical size of the page, including non-printable margins,
- // in pixels according to dpi.
- gfx::Size page_size;
-
- // In pixels according to dpi_x and dpi_y.
- gfx::Size printable_size;
-
- // The y-offset of the printable area, in pixels according to dpi.
- int margin_top;
-
- // The x-offset of the printable area, in pixels according to dpi.
- int margin_left;
-
- // Specifies dots per inch.
- double dpi;
-
- // Minimum shrink factor. See PrintSettings::min_shrink for more information.
- double min_shrink;
-
- // Maximum shrink factor. See PrintSettings::max_shrink for more information.
- double max_shrink;
-
- // Desired apparent dpi on paper.
- int desired_dpi;
-
- // Cookie for the document to ensure correctness.
- int document_cookie;
-
- // Should only print currently selected text.
- bool selection_only;
-
- // Warning: do not compare document_cookie.
- bool Equals(const ViewMsg_Print_Params& rhs) const {
- return page_size == rhs.page_size &&
- printable_size == rhs.printable_size &&
- margin_top == rhs.margin_top &&
- margin_left == rhs.margin_left &&
- dpi == rhs.dpi &&
- min_shrink == rhs.min_shrink &&
- max_shrink == rhs.max_shrink &&
- desired_dpi == rhs.desired_dpi &&
- selection_only == rhs.selection_only;
- }
-
- // Checking if the current params is empty. Just initialized after a memset.
- bool IsEmpty() const {
- return !document_cookie && !desired_dpi && !max_shrink && !min_shrink &&
- !dpi && printable_size.IsEmpty() && !selection_only &&
- page_size.IsEmpty() && !margin_top && !margin_left;
- }
-};
-
-struct ViewMsg_PrintPage_Params {
- // Parameters to render the page as a printed page. It must always be the same
- // value for all the document.
- ViewMsg_Print_Params params;
-
- // The page number is the indicator of the square that should be rendered
- // according to the layout specified in ViewMsg_Print_Params.
- int page_number;
-};
-
-struct ViewMsg_PrintPages_Params {
- // Parameters to render the page as a printed page. It must always be the same
- // value for all the document.
- ViewMsg_Print_Params params;
-
- // If empty, this means a request to render all the printed pages.
- std::vector<int> pages;
-};
-
-// Parameters to describe a rendered page.
-struct ViewHostMsg_DidPrintPage_Params {
- // A shared memory handle to the EMF data. This data can be quite large so a
- // memory map needs to be used.
- base::SharedMemoryHandle metafile_data_handle;
-
- // Size of the metafile data.
- uint32 data_size;
-
- // Cookie for the document to ensure correctness.
- int document_cookie;
-
- // Page number.
- int page_number;
-
- // Shrink factor used to render this page.
- double actual_shrink;
-
- // The size of the page the page author specified.
- gfx::Size page_size;
-
- // The printable area the page author specified.
- gfx::Rect content_area;
-
- // True if the page has visible overlays.
- bool has_visible_overlays;
-};
-
-// Parameters for creating an audio output stream.
-struct ViewHostMsg_Audio_CreateStream_Params {
- // Format request for the stream.
- AudioManager::Format format;
-
- // Number of channels.
- int channels;
-
- // Sampling rate (frequency) of the output stream.
- int sample_rate;
-
- // Number of bits per sample;
- int bits_per_sample;
-
- // Number of bytes per packet. Determines the maximum number of bytes
- // transported for each audio packet request.
- // A value of 0 means that the audio packet size is selected automatically
- // by the browser process.
- uint32 packet_size;
-};
-
-// This message is used for supporting popup menus on Mac OS X using native
-// Cocoa controls. The renderer sends us this message which we use to populate
-// the popup menu.
-struct ViewHostMsg_ShowPopup_Params {
- // Position on the screen.
- gfx::Rect bounds;
-
- // The height of each item in the menu.
- int item_height;
-
- // The size of the font to use for those items.
- double item_font_size;
-
- // The currently selected (displayed) item in the menu.
- int selected_item;
-
- // The entire list of items in the popup menu.
- std::vector<WebMenuItem> popup_items;
-
- // Whether items should be right-aligned.
- bool right_aligned;
-};
-
-// Parameters for the IPC message ViewHostMsg_ScriptedPrint
-struct ViewHostMsg_ScriptedPrint_Params {
- int routing_id;
- gfx::NativeViewId host_window_id;
- int cookie;
- int expected_pages_count;
- bool has_selection;
- bool use_overlays;
-};
-
-// Signals a storage event.
-struct 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_IndexedDatabaseOpen_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_;
-};
-
-// Used to create an object store.
-struct ViewHostMsg_IDBDatabaseCreateObjectStore_Params {
- // The response should have this id.
- int32 response_id_;
-
- // 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 database the object store belongs to.
- int32 idb_database_id_;
-};
-
-// Used to create an index.
-struct ViewHostMsg_IDBObjectStoreCreateIndex_Params {
- // The response should have this id.
- int32 response_id_;
-
- // 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 object store the index belongs to.
- int32 idb_object_store_id_;
-};
-
-// Allows an extension to execute code in a tab.
-struct ViewMsg_ExecuteCode_Params {
- ViewMsg_ExecuteCode_Params() {}
- ViewMsg_ExecuteCode_Params(int request_id, const std::string& extension_id,
- const std::vector<URLPattern>& host_permissions,
- bool is_javascript, const std::string& code,
- bool all_frames)
- : request_id(request_id), extension_id(extension_id),
- host_permissions(host_permissions), is_javascript(is_javascript),
- code(code), all_frames(all_frames) {
- }
-
- // The extension API request id, for responding.
- int request_id;
-
- // The ID of the requesting extension. To know which isolated world to
- // execute the code inside of.
- std::string extension_id;
-
- // The host permissions of the requesting extension. So that we can check them
- // right before injecting, to avoid any race conditions.
- std::vector<URLPattern> host_permissions;
-
- // Whether the code is JavaScript or CSS.
- bool is_javascript;
-
- // String of code to execute.
- std::string code;
-
- // Whether to inject into all frames, or only the root frame.
- bool all_frames;
-};
-
-// Parameters for the message that creates a worker thread.
-struct ViewHostMsg_CreateWorker_Params {
- // URL for the worker script.
- GURL url;
-
- // True if this is a SharedWorker, false if it is a dedicated Worker.
- bool is_shared;
-
- // Name for a SharedWorker, otherwise empty string.
- string16 name;
-
- // The ID of the parent document (unique within parent renderer).
- unsigned long long document_id;
-
- // RenderView routing id used to send messages back to the parent.
- int render_view_route_id;
-
- // The route ID to associate with the worker. If MSG_ROUTING_NONE is passed,
- // a new unique ID is created and assigned to the worker.
- int route_id;
-
- // The ID of the parent's appcache host, only valid for dedicated workers.
- int parent_appcache_host_id;
-
- // The ID of the appcache the main shared worker script resource was loaded
- // from, only valid for shared workers.
- int64 script_resource_appcache_id;
-};
-
-// Parameters for the message that creates a desktop notification.
-struct ViewHostMsg_ShowNotification_Params {
- // URL which is the origin that created this notification.
- GURL origin;
-
- // True if this is HTML
- bool is_html;
-
- // URL which contains the HTML contents (if is_html is true), otherwise empty.
- GURL contents_url;
-
- // Contents of the notification if is_html is false.
- GURL icon_url;
- string16 title;
- string16 body;
-
- // Directionality of the notification.
- WebKit::WebTextDirection direction;
-
- // ReplaceID if this notification should replace an existing one; may be
- // empty if no replacement is called for.
- string16 replace_id;
-
- // Notification ID for sending events back for this notification.
- int notification_id;
-};
-
-// Creates a new view via a control message since the view doesn't yet exist.
-struct ViewMsg_New_Params {
- // The parent window's id.
- gfx::NativeViewId parent_window;
-
- // Renderer-wide preferences.
- RendererPreferences renderer_preferences;
-
- // Preferences for this view.
- WebPreferences web_preferences;
-
- // The ID of the view to be created.
- int32 view_id;
-
- // The session storage namespace ID this view should use.
- int64 session_storage_namespace_id;
-
- // The name of the frame associated with this view (or empty if none).
- string16 frame_name;
-};
-
-struct ViewHostMsg_CreateWindow_Params {
- // Routing ID of the view initiating the open.
- int opener_id;
-
- // True if this open request came in the context of a user gesture.
- bool user_gesture;
-
- // Type of window requested.
- WindowContainerType window_container_type;
-
- // The session storage namespace ID this view should use.
- int64 session_storage_namespace_id;
-
- // The name of the resulting frame that should be created (empty if none
- // has been specified).
- string16 frame_name;
-};
-
-struct ViewHostMsg_RunFileChooser_Params {
- enum Mode {
- // Requires that the file exists before allowing the user to pick it.
- Open,
-
- // Like Open, but allows picking multiple files to open.
- OpenMultiple,
-
- // Allows picking a nonexistent file, and prompts to overwrite if the file
- // already exists.
- Save,
- };
-
- Mode mode;
-
- // Title to be used for the dialog. This may be empty for the default title,
- // which will be either "Open" or "Save" depending on the mode.
- string16 title;
-
- // Default file name to select in the dialog.
- FilePath default_file_name;
-};
+namespace net {
+class HttpResponseHeaders;
+class UploadData;
+}
-struct ViewMsg_ExtensionExtentInfo {
- std::string extension_id;
- ExtensionExtent web_extent;
- ExtensionExtent browse_extent;
-};
+namespace webkit_glue {
+struct FormData;
+class FormField;
+struct PasswordFormFillData;
+struct WebAccessibility;
+struct WebCookie;
+struct WebPluginGeometry;
+struct WebAccessibility;
+}
-struct ViewMsg_ExtensionExtentsUpdated_Params {
- // Describes the installed extension apps and the URLs they cover.
- std::vector<ViewMsg_ExtensionExtentInfo> extension_apps;
-};
+class ExtensionExtent;
+class GURL;
+class SkBitmap;
+class URLPattern;
+struct ContextMenuParams;
+struct EditCommand;
+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
+// of parameters.
+struct ViewMsg_Navigate_Params;
+struct ViewMsg_AudioStreamState_Params;
+struct ViewMsg_StopFinding_Params;
+struct ViewHostMsg_GetSearchProviderInstallState_Params;
+struct ViewHostMsg_FrameNavigate_Params;
+struct ViewHostMsg_UpdateRect_Params;
+struct ViewMsg_ClosePage_Params;
+struct ViewHostMsg_Resource_Request;
+struct ViewMsg_Print_Params;
+struct ViewMsg_PrintPage_Params;
+struct ViewMsg_PrintPages_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;
+struct ViewMsg_New_Params;
+struct ViewHostMsg_CreateWindow_Params;
+struct ViewHostMsg_RunFileChooser_Params;
+struct ViewMsg_ExtensionRendererInfo;
+struct ViewMsg_ExtensionsUpdated_Params;
+struct ViewMsg_DeviceOrientationUpdated_Params;
+struct ViewHostMsg_DomMessage_Params;
+struct ViewHostMsg_AccessibilityNotification_Params;
// Values that may be OR'd together to form the 'flags' parameter of the
// ViewMsg_EnablePreferredSizeChangedMode message.
@@ -821,688 +121,74 @@ enum ViewHostMsg_EnablePreferredSizeChangedMode_Flags {
namespace IPC {
-template <>
-struct ParamTraits<ResourceType::Type> {
- typedef ResourceType::Type 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) || !ResourceType::ValidType(type))
- return false;
- *p = ResourceType::FromInt(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring type;
- switch (p) {
- case ResourceType::MAIN_FRAME:
- type = L"MAIN_FRAME";
- break;
- case ResourceType::SUB_FRAME:
- type = L"SUB_FRAME";
- break;
- case ResourceType::SUB_RESOURCE:
- type = L"SUB_RESOURCE";
- break;
- case ResourceType::OBJECT:
- type = L"OBJECT";
- break;
- case ResourceType::MEDIA:
- type = L"MEDIA";
- break;
- default:
- type = L"UNKNOWN";
- break;
- }
-
- LogParam(type, l);
- }
-};
-
-// Traits for ViewMsg_Navigate_Params structure to pack/unpack.
-template <>
-struct ParamTraits<ViewMsg_Navigate_Params> {
- typedef ViewMsg_Navigate_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.page_id);
- WriteParam(m, p.pending_history_list_offset);
- WriteParam(m, p.current_history_list_offset);
- WriteParam(m, p.current_history_list_length);
- WriteParam(m, p.url);
- WriteParam(m, p.referrer);
- WriteParam(m, p.transition);
- WriteParam(m, p.state);
- WriteParam(m, p.navigation_type);
- WriteParam(m, p.request_time);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->page_id) &&
- ReadParam(m, iter, &p->pending_history_list_offset) &&
- ReadParam(m, iter, &p->current_history_list_offset) &&
- ReadParam(m, iter, &p->current_history_list_length) &&
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->referrer) &&
- ReadParam(m, iter, &p->transition) &&
- ReadParam(m, iter, &p->state) &&
- ReadParam(m, iter, &p->navigation_type) &&
- ReadParam(m, iter, &p->request_time);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.page_id, l);
- l->append(L", ");
- LogParam(p.url, l);
- l->append(L", ");
- LogParam(p.transition, l);
- l->append(L", ");
- LogParam(p.state, l);
- l->append(L", ");
- LogParam(p.navigation_type, l);
- l->append(L", ");
- LogParam(p.request_time, l);
- l->append(L")");
- }
-};
-
-template<>
-struct ParamTraits<ViewMsg_Navigate_Params::NavigationType> {
- typedef ViewMsg_Navigate_Params::NavigationType 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<ViewMsg_Navigate_Params::NavigationType>(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring event;
- switch (p) {
- case ViewMsg_Navigate_Params::RELOAD:
- event = L"NavigationType_RELOAD";
- break;
-
- case ViewMsg_Navigate_Params::RELOAD_IGNORING_CACHE:
- event = L"NavigationType_RELOAD_IGNORING_CACHE";
- break;
-
- case ViewMsg_Navigate_Params::RESTORE:
- event = L"NavigationType_RESTORE";
- break;
-
- case ViewMsg_Navigate_Params::NORMAL:
- event = L"NavigationType_NORMAL";
- break;
-
- default:
- event = L"NavigationType_UNKNOWN";
- break;
- }
- LogParam(event, l);
- }
-};
-
// Traits for FormField_Params structure to pack/unpack.
template <>
struct ParamTraits<webkit_glue::FormField> {
typedef webkit_glue::FormField param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.label());
- WriteParam(m, p.name());
- WriteParam(m, p.value());
- WriteParam(m, p.form_control_type());
- WriteParam(m, p.size());
- WriteParam(m, p.option_strings());
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- string16 label, name, value, form_control_type;
- int size = 0;
- std::vector<string16> options;
- bool result = ReadParam(m, iter, &label);
- result = result && ReadParam(m, iter, &name);
- result = result && ReadParam(m, iter, &value);
- result = result && ReadParam(m, iter, &form_control_type);
- result = result && ReadParam(m, iter, &size);
- result = result && ReadParam(m, iter, &options);
- if (!result)
- return false;
-
- p->set_label(label);
- p->set_name(name);
- p->set_value(value);
- p->set_form_control_type(form_control_type);
- p->set_size(size);
- p->set_option_strings(options);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<FormField>");
- }
+ 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_MACOSX)
// Traits for FontDescriptor structure to pack/unpack.
template <>
struct ParamTraits<FontDescriptor> {
typedef FontDescriptor param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.font_name);
- WriteParam(m, p.font_point_size);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return(
- ReadParam(m, iter, &p->font_name) &&
- ReadParam(m, iter, &p->font_point_size));
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<FontDescriptor>");
- }
-};
-
-// Traits for ViewHostMsg_GetSearchProviderInstallState_Params structure to
-// pack/unpack.
-template <>
-struct ParamTraits<ViewHostMsg_GetSearchProviderInstallState_Params> {
- typedef ViewHostMsg_GetSearchProviderInstallState_Params param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p.state);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- p->state = static_cast<param_type::State>(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring state;
- switch (p.state) {
- case ViewHostMsg_GetSearchProviderInstallState_Params::DENIED:
- state = L"ViewHostMsg_GetSearchProviderInstallState_Params::DENIED";
- break;
- case ViewHostMsg_GetSearchProviderInstallState_Params::NOT_INSTALLED:
- state =
- L"ViewHostMsg_GetSearchProviderInstallState_Params::NOT_INSTALLED";
- break;
- case ViewHostMsg_GetSearchProviderInstallState_Params::
- INSTALLED_BUT_NOT_DEFAULT:
- state = L"ViewHostMsg_GetSearchProviderInstallState_Params::"
- L"INSTALLED_BUT_NOT_DEFAULT";
- break;
- case ViewHostMsg_GetSearchProviderInstallState_Params::
- INSTALLED_AS_DEFAULT:
- state = L"ViewHostMsg_GetSearchProviderInstallState_Params::"
- L"INSTALLED_AS_DEFAULT";
- break;
- default:
- state = L"UNKNOWN";
- break;
- }
- LogParam(state, l);
- }
-};
-
-// Traits for ViewHostMsg_FrameNavigate_Params structure to pack/unpack.
-template <>
-struct ParamTraits<ViewHostMsg_FrameNavigate_Params> {
- typedef ViewHostMsg_FrameNavigate_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.page_id);
- WriteParam(m, p.url);
- WriteParam(m, p.referrer);
- WriteParam(m, p.transition);
- WriteParam(m, p.redirects);
- WriteParam(m, p.should_update_history);
- WriteParam(m, p.searchable_form_url);
- WriteParam(m, p.searchable_form_encoding);
- WriteParam(m, p.password_form);
- WriteParam(m, p.security_info);
- WriteParam(m, p.gesture);
- WriteParam(m, p.contents_mime_type);
- WriteParam(m, p.is_post);
- WriteParam(m, p.is_content_filtered);
- WriteParam(m, p.http_status_code);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->page_id) &&
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->referrer) &&
- ReadParam(m, iter, &p->transition) &&
- ReadParam(m, iter, &p->redirects) &&
- ReadParam(m, iter, &p->should_update_history) &&
- ReadParam(m, iter, &p->searchable_form_url) &&
- ReadParam(m, iter, &p->searchable_form_encoding) &&
- ReadParam(m, iter, &p->password_form) &&
- ReadParam(m, iter, &p->security_info) &&
- ReadParam(m, iter, &p->gesture) &&
- ReadParam(m, iter, &p->contents_mime_type) &&
- ReadParam(m, iter, &p->is_post) &&
- ReadParam(m, iter, &p->is_content_filtered) &&
- ReadParam(m, iter, &p->http_status_code);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.page_id, l);
- l->append(L", ");
- LogParam(p.url, l);
- l->append(L", ");
- LogParam(p.referrer, l);
- l->append(L", ");
- LogParam(p.transition, l);
- l->append(L", ");
- LogParam(p.redirects, l);
- l->append(L", ");
- LogParam(p.should_update_history, l);
- l->append(L", ");
- LogParam(p.searchable_form_url, l);
- l->append(L", ");
- LogParam(p.searchable_form_encoding, l);
- l->append(L", ");
- LogParam(p.password_form, l);
- l->append(L", ");
- LogParam(p.security_info, l);
- l->append(L", ");
- LogParam(p.gesture, l);
- l->append(L", ");
- LogParam(p.contents_mime_type, l);
- l->append(L", ");
- LogParam(p.is_post, l);
- l->append(L", ");
- LogParam(p.is_content_filtered, l);
- l->append(L", ");
- LogParam(p.http_status_code, l);
- l->append(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);
};
+#endif
template <>
struct ParamTraits<ContextMenuParams> {
typedef ContextMenuParams param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.media_type);
- WriteParam(m, p.x);
- WriteParam(m, p.y);
- WriteParam(m, p.link_url);
- WriteParam(m, p.unfiltered_link_url);
- WriteParam(m, p.src_url);
- WriteParam(m, p.is_image_blocked);
- WriteParam(m, p.page_url);
- WriteParam(m, p.frame_url);
- WriteParam(m, p.media_flags);
- WriteParam(m, p.selection_text);
- WriteParam(m, p.misspelled_word);
- WriteParam(m, p.dictionary_suggestions);
- WriteParam(m, p.spellcheck_enabled);
- WriteParam(m, p.is_editable);
-#if defined(OS_MACOSX)
- WriteParam(m, p.writing_direction_default);
- WriteParam(m, p.writing_direction_left_to_right);
- WriteParam(m, p.writing_direction_right_to_left);
-#endif // OS_MACOSX
- WriteParam(m, p.edit_flags);
- WriteParam(m, p.security_info);
- WriteParam(m, p.frame_charset);
- WriteParam(m, p.custom_items);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->media_type) &&
- ReadParam(m, iter, &p->x) &&
- ReadParam(m, iter, &p->y) &&
- ReadParam(m, iter, &p->link_url) &&
- ReadParam(m, iter, &p->unfiltered_link_url) &&
- ReadParam(m, iter, &p->src_url) &&
- ReadParam(m, iter, &p->is_image_blocked) &&
- ReadParam(m, iter, &p->page_url) &&
- ReadParam(m, iter, &p->frame_url) &&
- ReadParam(m, iter, &p->media_flags) &&
- ReadParam(m, iter, &p->selection_text) &&
- ReadParam(m, iter, &p->misspelled_word) &&
- ReadParam(m, iter, &p->dictionary_suggestions) &&
- ReadParam(m, iter, &p->spellcheck_enabled) &&
- ReadParam(m, iter, &p->is_editable) &&
-#if defined(OS_MACOSX)
- ReadParam(m, iter, &p->writing_direction_default) &&
- ReadParam(m, iter, &p->writing_direction_left_to_right) &&
- ReadParam(m, iter, &p->writing_direction_right_to_left) &&
-#endif // OS_MACOSX
- ReadParam(m, iter, &p->edit_flags) &&
- ReadParam(m, iter, &p->security_info) &&
- ReadParam(m, iter, &p->frame_charset) &&
- ReadParam(m, iter, &p->custom_items);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<ContextMenuParams>");
- }
-};
-
-// Traits for ViewHostMsg_UpdateRect_Params structure to pack/unpack.
-template <>
-struct ParamTraits<ViewHostMsg_UpdateRect_Params> {
- typedef ViewHostMsg_UpdateRect_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.bitmap);
- WriteParam(m, p.bitmap_rect);
- WriteParam(m, p.dx);
- WriteParam(m, p.dy);
- WriteParam(m, p.scroll_rect);
- WriteParam(m, p.copy_rects);
- WriteParam(m, p.view_size);
- WriteParam(m, p.plugin_window_moves);
- WriteParam(m, p.flags);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->bitmap) &&
- ReadParam(m, iter, &p->bitmap_rect) &&
- ReadParam(m, iter, &p->dx) &&
- ReadParam(m, iter, &p->dy) &&
- ReadParam(m, iter, &p->scroll_rect) &&
- ReadParam(m, iter, &p->copy_rects) &&
- ReadParam(m, iter, &p->view_size) &&
- ReadParam(m, iter, &p->plugin_window_moves) &&
- ReadParam(m, iter, &p->flags);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.bitmap, l);
- l->append(L", ");
- LogParam(p.bitmap_rect, l);
- l->append(L", ");
- LogParam(p.dx, l);
- l->append(L", ");
- LogParam(p.dy, l);
- l->append(L", ");
- LogParam(p.scroll_rect, l);
- l->append(L", ");
- LogParam(p.copy_rects, l);
- l->append(L", ");
- LogParam(p.view_size, l);
- l->append(L", ");
- LogParam(p.plugin_window_moves, l);
- l->append(L", ");
- LogParam(p.flags, l);
- l->append(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<webkit_glue::WebPluginGeometry> {
typedef webkit_glue::WebPluginGeometry param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.window);
- WriteParam(m, p.window_rect);
- WriteParam(m, p.clip_rect);
- WriteParam(m, p.cutout_rects);
- WriteParam(m, p.rects_valid);
- WriteParam(m, p.visible);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->window) &&
- ReadParam(m, iter, &p->window_rect) &&
- ReadParam(m, iter, &p->clip_rect) &&
- ReadParam(m, iter, &p->cutout_rects) &&
- ReadParam(m, iter, &p->rects_valid) &&
- ReadParam(m, iter, &p->visible);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.window, l);
- l->append(L", ");
- LogParam(p.window_rect, l);
- l->append(L", ");
- LogParam(p.clip_rect, l);
- l->append(L", ");
- LogParam(p.cutout_rects, l);
- l->append(L", ");
- LogParam(p.rects_valid, l);
- l->append(L", ");
- LogParam(p.visible, l);
- l->append(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);
};
// Traits for ViewMsg_GetPlugins_Reply structure to pack/unpack.
template <>
struct ParamTraits<WebPluginMimeType> {
typedef WebPluginMimeType param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.mime_type);
- WriteParam(m, p.file_extensions);
- WriteParam(m, p.description);
- }
- static bool 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);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.mime_type, l);
- l->append(L", ");
- LogParam(p.file_extensions, l);
- l->append(L", ");
- LogParam(p.description, l);
- l->append(L")");
- }
+ 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;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.name);
- WriteParam(m, p.path);
- WriteParam(m, p.version);
- WriteParam(m, p.desc);
- WriteParam(m, p.mime_types);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- return
- ReadParam(m, iter, &r->name) &&
- ReadParam(m, iter, &r->path) &&
- ReadParam(m, iter, &r->version) &&
- ReadParam(m, iter, &r->desc) &&
- ReadParam(m, iter, &r->mime_types);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.name, l);
- l->append(L", ");
- l->append(L", ");
- LogParam(p.path, l);
- l->append(L", ");
- LogParam(p.version, l);
- l->append(L", ");
- LogParam(p.desc, l);
- l->append(L", ");
- LogParam(p.mime_types, l);
- l->append(L")");
- }
+ 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);
};
// Traits for webkit_glue::PasswordFormDomManager::FillData.
template <>
struct ParamTraits<webkit_glue::PasswordFormFillData> {
typedef webkit_glue::PasswordFormFillData param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.basic_data);
- WriteParam(m, p.additional_logins);
- WriteParam(m, p.wait_for_username);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- return
- ReadParam(m, iter, &r->basic_data) &&
- ReadParam(m, iter, &r->additional_logins) &&
- ReadParam(m, iter, &r->wait_for_username);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<PasswordFormFillData>");
- }
-};
-
-template<>
-struct ParamTraits<NavigationGesture> {
- typedef NavigationGesture 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<NavigationGesture>(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring event;
- switch (p) {
- case NavigationGestureUser:
- event = L"GESTURE_USER";
- break;
- case NavigationGestureAuto:
- event = L"GESTURE_AUTO";
- break;
- default:
- event = L"GESTURE_UNKNOWN";
- break;
- }
- LogParam(event, l);
- }
-};
-
-// Traits for ViewMsg_Close_Params.
-template <>
-struct ParamTraits<ViewMsg_ClosePage_Params> {
- typedef ViewMsg_ClosePage_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.closing_process_id);
- WriteParam(m, p.closing_route_id);
- WriteParam(m, p.for_cross_site_transition);
- WriteParam(m, p.new_render_process_host_id);
- WriteParam(m, p.new_request_id);
- }
-
- static bool Read(const Message* m, void** iter, param_type* r) {
- return ReadParam(m, iter, &r->closing_process_id) &&
- ReadParam(m, iter, &r->closing_route_id) &&
- ReadParam(m, iter, &r->for_cross_site_transition) &&
- ReadParam(m, iter, &r->new_render_process_host_id) &&
- ReadParam(m, iter, &r->new_request_id);
- }
-
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.closing_process_id, l);
- l->append(L", ");
- LogParam(p.closing_route_id, l);
- l->append(L", ");
- LogParam(p.for_cross_site_transition, l);
- l->append(L", ");
- LogParam(p.new_render_process_host_id, l);
- l->append(L", ");
- LogParam(p.new_request_id, l);
- l->append(L")");
- }
-};
-
-// Traits for ViewHostMsg_Resource_Request
-template <>
-struct ParamTraits<ViewHostMsg_Resource_Request> {
- typedef ViewHostMsg_Resource_Request param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.method);
- WriteParam(m, p.url);
- WriteParam(m, p.first_party_for_cookies);
- WriteParam(m, p.referrer);
- WriteParam(m, p.frame_origin);
- WriteParam(m, p.main_frame_origin);
- WriteParam(m, p.headers);
- WriteParam(m, p.load_flags);
- WriteParam(m, p.origin_child_id);
- WriteParam(m, p.resource_type);
- WriteParam(m, p.request_context);
- WriteParam(m, p.appcache_host_id);
- WriteParam(m, p.upload_data);
- WriteParam(m, p.host_renderer_id);
- WriteParam(m, p.host_render_view_id);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- return
- ReadParam(m, iter, &r->method) &&
- ReadParam(m, iter, &r->url) &&
- ReadParam(m, iter, &r->first_party_for_cookies) &&
- ReadParam(m, iter, &r->referrer) &&
- ReadParam(m, iter, &r->frame_origin) &&
- ReadParam(m, iter, &r->main_frame_origin) &&
- ReadParam(m, iter, &r->headers) &&
- ReadParam(m, iter, &r->load_flags) &&
- ReadParam(m, iter, &r->origin_child_id) &&
- ReadParam(m, iter, &r->resource_type) &&
- ReadParam(m, iter, &r->request_context) &&
- ReadParam(m, iter, &r->appcache_host_id) &&
- ReadParam(m, iter, &r->upload_data) &&
- ReadParam(m, iter, &r->host_renderer_id) &&
- ReadParam(m, iter, &r->host_render_view_id);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.method, l);
- l->append(L", ");
- LogParam(p.url, l);
- l->append(L", ");
- LogParam(p.referrer, l);
- l->append(L", ");
- LogParam(p.frame_origin, l);
- l->append(L", ");
- LogParam(p.main_frame_origin, l);
- l->append(L", ");
- LogParam(p.load_flags, l);
- l->append(L", ");
- LogParam(p.origin_child_id, l);
- l->append(L", ");
- LogParam(p.resource_type, l);
- l->append(L", ");
- LogParam(p.request_context, l);
- l->append(L", ");
- LogParam(p.appcache_host_id, l);
- l->append(L", ");
- LogParam(p.host_renderer_id, l);
- l->append(L", ");
- LogParam(p.host_render_view_id, l);
- l->append(L")");
- }
+ 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<scoped_refptr<net::HttpResponseHeaders> > {
typedef scoped_refptr<net::HttpResponseHeaders> param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.get() != NULL);
- if (p) {
- // Do not disclose Set-Cookie headers over IPC.
- p->Persist(m, net::HttpResponseHeaders::PERSIST_SANS_COOKIES);
- }
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- bool has_object;
- if (!ReadParam(m, iter, &has_object))
- return false;
- if (has_object)
- *r = new net::HttpResponseHeaders(*m, iter);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<HttpResponseHeaders>");
- }
+ 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);
};
// Traits for webkit_glue::ResourceLoaderBridge::LoadTimingInfo
@@ -1549,34 +235,34 @@ struct ParamTraits<webkit_glue::ResourceLoaderBridge::LoadTimingInfo> {
ReadParam(m, iter, &r->receive_headers_start) &&
ReadParam(m, iter, &r->receive_headers_end);
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.base_time, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.proxy_start, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.proxy_end, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.dns_start, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.dns_end, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.connect_start, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.connect_end, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.ssl_start, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.ssl_end, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.send_start, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.send_end, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.receive_headers_start, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.receive_headers_end, l);
- l->append(L")");
+ l->append(")");
}
};
@@ -1597,6 +283,7 @@ struct ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo> {
WriteParam(m, p.connection_id);
WriteParam(m, p.connection_reused);
WriteParam(m, p.load_timing);
+ WriteParam(m, p.download_file_path);
WriteParam(m, p.was_fetched_via_spdy);
WriteParam(m, p.was_npn_negotiated);
WriteParam(m, p.was_alternate_protocol_available);
@@ -1616,45 +303,48 @@ struct ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo> {
ReadParam(m, iter, &r->connection_id) &&
ReadParam(m, iter, &r->connection_reused) &&
ReadParam(m, iter, &r->load_timing) &&
+ ReadParam(m, iter, &r->download_file_path) &&
ReadParam(m, iter, &r->was_fetched_via_spdy) &&
ReadParam(m, iter, &r->was_npn_negotiated) &&
ReadParam(m, iter, &r->was_alternate_protocol_available) &&
ReadParam(m, iter, &r->was_fetched_via_proxy);
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.request_time, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.response_time, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.headers, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.mime_type, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.charset, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.security_info, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.content_length, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.appcache_id, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.appcache_manifest_url, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.connection_id, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.connection_reused, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.load_timing, l);
- l->append(L", ");
+ l->append(", ");
+ LogParam(p.download_file_path, l);
+ l->append(", ");
LogParam(p.was_fetched_via_spdy, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.was_npn_negotiated, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.was_alternate_protocol_available, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.was_fetched_via_proxy, l);
- l->append(L")");
+ l->append(")");
}
};
@@ -1672,7 +362,7 @@ struct ParamTraits<ResourceResponseHead> {
ReadParam(m, iter, &r->status) &&
ReadParam(m, iter, &r->replace_extension_localization_templates);
}
- static void Log(const param_type& p, std::wstring* l) {
+ static void Log(const param_type& p, std::string* l) {
// log more?
ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo>::Log(p, l);
}
@@ -1692,211 +382,19 @@ struct ParamTraits<SyncLoadResult> {
ReadParam(m, iter, &r->final_url) &&
ReadParam(m, iter, &r->data);
}
- static void Log(const param_type& p, std::wstring* l) {
+ static void Log(const param_type& p, std::string* l) {
// log more?
ParamTraits<webkit_glue::ResourceLoaderBridge::ResponseInfo>::Log(p, l);
}
};
-template <>
-struct ParamTraits<SerializedScriptValue> {
- typedef SerializedScriptValue param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.is_null());
- WriteParam(m, p.is_invalid());
- WriteParam(m, p.data());
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- bool is_null;
- bool is_invalid;
- string16 data;
- bool ok =
- ReadParam(m, iter, &is_null) &&
- ReadParam(m, iter, &is_invalid) &&
- ReadParam(m, iter, &data);
- if (!ok)
- return false;
- r->set_is_null(is_null);
- r->set_is_invalid(is_invalid);
- r->set_data(data);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<SerializedScriptValue>(");
- LogParam(p.is_null(), l);
- l->append(L", ");
- LogParam(p.is_invalid(), l);
- l->append(L", ");
- LogParam(p.data(), l);
- l->append(L")");
- }
-};
-
-template <>
-struct ParamTraits<IndexedDBKey> {
- typedef IndexedDBKey param_type;
- static void 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.number());
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int type;
- string16 string;
- int32 number;
- bool ok =
- ReadParam(m, iter, &type) &&
- ReadParam(m, iter, &string) &&
- ReadParam(m, iter, &number);
- if (!ok)
- return false;
- switch (type) {
- case WebKit::WebIDBKey::NullType:
- r->SetNull();
- return true;
- case WebKit::WebIDBKey::StringType:
- r->Set(string);
- return true;
- case WebKit::WebIDBKey::NumberType:
- r->Set(number);
- return true;
- case WebKit::WebIDBKey::InvalidType:
- r->SetInvalid();
- return true;
- }
- NOTREACHED();
- return false;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<IndexedDBKey>(");
- LogParam(int(p.type()), l);
- l->append(L", ");
- LogParam(p.string(), l);
- l->append(L", ");
- LogParam(p.number(), l);
- l->append(L")");
- }
-};
-
// Traits for FormData structure to pack/unpack.
template <>
struct ParamTraits<webkit_glue::FormData> {
typedef webkit_glue::FormData param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.name);
- WriteParam(m, p.method);
- WriteParam(m, p.origin);
- WriteParam(m, p.action);
- WriteParam(m, p.fields);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->name) &&
- ReadParam(m, iter, &p->method) &&
- ReadParam(m, iter, &p->origin) &&
- ReadParam(m, iter, &p->action) &&
- ReadParam(m, iter, &p->fields);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<FormData>");
- }
-};
-
-// Traits for ViewMsg_Print_Params
-template <>
-struct ParamTraits<ViewMsg_Print_Params> {
- typedef ViewMsg_Print_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.page_size);
- WriteParam(m, p.printable_size);
- WriteParam(m, p.margin_top);
- WriteParam(m, p.margin_left);
- WriteParam(m, p.dpi);
- WriteParam(m, p.min_shrink);
- WriteParam(m, p.max_shrink);
- WriteParam(m, p.desired_dpi);
- WriteParam(m, p.document_cookie);
- WriteParam(m, p.selection_only);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->page_size) &&
- ReadParam(m, iter, &p->printable_size) &&
- ReadParam(m, iter, &p->margin_top) &&
- ReadParam(m, iter, &p->margin_left) &&
- ReadParam(m, iter, &p->dpi) &&
- ReadParam(m, iter, &p->min_shrink) &&
- ReadParam(m, iter, &p->max_shrink) &&
- ReadParam(m, iter, &p->desired_dpi) &&
- ReadParam(m, iter, &p->document_cookie) &&
- ReadParam(m, iter, &p->selection_only);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<ViewMsg_Print_Params>");
- }
-};
-
-// Traits for ViewMsg_PrintPage_Params
-template <>
-struct ParamTraits<ViewMsg_PrintPage_Params> {
- typedef ViewMsg_PrintPage_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.params);
- WriteParam(m, p.page_number);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->params) &&
- ReadParam(m, iter, &p->page_number);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<ViewMsg_PrintPage_Params>");
- }
-};
-
-// Traits for ViewMsg_PrintPages_Params
-template <>
-struct ParamTraits<ViewMsg_PrintPages_Params> {
- typedef ViewMsg_PrintPages_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.params);
- WriteParam(m, p.pages);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->params) &&
- ReadParam(m, iter, &p->pages);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<ViewMsg_PrintPages_Params>");
- }
-};
-
-// Traits for ViewHostMsg_DidPrintPage_Params
-template <>
-struct ParamTraits<ViewHostMsg_DidPrintPage_Params> {
- typedef ViewHostMsg_DidPrintPage_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.metafile_data_handle);
- WriteParam(m, p.data_size);
- WriteParam(m, p.document_cookie);
- WriteParam(m, p.page_number);
- WriteParam(m, p.actual_shrink);
- WriteParam(m, p.page_size);
- WriteParam(m, p.content_area);
- WriteParam(m, p.has_visible_overlays);
- }
- static bool 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) &&
- ReadParam(m, iter, &p->page_number) &&
- ReadParam(m, iter, &p->actual_shrink) &&
- ReadParam(m, iter, &p->page_size) &&
- ReadParam(m, iter, &p->content_area) &&
- ReadParam(m, iter, &p->has_visible_overlays);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<ViewHostMsg_DidPrintPage_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);
};
// Traits for reading/writing CSS Colors
@@ -1909,290 +407,38 @@ struct ParamTraits<CSSColors::CSSColorName> {
static bool Read(const Message* m, void** iter, param_type* p) {
return ReadParam(m, iter, reinterpret_cast<int*>(p));
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<CSSColorName>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<CSSColorName>");
}
};
-
// Traits for RendererPreferences structure to pack/unpack.
template <>
struct ParamTraits<RendererPreferences> {
typedef RendererPreferences param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.can_accept_load_drops);
- WriteParam(m, p.should_antialias_text);
- WriteParam(m, static_cast<int>(p.hinting));
- WriteParam(m, static_cast<int>(p.subpixel_rendering));
- WriteParam(m, p.focus_ring_color);
- WriteParam(m, p.thumb_active_color);
- WriteParam(m, p.thumb_inactive_color);
- WriteParam(m, p.track_color);
- WriteParam(m, p.active_selection_bg_color);
- WriteParam(m, p.active_selection_fg_color);
- WriteParam(m, p.inactive_selection_bg_color);
- WriteParam(m, p.inactive_selection_fg_color);
- WriteParam(m, p.browser_handles_top_level_requests);
- WriteParam(m, p.caret_blink_interval);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- if (!ReadParam(m, iter, &p->can_accept_load_drops))
- return false;
- if (!ReadParam(m, iter, &p->should_antialias_text))
- return false;
-
- int hinting = 0;
- if (!ReadParam(m, iter, &hinting))
- return false;
- p->hinting = static_cast<RendererPreferencesHintingEnum>(hinting);
-
- int subpixel_rendering = 0;
- if (!ReadParam(m, iter, &subpixel_rendering))
- return false;
- p->subpixel_rendering =
- static_cast<RendererPreferencesSubpixelRenderingEnum>(
- subpixel_rendering);
-
- int focus_ring_color;
- if (!ReadParam(m, iter, &focus_ring_color))
- return false;
- p->focus_ring_color = focus_ring_color;
-
- int thumb_active_color, thumb_inactive_color, track_color;
- int active_selection_bg_color, active_selection_fg_color;
- int inactive_selection_bg_color, inactive_selection_fg_color;
- if (!ReadParam(m, iter, &thumb_active_color) ||
- !ReadParam(m, iter, &thumb_inactive_color) ||
- !ReadParam(m, iter, &track_color) ||
- !ReadParam(m, iter, &active_selection_bg_color) ||
- !ReadParam(m, iter, &active_selection_fg_color) ||
- !ReadParam(m, iter, &inactive_selection_bg_color) ||
- !ReadParam(m, iter, &inactive_selection_fg_color))
- return false;
- p->thumb_active_color = thumb_active_color;
- p->thumb_inactive_color = thumb_inactive_color;
- p->track_color = track_color;
- p->active_selection_bg_color = active_selection_bg_color;
- p->active_selection_fg_color = active_selection_fg_color;
- p->inactive_selection_bg_color = inactive_selection_bg_color;
- p->inactive_selection_fg_color = inactive_selection_fg_color;
-
- if (!ReadParam(m, iter, &p->browser_handles_top_level_requests))
- return false;
-
- if (!ReadParam(m, iter, &p->caret_blink_interval))
- return false;
-
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<RendererPreferences>");
- }
+ 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 WebPreferences structure to pack/unpack.
template <>
struct ParamTraits<WebPreferences> {
typedef WebPreferences param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.standard_font_family);
- WriteParam(m, p.fixed_font_family);
- WriteParam(m, p.serif_font_family);
- WriteParam(m, p.sans_serif_font_family);
- WriteParam(m, p.cursive_font_family);
- WriteParam(m, p.fantasy_font_family);
- WriteParam(m, p.default_font_size);
- WriteParam(m, p.default_fixed_font_size);
- WriteParam(m, p.minimum_font_size);
- WriteParam(m, p.minimum_logical_font_size);
- WriteParam(m, p.default_encoding);
- WriteParam(m, p.javascript_enabled);
- WriteParam(m, p.web_security_enabled);
- WriteParam(m, p.javascript_can_open_windows_automatically);
- WriteParam(m, p.loads_images_automatically);
- WriteParam(m, p.plugins_enabled);
- WriteParam(m, p.dom_paste_enabled);
- WriteParam(m, p.developer_extras_enabled);
- WriteParam(m, p.inspector_settings);
- WriteParam(m, p.site_specific_quirks_enabled);
- WriteParam(m, p.shrinks_standalone_images_to_fit);
- WriteParam(m, p.uses_universal_detector);
- WriteParam(m, p.text_areas_are_resizable);
- WriteParam(m, p.java_enabled);
- WriteParam(m, p.allow_scripts_to_close_windows);
- WriteParam(m, p.uses_page_cache);
- WriteParam(m, p.remote_fonts_enabled);
- WriteParam(m, p.javascript_can_access_clipboard);
- WriteParam(m, p.xss_auditor_enabled);
- WriteParam(m, p.local_storage_enabled);
- WriteParam(m, p.databases_enabled);
- WriteParam(m, p.application_cache_enabled);
- WriteParam(m, p.tabs_to_links);
- WriteParam(m, p.user_style_sheet_enabled);
- WriteParam(m, p.user_style_sheet_location);
- WriteParam(m, p.author_and_user_styles_enabled);
- WriteParam(m, p.allow_universal_access_from_file_urls);
- WriteParam(m, p.allow_file_access_from_file_urls);
- WriteParam(m, p.experimental_webgl_enabled);
- WriteParam(m, p.show_composited_layer_borders);
- WriteParam(m, p.accelerated_compositing_enabled);
- WriteParam(m, p.memory_info_enabled);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->standard_font_family) &&
- ReadParam(m, iter, &p->fixed_font_family) &&
- ReadParam(m, iter, &p->serif_font_family) &&
- ReadParam(m, iter, &p->sans_serif_font_family) &&
- ReadParam(m, iter, &p->cursive_font_family) &&
- ReadParam(m, iter, &p->fantasy_font_family) &&
- ReadParam(m, iter, &p->default_font_size) &&
- ReadParam(m, iter, &p->default_fixed_font_size) &&
- ReadParam(m, iter, &p->minimum_font_size) &&
- ReadParam(m, iter, &p->minimum_logical_font_size) &&
- ReadParam(m, iter, &p->default_encoding) &&
- ReadParam(m, iter, &p->javascript_enabled) &&
- ReadParam(m, iter, &p->web_security_enabled) &&
- ReadParam(m, iter, &p->javascript_can_open_windows_automatically) &&
- ReadParam(m, iter, &p->loads_images_automatically) &&
- ReadParam(m, iter, &p->plugins_enabled) &&
- ReadParam(m, iter, &p->dom_paste_enabled) &&
- ReadParam(m, iter, &p->developer_extras_enabled) &&
- ReadParam(m, iter, &p->inspector_settings) &&
- ReadParam(m, iter, &p->site_specific_quirks_enabled) &&
- ReadParam(m, iter, &p->shrinks_standalone_images_to_fit) &&
- ReadParam(m, iter, &p->uses_universal_detector) &&
- ReadParam(m, iter, &p->text_areas_are_resizable) &&
- ReadParam(m, iter, &p->java_enabled) &&
- ReadParam(m, iter, &p->allow_scripts_to_close_windows) &&
- ReadParam(m, iter, &p->uses_page_cache) &&
- ReadParam(m, iter, &p->remote_fonts_enabled) &&
- ReadParam(m, iter, &p->javascript_can_access_clipboard) &&
- ReadParam(m, iter, &p->xss_auditor_enabled) &&
- ReadParam(m, iter, &p->local_storage_enabled) &&
- ReadParam(m, iter, &p->databases_enabled) &&
- ReadParam(m, iter, &p->application_cache_enabled) &&
- ReadParam(m, iter, &p->tabs_to_links) &&
- ReadParam(m, iter, &p->user_style_sheet_enabled) &&
- ReadParam(m, iter, &p->user_style_sheet_location) &&
- ReadParam(m, iter, &p->author_and_user_styles_enabled) &&
- ReadParam(m, iter, &p->allow_universal_access_from_file_urls) &&
- ReadParam(m, iter, &p->allow_file_access_from_file_urls) &&
- ReadParam(m, iter, &p->experimental_webgl_enabled) &&
- ReadParam(m, iter, &p->show_composited_layer_borders) &&
- ReadParam(m, iter, &p->accelerated_compositing_enabled) &&
- ReadParam(m, iter, &p->memory_info_enabled);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<WebPreferences>");
- }
+ 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 WebDropData
template <>
struct ParamTraits<WebDropData> {
typedef WebDropData param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.identity);
- WriteParam(m, p.url);
- WriteParam(m, p.url_title);
- WriteParam(m, p.download_metadata);
- WriteParam(m, p.file_extension);
- WriteParam(m, p.filenames);
- WriteParam(m, p.plain_text);
- WriteParam(m, p.text_html);
- WriteParam(m, p.html_base_url);
- WriteParam(m, p.file_description_filename);
- WriteParam(m, p.file_contents);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->identity) &&
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->url_title) &&
- ReadParam(m, iter, &p->download_metadata) &&
- ReadParam(m, iter, &p->file_extension) &&
- ReadParam(m, iter, &p->filenames) &&
- ReadParam(m, iter, &p->plain_text) &&
- ReadParam(m, iter, &p->text_html) &&
- ReadParam(m, iter, &p->html_base_url) &&
- ReadParam(m, iter, &p->file_description_filename) &&
- ReadParam(m, iter, &p->file_contents);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<WebDropData>");
- }
+ 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 AudioManager::Format.
-template <>
-struct ParamTraits<AudioManager::Format> {
- typedef AudioManager::Format 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<AudioManager::Format>(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring format;
- switch (p) {
- case AudioManager::AUDIO_PCM_LINEAR:
- format = L"AUDIO_PCM_LINEAR";
- break;
- case AudioManager::AUDIO_PCM_LOW_LATENCY:
- format = L"AUDIO_PCM_LOW_LATENCY";
- break;
- case AudioManager::AUDIO_MOCK:
- format = L"AUDIO_MOCK";
- break;
- default:
- format = L"AUDIO_LAST_FORMAT";
- break;
- }
- LogParam(format, l);
- }
-};
-
-// Traits for ViewHostMsg_Audio_CreateStream_Params.
-template <>
-struct ParamTraits<ViewHostMsg_Audio_CreateStream_Params> {
- typedef ViewHostMsg_Audio_CreateStream_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.format);
- WriteParam(m, p.channels);
- WriteParam(m, p.sample_rate);
- WriteParam(m, p.bits_per_sample);
- WriteParam(m, p.packet_size);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->format) &&
- ReadParam(m, iter, &p->channels) &&
- ReadParam(m, iter, &p->sample_rate) &&
- ReadParam(m, iter, &p->bits_per_sample) &&
- ReadParam(m, iter, &p->packet_size);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<ViewHostMsg_Audio_CreateStream_Params>(");
- LogParam(p.format, l);
- l->append(L", ");
- LogParam(p.channels, l);
- l->append(L", ");
- LogParam(p.sample_rate, l);
- l->append(L", ");
- LogParam(p.bits_per_sample, l);
- l->append(L", ");
- LogParam(p.packet_size, l);
- l->append(L")");
- }
-};
-
-
#if defined(OS_POSIX)
// TODO(port): this shouldn't exist. However, the plugin stuff is really using
@@ -2211,80 +457,14 @@ struct ParamTraits<gfx::NativeView> {
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(StringPrintf(L"<gfx::NativeView>"));
+ static void Log(const param_type& p, std::string* l) {
+ l->append(StringPrintf("<gfx::NativeView>"));
}
};
#endif // defined(OS_POSIX)
template <>
-struct ParamTraits<ViewMsg_AudioStreamState_Params> {
- typedef ViewMsg_AudioStreamState_Params param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p.state);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- p->state = static_cast<ViewMsg_AudioStreamState_Params::State>(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring state;
- switch (p.state) {
- case ViewMsg_AudioStreamState_Params::kPlaying:
- state = L"ViewMsg_AudioStreamState_Params::kPlaying";
- break;
- case ViewMsg_AudioStreamState_Params::kPaused:
- state = L"ViewMsg_AudioStreamState_Params::kPaused";
- break;
- case ViewMsg_AudioStreamState_Params::kError:
- state = L"ViewMsg_AudioStreamState_Params::kError";
- break;
- default:
- state = L"UNKNOWN";
- break;
- }
- LogParam(state, l);
- }
-};
-
-template <>
-struct ParamTraits<ViewMsg_StopFinding_Params> {
- typedef ViewMsg_StopFinding_Params param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p.action);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- p->action = static_cast<ViewMsg_StopFinding_Params::Action>(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring action;
- switch (p.action) {
- case ViewMsg_StopFinding_Params::kClearSelection:
- action = L"ViewMsg_StopFinding_Params::kClearSelection";
- break;
- case ViewMsg_StopFinding_Params::kKeepSelection:
- action = L"ViewMsg_StopFinding_Params::kKeepSelection";
- break;
- case ViewMsg_StopFinding_Params::kActivateSelection:
- action = L"ViewMsg_StopFinding_Params::kActivateSelection";
- break;
- default:
- action = L"UNKNOWN";
- break;
- }
- LogParam(action, l);
- }
-};
-
-template <>
struct ParamTraits<appcache::Status> {
typedef appcache::Status param_type;
static void Write(Message* m, const param_type& p) {
@@ -2297,29 +477,29 @@ struct ParamTraits<appcache::Status> {
*p = static_cast<param_type>(type);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring state;
+ static void Log(const param_type& p, std::string* l) {
+ std::string state;
switch (p) {
case appcache::UNCACHED:
- state = L"UNCACHED";
+ state = "UNCACHED";
break;
case appcache::IDLE:
- state = L"IDLE";
+ state = "IDLE";
break;
case appcache::CHECKING:
- state = L"CHECKING";
+ state = "CHECKING";
break;
case appcache::DOWNLOADING:
- state = L"DOWNLOADING";
+ state = "DOWNLOADING";
break;
case appcache::UPDATE_READY:
- state = L"UPDATE_READY";
+ state = "UPDATE_READY";
break;
case appcache::OBSOLETE:
- state = L"OBSOLETE";
+ state = "OBSOLETE";
break;
default:
- state = L"InvalidStatusValue";
+ state = "InvalidStatusValue";
break;
}
@@ -2340,35 +520,35 @@ struct ParamTraits<appcache::EventID> {
*p = static_cast<param_type>(type);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring state;
+ static void Log(const param_type& p, std::string* l) {
+ std::string state;
switch (p) {
case appcache::CHECKING_EVENT:
- state = L"CHECKING_EVENT";
+ state = "CHECKING_EVENT";
break;
case appcache::ERROR_EVENT:
- state = L"ERROR_EVENT";
+ state = "ERROR_EVENT";
break;
case appcache::NO_UPDATE_EVENT:
- state = L"NO_UPDATE_EVENT";
+ state = "NO_UPDATE_EVENT";
break;
case appcache::DOWNLOADING_EVENT:
- state = L"DOWNLOADING_EVENT";
+ state = "DOWNLOADING_EVENT";
break;
case appcache::PROGRESS_EVENT:
- state = L"PROGRESS_EVENT";
+ state = "PROGRESS_EVENT";
break;
case appcache::UPDATE_READY_EVENT:
- state = L"UPDATE_READY_EVENT";
+ state = "UPDATE_READY_EVENT";
break;
case appcache::CACHED_EVENT:
- state = L"CACHED_EVENT";
+ state = "CACHED_EVENT";
break;
case appcache::OBSOLETE_EVENT:
- state = L"OBSOLETE_EVENT";
+ state = "OBSOLETE_EVENT";
break;
default:
- state = L"InvalidEventValue";
+ state = "InvalidEventValue";
break;
}
@@ -2377,145 +557,11 @@ struct ParamTraits<appcache::EventID> {
};
template<>
-struct ParamTraits<WebMenuItem::Type> {
- typedef WebMenuItem::Type 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<WebMenuItem::Type>(type);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring type;
- switch (p) {
- case WebMenuItem::OPTION:
- type = L"OPTION";
- break;
- case WebMenuItem::GROUP:
- type = L"GROUP";
- break;
- case WebMenuItem::SEPARATOR:
- type = L"SEPARATOR";
- break;
- default:
- type = L"UNKNOWN";
- break;
- }
- LogParam(type, l);
- }
-};
-
-template<>
struct ParamTraits<WebMenuItem> {
typedef WebMenuItem param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.label);
- WriteParam(m, p.type);
- WriteParam(m, p.enabled);
- WriteParam(m, p.checked);
- WriteParam(m, p.action);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->label) &&
- ReadParam(m, iter, &p->type) &&
- ReadParam(m, iter, &p->enabled) &&
- ReadParam(m, iter, &p->checked) &&
- ReadParam(m, iter, &p->action);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.label, l);
- l->append(L", ");
- LogParam(p.type, l);
- l->append(L", ");
- LogParam(p.enabled, l);
- l->append(L", ");
- LogParam(p.checked, l);
- l->append(L", ");
- LogParam(p.action, l);
- l->append(L")");
- }
-};
-
-// Traits for ViewHostMsg_ShowPopup_Params.
-template <>
-struct ParamTraits<ViewHostMsg_ShowPopup_Params> {
- typedef ViewHostMsg_ShowPopup_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.bounds);
- WriteParam(m, p.item_height);
- WriteParam(m, p.item_font_size);
- WriteParam(m, p.selected_item);
- WriteParam(m, p.popup_items);
- WriteParam(m, p.right_aligned);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->bounds) &&
- ReadParam(m, iter, &p->item_height) &&
- ReadParam(m, iter, &p->item_font_size) &&
- ReadParam(m, iter, &p->selected_item) &&
- ReadParam(m, iter, &p->popup_items) &&
- ReadParam(m, iter, &p->right_aligned);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.bounds, l);
- l->append(L", ");
- LogParam(p.item_height, l);
- l->append(L", ");
- LogParam(p.item_font_size, l);
- l->append(L", ");
- LogParam(p.selected_item, l);
- l->append(L", ");
- LogParam(p.popup_items, l);
- l->append(L", ");
- LogParam(p.right_aligned, l);
- l->append(L")");
- }
-};
-
-// Traits for ViewHostMsg_ScriptedPrint_Params.
-template <>
-struct ParamTraits<ViewHostMsg_ScriptedPrint_Params> {
- typedef ViewHostMsg_ScriptedPrint_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.routing_id);
- WriteParam(m, p.host_window_id);
- WriteParam(m, p.cookie);
- WriteParam(m, p.expected_pages_count);
- WriteParam(m, p.has_selection);
- WriteParam(m, p.use_overlays);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->routing_id) &&
- ReadParam(m, iter, &p->host_window_id) &&
- ReadParam(m, iter, &p->cookie) &&
- ReadParam(m, iter, &p->expected_pages_count) &&
- ReadParam(m, iter, &p->has_selection) &&
- ReadParam(m, iter, &p->use_overlays);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.routing_id, l);
- l->append(L", ");
- LogParam(p.host_window_id, l);
- l->append(L", ");
- LogParam(p.cookie, l);
- l->append(L", ");
- LogParam(p.expected_pages_count, l);
- l->append(L", ");
- LogParam(p.has_selection, l);
- l->append(L",");
- LogParam(p.use_overlays, l);
- l->append(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 <>
@@ -2527,23 +573,9 @@ struct SimilarTypeTraits<ViewType::Type> {
template <>
struct ParamTraits<URLPattern> {
typedef URLPattern param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.valid_schemes());
- WriteParam(m, p.GetAsString());
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int valid_schemes;
- std::string spec;
- if (!ReadParam(m, iter, &valid_schemes) ||
- !ReadParam(m, iter, &spec))
- return false;
-
- p->set_valid_schemes(valid_schemes);
- return p->Parse(spec);
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(p.GetAsString(), 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 <>
@@ -2559,22 +591,22 @@ struct ParamTraits<Clipboard::Buffer> {
*p = Clipboard::FromInt(buffer);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring type;
+ static void Log(const param_type& p, std::string* l) {
+ std::string type;
switch (p) {
case Clipboard::BUFFER_STANDARD:
- type = L"BUFFER_STANDARD";
+ type = "BUFFER_STANDARD";
break;
#if defined(USE_X11)
case Clipboard::BUFFER_SELECTION:
- type = L"BUFFER_SELECTION";
+ type = "BUFFER_SELECTION";
break;
#endif
case Clipboard::BUFFER_DRAG:
- type = L"BUFFER_DRAG";
+ type = "BUFFER_DRAG";
break;
default:
- type = L"UNKNOWN";
+ type = "UNKNOWN";
break;
}
@@ -2586,20 +618,9 @@ struct ParamTraits<Clipboard::Buffer> {
template <>
struct ParamTraits<EditCommand> {
typedef EditCommand param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.name);
- WriteParam(m, p.value);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->name) && ReadParam(m, iter, &p->value);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.name, l);
- l->append(L":");
- LogParam(p.value, l);
- l->append(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);
};
// Traits for DOMStorageType enum.
@@ -2616,18 +637,18 @@ struct ParamTraits<DOMStorageType> {
*p = static_cast<param_type>(type);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring control;
+ static void Log(const param_type& p, std::string* l) {
+ std::string control;
switch (p) {
case DOM_STORAGE_LOCAL:
- control = L"DOM_STORAGE_LOCAL";
+ control = "DOM_STORAGE_LOCAL";
break;
case DOM_STORAGE_SESSION:
- control = L"DOM_STORAGE_SESSION";
+ control = "DOM_STORAGE_SESSION";
break;
default:
NOTIMPLEMENTED();
- control = L"UNKNOWN";
+ control = "UNKNOWN";
break;
}
LogParam(control, l);
@@ -2648,354 +669,34 @@ struct ParamTraits<WebKit::WebStorageArea::Result> {
*p = static_cast<param_type>(type);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring control;
+ static void Log(const param_type& p, std::string* l) {
+ std::string control;
switch (p) {
case WebKit::WebStorageArea::ResultOK:
- control = L"WebKit::WebStorageArea::ResultOK";
+ control = "WebKit::WebStorageArea::ResultOK";
break;
case WebKit::WebStorageArea::ResultBlockedByQuota:
- control = L"WebKit::WebStorageArea::ResultBlockedByQuota";
+ control = "WebKit::WebStorageArea::ResultBlockedByQuota";
break;
case WebKit::WebStorageArea::ResultBlockedByPolicy:
- control = L"WebKit::WebStorageArea::ResultBlockedByPolicy";
+ control = "WebKit::WebStorageArea::ResultBlockedByPolicy";
break;
default:
NOTIMPLEMENTED();
- control = L"UNKNOWN";
+ control = "UNKNOWN";
break;
}
LogParam(control, l);
}
};
-// Traits for ViewMsg_DOMStorageEvent_Params.
-template <>
-struct ParamTraits<ViewMsg_DOMStorageEvent_Params> {
- typedef ViewMsg_DOMStorageEvent_Params param_type;
- static void 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_);
- }
- static bool 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_);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.key_, l);
- l->append(L", ");
- LogParam(p.old_value_, l);
- l->append(L", ");
- LogParam(p.new_value_, l);
- l->append(L", ");
- LogParam(p.origin_, l);
- l->append(L", ");
- LogParam(p.url_, l);
- l->append(L", ");
- LogParam(p.storage_type_, l);
- l->append(L")");
- }
-};
-
-// Traits for ViewHostMsg_IndexedDatabaseOpen_Params.
-template <>
-struct ParamTraits<ViewHostMsg_IndexedDatabaseOpen_Params> {
- typedef ViewHostMsg_IndexedDatabaseOpen_Params param_type;
- static void 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_);
- }
- static bool 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_);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.routing_id_, l);
- l->append(L", ");
- LogParam(p.response_id_, l);
- l->append(L", ");
- LogParam(p.origin_, l);
- l->append(L", ");
- LogParam(p.name_, l);
- l->append(L", ");
- LogParam(p.description_, l);
- l->append(L")");
- }
-};
-
-// Traits for ViewHostMsg_IDBDatabaseCreateObjectStore_Params.
-template <>
-struct ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params> {
- typedef ViewHostMsg_IDBDatabaseCreateObjectStore_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.response_id_);
- WriteParam(m, p.name_);
- WriteParam(m, p.key_path_);
- WriteParam(m, p.auto_increment_);
- WriteParam(m, p.idb_database_id_);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->response_id_) &&
- ReadParam(m, iter, &p->name_) &&
- ReadParam(m, iter, &p->key_path_) &&
- ReadParam(m, iter, &p->auto_increment_) &&
- ReadParam(m, iter, &p->idb_database_id_);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.response_id_, l);
- l->append(L", ");
- LogParam(p.name_, l);
- l->append(L", ");
- LogParam(p.key_path_, l);
- l->append(L", ");
- LogParam(p.auto_increment_, l);
- l->append(L", ");
- LogParam(p.idb_database_id_, l);
- l->append(L")");
- }
-};
-
-// Traits for ViewHostMsg_IDBObjectStoreCreateIndex_Params.
-template <>
-struct ParamTraits<ViewHostMsg_IDBObjectStoreCreateIndex_Params> {
- typedef ViewHostMsg_IDBObjectStoreCreateIndex_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.response_id_);
- WriteParam(m, p.name_);
- WriteParam(m, p.key_path_);
- WriteParam(m, p.unique_);
- WriteParam(m, p.idb_object_store_id_);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->response_id_) &&
- ReadParam(m, iter, &p->name_) &&
- ReadParam(m, iter, &p->key_path_) &&
- ReadParam(m, iter, &p->unique_) &&
- ReadParam(m, iter, &p->idb_object_store_id_);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.response_id_, l);
- l->append(L", ");
- LogParam(p.name_, l);
- l->append(L", ");
- LogParam(p.key_path_, l);
- l->append(L", ");
- LogParam(p.unique_, l);
- l->append(L", ");
- LogParam(p.idb_object_store_id_, l);
- l->append(L")");
- }
-};
-
-// Traits for ViewHostMsg_CreateWorker_Params
-template <>
-struct ParamTraits<ViewHostMsg_CreateWorker_Params> {
- typedef ViewHostMsg_CreateWorker_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.url);
- WriteParam(m, p.is_shared);
- WriteParam(m, p.name);
- WriteParam(m, p.document_id);
- WriteParam(m, p.render_view_route_id);
- WriteParam(m, p.route_id);
- WriteParam(m, p.parent_appcache_host_id);
- WriteParam(m, p.script_resource_appcache_id);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->is_shared) &&
- ReadParam(m, iter, &p->name) &&
- ReadParam(m, iter, &p->document_id) &&
- ReadParam(m, iter, &p->render_view_route_id) &&
- ReadParam(m, iter, &p->route_id) &&
- ReadParam(m, iter, &p->parent_appcache_host_id) &&
- ReadParam(m, iter, &p->script_resource_appcache_id);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.url, l);
- l->append(L", ");
- LogParam(p.is_shared, l);
- l->append(L", ");
- LogParam(p.name, l);
- l->append(L", ");
- LogParam(p.document_id, l);
- l->append(L", ");
- LogParam(p.render_view_route_id, l);
- l->append(L",");
- LogParam(p.route_id, l);
- l->append(L", ");
- LogParam(p.parent_appcache_host_id, l);
- l->append(L",");
- LogParam(p.script_resource_appcache_id, l);
- l->append(L")");
- }
-};
-
-// Traits for ShowNotification_Params
-template <>
-struct ParamTraits<ViewHostMsg_ShowNotification_Params> {
- typedef ViewHostMsg_ShowNotification_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.origin);
- WriteParam(m, p.is_html);
- WriteParam(m, p.contents_url);
- WriteParam(m, p.icon_url);
- WriteParam(m, p.title);
- WriteParam(m, p.body);
- WriteParam(m, p.direction);
- WriteParam(m, p.replace_id);
- WriteParam(m, p.notification_id);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->origin) &&
- ReadParam(m, iter, &p->is_html) &&
- ReadParam(m, iter, &p->contents_url) &&
- ReadParam(m, iter, &p->icon_url) &&
- ReadParam(m, iter, &p->title) &&
- ReadParam(m, iter, &p->body) &&
- ReadParam(m, iter, &p->direction) &&
- ReadParam(m, iter, &p->replace_id) &&
- ReadParam(m, iter, &p->notification_id);
- }
- static void Log(const param_type &p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.origin, l);
- l->append(L", ");
- LogParam(p.is_html, l);
- l->append(L", ");
- LogParam(p.contents_url, l);
- l->append(L", ");
- LogParam(p.icon_url, l);
- l->append(L", ");
- LogParam(p.title, l);
- l->append(L",");
- LogParam(p.body, l);
- l->append(L",");
- LogParam(p.direction, l);
- l->append(L",");
- LogParam(p.replace_id, l);
- l->append(L",");
- LogParam(p.notification_id, l);
- l->append(L")");
- }
-};
-
// Traits for WebCookie
template <>
struct ParamTraits<webkit_glue::WebCookie> {
typedef webkit_glue::WebCookie param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.name);
- WriteParam(m, p.value);
- WriteParam(m, p.domain);
- WriteParam(m, p.path);
- WriteParam(m, p.expires);
- WriteParam(m, p.http_only);
- WriteParam(m, p.secure);
- WriteParam(m, p.session);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->name) &&
- ReadParam(m, iter, &p->value) &&
- ReadParam(m, iter, &p->domain) &&
- ReadParam(m, iter, &p->path) &&
- ReadParam(m, iter, &p->expires) &&
- ReadParam(m, iter, &p->http_only) &&
- ReadParam(m, iter, &p->secure) &&
- ReadParam(m, iter, &p->session);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<WebCookie>");
- }
-};
-
-template<>
-struct ParamTraits<ViewMsg_ExecuteCode_Params> {
- typedef ViewMsg_ExecuteCode_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.request_id);
- WriteParam(m, p.extension_id);
- WriteParam(m, p.host_permissions);
- WriteParam(m, p.is_javascript);
- WriteParam(m, p.code);
- WriteParam(m, p.all_frames);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->request_id) &&
- ReadParam(m, iter, &p->extension_id) &&
- ReadParam(m, iter, &p->host_permissions) &&
- ReadParam(m, iter, &p->is_javascript) &&
- ReadParam(m, iter, &p->code) &&
- ReadParam(m, iter, &p->all_frames);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<ViewMsg_ExecuteCode_Params>");
- }
-};
-
-template<>
-struct ParamTraits<ViewMsg_New_Params> {
- typedef ViewMsg_New_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.parent_window);
- WriteParam(m, p.renderer_preferences);
- WriteParam(m, p.web_preferences);
- WriteParam(m, p.view_id);
- WriteParam(m, p.session_storage_namespace_id);
- WriteParam(m, p.frame_name);
- }
-
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->parent_window) &&
- ReadParam(m, iter, &p->renderer_preferences) &&
- ReadParam(m, iter, &p->web_preferences) &&
- ReadParam(m, iter, &p->view_id) &&
- ReadParam(m, iter, &p->session_storage_namespace_id) &&
- ReadParam(m, iter, &p->frame_name);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.parent_window, l);
- l->append(L", ");
- LogParam(p.renderer_preferences, l);
- l->append(L", ");
- LogParam(p.web_preferences, l);
- l->append(L", ");
- LogParam(p.view_id, l);
- l->append(L", ");
- LogParam(p.session_storage_namespace_id, l);
- l->append(L", ");
- LogParam(p.frame_name, l);
- l->append(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 <>
@@ -3003,207 +704,57 @@ struct SimilarTypeTraits<TranslateErrors::Type> {
typedef int Type;
};
-template<>
-struct ParamTraits<ViewHostMsg_RunFileChooser_Params> {
- typedef ViewHostMsg_RunFileChooser_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, static_cast<int>(p.mode));
- WriteParam(m, p.title);
- WriteParam(m, p.default_file_name);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int mode;
- if (!ReadParam(m, iter, &mode))
- return false;
- if (mode != param_type::Open &&
- mode != param_type::OpenMultiple &&
- mode != param_type::Save)
- return false;
- p->mode = static_cast<param_type::Mode>(mode);
- return
- ReadParam(m, iter, &p->title) &&
- ReadParam(m, iter, &p->default_file_name);
- };
- static void Log(const param_type& p, std::wstring* l) {
- switch (p.mode) {
- case param_type::Open:
- l->append(L"(Open, ");
- break;
- case param_type::OpenMultiple:
- l->append(L"(OpenMultiple, ");
- break;
- case param_type::Save:
- l->append(L"(Save, ");
- break;
- default:
- l->append(L"(UNKNOWN, ");
- }
- LogParam(p.title, l);
- l->append(L", ");
- LogParam(p.default_file_name, l);
- }
+template <>
+struct ParamTraits<ExtensionExtent> {
+ typedef ExtensionExtent 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_CreateWindow_Params> {
- typedef ViewHostMsg_CreateWindow_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.opener_id);
- WriteParam(m, p.user_gesture);
- WriteParam(m, p.window_container_type);
- WriteParam(m, p.session_storage_namespace_id);
- WriteParam(m, p.frame_name);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->opener_id) &&
- ReadParam(m, iter, &p->user_gesture) &&
- ReadParam(m, iter, &p->window_container_type) &&
- ReadParam(m, iter, &p->session_storage_namespace_id) &&
- ReadParam(m, iter, &p->frame_name);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.opener_id, l);
- l->append(L", ");
- LogParam(p.user_gesture, l);
- l->append(L", ");
- LogParam(p.window_container_type, l);
- l->append(L", ");
- LogParam(p.session_storage_namespace_id, l);
- l->append(L", ");
- LogParam(p.frame_name, l);
- l->append(L")");
- }
+struct ParamTraits<appcache::AppCacheResourceInfo> {
+ typedef appcache::AppCacheResourceInfo 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<ExtensionExtent> {
- typedef ExtensionExtent param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.patterns());
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- std::vector<URLPattern> patterns;
- bool success =
- ReadParam(m, iter, &patterns);
- if (!success)
- return false;
-
- for (size_t i = 0; i < patterns.size(); ++i)
- p->AddPattern(patterns[i]);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(p.patterns(), l);
- }
+struct ParamTraits<appcache::AppCacheInfo> {
+ typedef appcache::AppCacheInfo 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_ExtensionExtentInfo> {
- typedef ViewMsg_ExtensionExtentInfo param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.extension_id);
- WriteParam(m, p.web_extent);
- WriteParam(m, p.browse_extent);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->extension_id) &&
- ReadParam(m, iter, &p->web_extent) &&
- ReadParam(m, iter, &p->browse_extent);
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(p.extension_id, l);
- }
+struct ParamTraits<webkit_glue::WebAccessibility> {
+ typedef webkit_glue::WebAccessibility 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);
};
+// Traits for base::PlatformFileError
template <>
-struct ParamTraits<ViewMsg_ExtensionExtentsUpdated_Params> {
- typedef ViewMsg_ExtensionExtentsUpdated_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.extension_apps);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->extension_apps);
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(p.extension_apps, l);
- }
+struct SimilarTypeTraits<base::PlatformFileError> {
+ typedef int Type;
};
template <>
-struct ParamTraits<WindowContainerType> {
- typedef WindowContainerType param_type;
- static void Write(Message* m, const param_type& p) {
- int val = static_cast<int>(p);
- WriteParam(m, val);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int val = 0;
- if (!ReadParam(m, iter, &val) ||
- val < WINDOW_CONTAINER_TYPE_NORMAL ||
- val >= WINDOW_CONTAINER_TYPE_MAX_VALUE)
- return false;
- *p = static_cast<param_type>(val);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(p, l);
- }
+struct SimilarTypeTraits<fileapi::FileSystemType> {
+ typedef int Type;
};
+// Traits for AudioBuffersState structure.
template <>
-struct ParamTraits<webkit_glue::WebAccessibility> {
- typedef webkit_glue::WebAccessibility param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.id);
- WriteParam(m, p.name);
- WriteParam(m, p.value);
- WriteParam(m, static_cast<int>(p.role));
- WriteParam(m, static_cast<int>(p.state));
- WriteParam(m, p.location);
- WriteParam(m, p.attributes);
- WriteParam(m, p.children);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- bool ret = ReadParam(m, iter, &p->id);
- ret = ret && ReadParam(m, iter, &p->name);
- ret = ret && ReadParam(m, iter, &p->value);
- int role = -1;
- ret = ret && ReadParam(m, iter, &role);
- if (role >= webkit_glue::WebAccessibility::ROLE_NONE &&
- role < webkit_glue::WebAccessibility::NUM_ROLES) {
- p->role = static_cast<webkit_glue::WebAccessibility::Role>(role);
- } else {
- p->role = webkit_glue::WebAccessibility::ROLE_NONE;
- }
- int state = 0;
- ret = ret && ReadParam(m, iter, &state);
- p->state = static_cast<webkit_glue::WebAccessibility::State>(state);
- ret = ret && ReadParam(m, iter, &p->location);
- ret = ret && ReadParam(m, iter, &p->attributes);
- ret = ret && ReadParam(m, iter, &p->children);
- return ret;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.id, l);
- l->append(L", ");
- LogParam(p.name, l);
- l->append(L", ");
- LogParam(p.value, l);
- l->append(L", ");
- LogParam(static_cast<int>(p.role), l);
- l->append(L", ");
- LogParam(static_cast<int>(p.state), l);
- l->append(L", ");
- LogParam(p.location, l);
- l->append(L", ");
- LogParam(p.attributes, l);
- l->append(L", ");
- LogParam(p.children, l);
- l->append(L")");
- }
+struct ParamTraits<AudioBuffersState> {
+ typedef AudioBuffersState 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
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 2cedec8..b3e2b53 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -16,25 +16,15 @@
#include "base/nullable_string16.h"
#include "base/platform_file.h"
#include "base/sync_socket.h"
-#include "base/time.h"
-#include "base/values.h"
#include "chrome/common/content_settings.h"
-#include "chrome/common/extensions/update_manifest.h"
#include "chrome/common/geoposition.h"
#include "chrome/common/nacl_types.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/page_zoom.h"
-#include "chrome/common/thumbnail_score.h"
#include "chrome/common/translate_errors.h"
#include "chrome/common/window_container_type.h"
-#include "gfx/rect.h"
-#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/glue/dom_operations.h"
-#include "webkit/glue/form_field.h"
-#include "webkit/glue/webcursor.h"
+#include "media/audio/audio_buffers_state.h"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -52,6 +42,31 @@
// Substitution map for l10n messages.
typedef std::map<std::string, std::string> SubstitutionMap;
+class GPUInfo;
+class SerializedScriptValue;
+class SkBitmap;
+struct ThumbnailScore;
+class WebCursor;
+
+namespace base {
+namespace file_util_proxy {
+struct Entry;
+}
+}
+
+namespace IPC {
+struct ChannelHandle;
+class Message;
+}
+
+namespace webkit_blob {
+class BlobData;
+}
+
+namespace file_util {
+struct FileInfo;
+}
+
//-----------------------------------------------------------------------------
// RenderView messages
// These are messages sent from the browser to the renderer process.
@@ -190,7 +205,7 @@ IPC_BEGIN_MESSAGES(View)
//
// This message must be sent just before sending a key event.
IPC_MESSAGE_ROUTED1(ViewMsg_SetEditCommandsForNextKeyEvent,
- EditCommands /* edit_commands */)
+ std::vector<EditCommand> /* edit_commands */)
// Message payload is the name/value of a WebCore edit command to execute.
IPC_MESSAGE_ROUTED2(ViewMsg_ExecuteEditCommand,
@@ -289,13 +304,6 @@ IPC_BEGIN_MESSAGES(View)
int /* request_id */,
std::vector<char> /* data */)
- // Sent as download progress is being made, size of the resource may be
- // unknown, in that case |size| is -1.
- IPC_MESSAGE_ROUTED3(ViewMsg_Resource_DownloadProgress,
- int /* request_id */,
- int64 /* position */,
- int64 /* size */)
-
// Sent as upload progress is being made.
IPC_MESSAGE_ROUTED3(ViewMsg_Resource_UploadProgress,
int /* request_id */,
@@ -317,11 +325,19 @@ IPC_BEGIN_MESSAGES(View)
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_ROUTED3(ViewMsg_Resource_RequestComplete,
+ IPC_MESSAGE_ROUTED4(ViewMsg_Resource_RequestComplete,
int /* request_id */,
URLRequestStatus /* status */,
- std::string /* security info */)
+ 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
@@ -509,6 +525,9 @@ IPC_BEGIN_MESSAGES(View)
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 */)
@@ -596,15 +615,15 @@ IPC_BEGIN_MESSAGES(View)
// The browser sends this to a renderer process in response to a
// ViewHostMsg_EstablishGpuChannel message.
- IPC_MESSAGE_CONTROL1(ViewMsg_GpuChannelEstablished,
- IPC::ChannelHandle /* handle to channel */)
+ 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_CONTROL3(AppCacheMsg_CacheSelected,
+ IPC_MESSAGE_CONTROL2(AppCacheMsg_CacheSelected,
int /* host_id */,
- int64 /* appcache_id */,
- appcache::Status)
+ appcache::AppCacheInfo)
// Notifies the renderer of an AppCache status change.
IPC_MESSAGE_CONTROL2(AppCacheMsg_StatusChanged,
@@ -642,10 +661,11 @@ IPC_BEGIN_MESSAGES(View)
// Reply to the ViewHostMsg_QueryFormFieldAutoFill message with the
// AutoFill suggestions.
- IPC_MESSAGE_ROUTED4(ViewMsg_AutoFillSuggestionsReturned,
+ 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
@@ -661,10 +681,9 @@ IPC_BEGIN_MESSAGES(View)
bool /* script_can_close */)
// Sent by AudioRendererHost to renderer to request an audio packet.
- IPC_MESSAGE_ROUTED3(ViewMsg_RequestAudioPacket,
+ IPC_MESSAGE_ROUTED2(ViewMsg_RequestAudioPacket,
int /* stream id */,
- uint32 /* bytes in buffer */,
- int64 /* message timestamp */)
+ 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
@@ -731,7 +750,7 @@ IPC_BEGIN_MESSAGES(View)
// Extension::Permissions for which elements correspond to which permissions.
IPC_MESSAGE_CONTROL2(ViewMsg_Extension_SetAPIPermissions,
std::string /* extension_id */,
- std::vector<std::string> /* permissions */)
+ std::set<std::string> /* permissions */)
// Tell the renderer process which host permissions the given extension has.
IPC_MESSAGE_CONTROL2(
@@ -740,10 +759,11 @@ IPC_BEGIN_MESSAGES(View)
std::vector<URLPattern> /* URLPatterns the extension can access */)
// Tell the renderer process that the given extension is enabled or disabled
- // for incognito mode.
- IPC_MESSAGE_CONTROL2(ViewMsg_Extension_ExtensionSetIncognitoEnabled,
+ // for incognito mode, and what kind of incognito behavior it has.
+ IPC_MESSAGE_CONTROL3(ViewMsg_Extension_ExtensionSetIncognitoEnabled,
std::string /* extension_id */,
- bool /* enabled */)
+ bool /* enabled */,
+ bool /* incognito_split_mode */)
// Tell the renderer process all known page action ids for a particular
// extension.
@@ -794,6 +814,10 @@ IPC_BEGIN_MESSAGES(View)
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 */)
@@ -864,11 +888,18 @@ IPC_BEGIN_MESSAGES(View)
IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessSerializedScriptValue,
int32 /* response_id */,
SerializedScriptValue /* serialized_script_value */)
+ IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbackSuccessOpenCursor,
+ int32 /* response_id */,
+ int32 /* cursor_id */)
IPC_MESSAGE_CONTROL3(ViewMsg_IDBCallbacksError,
int32 /* response_id */,
int /* code */,
string16 /* message */)
+ // IDBTransactionCallback message handlers.
+ IPC_MESSAGE_CONTROL1(ViewMsg_IDBTransactionCallbacksAbort,
+ int /* transaction_id */)
+
#if defined(IPC_MESSAGE_LOG_ENABLED)
// Tell the renderer process to begin or end IPC message logging.
IPC_MESSAGE_CONTROL1(ViewMsg_SetIPCLoggingEnabled,
@@ -957,12 +988,12 @@ IPC_BEGIN_MESSAGES(View)
IPC_MESSAGE_CONTROL1(ViewMsg_SetIsIncognitoProcess,
bool /* is_incognito_processs */)
- // Notification that the list of extensions with web extents has been updated.
- IPC_MESSAGE_CONTROL1(ViewMsg_ExtensionExtentsUpdated,
- ViewMsg_ExtensionExtentsUpdated_Params)
+ // Notification that the list of extensions has been updated.
+ IPC_MESSAGE_CONTROL1(ViewMsg_ExtensionsUpdated,
+ ViewMsg_ExtensionsUpdated_Params)
- // Request a tree of Accessibility data from the render process.
- IPC_MESSAGE_ROUTED0(ViewMsg_GetAccessibilityTree)
+ // 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,
@@ -973,6 +1004,68 @@ IPC_BEGIN_MESSAGES(View)
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 */,
+ string16 /* 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::file_util_proxy::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 */)
+
IPC_END_MESSAGES(View)
@@ -997,8 +1090,16 @@ IPC_BEGIN_MESSAGES(ViewHost)
WebKit::WebPopupType /* popup type */,
int /* route_id */)
- // These two messages are sent to the parent RenderViewHost to display the
- // page/widget that was created by CreateWindow/CreateWidget. routing_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.
//
@@ -1014,6 +1115,10 @@ IPC_BEGIN_MESSAGES(ViewHost)
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)
@@ -1093,7 +1198,8 @@ IPC_BEGIN_MESSAGES(ViewHost)
// Sent when after the onload handler has been invoked for the document
// in the toplevel frame.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_DocumentOnLoadCompletedInMainFrame)
+ 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
@@ -1231,25 +1337,32 @@ IPC_BEGIN_MESSAGES(ViewHost)
GURL /* url */,
std::string /* cookie_name */)
- // Used to get raw cookie information for the given URL
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_GetCookiesEnabled,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- bool /* enabled */)
-
// Used to get the list of plugins
IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetPlugins,
bool /* refresh*/,
std::vector<WebPluginInfo> /* plugins */)
- // Returns a path to a plugin for the given url and mime type. If there's
- // no plugin, an empty string is returned.
- IPC_SYNC_MESSAGE_CONTROL3_2(ViewHostMsg_GetPluginPath,
+ // Return information about a plugin for the given URL and MIME type. If there
+ // is no matching plugin, |found| is set to false.
+ // If |enabled| in the WebPluginInfo struct is false, the plug-in is basically
+ // 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.
+ IPC_SYNC_MESSAGE_CONTROL3_4(ViewHostMsg_GetPluginInfo,
GURL /* url */,
GURL /* policy_url */,
std::string /* mime_type */,
- FilePath /* filename */,
- std::string /* actual mime type for url */)
+ bool /* found */,
+ WebPluginInfo /* plugin info */,
+ ContentSetting /* setting */,
+ std::string /* actual_mime_type */)
// Requests spellcheck for a word.
IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_SpellCheck,
@@ -1279,8 +1392,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
// Tells the browser that content in the current page was blocked due to the
// user's content settings.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ContentBlocked,
- ContentSettingsType /* type of blocked content */)
+ 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.
@@ -1389,7 +1503,7 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_SYNC_MESSAGE_CONTROL3_2(ViewHostMsg_OpenChannelToPlugin,
GURL /* url */,
std::string /* mime_type */,
- std::wstring /* locale */,
+ std::string /* locale */,
IPC::ChannelHandle /* handle to channel */,
WebPluginInfo /* info */)
@@ -1409,8 +1523,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
// 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 /* channel number */,
- nacl::FileDescriptor /* imc channel handle */,
+ int /* socket count */,
+ std::vector<nacl::FileDescriptor>
+ /* imc channel handles */,
base::ProcessHandle /* NaCl process handle */,
base::ProcessId /* NaCl process id */)
@@ -1556,9 +1671,10 @@ IPC_BEGIN_MESSAGES(ViewHost)
// Find out if the given url's security origin is installed as a search
// provider.
- IPC_SYNC_MESSAGE_ROUTED1_1(
+ IPC_SYNC_MESSAGE_ROUTED2_1(
ViewHostMsg_GetSearchProviderInstallState,
- GURL,
+ GURL /* page url */,
+ GURL /* inquiry url */,
ViewHostMsg_GetSearchProviderInstallState_Params /* install */)
// Required for updating text input state.
@@ -1585,7 +1701,6 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDefaultPrintSettings,
ViewMsg_Print_Params /* default_settings */)
-#if defined(OS_WIN) || defined(OS_MACOSX)
// 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
@@ -1594,7 +1709,6 @@ IPC_BEGIN_MESSAGES(ViewHost)
ViewHostMsg_ScriptedPrint_Params,
ViewMsg_PrintPages_Params
/* settings chosen by the user*/)
-#endif // defined(OS_WIN) || defined(OS_MACOSX)
// WebKit and JavaScript error messages to log to the console
// or debugger UI.
@@ -1632,9 +1746,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
// Updates runtime features store in devtools manager in order to support
// cross-navigation instrumentation.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_DevToolsRuntimeFeatureStateChanged,
- std::string /* feature */,
- bool /* enabled */)
+ IPC_MESSAGE_ROUTED2(ViewHostMsg_DevToolsRuntimePropertyChanged,
+ std::string /* name */,
+ std::string /* value */)
// Send back a string to be recorded by UserMetrics.
IPC_MESSAGE_ROUTED1(ViewHostMsg_UserMetricsRecordAction,
@@ -1666,11 +1780,26 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_ROUTED1(ViewHostMsg_MissingPluginStatus,
int /* status */)
+ // Notifies when a non-sandboxed plugin was blocked.
+ // |plugin| is the identifier for the plugin (currently its path),
+ // |name| is its user-visible name.
+ IPC_MESSAGE_ROUTED2(ViewHostMsg_NonSandboxedPluginBlocked,
+ std::string /* plugin */,
+ string16 /* name */)
+
+ // Notifies when a blocked plugin was loaded via click-to-load.
+ IPC_MESSAGE_ROUTED0(ViewHostMsg_BlockedPluginLoaded)
+
// 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)
@@ -1743,6 +1872,14 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_ROUTED1(ViewHostMsg_DataReceived_ACK,
int /* request_id */)
+ // 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 */,
@@ -1750,11 +1887,6 @@ IPC_BEGIN_MESSAGES(ViewHost)
GURL /* url redirected to */)
// Sent by the renderer process to acknowledge receipt of a
- // DownloadProgress message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DownloadProgress_ACK,
- int /* request_id */)
-
- // Sent by the renderer process to acknowledge receipt of a
// UploadProgress message.
IPC_MESSAGE_ROUTED1(ViewHostMsg_UploadProgress_ACK,
int /* request_id */)
@@ -1868,11 +2000,11 @@ IPC_BEGIN_MESSAGES(ViewHost)
int /* host_id */,
bool /* success */)
- // Returns the resizer box location in the window this widget is embedded.
- // Important for Mac OS X, but not Win or Linux.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetRootWindowResizerRect,
- gfx::NativeViewId /* window */,
- gfx::Rect /* Out: Window location */)
+ // 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,
@@ -1882,11 +2014,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
// Instructs the browser to fill in the values for a form using AutoFill
// profile data.
- IPC_MESSAGE_ROUTED5(ViewHostMsg_FillAutoFillFormData,
+ IPC_MESSAGE_ROUTED3(ViewHostMsg_FillAutoFillFormData,
int /* id of this message */,
webkit_glue::FormData /* the form */,
- string16 /* profile name */,
- string16 /* profile label */,
int /* profile unique ID */)
// Instructs the browser to remove the specified Autocomplete entry from the
@@ -1947,12 +2077,8 @@ IPC_BEGIN_MESSAGES(ViewHost)
// A renderer sends this message when an extension process starts an API
// request. The browser will always respond with a ViewMsg_ExtensionResponse.
- IPC_MESSAGE_ROUTED5(ViewHostMsg_ExtensionRequest,
- std::string /* name */,
- ListValue /* arguments */,
- GURL /* source_url */,
- int /* callback id */,
- bool /* has_callback */)
+ IPC_MESSAGE_ROUTED1(ViewHostMsg_ExtensionRequest,
+ ViewHostMsg_DomMessage_Params)
// Notify the browser that this renderer added a listener to an event.
IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionAddListener,
@@ -1989,9 +2115,13 @@ IPC_BEGIN_MESSAGES(ViewHost)
// 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.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_AllocateFakePluginWindowHandle,
+ // 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
@@ -2058,7 +2188,7 @@ IPC_BEGIN_MESSAGES(ViewHost)
// processes (SharedWorkers are shut down when their last associated document
// is detached).
IPC_MESSAGE_CONTROL1(ViewHostMsg_DocumentDetached,
- unsigned long long /* document_id */)
+ uint64 /* document_id */)
// A message sent to the browser on behalf of a renderer which wants to show
// a desktop notification.
@@ -2116,18 +2246,11 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionCloseChannel,
int /* port_id */)
- // Sent as a result of a focus change in the renderer (if accessibility is
- // enabled), to notify the browser side that its accessibility focus needs to
- // change as well. Takes the id of the accessibility object that now has
- // focus.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_AccessibilityFocusChange,
- int /* accessibility object id */)
-
- // Send as a result of a state change in the renderer (if accessibility is
- // enabled), to notify the browser side. Takes the id of the accessibility
- // object that had a state change
- IPC_MESSAGE_ROUTED1(ViewHostMsg_AccessibilityObjectStateChange,
- int /* accessibility object 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.
@@ -2144,6 +2267,11 @@ IPC_BEGIN_MESSAGES(ViewHost)
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 */,
@@ -2195,9 +2323,42 @@ IPC_BEGIN_MESSAGES(ViewHost)
GURL /* url */,
bool /* something_cleared */)
- // WebIndexedDatabase::open() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IndexedDatabaseOpen,
- ViewHostMsg_IndexedDatabaseOpen_Params)
+ // 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_MESSAGE_CONTROL3(ViewHostMsg_IDBCursorUpdate,
+ int32, /* idb_cursor_id */
+ int32, /* response_id */
+ SerializedScriptValue /* value */)
+
+ // WebIDBCursor::continue() message.
+ IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBCursorContinue,
+ int32, /* idb_cursor_id */
+ int32, /* response_id */
+ IndexedDBKey /* key */)
+
+ // WebIDBCursor::remove() message.
+ IPC_MESSAGE_CONTROL2(ViewHostMsg_IDBCursorRemove,
+ int32, /* idb_cursor_id */
+ int32 /* response_id */)
+
+ // WebIDBFactory::open() message.
+ IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBFactoryOpen,
+ ViewHostMsg_IDBFactoryOpen_Params)
// WebIDBDatabase::name() message.
IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseName,
@@ -2237,6 +2398,24 @@ IPC_BEGIN_MESSAGES(ViewHost)
int32, /* response_id */
string16 /* name */)
+ // WebIDBDatabase::setVersion() message.
+ IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBDatabaseSetVersion,
+ int32, /* idb_database_id */
+ int32, /* response_id */
+ string16 /* version */)
+
+ // 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_1(ViewHostMsg_IDBDatabaseTransaction,
+ int32, /* idb_database_id */
+ std::vector<string16>, /* object_stores */
+ int32, /* mode */
+ int32, /* timeout */
+ int32 /* idb_transaction_id */)
+
// WebIDBDatabase::~WebIDBDatabase() message.
IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBDatabaseDestroyed,
int32 /* idb_database_id */)
@@ -2246,6 +2425,11 @@ IPC_BEGIN_MESSAGES(ViewHost)
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 */
@@ -2256,6 +2440,28 @@ IPC_BEGIN_MESSAGES(ViewHost)
int32, /* idb_unique_id */
bool /* unique */)
+ // WebIDBIndex::openObjectCursor() message. (Uses openCursor's params though.)
+ IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBIndexOpenObjectCursor,
+ ViewHostMsg_IDBIndexOpenCursor_Params)
+
+ // WebIDBIndex::openCursor() message.
+ IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBIndexOpenCursor,
+ ViewHostMsg_IDBIndexOpenCursor_Params)
+
+ // WebIDBIndex::getObject() message.
+ IPC_MESSAGE_CONTROL4(ViewHostMsg_IDBIndexGetObject,
+ int32, /* idb_index_id */
+ int32, /* response_id */
+ IndexedDBKey, /* key */
+ int /* transaction_id */)
+
+ // WebIDBIndex::get() message.
+ IPC_MESSAGE_CONTROL4(ViewHostMsg_IDBIndexGet,
+ int32, /* idb_index_id */
+ int32, /* response_id */
+ IndexedDBKey, /* key */
+ int /* transaction_id */)
+
// WebIDBIndex::~WebIDBIndex() message.
IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBIndexDestroyed,
int32 /* idb_index_id */)
@@ -2276,24 +2482,22 @@ IPC_BEGIN_MESSAGES(ViewHost)
std::vector<string16> /* index_names */)
// WebIDBObjectStore::get() message.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBObjectStoreGet,
+ IPC_MESSAGE_CONTROL4(ViewHostMsg_IDBObjectStoreGet,
int32, /* idb_object_store_id */
int32, /* response_id */
- IndexedDBKey /* key */)
+ IndexedDBKey, /* key */
+ int /* transaction_id */)
// WebIDBObjectStore::put() message.
- IPC_MESSAGE_CONTROL5(ViewHostMsg_IDBObjectStorePut,
- int32, /* idb_object_store_id */
- int32, /* response_id */
- SerializedScriptValue, /* serialized_value */
- IndexedDBKey, /* key */
- bool /* add_only */)
+ IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBObjectStorePut,
+ ViewHostMsg_IDBObjectStorePut_Params)
// WebIDBObjectStore::remove() message.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_IDBObjectStoreRemove,
+ IPC_MESSAGE_CONTROL4(ViewHostMsg_IDBObjectStoreRemove,
int32, /* idb_object_store_id */
int32, /* response_id */
- IndexedDBKey /* key */)
+ IndexedDBKey, /* key */
+ int /* transaction_id */)
// WebIDBObjectStore::createIndex() message.
IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBObjectStoreCreateIndex,
@@ -2312,10 +2516,36 @@ IPC_BEGIN_MESSAGES(ViewHost)
int32, /* response_id */
string16 /* name */)
+ // WebIDBObjectStore::openCursor() message.
+ IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBObjectStoreOpenCursor,
+ ViewHostMsg_IDBObjectStoreOpenCursor_Params)
+
// 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_1(ViewHostMsg_IDBTransactionObjectStore,
+ int32, /* transaction_id */
+ string16, /* name */
+ int32 /* object_store_id */)
+
+ // 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 */,
@@ -2333,6 +2563,13 @@ IPC_BEGIN_MESSAGES(ViewHost)
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)
@@ -2354,18 +2591,18 @@ IPC_BEGIN_MESSAGES(ViewHost)
// 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 */,
+ 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 */,
+ 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 */,
+ string16 /* vfs file name */,
int64 /* the size of the given DB file */)
// Notifies the browser process that a new database has been opened
@@ -2521,9 +2758,149 @@ IPC_BEGIN_MESSAGES(ViewHost)
int /* render_view_id */,
int /* bridge_id */)
- // Send the tree of accessibility data to the browser, where it's cached
- // in order to respond to OS accessibility queries immediately.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_AccessibilityTree,
- webkit_glue::WebAccessibility)
+ // Notifies the TabContents that the content being displayed is PDF.
+ // This allows the browser to handle things such as zooming differently.
+ IPC_MESSAGE_ROUTED0(ViewHostMsg_SetDisplayingPDFContent)
+
+ // Requests the speech input service to start speech recognition on behalf of
+ // the given |render_view_id|.
+ IPC_MESSAGE_CONTROL3(ViewHostMsg_SpeechInput_StartRecognition,
+ int /* render_view_id */,
+ int /* request id */,
+ gfx::Rect /* element rect in render view coordinates */)
+
+ // 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_CONTROL4(ViewHostMsg_OpenFileSystemRequest,
+ int /* request_id */,
+ GURL /* origin_url */,
+ fileapi::FileSystemType /* type */,
+ int64 /* requested_size */)
+
+ // 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_CONTROL2(ViewHostMsg_FileSystem_Remove,
+ int /* request_id */,
+ FilePath /* path */)
+
+ // 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_SetSuggestResult,
+ int32 /* page_id */,
+ std::string /* suggest */)
+
+ // 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 */)
IPC_END_MESSAGES(ViewHost)
diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc
new file mode 100644
index 0000000..4b28b3d
--- /dev/null
+++ b/chrome/common/render_messages_params.cc
@@ -0,0 +1,1843 @@
+// Copyright (c) 2010 The Chromium Authors. All 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/render_messages_params.h"
+
+#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"
+
+ViewMsg_Navigate_Params::ViewMsg_Navigate_Params()
+ : page_id(-1),
+ pending_history_list_offset(-1),
+ current_history_list_offset(-1),
+ current_history_list_length(0),
+ transition(PageTransition::LINK),
+ navigation_type(NORMAL) {
+}
+
+ViewMsg_Navigate_Params::~ViewMsg_Navigate_Params() {
+}
+
+ViewHostMsg_FrameNavigate_Params::ViewHostMsg_FrameNavigate_Params()
+ : page_id(0),
+ transition(PageTransition::TYPED),
+ should_update_history(false),
+ gesture(NavigationGestureUser),
+ is_post(false),
+ is_content_filtered(false),
+ was_within_same_page(false),
+ http_status_code(0) {
+}
+
+ViewHostMsg_FrameNavigate_Params::~ViewHostMsg_FrameNavigate_Params() {
+}
+
+ViewHostMsg_UpdateRect_Params::ViewHostMsg_UpdateRect_Params()
+ : dx(0),
+ dy(0),
+ flags(0) {
+}
+
+ViewHostMsg_UpdateRect_Params::~ViewHostMsg_UpdateRect_Params() {
+}
+
+ViewMsg_ClosePage_Params::ViewMsg_ClosePage_Params()
+ : closing_process_id(0),
+ closing_route_id(0),
+ for_cross_site_transition(false),
+ new_render_process_host_id(0),
+ new_request_id(0) {
+}
+
+ViewMsg_ClosePage_Params::~ViewMsg_ClosePage_Params() {
+}
+
+ViewHostMsg_Resource_Request::ViewHostMsg_Resource_Request()
+ : load_flags(0),
+ origin_child_id(0),
+ resource_type(ResourceType::MAIN_FRAME),
+ request_context(0),
+ appcache_host_id(0),
+ download_to_file(false),
+ host_renderer_id(0),
+ host_render_view_id(0) {
+}
+
+ViewHostMsg_Resource_Request::~ViewHostMsg_Resource_Request() {
+}
+
+ViewMsg_Print_Params::ViewMsg_Print_Params()
+ : margin_top(0),
+ margin_left(0),
+ dpi(0),
+ min_shrink(0),
+ max_shrink(0),
+ desired_dpi(0),
+ document_cookie(0),
+ selection_only(false) {
+}
+
+ViewMsg_Print_Params::~ViewMsg_Print_Params() {
+}
+
+bool ViewMsg_Print_Params::Equals(const ViewMsg_Print_Params& rhs) const {
+ return page_size == rhs.page_size &&
+ printable_size == rhs.printable_size &&
+ margin_top == rhs.margin_top &&
+ margin_left == rhs.margin_left &&
+ dpi == rhs.dpi &&
+ min_shrink == rhs.min_shrink &&
+ max_shrink == rhs.max_shrink &&
+ desired_dpi == rhs.desired_dpi &&
+ selection_only == rhs.selection_only;
+}
+
+bool ViewMsg_Print_Params::IsEmpty() const {
+ return !document_cookie && !desired_dpi && !max_shrink && !min_shrink &&
+ !dpi && printable_size.IsEmpty() && !selection_only &&
+ page_size.IsEmpty() && !margin_top && !margin_left;
+}
+
+ViewMsg_PrintPage_Params::ViewMsg_PrintPage_Params()
+ : page_number(0) {
+}
+
+ViewMsg_PrintPage_Params::~ViewMsg_PrintPage_Params() {
+}
+
+ViewMsg_PrintPages_Params::ViewMsg_PrintPages_Params() {
+}
+
+ViewMsg_PrintPages_Params::~ViewMsg_PrintPages_Params() {
+}
+
+ViewHostMsg_DidPrintPage_Params::ViewHostMsg_DidPrintPage_Params()
+ : data_size(0),
+ document_cookie(0),
+ page_number(0),
+ actual_shrink(0),
+ has_visible_overlays(false) {
+#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_DidPrintPage_Params::~ViewHostMsg_DidPrintPage_Params() {
+}
+
+ViewHostMsg_Audio_CreateStream_Params::ViewHostMsg_Audio_CreateStream_Params()
+ : packet_size(0) {
+}
+
+ViewHostMsg_Audio_CreateStream_Params::
+ ~ViewHostMsg_Audio_CreateStream_Params() {
+}
+
+ViewHostMsg_ShowPopup_Params::ViewHostMsg_ShowPopup_Params()
+ : item_height(0),
+ item_font_size(0),
+ selected_item(0),
+ right_aligned(false) {
+}
+
+ViewHostMsg_ShowPopup_Params::~ViewHostMsg_ShowPopup_Params() {
+}
+
+ViewHostMsg_ScriptedPrint_Params::ViewHostMsg_ScriptedPrint_Params()
+ : routing_id(0),
+ host_window_id(0),
+ cookie(0),
+ expected_pages_count(0),
+ has_selection(false),
+ use_overlays(false) {
+}
+
+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) {
+}
+
+ViewHostMsg_IDBFactoryOpen_Params::~ViewHostMsg_IDBFactoryOpen_Params() {
+}
+
+ViewHostMsg_IDBDatabaseCreateObjectStore_Params::
+ ViewHostMsg_IDBDatabaseCreateObjectStore_Params()
+ : response_id_(0),
+ auto_increment_(false) {
+}
+
+ViewHostMsg_IDBDatabaseCreateObjectStore_Params::
+ ~ViewHostMsg_IDBDatabaseCreateObjectStore_Params() {
+}
+
+ViewHostMsg_IDBObjectStoreOpenCursor_Params::
+ ViewHostMsg_IDBObjectStoreOpenCursor_Params()
+ : response_id_(0),
+ flags_(0),
+ direction_(0),
+ idb_object_store_id_(0),
+ transaction_id_(0) {
+}
+
+ViewHostMsg_IDBObjectStoreOpenCursor_Params::
+ ~ViewHostMsg_IDBObjectStoreOpenCursor_Params() {
+}
+
+ViewMsg_ExecuteCode_Params::ViewMsg_ExecuteCode_Params() {
+}
+
+ViewMsg_ExecuteCode_Params::ViewMsg_ExecuteCode_Params(
+ int request_id,
+ const std::string& extension_id,
+ const std::vector<URLPattern>& host_permissions,
+ bool is_javascript,
+ const std::string& code,
+ bool all_frames)
+ : request_id(request_id), extension_id(extension_id),
+ host_permissions(host_permissions), is_javascript(is_javascript),
+ code(code), all_frames(all_frames) {
+}
+
+ViewMsg_ExecuteCode_Params::~ViewMsg_ExecuteCode_Params() {
+}
+
+ViewHostMsg_CreateWorker_Params::ViewHostMsg_CreateWorker_Params()
+ : is_shared(false),
+ document_id(0),
+ render_view_route_id(0),
+ route_id(0),
+ parent_appcache_host_id(0),
+ script_resource_appcache_id(0) {
+}
+
+ViewHostMsg_CreateWorker_Params::~ViewHostMsg_CreateWorker_Params() {
+}
+
+ViewHostMsg_ShowNotification_Params::ViewHostMsg_ShowNotification_Params()
+ : is_html(false),
+ direction(WebKit::WebTextDirectionDefault),
+ notification_id(0) {
+}
+
+ViewHostMsg_ShowNotification_Params::~ViewHostMsg_ShowNotification_Params() {
+}
+
+ViewMsg_New_Params::ViewMsg_New_Params()
+ : parent_window(0),
+ view_id(0),
+ session_storage_namespace_id(0) {
+}
+
+ViewMsg_New_Params::~ViewMsg_New_Params() {
+}
+
+ViewHostMsg_CreateWindow_Params::ViewHostMsg_CreateWindow_Params()
+ : opener_id(0),
+ user_gesture(false),
+ window_container_type(WINDOW_CONTAINER_TYPE_NORMAL),
+ session_storage_namespace_id(0) {
+}
+
+ViewHostMsg_CreateWindow_Params::~ViewHostMsg_CreateWindow_Params() {
+}
+
+ViewHostMsg_RunFileChooser_Params::ViewHostMsg_RunFileChooser_Params()
+ : mode(Open) {
+}
+
+ViewHostMsg_RunFileChooser_Params::~ViewHostMsg_RunFileChooser_Params() {
+}
+
+ViewMsg_ExtensionRendererInfo::ViewMsg_ExtensionRendererInfo()
+ : location(Extension::INVALID) {
+}
+
+ViewMsg_ExtensionRendererInfo::~ViewMsg_ExtensionRendererInfo() {
+}
+
+ViewMsg_ExtensionsUpdated_Params::ViewMsg_ExtensionsUpdated_Params() {
+}
+
+ViewMsg_ExtensionsUpdated_Params::~ViewMsg_ExtensionsUpdated_Params() {
+}
+
+ViewMsg_DeviceOrientationUpdated_Params::
+ ViewMsg_DeviceOrientationUpdated_Params()
+ : can_provide_alpha(false),
+ alpha(0),
+ can_provide_beta(false),
+ beta(0),
+ can_provide_gamma(false),
+ gamma(0) {
+}
+
+ViewMsg_DeviceOrientationUpdated_Params::
+ ~ViewMsg_DeviceOrientationUpdated_Params() {
+}
+
+ViewHostMsg_DomMessage_Params::ViewHostMsg_DomMessage_Params()
+ : request_id(0),
+ has_callback(false),
+ user_gesture(false) {
+}
+
+ViewHostMsg_DomMessage_Params::~ViewHostMsg_DomMessage_Params() {
+}
+
+namespace IPC {
+
+// Self contained templates which are only used inside serializing Params
+// structs.
+template<>
+struct ParamTraits<ViewMsg_Navigate_Params::NavigationType> {
+ typedef ViewMsg_Navigate_Params::NavigationType 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<ViewMsg_Navigate_Params::NavigationType>(type);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ std::string event;
+ switch (p) {
+ case ViewMsg_Navigate_Params::RELOAD:
+ event = "NavigationType_RELOAD";
+ break;
+
+ case ViewMsg_Navigate_Params::RELOAD_IGNORING_CACHE:
+ event = "NavigationType_RELOAD_IGNORING_CACHE";
+ break;
+
+ case ViewMsg_Navigate_Params::RESTORE:
+ event = "NavigationType_RESTORE";
+ break;
+
+ case ViewMsg_Navigate_Params::NORMAL:
+ event = "NavigationType_NORMA";
+ break;
+
+ default:
+ event = "NavigationType_UNKNOWN";
+ break;
+ }
+ LogParam(event, l);
+ }
+};
+
+template <>
+struct ParamTraits<ResourceType::Type> {
+ typedef ResourceType::Type 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) || !ResourceType::ValidType(type))
+ return false;
+ *p = ResourceType::FromInt(type);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ std::string type;
+ switch (p) {
+ case ResourceType::MAIN_FRAME:
+ type = "MAIN_FRAME";
+ break;
+ case ResourceType::SUB_FRAME:
+ type = "SUB_FRAME";
+ break;
+ case ResourceType::SUB_RESOURCE:
+ type = "SUB_RESOURCE";
+ break;
+ case ResourceType::OBJECT:
+ type = "OBJECT";
+ break;
+ case ResourceType::MEDIA:
+ type = "MEDIA";
+ break;
+ default:
+ type = "UNKNOWN";
+ break;
+ }
+
+ LogParam(type, l);
+ }
+};
+
+template<>
+struct ParamTraits<NavigationGesture> {
+ typedef NavigationGesture 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<NavigationGesture>(type);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ std::string event;
+ switch (p) {
+ case NavigationGestureUser:
+ event = "GESTURE_USER";
+ break;
+ case NavigationGestureAuto:
+ event = "GESTURE_AUTO";
+ break;
+ default:
+ event = "GESTURE_UNKNOWN";
+ break;
+ }
+ LogParam(event, l);
+ }
+};
+
+// Traits for AudioManager::Format.
+template <>
+struct ParamTraits<AudioParameters::Format> {
+ typedef AudioParameters::Format 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<AudioParameters::Format>(type);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ std::string format;
+ switch (p) {
+ case AudioParameters::AUDIO_PCM_LINEAR:
+ format = "AUDIO_PCM_LINEAR";
+ break;
+ case AudioParameters::AUDIO_PCM_LOW_LATENCY:
+ format = "AUDIO_PCM_LOW_LATENCY";
+ break;
+ case AudioParameters::AUDIO_MOCK:
+ format = "AUDIO_MOCK";
+ break;
+ default:
+ format = "AUDIO_LAST_FORMAT";
+ break;
+ }
+ LogParam(format, l);
+ }
+};
+
+template <>
+struct ParamTraits<WindowContainerType> {
+ typedef WindowContainerType param_type;
+ static void Write(Message* m, const param_type& p) {
+ int val = static_cast<int>(p);
+ WriteParam(m, val);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ int val = 0;
+ if (!ReadParam(m, iter, &val) ||
+ val < WINDOW_CONTAINER_TYPE_NORMAL ||
+ val >= WINDOW_CONTAINER_TYPE_MAX_VALUE)
+ return false;
+ *p = static_cast<param_type>(val);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ ParamTraits<int>::Log(static_cast<int>(p), l);
+ }
+};
+
+template <>
+struct ParamTraits<Extension::Location> {
+ typedef Extension::Location param_type;
+ static void Write(Message* m, const param_type& p) {
+ int val = static_cast<int>(p);
+ WriteParam(m, val);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ int val = 0;
+ if (!ReadParam(m, iter, &val) ||
+ val < Extension::INVALID ||
+ val > Extension::EXTERNAL_PREF_DOWNLOAD)
+ return false;
+ *p = static_cast<param_type>(val);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ ParamTraits<int>::Log(static_cast<int>(p), l);
+ }
+};
+
+template <>
+struct ParamTraits
+ <ViewHostMsg_AccessibilityNotification_Params::NotificationType> {
+ typedef ViewHostMsg_AccessibilityNotification_Params params;
+ typedef params::NotificationType param_type;
+ static void Write(Message* m, const param_type& p) {
+ int val = static_cast<int>(p);
+ WriteParam(m, val);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ int val = 0;
+ if (!ReadParam(m, iter, &val) ||
+ val < params::NOTIFICATION_TYPE_CHECK_STATE_CHANGED ||
+ val > params::NOTIFICATION_TYPE_VALUE_CHANGED) {
+ return false;
+ }
+ *p = static_cast<param_type>(val);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ ParamTraits<int>::Log(static_cast<int>(p), l);
+ }
+};
+
+
+void ParamTraits<ViewMsg_Navigate_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.page_id);
+ WriteParam(m, p.pending_history_list_offset);
+ WriteParam(m, p.current_history_list_offset);
+ WriteParam(m, p.current_history_list_length);
+ WriteParam(m, p.url);
+ WriteParam(m, p.referrer);
+ WriteParam(m, p.transition);
+ WriteParam(m, p.state);
+ WriteParam(m, p.navigation_type);
+ WriteParam(m, p.request_time);
+}
+
+bool ParamTraits<ViewMsg_Navigate_Params>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->page_id) &&
+ ReadParam(m, iter, &p->pending_history_list_offset) &&
+ ReadParam(m, iter, &p->current_history_list_offset) &&
+ ReadParam(m, iter, &p->current_history_list_length) &&
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->referrer) &&
+ ReadParam(m, iter, &p->transition) &&
+ ReadParam(m, iter, &p->state) &&
+ ReadParam(m, iter, &p->navigation_type) &&
+ ReadParam(m, iter, &p->request_time);
+}
+
+void ParamTraits<ViewMsg_Navigate_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.page_id, l);
+ l->append(", ");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.transition, l);
+ l->append(", ");
+ LogParam(p.state, l);
+ l->append(", ");
+ LogParam(p.navigation_type, l);
+ l->append(", ");
+ LogParam(p.request_time, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewMsg_AudioStreamState_Params>::Write(Message* m,
+ const param_type& p) {
+ m->WriteInt(p.state);
+}
+
+bool ParamTraits<ViewMsg_AudioStreamState_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ p->state = static_cast<ViewMsg_AudioStreamState_Params::State>(type);
+ return true;
+}
+
+void ParamTraits<ViewMsg_AudioStreamState_Params>::Log(const param_type& p,
+ std::string* l) {
+ std::string state;
+ switch (p.state) {
+ case ViewMsg_AudioStreamState_Params::kPlaying:
+ state = "ViewMsg_AudioStreamState_Params::kPlaying";
+ break;
+ case ViewMsg_AudioStreamState_Params::kPaused:
+ state = "ViewMsg_AudioStreamState_Params::kPaused";
+ break;
+ case ViewMsg_AudioStreamState_Params::kError:
+ state = "ViewMsg_AudioStreamState_Params::kError";
+ break;
+ default:
+ state = "UNKNOWN";
+ break;
+ }
+ LogParam(state, l);
+}
+
+void ParamTraits<ViewMsg_StopFinding_Params>::Write(Message* m,
+ const param_type& p) {
+ m->WriteInt(p.action);
+}
+
+bool ParamTraits<ViewMsg_StopFinding_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ p->action = static_cast<ViewMsg_StopFinding_Params::Action>(type);
+ return true;
+}
+
+void ParamTraits<ViewMsg_StopFinding_Params>::Log(const param_type& p,
+ std::string* l) {
+ std::string action;
+ switch (p.action) {
+ case ViewMsg_StopFinding_Params::kClearSelection:
+ action = "ViewMsg_StopFinding_Params::kClearSelection";
+ break;
+ case ViewMsg_StopFinding_Params::kKeepSelection:
+ action = "ViewMsg_StopFinding_Params::kKeepSelection";
+ break;
+ case ViewMsg_StopFinding_Params::kActivateSelection:
+ action = "ViewMsg_StopFinding_Params::kActivateSelection";
+ break;
+ default:
+ action = "UNKNOWN";
+ break;
+ }
+ LogParam(action, l);
+}
+
+void ParamTraits<ViewHostMsg_GetSearchProviderInstallState_Params>::Write(
+ Message* m, const param_type& p) {
+ m->WriteInt(p.state);
+}
+
+bool ParamTraits<ViewHostMsg_GetSearchProviderInstallState_Params>::Read(
+ const Message* m, void** iter, param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ p->state = static_cast<param_type::State>(type);
+ return true;
+}
+
+void ParamTraits<ViewHostMsg_GetSearchProviderInstallState_Params>::Log(
+ const param_type& p, std::string* l) {
+ std::string state;
+ switch (p.state) {
+ case ViewHostMsg_GetSearchProviderInstallState_Params::DENIED:
+ state = "ViewHostMsg_GetSearchProviderInstallState_Params::DENIED";
+ break;
+ case ViewHostMsg_GetSearchProviderInstallState_Params::NOT_INSTALLED:
+ state =
+ "ViewHostMsg_GetSearchProviderInstallState_Params::NOT_INSTALLED";
+ break;
+ case ViewHostMsg_GetSearchProviderInstallState_Params::
+ INSTALLED_BUT_NOT_DEFAULT:
+ state = "ViewHostMsg_GetSearchProviderInstallState_Params::"
+ "INSTALLED_BUT_NOT_DEFAULT";
+ break;
+ case ViewHostMsg_GetSearchProviderInstallState_Params::
+ INSTALLED_AS_DEFAULT:
+ state = "ViewHostMsg_GetSearchProviderInstallState_Params::"
+ "INSTALLED_AS_DEFAULT";
+ break;
+ default:
+ state = "UNKNOWN";
+ break;
+ }
+ LogParam(state, l);
+}
+
+void ParamTraits<ViewHostMsg_FrameNavigate_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.page_id);
+ WriteParam(m, p.url);
+ WriteParam(m, p.referrer);
+ WriteParam(m, p.transition);
+ WriteParam(m, p.redirects);
+ WriteParam(m, p.should_update_history);
+ WriteParam(m, p.searchable_form_url);
+ WriteParam(m, p.searchable_form_encoding);
+ WriteParam(m, p.password_form);
+ WriteParam(m, p.security_info);
+ WriteParam(m, p.gesture);
+ WriteParam(m, p.contents_mime_type);
+ WriteParam(m, p.is_post);
+ WriteParam(m, p.is_content_filtered);
+ WriteParam(m, p.was_within_same_page);
+ WriteParam(m, p.http_status_code);
+}
+
+bool ParamTraits<ViewHostMsg_FrameNavigate_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->page_id) &&
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->referrer) &&
+ ReadParam(m, iter, &p->transition) &&
+ ReadParam(m, iter, &p->redirects) &&
+ ReadParam(m, iter, &p->should_update_history) &&
+ ReadParam(m, iter, &p->searchable_form_url) &&
+ ReadParam(m, iter, &p->searchable_form_encoding) &&
+ ReadParam(m, iter, &p->password_form) &&
+ ReadParam(m, iter, &p->security_info) &&
+ ReadParam(m, iter, &p->gesture) &&
+ ReadParam(m, iter, &p->contents_mime_type) &&
+ ReadParam(m, iter, &p->is_post) &&
+ ReadParam(m, iter, &p->is_content_filtered) &&
+ ReadParam(m, iter, &p->was_within_same_page) &&
+ ReadParam(m, iter, &p->http_status_code);
+}
+
+void ParamTraits<ViewHostMsg_FrameNavigate_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.page_id, l);
+ l->append(", ");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.referrer, l);
+ l->append(", ");
+ LogParam(p.transition, l);
+ l->append(", ");
+ LogParam(p.redirects, l);
+ l->append(", ");
+ LogParam(p.should_update_history, l);
+ l->append(", ");
+ LogParam(p.searchable_form_url, l);
+ l->append(", ");
+ LogParam(p.searchable_form_encoding, l);
+ l->append(", ");
+ LogParam(p.password_form, l);
+ l->append(", ");
+ LogParam(p.security_info, l);
+ l->append(", ");
+ LogParam(p.gesture, l);
+ l->append(", ");
+ LogParam(p.contents_mime_type, l);
+ l->append(", ");
+ LogParam(p.is_post, l);
+ l->append(", ");
+ LogParam(p.is_content_filtered, l);
+ l->append(", ");
+ LogParam(p.was_within_same_page, l);
+ l->append(", ");
+ LogParam(p.http_status_code, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_UpdateRect_Params>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.bitmap);
+ WriteParam(m, p.bitmap_rect);
+ WriteParam(m, p.dx);
+ WriteParam(m, p.dy);
+ WriteParam(m, p.scroll_rect);
+ WriteParam(m, p.copy_rects);
+ WriteParam(m, p.view_size);
+ WriteParam(m, p.plugin_window_moves);
+ WriteParam(m, p.flags);
+}
+
+bool ParamTraits<ViewHostMsg_UpdateRect_Params>::Read(
+ const Message* m, void** iter, param_type* p) {
+ return
+ ReadParam(m, iter, &p->bitmap) &&
+ ReadParam(m, iter, &p->bitmap_rect) &&
+ ReadParam(m, iter, &p->dx) &&
+ ReadParam(m, iter, &p->dy) &&
+ ReadParam(m, iter, &p->scroll_rect) &&
+ ReadParam(m, iter, &p->copy_rects) &&
+ ReadParam(m, iter, &p->view_size) &&
+ ReadParam(m, iter, &p->plugin_window_moves) &&
+ ReadParam(m, iter, &p->flags);
+}
+
+void ParamTraits<ViewHostMsg_UpdateRect_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.bitmap, l);
+ l->append(", ");
+ LogParam(p.bitmap_rect, l);
+ l->append(", ");
+ LogParam(p.dx, l);
+ l->append(", ");
+ LogParam(p.dy, l);
+ l->append(", ");
+ LogParam(p.scroll_rect, l);
+ l->append(", ");
+ LogParam(p.copy_rects, l);
+ l->append(", ");
+ LogParam(p.view_size, l);
+ l->append(", ");
+ LogParam(p.plugin_window_moves, l);
+ l->append(", ");
+ LogParam(p.flags, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewMsg_ClosePage_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.closing_process_id);
+ WriteParam(m, p.closing_route_id);
+ WriteParam(m, p.for_cross_site_transition);
+ WriteParam(m, p.new_render_process_host_id);
+ WriteParam(m, p.new_request_id);
+}
+
+bool ParamTraits<ViewMsg_ClosePage_Params>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ return ReadParam(m, iter, &r->closing_process_id) &&
+ ReadParam(m, iter, &r->closing_route_id) &&
+ ReadParam(m, iter, &r->for_cross_site_transition) &&
+ ReadParam(m, iter, &r->new_render_process_host_id) &&
+ ReadParam(m, iter, &r->new_request_id);
+}
+
+void ParamTraits<ViewMsg_ClosePage_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.closing_process_id, l);
+ l->append(", ");
+ LogParam(p.closing_route_id, l);
+ l->append(", ");
+ LogParam(p.for_cross_site_transition, l);
+ l->append(", ");
+ LogParam(p.new_render_process_host_id, l);
+ l->append(", ");
+ LogParam(p.new_request_id, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_Resource_Request>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.method);
+ WriteParam(m, p.url);
+ WriteParam(m, p.first_party_for_cookies);
+ WriteParam(m, p.referrer);
+ WriteParam(m, p.frame_origin);
+ WriteParam(m, p.main_frame_origin);
+ WriteParam(m, p.headers);
+ WriteParam(m, p.load_flags);
+ WriteParam(m, p.origin_child_id);
+ WriteParam(m, p.resource_type);
+ WriteParam(m, p.request_context);
+ WriteParam(m, p.appcache_host_id);
+ WriteParam(m, p.upload_data);
+ WriteParam(m, p.download_to_file);
+ WriteParam(m, p.host_renderer_id);
+ WriteParam(m, p.host_render_view_id);
+}
+
+bool ParamTraits<ViewHostMsg_Resource_Request>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ return
+ ReadParam(m, iter, &r->method) &&
+ ReadParam(m, iter, &r->url) &&
+ ReadParam(m, iter, &r->first_party_for_cookies) &&
+ ReadParam(m, iter, &r->referrer) &&
+ ReadParam(m, iter, &r->frame_origin) &&
+ ReadParam(m, iter, &r->main_frame_origin) &&
+ ReadParam(m, iter, &r->headers) &&
+ ReadParam(m, iter, &r->load_flags) &&
+ ReadParam(m, iter, &r->origin_child_id) &&
+ ReadParam(m, iter, &r->resource_type) &&
+ ReadParam(m, iter, &r->request_context) &&
+ ReadParam(m, iter, &r->appcache_host_id) &&
+ ReadParam(m, iter, &r->upload_data) &&
+ ReadParam(m, iter, &r->download_to_file) &&
+ ReadParam(m, iter, &r->host_renderer_id) &&
+ ReadParam(m, iter, &r->host_render_view_id);
+}
+
+void ParamTraits<ViewHostMsg_Resource_Request>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.method, l);
+ l->append(", ");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.referrer, l);
+ l->append(", ");
+ LogParam(p.frame_origin, l);
+ l->append(", ");
+ LogParam(p.main_frame_origin, l);
+ l->append(", ");
+ LogParam(p.load_flags, l);
+ l->append(", ");
+ LogParam(p.origin_child_id, l);
+ l->append(", ");
+ LogParam(p.resource_type, l);
+ l->append(", ");
+ LogParam(p.request_context, l);
+ l->append(", ");
+ LogParam(p.appcache_host_id, l);
+ l->append(", ");
+ LogParam(p.download_to_file, l);
+ l->append(", ");
+ LogParam(p.host_renderer_id, l);
+ l->append(", ");
+ LogParam(p.host_render_view_id, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewMsg_Print_Params>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.page_size);
+ WriteParam(m, p.printable_size);
+ WriteParam(m, p.margin_top);
+ WriteParam(m, p.margin_left);
+ WriteParam(m, p.dpi);
+ WriteParam(m, p.min_shrink);
+ WriteParam(m, p.max_shrink);
+ WriteParam(m, p.desired_dpi);
+ WriteParam(m, p.document_cookie);
+ WriteParam(m, p.selection_only);
+}
+
+bool ParamTraits<ViewMsg_Print_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->page_size) &&
+ ReadParam(m, iter, &p->printable_size) &&
+ ReadParam(m, iter, &p->margin_top) &&
+ ReadParam(m, iter, &p->margin_left) &&
+ ReadParam(m, iter, &p->dpi) &&
+ ReadParam(m, iter, &p->min_shrink) &&
+ ReadParam(m, iter, &p->max_shrink) &&
+ ReadParam(m, iter, &p->desired_dpi) &&
+ ReadParam(m, iter, &p->document_cookie) &&
+ ReadParam(m, iter, &p->selection_only);
+}
+
+void ParamTraits<ViewMsg_Print_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<ViewMsg_Print_Params>");
+}
+
+void ParamTraits<ViewMsg_PrintPage_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.params);
+ WriteParam(m, p.page_number);
+}
+
+bool ParamTraits<ViewMsg_PrintPage_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->params) &&
+ ReadParam(m, iter, &p->page_number);
+}
+
+void ParamTraits<ViewMsg_PrintPage_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<ViewMsg_PrintPage_Params>");
+}
+
+void ParamTraits<ViewMsg_PrintPages_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.params);
+ WriteParam(m, p.pages);
+}
+
+bool ParamTraits<ViewMsg_PrintPages_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->params) &&
+ ReadParam(m, iter, &p->pages);
+}
+
+void ParamTraits<ViewMsg_PrintPages_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<ViewMsg_PrintPages_Params>");
+}
+
+void ParamTraits<ViewHostMsg_DidPrintPage_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.metafile_data_handle);
+ WriteParam(m, p.data_size);
+ WriteParam(m, p.document_cookie);
+ WriteParam(m, p.page_number);
+ WriteParam(m, p.actual_shrink);
+ WriteParam(m, p.page_size);
+ WriteParam(m, p.content_area);
+ WriteParam(m, p.has_visible_overlays);
+}
+
+bool ParamTraits<ViewHostMsg_DidPrintPage_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) &&
+ ReadParam(m, iter, &p->page_number) &&
+ ReadParam(m, iter, &p->actual_shrink) &&
+ ReadParam(m, iter, &p->page_size) &&
+ ReadParam(m, iter, &p->content_area) &&
+ ReadParam(m, iter, &p->has_visible_overlays);
+}
+
+void ParamTraits<ViewHostMsg_DidPrintPage_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<ViewHostMsg_DidPrintPage_Params>");
+}
+
+void ParamTraits<ViewHostMsg_Audio_CreateStream_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.params.format);
+ WriteParam(m, p.params.channels);
+ WriteParam(m, p.params.sample_rate);
+ WriteParam(m, p.params.bits_per_sample);
+ WriteParam(m, p.packet_size);
+}
+
+bool ParamTraits<ViewHostMsg_Audio_CreateStream_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->params.format) &&
+ ReadParam(m, iter, &p->params.channels) &&
+ ReadParam(m, iter, &p->params.sample_rate) &&
+ ReadParam(m, iter, &p->params.bits_per_sample) &&
+ ReadParam(m, iter, &p->packet_size);
+}
+
+void ParamTraits<ViewHostMsg_Audio_CreateStream_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("<ViewHostMsg_Audio_CreateStream_Params>(");
+ LogParam(p.params.format, l);
+ l->append(", ");
+ LogParam(p.params.channels, l);
+ l->append(", ");
+ LogParam(p.params.sample_rate, l);
+ l->append(", ");
+ LogParam(p.params.bits_per_sample, l);
+ l->append(", ");
+ LogParam(p.packet_size, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_ShowPopup_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.bounds);
+ WriteParam(m, p.item_height);
+ WriteParam(m, p.item_font_size);
+ WriteParam(m, p.selected_item);
+ WriteParam(m, p.popup_items);
+ WriteParam(m, p.right_aligned);
+}
+
+bool ParamTraits<ViewHostMsg_ShowPopup_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->bounds) &&
+ ReadParam(m, iter, &p->item_height) &&
+ ReadParam(m, iter, &p->item_font_size) &&
+ ReadParam(m, iter, &p->selected_item) &&
+ ReadParam(m, iter, &p->popup_items) &&
+ ReadParam(m, iter, &p->right_aligned);
+}
+
+void ParamTraits<ViewHostMsg_ShowPopup_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.bounds, l);
+ l->append(", ");
+ LogParam(p.item_height, l);
+ l->append(", ");
+ LogParam(p.item_font_size, l);
+ l->append(", ");
+ LogParam(p.selected_item, l);
+ l->append(", ");
+ LogParam(p.popup_items, l);
+ l->append(", ");
+ LogParam(p.right_aligned, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_ScriptedPrint_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.routing_id);
+ WriteParam(m, p.host_window_id);
+ WriteParam(m, p.cookie);
+ WriteParam(m, p.expected_pages_count);
+ WriteParam(m, p.has_selection);
+ WriteParam(m, p.use_overlays);
+}
+
+bool ParamTraits<ViewHostMsg_ScriptedPrint_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->routing_id) &&
+ ReadParam(m, iter, &p->host_window_id) &&
+ ReadParam(m, iter, &p->cookie) &&
+ ReadParam(m, iter, &p->expected_pages_count) &&
+ ReadParam(m, iter, &p->has_selection) &&
+ ReadParam(m, iter, &p->use_overlays);
+}
+
+void ParamTraits<ViewHostMsg_ScriptedPrint_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.routing_id, l);
+ l->append(", ");
+ LogParam(p.host_window_id, l);
+ l->append(", ");
+ LogParam(p.cookie, l);
+ l->append(", ");
+ LogParam(p.expected_pages_count, l);
+ l->append(", ");
+ LogParam(p.has_selection, l);
+ l->append(",");
+ LogParam(p.use_overlays, l);
+ 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_);
+}
+
+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_);
+}
+
+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(")");
+}
+
+void ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.response_id_);
+ WriteParam(m, p.name_);
+ WriteParam(m, p.key_path_);
+ WriteParam(m, p.auto_increment_);
+ 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->response_id_) &&
+ ReadParam(m, iter, &p->name_) &&
+ ReadParam(m, iter, &p->key_path_) &&
+ ReadParam(m, iter, &p->auto_increment_) &&
+ ReadParam(m, iter, &p->idb_database_id_);
+}
+
+void ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.response_id_, 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.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.left_key_);
+ WriteParam(m, p.right_key_);
+ WriteParam(m, p.key_flags_);
+ 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->left_key_) &&
+ ReadParam(m, iter, &p->right_key_) &&
+ ReadParam(m, iter, &p->key_flags_) &&
+ 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.left_key_, l);
+ l->append(", ");
+ LogParam(p.right_key_, l);
+ l->append(", ");
+ LogParam(p.key_flags_, 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.response_id_);
+ WriteParam(m, p.name_);
+ WriteParam(m, p.key_path_);
+ WriteParam(m, p.unique_);
+ 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->response_id_) &&
+ ReadParam(m, iter, &p->name_) &&
+ ReadParam(m, iter, &p->key_path_) &&
+ ReadParam(m, iter, &p->unique_) &&
+ 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.response_id_, l);
+ l->append(", ");
+ LogParam(p.name_, l);
+ l->append(", ");
+ LogParam(p.key_path_, l);
+ l->append(", ");
+ LogParam(p.unique_, 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.left_key_);
+ WriteParam(m, p.right_key_);
+ WriteParam(m, p.flags_);
+ 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->left_key_) &&
+ ReadParam(m, iter, &p->right_key_) &&
+ ReadParam(m, iter, &p->flags_) &&
+ 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.left_key_, l);
+ l->append(", ");
+ LogParam(p.right_key_, l);
+ l->append(", ");
+ LogParam(p.flags_, 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);
+ WriteParam(m, p.extension_id);
+ WriteParam(m, p.host_permissions);
+ WriteParam(m, p.is_javascript);
+ WriteParam(m, p.code);
+ WriteParam(m, p.all_frames);
+}
+
+bool ParamTraits<ViewMsg_ExecuteCode_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->request_id) &&
+ ReadParam(m, iter, &p->extension_id) &&
+ ReadParam(m, iter, &p->host_permissions) &&
+ ReadParam(m, iter, &p->is_javascript) &&
+ ReadParam(m, iter, &p->code) &&
+ ReadParam(m, iter, &p->all_frames);
+}
+
+void ParamTraits<ViewMsg_ExecuteCode_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<ViewMsg_ExecuteCode_Params>");
+}
+
+void ParamTraits<ViewHostMsg_CreateWorker_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.url);
+ WriteParam(m, p.is_shared);
+ WriteParam(m, p.name);
+ WriteParam(m, p.document_id);
+ WriteParam(m, p.render_view_route_id);
+ WriteParam(m, p.route_id);
+ WriteParam(m, p.parent_appcache_host_id);
+ WriteParam(m, p.script_resource_appcache_id);
+}
+
+bool ParamTraits<ViewHostMsg_CreateWorker_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->is_shared) &&
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->document_id) &&
+ ReadParam(m, iter, &p->render_view_route_id) &&
+ ReadParam(m, iter, &p->route_id) &&
+ ReadParam(m, iter, &p->parent_appcache_host_id) &&
+ ReadParam(m, iter, &p->script_resource_appcache_id);
+}
+
+void ParamTraits<ViewHostMsg_CreateWorker_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.is_shared, l);
+ l->append(", ");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.document_id, l);
+ l->append(", ");
+ LogParam(p.render_view_route_id, l);
+ l->append(",");
+ LogParam(p.route_id, l);
+ l->append(", ");
+ LogParam(p.parent_appcache_host_id, l);
+ l->append(",");
+ LogParam(p.script_resource_appcache_id, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_ShowNotification_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.origin);
+ WriteParam(m, p.is_html);
+ WriteParam(m, p.contents_url);
+ WriteParam(m, p.icon_url);
+ WriteParam(m, p.title);
+ WriteParam(m, p.body);
+ WriteParam(m, p.direction);
+ WriteParam(m, p.replace_id);
+ WriteParam(m, p.notification_id);
+}
+
+bool ParamTraits<ViewHostMsg_ShowNotification_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->origin) &&
+ ReadParam(m, iter, &p->is_html) &&
+ ReadParam(m, iter, &p->contents_url) &&
+ ReadParam(m, iter, &p->icon_url) &&
+ ReadParam(m, iter, &p->title) &&
+ ReadParam(m, iter, &p->body) &&
+ ReadParam(m, iter, &p->direction) &&
+ ReadParam(m, iter, &p->replace_id) &&
+ ReadParam(m, iter, &p->notification_id);
+}
+
+void ParamTraits<ViewHostMsg_ShowNotification_Params>::Log(
+ const param_type &p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.origin, l);
+ l->append(", ");
+ LogParam(p.is_html, l);
+ l->append(", ");
+ LogParam(p.contents_url, l);
+ l->append(", ");
+ LogParam(p.icon_url, l);
+ l->append(", ");
+ LogParam(p.title, l);
+ l->append(",");
+ LogParam(p.body, l);
+ l->append(",");
+ LogParam(p.direction, l);
+ l->append(",");
+ LogParam(p.replace_id, l);
+ l->append(",");
+ LogParam(p.notification_id, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewMsg_New_Params>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.parent_window);
+ WriteParam(m, p.renderer_preferences);
+ WriteParam(m, p.web_preferences);
+ WriteParam(m, p.view_id);
+ WriteParam(m, p.session_storage_namespace_id);
+ WriteParam(m, p.frame_name);
+}
+
+bool ParamTraits<ViewMsg_New_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->parent_window) &&
+ ReadParam(m, iter, &p->renderer_preferences) &&
+ ReadParam(m, iter, &p->web_preferences) &&
+ ReadParam(m, iter, &p->view_id) &&
+ ReadParam(m, iter, &p->session_storage_namespace_id) &&
+ ReadParam(m, iter, &p->frame_name);
+}
+
+void ParamTraits<ViewMsg_New_Params>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.parent_window, l);
+ l->append(", ");
+ LogParam(p.renderer_preferences, l);
+ l->append(", ");
+ LogParam(p.web_preferences, l);
+ l->append(", ");
+ LogParam(p.view_id, l);
+ l->append(", ");
+ LogParam(p.session_storage_namespace_id, l);
+ l->append(", ");
+ LogParam(p.frame_name, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_CreateWindow_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.opener_id);
+ WriteParam(m, p.user_gesture);
+ WriteParam(m, p.window_container_type);
+ WriteParam(m, p.session_storage_namespace_id);
+ WriteParam(m, p.frame_name);
+}
+
+bool ParamTraits<ViewHostMsg_CreateWindow_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->opener_id) &&
+ ReadParam(m, iter, &p->user_gesture) &&
+ ReadParam(m, iter, &p->window_container_type) &&
+ ReadParam(m, iter, &p->session_storage_namespace_id) &&
+ ReadParam(m, iter, &p->frame_name);
+}
+
+void ParamTraits<ViewHostMsg_CreateWindow_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.opener_id, l);
+ l->append(", ");
+ LogParam(p.user_gesture, l);
+ l->append(", ");
+ LogParam(p.window_container_type, l);
+ l->append(", ");
+ LogParam(p.session_storage_namespace_id, l);
+ l->append(", ");
+ LogParam(p.frame_name, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_RunFileChooser_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, static_cast<int>(p.mode));
+ WriteParam(m, p.title);
+ WriteParam(m, p.default_file_name);
+ WriteParam(m, p.accept_types);
+}
+
+bool ParamTraits<ViewHostMsg_RunFileChooser_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ int mode;
+ if (!ReadParam(m, iter, &mode))
+ return false;
+ if (mode != param_type::Open &&
+ mode != param_type::OpenMultiple &&
+ mode != param_type::OpenFolder &&
+ mode != param_type::Save)
+ return false;
+ p->mode = static_cast<param_type::Mode>(mode);
+ return
+ ReadParam(m, iter, &p->title) &&
+ ReadParam(m, iter, &p->default_file_name) &&
+ ReadParam(m, iter, &p->accept_types);
+};
+
+void ParamTraits<ViewHostMsg_RunFileChooser_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ switch (p.mode) {
+ case param_type::Open:
+ l->append("(Open, ");
+ break;
+ case param_type::OpenMultiple:
+ l->append("(OpenMultiple, ");
+ break;
+ case param_type::OpenFolder:
+ l->append("(OpenFolder, ");
+ break;
+ case param_type::Save:
+ l->append("(Save, ");
+ break;
+ default:
+ l->append("(UNKNOWN, ");
+ }
+ LogParam(p.title, l);
+ l->append(", ");
+ LogParam(p.default_file_name, l);
+ l->append(", ");
+ LogParam(p.accept_types, l);
+}
+
+void ParamTraits<ViewMsg_ExtensionRendererInfo>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.id);
+ WriteParam(m, p.web_extent);
+ WriteParam(m, p.name);
+ WriteParam(m, p.icon_url);
+ WriteParam(m, p.location);
+}
+
+bool ParamTraits<ViewMsg_ExtensionRendererInfo>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->id) &&
+ ReadParam(m, iter, &p->web_extent) &&
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->icon_url) &&
+ ReadParam(m, iter, &p->location);
+}
+
+void ParamTraits<ViewMsg_ExtensionRendererInfo>::Log(const param_type& p,
+ std::string* l) {
+ LogParam(p.id, l);
+}
+
+void ParamTraits<ViewMsg_ExtensionsUpdated_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.extensions);
+}
+
+bool ParamTraits<ViewMsg_ExtensionsUpdated_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->extensions);
+}
+
+void ParamTraits<ViewMsg_ExtensionsUpdated_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ LogParam(p.extensions, l);
+}
+
+void ParamTraits<ViewMsg_DeviceOrientationUpdated_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.can_provide_alpha);
+ WriteParam(m, p.alpha);
+ WriteParam(m, p.can_provide_beta);
+ WriteParam(m, p.beta);
+ WriteParam(m, p.can_provide_gamma);
+ WriteParam(m, p.gamma);
+}
+
+bool ParamTraits<ViewMsg_DeviceOrientationUpdated_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->can_provide_alpha) &&
+ ReadParam(m, iter, &p->alpha) &&
+ ReadParam(m, iter, &p->can_provide_beta) &&
+ ReadParam(m, iter, &p->beta) &&
+ ReadParam(m, iter, &p->can_provide_gamma) &&
+ ReadParam(m, iter, &p->gamma);
+}
+
+void ParamTraits<ViewMsg_DeviceOrientationUpdated_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.can_provide_alpha, l);
+ l->append(", ");
+ LogParam(p.alpha, l);
+ l->append(", ");
+ LogParam(p.can_provide_beta, l);
+ l->append(", ");
+ LogParam(p.beta, l);
+ l->append(", ");
+ LogParam(p.can_provide_gamma, l);
+ l->append(", ");
+ LogParam(p.gamma, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_DomMessage_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.arguments);
+ WriteParam(m, p.source_url);
+ WriteParam(m, p.request_id);
+ WriteParam(m, p.has_callback);
+ WriteParam(m, p.user_gesture);
+}
+
+bool ParamTraits<ViewHostMsg_DomMessage_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->arguments) &&
+ ReadParam(m, iter, &p->source_url) &&
+ ReadParam(m, iter, &p->request_id) &&
+ ReadParam(m, iter, &p->has_callback) &&
+ ReadParam(m, iter, &p->user_gesture);
+}
+
+void ParamTraits<ViewHostMsg_DomMessage_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.arguments, l);
+ l->append(", ");
+ LogParam(p.source_url, l);
+ l->append(", ");
+ LogParam(p.request_id, l);
+ l->append(", ");
+ LogParam(p.has_callback, l);
+ l->append(", ");
+ LogParam(p.user_gesture, l);
+ l->append(")");
+}
+
+void ParamTraits<base::file_util_proxy::Entry>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.is_directory);
+}
+
+bool ParamTraits<base::file_util_proxy::Entry>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->is_directory);
+}
+
+void ParamTraits<base::file_util_proxy::Entry>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.is_directory, l);
+ l->append(")");
+}
+
+void ParamTraits<ViewHostMsg_AccessibilityNotification_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.notification_type);
+ WriteParam(m, p.acc_obj);
+}
+
+bool ParamTraits<ViewHostMsg_AccessibilityNotification_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->notification_type) &&
+ ReadParam(m, iter, &p->acc_obj);
+}
+
+void ParamTraits<ViewHostMsg_AccessibilityNotification_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.notification_type, l);
+ l->append(", ");
+ LogParam(p.acc_obj, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h
new file mode 100644
index 0000000..5c2b0d1
--- /dev/null
+++ b/chrome/common/render_messages_params.h
@@ -0,0 +1,1275 @@
+// Copyright (c) 2010 The Chromium Authors. All 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_RENDER_MESSAGES_PARAMS_H_
+#define CHROME_COMMON_RENDER_MESSAGES_PARAMS_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "app/surface/transport_dib.h"
+#include "base/file_path.h"
+#include "base/file_util_proxy.h"
+#include "base/ref_counted.h"
+#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"
+#include "chrome/common/renderer_preferences.h"
+#include "chrome/common/serialized_script_value.h"
+#include "chrome/common/window_container_type.h"
+#include "googleurl/src/gurl.h"
+#include "ipc/ipc_param_traits.h"
+#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"
+
+// TODO(erg): Split this file into $1_db_params.h, $1_audio_params.h,
+// $1_print_params.h and $1_render_params.h.
+
+namespace net {
+class UploadData;
+}
+
+// Parameters structure for ViewMsg_Navigate, which has too many data
+// parameters to be reasonably put in a predefined IPC message.
+struct ViewMsg_Navigate_Params {
+ enum NavigationType {
+ // Reload the page.
+ RELOAD,
+
+ // Reload the page, ignoring any cache entries.
+ RELOAD_IGNORING_CACHE,
+
+ // The navigation is the result of session restore and should honor the
+ // page's cache policy while restoring form state. This is set to true if
+ // restoring a tab/session from the previous session and the previous
+ // session did not crash. If this is not set and the page was restored then
+ // the page's cache policy is ignored and we load from the cache.
+ RESTORE,
+
+ // Navigation type not categorized by the other types.
+ NORMAL
+ };
+
+ ViewMsg_Navigate_Params();
+ ~ViewMsg_Navigate_Params();
+
+ // The page_id for this navigation, or -1 if it is a new navigation. Back,
+ // Forward, and Reload navigations should have a valid page_id. If the load
+ // succeeds, then this page_id will be reflected in the resultant
+ // ViewHostMsg_FrameNavigate message.
+ int32 page_id;
+
+ // If page_id is -1, then pending_history_list_offset will also be -1.
+ // Otherwise, it contains the offset into the history list corresponding to
+ // the current navigation.
+ int pending_history_list_offset;
+
+ // Informs the RenderView of where its current page contents reside in
+ // session history and the total size of the session history list.
+ int current_history_list_offset;
+ int current_history_list_length;
+
+ // The URL to load.
+ GURL url;
+
+ // The URL to send in the "Referer" header field. Can be empty if there is
+ // no referrer.
+ GURL referrer;
+
+ // The type of transition.
+ PageTransition::Type transition;
+
+ // Opaque history state (received by ViewHostMsg_UpdateState).
+ std::string state;
+
+ // Type of navigation.
+ NavigationType navigation_type;
+
+ // The time the request was created
+ base::Time request_time;
+};
+
+// Current status of the audio output stream in the browser process. Browser
+// sends information about the current playback state and error to the
+// renderer process using this type.
+struct ViewMsg_AudioStreamState_Params {
+ enum State {
+ kPlaying,
+ kPaused,
+ kError
+ };
+
+ ViewMsg_AudioStreamState_Params()
+ : state(kPlaying) {
+ }
+
+ explicit ViewMsg_AudioStreamState_Params(State s)
+ : state(s) {
+ }
+
+ // Carries the current playback state.
+ State state;
+};
+
+// The user has completed a find-in-page; this type defines what actions the
+// renderer should take next.
+struct ViewMsg_StopFinding_Params {
+ enum Action {
+ kClearSelection,
+ kKeepSelection,
+ kActivateSelection
+ };
+
+ ViewMsg_StopFinding_Params()
+ : action(kClearSelection) {
+ }
+
+ // The action that should be taken when the find is completed.
+ Action action;
+};
+
+// The install state of the search provider (not installed, installed, default).
+struct ViewHostMsg_GetSearchProviderInstallState_Params {
+ enum State {
+ // Equates to an access denied error.
+ DENIED = -1,
+
+ // DON'T CHANGE THE VALUES BELOW.
+ // All of the following values are manidated by the
+ // spec for window.external.IsSearchProviderInstalled.
+
+ // The search provider is not installed.
+ NOT_INSTALLED = 0,
+
+ // The search provider is in the user's set but is not
+ INSTALLED_BUT_NOT_DEFAULT = 1,
+
+ // The search provider is set as the user's default.
+ INSTALLED_AS_DEFAULT = 2
+ };
+ State state;
+
+ ViewHostMsg_GetSearchProviderInstallState_Params()
+ : state(DENIED) {
+ }
+
+ explicit ViewHostMsg_GetSearchProviderInstallState_Params(State s)
+ : state(s) {
+ }
+
+ static ViewHostMsg_GetSearchProviderInstallState_Params Denied() {
+ return ViewHostMsg_GetSearchProviderInstallState_Params(DENIED);
+ }
+
+ static ViewHostMsg_GetSearchProviderInstallState_Params NotInstalled() {
+ return ViewHostMsg_GetSearchProviderInstallState_Params(NOT_INSTALLED);
+ }
+
+ static ViewHostMsg_GetSearchProviderInstallState_Params
+ InstallButNotDefault() {
+ return ViewHostMsg_GetSearchProviderInstallState_Params(
+ INSTALLED_BUT_NOT_DEFAULT);
+ }
+
+ static ViewHostMsg_GetSearchProviderInstallState_Params InstalledAsDefault() {
+ return ViewHostMsg_GetSearchProviderInstallState_Params(
+ INSTALLED_AS_DEFAULT);
+ }
+};
+
+// Parameters structure for ViewHostMsg_FrameNavigate, which has too many data
+// parameters to be reasonably put in a predefined IPC message.
+struct ViewHostMsg_FrameNavigate_Params {
+ ViewHostMsg_FrameNavigate_Params();
+ ~ViewHostMsg_FrameNavigate_Params();
+
+ // Page ID of this navigation. The renderer creates a new unique page ID
+ // anytime a new session history entry is created. This means you'll get new
+ // page IDs for user actions, and the old page IDs will be reloaded when
+ // iframes are loaded automatically.
+ int32 page_id;
+
+ // URL of the page being loaded.
+ GURL url;
+
+ // URL of the referrer of this load. WebKit generates this based on the
+ // source of the event that caused the load.
+ GURL referrer;
+
+ // The type of transition.
+ PageTransition::Type transition;
+
+ // Lists the redirects that occurred on the way to the current page. This
+ // vector has the same format as reported by the WebDataSource in the glue,
+ // with the current page being the last one in the list (so even when
+ // there's no redirect, there will be one entry in the list.
+ std::vector<GURL> redirects;
+
+ // Set to false if we want to update the session history but not update
+ // the browser history. E.g., on unreachable urls.
+ bool should_update_history;
+
+ // See SearchableFormData for a description of these.
+ GURL searchable_form_url;
+ std::string searchable_form_encoding;
+
+ // See password_form.h.
+ webkit_glue::PasswordForm password_form;
+
+ // Information regarding the security of the connection (empty if the
+ // connection was not secure).
+ std::string security_info;
+
+ // The gesture that initiated this navigation.
+ NavigationGesture gesture;
+
+ // Contents MIME type of main frame.
+ std::string contents_mime_type;
+
+ // True if this was a post request.
+ bool is_post;
+
+ // Whether the content of the frame was replaced with some alternate content
+ // (this can happen if the resource was insecure).
+ bool is_content_filtered;
+
+ // Whether the frame navigation resulted in no change to the documents within
+ // the page. For example, the navigation may have just resulted in scrolling
+ // to a named anchor.
+ bool was_within_same_page;
+
+ // The status code of the HTTP request.
+ int http_status_code;
+};
+
+// Values that may be OR'd together to form the 'flags' parameter of a
+// ViewHostMsg_UpdateRect_Params structure.
+struct ViewHostMsg_UpdateRect_Flags {
+ enum {
+ IS_RESIZE_ACK = 1 << 0,
+ IS_RESTORE_ACK = 1 << 1,
+ IS_REPAINT_ACK = 1 << 2,
+ };
+ static bool is_resize_ack(int flags) {
+ return (flags & IS_RESIZE_ACK) != 0;
+ }
+ static bool is_restore_ack(int flags) {
+ return (flags & IS_RESTORE_ACK) != 0;
+ }
+ static bool is_repaint_ack(int flags) {
+ return (flags & IS_REPAINT_ACK) != 0;
+ }
+};
+
+struct ViewHostMsg_UpdateRect_Params {
+ ViewHostMsg_UpdateRect_Params();
+ ~ViewHostMsg_UpdateRect_Params();
+
+ // The bitmap to be painted into the view at the locations specified by
+ // update_rects.
+ TransportDIB::Id bitmap;
+
+ // The position and size of the bitmap.
+ gfx::Rect bitmap_rect;
+
+ // The scroll offset. Only one of these can be non-zero, and if they are
+ // both zero, then it means there is no scrolling and the scroll_rect is
+ // ignored.
+ int dx;
+ int dy;
+
+ // The rectangular region to scroll.
+ gfx::Rect scroll_rect;
+
+ // The regions of the bitmap (in view coords) that contain updated pixels.
+ // In the case of scrolling, this includes the scroll damage rect.
+ std::vector<gfx::Rect> copy_rects;
+
+ // The size of the RenderView when this message was generated. This is
+ // included so the host knows how large the view is from the perspective of
+ // the renderer process. This is necessary in case a resize operation is in
+ // progress.
+ gfx::Size view_size;
+
+ // New window locations for plugin child windows.
+ std::vector<webkit_glue::WebPluginGeometry> plugin_window_moves;
+
+ // The following describes the various bits that may be set in flags:
+ //
+ // ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK
+ // Indicates that this is a response to a ViewMsg_Resize message.
+ //
+ // ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK
+ // Indicates that this is a response to a ViewMsg_WasRestored message.
+ //
+ // ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK
+ // Indicates that this is a response to a ViewMsg_Repaint message.
+ //
+ // If flags is zero, then this message corresponds to an unsoliticed paint
+ // request by the render view. Any of the above bits may be set in flags,
+ // which would indicate that this paint message is an ACK for multiple
+ // request messages.
+ int flags;
+};
+
+// Information on closing a tab. This is used both for ViewMsg_ClosePage, and
+// the corresponding ViewHostMsg_ClosePage_ACK.
+struct ViewMsg_ClosePage_Params {
+ ViewMsg_ClosePage_Params();
+ ~ViewMsg_ClosePage_Params();
+
+ // The identifier of the RenderProcessHost for the currently closing view.
+ //
+ // These first two parameters are technically redundant since they are
+ // needed only when processing the ACK message, and the processor
+ // theoretically knows both the process and route ID. However, this is
+ // difficult to figure out with our current implementation, so this
+ // information is duplicate here.
+ int closing_process_id;
+
+ // The route identifier for the currently closing RenderView.
+ int closing_route_id;
+
+ // True when this close is for the first (closing) tab of a cross-site
+ // transition where we switch processes. False indicates the close is for the
+ // entire tab.
+ //
+ // When true, the new_* variables below must be filled in. Otherwise they must
+ // both be -1.
+ bool for_cross_site_transition;
+
+ // The identifier of the RenderProcessHost for the new view attempting to
+ // replace the closing one above. This must be valid when
+ // for_cross_site_transition is set, and must be -1 otherwise.
+ int new_render_process_host_id;
+
+ // The identifier of the *request* the new view made that is causing the
+ // cross-site transition. This is *not* a route_id, but the request that we
+ // will resume once the ACK from the closing view has been received. This
+ // must be valid when for_cross_site_transition is set, and must be -1
+ // otherwise.
+ int new_request_id;
+};
+
+// Parameters for a resource request.
+struct ViewHostMsg_Resource_Request {
+ ViewHostMsg_Resource_Request();
+ ~ViewHostMsg_Resource_Request();
+
+ // The request method: GET, POST, etc.
+ std::string method;
+
+ // The requested URL.
+ GURL url;
+
+ // Usually the URL of the document in the top-level window, which may be
+ // checked by the third-party cookie blocking policy. Leaving it empty may
+ // lead to undesired cookie blocking. Third-party cookie blocking can be
+ // bypassed by setting first_party_for_cookies = url, but this should ideally
+ // only be done if there really is no way to determine the correct value.
+ GURL first_party_for_cookies;
+
+ // The referrer to use (may be empty).
+ GURL referrer;
+
+ // The origin of the frame that is associated with this request. This is used
+ // to update our insecure content state.
+ std::string frame_origin;
+
+ // The origin of the main frame (top-level frame) that is associated with this
+ // request. This is used to update our insecure content state.
+ std::string main_frame_origin;
+
+ // Additional HTTP request headers.
+ std::string headers;
+
+ // URLRequest load flags (0 by default).
+ int load_flags;
+
+ // Unique ID of process that originated this request. For normal renderer
+ // requests, this will be the ID of the renderer. For plugin requests routed
+ // through the renderer, this will be the plugin's ID.
+ int origin_child_id;
+
+ // What this resource load is for (main frame, sub-frame, sub-resource,
+ // object).
+ ResourceType::Type resource_type;
+
+ // Used by plugin->browser requests to get the correct URLRequestContext.
+ uint32 request_context;
+
+ // Indicates which frame (or worker context) the request is being loaded into,
+ // or kNoHostId.
+ int appcache_host_id;
+
+ // Optional upload data (may be null).
+ scoped_refptr<net::UploadData> upload_data;
+
+ bool download_to_file;
+
+ // The following two members are specified if the request is initiated by
+ // a plugin like Gears.
+
+ // Contains the id of the host renderer.
+ int host_renderer_id;
+
+ // Contains the id of the host render view.
+ int host_render_view_id;
+};
+
+// Parameters for a render request.
+struct ViewMsg_Print_Params {
+ ViewMsg_Print_Params();
+ ~ViewMsg_Print_Params();
+
+ // Physical size of the page, including non-printable margins,
+ // in pixels according to dpi.
+ gfx::Size page_size;
+
+ // In pixels according to dpi_x and dpi_y.
+ gfx::Size printable_size;
+
+ // The y-offset of the printable area, in pixels according to dpi.
+ int margin_top;
+
+ // The x-offset of the printable area, in pixels according to dpi.
+ int margin_left;
+
+ // Specifies dots per inch.
+ double dpi;
+
+ // Minimum shrink factor. See PrintSettings::min_shrink for more information.
+ double min_shrink;
+
+ // Maximum shrink factor. See PrintSettings::max_shrink for more information.
+ double max_shrink;
+
+ // Desired apparent dpi on paper.
+ int desired_dpi;
+
+ // Cookie for the document to ensure correctness.
+ int document_cookie;
+
+ // Should only print currently selected text.
+ bool selection_only;
+
+ // Warning: do not compare document_cookie.
+ bool Equals(const ViewMsg_Print_Params& rhs) const;
+
+ // Checking if the current params is empty. Just initialized after a memset.
+ bool IsEmpty() const;
+};
+
+struct ViewMsg_PrintPage_Params {
+ ViewMsg_PrintPage_Params();
+ ~ViewMsg_PrintPage_Params();
+
+ // Parameters to render the page as a printed page. It must always be the same
+ // value for all the document.
+ ViewMsg_Print_Params params;
+
+ // The page number is the indicator of the square that should be rendered
+ // according to the layout specified in ViewMsg_Print_Params.
+ int page_number;
+};
+
+struct ViewMsg_PrintPages_Params {
+ ViewMsg_PrintPages_Params();
+ ~ViewMsg_PrintPages_Params();
+
+ // Parameters to render the page as a printed page. It must always be the same
+ // value for all the document.
+ ViewMsg_Print_Params params;
+
+ // If empty, this means a request to render all the printed pages.
+ std::vector<int> pages;
+};
+
+// Parameters to describe a rendered page.
+struct ViewHostMsg_DidPrintPage_Params {
+ ViewHostMsg_DidPrintPage_Params();
+ ~ViewHostMsg_DidPrintPage_Params();
+
+ // A shared memory handle to the EMF data. This data can be quite large so a
+ // memory map needs to be used.
+ base::SharedMemoryHandle metafile_data_handle;
+
+ // Size of the metafile data.
+ uint32 data_size;
+
+ // Cookie for the document to ensure correctness.
+ int document_cookie;
+
+ // Page number.
+ int page_number;
+
+ // Shrink factor used to render this page.
+ double actual_shrink;
+
+ // The size of the page the page author specified.
+ gfx::Size page_size;
+
+ // The printable area the page author specified.
+ gfx::Rect content_area;
+
+ // True if the page has visible overlays.
+ bool has_visible_overlays;
+};
+
+// Parameters for creating an audio output stream.
+struct ViewHostMsg_Audio_CreateStream_Params {
+ ViewHostMsg_Audio_CreateStream_Params();
+ ~ViewHostMsg_Audio_CreateStream_Params();
+
+ // Format request for the stream.
+ AudioParameters params;
+
+ // Number of bytes per packet. Determines the maximum number of bytes
+ // transported for each audio packet request.
+ // A value of 0 means that the audio packet size is selected automatically
+ // by the browser process.
+ uint32 packet_size;
+};
+
+// This message is used for supporting popup menus on Mac OS X using native
+// Cocoa controls. The renderer sends us this message which we use to populate
+// the popup menu.
+struct ViewHostMsg_ShowPopup_Params {
+ ViewHostMsg_ShowPopup_Params();
+ ~ViewHostMsg_ShowPopup_Params();
+
+ // Position on the screen.
+ gfx::Rect bounds;
+
+ // The height of each item in the menu.
+ int item_height;
+
+ // The size of the font to use for those items.
+ double item_font_size;
+
+ // The currently selected (displayed) item in the menu.
+ int selected_item;
+
+ // The entire list of items in the popup menu.
+ std::vector<WebMenuItem> popup_items;
+
+ // Whether items should be right-aligned.
+ bool right_aligned;
+};
+
+// Parameters for the IPC message ViewHostMsg_ScriptedPrint
+struct ViewHostMsg_ScriptedPrint_Params {
+ ViewHostMsg_ScriptedPrint_Params();
+ ~ViewHostMsg_ScriptedPrint_Params();
+
+ int routing_id;
+ gfx::NativeViewId host_window_id;
+ int cookie;
+ int expected_pages_count;
+ bool has_selection;
+ 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_;
+};
+
+// Used to create an object store.
+struct ViewHostMsg_IDBDatabaseCreateObjectStore_Params {
+ ViewHostMsg_IDBDatabaseCreateObjectStore_Params();
+ ~ViewHostMsg_IDBDatabaseCreateObjectStore_Params();
+
+ // The response should have this id.
+ int32 response_id_;
+
+ // 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 database the object store belongs to.
+ int32 idb_database_id_;
+};
+
+// Used to open both cursors and object cursors in IndexedDB.
+struct ViewHostMsg_IDBIndexOpenCursor_Params {
+ // The response should have this id.
+ int32 response_id_;
+
+ // The serialized left key.
+ IndexedDBKey left_key_;
+
+ // The serialized right key.
+ IndexedDBKey right_key_;
+
+ // The key flags.
+ int32 key_flags_;
+
+ // 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 {
+ // 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 {
+ // The response should have this id.
+ int32 response_id_;
+
+ // 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 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 left key.
+ IndexedDBKey left_key_;
+
+ // The serialized right key.
+ IndexedDBKey right_key_;
+
+ // The key flags.
+ int32 flags_;
+
+ // 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();
+ ViewMsg_ExecuteCode_Params(int request_id, const std::string& extension_id,
+ const std::vector<URLPattern>& host_permissions,
+ bool is_javascript, const std::string& code,
+ bool all_frames);
+ ~ViewMsg_ExecuteCode_Params();
+
+ // The extension API request id, for responding.
+ int request_id;
+
+ // The ID of the requesting extension. To know which isolated world to
+ // execute the code inside of.
+ std::string extension_id;
+
+ // The host permissions of the requesting extension. So that we can check them
+ // right before injecting, to avoid any race conditions.
+ std::vector<URLPattern> host_permissions;
+
+ // Whether the code is JavaScript or CSS.
+ bool is_javascript;
+
+ // String of code to execute.
+ std::string code;
+
+ // Whether to inject into all frames, or only the root frame.
+ bool all_frames;
+};
+
+// Parameters for the message that creates a worker thread.
+struct ViewHostMsg_CreateWorker_Params {
+ ViewHostMsg_CreateWorker_Params();
+ ~ViewHostMsg_CreateWorker_Params();
+
+ // URL for the worker script.
+ GURL url;
+
+ // True if this is a SharedWorker, false if it is a dedicated Worker.
+ bool is_shared;
+
+ // Name for a SharedWorker, otherwise empty string.
+ string16 name;
+
+ // The ID of the parent document (unique within parent renderer).
+ unsigned long long document_id;
+
+ // RenderView routing id used to send messages back to the parent.
+ int render_view_route_id;
+
+ // The route ID to associate with the worker. If MSG_ROUTING_NONE is passed,
+ // a new unique ID is created and assigned to the worker.
+ int route_id;
+
+ // The ID of the parent's appcache host, only valid for dedicated workers.
+ int parent_appcache_host_id;
+
+ // The ID of the appcache the main shared worker script resource was loaded
+ // from, only valid for shared workers.
+ int64 script_resource_appcache_id;
+};
+
+// Parameters for the message that creates a desktop notification.
+struct ViewHostMsg_ShowNotification_Params {
+ ViewHostMsg_ShowNotification_Params();
+ ~ViewHostMsg_ShowNotification_Params();
+
+ // URL which is the origin that created this notification.
+ GURL origin;
+
+ // True if this is HTML
+ bool is_html;
+
+ // URL which contains the HTML contents (if is_html is true), otherwise empty.
+ GURL contents_url;
+
+ // Contents of the notification if is_html is false.
+ GURL icon_url;
+ string16 title;
+ string16 body;
+
+ // Directionality of the notification.
+ WebKit::WebTextDirection direction;
+
+ // ReplaceID if this notification should replace an existing one; may be
+ // empty if no replacement is called for.
+ string16 replace_id;
+
+ // Notification ID for sending events back for this notification.
+ int notification_id;
+};
+
+// Creates a new view via a control message since the view doesn't yet exist.
+struct ViewMsg_New_Params {
+ ViewMsg_New_Params();
+ ~ViewMsg_New_Params();
+
+ // The parent window's id.
+ gfx::NativeViewId parent_window;
+
+ // Renderer-wide preferences.
+ RendererPreferences renderer_preferences;
+
+ // Preferences for this view.
+ WebPreferences web_preferences;
+
+ // The ID of the view to be created.
+ int32 view_id;
+
+ // The session storage namespace ID this view should use.
+ int64 session_storage_namespace_id;
+
+ // The name of the frame associated with this view (or empty if none).
+ string16 frame_name;
+};
+
+struct ViewHostMsg_CreateWindow_Params {
+ ViewHostMsg_CreateWindow_Params();
+ ~ViewHostMsg_CreateWindow_Params();
+
+ // Routing ID of the view initiating the open.
+ int opener_id;
+
+ // True if this open request came in the context of a user gesture.
+ bool user_gesture;
+
+ // Type of window requested.
+ WindowContainerType window_container_type;
+
+ // The session storage namespace ID this view should use.
+ int64 session_storage_namespace_id;
+
+ // The name of the resulting frame that should be created (empty if none
+ // has been specified).
+ string16 frame_name;
+};
+
+struct ViewHostMsg_RunFileChooser_Params {
+ enum Mode {
+ // Requires that the file exists before allowing the user to pick it.
+ Open,
+
+ // Like Open, but allows picking multiple files to open.
+ OpenMultiple,
+
+ // Like Open, but selects a folder.
+ OpenFolder,
+
+ // Allows picking a nonexistent file, and prompts to overwrite if the file
+ // already exists.
+ Save,
+ };
+
+ ViewHostMsg_RunFileChooser_Params();
+ ~ViewHostMsg_RunFileChooser_Params();
+
+ Mode mode;
+
+ // Title to be used for the dialog. This may be empty for the default title,
+ // which will be either "Open" or "Save" depending on the mode.
+ string16 title;
+
+ // Default file name to select in the dialog.
+ FilePath default_file_name;
+
+ // A comma-separated MIME types such as "audio/*,text/plain", that is used
+ // to restrict selectable files to such types.
+ string16 accept_types;
+};
+
+struct ViewMsg_ExtensionRendererInfo {
+ ViewMsg_ExtensionRendererInfo();
+ ~ViewMsg_ExtensionRendererInfo();
+
+ std::string id;
+ ExtensionExtent web_extent;
+ std::string name;
+ GURL icon_url;
+ Extension::Location location;
+};
+
+struct ViewMsg_ExtensionsUpdated_Params {
+ ViewMsg_ExtensionsUpdated_Params();
+ ~ViewMsg_ExtensionsUpdated_Params();
+
+ // Describes the installed extension apps and the URLs they cover.
+ std::vector<ViewMsg_ExtensionRendererInfo> extensions;
+};
+
+struct ViewMsg_DeviceOrientationUpdated_Params {
+ ViewMsg_DeviceOrientationUpdated_Params();
+ ~ViewMsg_DeviceOrientationUpdated_Params();
+
+ // These fields have the same meaning as in device_orientation::Orientation.
+ bool can_provide_alpha;
+ double alpha;
+ bool can_provide_beta;
+ double beta;
+ bool can_provide_gamma;
+ double gamma;
+};
+
+// Parameters structure for ViewHostMsg_ExtensionRequest.
+struct ViewHostMsg_DomMessage_Params {
+ ViewHostMsg_DomMessage_Params();
+ ~ViewHostMsg_DomMessage_Params();
+
+ // Message name.
+ std::string name;
+
+ // List of message arguments.
+ ListValue arguments;
+
+ // URL of the frame request was sent from.
+ GURL source_url;
+
+ // Unique request id to match requests and responses.
+ int request_id;
+
+ // True if request has a callback specified.
+ bool has_callback;
+
+ // True if request is executed in response to an explicit user gesture.
+ bool user_gesture;
+};
+
+struct ViewHostMsg_AccessibilityNotification_Params {
+ enum NotificationType {
+ // The node checked state has changed.
+ NOTIFICATION_TYPE_CHECK_STATE_CHANGED,
+
+ // The node tree structure has changed.
+ NOTIFICATION_TYPE_CHILDREN_CHANGED,
+
+ // The node in focus has changed.
+ NOTIFICATION_TYPE_FOCUS_CHANGED,
+
+ // The document node has loaded.
+ NOTIFICATION_TYPE_LOAD_COMPLETE,
+
+ // The node value has changed.
+ NOTIFICATION_TYPE_VALUE_CHANGED,
+ };
+
+ // Type of notification.
+ NotificationType notification_type;
+
+ // The accessibility node tree.
+ webkit_glue::WebAccessibility acc_obj;
+};
+
+namespace IPC {
+
+class Message;
+
+// Traits for ViewMsg_Navigate_Params structure to pack/unpack.
+template <>
+struct ParamTraits<ViewMsg_Navigate_Params> {
+ typedef ViewMsg_Navigate_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_AudioStreamState_Params> {
+ typedef ViewMsg_AudioStreamState_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_StopFinding_Params> {
+ typedef ViewMsg_StopFinding_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_GetSearchProviderInstallState_Params> {
+ typedef ViewHostMsg_GetSearchProviderInstallState_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_FrameNavigate_Params> {
+ typedef ViewHostMsg_FrameNavigate_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_UpdateRect_Params> {
+ typedef ViewHostMsg_UpdateRect_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_ClosePage_Params> {
+ typedef ViewMsg_ClosePage_Params 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<ViewHostMsg_Resource_Request> {
+ typedef ViewHostMsg_Resource_Request 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<ViewMsg_Print_Params> {
+ typedef ViewMsg_Print_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_PrintPage_Params> {
+ typedef ViewMsg_PrintPage_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_PrintPages_Params> {
+ typedef ViewMsg_PrintPages_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);
+ 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_Audio_CreateStream_Params> {
+ typedef ViewHostMsg_Audio_CreateStream_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_ShowPopup_Params> {
+ typedef ViewHostMsg_ShowPopup_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_ScriptedPrint_Params> {
+ typedef ViewHostMsg_ScriptedPrint_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_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);
+ 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_CreateWorker_Params> {
+ typedef ViewHostMsg_CreateWorker_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_ShowNotification_Params> {
+ typedef ViewHostMsg_ShowNotification_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_New_Params> {
+ typedef ViewMsg_New_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_CreateWindow_Params> {
+ typedef ViewHostMsg_CreateWindow_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_RunFileChooser_Params> {
+ typedef ViewHostMsg_RunFileChooser_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_ExtensionRendererInfo> {
+ typedef ViewMsg_ExtensionRendererInfo 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_ExtensionsUpdated_Params> {
+ typedef ViewMsg_ExtensionsUpdated_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_DeviceOrientationUpdated_Params> {
+ typedef ViewMsg_DeviceOrientationUpdated_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_DomMessage_Params> {
+ typedef ViewHostMsg_DomMessage_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<base::file_util_proxy::Entry> {
+ typedef base::file_util_proxy::Entry 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_AccessibilityNotification_Params> {
+ typedef ViewHostMsg_AccessibilityNotification_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
+
+#endif // CHROME_COMMON_RENDER_MESSAGES_PARAMS_H_
diff --git a/chrome/common/render_messages_unittest.cc b/chrome/common/render_messages_unittest.cc
index 30b1446..d45d5df 100644
--- a/chrome/common/render_messages_unittest.cc
+++ b/chrome/common/render_messages_unittest.cc
@@ -4,9 +4,11 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
-#include "base/values.h"
+#include "base/utf_string_conversions.h"
#include "chrome/common/render_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/webaccessibility.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
TEST(RenderMessagesUnittest, WebAccessibility) {
// Test a simple case.
@@ -21,6 +23,10 @@ TEST(RenderMessagesUnittest, WebAccessibility) {
(1 << webkit_glue::WebAccessibility::STATE_CHECKED) |
(1 << webkit_glue::WebAccessibility::STATE_FOCUSED);
input.location = WebKit::WebRect(11, 22, 333, 444);
+ input.html_attributes.push_back(
+ std::pair<string16, string16>(ASCIIToUTF16("id"), ASCIIToUTF16("a")));
+ input.html_attributes.push_back(
+ std::pair<string16, string16>(ASCIIToUTF16("class"), ASCIIToUTF16("b")));
IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
IPC::WriteParam(&msg, input);
@@ -37,6 +43,15 @@ TEST(RenderMessagesUnittest, WebAccessibility) {
EXPECT_EQ(input.state, output.state);
EXPECT_EQ(input.location, output.location);
EXPECT_EQ(input.children.size(), output.children.size());
+ EXPECT_EQ(input.html_attributes.size(), output.html_attributes.size());
+ EXPECT_EQ(input.html_attributes[0].first,
+ output.html_attributes[0].first);
+ EXPECT_EQ(input.html_attributes[0].second,
+ output.html_attributes[0].second);
+ EXPECT_EQ(input.html_attributes[1].first,
+ output.html_attributes[1].first);
+ EXPECT_EQ(input.html_attributes[1].second,
+ output.html_attributes[1].second);
// Test a corrupt case.
IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL);
diff --git a/chrome/common/renderer_preferences.h b/chrome/common/renderer_preferences.h
index 7a55b17..dd57866 100644
--- a/chrome/common/renderer_preferences.h
+++ b/chrome/common/renderer_preferences.h
@@ -11,6 +11,7 @@
#ifndef CHROME_COMMON_RENDERER_PREFERENCES_H_
#define CHROME_COMMON_RENDERER_PREFERENCES_H_
+#pragma once
#include "third_party/skia/include/core/SkColor.h"
diff --git a/chrome/common/resource_dispatcher.cc b/chrome/common/resource_dispatcher.cc
index ace6169..9f182a1 100644
--- a/chrome/common/resource_dispatcher.cc
+++ b/chrome/common/resource_dispatcher.cc
@@ -14,9 +14,12 @@
#include "base/string_util.h"
#include "chrome/common/extensions/extension_localization_peer.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/security_filter_peer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/upload_data.h"
+#include "net/http/http_response_headers.h"
#include "webkit/glue/resource_type.h"
#include "webkit/glue/webkit_glue.h"
@@ -57,6 +60,7 @@ class IPCResourceLoaderBridge : public ResourceLoaderBridge {
uint64 offset,
uint64 length,
const base::Time& expected_modification_time);
+ virtual void AppendBlobToUpload(const GURL& blob_url);
virtual void SetUploadIdentifier(int64 identifier);
virtual bool Start(Peer* peer);
virtual void Cancel();
@@ -123,11 +127,12 @@ IPCResourceLoaderBridge::IPCResourceLoaderBridge(
request_.resource_type = request_info.request_type;
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_.host_renderer_id = host_renderer_id_;
request_.host_render_view_id = host_render_view_id_;
#ifdef LOG_RESOURCE_REQUESTS
- url_ = url.possibly_invalid_spec();
+ url_ = request_.url.possibly_invalid_spec();
#endif
}
@@ -138,6 +143,11 @@ IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
// this operation may fail, as the dispatcher will have preemptively
// removed us when the renderer sends the ReceivedAllData message.
dispatcher_->RemovePendingRequest(request_id_);
+
+ if (request_.download_to_file) {
+ dispatcher_->message_sender()->Send(
+ new ViewHostMsg_ReleaseDownloadedFile(request_id_));
+ }
}
}
@@ -165,6 +175,14 @@ void IPCResourceLoaderBridge::AppendFileRangeToUpload(
expected_modification_time);
}
+void IPCResourceLoaderBridge::AppendBlobToUpload(const GURL& blob_url) {
+ DCHECK(request_id_ == -1) << "request already started";
+
+ if (!request_.upload_data)
+ request_.upload_data = new net::UploadData();
+ request_.upload_data->AppendBlob(blob_url);
+}
+
void IPCResourceLoaderBridge::SetUploadIdentifier(int64 identifier) {
DCHECK(request_id_ == -1) << "request already started";
@@ -241,7 +259,13 @@ void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) {
response->headers = result.headers;
response->mime_type = result.mime_type;
response->charset = result.charset;
+ response->request_time = result.request_time;
+ response->response_time = result.response_time;
+ response->connection_id = result.connection_id;
+ response->connection_reused = result.connection_reused;
+ response->load_timing = result.load_timing;
response->data.swap(result.data);
+ response->download_file_path = result.download_file_path;
}
} // namespace webkit_glue
@@ -271,30 +295,26 @@ bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
return true;
}
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // This might happen for kill()ed requests on the webkit end, so perhaps it
- // shouldn't be a warning...
- DLOG(WARNING) << "Got response for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info) {
// Release resources in the message if it is a data message.
ReleaseResourcesInDataMessage(message);
return true;
}
- PendingRequestInfo& request_info = it->second;
- if (request_info.is_deferred) {
- request_info.deferred_message_queue.push_back(new IPC::Message(message));
+ if (request_info->is_deferred) {
+ request_info->deferred_message_queue.push_back(new IPC::Message(message));
return true;
}
// Make sure any deferred messages are dispatched before we dispatch more.
- if (!request_info.deferred_message_queue.empty()) {
+ if (!request_info->deferred_message_queue.empty()) {
FlushDeferredMessages(request_id);
// The request could have been deferred now. If yes then the current
// message has to be queued up. The request_info instance should remain
// valid here as there are pending messages for it.
DCHECK(pending_requests_.find(request_id) != pending_requests_.end());
- if (request_info.is_deferred) {
- request_info.deferred_message_queue.push_back(new IPC::Message(message));
+ if (request_info->is_deferred) {
+ request_info->deferred_message_queue.push_back(new IPC::Message(message));
return true;
}
}
@@ -303,22 +323,27 @@ bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
return true;
}
-void ResourceDispatcher::OnUploadProgress(
- const IPC::Message& message, int request_id, int64 position, int64 size) {
+ResourceDispatcher::PendingRequestInfo*
+ResourceDispatcher::GetPendingRequestInfo(int request_id) {
PendingRequestList::iterator it = pending_requests_.find(request_id);
if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got upload progress for a nonexistent or "
- "finished request";
- return;
+ // This might happen for kill()ed requests on the webkit end, so perhaps it
+ // shouldn't be a warning...
+ DLOG(WARNING) << "Received message for a nonexistent or finished request";
+ return NULL;
}
+ return &(it->second);
+}
- PendingRequestInfo& request_info = it->second;
+void ResourceDispatcher::OnUploadProgress(
+ const IPC::Message& message, int request_id, int64 position, int64 size) {
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
+ return;
RESOURCE_LOG("Dispatching upload progress for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
- request_info.peer->OnUploadProgress(position, size);
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnUploadProgress(position, size);
// Acknowledge receipt
message_sender()->Send(
@@ -327,44 +352,34 @@ void ResourceDispatcher::OnUploadProgress(
void ResourceDispatcher::OnReceivedResponse(
int request_id, const ResourceResponseHead& response_head) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // This might happen for kill()ed requests on the webkit end, so perhaps it
- // shouldn't be a warning...
- DLOG(WARNING) << "Got response for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
- PendingRequestInfo& request_info = it->second;
if (response_head.replace_extension_localization_templates) {
webkit_glue::ResourceLoaderBridge::Peer* new_peer =
ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
- request_info.peer, message_sender(), response_head.mime_type,
- request_info.url);
+ request_info->peer, message_sender(), response_head.mime_type,
+ request_info->url);
if (new_peer)
- request_info.peer = new_peer;
+ request_info->peer = new_peer;
}
RESOURCE_LOG("Dispatching response for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
- request_info.peer->OnReceivedResponse(response_head, false);
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnReceivedResponse(response_head, false);
}
void ResourceDispatcher::OnReceivedCachedMetadata(
int request_id, const std::vector<char>& data) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got metadata for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
if (data.size()) {
- PendingRequestInfo& request_info = it->second;
RESOURCE_LOG("Dispatching " << data.size() << " metadata bytes for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
- request_info.peer->OnReceivedCachedMetadata(&data.front(), data.size());
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size());
}
}
@@ -380,45 +395,50 @@ void ResourceDispatcher::OnReceivedData(const IPC::Message& message,
DCHECK((shm_valid && data_len > 0) || (!shm_valid && !data_len));
base::SharedMemory shared_mem(shm_handle, true); // read only
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got data for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
-
- PendingRequestInfo& request_info = it->second;
if (data_len > 0 && shared_mem.Map(data_len)) {
RESOURCE_LOG("Dispatching " << data_len << " bytes for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
const char* data = static_cast<char*>(shared_mem.memory());
- request_info.peer->OnReceivedData(data, data_len);
+ request_info->peer->OnReceivedData(data, data_len);
}
}
+void ResourceDispatcher::OnDownloadedData(const IPC::Message& message,
+ int request_id,
+ int data_len) {
+ // Acknowledge the reception of this message.
+ message_sender()->Send(
+ new ViewHostMsg_DataDownloaded_ACK(message.routing_id(), request_id));
+
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
+ return;
+
+ RESOURCE_LOG("Dispatching " << data_len << " downloaded for " <<
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnDownloadedData(data_len);
+}
+
void ResourceDispatcher::OnReceivedRedirect(
const IPC::Message& message,
int request_id,
const GURL& new_url,
const webkit_glue::ResourceLoaderBridge::ResponseInfo& info) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got data for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
- PendingRequestInfo& request_info = it->second;
-
- RESOURCE_LOG("Dispatching redirect for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
+ RESOURCE_LOG(
+ "Dispatching redirect for " <<
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
bool has_new_first_party_for_cookies = false;
GURL new_first_party_for_cookies;
- if (request_info.peer->OnReceivedRedirect(new_url, info,
+ if (request_info->peer->OnReceivedRedirect(new_url, info,
&has_new_first_party_for_cookies,
&new_first_party_for_cookies)) {
message_sender()->Send(
@@ -432,31 +452,27 @@ void ResourceDispatcher::OnReceivedRedirect(
void ResourceDispatcher::OnRequestComplete(int request_id,
const URLRequestStatus& status,
- const std::string& security_info) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got 'complete' for a nonexistent or finished request";
+ const std::string& security_info,
+ const base::Time& completion_time) {
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
- PendingRequestInfo& request_info = it->second;
- webkit_glue::ResourceLoaderBridge::Peer* peer = request_info.peer;
+ webkit_glue::ResourceLoaderBridge::Peer* peer = request_info->peer;
RESOURCE_LOG("Dispatching complete for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
+ peer->GetURLForDebugging().possibly_invalid_spec());
if (status.status() == URLRequestStatus::CANCELED &&
status.os_error() != net::ERR_ABORTED) {
// Resource canceled with a specific error are filtered.
SecurityFilterPeer* new_peer =
SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
- request_info.resource_type,
- request_info.peer,
+ request_info->resource_type,
+ request_info->peer,
status.os_error());
if (new_peer) {
- request_info.peer = new_peer;
+ request_info->peer = new_peer;
peer = new_peer;
}
}
@@ -464,7 +480,7 @@ void ResourceDispatcher::OnRequestComplete(int request_id,
// The request ID will be removed from our pending list in the destructor.
// Normally, dispatching this message causes the reference-counted request to
// die immediately.
- peer->OnCompletedRequest(status, security_info);
+ peer->OnCompletedRequest(status, security_info, completion_time);
webkit_glue::NotifyCacheStats();
}
@@ -533,6 +549,7 @@ void ResourceDispatcher::DispatchMessage(const IPC::Message& message) {
ViewMsg_Resource_ReceivedCachedMetadata, OnReceivedCachedMetadata)
IPC_MESSAGE_HANDLER(ViewMsg_Resource_ReceivedRedirect, OnReceivedRedirect)
IPC_MESSAGE_HANDLER(ViewMsg_Resource_DataReceived, OnReceivedData)
+ IPC_MESSAGE_HANDLER(ViewMsg_Resource_DataDownloaded, OnDownloadedData)
IPC_MESSAGE_HANDLER(ViewMsg_Resource_RequestComplete, OnRequestComplete)
IPC_END_MESSAGE_MAP()
}
@@ -585,6 +602,7 @@ bool ResourceDispatcher::IsResourceDispatcherMessage(
case ViewMsg_Resource_ReceivedCachedMetadata::ID:
case ViewMsg_Resource_ReceivedRedirect::ID:
case ViewMsg_Resource_DataReceived::ID:
+ case ViewMsg_Resource_DataDownloaded::ID:
case ViewMsg_Resource_RequestComplete::ID:
return true;
diff --git a/chrome/common/resource_dispatcher.h b/chrome/common/resource_dispatcher.h
index c98b11a..77e08ac 100644
--- a/chrome/common/resource_dispatcher.h
+++ b/chrome/common/resource_dispatcher.h
@@ -6,6 +6,7 @@
#ifndef CHROME_COMMON_RESOURCE_DISPATCHER_H__
#define CHROME_COMMON_RESOURCE_DISPATCHER_H__
+#pragma once
#include <deque>
#include <string>
@@ -81,6 +82,10 @@ class ResourceDispatcher {
};
typedef base::hash_map<int, PendingRequestInfo> PendingRequestList;
+ // Helper to lookup the info based on the request_id.
+ // May return NULL if the request as been canceled from the client side.
+ PendingRequestInfo* GetPendingRequestInfo(int request_id);
+
// Message response handlers, called by the message handler for this process.
void OnUploadProgress(
const IPC::Message& message,
@@ -99,10 +104,15 @@ class ResourceDispatcher {
int request_id,
base::SharedMemoryHandle data,
int data_len);
+ void OnDownloadedData(
+ const IPC::Message& message,
+ int request_id,
+ int data_len);
void OnRequestComplete(
int request_id,
const URLRequestStatus& status,
- const std::string& security_info);
+ const std::string& security_info,
+ const base::Time& completion_time);
// Dispatch the message to one of the message response handlers.
void DispatchMessage(const IPC::Message& message);
diff --git a/chrome/common/resource_dispatcher_unittest.cc b/chrome/common/resource_dispatcher_unittest.cc
index 323a6e4..ff007f9 100644
--- a/chrome/common/resource_dispatcher_unittest.cc
+++ b/chrome/common/resource_dispatcher_unittest.cc
@@ -10,7 +10,10 @@
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/resource_dispatcher.h"
+#include "net/base/upload_data.h"
+#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/appcache/appcache_interfaces.h"
@@ -32,6 +35,9 @@ class TestRequestCallback : public ResourceLoaderBridge::Peer {
TestRequestCallback() : complete_(false) {
}
+ virtual void OnUploadProgress(uint64 position, uint64 size) {
+ }
+
virtual bool OnReceivedRedirect(
const GURL& new_url,
const ResourceLoaderBridge::ResponseInfo& info,
@@ -46,16 +52,17 @@ class TestRequestCallback : public ResourceLoaderBridge::Peer {
bool content_filtered) {
}
+ virtual void OnDownloadedData(int len) {
+ }
+
virtual void OnReceivedData(const char* data, int len) {
EXPECT_FALSE(complete_);
data_.append(data, len);
}
- virtual void OnUploadProgress(uint64 position, uint64 size) {
- }
-
virtual void OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info) {
+ const std::string& security_info,
+ const base::Time& completion_time) {
EXPECT_FALSE(complete_);
complete_ = true;
}
@@ -112,8 +119,8 @@ class ResourceDispatcherTest : public testing::Test,
// received data message with the test contents
base::SharedMemory shared_mem;
- EXPECT_TRUE(shared_mem.Create(std::wstring(),
- false, false, test_page_contents_len));
+ EXPECT_TRUE(shared_mem.Create(std::string(), false, false,
+ test_page_contents_len));
EXPECT_TRUE(shared_mem.Map(test_page_contents_len));
char* put_data_here = static_cast<char*>(shared_mem.memory());
memcpy(put_data_here, test_page_contents, test_page_contents_len);
@@ -252,11 +259,7 @@ class DeferredResourceLoadingTest : public ResourceDispatcherTest,
}
// ResourceLoaderBridge::Peer methods.
- virtual void OnReceivedResponse(
- const ResourceLoaderBridge::ResponseInfo& info,
- bool content_filtered) {
- EXPECT_EQ(defer_loading_, false);
- set_defer_loading(true);
+ virtual void OnUploadProgress(uint64 position, uint64 size) {
}
virtual bool OnReceivedRedirect(
@@ -268,16 +271,24 @@ class DeferredResourceLoadingTest : public ResourceDispatcherTest,
return true;
}
- virtual void OnReceivedData(const char* data, int len) {
+ virtual void OnReceivedResponse(
+ const ResourceLoaderBridge::ResponseInfo& info,
+ bool content_filtered) {
EXPECT_EQ(defer_loading_, false);
- set_defer_loading(false);
+ set_defer_loading(true);
}
- virtual void OnUploadProgress(uint64 position, uint64 size) {
+ virtual void OnDownloadedData(int len) {
+ }
+
+ virtual void OnReceivedData(const char* data, int len) {
+ EXPECT_EQ(defer_loading_, false);
+ set_defer_loading(false);
}
virtual void OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info) {
+ const std::string& security_info,
+ const base::Time& completion_time) {
}
virtual GURL GetURLForDebugging() const {
@@ -286,7 +297,7 @@ class DeferredResourceLoadingTest : public ResourceDispatcherTest,
protected:
virtual void SetUp() {
- EXPECT_EQ(true, shared_handle_.Create(L"DeferredResourceLoaderTest", false,
+ EXPECT_EQ(true, shared_handle_.Create("DeferredResourceLoaderTest", false,
false, 100));
ResourceDispatcherTest::SetUp();
}
diff --git a/chrome/common/resource_response.h b/chrome/common/resource_response.h
index 1c9b766..368e410 100644
--- a/chrome/common/resource_response.h
+++ b/chrome/common/resource_response.h
@@ -6,6 +6,7 @@
#ifndef CHROME_COMMON_RESOURCE_RESPONSE_H_
#define CHROME_COMMON_RESOURCE_RESPONSE_H_
+#pragma once
#include <string>
diff --git a/chrome/common/result_codes.h b/chrome/common/result_codes.h
index 6ca19b8..0b4bc3c 100644
--- a/chrome/common/result_codes.h
+++ b/chrome/common/result_codes.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_RESULT_CODES_H_
#define CHROME_COMMON_RESULT_CODES_H_
+#pragma once
#include "base/process_util.h"
diff --git a/chrome/common/sandbox_init_wrapper.h b/chrome/common/sandbox_init_wrapper.h
index d1652d2..56716fc 100644
--- a/chrome/common/sandbox_init_wrapper.h
+++ b/chrome/common/sandbox_init_wrapper.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_SANDBOX_INIT_WRAPPER_H_
#define CHROME_COMMON_SANDBOX_INIT_WRAPPER_H_
+#pragma once
// Wraps the sandbox initialization and platform variables to consolodate
// the code and reduce the number of platform ifdefs elsewhere. The POSIX
diff --git a/chrome/common/sandbox_init_wrapper_mac.cc b/chrome/common/sandbox_init_wrapper_mac.cc
index 998fe64..ca21255 100644
--- a/chrome/common/sandbox_init_wrapper_mac.cc
+++ b/chrome/common/sandbox_init_wrapper_mac.cc
@@ -1,10 +1,12 @@
-// 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.
#include "chrome/common/sandbox_init_wrapper.h"
#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/logging.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/sandbox_mac.h"
@@ -20,20 +22,12 @@ bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line,
// Browser process isn't sandboxed.
return true;
} else if (process_type == switches::kRendererProcess) {
- if (command_line.HasSwitch(switches::kEnableExperimentalWebGL) &&
+ if (!command_line.HasSwitch(switches::kDisableExperimentalWebGL) &&
command_line.HasSwitch(switches::kInProcessWebGL)) {
// TODO(kbr): this check seems to be necessary only on this
// platform because the sandbox is initialized later. Remove
// this once this flag is removed.
return true;
- } else if (command_line.HasSwitch(switches::kInternalNaCl)) {
- // Renderer process sandbox. If --internal_nacl is present then use the
- // version of the renderer sandbox which allows Native Client to use Unix
- // sockets.
- // TODO(msneck): Remove the use of Unix sockets from Native Client and
- // then get rid of the SANDBOX_TYPE_NACL_PLUGIN enum.
- // See http://code.google.com/p/nativeclient/issues/detail?id=344
- sandbox_process_type = sandbox::SANDBOX_TYPE_NACL_PLUGIN;
} else {
sandbox_process_type = sandbox::SANDBOX_TYPE_RENDERER;
}
@@ -49,8 +43,8 @@ bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line,
} else if (process_type == switches::kUtilityProcess) {
// Utility process sandbox.
sandbox_process_type = sandbox::SANDBOX_TYPE_UTILITY;
- allowed_dir = FilePath::FromWStringHack(
- command_line.GetSwitchValue(switches::kUtilityProcessAllowedDir));
+ allowed_dir =
+ command_line.GetSwitchValuePath(switches::kUtilityProcessAllowedDir);
} else if (process_type == switches::kWorkerProcess) {
// Worker process sandbox.
sandbox_process_type = sandbox::SANDBOX_TYPE_WORKER;
diff --git a/chrome/common/sandbox_mac.h b/chrome/common/sandbox_mac.h
index 249eaa3..61a02fc 100644
--- a/chrome/common/sandbox_mac.h
+++ b/chrome/common/sandbox_mac.h
@@ -1,16 +1,16 @@
-// 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.
#ifndef CHROME_COMMON_SANDBOX_MAC_H_
#define CHROME_COMMON_SANDBOX_MAC_H_
+#pragma once
-#include "base/file_path.h"
+class FilePath;
namespace sandbox {
enum SandboxProcessType {
-
SANDBOX_TYPE_FIRST_TYPE, // Placeholder to ease iteration.
SANDBOX_TYPE_RENDERER = SANDBOX_TYPE_FIRST_TYPE,
@@ -25,9 +25,7 @@ enum SandboxProcessType {
// is allowed to one configurable directory.
SANDBOX_TYPE_UTILITY,
- // Native Client sandboxes. The plugin contains trusted code and the
- // loader contains the user's untrusted code.
- SANDBOX_TYPE_NACL_PLUGIN,
+ // Native Client sandbox for the user's untrusted code.
SANDBOX_TYPE_NACL_LOADER,
SANDBOX_AFTER_TYPE_LAST_TYPE, // Placeholder to ease iteration.
diff --git a/chrome/common/sandbox_mac.mm b/chrome/common/sandbox_mac.mm
index 3d2985c..303a538 100644
--- a/chrome/common/sandbox_mac.mm
+++ b/chrome/common/sandbox_mac.mm
@@ -20,6 +20,7 @@ extern "C" {
#include "base/scoped_cftyperef.h"
#include "base/scoped_nsautorelease_pool.h"
#include "base/string16.h"
+#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
@@ -255,7 +256,6 @@ bool EnableSandbox(SandboxProcessType sandbox_type,
// TODO(jeremy): Look at using include syntax to unify common parts of sandbox
// definition files.
NSString* sandbox_config_filename = nil;
- bool allow_nacl_lines = false;
switch (sandbox_type) {
case SANDBOX_TYPE_RENDERER:
sandbox_config_filename = @"renderer";
@@ -266,24 +266,9 @@ bool EnableSandbox(SandboxProcessType sandbox_type,
case SANDBOX_TYPE_UTILITY:
sandbox_config_filename = @"utility";
break;
- case SANDBOX_TYPE_NACL_PLUGIN:
- // The Native Client plugin is a standard renderer sandbox with some
- // additional lines to support use of Unix sockets.
- // TODO(msneck): Remove the use of Unix sockets from Native Client and
- // then remove the associated rules from chrome/renderer/renderer.sb.
- // See http://code.google.com/p/nativeclient/issues/detail?id=344
- sandbox_config_filename = @"renderer";
- allow_nacl_lines = true;
- break;
case SANDBOX_TYPE_NACL_LOADER:
// The Native Client loader is used for safeguarding the user's
// untrusted code within Native Client.
- // TODO(msneck): Remove the use of Unix sockets from Native Client and
- // then decide on an appropriate sandbox type for the untrusted code.
- // This might simply mean removing the Unix socket rules from
- // chrome/browser/nacl_loader.sb or it might mean sharing the
- // sandbox configuration with SANDBOX_TYPE_WORKER.
- // See http://code.google.com/p/nativeclient/issues/detail?id=344
sandbox_config_filename = @"nacl_loader";
break;
default:
@@ -324,19 +309,34 @@ bool EnableSandbox(SandboxProcessType sandbox_type,
sandbox_data =
[common_sandbox_prefix_data stringByAppendingString:sandbox_data];
- // Enable verbose logging if enabled on the command line.
- // (see renderer.sb for details).
+ // Enable verbose logging if enabled on the command line. (See common.sb
+ // for details).
const CommandLine *command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kEnableSandboxLogging)) {
+ bool enable_logging =
+ command_line->HasSwitch(switches::kEnableSandboxLogging);
+ if (enable_logging) {
sandbox_data = [sandbox_data
stringByReplacingOccurrencesOfString:@";ENABLE_LOGGING"
withString:@""];
}
- // Enable Native Client lines if they are allowed.
- if (allow_nacl_lines) {
+ // Get the OS version.
+ int32 major_version, minor_version, bugfix_version;
+ base::SysInfo::OperatingSystemVersionNumbers(&major_version,
+ &minor_version, &bugfix_version);
+ bool snow_leopard_or_higher =
+ (major_version > 10 || (major_version == 10 && minor_version >= 6));
+
+ // Without this, the sandbox will print a message to the system log every
+ // time it denies a request. This floods the console with useless spew. The
+ // (with no-log) syntax is only supported on 10.6+
+ if (snow_leopard_or_higher && !enable_logging) {
sandbox_data = [sandbox_data
- stringByReplacingOccurrencesOfString:@";NACL"
+ stringByReplacingOccurrencesOfString:@"DISABLE_SANDBOX_DENIAL_LOGGING"
+ withString:@"(with no-log)"];
+ } else {
+ sandbox_data = [sandbox_data
+ stringByReplacingOccurrencesOfString:@"DISABLE_SANDBOX_DENIAL_LOGGING"
withString:@""];
}
@@ -365,11 +365,7 @@ bool EnableSandbox(SandboxProcessType sandbox_type,
}
- int32 major_version, minor_version, bugfix_version;
- base::SysInfo::OperatingSystemVersionNumbers(&major_version,
- &minor_version, &bugfix_version);
-
- if (major_version > 10 || (major_version == 10 && minor_version >= 6)) {
+ if (snow_leopard_or_higher) {
// 10.6-only Sandbox rules.
sandbox_data = [sandbox_data
stringByReplacingOccurrencesOfString:@";10.6_ONLY"
diff --git a/chrome/common/sandbox_mac_diraccess_unittest.mm b/chrome/common/sandbox_mac_diraccess_unittest.mm
index f356453..5804361 100644
--- a/chrome/common/sandbox_mac_diraccess_unittest.mm
+++ b/chrome/common/sandbox_mac_diraccess_unittest.mm
@@ -11,11 +11,12 @@ extern "C" {
#include "base/file_util.h"
#include "base/file_path.h"
-#include "base/multiprocess_test.h"
+#include "base/test/multiprocess_test.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/sandbox_mac.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
// Tests to exercise directory-access-related restrictions of Mac sandbox.
@@ -30,11 +31,12 @@ namespace {
static const char* kSandboxAccessPathKey = "sandbox_dir";
-class MacDirAccessSandboxTest : public MultiProcessTest {
+class MacDirAccessSandboxTest : public base::MultiProcessTest {
public:
- bool CheckSandbox(std::string directory_to_try) {
+ bool CheckSandbox(const std::string& directory_to_try) {
setenv(kSandboxAccessPathKey, directory_to_try.c_str(), 1);
- base::ProcessHandle child_process = SpawnChild(L"mac_sandbox_path_access");
+ base::ProcessHandle child_process = SpawnChild("mac_sandbox_path_access",
+ false);
int code = -1;
if (!base::WaitForExitCode(child_process, &code)) {
LOG(WARNING) << "base::WaitForExitCode failed";
@@ -141,7 +143,8 @@ class ScopedDirectoryDelete {
typedef scoped_ptr_malloc<FilePath, ScopedDirectoryDelete> ScopedDirectory;
-TEST_F(MacDirAccessSandboxTest, SandboxAccess) {
+// Crashy, http://crbug.com/56765.
+TEST_F(MacDirAccessSandboxTest, DISABLED_SandboxAccess) {
FilePath tmp_dir;
ASSERT_TRUE(file_util::CreateNewTempDirectory("", &tmp_dir));
// This step is important on OS X since the sandbox only understands "real"
diff --git a/chrome/common/sandbox_mac_fontloading_unittest.mm b/chrome/common/sandbox_mac_fontloading_unittest.mm
index a20d263..f07a444 100644
--- a/chrome/common/sandbox_mac_fontloading_unittest.mm
+++ b/chrome/common/sandbox_mac_fontloading_unittest.mm
@@ -91,7 +91,7 @@ bool FontLoadingTestCase::BeforeSandboxInit() {
return false;
}
- if (!font_shmem_->Create(L"", false, false, font_data_length_)) {
+ if (!font_shmem_->Create("", false, false, font_data_length_)) {
LOG(ERROR) << "SharedMemory::Create failed";
return false;
}
diff --git a/chrome/common/sandbox_mac_unittest_helper.h b/chrome/common/sandbox_mac_unittest_helper.h
index 3e24009..960a4cf 100644
--- a/chrome/common/sandbox_mac_unittest_helper.h
+++ b/chrome/common/sandbox_mac_unittest_helper.h
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_COMMON_SANDBOX_MAC_UNITTEST_RUNNER_H_
-#define CHROME_COMMON_SANDBOX_MAC_UNITTEST_RUNNER_H_
+#ifndef CHROME_COMMON_SANDBOX_MAC_UNITTEST_HELPER_H_
+#define CHROME_COMMON_SANDBOX_MAC_UNITTEST_HELPER_H_
+#pragma once
-#include "base/multiprocess_test.h"
+#include "base/test/multiprocess_test.h"
#include "chrome/common/sandbox_mac.h"
namespace sandboxtest {
@@ -14,12 +15,12 @@ namespace sandboxtest {
//
// How to write a sandboxed test:
// 1. Create a class that inherits from MacSandboxTestCase and overrides
-// it's functions to run code before or after the sandbox is initialised in a
+// its functions to run code before or after the sandbox is initialised in a
// subprocess.
// 2. Register the class you just created with the REGISTER_SANDBOX_TEST_CASE()
// macro.
// 3. Write a test [using TEST_F()] that inherits from MacSandboxTest and call
-// one of it's helper functions to launch the test.
+// one of its helper functions to launch the test.
//
// Example:
// class TestCaseThatRunsInSandboxedSubprocess :
@@ -42,7 +43,7 @@ namespace sandboxtest {
// Base test type with helper functions to spawn a subprocess that exercises
// a given test in the sandbox.
-class MacSandboxTest : public MultiProcessTest {
+class MacSandboxTest : public base::MultiProcessTest {
public:
// Runs a test specified by |test_name| in a sandbox of the type specified
// by |sandbox_type|. |test_data| is a custom string that a test can pass
@@ -69,6 +70,8 @@ class MacSandboxTest : public MultiProcessTest {
// REGISTER_SANDBOX_TEST_CASE so it's visible to the test driver.
class MacSandboxTestCase {
public:
+ virtual ~MacSandboxTestCase() {}
+
// Code that runs in the sandboxed subprocess before the sandbox is
// initialized.
// Returning false from this function will cause the entire test case to fail.
@@ -111,4 +114,4 @@ template <class T> struct RegisterSandboxTest {
} // namespace sandboxtest
-#endif // CHROME_COMMON_SANDBOX_MAC_UNITTEST_RUNNER_H_
+#endif // CHROME_COMMON_SANDBOX_MAC_UNITTEST_HELPER_H_
diff --git a/chrome/common/sandbox_mac_unittest_helper.mm b/chrome/common/sandbox_mac_unittest_helper.mm
index a14370f..007530e 100644
--- a/chrome/common/sandbox_mac_unittest_helper.mm
+++ b/chrome/common/sandbox_mac_unittest_helper.mm
@@ -8,8 +8,13 @@ extern "C" {
#include <sandbox.h>
}
+#include <map>
+
+#include "base/file_path.h"
+#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "chrome/common/sandbox_mac.h"
+#include "testing/multiprocess_func_list.h"
namespace {
@@ -71,7 +76,8 @@ bool MacSandboxTest::RunTestInSandbox(sandbox::SandboxProcessType sandbox_type,
if (test_data)
setenv(kTestDataKey, test_data, 1);
- base::ProcessHandle child_process = SpawnChild(L"mac_sandbox_test_runner");
+ base::ProcessHandle child_process = SpawnChild("mac_sandbox_test_runner",
+ false);
int code = -1;
if (!base::WaitForExitCode(child_process, &code)) {
LOG(WARNING) << "base::WaitForExitCode failed";
diff --git a/chrome/common/sandbox_methods_linux.h b/chrome/common/sandbox_methods_linux.h
index 254ba62..08cb00b 100644
--- a/chrome/common/sandbox_methods_linux.h
+++ b/chrome/common/sandbox_methods_linux.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_SANDBOX_METHODS_LINUX_H_
#define CHROME_COMMON_SANDBOX_METHODS_LINUX_H_
+#pragma once
// This is a list of sandbox IPC methods which the renderer may send to the
// sandbox host. See http://code.google.com/p/chromium/LinuxSandboxIPC
diff --git a/chrome/common/sandbox_policy.cc b/chrome/common/sandbox_policy.cc
index aa5249f..7398734 100644
--- a/chrome/common/sandbox_policy.cc
+++ b/chrome/common/sandbox_policy.cc
@@ -13,8 +13,10 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
-#include "base/registry.h"
+#include "base/stringprintf.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/trace_event.h"
#include "base/win_util.h"
#include "chrome/common/child_process_info.h"
#include "chrome/common/chrome_constants.h"
@@ -300,14 +302,75 @@ bool ApplyPolicyForUntrustedPlugin(sandbox::TargetPolicy* policy) {
return true;
}
+// Launches the privileged flash broker, used when flash is sandboxed.
+// The broker is the same flash dll, except that it uses a different
+// entrypoint (BrokerMain) and it is hosted in windows' generic surrogate
+// process rundll32. After launching the broker we need to pass to
+// the flash plugin the process id of the broker via the command line
+// using --flash-broker=pid.
+// More info about rundll32 at http://support.microsoft.com/kb/164787.
+bool LoadFlashBroker(const FilePath& plugin_path, CommandLine* cmd_line) {
+ FilePath rundll;
+ if (!PathService::Get(base::DIR_SYSTEM, &rundll))
+ return false;
+ rundll = rundll.AppendASCII("rundll32.exe");
+ // Rundll32 cannot handle paths with spaces, so we use the short path.
+ wchar_t short_path[MAX_PATH];
+ if (0 == ::GetShortPathNameW(plugin_path.value().c_str(),
+ short_path, arraysize(short_path)))
+ return false;
+ std::wstring cmd_final =
+ base::StringPrintf(L"%ls %ls,BrokerMain browser=chrome",
+ rundll.value().c_str(),
+ short_path);
+ base::ProcessHandle process;
+ if (!base::LaunchApp(cmd_final, false, true, &process))
+ return false;
+
+ cmd_line->AppendSwitchASCII("flash-broker",
+ base::Int64ToString(::GetProcessId(process)));
+ ::CloseHandle(process);
+ return true;
+}
+
+// Creates a sandbox for the built-in flash plugin running in a restricted
+// environment. This is a work in progress and for the time being do not
+// pay attention to the duplication between this function and the above
+// function. For more information see bug 50796.
+bool ApplyPolicyForBuiltInFlashPlugin(sandbox::TargetPolicy* policy) {
+ // TODO(cpu): Lock down the job level more.
+ policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
+
+ sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED;
+
+ if (win_util::GetWinVersion() > win_util::WINVERSION_XP)
+ initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS;
+
+ policy->SetTokenLevel(initial_token, sandbox::USER_LIMITED);
+
+ policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
+
+ // TODO(cpu): Proxy registry access and remove these policies.
+ if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\ADOBE",
+ sandbox::TargetPolicy::REG_ALLOW_ANY,
+ policy))
+ return false;
+
+ if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\MACROMEDIA",
+ sandbox::TargetPolicy::REG_ALLOW_ANY,
+ policy))
+ return false;
+ return true;
+}
+
// Adds the custom policy rules for a given plugin. |trusted_plugins| contains
// the comma separate list of plugin dll names that should not be sandboxed.
-bool AddPolicyForPlugin(const CommandLine* cmd_line,
+bool AddPolicyForPlugin(CommandLine* cmd_line,
sandbox::TargetPolicy* policy) {
std::wstring plugin_dll = cmd_line->
- GetSwitchValue(switches::kPluginPath);
+ GetSwitchValueNative(switches::kPluginPath);
std::wstring trusted_plugins = CommandLine::ForCurrentProcess()->
- GetSwitchValue(switches::kTrustedPlugins);
+ GetSwitchValueNative(switches::kTrustedPlugins);
// Add the policy for the pipes.
sandbox::ResultCode result = sandbox::SBOX_ALL_OK;
result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
@@ -318,6 +381,21 @@ bool AddPolicyForPlugin(const CommandLine* cmd_line,
return false;
}
+ // The built-in flash gets a custom, more restricted sandbox.
+ FilePath builtin_flash;
+ if (PathService::Get(chrome::FILE_FLASH_PLUGIN, &builtin_flash)) {
+ FilePath plugin_path(plugin_dll);
+ if (plugin_path == builtin_flash) {
+ // Spawn the flash broker and apply sandbox policy.
+ if (!LoadFlashBroker(plugin_path, cmd_line)) {
+ // Could not start the broker, use a very weak policy instead.
+ DLOG(WARNING) << "Failed to start flash broker";
+ return ApplyPolicyForTrustedPlugin(policy);
+ }
+ return ApplyPolicyForBuiltInFlashPlugin(policy);
+ }
+ }
+
PluginPolicyCategory policy_category =
GetPolicyCategoryForPlugin(plugin_dll, trusted_plugins);
@@ -402,6 +480,8 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
return 0;
}
+ TRACE_EVENT_BEGIN("StartProcessWithAccess", 0, type_str);
+
bool in_sandbox =
(type != ChildProcessInfo::NACL_BROKER_PROCESS) &&
!browser_command_line.HasSwitch(switches::kNoSandbox) &&
@@ -414,7 +494,7 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
in_sandbox = false;
}
#endif
- if (browser_command_line.HasSwitch(switches::kEnableExperimentalWebGL) &&
+ if (!browser_command_line.HasSwitch(switches::kDisableExperimentalWebGL) &&
browser_command_line.HasSwitch(switches::kInProcessWebGL)) {
// In process WebGL won't work if the sandbox is enabled.
in_sandbox = false;
@@ -433,7 +513,7 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
// Prefetch hints on windows:
// Using a different prefetch profile per process type will allow Windows
// to create separate pretetch settings for browser, renderer etc.
- cmd_line->AppendLooseValue(StringPrintf(L"/prefetch:%d", type));
+ cmd_line->AppendArg(StringPrintf("/prefetch:%d", type));
if (!in_sandbox) {
base::LaunchApp(*cmd_line, false, false, &process);
@@ -455,7 +535,7 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
// Hack for Google Desktop crash. Trick GD into not injecting its DLL into
// this subprocess. See
// http://code.google.com/p/chromium/issues/detail?id=25580
- cmd_line->AppendSwitchWithValue("ignored", " --type=renderer ");
+ cmd_line->AppendSwitchASCII("ignored", " --type=renderer ");
}
}
@@ -479,12 +559,16 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
return 0;
}
+ TRACE_EVENT_BEGIN("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
+
result = g_broker_services->SpawnTarget(
cmd_line->program().c_str(),
cmd_line->command_line_string().c_str(),
policy, &target);
policy->Release();
+ TRACE_EVENT_END("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
+
if (sandbox::SBOX_ALL_OK != result)
return 0;
diff --git a/chrome/common/sandbox_policy.h b/chrome/common/sandbox_policy.h
index 46ab7bf..04a9b88 100644
--- a/chrome/common/sandbox_policy.h
+++ b/chrome/common/sandbox_policy.h
@@ -1,14 +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.
#ifndef CHROME_COMMON_SANDBOX_POLICY_H_
#define CHROME_COMMON_SANDBOX_POLICY_H_
+#pragma once
#include "base/process.h"
-#include "base/file_path.h"
class CommandLine;
+class FilePath;
namespace sandbox {
diff --git a/chrome/common/security_filter_peer.cc b/chrome/common/security_filter_peer.cc
index 6448d20..b4fcbd3 100644
--- a/chrome/common/security_filter_peer.cc
+++ b/chrome/common/security_filter_peer.cc
@@ -85,7 +85,8 @@ void SecurityFilterPeer::OnReceivedData(const char* data, int len) {
}
void SecurityFilterPeer::OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info) {
+ const std::string& security_info,
+ const base::Time& completion_time) {
NOTREACHED();
}
@@ -147,7 +148,8 @@ void BufferedPeer::OnReceivedData(const char* data, int len) {
}
void BufferedPeer::OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info) {
+ const std::string& security_info,
+ const base::Time& completion_time) {
// Make sure we delete ourselves at the end of this call.
scoped_ptr<BufferedPeer> this_deleter(this);
@@ -156,7 +158,7 @@ void BufferedPeer::OnCompletedRequest(const URLRequestStatus& status,
// Pretend we failed to load the resource.
original_peer_->OnReceivedResponse(response_info_, true);
URLRequestStatus status(URLRequestStatus::CANCELED, net::ERR_ABORTED);
- original_peer_->OnCompletedRequest(status, security_info);
+ original_peer_->OnCompletedRequest(status, security_info, completion_time);
return;
}
@@ -164,7 +166,7 @@ void BufferedPeer::OnCompletedRequest(const URLRequestStatus& status,
if (!data_.empty())
original_peer_->OnReceivedData(data_.data(),
static_cast<int>(data_.size()));
- original_peer_->OnCompletedRequest(status, security_info);
+ original_peer_->OnCompletedRequest(status, security_info, completion_time);
}
////////////////////////////////////////////////////////////////////////////////
@@ -193,8 +195,10 @@ void ReplaceContentPeer::OnReceivedData(const char* data, int len) {
// Ignore this, we'll serve some alternate content in OnCompletedRequest.
}
-void ReplaceContentPeer::OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info) {
+void ReplaceContentPeer::OnCompletedRequest(
+ const URLRequestStatus& status,
+ const std::string& security_info,
+ const base::Time& completion_time) {
webkit_glue::ResourceLoaderBridge::ResponseInfo info;
ProcessResponseInfo(info, &info, mime_type_);
info.security_info = security_info;
@@ -203,7 +207,9 @@ void ReplaceContentPeer::OnCompletedRequest(const URLRequestStatus& status,
if (!data_.empty())
original_peer_->OnReceivedData(data_.data(),
static_cast<int>(data_.size()));
- original_peer_->OnCompletedRequest(URLRequestStatus(), security_info);
+ original_peer_->OnCompletedRequest(URLRequestStatus(),
+ security_info,
+ completion_time);
// The request processing is complete, we must delete ourselves.
delete this;
diff --git a/chrome/common/security_filter_peer.h b/chrome/common/security_filter_peer.h
index 4a44be3..593fbb0 100644
--- a/chrome/common/security_filter_peer.h
+++ b/chrome/common/security_filter_peer.h
@@ -5,6 +5,7 @@
#ifndef CHROME_COMMON_SECURITY_FILTER_PEER_H__
#define CHROME_COMMON_SECURITY_FILTER_PEER_H__
+#pragma once
#include "webkit/glue/resource_loader_bridge.h"
@@ -38,9 +39,11 @@ class SecurityFilterPeer : public webkit_glue::ResourceLoaderBridge::Peer {
virtual void OnReceivedResponse(
const webkit_glue::ResourceLoaderBridge::ResponseInfo& 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 std::string& security_info,
+ const base::Time& completion_time);
virtual GURL GetURLForDebugging() const;
protected:
@@ -69,7 +72,8 @@ class BufferedPeer : public SecurityFilterPeer {
bool content_filtered);
virtual void OnReceivedData(const char* data, int len);
virtual void OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info);
+ const std::string& security_info,
+ const base::Time& completion_time);
protected:
// Invoked when the entire request has been processed before the data is sent
@@ -109,7 +113,8 @@ class ReplaceContentPeer : public SecurityFilterPeer {
bool content_filtered);
void OnReceivedData(const char* data, int len);
void OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info);
+ const std::string& security_info,
+ const base::Time& completion_time);
private:
webkit_glue::ResourceLoaderBridge::ResponseInfo response_info_;
diff --git a/chrome/common/serialized_script_value.cc b/chrome/common/serialized_script_value.cc
index 095f4e6..deff44c 100644
--- a/chrome/common/serialized_script_value.cc
+++ b/chrome/common/serialized_script_value.cc
@@ -4,6 +4,7 @@
#include "chrome/common/serialized_script_value.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSerializedScriptValue.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
using WebKit::WebSerializedScriptValue;
@@ -21,11 +22,8 @@ SerializedScriptValue::SerializedScriptValue(
}
SerializedScriptValue::SerializedScriptValue(
- const WebSerializedScriptValue& value)
- : is_null_(value.isNull()),
- is_invalid_(value.isNull() ? false : value.toString().isNull()),
- data_(value.isNull() ? string16()
- : static_cast<string16>(value.toString())) {
+ const WebSerializedScriptValue& value) {
+ set_web_serialized_script_value(value);
}
SerializedScriptValue::operator WebSerializedScriptValue() const {
@@ -35,3 +33,10 @@ SerializedScriptValue::operator WebSerializedScriptValue() const {
return WebSerializedScriptValue::createInvalid();
return WebSerializedScriptValue::fromString(data_);
}
+
+void SerializedScriptValue::set_web_serialized_script_value(
+ const WebSerializedScriptValue& value) {
+ is_null_ = value.isNull();
+ is_invalid_ = value.isNull() ? false : value.toString().isNull();
+ data_ = value.isNull() ? string16() : static_cast<string16>(value.toString());
+}
diff --git a/chrome/common/serialized_script_value.h b/chrome/common/serialized_script_value.h
index e464134..9848d13 100644
--- a/chrome/common/serialized_script_value.h
+++ b/chrome/common/serialized_script_value.h
@@ -4,9 +4,13 @@
#ifndef CHROME_COMMON_SERIALIZED_SCRIPT_VALUE_H_
#define CHROME_COMMON_SERIALIZED_SCRIPT_VALUE_H_
+#pragma once
#include "base/string16.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebSerializedScriptValue.h"
+
+namespace WebKit {
+class WebSerializedScriptValue;
+}
class SerializedScriptValue {
public:
@@ -23,6 +27,9 @@ class SerializedScriptValue {
void set_data(const string16& data) { data_ = data; }
const string16& data() const { return data_; }
+ void set_web_serialized_script_value(
+ const WebKit::WebSerializedScriptValue& value);
+
operator WebKit::WebSerializedScriptValue() const;
private:
diff --git a/chrome/common/service_messages.cc b/chrome/common/service_messages.cc
new file mode 100644
index 0000000..97a10fd
--- /dev/null
+++ b/chrome/common/service_messages.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/common/service_messages.h"
+
+#define MESSAGES_INTERNAL_IMPL_FILE \
+ "chrome/common/service_messages_internal.h"
+#include "ipc/ipc_message_impl_macros.h"
diff --git a/chrome/common/service_messages.h b/chrome/common/service_messages.h
new file mode 100644
index 0000000..d514bff
--- /dev/null
+++ b/chrome/common/service_messages.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2010 The Chromium Authors. All 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_SERVICE_MESSAGES_H_
+#define CHROME_COMMON_SERVICE_MESSAGES_H_
+
+#include "ipc/ipc_message_utils.h"
+
+#define MESSAGES_INTERNAL_FILE "chrome/common/service_messages_internal.h"
+#include "ipc/ipc_message_macros.h"
+
+#endif // CHROME_COMMON_SERVICE_MESSAGES_H_
+
diff --git a/chrome/common/service_messages_internal.h b/chrome/common/service_messages_internal.h
new file mode 100644
index 0000000..bdacb34
--- /dev/null
+++ b/chrome/common/service_messages_internal.h
@@ -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 <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"
+
+//------------------------------------------------------------------------------
+// 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)
+
+ // 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 enabling the remoting process.
+ IPC_MESSAGE_CONTROL3(ServiceMsg_EnableRemotingWithTokens,
+ std::string, /* username */
+ std::string, /* Token for remoting */
+ std::string /* Token for Google Talk */)
+
+ // Tell the service process to shutdown.
+ IPC_MESSAGE_CONTROL0(ServiceMsg_Shutdown)
+
+IPC_END_MESSAGES(Service)
+
+//------------------------------------------------------------------------------
+// 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 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_END_MESSAGES(ServiceHost)
diff --git a/chrome/common/service_process_type.h b/chrome/common/service_process_type.h
new file mode 100644
index 0000000..7f80ede
--- /dev/null
+++ b/chrome/common/service_process_type.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_COMMON_SERVICE_PROCESS_TYPE_H_
+#define CHROME_COMMON_SERVICE_PROCESS_TYPE_H_
+
+// Defines different types of service process.
+enum ServiceProcessType {
+ // A service process that hosts a cloud print proxy.
+ kServiceProcessCloudPrint,
+
+ // A service process that hosts a remoting host process.
+ kServiceProcessRemoting,
+};
+
+#endif // CHROME_COMMON_SERVICE_PROCESS_TYPE_H_
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc
new file mode 100644
index 0000000..df3839c
--- /dev/null
+++ b/chrome/common/service_process_util.cc
@@ -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.
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/service_process_util.h"
+
+#if defined(OS_WIN)
+#include "base/scoped_handle_win.h"
+#endif
+
+// TODO(hclam): Split this file for different platforms.
+std::string GetServiceProcessChannelName() {
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+
+ // TODO(sanjeevr): We need to actually figure out the right way to determine
+ // a channel name. The below is to facilitate testing only.
+#if defined(OS_WIN)
+ std::string channel_name = WideToUTF8(user_data_dir.value());
+#elif defined(OS_POSIX)
+ std::string channel_name = user_data_dir.value();
+#endif // defined(OS_WIN)
+ std::replace(channel_name.begin(), channel_name.end(), '\\', '!');
+ channel_name.append("_service_ipc");
+ return channel_name;
+}
+
+// Gets the name of the lock file for service process.
+static FilePath GetServiceProcessLockFilePath(ServiceProcessType type) {
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ return user_data_dir.Append(FILE_PATH_LITERAL("Service Process Lock"));
+}
+
+#if defined(OS_WIN)
+static std::wstring GetServiceProcessEventName(
+ ServiceProcessType type) {
+ FilePath path = GetServiceProcessLockFilePath(type);
+ std::wstring event_name = path.value();
+ std::replace(event_name.begin(), event_name.end(), '\\', '!');
+ return event_name;
+}
+
+// An event that is signaled when a service process is running. This
+// variable is used only in the service process.
+static ScopedHandle service_process_running_event;
+#endif
+
+void SignalServiceProcessRunning(ServiceProcessType type) {
+#if defined(OS_WIN)
+ std::wstring event_name = GetServiceProcessEventName(type);
+ service_process_running_event.Set(
+ CreateEvent(NULL, true, true, event_name.c_str()));
+ DCHECK(service_process_running_event.IsValid());
+#else
+ // TODO(hclam): Implement better mechanism for these platform.
+ const FilePath path = GetServiceProcessLockFilePath(type);
+ FILE* file = file_util::OpenFile(path, "wb+");
+ if (!file)
+ return;
+ LOG(INFO) << "Created Service Process lock file: " << path.value();
+ file_util::TruncateFile(file) && file_util::CloseFile(file);
+#endif
+}
+
+void SignalServiceProcessStopped(ServiceProcessType type) {
+#if defined(OS_WIN)
+ // Close the handle to the event.
+ service_process_running_event.Close();
+#else
+ // TODO(hclam): Implement better mechanism for these platform.
+ const FilePath path = GetServiceProcessLockFilePath(type);
+ file_util::Delete(path, false);
+#endif
+}
+
+bool CheckServiceProcessRunning(ServiceProcessType type) {
+#if defined(OS_WIN)
+ std::wstring event_name = GetServiceProcessEventName(type);
+ ScopedHandle event(
+ OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
+ if (!event.IsValid())
+ return false;
+ // Check if the event is signaled.
+ return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
+#else
+ // TODO(hclam): Implement better mechanism for these platform.
+ const FilePath path = GetServiceProcessLockFilePath(type);
+ return file_util::PathExists(path);
+#endif
+}
diff --git a/chrome/common/service_process_util.h b/chrome/common/service_process_util.h
new file mode 100644
index 0000000..37ea33c
--- /dev/null
+++ b/chrome/common/service_process_util.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_SERVICE_PROCESS_UTIL_H_
+#define CHROME_COMMON_SERVICE_PROCESS_UTIL_H_
+
+#include <string>
+
+#include "chrome/common/service_process_type.h"
+
+class Profile;
+
+// Return the IPC channel to connect to the service process.
+//
+// TODO(hclam): Need more information to come up with the channel name.
+std::string GetServiceProcessChannelName();
+
+// The following methods are used as a mechanism to signal a service process
+// is running properly and all initialized.
+//
+// Signal that the service process is running.
+// This method is called when the service process is running and initialized.
+void SignalServiceProcessRunning(ServiceProcessType type);
+
+// Signal that the service process is stopped.
+void SignalServiceProcessStopped(ServiceProcessType type);
+
+// This method checks that if the service process is running.
+bool CheckServiceProcessRunning(ServiceProcessType type);
+
+#endif // CHROME_COMMON_SERVICE_PROCESS_UTIL_H_
diff --git a/chrome/common/socket_stream_dispatcher.cc b/chrome/common/socket_stream_dispatcher.cc
index 97aed21..1ad0be6 100644
--- a/chrome/common/socket_stream_dispatcher.cc
+++ b/chrome/common/socket_stream_dispatcher.cc
@@ -7,11 +7,14 @@
#include <vector>
#include "base/id_map.h"
+#include "base/message_loop.h"
#include "base/ref_counted.h"
+#include "base/task.h"
#include "chrome/common/child_thread.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/net/socket_stream.h"
#include "googleurl/src/gurl.h"
+#include "ipc/ipc_message.h"
#include "webkit/glue/websocketstreamhandle_bridge.h"
#include "webkit/glue/websocketstreamhandle_delegate.h"
diff --git a/chrome/common/socket_stream_dispatcher.h b/chrome/common/socket_stream_dispatcher.h
index 8e3bbe4..e0bf58f 100644
--- a/chrome/common/socket_stream_dispatcher.h
+++ b/chrome/common/socket_stream_dispatcher.h
@@ -4,13 +4,24 @@
#ifndef CHROME_COMMON_SOCKET_STREAM_DISPATCHER_H_
#define CHROME_COMMON_SOCKET_STREAM_DISPATCHER_H_
+#pragma once
#include <vector>
#include "base/basictypes.h"
-#include "ipc/ipc_channel.h"
-#include "ipc/ipc_message.h"
-#include "webkit/glue/websocketstreamhandle_bridge.h"
+
+namespace IPC {
+class Message;
+}
+
+namespace WebKit {
+class WebSocketStreamHandle;
+}
+
+namespace webkit_glue {
+class WebSocketStreamHandleBridge;
+class WebSocketStreamHandleDelegate;
+}
// Dispatches socket stream related messages sent to a child process from the
// main browser process. There is one instance per child process. Messages
diff --git a/chrome/common/spellcheck_common.cc b/chrome/common/spellcheck_common.cc
index d1abfa5..c52dcba 100644
--- a/chrome/common/spellcheck_common.cc
+++ b/chrome/common/spellcheck_common.cc
@@ -46,8 +46,10 @@ static const struct {
{"ru", "ru-RU"},
{"sk", "sk-SK"},
{"sl", "sl-SI"},
+ {"sr", "sr"},
{"sv", "sv-SE"},
{"tr", "tr-TR"},
+ {"uk", "uk-UA"},
{"vi", "vi-VN"},
};
@@ -98,6 +100,8 @@ FilePath GetVersionedFileName(const std::string& input_language,
{"ro-RO", "-2-0"},
{"ru-RU", "-2-0"},
{"bg-BG", "-2-0"},
+ {"sr", "-2-0"},
+ {"uk-UA", "-2-0"},
};
// Generate the bdict file name using default version string or special
diff --git a/chrome/common/spellcheck_common.h b/chrome/common/spellcheck_common.h
index 5c2569e..9074e16 100644
--- a/chrome/common/spellcheck_common.h
+++ b/chrome/common/spellcheck_common.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_SPELLCHECK_COMMON_H_
#define CHROME_COMMON_SPELLCHECK_COMMON_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/chrome/common/sqlite_compiled_statement.cc b/chrome/common/sqlite_compiled_statement.cc
index f54182a..19b9e53 100644
--- a/chrome/common/sqlite_compiled_statement.cc
+++ b/chrome/common/sqlite_compiled_statement.cc
@@ -7,7 +7,7 @@
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "chrome/common/sqlite_utils.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
// SqliteStatementCache -------------------------------------------------------
diff --git a/chrome/common/sqlite_compiled_statement.h b/chrome/common/sqlite_compiled_statement.h
index 01b7f1e..edc60de 100644
--- a/chrome/common/sqlite_compiled_statement.h
+++ b/chrome/common/sqlite_compiled_statement.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_SQLITE_COMPILED_STATEMENT_H_
#define CHROME_COMMON_SQLITE_COMPILED_STATEMENT_H_
+#pragma once
#include <map>
#include <string>
diff --git a/chrome/common/sqlite_utils.cc b/chrome/common/sqlite_utils.cc
index ed383be..d11b925 100644
--- a/chrome/common/sqlite_utils.cc
+++ b/chrome/common/sqlite_utils.cc
@@ -6,7 +6,6 @@
#include <list>
-#include "base/at_exit.h"
#include "base/file_path.h"
#include "base/lock.h"
#include "base/logging.h"
diff --git a/chrome/common/sqlite_utils.h b/chrome/common/sqlite_utils.h
index f7351a2..9b0180c 100644
--- a/chrome/common/sqlite_utils.h
+++ b/chrome/common/sqlite_utils.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_SQLITE_UTILS_H_
#define CHROME_COMMON_SQLITE_UTILS_H_
+#pragma once
#include <string>
#include <vector>
@@ -12,7 +13,7 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
-#include "third_party/sqlite/preprocessed/sqlite3.h"
+#include "third_party/sqlite/sqlite3.h"
// forward declarations of classes defined here
class FilePath;
diff --git a/chrome/common/switch_utils.cc b/chrome/common/switch_utils.cc
new file mode 100644
index 0000000..d202bcb
--- /dev/null
+++ b/chrome/common/switch_utils.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/common/switch_utils.h"
+
+#include "chrome/common/chrome_switches.h"
+
+namespace switches {
+
+// Switches enumerated here will be removed when a background instance of
+// Chrome restarts itself. If your key is designed to only be used once,
+// or if it does not make sense when restarting a background instance to
+// pick up an automatic update, be sure to add it to this list.
+const char* const kSwitchesToRemoveOnAutorestart[] = {
+ switches::kApp,
+ switches::kFirstRun,
+ switches::kImport,
+ switches::kImportFromFile,
+ switches::kMakeDefaultBrowser
+};
+
+void RemoveSwitchesForAutostart(
+ std::map<std::string, CommandLine::StringType>* switch_list) {
+ for (size_t i = 0; i < arraysize(kSwitchesToRemoveOnAutorestart); ++i)
+ switch_list->erase(kSwitchesToRemoveOnAutorestart[i]);
+}
+
+} // namespace switches
diff --git a/chrome/common/switch_utils.h b/chrome/common/switch_utils.h
new file mode 100644
index 0000000..3c9088b
--- /dev/null
+++ b/chrome/common/switch_utils.h
@@ -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.
+
+#ifndef CHROME_COMMON_SWITCH_UTILS_H_
+#define CHROME_COMMON_SWITCH_UTILS_H_
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "base/command_line.h"
+
+namespace switches {
+
+// Remove the keys that we shouldn't pass through during restart.
+void RemoveSwitchesForAutostart(
+ std::map<std::string, CommandLine::StringType>* switches);
+
+} // namespace switches
+
+#endif // CHROME_COMMON_SWITCH_UTILS_H_
diff --git a/chrome/common/switch_utils_unittest.cc b/chrome/common/switch_utils_unittest.cc
new file mode 100644
index 0000000..2c73b17
--- /dev/null
+++ b/chrome/common/switch_utils_unittest.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/common/switch_utils.h"
+
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SwitchUtilsTest, RemoveSwitches) {
+#if defined(OS_WIN)
+ // All these command line args (except foo and bar) will
+ // be removed after RemoveSwitchesForAutostart:
+ CommandLine cmd_line = CommandLine::FromString(
+ L"program"
+ L" --app=http://www.google.com/"
+ L" --first-run"
+ L" --import"
+ L" --import-from-file=c:\\test.html"
+ L" --make-default-browser"
+ L" --foo"
+ L" --bar");
+ EXPECT_FALSE(cmd_line.command_line_string().empty());
+#elif defined(OS_POSIX)
+ const char* argv[] = {
+ "program",
+ "--app=http://www.google.com/",
+ "--first-run",
+ "--import",
+ "--import-from-file=c:\\test.html",
+ "--make-default-browser",
+ "--foo",
+ "--bar"};
+ CommandLine cmd_line(arraysize(argv), argv);
+#endif
+
+ std::map<std::string, CommandLine::StringType> switches =
+ cmd_line.GetSwitches();
+ EXPECT_EQ(7U, switches.size());
+
+ switches::RemoveSwitchesForAutostart(&switches);
+ EXPECT_EQ(2U, switches.size());
+ EXPECT_TRUE(cmd_line.HasSwitch("foo"));
+ EXPECT_TRUE(cmd_line.HasSwitch("bar"));
+}
diff --git a/chrome/common/thumbnail_score.h b/chrome/common/thumbnail_score.h
index c3a5a90..30bcf8f 100644
--- a/chrome/common/thumbnail_score.h
+++ b/chrome/common/thumbnail_score.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_THUMBNAIL_SCORE_H_
#define CHROME_COMMON_THUMBNAIL_SCORE_H_
+#pragma once
#include "base/time.h"
diff --git a/chrome/common/time_format.cc b/chrome/common/time_format.cc
index 4ca5187..c62f4f5 100644
--- a/chrome/common/time_format.cc
+++ b/chrome/common/time_format.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,11 +7,11 @@
#include <vector>
#include "app/l10n_util.h"
-#include "base/i18n/time_formatting.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"
#include "base/utf_string_conversions.h"
#include "grit/generated_resources.h"
@@ -205,7 +205,7 @@ void TimeFormatter::BuildFormats(
icu::UnicodeString pattern;
for (size_t j = 0; j < arraysize(kKeywords); ++j) {
int msg_id = message_ids.ids[i][j];
- std::string sub_pattern = WideToUTF8(l10n_util::GetString(msg_id));
+ std::string sub_pattern = l10n_util::GetStringUTF8(msg_id);
// NA means this keyword is not used in the current locale.
// Even if a translator translated for this keyword, we do not
// use it unless it's 'other' (j=0) or it's defined in the rules
@@ -255,11 +255,10 @@ icu::PluralFormat* TimeFormatter::createFallbackFormat(
Singleton<TimeFormatter> time_formatter;
-static std::wstring FormatTimeImpl(const TimeDelta& delta,
- FormatType format_type) {
+static string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
if (delta.ToInternalValue() < 0) {
NOTREACHED() << "Negative duration";
- return std::wstring();
+ return string16();
}
int number;
@@ -297,31 +296,31 @@ static std::wstring FormatTimeImpl(const TimeDelta& delta,
// With the fallback added, this should never fail.
DCHECK(U_SUCCESS(error));
int capacity = time_string.length() + 1;
- string16 result_utf16;
+ string16 result;
time_string.extract(static_cast<UChar*>(
- WriteInto(&result_utf16, capacity)),
+ WriteInto(&result, capacity)),
capacity, error);
DCHECK(U_SUCCESS(error));
- return UTF16ToWide(result_utf16);
+ return result;
}
// static
-std::wstring TimeFormat::TimeElapsed(const TimeDelta& delta) {
+string16 TimeFormat::TimeElapsed(const TimeDelta& delta) {
return FormatTimeImpl(delta, FORMAT_ELAPSED);
}
// static
-std::wstring TimeFormat::TimeRemaining(const TimeDelta& delta) {
+string16 TimeFormat::TimeRemaining(const TimeDelta& delta) {
return FormatTimeImpl(delta, FORMAT_REMAINING);
}
// static
-std::wstring TimeFormat::TimeRemainingShort(const TimeDelta& delta) {
+string16 TimeFormat::TimeRemainingShort(const TimeDelta& delta) {
return FormatTimeImpl(delta, FORMAT_SHORT);
}
// static
-std::wstring TimeFormat::RelativeDate(
+string16 TimeFormat::RelativeDate(
const Time& time,
const Time* optional_midnight_today) {
Time midnight_today = optional_midnight_today ? *optional_midnight_today :
@@ -329,10 +328,10 @@ std::wstring TimeFormat::RelativeDate(
// Filter out "today" and "yesterday"
if (time >= midnight_today)
- return l10n_util::GetString(IDS_PAST_TIME_TODAY);
+ return l10n_util::GetStringUTF16(IDS_PAST_TIME_TODAY);
else if (time >= midnight_today -
TimeDelta::FromMicroseconds(Time::kMicrosecondsPerDay))
- return l10n_util::GetString(IDS_PAST_TIME_YESTERDAY);
+ return l10n_util::GetStringUTF16(IDS_PAST_TIME_YESTERDAY);
- return std::wstring();
+ return string16();
}
diff --git a/chrome/common/time_format.h b/chrome/common/time_format.h
index c04ed62..86c80b2 100644
--- a/chrome/common/time_format.h
+++ b/chrome/common/time_format.h
@@ -1,13 +1,14 @@
-// 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.
#ifndef CHROME_COMMON_TIME_FORMAT_H__
#define CHROME_COMMON_TIME_FORMAT_H__
+#pragma once
// This file defines methods to format time values as strings.
-#include <string>
+#include "base/string16.h"
#include "unicode/smpdtfmt.h"
@@ -24,13 +25,13 @@ class TimeFormat {
// in-progress operations and users have different expectations of units.
// Returns times in elapsed-format: "3 mins ago", "2 days ago".
- static std::wstring TimeElapsed(const base::TimeDelta& delta);
+ static string16 TimeElapsed(const base::TimeDelta& delta);
// Returns times in remaining-format: "3 mins left", "2 days left".
- static std::wstring TimeRemaining(const base::TimeDelta& delta);
+ static string16 TimeRemaining(const base::TimeDelta& delta);
// Returns times in short-format: "3 mins", "2 days".
- static std::wstring TimeRemainingShort(const base::TimeDelta& delta);
+ static string16 TimeRemainingShort(const base::TimeDelta& delta);
// For displaying a relative time in the past. This method returns either
// "Today", "Yesterday", or an empty string if it's older than that.
@@ -45,8 +46,8 @@ class TimeFormat {
// If NULL, the current day's midnight will be retrieved, which can be
// slow. If many items are being processed, it is best to get the current
// time once at the beginning and pass it for each computation.
- static std::wstring RelativeDate(const base::Time& time,
- const base::Time* optional_midnight_today);
+ static string16 RelativeDate(const base::Time& time,
+ const base::Time* optional_midnight_today);
};
#endif // CHROME_COMMON_TIME_FORMAT_H__
diff --git a/chrome/common/time_format_unittest.cc b/chrome/common/time_format_unittest.cc
index d437859..31976e3 100644
--- a/chrome/common/time_format_unittest.cc
+++ b/chrome/common/time_format_unittest.cc
@@ -1,12 +1,13 @@
-// 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 <time.h>
-#include "app/l10n_util.h"
#include "base/basictypes.h"
+#include "base/string16.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/common/time_format.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,26 +16,27 @@ using base::TimeDelta;
TEST(TimeFormat, RelativeDate) {
Time now = Time::Now();
- std::wstring today_str = TimeFormat::RelativeDate(now, NULL);
- EXPECT_EQ(L"Today", today_str);
+ string16 today_str = TimeFormat::RelativeDate(now, NULL);
+ EXPECT_EQ(ASCIIToUTF16("Today"), today_str);
Time yesterday = now - TimeDelta::FromDays(1);
- std::wstring yesterday_str = TimeFormat::RelativeDate(yesterday, NULL);
- EXPECT_EQ(L"Yesterday", yesterday_str);
+ string16 yesterday_str = TimeFormat::RelativeDate(yesterday, NULL);
+ EXPECT_EQ(ASCIIToUTF16("Yesterday"), yesterday_str);
Time two_days_ago = now - TimeDelta::FromDays(2);
- std::wstring two_days_ago_str = TimeFormat::RelativeDate(two_days_ago, NULL);
+ string16 two_days_ago_str = TimeFormat::RelativeDate(two_days_ago, NULL);
EXPECT_TRUE(two_days_ago_str.empty());
Time a_week_ago = now - TimeDelta::FromDays(7);
- std::wstring a_week_ago_str = TimeFormat::RelativeDate(a_week_ago, NULL);
+ string16 a_week_ago_str = TimeFormat::RelativeDate(a_week_ago, NULL);
EXPECT_TRUE(a_week_ago_str.empty());
}
namespace {
-void TestTimeFormats(const TimeDelta delta, const std::wstring& expected) {
- std::wstring expected_left = expected + L" left";
- std::wstring expected_ago = expected + L" ago";
+void TestTimeFormats(const TimeDelta delta, const char* expected_ascii) {
+ string16 expected = ASCIIToUTF16(expected_ascii);
+ string16 expected_left = expected + ASCIIToUTF16(" left");
+ string16 expected_ago = expected + ASCIIToUTF16(" ago");
EXPECT_EQ(expected, TimeFormat::TimeRemainingShort(delta));
EXPECT_EQ(expected_left, TimeFormat::TimeRemaining(delta));
EXPECT_EQ(expected_ago, TimeFormat::TimeElapsed(delta));
@@ -55,15 +57,15 @@ TEST(TimeFormat, FormatTime) {
// TODO(jungshik) : These test only pass when the OS locale is 'en'.
// We need to add SetUp() and TearDown() to set the locale to 'en'.
- TestTimeFormats(twohundred_millisecs, L"0 secs");
- TestTimeFormats(one_sec - twohundred_millisecs, L"0 secs");
- TestTimeFormats(one_sec + twohundred_millisecs, L"1 sec");
- TestTimeFormats(five_secs + twohundred_millisecs, L"5 secs");
- TestTimeFormats(one_min + five_secs, L"1 min");
- TestTimeFormats(three_mins + twohundred_millisecs, L"3 mins");
- TestTimeFormats(one_hour + five_secs, L"1 hour");
- TestTimeFormats(four_hours + five_secs, L"4 hours");
- TestTimeFormats(one_day + five_secs, L"1 day");
- TestTimeFormats(three_days, L"3 days");
- TestTimeFormats(three_days + four_hours, L"3 days");
+ TestTimeFormats(twohundred_millisecs, "0 secs");
+ TestTimeFormats(one_sec - twohundred_millisecs, "0 secs");
+ TestTimeFormats(one_sec + twohundred_millisecs, "1 sec");
+ TestTimeFormats(five_secs + twohundred_millisecs, "5 secs");
+ TestTimeFormats(one_min + five_secs, "1 min");
+ TestTimeFormats(three_mins + twohundred_millisecs, "3 mins");
+ TestTimeFormats(one_hour + five_secs, "1 hour");
+ TestTimeFormats(four_hours + five_secs, "4 hours");
+ TestTimeFormats(one_day + five_secs, "1 day");
+ TestTimeFormats(three_days, "3 days");
+ TestTimeFormats(three_days + four_hours, "3 days");
}
diff --git a/chrome/common/translate_errors.h b/chrome/common/translate_errors.h
index 1c6ea8a..33e5c3d 100644
--- a/chrome/common/translate_errors.h
+++ b/chrome/common/translate_errors.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_TRANSLATE_ERRORS_H_
#define CHROME_COMMON_TRANSLATE_ERRORS_H_
+#pragma once
// This file consolidates all the error types for translation of a page.
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index a2a32bd..7e880d3 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -10,6 +10,7 @@
namespace chrome {
const char kAboutScheme[] = "about";
+const char kBlobScheme[] = "blob";
const char kChromeInternalScheme[] = "chrome-internal";
const char kChromeUIScheme[] = "chrome";
const char kDataScheme[] = "data";
@@ -41,69 +42,94 @@ const char* kSavableSchemes[] = {
NULL
};
+const char kAboutAboutURL[] = "about:about";
const char kAboutAppCacheInternalsURL[] = "about:appcache-internals";
const char kAboutBlankURL[] = "about:blank";
const char kAboutCacheURL[] = "about:cache";
const char kAboutCrashURL[] = "about:crash";
const char kAboutCreditsURL[] = "about:credits";
+const char kAboutDNSURL[] = "about:dns";
+const char kAboutGpuCrashURL[] = "about:gpucrash";
+const char kAboutGpuHangURL[] = "about:gpuhang";
const char kAboutHangURL[] = "about:hang";
+const char kAboutHistogramsURL[] = "about:histograms";
+const char kAboutLabsURL[] = "about:labs";
const char kAboutMemoryURL[] = "about:memory";
const char kAboutNetInternalsURL[] = "about:net-internals";
const char kAboutPluginsURL[] = "about:plugins";
const char kAboutShorthangURL[] = "about:shorthang";
-const char kAboutSystemURL[] = "about:system";
const char kAboutTermsURL[] = "about:terms";
-const char kAboutAboutURL[] = "about:about";
-const char kAboutDNSURL[] = "about:dns";
-const char kAboutHistogramsURL[] = "about:histograms";
+const char kAboutVaporwareURL[] = "about:vaporware";
const char kAboutVersionURL[] = "about:version";
// Use an obfuscated URL to make this nondiscoverable, we only want this
// to be used for testing.
const char kAboutBrowserCrash[] = "about:inducebrowsercrashforrealz";
+const char kChromeUIAboutURL[] = "chrome://settings/about";
const char kChromeUIAppLauncherURL[] = "chrome://newtab/#mode=app-launcher";
const char kChromeUIBookmarksURL[] = "chrome://bookmarks/";
+const char kChromeUIBugReportURL[] = "chrome://bugreport/";
const char kChromeUIDevToolsURL[] = "chrome://devtools/";
const char kChromeUIDownloadsURL[] = "chrome://downloads/";
const char kChromeUIExtensionsURL[] = "chrome://extensions/";
const char kChromeUIFavIconURL[] = "chrome://favicon/";
-const char kChromeUIFileBrowseURL[] = "chrome://filebrowse/";
-const char kChromeUIHistoryURL[] = "chrome://history/";
const char kChromeUIHistory2URL[] = "chrome://history2/";
+const char kChromeUIHistoryURL[] = "chrome://history/";
const char kChromeUIIPCURL[] = "chrome://about/ipc";
-const char kChromeUIMediaplayerURL[] = "chrome://mediaplayer/";
+const char kChromeUIKeyboardURL[] = "chrome://keyboard/";
+const char kChromeUILabsURL[] = "chrome://labs/";
const char kChromeUINewTabURL[] = "chrome://newtab";
-const char kChromeUIOptionsURL[] = "chrome://options/";
const char kChromeUIPluginsURL[] = "chrome://plugins/";
const char kChromeUIPrintURL[] = "chrome://print/";
+const char kChromeUISettingsURL[] = "chrome://settings/";
+
+#if defined(OS_CHROMEOS)
+const char kChromeUIFileBrowseURL[] = "chrome://filebrowse/";
+const char kChromeUIImageBurnerURL[] = "chrome://imageburner/";
+const char kChromeUIMediaplayerURL[] = "chrome://mediaplayer/";
+const char kChromeUIMobileSetupURL[] = "chrome://mobilesetup/";
const char kChromeUIRegisterPageURL[] = "chrome://register/";
const char kChromeUISlideshowURL[] = "chrome://slideshow/";
+const char kChromeUISystemInfoURL[] = "chrome://system/";
+#endif
+// Keep this list sorted please.
const char kChromeUIBookmarksHost[] = "bookmarks";
+const char kChromeUIBugReportHost[] = "bugreport";
const char kChromeUIDevToolsHost[] = "devtools";
const char kChromeUIDialogHost[] = "dialog";
const char kChromeUIDownloadsHost[] = "downloads";
const char kChromeUIExtensionsHost[] = "extensions";
const char kChromeUIFavIconHost[] = "favicon";
-const char kChromeUIFileBrowseHost[] = "filebrowse";
const char kChromeUIHistoryHost[] = "history";
const char kChromeUIHistory2Host[] = "history2";
const char kChromeUIInspectorHost[] = "inspector";
-const char kChromeUIMediaplayerHost[] = "mediaplayer";
+const char kChromeUIKeyboardHost[] = "keyboard";
+const char kChromeUILabsHost[] = "labs";
const char kChromeUINetInternalsHost[] = "net-internals";
const char kChromeUINewTabHost[] = "newtab";
-const char kChromeUIOptionsHost[] = "options";
const char kChromeUIPluginsHost[] = "plugins";
const char kChromeUIPrintHost[] = "print";
-const char kChromeUIRegisterPageHost[] = "register";
const char kChromeUIRemotingHost[] = "remoting";
+const char kChromeUIRemotingResourcesHost[] = "remotingresources";
const char kChromeUIResourcesHost[] = "resources";
-const char kChromeUISlideshowHost[] = "slideshow";
+const char kChromeUIScreenshotPath[] = "screenshots";
+const char kChromeUISettingsHost[] = "settings";
const char kChromeUISyncResourcesHost[] = "syncresources";
const char kChromeUIThemePath[] = "theme";
const char kChromeUIThumbnailPath[] = "thumb";
+#if defined(OS_CHROMEOS)
+const char kChromeUIFileBrowseHost[] = "filebrowse";
+const char kChromeUIImageBurnerHost[] = "imageburner";
+const char kChromeUIMediaplayerHost[] = "mediaplayer";
+const char kChromeUIMobileSetupHost[] = "mobilesetup";
+const char kChromeUIRegisterPageHost[] = "register";
+const char kChromeUISlideshowHost[] = "slideshow";
+const char kChromeUISystemInfoHost[] = "system";
+#endif
+
const char kAppCacheViewInternalsURL[] = "chrome://appcache-internals/";
const char kCloudPrintResourcesURL[] = "chrome://cloudprintresources/";
@@ -112,6 +138,22 @@ const char kCloudPrintResourcesHost[] = "cloudprintresources";
const char kNetworkViewInternalsURL[] = "chrome://net-internals/";
const char kNetworkViewCacheURL[] = "chrome://view-http-cache/";
+// Option sub pages.
+const char kDefaultOptionsSubPage[] = "";
+const char kBrowserOptionsSubPage[] = "browser";
+const char kPersonalOptionsSubPage[] = "personal";
+const char kAdvancedOptionsSubPage[] = "advanced";
+const char kAutoFillSubPage[] = "autoFillOptions";
+const char kSearchEnginesOptionsSubPage[] = "editSearchEngineOverlay";
+const char kClearBrowserDataSubPage[] = "clearBrowserDataOverlay";
+const char kImportDataSubPage[] = "importDataOverlay";
+const char kContentSettingsSubPage[] = "content";
+#if defined(OS_CHROMEOS)
+const char kSystemOptionsSubPage[] = "system";
+const char kLanguageOptionsSubPage[] = "language";
+const char kInternetOptionsSubPage[] = "internet";
+#endif
+
void RegisterChromeSchemes() {
// Don't need "chrome-internal" which was used in old versions of Chrome for
// the new tab page.
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 216ffb1..ecde9ee 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -6,11 +6,13 @@
#ifndef CHROME_COMMON_URL_CONSTANTS_H_
#define CHROME_COMMON_URL_CONSTANTS_H_
+#pragma once
namespace chrome {
// Canonical schemes you can use as input to GURL.SchemeIs().
extern const char kAboutScheme[];
+extern const char kBlobScheme[];
extern const char kChromeInternalScheme[];
extern const char kChromeUIScheme[]; // The scheme used for DOMUIs.
extern const char kCrosScheme[]; // The scheme used for ChromeOS.
@@ -34,69 +36,93 @@ extern const char kStandardSchemeSeparator[];
extern const char* kSavableSchemes[];
// About URLs (including schemes).
+extern const char kAboutAboutURL[];
extern const char kAboutAppCacheInternalsURL[];
extern const char kAboutBlankURL[];
extern const char kAboutBrowserCrash[];
extern const char kAboutCacheURL[];
-extern const char kAboutNetInternalsURL[];
extern const char kAboutCrashURL[];
extern const char kAboutCreditsURL[];
+extern const char kAboutDNSURL[];
+extern const char kAboutGpuCrashURL[];
+extern const char kAboutGpuHangURL[];
extern const char kAboutHangURL[];
+extern const char kAboutHistogramsURL[];
+extern const char kAboutLabsURL[];
extern const char kAboutMemoryURL[];
+extern const char kAboutNetInternalsURL[];
extern const char kAboutPluginsURL[];
extern const char kAboutShorthangURL[];
-extern const char kAboutSystemURL[];
extern const char kAboutTermsURL[];
-extern const char kAboutAboutURL[];
-extern const char kAboutDNSURL[];
-extern const char kAboutHistogramsURL[];
+extern const char kAboutVaporwareURL[];
extern const char kAboutVersionURL[];
// chrome: URLs (including schemes). Should be kept in sync with the
// components below.
+extern const char kChromeUIAboutURL[];
extern const char kChromeUIAppLauncherURL[];
extern const char kChromeUIBookmarksURL[];
+extern const char kChromeUIBugReportURL[];
extern const char kChromeUIDevToolsURL[];
extern const char kChromeUIDownloadsURL[];
extern const char kChromeUIExtensionsURL[];
extern const char kChromeUIFavIconURL[];
-extern const char kChromeUIFileBrowseURL[];
-extern const char kChromeUIHistoryURL[];
extern const char kChromeUIHistory2URL[];
+extern const char kChromeUIHistoryURL[];
extern const char kChromeUIIPCURL[];
-extern const char kChromeUIMediaplayerURL[];
+extern const char kChromeUIKeyboardURL[];
+extern const char kChromeUILabsURL[];
extern const char kChromeUINewTabURL[];
-extern const char kChromeUIOptionsURL[];
extern const char kChromeUIPluginsURL[];
extern const char kChromeUIPrintURL[];
+extern const char kChromeUISettingsURL[];
+
+#if defined(OS_CHROMEOS)
+extern const char kChromeUIFileBrowseURL[];
+extern const char kChromeUIImageBurnerURL[];
+extern const char kChromeUIMediaplayerURL[];
+extern const char kChromeUIMobileSetupURL[];
extern const char kChromeUIRegisterPageURL[];
extern const char kChromeUISlideshowURL[];
+extern const char kChromeUISystemInfoURL[];
+#endif
// chrome components of URLs. Should be kept in sync with the full URLs
// above.
extern const char kChromeUIBookmarksHost[];
+extern const char kChromeUIBugReportHost[];
extern const char kChromeUIDevToolsHost[];
extern const char kChromeUIDialogHost[];
extern const char kChromeUIDownloadsHost[];
extern const char kChromeUIExtensionsHost[];
extern const char kChromeUIFavIconHost[];
-extern const char kChromeUIFileBrowseHost[];
-extern const char kChromeUIHistoryHost[];
extern const char kChromeUIHistory2Host[];
+extern const char kChromeUIHistoryHost[];
extern const char kChromeUIInspectorHost[];
-extern const char kChromeUIMediaplayerHost[];
+extern const char kChromeUIKeyboardHost[];
+extern const char kChromeUILabsHost[];
extern const char kChromeUINetInternalsHost[];
extern const char kChromeUINewTabHost[];
-extern const char kChromeUIOptionsHost[];
extern const char kChromeUIPluginsHost[];
extern const char kChromeUIPrintHost[];
-extern const char kChromeUIRegisterPageHost[];
extern const char kChromeUIRemotingHost[];
+extern const char kChromeUIRemotingResourcesHost[];
extern const char kChromeUIResourcesHost[];
-extern const char kChromeUISlideshowHost[];
+extern const char kChromeUIScreenshotPath[];
+extern const char kChromeUISettingsHost[];
extern const char kChromeUISyncResourcesHost[];
-extern const char kChromeUIThumbnailPath[];
extern const char kChromeUIThemePath[];
+extern const char kChromeUIThumbnailPath[];
+
+#if defined(OS_CHROMEOS)
+extern const char kChromeUIFileBrowseHost[];
+extern const char kChromeUIImageBurnerHost[];
+extern const char kChromeUIMediaplayerHost[];
+extern const char kChromeUIMobileSetupHost[];
+extern const char kChromeUIRegisterPageHost[];
+extern const char kChromeUISlideshowHost[];
+extern const char kChromeUISystemInfoHost[];
+#endif
// AppCache related URL.
extern const char kAppCacheViewInternalsURL[];
@@ -109,6 +135,22 @@ extern const char kCloudPrintResourcesHost[];
extern const char kNetworkViewCacheURL[];
extern const char kNetworkViewInternalsURL[];
+// Options sub-pages.
+extern const char kDefaultOptionsSubPage[];
+extern const char kBrowserOptionsSubPage[];
+extern const char kPersonalOptionsSubPage[];
+extern const char kAdvancedOptionsSubPage[];
+extern const char kAutoFillSubPage[];
+extern const char kSearchEnginesOptionsSubPage[];
+extern const char kClearBrowserDataSubPage[];
+extern const char kImportDataSubPage[];
+extern const char kContentSettingsSubPage[];
+#if defined(OS_CHROMEOS)
+extern const char kSystemOptionsSubPage[];
+extern const char kLanguageOptionsSubPage[];
+extern const char kInternetOptionsSubPage[];
+#endif
+
// Call near the beginning of startup to register Chrome's internal URLs that
// should be parsed as "standard" with the googleurl library.
void RegisterChromeSchemes();
diff --git a/chrome/common/utility_messages.cc b/chrome/common/utility_messages.cc
new file mode 100644
index 0000000..b0cd5cc
--- /dev/null
+++ b/chrome/common/utility_messages.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/common/utility_messages.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"
diff --git a/chrome/common/utility_messages.h b/chrome/common/utility_messages.h
index 867131f..49bc9ce 100644
--- a/chrome/common/utility_messages.h
+++ b/chrome/common/utility_messages.h
@@ -1,18 +1,17 @@
-// 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.
#ifndef CHROME_COMMON_UTILITY_MESSAGES_H_
#define CHROME_COMMON_UTILITY_MESSAGES_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/values.h"
#include "chrome/common/common_param_traits.h"
#include "chrome/common/extensions/update_manifest.h"
+#include "chrome/common/indexed_db_param_traits.h"
#include "ipc/ipc_message_utils.h"
namespace IPC {
@@ -35,18 +34,18 @@ struct ParamTraits<UpdateManifest::Result> {
ReadParam(m, iter, &p->package_hash) &&
ReadParam(m, iter, &p->crx_url);
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.extension_id, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.version, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.browser_min_version, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.package_hash, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.crx_url, l);
- l->append(L")");
+ l->append(")");
}
};
@@ -61,12 +60,12 @@ struct ParamTraits<UpdateManifest::Results> {
return ReadParam(m, iter, &p->list) &&
ReadParam(m, iter, &p->daystart_elapsed_seconds);
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
LogParam(p.list, l);
- l->append(L", ");
+ l->append(", ");
LogParam(p.daystart_elapsed_seconds, l);
- l->append(L")");
+ l->append(")");
}
};
diff --git a/chrome/common/utility_messages_internal.h b/chrome/common/utility_messages_internal.h
index 9231501..15bd8d6 100644
--- a/chrome/common/utility_messages_internal.h
+++ b/chrome/common/utility_messages_internal.h
@@ -17,7 +17,11 @@
#include "gfx/rect.h"
#include "printing/native_metafile.h"
#include "printing/page_range.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+
+class FilePath;
+class IndexedDBKey;
+class SerializedScriptValue;
+class SkBitmap;
//------------------------------------------------------------------------------
// Utility process messages:
@@ -48,6 +52,20 @@ IPC_BEGIN_MESSAGES(Utility)
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)
//------------------------------------------------------------------------------
@@ -111,4 +129,15 @@ IPC_BEGIN_MESSAGES(UtilityHost)
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 failed in obtaining the value for
+ // IDBKeyPath.
+ IPC_MESSAGE_CONTROL1(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed,
+ int /* id */)
+
IPC_END_MESSAGES(UtilityHost)
diff --git a/chrome/common/view_types.cc b/chrome/common/view_types.cc
index c32174b..73c604f 100644
--- a/chrome/common/view_types.cc
+++ b/chrome/common/view_types.cc
@@ -5,8 +5,6 @@
#include "chrome/common/view_types.h"
const char* ViewType::kTabContents = "TAB";
-const char* ViewType::kToolstrip = "TOOLSTRIP";
-const char* ViewType::kMole = "MOLE";
const char* ViewType::kBackgroundPage = "BACKGROUND";
const char* ViewType::kPopup = "POPUP";
const char* ViewType::kInfobar = "INFOBAR";
diff --git a/chrome/common/view_types.h b/chrome/common/view_types.h
index 697ebbd..2d9c539 100644
--- a/chrome/common/view_types.h
+++ b/chrome/common/view_types.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_VIEW_TYPES_H_
#define CHROME_COMMON_VIEW_TYPES_H_
+#pragma once
#include "base/basictypes.h"
@@ -14,8 +15,6 @@ class ViewType {
INVALID,
BACKGROUND_CONTENTS,
TAB_CONTENTS,
- EXTENSION_TOOLSTRIP,
- EXTENSION_MOLE,
EXTENSION_BACKGROUND_PAGE,
EXTENSION_POPUP,
EXTENSION_INFOBAR,
@@ -27,8 +26,6 @@ class ViewType {
// Constant strings corresponding to the Type enumeration values. Used
// when converting JS arguments.
static const char* kTabContents;
- static const char* kToolstrip;
- static const char* kMole;
static const char* kBackgroundPage;
static const char* kPopup;
static const char* kInfobar;
diff --git a/chrome/common/visitedlink_common.cc b/chrome/common/visitedlink_common.cc
index 2782311..9cd1e84 100644
--- a/chrome/common/visitedlink_common.cc
+++ b/chrome/common/visitedlink_common.cc
@@ -4,8 +4,11 @@
#include "chrome/common/visitedlink_common.h"
+#include <string.h> // for memset()
+
#include "base/logging.h"
#include "base/md5.h"
+#include "googleurl/src/gurl.h"
const VisitedLinkCommon::Fingerprint VisitedLinkCommon::null_fingerprint_ = 0;
const VisitedLinkCommon::Hash VisitedLinkCommon::null_hash_ = -1;
@@ -13,6 +16,7 @@ const VisitedLinkCommon::Hash VisitedLinkCommon::null_hash_ = -1;
VisitedLinkCommon::VisitedLinkCommon()
: hash_table_(NULL),
table_length_(0) {
+ memset(salt_, 0, sizeof(salt_));
}
VisitedLinkCommon::~VisitedLinkCommon() {
@@ -29,6 +33,10 @@ bool VisitedLinkCommon::IsVisited(const char* canonical_url,
return IsVisited(ComputeURLFingerprint(canonical_url, url_len));
}
+bool VisitedLinkCommon::IsVisited(const GURL& url) const {
+ return IsVisited(url.spec().data(), url.spec().size());
+}
+
bool VisitedLinkCommon::IsVisited(Fingerprint fingerprint) const {
// Go through the table until we find the item or an empty spot (meaning it
// wasn't found). This loop will terminate as long as the table isn't full,
diff --git a/chrome/common/visitedlink_common.h b/chrome/common/visitedlink_common.h
index 0e79c04..f68015f 100644
--- a/chrome/common/visitedlink_common.h
+++ b/chrome/common/visitedlink_common.h
@@ -4,13 +4,13 @@
#ifndef CHROME_COMMON_VISITEDLINK_COMMON_H__
#define CHROME_COMMON_VISITEDLINK_COMMON_H__
+#pragma once
-#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/logging.h"
-#include "googleurl/src/gurl.h"
+
+class GURL;
// number of bytes in the salt
#define LINK_SALT_LENGTH 8
@@ -67,9 +67,7 @@ class VisitedLinkCommon {
// computed if you call one with the string argument. Returns true if found.
// Does not modify the hastable.
bool IsVisited(const char* canonical_url, size_t url_len) const;
- bool IsVisited(const GURL& url) const {
- return IsVisited(url.spec().data(), url.spec().size());
- }
+ bool IsVisited(const GURL& url) const;
bool IsVisited(Fingerprint fingerprint) const;
#ifdef UNIT_TEST
diff --git a/chrome/common/web_database_observer_impl.h b/chrome/common/web_database_observer_impl.h
index 3f5e80b..84101c8 100644
--- a/chrome/common/web_database_observer_impl.h
+++ b/chrome/common/web_database_observer_impl.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_WEB_DATABASE_OBSERVER_IMPL_H_
#define CHROME_COMMON_WEB_DATABASE_OBSERVER_IMPL_H_
+#pragma once
#include "ipc/ipc_message.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDatabaseObserver.h"
@@ -12,6 +13,7 @@
class WebDatabaseObserverImpl : public WebKit::WebDatabaseObserver {
public:
explicit WebDatabaseObserverImpl(IPC::Message::Sender* sender);
+ virtual ~WebDatabaseObserverImpl() {}
virtual void databaseOpened(const WebKit::WebDatabase& database);
virtual void databaseModified(const WebKit::WebDatabase& database);
virtual void databaseClosed(const WebKit::WebDatabase& database);
diff --git a/chrome/common/web_resource/web_resource_unpacker.h b/chrome/common/web_resource/web_resource_unpacker.h
index f07c06f..c49f2fa 100644
--- a/chrome/common/web_resource/web_resource_unpacker.h
+++ b/chrome/common/web_resource/web_resource_unpacker.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.
@@ -11,10 +11,11 @@
#ifndef CHROME_COMMON_WEB_RESOURCE_WEB_RESOURCE_UNPACKER_H_
#define CHROME_COMMON_WEB_RESOURCE_WEB_RESOURCE_UNPACKER_H_
+#pragma once
#include <string>
-#include "base/file_path.h"
+#include "base/basictypes.h"
#include "base/scoped_ptr.h"
class DictionaryValue;
@@ -53,5 +54,3 @@ class WebResourceUnpacker {
};
#endif // CHROME_COMMON_WEB_RESOURCE_WEB_RESOURCE_UNPACKER_H_
-
-
diff --git a/chrome/common/webblobregistry_impl.cc b/chrome/common/webblobregistry_impl.cc
new file mode 100644
index 0000000..c28f168
--- /dev/null
+++ b/chrome/common/webblobregistry_impl.cc
@@ -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/common/webblobregistry_impl.h"
+
+#include "base/ref_counted.h"
+#include "chrome/common/render_messages.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebBlobData.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
+#include "webkit/blob/blob_data.h"
+
+using WebKit::WebBlobData;
+using WebKit::WebBlobStorageData;
+using WebKit::WebString;
+using WebKit::WebURL;
+
+WebBlobRegistryImpl::WebBlobRegistryImpl(IPC::Message::Sender* sender)
+ : sender_(sender) {
+}
+
+WebBlobRegistryImpl::~WebBlobRegistryImpl() {
+}
+
+void WebBlobRegistryImpl::registerBlobURL(
+ const WebURL& url, WebBlobData& data) {
+ scoped_refptr<webkit_blob::BlobData> blob_data(
+ new webkit_blob::BlobData(data));
+ sender_->Send(new ViewHostMsg_RegisterBlobUrl(url, blob_data));
+}
+
+void WebBlobRegistryImpl::registerBlobURL(
+ const WebURL& url, const WebURL& src_url) {
+ sender_->Send(new ViewHostMsg_RegisterBlobUrlFrom(url, src_url));
+}
+
+void WebBlobRegistryImpl::unregisterBlobURL(const WebURL& url) {
+ sender_->Send(new ViewHostMsg_UnregisterBlobUrl(url));
+}
diff --git a/chrome/common/webblobregistry_impl.h b/chrome/common/webblobregistry_impl.h
new file mode 100644
index 0000000..79bd06c
--- /dev/null
+++ b/chrome/common/webblobregistry_impl.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_WEBBLOBREGISTRY_IMPL_H_
+#define CHROME_COMMON_WEBBLOBREGISTRY_IMPL_H_
+#pragma once
+
+#include "ipc/ipc_message.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebBlobRegistry.h"
+
+namespace WebKit {
+class WebBlobData;
+class WebBlobStorageData;
+class WebString;
+class WebURL;
+}
+
+class WebBlobRegistryImpl : public WebKit::WebBlobRegistry {
+ public:
+ explicit WebBlobRegistryImpl(IPC::Message::Sender* sender);
+ virtual ~WebBlobRegistryImpl();
+
+ // See WebBlobRegistry.h for documentation on these functions.
+ virtual void registerBlobURL(const WebKit::WebURL& url,
+ WebKit::WebBlobData& data);
+ virtual void registerBlobURL(const WebKit::WebURL& url,
+ const WebKit::WebURL& src_url);
+ virtual void unregisterBlobURL(const WebKit::WebURL& url);
+
+ private:
+ IPC::Message::Sender* sender_;
+};
+
+#endif // CHROME_COMMON_WEBBLOBREGISTRY_IMPL_H_
diff --git a/chrome/common/webkit_param_traits.cc b/chrome/common/webkit_param_traits.cc
new file mode 100644
index 0000000..26465dd
--- /dev/null
+++ b/chrome/common/webkit_param_traits.cc
@@ -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.
+
+#include "chrome/common/webkit_param_traits.h"
+
+#include "base/format_macros.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"
+
+namespace IPC {
+
+void ParamTraits<WebKit::WebRect>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.x);
+ WriteParam(m, p.y);
+ WriteParam(m, p.width);
+ WriteParam(m, p.height);
+ }
+
+bool ParamTraits<WebKit::WebRect>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->x) &&
+ ReadParam(m, iter, &p->y) &&
+ ReadParam(m, iter, &p->width) &&
+ ReadParam(m, iter, &p->height);
+}
+
+void ParamTraits<WebKit::WebRect>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.x, l);
+ l->append(", ");
+ LogParam(p.y, l);
+ l->append(", ");
+ LogParam(p.width, l);
+ l->append(", ");
+ LogParam(p.height, l);
+ l->append(")");
+}
+
+void ParamTraits<WebKit::WebScreenInfo>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.depth);
+ WriteParam(m, p.depthPerComponent);
+ WriteParam(m, p.isMonochrome);
+ WriteParam(m, p.rect);
+ WriteParam(m, p.availableRect);
+}
+
+bool ParamTraits<WebKit::WebScreenInfo>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->depth) &&
+ ReadParam(m, iter, &p->depthPerComponent) &&
+ ReadParam(m, iter, &p->isMonochrome) &&
+ ReadParam(m, iter, &p->rect) &&
+ ReadParam(m, iter, &p->availableRect);
+}
+
+void ParamTraits<WebKit::WebScreenInfo>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.depth, l);
+ l->append(", ");
+ LogParam(p.depthPerComponent, l);
+ l->append(", ");
+ LogParam(p.isMonochrome, l);
+ l->append(", ");
+ LogParam(p.rect, l);
+ l->append(", ");
+ LogParam(p.availableRect, l);
+ l->append(")");
+}
+
+void ParamTraits<WebKit::WebFindOptions>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.forward);
+ WriteParam(m, p.matchCase);
+ WriteParam(m, p.findNext);
+}
+
+bool ParamTraits<WebKit::WebFindOptions>::Read(const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->forward) &&
+ ReadParam(m, iter, &p->matchCase) &&
+ ReadParam(m, iter, &p->findNext);
+}
+
+void ParamTraits<WebKit::WebFindOptions>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.forward, l);
+ l->append(", ");
+ LogParam(p.matchCase, l);
+ l->append(", ");
+ LogParam(p.findNext, l);
+ l->append(")");
+}
+
+void ParamTraits<WebKit::WebCache::ResourceTypeStat>::Log(
+ const param_type& p, std::string* l) {
+ l->append(StringPrintf("%" PRIuS " %" PRIuS " %" PRIuS " %" PRIuS,
+ p.count, p.size, p.liveSize, p.decodedSize));
+}
+
+void ParamTraits<WebKit::WebMediaPlayerAction>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, static_cast<int>(p.type));
+ WriteParam(m, p.enable);
+}
+
+bool ParamTraits<WebKit::WebMediaPlayerAction>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ int temp;
+ if (!ReadParam(m, iter, &temp))
+ return false;
+ r->type = static_cast<param_type::Type>(temp);
+ return ReadParam(m, iter, &r->enable);
+}
+
+void ParamTraits<WebKit::WebMediaPlayerAction>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ switch (p.type) {
+ case WebKit::WebMediaPlayerAction::Play:
+ l->append("Play");
+ break;
+ case WebKit::WebMediaPlayerAction::Mute:
+ l->append("Mute");
+ break;
+ case WebKit::WebMediaPlayerAction::Loop:
+ l->append("Loop");
+ break;
+ default:
+ l->append("Unknown");
+ break;
+ }
+ l->append(", ");
+ LogParam(p.enable, l);
+ l->append(")");
+}
+
+void ParamTraits<WebKit::WebCompositionUnderline>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.startOffset);
+ WriteParam(m, p.endOffset);
+ WriteParam(m, p.color);
+ WriteParam(m, p.thick);
+}
+
+bool ParamTraits<WebKit::WebCompositionUnderline>::Read(
+ const Message* m, void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->startOffset) &&
+ ReadParam(m, iter, &p->endOffset) &&
+ ReadParam(m, iter, &p->color) &&
+ ReadParam(m, iter, &p->thick);
+}
+
+void ParamTraits<WebKit::WebCompositionUnderline>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.startOffset, l);
+ l->append(",");
+ LogParam(p.endOffset, l);
+ l->append(":");
+ LogParam(p.color, l);
+ l->append(":");
+ LogParam(p.thick, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/webkit_param_traits.h b/chrome/common/webkit_param_traits.h
index e277e38..6014f25 100644
--- a/chrome/common/webkit_param_traits.h
+++ b/chrome/common/webkit_param_traits.h
@@ -1,7 +1,7 @@
-// Copyright (c) 2010 The Chromium 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.
+
// This file contains ParamTraits templates to support serialization of WebKit
// data types over IPC.
//
@@ -13,153 +13,70 @@
//
// o Many WebKit structures are not thread-safe. WebString, for example,
// contains a reference counted buffer, which does not use thread-safe
-// reference counting. If we allowed serializing WebString, then we may run
-// the risk of introducing subtle thread-safety bugs if people passed a
+// reference counting. If we allowed serializing WebString, then we may
+// run the risk of introducing subtle thread-safety bugs if people passed a
// WebString across threads via PostTask(NewRunnableMethod(...)).
//
-// o The WebKit API has redundant types for strings, and we should avoid using
-// those beyond code that interfaces with the WebKit API.
+// o The WebKit API has redundant types for strings, and we should avoid
+// using those beyond code that interfaces with the WebKit API.
#ifndef CHROME_COMMON_WEBKIT_PARAM_TRAITS_H_
#define CHROME_COMMON_WEBKIT_PARAM_TRAITS_H_
+#pragma once
#include "ipc/ipc_message_utils.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCompositionUnderline.h"
#include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h"
#include "third_party/WebKit/WebKit/chromium/public/WebContextMenuData.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDragOperation.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFileError.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebMediaPlayerAction.h"
#include "third_party/WebKit/WebKit/chromium/public/WebPopupType.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h"
#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h"
#include "third_party/WebKit/WebKit/chromium/public/WebTextInputType.h"
+namespace WebKit {
+struct WebCompositionUnderline;
+struct WebFindOptions;
+struct WebMediaPlayerAction;
+struct WebRect;
+struct WebScreenInfo;
+}
+
namespace IPC {
template <>
struct ParamTraits<WebKit::WebRect> {
typedef WebKit::WebRect param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.x);
- WriteParam(m, p.y);
- WriteParam(m, p.width);
- WriteParam(m, p.height);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->x) &&
- ReadParam(m, iter, &p->y) &&
- ReadParam(m, iter, &p->width) &&
- ReadParam(m, iter, &p->height);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.x, l);
- l->append(L", ");
- LogParam(p.y, l);
- l->append(L", ");
- LogParam(p.width, l);
- l->append(L", ");
- LogParam(p.height, l);
- l->append(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<WebKit::WebScreenInfo> {
typedef WebKit::WebScreenInfo param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.depth);
- WriteParam(m, p.depthPerComponent);
- WriteParam(m, p.isMonochrome);
- WriteParam(m, p.rect);
- WriteParam(m, p.availableRect);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->depth) &&
- ReadParam(m, iter, &p->depthPerComponent) &&
- ReadParam(m, iter, &p->isMonochrome) &&
- ReadParam(m, iter, &p->rect) &&
- ReadParam(m, iter, &p->availableRect);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.depth, l);
- l->append(L", ");
- LogParam(p.depthPerComponent, l);
- l->append(L", ");
- LogParam(p.isMonochrome, l);
- l->append(L", ");
- LogParam(p.rect, l);
- l->append(L", ");
- LogParam(p.availableRect, l);
- l->append(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<WebKit::WebConsoleMessage::Level> {
- typedef WebKit::WebConsoleMessage::Level param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, static_cast<int>(p));
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int value;
- if (!ReadParam(m, iter, &value))
- return false;
- *r = static_cast<param_type>(value);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(static_cast<int>(p), l);
- }
+struct SimilarTypeTraits<WebKit::WebConsoleMessage::Level> {
+ typedef int Type;
};
template <>
-struct ParamTraits<WebKit::WebPopupType> {
- typedef WebKit::WebPopupType param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, static_cast<int>(p));
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int value;
- if (!ReadParam(m, iter, &value))
- return false;
- *r = static_cast<param_type>(value);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(static_cast<int>(p), l);
- }
+struct SimilarTypeTraits<WebKit::WebPopupType> {
+ typedef int Type;
};
template <>
struct ParamTraits<WebKit::WebFindOptions> {
typedef WebKit::WebFindOptions param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.forward);
- WriteParam(m, p.matchCase);
- WriteParam(m, p.findNext);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->forward) &&
- ReadParam(m, iter, &p->matchCase) &&
- ReadParam(m, iter, &p->findNext);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.forward, l);
- l->append(L", ");
- LogParam(p.matchCase, l);
- l->append(L", ");
- LogParam(p.findNext, l);
- l->append(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 <>
@@ -175,41 +92,41 @@ struct ParamTraits<WebKit::WebInputEvent::Type> {
*p = static_cast<WebKit::WebInputEvent::Type>(type);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- const wchar_t* type;
+ static void Log(const param_type& p, std::string* l) {
+ const char* type;
switch (p) {
case WebKit::WebInputEvent::MouseDown:
- type = L"MouseDown";
+ type = "MouseDown";
break;
case WebKit::WebInputEvent::MouseUp:
- type = L"MouseUp";
+ type = "MouseUp";
break;
case WebKit::WebInputEvent::MouseMove:
- type = L"MouseMove";
+ type = "MouseMove";
break;
case WebKit::WebInputEvent::MouseLeave:
- type = L"MouseLeave";
+ type = "MouseLeave";
break;
case WebKit::WebInputEvent::MouseEnter:
- type = L"MouseEnter";
+ type = "MouseEnter";
break;
case WebKit::WebInputEvent::MouseWheel:
- type = L"MouseWheel";
+ type = "MouseWheel";
break;
case WebKit::WebInputEvent::RawKeyDown:
- type = L"RawKeyDown";
+ type = "RawKeyDown";
break;
case WebKit::WebInputEvent::KeyDown:
- type = L"KeyDown";
+ type = "KeyDown";
break;
case WebKit::WebInputEvent::KeyUp:
- type = L"KeyUp";
+ type = "KeyUp";
break;
default:
- type = L"None";
+ type = "None";
break;
}
- LogParam(std::wstring(type), l);
+ LogParam(std::string(type), l);
}
};
@@ -231,8 +148,8 @@ struct ParamTraits<WebKit::WebCache::UsageStats> {
ReadParam(m, iter, &r->liveSize) &&
ReadParam(m, iter, &r->deadSize);
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<WebCache::UsageStats>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<WebCache::UsageStats>");
}
};
@@ -253,10 +170,7 @@ struct ParamTraits<WebKit::WebCache::ResourceTypeStat> {
ReadParam(m, iter, &r->decodedSize);
return result;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(StringPrintf(L"%d %d %d %d", p.count, p.size, p.liveSize,
- p.decodedSize));
- }
+ static void Log(const param_type& p, std::string* l);
};
template <>
@@ -278,129 +192,46 @@ struct ParamTraits<WebKit::WebCache::ResourceTypeStats> {
ReadParam(m, iter, &r->fonts);
return result;
}
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"<WebCoreStats>");
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<WebCoreStats>");
LogParam(p.images, l);
LogParam(p.cssStyleSheets, l);
LogParam(p.scripts, l);
LogParam(p.xslStyleSheets, l);
LogParam(p.fonts, l);
- l->append(L"</WebCoreStats>");
+ l->append("</WebCoreStats>");
}
};
template <>
-struct ParamTraits<WebKit::WebTextDirection> {
- typedef WebKit::WebTextDirection param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, static_cast<int>(p));
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int value;
- if (!ReadParam(m, iter, &value))
- return false;
- *r = static_cast<param_type>(value);
- return true;
- }
- static void Log(const param_type& p, std::wstring* l) {
- LogParam(static_cast<int>(p), l);
- }
+struct SimilarTypeTraits<WebKit::WebTextDirection> {
+ typedef int Type;
};
template <>
-struct ParamTraits<WebKit::WebDragOperation> {
- typedef WebKit::WebDragOperation param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int temp;
- bool res = m->ReadInt(iter, &temp);
- *r = static_cast<param_type>(temp);
- return res;
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(StringPrintf(L"%d", p));
- }
+struct SimilarTypeTraits<WebKit::WebDragOperation> {
+ typedef int Type;
};
template <>
struct ParamTraits<WebKit::WebMediaPlayerAction> {
typedef WebKit::WebMediaPlayerAction param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, static_cast<int>(p.type));
- WriteParam(m, p.enable);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int temp;
- if (!ReadParam(m, iter, &temp))
- return false;
- r->type = static_cast<param_type::Type>(temp);
- return ReadParam(m, iter, &r->enable);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- switch (p.type) {
- case WebKit::WebMediaPlayerAction::Play:
- l->append(L"Play");
- break;
- case WebKit::WebMediaPlayerAction::Mute:
- l->append(L"Mute");
- break;
- case WebKit::WebMediaPlayerAction::Loop:
- l->append(L"Loop");
- break;
- default:
- l->append(L"Unknown");
- break;
- }
- l->append(L", ");
- LogParam(p.enable, l);
- l->append(L")");
- }
+ 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<WebKit::WebContextMenuData::MediaType> {
- typedef WebKit::WebContextMenuData::MediaType param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* r) {
- int temp;
- bool res = m->ReadInt(iter, &temp);
- *r = static_cast<param_type>(temp);
- return res;
- }
+struct SimilarTypeTraits<WebKit::WebContextMenuData::MediaType> {
+ typedef int Type;
};
template <>
struct ParamTraits<WebKit::WebCompositionUnderline> {
typedef WebKit::WebCompositionUnderline param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.startOffset);
- WriteParam(m, p.endOffset);
- WriteParam(m, p.color);
- WriteParam(m, p.thick);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->startOffset) &&
- ReadParam(m, iter, &p->endOffset) &&
- ReadParam(m, iter, &p->color) &&
- ReadParam(m, iter, &p->thick);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.startOffset, l);
- l->append(L",");
- LogParam(p.endOffset, l);
- l->append(L":");
- LogParam(p.color, l);
- l->append(L":");
- LogParam(p.thick, l);
- l->append(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 <>
@@ -416,27 +247,32 @@ struct ParamTraits<WebKit::WebTextInputType> {
*p = static_cast<param_type>(type);
return true;
}
- static void Log(const param_type& p, std::wstring* l) {
- std::wstring control;
+ static void Log(const param_type& p, std::string* l) {
+ std::string control;
switch (p) {
case WebKit::WebTextInputTypeNone:
- control = L"WebKit::WebTextInputTypeNone";
+ control = "WebKit::WebTextInputTypeNone";
break;
case WebKit::WebTextInputTypeText:
- control = L"WebKit::WebTextInputTypeText";
+ control = "WebKit::WebTextInputTypeText";
break;
case WebKit::WebTextInputTypePassword:
- control = L"WebKit::WebTextInputTypePassword";
+ control = "WebKit::WebTextInputTypePassword";
break;
default:
NOTIMPLEMENTED();
- control = L"UNKNOWN";
+ control = "UNKNOWN";
break;
}
LogParam(control, l);
}
};
+template <>
+struct SimilarTypeTraits<WebKit::WebFileError> {
+ typedef int Type;
+};
+
} // namespace IPC
#endif // CHROME_COMMON_WEBKIT_PARAM_TRAITS_H_
diff --git a/chrome/common/webmessageportchannel_impl.h b/chrome/common/webmessageportchannel_impl.h
index da52b9d..24e7ddc 100644
--- a/chrome/common/webmessageportchannel_impl.h
+++ b/chrome/common/webmessageportchannel_impl.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_
#define CHROME_COMMON_WEBMESSAGEPORTCHANNEL_IMPL_H_
+#pragma once
#include <queue>
#include <vector>
diff --git a/chrome/common/win_safe_util.cc b/chrome/common/win_safe_util.cc
index f215566..dc5cc25 100644
--- a/chrome/common/win_safe_util.cc
+++ b/chrome/common/win_safe_util.cc
@@ -60,33 +60,23 @@ bool SaferOpenItemViaShell(HWND hwnd, const std::wstring& window_title,
return false;
// Now check the windows policy.
- bool do_prompt;
- hr = attachment_services->CheckPolicy();
- if (S_FALSE == hr) {
- // The user prompt is required.
- do_prompt = true;
- } else if (S_OK == hr) {
- // An S_OK means that the file is safe to open without user consent.
- do_prompt = false;
- } else {
- // It is possible that the last call returns an undocumented result
+ if (attachment_services->CheckPolicy() != S_OK) {
+ // It is possible that the above call returns an undocumented result
// equal to 0x800c000e which seems to indicate that the URL failed the
// the security check. If you proceed with the Prompt() call the
// Shell might show a dialog that says:
// "windows found that this file is potentially harmful. To help protect
// your computer, Windows has blocked access to this file."
// Upon dismissal of the dialog windows will delete the file (!!).
- // So, we can 'return' here but maybe is best to let it happen to fail on
- // the safe side.
- }
- if (do_prompt) {
+ // So, we can 'return' in that case but maybe is best to let it happen to
+ // fail on the safe side.
+
ATTACHMENT_ACTION action;
// We cannot control what the prompt says or does directly but it
- // is a pretty decent dialog; for example, if an excutable is signed it can
+ // is a pretty decent dialog; for example, if an executable is signed it can
// decode and show the publisher and the certificate.
hr = attachment_services->Prompt(hwnd, ATTACHMENT_PROMPT_EXEC, &action);
- if (FAILED(hr) || (ATTACHMENT_ACTION_CANCEL == action))
- {
+ if (FAILED(hr) || (ATTACHMENT_ACTION_CANCEL == action)) {
// The user has declined opening the item.
return false;
}
diff --git a/chrome/common/win_safe_util.h b/chrome/common/win_safe_util.h
index d9c7097..dee073d 100644
--- a/chrome/common/win_safe_util.h
+++ b/chrome/common/win_safe_util.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_WIN_SAFE_UTIL_H__
#define CHROME_COMMON_WIN_SAFE_UTIL_H__
+#pragma once
#include <string>
#include <windows.h>
diff --git a/chrome/common/window_container_type.h b/chrome/common/window_container_type.h
index 303d1cc..5db1d0e 100644
--- a/chrome/common/window_container_type.h
+++ b/chrome/common/window_container_type.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_WINDOW_CONTAINER_TYPE_H_
#define CHROME_COMMON_WINDOW_CONTAINER_TYPE_H_
+#pragma once
namespace WebKit {
diff --git a/chrome/common/worker_messages.cc b/chrome/common/worker_messages.cc
new file mode 100644
index 0000000..192e4fd
--- /dev/null
+++ b/chrome/common/worker_messages.cc
@@ -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.
+
+#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"
+
+WorkerHostMsg_PostConsoleMessageToWorkerObject_Params::
+WorkerHostMsg_PostConsoleMessageToWorkerObject_Params()
+ : source_identifier(-1),
+ message_type(-1),
+ message_level(-1),
+ line_number(-1) {
+}
+
+WorkerHostMsg_PostConsoleMessageToWorkerObject_Params::
+~WorkerHostMsg_PostConsoleMessageToWorkerObject_Params() {
+}
+
+WorkerProcessMsg_CreateWorker_Params::WorkerProcessMsg_CreateWorker_Params()
+ : is_shared(false),
+ route_id(-1),
+ creator_process_id(-1),
+ creator_appcache_host_id(-1),
+ shared_worker_appcache_id(-1) {
+}
+
+WorkerProcessMsg_CreateWorker_Params::~WorkerProcessMsg_CreateWorker_Params() {
+}
+
+
+namespace IPC {
+
+void ParamTraits<WorkerHostMsg_PostConsoleMessageToWorkerObject_Params>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.source_identifier);
+ WriteParam(m, p.message_type);
+ WriteParam(m, p.message_level);
+ WriteParam(m, p.message);
+ WriteParam(m, p.line_number);
+ WriteParam(m, p.source_url);
+}
+
+bool ParamTraits<WorkerHostMsg_PostConsoleMessageToWorkerObject_Params>::Read(
+ const Message* m, void** iter, param_type* p) {
+ return
+ ReadParam(m, iter, &p->source_identifier) &&
+ ReadParam(m, iter, &p->message_type) &&
+ ReadParam(m, iter, &p->message_level) &&
+ ReadParam(m, iter, &p->message) &&
+ ReadParam(m, iter, &p->line_number) &&
+ ReadParam(m, iter, &p->source_url);
+}
+
+void ParamTraits<WorkerHostMsg_PostConsoleMessageToWorkerObject_Params>::Log(
+ const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.source_identifier, l);
+ l->append(", ");
+ LogParam(p.message_type, l);
+ l->append(", ");
+ LogParam(p.message_level, l);
+ l->append(", ");
+ LogParam(p.message, l);
+ l->append(", ");
+ LogParam(p.line_number, l);
+ l->append(", ");
+ LogParam(p.source_url, l);
+ l->append(")");
+}
+
+void ParamTraits<WorkerProcessMsg_CreateWorker_Params>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.url);
+ WriteParam(m, p.is_shared);
+ WriteParam(m, p.name);
+ WriteParam(m, p.route_id);
+ WriteParam(m, p.creator_process_id);
+ WriteParam(m, p.creator_appcache_host_id);
+ WriteParam(m, p.shared_worker_appcache_id);
+}
+
+bool ParamTraits<WorkerProcessMsg_CreateWorker_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->is_shared) &&
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->route_id) &&
+ ReadParam(m, iter, &p->creator_process_id) &&
+ ReadParam(m, iter, &p->creator_appcache_host_id) &&
+ ReadParam(m, iter, &p->shared_worker_appcache_id);
+}
+
+void ParamTraits<WorkerProcessMsg_CreateWorker_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.is_shared, l);
+ l->append(", ");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.route_id, l);
+ l->append(", ");
+ LogParam(p.creator_process_id, l);
+ l->append(", ");
+ LogParam(p.creator_appcache_host_id, l);
+ l->append(", ");
+ LogParam(p.shared_worker_appcache_id, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/worker_messages.h b/chrome/common/worker_messages.h
index 1228ba3..0e76c4f 100644
--- a/chrome/common/worker_messages.h
+++ b/chrome/common/worker_messages.h
@@ -7,12 +7,12 @@
#ifndef CHROME_COMMON_WORKER_MESSAGES_H_
#define CHROME_COMMON_WORKER_MESSAGES_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "chrome/common/common_param_traits.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message_utils.h"
@@ -23,6 +23,9 @@ typedef std::pair<string16, std::vector<int> > QueuedMessage;
// IPC message. The data members directly correspond to parameters of
// WebWorkerClient::postConsoleMessageToWorkerObject()
struct WorkerHostMsg_PostConsoleMessageToWorkerObject_Params {
+ WorkerHostMsg_PostConsoleMessageToWorkerObject_Params();
+ ~WorkerHostMsg_PostConsoleMessageToWorkerObject_Params();
+
int source_identifier;
int message_type;
int message_level;
@@ -33,6 +36,9 @@ struct WorkerHostMsg_PostConsoleMessageToWorkerObject_Params {
// Parameter structure for WorkerProcessMsg_CreateWorker.
struct WorkerProcessMsg_CreateWorker_Params {
+ WorkerProcessMsg_CreateWorker_Params();
+ ~WorkerProcessMsg_CreateWorker_Params();
+
GURL url;
bool is_shared;
string16 name;
@@ -49,80 +55,18 @@ namespace IPC {
template <>
struct ParamTraits<WorkerHostMsg_PostConsoleMessageToWorkerObject_Params> {
typedef WorkerHostMsg_PostConsoleMessageToWorkerObject_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.source_identifier);
- WriteParam(m, p.message_type);
- WriteParam(m, p.message_level);
- WriteParam(m, p.message);
- WriteParam(m, p.line_number);
- WriteParam(m, p.source_url);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->source_identifier) &&
- ReadParam(m, iter, &p->message_type) &&
- ReadParam(m, iter, &p->message_level) &&
- ReadParam(m, iter, &p->message) &&
- ReadParam(m, iter, &p->line_number) &&
- ReadParam(m, iter, &p->source_url);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.source_identifier, l);
- l->append(L", ");
- LogParam(p.message_type, l);
- l->append(L", ");
- LogParam(p.message_level, l);
- l->append(L", ");
- LogParam(p.message, l);
- l->append(L", ");
- LogParam(p.line_number, l);
- l->append(L", ");
- LogParam(p.source_url, l);
- l->append(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);
};
// Traits for WorkerProcessMsg_CreateWorker_Params.
template <>
struct ParamTraits<WorkerProcessMsg_CreateWorker_Params> {
typedef WorkerProcessMsg_CreateWorker_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.url);
- WriteParam(m, p.is_shared);
- WriteParam(m, p.name);
- WriteParam(m, p.route_id);
- WriteParam(m, p.creator_process_id);
- WriteParam(m, p.creator_appcache_host_id);
- WriteParam(m, p.shared_worker_appcache_id);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->is_shared) &&
- ReadParam(m, iter, &p->name) &&
- ReadParam(m, iter, &p->route_id) &&
- ReadParam(m, iter, &p->creator_process_id) &&
- ReadParam(m, iter, &p->creator_appcache_host_id) &&
- ReadParam(m, iter, &p->shared_worker_appcache_id);
- }
- static void Log(const param_type& p, std::wstring* l) {
- l->append(L"(");
- LogParam(p.url, l);
- l->append(L", ");
- LogParam(p.is_shared, l);
- l->append(L", ");
- LogParam(p.name, l);
- l->append(L", ");
- LogParam(p.route_id, l);
- l->append(L", ");
- LogParam(p.creator_process_id, l);
- l->append(L", ");
- LogParam(p.creator_appcache_host_id, l);
- l->append(L", ");
- LogParam(p.shared_worker_appcache_id, l);
- l->append(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);
};
} // namespace IPC
diff --git a/chrome/common/worker_thread_ticker.h b/chrome/common/worker_thread_ticker.h
index bb39c3b..d392749 100644
--- a/chrome/common/worker_thread_ticker.h
+++ b/chrome/common/worker_thread_ticker.h
@@ -4,6 +4,7 @@
#ifndef CHROME_COMMON_WORKER_THREAD_TICKER_H_
#define CHROME_COMMON_WORKER_THREAD_TICKER_H_
+#pragma once
#include <vector>
diff --git a/chrome/common/zip.cc b/chrome/common/zip.cc
index f1d89b5..01de36f 100644
--- a/chrome/common/zip.cc
+++ b/chrome/common/zip.cc
@@ -6,6 +6,7 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "net/base/file_stream.h"
diff --git a/chrome/common/zip.h b/chrome/common/zip.h
index 2c3d456..069d150 100644
--- a/chrome/common/zip.h
+++ b/chrome/common/zip.h
@@ -1,13 +1,12 @@
-// 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.
#ifndef CHROME_COMMON_ZIP_H_
#define CHROME_COMMON_ZIP_H_
+#pragma once
-#include <vector>
-
-#include "base/file_path.h"
+class FilePath;
// Zip the contents of src_dir into dest_file. src_path must be a directory.
// An entry will *not* be created in the zip for the root folder -- children
diff --git a/googleurl/src/gurl.h b/googleurl/src/gurl.h
index 29fea81..ba97191 100644
--- a/googleurl/src/gurl.h
+++ b/googleurl/src/gurl.h
@@ -30,7 +30,7 @@
#ifndef GOOGLEURL_SRC_GURL_H__
#define GOOGLEURL_SRC_GURL_H__
-#include <iostream>
+#include <iosfwd>
#include <string>
#include "base/string16.h"
diff --git a/googleurl/src/url_canon_etc.cc b/googleurl/src/url_canon_etc.cc
index aea181a..318c906 100644
--- a/googleurl/src/url_canon_etc.cc
+++ b/googleurl/src/url_canon_etc.cc
@@ -213,9 +213,6 @@ bool DoUserInfo(const CHAR* username_spec,
inline void WritePortInt(char* output, int output_len, int port) {
_itoa_s(port, output, output_len, 10);
}
-inline void WritePortInt(char16* output, int output_len, int port) {
- _itow_s(port, output, output_len, 10);
-}
// This function will prepend the colon if there will be a port.
template<typename CHAR, typename UCHAR>
@@ -290,12 +287,11 @@ void DoCanonicalizeRef(const CHAR* spec,
} else {
// Non-ASCII characters are appended unescaped, but only when they are
// valid. Invalid Unicode characters are replaced with the "invalid
- // character" as IE seems to.
+ // character" as IE seems to (ReadUTFChar puts the unicode replacement
+ // character in the output on failure for us).
unsigned code_point;
- if (!ReadUTFChar(spec, &i, end, &code_point))
- AppendUTF8Value(kUnicodeReplacementCharacter, output);
- else
- AppendUTF8Value(code_point, output);
+ ReadUTFChar(spec, &i, end, &code_point);
+ AppendUTF8Value(code_point, output);
}
}
diff --git a/googleurl/src/url_canon_internal.h b/googleurl/src/url_canon_internal.h
index 4b1e45a..6305647 100644
--- a/googleurl/src/url_canon_internal.h
+++ b/googleurl/src/url_canon_internal.h
@@ -37,6 +37,7 @@
#include <stdlib.h>
+#include "base/logging.h"
#include "googleurl/src/url_canon.h"
namespace url_canon {
@@ -173,6 +174,9 @@ bool ReadUTFChar(const char* str, int* begin, int length,
// Generic To-UTF-8 converter. This will call the given append method for each
// character that should be appended, with the given output method. Wrappers
// are provided below for escaped and non-escaped versions of this.
+//
+// The char_value must have already been checked that it's a valid Unicode
+// character.
template<class Output, void Appender(unsigned char, Output*)>
inline void DoAppendUTF8(unsigned char_value, Output* output) {
if (char_value <= 0x7f) {
@@ -191,7 +195,7 @@ inline void DoAppendUTF8(unsigned char_value, Output* output) {
output);
Appender(static_cast<unsigned char>(0x80 | (char_value & 0x3f)),
output);
- } else if (char_value <= 0x1fffff) {
+ } else if (char_value <= 0x10FFFF) { // Max unicode code point.
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Appender(static_cast<unsigned char>(0xf0 | (char_value >> 18)),
output);
@@ -201,20 +205,9 @@ inline void DoAppendUTF8(unsigned char_value, Output* output) {
output);
Appender(static_cast<unsigned char>(0x80 | (char_value & 0x3f)),
output);
- } else if (char_value <= 0x10FFFF) { // Max unicode code point.
- // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- Appender(static_cast<unsigned char>(0xf8 | (char_value >> 24)),
- output);
- Appender(static_cast<unsigned char>(0x80 | ((char_value >> 18) & 0x3f)),
- output);
- Appender(static_cast<unsigned char>(0x80 | ((char_value >> 12) & 0x3f)),
- output);
- Appender(static_cast<unsigned char>(0x80 | ((char_value >> 6) & 0x3f)),
- output);
- Appender(static_cast<unsigned char>(0x80 | (char_value & 0x3f)),
- output);
} else {
- // Invalid UTF-8 character (>20 bits)
+ // Invalid UTF-8 character (>20 bits).
+ NOTREACHED();
}
}
diff --git a/googleurl/src/url_canon_unittest.cc b/googleurl/src/url_canon_unittest.cc
index a3e43e2..1a3cd53 100644
--- a/googleurl/src/url_canon_unittest.cc
+++ b/googleurl/src/url_canon_unittest.cc
@@ -144,6 +144,44 @@ void SetupReplComp(
} // namespace
+TEST(URLCanonTest, DoAppendUTF8) {
+ struct UTF8Case {
+ unsigned input;
+ const char* output;
+ } utf_cases[] = {
+ // Valid code points.
+ {0x24, "\x24"},
+ {0xA2, "\xC2\xA2"},
+ {0x20AC, "\xE2\x82\xAC"},
+ {0x24B62, "\xF0\xA4\xAD\xA2"},
+ {0x10FFFF, "\xF4\x8F\xBF\xBF"},
+ };
+ std::string out_str;
+ for (size_t i = 0; i < ARRAYSIZE(utf_cases); i++) {
+ out_str.clear();
+ url_canon::StdStringCanonOutput output(&out_str);
+ url_canon::AppendUTF8Value(utf_cases[i].input, &output);
+ output.Complete();
+ EXPECT_EQ(utf_cases[i].output, out_str);
+ }
+}
+
+// TODO(mattm): Can't run this in debug mode for now, since the DCHECK will
+// cause the Chromium stacktrace dialog to appear and hang the test.
+// See http://crbug.com/49580.
+#ifdef NDEBUG
+TEST(URLCanonTest, DoAppendUTF8Invalid) {
+ std::string out_str;
+ url_canon::StdStringCanonOutput output(&out_str);
+ // Invalid code point (too large).
+ ASSERT_DEBUG_DEATH({
+ url_canon::AppendUTF8Value(0x110000, &output);
+ output.Complete();
+ EXPECT_EQ("", out_str);
+ }, "");
+}
+#endif
+
TEST(URLCanonTest, UTF) {
// Low-level test that we handle reading, canonicalization, and writing
// UTF-8/UTF-16 strings properly.
diff --git a/googleurl/src/url_parse.cc b/googleurl/src/url_parse.cc
index a08c4da..fa31210 100644
--- a/googleurl/src/url_parse.cc
+++ b/googleurl/src/url_parse.cc
@@ -324,7 +324,7 @@ void DoParseStandardURL(const CHAR* spec, int spec_len, Parsed* parsed) {
if (DoExtractScheme(spec, spec_len, &parsed->scheme)) {
after_scheme = parsed->scheme.end() + 1; // Skip past the colon.
} else {
- // Say there's no scheme when there is a colon. We could also say that
+ // Say there's no scheme when there is no colon. We could also say that
// everything is the scheme. Both would produce an invalid URL, but this way
// seems less wrong in more cases.
parsed->scheme.reset();
@@ -645,7 +645,7 @@ bool ExtractScheme(const char16* url, int url_len, Component* scheme) {
// This handles everything that may be an authority terminator, including
// backslash. For special backslash handling see DoParseAfterScheme.
bool IsAuthorityTerminator(char16 ch) {
- return IsURLSlash(ch) || ch == '?' || ch == '#' || ch == ';';
+ return IsURLSlash(ch) || ch == '?' || ch == '#';
}
void ExtractFileName(const char* url,
diff --git a/googleurl/src/url_test_utils.h b/googleurl/src/url_test_utils.h
index 5294202..6278e3f 100644
--- a/googleurl/src/url_test_utils.h
+++ b/googleurl/src/url_test_utils.h
@@ -75,11 +75,4 @@ inline std::string ConvertUTF16ToUTF8(const string16& src) {
} // namespace url_test_utils
-// This operator allows EXPECT_EQ(astring16, anotherstring16); to work.
-inline std::ostream& operator<<(std::ostream& os,
- const string16& str) {
- // Convert to UTF-8 and print the string
- return os << url_test_utils::ConvertUTF16ToUTF8(str);
-}
-
#endif // GOOGLEURL_SRC_URL_TEST_UTILS_H__
diff --git a/net/base/address_family.h b/net/base/address_family.h
index fee0584..8ea5256 100644
--- a/net/base/address_family.h
+++ b/net/base/address_family.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_ADDRESS_FAMILY_H_
#define NET_BASE_ADDRESS_FAMILY_H_
+#pragma once
namespace net {
@@ -15,10 +16,15 @@ enum AddressFamily {
ADDRESS_FAMILY_IPV6, // AF_INET6
};
-// HostResolverFlags is a bitflag enum wrapper around the addrinfo.ai_flags
-// supported by host resolver procedures.
+// HostResolverFlags is a bitflag enum used by host resolver procedures to
+// determine the value of addrinfo.ai_flags and work around getaddrinfo
+// peculiarities.
enum {
- HOST_RESOLVER_CANONNAME = 1 << 0, // 0x1, AI_CANONNAME
+ HOST_RESOLVER_CANONNAME = 1 << 0, // AI_CANONNAME
+ // Hint to the resolver proc that only loopback addresses are configured.
+ HOST_RESOLVER_LOOPBACK_ONLY = 1 << 1,
+ // Indicate the address family was set because no IPv6 support was detected.
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6 = 1 << 2,
};
typedef int HostResolverFlags;
diff --git a/net/base/address_list.cc b/net/base/address_list.cc
index 0fbf38a..cef461d 100644
--- a/net/base/address_list.cc
+++ b/net/base/address_list.cc
@@ -86,6 +86,81 @@ void SetPortRecursive(struct addrinfo* info, int port) {
} // namespace
+struct AddressList::Data : public base::RefCountedThreadSafe<Data> {
+ Data(struct addrinfo* ai, bool is_system_created);
+ struct addrinfo* head;
+
+ // Indicates which free function to use for |head|.
+ bool is_system_created;
+
+ private:
+ friend class base::RefCountedThreadSafe<Data>;
+
+ ~Data();
+};
+
+AddressList::AddressList() {
+}
+
+AddressList::AddressList(const AddressList& addresslist)
+ : data_(addresslist.data_) {
+}
+
+AddressList::~AddressList() {
+}
+
+AddressList& AddressList::operator=(const AddressList& addresslist) {
+ data_ = addresslist.data_;
+ return *this;
+}
+
+AddressList::AddressList(const IPAddressNumber& address, int port,
+ bool canonicalize_name) {
+ struct addrinfo* ai = new addrinfo;
+ memset(ai, 0, sizeof(addrinfo));
+ ai->ai_socktype = SOCK_STREAM;
+
+ switch (address.size()) {
+ case 4: {
+ ai->ai_family = AF_INET;
+ const size_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ ai->ai_addrlen = sockaddr_in_size;
+
+ struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(
+ new char[sockaddr_in_size]);
+ memset(addr, 0, sockaddr_in_size);
+ addr->sin_family = AF_INET;
+ memcpy(&addr->sin_addr, &address[0], 4);
+ ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr);
+ break;
+ }
+ case 16: {
+ ai->ai_family = AF_INET6;
+ const size_t sockaddr_in6_size = sizeof(struct sockaddr_in6);
+ ai->ai_addrlen = sockaddr_in6_size;
+
+ struct sockaddr_in6* addr6 = reinterpret_cast<struct sockaddr_in6*>(
+ new char[sockaddr_in6_size]);
+ memset(addr6, 0, sockaddr_in6_size);
+ addr6->sin6_family = AF_INET6;
+ memcpy(&addr6->sin6_addr, &address[0], 16);
+ ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr6);
+ break;
+ }
+ default: {
+ NOTREACHED() << "Bad IP address";
+ break;
+ }
+ }
+
+ if (canonicalize_name) {
+ std::string name = NetAddressToString(ai);
+ ai->ai_canonname = do_strdup(name.c_str());
+ }
+ data_ = new Data(ai, false /*is_system_created*/);
+ SetPort(port);
+}
+
void AddressList::Adopt(struct addrinfo* head) {
data_ = new Data(head, true /*is_system_created*/);
}
@@ -144,49 +219,11 @@ void AddressList::Reset() {
data_ = NULL;
}
-// static
-AddressList AddressList::CreateIPv4Address(unsigned char data[4],
- const std::string& canonical_name) {
- struct addrinfo* ai = new addrinfo;
- memset(ai, 0, sizeof(addrinfo));
- ai->ai_family = AF_INET;
- ai->ai_socktype = SOCK_STREAM;
- const size_t sockaddr_in_size = sizeof(struct sockaddr_in);
- ai->ai_addrlen = sockaddr_in_size;
- if (!canonical_name.empty())
- ai->ai_canonname = do_strdup(canonical_name.c_str());
-
- struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(
- new char[sockaddr_in_size]);
- memset(addr, 0, sockaddr_in_size);
- addr->sin_family = AF_INET;
- memcpy(&addr->sin_addr, data, 4);
- ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr);
-
- return AddressList(new Data(ai, false /*is_system_created*/));
+const struct addrinfo* AddressList::head() const {
+ return data_->head;
}
-// static
-AddressList AddressList::CreateIPv6Address(unsigned char data[16],
- const std::string& canonical_name) {
- struct addrinfo* ai = new addrinfo;
- memset(ai, 0, sizeof(addrinfo));
- ai->ai_family = AF_INET6;
- ai->ai_socktype = SOCK_STREAM;
- const size_t sockaddr_in6_size = sizeof(struct sockaddr_in6);
- ai->ai_addrlen = sockaddr_in6_size;
- if (!canonical_name.empty())
- ai->ai_canonname = do_strdup(canonical_name.c_str());
-
- struct sockaddr_in6* addr6 = reinterpret_cast<struct sockaddr_in6*>(
- new char[sockaddr_in6_size]);
- memset(addr6, 0, sockaddr_in6_size);
- addr6->sin6_family = AF_INET6;
- memcpy(&addr6->sin6_addr, data, 16);
- ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr6);
-
- return AddressList(new Data(ai, false /*is_system_created*/));
-}
+AddressList::AddressList(Data* data) : data_(data) {}
AddressList::Data::Data(struct addrinfo* ai, bool is_system_created)
: head(ai), is_system_created(is_system_created) {
diff --git a/net/base/address_list.h b/net/base/address_list.h
index ce17645..9406a8c 100644
--- a/net/base/address_list.h
+++ b/net/base/address_list.h
@@ -4,10 +4,12 @@
#ifndef NET_BASE_ADDRESS_LIST_H_
#define NET_BASE_ADDRESS_LIST_H_
+#pragma once
#include <string>
#include "base/ref_counted.h"
+#include "net/base/net_util.h"
struct addrinfo;
@@ -18,11 +20,21 @@ namespace net {
class AddressList {
public:
// Constructs an empty address list.
- AddressList() {}
+ AddressList();
- // Adopt the given addrinfo list in place of the existing one if any. This
- // hands over responsibility for freeing the addrinfo list to the AddressList
- // object.
+ // Constructs an address list for a single IP literal. If
+ // |canonicalize_name| is true, fill the ai_canonname field with the
+ // canonicalized IP address.
+ AddressList(const IPAddressNumber& address, int port, bool canonicalize_name);
+
+ AddressList(const AddressList& addresslist);
+ ~AddressList();
+ AddressList& operator=(const AddressList& addresslist);
+
+ // Adopt the given addrinfo list (assumed to have been created by
+ // the system, e.g. returned by getaddrinfo()) in place of the
+ // existing one if any. This hands over responsibility for freeing
+ // the addrinfo list to the AddressList object.
void Adopt(struct addrinfo* head);
// Copies the given addrinfo rather than adopting it. If |recursive| is true,
@@ -59,38 +71,13 @@ class AddressList {
// empty state as when first constructed.
void Reset();
- // Used by unit-tests to manually create an IPv4 AddressList. |data| should
- // be an IPv4 address in network order (big endian).
- // If |canonical_name| is non-empty, it will be duplicated in the
- // ai_canonname field of the addrinfo struct.
- static AddressList CreateIPv4Address(unsigned char data[4],
- const std::string& canonical_name);
-
- // Used by unit-tests to manually create an IPv6 AddressList. |data| should
- // be an IPv6 address in network order (big endian).
- // If |canonical_name| is non-empty, it will be duplicated in the
- // ai_canonname field of the addrinfo struct.
- static AddressList CreateIPv6Address(unsigned char data[16],
- const std::string& canonical_name);
-
// Get access to the head of the addrinfo list.
- const struct addrinfo* head() const { return data_->head; }
+ const struct addrinfo* head() const;
private:
- struct Data : public base::RefCountedThreadSafe<Data> {
- Data(struct addrinfo* ai, bool is_system_created);
- struct addrinfo* head;
-
- // Indicates which free function to use for |head|.
- bool is_system_created;
-
- private:
- friend class base::RefCountedThreadSafe<Data>;
-
- ~Data();
- };
+ struct Data;
- explicit AddressList(Data* data) : data_(data) {}
+ explicit AddressList(Data* data);
scoped_refptr<Data> data_;
};
diff --git a/net/base/address_list_net_log_param.cc b/net/base/address_list_net_log_param.cc
index 05b1a0d..72332ef 100644
--- a/net/base/address_list_net_log_param.cc
+++ b/net/base/address_list_net_log_param.cc
@@ -23,7 +23,7 @@ Value* AddressListNetLogParam::ToValue() const {
list->Append(Value::CreateStringValue(NetAddressToStringWithPort(head)));
}
- dict->Set(L"address_list", list);
+ dict->Set("address_list", list);
return dict;
}
diff --git a/net/base/address_list_net_log_param.h b/net/base/address_list_net_log_param.h
index 2a56961..141c2d0 100644
--- a/net/base/address_list_net_log_param.h
+++ b/net/base/address_list_net_log_param.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_ADDRESS_LIST_NET_LOG_PARAM_H_
#define NET_BASE_ADDRESS_LIST_NET_LOG_PARAM_H_
+#pragma once
#include "net/base/address_list.h"
#include "net/base/net_log.h"
diff --git a/net/base/address_list_unittest.cc b/net/base/address_list_unittest.cc
index 6e38c7d..65d0f5c 100644
--- a/net/base/address_list_unittest.cc
+++ b/net/base/address_list_unittest.cc
@@ -16,9 +16,8 @@
namespace {
// Use getaddrinfo() to allocate an addrinfo structure.
-void CreateAddressList(const std::string& hostname,
- int port,
- net::AddressList* addrlist) {
+int CreateAddressList(const std::string& hostname, int port,
+ net::AddressList* addrlist) {
#if defined(OS_WIN)
net::EnsureWinsockInit();
#endif
@@ -26,20 +25,21 @@ void CreateAddressList(const std::string& hostname,
net::ADDRESS_FAMILY_UNSPECIFIED,
0,
addrlist, NULL);
- EXPECT_EQ(0, rv);
- addrlist->SetPort(port);
+ if (rv == 0)
+ addrlist->SetPort(port);
+ return rv;
}
void CreateLongAddressList(net::AddressList* addrlist, int port) {
- CreateAddressList("192.168.1.1", port, addrlist);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", port, addrlist));
net::AddressList second_list;
- CreateAddressList("192.168.1.2", port, &second_list);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.2", port, &second_list));
addrlist->Append(second_list.head());
}
TEST(AddressListTest, GetPort) {
net::AddressList addrlist;
- CreateAddressList("192.168.1.1", 81, &addrlist);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", 81, &addrlist));
EXPECT_EQ(81, addrlist.GetPort());
addrlist.SetPort(83);
@@ -48,7 +48,7 @@ TEST(AddressListTest, GetPort) {
TEST(AddressListTest, Assignment) {
net::AddressList addrlist1;
- CreateAddressList("192.168.1.1", 85, &addrlist1);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", 85, &addrlist1));
EXPECT_EQ(85, addrlist1.GetPort());
// Should reference the same data as addrlist1 -- so when we change addrlist1
@@ -107,10 +107,10 @@ TEST(AddressListTest, CopyNonRecursive) {
TEST(AddressListTest, Append) {
net::AddressList addrlist1;
- CreateAddressList("192.168.1.1", 11, &addrlist1);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", 11, &addrlist1));
EXPECT_EQ(11, addrlist1.GetPort());
net::AddressList addrlist2;
- CreateAddressList("192.168.1.2", 12, &addrlist2);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.2", 12, &addrlist2));
EXPECT_EQ(12, addrlist2.GetPort());
ASSERT_TRUE(addrlist1.head()->ai_next == NULL);
@@ -172,4 +172,45 @@ TEST(AddressListTest, Canonical) {
EXPECT_EQ("blah", canon_name3);
}
+TEST(AddressListTest, IPLiteralConstructor) {
+ struct TestData {
+ std::string ip_address;
+ std::string canonical_ip_address;
+ bool is_ipv6;
+ } tests[] = {
+ { "127.0.00.1", "127.0.0.1", false },
+ { "192.168.1.1", "192.168.1.1", false },
+ { "::1", "::1", true },
+ { "2001:db8:0::42", "2001:db8::42", true },
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); i++) {
+ net::AddressList expected_list;
+ int rv = CreateAddressList(tests[i].canonical_ip_address, 80,
+ &expected_list);
+ if (tests[i].is_ipv6 && rv != 0) {
+ LOG(WARNING) << "Unable to resolve ip literal '" << tests[i].ip_address
+ << "' test skipped.";
+ continue;
+ }
+ ASSERT_EQ(0, rv);
+ const struct addrinfo* good_ai = expected_list.head();
+
+ net::IPAddressNumber ip_number;
+ net::ParseIPLiteralToNumber(tests[i].ip_address, &ip_number);
+ net::AddressList test_list(ip_number, 80, true);
+ const struct addrinfo* test_ai = test_list.head();
+
+ EXPECT_EQ(good_ai->ai_family, test_ai->ai_family);
+ EXPECT_EQ(good_ai->ai_socktype, test_ai->ai_socktype);
+ EXPECT_EQ(good_ai->ai_addrlen, test_ai->ai_addrlen);
+ size_t sockaddr_size =
+ good_ai->ai_socktype == AF_INET ? sizeof(struct sockaddr_in) :
+ good_ai->ai_socktype == AF_INET6 ? sizeof(struct sockaddr_in6) : 0;
+ EXPECT_EQ(memcmp(good_ai->ai_addr, test_ai->ai_addr, sockaddr_size), 0);
+ EXPECT_EQ(good_ai->ai_next, test_ai->ai_next);
+ EXPECT_EQ(strcmp(tests[i].canonical_ip_address.c_str(),
+ test_ai->ai_canonname), 0);
+ }
+}
+
} // namespace
diff --git a/net/base/auth.cc b/net/base/auth.cc
new file mode 100644
index 0000000..08b869c
--- /dev/null
+++ b/net/base/auth.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 "net/base/auth.h"
+
+namespace net {
+
+AuthChallengeInfo::AuthChallengeInfo() : is_proxy(false) {
+}
+
+bool AuthChallengeInfo::operator==(const AuthChallengeInfo& that) const {
+ return (this->is_proxy == that.is_proxy &&
+ this->host_and_port == that.host_and_port &&
+ this->scheme == that.scheme &&
+ this->realm == that.realm);
+}
+
+AuthChallengeInfo::~AuthChallengeInfo() {
+}
+
+AuthData::AuthData() : state(AUTH_STATE_NEED_AUTH) {
+}
+
+AuthData::~AuthData() {
+}
+
+} // namespace net
diff --git a/net/base/auth.h b/net/base/auth.h
index 1704e5b..908b769 100644
--- a/net/base/auth.h
+++ b/net/base/auth.h
@@ -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.
#ifndef NET_BASE_AUTH_H__
#define NET_BASE_AUTH_H__
+#pragma once
#include <string>
#include "base/ref_counted.h"
+#include "base/string16.h"
namespace net {
@@ -16,12 +18,9 @@ namespace net {
class AuthChallengeInfo :
public base::RefCountedThreadSafe<AuthChallengeInfo> {
public:
- bool operator==(const AuthChallengeInfo& that) const {
- return (this->is_proxy == that.is_proxy &&
- this->host_and_port == that.host_and_port &&
- this->scheme == that.scheme &&
- this->realm == that.realm);
- }
+ AuthChallengeInfo();
+
+ bool operator==(const AuthChallengeInfo& that) const;
bool operator!=(const AuthChallengeInfo& that) const {
return !(*this == that);
@@ -35,7 +34,7 @@ class AuthChallengeInfo :
private:
friend class base::RefCountedThreadSafe<AuthChallengeInfo>;
- ~AuthChallengeInfo() {}
+ ~AuthChallengeInfo();
};
// Authentication structures
@@ -50,15 +49,15 @@ class AuthData : public base::RefCountedThreadSafe<AuthData> {
public:
AuthState state; // whether we need, have, or gave up on authentication.
std::wstring scheme; // the authentication scheme.
- std::wstring username; // the username supplied to us for auth.
- std::wstring password; // the password supplied to us for auth.
+ string16 username; // the username supplied to us for auth.
+ string16 password; // the password supplied to us for auth.
// We wouldn't instantiate this class if we didn't need authentication.
- AuthData() : state(AUTH_STATE_NEED_AUTH) {}
+ AuthData();
private:
friend class base::RefCountedThreadSafe<AuthData>;
- ~AuthData() {}
+ ~AuthData();
};
} // namespace net
diff --git a/net/base/bandwidth_metrics.h b/net/base/bandwidth_metrics.h
index 2396157..b201f42 100644
--- a/net/base/bandwidth_metrics.h
+++ b/net/base/bandwidth_metrics.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_BANDWIDTH_METRICS_H_
#define NET_BASE_BANDWIDTH_METRICS_H_
+#pragma once
#include <list>
diff --git a/net/base/cache_type.h b/net/base/cache_type.h
index 0823389..280a3d2 100644
--- a/net/base/cache_type.h
+++ b/net/base/cache_type.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_CACHE_TYPE_H_
#define NET_BASE_CACHE_TYPE_H_
+#pragma once
namespace net {
diff --git a/net/base/capturing_net_log.h b/net/base/capturing_net_log.h
index cad2d26..9669445 100644
--- a/net/base/capturing_net_log.h
+++ b/net/base/capturing_net_log.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_CAPTURING_NET_LOG_H_
#define NET_BASE_CAPTURING_NET_LOG_H_
+#pragma once
#include <vector>
@@ -52,7 +53,7 @@ class CapturingNetLog : public NetLog {
EventPhase phase,
EventParameters* extra_parameters);
virtual uint32 NextID();
- virtual bool HasListener() const { return true; }
+ virtual LogLevel GetLogLevel() const { return LOG_ALL; }
// Returns the list of all entries in the log.
const EntryList& entries() const { return entries_; }
diff --git a/net/base/cert_database.cc b/net/base/cert_database.cc
new file mode 100644
index 0000000..961638c
--- /dev/null
+++ b/net/base/cert_database.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 "net/base/cert_database.h"
+
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+CertDatabase::ImportCertFailure::ImportCertFailure(
+ X509Certificate* cert, int err)
+ : certificate(cert), net_error(err) {
+}
+
+} // namespace net
diff --git a/net/base/cert_database.h b/net/base/cert_database.h
index 31e3401..52888fe 100644
--- a/net/base/cert_database.h
+++ b/net/base/cert_database.h
@@ -4,12 +4,37 @@
#ifndef NET_BASE_CERT_DATABASE_H_
#define NET_BASE_CERT_DATABASE_H_
+#pragma once
+
+#include <string>
+#include <vector>
#include "base/basictypes.h"
+#include "base/string16.h"
+#include "base/ref_counted.h"
namespace net {
class X509Certificate;
+typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
+
+// Constants to classify the type of a certificate.
+// This is only used in the context of CertDatabase, but is defined outside to
+// avoid an awkwardly long type name.
+// The type is a combination of intrinsic properties, such as the presense of an
+// email address or Certificate Authority Basic Constraint, and assigned trust
+// values. For example, a cert with no email address, basic constraints, or
+// trust, would be classified as UNKNOWN_CERT. If that cert is then trusted
+// with SetCertTrust(cert, SERVER_CERT, TRUSTED_SSL), it would become a
+// SERVER_CERT.
+enum CertType {
+ UNKNOWN_CERT,
+ CA_CERT,
+ USER_CERT,
+ EMAIL_CERT,
+ SERVER_CERT,
+ NUM_CERT_TYPES
+};
// This class provides functions to manipulate the local
// certificate store.
@@ -20,6 +45,32 @@ class X509Certificate;
class CertDatabase {
public:
+ // Constants that define which usages a certificate is trusted for.
+ // They are used in combination with CertType to specify trust for each type
+ // of certificate.
+ // For a CA_CERT, they specify that the CA is trusted for issuing server and
+ // client certs of each type.
+ // For SERVER_CERT, only TRUSTED_SSL makes sense, and specifies the cert is
+ // trusted as a server.
+ // For EMAIL_CERT, only TRUSTED_EMAIL makes sense, and specifies the cert is
+ // trusted for email.
+ enum {
+ UNTRUSTED = 0,
+ TRUSTED_SSL = 1 << 0,
+ TRUSTED_EMAIL = 1 << 1,
+ TRUSTED_OBJ_SIGN = 1 << 2,
+ };
+
+ // Stores per-certificate error codes for import failures.
+ struct ImportCertFailure {
+ public:
+ ImportCertFailure(X509Certificate* cert, int err);
+
+ scoped_refptr<X509Certificate> certificate;
+ int net_error;
+ };
+ typedef std::vector<ImportCertFailure> ImportCertFailureList;
+
CertDatabase();
// Check whether this is a valid user cert that we have the private key for.
@@ -31,6 +82,50 @@ class CertDatabase {
// the platform cert database, or possibly other network error codes.
int AddUserCert(X509Certificate* cert);
+#if defined(USE_NSS)
+ // Get a list of unique certificates in the certificate database. (One
+ // instance of all certificates.)
+ void ListCerts(CertificateList* certs);
+
+ // Import certificates and private keys from PKCS #12 blob.
+ // Returns OK or a network error code such as ERR_PKCS12_IMPORT_BAD_PASSWORD
+ // or ERR_PKCS12_IMPORT_ERROR.
+ int ImportFromPKCS12(const std::string& data, const string16& password);
+
+ // Export the given certificates and private keys into a PKCS #12 blob,
+ // storing into |output|.
+ // Returns the number of certificates successfully exported.
+ int ExportToPKCS12(const CertificateList& certs, const string16& password,
+ std::string* output);
+
+ // Uses similar logic to nsNSSCertificateDB::handleCACertDownload to find the
+ // root. Assumes the list is an ordered hierarchy with the root being either
+ // the first or last element.
+ // TODO(mattm): improve this to handle any order.
+ X509Certificate* FindRootInList(const CertificateList& certificates);
+
+ // Import CA certificates.
+ // Tries to import all the certificates given. The root will be trusted
+ // according to |trust_bits|. Any certificates that could not be imported
+ // will be listed in |not_imported|.
+ // Returns false if there is an internal error, otherwise true is returned and
+ // |not_imported| should be checked for any certificates that were not
+ // imported.
+ bool ImportCACerts(const CertificateList& certificates,
+ unsigned int trust_bits,
+ ImportCertFailureList* not_imported);
+
+ // Set trust values for certificate.
+ // Returns true on success or false on failure.
+ bool SetCertTrust(const X509Certificate* cert,
+ CertType type,
+ unsigned int trust_bits);
+
+ // Delete certificate and associated private key (if one exists).
+ // Returns true on success or false on failure.
+ bool DeleteCertAndKey(const X509Certificate* cert);
+#endif
+
private:
DISALLOW_COPY_AND_ASSIGN(CertDatabase);
};
diff --git a/net/base/cert_database_nss.cc b/net/base/cert_database_nss.cc
index 98930ff..18c7eba 100644
--- a/net/base/cert_database_nss.cc
+++ b/net/base/cert_database_nss.cc
@@ -4,24 +4,28 @@
#include "net/base/cert_database.h"
+#include <cert.h>
+#include <certdb.h>
+#include <keyhi.h>
#include <pk11pub.h>
#include <secmod.h>
-#include <ssl.h>
-#include <nssb64.h> // NSSBase64_EncodeItem()
-#include <secder.h> // DER_Encode()
-#include <cryptohi.h> // SEC_DerSignData()
-#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
#include "base/logging.h"
-#include "base/scoped_ptr.h"
#include "base/nss_util.h"
+#include "base/scoped_ptr.h"
#include "net/base/net_errors.h"
#include "net/base/x509_certificate.h"
+#include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
+#include "net/third_party/mozilla_security_manager/nsPKCS12Blob.h"
+
+// PSM = Mozilla's Personal Security Manager.
+namespace psm = mozilla_security_manager;
namespace net {
CertDatabase::CertDatabase() {
base::EnsureNSSInit();
+ psm::EnsurePKCS12Init();
}
int CertDatabase::CheckUserCert(X509Certificate* cert_obj) {
@@ -85,4 +89,90 @@ int CertDatabase::AddUserCert(X509Certificate* cert_obj) {
return OK;
}
+void CertDatabase::ListCerts(CertificateList* certs) {
+ certs->clear();
+
+ CERTCertList* cert_list = PK11_ListCerts(PK11CertListUnique, NULL);
+ CERTCertListNode* node;
+ for (node = CERT_LIST_HEAD(cert_list);
+ !CERT_LIST_END(node, cert_list);
+ node = CERT_LIST_NEXT(node)) {
+ certs->push_back(X509Certificate::CreateFromHandle(
+ node->cert,
+ X509Certificate::SOURCE_LONE_CERT_IMPORT,
+ X509Certificate::OSCertHandles()));
+ }
+ CERT_DestroyCertList(cert_list);
+}
+
+int CertDatabase::ImportFromPKCS12(
+ const std::string& data, const string16& password) {
+ return psm::nsPKCS12Blob_Import(data.data(), data.size(), password);
+}
+
+int CertDatabase::ExportToPKCS12(
+ const CertificateList& certs,
+ const string16& password,
+ std::string* output) {
+ return psm::nsPKCS12Blob_Export(output, certs, password);
+}
+
+X509Certificate* CertDatabase::FindRootInList(
+ const CertificateList& certificates) {
+ DCHECK_GT(certificates.size(), 0U);
+
+ if (certificates.size() == 1)
+ return certificates[0].get();
+
+ X509Certificate* cert0 = certificates[0];
+ X509Certificate* cert1 = certificates[1];
+ X509Certificate* certn_2 = certificates[certificates.size() - 2];
+ X509Certificate* certn_1 = certificates[certificates.size() - 1];
+
+ if (CERT_CompareName(&cert1->os_cert_handle()->issuer,
+ &cert0->os_cert_handle()->subject) == SECEqual)
+ return cert0;
+ if (CERT_CompareName(&certn_2->os_cert_handle()->issuer,
+ &certn_1->os_cert_handle()->subject) == SECEqual)
+ return certn_1;
+
+ LOG(INFO) << "certificate list is not a hierarchy";
+ return cert0;
+}
+
+bool CertDatabase::ImportCACerts(const CertificateList& certificates,
+ unsigned int trust_bits,
+ ImportCertFailureList* not_imported) {
+ X509Certificate* root = FindRootInList(certificates);
+ return psm::ImportCACerts(certificates, root, trust_bits, not_imported);
+}
+
+bool CertDatabase::SetCertTrust(const X509Certificate* cert,
+ CertType type,
+ unsigned int trusted) {
+ return psm::SetCertTrust(cert, type, trusted);
+}
+
+bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
+ // For some reason, PK11_DeleteTokenCertAndKey only calls
+ // SEC_DeletePermCertificate if the private key is found. So, we check
+ // whether a private key exists before deciding which function to call to
+ // delete the cert.
+ SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert->os_cert_handle(),
+ NULL);
+ if (privKey) {
+ SECKEY_DestroyPrivateKey(privKey);
+ if (PK11_DeleteTokenCertAndKey(cert->os_cert_handle(), NULL)) {
+ LOG(ERROR) << "PK11_DeleteTokenCertAndKey failed: " << PORT_GetError();
+ return false;
+ }
+ } else {
+ if (SEC_DeletePermCertificate(cert->os_cert_handle())) {
+ LOG(ERROR) << "SEC_DeletePermCertificate failed: " << PORT_GetError();
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace net
diff --git a/net/base/cert_database_nss_unittest.cc b/net/base/cert_database_nss_unittest.cc
new file mode 100644
index 0000000..b115ac0
--- /dev/null
+++ b/net/base/cert_database_nss_unittest.cc
@@ -0,0 +1,421 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cert.h>
+#include <pk11pub.h>
+
+#include <algorithm>
+
+#include "base/crypto/scoped_nss_types.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/nss_util.h"
+#include "base/nss_util_internal.h"
+#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/cert_database.h"
+#include "net/base/net_errors.h"
+#include "net/base/x509_certificate.h"
+#include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
+#include "net/third_party/mozilla_security_manager/nsNSSCertTrust.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace psm = mozilla_security_manager;
+
+namespace net {
+
+namespace {
+
+// 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;
+}
+
+CertificateList ListCertsInSlot(PK11SlotInfo* slot) {
+ CertificateList result;
+ CERTCertList* cert_list = PK11_ListCertsInSlot(slot);
+ for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
+ !CERT_LIST_END(node, cert_list);
+ node = CERT_LIST_NEXT(node)) {
+ result.push_back(
+ X509Certificate::CreateFromHandle(
+ node->cert,
+ X509Certificate::SOURCE_LONE_CERT_IMPORT,
+ X509Certificate::OSCertHandles()));
+ }
+ CERT_DestroyCertList(cert_list);
+
+ // Sort the result so that test comparisons can be deterministic.
+ std::sort(result.begin(), result.end(), X509Certificate::LessThan());
+ return result;
+}
+
+bool CleanupSlotContents(PK11SlotInfo* slot) {
+ CertDatabase cert_db;
+ bool ok = true;
+ CertificateList certs = ListCertsInSlot(slot);
+ for (size_t i = 0; i < certs.size(); ++i) {
+ if (!cert_db.DeleteCertAndKey(certs[i]))
+ ok = false;
+ }
+ return ok;
+}
+
+std::string ReadTestFile(const std::string& name) {
+ std::string result;
+ FilePath cert_path = GetTestCertsDirectory().AppendASCII(name);
+ EXPECT_TRUE(file_util::ReadFileToString(cert_path, &result));
+ return result;
+}
+
+bool ReadCertIntoList(const std::string& name, CertificateList* certs) {
+ std::string cert_data = ReadTestFile(name);
+ if (cert_data.empty())
+ return false;
+
+ X509Certificate* cert = X509Certificate::CreateFromBytes(
+ cert_data.data(), cert_data.size());
+ if (!cert)
+ return false;
+
+ certs->push_back(cert);
+ return true;
+}
+
+} // namespace
+
+// TODO(mattm): when https://bugzilla.mozilla.org/show_bug.cgi?id=588269 is
+// fixed, switch back to using a separate userdb for each test.
+// (When doing so, remember to add some standalone tests of DeleteCert since it
+// won't be tested by TearDown anymore.)
+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;
+ }
+ slot_.reset(base::GetDefaultNSSKeySlot());
+
+ // Test db should be empty at start of test.
+ EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+ }
+ 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()));
+ EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+ }
+
+ protected:
+ base::ScopedPK11Slot slot_;
+ CertDatabase cert_db_;
+
+ private:
+ static bool temp_db_initialized_;
+};
+
+// 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.
+ CertificateList certs;
+ cert_db_.ListCerts(&certs);
+ // The test DB is empty, but let's assume there will always be something in
+ // the other slots.
+ EXPECT_LT(0U, certs.size());
+}
+
+TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) {
+ std::string pkcs12_data = ReadTestFile("client.p12");
+
+ EXPECT_EQ(ERR_PKCS12_IMPORT_BAD_PASSWORD,
+ cert_db_.ImportFromPKCS12(pkcs12_data, ASCIIToUTF16("")));
+
+ // Test db should still be empty.
+ EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+}
+
+TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AndExportAgain) {
+ std::string pkcs12_data = ReadTestFile("client.p12");
+
+ EXPECT_EQ(OK, cert_db_.ImportFromPKCS12(pkcs12_data, ASCIIToUTF16("12345")));
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(1U, cert_list.size());
+ scoped_refptr<X509Certificate> cert(cert_list[0]);
+
+ EXPECT_EQ("testusercert",
+ cert->subject().common_name);
+
+ // TODO(mattm): move export test to seperate test case?
+ std::string exported_data;
+ EXPECT_EQ(1, cert_db_.ExportToPKCS12(cert_list, ASCIIToUTF16("exportpw"),
+ &exported_data));
+ ASSERT_LT(0U, exported_data.size());
+ // TODO(mattm): further verification of exported data?
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACert_SSLTrust) {
+ std::string cert_data = ReadTestFile("root_ca_cert.crt");
+
+ CertificateList certs =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(1U, certs.size());
+ EXPECT_FALSE(certs[0]->os_cert_handle()->isperm);
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true, cert_db_.ImportCACerts(certs, CertDatabase::TRUSTED_SSL,
+ &failed));
+
+ EXPECT_EQ(0U, failed.size());
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(1U, cert_list.size());
+ scoped_refptr<X509Certificate> cert(cert_list[0]);
+ EXPECT_EQ("Test CA", cert->subject().common_name);
+
+ psm::nsNSSCertTrust trust(cert->os_cert_handle()->trust);
+ EXPECT_TRUE(trust.HasTrustedCA(PR_TRUE, PR_FALSE, PR_FALSE));
+ EXPECT_FALSE(trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE));
+ EXPECT_FALSE(trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE));
+ EXPECT_FALSE(trust.HasTrustedCA(PR_TRUE, PR_TRUE, PR_TRUE));
+ EXPECT_TRUE(trust.HasCA(PR_TRUE, PR_TRUE, PR_TRUE));
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACert_EmailTrust) {
+ std::string cert_data = ReadTestFile("root_ca_cert.crt");
+
+ CertificateList certs =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(1U, certs.size());
+ EXPECT_FALSE(certs[0]->os_cert_handle()->isperm);
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true, cert_db_.ImportCACerts(certs, CertDatabase::TRUSTED_EMAIL,
+ &failed));
+
+ EXPECT_EQ(0U, failed.size());
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(1U, cert_list.size());
+ scoped_refptr<X509Certificate> cert(cert_list[0]);
+ EXPECT_EQ("Test CA", cert->subject().common_name);
+
+ psm::nsNSSCertTrust trust(cert->os_cert_handle()->trust);
+ EXPECT_FALSE(trust.HasTrustedCA(PR_TRUE, PR_FALSE, PR_FALSE));
+ EXPECT_TRUE(trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE));
+ EXPECT_FALSE(trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE));
+ EXPECT_TRUE(trust.HasCA(PR_TRUE, PR_TRUE, PR_TRUE));
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACert_ObjSignTrust) {
+ std::string cert_data = ReadTestFile("root_ca_cert.crt");
+
+ CertificateList certs =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(1U, certs.size());
+ EXPECT_FALSE(certs[0]->os_cert_handle()->isperm);
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true, cert_db_.ImportCACerts(certs, CertDatabase::TRUSTED_OBJ_SIGN,
+ &failed));
+
+ EXPECT_EQ(0U, failed.size());
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(1U, cert_list.size());
+ scoped_refptr<X509Certificate> cert(cert_list[0]);
+ EXPECT_EQ("Test CA", cert->subject().common_name);
+
+ psm::nsNSSCertTrust trust(cert->os_cert_handle()->trust);
+ EXPECT_FALSE(trust.HasTrustedCA(PR_TRUE, PR_FALSE, PR_FALSE));
+ EXPECT_FALSE(trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE));
+ EXPECT_TRUE(trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE));
+ EXPECT_TRUE(trust.HasCA(PR_TRUE, PR_TRUE, PR_TRUE));
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCA_NotCACert) {
+ std::string cert_data = ReadTestFile("google.single.pem");
+
+ CertificateList certs =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(1U, certs.size());
+ EXPECT_FALSE(certs[0]->os_cert_handle()->isperm);
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true,
+ cert_db_.ImportCACerts(certs, CertDatabase::TRUSTED_SSL, &failed));
+ ASSERT_EQ(1U, failed.size());
+ // Note: this compares pointers directly. It's okay in this case because
+ // ImportCACerts returns the same pointers that were passed in. In the
+ // general case IsSameOSCert should be used.
+ EXPECT_EQ(certs[0], failed[0].certificate);
+ EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[0].net_error);
+
+ EXPECT_EQ(0U, ListCertsInSlot(slot_.get()).size());
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACertHierarchy) {
+ CertificateList certs;
+ ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs));
+ ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs));
+ ASSERT_TRUE(ReadCertIntoList("www_us_army_mil_cert.der", &certs));
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ // Have to specify email trust for the cert verification of the child cert to
+ // work (see
+ // http://mxr.mozilla.org/mozilla/source/security/nss/lib/certhigh/certvfy.c#752
+ // "XXX This choice of trustType seems arbitrary.")
+ EXPECT_EQ(true, cert_db_.ImportCACerts(
+ certs, CertDatabase::TRUSTED_SSL | CertDatabase::TRUSTED_EMAIL,
+ &failed));
+
+ ASSERT_EQ(1U, failed.size());
+ EXPECT_EQ("www.us.army.mil", failed[0].certificate->subject().common_name);
+ EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[0].net_error);
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(2U, cert_list.size());
+ EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
+ EXPECT_EQ("DOD CA-17", cert_list[1]->subject().common_name);
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyDupeRoot) {
+ CertificateList certs;
+ ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs));
+
+ // First import just the root.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true, cert_db_.ImportCACerts(
+ certs, CertDatabase::TRUSTED_SSL | CertDatabase::TRUSTED_EMAIL,
+ &failed));
+
+ EXPECT_EQ(0U, failed.size());
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(1U, cert_list.size());
+ EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
+
+ ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs));
+ ASSERT_TRUE(ReadCertIntoList("www_us_army_mil_cert.der", &certs));
+
+ // Now import with the other certs in the list too. Even though the root is
+ // already present, we should still import the rest.
+ failed.clear();
+ EXPECT_EQ(true, cert_db_.ImportCACerts(
+ certs, CertDatabase::TRUSTED_SSL | CertDatabase::TRUSTED_EMAIL,
+ &failed));
+
+ ASSERT_EQ(2U, failed.size());
+ EXPECT_EQ("DoD Root CA 2", failed[0].certificate->subject().common_name);
+ EXPECT_EQ(ERR_IMPORT_CERT_ALREADY_EXISTS, failed[0].net_error);
+ EXPECT_EQ("www.us.army.mil", failed[1].certificate->subject().common_name);
+ EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[1].net_error);
+
+ cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(2U, cert_list.size());
+ EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
+ EXPECT_EQ("DOD CA-17", cert_list[1]->subject().common_name);
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyUntrusted) {
+ CertificateList certs;
+ ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs));
+ ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs));
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true, cert_db_.ImportCACerts(certs, CertDatabase::UNTRUSTED,
+ &failed));
+
+ ASSERT_EQ(1U, failed.size());
+ EXPECT_EQ("DOD CA-17", failed[0].certificate->subject().common_name);
+ // TODO(mattm): should check for net error equivalent of
+ // SEC_ERROR_UNTRUSTED_ISSUER
+ EXPECT_EQ(ERR_FAILED, failed[0].net_error);
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(1U, cert_list.size());
+ EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name);
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyTree) {
+ CertificateList certs;
+ ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs));
+ ASSERT_TRUE(ReadCertIntoList("dod_ca_13_cert.der", &certs));
+ ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs));
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true, cert_db_.ImportCACerts(
+ certs, CertDatabase::TRUSTED_SSL | CertDatabase::TRUSTED_EMAIL,
+ &failed));
+
+ EXPECT_EQ(0U, failed.size());
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(3U, cert_list.size());
+ EXPECT_EQ("DOD CA-13", cert_list[0]->subject().common_name);
+ EXPECT_EQ("DoD Root CA 2", cert_list[1]->subject().common_name);
+ EXPECT_EQ("DOD CA-17", cert_list[2]->subject().common_name);
+}
+
+TEST_F(CertDatabaseNSSTest, ImportCACertNotHierarchy) {
+ std::string cert_data = ReadTestFile("root_ca_cert.crt");
+ CertificateList certs =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+ ASSERT_EQ(1U, certs.size());
+ ASSERT_TRUE(ReadCertIntoList("dod_ca_13_cert.der", &certs));
+ ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs));
+
+ // Import it.
+ CertDatabase::ImportCertFailureList failed;
+ EXPECT_EQ(true, cert_db_.ImportCACerts(
+ certs, CertDatabase::TRUSTED_SSL | CertDatabase::TRUSTED_EMAIL |
+ CertDatabase::TRUSTED_OBJ_SIGN, &failed));
+
+ ASSERT_EQ(2U, failed.size());
+ // TODO(mattm): should check for net error equivalent of
+ // SEC_ERROR_UNKNOWN_ISSUER
+ EXPECT_EQ("DOD CA-13", failed[0].certificate->subject().common_name);
+ EXPECT_EQ(ERR_FAILED, failed[0].net_error);
+ EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name);
+ EXPECT_EQ(ERR_FAILED, failed[1].net_error);
+
+ CertificateList cert_list = ListCertsInSlot(slot_.get());
+ ASSERT_EQ(1U, cert_list.size());
+ EXPECT_EQ("Test CA", cert_list[0]->subject().common_name);
+}
+
+
+} // namespace net
diff --git a/net/base/cert_status_flags.cc b/net/base/cert_status_flags.cc
index 7e20cec..a6bdce4 100644
--- a/net/base/cert_status_flags.cc
+++ b/net/base/cert_status_flags.cc
@@ -33,6 +33,8 @@ int MapNetErrorToCertStatus(int error) {
return CERT_STATUS_INVALID;
case ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
return CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
+ case ERR_CERT_NOT_IN_DNS:
+ return CERT_STATUS_NOT_IN_DNS;
default:
return 0;
}
@@ -63,6 +65,8 @@ int MapCertStatusToNetError(int cert_status) {
return ERR_CERT_UNABLE_TO_CHECK_REVOCATION;
if (cert_status & CERT_STATUS_NO_REVOCATION_MECHANISM)
return ERR_CERT_NO_REVOCATION_MECHANISM;
+ if (cert_status & CERT_STATUS_NOT_IN_DNS)
+ return ERR_CERT_NOT_IN_DNS;
NOTREACHED();
return ERR_UNEXPECTED;
diff --git a/net/base/cert_status_flags.h b/net/base/cert_status_flags.h
index e4f07bb..8bf2565 100644
--- a/net/base/cert_status_flags.h
+++ b/net/base/cert_status_flags.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_CERT_STATUS_FLAGS_H_
#define NET_BASE_CERT_STATUS_FLAGS_H_
+#pragma once
namespace net {
@@ -20,10 +21,12 @@ enum {
CERT_STATUS_REVOKED = 1 << 6,
CERT_STATUS_INVALID = 1 << 7,
CERT_STATUS_WEAK_SIGNATURE_ALGORITHM = 1 << 8,
+ CERT_STATUS_NOT_IN_DNS = 1 << 9,
// Bits 16 to 30 are for non-error statuses.
CERT_STATUS_IS_EV = 1 << 16,
CERT_STATUS_REV_CHECKING_ENABLED = 1 << 17,
+ CERT_STATUS_IS_DNSSEC = 1 << 18,
// 1 << 31 (the sign bit) is reserved so that the cert status will never be
// negative.
diff --git a/net/base/cert_test_util.h b/net/base/cert_test_util.h
index a288774..45c8ed3 100644
--- a/net/base/cert_test_util.h
+++ b/net/base/cert_test_util.h
@@ -4,10 +4,12 @@
#ifndef NET_BASE_CERT_TEST_UTIL_H_
#define NET_BASE_CERT_TEST_UTIL_H_
+#pragma once
-#include "base/file_path.h"
#include "build/build_config.h"
+class FilePath;
+
namespace net {
class X509Certificate;
diff --git a/net/base/cert_verifier.h b/net/base/cert_verifier.h
index b685f2e..791f8d3 100644
--- a/net/base/cert_verifier.h
+++ b/net/base/cert_verifier.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_CERT_VERIFIER_H_
#define NET_BASE_CERT_VERIFIER_H_
+#pragma once
#include <string>
diff --git a/net/base/cert_verify_result.h b/net/base/cert_verify_result.h
index 9ab48b9..faac17a 100644
--- a/net/base/cert_verify_result.h
+++ b/net/base/cert_verify_result.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_CERT_VERIFY_RESULT_H_
#define NET_BASE_CERT_VERIFY_RESULT_H_
+#pragma once
namespace net {
@@ -22,6 +23,7 @@ class CertVerifyResult {
has_md2_ca = false;
}
+ // Bitmask of CERT_STATUS_* from net/base/cert_status_flags.h
int cert_status;
// Properties of the certificate chain.
diff --git a/net/base/completion_callback.h b/net/base/completion_callback.h
index 11a6b3a..739d86d 100644
--- a/net/base/completion_callback.h
+++ b/net/base/completion_callback.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_COMPLETION_CALLBACK_H__
#define NET_BASE_COMPLETION_CALLBACK_H__
+#pragma once
#include "base/callback.h"
diff --git a/net/base/connection_type_histograms.h b/net/base/connection_type_histograms.h
index 582f09d..e6c2a59 100644
--- a/net/base/connection_type_histograms.h
+++ b/net/base/connection_type_histograms.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_CONNECTION_TYPE_HISTOGRAMS_H_
#define NET_BASE_CONNECTION_TYPE_HISTOGRAMS_H_
+#pragma once
// The UpdateConnectionTypeHistograms function collects statistics related
// to the number of MD5 certificates that our users are encountering. The
diff --git a/net/base/cookie_monster.cc b/net/base/cookie_monster.cc
index e79cf47..f9ec08f 100644
--- a/net/base/cookie_monster.cc
+++ b/net/base/cookie_monster.cc
@@ -48,10 +48,12 @@
#include "base/basictypes.h"
#include "base/format_macros.h"
+#include "base/histogram.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_canon.h"
#include "net/base/net_util.h"
@@ -66,22 +68,20 @@
using base::Time;
using base::TimeDelta;
+using base::TimeTicks;
static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
namespace net {
-namespace {
+// See comments at declaration of these variables in cookie_monster.h
+// for details.
+const size_t CookieMonster::kDomainMaxCookies = 180;
+const size_t CookieMonster::kDomainPurgeCookies = 30;
+const size_t CookieMonster::kMaxCookies = 3300;
+const size_t CookieMonster::kPurgeCookies = 300;
-// Cookie garbage collection thresholds. Based off of the Mozilla defaults.
-// It might seem scary to have a high purge value, but really it's not. You
-// just make sure that you increase the max to cover the increase in purge,
-// and we would have been purging the same amount of cookies. We're just
-// going through the garbage collection process less often.
-const size_t kNumCookiesPerHost = 70; // ~50 cookies
-const size_t kNumCookiesPerHostPurge = 20;
-const size_t kNumCookiesTotal = 3300; // ~3000 cookies
-const size_t kNumCookiesTotalPurge = 300;
+namespace {
// Default minimum delay after updating a cookie's LastAccessDate before we
// will update it again.
@@ -108,6 +108,7 @@ void CookieMonster::EnableFileScheme() {
CookieMonster::CookieMonster(PersistentCookieStore* store, Delegate* delegate)
: initialized_(false),
+ use_effective_domain_key_scheme_(use_effective_domain_key_default_),
store_(store),
last_access_threshold_(
TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)),
@@ -147,19 +148,28 @@ CookieMonster::~CookieMonster() {
void CookieMonster::InitializeHistograms() {
// From UMA_HISTOGRAM_CUSTOM_COUNTS
histogram_expiration_duration_minutes_ = Histogram::FactoryGet(
- "net.CookieExpirationDurationMinutes",
+ "Cookie.ExpirationDurationMinutes",
1, kMinutesInTenYears, 50,
Histogram::kUmaTargetedHistogramFlag);
histogram_between_access_interval_minutes_ = Histogram::FactoryGet(
- "net.CookieBetweenAccessIntervalMinutes",
+ "Cookie.BetweenAccessIntervalMinutes",
1, kMinutesInTenYears, 50,
Histogram::kUmaTargetedHistogramFlag);
histogram_evicted_last_access_minutes_ = Histogram::FactoryGet(
- "net.CookieEvictedLastAccessMinutes",
+ "Cookie.EvictedLastAccessMinutes",
1, kMinutesInTenYears, 50,
Histogram::kUmaTargetedHistogramFlag);
- histogram_count_ = Histogram::FactoryGet(
- "net.CookieCount", 1, 4000, 50,
+ histogram_count_ = Histogram::FactoryGet(
+ "Cookie.Count", 1, 4000, 50,
+ Histogram::kUmaTargetedHistogramFlag);
+ histogram_domain_count_ = Histogram::FactoryGet(
+ "Cookie.DomainCount", 1, 4000, 50,
+ Histogram::kUmaTargetedHistogramFlag);
+ histogram_etldp1_count_ = Histogram::FactoryGet(
+ "Cookie.Etldp1Count", 1, 4000, 50,
+ Histogram::kUmaTargetedHistogramFlag);
+ histogram_domain_per_etldp1_count_ = Histogram::FactoryGet(
+ "Cookie.DomainPerEtldp1Count", 1, 4000, 50,
Histogram::kUmaTargetedHistogramFlag);
// From UMA_HISTOGRAM_COUNTS_10000 & UMA_HISTOGRAM_CUSTOM_COUNTS
@@ -169,32 +179,63 @@ void CookieMonster::InitializeHistograms() {
// From UMA_HISTOGRAM_ENUMERATION
histogram_cookie_deletion_cause_ = LinearHistogram::FactoryGet(
- "net.CookieDeletionCause", 1,
+ "Cookie.DeletionCause", 1,
DELETE_COOKIE_LAST_ENTRY, DELETE_COOKIE_LAST_ENTRY + 1,
Histogram::kUmaTargetedHistogramFlag);
+
+ // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
+ histogram_time_get_ = Histogram::FactoryTimeGet("Cookie.TimeGet",
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
+ 50, Histogram::kUmaTargetedHistogramFlag);
+ histogram_time_load_ = Histogram::FactoryTimeGet("Cookie.TimeLoad",
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
+ 50, Histogram::kUmaTargetedHistogramFlag);
}
void CookieMonster::InitStore() {
DCHECK(store_) << "Store must exist to initialize";
+ TimeTicks beginning_time(TimeTicks::Now());
+
// Initialize the store and sync in any saved persistent cookies. We don't
// care if it's expired, insert it so it can be garbage collected, removed,
// and sync'd.
- std::vector<KeyedCanonicalCookie> cookies;
+ std::vector<CanonicalCookie*> cookies;
// Reserve space for the maximum amount of cookies a database should have.
// This prevents multiple vector growth / copies as we append cookies.
- cookies.reserve(kNumCookiesTotal);
+ cookies.reserve(kMaxCookies);
store_->Load(&cookies);
- for (std::vector<KeyedCanonicalCookie>::const_iterator it = cookies.begin();
+
+ // Avoid ever letting cookies with duplicate creation times into the store;
+ // that way we don't have to worry about what sections of code are safe
+ // to call while it's in that state.
+ std::set<int64> creation_times;
+ for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
it != cookies.end(); ++it) {
- InternalInsertCookie(it->first, it->second, false);
+ int64 cookie_creation_time = (*it)->CreationDate().ToInternalValue();
+
+ if (creation_times.insert(cookie_creation_time).second) {
+ InternalInsertCookie(GetKey((*it)->Domain()), *it, false);
+ } else {
+ LOG(ERROR) << base::StringPrintf("Found cookies with duplicate creation "
+ "times in backing store: "
+ "{name='%s', domain='%s', path='%s'}",
+ (*it)->Name().c_str(),
+ (*it)->Domain().c_str(),
+ (*it)->Path().c_str());
+ // We've been given ownership of the cookie and are throwing it
+ // away; reclaim the space.
+ delete (*it);
+ }
}
// After importing cookies from the PersistentCookieStore, verify that
- // none of our constraints are violated.
+ // none of our other constraints are violated.
//
// In particular, the backing store might have given us duplicate cookies.
EnsureCookiesMapIsValid();
+
+ histogram_time_load_->AddTime(TimeTicks::Now() - beginning_time);
}
void CookieMonster::EnsureCookiesMapIsValid() {
@@ -212,15 +253,12 @@ void CookieMonster::EnsureCookiesMapIsValid() {
// Ensure no equivalent cookies for this host.
num_duplicates_trimmed +=
- TrimDuplicateCookiesForHost(key, cur_range_begin, cur_range_end);
+ TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
}
// Record how many duplicates were found in the database.
// See InitializeHistograms() for details.
histogram_cookie_deletion_cause_->Add(num_duplicates_trimmed);
-
- // TODO(eroman): Should also verify that there are no cookies with the same
- // creation time, since that is assumed to be unique by the rest of the code.
}
// Our strategy to find duplicates is:
@@ -262,7 +300,7 @@ struct CookieSignature {
};
}
-int CookieMonster::TrimDuplicateCookiesForHost(
+int CookieMonster::TrimDuplicateCookiesForKey(
const std::string& key,
CookieMap::iterator begin,
CookieMap::iterator end) {
@@ -286,21 +324,26 @@ int CookieMonster::TrimDuplicateCookiesForHost(
CookieSignature signature(cookie->Name(), cookie->Domain(),
cookie->Path());
- CookieSet& list = equivalent_cookies[signature];
+ CookieSet& set = equivalent_cookies[signature];
// We found a duplicate!
- if (!list.empty())
+ if (!set.empty())
num_duplicates++;
// We save the iterator into |cookies_| rather than the actual cookie
// pointer, since we may need to delete it later.
- list.insert(it);
+ bool insert_success = set.insert(it).second;
+ DCHECK(insert_success) <<
+ "Duplicate creation times found in duplicate cookie name scan.";
}
// If there were no duplicates, we are done!
if (num_duplicates == 0)
return 0;
+ // Make sure we find everything below that we did above.
+ int num_duplicates_found = 0;
+
// Otherwise, delete all the duplicate cookies, both from our in-memory store
// and from the backing store.
for (EquivalenceMap::iterator it = equivalent_cookies.begin();
@@ -311,18 +354,20 @@ int CookieMonster::TrimDuplicateCookiesForHost(
if (dupes.size() <= 1)
continue; // This cookiename/path has no duplicates.
+ num_duplicates_found += dupes.size() - 1;
// Since |dups| is sorted by creation time (descending), the first cookie
// is the most recent one, so we will keep it. The rest are duplicates.
dupes.erase(dupes.begin());
- LOG(ERROR) << StringPrintf("Found %d duplicate cookies for host='%s', "
- "with {name='%s', domain='%s', path='%s'}",
- static_cast<int>(dupes.size()),
- key.c_str(),
- signature.name.c_str(),
- signature.domain.c_str(),
- signature.path.c_str());
+ LOG(ERROR) << base::StringPrintf(
+ "Found %d duplicate cookies for host='%s', "
+ "with {name='%s', domain='%s', path='%s'}",
+ static_cast<int>(dupes.size()),
+ key.c_str(),
+ signature.name.c_str(),
+ signature.domain.c_str(),
+ signature.path.c_str());
// Remove all the cookies identified by |dupes|. It is valid to delete our
// list of iterators one at a time, since |cookies_| is a multimap (they
@@ -334,6 +379,7 @@ int CookieMonster::TrimDuplicateCookiesForHost(
DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
}
}
+ DCHECK_EQ(num_duplicates, num_duplicates_found);
return num_duplicates;
}
@@ -345,6 +391,11 @@ void CookieMonster::SetDefaultCookieableSchemes() {
SetCookieableSchemes(kDefaultCookieableSchemes, num_schemes);
}
+void CookieMonster::SetKeyScheme(bool use_effective_domain_key) {
+ DCHECK(!initialized_);
+ use_effective_domain_key_scheme_ = use_effective_domain_key;
+}
+
// 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
// increment by one Time unit. Let's hope computers don't get too fast.
@@ -477,7 +528,7 @@ bool CookieMonster::DomainIsHostOnly(const std::string& domain_string) {
// Returns the effective TLD+1 for a given host. This only makes sense for http
// and https schemes. For other schemes, the host will be returned unchanged
-// (minus any leading .).
+// (minus any leading period).
static std::string GetEffectiveDomain(const std::string& scheme,
const std::string& host) {
if (scheme == "http" || scheme == "https")
@@ -488,14 +539,51 @@ static std::string GetEffectiveDomain(const std::string& scheme,
return host;
}
-// Determine the cookie domain key to use for setting a cookie with the
-// specified domain attribute string.
-// On success returns true, and sets cookie_domain_key to either a
-// -host cookie key (ex: "google.com")
-// -domain cookie key (ex: ".google.com")
-static bool GetCookieDomainKeyWithString(const GURL& url,
- const std::string& domain_string,
- std::string* cookie_domain_key) {
+// A wrapper around RegistryControlledDomainService::GetDomainAndRegistry
+// to make clear we're creating a key for our local map. Here and
+// in FindCookiesForHostAndDomain() are the only two places where
+// we need to conditionalize based on key type.
+//
+// Note that this key algorithm explicitly ignores the scheme. This is
+// because when we're entering cookies into the map from the backing store,
+// we in general won't have the scheme at that point.
+// In practical terms, this means that file cookies will be stored
+// in the map either by an empty string or by UNC name (and will be
+// limited by kMaxCookiesPerHost), and extension cookies will be stored
+// based on the single extension id, as the extension id won't have the
+// form of a DNS host and hence GetKey() will return it unchanged.
+//
+// Arguably the right thing to do here is to make the key
+// algorithm dependent on the scheme, and make sure that the scheme is
+// available everywhere the key must be obtained (specfically at backing
+// store load time). This would require either changing the backing store
+// database schema to include the scheme (far more trouble than it's worth), or
+// separating out file cookies into their own CookieMonster instance and
+// thus restricting each scheme to a single cookie monster (which might
+// be worth it, but is still too much trouble to solve what is currently a
+// non-problem).
+std::string CookieMonster::GetKey(const std::string& domain) const {
+ if (!use_effective_domain_key_scheme_)
+ return domain;
+
+ std::string effective_domain(
+ RegistryControlledDomainService::GetDomainAndRegistry(domain));
+ if (effective_domain.empty())
+ effective_domain = domain;
+
+ if (!effective_domain.empty() && effective_domain[0] == '.')
+ return effective_domain.substr(1);
+ return effective_domain;
+}
+
+// Determine the actual cookie domain based on the domain string passed
+// (if any) and the URL from which the cookie came.
+// On success returns true, and sets cookie_domain to either a
+// -host cookie domain (ex: "google.com")
+// -domain cookie domain (ex: ".google.com")
+static bool GetCookieDomainWithString(const GURL& url,
+ const std::string& domain_string,
+ std::string* result) {
const std::string url_host(url.host());
// If no domain was specified in the domain string, default to a host cookie.
@@ -503,8 +591,8 @@ static bool GetCookieDomainKeyWithString(const GURL& url,
// ip address hostname exactly. It should be treated as a host cookie.
if (domain_string.empty() ||
(url.HostIsIPAddress() && url_host == domain_string)) {
- *cookie_domain_key = url_host;
- DCHECK(CookieMonster::DomainIsHostOnly(*cookie_domain_key));
+ *result = url_host;
+ DCHECK(CookieMonster::DomainIsHostOnly(*result));
return true;
}
@@ -542,18 +630,18 @@ static bool GetCookieDomainKeyWithString(const GURL& url,
cookie_domain.length(), cookie_domain))
return false;
- *cookie_domain_key = cookie_domain;
+ *result = cookie_domain;
return true;
}
-// Determine the cookie domain key to use for setting the specified cookie.
-static bool GetCookieDomainKey(const GURL& url,
- const CookieMonster::ParsedCookie& pc,
- std::string* cookie_domain_key) {
+// Determine the cookie domain to use for setting the specified cookie.
+static bool GetCookieDomain(const GURL& url,
+ const CookieMonster::ParsedCookie& pc,
+ std::string* result) {
std::string domain_string;
if (pc.HasDomain())
domain_string = pc.Domain();
- return GetCookieDomainKeyWithString(url, domain_string, cookie_domain_key);
+ return GetCookieDomainWithString(url, domain_string, result);
}
static std::string CanonPathWithString(const GURL& url,
@@ -654,13 +742,7 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions(
const std::string& cookie_line,
const Time& creation_time_or_null,
const CookieOptions& options) {
- AutoLock autolock(lock_);
-
- if (!HasCookieableScheme(url)) {
- return false;
- }
-
- InitIfNecessary();
+ lock_.AssertAcquired();
COOKIE_DLOG(INFO) << "SetCookie() line: " << cookie_line;
@@ -684,7 +766,7 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions(
}
std::string cookie_domain;
- if (!GetCookieDomainKey(url, pc, &cookie_domain)) {
+ if (!GetCookieDomain(url, pc, &cookie_domain)) {
return false;
}
@@ -703,7 +785,21 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions(
COOKIE_DLOG(WARNING) << "Failed to allocate CanonicalCookie";
return false;
}
- return SetCanonicalCookie(&cc, cookie_domain, creation_time, options);
+ return SetCanonicalCookie(&cc, creation_time, options);
+}
+
+bool CookieMonster::SetCookieWithCreationTime(const GURL& url,
+ const std::string& cookie_line,
+ const base::Time& creation_time) {
+ AutoLock autolock(lock_);
+
+ if (!HasCookieableScheme(url)) {
+ return false;
+ }
+
+ InitIfNecessary();
+ return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time,
+ CookieOptions());
}
bool CookieMonster::SetCookieWithDetails(
@@ -732,20 +828,20 @@ bool CookieMonster::SetCookieWithDetails(
CookieOptions options;
options.set_include_httponly();
- return SetCanonicalCookie(&cc, cc->Domain(), creation_time, options);
+ return SetCanonicalCookie(&cc, creation_time, options);
}
bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc,
- const std::string& cookie_domain,
const Time& creation_time,
const CookieOptions& options) {
- if (DeleteAnyEquivalentCookie(cookie_domain, **cc,
- options.exclude_httponly())) {
+ const std::string key(GetKey((*cc)->Domain()));
+ if (DeleteAnyEquivalentCookie(key, **cc, options.exclude_httponly())) {
COOKIE_DLOG(INFO) << "SetCookie() not clobbering httponly cookie";
return false;
}
- COOKIE_DLOG(INFO) << "SetCookie() cc: " << (*cc)->DebugString();
+ COOKIE_DLOG(INFO) << "SetCookie() key: " << key
+ << " cc: " << (*cc)->DebugString();
// Realize that we might be setting an expired cookie, and the only point
// was to delete the cookie which we've already done.
@@ -753,7 +849,7 @@ bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc,
// See InitializeHistograms() for details.
histogram_expiration_duration_minutes_->Add(
((*cc)->ExpiryDate() - creation_time).InMinutes());
- InternalInsertCookie(cookie_domain, cc->release(), true);
+ InternalInsertCookie(key, cc->release(), true);
}
// We assume that hopefully setting a cookie will be less common than
@@ -761,7 +857,7 @@ bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc,
// make sure that we garbage collect... We can also make the assumption that
// if a cookie was set, in the common case it will be used soon after,
// and we will purge the expired cookies in GetCookies().
- GarbageCollect(creation_time, cookie_domain);
+ GarbageCollect(creation_time, key);
return true;
}
@@ -772,20 +868,20 @@ void CookieMonster::InternalInsertCookie(const std::string& key,
lock_.AssertAcquired();
if (cc->IsPersistent() && store_ && sync_to_store)
- store_->AddCookie(key, *cc);
+ store_->AddCookie(*cc);
cookies_.insert(CookieMap::value_type(key, cc));
if (delegate_.get())
delegate_->OnCookieChanged(*cc, false);
}
-void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc) {
+void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
+ const Time& current) {
lock_.AssertAcquired();
// Based off the Mozilla code. When a cookie has been accessed recently,
// don't bother updating its access time again. This reduces the number of
// updates we do during pageload, which in turn reduces the chance our storage
// backend will hit its batch thresholds and be forced to update.
- const Time current = Time::Now();
if ((current - cc->LastAccessDate()) < last_access_threshold_)
return;
@@ -804,10 +900,12 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
lock_.AssertAcquired();
// See InitializeHistograms() for details.
- histogram_cookie_deletion_cause_->Add(deletion_cause);
+ if (deletion_cause != DELETE_COOKIE_DONT_RECORD)
+ histogram_cookie_deletion_cause_->Add(deletion_cause);
CanonicalCookie* cc = it->second;
COOKIE_DLOG(INFO) << "InternalDeleteCookie() cc: " << cc->DebugString();
+
if (cc->IsPersistent() && store_ && sync_to_store)
store_->DeleteCookie(*cc);
if (delegate_.get())
@@ -852,18 +950,27 @@ int CookieMonster::GarbageCollect(const Time& current,
int num_deleted = 0;
// Collect garbage for this key.
- if (cookies_.count(key) > kNumCookiesPerHost) {
+ if (cookies_.count(key) > kDomainMaxCookies) {
COOKIE_DLOG(INFO) << "GarbageCollect() key: " << key;
- num_deleted += GarbageCollectRange(current, cookies_.equal_range(key),
- kNumCookiesPerHost, kNumCookiesPerHostPurge);
+
+ std::vector<CookieMap::iterator> cookie_its;
+ num_deleted += GarbageCollectExpired(current, cookies_.equal_range(key),
+ &cookie_its);
+ num_deleted += GarbageCollectEvict(
+ current, kDomainMaxCookies, kDomainPurgeCookies,
+ DELETE_COOKIE_EVICTED_DOMAIN, &cookie_its);
}
// Collect garbage for everything.
- if (cookies_.size() > kNumCookiesTotal) {
+ if (cookies_.size() > kMaxCookies) {
COOKIE_DLOG(INFO) << "GarbageCollect() everything";
- num_deleted += GarbageCollectRange(current,
- CookieMapItPair(cookies_.begin(), cookies_.end()), kNumCookiesTotal,
- kNumCookiesTotalPurge);
+ std::vector<CookieMap::iterator> cookie_its;
+ num_deleted += GarbageCollectExpired(
+ current, CookieMapItPair(cookies_.begin(), cookies_.end()),
+ &cookie_its);
+ num_deleted += GarbageCollectEvict(
+ current, kMaxCookies, kPurgeCookies,
+ DELETE_COOKIE_EVICTED_GLOBAL, &cookie_its);
}
return num_deleted;
@@ -881,38 +988,6 @@ static bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1,
return it1->second->CreationDate() < it2->second->CreationDate();
}
-int CookieMonster::GarbageCollectRange(const Time& current,
- const CookieMapItPair& itpair,
- size_t num_max,
- size_t num_purge) {
- lock_.AssertAcquired();
-
- // First, delete anything that's expired.
- std::vector<CookieMap::iterator> cookie_its;
- int num_deleted = GarbageCollectExpired(current, itpair, &cookie_its);
-
- // If the range still has too many cookies, delete the least recently used.
- if (cookie_its.size() > num_max) {
- COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect.";
- // Purge down to (|num_max| - |num_purge|) total cookies.
- DCHECK(num_purge <= num_max);
- num_purge += cookie_its.size() - num_max;
-
- std::partial_sort(cookie_its.begin(), cookie_its.begin() + num_purge,
- cookie_its.end(), LRUCookieSorter);
- for (size_t i = 0; i < num_purge; ++i) {
- // See InitializeHistograms() for details.
- histogram_evicted_last_access_minutes_->Add(
- (current - cookie_its[i]->second->LastAccessDate()).InMinutes());
- InternalDeleteCookie(cookie_its[i], true, DELETE_COOKIE_EVICTED);
- }
-
- num_deleted += num_purge;
- }
-
- return num_deleted;
-}
-
int CookieMonster::GarbageCollectExpired(
const Time& current,
const CookieMapItPair& itpair,
@@ -935,6 +1010,32 @@ int CookieMonster::GarbageCollectExpired(
return num_deleted;
}
+int CookieMonster::GarbageCollectEvict(
+ const Time& current,
+ size_t num_max,
+ size_t num_purge,
+ DeletionCause cause,
+ std::vector<CookieMap::iterator>* cookie_its) {
+ if (cookie_its->size() <= num_max) {
+ return 0;
+ }
+
+ COOKIE_DLOG(INFO) << "GarbageCollectEvict() Deep Garbage Collect.";
+ // Purge down to (|num_max| - |num_purge|) total cookies.
+ DCHECK_LE(num_purge, num_max);
+ num_purge += cookie_its->size() - num_max;
+
+ std::partial_sort(cookie_its->begin(), cookie_its->begin() + num_purge,
+ cookie_its->end(), LRUCookieSorter);
+ for (size_t i = 0; i < num_purge; ++i) {
+ // See InitializeHistograms() for details.
+ histogram_evicted_last_access_minutes_->Add(
+ (current - (*cookie_its)[i]->second->LastAccessDate()).InMinutes());
+ InternalDeleteCookie((*cookie_its)[i], true, cause);
+ }
+ return num_purge;
+}
+
int CookieMonster::DeleteAll(bool sync_to_store) {
AutoLock autolock(lock_);
InitIfNecessary();
@@ -986,32 +1087,39 @@ int CookieMonster::DeleteAllForHost(const GURL& url) {
if (!HasCookieableScheme(url))
return 0;
+ const std::string scheme(url.scheme());
+ const std::string host(url.host());
+
// We store host cookies in the store by their canonical host name;
// domain cookies are stored with a leading ".". So this is a pretty
// simple lookup and per-cookie delete.
int num_deleted = 0;
- for (CookieMapItPair its = cookies_.equal_range(url.host());
+ for (CookieMapItPair its = cookies_.equal_range(GetKey(host));
its.first != its.second;) {
CookieMap::iterator curit = its.first;
++its.first;
- num_deleted++;
- InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
+ const CanonicalCookie* const cc = curit->second;
+
+ // Delete only on a match as a host cookie.
+ if (cc->IsHostCookie() && cc->IsDomainMatch(scheme, host)) {
+ num_deleted++;
+
+ InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
+ }
}
return num_deleted;
}
-bool CookieMonster::DeleteCookie(const std::string& domain,
- const CanonicalCookie& cookie,
- bool sync_to_store) {
+bool CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie) {
AutoLock autolock(lock_);
InitIfNecessary();
- for (CookieMapItPair its = cookies_.equal_range(domain);
+ for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
its.first != its.second; ++its.first) {
// The creation date acts as our unique index...
if (its.first->second->CreationDate() == cookie.CreationDate()) {
- InternalDeleteCookie(its.first, sync_to_store, DELETE_COOKIE_EXPLICIT);
+ InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
return true;
}
}
@@ -1031,21 +1139,17 @@ static bool CookieSorter(CookieMonster::CanonicalCookie* cc1,
bool CookieMonster::SetCookieWithOptions(const GURL& url,
const std::string& cookie_line,
const CookieOptions& options) {
+ AutoLock autolock(lock_);
+
+ if (!HasCookieableScheme(url)) {
+ return false;
+ }
+
+ InitIfNecessary();
+
return SetCookieWithCreationTimeAndOptions(url, cookie_line, Time(), options);
}
-// Currently our cookie datastructure is based on Mozilla's approach. We have a
-// hash keyed on the cookie's domain, and for any query we walk down the domain
-// components and probe for cookies until we reach the TLD, where we stop.
-// For example, a.b.blah.com, we would probe
-// - a.b.blah.com
-// - .a.b.blah.com (TODO should we check this first or second?)
-// - .b.blah.com
-// - .blah.com
-// There are some alternative datastructures we could try, like a
-// search/prefix trie, where we reverse the hostname and query for all
-// keys that are a prefix of our hostname. I think the hash probing
-// should be fast and simple enough for now.
std::string CookieMonster::GetCookiesWithOptions(const GURL& url,
const CookieOptions& options) {
AutoLock autolock(lock_);
@@ -1055,9 +1159,11 @@ std::string CookieMonster::GetCookiesWithOptions(const GURL& url,
return std::string();
}
+ TimeTicks start_time(TimeTicks::Now());
+
// Get the cookies for this host and its domain(s).
std::vector<CanonicalCookie*> cookies;
- FindCookiesForHostAndDomain(url, options, &cookies);
+ FindCookiesForHostAndDomain(url, options, true, &cookies);
std::sort(cookies.begin(), cookies.end(), CookieSorter);
std::string cookie_line;
@@ -1073,6 +1179,8 @@ std::string CookieMonster::GetCookiesWithOptions(const GURL& url,
cookie_line += (*it)->Value();
}
+ histogram_time_get_->AddTime(TimeTicks::Now() - start_time);
+
COOKIE_DLOG(INFO) << "GetCookies() result: " << cookie_line;
return cookie_line;
@@ -1090,7 +1198,7 @@ void CookieMonster::DeleteCookie(const GURL& url,
options.set_include_httponly();
// Get the cookies for this host and its domain(s).
std::vector<CanonicalCookie*> cookies;
- FindCookiesForHostAndDomain(url, options, &cookies);
+ FindCookiesForHostAndDomain(url, options, true, &cookies);
std::set<CanonicalCookie*> matching_cookies;
for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
@@ -1127,9 +1235,19 @@ CookieMonster::CookieList CookieMonster::GetAllCookies() {
CookieMapItPair(cookies_.begin(), cookies_.end()),
NULL);
- CookieList cookie_list;
+ // Copy the CanonicalCookie pointers from the map so that we can use the same
+ // sorter as elsewhere, then copy the result out.
+ std::vector<CanonicalCookie*> cookie_ptrs;
+ cookie_ptrs.reserve(cookies_.size());
for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end(); ++it)
- cookie_list.push_back(*it->second);
+ cookie_ptrs.push_back(it->second);
+ std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
+
+ CookieList cookie_list;
+ cookie_list.reserve(cookie_ptrs.size());
+ for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
+ it != cookie_ptrs.end(); ++it)
+ cookie_list.push_back(**it);
return cookie_list;
}
@@ -1138,12 +1256,25 @@ CookieMonster::CookieList CookieMonster::GetAllCookiesForURL(const GURL& url) {
AutoLock autolock(lock_);
InitIfNecessary();
- return InternalGetAllCookiesForURL(url);
+ 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);
+
+ CookieList cookies;
+ for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
+ it != cookie_ptrs.end(); it++)
+ cookies.push_back(**it);
+
+ return cookies;
}
void CookieMonster::FindCookiesForHostAndDomain(
const GURL& url,
const CookieOptions& options,
+ bool update_access_time,
std::vector<CanonicalCookie*>* cookies) {
lock_.AssertAcquired();
@@ -1154,27 +1285,39 @@ void CookieMonster::FindCookiesForHostAndDomain(
// want to collect statistics whenever the browser's being used.
RecordPeriodicStats(current_time);
- // Query for the full host, For example: 'a.c.blah.com'.
- std::string key(url.host());
- FindCookiesForKey(key, url, options, current_time, cookies);
-
- // See if we can search for domain cookies, i.e. if the host has a TLD + 1.
- const std::string domain(GetEffectiveDomain(url.scheme(), key));
- if (domain.empty())
- return;
- DCHECK_LE(domain.length(), key.length());
- DCHECK_EQ(0, key.compare(key.length() - domain.length(), domain.length(),
- domain));
-
- // Walk through the string and query at the dot points (GURL should have
- // canonicalized the dots, so this should be safe). Stop once we reach the
- // domain + registry; we can't write cookies past this point, and with some
- // registrars other domains can, in which case we don't want to read their
- // cookies.
- for (key = "." + key; key.length() > domain.length(); ) {
- FindCookiesForKey(key, url, options, current_time, cookies);
- const size_t next_dot = key.find('.', 1); // Skip over leading dot.
- key.erase(0, next_dot);
+ if (use_effective_domain_key_scheme_) {
+ // Can just dispatch to FindCookiesForKey
+ const std::string key(GetKey(url.host()));
+ FindCookiesForKey(key, url, options, current_time,
+ update_access_time, cookies);
+ } else {
+ // Need to probe for all domains that might have relevant
+ // cookies for us.
+
+ // Query for the full host, For example: 'a.c.blah.com'.
+ std::string key(GetKey(url.host()));
+ FindCookiesForKey(key, url, options, current_time, update_access_time,
+ cookies);
+
+ // See if we can search for domain cookies, i.e. if the host has a TLD + 1.
+ const std::string domain(GetEffectiveDomain(url.scheme(), key));
+ if (domain.empty())
+ return;
+ DCHECK_LE(domain.length(), key.length());
+ DCHECK_EQ(0, key.compare(key.length() - domain.length(), domain.length(),
+ domain));
+
+ // Walk through the string and query at the dot points (GURL should have
+ // canonicalized the dots, so this should be safe). Stop once we reach the
+ // domain + registry; we can't write cookies past this point, and with some
+ // registrars other domains can, in which case we don't want to read their
+ // cookies.
+ for (key = "." + key; key.length() > domain.length(); ) {
+ FindCookiesForKey(key, url, options, current_time, update_access_time,
+ cookies);
+ const size_t next_dot = key.find('.', 1); // Skip over leading dot.
+ key.erase(0, next_dot);
+ }
}
}
@@ -1183,9 +1326,12 @@ void CookieMonster::FindCookiesForKey(
const GURL& url,
const CookieOptions& options,
const Time& current,
+ bool update_access_time,
std::vector<CanonicalCookie*>* cookies) {
lock_.AssertAcquired();
+ const std::string scheme(url.scheme());
+ const std::string host(url.host());
bool secure = url.SchemeIsSecure();
for (CookieMapItPair its = cookies_.equal_range(key);
@@ -1208,67 +1354,20 @@ void CookieMonster::FindCookiesForKey(
if (!secure && cc->IsSecure())
continue;
- if (!cc->IsOnPath(url.path()))
+ // Filter out cookies that don't apply to this domain.
+ if (use_effective_domain_key_scheme_ && !cc->IsDomainMatch(scheme, host))
continue;
- // Add this cookie to the set of matching cookies. Since we're reading the
- // cookie, update its last access time.
- InternalUpdateCookieAccessTime(cc);
- cookies->push_back(cc);
- }
-}
-
-void CookieMonster::FindRawCookies(const std::string& key,
- bool include_secure,
- const std::string& path,
- CookieList* list) {
- lock_.AssertAcquired();
-
- for (CookieMapItPair its = cookies_.equal_range(key);
- its.first != its.second; ++its.first) {
- CanonicalCookie* cc = its.first->second;
- if (!include_secure && cc->IsSecure())
- continue;
- if (!cc->IsOnPath(path))
+ if (!cc->IsOnPath(url.path()))
continue;
- list->push_back(*cc);
- }
-}
-
-CookieMonster::CookieList CookieMonster::InternalGetAllCookiesForURL(
- const GURL& url) {
- lock_.AssertAcquired();
-
- // Do not return removed cookies.
- GarbageCollectExpired(Time::Now(),
- CookieMapItPair(cookies_.begin(), cookies_.end()),
- NULL);
-
- CookieList cookie_list;
- if (!HasCookieableScheme(url))
- return cookie_list;
- bool secure = url.SchemeIsSecure();
-
- // Query for the full host, For example: 'a.c.blah.com'.
- std::string key(url.host());
- FindRawCookies(key, secure, url.path(), &cookie_list);
-
- // See if we can search for domain cookies, i.e. if the host has a TLD + 1.
- const std::string domain(GetEffectiveDomain(url.scheme(), key));
- if (domain.empty())
- return cookie_list;
-
- // Use same logic as in FindCookiesForHostAndDomain.
- DCHECK_LE(domain.length(), key.length());
- DCHECK_EQ(0, key.compare(key.length() - domain.length(), domain.length(),
- domain));
- for (key = "." + key; key.length() > domain.length(); ) {
- FindRawCookies(key, secure, url.path(), &cookie_list);
- const size_t next_dot = key.find('.', 1); // Skip over leading dot.
- key.erase(0, next_dot);
+ // Add this cookie to the set of matching cookies. Update the access
+ // time if we've been requested to do so.
+ if (update_access_time) {
+ InternalUpdateCookieAccessTime(cc, current);
+ }
+ cookies->push_back(cc);
}
- return cookie_list;
}
// Test to see if stats should be recorded, and record them if so.
@@ -1283,12 +1382,47 @@ void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
const base::TimeDelta kRecordStatisticsIntervalTime(
base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
- if (current_time - last_statistic_record_time_ >
+ // If we've taken statistics recently, return.
+ if (current_time - last_statistic_record_time_ <=
kRecordStatisticsIntervalTime) {
- // See InitializeHistograms() for details.
- histogram_count_->Add(cookies_.size());
- last_statistic_record_time_ = current_time;
+ return;
}
+
+ // See InitializeHistograms() for details.
+ histogram_count_->Add(cookies_.size());
+
+ // More detailed statistics on cookie counts at different granularities.
+ TimeTicks beginning_of_time(TimeTicks::Now());
+
+ for (CookieMap::const_iterator it_key = cookies_.begin();
+ it_key != cookies_.end(); ) {
+ const std::string& key(it_key->first);
+
+ int key_count = 0;
+ typedef std::map<std::string, unsigned int> DomainMap;
+ DomainMap domain_map;
+ CookieMapItPair its_cookies = cookies_.equal_range(key);
+ while (its_cookies.first != its_cookies.second) {
+ key_count++;
+ const std::string& cookie_domain(its_cookies.first->second->Domain());
+ domain_map[cookie_domain]++;
+
+ its_cookies.first++;
+ }
+ histogram_etldp1_count_->Add(key_count);
+ histogram_domain_per_etldp1_count_->Add(domain_map.size());
+ for (DomainMap::const_iterator domain_map_it = domain_map.begin();
+ domain_map_it != domain_map.end(); domain_map_it++)
+ histogram_domain_count_->Add(domain_map_it->second);
+
+ it_key = its_cookies.second;
+ }
+
+ DLOG(INFO) << "Time for recording cookie stats (us): "
+ << (TimeTicks::Now() - beginning_of_time).InMicroseconds()
+ << std::endl;
+
+ last_statistic_record_time_ = current_time;
}
CookieMonster::ParsedCookie::ParsedCookie(const std::string& cookie_line)
@@ -1566,6 +1700,31 @@ std::string CookieMonster::ParsedCookie::DebugString() const {
return out;
}
+CookieMonster::CanonicalCookie::CanonicalCookie() {
+}
+
+CookieMonster::CanonicalCookie::CanonicalCookie(const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ bool secure,
+ bool httponly,
+ const base::Time& creation,
+ const base::Time& last_access,
+ bool has_expires,
+ const base::Time& expires)
+ : name_(name),
+ value_(value),
+ domain_(domain),
+ path_(path),
+ creation_date_(creation),
+ last_access_date_(last_access),
+ expiry_date_(expires),
+ has_expires_(has_expires),
+ secure_(secure),
+ httponly_(httponly) {
+}
+
CookieMonster::CanonicalCookie::CanonicalCookie(const GURL& url,
const ParsedCookie& pc)
: name_(pc.Name()),
@@ -1586,13 +1745,30 @@ CookieMonster::CanonicalCookie::CanonicalCookie(const GURL& url,
domain_string = pc.Domain();
}
bool result
- = GetCookieDomainKeyWithString(url, domain_string,
- &cookie_domain);
+ = GetCookieDomainWithString(url, domain_string,
+ &cookie_domain);
// Caller is responsible for passing in good arguments.
DCHECK(result);
domain_ = cookie_domain;
}
+CookieMonster::CookieMonster(PersistentCookieStore* store,
+ Delegate* delegate,
+ int last_access_threshold_milliseconds)
+ : initialized_(false),
+ use_effective_domain_key_scheme_(use_effective_domain_key_default_),
+ store_(store),
+ last_access_threshold_(base::TimeDelta::FromMilliseconds(
+ last_access_threshold_milliseconds)),
+ delegate_(delegate),
+ last_statistic_record_time_(base::Time::Now()) {
+ InitializeHistograms();
+ SetDefaultCookieableSchemes();
+}
+
+CookieMonster::CanonicalCookie::~CanonicalCookie() {
+}
+
CookieMonster::CanonicalCookie* CookieMonster::CanonicalCookie::Create(
const GURL& url, const std::string& name, const std::string& value,
const std::string& domain, const std::string& path,
@@ -1611,8 +1787,8 @@ CookieMonster::CanonicalCookie* CookieMonster::CanonicalCookie::Create(
if (parsed_domain != domain)
return NULL;
std::string cookie_domain;
- if (!GetCookieDomainKeyWithString(url, parsed_domain, &cookie_domain))
- return false;
+ if (!GetCookieDomainWithString(url, parsed_domain, &cookie_domain))
+ return NULL;
std::string parsed_path = ParsedCookie::ParseValueString(path);
if (parsed_path != path)
@@ -1673,12 +1849,48 @@ bool CookieMonster::CanonicalCookie::IsOnPath(
return true;
}
+bool CookieMonster::CanonicalCookie::IsDomainMatch(
+ const std::string& scheme,
+ const std::string& host) const {
+ // Can domain match in two ways; as a domain cookie (where the cookie
+ // domain begins with ".") or as a host cookie (where it doesn't).
+
+ // Some consumers of the CookieMonster expect to set cookies on
+ // URLs like http://.strange.url. To retrieve cookies in this instance,
+ // we allow matching as a host cookie even when the domain_ starts with
+ // a period.
+ if (host == domain_)
+ return true;
+
+ // Domain cookie must have an initial ".". To match, it must be
+ // equal to url's host with initial period removed, or a suffix of
+ // it.
+
+ // Arguably this should only apply to "http" or "https" cookies, but
+ // extension cookie tests currently use the funtionality, and if we
+ // ever decide to implement that it should be done by preventing
+ // such cookies from being set.
+ if (domain_.empty() || domain_[0] != '.')
+ return false;
+
+ // The host with a "." prefixed.
+ if (domain_.compare(1, std::string::npos, host) == 0)
+ return true;
+
+ // A pure suffix of the host (ok since we know the domain already
+ // starts with a ".")
+ return (host.length() > domain_.length() &&
+ host.compare(host.length() - domain_.length(),
+ domain_.length(), domain_) == 0);
+}
+
std::string CookieMonster::CanonicalCookie::DebugString() const {
- return StringPrintf("name: %s value: %s domain: %s path: %s creation: %"
- PRId64,
- name_.c_str(), value_.c_str(),
- domain_.c_str(), path_.c_str(),
- static_cast<int64>(creation_date_.ToTimeT()));
+ return base::StringPrintf(
+ "name: %s value: %s domain: %s path: %s creation: %"
+ PRId64,
+ name_.c_str(), value_.c_str(),
+ domain_.c_str(), path_.c_str(),
+ static_cast<int64>(creation_date_.ToTimeT()));
}
} // namespace
diff --git a/net/base/cookie_monster.h b/net/base/cookie_monster.h
index 623363f..8063876 100644
--- a/net/base/cookie_monster.h
+++ b/net/base/cookie_monster.h
@@ -6,6 +6,7 @@
#ifndef NET_BASE_COOKIE_MONSTER_H_
#define NET_BASE_COOKIE_MONSTER_H_
+#pragma once
#include <map>
#include <string>
@@ -13,7 +14,7 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/histogram.h"
+#include "base/gtest_prod_util.h"
#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
@@ -21,6 +22,7 @@
#include "net/base/cookie_store.h"
class GURL;
+class Histogram;
namespace net {
@@ -41,6 +43,42 @@ class CookieMonster : public CookieStore {
class ParsedCookie;
class PersistentCookieStore;
+ // Terminology:
+ // * The 'top level domain' (TLD) of an internet domain name is
+ // the terminal "." free substring (e.g. "com" for google.com
+ // or world.std.com).
+ // * The 'effective top level domain' (eTLD) is the longest
+ // "." initiated terminal substring of an internet domain name
+ // that is controlled by a general domain registrar.
+ // (e.g. "co.uk" for news.bbc.co.uk).
+ // * The 'effective top level domain plus one' (eTLD+1) is the
+ // shortest "." delimited terminal substring of an internet
+ // domain name that is not controlled by a general domain
+ // registrar (e.g. "bbc.co.uk" for news.bbc.co.uk, or
+ // "google.com" for news.google.com). The general assumption
+ // is that all hosts and domains under an eTLD+1 share some
+ // administrative control.
+
+ // CookieMap is the central data structure of the CookieMonster. It
+ // is a map whose values are pointers to CanonicalCookie data
+ // structures (the data structures are owned by the CookieMonster
+ // and must be destroyed when removed from the map). There are two
+ // possible keys for the map, controlled on a per-CookieMonster basis
+ // by use_effective_domain_key_scheme_/SetKeyScheme()
+ // (defaulted by use_effective_domain_key_default_):
+
+ // If use_effective_domain_key_scheme_ is true (default), then the key is
+ // based on the effective domain of the cookies. If the domain
+ // of the cookie has an eTLD+1, that is the key for the map. If the
+ // domain of the cookie does not have an eTLD+1, the key of the map
+ // is the host the cookie applies to (it is not legal to have domain
+ // cookies without an eTLD+1). This rule excludes cookies for,
+ // e.g, ".com", ".co.uk", or ".internalnetwork".
+
+ // If use_effective_domain_key_scheme_ is false, then the key is
+ // just the domain of the cookie. Eventually, this option will be
+ // removed.
+
// NOTE(deanm):
// I benchmarked hash_multimap vs multimap. We're going to be query-heavy
// so it would seem like hashing would help. However they were very
@@ -48,9 +86,10 @@ class CookieMonster : public CookieStore {
// our map is at max around 1000 entries, and the additional complexity
// for the hashing might not overcome the O(log(1000)) for querying
// a multimap. Also, multimap is standard, another reason to use it.
+ // TODO(rdsmith): This benchmark should be re-done now that we're allowing
+ // subtantially more entries in the map.
typedef std::multimap<std::string, CanonicalCookie*> CookieMap;
typedef std::pair<CookieMap::iterator, CookieMap::iterator> CookieMapItPair;
- typedef std::pair<std::string, CanonicalCookie*> KeyedCanonicalCookie;
typedef std::vector<CanonicalCookie> CookieList;
// The store passed in should not have had Init() called on it yet. This
@@ -61,22 +100,12 @@ class CookieMonster : public CookieStore {
// creation/deletion of cookies.
CookieMonster(PersistentCookieStore* store, Delegate* delegate);
-#ifdef UNIT_TEST
+ // Only used during unit testing.
CookieMonster(PersistentCookieStore* store,
Delegate* delegate,
- int last_access_threshold_milliseconds)
- : initialized_(false),
- store_(store),
- last_access_threshold_(base::TimeDelta::FromMilliseconds(
- last_access_threshold_milliseconds)),
- delegate_(delegate),
- last_statistic_record_time_(base::Time::Now()) {
- InitializeHistograms();
- SetDefaultCookieableSchemes();
- }
-#endif
+ int last_access_threshold_milliseconds);
- // Parse the string with the cookie time (very forgivingly).
+ // Parses the string with the cookie time (very forgivingly).
static base::Time ParseCookieTime(const std::string& time_string);
// Returns true if a domain string represents a host-only cookie,
@@ -84,12 +113,22 @@ class CookieMonster : public CookieStore {
static bool DomainIsHostOnly(const std::string& domain_string);
// CookieStore implementation.
+
+ // Sets the cookies specified by |cookie_list| returned from |url|
+ // with options |options| in effect.
virtual bool SetCookieWithOptions(const GURL& url,
const std::string& cookie_line,
const CookieOptions& options);
+
+ // Gets all cookies that apply to |url| given |options|.
+ // The returned cookies are ordered by longest path, then earliest
+ // creation date.
virtual std::string GetCookiesWithOptions(const GURL& url,
const CookieOptions& options);
+
+ // 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; }
// Sets a cookie given explicit user-provided cookie attributes. The cookie
@@ -106,56 +145,50 @@ class CookieMonster : public CookieStore {
const base::Time& expiration_time,
bool secure, bool http_only);
- // Exposed for unit testing.
- bool SetCookieWithCreationTimeAndOptions(const GURL& url,
- const std::string& cookie_line,
- const base::Time& creation_time,
- const CookieOptions& options);
- bool SetCookieWithCreationTime(const GURL& url,
- const std::string& cookie_line,
- const base::Time& creation_time) {
- return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time,
- CookieOptions());
- }
-
// Returns all the cookies, for use in management UI, etc. This does not mark
// the cookies as having been accessed.
+ // The returned cookies are ordered by longest path, then by earliest
+ // creation date.
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.
+ // The returned cookies are ordered by longest path, then earliest
+ // creation date.
CookieList GetAllCookiesForURL(const GURL& url);
- // Delete all of the cookies.
+ // Deletes all of the cookies.
int DeleteAll(bool sync_to_store);
- // Delete all of the cookies that have a creation_date greater than or equal
+ // Deletes all of the cookies that have a creation_date greater than or equal
// to |delete_begin| and less than |delete_end|
int DeleteAllCreatedBetween(const base::Time& delete_begin,
const base::Time& delete_end,
bool sync_to_store);
- // Delete all of the cookies that have a creation_date more recent than the
+ // Deletes all of the cookies that have a creation_date more recent than the
// one passed into the function via |delete_after|.
int DeleteAllCreatedAfter(const base::Time& delete_begin, bool sync_to_store);
- // Delete all cookies that match the host of the given URL
+ // Deletes all cookies that match the host of the given URL
// regardless of path. This includes all http_only and secure cookies,
// but does not include any domain cookies that may apply to this host.
// Returns the number of cookies deleted.
int DeleteAllForHost(const GURL& url);
- // Delete one specific cookie.
- bool DeleteCookie(const std::string& domain,
- const CanonicalCookie& cookie,
- bool sync_to_store);
+ // Deletes one specific cookie.
+ bool DeleteCanonicalCookie(const CanonicalCookie& cookie);
// Override the default list of schemes that are allowed to be set in
// this cookie store. Calling his overrides the value of
// "enable_file_scheme_".
// If this this method is called, it must be called before first use of
- // the instance (i.e. as part of the instance initialization process.)
+ // the instance (i.e. as part of the instance initialization process).
void SetCookieableSchemes(const char* schemes[], size_t num_schemes);
+ // Overrides the default key scheme. This function must be called
+ // before initialization.
+ void SetKeyScheme(bool use_effective_domain_key);
+
// 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.
@@ -166,6 +199,50 @@ class CookieMonster : public CookieStore {
private:
~CookieMonster();
+ // Testing support.
+ // For SetCookieWithCreationTime.
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest,
+ TestCookieDeleteAllCreatedAfterTimestamp);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest,
+ TestCookieDeleteAllCreatedBetweenTimestamps);
+
+ // For gargage collection constants.
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestHostGarbageCollection);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestTotalGarbageCollection);
+
+ // For validation of key values.
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestDomainTree);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestImport);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, GetKey);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestGetKey);
+
+ // Cookie garbage collection thresholds. Based off of the Mozilla defaults.
+ // When the number of cookies gets to k{Domain,}MaxCookies
+ // purge down to k{Domain,}MaxCookies - k{Domain,}PurgeCookies.
+ // It might seem scary to have a high purge value, but really it's not.
+ // You just make sure that you increase the max to cover the increase
+ // in purge, and we would have been purging the same amount of cookies.
+ // We're just going through the garbage collection process less often.
+ // Note that the DOMAIN values are per eTLD+1; see comment for the
+ // CookieMap typedef. So, e.g., the maximum number of cookies allowed for
+ // google.com and all of its subdomains will be 150-180.
+ //
+ // Present in .h file to make accessible to tests through FRIEND_TEST.
+ // Actual definitions are in cookie_monster.cc.
+ static const size_t kDomainMaxCookies;
+ static const size_t kDomainPurgeCookies;
+ static const size_t kMaxCookies;
+ static const size_t kPurgeCookies;
+
+ // Default value for key scheme. true means to use the new
+ // key scheme based on effective domain; false to use the
+ // old key scheme based on full domain.
+ static const bool use_effective_domain_key_default_ = true;
+
+ bool SetCookieWithCreationTime(const GURL& url,
+ const std::string& cookie_line,
+ const base::Time& creation_time);
+
// Called by all non-static functions to ensure that the cookies store has
// been initialized. This is not done during creating so it doesn't block
// the window showing.
@@ -186,54 +263,59 @@ class CookieMonster : public CookieStore {
// inconsistencies. (In other words, it does not have duplicate cookies).
void EnsureCookiesMapIsValid();
- // Checks for any duplicate cookies for host |key|, which lie between
+ // Checks for any duplicate cookies for CookieMap key |key| which lie between
// |begin| and |end|. If any are found, all but the most recent are deleted.
// Returns the number of duplicate cookies that were deleted.
- int TrimDuplicateCookiesForHost(const std::string& key,
- CookieMap::iterator begin,
- CookieMap::iterator end);
+ int TrimDuplicateCookiesForKey(const std::string& key,
+ CookieMap::iterator begin,
+ CookieMap::iterator end);
void SetDefaultCookieableSchemes();
void FindCookiesForHostAndDomain(const GURL& url,
const CookieOptions& options,
+ bool update_access_time,
std::vector<CanonicalCookie*>* cookies);
void FindCookiesForKey(const std::string& key,
const GURL& url,
const CookieOptions& options,
const base::Time& current,
+ bool update_access_time,
std::vector<CanonicalCookie*>* cookies);
- void FindRawCookies(const std::string& key,
- bool include_secure,
- const std::string& path,
- CookieList* list);
-
- // Internal helper returning all cookies for a given URL. The caller is
- // assumed to hold lock_ and having called InitIfNecessary().
- CookieList InternalGetAllCookiesForURL(const GURL& url);
-
- // Delete any cookies that are equivalent to |ecc| (same path, key, etc).
+ // Delete any cookies that are equivalent to |ecc| (same path, domain, etc).
// If |skip_httponly| is true, httponly cookies will not be deleted. The
// return value with be true if |skip_httponly| skipped an httponly cookie.
+ // |key| is the key to find the cookie in cookies_; see the comment before
+ // the CookieMap typedef for details.
// NOTE: There should never be more than a single matching equivalent cookie.
bool DeleteAnyEquivalentCookie(const std::string& key,
const CanonicalCookie& ecc,
bool skip_httponly);
+ // Takes ownership of *cc.
void InternalInsertCookie(const std::string& key,
CanonicalCookie* cc,
bool sync_to_store);
+ // Helper function that sets cookies with more control.
+ // Not exposed as we don't want callers to have the ability
+ // to specify (potentially duplicate) creation times.
+ bool SetCookieWithCreationTimeAndOptions(const GURL& url,
+ const std::string& cookie_line,
+ const base::Time& creation_time,
+ const CookieOptions& options);
+
+
// Helper function that sets a canonical cookie, deleting equivalents and
// performing garbage collection.
bool SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc,
- const std::string& cookie_domain,
const base::Time& creation_time,
const CookieOptions& options);
- void InternalUpdateCookieAccessTime(CanonicalCookie* cc);
+ void InternalUpdateCookieAccessTime(CanonicalCookie* cc,
+ const base::Time& current_time);
enum DeletionCause {
DELETE_COOKIE_EXPLICIT,
@@ -241,33 +323,23 @@ class CookieMonster : public CookieStore {
DELETE_COOKIE_EXPIRED,
DELETE_COOKIE_EVICTED,
DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE,
- DELETE_COOKIE_DONT_RECORD,
- DELETE_COOKIE_LAST_ENTRY = DELETE_COOKIE_DONT_RECORD
+ DELETE_COOKIE_DONT_RECORD, // e.g. For final cleanup after flush to store.
+ DELETE_COOKIE_EVICTED_DOMAIN,
+ DELETE_COOKIE_EVICTED_GLOBAL,
+ DELETE_COOKIE_LAST_ENTRY = DELETE_COOKIE_EVICTED_GLOBAL
};
// |deletion_cause| argument is for collecting statistics.
void InternalDeleteCookie(CookieMap::iterator it, bool sync_to_store,
DeletionCause deletion_cause);
- // If the number of cookies for host |key|, or globally, are over preset
- // maximums, garbage collects, first for the host and then globally, as
- // described by GarbageCollectRange(). The limits can be found as constants
- // at the top of the function body.
+ // If the number of cookies for CookieMap key |key|, or globally, are
+ // over the preset maximums above, garbage collect, first for the host and
+ // then globally, as described by GarbageCollectRange().
//
// Returns the number of cookies deleted (useful for debugging).
int GarbageCollect(const base::Time& current, const std::string& key);
- // Deletes all expired cookies in |itpair|;
- // then, if the number of remaining cookies is greater than |num_max|,
- // collects the least recently accessed cookies until
- // (|num_max| - |num_purge|) cookies remain.
- //
- // Returns the number of cookies deleted.
- int GarbageCollectRange(const base::Time& current,
- const CookieMapItPair& itpair,
- size_t num_max,
- size_t num_purge);
-
// Helper for GarbageCollectRange(); can be called directly as well. Deletes
// all expired cookies in |itpair|. If |cookie_its| is non-NULL, it is
// populated with all the non-expired cookies from |itpair|.
@@ -277,6 +349,19 @@ class CookieMonster : public CookieStore {
const CookieMapItPair& itpair,
std::vector<CookieMap::iterator>* cookie_its);
+ // If needed, evicts least recently accessed cookies in iterator
+ // list until (|num_max| - |num_purge|) cookies remain.
+ int GarbageCollectEvict(
+ const base::Time& current,
+ size_t num_max,
+ size_t num_purge,
+ DeletionCause cause,
+ std::vector<CookieMap::iterator>* cookie_its);
+
+ // Find the key (for lookup in cookies_) based on the given domain.
+ // See comment on keys before the CookieMap typedef.
+ std::string GetKey(const std::string& domain) const;
+
bool HasCookieableScheme(const GURL& url);
// Statistics support
@@ -293,8 +378,13 @@ class CookieMonster : public CookieStore {
scoped_refptr<Histogram> histogram_between_access_interval_minutes_;
scoped_refptr<Histogram> histogram_evicted_last_access_minutes_;
scoped_refptr<Histogram> histogram_count_;
+ scoped_refptr<Histogram> histogram_domain_count_;
+ scoped_refptr<Histogram> histogram_etldp1_count_;
+ scoped_refptr<Histogram> histogram_domain_per_etldp1_count_;
scoped_refptr<Histogram> histogram_number_duplicate_db_cookies_;
scoped_refptr<Histogram> histogram_cookie_deletion_cause_;
+ scoped_refptr<Histogram> histogram_time_get_;
+ scoped_refptr<Histogram> histogram_time_load_;
// Initialize the above variables; should only be called from
// the constructor.
@@ -306,6 +396,10 @@ class CookieMonster : public CookieStore {
// lazily in InitStoreIfNecessary().
bool initialized_;
+ // Indicates whether this cookie monster uses the new effective domain
+ // key scheme or not.
+ bool use_effective_domain_key_scheme_;
+
scoped_refptr<PersistentCookieStore> store_;
// The resolution of our time isn't enough, so we do something
@@ -336,7 +430,7 @@ class CookieMonster::CanonicalCookie {
// the resulting CanonicalCookies should not be relied on to be canonical
// unless the caller has done appropriate validation and canonicalization
// themselves.
- CanonicalCookie() { }
+ CanonicalCookie();
CanonicalCookie(const std::string& name,
const std::string& value,
const std::string& domain,
@@ -346,24 +440,15 @@ class CookieMonster::CanonicalCookie {
const base::Time& creation,
const base::Time& last_access,
bool has_expires,
- const base::Time& expires)
- : name_(name),
- value_(value),
- domain_(domain),
- path_(path),
- creation_date_(creation),
- last_access_date_(last_access),
- expiry_date_(expires),
- has_expires_(has_expires),
- secure_(secure),
- httponly_(httponly) {
- }
+ const base::Time& expires);
// This constructor does canonicalization but not validation.
// The result of this constructor should not be relied on in contexts
// in which pre-validation of the ParsedCookie has not been done.
CanonicalCookie(const GURL& url, const ParsedCookie& pc);
+ ~CanonicalCookie();
+
// Supports the default copy constructor.
// Creates a canonical cookie from unparsed attribute values.
@@ -386,6 +471,9 @@ class CookieMonster::CanonicalCookie {
const base::Time& ExpiryDate() const { return expiry_date_; }
bool IsSecure() const { return secure_; }
bool IsHttpOnly() const { return httponly_; }
+ bool IsDomainCookie() const {
+ return !domain_.empty() && domain_[0] == '.'; }
+ bool IsHostCookie() const { return !IsDomainCookie(); }
bool IsExpired(const base::Time& current) {
return has_expires_ && current >= expiry_date_;
@@ -396,7 +484,7 @@ class CookieMonster::CanonicalCookie {
// match (case insensitive), and path must match (case sensitive).
// For the case insensitive domain compare, we rely on the domain
// having been canonicalized (in
- // GetCookieDomainKeyWithString->CanonicalizeHost).
+ // GetCookieDomainWithString->CanonicalizeHost).
bool IsEquivalent(const CanonicalCookie& ecc) const {
// It seems like it would make sense to take secure and httponly into
// account, but the RFC doesn't specify this.
@@ -410,6 +498,7 @@ class CookieMonster::CanonicalCookie {
}
bool IsOnPath(const std::string& url_path) const;
+ bool IsDomainMatch(const std::string& scheme, const std::string& host) const;
std::string DebugString() const;
private:
@@ -541,9 +630,9 @@ class CookieMonster::PersistentCookieStore
// Initializes the store and retrieves the existing cookies. This will be
// called only once at startup.
- virtual bool Load(std::vector<CookieMonster::KeyedCanonicalCookie>*) = 0;
+ virtual bool Load(std::vector<CookieMonster::CanonicalCookie*>*) = 0;
- virtual void AddCookie(const std::string&, const CanonicalCookie&) = 0;
+ virtual void AddCookie(const CanonicalCookie&) = 0;
virtual void UpdateCookieAccessTime(const CanonicalCookie&) = 0;
virtual void DeleteCookie(const CanonicalCookie&) = 0;
diff --git a/net/base/cookie_monster_perftest.cc b/net/base/cookie_monster_perftest.cc
index 3d1e7a7..5326654 100644
--- a/net/base/cookie_monster_perftest.cc
+++ b/net/base/cookie_monster_perftest.cc
@@ -1,12 +1,14 @@
-// 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/perftimer.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "googleurl/src/gurl.h"
#include "net/base/cookie_monster.h"
+#include "net/base/cookie_monster_store_test.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "googleurl/src/gurl.h"
namespace {
class ParsedCookieTest : public testing::Test { };
@@ -16,11 +18,13 @@ namespace {
static const int kNumCookies = 20000;
static const char kCookieLine[] = "A = \"b=;\\\"\" ;secure;;;";
+namespace net {
+
TEST(ParsedCookieTest, TestParseCookies) {
std::string cookie(kCookieLine);
PerfTimeLogger timer("Parsed_cookie_parse_cookies");
for (int i = 0; i < kNumCookies; ++i) {
- net::CookieMonster::ParsedCookie pc(cookie);
+ CookieMonster::ParsedCookie pc(cookie);
EXPECT_TRUE(pc.IsValid());
}
timer.Done();
@@ -31,7 +35,7 @@ TEST(ParsedCookieTest, TestParseBigCookies) {
cookie += kCookieLine;
PerfTimeLogger timer("Parsed_cookie_parse_big_cookies");
for (int i = 0; i < kNumCookies; ++i) {
- net::CookieMonster::ParsedCookie pc(cookie);
+ CookieMonster::ParsedCookie pc(cookie);
EXPECT_TRUE(pc.IsValid());
}
timer.Done();
@@ -40,10 +44,10 @@ TEST(ParsedCookieTest, TestParseBigCookies) {
static const GURL kUrlGoogle("http://www.google.izzle");
TEST(CookieMonsterTest, TestAddCookiesOnSingleHost) {
- scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
+ scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
std::vector<std::string> cookies;
for (int i = 0; i < kNumCookies; i++) {
- cookies.push_back(StringPrintf("a%03d=b", i));
+ cookies.push_back(base::StringPrintf("a%03d=b", i));
}
// Add a bunch of cookies on a single host
@@ -67,11 +71,11 @@ TEST(CookieMonsterTest, TestAddCookiesOnSingleHost) {
}
TEST(CookieMonsterTest, TestAddCookieOnManyHosts) {
- scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
+ scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
std::string cookie(kCookieLine);
std::vector<GURL> gurls; // just wanna have ffffuunnn
for (int i = 0; i < kNumCookies; ++i) {
- gurls.push_back(GURL(StringPrintf("http://a%04d.izzle", i)));
+ gurls.push_back(GURL(base::StringPrintf("http://a%04d.izzle", i)));
}
// Add a cookie on a bunch of host
@@ -94,49 +98,69 @@ TEST(CookieMonsterTest, TestAddCookieOnManyHosts) {
timer3.Done();
}
+static int CountInString(const std::string& str, char c) {
+ return std::count(str.begin(), str.end(), c);
+}
+
TEST(CookieMonsterTest, TestDomainTree) {
- scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
- std::string cookie(kCookieLine);
- std::string domain_base("top.com");
+ scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
+ const char* domain_cookie_format_tree = "a=b; domain=%s";
+ const std::string domain_base("top.com");
- std::vector<GURL> gurl_list;
+ std::vector<std::string> domain_list;
// Create a balanced binary tree of domains on which the cookie is set.
- for (int i1=0; i1 < 2; i1++) {
+ domain_list.push_back(domain_base);
+ for (int i1 = 0; i1 < 2; i1++) {
std::string domain_base_1((i1 ? "a." : "b.") + domain_base);
- gurl_list.push_back(GURL(StringPrintf("http://%s",
- domain_base_1.c_str())));
- for (int i2=0; i2 < 2; i2++) {
- std::string domain_base_2((i1 ? "a." : "b.") + domain_base_1);
- gurl_list.push_back(GURL(StringPrintf("http://%s",
- domain_base_2.c_str())));
- for (int i3=0; i3 < 2; i3++) {
- std::string domain_base_3((i1 ? "a." : "b.") + domain_base_2);
- gurl_list.push_back(GURL(StringPrintf("http://%s",
- domain_base_3.c_str())));
- for (int i4=0; i4 < 2; i4++) {
- gurl_list.push_back(GURL(StringPrintf("http://%s.%s",
- i4 ? "a" : "b",
- domain_base_3.c_str())));
+ EXPECT_EQ("top.com", cm->GetKey(domain_base_1));
+ domain_list.push_back(domain_base_1);
+ for (int i2 = 0; i2 < 2; i2++) {
+ std::string domain_base_2((i2 ? "a." : "b.") + domain_base_1);
+ EXPECT_EQ("top.com", cm->GetKey(domain_base_2));
+ domain_list.push_back(domain_base_2);
+ for (int i3 = 0; i3 < 2; i3++) {
+ std::string domain_base_3((i3 ? "a." : "b.") + domain_base_2);
+ EXPECT_EQ("top.com", cm->GetKey(domain_base_3));
+ domain_list.push_back(domain_base_3);
+ for (int i4 = 0; i4 < 2; i4++) {
+ std::string domain_base_4((i4 ? "a." : "b.") + domain_base_3);
+ EXPECT_EQ("top.com", cm->GetKey(domain_base_4));
+ domain_list.push_back(domain_base_4);
}
}
}
}
- for (std::vector<GURL>::const_iterator it = gurl_list.begin();
- it != gurl_list.end(); it++) {
- EXPECT_TRUE(cm->SetCookie(*it, cookie));
+
+ EXPECT_EQ(31u, domain_list.size());
+ for (std::vector<std::string>::const_iterator it = domain_list.begin();
+ it != domain_list.end(); it++) {
+ GURL gurl("https://" + *it + "/");
+ const std::string cookie = base::StringPrintf(domain_cookie_format_tree,
+ it->c_str());
+ EXPECT_TRUE(cm->SetCookie(gurl, cookie));
}
+ EXPECT_EQ(31u, cm->GetAllCookies().size());
- GURL probe_gurl("http://b.a.b.a.top.com/");
+ GURL probe_gurl("https://b.a.b.a.top.com/");
+ std::string cookie_line;
+ cookie_line = cm->GetCookies(probe_gurl);
+ EXPECT_EQ(5, CountInString(cookie_line, '=')) << "Cookie line: "
+ << cookie_line;
PerfTimeLogger timer("Cookie_monster_query_domain_tree");
for (int i = 0; i < kNumCookies; i++) {
cm->GetCookies(probe_gurl);
}
timer.Done();
- cm->DeleteAll(false);
- gurl_list.clear();
+}
+
+TEST(CookieMonsterTest, TestDomainLine) {
+ scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
+ std::vector<std::string> domain_list;
+ GURL probe_gurl("https://b.a.b.a.top.com/");
+ std::string cookie_line;
// Create a line of 32 domain cookies such that all cookies stored
// by effective TLD+1 will apply to probe GURL.
@@ -144,20 +168,74 @@ TEST(CookieMonsterTest, TestDomainTree) {
// or "google.com". "Effective" is added to include sites like
// bbc.co.uk, where the effetive TLD+1 is more than one level
// below the top level.)
- gurl_list.push_back(GURL("http://a.top.com"));
- gurl_list.push_back(GURL("http://b.a.top.com"));
- gurl_list.push_back(GURL("http://a.b.a.top.com"));
- gurl_list.push_back(GURL("http://b.a.b.a.top.com"));
+ domain_list.push_back("a.top.com");
+ domain_list.push_back("b.a.top.com");
+ domain_list.push_back("a.b.a.top.com");
+ domain_list.push_back("b.a.b.a.top.com");
+ EXPECT_EQ(4u, domain_list.size());
+ const char* domain_cookie_format_line = "a%03d=b; domain=%s";
for (int i = 0; i < 8; i++) {
- for (std::vector<GURL>::const_iterator it = gurl_list.begin();
- it != gurl_list.end(); it++) {
- EXPECT_TRUE(cm->SetCookie(*it, StringPrintf("a%03d=b", i)));
+ for (std::vector<std::string>::const_iterator it = domain_list.begin();
+ it != domain_list.end(); it++) {
+ GURL gurl("https://" + *it + "/");
+ const std::string cookie = base::StringPrintf(domain_cookie_format_line,
+ i, it->c_str());
+ EXPECT_TRUE(cm->SetCookie(gurl, cookie));
}
}
+ EXPECT_EQ(32u, cm->GetAllCookies().size());
+
+ cookie_line = cm->GetCookies(probe_gurl);
+ EXPECT_EQ(32, CountInString(cookie_line, '='));
PerfTimeLogger timer2("Cookie_monster_query_domain_line");
for (int i = 0; i < kNumCookies; i++) {
cm->GetCookies(probe_gurl);
}
timer2.Done();
}
+
+TEST(CookieMonsterTest, TestImport) {
+ scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
+ std::vector<CookieMonster::CanonicalCookie*> initial_cookies;
+
+ // We want to setup a fairly large backing store, with 300 domains of 50
+ // cookies each. Creation times must be unique.
+ int64 time_tick(base::Time::Now().ToInternalValue());
+
+ for (int domain_num = 0; domain_num < 300; domain_num++) {
+ std::string domain_name(base::StringPrintf(".Domain_%d.com", domain_num));
+ std::string gurl("www" + domain_name);
+ for (int cookie_num = 0; cookie_num < 50; cookie_num++) {
+ std::string cookie_line(base::StringPrintf("Cookie_%d=1; Path=/",
+ cookie_num));
+ AddCookieToList(gurl, cookie_line,
+ base::Time::FromInternalValue(time_tick++),
+ &initial_cookies);
+ }
+ }
+
+ store->SetLoadExpectation(true, initial_cookies);
+
+ scoped_refptr<CookieMonster> cm(new CookieMonster(store, NULL));
+
+ // Import will happen on first access.
+ GURL gurl("www.google.com");
+ CookieOptions options;
+ PerfTimeLogger timer("Cookie_monster_import_from_store");
+ cm->GetCookiesWithOptions(gurl, options);
+ timer.Done();
+
+ // Just confirm keys were set as expected.
+ EXPECT_EQ("domain_1.com", cm->GetKey("www.Domain_1.com"));
+}
+
+TEST(CookieMonsterTest, TestGetKey) {
+ scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
+ PerfTimeLogger timer("Cookie_monster_get_key");
+ for (int i = 0; i < kNumCookies; i++)
+ cm->GetKey("www.google.com");
+ timer.Done();
+}
+
+} // namespace
diff --git a/net/base/cookie_monster_store_test.h b/net/base/cookie_monster_store_test.h
new file mode 100644
index 0000000..79d919f
--- /dev/null
+++ b/net/base/cookie_monster_store_test.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.
+
+// This file contains test infrastructure for multiple files
+// (current cookie_monster_unittest.cc and cookie_monster_perftest.cc)
+// that need to test out CookieMonster interactions with the backing store.
+// It should only be included by test code.
+
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Describes a call to one of the 3 functions of PersistentCookieStore.
+struct CookieStoreCommand {
+ enum Type {
+ ADD,
+ UPDATE_ACCESS_TIME,
+ REMOVE,
+ };
+
+ CookieStoreCommand(Type type,
+ const net::CookieMonster::CanonicalCookie& cookie)
+ : type(type),
+ cookie(cookie) {}
+
+ Type type;
+ net::CookieMonster::CanonicalCookie cookie;
+};
+
+// Implementation of PersistentCookieStore that captures the
+// received commands and saves them to a list.
+// The result of calls to Load() can be configured using SetLoadExpectation().
+class MockPersistentCookieStore
+ : public net::CookieMonster::PersistentCookieStore {
+ public:
+ typedef std::vector<CookieStoreCommand> CommandList;
+
+ MockPersistentCookieStore() : load_return_value_(true) {
+ }
+
+ virtual bool Load(
+ std::vector<net::CookieMonster::CanonicalCookie*>* out_cookies) {
+ bool ok = load_return_value_;
+ if (ok)
+ *out_cookies = load_result_;
+ return ok;
+ }
+
+ virtual void AddCookie(const net::CookieMonster::CanonicalCookie& cookie) {
+ commands_.push_back(
+ CookieStoreCommand(CookieStoreCommand::ADD, cookie));
+ }
+
+ virtual void UpdateCookieAccessTime(
+ const net::CookieMonster::CanonicalCookie& cookie) {
+ commands_.push_back(CookieStoreCommand(
+ CookieStoreCommand::UPDATE_ACCESS_TIME, cookie));
+ }
+
+ virtual void DeleteCookie(
+ const net::CookieMonster::CanonicalCookie& cookie) {
+ commands_.push_back(
+ CookieStoreCommand(CookieStoreCommand::REMOVE, cookie));
+ }
+
+ void SetLoadExpectation(
+ bool return_value,
+ const std::vector<net::CookieMonster::CanonicalCookie*>& result) {
+ load_return_value_ = return_value;
+ load_result_ = result;
+ }
+
+ const CommandList& commands() const {
+ return commands_;
+ }
+
+ private:
+ CommandList commands_;
+
+ // Deferred result to use when Load() is called.
+ bool load_return_value_;
+ std::vector<net::CookieMonster::CanonicalCookie*> load_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore);
+};
+
+// Mock for CookieMonster::Delegate
+class MockCookieMonsterDelegate : public net::CookieMonster::Delegate {
+ public:
+ typedef std::pair<net::CookieMonster::CanonicalCookie, bool>
+ CookieNotification;
+
+ MockCookieMonsterDelegate() {}
+
+ virtual void OnCookieChanged(
+ const net::CookieMonster::CanonicalCookie& cookie,
+ bool removed) {
+ CookieNotification notification(cookie, removed);
+ changes_.push_back(notification);
+ }
+
+ const std::vector<CookieNotification>& changes() const { return changes_; }
+
+ void reset() { changes_.clear(); }
+
+ private:
+ virtual ~MockCookieMonsterDelegate() {}
+
+ std::vector<CookieNotification> changes_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate);
+};
+
+// Helper to build a list of CanonicalCookie*s.
+static void AddCookieToList(
+ const std::string& key,
+ const std::string& cookie_line,
+ const base::Time& creation_time,
+ std::vector<net::CookieMonster::CanonicalCookie*>* out_list) {
+
+ // Parse the cookie line.
+ net::CookieMonster::ParsedCookie pc(cookie_line);
+ EXPECT_TRUE(pc.IsValid());
+
+ // This helper is simplistic in interpreting a parsed cookie, in order to
+ // avoid duplicated CookieMonster's CanonPath() and CanonExpiration()
+ // functions. Would be nice to export them, and re-use here.
+ EXPECT_FALSE(pc.HasMaxAge());
+ EXPECT_TRUE(pc.HasPath());
+ base::Time cookie_expires = pc.HasExpires() ?
+ net::CookieMonster::ParseCookieTime(pc.Expires()) : base::Time();
+ std::string cookie_path = pc.Path();
+
+ scoped_ptr<net::CookieMonster::CanonicalCookie> cookie(
+ new net::CookieMonster::CanonicalCookie(
+ pc.Name(), pc.Value(), key, cookie_path,
+ pc.IsSecure(), pc.IsHttpOnly(),
+ creation_time, creation_time,
+ !cookie_expires.is_null(),
+ cookie_expires));
+
+ out_list->push_back(cookie.release());
+}
+
+} // namespace
diff --git a/net/base/cookie_monster_unittest.cc b/net/base/cookie_monster_unittest.cc
index c61a782..83c7f7d 100644
--- a/net/base/cookie_monster_unittest.cc
+++ b/net/base/cookie_monster_unittest.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.
@@ -11,11 +11,15 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "net/base/cookie_monster.h"
+#include "net/base/cookie_monster_store_test.h" // For CookieStore Mock
#include "testing/gtest/include/gtest/gtest.h"
+namespace net {
+
using base::Time;
using base::TimeDelta;
@@ -24,142 +28,6 @@ namespace {
class ParsedCookieTest : public testing::Test { };
class CookieMonsterTest : public testing::Test { };
-// Describes a call to one of the 3 functions of PersistentCookieStore.
-struct CookieStoreCommand {
- enum Type {
- ADD,
- UPDATE_ACCESS_TIME,
- REMOVE,
- };
-
- CookieStoreCommand(Type type,
- const std::string& key,
- const net::CookieMonster::CanonicalCookie& cookie)
- : type(type), key(key), cookie(cookie) {}
-
- Type type;
- std::string key; // Only applicable to the ADD command.
- net::CookieMonster::CanonicalCookie cookie;
-};
-
-// Implementation of PersistentCookieStore that captures the
-// received commands and saves them to a list.
-// The result of calls to Load() can be configured using SetLoadExpectation().
-class MockPersistentCookieStore
- : public net::CookieMonster::PersistentCookieStore {
- public:
- typedef std::vector<CookieStoreCommand> CommandList;
-
- MockPersistentCookieStore() : load_return_value_(true) {
- }
-
- virtual bool Load(
- std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_cookies) {
- bool ok = load_return_value_;
- if (ok)
- *out_cookies = load_result_;
- return ok;
- }
-
- virtual void AddCookie(const std::string& key,
- const net::CookieMonster::CanonicalCookie& cookie) {
- commands_.push_back(
- CookieStoreCommand(CookieStoreCommand::ADD, key, cookie));
- }
-
- virtual void UpdateCookieAccessTime(
- const net::CookieMonster::CanonicalCookie& cookie) {
- commands_.push_back(CookieStoreCommand(
- CookieStoreCommand::UPDATE_ACCESS_TIME, std::string(), cookie));
- }
-
- virtual void DeleteCookie(
- const net::CookieMonster::CanonicalCookie& cookie) {
- commands_.push_back(
- CookieStoreCommand(CookieStoreCommand::REMOVE, std::string(), cookie));
- }
-
- void SetLoadExpectation(
- bool return_value,
- const std::vector<net::CookieMonster::KeyedCanonicalCookie>& result) {
- load_return_value_ = return_value;
- load_result_ = result;
- }
-
- const CommandList& commands() const {
- return commands_;
- }
-
- private:
- CommandList commands_;
-
- // Deferred result to use when Load() is called.
- bool load_return_value_;
- std::vector<net::CookieMonster::KeyedCanonicalCookie> load_result_;
-
- DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore);
-};
-
-// Mock for CookieMonster::Delegate
-class MockCookieMonsterDelegate : public net::CookieMonster::Delegate {
- public:
- typedef std::pair<net::CookieMonster::CanonicalCookie, bool>
- CookieNotification;
-
- MockCookieMonsterDelegate() {}
-
- virtual void OnCookieChanged(
- const net::CookieMonster::CanonicalCookie& cookie,
- bool removed) {
- CookieNotification notification(cookie, removed);
- changes_.push_back(notification);
- }
-
- const std::vector<CookieNotification>& changes() const { return changes_; }
-
- void reset() { changes_.clear(); }
-
- private:
- virtual ~MockCookieMonsterDelegate() {}
-
- std::vector<CookieNotification> changes_;
-
- DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate);
-};
-
-// Helper to build a list of KeyedCanonicalCookies.
-void AddKeyedCookieToList(
- const std::string& key,
- const std::string& cookie_line,
- const Time& creation_time,
- std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_list) {
-
- // Parse the cookie line.
- net::CookieMonster::ParsedCookie pc(cookie_line);
- EXPECT_TRUE(pc.IsValid());
-
- // This helper is simplistic in interpreting a parsed cookie, in order to
- // avoid duplicated CookieMonster's CanonPath() and CanonExpiration()
- // functions. Would be nice to export them, and re-use here.
- EXPECT_FALSE(pc.HasMaxAge());
- EXPECT_TRUE(pc.HasPath());
- Time cookie_expires = pc.HasExpires() ?
- net::CookieMonster::ParseCookieTime(pc.Expires()) : Time();
- std::string cookie_path = pc.Path();
-
- scoped_ptr<net::CookieMonster::CanonicalCookie> cookie(
- new net::CookieMonster::CanonicalCookie(
- pc.Name(), pc.Value(), key, cookie_path,
- pc.IsSecure(), pc.IsHttpOnly(),
- creation_time, creation_time,
- !cookie_expires.is_null(),
- cookie_expires));
-
- out_list->push_back(
- net::CookieMonster::KeyedCanonicalCookie(
- key, cookie.release()));
-}
-
// Helper for DeleteAllForHost test; repopulates CM with same layout
// each time.
const char* kTopLevelDomainPlus1 = "http://www.harvard.edu";
@@ -247,7 +115,6 @@ void PopulateCmForDeleteAllForHost(scoped_refptr<net::CookieMonster> cm) {
} // namespace
-
TEST(ParsedCookieTest, TestBasic) {
net::CookieMonster::ParsedCookie pc("a=b");
EXPECT_TRUE(pc.IsValid());
@@ -489,6 +356,7 @@ TEST(ParsedCookieTest, ParseTokensAndValues) {
}
static const char kUrlGoogle[] = "http://www.google.izzle";
+static const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle";
static const char kUrlGoogleSecure[] = "https://www.google.izzle";
static const char kUrlFtp[] = "ftp://ftp.google.izzle/";
static const char kValidCookieLine[] = "A=B; path=/";
@@ -1161,30 +1029,88 @@ TEST(CookieMonsterTest, TestLastAccess) {
}
static int CountInString(const std::string& str, char c) {
- int count = 0;
- for (std::string::const_iterator it = str.begin();
- it != str.end(); ++it) {
- if (*it == c)
- ++count;
- }
- return count;
+ return std::count(str.begin(), str.end(), c);
}
-TEST(CookieMonsterTest, TestHostGarbageCollection) {
+static void TestHostGarbageCollectHelper(int domain_max_cookies,
+ int domain_purge_cookies,
+ bool new_key_scheme) {
GURL url_google(kUrlGoogle);
- scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
+ const int more_than_enough_cookies =
+ (domain_max_cookies + domain_purge_cookies) * 2;
// Add a bunch of cookies on a single host, should purge them.
- for (int i = 0; i < 101; i++) {
- std::string cookie = StringPrintf("a%03d=b", i);
- EXPECT_TRUE(cm->SetCookie(url_google, cookie));
- std::string cookies = cm->GetCookies(url_google);
- // Make sure we find it in the cookies.
- EXPECT_TRUE(cookies.find(cookie) != std::string::npos);
- // Count the number of cookies.
- EXPECT_LE(CountInString(cookies, '='), 70);
+ {
+ scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
+ cm->SetKeyScheme(new_key_scheme);
+ for (int i = 0; i < more_than_enough_cookies; ++i) {
+ std::string cookie = base::StringPrintf("a%03d=b", i);
+ EXPECT_TRUE(cm->SetCookie(url_google, cookie));
+ std::string cookies = cm->GetCookies(url_google);
+ // Make sure we find it in the cookies.
+ EXPECT_NE(cookies.find(cookie), std::string::npos);
+ // Count the number of cookies.
+ EXPECT_LE(CountInString(cookies, '='), domain_max_cookies);
+ }
+ }
+
+ // Add a bunch of cookies on multiple hosts within a single eTLD.
+ // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
+ // between them. If we are using the (new) effective domain keying system
+ // we shouldn't go above kDomainMaxCookies for both together.
+ // If we're using the (old) domain keying system, each individual
+ // domain shouldn't go above kDomainMaxCookies.
+ GURL url_google_specific(kUrlGoogleSpecific);
+ {
+ scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
+ cm->SetKeyScheme(new_key_scheme);
+ for (int i = 0; i < more_than_enough_cookies; ++i) {
+ std::string cookie_general = base::StringPrintf("a%03d=b", i);
+ EXPECT_TRUE(cm->SetCookie(url_google, cookie_general));
+ std::string cookie_specific = base::StringPrintf("c%03d=b", i);
+ EXPECT_TRUE(cm->SetCookie(url_google_specific, cookie_specific));
+ std::string cookies_general = cm->GetCookies(url_google);
+ EXPECT_NE(cookies_general.find(cookie_general), std::string::npos);
+ std::string cookies_specific = cm->GetCookies(url_google_specific);
+ EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos);
+ if (new_key_scheme) {
+ EXPECT_LE((CountInString(cookies_general, '=') +
+ CountInString(cookies_specific, '=')),
+ domain_max_cookies);
+ } else {
+ EXPECT_LE(CountInString(cookies_general, '='), domain_max_cookies);
+ EXPECT_LE(CountInString(cookies_specific, '='), domain_max_cookies);
+ }
+ }
+ // After all this, there should be at least
+ // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
+ std::string cookies_general = cm->GetCookies(url_google);
+ std::string cookies_specific = cm->GetCookies(url_google_specific);
+ if (new_key_scheme) {
+ int total_cookies = (CountInString(cookies_general, '=') +
+ CountInString(cookies_specific, '='));
+ EXPECT_GE(total_cookies,
+ domain_max_cookies - domain_purge_cookies);
+ EXPECT_LE(total_cookies, domain_max_cookies);
+ } else {
+ int general_cookies = CountInString(cookies_general, '=');
+ int specific_cookies = CountInString(cookies_specific, '=');
+ EXPECT_GE(general_cookies,
+ domain_max_cookies - domain_purge_cookies);
+ EXPECT_LE(general_cookies, domain_max_cookies);
+ EXPECT_GE(specific_cookies,
+ domain_max_cookies - domain_purge_cookies);
+ EXPECT_LE(specific_cookies, domain_max_cookies);
+ }
}
}
+TEST(CookieMonsterTest, TestHostGarbageCollection) {
+ TestHostGarbageCollectHelper(CookieMonster::kDomainMaxCookies,
+ CookieMonster::kDomainPurgeCookies, false);
+ TestHostGarbageCollectHelper(CookieMonster::kDomainMaxCookies,
+ CookieMonster::kDomainPurgeCookies, true);
+}
+
TEST(CookieMonsterTest, TestTotalGarbageCollection) {
scoped_refptr<net::CookieMonster> cm(
new net::CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
@@ -1192,7 +1118,7 @@ TEST(CookieMonsterTest, TestTotalGarbageCollection) {
// Add a bunch of cookies on a bunch of host, some should get purged.
const GURL sticky_cookie("http://a0000.izzle");
for (int i = 0; i < 4000; ++i) {
- GURL url(StringPrintf("http://a%04d.izzle", i));
+ GURL url(base::StringPrintf("http://a%04d.izzle", i));
EXPECT_TRUE(cm->SetCookie(url, "a=b"));
EXPECT_EQ("a=b", cm->GetCookies(url));
@@ -1207,7 +1133,7 @@ TEST(CookieMonsterTest, TestTotalGarbageCollection) {
// Check that cookies that still exist.
for (int i = 0; i < 4000; ++i) {
- GURL url(StringPrintf("http://a%04d.izzle", i));
+ GURL url(base::StringPrintf("http://a%04d.izzle", i));
if ((i == 0) || (i > 1001)) {
// Cookies should still be around.
EXPECT_FALSE(cm->GetCookies(url).empty());
@@ -1245,7 +1171,7 @@ static bool FindAndDeleteCookie(net::CookieMonster* cm,
for (net::CookieMonster::CookieList::iterator it = cookies.begin();
it != cookies.end(); ++it)
if (it->Domain() == domain && it->Name() == name)
- return cm->DeleteCookie(domain, *it, false);
+ return cm->DeleteCanonicalCookie(*it);
return false;
}
@@ -1490,53 +1416,56 @@ TEST(CookieMonsterTest, DontImportDuplicateCookies) {
new MockPersistentCookieStore);
// We will fill some initial cookies into the PersistentCookieStore,
- // to simulate a database with 4 duplicates.
- std::vector<net::CookieMonster::KeyedCanonicalCookie> initial_cookies;
+ // to simulate a database with 4 duplicates. Note that we need to
+ // be careful not to have any duplicate creation times at all (as it's a
+ // violation of a CookieMonster invariant) even if Time::Now() doesn't
+ // move between calls.
+ std::vector<net::CookieMonster::CanonicalCookie*> initial_cookies;
// Insert 4 cookies with name "X" on path "/", with varying creation
// dates. We expect only the most recent one to be preserved following
// the import.
- AddKeyedCookieToList("www.google.com",
- "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
- Time::Now() + TimeDelta::FromDays(3),
- &initial_cookies);
+ AddCookieToList("www.google.com",
+ "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
+ Time::Now() + TimeDelta::FromDays(3),
+ &initial_cookies);
- AddKeyedCookieToList("www.google.com",
- "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
- Time::Now() + TimeDelta::FromDays(1),
- &initial_cookies);
+ AddCookieToList("www.google.com",
+ "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
+ Time::Now() + TimeDelta::FromDays(1),
+ &initial_cookies);
// ===> This one is the WINNER (biggest creation time). <====
- AddKeyedCookieToList("www.google.com",
- "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
- Time::Now() + TimeDelta::FromDays(4),
- &initial_cookies);
+ AddCookieToList("www.google.com",
+ "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
+ Time::Now() + TimeDelta::FromDays(4),
+ &initial_cookies);
- AddKeyedCookieToList("www.google.com",
- "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
- Time::Now(),
- &initial_cookies);
+ AddCookieToList("www.google.com",
+ "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
+ Time::Now(),
+ &initial_cookies);
// Insert 2 cookies with name "X" on path "/2", with varying creation
// dates. We expect only the most recent one to be preserved the import.
// ===> This one is the WINNER (biggest creation time). <====
- AddKeyedCookieToList("www.google.com",
- "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
- Time::Now() + TimeDelta::FromDays(9),
- &initial_cookies);
+ AddCookieToList("www.google.com",
+ "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
+ Time::Now() + TimeDelta::FromDays(9),
+ &initial_cookies);
- AddKeyedCookieToList("www.google.com",
- "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
- Time::Now() + TimeDelta::FromDays(1),
- &initial_cookies);
+ AddCookieToList("www.google.com",
+ "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
+ Time::Now() + TimeDelta::FromDays(2),
+ &initial_cookies);
// Insert 1 cookie with name "Y" on path "/".
- AddKeyedCookieToList("www.google.com",
- "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
- Time::Now() + TimeDelta::FromDays(9),
- &initial_cookies);
+ AddCookieToList("www.google.com",
+ "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
+ Time::Now() + TimeDelta::FromDays(10),
+ &initial_cookies);
// Inject our initial cookies into the mock PersistentCookieStore.
store->SetLoadExpectation(true, initial_cookies);
@@ -1560,6 +1489,50 @@ TEST(CookieMonsterTest, DontImportDuplicateCookies) {
EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
}
+// Tests importing from a persistent cookie store that contains cookies
+// with duplicate creation times. This situation should be handled by
+// dropping the cookies before insertion/visibility to user.
+//
+// This is a regression test for: http://crbug.com/43188.
+TEST(CookieMonsterTest, DontImportDuplicateCreationTimes) {
+ GURL url_google("http://www.google.com/");
+
+ scoped_refptr<MockPersistentCookieStore> store(
+ new MockPersistentCookieStore);
+
+ Time now(Time::Now());
+ Time earlier(now - TimeDelta::FromDays(1));
+
+ // Insert 8 cookies, four with the current time as creation times, and
+ // four with the earlier time as creation times. We should only get
+ // two cookies remaining, but which two (other than that there should
+ // be one from each set) will be random.
+ std::vector<net::CookieMonster::CanonicalCookie*> initial_cookies;
+ AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies);
+ AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies);
+ AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies);
+ AddCookieToList("www.google.com", "X=4; path=/", now, &initial_cookies);
+
+ AddCookieToList("www.google.com", "Y=1; path=/", earlier, &initial_cookies);
+ AddCookieToList("www.google.com", "Y=2; path=/", earlier, &initial_cookies);
+ AddCookieToList("www.google.com", "Y=3; path=/", earlier, &initial_cookies);
+ AddCookieToList("www.google.com", "Y=4; path=/", earlier, &initial_cookies);
+
+ // Inject our initial cookies into the mock PersistentCookieStore.
+ store->SetLoadExpectation(true, initial_cookies);
+
+ scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
+
+ net::CookieMonster::CookieList list(cm->GetAllCookies());
+ EXPECT_EQ(2U, list.size());
+ // Confirm that we have one of each.
+ std::string name1(list[0].Name());
+ std::string name2(list[1].Name());
+ EXPECT_TRUE(name1 == "X" || name2 == "X");
+ EXPECT_TRUE(name1 == "Y" || name2 == "Y");
+ EXPECT_NE(name1, name2);
+}
+
TEST(CookieMonsterTest, Delegate) {
GURL url_google(kUrlGoogle);
@@ -1715,8 +1688,6 @@ TEST(CookieMonsterTest, SetCookieWithDetails) {
ASSERT_TRUE(++it == cookies.end());
}
-
-
TEST(CookieMonsterTest, DeleteAllForHost) {
scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
@@ -1779,3 +1750,281 @@ TEST(CookieMonsterTest, DeleteAllForHost) {
std::string("/dir1/dir2/xxx"))));
}
+
+TEST(CookieMonsterTest, UniqueCreationTime) {
+ scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
+ GURL url_google(kUrlGoogle);
+ net::CookieOptions options;
+
+ // Add in three cookies through every public interface to the
+ // CookieMonster and confirm that none of them have duplicate
+ // creation times.
+
+ // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
+ // are not included as they aren't going to be public for very much
+ // longer.
+
+ // SetCookie, SetCookies, SetCookiesWithOptions,
+ // SetCookieWithOptions, SetCookieWithDetails
+
+ cm->SetCookie(url_google, "SetCookie1=A");
+ cm->SetCookie(url_google, "SetCookie2=A");
+ cm->SetCookie(url_google, "SetCookie3=A");
+
+ {
+ std::vector<std::string> cookie_lines;
+ cookie_lines.push_back("setCookies1=A");
+ cookie_lines.push_back("setCookies2=A");
+ cookie_lines.push_back("setCookies4=A");
+ cm->SetCookies(url_google, cookie_lines);
+ }
+
+ {
+ std::vector<std::string> cookie_lines;
+ cookie_lines.push_back("setCookiesWithOptions1=A");
+ cookie_lines.push_back("setCookiesWithOptions2=A");
+ cookie_lines.push_back("setCookiesWithOptions3=A");
+
+ cm->SetCookiesWithOptions(url_google, cookie_lines, options);
+ }
+
+ cm->SetCookieWithOptions(url_google, "setCookieWithOptions1=A", options);
+ cm->SetCookieWithOptions(url_google, "setCookieWithOptions2=A", options);
+ cm->SetCookieWithOptions(url_google, "setCookieWithOptions3=A", options);
+
+ cm->SetCookieWithDetails(url_google, "setCookieWithDetails1", "A",
+ ".google.com", "/", Time(), false, false);
+ cm->SetCookieWithDetails(url_google, "setCookieWithDetails2", "A",
+ ".google.com", "/", Time(), false, false);
+ cm->SetCookieWithDetails(url_google, "setCookieWithDetails3", "A",
+ ".google.com", "/", Time(), false, false);
+
+ // Now we check
+ net::CookieMonster::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();
+ it != cookie_list.end(); it++) {
+ const int64 creation_date = it->CreationDate().ToInternalValue();
+ TimeCookieMap::const_iterator
+ existing_cookie_it(check_map.find(creation_date));
+ EXPECT_TRUE(existing_cookie_it == check_map.end())
+ << "Cookie " << it->Name() << " has same creation date ("
+ << it->CreationDate().ToInternalValue()
+ << ") as previously entered cookie "
+ << existing_cookie_it->second.Name();
+
+ if (existing_cookie_it == check_map.end()) {
+ check_map.insert(TimeCookieMap::value_type(
+ it->CreationDate().ToInternalValue(), *it));
+ }
+ }
+}
+
+// Mainly a test of GetEffectiveDomain, or more specifically, of the
+// expected behavior of GetEffectiveDomain within the CookieMonster.
+TEST(CookieMonsterTest, GetKey) {
+ scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
+
+ // This test is really only interesting if GetKey() actually does something.
+ if (cm->use_effective_domain_key_scheme_) {
+ EXPECT_EQ("google.com", cm->GetKey("www.google.com"));
+ EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie"));
+ EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie"));
+ EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk"));
+ EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk"));
+ EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com"));
+ EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie"));
+
+ // Cases where the effective domain is null, so we use the host
+ // as the key.
+ EXPECT_EQ("co.uk", cm->GetKey("co.uk"));
+ const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
+ EXPECT_EQ(extension_name, cm->GetKey(extension_name));
+ EXPECT_EQ("com", cm->GetKey("com"));
+ EXPECT_EQ("hostalias", cm->GetKey("hostalias"));
+ EXPECT_EQ("localhost", cm->GetKey("localhost"));
+ }
+}
+
+// Just act like a backing database. Keep cookie information from
+// Add/Update/Delete and regurgitate it when Load is called.
+class MockSimplePersistentCookieStore
+ : public CookieMonster::PersistentCookieStore {
+ public:
+ typedef std::vector<CookieMonster::CanonicalCookie> CanonicalCookieVector;
+
+ virtual bool Load(std::vector<CookieMonster::CanonicalCookie*>* out_cookies);
+
+ virtual void AddCookie(const net::CookieMonster::CanonicalCookie& cookie);
+
+ virtual void UpdateCookieAccessTime(
+ const CookieMonster::CanonicalCookie& cookie);
+
+ virtual void DeleteCookie(const CookieMonster::CanonicalCookie& cookie);
+
+ private:
+ std::vector<CookieMonster::CanonicalCookie> cookies_;
+};
+
+bool MockSimplePersistentCookieStore::Load(
+ std::vector<CookieMonster::CanonicalCookie*>* out_cookies) {
+ for (CanonicalCookieVector::const_iterator it = cookies_.begin();
+ it != cookies_.end(); it++)
+ out_cookies->push_back(new CookieMonster::CanonicalCookie(*it));
+ return true;
+}
+
+void MockSimplePersistentCookieStore::AddCookie(
+ const net::CookieMonster::CanonicalCookie& cookie) {
+ for (CanonicalCookieVector::const_iterator it = cookies_.begin();
+ it != cookies_.end(); it++) {
+ // Caller must assure creation dates unique.
+ EXPECT_NE(cookie.CreationDate().ToInternalValue(),
+ it->CreationDate().ToInternalValue());
+ }
+ cookies_.push_back(cookie);
+}
+
+void MockSimplePersistentCookieStore::UpdateCookieAccessTime(
+ const CookieMonster::CanonicalCookie& cookie) {
+ for (CanonicalCookieVector::iterator it = cookies_.begin();
+ it != cookies_.end(); it++) {
+ if (it->CreationDate() == cookie.CreationDate())
+ it->SetLastAccessDate(base::Time::Now());
+ }
+}
+
+void MockSimplePersistentCookieStore::DeleteCookie(
+ const CookieMonster::CanonicalCookie& cookie) {
+ for (CanonicalCookieVector::iterator it = cookies_.begin();
+ it != cookies_.end(); it++) {
+ if (it->CreationDate() == cookie.CreationDate()) {
+ cookies_.erase(it);
+ return;
+ }
+ }
+}
+
+// Helper type for BackingStoreCommunication; defined outside of the
+// function so that arraysize() macro can beu used.
+struct CookiesInputInfo {
+ std::string gurl;
+ std::string name;
+ std::string value;
+ std::string domain;
+ std::string path;
+ base::Time expires;
+ bool secure;
+ bool http_only;
+};
+
+// Test that cookies transfer from/to the backing store correctly.
+TEST(CookieMonsterTest, BackingStoreCommunication) {
+ // Store details for cookies transforming through the backing store interface.
+
+ base::Time current(base::Time::Now());
+ scoped_refptr<MockSimplePersistentCookieStore> store(
+ new MockSimplePersistentCookieStore);
+ base::Time new_access_time;
+ base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
+
+ const CookiesInputInfo input_info[] = {
+ {"http://a.b.google.com", "a", "1", "", "/path/to/cookie", expires,
+ false, false},
+ {"https://www.google.com", "b", "2", ".google.com", "/path/from/cookie",
+ expires + TimeDelta::FromSeconds(10), true, true},
+ {"https://google.com", "c", "3", "", "/another/path/to/cookie",
+ base::Time::Now() + base::TimeDelta::FromSeconds(100),
+ true, false}
+ };
+ const int INPUT_DELETE = 1;
+
+ // Create new cookies and flush them to the store.
+ {
+ scoped_refptr<net::CookieMonster> cmout = new CookieMonster(store, NULL);
+ for (const CookiesInputInfo* p = input_info;
+ p < &input_info[arraysize(input_info)]; p++) {
+ EXPECT_TRUE(cmout->SetCookieWithDetails(GURL(p->gurl), p->name, p->value,
+ p->domain, p->path, p->expires,
+ p->secure, p->http_only));
+ }
+ cmout->DeleteCookie(GURL(std::string(input_info[INPUT_DELETE].gurl) +
+ input_info[INPUT_DELETE].path),
+ input_info[INPUT_DELETE].name);
+ }
+
+ // 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());
+ ASSERT_EQ(2u, cookies.size());
+ // Ordering is path length, then creation time. So second cookie
+ // will come first, and we need to swap them.
+ std::swap(cookies[0], cookies[1]);
+ for (int output_index = 0; output_index < 2; output_index++) {
+ int input_index = output_index * 2;
+ const CookiesInputInfo* input = &input_info[input_index];
+ const CookieMonster::CanonicalCookie* output = &cookies[output_index];
+
+ EXPECT_EQ(input->name, output->Name());
+ EXPECT_EQ(input->value, output->Value());
+ EXPECT_EQ(GURL(input->gurl).host(), output->Domain());
+ EXPECT_EQ(input->path, output->Path());
+ EXPECT_LE(current.ToInternalValue(),
+ output->CreationDate().ToInternalValue());
+ EXPECT_EQ(input->secure, output->IsSecure());
+ EXPECT_EQ(input->http_only, output->IsHttpOnly());
+ EXPECT_TRUE(output->IsPersistent());
+ EXPECT_EQ(input->expires.ToInternalValue(),
+ output->ExpiryDate().ToInternalValue());
+ }
+ }
+}
+
+TEST(CookieMonsterTest, CookieOrdering) {
+ // Put a random set of cookies into a monster and make sure
+ // they're returned in the right order.
+ scoped_refptr<net::CookieMonster> cm = new CookieMonster(NULL, NULL);
+ EXPECT_TRUE(cm->SetCookie(GURL("http://d.c.b.a.google.com/aa/x.html"),
+ "c=1"));
+ EXPECT_TRUE(cm->SetCookie(GURL("http://b.a.google.com/aa/bb/cc/x.html"),
+ "d=1; domain=b.a.google.com"));
+ EXPECT_TRUE(cm->SetCookie(GURL("http://b.a.google.com/aa/bb/cc/x.html"),
+ "a=4; domain=b.a.google.com"));
+ EXPECT_TRUE(cm->SetCookie(GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
+ "e=1; domain=c.b.a.google.com"));
+ EXPECT_TRUE(cm->SetCookie(GURL("http://d.c.b.a.google.com/aa/bb/x.html"),
+ "b=1"));
+ EXPECT_TRUE(cm->SetCookie(GURL("http://news.bbc.co.uk/midpath/x.html"),
+ "g=10"));
+ EXPECT_EQ("d=1; a=4; e=1; b=1; c=1",
+ cm->GetCookiesWithOptions(
+ GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"),
+ CookieOptions()));
+ {
+ unsigned int i = 0;
+ CookieMonster::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());
+ EXPECT_EQ("a", cookies[i++].Name());
+ EXPECT_EQ("e", cookies[i++].Name());
+ EXPECT_EQ("b", cookies[i++].Name());
+ EXPECT_EQ("c", cookies[i++].Name());
+ }
+
+ {
+ unsigned int i = 0;
+ CookieMonster::CookieList cookies(cm->GetAllCookies());
+ ASSERT_EQ(6u, cookies.size());
+ EXPECT_EQ("d", cookies[i++].Name());
+ EXPECT_EQ("a", cookies[i++].Name());
+ EXPECT_EQ("e", cookies[i++].Name());
+ EXPECT_EQ("g", cookies[i++].Name());
+ EXPECT_EQ("b", cookies[i++].Name());
+ EXPECT_EQ("c", cookies[i++].Name());
+ }
+}
+
+} // namespace
diff --git a/net/base/cookie_options.h b/net/base/cookie_options.h
index 9995a05..8ace523 100644
--- a/net/base/cookie_options.h
+++ b/net/base/cookie_options.h
@@ -6,6 +6,7 @@
#ifndef NET_BASE_COOKIE_OPTIONS_H_
#define NET_BASE_COOKIE_OPTIONS_H_
+#pragma once
namespace net {
diff --git a/net/base/cookie_policy.h b/net/base/cookie_policy.h
index 5e57c90..c32c8a9 100644
--- a/net/base/cookie_policy.h
+++ b/net/base/cookie_policy.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_COOKIE_POLICY_H_
#define NET_BASE_COOKIE_POLICY_H_
+#pragma once
#include <string>
diff --git a/net/base/cookie_store.h b/net/base/cookie_store.h
index 2fbe1d8..2360c96 100644
--- a/net/base/cookie_store.h
+++ b/net/base/cookie_store.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.
@@ -6,8 +6,10 @@
#ifndef NET_BASE_COOKIE_STORE_H_
#define NET_BASE_COOKIE_STORE_H_
+#pragma once
#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "base/ref_counted.h"
diff --git a/net/base/data_url.h b/net/base/data_url.h
index aa63d5c..b40878a 100644
--- a/net/base/data_url.h
+++ b/net/base/data_url.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_DATA_URL_H_
#define NET_BASE_DATA_URL_H_
+#pragma once
#include <string>
diff --git a/net/base/dir_header.html b/net/base/dir_header.html
index ad4ec0a..4f33bba 100644
--- a/net/base/dir_header.html
+++ b/net/base/dir_header.html
@@ -62,7 +62,7 @@ function onListingParsingError() {
var box = document.getElementById("listingParsingErrorBox");
box.innerHTML = box.innerHTML.replace("LOCATION", encodeURI(document.location)
+ "?raw");
- box.style.display = "";
+ box.style.display = "block";
}
</script>
diff --git a/net/base/directory_lister.cc b/net/base/directory_lister.cc
index ab45e2f..0a22d2b 100644
--- a/net/base/directory_lister.cc
+++ b/net/base/directory_lister.cc
@@ -17,8 +17,9 @@ namespace net {
static const int kFilesPerEvent = 8;
+// A task which is used to signal the delegate asynchronously.
class DirectoryDataEvent : public Task {
- public:
+public:
explicit DirectoryDataEvent(DirectoryLister* d) : lister(d), error(0) {
// Allocations of the FindInfo aren't super cheap, so reserve space.
data.reserve(64);
@@ -33,35 +34,87 @@ class DirectoryDataEvent : public Task {
}
scoped_refptr<DirectoryLister> lister;
- std::vector<file_util::FileEnumerator::FindInfo> data;
+ std::vector<DirectoryLister::DirectoryListerData> data;
int error;
};
-// Comparator for sorting FindInfo's. This uses the locale aware filename
+// Comparator for sorting lister results. This uses the locale aware filename
// comparison function on the filenames for sorting in the user's locale.
-static bool CompareFindInfo(const file_util::FileEnumerator::FindInfo& a,
- const file_util::FileEnumerator::FindInfo& b) {
+// Static.
+bool DirectoryLister::CompareAlphaDirsFirst(const DirectoryListerData& a,
+ const DirectoryListerData& b) {
// Parent directory before all else.
- if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a)))
+ if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
return true;
- if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b)))
+ if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
return false;
// Directories before regular files.
- bool a_is_directory = file_util::FileEnumerator::IsDirectory(a);
- bool b_is_directory = file_util::FileEnumerator::IsDirectory(b);
+ bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
+ bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
if (a_is_directory != b_is_directory)
return a_is_directory;
return file_util::LocaleAwareCompareFilenames(
- file_util::FileEnumerator::GetFilename(a),
- file_util::FileEnumerator::GetFilename(b));
+ file_util::FileEnumerator::GetFilename(a.info),
+ file_util::FileEnumerator::GetFilename(b.info));
+}
+
+// Static.
+bool DirectoryLister::CompareDate(const DirectoryListerData& a,
+ const DirectoryListerData& b) {
+ // Parent directory before all else.
+ if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
+ return true;
+ if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
+ return false;
+
+ // Directories before regular files.
+ bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
+ bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
+ if (a_is_directory != b_is_directory)
+ return a_is_directory;
+#if defined(OS_POSIX)
+ return a.info.stat.st_mtime > b.info.stat.st_mtime;
+#elif defined(OS_WIN)
+ if (a.info.ftLastWriteTime.dwHighDateTime ==
+ b.info.ftLastWriteTime.dwHighDateTime) {
+ return a.info.ftLastWriteTime.dwLowDateTime >
+ b.info.ftLastWriteTime.dwLowDateTime;
+ } else {
+ return a.info.ftLastWriteTime.dwHighDateTime >
+ b.info.ftLastWriteTime.dwHighDateTime;
+ }
+#endif
+}
+
+// Comparator for sorting find result by paths. This uses the locale-aware
+// comparison function on the filenames for sorting in the user's locale.
+// Static.
+bool DirectoryLister::CompareFullPath(const DirectoryListerData& a,
+ const DirectoryListerData& b) {
+ return file_util::LocaleAwareCompareFilenames(a.path, b.path);
}
DirectoryLister::DirectoryLister(const FilePath& dir,
DirectoryListerDelegate* delegate)
: dir_(dir),
+ recursive_(false),
delegate_(delegate),
+ sort_(ALPHA_DIRS_FIRST),
+ message_loop_(NULL),
+ thread_(kNullThreadHandle) {
+ DCHECK(!dir.value().empty());
+}
+
+DirectoryLister::DirectoryLister(const FilePath& dir,
+ bool recursive,
+ SORT_TYPE sort,
+ DirectoryListerDelegate* delegate)
+ : dir_(dir),
+ recursive_(recursive),
+ delegate_(delegate),
+ sort_(sort),
message_loop_(NULL),
thread_(kNullThreadHandle) {
DCHECK(!dir.value().empty());
@@ -109,15 +162,20 @@ void DirectoryLister::ThreadMain() {
return;
}
- file_util::FileEnumerator file_enum(dir_, false,
- static_cast<file_util::FileEnumerator::FILE_TYPE>(
- file_util::FileEnumerator::FILES |
- file_util::FileEnumerator::DIRECTORIES |
- file_util::FileEnumerator::INCLUDE_DOT_DOT));
+ int types = file_util::FileEnumerator::FILES |
+ file_util::FileEnumerator::DIRECTORIES;
+ if (!recursive_)
+ types |= file_util::FileEnumerator::INCLUDE_DOT_DOT;
+
+ file_util::FileEnumerator file_enum(dir_, recursive_,
+ static_cast<file_util::FileEnumerator::FILE_TYPE>(types));
- while (!canceled_.IsSet() && !(file_enum.Next().value().empty())) {
- e->data.push_back(file_util::FileEnumerator::FindInfo());
- file_enum.GetFindInfo(&e->data[e->data.size() - 1]);
+ FilePath path;
+ while (!canceled_.IsSet() && !(path = file_enum.Next()).empty()) {
+ DirectoryListerData data;
+ file_enum.GetFindInfo(&data.info);
+ data.path = path;
+ e->data.push_back(data);
/* TODO(brettw) bug 24107: It would be nice to send incremental updates.
We gather them all so they can be sorted, but eventually the sorting
@@ -133,7 +191,14 @@ void DirectoryLister::ThreadMain() {
if (!e->data.empty()) {
// Sort the results. See the TODO above (this sort should be removed and we
// should do it from JS).
- std::sort(e->data.begin(), e->data.end(), CompareFindInfo);
+ if (sort_ == DATE)
+ std::sort(e->data.begin(), e->data.end(), CompareDate);
+ else if (sort_ == FULL_PATH)
+ std::sort(e->data.begin(), e->data.end(), CompareFullPath);
+ else if (sort_ == ALPHA_DIRS_FIRST)
+ std::sort(e->data.begin(), e->data.end(), CompareAlphaDirsFirst);
+ else
+ DCHECK_EQ(NO_SORT, sort_);
message_loop_->PostTask(FROM_HERE, e);
e = new DirectoryDataEvent(this);
@@ -144,8 +209,8 @@ void DirectoryLister::ThreadMain() {
message_loop_->PostTask(FROM_HERE, e);
}
-void DirectoryLister::OnReceivedData(
- const file_util::FileEnumerator::FindInfo* data, int count) {
+void DirectoryLister::OnReceivedData(const DirectoryListerData* data,
+ int count) {
// Since the delegate can clear itself during the OnListFile callback, we
// need to null check it during each iteration of the loop. Similarly, it is
// necessary to check the canceled_ flag to avoid sending data to a delegate
diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h
index 541741e..8623088 100644
--- a/net/base/directory_lister.h
+++ b/net/base/directory_lister.h
@@ -1,17 +1,19 @@
-// 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.
#ifndef NET_BASE_DIRECTORY_LISTER_H_
#define NET_BASE_DIRECTORY_LISTER_H_
+#pragma once
-#include <string>
+#include <vector>
#include "base/cancellation_flag.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/platform_thread.h"
#include "base/ref_counted.h"
+#include "base/task.h"
class MessageLoop;
@@ -27,18 +29,45 @@ namespace net {
class DirectoryLister : public base::RefCountedThreadSafe<DirectoryLister>,
public PlatformThread::Delegate {
public:
+ // Represents one file found.
+ struct DirectoryListerData {
+ file_util::FileEnumerator::FindInfo info;
+ FilePath path;
+ };
+
// Implement this class to receive directory entries.
class DirectoryListerDelegate {
public:
- virtual void OnListFile(
- const file_util::FileEnumerator::FindInfo& data) = 0;
+ // Called for each file found by the lister.
+ virtual void OnListFile(const DirectoryListerData& data) = 0;
+
+ // Called when the listing is complete.
virtual void OnListDone(int error) = 0;
protected:
virtual ~DirectoryListerDelegate() {}
};
- DirectoryLister(const FilePath& dir, DirectoryListerDelegate* delegate);
+ // Sort options
+ // ALPHA_DIRS_FIRST is the default sort :
+ // directories first in name order, then files by name order
+ // FULL_PATH sorts by paths as strings, ignoring files v. directories
+ // DATE sorts by last modified date
+ enum SORT_TYPE {
+ NO_SORT,
+ DATE,
+ ALPHA_DIRS_FIRST,
+ FULL_PATH
+ };
+
+ DirectoryLister(const FilePath& dir,
+ DirectoryListerDelegate* delegate);
+
+ DirectoryLister(const FilePath& dir,
+ bool recursive,
+ SORT_TYPE sort,
+ DirectoryListerDelegate* delegate);
+
// Call this method to start the directory enumeration thread.
bool Start();
@@ -59,14 +88,23 @@ class DirectoryLister : public base::RefCountedThreadSafe<DirectoryLister>,
friend class base::RefCountedThreadSafe<DirectoryLister>;
friend class DirectoryDataEvent;
+ // Comparison methods for sorting, chosen based on |sort_|.
+ static bool CompareAlphaDirsFirst(const DirectoryListerData& a,
+ const DirectoryListerData& b);
+ static bool CompareDate(const DirectoryListerData& a,
+ const DirectoryListerData& b);
+ static bool CompareFullPath(const DirectoryListerData& a,
+ const DirectoryListerData& b);
+
~DirectoryLister();
- void OnReceivedData(const file_util::FileEnumerator::FindInfo* data,
- int count);
+ void OnReceivedData(const DirectoryListerData* data, int count);
void OnDone(int error);
FilePath dir_;
+ bool recursive_;
DirectoryListerDelegate* delegate_;
+ SORT_TYPE sort_;
MessageLoop* message_loop_;
PlatformThreadHandle thread_;
base::CancellationFlag canceled_;
diff --git a/net/base/directory_lister_unittest.cc b/net/base/directory_lister_unittest.cc
index f3cd33b..f75d8d8 100644
--- a/net/base/directory_lister_unittest.cc
+++ b/net/base/directory_lister_unittest.cc
@@ -5,6 +5,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/i18n/file_util_icu.h"
+#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "net/base/directory_lister.h"
@@ -17,14 +18,32 @@ class DirectoryListerTest : public testing::Test {};
class ListerDelegate : public net::DirectoryLister::DirectoryListerDelegate {
public:
- ListerDelegate() : error_(-1) {
+ explicit ListerDelegate(bool recursive) : error_(-1), recursive_(recursive) {
}
- void OnListFile(const file_util::FileEnumerator::FindInfo& data) {
- file_list_.push_back(data);
+ void OnListFile(const net::DirectoryLister::DirectoryListerData& data) {
+ file_list_.push_back(data.info);
+ paths_.push_back(data.path);
}
void OnListDone(int error) {
error_ = error;
MessageLoop::current()->Quit();
+ if (recursive_)
+ CheckRecursiveSort();
+ else
+ CheckSort();
+ }
+ void CheckRecursiveSort() {
+ // Check that we got files in the right order.
+ if (!file_list_.empty()) {
+ for (size_t previous = 0, current = 1;
+ current < file_list_.size();
+ previous++, current++) {
+ EXPECT_TRUE(file_util::LocaleAwareCompareFilenames(
+ paths_[previous], paths_[current]));
+ }
+ }
+ }
+ void CheckSort() {
// Check that we got files in the right order.
if (!file_list_.empty()) {
for (size_t previous = 0, current = 1;
@@ -48,14 +67,16 @@ class ListerDelegate : public net::DirectoryLister::DirectoryListerDelegate {
int error() const { return error_; }
private:
int error_;
+ bool recursive_;
std::vector<file_util::FileEnumerator::FindInfo> file_list_;
+ std::vector<FilePath> paths_;
};
TEST(DirectoryListerTest, BigDirTest) {
FilePath path;
ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &path));
- ListerDelegate delegate;
+ ListerDelegate delegate(false);
scoped_refptr<net::DirectoryLister> lister =
new net::DirectoryLister(path, &delegate);
@@ -66,11 +87,29 @@ TEST(DirectoryListerTest, BigDirTest) {
EXPECT_EQ(delegate.error(), net::OK);
}
+TEST(DirectoryListerTest, BigDirRecursiveTest) {
+ FilePath path;
+ ASSERT_TRUE(PathService::Get(base::DIR_EXE, &path));
+
+ ListerDelegate delegate(true);
+ scoped_refptr<net::DirectoryLister> lister =
+ new net::DirectoryLister(path,
+ true,
+ net::DirectoryLister::FULL_PATH,
+ &delegate);
+
+ lister->Start();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(delegate.error(), net::OK);
+}
+
TEST(DirectoryListerTest, CancelTest) {
FilePath path;
ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &path));
- ListerDelegate delegate;
+ ListerDelegate delegate(false);
scoped_refptr<net::DirectoryLister> lister =
new net::DirectoryLister(path, &delegate);
diff --git a/net/base/dns_reload_timer.cc b/net/base/dns_reload_timer.cc
new file mode 100644
index 0000000..5931c5b
--- /dev/null
+++ b/net/base/dns_reload_timer.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 "net/base/dns_reload_timer.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+#include "base/singleton.h"
+#include "base/thread_local_storage.h"
+#include "base/time.h"
+
+namespace net {
+
+// On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting
+// in DNS queries failing either because nameservers are unknown on startup
+// or because nameserver info has changed as a result of e.g. connecting to
+// a new network. Some distributions patch glibc to stat /etc/resolv.conf
+// to try to automatically detect such changes but these patches are not
+// universal and even patched systems such as Jaunty appear to need calls
+// to res_ninit to reload the nameserver information in different threads.
+//
+// We adopt the Mozilla solution here which is to call res_ninit when
+// lookups fail and to rate limit the reloading to once per second per
+// thread.
+//
+// OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do
+// the same trick there.
+
+// Keep a timer per calling thread to rate limit the calling of res_ninit.
+class DnsReloadTimer {
+ public:
+ // Check if the timer for the calling thread has expired. When no
+ // timer exists for the calling thread, create one.
+ bool Expired() {
+ const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeTicks* timer_ptr =
+ static_cast<base::TimeTicks*>(tls_index_.Get());
+
+ if (!timer_ptr) {
+ timer_ptr = new base::TimeTicks();
+ *timer_ptr = base::TimeTicks::Now();
+ tls_index_.Set(timer_ptr);
+ // Return true to reload dns info on the first call for each thread.
+ return true;
+ } else if (now - *timer_ptr > kRetryTime) {
+ *timer_ptr = now;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Free the allocated timer.
+ static void SlotReturnFunction(void* data) {
+ base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data);
+ delete tls_data;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<DnsReloadTimer>;
+
+ DnsReloadTimer() {
+ // During testing the DnsReloadTimer Singleton may be created and destroyed
+ // multiple times. Initialize the ThreadLocalStorage slot only once.
+ if (!tls_index_.initialized())
+ tls_index_.Initialize(SlotReturnFunction);
+ }
+
+ ~DnsReloadTimer() {
+ }
+
+ // We use thread local storage to identify which base::TimeTicks to
+ // interact with.
+ static ThreadLocalStorage::Slot tls_index_ ;
+
+ DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
+};
+
+// A TLS slot to the TimeTicks for the current thread.
+// static
+ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);
+
+bool DnsReloadTimerHasExpired() {
+ DnsReloadTimer* dns_timer = Singleton<DnsReloadTimer>::get();
+ return dns_timer->Expired();
+}
+
+} // namespace net
+
+#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
diff --git a/net/base/dns_reload_timer.h b/net/base/dns_reload_timer.h
new file mode 100644
index 0000000..fdd90a7
--- /dev/null
+++ b/net/base/dns_reload_timer.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 NET_BASE_DNS_RELOAD_TIMER_H_
+#define NET_BASE_DNS_RELOAD_TIMER_H_
+#pragma once
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+namespace net {
+
+// DnsReloadTimerExpired tests the thread local DNS reload timer and, if it has
+// expired, returns true and resets the timer. See comments in
+// host_resolver_proc.cc for details.
+bool DnsReloadTimerHasExpired();
+
+} // namespace net
+#endif
+
+#endif // NET_BASE_DNS_RELOAD_TIMER_H_
diff --git a/net/base/dns_util.cc b/net/base/dns_util.cc
index 87d1866..f1e0de4 100644
--- a/net/base/dns_util.cc
+++ b/net/base/dns_util.cc
@@ -50,9 +50,9 @@ bool DNSDomainFromDot(const std::string& dotted, std::string* out) {
if (namelen + 1 > sizeof name)
return false;
- name[namelen++] = 0;
+ name[namelen++] = 0; // This is the root label (of length 0).
- *out = name;
+ *out = std::string(name, namelen);
return true;
}
diff --git a/net/base/dns_util.h b/net/base/dns_util.h
index f0d2051..c91587d 100644
--- a/net/base/dns_util.h
+++ b/net/base/dns_util.h
@@ -4,9 +4,12 @@
#ifndef NET_BASE_DNS_UTIL_H_
#define NET_BASE_DNS_UTIL_H_
+#pragma once
#include <string>
+#include "base/basictypes.h"
+
namespace net {
// DNSDomainFromDot - convert a domain string to DNS format. From DJB's
@@ -23,6 +26,26 @@ bool IsSTD3ASCIIValidCharacter(char c);
// Returns the hostname by trimming the ending dot, if one exists.
std::string TrimEndingDot(const std::string& host);
+// DNS resource record types. See
+// http://www.iana.org/assignments/dns-parameters
+
+static const uint16 kDNS_CNAME = 5;
+static const uint16 kDNS_TXT = 16;
+static const uint16 kDNS_CERT = 37;
+static const uint16 kDNS_DS = 43;
+static const uint16 kDNS_RRSIG = 46;
+static const uint16 kDNS_DNSKEY = 48;
+static const uint16 kDNS_ANY = 0xff;
+
+// http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
+static const uint8 kDNSSEC_RSA_SHA1 = 5;
+static const uint8 kDNSSEC_RSA_SHA1_NSEC3 = 7;
+static const uint8 kDNSSEC_RSA_SHA256 = 8;
+
+// RFC 4509
+static const uint8 kDNSSEC_SHA1 = 1;
+static const uint8 kDNSSEC_SHA256 = 2;
+
} // namespace net
#endif // NET_BASE_DNS_UTIL_H_
diff --git a/net/base/dns_util_unittest.cc b/net/base/dns_util_unittest.cc
index 7995b92..feeba55 100644
--- a/net/base/dns_util_unittest.cc
+++ b/net/base/dns_util_unittest.cc
@@ -10,38 +10,47 @@ namespace net {
class DNSUtilTest : public testing::Test {
};
+// IncludeNUL converts a char* to a std::string and includes the terminating
+// NUL in the result.
+static std::string IncludeNUL(const char* in) {
+ return std::string(in, strlen(in) + 1);
+}
+
TEST_F(DNSUtilTest, DNSDomainFromDot) {
std::string out;
EXPECT_TRUE(DNSDomainFromDot("", &out));
- EXPECT_EQ(out, "");
+ EXPECT_EQ(out, IncludeNUL(""));
EXPECT_TRUE(DNSDomainFromDot("com", &out));
- EXPECT_EQ(out, "\003com");
+ EXPECT_EQ(out, IncludeNUL("\003com"));
EXPECT_TRUE(DNSDomainFromDot("google.com", &out));
- EXPECT_EQ(out, "\x006google\003com");
+ EXPECT_EQ(out, IncludeNUL("\x006google\003com"));
EXPECT_TRUE(DNSDomainFromDot("www.google.com", &out));
- EXPECT_EQ(out, "\003www\006google\003com");
+ EXPECT_EQ(out, IncludeNUL("\003www\006google\003com"));
// Label is 63 chars: still valid
EXPECT_TRUE(DNSDomainFromDot("123456789a123456789a123456789a123456789a123456789a123456789a123", &out));
- EXPECT_EQ(out, "\077123456789a123456789a123456789a123456789a123456789a123456789a123");
+ EXPECT_EQ(out, IncludeNUL("\077123456789a123456789a123456789a123456789a123456789a123456789a123"));
// Label is too long: invalid
EXPECT_FALSE(DNSDomainFromDot("123456789a123456789a123456789a123456789a123456789a123456789a1234", &out));
// 253 characters in the name: still valid
EXPECT_TRUE(DNSDomainFromDot("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123", &out));
- EXPECT_EQ(out, "\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\003123");
+ EXPECT_EQ(out, IncludeNUL("\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\011123456789\003123"));
// 254 characters in the name: invalid
EXPECT_FALSE(DNSDomainFromDot("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.1234", &out));
// Zero length labels should be dropped.
EXPECT_TRUE(DNSDomainFromDot("www.google.com.", &out));
- EXPECT_EQ(out, "\003www\006google\003com");
+ EXPECT_EQ(out, IncludeNUL("\003www\006google\003com"));
EXPECT_TRUE(DNSDomainFromDot(".google.com", &out));
- EXPECT_EQ(out, "\006google\003com");
+ EXPECT_EQ(out, IncludeNUL("\006google\003com"));
+
+ EXPECT_TRUE(DNSDomainFromDot("www..google.com", &out));
+ EXPECT_EQ(out, IncludeNUL("\003www\006google\003com"));
}
TEST_F(DNSUtilTest, STD3ASCII) {
diff --git a/net/base/dnsrr_resolver.cc b/net/base/dnsrr_resolver.cc
new file mode 100644
index 0000000..dbbb0af
--- /dev/null
+++ b/net/base/dnsrr_resolver.cc
@@ -0,0 +1,417 @@
+// Copyright (c) 2010 The Chromium Authors. 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/dnsrr_resolver.h"
+
+#if defined(OS_POSIX)
+#include <resolv.h>
+#endif
+
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "base/task.h"
+#include "base/worker_pool.h"
+#include "net/base/dns_reload_timer.h"
+#include "net/base/dns_util.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+static const uint16 kClassIN = 1;
+
+namespace {
+
+class CompletionCallbackTask : public Task,
+ public MessageLoop::DestructionObserver {
+ public:
+ explicit CompletionCallbackTask(CompletionCallback* callback,
+ MessageLoop* ml)
+ : callback_(callback),
+ rv_(OK),
+ posted_(false),
+ message_loop_(ml) {
+ ml->AddDestructionObserver(this);
+ }
+
+ void set_rv(int rv) {
+ rv_ = rv;
+ }
+
+ void Post() {
+ AutoLock locked(lock_);
+ DCHECK(!posted_);
+
+ if (!message_loop_) {
+ // MessageLoop got deleted, nothing to do.
+ delete this;
+ return;
+ }
+ posted_ = true;
+ message_loop_->PostTask(FROM_HERE, this);
+ }
+
+ // Task interface
+ void Run() {
+ message_loop_->RemoveDestructionObserver(this);
+ callback_->Run(rv_);
+ // We will be deleted by the message loop.
+ }
+
+ // DestructionObserver interface
+ virtual void WillDestroyCurrentMessageLoop() {
+ AutoLock locked(lock_);
+ message_loop_ = NULL;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CompletionCallbackTask);
+
+ CompletionCallback* callback_;
+ int rv_;
+ bool posted_;
+
+ Lock lock_; // covers |message_loop_|
+ MessageLoop* message_loop_;
+};
+
+#if defined(OS_POSIX)
+class ResolveTask : public Task {
+ public:
+ ResolveTask(const std::string& name, uint16 rrtype,
+ uint16 flags, CompletionCallback* callback,
+ RRResponse* response, MessageLoop* ml)
+ : name_(name),
+ rrtype_(rrtype),
+ flags_(flags),
+ subtask_(new CompletionCallbackTask(callback, ml)),
+ response_(response) {
+ }
+
+ virtual void Run() {
+ // Runs on a worker thread.
+
+ bool r = true;
+ if ((_res.options & RES_INIT) == 0) {
+ if (res_ninit(&_res) != 0)
+ r = false;
+ }
+
+ if (r) {
+ unsigned long saved_options = _res.options;
+ r = Do();
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+ if (!r && DnsReloadTimerHasExpired()) {
+ res_nclose(&_res);
+ if (res_ninit(&_res) == 0)
+ r = Do();
+ }
+#endif
+ _res.options = saved_options;
+ }
+ int error = r ? OK : ERR_NAME_NOT_RESOLVED;
+
+ subtask_->set_rv(error);
+ subtask_.release()->Post();
+ }
+
+ bool Do() {
+ // For DNSSEC, a 4K buffer is suggested
+ static const unsigned kMaxDNSPayload = 4096;
+
+#ifndef RES_USE_DNSSEC
+ // Some versions of libresolv don't have support for the DO bit. In this
+ // case, we proceed without it.
+ static const int RES_USE_DNSSEC = 0;
+#endif
+
+#ifndef RES_USE_EDNS0
+ // Some versions of glibc are so old that they don't support EDNS0 either.
+ // http://code.google.com/p/chromium/issues/detail?id=51676
+ static const int RES_USE_EDNS0 = 0;
+#endif
+
+ // We set the options explicitly. Note that this removes several default
+ // options: RES_DEFNAMES and RES_DNSRCH (see res_init(3)).
+ _res.options = RES_INIT | RES_RECURSE | RES_USE_EDNS0 | RES_USE_DNSSEC;
+ uint8 answer[kMaxDNSPayload];
+ int len = res_search(name_.c_str(), kClassIN, rrtype_, answer,
+ sizeof(answer));
+ if (len == -1)
+ return false;
+
+ return response_->ParseFromResponse(answer, len, rrtype_);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResolveTask);
+
+ const std::string name_;
+ const uint16 rrtype_;
+ const uint16 flags_;
+ scoped_ptr<CompletionCallbackTask> subtask_;
+ RRResponse* const response_;
+};
+#else // OS_POSIX
+// On non-Linux platforms we fail everything for now.
+class ResolveTask : public Task {
+ public:
+ ResolveTask(const std::string& name, uint16 rrtype,
+ uint16 flags, CompletionCallback* callback,
+ RRResponse* response, MessageLoop* ml)
+ : subtask_(new CompletionCallbackTask(callback, ml)) {
+ }
+
+ virtual void Run() {
+ subtask_->set_rv(ERR_NAME_NOT_RESOLVED);
+ subtask_->Post();
+ }
+
+ private:
+ CompletionCallbackTask* const subtask_;
+ DISALLOW_COPY_AND_ASSIGN(ResolveTask);
+};
+#endif
+
+// A Buffer is used for walking over a DNS packet.
+class Buffer {
+ public:
+ Buffer(const uint8* p, unsigned len)
+ : p_(p),
+ packet_(p),
+ len_(len),
+ packet_len_(len) {
+ }
+
+ bool U8(uint8* v) {
+ if (len_ < 1)
+ return false;
+ *v = *p_;
+ p_++;
+ len_--;
+ return true;
+ }
+
+ bool U16(uint16* v) {
+ if (len_ < 2)
+ return false;
+ *v = static_cast<uint16>(p_[0]) << 8 |
+ static_cast<uint16>(p_[1]);
+ p_ += 2;
+ len_ -= 2;
+ return true;
+ }
+
+ bool U32(uint32* v) {
+ if (len_ < 4)
+ return false;
+ *v = static_cast<uint32>(p_[0]) << 24 |
+ static_cast<uint32>(p_[1]) << 16 |
+ static_cast<uint32>(p_[2]) << 8 |
+ static_cast<uint32>(p_[3]);
+ p_ += 4;
+ len_ -= 4;
+ return true;
+ }
+
+ bool Skip(unsigned n) {
+ if (len_ < n)
+ return false;
+ p_ += n;
+ len_ -= n;
+ return true;
+ }
+
+ bool Block(base::StringPiece* out, unsigned len) {
+ if (len_ < len)
+ return false;
+ *out = base::StringPiece(reinterpret_cast<const char*>(p_), len);
+ p_ += len;
+ len_ -= len;
+ return true;
+ }
+
+ // DNSName parses a (possibly compressed) DNS name from the packet. If |name|
+ // is not NULL, then the name is written into it. See RFC 1035 section 4.1.4.
+ bool DNSName(std::string* name) {
+ unsigned jumps = 0;
+ const uint8* p = p_;
+ unsigned len = len_;
+
+ if (name)
+ name->clear();
+
+ for (;;) {
+ if (len < 1)
+ return false;
+ uint8 d = *p;
+ p++;
+ len--;
+
+ // The two couple of bits of the length give the type of the length. It's
+ // either a direct length or a pointer to the remainder of the name.
+ if ((d & 0xc0) == 0xc0) {
+ // This limit matches the depth limit in djbdns.
+ if (jumps > 100)
+ return false;
+ if (len < 1)
+ return false;
+ uint16 offset = static_cast<uint16>(d) << 8 |
+ static_cast<uint16>(p[0]);
+ offset &= 0x3ff;
+ p++;
+ len--;
+
+ if (jumps == 0) {
+ p_ = p;
+ len_ = len;
+ }
+ jumps++;
+
+ if (offset >= packet_len_)
+ return false;
+ p = &packet_[offset];
+ } else if ((d & 0xc0) == 0) {
+ uint8 label_len = d;
+ if (len < label_len)
+ return false;
+ if (name && label_len) {
+ if (!name->empty())
+ name->append(".");
+ name->append(reinterpret_cast<const char*>(p), label_len);
+ }
+ p += label_len;
+ len -= label_len;
+
+ if (jumps == 0) {
+ p_ = p;
+ len_ = len;
+ }
+
+ if (label_len == 0)
+ break;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Buffer);
+
+ const uint8* p_;
+ const uint8* const packet_;
+ unsigned len_;
+ const unsigned packet_len_;
+};
+
+} // anonymous namespace
+
+bool RRResponse::ParseFromResponse(const uint8* p, unsigned len,
+ uint16 rrtype_requested) {
+#if defined(OS_POSIX)
+ name.clear();
+ ttl = 0;
+ dnssec = false;
+ rrdatas.clear();
+ signatures.clear();
+
+ // RFC 1035 section 4.4.1
+ uint8 flags2;
+ Buffer buf(p, len);
+ if (!buf.Skip(2) || // skip id
+ !buf.Skip(1) || // skip first flags byte
+ !buf.U8(&flags2)) {
+ return false;
+ }
+
+ // Bit 5 is the Authenticated Data (AD) bit. See
+ // http://tools.ietf.org/html/rfc2535#section-6.1
+ if (flags2 & 32) {
+ // AD flag is set. We'll trust it if it came from a local nameserver.
+ // Currently the resolv structure is IPv4 only, so we can't test for IPv6
+ // loopback addresses.
+ if (_res.nscount == 1 &&
+ memcmp(&_res.nsaddr_list[0].sin_addr,
+ "\x7f\x00\x00\x01" /* 127.0.0.1 */, 4) == 0) {
+ dnssec = true;
+ }
+ }
+
+ uint16 query_count, answer_count, authority_count, additional_count;
+ if (!buf.U16(&query_count) ||
+ !buf.U16(&answer_count) ||
+ !buf.U16(&authority_count) ||
+ !buf.U16(&additional_count)) {
+ return false;
+ }
+
+ if (query_count != 1)
+ return false;
+
+ uint16 type, klass;
+ if (!buf.DNSName(NULL) ||
+ !buf.U16(&type) ||
+ !buf.U16(&klass) ||
+ type != rrtype_requested ||
+ klass != kClassIN) {
+ return false;
+ }
+
+ if (answer_count < 1)
+ return false;
+
+ for (uint32 i = 0; i < answer_count; i++) {
+ std::string* name = NULL;
+ if (i == 0)
+ name = &this->name;
+ uint32 ttl;
+ uint16 rrdata_len;
+ if (!buf.DNSName(name) ||
+ !buf.U16(&type) ||
+ !buf.U16(&klass) ||
+ !buf.U32(&ttl) ||
+ !buf.U16(&rrdata_len)) {
+ return false;
+ }
+
+ base::StringPiece rrdata;
+ if (!buf.Block(&rrdata, rrdata_len))
+ return false;
+
+ if (klass == kClassIN && type == rrtype_requested) {
+ if (i == 0)
+ this->ttl = ttl;
+ rrdatas.push_back(std::string(rrdata.data(), rrdata.size()));
+ } else if (klass == kClassIN && type == kDNS_RRSIG) {
+ signatures.push_back(std::string(rrdata.data(), rrdata.size()));
+ }
+ }
+#endif // defined(OS_POSIX)
+
+ return true;
+}
+
+
+// static
+bool DnsRRResolver::Resolve(const std::string& name, uint16 rrtype,
+ uint16 flags, CompletionCallback* callback,
+ RRResponse* response) {
+ if (!callback || !response || name.empty())
+ return false;
+
+ // Don't allow queries of type ANY
+ if (rrtype == kDNS_ANY)
+ return false;
+
+ ResolveTask* task = new ResolveTask(name, rrtype, flags, callback, response,
+ MessageLoop::current());
+
+ return WorkerPool::PostTask(FROM_HERE, task, true /* task is slow */);
+}
+
+} // namespace net
diff --git a/net/base/dnsrr_resolver.h b/net/base/dnsrr_resolver.h
new file mode 100644
index 0000000..28bceaa
--- /dev/null
+++ b/net/base/dnsrr_resolver.h
@@ -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.
+
+#ifndef NET_BASE_DNSRR_RESOLVER_H_
+#define NET_BASE_DNSRR_RESOLVER_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+#include "net/base/completion_callback.h"
+
+namespace net {
+
+// RRResponse contains the result of a successful request for a resource record.
+struct RRResponse {
+ // name contains the canonical name of the resulting domain. If the queried
+ // name was a CNAME then this can differ.
+ std::string name;
+ // ttl contains the TTL of the resource records.
+ uint32 ttl;
+ // dnssec is true if the response was DNSSEC validated.
+ bool dnssec;
+ std::vector<std::string> rrdatas;
+ // sigs contains the RRSIG records returned.
+ std::vector<std::string> signatures;
+
+ // For testing only
+ bool ParseFromResponse(const uint8* data, unsigned len,
+ uint16 rrtype_requested);
+};
+
+// DnsRRResolver resolves arbitary DNS resource record types. It should not be
+// confused with HostResolver and should not be used to resolve A/AAAA records.
+//
+// HostResolver exists to lookup addresses and there are many details about
+// address resolution over and above DNS (i.e. Bonjour, VPNs etc).
+//
+// DnsRRResolver should only be used when the data is specifically DNS data and
+// the name is a fully qualified DNS domain.
+class DnsRRResolver {
+ public:
+ enum {
+ // Try harder to get a DNSSEC signed response. This doesn't mean that the
+ // RRResponse will always have the dnssec bit set.
+ FLAG_WANT_DNSSEC = 1,
+ };
+
+ // Resolve starts the resolution process. When complete, |callback| is called
+ // with a result. If the result is |OK| then |response| is filled with the
+ // result of the resolution. Note the |callback| is called on the current
+ // MessageLoop.
+ static bool Resolve(const std::string& name, uint16 rrtype,
+ uint16 flags, CompletionCallback* callback,
+ RRResponse* response);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DnsRRResolver);
+};
+
+} // namespace net
+
+#endif // NET_BASE_DNSRR_RESOLVER_H_
diff --git a/net/base/dnsrr_resolver_unittest.cc b/net/base/dnsrr_resolver_unittest.cc
new file mode 100644
index 0000000..23a0b40
--- /dev/null
+++ b/net/base/dnsrr_resolver_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 "net/base/dnsrr_resolver.h"
+
+#include "base/callback.h"
+#include "base/condition_variable.h"
+#include "base/lock.h"
+#include "net/base/dns_util.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class DnsRRResolverTest : public testing::Test {
+};
+
+#if defined(OS_LINUX)
+
+class Rendezvous : public CallbackRunner<Tuple1<int> > {
+ public:
+ Rendezvous()
+ : have_result_(false),
+ cv_(&lock_) {
+ }
+
+ int WaitForResult() {
+ lock_.Acquire();
+ while (!have_result_)
+ cv_.Wait();
+ lock_.Release();
+ return result_;
+ }
+
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ lock_.Acquire();
+ result_ = params.a;
+ have_result_ = true;
+ lock_.Release();
+ cv_.Broadcast();
+ }
+
+ private:
+ bool have_result_;
+ int result_;
+ Lock lock_;
+ ConditionVariable cv_;
+};
+
+// This test is disabled because it depends on the external network to pass.
+// However, it may be useful when chaging the code.
+TEST_F(DnsRRResolverTest, DISABLED_NetworkResolve) {
+ RRResponse response;
+ Rendezvous callback;
+ ASSERT_TRUE(DnsRRResolver::Resolve(
+ "agl._pka.imperialviolet.org", kDNS_TXT, 0, &callback, &response));
+ ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_EQ(1u, response.rrdatas.size());
+ ASSERT_EQ(1u, response.signatures.size());
+ ASSERT_STREQ("]v=pka1;fpr=2AF0032B48E856CE06157A1AD43C670DE04AAA74;"
+ "uri=http://www.imperialviolet.org/key.asc",
+ response.rrdatas[0].c_str());
+}
+
+// This is a DNS packet resulting from querying a recursive resolver for a TXT
+// record for agl._pka.imperialviolet.org. You should be able to get a
+// replacement from a packet capture should it ever be needed.
+static const uint8 kExamplePacket[] = {
+ 0xce, 0xfe, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x03,
+ 0x61, 0x67, 0x6c, 0x04, 0x5f, 0x70, 0x6b, 0x61, 0x0e, 0x69, 0x6d, 0x70, 0x65,
+ 0x72, 0x69, 0x61, 0x6c, 0x76, 0x69, 0x6f, 0x6c, 0x65, 0x74, 0x03, 0x6f, 0x72,
+ 0x67, 0x00, 0x00, 0x10, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x00, 0x01, 0x2c, 0x00, 0x5e, 0x5d, 0x76, 0x3d, 0x70, 0x6b, 0x61, 0x31, 0x3b,
+ 0x66, 0x70, 0x72, 0x3d, 0x32, 0x41, 0x46, 0x30, 0x30, 0x33, 0x32, 0x42, 0x34,
+ 0x38, 0x45, 0x38, 0x35, 0x36, 0x43, 0x45, 0x30, 0x36, 0x31, 0x35, 0x37, 0x41,
+ 0x31, 0x41, 0x44, 0x34, 0x33, 0x43, 0x36, 0x37, 0x30, 0x44, 0x45, 0x30, 0x34,
+ 0x41, 0x41, 0x41, 0x37, 0x34, 0x3b, 0x75, 0x72, 0x69, 0x3d, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6d, 0x70, 0x65, 0x72,
+ 0x69, 0x61, 0x6c, 0x76, 0x69, 0x6f, 0x6c, 0x65, 0x74, 0x2e, 0x6f, 0x72, 0x67,
+ 0x2f, 0x6b, 0x65, 0x79, 0x2e, 0x61, 0x73, 0x63, 0xc0, 0x0c, 0x00, 0x2e, 0x00,
+ 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0xc6, 0x00, 0x10, 0x05, 0x04, 0x00, 0x01,
+ 0x51, 0x80, 0x4c, 0x74, 0x2f, 0x1a, 0x4c, 0x4c, 0x9c, 0xeb, 0x45, 0xc9, 0x0e,
+ 0x69, 0x6d, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x76, 0x69, 0x6f, 0x6c, 0x65,
+ 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x3b, 0x6d, 0x3d, 0xbb, 0xae, 0x1b, 0x07,
+ 0x8d, 0xa9, 0xb0, 0xa7, 0xa5, 0x7a, 0x84, 0x24, 0x34, 0x29, 0x43, 0x36, 0x3f,
+ 0x5a, 0x48, 0x3b, 0x79, 0xa3, 0x16, 0xa4, 0x28, 0x5b, 0xd7, 0x03, 0xc6, 0x93,
+ 0xba, 0x4e, 0x93, 0x4d, 0x18, 0x5c, 0x98, 0xc2, 0x0d, 0x57, 0xd2, 0x6b, 0x9a,
+ 0x72, 0xbd, 0xe5, 0x8d, 0x10, 0x7b, 0x03, 0xe7, 0x19, 0x1e, 0x51, 0xe5, 0x7e,
+ 0x49, 0x6b, 0xa3, 0xa8, 0xf1, 0xd3, 0x1b, 0xff, 0x40, 0x26, 0x82, 0x65, 0xd0,
+ 0x74, 0x8e, 0xcf, 0xc9, 0x71, 0xea, 0x91, 0x57, 0x7e, 0x50, 0x61, 0x4d, 0x4b,
+ 0x77, 0x05, 0x6a, 0xd8, 0x3f, 0x12, 0x87, 0x50, 0xc2, 0x35, 0x13, 0xab, 0x01,
+ 0x78, 0xd2, 0x3a, 0x55, 0xa2, 0x89, 0xc8, 0x87, 0xe2, 0x7b, 0xec, 0x51, 0x7c,
+ 0xc0, 0x24, 0xb5, 0xa3, 0x33, 0x78, 0x98, 0x28, 0x8e, 0x9b, 0x6b, 0x88, 0x13,
+ 0x25, 0xfa, 0x1d, 0xdc, 0xf1, 0xf0, 0xa6, 0x8d, 0x2a, 0xbb, 0xbc, 0xb0, 0xc7,
+ 0x97, 0x98, 0x8e, 0xef, 0xd9, 0x12, 0x24, 0xee, 0x38, 0x50, 0xdb, 0xd3, 0x59,
+ 0xcc, 0x30, 0x54, 0x4c, 0x38, 0x94, 0x24, 0xbc, 0x75, 0xa5, 0xc0, 0xc4, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x15, 0x02, 0x62, 0x30, 0x03,
+ 0x6f, 0x72, 0x67, 0x0b, 0x61, 0x66, 0x69, 0x6c, 0x69, 0x61, 0x73, 0x2d, 0x6e,
+ 0x73, 0x74, 0xc0, 0xc4, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x3a, 0x00, 0x19, 0x02, 0x63, 0x30, 0x03, 0x6f, 0x72, 0x67, 0x0b, 0x61, 0x66,
+ 0x69, 0x6c, 0x69, 0x61, 0x73, 0x2d, 0x6e, 0x73, 0x74, 0x04, 0x69, 0x6e, 0x66,
+ 0x6f, 0x00, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00,
+ 0x05, 0x02, 0x61, 0x30, 0xc1, 0x99, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x3a, 0x00, 0x05, 0x02, 0x62, 0x32, 0xc1, 0x78, 0xc0, 0xc4, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x05, 0x02, 0x64, 0x30, 0xc1,
+ 0x78, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x05,
+ 0x02, 0x61, 0x32, 0xc1, 0x99, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00,
+};
+
+TEST_F(DnsRRResolverTest, ParseExample) {
+ RRResponse response;
+ ASSERT_TRUE(response.ParseFromResponse(kExamplePacket,
+ sizeof(kExamplePacket), kDNS_TXT));
+ ASSERT_EQ(1u, response.rrdatas.size());
+ ASSERT_EQ(1u, response.signatures.size());
+ ASSERT_STREQ("agl._pka.imperialviolet.org", response.name.c_str());
+ ASSERT_STREQ("]v=pka1;fpr=2AF0032B48E856CE06157A1AD43C670DE04AAA74;"
+ "uri=http://www.imperialviolet.org/key.asc",
+ response.rrdatas[0].c_str());
+ ASSERT_FALSE(response.dnssec);
+}
+
+TEST_F(DnsRRResolverTest, FuzzTruncation) {
+ RRResponse response;
+
+ for (unsigned len = sizeof(kExamplePacket); len <= sizeof(kExamplePacket);
+ len--) {
+ response.ParseFromResponse(kExamplePacket, len, kDNS_TXT);
+ }
+}
+
+TEST_F(DnsRRResolverTest, FuzzCorruption) {
+ RRResponse response;
+ uint8 copy[sizeof(kExamplePacket)];
+
+
+ for (unsigned bit_to_corrupt = 0; bit_to_corrupt < sizeof(kExamplePacket) * 8;
+ bit_to_corrupt++) {
+ unsigned byte = bit_to_corrupt >> 3;
+ unsigned bit = bit_to_corrupt & 7;
+
+ memcpy(copy, kExamplePacket, sizeof(copy));
+ copy[byte] ^= (1 << bit);
+
+ response.ParseFromResponse(copy, sizeof(copy), kDNS_TXT);
+ }
+}
+
+#endif // OS_LINUX
+
+} // namespace net
diff --git a/net/base/dnssec_chain_verifier.cc b/net/base/dnssec_chain_verifier.cc
new file mode 100644
index 0000000..2dbacbc
--- /dev/null
+++ b/net/base/dnssec_chain_verifier.cc
@@ -0,0 +1,809 @@
+// Copyright (c) 2010 The Chromium Authors. 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/dnssec_chain_verifier.h"
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/sha1.h"
+#include "base/sha2.h"
+#include "base/string_util.h"
+#include "net/base/dns_util.h"
+#include "net/base/dnssec_keyset.h"
+
+// We don't have a location for the spec yet, so we'll include it here until it
+// finds a better home.
+
+/*
+When connecting to a host www.example.com, www.example.com may present a certificate which includes a DNSSEC chain embedded in it. The aim of the embedded chain is to prove that the fingerprint of the public key is valid DNSSEC data. This is achieved by proving a CERT record for the target domain.
+
+Initially, the target domain is constructed by prepending _ssl. For example, the initial target domain for www.example.com is _ssl.www.example.com.
+
+A DNSSEC chain verifier can be in one of two states: entering a zone, or within a zone. Initially, the verifier is entering the root zone.
+
+When entering a zone, the verifier reads the following structure:
+
+uint8 entryKey
+uint16 signature length:
+ // See RRSIG RDATA in RFC 4043 for details
+ uint8 algorithm
+ uint8 labels
+ uint32 ttl
+ uint32 expires
+ uint32 begins
+ uint16 keyid
+ []byte signature
+uint8 numKeys
+// for each key:
+uint16 key length:
+ []byte DNSKEY RDATA
+
+|entryKey| indexes the array of DNSKEYs and MUST be less than |numKeys|. The indexed DNSKEY MUST be a key that the verifier trusts, either because it's the long-term root key, or because of a previously presented DS signature.
+
+If only a trusted key is needed within this zone, then the signature length MAY be zero. In which case, |entryKey| MUST be 0 and |numKeys| MUST be 1.
+
+After processing this data, the verifier trusts one or more keys for this zone.
+
+When within a zone, the verifier reads the following structure:
+
+dnsName name
+uint16 RRtype
+
+|name| is in DNS format (a series of 8-bit, length prefixed strings). No DNS name compression is permitted.
+
+|name| must be closer to the current target domain than the current zone. Here, 'closer' is defined as a greater number of matching labels when comparing right to left.
+
+|RRtype| may be either DS, CERT or CNAME:
+
+DS: this indicates a zone transition to a new zone named |name|. The verifier reads the following structure:
+ uint16 signature length:
+ ... (see above for the signature structure)
+ uint8 num_ds
+ // for each DS:
+ uint8 digest_type
+ uint16 length
+ []byte DS DATA
+
+The verifier is now entering the named zone. It reads ahead and extracts the entry key from the zone entry data and synthisises a DS record for the given digest type and verifies the signature. It then enters the next zone.
+
+
+CERT: |name| MUST match the target domain. The verifier reads the following structure:
+ uint16 signature length:
+ ... (see above for the signature structure)
+ []byte CERT RDATA
+
+(The format of the CERT RDATA isn't specified here, but the verifier must be able to extract a public key fingerprint in order to validate the original certificate.)
+
+This terminates the verification. There MUST NOT be any more data in the chain.
+
+
+CNAME: |name| MUST match the target domain. The verifier reads the following structure:
+ uint16 signature length:
+ ... (see above for the signature structure)
+ []byte CNAME RDATA
+
+This replaces the target domain with a new domain. The new domain is the target of the CNAME with _ssl prepended. The verifier is now in the zone that is the greatest common ancestor of the old and new target domains. (For example, when switching from _ssl.www.example.com to _ssl.www.example2.com, the verifier is now in com.)
+
+
+Example for www.google.com:
+
+The target domain is www.google.com.
+
+The verifier enters ., it already trusts the long-term root key and both root keys are presented in order to extend the trust to the smaller root key.
+
+A DS signature is presented for .com. The verifier is now entering .com.
+
+All four .com keys are presented. The verifier is now in .com.
+
+A DS signature is presented for google.com. The verifier is now entering google.com
+
+As google.com contains only a single DNSKEY, it is included without a signature. The verifier is now in google.com.
+
+A CNAME is presented for www.google.com pointing to www.l.google.com. The target domain is now www.l.google.com. The verifier is now in google.com.
+
+A DS signature is presented for l.google.com. The verifier is now entering l.google.com.
+
+As l.google.com contains only a single DNSKEY, it is included without a signature. The verifier is now in l.google.com.
+
+A CERT record is presented for www.l.google.com. The verification is complete.
+*/
+
+// This is the 2048-bit DNS root key: http://www.iana.org/dnssec
+// 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
+static const unsigned char kRootKey[] = {
+ 0x01, 0x01, 0x03, 0x08, 0x03, 0x01, 0x00, 0x01, 0xa8, 0x00, 0x20, 0xa9, 0x55,
+ 0x66, 0xba, 0x42, 0xe8, 0x86, 0xbb, 0x80, 0x4c, 0xda, 0x84, 0xe4, 0x7e, 0xf5,
+ 0x6d, 0xbd, 0x7a, 0xec, 0x61, 0x26, 0x15, 0x55, 0x2c, 0xec, 0x90, 0x6d, 0x21,
+ 0x16, 0xd0, 0xef, 0x20, 0x70, 0x28, 0xc5, 0x15, 0x54, 0x14, 0x4d, 0xfe, 0xaf,
+ 0xe7, 0xc7, 0xcb, 0x8f, 0x00, 0x5d, 0xd1, 0x82, 0x34, 0x13, 0x3a, 0xc0, 0x71,
+ 0x0a, 0x81, 0x18, 0x2c, 0xe1, 0xfd, 0x14, 0xad, 0x22, 0x83, 0xbc, 0x83, 0x43,
+ 0x5f, 0x9d, 0xf2, 0xf6, 0x31, 0x32, 0x51, 0x93, 0x1a, 0x17, 0x6d, 0xf0, 0xda,
+ 0x51, 0xe5, 0x4f, 0x42, 0xe6, 0x04, 0x86, 0x0d, 0xfb, 0x35, 0x95, 0x80, 0x25,
+ 0x0f, 0x55, 0x9c, 0xc5, 0x43, 0xc4, 0xff, 0xd5, 0x1c, 0xbe, 0x3d, 0xe8, 0xcf,
+ 0xd0, 0x67, 0x19, 0x23, 0x7f, 0x9f, 0xc4, 0x7e, 0xe7, 0x29, 0xda, 0x06, 0x83,
+ 0x5f, 0xa4, 0x52, 0xe8, 0x25, 0xe9, 0xa1, 0x8e, 0xbc, 0x2e, 0xcb, 0xcf, 0x56,
+ 0x34, 0x74, 0x65, 0x2c, 0x33, 0xcf, 0x56, 0xa9, 0x03, 0x3b, 0xcd, 0xf5, 0xd9,
+ 0x73, 0x12, 0x17, 0x97, 0xec, 0x80, 0x89, 0x04, 0x1b, 0x6e, 0x03, 0xa1, 0xb7,
+ 0x2d, 0x0a, 0x73, 0x5b, 0x98, 0x4e, 0x03, 0x68, 0x73, 0x09, 0x33, 0x23, 0x24,
+ 0xf2, 0x7c, 0x2d, 0xba, 0x85, 0xe9, 0xdb, 0x15, 0xe8, 0x3a, 0x01, 0x43, 0x38,
+ 0x2e, 0x97, 0x4b, 0x06, 0x21, 0xc1, 0x8e, 0x62, 0x5e, 0xce, 0xc9, 0x07, 0x57,
+ 0x7d, 0x9e, 0x7b, 0xad, 0xe9, 0x52, 0x41, 0xa8, 0x1e, 0xbb, 0xe8, 0xa9, 0x01,
+ 0xd4, 0xd3, 0x27, 0x6e, 0x40, 0xb1, 0x14, 0xc0, 0xa2, 0xe6, 0xfc, 0x38, 0xd1,
+ 0x9c, 0x2e, 0x6a, 0xab, 0x02, 0x64, 0x4b, 0x28, 0x13, 0xf5, 0x75, 0xfc, 0x21,
+ 0x60, 0x1e, 0x0d, 0xee, 0x49, 0xcd, 0x9e, 0xe9, 0x6a, 0x43, 0x10, 0x3e, 0x52,
+ 0x4d, 0x62, 0x87, 0x3d,
+};
+
+// kRootKeyID is the key id for kRootKey
+static const uint16 kRootKeyID = 19036;
+
+namespace net {
+
+struct DNSSECChainVerifier::Zone {
+ base::StringPiece name;
+ // The number of consecutive labels which |name| shares with |target_|,
+ // counting right-to-left from the root.
+ unsigned matching_labels;
+ DNSSECKeySet trusted_keys;
+ Zone* prev;
+};
+
+DNSSECChainVerifier::DNSSECChainVerifier(const std::string& target,
+ const base::StringPiece& chain)
+ : current_zone_(NULL),
+ target_(target),
+ chain_(chain),
+ ignore_timestamps_(false),
+ valid_(false),
+ already_entered_zone_(false),
+ rrtype_(0) {
+}
+
+DNSSECChainVerifier::~DNSSECChainVerifier() {
+ for (std::vector<void*>::iterator
+ i = scratch_pool_.begin(); i != scratch_pool_.end(); i++) {
+ free(*i);
+ }
+
+ Zone* next;
+ for (Zone* cur = current_zone_; cur; cur = next) {
+ next = cur->prev;
+ delete cur;
+ }
+}
+
+void DNSSECChainVerifier::IgnoreTimestamps() {
+ ignore_timestamps_ = true;
+}
+
+DNSSECChainVerifier::Error DNSSECChainVerifier::Verify() {
+ Error err;
+
+ err = EnterRoot();
+ if (err != OK)
+ return err;
+
+ for (;;) {
+ base::StringPiece next_name;
+ err = LeaveZone(&next_name);
+ if (err != OK)
+ return err;
+ if (valid_) {
+ if (!chain_.empty())
+ return BAD_DATA; // no trailing data allowed.
+ break;
+ }
+
+ if (already_entered_zone_) {
+ already_entered_zone_ = false;
+ } else {
+ err = EnterZone(next_name);
+ if (err != OK)
+ return err;
+ }
+ }
+
+ return OK;
+}
+
+uint16 DNSSECChainVerifier::rrtype() const {
+ DCHECK(valid_);
+ return rrtype_;
+}
+
+const std::vector<base::StringPiece>& DNSSECChainVerifier::rrdatas() const {
+ DCHECK(valid_);
+ return rrdatas_;
+}
+
+// U8 reads, and removes, a single byte from |chain_|
+bool DNSSECChainVerifier::U8(uint8* v) {
+ if (chain_.size() < 1)
+ return false;
+ *v = chain_[0];
+ chain_.remove_prefix(1);
+ return true;
+}
+
+// U16 reads, and removes, a big-endian uint16 from |chain_|
+bool DNSSECChainVerifier::U16(uint16* v) {
+ if (chain_.size() < 2)
+ return false;
+ const uint8* data = reinterpret_cast<const uint8*>(chain_.data());
+ *v = static_cast<uint16>(data[0]) << 8 |
+ static_cast<uint16>(data[1]);
+ chain_.remove_prefix(2);
+ return true;
+}
+
+// VariableLength16 reads, and removes, a big-endian, uint16, length-prefixed
+// chunk from |chain_|
+bool DNSSECChainVerifier::VariableLength16(base::StringPiece* v) {
+ uint16 length;
+ if (!U16(&length))
+ return false;
+ if (chain_.size() < length)
+ return false;
+ *v = chain_.substr(0, length);
+ chain_.remove_prefix(length);
+ return true;
+}
+
+// ReadName reads, and removes, an 8-bit length prefixed DNS name from |chain_|
+bool DNSSECChainVerifier::ReadName(base::StringPiece* v) {
+ base::StringPiece saved = chain_;
+ unsigned length = 0;
+ static const uint8 kMaxDNSLabelLen = 63;
+
+ for (;;) {
+ if (chain_.size() < 1)
+ return false;
+ uint8 label_len = chain_.data()[0];
+ chain_.remove_prefix(1);
+ if (label_len > kMaxDNSLabelLen)
+ return false;
+ length += 1 + label_len;
+
+ if (label_len == 0)
+ break;
+
+ if (chain_.size() < label_len)
+ return false;
+ chain_.remove_prefix(label_len);
+ }
+
+ *v = base::StringPiece(saved.data(), length);
+ return true;
+}
+
+// ReadAheadEntryKey returns the entry key when |chain_| is positioned at the
+// start of a zone.
+bool DNSSECChainVerifier::ReadAheadEntryKey(base::StringPiece* v) {
+ base::StringPiece saved = chain_;
+
+ uint8 entry_key;
+ base::StringPiece sig;
+ if (!U8(&entry_key) ||
+ !VariableLength16(&sig)) {
+ return false;
+ }
+
+ if (!ReadAheadKey(v, entry_key))
+ return false;
+ chain_ = saved;
+ return true;
+}
+
+// ReadAheadKey returns the entry key when |chain_| is positioned at the start
+// of a list of keys.
+bool DNSSECChainVerifier::ReadAheadKey(base::StringPiece* v, uint8 entry_key) {
+ base::StringPiece saved = chain_;
+
+ uint8 num_keys;
+ if (!U8(&num_keys))
+ return false;
+
+ for (unsigned i = 0; i < num_keys; i++) {
+ if (!VariableLength16(v))
+ return false;
+ if (i == entry_key) {
+ chain_ = saved;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DNSSECChainVerifier::ReadDNSKEYs(std::vector<base::StringPiece>* out,
+ bool is_root) {
+ uint8 num_keys;
+ if (!U8(&num_keys))
+ return false;
+
+ for (unsigned i = 0; i < num_keys; i++) {
+ base::StringPiece key;
+ if (!VariableLength16(&key))
+ return false;
+ if (key.size() == 0) {
+ if (!is_root)
+ return false;
+ key = base::StringPiece(reinterpret_cast<const char*>(kRootKey),
+ sizeof(kRootKey));
+ }
+
+ out->push_back(key);
+ }
+
+ return true;
+}
+
+// DigestKey calculates a DS digest as specified in
+// http://tools.ietf.org/html/rfc4034#section-5.1.4
+// name: the DNS form name of the key
+// dnskey: the DNSKEY's RRDATA
+// digest_type: see http://tools.ietf.org/html/rfc4034#appendix-A.2
+// keyid: the key's id
+// algorithm: see http://tools.ietf.org/html/rfc4034#appendix-A.1
+bool DNSSECChainVerifier::DigestKey(base::StringPiece* out,
+ const base::StringPiece& name,
+ const base::StringPiece& dnskey,
+ uint8 digest_type,
+ uint16 keyid,
+ uint8 algorithm) {
+ std::string temp;
+ uint8 temp2[base::SHA256_LENGTH];
+ const uint8* digest;
+ unsigned digest_len;
+
+ std::string input = name.as_string() + dnskey.as_string();
+
+ if (digest_type == kDNSSEC_SHA1) {
+ temp = base::SHA1HashString(input);
+ digest = reinterpret_cast<const uint8*>(temp.data());
+ digest_len = base::SHA1_LENGTH;
+ } else if (digest_type == kDNSSEC_SHA256) {
+ base::SHA256HashString(input, temp2, sizeof(temp2));
+ digest = temp2;
+ digest_len = sizeof(temp2);
+ } else {
+ return false;
+ }
+
+ uint8* output = static_cast<uint8*>(malloc(4 + digest_len));
+ scratch_pool_.push_back(output);
+ output[0] = static_cast<uint8>(keyid >> 8);
+ output[1] = static_cast<uint8>(keyid);
+ output[2] = algorithm;
+ output[3] = digest_type;
+ memcpy(output + 4, digest, digest_len);
+ *out = base::StringPiece(reinterpret_cast<char*>(output), 4 + digest_len);
+ return true;
+}
+
+// EnterRoot enters the root zone at the beginning of the chain. This is
+// special because no DS record lead us here: we have to validate that the
+// entry key is the DNS root key that we already know and trust. Additionally,
+// for the root zone only, the keyid of the entry key is prepended to the data.
+DNSSECChainVerifier::Error DNSSECChainVerifier::EnterRoot() {
+ uint16 root_keyid;
+
+ if (!U16(&root_keyid))
+ return BAD_DATA;
+
+ if (root_keyid != kRootKeyID)
+ return UNKNOWN_ROOT_KEY;
+
+ base::StringPiece root_key;
+ if (!ReadAheadEntryKey(&root_key))
+ return BAD_DATA;
+
+ // If the root key is given then it must match the expected root key exactly.
+ if (root_key.size()) {
+ if (root_key.size() != sizeof(kRootKey) ||
+ memcmp(root_key.data(), kRootKey, sizeof(kRootKey))) {
+ return UNKNOWN_ROOT_KEY;
+ }
+ }
+
+ base::StringPiece root("", 1);
+ return EnterZone(root);
+}
+
+// EnterZone enters a new DNS zone. On entry it's assumed that the entry key
+// has been validated.
+DNSSECChainVerifier::Error DNSSECChainVerifier::EnterZone(
+ const base::StringPiece& zone) {
+ Zone* prev = current_zone_;
+ current_zone_ = new Zone;
+ current_zone_->prev = prev;
+ current_zone_->name = zone;
+ current_zone_->matching_labels = MatchingLabels(target_, zone);
+ if (ignore_timestamps_)
+ current_zone_->trusted_keys.IgnoreTimestamps();
+
+ uint8 entry_key;
+ base::StringPiece sig;
+ if (!U8(&entry_key) ||
+ !VariableLength16(&sig)) {
+ return BAD_DATA;
+ }
+
+ base::StringPiece key;
+ if (!ReadAheadKey(&key, entry_key))
+ return BAD_DATA;
+
+ if (zone.size() == 1 && key.size() == 0) {
+ // If a key is omitted in the root zone then it's the root key.
+ key = base::StringPiece(reinterpret_cast<const char*>(kRootKey),
+ sizeof(kRootKey));
+ }
+ if (!current_zone_->trusted_keys.AddKey(key))
+ return BAD_DATA;
+
+ std::vector<base::StringPiece> dnskeys;
+ if (!ReadDNSKEYs(&dnskeys, zone.size() == 1))
+ return BAD_DATA;
+
+ if (sig.size() == 0) {
+ // An omitted signature on the keys means that only the entry key is used.
+ if (dnskeys.size() > 1 || entry_key != 0)
+ return BAD_DATA;
+ return OK;
+ }
+
+ if (!current_zone_->trusted_keys.CheckSignature(
+ zone, zone, sig, kDNS_DNSKEY, dnskeys)) {
+ return BAD_SIGNATURE;
+ }
+
+ // Add all the keys as trusted.
+ for (unsigned i = 0; i < dnskeys.size(); i++) {
+ if (i == entry_key)
+ continue;
+ current_zone_->trusted_keys.AddKey(dnskeys[i]);
+ }
+
+ return OK;
+}
+
+// CountLabels returns the number of DNS labels in |a|, which must be in DNS,
+// length-prefixed form.
+static unsigned CountLabels(base::StringPiece a) {
+ for (unsigned c = 0;; c++) {
+ if (!a.size())
+ return c;
+ uint8 label_len = a.data()[0];
+ a.remove_prefix(1);
+ DCHECK_GE(a.size(), label_len);
+ a.remove_prefix(label_len);
+ }
+}
+
+// LeaveZone transitions out of the current zone, either by following DS
+// records to validate the entry key of the next zone, or because the final
+// resource records are given.
+DNSSECChainVerifier::Error DNSSECChainVerifier::LeaveZone(
+ base::StringPiece* next_name) {
+ base::StringPiece sig;
+ uint16 rrtype;
+ Error err;
+
+ if (!ReadName(next_name) ||
+ !U16(&rrtype) ||
+ !VariableLength16(&sig)) {
+ return BAD_DATA;
+ }
+
+ std::vector<base::StringPiece> rrdatas;
+
+ if (rrtype == kDNS_DS) {
+ err = ReadDSSet(&rrdatas, *next_name);
+ } else if (rrtype == kDNS_CERT || rrtype == kDNS_TXT) {
+ err = ReadGenericRRs(&rrdatas);
+ } else if (rrtype == kDNS_CNAME) {
+ err = ReadCNAME(&rrdatas);
+ } else {
+ return UNKNOWN_TERMINAL_RRTYPE;
+ }
+ if (err != OK)
+ return err;
+
+ if (!current_zone_->trusted_keys.CheckSignature(
+ *next_name, current_zone_->name, sig, rrtype, rrdatas)) {
+ return BAD_SIGNATURE;
+ }
+
+ if (rrtype == kDNS_DS) {
+ // If we are transitioning to another zone then the next zone must be
+ // 'closer' to the target than the current zone.
+ if (MatchingLabels(target_, *next_name) <= current_zone_->matching_labels)
+ return OFF_COURSE;
+ } else if (rrtype == kDNS_CERT || rrtype == kDNS_TXT) {
+ // If this is the final entry in the chain then the name must match target_
+ if (next_name->size() != target_.size() ||
+ memcmp(next_name->data(), target_.data(), target_.size())) {
+ return BAD_TARGET;
+ }
+ rrdatas_ = rrdatas;
+ valid_ = true;
+ rrtype_ = rrtype;
+ } else if (rrtype == kDNS_CNAME) {
+ // A CNAME must match the current target. Then we update the current target
+ // and unwind the chain to the closest common ancestor.
+ if (next_name->size() != target_.size() ||
+ memcmp(next_name->data(), target_.data(), target_.size())) {
+ return BAD_TARGET;
+ }
+ DCHECK_EQ(1u, rrdatas.size());
+ target_ = rrdatas[0].as_string();
+ // We unwind the zones until the current zone is a (non-strict) subset of
+ // the new target.
+ while (MatchingLabels(target_, current_zone_->name) <
+ CountLabels(current_zone_->name)) {
+ Zone* prev = current_zone_->prev;
+ delete current_zone_;
+ current_zone_ = prev;
+ if (!current_zone_) {
+ NOTREACHED();
+ return BAD_DATA;
+ }
+ }
+ already_entered_zone_ = true;
+ } else {
+ NOTREACHED();
+ return UNKNOWN_TERMINAL_RRTYPE;
+ }
+
+ return OK;
+}
+
+// ReadDSSet reads a set of DS records from the chain. DS records which are
+// omitted are calculated from the entry key of the next zone.
+DNSSECChainVerifier::Error DNSSECChainVerifier::ReadDSSet(
+ std::vector<base::StringPiece>* rrdatas,
+ const base::StringPiece& next_name) {
+ uint8 num_ds;
+ if (!U8(&num_ds))
+ return BAD_DATA;
+ scoped_array<uint8> digest_types(new uint8[num_ds]);
+ // lookahead[i] is true iff the i'th DS record was empty and needs to be
+ // computed by hashing the next entry key.
+ scoped_array<bool> lookahead(new bool[num_ds]);
+ rrdatas->resize(num_ds);
+
+ for (unsigned i = 0; i < num_ds; i++) {
+ uint8 digest_type;
+ base::StringPiece digest;
+ if (!U8(&digest_type) ||
+ !VariableLength16(&digest)) {
+ return BAD_DATA;
+ }
+
+ digest_types[i] = digest_type;
+ if (digest.size() > 0) {
+ (*rrdatas)[i] = digest;
+ lookahead[i] = false;
+ } else {
+ lookahead[i] = true;
+ }
+ }
+
+ base::StringPiece next_entry_key;
+ if (!ReadAheadEntryKey(&next_entry_key))
+ return BAD_DATA;
+ if (next_entry_key.size() < 4)
+ return BAD_DATA;
+ uint16 keyid = DNSSECKeySet::DNSKEYToKeyID(next_entry_key);
+ uint8 algorithm = next_entry_key[3];
+
+ bool good = false;
+ for (unsigned i = 0; i < num_ds; i++) {
+ base::StringPiece digest;
+ bool have_digest = false;
+ if (DigestKey(&digest, next_name, next_entry_key, digest_types[i],
+ keyid, algorithm)) {
+ have_digest = true;
+ }
+
+ if (lookahead[i]) {
+ // If we needed to fill in one of the DS entries, but we can't calculate
+ // that type of digest, then we can't continue.
+ if (!have_digest)
+ return UNKNOWN_DIGEST;
+ (*rrdatas)[i] = digest;
+ good = true;
+ } else {
+ const base::StringPiece& given_digest = (*rrdatas)[i];
+ if (have_digest &&
+ given_digest.size() == digest.size() &&
+ memcmp(given_digest.data(), digest.data(), digest.size()) == 0) {
+ good = true;
+ }
+ }
+ }
+
+ if (!good) {
+ // We didn't calculate or match any of the digests.
+ return NO_DS_LINK;
+ }
+
+ return OK;
+}
+
+DNSSECChainVerifier::Error DNSSECChainVerifier::ReadGenericRRs(
+ std::vector<base::StringPiece>* rrdatas) {
+ uint8 num_rrs;
+ if (!U8(&num_rrs))
+ return BAD_DATA;
+ rrdatas->resize(num_rrs);
+
+ for (unsigned i = 0; i < num_rrs; i++) {
+ base::StringPiece rrdata;
+ if (!VariableLength16(&rrdata))
+ return BAD_DATA;
+ (*rrdatas)[i] = rrdata;
+ }
+
+ return OK;
+}
+
+DNSSECChainVerifier::Error DNSSECChainVerifier::ReadCNAME(
+ std::vector<base::StringPiece>* rrdatas) {
+ base::StringPiece name;
+ if (!ReadName(&name))
+ return BAD_DATA;
+
+ rrdatas->resize(1);
+ (*rrdatas)[0] = name;
+ return OK;
+}
+
+// static
+std::map<std::string, std::string>
+DNSSECChainVerifier::ParseTLSTXTRecord(base::StringPiece rrdata) {
+ std::map<std::string, std::string> ret;
+
+ if (rrdata.empty())
+ return ret;
+
+ std::string txt;
+ txt.reserve(rrdata.size());
+
+ // TXT records are a series of 8-bit length prefixed substrings that we
+ // concatenate into |txt|
+ while (!rrdata.empty()) {
+ unsigned len = rrdata[0];
+ if (len == 0 || len + 1 > rrdata.size())
+ return ret;
+ txt.append(rrdata.data() + 1, len);
+ rrdata.remove_prefix(len + 1);
+ }
+
+ // We append a space to |txt| to make the parsing code, below, cleaner.
+ txt.append(" ");
+
+ // RECORD = KV (' '+ KV)*
+ // KV = KEY '=' VALUE
+ // KEY = [a-zA-Z0-9]+
+ // VALUE = [^ \0]*
+
+ enum State {
+ STATE_KEY,
+ STATE_VALUE,
+ STATE_SPACE,
+ };
+
+ State state = STATE_KEY;
+
+ std::map<std::string, std::string> m;
+
+ unsigned start = 0;
+ std::string key;
+
+ for (unsigned i = 0; i < txt.size(); i++) {
+ char c = txt[i];
+ if (c == 0)
+ return ret; // NUL values are never allowed.
+
+ switch (state) {
+ case STATE_KEY:
+ if (c == '=') {
+ if (i == start)
+ return ret; // zero length keys are not allowed.
+ key = txt.substr(start, i - start);
+ start = i + 1;
+ state = STATE_VALUE;
+ continue;
+ }
+ if (!IsAsciiAlpha(c) && !IsAsciiDigit(c))
+ return ret; // invalid key value
+ break;
+ case STATE_VALUE:
+ if (c == ' ') {
+ if (m.find(key) == m.end())
+ m.insert(make_pair(key, txt.substr(start, i - start)));
+ state = STATE_SPACE;
+ continue;
+ }
+ break;
+ case STATE_SPACE:
+ if (c != ' ') {
+ start = i;
+ i--;
+ state = STATE_KEY;
+ continue;
+ }
+ break;
+ default:
+ NOTREACHED();
+ return ret;
+ }
+ }
+
+ if (state != STATE_SPACE)
+ return ret;
+
+ ret.swap(m);
+ return ret;
+}
+
+// RemoveLeadingLabel removes the first label from |a|, which must be in DNS,
+// length-prefixed form.
+static void RemoveLeadingLabel(base::StringPiece* a) {
+ if (!a->size())
+ return;
+ uint8 label_len = a->data()[0];
+ a->remove_prefix(1);
+ a->remove_prefix(label_len);
+}
+
+// MatchingLabels returns the number of labels which |a| and |b| share,
+// counting right-to-left from the root. |a| and |b| must be DNS,
+// length-prefixed names. All names match at the root label, so this always
+// returns a value >= 1.
+
+// static
+unsigned DNSSECChainVerifier::MatchingLabels(base::StringPiece a,
+ base::StringPiece b) {
+ unsigned c = 0;
+ unsigned a_labels = CountLabels(a);
+ unsigned b_labels = CountLabels(b);
+
+ while (a_labels > b_labels) {
+ RemoveLeadingLabel(&a);
+ a_labels--;
+ }
+ while (b_labels > a_labels) {
+ RemoveLeadingLabel(&b);
+ b_labels--;
+ }
+
+ for (;;) {
+ if (!a.size()) {
+ if (!b.size())
+ return c;
+ return 0;
+ }
+ if (!b.size())
+ return 0;
+ uint8 a_length = a.data()[0];
+ a.remove_prefix(1);
+ uint8 b_length = b.data()[0];
+ b.remove_prefix(1);
+ DCHECK_GE(a.size(), a_length);
+ DCHECK_GE(b.size(), b_length);
+
+ if (a_length == b_length && memcmp(a.data(), b.data(), a_length) == 0) {
+ c++;
+ } else {
+ c = 0;
+ }
+
+ a.remove_prefix(a_length);
+ b.remove_prefix(b_length);
+ }
+}
+
+} // namespace net
diff --git a/net/base/dnssec_chain_verifier.h b/net/base/dnssec_chain_verifier.h
new file mode 100644
index 0000000..60376c0
--- /dev/null
+++ b/net/base/dnssec_chain_verifier.h
@@ -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.
+
+#ifndef NET_BASE_DNSSEC_CHAIN_VERIFIER_H_
+#define NET_BASE_DNSSEC_CHAIN_VERIFIER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/string_piece.h"
+
+namespace net {
+
+// DNSSECChainVerifier verifies a chain of DNSSEC records. These records
+// eventually prove the validity of a set of resource records for the target
+// name. For example, if the fingerprint of a certificate was stored in a CERT
+// record for a given domain, then a chain could prove the validity of that
+// fingerprint.
+class DNSSECChainVerifier {
+ public:
+ enum Error {
+ OK = 0,
+ BAD_DATA, // The chain was corrupt in some fashion.
+ UNKNOWN_ROOT_KEY, // The chain is assuming an unknown DNS root.
+ UNKNOWN_DIGEST, // An omitted DS record used an unknown hash function.
+ UNKNOWN_TERMINAL_RRTYPE, // The chain proved an unknown RRTYPE.
+ BAD_SIGNATURE, // One of the signature was incorrect.
+ NO_DS_LINK, // a DS set didn't include the next entry key.
+ OFF_COURSE, // the chain is diverging from the target name.
+ BAD_TARGET, // the chain didn't end up at the target.
+ };
+
+ // |target|: the target hostname. This must be in canonical (all
+ // lower-case), length-prefixed DNS form. For example:
+ // "\003www\007example\003com\000"
+ // |chain|: the contents of the chain.
+ DNSSECChainVerifier(const std::string& target,
+ const base::StringPiece& chain);
+ ~DNSSECChainVerifier();
+
+ // If called, timestamps in the signatures will be ignored. This is for
+ // testing only.
+ void IgnoreTimestamps();
+
+ // Verify verifies the chain. Returns |OK| on success.
+ Error Verify();
+
+ // rrtype returns the RRTYPE of the proven resource records. Only call this
+ // after Verify has returned OK.
+ uint16 rrtype() const;
+ // rrdatas returns the contents of the proven resource records. Only call
+ // this after Verify has returned OK.
+ const std::vector<base::StringPiece>& rrdatas() const;
+
+ // ParseTLSTXTRecord parses a TXT record which should contain TLS fingerprint
+ // information.
+ // rrdata: the raw TXT RRDATA from DNS
+ // returns: an empty map on failure, or the result of the parse.
+ static std::map<std::string, std::string>
+ ParseTLSTXTRecord(base::StringPiece rrdata);
+
+ // Exposed for testing only.
+ static unsigned MatchingLabels(base::StringPiece a,
+ base::StringPiece b);
+
+ private:
+ struct Zone;
+
+ bool U8(uint8*);
+ bool U16(uint16*);
+ bool VariableLength16(base::StringPiece*);
+ bool ReadName(base::StringPiece*);
+
+ bool ReadAheadEntryKey(base::StringPiece*);
+ bool ReadAheadKey(base::StringPiece*, uint8 entry_key);
+ bool ReadDNSKEYs(std::vector<base::StringPiece>*, bool is_root);
+ bool DigestKey(base::StringPiece* digest,
+ const base::StringPiece& name,
+ const base::StringPiece& dnskey,
+ uint8 digest_type,
+ uint16 keyid,
+ uint8 algorithm);
+
+ Error EnterRoot();
+ Error EnterZone(const base::StringPiece& zone);
+ Error LeaveZone(base::StringPiece* next_name);
+ Error ReadDSSet(std::vector<base::StringPiece>*,
+ const base::StringPiece& next_name);
+ Error ReadGenericRRs(std::vector<base::StringPiece>*);
+ Error ReadCNAME(std::vector<base::StringPiece>*);
+
+ Zone* current_zone_;
+ std::string target_;
+ base::StringPiece chain_;
+ bool ignore_timestamps_;
+ bool valid_;
+ // already_entered_zone_ is set to true when we unwind a Zone chain and start
+ // off from a point where we have already entered a zone.
+ bool already_entered_zone_;
+ uint16 rrtype_;
+ std::vector<base::StringPiece> rrdatas_;
+ // A list of pointers which need to be free()ed on destruction.
+ std::vector<void*> scratch_pool_;
+};
+
+} // namespace net
+
+#endif // NET_BASE_DNSSEC_CHAIN_VERIFIER_H_
diff --git a/net/base/dnssec_keyset.cc b/net/base/dnssec_keyset.cc
new file mode 100644
index 0000000..70aa217
--- /dev/null
+++ b/net/base/dnssec_keyset.cc
@@ -0,0 +1,457 @@
+// Copyright (c) 2010 The Chromium Authors. 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/dnssec_keyset.h"
+
+#include <cryptohi.h>
+#include <cryptoht.h>
+#include <keyhi.h>
+
+#include "base/crypto/signature_verifier.h"
+#include "base/logging.h"
+#include "base/nss_util.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "net/base/dns_util.h"
+
+namespace net {
+
+DNSSECKeySet::DNSSECKeySet()
+ : ignore_timestamps_(false) {
+}
+
+DNSSECKeySet::~DNSSECKeySet() {
+}
+
+bool DNSSECKeySet::AddKey(const base::StringPiece& dnskey) {
+ uint16 keyid = DNSKEYToKeyID(dnskey);
+ std::string der_encoded = ASN1WrapDNSKEY(dnskey);
+ if (der_encoded.empty())
+ return false;
+
+ keyids_.push_back(keyid);
+ public_keys_.push_back(der_encoded);
+ return true;
+}
+
+// static
+uint16 DNSSECKeySet::DNSKEYToKeyID(const base::StringPiece& dnskey) {
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(dnskey.data());
+
+ // RFC 4043: App B
+ uint32 ac = 0;
+ for (unsigned i = 0; i < dnskey.size(); i++) {
+ if (i & 1) {
+ ac += data[i];
+ } else {
+ ac += static_cast<uint32>(data[i]) << 8;
+ }
+ }
+ ac += (ac >> 16) & 0xffff;
+ return ac;
+}
+
+// These are encoded AlgorithmIdentifiers for the given signature algorithm.
+static const unsigned char kRSAWithSHA1[] = {
+ 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x5, 5, 0
+};
+
+static const unsigned char kRSAWithSHA256[] = {
+ 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0xb, 5, 0
+};
+
+bool DNSSECKeySet::CheckSignature(
+ const base::StringPiece& name,
+ const base::StringPiece& zone,
+ const base::StringPiece& signature,
+ uint16 rrtype,
+ const std::vector<base::StringPiece>& rrdatas) {
+ // signature has this format:
+ // algorithm uint8
+ // labels uint8
+ // ttl uint32
+ // expires uint32
+ // begins uint32
+ // keyid uint16
+ //
+ // followed by the actual signature.
+ if (signature.size() < 16)
+ return false;
+ const unsigned char* sigdata =
+ reinterpret_cast<const unsigned char*>(signature.data());
+
+ uint8 algorithm = sigdata[0];
+ uint32 expires = static_cast<uint32>(sigdata[6]) << 24 |
+ static_cast<uint32>(sigdata[7]) << 16 |
+ static_cast<uint32>(sigdata[8]) << 8 |
+ static_cast<uint32>(sigdata[9]);
+ uint32 begins = static_cast<uint32>(sigdata[10]) << 24 |
+ static_cast<uint32>(sigdata[11]) << 16 |
+ static_cast<uint32>(sigdata[12]) << 8 |
+ static_cast<uint32>(sigdata[13]);
+ uint16 keyid = static_cast<uint16>(sigdata[14]) << 8 |
+ static_cast<uint16>(sigdata[15]);
+
+ if (!ignore_timestamps_) {
+ uint32 now = static_cast<uint32>(base::Time::Now().ToTimeT());
+ if (now < begins || now >= expires)
+ return false;
+ }
+
+ base::StringPiece sig(signature.data() + 16, signature.size() - 16);
+
+ // You should have RFC 4034, 3.1.8.1 open when reading this code.
+ unsigned signed_data_len = 0;
+ signed_data_len += 2; // rrtype
+ signed_data_len += 16; // (see signature format, above)
+ signed_data_len += zone.size();
+
+ for (std::vector<base::StringPiece>::const_iterator
+ i = rrdatas.begin(); i != rrdatas.end(); i++) {
+ signed_data_len += name.size();
+ signed_data_len += 2; // rrtype
+ signed_data_len += 2; // class
+ signed_data_len += 4; // ttl
+ signed_data_len += 2; // RRDATA length
+ signed_data_len += i->size();
+ }
+
+ scoped_array<unsigned char> signed_data(new unsigned char[signed_data_len]);
+ unsigned j = 0;
+
+ signed_data[j++] = static_cast<uint8>(rrtype >> 8);
+ signed_data[j++] = static_cast<uint8>(rrtype);
+ memcpy(&signed_data[j], sigdata, 16);
+ j += 16;
+ memcpy(&signed_data[j], zone.data(), zone.size());
+ j += zone.size();
+
+ for (std::vector<base::StringPiece>::const_iterator
+ i = rrdatas.begin(); i != rrdatas.end(); i++) {
+ memcpy(&signed_data[j], name.data(), name.size());
+ j += name.size();
+ signed_data[j++] = static_cast<uint8>(rrtype >> 8);
+ signed_data[j++] = static_cast<uint8>(rrtype);
+ signed_data[j++] = 0; // CLASS (always IN = 1)
+ signed_data[j++] = 1;
+ // Copy the TTL from |signature|.
+ memcpy(&signed_data[j], signature.data() + 2, sizeof(uint32));
+ j += sizeof(uint32);
+ unsigned rrdata_len = i->size();
+ signed_data[j++] = rrdata_len >> 8;
+ signed_data[j++] = rrdata_len;
+ memcpy(&signed_data[j], i->data(), i->size());
+ j += i->size();
+ }
+
+ DCHECK_EQ(j, signed_data_len);
+
+ base::StringPiece signature_algorithm;
+ if (algorithm == kDNSSEC_RSA_SHA1 ||
+ algorithm == kDNSSEC_RSA_SHA1_NSEC3) {
+ signature_algorithm = base::StringPiece(
+ reinterpret_cast<const char*>(kRSAWithSHA1),
+ sizeof(kRSAWithSHA1));
+ } else if (algorithm == kDNSSEC_RSA_SHA256) {
+ signature_algorithm = base::StringPiece(
+ reinterpret_cast<const char*>(kRSAWithSHA256),
+ sizeof(kRSAWithSHA256));
+ } else {
+ // Unknown algorithm.
+ return false;
+ }
+
+ // Check the signature with each trusted key which has a matching keyid.
+ DCHECK_EQ(public_keys_.size(), keyids_.size());
+ for (unsigned i = 0; i < public_keys_.size(); i++) {
+ if (keyids_[i] != keyid)
+ continue;
+
+ if (VerifySignature(
+ signature_algorithm, sig, public_keys_[i],
+ base::StringPiece(reinterpret_cast<const char*>(signed_data.get()),
+ signed_data_len))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DNSSECKeySet::IgnoreTimestamps() {
+ ignore_timestamps_ = true;
+}
+
+// This is an ASN.1 encoded AlgorithmIdentifier for RSA
+static const unsigned char kASN1AlgorithmIdentifierRSA[] = {
+ 0x30, // SEQUENCE
+ 0x0d, // length (11 bytes)
+ 0x06, // OBJECT IDENTIFER
+ 0x09, // length (9 bytes)
+ // OID 1.2.840.113549.1.1.1 (RSA)
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ // NULL of length 0
+ 0x05, 0x00,
+};
+
+// EncodeASN1Length assumes that |*length| contains the number of DER-encoded,
+// length-prefixed ASN.1 bytes to follow and serialises the length to |out[*j]|
+// and updates |j| and |length| accordingly.
+static void EncodeASN1Length(unsigned char* out, unsigned* j,
+ unsigned* length) {
+ if ((*length - 1) < 128) {
+ (*length) -= 1;
+ out[(*j)++] = *length;
+ } else if ((*length - 2) < 256) {
+ (*length) -= 2;
+ out[(*j)++] = 0x80 | 1;
+ out[(*j)++] = *length;
+ } else {
+ (*length) -= 3;
+ out[(*j)++] = 0x80 | 2;
+ out[(*j)++] = *length >> 8;
+ out[(*j)++] = *length;
+ }
+}
+
+// AdvanceForASN1Length returns the number of bytes required to encode a ASN1
+// DER length value of |remaining|.
+static unsigned AdvanceForASN1Length(unsigned remaining) {
+ if (remaining < 128) {
+ return 1;
+ } else if (remaining < 256) {
+ return 2;
+ } else if (remaining < 65536) {
+ return 3;
+ } else {
+ NOTREACHED();
+ return 3;
+ }
+}
+
+// ASN1WrapDNSKEY converts the DNSKEY RDATA in |dnskey| into the ASN.1 wrapped
+// format expected by NSS. To wit:
+// SubjectPublicKeyInfo ::= SEQUENCE {
+// algorithm AlgorithmIdentifier,
+// subjectPublicKey BIT STRING }
+std::string DNSSECKeySet::ASN1WrapDNSKEY(const base::StringPiece& dnskey) {
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(dnskey.data());
+
+ if (dnskey.size() < 5 || dnskey.size() > 32767)
+ return "";
+ const uint8 algorithm = data[3];
+ if (algorithm != kDNSSEC_RSA_SHA1 &&
+ algorithm != kDNSSEC_RSA_SHA1_NSEC3 &&
+ algorithm != kDNSSEC_RSA_SHA256) {
+ return "";
+ }
+
+ unsigned exp_length;
+ unsigned exp_offset;
+ // First we extract the public exponent.
+ if (data[4] == 0) {
+ if (dnskey.size() < 7)
+ return "";
+ exp_length = static_cast<unsigned>(data[5]) << 8 |
+ static_cast<unsigned>(data[6]);
+ exp_offset = 7;
+ } else {
+ exp_length = static_cast<unsigned>(data[4]);
+ exp_offset = 5;
+ }
+
+ // We refuse to deal with large public exponents.
+ if (exp_length > 3)
+ return "";
+ if (dnskey.size() < exp_offset + exp_length)
+ return "";
+
+ unsigned exp = 0;
+ for (unsigned i = 0; i < exp_length; i++) {
+ exp <<= 8;
+ exp |= static_cast<unsigned>(data[exp_offset + i]);
+ }
+
+ unsigned n_offset = exp_offset + exp_length;
+ unsigned n_length = dnskey.size() - n_offset;
+
+ // Anything smaller than 512 bits is too weak to be trusted.
+ if (n_length < 64)
+ return "";
+
+ // If the MSB of exp is true then we need to prefix a zero byte to stop the
+ // ASN.1 encoding from being negative.
+ if (exp & (1 << ((8 * exp_length) - 1)))
+ exp_length++;
+
+ // Likewise with the modulus
+ unsigned n_padding = data[n_offset] & 0x80 ? 1 : 0;
+
+ // We now calculate the length of the full ASN.1 encoded public key. We're
+ // working backwards from the end of the structure. Keep in mind that it's:
+ // SEQUENCE
+ // AlgorithmIdentifier
+ // BITSTRING
+ // SEQUENCE
+ // INTEGER
+ // INTEGER
+ unsigned length = 0;
+ length += exp_length; // exponent data
+ length++; // we know that |exp_length| < 128
+ length++; // INTEGER tag for exponent
+ length += n_length + n_padding;
+ length += AdvanceForASN1Length(n_length + n_padding);
+ length++; // INTEGER tag for modulus
+ length += AdvanceForASN1Length(length); // SEQUENCE length
+ length++; // SEQUENCE tag
+ length++; // BITSTRING unused bits
+ length += AdvanceForASN1Length(length); // BITSTRING length
+ length++; // BITSTRING tag
+ length += sizeof(kASN1AlgorithmIdentifierRSA);
+ length += AdvanceForASN1Length(length); // SEQUENCE length
+ length++; // SEQUENCE tag
+
+ scoped_array<unsigned char> out(new unsigned char[length]);
+
+ // Now we walk forwards and serialise the ASN.1, undoing the steps above.
+ unsigned j = 0;
+ out[j++] = 0x30; // SEQUENCE
+ length--;
+ EncodeASN1Length(out.get(), &j, &length);
+ memcpy(&out[j], kASN1AlgorithmIdentifierRSA,
+ sizeof(kASN1AlgorithmIdentifierRSA));
+ j += sizeof(kASN1AlgorithmIdentifierRSA);
+ length -= sizeof(kASN1AlgorithmIdentifierRSA);
+ out[j++] = 3; // BITSTRING tag
+ length--;
+ EncodeASN1Length(out.get(), &j, &length);
+ out[j++] = 0; // BITSTRING unused bits
+ length--;
+ out[j++] = 0x30; // SEQUENCE
+ length--;
+ EncodeASN1Length(out.get(), &j, &length);
+ out[j++] = 2; // INTEGER
+ length--;
+ unsigned l = n_length + n_padding;
+ if (l < 128) {
+ out[j++] = l;
+ length--;
+ } else if (l < 256) {
+ out[j++] = 0x80 | 1;
+ out[j++] = l;
+ length -= 2;
+ } else if (l < 65536) {
+ out[j++] = 0x80 | 2;
+ out[j++] = l >> 8;
+ out[j++] = l;
+ length -= 3;
+ } else {
+ NOTREACHED();
+ }
+
+ if (n_padding) {
+ out[j++] = 0;
+ length--;
+ }
+ memcpy(&out[j], &data[n_offset], n_length);
+ j += n_length;
+ length -= n_length;
+ out[j++] = 2; // INTEGER
+ length--;
+ out[j++] = exp_length;
+ length--;
+ for (unsigned i = exp_length - 1; i < exp_length; i--) {
+ out[j++] = exp >> (8 * i);
+ length--;
+ }
+
+ DCHECK_EQ(0u, length);
+
+ return std::string(reinterpret_cast<char*>(out.get()), j);
+}
+
+bool DNSSECKeySet::VerifySignature(
+ base::StringPiece signature_algorithm,
+ base::StringPiece signature,
+ base::StringPiece public_key,
+ base::StringPiece signed_data) {
+ // This code is largely a copy-and-paste from
+ // base/crypto/signature_verifier_nss.cc. We can't change
+ // base::SignatureVerifier to always use NSS because we want the ability to
+ // be FIPS 140-2 compliant. However, we can't use base::SignatureVerifier
+ // here because some platforms don't support SHA256 signatures. Therefore, we
+ // use NSS directly.
+
+ base::EnsureNSSInit();
+
+ CERTSubjectPublicKeyInfo* spki = NULL;
+ SECItem spki_der;
+ spki_der.type = siBuffer;
+ spki_der.data = (uint8*) public_key.data();
+ spki_der.len = public_key.size();
+ spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der);
+ if (!spki)
+ return false;
+ SECKEYPublicKey* pub_key = SECKEY_ExtractPublicKey(spki);
+ SECKEY_DestroySubjectPublicKeyInfo(spki); // Done with spki.
+ if (!pub_key)
+ return false;
+
+ PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ SECKEY_DestroyPublicKey(pub_key);
+ return false;
+ }
+
+ SECItem sig_alg_der;
+ sig_alg_der.type = siBuffer;
+ sig_alg_der.data = (uint8*) signature_algorithm.data();
+ sig_alg_der.len = signature_algorithm.size();
+ SECAlgorithmID sig_alg_id;
+ SECStatus rv;
+ rv = SEC_QuickDERDecodeItem(arena, &sig_alg_id, SECOID_AlgorithmIDTemplate,
+ &sig_alg_der);
+ if (rv != SECSuccess) {
+ SECKEY_DestroyPublicKey(pub_key);
+ PORT_FreeArena(arena, PR_TRUE);
+ return false;
+ }
+
+ SECItem sig;
+ sig.type = siBuffer;
+ sig.data = (uint8*) signature.data();
+ sig.len = signature.size();
+ SECOidTag hash_alg_tag;
+ VFYContext* vfy_context =
+ VFY_CreateContextWithAlgorithmID(pub_key, &sig,
+ &sig_alg_id, &hash_alg_tag,
+ NULL);
+ SECKEY_DestroyPublicKey(pub_key);
+ PORT_FreeArena(arena, PR_TRUE); // Done with sig_alg_id.
+ if (!vfy_context) {
+ // A corrupted RSA signature could be detected without the data, so
+ // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE
+ // (-8182).
+ return false;
+ }
+
+ rv = VFY_Begin(vfy_context);
+ if (rv != SECSuccess) {
+ NOTREACHED();
+ return false;
+ }
+ rv = VFY_Update(vfy_context, (uint8*) signed_data.data(), signed_data.size());
+ if (rv != SECSuccess) {
+ NOTREACHED();
+ return false;
+ }
+ rv = VFY_End(vfy_context);
+ VFY_DestroyContext(vfy_context, PR_TRUE);
+
+ return rv == SECSuccess;
+}
+
+} // namespace net
diff --git a/net/base/dnssec_keyset.h b/net/base/dnssec_keyset.h
new file mode 100644
index 0000000..58bd288
--- /dev/null
+++ b/net/base/dnssec_keyset.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 NET_BASE_DNSSEC_KEYSET_H_
+#define NET_BASE_DNSSEC_KEYSET_H_
+
+#include <string>
+#include <vector>
+
+#include "base/string_piece.h"
+
+namespace net {
+
+// DNSSECKeySet function wraps base/crypto/signature_verifier.h to accept
+// DNSSEC encodings. (See RFC 4043)
+class DNSSECKeySet {
+ public:
+ DNSSECKeySet();
+ ~DNSSECKeySet();
+
+ // AddKey adds a key to the trusted set.
+ // dnskey: the RRDATA of a DNSKEY.
+ bool AddKey(const base::StringPiece& dnskey);
+
+ // CheckSignature checks the DNSSEC signature on set of resource records.
+ // name: the domain that the records are from
+ // zone: the signing zone
+ // signature: the RRSIG signature, not include the signing zone.
+ // rrtype: the type of the resource records
+ // rrdatas: the RRDATA of the signed resource records, in canonical order.
+ bool CheckSignature(const base::StringPiece& name,
+ const base::StringPiece& zone,
+ const base::StringPiece& signature,
+ uint16 rrtype,
+ const std::vector<base::StringPiece>& rrdatas);
+
+ // DNSKEYToKeyID converts the RRDATA of a DNSKEY to its key id. See RFC 4043,
+ // app B.
+ static uint16 DNSKEYToKeyID(const base::StringPiece& dnskey);
+
+ // Used for testing: the timestamps on signatures will be ignored to allow
+ // golden data to remain valid.
+ void IgnoreTimestamps();
+
+ private:
+ bool VerifySignature(
+ base::StringPiece signature_algorithm,
+ base::StringPiece signature,
+ base::StringPiece public_key,
+ base::StringPiece signed_data);
+
+ std::string ASN1WrapDNSKEY(const base::StringPiece& dnskey);
+
+ bool ignore_timestamps_;
+ std::vector<uint16> keyids_;
+ std::vector<std::string> public_keys_;
+};
+
+} // namespace net
+
+#endif // NET_BASE_DNSSEC_KEYSET_H_
diff --git a/net/base/dnssec_unittest.cc b/net/base/dnssec_unittest.cc
new file mode 100644
index 0000000..f95c771
--- /dev/null
+++ b/net/base/dnssec_unittest.cc
@@ -0,0 +1,694 @@
+// Copyright (c) 2010 The Chromium Authors. 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/scoped_ptr.h"
+#include "net/base/dns_util.h"
+#include "net/base/dnssec_chain_verifier.h"
+#include "net/base/dnssec_keyset.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SignatureVerifierDNSSECTest : public testing::Test {
+};
+
+class DNSSECChainVerifierTest : public testing::Test {
+};
+
+} // anonymous namespace
+
+// This is a DNSKEY record. You can get one with `dig dnskey .` (where '.' can
+// be any signed zone).
+static const unsigned char kExampleKey[] = {
+ 0x01, 0x01, 0x03, 0x08, 0x03, 0x01, 0x00, 0x01, 0xa8, 0x00, 0x20, 0xa9, 0x55,
+ 0x66, 0xba, 0x42, 0xe8, 0x86, 0xbb, 0x80, 0x4c, 0xda, 0x84, 0xe4, 0x7e, 0xf5,
+ 0x6d, 0xbd, 0x7a, 0xec, 0x61, 0x26, 0x15, 0x55, 0x2c, 0xec, 0x90, 0x6d, 0x21,
+ 0x16, 0xd0, 0xef, 0x20, 0x70, 0x28, 0xc5, 0x15, 0x54, 0x14, 0x4d, 0xfe, 0xaf,
+ 0xe7, 0xc7, 0xcb, 0x8f, 0x00, 0x5d, 0xd1, 0x82, 0x34, 0x13, 0x3a, 0xc0, 0x71,
+ 0x0a, 0x81, 0x18, 0x2c, 0xe1, 0xfd, 0x14, 0xad, 0x22, 0x83, 0xbc, 0x83, 0x43,
+ 0x5f, 0x9d, 0xf2, 0xf6, 0x31, 0x32, 0x51, 0x93, 0x1a, 0x17, 0x6d, 0xf0, 0xda,
+ 0x51, 0xe5, 0x4f, 0x42, 0xe6, 0x04, 0x86, 0x0d, 0xfb, 0x35, 0x95, 0x80, 0x25,
+ 0x0f, 0x55, 0x9c, 0xc5, 0x43, 0xc4, 0xff, 0xd5, 0x1c, 0xbe, 0x3d, 0xe8, 0xcf,
+ 0xd0, 0x67, 0x19, 0x23, 0x7f, 0x9f, 0xc4, 0x7e, 0xe7, 0x29, 0xda, 0x06, 0x83,
+ 0x5f, 0xa4, 0x52, 0xe8, 0x25, 0xe9, 0xa1, 0x8e, 0xbc, 0x2e, 0xcb, 0xcf, 0x56,
+ 0x34, 0x74, 0x65, 0x2c, 0x33, 0xcf, 0x56, 0xa9, 0x03, 0x3b, 0xcd, 0xf5, 0xd9,
+ 0x73, 0x12, 0x17, 0x97, 0xec, 0x80, 0x89, 0x04, 0x1b, 0x6e, 0x03, 0xa1, 0xb7,
+ 0x2d, 0x0a, 0x73, 0x5b, 0x98, 0x4e, 0x03, 0x68, 0x73, 0x09, 0x33, 0x23, 0x24,
+ 0xf2, 0x7c, 0x2d, 0xba, 0x85, 0xe9, 0xdb, 0x15, 0xe8, 0x3a, 0x01, 0x43, 0x38,
+ 0x2e, 0x97, 0x4b, 0x06, 0x21, 0xc1, 0x8e, 0x62, 0x5e, 0xce, 0xc9, 0x07, 0x57,
+ 0x7d, 0x9e, 0x7b, 0xad, 0xe9, 0x52, 0x41, 0xa8, 0x1e, 0xbb, 0xe8, 0xa9, 0x01,
+ 0xd4, 0xd3, 0x27, 0x6e, 0x40, 0xb1, 0x14, 0xc0, 0xa2, 0xe6, 0xfc, 0x38, 0xd1,
+ 0x9c, 0x2e, 0x6a, 0xab, 0x02, 0x64, 0x4b, 0x28, 0x13, 0xf5, 0x75, 0xfc, 0x21,
+ 0x60, 0x1e, 0x0d, 0xee, 0x49, 0xcd, 0x9e, 0xe9, 0x6a, 0x43, 0x10, 0x3e, 0x52,
+ 0x4d, 0x62, 0x87, 0x3d,
+};
+
+TEST(SignatureVerifierDNSSECTest, KeyID) {
+ uint16 keyid = net::DNSSECKeySet::DNSKEYToKeyID(
+ base::StringPiece(reinterpret_cast<const char*>(kExampleKey),
+ sizeof(kExampleKey)));
+ ASSERT_EQ(19036u, keyid);
+}
+
+TEST(SignatureVerifierDNSSECTest, ImportKey) {
+ net::DNSSECKeySet keyset;
+
+ ASSERT_TRUE(keyset.AddKey(
+ base::StringPiece(reinterpret_cast<const char*>(kExampleKey),
+ sizeof(kExampleKey))));
+}
+
+// This is root's DNSSKEY signature
+const unsigned char kSignatureData[] = {
+ 0x08, 0x00, 0x00, 0x01, 0x51, 0x80, 0x4c, 0x59, 0xfe, 0xff, 0x4c, 0x46, 0x38,
+ 0x80, 0x4a, 0x5c, 0x2e, 0x63, 0xb7, 0x71, 0xf6, 0xb0, 0x32, 0xb7, 0x71, 0xb5,
+ 0xaa, 0xca, 0xd4, 0x4c, 0xeb, 0xf1, 0x7f, 0xa3, 0x28, 0x00, 0x43, 0x85, 0x76,
+ 0x9f, 0x46, 0x3d, 0x85, 0x39, 0x8d, 0x66, 0x7a, 0xeb, 0x4c, 0x6e, 0x60, 0x0a,
+ 0xe6, 0x49, 0x20, 0x47, 0xf9, 0x13, 0x81, 0x3e, 0xc8, 0xf5, 0x09, 0x92, 0x75,
+ 0xab, 0x87, 0xc6, 0x70, 0x35, 0xdd, 0xd9, 0x9e, 0xb6, 0xd4, 0x09, 0x66, 0xcc,
+ 0x0d, 0x71, 0x71, 0x3d, 0x4c, 0x96, 0xbc, 0x7d, 0x2c, 0x05, 0x0a, 0x9c, 0xc3,
+ 0xcd, 0x5d, 0xfa, 0xab, 0xb5, 0x17, 0x55, 0xca, 0x86, 0x31, 0x4b, 0x7b, 0x93,
+ 0x4a, 0x4b, 0x91, 0xd9, 0xea, 0x71, 0xf8, 0x3f, 0xb3, 0x4f, 0xb4, 0x94, 0xcd,
+ 0x6f, 0xe4, 0x83, 0xf6, 0xd4, 0xcb, 0xb8, 0x3c, 0x7d, 0xf6, 0x73, 0xf7, 0xf2,
+ 0x6f, 0xa5, 0x92, 0x25, 0xdc, 0xe5, 0xdd, 0x83, 0x55, 0xef, 0xde, 0x20, 0x00,
+ 0x64, 0x9e, 0x25, 0x76, 0x70, 0x08, 0x14, 0x29, 0xec, 0x66, 0xa3, 0xfd, 0x48,
+ 0x3b, 0x67, 0x21, 0x6e, 0x3d, 0x1e, 0x26, 0xb4, 0x74, 0x07, 0x1f, 0x1f, 0x4d,
+ 0xdf, 0x74, 0xae, 0x04, 0x70, 0xf0, 0x08, 0x3f, 0xe2, 0x6a, 0x39, 0x51, 0x79,
+ 0x25, 0xd9, 0xc2, 0xf9, 0xa4, 0xb6, 0x38, 0x4a, 0x5f, 0x80, 0x12, 0x4d, 0x98,
+ 0x7a, 0x3b, 0x8d, 0xb8, 0x3d, 0x51, 0x6b, 0x7c, 0x27, 0xc9, 0xc0, 0xcc, 0x26,
+ 0x73, 0xef, 0x43, 0x8a, 0x6c, 0x42, 0xa5, 0x2d, 0x11, 0x77, 0x9f, 0xe4, 0xa4,
+ 0x50, 0xb3, 0x29, 0xe4, 0x5c, 0x04, 0xc7, 0x38, 0xbb, 0xfa, 0x27, 0xfa, 0x02,
+ 0x76, 0x07, 0x5b, 0x88, 0x39, 0xd8, 0x60, 0x81, 0x9f, 0x36, 0xfc, 0x9c, 0x17,
+ 0x83, 0x0a, 0x54, 0x59, 0x86, 0x6b, 0xd6, 0x54, 0x5c, 0x9a, 0xba, 0x10, 0xe6,
+ 0x2e, 0x12, 0x78, 0x85, 0x1c, 0xed, 0x26, 0x79, 0xd4, 0xfc, 0x83, 0x51,
+};
+
+// The is root's 1024-bit key.
+static const unsigned char kRRDATA1[] = {
+ 1, 0, 3, 8, 3, 1, 0, 1, 189, 96, 112, 56, 65, 148, 127, 253, 50, 88, 20, 197,
+ 45, 34, 147, 103, 112, 99, 242, 98, 4, 138, 85, 248, 72, 74, 101, 94, 203,
+ 113, 204, 77, 115, 164, 37, 143, 142, 187, 66, 49, 208, 220, 88, 38, 218, 45,
+ 139, 19, 220, 58, 46, 163, 197, 13, 41, 224, 230, 165, 106, 212, 230, 5, 201,
+ 48, 109, 220, 52, 41, 166, 160, 231, 0, 250, 226, 79, 5, 185, 168, 132, 13,
+ 12, 209, 111, 223, 140, 168, 235, 123, 0, 116, 23, 148, 224, 111, 109, 191,
+ 183, 115, 79, 155, 15, 200, 8, 38, 86, 30, 71, 12, 39, 190, 233, 115, 54,
+ 248, 135, 165, 215, 233, 20, 40, 39, 165, 240, 135, 50, 215, 216, 81,
+};
+
+// The is root's 2048-bit key.
+static const unsigned char kRRDATA2[] = {
+ 1, 1, 3, 8, 3, 1, 0, 1, 168, 0, 32, 169, 85, 102, 186, 66, 232, 134, 187,
+ 128, 76, 218, 132, 228, 126, 245, 109, 189, 122, 236, 97, 38, 21, 85, 44,
+ 236, 144, 109, 33, 22, 208, 239, 32, 112, 40, 197, 21, 84, 20, 77, 254, 175,
+ 231, 199, 203, 143, 0, 93, 209, 130, 52, 19, 58, 192, 113, 10, 129, 24, 44,
+ 225, 253, 20, 173, 34, 131, 188, 131, 67, 95, 157, 242, 246, 49, 50, 81, 147,
+ 26, 23, 109, 240, 218, 81, 229, 79, 66, 230, 4, 134, 13, 251, 53, 149, 128,
+ 37, 15, 85, 156, 197, 67, 196, 255, 213, 28, 190, 61, 232, 207, 208, 103, 25,
+ 35, 127, 159, 196, 126, 231, 41, 218, 6, 131, 95, 164, 82, 232, 37, 233, 161,
+ 142, 188, 46, 203, 207, 86, 52, 116, 101, 44, 51, 207, 86, 169, 3, 59, 205,
+ 245, 217, 115, 18, 23, 151, 236, 128, 137, 4, 27, 110, 3, 161, 183, 45, 10,
+ 115, 91, 152, 78, 3, 104, 115, 9, 51, 35, 36, 242, 124, 45, 186, 133, 233,
+ 219, 21, 232, 58, 1, 67, 56, 46, 151, 75, 6, 33, 193, 142, 98, 94, 206, 201,
+ 7, 87, 125, 158, 123, 173, 233, 82, 65, 168, 30, 187, 232, 169, 1, 212, 211,
+ 39, 110, 64, 177, 20, 192, 162, 230, 252, 56, 209, 156, 46, 106, 171, 2, 100,
+ 75, 40, 19, 245, 117, 252, 33, 96, 30, 13, 238, 73, 205, 158, 233, 106, 67,
+ 16, 62, 82, 77, 98, 135, 61,
+};
+
+TEST(SignatureVerifierDNSSECTest, VerifySignature) {
+ net::DNSSECKeySet keyset;
+
+ ASSERT_TRUE(keyset.AddKey(
+ base::StringPiece(reinterpret_cast<const char*>(kExampleKey),
+ sizeof(kExampleKey))));
+ keyset.IgnoreTimestamps();
+
+ static const uint16 kDNSKEY = 48; // RRTYPE for DNSKEY
+ static const char kRootLabel[] = "";
+ base::StringPiece root(kRootLabel, 1);
+ base::StringPiece signature(reinterpret_cast<const char*>(kSignatureData),
+ sizeof(kSignatureData));
+ std::vector<base::StringPiece> rrdatas;
+ rrdatas.push_back(base::StringPiece(reinterpret_cast<const char*>(kRRDATA1),
+ sizeof(kRRDATA1)));
+ rrdatas.push_back(base::StringPiece(reinterpret_cast<const char*>(kRRDATA2),
+ sizeof(kRRDATA2)));
+ ASSERT_TRUE(keyset.CheckSignature(root, root, signature, kDNSKEY, rrdatas));
+}
+
+static std::string FromDNSName(const char* name) {
+ std::string result;
+ bool ok = net::DNSDomainFromDot(name, &result);
+ EXPECT_TRUE(ok);
+ if (!ok)
+ result = "";
+ return result;
+}
+
+TEST(DNSSECChainVerifierTest, MatchingLabels) {
+ ASSERT_EQ(1u, net::DNSSECChainVerifier::MatchingLabels(
+ FromDNSName(""), FromDNSName("")));
+ ASSERT_EQ(2u, net::DNSSECChainVerifier::MatchingLabels(
+ FromDNSName("org"), FromDNSName("org")));
+ ASSERT_EQ(3u, net::DNSSECChainVerifier::MatchingLabels(
+ FromDNSName("foo.org"), FromDNSName("foo.org")));
+ ASSERT_EQ(3u, net::DNSSECChainVerifier::MatchingLabels(
+ FromDNSName("bar.foo.org"), FromDNSName("foo.org")));
+ ASSERT_EQ(3u, net::DNSSECChainVerifier::MatchingLabels(
+ FromDNSName("foo.org"), FromDNSName("bar.foo.org")));
+ ASSERT_EQ(1u, net::DNSSECChainVerifier::MatchingLabels(
+ FromDNSName("foo.org"), FromDNSName("foo.com")));
+ ASSERT_EQ(2u, net::DNSSECChainVerifier::MatchingLabels(
+ FromDNSName("foo.org"), FromDNSName("bar.org")));
+}
+
+static const unsigned char kChain[] = {
+ 0x4a, 0x5c, 0x01, 0x01, 0x10, 0x08, 0x00, 0x00, 0x01, 0x51, 0x80, 0x4c, 0x59,
+ 0xfe, 0xff, 0x4c, 0x46, 0x38, 0x80, 0x4a, 0x5c, 0x2e, 0x63, 0xb7, 0x71, 0xf6,
+ 0xb0, 0x32, 0xb7, 0x71, 0xb5, 0xaa, 0xca, 0xd4, 0x4c, 0xeb, 0xf1, 0x7f, 0xa3,
+ 0x28, 0x00, 0x43, 0x85, 0x76, 0x9f, 0x46, 0x3d, 0x85, 0x39, 0x8d, 0x66, 0x7a,
+ 0xeb, 0x4c, 0x6e, 0x60, 0x0a, 0xe6, 0x49, 0x20, 0x47, 0xf9, 0x13, 0x81, 0x3e,
+ 0xc8, 0xf5, 0x09, 0x92, 0x75, 0xab, 0x87, 0xc6, 0x70, 0x35, 0xdd, 0xd9, 0x9e,
+ 0xb6, 0xd4, 0x09, 0x66, 0xcc, 0x0d, 0x71, 0x71, 0x3d, 0x4c, 0x96, 0xbc, 0x7d,
+ 0x2c, 0x05, 0x0a, 0x9c, 0xc3, 0xcd, 0x5d, 0xfa, 0xab, 0xb5, 0x17, 0x55, 0xca,
+ 0x86, 0x31, 0x4b, 0x7b, 0x93, 0x4a, 0x4b, 0x91, 0xd9, 0xea, 0x71, 0xf8, 0x3f,
+ 0xb3, 0x4f, 0xb4, 0x94, 0xcd, 0x6f, 0xe4, 0x83, 0xf6, 0xd4, 0xcb, 0xb8, 0x3c,
+ 0x7d, 0xf6, 0x73, 0xf7, 0xf2, 0x6f, 0xa5, 0x92, 0x25, 0xdc, 0xe5, 0xdd, 0x83,
+ 0x55, 0xef, 0xde, 0x20, 0x00, 0x64, 0x9e, 0x25, 0x76, 0x70, 0x08, 0x14, 0x29,
+ 0xec, 0x66, 0xa3, 0xfd, 0x48, 0x3b, 0x67, 0x21, 0x6e, 0x3d, 0x1e, 0x26, 0xb4,
+ 0x74, 0x07, 0x1f, 0x1f, 0x4d, 0xdf, 0x74, 0xae, 0x04, 0x70, 0xf0, 0x08, 0x3f,
+ 0xe2, 0x6a, 0x39, 0x51, 0x79, 0x25, 0xd9, 0xc2, 0xf9, 0xa4, 0xb6, 0x38, 0x4a,
+ 0x5f, 0x80, 0x12, 0x4d, 0x98, 0x7a, 0x3b, 0x8d, 0xb8, 0x3d, 0x51, 0x6b, 0x7c,
+ 0x27, 0xc9, 0xc0, 0xcc, 0x26, 0x73, 0xef, 0x43, 0x8a, 0x6c, 0x42, 0xa5, 0x2d,
+ 0x11, 0x77, 0x9f, 0xe4, 0xa4, 0x50, 0xb3, 0x29, 0xe4, 0x5c, 0x04, 0xc7, 0x38,
+ 0xbb, 0xfa, 0x27, 0xfa, 0x02, 0x76, 0x07, 0x5b, 0x88, 0x39, 0xd8, 0x60, 0x81,
+ 0x9f, 0x36, 0xfc, 0x9c, 0x17, 0x83, 0x0a, 0x54, 0x59, 0x86, 0x6b, 0xd6, 0x54,
+ 0x5c, 0x9a, 0xba, 0x10, 0xe6, 0x2e, 0x12, 0x78, 0x85, 0x1c, 0xed, 0x26, 0x79,
+ 0xd4, 0xfc, 0x83, 0x51, 0x02, 0x00, 0x88, 0x01, 0x00, 0x03, 0x08, 0x03, 0x01,
+ 0x00, 0x01, 0xbd, 0x60, 0x70, 0x38, 0x41, 0x94, 0x7f, 0xfd, 0x32, 0x58, 0x14,
+ 0xc5, 0x2d, 0x22, 0x93, 0x67, 0x70, 0x63, 0xf2, 0x62, 0x04, 0x8a, 0x55, 0xf8,
+ 0x48, 0x4a, 0x65, 0x5e, 0xcb, 0x71, 0xcc, 0x4d, 0x73, 0xa4, 0x25, 0x8f, 0x8e,
+ 0xbb, 0x42, 0x31, 0xd0, 0xdc, 0x58, 0x26, 0xda, 0x2d, 0x8b, 0x13, 0xdc, 0x3a,
+ 0x2e, 0xa3, 0xc5, 0x0d, 0x29, 0xe0, 0xe6, 0xa5, 0x6a, 0xd4, 0xe6, 0x05, 0xc9,
+ 0x30, 0x6d, 0xdc, 0x34, 0x29, 0xa6, 0xa0, 0xe7, 0x00, 0xfa, 0xe2, 0x4f, 0x05,
+ 0xb9, 0xa8, 0x84, 0x0d, 0x0c, 0xd1, 0x6f, 0xdf, 0x8c, 0xa8, 0xeb, 0x7b, 0x00,
+ 0x74, 0x17, 0x94, 0xe0, 0x6f, 0x6d, 0xbf, 0xb7, 0x73, 0x4f, 0x9b, 0x0f, 0xc8,
+ 0x08, 0x26, 0x56, 0x1e, 0x47, 0x0c, 0x27, 0xbe, 0xe9, 0x73, 0x36, 0xf8, 0x87,
+ 0xa5, 0xd7, 0xe9, 0x14, 0x28, 0x27, 0xa5, 0xf0, 0x87, 0x32, 0xd7, 0xd8, 0x51,
+ 0x01, 0x08, 0x01, 0x01, 0x03, 0x08, 0x03, 0x01, 0x00, 0x01, 0xa8, 0x00, 0x20,
+ 0xa9, 0x55, 0x66, 0xba, 0x42, 0xe8, 0x86, 0xbb, 0x80, 0x4c, 0xda, 0x84, 0xe4,
+ 0x7e, 0xf5, 0x6d, 0xbd, 0x7a, 0xec, 0x61, 0x26, 0x15, 0x55, 0x2c, 0xec, 0x90,
+ 0x6d, 0x21, 0x16, 0xd0, 0xef, 0x20, 0x70, 0x28, 0xc5, 0x15, 0x54, 0x14, 0x4d,
+ 0xfe, 0xaf, 0xe7, 0xc7, 0xcb, 0x8f, 0x00, 0x5d, 0xd1, 0x82, 0x34, 0x13, 0x3a,
+ 0xc0, 0x71, 0x0a, 0x81, 0x18, 0x2c, 0xe1, 0xfd, 0x14, 0xad, 0x22, 0x83, 0xbc,
+ 0x83, 0x43, 0x5f, 0x9d, 0xf2, 0xf6, 0x31, 0x32, 0x51, 0x93, 0x1a, 0x17, 0x6d,
+ 0xf0, 0xda, 0x51, 0xe5, 0x4f, 0x42, 0xe6, 0x04, 0x86, 0x0d, 0xfb, 0x35, 0x95,
+ 0x80, 0x25, 0x0f, 0x55, 0x9c, 0xc5, 0x43, 0xc4, 0xff, 0xd5, 0x1c, 0xbe, 0x3d,
+ 0xe8, 0xcf, 0xd0, 0x67, 0x19, 0x23, 0x7f, 0x9f, 0xc4, 0x7e, 0xe7, 0x29, 0xda,
+ 0x06, 0x83, 0x5f, 0xa4, 0x52, 0xe8, 0x25, 0xe9, 0xa1, 0x8e, 0xbc, 0x2e, 0xcb,
+ 0xcf, 0x56, 0x34, 0x74, 0x65, 0x2c, 0x33, 0xcf, 0x56, 0xa9, 0x03, 0x3b, 0xcd,
+ 0xf5, 0xd9, 0x73, 0x12, 0x17, 0x97, 0xec, 0x80, 0x89, 0x04, 0x1b, 0x6e, 0x03,
+ 0xa1, 0xb7, 0x2d, 0x0a, 0x73, 0x5b, 0x98, 0x4e, 0x03, 0x68, 0x73, 0x09, 0x33,
+ 0x23, 0x24, 0xf2, 0x7c, 0x2d, 0xba, 0x85, 0xe9, 0xdb, 0x15, 0xe8, 0x3a, 0x01,
+ 0x43, 0x38, 0x2e, 0x97, 0x4b, 0x06, 0x21, 0xc1, 0x8e, 0x62, 0x5e, 0xce, 0xc9,
+ 0x07, 0x57, 0x7d, 0x9e, 0x7b, 0xad, 0xe9, 0x52, 0x41, 0xa8, 0x1e, 0xbb, 0xe8,
+ 0xa9, 0x01, 0xd4, 0xd3, 0x27, 0x6e, 0x40, 0xb1, 0x14, 0xc0, 0xa2, 0xe6, 0xfc,
+ 0x38, 0xd1, 0x9c, 0x2e, 0x6a, 0xab, 0x02, 0x64, 0x4b, 0x28, 0x13, 0xf5, 0x75,
+ 0xfc, 0x21, 0x60, 0x1e, 0x0d, 0xee, 0x49, 0xcd, 0x9e, 0xe9, 0x6a, 0x43, 0x10,
+ 0x3e, 0x52, 0x4d, 0x62, 0x87, 0x3d, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x2b,
+ 0x00, 0x90, 0x08, 0x01, 0x00, 0x02, 0xa3, 0x00, 0x4c, 0x54, 0xb9, 0x00, 0x4c,
+ 0x4b, 0x70, 0x70, 0xa1, 0x20, 0x5c, 0x2f, 0xd0, 0x29, 0x2c, 0x13, 0xf8, 0xbc,
+ 0xbb, 0xfe, 0xd2, 0xb2, 0xf2, 0x6a, 0xfa, 0xe0, 0x4a, 0x2e, 0x80, 0xb5, 0x3c,
+ 0xb9, 0xa1, 0x6f, 0x14, 0x57, 0x9e, 0x80, 0x3f, 0xb8, 0x5d, 0xbc, 0xac, 0x81,
+ 0x1f, 0x7a, 0xf9, 0x18, 0xda, 0x31, 0x3f, 0x97, 0x68, 0x2b, 0x37, 0x79, 0xb2,
+ 0xb8, 0xd7, 0x1a, 0x40, 0x35, 0xb1, 0x3b, 0x64, 0x22, 0x0d, 0xb6, 0xb9, 0x17,
+ 0x64, 0xfe, 0xed, 0x23, 0xaf, 0x17, 0xb2, 0x7f, 0x49, 0xa9, 0x2b, 0xa0, 0x06,
+ 0xfb, 0xe9, 0x4a, 0x17, 0x88, 0x91, 0x55, 0xe5, 0xb3, 0x5f, 0xee, 0x73, 0xd7,
+ 0x00, 0x58, 0x21, 0x29, 0x39, 0x7a, 0xe2, 0xc5, 0x03, 0x8f, 0xf2, 0x11, 0xed,
+ 0xd6, 0xb0, 0xdb, 0x5e, 0x7f, 0x37, 0x46, 0x80, 0xf9, 0x67, 0xfc, 0xdd, 0xbf,
+ 0xb5, 0x46, 0x4d, 0xe5, 0xcf, 0x3f, 0xf9, 0xb2, 0x08, 0x52, 0x36, 0xf5, 0x7f,
+ 0x8c, 0x19, 0x88, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x10,
+ 0x07, 0x01, 0x00, 0x00, 0x03, 0x84, 0x4c, 0x54, 0x44, 0xe0, 0x4c, 0x41, 0xc1,
+ 0xd0, 0x53, 0x76, 0x53, 0x1b, 0xac, 0x55, 0xb7, 0x5b, 0xc8, 0xca, 0xe7, 0x05,
+ 0xe2, 0x19, 0x50, 0x5b, 0xf4, 0x05, 0xc6, 0x11, 0x41, 0xb7, 0xde, 0x29, 0xd8,
+ 0x71, 0x9b, 0x1d, 0x44, 0x8b, 0x1f, 0xf9, 0x9d, 0x4e, 0x94, 0xc9, 0xe9, 0xfe,
+ 0xc2, 0x7c, 0x73, 0xd1, 0xc7, 0x9b, 0xbe, 0x15, 0x8f, 0xc4, 0xb6, 0xe7, 0x91,
+ 0xe4, 0x67, 0xc3, 0xab, 0x2f, 0x89, 0x60, 0xf0, 0x29, 0xfb, 0xb1, 0x0a, 0x05,
+ 0xc6, 0xf2, 0xf6, 0xb3, 0xf2, 0x4d, 0x68, 0xb5, 0xde, 0x66, 0x45, 0x39, 0xe8,
+ 0x9b, 0xfa, 0x0f, 0x7d, 0x9d, 0xbc, 0xd4, 0xc5, 0xb7, 0x14, 0x9d, 0xa0, 0x21,
+ 0x33, 0x04, 0x2a, 0x97, 0x40, 0x98, 0x40, 0x16, 0xfe, 0xe0, 0xcf, 0xdd, 0x22,
+ 0x94, 0xbe, 0xbc, 0x4c, 0x09, 0x5c, 0xef, 0x0e, 0x99, 0xac, 0xa0, 0xb6, 0xa5,
+ 0xde, 0xe8, 0xf1, 0x1f, 0xff, 0x84, 0x3a, 0x19, 0x7e, 0x46, 0x26, 0x6f, 0xdc,
+ 0xfd, 0x15, 0x9d, 0xfd, 0x6e, 0x58, 0xf2, 0x94, 0x02, 0x25, 0x9a, 0x37, 0x99,
+ 0x9f, 0x27, 0xdb, 0xbe, 0xcd, 0x3a, 0x2b, 0xa8, 0xa3, 0xd6, 0x96, 0x4e, 0xdb,
+ 0xe5, 0x87, 0x55, 0xd8, 0xd2, 0x6e, 0xa7, 0x09, 0x7d, 0xe4, 0xfc, 0x20, 0x6c,
+ 0x4d, 0x99, 0xb3, 0x48, 0xf9, 0x63, 0xee, 0x4e, 0xa5, 0x24, 0xcc, 0xb1, 0x99,
+ 0xf8, 0x0e, 0x1d, 0x6e, 0x1a, 0x88, 0x0b, 0x98, 0xa5, 0x21, 0xdc, 0x43, 0x75,
+ 0xb5, 0x20, 0x5a, 0xcd, 0xac, 0xb8, 0x08, 0x60, 0x2c, 0xb0, 0x2f, 0x6f, 0xac,
+ 0x7b, 0xda, 0x16, 0x24, 0xc7, 0xc6, 0x22, 0xf6, 0xc8, 0x47, 0x8a, 0x93, 0x93,
+ 0x1e, 0x1d, 0xb5, 0xe2, 0x1e, 0xe5, 0xc6, 0x8e, 0xa9, 0xe4, 0xd3, 0x35, 0x97,
+ 0x31, 0x64, 0xce, 0xd8, 0xa1, 0x16, 0x1d, 0x67, 0x0e, 0x2c, 0x07, 0x2e, 0x67,
+ 0xef, 0xcc, 0x80, 0x59, 0x35, 0xdd, 0xa0, 0xa8, 0x60, 0x99, 0x4e, 0x8e, 0x04,
+ 0x00, 0x88, 0x01, 0x00, 0x03, 0x07, 0x03, 0x01, 0x00, 0x01, 0x9c, 0xf3, 0x56,
+ 0x70, 0x44, 0x1d, 0x37, 0x51, 0xf9, 0x88, 0xa4, 0xf7, 0xf9, 0x1f, 0x60, 0x1b,
+ 0x14, 0x03, 0xa8, 0xcd, 0xc1, 0xaf, 0x44, 0x6e, 0x5c, 0xdb, 0x83, 0x64, 0x48,
+ 0x9a, 0x7f, 0xdc, 0x6b, 0x64, 0x46, 0x72, 0xb5, 0xd5, 0x7f, 0xd2, 0xe9, 0x95,
+ 0x2f, 0x14, 0xf9, 0xff, 0x68, 0xbf, 0x35, 0xb7, 0xcc, 0x13, 0x95, 0xab, 0x07,
+ 0x4d, 0x5d, 0x47, 0xdb, 0xaa, 0xc0, 0xfc, 0xf9, 0xdc, 0xd4, 0x97, 0x51, 0x64,
+ 0xbb, 0x8a, 0x66, 0x71, 0xa8, 0x1c, 0xb8, 0x7b, 0xa4, 0xf6, 0xb9, 0x54, 0x98,
+ 0xf6, 0xa7, 0x41, 0xa8, 0xae, 0x8e, 0x17, 0x2b, 0x7e, 0xdd, 0x60, 0x8b, 0x84,
+ 0x21, 0xe4, 0x68, 0xdd, 0xfc, 0x34, 0x5b, 0x8f, 0x53, 0x14, 0x93, 0xa3, 0xb1,
+ 0xd6, 0xcb, 0x9f, 0x26, 0xac, 0xfd, 0x9e, 0xf3, 0x44, 0x8a, 0x35, 0xf6, 0x8b,
+ 0x20, 0xf8, 0x7a, 0xf7, 0xa2, 0x2c, 0xf3, 0xfd, 0x00, 0x88, 0x01, 0x00, 0x03,
+ 0x07, 0x03, 0x01, 0x00, 0x01, 0xc9, 0x06, 0x00, 0x53, 0x45, 0x4a, 0x0b, 0xb8,
+ 0xe2, 0xb0, 0x4e, 0x29, 0xc8, 0x19, 0xb4, 0xa3, 0x63, 0x27, 0xe2, 0xcd, 0xc7,
+ 0xc7, 0x6d, 0x60, 0x31, 0xeb, 0xc0, 0x82, 0x5f, 0x44, 0x14, 0x96, 0x60, 0x4e,
+ 0xc8, 0x62, 0xf4, 0xcc, 0xb9, 0x99, 0x7a, 0x19, 0xf0, 0xaf, 0x34, 0xd9, 0x63,
+ 0xca, 0x40, 0xe3, 0x7b, 0xb6, 0xbc, 0xfa, 0x40, 0x08, 0x1d, 0xe7, 0xc3, 0xa4,
+ 0xd2, 0x73, 0x3a, 0x32, 0xf2, 0xa4, 0x4c, 0x3c, 0x4f, 0xd6, 0x52, 0x52, 0xc8,
+ 0x6d, 0xa5, 0xf6, 0xd9, 0x4d, 0x0c, 0xfd, 0xb4, 0x93, 0x8b, 0x61, 0x72, 0xdb,
+ 0x6e, 0x5f, 0x2d, 0xd9, 0x2d, 0xab, 0x18, 0x2f, 0x87, 0x2d, 0xbf, 0x8d, 0x42,
+ 0x37, 0x93, 0x41, 0x18, 0xf6, 0x93, 0x97, 0xda, 0x27, 0x31, 0xdc, 0xda, 0xec,
+ 0x21, 0x16, 0x61, 0xe1, 0xe0, 0x7a, 0x53, 0x26, 0x82, 0xc7, 0x62, 0x99, 0x18,
+ 0x81, 0x6a, 0x65, 0x01, 0x08, 0x01, 0x01, 0x03, 0x07, 0x03, 0x01, 0x00, 0x01,
+ 0x8a, 0x58, 0x7e, 0x3d, 0xda, 0x69, 0x1c, 0xf3, 0x93, 0x15, 0x90, 0xa8, 0xc7,
+ 0x65, 0xed, 0x81, 0x31, 0x63, 0xcd, 0x4d, 0x75, 0x84, 0xaf, 0xfa, 0xa6, 0xb2,
+ 0xb9, 0x90, 0xe8, 0x76, 0x76, 0x7d, 0x20, 0xc8, 0x74, 0x6f, 0x03, 0x1c, 0x61,
+ 0xa5, 0x54, 0x77, 0x33, 0x40, 0x6d, 0x57, 0x89, 0xf2, 0x07, 0x7a, 0x8e, 0xad,
+ 0x6c, 0x47, 0x75, 0x6f, 0x3f, 0xf4, 0x91, 0xdf, 0xa9, 0xa6, 0x1a, 0xcb, 0x1b,
+ 0x57, 0x85, 0x1d, 0x97, 0x93, 0x91, 0x0e, 0xda, 0xa2, 0x64, 0xfd, 0x93, 0x0c,
+ 0xd0, 0xc7, 0xc4, 0x49, 0xca, 0x29, 0x35, 0xfe, 0x8d, 0x67, 0xf2, 0xb5, 0x97,
+ 0x93, 0xed, 0xdd, 0xc0, 0x6d, 0x2c, 0xc1, 0x28, 0x2d, 0x2f, 0xee, 0xe6, 0x6b,
+ 0x33, 0xa3, 0x36, 0x7a, 0x82, 0x67, 0x97, 0xa8, 0x9d, 0xeb, 0xaa, 0xc4, 0x52,
+ 0x64, 0x02, 0xda, 0x9f, 0x43, 0xae, 0xb0, 0xe0, 0xf4, 0x5e, 0xad, 0x5c, 0x2f,
+ 0x42, 0x0f, 0xfc, 0xc2, 0xef, 0xfc, 0xbe, 0x04, 0xd3, 0x69, 0x88, 0xe7, 0x67,
+ 0x33, 0x90, 0xd7, 0x93, 0xb1, 0xe1, 0x66, 0x6e, 0xeb, 0x6b, 0xd1, 0x3b, 0x96,
+ 0xd2, 0xf5, 0xde, 0x1d, 0xa6, 0xc7, 0xb9, 0x04, 0x81, 0x4f, 0x1e, 0xea, 0x7a,
+ 0x49, 0x94, 0x2a, 0x17, 0x8e, 0xb6, 0x88, 0x06, 0x05, 0x03, 0xb6, 0x16, 0x2c,
+ 0xe3, 0xc5, 0xbf, 0xb1, 0xd4, 0xc3, 0x2e, 0xee, 0xcd, 0xe7, 0xda, 0xe3, 0x08,
+ 0x6f, 0x9b, 0xa6, 0x29, 0x7e, 0x73, 0xca, 0x19, 0xf5, 0xfe, 0xcd, 0x47, 0x7a,
+ 0xa6, 0x49, 0x3a, 0x53, 0x3f, 0x59, 0xbc, 0xe9, 0x1a, 0x94, 0x42, 0x75, 0x44,
+ 0xae, 0x27, 0xeb, 0x1f, 0xc2, 0xa3, 0x0e, 0xa2, 0xfe, 0xdf, 0x0c, 0xd4, 0x74,
+ 0x5e, 0x40, 0x0a, 0x46, 0x30, 0xb7, 0x55, 0xe1, 0x3d, 0x53, 0xd4, 0xfb, 0x04,
+ 0x88, 0x97, 0x36, 0xda, 0x01, 0x03, 0x78, 0xf4, 0xf5, 0x01, 0x08, 0x01, 0x01,
+ 0x03, 0x07, 0x03, 0x01, 0x00, 0x01, 0x94, 0xe3, 0x6c, 0x83, 0xb9, 0x90, 0x8a,
+ 0x71, 0x59, 0x4b, 0x72, 0x5d, 0xcf, 0x1a, 0xbe, 0xc2, 0xb2, 0x1c, 0x82, 0x19,
+ 0xf8, 0xb8, 0xc2, 0xd8, 0x3b, 0xfc, 0x9d, 0xa3, 0xbe, 0x4f, 0x3e, 0x97, 0xd9,
+ 0xfa, 0xb3, 0x0c, 0x2d, 0x5b, 0x76, 0xae, 0xc7, 0x95, 0x9c, 0x2d, 0x91, 0xaa,
+ 0x93, 0x90, 0xc5, 0x55, 0x27, 0xef, 0x20, 0x13, 0xd1, 0x48, 0xad, 0xe1, 0x89,
+ 0xe1, 0xcf, 0x06, 0xd4, 0x67, 0x5b, 0x8d, 0x08, 0x1b, 0x3f, 0x53, 0xb2, 0x60,
+ 0x81, 0xbb, 0x38, 0x74, 0xdc, 0xe2, 0x1b, 0xf9, 0x4f, 0x63, 0x65, 0xc9, 0x6a,
+ 0xfa, 0x93, 0xa4, 0x05, 0xcf, 0xdf, 0x10, 0xe3, 0x3c, 0x05, 0x20, 0x64, 0xc5,
+ 0x56, 0xfc, 0x01, 0x86, 0x6a, 0xcc, 0x0d, 0x8b, 0x0e, 0x4e, 0xd5, 0xda, 0x90,
+ 0xae, 0x90, 0xc0, 0x7a, 0x2f, 0x03, 0x5f, 0xbc, 0xdc, 0x1b, 0x14, 0x00, 0x2c,
+ 0x65, 0x89, 0xda, 0x70, 0x07, 0x48, 0x50, 0x69, 0xc6, 0xc3, 0xeb, 0x1f, 0x88,
+ 0xd9, 0x10, 0x83, 0xcd, 0x8b, 0x93, 0xce, 0x3e, 0xb8, 0x26, 0xfd, 0x3f, 0xf5,
+ 0x7b, 0x17, 0xe8, 0x06, 0x15, 0xdd, 0xe6, 0xdc, 0x82, 0x7e, 0x21, 0x2f, 0x58,
+ 0xc8, 0x47, 0x67, 0x89, 0x63, 0x25, 0xe5, 0xac, 0x0a, 0x16, 0xc5, 0xdc, 0xf1,
+ 0x71, 0x6f, 0xff, 0xe7, 0x27, 0x8b, 0xe5, 0x15, 0x56, 0xba, 0x14, 0x71, 0x7a,
+ 0x39, 0xa7, 0x49, 0x59, 0xc2, 0xbb, 0x19, 0x1f, 0x4b, 0x80, 0x10, 0xe3, 0xce,
+ 0x4a, 0x1f, 0x6b, 0x69, 0x75, 0xb5, 0x9c, 0x0a, 0x8a, 0x4b, 0x25, 0x9b, 0x3a,
+ 0xb7, 0x0f, 0x2a, 0xde, 0x35, 0x9c, 0xa5, 0x31, 0xb3, 0x76, 0x1f, 0xef, 0xdf,
+ 0x17, 0x58, 0x7c, 0xda, 0x50, 0x35, 0xc3, 0xc8, 0x98, 0x59, 0x71, 0x02, 0xe9,
+ 0xf7, 0x06, 0xd3, 0x91, 0x3c, 0x0d, 0xab, 0xf2, 0xd8, 0xba, 0x30, 0xda, 0x09,
+ 0x10, 0x75, 0x0a, 0x64, 0x6e, 0x73, 0x73, 0x65, 0x63, 0x2d, 0x65, 0x78, 0x70,
+ 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x2b, 0x00, 0x90, 0x07, 0x02, 0x00, 0x01,
+ 0x51, 0x80, 0x4c, 0x54, 0x44, 0xe0, 0x4c, 0x41, 0xc1, 0xd0, 0xf2, 0x12, 0x0d,
+ 0x95, 0xb4, 0x6f, 0x7c, 0xfc, 0xde, 0x67, 0xa0, 0x1d, 0x84, 0x49, 0x3e, 0xa8,
+ 0xe1, 0x07, 0xea, 0xde, 0x75, 0x14, 0x98, 0xa9, 0xcc, 0x09, 0x20, 0x66, 0x59,
+ 0xd2, 0x40, 0xfd, 0xc6, 0xcf, 0x54, 0x22, 0x4a, 0x13, 0xf9, 0xc2, 0x1e, 0xe3,
+ 0x48, 0xf1, 0xd0, 0x6d, 0x18, 0x27, 0xe5, 0x8e, 0x92, 0xc2, 0x5f, 0xcc, 0xb8,
+ 0xd6, 0x1a, 0xbb, 0xfa, 0xe7, 0xac, 0xa8, 0x23, 0x4b, 0x89, 0xef, 0xb0, 0xc7,
+ 0x9a, 0xaa, 0x00, 0x99, 0x82, 0x3d, 0xa8, 0x25, 0x6b, 0xb3, 0x59, 0xd5, 0x7a,
+ 0x90, 0xba, 0xc4, 0xa4, 0x79, 0x8c, 0xa4, 0x39, 0xc2, 0xe9, 0x54, 0xc0, 0x4c,
+ 0x0a, 0x0e, 0x06, 0xcc, 0x25, 0xac, 0xb6, 0x75, 0x45, 0x8c, 0xd9, 0x99, 0x4f,
+ 0x31, 0xff, 0x3d, 0x40, 0x3b, 0x1c, 0x40, 0x94, 0xed, 0x9d, 0x7f, 0x60, 0x08,
+ 0x23, 0x63, 0x18, 0x5c, 0x50, 0x6f, 0x26, 0x7b, 0x39, 0x8b, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xa8, 0x01, 0x00, 0x03, 0x05, 0x03, 0x01,
+ 0x00, 0x01, 0xd0, 0x0a, 0x64, 0x8e, 0xb5, 0x90, 0x0b, 0x75, 0xc2, 0xeb, 0x52,
+ 0x5f, 0xa4, 0xcb, 0xeb, 0x1d, 0x77, 0x8d, 0x84, 0x2c, 0xef, 0xb6, 0x88, 0xd4,
+ 0x7c, 0x50, 0x4c, 0x52, 0x7b, 0x9d, 0x37, 0x31, 0x36, 0xb2, 0x5b, 0x6c, 0x47,
+ 0xb4, 0x21, 0x80, 0x61, 0x46, 0xfa, 0x5b, 0x44, 0x50, 0x91, 0x9d, 0xf8, 0xc1,
+ 0x78, 0x00, 0x78, 0x29, 0xfe, 0xe2, 0x08, 0x65, 0xf8, 0xc9, 0xdf, 0x69, 0x0b,
+ 0x59, 0x6b, 0xf4, 0x93, 0x9f, 0x8b, 0x25, 0x0b, 0x6b, 0x93, 0x12, 0x06, 0x57,
+ 0xc8, 0x04, 0x9d, 0x3f, 0x33, 0xbd, 0x2b, 0x35, 0x54, 0xb9, 0x98, 0x75, 0xe4,
+ 0xb0, 0x49, 0x3c, 0x29, 0xc1, 0xfb, 0x74, 0xbc, 0x91, 0x82, 0x9e, 0xc5, 0x61,
+ 0xa6, 0x16, 0xe1, 0xf0, 0x8f, 0xe9, 0xe1, 0x23, 0x55, 0x5e, 0xfb, 0xf1, 0xcc,
+ 0x8a, 0x75, 0x5d, 0xf2, 0x86, 0x89, 0x0a, 0x29, 0xcb, 0xca, 0x33, 0xde, 0x9d,
+ 0x74, 0x43, 0x0d, 0xde, 0x67, 0xde, 0x71, 0x0f, 0x7f, 0xa3, 0xbb, 0x22, 0x82,
+ 0x81, 0x66, 0xd1, 0xbd, 0x49, 0x0d, 0x89, 0x45, 0xd7, 0x18, 0xcf, 0x98, 0x2c,
+ 0x19, 0xaf, 0x63, 0x16, 0x20, 0x91, 0x0a, 0x64, 0x6e, 0x73, 0x73, 0x65, 0x63,
+ 0x2d, 0x65, 0x78, 0x70, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x25, 0x00, 0xb0,
+ 0x05, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x4c, 0x71, 0x48, 0x0a, 0x4c, 0x49, 0xb6,
+ 0xcb, 0x83, 0x7f, 0x3d, 0xfa, 0xd9, 0x59, 0x7a, 0xc5, 0xa2, 0xd3, 0x0e, 0x3e,
+ 0x48, 0xa8, 0x9b, 0xc5, 0xef, 0x43, 0xe3, 0x3e, 0x3a, 0x1a, 0xb2, 0x39, 0x00,
+ 0x01, 0x73, 0x78, 0x80, 0x26, 0xac, 0xb0, 0x01, 0xe9, 0xc9, 0x7a, 0x0f, 0x5e,
+ 0xa7, 0xa2, 0x7f, 0xec, 0xa8, 0xf4, 0x42, 0x58, 0xdc, 0xba, 0xc1, 0x9e, 0xc8,
+ 0xa8, 0xc7, 0x93, 0x9f, 0x13, 0xc5, 0xbe, 0x99, 0xa9, 0xcc, 0x75, 0xd6, 0x7b,
+ 0xb4, 0xd4, 0x9b, 0x0e, 0x61, 0x96, 0x6d, 0x3f, 0xbf, 0x47, 0x42, 0xae, 0x8c,
+ 0xd7, 0xc1, 0x09, 0xb3, 0x84, 0x50, 0xac, 0xae, 0xbd, 0xc4, 0x54, 0x77, 0xe0,
+ 0xfe, 0xa8, 0xc3, 0xd4, 0x68, 0x76, 0x07, 0xdb, 0x14, 0x51, 0x2e, 0x43, 0x15,
+ 0x2b, 0x67, 0x4b, 0x76, 0x18, 0xbd, 0x04, 0xb3, 0xb7, 0xe5, 0xb7, 0xaf, 0xaa,
+ 0xb1, 0x4c, 0xa6, 0xd2, 0xbe, 0x2d, 0xdb, 0xa5, 0x2c, 0x1d, 0xe7, 0x67, 0x79,
+ 0x0b, 0xc4, 0x2e, 0x26, 0x0f, 0x9d, 0x98, 0x1f, 0x21, 0x1f, 0x9e, 0xfe, 0x3f,
+ 0x67, 0xf3, 0x67, 0x73, 0xe5, 0x88, 0xdf, 0xa8, 0x9f, 0x8c, 0x74, 0x97, 0xc2,
+ 0x44, 0x29, 0x28, 0x15, 0x0f, 0x1f, 0x83, 0x01, 0x00, 0x19, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x90, 0x38, 0x61, 0x31, 0x19, 0x52, 0x21, 0x14, 0x83, 0x08, 0x44,
+ 0xeb, 0xdd, 0xe5, 0xc7, 0x1d, 0x16, 0xa2, 0x45, 0x1c,
+};
+
+// kCNAMEChain is a chain which proves that www.dnssec-exp.org is a CNAME to
+// dnssec-exp.org and then proves a TXT record on dnssec-exp.org.
+static const unsigned char kCNAMEChain[] = {
+ 0x4a, 0x5c, 0x01, 0x01, 0x10, 0x08, 0x00, 0x00, 0x01, 0x51, 0x80, 0x4c, 0x8e,
+ 0xba, 0xff, 0x4c, 0x7a, 0xf4, 0x80, 0x4a, 0x5c, 0x6d, 0xe6, 0xa7, 0xaa, 0x97,
+ 0xca, 0x48, 0x4a, 0x49, 0xbb, 0xff, 0x91, 0x1a, 0xd8, 0xc2, 0x55, 0x0d, 0x80,
+ 0x1c, 0x83, 0x41, 0x2b, 0x89, 0x70, 0x87, 0xd9, 0x3a, 0x23, 0x9f, 0xdc, 0xa4,
+ 0xb6, 0x0c, 0xe3, 0x3a, 0x5a, 0xbe, 0xfc, 0x2b, 0xcb, 0xb7, 0x14, 0xbd, 0xbf,
+ 0x43, 0xaa, 0x03, 0x34, 0xe8, 0x84, 0x18, 0x2e, 0x95, 0x0e, 0x77, 0xb1, 0xe2,
+ 0x74, 0x86, 0xd8, 0xc3, 0x9c, 0xdc, 0x00, 0x80, 0x8c, 0x92, 0xfc, 0x92, 0xfe,
+ 0x25, 0xe3, 0x6d, 0x94, 0xe5, 0xc4, 0x08, 0x18, 0xf7, 0xc2, 0x96, 0xde, 0x8c,
+ 0x85, 0x73, 0x22, 0x0d, 0x03, 0x7a, 0xe0, 0xa9, 0x51, 0x27, 0x24, 0xbc, 0xf8,
+ 0xbf, 0x63, 0x52, 0xef, 0xbd, 0xb8, 0x07, 0xe8, 0xf6, 0xaa, 0x3d, 0x02, 0x28,
+ 0xfe, 0x44, 0xd4, 0xe4, 0x04, 0x10, 0x61, 0x95, 0x6c, 0x87, 0x06, 0x2a, 0x5c,
+ 0xdb, 0x67, 0x0d, 0xac, 0x1a, 0x02, 0x2e, 0x66, 0x35, 0x08, 0x28, 0x29, 0x24,
+ 0x8e, 0xad, 0x4c, 0x3b, 0x6a, 0x99, 0x88, 0xd6, 0x32, 0xa6, 0x7d, 0xc3, 0x0c,
+ 0x3d, 0xbc, 0x0b, 0xff, 0x86, 0x8d, 0xc6, 0x50, 0x8b, 0xad, 0x1f, 0x1f, 0xf7,
+ 0x06, 0xc5, 0x9e, 0x0c, 0x6f, 0xbb, 0x3c, 0x02, 0x5c, 0x67, 0xa7, 0xaf, 0x53,
+ 0x63, 0x5a, 0xae, 0x99, 0x47, 0x93, 0x61, 0xc8, 0x4f, 0xfb, 0x03, 0xec, 0xfe,
+ 0xa3, 0xc1, 0xee, 0x45, 0xf8, 0x56, 0x73, 0x88, 0xf4, 0x14, 0x6d, 0x96, 0x7c,
+ 0xdc, 0x88, 0x01, 0x99, 0x04, 0x18, 0x3d, 0x42, 0x56, 0x57, 0x54, 0xd7, 0xed,
+ 0xf8, 0x6b, 0x46, 0xff, 0x01, 0xe6, 0x1a, 0x75, 0x37, 0xd4, 0xf6, 0xb2, 0x57,
+ 0x61, 0x6b, 0xbf, 0x24, 0x99, 0x6d, 0xcd, 0x63, 0xc6, 0x45, 0xd0, 0x0a, 0x93,
+ 0x5c, 0xbb, 0xd3, 0x36, 0xac, 0xfa, 0x57, 0x51, 0xa0, 0xcf, 0x32, 0x0e, 0xb3,
+ 0x57, 0xf3, 0x02, 0x77, 0x02, 0x00, 0x88, 0x01, 0x00, 0x03, 0x08, 0x03, 0x01,
+ 0x00, 0x01, 0xbd, 0x60, 0x70, 0x38, 0x41, 0x94, 0x7f, 0xfd, 0x32, 0x58, 0x14,
+ 0xc5, 0x2d, 0x22, 0x93, 0x67, 0x70, 0x63, 0xf2, 0x62, 0x04, 0x8a, 0x55, 0xf8,
+ 0x48, 0x4a, 0x65, 0x5e, 0xcb, 0x71, 0xcc, 0x4d, 0x73, 0xa4, 0x25, 0x8f, 0x8e,
+ 0xbb, 0x42, 0x31, 0xd0, 0xdc, 0x58, 0x26, 0xda, 0x2d, 0x8b, 0x13, 0xdc, 0x3a,
+ 0x2e, 0xa3, 0xc5, 0x0d, 0x29, 0xe0, 0xe6, 0xa5, 0x6a, 0xd4, 0xe6, 0x05, 0xc9,
+ 0x30, 0x6d, 0xdc, 0x34, 0x29, 0xa6, 0xa0, 0xe7, 0x00, 0xfa, 0xe2, 0x4f, 0x05,
+ 0xb9, 0xa8, 0x84, 0x0d, 0x0c, 0xd1, 0x6f, 0xdf, 0x8c, 0xa8, 0xeb, 0x7b, 0x00,
+ 0x74, 0x17, 0x94, 0xe0, 0x6f, 0x6d, 0xbf, 0xb7, 0x73, 0x4f, 0x9b, 0x0f, 0xc8,
+ 0x08, 0x26, 0x56, 0x1e, 0x47, 0x0c, 0x27, 0xbe, 0xe9, 0x73, 0x36, 0xf8, 0x87,
+ 0xa5, 0xd7, 0xe9, 0x14, 0x28, 0x27, 0xa5, 0xf0, 0x87, 0x32, 0xd7, 0xd8, 0x51,
+ 0x00, 0x00, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x2b, 0x00, 0x90, 0x08, 0x01,
+ 0x00, 0x02, 0xa3, 0x00, 0x4c, 0x90, 0x0c, 0x80, 0x4c, 0x86, 0xc3, 0xf0, 0xa1,
+ 0x20, 0x10, 0x1a, 0xab, 0x3c, 0x50, 0xae, 0x3f, 0x7f, 0x49, 0x4a, 0x3f, 0xfc,
+ 0xf1, 0xfb, 0x5c, 0x63, 0x76, 0x7f, 0x60, 0xf8, 0x0e, 0x08, 0x30, 0x23, 0xb1,
+ 0xe7, 0xa9, 0xbc, 0x23, 0xa4, 0x1a, 0xaf, 0xc5, 0x99, 0x3e, 0x85, 0x1f, 0x0b,
+ 0xf3, 0x7f, 0x04, 0x12, 0x5b, 0x7e, 0x26, 0xb1, 0x87, 0xa0, 0x4c, 0xd9, 0xaf,
+ 0xf0, 0x30, 0xeb, 0x88, 0xb0, 0xf6, 0x88, 0xb5, 0x10, 0xb7, 0xc9, 0xa8, 0xc8,
+ 0xc0, 0xc0, 0x26, 0x69, 0x16, 0x90, 0xec, 0xec, 0x53, 0xf2, 0xc4, 0x24, 0x7c,
+ 0x24, 0xc0, 0x67, 0x09, 0x29, 0x4b, 0xcc, 0x80, 0x92, 0xe5, 0xd9, 0xc4, 0xa3,
+ 0x18, 0x0b, 0x16, 0x65, 0xc2, 0x11, 0x7a, 0x3b, 0xb1, 0xc0, 0xaf, 0x0b, 0x93,
+ 0xe6, 0x7b, 0x76, 0x25, 0x18, 0x7a, 0x1e, 0x8e, 0x4f, 0x50, 0xf2, 0xb4, 0xda,
+ 0x72, 0x72, 0x44, 0x3a, 0x18, 0xf9, 0xed, 0x72, 0x05, 0x19, 0x77, 0x34, 0x02,
+ 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x10, 0x07, 0x01, 0x00, 0x00,
+ 0x03, 0x84, 0x4c, 0x90, 0xea, 0x0d, 0x4c, 0x7e, 0x66, 0xfd, 0x53, 0x76, 0x37,
+ 0x11, 0x28, 0x49, 0x49, 0xa9, 0xaa, 0x7e, 0xe7, 0xc6, 0x2b, 0x0f, 0x0e, 0x76,
+ 0xb7, 0xa6, 0x15, 0x4d, 0xcf, 0x95, 0x9e, 0x5b, 0x25, 0x5a, 0x52, 0xcc, 0x62,
+ 0xd7, 0x31, 0x2b, 0x6a, 0x35, 0xf7, 0x9f, 0x5b, 0xc1, 0x5e, 0xba, 0xc1, 0x53,
+ 0x98, 0x3e, 0xc8, 0x6c, 0x21, 0x6f, 0xf1, 0x93, 0xb6, 0xb7, 0x6e, 0x65, 0x04,
+ 0x30, 0xe2, 0x0c, 0x6d, 0xa5, 0xdd, 0x15, 0xd4, 0x01, 0xb8, 0xd3, 0x9b, 0xd2,
+ 0x86, 0x38, 0x24, 0x6f, 0xed, 0x03, 0x47, 0xb4, 0x9e, 0x0b, 0x1a, 0xe3, 0x16,
+ 0x7d, 0x20, 0x68, 0x50, 0xe5, 0xb1, 0x2c, 0xae, 0x14, 0xc0, 0xdc, 0x09, 0x31,
+ 0x6d, 0xa0, 0x4e, 0x55, 0xdc, 0x65, 0xbe, 0xe5, 0x89, 0xe4, 0x35, 0x57, 0x3e,
+ 0x2b, 0xda, 0x06, 0x8d, 0xef, 0xc8, 0xdf, 0xf9, 0xf6, 0xc3, 0x09, 0x39, 0xc7,
+ 0x83, 0xe9, 0xe0, 0xf0, 0x2e, 0xad, 0x21, 0x56, 0x8b, 0x60, 0xf9, 0x84, 0x53,
+ 0xac, 0x1e, 0x84, 0x42, 0x7a, 0xfa, 0xa1, 0xbd, 0x86, 0x61, 0x12, 0xd0, 0x70,
+ 0xdc, 0x54, 0x50, 0x0e, 0xbe, 0x1a, 0x47, 0xe4, 0x38, 0x96, 0xb4, 0xe7, 0x3c,
+ 0x26, 0xae, 0x1d, 0x7e, 0x37, 0x28, 0xf5, 0x54, 0xe6, 0x94, 0x63, 0x30, 0x42,
+ 0x7e, 0x52, 0xb2, 0x8b, 0xda, 0x96, 0x44, 0x0c, 0xa4, 0xda, 0x33, 0x28, 0x77,
+ 0x02, 0xdf, 0xcf, 0xa0, 0xc7, 0x14, 0x2b, 0x68, 0xbb, 0x5d, 0x1b, 0x7e, 0x32,
+ 0x5c, 0xf2, 0x0e, 0xcb, 0x1b, 0xe1, 0x6d, 0x1c, 0xb8, 0x96, 0xbf, 0x0d, 0x1a,
+ 0xcc, 0x0f, 0x2f, 0xfd, 0x25, 0xff, 0x33, 0x3d, 0x89, 0x6d, 0x27, 0x9e, 0xe0,
+ 0xb9, 0x5a, 0x72, 0xbb, 0x2f, 0xe5, 0x95, 0xbb, 0x40, 0xb6, 0x4c, 0x11, 0x6c,
+ 0x80, 0xb6, 0x9e, 0xa9, 0xd9, 0x31, 0x61, 0xb9, 0x69, 0x9c, 0xf2, 0xe8, 0xc5,
+ 0xa0, 0xfd, 0x07, 0x59, 0x87, 0x38, 0xff, 0x25, 0x04, 0x00, 0x88, 0x01, 0x00,
+ 0x03, 0x07, 0x03, 0x01, 0x00, 0x01, 0x80, 0x97, 0x87, 0xf6, 0x40, 0x06, 0x2f,
+ 0x24, 0x88, 0x92, 0x03, 0x5d, 0x89, 0xb2, 0x52, 0x51, 0xf3, 0x0b, 0x40, 0x87,
+ 0x78, 0x1c, 0xea, 0x72, 0x9c, 0x99, 0x00, 0x88, 0xc2, 0xed, 0xd2, 0xb5, 0xc2,
+ 0x44, 0x58, 0x55, 0xc5, 0x2f, 0x22, 0x5a, 0x53, 0x3a, 0x99, 0xce, 0x55, 0x57,
+ 0xdc, 0x0b, 0x73, 0xf2, 0xf5, 0x48, 0xbf, 0xc7, 0x8e, 0x6a, 0x29, 0xbd, 0x0b,
+ 0xca, 0xdb, 0xca, 0xed, 0x66, 0x00, 0x7b, 0x75, 0xb2, 0x38, 0xec, 0x24, 0xe6,
+ 0x49, 0x70, 0x22, 0xa4, 0x42, 0xff, 0x4a, 0x78, 0x96, 0xe6, 0x9f, 0x6d, 0xdd,
+ 0xb2, 0x85, 0x13, 0x05, 0xee, 0xab, 0x8e, 0x05, 0x5a, 0x98, 0xac, 0xba, 0x07,
+ 0xc2, 0xff, 0x22, 0xf4, 0xba, 0xd5, 0xfa, 0xbf, 0x1d, 0x84, 0x1e, 0xeb, 0x5e,
+ 0xff, 0xe5, 0x91, 0x34, 0x88, 0xea, 0x61, 0x19, 0xb2, 0x0e, 0x6b, 0x0d, 0xf7,
+ 0x9e, 0xf1, 0x8c, 0xb5, 0x00, 0x88, 0x01, 0x00, 0x03, 0x07, 0x03, 0x01, 0x00,
+ 0x01, 0xc9, 0x06, 0x00, 0x53, 0x45, 0x4a, 0x0b, 0xb8, 0xe2, 0xb0, 0x4e, 0x29,
+ 0xc8, 0x19, 0xb4, 0xa3, 0x63, 0x27, 0xe2, 0xcd, 0xc7, 0xc7, 0x6d, 0x60, 0x31,
+ 0xeb, 0xc0, 0x82, 0x5f, 0x44, 0x14, 0x96, 0x60, 0x4e, 0xc8, 0x62, 0xf4, 0xcc,
+ 0xb9, 0x99, 0x7a, 0x19, 0xf0, 0xaf, 0x34, 0xd9, 0x63, 0xca, 0x40, 0xe3, 0x7b,
+ 0xb6, 0xbc, 0xfa, 0x40, 0x08, 0x1d, 0xe7, 0xc3, 0xa4, 0xd2, 0x73, 0x3a, 0x32,
+ 0xf2, 0xa4, 0x4c, 0x3c, 0x4f, 0xd6, 0x52, 0x52, 0xc8, 0x6d, 0xa5, 0xf6, 0xd9,
+ 0x4d, 0x0c, 0xfd, 0xb4, 0x93, 0x8b, 0x61, 0x72, 0xdb, 0x6e, 0x5f, 0x2d, 0xd9,
+ 0x2d, 0xab, 0x18, 0x2f, 0x87, 0x2d, 0xbf, 0x8d, 0x42, 0x37, 0x93, 0x41, 0x18,
+ 0xf6, 0x93, 0x97, 0xda, 0x27, 0x31, 0xdc, 0xda, 0xec, 0x21, 0x16, 0x61, 0xe1,
+ 0xe0, 0x7a, 0x53, 0x26, 0x82, 0xc7, 0x62, 0x99, 0x18, 0x81, 0x6a, 0x65, 0x01,
+ 0x08, 0x01, 0x01, 0x03, 0x07, 0x03, 0x01, 0x00, 0x01, 0x8a, 0x58, 0x7e, 0x3d,
+ 0xda, 0x69, 0x1c, 0xf3, 0x93, 0x15, 0x90, 0xa8, 0xc7, 0x65, 0xed, 0x81, 0x31,
+ 0x63, 0xcd, 0x4d, 0x75, 0x84, 0xaf, 0xfa, 0xa6, 0xb2, 0xb9, 0x90, 0xe8, 0x76,
+ 0x76, 0x7d, 0x20, 0xc8, 0x74, 0x6f, 0x03, 0x1c, 0x61, 0xa5, 0x54, 0x77, 0x33,
+ 0x40, 0x6d, 0x57, 0x89, 0xf2, 0x07, 0x7a, 0x8e, 0xad, 0x6c, 0x47, 0x75, 0x6f,
+ 0x3f, 0xf4, 0x91, 0xdf, 0xa9, 0xa6, 0x1a, 0xcb, 0x1b, 0x57, 0x85, 0x1d, 0x97,
+ 0x93, 0x91, 0x0e, 0xda, 0xa2, 0x64, 0xfd, 0x93, 0x0c, 0xd0, 0xc7, 0xc4, 0x49,
+ 0xca, 0x29, 0x35, 0xfe, 0x8d, 0x67, 0xf2, 0xb5, 0x97, 0x93, 0xed, 0xdd, 0xc0,
+ 0x6d, 0x2c, 0xc1, 0x28, 0x2d, 0x2f, 0xee, 0xe6, 0x6b, 0x33, 0xa3, 0x36, 0x7a,
+ 0x82, 0x67, 0x97, 0xa8, 0x9d, 0xeb, 0xaa, 0xc4, 0x52, 0x64, 0x02, 0xda, 0x9f,
+ 0x43, 0xae, 0xb0, 0xe0, 0xf4, 0x5e, 0xad, 0x5c, 0x2f, 0x42, 0x0f, 0xfc, 0xc2,
+ 0xef, 0xfc, 0xbe, 0x04, 0xd3, 0x69, 0x88, 0xe7, 0x67, 0x33, 0x90, 0xd7, 0x93,
+ 0xb1, 0xe1, 0x66, 0x6e, 0xeb, 0x6b, 0xd1, 0x3b, 0x96, 0xd2, 0xf5, 0xde, 0x1d,
+ 0xa6, 0xc7, 0xb9, 0x04, 0x81, 0x4f, 0x1e, 0xea, 0x7a, 0x49, 0x94, 0x2a, 0x17,
+ 0x8e, 0xb6, 0x88, 0x06, 0x05, 0x03, 0xb6, 0x16, 0x2c, 0xe3, 0xc5, 0xbf, 0xb1,
+ 0xd4, 0xc3, 0x2e, 0xee, 0xcd, 0xe7, 0xda, 0xe3, 0x08, 0x6f, 0x9b, 0xa6, 0x29,
+ 0x7e, 0x73, 0xca, 0x19, 0xf5, 0xfe, 0xcd, 0x47, 0x7a, 0xa6, 0x49, 0x3a, 0x53,
+ 0x3f, 0x59, 0xbc, 0xe9, 0x1a, 0x94, 0x42, 0x75, 0x44, 0xae, 0x27, 0xeb, 0x1f,
+ 0xc2, 0xa3, 0x0e, 0xa2, 0xfe, 0xdf, 0x0c, 0xd4, 0x74, 0x5e, 0x40, 0x0a, 0x46,
+ 0x30, 0xb7, 0x55, 0xe1, 0x3d, 0x53, 0xd4, 0xfb, 0x04, 0x88, 0x97, 0x36, 0xda,
+ 0x01, 0x03, 0x78, 0xf4, 0xf5, 0x01, 0x08, 0x01, 0x01, 0x03, 0x07, 0x03, 0x01,
+ 0x00, 0x01, 0x94, 0xe3, 0x6c, 0x83, 0xb9, 0x90, 0x8a, 0x71, 0x59, 0x4b, 0x72,
+ 0x5d, 0xcf, 0x1a, 0xbe, 0xc2, 0xb2, 0x1c, 0x82, 0x19, 0xf8, 0xb8, 0xc2, 0xd8,
+ 0x3b, 0xfc, 0x9d, 0xa3, 0xbe, 0x4f, 0x3e, 0x97, 0xd9, 0xfa, 0xb3, 0x0c, 0x2d,
+ 0x5b, 0x76, 0xae, 0xc7, 0x95, 0x9c, 0x2d, 0x91, 0xaa, 0x93, 0x90, 0xc5, 0x55,
+ 0x27, 0xef, 0x20, 0x13, 0xd1, 0x48, 0xad, 0xe1, 0x89, 0xe1, 0xcf, 0x06, 0xd4,
+ 0x67, 0x5b, 0x8d, 0x08, 0x1b, 0x3f, 0x53, 0xb2, 0x60, 0x81, 0xbb, 0x38, 0x74,
+ 0xdc, 0xe2, 0x1b, 0xf9, 0x4f, 0x63, 0x65, 0xc9, 0x6a, 0xfa, 0x93, 0xa4, 0x05,
+ 0xcf, 0xdf, 0x10, 0xe3, 0x3c, 0x05, 0x20, 0x64, 0xc5, 0x56, 0xfc, 0x01, 0x86,
+ 0x6a, 0xcc, 0x0d, 0x8b, 0x0e, 0x4e, 0xd5, 0xda, 0x90, 0xae, 0x90, 0xc0, 0x7a,
+ 0x2f, 0x03, 0x5f, 0xbc, 0xdc, 0x1b, 0x14, 0x00, 0x2c, 0x65, 0x89, 0xda, 0x70,
+ 0x07, 0x48, 0x50, 0x69, 0xc6, 0xc3, 0xeb, 0x1f, 0x88, 0xd9, 0x10, 0x83, 0xcd,
+ 0x8b, 0x93, 0xce, 0x3e, 0xb8, 0x26, 0xfd, 0x3f, 0xf5, 0x7b, 0x17, 0xe8, 0x06,
+ 0x15, 0xdd, 0xe6, 0xdc, 0x82, 0x7e, 0x21, 0x2f, 0x58, 0xc8, 0x47, 0x67, 0x89,
+ 0x63, 0x25, 0xe5, 0xac, 0x0a, 0x16, 0xc5, 0xdc, 0xf1, 0x71, 0x6f, 0xff, 0xe7,
+ 0x27, 0x8b, 0xe5, 0x15, 0x56, 0xba, 0x14, 0x71, 0x7a, 0x39, 0xa7, 0x49, 0x59,
+ 0xc2, 0xbb, 0x19, 0x1f, 0x4b, 0x80, 0x10, 0xe3, 0xce, 0x4a, 0x1f, 0x6b, 0x69,
+ 0x75, 0xb5, 0x9c, 0x0a, 0x8a, 0x4b, 0x25, 0x9b, 0x3a, 0xb7, 0x0f, 0x2a, 0xde,
+ 0x35, 0x9c, 0xa5, 0x31, 0xb3, 0x76, 0x1f, 0xef, 0xdf, 0x17, 0x58, 0x7c, 0xda,
+ 0x50, 0x35, 0xc3, 0xc8, 0x98, 0x59, 0x71, 0x02, 0xe9, 0xf7, 0x06, 0xd3, 0x91,
+ 0x3c, 0x0d, 0xab, 0xf2, 0xd8, 0xba, 0x30, 0xda, 0x09, 0x10, 0x75, 0x0a, 0x64,
+ 0x6e, 0x73, 0x73, 0x65, 0x63, 0x2d, 0x65, 0x78, 0x70, 0x03, 0x6f, 0x72, 0x67,
+ 0x00, 0x00, 0x2b, 0x00, 0x90, 0x07, 0x02, 0x00, 0x01, 0x51, 0x80, 0x4c, 0x90,
+ 0xea, 0x0d, 0x4c, 0x7e, 0x66, 0xfd, 0x93, 0xb4, 0x39, 0xee, 0x27, 0x29, 0x54,
+ 0x9e, 0x57, 0x41, 0x12, 0x60, 0x19, 0xf6, 0x3f, 0xa6, 0xba, 0xd6, 0x41, 0x98,
+ 0x57, 0xec, 0x30, 0x9e, 0x96, 0x08, 0x8c, 0x13, 0xa9, 0x76, 0x95, 0x74, 0xcd,
+ 0xcd, 0x2e, 0xa6, 0x22, 0x21, 0x44, 0x3f, 0x13, 0xdf, 0x7a, 0x33, 0xf1, 0x8c,
+ 0x4c, 0xf9, 0xa3, 0x6d, 0x50, 0x38, 0xfa, 0x71, 0x7b, 0x7a, 0xfe, 0x54, 0xa9,
+ 0x44, 0x81, 0x8c, 0xd5, 0x04, 0x9e, 0x46, 0x89, 0xda, 0x26, 0x43, 0x40, 0xf6,
+ 0xd7, 0x23, 0x48, 0x07, 0x0e, 0x48, 0x2e, 0x19, 0x0d, 0x41, 0x27, 0x85, 0x75,
+ 0x1e, 0xa0, 0xa9, 0xad, 0x39, 0xaf, 0x8d, 0xc1, 0xed, 0xc5, 0x93, 0x73, 0x05,
+ 0x09, 0x7a, 0x8f, 0xf0, 0x97, 0xc3, 0x98, 0xab, 0xcc, 0x7c, 0xbf, 0x48, 0xef,
+ 0xea, 0x34, 0xf3, 0xe6, 0x5d, 0x8d, 0x1b, 0xbe, 0x43, 0x97, 0x56, 0x4e, 0x60,
+ 0x9f, 0xdd, 0x1b, 0xf5, 0x15, 0x6c, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0xa8, 0x01, 0x00, 0x03, 0x05, 0x03, 0x01, 0x00, 0x01, 0xd0, 0x0a,
+ 0x64, 0x8e, 0xb5, 0x90, 0x0b, 0x75, 0xc2, 0xeb, 0x52, 0x5f, 0xa4, 0xcb, 0xeb,
+ 0x1d, 0x77, 0x8d, 0x84, 0x2c, 0xef, 0xb6, 0x88, 0xd4, 0x7c, 0x50, 0x4c, 0x52,
+ 0x7b, 0x9d, 0x37, 0x31, 0x36, 0xb2, 0x5b, 0x6c, 0x47, 0xb4, 0x21, 0x80, 0x61,
+ 0x46, 0xfa, 0x5b, 0x44, 0x50, 0x91, 0x9d, 0xf8, 0xc1, 0x78, 0x00, 0x78, 0x29,
+ 0xfe, 0xe2, 0x08, 0x65, 0xf8, 0xc9, 0xdf, 0x69, 0x0b, 0x59, 0x6b, 0xf4, 0x93,
+ 0x9f, 0x8b, 0x25, 0x0b, 0x6b, 0x93, 0x12, 0x06, 0x57, 0xc8, 0x04, 0x9d, 0x3f,
+ 0x33, 0xbd, 0x2b, 0x35, 0x54, 0xb9, 0x98, 0x75, 0xe4, 0xb0, 0x49, 0x3c, 0x29,
+ 0xc1, 0xfb, 0x74, 0xbc, 0x91, 0x82, 0x9e, 0xc5, 0x61, 0xa6, 0x16, 0xe1, 0xf0,
+ 0x8f, 0xe9, 0xe1, 0x23, 0x55, 0x5e, 0xfb, 0xf1, 0xcc, 0x8a, 0x75, 0x5d, 0xf2,
+ 0x86, 0x89, 0x0a, 0x29, 0xcb, 0xca, 0x33, 0xde, 0x9d, 0x74, 0x43, 0x0d, 0xde,
+ 0x67, 0xde, 0x71, 0x0f, 0x7f, 0xa3, 0xbb, 0x22, 0x82, 0x81, 0x66, 0xd1, 0xbd,
+ 0x49, 0x0d, 0x89, 0x45, 0xd7, 0x18, 0xcf, 0x98, 0x2c, 0x19, 0xaf, 0x63, 0x16,
+ 0x20, 0x91, 0x03, 0x77, 0x77, 0x77, 0x0a, 0x64, 0x6e, 0x73, 0x73, 0x65, 0x63,
+ 0x2d, 0x65, 0x78, 0x70, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x05, 0x00, 0xb0,
+ 0x05, 0x03, 0x00, 0x00, 0x00, 0x3c, 0x4c, 0xae, 0xeb, 0xfc, 0x4c, 0x87, 0x59,
+ 0xf6, 0x83, 0x7f, 0x01, 0x90, 0xde, 0x40, 0xa3, 0x42, 0x73, 0x59, 0xb7, 0xc7,
+ 0x3a, 0xe1, 0x01, 0xae, 0x5c, 0x0f, 0xd4, 0x22, 0x9d, 0xb5, 0x88, 0xb8, 0xbb,
+ 0x14, 0x95, 0x7f, 0xfa, 0xa7, 0xff, 0x48, 0x30, 0x90, 0x4c, 0x1b, 0x71, 0x33,
+ 0x1c, 0x36, 0xbc, 0xaf, 0xae, 0x1d, 0x97, 0xec, 0xee, 0x71, 0xb8, 0xb1, 0x2a,
+ 0x19, 0xd7, 0xf3, 0x25, 0x78, 0x94, 0x59, 0x54, 0xbb, 0x2b, 0xac, 0xe6, 0x3c,
+ 0x3e, 0x7e, 0x43, 0x7c, 0x2d, 0xc0, 0x72, 0x58, 0xe8, 0x4a, 0xa2, 0xed, 0x1f,
+ 0x39, 0x5f, 0x6a, 0x98, 0x62, 0xd0, 0xfc, 0x6e, 0xbe, 0x01, 0x1f, 0xa0, 0x39,
+ 0xf2, 0xb4, 0x4d, 0x33, 0x9b, 0x4d, 0xe3, 0x81, 0x65, 0x77, 0x80, 0x3d, 0x2c,
+ 0x44, 0xee, 0x1a, 0x65, 0xf7, 0x25, 0x68, 0x95, 0x3f, 0xa1, 0x22, 0xd5, 0x9d,
+ 0x59, 0x7e, 0xa7, 0xa6, 0xf2, 0x7e, 0x4d, 0x47, 0x8b, 0x98, 0x4a, 0x0d, 0x16,
+ 0xa1, 0x78, 0x12, 0xc7, 0x90, 0xe2, 0xe9, 0x6d, 0xe6, 0x89, 0xf3, 0xa1, 0xc4,
+ 0x30, 0xbd, 0xe8, 0xf9, 0x75, 0xc6, 0x49, 0x9e, 0x5f, 0x9c, 0x1e, 0x23, 0xb5,
+ 0x0e, 0x82, 0x70, 0x8e, 0xb3, 0x0d, 0x1c, 0x0a, 0x64, 0x6e, 0x73, 0x73, 0x65,
+ 0x63, 0x2d, 0x65, 0x78, 0x70, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x0a, 0x64, 0x6e,
+ 0x73, 0x73, 0x65, 0x63, 0x2d, 0x65, 0x78, 0x70, 0x03, 0x6f, 0x72, 0x67, 0x00,
+ 0x00, 0x10, 0x00, 0xb0, 0x05, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x4c, 0xae, 0xf6,
+ 0xe5, 0x4c, 0x87, 0x5e, 0xd9, 0x83, 0x7f, 0x2a, 0x88, 0x85, 0xb8, 0xf1, 0x73,
+ 0x93, 0xe3, 0x85, 0xee, 0xc8, 0x93, 0x34, 0x2d, 0xd2, 0x47, 0x2d, 0x86, 0xe5,
+ 0xc6, 0x18, 0x69, 0x94, 0x94, 0x7a, 0x2d, 0x7e, 0xa2, 0x57, 0xf1, 0x75, 0x3e,
+ 0x51, 0xbf, 0xaa, 0xed, 0xdd, 0xf8, 0x1a, 0xb9, 0x1e, 0x86, 0x6f, 0x7f, 0xe9,
+ 0xdc, 0xad, 0x83, 0xda, 0x7d, 0xcd, 0x2d, 0x4d, 0x9b, 0xe3, 0x66, 0x92, 0xb9,
+ 0x21, 0x96, 0xbf, 0xea, 0x70, 0x55, 0xbf, 0xb3, 0xb0, 0x85, 0x90, 0x72, 0x5f,
+ 0x09, 0xd1, 0x7c, 0x49, 0x25, 0x07, 0x79, 0x34, 0x48, 0xe7, 0x1c, 0xaa, 0x53,
+ 0x33, 0xcb, 0x62, 0xb9, 0x9f, 0x42, 0x6e, 0x36, 0x00, 0x31, 0xab, 0x9f, 0xcc,
+ 0xf5, 0xa9, 0x02, 0x2f, 0x75, 0x4c, 0xf1, 0xd6, 0x86, 0x3a, 0x7f, 0x08, 0xe4,
+ 0x72, 0x7d, 0x34, 0xe0, 0x40, 0x76, 0xd1, 0xf0, 0xe3, 0x98, 0x37, 0xe7, 0x93,
+ 0x94, 0x57, 0x95, 0x6c, 0xde, 0x9e, 0x17, 0x57, 0x3a, 0x78, 0xe9, 0x8b, 0x57,
+ 0x7f, 0x74, 0xe2, 0xaf, 0xf8, 0xaf, 0x11, 0x64, 0xa9, 0xe9, 0xdb, 0xb2, 0x58,
+ 0xda, 0x7c, 0xfe, 0x3f, 0x52, 0x06, 0x39, 0xfc, 0xdd, 0x1c, 0x1c, 0x01, 0x00,
+ 0x3a, 0x39, 0x76, 0x3d, 0x74, 0x6c, 0x73, 0x31, 0x20, 0x68, 0x61, 0x3d, 0x73,
+ 0x68, 0x61, 0x31, 0x20, 0x68, 0x3d, 0x31, 0x30, 0x39, 0x63, 0x38, 0x31, 0x34,
+ 0x36, 0x33, 0x30, 0x34, 0x64, 0x65, 0x37, 0x63, 0x34, 0x63, 0x38, 0x37, 0x30,
+ 0x35, 0x62, 0x63, 0x63, 0x31, 0x64, 0x38, 0x61, 0x32, 0x63, 0x32, 0x33, 0x37,
+ 0x66, 0x30, 0x35, 0x35, 0x38, 0x64, 0x37,
+};
+
+TEST(DNSSECChainVerifierTest, TestChain) {
+ base::StringPiece chain(reinterpret_cast<const char*>(kChain),
+ sizeof(kChain));
+ net::DNSSECChainVerifier verifier(FromDNSName("dnssec-exp.org"), chain);
+ verifier.IgnoreTimestamps();
+ ASSERT_EQ(net::DNSSECChainVerifier::OK, verifier.Verify());
+ ASSERT_EQ(net::kDNS_CERT, verifier.rrtype());
+}
+
+TEST(DNSSECChainVerifierTest, OffCourse) {
+ base::StringPiece chain(reinterpret_cast<const char*>(kChain),
+ sizeof(kChain));
+ net::DNSSECChainVerifier verifier(FromDNSName("foo.org"), chain);
+ verifier.IgnoreTimestamps();
+ ASSERT_EQ(net::DNSSECChainVerifier::OFF_COURSE, verifier.Verify());
+}
+
+TEST(DNSSECChainVerifierTest, BadTarget) {
+ base::StringPiece chain(reinterpret_cast<const char*>(kChain),
+ sizeof(kChain));
+ net::DNSSECChainVerifier verifier(FromDNSName("www.dnssec-exp.org"), chain);
+ verifier.IgnoreTimestamps();
+ ASSERT_EQ(net::DNSSECChainVerifier::BAD_TARGET, verifier.Verify());
+}
+
+TEST(DNSSECChainVerifierTest, TestCNAMEChain) {
+ base::StringPiece chain(reinterpret_cast<const char*>(kCNAMEChain),
+ sizeof(kCNAMEChain));
+ net::DNSSECChainVerifier verifier(FromDNSName("www.dnssec-exp.org"), chain);
+ verifier.IgnoreTimestamps();
+ ASSERT_EQ(net::DNSSECChainVerifier::OK, verifier.Verify());
+ ASSERT_EQ(net::kDNS_TXT, verifier.rrtype());
+}
+
+// This is too slow to run all the time.
+TEST(DNSSECChainVerifierTest, DISABLED_Fuzz) {
+ uint8 copy[sizeof(kChain)];
+ base::StringPiece chain(reinterpret_cast<const char*>(copy), sizeof(copy));
+ static const unsigned bit_length = sizeof(kChain) * 8;
+
+ for (unsigned bit_to_flip = 0; bit_to_flip < bit_length; bit_to_flip++) {
+ memcpy(copy, kChain, sizeof(copy));
+
+ unsigned byte = bit_to_flip >> 3;
+ unsigned bit = bit_to_flip & 7;
+ copy[byte] ^= (1 << bit);
+
+ net::DNSSECChainVerifier verifier(FromDNSName("dnssec-exp.org"), chain);
+ verifier.IgnoreTimestamps();
+ ASSERT_NE(net::DNSSECChainVerifier::OK, verifier.Verify());
+ }
+}
+
+// StringToTXTRecord takes a NUL terminated string and returns a valid TXT
+// RRDATA by prefixing an 8-bit length.
+static std::string StringToTXTRecord(const char* in) {
+ const unsigned len = strlen(in);
+ CHECK_LT(len, 256u);
+ std::string wrapped;
+ char l = len;
+ wrapped.append(&l, 1);
+ wrapped.append(in, len);
+ return wrapped;
+}
+
+TEST(DNSSECChainVerifierTest, BadTXT) {
+ static const char *const kBadTXTRecords[] = {
+ "",
+ " ",
+ " a=b",
+ "a=b \t",
+ "abc!=1",
+ };
+
+ for (unsigned i = 0; i < arraysize(kBadTXTRecords); i++) {
+ std::string wrapped(StringToTXTRecord(kBadTXTRecords[i]));
+ EXPECT_TRUE(net::DNSSECChainVerifier::ParseTLSTXTRecord(wrapped).empty());
+ }
+
+ EXPECT_TRUE(net::DNSSECChainVerifier::ParseTLSTXTRecord(
+ std::string("a=b\0", 4)).empty());
+}
+
+static bool MatchMap(const std::map<std::string, std::string>& m,
+ const char* const* match) {
+ unsigned matched = 0;
+
+ for (unsigned i = 0; match[i]; i += 2) {
+ const char* key = match[i];
+ const char* value = match[i+1];
+ std::map<std::string, std::string>::const_iterator j;
+ j = m.find(key);
+ if (j == m.end())
+ return false;
+ if (j->second != value)
+ return false;
+ matched++;
+ }
+
+ if (m.size() != matched)
+ return false;
+ return true;
+}
+
+TEST(DNSSECChainVerifierTest, GoodTXT) {
+ // This array consists of a NULL terminated series of records. A record
+ // consists of a TXT string followed by a NULL terminated series of key,
+ // value pairs.
+ static const char *const kTXTRecords[] = {
+ "a=",
+ "a", "", NULL,
+
+ "a=b",
+ "a", "b", NULL,
+
+ "a=b c=",
+ "a", "b", "c", "", NULL,
+
+ "a=b a=c",
+ "a", "b", NULL,
+
+ "v=tls1 ha=sha1 h=<hexhash> sts=1",
+ "v", "tls1", "ha", "sha1", "h", "<hexhash>", "sts", "1", NULL,
+
+ NULL,
+ };
+
+ for (unsigned i = 0; kTXTRecords[i]; i++) {
+ std::string wrapped(StringToTXTRecord(kTXTRecords[i]));
+ std::map<std::string, std::string> m(
+ net::DNSSECChainVerifier::ParseTLSTXTRecord(wrapped));
+ ASSERT_FALSE(m.empty());
+ ASSERT_TRUE(MatchMap(m, &kTXTRecords[i+1]));
+ while (kTXTRecords[i])
+ i++;
+ }
+}
diff --git a/net/base/escape.cc b/net/base/escape.cc
index bc01e11..3c39f95 100644
--- a/net/base/escape.cc
+++ b/net/base/escape.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,30 +9,12 @@
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
#include "base/string_piece.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/utf_offset_string_conversions.h"
namespace {
-template <class char_type>
-inline bool IsHex(char_type ch) {
- return (ch >= '0' && ch <= '9') ||
- (ch >= 'A' && ch <= 'F') ||
- (ch >= 'a' && ch <= 'f');
-}
-
-template <class char_type>
-inline char_type HexToInt(char_type ch) {
- if (ch >= '0' && ch <= '9')
- return ch - '0';
- if (ch >= 'A' && ch <= 'F')
- return ch - 'A' + 10;
- if (ch >= 'a' && ch <= 'f')
- return ch - 'a' + 10;
- NOTREACHED();
- return 0;
-}
-
static const char* const kHexString = "0123456789ABCDEF";
inline char IntToHex(int i) {
DCHECK(i >= 0 && i <= 15) << i << " not a hex value";
@@ -141,9 +123,9 @@ STR UnescapeURLImpl(const STR& escaped_text,
static_cast<typename STR::value_type>(escaped_text[i + 1]));
const typename STR::value_type least_sig_digit(
static_cast<typename STR::value_type>(escaped_text[i + 2]));
- if (IsHex(most_sig_digit) && IsHex(least_sig_digit)) {
- unsigned char value = HexToInt(most_sig_digit) * 16 +
- HexToInt(least_sig_digit);
+ if (IsHexDigit(most_sig_digit) && IsHexDigit(least_sig_digit)) {
+ unsigned char value = HexDigitToInt(most_sig_digit) * 16 +
+ HexDigitToInt(least_sig_digit);
if (value >= 0x80 || // Unescape all high-bit characters.
// For 7-bit characters, the lookup table tells us all valid chars.
(kUrlUnescape[value] ||
diff --git a/net/base/escape.h b/net/base/escape.h
index b9b0b6a..315c647 100644
--- a/net/base/escape.h
+++ b/net/base/escape.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_ESCAPE_H_
#define NET_BASE_ESCAPE_H_
+#pragma once
#include <string>
diff --git a/net/base/escape_unittest.cc b/net/base/escape_unittest.cc
index 28972cb..01cd9e1 100644
--- a/net/base/escape_unittest.cc
+++ b/net/base/escape_unittest.cc
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -95,7 +96,7 @@ TEST(EscapeTest, EscapeTextForFormSubmission) {
EXPECT_EQ(out, std::string("+"));
} else if (no_escape.find(in) == std::string::npos) {
// Check %hex escaping
- std::string expected = StringPrintf("%%%02X", i);
+ std::string expected = base::StringPrintf("%%%02X", i);
EXPECT_EQ(expected, out);
} else {
// No change for things in the no_escape list.
diff --git a/net/base/ev_root_ca_metadata.cc b/net/base/ev_root_ca_metadata.cc
index 023b1fb..3aa02e5 100644
--- a/net/base/ev_root_ca_metadata.cc
+++ b/net/base/ev_root_ca_metadata.cc
@@ -281,4 +281,7 @@ EVRootCAMetadata::EVRootCAMetadata() {
#endif
}
+EVRootCAMetadata::~EVRootCAMetadata() {
+}
+
} // namespace net
diff --git a/net/base/ev_root_ca_metadata.h b/net/base/ev_root_ca_metadata.h
index b1b2781..e9e8130 100644
--- a/net/base/ev_root_ca_metadata.h
+++ b/net/base/ev_root_ca_metadata.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_EV_ROOT_CA_METADATA_H_
#define NET_BASE_EV_ROOT_CA_METADATA_H_
+#pragma once
#include "build/build_config.h"
@@ -43,7 +44,7 @@ class EVRootCAMetadata {
private:
EVRootCAMetadata();
- ~EVRootCAMetadata() { }
+ ~EVRootCAMetadata();
friend struct DefaultSingletonTraits<EVRootCAMetadata>;
diff --git a/net/base/file_stream.h b/net/base/file_stream.h
index a6d5739..6a53204 100644
--- a/net/base/file_stream.h
+++ b/net/base/file_stream.h
@@ -1,6 +1,6 @@
-// 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.
// This file defines FileStream, a basic interface for reading and writing files
// synchronously or asynchronously with support for seeking to an offset.
@@ -9,6 +9,7 @@
#ifndef NET_BASE_FILE_STREAM_H_
#define NET_BASE_FILE_STREAM_H_
+#pragma once
#include "base/platform_file.h"
#include "base/scoped_ptr.h"
diff --git a/net/base/file_stream_posix.cc b/net/base/file_stream_posix.cc
index b83729a..75d8eb7 100644
--- a/net/base/file_stream_posix.cc
+++ b/net/base/file_stream_posix.cc
@@ -349,7 +349,7 @@ int FileStream::Open(const FilePath& path, int open_flags) {
}
open_flags_ = open_flags;
- file_ = base::CreatePlatformFile(path, open_flags_, NULL);
+ file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
if (file_ == base::kInvalidPlatformFileValue) {
LOG(WARNING) << "Failed to open file: " << errno
<< " (" << path.ToWStringHack() << ")";
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
index cf80699..b93d886 100644
--- a/net/base/file_stream_unittest.cc
+++ b/net/base/file_stream_unittest.cc
@@ -51,7 +51,7 @@ TEST_F(FileStreamTest, UseFileHandle) {
file_util::WriteFile(temp_file_path(), kTestData, kTestDataSize));
int flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ;
base::PlatformFile file = base::CreatePlatformFile(
- temp_file_path().ToWStringHack(), flags, &created);
+ temp_file_path(), flags, &created, NULL);
// Seek to the beginning of the file and read.
net::FileStream read_stream(file, flags);
@@ -66,8 +66,7 @@ TEST_F(FileStreamTest, UseFileHandle) {
// 2. Test writing with a file handle.
file_util::Delete(temp_file_path(), false);
flags = base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE;
- file = base::CreatePlatformFile(temp_file_path().ToWStringHack(),
- flags, &created);
+ file = base::CreatePlatformFile(temp_file_path(), flags, &created, NULL);
net::FileStream write_stream(file, flags);
ASSERT_EQ(0, write_stream.Seek(net::FROM_BEGIN, 0));
diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc
index 0460b3d..234ddf9 100644
--- a/net/base/file_stream_win.cc
+++ b/net/base/file_stream_win.cc
@@ -159,7 +159,7 @@ int FileStream::Open(const FilePath& path, int open_flags) {
}
open_flags_ = open_flags;
- file_ = base::CreatePlatformFile(path.value(), open_flags_, NULL);
+ file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
if (file_ == INVALID_HANDLE_VALUE) {
DWORD error = GetLastError();
LOG(WARNING) << "Failed to open file: " << error;
diff --git a/net/base/filter.cc b/net/base/filter.cc
index c72e00e..5e47ecb 100644
--- a/net/base/filter.cc
+++ b/net/base/filter.cc
@@ -108,17 +108,17 @@ void Filter::FixupEncodingTypes(
// When viewing a .svgz file, we need to uncompress it, but we don't
// want to do that when downloading.
// See Firefox's nonDecodableExtensions in nsExternalHelperAppService.cpp
- if (FILE_PATH_LITERAL(".gz" == extension) ||
- FILE_PATH_LITERAL(".tgz" == extension) ||
- FILE_PATH_LITERAL(".svgz") == extension)
+ if (EndsWith(extension, FILE_PATH_LITERAL(".gz"), false) ||
+ LowerCaseEqualsASCII(extension, ".tgz") ||
+ LowerCaseEqualsASCII(extension, ".svgz"))
encoding_types->clear();
} else {
// When the user does not explicitly ask to download a file, if we get a
// supported mime type, then we attempt to decompress in order to view it.
// However, if it's not a supported mime type, then we will attempt to
// download it, and in that case, don't decompress .gz/.tgz files.
- if ((FILE_PATH_LITERAL(".gz" == extension) ||
- FILE_PATH_LITERAL(".tgz") == extension) &&
+ if ((EndsWith(extension, FILE_PATH_LITERAL(".gz"), false) ||
+ LowerCaseEqualsASCII(extension, ".tgz")) &&
!net::IsSupportedMimeType(mime_type))
encoding_types->clear();
}
diff --git a/net/base/filter.h b/net/base/filter.h
index acc0e7e..d00a351 100644
--- a/net/base/filter.h
+++ b/net/base/filter.h
@@ -28,15 +28,16 @@
#ifndef NET_BASE_FILTER_H__
#define NET_BASE_FILTER_H__
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
class GURL;
@@ -200,7 +201,7 @@ class Filter {
protected:
explicit Filter(const FilterContext& filter_context);
- FRIEND_TEST(SdchFilterTest, ContentTypeId);
+ FRIEND_TEST_ALL_PREFIXES(SdchFilterTest, ContentTypeId);
// Filters the data stored in stream_buffer_ and writes the output into the
// dest_buffer passed in.
//
diff --git a/net/base/filter_unittest.h b/net/base/filter_unittest.h
index 9de5bb5..a45e353 100644
--- a/net/base/filter_unittest.h
+++ b/net/base/filter_unittest.h
@@ -5,6 +5,7 @@
#ifndef NET_BASE_FILTER_UNITTEST_H_
#define NET_BASE_FILTER_UNITTEST_H_
+#pragma once
#include <string>
diff --git a/net/base/forwarding_net_log.cc b/net/base/forwarding_net_log.cc
index 6cea529..efe6eff 100644
--- a/net/base/forwarding_net_log.cc
+++ b/net/base/forwarding_net_log.cc
@@ -56,12 +56,7 @@ class ForwardingNetLog::Core
DCHECK_EQ(MessageLoop::current(), loop_);
- // TODO(eroman): This shouldn't be necessary. See crbug.com/48806.
- NetLog::Source effective_source = source;
- if (effective_source.id == NetLog::Source::kInvalidId)
- effective_source.id = impl_->NextID();
-
- impl_->AddEntry(type, time, effective_source, phase, params);
+ impl_->AddEntry(type, time, source, phase, params);
}
Lock lock_;
@@ -91,10 +86,10 @@ uint32 ForwardingNetLog::NextID() {
return 0;
}
-bool ForwardingNetLog::HasListener() const {
+NetLog::LogLevel ForwardingNetLog::GetLogLevel() const {
// Can't forward a synchronous API.
CHECK(false) << "Not supported";
- return false;
+ return LOG_ALL;
}
} // namespace net
diff --git a/net/base/forwarding_net_log.h b/net/base/forwarding_net_log.h
index a97d4ac..257b4c7 100644
--- a/net/base/forwarding_net_log.h
+++ b/net/base/forwarding_net_log.h
@@ -4,6 +4,7 @@
#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"
@@ -38,7 +39,7 @@ class ForwardingNetLog : public NetLog {
EventPhase phase,
EventParameters* params);
virtual uint32 NextID();
- virtual bool HasListener() const;
+ virtual LogLevel GetLogLevel() const;
private:
class Core;
diff --git a/net/base/gzip_filter.h b/net/base/gzip_filter.h
index eb88b7f..afdc970 100644
--- a/net/base/gzip_filter.h
+++ b/net/base/gzip_filter.h
@@ -14,6 +14,7 @@
#ifndef NET_BASE_GZIP_FILTER_H__
#define NET_BASE_GZIP_FILTER_H__
+#pragma once
#include "base/scoped_ptr.h"
#include "net/base/filter.h"
diff --git a/net/base/gzip_header.h b/net/base/gzip_header.h
index 725537b..81f6f19 100644
--- a/net/base/gzip_header.h
+++ b/net/base/gzip_header.h
@@ -14,6 +14,7 @@
#ifndef NET_BASE_GZIP_HEADER_H_
#define NET_BASE_GZIP_HEADER_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/net/base/host_cache.h b/net/base/host_cache.h
index 1b40318..aedc499 100644
--- a/net/base/host_cache.h
+++ b/net/base/host_cache.h
@@ -4,16 +4,17 @@
#ifndef NET_BASE_HOST_CACHE_H_
#define NET_BASE_HOST_CACHE_H_
+#pragma once
#include <map>
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
#include "base/time.h"
#include "net/base/address_family.h"
#include "net/base/address_list.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
namespace net {
@@ -110,8 +111,8 @@ class HostCache : public NonThreadSafe {
const EntryMap& entries() const;
private:
- FRIEND_TEST(HostCacheTest, Compact);
- FRIEND_TEST(HostCacheTest, NoCache);
+ FRIEND_TEST_ALL_PREFIXES(HostCacheTest, Compact);
+ FRIEND_TEST_ALL_PREFIXES(HostCacheTest, NoCache);
// Returns true if this cache entry's result is valid at time |now|.
static bool CanUseEntry(const Entry* entry, const base::TimeTicks now);
diff --git a/net/base/host_cache_unittest.cc b/net/base/host_cache_unittest.cc
index a851c0b..e534695 100644
--- a/net/base/host_cache_unittest.cc
+++ b/net/base/host_cache_unittest.cc
@@ -7,6 +7,7 @@
#include "base/format_macros.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -178,14 +179,14 @@ TEST(HostCacheTest, Compact) {
// Add five valid entries at t=10.
for (int i = 0; i < 5; ++i) {
- std::string hostname = StringPrintf("valid%d", i);
+ std::string hostname = base::StringPrintf("valid%d", i);
cache.Set(Key(hostname), OK, AddressList(), now);
}
EXPECT_EQ(5U, cache.size());
// Add 3 expired entries at t=0.
for (int i = 0; i < 3; ++i) {
- std::string hostname = StringPrintf("expired%d", i);
+ std::string hostname = base::StringPrintf("expired%d", i);
base::TimeTicks t = now - base::TimeDelta::FromSeconds(10);
cache.Set(Key(hostname), OK, AddressList(), t);
}
@@ -193,7 +194,7 @@ TEST(HostCacheTest, Compact) {
// Add 2 negative entries at t=10
for (int i = 0; i < 2; ++i) {
- std::string hostname = StringPrintf("negative%d", i);
+ std::string hostname = base::StringPrintf("negative%d", i);
cache.Set(Key(hostname), ERR_NAME_NOT_RESOLVED, AddressList(), now);
}
EXPECT_EQ(10U, cache.size());
@@ -314,9 +315,12 @@ TEST(HostCacheTest, HostResolverFlagsArePartOfKey) {
HostCache::Key key1("foobar.com", ADDRESS_FAMILY_IPV4, 0);
HostCache::Key key2("foobar.com", ADDRESS_FAMILY_IPV4,
HOST_RESOLVER_CANONNAME);
+ HostCache::Key key3("foobar.com", ADDRESS_FAMILY_IPV4,
+ HOST_RESOLVER_LOOPBACK_ONLY);
const HostCache::Entry* entry1 = NULL; // Entry for key1
const HostCache::Entry* entry2 = NULL; // Entry for key2
+ const HostCache::Entry* entry3 = NULL; // Entry for key3
EXPECT_EQ(0U, cache.size());
@@ -334,9 +338,18 @@ TEST(HostCacheTest, HostResolverFlagsArePartOfKey) {
EXPECT_FALSE(entry2 == NULL);
EXPECT_EQ(2U, cache.size());
+ // Add an entry for ("foobar.com", IPV4, LOOPBACK_ONLY) at t=0.
+ EXPECT_TRUE(cache.Lookup(key3, base::TimeTicks()) == NULL);
+ cache.Set(key3, OK, AddressList(), now);
+ entry3 = cache.Lookup(key3, base::TimeTicks());
+ EXPECT_FALSE(entry3 == NULL);
+ EXPECT_EQ(3U, cache.size());
+
// Even though the hostnames were the same, we should have two unique
// entries (because the HostResolverFlags differ).
EXPECT_NE(entry1, entry2);
+ EXPECT_NE(entry1, entry3);
+ EXPECT_NE(entry2, entry3);
}
TEST(HostCacheTest, NoCache) {
@@ -440,7 +453,7 @@ TEST(HostCacheTest, KeyComparators) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]", i));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
const HostCache::Key& key1 = tests[i].key1;
const HostCache::Key& key2 = tests[i].key2;
diff --git a/net/base/host_mapping_rules.cc b/net/base/host_mapping_rules.cc
index 3296b0e..a1ec12d 100644
--- a/net/base/host_mapping_rules.cc
+++ b/net/base/host_mapping_rules.cc
@@ -5,6 +5,7 @@
#include "net/base/host_mapping_rules.h"
#include "base/logging.h"
+#include "base/string_split.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "net/base/host_port_pair.h"
@@ -12,14 +13,28 @@
namespace net {
+struct HostMappingRules::MapRule {
+ MapRule() : replacement_port(-1) {}
+
+ std::string hostname_pattern;
+ std::string replacement_hostname;
+ int replacement_port;
+};
+
+struct HostMappingRules::ExclusionRule {
+ std::string hostname_pattern;
+};
+
HostMappingRules::HostMappingRules() {}
+HostMappingRules::~HostMappingRules() {}
+
bool HostMappingRules::RewriteHost(HostPortPair* host_port) const {
// Check if the hostname was excluded.
for (ExclusionRuleList::const_iterator it = exclusion_rules_.begin();
it != exclusion_rules_.end(); ++it) {
const ExclusionRule& rule = *it;
- if (MatchPatternASCII(host_port->host, rule.hostname_pattern))
+ if (MatchPattern(host_port->host(), rule.hostname_pattern))
return false;
}
@@ -28,12 +43,22 @@ bool HostMappingRules::RewriteHost(HostPortPair* host_port) const {
it != map_rules_.end(); ++it) {
const MapRule& rule = *it;
- if (!MatchPatternASCII(host_port->host, rule.hostname_pattern))
- continue; // This rule doesn't apply.
+ // The rule's hostname_pattern will be something like:
+ // www.foo.com
+ // *.foo.com
+ // www.foo.com:1234
+ // *.foo.com:1234
+ // First, we'll check for a match just on hostname.
+ // If that fails, we'll check for a match with both hostname and port.
+ if (!MatchPattern(host_port->host(), rule.hostname_pattern)) {
+ std::string host_port_string = host_port->ToString();
+ if (!MatchPattern(host_port_string, rule.hostname_pattern))
+ continue; // This rule doesn't apply.
+ }
- host_port->host = rule.replacement_hostname;
+ host_port->set_host(rule.replacement_hostname);
if (rule.replacement_port != -1)
- host_port->port = rule.replacement_port;
+ host_port->set_port(rule.replacement_port);
return true;
}
diff --git a/net/base/host_mapping_rules.h b/net/base/host_mapping_rules.h
index a754a47..05f531f 100644
--- a/net/base/host_mapping_rules.h
+++ b/net/base/host_mapping_rules.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_HOST_MAPPING_RULES_H_
#define NET_BASE_HOST_MAPPING_RULES_H_
+#pragma once
#include <string>
#include <vector>
@@ -11,12 +12,13 @@
namespace net {
-struct HostPortPair;
+class HostPortPair;
class HostMappingRules {
public:
HostMappingRules();
-
+ ~HostMappingRules();
+
// Modifies |*host_port| based on the current rules. Returns true if the
// RequestInfo was modified, false otherwise.
bool RewriteHost(HostPortPair* host_port) const;
@@ -35,17 +37,8 @@ class HostMappingRules {
void SetRulesFromString(const std::string& rules_string);
private:
- struct MapRule {
- MapRule() : replacement_port(-1) {}
-
- std::string hostname_pattern;
- std::string replacement_hostname;
- int replacement_port;
- };
-
- struct ExclusionRule {
- std::string hostname_pattern;
- };
+ struct MapRule;
+ struct ExclusionRule;
typedef std::vector<MapRule> MapRuleList;
typedef std::vector<ExclusionRule> ExclusionRuleList;
diff --git a/net/base/host_mapping_rules_unittest.cc b/net/base/host_mapping_rules_unittest.cc
index 0cea821..9ecd4b7 100644
--- a/net/base/host_mapping_rules_unittest.cc
+++ b/net/base/host_mapping_rules_unittest.cc
@@ -18,23 +18,53 @@ TEST(HostMappingRulesTest, SetRulesFromString) {
HostPortPair host_port("test", 1234);
EXPECT_FALSE(rules.RewriteHost(&host_port));
- EXPECT_EQ("test", host_port.host);
- EXPECT_EQ(1234u, host_port.port);
+ EXPECT_EQ("test", host_port.host());
+ EXPECT_EQ(1234u, host_port.port());
host_port = HostPortPair("chrome.net", 80);
EXPECT_TRUE(rules.RewriteHost(&host_port));
- EXPECT_EQ("bar", host_port.host);
- EXPECT_EQ(60u, host_port.port);
+ EXPECT_EQ("bar", host_port.host());
+ EXPECT_EQ(60u, host_port.port());
host_port = HostPortPair("crack.com", 80);
EXPECT_TRUE(rules.RewriteHost(&host_port));
- EXPECT_EQ("baz", host_port.host);
- EXPECT_EQ(80u, host_port.port);
+ EXPECT_EQ("baz", host_port.host());
+ EXPECT_EQ(80u, host_port.port());
host_port = HostPortPair("wtf.foo.com", 666);
EXPECT_FALSE(rules.RewriteHost(&host_port));
- EXPECT_EQ("wtf.foo.com", host_port.host);
- EXPECT_EQ(666u, host_port.port);
+ EXPECT_EQ("wtf.foo.com", host_port.host());
+ EXPECT_EQ(666u, host_port.port());
+}
+
+TEST(HostMappingRulesTest, PortSpecificMatching) {
+ HostMappingRules rules;
+ rules.SetRulesFromString(
+ "map *.com:80 baz:111 , map *.com:443 blat:333, EXCLUDE *.foo.com");
+
+ // No match
+ HostPortPair host_port("test.com", 1234);
+ EXPECT_FALSE(rules.RewriteHost(&host_port));
+ EXPECT_EQ("test.com", host_port.host());
+ EXPECT_EQ(1234u, host_port.port());
+
+ // Match port 80
+ host_port = HostPortPair("crack.com", 80);
+ EXPECT_TRUE(rules.RewriteHost(&host_port));
+ EXPECT_EQ("baz", host_port.host());
+ EXPECT_EQ(111u, host_port.port());
+
+ // Match port 443
+ host_port = HostPortPair("wtf.com", 443);
+ EXPECT_TRUE(rules.RewriteHost(&host_port));
+ EXPECT_EQ("blat", host_port.host());
+ EXPECT_EQ(333u, host_port.port());
+
+ // Match port 443, but excluded.
+ host_port = HostPortPair("wtf.foo.com", 443);
+ EXPECT_FALSE(rules.RewriteHost(&host_port));
+ EXPECT_EQ("wtf.foo.com", host_port.host());
+ EXPECT_EQ(443u, host_port.port());
}
// Parsing bad rules should silently discard the rule (and never crash).
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc
index d4e7d4e..1c4406f 100644
--- a/net/base/host_port_pair.cc
+++ b/net/base/host_port_pair.cc
@@ -3,19 +3,34 @@
// found in the LICENSE file.
#include "net/base/host_port_pair.h"
+
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "googleurl/src/gurl.h"
namespace net {
-HostPortPair::HostPortPair() : port(0) {}
+HostPortPair::HostPortPair() : port_(0) {}
HostPortPair::HostPortPair(const std::string& in_host, uint16 in_port)
- : host(in_host), port(in_port) {}
+ : host_(in_host), port_(in_port) {}
+
+// static
+HostPortPair HostPortPair::FromURL(const GURL& url) {
+ return HostPortPair(url.HostNoBrackets(), url.EffectiveIntPort());
+}
std::string HostPortPair::ToString() const {
+ return base::StringPrintf("%s:%u", HostForURL().c_str(), port_);
+}
+
+std::string HostPortPair::HostForURL() const {
// Check to see if the host is an IPv6 address. If so, added brackets.
- if (host.find(':') != std::string::npos)
- return StringPrintf("[%s]:%u", host.c_str(), port);
- return StringPrintf("%s:%u", host.c_str(), port);
+ if (host_.find(':') != std::string::npos) {
+ DCHECK_NE(host_[0], '[');
+ return base::StringPrintf("[%s]", host_.c_str());
+ }
+
+ return host_;
}
} // namespace net
diff --git a/net/base/host_port_pair.h b/net/base/host_port_pair.h
index 78f74ea..2c7bb9f 100644
--- a/net/base/host_port_pair.h
+++ b/net/base/host_port_pair.h
@@ -4,39 +4,65 @@
#ifndef NET_BASE_HOST_PORT_PAIR_H_
#define NET_BASE_HOST_PORT_PAIR_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+class GURL;
+
namespace net {
-struct HostPortPair {
+class HostPortPair {
+ public:
HostPortPair();
// If |in_host| represents an IPv6 address, it should not bracket the address.
HostPortPair(const std::string& in_host, uint16 in_port);
+ // Creates a HostPortPair for the origin of |url|.
+ static HostPortPair FromURL(const GURL& url);
+
// TODO(willchan): Define a functor instead.
// Comparator function so this can be placed in a std::map.
- // TODO(jar): Violation of style guide, and should be removed.
bool operator<(const HostPortPair& other) const {
- if (port != other.port)
- return port < other.port;
- return host < other.host;
+ if (port_ != other.port_)
+ return port_ < other.port_;
+ return host_ < other.host_;
}
// Equality test of contents. (Probably another violation of style guide).
bool Equals(const HostPortPair& other) const {
- return host == other.host && port == other.port;
+ return host_ == other.host_ && port_ == other.port_;
+ }
+
+ const std::string& host() const {
+ return host_;
+ }
+
+ uint16 port() const {
+ return port_;
}
- // ToString() will convert the HostPortPair to "host:port". If |host| is an
- // IPv6 literal, it will add brackets around |host|.
+ void set_host(const std::string& in_host) {
+ host_ = in_host;
+ }
+
+ void set_port(uint16 in_port) {
+ port_ = in_port;
+ }
+
+ // ToString() will convert the HostPortPair to "host:port". If |host_| is an
+ // IPv6 literal, it will add brackets around |host_|.
std::string ToString() const;
- // If |host| represents an IPv6 address, this string will not contain brackets
- // around the address.
- std::string host;
- uint16 port;
+ // Returns |host_|, adding IPv6 brackets if needed.
+ std::string HostForURL() const;
+
+ private:
+ // If |host_| represents an IPv6 address, this string will not contain
+ // brackets around the address.
+ std::string host_;
+ uint16 port_;
};
} // namespace net
diff --git a/net/base/host_resolver.cc b/net/base/host_resolver.cc
index 82a5f7e..5836c65 100644
--- a/net/base/host_resolver.cc
+++ b/net/base/host_resolver.cc
@@ -10,6 +10,21 @@
namespace net {
+HostResolver::RequestInfo::RequestInfo(const HostPortPair& host_port_pair)
+ : host_port_pair_(host_port_pair),
+ address_family_(ADDRESS_FAMILY_UNSPECIFIED),
+ host_resolver_flags_(0),
+ allow_cached_response_(true),
+ is_speculative_(false),
+ priority_(MEDIUM) {
+}
+
+HostResolver::HostResolver() {
+}
+
+HostResolver::~HostResolver() {
+}
+
SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver)
: resolver_(resolver),
cur_request_(NULL),
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index 895ffc2..1c0982d 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_HOST_RESOLVER_H_
#define NET_BASE_HOST_RESOLVER_H_
+#pragma once
#include <string>
@@ -11,16 +12,15 @@
#include "googleurl/src/gurl.h"
#include "net/base/address_family.h"
#include "net/base/completion_callback.h"
+#include "net/base/host_port_pair.h"
#include "net/base/request_priority.h"
-class MessageLoop;
-
namespace net {
class AddressList;
class BoundNetLog;
-class HostCache;
class HostResolverImpl;
+class NetLog;
// This class represents the task of resolving hostnames (or IP address
// literal) to an AddressList object.
@@ -33,29 +33,20 @@ class HostResolverImpl;
// goes out of scope).
class HostResolver : public base::RefCounted<HostResolver> {
public:
- // The parameters for doing a Resolve(). |hostname| and |port| are required,
+ // The parameters for doing a Resolve(). A hostname and port are required,
// the rest are optional (and have reasonable defaults).
class RequestInfo {
public:
- RequestInfo(const std::string& hostname, int port)
- : hostname_(hostname),
- address_family_(ADDRESS_FAMILY_UNSPECIFIED),
- host_resolver_flags_(0),
- port_(port),
- allow_cached_response_(true),
- is_speculative_(false),
- priority_(MEDIUM) {}
-
- int port() const { return port_; }
- void set_port(int port) {
- port_ = port;
- }
+ explicit RequestInfo(const HostPortPair& host_port_pair);
- const std::string& hostname() const { return hostname_; }
- void set_hostname(const std::string& hostname) {
- hostname_ = hostname;
+ const HostPortPair& host_port_pair() const { return host_port_pair_; }
+ void set_host_port_pair(const HostPortPair& host_port_pair) {
+ host_port_pair_ = host_port_pair;
}
+ int port() const { return host_port_pair_.port(); }
+ const std::string& hostname() const { return host_port_pair_.host(); }
+
AddressFamily address_family() const { return address_family_; }
void set_address_family(AddressFamily address_family) {
address_family_ = address_family;
@@ -81,8 +72,8 @@ class HostResolver : public base::RefCounted<HostResolver> {
void set_referrer(const GURL& referrer) { referrer_ = referrer; }
private:
- // The hostname to resolve.
- std::string hostname_;
+ // The hostname to resolve, and the port to use in resulting sockaddrs.
+ HostPortPair host_port_pair_;
// The address family to restrict results to.
AddressFamily address_family_;
@@ -90,9 +81,6 @@ class HostResolver : public base::RefCounted<HostResolver> {
// Flags to use when resolving this request.
HostResolverFlags host_resolver_flags_;
- // The port number to set in the result's sockaddrs.
- int port_;
-
// Whether it is ok to return a result from the host cache.
bool allow_cached_response_;
@@ -188,12 +176,12 @@ class HostResolver : public base::RefCounted<HostResolver> {
protected:
friend class base::RefCounted<HostResolver>;
- HostResolver() { }
+ HostResolver();
// If any completion callbacks are pending when the resolver is destroyed,
// the host resolutions are cancelled, and the completion callbacks will not
// be called.
- virtual ~HostResolver() {}
+ virtual ~HostResolver();
private:
DISALLOW_COPY_AND_ASSIGN(HostResolver);
@@ -246,7 +234,8 @@ class SingleRequestHostResolver {
// |max_concurrent_resolves| is how many resolve requests will be allowed to
// run in parallel. Pass HostResolver::kDefaultParallelism to choose a
// default value.
-HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves);
+HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
+ NetLog* net_log);
} // namespace net
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index c06e065..51125e8 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -23,12 +23,15 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/worker_pool.h"
#include "net/base/address_list.h"
+#include "net/base/address_list_net_log_param.h"
+#include "net/base/host_port_pair.h"
#include "net/base/host_resolver_proc.h"
-#include "net/base/net_log.h"
#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
#include "net/base/net_util.h"
#if defined(OS_WIN)
@@ -53,7 +56,8 @@ HostResolver* systemResolver = NULL;
} // anonymous namespace
-HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves) {
+HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
+ NetLog* net_log) {
// Maximum of 50 concurrent threads.
// TODO(eroman): Adjust this, do some A/B experiments.
#ifdef ANDROID
@@ -73,8 +77,12 @@ HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves) {
#else
HostResolverImpl* resolver =
new HostResolverImpl(NULL, CreateDefaultCache(),
+<<<<<<< HEAD
max_concurrent_resolves);
#endif
+=======
+ max_concurrent_resolves, net_log);
+>>>>>>> Chromium at release 7.0.540.0
return systemResolver;
}
@@ -99,21 +107,19 @@ static int ResolveAddrInfo(HostResolverProc* resolver_proc,
// Extra parameters to attach to the NetLog when the resolve failed.
class HostResolveFailedParams : public NetLog::EventParameters {
public:
- HostResolveFailedParams(int net_error, int os_error, bool was_from_cache)
+ HostResolveFailedParams(int net_error, int os_error)
: net_error_(net_error),
- os_error_(os_error),
- was_from_cache_(was_from_cache) {
+ os_error_(os_error) {
}
virtual Value* ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- dict->SetInteger(L"net_error", net_error_);
- dict->SetBoolean(L"was_from_cache", was_from_cache_);
+ dict->SetInteger("net_error", net_error_);
if (os_error_) {
- dict->SetInteger(L"os_error", os_error_);
+ dict->SetInteger("os_error", os_error_);
#if defined(OS_POSIX)
- dict->SetString(L"os_error_string", gai_strerror(os_error_));
+ dict->SetString("os_error_string", gai_strerror(os_error_));
#elif defined(OS_WIN)
// Map the error code to a human-readable string.
LPWSTR error_string = NULL;
@@ -125,7 +131,7 @@ class HostResolveFailedParams : public NetLog::EventParameters {
(LPWSTR)&error_string,
0, // Buffer size.
0); // Arguments (unused).
- dict->SetString(L"os_error_string", error_string);
+ dict->SetString("os_error_string", WideToUTF8(error_string));
LocalFree(error_string);
#endif
}
@@ -136,7 +142,52 @@ class HostResolveFailedParams : public NetLog::EventParameters {
private:
const int net_error_;
const int os_error_;
- const bool was_from_cache_;
+};
+
+// Parameters representing the information in a RequestInfo object, along with
+// the associated NetLog::Source.
+class RequestInfoParameters : public NetLog::EventParameters {
+ public:
+ RequestInfoParameters(const HostResolver::RequestInfo& info,
+ const NetLog::Source& source)
+ : info_(info), source_(source) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("host", info_.host_port_pair().ToString());
+ dict->SetInteger("address_family",
+ static_cast<int>(info_.address_family()));
+ dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
+ dict->SetBoolean("is_speculative", info_.is_speculative());
+ dict->SetInteger("priority", info_.priority());
+
+ if (source_.is_valid())
+ dict->Set("source_dependency", source_.ToValue());
+
+ return dict;
+ }
+
+ private:
+ const HostResolver::RequestInfo info_;
+ const NetLog::Source source_;
+};
+
+// Parameters associated with the creation of a HostResolveImpl::Job.
+class JobCreationParameters : public NetLog::EventParameters {
+ public:
+ JobCreationParameters(const std::string& host, const NetLog::Source& source)
+ : host_(host), source_(source) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("host", host_);
+ dict->Set("source_dependency", source_.ToValue());
+ return dict;
+ }
+
+ private:
+ const std::string host_;
+ const NetLog::Source source_;
};
// Gets a list of the likely error codes that getaddrinfo() can return
@@ -190,12 +241,14 @@ std::vector<int> GetAllGetAddrinfoOSErrors() {
class HostResolverImpl::Request {
public:
- Request(const BoundNetLog& net_log,
+ Request(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
int id,
const RequestInfo& info,
CompletionCallback* callback,
AddressList* addresses)
- : net_log_(net_log),
+ : source_net_log_(source_net_log),
+ request_net_log_(request_net_log),
id_(id),
info_(info),
job_(NULL),
@@ -223,7 +276,9 @@ class HostResolverImpl::Request {
void OnComplete(int error, const AddressList& addrlist) {
if (error == OK)
addresses_->SetFrom(addrlist, port());
- callback_->Run(error);
+ CompletionCallback* callback = callback_;
+ MarkAsCancelled();
+ callback->Run(error);
}
int port() const {
@@ -234,8 +289,12 @@ class HostResolverImpl::Request {
return job_;
}
- const BoundNetLog& net_log() {
- return net_log_;
+ const BoundNetLog& source_net_log() {
+ return source_net_log_;
+ }
+
+ const BoundNetLog& request_net_log() {
+ return request_net_log_;
}
int id() const {
@@ -247,7 +306,8 @@ class HostResolverImpl::Request {
}
private:
- BoundNetLog net_log_;
+ BoundNetLog source_net_log_;
+ BoundNetLog request_net_log_;
// Unique ID for this request. Used by observers to identify requests.
int id_;
@@ -274,20 +334,33 @@ class HostResolverImpl::Request {
class HostResolverImpl::Job
: public base::RefCountedThreadSafe<HostResolverImpl::Job> {
public:
- Job(int id, HostResolverImpl* resolver, const Key& key)
- : id_(id),
- key_(key),
- resolver_(resolver),
- origin_loop_(MessageLoop::current()),
- resolver_proc_(resolver->effective_resolver_proc()),
- error_(OK),
- os_error_(0),
- had_non_speculative_request_(false) {
+ Job(int id,
+ HostResolverImpl* resolver,
+ const Key& key,
+ const BoundNetLog& source_net_log,
+ NetLog* net_log)
+ : id_(id),
+ key_(key),
+ resolver_(resolver),
+ origin_loop_(MessageLoop::current()),
+ resolver_proc_(resolver->effective_resolver_proc()),
+ error_(OK),
+ os_error_(0),
+ had_non_speculative_request_(false),
+ net_log_(BoundNetLog::Make(net_log,
+ NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
+ net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ new JobCreationParameters(key.hostname,
+ source_net_log.source()));
}
// Attaches a request to this job. The job takes ownership of |req| and will
// take care to delete it.
void AddRequest(Request* req) {
+ req->request_net_log().BeginEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
+ new NetLogSourceParameter("source_dependency", net_log_.source()));
+
req->set_job(this);
requests_.push_back(req);
@@ -315,6 +388,8 @@ class HostResolverImpl::Job
// Cancels the current job. Callable from origin thread.
void Cancel() {
+ net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
+
HostResolver* resolver = resolver_;
resolver_ = NULL;
@@ -325,6 +400,10 @@ class HostResolverImpl::Job
origin_loop_ = NULL;
}
+ // End here to prevent issues when a Job outlives the HostResolver that
+ // spawned it.
+ net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
+
// We will call HostResolverImpl::CancelRequest(Request*) on each one
// in order to notify any observers.
for (RequestsList::const_iterator it = requests_.begin();
@@ -426,6 +505,17 @@ class HostResolverImpl::Job
if (was_cancelled())
return;
+ scoped_refptr<NetLog::EventParameters> params;
+ if (error_ != OK) {
+ params = new HostResolveFailedParams(error_, os_error_);
+ } else {
+ params = new AddressListNetLogParam(results_);
+ }
+
+ // End here to prevent issues when a Job outlives the HostResolver that
+ // spawned it.
+ net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
+
DCHECK(!requests_.empty());
// Use the port number of the first request.
@@ -470,6 +560,8 @@ class HostResolverImpl::Job
// The time when the job was started.
base::TimeTicks start_time_;
+ BoundNetLog net_log_;
+
DISALLOW_COPY_AND_ASSIGN(Job);
};
@@ -575,7 +667,8 @@ class HostResolverImpl::IPv6ProbeJob
// and increasing for lower priorities.
COMPILE_ASSERT(HIGHEST == 0u &&
LOWEST > HIGHEST &&
- NUM_PRIORITIES > LOWEST,
+ IDLE > LOWEST &&
+ NUM_PRIORITIES > IDLE,
priority_indexes_incompatible);
// JobPool contains all the information relating to queued requests, including
@@ -621,6 +714,10 @@ class HostResolverImpl::JobPool {
// evicted from the queue, and returned. Otherwise returns NULL. The caller
// is responsible for freeing the evicted request.
Request* InsertPendingRequest(Request* req) {
+ req->request_net_log().BeginEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
+ NULL);
+
PendingRequestsQueue& q = pending_requests_[req->info().priority()];
q.push_back(req);
@@ -633,6 +730,10 @@ class HostResolverImpl::JobPool {
if (!q.empty()) {
Request* req = q.front();
q.pop_front();
+ req->request_net_log().AddEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
+ req->request_net_log().EndEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
return req;
}
}
@@ -648,6 +749,8 @@ class HostResolverImpl::JobPool {
PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
DCHECK(it != q.end());
q.erase(it);
+ req->request_net_log().EndEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
}
// Removes and returns the highest priority pending request.
@@ -659,6 +762,8 @@ class HostResolverImpl::JobPool {
if (!q.empty()) {
Request* req = q.front();
q.pop_front();
+ req->request_net_log().EndEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
return req;
}
}
@@ -673,6 +778,10 @@ class HostResolverImpl::JobPool {
num_outstanding_jobs_ += offset;
}
+ void ResetNumOutstandingJobs() {
+ num_outstanding_jobs_ = 0;
+ }
+
// Returns true if a new job can be created for this pool.
bool CanCreateJob() const {
return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
@@ -722,7 +831,8 @@ class HostResolverImpl::JobPool {
HostResolverImpl::HostResolverImpl(
HostResolverProc* resolver_proc,
HostCache* cache,
- size_t max_jobs)
+ size_t max_jobs,
+ NetLog* net_log)
: cache_(cache),
max_jobs_(max_jobs),
next_request_id_(0),
@@ -730,7 +840,9 @@ HostResolverImpl::HostResolverImpl(
resolver_proc_(resolver_proc),
default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
shutdown_(false),
- ipv6_probe_monitoring_(false) {
+ ipv6_probe_monitoring_(false),
+ additional_resolver_flags_(0),
+ net_log_(net_log) {
DCHECK_GT(max_jobs, 0u);
// It is cumbersome to expose all of the constraints in the constructor,
@@ -740,6 +852,10 @@ HostResolverImpl::HostResolverImpl(
#if defined(OS_WIN)
EnsureWinsockInit();
#endif
+#if defined(OS_LINUX)
+ if (HaveOnlyLoopbackAddresses())
+ additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
+#endif
NetworkChangeNotifier::AddObserver(this);
}
@@ -748,8 +864,7 @@ HostResolverImpl::~HostResolverImpl() {
// requests, which will also be cancelled.
DiscardIPv6ProbeJob();
- for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
- it->second->Cancel();
+ CancelAllJobs();
// In case we are being deleted during the processing of a callback.
if (cur_completing_job_)
@@ -762,13 +877,11 @@ HostResolverImpl::~HostResolverImpl() {
delete job_pools_[i];
}
-// TODO(eroman): Don't create cache entries for hostnames which are simply IP
-// address literals.
int HostResolverImpl::Resolve(const RequestInfo& info,
AddressList* addresses,
CompletionCallback* callback,
RequestHandle* out_req,
- const BoundNetLog& net_log) {
+ const BoundNetLog& source_net_log) {
DCHECK(CalledOnValidThread());
if (shutdown_)
@@ -777,26 +890,54 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
// Choose a unique ID number for observers to see.
int request_id = next_request_id_++;
+ // Make a log item for the request.
+ BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
+ NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
+
// Update the net log and notify registered observers.
- OnStartRequest(net_log, request_id, info);
+ OnStartRequest(source_net_log, request_net_log, request_id, info);
// Build a key that identifies the request in the cache and in the
// outstanding jobs map.
Key key = GetEffectiveKeyForRequest(info);
+ // Check for IP literal.
+ IPAddressNumber ip_number;
+ if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) {
+ DCHECK_EQ(key.host_resolver_flags &
+ ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
+ 0) << " Unhandled flag";
+ bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
+ !ipv6_probe_monitoring_;
+ int net_error = OK;
+ if (ip_number.size() == 16 && ipv6_disabled) {
+ net_error = ERR_NAME_NOT_RESOLVED;
+ } else {
+ AddressList result(ip_number, info.port(),
+ (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
+ *addresses = result;
+ }
+ // Update the net log and notify registered observers.
+ OnFinishRequest(source_net_log, request_net_log, request_id, info,
+ net_error, 0 /* os_error (unknown since from cache) */);
+ return net_error;
+ }
+
// If we have an unexpired cache entry, use it.
if (info.allow_cached_response() && cache_.get()) {
const HostCache::Entry* cache_entry = cache_->Lookup(
key, base::TimeTicks::Now());
if (cache_entry) {
+ request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
int net_error = cache_entry->error;
if (net_error == OK)
addresses->SetFrom(cache_entry->addrlist, info.port());
// Update the net log and notify registered observers.
- OnFinishRequest(net_log, request_id, info, net_error,
- 0, /* os_error (unknown since from cache) */
- true /* was_from_cache */);
+ OnFinishRequest(source_net_log, request_net_log, request_id, info,
+ net_error,
+ 0 /* os_error (unknown since from cache) */);
return net_error;
}
@@ -819,15 +960,16 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
cache_->Set(key, error, addrlist, base::TimeTicks::Now());
// Update the net log and notify registered observers.
- OnFinishRequest(net_log, request_id, info, error, os_error,
- false /* was_from_cache */);
+ OnFinishRequest(source_net_log, request_net_log, request_id, info, error,
+ os_error);
return error;
}
// Create a handle for this request, and pass it back to the user if they
// asked for it (out_req != NULL).
- Request* req = new Request(net_log, request_id, info, callback, addresses);
+ Request* req = new Request(source_net_log, request_net_log, request_id, info,
+ callback, addresses);
if (out_req)
*out_req = reinterpret_cast<RequestHandle>(req);
@@ -878,11 +1020,15 @@ void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
JobPool* pool = GetPoolForRequest(req);
pool->RemovePendingRequest(req);
request_deleter.reset(req);
+ } else {
+ req->request_net_log().EndEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
}
// NULL out the fields of req, to mark it as cancelled.
req->MarkAsCancelled();
- OnCancelRequest(req->net_log(), req->id(), req->info());
+ OnCancelRequest(req->source_net_log(), req->request_net_log(), req->id(),
+ req->info());
}
void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
@@ -917,13 +1063,12 @@ void HostResolverImpl::ProbeIPv6Support() {
void HostResolverImpl::Shutdown() {
DCHECK(CalledOnValidThread());
- shutdown_ = true;
// Cancel the outstanding jobs.
- for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
- it->second->Cancel();
- jobs_.clear();
+ CancelAllJobs();
DiscardIPv6ProbeJob();
+
+ shutdown_ = true;
}
void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
@@ -973,6 +1118,18 @@ void HostResolverImpl::OnJobComplete(Job* job,
if (cache_.get())
cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
+ OnJobCompleteInternal(job, net_error, os_error, addrlist);
+}
+
+void HostResolverImpl::AbortJob(Job* job) {
+ OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
+}
+
+void HostResolverImpl::OnJobCompleteInternal(
+ Job* job,
+ int net_error,
+ int os_error,
+ const AddressList& addrlist) {
// Make a note that we are executing within OnJobComplete() in case the
// HostResolver is deleted by a callback invocation.
DCHECK(!cur_completing_job_);
@@ -987,10 +1144,12 @@ void HostResolverImpl::OnJobComplete(Job* job,
Request* req = *it;
if (!req->was_cancelled()) {
DCHECK_EQ(job, req->job());
+ req->request_net_log().EndEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
// Update the net log and notify registered observers.
- OnFinishRequest(req->net_log(), req->id(), req->info(), net_error,
- os_error, false /* was_from_cache */);
+ OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
+ req->info(), net_error, os_error);
req->OnComplete(net_error, addrlist);
@@ -1004,10 +1163,17 @@ void HostResolverImpl::OnJobComplete(Job* job,
cur_completing_job_ = NULL;
}
-void HostResolverImpl::OnStartRequest(const BoundNetLog& net_log,
+void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
int request_id,
const RequestInfo& info) {
- net_log.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
+ source_net_log.BeginEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL,
+ new NetLogSourceParameter("source_dependency", request_net_log.source()));
+
+ request_net_log.BeginEvent(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
+ new RequestInfoParameters(info, source_net_log.source()));
// Notify the observers of the start.
if (!observers_.empty()) {
@@ -1018,12 +1184,12 @@ void HostResolverImpl::OnStartRequest(const BoundNetLog& net_log,
}
}
-void HostResolverImpl::OnFinishRequest(const BoundNetLog& net_log,
+void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
int request_id,
const RequestInfo& info,
int net_error,
- int os_error,
- bool was_from_cache) {
+ int os_error) {
bool was_resolved = net_error == OK;
// Notify the observers of the completion.
@@ -1034,18 +1200,21 @@ void HostResolverImpl::OnFinishRequest(const BoundNetLog& net_log,
}
}
- // Log some extra parameters on failure.
+ // Log some extra parameters on failure for synchronous requests.
scoped_refptr<NetLog::EventParameters> params;
- if (!was_resolved)
- params = new HostResolveFailedParams(net_error, os_error, was_from_cache);
+ if (!was_resolved) {
+ params = new HostResolveFailedParams(net_error, os_error);
+ }
- net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, params);
+ request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
+ source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
}
-void HostResolverImpl::OnCancelRequest(const BoundNetLog& net_log,
+void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
int request_id,
const RequestInfo& info) {
- net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
+ request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
// Notify the observers of the cancellation.
if (!observers_.empty()) {
@@ -1055,7 +1224,8 @@ void HostResolverImpl::OnCancelRequest(const BoundNetLog& net_log,
}
}
- net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
+ request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
+ source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
}
void HostResolverImpl::OnIPAddressChanged() {
@@ -1069,6 +1239,15 @@ void HostResolverImpl::OnIPAddressChanged() {
ipv6_probe_job_ = new IPv6ProbeJob(this);
ipv6_probe_job_->Start();
}
+#if defined(OS_LINUX)
+ if (HaveOnlyLoopbackAddresses()) {
+ additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
+ } else {
+ additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
+ }
+#endif
+ AbortAllInProgressJobs();
+ // |this| may be deleted inside AbortAllInProgressJobs().
}
void HostResolverImpl::DiscardIPv6ProbeJob() {
@@ -1135,20 +1314,31 @@ void HostResolverImpl::ProcessQueuedRequests() {
HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
const RequestInfo& info) const {
+ HostResolverFlags effective_flags =
+ info.host_resolver_flags() | additional_resolver_flags_;
AddressFamily effective_address_family = info.address_family();
- if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED)
+ if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
+ default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
effective_address_family = default_address_family_;
- return Key(info.hostname(), effective_address_family,
- info.host_resolver_flags());
+ if (ipv6_probe_monitoring_)
+ effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ }
+ return Key(info.hostname(), effective_address_family, effective_flags);
}
HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
Key key = GetEffectiveKeyForRequest(req->info());
- scoped_refptr<Job> job = new Job(next_job_id_++, this, key);
+
+ req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
+ NULL);
+
+ scoped_refptr<Job> job = new Job(next_job_id_++, this, key,
+ req->request_net_log(), net_log_);
job->AddRequest(req);
AddOutstandingJob(job);
job->Start();
+
return job.get();
}
@@ -1161,9 +1351,9 @@ int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
Request* r = req_evicted_from_queue.get();
int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
- OnFinishRequest(r->net_log(), r->id(), r->info(), error,
- 0, /* os_error (not applicable) */
- false /* was_from_cache */);
+ OnFinishRequest(r->source_net_log(), r->request_net_log(), r->id(),
+ r->info(), error,
+ 0 /* os_error (not applicable) */);
if (r == req)
return error;
@@ -1174,4 +1364,22 @@ int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
return ERR_IO_PENDING;
}
+void HostResolverImpl::CancelAllJobs() {
+ JobMap jobs;
+ jobs.swap(jobs_);
+ for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
+ it->second->Cancel();
+}
+
+void HostResolverImpl::AbortAllInProgressJobs() {
+ for (size_t i = 0; i < arraysize(job_pools_); ++i)
+ job_pools_[i]->ResetNumOutstandingJobs();
+ JobMap jobs;
+ jobs.swap(jobs_);
+ for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
+ AbortJob(it->second);
+ it->second->Cancel();
+ }
+}
+
} // namespace net
diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h
index 28526d1..b1002ab 100644
--- a/net/base/host_resolver_impl.h
+++ b/net/base/host_resolver_impl.h
@@ -4,8 +4,8 @@
#ifndef NET_BASE_HOST_RESOLVER_IMPL_H_
#define NET_BASE_HOST_RESOLVER_IMPL_H_
+#pragma once
-#include <string>
#include <vector>
#include "base/non_thread_safe.h"
@@ -75,16 +75,19 @@ class HostResolverImpl : public HostResolver,
// used (which is SystemHostResolverProc except if overridden).
// |max_jobs| specifies the maximum number of threads that the host resolver
// will use. Use SetPoolConstraints() to specify finer-grain settings.
+ //
+ // |net_log| must remain valid for the life of the HostResolverImpl.
HostResolverImpl(HostResolverProc* resolver_proc,
HostCache* cache,
- size_t max_jobs);
+ size_t max_jobs,
+ NetLog* net_log);
// HostResolver methods:
virtual int Resolve(const RequestInfo& info,
AddressList* addresses,
CompletionCallback* callback,
RequestHandle* out_req,
- const BoundNetLog& net_log);
+ const BoundNetLog& source_net_log);
virtual void CancelRequest(RequestHandle req);
virtual void AddObserver(HostResolver::Observer* observer);
virtual void RemoveObserver(HostResolver::Observer* observer);
@@ -153,21 +156,31 @@ class HostResolverImpl : public HostResolver,
void OnJobComplete(Job* job, int net_error, int os_error,
const AddressList& addrlist);
+ // Aborts |job|. Same as OnJobComplete() except does not remove |job|
+ // from |jobs_| and does not cache the result (ERR_ABORTED).
+ void AbortJob(Job* job);
+
+ // Used by both OnJobComplete() and AbortJob();
+ void OnJobCompleteInternal(Job* job, int net_error, int os_error,
+ const AddressList& addrlist);
+
// Called when a request has just been started.
- void OnStartRequest(const BoundNetLog& net_log,
+ void OnStartRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
int request_id,
const RequestInfo& info);
// Called when a request has just completed (before its callback is run).
- void OnFinishRequest(const BoundNetLog& net_log,
+ void OnFinishRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
int request_id,
const RequestInfo& info,
int net_error,
- int os_error,
- bool was_from_cache);
+ int os_error);
// Called when a request has been cancelled.
- void OnCancelRequest(const BoundNetLog& net_log,
+ void OnCancelRequest(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
int request_id,
const RequestInfo& info);
@@ -206,6 +219,12 @@ class HostResolverImpl : public HostResolver,
// Adds a pending request |req| to |pool|.
int EnqueueRequest(JobPool* pool, Request* req);
+ // Cancels all jobs.
+ void CancelAllJobs();
+
+ // Aborts all in progress jobs (but might start new ones).
+ void AbortAllInProgressJobs();
+
// Cache of host resolution results.
scoped_ptr<HostCache> cache_;
@@ -252,6 +271,11 @@ class HostResolverImpl : public HostResolver,
// The last un-cancelled IPv6ProbeJob (if any).
scoped_refptr<IPv6ProbeJob> ipv6_probe_job_;
+ // Any resolver flags that should be added to a request by default.
+ HostResolverFlags additional_resolver_flags_;
+
+ NetLog* net_log_;
+
DISALLOW_COPY_AND_ASSIGN(HostResolverImpl);
};
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index 6b33a56..4b28b8c 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -10,6 +10,7 @@
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/mock_host_resolver.h"
@@ -38,14 +39,15 @@ HostCache* CreateDefaultCache() {
static const size_t kMaxJobs = 10u;
HostResolverImpl* CreateHostResolverImpl(HostResolverProc* resolver_proc) {
- return new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs);
+ return new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs,
+ NULL);
}
// Helper to create a HostResolver::RequestInfo.
HostResolver::RequestInfo CreateResolverRequest(
const std::string& hostname,
RequestPriority priority) {
- HostResolver::RequestInfo info(hostname, 80);
+ HostResolver::RequestInfo info(HostPortPair(hostname, 80));
info.set_priority(priority);
return info;
}
@@ -55,7 +57,7 @@ HostResolver::RequestInfo CreateResolverRequestForAddressFamily(
const std::string& hostname,
RequestPriority priority,
AddressFamily address_family) {
- HostResolver::RequestInfo info(hostname, 80);
+ HostResolver::RequestInfo info(HostPortPair(hostname, 80));
info.set_priority(priority);
info.set_address_family(address_family);
return info;
@@ -136,7 +138,7 @@ class EchoingHostResolverProc : public HostResolverProc {
AddressList* addrlist,
int* os_error) {
// Encode the request's hostname and address_family in the output address.
- std::string ip_literal = StringPrintf("192.%d.%d.%d",
+ std::string ip_literal = base::StringPrintf("192.%d.%d.%d",
static_cast<int>(hostname.size()),
static_cast<int>(hostname[0]),
static_cast<int>(address_family));
@@ -163,7 +165,9 @@ class ResolveRequest {
const std::string& hostname,
int port,
Delegate* delegate)
- : info_(hostname, port), resolver_(resolver), delegate_(delegate),
+ : info_(HostPortPair(hostname, port)),
+ resolver_(resolver),
+ delegate_(delegate),
ALLOW_THIS_IN_INITIALIZER_LIST(
callback_(this, &ResolveRequest::OnLookupFinished)) {
// Start the request.
@@ -254,7 +258,7 @@ class HostResolverImplTest : public testing::Test {
};
TEST_F(HostResolverImplTest, SynchronousLookup) {
- AddressList adrlist;
+ AddressList addrlist;
const int kPortnum = 80;
scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
@@ -264,9 +268,9 @@ TEST_F(HostResolverImplTest, SynchronousLookup) {
scoped_refptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
- HostResolver::RequestInfo info("just.testing", kPortnum);
+ HostResolver::RequestInfo info(HostPortPair("just.testing", kPortnum));
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
- int err = host_resolver->Resolve(info, &adrlist, NULL, NULL, log.bound());
+ int err = host_resolver->Resolve(info, &addrlist, NULL, NULL, log.bound());
EXPECT_EQ(OK, err);
EXPECT_EQ(2u, log.entries().size());
@@ -275,7 +279,7 @@ TEST_F(HostResolverImplTest, SynchronousLookup) {
EXPECT_TRUE(LogContainsEndEvent(
log.entries(), 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
- const struct addrinfo* ainfo = adrlist.head();
+ const struct addrinfo* ainfo = addrlist.head();
EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen);
@@ -286,7 +290,7 @@ TEST_F(HostResolverImplTest, SynchronousLookup) {
}
TEST_F(HostResolverImplTest, AsynchronousLookup) {
- AddressList adrlist;
+ AddressList addrlist;
const int kPortnum = 80;
scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
@@ -296,9 +300,9 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) {
scoped_refptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
- HostResolver::RequestInfo info("just.testing", kPortnum);
+ HostResolver::RequestInfo info(HostPortPair("just.testing", kPortnum));
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
- int err = host_resolver->Resolve(info, &adrlist, &callback_, NULL,
+ int err = host_resolver->Resolve(info, &addrlist, &callback_, NULL,
log.bound());
EXPECT_EQ(ERR_IO_PENDING, err);
@@ -315,7 +319,7 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) {
EXPECT_TRUE(LogContainsEndEvent(
log.entries(), 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
- const struct addrinfo* ainfo = adrlist.head();
+ const struct addrinfo* ainfo = addrlist.head();
EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen);
@@ -329,15 +333,19 @@ TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) {
scoped_refptr<WaitingHostResolverProc> resolver_proc =
new WaitingHostResolverProc(NULL);
+ CapturingNetLog net_log(CapturingNetLog::kUnbounded);
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
{
scoped_refptr<HostResolver> host_resolver(
- CreateHostResolverImpl(resolver_proc));
- AddressList adrlist;
+ new HostResolverImpl(resolver_proc,
+ CreateDefaultCache(),
+ kMaxJobs,
+ &net_log));
+ AddressList addrlist;
const int kPortnum = 80;
- HostResolver::RequestInfo info("just.testing", kPortnum);
- int err = host_resolver->Resolve(info, &adrlist, &callback_, NULL,
+ HostResolver::RequestInfo info(HostPortPair("just.testing", kPortnum));
+ int err = host_resolver->Resolve(info, &addrlist, &callback_, NULL,
log.bound());
EXPECT_EQ(ERR_IO_PENDING, err);
@@ -350,13 +358,33 @@ TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) {
resolver_proc->Signal();
- EXPECT_EQ(3u, log.entries().size());
+ EXPECT_EQ(2u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
log.entries(), 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
- EXPECT_TRUE(LogContainsEvent(
- log.entries(), 1, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ log.entries(), 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
+
+ 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,
+ 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,
+ 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::NetLog::TYPE_CANCELLED,
+ net::NetLog::PHASE_NONE);
+ 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::NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ net::NetLog::PHASE_END);
EXPECT_FALSE(callback_called_);
}
@@ -370,13 +398,13 @@ TEST_F(HostResolverImplTest, NumericIPv4Address) {
scoped_refptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
- AddressList adrlist;
+ AddressList addrlist;
const int kPortnum = 5555;
- HostResolver::RequestInfo info("127.1.2.3", kPortnum);
- int err = host_resolver->Resolve(info, &adrlist, NULL, NULL, BoundNetLog());
+ HostResolver::RequestInfo info(HostPortPair("127.1.2.3", kPortnum));
+ int err = host_resolver->Resolve(info, &addrlist, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, err);
- const struct addrinfo* ainfo = adrlist.head();
+ const struct addrinfo* ainfo = addrlist.head();
EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen);
@@ -395,18 +423,13 @@ TEST_F(HostResolverImplTest, NumericIPv6Address) {
// the caller should have removed them.
scoped_refptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
- AddressList adrlist;
+ AddressList addrlist;
const int kPortnum = 5555;
- HostResolver::RequestInfo info("2001:db8::1", kPortnum);
- int err = host_resolver->Resolve(info, &adrlist, NULL, NULL, BoundNetLog());
- // On computers without IPv6 support, getaddrinfo cannot convert IPv6
- // address literals to addresses (getaddrinfo returns EAI_NONAME). So this
- // test has to allow host_resolver->Resolve to fail.
- if (err == ERR_NAME_NOT_RESOLVED)
- return;
+ HostResolver::RequestInfo info(HostPortPair("2001:db8::1", kPortnum));
+ int err = host_resolver->Resolve(info, &addrlist, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, err);
- const struct addrinfo* ainfo = adrlist.head();
+ const struct addrinfo* ainfo = addrlist.head();
EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
EXPECT_EQ(sizeof(struct sockaddr_in6), ainfo->ai_addrlen);
@@ -430,10 +453,25 @@ TEST_F(HostResolverImplTest, EmptyHost) {
scoped_refptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
- AddressList adrlist;
+ AddressList addrlist;
+ const int kPortnum = 5555;
+ HostResolver::RequestInfo info(HostPortPair("", kPortnum));
+ int err = host_resolver->Resolve(info, &addrlist, NULL, NULL, BoundNetLog());
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, err);
+}
+
+TEST_F(HostResolverImplTest, LongHost) {
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
+ new RuleBasedHostResolverProc(NULL);
+ resolver_proc->AllowDirectLookup("*");
+
+ scoped_refptr<HostResolver> host_resolver(
+ CreateHostResolverImpl(resolver_proc));
+ AddressList addrlist;
const int kPortnum = 5555;
- HostResolver::RequestInfo info("", kPortnum);
- int err = host_resolver->Resolve(info, &adrlist, NULL, NULL, BoundNetLog());
+ std::string hostname(4097, 'a');
+ HostResolver::RequestInfo info(HostPortPair(hostname, kPortnum));
+ int err = host_resolver->Resolve(info, &addrlist, NULL, NULL, BoundNetLog());
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, err);
}
@@ -743,7 +781,7 @@ TEST_F(HostResolverImplTest, StartWithinCallback) {
// Turn off caching for this host resolver.
scoped_refptr<HostResolver> host_resolver(
- new HostResolverImpl(resolver_proc, NULL, kMaxJobs));
+ new HostResolverImpl(resolver_proc, NULL, kMaxJobs, NULL));
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened.
@@ -784,14 +822,14 @@ class BypassCacheVerifier : public ResolveRequest::Delegate {
reinterpret_cast<CompletionCallback*> (1);
AddressList addrlist;
- HostResolver::RequestInfo info("a", 70);
+ HostResolver::RequestInfo info(HostPortPair("a", 70));
int error = resolver->Resolve(info, &addrlist, junk_callback, NULL,
BoundNetLog());
EXPECT_EQ(OK, error);
// Ok good. Now make sure that if we ask to bypass the cache, it can no
// longer service the request synchronously.
- info = HostResolver::RequestInfo("a", 71);
+ info = HostResolver::RequestInfo(HostPortPair("a", 71));
info.set_allow_cached_response(false);
final_request_.reset(new ResolveRequest(resolver, info, this));
} else if (71 == resolve->port()) {
@@ -903,7 +941,7 @@ TEST_F(HostResolverImplTest, Observers) {
AddressList addrlist;
// Resolve "host1".
- HostResolver::RequestInfo info1("host1", 70);
+ HostResolver::RequestInfo info1(HostPortPair("host1", 70));
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
int rv = host_resolver->Resolve(info1, &addrlist, NULL, NULL, log.bound());
EXPECT_EQ(OK, rv);
@@ -937,7 +975,7 @@ TEST_F(HostResolverImplTest, Observers) {
CapturingObserver::FinishEntry(1, true, info1));
// Resolve "host2", setting referrer to "http://foobar.com"
- HostResolver::RequestInfo info2("host2", 70);
+ HostResolver::RequestInfo info2(HostPortPair("host2", 70));
info2.set_referrer(GURL("http://foobar.com"));
rv = host_resolver->Resolve(info2, &addrlist, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
@@ -954,7 +992,7 @@ TEST_F(HostResolverImplTest, Observers) {
host_resolver->RemoveObserver(&observer);
// Resolve "host3"
- HostResolver::RequestInfo info3("host3", 70);
+ HostResolver::RequestInfo info3(HostPortPair("host3", 70));
host_resolver->Resolve(info3, &addrlist, NULL, NULL, BoundNetLog());
// No effect this time, since observer was removed.
@@ -982,7 +1020,7 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
EXPECT_EQ(0U, observer.cancel_log.size());
// Start an async resolve for (host1:70).
- HostResolver::RequestInfo info1("host1", 70);
+ HostResolver::RequestInfo info1(HostPortPair("host1", 70));
HostResolver::RequestHandle req = NULL;
AddressList addrlist;
int rv = host_resolver->Resolve(info1, &addrlist, &callback, &req,
@@ -1008,7 +1046,7 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
CapturingObserver::StartOrCancelEntry(0, info1));
// Start an async request for (host2:60)
- HostResolver::RequestInfo info2("host2", 60);
+ HostResolver::RequestInfo info2(HostPortPair("host2", 60));
rv = host_resolver->Resolve(info2, &addrlist, &callback, NULL,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1032,7 +1070,7 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
EXPECT_EQ(0U, observer.finish_log.size());
EXPECT_EQ(2U, observer.cancel_log.size());
- HostResolver::RequestInfo info("host2", 60);
+ HostResolver::RequestInfo info(HostPortPair("host2", 60));
EXPECT_TRUE(observer.cancel_log[1] ==
CapturingObserver::StartOrCancelEntry(1, info));
}
@@ -1040,12 +1078,12 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
// Test that IP address changes flush the cache.
TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) {
scoped_refptr<HostResolver> host_resolver(
- new HostResolverImpl(NULL, CreateDefaultCache(), kMaxJobs));
+ new HostResolverImpl(NULL, CreateDefaultCache(), kMaxJobs, NULL));
AddressList addrlist;
// Resolve "host1".
- HostResolver::RequestInfo info1("host1", 70);
+ HostResolver::RequestInfo info1(HostPortPair("host1", 70));
TestCompletionCallback callback;
int rv = host_resolver->Resolve(info1, &addrlist, &callback, NULL,
BoundNetLog());
@@ -1068,6 +1106,127 @@ TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) {
EXPECT_EQ(OK, callback.WaitForResult());
}
+// Test that IP address changes send ERR_ABORTED to pending requests.
+TEST_F(HostResolverImplTest, AbortOnIPAddressChanged) {
+ scoped_refptr<WaitingHostResolverProc> resolver_proc =
+ new WaitingHostResolverProc(NULL);
+ HostCache* cache = CreateDefaultCache();
+ scoped_refptr<HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, cache, kMaxJobs, NULL));
+
+ // Resolve "host1".
+ HostResolver::RequestInfo info(HostPortPair("host1", 70));
+ TestCompletionCallback callback;
+ AddressList addrlist;
+ int rv = host_resolver->Resolve(info, &addrlist, &callback, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Triggering an IP address change.
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ MessageLoop::current()->RunAllPending(); // Notification happens async.
+ resolver_proc->Signal();
+
+ EXPECT_EQ(ERR_ABORTED, callback.WaitForResult());
+ EXPECT_EQ(0u, cache->size());
+}
+
+// Obey pool constraints after IP address has changed.
+TEST_F(HostResolverImplTest, ObeyPoolConstraintsAfterIPAddressChange) {
+ scoped_refptr<WaitingHostResolverProc> resolver_proc =
+ new WaitingHostResolverProc(NULL);
+ scoped_refptr<MockHostResolver> host_resolver(new MockHostResolver());
+ host_resolver->Reset(resolver_proc);
+
+ const size_t kMaxOutstandingJobs = 1u;
+ const size_t kMaxPendingRequests = 1000000u; // not relevant.
+ host_resolver->SetPoolConstraints(HostResolverImpl::POOL_NORMAL,
+ kMaxOutstandingJobs,
+ kMaxPendingRequests);
+
+ // Resolve "host1".
+ HostResolver::RequestInfo info(HostPortPair("host1", 70));
+ TestCompletionCallback callback;
+ AddressList addrlist;
+ int rv = host_resolver->Resolve(info, &addrlist, &callback, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Triggering an IP address change.
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ MessageLoop::current()->RunAllPending(); // Notification happens async.
+ resolver_proc->Signal();
+
+ EXPECT_EQ(ERR_ABORTED, callback.WaitForResult());
+
+ // Don't bother with WaitingHostResolverProc anymore.
+ host_resolver->Reset(NULL);
+
+ rv = host_resolver->Resolve(info, &addrlist, &callback, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+}
+
+class ResolveWithinCallback : public CallbackRunner< Tuple1<int> > {
+ public:
+ ResolveWithinCallback(
+ const scoped_refptr<MockHostResolver>& host_resolver,
+ const HostResolver::RequestInfo& info)
+ : host_resolver_(host_resolver),
+ info_(info) {
+ DCHECK(host_resolver.get());
+ }
+
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ // Ditch the WaitingHostResolverProc so that the subsequent request
+ // succeeds.
+ host_resolver_->Reset(NULL);
+ callback_.RunWithParams(params);
+ EXPECT_EQ(ERR_IO_PENDING,
+ host_resolver_->Resolve(info_, &addrlist_, &nested_callback_,
+ NULL, BoundNetLog()));
+ }
+
+ int WaitForResult() {
+ return callback_.WaitForResult();
+ }
+
+ int WaitForNestedResult() {
+ return nested_callback_.WaitForResult();
+ }
+
+ private:
+ const scoped_refptr<MockHostResolver> host_resolver_;
+ const HostResolver::RequestInfo info_;
+ AddressList addrlist_;
+ TestCompletionCallback callback_;
+ TestCompletionCallback nested_callback_;
+};
+
+TEST_F(HostResolverImplTest, OnlyAbortExistingRequestsOnIPAddressChange) {
+ scoped_refptr<WaitingHostResolverProc> resolver_proc =
+ new WaitingHostResolverProc(NULL);
+ scoped_refptr<MockHostResolver> host_resolver(new MockHostResolver());
+ host_resolver->Reset(resolver_proc);
+
+ // Resolve "host1".
+ HostResolver::RequestInfo info(HostPortPair("host1", 70));
+ ResolveWithinCallback callback(host_resolver, info);
+ AddressList addrlist;
+ int rv = host_resolver->Resolve(info, &addrlist, &callback, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Triggering an IP address change.
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ MessageLoop::current()->RunAllPending(); // Notification happens async.
+
+ EXPECT_EQ(ERR_ABORTED, callback.WaitForResult());
+ resolver_proc->Signal();
+ EXPECT_EQ(OK, callback.WaitForNestedResult());
+}
+
// Tests that when the maximum threads is set to 1, requests are dequeued
// in order of priority.
TEST_F(HostResolverImplTest, HigherPriorityRequestsStartedFirst) {
@@ -1077,7 +1236,8 @@ TEST_F(HostResolverImplTest, HigherPriorityRequestsStartedFirst) {
// This HostResolverImpl will only allow 1 outstanding resolve at a time.
size_t kMaxJobs = 1u;
scoped_refptr<HostResolver> host_resolver(
- new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs));
+ new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs,
+ NULL));
CapturingObserver observer;
host_resolver->AddObserver(&observer);
@@ -1161,7 +1321,8 @@ TEST_F(HostResolverImplTest, CancelPendingRequest) {
// This HostResolverImpl will only allow 1 outstanding resolve at a time.
const size_t kMaxJobs = 1u;
scoped_refptr<HostResolver> host_resolver(
- new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs));
+ new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs,
+ NULL));
// Note that at this point the CapturingHostResolverProc is blocked, so any
// requests we make will not complete.
@@ -1223,7 +1384,7 @@ TEST_F(HostResolverImplTest, QueueOverflow) {
// This HostResolverImpl will only allow 1 outstanding resolve at a time.
const size_t kMaxOutstandingJobs = 1u;
scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl(
- resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs));
+ resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs, NULL));
// Only allow up to 3 requests to be enqueued at a time.
const size_t kMaxPendingRequests = 3u;
@@ -1301,7 +1462,7 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) {
// This HostResolverImpl will only allow 1 outstanding resolve at a time.
const size_t kMaxOutstandingJobs = 1u;
scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl(
- resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs));
+ resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs, NULL));
host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
@@ -1369,7 +1530,7 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) {
// This HostResolverImpl will only allow 1 outstanding resolve at a time.
const size_t kMaxOutstandingJobs = 1u;
scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl(
- resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs));
+ resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs, NULL));
host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV6);
@@ -1435,7 +1596,7 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_Synchronous) {
const size_t kMaxOutstandingJobs = 10u;
scoped_refptr<HostResolverImpl> host_resolver(new HostResolverImpl(
- resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs));
+ resolver_proc, CreateDefaultCache(), kMaxOutstandingJobs, NULL));
host_resolver->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc
index 39bd808..009a636 100644
--- a/net/base/host_resolver_proc.cc
+++ b/net/base/host_resolver_proc.cc
@@ -13,18 +13,49 @@
#include <netinet/in.h>
#include "base/logging.h"
-#include "base/time.h"
#include "net/base/address_list.h"
+#include "net/base/dns_reload_timer.h"
#include "net/base/net_errors.h"
#include "net/base/sys_addrinfo.h"
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-#include "base/singleton.h"
-#include "base/thread_local_storage.h"
-#endif
-
namespace net {
+namespace {
+
+bool IsAllLocalhostOfOneFamily(const struct addrinfo* ai) {
+ bool saw_v4_localhost = false;
+ bool saw_v6_localhost = false;
+ for (; ai != NULL; ai = ai->ai_next) {
+ switch (ai->ai_family) {
+ case AF_INET: {
+ const struct sockaddr_in* addr_in =
+ reinterpret_cast<struct sockaddr_in*>(ai->ai_addr);
+ if ((ntohl(addr_in->sin_addr.s_addr) & 0xff000000) == 0x7f000000)
+ saw_v4_localhost = true;
+ else
+ return false;
+ break;
+ }
+ case AF_INET6: {
+ const struct sockaddr_in6* addr_in6 =
+ reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr);
+ if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr))
+ saw_v6_localhost = true;
+ else
+ return false;
+ break;
+ }
+ default:
+ NOTREACHED();
+ return false;
+ }
+ }
+
+ return saw_v4_localhost != saw_v6_localhost;
+}
+
+} // namespace
+
HostResolverProc* HostResolverProc::default_proc_ = NULL;
HostResolverProc::HostResolverProc(HostResolverProc* previous) {
@@ -69,6 +100,9 @@ HostResolverProc* HostResolverProc::GetDefault() {
return default_proc_;
}
+HostResolverProc::~HostResolverProc() {
+}
+
int HostResolverProc::ResolveUsingPrevious(
const std::string& host,
AddressFamily address_family,
@@ -85,84 +119,13 @@ int HostResolverProc::ResolveUsingPrevious(
addrlist, os_error);
}
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
-// On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting
-// in DNS queries failing either because nameservers are unknown on startup
-// or because nameserver info has changed as a result of e.g. connecting to
-// a new network. Some distributions patch glibc to stat /etc/resolv.conf
-// to try to automatically detect such changes but these patches are not
-// universal and even patched systems such as Jaunty appear to need calls
-// to res_ninit to reload the nameserver information in different threads.
-//
-// We adopt the Mozilla solution here which is to call res_ninit when
-// lookups fail and to rate limit the reloading to once per second per
-// thread.
-//
-// OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do
-// the same trick there.
-
-// Keep a timer per calling thread to rate limit the calling of res_ninit.
-class DnsReloadTimer {
- public:
- // Check if the timer for the calling thread has expired. When no
- // timer exists for the calling thread, create one.
- bool Expired() {
- const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
- base::TimeTicks now = base::TimeTicks::Now();
- base::TimeTicks* timer_ptr =
- static_cast<base::TimeTicks*>(tls_index_.Get());
-
- if (!timer_ptr) {
- timer_ptr = new base::TimeTicks();
- *timer_ptr = base::TimeTicks::Now();
- tls_index_.Set(timer_ptr);
- // Return true to reload dns info on the first call for each thread.
- return true;
- } else if (now - *timer_ptr > kRetryTime) {
- *timer_ptr = now;
- return true;
- } else {
- return false;
- }
- }
-
- // Free the allocated timer.
- static void SlotReturnFunction(void* data) {
- base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data);
- delete tls_data;
- }
-
- private:
- friend struct DefaultSingletonTraits<DnsReloadTimer>;
-
- DnsReloadTimer() {
- // During testing the DnsReloadTimer Singleton may be created and destroyed
- // multiple times. Initialize the ThreadLocalStorage slot only once.
- if (!tls_index_.initialized())
- tls_index_.Initialize(SlotReturnFunction);
- }
-
- ~DnsReloadTimer() {
- }
-
- // We use thread local storage to identify which base::TimeTicks to
- // interact with.
- static ThreadLocalStorage::Slot tls_index_ ;
-
- DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
-};
-
-// A TLS slot to the TimeTicks for the current thread.
-// static
-ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);
-
-#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
-
int SystemHostResolverProc(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
AddressList* addrlist,
int* os_error) {
+ static const size_t kMaxHostLength = 4096;
+
if (os_error)
*os_error = 0;
@@ -172,6 +135,11 @@ int SystemHostResolverProc(const std::string& host,
if (host.empty())
return ERR_NAME_NOT_RESOLVED;
+ // Limit the size of hostnames that will be resolved to combat issues in some
+ // platform's resolvers.
+ if (host.size() > kMaxHostLength)
+ return ERR_NAME_NOT_RESOLVED;
+
struct addrinfo* ai = NULL;
struct addrinfo hints = {0};
@@ -218,6 +186,12 @@ int SystemHostResolverProc(const std::string& host,
hints.ai_flags = AI_ADDRCONFIG;
#endif
+ // On Linux AI_ADDRCONFIG doesn't consider loopback addreses, even if only
+ // loopback addresses are configured. So don't use it when there are only
+ // loopback addresses.
+ if (host_resolver_flags & HOST_RESOLVER_LOOPBACK_ONLY)
+ hints.ai_flags &= ~AI_ADDRCONFIG;
+
if (host_resolver_flags & HOST_RESOLVER_CANONNAME)
hints.ai_flags |= AI_CANONNAME;
@@ -225,16 +199,43 @@ int SystemHostResolverProc(const std::string& host,
hints.ai_socktype = SOCK_STREAM;
int err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
+<<<<<<< HEAD
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && !defined(ANDROID)
net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get();
+=======
+ bool should_retry = false;
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+>>>>>>> Chromium at release 7.0.540.0
// If we fail, re-initialise the resolver just in case there have been any
// changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
- if (err && dns_timer->Expired()) {
+ if (err && DnsReloadTimerHasExpired()) {
res_nclose(&_res);
if (!res_ninit(&_res))
- err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
+ should_retry = true;
}
#endif
+ // If the lookup was restricted (either by address family, or address
+ // detection), and the results where all localhost of a single family,
+ // maybe we should retry. There were several bugs related to these
+ // issues, for example http://crbug.com/42058 and http://crbug.com/49024
+ if ((hints.ai_family != AF_UNSPEC || hints.ai_flags & AI_ADDRCONFIG) &&
+ err == 0 && IsAllLocalhostOfOneFamily(ai)) {
+ if (host_resolver_flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6) {
+ hints.ai_family = AF_UNSPEC;
+ should_retry = true;
+ }
+ if (hints.ai_flags & AI_ADDRCONFIG) {
+ hints.ai_flags &= ~AI_ADDRCONFIG;
+ should_retry = true;
+ }
+ }
+ if (should_retry) {
+ if (ai != NULL) {
+ freeaddrinfo(ai);
+ ai = NULL;
+ }
+ err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
+ }
if (err) {
if (os_error) {
diff --git a/net/base/host_resolver_proc.h b/net/base/host_resolver_proc.h
index 3a8adc7..f20d71a 100644
--- a/net/base/host_resolver_proc.h
+++ b/net/base/host_resolver_proc.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_HOST_RESOLVER_PROC_H_
#define NET_BASE_HOST_RESOLVER_PROC_H_
+#pragma once
#include <string>
@@ -38,7 +39,7 @@ class HostResolverProc : public base::RefCountedThreadSafe<HostResolverProc> {
protected:
friend class base::RefCountedThreadSafe<HostResolverProc>;
- virtual ~HostResolverProc() {}
+ virtual ~HostResolverProc();
// Asks the fallback procedure (if set) to do the resolve.
int ResolveUsingPrevious(const std::string& host,
diff --git a/net/base/https_prober.cc b/net/base/https_prober.cc
deleted file mode 100644
index c37f17d..0000000
--- a/net/base/https_prober.cc
+++ /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.
-
-#include "net/base/https_prober.h"
-
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-
-namespace net {
-
-bool HTTPSProber::HaveProbed(const std::string& host) const {
- return probed_.find(host) != probed_.end();
-}
-
-bool HTTPSProber::InFlight(const std::string& host) const {
- return inflight_probes_.find(host) != inflight_probes_.end();
-}
-
-bool HTTPSProber::ProbeHost(const std::string& host, URLRequestContext* ctx,
- HTTPSProberDelegate* delegate) {
- if (HaveProbed(host) || InFlight(host)) {
- return false;
- }
-
- inflight_probes_[host] = delegate;
-
- GURL url("https://" + host);
- DCHECK_EQ(url.host(), host);
-
- URLRequest* req = new URLRequest(url, this);
- req->set_context(ctx);
- req->Start();
- return true;
-}
-
-void HTTPSProber::Success(URLRequest* request) {
- DoCallback(request, true);
-}
-
-void HTTPSProber::Failure(URLRequest* request) {
- DoCallback(request, false);
-}
-
-void HTTPSProber::DoCallback(URLRequest* request, bool result) {
- std::map<std::string, HTTPSProberDelegate*>::iterator i =
- inflight_probes_.find(request->original_url().host());
- DCHECK(i != inflight_probes_.end());
-
- HTTPSProberDelegate* delegate = i->second;
- inflight_probes_.erase(i);
- probed_.insert(request->original_url().host());
- delete request;
- delegate->ProbeComplete(result);
-}
-
-void HTTPSProber::OnAuthRequired(URLRequest* request,
- net::AuthChallengeInfo* auth_info) {
- Success(request);
-}
-
-void HTTPSProber::OnSSLCertificateError(URLRequest* request,
- int cert_error,
- net::X509Certificate* cert) {
- request->ContinueDespiteLastError();
-}
-
-void HTTPSProber::OnResponseStarted(URLRequest* request) {
- if (request->status().status() == URLRequestStatus::SUCCESS) {
- Success(request);
- } else {
- Failure(request);
- }
-}
-
-void HTTPSProber::OnReadCompleted(URLRequest* request, int bytes_read) {
- NOTREACHED();
-}
-
-} // namespace net
diff --git a/net/base/https_prober.h b/net/base/https_prober.h
deleted file mode 100644
index 952176b..0000000
--- a/net/base/https_prober.h
+++ /dev/null
@@ -1,74 +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 NET_BASE_HTTPS_PROBER_H_
-#define NET_BASE_HTTPS_PROBER_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "base/singleton.h"
-#include "base/task.h"
-#include "net/url_request/url_request.h"
-
-class URLRequestContext;
-
-namespace net {
-
-// This should be scoped inside HTTPSProber, but VC cannot compile
-// HTTPProber::Delegate when HTTPSProber also inherits from
-// URLRequest::Delegate.
-class HTTPSProberDelegate {
- public:
- virtual void ProbeComplete(bool result) = 0;
- virtual ~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 {
- public:
- HTTPSProber() { }
-
- // HaveProbed returns true if the given host is known to have been probed
- // since the browser was last started.
- bool HaveProbed(const std::string& host) const;
-
- // InFlight returns true iff a probe for the given host is currently active.
- bool InFlight(const std::string& host) const;
-
- // ProbeHost starts a new probe for the given host. If the host is known to
- // have been probed since the browser was started, false is returned and no
- // other action is taken. If a probe to the given host in currently inflight,
- // false will be returned, and no other action is taken. Otherwise, a new
- // probe is started, true is returned and the Delegate will be called with the
- // results (true means a successful handshake).
- 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);
-
- private:
- void Success(URLRequest* request);
- void Failure(URLRequest* request);
- void DoCallback(URLRequest* request, bool result);
-
- std::map<std::string, HTTPSProberDelegate*> inflight_probes_;
- std::set<std::string> probed_;
-
- friend struct DefaultSingletonTraits<HTTPSProber>;
- DISALLOW_EVIL_CONSTRUCTORS(HTTPSProber);
-};
-
-} // namespace net
-#endif
diff --git a/net/base/io_buffer.cc b/net/base/io_buffer.cc
index b922733..dfd4d38 100644
--- a/net/base/io_buffer.cc
+++ b/net/base/io_buffer.cc
@@ -30,6 +30,9 @@ IOBufferWithSize::IOBufferWithSize(int size)
size_(size) {
}
+IOBufferWithSize::~IOBufferWithSize() {
+}
+
StringIOBuffer::StringIOBuffer(const std::string& s)
: IOBuffer(static_cast<char*>(NULL)),
string_data_(s) {
diff --git a/net/base/io_buffer.h b/net/base/io_buffer.h
index cc6092a..527864b 100644
--- a/net/base/io_buffer.h
+++ b/net/base/io_buffer.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_IO_BUFFER_H_
#define NET_BASE_IO_BUFFER_H_
+#pragma once
#include <string>
@@ -45,7 +46,7 @@ class IOBufferWithSize : public IOBuffer {
int size() const { return size_; }
private:
- ~IOBufferWithSize() {}
+ virtual ~IOBufferWithSize();
int size_;
};
@@ -59,7 +60,7 @@ class StringIOBuffer : public IOBuffer {
int size() const { return string_data_.size(); }
private:
- ~StringIOBuffer();
+ virtual ~StringIOBuffer();
std::string string_data_;
};
@@ -87,7 +88,7 @@ class DrainableIOBuffer : public IOBuffer {
int size() const { return size_; }
private:
- ~DrainableIOBuffer();
+ virtual ~DrainableIOBuffer();
scoped_refptr<IOBuffer> base_;
int size_;
@@ -111,7 +112,7 @@ class GrowableIOBuffer : public IOBuffer {
char* StartOfBuffer();
private:
- ~GrowableIOBuffer();
+ virtual ~GrowableIOBuffer();
scoped_ptr_malloc<char> real_data_;
int capacity_;
@@ -131,7 +132,7 @@ class PickledIOBuffer : public IOBuffer {
void Done();
private:
- ~PickledIOBuffer();
+ virtual ~PickledIOBuffer();
Pickle pickle_;
};
@@ -146,7 +147,7 @@ class WrappedIOBuffer : public IOBuffer {
explicit WrappedIOBuffer(const char* data);
protected:
- ~WrappedIOBuffer();
+ virtual ~WrappedIOBuffer();
};
} // namespace net
diff --git a/net/base/keygen_handler.h b/net/base/keygen_handler.h
index a582816..5ca6027 100644
--- a/net/base/keygen_handler.h
+++ b/net/base/keygen_handler.h
@@ -4,9 +4,12 @@
#ifndef NET_BASE_KEYGEN_HANDLER_H_
#define NET_BASE_KEYGEN_HANDLER_H_
+#pragma once
#include <string>
+#include "googleurl/src/gurl.h"
+
namespace net {
// This class handles keypair generation for generating client
@@ -16,9 +19,12 @@ namespace net {
class KeygenHandler {
public:
- // Creates a handler that will generate a key with the given key size
- // and incorporate the |challenge| into the Netscape SPKAC structure.
- inline KeygenHandler(int key_size_in_bits, const std::string& challenge);
+ // Creates a handler that will generate a key with the given key size and
+ // incorporate the |challenge| into the Netscape SPKAC structure. The request
+ // for the key originated from |url|.
+ inline KeygenHandler(int key_size_in_bits,
+ const std::string& challenge,
+ const GURL& url);
// Actually generates the key-pair and the cert request (SPKAC), and returns
// a base64-encoded string suitable for use as the form value of <keygen>.
@@ -30,13 +36,16 @@ class KeygenHandler {
private:
int key_size_in_bits_; // key size in bits (usually 2048)
std::string challenge_; // challenge string sent by server
+ GURL url_; // the URL that requested the key
bool stores_key_; // should the generated key-pair be stored persistently?
};
KeygenHandler::KeygenHandler(int key_size_in_bits,
- const std::string& challenge)
+ const std::string& challenge,
+ const GURL& url)
: key_size_in_bits_(key_size_in_bits),
challenge_(challenge),
+ url_(url),
stores_key_(true) {
}
diff --git a/net/base/keygen_handler_mac.cc b/net/base/keygen_handler_mac.cc
index c2c63d7..f5097a3 100644
--- a/net/base/keygen_handler_mac.cc
+++ b/net/base/keygen_handler_mac.cc
@@ -13,6 +13,8 @@
#include "base/lock.h"
#include "base/logging.h"
#include "base/scoped_cftyperef.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
// These are in Security.framework but not declared in a public header.
extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[];
@@ -89,6 +91,7 @@ static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = {
static OSStatus CreateRSAKeyPair(int size_in_bits,
+ SecAccessRef initial_access,
SecKeyRef* out_pub_key,
SecKeyRef* out_priv_key);
static OSStatus SignData(CSSM_DATA data,
@@ -98,14 +101,31 @@ static OSStatus SignData(CSSM_DATA data,
std::string KeygenHandler::GenKeyAndSignChallenge() {
std::string result;
OSStatus err;
+ SecAccessRef initial_access = NULL;
SecKeyRef public_key = NULL;
SecKeyRef private_key = NULL;
SecAsn1CoderRef coder = NULL;
CSSM_DATA signature = {0, NULL};
{
+ if (url_.has_host()) {
+ // TODO(davidben): Use something like "Key generated for
+ // example.com", but localize it.
+ scoped_cftyperef<CFStringRef> label(
+ base::SysUTF8ToCFStringRef(url_.host()));
+ // Create an initial access object to set the SecAccessRef. This
+ // sets a label on the Keychain dialogs. Pass NULL as the second
+ // argument to use the default trusted list; only allow the
+ // current application to access without user confirmation.
+ err = SecAccessCreate(label, NULL, &initial_access);
+ // If we fail, just continue without a label.
+ if (err)
+ base::LogCSSMError("SecAccessCreate", err);
+ }
+
// Create the key-pair.
- err = CreateRSAKeyPair(key_size_in_bits_, &public_key, &private_key);
+ err = CreateRSAKeyPair(key_size_in_bits_, initial_access,
+ &public_key, &private_key);
if (err)
goto failure;
@@ -188,6 +208,8 @@ std::string KeygenHandler::GenKeyAndSignChallenge() {
free(signature.Data);
if (coder)
SecAsn1CoderRelease(coder);
+ if (initial_access)
+ CFRelease(initial_access);
if (public_key)
CFRelease(public_key);
if (private_key)
@@ -196,7 +218,12 @@ std::string KeygenHandler::GenKeyAndSignChallenge() {
}
+// Create an RSA key pair with size |size_in_bits|. |initial_access|
+// is passed as the initial access control list in Keychain. The
+// public and private keys are placed in |out_pub_key| and
+// |out_priv_key|, respectively.
static OSStatus CreateRSAKeyPair(int size_in_bits,
+ SecAccessRef initial_access,
SecKeyRef* out_pub_key,
SecKeyRef* out_priv_key) {
OSStatus err;
@@ -221,7 +248,7 @@ static OSStatus CreateRSAKeyPair(int size_in_bits,
CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP,
CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT |
CSSM_KEYATTR_SENSITIVE,
- NULL,
+ initial_access,
out_pub_key, out_priv_key);
}
if (err)
diff --git a/net/base/keygen_handler_nss.cc b/net/base/keygen_handler_nss.cc
index 638fbd5..215244c 100644
--- a/net/base/keygen_handler_nss.cc
+++ b/net/base/keygen_handler_nss.cc
@@ -12,7 +12,7 @@ namespace psm = mozilla_security_manager;
namespace net {
std::string KeygenHandler::GenKeyAndSignChallenge() {
- return psm::GenKeyAndSignChallenge(key_size_in_bits_, challenge_,
+ return psm::GenKeyAndSignChallenge(key_size_in_bits_, challenge_, url_,
stores_key_);
}
diff --git a/net/base/keygen_handler_unittest.cc b/net/base/keygen_handler_unittest.cc
index 15ec0ce..85fd0bc 100644
--- a/net/base/keygen_handler_unittest.cc
+++ b/net/base/keygen_handler_unittest.cc
@@ -49,8 +49,8 @@ void AssertValidSignedPublicKeyAndChallenge(const std::string& result,
// just check that it exists and has a reasonable length.
// (It's almost always 590 bytes, but the DER encoding of the random key
// and signature could sometimes be a few bytes different.)
- ASSERT_GE(spkac.length(), 580U);
- ASSERT_LE(spkac.length(), 600U);
+ ASSERT_GE(spkac.length(), 200U);
+ ASSERT_LE(spkac.length(), 300U);
// NOTE:
// The value of |result| can be validated by prefixing 'SPKAC=' to it
@@ -72,8 +72,8 @@ void AssertValidSignedPublicKeyAndChallenge(const std::string& result,
// openssl asn1parse -inform DER
}
-TEST_F(KeygenHandlerTest, FLAKY_SmokeTest) {
- KeygenHandler handler(2048, "some challenge");
+TEST_F(KeygenHandlerTest, SmokeTest) {
+ KeygenHandler handler(768, "some challenge", GURL("http://www.example.com"));
handler.set_stores_key(false); // Don't leave the key-pair behind
std::string result = handler.GenKeyAndSignChallenge();
LOG(INFO) << "KeygenHandler produced: " << result;
@@ -90,7 +90,8 @@ class ConcurrencyTestTask : public Task {
}
virtual void Run() {
- KeygenHandler handler(2048, "some challenge");
+ KeygenHandler handler(768, "some challenge",
+ GURL("http://www.example.com"));
handler.set_stores_key(false); // Don't leave the key-pair behind.
*result_ = handler.GenKeyAndSignChallenge();
event_->Signal();
diff --git a/net/base/listen_socket.h b/net/base/listen_socket.h
index 923d361..7ce8887 100644
--- a/net/base/listen_socket.h
+++ b/net/base/listen_socket.h
@@ -10,6 +10,7 @@
#ifndef NET_BASE_LISTEN_SOCKET_H_
#define NET_BASE_LISTEN_SOCKET_H_
+#pragma once
#include "build/build_config.h"
diff --git a/net/base/listen_socket_unittest.cc b/net/base/listen_socket_unittest.cc
index b38019d..23dd089 100644
--- a/net/base/listen_socket_unittest.cc
+++ b/net/base/listen_socket_unittest.cc
@@ -5,6 +5,7 @@
#include "net/base/listen_socket_unittest.h"
#include <fcntl.h>
+#include <sys/types.h>
#include "base/eintr_wrapper.h"
#include "net/base/net_util.h"
@@ -13,31 +14,16 @@
const int ListenSocketTester::kTestPort = 9999;
static const int kReadBufSize = 1024;
-static const char* kHelloWorld = "HELLO, WORLD";
+static const char kHelloWorld[] = "HELLO, WORLD";
static const int kMaxQueueSize = 20;
-static const char* kLoopback = "127.0.0.1";
+static const char kLoopback[] = "127.0.0.1";
static const int kDefaultTimeoutMs = 5000;
-#if defined(OS_POSIX)
-static const char* kSemaphoreName = "chromium.listen_socket";
-#endif
-
ListenSocket* ListenSocketTester::DoListen() {
return ListenSocket::Listen(kLoopback, kTestPort, this);
}
void ListenSocketTester::SetUp() {
-#if defined(OS_WIN)
- InitializeCriticalSection(&lock_);
- semaphore_ = CreateSemaphore(NULL, 0, kMaxQueueSize, NULL);
- server_ = NULL;
- net::EnsureWinsockInit();
-#elif defined(OS_POSIX)
- ASSERT_EQ(0, pthread_mutex_init(&lock_, NULL));
- sem_unlink(kSemaphoreName);
- semaphore_ = sem_open(kSemaphoreName, O_CREAT, 0, 0);
- ASSERT_NE(SEM_FAILED, semaphore_);
-#endif
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
thread_.reset(new base::Thread("socketio_test"));
@@ -48,7 +34,7 @@ void ListenSocketTester::SetUp() {
this, &ListenSocketTester::Listen));
// verify Listen succeeded
- ASSERT_TRUE(NextAction(kDefaultTimeoutMs));
+ NextAction();
ASSERT_FALSE(server_ == NULL);
ASSERT_EQ(ACTION_LISTEN, last_action_.type());
@@ -59,124 +45,55 @@ void ListenSocketTester::SetUp() {
client.sin_family = AF_INET;
client.sin_addr.s_addr = inet_addr(kLoopback);
client.sin_port = htons(kTestPort);
- int ret =
- HANDLE_EINTR(connect(test_socket_, reinterpret_cast<sockaddr*>(&client),
- sizeof(client)));
+ int ret = HANDLE_EINTR(
+ connect(test_socket_, reinterpret_cast<sockaddr*>(&client),
+ sizeof(client)));
ASSERT_NE(ret, SOCKET_ERROR);
- net::SetNonBlocking(test_socket_);
- ASSERT_TRUE(NextAction(kDefaultTimeoutMs));
+ NextAction();
ASSERT_EQ(ACTION_ACCEPT, last_action_.type());
}
void ListenSocketTester::TearDown() {
- // verify close
#if defined(OS_WIN)
- closesocket(test_socket_);
+ ASSERT_EQ(0, closesocket(test_socket_));
#elif defined(OS_POSIX)
- close(test_socket_);
+ ASSERT_EQ(0, HANDLE_EINTR(close(test_socket_)));
#endif
- ASSERT_TRUE(NextAction(kDefaultTimeoutMs));
+ NextAction();
ASSERT_EQ(ACTION_CLOSE, last_action_.type());
loop_->PostTask(FROM_HERE, NewRunnableMethod(
this, &ListenSocketTester::Shutdown));
- ASSERT_TRUE(NextAction(kDefaultTimeoutMs));
+ NextAction();
ASSERT_EQ(ACTION_SHUTDOWN, last_action_.type());
-#if defined(OS_WIN)
- CloseHandle(semaphore_);
- semaphore_ = 0;
- DeleteCriticalSection(&lock_);
-#elif defined(OS_POSIX)
- ASSERT_EQ(0, pthread_mutex_lock(&lock_));
- semaphore_ = NULL;
- ASSERT_EQ(0, pthread_mutex_unlock(&lock_));
- ASSERT_EQ(0, sem_unlink(kSemaphoreName));
- ASSERT_EQ(0, pthread_mutex_destroy(&lock_));
-#endif
-
thread_.reset();
loop_ = NULL;
}
void ListenSocketTester::ReportAction(const ListenSocketTestAction& action) {
-#if defined(OS_WIN)
- EnterCriticalSection(&lock_);
+ AutoLock locked(lock_);
queue_.push_back(action);
- LeaveCriticalSection(&lock_);
- ReleaseSemaphore(semaphore_, 1, NULL);
-#elif defined(OS_POSIX)
- ASSERT_EQ(0, pthread_mutex_lock(&lock_));
- queue_.push_back(action);
- ASSERT_EQ(0, pthread_mutex_unlock(&lock_));
- ASSERT_EQ(0, sem_post(semaphore_));
-#endif
+ cv_.Broadcast();
}
-bool ListenSocketTester::NextAction(int timeout) {
-#if defined(OS_WIN)
- DWORD ret = ::WaitForSingleObject(semaphore_, timeout);
- if (ret != WAIT_OBJECT_0)
- return false;
- EnterCriticalSection(&lock_);
- if (queue_.size() == 0) {
- LeaveCriticalSection(&lock_);
- return false;
- }
+void ListenSocketTester::NextAction() {
+ AutoLock locked(lock_);
+ while (queue_.empty())
+ cv_.Wait();
last_action_ = queue_.front();
queue_.pop_front();
- LeaveCriticalSection(&lock_);
- return true;
-#elif defined(OS_POSIX)
- if (semaphore_ == SEM_FAILED)
- return false;
- while (true) {
- int result = sem_trywait(semaphore_);
- PlatformThread::Sleep(1); // 1MS sleep
- timeout--;
- if (timeout <= 0)
- return false;
- if (result == 0)
- break;
- }
- pthread_mutex_lock(&lock_);
- if (queue_.size() == 0) {
- pthread_mutex_unlock(&lock_);
- return false;
- }
- last_action_ = queue_.front();
- queue_.pop_front();
- pthread_mutex_unlock(&lock_);
- return true;
-#endif
}
int ListenSocketTester::ClearTestSocket() {
char buf[kReadBufSize];
int len_ret = 0;
- int time_out = 0;
do {
int len = HANDLE_EINTR(recv(test_socket_, buf, kReadBufSize, 0));
-#if defined(OS_WIN)
- if (len == SOCKET_ERROR) {
- int err = WSAGetLastError();
- if (err == WSAEWOULDBLOCK) {
-#elif defined(OS_POSIX)
- if (len == SOCKET_ERROR) {
- if (errno == EWOULDBLOCK || errno == EAGAIN) {
-#endif
- PlatformThread::Sleep(1);
- time_out++;
- if (time_out > 10)
- break;
- continue; // still trying
- }
- } else if (len == 0) {
- // socket closed
+ if (len == SOCKET_ERROR || len == 0) {
break;
} else {
- time_out = 0;
len_ret += len;
}
} while (true);
@@ -236,30 +153,30 @@ bool ListenSocketTester::Send(SOCKET sock, const std::string& str) {
void ListenSocketTester::TestClientSend() {
ASSERT_TRUE(Send(test_socket_, kHelloWorld));
- ASSERT_TRUE(NextAction(kDefaultTimeoutMs));
+ NextAction();
ASSERT_EQ(ACTION_READ, last_action_.type());
ASSERT_EQ(last_action_.data(), kHelloWorld);
}
void ListenSocketTester::TestClientSendLong() {
- int hello_len = strlen(kHelloWorld);
+ size_t hello_len = strlen(kHelloWorld);
std::string long_string;
- int long_len = 0;
+ size_t long_len = 0;
for (int i = 0; i < 200; i++) {
long_string += kHelloWorld;
long_len += hello_len;
}
ASSERT_TRUE(Send(test_socket_, long_string));
- int read_len = 0;
+ size_t read_len = 0;
while (read_len < long_len) {
- ASSERT_TRUE(NextAction(kDefaultTimeoutMs));
+ NextAction();
ASSERT_EQ(ACTION_READ, last_action_.type());
std::string last_data = last_action_.data();
size_t len = last_data.length();
if (long_string.compare(read_len, len, last_data)) {
ASSERT_EQ(long_string.compare(read_len, len, last_data), 0);
}
- read_len += static_cast<int>(last_data.length());
+ read_len += last_data.length();
}
ASSERT_EQ(read_len, long_len);
}
@@ -267,24 +184,18 @@ void ListenSocketTester::TestClientSendLong() {
void ListenSocketTester::TestServerSend() {
loop_->PostTask(FROM_HERE, NewRunnableMethod(
this, &ListenSocketTester::SendFromTester));
- ASSERT_TRUE(NextAction(kDefaultTimeoutMs));
+ NextAction();
ASSERT_EQ(ACTION_SEND, last_action_.type());
- // TODO(erikkay): Without this sleep, the recv seems to fail a small amount
- // of the time. I could fix this by making the socket blocking, but then
- // this test might hang in the case of errors. It would be nice to do
- // something that felt more reliable here.
- PlatformThread::Sleep(10); // sleep for 10ms
const int buf_len = 200;
char buf[buf_len+1];
- int recv_len;
- do {
- recv_len = HANDLE_EINTR(recv(test_socket_, buf, buf_len, 0));
-#if defined(OS_POSIX)
- } while (recv_len == SOCKET_ERROR && errno == EINTR);
-#else
- } while (false);
-#endif
- ASSERT_NE(recv_len, SOCKET_ERROR);
+ unsigned recv_len = 0;
+ while (recv_len < strlen(kHelloWorld)) {
+ int r = HANDLE_EINTR(recv(test_socket_, buf, buf_len, 0));
+ ASSERT_GE(r, 0);
+ recv_len += static_cast<unsigned>(r);
+ if (!r)
+ break;
+ }
buf[recv_len] = 0;
ASSERT_STREQ(buf, kHelloWorld);
}
@@ -319,8 +230,6 @@ TEST_F(ListenSocketTest, ClientSendLong) {
tester_->TestClientSendLong();
}
-// This test is flaky; see comment in ::TestServerSend.
-// http://code.google.com/p/chromium/issues/detail?id=48562
-TEST_F(ListenSocketTest, FLAKY_ServerSend) {
+TEST_F(ListenSocketTest, ServerSend) {
tester_->TestServerSend();
}
diff --git a/net/base/listen_socket_unittest.h b/net/base/listen_socket_unittest.h
index d43364a..6658d91 100644
--- a/net/base/listen_socket_unittest.h
+++ b/net/base/listen_socket_unittest.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_LISTEN_SOCKET_UNITTEST_H_
#define NET_BASE_LISTEN_SOCKET_UNITTEST_H_
+#pragma once
#include "build/build_config.h"
@@ -12,18 +13,18 @@
#elif defined(OS_POSIX)
#include <sys/socket.h>
#include <errno.h>
-#include <semaphore.h>
#include <arpa/inet.h>
#endif
-#include "base/scoped_ptr.h"
-#include "base/thread.h"
#include "base/basictypes.h"
+#include "base/condition_variable.h"
+#include "base/lock.h"
#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/thread.h"
-#include "net/base/net_util.h"
#include "net/base/listen_socket.h"
+#include "net/base/net_util.h"
#include "net/base/winsock_init.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -79,14 +80,15 @@ class ListenSocketTester :
: thread_(NULL),
loop_(NULL),
server_(NULL),
- connection_(NULL){
+ connection_(NULL),
+ cv_(&lock_) {
}
virtual void SetUp();
virtual void TearDown();
void ReportAction(const ListenSocketTestAction& action);
- bool NextAction(int timeout);
+ void NextAction();
// read all pending data from the test socket
int ClearTestSocket();
@@ -105,22 +107,18 @@ class ListenSocketTester :
// verify a send/read from server to client
void TestServerSend();
-#if defined(OS_WIN)
- CRITICAL_SECTION lock_;
- HANDLE semaphore_;
-#elif defined(OS_POSIX)
- pthread_mutex_t lock_;
- sem_t* semaphore_;
-#endif
-
scoped_ptr<base::Thread> thread_;
MessageLoopForIO* loop_;
ListenSocket* server_;
ListenSocket* connection_;
ListenSocketTestAction last_action_;
- std::deque<ListenSocketTestAction> queue_;
+
SOCKET test_socket_;
static const int kTestPort;
+
+ Lock lock_; // protects |queue_| and wraps |cv_|
+ ConditionVariable cv_;
+ std::deque<ListenSocketTestAction> queue_;
};
#endif // NET_BASE_LISTEN_SOCKET_UNITTEST_H_
diff --git a/net/base/load_flags.h b/net/base/load_flags.h
index 53b2d58..f3ce82a 100644
--- a/net/base/load_flags.h
+++ b/net/base/load_flags.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_LOAD_FLAGS_H_
#define NET_BASE_LOAD_FLAGS_H_
+#pragma once
namespace net {
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index ff5e609..1125a3e 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -82,3 +82,12 @@ LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 18)
// This should only be used for testing (set by HttpNetworkTransaction).
LOAD_FLAG(IGNORE_ALL_CERT_ERRORS, 1 << 19)
+
+// Indicate that this is a top level frame, so that we don't assume it is a
+// subresource and speculatively pre-connect or pre-resolve when a referring
+// page is loaded.
+LOAD_FLAG(MAIN_FRAME, 1 << 20)
+
+// Indicate that this is a sub frame, and hence it might have subresources that
+// should be speculatively resolved, or even speculatively preconnected.
+LOAD_FLAG(SUB_FRAME, 1 << 21)
diff --git a/net/base/load_states.h b/net/base/load_states.h
index 321dee8..d80e182 100644
--- a/net/base/load_states.h
+++ b/net/base/load_states.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_LOAD_STATES_H__
#define NET_BASE_LOAD_STATES_H__
+#pragma once
namespace net {
diff --git a/net/base/mapped_host_resolver.cc b/net/base/mapped_host_resolver.cc
index b401917..d81efc6 100644
--- a/net/base/mapped_host_resolver.cc
+++ b/net/base/mapped_host_resolver.cc
@@ -22,11 +22,9 @@ int MappedHostResolver::Resolve(const RequestInfo& info,
const BoundNetLog& net_log) {
// Modify the request before forwarding it to |impl_|.
RequestInfo modified_info = info;
- HostPortPair host_port(info.hostname(), info.port());
- if (rules_.RewriteHost(&host_port)) {
- modified_info.set_hostname(host_port.host);
- modified_info.set_port(host_port.port);
- }
+ HostPortPair host_port(info.host_port_pair());
+ if (rules_.RewriteHost(&host_port))
+ modified_info.set_host_port_pair(host_port);
return impl_->Resolve(modified_info, addresses, callback, out_req, net_log);
}
diff --git a/net/base/mapped_host_resolver.h b/net/base/mapped_host_resolver.h
index 3229209..1f1bf1c 100644
--- a/net/base/mapped_host_resolver.h
+++ b/net/base/mapped_host_resolver.h
@@ -4,9 +4,9 @@
#ifndef NET_BASE_MAPPED_HOST_RESOLVER_H_
#define NET_BASE_MAPPED_HOST_RESOLVER_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/ref_counted.h"
#include "net/base/host_mapping_rules.h"
diff --git a/net/base/mapped_host_resolver_unittest.cc b/net/base/mapped_host_resolver_unittest.cc
index 4b7281c..06beeb7 100644
--- a/net/base/mapped_host_resolver_unittest.cc
+++ b/net/base/mapped_host_resolver_unittest.cc
@@ -31,7 +31,8 @@ TEST(MappedHostResolverTest, Inclusion) {
// Try resolving "www.google.com:80". There are no mappings yet, so this
// hits |resolver_impl| and fails.
- rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80),
+ rv = resolver->Resolve(HostResolver::RequestInfo(
+ HostPortPair("www.google.com", 80)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
@@ -39,7 +40,8 @@ TEST(MappedHostResolverTest, Inclusion) {
EXPECT_TRUE(resolver->AddRuleFromString("map *.google.com baz.com"));
// Try resolving "www.google.com:80". Should be remapped to "baz.com:80".
- rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80),
+ rv = resolver->Resolve(HostResolver::RequestInfo(
+ HostPortPair("www.google.com", 80)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.5", NetAddressToString(address_list.head()));
@@ -47,7 +49,7 @@ TEST(MappedHostResolverTest, Inclusion) {
// Try resolving "foo.com:77". This will NOT be remapped, so result
// is "foo.com:77".
- rv = resolver->Resolve(HostResolver::RequestInfo("foo.com", 77),
+ rv = resolver->Resolve(HostResolver::RequestInfo(HostPortPair("foo.com", 77)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.8", NetAddressToString(address_list.head()));
@@ -57,7 +59,8 @@ TEST(MappedHostResolverTest, Inclusion) {
EXPECT_TRUE(resolver->AddRuleFromString("Map *.org proxy:99"));
// Try resolving "chromium.org:61". Should be remapped to "proxy:99".
- rv = resolver->Resolve(HostResolver::RequestInfo("chromium.org", 61),
+ rv = resolver->Resolve(HostResolver::RequestInfo
+ (HostPortPair("chromium.org", 61)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.11", NetAddressToString(address_list.head()));
@@ -85,14 +88,16 @@ TEST(MappedHostResolverTest, Exclusion) {
EXPECT_TRUE(resolver->AddRuleFromString("EXCLUDE *.google.com"));
// Try resolving "www.google.com". Should not be remapped due to exclusion).
- rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80),
+ rv = resolver->Resolve(HostResolver::RequestInfo(
+ HostPortPair("www.google.com", 80)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.3", NetAddressToString(address_list.head()));
EXPECT_EQ(80, address_list.GetPort());
// Try resolving "chrome.com:80". Should be remapped to "baz:80".
- rv = resolver->Resolve(HostResolver::RequestInfo("chrome.com", 80),
+ rv = resolver->Resolve(HostResolver::RequestInfo(
+ HostPortPair("chrome.com", 80)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.5", NetAddressToString(address_list.head()));
@@ -116,14 +121,16 @@ TEST(MappedHostResolverTest, SetRulesFromString) {
resolver->SetRulesFromString("map *.com baz , map *.net bar:60");
// Try resolving "www.google.com". Should be remapped to "baz".
- rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80),
+ rv = resolver->Resolve(HostResolver::RequestInfo(
+ HostPortPair("www.google.com", 80)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.7", NetAddressToString(address_list.head()));
EXPECT_EQ(80, address_list.GetPort());
// Try resolving "chrome.net:80". Should be remapped to "bar:60".
- rv = resolver->Resolve(HostResolver::RequestInfo("chrome.net", 80),
+ rv = resolver->Resolve(HostResolver::RequestInfo(
+ HostPortPair("chrome.net", 80)),
&address_list, NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.9", NetAddressToString(address_list.head()));
diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc
index 1961107..4ad4e1d 100644
--- a/net/base/mime_sniffer.cc
+++ b/net/base/mime_sniffer.cc
@@ -228,7 +228,8 @@ static bool MatchMagicNumber(const char* content, size_t size,
// pretend the length is content_size.
const char* end =
static_cast<const char*>(memchr(content, '\0', size));
- const size_t content_strlen = (end != NULL) ? (end - content) : size;
+ const size_t content_strlen =
+ (end != NULL) ? static_cast<size_t>(end - content) : size;
bool match = false;
if (magic_entry->is_string) {
diff --git a/net/base/mime_sniffer.h b/net/base/mime_sniffer.h
index d0c4e78..5f3862b 100644
--- a/net/base/mime_sniffer.h
+++ b/net/base/mime_sniffer.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_MIME_SNIFFER_H__
#define NET_BASE_MIME_SNIFFER_H__
+#pragma once
#include <string>
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index 9163eeb..2e663e2 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -11,6 +11,7 @@
#include "base/hash_tables.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"
@@ -89,6 +90,7 @@ static const MimeInfo primary_mappings[] = {
{ "audio/ogg", "ogg,oga" },
{ "video/webm", "webm" },
{ "audio/webm", "webm" },
+ { "audio/wav", "wav" },
{ "application/xhtml+xml", "xhtml,xht" },
{ "application/x-chrome-extension", "crx" }
};
@@ -208,6 +210,8 @@ static const char* const supported_media_types[] = {
"application/ogg",
"video/webm",
"audio/webm",
+ "audio/wav",
+ "audio/x-wav",
#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
// MPEG-4.
@@ -234,7 +238,8 @@ static const char* const supported_media_codecs[] = {
#endif
"theora",
"vorbis",
- "vp8"
+ "vp8",
+ "1" // PCM for WAV.
};
// Note: does not include javascript types list (see supported_javascript_types)
@@ -305,7 +310,8 @@ struct MediaFormatStrict {
static const MediaFormatStrict format_codec_mappings[] = {
{ "video/webm", "vorbis,vp8,vp8.0" },
- { "audio/webm", "vorbis" }
+ { "audio/webm", "vorbis" },
+ { "audio/wav", "1" }
};
void MimeUtil::InitializeMimeTypeMaps() {
@@ -537,4 +543,179 @@ void ParseCodecString(const std::string& codecs,
GetMimeUtil()->ParseCodecString(codecs, codecs_out, strip);
}
+namespace {
+
+// From http://www.w3schools.com/media/media_mimeref.asp and
+// http://plugindoc.mozdev.org/winmime.php
+static const char* kStandardImageTypes[] = {
+ "image/bmp",
+ "image/cis-cod",
+ "image/gif",
+ "image/ief",
+ "image/jpeg",
+ "image/pict",
+ "image/pipeg",
+ "image/png",
+ "image/svg+xml",
+ "image/tiff",
+ "image/x-cmu-raster",
+ "image/x-cmx",
+ "image/x-icon",
+ "image/x-portable-anymap",
+ "image/x-portable-bitmap",
+ "image/x-portable-graymap",
+ "image/x-portable-pixmap",
+ "image/x-rgb",
+ "image/x-xbitmap",
+ "image/x-xpixmap",
+ "image/x-xwindowdump"
+};
+static const char* kStandardAudioTypes[] = {
+ "audio/aac",
+ "audio/aiff",
+ "audio/amr",
+ "audio/basic",
+ "audio/midi",
+ "audio/mp3",
+ "audio/mp4",
+ "audio/mpeg",
+ "audio/mpeg3",
+ "audio/ogg",
+ "audio/vorbis",
+ "audio/wav",
+ "audio/webm",
+ "audio/x-m4a",
+ "audio/x-ms-wma",
+ "audio/vnd.rn-realaudio",
+ "audio/vnd.wave"
+};
+static const char* kStandardVideoTypes[] = {
+ "video/avi",
+ "video/divx",
+ "video/flc",
+ "video/mp4",
+ "video/mpeg",
+ "video/ogg",
+ "video/quicktime",
+ "video/sd-video",
+ "video/webm",
+ "video/x-dv",
+ "video/x-m4v",
+ "video/x-mpeg",
+ "video/x-ms-asf",
+ "video/x-ms-wmv"
+};
+
+void GetExtensionsFromHardCodedMappings(
+ const MimeInfo* mappings,
+ size_t mappings_len,
+ const std::string& leading_mime_type,
+ base::hash_set<FilePath::StringType>* extensions) {
+ FilePath::StringType extension;
+ for (size_t i = 0; i < mappings_len; ++i) {
+ if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
+ std::vector<string> this_extensions;
+ base::SplitStringUsingSubstr(mappings[i].extensions,
+ ",",
+ &this_extensions);
+ for (size_t j = 0; j < this_extensions.size(); ++j) {
+#if defined(OS_WIN)
+ FilePath::StringType extension(UTF8ToWide(this_extensions[j]));
+#else
+ FilePath::StringType extension(this_extensions[j]);
+#endif
+ extensions->insert(extension);
+ }
+ }
+ }
+}
+
+void GetExtensionsHelper(
+ const char** standard_types,
+ size_t standard_types_len,
+ const std::string& leading_mime_type,
+ base::hash_set<FilePath::StringType>* extensions) {
+ FilePath::StringType extension;
+ for (size_t i = 0; i < standard_types_len; ++i) {
+ if (net::GetPreferredExtensionForMimeType(standard_types[i], &extension))
+ extensions->insert(extension);
+ }
+
+ // Also look up the extensions from hard-coded mappings in case that some
+ // supported extensions are not registered in the system registry, like ogg.
+ GetExtensionsFromHardCodedMappings(primary_mappings,
+ arraysize(primary_mappings),
+ leading_mime_type,
+ extensions);
+
+ GetExtensionsFromHardCodedMappings(secondary_mappings,
+ arraysize(secondary_mappings),
+ leading_mime_type,
+ extensions);
+}
+
+// Note that the elements in the source set will be appended to the target
+// vector.
+template<class T>
+void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
+ size_t old_target_size = target->size();
+ target->resize(old_target_size + source->size());
+ size_t i = 0;
+ for (typename base::hash_set<T>::iterator iter = source->begin();
+ iter != source->end(); ++iter, ++i) {
+ target->at(old_target_size + i) = *iter;
+ }
+}
+
+}
+
+void GetImageExtensions(std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ GetExtensionsHelper(kStandardImageTypes,
+ arraysize(kStandardImageTypes),
+ "image/",
+ &unique_extensions);
+ HashSetToVector(&unique_extensions, extensions);
+}
+
+void GetAudioExtensions(std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ GetExtensionsHelper(kStandardAudioTypes,
+ arraysize(kStandardAudioTypes),
+ "audio/",
+ &unique_extensions);
+ HashSetToVector(&unique_extensions, extensions);
+}
+
+void GetVideoExtensions(std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ GetExtensionsHelper(kStandardVideoTypes,
+ arraysize(kStandardVideoTypes),
+ "video/",
+ &unique_extensions);
+ HashSetToVector(&unique_extensions, extensions);
+}
+
+void GetExtensionsForMimeType(const std::string& mime_type,
+ std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ FilePath::StringType extension;
+ if (net::GetPreferredExtensionForMimeType(mime_type, &extension))
+ unique_extensions.insert(extension);
+
+ // Also look up the extensions from hard-coded mappings in case that some
+ // supported extensions are not registered in the system registry, like ogg.
+ GetExtensionsFromHardCodedMappings(primary_mappings,
+ arraysize(primary_mappings),
+ mime_type,
+ &unique_extensions);
+
+ GetExtensionsFromHardCodedMappings(secondary_mappings,
+ arraysize(secondary_mappings),
+ mime_type,
+ &unique_extensions);
+
+ HashSetToVector(&unique_extensions, extensions);
+}
+
} // namespace net
diff --git a/net/base/mime_util.h b/net/base/mime_util.h
index eebc2e8..249a25b 100644
--- a/net/base/mime_util.h
+++ b/net/base/mime_util.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_MIME_UTIL_H__
#define NET_BASE_MIME_UTIL_H__
+#pragma once
#include <string>
#include <vector>
@@ -70,6 +71,29 @@ bool IsStrictMediaMimeType(const std::string& mime_type);
bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
const std::vector<std::string>& codecs);
+// Get the extensions for images files.
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetImageExtensions(std::vector<FilePath::StringType>* extensions);
+
+// Get the extensions for audio files.
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetAudioExtensions(std::vector<FilePath::StringType>* extensions);
+
+// Get the extensions for video files.
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetVideoExtensions(std::vector<FilePath::StringType>* extensions);
+
+// Get the extensions associated with the given mime type.
+// There could be multiple extensions for a given mime type, like "html,htm"
+// for "text/html".
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetExtensionsForMimeType(const std::string& mime_type,
+ std::vector<FilePath::StringType>* extensions);
+
} // namespace net
#endif // NET_BASE_MIME_UTIL_H__
diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc
index 8d1fd89..f8c53a6 100644
--- a/net/base/mock_host_resolver.cc
+++ b/net/base/mock_host_resolver.cc
@@ -9,11 +9,20 @@
#include "base/ref_counted.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/sys_addrinfo.h"
namespace net {
namespace {
+char* do_strdup(const char* src) {
+#if defined(OS_WIN)
+ return _strdup(src);
+#else
+ return strdup(src);
+#endif
+}
+
// Fills |*addrlist| with a socket address for |host| which should be an
// IPv4 or IPv6 literal without enclosing brackets. If |canonical_name| is
// non-empty it is used as the DNS canonical name for the host. Returns OK on
@@ -27,15 +36,10 @@ int CreateIPAddress(const std::string& host,
return ERR_UNEXPECTED;
}
- if (ip_number.size() == 4) {
- *addrlist = AddressList::CreateIPv4Address(&ip_number[0], canonical_name);
- } else if (ip_number.size() == 16) {
- *addrlist = AddressList::CreateIPv6Address(&ip_number[0], canonical_name);
- } else {
- NOTREACHED();
- return ERR_UNEXPECTED;
- }
-
+ AddressList result(ip_number, -1, false);
+ struct addrinfo* ai = const_cast<struct addrinfo*>(result.head());
+ ai->ai_canonname = do_strdup(canonical_name.c_str());
+ *addrlist = result;
return OK;
}
@@ -98,7 +102,7 @@ void MockHostResolverBase::Reset(HostResolverProc* interceptor) {
base::TimeDelta::FromSeconds(0));
}
- impl_ = new HostResolverImpl(proc, cache, 50u);
+ impl_ = new HostResolverImpl(proc, cache, 50u, NULL);
}
//-----------------------------------------------------------------------------
@@ -152,8 +156,10 @@ void RuleBasedHostResolverProc::AddRuleForAddressFamily(
AddressFamily address_family,
const std::string& replacement) {
DCHECK(!replacement.empty());
- Rule rule(Rule::kResolverTypeSystem, host_pattern,
- address_family, 0, replacement, "", 0);
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeSystem, host_pattern, address_family, flags,
+ replacement, "", 0);
rules_.push_back(rule);
}
@@ -161,13 +167,16 @@ void RuleBasedHostResolverProc::AddIPLiteralRule(
const std::string& host_pattern,
const std::string& ip_literal,
const std::string& canonical_name) {
- Rule rule(Rule::kResolverTypeIPLiteral,
- host_pattern,
- ADDRESS_FAMILY_UNSPECIFIED,
- canonical_name.empty() ? 0 : HOST_RESOLVER_CANONNAME,
- ip_literal,
- canonical_name,
- 0);
+ // Literals are always resolved to themselves by HostResolverImpl,
+ // consequently we do not support remapping them.
+ IPAddressNumber ip_number;
+ DCHECK(!ParseIPLiteralToNumber(host_pattern, &ip_number));
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ if (!canonical_name.empty())
+ flags |= HOST_RESOLVER_CANONNAME;
+ Rule rule(Rule::kResolverTypeIPLiteral, host_pattern,
+ ADDRESS_FAMILY_UNSPECIFIED, flags, ip_literal, canonical_name, 0);
rules_.push_back(rule);
}
@@ -176,22 +185,28 @@ void RuleBasedHostResolverProc::AddRuleWithLatency(
const std::string& replacement,
int latency_ms) {
DCHECK(!replacement.empty());
- Rule rule(Rule::kResolverTypeSystem, host_pattern,
- ADDRESS_FAMILY_UNSPECIFIED, 0, replacement, "", latency_ms);
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED,
+ flags, replacement, "", latency_ms);
rules_.push_back(rule);
}
void RuleBasedHostResolverProc::AllowDirectLookup(
const std::string& host_pattern) {
- Rule rule(Rule::kResolverTypeSystem, host_pattern,
- ADDRESS_FAMILY_UNSPECIFIED, 0, "", "", 0);
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED,
+ flags, "", "", 0);
rules_.push_back(rule);
}
void RuleBasedHostResolverProc::AddSimulatedFailure(
const std::string& host_pattern) {
- Rule rule(Rule::kResolverTypeFail, host_pattern,
- ADDRESS_FAMILY_UNSPECIFIED, 0, "", "", 0);
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeFail, host_pattern, ADDRESS_FAMILY_UNSPECIFIED,
+ flags, "", "", 0);
rules_.push_back(rule);
}
@@ -212,7 +227,7 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
bool matches_flags = (r->host_resolver_flags & host_resolver_flags) ==
host_resolver_flags;
if (matches_flags && matches_address_family &&
- MatchPatternASCII(host, r->host_pattern)) {
+ MatchPattern(host, r->host_pattern)) {
if (r->latency_ms != 0)
PlatformThread::Sleep(r->latency_ms);
diff --git a/net/base/mock_host_resolver.h b/net/base/mock_host_resolver.h
index ee1e55a..4b185b2 100644
--- a/net/base/mock_host_resolver.h
+++ b/net/base/mock_host_resolver.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_MOCK_HOST_RESOLVER_H_
#define NET_BASE_MOCK_HOST_RESOLVER_H_
+#pragma once
#include <list>
@@ -58,6 +59,13 @@ class MockHostResolverBase : public HostResolver {
// Resets the mock.
void Reset(HostResolverProc* interceptor);
+ void SetPoolConstraints(HostResolverImpl::JobPoolIndex pool_index,
+ size_t max_outstanding_jobs,
+ size_t max_pending_requests) {
+ impl_->SetPoolConstraints(
+ pool_index, max_outstanding_jobs, max_pending_requests);
+ }
+
protected:
MockHostResolverBase(bool use_caching);
virtual ~MockHostResolverBase() {}
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index e302a9f..0370874 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -16,6 +16,7 @@
// 400-499 Cache errors
// 500-599 ?
// 600-699 FTP errors
+// 700-799 Certificate manager errors
//
// An asynchronous IO operation is not yet complete. This usually does not
@@ -167,10 +168,14 @@ NET_ERROR(PROXY_AUTH_REQUESTED, -127)
// A known TLS strict server didn't offer the renegotiation extension.
NET_ERROR(SSL_UNSAFE_NEGOTIATION, -128)
-// The socket is reporting that we tried to provide new credentials after a
-// a failed attempt on a connection without keep alive. We need to
-// reestablish the transport socket in order to retry the authentication.
-NET_ERROR(RETRY_CONNECTION, -129)
+// The SSL server attempted to use a weak ephemeral Diffie-Hellman key.
+NET_ERROR(SSL_WEAK_SERVER_EPHEMERAL_DH_KEY, -129)
+
+// Could not create a TCP connection to the proxy server. An error occurred
+// either in resolving its name, or in connecting a socket to it.
+// Note that this does NOT include failures during the actual "CONNECT" method
+// of an HTTP proxy.
+NET_ERROR(PROXY_CONNECTION_FAILED, -130)
// Certificate error codes
//
@@ -260,13 +265,17 @@ NET_ERROR(CERT_INVALID, -207)
// signature algorithm.
NET_ERROR(CERT_WEAK_SIGNATURE_ALGORITHM, -208)
+// The domain has CERT records which are tagged as being an exclusive list of
+// valid fingerprints. But the certificate presented was not in this list.
+NET_ERROR(CERT_NOT_IN_DNS, -209)
+
// Add new certificate error codes here.
//
// Update the value of CERT_END whenever you add a new certificate error
// code.
// The value immediately past the last certificate error code.
-NET_ERROR(CERT_END, -209)
+NET_ERROR(CERT_END, -210)
// The URL is invalid.
NET_ERROR(INVALID_URL, -300)
@@ -360,6 +369,22 @@ NET_ERROR(ENCODING_DETECTION_FAILED, -340)
// (GSSAPI) No Kerberos credentials were available during HTTP Authentication.
NET_ERROR(MISSING_AUTH_CREDENTIALS, -341)
+// An unexpected, but documented, SSPI or GSSAPI status code was returned.
+NET_ERROR(UNEXPECTED_SECURITY_LIBRARY_STATUS, -342)
+
+// The environment was not set up correctly for authentication (for
+// example, no KDC could be found or the principal is unknown.
+NET_ERROR(MISCONFIGURED_AUTH_ENVIRONMENT, -343)
+
+// An undocumented SSPI or GSSAPI status code was returned.
+NET_ERROR(UNDOCUMENTED_SECURITY_LIBRARY_STATUS, -344)
+
+// The HTTP response was too big to drain.
+NET_ERROR(RESPONSE_BODY_TOO_BIG_TO_DRAIN, -345)
+
+// The HTTP response was too big to drain.
+NET_ERROR(RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, -346)
+
// The cache does not have the requested entry.
NET_ERROR(CACHE_MISS, -400)
@@ -425,3 +450,20 @@ NET_ERROR(FTP_COMMAND_NOT_SUPPORTED, -606)
// order.
// FTP response code 503.
NET_ERROR(FTP_BAD_COMMAND_SEQUENCE, -607)
+
+// PKCS #12 import failed due to incorrect password.
+NET_ERROR(PKCS12_IMPORT_BAD_PASSWORD, -701)
+
+// PKCS #12 import failed due to other error.
+NET_ERROR(PKCS12_IMPORT_FAILED, -702)
+
+// CA import failed - not a CA cert.
+NET_ERROR(IMPORT_CA_CERT_NOT_CA, -703)
+
+// Import failed - certificate already exists in database.
+// Note it's a little weird this is an error but reimporting a PKCS12 is ok
+// (no-op). That's how mozilla does it, though.
+NET_ERROR(IMPORT_CERT_ALREADY_EXISTS, -704)
+
+// CA import failed due to some other error.
+NET_ERROR(IMPORT_CA_CERT_FAILED, -705)
diff --git a/net/base/net_errors.h b/net/base/net_errors.h
index 227b5b8..847b215 100644
--- a/net/base/net_errors.h
+++ b/net/base/net_errors.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_NET_ERRORS_H__
#define NET_BASE_NET_ERRORS_H__
+#pragma once
#include "base/basictypes.h"
diff --git a/net/base/net_log.cc b/net/base/net_log.cc
index bd62f91..2cc149f 100644
--- a/net/base/net_log.cc
+++ b/net/base/net_log.cc
@@ -3,12 +3,21 @@
// found in the LICENSE file.
#include "net/base/net_log.h"
-#include "base/string_util.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
namespace net {
+Value* NetLog::Source::ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("type", static_cast<int>(type));
+ dict->SetInteger("id", static_cast<int>(id));
+ return dict;
+}
+
// static
const char* NetLog::EventTypeToString(EventType event) {
switch (event) {
@@ -28,6 +37,72 @@ std::vector<NetLog::EventType> NetLog::GetAllEventTypes() {
return types;
}
+// static
+const char* NetLog::SourceTypeToString(SourceType source) {
+ switch (source) {
+#define SOURCE_TYPE(label, id) case id: return #label;
+#include "net/base/net_log_source_type_list.h"
+#undef SOURCE_TYPE
+ }
+ NOTREACHED();
+ return NULL;
+}
+
+// static
+const char* NetLog::EventPhaseToString(EventPhase phase) {
+ switch (phase) {
+ case PHASE_BEGIN:
+ return "PHASE_BEGIN";
+ case PHASE_END:
+ return "PHASE_END";
+ case PHASE_NONE:
+ return "PHASE_NONE";
+ }
+ NOTREACHED();
+ return NULL;
+}
+
+// static
+Value* NetLog::EntryToDictionaryValue(net::NetLog::EventType type,
+ const base::TimeTicks& time,
+ const net::NetLog::Source& source,
+ net::NetLog::EventPhase phase,
+ net::NetLog::EventParameters* params,
+ bool use_strings) {
+ DictionaryValue* entry_dict = new DictionaryValue();
+
+ // Set the entry time. (Note that we send it as a string since integers
+ // might overflow).
+ int64 delta_time = (time - base::TimeTicks()).InMilliseconds();
+ entry_dict->SetString("time", base::Int64ToString(delta_time));
+
+ // Set the entry source.
+ DictionaryValue* source_dict = new DictionaryValue();
+ source_dict->SetInteger("id", source.id);
+ if (!use_strings) {
+ source_dict->SetInteger("type", static_cast<int>(source.type));
+ } else {
+ source_dict->SetString("type",
+ net::NetLog::SourceTypeToString(source.type));
+ }
+ entry_dict->Set("source", source_dict);
+
+ // Set the event info.
+ if (!use_strings) {
+ entry_dict->SetInteger("type", static_cast<int>(type));
+ entry_dict->SetInteger("phase", static_cast<int>(phase));
+ } else {
+ entry_dict->SetString("type", net::NetLog::EventTypeToString(type));
+ entry_dict->SetString("phase", net::NetLog::EventPhaseToString(phase));
+ }
+
+ // Set the event-specific parameters.
+ if (params)
+ entry_dict->Set("params", params->ToValue());
+
+ return entry_dict;
+}
+
void BoundNetLog::AddEntry(
NetLog::EventType type,
NetLog::EventPhase phase,
@@ -47,10 +122,14 @@ void BoundNetLog::AddEntryWithTime(
}
}
-bool BoundNetLog::HasListener() const {
+NetLog::LogLevel BoundNetLog::GetLogLevel() const {
if (net_log_)
- return net_log_->HasListener();
- return false;
+ return net_log_->GetLogLevel();
+ return NetLog::LOG_BASIC;
+}
+
+bool BoundNetLog::IsLoggingAll() const {
+ return GetLogLevel() == NetLog::LOG_ALL;
}
void BoundNetLog::AddEvent(
@@ -86,26 +165,25 @@ NetLogStringParameter::NetLogStringParameter(const char* name,
: name_(name), value_(value) {
}
+NetLogStringParameter::~NetLogStringParameter() {
+}
+
Value* NetLogIntegerParameter::ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- dict->SetInteger(ASCIIToWide(name_), value_);
+ dict->SetInteger(name_, value_);
return dict;
}
Value* NetLogStringParameter::ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- dict->SetString(ASCIIToWide(name_), value_);
+ dict->SetString(name_, value_);
return dict;
}
Value* NetLogSourceParameter::ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- DictionaryValue* source_dict = new DictionaryValue();
- source_dict->SetInteger(L"type", static_cast<int>(value_.type));
- source_dict->SetInteger(L"id", static_cast<int>(value_.id));
-
- dict->Set(ASCIIToWide(name_), source_dict);
+ dict->Set(name_, value_.ToValue());
return dict;
}
diff --git a/net/base/net_log.h b/net/base/net_log.h
index 266b93a..c97eb1a 100644
--- a/net/base/net_log.h
+++ b/net/base/net_log.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_NET_LOG_H_
#define NET_BASE_NET_LOG_H_
+#pragma once
#include <string>
#include <vector>
@@ -68,7 +69,10 @@ class NetLog {
Source() : type(SOURCE_NONE), id(kInvalidId) {}
Source(SourceType type, uint32 id) : type(type), id(id) {}
- bool is_valid() { return id != kInvalidId; }
+ bool is_valid() const { return id != kInvalidId; }
+
+ // The caller takes ownership of the returned Value*.
+ Value* ToValue() const;
SourceType type;
uint32 id;
@@ -91,6 +95,15 @@ class NetLog {
DISALLOW_COPY_AND_ASSIGN(EventParameters);
};
+ // Specifies the granularity of events that should be emitted to the log.
+ enum LogLevel {
+ // Log everything possible, even if it is slow and memory expensive.
+ LOG_ALL,
+
+ // Only log events which are cheap, and don't consume much memory.
+ LOG_BASIC,
+ };
+
NetLog() {}
virtual ~NetLog() {}
@@ -113,8 +126,9 @@ class NetLog {
// Returns a unique ID which can be used as a source ID.
virtual uint32 NextID() = 0;
- // Returns true if more complicated messages should be sent to the log.
- virtual bool HasListener() const = 0;
+ // Returns the logging level for this NetLog. This is used to avoid computing
+ // and saving expensive log entries.
+ virtual LogLevel GetLogLevel() const = 0;
// Returns a C-String symbolic name for |event_type|.
static const char* EventTypeToString(EventType event_type);
@@ -122,6 +136,21 @@ class NetLog {
// Returns a list of all the available EventTypes.
static std::vector<EventType> GetAllEventTypes();
+ // Returns a C-String symbolic name for |source_type|.
+ static const char* SourceTypeToString(SourceType source_type);
+
+ // Returns a C-String symbolic name for |event_phase|.
+ static const char* EventPhaseToString(EventPhase event_phase);
+
+ // Serializes the specified event to a DictionaryValue.
+ // If |use_strings| is true, uses strings rather than numeric ids.
+ static Value* EntryToDictionaryValue(net::NetLog::EventType type,
+ const base::TimeTicks& time,
+ const net::NetLog::Source& source,
+ net::NetLog::EventPhase phase,
+ net::NetLog::EventParameters* params,
+ bool use_strings);
+
private:
DISALLOW_COPY_AND_ASSIGN(NetLog);
};
@@ -158,7 +187,10 @@ class BoundNetLog {
void EndEvent(NetLog::EventType event_type,
const scoped_refptr<NetLog::EventParameters>& params) const;
- bool HasListener() const;
+ NetLog::LogLevel GetLogLevel() const;
+
+ // Returns true if the log level is LOG_ALL.
+ bool IsLoggingAll() const;
// Helper to create a BoundNetLog given a NetLog and a SourceType. Takes care
// of creating a unique source ID, and handles the case of NULL net_log.
@@ -178,6 +210,7 @@ class NetLogStringParameter : public NetLog::EventParameters {
public:
// |name| must be a string literal.
NetLogStringParameter(const char* name, const std::string& value);
+ virtual ~NetLogStringParameter();
const std::string& value() const {
return value_;
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 2fcd6fa..d47e575 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -20,14 +20,86 @@ EVENT_TYPE(REQUEST_ALIVE)
// HostResolverImpl
// ------------------------------------------------------------------------
-// The start/end of a host resolve (DNS) request.
-// If an error occurred, the end phase will contain these parameters:
+// The start/end of waiting on a host resolve (DNS) request.
+// The BEGIN phase contains the following parameters:
+//
+// {
+// "source_dependency": <Source id of the request being waited on>
+// }
+EVENT_TYPE(HOST_RESOLVER_IMPL)
+
+// The start/end of a host resolve (DNS) request. Note that these events are
+// logged for all DNS requests, though not all requests result in the creation
+// of a HostResolvedImpl::Request object.
+//
+// The BEGIN phase contains the following parameters:
+//
+// {
+// "host": <Hostname associated with the request>
+// "source_dependency": <Source id, if any, of what created the request>
+// }
+//
+// If an error occurred, the END phase will contain these parameters:
// {
// "net_error": <The net error code integer for the failure>,
// "os_error": <The exact error code integer that getaddrinfo() returned>,
-// "was_from_cache": <True if the response was gotten from the cache>
// }
-EVENT_TYPE(HOST_RESOLVER_IMPL)
+
+EVENT_TYPE(HOST_RESOLVER_IMPL_REQUEST)
+
+// This event is logged when a request is handled by a cache entry.
+EVENT_TYPE(HOST_RESOLVER_IMPL_CACHE_HIT)
+
+// This event means a request was queued/dequeued for subsequent job creation,
+// because there are already too many active HostResolverImpl::Jobs.
+//
+// The BEGIN phase contains the following parameters:
+//
+// {
+// "priority": <Priority of the queued request>
+// }
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_POOL_QUEUE)
+
+// This event is created when a new HostResolverImpl::Request is evicted from
+// JobPool without a Job being created, because the limit on number of queued
+// Requests was reached.
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED)
+
+// This event is created when a new HostResolverImpl::Job is about to be created
+// for a request.
+EVENT_TYPE(HOST_RESOLVER_IMPL_CREATE_JOB)
+
+// This is logged for a request when it's attached to a
+// HostResolverImpl::Job. When this occurs without a preceding
+// HOST_RESOLVER_IMPL_CREATE_JOB entry, it means the request was attached to an
+// existing HostResolverImpl::Job.
+//
+// If the BoundNetLog used to create the event has a valid source id, the BEGIN
+// phase contains the following parameters:
+//
+// {
+// "source_dependency": <Source identifier for the attached Job>
+// }
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB_ATTACH)
+
+// The creation/completion of a host resolve (DNS) job.
+// The BEGIN phase contains the following parameters:
+//
+// {
+// "host": <Hostname associated with the request>
+// "source_dependency": <Source id, if any, of what created the request>
+// }
+//
+// On success, the END phase has these parameters:
+// {
+// "address_list": <The host name being resolved>,
+// }
+// If an error occurred, the END phase will contain these parameters:
+// {
+// "net_error": <The net error code integer for the failure>,
+// "os_error": <The exact error code integer that getaddrinfo() returned>,
+// }
+EVENT_TYPE(HOST_RESOLVER_IMPL_JOB)
// ------------------------------------------------------------------------
// InitProxyResolver
@@ -36,6 +108,11 @@ EVENT_TYPE(HOST_RESOLVER_IMPL)
// The start/end of auto-detect + custom PAC URL configuration.
EVENT_TYPE(INIT_PROXY_RESOLVER)
+// The start/end of when proxy autoconfig was artificially paused following
+// a network change event. (We wait some amount of time after being told of
+// network changes to avoid hitting spurious errors during auto-detect).
+EVENT_TYPE(INIT_PROXY_RESOLVER_WAIT)
+
// The start/end of download of a PAC script. This could be the well-known
// WPAD URL (if testing auto-detect), or a custom PAC URL.
//
@@ -79,9 +156,6 @@ EVENT_TYPE(PROXY_SERVICE)
// are found from ProxyService::init_proxy_resolver_log().
EVENT_TYPE(PROXY_SERVICE_WAITING_FOR_INIT_PAC)
-// The time taken to fetch the system proxy configuration.
-EVENT_TYPE(PROXY_SERVICE_POLL_CONFIG_SERVICE_FOR_CHANGES)
-
// This event is emitted to show what the PAC script returned. It can contain
// extra parameters that are either:
// {
@@ -94,6 +168,19 @@ EVENT_TYPE(PROXY_SERVICE_POLL_CONFIG_SERVICE_FOR_CHANGES)
// }
EVENT_TYPE(PROXY_SERVICE_RESOLVED_PROXY_LIST)
+// This event is emitted whenever the proxy settings used by ProxyService
+// change.
+//
+// It contains these parameters:
+// {
+// "old_config": <Dump of the previous proxy settings>,
+// "new_config": <Dump of the new proxy settings>
+// }
+//
+// Note that the "old_config" key will be omitted on the first fetch of the
+// proxy settings (since there wasn't a previous value).
+EVENT_TYPE(PROXY_CONFIG_CHANGED)
+
// ------------------------------------------------------------------------
// Proxy Resolver
// ------------------------------------------------------------------------
@@ -433,28 +520,44 @@ EVENT_TYPE(HTTP_TRANSACTION_READ_BODY)
EVENT_TYPE(HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART)
// ------------------------------------------------------------------------
-// SpdyNetworkTransaction
-// ------------------------------------------------------------------------
-
-// Measures the time taken to get a spdy stream.
-EVENT_TYPE(SPDY_TRANSACTION_INIT_CONNECTION)
-
-// Measures the time taken to send the request to the server.
-EVENT_TYPE(SPDY_TRANSACTION_SEND_REQUEST)
-
-// Measures the time to read HTTP response headers from the server.
-EVENT_TYPE(SPDY_TRANSACTION_READ_HEADERS)
-
-// Measures the time to read the entity body from the server.
-EVENT_TYPE(SPDY_TRANSACTION_READ_BODY)
-
-// ------------------------------------------------------------------------
// SpdySession
// ------------------------------------------------------------------------
// The start/end of a SpdySession.
+// {
+// "host": <The host-port string>,
+// "proxy": <The Proxy PAC string>,
+// }
EVENT_TYPE(SPDY_SESSION)
+// This event is sent for a SPDY SYN_STREAM.
+// The following parameters are attached:
+// {
+// "flags": <The control frame flags>,
+// "headers": <The list of header:value pairs>,
+// "id": <The stream id>
+// }
+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.
+// The following parameters are attached:
+// {
+// "flags": <The control frame flags>
+// "headers": <The list of header:value pairs>
+// "id": <The stream id>
+// }
+EVENT_TYPE(SPDY_SESSION_PUSHED_SYN_STREAM)
+
+// This event is sent for a SPDY SYN_REPLY.
+// The following parameters are attached:
+// {
+// "flags": <The control frame flags>,
+// "headers": <The list of header:value pairs>,
+// "id": <The stream id>
+// }
+EVENT_TYPE(SPDY_SESSION_SYN_REPLY)
+
// On sending a SPDY SETTINGS frame.
// The following parameters are attached:
// {
@@ -469,76 +572,129 @@ EVENT_TYPE(SPDY_SESSION_SEND_SETTINGS)
// }
EVENT_TYPE(SPDY_SESSION_RECV_SETTINGS)
+// The receipt of a RST_STREAM
+// The following parameters are attached:
+// {
+// "stream_id": <The stream ID for the window update>
+// "status": <The reason for the RST_STREAM>
+// }
+EVENT_TYPE(SPDY_SESSION_RST_STREAM)
+
+// Sending of a RST_STREAM
+// The following parameters are attached:
+// {
+// "stream_id": <The stream ID for the window update>
+// "status": <The reason for the RST_STREAM>
+// }
+EVENT_TYPE(SPDY_SESSION_SEND_RST_STREAM)
+
// Receipt of a SPDY GOAWAY frame.
// The following parameters are attached:
// {
// "last_accepted_stream_id": <Last stream id accepted by the server, duh>
+// "active_streams": <Number of active streams>
+// "unclaimed_streams": <Number of unclaimed push streams>
// }
EVENT_TYPE(SPDY_SESSION_GOAWAY)
-// This event is sent for a SPDY SYN_STREAM pushed by the server, but no
-// URLRequest has requested it yet.
-// The following parameters are attached:
+// Receipt of a SPDY WINDOW_UPDATE frame (which controls the send window).
// {
-// "flags": <The control frame flags>
-// "headers": <The list of header:value pairs>
-// "id": <The stream id>
+// "stream_id": <The stream ID for the window update>
+// "delta" : <The delta window size>
+// "new_size" : <The new window size (computed)>
// }
-EVENT_TYPE(SPDY_SESSION_PUSHED_SYN_STREAM)
+EVENT_TYPE(SPDY_SESSION_SEND_WINDOW_UPDATE)
+
+// Sending of a SPDY WINDOW_UPDATE frame (which controls the receive window).
+// {
+// "stream_id": <The stream ID for the window update>
+// "delta" : <The delta window size>
+// "new_size" : <The new window size (computed)>
+// }
+EVENT_TYPE(SPDY_SESSION_RECV_WINDOW_UPDATE)
+
+// Sending a data frame
+// {
+// "stream_id": <The stream ID for the window update>
+// "length" : <The size of data sent>
+// "flags" : <Send data flags>
+// }
+EVENT_TYPE(SPDY_SESSION_SEND_DATA)
+
+// Receiving a data frame
+// {
+// "stream_id": <The stream ID for the window update>
+// "length" : <The size of data sent>
+// "flags" : <Send data flags>
+// }
+EVENT_TYPE(SPDY_SESSION_RECV_DATA)
+
+// Logs that a stream is stalled on the send window being closed.
+EVENT_TYPE(SPDY_SESSION_STALLED_ON_SEND_WINDOW)
+
+// Session is closing
+// {
+// "status": <The error status of the closure>
+// }
+EVENT_TYPE(SPDY_SESSION_CLOSE)
+
+// Event when the creation of a stream is stalled because we're at
+// the maximum number of concurrent streams.
+EVENT_TYPE(SPDY_SESSION_STALLED_MAX_STREAMS)
// ------------------------------------------------------------------------
-// SpdyStream
+// SpdySessionPool
// ------------------------------------------------------------------------
-// This event is sent for a SPDY SYN_STREAM.
-// The following parameters are attached:
+// This event indicates the pool is reusing an existing session
// {
-// "flags": <The control frame flags>,
-// "headers": <The list of header:value pairs>,
-// "id": <The stream id>
+// "id": <The session id>,
// }
-EVENT_TYPE(SPDY_STREAM_SYN_STREAM)
+EVENT_TYPE(SPDY_SESSION_POOL_FOUND_EXISTING_SESSION)
-// This event is sent for a SPDY SYN_STREAM pushed by the server, where a
-// URLRequest is already waiting for the stream.
-// The following parameters are attached:
+// This event indicates the pool created a new session
// {
-// "flags": <The control frame flags>
-// "headers": <The list of header:value pairs>
-// "id": <The stream id>
+// "id": <The session id>,
// }
-EVENT_TYPE(SPDY_STREAM_PUSHED_SYN_STREAM)
+EVENT_TYPE(SPDY_SESSION_POOL_CREATED_NEW_SESSION)
-// Measures the time taken to send headers on a stream.
-EVENT_TYPE(SPDY_STREAM_SEND_HEADERS)
-
-// Measures the time taken to send the body (e.g. a POST) on a stream.
-EVENT_TYPE(SPDY_STREAM_SEND_BODY)
+// This event indicates that a SSL socket has been upgraded to a SPDY session.
+// {
+// "id": <The session id>,
+// }
+EVENT_TYPE(SPDY_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET)
-// This event is sent for a SPDY SYN_REPLY.
-// The following parameters are attached:
+// This event indicates that the session has been removed.
// {
-// "flags": <The control frame flags>,
-// "headers": <The list of header:value pairs>,
-// "id": <The stream id>
+// "id": <The session id>,
// }
-EVENT_TYPE(SPDY_STREAM_SYN_REPLY)
+EVENT_TYPE(SPDY_SESSION_POOL_REMOVE_SESSION)
-// Measures the time taken to read headers on a stream.
-EVENT_TYPE(SPDY_STREAM_READ_HEADERS)
+// ------------------------------------------------------------------------
+// SpdyStream
+// ------------------------------------------------------------------------
-// Measures the time taken to read the body on a stream.
-EVENT_TYPE(SPDY_STREAM_READ_BODY)
+// The begin and end of a SPDY STREAM.
+EVENT_TYPE(SPDY_STREAM)
// Logs that a stream attached to a pushed stream.
EVENT_TYPE(SPDY_STREAM_ADOPTED_PUSH_STREAM)
-// The receipt of a RST_STREAM
-// The following parameters are attached:
+// This event indicates that the send window has been updated
// {
-// "status": <The reason for the RST_STREAM>
+// "id": <The stream id>,
+// "delta": <The window size delta>,
+// "new_window": <The new window size>,
// }
-EVENT_TYPE(SPDY_STREAM_RST_STREAM)
+EVENT_TYPE(SPDY_STREAM_SEND_WINDOW_UPDATE)
+
+// This event indicates that the recv window has been updated
+// {
+// "id": <The stream id>,
+// "delta": <The window size delta>,
+// "new_window": <The new window size>,
+// }
+EVENT_TYPE(SPDY_STREAM_RECV_WINDOW_UPDATE)
// ------------------------------------------------------------------------
// HttpStreamParser
@@ -573,6 +729,24 @@ EVENT_TYPE(SOCKET_STREAM_SENT)
EVENT_TYPE(SOCKET_STREAM_RECEIVED)
// ------------------------------------------------------------------------
+// WebSocketJob
+// ------------------------------------------------------------------------
+
+// This event is sent for a WebSocket handshake request.
+// The following parameters are attached:
+// {
+// "headers": <handshake request message>
+// }
+EVENT_TYPE(WEB_SOCKET_SEND_REQUEST_HEADERS)
+
+// This event is sent on receipt of the WebSocket handshake response headers.
+// The following parameters are attached:
+// {
+// "headers": <handshake response message>
+// }
+EVENT_TYPE(WEB_SOCKET_READ_RESPONSE_HEADERS)
+
+// ------------------------------------------------------------------------
// SOCKS5ClientSocket
// ------------------------------------------------------------------------
@@ -599,6 +773,20 @@ EVENT_TYPE(AUTH_PROXY)
EVENT_TYPE(AUTH_SERVER)
// ------------------------------------------------------------------------
+// HTML5 Application Cache
+// ------------------------------------------------------------------------
+
+// This event is emitted whenever a request is satistifed directly from
+// the appache.
+EVENT_TYPE(APPCACHE_DELIVERING_CACHED_RESPONSE)
+
+// This event is emitted whenever the appcache uses a fallback response.
+EVENT_TYPE(APPCACHE_DELIVERING_FALLBACK_RESPONSE)
+
+// This event is emitted whenever the appcache generates an error response.
+EVENT_TYPE(APPCACHE_DELIVERING_ERROR_RESPONSE)
+
+// ------------------------------------------------------------------------
// Global events
// ------------------------------------------------------------------------
// These are events which are not grouped by source id, as they have no
@@ -606,4 +794,4 @@ EVENT_TYPE(AUTH_SERVER)
// This event is emitted whenever NetworkChangeNotifier determines that the
// underlying network has changed.
-EVENT_TYPE(NETWORK_IP_ADDRESSSES_CHANGED)
+EVENT_TYPE(NETWORK_IP_ADDRESSES_CHANGED)
diff --git a/net/base/net_log_source_type_list.h b/net/base/net_log_source_type_list.h
index d416f3f..231ecd2 100644
--- a/net/base/net_log_source_type_list.h
+++ b/net/base/net_log_source_type_list.h
@@ -13,5 +13,7 @@ SOURCE_TYPE(INIT_PROXY_RESOLVER, 3)
SOURCE_TYPE(CONNECT_JOB, 4)
SOURCE_TYPE(SOCKET, 5)
SOURCE_TYPE(SPDY_SESSION, 6)
+SOURCE_TYPE(HOST_RESOLVER_IMPL_REQUEST, 7)
+SOURCE_TYPE(HOST_RESOLVER_IMPL_JOB, 8)
-SOURCE_TYPE(COUNT, 7) // Always keep this as the last entry.
+SOURCE_TYPE(COUNT, 9) // Always keep this as the last entry.
diff --git a/net/base/net_log_unittest.h b/net/base/net_log_unittest.h
index 376ceac..77a9cbd 100644
--- a/net/base/net_log_unittest.h
+++ b/net/base/net_log_unittest.h
@@ -1,12 +1,13 @@
-// 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.
#ifndef NET_BASE_NET_LOG_UNITTEST_H_
#define NET_BASE_NET_LOG_UNITTEST_H_
+#pragma once
#include <cstddef>
-#include <vector>
+
#include "net/base/capturing_net_log.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -105,7 +106,7 @@ inline ::testing::AssertionResult LogContainsEntryWithType(
// Expect that the log contains an event, but don't care about where
-// as long as the index where it is found is greater than min_index.
+// as long as the first index where it is found is at least |min_index|.
// Returns the position where the event was found.
inline size_t ExpectLogContainsSomewhere(
const CapturingNetLog::EntryList& entries,
@@ -124,6 +125,25 @@ inline size_t ExpectLogContainsSomewhere(
return i;
}
+// Expect that the log contains an event, but don't care about where
+// as long as one index where it is found is at least |min_index|.
+// Returns the first such position where the event was found.
+inline size_t ExpectLogContainsSomewhereAfter(
+ const CapturingNetLog::EntryList& entries,
+ size_t min_index,
+ NetLog::EventType expected_event,
+ NetLog::EventPhase expected_phase) {
+ size_t i = min_index;
+ for (; i < entries.size(); ++i) {
+ const CapturingNetLog::Entry& entry = entries[i];
+ if (entry.type == expected_event &&
+ entry.phase == expected_phase)
+ break;
+ }
+ EXPECT_LT(i, entries.size());
+ return i;
+}
+
} // namespace net
#endif // NET_BASE_NET_LOG_UNITTEST_H_
diff --git a/net/base/net_module.h b/net/base/net_module.h
index 6df4bfe..b08a30a 100644
--- a/net/base/net_module.h
+++ b/net/base/net_module.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_NET_MODULE_H__
#define NET_BASE_NET_MODULE_H__
+#pragma once
#include "base/basictypes.h"
#include "base/string_piece.h"
diff --git a/net/base/net_test_constants.h b/net/base/net_test_constants.h
deleted file mode 100644
index 83eb43f..0000000
--- a/net/base/net_test_constants.h
+++ /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.
-
-#ifndef NET_BASE_NET_TEST_CONSTANTS_H_
-#define NET_BASE_NET_TEST_CONSTANTS_H_
-
-namespace net {
-
-// Number of connection attempts for tests.
-const int kDefaultTestConnectionAttempts = 10;
-
-// Connection timeout in milliseconds for tests.
-const int kDefaultTestConnectionTimeout = 1000;
-
-} // namespace net
-
-#endif // NET_BASE_NET_TEST_CONSTANTS_H_
diff --git a/net/base/net_test_suite.h b/net/base/net_test_suite.h
index cc4ed2a..eab3a53 100644
--- a/net/base/net_test_suite.h
+++ b/net/base/net_test_suite.h
@@ -4,13 +4,14 @@
#ifndef NET_BASE_NET_TEST_SUITE_H_
#define NET_BASE_NET_TEST_SUITE_H_
+#pragma once
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/test/test_suite.h"
#include "net/base/mock_host_resolver.h"
-class NetTestSuite : public TestSuite {
+class NetTestSuite : public base::TestSuite {
public:
NetTestSuite(int argc, char** argv) : TestSuite(argc, argv) {
}
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index b0715e3..29c76bb 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <map>
+#include <unicode/regex.h>
#include <unicode/ucnv.h>
#include <unicode/uidna.h>
#include <unicode/ulocdata.h>
@@ -46,18 +47,21 @@
#include "base/path_service.h"
#include "base/singleton.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
+#include "base/string_split.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/sys_string_conversions.h"
#include "base/time.h"
#include "base/utf_offset_string_conversions.h"
#include "base/utf_string_conversions.h"
-#include "grit/net_resources.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_canon.h"
#include "googleurl/src/url_canon_ip.h"
#include "googleurl/src/url_parse.h"
+#include "grit/net_resources.h"
#include "net/base/dns_util.h"
#include "net/base/escape.h"
#include "net/base/net_module.h"
@@ -73,6 +77,8 @@
using base::Time;
+namespace net {
+
namespace {
// what we prepend to get a file URL
@@ -190,19 +196,6 @@ STR GetSpecificHeaderT(const STR& headers, const STR& name) {
return ret;
}
-// TODO(jungshik): We have almost identical hex-decoding code else where.
-// Consider refactoring and moving it somewhere(base?). Bug 1224311
-inline bool IsHexDigit(unsigned char c) {
- return (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') ||
- ('a' <= c && c <= 'f'));
-}
-
-inline unsigned char HexToInt(unsigned char c) {
- DCHECK(IsHexDigit(c));
- static unsigned char kOffset[4] = {0, 0x30u, 0x37u, 0x57u};
- return c - kOffset[(c >> 5) & 3];
-}
-
// Similar to Base64Decode. Decodes a Q-encoded string to a sequence
// of bytes. If input is invalid, return false.
bool QPDecode(const std::string& input, std::string* output) {
@@ -218,7 +211,8 @@ bool QPDecode(const std::string& input, std::string* output) {
}
if (IsHexDigit(static_cast<unsigned char>(*(it + 1))) &&
IsHexDigit(static_cast<unsigned char>(*(it + 2)))) {
- unsigned char ch = HexToInt(*(it + 1)) * 16 + HexToInt(*(it + 2));
+ unsigned char ch = HexDigitToInt(*(it + 1)) * 16 +
+ HexDigitToInt(*(it + 2));
temp.push_back(static_cast<char>(ch));
++it;
++it;
@@ -627,6 +621,13 @@ bool IsIDNComponentSafe(const char16* str,
L"\u3015\u3033\u3164\u321d\u321e\u33ae\u33af\u33c6\u33df\ufe14"
L"\ufe15\ufe3f\ufe5d\ufe5e\ufeff\uff0e\uff06\uff61\uffa0\ufff9]"
L"[\ufffa-\ufffd]]"), status);
+ DCHECK(U_SUCCESS(status));
+ icu::RegexMatcher dangerous_patterns(icu::UnicodeString(
+ // Lone katakana no, so, or n
+ L"[^\\p{Katakana}][\u30ce\u30f3\u30bd][^\\p{Katakana}]"
+ // Repeating Japanese accent characters
+ L"|[\u3099\u309a\u309b\u309c][\u3099\u309a\u309b\u309c]"),
+ 0, status);
#else
icu::UnicodeSet dangerous_characters(icu::UnicodeString(
"[[\\u0020\\u00bc\\u00bd\\u01c3\\u0337\\u0338"
@@ -637,13 +638,26 @@ bool IsIDNComponentSafe(const char16* str,
"\\u3015\\u3033\\u3164\\u321d\\u321e\\u33ae\\u33af\\u33c6\\u33df\\ufe14"
"\\ufe15\\ufe3f\\ufe5d\\ufe5e\\ufeff\\uff0e\\uff06\\uff61\\uffa0\\ufff9]"
"[\\ufffa-\\ufffd]]", -1, US_INV), status);
+ DCHECK(U_SUCCESS(status));
+ icu::RegexMatcher dangerous_patterns(icu::UnicodeString(
+ // Lone katakana no, so, or n
+ "[^\\p{Katakana}][\\u30ce\\u30f3\u30bd][^\\p{Katakana}]"
+ // Repeating Japanese accent characters
+ "|[\\u3099\\u309a\\u309b\\u309c][\\u3099\\u309a\\u309b\\u309c]"),
+ 0, status);
#endif
DCHECK(U_SUCCESS(status));
icu::UnicodeSet component_characters;
- component_characters.addAll(icu::UnicodeString(str, str_len));
+ icu::UnicodeString component_string(str, str_len);
+ component_characters.addAll(component_string);
if (dangerous_characters.containsSome(component_characters))
return false;
+ DCHECK(U_SUCCESS(status));
+ dangerous_patterns.reset(component_string);
+ if (dangerous_patterns.find())
+ return false;
+
// If the language list is empty, the result is completely determined
// by whether a component is a single script or not. This will block
// even "safe" script mixing cases like <Chinese, Latin-ASCII> that are
@@ -742,7 +756,15 @@ void AdjustComponents(int delta, url_parse::Parsed* parsed) {
AdjustComponent(delta, &(parsed->ref));
}
-// Helper for FormatUrl().
+std::wstring FormatUrlInternal(const GURL& url,
+ const std::wstring& languages,
+ FormatUrlTypes format_types,
+ UnescapeRule::Type unescape_rules,
+ url_parse::Parsed* new_parsed,
+ size_t* prefix_end,
+ size_t* offset_for_adjustment);
+
+// Helper for FormatUrl()/FormatUrlInternal().
std::wstring FormatViewSourceUrl(const GURL& url,
const std::wstring& languages,
net::FormatUrlTypes format_types,
@@ -759,8 +781,8 @@ std::wstring FormatViewSourceUrl(const GURL& url,
std::wstring::npos : (*offset_for_adjustment - kViewSourceLengthPlus1);
size_t* temp_offset_ptr = (*offset_for_adjustment < kViewSourceLengthPlus1) ?
NULL : &temp_offset;
- std::wstring result = net::FormatUrl(real_url, languages,
- format_types, unescape_rules, new_parsed, prefix_end, temp_offset_ptr);
+ std::wstring result = FormatUrlInternal(real_url, languages, format_types,
+ unescape_rules, new_parsed, prefix_end, temp_offset_ptr);
result.insert(0, kWideViewSource);
// Adjust position values.
@@ -781,19 +803,6 @@ std::wstring FormatViewSourceUrl(const GURL& url,
return result;
}
-} // namespace
-
-namespace net {
-
-const FormatUrlType kFormatUrlOmitNothing = 0;
-const FormatUrlType kFormatUrlOmitUsernamePassword = 1 << 0;
-const FormatUrlType kFormatUrlOmitHTTP = 1 << 1;
-const FormatUrlType kFormatUrlOmitTrailingSlashOnBareHostname = 1 << 2;
-const FormatUrlType kFormatUrlOmitAll = kFormatUrlOmitUsernamePassword |
- kFormatUrlOmitHTTP | kFormatUrlOmitTrailingSlashOnBareHostname;
-
-std::set<int> explicitly_allowed_ports;
-
// Appends the substring |in_component| inside of the URL |spec| to |output|,
// and the resulting range will be filled into |out_component|. |unescape_rules|
// defines how to clean the URL for human readability. |offset_for_adjustment|
@@ -804,12 +813,248 @@ std::set<int> explicitly_allowed_ports;
// components. Otherwise it points into the component being converted, and is
// adjusted to point to the same logical place in |output|.
// |offset_for_adjustment| may not be NULL.
-static void AppendFormattedComponent(const std::string& spec,
- const url_parse::Component& in_component,
- UnescapeRule::Type unescape_rules,
- std::wstring* output,
- url_parse::Component* out_component,
- size_t* offset_for_adjustment);
+void AppendFormattedComponent(const std::string& spec,
+ const url_parse::Component& in_component,
+ UnescapeRule::Type unescape_rules,
+ std::wstring* output,
+ url_parse::Component* out_component,
+ size_t* offset_for_adjustment) {
+ DCHECK(output);
+ DCHECK(offset_for_adjustment);
+ if (in_component.is_nonempty()) {
+ out_component->begin = static_cast<int>(output->length());
+ size_t offset_past_current_output =
+ ((*offset_for_adjustment == std::wstring::npos) ||
+ (*offset_for_adjustment < output->length())) ?
+ std::wstring::npos : (*offset_for_adjustment - output->length());
+ size_t* offset_into_component =
+ (offset_past_current_output >= static_cast<size_t>(in_component.len)) ?
+ NULL : &offset_past_current_output;
+ if (unescape_rules == UnescapeRule::NONE) {
+ output->append(UTF8ToWideAndAdjustOffset(
+ spec.substr(in_component.begin, in_component.len),
+ offset_into_component));
+ } else {
+ output->append(UTF16ToWideHack(UnescapeAndDecodeUTF8URLComponent(
+ spec.substr(in_component.begin, in_component.len), unescape_rules,
+ offset_into_component)));
+ }
+ out_component->len =
+ static_cast<int>(output->length()) - out_component->begin;
+ if (offset_into_component) {
+ *offset_for_adjustment = (*offset_into_component == std::wstring::npos) ?
+ std::wstring::npos : (out_component->begin + *offset_into_component);
+ } else if (offset_past_current_output != std::wstring::npos) {
+ *offset_for_adjustment += out_component->len - in_component.len;
+ }
+ } else {
+ out_component->reset();
+ }
+}
+
+// TODO(viettrungluu): This is really the old-fashioned version, made internal.
+// I need to really convert |FormatUrl()|.
+std::wstring FormatUrlInternal(const GURL& url,
+ const std::wstring& languages,
+ FormatUrlTypes format_types,
+ UnescapeRule::Type unescape_rules,
+ url_parse::Parsed* new_parsed,
+ size_t* prefix_end,
+ size_t* offset_for_adjustment) {
+ url_parse::Parsed parsed_temp;
+ if (!new_parsed)
+ new_parsed = &parsed_temp;
+ else
+ *new_parsed = url_parse::Parsed();
+ size_t offset_temp = std::wstring::npos;
+ if (!offset_for_adjustment)
+ offset_for_adjustment = &offset_temp;
+
+ std::wstring url_string;
+
+ // Check for empty URLs or 0 available text width.
+ if (url.is_empty()) {
+ if (prefix_end)
+ *prefix_end = 0;
+ *offset_for_adjustment = std::wstring::npos;
+ return url_string;
+ }
+
+ // Special handling for view-source:. Don't use chrome::kViewSourceScheme
+ // because this library shouldn't depend on chrome.
+ const char* const kViewSource = "view-source";
+ // Reject "view-source:view-source:..." to avoid deep recursion.
+ const char* const kViewSourceTwice = "view-source:view-source:";
+ if (url.SchemeIs(kViewSource) &&
+ !StartsWithASCII(url.possibly_invalid_spec(), kViewSourceTwice, false)) {
+ return FormatViewSourceUrl(url, languages, format_types,
+ unescape_rules, new_parsed, prefix_end, offset_for_adjustment);
+ }
+
+ // We handle both valid and invalid URLs (this will give us the spec
+ // regardless of validity).
+ const std::string& spec = url.possibly_invalid_spec();
+ const url_parse::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
+ if (*offset_for_adjustment >= spec.length())
+ *offset_for_adjustment = std::wstring::npos;
+
+ // Copy everything before the username (the scheme and the separators.)
+ // These are ASCII.
+ std::copy(spec.begin(),
+ spec.begin() + parsed.CountCharactersBefore(url_parse::Parsed::USERNAME,
+ true),
+ std::back_inserter(url_string));
+
+ const wchar_t kHTTP[] = L"http://";
+ const char kFTP[] = "ftp.";
+ // URLFixerUpper::FixupURL() treats "ftp.foo.com" as ftp://ftp.foo.com. This
+ // means that if we trim "http://" off a URL whose host starts with "ftp." and
+ // the user inputs this into any field subject to fixup (which is basically
+ // all input fields), the meaning would be changed. (In fact, often the
+ // formatted URL is directly pre-filled into an input field.) For this reason
+ // we avoid stripping "http://" in this case.
+ bool omit_http =
+ (format_types & kFormatUrlOmitHTTP) && (url_string == kHTTP) &&
+ (url.host().compare(0, arraysize(kFTP) - 1, kFTP) != 0);
+
+ new_parsed->scheme = parsed.scheme;
+
+ if ((format_types & kFormatUrlOmitUsernamePassword) != 0) {
+ // Remove the username and password fields. We don't want to display those
+ // to the user since they can be used for attacks,
+ // e.g. "http://google.com:search@evil.ru/"
+ new_parsed->username.reset();
+ new_parsed->password.reset();
+ if ((*offset_for_adjustment != std::wstring::npos) &&
+ (parsed.username.is_nonempty() || parsed.password.is_nonempty())) {
+ if (parsed.username.is_nonempty() && parsed.password.is_nonempty()) {
+ // The seeming off-by-one and off-by-two in these first two lines are to
+ // account for the ':' after the username and '@' after the password.
+ if (*offset_for_adjustment >
+ static_cast<size_t>(parsed.password.end())) {
+ *offset_for_adjustment -=
+ (parsed.username.len + parsed.password.len + 2);
+ } else if (*offset_for_adjustment >
+ static_cast<size_t>(parsed.username.begin)) {
+ *offset_for_adjustment = std::wstring::npos;
+ }
+ } else {
+ const url_parse::Component* nonempty_component =
+ parsed.username.is_nonempty() ? &parsed.username : &parsed.password;
+ // The seeming off-by-one in these first two lines is to account for the
+ // '@' after the username/password.
+ if (*offset_for_adjustment >
+ static_cast<size_t>(nonempty_component->end())) {
+ *offset_for_adjustment -= (nonempty_component->len + 1);
+ } else if (*offset_for_adjustment >
+ static_cast<size_t>(nonempty_component->begin)) {
+ *offset_for_adjustment = std::wstring::npos;
+ }
+ }
+ }
+ } else {
+ AppendFormattedComponent(spec, parsed.username, unescape_rules, &url_string,
+ &new_parsed->username, offset_for_adjustment);
+ if (parsed.password.is_valid())
+ url_string.push_back(':');
+ AppendFormattedComponent(spec, parsed.password, unescape_rules, &url_string,
+ &new_parsed->password, offset_for_adjustment);
+ if (parsed.username.is_valid() || parsed.password.is_valid())
+ url_string.push_back('@');
+ }
+ if (prefix_end)
+ *prefix_end = static_cast<size_t>(url_string.length());
+
+ AppendFormattedHost(url, languages, &url_string, new_parsed,
+ offset_for_adjustment);
+
+ // Port.
+ if (parsed.port.is_nonempty()) {
+ url_string.push_back(':');
+ new_parsed->port.begin = url_string.length();
+ std::copy(spec.begin() + parsed.port.begin,
+ spec.begin() + parsed.port.end(), std::back_inserter(url_string));
+ new_parsed->port.len = url_string.length() - new_parsed->port.begin;
+ } else {
+ new_parsed->port.reset();
+ }
+
+ // Path and query both get the same general unescape & convert treatment.
+ if (!(format_types & kFormatUrlOmitTrailingSlashOnBareHostname) ||
+ !CanStripTrailingSlash(url)) {
+ AppendFormattedComponent(spec, parsed.path, unescape_rules, &url_string,
+ &new_parsed->path, offset_for_adjustment);
+ }
+ if (parsed.query.is_valid())
+ url_string.push_back('?');
+ AppendFormattedComponent(spec, parsed.query, unescape_rules, &url_string,
+ &new_parsed->query, offset_for_adjustment);
+
+ // Reference is stored in valid, unescaped UTF-8, so we can just convert.
+ if (parsed.ref.is_valid()) {
+ url_string.push_back('#');
+ new_parsed->ref.begin = url_string.length();
+ size_t offset_past_current_output =
+ ((*offset_for_adjustment == std::wstring::npos) ||
+ (*offset_for_adjustment < url_string.length())) ?
+ std::wstring::npos : (*offset_for_adjustment - url_string.length());
+ size_t* offset_into_ref =
+ (offset_past_current_output >= static_cast<size_t>(parsed.ref.len)) ?
+ NULL : &offset_past_current_output;
+ if (parsed.ref.len > 0) {
+ url_string.append(UTF8ToWideAndAdjustOffset(spec.substr(parsed.ref.begin,
+ parsed.ref.len),
+ offset_into_ref));
+ }
+ new_parsed->ref.len = url_string.length() - new_parsed->ref.begin;
+ if (offset_into_ref) {
+ *offset_for_adjustment = (*offset_into_ref == std::wstring::npos) ?
+ std::wstring::npos : (new_parsed->ref.begin + *offset_into_ref);
+ } else if (offset_past_current_output != std::wstring::npos) {
+ // We clamped the offset near the beginning of this function to ensure it
+ // was within the input URL. If we reach here, the input was something
+ // invalid and non-parseable such that the offset was past any component
+ // we could figure out. In this case it won't be represented in the
+ // output string, so reset it.
+ *offset_for_adjustment = std::wstring::npos;
+ }
+ }
+
+ // If we need to strip out http do it after the fact. This way we don't need
+ // to worry about how offset_for_adjustment is interpreted.
+ const size_t kHTTPSize = arraysize(kHTTP) - 1;
+ if (omit_http && !url_string.compare(0, kHTTPSize, kHTTP)) {
+ url_string = url_string.substr(kHTTPSize);
+ if (*offset_for_adjustment != std::wstring::npos) {
+ if (*offset_for_adjustment < kHTTPSize)
+ *offset_for_adjustment = std::wstring::npos;
+ else
+ *offset_for_adjustment -= kHTTPSize;
+ }
+ if (prefix_end)
+ *prefix_end -= kHTTPSize;
+
+ // Adjust new_parsed.
+ DCHECK(new_parsed->scheme.is_valid());
+ int delta = -(new_parsed->scheme.len + 3); // +3 for ://.
+ new_parsed->scheme.reset();
+ AdjustComponents(delta, new_parsed);
+ }
+
+ return url_string;
+}
+
+} // namespace
+
+const FormatUrlType kFormatUrlOmitNothing = 0;
+const FormatUrlType kFormatUrlOmitUsernamePassword = 1 << 0;
+const FormatUrlType kFormatUrlOmitHTTP = 1 << 1;
+const FormatUrlType kFormatUrlOmitTrailingSlashOnBareHostname = 1 << 2;
+const FormatUrlType kFormatUrlOmitAll = kFormatUrlOmitUsernamePassword |
+ kFormatUrlOmitHTTP | kFormatUrlOmitTrailingSlashOnBareHostname;
+
+// TODO(viettrungluu): We don't want non-POD globals; change this.
+std::set<int> explicitly_allowed_ports;
GURL FilePathToFileURL(const FilePath& path) {
// Produce a URL like "file:///C:/foo" for a regular file, or
@@ -1051,7 +1296,8 @@ std::string GetDirectoryListingEntry(const string16& name,
}
base::JsonDoubleQuote(
- WideToUTF16Hack(FormatBytes(size, GetByteDisplayUnits(size), true)), true,
+ FormatBytes(size, GetByteDisplayUnits(size), true),
+ true,
&result);
result.append(",");
@@ -1068,8 +1314,8 @@ std::string GetDirectoryListingEntry(const string16& name,
return result;
}
-std::wstring StripWWW(const std::wstring& text) {
- const std::wstring www(L"www.");
+string16 StripWWW(const string16& text) {
+ const string16 www(ASCIIToUTF16("www."));
return (text.compare(0, www.length(), www) == 0) ?
text.substr(www.length()) : text;
}
@@ -1270,14 +1516,15 @@ bool ParseHostAndPort(const std::string& host_and_port,
std::string GetHostAndPort(const GURL& url) {
// For IPv6 literals, GURL::host() already includes the brackets so it is
// safe to just append a colon.
- return StringPrintf("%s:%d", url.host().c_str(), url.EffectiveIntPort());
+ return base::StringPrintf("%s:%d", url.host().c_str(),
+ url.EffectiveIntPort());
}
std::string GetHostAndOptionalPort(const GURL& url) {
// For IPv6 literals, GURL::host() already includes the brackets
// so it is safe to just append a colon.
if (url.has_port())
- return StringPrintf("%s:%s", url.host().c_str(), url.port().c_str());
+ return base::StringPrintf("%s:%s", url.host().c_str(), url.port().c_str());
return url.host();
}
@@ -1308,10 +1555,10 @@ std::string NetAddressToStringWithPort(const struct addrinfo* net_address) {
if (ip_address_string.find(':') != std::string::npos) {
// Surround with square brackets to avoid ambiguity.
- return StringPrintf("[%s]:%d", ip_address_string.c_str(), port);
+ return base::StringPrintf("[%s]:%d", ip_address_string.c_str(), port);
}
- return StringPrintf("%s:%d", ip_address_string.c_str(), port);
+ return base::StringPrintf("%s:%d", ip_address_string.c_str(), port);
}
std::string GetHostName() {
@@ -1330,14 +1577,12 @@ std::string GetHostName() {
}
void GetIdentityFromURL(const GURL& url,
- std::wstring* username,
- std::wstring* password) {
+ string16* username,
+ string16* password) {
UnescapeRule::Type flags =
UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS;
- *username = UTF16ToWideHack(UnescapeAndDecodeUTF8URLComponent(url.username(),
- flags, NULL));
- *password = UTF16ToWideHack(UnescapeAndDecodeUTF8URLComponent(url.password(),
- flags, NULL));
+ *username = UnescapeAndDecodeUTF8URLComponent(url.username(), flags, NULL);
+ *password = UnescapeAndDecodeUTF8URLComponent(url.password(), flags, NULL);
}
std::string GetHostOrSpecFromURL(const GURL& url) {
@@ -1388,234 +1633,18 @@ void AppendFormattedHost(const GURL& url,
}
}
-/* static */
-void AppendFormattedComponent(const std::string& spec,
- const url_parse::Component& in_component,
- UnescapeRule::Type unescape_rules,
- std::wstring* output,
- url_parse::Component* out_component,
- size_t* offset_for_adjustment) {
- DCHECK(output);
- DCHECK(offset_for_adjustment);
- if (in_component.is_nonempty()) {
- out_component->begin = static_cast<int>(output->length());
- size_t offset_past_current_output =
- ((*offset_for_adjustment == std::wstring::npos) ||
- (*offset_for_adjustment < output->length())) ?
- std::wstring::npos : (*offset_for_adjustment - output->length());
- size_t* offset_into_component =
- (offset_past_current_output >= static_cast<size_t>(in_component.len)) ?
- NULL : &offset_past_current_output;
- if (unescape_rules == UnescapeRule::NONE) {
- output->append(UTF8ToWideAndAdjustOffset(
- spec.substr(in_component.begin, in_component.len),
- offset_into_component));
- } else {
- output->append(UTF16ToWideHack(UnescapeAndDecodeUTF8URLComponent(
- spec.substr(in_component.begin, in_component.len), unescape_rules,
- offset_into_component)));
- }
- out_component->len =
- static_cast<int>(output->length()) - out_component->begin;
- if (offset_into_component) {
- *offset_for_adjustment = (*offset_into_component == std::wstring::npos) ?
- std::wstring::npos : (out_component->begin + *offset_into_component);
- } else if (offset_past_current_output != std::wstring::npos) {
- *offset_for_adjustment += out_component->len - in_component.len;
- }
- } else {
- out_component->reset();
- }
-}
-
-std::wstring FormatUrl(const GURL& url,
- const std::wstring& languages,
- FormatUrlTypes format_types,
- UnescapeRule::Type unescape_rules,
- url_parse::Parsed* new_parsed,
- size_t* prefix_end,
- size_t* offset_for_adjustment) {
- url_parse::Parsed parsed_temp;
- if (!new_parsed)
- new_parsed = &parsed_temp;
- else
- *new_parsed = url_parse::Parsed();
- size_t offset_temp = std::wstring::npos;
- if (!offset_for_adjustment)
- offset_for_adjustment = &offset_temp;
-
- std::wstring url_string;
-
- // Check for empty URLs or 0 available text width.
- if (url.is_empty()) {
- if (prefix_end)
- *prefix_end = 0;
- *offset_for_adjustment = std::wstring::npos;
- return url_string;
- }
-
- // Special handling for view-source:. Don't use chrome::kViewSourceScheme
- // because this library shouldn't depend on chrome.
- const char* const kViewSource = "view-source";
- // Reject "view-source:view-source:..." to avoid deep recursion.
- const char* const kViewSourceTwice = "view-source:view-source:";
- if (url.SchemeIs(kViewSource) &&
- !StartsWithASCII(url.possibly_invalid_spec(), kViewSourceTwice, false)) {
- return FormatViewSourceUrl(url, languages, format_types,
- unescape_rules, new_parsed, prefix_end, offset_for_adjustment);
- }
-
- // We handle both valid and invalid URLs (this will give us the spec
- // regardless of validity).
- const std::string& spec = url.possibly_invalid_spec();
- const url_parse::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
- if (*offset_for_adjustment >= spec.length())
- *offset_for_adjustment = std::wstring::npos;
-
- // Copy everything before the username (the scheme and the separators.)
- // These are ASCII.
- std::copy(spec.begin(),
- spec.begin() + parsed.CountCharactersBefore(url_parse::Parsed::USERNAME,
- true),
- std::back_inserter(url_string));
-
- const wchar_t kHTTP[] = L"http://";
- const char kFTP[] = "ftp.";
- // URLFixerUpper::FixupURL() treats "ftp.foo.com" as ftp://ftp.foo.com. This
- // means that if we trim "http://" off a URL whose host starts with "ftp." and
- // the user inputs this into any field subject to fixup (which is basically
- // all input fields), the meaning would be changed. (In fact, often the
- // formatted URL is directly pre-filled into an input field.) For this reason
- // we avoid stripping "http://" in this case.
- bool omit_http =
- (format_types & kFormatUrlOmitHTTP) && (url_string == kHTTP) &&
- (url.host().compare(0, arraysize(kFTP) - 1, kFTP) != 0);
-
- new_parsed->scheme = parsed.scheme;
-
- if ((format_types & kFormatUrlOmitUsernamePassword) != 0) {
- // Remove the username and password fields. We don't want to display those
- // to the user since they can be used for attacks,
- // e.g. "http://google.com:search@evil.ru/"
- new_parsed->username.reset();
- new_parsed->password.reset();
- if ((*offset_for_adjustment != std::wstring::npos) &&
- (parsed.username.is_nonempty() || parsed.password.is_nonempty())) {
- if (parsed.username.is_nonempty() && parsed.password.is_nonempty()) {
- // The seeming off-by-one and off-by-two in these first two lines are to
- // account for the ':' after the username and '@' after the password.
- if (*offset_for_adjustment >
- static_cast<size_t>(parsed.password.end())) {
- *offset_for_adjustment -=
- (parsed.username.len + parsed.password.len + 2);
- } else if (*offset_for_adjustment >
- static_cast<size_t>(parsed.username.begin)) {
- *offset_for_adjustment = std::wstring::npos;
- }
- } else {
- const url_parse::Component* nonempty_component =
- parsed.username.is_nonempty() ? &parsed.username : &parsed.password;
- // The seeming off-by-one in these first two lines is to account for the
- // '@' after the username/password.
- if (*offset_for_adjustment >
- static_cast<size_t>(nonempty_component->end())) {
- *offset_for_adjustment -= (nonempty_component->len + 1);
- } else if (*offset_for_adjustment >
- static_cast<size_t>(nonempty_component->begin)) {
- *offset_for_adjustment = std::wstring::npos;
- }
- }
- }
- } else {
- AppendFormattedComponent(spec, parsed.username, unescape_rules, &url_string,
- &new_parsed->username, offset_for_adjustment);
- if (parsed.password.is_valid())
- url_string.push_back(':');
- AppendFormattedComponent(spec, parsed.password, unescape_rules, &url_string,
- &new_parsed->password, offset_for_adjustment);
- if (parsed.username.is_valid() || parsed.password.is_valid())
- url_string.push_back('@');
- }
- if (prefix_end)
- *prefix_end = static_cast<size_t>(url_string.length());
-
- AppendFormattedHost(url, languages, &url_string, new_parsed,
- offset_for_adjustment);
-
- // Port.
- if (parsed.port.is_nonempty()) {
- url_string.push_back(':');
- new_parsed->port.begin = url_string.length();
- std::copy(spec.begin() + parsed.port.begin,
- spec.begin() + parsed.port.end(), std::back_inserter(url_string));
- new_parsed->port.len = url_string.length() - new_parsed->port.begin;
- } else {
- new_parsed->port.reset();
- }
-
- // Path and query both get the same general unescape & convert treatment.
- if (!(format_types & kFormatUrlOmitTrailingSlashOnBareHostname) ||
- !CanStripTrailingSlash(url)) {
- AppendFormattedComponent(spec, parsed.path, unescape_rules, &url_string,
- &new_parsed->path, offset_for_adjustment);
- }
- if (parsed.query.is_valid())
- url_string.push_back('?');
- AppendFormattedComponent(spec, parsed.query, unescape_rules, &url_string,
- &new_parsed->query, offset_for_adjustment);
-
- // Reference is stored in valid, unescaped UTF-8, so we can just convert.
- if (parsed.ref.is_valid()) {
- url_string.push_back('#');
- new_parsed->ref.begin = url_string.length();
- size_t offset_past_current_output =
- ((*offset_for_adjustment == std::wstring::npos) ||
- (*offset_for_adjustment < url_string.length())) ?
- std::wstring::npos : (*offset_for_adjustment - url_string.length());
- size_t* offset_into_ref =
- (offset_past_current_output >= static_cast<size_t>(parsed.ref.len)) ?
- NULL : &offset_past_current_output;
- if (parsed.ref.len > 0) {
- url_string.append(UTF8ToWideAndAdjustOffset(spec.substr(parsed.ref.begin,
- parsed.ref.len),
- offset_into_ref));
- }
- new_parsed->ref.len = url_string.length() - new_parsed->ref.begin;
- if (offset_into_ref) {
- *offset_for_adjustment = (*offset_into_ref == std::wstring::npos) ?
- std::wstring::npos : (new_parsed->ref.begin + *offset_into_ref);
- } else if (offset_past_current_output != std::wstring::npos) {
- // We clamped the offset near the beginning of this function to ensure it
- // was within the input URL. If we reach here, the input was something
- // invalid and non-parseable such that the offset was past any component
- // we could figure out. In this case it won't be represented in the
- // output string, so reset it.
- *offset_for_adjustment = std::wstring::npos;
- }
- }
-
- // If we need to strip out http do it after the fact. This way we don't need
- // to worry about how offset_for_adjustment is interpreted.
- const size_t kHTTPSize = arraysize(kHTTP) - 1;
- if (omit_http && !url_string.compare(0, kHTTPSize, kHTTP)) {
- url_string = url_string.substr(kHTTPSize);
- if (*offset_for_adjustment != std::wstring::npos) {
- if (*offset_for_adjustment < kHTTPSize)
- *offset_for_adjustment = std::wstring::npos;
- else
- *offset_for_adjustment -= kHTTPSize;
- }
- if (prefix_end)
- *prefix_end -= kHTTPSize;
-
- // Adjust new_parsed.
- DCHECK(new_parsed->scheme.is_valid());
- int delta = -(new_parsed->scheme.len + 3); // +3 for ://.
- new_parsed->scheme.reset();
- AdjustComponents(delta, new_parsed);
- }
-
- return url_string;
+// TODO(viettrungluu): convert the wstring |FormatUrlInternal()|.
+string16 FormatUrl(const GURL& url,
+ const std::string& languages,
+ FormatUrlTypes format_types,
+ UnescapeRule::Type unescape_rules,
+ url_parse::Parsed* new_parsed,
+ size_t* prefix_end,
+ size_t* offset_for_adjustment) {
+ return WideToUTF16Hack(
+ FormatUrlInternal(url, ASCIIToWide(languages), format_types,
+ unescape_rules, new_parsed, prefix_end,
+ offset_for_adjustment));
}
bool CanStripTrailingSlash(const GURL& url) {
@@ -1636,7 +1665,7 @@ GURL SimplifyUrlForRequest(const GURL& url) {
// Specifies a comma separated list of port numbers that should be accepted
// despite bans. If the string is invalid no allowed ports are stored.
-void SetExplicitlyAllowedPorts(const std::wstring& allowed_ports) {
+void SetExplicitlyAllowedPorts(const std::string& allowed_ports) {
if (allowed_ports.empty())
return;
@@ -1644,7 +1673,7 @@ void SetExplicitlyAllowedPorts(const std::wstring& allowed_ports) {
size_t last = 0;
size_t size = allowed_ports.size();
// The comma delimiter.
- const std::wstring::value_type kComma = L',';
+ const std::string::value_type kComma = ',';
// Overflow is still possible for evil user inputs.
for (size_t i = 0; i <= size; ++i) {
@@ -1654,9 +1683,11 @@ void SetExplicitlyAllowedPorts(const std::wstring& allowed_ports) {
return;
if (i == size || allowed_ports[i] == kComma) {
size_t length = i - last;
- if (length > 0)
- ports.insert(StringToInt(WideToASCII(
- allowed_ports.substr(last, length))));
+ if (length > 0) {
+ int port;
+ base::StringToInt(allowed_ports.substr(last, length), &port);
+ ports.insert(port);
+ }
last = i + 1;
}
}
@@ -1792,6 +1823,48 @@ bool IPv6Supported() {
#endif // defined(various platforms)
}
+bool HaveOnlyLoopbackAddresses() {
+#if defined(OS_POSIX)
+ struct ifaddrs* interface_addr = NULL;
+ int rv = getifaddrs(&interface_addr);
+ if (rv != 0) {
+ DLOG(INFO) << "getifaddrs() failed with errno = " << errno;
+ return false;
+ }
+
+ bool result = true;
+ for (struct ifaddrs* interface = interface_addr;
+ interface != NULL;
+ interface = interface->ifa_next) {
+ if (!(IFF_UP & interface->ifa_flags))
+ continue;
+ if (IFF_LOOPBACK & interface->ifa_flags)
+ continue;
+ const struct sockaddr* addr = interface->ifa_addr;
+ if (!addr)
+ continue;
+ if (addr->sa_family == AF_INET6) {
+ // Safe cast since this is AF_INET6.
+ const struct sockaddr_in6* addr_in6 =
+ reinterpret_cast<const struct sockaddr_in6*>(addr);
+ const struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
+ if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr))
+ continue;
+ }
+ if (addr->sa_family != AF_INET6 && addr->sa_family != AF_INET)
+ continue;
+
+ result = false;
+ break;
+ }
+ freeifaddrs(interface_addr);
+ return result;
+#else
+ NOTIMPLEMENTED();
+ return false;
+#endif // defined(various platforms)
+}
+
bool ParseIPLiteralToNumber(const std::string& ip_literal,
IPAddressNumber* ip_number) {
// |ip_literal| could be either a IPv4 or an IPv6 literal. If it contains
@@ -1850,7 +1923,7 @@ bool ParseCIDRBlock(const std::string& cidr_literal,
// Parse the prefix length.
int number_of_bits = -1;
- if (!StringToInt(parts[1], &number_of_bits))
+ if (!base::StringToInt(parts[1], &number_of_bits))
return false;
// Make sure the prefix length is in a valid range.
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 5633c11..f5a6151 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_NET_UTIL_H_
#define NET_BASE_NET_UTIL_H_
+#pragma once
#include "build/build_config.h"
@@ -105,8 +106,8 @@ std::string GetHostName();
// Extracts the unescaped username/password from |url|, saving the results
// into |*username| and |*password|.
void GetIdentityFromURL(const GURL& url,
- std::wstring* username,
- std::wstring* password);
+ string16* username,
+ string16* password);
// Returns either the host from |url|, or, if the host is empty, the full spec.
std::string GetHostOrSpecFromURL(const GURL& url);
@@ -232,7 +233,7 @@ std::string GetDirectoryListingEntry(const string16& name,
// If text starts with "www." it is removed, otherwise text is returned
// unmodified.
-std::wstring StripWWW(const std::wstring& text);
+string16 StripWWW(const string16& text);
// Gets the filename from the raw Content-Disposition header (as read from the
// network). Otherwise uses the last path component name or hostname from
@@ -293,20 +294,20 @@ void AppendFormattedHost(const GURL& url,
// 8. If the offset cannot be successfully adjusted (e.g. because it points
// into the middle of a component that was entirely removed, past the end of the
// string, or into the middle of an encoding sequence), it will be set to
-// std::wstring::npos.
-std::wstring FormatUrl(const GURL& url,
- const std::wstring& languages,
- FormatUrlTypes format_types,
- UnescapeRule::Type unescape_rules,
- url_parse::Parsed* new_parsed,
- size_t* prefix_end,
- size_t* offset_for_adjustment);
+// string16::npos.
+string16 FormatUrl(const GURL& url,
+ const std::string& languages,
+ FormatUrlTypes format_types,
+ UnescapeRule::Type unescape_rules,
+ url_parse::Parsed* new_parsed,
+ size_t* prefix_end,
+ size_t* offset_for_adjustment);
// This is a convenience function for FormatUrl() with
// format_types = kFormatUrlOmitAll and unescape = SPACES. This is the typical
// set of flags for "URLs to display to the user". You should be cautious about
// using this for URLs which will be parsed or sent to other applications.
-inline std::wstring FormatUrl(const GURL& url, const std::wstring& languages) {
+inline string16 FormatUrl(const GURL& url, const std::string& languages) {
return FormatUrl(url, languages, kFormatUrlOmitAll, UnescapeRule::SPACES,
NULL, NULL, NULL);
}
@@ -320,13 +321,17 @@ bool CanStripTrailingSlash(const GURL& url);
// - reference section
GURL SimplifyUrlForRequest(const GURL& url);
-void SetExplicitlyAllowedPorts(const std::wstring& allowed_ports);
+void SetExplicitlyAllowedPorts(const std::string& allowed_ports);
// 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.
bool IPv6Supported();
+// Returns true if it can determine that only loopback addresses are configured.
+// i.e. if only 127.0.0.1 and ::1 are routable.
+bool HaveOnlyLoopbackAddresses();
+
// IPAddressNumber is used to represent an IP address's numeric value as an
// array of bytes, from most significant to least significant. This is the
// network byte ordering.
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index 461b6d3..ad7ccad 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -6,10 +6,12 @@
#include "base/file_path.h"
#include "base/format_macros.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "net/base/sys_addrinfo.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -128,6 +130,12 @@ const IDNTestCase idn_cases[] = {
false, false, false, false, false,
false, false, false, true, false,
}},
+ {"xn--3ck7a7g.jp", L"\u30ce\u30f3\u30bd.jp",
+ {true, false, false, true, false,
+ false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, false, true, false,
+ }},
// Katakana + Latin (Japanese)
// TODO(jungshik): Change 'false' in the first element to 'true'
// after upgrading to ICU 4.2.1 to use new uspoof_* APIs instead
@@ -138,6 +146,12 @@ const IDNTestCase idn_cases[] = {
false, false, false, false, false,
false, false, false, true, false,
}},
+ {"xn--3bkxe.jp", L"\x30c8\x309a.jp",
+ {false, false, false, true, false,
+ false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, false, true, false,
+ }},
// Hangul (Korean)
{"www.xn--or3b17p6jjc.kr", L"www.\xc804\xc790\xc815\xbd80.kr",
{true, false, false, false, true,
@@ -322,7 +336,19 @@ const IDNTestCase idn_cases[] = {
false, false, false, false, false,
false, false, false, false, false,
false, false, false, false, false,
- }},
+ }},
+ {"google.xn--com-oh4ba.evil.jp", L"google.com\x309a\x309a.evil.jp",
+ {false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, false, false, false,
+ }},
+ {"google.xn--comevil-v04f.jp", L"google.com\x30ce" L"evil.jp",
+ {false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, false, false, false,
+ }},
#if 0
// These two cases are special. We need a separate test.
// U+3000 and U+3002 are normalized to ASCII space and dot.
@@ -363,10 +389,10 @@ struct SuggestedFilenameCase {
struct UrlTestData {
const char* description;
const char* input;
- const std::wstring languages;
+ const char* languages;
net::FormatUrlTypes format_types;
UnescapeRule::Type escape_rules;
- const std::wstring output;
+ const wchar_t* output; // Use |wchar_t| to handle Unicode constants easily.
size_t prefix_len;
};
@@ -436,7 +462,7 @@ std::string DumpIPNumber(const net::IPAddressNumber& v) {
for (size_t i = 0; i < v.size(); ++i) {
if (i != 0)
out.append(",");
- out.append(IntToString(static_cast<int>(v[i])));
+ out.append(base::IntToString(static_cast<int>(v[i])));
}
return out;
}
@@ -551,54 +577,55 @@ TEST(NetUtilTest, FileURLConversion) {
TEST(NetUtilTest, GetIdentityFromURL) {
struct {
const char* input_url;
- const wchar_t* expected_username;
- const wchar_t* expected_password;
+ const char* expected_username;
+ const char* expected_password;
} tests[] = {
{
"http://username:password@google.com",
- L"username",
- L"password",
+ "username",
+ "password",
},
{ // Test for http://crbug.com/19200
"http://username:p@ssword@google.com",
- L"username",
- L"p@ssword",
+ "username",
+ "p@ssword",
},
{ // Special URL characters should be unescaped.
"http://username:p%3fa%26s%2fs%23@google.com",
- L"username",
- L"p?a&s/s#",
+ "username",
+ "p?a&s/s#",
},
{ // Username contains %20.
"http://use rname:password@google.com",
- L"use rname",
- L"password",
+ "use rname",
+ "password",
},
{ // Keep %00 as is.
"http://use%00rname:password@google.com",
- L"use%00rname",
- L"password",
+ "use%00rname",
+ "password",
},
{ // Use a '+' in the username.
"http://use+rname:password@google.com",
- L"use+rname",
- L"password",
+ "use+rname",
+ "password",
},
{ // Use a '&' in the password.
"http://username:p&ssword@google.com",
- L"username",
- L"p&ssword",
+ "username",
+ "p&ssword",
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, tests[i].input_url));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ tests[i].input_url));
GURL url(tests[i].input_url);
- std::wstring username, password;
+ string16 username, password;
net::GetIdentityFromURL(url, &username, &password);
- EXPECT_EQ(tests[i].expected_username, username);
- EXPECT_EQ(tests[i].expected_password, password);
+ EXPECT_EQ(ASCIIToUTF16(tests[i].expected_username), username);
+ EXPECT_EQ(ASCIIToUTF16(tests[i].expected_password), password);
}
}
@@ -610,12 +637,12 @@ TEST(NetUtilTest, GetIdentityFromURL_UTF8) {
EXPECT_EQ("%E4%BD%A0%E5%A5%BD", url.password());
// Extract the unescaped identity.
- std::wstring username, password;
+ string16 username, password;
net::GetIdentityFromURL(url, &username, &password);
// Verify that it was decoded as UTF8.
- EXPECT_EQ(L"foo", username);
- EXPECT_EQ(L"\x4f60\x597d", password);
+ EXPECT_EQ(ASCIIToUTF16("foo"), username);
+ EXPECT_EQ(WideToUTF16(L"\x4f60\x597d"), password);
}
// Just a bunch of fake headers.
@@ -831,17 +858,17 @@ TEST(NetUtilTest, IDNToUnicodeAdjustOffset) {
{2, 2},
{4, 4},
{5, 5},
- {6, std::wstring::npos},
- {16, std::wstring::npos},
+ {6, string16::npos},
+ {16, string16::npos},
{17, 7},
{18, 8},
- {19, std::wstring::npos},
- {25, std::wstring::npos},
+ {19, string16::npos},
+ {25, string16::npos},
{34, 12},
{35, 13},
{38, 16},
- {39, std::wstring::npos},
- {std::wstring::npos, std::wstring::npos},
+ {39, string16::npos},
+ {string16::npos, string16::npos},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(adjust_cases); ++i) {
size_t offset = adjust_cases[i].input_offset;
@@ -887,10 +914,10 @@ TEST(NetUtilTest, CompliantHost) {
}
TEST(NetUtilTest, StripWWW) {
- EXPECT_EQ(L"", net::StripWWW(L""));
- EXPECT_EQ(L"", net::StripWWW(L"www."));
- EXPECT_EQ(L"blah", net::StripWWW(L"www.blah"));
- EXPECT_EQ(L"blah", net::StripWWW(L"blah"));
+ EXPECT_EQ(string16(), net::StripWWW(string16()));
+ EXPECT_EQ(string16(), net::StripWWW(ASCIIToUTF16("www.")));
+ EXPECT_EQ(ASCIIToUTF16("blah"), net::StripWWW(ASCIIToUTF16("www.blah")));
+ EXPECT_EQ(ASCIIToUTF16("blah"), net::StripWWW(ASCIIToUTF16("blah")));
}
TEST(NetUtilTest, GetSuggestedFilename) {
@@ -1316,76 +1343,76 @@ TEST(NetUtilTest, GetHostName) {
TEST(NetUtilTest, FormatUrl) {
net::FormatUrlTypes default_format_type = net::kFormatUrlOmitUsernamePassword;
const UrlTestData tests[] = {
- {"Empty URL", "", L"", default_format_type, UnescapeRule::NORMAL, L"", 0},
+ {"Empty URL", "", "", default_format_type, UnescapeRule::NORMAL, L"", 0},
{"Simple URL",
- "http://www.google.com/", L"", default_format_type, UnescapeRule::NORMAL,
+ "http://www.google.com/", "", default_format_type, UnescapeRule::NORMAL,
L"http://www.google.com/", 7},
{"With a port number and a reference",
- "http://www.google.com:8080/#\xE3\x82\xB0", L"", default_format_type,
+ "http://www.google.com:8080/#\xE3\x82\xB0", "", default_format_type,
UnescapeRule::NORMAL,
L"http://www.google.com:8080/#\x30B0", 7},
// -------- IDN tests --------
{"Japanese IDN with ja",
- "http://xn--l8jvb1ey91xtjb.jp", L"ja", default_format_type,
+ "http://xn--l8jvb1ey91xtjb.jp", "ja", default_format_type,
UnescapeRule::NORMAL, L"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
{"Japanese IDN with en",
- "http://xn--l8jvb1ey91xtjb.jp", L"en", default_format_type,
+ "http://xn--l8jvb1ey91xtjb.jp", "en", default_format_type,
UnescapeRule::NORMAL, L"http://xn--l8jvb1ey91xtjb.jp/", 7},
{"Japanese IDN without any languages",
- "http://xn--l8jvb1ey91xtjb.jp", L"", default_format_type,
+ "http://xn--l8jvb1ey91xtjb.jp", "", default_format_type,
UnescapeRule::NORMAL,
// Single script is safe for empty languages.
L"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
{"mailto: with Japanese IDN",
- "mailto:foo@xn--l8jvb1ey91xtjb.jp", L"ja", default_format_type,
+ "mailto:foo@xn--l8jvb1ey91xtjb.jp", "ja", default_format_type,
UnescapeRule::NORMAL,
// GURL doesn't assume an email address's domain part as a host name.
L"mailto:foo@xn--l8jvb1ey91xtjb.jp", 7},
{"file: with Japanese IDN",
- "file://xn--l8jvb1ey91xtjb.jp/config.sys", L"ja", default_format_type,
+ "file://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type,
UnescapeRule::NORMAL,
L"file://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 7},
{"ftp: with Japanese IDN",
- "ftp://xn--l8jvb1ey91xtjb.jp/config.sys", L"ja", default_format_type,
+ "ftp://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type,
UnescapeRule::NORMAL,
L"ftp://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 6},
// -------- omit_username_password flag tests --------
{"With username and password, omit_username_password=false",
- "http://user:passwd@example.com/foo", L"",
+ "http://user:passwd@example.com/foo", "",
net::kFormatUrlOmitNothing, UnescapeRule::NORMAL,
L"http://user:passwd@example.com/foo", 19},
{"With username and password, omit_username_password=true",
- "http://user:passwd@example.com/foo", L"", default_format_type,
+ "http://user:passwd@example.com/foo", "", default_format_type,
UnescapeRule::NORMAL, L"http://example.com/foo", 7},
{"With username and no password",
- "http://user@example.com/foo", L"", default_format_type,
+ "http://user@example.com/foo", "", default_format_type,
UnescapeRule::NORMAL, L"http://example.com/foo", 7},
{"Just '@' without username and password",
- "http://@example.com/foo", L"", default_format_type, UnescapeRule::NORMAL,
+ "http://@example.com/foo", "", default_format_type, UnescapeRule::NORMAL,
L"http://example.com/foo", 7},
// GURL doesn't think local-part of an email address is username for URL.
{"mailto:, omit_username_password=true",
- "mailto:foo@example.com", L"", default_format_type, UnescapeRule::NORMAL,
+ "mailto:foo@example.com", "", default_format_type, UnescapeRule::NORMAL,
L"mailto:foo@example.com", 7},
// -------- unescape flag tests --------
{"Do not unescape",
"http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
"%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
- "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", L"en", default_format_type,
+ "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type,
UnescapeRule::NONE,
// GURL parses %-encoded hostnames into Punycode.
L"http://xn--qcka1pmc.jp/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
@@ -1394,18 +1421,18 @@ TEST(NetUtilTest, FormatUrl) {
{"Unescape normally",
"http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
"%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
- "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", L"en", default_format_type,
+ "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type,
UnescapeRule::NORMAL,
L"http://xn--qcka1pmc.jp/\x30B0\x30FC\x30B0\x30EB"
L"?q=\x30B0\x30FC\x30B0\x30EB", 7},
{"Unescape normally including unescape spaces",
- "http://www.google.com/search?q=Hello%20World", L"en", default_format_type,
+ "http://www.google.com/search?q=Hello%20World", "en", default_format_type,
UnescapeRule::SPACES, L"http://www.google.com/search?q=Hello World", 7},
/*
{"unescape=true with some special characters",
- "http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", L"",
+ "http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", "",
net::kFormatUrlOmitNothing, UnescapeRule::NORMAL,
L"http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", 25},
*/
@@ -1413,81 +1440,81 @@ TEST(NetUtilTest, FormatUrl) {
// -------- omit http: --------
{"omit http with user name",
- "http://user@example.com/foo", L"", net::kFormatUrlOmitAll,
+ "http://user@example.com/foo", "", net::kFormatUrlOmitAll,
UnescapeRule::NORMAL, L"example.com/foo", 0},
{"omit http",
- "http://www.google.com/", L"en", net::kFormatUrlOmitHTTP,
+ "http://www.google.com/", "en", net::kFormatUrlOmitHTTP,
UnescapeRule::NORMAL, L"www.google.com/",
0},
{"omit http with https",
- "https://www.google.com/", L"en", net::kFormatUrlOmitHTTP,
+ "https://www.google.com/", "en", net::kFormatUrlOmitHTTP,
UnescapeRule::NORMAL, L"https://www.google.com/",
8},
{"omit http starts with ftp.",
- "http://ftp.google.com/", L"en", net::kFormatUrlOmitHTTP,
+ "http://ftp.google.com/", "en", net::kFormatUrlOmitHTTP,
UnescapeRule::NORMAL, L"http://ftp.google.com/",
7},
// -------- omit trailing slash on bare hostname --------
{"omit slash when it's the entire path",
- "http://www.google.com/", L"en",
+ "http://www.google.com/", "en",
net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
L"http://www.google.com", 7},
{"omit slash when there's a ref",
- "http://www.google.com/#ref", L"en",
+ "http://www.google.com/#ref", "en",
net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
L"http://www.google.com/#ref", 7},
{"omit slash when there's a query",
- "http://www.google.com/?", L"en",
+ "http://www.google.com/?", "en",
net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
L"http://www.google.com/?", 7},
{"omit slash when it's not the entire path",
- "http://www.google.com/foo", L"en",
+ "http://www.google.com/foo", "en",
net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
L"http://www.google.com/foo", 7},
{"omit slash for nonstandard URLs",
- "data:/", L"en", net::kFormatUrlOmitTrailingSlashOnBareHostname,
+ "data:/", "en", net::kFormatUrlOmitTrailingSlashOnBareHostname,
UnescapeRule::NORMAL, L"data:/", 5},
{"omit slash for file URLs",
- "file:///", L"en", net::kFormatUrlOmitTrailingSlashOnBareHostname,
+ "file:///", "en", net::kFormatUrlOmitTrailingSlashOnBareHostname,
UnescapeRule::NORMAL, L"file:///", 7},
// -------- view-source: --------
{"view-source",
- "view-source:http://xn--qcka1pmc.jp/", L"ja", default_format_type,
+ "view-source:http://xn--qcka1pmc.jp/", "ja", default_format_type,
UnescapeRule::NORMAL, L"view-source:http://\x30B0\x30FC\x30B0\x30EB.jp/",
19},
{"view-source of view-source",
- "view-source:view-source:http://xn--qcka1pmc.jp/", L"ja",
+ "view-source:view-source:http://xn--qcka1pmc.jp/", "ja",
default_format_type, UnescapeRule::NORMAL,
L"view-source:view-source:http://xn--qcka1pmc.jp/", 12},
// view-source should omit http and trailing slash where non-view-source
// would.
{"view-source omit http",
- "view-source:http://a.b/c", L"en", net::kFormatUrlOmitAll,
+ "view-source:http://a.b/c", "en", net::kFormatUrlOmitAll,
UnescapeRule::NORMAL, L"view-source:a.b/c",
12},
{"view-source omit http starts with ftp.",
- "view-source:http://ftp.b/c", L"en", net::kFormatUrlOmitAll,
+ "view-source:http://ftp.b/c", "en", net::kFormatUrlOmitAll,
UnescapeRule::NORMAL, L"view-source:http://ftp.b/c",
19},
{"view-source omit slash when it's the entire path",
- "view-source:http://a.b/", L"en", net::kFormatUrlOmitAll,
+ "view-source:http://a.b/", "en", net::kFormatUrlOmitAll,
UnescapeRule::NORMAL, L"view-source:a.b",
12},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
size_t prefix_len;
- std::wstring formatted = net::FormatUrl(
+ string16 formatted = net::FormatUrl(
GURL(tests[i].input), tests[i].languages, tests[i].format_types,
tests[i].escape_rules, NULL, &prefix_len, NULL);
- EXPECT_EQ(tests[i].output, formatted) << tests[i].description;
+ EXPECT_EQ(WideToUTF16(tests[i].output), formatted) << tests[i].description;
EXPECT_EQ(tests[i].prefix_len, prefix_len) << tests[i].description;
}
}
@@ -1495,114 +1522,140 @@ TEST(NetUtilTest, FormatUrl) {
TEST(NetUtilTest, FormatUrlParsed) {
// No unescape case.
url_parse::Parsed parsed;
- std::wstring formatted = net::FormatUrl(
+ string16 formatted = net::FormatUrl(
GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
"%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
- L"ja", net::kFormatUrlOmitNothing, UnescapeRule::NONE, &parsed, NULL,
+ "ja", net::kFormatUrlOmitNothing, UnescapeRule::NONE, &parsed, NULL,
NULL);
- EXPECT_EQ(L"http://%E3%82%B0:%E3%83%BC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
- L"/%E3%82%B0/?q=%E3%82%B0#\x30B0", formatted);
- EXPECT_EQ(L"%E3%82%B0",
+ EXPECT_EQ(WideToUTF16(
+ L"http://%E3%82%B0:%E3%83%BC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
+ L"/%E3%82%B0/?q=%E3%82%B0#\x30B0"), formatted);
+ EXPECT_EQ(WideToUTF16(L"%E3%82%B0"),
formatted.substr(parsed.username.begin, parsed.username.len));
- EXPECT_EQ(L"%E3%83%BC",
+ EXPECT_EQ(WideToUTF16(L"%E3%83%BC"),
formatted.substr(parsed.password.begin, parsed.password.len));
- EXPECT_EQ(L"\x30B0\x30FC\x30B0\x30EB.jp",
+ EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
formatted.substr(parsed.host.begin, parsed.host.len));
- EXPECT_EQ(L"8080", formatted.substr(parsed.port.begin, parsed.port.len));
- EXPECT_EQ(L"/%E3%82%B0/",
+ EXPECT_EQ(WideToUTF16(L"8080"),
+ formatted.substr(parsed.port.begin, parsed.port.len));
+ EXPECT_EQ(WideToUTF16(L"/%E3%82%B0/"),
formatted.substr(parsed.path.begin, parsed.path.len));
- EXPECT_EQ(L"q=%E3%82%B0",
+ EXPECT_EQ(WideToUTF16(L"q=%E3%82%B0"),
formatted.substr(parsed.query.begin, parsed.query.len));
- EXPECT_EQ(L"\x30B0", formatted.substr(parsed.ref.begin, parsed.ref.len));
+ EXPECT_EQ(WideToUTF16(L"\x30B0"),
+ formatted.substr(parsed.ref.begin, parsed.ref.len));
// Unescape case.
formatted = net::FormatUrl(
GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
"%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
- L"ja", net::kFormatUrlOmitNothing, UnescapeRule::NORMAL, &parsed, NULL,
+ "ja", net::kFormatUrlOmitNothing, UnescapeRule::NORMAL, &parsed, NULL,
NULL);
- EXPECT_EQ(L"http://\x30B0:\x30FC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
- L"/\x30B0/?q=\x30B0#\x30B0", formatted);
- EXPECT_EQ(L"\x30B0",
+ EXPECT_EQ(WideToUTF16(L"http://\x30B0:\x30FC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
+ L"/\x30B0/?q=\x30B0#\x30B0"), formatted);
+ EXPECT_EQ(WideToUTF16(L"\x30B0"),
formatted.substr(parsed.username.begin, parsed.username.len));
- EXPECT_EQ(L"\x30FC",
+ EXPECT_EQ(WideToUTF16(L"\x30FC"),
formatted.substr(parsed.password.begin, parsed.password.len));
- EXPECT_EQ(L"\x30B0\x30FC\x30B0\x30EB.jp",
+ EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
formatted.substr(parsed.host.begin, parsed.host.len));
- EXPECT_EQ(L"8080", formatted.substr(parsed.port.begin, parsed.port.len));
- EXPECT_EQ(L"/\x30B0/", formatted.substr(parsed.path.begin, parsed.path.len));
- EXPECT_EQ(L"q=\x30B0",
+ EXPECT_EQ(WideToUTF16(L"8080"),
+ formatted.substr(parsed.port.begin, parsed.port.len));
+ EXPECT_EQ(WideToUTF16(L"/\x30B0/"),
+ formatted.substr(parsed.path.begin, parsed.path.len));
+ EXPECT_EQ(WideToUTF16(L"q=\x30B0"),
formatted.substr(parsed.query.begin, parsed.query.len));
- EXPECT_EQ(L"\x30B0", formatted.substr(parsed.ref.begin, parsed.ref.len));
+ EXPECT_EQ(WideToUTF16(L"\x30B0"),
+ formatted.substr(parsed.ref.begin, parsed.ref.len));
// Omit_username_password + unescape case.
formatted = net::FormatUrl(
GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
"%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
- L"ja", net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
- &parsed, NULL, NULL);
- EXPECT_EQ(L"http://\x30B0\x30FC\x30B0\x30EB.jp:8080"
- L"/\x30B0/?q=\x30B0#\x30B0", formatted);
+ "ja", net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, &parsed,
+ NULL, NULL);
+ EXPECT_EQ(WideToUTF16(L"http://\x30B0\x30FC\x30B0\x30EB.jp:8080"
+ L"/\x30B0/?q=\x30B0#\x30B0"), formatted);
EXPECT_FALSE(parsed.username.is_valid());
EXPECT_FALSE(parsed.password.is_valid());
- EXPECT_EQ(L"\x30B0\x30FC\x30B0\x30EB.jp",
+ EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
formatted.substr(parsed.host.begin, parsed.host.len));
- EXPECT_EQ(L"8080", formatted.substr(parsed.port.begin, parsed.port.len));
- EXPECT_EQ(L"/\x30B0/", formatted.substr(parsed.path.begin, parsed.path.len));
- EXPECT_EQ(L"q=\x30B0",
+ EXPECT_EQ(WideToUTF16(L"8080"),
+ formatted.substr(parsed.port.begin, parsed.port.len));
+ EXPECT_EQ(WideToUTF16(L"/\x30B0/"),
+ formatted.substr(parsed.path.begin, parsed.path.len));
+ EXPECT_EQ(WideToUTF16(L"q=\x30B0"),
formatted.substr(parsed.query.begin, parsed.query.len));
- EXPECT_EQ(L"\x30B0", formatted.substr(parsed.ref.begin, parsed.ref.len));
+ EXPECT_EQ(WideToUTF16(L"\x30B0"),
+ formatted.substr(parsed.ref.begin, parsed.ref.len));
// View-source case.
formatted = net::FormatUrl(
GURL("view-source:http://user:passwd@host:81/path?query#ref"),
- L"", net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, &parsed,
+ "", net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, &parsed,
NULL, NULL);
- EXPECT_EQ(L"view-source:http://host:81/path?query#ref", formatted);
- EXPECT_EQ(L"view-source:http",
+ EXPECT_EQ(WideToUTF16(L"view-source:http://host:81/path?query#ref"),
+ formatted);
+ EXPECT_EQ(WideToUTF16(L"view-source:http"),
formatted.substr(parsed.scheme.begin, parsed.scheme.len));
EXPECT_FALSE(parsed.username.is_valid());
EXPECT_FALSE(parsed.password.is_valid());
- EXPECT_EQ(L"host", formatted.substr(parsed.host.begin, parsed.host.len));
- EXPECT_EQ(L"81", formatted.substr(parsed.port.begin, parsed.port.len));
- EXPECT_EQ(L"/path", formatted.substr(parsed.path.begin, parsed.path.len));
- EXPECT_EQ(L"query", formatted.substr(parsed.query.begin, parsed.query.len));
- EXPECT_EQ(L"ref", formatted.substr(parsed.ref.begin, parsed.ref.len));
+ EXPECT_EQ(WideToUTF16(L"host"),
+ formatted.substr(parsed.host.begin, parsed.host.len));
+ EXPECT_EQ(WideToUTF16(L"81"),
+ formatted.substr(parsed.port.begin, parsed.port.len));
+ EXPECT_EQ(WideToUTF16(L"/path"),
+ formatted.substr(parsed.path.begin, parsed.path.len));
+ EXPECT_EQ(WideToUTF16(L"query"),
+ formatted.substr(parsed.query.begin, parsed.query.len));
+ EXPECT_EQ(WideToUTF16(L"ref"),
+ formatted.substr(parsed.ref.begin, parsed.ref.len));
// omit http case.
formatted = net::FormatUrl(
GURL("http://host:8000/a?b=c#d"),
- L"", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
- EXPECT_EQ(L"host:8000/a?b=c#d", formatted);
+ "", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
+ EXPECT_EQ(WideToUTF16(L"host:8000/a?b=c#d"), formatted);
EXPECT_FALSE(parsed.scheme.is_valid());
EXPECT_FALSE(parsed.username.is_valid());
EXPECT_FALSE(parsed.password.is_valid());
- EXPECT_EQ(L"host", formatted.substr(parsed.host.begin, parsed.host.len));
- EXPECT_EQ(L"8000", formatted.substr(parsed.port.begin, parsed.port.len));
- EXPECT_EQ(L"/a", formatted.substr(parsed.path.begin, parsed.path.len));
- EXPECT_EQ(L"b=c", formatted.substr(parsed.query.begin, parsed.query.len));
- EXPECT_EQ(L"d", formatted.substr(parsed.ref.begin, parsed.ref.len));
+ EXPECT_EQ(WideToUTF16(L"host"),
+ formatted.substr(parsed.host.begin, parsed.host.len));
+ EXPECT_EQ(WideToUTF16(L"8000"),
+ formatted.substr(parsed.port.begin, parsed.port.len));
+ EXPECT_EQ(WideToUTF16(L"/a"),
+ formatted.substr(parsed.path.begin, parsed.path.len));
+ EXPECT_EQ(WideToUTF16(L"b=c"),
+ formatted.substr(parsed.query.begin, parsed.query.len));
+ EXPECT_EQ(WideToUTF16(L"d"),
+ formatted.substr(parsed.ref.begin, parsed.ref.len));
// omit http starts with ftp case.
formatted = net::FormatUrl(
GURL("http://ftp.host:8000/a?b=c#d"),
- L"", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
- EXPECT_EQ(L"http://ftp.host:8000/a?b=c#d", formatted);
+ "", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
+ EXPECT_EQ(WideToUTF16(L"http://ftp.host:8000/a?b=c#d"), formatted);
EXPECT_TRUE(parsed.scheme.is_valid());
EXPECT_FALSE(parsed.username.is_valid());
EXPECT_FALSE(parsed.password.is_valid());
- EXPECT_EQ(L"http", formatted.substr(parsed.scheme.begin, parsed.scheme.len));
- EXPECT_EQ(L"ftp.host", formatted.substr(parsed.host.begin, parsed.host.len));
- EXPECT_EQ(L"8000", formatted.substr(parsed.port.begin, parsed.port.len));
- EXPECT_EQ(L"/a", formatted.substr(parsed.path.begin, parsed.path.len));
- EXPECT_EQ(L"b=c", formatted.substr(parsed.query.begin, parsed.query.len));
- EXPECT_EQ(L"d", formatted.substr(parsed.ref.begin, parsed.ref.len));
+ EXPECT_EQ(WideToUTF16(L"http"),
+ formatted.substr(parsed.scheme.begin, parsed.scheme.len));
+ EXPECT_EQ(WideToUTF16(L"ftp.host"),
+ formatted.substr(parsed.host.begin, parsed.host.len));
+ EXPECT_EQ(WideToUTF16(L"8000"),
+ formatted.substr(parsed.port.begin, parsed.port.len));
+ EXPECT_EQ(WideToUTF16(L"/a"),
+ formatted.substr(parsed.path.begin, parsed.path.len));
+ EXPECT_EQ(WideToUTF16(L"b=c"),
+ formatted.substr(parsed.query.begin, parsed.query.len));
+ EXPECT_EQ(WideToUTF16(L"d"),
+ formatted.substr(parsed.ref.begin, parsed.ref.len));
// omit http starts with 'f' case.
formatted = net::FormatUrl(
GURL("http://f/"),
- L"", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
- EXPECT_EQ(L"f/", formatted);
+ "", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
+ EXPECT_EQ(WideToUTF16(L"f/"), formatted);
EXPECT_FALSE(parsed.scheme.is_valid());
EXPECT_FALSE(parsed.username.is_valid());
EXPECT_FALSE(parsed.password.is_valid());
@@ -1610,8 +1663,10 @@ TEST(NetUtilTest, FormatUrlParsed) {
EXPECT_TRUE(parsed.path.is_valid());
EXPECT_FALSE(parsed.query.is_valid());
EXPECT_FALSE(parsed.ref.is_valid());
- EXPECT_EQ(L"f", formatted.substr(parsed.host.begin, parsed.host.len));
- EXPECT_EQ(L"/", formatted.substr(parsed.path.begin, parsed.path.len));
+ EXPECT_EQ(WideToUTF16(L"f"),
+ formatted.substr(parsed.host.begin, parsed.host.len));
+ EXPECT_EQ(WideToUTF16(L"/"),
+ formatted.substr(parsed.path.begin, parsed.path.len));
}
TEST(NetUtilTest, FormatUrlAdjustOffset) {
@@ -1625,13 +1680,13 @@ TEST(NetUtilTest, FormatUrlAdjustOffset) {
{22, 22},
{23, 23},
{25, 25},
- {26, std::wstring::npos},
- {500000, std::wstring::npos},
- {std::wstring::npos, std::wstring::npos},
+ {26, string16::npos},
+ {500000, string16::npos},
+ {string16::npos, string16::npos},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(basic_cases); ++i) {
size_t offset = basic_cases[i].input_offset;
- net::FormatUrl(GURL("http://www.google.com/foo/"), L"en",
+ net::FormatUrl(GURL("http://www.google.com/foo/"), "en",
net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
NULL, NULL, &offset);
EXPECT_EQ(basic_cases[i].output_offset, offset);
@@ -1644,18 +1699,18 @@ TEST(NetUtilTest, FormatUrlAdjustOffset) {
} omit_auth_cases[] = {
{"http://foo:bar@www.google.com/", 6, 6},
{"http://foo:bar@www.google.com/", 7, 7},
- {"http://foo:bar@www.google.com/", 8, std::wstring::npos},
- {"http://foo:bar@www.google.com/", 10, std::wstring::npos},
- {"http://foo:bar@www.google.com/", 11, std::wstring::npos},
- {"http://foo:bar@www.google.com/", 14, std::wstring::npos},
+ {"http://foo:bar@www.google.com/", 8, string16::npos},
+ {"http://foo:bar@www.google.com/", 10, string16::npos},
+ {"http://foo:bar@www.google.com/", 11, string16::npos},
+ {"http://foo:bar@www.google.com/", 14, string16::npos},
{"http://foo:bar@www.google.com/", 15, 7},
{"http://foo:bar@www.google.com/", 25, 17},
- {"http://foo@www.google.com/", 9, std::wstring::npos},
+ {"http://foo@www.google.com/", 9, string16::npos},
{"http://foo@www.google.com/", 11, 7},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_auth_cases); ++i) {
size_t offset = omit_auth_cases[i].input_offset;
- net::FormatUrl(GURL(omit_auth_cases[i].input_url), L"en",
+ net::FormatUrl(GURL(omit_auth_cases[i].input_url), "en",
net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
NULL, NULL, &offset);
EXPECT_EQ(omit_auth_cases[i].output_offset, offset);
@@ -1668,30 +1723,30 @@ TEST(NetUtilTest, FormatUrlAdjustOffset) {
{12, 12},
{13, 13},
{19, 19},
- {20, std::wstring::npos},
+ {20, string16::npos},
{23, 19},
{26, 22},
- {std::wstring::npos, std::wstring::npos},
+ {string16::npos, string16::npos},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(view_source_cases); ++i) {
size_t offset = view_source_cases[i].input_offset;
- net::FormatUrl(GURL("view-source:http://foo@www.google.com/"), L"en",
+ net::FormatUrl(GURL("view-source:http://foo@www.google.com/"), "en",
net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
NULL, NULL, &offset);
EXPECT_EQ(view_source_cases[i].output_offset, offset);
}
const AdjustOffsetCase idn_hostname_cases[] = {
- {8, std::wstring::npos},
- {16, std::wstring::npos},
- {24, std::wstring::npos},
+ {8, string16::npos},
+ {16, string16::npos},
+ {24, string16::npos},
{25, 12},
{30, 17},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(idn_hostname_cases); ++i) {
size_t offset = idn_hostname_cases[i].input_offset;
// "http://\x671d\x65e5\x3042\x3055\x3072.jp/foo/"
- net::FormatUrl(GURL("http://xn--l8jvb1ey91xtjb.jp/foo/"), L"ja",
+ net::FormatUrl(GURL("http://xn--l8jvb1ey91xtjb.jp/foo/"), "ja",
net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
NULL, NULL, &offset);
EXPECT_EQ(idn_hostname_cases[i].output_offset, offset);
@@ -1699,22 +1754,22 @@ TEST(NetUtilTest, FormatUrlAdjustOffset) {
const AdjustOffsetCase unescape_cases[] = {
{25, 25},
- {26, std::wstring::npos},
- {27, std::wstring::npos},
+ {26, string16::npos},
+ {27, string16::npos},
{28, 26},
- {35, std::wstring::npos},
+ {35, string16::npos},
{41, 31},
{59, 33},
- {60, std::wstring::npos},
- {67, std::wstring::npos},
- {68, std::wstring::npos},
+ {60, string16::npos},
+ {67, string16::npos},
+ {68, string16::npos},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(unescape_cases); ++i) {
size_t offset = unescape_cases[i].input_offset;
// "http://www.google.com/foo bar/\x30B0\x30FC\x30B0\x30EB"
net::FormatUrl(GURL(
"http://www.google.com/foo%20bar/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"),
- L"en", net::kFormatUrlOmitUsernamePassword, UnescapeRule::SPACES, NULL,
+ "en", net::kFormatUrlOmitUsernamePassword, UnescapeRule::SPACES, NULL,
NULL, &offset);
EXPECT_EQ(unescape_cases[i].output_offset, offset);
}
@@ -1722,30 +1777,30 @@ TEST(NetUtilTest, FormatUrlAdjustOffset) {
const AdjustOffsetCase ref_cases[] = {
{30, 30},
{31, 31},
- {32, std::wstring::npos},
+ {32, string16::npos},
{34, 32},
{37, 33},
- {38, std::wstring::npos},
+ {38, string16::npos},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(ref_cases); ++i) {
size_t offset = ref_cases[i].input_offset;
// "http://www.google.com/foo.html#\x30B0\x30B0z"
net::FormatUrl(GURL(
- "http://www.google.com/foo.html#\xE3\x82\xB0\xE3\x82\xB0z"), L"en",
+ "http://www.google.com/foo.html#\xE3\x82\xB0\xE3\x82\xB0z"), "en",
net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, NULL, NULL,
&offset);
EXPECT_EQ(ref_cases[i].output_offset, offset);
}
const AdjustOffsetCase omit_http_cases[] = {
- {0, std::wstring::npos},
- {3, std::wstring::npos},
+ {0, string16::npos},
+ {3, string16::npos},
{7, 0},
{8, 1},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_http_cases); ++i) {
size_t offset = omit_http_cases[i].input_offset;
- net::FormatUrl(GURL("http://www.google.com"), L"en",
+ net::FormatUrl(GURL("http://www.google.com"), "en",
net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, NULL, NULL, &offset);
EXPECT_EQ(omit_http_cases[i].output_offset, offset);
}
@@ -1757,7 +1812,7 @@ TEST(NetUtilTest, FormatUrlAdjustOffset) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_http_start_with_ftp); ++i) {
size_t offset = omit_http_start_with_ftp[i].input_offset;
- net::FormatUrl(GURL("http://ftp.google.com"), L"en",
+ net::FormatUrl(GURL("http://ftp.google.com"), "en",
net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, NULL, NULL, &offset);
EXPECT_EQ(omit_http_start_with_ftp[i].output_offset, offset);
}
@@ -1765,12 +1820,12 @@ TEST(NetUtilTest, FormatUrlAdjustOffset) {
const AdjustOffsetCase omit_all_cases[] = {
{12, 0},
{13, 1},
- {0, std::wstring::npos},
- {3, std::wstring::npos},
+ {0, string16::npos},
+ {3, string16::npos},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_all_cases); ++i) {
size_t offset = omit_all_cases[i].input_offset;
- net::FormatUrl(GURL("http://user@foo.com/"), L"en", net::kFormatUrlOmitAll,
+ net::FormatUrl(GURL("http://user@foo.com/"), "en", net::kFormatUrlOmitAll,
UnescapeRule::NORMAL, NULL, NULL, &offset);
EXPECT_EQ(omit_all_cases[i].output_offset, offset);
}
@@ -1813,7 +1868,8 @@ TEST(NetUtilTest, SimplifyUrlForRequest) {
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, tests[i].input_url));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ tests[i].input_url));
GURL input_url(GURL(tests[i].input_url));
GURL expected_url(GURL(tests[i].expected_simplified_url));
EXPECT_EQ(expected_url, net::SimplifyUrlForRequest(input_url));
@@ -1821,8 +1877,8 @@ TEST(NetUtilTest, SimplifyUrlForRequest) {
}
TEST(NetUtilTest, SetExplicitlyAllowedPortsTest) {
- std::wstring invalid[] = { L"1,2,a", L"'1','2'", L"1, 2, 3", L"1 0,11,12" };
- std::wstring valid[] = { L"", L"1", L"1,2", L"1,2,3", L"10,11,12,13" };
+ std::string invalid[] = { "1,2,a", "'1','2'", "1, 2, 3", "1 0,11,12" };
+ std::string valid[] = { "", "1", "1,2", "1,2,3", "10,11,12,13" };
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(invalid); ++i) {
net::SetExplicitlyAllowedPorts(invalid[i]);
@@ -1984,9 +2040,9 @@ TEST(NetUtilTest, IPNumberMatchesPrefix) {
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s, %s", i,
- tests[i].cidr_literal,
- tests[i].ip_literal));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s, %s", i,
+ tests[i].cidr_literal,
+ tests[i].ip_literal));
net::IPAddressNumber ip_number;
EXPECT_TRUE(net::ParseIPLiteralToNumber(tests[i].ip_literal, &ip_number));
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc
index a0bc6b5..d069879 100644
--- a/net/base/network_change_notifier.cc
+++ b/net/base/network_change_notifier.cc
@@ -53,7 +53,9 @@ void NetworkChangeNotifier::RemoveObserver(Observer* observer) {
}
NetworkChangeNotifier::NetworkChangeNotifier()
- : observer_list_(new ObserverListThreadSafe<Observer>()) {
+ : observer_list_(
+ new ObserverListThreadSafe<Observer>(
+ ObserverListBase<Observer>::NOTIFY_EXISTING_ONLY)) {
DCHECK(!g_network_change_notifier);
g_network_change_notifier = this;
}
diff --git a/net/base/network_change_notifier.h b/net/base/network_change_notifier.h
index e0a8800..79909c2 100644
--- a/net/base/network_change_notifier.h
+++ b/net/base/network_change_notifier.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_H_
#define NET_BASE_NETWORK_CHANGE_NOTIFIER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/observer_list_threadsafe.h"
diff --git a/net/base/network_change_notifier_linux.h b/net/base/network_change_notifier_linux.h
index aca9377..d5a64d7 100644
--- a/net/base/network_change_notifier_linux.h
+++ b/net/base/network_change_notifier_linux.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_LINUX_H_
#define NET_BASE_NETWORK_CHANGE_NOTIFIER_LINUX_H_
+#pragma once
#include "base/basictypes.h"
#include "base/message_loop.h"
diff --git a/net/base/network_change_notifier_mac.cc b/net/base/network_change_notifier_mac.cc
index 797de6d..d07a15c 100644
--- a/net/base/network_change_notifier_mac.cc
+++ b/net/base/network_change_notifier_mac.cc
@@ -6,78 +6,17 @@
#include <SystemConfiguration/SCDynamicStoreKey.h>
#include <SystemConfiguration/SCSchemaDefinitions.h>
-#include <algorithm>
-
-#include "base/thread.h"
-
-// We only post tasks to a child thread we own, so we don't need refcounting.
-DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkChangeNotifierMac);
namespace net {
NetworkChangeNotifierMac::NetworkChangeNotifierMac()
- : notifier_thread_(new base::Thread("NetworkChangeNotifier")) {
- // We create this notifier thread because the notification implementation
- // needs a thread with a CFRunLoop, and there's no guarantee that
- // MessageLoop::current() meets that criterion.
- base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0);
- notifier_thread_->StartWithOptions(thread_options);
- // TODO(willchan): Look to see if there's a better signal for when it's ok to
- // initialize this, rather than just delaying it by a fixed time.
- const int kNotifierThreadInitializationDelayMS = 1000;
- notifier_thread_->message_loop()->PostDelayedTask(FROM_HERE,
- NewRunnableMethod(this, &NetworkChangeNotifierMac::Init),
- kNotifierThreadInitializationDelayMS);
-}
-
-NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {
- // We don't need to explicitly Stop(), but doing so allows us to sanity-
- // check that the notifier thread shut down properly.
- notifier_thread_->Stop();
- DCHECK(run_loop_source_ == NULL);
-}
-
-// static
-void NetworkChangeNotifierMac::DynamicStoreCallback(
- SCDynamicStoreRef /* store */,
- CFArrayRef changed_keys,
- void* config) {
- NetworkChangeNotifierMac* net_config =
- static_cast<NetworkChangeNotifierMac*>(config);
- net_config->OnNetworkConfigChange(changed_keys);
-}
+ : forwarder_(this),
+ config_watcher_(&forwarder_) {}
+NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {}
-void NetworkChangeNotifierMac::WillDestroyCurrentMessageLoop() {
- DCHECK(notifier_thread_ != NULL);
- // We can't check the notifier_thread_'s message_loop(), as it's now 0.
- // DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
-
- DCHECK(run_loop_source_ != NULL);
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
- kCFRunLoopCommonModes);
- run_loop_source_.reset();
-}
-
-void NetworkChangeNotifierMac::Init() {
- DCHECK(notifier_thread_ != NULL);
- DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
-
- // Add a run loop source for a dynamic store to the current run loop.
- SCDynamicStoreContext context = {
- 0, // Version 0.
- this, // User data.
- NULL, // This is not reference counted. No retain function.
- NULL, // This is not reference counted. No release function.
- NULL, // No description for this.
- };
- scoped_cftyperef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
- NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context));
- run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource(
- NULL, store.get(), 0));
- CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
- kCFRunLoopCommonModes);
-
- // Set up notifications for interface and IP address changes.
+void NetworkChangeNotifierMac::SetDynamicStoreNotificationKeys(
+ SCDynamicStoreRef store) {
+ // Called on notifier thread.
scoped_cftyperef<CFMutableArrayRef> notification_keys(
CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
scoped_cftyperef<CFStringRef> key(SCDynamicStoreKeyCreateNetworkGlobalEntity(
@@ -92,16 +31,13 @@ void NetworkChangeNotifierMac::Init() {
// Set the notification keys. This starts us receiving notifications.
bool ret = SCDynamicStoreSetNotificationKeys(
- store.get(), notification_keys.get(), NULL);
+ store, notification_keys.get(), NULL);
// TODO(willchan): Figure out a proper way to handle this rather than crash.
CHECK(ret);
-
- MessageLoop::current()->AddDestructionObserver(this);
}
void NetworkChangeNotifierMac::OnNetworkConfigChange(CFArrayRef changed_keys) {
- DCHECK(notifier_thread_ != NULL);
- DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
+ // Called on notifier thread.
for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) {
CFStringRef key = static_cast<CFStringRef>(
diff --git a/net/base/network_change_notifier_mac.h b/net/base/network_change_notifier_mac.h
index c85f244..583fa64 100644
--- a/net/base/network_change_notifier_mac.h
+++ b/net/base/network_change_notifier_mac.h
@@ -4,53 +4,48 @@
#ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_MAC_H_
#define NET_BASE_NETWORK_CHANGE_NOTIFIER_MAC_H_
+#pragma once
#include <SystemConfiguration/SCDynamicStore.h>
#include "base/basictypes.h"
-#include "base/message_loop.h"
-#include "base/scoped_cftyperef.h"
-#include "base/scoped_ptr.h"
#include "net/base/network_change_notifier.h"
-
-namespace base {
-class Thread;
-}
+#include "net/base/network_config_watcher_mac.h"
namespace net {
-class NetworkChangeNotifierMac : public MessageLoop::DestructionObserver,
- public NetworkChangeNotifier {
+class NetworkChangeNotifierMac: public NetworkChangeNotifier {
public:
NetworkChangeNotifierMac();
-
- private:
virtual ~NetworkChangeNotifierMac();
- // Called back by OS. Calls OnNetworkConfigChange().
- static void DynamicStoreCallback(SCDynamicStoreRef /* store */,
- CFArrayRef changed_keys,
- void* config);
-
- // MessageLoop::DestructionObserver:
- virtual void WillDestroyCurrentMessageLoop();
-
- // Called on the notifier thread to initialize the notification
- // implementation. The SystemConfiguration calls in this function can lead to
- // contention early on, so we invoke this function later on in startup to keep
- // it fast.
- void Init();
-
- // Called by DynamicStoreCallback() when something about the network config
- // changes.
+ private:
+ // Forwarder just exists to keep the NetworkConfigWatcherMac API out of
+ // NetworkChangeNotifierMac's public API.
+ class Forwarder : public NetworkConfigWatcherMac::Delegate {
+ public:
+ explicit Forwarder(NetworkChangeNotifierMac* net_config_watcher)
+ : net_config_watcher_(net_config_watcher) {}
+
+ // NetworkConfigWatcherMac::Delegate implementation:
+ virtual void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store) {
+ net_config_watcher_->SetDynamicStoreNotificationKeys(store);
+ }
+ virtual void OnNetworkConfigChange(CFArrayRef changed_keys) {
+ net_config_watcher_->OnNetworkConfigChange(changed_keys);
+ }
+
+ private:
+ NetworkChangeNotifierMac* const net_config_watcher_;
+ DISALLOW_COPY_AND_ASSIGN(Forwarder);
+ };
+
+ // NetworkConfigWatcherMac::Delegate implementation:
+ void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store);
void OnNetworkConfigChange(CFArrayRef changed_keys);
- // The thread used to listen for notifications. This relays the notification
- // to the registered observers without posting back to the thread the object
- // was created on.
- scoped_ptr<base::Thread> notifier_thread_;
-
- scoped_cftyperef<CFRunLoopSourceRef> run_loop_source_;
+ Forwarder forwarder_;
+ const NetworkConfigWatcherMac config_watcher_;
DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierMac);
};
diff --git a/net/base/network_change_notifier_netlink_linux.cc b/net/base/network_change_notifier_netlink_linux.cc
index 5f71f45..493e17a 100644
--- a/net/base/network_change_notifier_netlink_linux.cc
+++ b/net/base/network_change_notifier_netlink_linux.cc
@@ -26,6 +26,35 @@ bool SetNonBlocking(int fd) {
return fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0 ? true : false;
}
+bool IsIPv6Update(const struct nlmsghdr* netlink_message_header) {
+ const struct ifaddrmsg* address_message =
+ reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header));
+ return address_message->ifa_family == AF_INET6;
+}
+
+bool IsDuplicateIPv6AddressUpdate(
+ const struct nlmsghdr* netlink_message_header) {
+ const struct ifaddrmsg* address_message =
+ reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_message_header));
+ int address_message_length = IFA_PAYLOAD(netlink_message_header);
+ const struct rtattr* route_attribute =
+ reinterpret_cast<struct rtattr*>(IFA_RTA(address_message));
+ DCHECK_EQ(address_message->ifa_family, AF_INET6);
+
+ // Look for a cacheinfo attribute, and ignore new address broadcasts
+ // where the updated time stamp is newer than the created time stamp.
+ while (RTA_OK(route_attribute, address_message_length)) {
+ if (route_attribute->rta_type == IFA_CACHEINFO) {
+ struct ifa_cacheinfo* cache_info =
+ reinterpret_cast<struct ifa_cacheinfo*>(RTA_DATA(route_attribute));
+ if (cache_info->cstamp != cache_info->tstamp)
+ return true;
+ }
+ route_attribute = RTA_NEXT(route_attribute, address_message_length);
+ }
+ return false;
+}
+
} // namespace
int InitializeNetlinkSocket() {
@@ -46,7 +75,8 @@ int InitializeNetlinkSocket() {
memset(&local_addr, 0, sizeof(local_addr));
local_addr.nl_family = AF_NETLINK;
local_addr.nl_pid = getpid();
- local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_NOTIFY;
+ local_addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
+ RTMGRP_NOTIFY;
int ret = bind(sock, reinterpret_cast<struct sockaddr*>(&local_addr),
sizeof(local_addr));
if (ret < 0) {
@@ -79,6 +109,10 @@ bool HandleNetlinkMessage(char* buf, size_t len) {
// may still end up notifying observers more than strictly necessary, but
// if the primary interface goes down and back up, then this is necessary.
case RTM_NEWADDR:
+ if (IsIPv6Update(netlink_message_header) &&
+ IsDuplicateIPv6AddressUpdate(netlink_message_header))
+ return false;
+ return true;
case RTM_DELADDR:
return true;
case RTM_NEWLINK:
diff --git a/net/base/network_change_notifier_netlink_linux.h b/net/base/network_change_notifier_netlink_linux.h
index c06fdc7..13abbc6 100644
--- a/net/base/network_change_notifier_netlink_linux.h
+++ b/net/base/network_change_notifier_netlink_linux.h
@@ -8,6 +8,7 @@
#ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_NETLINK_LINUX_H_
#define NET_BASE_NETWORK_CHANGE_NOTIFIER_NETLINK_LINUX_H_
+#pragma once
#include <cstddef>
diff --git a/net/base/network_change_notifier_win.h b/net/base/network_change_notifier_win.h
index 2077ca8..80f13f0 100644
--- a/net/base/network_change_notifier_win.h
+++ b/net/base/network_change_notifier_win.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
#define NET_BASE_NETWORK_CHANGE_NOTIFIER_WIN_H_
+#pragma once
#include <windows.h>
diff --git a/net/base/network_config_watcher_mac.cc b/net/base/network_config_watcher_mac.cc
new file mode 100644
index 0000000..8e60223
--- /dev/null
+++ b/net/base/network_config_watcher_mac.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2010 The Chromium Authors. 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/network_config_watcher_mac.h"
+
+#include <SystemConfiguration/SCDynamicStoreKey.h>
+#include <SystemConfiguration/SCSchemaDefinitions.h>
+#include <algorithm>
+
+#include "base/thread.h"
+
+// We only post tasks to a child thread we own, so we don't need refcounting.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(net::NetworkConfigWatcherMac);
+
+namespace net {
+
+namespace {
+
+// Called back by OS. Calls OnNetworkConfigChange().
+void DynamicStoreCallback(SCDynamicStoreRef /* store */,
+ CFArrayRef changed_keys,
+ void* config_delegate) {
+ NetworkConfigWatcherMac::Delegate* net_config_delegate =
+ static_cast<NetworkConfigWatcherMac::Delegate*>(config_delegate);
+ net_config_delegate->OnNetworkConfigChange(changed_keys);
+}
+
+} // namespace
+
+NetworkConfigWatcherMac::NetworkConfigWatcherMac(
+ Delegate* delegate)
+ : notifier_thread_(new base::Thread("NetworkConfigWatcher")),
+ delegate_(delegate) {
+ // We create this notifier thread because the notification implementation
+ // needs a thread with a CFRunLoop, and there's no guarantee that
+ // MessageLoop::current() meets that criterion.
+ base::Thread::Options thread_options(MessageLoop::TYPE_UI, 0);
+ notifier_thread_->StartWithOptions(thread_options);
+ // TODO(willchan): Look to see if there's a better signal for when it's ok to
+ // initialize this, rather than just delaying it by a fixed time.
+ const int kNotifierThreadInitializationDelayMS = 1000;
+ notifier_thread_->message_loop()->PostDelayedTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &NetworkConfigWatcherMac::Init),
+ kNotifierThreadInitializationDelayMS);
+}
+
+NetworkConfigWatcherMac::~NetworkConfigWatcherMac() {
+ // We don't need to explicitly Stop(), but doing so allows us to sanity-
+ // check that the notifier thread shut down properly.
+ notifier_thread_->Stop();
+ DCHECK(run_loop_source_ == NULL);
+}
+
+void NetworkConfigWatcherMac::WillDestroyCurrentMessageLoop() {
+ DCHECK(notifier_thread_ != NULL);
+ // We can't check the notifier_thread_'s message_loop(), as it's now 0.
+ // DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
+
+ DCHECK(run_loop_source_ != NULL);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
+ kCFRunLoopCommonModes);
+ run_loop_source_.reset();
+}
+
+void NetworkConfigWatcherMac::Init() {
+ DCHECK(notifier_thread_ != NULL);
+ DCHECK_EQ(notifier_thread_->message_loop(), MessageLoop::current());
+
+ // Add a run loop source for a dynamic store to the current run loop.
+ SCDynamicStoreContext context = {
+ 0, // Version 0.
+ delegate_, // User data.
+ NULL, // This is not reference counted. No retain function.
+ NULL, // This is not reference counted. No release function.
+ NULL, // No description for this.
+ };
+ scoped_cftyperef<SCDynamicStoreRef> store(SCDynamicStoreCreate(
+ NULL, CFSTR("org.chromium"), DynamicStoreCallback, &context));
+ run_loop_source_.reset(SCDynamicStoreCreateRunLoopSource(
+ NULL, store.get(), 0));
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_.get(),
+ kCFRunLoopCommonModes);
+
+ // Set up notifications for interface and IP address changes.
+ delegate_->SetDynamicStoreNotificationKeys(store.get());
+
+ MessageLoop::current()->AddDestructionObserver(this);
+}
+
+} // namespace net
diff --git a/net/base/network_config_watcher_mac.h b/net/base/network_config_watcher_mac.h
new file mode 100644
index 0000000..78f06a5
--- /dev/null
+++ b/net/base/network_config_watcher_mac.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 NET_BASE_NETWORK_CONFIG_WATCHER_MAC_H_
+#define NET_BASE_NETWORK_CONFIG_WATCHER_MAC_H_
+
+#include <SystemConfiguration/SCDynamicStore.h>
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "base/scoped_cftyperef.h"
+#include "base/scoped_ptr.h"
+
+namespace base {
+class Thread;
+}
+
+namespace net {
+
+// Base class for watching the Mac OS system network settings.
+class NetworkConfigWatcherMac : public MessageLoop::DestructionObserver {
+ public:
+ // NOTE: The lifetime of Delegate is expected to exceed the lifetime of
+ // NetworkConfigWatcherMac.
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Called to register the notification keys on |store|.
+ // Implementors are expected to call SCDynamicStoreSetNotificationKeys().
+ // Will be called on the notifier thread.
+ virtual void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store) = 0;
+
+ // Called when one of the notification keys has changed.
+ // Will be called on the notifier thread.
+ virtual void OnNetworkConfigChange(CFArrayRef changed_keys) = 0;
+ };
+
+ explicit NetworkConfigWatcherMac(Delegate* delegate);
+ virtual ~NetworkConfigWatcherMac();
+
+ private:
+ // MessageLoop::DestructionObserver:
+ virtual void WillDestroyCurrentMessageLoop();
+
+ // Called on the notifier thread to initialize the notification
+ // implementation. The SystemConfiguration calls in this function can lead to
+ // contention early on, so we invoke this function later on in startup to keep
+ // it fast.
+ void Init();
+
+ // The thread used to listen for notifications. This relays the notification
+ // to the registered observers without posting back to the thread the object
+ // was created on.
+ scoped_ptr<base::Thread> notifier_thread_;
+
+ scoped_cftyperef<CFRunLoopSourceRef> run_loop_source_;
+
+ Delegate* const delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkConfigWatcherMac);
+};
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_CONFIG_WATCHER_MAC_H_
diff --git a/net/base/nss_memio.c b/net/base/nss_memio.c
index 5f7fd00..8b45c49 100644
--- a/net/base/nss_memio.c
+++ b/net/base/nss_memio.c
@@ -70,6 +70,9 @@ static void memio_buffer_destroy(struct memio_buffer *mb);
/* How many bytes can be read out of the buffer without wrapping */
static int memio_buffer_used_contiguous(const struct memio_buffer *mb);
+/* How many bytes exist after the wrap? */
+static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb);
+
/* How many bytes can be written into the buffer without wrapping */
static int memio_buffer_unused_contiguous(const struct memio_buffer *mb);
@@ -103,6 +106,12 @@ static int memio_buffer_used_contiguous(const struct memio_buffer *mb)
return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head);
}
+/* How many bytes exist after the wrap? */
+static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb)
+{
+ return (mb->tail >= mb->head) ? 0 : mb->tail;
+}
+
/* How many bytes can be written into the buffer without wrapping */
static int memio_buffer_unused_contiguous(const struct memio_buffer *mb)
{
@@ -399,13 +408,17 @@ void memio_PutReadResult(memio_Private *secret, int bytes_read)
}
}
-int memio_GetWriteParams(memio_Private *secret, const char **buf)
+void memio_GetWriteParams(memio_Private *secret,
+ const char **buf1, unsigned int *len1,
+ const char **buf2, unsigned int *len2)
{
struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf;
PR_ASSERT(mb->bufsize);
- *buf = &mb->buf[mb->head];
- return memio_buffer_used_contiguous(mb);
+ *buf1 = &mb->buf[mb->head];
+ *len1 = memio_buffer_used_contiguous(mb);
+ *buf2 = mb->buf;
+ *len2 = memio_buffer_wrapped_bytes(mb);
}
void memio_PutWriteResult(memio_Private *secret, int bytes_written)
@@ -415,8 +428,8 @@ void memio_PutWriteResult(memio_Private *secret, int bytes_written)
if (bytes_written > 0) {
mb->head += bytes_written;
- if (mb->head == mb->bufsize)
- mb->head = 0;
+ if (mb->head >= mb->bufsize)
+ mb->head -= mb->bufsize;
} else if (bytes_written < 0) {
mb->last_err = bytes_written;
}
@@ -453,11 +466,13 @@ int main()
CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
CHECKEQ(memio_buffer_used_contiguous(&mb), 5);
+ CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
CHECKEQ(memio_buffer_put(&mb, "!", 1), 1);
CHECKEQ(memio_buffer_unused_contiguous(&mb), 0);
CHECKEQ(memio_buffer_used_contiguous(&mb), 6);
+ CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0);
CHECKEQ(memio_buffer_get(&mb, buf, 6), 6);
CHECKEQ(memcmp(buf, "howdy!", 6), 0);
@@ -468,6 +483,7 @@ int main()
CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5);
CHECKEQ(memio_buffer_used_contiguous(&mb), 1);
+ CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4);
CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5);
CHECKEQ(memio_buffer_put(&mb, "5", 1), 1);
diff --git a/net/base/nss_memio.h b/net/base/nss_memio.h
index a2b642a..49d7cbc 100644
--- a/net/base/nss_memio.h
+++ b/net/base/nss_memio.h
@@ -5,6 +5,7 @@
#ifndef __MEMIO_H
#define __MEMIO_H
+#pragma once
#include <stddef.h>
@@ -67,10 +68,12 @@ int memio_GetReadParams(memio_Private *secret, char **buf);
void memio_PutReadResult(memio_Private *secret, int bytes_read);
/* Ask memio what data it has to send to the network.
- * Returns buffer space available to read into, or 0 if none available.
- * Puts current buffer position into *buf.
+ * Returns up to two buffers of data by writing the positions and lengths into
+ * |buf1|, |len1| and |buf2|, |len2|.
*/
-int memio_GetWriteParams(memio_Private *secret, const char **buf);
+void memio_GetWriteParams(memio_Private *secret,
+ const char **buf1, unsigned int *len1,
+ const char **buf2, unsigned int *len2);
/* Tell memio how many bytes were sent to the network.
* If bytes_written is < 0, it is treated as an NSPR error code.
diff --git a/net/base/pem_tokenizer.cc b/net/base/pem_tokenizer.cc
new file mode 100644
index 0000000..c79eec1
--- /dev/null
+++ b/net/base/pem_tokenizer.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 "net/base/pem_tokenizer.h"
+
+#include "base/base64.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+
+namespace {
+
+const char kPEMSearchBlock[] = "-----BEGIN ";
+const char kPEMBeginBlock[] = "-----BEGIN %s-----";
+const char kPEMEndBlock[] = "-----END %s-----";
+
+} // namespace
+
+namespace net {
+
+using base::StringPiece;
+
+struct PEMTokenizer::PEMType {
+ std::string type;
+ std::string header;
+ std::string footer;
+};
+
+PEMTokenizer::PEMTokenizer(
+ const StringPiece& str,
+ const std::vector<std::string>& allowed_block_types) {
+ Init(str, allowed_block_types);
+}
+
+PEMTokenizer::~PEMTokenizer() {
+}
+
+bool PEMTokenizer::GetNext() {
+ while (pos_ != StringPiece::npos) {
+ // Scan for the beginning of the next PEM encoded block.
+ pos_ = str_.find(kPEMSearchBlock, pos_);
+ if (pos_ == StringPiece::npos)
+ return false; // No more PEM blocks
+
+ std::vector<PEMType>::const_iterator it;
+ // Check to see if it is of an acceptable block type.
+ for (it = block_types_.begin(); it != block_types_.end(); ++it) {
+ if (!str_.substr(pos_).starts_with(it->header))
+ continue;
+
+ // Look for a footer matching the header. If none is found, then all
+ // data following this point is invalid and should not be parsed.
+ StringPiece::size_type footer_pos = str_.find(it->footer, pos_);
+ if (footer_pos == StringPiece::npos) {
+ pos_ = StringPiece::npos;
+ return false;
+ }
+
+ // Chop off the header and footer and parse the data in between.
+ StringPiece::size_type data_begin = pos_ + it->header.size();
+ pos_ = footer_pos + it->footer.size();
+ block_type_ = it->type;
+
+ StringPiece encoded = str_.substr(data_begin,
+ footer_pos - data_begin);
+ if (!base::Base64Decode(CollapseWhitespaceASCII(encoded.as_string(),
+ true), &data_)) {
+ // The most likely cause for a decode failure is a datatype that
+ // includes PEM headers, which are not supported.
+ break;
+ }
+
+ return true;
+ }
+
+ // If the block did not match any acceptable type, move past it and
+ // continue the search. Otherwise, |pos_| has been updated to the most
+ // appropriate search position to continue searching from and should not
+ // be adjusted.
+ if (it == block_types_.end())
+ pos_ += sizeof(kPEMSearchBlock);
+ }
+
+ return false;
+}
+
+void PEMTokenizer::Init(
+ const StringPiece& str,
+ const std::vector<std::string>& allowed_block_types) {
+ str_ = str;
+ pos_ = 0;
+
+ // Construct PEM header/footer strings for all the accepted types, to
+ // reduce parsing later.
+ for (std::vector<std::string>::const_iterator it =
+ allowed_block_types.begin(); it != allowed_block_types.end(); ++it) {
+ PEMType allowed_type;
+ allowed_type.type = *it;
+ allowed_type.header = base::StringPrintf(kPEMBeginBlock, it->c_str());
+ allowed_type.footer = base::StringPrintf(kPEMEndBlock, it->c_str());
+ block_types_.push_back(allowed_type);
+ }
+}
+
+} // namespace net
diff --git a/net/base/pem_tokenizer.h b/net/base/pem_tokenizer.h
new file mode 100644
index 0000000..b54337e
--- /dev/null
+++ b/net/base/pem_tokenizer.h
@@ -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.
+
+#ifndef NET_BASE_PEM_TOKENIZER_H_
+#define NET_BASE_PEM_TOKENIZER_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/string_piece.h"
+
+namespace net {
+
+// PEMTokenizer is a utility class for the parsing of data encapsulated
+// using RFC 1421, Privacy Enhancement for Internet Electronic Mail. It
+// does not implement the full specification, most notably it does not
+// support the Encapsulated Header Portion described in Section 4.4.
+class PEMTokenizer {
+ public:
+ // Create a new PEMTokenizer that iterates through |str| searching for
+ // instances of PEM encoded blocks that are of the |allowed_block_types|.
+ // |str| must remain valid for the duration of the PEMTokenizer.
+ PEMTokenizer(const base::StringPiece& str,
+ const std::vector<std::string>& allowed_block_types);
+ ~PEMTokenizer();
+
+ // Attempts to decode the next PEM block in the string. Returns false if no
+ // PEM blocks can be decoded. The decoded PEM block will be available via
+ // data().
+ bool GetNext();
+
+ // Returns the PEM block type (eg: CERTIFICATE) of the last successfully
+ // decoded PEM block.
+ // GetNext() must have returned true before calling this method.
+ const std::string& block_type() const { return block_type_; }
+
+ // Returns the raw, Base64-decoded data of the last successfully decoded
+ // PEM block.
+ // GetNext() must have returned true before calling this method.
+ const std::string& data() const { return data_; }
+
+ private:
+ void Init(const base::StringPiece& str,
+ const std::vector<std::string>& allowed_block_types);
+
+ // A simple cache of the allowed PEM header and footer for a given PEM
+ // block type, so that it is only computed once.
+ struct PEMType;
+
+ // The string to search, which must remain valid for as long as this class
+ // is around.
+ base::StringPiece str_;
+
+ // The current position within |str_| that searching should begin from,
+ // or StringPiece::npos if iteration is complete
+ base::StringPiece::size_type pos_;
+
+ // The type of data that was encoded, as indicated in the PEM
+ // Pre-Encapsulation Boundary (eg: CERTIFICATE, PKCS7, or
+ // PRIVACY-ENHANCED MESSAGE).
+ std::string block_type_;
+
+ // The types of PEM blocks that are allowed. PEM blocks that are not of
+ // one of these types will be skipped.
+ std::vector<PEMType> block_types_;
+
+ // The raw (Base64-decoded) data of the last successfully decoded block.
+ std::string data_;
+
+ DISALLOW_COPY_AND_ASSIGN(PEMTokenizer);
+};
+
+} // namespace net
+
+#endif // NET_BASE_PEM_TOKENIZER_H_
diff --git a/net/base/pem_tokenizer_unittest.cc b/net/base/pem_tokenizer_unittest.cc
new file mode 100644
index 0000000..af2446c
--- /dev/null
+++ b/net/base/pem_tokenizer_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2010 The Chromium Authors. 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/pem_tokenizer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+TEST(PEMTokenizerTest, BasicParsing) {
+ const char data[] =
+ "-----BEGIN EXPECTED-BLOCK-----\n"
+ "TWF0Y2hlc0FjY2VwdGVkQmxvY2tUeXBl\n"
+ "-----END EXPECTED-BLOCK-----\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+ accepted_types.push_back("EXPECTED-BLOCK");
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_TRUE(tokenizer.GetNext());
+
+ EXPECT_EQ("EXPECTED-BLOCK", tokenizer.block_type());
+ EXPECT_EQ("MatchesAcceptedBlockType", tokenizer.data());
+
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+TEST(PEMTokenizerTest, CarriageReturnLineFeeds) {
+ const char data[] =
+ "-----BEGIN EXPECTED-BLOCK-----\r\n"
+ "TWF0Y2hlc0FjY2VwdGVkQmxvY2tUeXBl\r\n"
+ "-----END EXPECTED-BLOCK-----\r\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+ accepted_types.push_back("EXPECTED-BLOCK");
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_TRUE(tokenizer.GetNext());
+
+ EXPECT_EQ("EXPECTED-BLOCK", tokenizer.block_type());
+ EXPECT_EQ("MatchesAcceptedBlockType", tokenizer.data());
+
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+TEST(PEMTokenizerTest, NoAcceptedBlockTypes) {
+ const char data[] =
+ "-----BEGIN UNEXPECTED-BLOCK-----\n"
+ "SWdub3Jlc1JlamVjdGVkQmxvY2tUeXBl\n"
+ "-----END UNEXPECTED-BLOCK-----\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+ accepted_types.push_back("EXPECTED-BLOCK");
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+TEST(PEMTokenizerTest, MultipleAcceptedBlockTypes) {
+ const char data[] =
+ "-----BEGIN BLOCK-ONE-----\n"
+ "RW5jb2RlZERhdGFPbmU=\n"
+ "-----END BLOCK-ONE-----\n"
+ "-----BEGIN BLOCK-TWO-----\n"
+ "RW5jb2RlZERhdGFUd28=\n"
+ "-----END BLOCK-TWO-----\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+ accepted_types.push_back("BLOCK-ONE");
+ accepted_types.push_back("BLOCK-TWO");
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_TRUE(tokenizer.GetNext());
+
+ EXPECT_EQ("BLOCK-ONE", tokenizer.block_type());
+ EXPECT_EQ("EncodedDataOne", tokenizer.data());
+
+ EXPECT_TRUE(tokenizer.GetNext());
+
+ EXPECT_EQ("BLOCK-TWO", tokenizer.block_type());
+ EXPECT_EQ("EncodedDataTwo", tokenizer.data());
+
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+TEST(PEMTokenizerTest, MissingFooter) {
+ const char data[] =
+ "-----BEGIN MISSING-FOOTER-----\n"
+ "RW5jb2RlZERhdGFPbmU=\n"
+ "-----END MISSING-FOOTER-----\n"
+ "-----BEGIN MISSING-FOOTER-----\n"
+ "RW5jb2RlZERhdGFUd28=\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+ accepted_types.push_back("MISSING-FOOTER");
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_TRUE(tokenizer.GetNext());
+
+ EXPECT_EQ("MISSING-FOOTER", tokenizer.block_type());
+ EXPECT_EQ("EncodedDataOne", tokenizer.data());
+
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+TEST(PEMTokenizerTest, NestedEncoding) {
+ const char data[] =
+ "-----BEGIN BLOCK-ONE-----\n"
+ "RW5jb2RlZERhdGFPbmU=\n"
+ "-----BEGIN BLOCK-TWO-----\n"
+ "RW5jb2RlZERhdGFUd28=\n"
+ "-----END BLOCK-TWO-----\n"
+ "-----END BLOCK-ONE-----\n"
+ "-----BEGIN BLOCK-ONE-----\n"
+ "RW5jb2RlZERhdGFUaHJlZQ==\n"
+ "-----END BLOCK-ONE-----\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+ accepted_types.push_back("BLOCK-ONE");
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_TRUE(tokenizer.GetNext());
+
+ EXPECT_EQ("BLOCK-ONE", tokenizer.block_type());
+ EXPECT_EQ("EncodedDataThree", tokenizer.data());
+
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+TEST(PEMTokenizerTest, EmptyAcceptedTypes) {
+ const char data[] =
+ "-----BEGIN BLOCK-ONE-----\n"
+ "RW5jb2RlZERhdGFPbmU=\n"
+ "-----END BLOCK-ONE-----\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+TEST(PEMTokenizerTest, BlockWithHeader) {
+ const char data[] =
+ "-----BEGIN BLOCK-ONE-----\n"
+ "Header-One: Data data data\n"
+ "Header-Two: \n"
+ " continuation\n"
+ "Header-Three: Mix-And,Match\n"
+ "\n"
+ "RW5jb2RlZERhdGFPbmU=\n"
+ "-----END BLOCK-ONE-----\n"
+ "-----BEGIN BLOCK-ONE-----\n"
+ "RW5jb2RlZERhdGFUd28=\n"
+ "-----END BLOCK-ONE-----\n";
+ base::StringPiece string_piece(data);
+ std::vector<std::string> accepted_types;
+ accepted_types.push_back("BLOCK-ONE");
+
+ PEMTokenizer tokenizer(string_piece, accepted_types);
+ EXPECT_TRUE(tokenizer.GetNext());
+
+ EXPECT_EQ("BLOCK-ONE", tokenizer.block_type());
+ EXPECT_EQ("EncodedDataTwo", tokenizer.data());
+
+ EXPECT_FALSE(tokenizer.GetNext());
+}
+
+} // namespace net
diff --git a/net/base/platform_mime_util.h b/net/base/platform_mime_util.h
index 5bbabb8..e2b9589 100644
--- a/net/base/platform_mime_util.h
+++ b/net/base/platform_mime_util.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_PLATFORM_MIME_UTIL_H_
#define NET_BASE_PLATFORM_MIME_UTIL_H_
+#pragma once
#include <string>
diff --git a/net/base/platform_mime_util_win.cc b/net/base/platform_mime_util_win.cc
index 26d924b..bffb81a 100644
--- a/net/base/platform_mime_util_win.cc
+++ b/net/base/platform_mime_util_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.
@@ -16,7 +16,8 @@ bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension(
// check windows registry for file extension's mime type (registry key
// names are not case-sensitive).
std::wstring value, key = L"." + ext;
- RegKey(HKEY_CLASSES_ROOT, key.c_str()).ReadValue(L"Content Type", &value);
+ RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).ReadValue(L"Content Type",
+ &value);
if (!value.empty()) {
*result = WideToUTF8(value);
return true;
@@ -27,9 +28,10 @@ bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension(
bool PlatformMimeUtil::GetPreferredExtensionForMimeType(
const std::string& mime_type, FilePath::StringType* ext) const {
std::wstring key(L"MIME\\Database\\Content Type\\" + UTF8ToWide(mime_type));
- if (!RegKey(HKEY_CLASSES_ROOT, key.c_str()).ReadValue(L"Extension", ext))
+ if (!RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).ReadValue(L"Extension",
+ ext)) {
return false;
-
+ }
// Strip off the leading dot, this should always be the case.
if (!ext->empty() && ext->at(0) == L'.')
ext->erase(ext->begin());
diff --git a/net/base/registry_controlled_domain.h b/net/base/registry_controlled_domain.h
index ff922dd..fc64f3a 100644
--- a/net/base/registry_controlled_domain.h
+++ b/net/base/registry_controlled_domain.h
@@ -109,6 +109,7 @@
#ifndef NET_BASE_REGISTRY_CONTROLLED_DOMAIN_H_
#define NET_BASE_REGISTRY_CONTROLLED_DOMAIN_H_
+#pragma once
#include <string>
diff --git a/net/base/request_priority.h b/net/base/request_priority.h
index 1347001..ca7a1ec 100644
--- a/net/base/request_priority.h
+++ b/net/base/request_priority.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_REQUEST_PRIORITY_H__
#define NET_BASE_REQUEST_PRIORITY_H__
+#pragma once
namespace net {
@@ -14,10 +15,10 @@ enum RequestPriority {
MEDIUM,
LOW,
LOWEST,
+ IDLE,
NUM_PRIORITIES,
};
} // namespace net
#endif // NET_BASE_REQUEST_PRIORITY_H__
-
diff --git a/net/base/run_all_unittests.cc b/net/base/run_all_unittests.cc
index 85bda7d..77f00f0 100644
--- a/net/base/run_all_unittests.cc
+++ b/net/base/run_all_unittests.cc
@@ -4,6 +4,7 @@
#include "build/build_config.h"
#include "base/histogram.h"
+#include "base/nss_util.h"
#include "net/base/net_test_suite.h"
#if defined(OS_WIN)
#include "net/socket/ssl_client_socket_nss_factory.h"
@@ -23,6 +24,5 @@ int main(int argc, char** argv) {
base::EnsureNSPRInit();
#endif
- // TODO(phajdan.jr): Enforce test isolation, http://crbug.com/12710.
return test_suite.Run();
}
diff --git a/net/base/scoped_cert_chain_context.h b/net/base/scoped_cert_chain_context.h
index 61bb2f3..af60dd3 100644
--- a/net/base/scoped_cert_chain_context.h
+++ b/net/base/scoped_cert_chain_context.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_SCOPED_CERT_CHAIN_CONTEXT_H_
#define NET_BASE_SCOPED_CERT_CHAIN_CONTEXT_H_
+#pragma once
#include <windows.h>
#include <wincrypt.h>
diff --git a/net/base/sdch_filter.h b/net/base/sdch_filter.h
index 20a3b6e..963cf32 100644
--- a/net/base/sdch_filter.h
+++ b/net/base/sdch_filter.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.
@@ -13,6 +13,7 @@
#ifndef NET_BASE_SDCH_FILTER_H_
#define NET_BASE_SDCH_FILTER_H_
+#pragma once
#include <string>
@@ -20,8 +21,6 @@
#include "net/base/filter.h"
#include "net/base/sdch_manager.h"
-class SafeOutputStringInterface;
-
namespace open_vcdiff {
class VCDiffStreamingDecoder;
}
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc
index 0957382..3680562 100644
--- a/net/base/sdch_manager.cc
+++ b/net/base/sdch_manager.cc
@@ -2,14 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/base/sdch_manager.h"
+
#include "base/base64.h"
#include "base/field_trial.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "base/sha2.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "net/base/registry_controlled_domain.h"
-#include "net/base/sdch_manager.h"
#include "net/url_request/url_request_http_job.h"
using base::Time;
@@ -240,9 +242,12 @@ bool SdchManager::AddSdchDictionary(const std::string& dictionary_text,
if (value != "1.0")
return false;
} else if (name == "max-age") {
- expiration = Time::Now() + TimeDelta::FromSeconds(StringToInt64(value));
+ int64 seconds;
+ base::StringToInt64(value, &seconds);
+ expiration = Time::Now() + TimeDelta::FromSeconds(seconds);
} else if (name == "port") {
- int port = StringToInt(value);
+ int port;
+ base::StringToInt(value, &port);
if (port >= 0)
ports.insert(port);
}
@@ -326,6 +331,9 @@ SdchManager::Dictionary::Dictionary(const std::string& dictionary_text,
ports_(ports) {
}
+SdchManager::Dictionary::~Dictionary() {
+}
+
// static
void SdchManager::GenerateHash(const std::string& dictionary_text,
std::string* client_hash, std::string* server_hash) {
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h
index 23d100d..d53be00 100644
--- a/net/base/sdch_manager.h
+++ b/net/base/sdch_manager.h
@@ -19,16 +19,17 @@
#ifndef NET_BASE_SDCH_MANAGER_H_
#define NET_BASE_SDCH_MANAGER_H_
+#pragma once
#include <map>
#include <set>
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
//------------------------------------------------------------------------------
// Create a public interface to help us load SDCH dictionaries.
@@ -165,7 +166,7 @@ class SdchManager {
private:
friend class base::RefCounted<Dictionary>;
friend class SdchManager; // Only manager can construct an instance.
- FRIEND_TEST(SdchFilterTest, PathMatch);
+ FRIEND_TEST_ALL_PREFIXES(SdchFilterTest, PathMatch);
// Construct a vc-diff usable dictionary from the dictionary_text starting
// at the given offset. The supplied client_hash should be used to
@@ -174,7 +175,7 @@ class SdchManager {
const std::string& client_hash, const GURL& url,
const std::string& domain, const std::string& path,
const base::Time& expiration, const std::set<int> ports);
- ~Dictionary() {}
+ ~Dictionary();
const GURL& url() const { return url_; }
const std::string& client_hash() const { return client_hash_; }
diff --git a/net/base/ssl_cert_request_info.cc b/net/base/ssl_cert_request_info.cc
new file mode 100644
index 0000000..bb91632
--- /dev/null
+++ b/net/base/ssl_cert_request_info.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 "net/base/ssl_cert_request_info.h"
+
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+SSLCertRequestInfo::SSLCertRequestInfo() {
+}
+
+SSLCertRequestInfo::~SSLCertRequestInfo() {
+}
+
+} // namespace net
diff --git a/net/base/ssl_cert_request_info.h b/net/base/ssl_cert_request_info.h
index 7946e17..22eecfe 100644
--- a/net/base/ssl_cert_request_info.h
+++ b/net/base/ssl_cert_request_info.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_SSL_CERT_REQUEST_INFO_H_
#define NET_BASE_SSL_CERT_REQUEST_INFO_H_
+#pragma once
#include <string>
#include <vector>
@@ -19,6 +20,8 @@ class X509Certificate;
class SSLCertRequestInfo
: public base::RefCountedThreadSafe<SSLCertRequestInfo> {
public:
+ SSLCertRequestInfo();
+
// The host and port of the SSL server that requested client authentication.
std::string host_and_port;
@@ -41,7 +44,7 @@ class SSLCertRequestInfo
private:
friend class base::RefCountedThreadSafe<SSLCertRequestInfo>;
- ~SSLCertRequestInfo() {}
+ ~SSLCertRequestInfo();
};
} // namespace net
diff --git a/net/base/ssl_cipher_suite_names.cc b/net/base/ssl_cipher_suite_names.cc
index dfff63f..2db9a4b 100644
--- a/net/base/ssl_cipher_suite_names.cc
+++ b/net/base/ssl_cipher_suite_names.cc
@@ -6,7 +6,6 @@
#include <stdlib.h>
-#include "base/logging.h"
// Rather than storing the names of all the ciphersuites we eliminate the
// redundancy and break each cipher suite into a key exchange method, cipher
@@ -314,7 +313,7 @@ void SSLCipherSuiteToStrings(const char** key_exchange_str,
const char** mac_str, uint16 cipher_suite) {
*key_exchange_str = *cipher_str = *mac_str = "???";
- struct CipherSuite desired;
+ struct CipherSuite desired = {0};
desired.cipher_suite = cipher_suite;
void* r = bsearch(&desired, kCipherSuites,
diff --git a/net/base/ssl_cipher_suite_names.h b/net/base/ssl_cipher_suite_names.h
index 09429ae..cd61471 100644
--- a/net/base/ssl_cipher_suite_names.h
+++ b/net/base/ssl_cipher_suite_names.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_SSL_CIPHER_SUITE_NAMES_H_
#define NET_BASE_SSL_CIPHER_SUITE_NAMES_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/net/base/ssl_client_auth_cache.h b/net/base/ssl_client_auth_cache.h
index 386da41..3c8ed99 100644
--- a/net/base/ssl_client_auth_cache.h
+++ b/net/base/ssl_client_auth_cache.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_SSL_CLIENT_AUTH_CACHE_H_
#define NET_BASE_SSL_CLIENT_AUTH_CACHE_H_
+#pragma once
#include <string>
#include <map>
diff --git a/net/base/ssl_config_service.cc b/net/base/ssl_config_service.cc
index 06dc610..c20284f 100644
--- a/net/base/ssl_config_service.cc
+++ b/net/base/ssl_config_service.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "net/base/ssl_config_service.h"
+#include "net/base/ssl_false_start_blacklist.h"
#if defined(OS_WIN)
#include "net/base/ssl_config_service_win.h"
@@ -14,6 +15,31 @@
namespace net {
+SSLConfig::SSLConfig()
+ : rev_checking_enabled(true), ssl2_enabled(false), ssl3_enabled(true),
+ tls1_enabled(true), dnssec_enabled(false), mitm_proxies_allowed(false),
+ false_start_enabled(true), send_client_cert(false),
+ verify_ev_cert(false), ssl3_fallback(false) {
+}
+
+SSLConfig::~SSLConfig() {
+}
+
+bool SSLConfig::IsAllowedBadCert(X509Certificate* cert) const {
+ for (size_t i = 0; i < allowed_bad_certs.size(); ++i) {
+ if (cert == allowed_bad_certs[i].cert)
+ return true;
+ }
+ return false;
+}
+
+SSLConfigService::SSLConfigService()
+ : observer_list_(ObserverList<Observer>::NOTIFY_EXISTING_ONLY) {
+}
+
+SSLConfigService::~SSLConfigService() {
+}
+
// static
SSLConfigService* SSLConfigService::CreateSystemSSLConfigService() {
#if defined(OS_WIN)
@@ -32,12 +58,14 @@ bool SSLConfigService::IsKnownStrictTLSServer(const std::string& hostname) {
//
// If this list starts growing, it'll need to be something more efficient
// than a linear list.
- static const char kStrictServers[][20] = {
+ static const char kStrictServers[][22] = {
"www.google.com",
"mail.google.com",
"www.gmail.com",
"docs.google.com",
"clients1.google.com",
+ "sunshinepress.org",
+ "www.sunshinepress.org",
// Removed until we update the XMPP servers with the renegotiation
// extension.
@@ -45,6 +73,7 @@ bool SSLConfigService::IsKnownStrictTLSServer(const std::string& hostname) {
};
for (size_t i = 0; i < arraysize(kStrictServers); i++) {
+ // Note that the hostname is normalised to lower-case by this point.
if (strcmp(hostname.c_str(), kStrictServers[i]) == 0)
return true;
}
@@ -52,4 +81,69 @@ bool SSLConfigService::IsKnownStrictTLSServer(const std::string& hostname) {
return false;
}
+// static
+bool SSLConfigService::IsKnownFalseStartIncompatibleServer(
+ const std::string& hostname) {
+ return SSLFalseStartBlacklist::IsMember(hostname.c_str());
+}
+
+static bool g_dnssec_enabled = false;
+static bool g_false_start_enabled = true;
+static bool g_mitm_proxies_allowed = false;
+
+// static
+void SSLConfigService::SetSSLConfigFlags(SSLConfig* ssl_config) {
+ ssl_config->dnssec_enabled = g_dnssec_enabled;
+ ssl_config->false_start_enabled = g_false_start_enabled;
+ ssl_config->mitm_proxies_allowed = g_mitm_proxies_allowed;
+}
+
+// static
+void SSLConfigService::EnableDNSSEC() {
+ g_dnssec_enabled = true;
+}
+
+// static
+bool SSLConfigService::dnssec_enabled() {
+ return g_dnssec_enabled;
+}
+
+// static
+void SSLConfigService::DisableFalseStart() {
+ g_false_start_enabled = false;
+}
+
+// static
+bool SSLConfigService::false_start_enabled() {
+ return g_false_start_enabled;
+}
+
+// static
+void SSLConfigService::AllowMITMProxies() {
+ g_mitm_proxies_allowed = true;
+}
+
+// static
+bool SSLConfigService::mitm_proxies_allowed() {
+ return g_mitm_proxies_allowed;
+}
+
+void SSLConfigService::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void SSLConfigService::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(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());
+ }
+}
+
} // namespace net
diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h
index 3f0f479..f78e3df 100644
--- a/net/base/ssl_config_service.h
+++ b/net/base/ssl_config_service.h
@@ -4,9 +4,11 @@
#ifndef NET_BASE_SSL_CONFIG_SERVICE_H_
#define NET_BASE_SSL_CONFIG_SERVICE_H_
+#pragma once
#include <vector>
+#include "base/observer_list.h"
#include "base/ref_counted.h"
#include "net/base/x509_certificate.h"
@@ -16,19 +18,25 @@ namespace net {
struct SSLConfig {
// Default to revocation checking.
// Default to SSL 2.0 off, SSL 3.0 on, and TLS 1.0 on.
- SSLConfig()
- : rev_checking_enabled(true), ssl2_enabled(false), ssl3_enabled(true),
- tls1_enabled(true), ssl3_fallback(false), send_client_cert(false),
- verify_ev_cert(false) {
- }
+ SSLConfig();
+ ~SSLConfig();
bool rev_checking_enabled; // True if server certificate revocation
// checking is enabled.
bool ssl2_enabled; // True if SSL 2.0 is enabled.
bool ssl3_enabled; // True if SSL 3.0 is enabled.
bool tls1_enabled; // True if TLS 1.0 is enabled.
- bool ssl3_fallback; // True if we are falling back to SSL 3.0 (one still
- // needs to clear tls1_enabled).
+ bool dnssec_enabled; // True if we'll accept DNSSEC chains in certificates.
+
+ // True if we allow this connection to be MITM attacked. This sounds a little
+ // worse than it is: large networks sometimes MITM attack all SSL connections
+ // on egress. We want to know this because we might not have the end-to-end
+ // connection that we believe that we have based on the hostname. Therefore,
+ // certain certificate checks can't be performed and we can't use outside
+ // knowledge about whether the server has the renegotiation extension.
+ bool mitm_proxies_allowed;
+
+ bool false_start_enabled; // True if we'll use TLS False Start.
// TODO(wtc): move the following members to a new SSLParams structure. They
// are not SSL configuration settings.
@@ -39,15 +47,7 @@ struct SSLConfig {
};
// Returns true if |cert| is one of the certs in |allowed_bad_certs|.
- // TODO(wtc): Move this to a .cc file. ssl_config_service.cc is Windows
- // only right now, so I can't move it there.
- bool IsAllowedBadCert(X509Certificate* cert) const {
- for (size_t i = 0; i < allowed_bad_certs.size(); ++i) {
- if (cert == allowed_bad_certs[i].cert)
- return true;
- }
- return false;
- }
+ bool IsAllowedBadCert(X509Certificate* cert) const;
// Add any known-bad SSL certificate (with its cert status) to
// |allowed_bad_certs| that should not trigger an ERR_CERT_* error when
@@ -60,6 +60,9 @@ struct SSLConfig {
bool verify_ev_cert; // True if we should verify the certificate for EV.
+ bool ssl3_fallback; // True if we are falling back to SSL 3.0 (one still
+ // needs to clear tls1_enabled).
+
// The list of application level protocols supported. If set, this will
// enable Next Protocol Negotiation (if supported). This is a list of 8-bit
// length prefixed strings. The order of the protocols doesn't matter expect
@@ -77,6 +80,24 @@ struct SSLConfig {
// live longer than the configuration preferences.
class SSLConfigService : public base::RefCountedThreadSafe<SSLConfigService> {
public:
+ // Observer is notified when SSL config settings have changed.
+ class Observer {
+ public:
+ // Notify observers if SSL settings have changed. We don't check all of the
+ // 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;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ SSLConfigService();
+
// Create an instance of SSLConfigService which retrieves the configuration
// from the system SSL configuration, or an instance of
// SSLConfigServiceDefaults if the current system does not have a system SSL
@@ -95,10 +116,45 @@ class SSLConfigService : public base::RefCountedThreadSafe<SSLConfigService> {
// http://crbug.com and email the link to agl AT chromium DOT org.
static bool IsKnownStrictTLSServer(const std::string& hostname);
+ // Returns true if the given hostname is known to be incompatible with TLS
+ // False Start.
+ static bool IsKnownFalseStartIncompatibleServer(const std::string& hostname);
+
+ // Enables the acceptance of self-signed certificates which contain an
+ // embedded DNSSEC chain proving their validity.
+ static void EnableDNSSEC();
+ static bool dnssec_enabled();
+
+ // Sets a global flag which allows SSL connections to be MITM attacked. See
+ // the comment about this flag in |SSLConfig|.
+ static void AllowMITMProxies();
+ static bool mitm_proxies_allowed();
+
+ // Disables False Start in SSL connections.
+ static void DisableFalseStart();
+ // True if we use False Start for SSL and TLS.
+ static bool false_start_enabled();
+
+ // Add an observer of this service.
+ void AddObserver(Observer* observer);
+
+ // Remove an observer of this service.
+ void RemoveObserver(Observer* observer);
+
protected:
friend class base::RefCountedThreadSafe<SSLConfigService>;
- virtual ~SSLConfigService() {}
+ virtual ~SSLConfigService();
+
+ // SetFlags sets the values of several flags based on global configuration.
+ static void SetSSLConfigFlags(SSLConfig*);
+
+ // Process before/after config update.
+ void ProcessConfigUpdate(const SSLConfig& orig_config,
+ const SSLConfig& new_config);
+
+ private:
+ ObserverList<Observer> observer_list_;
};
} // namespace net
diff --git a/net/base/ssl_config_service_defaults.cc b/net/base/ssl_config_service_defaults.cc
new file mode 100644
index 0000000..9a3afa2
--- /dev/null
+++ b/net/base/ssl_config_service_defaults.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/base/ssl_config_service_defaults.h"
+
+namespace net {
+
+SSLConfigServiceDefaults::SSLConfigServiceDefaults() {
+}
+
+void SSLConfigServiceDefaults::GetSSLConfig(SSLConfig* config) {
+ *config = default_config_;
+ SetSSLConfigFlags(config);
+}
+
+SSLConfigServiceDefaults::~SSLConfigServiceDefaults() {
+}
+
+} // namespace net
diff --git a/net/base/ssl_config_service_defaults.h b/net/base/ssl_config_service_defaults.h
index 5425b27..6d96a44 100644
--- a/net/base/ssl_config_service_defaults.h
+++ b/net/base/ssl_config_service_defaults.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_BASE_SSL_CONFIG_SERVICE_DEFAULTS_H_
#define NET_BASE_SSL_CONFIG_SERVICE_DEFAULTS_H_
+#pragma once
#include "net/base/ssl_config_service.h"
@@ -14,15 +15,13 @@ namespace net {
// implementation of SSLConfigService yet.
class SSLConfigServiceDefaults : public SSLConfigService {
public:
- SSLConfigServiceDefaults() {}
+ SSLConfigServiceDefaults();
// Store default SSL config settings in |config|.
- virtual void GetSSLConfig(SSLConfig* config) {
- *config = default_config_;
- }
+ virtual void GetSSLConfig(SSLConfig* config);
private:
- virtual ~SSLConfigServiceDefaults() {}
+ virtual ~SSLConfigServiceDefaults();
// Default value of prefs.
const SSLConfig default_config_;
diff --git a/net/base/ssl_config_service_mac.cc b/net/base/ssl_config_service_mac.cc
index 81897c5..82a3632 100644
--- a/net/base/ssl_config_service_mac.cc
+++ b/net/base/ssl_config_service_mac.cc
@@ -95,6 +95,7 @@ bool SSLConfigServiceMac::GetSSLConfigNow(SSLConfig* config) {
kSSL3EnabledDefaultValue);
config->tls1_enabled = SSLVersionIsEnabled(kTLS1EnabledKey,
kTLS1EnabledDefaultValue);
+ SSLConfigService::SetSSLConfigFlags(config);
return true;
}
@@ -139,7 +140,10 @@ void SSLConfigServiceMac::SetRevCheckingEnabled(bool enabled) {
}
void SSLConfigServiceMac::UpdateConfig(TimeTicks now) {
+ SSLConfig orig_config = config_info_;
GetSSLConfigNow(&config_info_);
+ if (ever_updated_)
+ ProcessConfigUpdate(orig_config, config_info_);
config_time_ = now;
ever_updated_ = true;
}
diff --git a/net/base/ssl_config_service_mac.h b/net/base/ssl_config_service_mac.h
index 6d639ca..4524d95 100644
--- a/net/base/ssl_config_service_mac.h
+++ b/net/base/ssl_config_service_mac.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_SSL_CONFIG_SERVICE_MAC_H_
#define NET_BASE_SSL_CONFIG_SERVICE_MAC_H_
+#pragma once
#include "base/time.h"
#include "net/base/ssl_config_service.h"
diff --git a/net/base/ssl_config_service_mac_unittest.cc b/net/base/ssl_config_service_mac_unittest.cc
index d16129b..0aa06f9 100644
--- a/net/base/ssl_config_service_mac_unittest.cc
+++ b/net/base/ssl_config_service_mac_unittest.cc
@@ -10,6 +10,26 @@ using base::TimeTicks;
namespace {
+// SSLClientConfig service caches settings for 10 seconds for performance.
+// So we use synthetic time values along with the 'GetSSLConfigAt' method
+// to ensure that the current settings are re-read. By incrementing the time
+// value by 11 seconds, we ensure fresh config settings.
+const int kSSLConfigNextTimeInternal = 11;
+
+class SSLConfigServiceMacObserver : public net::SSLConfigService::Observer {
+ public:
+ SSLConfigServiceMacObserver() : change_was_observed_(false) {
+ }
+ bool change_was_observed() const {
+ return change_was_observed_;
+ }
+ protected:
+ virtual void OnSSLConfigChanged() {
+ change_was_observed_ = true;
+ }
+ bool change_was_observed_;
+};
+
class SSLConfigServiceMacTest : public testing::Test {
};
@@ -92,9 +112,9 @@ TEST(SSLConfigServiceMacTest, SetTest) {
TEST(SSLConfigServiceMacTest, GetTest) {
TimeTicks now = TimeTicks::Now();
TimeTicks now_1 = now + TimeDelta::FromSeconds(1);
- TimeTicks now_11 = now + TimeDelta::FromSeconds(11);
+ TimeTicks later = now + TimeDelta::FromSeconds(kSSLConfigNextTimeInternal);
- net::SSLConfig config, config_1, config_11;
+ net::SSLConfig config, config_1, config_later;
scoped_refptr<net::SSLConfigServiceMac> config_service(
new net::SSLConfigServiceMac(now));
config_service->GetSSLConfigAt(&config, now);
@@ -106,10 +126,45 @@ TEST(SSLConfigServiceMacTest, GetTest) {
config_service->GetSSLConfigAt(&config_1, now_1);
EXPECT_EQ(config.rev_checking_enabled, config_1.rev_checking_enabled);
- config_service->GetSSLConfigAt(&config_11, now_11);
- EXPECT_EQ(!config.rev_checking_enabled, config_11.rev_checking_enabled);
+ config_service->GetSSLConfigAt(&config_later, later);
+ EXPECT_EQ(!config.rev_checking_enabled, config_later.rev_checking_enabled);
// Restore the original value.
net::SSLConfigServiceMac::SetRevCheckingEnabled(
config.rev_checking_enabled);
}
+
+TEST(SSLConfigServiceMacTest, ObserverTest) {
+ TimeTicks now = TimeTicks::Now();
+ TimeTicks later = now + TimeDelta::FromSeconds(kSSLConfigNextTimeInternal);
+
+ scoped_refptr<net::SSLConfigServiceMac> config_service(
+ new net::SSLConfigServiceMac(now));
+
+ // Save the current settings so we can restore them after the tests.
+ net::SSLConfig config_save;
+ bool rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config_save);
+ 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);
+ config_service->GetSSLConfigAt(&config, later);
+
+ // Verify that the observer was notified.
+ EXPECT_TRUE(observer.change_was_observed());
+
+ // Remove the observer.
+ config_service->RemoveObserver(&observer);
+
+ // Restore the original SSL2 setting.
+ net::SSLConfigServiceMac::SetSSL2Enabled(config_save.ssl2_enabled);
+}
+
diff --git a/net/base/ssl_config_service_unittest.cc b/net/base/ssl_config_service_unittest.cc
new file mode 100644
index 0000000..47af3ee
--- /dev/null
+++ b/net/base/ssl_config_service_unittest.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 "net/base/ssl_config_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SSLConfigServiceTest : public testing::Test {
+};
+
+bool IsFalseStartIncompatible(const std::string& hostname) {
+ return net::SSLConfigService::IsKnownFalseStartIncompatibleServer(
+ hostname);
+}
+
+} // namespace
+
+TEST(SSLConfigServiceTest, FalseStartDisabledHosts) {
+ EXPECT_TRUE(IsFalseStartIncompatible("www.picnik.com"));
+ EXPECT_FALSE(IsFalseStartIncompatible("picnikfoo.com"));
+ EXPECT_FALSE(IsFalseStartIncompatible("foopicnik.com"));
+}
+
+TEST(SSLConfigServiceTest, FalseStartDisabledDomains) {
+ EXPECT_TRUE(IsFalseStartIncompatible("yodlee.com"));
+ EXPECT_TRUE(IsFalseStartIncompatible("a.yodlee.com"));
+ EXPECT_TRUE(IsFalseStartIncompatible("b.a.yodlee.com"));
+ EXPECT_FALSE(IsFalseStartIncompatible("ayodlee.com"));
+ EXPECT_FALSE(IsFalseStartIncompatible("yodleea.com"));
+ EXPECT_FALSE(IsFalseStartIncompatible("yodlee.org"));
+}
diff --git a/net/base/ssl_config_service_win.cc b/net/base/ssl_config_service_win.cc
index 513681f..4b289dd 100644
--- a/net/base/ssl_config_service_win.cc
+++ b/net/base/ssl_config_service_win.cc
@@ -75,6 +75,7 @@ bool SSLConfigServiceWin::GetSSLConfigNow(SSLConfig* config) {
config->ssl2_enabled = ((protocols & SSL2) != 0);
config->ssl3_enabled = ((protocols & SSL3) != 0);
config->tls1_enabled = ((protocols & TLS1) != 0);
+ SSLConfigService::SetSSLConfigFlags(config);
return true;
}
@@ -106,7 +107,10 @@ void SSLConfigServiceWin::SetSSL2Enabled(bool enabled) {
}
void SSLConfigServiceWin::UpdateConfig(TimeTicks now) {
+ SSLConfig orig_config = config_info_;
GetSSLConfigNow(&config_info_);
+ if (ever_updated_)
+ ProcessConfigUpdate(orig_config, config_info_);
config_time_ = now;
ever_updated_ = true;
}
diff --git a/net/base/ssl_config_service_win.h b/net/base/ssl_config_service_win.h
index 928ca1a..2b37f84 100644
--- a/net/base/ssl_config_service_win.h
+++ b/net/base/ssl_config_service_win.h
@@ -4,8 +4,7 @@
#ifndef NET_BASE_SSL_CONFIG_SERVICE_WIN_H_
#define NET_BASE_SSL_CONFIG_SERVICE_WIN_H_
-
-#include <set>
+#pragma once
#include "base/time.h"
#include "net/base/ssl_config_service.h"
diff --git a/net/base/ssl_config_service_win_unittest.cc b/net/base/ssl_config_service_win_unittest.cc
index d9f68e2..736f93c 100644
--- a/net/base/ssl_config_service_win_unittest.cc
+++ b/net/base/ssl_config_service_win_unittest.cc
@@ -10,6 +10,26 @@ using base::TimeTicks;
namespace {
+// SSLClientConfig service caches settings for 10 seconds for performance.
+// So we use synthetic time values along with the 'GetSSLConfigAt' method
+// to ensure that the current settings are re-read. By incrementing the time
+// value by 11 seconds, we ensure fresh config settings.
+const int kSSLConfigNextTimeInternal = 11;
+
+class SSLConfigServiceWinObserver : public net::SSLConfigService::Observer {
+ public:
+ SSLConfigServiceWinObserver() : change_was_observed_(false) {
+ }
+ bool change_was_observed() const {
+ return change_was_observed_;
+ }
+ protected:
+ virtual void OnSSLConfigChanged() {
+ change_was_observed_ = true;
+ }
+ bool change_was_observed_;
+};
+
class SSLConfigServiceWinTest : public testing::Test {
};
@@ -66,9 +86,9 @@ TEST(SSLConfigServiceWinTest, SetTest) {
TEST(SSLConfigServiceWinTest, GetTest) {
TimeTicks now = TimeTicks::Now();
TimeTicks now_1 = now + TimeDelta::FromSeconds(1);
- TimeTicks now_11 = now + TimeDelta::FromSeconds(11);
+ TimeTicks later = now + TimeDelta::FromSeconds(kSSLConfigNextTimeInternal);
- net::SSLConfig config, config_1, config_11;
+ net::SSLConfig config, config_1, config_later;
scoped_refptr<net::SSLConfigServiceWin> config_service(
new net::SSLConfigServiceWin(now));
config_service->GetSSLConfigAt(&config, now);
@@ -80,10 +100,45 @@ TEST(SSLConfigServiceWinTest, GetTest) {
config_service->GetSSLConfigAt(&config_1, now_1);
EXPECT_EQ(config.rev_checking_enabled, config_1.rev_checking_enabled);
- config_service->GetSSLConfigAt(&config_11, now_11);
- EXPECT_EQ(!config.rev_checking_enabled, config_11.rev_checking_enabled);
+ config_service->GetSSLConfigAt(&config_later, later);
+ EXPECT_EQ(!config.rev_checking_enabled, config_later.rev_checking_enabled);
// Restore the original value.
net::SSLConfigServiceWin::SetRevCheckingEnabled(
config.rev_checking_enabled);
}
+
+TEST(SSLConfigServiceWinTest, ObserverTest) {
+ TimeTicks now = TimeTicks::Now();
+ TimeTicks later = now + TimeDelta::FromSeconds(kSSLConfigNextTimeInternal);
+
+ scoped_refptr<net::SSLConfigServiceWin> config_service(
+ new net::SSLConfigServiceWin(now));
+
+ // Save the current settings so we can restore them after the tests.
+ net::SSLConfig config_save;
+ bool rv = net::SSLConfigServiceWin::GetSSLConfigNow(&config_save);
+ 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);
+ config_service->GetSSLConfigAt(&config, later);
+
+ // Verify that the observer was notified.
+ EXPECT_TRUE(observer.change_was_observed());
+
+ // Remove the observer.
+ config_service->RemoveObserver(&observer);
+
+ // Restore the original SSL2 setting.
+ net::SSLConfigServiceWin::SetSSL2Enabled(config_save.ssl2_enabled);
+}
+
diff --git a/net/base/ssl_connection_status_flags.h b/net/base/ssl_connection_status_flags.h
index 9ec22fa..1b7640c 100644
--- a/net/base/ssl_connection_status_flags.h
+++ b/net/base/ssl_connection_status_flags.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_SSL_CONNECTION_STATUS_FLAGS_H_
#define NET_BASE_SSL_CONNECTION_STATUS_FLAGS_H_
+#pragma once
namespace net {
diff --git a/net/base/ssl_false_start_blacklist.cc b/net/base/ssl_false_start_blacklist.cc
new file mode 100644
index 0000000..9e0f309
--- /dev/null
+++ b/net/base/ssl_false_start_blacklist.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/ssl_false_start_blacklist.h"
+
+namespace net {
+
+// static
+bool SSLFalseStartBlacklist::IsMember(const char* host) {
+ const char* last_two_labels = LastTwoLabels(host);
+ if (!last_two_labels)
+ return false;
+ const unsigned bucket = Hash(last_two_labels) & (kBuckets - 1);
+ const uint16 start = kHashTable[bucket];
+ const uint16 end = kHashTable[bucket + 1];
+ const size_t len = strlen(host);
+
+ for (size_t i = start; i < end;) {
+ const size_t blacklist_entry_len = static_cast<uint8>(kHashData[i]);
+ if (len >= blacklist_entry_len &&
+ memcmp(&host[len - blacklist_entry_len], &kHashData[i + 1],
+ blacklist_entry_len) == 0 &&
+ (len == blacklist_entry_len ||
+ host[len - blacklist_entry_len - 1] == '.')) {
+ return true;
+ }
+ i += blacklist_entry_len + 1;
+ }
+
+ return false;
+}
+
+} // namespace net
diff --git a/net/base/ssl_false_start_blacklist.h b/net/base/ssl_false_start_blacklist.h
new file mode 100644
index 0000000..1d44d0a
--- /dev/null
+++ b/net/base/ssl_false_start_blacklist.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 NET_BASE_SSL_FALSE_START_BLACKLIST_H_
+#define NET_BASE_SSL_FALSE_START_BLACKLIST_H_
+
+#include "base/basictypes.h"
+
+namespace net {
+
+// SSLFalseStartBlacklist is a set of domains which we believe to be intolerant
+// to TLS False Start. Because this set is several hundred long, it's
+// precompiled by the code in ssl_false_start_blacklist_process.cc into a hash
+// table for fast lookups.
+class SSLFalseStartBlacklist {
+ public:
+ // IsMember returns true if the given host is in the blacklist.
+ // host: a DNS name in dotted form (i.e. "www.example.com")
+ static bool IsMember(const char* host);
+
+ // Hash returns the modified djb2 hash of the given string.
+ static unsigned Hash(const char* str) {
+ // This is inline because the code which generates the hash table needs to
+ // use it. However, the generating code cannot link against
+ // ssl_false_start_blacklist.cc because that needs the tables which it
+ // generates.
+ const unsigned char* in = reinterpret_cast<const unsigned char*>(str);
+ unsigned hash = 5381;
+ unsigned char c;
+
+ while ((c = *in++))
+ hash = ((hash << 5) + hash) ^ c;
+ return hash;
+ }
+
+ // LastTwoLabels returns a pointer within |host| to the last two labels of
+ // |host|. For example, if |host| is "a.b.c.d" then LastTwoLabels will return
+ // "c.d".
+ // host: a DNS name in dotted form.
+ // returns: NULL on error, otherwise a pointer inside |host|.
+ static const char* LastTwoLabels(const char* host) {
+ // See comment in |Hash| for why this function is inline.
+ const size_t len = strlen(host);
+ if (len == 0)
+ return NULL;
+
+ unsigned dots_found = 0;
+ size_t i;
+ for (i = len - 1; i < len; i--) {
+ if (host[i] == '.') {
+ dots_found++;
+ if (dots_found == 2) {
+ i++;
+ break;
+ }
+ }
+ }
+
+ if (i > len)
+ i = 0;
+
+ if (dots_found == 0)
+ return NULL; // no names with less than two labels are in the blacklist.
+ if (dots_found == 1) {
+ if (host[0] == '.')
+ return NULL; // ditto
+ }
+
+ return &host[i];
+ }
+
+ // This is the number of buckets in the blacklist hash table. (Must be a
+ // power of two).
+ static const unsigned kBuckets = 128;
+
+ private:
+ // The following two members are defined in
+ // ssl_false_start_blacklist_data.cc, which is generated by
+ // ssl_false_start_blacklist_process.cc
+
+ // kHashTable contains an offset into |kHashData| for each bucket. The
+ // additional element at the end contains the length of |kHashData|.
+ static const uint16 kHashTable[kBuckets + 1];
+ // kHashData contains the contents of the hash table. |kHashTable| indexes
+ // into this array. Each bucket consists of zero or more, 8-bit length
+ // prefixed strings. Each string is a DNS name in dotted form. For a given
+ // string x, x and *.x are considered to be in the blacklist. In order to
+ // assign a string to a hash bucket, the last two labels (not including the
+ // root label) are hashed. Thus, the bucket for "www.example.com" is
+ // Hash("example.com"). No names that are less than two labels long are
+ // included in the blacklist.
+ static const char kHashData[];
+};
+
+} // namespace net
+
+#endif // NET_BASE_SSL_FALSE_START_BLACKLIST_H_
diff --git a/net/base/ssl_false_start_blacklist.txt b/net/base/ssl_false_start_blacklist.txt
new file mode 100644
index 0000000..9b97c57
--- /dev/null
+++ b/net/base/ssl_false_start_blacklist.txt
@@ -0,0 +1,671 @@
+# Copyright (c) 2010 The Chromium Authors. 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 the list of hosts for which we will not perform False Start. It was
+# gathered from probing and bug reports.
+
+# This is included for unit tests:
+example.com
+
+123.cht.com.tw
+4science.net
+abangdani.wordpress.com
+access.arkansas.gov
+accessgeneral.com
+accessingram.com
+accorservicesdirect.net
+adfox.cz
+ads.bridgetrack.com
+adult.dl.rakuten.co.jp
+adulthire.com
+advanceautoparts.com
+agents.nationalsecuritygroup.com
+alamode.com
+algoritam.hr
+alsformalwear.com
+alucmo.com
+amail.centrum.cz
+amexweb.com.mx
+amsi.alliedgroup.net
+amwaylive.com
+anntaylor.recruitmax.com
+apps.revenuecycle.com
+aps2.toshiba-tro.de
+apus.edu
+aribabuyer.us.dell.com
+ariston.es
+asb.dk
+ashgate.com
+ashleymadison.com
+asp.fm-pc.com
+atari.com
+ats.openhire.com
+attask-ondemand.com
+attask.com
+axa.co.uk
+banking.ing-diba.at
+baptisthealth.net
+barkoff.tv
+barracudaserver.com
+barronscatalog.com
+bb3.utc.edu
+bcbsfl.recruitmax.com
+bentley.edu
+biddingforgood.com
+biffalo.net
+bilder.buecher.de
+bishops.org.za
+bitfang.com
+blogger.huffingtonpost.com
+brinksinc.com
+buecher.de
+buildings.com
+bux.ee
+buyshakeweightformen.com
+cagreatamerica.com
+candydirect.com
+cardsdirect.com
+caringbridge.org
+cash.netmarble.net
+ccmail.cc.gatech.edu
+celebrateyourfaith.com
+centralr.com
+certs.zurich.co.uk
+champions-online.com
+chnla.com
+chw.recruitmax.com
+ciaoitalia.com
+cinema.warnermycal.com
+circlesofwisdom.com
+cisr-ssl-vpn2.univ-lyon1.fr
+citi.bridgetrack.com
+citizensfla.com
+claritycon.com
+classbauth.austin.hp.com
+cofunds.co.uk
+combattesting.com
+compaxtrade.com
+confirmit.suw.corp.google.com
+coopervisionrebates.com
+corporate.bpn.pt
+correo.uft.cl
+credinamico.programapar.com.br
+creditcards.citicards.com
+cts.vresp.com
+cubizone.com
+customer.precash.com
+cvintranet.classifiedventures.com
+d49.org
+depo.ru
+destinationlighting.com
+djmmusic.com
+dl.rakuten.co.jp
+dmgov.org
+docstoc.com
+docuware.com
+dokeos.ehb.be
+drammen.skole.d-ikt.no
+drsha.com
+dskdirect.bg
+dwarest.disc.co.jp
+easybillindia.in
+easyswitch.nl
+ebb.ubb.bg
+ebit.com.br
+echo.com
+echotrak.com
+econda-monitor.de
+edaccents.com
+edumail.tokem.fi
+eduportal.pl
+elm.mcmaster.ca
+elmls.mcmaster.ca
+email.manutouch.com.hk
+email.wsd1.org
+email.yorksj.ac.uk
+employee.translink.bc.ca
+ent.enteduc.fr
+enterprise.channeladvisor.com
+epk.tv
+epoti.abanka.si
+equippers.com
+eumail.nov.com
+eurobank.pl
+exchange.chc.be
+exchange.hostnet.nl
+exchange.selco.info
+external1.collaboration.hp.com
+extra.chrysler.de
+extranet.cchmc.org
+faxbetter.com
+fdc.org.br
+financialengines.com
+firstam.net
+flydenver.com
+forums.champions-online.com
+forums.startrekonline.com
+fucam.ac.be
+fullseat.com
+futuretrails.com
+ganymede.chester.ac.uk
+gateway.madisoncity.k12.al.us
+genuineonlinebank.com
+getslimtsnow.com
+global2.mtsallstream.com
+go.enbw.net
+goamp.com
+gomopa.net
+goredsea.com
+gotobelfast.com
+greenpower24.com
+gw2.fli.bund.de
+haken.mynavi.jp
+hangikredi.com
+hastingsdirect.com
+hearablog.com
+heavens-above.com
+helpdesk.clear2pay.com
+helwanbb.com
+hercle.com
+hivanet.hitachi-ies.co.jp
+hoken-clinic.info
+homedepotrebates.com
+honeybakedonline.com
+hood.com
+hostedjobs.openhire.com
+howtowritearesume.net
+humana.recruitmax.com
+hurmail01.hurriyet.com.tr
+hydra.cusys.edu
+hz.nl
+il.systemb2b.com
+il2l.com
+indraweb.indra.es
+ineways.com
+info.enet-japan.com
+infonet.hz.nl
+inside.nhl.com
+insight.smartdm.com
+integrishealth.recruitmax.com
+interiorsandsources.com
+internal.imaginets.com
+intra.billing.ru
+intranet.peckham.org
+intranet.ucol.ac.nz
+inverhills.edu
+iol.pt
+iqsystem.irrc.co.jp
+ito.org.tr
+itrade.fhtrust.com.tw
+iweb.thebankersbank.com
+j-union.com
+jasaga.or.jp
+jnet.agsys.sompo-japan.co.jp
+job.disc.co.jp
+job.nikkei.co.jp
+jobmgr.disc.co.jp
+kahosl.be
+keas.com
+kimberlyclark.myvurv.com
+king-invest.net
+kingsdominion.com
+kingsroadmerch.com
+kwiktrip.com
+leerlingmail.niftarlake.nl
+legalconnection.com
+lightstone.co.za
+login-pos.eurobank.pl
+login-raty.eurobank.pl
+lxr.com
+maartenluther.calvijn.nl
+magelo.com
+magtek.com
+mail.centrum.cz
+mail.extranet.hp.com
+mail.gtri.gatech.edu
+mail.gunnebo.com
+mail.hoover.k12.al.us
+mail.hzeeland.nl
+mail.idera.com
+mail.ilsole24ore.com
+mail.jetblue.com
+mail.officebroker.com
+mail.oma.nl
+mail.rawlinscollege.org.uk
+mail.rcsdk12.org
+mail.silmu.fi
+mail.sinclair.edu
+mail.skmc.gov.ae
+mail.the-ascott.com
+mail.tox-us.com
+mail.ugs.com
+mail.uottawa.ca
+mail.yvc.ac.il
+mail2.law.stetson.edu
+mail2.skanetrafiken.se
+mailhub1.cpsb.org
+mailhub2.cpsb.org
+marshallsonline.com
+massport.com
+mediabistro.com
+member.yong-online.com.tw
+merchantonlineapp.com
+merrickbank.com
+metalinq.com
+miele.co.uk
+miller.co.jp
+mishlohim.co.il
+mizunoshop.net
+mochibot.com
+mochigames.com
+mochimedia.com
+moss.esher.ac.uk
+msexchange.lyon.edu
+msishopper.net
+mtsexchange.mtsn.org.uk
+mudy.info
+my.bentley.edu
+my.berkeleycollege.edu
+my.dover.edu
+my.ecwid.com
+my.wcupa.edu
+mycls.cls.ch
+myoffice.eu.goodyear.com
+myoffice.na.goodyear.com
+myparceldelivery.com
+na.ntrsupport.com
+naramail.nara.gov
+neospeech.com
+nettkontoret.kredinor.no
+neways.com
+newaysonline.com
+newvistalive.com
+nochex.com
+noridian.totalonboarding.com
+noticiastelemicro.com
+nr.edu
+nuwaveoven.com
+online.eurobank.pl
+onyxinv.com
+orix-sumai.jp
+osvinc.com
+otpbank.hu
+owa.dist113.org
+owa.kajak.fi
+owa.kan.se
+owa.nordakademie.de
+owa.tecnicasreunidas.es
+owa2k3.bhw.de
+parfumdreams.de
+partner.buzzcity.com
+partners.conocophillipsalaska.com
+pastel.co.za
+perfectmoney.com
+picnik.com
+pimkie.de
+pimkie.es
+pimkie.fr
+pimkie.it
+pineconeresearch.com
+planet-tachyon.com
+playneverwinter.com
+pocket.matsui.co.jp
+pokervt.com
+poolzconnect.singaporepools.com.sg
+popularglasses.com
+portaal.nh1816.nl
+portail.mont-notre-dame.qc.ca
+portal.eduweb.vic.gov.au
+portal.eiffel.nl
+portal.hello.ch
+portal.klz.org.uk
+portal.langara.bc.ca
+portal.mariestad.se
+portal.peckham.org
+portal.perse.co.uk
+portal.tku.ac.jp
+post.norwegian.no
+posta.dsi.gov.tr
+powerschool.ccsdut.net
+powerschool.lawrence.k12.ma.us
+profil.centrum.cz
+projectinsight.cbre.com
+providers.tufts-health.com
+ps.dvusd.org
+ps.glenbard.org
+ps.liberty.k12.mo.us
+psyquel.com
+pushentertainment.com
+q8car.com
+qisweb2-verw.uni-hohenheim.de
+quotien.onlinebank.com
+rainforest-alliance.org
+rakuraku-market.com
+rbc.bridgetrack.com
+rc.kotoha.co.jp
+remote.cushingco.com
+reprofinance.com
+restaurantwedding.jp
+rio.edu
+rlcdn.com
+rmg.i-grasp.com
+rosevalleyindia.com
+rotaban.ru
+rozodoniy.com
+rpv.fbn.ca
+rr.com
+run.auone.jp
+runnet.jp
+s-yoyaku.city.sagamihara.kanagawa.jp
+s-yoyaku.city.urayasu.chiba.jp
+safelinkwireless.com
+sail.iwcc.edu
+samba.huji.ac.il
+samsami2u.wordpress.com
+samstores.com
+sap.kenexa.com
+saratogaschools.org
+scottsliquidgold.com
+search.boox.jp
+search.petfinder.com
+secure.cambrianc.on.ca
+secure.court.gov.il
+secure.discountadvances.com
+secure.earthclassmail.com
+secure.merchantcart.net
+secure.mycashnow.com
+secure.nochex.com
+secure.paydaymax.com
+secure.www.denverpost.com
+secure.www.mercurynews.com
+secure.www.twincities.com
+secure.zeelandnet.nl
+secure.zoominfo.com
+secureaccess.cacu.com
+securedlogons.humanadental.com
+seha.ae
+selfcare.rr.com
+services.bag-mail.de
+shakeweight.com
+shiki.gr.jp
+showcase-tv.com
+shsremote.solarishs.org
+sierranevada.com
+sis.ggusd.us
+sisense.com
+smart.otpbanka.hr
+sobexinvest.com
+socketstore.co.uk
+soundvision.com
+spalding.edu
+sprintrebates.com
+squareup.com
+ss3.e-state.co.jp
+ssl.arcsoft.com
+sslvpn.broadcom.com
+sslvpn.savannah.chatham.k12.ga.us
+staffmail.brighton.ac.uk
+staffportal.bne.catholic.edu.au
+stapleseasyrebates.com
+startnextweek.com.au
+startrekonline.com
+ste-exch1.nhc.ac.uk
+stores.channeladvisor.com
+strideeveryday.com
+studentdata.warwick.ac.uk
+studynet.dem.hva.nl
+subjectivemetrics.com
+survey5.spss-asp.com
+surveys.itsyourview.com
+suvana.com
+svelvik.skole.d-ikt.no
+syllabus.doshisha.ac.jp
+sys.ins-uni.co.jp
+taocan777.com
+teetimesusa.com
+terrabanking.romexterra.ro
+testdriveunlimited2.com
+tgn.co.jp
+tgw.com
+thecinema.in
+thediamondstore.co.uk
+thor.movistar.com.co
+thymes.com
+tlfw01.fhsg.ch
+tools.med.nyu.edu
+topfox.co.uk
+totalcore.com
+tracs.txstate.edu
+trialpay.com
+tryshakeweight.com
+trytotalpillow.com
+tvspy.com
+tw.event.gamania.com
+ucol.ac.nz
+ukblelite01.emea.aza-lite.com
+ukblelite02.emea.aza-lite.com
+uni-hohenheim.de
+user.centrum.cz
+usuwazavpn04.americas.aza-lite.com
+vcsportal.viasyscs.com
+vle.guilsborough.northants.sch.uk
+voogd.com
+vpn-01.houstonisd.org
+vpn-03.houstonisd.org
+vpn-04.houstonisd.org
+vpn.tarumanagara.com
+vr.is
+vtrade.vincomsc.com.vn
+warranty.akeryards.as
+web-opas.osakaya.co.jp
+webaccess.7p-group.com
+webaccess.pvhs.org
+webbt.banque-tahiti.pf
+webforensics.co.uk
+webmail.asb.dk
+webmail.austmus.gov.au
+webmail.bne.catholic.edu.au
+webmail.bose.com
+webmail.choa.org
+webmail.csaa.com
+webmail.firstam.net
+webmail.hrblock.com
+webmail.ingbank.com.tr
+webmail.kapsch.net
+webmail.levinglobal.com
+webmail.lolland.dk
+webmail.mopera.net
+webmail.mt.gov
+webmail.newlook.net
+webmail.ordina.nl
+webmail.peelpolice.ca
+webmail.springer-sbm.com
+webmail.srhs.com
+webmail.toho-u.ac.jp
+webmail.transat.com
+webmail.tribune.com
+webmail.tuev-nord.de
+webmail.valamar.com
+webmail.waterman-group.co.uk
+webmail.wcupa.edu
+webmaildata.rr.com
+webshop.weijntjes.nl
+webvpn.au.aecom.com
+webvpn.ben.edu
+webvpn.eu.aecom.com
+webvpn.usaa.com
+webvpn.usps.gov
+welltrix.com
+werecoverdata.com
+wettstar.de
+workhere.jetblue.com
+wowbeez.com
+ws.licenzji-vetturi.gov.mt
+wtc.lxr.com
+www.accessgeneral.com
+www.accessingram.com
+www.adfox.cz
+www.agromercantil.com.gt
+www.algoritam.hr
+www.amu.apus.edu
+www.amwaylive.com
+www.anoka.k12.mn.us
+www.apus.edu
+www.aramex.net
+www.asb.dk
+www.ashleymadison.com
+www.aussiecupid.com.au
+www.azimut.portail.soquij.qc.ca
+www.benefitsconnect.net
+www.bsnparentnet.nl
+www.buecher.de
+www.cardsdirect.com
+www.caringbridge.org
+www.cashpoint.com
+www.centralr.com
+www.champions-online.com
+www.chineselovelinks.com
+www.citizensfla.com
+www.cmarket.com
+www.coop-kobe.net
+www.costco.com.mx
+www.cubizone.com
+www.cupidmedia.com
+www.dandh.com
+www.djmmusic.com
+www.docstoc.com
+www.docuware.com
+www.dskdirect.bg
+www.dualsaw.com
+www.e-denpo.net
+www.e-zoa.com
+www.easy-share.com
+www.echo.com
+www.echotrak.com
+www.econda-monitor.de
+www.edumail.vic.gov.au
+www.eduweb.vic.gov.au
+www.empresas.bancobcr.com
+www.eurobank.pl
+www.expesite.com
+www.fareastcafe.co.jp
+www.feitest.com
+www.filipinaheart.com
+www.financialengines.com
+www.firstassistinsurance.com
+www.frankfurt-oder.de
+www.fucam.ac.be
+www.goamp.com
+www.golfdo.com
+www.gomopa.net
+www.hangikredi.com
+www.hastingsdirect.com
+www.hastingsessential.com
+www.helwanbb.com
+www.homedepotrebates.com
+www.hongkongcupid.com
+www.ihale.gov.tr
+www.improvementscatalog.com
+www.inetportals.com
+www.internationalcupid.com
+www.inverhills.edu
+www.iol.pt
+www.istyle.com.tw
+www.jerusalem.muni.il
+www.krungsricashlink.com
+www.kultur.gov.tr
+www.m-pesa.com
+www.mallorca.co.uk
+www.marshallsonline.com
+www.meadsd.net
+www.mediabistro.com
+www.merrickbank.com
+www.microline.hr
+www.miller.co.jp
+www.mishlohim.co.il
+www.mochibot.com
+www.mochigames.com
+www.mochimedia.com
+www.mochipass.com
+www.moe.gov.ae
+www.mof.go.jp
+www.montimbrenligne.laposte.fr
+www.mopera.net
+www.mp4all.nl
+www.msishopper.net
+www.mypoint.com
+www.nbch.com.ar
+www.ncatrak.org
+www.neways.com
+www.newaysonline.com
+www.nhk-ep.com
+www.nochex.com
+www.officemd.net
+www.onlineaha.org
+www.otpbank.hu
+www.pagport.jp
+www.pandorashop.nl
+www.picnik.com
+www.promptparts.com
+www.q8car.com
+www.redbullcontentpool.com
+www.regmurcia.com
+www.riksgalden.se
+www.rotaban.ru
+www.rr.com
+www.safelinkwireless.com
+www.samstores.com
+www.sharedoc.com
+www.smarttickets.com.au
+www.smartypig.com
+www.smiles.caisse-epargne.fr
+www.sprintrebates.com
+www.stapleseasyrebates.com
+www.startrekonline.com
+www.store.limewire.com
+www.supplier.nokia.com
+www.thailovelinks.com
+www.thecinema.in
+www.themls.com
+www.tjmaxx.com
+www.tnc.ne.jp
+www.topfox.co.uk
+www.toranoana.jp
+www.trialpay.com
+www.tryabcircle.com
+www.tzamtzam.co.il
+www.ucol.ac.nz
+www.user.zoominfo.com
+www.variety.com
+www.vietnamcupid.com
+www.voogd.com
+www.vpn.cmu.edu
+www.wettstar.de
+www.wiso.uni-hamburg.de
+www.worthington-portal.org
+www.wowbeez.com
+www.y-do.net
+www.yourwirelessrebatecenter.com
+www.zenfolio.com
+www.zenryonetwork.com
+www.zoominfo.com
+www1.cat365.net
+www1.ticket-web-shochiku.com
+www2.fakton.nl
+www2.proexam.org
+www2.secom-techno.co.jp
+www2.ticket-web-shochiku.com
+www6.hsmv.state.fl.us
+wwws.jp-bank.japanpost.jp
+wwy01.shiki.gr.jp
+wynbilling.wyndhamworldwide.com
+wynnmacau.recruitmax.com
+xbox.redeemer.ab.ca
+yodlee.com
+yourwirelessrebatecenter.com
+yoyaku.city.funabashi.chiba.jp
+yoyaku.city.hachioji.tokyo.jp
+zenfolio.com
+zoominfo.com
+zumbafitness.com
diff --git a/net/base/ssl_false_start_blacklist_process.cc b/net/base/ssl_false_start_blacklist_process.cc
new file mode 100644
index 0000000..46b99af
--- /dev/null
+++ b/net/base/ssl_false_start_blacklist_process.cc
@@ -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.
+
+// This utility program exists to process the False Start blacklist file into
+// a static hash table so that it can be efficiently queried by Chrome.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "net/base/ssl_false_start_blacklist.h"
+
+using net::SSLFalseStartBlacklist;
+
+static const unsigned kBuckets = SSLFalseStartBlacklist::kBuckets;
+
+static int
+usage(const char* argv0) {
+ fprintf(stderr, "Usage: %s <blacklist file> <output .c file>\n", argv0);
+ return 1;
+}
+
+// StripWWWPrefix removes "www." from the beginning of any elements of the
+// vector.
+static void StripWWWPrefix(std::vector<std::string>* hosts) {
+ static const char kPrefix[] = "www.";
+ static const unsigned kPrefixLen = sizeof(kPrefix) - 1;
+
+ for (size_t i = 0; i < hosts->size(); i++) {
+ const std::string& h = (*hosts)[i];
+ if (h.size() >= kPrefixLen &&
+ memcmp(h.data(), kPrefix, kPrefixLen) == 0) {
+ (*hosts)[i] = h.substr(kPrefixLen, h.size() - kPrefixLen);
+ }
+ }
+}
+
+// RemoveDuplicateEntries removes all duplicates from |hosts|.
+static void RemoveDuplicateEntries(std::vector<std::string>* hosts) {
+ std::set<std::string> hosts_set;
+ std::vector<std::string> ret;
+
+ for (std::vector<std::string>::const_iterator
+ i = hosts->begin(); i != hosts->end(); i++) {
+ if (hosts_set.count(*i)) {
+ fprintf(stderr, "Removing duplicate entry for %s\n", i->c_str());
+ continue;
+ }
+ hosts_set.insert(*i);
+ ret.push_back(*i);
+ }
+
+ hosts->swap(ret);
+}
+
+// ParentDomain returns the parent domain for a given domain name or the empty
+// string if the name is a top-level domain.
+static std::string ParentDomain(const std::string& in) {
+ for (size_t i = 0; i < in.size(); i++) {
+ if (in[i] == '.') {
+ return in.substr(i + 1, in.size() - i - 1);
+ }
+ }
+
+ return std::string();
+}
+
+// RemoveRedundantEntries removes any entries which are subdomains of other
+// entries. (i.e. foo.example.com would be removed if example.com were also
+// included.)
+static void RemoveRedundantEntries(std::vector<std::string>* hosts) {
+ std::set<std::string> hosts_set;
+ std::vector<std::string> ret;
+
+ for (std::vector<std::string>::const_iterator
+ i = hosts->begin(); i != hosts->end(); i++) {
+ hosts_set.insert(*i);
+ }
+
+ for (std::vector<std::string>::const_iterator
+ i = hosts->begin(); i != hosts->end(); i++) {
+ std::string parent = ParentDomain(*i);
+ while (!parent.empty()) {
+ if (hosts_set.count(parent))
+ break;
+ parent = ParentDomain(parent);
+ }
+ if (parent.empty()) {
+ ret.push_back(*i);
+ } else {
+ fprintf(stderr, "Removing %s as redundant\n", i->c_str());
+ }
+ }
+
+ hosts->swap(ret);
+}
+
+// CheckLengths returns true iff every host is less than 256 bytes long (not
+// including the terminating NUL) and contains two or more labels.
+static bool CheckLengths(const std::vector<std::string>& hosts) {
+ for (std::vector<std::string>::const_iterator
+ i = hosts.begin(); i != hosts.end(); i++) {
+ if (i->size() >= 256) {
+ fprintf(stderr, "Entry %s is too large\n", i->c_str());
+ return false;
+ }
+ if (SSLFalseStartBlacklist::LastTwoLabels(i->c_str()) == NULL) {
+ fprintf(stderr, "Entry %s contains too few labels\n", i->c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int main(int argc, char** argv) {
+ if (argc != 3)
+ return usage(argv[0]);
+
+ const char* input_file = argv[1];
+ const char* output_file = argv[2];
+ FILE* input = fopen(input_file, "r");
+ if (!input) {
+ perror("open");
+ return usage(argv[0]);
+ }
+
+ if (fseek(input, 0, SEEK_END)) {
+ perror("fseek");
+ return 1;
+ }
+
+ const long input_size = ftell(input);
+
+ if (fseek(input, 0, SEEK_SET)) {
+ perror("fseek");
+ return 1;
+ }
+
+ char* buffer = static_cast<char*>(malloc(input_size));
+ if (fread(buffer, input_size, 1, input) != 1) {
+ perror("fread");
+ free(buffer);
+ fclose(input);
+ return 1;
+ }
+ fclose(input);
+
+ std::vector<std::string> hosts;
+
+ off_t line_start = 0;
+ bool is_comment = false;
+ bool non_whitespace_seen = false;
+ for (long i = 0; i <= input_size; i++) {
+ if (i == input_size || buffer[i] == '\n') {
+ if (!is_comment && non_whitespace_seen)
+ hosts.push_back(std::string(&buffer[line_start], i - line_start));
+ is_comment = false;
+ non_whitespace_seen = false;
+ line_start = i + 1;
+ continue;
+ }
+
+ if (i == line_start && buffer[i] == '#')
+ is_comment = true;
+ if (buffer[i] != ' ' && buffer[i] != '\t')
+ non_whitespace_seen = true;
+ }
+ free(buffer);
+
+ fprintf(stderr, "Have %d hosts after parse\n", (int) hosts.size());
+ StripWWWPrefix(&hosts);
+ RemoveDuplicateEntries(&hosts);
+ fprintf(stderr, "Have %d hosts after removing duplicates\n", (int) hosts.size());
+ RemoveRedundantEntries(&hosts);
+ fprintf(stderr, "Have %d hosts after removing redundants\n", (int) hosts.size());
+ if (!CheckLengths(hosts)) {
+ fprintf(stderr, "One or more entries is too large or too small\n");
+ return 2;
+ }
+
+ fprintf(stderr, "Using %d entry hash table\n", kBuckets);
+ uint16 table[kBuckets];
+ std::vector<std::string> buckets[kBuckets];
+
+ for (std::vector<std::string>::const_iterator
+ i = hosts.begin(); i != hosts.end(); i++) {
+ const char* last_two_labels =
+ SSLFalseStartBlacklist::LastTwoLabels(i->c_str());
+ const unsigned h = SSLFalseStartBlacklist::Hash(last_two_labels);
+ buckets[h & (kBuckets - 1)].push_back(*i);
+ }
+
+ std::string table_data;
+ unsigned max_bucket_size = 0;
+ for (unsigned i = 0; i < kBuckets; i++) {
+ if (table_data.size() > 65535) {
+ fprintf(stderr, "Hash table overflowed a uint16_t index\n");
+ return 3;
+ }
+
+ if (buckets[i].size() > max_bucket_size)
+ max_bucket_size = buckets[i].size();
+
+ table[i] = table_data.size();
+ for (std::vector<std::string>::const_iterator
+ j = buckets[i].begin(); j != buckets[i].end(); j++) {
+ table_data.push_back((char) j->size());
+ table_data.append(*j);
+ }
+ }
+
+ fprintf(stderr, "Largest bucket has %d entries\n", max_bucket_size);
+
+ FILE* out = fopen(output_file, "w+");
+ if (!out) {
+ perror("opening output file");
+ return 4;
+ }
+
+ fprintf(out, "// Copyright (c) 2010 The Chromium Authors. All rights "
+ "reserved.\n// Use of this source code is governed by a BSD-style "
+ "license that can be\n// found in the LICENSE file.\n\n");
+ fprintf(out, "// WARNING: this code is generated by\n"
+ "// ssl_false_start_blacklist_process.cc. Do not edit.\n\n");
+ fprintf(out, "#include \"base/basictypes.h\"\n\n");
+ fprintf(out, "#include \"net/base/ssl_false_start_blacklist.h\"\n\n");
+ fprintf(out, "namespace net {\n\n");
+ fprintf(out, "const uint16 SSLFalseStartBlacklist::kHashTable[%d + 1] = {\n",
+ kBuckets);
+ for (unsigned i = 0; i < kBuckets; i++) {
+ fprintf(out, " %d,\n", (int) table[i]);
+ }
+ fprintf(out, " %d,\n", (int) table_data.size());
+ fprintf(out, "};\n\n");
+
+ fprintf(out, "const char SSLFalseStartBlacklist::kHashData[] = \n");
+ for (unsigned i = 0, line_length = 0; i < table_data.size(); i++) {
+ if (line_length == 0)
+ fprintf(out, " \"");
+ uint8 c = static_cast<uint8>(table_data[i]);
+ if (c < 32 || c > 127 || c == '"') {
+ fprintf(out, "\\%c%c%c", '0' + ((c >> 6) & 7), '0' + ((c >> 3) & 7),
+ '0' + (c & 7));
+ line_length += 4;
+ } else {
+ fprintf(out, "%c", c);
+ line_length++;
+ }
+ if (i == table_data.size() - 1) {
+ fprintf(out, "\";\n");
+ } else if (line_length >= 70) {
+ fprintf(out, "\"\n");
+ line_length = 0;
+ }
+ }
+ fprintf(out, "\n} // namespace net\n");
+ fclose(out);
+
+ return 0;
+}
diff --git a/net/base/ssl_false_start_blacklist_unittest.cc b/net/base/ssl_false_start_blacklist_unittest.cc
new file mode 100644
index 0000000..7ade428
--- /dev/null
+++ b/net/base/ssl_false_start_blacklist_unittest.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 "net/base/ssl_false_start_blacklist.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SSLFalseStartBlacklistTest, LastTwoLabels) {
+#define F net::SSLFalseStartBlacklist::LastTwoLabels
+ EXPECT_STREQ(F("a.b.c.d"), "c.d");
+ EXPECT_STREQ(F("a.b"), "a.b");
+ EXPECT_STREQ(F("example.com"), "example.com");
+ EXPECT_STREQ(F("www.example.com"), "example.com");
+ EXPECT_STREQ(F("www.www.example.com"), "example.com");
+
+ EXPECT_TRUE(F("com") == NULL);
+ EXPECT_TRUE(F(".com") == NULL);
+ EXPECT_TRUE(F("") == NULL);
+#undef F
+}
+
+TEST(SSLFalseStartBlacklistTest, IsMember) {
+ EXPECT_TRUE(net::SSLFalseStartBlacklist::IsMember("example.com"));
+ EXPECT_TRUE(net::SSLFalseStartBlacklist::IsMember("www.example.com"));
+ EXPECT_TRUE(net::SSLFalseStartBlacklist::IsMember("a.b.example.com"));
+ EXPECT_FALSE(net::SSLFalseStartBlacklist::IsMember("aexample.com"));
+ EXPECT_FALSE(net::SSLFalseStartBlacklist::IsMember("com"));
+}
diff --git a/net/base/ssl_info.cc b/net/base/ssl_info.cc
new file mode 100644
index 0000000..1b60644
--- /dev/null
+++ b/net/base/ssl_info.cc
@@ -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 "net/base/ssl_info.h"
+
+#include "net/base/cert_status_flags.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+SSLInfo::SSLInfo()
+ : cert_status(0),
+ security_bits(-1),
+ connection_status(0) {
+}
+
+SSLInfo::SSLInfo(const SSLInfo& info)
+ : cert(info.cert),
+ cert_status(info.cert_status),
+ security_bits(info.security_bits),
+ connection_status(info.connection_status) {
+}
+
+SSLInfo::~SSLInfo() {
+}
+
+SSLInfo& SSLInfo::operator=(const SSLInfo& info) {
+ cert = info.cert;
+ cert_status = info.cert_status;
+ security_bits = info.security_bits;
+ connection_status = info.connection_status;
+ return *this;
+}
+
+void SSLInfo::Reset() {
+ cert = NULL;
+ cert_status = 0;
+ security_bits = -1;
+ connection_status = 0;
+}
+
+void SSLInfo::SetCertError(int error) {
+ cert_status |= MapNetErrorToCertStatus(error);
+}
+
+} // namespace net
diff --git a/net/base/ssl_info.h b/net/base/ssl_info.h
index 7c14163..1786b58 100644
--- a/net/base/ssl_info.h
+++ b/net/base/ssl_info.h
@@ -1,36 +1,32 @@
-// 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.
#ifndef NET_BASE_SSL_INFO_H_
#define NET_BASE_SSL_INFO_H_
+#pragma once
-#include <string>
-
-#include "net/base/cert_status_flags.h"
-#include "net/base/x509_certificate.h"
+#include "base/ref_counted.h"
namespace net {
+class X509Certificate;
+
// SSL connection info.
// This is really a struct. All members are public.
class SSLInfo {
public:
- SSLInfo() : cert_status(0), security_bits(-1), connection_status(0) { }
+ SSLInfo();
+ SSLInfo(const SSLInfo& info);
+ ~SSLInfo();
+ SSLInfo& operator=(const SSLInfo& info);
- void Reset() {
- cert = NULL;
- cert_status = 0;
- security_bits = -1;
- connection_status = 0;
- }
+ void Reset();
bool is_valid() const { return cert != NULL; }
// Adds the specified |error| to the cert status.
- void SetCertError(int error) {
- cert_status |= MapNetErrorToCertStatus(error);
- }
+ void SetCertError(int error);
// The SSL certificate.
scoped_refptr<X509Certificate> cert;
diff --git a/net/base/ssl_non_sensitive_host_info.h b/net/base/ssl_non_sensitive_host_info.h
new file mode 100644
index 0000000..88d5cef
--- /dev/null
+++ b/net/base/ssl_non_sensitive_host_info.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 NET_BASE_SSL_NON_SENSITIVE_HOST_INFO_H
+#define NET_BASE_SSL_NON_SENSITIVE_HOST_INFO_H
+
+#include <string>
+#include "base/ref_counted.h"
+#include "net/base/completion_callback.h"
+
+namespace net {
+
+// SSLNonSensitiveHostInfo is an interface for fetching information about an
+// SSL server. This information may be stored on disk so does not include keys
+// or session information etc. Primarily it's intended for caching the server's
+// certificates.
+class SSLNonSensitiveHostInfo :
+ public base::RefCountedThreadSafe<SSLNonSensitiveHostInfo> {
+ public:
+ // Start will commence the lookup. This must be called before any other
+ // methods. By opportunistically calling this early, it may be possible to
+ // overlap this object's lookup and reduce latency.
+ virtual void Start() = 0;
+
+ // WaitForDataReady returns OK if the fetch of the requested data has
+ // completed. Otherwise it returns ERR_IO_PENDING and will call |callback| on
+ // the current thread when ready.
+ //
+ // Only a single callback can be outstanding at a given time and, in the
+ // event that WaitForDataReady returns OK, it's the caller's responsibility
+ // to delete |callback|.
+ //
+ // |callback| may be NULL, in which case ERR_IO_PENDING may still be returned
+ // but, obviously, a callback will never be made.
+ virtual int WaitForDataReady(CompletionCallback* callback) = 0;
+
+ // data returns any host information once WaitForDataReady has indicated that
+ // the fetch has completed. In the event of an error, |data| returns an empty
+ // string.
+ virtual const std::string& data() const = 0;
+
+ // Set allows for the host information to be updated for future users. This
+ // is a fire and forget operation: the caller may drop its reference from
+ // this object and the store operation will still complete. This can only be
+ // called once WaitForDataReady has returned OK or called its callback.
+ virtual void Set(const std::string& new_data) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<SSLNonSensitiveHostInfo>;
+ virtual ~SSLNonSensitiveHostInfo() { }
+};
+
+} // namespace net
+
+#endif // NET_BASE_SSL_NON_SENSITIVE_HOST_INFO_H
diff --git a/net/base/static_cookie_policy.h b/net/base/static_cookie_policy.h
index d903149..4633161 100644
--- a/net/base/static_cookie_policy.h
+++ b/net/base/static_cookie_policy.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_STATIC_COOKIE_POLICY_H_
#define NET_BASE_STATIC_COOKIE_POLICY_H_
+#pragma once
#include <string>
diff --git a/net/base/telnet_server.cc b/net/base/telnet_server.cc
deleted file mode 100644
index 5b027d7..0000000
--- a/net/base/telnet_server.cc
+++ /dev/null
@@ -1,284 +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"
-
-#if defined(OS_WIN)
-// winsock2.h must be included first in order to ensure it is included before
-// windows.h.
-#include <winsock2.h>
-#elif defined(OS_POSIX)
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "base/message_loop.h"
-#include "net/base/net_errors.h"
-#if defined(USE_SYSTEM_LIBEVENT)
-#include <event.h>
-#else
-#include "third_party/libevent/event.h"
-#endif
-#include "base/message_pump_libevent.h"
-#endif
-
-#include "base/eintr_wrapper.h"
-#include "net/base/telnet_server.h"
-
-#if defined(OS_POSIX)
-// Used same name as in Windows to avoid #ifdef where refrenced
-#define SOCKET int
-const int INVALID_SOCKET = -1;
-const int SOCKET_ERROR = -1;
-struct event; // From libevent
-#endif
-
-const int kReadBufSize = 200;
-
-// Telnet protocol constants.
-class TelnetProtocol {
- public:
- // Telnet command definitions (from arpa/telnet.h).
- enum Commands {
- IAC = 255, // Interpret as command.
- DONT = 254, // You are not to use option.
- DO = 253, // Please, you use option.
- WONT = 252, // I won't use option.
- WILL = 251, // I will use option.
- SB = 250, // Interpret as subnegotiation.
- GA = 249, // You may reverse the line.
- EL = 248, // Erase the current line.
- EC = 247, // Erase the current character.
- AYT = 246, // Are you there.
- AO = 245, // Abort output--but let prog finish.
- IP = 244, // Interrupt process--permanently.
- BREAK = 243, // Break.
- DM = 242, // Data mark--for connect. cleaning.
- NOP = 241, // Nop.
- SE = 240, // End sub negotiation.
- EOR = 239, // End of record (transparent mode).
- ABORT = 238, // Abort process.
- SUSP = 237, // Suspend process.
- XEOF = 236 // End of file: EOF is already used...
- };
-
- // Telnet options (from arpa/telnet.h).
- enum Options {
- BINARY = 0, // 8-bit data path.
- ECHO = 1, // Echo.
- SGA = 3, // Suppress go ahead.
- NAWS = 31, // Window size.
- LFLOW = 33 // Remote flow control.
- };
-
- // Fixed character definitions mentioned in RFC 854.
- enum Characters {
- NUL = 0x00,
- LF = 0x0A,
- CR = 0x0D,
- BELL = 0x07,
- BS = 0x08,
- HT = 0x09,
- VT = 0x0B,
- FF = 0x0C,
- DEL = 0x7F,
- ESC = 0x1B
- };
-};
-
-
-///////////////////////
-
-// must run in the IO thread
-TelnetServer::TelnetServer(SOCKET s, ListenSocketDelegate* del)
- : ListenSocket(s, del) {
- input_state_ = NOT_IN_IAC_OR_ESC_SEQUENCE;
-}
-
-// must run in the IO thread
-TelnetServer::~TelnetServer() {
-}
-
-void TelnetServer::SendIAC(int command, int option) {
- char data[3];
- data[0] = static_cast<unsigned char>(TelnetProtocol::IAC);
- data[1] = static_cast<unsigned char>(command);
- data[2] = option;
- Send(data, 3);
-}
-
-// always fixup \n to \r\n
-void TelnetServer::SendInternal(const char* data, int len) {
- int begin_index = 0;
- for (int i = 0; i < len; i++) {
- if (data[i] == TelnetProtocol::LF) {
- // Send CR before LF if missing before.
- if (i == 0 || data[i - 1] != TelnetProtocol::CR) {
- // Send til before LF.
- ListenSocket::SendInternal(data + begin_index, i - begin_index);
- // Send CRLF.
- ListenSocket::SendInternal("\r\n", 2);
- // Continue after LF.
- begin_index = i + 1;
- }
- }
- }
- // Send what is left (the whole string is sent here if CRLF was ok)
- ListenSocket::SendInternal(data + begin_index, len - begin_index);
-}
-
-void TelnetServer::Accept() {
- SOCKET conn = ListenSocket::Accept(socket_);
- if (conn == INVALID_SOCKET) {
- // TODO
- } else {
- scoped_refptr<TelnetServer> sock =
- new TelnetServer(conn, socket_delegate_);
-#if defined(OS_POSIX)
- sock->WatchSocket(WAITING_READ);
-#endif
- // Setup the way we want to communicate
- sock->SendIAC(TelnetProtocol::DO, TelnetProtocol::ECHO);
- sock->SendIAC(TelnetProtocol::DO, TelnetProtocol::NAWS);
- sock->SendIAC(TelnetProtocol::DO, TelnetProtocol::LFLOW);
- sock->SendIAC(TelnetProtocol::WILL, TelnetProtocol::ECHO);
- sock->SendIAC(TelnetProtocol::WILL, TelnetProtocol::SGA);
-
- // it's up to the delegate to AddRef if it wants to keep it around
- socket_delegate_->DidAccept(this, sock);
- }
-}
-
-TelnetServer* TelnetServer::Listen(std::string ip, int port,
- ListenSocketDelegate *del) {
- SOCKET s = ListenSocket::Listen(ip, port);
- if (s == INVALID_SOCKET) {
- // TODO (ibrar): error handling
- } else {
- TelnetServer *serv = new TelnetServer(s, del);
- serv->Listen();
- return serv;
- }
- return NULL;
-}
-
-void TelnetServer::StateMachineStep(unsigned char c) {
- switch (input_state_) {
- case NOT_IN_IAC_OR_ESC_SEQUENCE:
- if (c == TelnetProtocol::IAC) {
- // Expect IAC command
- input_state_ = EXPECTING_COMMAND;
- } else if (c == TelnetProtocol::ESC) {
- // Expect left suare bracket
- input_state_ = EXPECTING_FIRST_ESC_CHARACTER;
- } else {
- char data[1];
- data[0] = c;
- // handle backspace specially
- if (c == TelnetProtocol::DEL) {
- if (!command_line_.empty()) {
- command_line_.erase(--command_line_.end());
- Send(data, 1);
- }
- } else {
- // Collect command
- if (c >= ' ')
- command_line_ += c;
- // Echo character to client (for now ignore control characters).
- if (c >= ' ' || c == TelnetProtocol::CR) {
- Send(data, 1);
- }
- // Check for line termination
- if (c == TelnetProtocol::CR)
- input_state_ = EXPECTING_NEW_LINE;
- }
- }
- break;
- case EXPECTING_NEW_LINE:
- if (c == TelnetProtocol::LF) {
- Send("\n", 1);
- socket_delegate_->DidRead(this,
- command_line_.c_str(),
- command_line_.length());
- command_line_ = "";
- }
- input_state_ = NOT_IN_IAC_OR_ESC_SEQUENCE;
- break;
- case EXPECTING_COMMAND:
- // Read command, expect option.
- iac_command_ = c;
- input_state_ = EXPECTING_OPTION;
- break;
- case EXPECTING_OPTION:
- // Read option
- iac_option_ = c;
- // check for subnegoating if not done reading IAC.
- if (iac_command_ != TelnetProtocol::SB) {
- input_state_ = NOT_IN_IAC_OR_ESC_SEQUENCE;
- } else {
- input_state_ = SUBNEGOTIATION_EXPECTING_IAC;
- }
- break;
- case SUBNEGOTIATION_EXPECTING_IAC:
- // Currently ignore content of subnegotiation.
- if (c == TelnetProtocol::IAC)
- input_state_ = SUBNEGOTIATION_EXPECTING_SE;
- break;
- case SUBNEGOTIATION_EXPECTING_SE:
- // Character must be SE and subnegotiation is finished.
- input_state_ = NOT_IN_IAC_OR_ESC_SEQUENCE;
- break;
- case EXPECTING_FIRST_ESC_CHARACTER:
- if (c == '[') {
- // Expect ESC sequence content.
- input_state_ = EXPECTING_NUMBER_SEMICOLON_OR_END;
- } else if (c == 'O') {
- // VT100 "ESC O" sequence.
- input_state_ = EXPECTING_SECOND_ESC_CHARACTER;
- } else {
- // Unknown ESC sequence - ignore.
- }
- break;
- case EXPECTING_SECOND_ESC_CHARACTER:
- // Ignore ESC sequence content for now.
- input_state_ = NOT_IN_IAC_OR_ESC_SEQUENCE;
- break;
- case EXPECTING_NUMBER_SEMICOLON_OR_END:
- if (isdigit(c) || c ==';') {
- // Ignore ESC sequence content for now.
- } else {
- // Final character in ESC sequence.
- input_state_ = NOT_IN_IAC_OR_ESC_SEQUENCE;
- }
- break;
- }
-}
-
-void TelnetServer::Read() {
- char buf[kReadBufSize + 1];
- int len;
- do {
- len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0));
-
-#if defined(OS_WIN)
- if (len == SOCKET_ERROR) {
- int err = WSAGetLastError();
- if (err == WSAEWOULDBLOCK)
- break;
-#else
- if (len == SOCKET_ERROR) {
- if (errno == EWOULDBLOCK || errno == EAGAIN)
- break;
-#endif
- } else if (len == 0) {
- Close();
- } else {
- const char *data = buf;
- for (int i = 0; i < len; ++i) {
- unsigned char c = static_cast<unsigned char>(*data);
- StateMachineStep(c);
- data++;
- }
- }
- } while (len == kReadBufSize);
-}
diff --git a/net/base/telnet_server.h b/net/base/telnet_server.h
deleted file mode 100644
index 8160141..0000000
--- a/net/base/telnet_server.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 NET_BASE_TELNET_SERVER_H_
-#define NET_BASE_TELNET_SERVER_H_
-
-#include "net/base/listen_socket.h"
-
-// Implements the telnet protocol on top of the raw socket interface.
-// DidRead calls to the delegate are buffered on a line by line basis.
-// (for now this means that basic line editing is handled in this object)
-class TelnetServer : public ListenSocket {
-public:
- static TelnetServer* Listen(std::string ip, int port,
- ListenSocketDelegate *del);
-
-protected:
- void Listen() { ListenSocket::Listen(); }
- virtual void Read();
- virtual void Accept();
- virtual void SendInternal(const char* bytes, int len);
-
-private:
- enum TelnetInputState {
- // Currently not processing any IAC or ESC sequence.
- NOT_IN_IAC_OR_ESC_SEQUENCE,
- // Received carriage return (CR) expecting new line (LF).
- EXPECTING_NEW_LINE,
- // Processing IAC expecting command.
- EXPECTING_COMMAND,
- // Processing IAC expecting option.
- EXPECTING_OPTION,
- // Inside subnegoation IAC,SE will end it.
- SUBNEGOTIATION_EXPECTING_IAC,
- // Ending subnegoation expecting SE.
- SUBNEGOTIATION_EXPECTING_SE,
- // Processing ESC sequence.
- EXPECTING_FIRST_ESC_CHARACTER,
- // Processing ESC sequence with two characters.
- EXPECTING_SECOND_ESC_CHARACTER,
- // Processing "ESC [" sequence.
- EXPECTING_NUMBER_SEMICOLON_OR_END
- };
-
- TelnetServer(SOCKET s, ListenSocketDelegate* del);
- virtual ~TelnetServer();
-
- // telnet commands
- void SendIAC(int command, int option);
- void StateMachineStep(unsigned char c);
-
- TelnetInputState input_state_;
- int iac_command_; // Last command read.
- int iac_option_; // Last option read.
- std::string command_line_;
-
- DISALLOW_COPY_AND_ASSIGN(TelnetServer);
-};
-
-#endif // NET_BASE_TELNET_SERVER_H_
diff --git a/net/base/telnet_server_unittest.cc b/net/base/telnet_server_unittest.cc
deleted file mode 100644
index 1112bd2..0000000
--- a/net/base/telnet_server_unittest.cc
+++ /dev/null
@@ -1,73 +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.
-
-// Tests TelnetServer.
-
-#include "net/base/listen_socket_unittest.h"
-#include "net/base/telnet_server.h"
-#include "testing/platform_test.h"
-
-static const char* kCRLF = "\r\n";
-
-class TelnetServerTester : public ListenSocketTester {
-public:
- virtual ListenSocket* DoListen() {
- return TelnetServer::Listen("127.0.0.1", kTestPort, this);
- }
-
- virtual void SetUp() {
- ListenSocketTester::SetUp();
- // With TelnetServer, there's some control codes sent at connect time,
- // so we need to eat those to avoid affecting the subsequent tests.
- EXPECT_EQ(ClearTestSocket(), 15);
- }
-
- virtual bool Send(SOCKET sock, const std::string& str) {
- if (ListenSocketTester::Send(sock, str)) {
- // TelnetServer currently calls DidRead after a CRLF, so we need to
- // append one to the end of the data that we send.
- if (ListenSocketTester::Send(sock, kCRLF)) {
- return true;
- }
- }
- return false;
- }
-
-private:
- ~TelnetServerTester() {}
-};
-
-class TelnetServerTest: public PlatformTest {
-protected:
- TelnetServerTest() {
- tester_ = NULL;
- }
-
- virtual void SetUp() {
- PlatformTest::SetUp();
- tester_ = new TelnetServerTester();
- tester_->SetUp();
- }
-
- virtual void TearDown() {
- PlatformTest::TearDown();
- tester_->TearDown();
- tester_ = NULL;
- }
-
- scoped_refptr<TelnetServerTester> tester_;
-};
-
-// Flaky, http://crbug.com/38093.
-TEST_F(TelnetServerTest, FLAKY_ServerClientSend) {
- tester_->TestClientSend();
-}
-
-TEST_F(TelnetServerTest, ClientSendLong) {
- tester_->TestClientSendLong();
-}
-
-TEST_F(TelnetServerTest, ServerSend) {
- tester_->TestServerSend();
-}
diff --git a/net/base/test_completion_callback.h b/net/base/test_completion_callback.h
index 1d24532..b4a005b 100644
--- a/net/base/test_completion_callback.h
+++ b/net/base/test_completion_callback.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_TEST_COMPLETION_CALLBACK_H_
#define NET_BASE_TEST_COMPLETION_CALLBACK_H_
+#pragma once
#include "base/callback.h"
#include "base/message_loop.h"
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc
index 5ddcf39..a0d2794 100644
--- a/net/base/transport_security_state.cc
+++ b/net/base/transport_security_state.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.
@@ -10,8 +10,10 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/sha2.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "googleurl/src/gurl.h"
#include "net/base/dns_util.h"
@@ -29,7 +31,7 @@ void TransportSecurityState::EnableHost(const std::string& host,
return;
bool temp;
- if (isPreloadedSTS(canonicalised_host, &temp))
+ if (IsPreloadedSTS(canonicalised_host, &temp))
return;
char hashed[base::SHA256_LENGTH];
@@ -45,6 +47,12 @@ void TransportSecurityState::EnableHost(const std::string& host,
DirtyNotify();
}
+// IncludeNUL converts a char* to a std::string and includes the terminating
+// NUL in the result.
+static std::string IncludeNUL(const char* in) {
+ return std::string(in, strlen(in) + 1);
+}
+
bool TransportSecurityState::IsEnabledForHost(DomainState* result,
const std::string& host) {
const std::string canonicalised_host = CanonicaliseHost(host);
@@ -52,7 +60,7 @@ bool TransportSecurityState::IsEnabledForHost(DomainState* result,
return false;
bool include_subdomains;
- if (isPreloadedSTS(canonicalised_host, &include_subdomains)) {
+ if (IsPreloadedSTS(canonicalised_host, &include_subdomains)) {
result->created = result->expiry = base::Time::FromTimeT(0);
result->mode = DomainState::MODE_STRICT;
result->include_subdomains = include_subdomains;
@@ -64,7 +72,7 @@ bool TransportSecurityState::IsEnabledForHost(DomainState* result,
for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
char hashed_domain[base::SHA256_LENGTH];
- base::SHA256HashString(&canonicalised_host[i], &hashed_domain,
+ base::SHA256HashString(IncludeNUL(&canonicalised_host[i]), &hashed_domain,
sizeof(hashed_domain));
std::map<std::string, DomainState>::iterator j =
enabled_hosts_.find(std::string(hashed_domain, sizeof(hashed_domain)));
@@ -134,7 +142,7 @@ bool TransportSecurityState::ParseHeader(const std::string& value,
case AFTER_MAX_AGE_EQUALS:
if (IsAsciiWhitespace(*tokenizer.token_begin()))
continue;
- if (!StringToInt(tokenizer.token(), &max_age_candidate))
+ if (!base::StringToInt(tokenizer.token(), &max_age_candidate))
return false;
if (max_age_candidate < 0)
return false;
@@ -196,18 +204,17 @@ void TransportSecurityState::SetDelegate(
// This function converts the binary hashes, which we store in
// |enabled_hosts_|, to a base64 string which we can include in a JSON file.
-static std::wstring HashedDomainToExternalString(const std::string& hashed) {
+static std::string HashedDomainToExternalString(const std::string& hashed) {
std::string out;
CHECK(base::Base64Encode(hashed, &out));
- return ASCIIToWide(out);
+ return out;
}
// This inverts |HashedDomainToExternalString|, above. It turns an external
// string (from a JSON file) into an internal (binary) string.
-static std::string ExternalStringToHashedDomain(const std::wstring& external) {
- std::string external_ascii = WideToASCII(external);
+static std::string ExternalStringToHashedDomain(const std::string& external) {
std::string out;
- if (!base::Base64Decode(external_ascii, &out) ||
+ if (!base::Base64Decode(external, &out) ||
out.size() != base::SHA256_LENGTH) {
return std::string();
}
@@ -220,19 +227,19 @@ bool TransportSecurityState::Serialise(std::string* output) {
for (std::map<std::string, DomainState>::const_iterator
i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) {
DictionaryValue* state = new DictionaryValue;
- state->SetBoolean(L"include_subdomains", i->second.include_subdomains);
- state->SetReal(L"created", i->second.created.ToDoubleT());
- state->SetReal(L"expiry", i->second.expiry.ToDoubleT());
+ state->SetBoolean("include_subdomains", i->second.include_subdomains);
+ state->SetReal("created", i->second.created.ToDoubleT());
+ state->SetReal("expiry", i->second.expiry.ToDoubleT());
switch (i->second.mode) {
case DomainState::MODE_STRICT:
- state->SetString(L"mode", "strict");
+ state->SetString("mode", "strict");
break;
case DomainState::MODE_OPPORTUNISTIC:
- state->SetString(L"mode", "opportunistic");
+ state->SetString("mode", "opportunistic");
break;
case DomainState::MODE_SPDY_ONLY:
- state->SetString(L"mode", "spdy-only");
+ state->SetString("mode", "spdy-only");
break;
default:
NOTREACHED() << "DomainState with unknown mode";
@@ -271,9 +278,9 @@ bool TransportSecurityState::Deserialise(const std::string& input,
double created;
double expiry;
- if (!state->GetBoolean(L"include_subdomains", &include_subdomains) ||
- !state->GetString(L"mode", &mode_string) ||
- !state->GetReal(L"expiry", &expiry)) {
+ if (!state->GetBoolean("include_subdomains", &include_subdomains) ||
+ !state->GetString("mode", &mode_string) ||
+ !state->GetReal("expiry", &expiry)) {
continue;
}
@@ -292,7 +299,7 @@ bool TransportSecurityState::Deserialise(const std::string& input,
base::Time expiry_time = base::Time::FromDoubleT(expiry);
base::Time created_time;
- if (state->GetReal(L"created", &created)) {
+ if (state->GetReal("created", &created)) {
created_time = base::Time::FromDoubleT(created);
} else {
// We're migrating an old entry with no creation date. Make sure we
@@ -340,6 +347,9 @@ void TransportSecurityState::DeleteSince(const base::Time& time) {
DirtyNotify();
}
+TransportSecurityState::~TransportSecurityState() {
+}
+
void TransportSecurityState::DirtyNotify() {
if (delegate_)
delegate_->StateIsDirty(this);
@@ -353,7 +363,8 @@ std::string TransportSecurityState::CanonicaliseHost(const std::string& host) {
std::string new_host;
if (!DNSDomainFromDot(host, &new_host)) {
- NOTREACHED();
+ // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
+ // name is >255 bytes. However, search terms can have those properties.
return std::string();
}
@@ -380,10 +391,10 @@ std::string TransportSecurityState::CanonicaliseHost(const std::string& host) {
return new_host;
}
-// isPreloadedSTS returns true if the canonicalised hostname should always be
+// IsPreloadedSTS returns true if the canonicalised hostname should always be
// considered to have STS enabled.
// static
-bool TransportSecurityState::isPreloadedSTS(
+bool TransportSecurityState::IsPreloadedSTS(
const std::string& canonicalised_host, bool *include_subdomains) {
// In the medium term this list is likely to just be hardcoded here. This,
// slightly odd, form removes the need for additional relocations records.
@@ -395,12 +406,14 @@ bool TransportSecurityState::isPreloadedSTS(
{16, false, "\003www\006paypal\003com"},
{16, false, "\003www\006elanex\003biz"},
{12, true, "\006jottit\003com"},
+ {19, true, "\015sunshinepress\003org"},
+ {21, false, "\003www\013noisebridge\003net"},
};
static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);
for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
for (size_t j = 0; j < kNumPreloadedSTS; j++) {
- if (kPreloadedSTS[j].length == canonicalised_host.size() + 1 - i &&
+ if (kPreloadedSTS[j].length == canonicalised_host.size() - i &&
(kPreloadedSTS[j].include_subdomains || i == 0) &&
memcmp(kPreloadedSTS[j].dns_name, &canonicalised_host[i],
kPreloadedSTS[j].length) == 0) {
diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h
index 6d03776..b7db72c 100644
--- a/net/base/transport_security_state.h
+++ b/net/base/transport_security_state.h
@@ -1,20 +1,19 @@
-// 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.
#ifndef NET_BASE_TRANSPORT_SECURITY_STATE_H_
#define NET_BASE_TRANSPORT_SECURITY_STATE_H_
+#pragma once
#include <map>
#include <string>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/time.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
-
-class GURL;
namespace net {
@@ -92,9 +91,9 @@ class TransportSecurityState :
private:
friend class base::RefCountedThreadSafe<TransportSecurityState>;
- FRIEND_TEST(TransportSecurityStateTest, IsPreloaded);
+ FRIEND_TEST_ALL_PREFIXES(TransportSecurityStateTest, IsPreloaded);
- ~TransportSecurityState() {}
+ ~TransportSecurityState();
// If we have a callback configured, call it to let our serialiser know that
// our state is dirty.
@@ -109,7 +108,7 @@ class TransportSecurityState :
Delegate* delegate_;
static std::string CanonicaliseHost(const std::string& host);
- static bool isPreloadedSTS(const std::string& canonicalised_host,
+ static bool IsPreloadedSTS(const std::string& canonicalised_host,
bool* out_include_subdomains);
DISALLOW_COPY_AND_ASSIGN(TransportSecurityState);
diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc
index 00eeae4..c4a173c 100644
--- a/net/base/transport_security_state_unittest.cc
+++ b/net/base/transport_security_state_unittest.cc
@@ -305,13 +305,13 @@ TEST_F(TransportSecurityStateTest, IsPreloaded) {
TransportSecurityState::CanonicaliseHost("aypal.com");
bool b;
- EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(paypal, &b));
- EXPECT_TRUE(TransportSecurityState::isPreloadedSTS(www_paypal, &b));
+ EXPECT_FALSE(TransportSecurityState::IsPreloadedSTS(paypal, &b));
+ EXPECT_TRUE(TransportSecurityState::IsPreloadedSTS(www_paypal, &b));
EXPECT_FALSE(b);
- EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(a_www_paypal, &b));
- EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(abc_paypal, &b));
- EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(example, &b));
- EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(aypal, &b));
+ EXPECT_FALSE(TransportSecurityState::IsPreloadedSTS(a_www_paypal, &b));
+ EXPECT_FALSE(TransportSecurityState::IsPreloadedSTS(abc_paypal, &b));
+ EXPECT_FALSE(TransportSecurityState::IsPreloadedSTS(example, &b));
+ EXPECT_FALSE(TransportSecurityState::IsPreloadedSTS(aypal, &b));
}
TEST_F(TransportSecurityStateTest, Preloaded) {
@@ -332,6 +332,27 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
TransportSecurityState::DomainState::MODE_STRICT);
EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "foo.elanex.biz"));
EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "a.foo.elanex.biz"));
+
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "sunshinepress.org"));
+ EXPECT_EQ(domain_state.mode,
+ TransportSecurityState::DomainState::MODE_STRICT);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "www.sunshinepress.org"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "a.b.sunshinepress.org"));
+
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "www.noisebridge.net"));
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "noisebridge.net"));
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "foo.noisebridge.net"));
+}
+
+TEST_F(TransportSecurityStateTest, LongNames) {
+ scoped_refptr<TransportSecurityState> state(
+ new TransportSecurityState);
+ const char kLongName[] =
+ "lookupByWaveIdHashAndWaveIdIdAndWaveIdDomainAndWaveletIdIdAnd"
+ "WaveletIdDomainAndBlipBlipid";
+ TransportSecurityState::DomainState domain_state;
+ // Just checks that we don't hit a NOTREACHED.
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, kLongName));
}
} // namespace net
diff --git a/net/base/upload_data.cc b/net/base/upload_data.cc
index 198b051..774dc5c 100644
--- a/net/base/upload_data.cc
+++ b/net/base/upload_data.cc
@@ -6,16 +6,23 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "net/base/file_stream.h"
#include "net/base/net_errors.h"
namespace net {
-uint64 UploadData::GetContentLength() {
- uint64 len = 0;
- std::vector<Element>::iterator it = elements_.begin();
- for (; it != elements_.end(); ++it)
- len += (*it).GetContentLength();
- return len;
+UploadData::Element::Element()
+ : type_(TYPE_BYTES),
+ file_range_offset_(0),
+ file_range_length_(kuint64max),
+ override_content_length_(false),
+ content_length_computed_(false),
+ file_stream_(NULL) {
+}
+
+UploadData::Element::~Element() {
+ // In the common case |file__stream_| will be null.
+ delete file_stream_;
}
uint64 UploadData::Element::GetContentLength() {
@@ -24,6 +31,9 @@ uint64 UploadData::Element::GetContentLength() {
if (type_ == TYPE_BYTES)
return static_cast<uint64>(bytes_.size());
+ else if (type_ == TYPE_BLOB)
+ // The blob reference will be resolved later.
+ return 0;
DCHECK_EQ(TYPE_FILE, type_);
DCHECK(!file_stream_);
@@ -86,4 +96,47 @@ FileStream* UploadData::Element::NewFileStreamForReading() {
return file.release();
}
+UploadData::UploadData() : identifier_(0) {
+}
+
+void UploadData::AppendBytes(const char* bytes, int bytes_len) {
+ if (bytes_len > 0) {
+ elements_.push_back(Element());
+ elements_.back().SetToBytes(bytes, bytes_len);
+ }
+}
+
+void UploadData::AppendFile(const FilePath& file_path) {
+ elements_.push_back(Element());
+ elements_.back().SetToFilePath(file_path);
+}
+
+void UploadData::AppendFileRange(const FilePath& file_path,
+ uint64 offset, uint64 length,
+ const base::Time& expected_modification_time) {
+ elements_.push_back(Element());
+ elements_.back().SetToFilePathRange(file_path, offset, length,
+ expected_modification_time);
+}
+
+void UploadData::AppendBlob(const GURL& blob_url) {
+ elements_.push_back(Element());
+ elements_.back().SetToBlobUrl(blob_url);
+}
+
+uint64 UploadData::GetContentLength() {
+ uint64 len = 0;
+ std::vector<Element>::iterator it = elements_.begin();
+ for (; it != elements_.end(); ++it)
+ len += (*it).GetContentLength();
+ return len;
+}
+
+void UploadData::SetElements(const std::vector<Element>& elements) {
+ elements_ = elements;
+}
+
+UploadData::~UploadData() {
+}
+
} // namespace net
diff --git a/net/base/upload_data.h b/net/base/upload_data.h
index fe395f0..6f72162 100644
--- a/net/base/upload_data.h
+++ b/net/base/upload_data.h
@@ -4,41 +4,33 @@
#ifndef NET_BASE_UPLOAD_DATA_H_
#define NET_BASE_UPLOAD_DATA_H_
+#pragma once
#include <vector>
#include "base/basictypes.h"
#include "base/file_path.h"
-#include "base/logging.h"
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
-#include "net/base/file_stream.h"
+#include "googleurl/src/gurl.h"
#include "base/time.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
namespace net {
+class FileStream;
+
class UploadData : public base::RefCounted<UploadData> {
public:
- UploadData() : identifier_(0) {}
-
enum Type {
TYPE_BYTES,
- TYPE_FILE
+ TYPE_FILE,
+ TYPE_BLOB
};
class Element {
public:
- Element() : type_(TYPE_BYTES), file_range_offset_(0),
- file_range_length_(kuint64max),
- override_content_length_(false),
- content_length_computed_(false),
- file_stream_(NULL) {
- }
-
- ~Element() {
- // In the common case |file__stream_| will be null.
- delete file_stream_;
- }
+ Element();
+ ~Element();
Type type() const { return type_; }
const std::vector<char>& bytes() const { return bytes_; }
@@ -49,6 +41,7 @@ class UploadData : public base::RefCounted<UploadData> {
const base::Time& expected_file_modification_time() const {
return expected_file_modification_time_;
}
+ const GURL& blob_url() const { return blob_url_; }
void SetToBytes(const char* bytes, int bytes_len) {
type_ = TYPE_BYTES;
@@ -72,6 +65,13 @@ class UploadData : public base::RefCounted<UploadData> {
expected_file_modification_time_ = expected_modification_time;
}
+ // TODO(jianli): UploadData should not contain any blob reference. We need
+ // to define another structure to represent WebKit::WebHTTPBody.
+ void SetToBlobUrl(const GURL& blob_url) {
+ type_ = TYPE_BLOB;
+ blob_url_ = blob_url;
+ }
+
// Returns the byte-length of the element. For files that do not exist, 0
// is returned. This is done for consistency with Mozilla.
// Once called, this function will always return the same value.
@@ -96,34 +96,28 @@ class UploadData : public base::RefCounted<UploadData> {
uint64 file_range_offset_;
uint64 file_range_length_;
base::Time expected_file_modification_time_;
+ GURL blob_url_;
bool override_content_length_;
bool content_length_computed_;
uint64 content_length_;
FileStream* file_stream_;
- FRIEND_TEST(UploadDataStreamTest, FileSmallerThanLength);
- FRIEND_TEST(HttpNetworkTransactionTest, UploadFileSmallerThanLength);
+ FRIEND_TEST_ALL_PREFIXES(UploadDataStreamTest, FileSmallerThanLength);
+ FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest,
+ UploadFileSmallerThanLength);
};
- void AppendBytes(const char* bytes, int bytes_len) {
- if (bytes_len > 0) {
- elements_.push_back(Element());
- elements_.back().SetToBytes(bytes, bytes_len);
- }
- }
+ UploadData();
- void AppendFile(const FilePath& file_path) {
- elements_.push_back(Element());
- elements_.back().SetToFilePath(file_path);
- }
+ void AppendBytes(const char* bytes, int bytes_len);
+
+ void AppendFile(const FilePath& file_path);
void AppendFileRange(const FilePath& file_path,
uint64 offset, uint64 length,
- const base::Time& expected_modification_time) {
- elements_.push_back(Element());
- elements_.back().SetToFilePathRange(file_path, offset, length,
- expected_modification_time);
- }
+ const base::Time& expected_modification_time);
+
+ void AppendBlob(const GURL& blob_url);
// Returns the total size in bytes of the data to upload.
uint64 GetContentLength();
@@ -132,9 +126,7 @@ class UploadData : public base::RefCounted<UploadData> {
return &elements_;
}
- void set_elements(const std::vector<Element>& elements) {
- elements_ = elements;
- }
+ void SetElements(const std::vector<Element>& elements);
void swap_elements(std::vector<Element>* elements) {
elements_.swap(*elements);
@@ -149,12 +141,39 @@ class UploadData : public base::RefCounted<UploadData> {
private:
friend class base::RefCounted<UploadData>;
- ~UploadData() {}
+ ~UploadData();
std::vector<Element> elements_;
int64 identifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadData);
};
+#if defined(UNIT_TEST)
+inline bool operator==(const UploadData::Element& a,
+ const UploadData::Element& b) {
+ if (a.type() != b.type())
+ return false;
+ if (a.type() == UploadData::TYPE_BYTES)
+ return a.bytes() == b.bytes();
+ if (a.type() == UploadData::TYPE_FILE) {
+ return a.file_path() == b.file_path() &&
+ a.file_range_offset() == b.file_range_offset() &&
+ a.file_range_length() == b.file_range_length() &&
+ a.expected_file_modification_time() ==
+ b.expected_file_modification_time();
+ }
+ if (a.type() == UploadData::TYPE_BLOB)
+ return a.blob_url() == b.blob_url();
+ return false;
+}
+
+inline bool operator!=(const UploadData::Element& a,
+ const UploadData::Element& b) {
+ return !(a == b);
+}
+#endif // defined(UNIT_TEST)
+
} // namespace net
#endif // NET_BASE_UPLOAD_DATA_H_
diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc
index bc38e1b..3acf6b8 100644
--- a/net/base/upload_data_stream.cc
+++ b/net/base/upload_data_stream.cc
@@ -8,6 +8,7 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -84,7 +85,7 @@ int UploadDataStream::FillBuf() {
// Note that the expected modification time from WebKit is based on
// time_t precision. So we have to convert both to time_t to compare.
if (!element.expected_file_modification_time().is_null()) {
- file_util::FileInfo info;
+ base::PlatformFileInfo info;
if (file_util::GetFileInfo(element.file_path(), &info) &&
element.expected_file_modification_time().ToTimeT() !=
info.last_modified.ToTimeT()) {
diff --git a/net/base/upload_data_stream.h b/net/base/upload_data_stream.h
index 5e28721..0d179d2 100644
--- a/net/base/upload_data_stream.h
+++ b/net/base/upload_data_stream.h
@@ -4,12 +4,14 @@
#ifndef NET_BASE_UPLOAD_DATA_STREAM_H_
#define NET_BASE_UPLOAD_DATA_STREAM_H_
+#pragma once
-#include "net/base/file_stream.h"
+#include "base/scoped_ptr.h"
#include "net/base/upload_data.h"
namespace net {
+class FileStream;
class IOBuffer;
class UploadDataStream {
diff --git a/net/base/upload_data_stream_unittest.cc b/net/base/upload_data_stream_unittest.cc
index 92c065e..8a21ad6 100644
--- a/net/base/upload_data_stream_unittest.cc
+++ b/net/base/upload_data_stream_unittest.cc
@@ -66,7 +66,7 @@ TEST_F(UploadDataStreamTest, FileSmallerThanLength) {
element.SetToFilePath(temp_file_path);
element.SetContentLength(kFakeSize);
elements.push_back(element);
- upload_data_->set_elements(elements);
+ upload_data_->SetElements(elements);
EXPECT_EQ(kFakeSize, upload_data_->GetContentLength());
scoped_ptr<UploadDataStream> stream(
@@ -92,7 +92,7 @@ void UploadDataStreamTest::FileChangedHelper(const FilePath& file_path,
UploadData::Element element;
element.SetToFilePathRange(file_path, 1, 2, time);
elements.push_back(element);
- upload_data_->set_elements(elements);
+ upload_data_->SetElements(elements);
int error_code;
scoped_ptr<UploadDataStream> stream(
@@ -109,7 +109,7 @@ TEST_F(UploadDataStreamTest, FileChanged) {
ASSERT_EQ(kTestDataSize, file_util::WriteFile(temp_file_path,
kTestData, kTestDataSize));
- file_util::FileInfo file_info;
+ base::PlatformFileInfo file_info;
ASSERT_TRUE(file_util::GetFileInfo(temp_file_path, &file_info));
// Test file not changed.
@@ -124,4 +124,3 @@ TEST_F(UploadDataStreamTest, FileChanged) {
}
} // namespace net
-
diff --git a/net/base/winsock_init.h b/net/base/winsock_init.h
index 9608e95..3d2bcb1 100644
--- a/net/base/winsock_init.h
+++ b/net/base/winsock_init.h
@@ -7,6 +7,7 @@
#ifndef NET_BASE_WINSOCK_INIT_H_
#define NET_BASE_WINSOCK_INIT_H_
+#pragma once
namespace net {
diff --git a/net/base/x509_cert_types.cc b/net/base/x509_cert_types.cc
index 8f7a2ae..5dfc57a 100644
--- a/net/base/x509_cert_types.cc
+++ b/net/base/x509_cert_types.cc
@@ -36,6 +36,13 @@ bool match(const std::vector<std::string> &rdn1,
return true;
}
+CertPrincipal::CertPrincipal() {
+}
+
+CertPrincipal::CertPrincipal(const std::string& name) : common_name(name) {}
+
+CertPrincipal::~CertPrincipal() {
+}
bool CertPrincipal::Matches(const CertPrincipal& against) const {
return match(common_name, against.common_name) &&
@@ -49,6 +56,17 @@ bool CertPrincipal::Matches(const CertPrincipal& against) const {
match(domain_components, against.domain_components);
}
+std::string CertPrincipal::GetDisplayName() const {
+ if (!common_name.empty())
+ return common_name;
+ if (!organization_names.empty())
+ return organization_names[0];
+ if (!organization_unit_names.empty())
+ return organization_unit_names[0];
+
+ return std::string();
+}
+
std::ostream& operator<<(std::ostream& s, const CertPrincipal& p) {
s << "CertPrincipal[";
if (!p.common_name.empty())
@@ -70,6 +88,12 @@ std::ostream& operator<<(std::ostream& s, const CertPrincipal& p) {
return s << "]";
}
+CertPolicy::CertPolicy() {
+}
+
+CertPolicy::~CertPolicy() {
+}
+
CertPolicy::Judgment CertPolicy::Check(
X509Certificate* cert) const {
// It shouldn't matter which set we check first, but we check denied first
diff --git a/net/base/x509_cert_types.h b/net/base/x509_cert_types.h
index ad3ea2d..7723c22 100644
--- a/net/base/x509_cert_types.h
+++ b/net/base/x509_cert_types.h
@@ -1,15 +1,15 @@
-// Copyright (c) 2007-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.
#ifndef NET_BASE_X509_CERT_TYPES_H_
#define NET_BASE_X509_CERT_TYPES_H_
+#pragma once
#include <string.h>
#include <functional>
#include <iosfwd>
-#include <map>
#include <set>
#include <string>
#include <vector>
@@ -42,8 +42,7 @@ struct SHA1Fingerprint {
unsigned char data[20];
};
-class SHA1FingerprintLessThan
- : public std::binary_function<SHA1Fingerprint, SHA1Fingerprint, bool> {
+class SHA1FingerprintLessThan {
public:
bool operator() (const SHA1Fingerprint& lhs,
const SHA1Fingerprint& rhs) const {
@@ -53,8 +52,9 @@ class SHA1FingerprintLessThan
// CertPrincipal represents the issuer or subject field of an X.509 certificate.
struct CertPrincipal {
- CertPrincipal() { }
- explicit CertPrincipal(const std::string& name) : common_name(name) { }
+ CertPrincipal();
+ explicit CertPrincipal(const std::string& name);
+ ~CertPrincipal();
// Parses a BER-format DistinguishedName.
bool ParseDistinguishedName(const void* ber_name_data, size_t length);
@@ -68,6 +68,10 @@ struct CertPrincipal {
// where "match" is defined in RFC 5280 sec. 7.1.
bool Matches(const CertPrincipal& against) const;
+ // Returns a name that can be used to represent the issuer. It tries in this
+ // order: CN, O and OU and returns the first non-empty one found.
+ std::string GetDisplayName() const;
+
// The different attributes for a principal. They may be "".
// Note that some of them can have several values.
@@ -101,6 +105,9 @@ class CertPolicy {
DENIED,
};
+ CertPolicy();
+ ~CertPolicy();
+
// Returns the judgment this policy makes about this certificate.
Judgment Check(X509Certificate* cert) const;
diff --git a/net/base/x509_cert_types_mac.cc b/net/base/x509_cert_types_mac.cc
index 504dde5..14d5eee 100644
--- a/net/base/x509_cert_types_mac.cc
+++ b/net/base/x509_cert_types_mac.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.
@@ -235,7 +235,7 @@ bool CertPrincipal::ParseDistinguishedName(const void* ber_name_data,
return true;
}
-
+
// SUBROUTINES:
static std::string DataToString(CSSM_DATA data) {
diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc
index 7f607ea..a030c60 100644
--- a/net/base/x509_certificate.cc
+++ b/net/base/x509_certificate.cc
@@ -15,7 +15,9 @@
#include "base/histogram.h"
#include "base/logging.h"
#include "base/singleton.h"
+#include "base/string_piece.h"
#include "base/time.h"
+#include "net/base/pem_tokenizer.h"
namespace net {
@@ -31,6 +33,18 @@ bool IsNullFingerprint(const SHA1Fingerprint& fingerprint) {
return true;
}
+// Indicates the order to use when trying to decode binary data, which is
+// based on (speculation) as to what will be most common -> least common
+const X509Certificate::Format kFormatDecodePriority[] = {
+ X509Certificate::FORMAT_SINGLE_CERTIFICATE,
+ X509Certificate::FORMAT_PKCS7
+};
+
+// The PEM block header used for DER certificates
+const char kCertificateHeader[] = "CERTIFICATE";
+// The PEM block header used for PKCS#7 data
+const char kPKCS7Header[] = "PKCS7";
+
} // namespace
// static
@@ -189,6 +203,83 @@ X509Certificate* X509Certificate::CreateFromBytes(const char* data,
return cert;
}
+CertificateList X509Certificate::CreateCertificateListFromBytes(
+ const char* data, int length, int format) {
+ OSCertHandles certificates;
+
+ // Check to see if it is in a PEM-encoded form. This check is performed
+ // first, as both OS X and NSS will both try to convert if they detect
+ // PEM encoding, except they don't do it consistently between the two.
+ base::StringPiece data_string(data, length);
+ std::vector<std::string> pem_headers;
+
+ // To maintain compatibility with NSS/Firefox, CERTIFICATE is a universally
+ // valid PEM block header for any format.
+ pem_headers.push_back(kCertificateHeader);
+ if (format & FORMAT_PKCS7)
+ pem_headers.push_back(kPKCS7Header);
+
+ PEMTokenizer pem_tok(data_string, pem_headers);
+ while (pem_tok.GetNext()) {
+ std::string decoded(pem_tok.data());
+
+ OSCertHandle handle = NULL;
+ if (format & FORMAT_PEM_CERT_SEQUENCE)
+ handle = CreateOSCertHandleFromBytes(decoded.c_str(), decoded.size());
+ if (handle != NULL) {
+ // Parsed a DER encoded certificate. All PEM blocks that follow must
+ // also be DER encoded certificates wrapped inside of PEM blocks.
+ format = FORMAT_PEM_CERT_SEQUENCE;
+ certificates.push_back(handle);
+ continue;
+ }
+
+ // If the first block failed to parse as a DER certificate, and
+ // formats other than PEM are acceptable, check to see if the decoded
+ // data is one of the accepted formats.
+ if (format & ~FORMAT_PEM_CERT_SEQUENCE) {
+ for (size_t i = 0; certificates.empty() &&
+ i < arraysize(kFormatDecodePriority); ++i) {
+ if (format & kFormatDecodePriority[i]) {
+ certificates = CreateOSCertHandlesFromBytes(decoded.c_str(),
+ decoded.size(), kFormatDecodePriority[i]);
+ }
+ }
+ }
+
+ // Stop parsing after the first block for any format but a sequence of
+ // PEM-encoded DER certificates. The case of FORMAT_PEM_CERT_SEQUENCE
+ // is handled above, and continues processing until a certificate fails
+ // to parse.
+ break;
+ }
+
+ // Try each of the formats, in order of parse preference, to see if |data|
+ // contains the binary representation of a Format, if it failed to parse
+ // as a PEM certificate/chain.
+ for (size_t i = 0; certificates.empty() &&
+ i < arraysize(kFormatDecodePriority); ++i) {
+ if (format & kFormatDecodePriority[i])
+ certificates = CreateOSCertHandlesFromBytes(data, length,
+ kFormatDecodePriority[i]);
+ }
+
+ CertificateList results;
+ // No certificates parsed.
+ if (certificates.empty())
+ return results;
+
+ for (OSCertHandles::iterator it = certificates.begin();
+ it != certificates.end(); ++it) {
+ X509Certificate* result = CreateFromHandle(*it, SOURCE_LONE_CERT_IMPORT,
+ OSCertHandles());
+ results.push_back(scoped_refptr<X509Certificate>(result));
+ FreeOSCertHandle(*it);
+ }
+
+ return results;
+}
+
X509Certificate::X509Certificate(OSCertHandle cert_handle,
Source source,
const OSCertHandles& intermediates)
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h
index 4d65919..8c9e534 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -4,16 +4,17 @@
#ifndef NET_BASE_X509_CERTIFICATE_H_
#define NET_BASE_X509_CERTIFICATE_H_
+#pragma once
#include <string.h>
#include <string>
#include <vector>
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/time.h"
#include "net/base/x509_cert_types.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -35,6 +36,8 @@ namespace net {
class CertVerifyResult;
+typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
+
// X509Certificate represents an X.509 certificate used by SSL.
class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
public:
@@ -77,6 +80,28 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
VERIFY_EV_CERT = 1 << 1,
};
+ enum Format {
+ // The data contains a single DER-encoded certificate, or a PEM-encoded
+ // DER certificate with the PEM encoding block name of "CERTIFICATE".
+ // Any subsequent blocks will be ignored.
+ FORMAT_SINGLE_CERTIFICATE = 1 << 0,
+
+ // The data contains a sequence of one or more PEM-encoded, DER
+ // certificates, with the PEM encoding block name of "CERTIFICATE".
+ // All PEM blocks will be parsed, until the first error is encountered.
+ FORMAT_PEM_CERT_SEQUENCE = 1 << 1,
+
+ // The data contains a PKCS#7 SignedData structure, whose certificates
+ // member is to be used to initialize the certificate and intermediates.
+ // The data may further be encoded using PEM, specifying block names of
+ // either "PKCS7" or "CERTIFICATE".
+ FORMAT_PKCS7 = 1 << 2,
+
+ // Automatically detect the format.
+ FORMAT_AUTO = FORMAT_SINGLE_CERTIFICATE | FORMAT_PEM_CERT_SEQUENCE |
+ FORMAT_PKCS7,
+ };
+
// Create an X509Certificate from a handle to the certificate object in the
// underlying crypto library. |source| specifies where |cert_handle| comes
// from. Given two certificate handles for the same certificate, our
@@ -89,7 +114,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
Source source,
const OSCertHandles& intermediates);
- // Create an X509Certificate from the BER-encoded representation.
+ // Create an X509Certificate from the DER-encoded representation.
// Returns NULL on failure.
//
// The returned pointer must be stored in a scoped_refptr<X509Certificate>.
@@ -104,6 +129,14 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
static X509Certificate* CreateFromPickle(const Pickle& pickle,
void** pickle_iter);
+ // Parses all of the certificates possible from |data|. |format| is a
+ // bit-wise OR of Format, indicating the possible formats the
+ // certificates may have been serialized as. If an error occurs, an empty
+ // collection will be returned.
+ static CertificateList CreateCertificateListFromBytes(const char* data,
+ int length,
+ int format);
+
// Creates a X509Certificate from the ground up. Used by tests that simulate
// SSL connections.
X509Certificate(const std::string& subject, const std::string& issuer,
@@ -208,6 +241,11 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
static OSCertHandle CreateOSCertHandleFromBytes(const char* data,
int length);
+ // Creates all possible OS certificate handles from |data| encoded in a
+ // specific |format|. Returns an empty collection on failure.
+ static OSCertHandles CreateOSCertHandlesFromBytes(
+ const char* data, int length, Format format);
+
// Duplicates (or adds a reference to) an OS certificate handle.
static OSCertHandle DupOSCertHandle(OSCertHandle cert_handle);
@@ -216,8 +254,8 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
private:
friend class base::RefCountedThreadSafe<X509Certificate>;
- FRIEND_TEST(X509CertificateTest, Cache);
- FRIEND_TEST(X509CertificateTest, IntermediateCertificates);
+ FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, Cache);
+ FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, IntermediateCertificates);
class Cache;
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index ed46adc..e4c5c7f 100644
--- a/net/base/x509_certificate_mac.cc
+++ b/net/base/x509_certificate_mac.cc
@@ -8,9 +8,9 @@
#include <Security/Security.h>
#include <time.h>
-#include "base/scoped_cftyperef.h"
#include "base/logging.h"
#include "base/pickle.h"
+#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#include "net/base/cert_status_flags.h"
#include "net/base/cert_verify_result.h"
@@ -372,6 +372,74 @@ bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage* usage,
return false;
}
+// Test that a given |cert_handle| is actually a valid X.509 certificate, and
+// return true if it is.
+//
+// On OS X, SecCertificateCreateFromData() does not return any errors if
+// called with invalid data, as long as data is present. The actual decoding
+// of the certificate does not happen until an API that requires a CSSM
+// handle is called. While SecCertificateGetCLHandle is the most likely
+// candidate, as it performs the parsing, it does not check whether the
+// parsing was actually successful. Instead, SecCertificateGetSubject is
+// used (supported since 10.3), as a means to check that the certificate
+// parsed as a valid X.509 certificate.
+bool IsValidOSCertHandle(SecCertificateRef cert_handle) {
+ const CSSM_X509_NAME* sanity_check = NULL;
+ OSStatus status = SecCertificateGetSubject(cert_handle, &sanity_check);
+ return status == noErr && sanity_check;
+}
+
+// Parses |data| of length |length|, attempting to decode it as the specified
+// |format|. If |data| is in the specified format, any certificates contained
+// within are stored into |output|.
+void AddCertificatesFromBytes(const char* data, size_t length,
+ SecExternalFormat format,
+ X509Certificate::OSCertHandles* output) {
+ SecExternalFormat input_format = format;
+ scoped_cftyperef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data),
+ length, kCFAllocatorNull));
+
+ CFArrayRef items = NULL;
+ OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format,
+ NULL, 0, NULL, NULL, &items);
+ if (status) {
+ DLOG(WARNING) << status << " Unable to import items from data of length "
+ << length;
+ return;
+ }
+
+ scoped_cftyperef<CFArrayRef> scoped_items(items);
+ CFTypeID cert_type_id = SecCertificateGetTypeID();
+
+ for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
+ SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(items, i)));
+
+ // While inputFormat implies only certificates will be imported, if/when
+ // other formats (eg: PKCS#12) are supported, this may also include
+ // private keys or other items types, so filter appropriately.
+ if (CFGetTypeID(item) == cert_type_id) {
+ SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(item);
+ // OS X ignores |input_format| if it detects that |local_data| is PEM
+ // encoded, attempting to decode data based on internal rules for PEM
+ // block headers. If a PKCS#7 blob is encoded with a PEM block of
+ // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
+ // based on the decoded data. If this happens, the certificate should
+ // not be included in |output|. Because |output| is empty,
+ // CreateCertificateListfromBytes will use PEMTokenizer to decode the
+ // data. When called again with the decoded data, OS X will honor
+ // |input_format|, causing decode to succeed. On OS X 10.6, the data
+ // is properly decoded as a PKCS#7, whether PEM or not, which avoids
+ // the need to fallback to internal decoding.
+ if (IsValidOSCertHandle(cert)) {
+ CFRetain(cert);
+ output->push_back(cert);
+ }
+ }
+ }
+}
+
} // namespace
void X509Certificate::Initialize() {
@@ -669,15 +737,41 @@ X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
OSCertHandle cert_handle = NULL;
OSStatus status = SecCertificateCreateFromData(&cert_data,
CSSM_CERT_X_509v3,
- CSSM_CERT_ENCODING_BER,
+ CSSM_CERT_ENCODING_DER,
&cert_handle);
- if (status)
+ if (status != noErr)
return NULL;
-
+ if (!IsValidOSCertHandle(cert_handle)) {
+ CFRelease(cert_handle);
+ return NULL;
+ }
return cert_handle;
}
// static
+X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
+ const char* data, int length, Format format) {
+ OSCertHandles results;
+
+ switch (format) {
+ case FORMAT_SINGLE_CERTIFICATE: {
+ OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
+ if (handle)
+ results.push_back(handle);
+ break;
+ }
+ case FORMAT_PKCS7:
+ AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
+ break;
+ default:
+ NOTREACHED() << "Certificate format " << format << " unimplemented";
+ break;
+ }
+
+ return results;
+}
+
+// static
X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
OSCertHandle handle) {
if (!handle)
@@ -767,7 +861,7 @@ bool X509Certificate::IsIssuedBy(
X509Certificate::SOURCE_LONE_CERT_IMPORT,
X509Certificate::OSCertHandles());
for (unsigned j = 0; j < valid_issuers.size(); j++) {
- if (cert->subject().Matches(valid_issuers[j]))
+ if (cert->issuer().Matches(valid_issuers[j]))
return true;
}
}
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index 8eb337f..0088002 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -16,6 +16,7 @@
#include "base/logging.h"
#include "base/pickle.h"
+#include "base/scoped_ptr.h"
#include "base/time.h"
#include "base/nss_util.h"
#include "net/base/cert_status_flags.h"
@@ -27,38 +28,6 @@ namespace net {
namespace {
-class ScopedCERTCertificate {
- public:
- explicit ScopedCERTCertificate(CERTCertificate* cert)
- : cert_(cert) {}
-
- ~ScopedCERTCertificate() {
- if (cert_)
- CERT_DestroyCertificate(cert_);
- }
-
- private:
- CERTCertificate* cert_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificate);
-};
-
-class ScopedCERTCertList {
- public:
- explicit ScopedCERTCertList(CERTCertList* cert_list)
- : cert_list_(cert_list) {}
-
- ~ScopedCERTCertList() {
- if (cert_list_)
- CERT_DestroyCertList(cert_list_);
- }
-
- private:
- CERTCertList* cert_list_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertList);
-};
-
class ScopedCERTCertificatePolicies {
public:
explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
@@ -341,6 +310,31 @@ SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,
bool use_crl = check_revocation;
bool use_ocsp = check_revocation;
+ // These CAs have multiple keys, which trigger two bugs in NSS's CRL code.
+ // 1. NSS may use one key to verify a CRL signed with another key,
+ // incorrectly concluding that the CRL's signature is invalid.
+ // Hopefully this bug will be fixed in NSS 3.12.9.
+ // 2. NSS considers all certificates issued by the CA as revoked when it
+ // receives a CRL with an invalid signature. This overly strict policy
+ // has been relaxed in NSS 3.12.7. See
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=562542.
+ // So we have to turn off CRL checking for these CAs. See
+ // http://crbug.com/55695.
+ static const char* const kMultipleKeyCA[] = {
+ "CN=Microsoft Secure Server Authority,"
+ "DC=redmond,DC=corp,DC=microsoft,DC=com",
+ "CN=Microsoft Secure Server Authority",
+ };
+
+ if (!NSS_VersionCheck("3.12.7")) {
+ for (size_t i = 0; i < arraysize(kMultipleKeyCA); ++i) {
+ if (strcmp(cert_handle->issuerName, kMultipleKeyCA[i]) == 0) {
+ use_crl = false;
+ break;
+ }
+ }
+ }
+
PRUint64 revocation_method_flags =
CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
CERT_REV_M_ALLOW_NETWORK_FETCHING |
@@ -571,6 +565,22 @@ bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
return false;
}
+SECStatus PR_CALLBACK
+CollectCertsCallback(void* arg, SECItem** certs, int num_certs) {
+ X509Certificate::OSCertHandles* results =
+ reinterpret_cast<X509Certificate::OSCertHandles*>(arg);
+
+ for (int i = 0; i < num_certs; ++i) {
+ X509Certificate::OSCertHandle handle =
+ X509Certificate::CreateOSCertHandleFromBytes(
+ reinterpret_cast<char*>(certs[i]->data), certs[i]->len);
+ if (handle)
+ results->push_back(handle);
+ }
+
+ return SECSuccess;
+}
+
} // namespace
void X509Certificate::Initialize() {
@@ -605,10 +615,6 @@ void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
// Compare with CERT_VerifyCertName().
GetCertSubjectAltNamesOfType(cert_handle_, certDNSName, dns_names);
- // TODO(port): suppress nss's support of the obsolete extension
- // SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME
- // by providing our own authCertificate callback.
-
if (dns_names->empty())
dns_names->push_back(subject_.common_name);
}
@@ -721,21 +727,59 @@ bool X509Certificate::VerifyEV() const {
// static
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data, int length) {
+ if (length < 0)
+ return NULL;
+
base::EnsureNSSInit();
if (!NSS_IsInitialized())
return NULL;
- // Make a copy of |data| since CERT_DecodeCertPackage might modify it.
- char* data_copy = new char[length];
- memcpy(data_copy, data, length);
+ SECItem der_cert;
+ der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
+ der_cert.len = length;
+ der_cert.type = siDERCertBuffer;
// Parse into a certificate structure.
- CERTCertificate* cert = CERT_DecodeCertFromPackage(data_copy, length);
- delete [] data_copy;
- if (!cert)
- LOG(ERROR) << "Couldn't parse a certificate from " << length << " bytes";
- return cert;
+ return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL,
+ PR_FALSE, PR_TRUE);
+}
+
+// static
+X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
+ const char* data, int length, Format format) {
+ OSCertHandles results;
+ if (length < 0)
+ return results;
+
+ base::EnsureNSSInit();
+
+ if (!NSS_IsInitialized())
+ return results;
+
+ switch (format) {
+ case FORMAT_SINGLE_CERTIFICATE: {
+ OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
+ if (handle)
+ results.push_back(handle);
+ break;
+ }
+ case FORMAT_PKCS7: {
+ // Make a copy since CERT_DecodeCertPackage may modify it
+ std::vector<char> data_copy(data, data + length);
+
+ SECStatus result = CERT_DecodeCertPackage(&data_copy[0],
+ length, CollectCertsCallback, &results);
+ if (result != SECSuccess)
+ results.clear();
+ break;
+ }
+ default:
+ NOTREACHED() << "Certificate format " << format << " unimplemented";
+ break;
+ }
+
+ return results;
}
// static
diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc
index 63eec15..e1319d7 100644
--- a/net/base/x509_certificate_unittest.cc
+++ b/net/base/x509_certificate_unittest.cc
@@ -29,8 +29,6 @@ using base::Time;
namespace net {
-namespace {
-
// Certificates for test data. They're obtained with:
//
// $ openssl s_client -connect [host]:443 -showcerts > /tmp/host.pem < /dev/null
@@ -76,6 +74,93 @@ unsigned char unosoft_hu_fingerprint[] = {
0x25, 0x66, 0xf2, 0xec, 0x8b, 0x0f, 0xbf, 0xd8
};
+// The fingerprint of the Google certificate used in the parsing tests,
+// which is newer than the one included in the x509_certificate_data.h
+unsigned char google_parse_fingerprint[] = {
+ 0x40, 0x50, 0x62, 0xe5, 0xbe, 0xfd, 0xe4, 0xaf, 0x97, 0xe9, 0x38, 0x2a,
+ 0xf1, 0x6c, 0xc8, 0x7c, 0x8f, 0xb7, 0xc4, 0xe2
+};
+
+// The fingerprint for the Thawte SGC certificate
+unsigned char thawte_parse_fingerprint[] = {
+ 0xec, 0x07, 0x10, 0x03, 0xd8, 0xf5, 0xa3, 0x7f, 0x42, 0xc4, 0x55, 0x7f,
+ 0x65, 0x6a, 0xae, 0x86, 0x65, 0xfa, 0x4b, 0x02
+};
+
+// Dec 18 00:00:00 2009 GMT
+const double kGoogleParseValidFrom = 1261094400;
+// Dec 18 23:59:59 2011 GMT
+const double kGoogleParseValidTo = 1324252799;
+
+struct CertificateFormatTestData {
+ const char* file_name;
+ X509Certificate::Format format;
+ unsigned char* chain_fingerprints[3];
+};
+
+const CertificateFormatTestData FormatTestData[] = {
+ // DER Parsing - single certificate, DER encoded
+ { "google.single.der", X509Certificate::FORMAT_SINGLE_CERTIFICATE,
+ { google_parse_fingerprint,
+ NULL, } },
+ // DER parsing - single certificate, PEM encoded
+ { "google.single.pem", X509Certificate::FORMAT_SINGLE_CERTIFICATE,
+ { google_parse_fingerprint,
+ NULL, } },
+ // PEM parsing - single certificate, PEM encoded with a PEB of
+ // "CERTIFICATE"
+ { "google.single.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE,
+ { google_parse_fingerprint,
+ NULL, } },
+ // PEM parsing - sequence of certificates, PEM encoded with a PEB of
+ // "CERTIFICATE"
+ { "google.chain.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+ // PKCS#7 parsing - "degenerate" SignedData collection of certificates, DER
+ // encoding
+ { "google.binary.p7b", X509Certificate::FORMAT_PKCS7,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+ // PKCS#7 parsing - "degenerate" SignedData collection of certificates, PEM
+ // encoded with a PEM PEB of "CERTIFICATE"
+ { "google.pem_cert.p7b", X509Certificate::FORMAT_PKCS7,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+ // PKCS#7 parsing - "degenerate" SignedData collection of certificates, PEM
+ // encoded with a PEM PEB of "PKCS7"
+ { "google.pem_pkcs7.p7b", X509Certificate::FORMAT_PKCS7,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+ // All of the above, this time using auto-detection
+ { "google.single.der", X509Certificate::FORMAT_AUTO,
+ { google_parse_fingerprint,
+ NULL, } },
+ { "google.single.pem", X509Certificate::FORMAT_AUTO,
+ { google_parse_fingerprint,
+ NULL, } },
+ { "google.chain.pem", X509Certificate::FORMAT_AUTO,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+ { "google.binary.p7b", X509Certificate::FORMAT_AUTO,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+ { "google.pem_cert.p7b", X509Certificate::FORMAT_AUTO,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+ { "google.pem_pkcs7.p7b", X509Certificate::FORMAT_AUTO,
+ { google_parse_fingerprint,
+ thawte_parse_fingerprint,
+ NULL, } },
+};
+
// Returns a FilePath object representing the src/net/data/ssl/certificates
// directory in the source tree.
FilePath GetTestCertsDirectory() {
@@ -100,12 +185,22 @@ X509Certificate* ImportCertFromFile(const FilePath& certs_dir,
return X509Certificate::CreateFromBytes(cert_data.data(), cert_data.size());
}
-} // namespace
-
-TEST(X509CertificateTest, GoogleCertParsing) {
- scoped_refptr<X509Certificate> google_cert = X509Certificate::CreateFromBytes(
- reinterpret_cast<const char*>(google_der), sizeof(google_der));
+CertificateList CreateCertificateListFromFile(
+ const FilePath& certs_dir,
+ const std::string& cert_file,
+ int format) {
+ FilePath cert_path = certs_dir.AppendASCII(cert_file);
+ std::string cert_data;
+ if (!file_util::ReadFileToString(cert_path, &cert_data))
+ return CertificateList();
+ return X509Certificate::CreateCertificateListFromBytes(cert_data.data(),
+ cert_data.size(),
+ format);
+}
+void CheckGoogleCert(const scoped_refptr<X509Certificate>& google_cert,
+ unsigned char* expected_fingerprint,
+ double valid_from, double valid_to) {
ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
const CertPrincipal& subject = google_cert->subject();
@@ -114,7 +209,7 @@ TEST(X509CertificateTest, GoogleCertParsing) {
EXPECT_EQ("California", subject.state_or_province_name);
EXPECT_EQ("US", subject.country_name);
EXPECT_EQ(0U, subject.street_addresses.size());
- EXPECT_EQ(1U, subject.organization_names.size());
+ ASSERT_EQ(1U, subject.organization_names.size());
EXPECT_EQ("Google Inc", subject.organization_names[0]);
EXPECT_EQ(0U, subject.organization_unit_names.size());
EXPECT_EQ(0U, subject.domain_components.size());
@@ -125,25 +220,25 @@ TEST(X509CertificateTest, GoogleCertParsing) {
EXPECT_EQ("", issuer.state_or_province_name);
EXPECT_EQ("ZA", issuer.country_name);
EXPECT_EQ(0U, issuer.street_addresses.size());
- EXPECT_EQ(1U, issuer.organization_names.size());
+ ASSERT_EQ(1U, issuer.organization_names.size());
EXPECT_EQ("Thawte Consulting (Pty) Ltd.", issuer.organization_names[0]);
EXPECT_EQ(0U, issuer.organization_unit_names.size());
EXPECT_EQ(0U, issuer.domain_components.size());
// Use DoubleT because its epoch is the same on all platforms
const Time& valid_start = google_cert->valid_start();
- EXPECT_EQ(1238192407, valid_start.ToDoubleT()); // Mar 27 22:20:07 2009 GMT
+ EXPECT_EQ(valid_from, valid_start.ToDoubleT());
const Time& valid_expiry = google_cert->valid_expiry();
- EXPECT_EQ(1269728407, valid_expiry.ToDoubleT()); // Mar 27 22:20:07 2010 GMT
+ EXPECT_EQ(valid_to, valid_expiry.ToDoubleT());
const SHA1Fingerprint& fingerprint = google_cert->fingerprint();
for (size_t i = 0; i < 20; ++i)
- EXPECT_EQ(google_fingerprint[i], fingerprint.data[i]);
+ EXPECT_EQ(expected_fingerprint[i], fingerprint.data[i]);
std::vector<std::string> dns_names;
google_cert->GetDNSNames(&dns_names);
- EXPECT_EQ(1U, dns_names.size());
+ ASSERT_EQ(1U, dns_names.size());
EXPECT_EQ("www.google.com", dns_names[0]);
#if TEST_EV
@@ -156,6 +251,16 @@ TEST(X509CertificateTest, GoogleCertParsing) {
#endif
}
+TEST(X509CertificateTest, GoogleCertParsing) {
+ scoped_refptr<X509Certificate> google_cert =
+ X509Certificate::CreateFromBytes(
+ reinterpret_cast<const char*>(google_der), sizeof(google_der));
+
+ CheckGoogleCert(google_cert, google_fingerprint,
+ 1238192407, // Mar 27 22:20:07 2009 GMT
+ 1269728407); // Mar 27 22:20:07 2010 GMT
+}
+
TEST(X509CertificateTest, WebkitCertParsing) {
scoped_refptr<X509Certificate> webkit_cert = X509Certificate::CreateFromBytes(
reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der));
@@ -167,9 +272,9 @@ TEST(X509CertificateTest, WebkitCertParsing) {
EXPECT_EQ("California", subject.state_or_province_name);
EXPECT_EQ("US", subject.country_name);
EXPECT_EQ(0U, subject.street_addresses.size());
- EXPECT_EQ(1U, subject.organization_names.size());
+ ASSERT_EQ(1U, subject.organization_names.size());
EXPECT_EQ("Apple Inc.", subject.organization_names[0]);
- EXPECT_EQ(1U, subject.organization_unit_names.size());
+ ASSERT_EQ(1U, subject.organization_unit_names.size());
EXPECT_EQ("Mac OS Forge", subject.organization_unit_names[0]);
EXPECT_EQ(0U, subject.domain_components.size());
@@ -179,9 +284,9 @@ TEST(X509CertificateTest, WebkitCertParsing) {
EXPECT_EQ("Arizona", issuer.state_or_province_name);
EXPECT_EQ("US", issuer.country_name);
EXPECT_EQ(0U, issuer.street_addresses.size());
- EXPECT_EQ(1U, issuer.organization_names.size());
+ ASSERT_EQ(1U, issuer.organization_names.size());
EXPECT_EQ("GoDaddy.com, Inc.", issuer.organization_names[0]);
- EXPECT_EQ(1U, issuer.organization_unit_names.size());
+ ASSERT_EQ(1U, issuer.organization_unit_names.size());
EXPECT_EQ("http://certificates.godaddy.com/repository",
issuer.organization_unit_names[0]);
EXPECT_EQ(0U, issuer.domain_components.size());
@@ -199,7 +304,7 @@ TEST(X509CertificateTest, WebkitCertParsing) {
std::vector<std::string> dns_names;
webkit_cert->GetDNSNames(&dns_names);
- EXPECT_EQ(2U, dns_names.size());
+ ASSERT_EQ(2U, dns_names.size());
EXPECT_EQ("*.webkit.org", dns_names[0]);
EXPECT_EQ("webkit.org", dns_names[1]);
@@ -224,7 +329,7 @@ TEST(X509CertificateTest, ThawteCertParsing) {
EXPECT_EQ("California", subject.state_or_province_name);
EXPECT_EQ("US", subject.country_name);
EXPECT_EQ(0U, subject.street_addresses.size());
- EXPECT_EQ(1U, subject.organization_names.size());
+ ASSERT_EQ(1U, subject.organization_names.size());
EXPECT_EQ("Thawte Inc", subject.organization_names[0]);
EXPECT_EQ(0U, subject.organization_unit_names.size());
EXPECT_EQ(0U, subject.domain_components.size());
@@ -235,9 +340,9 @@ TEST(X509CertificateTest, ThawteCertParsing) {
EXPECT_EQ("", issuer.state_or_province_name);
EXPECT_EQ("US", issuer.country_name);
EXPECT_EQ(0U, issuer.street_addresses.size());
- EXPECT_EQ(1U, issuer.organization_names.size());
+ ASSERT_EQ(1U, issuer.organization_names.size());
EXPECT_EQ("thawte, Inc.", issuer.organization_names[0]);
- EXPECT_EQ(1U, issuer.organization_unit_names.size());
+ ASSERT_EQ(1U, issuer.organization_unit_names.size());
EXPECT_EQ("Terms of use at https://www.thawte.com/cps (c)06",
issuer.organization_unit_names[0]);
EXPECT_EQ(0U, issuer.domain_components.size());
@@ -255,7 +360,7 @@ TEST(X509CertificateTest, ThawteCertParsing) {
std::vector<std::string> dns_names;
thawte_cert->GetDNSNames(&dns_names);
- EXPECT_EQ(1U, dns_names.size());
+ ASSERT_EQ(1U, dns_names.size());
EXPECT_EQ("www.thawte.com", dns_names[0]);
#if TEST_EV
@@ -528,4 +633,99 @@ TEST(X509CertificateTest, IntermediateCertificates) {
}
#endif
+#if defined(OS_MACOSX)
+TEST(X509CertificateTest, IsIssuedBy) {
+ FilePath certs_dir = GetTestCertsDirectory();
+
+ // Test a client certificate from MIT.
+ scoped_refptr<X509Certificate> mit_davidben_cert =
+ ImportCertFromFile(certs_dir, "mit.davidben.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), mit_davidben_cert);
+
+ CertPrincipal mit_issuer;
+ mit_issuer.country_name = "US";
+ mit_issuer.state_or_province_name = "Massachusetts";
+ mit_issuer.organization_names.push_back(
+ "Massachusetts Institute of Technology");
+ mit_issuer.organization_unit_names.push_back("Client CA v1");
+
+ // IsIssuedBy should return true even if it cannot build a chain
+ // with that principal.
+ std::vector<CertPrincipal> mit_issuers(1, mit_issuer);
+ EXPECT_TRUE(mit_davidben_cert->IsIssuedBy(mit_issuers));
+
+ // Test a client certificate from FOAF.ME.
+ scoped_refptr<X509Certificate> foaf_me_chromium_test_cert =
+ ImportCertFromFile(certs_dir, "foaf.me.chromium-test-cert.der");
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), foaf_me_chromium_test_cert);
+
+ CertPrincipal foaf_issuer;
+ foaf_issuer.common_name = "FOAF.ME";
+ foaf_issuer.locality_name = "Wimbledon";
+ foaf_issuer.state_or_province_name = "LONDON";
+ foaf_issuer.country_name = "GB";
+ foaf_issuer.organization_names.push_back("FOAF.ME");
+
+ std::vector<CertPrincipal> foaf_issuers(1, foaf_issuer);
+ EXPECT_TRUE(foaf_me_chromium_test_cert->IsIssuedBy(foaf_issuers));
+
+ // And test some combinations and mismatches.
+ std::vector<CertPrincipal> both_issuers;
+ both_issuers.push_back(mit_issuer);
+ both_issuers.push_back(foaf_issuer);
+ EXPECT_TRUE(foaf_me_chromium_test_cert->IsIssuedBy(both_issuers));
+ EXPECT_TRUE(mit_davidben_cert->IsIssuedBy(both_issuers));
+ EXPECT_FALSE(foaf_me_chromium_test_cert->IsIssuedBy(mit_issuers));
+ EXPECT_FALSE(mit_davidben_cert->IsIssuedBy(foaf_issuers));
+}
+#endif // defined(OS_MACOSX)
+
+class X509CertificateParseTest
+ : public testing::TestWithParam<CertificateFormatTestData> {
+ public:
+ virtual ~X509CertificateParseTest() {}
+ virtual void SetUp() {
+ test_data_ = GetParam();
+ }
+ virtual void TearDown() {}
+
+ protected:
+ CertificateFormatTestData test_data_;
+};
+
+TEST_P(X509CertificateParseTest, CanParseFormat) {
+ FilePath certs_dir = GetTestCertsDirectory();
+ CertificateList certs = CreateCertificateListFromFile(
+ certs_dir, test_data_.file_name, test_data_.format);
+ ASSERT_FALSE(certs.empty());
+ ASSERT_LE(certs.size(), arraysize(test_data_.chain_fingerprints));
+ CheckGoogleCert(certs.front(), google_parse_fingerprint,
+ kGoogleParseValidFrom, kGoogleParseValidTo);
+
+ size_t i;
+ for (i = 0; i < arraysize(test_data_.chain_fingerprints); ++i) {
+ if (test_data_.chain_fingerprints[i] == NULL) {
+ // No more test certificates expected - make sure no more were
+ // returned before marking this test a success.
+ EXPECT_EQ(i, certs.size());
+ break;
+ }
+
+ // A cert is expected - make sure that one was parsed.
+ ASSERT_LT(i, certs.size());
+
+ // Compare the parsed certificate with the expected certificate, by
+ // comparing fingerprints.
+ const X509Certificate* cert = certs[i];
+ const SHA1Fingerprint& actual_fingerprint = cert->fingerprint();
+ unsigned char* expected_fingerprint = test_data_.chain_fingerprints[i];
+
+ for (size_t j = 0; j < 20; ++j)
+ EXPECT_EQ(expected_fingerprint[j], actual_fingerprint.data[j]);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(, X509CertificateParseTest,
+ testing::ValuesIn(FormatTestData));
+
} // namespace net
diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc
index 901c0a6..03434bb 100644
--- a/net/base/x509_certificate_win.cc
+++ b/net/base/x509_certificate_win.cc
@@ -434,6 +434,54 @@ void ParsePrincipal(const std::string& description,
}
}
+void AddCertsFromStore(HCERTSTORE store,
+ X509Certificate::OSCertHandles* results) {
+ PCCERT_CONTEXT cert = NULL;
+
+ while ((cert = CertEnumCertificatesInStore(store, cert)) != NULL) {
+ PCCERT_CONTEXT to_add = NULL;
+ if (CertAddCertificateContextToStore(
+ NULL, // The cert won't be persisted in any cert store. This breaks
+ // any association the context currently has to |store|, which
+ // allows us, the caller, to safely close |store| without
+ // releasing the cert handles.
+ cert,
+ CERT_STORE_ADD_USE_EXISTING,
+ &to_add) && to_add != NULL) {
+ // When processing stores generated from PKCS#7/PKCS#12 files, it
+ // appears that the order returned is the inverse of the order that it
+ // appeared in the file.
+ // TODO(rsleevi): Ensure this order is consistent across all Win
+ // versions
+ results->insert(results->begin(), to_add);
+ }
+ }
+}
+
+X509Certificate::OSCertHandles ParsePKCS7(const char* data, size_t length) {
+ X509Certificate::OSCertHandles results;
+ CERT_BLOB data_blob;
+ data_blob.cbData = length;
+ data_blob.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(data));
+
+ HCERTSTORE out_store = NULL;
+
+ DWORD expected_types = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED |
+ CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED;
+
+ if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &data_blob, expected_types,
+ CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL,
+ &out_store, NULL, NULL) || out_store == NULL) {
+ return results;
+ }
+
+ AddCertsFromStore(out_store, &results);
+ CertCloseStore(out_store, CERT_CLOSE_STORE_CHECK_FLAG);
+
+ return results;
+}
+
} // namespace
void X509Certificate::Initialize() {
@@ -753,6 +801,27 @@ X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
return cert_handle;
}
+X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
+ const char* data, int length, Format format) {
+ OSCertHandles results;
+ switch (format) {
+ case FORMAT_SINGLE_CERTIFICATE: {
+ OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
+ if (handle != NULL)
+ results.push_back(handle);
+ break;
+ }
+ case FORMAT_PKCS7:
+ results = ParsePKCS7(data, length);
+ break;
+ default:
+ NOTREACHED() << "Certificate format " << format << " unimplemented";
+ break;
+ }
+
+ return results;
+}
+
// static
X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
diff --git a/net/crash_cache.target.mk b/net/crash_cache.target.mk
index d339afc..5787b12 100644
--- a/net/crash_cache.target.mk
+++ b/net/crash_cache.target.mk
@@ -19,6 +19,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -65,6 +66,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -128,14 +130,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -164,7 +167,8 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/crash_cache: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/crash_cache: LIBS := $(LIBS)
diff --git a/net/data/heapcheck/net_unittests.gtest.txt b/net/data/heapcheck/net_unittests.gtest.txt
index 596bd79..bfc3a35 100644
--- a/net/data/heapcheck/net_unittests.gtest.txt
+++ b/net/data/heapcheck/net_unittests.gtest.txt
@@ -1,4 +1,20 @@
# http://crbug.com/31129 -- forking Python servers may break heapchecker's
# symbolization.
URLRequestTestHTTP.*
-
+# Exclude tests that simulate a crash: they leak a lot of stuff.
+# Note that *InvalidEntry* is too general.
+DiskCacheBackendTest.AppCacheInvalidEntry
+DiskCacheBackendTest.AppCacheInvalidEntryRead
+DiskCacheBackendTest.AppCacheInvalidEntryWithLoad
+DiskCacheBackendTest.InvalidEntry
+DiskCacheBackendTest.InvalidEntryEnumeration
+DiskCacheBackendTest.InvalidEntryRead
+DiskCacheBackendTest.InvalidEntryWithLoad
+DiskCacheBackendTest.TrimInvalidEntry
+DiskCacheBackendTest.TrimInvalidEntry2
+DiskCacheBackendTest.NewEvictionInvalidEntry
+DiskCacheBackendTest.NewEvictionInvalidEntryEnumeration
+DiskCacheBackendTest.NewEvictionInvalidEntryRead
+DiskCacheBackendTest.NewEvictionInvalidEntryWithLoad
+DiskCacheBackendTest.NewEvictionTrimInvalidEntry
+DiskCacheBackendTest.NewEvictionTrimInvalidEntry2
diff --git a/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js b/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js
index e3b3504..0c0a4a9 100644
--- a/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js
+++ b/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js
@@ -76,6 +76,87 @@ Tests.testShExpMatch = function(t) {
t.expectFalse(shExpMatch("foo.jpg", "foo"));
};
+Tests.testSortIpAddressList = function(t) {
+ t.expectEquals("::1;::2;::3", sortIpAddressList("::2;::3;::1"));
+ t.expectEquals(
+ "2001:4898:28:3:201:2ff:feea:fc14;fe80::5efe:157:9d3b:8b16;157.59.139.22",
+ sortIpAddressList("157.59.139.22;" +
+ "2001:4898:28:3:201:2ff:feea:fc14;" +
+ "fe80::5efe:157:9d3b:8b16"));
+
+ // Single IP address (v4 and v6).
+ t.expectEquals("127.0.0.1", sortIpAddressList("127.0.0.1"));
+ t.expectEquals("::1", sortIpAddressList("::1"))
+
+ // Verify that IPv6 address is not re-written (not reduced).
+ t.expectEquals("0:0::1;192.168.1.1", sortIpAddressList("192.168.1.1;0:0::1"));
+
+ // Input is already sorted.
+ t.expectEquals("::1;192.168.1.3", sortIpAddressList("::1;192.168.1.3"));
+
+ // Same-valued IP addresses (also tests stability).
+ t.expectEquals("0::1;::1;0:0::1", sortIpAddressList("0::1;::1;0:0::1"));
+
+ // Contains extra semi-colons.
+ t.expectEquals("127.0.0.1", sortIpAddressList(";127.0.0.1;"));
+
+ // Contains whitespace (spaces and tabs).
+ t.expectEquals("192.168.0.1;192.168.0.2",
+ sortIpAddressList("192.168.0.1; 192.168.0.2"));
+ t.expectEquals("127.0.0.0;127.0.0.1;127.0.0.2",
+ sortIpAddressList("127.0.0.1; 127.0.0.2; 127.0.0.0"));
+
+ // Empty lists.
+ t.expectFalse(sortIpAddressList(""));
+ t.expectFalse(sortIpAddressList(" "));
+ t.expectFalse(sortIpAddressList(";"));
+ t.expectFalse(sortIpAddressList(";;"));
+ t.expectFalse(sortIpAddressList(" ; ; "));
+
+ // Invalid IP addresses.
+ t.expectFalse(sortIpAddressList("256.0.0.1"));
+ t.expectFalse(sortIpAddressList("192.168.1.1;0:0:0:1;127.0.0.1"));
+
+ // Call sortIpAddressList() with wonky arguments.
+ t.expectEquals(null, sortIpAddressList());
+ t.expectEquals(null, sortIpAddressList(null));
+ t.expectEquals(null, sortIpAddressList(null, null));
+};
+
+Tests.testIsInNetEx = function(t) {
+ t.expectTrue(isInNetEx("198.95.249.79", "198.95.249.79/32"));
+ t.expectTrue(isInNetEx("198.95.115.10", "198.95.0.0/16"));
+ t.expectTrue(isInNetEx("198.95.1.1", "198.95.0.0/16"));
+ t.expectTrue(isInNetEx("198.95.1.1", "198.95.3.3/16"));
+ t.expectTrue(isInNetEx("0:0:0:0:0:0:7f00:1", "0:0:0:0:0:0:7f00:1/32"));
+ t.expectTrue(isInNetEx("3ffe:8311:ffff:abcd:1234:dead:beef:101",
+ "3ffe:8311:ffff::/48"));
+
+ // IPv4 and IPv6 mix.
+ t.expectFalse(isInNetEx("127.0.0.1", "0:0:0:0:0:0:7f00:1/16"));
+ t.expectFalse(isInNetEx("192.168.24.3", "fe80:0:0:0:0:0:c0a8:1803/32"));
+
+ t.expectFalse(isInNetEx("198.95.249.78", "198.95.249.79/32"));
+ t.expectFalse(isInNetEx("198.96.115.10", "198.95.0.0/16"));
+ t.expectFalse(isInNetEx("3fff:8311:ffff:abcd:1234:dead:beef:101",
+ "3ffe:8311:ffff::/48"));
+
+ // Call isInNetEx with wonky arguments.
+ t.expectEquals(null, isInNetEx());
+ t.expectEquals(null, isInNetEx(null));
+ t.expectEquals(null, isInNetEx(null, null));
+ t.expectEquals(null, isInNetEx(null, null, null));
+ t.expectEquals(null, isInNetEx("198.95.249.79"));
+
+ // Invalid IP address.
+ t.expectFalse(isInNetEx("256.0.0.1", "198.95.249.79"));
+ t.expectFalse(isInNetEx("127.0.0.1 ", "127.0.0.1/32")); // Extra space.
+
+ // Invalid prefix.
+ t.expectFalse(isInNetEx("198.95.115.10", "198.95.0.0/34"));
+ t.expectFalse(isInNetEx("127.0.0.1", "127.0.0.1")); // Missing '/' in prefix.
+};
+
Tests.testWeekdayRange = function(t) {
// Test with local time.
MockDate.setCurrent("Tue Mar 03 2009");
diff --git a/net/data/valgrind/net_unittests.gtest-memcheck.txt b/net/data/valgrind/net_unittests.gtest-memcheck.txt
index 458ddef..e7f42dd 100644
--- a/net/data/valgrind/net_unittests.gtest-memcheck.txt
+++ b/net/data/valgrind/net_unittests.gtest-memcheck.txt
@@ -2,6 +2,9 @@
# Similar list in ../purify/net_unittests.exe.gtest.txt
# TODO(dkegel): either merge the two files or keep them in sync,
# see http://code.google.com/p/chromium/issues/detail?id=8951
+DiskCacheBackendTest.AppCacheInvalidEntry
+DiskCacheBackendTest.AppCacheInvalidEntryRead
+DiskCacheBackendTest.AppCacheInvalidEntryWithLoad
DiskCacheBackendTest.InvalidEntry
DiskCacheBackendTest.InvalidEntryRead
DiskCacheBackendTest.InvalidEntryWithLoad
diff --git a/net/data/valgrind/net_unittests.gtest-tsan_mac.txt b/net/data/valgrind/net_unittests.gtest-tsan_mac.txt
index 4362060..6359e4b 100644
--- a/net/data/valgrind/net_unittests.gtest-tsan_mac.txt
+++ b/net/data/valgrind/net_unittests.gtest-tsan_mac.txt
@@ -1,24 +1,8 @@
-# Former aspacem warnings on Valgrind.
-# Tsan still tends to hang on these tests unexpectedly on Mac OS.
-# (see https://bugs.kde.org/show_bug.cgi?id=192634 and
-# http://code.google.com/p/data-race-test/issues/detail?id=11)
-HttpNetworkLayerTest.GET
-HttpNetworkLayerTest.SimpleGET
-
# WebSocketTest tests are extraordinary slow under ThreadSanitizer,
# (see http://crbug.com/25392)
# TODO(glider): investigate this.
WebSocketTest.*
-# These tests die because of unhandled shm_unlink call
-# (see http://crbug.com/36657)
-DiskCacheBackendTest.*InvalidRankings*
-DiskCacheBackendTest.*DisableSuccess*
-DiskCacheBackendTest.*DisableFailure*
-
# Strange reports from __NSThread__main__ appeared with the new TSan binaries
# See http://crbug.com/38926
DirectoryLister*
-
-# See http://crbug.com/44570
-HttpNetworkTransactionTest.StopsReading204
diff --git a/net/data/valgrind/net_unittests.gtest-tsan_win32.txt b/net/data/valgrind/net_unittests.gtest-tsan_win32.txt
index 52de2b7..8f35ff1 100644
--- a/net/data/valgrind/net_unittests.gtest-tsan_win32.txt
+++ b/net/data/valgrind/net_unittests.gtest-tsan_win32.txt
@@ -7,14 +7,20 @@ SpdyNetworkTransactionTest.SynReplyHeadersVary
X509CertificateTest.UnoSoftCertParsing
URLRequestTest.DoNotSaveCookies
URLRequestTest.QuitTest
-DiskCacheEntryTest.*HugeSparse*
# See http://crbug.com/46647
DiskCacheBackendTest.*
+# See http://crbug.com/53304
+URLRequestTest.*
+
# See http://crbug.com/47836
ClientSocketPoolBaseTest.CancelPendingSocketAtSocketLimit
+# See http://crbug.com/51145
+HttpNetworkTransactionTest.*
+HttpNetworkLayerTest.GET
+
#########################################
# These tests fail if you don't have our SSL certificate installed.
# Please see http://dev.chromium.org/developers/testing#TOC-SSL-tests
diff --git a/net/data/valgrind/net_unittests.gtest_mac.txt b/net/data/valgrind/net_unittests.gtest_mac.txt
index ec7da13..57f2365 100644
--- a/net/data/valgrind/net_unittests.gtest_mac.txt
+++ b/net/data/valgrind/net_unittests.gtest_mac.txt
@@ -1,2 +1,2 @@
# Very slow under Valgrind, (see <http://crbug.com/37289>).
-KeygenHandlerTest.FLAKY_SmokeTest
+KeygenHandlerTest.SmokeTest
diff --git a/net/disk_cache/addr.h b/net/disk_cache/addr.h
index 938a442..c10dcc3 100644
--- a/net/disk_cache/addr.h
+++ b/net/disk_cache/addr.h
@@ -7,6 +7,7 @@
#ifndef NET_DISK_CACHE_ADDR_H_
#define NET_DISK_CACHE_ADDR_H_
+#pragma once
#include "net/disk_cache/disk_format.h"
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc
index 84f023d..7a0f9b3 100644
--- a/net/disk_cache/backend_impl.cc
+++ b/net/disk_cache/backend_impl.cc
@@ -11,15 +11,18 @@
#include "base/message_loop.h"
#include "base/rand_util.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/sys_info.h"
+#include "base/time.h"
#include "base/timer.h"
#include "base/worker_pool.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/cache_util.h"
#include "net/disk_cache/entry_impl.h"
#include "net/disk_cache/errors.h"
-#include "net/disk_cache/hash.h"
+#include "net/disk_cache/experiments.h"
#include "net/disk_cache/file.h"
+#include "net/disk_cache/hash.h"
#include "net/disk_cache/mem_backend_impl.h"
// This has to be defined before including histogram_macros.h from this file.
@@ -36,6 +39,8 @@ const char* kIndexName = "index";
const int kMaxOldFolders = 100;
// Seems like ~240 MB correspond to less than 50k entries for 99% of the people.
+// Note that the actual target is to keep the index table load factor under 55%
+// for most users.
const int k64kEntriesStore = 240 * 1000 * 1000;
const int kBaseTableLen = 64 * 1024;
const int kDefaultCacheSize = 80 * 1024 * 1024;
@@ -70,7 +75,8 @@ size_t GetIndexSize(int table_len) {
// will return "/foo/old_bar_005".
FilePath GetPrefixedName(const FilePath& path, const std::string& name,
int index) {
- std::string tmp = StringPrintf("%s%s_%03d", "old_", name.c_str(), index);
+ std::string tmp = base::StringPrintf("%s%s_%03d", "old_",
+ name.c_str(), index);
return path.AppendASCII(tmp);
}
@@ -135,31 +141,66 @@ bool DelayedCacheCleanup(const FilePath& full_path) {
return true;
}
-// Sets |current_group| for the current experiment. Returns false if the files
-// should be discarded.
-bool InitExperiment(int* current_group) {
- if (*current_group == 3 || *current_group == 4) {
- // Discard current cache for groups 3 and 4.
+// Sets group for the current experiment. Returns false if the files should be
+// discarded.
+bool InitExperiment(disk_cache::IndexHeader* header, uint32 mask) {
+ if (header->experiment == disk_cache::EXPERIMENT_OLD_FILE1 ||
+ header->experiment == disk_cache::EXPERIMENT_OLD_FILE2) {
+ // Discard current cache.
return false;
}
- // There is no experiment.
- *current_group = 0;
+ // See if we already defined the group for this profile.
+ if (header->experiment >= disk_cache::EXPERIMENT_DELETED_LIST_OUT)
+ return true;
+
+ if (!header->create_time || !header->lru.filled) {
+ // Only for users with a full cache.
+ header->experiment = disk_cache::EXPERIMENT_DELETED_LIST_OUT;
+ return true;
+ }
+
+ int index_load = header->num_entries * 100 / (mask + 1);
+ if (index_load > 20) {
+ // Out of the experiment (~ 35% users).
+ header->experiment = disk_cache::EXPERIMENT_DELETED_LIST_OUT;
+ return true;
+ }
+
+ int option = base::RandInt(0, 5);
+ if (option > 1) {
+ // 60% out (39% of the total).
+ header->experiment = disk_cache::EXPERIMENT_DELETED_LIST_OUT;
+ } else if (!option) {
+ // About 13% of the total.
+ header->experiment = disk_cache::EXPERIMENT_DELETED_LIST_CONTROL;
+ } else {
+ // About 13% of the total.
+ header->experiment = disk_cache::EXPERIMENT_DELETED_LIST_IN;
+ }
+
return true;
}
// Initializes the field trial structures to allow performance measurements
-// for the current cache configuration.
-void SetFieldTrialInfo(int size_group) {
+// for the current cache configuration. Returns true if we are active part of
+// the CacheThrottle field trial.
+bool SetFieldTrialInfo(int size_group) {
static bool first = true;
if (!first)
- return;
+ return false;
// Field trials involve static objects so we have to do this only once.
first = false;
scoped_refptr<FieldTrial> trial1 = new FieldTrial("CacheSize", 10);
- std::string group1 = StringPrintf("CacheSizeGroup_%d", size_group);
+ std::string group1 = base::StringPrintf("CacheSizeGroup_%d", size_group);
trial1->AppendGroup(group1, FieldTrial::kAllRemainingProbability);
+
+ scoped_refptr<FieldTrial> trial2 = new FieldTrial("CacheThrottle", 100);
+ int group2a = trial2->AppendGroup("CacheThrottle_On", 10); // 10 % in.
+ trial2->AppendGroup("CacheThrottle_Off", 10); // 10 % control.
+
+ return trial2->group() == group2a;
}
// ------------------------------------------------------------------------
@@ -259,7 +300,7 @@ class FinalCleanup : public Task {
};
void FinalCleanup::Run() {
- backend_->StartCleanup();
+ backend_->CleanupCache();
}
} // namespace
@@ -328,6 +369,7 @@ int BackendImpl::CreateBackend(const FilePath& full_path, bool force,
uint32 flags, base::MessageLoopProxy* thread,
Backend** backend,
CompletionCallback* callback) {
+ DCHECK(callback);
CacheCreator* creator = new CacheCreator(full_path, force, max_bytes, type,
flags, thread, backend, callback);
// This object will self-destroy when finished.
@@ -339,6 +381,53 @@ int BackendImpl::Init(CompletionCallback* callback) {
return net::ERR_IO_PENDING;
}
+BackendImpl::BackendImpl(const FilePath& path,
+ base::MessageLoopProxy* cache_thread)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(background_queue_(this, cache_thread)),
+ path_(path),
+ block_files_(path),
+ mask_(0),
+ max_size_(0),
+ io_delay_(0),
+ cache_type_(net::DISK_CACHE),
+ uma_report_(0),
+ user_flags_(0),
+ init_(false),
+ restarted_(false),
+ unit_test_(false),
+ read_only_(false),
+ new_eviction_(false),
+ first_timer_(true),
+ throttle_requests_(false),
+ done_(true, false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(ptr_factory_(this)) {
+}
+
+BackendImpl::BackendImpl(const FilePath& path,
+ uint32 mask,
+ base::MessageLoopProxy* cache_thread)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(background_queue_(this, cache_thread)),
+ path_(path),
+ block_files_(path),
+ mask_(mask),
+ max_size_(0),
+ io_delay_(0),
+ cache_type_(net::DISK_CACHE),
+ uma_report_(0),
+ user_flags_(kMask),
+ init_(false),
+ restarted_(false),
+ unit_test_(false),
+ read_only_(false),
+ new_eviction_(false),
+ first_timer_(true),
+ throttle_requests_(false),
+ done_(true, false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(ptr_factory_(this)) {
+}
+
BackendImpl::~BackendImpl() {
background_queue_.WaitForPendingIO();
@@ -430,19 +519,19 @@ void BackendImpl::GetStats(StatsItems* stats) {
std::pair<std::string, std::string> item;
item.first = "Entries";
- item.second = StringPrintf("%d", data_->header.num_entries);
+ item.second = base::StringPrintf("%d", data_->header.num_entries);
stats->push_back(item);
item.first = "Pending IO";
- item.second = StringPrintf("%d", num_pending_io_);
+ item.second = base::StringPrintf("%d", num_pending_io_);
stats->push_back(item);
item.first = "Max size";
- item.second = StringPrintf("%d", max_size_);
+ item.second = base::StringPrintf("%d", max_size_);
stats->push_back(item);
item.first = "Current size";
- item.second = StringPrintf("%d", data_->header.num_bytes);
+ item.second = base::StringPrintf("%d", data_->header.num_bytes);
stats->push_back(item);
stats_.GetItems(stats);
@@ -465,6 +554,7 @@ int BackendImpl::SyncInit() {
entry_count_ = byte_count_ = 0;
if (!restarted_) {
+ buffer_bytes_ = 0;
trace_object_ = TraceObject::GetTraceObject();
// Create a recurrent timer of 30 secs.
int timer_delay = unit_test_ ? 1000 : 30000;
@@ -474,16 +564,14 @@ int BackendImpl::SyncInit() {
init_ = true;
- if (data_->header.experiment != 0 && cache_type_ != net::DISK_CACHE) {
+ if (data_->header.experiment != NO_EXPERIMENT &&
+ cache_type_ != net::DISK_CACHE) {
// No experiment for other caches.
return net::ERR_FAILED;
}
if (!(user_flags_ & disk_cache::kNoRandom)) {
// The unit test controls directly what to test.
- if (!InitExperiment(&data_->header.experiment))
- return net::ERR_FAILED;
-
new_eviction_ = (cache_type_ == net::DISK_CACHE);
}
@@ -492,6 +580,11 @@ int BackendImpl::SyncInit() {
return net::ERR_FAILED;
}
+ if (!(user_flags_ & disk_cache::kNoRandom) &&
+ cache_type_ == net::DISK_CACHE &&
+ !InitExperiment(&data_->header, mask_))
+ return net::ERR_FAILED;
+
// We don't care if the value overflows. The only thing we care about is that
// the id cannot be zero, because that value is used as "not dirty".
// Increasing the value once per second gives us many years before we start
@@ -510,6 +603,12 @@ int BackendImpl::SyncInit() {
if (!block_files_.Init(create_files))
return net::ERR_FAILED;
+ // We want to minimize the changes to cache for an AppCache.
+ if (cache_type() == net::APP_CACHE) {
+ DCHECK(!new_eviction_);
+ read_only_ = true;
+ }
+
// stats_ and rankings_ may end up calling back to us so we better be enabled.
disabled_ = false;
if (!stats_.Init(this, &data_->header.stats))
@@ -519,32 +618,31 @@ int BackendImpl::SyncInit() {
eviction_.Init(this);
// Setup load-time data only for the main cache.
- if (cache_type() == net::DISK_CACHE)
- SetFieldTrialInfo(GetSizeGroup());
+ if (!throttle_requests_ && cache_type() == net::DISK_CACHE)
+ throttle_requests_ = SetFieldTrialInfo(GetSizeGroup());
return disabled_ ? net::ERR_FAILED : net::OK;
}
-void BackendImpl::StartCleanup() {
- Trace("Backend StartCleanup");
- eviction_.Stop();
-
- // Give a chance for any posted evictions to be discarded.
- MessageLoop::current()->PostTask(FROM_HERE,
- factory_.NewRunnableMethod(&BackendImpl::CleanupCache));
-}
-
void BackendImpl::CleanupCache() {
Trace("Backend Cleanup");
+ eviction_.Stop();
+ timer_.Stop();
+
if (init_) {
+ stats_.Store();
if (data_)
data_->header.crash = 0;
- timer_.Stop();
File::WaitForPendingIO(&num_pending_io_);
- DCHECK(!num_refs_);
+ if (user_flags_ & kNoRandom) {
+ // This is a net_unittest, verify that we are not 'leaking' entries.
+ DCHECK(!num_refs_);
+ }
}
+ block_files_.CloseFiles();
factory_.RevokeAll();
+ ptr_factory_.InvalidateWeakPtrs();
done_.Signal();
}
@@ -583,6 +681,8 @@ int BackendImpl::SyncDoomEntry(const std::string& key) {
}
int BackendImpl::SyncDoomAllEntries() {
+ // This is not really an error, but it is an interesting condition.
+ ReportError(ERR_CACHE_DOOMED);
if (!num_refs_) {
PrepareForRestart();
DeleteCache(path_, false);
@@ -599,6 +699,7 @@ int BackendImpl::SyncDoomAllEntries() {
int BackendImpl::SyncDoomEntriesBetween(const base::Time initial_time,
const base::Time end_time) {
+ DCHECK_NE(net::APP_CACHE, cache_type_);
if (end_time.is_null())
return SyncDoomEntriesSince(initial_time);
@@ -636,6 +737,7 @@ int BackendImpl::SyncDoomEntriesBetween(const base::Time initial_time,
// We use OpenNextEntryImpl to retrieve elements from the cache, until we get
// entries that are too old.
int BackendImpl::SyncDoomEntriesSince(const base::Time initial_time) {
+ DCHECK_NE(net::APP_CACHE, cache_type_);
if (disabled_)
return net::ERR_FAILED;
@@ -678,6 +780,7 @@ EntryImpl* BackendImpl::OpenEntryImpl(const std::string& key) {
TimeTicks start = TimeTicks::Now();
uint32 hash = Hash(key);
+ Trace("Open hash 0x%x", hash);
EntryImpl* cache_entry = MatchEntry(key, hash, false);
if (!cache_entry) {
@@ -706,6 +809,7 @@ EntryImpl* BackendImpl::CreateEntryImpl(const std::string& key) {
TimeTicks start = TimeTicks::Now();
uint32 hash = Hash(key);
+ Trace("Create hash 0x%x", hash);
scoped_refptr<EntryImpl> parent;
Addr entry_address(data_->table[hash & mask_]);
@@ -717,11 +821,13 @@ EntryImpl* BackendImpl::CreateEntryImpl(const std::string& key) {
return ResurrectEntry(old_entry);
EntryImpl* parent_entry = MatchEntry(key, hash, true);
- if (!parent_entry) {
+ if (parent_entry) {
+ parent.swap(&parent_entry);
+ } else if (data_->table[hash & mask_]) {
+ // We should have corrected the problem.
NOTREACHED();
return NULL;
}
- parent.swap(&parent_entry);
}
int num_blocks;
@@ -746,7 +852,8 @@ EntryImpl* BackendImpl::CreateEntryImpl(const std::string& key) {
return NULL;
}
- scoped_refptr<EntryImpl> cache_entry(new EntryImpl(this, entry_address));
+ scoped_refptr<EntryImpl> cache_entry(
+ new EntryImpl(this, entry_address, false));
IncreaseNumRefs();
if (!cache_entry->CreateEntry(node_address, key, hash)) {
@@ -815,7 +922,7 @@ FilePath BackendImpl::GetFileName(Addr address) const {
return FilePath();
}
- std::string tmp = StringPrintf("f_%06x", address.FileNumber());
+ std::string tmp = base::StringPrintf("f_%06x", address.FileNumber());
return path_.AppendASCII(tmp);
}
@@ -840,7 +947,7 @@ bool BackendImpl::CreateExternalFile(Addr* address) {
base::PLATFORM_FILE_CREATE |
base::PLATFORM_FILE_EXCLUSIVE_WRITE;
scoped_refptr<disk_cache::File> file(new disk_cache::File(
- base::CreatePlatformFile(name, flags, NULL)));
+ base::CreatePlatformFile(name, flags, NULL, NULL)));
if (!file->IsValid())
continue;
@@ -931,11 +1038,16 @@ void BackendImpl::RemoveEntry(EntryImpl* entry) {
DecreaseNumEntries();
}
-void BackendImpl::CacheEntryDestroyed(Addr address) {
+void BackendImpl::OnEntryDestroyBegin(Addr address) {
EntriesMap::iterator it = open_entries_.find(address.value());
if (it != open_entries_.end())
open_entries_.erase(it);
+}
+
+void BackendImpl::OnEntryDestroyEnd() {
DecreaseNumRefs();
+ if (data_->header.num_bytes > max_size_ && !read_only_)
+ eviction_.TrimCache(false);
}
EntryImpl* BackendImpl::GetOpenEntry(CacheRankingsBlock* rankings) const {
@@ -974,6 +1086,25 @@ void BackendImpl::TooMuchStorageRequested(int32 size) {
stats_.ModifyStorageStats(0, size);
}
+bool BackendImpl::IsAllocAllowed(int current_size, int new_size) {
+ DCHECK_GT(new_size, current_size);
+ if (user_flags_ & kNoBuffering)
+ return false;
+
+ int to_add = new_size - current_size;
+ if (buffer_bytes_ + to_add > MaxBuffersSize())
+ return false;
+
+ buffer_bytes_ += to_add;
+ CACHE_UMA(COUNTS_50000, "BufferBytes", 0, buffer_bytes_ / 1024);
+ return true;
+}
+
+void BackendImpl::BufferDeleted(int size) {
+ buffer_bytes_ -= size;
+ DCHECK_GE(size, 0);
+}
+
bool BackendImpl::IsLoaded() const {
CACHE_UMA(COUNTS, "PendingIO", GetSizeGroup(), num_pending_io_);
if (user_flags_ & kNoLoadProtection)
@@ -984,8 +1115,13 @@ bool BackendImpl::IsLoaded() const {
std::string BackendImpl::HistogramName(const char* name, int experiment) const {
if (!experiment)
- return StringPrintf("DiskCache.%d.%s", cache_type_, name);
- return StringPrintf("DiskCache.%d.%s_%d", cache_type_, name, experiment);
+ return base::StringPrintf("DiskCache.%d.%s", cache_type_, name);
+ return base::StringPrintf("DiskCache.%d.%s_%d", cache_type_,
+ name, experiment);
+}
+
+base::WeakPtr<BackendImpl> BackendImpl::GetWeakPtr() {
+ return ptr_factory_.GetWeakPtr();
}
int BackendImpl::GetSizeGroup() const {
@@ -1093,6 +1229,31 @@ void BackendImpl::OnWrite(int32 bytes) {
OnRead(bytes);
}
+void BackendImpl::OnOperationCompleted(base::TimeDelta elapsed_time) {
+ CACHE_UMA(TIMES, "TotalIOTime", 0, elapsed_time);
+
+ if (cache_type() != net::DISK_CACHE)
+ return;
+
+ UMA_HISTOGRAM_TIMES(
+ FieldTrial::MakeName("DiskCache.TotalIOTime", "CacheThrottle").data(),
+ elapsed_time);
+
+ if (!throttle_requests_)
+ return;
+
+ const int kMaxNormalDelayMS = 100;
+
+ bool throttling = io_delay_ > kMaxNormalDelayMS;
+
+ // We keep a simple exponential average of elapsed_time.
+ io_delay_ = (io_delay_ + static_cast<int>(elapsed_time.InMilliseconds())) / 2;
+ if (io_delay_ > kMaxNormalDelayMS && !throttling)
+ background_queue_.StartQueingOperations();
+ else if (io_delay_ <= kMaxNormalDelayMS && throttling)
+ background_queue_.StopQueingOperations();
+}
+
void BackendImpl::OnStatsTimer() {
stats_.OnEvent(Stats::TIMER);
int64 time = stats_.GetCounter(Stats::TIMER);
@@ -1165,6 +1326,11 @@ int BackendImpl::FlushQueueForTest(CompletionCallback* callback) {
return net::ERR_IO_PENDING;
}
+int BackendImpl::RunTaskForTest(Task* task, CompletionCallback* callback) {
+ background_queue_.RunTask(task, callback);
+ return net::ERR_IO_PENDING;
+}
+
int BackendImpl::SelfCheck() {
if (!init_) {
LOG(ERROR) << "Init failed";
@@ -1217,7 +1383,7 @@ bool BackendImpl::InitBackingStore(bool* file_created) {
base::PLATFORM_FILE_OPEN_ALWAYS |
base::PLATFORM_FILE_EXCLUSIVE_WRITE;
scoped_refptr<disk_cache::File> file(new disk_cache::File(
- base::CreatePlatformFile(index_name, flags, file_created)));
+ base::CreatePlatformFile(index_name, flags, file_created, NULL)));
if (!file->IsValid())
return false;
@@ -1332,7 +1498,8 @@ int BackendImpl::NewEntry(Addr address, EntryImpl** entry, bool* dirty) {
return 0;
}
- scoped_refptr<EntryImpl> cache_entry(new EntryImpl(this, address));
+ scoped_refptr<EntryImpl> cache_entry(
+ new EntryImpl(this, address, read_only_));
IncreaseNumRefs();
*entry = NULL;
@@ -1366,9 +1533,13 @@ int BackendImpl::NewEntry(Addr address, EntryImpl** entry, bool* dirty) {
if (!rankings_.SanityCheck(cache_entry->rankings(), false))
return ERR_INVALID_LINKS;
- // We only add clean entries to the map.
- if (!*dirty)
+ if (*dirty) {
+ Trace("Dirty entry 0x%p 0x%x", reinterpret_cast<void*>(cache_entry.get()),
+ address.value());
+ } else {
+ // We only add clean entries to the map.
open_entries_[address.value()] = cache_entry;
+ }
cache_entry.swap(entry);
return 0;
@@ -1423,6 +1594,7 @@ EntryImpl* BackendImpl::MatchEntry(const std::string& key, uint32 hash,
continue;
}
+ DCHECK_EQ(hash & mask_, cache_entry->entry()->Data()->hash & mask_);
if (cache_entry->IsSameEntry(key, hash)) {
if (!cache_entry->Update())
cache_entry = NULL;
@@ -1591,7 +1763,7 @@ EntryImpl* BackendImpl::ResurrectEntry(EntryImpl* deleted_entry) {
eviction_.OnCreateEntry(deleted_entry);
entry_count_++;
- stats_.OnEvent(Stats::CREATE_HIT);
+ stats_.OnEvent(Stats::RESURRECT_HIT);
Trace("Resurrect entry hit ");
return deleted_entry;
}
@@ -1649,9 +1821,6 @@ void BackendImpl::DestroyInvalidEntryFromEnumeration(EntryImpl* entry) {
void BackendImpl::AddStorageSize(int32 bytes) {
data_->header.num_bytes += bytes;
DCHECK_GE(data_->header.num_bytes, 0);
-
- if (data_->header.num_bytes > max_size_)
- eviction_.TrimCache(false);
}
void BackendImpl::SubstractStorageSize(int32 bytes) {
@@ -1698,8 +1867,14 @@ void BackendImpl::LogStats() {
void BackendImpl::ReportStats() {
CACHE_UMA(COUNTS, "Entries", 0, data_->header.num_entries);
- CACHE_UMA(COUNTS_10000, "Size2", 0, data_->header.num_bytes / (1024 * 1024));
- CACHE_UMA(COUNTS_10000, "MaxSize2", 0, max_size_ / (1024 * 1024));
+
+ int current_size = data_->header.num_bytes / (1024 * 1024);
+ int max_size = max_size_ / (1024 * 1024);
+ CACHE_UMA(COUNTS_10000, "Size2", 0, current_size);
+ CACHE_UMA(COUNTS_10000, "MaxSize2", 0, max_size);
+ if (!max_size)
+ max_size++;
+ CACHE_UMA(PERCENTAGE, "UsedSpace", 0, current_size * 100 / max_size);
CACHE_UMA(COUNTS_10000, "AverageOpenEntries2", 0,
static_cast<int>(stats_.GetCounter(Stats::OPEN_ENTRIES)));
@@ -1707,8 +1882,13 @@ void BackendImpl::ReportStats() {
static_cast<int>(stats_.GetCounter(Stats::MAX_ENTRIES)));
stats_.SetCounter(Stats::MAX_ENTRIES, 0);
- if (!data_->header.create_time || !data_->header.lru.filled)
+ if (!data_->header.create_time || !data_->header.lru.filled) {
+ int cause = data_->header.create_time ? 0 : 1;
+ if (!data_->header.lru.filled)
+ cause |= 2;
+ CACHE_UMA(CACHE_ERROR, "ShortReport", 0, cause);
return;
+ }
// This is an up to date client that will report FirstEviction() data. After
// that event, start reporting this:
@@ -1728,7 +1908,8 @@ void BackendImpl::ReportStats() {
return;
CACHE_UMA(HOURS, "UseTime", 0, static_cast<int>(use_hours));
- CACHE_UMA(PERCENTAGE, "HitRatio", 0, stats_.GetHitRatio());
+ CACHE_UMA(PERCENTAGE, "HitRatio", data_->header.experiment,
+ stats_.GetHitRatio());
int64 trim_rate = stats_.GetCounter(Stats::TRIM_ENTRY) / use_hours;
CACHE_UMA(COUNTS, "TrimRate", 0, static_cast<int>(trim_rate));
@@ -1745,14 +1926,15 @@ void BackendImpl::ReportStats() {
CACHE_UMA(PERCENTAGE, "LargeEntriesRatio", 0, large_ratio);
if (new_eviction_) {
- CACHE_UMA(PERCENTAGE, "ResurrectRatio", 0, stats_.GetResurrectRatio());
+ CACHE_UMA(PERCENTAGE, "ResurrectRatio", data_->header.experiment,
+ stats_.GetResurrectRatio());
CACHE_UMA(PERCENTAGE, "NoUseRatio", 0,
data_->header.lru.sizes[0] * 100 / data_->header.num_entries);
CACHE_UMA(PERCENTAGE, "LowUseRatio", 0,
data_->header.lru.sizes[1] * 100 / data_->header.num_entries);
CACHE_UMA(PERCENTAGE, "HighUseRatio", 0,
data_->header.lru.sizes[2] * 100 / data_->header.num_entries);
- CACHE_UMA(PERCENTAGE, "DeletedRatio", 0,
+ CACHE_UMA(PERCENTAGE, "DeletedRatio", data_->header.experiment,
data_->header.lru.sizes[4] * 100 / data_->header.num_entries);
}
@@ -1862,6 +2044,7 @@ int BackendImpl::CheckAllEntries() {
}
}
+ Trace("CheckAllEntries End");
if (num_entries + num_dirty != data_->header.num_entries) {
LOG(ERROR) << "Number of entries mismatch";
return ERR_NUM_ENTRIES_MISMATCH;
@@ -1871,8 +2054,37 @@ int BackendImpl::CheckAllEntries() {
}
bool BackendImpl::CheckEntry(EntryImpl* cache_entry) {
+ bool ok = block_files_.IsValid(cache_entry->entry()->address());
+ ok = ok && block_files_.IsValid(cache_entry->rankings()->address());
+ EntryStore* data = cache_entry->entry()->Data();
+ for (size_t i = 0; i < arraysize(data->data_addr); i++) {
+ if (data->data_addr[i]) {
+ Addr address(data->data_addr[i]);
+ if (address.is_block_file())
+ ok = ok && block_files_.IsValid(address);
+ }
+ }
+
RankingsNode* rankings = cache_entry->rankings()->Data();
- return !rankings->dummy;
+ return ok && !rankings->dummy;
+}
+
+int BackendImpl::MaxBuffersSize() {
+ static int64 total_memory = base::SysInfo::AmountOfPhysicalMemory();
+ static bool done = false;
+
+ if (!done) {
+ const int kMaxBuffersSize = 30 * 1024 * 1024;
+
+ // We want to use up to 2% of the computer's memory.
+ total_memory = total_memory * 2 / 100;
+ if (total_memory > kMaxBuffersSize || total_memory <= 0)
+ total_memory = kMaxBuffersSize;
+
+ done = true;
+ }
+
+ return static_cast<int>(total_memory);
}
} // namespace disk_cache
diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h
index 90283fb..a8880d1 100644
--- a/net/disk_cache/backend_impl.h
+++ b/net/disk_cache/backend_impl.h
@@ -6,6 +6,7 @@
#ifndef NET_DISK_CACHE_BACKEND_IMPL_H_
#define NET_DISK_CACHE_BACKEND_IMPL_H_
+#pragma once
#include "base/file_path.h"
#include "base/hash_tables.h"
@@ -28,7 +29,8 @@ enum BackendFlags {
kUpgradeMode = 1 << 3, // This is the upgrade tool (dump).
kNewEviction = 1 << 4, // Use of new eviction was specified.
kNoRandom = 1 << 5, // Don't add randomness to the behavior.
- kNoLoadProtection = 1 << 6 // Don't act conservatively under load.
+ kNoLoadProtection = 1 << 6, // Don't act conservatively under load.
+ kNoBuffering = 1 << 7 // Disable extended IO buffering.
};
// This class implements the Backend interface. An object of this
@@ -36,22 +38,10 @@ enum BackendFlags {
class BackendImpl : public Backend {
friend class Eviction;
public:
- BackendImpl(const FilePath& path, base::MessageLoopProxy* cache_thread)
- : ALLOW_THIS_IN_INITIALIZER_LIST(background_queue_(this, cache_thread)),
- path_(path), block_files_(path), mask_(0), max_size_(0),
- cache_type_(net::DISK_CACHE), uma_report_(0), user_flags_(0),
- init_(false), restarted_(false), unit_test_(false), read_only_(false),
- new_eviction_(false), first_timer_(true), done_(true, false),
- ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {}
+ BackendImpl(const FilePath& path, base::MessageLoopProxy* cache_thread);
// mask can be used to limit the usable size of the hash table, for testing.
BackendImpl(const FilePath& path, uint32 mask,
- base::MessageLoopProxy* cache_thread)
- : ALLOW_THIS_IN_INITIALIZER_LIST(background_queue_(this, cache_thread)),
- path_(path), block_files_(path), mask_(mask), max_size_(0),
- cache_type_(net::DISK_CACHE), uma_report_(0), user_flags_(kMask),
- init_(false), restarted_(false), unit_test_(false), read_only_(false),
- new_eviction_(false), first_timer_(true), done_(true, false),
- ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {}
+ base::MessageLoopProxy* cache_thread);
~BackendImpl();
// Returns a new backend with the desired flags. See the declaration of
@@ -83,10 +73,7 @@ class BackendImpl : public Backend {
virtual void GetStats(StatsItems* stats);
// Performs the actual initialization and final cleanup on destruction.
- // Cleanup is a two step process (with a trip to the message loop in between).
- // Note that these methods are not intended for external consumption.
int SyncInit();
- void StartCleanup();
void CleanupCache();
// Same bahavior as OpenNextEntry but walks the list from back to front.
@@ -154,9 +141,14 @@ class BackendImpl : public Backend {
// Removes all references to this entry.
void RemoveEntry(EntryImpl* entry);
- // This method must be called whenever an entry is released for the last time.
- // |address| is the cache address of the entry.
- void CacheEntryDestroyed(Addr address);
+ // This method must be called when an entry is released for the last time, so
+ // the entry should not be used anymore. |address| is the cache address of the
+ // entry.
+ void OnEntryDestroyBegin(Addr address);
+
+ // This method must be called after all resources for an entry have been
+ // released.
+ void OnEntryDestroyEnd();
// If the data stored by the provided |rankings| points to an open entry,
// returns a pointer to that entry, otherwise returns NULL. Note that this
@@ -175,6 +167,17 @@ class BackendImpl : public Backend {
// Logs requests that are denied due to being too big.
void TooMuchStorageRequested(int32 size);
+ // Returns true if a temporary buffer is allowed to be extended.
+ bool IsAllocAllowed(int current_size, int new_size);
+
+ // Tracks the release of |size| bytes by an entry buffer.
+ void BufferDeleted(int size);
+
+ // Only intended for testing the two previous methods.
+ int GetTotalBuffersSize() const {
+ return buffer_bytes_;
+ }
+
// Returns true if this instance seems to be under heavy load.
bool IsLoaded() const;
@@ -187,6 +190,9 @@ class BackendImpl : public Backend {
return cache_type_;
}
+ // Returns a weak pointer to this object.
+ base::WeakPtr<BackendImpl> GetWeakPtr();
+
// Returns the group for this client, based on the current cache size.
int GetSizeGroup() const;
@@ -211,6 +217,9 @@ class BackendImpl : public Backend {
void OnRead(int bytes);
void OnWrite(int bytes);
+ // Keeps track of the time needed to complete some IO operations.
+ void OnOperationCompleted(base::TimeDelta elapsed_time);
+
// Timer callback to calculate usage statistics.
void OnStatsTimer();
@@ -236,6 +245,10 @@ class BackendImpl : public Backend {
// Sends a dummy operation through the operation queue, for unit tests.
int FlushQueueForTest(CompletionCallback* callback);
+ // Runs the provided task on the cache thread. The task will be automatically
+ // deleted after it runs.
+ int RunTaskForTest(Task* task, CompletionCallback* callback);
+
// Peforms a simple self-check, and returns the number of dirty items
// or an error code (negative value).
int SelfCheck();
@@ -309,6 +322,9 @@ class BackendImpl : public Backend {
// Part of the self test. Returns false if the entry is corrupt.
bool CheckEntry(EntryImpl* cache_entry);
+ // Returns the maximum total memory for the memory buffers.
+ int MaxBuffersSize();
+
InFlightBackendIO background_queue_; // The controller of pending operations.
scoped_refptr<MappedFile> index_; // The main cache index.
FilePath path_; // Path to the folder used as backing storage.
@@ -324,6 +340,8 @@ class BackendImpl : public Backend {
int num_pending_io_; // Number of pending IO operations.
int entry_count_; // Number of entries accessed lately.
int byte_count_; // Number of bytes read/written lately.
+ int buffer_bytes_; // Total size of the temporary entries' buffers.
+ int io_delay_; // Average time (ms) required to complete some IO operations.
net::CacheType cache_type_;
int uma_report_; // Controls transmision of UMA data.
uint32 user_flags_; // Flags set by the user.
@@ -334,12 +352,14 @@ class BackendImpl : public Backend {
bool disabled_;
bool new_eviction_; // What eviction algorithm should be used.
bool first_timer_; // True if the timer has not been called.
+ bool throttle_requests_;
Stats stats_; // Usage statistcs.
base::RepeatingTimer<BackendImpl> timer_; // Usage timer.
base::WaitableEvent done_; // Signals the end of background work.
scoped_refptr<TraceObject> trace_object_; // Inits internal tracing.
ScopedRunnableMethodFactory<BackendImpl> factory_;
+ base::WeakPtrFactory<BackendImpl> ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BackendImpl);
};
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 7bb27d2..adfc95c 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -6,10 +6,13 @@
#include "base/file_util.h"
#include "base/platform_thread.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/backend_impl.h"
+#include "net/disk_cache/cache_util.h"
#include "net/disk_cache/disk_cache_test_base.h"
#include "net/disk_cache/disk_cache_test_util.h"
#include "net/disk_cache/histogram_macros.h"
@@ -113,6 +116,11 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyBasics) {
BackendBasics();
}
+TEST_F(DiskCacheBackendTest, AppCacheBasics) {
+ SetCacheType(net::APP_CACHE);
+ BackendBasics();
+}
+
void DiskCacheBackendTest::BackendKeying() {
InitCache();
const char* kName1 = "the first key";
@@ -168,6 +176,11 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyKeying) {
BackendKeying();
}
+TEST_F(DiskCacheBackendTest, AppCacheKeying) {
+ SetCacheType(net::APP_CACHE);
+ BackendKeying();
+}
+
TEST_F(DiskCacheTest, CreateBackend) {
TestCompletionCallback cb;
@@ -224,7 +237,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) {
// Now let's create a file with the cache.
disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry("key", &entry));
- ASSERT_EQ(0, entry->WriteData(0, 20000, buffer1, 0, NULL, false));
+ ASSERT_EQ(0, WriteData(entry, 0, 20000, buffer1, 0, false));
entry->Close();
// And verify that the first file is still there.
@@ -355,21 +368,21 @@ void DiskCacheBackendTest::BackendSetSize() {
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(cache_size);
memset(buffer->data(), 0, cache_size);
- EXPECT_EQ(cache_size / 10, entry->WriteData(0, 0, buffer, cache_size / 10,
- NULL, false)) << "normal file";
+ EXPECT_EQ(cache_size / 10, WriteData(entry, 0, 0, buffer, cache_size / 10,
+ false)) << "normal file";
- EXPECT_EQ(net::ERR_FAILED, entry->WriteData(1, 0, buffer, cache_size / 5,
- NULL, false)) << "file size above the limit";
+ EXPECT_EQ(net::ERR_FAILED, WriteData(entry, 1, 0, buffer, cache_size / 5,
+ false)) << "file size above the limit";
// By doubling the total size, we make this file cacheable.
SetMaxSize(cache_size * 2);
- EXPECT_EQ(cache_size / 5, entry->WriteData(1, 0, buffer, cache_size / 5,
- NULL, false));
+ EXPECT_EQ(cache_size / 5, WriteData(entry, 1, 0, buffer, cache_size / 5,
+ false));
// Let's fill up the cache!.
SetMaxSize(cache_size * 10);
- EXPECT_EQ(cache_size * 3 / 4, entry->WriteData(0, 0, buffer,
- cache_size * 3 / 4, NULL, false));
+ EXPECT_EQ(cache_size * 3 / 4, WriteData(entry, 0, 0, buffer,
+ cache_size * 3 / 4, false));
entry->Close();
FlushQueueForTest();
@@ -378,13 +391,13 @@ void DiskCacheBackendTest::BackendSetSize() {
// The cache is 95% full.
ASSERT_EQ(net::OK, CreateEntry(second, &entry));
- EXPECT_EQ(cache_size / 10, entry->WriteData(0, 0, buffer, cache_size / 10,
- NULL, false));
+ EXPECT_EQ(cache_size / 10, WriteData(entry, 0, 0, buffer, cache_size / 10,
+ false));
disk_cache::Entry* entry2;
ASSERT_EQ(net::OK, CreateEntry("an extra key", &entry2));
- EXPECT_EQ(cache_size / 10, entry2->WriteData(0, 0, buffer, cache_size / 10,
- NULL, false));
+ EXPECT_EQ(cache_size / 10, WriteData(entry2, 0, 0, buffer, cache_size / 10,
+ false));
entry2->Close(); // This will trigger the cache trim.
EXPECT_NE(net::OK, OpenEntry(first, &entry2));
@@ -466,29 +479,37 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyLoad) {
BackendLoad();
}
+TEST_F(DiskCacheBackendTest, AppCacheLoad) {
+ SetCacheType(net::APP_CACHE);
+ // Work with a tiny index table (16 entries)
+ SetMask(0xf);
+ SetMaxSize(0x100000);
+ BackendLoad();
+}
+
// Before looking for invalid entries, let's check a valid entry.
void DiskCacheBackendTest::BackendValidEntry() {
SetDirectMode();
InitCache();
std::string key("Some key");
- disk_cache::Entry* entry1;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
memset(buffer1->data(), 0, kSize);
base::strlcpy(buffer1->data(), "And the data to save", kSize);
- EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
- entry1->Close();
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer1, kSize, false));
+ entry->Close();
SimulateCrash();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize);
memset(buffer2->data(), 0, kSize);
- EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer2, kSize, NULL));
- entry1->Close();
+ EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer2, kSize));
+ entry->Close();
EXPECT_STREQ(buffer1->data(), buffer2->data());
}
@@ -510,17 +531,17 @@ void DiskCacheBackendTest::BackendInvalidEntry() {
InitCache();
std::string key("Some key");
- disk_cache::Entry* entry1;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize = 50;
- scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
- memset(buffer1->data(), 0, kSize);
- base::strlcpy(buffer1->data(), "And the data to save", kSize);
- EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+ memset(buffer->data(), 0, kSize);
+ base::strlcpy(buffer->data(), "And the data to save", kSize);
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
SimulateCrash();
- EXPECT_NE(net::OK, OpenEntry(key, &entry1));
+ EXPECT_NE(net::OK, OpenEntry(key, &entry));
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -540,6 +561,12 @@ TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntry) {
BackendInvalidEntry();
}
+// We'll be leaking memory from this test.
+TEST_F(DiskCacheBackendTest, AppCacheInvalidEntry) {
+ SetCacheType(net::APP_CACHE);
+ BackendInvalidEntry();
+}
+
// Almost the same test, but this time crash the cache after reading an entry.
// We'll be leaking memory from this test.
void DiskCacheBackendTest::BackendInvalidEntryRead() {
@@ -548,22 +575,29 @@ void DiskCacheBackendTest::BackendInvalidEntryRead() {
InitCache();
std::string key("Some key");
- disk_cache::Entry* entry1;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize = 50;
- scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
- memset(buffer1->data(), 0, kSize);
- base::strlcpy(buffer1->data(), "And the data to save", kSize);
- EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
- EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer1, kSize, NULL));
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+ memset(buffer->data(), 0, kSize);
+ base::strlcpy(buffer->data(), "And the data to save", kSize);
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer, kSize));
SimulateCrash();
- EXPECT_NE(net::OK, OpenEntry(key, &entry1));
- EXPECT_EQ(0, cache_->GetEntryCount());
+ if (type_ == net::APP_CACHE) {
+ // Reading an entry and crashing should not make it dirty.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(1, cache_->GetEntryCount());
+ entry->Close();
+ } else {
+ EXPECT_NE(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(0, cache_->GetEntryCount());
+ }
}
// We'll be leaking memory from this test.
@@ -578,6 +612,12 @@ TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntryRead) {
}
// We'll be leaking memory from this test.
+TEST_F(DiskCacheBackendTest, AppCacheInvalidEntryRead) {
+ SetCacheType(net::APP_CACHE);
+ BackendInvalidEntryRead();
+}
+
+// We'll be leaking memory from this test.
void DiskCacheBackendTest::BackendInvalidEntryWithLoad() {
// Work with a tiny index table (16 entries)
SetMask(0xf);
@@ -638,6 +678,12 @@ TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntryWithLoad) {
}
// We'll be leaking memory from this test.
+TEST_F(DiskCacheBackendTest, AppCacheInvalidEntryWithLoad) {
+ SetCacheType(net::APP_CACHE);
+ BackendInvalidEntryWithLoad();
+}
+
+// We'll be leaking memory from this test.
void DiskCacheBackendTest::BackendTrimInvalidEntry() {
// Use the implementation directly... we need to simulate a crash.
SetDirectMode();
@@ -653,13 +699,13 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry() {
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
memset(buffer->data(), 0, kSize);
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
// Simulate a crash.
SimulateCrash();
ASSERT_EQ(net::OK, CreateEntry(second, &entry));
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
EXPECT_EQ(2, cache_->GetEntryCount());
SetMaxSize(kSize);
@@ -670,7 +716,14 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry() {
// if it took more than that, we posted a task and we'll delete the second
// entry too.
MessageLoop::current()->RunAllPending();
+
+ // This may be not thread-safe in general, but for now it's OK so add some
+ // ThreadSanitizer annotations to ignore data races on cache_.
+ // See http://crbug.com/55970
+ ANNOTATE_IGNORE_READS_BEGIN();
EXPECT_GE(1, cache_->GetEntryCount());
+ ANNOTATE_IGNORE_READS_END();
+
EXPECT_NE(net::OK, OpenEntry(first, &entry));
}
@@ -701,9 +754,9 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() {
// Writing 32 entries to this cache chains most of them.
for (int i = 0; i < 32; i++) {
- std::string key(StringPrintf("some key %d", i));
+ std::string key(base::StringPrintf("some key %d", i));
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
entry->Close();
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// Note that we are not closing the entries.
@@ -713,7 +766,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() {
SimulateCrash();
ASSERT_EQ(net::OK, CreateEntry("Something else", &entry));
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buffer, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, false));
EXPECT_EQ(33, cache_->GetEntryCount());
SetMaxSize(kSize);
@@ -807,6 +860,11 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyEnumerations) {
BackendEnumerations();
}
+TEST_F(DiskCacheBackendTest, AppCacheEnumerations) {
+ SetCacheType(net::APP_CACHE);
+ BackendEnumerations();
+}
+
// Verifies enumerations while entries are open.
void DiskCacheBackendTest::BackendEnumerations2() {
InitCache();
@@ -823,7 +881,7 @@ void DiskCacheBackendTest::BackendEnumerations2() {
ASSERT_EQ(net::OK, OpenEntry(second, &entry1));
void* iter = NULL;
ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry2));
- ASSERT_EQ(entry2->GetKey(), second);
+ EXPECT_EQ(entry2->GetKey(), second);
// Two entries and the iterator pointing at "first".
entry1->Close();
@@ -831,7 +889,22 @@ void DiskCacheBackendTest::BackendEnumerations2() {
// The iterator should still be valid, so we should not crash.
ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry2));
- ASSERT_EQ(entry2->GetKey(), first);
+ EXPECT_EQ(entry2->GetKey(), first);
+ entry2->Close();
+ cache_->EndEnumeration(&iter);
+
+ // Modify the oldest entry and get the newest element.
+ ASSERT_EQ(net::OK, OpenEntry(first, &entry1));
+ EXPECT_EQ(0, WriteData(entry1, 0, 200, NULL, 0, false));
+ ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry2));
+ if (type_ == net::APP_CACHE) {
+ // The list is not updated.
+ EXPECT_EQ(entry2->GetKey(), second);
+ } else {
+ EXPECT_EQ(entry2->GetKey(), first);
+ }
+
+ entry1->Close();
entry2->Close();
cache_->EndEnumeration(&iter);
}
@@ -850,6 +923,10 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyEnumerations2) {
BackendEnumerations2();
}
+TEST_F(DiskCacheBackendTest, AppCacheEnumerations2) {
+ SetCacheType(net::APP_CACHE);
+ BackendEnumerations2();
+}
// Verify handling of invalid entries while doing enumerations.
// We'll be leaking memory from this test.
@@ -866,10 +943,10 @@ void DiskCacheBackendTest::BackendInvalidEntryEnumeration() {
scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
memset(buffer1->data(), 0, kSize);
base::strlcpy(buffer1->data(), "And the data to save", kSize);
- EXPECT_EQ(kSize, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry1, 0, 0, buffer1, kSize, false));
entry1->Close();
ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
- EXPECT_EQ(kSize, entry1->ReadData(0, 0, buffer1, kSize, NULL));
+ EXPECT_EQ(kSize, ReadData(entry1, 0, 0, buffer1, kSize));
std::string key2("Another key");
ASSERT_EQ(net::OK, CreateEntry(key2, &entry2));
@@ -1499,8 +1576,8 @@ void DiskCacheBackendTest::BackendDisable4() {
const int kBufSize = 20000;
scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kBufSize);
memset(buf->data(), 0, kBufSize);
- EXPECT_EQ(100, entry2->WriteData(0, 0, buf, 100, NULL, false));
- EXPECT_EQ(kBufSize, entry3->WriteData(0, 0, buf, kBufSize, NULL, false));
+ EXPECT_EQ(100, WriteData(entry2, 0, 0, buf, 100, false));
+ EXPECT_EQ(kBufSize, WriteData(entry3, 0, 0, buf, kBufSize, false));
// This line should disable the cache but not delete it.
EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry4));
@@ -1508,13 +1585,13 @@ void DiskCacheBackendTest::BackendDisable4() {
EXPECT_NE(net::OK, CreateEntry("cache is disabled", &entry4));
- EXPECT_EQ(100, entry2->ReadData(0, 0, buf, 100, NULL));
- EXPECT_EQ(100, entry2->WriteData(0, 0, buf, 100, NULL, false));
- EXPECT_EQ(100, entry2->WriteData(1, 0, buf, 100, NULL, false));
+ EXPECT_EQ(100, ReadData(entry2, 0, 0, buf, 100));
+ EXPECT_EQ(100, WriteData(entry2, 0, 0, buf, 100, false));
+ EXPECT_EQ(100, WriteData(entry2, 1, 0, buf, 100, false));
- EXPECT_EQ(kBufSize, entry3->ReadData(0, 0, buf, kBufSize, NULL));
- EXPECT_EQ(kBufSize, entry3->WriteData(0, 0, buf, kBufSize, NULL, false));
- EXPECT_EQ(kBufSize, entry3->WriteData(1, 0, buf, kBufSize, NULL, false));
+ EXPECT_EQ(kBufSize, ReadData(entry3, 0, 0, buf, kBufSize));
+ EXPECT_EQ(kBufSize, WriteData(entry3, 0, 0, buf, kBufSize, false));
+ EXPECT_EQ(kBufSize, WriteData(entry3, 1, 0, buf, kBufSize, false));
std::string key = entry2->GetKey();
EXPECT_EQ(sizeof(key2) - 1, key.size());
@@ -1622,6 +1699,11 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyDoomAll) {
BackendDoomAll();
}
+TEST_F(DiskCacheBackendTest, AppCacheOnlyDoomAll) {
+ SetCacheType(net::APP_CACHE);
+ BackendDoomAll();
+}
+
// If the index size changes when we doom the cache, we should not crash.
void DiskCacheBackendTest::BackendDoomAll2() {
EXPECT_EQ(2, cache_->GetEntryCount());
@@ -1747,3 +1829,105 @@ TEST_F(DiskCacheBackendTest, Histograms) {
CACHE_UMA(HOURS, "FillupTime", i, 28);
}
}
+
+// Make sure that we keep the total memory used by the internal buffers under
+// control.
+TEST_F(DiskCacheBackendTest, TotalBuffersSize1) {
+ SetDirectMode();
+ InitCache();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+ const int kSize = 200;
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buffer->data(), kSize, true);
+
+ for (int i = 0; i < 10; i++) {
+ SCOPED_TRACE(i);
+ // Allocate 2MB for this entry.
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buffer, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 1024 * 1024, buffer, kSize, false));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 1024 * 1024, buffer, kSize, false));
+
+ // Delete one of the buffers and truncate the other.
+ EXPECT_EQ(0, WriteData(entry, 0, 0, buffer, 0, true));
+ EXPECT_EQ(0, WriteData(entry, 1, 10, buffer, 0, true));
+
+ // Delete the second buffer, writing 10 bytes to disk.
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ }
+
+ entry->Close();
+ EXPECT_EQ(0, cache_impl_->GetTotalBuffersSize());
+}
+
+// This test assumes at least 150MB of system memory.
+TEST_F(DiskCacheBackendTest, TotalBuffersSize2) {
+ SetDirectMode();
+ InitCache();
+
+ const int kOneMB = 1024 * 1024;
+ EXPECT_TRUE(cache_impl_->IsAllocAllowed(0, kOneMB));
+ EXPECT_EQ(kOneMB, cache_impl_->GetTotalBuffersSize());
+
+ EXPECT_TRUE(cache_impl_->IsAllocAllowed(0, kOneMB));
+ EXPECT_EQ(kOneMB * 2, cache_impl_->GetTotalBuffersSize());
+
+ EXPECT_TRUE(cache_impl_->IsAllocAllowed(0, kOneMB));
+ EXPECT_EQ(kOneMB * 3, cache_impl_->GetTotalBuffersSize());
+
+ cache_impl_->BufferDeleted(kOneMB);
+ EXPECT_EQ(kOneMB * 2, cache_impl_->GetTotalBuffersSize());
+
+ // Check the upper limit.
+ EXPECT_FALSE(cache_impl_->IsAllocAllowed(0, 30 * kOneMB));
+
+ for (int i = 0; i < 30; i++)
+ cache_impl_->IsAllocAllowed(0, kOneMB); // Ignore the result.
+
+ EXPECT_FALSE(cache_impl_->IsAllocAllowed(0, kOneMB));
+}
+
+// Tests that sharing of external files works and we are able to delete the
+// files when we need to.
+TEST_F(DiskCacheBackendTest, FileSharing) {
+ SetDirectMode();
+ InitCache();
+
+ disk_cache::Addr address(0x80000001);
+ ASSERT_TRUE(cache_impl_->CreateExternalFile(&address));
+ FilePath name = cache_impl_->GetFileName(address);
+
+ scoped_refptr<disk_cache::File> file(new disk_cache::File(false));
+ file->Init(name);
+
+#if defined(OS_WIN)
+ DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD access = GENERIC_READ | GENERIC_WRITE;
+ ScopedHandle file2(CreateFile(name.value().c_str(), access, sharing, NULL,
+ OPEN_EXISTING, 0, NULL));
+ EXPECT_FALSE(file2.IsValid());
+
+ sharing |= FILE_SHARE_DELETE;
+ file2.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
+ OPEN_EXISTING, 0, NULL));
+ EXPECT_TRUE(file2.IsValid());
+#endif
+
+ EXPECT_TRUE(file_util::Delete(name, false));
+
+ // We should be able to use the file.
+ const int kSize = 200;
+ char buffer1[kSize];
+ char buffer2[kSize];
+ memset(buffer1, 't', kSize);
+ memset(buffer2, 0, kSize);
+ EXPECT_TRUE(file->Write(buffer1, kSize, 0));
+ EXPECT_TRUE(file->Read(buffer2, kSize, 0));
+ EXPECT_EQ(0, memcmp(buffer1, buffer2, kSize));
+
+ EXPECT_TRUE(disk_cache::DeleteCacheFile(name));
+}
diff --git a/net/disk_cache/bitmap.h b/net/disk_cache/bitmap.h
index 4d38f83..8e24e15 100644
--- a/net/disk_cache/bitmap.h
+++ b/net/disk_cache/bitmap.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_BITMAP_H_
#define NET_DISK_CACHE_BITMAP_H_
+#pragma once
#include <algorithm>
diff --git a/net/disk_cache/block_files.cc b/net/disk_cache/block_files.cc
index 48e5be3..a0fc6b6 100644
--- a/net/disk_cache/block_files.cc
+++ b/net/disk_cache/block_files.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2010 The Chromium 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,9 +7,12 @@
#include "base/file_util.h"
#include "base/histogram.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/thread_checker.h"
#include "base/time.h"
#include "net/disk_cache/cache_util.h"
#include "net/disk_cache/file_lock.h"
+#include "net/disk_cache/trace.h"
using base::TimeTicks;
@@ -57,6 +60,7 @@ bool CreateMapBlock(int target, int size, disk_cache::BlockFileHeader* header,
disk_cache::FileLock lock(header);
int index_offset = j * 4 + 4 - target;
*index = current * 32 + index_offset;
+ DCHECK_EQ(*index / 4, (*index + size - 1) / 4);
uint32 to_add = ((1 << size) - 1) << index_offset;
header->allocation_map[current] |= to_add;
@@ -118,6 +122,25 @@ void DeleteMapBlock(int index, int size, disk_cache::BlockFileHeader* header) {
HISTOGRAM_TIMES("DiskCache.DeleteBlock", TimeTicks::Now() - start);
}
+// Returns true if the specified block is used. Note that this is a simplified
+// version of DeleteMapBlock().
+bool UsedMapBlock(int index, int size, disk_cache::BlockFileHeader* header) {
+ if (size < 0 || size > disk_cache::kMaxNumBlocks) {
+ NOTREACHED();
+ return false;
+ }
+ int byte_index = index / 8;
+ uint8* byte_map = reinterpret_cast<uint8*>(header->allocation_map);
+ uint8 map_block = byte_map[byte_index];
+
+ if (index % 8 >= 4)
+ map_block >>= 4;
+
+ DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
+ uint8 to_clear = ((1 << size) - 1) << (index % 8);
+ return ((byte_map[byte_index] & to_clear) == to_clear);
+}
+
// Restores the "empty counters" and allocation hints.
void FixAllocationCounters(disk_cache::BlockFileHeader* header) {
for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) {
@@ -161,6 +184,10 @@ bool NeedToGrowBlockFile(const disk_cache::BlockFileHeader* header,
namespace disk_cache {
+BlockFiles::BlockFiles(const FilePath& path)
+ : init_(false), zero_buffer_(NULL), path_(path) {
+}
+
BlockFiles::~BlockFiles() {
if (zero_buffer_)
delete[] zero_buffer_;
@@ -172,6 +199,8 @@ bool BlockFiles::Init(bool create_files) {
if (init_)
return false;
+ thread_checker_.reset(new ThreadChecker);
+
block_files_.resize(kFirstAdditionalBlockFile);
for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
if (create_files)
@@ -190,6 +219,9 @@ bool BlockFiles::Init(bool create_files) {
}
void BlockFiles::CloseFiles() {
+ if (init_) {
+ DCHECK(thread_checker_->CalledOnValidThread());
+ }
init_ = false;
for (unsigned int i = 0; i < block_files_.size(); i++) {
if (block_files_[i]) {
@@ -201,6 +233,7 @@ void BlockFiles::CloseFiles() {
}
void BlockFiles::ReportStats() {
+ DCHECK(thread_checker_->CalledOnValidThread());
int used_blocks[kFirstAdditionalBlockFile];
int load[kFirstAdditionalBlockFile];
for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
@@ -217,6 +250,36 @@ void BlockFiles::ReportStats() {
UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101);
}
+bool BlockFiles::IsValid(Addr address) {
+#ifdef NDEBUG
+ return true;
+#else
+ if (!address.is_initialized() || address.is_separate_file())
+ return false;
+
+ MappedFile* file = GetFile(address);
+ if (!file)
+ return false;
+
+ BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
+ bool rv = UsedMapBlock(address.start_block(), address.num_blocks(), header);
+ DCHECK(rv);
+
+ static bool read_contents = false;
+ if (read_contents) {
+ scoped_array<char> buffer;
+ buffer.reset(new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]);
+ size_t size = address.BlockSize() * address.num_blocks();
+ size_t offset = address.start_block() * address.BlockSize() +
+ kBlockHeaderSize;
+ bool ok = file->Read(buffer.get(), size, offset);
+ DCHECK(ok);
+ }
+
+ return rv;
+#endif
+}
+
bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) {
FilePath name = Name(index);
int flags =
@@ -224,7 +287,7 @@ bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) {
flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE;
scoped_refptr<File> file(new File(
- base::CreatePlatformFile(name, flags, NULL)));
+ base::CreatePlatformFile(name, flags, NULL, NULL)));
if (!file->IsValid())
return false;
@@ -282,6 +345,7 @@ bool BlockFiles::OpenBlockFile(int index) {
}
MappedFile* BlockFiles::GetFile(Addr address) {
+ DCHECK(thread_checker_->CalledOnValidThread());
DCHECK(block_files_.size() >= 4);
DCHECK(address.is_block_file() || !address.is_initialized());
if (!address.is_initialized())
@@ -402,10 +466,15 @@ void BlockFiles::RemoveEmptyFile(FileType block_type) {
int file_index = header->next_file;
header->next_file = next_header->next_file;
DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index));
+
+ // We get a new handle to the file and release the old one so that the
+ // file gets unmmaped... so we can delete it.
+ FilePath name = Name(file_index);
+ scoped_refptr<File> this_file(new File(false));
+ this_file->Init(name);
block_files_[file_index]->Release();
block_files_[file_index] = NULL;
- FilePath name = Name(file_index);
int failure = DeleteCacheFile(name) ? 0 : 1;
UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
if (failure)
@@ -420,6 +489,7 @@ void BlockFiles::RemoveEmptyFile(FileType block_type) {
bool BlockFiles::CreateBlock(FileType block_type, int block_count,
Addr* block_address) {
+ DCHECK(thread_checker_->CalledOnValidThread());
if (block_type < RANKINGS || block_type > BLOCK_4K ||
block_count < 1 || block_count > 4)
return false;
@@ -447,10 +517,12 @@ bool BlockFiles::CreateBlock(FileType block_type, int block_count,
Addr address(block_type, block_count, header->this_file, index);
block_address->set_value(address.value());
+ Trace("CreateBlock 0x%x", address.value());
return true;
}
void BlockFiles::DeleteBlock(Addr address, bool deep) {
+ DCHECK(thread_checker_->CalledOnValidThread());
if (!address.is_initialized() || address.is_separate_file())
return;
@@ -462,14 +534,17 @@ void BlockFiles::DeleteBlock(Addr address, bool deep) {
if (!file)
return;
+ Trace("DeleteBlock 0x%x", address.value());
+
+ BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
+ DeleteMapBlock(address.start_block(), address.num_blocks(), header);
+
size_t size = address.BlockSize() * address.num_blocks();
size_t offset = address.start_block() * address.BlockSize() +
kBlockHeaderSize;
if (deep)
file->Write(zero_buffer_, size, offset);
- BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
- DeleteMapBlock(address.start_block(), address.num_blocks(), header);
if (!header->num_entries) {
// This file is now empty. Let's try to delete it.
FileType type = Addr::RequiredFileType(header->entry_size);
@@ -503,7 +578,7 @@ bool BlockFiles::FixBlockFileHeader(MappedFile* file) {
return true;
}
-// We are interested in the total number of block used by this file type, and
+// We are interested in the total number of blocks used by this file type, and
// the max number of blocks that we can store (reported as the percentage of
// used blocks). In order to find out the number of used blocks, we have to
// substract the empty blocks from the total blocks for each file in the chain.
@@ -537,7 +612,7 @@ void BlockFiles::GetFileStats(int index, int* used_count, int* load) {
FilePath BlockFiles::Name(int index) {
// The file format allows for 256 files.
DCHECK(index < 256 || index >= 0);
- std::string tmp = StringPrintf("%s%d", kBlockName, index);
+ std::string tmp = base::StringPrintf("%s%d", kBlockName, index);
return path_.AppendASCII(tmp);
}
diff --git a/net/disk_cache/block_files.h b/net/disk_cache/block_files.h
index 3ed19de..5427a58 100644
--- a/net/disk_cache/block_files.h
+++ b/net/disk_cache/block_files.h
@@ -6,23 +6,24 @@
#ifndef NET_DISK_CACHE_BLOCK_FILES_H__
#define NET_DISK_CACHE_BLOCK_FILES_H__
+#pragma once
#include <vector>
#include "base/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/scoped_ptr.h"
#include "net/disk_cache/addr.h"
#include "net/disk_cache/mapped_file.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
-namespace disk_cache {
+class ThreadChecker;
-class EntryImpl;
+namespace disk_cache {
// This class handles the set of block-files open by the disk cache.
class BlockFiles {
public:
- explicit BlockFiles(const FilePath& path)
- : init_(false), zero_buffer_(NULL), path_(path) {}
+ explicit BlockFiles(const FilePath& path);
~BlockFiles();
// Performs the object initialization. create_files indicates if the backing
@@ -49,6 +50,10 @@ class BlockFiles {
// Sends UMA stats.
void ReportStats();
+ // Returns true if the blocks pointed by a given address are currently used.
+ // This method is only intended for debugging.
+ bool IsValid(Addr address);
+
private:
// Set force to true to overwrite the file if it exists.
bool CreateBlockFile(int index, FileType file_type, bool force);
@@ -82,10 +87,11 @@ class BlockFiles {
char* zero_buffer_; // Buffer to speed-up cleaning deleted entries.
FilePath path_; // Path to the backing folder.
std::vector<MappedFile*> block_files_; // The actual files.
+ scoped_ptr<ThreadChecker> thread_checker_;
- FRIEND_TEST(DiskCacheTest, BlockFiles_ZeroSizeFile);
- FRIEND_TEST(DiskCacheTest, BlockFiles_InvalidFile);
- FRIEND_TEST(DiskCacheTest, BlockFiles_Stats);
+ FRIEND_TEST_ALL_PREFIXES(DiskCacheTest, BlockFiles_ZeroSizeFile);
+ FRIEND_TEST_ALL_PREFIXES(DiskCacheTest, BlockFiles_InvalidFile);
+ FRIEND_TEST_ALL_PREFIXES(DiskCacheTest, BlockFiles_Stats);
DISALLOW_COPY_AND_ASSIGN(BlockFiles);
};
diff --git a/net/disk_cache/block_files_unittest.cc b/net/disk_cache/block_files_unittest.cc
index 2c87179..90bf048 100644
--- a/net/disk_cache/block_files_unittest.cc
+++ b/net/disk_cache/block_files_unittest.cc
@@ -225,4 +225,53 @@ TEST_F(DiskCacheTest, BlockFiles_Stats) {
EXPECT_EQ(0, load);
}
+// Tests that we add and remove blocks correctly.
+TEST_F(DiskCacheTest, AllocationMap) {
+ FilePath path = GetCacheFilePath();
+ ASSERT_TRUE(DeleteCache(path));
+ ASSERT_TRUE(file_util::CreateDirectory(path));
+
+ BlockFiles files(path);
+ ASSERT_TRUE(files.Init(true));
+
+ // Create a bunch of entries.
+ const int kSize = 100;
+ Addr address[kSize];
+ for (int i = 0; i < kSize; i++) {
+ SCOPED_TRACE(i);
+ int block_size = i % 4 + 1;
+ EXPECT_TRUE(files.CreateBlock(BLOCK_1K, block_size, &address[i]));
+ EXPECT_EQ(BLOCK_1K, address[i].file_type());
+ EXPECT_EQ(block_size, address[i].num_blocks());
+ int start = address[i].start_block();
+ EXPECT_EQ(start / 4, (start + block_size - 1) / 4);
+ }
+
+ for (int i = 0; i < kSize; i++) {
+ SCOPED_TRACE(i);
+ EXPECT_TRUE(files.IsValid(address[i]));
+ }
+
+ // The first part of the allocation map should be completely filled. We used
+ // 10 bits per each four entries, so 250 bits total.
+ BlockFileHeader* header =
+ reinterpret_cast<BlockFileHeader*>(files.GetFile(address[0])->buffer());
+ uint8* buffer = reinterpret_cast<uint8*>(&header->allocation_map);
+ for (int i =0; i < 29; i++) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(0xff, buffer[i]);
+ }
+
+ for (int i = 0; i < kSize; i++) {
+ SCOPED_TRACE(i);
+ files.DeleteBlock(address[i], false);
+ }
+
+ // The allocation map should be empty.
+ for (int i =0; i < 50; i++) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(0, buffer[i]);
+ }
+}
+
} // namespace disk_cache
diff --git a/net/disk_cache/cache_util.h b/net/disk_cache/cache_util.h
index cb78f16..455bf30 100644
--- a/net/disk_cache/cache_util.h
+++ b/net/disk_cache/cache_util.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef NET_DISK_CACHE_CACHE_UTIL_H_
#define NET_DISK_CACHE_CACHE_UTIL_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
diff --git a/net/disk_cache/cache_util_win.cc b/net/disk_cache/cache_util_win.cc
index aefce30..3e1d673 100644
--- a/net/disk_cache/cache_util_win.cc
+++ b/net/disk_cache/cache_util_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -58,7 +58,21 @@ void DeleteCache(const FilePath& path, bool remove_folder) {
bool DeleteCacheFile(const FilePath& name) {
// We do a simple delete, without ever falling back to SHFileOperation, as the
// version from base does.
- return DeleteFile(name.value().c_str()) ? true : false;
+ if (!DeleteFile(name.value().c_str())) {
+ // There is an error, but we share delete access so let's see if there is a
+ // file to open. Note that this code assumes that we have a handle to the
+ // file at all times (even now), so nobody can have a handle that prevents
+ // us from opening the file again (unless it was deleted).
+ DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ DWORD access = SYNCHRONIZE;
+ ScopedHandle file(CreateFile(name.value().c_str(), access, sharing, NULL,
+ OPEN_EXISTING, 0, NULL));
+ if (file.IsValid())
+ return false;
+
+ // Most likely there is no file to open... and that's what we wanted.
+ }
+ return true;
}
} // namespace disk_cache
diff --git a/net/disk_cache/disk_cache.h b/net/disk_cache/disk_cache.h
index b2d76a4..59efe06 100644
--- a/net/disk_cache/disk_cache.h
+++ b/net/disk_cache/disk_cache.h
@@ -7,6 +7,7 @@
#ifndef NET_DISK_CACHE_DISK_CACHE_H_
#define NET_DISK_CACHE_DISK_CACHE_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/net/disk_cache/disk_cache_test_base.cc b/net/disk_cache/disk_cache_test_base.cc
index 0add3c7..cffe3fa 100644
--- a/net/disk_cache/disk_cache_test_base.cc
+++ b/net/disk_cache/disk_cache_test_base.cc
@@ -4,6 +4,7 @@
#include "net/disk_cache/disk_cache_test_base.h"
+#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/backend_impl.h"
@@ -73,7 +74,7 @@ void DiskCacheTestWithCache::InitDiskCache() {
TestCompletionCallback cb;
int rv = disk_cache::BackendImpl::CreateBackend(
- path, force_creation_, size_, net::DISK_CACHE,
+ path, force_creation_, size_, type_,
disk_cache::kNoRandom, thread, &cache_, &cb);
ASSERT_EQ(net::OK, cb.GetResult(rv));
}
@@ -96,6 +97,7 @@ void DiskCacheTestWithCache::InitDiskCacheImpl(const FilePath& path) {
if (new_eviction_)
cache_impl_->SetNewEviction();
+ cache_impl_->SetType(type_);
cache_impl_->SetFlags(disk_cache::kNoRandom);
TestCompletionCallback cb;
int rv = cache_impl_->Init(&cb);
@@ -190,3 +192,47 @@ void DiskCacheTestWithCache::FlushQueueForTest() {
int rv = cache_impl_->FlushQueueForTest(&cb);
EXPECT_EQ(net::OK, cb.GetResult(rv));
}
+
+void DiskCacheTestWithCache::RunTaskForTest(Task* task) {
+ if (memory_only_ || !cache_impl_) {
+ task->Run();
+ delete task;
+ return;
+ }
+
+ TestCompletionCallback cb;
+ int rv = cache_impl_->RunTaskForTest(task, &cb);
+ EXPECT_EQ(net::OK, cb.GetResult(rv));
+}
+
+int DiskCacheTestWithCache::ReadData(disk_cache::Entry* entry, int index,
+ int offset, net::IOBuffer* buf, int len) {
+ TestCompletionCallback cb;
+ int rv = entry->ReadData(index, offset, buf, len, &cb);
+ return cb.GetResult(rv);
+}
+
+
+int DiskCacheTestWithCache::WriteData(disk_cache::Entry* entry, int index,
+ int offset, net::IOBuffer* buf, int len,
+ bool truncate) {
+ TestCompletionCallback cb;
+ int rv = entry->WriteData(index, offset, buf, len, &cb, truncate);
+ return cb.GetResult(rv);
+}
+
+int DiskCacheTestWithCache::ReadSparseData(disk_cache::Entry* entry,
+ int64 offset, net::IOBuffer* buf,
+ int len) {
+ TestCompletionCallback cb;
+ int rv = entry->ReadSparseData(offset, buf, len, &cb);
+ return cb.GetResult(rv);
+}
+
+int DiskCacheTestWithCache::WriteSparseData(disk_cache::Entry* entry,
+ int64 offset,
+ net::IOBuffer* buf, int len) {
+ TestCompletionCallback cb;
+ int rv = entry->WriteSparseData(offset, buf, len, &cb);
+ return cb.GetResult(rv);
+}
diff --git a/net/disk_cache/disk_cache_test_base.h b/net/disk_cache/disk_cache_test_base.h
index 6c6b54b..faecc17 100644
--- a/net/disk_cache/disk_cache_test_base.h
+++ b/net/disk_cache/disk_cache_test_base.h
@@ -4,14 +4,22 @@
#ifndef NET_DISK_CACHE_DISK_CACHE_TEST_BASE_H_
#define NET_DISK_CACHE_DISK_CACHE_TEST_BASE_H_
+#pragma once
#include "base/basictypes.h"
#include "base/thread.h"
+#include "net/base/cache_type.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
class FilePath;
+namespace net {
+
+class IOBuffer;
+
+} // namespace net
+
namespace disk_cache {
class Backend;
@@ -34,9 +42,10 @@ class DiskCacheTestWithCache : public DiskCacheTest {
protected:
DiskCacheTestWithCache()
: cache_(NULL), cache_impl_(NULL), mem_cache_(NULL), mask_(0), size_(0),
- memory_only_(false), implementation_(false), force_creation_(false),
- new_eviction_(false), first_cleanup_(true), integrity_(true),
- use_current_thread_(false), cache_thread_("CacheThread") {}
+ type_(net::DISK_CACHE), memory_only_(false), implementation_(false),
+ force_creation_(false), new_eviction_(false), first_cleanup_(true),
+ integrity_(true), use_current_thread_(false),
+ cache_thread_("CacheThread") {}
void InitCache();
virtual void TearDown();
@@ -79,6 +88,10 @@ class DiskCacheTestWithCache : public DiskCacheTest {
use_current_thread_ = true;
}
+ void SetCacheType(net::CacheType type) {
+ type_ = type;
+ }
+
// Utility methods to access the cache and wait for each operation to finish.
int OpenEntry(const std::string& key, disk_cache::Entry** entry);
int CreateEntry(const std::string& key, disk_cache::Entry** entry);
@@ -89,6 +102,15 @@ class DiskCacheTestWithCache : public DiskCacheTest {
int DoomEntriesSince(const base::Time initial_time);
int OpenNextEntry(void** iter, disk_cache::Entry** next_entry);
void FlushQueueForTest();
+ void RunTaskForTest(Task* task);
+ int ReadData(disk_cache::Entry* entry, int index, int offset,
+ net::IOBuffer* buf, int len);
+ int WriteData(disk_cache::Entry* entry, int index, int offset,
+ net::IOBuffer* buf, int len, bool truncate);
+ int ReadSparseData(disk_cache::Entry* entry, int64 offset, net::IOBuffer* buf,
+ int len);
+ int WriteSparseData(disk_cache::Entry* entry, int64 offset,
+ net::IOBuffer* buf, int len);
// cache_ will always have a valid object, regardless of how the cache was
// initialized. The implementation pointers can be NULL.
@@ -98,6 +120,7 @@ class DiskCacheTestWithCache : public DiskCacheTest {
uint32 mask_;
int size_;
+ net::CacheType type_;
bool memory_only_;
bool implementation_;
bool force_creation_;
diff --git a/net/disk_cache/disk_cache_test_util.cc b/net/disk_cache/disk_cache_test_util.cc
index 46e33db..7dd618a 100644
--- a/net/disk_cache/disk_cache_test_util.cc
+++ b/net/disk_cache/disk_cache_test_util.cc
@@ -65,7 +65,7 @@ bool CreateCacheTestFile(const FilePath& name) {
base::PLATFORM_FILE_WRITE;
scoped_refptr<disk_cache::File> file(new disk_cache::File(
- base::CreatePlatformFile(name, flags, NULL)));
+ base::CreatePlatformFile(name, flags, NULL, NULL)));
if (!file->IsValid())
return false;
@@ -151,6 +151,9 @@ MessageLoopHelper::MessageLoopHelper()
TimeDelta::FromMilliseconds(50), this, &MessageLoopHelper::TimerExpired);
}
+MessageLoopHelper::~MessageLoopHelper() {
+}
+
bool MessageLoopHelper::WaitUntilCacheIoFinished(int num_callbacks) {
if (num_callbacks == g_cache_tests_received)
return true;
diff --git a/net/disk_cache/disk_cache_test_util.h b/net/disk_cache/disk_cache_test_util.h
index 7249ee0..f6348e9 100644
--- a/net/disk_cache/disk_cache_test_util.h
+++ b/net/disk_cache/disk_cache_test_util.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_DISK_CACHE_DISK_CACHE_TEST_UTIL_H_
#define NET_DISK_CACHE_DISK_CACHE_TEST_UTIL_H_
+#pragma once
#include <string>
@@ -13,8 +14,6 @@
#include "base/timer.h"
#include "build/build_config.h"
-class FilePath;
-
// Re-creates a given test file inside the cache test folder.
bool CreateCacheTestFile(const FilePath& name);
@@ -41,7 +40,8 @@ bool CheckCacheIntegrity(const FilePath& path, bool new_eviction);
class ScopedTestCache {
public:
ScopedTestCache();
- ScopedTestCache(const std::string& name); // Use a specific folder name.
+ // Use a specific folder name.
+ explicit ScopedTestCache(const std::string& name);
~ScopedTestCache();
FilePath path() const { return path_; }
@@ -76,6 +76,7 @@ class CallbackTest : public CallbackRunner< Tuple1<int> > {
class MessageLoopHelper {
public:
MessageLoopHelper();
+ ~MessageLoopHelper();
// Run the message loop and wait for num_callbacks before returning. Returns
// false if we are waiting to long.
diff --git a/net/disk_cache/disk_format.h b/net/disk_cache/disk_format.h
index 619bd89..ac4c634 100644
--- a/net/disk_cache/disk_format.h
+++ b/net/disk_cache/disk_format.h
@@ -54,6 +54,7 @@
#ifndef NET_DISK_CACHE_DISK_FORMAT_H_
#define NET_DISK_CACHE_DISK_FORMAT_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc
index a017549..0655b28 100644
--- a/net/disk_cache/entry_impl.cc
+++ b/net/disk_cache/entry_impl.cc
@@ -64,25 +64,218 @@ void SyncCallback::Discard() {
OnFileIOComplete(0);
}
-// Clears buffer before offset and after valid_len, knowing that the size of
-// buffer is kMaxBlockSize.
-void ClearInvalidData(char* buffer, int offset, int valid_len) {
- DCHECK_GE(offset, 0);
- DCHECK_GE(valid_len, 0);
- DCHECK(disk_cache::kMaxBlockSize >= offset + valid_len);
- if (offset)
- memset(buffer, 0, offset);
- int end = disk_cache::kMaxBlockSize - offset - valid_len;
- if (end)
- memset(buffer + offset + valid_len, 0, end);
-}
+const int kMaxBufferSize = 1024 * 1024; // 1 MB.
} // namespace
namespace disk_cache {
-EntryImpl::EntryImpl(BackendImpl* backend, Addr address)
- : entry_(NULL, Addr(0)), node_(NULL, Addr(0)) {
+// This class handles individual memory buffers that store data before it is
+// sent to disk. The buffer can start at any offset, but if we try to write to
+// anywhere in the first 16KB of the file (kMaxBlockSize), we set the offset to
+// zero. The buffer grows up to a size determined by the backend, to keep the
+// total memory used under control.
+class EntryImpl::UserBuffer {
+ public:
+ explicit UserBuffer(BackendImpl* backend)
+ : backend_(backend->GetWeakPtr()), offset_(0), grow_allowed_(true) {
+ buffer_.reserve(kMaxBlockSize);
+ }
+ ~UserBuffer() {
+ if (backend_)
+ backend_->BufferDeleted(capacity() - kMaxBlockSize);
+ }
+
+ // Returns true if we can handle writing |len| bytes to |offset|.
+ bool PreWrite(int offset, int len);
+
+ // Truncates the buffer to |offset| bytes.
+ void Truncate(int offset);
+
+ // Writes |len| bytes from |buf| at the given |offset|.
+ void Write(int offset, net::IOBuffer* buf, int len);
+
+ // Returns true if we can read |len| bytes from |offset|, given that the
+ // actual file has |eof| bytes stored. Note that the number of bytes to read
+ // may be modified by this method even though it returns false: that means we
+ // should do a smaller read from disk.
+ bool PreRead(int eof, int offset, int* len);
+
+ // Read |len| bytes from |buf| at the given |offset|.
+ int Read(int offset, net::IOBuffer* buf, int len);
+
+ // Prepare this buffer for reuse.
+ void Reset();
+
+ char* Data() { return buffer_.size() ? &buffer_[0] : NULL; }
+ int Size() { return static_cast<int>(buffer_.size()); }
+ int Start() { return offset_; }
+ int End() { return offset_ + Size(); }
+
+ private:
+ int capacity() { return static_cast<int>(buffer_.capacity()); }
+ bool GrowBuffer(int required, int limit);
+
+ base::WeakPtr<BackendImpl> backend_;
+ int offset_;
+ std::vector<char> buffer_;
+ bool grow_allowed_;
+ DISALLOW_COPY_AND_ASSIGN(UserBuffer);
+};
+
+bool EntryImpl::UserBuffer::PreWrite(int offset, int len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GE(len, 0);
+ DCHECK_GE(offset + len, 0);
+
+ // We don't want to write before our current start.
+ if (offset < offset_)
+ return false;
+
+ // Lets get the common case out of the way.
+ if (offset + len <= capacity())
+ return true;
+
+ // If we are writing to the first 16K (kMaxBlockSize), we want to keep the
+ // buffer offset_ at 0.
+ if (!Size() && offset > kMaxBlockSize)
+ return GrowBuffer(len, kMaxBufferSize);
+
+ int required = offset - offset_ + len;
+ return GrowBuffer(required, kMaxBufferSize * 6 / 5);
+}
+
+void EntryImpl::UserBuffer::Truncate(int offset) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GE(offset, offset_);
+
+ offset -= offset_;
+ if (Size() >= offset)
+ buffer_.resize(offset);
+}
+
+void EntryImpl::UserBuffer::Write(int offset, net::IOBuffer* buf, int len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GE(len, 0);
+ DCHECK_GE(offset + len, 0);
+ DCHECK_GE(offset, offset_);
+
+ if (!Size() && offset > kMaxBlockSize)
+ offset_ = offset;
+
+ offset -= offset_;
+
+ if (offset > Size())
+ buffer_.resize(offset);
+
+ if (!len)
+ return;
+
+ char* buffer = buf->data();
+ int valid_len = Size() - offset;
+ int copy_len = std::min(valid_len, len);
+ if (copy_len) {
+ memcpy(&buffer_[offset], buffer, copy_len);
+ len -= copy_len;
+ buffer += copy_len;
+ }
+ if (!len)
+ return;
+
+ buffer_.insert(buffer_.end(), buffer, buffer + len);
+}
+
+bool EntryImpl::UserBuffer::PreRead(int eof, int offset, int* len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GT(*len, 0);
+
+ if (offset < offset_) {
+ // We are reading before this buffer.
+ if (offset >= eof)
+ return true;
+
+ // If the read overlaps with the buffer, change its length so that there is
+ // no overlap.
+ *len = std::min(*len, offset_ - offset);
+ *len = std::min(*len, eof - offset);
+
+ // We should read from disk.
+ return false;
+ }
+
+ if (!Size())
+ return false;
+
+ // See if we can fulfill the first part of the operation.
+ return (offset - offset_ < Size());
+}
+
+int EntryImpl::UserBuffer::Read(int offset, net::IOBuffer* buf, int len) {
+ DCHECK_GE(offset, 0);
+ DCHECK_GT(len, 0);
+ DCHECK(Size() || offset < offset_);
+
+ int clean_bytes = 0;
+ if (offset < offset_) {
+ // We don't have a file so lets fill the first part with 0.
+ clean_bytes = std::min(offset_ - offset, len);
+ memset(buf->data(), 0, clean_bytes);
+ if (len == clean_bytes)
+ return len;
+ offset = offset_;
+ len -= clean_bytes;
+ }
+
+ int start = offset - offset_;
+ int available = Size() - start;
+ DCHECK_GE(start, 0);
+ DCHECK_GE(available, 0);
+ len = std::min(len, available);
+ memcpy(buf->data() + clean_bytes, &buffer_[start], len);
+ return len + clean_bytes;
+}
+
+void EntryImpl::UserBuffer::Reset() {
+ if (!grow_allowed_) {
+ if (backend_)
+ backend_->BufferDeleted(capacity() - kMaxBlockSize);
+ grow_allowed_ = true;
+ std::vector<char> tmp;
+ buffer_.swap(tmp);
+ buffer_.reserve(kMaxBlockSize);
+ }
+ offset_ = 0;
+ buffer_.clear();
+}
+
+bool EntryImpl::UserBuffer::GrowBuffer(int required, int limit) {
+ DCHECK_GE(required, 0);
+ int current_size = capacity();
+ if (required <= current_size)
+ return true;
+
+ if (required > limit)
+ return false;
+
+ if (!backend_)
+ return false;
+
+ int to_add = std::max(required - current_size, kMaxBlockSize * 4);
+ to_add = std::max(current_size, to_add);
+ required = std::min(current_size + to_add, limit);
+
+ grow_allowed_ = backend_->IsAllocAllowed(current_size, required);
+ if (!grow_allowed_)
+ return false;
+
+ buffer_.reserve(required);
+ return true;
+}
+
+// ------------------------------------------------------------------------
+
+EntryImpl::EntryImpl(BackendImpl* backend, Addr address, bool read_only)
+ : entry_(NULL, Addr(0)), node_(NULL, Addr(0)), read_only_(read_only) {
entry_.LazyInit(backend->File(address), address);
doomed_ = false;
backend_ = backend;
@@ -98,6 +291,9 @@ EntryImpl::EntryImpl(BackendImpl* backend, Addr address)
// data related to a previous cache entry because the range was not fully
// written before).
EntryImpl::~EntryImpl() {
+ Log("~EntryImpl in");
+ backend_->OnEntryDestroyBegin(entry_.address());
+
// Save the sparse info to disk before deleting this entry.
sparse_.reset();
@@ -107,9 +303,10 @@ EntryImpl::~EntryImpl() {
bool ret = true;
for (int index = 0; index < kNumStreams; index++) {
if (user_buffers_[index].get()) {
- if (!(ret = Flush(index, entry_.Data()->data_size[index], false)))
+ if (!(ret = Flush(index, 0)))
LOG(ERROR) << "Failed to save user data";
- } else if (unreported_size_[index]) {
+ }
+ if (unreported_size_[index]) {
backend_->ModifyStorageSize(
entry_.Data()->data_size[index] - unreported_size_[index],
entry_.Data()->data_size[index]);
@@ -127,7 +324,8 @@ EntryImpl::~EntryImpl() {
}
}
- backend_->CacheEntryDestroyed(entry_.address());
+ Trace("~EntryImpl out 0x%p", reinterpret_cast<void*>(this));
+ backend_->OnEntryDestroyEnd();
}
void EntryImpl::Doom() {
@@ -188,7 +386,7 @@ int EntryImpl::ReadData(int index, int offset, net::IOBuffer* buf, int buf_len,
if (!callback)
return ReadDataImpl(index, offset, buf, buf_len, callback);
- DCHECK(node_.Data()->dirty);
+ DCHECK(node_.Data()->dirty || read_only_);
if (index < 0 || index >= kNumStreams)
return net::ERR_INVALID_ARGUMENT;
@@ -209,7 +407,7 @@ int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
if (!callback)
return WriteDataImpl(index, offset, buf, buf_len, callback, truncate);
- DCHECK(node_.Data()->dirty);
+ DCHECK(node_.Data()->dirty || read_only_);
if (index < 0 || index >= kNumStreams)
return net::ERR_INVALID_ARGUMENT;
@@ -281,7 +479,7 @@ void EntryImpl::DoomImpl() {
int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf,
int buf_len, CompletionCallback* callback) {
- DCHECK(node_.Data()->dirty);
+ DCHECK(node_.Data()->dirty || read_only_);
if (index < 0 || index >= kNumStreams)
return net::ERR_INVALID_ARGUMENT;
@@ -302,10 +500,12 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf,
backend_->OnEvent(Stats::READ_DATA);
backend_->OnRead(buf_len);
- if (user_buffers_[index].get()) {
+ // We need the current size in disk.
+ int eof = entry_size - unreported_size_[index];
+ if (user_buffers_[index].get() &&
+ user_buffers_[index]->PreRead(eof, offset, &buf_len)) {
// Complete the operation locally.
- DCHECK(kMaxBlockSize >= offset + buf_len);
- memcpy(buf->data() , user_buffers_[index].get() + offset, buf_len);
+ buf_len = user_buffers_[index]->Read(offset, buf, buf_len);
ReportIOTime(kRead, start);
return buf_len;
}
@@ -320,9 +520,11 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf,
return net::ERR_FAILED;
size_t file_offset = offset;
- if (address.is_block_file())
+ if (address.is_block_file()) {
+ DCHECK_LE(offset + buf_len, kMaxBlockSize);
file_offset += address.start_block() * address.BlockSize() +
kBlockHeaderSize;
+ }
SyncCallback* io_callback = NULL;
if (callback)
@@ -345,7 +547,7 @@ int EntryImpl::ReadDataImpl(int index, int offset, net::IOBuffer* buf,
int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
int buf_len, CompletionCallback* callback,
bool truncate) {
- DCHECK(node_.Data()->dirty);
+ DCHECK(node_.Data()->dirty || read_only_);
if (index < 0 || index >= kNumStreams)
return net::ERR_INVALID_ARGUMENT;
@@ -368,28 +570,15 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
// Read the size at this point (it may change inside prepare).
int entry_size = entry_.Data()->data_size[index];
+ bool extending = entry_size < offset + buf_len;
+ truncate = truncate && entry_size > offset + buf_len;
+ Trace("To PrepareTarget 0x%x", entry_.address().value());
if (!PrepareTarget(index, offset, buf_len, truncate))
return net::ERR_FAILED;
- if (entry_size < offset + buf_len) {
- unreported_size_[index] += offset + buf_len - entry_size;
- entry_.Data()->data_size[index] = offset + buf_len;
- entry_.set_modified();
- if (!buf_len)
- truncate = true; // Force file extension.
- } else if (truncate) {
- // If the size was modified inside PrepareTarget, we should not do
- // anything here.
- if ((entry_size > offset + buf_len) &&
- (entry_size == entry_.Data()->data_size[index])) {
- unreported_size_[index] += offset + buf_len - entry_size;
- entry_.Data()->data_size[index] = offset + buf_len;
- entry_.set_modified();
- } else {
- // Nothing to truncate.
- truncate = false;
- }
- }
+ Trace("From PrepareTarget 0x%x", entry_.address().value());
+ if (extending || truncate)
+ UpdateSize(index, entry_size, offset + buf_len);
UpdateRank(true);
@@ -398,25 +587,27 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
if (user_buffers_[index].get()) {
// Complete the operation locally.
- if (!buf_len)
- return 0;
-
- DCHECK(kMaxBlockSize >= offset + buf_len);
- memcpy(user_buffers_[index].get() + offset, buf->data(), buf_len);
+ user_buffers_[index]->Write(offset, buf, buf_len);
ReportIOTime(kWrite, start);
return buf_len;
}
Addr address(entry_.Data()->data_addr[index]);
+ if (truncate && offset + buf_len == 0) {
+ DCHECK(!address.is_initialized());
+ return 0;
+ }
+
File* file = GetBackingFile(address, index);
if (!file)
return net::ERR_FAILED;
size_t file_offset = offset;
if (address.is_block_file()) {
+ DCHECK_LE(offset + buf_len, kMaxBlockSize);
file_offset += address.start_block() * address.BlockSize() +
kBlockHeaderSize;
- } else if (truncate) {
+ } else if (truncate || (extending && !buf_len)) {
if (!file->SetLength(offset + buf_len))
return net::ERR_FAILED;
}
@@ -445,7 +636,7 @@ int EntryImpl::WriteDataImpl(int index, int offset, net::IOBuffer* buf,
int EntryImpl::ReadSparseDataImpl(int64 offset, net::IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
- DCHECK(node_.Data()->dirty);
+ DCHECK(node_.Data()->dirty || read_only_);
int result = InitSparseData();
if (net::OK != result)
return result;
@@ -459,7 +650,7 @@ int EntryImpl::ReadSparseDataImpl(int64 offset, net::IOBuffer* buf, int buf_len,
int EntryImpl::WriteSparseDataImpl(int64 offset, net::IOBuffer* buf,
int buf_len, CompletionCallback* callback) {
- DCHECK(node_.Data()->dirty);
+ DCHECK(node_.Data()->dirty || read_only_);
int result = InitSparseData();
if (net::OK != result)
return result;
@@ -577,18 +768,17 @@ void EntryImpl::DeleteEntryData(bool everything) {
for (int index = 0; index < kNumStreams; index++) {
Addr address(entry_.Data()->data_addr[index]);
if (address.is_initialized()) {
- DeleteData(address, index);
backend_->ModifyStorageSize(entry_.Data()->data_size[index] -
unreported_size_[index], 0);
entry_.Data()->data_addr[index] = 0;
entry_.Data()->data_size[index] = 0;
+ entry_.Store();
+ DeleteData(address, index);
}
}
- if (!everything) {
- entry_.Store();
+ if (!everything)
return;
- }
// Remove all traces of this entry.
backend_->RemoveEntry(this);
@@ -626,6 +816,9 @@ bool EntryImpl::LoadNodeAddress() {
bool EntryImpl::Update() {
DCHECK(node_.HasData());
+ if (read_only_)
+ return true;
+
RankingsNode* rankings = node_.Data();
if (!rankings->dirty) {
rankings->dirty = backend_->GetCurrentEntryId();
@@ -742,18 +935,24 @@ bool EntryImpl::CreateBlock(int size, Addr* address) {
return true;
}
+// Note that this method may end up modifying a block file so upon return the
+// involved block will be free, and could be reused for something else. If there
+// is a crash after that point (and maybe before returning to the caller), the
+// entry will be left dirty... and at some point it will be discarded; it is
+// important that the entry doesn't keep a reference to this address, or we'll
+// end up deleting the contents of |address| once again.
void EntryImpl::DeleteData(Addr address, int index) {
if (!address.is_initialized())
return;
if (address.is_separate_file()) {
- if (files_[index])
- files_[index] = NULL; // Releases the object.
-
- int failure = DeleteCacheFile(backend_->GetFileName(address)) ? 0 : 1;
+ int failure = !DeleteCacheFile(backend_->GetFileName(address));
CACHE_UMA(COUNTS, "DeleteFailed", 0, failure);
- if (failure)
+ if (failure) {
LOG(ERROR) << "Failed to delete " <<
backend_->GetFileName(address).value() << " from the cache.";
+ }
+ if (files_[index])
+ files_[index] = NULL; // Releases the object.
} else {
backend_->DeleteBlock(address, true);
}
@@ -762,7 +961,7 @@ void EntryImpl::DeleteData(Addr address, int index) {
void EntryImpl::UpdateRank(bool modified) {
if (!doomed_) {
// Everything is handled by the backend.
- backend_->UpdateRank(this, true);
+ backend_->UpdateRank(this, modified);
return;
}
@@ -793,173 +992,224 @@ File* EntryImpl::GetExternalFile(Addr address, int index) {
return files_[index].get();
}
+// We keep a memory buffer for everything that ends up stored on a block file
+// (because we don't know yet the final data size), and for some of the data
+// that end up on external files. This function will initialize that memory
+// buffer and / or the files needed to store the data.
+//
+// In general, a buffer may overlap data already stored on disk, and in that
+// case, the contents of the buffer are the most accurate. It may also extend
+// the file, but we don't want to read from disk just to keep the buffer up to
+// date. This means that as soon as there is a chance to get confused about what
+// is the most recent version of some part of a file, we'll flush the buffer and
+// reuse it for the new data. Keep in mind that the normal use pattern is quite
+// simple (write sequentially from the beginning), so we optimize for handling
+// that case.
bool EntryImpl::PrepareTarget(int index, int offset, int buf_len,
bool truncate) {
- Addr address(entry_.Data()->data_addr[index]);
-
- if (address.is_initialized() || user_buffers_[index].get())
- return GrowUserBuffer(index, offset, buf_len, truncate);
+ if (truncate)
+ return HandleTruncation(index, offset, buf_len);
- if (offset + buf_len > kMaxBlockSize)
- return CreateDataBlock(index, offset + buf_len);
+ Addr address(entry_.Data()->data_addr[index]);
+ if (address.is_initialized()) {
+ if (address.is_block_file() && !MoveToLocalBuffer(index))
+ return false;
- user_buffers_[index].reset(new char[kMaxBlockSize]);
+ if (!user_buffers_[index].get() && offset < kMaxBlockSize) {
+ // We are about to create a buffer for the first 16KB, make sure that we
+ // preserve existing data.
+ if (!CopyToLocalBuffer(index))
+ return false;
+ }
+ }
- // Overwrite the parts of the buffer that are not going to be written
- // by the current operation (and yes, let's assume that nothing is going
- // to fail, and we'll actually write over the part that we are not cleaning
- // here). The point is to avoid writing random stuff to disk later on.
- ClearInvalidData(user_buffers_[index].get(), offset, buf_len);
+ if (!user_buffers_[index].get())
+ user_buffers_[index].reset(new UserBuffer(backend_));
- return true;
+ return PrepareBuffer(index, offset, buf_len);
}
// We get to this function with some data already stored. If there is a
// truncation that results on data stored internally, we'll explicitly
// handle the case here.
-bool EntryImpl::GrowUserBuffer(int index, int offset, int buf_len,
- bool truncate) {
+bool EntryImpl::HandleTruncation(int index, int offset, int buf_len) {
Addr address(entry_.Data()->data_addr[index]);
- if (offset + buf_len > kMaxBlockSize) {
- // The data has to be stored externally.
- if (address.is_initialized()) {
- if (address.is_separate_file())
- return true;
- if (!MoveToLocalBuffer(index))
- return false;
- }
- return Flush(index, offset + buf_len, true);
- }
+ int current_size = entry_.Data()->data_size[index];
+ int new_size = offset + buf_len;
+
+ if (!new_size) {
+ // This is by far the most common scenario.
+ backend_->ModifyStorageSize(current_size - unreported_size_[index], 0);
+ entry_.Data()->data_addr[index] = 0;
+ entry_.Data()->data_size[index] = 0;
+ unreported_size_[index] = 0;
+ entry_.Store();
+ DeleteData(address, index);
- if (!address.is_initialized()) {
- DCHECK(user_buffers_[index].get());
- if (truncate)
- ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len);
+ user_buffers_[index].reset();
return true;
}
- if (address.is_separate_file()) {
- if (!truncate)
- return true;
- return ImportSeparateFile(index, offset, buf_len);
- }
- // At this point we are dealing with data stored on disk, inside a block file.
- if (offset + buf_len <= address.BlockSize() * address.num_blocks())
- return true;
+ // We never postpone truncating a file, if there is one, but we may postpone
+ // telling the backend about the size reduction.
+ if (user_buffers_[index].get()) {
+ DCHECK_GE(current_size, user_buffers_[index]->Start());
+ if (!address.is_initialized()) {
+ // There is no overlap between the buffer and disk.
+ if (new_size > user_buffers_[index]->Start()) {
+ // Just truncate our buffer.
+ DCHECK_LT(new_size, user_buffers_[index]->End());
+ user_buffers_[index]->Truncate(new_size);
+ return true;
+ }
- // ... and the allocated block has to change.
- if (!MoveToLocalBuffer(index))
- return false;
+ // Just discard our buffer.
+ user_buffers_[index]->Reset();
+ return PrepareBuffer(index, offset, buf_len);
+ }
- int clear_start = entry_.Data()->data_size[index];
- if (truncate)
- clear_start = std::min(clear_start, offset + buf_len);
- else if (offset < clear_start)
- clear_start = std::max(offset + buf_len, clear_start);
+ // There is some overlap or we need to extend the file before the
+ // truncation.
+ if (offset > user_buffers_[index]->Start())
+ user_buffers_[index]->Truncate(new_size);
+ UpdateSize(index, current_size, new_size);
+ if (!Flush(index, 0))
+ return false;
+ user_buffers_[index].reset();
+ }
- // Clear the end of the buffer.
- ClearInvalidData(user_buffers_[index].get(), 0, clear_start);
- return true;
+ // We have data somewhere, and it is not in a buffer.
+ DCHECK(!user_buffers_[index].get());
+ DCHECK(address.is_initialized());
+
+ if (new_size > kMaxBlockSize)
+ return true; // Let the operation go directly to disk.
+
+ return ImportSeparateFile(index, offset + buf_len);
}
-bool EntryImpl::MoveToLocalBuffer(int index) {
+bool EntryImpl::CopyToLocalBuffer(int index) {
Addr address(entry_.Data()->data_addr[index]);
DCHECK(!user_buffers_[index].get());
DCHECK(address.is_initialized());
- scoped_array<char> buffer(new char[kMaxBlockSize]);
+
+ int len = std::min(entry_.Data()->data_size[index], kMaxBlockSize);
+ user_buffers_[index].reset(new UserBuffer(backend_));
+ user_buffers_[index]->Write(len, NULL, 0);
File* file = GetBackingFile(address, index);
- size_t len = entry_.Data()->data_size[index];
- size_t offset = 0;
+ int offset = 0;
if (address.is_block_file())
offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
- if (!file || !file->Read(buffer.get(), len, offset, NULL, NULL))
+ if (!file ||
+ !file->Read(user_buffers_[index]->Data(), len, offset, NULL, NULL)) {
+ user_buffers_[index].reset();
+ return false;
+ }
+ return true;
+}
+
+bool EntryImpl::MoveToLocalBuffer(int index) {
+ if (!CopyToLocalBuffer(index))
return false;
- DeleteData(address, index);
+ Addr address(entry_.Data()->data_addr[index]);
entry_.Data()->data_addr[index] = 0;
entry_.Store();
+ DeleteData(address, index);
// If we lose this entry we'll see it as zero sized.
- backend_->ModifyStorageSize(static_cast<int>(len) - unreported_size_[index],
- 0);
- unreported_size_[index] = static_cast<int>(len);
-
- user_buffers_[index].swap(buffer);
+ int len = entry_.Data()->data_size[index];
+ backend_->ModifyStorageSize(len - unreported_size_[index], 0);
+ unreported_size_[index] = len;
return true;
}
-bool EntryImpl::ImportSeparateFile(int index, int offset, int buf_len) {
- if (entry_.Data()->data_size[index] > offset + buf_len) {
- unreported_size_[index] += offset + buf_len -
- entry_.Data()->data_size[index];
- entry_.Data()->data_size[index] = offset + buf_len;
+bool EntryImpl::ImportSeparateFile(int index, int new_size) {
+ if (entry_.Data()->data_size[index] > new_size)
+ UpdateSize(index, entry_.Data()->data_size[index], new_size);
+
+ return MoveToLocalBuffer(index);
+}
+
+bool EntryImpl::PrepareBuffer(int index, int offset, int buf_len) {
+ DCHECK(user_buffers_[index].get());
+ if (offset > user_buffers_[index]->End()) {
+ // We are about to extend the buffer (with zeros), so make sure that we are
+ // not overwriting anything.
+ Addr address(entry_.Data()->data_addr[index]);
+ if (address.is_initialized() && address.is_separate_file()) {
+ int eof = entry_.Data()->data_size[index];
+ if (eof > user_buffers_[index]->Start() && !Flush(index, 0))
+ return false;
+ }
}
- if (!MoveToLocalBuffer(index))
- return false;
+ if (!user_buffers_[index]->PreWrite(offset, buf_len)) {
+ if (!Flush(index, offset + buf_len))
+ return false;
- // Clear the end of the buffer.
- ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len);
+ // Lets try again.
+ if (!user_buffers_[index]->PreWrite(offset, buf_len)) {
+ // We cannot complete the operation with a buffer.
+ DCHECK(!user_buffers_[index]->Size());
+ DCHECK(!user_buffers_[index]->Start());
+ user_buffers_[index].reset();
+ }
+ }
return true;
}
-// The common scenario is that this is called from the destructor of the entry,
-// to write to disk what we have buffered. We don't want to hold the destructor
-// until the actual IO finishes, so we'll send an asynchronous write that will
-// free up the memory containing the data. To be consistent, this method always
-// returns with the buffer freed up (on success).
-bool EntryImpl::Flush(int index, int size, bool async) {
+bool EntryImpl::Flush(int index, int min_len) {
Addr address(entry_.Data()->data_addr[index]);
DCHECK(user_buffers_[index].get());
- DCHECK(!address.is_initialized());
-
- if (!size)
- return true;
+ DCHECK(!address.is_initialized() || address.is_separate_file());
- if (!CreateDataBlock(index, size))
+ int size = std::max(entry_.Data()->data_size[index], min_len);
+ if (!address.is_initialized() && !CreateDataBlock(index, size))
return false;
+ if (!entry_.Data()->data_size[index]) {
+ DCHECK(!user_buffers_[index]->Size());
+ return true;
+ }
+
address.set_value(entry_.Data()->data_addr[index]);
- File* file = GetBackingFile(address, index);
- size_t len = entry_.Data()->data_size[index];
- size_t offset = 0;
- if (address.is_block_file())
- offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
+ int len = user_buffers_[index]->Size();
+ int offset = user_buffers_[index]->Start();
+ if (!len && !offset)
+ return true;
- // We just told the backend to store len bytes for real.
- DCHECK(len == static_cast<size_t>(unreported_size_[index]));
- backend_->ModifyStorageSize(0, static_cast<int>(len));
- unreported_size_[index] = 0;
+ if (address.is_block_file()) {
+ DCHECK_EQ(len, entry_.Data()->data_size[index]);
+ DCHECK(!offset);
+ offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
+ }
+ File* file = GetBackingFile(address, index);
if (!file)
return false;
- // TODO(rvargas): figure out if it's worth to re-enable posting operations.
- // Right now it is only used from GrowUserBuffer, not the destructor, and
- // it is not accounted for from the point of view of the total number of
- // pending operations of the cache. It is also racing with the actual write
- // on the GrowUserBuffer path because there is no code to exclude the range
- // that is going to be written.
- async = false;
- if (async) {
- if (!file->PostWrite(user_buffers_[index].get(), len, offset))
- return false;
- // The buffer is deleted from the PostWrite operation.
- ignore_result(user_buffers_[index].release());
- } else {
- if (!file->Write(user_buffers_[index].get(), len, offset, NULL, NULL))
- return false;
- user_buffers_[index].reset(NULL);
- }
+ if (!file->Write(user_buffers_[index]->Data(), len, offset, NULL, NULL))
+ return false;
+ user_buffers_[index]->Reset();
return true;
}
+void EntryImpl::UpdateSize(int index, int old_size, int new_size) {
+ if (entry_.Data()->data_size[index] == new_size)
+ return;
+
+ unreported_size_[index] += new_size - old_size;
+ entry_.Data()->data_size[index] = new_size;
+ entry_.set_modified();
+}
+
int EntryImpl::InitSparseData() {
if (sparse_.get())
return net::OK;
@@ -983,13 +1233,16 @@ uint32 EntryImpl::GetEntryFlags() {
}
void EntryImpl::GetData(int index, char** buffer, Addr* address) {
- if (user_buffers_[index].get()) {
+ if (user_buffers_[index].get() && user_buffers_[index]->Size() &&
+ !user_buffers_[index]->Start()) {
// The data is already in memory, just copy it and we're done.
int data_len = entry_.Data()->data_size[index];
- DCHECK(data_len <= kMaxBlockSize);
- *buffer = new char[data_len];
- memcpy(*buffer, user_buffers_[index].get(), data_len);
- return;
+ if (data_len <= user_buffers_[index]->Size()) {
+ DCHECK(!user_buffers_[index]->Start());
+ *buffer = new char[data_len];
+ memcpy(*buffer, user_buffers_[index]->Data(), data_len);
+ return;
+ }
}
// Bad news: we'd have to read the info from disk so instead we'll just tell
diff --git a/net/disk_cache/entry_impl.h b/net/disk_cache/entry_impl.h
index 9d37fff..e27f23a 100644
--- a/net/disk_cache/entry_impl.h
+++ b/net/disk_cache/entry_impl.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_ENTRY_IMPL_H_
#define NET_DISK_CACHE_ENTRY_IMPL_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "net/disk_cache/disk_cache.h"
@@ -29,7 +30,7 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
kAsyncIO
};
- EntryImpl(BackendImpl* backend, Addr address);
+ EntryImpl(BackendImpl* backend, Addr address, bool read_only);
// Entry interface.
virtual void Doom();
@@ -132,6 +133,7 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
enum {
kNumStreams = 3
};
+ class UserBuffer;
~EntryImpl();
@@ -142,6 +144,9 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
bool CreateBlock(int size, Addr* address);
// Deletes the data pointed by address, maybe backed by files_[index].
+ // Note that most likely the caller should delete (and store) the reference to
+ // |address| *before* calling this method because we don't want to have an
+ // entry using an address that is already free.
void DeleteData(Addr address, int index);
// Updates ranking information.
@@ -157,17 +162,29 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
// given offset.
bool PrepareTarget(int index, int offset, int buf_len, bool truncate);
- // Grows the size of the storage used to store user data, if needed.
- bool GrowUserBuffer(int index, int offset, int buf_len, bool truncate);
+ // Adjusts the internal buffer and file handle for a write that truncates this
+ // stream.
+ bool HandleTruncation(int index, int offset, int buf_len);
+
+ // Copies data from disk to the internal buffer.
+ bool CopyToLocalBuffer(int index);
// Reads from a block data file to this object's memory buffer.
bool MoveToLocalBuffer(int index);
// Loads the external file to this object's memory buffer.
- bool ImportSeparateFile(int index, int offset, int buf_len);
+ bool ImportSeparateFile(int index, int new_size);
+
+ // Makes sure that the internal buffer can handle the a write of |buf_len|
+ // bytes to |offset|.
+ bool PrepareBuffer(int index, int offset, int buf_len);
+
+ // Flushes the in-memory data to the backing storage. The data destination
+ // is determined based on the current data length and |min_len|.
+ bool Flush(int index, int min_len);
- // Flush the in-memory data to the backing storage.
- bool Flush(int index, int size, bool async);
+ // Updates the size of a given data stream.
+ void UpdateSize(int index, int old_size, int new_size);
// Initializes the sparse control object. Returns a net error code.
int InitSparseData();
@@ -194,12 +211,13 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
CacheEntryBlock entry_; // Key related information for this entry.
CacheRankingsBlock node_; // Rankings related information for this entry.
BackendImpl* backend_; // Back pointer to the cache.
- scoped_array<char> user_buffers_[kNumStreams]; // Store user data.
+ scoped_ptr<UserBuffer> user_buffers_[kNumStreams]; // Stores user data.
// Files to store external user data and key.
scoped_refptr<File> files_[kNumStreams + 1];
mutable std::string key_; // Copy of the key.
int unreported_size_[kNumStreams]; // Bytes not reported yet to the backend.
bool doomed_; // True if this entry was removed from the cache.
+ bool read_only_; // True if not yet writing.
scoped_ptr<SparseControl> sparse_; // Support for sparse entries.
DISALLOW_COPY_AND_ASSIGN(EntryImpl);
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 067f260..c4dc705 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -9,6 +9,7 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
+#include "net/disk_cache/backend_impl.h"
#include "net/disk_cache/disk_cache_test_base.h"
#include "net/disk_cache/disk_cache_test_util.h"
#include "net/disk_cache/entry_impl.h"
@@ -22,6 +23,10 @@ extern volatile bool g_cache_tests_error;
// Tests that can run with different types of caches.
class DiskCacheEntryTest : public DiskCacheTestWithCache {
+ public:
+ void InternalSyncIOBackground(disk_cache::Entry* entry);
+ void ExternalSyncIOBackground(disk_cache::Entry* entry);
+
protected:
void InternalSyncIO();
void InternalAsyncIO();
@@ -29,34 +34,55 @@ class DiskCacheEntryTest : public DiskCacheTestWithCache {
void ExternalAsyncIO();
void StreamAccess();
void GetKey();
+ void GetTimes();
void GrowData();
void TruncateData();
void ZeroLengthIO();
+ void Buffering();
+ void SizeChanges();
void ReuseEntry(int size);
void InvalidData();
void DoomNormalEntry();
void DoomedEntry();
- void BasicSparseIO(bool async);
- void HugeSparseIO(bool async);
+ void BasicSparseIO();
+ void HugeSparseIO();
void GetAvailableRange();
void CouldBeSparse();
void DoomSparseEntry();
void PartialSparseEntry();
};
-void DiskCacheEntryTest::InternalSyncIO() {
- disk_cache::Entry *entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
- ASSERT_TRUE(NULL != entry1);
+// Simple task to run part of a test from the cache thread.
+class SyncIOTask : public Task {
+ public:
+ SyncIOTask(DiskCacheEntryTest* test, disk_cache::Entry* entry)
+ : test_(test), entry_(entry) {}
+
+ protected:
+ DiskCacheEntryTest* test_;
+ disk_cache::Entry* entry_;
+};
+class InternalSyncIOTask : public SyncIOTask {
+ public:
+ InternalSyncIOTask(DiskCacheEntryTest* test, disk_cache::Entry* entry)
+ : SyncIOTask(test, entry) {}
+
+ virtual void Run() {
+ test_->InternalSyncIOBackground(entry_);
+ }
+};
+
+// This part of the test runs on the background thread.
+void DiskCacheEntryTest::InternalSyncIOBackground(disk_cache::Entry* entry) {
const int kSize1 = 10;
scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1);
CacheTestFillBuffer(buffer1->data(), kSize1, false);
- EXPECT_EQ(0, entry1->ReadData(0, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(0, entry->ReadData(0, 0, buffer1, kSize1, NULL));
base::strlcpy(buffer1->data(), "the data", kSize1);
- EXPECT_EQ(10, entry1->WriteData(0, 0, buffer1, kSize1, NULL, false));
+ EXPECT_EQ(10, entry->WriteData(0, 0, buffer1, kSize1, NULL, false));
memset(buffer1->data(), 0, kSize1);
- EXPECT_EQ(10, entry1->ReadData(0, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(10, entry->ReadData(0, 0, buffer1, kSize1, NULL));
EXPECT_STREQ("the data", buffer1->data());
const int kSize2 = 5000;
@@ -66,22 +92,39 @@ void DiskCacheEntryTest::InternalSyncIO() {
memset(buffer3->data(), 0, kSize3);
CacheTestFillBuffer(buffer2->data(), kSize2, false);
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- EXPECT_EQ(5000, entry1->WriteData(1, 1500, buffer2, kSize2, NULL, false));
+ EXPECT_EQ(5000, entry->WriteData(1, 1500, buffer2, kSize2, NULL, false));
memset(buffer2->data(), 0, kSize2);
- EXPECT_EQ(4989, entry1->ReadData(1, 1511, buffer2, kSize2, NULL));
+ EXPECT_EQ(4989, entry->ReadData(1, 1511, buffer2, kSize2, NULL));
EXPECT_STREQ("big data goes here", buffer2->data());
- EXPECT_EQ(5000, entry1->ReadData(1, 0, buffer2, kSize2, NULL));
+ EXPECT_EQ(5000, entry->ReadData(1, 0, buffer2, kSize2, NULL));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer3->data(), 1500));
- EXPECT_EQ(1500, entry1->ReadData(1, 5000, buffer2, kSize2, NULL));
+ EXPECT_EQ(1500, entry->ReadData(1, 5000, buffer2, kSize2, NULL));
- EXPECT_EQ(0, entry1->ReadData(1, 6500, buffer2, kSize2, NULL));
- EXPECT_EQ(6500, entry1->ReadData(1, 0, buffer3, kSize3, NULL));
- EXPECT_EQ(8192, entry1->WriteData(1, 0, buffer3, 8192, NULL, false));
- EXPECT_EQ(8192, entry1->ReadData(1, 0, buffer3, kSize3, NULL));
- EXPECT_EQ(8192, entry1->GetDataSize(1));
+ EXPECT_EQ(0, entry->ReadData(1, 6500, buffer2, kSize2, NULL));
+ EXPECT_EQ(6500, entry->ReadData(1, 0, buffer3, kSize3, NULL));
+ EXPECT_EQ(8192, entry->WriteData(1, 0, buffer3, 8192, NULL, false));
+ EXPECT_EQ(8192, entry->ReadData(1, 0, buffer3, kSize3, NULL));
+ EXPECT_EQ(8192, entry->GetDataSize(1));
- entry1->Doom();
- entry1->Close();
+ // We need to delete the memory buffer on this thread.
+ EXPECT_EQ(0, entry->WriteData(0, 0, NULL, 0, NULL, true));
+ EXPECT_EQ(0, entry->WriteData(1, 0, NULL, 0, NULL, true));
+}
+
+// We need to support synchronous IO even though it is not a supported operation
+// from the point of view of the disk cache's public interface, because we use
+// it internally, not just by a few tests, but as part of the implementation
+// (see sparse_control.cc, for example).
+void DiskCacheEntryTest::InternalSyncIO() {
+ disk_cache::Entry* entry = NULL;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_TRUE(NULL != entry);
+
+ // The bulk of the test runs from within the task, on the cache thread.
+ RunTaskForTest(new InternalSyncIOTask(this, entry));
+
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -99,19 +142,19 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyInternalSyncIO) {
}
void DiskCacheEntryTest::InternalAsyncIO() {
- disk_cache::Entry *entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
- ASSERT_TRUE(NULL != entry1);
+ disk_cache::Entry* entry = NULL;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_TRUE(NULL != entry);
// Avoid using internal buffers for the test. We have to write something to
// the entry and close it so that we flush the internal buffer to disk. After
// that, IO operations will be really hitting the disk. We don't care about
// the content, so just extending the entry is enough (all extensions zero-
// fill any holes).
- EXPECT_EQ(0, entry1->WriteData(0, 15 * 1024, NULL, 0, NULL, false));
- EXPECT_EQ(0, entry1->WriteData(1, 15 * 1024, NULL, 0, NULL, false));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry1));
+ EXPECT_EQ(0, WriteData(entry, 0, 15 * 1024, NULL, 0, false));
+ EXPECT_EQ(0, WriteData(entry, 1, 15 * 1024, NULL, 0, false));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry("the first key", &entry));
// Let's verify that each IO goes to the right callback object.
CallbackTest callback1(false);
@@ -143,17 +186,17 @@ void DiskCacheEntryTest::InternalAsyncIO() {
CacheTestFillBuffer(buffer2->data(), kSize2, false);
CacheTestFillBuffer(buffer3->data(), kSize3, false);
- EXPECT_EQ(0, entry1->ReadData(0, 15 * 1024, buffer1, kSize1, &callback1));
+ EXPECT_EQ(0, entry->ReadData(0, 15 * 1024, buffer1, kSize1, &callback1));
base::strlcpy(buffer1->data(), "the data", kSize1);
int expected = 0;
- int ret = entry1->WriteData(0, 0, buffer1, kSize1, &callback2, false);
+ int ret = entry->WriteData(0, 0, buffer1, kSize1, &callback2, false);
EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer2->data(), 0, kSize2);
- ret = entry1->ReadData(0, 0, buffer2, kSize1, &callback3);
+ ret = entry->ReadData(0, 0, buffer2, kSize1, &callback3);
EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -162,21 +205,21 @@ void DiskCacheEntryTest::InternalAsyncIO() {
EXPECT_STREQ("the data", buffer2->data());
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- ret = entry1->WriteData(1, 1500, buffer2, kSize2, &callback4, true);
+ ret = entry->WriteData(1, 1500, buffer2, kSize2, &callback4, true);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer3->data(), 0, kSize3);
- ret = entry1->ReadData(1, 1511, buffer3, kSize2, &callback5);
+ ret = entry->ReadData(1, 1511, buffer3, kSize2, &callback5);
EXPECT_TRUE(4989 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_STREQ("big data goes here", buffer3->data());
- ret = entry1->ReadData(1, 0, buffer2, kSize2, &callback6);
+ ret = entry->ReadData(1, 0, buffer2, kSize2, &callback6);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -185,35 +228,35 @@ void DiskCacheEntryTest::InternalAsyncIO() {
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer3->data(), 1500));
- ret = entry1->ReadData(1, 5000, buffer2, kSize2, &callback7);
+ ret = entry->ReadData(1, 5000, buffer2, kSize2, &callback7);
EXPECT_TRUE(1500 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->ReadData(1, 0, buffer3, kSize3, &callback9);
+ ret = entry->ReadData(1, 0, buffer3, kSize3, &callback9);
EXPECT_TRUE(6500 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->WriteData(1, 0, buffer3, 8192, &callback10, true);
+ ret = entry->WriteData(1, 0, buffer3, 8192, &callback10, true);
EXPECT_TRUE(8192 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
- ret = entry1->ReadData(1, 0, buffer3, kSize3, &callback11);
+ ret = entry->ReadData(1, 0, buffer3, kSize3, &callback11);
EXPECT_TRUE(8192 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- EXPECT_EQ(8192, entry1->GetDataSize(1));
+ EXPECT_EQ(8192, entry->GetDataSize(1));
- ret = entry1->ReadData(0, 0, buffer1, kSize1, &callback12);
+ ret = entry->ReadData(0, 0, buffer1, kSize1, &callback12);
EXPECT_TRUE(10 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->ReadData(1, 0, buffer2, kSize2, &callback13);
+ ret = entry->ReadData(1, 0, buffer2, kSize2, &callback13);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -223,8 +266,8 @@ void DiskCacheEntryTest::InternalAsyncIO() {
EXPECT_FALSE(g_cache_tests_error);
EXPECT_EQ(expected, g_cache_tests_received);
- entry1->Doom();
- entry1->Close();
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -241,10 +284,18 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyInternalAsyncIO) {
InternalAsyncIO();
}
-void DiskCacheEntryTest::ExternalSyncIO() {
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
+class ExternalSyncIOTask : public SyncIOTask {
+ public:
+ ExternalSyncIOTask(DiskCacheEntryTest* test, disk_cache::Entry* entry)
+ : SyncIOTask(test, entry) {}
+ virtual void Run() {
+ test_->ExternalSyncIOBackground(entry_);
+ }
+};
+
+// This part of the test runs on the background thread.
+void DiskCacheEntryTest::ExternalSyncIOBackground(disk_cache::Entry* entry) {
const int kSize1 = 17000;
const int kSize2 = 25000;
scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize1);
@@ -252,27 +303,39 @@ void DiskCacheEntryTest::ExternalSyncIO() {
CacheTestFillBuffer(buffer1->data(), kSize1, false);
CacheTestFillBuffer(buffer2->data(), kSize2, false);
base::strlcpy(buffer1->data(), "the data", kSize1);
- EXPECT_EQ(17000, entry1->WriteData(0, 0, buffer1, kSize1, NULL, false));
+ EXPECT_EQ(17000, entry->WriteData(0, 0, buffer1, kSize1, NULL, false));
memset(buffer1->data(), 0, kSize1);
- EXPECT_EQ(17000, entry1->ReadData(0, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(17000, entry->ReadData(0, 0, buffer1, kSize1, NULL));
EXPECT_STREQ("the data", buffer1->data());
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- EXPECT_EQ(25000, entry1->WriteData(1, 10000, buffer2, kSize2, NULL, false));
+ EXPECT_EQ(25000, entry->WriteData(1, 10000, buffer2, kSize2, NULL, false));
memset(buffer2->data(), 0, kSize2);
- EXPECT_EQ(24989, entry1->ReadData(1, 10011, buffer2, kSize2, NULL));
+ EXPECT_EQ(24989, entry->ReadData(1, 10011, buffer2, kSize2, NULL));
EXPECT_STREQ("big data goes here", buffer2->data());
- EXPECT_EQ(25000, entry1->ReadData(1, 0, buffer2, kSize2, NULL));
+ EXPECT_EQ(25000, entry->ReadData(1, 0, buffer2, kSize2, NULL));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer2->data(), 10000));
- EXPECT_EQ(5000, entry1->ReadData(1, 30000, buffer2, kSize2, NULL));
+ EXPECT_EQ(5000, entry->ReadData(1, 30000, buffer2, kSize2, NULL));
- EXPECT_EQ(0, entry1->ReadData(1, 35000, buffer2, kSize2, NULL));
- EXPECT_EQ(17000, entry1->ReadData(1, 0, buffer1, kSize1, NULL));
- EXPECT_EQ(17000, entry1->WriteData(1, 20000, buffer1, kSize1, NULL, false));
- EXPECT_EQ(37000, entry1->GetDataSize(1));
+ EXPECT_EQ(0, entry->ReadData(1, 35000, buffer2, kSize2, NULL));
+ EXPECT_EQ(17000, entry->ReadData(1, 0, buffer1, kSize1, NULL));
+ EXPECT_EQ(17000, entry->WriteData(1, 20000, buffer1, kSize1, NULL, false));
+ EXPECT_EQ(37000, entry->GetDataSize(1));
- entry1->Doom();
- entry1->Close();
+ // We need to delete the memory buffer on this thread.
+ EXPECT_EQ(0, entry->WriteData(0, 0, NULL, 0, NULL, true));
+ EXPECT_EQ(0, entry->WriteData(1, 0, NULL, 0, NULL, true));
+}
+
+void DiskCacheEntryTest::ExternalSyncIO() {
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+
+ // The bulk of the test runs from within the task, on the cache thread.
+ RunTaskForTest(new ExternalSyncIOTask(this, entry));
+
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -283,6 +346,13 @@ TEST_F(DiskCacheEntryTest, ExternalSyncIO) {
ExternalSyncIO();
}
+TEST_F(DiskCacheEntryTest, ExternalSyncIONoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ ExternalSyncIO();
+}
+
TEST_F(DiskCacheEntryTest, MemoryOnlyExternalSyncIO) {
SetMemoryOnlyMode();
InitCache();
@@ -290,8 +360,8 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalSyncIO) {
}
void DiskCacheEntryTest::ExternalAsyncIO() {
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
// Let's verify that each IO goes to the right callback object.
CallbackTest callback1(false);
@@ -320,7 +390,7 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
CacheTestFillBuffer(buffer2->data(), kSize2, false);
CacheTestFillBuffer(buffer3->data(), kSize3, false);
base::strlcpy(buffer1->data(), "the data", kSize1);
- int ret = entry1->WriteData(0, 0, buffer1, kSize1, &callback1, false);
+ int ret = entry->WriteData(0, 0, buffer1, kSize1, &callback1, false);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -328,7 +398,7 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer2->data(), 0, kSize1);
- ret = entry1->ReadData(0, 0, buffer2, kSize1, &callback2);
+ ret = entry->ReadData(0, 0, buffer2, kSize1, &callback2);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -337,7 +407,7 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
EXPECT_STREQ("the data", buffer1->data());
base::strlcpy(buffer2->data(), "The really big data goes here", kSize2);
- ret = entry1->WriteData(1, 10000, buffer2, kSize2, &callback3, false);
+ ret = entry->WriteData(1, 10000, buffer2, kSize2, &callback3, false);
EXPECT_TRUE(25000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
@@ -345,43 +415,43 @@ void DiskCacheEntryTest::ExternalAsyncIO() {
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
memset(buffer3->data(), 0, kSize3);
- ret = entry1->ReadData(1, 10011, buffer3, kSize3, &callback4);
+ ret = entry->ReadData(1, 10011, buffer3, kSize3, &callback4);
EXPECT_TRUE(24989 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_STREQ("big data goes here", buffer3->data());
- ret = entry1->ReadData(1, 0, buffer2, kSize2, &callback5);
+ ret = entry->ReadData(1, 0, buffer2, kSize2, &callback5);
EXPECT_TRUE(25000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
EXPECT_EQ(0, memcmp(buffer2->data(), buffer2->data(), 10000));
- ret = entry1->ReadData(1, 30000, buffer2, kSize2, &callback6);
+ ret = entry->ReadData(1, 30000, buffer2, kSize2, &callback6);
EXPECT_TRUE(5000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- EXPECT_EQ(0, entry1->ReadData(1, 35000, buffer2, kSize2, &callback7));
- ret = entry1->ReadData(1, 0, buffer1, kSize1, &callback8);
+ EXPECT_EQ(0, entry->ReadData(1, 35000, buffer2, kSize2, &callback7));
+ ret = entry->ReadData(1, 0, buffer1, kSize1, &callback8);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
- ret = entry1->WriteData(1, 20000, buffer1, kSize1, &callback9, false);
+ ret = entry->WriteData(1, 20000, buffer1, kSize1, &callback9, false);
EXPECT_TRUE(17000 == ret || net::ERR_IO_PENDING == ret);
if (net::ERR_IO_PENDING == ret)
expected++;
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
- EXPECT_EQ(37000, entry1->GetDataSize(1));
+ EXPECT_EQ(37000, entry->GetDataSize(1));
EXPECT_FALSE(g_cache_tests_error);
EXPECT_EQ(expected, g_cache_tests_received);
- entry1->Doom();
- entry1->Close();
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -392,6 +462,13 @@ TEST_F(DiskCacheEntryTest, ExternalAsyncIO) {
ExternalAsyncIO();
}
+TEST_F(DiskCacheEntryTest, ExternalAsyncIONoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ ExternalAsyncIO();
+}
+
TEST_F(DiskCacheEntryTest, MemoryOnlyExternalAsyncIO) {
SetMemoryOnlyMode();
InitCache();
@@ -399,7 +476,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalAsyncIO) {
}
void DiskCacheEntryTest::StreamAccess() {
- disk_cache::Entry *entry = NULL;
+ disk_cache::Entry* entry = NULL;
ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
ASSERT_TRUE(NULL != entry);
@@ -410,15 +487,14 @@ void DiskCacheEntryTest::StreamAccess() {
const int kNumStreams = 3;
for (int i = 0; i < kNumStreams; i++) {
CacheTestFillBuffer(buffer1->data(), kBufferSize, false);
- EXPECT_EQ(kBufferSize, entry->WriteData(i, 0, buffer1, kBufferSize, NULL,
- false));
+ EXPECT_EQ(kBufferSize, WriteData(entry, i, 0, buffer1, kBufferSize, false));
memset(buffer2->data(), 0, kBufferSize);
- EXPECT_EQ(kBufferSize, entry->ReadData(i, 0, buffer2, kBufferSize, NULL));
+ EXPECT_EQ(kBufferSize, ReadData(entry, i, 0, buffer2, kBufferSize));
EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kBufferSize));
}
EXPECT_EQ(net::ERR_INVALID_ARGUMENT,
- entry->ReadData(kNumStreams, 0, buffer1, kBufferSize, NULL));
+ ReadData(entry, kNumStreams, 0, buffer1, kBufferSize));
entry->Close();
}
@@ -434,11 +510,11 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyStreamAccess) {
}
void DiskCacheEntryTest::GetKey() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_EQ(key1, entry1->GetKey()) << "short key";
- entry1->Close();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_EQ(key, entry->GetKey()) << "short key";
+ entry->Close();
int seed = static_cast<int>(Time::Now().ToInternalValue());
srand(seed);
@@ -447,25 +523,25 @@ void DiskCacheEntryTest::GetKey() {
CacheTestFillBuffer(key_buffer, 3000, true);
key_buffer[1000] = '\0';
- key1 = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_TRUE(key1 == entry1->GetKey()) << "1000 bytes key";
- entry1->Close();
+ key = key_buffer;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_TRUE(key == entry->GetKey()) << "1000 bytes key";
+ entry->Close();
key_buffer[1000] = 'p';
key_buffer[3000] = '\0';
- key1 = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_TRUE(key1 == entry1->GetKey()) << "medium size key";
- entry1->Close();
+ key = key_buffer;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_TRUE(key == entry->GetKey()) << "medium size key";
+ entry->Close();
CacheTestFillBuffer(key_buffer, sizeof(key_buffer), true);
key_buffer[19999] = '\0';
- key1 = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_TRUE(key1 == entry1->GetKey()) << "long key";
- entry1->Close();
+ key = key_buffer;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_TRUE(key == entry->GetKey()) << "long key";
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, GetKey) {
@@ -479,10 +555,63 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyGetKey) {
GetKey();
}
+void DiskCacheEntryTest::GetTimes() {
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+
+ Time t1 = Time::Now();
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_TRUE(entry->GetLastModified() >= t1);
+ EXPECT_TRUE(entry->GetLastModified() == entry->GetLastUsed());
+
+ PlatformThread::Sleep(20);
+ Time t2 = Time::Now();
+ EXPECT_TRUE(t2 > t1);
+ EXPECT_EQ(0, WriteData(entry, 0, 200, NULL, 0, false));
+ if (type_ == net::APP_CACHE) {
+ EXPECT_TRUE(entry->GetLastModified() < t2);
+ } else {
+ EXPECT_TRUE(entry->GetLastModified() >= t2);
+ }
+ EXPECT_TRUE(entry->GetLastModified() == entry->GetLastUsed());
+
+ PlatformThread::Sleep(20);
+ Time t3 = Time::Now();
+ EXPECT_TRUE(t3 > t2);
+ const int kSize = 200;
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+ EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer, kSize));
+ if (type_ == net::APP_CACHE) {
+ EXPECT_TRUE(entry->GetLastUsed() < t2);
+ EXPECT_TRUE(entry->GetLastModified() < t2);
+ } else {
+ EXPECT_TRUE(entry->GetLastUsed() >= t3);
+ EXPECT_TRUE(entry->GetLastModified() < t3);
+ }
+ entry->Close();
+}
+
+TEST_F(DiskCacheEntryTest, GetTimes) {
+ InitCache();
+ GetTimes();
+}
+
+TEST_F(DiskCacheEntryTest, MemoryOnlyGetTimes) {
+ SetMemoryOnlyMode();
+ InitCache();
+ GetTimes();
+}
+
+TEST_F(DiskCacheEntryTest, AppCacheGetTimes) {
+ SetCacheType(net::APP_CACHE);
+ InitCache();
+ GetTimes();
+}
+
void DiskCacheEntryTest::GrowData() {
std::string key1("the first key");
- disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key1, &entry));
const int kSize = 20000;
scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
@@ -491,44 +620,58 @@ void DiskCacheEntryTest::GrowData() {
memset(buffer2->data(), 0, kSize);
base::strlcpy(buffer1->data(), "the data", kSize);
- EXPECT_EQ(10, entry1->WriteData(0, 0, buffer1, 10, NULL, false));
- EXPECT_EQ(10, entry1->ReadData(0, 0, buffer2, 10, NULL));
+ EXPECT_EQ(10, WriteData(entry, 0, 0, buffer1, 10, false));
+ EXPECT_EQ(10, ReadData(entry, 0, 0, buffer2, 10));
EXPECT_STREQ("the data", buffer2->data());
- EXPECT_EQ(10, entry1->GetDataSize(0));
+ EXPECT_EQ(10, entry->GetDataSize(0));
- EXPECT_EQ(2000, entry1->WriteData(0, 0, buffer1, 2000, NULL, false));
- EXPECT_EQ(2000, entry1->GetDataSize(0));
- EXPECT_EQ(2000, entry1->ReadData(0, 0, buffer2, 2000, NULL));
+ EXPECT_EQ(2000, WriteData(entry, 0, 0, buffer1, 2000, false));
+ EXPECT_EQ(2000, entry->GetDataSize(0));
+ EXPECT_EQ(2000, ReadData(entry, 0, 0, buffer2, 2000));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 2000));
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, kSize, NULL, false));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(20000, entry1->ReadData(0, 0, buffer2, kSize, NULL));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer1, kSize, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(20000, ReadData(entry, 0, 0, buffer2, kSize));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), kSize));
- entry1->Close();
+ entry->Close();
memset(buffer2->data(), 0, kSize);
- ASSERT_EQ(net::OK, CreateEntry("Second key", &entry2));
- EXPECT_EQ(10, entry2->WriteData(0, 0, buffer1, 10, NULL, false));
- EXPECT_EQ(10, entry2->GetDataSize(0));
- entry2->Close();
+ std::string key2("Second key");
+ ASSERT_EQ(net::OK, CreateEntry(key2, &entry));
+ EXPECT_EQ(10, WriteData(entry, 0, 0, buffer1, 10, false));
+ EXPECT_EQ(10, entry->GetDataSize(0));
+ entry->Close();
// Go from an internal address to a bigger block size.
- ASSERT_EQ(net::OK, OpenEntry("Second key", &entry2));
- EXPECT_EQ(2000, entry2->WriteData(0, 0, buffer1, 2000, NULL, false));
- EXPECT_EQ(2000, entry2->GetDataSize(0));
- EXPECT_EQ(2000, entry2->ReadData(0, 0, buffer2, 2000, NULL));
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(2000, WriteData(entry, 0, 0, buffer1, 2000, false));
+ EXPECT_EQ(2000, entry->GetDataSize(0));
+ EXPECT_EQ(2000, ReadData(entry, 0, 0, buffer2, 2000));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 2000));
- entry2->Close();
+ entry->Close();
memset(buffer2->data(), 0, kSize);
// Go from an internal address to an external one.
- ASSERT_EQ(net::OK, OpenEntry("Second key", &entry2));
- EXPECT_EQ(20000, entry2->WriteData(0, 0, buffer1, kSize, NULL, false));
- EXPECT_EQ(20000, entry2->GetDataSize(0));
- EXPECT_EQ(20000, entry2->ReadData(0, 0, buffer2, kSize, NULL));
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer1, kSize, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(20000, ReadData(entry, 0, 0, buffer2, kSize));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), kSize));
- entry2->Close();
+ entry->Close();
+
+ // Double check the size from disk.
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+
+ // Now extend the entry without actual data.
+ EXPECT_EQ(0, WriteData(entry, 0, 45500, buffer1, 0, false));
+ entry->Close();
+
+ // And check again from disk.
+ ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ EXPECT_EQ(45500, entry->GetDataSize(0));
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, GrowData) {
@@ -536,6 +679,13 @@ TEST_F(DiskCacheEntryTest, GrowData) {
GrowData();
}
+TEST_F(DiskCacheEntryTest, GrowDataNoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ GrowData();
+}
+
TEST_F(DiskCacheEntryTest, MemoryOnlyGrowData) {
SetMemoryOnlyMode();
InitCache();
@@ -543,9 +693,9 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyGrowData) {
}
void DiskCacheEntryTest::TruncateData() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize1 = 20000;
const int kSize2 = 20000;
@@ -556,50 +706,50 @@ void DiskCacheEntryTest::TruncateData() {
memset(buffer2->data(), 0, kSize2);
// Simple truncation:
- EXPECT_EQ(200, entry1->WriteData(0, 0, buffer1, 200, NULL, false));
- EXPECT_EQ(200, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->WriteData(0, 0, buffer1, 100, NULL, false));
- EXPECT_EQ(200, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->WriteData(0, 0, buffer1, 100, NULL, true));
- EXPECT_EQ(100, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 50, buffer1, 0, NULL, true));
- EXPECT_EQ(50, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 0, buffer1, 0, NULL, true));
- EXPECT_EQ(0, entry1->GetDataSize(0));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key1, &entry1));
+ EXPECT_EQ(200, WriteData(entry, 0, 0, buffer1, 200, false));
+ EXPECT_EQ(200, entry->GetDataSize(0));
+ EXPECT_EQ(100, WriteData(entry, 0, 0, buffer1, 100, false));
+ EXPECT_EQ(200, entry->GetDataSize(0));
+ EXPECT_EQ(100, WriteData(entry, 0, 0, buffer1, 100, true));
+ EXPECT_EQ(100, entry->GetDataSize(0));
+ EXPECT_EQ(0, WriteData(entry, 0, 50, buffer1, 0, true));
+ EXPECT_EQ(50, entry->GetDataSize(0));
+ EXPECT_EQ(0, WriteData(entry, 0, 0, buffer1, 0, true));
+ EXPECT_EQ(0, entry->GetDataSize(0));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// Go to an external file.
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, 20000, NULL, true));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(20000, entry1->ReadData(0, 0, buffer2, 20000, NULL));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer1, 20000, true));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(20000, ReadData(entry, 0, 0, buffer2, 20000));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 20000));
memset(buffer2->data(), 0, kSize2);
// External file truncation
- EXPECT_EQ(18000, entry1->WriteData(0, 0, buffer1, 18000, NULL, false));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(18000, entry1->WriteData(0, 0, buffer1, 18000, NULL, true));
- EXPECT_EQ(18000, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 17500, buffer1, 0, NULL, true));
- EXPECT_EQ(17500, entry1->GetDataSize(0));
+ EXPECT_EQ(18000, WriteData(entry, 0, 0, buffer1, 18000, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(18000, WriteData(entry, 0, 0, buffer1, 18000, true));
+ EXPECT_EQ(18000, entry->GetDataSize(0));
+ EXPECT_EQ(0, WriteData(entry, 0, 17500, buffer1, 0, true));
+ EXPECT_EQ(17500, entry->GetDataSize(0));
// And back to an internal block.
- EXPECT_EQ(600, entry1->WriteData(0, 1000, buffer1, 600, NULL, true));
- EXPECT_EQ(1600, entry1->GetDataSize(0));
- EXPECT_EQ(600, entry1->ReadData(0, 1000, buffer2, 600, NULL));
+ EXPECT_EQ(600, WriteData(entry, 0, 1000, buffer1, 600, true));
+ EXPECT_EQ(1600, entry->GetDataSize(0));
+ EXPECT_EQ(600, ReadData(entry, 0, 1000, buffer2, 600));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 600));
- EXPECT_EQ(1000, entry1->ReadData(0, 0, buffer2, 1000, NULL));
+ EXPECT_EQ(1000, ReadData(entry, 0, 0, buffer2, 1000));
EXPECT_TRUE(!memcmp(buffer1->data(), buffer2->data(), 1000)) <<
"Preserves previous data";
// Go from external file to zero length.
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer1, 20000, NULL, true));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(0, entry1->WriteData(0, 0, buffer1, 0, NULL, true));
- EXPECT_EQ(0, entry1->GetDataSize(0));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer1, 20000, true));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(0, WriteData(entry, 0, 0, buffer1, 0, true));
+ EXPECT_EQ(0, entry->GetDataSize(0));
- entry1->Close();
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, TruncateData) {
@@ -612,6 +762,18 @@ TEST_F(DiskCacheEntryTest, TruncateData) {
helper.WaitUntilCacheIoFinished(1);
}
+TEST_F(DiskCacheEntryTest, TruncateDataNoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ TruncateData();
+
+ // We generate asynchronous IO that is not really tracked until completion
+ // so we just wait here before running the next test.
+ MessageLoopHelper helper;
+ helper.WaitUntilCacheIoFinished(1);
+}
+
TEST_F(DiskCacheEntryTest, MemoryOnlyTruncateData) {
SetMemoryOnlyMode();
InitCache();
@@ -619,19 +781,41 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyTruncateData) {
}
void DiskCacheEntryTest::ZeroLengthIO() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
- EXPECT_EQ(0, entry1->ReadData(0, 0, NULL, 0, NULL));
- EXPECT_EQ(0, entry1->WriteData(0, 0, NULL, 0, NULL, false));
+ EXPECT_EQ(0, ReadData(entry, 0, 0, NULL, 0));
+ EXPECT_EQ(0, WriteData(entry, 0, 0, NULL, 0, false));
// This write should extend the entry.
- EXPECT_EQ(0, entry1->WriteData(0, 1000, NULL, 0, NULL, false));
- EXPECT_EQ(0, entry1->ReadData(0, 500, NULL, 0, NULL));
- EXPECT_EQ(0, entry1->ReadData(0, 2000, NULL, 0, NULL));
- EXPECT_EQ(1000, entry1->GetDataSize(0));
- entry1->Close();
+ EXPECT_EQ(0, WriteData(entry, 0, 1000, NULL, 0, false));
+ EXPECT_EQ(0, ReadData(entry, 0, 500, NULL, 0));
+ EXPECT_EQ(0, ReadData(entry, 0, 2000, NULL, 0));
+ EXPECT_EQ(1000, entry->GetDataSize(0));
+
+ EXPECT_EQ(0, WriteData(entry, 0, 100000, NULL, 0, true));
+ EXPECT_EQ(0, ReadData(entry, 0, 50000, NULL, 0));
+ EXPECT_EQ(100000, entry->GetDataSize(0));
+
+ // Lets verify the actual content.
+ const int kSize = 20;
+ const char zeros[kSize] = {};
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+ EXPECT_EQ(kSize, ReadData(entry, 0, 500, buffer, kSize));
+ EXPECT_TRUE(!memcmp(buffer->data(), zeros, kSize));
+
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+ EXPECT_EQ(kSize, ReadData(entry, 0, 5000, buffer, kSize));
+ EXPECT_TRUE(!memcmp(buffer->data(), zeros, kSize));
+
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+ EXPECT_EQ(kSize, ReadData(entry, 0, 50000, buffer, kSize));
+ EXPECT_TRUE(!memcmp(buffer->data(), zeros, kSize));
+
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, ZeroLengthIO) {
@@ -639,17 +823,190 @@ TEST_F(DiskCacheEntryTest, ZeroLengthIO) {
ZeroLengthIO();
}
+TEST_F(DiskCacheEntryTest, ZeroLengthIONoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ ZeroLengthIO();
+}
+
TEST_F(DiskCacheEntryTest, MemoryOnlyZeroLengthIO) {
SetMemoryOnlyMode();
InitCache();
ZeroLengthIO();
}
+// Tests that we handle the content correctly when buffering.
+void DiskCacheEntryTest::Buffering() {
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+ const int kSize = 200;
+ scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
+ scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buffer1->data(), kSize, true);
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buffer1, kSize, false));
+ entry->Close();
+
+ // Write a little more and read what we wrote before.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 5000, buffer1, kSize, false));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 0, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+
+ // Now go to an external file.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 18000, buffer1, kSize, false));
+ entry->Close();
+
+ // Write something else and verify old data.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 10000, buffer1, kSize, false));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 5000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 0, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 18000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+
+ // Extend the file some more.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 23000, buffer1, kSize, false));
+ entry->Close();
+
+ // And now make sure that we can deal with data in both places (ram/disk).
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 17000, buffer1, kSize, false));
+
+ // We should not overwrite the data at 18000 with this.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 19000, buffer1, kSize, false));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 18000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 17000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
+
+ EXPECT_EQ(kSize, WriteData(entry, 1, 22900, buffer1, kSize, false));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(100, ReadData(entry, 1, 23000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + 100, 100));
+
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(100, ReadData(entry, 1, 23100, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + 100, 100));
+
+ entry->Close();
+}
+
+TEST_F(DiskCacheEntryTest, Buffering) {
+ InitCache();
+ Buffering();
+}
+
+TEST_F(DiskCacheEntryTest, BufferingNoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ Buffering();
+}
+
+// Some extra tests to make sure that buffering works properly when changing
+// the entry size.
+void DiskCacheEntryTest::SizeChanges() {
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+ const int kSize = 200;
+ const char zeros[kSize] = {};
+ scoped_refptr<net::IOBuffer> buffer1 = new net::IOBuffer(kSize);
+ scoped_refptr<net::IOBuffer> buffer2 = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buffer1->data(), kSize, true);
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buffer1, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 17000, buffer1, kSize, true));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 23000, buffer1, kSize, true));
+ entry->Close();
+
+ // Extend the file and read between the old size and the new write.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(23000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 25000, buffer1, kSize, true));
+ EXPECT_EQ(25000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 24000, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, kSize));
+
+ // Read at the end of the old file size.
+ EXPECT_EQ(35, ReadData(entry, 1, 23000 + kSize - 35, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + kSize - 35, 35));
+
+ // Read slightly before the last write.
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 24900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // Extend the entry a little more.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 26000, buffer1, kSize, true));
+ EXPECT_EQ(26000 + kSize, entry->GetDataSize(1));
+ CacheTestFillBuffer(buffer2->data(), kSize, true);
+ EXPECT_EQ(kSize, ReadData(entry, 1, 25900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // And now reduce the size.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 25000, buffer1, kSize, true));
+ EXPECT_EQ(25000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(28, ReadData(entry, 1, 25000 + kSize - 28, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data() + kSize - 28, 28));
+
+ // Reduce the size with a buffer that is not extending the size.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 24000, buffer1, kSize, false));
+ EXPECT_EQ(25000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 24500, buffer1, kSize, true));
+ EXPECT_EQ(24500 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 23900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // And now reduce the size below the old size.
+ EXPECT_EQ(kSize, WriteData(entry, 1, 19000, buffer1, kSize, true));
+ EXPECT_EQ(19000 + kSize, entry->GetDataSize(1));
+ EXPECT_EQ(kSize, ReadData(entry, 1, 18900, buffer2, kSize));
+ EXPECT_TRUE(!memcmp(buffer2->data(), zeros, 100));
+ EXPECT_TRUE(!memcmp(buffer2->data() + 100, buffer1->data(), kSize - 100));
+
+ // Verify that the actual file is truncated.
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ EXPECT_EQ(19000 + kSize, entry->GetDataSize(1));
+
+ entry->Close();
+}
+
+TEST_F(DiskCacheEntryTest, SizeChanges) {
+ InitCache();
+ SizeChanges();
+}
+
+TEST_F(DiskCacheEntryTest, SizeChangesNoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ SizeChanges();
+}
+
// Write more than the total cache capacity but to a single entry. |size| is the
// amount of bytes to write each time.
void DiskCacheEntryTest::ReuseEntry(int size) {
std::string key1("the first key");
- disk_cache::Entry *entry;
+ disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key1, &entry));
entry->Close();
@@ -660,8 +1017,8 @@ void DiskCacheEntryTest::ReuseEntry(int size) {
CacheTestFillBuffer(buffer->data(), size, false);
for (int i = 0; i < 15; i++) {
- EXPECT_EQ(0, entry->WriteData(0, 0, buffer, 0, NULL, true));
- EXPECT_EQ(size, entry->WriteData(0, 0, buffer, size, NULL, false));
+ EXPECT_EQ(0, WriteData(entry, 0, 0, buffer, 0, true));
+ EXPECT_EQ(size, WriteData(entry, 0, 0, buffer, size, false));
entry->Close();
ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
}
@@ -703,9 +1060,9 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyReuseInternalEntry) {
// Reading somewhere that was not written should return zeros.
void DiskCacheEntryTest::InvalidData() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
const int kSize1 = 20000;
const int kSize2 = 20000;
@@ -718,52 +1075,52 @@ void DiskCacheEntryTest::InvalidData() {
memset(buffer2->data(), 0, kSize2);
// Simple data grow:
- EXPECT_EQ(200, entry1->WriteData(0, 400, buffer1, 200, NULL, false));
- EXPECT_EQ(600, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->ReadData(0, 300, buffer3, 100, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 400, buffer1, 200, false));
+ EXPECT_EQ(600, entry->GetDataSize(0));
+ EXPECT_EQ(100, ReadData(entry, 0, 300, buffer3, 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key1, &entry1));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// The entry is now on disk. Load it and extend it.
- EXPECT_EQ(200, entry1->WriteData(0, 800, buffer1, 200, NULL, false));
- EXPECT_EQ(1000, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->ReadData(0, 700, buffer3, 100, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 800, buffer1, 200, false));
+ EXPECT_EQ(1000, entry->GetDataSize(0));
+ EXPECT_EQ(100, ReadData(entry, 0, 700, buffer3, 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
- entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key1, &entry1));
+ entry->Close();
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// This time using truncate.
- EXPECT_EQ(200, entry1->WriteData(0, 1800, buffer1, 200, NULL, true));
- EXPECT_EQ(2000, entry1->GetDataSize(0));
- EXPECT_EQ(100, entry1->ReadData(0, 1500, buffer3, 100, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 1800, buffer1, 200, true));
+ EXPECT_EQ(2000, entry->GetDataSize(0));
+ EXPECT_EQ(100, ReadData(entry, 0, 1500, buffer3, 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
// Go to an external file.
- EXPECT_EQ(200, entry1->WriteData(0, 19800, buffer1, 200, NULL, false));
- EXPECT_EQ(20000, entry1->GetDataSize(0));
- EXPECT_EQ(4000, entry1->ReadData(0, 14000, buffer3, 4000, NULL));
+ EXPECT_EQ(200, WriteData(entry, 0, 19800, buffer1, 200, false));
+ EXPECT_EQ(20000, entry->GetDataSize(0));
+ EXPECT_EQ(4000, ReadData(entry, 0, 14000, buffer3, 4000));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 4000));
// And back to an internal block.
- EXPECT_EQ(600, entry1->WriteData(0, 1000, buffer1, 600, NULL, true));
- EXPECT_EQ(1600, entry1->GetDataSize(0));
- EXPECT_EQ(600, entry1->ReadData(0, 1000, buffer3, 600, NULL));
+ EXPECT_EQ(600, WriteData(entry, 0, 1000, buffer1, 600, true));
+ EXPECT_EQ(1600, entry->GetDataSize(0));
+ EXPECT_EQ(600, ReadData(entry, 0, 1000, buffer3, 600));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer1->data(), 600));
// Extend it again.
- EXPECT_EQ(600, entry1->WriteData(0, 2000, buffer1, 600, NULL, false));
- EXPECT_EQ(2600, entry1->GetDataSize(0));
- EXPECT_EQ(200, entry1->ReadData(0, 1800, buffer3, 200, NULL));
+ EXPECT_EQ(600, WriteData(entry, 0, 2000, buffer1, 600, false));
+ EXPECT_EQ(2600, entry->GetDataSize(0));
+ EXPECT_EQ(200, ReadData(entry, 0, 1800, buffer3, 200));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 200));
// And again (with truncation flag).
- EXPECT_EQ(600, entry1->WriteData(0, 3000, buffer1, 600, NULL, true));
- EXPECT_EQ(3600, entry1->GetDataSize(0));
- EXPECT_EQ(200, entry1->ReadData(0, 2800, buffer3, 200, NULL));
+ EXPECT_EQ(600, WriteData(entry, 0, 3000, buffer1, 600, true));
+ EXPECT_EQ(3600, entry->GetDataSize(0));
+ EXPECT_EQ(200, ReadData(entry, 0, 2800, buffer3, 200));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 200));
- entry1->Close();
+ entry->Close();
}
TEST_F(DiskCacheEntryTest, InvalidData) {
@@ -771,30 +1128,67 @@ TEST_F(DiskCacheEntryTest, InvalidData) {
InvalidData();
}
+TEST_F(DiskCacheEntryTest, InvalidDataNoBuffer) {
+ SetDirectMode();
+ InitCache();
+ cache_impl_->SetFlags(disk_cache::kNoBuffering);
+ InvalidData();
+}
+
TEST_F(DiskCacheEntryTest, MemoryOnlyInvalidData) {
SetMemoryOnlyMode();
InitCache();
InvalidData();
}
+// Tests that the cache preserves the buffer of an IO operation.
+TEST_F(DiskCacheEntryTest, ReadWriteDestroyBuffer) {
+ InitCache();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+ const int kSize = 200;
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+
+ TestCompletionCallback cb;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ entry->WriteData(0, 0, buffer, kSize, &cb, false));
+
+ // Release our reference to the buffer.
+ buffer = NULL;
+ EXPECT_EQ(kSize, cb.WaitForResult());
+
+ // And now test with a Read().
+ buffer = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buffer->data(), kSize, false);
+
+ EXPECT_EQ(net::ERR_IO_PENDING, entry->ReadData(0, 0, buffer, kSize, &cb));
+ buffer = NULL;
+ EXPECT_EQ(kSize, cb.WaitForResult());
+
+ entry->Close();
+}
+
void DiskCacheEntryTest::DoomNormalEntry() {
- std::string key1("the first key");
- disk_cache::Entry *entry1;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- entry1->Doom();
- entry1->Close();
+ std::string key("the first key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ entry->Doom();
+ entry->Close();
const int kSize = 20000;
scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kSize);
CacheTestFillBuffer(buffer->data(), kSize, true);
buffer->data()[19999] = '\0';
- key1 = buffer->data();
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- EXPECT_EQ(20000, entry1->WriteData(0, 0, buffer, kSize, NULL, false));
- EXPECT_EQ(20000, entry1->WriteData(1, 0, buffer, kSize, NULL, false));
- entry1->Doom();
- entry1->Close();
+ key = buffer->data();
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer, kSize, false));
+ EXPECT_EQ(20000, WriteData(entry, 1, 0, buffer, kSize, false));
+ entry->Doom();
+ entry->Close();
FlushQueueForTest();
EXPECT_EQ(0, cache_->GetEntryCount());
@@ -815,7 +1209,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyDoomEntry) {
// Verify that basic operations work as expected with doomed entries.
void DiskCacheEntryTest::DoomedEntry() {
std::string key("the first key");
- disk_cache::Entry *entry;
+ disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
entry->Doom();
@@ -831,8 +1225,8 @@ void DiskCacheEntryTest::DoomedEntry() {
CacheTestFillBuffer(buffer1->data(), kSize1, false);
memset(buffer2->data(), 0, kSize2);
- EXPECT_EQ(2000, entry->WriteData(0, 0, buffer1, 2000, NULL, false));
- EXPECT_EQ(2000, entry->ReadData(0, 0, buffer2, 2000, NULL));
+ EXPECT_EQ(2000, WriteData(entry, 0, 0, buffer1, 2000, false));
+ EXPECT_EQ(2000, ReadData(entry, 0, 0, buffer2, 2000));
EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kSize1));
EXPECT_EQ(key, entry->GetKey());
EXPECT_TRUE(initial < entry->GetLastModified());
@@ -892,23 +1286,18 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyEnumerationWithSparseEntries) {
// Writes |buf_1| to offset and reads it back as |buf_2|.
void VerifySparseIO(disk_cache::Entry* entry, int64 offset,
- net::IOBuffer* buf_1, int size, bool async,
- net::IOBuffer* buf_2) {
- TestCompletionCallback callback;
- TestCompletionCallback* cb = async ? &callback : NULL;
+ net::IOBuffer* buf_1, int size, net::IOBuffer* buf_2) {
+ TestCompletionCallback cb;
memset(buf_2->data(), 0, size);
- int ret = entry->ReadSparseData(offset, buf_2, size, cb);
- ret = callback.GetResult(ret);
- EXPECT_EQ(0, ret);
+ int ret = entry->ReadSparseData(offset, buf_2, size, &cb);
+ EXPECT_EQ(0, cb.GetResult(ret));
- ret = entry->WriteSparseData(offset, buf_1, size, cb);
- ret = callback.GetResult(ret);
- EXPECT_EQ(size, ret);
+ ret = entry->WriteSparseData(offset, buf_1, size, &cb);
+ EXPECT_EQ(size, cb.GetResult(ret));
- ret = entry->ReadSparseData(offset, buf_2, size, cb);
- ret = callback.GetResult(ret);
- EXPECT_EQ(size, ret);
+ ret = entry->ReadSparseData(offset, buf_2, size, &cb);
+ EXPECT_EQ(size, cb.GetResult(ret));
EXPECT_EQ(0, memcmp(buf_1->data(), buf_2->data(), size));
}
@@ -916,20 +1305,18 @@ void VerifySparseIO(disk_cache::Entry* entry, int64 offset,
// Reads |size| bytes from |entry| at |offset| and verifies that they are the
// same as the content of the provided |buffer|.
void VerifyContentSparseIO(disk_cache::Entry* entry, int64 offset, char* buffer,
- int size, bool async) {
- TestCompletionCallback callback;
- TestCompletionCallback* cb = async ? &callback : NULL;
+ int size) {
+ TestCompletionCallback cb;
scoped_refptr<net::IOBuffer> buf_1 = new net::IOBuffer(size);
memset(buf_1->data(), 0, size);
- int ret = entry->ReadSparseData(offset, buf_1, size, cb);
- ret = callback.GetResult(ret);
- EXPECT_EQ(size, ret);
+ int ret = entry->ReadSparseData(offset, buf_1, size, &cb);
+ EXPECT_EQ(size, cb.GetResult(ret));
EXPECT_EQ(0, memcmp(buf_1->data(), buffer, size));
}
-void DiskCacheEntryTest::BasicSparseIO(bool async) {
+void DiskCacheEntryTest::BasicSparseIO() {
std::string key("the first key");
disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
@@ -940,47 +1327,36 @@ void DiskCacheEntryTest::BasicSparseIO(bool async) {
CacheTestFillBuffer(buf_1->data(), kSize, false);
// Write at offset 0.
- VerifySparseIO(entry, 0, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0, buf_1, kSize, buf_2);
// Write at offset 0x400000 (4 MB).
- VerifySparseIO(entry, 0x400000, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0x400000, buf_1, kSize, buf_2);
// Write at offset 0x800000000 (32 GB).
- VerifySparseIO(entry, 0x800000000LL, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0x800000000LL, buf_1, kSize, buf_2);
entry->Close();
// Check everything again.
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
- VerifyContentSparseIO(entry, 0, buf_1->data(), kSize, async);
- VerifyContentSparseIO(entry, 0x400000, buf_1->data(), kSize, async);
- VerifyContentSparseIO(entry, 0x800000000LL, buf_1->data(), kSize, async);
+ VerifyContentSparseIO(entry, 0, buf_1->data(), kSize);
+ VerifyContentSparseIO(entry, 0x400000, buf_1->data(), kSize);
+ VerifyContentSparseIO(entry, 0x800000000LL, buf_1->data(), kSize);
entry->Close();
}
-TEST_F(DiskCacheEntryTest, BasicSparseSyncIO) {
+TEST_F(DiskCacheEntryTest, BasicSparseIO) {
InitCache();
- BasicSparseIO(false);
+ BasicSparseIO();
}
-TEST_F(DiskCacheEntryTest, MemoryOnlyBasicSparseSyncIO) {
+TEST_F(DiskCacheEntryTest, MemoryOnlyBasicSparseIO) {
SetMemoryOnlyMode();
InitCache();
- BasicSparseIO(false);
+ BasicSparseIO();
}
-TEST_F(DiskCacheEntryTest, BasicSparseAsyncIO) {
- InitCache();
- BasicSparseIO(true);
-}
-
-TEST_F(DiskCacheEntryTest, MemoryOnlyBasicSparseAsyncIO) {
- SetMemoryOnlyMode();
- InitCache();
- BasicSparseIO(true);
-}
-
-void DiskCacheEntryTest::HugeSparseIO(bool async) {
+void DiskCacheEntryTest::HugeSparseIO() {
std::string key("the first key");
disk_cache::Entry* entry;
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
@@ -992,35 +1368,24 @@ void DiskCacheEntryTest::HugeSparseIO(bool async) {
CacheTestFillBuffer(buf_1->data(), kSize, false);
// Write at offset 0x20F0000 (33 MB - 64 KB).
- VerifySparseIO(entry, 0x20F0000, buf_1, kSize, async, buf_2);
+ VerifySparseIO(entry, 0x20F0000, buf_1, kSize, buf_2);
entry->Close();
// Check it again.
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
- VerifyContentSparseIO(entry, 0x20F0000, buf_1->data(), kSize, async);
+ VerifyContentSparseIO(entry, 0x20F0000, buf_1->data(), kSize);
entry->Close();
}
-TEST_F(DiskCacheEntryTest, HugeSparseSyncIO) {
+TEST_F(DiskCacheEntryTest, HugeSparseIO) {
InitCache();
- HugeSparseIO(false);
+ HugeSparseIO();
}
-TEST_F(DiskCacheEntryTest, MemoryOnlyHugeSparseSyncIO) {
+TEST_F(DiskCacheEntryTest, MemoryOnlyHugeSparseIO) {
SetMemoryOnlyMode();
InitCache();
- HugeSparseIO(false);
-}
-
-TEST_F(DiskCacheEntryTest, HugeSparseAsyncIO) {
- InitCache();
- HugeSparseIO(true);
-}
-
-TEST_F(DiskCacheEntryTest, MemoryOnlyHugeSparseAsyncIO) {
- SetMemoryOnlyMode();
- InitCache();
- HugeSparseIO(true);
+ HugeSparseIO();
}
void DiskCacheEntryTest::GetAvailableRange() {
@@ -1033,8 +1398,8 @@ void DiskCacheEntryTest::GetAvailableRange() {
CacheTestFillBuffer(buf->data(), kSize, false);
// Write at offset 0x20F0000 (33 MB - 64 KB), and 0x20F4400 (33 MB - 47 KB).
- EXPECT_EQ(kSize, entry->WriteSparseData(0x20F0000, buf, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(0x20F4400, buf, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 0x20F0000, buf, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 0x20F4400, buf, kSize));
// We stop at the first empty block.
int64 start;
@@ -1063,7 +1428,7 @@ void DiskCacheEntryTest::GetAvailableRange() {
rv = entry->GetAvailableRange(0x20F2000, kSize, &start, &cb);
EXPECT_EQ(0x2000, cb.GetResult(rv));
EXPECT_EQ(0x20F2000, start);
- EXPECT_EQ(0x2000, entry->ReadSparseData(start, buf, kSize, NULL));
+ EXPECT_EQ(0x2000, ReadSparseData(entry, start, buf, kSize));
// Make sure that we respect the |len| argument.
start = 0;
@@ -1095,7 +1460,7 @@ void DiskCacheEntryTest::CouldBeSparse() {
CacheTestFillBuffer(buf->data(), kSize, false);
// Write at offset 0x20F0000 (33 MB - 64 KB).
- EXPECT_EQ(kSize, entry->WriteSparseData(0x20F0000, buf, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 0x20F0000, buf, kSize));
EXPECT_TRUE(entry->CouldBeSparse());
entry->Close();
@@ -1109,9 +1474,9 @@ void DiskCacheEntryTest::CouldBeSparse() {
ASSERT_EQ(net::OK, CreateEntry(key, &entry));
EXPECT_FALSE(entry->CouldBeSparse());
- EXPECT_EQ(kSize, entry->WriteData(0, 0, buf, kSize, NULL, false));
- EXPECT_EQ(kSize, entry->WriteData(1, 0, buf, kSize, NULL, false));
- EXPECT_EQ(kSize, entry->WriteData(2, 0, buf, kSize, NULL, false));
+ EXPECT_EQ(kSize, WriteData(entry, 0, 0, buf, kSize, false));
+ EXPECT_EQ(kSize, WriteData(entry, 1, 0, buf, kSize, false));
+ EXPECT_EQ(kSize, WriteData(entry, 2, 0, buf, kSize, false));
EXPECT_FALSE(entry->CouldBeSparse());
entry->Close();
@@ -1149,16 +1514,16 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedSparseIO) {
for (int i = 0; i < kSize; i += 1024) {
scoped_refptr<net::WrappedIOBuffer> buf_3 =
new net::WrappedIOBuffer(buf_1->data() + i);
- VerifySparseIO(entry, i, buf_3, 1024, false, buf_2);
- VerifySparseIO(entry, 9000 + i, buf_3, 1024, false, buf_2);
+ VerifySparseIO(entry, i, buf_3, 1024, buf_2);
+ VerifySparseIO(entry, 9000 + i, buf_3, 1024, buf_2);
}
// Make sure we have data written.
- VerifyContentSparseIO(entry, 0, buf_1->data(), kSize, false);
- VerifyContentSparseIO(entry, 9000, buf_1->data(), kSize, false);
+ VerifyContentSparseIO(entry, 0, buf_1->data(), kSize);
+ VerifyContentSparseIO(entry, 9000, buf_1->data(), kSize);
// This tests a large write that spans 3 entries from a misaligned offset.
- VerifySparseIO(entry, 20481, buf_1, 8192, false, buf_2);
+ VerifySparseIO(entry, 20481, buf_1, 8192, buf_2);
entry->Close();
}
@@ -1287,6 +1652,56 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyDoomSparseEntry) {
DoomSparseEntry();
}
+// A CompletionCallback that deletes the cache from within the callback. The way
+// a TestCompletionCallback works means that all tasks (even new ones) are
+// executed by the message loop before returning to the caller so the only way
+// to simulate a race is to execute what we want on the callback.
+class SparseTestCompletionCallback : public TestCompletionCallback {
+ public:
+ explicit SparseTestCompletionCallback(disk_cache::Backend* cache)
+ : cache_(cache) {}
+
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ delete cache_;
+ TestCompletionCallback::RunWithParams(params);
+ }
+ private:
+ disk_cache::Backend* cache_;
+ DISALLOW_COPY_AND_ASSIGN(SparseTestCompletionCallback);
+};
+
+// Tests that we don't crash when the backend is deleted while we are working
+// deleting the sub-entries of a sparse entry.
+TEST_F(DiskCacheEntryTest, DoomSparseEntry2) {
+ SetDirectMode();
+ UseCurrentThread();
+ InitCache();
+ std::string key("the key");
+ disk_cache::Entry* entry;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+
+ const int kSize = 4 * 1024;
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize);
+ CacheTestFillBuffer(buf->data(), kSize, false);
+
+ int64 offset = 1024;
+ // Write to a bunch of ranges.
+ for (int i = 0; i < 12; i++) {
+ EXPECT_EQ(kSize, entry->WriteSparseData(offset, buf, kSize, NULL));
+ offset *= 4;
+ }
+ EXPECT_EQ(9, cache_->GetEntryCount());
+
+ entry->Close();
+ SparseTestCompletionCallback cb(cache_);
+ int rv = cache_->DoomEntry(key, &cb);
+ EXPECT_EQ(net::ERR_IO_PENDING, rv);
+ EXPECT_EQ(net::OK, cb.WaitForResult());
+
+ // TearDown will attempt to delete the cache_.
+ cache_ = NULL;
+}
+
void DiskCacheEntryTest::PartialSparseEntry() {
std::string key("the first key");
disk_cache::Entry* entry;
@@ -1302,25 +1717,24 @@ void DiskCacheEntryTest::PartialSparseEntry() {
// The first write is just to extend the entry. The third write occupies
// a 1KB block partially, it may not be written internally depending on the
// implementation.
- EXPECT_EQ(kSize, entry->WriteSparseData(20000, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(500, buf1, kSize, NULL));
- EXPECT_EQ(kSmallSize,
- entry->WriteSparseData(1080321, buf1, kSmallSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 20000, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 500, buf1, kSize));
+ EXPECT_EQ(kSmallSize, WriteSparseData(entry, 1080321, buf1, kSmallSize));
entry->Close();
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
scoped_refptr<net::IOBuffer> buf2 = new net::IOBuffer(kSize);
memset(buf2->data(), 0, kSize);
- EXPECT_EQ(0, entry->ReadSparseData(8000, buf2, kSize, NULL));
+ EXPECT_EQ(0, ReadSparseData(entry, 8000, buf2, kSize));
- EXPECT_EQ(500, entry->ReadSparseData(kSize, buf2, kSize, NULL));
+ EXPECT_EQ(500, ReadSparseData(entry, kSize, buf2, kSize));
EXPECT_EQ(0, memcmp(buf2->data(), buf1->data() + kSize - 500, 500));
- EXPECT_EQ(0, entry->ReadSparseData(0, buf2, kSize, NULL));
+ EXPECT_EQ(0, ReadSparseData(entry, 0, buf2, kSize));
// This read should not change anything.
- EXPECT_EQ(96, entry->ReadSparseData(24000, buf2, kSize, NULL));
- EXPECT_EQ(500, entry->ReadSparseData(kSize, buf2, kSize, NULL));
- EXPECT_EQ(0, entry->ReadSparseData(499, buf2, kSize, NULL));
+ EXPECT_EQ(96, ReadSparseData(entry, 24000, buf2, kSize));
+ EXPECT_EQ(500, ReadSparseData(entry, kSize, buf2, kSize));
+ EXPECT_EQ(0, ReadSparseData(entry, 99, buf2, kSize));
int rv;
int64 start;
@@ -1361,11 +1775,11 @@ void DiskCacheEntryTest::PartialSparseEntry() {
EXPECT_EQ(4600, start);
// Now make another write and verify that there is no hole in between.
- EXPECT_EQ(kSize, entry->WriteSparseData(500 + kSize, buf1, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 500 + kSize, buf1, kSize));
rv = entry->GetAvailableRange(1024, 10000, &start, &cb);
EXPECT_EQ(7 * 1024 + 500, cb.GetResult(rv));
EXPECT_EQ(1024, start);
- EXPECT_EQ(kSize, entry->ReadSparseData(kSize, buf2, kSize, NULL));
+ EXPECT_EQ(kSize, ReadSparseData(entry, kSize, buf2, kSize));
EXPECT_EQ(0, memcmp(buf2->data(), buf1->data() + kSize - 500, 500));
EXPECT_EQ(0, memcmp(buf2->data() + 500, buf1->data(), kSize - 500));
@@ -1395,9 +1809,9 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
CacheTestFillBuffer(buf1->data(), kSize, false);
const int k1Meg = 1024 * 1024;
- EXPECT_EQ(kSize, entry->WriteSparseData(8192, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(k1Meg + 8192, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(2 * k1Meg + 8192, buf1, kSize, NULL));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 8192, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, k1Meg + 8192, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, 2 * k1Meg + 8192, buf1, kSize));
entry->Close();
EXPECT_EQ(4, cache_->GetEntryCount());
@@ -1414,7 +1828,7 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
for (int i = 0; i < 2; i++) {
ASSERT_EQ(net::OK, OpenEntry(child_key[i], &entry));
// Overwrite the header's magic and signature.
- EXPECT_EQ(12, entry->WriteData(2, 0, buf1, 12, NULL, false));
+ EXPECT_EQ(12, WriteData(entry, 2, 0, buf1, 12, false));
entry->Close();
}
@@ -1422,12 +1836,12 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
ASSERT_EQ(net::OK, OpenEntry(key, &entry));
// Two children should be gone. One while reading and one while writing.
- EXPECT_EQ(0, entry->ReadSparseData(2 * k1Meg + 8192, buf1, kSize, NULL));
- EXPECT_EQ(kSize, entry->WriteSparseData(k1Meg + 16384, buf1, kSize, NULL));
- EXPECT_EQ(0, entry->ReadSparseData(k1Meg + 8192, buf1, kSize, NULL));
+ EXPECT_EQ(0, ReadSparseData(entry, 2 * k1Meg + 8192, buf1, kSize));
+ EXPECT_EQ(kSize, WriteSparseData(entry, k1Meg + 16384, buf1, kSize));
+ EXPECT_EQ(0, ReadSparseData(entry, k1Meg + 8192, buf1, kSize));
// We never touched this one.
- EXPECT_EQ(kSize, entry->ReadSparseData(8192, buf1, kSize, NULL));
+ EXPECT_EQ(kSize, ReadSparseData(entry, 8192, buf1, kSize));
entry->Close();
// We re-created one of the corrupt children.
diff --git a/net/disk_cache/errors.h b/net/disk_cache/errors.h
index 4bf6f72..68c0a1a 100644
--- a/net/disk_cache/errors.h
+++ b/net/disk_cache/errors.h
@@ -6,6 +6,7 @@
#ifndef NET_DISK_CACHE_ERRORS_H__
#define NET_DISK_CACHE_ERRORS_H__
+#pragma once
namespace disk_cache {
@@ -22,7 +23,8 @@ enum {
ERR_READ_FAILURE = -10,
ERR_PREVIOUS_CRASH = -11,
ERR_STORAGE_ERROR = -12,
- ERR_INVALID_MASK = -13
+ ERR_INVALID_MASK = -13,
+ ERR_CACHE_DOOMED = -14 // Not really an error condition
};
} // namespace disk_cache
diff --git a/net/disk_cache/eviction.cc b/net/disk_cache/eviction.cc
index 91ef9b7..0173c16 100644
--- a/net/disk_cache/eviction.cc
+++ b/net/disk_cache/eviction.cc
@@ -7,7 +7,7 @@
// only one list in use (Rankings::NO_USE), and elements are sent to the front
// of the list whenever they are accessed.
-// The new (in-development) eviction policy ads re-use as a factor to evict
+// The new (in-development) eviction policy adds re-use as a factor to evict
// an entry. The story so far:
// Entries are linked on separate lists depending on how often they are used.
@@ -28,12 +28,14 @@
#include "net/disk_cache/eviction.h"
+#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/time.h"
#include "net/disk_cache/backend_impl.h"
#include "net/disk_cache/entry_impl.h"
+#include "net/disk_cache/experiments.h"
#include "net/disk_cache/histogram_macros.h"
#include "net/disk_cache/trace.h"
@@ -58,6 +60,15 @@ int LowWaterAdjust(int high_water) {
namespace disk_cache {
+Eviction::Eviction()
+ : backend_(NULL),
+ init_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
+}
+
+Eviction::~Eviction() {
+}
+
void Eviction::Init(BackendImpl* backend) {
// We grab a bunch of info from the backend to make the code a little cleaner
// when we're actually doing work.
@@ -71,6 +82,7 @@ void Eviction::Init(BackendImpl* backend) {
delay_trim_ = false;
trim_delays_ = 0;
init_ = true;
+ in_experiment_ = (header_->experiment == EXPERIMENT_DELETED_LIST_IN);
}
void Eviction::Stop() {
@@ -83,6 +95,7 @@ void Eviction::Stop() {
// this point on.
DCHECK(!trimming_);
trimming_ = true;
+ factory_.RevokeAll();
}
void Eviction::TrimCache(bool empty) {
@@ -440,8 +453,14 @@ void Eviction::TrimDeleted(bool empty) {
deleted |= RemoveDeletedNode(node.get());
}
+ // Normally we use 25% for each list. The experiment doubles the number of
+ // deleted entries, so the total number of entries increases by 25%. Using
+ // 40% of that value for deleted entries leaves the size of the other three
+ // lists intact.
+ int max_length = in_experiment_ ? header_->num_entries * 2 / 5 :
+ header_->num_entries / 4;
if (deleted && !empty &&
- header_->lru.sizes[Rankings::DELETED] > header_->num_entries / 4)
+ header_->lru.sizes[Rankings::DELETED] > max_length)
MessageLoop::current()->PostTask(FROM_HERE,
factory_.NewRunnableMethod(&Eviction::TrimDeleted, false));
diff --git a/net/disk_cache/eviction.h b/net/disk_cache/eviction.h
index 76ee00b..0f5eeb7 100644
--- a/net/disk_cache/eviction.h
+++ b/net/disk_cache/eviction.h
@@ -4,9 +4,9 @@
#ifndef NET_DISK_CACHE_EVICTION_H_
#define NET_DISK_CACHE_EVICTION_H_
+#pragma once
#include "base/basictypes.h"
-#include "base/compiler_specific.h"
#include "base/task.h"
#include "net/disk_cache/disk_format.h"
#include "net/disk_cache/rankings.h"
@@ -20,10 +20,8 @@ class EntryImpl;
// integrated with BackendImpl.
class Eviction {
public:
- Eviction()
- : backend_(NULL), init_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {}
- ~Eviction() {}
+ Eviction();
+ ~Eviction();
void Init(BackendImpl* backend);
void Stop();
@@ -77,6 +75,7 @@ class Eviction {
bool trimming_;
bool delay_trim_;
bool init_;
+ bool in_experiment_;
ScopedRunnableMethodFactory<Eviction> factory_;
DISALLOW_COPY_AND_ASSIGN(Eviction);
diff --git a/net/disk_cache/experiments.h b/net/disk_cache/experiments.h
new file mode 100644
index 0000000..5ca24db
--- /dev/null
+++ b/net/disk_cache/experiments.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 NET_DISK_CACHE_EXPERIMENTS_H_
+#define NET_DISK_CACHE_EXPERIMENTS_H_
+#pragma once
+
+
+namespace disk_cache {
+
+// This lists the experiment groups that we care about. Only add new groups at
+// the end of the list, and always increase the number.
+enum {
+ NO_EXPERIMENT = 0,
+ EXPERIMENT_OLD_FILE1 = 3,
+ EXPERIMENT_OLD_FILE2 = 4,
+ EXPERIMENT_DELETED_LIST_OUT = 11,
+ EXPERIMENT_DELETED_LIST_CONTROL = 12,
+ EXPERIMENT_DELETED_LIST_IN = 13
+};
+
+} // namespace disk_cache
+
+#endif // NET_DISK_CACHE_EXPERIMENTS_H_
diff --git a/net/disk_cache/file.h b/net/disk_cache/file.h
index 76c2f79..43ba5c1 100644
--- a/net/disk_cache/file.h
+++ b/net/disk_cache/file.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.
@@ -6,8 +6,7 @@
#ifndef NET_DISK_CACHE_FILE_H_
#define NET_DISK_CACHE_FILE_H_
-
-#include <string>
+#pragma once
#include "base/platform_file.h"
#include "base/ref_counted.h"
@@ -60,10 +59,6 @@ class File : public base::RefCounted<File> {
bool Write(const void* buffer, size_t buffer_len, size_t offset,
FileIOCallback* callback, bool* completed);
- // Performs asynchronous writes, but doesn't notify when done. Automatically
- // deletes buffer when done.
- bool PostWrite(const void* buffer, size_t buffer_len, size_t offset);
-
// Sets the file's length. The file is truncated or extended with zeros to
// the new length.
bool SetLength(size_t length);
@@ -78,7 +73,7 @@ class File : public base::RefCounted<File> {
// Performs the actual asynchronous write. If notify is set and there is no
// callback, the call will be re-synchronized.
bool AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
- bool notify, FileIOCallback* callback, bool* completed);
+ FileIOCallback* callback, bool* completed);
private:
bool init_;
diff --git a/net/disk_cache/file_block.h b/net/disk_cache/file_block.h
index 2570920..7d453e5 100644
--- a/net/disk_cache/file_block.h
+++ b/net/disk_cache/file_block.h
@@ -6,6 +6,7 @@
#ifndef NET_DISK_CACHE_FILE_BLOCK_H__
#define NET_DISK_CACHE_FILE_BLOCK_H__
+#pragma once
namespace disk_cache {
diff --git a/net/disk_cache/file_lock.h b/net/disk_cache/file_lock.h
index 3ebed76..2c560ef 100644
--- a/net/disk_cache/file_lock.h
+++ b/net/disk_cache/file_lock.h
@@ -6,6 +6,7 @@
#ifndef NET_DISK_CACHE_FILE_LOCK_H__
#define NET_DISK_CACHE_FILE_LOCK_H__
+#pragma once
#include "net/disk_cache/disk_format.h"
diff --git a/net/disk_cache/file_posix.cc b/net/disk_cache/file_posix.cc
index 05f2cc5..ce167b3 100644
--- a/net/disk_cache/file_posix.cc
+++ b/net/disk_cache/file_posix.cc
@@ -37,12 +37,11 @@ class BackgroundIO : public base::RefCountedThreadSafe<BackgroundIO> {
// Read and Write are the operations that can be performed asynchronously.
// The actual parameters for the operation are setup in the constructor of
- // the object, with the exception of |delete_buffer|, that allows a write
- // without a callback. Both methods should be called from a worker thread, by
- // posting a task to the WorkerPool (they are RunnableMethods). When finished,
+ // the object. Both methods should be called from a worker thread, by posting
+ // a task to the WorkerPool (they are RunnableMethods). When finished,
// controller->OnIOComplete() is called.
void Read();
- void Write(bool delete_buffer);
+ void Write();
// This method signals the controller that this operation is finished, in the
// original thread (presumably the IO-Thread). In practice, this is a
@@ -122,8 +121,7 @@ class InFlightIO {
void PostRead(disk_cache::File* file, void* buf, size_t buf_len,
size_t offset, disk_cache::FileIOCallback* callback);
void PostWrite(disk_cache::File* file, const void* buf, size_t buf_len,
- size_t offset, disk_cache::FileIOCallback* callback,
- bool delete_buffer);
+ size_t offset, disk_cache::FileIOCallback* callback);
// Blocks the current thread until all IO operations tracked by this object
// complete.
@@ -167,12 +165,8 @@ void BackgroundIO::Cancel() {
}
// Runs on a worker thread.
-void BackgroundIO::Write(bool delete_buffer) {
+void BackgroundIO::Write() {
bool rv = file_->Write(buf_, buf_len_, offset_);
- if (delete_buffer) {
- // TODO(rvargas): remove or update this code.
- delete[] reinterpret_cast<const char*>(buf_);
- }
bytes_ = rv ? static_cast<int>(buf_len_) : -1;
controller_->OnIOComplete(this);
@@ -203,8 +197,7 @@ void InFlightIO::PostRead(disk_cache::File *file, void* buf, size_t buf_len,
void InFlightIO::PostWrite(disk_cache::File* file, const void* buf,
size_t buf_len, size_t offset,
- disk_cache::FileIOCallback* callback,
- bool delete_buffer) {
+ disk_cache::FileIOCallback* callback) {
scoped_refptr<BackgroundIO> operation =
new BackgroundIO(file, buf, buf_len, offset, callback, this);
io_list_.insert(operation.get());
@@ -214,8 +207,7 @@ void InFlightIO::PostWrite(disk_cache::File* file, const void* buf,
callback_thread_ = MessageLoop::current();
WorkerPool::PostTask(FROM_HERE,
- NewRunnableMethod(operation.get(), &BackgroundIO::Write,
- delete_buffer),
+ NewRunnableMethod(operation.get(), &BackgroundIO::Write),
true);
}
@@ -268,7 +260,7 @@ bool File::Init(const FilePath& name) {
int flags = base::PLATFORM_FILE_OPEN |
base::PLATFORM_FILE_READ |
base::PLATFORM_FILE_WRITE;
- platform_file_ = base::CreatePlatformFile(name, flags, NULL);
+ platform_file_ = base::CreatePlatformFile(name, flags, NULL, NULL);
if (platform_file_ < 0) {
platform_file_ = 0;
return false;
@@ -343,22 +335,17 @@ bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
return Write(buffer, buffer_len, offset);
}
- return AsyncWrite(buffer, buffer_len, offset, true, callback, completed);
-}
-
-bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) {
- DCHECK(init_);
- return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL);
+ return AsyncWrite(buffer, buffer_len, offset, callback, completed);
}
bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
- bool notify, FileIOCallback* callback, bool* completed) {
+ FileIOCallback* callback, bool* completed) {
DCHECK(init_);
if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
return false;
InFlightIO* io_operations = Singleton<InFlightIO>::get();
- io_operations->PostWrite(this, buffer, buffer_len, offset, callback, !notify);
+ io_operations->PostWrite(this, buffer, buffer_len, offset, callback);
if (completed)
*completed = false;
diff --git a/net/disk_cache/file_win.cc b/net/disk_cache/file_win.cc
index 2b1f20b..5b01224 100644
--- a/net/disk_cache/file_win.cc
+++ b/net/disk_cache/file_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,7 +15,7 @@ namespace {
struct MyOverlapped {
MyOverlapped(disk_cache::File* file, size_t offset,
disk_cache::FileIOCallback* callback);
- ~MyOverlapped();
+ ~MyOverlapped() {}
OVERLAPPED* overlapped() {
return &context_.overlapped;
}
@@ -23,8 +23,6 @@ struct MyOverlapped {
MessageLoopForIO::IOContext context_;
scoped_refptr<disk_cache::File> file_;
disk_cache::FileIOCallback* callback_;
- const void* buffer_;
- bool delete_buffer_; // Delete the user buffer at completion.
};
COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped);
@@ -60,15 +58,6 @@ MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset,
callback_ = callback;
}
-MyOverlapped::~MyOverlapped() {
- if (delete_buffer_) {
- DCHECK(!callback_);
- // This whole thing could be updated to use IOBuffer, but PostWrite is not
- // used at the moment. TODO(rvargas): remove or update this code.
- delete[] reinterpret_cast<const char*>(buffer_);
- }
-}
-
} // namespace
namespace disk_cache {
@@ -83,9 +72,9 @@ bool File::Init(const FilePath& name) {
if (init_)
return false;
- platform_file_ = CreateFile(name.value().c_str(),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ DWORD access = GENERIC_READ | GENERIC_WRITE | DELETE;
+ platform_file_ = CreateFile(name.value().c_str(), access, sharing, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (INVALID_HANDLE_VALUE == platform_file_)
@@ -95,9 +84,7 @@ bool File::Init(const FilePath& name) {
platform_file_, Singleton<CompletionHandler>::get());
init_ = true;
- sync_platform_file_ = CreateFile(name.value().c_str(),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ sync_platform_file_ = CreateFile(name.value().c_str(), access, sharing, NULL,
OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == sync_platform_file_)
@@ -207,29 +194,18 @@ bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
return Write(buffer, buffer_len, offset);
}
- return AsyncWrite(buffer, buffer_len, offset, true, callback, completed);
-}
-
-bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) {
- DCHECK(init_);
- return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL);
+ return AsyncWrite(buffer, buffer_len, offset, callback, completed);
}
bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
- bool notify, FileIOCallback* callback, bool* completed) {
+ FileIOCallback* callback, bool* completed) {
DCHECK(init_);
+ DCHECK(callback);
+ DCHECK(completed);
if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
return false;
MyOverlapped* data = new MyOverlapped(this, offset, callback);
- bool dummy_completed;
- if (!callback) {
- DCHECK(!notify);
- data->delete_buffer_ = true;
- data->buffer_ = buffer;
- completed = &dummy_completed;
- }
-
DWORD size = static_cast<DWORD>(buffer_len);
DWORD actual;
diff --git a/net/disk_cache/hash.h b/net/disk_cache/hash.h
index bf35c26..01e0058 100644
--- a/net/disk_cache/hash.h
+++ b/net/disk_cache/hash.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_HASH_H__
#define NET_DISK_CACHE_HASH_H__
+#pragma once
#include <string>
diff --git a/net/disk_cache/histogram_macros.h b/net/disk_cache/histogram_macros.h
index 361a9d6..2505a8a 100644
--- a/net/disk_cache/histogram_macros.h
+++ b/net/disk_cache/histogram_macros.h
@@ -10,6 +10,7 @@
#ifndef NET_DISK_CACHE_HISTOGRAM_MACROS_H_
#define NET_DISK_CACHE_HISTOGRAM_MACROS_H_
+#pragma once
// -----------------------------------------------------------------------------
@@ -32,6 +33,9 @@
#define CACHE_HISTOGRAM_COUNTS_10000(name, sample) \
CACHE_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+#define CACHE_HISTOGRAM_COUNTS_50000(name, sample) \
+ CACHE_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 50000000, 50)
+
#define CACHE_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
do { \
static scoped_refptr<Histogram> counter; \
diff --git a/net/disk_cache/in_flight_backend_io.cc b/net/disk_cache/in_flight_backend_io.cc
index 1e2ce9f..e400ac3 100644
--- a/net/disk_cache/in_flight_backend_io.cc
+++ b/net/disk_cache/in_flight_backend_io.cc
@@ -9,6 +9,7 @@
#include "net/base/net_errors.h"
#include "net/disk_cache/backend_impl.h"
#include "net/disk_cache/entry_impl.h"
+#include "net/disk_cache/histogram_macros.h"
namespace disk_cache {
@@ -18,6 +19,7 @@ BackendIO::BackendIO(InFlightIO* controller, BackendImpl* backend,
operation_(OP_NONE),
ALLOW_THIS_IN_INITIALIZER_LIST(
my_callback_(this, &BackendIO::OnIOComplete)) {
+ start_time_ = base::TimeTicks::Now();
}
// Runs on the background thread.
@@ -44,6 +46,10 @@ void BackendIO::ReleaseEntry() {
entry_ = NULL;
}
+base::TimeDelta BackendIO::ElapsedTime() const {
+ return base::TimeTicks::Now() - start_time_;
+}
+
void BackendIO::Init() {
operation_ = OP_INIT;
}
@@ -112,6 +118,11 @@ void BackendIO::FlushQueue() {
operation_ = OP_FLUSH_QUEUE;
}
+void BackendIO::RunTask(Task* task) {
+ operation_ = OP_RUN_TASK;
+ task_ = task;
+}
+
void BackendIO::ReadData(EntryImpl* entry, int index, int offset,
net::IOBuffer* buf, int buf_len) {
operation_ = OP_READ;
@@ -215,6 +226,11 @@ void BackendIO::ExecuteBackendOperation() {
case OP_FLUSH_QUEUE:
result_ = net::OK;
break;
+ case OP_RUN_TASK:
+ task_->Run();
+ delete task_;
+ result_ = net::OK;
+ break;
default:
NOTREACHED() << "Invalid Operation";
result_ = net::ERR_UNEXPECTED;
@@ -262,6 +278,16 @@ void BackendIO::ExecuteEntryOperation() {
// ---------------------------------------------------------------------------
+InFlightBackendIO::InFlightBackendIO(BackendImpl* backend,
+ base::MessageLoopProxy* background_thread)
+ : backend_(backend),
+ background_thread_(background_thread),
+ queue_entry_ops_(false) {
+}
+
+InFlightBackendIO::~InFlightBackendIO() {
+}
+
void InFlightBackendIO::Init(CompletionCallback* callback) {
scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback);
operation->Init();
@@ -348,6 +374,12 @@ void InFlightBackendIO::FlushQueue(net::CompletionCallback* callback) {
QueueOperation(operation);
}
+void InFlightBackendIO::RunTask(Task* task, net::CompletionCallback* callback) {
+ scoped_refptr<BackendIO> operation = new BackendIO(this, backend_, callback);
+ operation->RunTask(task);
+ QueueOperation(operation);
+}
+
void InFlightBackendIO::ReadData(EntryImpl* entry, int index, int offset,
net::IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
@@ -409,6 +441,14 @@ void InFlightBackendIO::WaitForPendingIO() {
InFlightIO::WaitForPendingIO();
}
+void InFlightBackendIO::StartQueingOperations() {
+ queue_entry_ops_ = true;
+}
+
+void InFlightBackendIO::StopQueingOperations() {
+ queue_entry_ops_ = false;
+}
+
void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation,
bool cancel) {
BackendIO* op = static_cast<BackendIO*>(operation);
@@ -417,9 +457,22 @@ 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.
- scoped_refptr<BackendIO> next_op = pending_ops_.front();
- pending_ops_.pop_front();
- PostOperation(next_op);
+ PostQueuedOperation(&pending_ops_);
+ }
+
+ if (op->IsEntryOperation()) {
+ backend_->OnOperationCompleted(op->ElapsedTime());
+ if (!pending_entry_ops_.empty()) {
+ PostQueuedOperation(&pending_entry_ops_);
+
+ // If we are not throttling requests anymore, dispatch the whole queue.
+ if (!queue_entry_ops_) {
+ CACHE_UMA(COUNTS_10000, "FinalQueuedOperations", 0,
+ pending_entry_ops_.size());
+ while (!pending_entry_ops_.empty())
+ PostQueuedOperation(&pending_entry_ops_);
+ }
+ }
}
if (op->callback() && (!cancel || op->IsEntryOperation()))
@@ -430,13 +483,15 @@ void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation,
}
void InFlightBackendIO::QueueOperation(BackendIO* operation) {
- if (operation->IsEntryOperation())
- return PostOperation(operation);
+ if (!operation->IsEntryOperation())
+ return QueueOperationToList(operation, &pending_ops_);
- if (pending_ops_.empty())
+ if (!queue_entry_ops_)
return PostOperation(operation);
- pending_ops_.push_back(operation);
+ CACHE_UMA(COUNTS_10000, "QueuedOperations", 0, pending_entry_ops_.size());
+
+ QueueOperationToList(operation, &pending_entry_ops_);
}
void InFlightBackendIO::PostOperation(BackendIO* operation) {
@@ -445,4 +500,18 @@ void InFlightBackendIO::PostOperation(BackendIO* operation) {
OnOperationPosted(operation);
}
+void InFlightBackendIO::PostQueuedOperation(OperationList* from_list) {
+ scoped_refptr<BackendIO> next_op = from_list->front();
+ from_list->pop_front();
+ PostOperation(next_op);
+}
+
+void InFlightBackendIO::QueueOperationToList(BackendIO* operation,
+ OperationList* list) {
+ if (list->empty())
+ return PostOperation(operation);
+
+ list->push_back(operation);
+}
+
} // namespace
diff --git a/net/disk_cache/in_flight_backend_io.h b/net/disk_cache/in_flight_backend_io.h
index 1cd0d41..889fb20 100644
--- a/net/disk_cache/in_flight_backend_io.h
+++ b/net/disk_cache/in_flight_backend_io.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_IN_FLIGHT_BACKEND_IO_H_
#define NET_DISK_CACHE_IN_FLIGHT_BACKEND_IO_H_
+#pragma once
#include <list>
#include <string>
@@ -38,6 +39,9 @@ class BackendIO : public BackgroundIO {
void ReleaseEntry();
+ // Returns the time that has passed since the operation was created.
+ base::TimeDelta ElapsedTime() const;
+
// The operations we proxy:
void Init();
void OpenEntry(const std::string& key, Entry** entry);
@@ -53,6 +57,7 @@ class BackendIO : public BackgroundIO {
void CloseEntryImpl(EntryImpl* entry);
void DoomEntryImpl(EntryImpl* entry);
void FlushQueue(); // Dummy operation.
+ void RunTask(Task* task);
void ReadData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf,
int buf_len);
void WriteData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf,
@@ -88,6 +93,7 @@ class BackendIO : public BackgroundIO {
OP_CLOSE_ENTRY,
OP_DOOM_ENTRY,
OP_FLUSH_QUEUE,
+ OP_RUN_TASK,
OP_MAX_BACKEND,
OP_READ,
OP_WRITE,
@@ -123,6 +129,8 @@ class BackendIO : public BackgroundIO {
bool truncate_;
int64 offset64_;
int64* start_;
+ base::TimeTicks start_time_;
+ Task* task_;
DISALLOW_COPY_AND_ASSIGN(BackendIO);
};
@@ -131,9 +139,8 @@ class BackendIO : public BackgroundIO {
class InFlightBackendIO : public InFlightIO {
public:
InFlightBackendIO(BackendImpl* backend,
- base::MessageLoopProxy* background_thread)
- : backend_(backend), background_thread_(background_thread) {}
- ~InFlightBackendIO() {}
+ base::MessageLoopProxy* background_thread);
+ ~InFlightBackendIO();
// The operations we proxy:
void Init(net::CompletionCallback* callback);
@@ -156,6 +163,7 @@ class InFlightBackendIO : public InFlightIO {
void CloseEntryImpl(EntryImpl* entry);
void DoomEntryImpl(EntryImpl* entry);
void FlushQueue(net::CompletionCallback* callback);
+ void RunTask(Task* task, net::CompletionCallback* callback);
void ReadData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf,
int buf_len, net::CompletionCallback* callback);
void WriteData(EntryImpl* entry, int index, int offset, net::IOBuffer* buf,
@@ -181,6 +189,10 @@ class InFlightBackendIO : public InFlightIO {
return background_thread_->BelongsToCurrentThread();
}
+ // Controls the queing of entry (async) operations.
+ void StartQueingOperations();
+ void StopQueingOperations();
+
protected:
virtual void OnOperationComplete(BackgroundIO* operation, bool cancel);
@@ -188,10 +200,14 @@ class InFlightBackendIO : public InFlightIO {
typedef std::list<scoped_refptr<BackendIO> > OperationList;
void QueueOperation(BackendIO* operation);
void PostOperation(BackendIO* operation);
+ void PostQueuedOperation(OperationList* from_list);
+ void QueueOperationToList(BackendIO* operation, OperationList* list);
BackendImpl* backend_;
scoped_refptr<base::MessageLoopProxy> background_thread_;
OperationList pending_ops_; // The list of operations to be posted.
+ OperationList pending_entry_ops_; // Entry (async) operations to be posted.
+ bool queue_entry_ops_; // True if we are queuing entry (async) operations.
DISALLOW_COPY_AND_ASSIGN(InFlightBackendIO);
};
diff --git a/net/disk_cache/in_flight_io.cc b/net/disk_cache/in_flight_io.cc
index 6112a9c..5c859af 100644
--- a/net/disk_cache/in_flight_io.cc
+++ b/net/disk_cache/in_flight_io.cc
@@ -8,6 +8,10 @@
namespace disk_cache {
+BackgroundIO::BackgroundIO(InFlightIO* controller)
+ : controller_(controller), result_(-1), io_completed_(true, false) {
+}
+
// Runs on the primary thread.
void BackgroundIO::OnIOSignalled() {
if (controller_)
@@ -19,6 +23,8 @@ void BackgroundIO::Cancel() {
controller_ = NULL;
}
+BackgroundIO::~BackgroundIO() {}
+
// Runs on the background thread.
void BackgroundIO::NotifyController() {
controller_->OnIOComplete(this);
@@ -26,6 +32,14 @@ void BackgroundIO::NotifyController() {
// ---------------------------------------------------------------------------
+InFlightIO::InFlightIO()
+ : callback_thread_(base::MessageLoopProxy::CreateForCurrentThread()),
+ running_(false), single_thread_(false) {
+}
+
+InFlightIO::~InFlightIO() {
+}
+
void InFlightIO::WaitForPendingIO() {
while (!io_list_.empty()) {
// Block the current thread until all pending IO completes.
diff --git a/net/disk_cache/in_flight_io.h b/net/disk_cache/in_flight_io.h
index 4486f44..6c5f8ab 100644
--- a/net/disk_cache/in_flight_io.h
+++ b/net/disk_cache/in_flight_io.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_IN_FLIGHT_IO_H_
#define NET_DISK_CACHE_IN_FLIGHT_IO_H_
+#pragma once
#include <set>
@@ -23,8 +24,7 @@ class BackgroundIO : public base::RefCountedThreadSafe<BackgroundIO> {
// is keeping track of all operations. When done, we notify the controller
// (we do NOT invoke the callback), in the worker thead that completed the
// operation.
- explicit BackgroundIO(InFlightIO* controller)
- : controller_(controller), result_(-1), io_completed_(true, false) {}
+ explicit BackgroundIO(InFlightIO* controller);
// This method signals the controller that this operation is finished, in the
// original thread. In practice, this is a RunableMethod that allows
@@ -46,7 +46,7 @@ class BackgroundIO : public base::RefCountedThreadSafe<BackgroundIO> {
}
protected:
- virtual ~BackgroundIO() {}
+ virtual ~BackgroundIO();
InFlightIO* controller_; // The controller that tracks all operations.
int result_; // Final operation result.
@@ -88,10 +88,8 @@ class BackgroundIO : public base::RefCountedThreadSafe<BackgroundIO> {
// of just waiting for step 7.
class InFlightIO {
public:
- InFlightIO()
- : callback_thread_(base::MessageLoopProxy::CreateForCurrentThread()),
- running_(false), single_thread_(false) {}
- virtual ~InFlightIO() {}
+ InFlightIO();
+ virtual ~InFlightIO();
// Blocks the current thread until all IO operations tracked by this object
// complete.
diff --git a/net/disk_cache/mapped_file.h b/net/disk_cache/mapped_file.h
index 5b34141..c39f3f9 100644
--- a/net/disk_cache/mapped_file.h
+++ b/net/disk_cache/mapped_file.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.
@@ -6,8 +6,7 @@
#ifndef NET_DISK_CACHE_MAPPED_FILE_H_
#define NET_DISK_CACHE_MAPPED_FILE_H_
-
-#include <string>
+#pragma once
#include "net/disk_cache/disk_format.h"
#include "net/disk_cache/file.h"
diff --git a/net/disk_cache/mem_backend_impl.h b/net/disk_cache/mem_backend_impl.h
index c5e947f..62ed3c5 100644
--- a/net/disk_cache/mem_backend_impl.h
+++ b/net/disk_cache/mem_backend_impl.h
@@ -6,6 +6,7 @@
#ifndef NET_DISK_CACHE_MEM_BACKEND_IMPL_H__
#define NET_DISK_CACHE_MEM_BACKEND_IMPL_H__
+#pragma once
#include "base/hash_tables.h"
diff --git a/net/disk_cache/mem_entry_impl.cc b/net/disk_cache/mem_entry_impl.cc
index 645619e..8d8bb4c 100644
--- a/net/disk_cache/mem_entry_impl.cc
+++ b/net/disk_cache/mem_entry_impl.cc
@@ -326,8 +326,9 @@ int MemEntryImpl::ReadyForSparseIO(
bool MemEntryImpl::CreateEntry(const std::string& key) {
key_ = key;
- last_modified_ = Time::Now();
- last_used_ = Time::Now();
+ Time current = Time::Now();
+ last_modified_ = current;
+ last_used_ = current;
Open();
backend_->ModifyStorageSize(0, static_cast<int32>(key.size()));
return true;
@@ -431,8 +432,9 @@ bool MemEntryImpl::InitChildEntry(MemEntryImpl* parent, int child_id) {
DCHECK(!child_id_);
parent_ = parent;
child_id_ = child_id;
- last_modified_ = Time::Now();
- last_used_ = Time::Now();
+ Time current = Time::Now();
+ last_modified_ = current;
+ last_used_ = current;
// Insert this to the backend's ranking list.
backend_->InsertIntoRankingList(this);
return true;
diff --git a/net/disk_cache/mem_entry_impl.h b/net/disk_cache/mem_entry_impl.h
index 66535d5..573a306 100644
--- a/net/disk_cache/mem_entry_impl.h
+++ b/net/disk_cache/mem_entry_impl.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_MEM_ENTRY_IMPL_H_
#define NET_DISK_CACHE_MEM_ENTRY_IMPL_H_
+#pragma once
#include "base/hash_tables.h"
#include "base/scoped_ptr.h"
diff --git a/net/disk_cache/mem_rankings.h b/net/disk_cache/mem_rankings.h
index fa90688..166224f 100644
--- a/net/disk_cache/mem_rankings.h
+++ b/net/disk_cache/mem_rankings.h
@@ -6,6 +6,7 @@
#ifndef NET_DISK_CACHE_MEM_RANKINGS_H__
#define NET_DISK_CACHE_MEM_RANKINGS_H__
+#pragma once
#include "base/basictypes.h"
diff --git a/net/disk_cache/rankings.cc b/net/disk_cache/rankings.cc
index 34c002b..e7c6736 100644
--- a/net/disk_cache/rankings.cc
+++ b/net/disk_cache/rankings.cc
@@ -176,6 +176,20 @@ void GenerateCrash(CrashLocation location) {
namespace disk_cache {
+Rankings::Iterator::Iterator(Rankings* rankings) {
+ memset(this, 0, sizeof(Iterator));
+ my_rankings = rankings;
+}
+
+Rankings::Iterator::~Iterator() {
+ for (int i = 0; i < 3; i++)
+ ScopedRankingsBlock(my_rankings, nodes[i]);
+}
+
+Rankings::Rankings() : init_(false) {}
+
+Rankings::~Rankings() {}
+
bool Rankings::Init(BackendImpl* backend, bool count_lists) {
DCHECK(!init_);
if (init_)
diff --git a/net/disk_cache/rankings.h b/net/disk_cache/rankings.h
index f635355..1914cf6 100644
--- a/net/disk_cache/rankings.h
+++ b/net/disk_cache/rankings.h
@@ -6,6 +6,7 @@
#ifndef NET_DISK_CACHE_RANKINGS_H_
#define NET_DISK_CACHE_RANKINGS_H_
+#pragma once
#include <list>
@@ -95,18 +96,12 @@ class Rankings {
List list; // Which entry was returned to the user.
CacheRankingsBlock* nodes[3]; // Nodes on the first three lists.
Rankings* my_rankings;
- explicit Iterator(Rankings* rankings) {
- memset(this, 0, sizeof(Iterator));
- my_rankings = rankings;
- }
- ~Iterator() {
- for (int i = 0; i < 3; i++)
- ScopedRankingsBlock(my_rankings, nodes[i]);
- }
+ explicit Iterator(Rankings* rankings);
+ ~Iterator();
};
- Rankings() : init_(false) {}
- ~Rankings() {}
+ Rankings();
+ ~Rankings();
bool Init(BackendImpl* backend, bool count_lists);
diff --git a/net/disk_cache/sparse_control.cc b/net/disk_cache/sparse_control.cc
index 884a1b7..2934184 100644
--- a/net/disk_cache/sparse_control.cc
+++ b/net/disk_cache/sparse_control.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/time.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -41,8 +42,8 @@ const int kBlockSize = 1024;
// number of the particular child.
std::string GenerateChildName(const std::string& base_name, int64 signature,
int64 child_id) {
- return StringPrintf("Range_%s:%" PRIx64 ":%" PRIx64, base_name.c_str(),
- signature, child_id);
+ return base::StringPrintf("Range_%s:%" PRIx64 ":%" PRIx64, base_name.c_str(),
+ signature, child_id);
}
// This class deletes the children of a sparse entry.
@@ -51,7 +52,7 @@ class ChildrenDeleter
public disk_cache::FileIOCallback {
public:
ChildrenDeleter(disk_cache::BackendImpl* backend, const std::string& name)
- : backend_(backend), name_(name) {}
+ : backend_(backend->GetWeakPtr()), name_(name) {}
virtual void OnFileIOComplete(int bytes_copied);
@@ -66,7 +67,7 @@ class ChildrenDeleter
void DeleteChildren();
- disk_cache::BackendImpl* backend_;
+ base::WeakPtr<disk_cache::BackendImpl> backend_;
std::string name_;
disk_cache::Bitmap children_map_;
int64 signature_;
@@ -101,6 +102,9 @@ void ChildrenDeleter::Start(char* buffer, int len) {
void ChildrenDeleter::ReadData(disk_cache::Addr address, int len) {
DCHECK(address.is_block_file());
+ if (!backend_)
+ return Release();
+
disk_cache::File* file(backend_->File(address));
if (!file)
return Release();
@@ -121,7 +125,7 @@ void ChildrenDeleter::ReadData(disk_cache::Addr address, int len) {
void ChildrenDeleter::DeleteChildren() {
int child_id = 0;
- if (!children_map_.FindNextSetBit(&child_id)) {
+ if (!children_map_.FindNextSetBit(&child_id) || !backend_) {
// We are done. Just delete this object.
return Release();
}
diff --git a/net/disk_cache/sparse_control.h b/net/disk_cache/sparse_control.h
index b88f258..88a012b 100644
--- a/net/disk_cache/sparse_control.h
+++ b/net/disk_cache/sparse_control.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_SPARSE_CONTROL_H_
#define NET_DISK_CACHE_SPARSE_CONTROL_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/net/disk_cache/stats.cc b/net/disk_cache/stats.cc
index e69ea00..f0446fb 100644
--- a/net/disk_cache/stats.cc
+++ b/net/disk_cache/stats.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 "base/format_macros.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/disk_cache/backend_impl.h"
namespace {
@@ -147,8 +148,10 @@ bool Stats::Init(BackendImpl* backend, uint32* storage_addr) {
return true;
}
+Stats::Stats() : backend_(NULL) {
+}
+
Stats::~Stats() {
- Store();
}
// The array will be filled this way:
@@ -258,14 +261,14 @@ int64 Stats::GetCounter(Counters counter) const {
void Stats::GetItems(StatsItems* items) {
std::pair<std::string, std::string> item;
for (int i = 0; i < kDataSizesLength; i++) {
- item.first = StringPrintf("Size%02d", i);
- item.second = StringPrintf("0x%08x", data_sizes_[i]);
+ item.first = base::StringPrintf("Size%02d", i);
+ item.second = base::StringPrintf("0x%08x", data_sizes_[i]);
items->push_back(item);
}
for (int i = MIN_COUNTER + 1; i < MAX_COUNTER; i++) {
item.first = kCounterNames[i];
- item.second = StringPrintf("0x%" PRIx64, counters_[i]);
+ item.second = base::StringPrintf("0x%" PRIx64, counters_[i]);
items->push_back(item);
}
}
diff --git a/net/disk_cache/stats.h b/net/disk_cache/stats.h
index 13536b1..3042590 100644
--- a/net/disk_cache/stats.h
+++ b/net/disk_cache/stats.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2010 The Chromium Authors. 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_DISK_CACHE_STATS_H_
#define NET_DISK_CACHE_STATS_H_
+#pragma once
#include <string>
#include <vector>
@@ -47,7 +48,7 @@ class Stats {
MAX_COUNTER
};
- Stats() : backend_(NULL) {}
+ Stats();
~Stats();
bool Init(BackendImpl* backend, uint32* storage_addr);
diff --git a/net/disk_cache/stats_histogram.h b/net/disk_cache/stats_histogram.h
index 995d486..1c2e15a 100644
--- a/net/disk_cache/stats_histogram.h
+++ b/net/disk_cache/stats_histogram.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_STATS_HISTOGRAM_H_
#define NET_DISK_CACHE_STATS_HISTOGRAM_H_
+#pragma once
#include <string>
diff --git a/net/disk_cache/storage_block-inl.h b/net/disk_cache/storage_block-inl.h
index 5e026a7..e2f4b3c 100644
--- a/net/disk_cache/storage_block-inl.h
+++ b/net/disk_cache/storage_block-inl.h
@@ -4,6 +4,7 @@
#ifndef NET_DISK_CACHE_STORAGE_BLOCK_INL_H_
#define NET_DISK_CACHE_STORAGE_BLOCK_INL_H_
+#pragma once
#include "net/disk_cache/storage_block.h"
diff --git a/net/disk_cache/storage_block.h b/net/disk_cache/storage_block.h
index e77c5bb..49694c6 100644
--- a/net/disk_cache/storage_block.h
+++ b/net/disk_cache/storage_block.h
@@ -6,14 +6,13 @@
#ifndef NET_DISK_CACHE_STORAGE_BLOCK_H__
#define NET_DISK_CACHE_STORAGE_BLOCK_H__
+#pragma once
#include "net/disk_cache/addr.h"
#include "net/disk_cache/mapped_file.h"
namespace disk_cache {
-class EntryImpl;
-
// This class encapsulates common behavior of a single "block" of data that is
// stored on a block-file. It implements the FileBlock interface, so it can be
// serialized directly to the backing file.
diff --git a/net/disk_cache/stress_cache.cc b/net/disk_cache/stress_cache.cc
index b153659..98dcbe1 100644
--- a/net/disk_cache/stress_cache.cc
+++ b/net/disk_cache/stress_cache.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.
@@ -10,6 +10,18 @@
// The child application has two threads: one to exercise the cache in an
// infinite loop, and another one to asynchronously kill the process.
+// A regular build should never crash.
+// To test that the disk cache doesn't generate critical errors with regular
+// application level crashes, add the following code and re-compile:
+//
+// void BackendImpl::CriticalError(int error) {
+// NOTREACHED();
+//
+// void BackendImpl::ReportError(int error) {
+// if (error && error != ERR_PREVIOUS_CRASH) {
+// NOTREACHED();
+// }
+
#include <string>
#include <vector>
@@ -22,8 +34,10 @@
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/base/io_buffer.h"
@@ -42,7 +56,7 @@ int RunSlave(int iteration) {
PathService::Get(base::FILE_EXE, &exe);
CommandLine cmdline(exe);
- cmdline.AppendLooseValue(ASCIIToWide(IntToString(iteration)));
+ cmdline.AppendArg(base::IntToString(iteration));
base::ProcessHandle handle;
if (!base::LaunchApp(cmdline, false, false, &handle)) {
@@ -78,7 +92,7 @@ int MasterCode() {
// to know which instance of the application wrote them.
void StressTheCache(int iteration) {
int cache_size = 0x800000; // 8MB
- FilePath path = GetCacheFilePath().AppendASCII("_stress");
+ FilePath path = GetCacheFilePath().InsertBeforeExtensionASCII("_stress");
base::Thread cache_thread("CacheThread");
if (!cache_thread.StartWithOptions(
@@ -102,7 +116,11 @@ void StressTheCache(int iteration) {
int seed = static_cast<int>(Time::Now().ToInternalValue());
srand(seed);
+#ifdef NDEBUG
const int kNumKeys = 5000;
+#else
+ const int kNumKeys = 1700;
+#endif
const int kNumEntries = 30;
std::string keys[kNumKeys];
disk_cache::Entry* entries[kNumEntries] = {0};
@@ -118,6 +136,8 @@ void StressTheCache(int iteration) {
for (int i = 0;; i++) {
int slot = rand() % kNumEntries;
int key = rand() % kNumKeys;
+ bool truncate = rand() % 2 ? false : true;
+ int size = kSize - (rand() % 4) * kSize / 4;
if (entries[slot])
entries[slot]->Close();
@@ -128,9 +148,11 @@ void StressTheCache(int iteration) {
CHECK_EQ(net::OK, cb.GetResult(rv));
}
- base::snprintf(buffer->data(), kSize, "%d %d", iteration, i);
- rv = entries[slot]->WriteData(0, 0, buffer, kSize, &cb, false);
- CHECK_EQ(kSize, cb.GetResult(rv));
+ base::snprintf(buffer->data(), kSize,
+ "i: %d iter: %d, size: %d, truncate: %d", i, iteration, size,
+ truncate ? 1 : 0);
+ rv = entries[slot]->WriteData(0, 0, buffer, size, &cb, truncate);
+ CHECK_EQ(size, cb.GetResult(rv));
if (rand() % 100 > 80) {
key = rand() % kNumKeys;
diff --git a/net/disk_cache/trace.cc b/net/disk_cache/trace.cc
index 7a61e20..9578339 100644
--- a/net/disk_cache/trace.cc
+++ b/net/disk_cache/trace.cc
@@ -57,6 +57,14 @@ TraceObject* TraceObject::GetTraceObject() {
return s_trace_object;
}
+TraceObject::TraceObject() {
+ InitTrace();
+}
+
+TraceObject::~TraceObject() {
+ DestroyTrace();
+}
+
#if ENABLE_TRACING
static TraceBuffer* s_trace_buffer = NULL;
diff --git a/net/disk_cache/trace.h b/net/disk_cache/trace.h
index a431890..a5aa651 100644
--- a/net/disk_cache/trace.h
+++ b/net/disk_cache/trace.h
@@ -8,9 +8,7 @@
#ifndef NET_DISK_CACHE_TRACE_H__
#define NET_DISK_CACHE_TRACE_H__
-
-#include <string>
-#include <vector>
+#pragma once
#include "base/basictypes.h"
#include "base/ref_counted.h"
@@ -29,13 +27,8 @@ class TraceObject : public base::RefCounted<TraceObject> {
static TraceObject* GetTraceObject();
private:
- TraceObject() {
- InitTrace();
- }
-
- ~TraceObject() {
- DestroyTrace();
- }
+ TraceObject();
+ ~TraceObject();
DISALLOW_COPY_AND_ASSIGN(TraceObject);
};
diff --git a/net/fetch_client.target.mk b/net/fetch_client.target.mk
index 114ceb5..4cbcc1f 100644
--- a/net/fetch_client.target.mk
+++ b/net/fetch_client.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -70,6 +71,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -134,14 +136,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -170,7 +173,8 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/fetch_client: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/fetch_client: LIBS := $(LIBS)
diff --git a/net/fetch_server.target.mk b/net/fetch_server.target.mk
index 7d176e6..bbd93ab 100644
--- a/net/fetch_server.target.mk
+++ b/net/fetch_server.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -70,6 +71,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -137,14 +139,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -173,7 +176,8 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/fetch_server: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/fetch_server: LIBS := $(LIBS)
diff --git a/net/ftp/ftp_auth_cache.cc b/net/ftp/ftp_auth_cache.cc
index d3bff90..caa2b8a 100644
--- a/net/ftp/ftp_auth_cache.cc
+++ b/net/ftp/ftp_auth_cache.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.
@@ -20,8 +20,8 @@ FtpAuthCache::Entry* FtpAuthCache::Lookup(const GURL& origin) {
return NULL;
}
-void FtpAuthCache::Add(const GURL& origin, const std::wstring& username,
- const std::wstring& password) {
+void FtpAuthCache::Add(const GURL& origin, const string16& username,
+ const string16& password) {
DCHECK(origin.SchemeIs("ftp"));
DCHECK_EQ(origin.GetOrigin(), origin);
@@ -38,8 +38,8 @@ void FtpAuthCache::Add(const GURL& origin, const std::wstring& username,
}
}
-void FtpAuthCache::Remove(const GURL& origin, const std::wstring& username,
- const std::wstring& password) {
+void FtpAuthCache::Remove(const GURL& origin, const string16& username,
+ const string16& password) {
for (EntryList::iterator it = entries_.begin(); it != entries_.end(); ++it) {
if (it->origin == origin && it->username == username &&
it->password == password) {
diff --git a/net/ftp/ftp_auth_cache.h b/net/ftp/ftp_auth_cache.h
index 83cdd63..36156da 100644
--- a/net/ftp/ftp_auth_cache.h
+++ b/net/ftp/ftp_auth_cache.h
@@ -1,13 +1,14 @@
-// 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.
#ifndef NET_FTP_FTP_AUTH_CACHE_H_
#define NET_FTP_FTP_AUTH_CACHE_H_
+#pragma once
#include <list>
-#include <string>
+#include "base/string16.h"
#include "googleurl/src/gurl.h"
namespace net {
@@ -26,16 +27,16 @@ class FtpAuthCache {
static const size_t kMaxEntries;
struct Entry {
- Entry(const GURL& origin, const std::wstring& username,
- const std::wstring& password)
+ Entry(const GURL& origin, const string16& username,
+ const string16& password)
: origin(origin),
username(username),
password(password) {
}
const GURL origin;
- std::wstring username;
- std::wstring password;
+ string16 username;
+ string16 password;
};
FtpAuthCache() {}
@@ -47,13 +48,13 @@ class FtpAuthCache {
// Add an entry for |origin| to the cache (consisting of |username| and
// |password|). If there is already an entry for |origin|, it will be
// overwritten.
- void Add(const GURL& origin, const std::wstring& username,
- const std::wstring& password);
+ void Add(const GURL& origin, const string16& username,
+ const string16& password);
// Remove the entry for |origin| from the cache, if one exists and matches
// |username| and |password|.
- void Remove(const GURL& origin, const std::wstring& username,
- const std::wstring& password);
+ void Remove(const GURL& origin, const string16& username,
+ const string16& password);
private:
typedef std::list<Entry> EntryList;
diff --git a/net/ftp/ftp_auth_cache_unittest.cc b/net/ftp/ftp_auth_cache_unittest.cc
index b23781e..a8c5732 100644
--- a/net/ftp/ftp_auth_cache_unittest.cc
+++ b/net/ftp/ftp_auth_cache_unittest.cc
@@ -1,15 +1,33 @@
-// 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.
#include "net/ftp/ftp_auth_cache.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
using net::FtpAuthCache;
+namespace {
+
+const string16 kBogus(ASCIIToUTF16("bogus"));
+const string16 kOthername(ASCIIToUTF16("othername"));
+const string16 kOtherword(ASCIIToUTF16("otherword"));
+const string16 kPassword(ASCIIToUTF16("password"));
+const string16 kPassword1(ASCIIToUTF16("password1"));
+const string16 kPassword2(ASCIIToUTF16("password2"));
+const string16 kPassword3(ASCIIToUTF16("password3"));
+const string16 kUsername(ASCIIToUTF16("username"));
+const string16 kUsername1(ASCIIToUTF16("username1"));
+const string16 kUsername2(ASCIIToUTF16("username2"));
+const string16 kUsername3(ASCIIToUTF16("username3"));
+
+} // namespace
+
TEST(FtpAuthCacheTest, LookupAddRemove) {
FtpAuthCache cache;
@@ -20,38 +38,38 @@ TEST(FtpAuthCacheTest, LookupAddRemove) {
EXPECT_TRUE(cache.Lookup(origin1) == NULL);
// Add entry for origin1.
- cache.Add(origin1, L"username1", L"password1");
+ cache.Add(origin1, kUsername1, kPassword1);
FtpAuthCache::Entry* entry1 = cache.Lookup(origin1);
ASSERT_TRUE(entry1);
EXPECT_EQ(origin1, entry1->origin);
- EXPECT_EQ(L"username1", entry1->username);
- EXPECT_EQ(L"password1", entry1->password);
+ EXPECT_EQ(kUsername1, entry1->username);
+ EXPECT_EQ(kPassword1, entry1->password);
// Add an entry for origin2.
- cache.Add(origin2, L"username2", L"password2");
+ cache.Add(origin2, kUsername2, kPassword2);
FtpAuthCache::Entry* entry2 = cache.Lookup(origin2);
ASSERT_TRUE(entry2);
EXPECT_EQ(origin2, entry2->origin);
- EXPECT_EQ(L"username2", entry2->username);
- EXPECT_EQ(L"password2", entry2->password);
+ EXPECT_EQ(kUsername2, entry2->username);
+ EXPECT_EQ(kPassword2, entry2->password);
// The original entry1 should still be there.
EXPECT_EQ(entry1, cache.Lookup(origin1));
// Overwrite the entry for origin1.
- cache.Add(origin1, L"username3", L"password3");
+ cache.Add(origin1, kUsername3, kPassword3);
FtpAuthCache::Entry* entry3 = cache.Lookup(origin1);
ASSERT_TRUE(entry3);
EXPECT_EQ(origin1, entry3->origin);
- EXPECT_EQ(L"username3", entry3->username);
- EXPECT_EQ(L"password3", entry3->password);
+ EXPECT_EQ(kUsername3, entry3->username);
+ EXPECT_EQ(kPassword3, entry3->password);
// Remove entry of origin1.
- cache.Remove(origin1, L"username3", L"password3");
+ cache.Remove(origin1, kUsername3, kPassword3);
EXPECT_TRUE(cache.Lookup(origin1) == NULL);
// Remove non-existent entry.
- cache.Remove(origin1, L"username3", L"password3");
+ cache.Remove(origin1, kUsername3, kPassword3);
EXPECT_TRUE(cache.Lookup(origin1) == NULL);
}
@@ -63,8 +81,8 @@ TEST(FtpAuthCacheTest, LookupWithPort) {
GURL origin1("ftp://foo:80");
GURL origin2("ftp://foo:21");
- cache.Add(origin1, L"username", L"password");
- cache.Add(origin2, L"username", L"password");
+ cache.Add(origin1, kUsername, kPassword);
+ cache.Add(origin2, kUsername, kPassword);
EXPECT_NE(cache.Lookup(origin1), cache.Lookup(origin2));
}
@@ -77,7 +95,7 @@ TEST(FtpAuthCacheTest, NormalizedKey) {
FtpAuthCache cache;
// Add.
- cache.Add(GURL("ftp://HoSt:21"), L"username", L"password");
+ cache.Add(GURL("ftp://HoSt:21"), kUsername, kPassword);
// Lookup.
FtpAuthCache::Entry* entry1 = cache.Lookup(GURL("ftp://HoSt:21"));
@@ -86,51 +104,53 @@ TEST(FtpAuthCacheTest, NormalizedKey) {
EXPECT_EQ(entry1, cache.Lookup(GURL("ftp://host")));
// Overwrite.
- cache.Add(GURL("ftp://host"), L"othername", L"otherword");
+ cache.Add(GURL("ftp://host"), kOthername, kOtherword);
FtpAuthCache::Entry* entry2 = cache.Lookup(GURL("ftp://HoSt:21"));
ASSERT_TRUE(entry2);
EXPECT_EQ(GURL("ftp://host"), entry2->origin);
- EXPECT_EQ(L"othername", entry2->username);
- EXPECT_EQ(L"otherword", entry2->password);
+ EXPECT_EQ(kOthername, entry2->username);
+ EXPECT_EQ(kOtherword, entry2->password);
// Remove
- cache.Remove(GURL("ftp://HOsT"), L"othername", L"otherword");
+ cache.Remove(GURL("ftp://HOsT"), kOthername, kOtherword);
EXPECT_TRUE(cache.Lookup(GURL("ftp://host")) == NULL);
}
TEST(FtpAuthCacheTest, OnlyRemoveMatching) {
FtpAuthCache cache;
- cache.Add(GURL("ftp://host"), L"username", L"password");
+ cache.Add(GURL("ftp://host"), kUsername, kPassword);
EXPECT_TRUE(cache.Lookup(GURL("ftp://host")));
// Auth data doesn't match, shouldn't remove.
- cache.Remove(GURL("ftp://host"), L"bogus", L"bogus");
+ cache.Remove(GURL("ftp://host"), kBogus, kBogus);
EXPECT_TRUE(cache.Lookup(GURL("ftp://host")));
// Auth data matches, should remove.
- cache.Remove(GURL("ftp://host"), L"username", L"password");
+ cache.Remove(GURL("ftp://host"), kUsername, kPassword);
EXPECT_TRUE(cache.Lookup(GURL("ftp://host")) == NULL);
}
TEST(FtpAuthCacheTest, EvictOldEntries) {
FtpAuthCache cache;
- for (size_t i = 0; i < FtpAuthCache::kMaxEntries; i++)
- cache.Add(GURL("ftp://host" + IntToString(i)), L"username", L"password");
+ for (size_t i = 0; i < FtpAuthCache::kMaxEntries; i++) {
+ cache.Add(GURL("ftp://host" + base::IntToString(i)),
+ kUsername, kPassword);
+ }
// No entries should be evicted before reaching the limit.
for (size_t i = 0; i < FtpAuthCache::kMaxEntries; i++) {
- EXPECT_TRUE(cache.Lookup(GURL("ftp://host" + IntToString(i))));
+ EXPECT_TRUE(cache.Lookup(GURL("ftp://host" + base::IntToString(i))));
}
// Adding one entry should cause eviction of the first entry.
- cache.Add(GURL("ftp://last_host"), L"username", L"password");
+ cache.Add(GURL("ftp://last_host"), kUsername, kPassword);
EXPECT_TRUE(cache.Lookup(GURL("ftp://host0")) == NULL);
// Remaining entries should not get evicted.
for (size_t i = 1; i < FtpAuthCache::kMaxEntries; i++) {
- EXPECT_TRUE(cache.Lookup(GURL("ftp://host" + IntToString(i))));
+ EXPECT_TRUE(cache.Lookup(GURL("ftp://host" + base::IntToString(i))));
}
EXPECT_TRUE(cache.Lookup(GURL("ftp://last_host")));
}
diff --git a/net/ftp/ftp_ctrl_response_buffer.cc b/net/ftp/ftp_ctrl_response_buffer.cc
index 8ea58cc..c9ee5dd 100644
--- a/net/ftp/ftp_ctrl_response_buffer.cc
+++ b/net/ftp/ftp_ctrl_response_buffer.cc
@@ -5,7 +5,8 @@
#include "net/ftp/ftp_ctrl_response_buffer.h"
#include "base/logging.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+//#include "base/string_util.h"
#include "net/base/net_errors.h"
namespace net {
@@ -69,7 +70,7 @@ FtpCtrlResponseBuffer::ParsedLine FtpCtrlResponseBuffer::ParseLine(
ParsedLine result;
if (line.length() >= 3) {
- if (StringToInt(line.substr(0, 3), &result.status_code))
+ if (base::StringToInt(line.substr(0, 3), &result.status_code))
result.has_status_code = (100 <= result.status_code &&
result.status_code <= 599);
if (result.has_status_code && line.length() >= 4 && line[3] == ' ') {
diff --git a/net/ftp/ftp_ctrl_response_buffer.h b/net/ftp/ftp_ctrl_response_buffer.h
index 6ea34cb..b98f494 100644
--- a/net/ftp/ftp_ctrl_response_buffer.h
+++ b/net/ftp/ftp_ctrl_response_buffer.h
@@ -1,9 +1,11 @@
-// Copyright (c) 2009 The Chromium 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.
+
#ifndef NET_FTP_FTP_CTRL_RESPONSE_BUFFER_H_
#define NET_FTP_FTP_CTRL_RESPONSE_BUFFER_H_
+#pragma once
#include <queue>
#include <string>
@@ -24,8 +26,7 @@ struct FtpCtrlResponse {
class FtpCtrlResponseBuffer {
public:
- FtpCtrlResponseBuffer() : multiline_(false) {
- }
+ FtpCtrlResponseBuffer() : multiline_(false) {}
// Called when data is received from the control socket. Returns error code.
int ConsumeData(const char* data, int data_length);
diff --git a/net/ftp/ftp_directory_listing_buffer.h b/net/ftp/ftp_directory_listing_buffer.h
index 4123cf0..0a25fff 100644
--- a/net/ftp/ftp_directory_listing_buffer.h
+++ b/net/ftp/ftp_directory_listing_buffer.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_BUFFER_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_BUFFER_H_
+#pragma once
#include <deque>
#include <set>
diff --git a/net/ftp/ftp_directory_listing_buffer_unittest.cc b/net/ftp/ftp_directory_listing_buffer_unittest.cc
index c3c55d0..ff7aedf 100644
--- a/net/ftp/ftp_directory_listing_buffer_unittest.cc
+++ b/net/ftp/ftp_directory_listing_buffer_unittest.cc
@@ -7,6 +7,7 @@
#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/path_service.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -60,7 +61,7 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
&mock_current_time));
for (size_t i = 0; i < arraysize(test_files); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, test_files[i]));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i, test_files[i]));
net::FtpDirectoryListingBuffer buffer(mock_current_time);
@@ -86,15 +87,17 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
for (size_t i = 0; i < lines.size() / 8; i++) {
std::string type(lines[8 * i]);
std::string name(lines[8 * i + 1]);
- int64 size = StringToInt64(lines[8 * i + 2]);
+ int64 size;
+ base::StringToInt64(lines[8 * i + 2], &size);
- SCOPED_TRACE(StringPrintf("Filename: %s", name.c_str()));
+ SCOPED_TRACE(base::StringPrintf("Filename: %s", name.c_str()));
- int year = StringToInt(lines[8 * i + 3]);
- int month = StringToInt(lines[8 * i + 4]);
- int day_of_month = StringToInt(lines[8 * i + 5]);
- int hour = StringToInt(lines[8 * i + 6]);
- int minute = StringToInt(lines[8 * i + 7]);
+ int year, month, day_of_month, hour, minute;
+ base::StringToInt(lines[8 * i + 3], &year);
+ base::StringToInt(lines[8 * i + 4], &month);
+ base::StringToInt(lines[8 * i + 5], &day_of_month);
+ base::StringToInt(lines[8 * i + 6], &hour);
+ base::StringToInt(lines[8 * i + 7], &minute);
ASSERT_TRUE(buffer.EntryAvailable());
net::FtpDirectoryListingEntry entry = buffer.PopEntry();
diff --git a/net/ftp/ftp_directory_listing_parser.h b/net/ftp/ftp_directory_listing_parser.h
index 7ba895a..6373312 100644
--- a/net/ftp/ftp_directory_listing_parser.h
+++ b/net/ftp/ftp_directory_listing_parser.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_H_
+#pragma once
#include "base/basictypes.h"
#include "base/string16.h"
diff --git a/net/ftp/ftp_directory_listing_parser_ls.cc b/net/ftp/ftp_directory_listing_parser_ls.cc
index 55f7844..038af11 100644
--- a/net/ftp/ftp_directory_listing_parser_ls.cc
+++ b/net/ftp/ftp_directory_listing_parser_ls.cc
@@ -1,12 +1,15 @@
-// Copyright (c) 2009 The Chromium 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 "net/ftp/ftp_directory_listing_parser_ls.h"
#include <vector>
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_util.h"
namespace {
@@ -107,7 +110,7 @@ bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) {
received_total_line_ = true;
int total_number;
- if (!StringToInt(columns[1], &total_number))
+ if (!base::StringToInt(columns[1], &total_number))
return false;
if (total_number < 0)
return false;
@@ -137,7 +140,7 @@ bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) {
entry.type = FtpDirectoryListingEntry::FILE;
}
- if (!StringToInt64(columns[2 + column_offset], &entry.size))
+ if (!base::StringToInt64(columns[2 + column_offset], &entry.size))
return false;
if (entry.size < 0)
return false;
@@ -155,9 +158,11 @@ bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) {
entry.name = FtpUtil::GetStringPartAfterColumns(line, 6 + column_offset);
if (entry.type == FtpDirectoryListingEntry::SYMLINK) {
string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> "));
- if (pos == string16::npos)
- return false;
- entry.name = entry.name.substr(0, pos);
+
+ // We don't require the " -> " to be present. Some FTP servers don't send
+ // the symlink target, possibly for security reasons.
+ if (pos != string16::npos)
+ entry.name = entry.name.substr(0, pos);
}
entries_.push(entry);
diff --git a/net/ftp/ftp_directory_listing_parser_ls.h b/net/ftp/ftp_directory_listing_parser_ls.h
index 0d52791..54856c1 100644
--- a/net/ftp/ftp_directory_listing_parser_ls.h
+++ b/net/ftp/ftp_directory_listing_parser_ls.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_LS_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_LS_H_
+#pragma once
#include <queue>
diff --git a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc b/net/ftp/ftp_directory_listing_parser_ls_unittest.cc
index 608e0e2..2b57b40 100644
--- a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_ls_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.
@@ -6,6 +6,7 @@
#include "base/format_macros.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/ftp/ftp_directory_listing_parser_ls.h"
namespace {
@@ -45,6 +46,12 @@ TEST_F(FtpDirectoryListingParserLsTest, Good) {
{ "d-wx-wx-wt+ 4 ftp 989 512 Dec 8 15:54 incoming",
net::FtpDirectoryListingEntry::DIRECTORY, "incoming", -1,
1993, 12, 8, 15, 54 },
+ { "drwxrwxrwx 1 owner group 0 Sep 13 0:30 audio",
+ net::FtpDirectoryListingEntry::DIRECTORY, "audio", -1,
+ 1994, 9, 13, 0, 30 },
+ { "lrwxrwxrwx 1 0 0 26 Sep 18 2008 pub",
+ net::FtpDirectoryListingEntry::SYMLINK, "pub", -1,
+ 2008, 9, 18, 0, 0 },
// Tests for the wu-ftpd variant:
{ "drwxr-xr-x 2 sys 512 Mar 27 2009 pub",
@@ -74,7 +81,8 @@ TEST_F(FtpDirectoryListingParserLsTest, Good) {
2006, 7, 17, 0, 0 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, good_cases[i].input));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ good_cases[i].input));
net::FtpDirectoryListingParserLs parser(mock_current_time);
RunSingleLineTestCase(&parser, good_cases[i]);
@@ -100,6 +108,7 @@ TEST_F(FtpDirectoryListingParserLsTest, Bad) {
"qrwwr--r-- 1 ftp ftp 528 Nov 01 2007 README",
"-rw-r--r-- 1 ftp ftp -528 Nov 01 2007 README",
"-rw-r--r-- 1 ftp ftp 528 Foo 01 2007 README",
+ "drwxrwxrwx 1 owner group 0 Sep 13 0:3 audio",
"d-wx-wx-wt++ 4 ftp 989 512 Dec 8 15:54 incoming",
"d-wx-wx-wt$ 4 ftp 989 512 Dec 8 15:54 incoming",
diff --git a/net/ftp/ftp_directory_listing_parser_mlsd.cc b/net/ftp/ftp_directory_listing_parser_mlsd.cc
index 7715dd3..6d49634 100644
--- a/net/ftp/ftp_directory_listing_parser_mlsd.cc
+++ b/net/ftp/ftp_directory_listing_parser_mlsd.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// Copyright (c) 2010 The Chromium 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,8 @@
#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"
@@ -26,15 +28,15 @@ bool MlsdDateListingToTime(const string16& text, base::Time* time) {
if (text.length() < 14)
return false;
- if (!StringToInt(text.substr(0, 4), &time_exploded.year))
+ if (!base::StringToInt(text.substr(0, 4), &time_exploded.year))
return false;
- if (!StringToInt(text.substr(4, 2), &time_exploded.month))
+ if (!base::StringToInt(text.substr(4, 2), &time_exploded.month))
return false;
- if (!StringToInt(text.substr(6, 2), &time_exploded.day_of_month))
+ if (!base::StringToInt(text.substr(6, 2), &time_exploded.day_of_month))
return false;
- if (!StringToInt(text.substr(8, 2), &time_exploded.hour))
+ if (!base::StringToInt(text.substr(8, 2), &time_exploded.hour))
return false;
- if (!StringToInt(text.substr(10, 2), &time_exploded.minute))
+ if (!base::StringToInt(text.substr(10, 2), &time_exploded.minute))
return false;
// We don't know the time zone of the server, so just use local time.
@@ -95,7 +97,7 @@ bool FtpDirectoryListingParserMlsd::ConsumeLine(const string16& line) {
entry.type = FtpDirectoryListingEntry::FILE;
if (!ContainsKey(facts, "size"))
return false;
- if (!StringToInt64(facts["size"], &entry.size))
+ if (!base::StringToInt64(facts["size"], &entry.size))
return false;
} else {
// Ignore other types of entries. They are either not interesting for us
diff --git a/net/ftp/ftp_directory_listing_parser_mlsd.h b/net/ftp/ftp_directory_listing_parser_mlsd.h
index 8d0e3b7..94df607 100644
--- a/net/ftp/ftp_directory_listing_parser_mlsd.h
+++ b/net/ftp/ftp_directory_listing_parser_mlsd.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_MLSD_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_MLSD_H_
+#pragma once
#include <queue>
diff --git a/net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc b/net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc
index 9663664..1a01f27 100644
--- a/net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_mlsd_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.
@@ -6,6 +6,7 @@
#include "base/format_macros.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/ftp/ftp_directory_listing_parser_mlsd.h"
namespace {
@@ -31,7 +32,8 @@ TEST_F(FtpDirectoryListingParserMlsdTest, Good) {
2001, 4, 14, 15, 52 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, good_cases[i].input));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ good_cases[i].input));
net::FtpDirectoryListingParserMlsd parser;
RunSingleLineTestCase(&parser, good_cases[i]);
diff --git a/net/ftp/ftp_directory_listing_parser_netware.cc b/net/ftp/ftp_directory_listing_parser_netware.cc
index 60c6c6a..40f6505 100644
--- a/net/ftp/ftp_directory_listing_parser_netware.cc
+++ b/net/ftp/ftp_directory_listing_parser_netware.cc
@@ -1,12 +1,15 @@
-// Copyright (c) 2009 The Chromium 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 "net/ftp/ftp_directory_listing_parser_netware.h"
#include <vector>
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_util.h"
namespace {
@@ -68,7 +71,7 @@ bool FtpDirectoryListingParserNetware::ConsumeLine(const string16& line) {
if (!LooksLikeNetwarePermissionsListing(columns[1]))
return false;
- if (!StringToInt64(columns[3], &entry.size))
+ if (!base::StringToInt64(columns[3], &entry.size))
return false;
if (entry.size < 0)
return false;
diff --git a/net/ftp/ftp_directory_listing_parser_netware.h b/net/ftp/ftp_directory_listing_parser_netware.h
index aef490a..e05b55d 100644
--- a/net/ftp/ftp_directory_listing_parser_netware.h
+++ b/net/ftp/ftp_directory_listing_parser_netware.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_NETWARE_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_NETWARE_H_
+#pragma once
#include <queue>
diff --git a/net/ftp/ftp_directory_listing_parser_netware_unittest.cc b/net/ftp/ftp_directory_listing_parser_netware_unittest.cc
index 6570846..f5e4a35 100644
--- a/net/ftp/ftp_directory_listing_parser_netware_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_netware_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.
@@ -6,6 +6,7 @@
#include "base/format_macros.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_directory_listing_parser_netware.h"
@@ -27,7 +28,8 @@ TEST_F(FtpDirectoryListingParserNetwareTest, Good) {
1994, 11, 11, 18, 25 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, good_cases[i].input));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ good_cases[i].input));
net::FtpDirectoryListingParserNetware parser(mock_current_time);
// The parser requires a "total n" like before accepting regular input.
diff --git a/net/ftp/ftp_directory_listing_parser_unittest.h b/net/ftp/ftp_directory_listing_parser_unittest.h
index 90670fd..c31546e 100644
--- a/net/ftp/ftp_directory_listing_parser_unittest.h
+++ b/net/ftp/ftp_directory_listing_parser_unittest.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_UNITTEST_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_UNITTEST_H_
+#pragma once
#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_directory_listing_parser.h"
@@ -26,8 +27,7 @@ class FtpDirectoryListingParserTest : public testing::Test {
};
protected:
- FtpDirectoryListingParserTest() {
- }
+ FtpDirectoryListingParserTest() {}
void RunSingleLineTestCase(FtpDirectoryListingParser* parser,
const SingleLineTestData& test_case) {
diff --git a/net/ftp/ftp_directory_listing_parser_vms.cc b/net/ftp/ftp_directory_listing_parser_vms.cc
index f8d3fbb..7148aee 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.cc
+++ b/net/ftp/ftp_directory_listing_parser_vms.cc
@@ -1,11 +1,13 @@
-// Copyright (c) 2009 The Chromium 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 "net/ftp/ftp_directory_listing_parser_vms.h"
#include <vector>
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_util.h"
@@ -23,7 +25,7 @@ bool ParseVmsFilename(const string16& raw_filename, string16* parsed_filename,
if (listing_parts.size() != 2)
return false;
int version_number;
- if (!StringToInt(listing_parts[1], &version_number))
+ if (!base::StringToInt(listing_parts[1], &version_number))
return false;
if (version_number < 0)
return false;
@@ -52,7 +54,7 @@ bool ParseVmsFilesize(const string16& input, int64* size) {
// best information we have.
const int kBlockSize = 512;
- if (StringToInt64(input, size)) {
+ if (base::StringToInt64(input, size)) {
*size *= kBlockSize;
return true;
}
@@ -63,9 +65,9 @@ bool ParseVmsFilesize(const string16& input, int64* size) {
return false;
int64 blocks_used, blocks_allocated;
- if (!StringToInt64(parts[0], &blocks_used))
+ if (!base::StringToInt64(parts[0], &blocks_used))
return false;
- if (!StringToInt64(parts[1], &blocks_allocated))
+ if (!base::StringToInt64(parts[1], &blocks_allocated))
return false;
if (blocks_used > blocks_allocated)
return false;
@@ -126,12 +128,12 @@ bool VmsDateListingToTime(const std::vector<string16>& columns,
SplitString(columns[1], '-', &date_parts);
if (date_parts.size() != 3)
return false;
- if (!StringToInt(date_parts[0], &time_exploded.day_of_month))
+ if (!base::StringToInt(date_parts[0], &time_exploded.day_of_month))
return false;
if (!net::FtpUtil::ThreeLetterMonthToNumber(date_parts[1],
&time_exploded.month))
return false;
- if (!StringToInt(date_parts[2], &time_exploded.year))
+ if (!base::StringToInt(date_parts[2], &time_exploded.year))
return false;
// Time can be in format HH:MM, HH:MM:SS, or HH:MM:SS.mm. Try to recognize the
@@ -147,9 +149,9 @@ bool VmsDateListingToTime(const std::vector<string16>& columns,
SplitString(time_column, ':', &time_parts);
if (time_parts.size() != 2)
return false;
- if (!StringToInt(time_parts[0], &time_exploded.hour))
+ if (!base::StringToInt(time_parts[0], &time_exploded.hour))
return false;
- if (!StringToInt(time_parts[1], &time_exploded.minute))
+ if (!base::StringToInt(time_parts[1], &time_exploded.minute))
return false;
// We don't know the time zone of the server, so just use local time.
diff --git a/net/ftp/ftp_directory_listing_parser_vms.h b/net/ftp/ftp_directory_listing_parser_vms.h
index 1512b63..1b1f082 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.h
+++ b/net/ftp/ftp_directory_listing_parser_vms.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_VMS_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_VMS_H_
+#pragma once
#include <queue>
diff --git a/net/ftp/ftp_directory_listing_parser_vms_unittest.cc b/net/ftp/ftp_directory_listing_parser_vms_unittest.cc
index 363c99c..ab5366f 100644
--- a/net/ftp/ftp_directory_listing_parser_vms_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_vms_unittest.cc
@@ -1,11 +1,14 @@
-// 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.
#include "net/ftp/ftp_directory_listing_parser_unittest.h"
#include "base/format_macros.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "net/ftp/ftp_directory_listing_parser_vms.h"
namespace {
@@ -43,7 +46,8 @@ TEST_F(FtpDirectoryListingParserVmsTest, Good) {
2005, 3, 12, 8, 44 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, good_cases[i].input));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ good_cases[i].input));
net::FtpDirectoryListingParserVms parser;
ASSERT_TRUE(
@@ -99,7 +103,7 @@ TEST_F(FtpDirectoryListingParserVmsTest, Bad) {
"Directory ROOT|X.TXT;2 1 12-MAR-2005 08:44:57 [X] (RWED,RRWWEEDD,RE,RE)",
};
for (size_t i = 0; i < arraysize(bad_cases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, bad_cases[i]));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i, bad_cases[i]));
std::vector<std::string> lines;
SplitString(bad_cases[i], '|', &lines);
diff --git a/net/ftp/ftp_directory_listing_parser_windows.cc b/net/ftp/ftp_directory_listing_parser_windows.cc
index 85ae6d5..2ff3cd2 100644
--- a/net/ftp/ftp_directory_listing_parser_windows.cc
+++ b/net/ftp/ftp_directory_listing_parser_windows.cc
@@ -1,11 +1,13 @@
-// Copyright (c) 2009 The Chromium 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 "net/ftp/ftp_directory_listing_parser_windows.h"
#include <vector>
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "net/ftp/ftp_util.h"
@@ -22,11 +24,11 @@ bool WindowsDateListingToTime(const std::vector<string16>& columns,
SplitString(columns[0], '-', &date_parts);
if (date_parts.size() != 3)
return false;
- if (!StringToInt(date_parts[0], &time_exploded.month))
+ if (!base::StringToInt(date_parts[0], &time_exploded.month))
return false;
- if (!StringToInt(date_parts[1], &time_exploded.day_of_month))
+ if (!base::StringToInt(date_parts[1], &time_exploded.day_of_month))
return false;
- if (!StringToInt(date_parts[2], &time_exploded.year))
+ if (!base::StringToInt(date_parts[2], &time_exploded.year))
return false;
if (time_exploded.year < 0)
return false;
@@ -44,15 +46,22 @@ bool WindowsDateListingToTime(const std::vector<string16>& columns,
SplitString(columns[1].substr(0, 5), ':', &time_parts);
if (time_parts.size() != 2)
return false;
- if (!StringToInt(time_parts[0], &time_exploded.hour))
+ if (!base::StringToInt(time_parts[0], &time_exploded.hour))
return false;
- if (!StringToInt(time_parts[1], &time_exploded.minute))
+ if (!base::StringToInt(time_parts[1], &time_exploded.minute))
+ return false;
+ if (!time_exploded.HasValidValues())
return false;
string16 am_or_pm(columns[1].substr(5, 2));
- if (EqualsASCII(am_or_pm, "PM"))
- time_exploded.hour += 12;
- else if (!EqualsASCII(am_or_pm, "AM"))
+ if (EqualsASCII(am_or_pm, "PM")) {
+ if (time_exploded.hour < 12)
+ time_exploded.hour += 12;
+ } else if (EqualsASCII(am_or_pm, "AM")) {
+ if (time_exploded.hour == 12)
+ time_exploded.hour = 0;
+ } else {
return false;
+ }
// We don't know the time zone of the server, so just use local time.
*time = base::Time::FromLocalExploded(time_exploded);
@@ -84,7 +93,7 @@ bool FtpDirectoryListingParserWindows::ConsumeLine(const string16& line) {
entry.size = -1;
} else {
entry.type = FtpDirectoryListingEntry::FILE;
- if (!StringToInt64(columns[2], &entry.size))
+ if (!base::StringToInt64(columns[2], &entry.size))
return false;
if (entry.size < 0)
return false;
diff --git a/net/ftp/ftp_directory_listing_parser_windows.h b/net/ftp/ftp_directory_listing_parser_windows.h
index da58370..cf869c3 100644
--- a/net/ftp/ftp_directory_listing_parser_windows.h
+++ b/net/ftp/ftp_directory_listing_parser_windows.h
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium 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.
#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_WINDOWS_H_
#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_WINDOWS_H_
+#pragma once
#include <queue>
diff --git a/net/ftp/ftp_directory_listing_parser_windows_unittest.cc b/net/ftp/ftp_directory_listing_parser_windows_unittest.cc
index a768d05..c53cfd1 100644
--- a/net/ftp/ftp_directory_listing_parser_windows_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_windows_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.
@@ -6,6 +6,7 @@
#include "base/format_macros.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/ftp/ftp_directory_listing_parser_windows.h"
namespace {
@@ -50,9 +51,16 @@ TEST_F(FtpDirectoryListingParserWindowsTest, Good) {
{ "11-02-09 05:32PM <DIR> My Directory",
net::FtpDirectoryListingEntry::DIRECTORY, "My Directory", -1,
2009, 11, 2, 17, 32 },
+ { "12-25-10 12:00AM <DIR> Christmas Midnight",
+ net::FtpDirectoryListingEntry::DIRECTORY, "Christmas Midnight", -1,
+ 2010, 12, 25, 0, 0 },
+ { "12-25-10 12:00PM <DIR> Christmas Midday",
+ net::FtpDirectoryListingEntry::DIRECTORY, "Christmas Midday", -1,
+ 2010, 12, 25, 12, 0 },
};
for (size_t i = 0; i < arraysize(good_cases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, good_cases[i].input));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ good_cases[i].input));
net::FtpDirectoryListingParserWindows parser;
RunSingleLineTestCase(&parser, good_cases[i]);
@@ -68,6 +76,11 @@ TEST_F(FtpDirectoryListingParserWindowsTest, Bad) {
"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 months out of range",
+ "12-99-10 12:00AM 0 days out of range",
+ "12-25-10 99:00AM 0 hours out of range",
+ "12-25-10 12:99AM 0 minutes out of range",
+ "12-25-10 12:00ZM 0 what does ZM mean",
};
for (size_t i = 0; i < arraysize(bad_cases); i++) {
net::FtpDirectoryListingParserWindows parser;
diff --git a/net/ftp/ftp_network_layer.h b/net/ftp/ftp_network_layer.h
index 2d37eae..a4191f9 100644
--- a/net/ftp/ftp_network_layer.h
+++ b/net/ftp/ftp_network_layer.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_FTP_FTP_NETWORK_LAYER_H_
#define NET_FTP_FTP_NETWORK_LAYER_H_
+#pragma once
#include "base/ref_counted.h"
#include "net/ftp/ftp_transaction_factory.h"
@@ -11,7 +12,6 @@
namespace net {
class FtpNetworkSession;
-class FtpAuthCache;
class HostResolver;
class FtpNetworkLayer : public FtpTransactionFactory {
diff --git a/net/ftp/ftp_network_session.h b/net/ftp/ftp_network_session.h
index 3c29a85..775bd01 100644
--- a/net/ftp/ftp_network_session.h
+++ b/net/ftp/ftp_network_session.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_FTP_FTP_NETWORK_SESSION_H_
#define NET_FTP_FTP_NETWORK_SESSION_H_
+#pragma once
#include "base/ref_counted.h"
#include "net/ftp/ftp_auth_cache.h"
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index f6b7203..8812843 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -6,6 +6,7 @@
#include "base/compiler_specific.h"
#include "base/histogram.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "net/base/connection_type_histograms.h"
@@ -212,8 +213,8 @@ int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
if (request_->url.has_username()) {
GetIdentityFromURL(request_->url, &username_, &password_);
} else {
- username_ = L"anonymous";
- password_ = L"chrome@example.com";
+ username_ = ASCIIToUTF16("anonymous");
+ password_ = ASCIIToUTF16("chrome@example.com");
}
DetectTypecode();
@@ -234,8 +235,8 @@ int FtpNetworkTransaction::Stop(int error) {
return OK;
}
-int FtpNetworkTransaction::RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
+int FtpNetworkTransaction::RestartWithAuth(const string16& username,
+ const string16& password,
CompletionCallback* callback) {
ResetStateForRestart();
@@ -610,13 +611,7 @@ int FtpNetworkTransaction::DoLoop(int result) {
int FtpNetworkTransaction::DoCtrlResolveHost() {
next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE;
- std::string host;
- int port;
-
- host = request_->url.HostNoBrackets();
- port = request_->url.EffectiveIntPort();
-
- HostResolver::RequestInfo info(host, port);
+ HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url));
// No known referrer.
return resolver_.Resolve(info, &addresses_, &io_callback_, net_log_);
}
@@ -630,7 +625,7 @@ int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) {
int FtpNetworkTransaction::DoCtrlConnect() {
next_state_ = STATE_CTRL_CONNECT_COMPLETE;
ctrl_socket_.reset(socket_factory_->CreateTCPClientSocket(
- addresses_, net_log_.net_log()));
+ addresses_, net_log_.net_log(), net_log_.source()));
return ctrl_socket_->Connect(&io_callback_);
}
@@ -653,7 +648,7 @@ int FtpNetworkTransaction::DoCtrlReadComplete(int result) {
// Some servers (for example Pure-FTPd) apparently close the control
// connection when anonymous login is not permitted. For more details
// see http://crbug.com/25023.
- if (command_sent_ == COMMAND_USER && username_ == L"anonymous")
+ if (command_sent_ == COMMAND_USER && username_ == ASCIIToUTF16("anonymous"))
response_.needs_auth = true;
return Stop(ERR_EMPTY_RESPONSE);
}
@@ -700,7 +695,7 @@ int FtpNetworkTransaction::DoCtrlWriteComplete(int result) {
// USER Command.
int FtpNetworkTransaction::DoCtrlWriteUSER() {
- std::string command = "USER " + WideToUTF8(username_);
+ std::string command = "USER " + UTF16ToUTF8(username_);
if (!IsValidFTPCommandString(command))
return Stop(ERR_MALFORMED_IDENTITY);
@@ -732,7 +727,7 @@ int FtpNetworkTransaction::ProcessResponseUSER(
// PASS command.
int FtpNetworkTransaction::DoCtrlWritePASS() {
- std::string command = "PASS " + WideToUTF8(password_);
+ std::string command = "PASS " + UTF16ToUTF8(password_);
if (!IsValidFTPCommandString(command))
return Stop(ERR_MALFORMED_IDENTITY);
@@ -978,7 +973,7 @@ int FtpNetworkTransaction::ProcessResponseSIZE(
if (response.lines.size() != 1)
return Stop(ERR_INVALID_RESPONSE);
int64 size;
- if (!StringToInt64(response.lines[0], &size))
+ if (!base::StringToInt64(response.lines[0], &size))
return Stop(ERR_INVALID_RESPONSE);
if (size < 0)
return Stop(ERR_INVALID_RESPONSE);
@@ -1182,12 +1177,27 @@ int FtpNetworkTransaction::DoDataConnect() {
return Stop(rv);
data_address.SetPort(data_connection_port_);
data_socket_.reset(socket_factory_->CreateTCPClientSocket(
- data_address, net_log_.net_log()));
+ data_address, net_log_.net_log(), net_log_.source()));
return data_socket_->Connect(&io_callback_);
}
int FtpNetworkTransaction::DoDataConnectComplete(int result) {
+ if (result == ERR_CONNECTION_TIMED_OUT && use_epsv_) {
+ // It's possible we hit a broken server, sadly. Fall back to PASV.
+ // TODO(phajdan.jr): remember it for future transactions with this server.
+ // TODO(phajdan.jr): write a test for this code path.
+ use_epsv_ = false;
+ next_state_ = STATE_CTRL_WRITE_PASV;
+ return OK;
+ }
+
+ // Only record the connection error after we've applied all our fallbacks.
+ // We want to capture the final error, one we're not going to recover from.
RecordDataConnectionError(result);
+
+ if (result != OK)
+ return Stop(result);
+
next_state_ = STATE_CTRL_WRITE_SIZE;
return OK;
}
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index 31c38c7..5bad335 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -4,14 +4,14 @@
#ifndef NET_FTP_FTP_NETWORK_TRANSACTION_H_
#define NET_FTP_FTP_NETWORK_TRANSACTION_H_
+#pragma once
#include <string>
-#include <queue>
#include <utility>
-#include <vector>
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "net/base/address_list.h"
#include "net/base/host_resolver.h"
#include "net/base/net_log.h"
@@ -36,8 +36,8 @@ class FtpNetworkTransaction : public FtpTransaction {
CompletionCallback* callback,
const BoundNetLog& net_log);
virtual int Stop(int error);
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
+ virtual int RestartWithAuth(const string16& username,
+ const string16& password,
CompletionCallback* callback);
virtual int RestartIgnoringLastError(CompletionCallback* callback);
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
@@ -200,10 +200,8 @@ class FtpNetworkTransaction : public FtpTransaction {
// EPSV fail, we fall back to PASV for the duration of connection.
bool use_epsv_;
- // We get username and password as wstrings in RestartWithAuth, so they are
- // also kept as wstrings here.
- std::wstring username_;
- std::wstring password_;
+ string16 username_;
+ string16 password_;
// Current directory on the remote server, as returned by last PWD command,
// with any trailing slash removed.
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc
index b7cc29d..8b877a9 100644
--- a/net/ftp/ftp_network_transaction_unittest.cc
+++ b/net/ftp/ftp_network_transaction_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.
@@ -7,6 +7,8 @@
#include "build/build_config.h"
#include "base/ref_counted.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/base/io_buffer.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_util.h"
@@ -81,6 +83,8 @@ class FtpSocketDataProvider : public DynamicSocketDataProvider {
return Verify("EPSV\r\n", data, PRE_SIZE,
"227 Entering Extended Passive Mode (|||31744|)\r\n");
case PRE_NOPASV:
+ // Use unallocated 599 FTP error code to make sure it falls into the
+ // generic ERR_FTP_FAILED bucket.
return Verify("PASV\r\n", data, PRE_QUIT,
"599 fail\r\n");
case PRE_QUIT:
@@ -473,6 +477,8 @@ class FtpSocketDataProviderFileDownloadInvalidResponse
return MockWriteResult(true, data.length());
switch (state()) {
case PRE_SIZE:
+ // Use unallocated 599 FTP error code to make sure it falls into the
+ // generic ERR_FTP_FAILED bucket.
return Verify("SIZE /file\r\n", data, PRE_QUIT,
"599 Evil Response\r\n"
"599 More Evil\r\n");
@@ -649,13 +655,10 @@ class FtpNetworkTransactionTest : public PlatformTest {
MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
MockRead(mock_data.c_str()),
};
- // For compatibility with FileZilla, the transaction code will use two data
- // sockets for directory requests. For more info see http://crbug.com/25316.
- StaticSocketDataProvider data1(data_reads, arraysize(data_reads), NULL, 0);
- StaticSocketDataProvider data2(data_reads, arraysize(data_reads), NULL, 0);
+ StaticSocketDataProvider data_socket(data_reads, arraysize(data_reads),
+ NULL, 0);
mock_socket_factory_.AddSocketDataProvider(ctrl_socket);
- mock_socket_factory_.AddSocketDataProvider(&data1);
- mock_socket_factory_.AddSocketDataProvider(&data2);
+ mock_socket_factory_.AddSocketDataProvider(&data_socket);
FtpRequestInfo request_info = GetRequestInfo(request);
EXPECT_EQ(LOAD_STATE_IDLE, transaction_.GetLoadState());
ASSERT_EQ(ERR_IO_PENDING,
@@ -1044,9 +1047,10 @@ TEST_F(FtpNetworkTransactionTest, EvilRestartUser) {
StaticSocketDataProvider ctrl_socket2(ctrl_reads, arraysize(ctrl_reads),
ctrl_writes, arraysize(ctrl_writes));
mock_socket_factory_.AddSocketDataProvider(&ctrl_socket2);
- ASSERT_EQ(ERR_IO_PENDING, transaction_.RestartWithAuth(L"foo\nownz0red",
- L"innocent",
- &callback_));
+ ASSERT_EQ(ERR_IO_PENDING,
+ transaction_.RestartWithAuth(ASCIIToUTF16("foo\nownz0red"),
+ ASCIIToUTF16("innocent"),
+ &callback_));
EXPECT_EQ(ERR_MALFORMED_IDENTITY, callback_.WaitForResult());
}
@@ -1076,9 +1080,10 @@ TEST_F(FtpNetworkTransactionTest, EvilRestartPassword) {
StaticSocketDataProvider ctrl_socket2(ctrl_reads, arraysize(ctrl_reads),
ctrl_writes, arraysize(ctrl_writes));
mock_socket_factory_.AddSocketDataProvider(&ctrl_socket2);
- ASSERT_EQ(ERR_IO_PENDING, transaction_.RestartWithAuth(L"innocent",
- L"foo\nownz0red",
- &callback_));
+ ASSERT_EQ(ERR_IO_PENDING,
+ transaction_.RestartWithAuth(ASCIIToUTF16("innocent"),
+ ASCIIToUTF16("foo\nownz0red"),
+ &callback_));
EXPECT_EQ(ERR_MALFORMED_IDENTITY, callback_.WaitForResult());
}
@@ -1116,6 +1121,8 @@ TEST_F(FtpNetworkTransactionTest, CloseConnection) {
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailUser) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host",
FtpSocketDataProvider::PRE_USER,
@@ -1147,6 +1154,8 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailPass503) {
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailSyst) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host",
FtpSocketDataProvider::PRE_SYST,
@@ -1157,6 +1166,8 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailSyst) {
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailPwd) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host",
FtpSocketDataProvider::PRE_PWD,
@@ -1167,6 +1178,8 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailPwd) {
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailType) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host",
FtpSocketDataProvider::PRE_TYPE,
@@ -1177,6 +1190,8 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailType) {
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailEpsv) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host",
FtpSocketDataProvider::PRE_EPSV,
@@ -1187,6 +1202,8 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailEpsv) {
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailCwd) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host",
FtpSocketDataProvider::PRE_CWD,
@@ -1217,6 +1234,8 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailMlsd) {
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailList) {
FtpSocketDataProviderVMSDirectoryListing ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host/dir",
FtpSocketDataProvider::PRE_LIST,
@@ -1227,6 +1246,8 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailList) {
TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailUser) {
FtpSocketDataProviderFileDownload ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
FtpSocketDataProvider::PRE_USER,
@@ -1247,6 +1268,8 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailPass) {
TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailSyst) {
FtpSocketDataProviderFileDownload ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
FtpSocketDataProvider::PRE_SYST,
@@ -1257,6 +1280,8 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailSyst) {
TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailPwd) {
FtpSocketDataProviderFileDownload ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
FtpSocketDataProvider::PRE_PWD,
@@ -1267,6 +1292,8 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailPwd) {
TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailType) {
FtpSocketDataProviderFileDownload ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
FtpSocketDataProvider::PRE_TYPE,
@@ -1277,6 +1304,8 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailType) {
TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailEpsv) {
FtpSocketDataProviderFileDownload ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
FtpSocketDataProvider::PRE_EPSV,
@@ -1287,6 +1316,8 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailEpsv) {
TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailRetr) {
FtpSocketDataProviderFileDownload ctrl_socket;
+ // Use unallocated 599 FTP error code to make sure it falls into the generic
+ // ERR_FTP_FAILED bucket.
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
FtpSocketDataProvider::PRE_RETR,
diff --git a/net/ftp/ftp_request_info.h b/net/ftp/ftp_request_info.h
index a2e90c6..c73be47 100644
--- a/net/ftp/ftp_request_info.h
+++ b/net/ftp/ftp_request_info.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_FTP_FTP_REQUEST_INFO_H_
#define NET_FTP_FTP_REQUEST_INFO_H_
+#pragma once
#include "googleurl/src/gurl.h"
diff --git a/net/ftp/ftp_response_info.h b/net/ftp/ftp_response_info.h
index daec6c2..0c8884c 100644
--- a/net/ftp/ftp_response_info.h
+++ b/net/ftp/ftp_response_info.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_FTP_FTP_RESPONSE_INFO_H_
#define NET_FTP_FTP_RESPONSE_INFO_H_
+#pragma once
#include "base/time.h"
diff --git a/net/ftp/ftp_server_type_histograms.h b/net/ftp/ftp_server_type_histograms.h
index ed77b69..72d3c78 100644
--- a/net/ftp/ftp_server_type_histograms.h
+++ b/net/ftp/ftp_server_type_histograms.h
@@ -4,6 +4,7 @@
#ifndef NET_FTP_FTP_SERVER_TYPE_HISTOGRAMS_H_
#define NET_FTP_FTP_SERVER_TYPE_HISTOGRAMS_H_
+#pragma once
// The UpdateFtpServerTypeHistograms function collects statistics related
// to the types of FTP servers that our users are encountering.
diff --git a/net/ftp/ftp_transaction.h b/net/ftp/ftp_transaction.h
index 881a977..b1f1add 100644
--- a/net/ftp/ftp_transaction.h
+++ b/net/ftp/ftp_transaction.h
@@ -1,10 +1,12 @@
-// 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.
#ifndef NET_FTP_FTP_TRANSACTION_H_
#define NET_FTP_FTP_TRANSACTION_H_
+#pragma once
+#include "base/string16.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/load_states.h"
@@ -41,8 +43,8 @@ class FtpTransaction {
const BoundNetLog& net_log) = 0;
// Restarts the FTP transaction with authentication credentials.
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
+ virtual int RestartWithAuth(const string16& username,
+ const string16& password,
CompletionCallback* callback) = 0;
// Once response info is available for the transaction, response data may be
diff --git a/net/ftp/ftp_transaction_factory.h b/net/ftp/ftp_transaction_factory.h
index 7e39026..f979714 100644
--- a/net/ftp/ftp_transaction_factory.h
+++ b/net/ftp/ftp_transaction_factory.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_FTP_FTP_TRANSACTION_FACTORY_H_
#define NET_FTP_FTP_TRANSACTION_FACTORY_H_
+#pragma once
namespace net {
diff --git a/net/ftp/ftp_util.cc b/net/ftp/ftp_util.cc
index 79e6b71..aeb2355 100644
--- a/net/ftp/ftp_util.cc
+++ b/net/ftp/ftp_util.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/time.h"
@@ -155,19 +156,27 @@ bool FtpUtil::LsDateListingToTime(const string16& month, const string16& day,
if (!ThreeLetterMonthToNumber(month, &time_exploded.month))
return false;
- if (!StringToInt(day, &time_exploded.day_of_month))
+ if (!base::StringToInt(day, &time_exploded.day_of_month))
return false;
- if (!StringToInt(rest, &time_exploded.year)) {
- // Maybe it's time. Does it look like time (MM:HH)?
- if (rest.length() != 5 || rest[2] != ':')
- return false;
-
- if (!StringToInt(rest.substr(0, 2), &time_exploded.hour))
- return false;
-
- if (!StringToInt(rest.substr(3, 2), &time_exploded.minute))
+ if (!base::StringToInt(rest, &time_exploded.year)) {
+ // Maybe it's time. Does it look like time (HH:MM)?
+ if (rest.length() == 5 && rest[2] == ':') {
+ if (!base::StringToInt(rest.substr(0, 2), &time_exploded.hour))
+ return false;
+
+ if (!base::StringToInt(rest.substr(3, 2), &time_exploded.minute))
+ return false;
+ } else if (rest.length() == 4 && rest[1] == ':') {
+ // Sometimes it's just H:MM.
+ if (!base::StringToInt(rest.substr(0, 1), &time_exploded.hour))
+ return false;
+
+ if (!base::StringToInt(rest.substr(2, 2), &time_exploded.minute))
+ return false;
+ } else {
return false;
+ }
// Guess the year.
base::Time::Exploded current_exploded;
diff --git a/net/ftp/ftp_util.h b/net/ftp/ftp_util.h
index 37a51c2..eb7e963 100644
--- a/net/ftp/ftp_util.h
+++ b/net/ftp/ftp_util.h
@@ -4,6 +4,7 @@
#ifndef NET_FTP_FTP_UTIL_H_
#define NET_FTP_FTP_UTIL_H_
+#pragma once
#include <string>
diff --git a/net/ftp/ftp_util_unittest.cc b/net/ftp/ftp_util_unittest.cc
index 20450c2..98ae975 100644
--- a/net/ftp/ftp_util_unittest.cc
+++ b/net/ftp/ftp_util_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.
@@ -7,8 +7,9 @@
#include "base/basictypes.h"
#include "base/format_macros.h"
#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
+#include "base/stringprintf.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -140,9 +141,9 @@ TEST(FtpUtilTest, LsDateListingToTime) {
{ "Dec", "06", "21:00", 1993, 12, 6, 21, 0 },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s %s %s", i,
- kTestCases[i].month, kTestCases[i].day,
- kTestCases[i].rest));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s %s %s", i,
+ kTestCases[i].month, kTestCases[i].day,
+ kTestCases[i].rest));
base::Time time;
ASSERT_TRUE(net::FtpUtil::LsDateListingToTime(
@@ -179,8 +180,8 @@ TEST(FtpUtilTest, GetStringPartAfterColumns) {
{ " foo abc ", 2, "" },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); i++) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s %d",
- i, kTestCases[i].text, kTestCases[i].column));
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s %d", i,
+ kTestCases[i].text, kTestCases[i].column));
EXPECT_EQ(ASCIIToUTF16(kTestCases[i].expected_result),
net::FtpUtil::GetStringPartAfterColumns(
diff --git a/net/hresolv.target.mk b/net/hresolv.target.mk
index 95b02a8..8180dad 100644
--- a/net/hresolv.target.mk
+++ b/net/hresolv.target.mk
@@ -19,6 +19,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -65,6 +66,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -128,14 +130,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -164,7 +167,8 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/hresolv: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/hresolv: LIBS := $(LIBS)
diff --git a/net/http/des.h b/net/http/des.h
index 7b1469b..94a4f7c 100644
--- a/net/http/des.h
+++ b/net/http/des.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_DES_H_
#define NET_HTTP_DES_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/net/http/disk_cache_based_ssl_host_info.cc b/net/http/disk_cache_based_ssl_host_info.cc
new file mode 100644
index 0000000..61ee450
--- /dev/null
+++ b/net/http/disk_cache_based_ssl_host_info.cc
@@ -0,0 +1,230 @@
+// Copyright (c) 2010 The Chromium Authors. 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/disk_cache_based_ssl_host_info.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_cache.h"
+
+namespace net {
+
+DiskCacheBasedSSLHostInfo::DiskCacheBasedSSLHostInfo(
+ const std::string& hostname, HttpCache* http_cache)
+ : callback_(new CancelableCompletionCallback<DiskCacheBasedSSLHostInfo>(
+ ALLOW_THIS_IN_INITIALIZER_LIST(this),
+ &DiskCacheBasedSSLHostInfo::DoLoop)),
+ state_(GET_BACKEND),
+ ready_(false),
+ hostname_(hostname),
+ http_cache_(http_cache),
+ backend_(NULL),
+ entry_(NULL),
+ user_callback_(NULL) {
+}
+
+void DiskCacheBasedSSLHostInfo::Start() {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(GET_BACKEND, state_);
+ DoLoop(OK);
+}
+
+DiskCacheBasedSSLHostInfo::~DiskCacheBasedSSLHostInfo() {
+ DCHECK(!user_callback_);
+ DCHECK(!entry_);
+ callback_->Cancel();
+}
+
+std::string DiskCacheBasedSSLHostInfo::key() const {
+ return "sslhostinfo:" + hostname_;
+}
+
+void DiskCacheBasedSSLHostInfo::DoLoop(int rv) {
+ do {
+ switch (state_) {
+ case GET_BACKEND:
+ rv = DoGetBackend();
+ break;
+ case GET_BACKEND_COMPLETE:
+ rv = DoGetBackendComplete(rv);
+ break;
+ case OPEN:
+ rv = DoOpen();
+ break;
+ case OPEN_COMPLETE:
+ rv = DoOpenComplete(rv);
+ break;
+ case READ:
+ rv = DoRead();
+ break;
+ case READ_COMPLETE:
+ rv = DoReadComplete(rv);
+ break;
+ case WAIT_FOR_DATA_READY_DONE:
+ rv = WaitForDataReadyDone();
+ break;
+ case CREATE:
+ rv = DoCreate();
+ break;
+ case CREATE_COMPLETE:
+ rv = DoCreateComplete(rv);
+ break;
+ case WRITE:
+ rv = DoWrite();
+ break;
+ case WRITE_COMPLETE:
+ rv = DoWriteComplete(rv);
+ break;
+ case SET_DONE:
+ rv = SetDone();
+ break;
+ default:
+ rv = OK;
+ NOTREACHED();
+ }
+ } while (rv != ERR_IO_PENDING && state_ != NONE);
+}
+
+int DiskCacheBasedSSLHostInfo::DoGetBackend() {
+ state_ = GET_BACKEND_COMPLETE;
+ return http_cache_->GetBackend(&backend_, callback_.get());
+}
+
+int DiskCacheBasedSSLHostInfo::DoGetBackendComplete(int rv) {
+ if (rv == OK) {
+ state_ = OPEN;
+ } else {
+ state_ = WAIT_FOR_DATA_READY_DONE;
+ }
+ return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::DoOpen() {
+ state_ = OPEN_COMPLETE;
+ return backend_->OpenEntry(key(), &entry_, callback_.get());
+}
+
+int DiskCacheBasedSSLHostInfo::DoOpenComplete(int rv) {
+ if (rv == OK) {
+ state_ = READ;
+ } else {
+ state_ = WAIT_FOR_DATA_READY_DONE;
+ }
+
+ return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::DoRead() {
+ const int32 size = entry_->GetDataSize(0 /* index */);
+ if (!size) {
+ state_ = WAIT_FOR_DATA_READY_DONE;
+ return OK;
+ }
+
+ read_buffer_ = new IOBuffer(size);
+ state_ = READ_COMPLETE;
+ return entry_->ReadData(0 /* index */, 0 /* offset */, read_buffer_,
+ size, callback_.get());
+}
+
+int DiskCacheBasedSSLHostInfo::DoReadComplete(int rv) {
+ if (rv > 0)
+ data_ = std::string(read_buffer_->data(), rv);
+
+ state_ = WAIT_FOR_DATA_READY_DONE;
+ return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::WaitForDataReadyDone() {
+ CompletionCallback* callback;
+
+ DCHECK(!ready_);
+ state_ = NONE;
+ ready_ = true;
+ callback = user_callback_;
+ user_callback_ = NULL;
+ // We close the entry because, if we shutdown before ::Set is called, then we
+ // might leak a cache reference, which causes a DCHECK on shutdown.
+ if (entry_)
+ entry_->Close();
+ entry_ = NULL;
+
+ if (callback)
+ callback->Run(OK);
+
+ return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::WaitForDataReady(CompletionCallback* callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(state_ != GET_BACKEND);
+
+ if (ready_)
+ return OK;
+ if (callback) {
+ DCHECK(!user_callback_);
+ user_callback_ = callback;
+ }
+ return ERR_IO_PENDING;
+}
+
+void DiskCacheBasedSSLHostInfo::Set(const std::string& new_data) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(state_ != GET_BACKEND);
+
+ if (new_data.empty())
+ return;
+
+ DCHECK(new_data_.empty());
+ CHECK(ready_);
+ DCHECK(user_callback_ == NULL);
+ new_data_ = new_data;
+
+ if (!backend_)
+ return;
+
+ state_ = CREATE;
+ DoLoop(OK);
+}
+
+int DiskCacheBasedSSLHostInfo::DoCreate() {
+ DCHECK(entry_ == NULL);
+ state_ = CREATE_COMPLETE;
+ return backend_->CreateEntry(key(), &entry_, callback_.get());
+}
+
+int DiskCacheBasedSSLHostInfo::DoCreateComplete(int rv) {
+ if (rv != OK) {
+ state_ = SET_DONE;
+ } else {
+ state_ = WRITE;
+ }
+ return OK;
+}
+
+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 */);
+}
+
+int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
+ state_ = SET_DONE;
+ return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::SetDone() {
+ if (entry_)
+ entry_->Close();
+ entry_ = NULL;
+ state_ = NONE;
+ return OK;
+}
+
+} // namespace net
diff --git a/net/http/disk_cache_based_ssl_host_info.h b/net/http/disk_cache_based_ssl_host_info.h
new file mode 100644
index 0000000..7b1e972
--- /dev/null
+++ b/net/http/disk_cache_based_ssl_host_info.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2010 The Chromium Authors. 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_DISK_CACHE_BASED_SSL_HOST_INFO_H
+#define NET_HTTP_DISK_CACHE_BASED_SSL_HOST_INFO_H
+
+#include <string>
+
+#include "base/lock.h"
+#include "base/non_thread_safe.h"
+#include "base/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/ssl_non_sensitive_host_info.h"
+#include "net/disk_cache/disk_cache.h"
+
+namespace net {
+
+class IOBuffer;
+class HttpCache;
+
+// DiskCacheBasedSSLHostInfo fetches information about an SSL host from our
+// standard disk cache. Since the information is defined to be non-sensitive,
+// it's ok for us to keep it on disk.
+class DiskCacheBasedSSLHostInfo : public SSLNonSensitiveHostInfo,
+ public NonThreadSafe {
+ public:
+ DiskCacheBasedSSLHostInfo(const std::string& hostname, HttpCache* http_cache);
+
+ // Implementation of SSLNonSensitiveHostInfo
+ virtual void Start();
+ virtual int WaitForDataReady(CompletionCallback* callback);
+ virtual const std::string& data() const { return data_; }
+ virtual void Set(const std::string& new_data);
+
+ private:
+ ~DiskCacheBasedSSLHostInfo();
+ std::string key() const;
+
+ void DoLoop(int rv);
+
+ int DoGetBackendComplete(int rv);
+ int DoOpenComplete(int rv);
+ int DoReadComplete(int rv);
+ int DoWriteComplete(int rv);
+ int DoCreateComplete(int rv);
+
+ int DoGetBackend();
+ int DoOpen();
+ int DoRead();
+ int DoCreate();
+ int DoWrite();
+
+ // WaitForDataReadyDone is the terminal state of the read operation.
+ int WaitForDataReadyDone();
+ // 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,
+ };
+
+ scoped_refptr<CancelableCompletionCallback<DiskCacheBasedSSLHostInfo> >
+ 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_;
+ CompletionCallback* user_callback_;
+ scoped_refptr<net::IOBuffer> read_buffer_;
+ scoped_refptr<net::IOBuffer> write_buffer_;
+ std::string data_;
+};
+
+} // namespace net
+
+#endif // NET_HTTP_DISK_CACHE_BASED_SSL_HOST_INFO_H
diff --git a/net/http/http_alternate_protocols.cc b/net/http/http_alternate_protocols.cc
index cd42ed5..e37af69 100644
--- a/net/http/http_alternate_protocols.cc
+++ b/net/http/http_alternate_protocols.cc
@@ -12,37 +12,47 @@ namespace net {
const char HttpAlternateProtocols::kHeader[] = "Alternate-Protocol";
const char* const HttpAlternateProtocols::kProtocolStrings[] = {
"npn-spdy/1",
+ "npn-spdy/2",
};
+// static
+HttpAlternateProtocols::PortProtocolPair*
+ HttpAlternateProtocols::forced_alternate_protocol_ = NULL;
+
HttpAlternateProtocols::HttpAlternateProtocols() {}
HttpAlternateProtocols::~HttpAlternateProtocols() {}
bool HttpAlternateProtocols::HasAlternateProtocolFor(
const HostPortPair& http_host_port_pair) const {
- return ContainsKey(protocol_map_, http_host_port_pair);
+ return ContainsKey(protocol_map_, http_host_port_pair) ||
+ forced_alternate_protocol_;
}
bool HttpAlternateProtocols::HasAlternateProtocolFor(
const std::string& host, uint16 port) const {
- struct HostPortPair http_host_port_pair;
- http_host_port_pair.host = host;
- http_host_port_pair.port = port;
+ HostPortPair http_host_port_pair(host, port);
return HasAlternateProtocolFor(http_host_port_pair);
}
HttpAlternateProtocols::PortProtocolPair
HttpAlternateProtocols::GetAlternateProtocolFor(
const HostPortPair& http_host_port_pair) const {
- DCHECK(ContainsKey(protocol_map_, http_host_port_pair));
- return protocol_map_.find(http_host_port_pair)->second;
+ DCHECK(HasAlternateProtocolFor(http_host_port_pair));
+
+ // First check the map.
+ ProtocolMap::const_iterator it = protocol_map_.find(http_host_port_pair);
+ if (it != protocol_map_.end())
+ return it->second;
+
+ // We must be forcing an alternate.
+ DCHECK(forced_alternate_protocol_);
+ return *forced_alternate_protocol_;
}
HttpAlternateProtocols::PortProtocolPair
HttpAlternateProtocols::GetAlternateProtocolFor(
const std::string& host, uint16 port) const {
- struct HostPortPair http_host_port_pair;
- http_host_port_pair.host = host;
- http_host_port_pair.port = port;
+ HostPortPair http_host_port_pair(host, port);
return GetAlternateProtocolFor(http_host_port_pair);
}
@@ -86,4 +96,19 @@ void HttpAlternateProtocols::MarkBrokenAlternateProtocolFor(
protocol_map_[http_host_port_pair].protocol = BROKEN;
}
+// static
+void HttpAlternateProtocols::ForceAlternateProtocol(
+ const PortProtocolPair& pair) {
+ // Note: we're going to leak this.
+ if (forced_alternate_protocol_)
+ delete forced_alternate_protocol_;
+ forced_alternate_protocol_ = new PortProtocolPair(pair);
+}
+
+// static
+void HttpAlternateProtocols::DisableForcedAlternateProtocol() {
+ delete forced_alternate_protocol_;
+ forced_alternate_protocol_ = NULL;
+}
+
} // namespace net
diff --git a/net/http/http_alternate_protocols.h b/net/http/http_alternate_protocols.h
index 56fb49a..e06e13a 100644
--- a/net/http/http_alternate_protocols.h
+++ b/net/http/http_alternate_protocols.h
@@ -8,9 +8,12 @@
#ifndef NET_HTTP_HTTP_ALTERNATE_PROTOCOLS_H_
#define NET_HTTP_HTTP_ALTERNATE_PROTOCOLS_H_
+#pragma once
#include <map>
+#include <string>
#include <utility>
+
#include "base/basictypes.h"
#include "net/base/host_port_pair.h"
@@ -20,6 +23,7 @@ class HttpAlternateProtocols {
public:
enum Protocol {
NPN_SPDY_1,
+ NPN_SPDY_2,
NUM_ALTERNATE_PROTOCOLS,
BROKEN, // The alternate protocol is known to be broken.
};
@@ -59,11 +63,21 @@ class HttpAlternateProtocols {
// attempts to set the alternate protocol for |http_host_port_pair| will fail.
void MarkBrokenAlternateProtocolFor(const HostPortPair& http_host_port_pair);
+ // Debugging to simulate presence of an AlternateProtocol.
+ // If we don't have an alternate protocol in the map for any given host/port
+ // pair, force this ProtocolPortPair.
+ static void ForceAlternateProtocol(const PortProtocolPair& pair);
+ static void DisableForcedAlternateProtocol();
+
private:
typedef std::map<HostPortPair, PortProtocolPair> ProtocolMap;
ProtocolMap protocol_map_;
+ // The forced alternate protocol. If not-null, there is a protocol being
+ // forced.
+ static PortProtocolPair* forced_alternate_protocol_;
+
DISALLOW_COPY_AND_ASSIGN(HttpAlternateProtocols);
};
diff --git a/net/http/http_alternate_protocols_unittest.cc b/net/http/http_alternate_protocols_unittest.cc
index d82f850..8a2ac66 100644
--- a/net/http/http_alternate_protocols_unittest.cc
+++ b/net/http/http_alternate_protocols_unittest.cc
@@ -14,9 +14,7 @@ namespace {
TEST(HttpAlternateProtocols, Basic) {
HttpAlternateProtocols alternate_protocols;
- HostPortPair test_host_port_pair;
- test_host_port_pair.host = "foo";
- test_host_port_pair.port = 80;
+ HostPortPair test_host_port_pair("foo", 80);
EXPECT_FALSE(
alternate_protocols.HasAlternateProtocolFor(test_host_port_pair));
alternate_protocols.SetAlternateProtocolFor(
@@ -30,9 +28,7 @@ TEST(HttpAlternateProtocols, Basic) {
TEST(HttpAlternateProtocols, SetBroken) {
HttpAlternateProtocols alternate_protocols;
- HostPortPair test_host_port_pair;
- test_host_port_pair.host = "foo";
- test_host_port_pair.port = 80;
+ HostPortPair test_host_port_pair("foo", 80);
alternate_protocols.MarkBrokenAlternateProtocolFor(test_host_port_pair);
ASSERT_TRUE(alternate_protocols.HasAlternateProtocolFor(test_host_port_pair));
HttpAlternateProtocols::PortProtocolPair alternate =
@@ -48,5 +44,42 @@ TEST(HttpAlternateProtocols, SetBroken) {
<< "Second attempt should be ignored.";
}
+TEST(HttpAlternateProtocols, Forced) {
+ // Test forced alternate protocols.
+
+ HttpAlternateProtocols::PortProtocolPair default_protocol;
+ default_protocol.port = 1234;
+ default_protocol.protocol = HttpAlternateProtocols::NPN_SPDY_2;
+ HttpAlternateProtocols::ForceAlternateProtocol(default_protocol);
+
+ HttpAlternateProtocols alternate_protocols;
+
+ // Verify the forced protocol.
+ HostPortPair test_host_port_pair("foo", 80);
+ EXPECT_TRUE(
+ alternate_protocols.HasAlternateProtocolFor(test_host_port_pair));
+ HttpAlternateProtocols::PortProtocolPair alternate =
+ alternate_protocols.GetAlternateProtocolFor(test_host_port_pair);
+ EXPECT_EQ(default_protocol.port, alternate.port);
+ EXPECT_EQ(default_protocol.protocol, alternate.protocol);
+
+ // Verify the real protocol overrides the forced protocol.
+ alternate_protocols.SetAlternateProtocolFor(
+ test_host_port_pair, 443, HttpAlternateProtocols::NPN_SPDY_1);
+ ASSERT_TRUE(alternate_protocols.HasAlternateProtocolFor(test_host_port_pair));
+ alternate = alternate_protocols.GetAlternateProtocolFor(test_host_port_pair);
+ EXPECT_EQ(443, alternate.port);
+ EXPECT_EQ(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
+
+ // Turn off the static, forced alternate protocol so that tests don't
+ // have this state.
+ HttpAlternateProtocols::DisableForcedAlternateProtocol();
+
+ // Verify the forced protocol is off.
+ HostPortPair test_host_port_pair2("bar", 80);
+ EXPECT_FALSE(
+ alternate_protocols.HasAlternateProtocolFor(test_host_port_pair2));
+}
+
} // namespace
} // namespace net
diff --git a/net/http/http_auth.cc b/net/http/http_auth.cc
index ff2ac4f..debcca7 100644
--- a/net/http/http_auth.cc
+++ b/net/http/http_auth.cc
@@ -28,20 +28,7 @@ void HttpAuth::ChooseBestChallenge(
const BoundNetLog& net_log,
scoped_ptr<HttpAuthHandler>* handler) {
DCHECK(http_auth_handler_factory);
-
- // A connection-based authentication scheme must continue to use the
- // existing handler object in |*handler|.
- if (handler->get() && (*handler)->is_connection_based()) {
- const std::string header_name = GetChallengeHeaderName(target);
- std::string challenge;
- void* iter = NULL;
- while (headers->EnumerateHeader(&iter, header_name, &challenge)) {
- ChallengeTokenizer props(challenge.begin(), challenge.end());
- if (LowerCaseEqualsASCII(props.scheme(), (*handler)->scheme().c_str()) &&
- (*handler)->InitFromChallenge(&props, target, origin, net_log))
- return;
- }
- }
+ DCHECK(handler->get() == NULL);
// Choose the challenge whose authentication handler gives the maximum score.
scoped_ptr<HttpAuthHandler> best;
@@ -53,18 +40,47 @@ void HttpAuth::ChooseBestChallenge(
int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
cur_challenge, target, origin, net_log, &cur);
if (rv != OK) {
- LOG(WARNING) << "Unable to create AuthHandler. Status: "
- << ErrorToString(rv) << " Challenge: " << cur_challenge;
+ LOG(INFO) << "Unable to create AuthHandler. Status: "
+ << ErrorToString(rv) << " Challenge: " << cur_challenge;
continue;
}
- if (cur.get() && (!best.get() || best->score() < cur->score())) {
- if (disabled_schemes.find(cur->scheme()) == disabled_schemes.end())
- best.swap(cur);
- }
+ if (cur.get() && (!best.get() || best->score() < cur->score()) &&
+ (disabled_schemes.find(cur->scheme()) == disabled_schemes.end()))
+ best.swap(cur);
}
handler->swap(best);
}
+// static
+HttpAuth::AuthorizationResult HttpAuth::HandleChallengeResponse(
+ HttpAuthHandler* handler,
+ const HttpResponseHeaders* headers,
+ Target target,
+ const std::set<std::string>& disabled_schemes,
+ std::string* challenge_used) {
+ DCHECK(challenge_used);
+ const std::string& current_scheme = handler->scheme();
+ if (disabled_schemes.find(current_scheme) != disabled_schemes.end())
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+ const std::string header_name = GetChallengeHeaderName(target);
+ void* iter = NULL;
+ std::string challenge;
+ HttpAuth::AuthorizationResult authorization_result =
+ HttpAuth::AUTHORIZATION_RESULT_INVALID;
+ while (headers->EnumerateHeader(&iter, header_name, &challenge)) {
+ HttpAuth::ChallengeTokenizer props(challenge.begin(), challenge.end());
+ if (!LowerCaseEqualsASCII(props.scheme(), current_scheme.c_str()))
+ continue;
+ authorization_result = handler->HandleAnotherChallenge(&props);
+ if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) {
+ *challenge_used = challenge;
+ return authorization_result;
+ }
+ }
+ // Finding no matches is equivalent to rejection.
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+}
+
void HttpAuth::ChallengeTokenizer::Init(std::string::const_iterator begin,
std::string::const_iterator end) {
// The first space-separated token is the auth-scheme.
diff --git a/net/http/http_auth.h b/net/http/http_auth.h
index 01afcc0..dc78f0c 100644
--- a/net/http/http_auth.h
+++ b/net/http/http_auth.h
@@ -4,10 +4,13 @@
#ifndef NET_HTTP_HTTP_AUTH_H_
#define NET_HTTP_HTTP_AUTH_H_
+#pragma once
#include <set>
+#include <string>
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "net/http/http_util.h"
template <class T> class scoped_refptr;
@@ -22,7 +25,6 @@ class HttpResponseHeaders;
// Utility class for http authentication.
class HttpAuth {
public:
-
// Http authentication can be done the the proxy server, origin server,
// or both. This enum tracks who the target is.
enum Target {
@@ -34,6 +36,24 @@ class HttpAuth {
AUTH_NUM_TARGETS = 2,
};
+ // What the HTTP WWW-Authenticate/Proxy-Authenticate headers indicate about
+ // the previous authorization attempt.
+ enum AuthorizationResult {
+ AUTHORIZATION_RESULT_ACCEPT, // The authorization attempt was accepted,
+ // although there still may be additional
+ // rounds of challenges.
+
+ AUTHORIZATION_RESULT_REJECT, // The authorization attempt was rejected.
+
+ AUTHORIZATION_RESULT_STALE, // (Digest) The nonce used in the
+ // authorization attempt is stale, but
+ // otherwise the attempt was valid.
+
+ AUTHORIZATION_RESULT_INVALID, // The authentication challenge headers are
+ // poorly formed (the authorization attempt
+ // itself may have been fine).
+ };
+
// Describes where the identity used for authentication came from.
enum IdentitySource {
// Came from nowhere -- the identity is not initialized.
@@ -67,9 +87,8 @@ class HttpAuth {
IdentitySource source;
bool invalid;
- // TODO(wtc): |username| and |password| should be string16.
- std::wstring username;
- std::wstring password;
+ string16 username;
+ string16 password;
};
// Get the name of the header containing the auth challenge
@@ -86,19 +105,13 @@ class HttpAuth {
// Iterate through the challenge headers, and pick the best one that
// we support. Obtains the implementation class for handling the challenge,
- // and passes it back in |*handler|. If the existing handler in |*handler|
- // should continue to be used (such as for the NTLM authentication scheme),
- // |*handler| is unchanged. If no supported challenge was found, |*handler|
- // is set to NULL.
+ // and passes it back in |*handler|. If no supported challenge was found,
+ // |*handler| is set to NULL.
//
// |disabled_schemes| is the set of schemes that we should not use.
//
- // |origin| is used by the NTLM authentication scheme to construct the
- // service principal name. It is ignored by other schemes.
- //
- // TODO(wtc): Continuing to use the existing handler in |*handler| (for
- // NTLM) is new behavior. Rename ChooseBestChallenge to fully encompass
- // what it does now.
+ // |origin| is used by the NTLM and Negotiation authentication scheme to
+ // construct the service principal name. It is ignored by other schemes.
static void ChooseBestChallenge(
HttpAuthHandlerFactory* http_auth_handler_factory,
const HttpResponseHeaders* headers,
@@ -108,6 +121,14 @@ class HttpAuth {
const BoundNetLog& net_log,
scoped_ptr<HttpAuthHandler>* handler);
+ // Handle a response to a previous authentication attempt.
+ static AuthorizationResult HandleChallengeResponse(
+ HttpAuthHandler* handler,
+ const HttpResponseHeaders* headers,
+ Target target,
+ const std::set<std::string>& disabled_schemes,
+ std::string* challenge_used);
+
// ChallengeTokenizer breaks up a challenge string into the the auth scheme
// and parameter list, according to RFC 2617 Sec 1.2:
// challenge = auth-scheme 1*SP 1#auth-param
@@ -119,7 +140,11 @@ class HttpAuth {
public:
ChallengeTokenizer(std::string::const_iterator begin,
std::string::const_iterator end)
- : props_(begin, end, ','), valid_(true), begin_(begin), end_(end),
+ : props_(begin, end, ','),
+ valid_(true),
+ begin_(begin),
+ end_(end),
+ value_is_quoted_(false),
expect_base64_token_(false) {
Init(begin, end);
}
diff --git a/net/http/http_auth_cache.cc b/net/http/http_auth_cache.cc
index 21db55d..7423115 100644
--- a/net/http/http_auth_cache.cc
+++ b/net/http/http_auth_cache.cc
@@ -48,14 +48,14 @@ void CheckOriginIsValid(const GURL& origin) {
// Functor used by remove_if.
struct IsEnclosedBy {
- IsEnclosedBy(const std::string& path) : path(path) { }
+ explicit IsEnclosedBy(const std::string& path) : path(path) { }
bool operator() (const std::string& x) {
return IsEnclosingPath(path, x);
}
const std::string& path;
};
-} // namespace
+} // namespace
namespace net {
@@ -71,7 +71,7 @@ HttpAuthCache::Entry* HttpAuthCache::Lookup(const GURL& origin,
it->scheme() == scheme)
return &(*it);
}
- return NULL; // No realm entry found.
+ return NULL; // No realm entry found.
}
// Performance: O(n*m), where n is the number of realm entries, m is the number
@@ -93,15 +93,15 @@ HttpAuthCache::Entry* HttpAuthCache::LookupByPath(const GURL& origin,
if (it->origin() == origin && it->HasEnclosingPath(parent_dir))
return &(*it);
}
- return NULL; // No entry found.
+ return NULL; // No entry found.
}
HttpAuthCache::Entry* HttpAuthCache::Add(const GURL& origin,
const std::string& realm,
const std::string& scheme,
const std::string& auth_challenge,
- const std::wstring& username,
- const std::wstring& password,
+ const string16& username,
+ const string16& password,
const std::string& path) {
CheckOriginIsValid(origin);
CheckPathIsValid(path);
@@ -134,6 +134,10 @@ HttpAuthCache::Entry* HttpAuthCache::Add(const GURL& origin,
return entry;
}
+HttpAuthCache::Entry::Entry()
+ : nonce_count_(0) {
+}
+
void HttpAuthCache::Entry::AddPath(const std::string& path) {
std::string parent_dir = GetParentDirectory(path);
if (!HasEnclosingPath(parent_dir)) {
@@ -162,11 +166,17 @@ bool HttpAuthCache::Entry::HasEnclosingPath(const std::string& dir) {
return false;
}
+void HttpAuthCache::Entry::UpdateStaleChallenge(
+ const std::string& auth_challenge) {
+ auth_challenge_ = auth_challenge;
+ nonce_count_ = 1;
+}
+
bool HttpAuthCache::Remove(const GURL& origin,
const std::string& realm,
const std::string& scheme,
- const std::wstring& username,
- const std::wstring& password) {
+ const string16& username,
+ const string16& password) {
for (EntryList::iterator it = entries_.begin(); it != entries_.end(); ++it) {
if (it->origin() == origin && it->realm() == realm &&
it->scheme() == scheme) {
@@ -180,4 +190,15 @@ bool HttpAuthCache::Remove(const GURL& origin,
return false;
}
-} // namespace net
+bool HttpAuthCache::UpdateStaleChallenge(const GURL& origin,
+ const std::string& realm,
+ const std::string& scheme,
+ const std::string& auth_challenge) {
+ HttpAuthCache::Entry* entry = Lookup(origin, realm, scheme);
+ if (!entry)
+ return false;
+ entry->UpdateStaleChallenge(auth_challenge);
+ return true;
+}
+
+} // namespace net
diff --git a/net/http/http_auth_cache.h b/net/http/http_auth_cache.h
index 1d238af..764a563 100644
--- a/net/http/http_auth_cache.h
+++ b/net/http/http_auth_cache.h
@@ -4,14 +4,15 @@
#ifndef NET_HTTP_HTTP_AUTH_CACHE_H_
#define NET_HTTP_HTTP_AUTH_CACHE_H_
+#pragma once
#include <list>
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
+#include "base/string16.h"
#include "googleurl/src/gurl.h"
-// This is needed for the FRIEND_TEST() macro.
-#include "testing/gtest/include/gtest/gtest_prod.h"
namespace net {
@@ -61,8 +62,8 @@ class HttpAuthCache {
const std::string& realm,
const std::string& scheme,
const std::string& auth_challenge,
- const std::wstring& username,
- const std::wstring& password,
+ const string16& username,
+ const string16& password,
const std::string& path);
// Remove entry on server |origin| for realm |realm| and scheme |scheme|
@@ -76,8 +77,18 @@ class HttpAuthCache {
bool Remove(const GURL& origin,
const std::string& realm,
const std::string& scheme,
- const std::wstring& username,
- const std::wstring& password);
+ const string16& username,
+ const string16& password);
+
+ // Updates a stale digest entry on server |origin| for realm |realm| and
+ // scheme |scheme|. The cached auth challenge is replaced with
+ // |auth_challenge| and the nonce count is reset.
+ // |UpdateStaleChallenge()| returns true if a matching entry exists in the
+ // cache, false otherwise.
+ bool UpdateStaleChallenge(const GURL& origin,
+ const std::string& realm,
+ const std::string& scheme,
+ const std::string& auth_challenge);
// Prevent unbounded memory growth. These are safeguards for abuse; it is
// not expected that the limits will be reached in ordinary usage.
@@ -114,12 +125,12 @@ class HttpAuthCache::Entry {
}
// The login username.
- const std::wstring username() const {
+ const string16 username() const {
return username_;
}
// The login password.
- const std::wstring password() const {
+ const string16 password() const {
return password_;
}
@@ -127,12 +138,14 @@ class HttpAuthCache::Entry {
return ++nonce_count_;
}
+ void UpdateStaleChallenge(const std::string& auth_challenge);
+
private:
friend class HttpAuthCache;
- FRIEND_TEST(HttpAuthCacheTest, AddPath);
- FRIEND_TEST(HttpAuthCacheTest, AddToExistingEntry);
+ FRIEND_TEST_ALL_PREFIXES(HttpAuthCacheTest, AddPath);
+ FRIEND_TEST_ALL_PREFIXES(HttpAuthCacheTest, AddToExistingEntry);
- Entry() {}
+ Entry();
// Adds a path defining the realm's protection space. If the path is
// already contained in the protection space, is a no-op.
@@ -148,8 +161,8 @@ class HttpAuthCache::Entry {
// Identity.
std::string auth_challenge_;
- std::wstring username_;
- std::wstring password_;
+ string16 username_;
+ string16 password_;
int nonce_count_;
@@ -158,6 +171,6 @@ class HttpAuthCache::Entry {
PathList paths_;
};
-} // namespace net
+} // namespace net
#endif // NET_HTTP_HTTP_AUTH_CACHE_H_
diff --git a/net/http/http_auth_cache_unittest.cc b/net/http/http_auth_cache_unittest.cc
index 4e2af9d..5773d15 100644
--- a/net/http/http_auth_cache_unittest.cc
+++ b/net/http/http_auth_cache_unittest.cc
@@ -2,11 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
+
+#include "base/string16.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_cache.h"
#include "net/http/http_auth_handler.h"
-
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -25,13 +29,18 @@ class MockAuthHandler : public HttpAuthHandler {
properties_ = 0;
}
+ HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) {
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+ }
+
protected:
virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) {
return false; // Unused.
}
- virtual int GenerateAuthTokenImpl(const std::wstring*,
- const std::wstring*,
+ virtual int GenerateAuthTokenImpl(const string16*,
+ const string16*,
const HttpRequestInfo*,
CompletionCallback* callback,
std::string* auth_token) {
@@ -44,6 +53,22 @@ class MockAuthHandler : public HttpAuthHandler {
~MockAuthHandler() {}
};
+const char* kBasic = "basic";
+const char* kDigest = "digest";
+const char* kRealm1 = "Realm1";
+const char* kRealm2 = "Realm2";
+const char* kRealm3 = "Realm3";
+const char* kRealm4 = "Realm4";
+const string16 k123(ASCIIToUTF16("123"));
+const string16 k1234(ASCIIToUTF16("1234"));
+const string16 kAdmin(ASCIIToUTF16("admin"));
+const string16 kAlice(ASCIIToUTF16("alice"));
+const string16 kAlice2(ASCIIToUTF16("alice2"));
+const string16 kPassword(ASCIIToUTF16("password"));
+const string16 kRoot(ASCIIToUTF16("root"));
+const string16 kUsername(ASCIIToUTF16("username"));
+const string16 kWileCoyote(ASCIIToUTF16("wilecoyote"));
+
} // namespace
// Test adding and looking-up cache entries (both by realm and by path).
@@ -55,73 +80,74 @@ TEST(HttpAuthCacheTest, Basic) {
// Add cache entries for 3 realms: "Realm1", "Realm2", "Realm3"
scoped_ptr<HttpAuthHandler> realm1_handler(
- new MockAuthHandler("basic", "Realm1", HttpAuth::AUTH_SERVER));
+ new MockAuthHandler(kBasic, kRealm1, HttpAuth::AUTH_SERVER));
cache.Add(origin, realm1_handler->realm(), realm1_handler->scheme(),
- "Basic realm=Realm1", L"realm1-user", L"realm1-password",
- "/foo/bar/index.html");
+ "Basic realm=Realm1", ASCIIToUTF16("realm1-user"),
+ ASCIIToUTF16("realm1-password"), "/foo/bar/index.html");
scoped_ptr<HttpAuthHandler> realm2_handler(
- new MockAuthHandler("basic", "Realm2", HttpAuth::AUTH_SERVER));
+ new MockAuthHandler(kBasic, kRealm2, HttpAuth::AUTH_SERVER));
cache.Add(origin, realm2_handler->realm(), realm2_handler->scheme(),
- "Basic realm=Realm2", L"realm2-user", L"realm2-password",
- "/foo2/index.html");
+ "Basic realm=Realm2", ASCIIToUTF16("realm2-user"),
+ ASCIIToUTF16("realm2-password"), "/foo2/index.html");
scoped_ptr<HttpAuthHandler> realm3_basic_handler(
- new MockAuthHandler("basic", "Realm3", HttpAuth::AUTH_PROXY));
+ new MockAuthHandler(kBasic, kRealm3, HttpAuth::AUTH_PROXY));
cache.Add(origin, realm3_basic_handler->realm(),
realm3_basic_handler->scheme(), "Basic realm=Realm3",
- L"realm3-basic-user", L"realm3-basic-password", "");
+ ASCIIToUTF16("realm3-basic-user"),
+ ASCIIToUTF16("realm3-basic-password"), "");
scoped_ptr<HttpAuthHandler> realm3_digest_handler(
- new MockAuthHandler("digest", "Realm3", HttpAuth::AUTH_PROXY));
+ new MockAuthHandler(kDigest, kRealm3, HttpAuth::AUTH_PROXY));
cache.Add(origin, realm3_digest_handler->realm(),
realm3_digest_handler->scheme(), "Digest realm=Realm3",
- L"realm3-digest-user", L"realm3-digest-password",
- "/baz/index.html");
+ ASCIIToUTF16("realm3-digest-user"),
+ ASCIIToUTF16("realm3-digest-password"), "/baz/index.html");
// There is no Realm4
- entry = cache.Lookup(origin, "Realm4", "basic");
+ entry = cache.Lookup(origin, kRealm4, kBasic);
EXPECT_TRUE(NULL == entry);
// While Realm3 does exist, the origin scheme is wrong.
- entry = cache.Lookup(GURL("https://www.google.com"), "Realm3",
- "basic");
+ entry = cache.Lookup(GURL("https://www.google.com"), kRealm3,
+ kBasic);
EXPECT_TRUE(NULL == entry);
// Realm, origin scheme ok, authentication scheme wrong
- entry = cache.Lookup(GURL("http://www.google.com"), "Realm1", "digest");
+ entry = cache.Lookup(GURL("http://www.google.com"), kRealm1, kDigest);
EXPECT_TRUE(NULL == entry);
// Valid lookup by origin, realm, scheme.
- entry = cache.Lookup(GURL("http://www.google.com:80"), "Realm3", "basic");
+ entry = cache.Lookup(GURL("http://www.google.com:80"), kRealm3, kBasic);
ASSERT_FALSE(NULL == entry);
- EXPECT_EQ("basic", entry->scheme());
- EXPECT_EQ("Realm3", entry->realm());
+ EXPECT_EQ(kBasic, entry->scheme());
+ EXPECT_EQ(kRealm3, entry->realm());
EXPECT_EQ("Basic realm=Realm3", entry->auth_challenge());
- EXPECT_EQ(L"realm3-basic-user", entry->username());
- EXPECT_EQ(L"realm3-basic-password", entry->password());
+ EXPECT_EQ(ASCIIToUTF16("realm3-basic-user"), entry->username());
+ EXPECT_EQ(ASCIIToUTF16("realm3-basic-password"), entry->password());
// Valid lookup by origin, realm, scheme when there's a duplicate
// origin, realm in the cache
- entry = cache.Lookup(GURL("http://www.google.com:80"), "Realm3", "digest");
+ entry = cache.Lookup(GURL("http://www.google.com:80"), kRealm3, kDigest);
ASSERT_FALSE(NULL == entry);
- EXPECT_EQ("digest", entry->scheme());
- EXPECT_EQ("Realm3", entry->realm());
+ EXPECT_EQ(kDigest, entry->scheme());
+ EXPECT_EQ(kRealm3, entry->realm());
EXPECT_EQ("Digest realm=Realm3", entry->auth_challenge());
- EXPECT_EQ(L"realm3-digest-user", entry->username());
- EXPECT_EQ(L"realm3-digest-password", entry->password());
+ EXPECT_EQ(ASCIIToUTF16("realm3-digest-user"), entry->username());
+ EXPECT_EQ(ASCIIToUTF16("realm3-digest-password"), entry->password());
// Valid lookup by realm.
- entry = cache.Lookup(origin, "Realm2", "basic");
+ entry = cache.Lookup(origin, kRealm2, kBasic);
ASSERT_FALSE(NULL == entry);
- EXPECT_EQ("basic", entry->scheme());
- EXPECT_EQ("Realm2", entry->realm());
+ EXPECT_EQ(kBasic, entry->scheme());
+ EXPECT_EQ(kRealm2, entry->realm());
EXPECT_EQ("Basic realm=Realm2", entry->auth_challenge());
- EXPECT_EQ(L"realm2-user", entry->username());
- EXPECT_EQ(L"realm2-password", entry->password());
+ EXPECT_EQ(ASCIIToUTF16("realm2-user"), entry->username());
+ EXPECT_EQ(ASCIIToUTF16("realm2-password"), entry->password());
// Check that subpaths are recognized.
- HttpAuthCache::Entry* realm2_entry = cache.Lookup(origin, "Realm2", "basic");
+ HttpAuthCache::Entry* realm2_entry = cache.Lookup(origin, kRealm2, kBasic);
EXPECT_FALSE(NULL == realm2_entry);
// Positive tests:
entry = cache.LookupByPath(origin, "/foo2/index.html");
@@ -145,7 +171,7 @@ TEST(HttpAuthCacheTest, Basic) {
// Confirm we find the same realm, different auth scheme by path lookup
HttpAuthCache::Entry* realm3_digest_entry =
- cache.Lookup(origin, "Realm3", "digest");
+ cache.Lookup(origin, kRealm3, kDigest);
EXPECT_FALSE(NULL == realm3_digest_entry);
entry = cache.LookupByPath(origin, "/baz/index.html");
EXPECT_TRUE(realm3_digest_entry == entry);
@@ -156,7 +182,7 @@ TEST(HttpAuthCacheTest, Basic) {
// Confirm we find the same realm, different auth scheme by path lookup
HttpAuthCache::Entry* realm3DigestEntry =
- cache.Lookup(origin, "Realm3", "digest");
+ cache.Lookup(origin, kRealm3, kDigest);
EXPECT_FALSE(NULL == realm3DigestEntry);
entry = cache.LookupByPath(origin, "/baz/index.html");
EXPECT_TRUE(realm3DigestEntry == entry);
@@ -168,8 +194,8 @@ TEST(HttpAuthCacheTest, Basic) {
// Lookup using empty path (may be used for proxy).
entry = cache.LookupByPath(origin, "");
EXPECT_FALSE(NULL == entry);
- EXPECT_EQ("basic", entry->scheme());
- EXPECT_EQ("Realm3", entry->realm());
+ EXPECT_EQ(kBasic, entry->scheme());
+ EXPECT_EQ(kRealm3, entry->realm());
}
TEST(HttpAuthCacheTest, AddPath) {
@@ -212,21 +238,21 @@ TEST(HttpAuthCacheTest, AddToExistingEntry) {
const std::string auth_challenge = "Basic realm=MyRealm";
scoped_ptr<HttpAuthHandler> handler(
- new MockAuthHandler("basic", "MyRealm", HttpAuth::AUTH_SERVER));
+ new MockAuthHandler(kBasic, "MyRealm", HttpAuth::AUTH_SERVER));
HttpAuthCache::Entry* orig_entry = cache.Add(
origin, handler->realm(), handler->scheme(), auth_challenge,
- L"user1", L"password1", "/x/y/z/");
+ ASCIIToUTF16("user1"), ASCIIToUTF16("password1"), "/x/y/z/");
cache.Add(origin, handler->realm(), handler->scheme(), auth_challenge,
- L"user2", L"password2", "/z/y/x/");
+ ASCIIToUTF16("user2"), ASCIIToUTF16("password2"), "/z/y/x/");
cache.Add(origin, handler->realm(), handler->scheme(), auth_challenge,
- L"user3", L"password3", "/z/y");
+ ASCIIToUTF16("user3"), ASCIIToUTF16("password3"), "/z/y");
- HttpAuthCache::Entry* entry = cache.Lookup(origin, "MyRealm", "basic");
+ HttpAuthCache::Entry* entry = cache.Lookup(origin, "MyRealm", kBasic);
EXPECT_TRUE(entry == orig_entry);
- EXPECT_EQ(L"user3", entry->username());
- EXPECT_EQ(L"password3", entry->password());
+ EXPECT_EQ(ASCIIToUTF16("user3"), entry->username());
+ EXPECT_EQ(ASCIIToUTF16("password3"), entry->password());
EXPECT_EQ(2U, entry->paths_.size());
EXPECT_EQ("/z/", entry->paths_.front());
@@ -237,66 +263,116 @@ TEST(HttpAuthCacheTest, Remove) {
GURL origin("http://foobar2.com");
scoped_ptr<HttpAuthHandler> realm1_handler(
- new MockAuthHandler("basic", "Realm1", HttpAuth::AUTH_SERVER));
+ new MockAuthHandler(kBasic, kRealm1, HttpAuth::AUTH_SERVER));
scoped_ptr<HttpAuthHandler> realm2_handler(
- new MockAuthHandler("basic", "Realm2", HttpAuth::AUTH_SERVER));
+ new MockAuthHandler(kBasic, kRealm2, HttpAuth::AUTH_SERVER));
scoped_ptr<HttpAuthHandler> realm3_basic_handler(
- new MockAuthHandler("basic", "Realm3", HttpAuth::AUTH_SERVER));
+ new MockAuthHandler(kBasic, kRealm3, HttpAuth::AUTH_SERVER));
scoped_ptr<HttpAuthHandler> realm3_digest_handler(
- new MockAuthHandler("digest", "Realm3", HttpAuth::AUTH_SERVER));
+ new MockAuthHandler(kDigest, kRealm3, HttpAuth::AUTH_SERVER));
HttpAuthCache cache;
cache.Add(origin, realm1_handler->realm(), realm1_handler->scheme(),
- "basic realm=Realm1", L"alice", L"123", "/");
+ "basic realm=Realm1", kAlice, k123, "/");
cache.Add(origin, realm2_handler->realm(), realm2_handler->scheme(),
- "basic realm=Realm2", L"bob", L"princess", "/");
+ "basic realm=Realm2", ASCIIToUTF16("bob"), ASCIIToUTF16("princess"),
+ "/");
cache.Add(origin, realm3_basic_handler->realm(),
- realm3_basic_handler->scheme(), "basic realm=Realm3", L"admin",
- L"password", "/");
+ realm3_basic_handler->scheme(), "basic realm=Realm3",
+ kAdmin, kPassword, "/");
cache.Add(origin, realm3_digest_handler->realm(),
- realm3_digest_handler->scheme(), "digest realm=Realm3", L"root",
- L"wilecoyote", "/");
+ realm3_digest_handler->scheme(), "digest realm=Realm3",
+ kRoot, kWileCoyote, "/");
// Fails, because there is no realm "Realm4".
- EXPECT_FALSE(cache.Remove(origin, "Realm4", "basic", L"alice", L"123"));
+ EXPECT_FALSE(cache.Remove(origin, kRealm4, kBasic, kAlice, k123));
// Fails because the origin is wrong.
EXPECT_FALSE(cache.Remove(
- GURL("http://foobar2.com:100"), "Realm1", "basic", L"alice", L"123"));
+ GURL("http://foobar2.com:100"), kRealm1, kBasic, kAlice, k123));
// Fails because the username is wrong.
- EXPECT_FALSE(cache.Remove(origin, "Realm1", "basic", L"alice2", L"123"));
+ EXPECT_FALSE(cache.Remove(origin, kRealm1, kBasic, kAlice2, k123));
// Fails because the password is wrong.
- EXPECT_FALSE(cache.Remove(origin, "Realm1", "basic", L"alice", L"1234"));
+ EXPECT_FALSE(cache.Remove(origin, kRealm1, kBasic, kAlice, k1234));
// Fails because the authentication type is wrong.
- EXPECT_FALSE(cache.Remove(origin, "Realm1", "digest", L"alice", L"123"));
+ EXPECT_FALSE(cache.Remove(origin, kRealm1, kDigest, kAlice, k123));
// Succeeds.
- EXPECT_TRUE(cache.Remove(origin, "Realm1", "basic", L"alice", L"123"));
+ EXPECT_TRUE(cache.Remove(origin, kRealm1, kBasic, kAlice, k123));
// Fails because we just deleted the entry!
- EXPECT_FALSE(cache.Remove(origin, "Realm1", "basic", L"alice", L"123"));
+ EXPECT_FALSE(cache.Remove(origin, kRealm1, kBasic, kAlice, k123));
// Succeed when there are two authentication types for the same origin,realm.
- EXPECT_TRUE(cache.Remove(origin, "Realm3", "digest", L"root", L"wilecoyote"));
+ EXPECT_TRUE(cache.Remove(origin, kRealm3, kDigest, kRoot, kWileCoyote));
// Succeed as above, but when entries were added in opposite order
cache.Add(origin, realm3_digest_handler->realm(),
- realm3_digest_handler->scheme(), "digest realm=Realm3", L"root",
- L"wilecoyote", "/");
- EXPECT_TRUE(cache.Remove(origin, "Realm3", "basic", L"admin", L"password"));
+ realm3_digest_handler->scheme(), "digest realm=Realm3",
+ kRoot, kWileCoyote, "/");
+ EXPECT_TRUE(cache.Remove(origin, kRealm3, kBasic, kAdmin, kPassword));
// Make sure that removing one entry still leaves the other available for
// lookup.
- HttpAuthCache::Entry* entry = cache.Lookup(origin, "Realm3", "digest");
+ HttpAuthCache::Entry* entry = cache.Lookup(origin, kRealm3, kDigest);
EXPECT_FALSE(NULL == entry);
}
+TEST(HttpAuthCacheTest, UpdateStaleChallenge) {
+ HttpAuthCache cache;
+ GURL origin("http://foobar2.com");
+ scoped_ptr<HttpAuthHandler> digest_handler(
+ new MockAuthHandler(kDigest, kRealm1, HttpAuth::AUTH_PROXY));
+ HttpAuthCache::Entry* entry_pre = cache.Add(
+ origin,
+ digest_handler->realm(),
+ digest_handler->scheme(),
+ "Digest realm=Realm1,"
+ "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\"",
+ ASCIIToUTF16("realm-digest-user"),
+ ASCIIToUTF16("realm-digest-password"),
+ "/baz/index.html");
+ ASSERT_TRUE(entry_pre != NULL);
+
+ EXPECT_EQ(2, entry_pre->IncrementNonceCount());
+ EXPECT_EQ(3, entry_pre->IncrementNonceCount());
+ EXPECT_EQ(4, entry_pre->IncrementNonceCount());
+
+ bool update_success = cache.UpdateStaleChallenge(
+ origin,
+ digest_handler->realm(),
+ digest_handler->scheme(),
+ "Digest realm=Realm1,"
+ "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\","
+ "stale=\"true\"");
+ EXPECT_TRUE(update_success);
+
+ // After the stale update, the entry should still exist in the cache and
+ // the nonce count should be reset to 0.
+ HttpAuthCache::Entry* entry_post = cache.Lookup(
+ origin,
+ digest_handler->realm(),
+ digest_handler->scheme());
+ ASSERT_TRUE(entry_post != NULL);
+ EXPECT_EQ(2, entry_post->IncrementNonceCount());
+
+ // UpdateStaleChallenge will fail if an entry doesn't exist in the cache.
+ bool update_failure = cache.UpdateStaleChallenge(
+ origin,
+ kRealm2,
+ digest_handler->scheme(),
+ "Digest realm=Realm2,"
+ "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\","
+ "stale=\"true\"");
+ EXPECT_FALSE(update_failure);
+}
+
// Test fixture class for eviction tests (contains helpers for bulk
// insertion and existence testing).
class HttpAuthCacheEvictionTest : public testing::Test {
@@ -304,11 +380,11 @@ class HttpAuthCacheEvictionTest : public testing::Test {
HttpAuthCacheEvictionTest() : origin_("http://www.google.com") { }
std::string GenerateRealm(int realm_i) {
- return StringPrintf("Realm %d", realm_i);
+ return base::StringPrintf("Realm %d", realm_i);
}
std::string GeneratePath(int realm_i, int path_i) {
- return StringPrintf("/%d/%d/x/y", realm_i, path_i);
+ return base::StringPrintf("/%d/%d/x/y", realm_i, path_i);
}
void AddRealm(int realm_i) {
@@ -316,13 +392,13 @@ class HttpAuthCacheEvictionTest : public testing::Test {
}
void AddPathToRealm(int realm_i, int path_i) {
- cache_.Add(origin_, GenerateRealm(realm_i), "basic", "",
- L"username", L"password", GeneratePath(realm_i, path_i));
+ cache_.Add(origin_, GenerateRealm(realm_i), kBasic, "",
+ kUsername, kPassword, GeneratePath(realm_i, path_i));
}
void CheckRealmExistence(int realm_i, bool exists) {
const HttpAuthCache::Entry* entry =
- cache_.Lookup(origin_, GenerateRealm(realm_i), "basic");
+ cache_.Lookup(origin_, GenerateRealm(realm_i), kBasic);
if (exists) {
EXPECT_FALSE(entry == NULL);
EXPECT_EQ(GenerateRealm(realm_i), entry->realm());
diff --git a/net/http/http_auth_controller.cc b/net/http/http_auth_controller.cc
index c077ee8..7fe07f4 100644
--- a/net/http/http_auth_controller.cc
+++ b/net/http/http_auth_controller.cc
@@ -5,12 +5,16 @@
#include "net/http/http_auth_controller.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/auth.h"
#include "net/base/host_resolver.h"
#include "net/base/net_util.h"
+#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_request_info.h"
+#include "net/http/http_response_headers.h"
namespace net {
@@ -50,14 +54,16 @@ std::string AuthChallengeLogMessage(HttpResponseHeaders* headers) {
HttpAuthController::HttpAuthController(
HttpAuth::Target target,
const GURL& auth_url,
- scoped_refptr<HttpNetworkSession> session)
+ HttpAuthCache* http_auth_cache,
+ HttpAuthHandlerFactory* http_auth_handler_factory)
: target_(target),
auth_url_(auth_url),
auth_origin_(auth_url.GetOrigin()),
auth_path_(HttpAuth::AUTH_PROXY ? std::string() : auth_url.path()),
embedded_identity_used_(false),
default_credentials_used_(false),
- session_(session),
+ http_auth_cache_(http_auth_cache),
+ http_auth_handler_factory_(http_auth_handler_factory),
ALLOW_THIS_IN_INITIALIZER_LIST(
io_callback_(this, &HttpAuthController::OnIOComplete)),
user_callback_(NULL) {
@@ -73,8 +79,8 @@ int HttpAuthController::MaybeGenerateAuthToken(const HttpRequestInfo* request,
bool needs_auth = HaveAuth() || SelectPreemptiveAuth(net_log);
if (!needs_auth)
return OK;
- const std::wstring* username = NULL;
- const std::wstring* password = NULL;
+ const string16* username = NULL;
+ const string16* password = NULL;
if (identity_.source != HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS) {
username = &identity_.username;
password = &identity_.password;
@@ -109,14 +115,14 @@ bool HttpAuthController::SelectPreemptiveAuth(const BoundNetLog& net_log) {
// is expected to be fast. LookupByPath() is fast in the common case, since
// the number of http auth cache entries is expected to be very small.
// (For most users in fact, it will be 0.)
- HttpAuthCache::Entry* entry = session_->auth_cache()->LookupByPath(
+ HttpAuthCache::Entry* entry = http_auth_cache_->LookupByPath(
auth_origin_, auth_path_);
if (!entry)
return false;
// Try to create a handler using the previous auth challenge.
scoped_ptr<HttpAuthHandler> handler_preemptive;
- int rv_create = session_->http_auth_handler_factory()->
+ int rv_create = http_auth_handler_factory_->
CreatePreemptiveAuthHandlerFromString(entry->auth_challenge(), target_,
auth_origin_,
entry->IncrementNonceCount(),
@@ -148,29 +154,52 @@ int HttpAuthController::HandleAuthChallenge(
const BoundNetLog& net_log) {
DCHECK(headers);
DCHECK(auth_origin_.is_valid());
-
LOG(INFO) << "The " << HttpAuth::GetAuthTargetString(target_) << " "
<< auth_origin_ << " requested auth"
<< AuthChallengeLogMessage(headers.get());
- // The auth we tried just failed, hence it can't be valid. Remove it from
- // the cache so it won't be used again.
- // TODO(wtc): IsFinalRound is not the right condition. In a multi-round
- // auth sequence, the server may fail the auth in round 1 if our first
- // authorization header is broken. We should inspect response_.headers to
- // determine if the server already failed the auth or wants us to continue.
- // See http://crbug.com/21015.
- if (HaveAuth() && handler_->IsFinalRound()) {
- InvalidateRejectedAuthFromCache();
- handler_.reset();
- identity_ = HttpAuth::Identity();
+ // Give the existing auth handler first try at the authentication headers.
+ // This will also evict the entry in the HttpAuthCache if the previous
+ // challenge appeared to be rejected, or is using a stale nonce in the Digest
+ // case.
+ if (HaveAuth()) {
+ std::string challenge_used;
+ HttpAuth::AuthorizationResult result = HttpAuth::HandleChallengeResponse(
+ handler_.get(), headers, target_, disabled_schemes_, &challenge_used);
+ switch (result) {
+ case HttpAuth::AUTHORIZATION_RESULT_ACCEPT:
+ break;
+ case HttpAuth::AUTHORIZATION_RESULT_INVALID:
+ case HttpAuth::AUTHORIZATION_RESULT_REJECT:
+ InvalidateCurrentHandler();
+ break;
+ case HttpAuth::AUTHORIZATION_RESULT_STALE:
+ if (http_auth_cache_->UpdateStaleChallenge(auth_origin_,
+ handler_->realm(),
+ handler_->scheme(),
+ challenge_used)) {
+ handler_.reset();
+ identity_ = HttpAuth::Identity();
+ } else {
+ // It's possible that a server could incorrectly issue a stale
+ // response when the entry is not in the cache. Just evict the
+ // current value from the cache.
+ InvalidateCurrentHandler();
+ }
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
}
identity_.invalid = true;
- if (target_ != HttpAuth::AUTH_SERVER || !do_not_send_server_auth) {
+ bool can_send_auth = (target_ != HttpAuth::AUTH_SERVER ||
+ !do_not_send_server_auth);
+ if (!handler_.get() && can_send_auth) {
// Find the best authentication challenge that we support.
- HttpAuth::ChooseBestChallenge(session_->http_auth_handler_factory(),
+ HttpAuth::ChooseBestChallenge(http_auth_handler_factory_,
headers, target_, auth_origin_,
disabled_schemes_, net_log,
&handler_);
@@ -200,9 +229,6 @@ int HttpAuthController::HandleAuthChallenge(
SelectNextAuthIdentityToTry();
} else {
// Proceed with the existing identity or a null identity.
- //
- // TODO(wtc): Add a safeguard against infinite transaction restarts, if
- // the server keeps returning "NTLM".
identity_.invalid = false;
}
@@ -219,8 +245,8 @@ int HttpAuthController::HandleAuthChallenge(
return OK;
}
-void HttpAuthController::ResetAuth(const std::wstring& username,
- const std::wstring& password) {
+void HttpAuthController::ResetAuth(const string16& username,
+ const string16& password) {
DCHECK(identity_.invalid || (username.empty() && password.empty()));
if (identity_.invalid) {
@@ -252,14 +278,20 @@ void HttpAuthController::ResetAuth(const std::wstring& username,
case HttpAuth::IDENT_SRC_DEFAULT_CREDENTIALS:
break;
default:
- session_->auth_cache()->Add(auth_origin_, handler_->realm(),
- handler_->scheme(), handler_->challenge(),
- identity_.username, identity_.password,
- auth_path_);
+ http_auth_cache_->Add(auth_origin_, handler_->realm(),
+ handler_->scheme(), handler_->challenge(),
+ identity_.username, identity_.password,
+ auth_path_);
break;
}
}
+void HttpAuthController::InvalidateCurrentHandler() {
+ InvalidateRejectedAuthFromCache();
+ handler_.reset();
+ identity_ = HttpAuth::Identity();
+}
+
void HttpAuthController::InvalidateRejectedAuthFromCache() {
DCHECK(HaveAuth());
@@ -273,9 +305,9 @@ void HttpAuthController::InvalidateRejectedAuthFromCache() {
// Clear the cache entry for the identity we just failed on.
// Note: we require the username/password to match before invalidating
// since the entry in the cache may be newer than what we used last time.
- session_->auth_cache()->Remove(auth_origin_, handler_->realm(),
- handler_->scheme(), identity_.username,
- identity_.password);
+ http_auth_cache_->Remove(auth_origin_, handler_->realm(),
+ handler_->scheme(), identity_.username,
+ identity_.password);
}
bool HttpAuthController::SelectNextAuthIdentityToTry() {
@@ -299,8 +331,8 @@ bool HttpAuthController::SelectNextAuthIdentityToTry() {
// Check the auth cache for a realm entry.
HttpAuthCache::Entry* entry =
- session_->auth_cache()->Lookup(auth_origin_, handler_->realm(),
- handler_->scheme());
+ http_auth_cache_->Lookup(auth_origin_, handler_->realm(),
+ handler_->scheme());
if (entry) {
identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
@@ -352,6 +384,10 @@ void HttpAuthController::OnIOComplete(int result) {
}
}
+scoped_refptr<AuthChallengeInfo> HttpAuthController::auth_info() {
+ return auth_info_;
+}
+
bool HttpAuthController::IsAuthSchemeDisabled(const std::string& scheme) const {
return disabled_schemes_.find(scheme) != disabled_schemes_.end();
}
diff --git a/net/http/http_auth_controller.h b/net/http/http_auth_controller.h
index 9bc8d59..097c4bc 100644
--- a/net/http/http_auth_controller.h
+++ b/net/http/http_auth_controller.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_AUTH_CONTROLLER_H_
#define NET_HTTP_HTTP_AUTH_CONTROLLER_H_
+#pragma once
#include <set>
#include <string>
@@ -11,6 +12,7 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "googleurl/src/gurl.h"
#include "net/base/completion_callback.h"
#include "net/base/net_log.h"
@@ -19,9 +21,9 @@
namespace net {
class AuthChallengeInfo;
-class HostResolver;
class HttpAuthHandler;
-class HttpNetworkSession;
+class HttpAuthHandlerFactory;
+class HttpAuthCache;
class HttpRequestHeaders;
struct HttpRequestInfo;
@@ -29,8 +31,10 @@ class HttpAuthController : public base::RefCounted<HttpAuthController> {
public:
// The arguments are self explanatory except possibly for |auth_url|, which
// should be both the auth target and auth path in a single url argument.
- HttpAuthController(HttpAuth::Target target, const GURL& auth_url,
- scoped_refptr<HttpNetworkSession> session);
+ HttpAuthController(HttpAuth::Target target,
+ const GURL& auth_url,
+ HttpAuthCache* http_auth_cache,
+ HttpAuthHandlerFactory* http_auth_handler_factory);
// Generate an authentication token for |target| if necessary. The return
// value is a net error code. |OK| will be returned both in the case that
@@ -54,8 +58,8 @@ class HttpAuthController : public base::RefCounted<HttpAuthController> {
const BoundNetLog& net_log);
// Store the supplied credentials and prepare to restart the auth.
- virtual void ResetAuth(const std::wstring& username,
- const std::wstring& password);
+ virtual void ResetAuth(const string16& username,
+ const string16& password);
virtual bool HaveAuthHandler() const {
return handler_.get() != NULL;
@@ -65,23 +69,25 @@ class HttpAuthController : public base::RefCounted<HttpAuthController> {
return handler_.get() && !identity_.invalid;
}
- virtual scoped_refptr<AuthChallengeInfo> auth_info() {
- return auth_info_;
- }
+ virtual scoped_refptr<AuthChallengeInfo> auth_info();
virtual bool IsAuthSchemeDisabled(const std::string& scheme) const;
virtual void DisableAuthScheme(const std::string& scheme);
- protected: // So that we can mock this object.
+ private:
+ // So that we can mock this object.
friend class base::RefCounted<HttpAuthController>;
+
virtual ~HttpAuthController();
- private:
// Searches the auth cache for an entry that encompasses the request's path.
// If such an entry is found, updates |identity_| and |handler_| with the
// cache entry's data and returns true.
bool SelectPreemptiveAuth(const BoundNetLog& net_log);
+ // Invalidates the current handler, including cache.
+ void InvalidateCurrentHandler();
+
// Invalidates any auth cache entries after authentication has failed.
// The identity that was rejected is |identity_|.
void InvalidateRejectedAuthFromCache();
@@ -136,7 +142,11 @@ class HttpAuthController : public base::RefCounted<HttpAuthController> {
// in response to an HTTP authentication challenge.
bool default_credentials_used_;
- scoped_refptr<HttpNetworkSession> session_;
+ // These two are owned by the HttpNetworkSession/IOThread, which own the
+ // objects which reference |this|. Therefore, these raw pointers are valid
+ // for the lifetime of this object.
+ HttpAuthCache* const http_auth_cache_;
+ HttpAuthHandlerFactory* const http_auth_handler_factory_;
std::set<std::string> disabled_schemes_;
diff --git a/net/http/http_auth_filter.cc b/net/http/http_auth_filter.cc
index 80d6e0c..a61e7f7 100644
--- a/net/http/http_auth_filter.cc
+++ b/net/http/http_auth_filter.cc
@@ -16,7 +16,9 @@ typedef std::set<string16> RegistryWhitelist;
// entries in the registry mean that you are only allowed to connect to the site
// via HTTPS and still be considered 'safe'.
-HttpAuthFilterWhitelist::HttpAuthFilterWhitelist() {
+HttpAuthFilterWhitelist::HttpAuthFilterWhitelist(
+ const std::string& server_whitelist) {
+ SetWhitelist(server_whitelist);
}
HttpAuthFilterWhitelist::~HttpAuthFilterWhitelist() {
diff --git a/net/http/http_auth_filter.h b/net/http/http_auth_filter.h
index 8a2524c..334bc91 100644
--- a/net/http/http_auth_filter.h
+++ b/net/http/http_auth_filter.h
@@ -4,12 +4,11 @@
#ifndef NET_HTTP_HTTP_AUTH_FILTER_H_
#define NET_HTTP_HTTP_AUTH_FILTER_H_
+#pragma once
#include <list>
-#include <set>
#include <string>
-#include "base/string_util.h"
#include "net/http/http_auth.h"
#include "net/proxy/proxy_bypass_rules.h"
@@ -35,16 +34,12 @@ class HttpAuthFilter {
// All proxies are allowed.
class HttpAuthFilterWhitelist : public HttpAuthFilter {
public:
- HttpAuthFilterWhitelist();
+ explicit HttpAuthFilterWhitelist(const std::string& server_whitelist);
virtual ~HttpAuthFilterWhitelist();
// HttpAuthFilter methods:
virtual bool IsValid(const GURL& url, HttpAuth::Target target) const;
- // Installs the whitelist.
- // |server_whitelist| is parsed by ProxyBypassRules.
- void SetWhitelist(const std::string& server_whitelist);
-
// Adds an individual URL |filter| to the list, of the specified |target|.
bool AddFilter(const std::string& filter, HttpAuth::Target target);
@@ -54,6 +49,10 @@ class HttpAuthFilterWhitelist : public HttpAuthFilter {
const ProxyBypassRules& rules() const { return rules_; }
private:
+ // Installs the whitelist.
+ // |server_whitelist| is parsed by ProxyBypassRules.
+ void SetWhitelist(const std::string& server_whitelist);
+
// We are using ProxyBypassRules because they have the functionality that we
// want, but we are not using it for proxy bypass.
ProxyBypassRules rules_;
diff --git a/net/http/http_auth_filter_unittest.cc b/net/http/http_auth_filter_unittest.cc
index df61e14..c7f91f9 100644
--- a/net/http/http_auth_filter_unittest.cc
+++ b/net/http/http_auth_filter_unittest.cc
@@ -4,7 +4,6 @@
#include <iostream>
-#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "googleurl/src/gurl.h"
@@ -78,7 +77,7 @@ static const UrlData urls[] = {
TEST(HttpAuthFilterTest, EmptyFilter) {
// Create an empty filter
- HttpAuthFilterWhitelist filter;
+ HttpAuthFilterWhitelist filter("");
for (size_t i = 0; i < arraysize(urls); i++) {
EXPECT_EQ(urls[i].target == HttpAuth::AUTH_PROXY,
filter.IsValid(urls[i].url, urls[i].target))
@@ -88,7 +87,6 @@ TEST(HttpAuthFilterTest, EmptyFilter) {
TEST(HttpAuthFilterTest, NonEmptyFilter) {
// Create an non-empty filter
- HttpAuthFilterWhitelist filter;
std::string server_whitelist_filter_string;
for (size_t i = 0; i < arraysize(server_whitelist_array); ++i) {
if (!server_whitelist_filter_string.empty())
@@ -96,7 +94,7 @@ TEST(HttpAuthFilterTest, NonEmptyFilter) {
server_whitelist_filter_string += "*";
server_whitelist_filter_string += server_whitelist_array[i];
}
- filter.SetWhitelist(server_whitelist_filter_string);
+ HttpAuthFilterWhitelist filter(server_whitelist_filter_string);
for (size_t i = 0; i < arraysize(urls); i++) {
EXPECT_EQ(urls[i].matches, filter.IsValid(urls[i].url, urls[i].target))
<< " " << i << ": " << urls[i].url;
diff --git a/net/http/http_auth_filter_win.h b/net/http/http_auth_filter_win.h
index f819523..ba15084 100644
--- a/net/http/http_auth_filter_win.h
+++ b/net/http/http_auth_filter_win.h
@@ -4,13 +4,12 @@
#ifndef NET_HTTP_HTTP_AUTH_FILTER_WIN_H_
#define NET_HTTP_HTTP_AUTH_FILTER_WIN_H_
-
-#include <string>
+#pragma once
#include "build/build_config.h"
#if defined(OS_WIN)
-#include "base/string_util.h"
+#include "base/string16.h"
namespace net {
diff --git a/net/http/http_auth_gssapi_posix.cc b/net/http/http_auth_gssapi_posix.cc
index 5c88375..fdbef63 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/singleton.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -96,7 +97,7 @@ std::string DisplayStatus(OM_uint32 major_status,
OM_uint32 minor_status) {
if (major_status == GSS_S_COMPLETE)
return "OK";
- return StringPrintf("0x%08X 0x%08X", major_status, minor_status);
+ return base::StringPrintf("0x%08X 0x%08X", major_status, minor_status);
}
std::string DisplayCode(GSSAPILibrary* gssapi_lib,
@@ -106,7 +107,7 @@ std::string DisplayCode(GSSAPILibrary* gssapi_lib,
const size_t kMaxMsgLength = 4096;
// msg_ctx needs to be outside the loop because it is invoked multiple times.
OM_uint32 msg_ctx = 0;
- std::string rv = StringPrintf("(0x%08X)", status);
+ std::string rv = base::StringPrintf("(0x%08X)", status);
// This loop should continue iterating until msg_ctx is 0 after the first
// iteration. To be cautious and prevent an infinite loop, it stops after
@@ -114,7 +115,7 @@ std::string DisplayCode(GSSAPILibrary* gssapi_lib,
// individual message may exceed |kMaxMsgLength|, and the final result
// will not exceed |kMaxMsgLength|*2-1.
for (int i = 0; i < kMaxDisplayIterations && rv.size() < kMaxMsgLength;
- ++i) {
+ ++i) {
OM_uint32 min_stat;
gss_buffer_desc_struct msg = GSS_C_EMPTY_BUFFER;
OM_uint32 maj_stat =
@@ -125,8 +126,8 @@ std::string DisplayCode(GSSAPILibrary* gssapi_lib,
static_cast<int>(kMaxMsgLength) :
static_cast<int>(msg.length);
if (msg_len > 0 && msg.value != NULL) {
- rv += StringPrintf(" %.*s", msg_len,
- static_cast<char*>(msg.value));
+ rv += base::StringPrintf(" %.*s", msg_len,
+ static_cast<char*>(msg.value));
}
}
gssapi_lib->release_buffer(&min_stat, &msg);
@@ -143,7 +144,8 @@ std::string DisplayExtendedStatus(GSSAPILibrary* gssapi_lib,
return "OK";
std::string major = DisplayCode(gssapi_lib, major_status, GSS_C_GSS_CODE);
std::string minor = DisplayCode(gssapi_lib, minor_status, GSS_C_MECH_CODE);
- return StringPrintf("Major: %s | Minor: %s", major.c_str(), minor.c_str());
+ return base::StringPrintf("Major: %s | Minor: %s", major.c_str(),
+ minor.c_str());
}
// ScopedName releases a gss_name_t when it goes out of scope.
@@ -253,11 +255,11 @@ std::string DescribeOid(GSSAPILibrary* gssapi_lib, const gss_OID oid) {
}
}
if (!str[str_length]) {
- output += StringPrintf("\"%s\"", str);
+ output += base::StringPrintf("\"%s\"", str);
return output;
}
}
- output = StringPrintf("(%u) \"", byte_length);
+ output = base::StringPrintf("(%u) \"", byte_length);
if (!oid->elements) {
output += "<NULL>";
return output;
@@ -267,7 +269,7 @@ std::string DescribeOid(GSSAPILibrary* gssapi_lib, const gss_OID oid) {
// Don't print more than |kMaxCharsToPrint| characters.
size_t i = 0;
for ( ; (i < byte_length) && (i < kMaxCharsToPrint); ++i) {
- output += StringPrintf("\\x%02X", elements[i]);
+ output += base::StringPrintf("\\x%02X", elements[i]);
}
if (i >= kMaxCharsToPrint)
output += "...";
@@ -299,42 +301,6 @@ std::string DescribeOid(GSSAPILibrary* gssapi_lib, const gss_OID oid) {
return output;
}
-std::string DescribeBuffer(const gss_buffer_t buffer) {
- if (!buffer)
- return "<NULL>";
- size_t length = buffer->length;
- std::string output(StringPrintf("(%" PRIuS ") ", length));
- if (!buffer->value) {
- output += "<NULL>";
- return output;
- }
- const char* value =
- reinterpret_cast<const char*>(buffer->value);
- bool is_printable = true;
- for (size_t i = 0; i < length; ++i) {
- if (!isprint(value[i])) {
- // Allow the last character to be a '0'.
- if ((i < (length - 1)) && !value[i])
- continue;
- is_printable = false;
- break;
- }
- }
- if (is_printable) {
- output += "\"";
- output += value;
- output += "\"";
- } else {
- output += "[";
- for (size_t i = 0; i < buffer->length; ++i) {
- output += StringPrintf("\\x%02X", value[i] & 0x0FF);
- }
- output += "]";
- }
-
- return output;
-}
-
std::string DescribeName(GSSAPILibrary* gssapi_lib, const gss_name_t name) {
OM_uint32 major_status = 0;
OM_uint32 minor_status = 0;
@@ -348,19 +314,19 @@ std::string DescribeName(GSSAPILibrary* gssapi_lib, const gss_name_t name) {
ScopedBuffer scoped_output_name(&output_name_buffer, gssapi_lib);
if (major_status != GSS_S_COMPLETE) {
std::string error =
- StringPrintf("Unable to describe name 0x%p, %s",
- name,
- DisplayExtendedStatus(gssapi_lib,
- major_status,
- minor_status).c_str());
+ base::StringPrintf("Unable to describe name 0x%p, %s",
+ name,
+ DisplayExtendedStatus(gssapi_lib,
+ major_status,
+ minor_status).c_str());
return error;
}
int len = output_name_buffer.length;
- std::string description =
- StringPrintf("%*s (Type %s)",
- len,
- reinterpret_cast<const char*>(output_name_buffer.value),
- DescribeOid(gssapi_lib, output_name_type).c_str());
+ std::string description = base::StringPrintf(
+ "%*s (Type %s)",
+ len,
+ reinterpret_cast<const char*>(output_name_buffer.value),
+ DescribeOid(gssapi_lib, output_name_type).c_str());
return description;
}
@@ -388,32 +354,32 @@ std::string DescribeContext(GSSAPILibrary* gssapi_lib,
ScopedName(targ_name, gssapi_lib);
if (major_status != GSS_S_COMPLETE) {
std::string error =
- StringPrintf("Unable to describe context 0x%p, %s",
- context_handle,
- DisplayExtendedStatus(gssapi_lib,
- major_status,
- minor_status).c_str());
+ base::StringPrintf("Unable to describe context 0x%p, %s",
+ context_handle,
+ DisplayExtendedStatus(gssapi_lib,
+ major_status,
+ minor_status).c_str());
return error;
}
std::string source(DescribeName(gssapi_lib, src_name));
std::string target(DescribeName(gssapi_lib, targ_name));
- std::string description = StringPrintf("Context 0x%p: "
- "Source \"%s\", "
- "Target \"%s\", "
- "lifetime %d, "
- "mechanism %s, "
- "flags 0x%08X, "
- "local %d, "
- "open %d",
- context_handle,
- source.c_str(),
- target.c_str(),
- lifetime_rec,
- DescribeOid(gssapi_lib,
- mech_type).c_str(),
- ctx_flags,
- locally_initiated,
- open);
+ std::string description = base::StringPrintf("Context 0x%p: "
+ "Source \"%s\", "
+ "Target \"%s\", "
+ "lifetime %d, "
+ "mechanism %s, "
+ "flags 0x%08X, "
+ "local %d, "
+ "open %d",
+ context_handle,
+ source.c_str(),
+ target.c_str(),
+ lifetime_rec,
+ DescribeOid(gssapi_lib,
+ mech_type).c_str(),
+ ctx_flags,
+ locally_initiated,
+ open);
return description;
}
@@ -482,26 +448,26 @@ base::NativeLibrary GSSAPISharedLibrary::LoadSharedLibrary() {
return NULL;
}
-#define BIND(lib, x) \
- gss_##x##_type x = reinterpret_cast<gss_##x##_type>( \
- base::GetFunctionPointerFromNativeLibrary(lib, "gss_" #x)); \
- if (x == NULL) { \
- LOG(WARNING) << "Unable to bind function \"" << "gss_" #x << "\""; \
- return false; \
+#define BIND(lib, x) \
+ gss_##x##_type x = reinterpret_cast<gss_##x##_type>( \
+ base::GetFunctionPointerFromNativeLibrary(lib, "gss_" #x)); \
+ if (x == NULL) { \
+ LOG(WARNING) << "Unable to bind function \"" << "gss_" #x << "\""; \
+ return false; \
}
bool GSSAPISharedLibrary::BindMethods(base::NativeLibrary lib) {
DCHECK(lib != NULL);
- BIND(lib, import_name)
- BIND(lib, release_name)
- BIND(lib, release_buffer)
- BIND(lib, display_name)
- BIND(lib, display_status)
- BIND(lib, init_sec_context)
- BIND(lib, wrap_size_limit)
- BIND(lib, delete_sec_context)
- BIND(lib, inquire_context)
+ BIND(lib, import_name);
+ BIND(lib, release_name);
+ BIND(lib, release_buffer);
+ BIND(lib, display_name);
+ BIND(lib, display_status);
+ BIND(lib, init_sec_context);
+ BIND(lib, wrap_size_limit);
+ BIND(lib, delete_sec_context);
+ BIND(lib, inquire_context);
import_name_ = import_name;
release_name_ = release_name;
@@ -638,14 +604,14 @@ OM_uint32 GSSAPISharedLibrary::inquire_context(
int* open) {
DCHECK(initialized_);
return inquire_context_(minor_status,
- context_handle,
- src_name,
- targ_name,
- lifetime_rec,
- mech_type,
- ctx_flags,
- locally_initiated,
- open);
+ context_handle,
+ src_name,
+ targ_name,
+ lifetime_rec,
+ mech_type,
+ ctx_flags,
+ locally_initiated,
+ open);
}
GSSAPILibrary* GSSAPILibrary::GetDefault() {
return Singleton<GSSAPISharedLibrary>::get();
@@ -677,7 +643,8 @@ HttpAuthGSSAPI::HttpAuthGSSAPI(GSSAPILibrary* library,
: scheme_(scheme),
gss_oid_(gss_oid),
library_(library),
- scoped_sec_context_(library) {
+ scoped_sec_context_(library),
+ can_delegate_(false) {
DCHECK(library_);
}
@@ -694,52 +661,54 @@ bool HttpAuthGSSAPI::NeedsIdentity() const {
return decoded_server_auth_token_.empty();
}
-bool HttpAuthGSSAPI::IsFinalRound() const {
- return !NeedsIdentity();
+void HttpAuthGSSAPI::Delegate() {
+ can_delegate_ = true;
}
-bool HttpAuthGSSAPI::ParseChallenge(HttpAuth::ChallengeTokenizer* tok) {
+HttpAuth::AuthorizationResult HttpAuthGSSAPI::ParseChallenge(
+ HttpAuth::ChallengeTokenizer* tok) {
// Verify the challenge's auth-scheme.
if (!tok->valid() ||
!LowerCaseEqualsASCII(tok->scheme(), StringToLowerASCII(scheme_).c_str()))
- return false;
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
tok->set_expect_base64_token(true);
if (!tok->GetNext()) {
- decoded_server_auth_token_.clear();
- return true;
+ // If a context has already been established, an empty Negotiate challenge
+ // should be treated as a rejection of the current attempt.
+ if (scoped_sec_context_.get() != GSS_C_NO_CONTEXT)
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+ DCHECK(decoded_server_auth_token_.empty());
+ return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
+ } else {
+ // If a context has not already been established, additional tokens should
+ // not be present in the auth challenge.
+ if (scoped_sec_context_.get() == GSS_C_NO_CONTEXT)
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
}
+ // Make sure the additional token is base64 encoded.
std::string encoded_auth_token = tok->value();
std::string decoded_auth_token;
bool base64_rv = base::Base64Decode(encoded_auth_token, &decoded_auth_token);
- if (!base64_rv) {
- LOG(ERROR) << "Base64 decoding of auth token failed.";
- return false;
- }
+ if (!base64_rv)
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
decoded_server_auth_token_ = decoded_auth_token;
- return true;
+ return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
}
-int HttpAuthGSSAPI::GenerateAuthToken(const std::wstring* username,
- const std::wstring* password,
+int HttpAuthGSSAPI::GenerateAuthToken(const string16* username,
+ const string16* password,
const std::wstring& spn,
std::string* auth_token) {
DCHECK(auth_token);
- DCHECK((username == NULL) == (password == NULL));
-
- if (!IsFinalRound()) {
- int rv = OnFirstRound(username, password);
- if (rv != OK)
- return rv;
- }
+ DCHECK(username == NULL && password == NULL);
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
input_token.length = decoded_server_auth_token_.length();
- input_token.value =
- (input_token.length > 0) ?
- const_cast<char*>(decoded_server_auth_token_.data()) :
- NULL;
+ input_token.value = (input_token.length > 0) ?
+ const_cast<char*>(decoded_server_auth_token_.data()) :
+ NULL;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
ScopedBuffer scoped_output_token(&output_token, library_);
int rv = GetNextSecurityToken(spn, &input_token, &output_token);
@@ -750,24 +719,107 @@ int HttpAuthGSSAPI::GenerateAuthToken(const std::wstring* username,
std::string encode_input(static_cast<char*>(output_token.value),
output_token.length);
std::string encode_output;
- bool ok = base::Base64Encode(encode_input, &encode_output);
- if (!ok)
- return ERR_UNEXPECTED;
+ bool base64_rv = base::Base64Encode(encode_input, &encode_output);
+ if (!base64_rv) {
+ LOG(ERROR) << "Base64 encoding of auth token failed.";
+ return ERR_ENCODING_CONVERSION_FAILED;
+ }
*auth_token = scheme_ + " " + encode_output;
return OK;
}
-int HttpAuthGSSAPI::OnFirstRound(const std::wstring* username,
- const std::wstring* password) {
- // TODO(cbentzel): Acquire credentials?
- DCHECK((username == NULL) == (password == NULL));
- username_.clear();
- password_.clear();
- if (username) {
- username_ = *username;
- password_ = *password;
+
+namespace {
+
+// GSSAPI status codes consist of a calling error (essentially, a programmer
+// bug), a routine error (defined by the RFC), and supplementary information,
+// all bitwise-or'ed together in different regions of the 32 bit return value.
+// This means a simple switch on the return codes is not sufficient.
+
+int MapImportNameStatusToError(OM_uint32 major_status) {
+ LOG(INFO) << "import_name returned 0x" << std::hex << major_status;
+ if (major_status == GSS_S_COMPLETE)
+ return OK;
+ if (GSS_CALLING_ERROR(major_status) != 0)
+ return ERR_UNEXPECTED;
+ OM_uint32 routine_error = GSS_ROUTINE_ERROR(major_status);
+ switch (routine_error) {
+ case GSS_S_FAILURE:
+ // Looking at the MIT Kerberos implementation, this typically is returned
+ // when memory allocation fails. However, the API does not guarantee
+ // that this is the case, so using ERR_UNEXPECTED rather than
+ // ERR_OUT_OF_MEMORY.
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
+ case GSS_S_BAD_NAME:
+ case GSS_S_BAD_NAMETYPE:
+ return ERR_MALFORMED_IDENTITY;
+ case GSS_S_DEFECTIVE_TOKEN:
+ // Not mentioned in the API, but part of code.
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
+ case GSS_S_BAD_MECH:
+ return ERR_UNSUPPORTED_AUTH_SCHEME;
+ default:
+ return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS;
}
- return OK;
+}
+
+int MapInitSecContextStatusToError(OM_uint32 major_status) {
+ LOG(INFO) << "init_sec_context returned 0x" << std::hex << major_status;
+ // Although GSS_S_CONTINUE_NEEDED is an additional bit, it seems like
+ // other code just checks if major_status is equivalent to it to indicate
+ // that there are no other errors included.
+ if (major_status == GSS_S_COMPLETE || major_status == GSS_S_CONTINUE_NEEDED)
+ return OK;
+ if (GSS_CALLING_ERROR(major_status) != 0)
+ return ERR_UNEXPECTED;
+ OM_uint32 routine_status = GSS_ROUTINE_ERROR(major_status);
+ switch (routine_status) {
+ case GSS_S_DEFECTIVE_TOKEN:
+ return ERR_INVALID_RESPONSE;
+ case GSS_S_DEFECTIVE_CREDENTIAL:
+ // Not expected since this implementation uses the default credential.
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
+ case GSS_S_BAD_SIG:
+ // Probably won't happen, but it's a bad response.
+ return ERR_INVALID_RESPONSE;
+ case GSS_S_NO_CRED:
+ return ERR_INVALID_AUTH_CREDENTIALS;
+ case GSS_S_CREDENTIALS_EXPIRED:
+ return ERR_INVALID_AUTH_CREDENTIALS;
+ case GSS_S_BAD_BINDINGS:
+ // This only happens with mutual authentication.
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
+ case GSS_S_NO_CONTEXT:
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
+ case GSS_S_BAD_NAMETYPE:
+ return ERR_UNSUPPORTED_AUTH_SCHEME;
+ case GSS_S_BAD_NAME:
+ return ERR_UNSUPPORTED_AUTH_SCHEME;
+ case GSS_S_BAD_MECH:
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
+ case GSS_S_FAILURE:
+ // This should be an "Unexpected Security Status" according to the
+ // GSSAPI documentation, but it's typically used to indicate that
+ // credentials are not correctly set up on a user machine, such
+ // as a missing credential cache or hitting this after calling
+ // kdestroy.
+ // TODO(cbentzel): Use minor code for even better mapping?
+ return ERR_MISSING_AUTH_CREDENTIALS;
+ default:
+ if (routine_status != 0)
+ return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS;
+ break;
+ }
+ OM_uint32 supplemental_status = GSS_SUPPLEMENTARY_INFO(major_status);
+ // Replays could indicate an attack.
+ if (supplemental_status & (GSS_S_DUPLICATE_TOKEN | GSS_S_OLD_TOKEN |
+ GSS_S_UNSEQ_TOKEN | GSS_S_GAP_TOKEN))
+ return ERR_INVALID_RESPONSE;
+
+ // At this point, every documented status has been checked.
+ return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS;
+}
+
}
int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn,
@@ -786,19 +838,22 @@ int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn,
&spn_buffer,
CHROME_GSS_C_NT_HOSTBASED_SERVICE,
&principal_name);
- if (major_status != GSS_S_COMPLETE) {
+ int rv = MapImportNameStatusToError(major_status);
+ if (rv != OK) {
LOG(ERROR) << "Problem importing name from "
<< "spn \"" << spn_principal << "\""
<< std::endl
<< DisplayExtendedStatus(library_,
major_status,
minor_status);
- return ERR_UNEXPECTED;
+ return rv;
}
ScopedName scoped_name(principal_name, library_);
// Continue creating a security context.
OM_uint32 req_flags = 0;
+ if (can_delegate_)
+ req_flags |= GSS_C_DELEG_FLAG;
major_status = library_->init_sec_context(
&minor_status,
GSS_C_NO_CREDENTIAL,
@@ -813,8 +868,8 @@ int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn,
out_token,
NULL, // ret flags
NULL);
- if (major_status != GSS_S_COMPLETE &&
- major_status != GSS_S_CONTINUE_NEEDED) {
+ rv = MapInitSecContextStatusToError(major_status);
+ if (rv != OK) {
LOG(ERROR) << "Problem initializing context. "
<< std::endl
<< DisplayExtendedStatus(library_,
@@ -822,7 +877,7 @@ int HttpAuthGSSAPI::GetNextSecurityToken(const std::wstring& spn,
minor_status)
<< std::endl
<< DescribeContext(library_, scoped_sec_context_.get());
- return ERR_MISSING_AUTH_CREDENTIALS;
+ return rv;
}
return OK;
diff --git a/net/http/http_auth_gssapi_posix.h b/net/http/http_auth_gssapi_posix.h
index f0642ea..3ea1131 100644
--- a/net/http/http_auth_gssapi_posix.h
+++ b/net/http/http_auth_gssapi_posix.h
@@ -4,22 +4,20 @@
#ifndef NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
#define NET_HTTP_HTTP_AUTH_GSSAPI_POSIX_H_
+#pragma once
#include <string>
#include "base/gtest_prod_util.h"
#include "base/native_library.h"
+#include "base/string16.h"
#include "net/http/http_auth.h"
#define GSS_USE_FUNCTION_POINTERS
#include "net/third_party/gssapi/gssapi.h"
-class GURL;
-
namespace net {
-class HttpRequestInfo;
-
extern gss_OID CHROME_GSS_C_NT_HOSTBASED_SERVICE_X;
extern gss_OID CHROME_GSS_C_NT_HOSTBASED_SERVICE;
extern gss_OID CHROME_GSS_KRB5_MECH_OID_DESC;
@@ -200,10 +198,10 @@ class GSSAPISharedLibrary : public GSSAPILibrary {
// scope.
class ScopedSecurityContext {
public:
- ScopedSecurityContext(GSSAPILibrary* gssapi_lib);
+ explicit ScopedSecurityContext(GSSAPILibrary* gssapi_lib);
~ScopedSecurityContext();
- const gss_ctx_id_t get() const { return security_context_; }
+ gss_ctx_id_t get() const { return security_context_; }
gss_ctx_id_t* receive() { return &security_context_; }
private:
@@ -225,9 +223,9 @@ class HttpAuthGSSAPI {
bool Init();
bool NeedsIdentity() const;
- bool IsFinalRound() const;
- bool ParseChallenge(HttpAuth::ChallengeTokenizer* tok);
+ HttpAuth::AuthorizationResult ParseChallenge(
+ HttpAuth::ChallengeTokenizer* tok);
// Generates an authentication token.
// The return value is an error code. If it's not |OK|, the value of
@@ -237,25 +235,27 @@ class HttpAuthGSSAPI {
// If this is the first round of a multiple round scheme, credentials are
// obtained using |*username| and |*password|. If |username| and |password|
// are NULL, the default credentials are used instead.
- int GenerateAuthToken(const std::wstring* username,
- const std::wstring* password,
+ int GenerateAuthToken(const string16* username,
+ const string16* password,
const std::wstring& spn,
std::string* auth_token);
+ // Delegation is allowed on the Kerberos ticket. This allows certain servers
+ // to act as the user, such as an IIS server retrieiving data from a
+ // Kerberized MSSQL server.
+ void Delegate();
+
private:
- int OnFirstRound(const std::wstring* username,
- const std::wstring* password);
int GetNextSecurityToken(const std::wstring& spn,
gss_buffer_t in_token,
gss_buffer_t out_token);
std::string scheme_;
- std::wstring username_;
- std::wstring password_;
gss_OID gss_oid_;
GSSAPILibrary* library_;
std::string decoded_server_auth_token_;
ScopedSecurityContext scoped_sec_context_;
+ bool can_delegate_;
};
} // namespace net
diff --git a/net/http/http_auth_gssapi_posix_unittest.cc b/net/http/http_auth_gssapi_posix_unittest.cc
index e66bf85..62bae71 100644
--- a/net/http/http_auth_gssapi_posix_unittest.cc
+++ b/net/http/http_auth_gssapi_posix_unittest.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/native_library.h"
#include "base/scoped_ptr.h"
+#include "net/base/net_errors.h"
#include "net/http/mock_gssapi_library_posix.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,6 +47,29 @@ void CopyBuffer(gss_buffer_t dest, const gss_buffer_t src) {
SetBuffer(dest, src->value, src->length);
}
+const char kInitialAuthResponse[] = "Mary had a little lamb";
+
+void EstablishInitialContext(test::MockGSSAPILibrary* library) {
+ test::GssContextMockImpl context_info(
+ "localhost", // Source name
+ "example.com", // Target name
+ 23, // Lifetime
+ *GSS_C_NT_HOSTBASED_SERVICE, // Mechanism
+ 0, // Context flags
+ 1, // Locally initiated
+ 0); // Open
+ gss_buffer_desc in_buffer = {0, NULL};
+ gss_buffer_desc out_buffer = {arraysize(kInitialAuthResponse),
+ const_cast<char*>(kInitialAuthResponse)};
+ library->ExpectSecurityContext(
+ "Negotiate",
+ GSS_S_CONTINUE_NEEDED,
+ 0,
+ context_info,
+ in_buffer,
+ out_buffer);
+}
+
} // namespace
TEST(HttpAuthGSSAPIPOSIXTest, GSSAPIStartup) {
@@ -144,4 +168,103 @@ TEST(HttpAuthGSSAPIPOSIXTest, GSSAPICycle) {
GSS_C_NO_BUFFER);
}
+TEST(HttpAuthGSSAPITest, ParseChallenge_FirstRound) {
+ // The first round should just consist of an unadorned "Negotiate" header.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
+ challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_TwoRounds) {
+ // The first round should just have "Negotiate", and the second round should
+ // have a valid base64 token associated with it.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&first_challenge));
+
+ // Generate an auth token and create another thing.
+ EstablishInitialContext(&mock_library);
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+
+ std::string second_challenge_text = "Negotiate Zm9vYmFy";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&second_challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_UnexpectedTokenFirstRound) {
+ // If the first round challenge has an additional authentication token, it
+ // should be treated as an invalid challenge from the server.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string challenge_text = "Negotiate Zm9vYmFy";
+ HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
+ challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
+ auth_gssapi.ParseChallenge(&challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_MissingTokenSecondRound) {
+ // If a later-round challenge is simply "Negotiate", it should be treated as
+ // an authentication challenge rejection from the server or proxy.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&first_challenge));
+
+ EstablishInitialContext(&mock_library);
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+ std::string second_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+ auth_gssapi.ParseChallenge(&second_challenge));
+}
+
+TEST(HttpAuthGSSAPITest, ParseChallenge_NonBase64EncodedToken) {
+ // If a later-round challenge has an invalid base64 encoded token, it should
+ // be treated as an invalid challenge.
+ test::MockGSSAPILibrary mock_library;
+ HttpAuthGSSAPI auth_gssapi(&mock_library, "Negotiate",
+ CHROME_GSS_KRB5_MECH_OID_DESC);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_gssapi.ParseChallenge(&first_challenge));
+
+ EstablishInitialContext(&mock_library);
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_gssapi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+ std::string second_challenge_text = "Negotiate =happyjoy=";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
+ auth_gssapi.ParseChallenge(&second_challenge));
+}
+
} // namespace net
diff --git a/net/http/http_auth_handler.cc b/net/http/http_auth_handler.cc
index 0bb017b..ccb8766 100644
--- a/net/http/http_auth_handler.cc
+++ b/net/http/http_auth_handler.cc
@@ -7,6 +7,7 @@
#include "base/histogram.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/net_errors.h"
namespace net {
@@ -27,7 +28,7 @@ HttpAuthHandler::~HttpAuthHandler() {
//static
std::string HttpAuthHandler::GenerateHistogramNameFromScheme(
const std::string& scheme) {
- return StringPrintf("Net.AuthGenerateToken_%s", scheme.c_str());
+ return base::StringPrintf("Net.AuthGenerateToken_%s", scheme.c_str());
}
bool HttpAuthHandler::InitFromChallenge(
@@ -76,8 +77,8 @@ NetLog::EventType EventTypeFromAuthTarget(HttpAuth::Target target) {
} // namespace
-int HttpAuthHandler::GenerateAuthToken(const std::wstring* username,
- const std::wstring* password,
+int HttpAuthHandler::GenerateAuthToken(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token) {
diff --git a/net/http/http_auth_handler.h b/net/http/http_auth_handler.h
index ad8c939..4c03a01 100644
--- a/net/http/http_auth_handler.h
+++ b/net/http/http_auth_handler.h
@@ -4,9 +4,11 @@
#ifndef NET_HTTP_HTTP_AUTH_HANDLER_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_H_
+#pragma once
#include <string>
+#include "base/string16.h"
#include "base/time.h"
#include "net/base/completion_callback.h"
#include "net/base/net_log.h"
@@ -16,8 +18,6 @@ class Histogram;
namespace net {
-class HostResolver;
-class ProxyInfo;
struct HttpRequestInfo;
// HttpAuthHandler is the interface for the authentication schemes
@@ -38,6 +38,22 @@ class HttpAuthHandler {
const GURL& origin,
const BoundNetLog& net_log);
+ // Determines how the previous authorization attempt was received.
+ //
+ // This is called when the server/proxy responds with a 401/407 after an
+ // earlier authorization attempt. Although this normally means that the
+ // previous attempt was rejected, in multi-round schemes such as
+ // NTLM+Negotiate it may indicate that another round of challenge+response
+ // is required. For Digest authentication it may also mean that the previous
+ // attempt used a stale nonce (and nonce-count) and that a new attempt should
+ // be made with a different nonce provided in the challenge.
+ //
+ // |challenge| must be non-NULL and have already tokenized the
+ // authentication scheme, but none of the tokens occuring after the
+ // authentication scheme.
+ virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) = 0;
+
// Generates an authentication token, potentially asynchronously.
//
// When |username| and |password| are NULL, the default credentials for
@@ -56,8 +72,8 @@ class HttpAuthHandler {
// call.
// Otherwise, there was a problem generating a token synchronously, and the
// value of |*auth_token| is unspecified.
- int GenerateAuthToken(const std::wstring* username,
- const std::wstring* password,
+ int GenerateAuthToken(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token);
@@ -107,11 +123,6 @@ class HttpAuthHandler {
// sequence used by a connection-based authentication scheme.
virtual bool NeedsIdentity() { return true; }
- // Returns true if this is the final round of the authentication sequence.
- // For Basic and Digest, the method always returns true because they are
- // single-round schemes.
- virtual bool IsFinalRound() { return true; }
-
// 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.
@@ -136,8 +147,8 @@ class HttpAuthHandler {
// |GenerateAuthTokenImpl()} is the auth-scheme specific implementation
// of generating the next auth token. Callers sohuld use |GenerateAuthToken()|
// which will in turn call |GenerateAuthTokenImpl()|
- virtual int GenerateAuthTokenImpl(const std::wstring* username,
- const std::wstring* password,
+ virtual int GenerateAuthTokenImpl(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token) = 0;
diff --git a/net/http/http_auth_handler_basic.cc b/net/http/http_auth_handler_basic.cc
index efd8c5e..355ce8b 100644
--- a/net/http/http_auth_handler_basic.cc
+++ b/net/http/http_auth_handler_basic.cc
@@ -26,30 +26,46 @@ bool HttpAuthHandlerBasic::Init(HttpAuth::ChallengeTokenizer* challenge) {
scheme_ = "basic";
score_ = 1;
properties_ = 0;
+ return ParseChallenge(challenge);
+}
+bool HttpAuthHandlerBasic::ParseChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) {
// Verify the challenge's auth-scheme.
if (!challenge->valid() ||
!LowerCaseEqualsASCII(challenge->scheme(), "basic"))
return false;
// Extract the realm (may be missing).
+ std::string realm;
while (challenge->GetNext()) {
if (LowerCaseEqualsASCII(challenge->name(), "realm"))
- realm_ = challenge->unquoted_value();
+ realm = challenge->unquoted_value();
}
- return challenge->valid();
+ if (!challenge->valid())
+ return false;
+
+ realm_ = realm;
+ return true;
+}
+
+HttpAuth::AuthorizationResult HttpAuthHandlerBasic::HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) {
+ // Basic authentication is always a single round, so any responses should
+ // be treated as a rejection.
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
}
int HttpAuthHandlerBasic::GenerateAuthTokenImpl(
- const std::wstring* username,
- const std::wstring* password,
+ const string16* username,
+ const string16* password,
const HttpRequestInfo*,
CompletionCallback*,
std::string* auth_token) {
// TODO(eroman): is this the right encoding of username/password?
std::string base64_username_password;
- if (!base::Base64Encode(WideToUTF8(*username) + ":" + WideToUTF8(*password),
+ if (!base::Base64Encode(UTF16ToUTF8(*username) + ":" + UTF16ToUTF8(*password),
&base64_username_password)) {
LOG(ERROR) << "Unexpected problem Base64 encoding.";
return ERR_UNEXPECTED;
diff --git a/net/http/http_auth_handler_basic.h b/net/http/http_auth_handler_basic.h
index 6ecb80a..a9031bb 100644
--- a/net/http/http_auth_handler_basic.h
+++ b/net/http/http_auth_handler_basic.h
@@ -4,7 +4,11 @@
#ifndef NET_HTTP_HTTP_AUTH_HANDLER_BASIC_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_BASIC_H_
+#pragma once
+#include <string>
+
+#include "base/string16.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
@@ -27,17 +31,22 @@ class HttpAuthHandlerBasic : public HttpAuthHandler {
scoped_ptr<HttpAuthHandler>* handler);
};
+ HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge);
+
protected:
virtual bool Init(HttpAuth::ChallengeTokenizer* challenge);
- virtual int GenerateAuthTokenImpl(const std::wstring* username,
- const std::wstring* password,
+ virtual int GenerateAuthTokenImpl(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token);
private:
~HttpAuthHandlerBasic() {}
+
+ bool ParseChallenge(HttpAuth::ChallengeTokenizer* challenge);
};
} // namespace net
diff --git a/net/http/http_auth_handler_basic_unittest.cc b/net/http/http_auth_handler_basic_unittest.cc
index 12e8830..f2ddbeb 100644
--- a/net/http/http_auth_handler_basic_unittest.cc
+++ b/net/http/http_auth_handler_basic_unittest.cc
@@ -2,28 +2,31 @@
// 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 <string>
#include "base/basictypes.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_handler_basic.h"
#include "net/http/http_request_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace net {
TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) {
static const struct {
- const wchar_t* username;
- const wchar_t* password;
+ const char* username;
+ const char* password;
const char* expected_credentials;
} tests[] = {
- { L"foo", L"bar", "Basic Zm9vOmJhcg==" },
+ { "foo", "bar", "Basic Zm9vOmJhcg==" },
// Empty username
- { L"", L"foobar", "Basic OmZvb2Jhcg==" },
+ { "", "foobar", "Basic OmZvb2Jhcg==" },
// Empty password
- { L"anon", L"", "Basic YW5vbjo=" },
+ { "anon", "", "Basic YW5vbjo=" },
// Empty username and empty password.
- { L"", L"", "Basic Og==" },
+ { "", "", "Basic Og==" },
};
GURL origin("http://www.example.com");
HttpAuthHandlerBasic::Factory factory;
@@ -32,8 +35,8 @@ TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) {
scoped_ptr<HttpAuthHandler> basic;
EXPECT_EQ(OK, factory.CreateAuthHandlerFromString(
challenge, HttpAuth::AUTH_SERVER, origin, BoundNetLog(), &basic));
- std::wstring username(tests[i].username);
- std::wstring password(tests[i].password);
+ string16 username(ASCIIToUTF16(tests[i].username));
+ string16 password(ASCIIToUTF16(tests[i].password));
HttpRequestInfo request_info;
std::string auth_token;
int rv = basic->GenerateAuthToken(&username, &password, &request_info,
@@ -63,6 +66,52 @@ TEST(HttpAuthHandlerBasicTest, InitFromChallenge) {
OK,
"",
},
+
+ // Realm is valid.
+ {
+ "Basic realm=\"test_realm\"",
+ OK,
+ "test_realm",
+ },
+
+ // The parser ignores tokens which aren't known.
+ {
+ "Basic realm=\"test_realm\",unknown_token=foobar",
+ OK,
+ "test_realm",
+ },
+
+ // The parser skips over tokens which aren't known.
+ {
+ "Basic unknown_token=foobar,realm=\"test_realm\"",
+ OK,
+ "test_realm",
+ },
+
+#if 0
+ // TODO(cbentzel): It's unclear what the parser should do in these cases.
+ // It seems like this should either be treated as invalid,
+ // or the spaces should be used as a separator.
+ {
+ "Basic realm=\"test_realm\" unknown_token=foobar",
+ OK,
+ "test_realm",
+ },
+
+ // The parser skips over tokens which aren't known.
+ {
+ "Basic unknown_token=foobar realm=\"test_realm\"",
+ OK,
+ "test_realm",
+ },
+#endif
+
+ // The parser fails when the first token is not "Basic".
+ {
+ "Negotiate",
+ ERR_INVALID_RESPONSE,
+ ""
+ },
};
HttpAuthHandlerBasic::Factory factory;
GURL origin("http://www.example.com");
@@ -77,4 +126,4 @@ TEST(HttpAuthHandlerBasicTest, InitFromChallenge) {
}
}
-} // namespace net
+} // namespace net
diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc
index 90090a6..7c14a47 100644
--- a/net/http/http_auth_handler_digest.cc
+++ b/net/http/http_auth_handler_digest.cc
@@ -4,10 +4,13 @@
#include "net/http/http_auth_handler_digest.h"
+#include <string>
+
#include "base/logging.h"
#include "base/md5.h"
#include "base/rand_util.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -85,9 +88,19 @@ std::string HttpAuthHandlerDigest::AlgorithmToString(int algorithm) {
}
}
+HttpAuthHandlerDigest::HttpAuthHandlerDigest(int nonce_count)
+ : stale_(false),
+ algorithm_(ALGORITHM_UNSPECIFIED),
+ qop_(0),
+ nonce_count_(nonce_count) {
+}
+
+HttpAuthHandlerDigest::~HttpAuthHandlerDigest() {
+}
+
int HttpAuthHandlerDigest::GenerateAuthTokenImpl(
- const std::wstring* username,
- const std::wstring* password,
+ const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token) {
@@ -101,9 +114,8 @@ int HttpAuthHandlerDigest::GenerateAuthTokenImpl(
GetRequestMethodAndPath(request, &method, &path);
*auth_token = AssembleCredentials(method, path,
- // TODO(eroman): is this the right encoding?
- WideToUTF8(*username),
- WideToUTF8(*password),
+ *username,
+ *password,
cnonce, nonce_count_);
return OK;
}
@@ -128,12 +140,14 @@ void HttpAuthHandlerDigest::GetRequestMethodAndPath(
std::string HttpAuthHandlerDigest::AssembleResponseDigest(
const std::string& method,
const std::string& path,
- const std::string& username,
- const std::string& password,
+ const string16& username,
+ const string16& password,
const std::string& cnonce,
const std::string& nc) const {
// ha1 = MD5(A1)
- std::string ha1 = MD5String(username + ":" + realm_ + ":" + password);
+ // TODO(eroman): is this the right encoding?
+ std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" +
+ UTF16ToUTF8(password));
if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
@@ -152,15 +166,16 @@ std::string HttpAuthHandlerDigest::AssembleResponseDigest(
std::string HttpAuthHandlerDigest::AssembleCredentials(
const std::string& method,
const std::string& path,
- const std::string& username,
- const std::string& password,
+ const string16& username,
+ const string16& password,
const std::string& cnonce,
int nonce_count) const {
// the nonce-count is an 8 digit hex string.
- std::string nc = StringPrintf("%08x", nonce_count);
+ std::string nc = base::StringPrintf("%08x", nonce_count);
- std::string authorization = std::string("Digest username=") +
- HttpUtil::Quote(username);
+ // TODO(eroman): is this the right encoding?
+ std::string authorization = (std::string("Digest username=") +
+ HttpUtil::Quote(UTF16ToUTF8(username)));
authorization += ", realm=" + HttpUtil::Quote(realm_);
authorization += ", nonce=" + HttpUtil::Quote(nonce_);
authorization += ", uri=" + HttpUtil::Quote(path);
@@ -187,6 +202,31 @@ std::string HttpAuthHandlerDigest::AssembleCredentials(
return authorization;
}
+bool HttpAuthHandlerDigest::Init(HttpAuth::ChallengeTokenizer* challenge) {
+ return ParseChallenge(challenge);
+}
+
+HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) {
+ // Even though Digest is not connection based, a "second round" is parsed
+ // to differentiate between stale and rejected responses.
+ // Note that the state of the current handler is not mutated - this way if
+ // there is a rejection the realm hasn't changed.
+ if (!challenge->valid() ||
+ !LowerCaseEqualsASCII(challenge->scheme(), "digest"))
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
+
+ // Try to find the "stale" value.
+ while (challenge->GetNext()) {
+ if (!LowerCaseEqualsASCII(challenge->name(), "stale"))
+ continue;
+ if (LowerCaseEqualsASCII(challenge->unquoted_value(), "true"))
+ return HttpAuth::AUTHORIZATION_RESULT_STALE;
+ }
+
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+}
+
// The digest challenge header looks like:
// WWW-Authenticate: Digest
// [realm="<realm-value>"]
@@ -217,9 +257,10 @@ bool HttpAuthHandlerDigest::ParseChallenge(
qop_ = QOP_UNSPECIFIED;
realm_ = nonce_ = domain_ = opaque_ = std::string();
+ // FAIL -- Couldn't match auth-scheme.
if (!challenge->valid() ||
!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
- return false; // FAIL -- Couldn't match auth-scheme.
+ return false;
// Loop through all the properties.
while (challenge->GetNext()) {
@@ -228,17 +269,18 @@ bool HttpAuthHandlerDigest::ParseChallenge(
return false;
}
+ // FAIL -- couldn't parse a property.
if (!ParseChallengeProperty(challenge->name(), challenge->unquoted_value()))
- return false; // FAIL -- couldn't parse a property.
+ return false;
}
// Check if tokenizer failed.
if (!challenge->valid())
- return false; // FAIL
+ return false;
// Check that a minimum set of properties were provided.
if (nonce_.empty())
- return false; // FAIL
+ return false;
return true;
}
@@ -264,7 +306,7 @@ bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name,
algorithm_ = ALGORITHM_MD5_SESS;
} else {
DLOG(INFO) << "Unknown value of algorithm";
- return false; // FAIL -- unsupported value of algorithm.
+ return false; // FAIL -- unsupported value of algorithm.
}
} else if (LowerCaseEqualsASCII(name, "qop")) {
// Parse the comma separated list of qops.
diff --git a/net/http/http_auth_handler_digest.h b/net/http/http_auth_handler_digest.h
index 2aa9028..0c38641 100644
--- a/net/http/http_auth_handler_digest.h
+++ b/net/http/http_auth_handler_digest.h
@@ -4,13 +4,15 @@
#ifndef NET_HTTP_HTTP_AUTH_HANDLER_DIGEST_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_DIGEST_H_
+#pragma once
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/string16.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
-// This is needed for the FRIEND_TEST() macro.
-#include "testing/gtest/include/gtest/gtest_prod.h"
-
namespace net {
// Code for handling http digest authentication.
@@ -30,21 +32,22 @@ class HttpAuthHandlerDigest : public HttpAuthHandler {
scoped_ptr<HttpAuthHandler>* handler);
};
+ HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge);
+
protected:
- virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) {
- return ParseChallenge(challenge);
- }
+ virtual bool Init(HttpAuth::ChallengeTokenizer* challenge);
- virtual int GenerateAuthTokenImpl(const std::wstring* username,
- const std::wstring* password,
+ virtual int GenerateAuthTokenImpl(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token);
private:
- FRIEND_TEST(HttpAuthHandlerDigestTest, ParseChallenge);
- FRIEND_TEST(HttpAuthHandlerDigestTest, AssembleCredentials);
- FRIEND_TEST(HttpNetworkTransactionTest, DigestPreAuthNonceCount);
+ FRIEND_TEST_ALL_PREFIXES(HttpAuthHandlerDigestTest, ParseChallenge);
+ FRIEND_TEST_ALL_PREFIXES(HttpAuthHandlerDigestTest, AssembleCredentials);
+ FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest, DigestPreAuthNonceCount);
// Possible values for the "algorithm" property.
enum DigestAlgorithm {
@@ -68,9 +71,8 @@ class HttpAuthHandlerDigest : public HttpAuthHandler {
QOP_AUTH_INT = 1 << 1,
};
- explicit HttpAuthHandlerDigest(int nonce_count) : nonce_count_(nonce_count) {}
-
- ~HttpAuthHandlerDigest() {}
+ explicit HttpAuthHandlerDigest(int nonce_count);
+ ~HttpAuthHandlerDigest();
// Parse the challenge, saving the results into this instance.
// Returns true on success.
@@ -96,16 +98,16 @@ class HttpAuthHandlerDigest : public HttpAuthHandler {
// Build up the 'response' production.
std::string AssembleResponseDigest(const std::string& method,
const std::string& path,
- const std::string& username,
- const std::string& password,
+ const string16& username,
+ const string16& password,
const std::string& cnonce,
const std::string& nc) const;
// Build up the value for (Authorization/Proxy-Authorization).
std::string AssembleCredentials(const std::string& method,
const std::string& path,
- const std::string& username,
- const std::string& password,
+ const string16& username,
+ const string16& password,
const std::string& cnonce,
int nonce_count) const;
@@ -120,7 +122,7 @@ class HttpAuthHandlerDigest : public HttpAuthHandler {
std::string opaque_;
bool stale_;
DigestAlgorithm algorithm_;
- int qop_; // Bitfield of QualityOfProtection
+ int qop_; // Bitfield of QualityOfProtection
int nonce_count_;
diff --git a/net/http/http_auth_handler_digest_unittest.cc b/net/http/http_auth_handler_digest_unittest.cc
index b1782f6..8026613 100644
--- a/net/http/http_auth_handler_digest_unittest.cc
+++ b/net/http/http_auth_handler_digest_unittest.cc
@@ -2,11 +2,14 @@
// 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 <string>
#include "base/basictypes.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_handler_digest.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -276,15 +279,46 @@ TEST(HttpAuthHandlerDigestTest, AssembleCredentials) {
HttpAuthHandlerDigest* digest =
static_cast<HttpAuthHandlerDigest*>(handler.get());
- std::string creds = digest->AssembleCredentials(tests[i].req_method,
- tests[i].req_path,
- tests[i].username,
- tests[i].password,
- tests[i].cnonce,
- tests[i].nonce_count);
+ std::string creds =
+ digest->AssembleCredentials(tests[i].req_method,
+ tests[i].req_path,
+ ASCIIToUTF16(tests[i].username),
+ ASCIIToUTF16(tests[i].password),
+ tests[i].cnonce,
+ tests[i].nonce_count);
EXPECT_STREQ(tests[i].expected_creds, creds.c_str());
}
}
+TEST(HttpAuthHandlerDigest, HandleAnotherChallenge_Failed) {
+ scoped_ptr<HttpAuthHandlerDigest::Factory> factory(
+ new HttpAuthHandlerDigest::Factory());
+ scoped_ptr<HttpAuthHandler> handler;
+ std::string default_challenge =
+ "Digest realm=\"Oblivion\", nonce=\"nonce-value\"";
+ GURL origin("intranet.google.com");
+ int rv = factory->CreateAuthHandlerFromString(
+ default_challenge, HttpAuth::AUTH_SERVER, origin, BoundNetLog(),
+ &handler);
+ EXPECT_EQ(OK, rv);
+
+ HttpAuth::ChallengeTokenizer tok_default(default_challenge.begin(),
+ default_challenge.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+ handler->HandleAnotherChallenge(&tok_default));
+
+ std::string stale_challenge = default_challenge + ", stale=true";
+ HttpAuth::ChallengeTokenizer tok_stale(stale_challenge.begin(),
+ stale_challenge.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_STALE,
+ handler->HandleAnotherChallenge(&tok_stale));
+
+ std::string stale_false_challenge = default_challenge + ", stale=false";
+ HttpAuth::ChallengeTokenizer tok_stale_false(stale_false_challenge.begin(),
+ stale_false_challenge.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+ handler->HandleAnotherChallenge(&tok_stale_false));
+}
+
} // namespace net
diff --git a/net/http/http_auth_handler_factory.cc b/net/http/http_auth_handler_factory.cc
index c2d011b..4ad7fe8 100644
--- a/net/http/http_auth_handler_factory.cc
+++ b/net/http/http_auth_handler_factory.cc
@@ -39,20 +39,70 @@ int HttpAuthHandlerFactory::CreatePreemptiveAuthHandlerFromString(
}
// static
-HttpAuthHandlerRegistryFactory* HttpAuthHandlerFactory::CreateDefault() {
+HttpAuthHandlerRegistryFactory* HttpAuthHandlerFactory::CreateDefault(
+ HostResolver* host_resolver) {
+ DCHECK(host_resolver);
HttpAuthHandlerRegistryFactory* registry_factory =
new HttpAuthHandlerRegistryFactory();
registry_factory->RegisterSchemeFactory(
"basic", new HttpAuthHandlerBasic::Factory());
registry_factory->RegisterSchemeFactory(
"digest", new HttpAuthHandlerDigest::Factory());
- registry_factory->RegisterSchemeFactory(
- "negotiate", new HttpAuthHandlerNegotiate::Factory());
+ HttpAuthHandlerNegotiate::Factory* negotiate_factory =
+ new HttpAuthHandlerNegotiate::Factory();
+ negotiate_factory->set_host_resolver(host_resolver);
+ registry_factory->RegisterSchemeFactory("negotiate", negotiate_factory);
registry_factory->RegisterSchemeFactory(
"ntlm", new HttpAuthHandlerNTLM::Factory());
return registry_factory;
}
+namespace {
+
+bool IsSupportedScheme(const std::vector<std::string>& supported_schemes,
+ const std::string& scheme) {
+ std::vector<std::string>::const_iterator it = std::find(
+ supported_schemes.begin(), supported_schemes.end(), scheme);
+ return it != supported_schemes.end();
+}
+
+}
+
+// static
+HttpAuthHandlerRegistryFactory* HttpAuthHandlerRegistryFactory::Create(
+ const std::vector<std::string>& supported_schemes,
+ URLSecurityManager* security_manager,
+ HostResolver* host_resolver,
+ bool negotiate_disable_cname_lookup,
+ bool negotiate_enable_port) {
+ HttpAuthHandlerRegistryFactory* registry_factory =
+ new HttpAuthHandlerRegistryFactory();
+ if (IsSupportedScheme(supported_schemes, "basic"))
+ registry_factory->RegisterSchemeFactory(
+ "basic", new HttpAuthHandlerBasic::Factory());
+ if (IsSupportedScheme(supported_schemes, "digest"))
+ registry_factory->RegisterSchemeFactory(
+ "digest", new HttpAuthHandlerDigest::Factory());
+ if (IsSupportedScheme(supported_schemes, "ntlm")) {
+ HttpAuthHandlerNTLM::Factory* ntlm_factory =
+ new HttpAuthHandlerNTLM::Factory();
+ ntlm_factory->set_url_security_manager(security_manager);
+ registry_factory->RegisterSchemeFactory("ntlm", ntlm_factory);
+ }
+ if (IsSupportedScheme(supported_schemes, "negotiate")) {
+ HttpAuthHandlerNegotiate::Factory* negotiate_factory =
+ new HttpAuthHandlerNegotiate::Factory();
+ negotiate_factory->set_url_security_manager(security_manager);
+ DCHECK(host_resolver || negotiate_disable_cname_lookup);
+ negotiate_factory->set_host_resolver(host_resolver);
+ negotiate_factory->set_disable_cname_lookup(negotiate_disable_cname_lookup);
+ negotiate_factory->set_use_port(negotiate_enable_port);
+ registry_factory->RegisterSchemeFactory("negotiate", negotiate_factory);
+ }
+
+ return registry_factory;
+}
+
HttpAuthHandlerRegistryFactory::HttpAuthHandlerRegistryFactory() {
}
diff --git a/net/http/http_auth_handler_factory.h b/net/http/http_auth_handler_factory.h
index 9e55350..06d0f83 100644
--- a/net/http/http_auth_handler_factory.h
+++ b/net/http/http_auth_handler_factory.h
@@ -4,9 +4,11 @@
#ifndef NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_FACTORY_H_
+#pragma once
#include <map>
#include <string>
+#include <vector>
#include "base/scoped_ptr.h"
#include "net/http/http_auth.h"
@@ -17,6 +19,7 @@ class GURL;
namespace net {
class BoundNetLog;
+class HostResolver;
class HttpAuthHandler;
class HttpAuthHandlerRegistryFactory;
@@ -103,7 +106,11 @@ class HttpAuthHandlerFactory {
// Creates a standard HttpAuthHandlerRegistryFactory. The caller is
// responsible for deleting the factory.
// The default factory supports Basic, Digest, NTLM, and Negotiate schemes.
- static HttpAuthHandlerRegistryFactory* CreateDefault();
+ //
+ // |host_resolver| is used by the Negotiate authentication handler to perform
+ // CNAME lookups to generate a Kerberos SPN for the server. It must be
+ // non-NULL.
+ static HttpAuthHandlerRegistryFactory* CreateDefault(HostResolver* resolver);
private:
// The URL security manager
@@ -151,6 +158,29 @@ class HttpAuthHandlerRegistryFactory : public HttpAuthHandlerFactory {
const BoundNetLog& net_log,
scoped_ptr<HttpAuthHandler>* handler);
+ // Creates an HttpAuthHandlerRegistryFactory.
+ //
+ // |supported_schemes| is a list of authentication schemes. Valid values
+ // include "basic", "digest", "ntlm", and "negotiate", where case matters.
+ //
+ // |security_manager| is used by the NTLM and Negotiate authenticators
+ // to determine which servers Integrated Authentication can be used with. If
+ // NULL, Integrated Authentication will not be used with any server.
+ //
+ // |host_resolver| is used by the Negotiate authentication handler to perform
+ // CNAME lookups to generate a Kerberos SPN for the server. If the "negotiate"
+ // scheme is used and |negotiate_disable_cname_lookup| is false,
+ // |host_resolver| must not be NULL.
+ //
+ // |negotiate_disable_cname_lookup| and |negotiate_enable_port| both control
+ // how Negotiate does SPN generation, by default these should be false.
+ static HttpAuthHandlerRegistryFactory* Create(
+ const std::vector<std::string>& supported_schemes,
+ URLSecurityManager* security_manager,
+ HostResolver* host_resolver,
+ bool negotiate_disable_cname_lookup,
+ bool negotiate_enable_port);
+
private:
typedef std::map<std::string, HttpAuthHandlerFactory*> FactoryMap;
diff --git a/net/http/http_auth_handler_factory_unittest.cc b/net/http/http_auth_handler_factory_unittest.cc
index 8dd37f0..173e951 100644
--- a/net/http/http_auth_handler_factory_unittest.cc
+++ b/net/http/http_auth_handler_factory_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/scoped_ptr.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
@@ -95,9 +96,10 @@ TEST(HttpAuthHandlerFactoryTest, RegistryFactory) {
}
TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
+ scoped_refptr<HostResolver> host_resolver(new MockHostResolver());
URLSecurityManagerAllow url_security_manager;
scoped_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault());
+ HttpAuthHandlerFactory::CreateDefault(host_resolver));
http_auth_handler_factory->SetURLSecurityManager(
"negotiate", &url_security_manager);
GURL server_origin("http://www.example.com");
@@ -111,7 +113,7 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
BoundNetLog(),
&handler);
EXPECT_EQ(OK, rv);
- EXPECT_FALSE(handler.get() == NULL);
+ ASSERT_FALSE(handler.get() == NULL);
EXPECT_STREQ("basic", handler->scheme().c_str());
EXPECT_STREQ("FooBar", handler->realm().c_str());
EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
@@ -138,7 +140,7 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
BoundNetLog(),
&handler);
EXPECT_EQ(OK, rv);
- EXPECT_FALSE(handler.get() == NULL);
+ ASSERT_FALSE(handler.get() == NULL);
EXPECT_STREQ("digest", handler->scheme().c_str());
EXPECT_STREQ("FooBar", handler->realm().c_str());
EXPECT_EQ(HttpAuth::AUTH_PROXY, handler->target());
@@ -170,7 +172,7 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
BoundNetLog(),
&handler);
EXPECT_EQ(OK, rv);
- EXPECT_FALSE(handler.get() == NULL);
+ ASSERT_FALSE(handler.get() == NULL);
EXPECT_STREQ("negotiate", handler->scheme().c_str());
EXPECT_STREQ("", handler->realm().c_str());
EXPECT_EQ(HttpAuth::AUTH_SERVER, handler->target());
diff --git a/net/http/http_auth_handler_mock.cc b/net/http/http_auth_handler_mock.cc
index 09a0356..90602d0 100644
--- a/net/http/http_auth_handler_mock.cc
+++ b/net/http/http_auth_handler_mock.cc
@@ -5,7 +5,9 @@
#include "net/http/http_auth_handler_mock.h"
#include "base/message_loop.h"
+#include "base/string_util.h"
#include "net/base/net_errors.h"
+#include "net/http/http_request_info.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -76,12 +78,23 @@ bool HttpAuthHandlerMock::Init(HttpAuth::ChallengeTokenizer* challenge) {
return true;
}
-int HttpAuthHandlerMock::GenerateAuthTokenImpl(const std::wstring* username,
- const std::wstring* password,
+HttpAuth::AuthorizationResult HttpAuthHandlerMock::HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) {
+ if (!is_connection_based())
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+ if (!challenge->valid() ||
+ !LowerCaseEqualsASCII(challenge->scheme(), "mock"))
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
+ return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
+}
+
+int HttpAuthHandlerMock::GenerateAuthTokenImpl(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token) {
first_round_ = false;
+ request_url_ = request->url;
if (generate_async_) {
EXPECT_TRUE(user_callback_ == NULL);
EXPECT_TRUE(auth_token_ == NULL);
@@ -118,6 +131,14 @@ void HttpAuthHandlerMock::OnGenerateAuthToken() {
callback->Run(generate_rv_);
}
+HttpAuthHandlerMock::Factory::Factory()
+ : do_init_from_challenge_(false) {
+ // TODO(cbentzel): Default do_init_from_challenge_ to true.
+}
+
+HttpAuthHandlerMock::Factory::~Factory() {
+}
+
void HttpAuthHandlerMock::Factory::set_mock_handler(
HttpAuthHandler* handler, HttpAuth::Target target) {
EXPECT_TRUE(handlers_[target].get() == NULL);
@@ -134,7 +155,11 @@ int HttpAuthHandlerMock::Factory::CreateAuthHandler(
scoped_ptr<HttpAuthHandler>* handler) {
if (!handlers_[target].get())
return ERR_UNEXPECTED;
- handler->swap(handlers_[target]);
+ scoped_ptr<HttpAuthHandler> tmp_handler(handlers_[target].release());
+ if (do_init_from_challenge_ &&
+ !tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
+ return ERR_INVALID_RESPONSE;
+ handler->swap(tmp_handler);
return OK;
}
diff --git a/net/http/http_auth_handler_mock.h b/net/http/http_auth_handler_mock.h
index a0ef4f0..bef8b2b 100644
--- a/net/http/http_auth_handler_mock.h
+++ b/net/http/http_auth_handler_mock.h
@@ -4,15 +4,20 @@
#ifndef NET_HTTP_HTTP_AUTH_HANDLER_MOCK_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_MOCK_H_
+#pragma once
#include <string>
+#include "base/string16.h"
#include "base/task.h"
+#include "googleurl/src/gurl.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
namespace net {
+class HostResolver;
+
// MockAuthHandler is used in tests to reliably trigger edge cases.
class HttpAuthHandlerMock : public HttpAuthHandler {
public:
@@ -36,7 +41,6 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
CompletionCallback* callback);
virtual bool NeedsIdentity() { return first_round_; }
- virtual bool IsFinalRound() { return false; }
void SetGenerateExpectation(bool async, int rv);
@@ -44,15 +48,26 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
connection_based_ = connection_based;
}
+ const GURL& request_url() const {
+ return request_url_;
+ }
+
+ HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge);
+
// The Factory class simply returns the same handler each time
// CreateAuthHandler is called.
class Factory : public HttpAuthHandlerFactory {
public:
- Factory() {}
- virtual ~Factory() {}
+ Factory();
+ virtual ~Factory();
void set_mock_handler(HttpAuthHandler* handler, HttpAuth::Target target);
+ void set_do_init_from_challenge(bool do_init_from_challenge) {
+ do_init_from_challenge_ = do_init_from_challenge;
+ }
+
virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge,
HttpAuth::Target target,
const GURL& origin,
@@ -63,13 +78,14 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
private:
scoped_ptr<HttpAuthHandler> handlers_[HttpAuth::AUTH_NUM_TARGETS];
+ bool do_init_from_challenge_;
};
protected:
virtual bool Init(HttpAuth::ChallengeTokenizer* challenge);
- virtual int GenerateAuthTokenImpl(const std::wstring* username,
- const std::wstring* password,
+ virtual int GenerateAuthTokenImpl(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token);
@@ -87,6 +103,7 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
std::string* auth_token_;
bool first_round_;
bool connection_based_;
+ GURL request_url_;
};
} // namespace net
diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc
index d7a9c50..6bbad88 100644
--- a/net/http/http_auth_handler_negotiate.cc
+++ b/net/http/http_auth_handler_negotiate.cc
@@ -5,6 +5,9 @@
#include "net/http/http_auth_handler_negotiate.h"
#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "net/base/address_family.h"
#include "net/base/host_resolver.h"
#include "net/base/net_errors.h"
@@ -44,8 +47,8 @@ HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
}
int HttpAuthHandlerNegotiate::GenerateAuthTokenImpl(
- const std::wstring* username,
- const std::wstring* password,
+ const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token) {
@@ -88,9 +91,18 @@ bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* challenge) {
if (!AllowsDefaultCredentials())
return false;
#endif
+ if (CanDelegate())
+ auth_system_.Delegate();
scheme_ = "negotiate";
score_ = 4;
properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
+ HttpAuth::AuthorizationResult auth_result =
+ auth_system_.ParseChallenge(challenge);
+ return (auth_result == HttpAuth::AUTHORIZATION_RESULT_ACCEPT);
+}
+
+HttpAuth::AuthorizationResult HttpAuthHandlerNegotiate::HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) {
return auth_system_.ParseChallenge(challenge);
}
@@ -99,10 +111,6 @@ bool HttpAuthHandlerNegotiate::NeedsIdentity() {
return auth_system_.NeedsIdentity();
}
-bool HttpAuthHandlerNegotiate::IsFinalRound() {
- return auth_system_.IsFinalRound();
-}
-
bool HttpAuthHandlerNegotiate::AllowsDefaultCredentials() {
if (target_ == HttpAuth::AUTH_PROXY)
return true;
@@ -111,6 +119,15 @@ bool HttpAuthHandlerNegotiate::AllowsDefaultCredentials() {
return url_security_manager_->CanUseDefaultCredentials(origin_);
}
+bool HttpAuthHandlerNegotiate::CanDelegate() const {
+ // TODO(cbentzel): Should delegation be allowed on proxies?
+ if (target_ == HttpAuth::AUTH_PROXY)
+ return false;
+ if (!url_security_manager_)
+ return false;
+ return url_security_manager_->CanDelegate(origin_);
+}
+
std::wstring HttpAuthHandlerNegotiate::CreateSPN(
const AddressList& address_list, const GURL& origin) {
// Kerberos Web Server SPNs are in the form HTTP/<host>:<port> through SSPI,
@@ -152,10 +169,11 @@ std::wstring HttpAuthHandlerNegotiate::CreateSPN(
static const char kSpnSeparator = '@';
#endif
if (port != 80 && port != 443 && use_port_) {
- return ASCIIToWide(StringPrintf("HTTP%c%s:%d", kSpnSeparator,
- server.c_str(), port));
+ return ASCIIToWide(base::StringPrintf("HTTP%c%s:%d", kSpnSeparator,
+ server.c_str(), port));
} else {
- return ASCIIToWide(StringPrintf("HTTP%c%s", kSpnSeparator, server.c_str()));
+ return ASCIIToWide(base::StringPrintf("HTTP%c%s", kSpnSeparator,
+ server.c_str()));
}
}
@@ -193,12 +211,12 @@ int HttpAuthHandlerNegotiate::DoLoop(int result) {
int HttpAuthHandlerNegotiate::DoResolveCanonicalName() {
next_state_ = STATE_RESOLVE_CANONICAL_NAME_COMPLETE;
- if (disable_cname_lookup_)
+ if (disable_cname_lookup_ || !resolver_)
return OK;
// TODO(cbentzel): Add reverse DNS lookup for numeric addresses.
DCHECK(!single_resolve_.get());
- HostResolver::RequestInfo info(origin_.host(), 0);
+ HostResolver::RequestInfo info(HostPortPair(origin_.host(), 0));
info.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
single_resolve_.reset(new SingleRequestHostResolver(resolver_));
return single_resolve_->Resolve(info, &address_list_, &io_callback_,
@@ -223,8 +241,8 @@ int HttpAuthHandlerNegotiate::DoResolveCanonicalNameComplete(int rv) {
int HttpAuthHandlerNegotiate::DoGenerateAuthToken() {
next_state_ = STATE_GENERATE_AUTH_TOKEN_COMPLETE;
- std::wstring* username = has_username_and_password_ ? &username_ : NULL;
- std::wstring* password = has_username_and_password_ ? &password_ : NULL;
+ string16* username = has_username_and_password_ ? &username_ : NULL;
+ string16* password = has_username_and_password_ ? &password_ : NULL;
// TODO(cbentzel): This should possibly be done async.
return auth_system_.GenerateAuthToken(username, password, spn_, auth_token_);
}
diff --git a/net/http/http_auth_handler_negotiate.h b/net/http/http_auth_handler_negotiate.h
index ec1a194..2ff4a9b 100644
--- a/net/http/http_auth_handler_negotiate.h
+++ b/net/http/http_auth_handler_negotiate.h
@@ -4,11 +4,11 @@
#ifndef NET_HTTP_HTTP_AUTH_HANDLER_NEGOTIATE_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_NEGOTIATE_H_
+#pragma once
#include <string>
-#include "build/build_config.h"
-
+#include "base/string16.h"
#include "build/build_config.h"
#include "net/base/address_list.h"
#include "net/http/http_auth_handler.h"
@@ -107,10 +107,11 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler {
virtual bool NeedsIdentity();
- virtual bool IsFinalRound();
-
virtual bool AllowsDefaultCredentials();
+ virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge);
+
// These are public for unit tests
std::wstring CreateSPN(const AddressList& address_list, const GURL& orign);
const std::wstring& spn() const { return spn_; }
@@ -118,8 +119,8 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler {
protected:
virtual bool Init(HttpAuth::ChallengeTokenizer* challenge);
- virtual int GenerateAuthTokenImpl(const std::wstring* username,
- const std::wstring* password,
+ virtual int GenerateAuthTokenImpl(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token);
@@ -141,6 +142,7 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler {
int DoResolveCanonicalNameComplete(int rv);
int DoGenerateAuthToken();
int DoGenerateAuthTokenComplete(int rv);
+ bool CanDelegate() const;
AuthSystem auth_system_;
bool disable_cname_lookup_;
@@ -155,8 +157,8 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler {
// Things which should be consistent after first call to GenerateAuthToken.
bool already_called_;
bool has_username_and_password_;
- std::wstring username_;
- std::wstring password_;
+ string16 username_;
+ string16 password_;
std::wstring spn_;
// Things which vary each round.
@@ -165,7 +167,7 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler {
State next_state_;
- URLSecurityManager* url_security_manager_;
+ const URLSecurityManager* url_security_manager_;
};
} // namespace net
diff --git a/net/http/http_auth_handler_negotiate_unittest.cc b/net/http/http_auth_handler_negotiate_unittest.cc
index 4fcdad1..5c90b4f 100644
--- a/net/http/http_auth_handler_negotiate_unittest.cc
+++ b/net/http/http_auth_handler_negotiate_unittest.cc
@@ -4,6 +4,8 @@
#include "net/http/http_auth_handler_negotiate.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
@@ -50,7 +52,7 @@ class HttpAuthHandlerNegotiateTest : public PlatformTest {
L"Negotiate", SEC_E_OK, security_package_.get());
#elif defined(OS_POSIX)
// Copied from an actual transaction!
- const char kAuthResponse[] =
+ static const char kAuthResponse[] =
"\x60\x82\x02\xCA\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01"
"\x00\x6E\x82\x02\xB9\x30\x82\x02\xB5\xA0\x03\x02\x01\x05\xA1\x03"
"\x02\x01\x0E\xA2\x07\x03\x05\x00\x00\x00\x00\x00\xA3\x82\x01\xC1"
@@ -225,9 +227,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, DisableCname) {
TestCompletionCallback callback;
HttpRequestInfo request_info;
std::string token;
- std::wstring username = L"foo";
- std::wstring password = L"bar";
- EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password,
+ EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL,
&request_info,
&callback, &token));
#if defined(OS_WIN)
@@ -246,9 +246,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameStandardPort) {
TestCompletionCallback callback;
HttpRequestInfo request_info;
std::string token;
- std::wstring username = L"foo";
- std::wstring password = L"bar";
- EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password,
+ EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL,
&request_info,
&callback, &token));
#if defined(OS_WIN)
@@ -267,9 +265,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, DisableCnameNonstandardPort) {
TestCompletionCallback callback;
HttpRequestInfo request_info;
std::string token;
- std::wstring username = L"foo";
- std::wstring password = L"bar";
- EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password,
+ EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL,
&request_info,
&callback, &token));
#if defined(OS_WIN)
@@ -288,9 +284,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, CnameSync) {
TestCompletionCallback callback;
HttpRequestInfo request_info;
std::string token;
- std::wstring username = L"foo";
- std::wstring password = L"bar";
- EXPECT_EQ(OK, auth_handler->GenerateAuthToken(&username, &password,
+ EXPECT_EQ(OK, auth_handler->GenerateAuthToken(NULL, NULL,
&request_info,
&callback, &token));
#if defined(OS_WIN)
@@ -309,10 +303,8 @@ TEST_F(HttpAuthHandlerNegotiateTest, CnameAsync) {
TestCompletionCallback callback;
HttpRequestInfo request_info;
std::string token;
- std::wstring username = L"foo";
- std::wstring password = L"bar";
EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken(
- &username, &password, &request_info, &callback, &token));
+ NULL, NULL, &request_info, &callback, &token));
EXPECT_EQ(OK, callback.WaitForResult());
#if defined(OS_WIN)
EXPECT_EQ(L"HTTP/canonical.example.com", auth_handler->spn());
diff --git a/net/http/http_auth_handler_ntlm.cc b/net/http/http_auth_handler_ntlm.cc
index d8e8a75..dddddb4 100644
--- a/net/http/http_auth_handler_ntlm.cc
+++ b/net/http/http_auth_handler_ntlm.cc
@@ -4,7 +4,9 @@
#include "net/http/http_auth_handler_ntlm.h"
+#if !defined(NTLM_SSPI)
#include "base/base64.h"
+#endif
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -14,8 +16,8 @@
namespace net {
int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
- const std::wstring* username,
- const std::wstring* password,
+ const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token) {
@@ -26,6 +28,11 @@ int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
CreateSPN(origin_),
auth_token);
#else // !defined(NTLM_SSPI)
+ // TODO(cbentzel): Shouldn't be hitting this case.
+ if (!username || !password) {
+ LOG(ERROR) << "Username and password are expected to be non-NULL.";
+ return ERR_MISSING_AUTH_CREDENTIALS;
+ }
// TODO(wtc): See if we can use char* instead of void* for in_buf and
// out_buf. This change will need to propagate to GetNextToken,
// GenerateType1Msg, and GenerateType3Msg, and perhaps further.
@@ -36,18 +43,19 @@ int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
// |username| may be in the form "DOMAIN\user". Parse it into the two
// components.
- std::wstring domain;
- std::wstring user;
- size_t backslash_idx = username->find(L'\\');
- if (backslash_idx == std::wstring::npos) {
+ string16 domain;
+ string16 user;
+ const char16 backslash_character = '\\';
+ size_t backslash_idx = username->find(backslash_character);
+ if (backslash_idx == string16::npos) {
user = *username;
} else {
domain = username->substr(0, backslash_idx);
user = username->substr(backslash_idx + 1);
}
- domain_ = WideToUTF16(domain);
- username_ = WideToUTF16(user);
- password_ = WideToUTF16(*password);
+ domain_ = domain;
+ username_ = user;
+ password_ = *password;
// Initial challenge.
if (auth_data_.empty()) {
@@ -84,27 +92,48 @@ int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
#endif
}
-// The NTLM challenge header looks like:
-// WWW-Authenticate: NTLM auth-data
-bool HttpAuthHandlerNTLM::ParseChallenge(
- HttpAuth::ChallengeTokenizer* tok) {
+bool HttpAuthHandlerNTLM::Init(HttpAuth::ChallengeTokenizer* tok) {
scheme_ = "ntlm";
score_ = 3;
properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
+ return ParseChallenge(tok, true) == HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
+}
+
+HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge) {
+ return ParseChallenge(challenge, false);
+}
+
+// The NTLM challenge header looks like:
+// WWW-Authenticate: NTLM auth-data
+HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::ParseChallenge(
+ HttpAuth::ChallengeTokenizer* tok, bool initial_challenge) {
#if defined(NTLM_SSPI)
+ // auth_sspi_ contains state for whether or not this is the initial challenge.
return auth_sspi_.ParseChallenge(tok);
#else
+ // TODO(cbentzel): Most of the logic between SSPI, GSSAPI, and portable NTLM
+ // authentication parsing could probably be shared - just need to know if
+ // there was previously a challenge round.
auth_data_.clear();
// Verify the challenge's auth-scheme.
if (!tok->valid() || !LowerCaseEqualsASCII(tok->scheme(), "ntlm"))
- return false;
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
tok->set_expect_base64_token(true);
- if (tok->GetNext())
- auth_data_.assign(tok->value_begin(), tok->value_end());
- return true;
+ if (!tok->GetNext()) {
+ if (!initial_challenge)
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+ return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
+ } else {
+ if (initial_challenge)
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
+ }
+
+ auth_data_.assign(tok->value_begin(), tok->value_end());
+ return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
#endif // defined(NTLM_SSPI)
}
diff --git a/net/http/http_auth_handler_ntlm.h b/net/http/http_auth_handler_ntlm.h
index f22a2b5..831e43d 100644
--- a/net/http/http_auth_handler_ntlm.h
+++ b/net/http/http_auth_handler_ntlm.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_AUTH_HANDLER_NTLM_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_NTLM_H_
+#pragma once
#include "build/build_config.h"
@@ -107,17 +108,16 @@ class HttpAuthHandlerNTLM : public HttpAuthHandler {
virtual bool NeedsIdentity();
- virtual bool IsFinalRound();
-
virtual bool AllowsDefaultCredentials();
+ virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ HttpAuth::ChallengeTokenizer* challenge);
+
protected:
- virtual bool Init(HttpAuth::ChallengeTokenizer* tok) {
- return ParseChallenge(tok);
- }
+ virtual bool Init(HttpAuth::ChallengeTokenizer* tok);
- virtual int GenerateAuthTokenImpl(const std::wstring* username,
- const std::wstring* password,
+ virtual int GenerateAuthTokenImpl(const string16* username,
+ const string16* password,
const HttpRequestInfo* request,
CompletionCallback* callback,
std::string* auth_token);
@@ -137,8 +137,8 @@ class HttpAuthHandlerNTLM : public HttpAuthHandler {
#endif
// Parse the challenge, saving the results into this instance.
- // Returns true on success.
- bool ParseChallenge(HttpAuth::ChallengeTokenizer* tok);
+ HttpAuth::AuthorizationResult ParseChallenge(
+ HttpAuth::ChallengeTokenizer* tok, bool initial_challenge);
// Given an input token received from the server, generate the next output
// token to be sent to the server.
diff --git a/net/http/http_auth_handler_ntlm_portable.cc b/net/http/http_auth_handler_ntlm_portable.cc
index e16d32c..d3abc98 100644
--- a/net/http/http_auth_handler_ntlm_portable.cc
+++ b/net/http/http_auth_handler_ntlm_portable.cc
@@ -653,10 +653,6 @@ bool HttpAuthHandlerNTLM::NeedsIdentity() {
return !auth_data_.empty();
}
-bool HttpAuthHandlerNTLM::IsFinalRound() {
- return !auth_data_.empty();
-}
-
bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() {
// Default credentials are not supported in the portable implementation of
// NTLM, but are supported in the SSPI implementation.
diff --git a/net/http/http_auth_handler_ntlm_win.cc b/net/http/http_auth_handler_ntlm_win.cc
index 0f67c68..1b7d1ac 100644
--- a/net/http/http_auth_handler_ntlm_win.cc
+++ b/net/http/http_auth_handler_ntlm_win.cc
@@ -9,7 +9,6 @@
#include "net/http/http_auth_handler_ntlm.h"
-#include "base/logging.h"
#include "base/string_util.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -35,10 +34,6 @@ bool HttpAuthHandlerNTLM::NeedsIdentity() {
return auth_sspi_.NeedsIdentity();
}
-bool HttpAuthHandlerNTLM::IsFinalRound() {
- return auth_sspi_.IsFinalRound();
-}
-
bool HttpAuthHandlerNTLM::AllowsDefaultCredentials() {
if (target_ == HttpAuth::AUTH_PROXY)
return true;
diff --git a/net/http/http_auth_handler_unittest.cc b/net/http/http_auth_handler_unittest.cc
index 2516745..d63b9fb 100644
--- a/net/http/http_auth_handler_unittest.cc
+++ b/net/http/http_auth_handler_unittest.cc
@@ -4,6 +4,8 @@
#include "net/http/http_auth_handler.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/base/capturing_net_log.h"
#include "net/base/net_errors.h"
#include "net/base/net_log_unittest.h"
@@ -18,8 +20,8 @@ TEST(HttpAuthHandlerTest, NetLog) {
NetLog::Source source;
GURL origin("http://www.example.com");
std::string challenge = "Mock asdf";
- std::wstring username = L"user";
- std::wstring password = L"pass";
+ string16 username = ASCIIToUTF16("user");
+ string16 password = ASCIIToUTF16("pass");
std::string auth_token;
HttpRequestInfo request;
diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc
index 221acf1..276eea4 100644
--- a/net/http/http_auth_sspi_win.cc
+++ b/net/http/http_auth_sspi_win.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/singleton.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
@@ -20,32 +21,34 @@ namespace {
int MapAcquireCredentialsStatusToError(SECURITY_STATUS status,
const SEC_WCHAR* package) {
+ LOG(INFO) << "AcquireCredentialsHandle returned 0x" << std::hex << status;
switch (status) {
case SEC_E_OK:
return OK;
case SEC_E_INSUFFICIENT_MEMORY:
return ERR_OUT_OF_MEMORY;
case SEC_E_INTERNAL_ERROR:
- return ERR_UNEXPECTED;
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
case SEC_E_NO_CREDENTIALS:
case SEC_E_NOT_OWNER:
case SEC_E_UNKNOWN_CREDENTIALS:
return ERR_INVALID_AUTH_CREDENTIALS;
case SEC_E_SECPKG_NOT_FOUND:
// This indicates that the SSPI configuration does not match expectations
- LOG(ERROR) << "Received SEC_E_SECPKG_NOT_FOUND for " << package;
return ERR_UNSUPPORTED_AUTH_SCHEME;
default:
- LOG(ERROR) << "Unexpected SECURITY_STATUS " << status;
- return ERR_UNEXPECTED;
+ LOG(WARNING)
+ << "AcquireSecurityCredentials returned undocumented status 0x"
+ << std::hex << status;
+ return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS;
}
}
int AcquireExplicitCredentials(SSPILibrary* library,
const SEC_WCHAR* package,
- const std::wstring& domain,
- const std::wstring& user,
- const std::wstring& password,
+ const string16& domain,
+ const string16& user,
+ const string16& password,
CredHandle* cred) {
SEC_WINNT_AUTH_IDENTITY identity;
identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
@@ -98,6 +101,85 @@ int AcquireDefaultCredentials(SSPILibrary* library, const SEC_WCHAR* package,
return MapAcquireCredentialsStatusToError(status, package);
}
+int MapInitializeSecurityContextStatusToError(SECURITY_STATUS status) {
+ LOG(INFO) << "InitializeSecurityContext returned 0x" << std::hex << status;
+ switch (status) {
+ case SEC_E_OK:
+ case SEC_I_CONTINUE_NEEDED:
+ return OK;
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ case SEC_I_COMPLETE_NEEDED:
+ case SEC_I_INCOMPLETE_CREDENTIALS:
+ case SEC_E_INCOMPLETE_MESSAGE:
+ case SEC_E_INTERNAL_ERROR:
+ // These are return codes reported by InitializeSecurityContext
+ // but not expected by Chrome (for example, INCOMPLETE_CREDENTIALS
+ // and INCOMPLETE_MESSAGE are intended for schannel).
+ LOG(WARNING)
+ << "InitializeSecurityContext returned unexpected status 0x"
+ << std::hex << status;
+ return ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS;
+ case SEC_E_INSUFFICIENT_MEMORY:
+ return ERR_OUT_OF_MEMORY;
+ case SEC_E_UNSUPPORTED_FUNCTION:
+ NOTREACHED();
+ return ERR_UNEXPECTED;
+ case SEC_E_INVALID_HANDLE:
+ NOTREACHED();
+ return ERR_INVALID_HANDLE;
+ case SEC_E_INVALID_TOKEN:
+ return ERR_INVALID_RESPONSE;
+ case SEC_E_LOGON_DENIED:
+ return ERR_ACCESS_DENIED;
+ case SEC_E_NO_CREDENTIALS:
+ case SEC_E_WRONG_PRINCIPAL:
+ return ERR_INVALID_AUTH_CREDENTIALS;
+ case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+ case SEC_E_TARGET_UNKNOWN:
+ return ERR_MISCONFIGURED_AUTH_ENVIRONMENT;
+ default:
+ LOG(WARNING)
+ << "InitializeSecurityContext returned undocumented status 0x"
+ << std::hex << status;
+ return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS;
+ }
+}
+
+int MapQuerySecurityPackageInfoStatusToError(SECURITY_STATUS status) {
+ LOG(INFO) << "QuerySecurityPackageInfo returned 0x" << std::hex << status;
+ switch (status) {
+ case SEC_E_OK:
+ return OK;
+ case SEC_E_SECPKG_NOT_FOUND:
+ // This isn't a documented return code, but has been encountered
+ // during testing.
+ return ERR_UNSUPPORTED_AUTH_SCHEME;
+ default:
+ LOG(WARNING)
+ << "QuerySecurityPackageInfo returned undocumented status 0x"
+ << std::hex << status;
+ return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS;
+ }
+}
+
+int MapFreeContextBufferStatusToError(SECURITY_STATUS status) {
+ LOG(INFO) << "FreeContextBuffer returned 0x" << std::hex << status;
+ switch (status) {
+ case SEC_E_OK:
+ return OK;
+ default:
+ // The documentation at
+ // http://msdn.microsoft.com/en-us/library/aa375416(VS.85).aspx
+ // only mentions that a non-zero (or non-SEC_E_OK) value is returned
+ // if the function fails, and does not indicate what the failure
+ // conditions are.
+ LOG(WARNING)
+ << "FreeContextBuffer returned undocumented status 0x"
+ << std::hex << status;
+ return ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS;
+ }
+}
+
} // anonymous namespace
HttpAuthSSPI::HttpAuthSSPI(SSPILibrary* library,
@@ -107,7 +189,8 @@ HttpAuthSSPI::HttpAuthSSPI(SSPILibrary* library,
: library_(library),
scheme_(scheme),
security_package_(security_package),
- max_token_length_(max_token_length) {
+ max_token_length_(max_token_length),
+ can_delegate_(false) {
DCHECK(library_);
SecInvalidateHandle(&cred_);
SecInvalidateHandle(&ctxt_);
@@ -125,8 +208,8 @@ bool HttpAuthSSPI::NeedsIdentity() const {
return decoded_server_auth_token_.empty();
}
-bool HttpAuthSSPI::IsFinalRound() const {
- return !decoded_server_auth_token_.empty();
+void HttpAuthSSPI::Delegate() {
+ can_delegate_ = true;
}
void HttpAuthSSPI::ResetSecurityContext() {
@@ -136,37 +219,45 @@ void HttpAuthSSPI::ResetSecurityContext() {
}
}
-bool HttpAuthSSPI::ParseChallenge(HttpAuth::ChallengeTokenizer* tok) {
+HttpAuth::AuthorizationResult HttpAuthSSPI::ParseChallenge(
+ HttpAuth::ChallengeTokenizer* tok) {
// Verify the challenge's auth-scheme.
if (!tok->valid() ||
!LowerCaseEqualsASCII(tok->scheme(), StringToLowerASCII(scheme_).c_str()))
- return false;
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
tok->set_expect_base64_token(true);
if (!tok->GetNext()) {
- decoded_server_auth_token_.clear();
- return true;
+ // If a context has already been established, an empty challenge
+ // should be treated as a rejection of the current attempt.
+ if (SecIsValidHandle(&ctxt_))
+ return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+ DCHECK(decoded_server_auth_token_.empty());
+ return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
+ } else {
+ // If a context has not already been established, additional tokens should
+ // not be present in the auth challenge.
+ if (!SecIsValidHandle(&ctxt_))
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
}
std::string encoded_auth_token = tok->value();
std::string decoded_auth_token;
bool base64_rv = base::Base64Decode(encoded_auth_token, &decoded_auth_token);
- if (!base64_rv) {
- LOG(ERROR) << "Base64 decoding of auth token failed.";
- return false;
- }
+ if (!base64_rv)
+ return HttpAuth::AUTHORIZATION_RESULT_INVALID;
decoded_server_auth_token_ = decoded_auth_token;
- return true;
+ return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
}
-int HttpAuthSSPI::GenerateAuthToken(const std::wstring* username,
- const std::wstring* password,
+int HttpAuthSSPI::GenerateAuthToken(const string16* username,
+ const string16* password,
const std::wstring& spn,
std::string* auth_token) {
DCHECK((username == NULL) == (password == NULL));
// Initial challenge.
- if (!IsFinalRound()) {
+ if (!SecIsValidHandle(&cred_)) {
int rv = OnFirstRound(username, password);
if (rv != OK)
return rv;
@@ -193,20 +284,20 @@ int HttpAuthSSPI::GenerateAuthToken(const std::wstring* username,
free(out_buf);
if (!base64_rv) {
LOG(ERROR) << "Base64 encoding of auth token failed.";
- return ERR_UNEXPECTED;
+ return ERR_ENCODING_CONVERSION_FAILED;
}
*auth_token = scheme_ + " " + encode_output;
return OK;
}
-int HttpAuthSSPI::OnFirstRound(const std::wstring* username,
- const std::wstring* password) {
+int HttpAuthSSPI::OnFirstRound(const string16* username,
+ const string16* password) {
DCHECK((username == NULL) == (password == NULL));
DCHECK(!SecIsValidHandle(&cred_));
int rv = OK;
if (username) {
- std::wstring domain;
- std::wstring user;
+ string16 domain;
+ string16 user;
SplitDomainAndUser(*username, &domain, &user);
rv = AcquireExplicitCredentials(library_, security_package_, domain,
user, *password, &cred_);
@@ -223,14 +314,10 @@ int HttpAuthSSPI::OnFirstRound(const std::wstring* username,
int HttpAuthSSPI::GetNextSecurityToken(
const std::wstring& spn,
- const void * in_token,
+ const void* in_token,
int in_token_len,
void** out_token,
int* out_token_len) {
- SECURITY_STATUS status;
- TimeStamp expiry;
-
- DWORD ctxt_attr;
CtxtHandle* ctxt_ptr;
SecBufferDesc in_buffer_desc, out_buffer_desc;
SecBufferDesc* in_buffer_desc_ptr;
@@ -251,7 +338,7 @@ int HttpAuthSSPI::GetNextSecurityToken(
// sequence. If we have already initialized our security context, then
// we're incorrectly reusing the auth handler for a new sequence.
if (SecIsValidHandle(&ctxt_)) {
- LOG(ERROR) << "Cannot restart authentication sequence";
+ NOTREACHED();
return ERR_UNEXPECTED;
}
ctxt_ptr = NULL;
@@ -268,28 +355,32 @@ int HttpAuthSSPI::GetNextSecurityToken(
if (!out_buffer.pvBuffer)
return ERR_OUT_OF_MEMORY;
+ DWORD context_flags = 0;
+ // Firefox only sets ISC_REQ_DELEGATE, but MSDN documentation indicates that
+ // ISC_REQ_MUTUAL_AUTH must also be set.
+ if (can_delegate_)
+ context_flags |= (ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH);
+
// This returns a token that is passed to the remote server.
- status = library_->InitializeSecurityContext(
+ DWORD context_attribute;
+ SECURITY_STATUS status = library_->InitializeSecurityContext(
&cred_, // phCredential
ctxt_ptr, // phContext
const_cast<wchar_t *>(spn.c_str()), // pszTargetName
- 0, // fContextReq
+ context_flags, // fContextReq
0, // Reserved1 (must be 0)
SECURITY_NATIVE_DREP, // TargetDataRep
in_buffer_desc_ptr, // pInput
0, // Reserved2 (must be 0)
&ctxt_, // phNewContext
&out_buffer_desc, // pOutput
- &ctxt_attr, // pfContextAttr
- &expiry); // ptsExpiry
- // On success, the function returns SEC_I_CONTINUE_NEEDED on the first call
- // and SEC_E_OK on the second call. On failure, the function returns an
- // error code.
- if (status != SEC_I_CONTINUE_NEEDED && status != SEC_E_OK) {
- LOG(ERROR) << "InitializeSecurityContext failed " << status;
+ &context_attribute, // pfContextAttr
+ NULL); // ptsExpiry
+ int rv = MapInitializeSecurityContextStatusToError(status);
+ if (rv != OK) {
ResetSecurityContext();
free(out_buffer.pvBuffer);
- return ERR_UNEXPECTED; // TODO(wtc): map error code.
+ return rv;
}
if (!out_buffer.cbBuffer) {
free(out_buffer.pvBuffer);
@@ -300,14 +391,14 @@ int HttpAuthSSPI::GetNextSecurityToken(
return OK;
}
-void SplitDomainAndUser(const std::wstring& combined,
- std::wstring* domain,
- std::wstring* user) {
+void SplitDomainAndUser(const string16& combined,
+ string16* domain,
+ string16* user) {
// |combined| may be in the form "user" or "DOMAIN\user".
- // Separatethe two parts if they exist.
+ // Separate the two parts if they exist.
// TODO(cbentzel): I believe user@domain is also a valid form.
size_t backslash_idx = combined.find(L'\\');
- if (backslash_idx == std::wstring::npos) {
+ if (backslash_idx == string16::npos) {
domain->clear();
*user = combined;
} else {
@@ -324,31 +415,14 @@ int DetermineMaxTokenLength(SSPILibrary* library,
PSecPkgInfo pkg_info = NULL;
SECURITY_STATUS status = library->QuerySecurityPackageInfo(
const_cast<wchar_t *>(package.c_str()), &pkg_info);
- if (status != SEC_E_OK) {
- // The documentation at
- // http://msdn.microsoft.com/en-us/library/aa379359(VS.85).aspx
- // only mentions that a non-zero (or non-SEC_E_OK) value is returned
- // if the function fails. In practice, it appears to return
- // SEC_E_SECPKG_NOT_FOUND for invalid/unknown packages.
- LOG(ERROR) << "Security package " << package << " not found."
- << " Status code: " << status;
- if (status == SEC_E_SECPKG_NOT_FOUND)
- return ERR_UNSUPPORTED_AUTH_SCHEME;
- else
- return ERR_UNEXPECTED;
- }
+ int rv = MapQuerySecurityPackageInfoStatusToError(status);
+ if (rv != OK)
+ return rv;
int token_length = pkg_info->cbMaxToken;
status = library->FreeContextBuffer(pkg_info);
- if (status != SEC_E_OK) {
- // The documentation at
- // http://msdn.microsoft.com/en-us/library/aa375416(VS.85).aspx
- // only mentions that a non-zero (or non-SEC_E_OK) value is returned
- // if the function fails, and does not indicate what the failure conditions
- // are.
- LOG(ERROR) << "Unexpected problem freeing context buffer. Status code: "
- << status;
- return ERR_UNEXPECTED;
- }
+ rv = MapFreeContextBufferStatusToError(status);
+ if (rv != OK)
+ return rv;
*max_token_length = token_length;
return OK;
}
diff --git a/net/http/http_auth_sspi_win.h b/net/http/http_auth_sspi_win.h
index 14d158a..c4df58e 100644
--- a/net/http/http_auth_sspi_win.h
+++ b/net/http/http_auth_sspi_win.h
@@ -7,6 +7,7 @@
#ifndef NET_HTTP_HTTP_AUTH_SSPI_WIN_H_
#define NET_HTTP_HTTP_AUTH_SSPI_WIN_H_
+#pragma once
// security.h needs to be included for CredHandle. Unfortunately CredHandle
// is a typedef and can't be forward declared.
@@ -16,13 +17,11 @@
#include <string>
+#include "base/string16.h"
#include "net/http/http_auth.h"
namespace net {
-struct HttpRequestInfo;
-class ProxyInfo;
-
// SSPILibrary is introduced so unit tests can mock the calls to Windows' SSPI
// implementation. The default implementation simply passes the arguments on to
// the SSPI implementation provided by Secur32.dll.
@@ -80,9 +79,9 @@ class HttpAuthSSPI {
~HttpAuthSSPI();
bool NeedsIdentity() const;
- bool IsFinalRound() const;
- bool ParseChallenge(HttpAuth::ChallengeTokenizer* tok);
+ HttpAuth::AuthorizationResult ParseChallenge(
+ HttpAuth::ChallengeTokenizer* tok);
// Generates an authentication token for the service specified by the
// Service Principal Name |spn| and stores the value in |*auth_token|.
@@ -92,14 +91,18 @@ class HttpAuthSSPI {
// obtained using |*username| and |*password|. If |username| and |password|
// are both NULL, the credentials for the currently logged in user are used
// instead.
- int GenerateAuthToken(const std::wstring* username,
- const std::wstring* password,
+ int GenerateAuthToken(const string16* username,
+ const string16* password,
const std::wstring& spn,
std::string* auth_token);
+ // Delegation is allowed on the Kerberos ticket. This allows certain servers
+ // to act as the user, such as an IIS server retrieiving data from a
+ // Kerberized MSSQL server.
+ void Delegate();
+
private:
- int OnFirstRound(const std::wstring* username,
- const std::wstring* password);
+ int OnFirstRound(const string16* username, const string16* password);
int GetNextSecurityToken(
const std::wstring& spn,
@@ -117,6 +120,7 @@ class HttpAuthSSPI {
ULONG max_token_length_;
CredHandle cred_;
CtxtHandle ctxt_;
+ bool can_delegate_;
};
// Splits |combined| into domain and username.
@@ -125,9 +129,9 @@ class HttpAuthSSPI {
// If |combined| is of form "bar", |domain| will be empty and |user| will
// contain "bar".
// |domain| and |user| must be non-NULL.
-void SplitDomainAndUser(const std::wstring& combined,
- std::wstring* domain,
- std::wstring* user);
+void SplitDomainAndUser(const string16& combined,
+ string16* domain,
+ string16* user);
// Determines the maximum token length in bytes for a particular SSPI package.
//
diff --git a/net/http/http_auth_sspi_win_unittest.cc b/net/http/http_auth_sspi_win_unittest.cc
index fdef793..331dcd6 100644
--- a/net/http/http_auth_sspi_win_unittest.cc
+++ b/net/http/http_auth_sspi_win_unittest.cc
@@ -22,6 +22,8 @@ void MatchDomainUserAfterSplit(const std::wstring& combined,
EXPECT_EQ(expected_user, actual_user);
}
+const ULONG kMaxTokenLength = 100;
+
} // namespace
TEST(HttpAuthSSPITest, SplitUserAndDomain) {
@@ -36,7 +38,7 @@ TEST(HttpAuthSSPITest, DetermineMaxTokenLength_Normal) {
MockSSPILibrary mock_library;
mock_library.ExpectQuerySecurityPackageInfo(L"NTLM", SEC_E_OK, &package_info);
- ULONG max_token_length = 100;
+ ULONG max_token_length = kMaxTokenLength;
int rv = DetermineMaxTokenLength(&mock_library, L"NTLM", &max_token_length);
EXPECT_EQ(OK, rv);
EXPECT_EQ(1337, max_token_length);
@@ -46,7 +48,7 @@ TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) {
MockSSPILibrary mock_library;
mock_library.ExpectQuerySecurityPackageInfo(L"Foo", SEC_E_SECPKG_NOT_FOUND,
NULL);
- ULONG max_token_length = 100;
+ ULONG max_token_length = kMaxTokenLength;
int rv = DetermineMaxTokenLength(&mock_library, L"Foo", &max_token_length);
EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
// |DetermineMaxTokenLength()| interface states that |max_token_length| should
@@ -54,4 +56,100 @@ TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) {
EXPECT_EQ(100, max_token_length);
}
+TEST(HttpAuthSSPITest, ParseChallenge_FirstRound) {
+ // The first round should just consist of an unadorned "Negotiate" header.
+ MockSSPILibrary mock_library;
+ HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
+ NEGOSSP_NAME, kMaxTokenLength);
+ std::string challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
+ challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_sspi.ParseChallenge(&challenge));
+}
+
+TEST(HttpAuthSSPITest, ParseChallenge_TwoRounds) {
+ // The first round should just have "Negotiate", and the second round should
+ // have a valid base64 token associated with it.
+ MockSSPILibrary mock_library;
+ HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
+ NEGOSSP_NAME, kMaxTokenLength);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_sspi.ParseChallenge(&first_challenge));
+
+ // Generate an auth token and create another thing.
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+
+ std::string second_challenge_text = "Negotiate Zm9vYmFy";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_sspi.ParseChallenge(&second_challenge));
+}
+
+TEST(HttpAuthSSPITest, ParseChallenge_UnexpectedTokenFirstRound) {
+ // If the first round challenge has an additional authentication token, it
+ // should be treated as an invalid challenge from the server.
+ MockSSPILibrary mock_library;
+ HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
+ NEGOSSP_NAME, kMaxTokenLength);
+ std::string challenge_text = "Negotiate Zm9vYmFy";
+ HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
+ challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
+ auth_sspi.ParseChallenge(&challenge));
+}
+
+TEST(HttpAuthSSPITest, ParseChallenge_MissingTokenSecondRound) {
+ // If a later-round challenge is simply "Negotiate", it should be treated as
+ // an authentication challenge rejection from the server or proxy.
+ MockSSPILibrary mock_library;
+ HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
+ NEGOSSP_NAME, kMaxTokenLength);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_sspi.ParseChallenge(&first_challenge));
+
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+ std::string second_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+ auth_sspi.ParseChallenge(&second_challenge));
+}
+
+TEST(HttpAuthSSPITest, ParseChallenge_NonBase64EncodedToken) {
+ // If a later-round challenge has an invalid base64 encoded token, it should
+ // be treated as an invalid challenge.
+ MockSSPILibrary mock_library;
+ HttpAuthSSPI auth_sspi(&mock_library, "Negotiate",
+ NEGOSSP_NAME, kMaxTokenLength);
+ std::string first_challenge_text = "Negotiate";
+ HttpAuth::ChallengeTokenizer first_challenge(first_challenge_text.begin(),
+ first_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ auth_sspi.ParseChallenge(&first_challenge));
+
+ std::string auth_token;
+ EXPECT_EQ(OK, auth_sspi.GenerateAuthToken(NULL, NULL,
+ L"HTTP/intranet.google.com",
+ &auth_token));
+ std::string second_challenge_text = "Negotiate =happyjoy=";
+ HttpAuth::ChallengeTokenizer second_challenge(second_challenge_text.begin(),
+ second_challenge_text.end());
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_INVALID,
+ auth_sspi.ParseChallenge(&second_challenge));
+}
+
} // namespace net
diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc
index cdc7e16..cc62214 100644
--- a/net/http/http_auth_unittest.cc
+++ b/net/http/http_auth_unittest.cc
@@ -8,17 +8,42 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_filter.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_auth_handler_mock.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
+namespace {
+
+HttpAuthHandlerMock* CreateMockHandler(bool connection_based) {
+ HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock();
+ auth_handler->set_connection_based(connection_based);
+ std::string challenge_text = "Mock";
+ HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(),
+ challenge_text.end());
+ GURL origin("www.example.com");
+ EXPECT_TRUE(auth_handler->InitFromChallenge(&challenge,
+ HttpAuth::AUTH_SERVER,
+ origin,
+ BoundNetLog()));
+ return auth_handler;
+}
+
+HttpResponseHeaders* HeadersFromResponseText(const std::string& response) {
+ return new HttpResponseHeaders(
+ HttpUtil::AssembleRawHeaders(response.c_str(), response.length()));
+}
+
+} // namespace
+
TEST(HttpAuthTest, ChooseBestChallenge) {
static const struct {
const char* headers;
@@ -73,8 +98,9 @@ TEST(HttpAuthTest, ChooseBestChallenge) {
GURL origin("http://www.example.com");
std::set<std::string> disabled_schemes;
URLSecurityManagerAllow url_security_manager;
+ scoped_refptr<HostResolver> host_resolver(new MockHostResolver());
scoped_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault());
+ HttpAuthHandlerFactory::CreateDefault(host_resolver));
http_auth_handler_factory->SetURLSecurityManager(
"negotiate", &url_security_manager);
@@ -82,11 +108,8 @@ TEST(HttpAuthTest, ChooseBestChallenge) {
// Make a HttpResponseHeaders object.
std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
headers_with_status_line += tests[i].headers;
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(
- net::HttpUtil::AssembleRawHeaders(
- headers_with_status_line.c_str(),
- headers_with_status_line.length())));
+ scoped_refptr<HttpResponseHeaders> headers(
+ HeadersFromResponseText(headers_with_status_line));
scoped_ptr<HttpAuthHandler> handler;
HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(),
@@ -107,130 +130,58 @@ TEST(HttpAuthTest, ChooseBestChallenge) {
}
}
-TEST(HttpAuthTest, ChooseBestChallengeConnectionBasedNTLM) {
- static const struct {
- const char* headers;
- const char* challenge_realm;
- } tests[] = {
- {
- "WWW-Authenticate: NTLM\r\n",
-
- "",
- },
- {
- "WWW-Authenticate: NTLM "
- "TlRMTVNTUAACAAAADAAMADgAAAAFgokCTroKF1e/DRcAAAAAAAAAALo"
- "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
- "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
- "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
- "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
- "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
- "BtAAAAAAA=\r\n",
-
- // Realm is empty.
- "",
- }
- };
- GURL origin("http://www.example.com");
+TEST(HttpAuthTest, HandleChallengeResponse_RequestBased) {
+ scoped_ptr<HttpAuthHandlerMock> mock_handler(CreateMockHandler(false));
std::set<std::string> disabled_schemes;
-
- scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault());
- scoped_ptr<HttpAuthHandler> handler;
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- // Make a HttpResponseHeaders object.
- std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
- headers_with_status_line += tests[i].headers;
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(
- net::HttpUtil::AssembleRawHeaders(
- headers_with_status_line.c_str(),
- headers_with_status_line.length())));
-
- // possibly_deleted_old_handler may point to deleted memory
- // after ChooseBestChallenge has been called, and should not
- // be dereferenced.
- HttpAuthHandler* possibly_deleted_old_handler = handler.get();
- HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(),
- headers.get(),
- HttpAuth::AUTH_SERVER,
- origin,
- disabled_schemes,
- BoundNetLog(),
- &handler);
- EXPECT_TRUE(handler != NULL);
- // Since NTLM is connection-based, we should continue to use the existing
- // handler rather than creating a new one.
- if (i != 0)
- EXPECT_EQ(possibly_deleted_old_handler, handler.get());
- ASSERT_NE(reinterpret_cast<net::HttpAuthHandler *>(NULL), handler.get());
- EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str());
- }
+ scoped_refptr<HttpResponseHeaders> headers(
+ HeadersFromResponseText(
+ "HTTP/1.1 401 Unauthorized\n"
+ "WWW-Authenticate: Mock token_here\n"));
+ std::string challenge_used;
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+ HttpAuth::HandleChallengeResponse(
+ mock_handler.get(),
+ headers.get(),
+ HttpAuth::AUTH_SERVER,
+ disabled_schemes,
+ &challenge_used));
+ EXPECT_EQ("Mock token_here", challenge_used);
}
-TEST(HttpAuthTest, ChooseBestChallengeConnectionBasedNegotiate) {
- static const struct {
- const char* headers;
- const char* challenge_realm;
- } tests[] = {
- {
- "WWW-Authenticate: Negotiate\r\n",
-
- "",
- },
- {
- "WWW-Authenticate: Negotiate "
- "TlRMTVNTUAACAAAADAAMADgAAAAFgokCTroKF1e/DRcAAAAAAAAAALo"
- "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
- "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
- "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
- "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
- "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
- "BtAAAAAAA=\r\n",
-
- // Realm is empty.
- "",
- }
- };
- GURL origin("http://www.example.com");
+TEST(HttpAuthTest, HandleChallengeResponse_ConnectionBased) {
+ scoped_ptr<HttpAuthHandlerMock> mock_handler(CreateMockHandler(true));
std::set<std::string> disabled_schemes;
- URLSecurityManagerAllow url_security_manager;
- scoped_ptr<HttpAuthHandlerRegistryFactory> http_auth_handler_factory(
- HttpAuthHandlerFactory::CreateDefault());
- http_auth_handler_factory->SetURLSecurityManager(
- "negotiate", &url_security_manager);
-
- scoped_ptr<HttpAuthHandler> handler;
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- // Make a HttpResponseHeaders object.
- std::string headers_with_status_line("HTTP/1.1 401 Unauthorized\n");
- headers_with_status_line += tests[i].headers;
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(
- net::HttpUtil::AssembleRawHeaders(
- headers_with_status_line.c_str(),
- headers_with_status_line.length())));
-
- HttpAuthHandler* old_handler = handler.get();
- HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(),
- headers.get(),
- HttpAuth::AUTH_SERVER,
- origin,
- disabled_schemes,
- BoundNetLog(),
- &handler);
-
- EXPECT_TRUE(handler != NULL);
- // Since Negotiate is connection-based, we should continue to use the
- // existing handler rather than creating a new one.
- if (i != 0)
- EXPECT_EQ(old_handler, handler.get());
-
- ASSERT_NE(reinterpret_cast<net::HttpAuthHandler *>(NULL), handler.get());
+ scoped_refptr<HttpResponseHeaders> headers(
+ HeadersFromResponseText(
+ "HTTP/1.1 401 Unauthorized\n"
+ "WWW-Authenticate: Mock token_here\n"));
+ std::string challenge_used;
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_ACCEPT,
+ HttpAuth::HandleChallengeResponse(
+ mock_handler.get(),
+ headers.get(),
+ HttpAuth::AUTH_SERVER,
+ disabled_schemes,
+ &challenge_used));
+ EXPECT_EQ("Mock token_here", challenge_used);
+}
- EXPECT_STREQ(tests[i].challenge_realm, handler->realm().c_str());
- }
+TEST(HttpAuthTest, HandleChallengeResponse_ConnectionBasedNoMatch) {
+ scoped_ptr<HttpAuthHandlerMock> mock_handler(CreateMockHandler(true));
+ std::set<std::string> disabled_schemes;
+ scoped_refptr<HttpResponseHeaders> headers(
+ HeadersFromResponseText(
+ "HTTP/1.1 401 Unauthorized\n"
+ "WWW-Authenticate: Basic realm=\"happy\"\n"));
+ std::string challenge_used;
+ EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
+ HttpAuth::HandleChallengeResponse(
+ mock_handler.get(),
+ headers.get(),
+ HttpAuth::AUTH_SERVER,
+ disabled_schemes,
+ &challenge_used));
+ EXPECT_TRUE(challenge_used.empty());
}
TEST(HttpAuthTest, ChallengeTokenizer) {
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index 8303357..d90cb73 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -4,21 +4,33 @@
#include "net/http/http_basic_stream.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_stream_parser.h"
+#include "net/socket/client_socket_handle.h"
+
namespace net {
-HttpBasicStream::HttpBasicStream(ClientSocketHandle* handle,
- const BoundNetLog& net_log)
+HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection)
: read_buf_(new GrowableIOBuffer()),
- parser_(new HttpStreamParser(handle, read_buf_, net_log)) {
+ connection_(connection) {
+}
+
+int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
+ const BoundNetLog& net_log,
+ CompletionCallback* callback) {
+ parser_.reset(new HttpStreamParser(connection_.get(), request_info,
+ read_buf_, net_log));
+ return OK;
}
-int HttpBasicStream::SendRequest(const HttpRequestInfo* request,
- const std::string& headers,
+
+int HttpBasicStream::SendRequest(const std::string& headers,
UploadDataStream* request_body,
HttpResponseInfo* response,
CompletionCallback* callback) {
- return parser_->SendRequest(
- request, headers, request_body, response, callback);
+ DCHECK(parser_.get());
+ return parser_->SendRequest(headers, request_body, response, callback);
}
HttpBasicStream::~HttpBasicStream() {}
@@ -31,7 +43,7 @@ int HttpBasicStream::ReadResponseHeaders(CompletionCallback* callback) {
return parser_->ReadResponseHeaders(callback);
}
-HttpResponseInfo* HttpBasicStream::GetResponseInfo() const {
+const HttpResponseInfo* HttpBasicStream::GetResponseInfo() const {
return parser_->GetResponseInfo();
}
@@ -40,6 +52,10 @@ int HttpBasicStream::ReadResponseBody(IOBuffer* buf, int buf_len,
return parser_->ReadResponseBody(buf, buf_len, callback);
}
+void HttpBasicStream::Close(bool not_reusable) {
+ parser_->Close(not_reusable);
+}
+
bool HttpBasicStream::IsResponseBodyComplete() const {
return parser_->IsResponseBodyComplete();
}
@@ -52,4 +68,21 @@ bool HttpBasicStream::IsMoreDataBuffered() const {
return parser_->IsMoreDataBuffered();
}
+bool HttpBasicStream::IsConnectionReused() const {
+ return parser_->IsConnectionReused();
+}
+
+void HttpBasicStream::SetConnectionReused() {
+ parser_->SetConnectionReused();
+}
+
+void HttpBasicStream::GetSSLInfo(SSLInfo* ssl_info) {
+ parser_->GetSSLInfo(ssl_info);
+}
+
+void HttpBasicStream::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ parser_->GetSSLCertRequestInfo(cert_request_info);
+}
+
} // namespace net
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index ff3bcf2..a572bfc 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -8,30 +8,36 @@
#ifndef NET_HTTP_HTTP_BASIC_STREAM_H_
#define NET_HTTP_HTTP_BASIC_STREAM_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
-#include "net/base/io_buffer.h"
+#include "base/scoped_ptr.h"
#include "net/http/http_stream.h"
-#include "net/http/http_stream_parser.h"
namespace net {
class BoundNetLog;
class ClientSocketHandle;
-struct HttpRequestInfo;
+class GrowableIOBuffer;
class HttpResponseInfo;
+struct HttpRequestInfo;
+class HttpStreamParser;
+class IOBuffer;
class UploadDataStream;
class HttpBasicStream : public HttpStream {
public:
- HttpBasicStream(ClientSocketHandle* handle, const BoundNetLog& net_log);
+ explicit HttpBasicStream(ClientSocketHandle* connection);
virtual ~HttpBasicStream();
// HttpStream methods:
- virtual int SendRequest(const HttpRequestInfo* request,
- const std::string& headers,
+ virtual int InitializeStream(const HttpRequestInfo* request_info,
+ const BoundNetLog& net_log,
+ CompletionCallback* callback);
+
+ virtual int SendRequest(const std::string& headers,
UploadDataStream* request_body,
HttpResponseInfo* response,
CompletionCallback* callback);
@@ -40,22 +46,34 @@ class HttpBasicStream : public HttpStream {
virtual int ReadResponseHeaders(CompletionCallback* callback);
- virtual HttpResponseInfo* GetResponseInfo() const;
+ virtual const HttpResponseInfo* GetResponseInfo() const;
virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
CompletionCallback* callback);
+ virtual void Close(bool not_reusable);
+
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);
+
private:
scoped_refptr<GrowableIOBuffer> read_buf_;
scoped_ptr<HttpStreamParser> parser_;
+ scoped_ptr<ClientSocketHandle> connection_;
+
DISALLOW_COPY_AND_ASSIGN(HttpBasicStream);
};
diff --git a/net/http/http_byte_range.h b/net/http/http_byte_range.h
index a4f52f2..5b0a9d1 100644
--- a/net/http/http_byte_range.h
+++ b/net/http/http_byte_range.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_BYTE_RANGE_H_
#define NET_HTTP_HTTP_BYTE_RANGE_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index dbd6bf1..2b2a221 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -18,7 +18,9 @@
#include "base/pickle.h"
#include "base/ref_counted.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -62,10 +64,11 @@ HttpCache::ActiveEntry::~ActiveEntry() {
// This structure keeps track of work items that are attempting to create or
// open cache entries or the backend itself.
struct HttpCache::PendingOp {
- PendingOp() : disk_entry(NULL), writer(NULL), callback(NULL) {}
+ PendingOp() : disk_entry(NULL), backend(NULL), writer(NULL), callback(NULL) {}
~PendingOp() {}
disk_cache::Entry* disk_entry;
+ disk_cache::Backend* backend;
WorkItem* writer;
CompletionCallback* callback; // BackendCallback.
WorkItemList pending_queue;
@@ -104,12 +107,16 @@ class HttpCache::WorkItem {
trans_->io_callback()->Run(result);
}
- // Notifies the caller about the operation completion.
- void DoCallback(int result, disk_cache::Backend* backend) {
+ // Notifies the caller about the operation completion. Returns true if the
+ // callback was invoked.
+ bool DoCallback(int result, disk_cache::Backend* backend) {
if (backend_)
*backend_ = backend;
- if (callback_)
+ if (callback_) {
callback_->Run(result);
+ return true;
+ }
+ return false;
}
WorkItemOperation operation() { return operation_; }
@@ -138,8 +145,13 @@ class HttpCache::BackendCallback : public CallbackRunner<Tuple1<int> > {
~BackendCallback() {}
virtual void RunWithParams(const Tuple1<int>& params) {
- if (cache_)
+ if (cache_) {
cache_->OnIOComplete(params.a, pending_op_);
+ } else {
+ // The callback was cancelled so we should delete the pending_op that
+ // was used with this callback.
+ delete pending_op_;
+ }
delete this;
}
@@ -238,7 +250,6 @@ HttpCache::HttpCache(HostResolver* host_resolver, ProxyService* proxy_service,
NetLog* net_log,
BackendFactory* backend_factory)
: backend_factory_(backend_factory),
- temp_backend_(NULL),
building_backend_(false),
mode_(NORMAL),
network_layer_(HttpNetworkLayer::CreateFactory(host_resolver,
@@ -251,7 +262,6 @@ HttpCache::HttpCache(HostResolver* host_resolver, ProxyService* proxy_service,
HttpCache::HttpCache(HttpNetworkSession* session,
BackendFactory* backend_factory)
: backend_factory_(backend_factory),
- temp_backend_(NULL),
building_backend_(false),
mode_(NORMAL),
network_layer_(HttpNetworkLayer::CreateFactory(session)),
@@ -262,7 +272,6 @@ HttpCache::HttpCache(HttpNetworkSession* session,
HttpCache::HttpCache(HttpTransactionFactory* network_layer,
BackendFactory* backend_factory)
: backend_factory_(backend_factory),
- temp_backend_(NULL),
building_backend_(false),
mode_(NORMAL),
network_layer_(network_layer),
@@ -292,18 +301,24 @@ HttpCache::~HttpCache() {
// though they are waiting for a callback that will never fire.
PendingOp* pending_op = pending_it->second;
delete pending_op->writer;
+ bool delete_pending_op = true;
if (building_backend_) {
// If we don't have a backend, when its construction finishes it will
// deliver the callbacks.
BackendCallback* callback =
static_cast<BackendCallback*>(pending_op->callback);
- callback->Cancel();
+ if (callback) {
+ // The callback will delete the pending operation.
+ callback->Cancel();
+ delete_pending_op = false;
+ }
} else {
delete pending_op->callback;
}
STLDeleteElements(&pending_op->pending_queue);
- delete pending_op;
+ if (delete_pending_op)
+ delete pending_op;
}
}
@@ -377,9 +392,9 @@ void HttpCache::CloseCurrentConnections() {
static_cast<net::HttpNetworkLayer*>(network_layer_.get());
HttpNetworkSession* session = network->GetSession();
if (session) {
- session->tcp_socket_pool()->Flush();
+ session->FlushSocketPools();
if (session->spdy_session_pool())
- session->spdy_session_pool()->CloseAllSessions();
+ session->spdy_session_pool()->CloseCurrentSessions();
}
}
@@ -410,7 +425,7 @@ int HttpCache::CreateBackend(disk_cache::Backend** backend,
BackendCallback* my_callback = new BackendCallback(this, pending_op);
pending_op->callback = my_callback;
- int rv = backend_factory_->CreateBackend(&temp_backend_, my_callback);
+ int rv = backend_factory_->CreateBackend(&pending_op->backend, my_callback);
if (rv != ERR_IO_PENDING) {
pending_op->writer->ClearCallback();
my_callback->Run(rv);
@@ -443,8 +458,8 @@ std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
// No valid URL can begin with numerals, so we should not have to worry
// about collisions with normal URLs.
if (request->upload_data && request->upload_data->identifier()) {
- url.insert(0, StringPrintf("%" PRId64 "/",
- request->upload_data->identifier()));
+ url.insert(0, base::StringPrintf("%" PRId64 "/",
+ request->upload_data->identifier()));
}
return url;
}
@@ -466,7 +481,7 @@ std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) {
(*playback_cache_map_)[url] = generation + 1;
// The key into the cache is GENERATION # + METHOD + URL.
- std::string result = IntToString(generation);
+ std::string result = base::IntToString(generation);
result.append(request->method);
result.append(url);
return result;
@@ -1007,26 +1022,40 @@ void HttpCache::OnBackendCreated(int result, PendingOp* pending_op) {
WorkItemOperation op = item->operation();
DCHECK_EQ(WI_CREATE_BACKEND, op);
- backend_factory_.reset(); // Reclaim memory.
-
- if (result == OK)
- disk_cache_.reset(temp_backend_);
-
- item->DoCallback(result, temp_backend_);
+ // We don't need the callback anymore.
+ pending_op->callback = NULL;
+ disk_cache::Backend* backend = pending_op->backend;
+
+ if (backend_factory_.get()) {
+ // We may end up calling OnBackendCreated multiple times if we have pending
+ // work items. The first call saves the backend and releases the factory,
+ // and the last call clears building_backend_.
+ backend_factory_.reset(); // Reclaim memory.
+ if (result == OK)
+ disk_cache_.reset(backend);
+ }
- // Notify all callers and delete all pending work items.
- while (!pending_op->pending_queue.empty()) {
- scoped_ptr<WorkItem> pending_item(pending_op->pending_queue.front());
+ if (!pending_op->pending_queue.empty()) {
+ WorkItem* pending_item = pending_op->pending_queue.front();
pending_op->pending_queue.pop_front();
DCHECK_EQ(WI_CREATE_BACKEND, pending_item->operation());
- // This could be an external caller or a transaction waiting on Start().
- pending_item->DoCallback(result, temp_backend_);
- pending_item->NotifyTransaction(result, NULL);
+ // We want to process a single callback at a time, because the cache may
+ // go away from the callback.
+ pending_op->writer = pending_item;
+
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ task_factory_.NewRunnableMethod(&HttpCache::OnBackendCreated,
+ result, pending_op));
+ } else {
+ building_backend_ = false;
+ DeletePendingOp(pending_op);
}
- DeletePendingOp(pending_op);
- building_backend_ = false;
+ // The cache may be gone when we return from the callback.
+ if (!item->DoCallback(result, backend))
+ item->NotifyTransaction(result, NULL);
}
} // namespace net
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index daa6d28..dc16715 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -13,6 +13,7 @@
#ifndef NET_HTTP_HTTP_CACHE_H_
#define NET_HTTP_HTTP_CACHE_H_
+#pragma once
#include <list>
#include <set>
@@ -346,7 +347,6 @@ class HttpCache : public HttpTransactionFactory,
// Used when lazily constructing the disk_cache_.
scoped_ptr<BackendFactory> backend_factory_;
- disk_cache::Backend* temp_backend_;
bool building_backend_;
Mode mode_;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 9bbf4d1..3129113 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -4,16 +4,21 @@
#include "net/http/http_cache_transaction.h"
-#include "base/compiler_specific.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include <unistd.h>
#endif
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/field_trial.h"
#include "base/histogram.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "net/base/cert_status_flags.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -223,8 +228,8 @@ int HttpCache::Transaction::RestartWithCertificate(
}
int HttpCache::Transaction::RestartWithAuth(
- const std::wstring& username,
- const std::wstring& password,
+ const string16& username,
+ const string16& password,
CompletionCallback* callback) {
DCHECK(auth_response_.headers);
DCHECK(callback);
@@ -827,8 +832,19 @@ int HttpCache::Transaction::DoAddToEntry() {
int HttpCache::Transaction::DoAddToEntryComplete(int result) {
net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WAITING, NULL);
- UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait",
- base::TimeTicks::Now() - entry_lock_waiting_since_);
+
+ const base::TimeDelta entry_lock_wait =
+ base::TimeTicks::Now() - entry_lock_waiting_since_;
+ UMA_HISTOGRAM_TIMES("HttpCache.EntryLockWait", entry_lock_wait);
+ static const bool prefetching_fieldtrial =
+ FieldTrialList::Find("Prefetch") &&
+ !FieldTrialList::Find("Prefetch")->group_name().empty();
+ if (prefetching_fieldtrial) {
+ UMA_HISTOGRAM_TIMES(
+ FieldTrial::MakeName("HttpCache.EntryLockWait", "Prefetch"),
+ entry_lock_wait);
+ }
+
entry_lock_waiting_since_ = base::TimeTicks();
DCHECK(new_entry_);
cache_pending_ = false;
@@ -1497,8 +1513,8 @@ int HttpCache::Transaction::RestartNetworkRequestWithCertificate(
}
int HttpCache::Transaction::RestartNetworkRequestWithAuth(
- const std::wstring& username,
- const std::wstring& password) {
+ const string16& username,
+ const string16& password) {
DCHECK(mode_ & WRITE || mode_ == NONE);
DCHECK(network_trans_.get());
DCHECK_EQ(STATE_NONE, next_state_);
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index ae143e9..2883282 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -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.
@@ -7,9 +7,13 @@
#ifndef NET_HTTP_HTTP_CACHE_TRANSACTION_H_
#define NET_HTTP_HTTP_CACHE_TRANSACTION_H_
+#pragma once
-#include "net/base/net_log.h"
+#include <string>
+
+#include "base/string16.h"
#include "base/time.h"
+#include "net/base/net_log.h"
#include "net/http/http_cache.h"
#include "net/http/http_response_info.h"
#include "net/http/http_transaction.h"
@@ -18,6 +22,7 @@ namespace net {
class HttpResponseHeaders;
class PartialData;
+struct HttpRequestInfo;
// This is the transaction that is returned by the HttpCache transaction
// factory.
@@ -32,8 +37,8 @@ class HttpCache::Transaction : public HttpTransaction {
virtual int RestartIgnoringLastError(CompletionCallback* callback);
virtual int RestartWithCertificate(X509Certificate* client_cert,
CompletionCallback* callback);
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
+ virtual int RestartWithAuth(const string16& username,
+ const string16& password,
CompletionCallback* callback);
virtual bool IsReadyToRestartForAuth();
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
@@ -249,8 +254,8 @@ class HttpCache::Transaction : public HttpTransaction {
// Called to restart a network transaction with authentication credentials.
// Returns network error code.
- int RestartNetworkRequestWithAuth(const std::wstring& username,
- const std::wstring& password);
+ int RestartNetworkRequestWithAuth(const string16& username,
+ const string16& password);
// Called to determine if we need to validate the cache entry before using it.
bool RequiresValidation();
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 8b2f7cc..2c8e16d 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.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.
@@ -8,9 +8,11 @@
#include "base/message_loop.h"
#include "base/scoped_vector.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/cache_type.h"
-#include "net/base/net_errors.h"
+#include "net/base/cert_status_flags.h"
#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
#include "net/base/net_log_unittest.h"
#include "net/base/ssl_cert_request_info.h"
#include "net/disk_cache/disk_cache.h"
@@ -667,6 +669,7 @@ class MockBlockingBackendFactory : public net::HttpCache::BackendFactory {
}
}
+ disk_cache::Backend** backend() { return backend_; }
void set_fail(bool fail) { fail_ = fail; }
net::CompletionCallback* callback() { return callback_; }
@@ -680,6 +683,20 @@ class MockBlockingBackendFactory : public net::HttpCache::BackendFactory {
bool fail_;
};
+class DeleteCacheCompletionCallback : public TestCompletionCallback {
+ public:
+ explicit DeleteCacheCompletionCallback(MockHttpCache* cache)
+ : cache_(cache) {}
+
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ delete cache_;
+ TestCompletionCallback::RunWithParams(params);
+ }
+
+ private:
+ MockHttpCache* cache_;
+};
+
//-----------------------------------------------------------------------------
// helpers
@@ -877,8 +894,8 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request,
EXPECT_LT(end, 80);
- std::string content_range = StringPrintf("Content-Range: bytes %d-%d/80\n",
- start, end);
+ std::string content_range = base::StringPrintf(
+ "Content-Range: bytes %d-%d/80\n", start, end);
response_headers->append(content_range);
if (!request->extra_headers.HasHeader("If-None-Match") || modified_) {
@@ -892,7 +909,8 @@ void RangeTransactionServer::RangeHandler(const net::HttpRequestInfo* request,
// We also have to fix content-length.
int len = end - start + 1;
EXPECT_EQ(0, len % 10);
- std::string content_length = StringPrintf("Content-Length: %d\n", len);
+ std::string content_length = base::StringPrintf("Content-Length: %d\n",
+ len);
response_headers->replace(response_headers->find("Content-Length:"),
content_length.size(), content_length);
}
@@ -2005,13 +2023,56 @@ TEST(HttpCache, DeleteCacheWaitingForBackend) {
// We cannot call FinishCreation because the factory itself will go away with
// the cache, so grab the callback and attempt to use it.
net::CompletionCallback* callback = factory->callback();
+ disk_cache::Backend** backend = factory->backend();
cache.reset();
MessageLoop::current()->RunAllPending();
+ *backend = NULL;
callback->Run(net::ERR_ABORTED);
}
+// Tests that we can delete the cache while creating the backend, from within
+// one of the callbacks.
+TEST(HttpCache, DeleteCacheWaitingForBackend2) {
+ MockBlockingBackendFactory* factory = new MockBlockingBackendFactory();
+ MockHttpCache* cache = new MockHttpCache(factory);
+
+ DeleteCacheCompletionCallback cb(cache);
+ disk_cache::Backend* backend;
+ int rv = cache->http_cache()->GetBackend(&backend, &cb);
+ EXPECT_EQ(net::ERR_IO_PENDING, rv);
+
+ // Now let's queue a regular transaction
+ MockHttpRequest request(kSimpleGET_Transaction);
+
+ scoped_ptr<Context> c(new Context());
+ c->result = cache->http_cache()->CreateTransaction(&c->trans);
+ EXPECT_EQ(net::OK, c->result);
+
+ c->trans->Start(&request, &c->callback, net::BoundNetLog());
+
+ // And another direct backend request.
+ TestCompletionCallback cb2;
+ rv = cache->http_cache()->GetBackend(&backend, &cb2);
+ EXPECT_EQ(net::ERR_IO_PENDING, rv);
+
+ // Just to make sure that everything is still pending.
+ MessageLoop::current()->RunAllPending();
+
+ // The request should be queued.
+ EXPECT_FALSE(c->callback.have_result());
+
+ // Generate the callback.
+ factory->FinishCreation();
+ rv = cb.WaitForResult();
+
+ // The cache should be gone by now.
+ MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(net::OK, c->callback.GetResult(c->result));
+ EXPECT_FALSE(cb2.have_result());
+}
+
TEST(HttpCache, TypicalGET_ConditionalRequest) {
MockHttpCache cache;
diff --git a/net/http/http_chunked_decoder.cc b/net/http/http_chunked_decoder.cc
index 1f6ef0d..1ac7a60 100644
--- a/net/http/http_chunked_decoder.cc
+++ b/net/http/http_chunked_decoder.cc
@@ -41,6 +41,7 @@
#include "net/http/http_chunked_decoder.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "net/base/net_errors.h"
@@ -188,7 +189,7 @@ bool HttpChunkedDecoder::ParseChunkSize(const char* start, int len, int* out) {
return false;
int parsed_number;
- bool ok = HexStringToInt(std::string(start, len), &parsed_number);
+ bool ok = base::HexStringToInt(std::string(start, len), &parsed_number);
if (ok && parsed_number >= 0) {
*out = parsed_number;
return true;
diff --git a/net/http/http_chunked_decoder.h b/net/http/http_chunked_decoder.h
index 174dddc..cf6e6b9 100644
--- a/net/http/http_chunked_decoder.h
+++ b/net/http/http_chunked_decoder.h
@@ -40,6 +40,7 @@
#ifndef NET_HTTP_HTTP_CHUNKED_DECODER_H_
#define NET_HTTP_HTTP_CHUNKED_DECODER_H_
+#pragma once
#include <string>
diff --git a/net/http/http_net_log_params.h b/net/http/http_net_log_params.h
index 563c799..5a5e84b 100644
--- a/net/http/http_net_log_params.h
+++ b/net/http/http_net_log_params.h
@@ -4,12 +4,13 @@
#ifndef NET_HTTP_HTTP_NET_LOG_PARAMS_H_
#define NET_HTTP_HTTP_NET_LOG_PARAMS_H_
+#pragma once
#include <string>
-#include <vector>
#include "base/basictypes.h"
#include "base/ref_counted.h"
+#include "base/stringprintf.h"
#include "base/values.h"
#include "net/base/net_log.h"
#include "net/http/http_request_headers.h"
@@ -27,16 +28,16 @@ class NetLogHttpRequestParameter : public NetLog::EventParameters {
Value* ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- dict->SetString(L"line", line_);
+ dict->SetString("line", line_);
ListValue* headers = new ListValue();
HttpRequestHeaders::Iterator iterator(headers_);
while (iterator.GetNext()) {
headers->Append(
- new StringValue(StringPrintf("%s: %s",
- iterator.name().c_str(),
- iterator.value().c_str())));
+ new StringValue(base::StringPrintf("%s: %s",
+ iterator.name().c_str(),
+ iterator.value().c_str())));
}
- dict->Set(L"headers", headers);
+ dict->Set("headers", headers);
return dict;
}
@@ -64,9 +65,10 @@ class NetLogHttpResponseParameter : public NetLog::EventParameters {
std::string value;
while (headers_->EnumerateHeaderLines(&iterator, &name, &value)) {
headers->Append(
- new StringValue(StringPrintf("%s: %s", name.c_str(), value.c_str())));
+ new StringValue(base::StringPrintf("%s: %s", name.c_str(),
+ value.c_str())));
}
- dict->Set(L"headers", headers);
+ dict->Set("headers", headers);
return dict;
}
diff --git a/net/http/http_network_delegate.h b/net/http/http_network_delegate.h
index 51c6766..6b60aba 100644
--- a/net/http/http_network_delegate.h
+++ b/net/http/http_network_delegate.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_NETWORK_DELEGATE_H_
#define NET_HTTP_HTTP_NETWORK_DELEGATE_H_
+#pragma once
namespace net {
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc
index 7df286f..65d2aa3 100644
--- a/net/http/http_network_layer.cc
+++ b/net/http/http_network_layer.cc
@@ -6,12 +6,12 @@
#include "base/field_trial.h"
#include "base/logging.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_transaction.h"
#include "net/socket/client_socket_factory.h"
#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_network_transaction.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
@@ -45,8 +45,6 @@ HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
}
//-----------------------------------------------------------------------------
-bool HttpNetworkLayer::force_spdy_ = false;
-
HttpNetworkLayer::HttpNetworkLayer(
ClientSocketFactory* socket_factory,
HostResolver* host_resolver,
@@ -69,6 +67,29 @@ HttpNetworkLayer::HttpNetworkLayer(
DCHECK(ssl_config_service_.get());
}
+HttpNetworkLayer::HttpNetworkLayer(
+ ClientSocketFactory* socket_factory,
+ HostResolver* host_resolver,
+ ProxyService* proxy_service,
+ SSLConfigService* ssl_config_service,
+ SpdySessionPool* spdy_session_pool,
+ HttpAuthHandlerFactory* http_auth_handler_factory,
+ HttpNetworkDelegate* network_delegate,
+ NetLog* net_log)
+ : socket_factory_(socket_factory),
+ host_resolver_(host_resolver),
+ proxy_service_(proxy_service),
+ ssl_config_service_(ssl_config_service),
+ session_(NULL),
+ spdy_session_pool_(spdy_session_pool),
+ http_auth_handler_factory_(http_auth_handler_factory),
+ network_delegate_(network_delegate),
+ net_log_(net_log),
+ suspended_(false) {
+ DCHECK(proxy_service_);
+ DCHECK(ssl_config_service_.get());
+}
+
HttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session)
: socket_factory_(ClientSocketFactory::GetDefaultFactory()),
ssl_config_service_(NULL),
@@ -88,10 +109,7 @@ int HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
if (suspended_)
return ERR_NETWORK_IO_SUSPENDED;
- if (force_spdy_)
- trans->reset(new SpdyNetworkTransaction(GetSession()));
- else
- trans->reset(new HttpNetworkTransaction(GetSession()));
+ trans->reset(new HttpNetworkTransaction(GetSession()));
return OK;
}
@@ -109,7 +127,7 @@ void HttpNetworkLayer::Suspend(bool suspend) {
HttpNetworkSession* HttpNetworkLayer::GetSession() {
if (!session_) {
DCHECK(proxy_service_);
- SpdySessionPool* spdy_pool = new SpdySessionPool();
+ SpdySessionPool* spdy_pool = new SpdySessionPool(ssl_config_service_);
session_ = new HttpNetworkSession(host_resolver_, proxy_service_,
socket_factory_, ssl_config_service_, spdy_pool,
http_auth_handler_factory_, network_delegate_, net_log_);
@@ -126,9 +144,18 @@ HttpNetworkSession* HttpNetworkLayer::GetSession() {
// static
void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
+ static const char kSSL[] = "ssl";
static const char kDisableSSL[] = "no-ssl";
static const char kDisableCompression[] = "no-compress";
static const char kDisableAltProtocols[] = "no-alt-protocols";
+ static const char kEnableVersionOne[] = "v1";
+ static const char kForceAltProtocols[] = "force-alt-protocols";
+
+ // If flow-control is enabled, received WINDOW_UPDATE and SETTINGS
+ // messages are processed and outstanding window size is actually obeyed
+ // when sending data frames, and WINDOW_UPDATE messages are generated
+ // when data is consumed.
+ static const char kEnableFlowControl[] = "flow-control";
// We want an A/B experiment between SPDY enabled and SPDY disabled,
// but only for pages where SPDY *could have been* negotiated. To do
@@ -146,17 +173,15 @@ void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
// will choose the first overlapping protocol in the server's list, since
// it presumedly has a better understanding of which protocol we should
// use, therefore the rest of the ordering here is not important.
- static const char kNpnProtosFull[] =
- "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy";
+ static const char kNpnProtosFull[] = "\x08http/1.1\x06spdy/2";
+ // This is a temporary hack to pretend we support version 1.
+ static const char kNpnProtosFullV1[] = "\x08http/1.1\x06spdy/1";
// No spdy specified.
static const char kNpnProtosHttpOnly[] = "\x08http/1.1\x07http1.1";
std::vector<std::string> spdy_options;
SplitString(mode, ',', &spdy_options);
- // Force spdy mode (use SpdyNetworkTransaction for all http requests).
- force_spdy_ = true;
-
bool use_alt_protocols = true;
for (std::vector<std::string>::iterator it = spdy_options.begin();
@@ -164,21 +189,34 @@ void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
const std::string& option = *it;
if (option == kDisableSSL) {
SpdySession::SetSSLMode(false); // Disable SSL
+ HttpStreamFactory::set_force_spdy_over_ssl(false);
+ HttpStreamFactory::set_force_spdy_always(true);
+ } else if (option == kSSL) {
+ HttpStreamFactory::set_force_spdy_over_ssl(true);
+ HttpStreamFactory::set_force_spdy_always(true);
} else if (option == kDisableCompression) {
spdy::SpdyFramer::set_enable_compression_default(false);
} else if (option == kEnableNPN) {
- HttpNetworkTransaction::SetUseAlternateProtocols(use_alt_protocols);
- HttpNetworkTransaction::SetNextProtos(kNpnProtosFull);
- force_spdy_ = false;
+ HttpStreamFactory::set_use_alternate_protocols(use_alt_protocols);
+ HttpStreamFactory::set_next_protos(kNpnProtosFull);
} else if (option == kEnableNpnHttpOnly) {
// Avoid alternate protocol in this case. Otherwise, browser will try SSL
// and then fallback to http. This introduces extra load.
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
- HttpNetworkTransaction::SetNextProtos(kNpnProtosHttpOnly);
- force_spdy_ = false;
+ HttpStreamFactory::set_use_alternate_protocols(false);
+ HttpStreamFactory::set_next_protos(kNpnProtosHttpOnly);
+ } else if (option == kEnableVersionOne) {
+ spdy::SpdyFramer::set_protocol_version(1);
+ HttpStreamFactory::set_next_protos(kNpnProtosFullV1);
} else if (option == kDisableAltProtocols) {
use_alt_protocols = false;
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_use_alternate_protocols(false);
+ } else if (option == kEnableFlowControl) {
+ SpdySession::set_flow_control(true);
+ } else if (option == kForceAltProtocols) {
+ HttpAlternateProtocols::PortProtocolPair pair;
+ pair.port = 443;
+ pair.protocol = HttpAlternateProtocols::NPN_SPDY_2;
+ HttpAlternateProtocols::ForceAlternateProtocol(pair);
} else if (option.empty() && it == spdy_options.begin()) {
continue;
} else {
@@ -186,5 +224,4 @@ void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
}
}
}
-
} // namespace net
diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h
index 8cc62ab..f4ce1f1 100644
--- a/net/http/http_network_layer.h
+++ b/net/http/http_network_layer.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_NETWORK_LAYER_H_
#define NET_HTTP_HTTP_NETWORK_LAYER_H_
+#pragma once
#include <string>
@@ -20,7 +21,6 @@ class HttpAuthHandlerFactory;
class HttpNetworkDelegate;
class HttpNetworkSession;
class NetLog;
-class ProxyInfo;
class ProxyService;
class SpdySessionPool;
class SSLConfigService;
@@ -38,6 +38,16 @@ class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
NetLog* net_log);
// Construct a HttpNetworkLayer with an existing HttpNetworkSession which
// contains a valid ProxyService.
+ HttpNetworkLayer(
+ ClientSocketFactory* socket_factory,
+ HostResolver* host_resolver,
+ ProxyService* proxy_service,
+ SSLConfigService* ssl_config_service,
+ SpdySessionPool* spdy_session_pool,
+ HttpAuthHandlerFactory* http_auth_handler_factory,
+ HttpNetworkDelegate* network_delegate,
+ NetLog* net_log);
+
explicit HttpNetworkLayer(HttpNetworkSession* session);
~HttpNetworkLayer();
@@ -66,9 +76,11 @@ class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
// Enable the spdy protocol.
// Without calling this function, SPDY is disabled. The mode can be:
- // "" : (default) SSL and compression are enabled.
+ // "" : (default) SSL and compression are enabled, flow
+ // control disabled.
// "no-ssl" : disables SSL.
// "no-compress" : disables compression.
+ // "flow-control": enables flow control.
// "none" : disables both SSL and compression.
static void EnableSpdy(const std::string& mode);
@@ -92,7 +104,6 @@ class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
NetLog* net_log_;
bool suspended_;
- static bool force_spdy_;
};
} // namespace net
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index 274d2dc..27822ed 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.cc
@@ -17,8 +17,8 @@ class HttpNetworkLayerTest : public PlatformTest {
TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
net::HttpNetworkLayer factory(NULL, new net::MockHostResolver,
- net::ProxyService::CreateNull(), new net::SSLConfigServiceDefaults, NULL,
- NULL, NULL);
+ net::ProxyService::CreateDirect(), new net::SSLConfigServiceDefaults,
+ NULL, NULL, NULL);
scoped_ptr<net::HttpTransaction> trans;
int rv = factory.CreateTransaction(&trans);
@@ -28,8 +28,8 @@ TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
TEST_F(HttpNetworkLayerTest, Suspend) {
net::HttpNetworkLayer factory(NULL, new net::MockHostResolver,
- net::ProxyService::CreateNull(), new net::SSLConfigServiceDefaults, NULL,
- NULL, NULL);
+ net::ProxyService::CreateDirect(), new net::SSLConfigServiceDefaults,
+ NULL, NULL, NULL);
scoped_ptr<net::HttpTransaction> trans;
int rv = factory.CreateTransaction(&trans);
@@ -68,8 +68,8 @@ TEST_F(HttpNetworkLayerTest, GET) {
mock_socket_factory.AddSocketDataProvider(&data);
net::HttpNetworkLayer factory(&mock_socket_factory, new net::MockHostResolver,
- net::ProxyService::CreateNull(), new net::SSLConfigServiceDefaults, NULL,
- NULL, NULL);
+ net::ProxyService::CreateDirect(), new net::SSLConfigServiceDefaults,
+ NULL, NULL, NULL);
TestCompletionCallback callback;
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 971786a..7b4fe0e 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -9,32 +9,15 @@
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/values.h"
#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_response_body_drainer.h"
#include "net/http/url_security_manager.h"
#include "net/spdy/spdy_session_pool.h"
namespace net {
-namespace {
-
-// Total limit of sockets.
-int g_max_sockets = 256;
-
-// Default to allow up to 6 connections per host. Experiment and tuning may
-// try other values (greater than 0). Too large may cause many problems, such
-// as home routers blocking the connections!?!? See http://crbug.com/12066.
-int g_max_sockets_per_group = 6;
-
-// The max number of sockets to allow per proxy server. This applies both to
-// http and SOCKS proxies. See http://crbug.com/12066 and
-// http://crbug.com/44501 for details about proxy server connection limits.
-int g_max_sockets_per_proxy_server = 32;
-
-uint16 g_fixed_http_port = 0;
-uint16 g_fixed_https_port = 0;
-
-} // namespace
-
+// TODO(mbelshe): Move the socket factories into HttpStreamFactory.
HttpNetworkSession::HttpNetworkSession(
HostResolver* host_resolver,
ProxyService* proxy_service,
@@ -44,26 +27,17 @@ HttpNetworkSession::HttpNetworkSession(
HttpAuthHandlerFactory* http_auth_handler_factory,
HttpNetworkDelegate* network_delegate,
NetLog* net_log)
- : tcp_pool_histograms_(new ClientSocketPoolHistograms("TCP")),
- tcp_for_http_proxy_pool_histograms_(
- new ClientSocketPoolHistograms("TCPforHTTPProxy")),
- http_proxy_pool_histograms_(new ClientSocketPoolHistograms("HTTPProxy")),
- tcp_for_socks_pool_histograms_(
- new ClientSocketPoolHistograms("TCPforSOCKS")),
- socks_pool_histograms_(new ClientSocketPoolHistograms("SOCK")),
- ssl_pool_histograms_(new ClientSocketPoolHistograms("SSL")),
- tcp_socket_pool_(new TCPClientSocketPool(
- g_max_sockets, g_max_sockets_per_group, tcp_pool_histograms_,
- host_resolver, client_socket_factory, net_log)),
- ssl_socket_pool_(new SSLClientSocketPool(
- g_max_sockets, g_max_sockets_per_group, ssl_pool_histograms_,
- host_resolver, client_socket_factory, tcp_socket_pool_, NULL,
- NULL, net_log)),
- socket_factory_(client_socket_factory),
+ : socket_factory_(client_socket_factory),
host_resolver_(host_resolver),
proxy_service_(proxy_service),
ssl_config_service_(ssl_config_service),
+ socket_pool_manager_(net_log,
+ client_socket_factory,
+ host_resolver,
+ proxy_service,
+ ssl_config_service),
spdy_session_pool_(spdy_session_pool),
+ http_stream_factory_(new HttpStreamFactory()),
http_auth_handler_factory_(http_auth_handler_factory),
network_delegate_(network_delegate),
net_log_(net_log) {
@@ -72,100 +46,19 @@ HttpNetworkSession::HttpNetworkSession(
}
HttpNetworkSession::~HttpNetworkSession() {
+ STLDeleteElements(&response_drainers_);
+ spdy_session_pool_->CloseAllSessions();
}
-const scoped_refptr<HttpProxyClientSocketPool>&
-HttpNetworkSession::GetSocketPoolForHTTPProxy(const HostPortPair& http_proxy) {
- HTTPProxySocketPoolMap::const_iterator it =
- http_proxy_socket_pools_.find(http_proxy);
- if (it != http_proxy_socket_pools_.end())
- return it->second;
-
- std::pair<HTTPProxySocketPoolMap::iterator, bool> ret =
- http_proxy_socket_pools_.insert(
- std::make_pair(
- http_proxy,
- new HttpProxyClientSocketPool(
- g_max_sockets_per_proxy_server, g_max_sockets_per_group,
- http_proxy_pool_histograms_, host_resolver_,
- new TCPClientSocketPool(
- g_max_sockets_per_proxy_server, g_max_sockets_per_group,
- tcp_for_http_proxy_pool_histograms_, host_resolver_,
- socket_factory_, net_log_),
- net_log_)));
-
- return ret.first->second;
-}
-
-const scoped_refptr<SOCKSClientSocketPool>&
-HttpNetworkSession::GetSocketPoolForSOCKSProxy(
- const HostPortPair& socks_proxy) {
- SOCKSSocketPoolMap::const_iterator it = socks_socket_pools_.find(socks_proxy);
- if (it != socks_socket_pools_.end())
- return it->second;
-
- std::pair<SOCKSSocketPoolMap::iterator, bool> ret =
- socks_socket_pools_.insert(
- std::make_pair(socks_proxy, new SOCKSClientSocketPool(
- g_max_sockets_per_proxy_server, g_max_sockets_per_group,
- socks_pool_histograms_, host_resolver_,
- new TCPClientSocketPool(g_max_sockets_per_proxy_server,
- g_max_sockets_per_group, tcp_for_socks_pool_histograms_,
- host_resolver_, socket_factory_, net_log_),
- net_log_)));
-
- return ret.first->second;
-}
-
-const scoped_refptr<SSLClientSocketPool>&
-HttpNetworkSession::GetSocketPoolForSSLWithProxy(
- const HostPortPair& proxy_server) {
- SSLSocketPoolMap::const_iterator it =
- ssl_socket_pools_for_proxies_.find(proxy_server);
- if (it != ssl_socket_pools_for_proxies_.end())
- return it->second;
-
- SSLClientSocketPool* new_pool = new SSLClientSocketPool(
- g_max_sockets_per_proxy_server, g_max_sockets_per_group,
- ssl_pool_histograms_, host_resolver_, socket_factory_,
- NULL,
- GetSocketPoolForHTTPProxy(proxy_server),
- GetSocketPoolForSOCKSProxy(proxy_server),
- net_log_);
-
- std::pair<SSLSocketPoolMap::iterator, bool> ret =
- ssl_socket_pools_for_proxies_.insert(std::make_pair(proxy_server,
- new_pool));
-
- return ret.first->second;
-}
-
-// static
-void HttpNetworkSession::set_max_sockets_per_group(int socket_count) {
- DCHECK_LT(0, socket_count);
- // The following is a sanity check... but we should NEVER be near this value.
- DCHECK_GT(100, socket_count);
- g_max_sockets_per_group = socket_count;
-}
-
-// static
-uint16 HttpNetworkSession::fixed_http_port() {
- return g_fixed_http_port;
-}
-
-// static
-void HttpNetworkSession::set_fixed_http_port(uint16 port) {
- g_fixed_http_port = port;
-}
-
-// static
-uint16 HttpNetworkSession::fixed_https_port() {
- return g_fixed_https_port;
+void HttpNetworkSession::AddResponseDrainer(HttpResponseBodyDrainer* drainer) {
+ DCHECK(!ContainsKey(response_drainers_, drainer));
+ response_drainers_.insert(drainer);
}
-// static
-void HttpNetworkSession::set_fixed_https_port(uint16 port) {
- g_fixed_https_port = port;
+void HttpNetworkSession::RemoveResponseDrainer(
+ HttpResponseBodyDrainer* drainer) {
+ DCHECK(ContainsKey(response_drainers_, drainer));
+ response_drainers_.erase(drainer);
}
} // namespace net
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index de57eba..3d1211c 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -4,8 +4,10 @@
#ifndef NET_HTTP_HTTP_NETWORK_SESSION_H_
#define NET_HTTP_HTTP_NETWORK_SESSION_H_
+#pragma once
#include <map>
+#include <set>
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
@@ -17,21 +19,25 @@
#include "net/http/http_auth_cache.h"
#include "net/http/http_network_delegate.h"
#include "net/http/http_network_transaction.h"
-#include "net/http/http_proxy_client_socket_pool.h"
+#include "net/http/http_stream_factory.h"
#include "net/proxy/proxy_service.h"
-#include "net/socket/client_socket_pool_histograms.h"
-#include "net/socket/socks_client_socket_pool.h"
-#include "net/socket/ssl_client_socket_pool.h"
-#include "net/socket/tcp_client_socket_pool.h"
+#include "net/socket/client_socket_pool_manager.h"
#include "net/spdy/spdy_settings_storage.h"
+class Value;
+
namespace net {
class ClientSocketFactory;
class HttpAuthHandlerFactory;
class HttpNetworkDelegate;
class HttpNetworkSessionPeer;
+class HttpProxyClientSocketPool;
+class HttpResponseBodyDrainer;
class SpdySessionPool;
+class SOCKSClientSocketPool;
+class SSLClientSocketPool;
+class TCPClientSocketPool;
// This class holds session objects used by HttpNetworkTransaction objects.
class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>,
@@ -52,6 +58,10 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>,
return &ssl_client_auth_cache_;
}
+ void AddResponseDrainer(HttpResponseBodyDrainer* drainer);
+
+ void RemoveResponseDrainer(HttpResponseBodyDrainer* drainer);
+
const HttpAlternateProtocols& alternate_protocols() const {
return alternate_protocols_;
}
@@ -67,23 +77,28 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>,
return &spdy_settings_;
}
- // TCP sockets come from the tcp_socket_pool().
- const scoped_refptr<TCPClientSocketPool>& tcp_socket_pool() {
- return tcp_socket_pool_;
+ TCPClientSocketPool* tcp_socket_pool() {
+ return socket_pool_manager_.tcp_socket_pool();
}
- const scoped_refptr<SSLClientSocketPool>& ssl_socket_pool() {
- return ssl_socket_pool_;
+ SSLClientSocketPool* ssl_socket_pool() {
+ return socket_pool_manager_.ssl_socket_pool();
}
- const scoped_refptr<SOCKSClientSocketPool>& GetSocketPoolForSOCKSProxy(
- const HostPortPair& socks_proxy);
+ SOCKSClientSocketPool* GetSocketPoolForSOCKSProxy(
+ const HostPortPair& socks_proxy) {
+ return socket_pool_manager_.GetSocketPoolForSOCKSProxy(socks_proxy);
+ }
- const scoped_refptr<HttpProxyClientSocketPool>& GetSocketPoolForHTTPProxy(
- const HostPortPair& http_proxy);
+ HttpProxyClientSocketPool* GetSocketPoolForHTTPProxy(
+ const HostPortPair& http_proxy) {
+ return socket_pool_manager_.GetSocketPoolForHTTPProxy(http_proxy);
+ }
- const scoped_refptr<SSLClientSocketPool>& GetSocketPoolForSSLWithProxy(
- const HostPortPair& proxy_server);
+ SSLClientSocketPool* GetSocketPoolForSSLWithProxy(
+ const HostPortPair& proxy_server) {
+ return socket_pool_manager_.GetSocketPoolForSSLWithProxy(proxy_server);
+ }
// SSL sockets come from the socket_factory().
ClientSocketFactory* socket_factory() { return socket_factory_; }
@@ -100,77 +115,41 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>,
return network_delegate_;
}
- static void set_max_sockets_per_group(int socket_count);
-
- static uint16 fixed_http_port();
- static void set_fixed_http_port(uint16 port);
+ const scoped_refptr<HttpStreamFactory>& http_stream_factory() {
+ return http_stream_factory_;
+ }
- static uint16 fixed_https_port();
- static void set_fixed_https_port(uint16 port);
+ // Creates a Value summary of the state of the socket pools. The caller is
+ // responsible for deleting the returned value.
+ Value* SocketPoolInfoToValue() const {
+ return socket_pool_manager_.SocketPoolInfoToValue();
+ }
-#ifdef UNIT_TEST
void FlushSocketPools() {
- if (ssl_socket_pool_.get())
- ssl_socket_pool_->Flush();
- if (tcp_socket_pool_.get())
- tcp_socket_pool_->Flush();
-
- for (SSLSocketPoolMap::const_iterator it =
- ssl_socket_pools_for_proxies_.begin();
- it != ssl_socket_pools_for_proxies_.end();
- it++)
- it->second->Flush();
-
- for (SOCKSSocketPoolMap::const_iterator it =
- socks_socket_pools_.begin();
- it != socks_socket_pools_.end();
- it++)
- it->second->Flush();
-
- for (HTTPProxySocketPoolMap::const_iterator it =
- http_proxy_socket_pools_.begin();
- it != http_proxy_socket_pools_.end();
- it++)
- it->second->Flush();
- }
-#endif
+ socket_pool_manager_.FlushSocketPools();
+ }
private:
- typedef std::map<HostPortPair, scoped_refptr<HttpProxyClientSocketPool> >
- HTTPProxySocketPoolMap;
- typedef std::map<HostPortPair, scoped_refptr<SOCKSClientSocketPool> >
- SOCKSSocketPoolMap;
- typedef std::map<HostPortPair, scoped_refptr<SSLClientSocketPool> >
- SSLSocketPoolMap;
-
friend class base::RefCounted<HttpNetworkSession>;
friend class HttpNetworkSessionPeer;
~HttpNetworkSession();
+ ClientSocketFactory* const socket_factory_;
HttpAuthCache auth_cache_;
SSLClientAuthCache ssl_client_auth_cache_;
HttpAlternateProtocols alternate_protocols_;
- scoped_refptr<ClientSocketPoolHistograms> tcp_pool_histograms_;
- scoped_refptr<ClientSocketPoolHistograms> tcp_for_http_proxy_pool_histograms_;
- scoped_refptr<ClientSocketPoolHistograms> http_proxy_pool_histograms_;
- scoped_refptr<ClientSocketPoolHistograms> tcp_for_socks_pool_histograms_;
- scoped_refptr<ClientSocketPoolHistograms> socks_pool_histograms_;
- scoped_refptr<ClientSocketPoolHistograms> ssl_pool_histograms_;
- scoped_refptr<TCPClientSocketPool> tcp_socket_pool_;
- scoped_refptr<SSLClientSocketPool> ssl_socket_pool_;
- HTTPProxySocketPoolMap http_proxy_socket_pools_;
- SOCKSSocketPoolMap socks_socket_pools_;
- SSLSocketPoolMap ssl_socket_pools_for_proxies_;
- ClientSocketFactory* socket_factory_;
scoped_refptr<HostResolver> host_resolver_;
scoped_refptr<ProxyService> proxy_service_;
scoped_refptr<SSLConfigService> ssl_config_service_;
+ ClientSocketPoolManager socket_pool_manager_;
scoped_refptr<SpdySessionPool> spdy_session_pool_;
+ scoped_refptr<HttpStreamFactory> http_stream_factory_;
HttpAuthHandlerFactory* http_auth_handler_factory_;
HttpNetworkDelegate* const network_delegate_;
NetLog* net_log_;
SpdySettingsStorage spdy_settings_;
+ std::set<HttpResponseBodyDrainer*> response_drainers_;
};
} // namespace net
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 6783a0a..0f0a7ea 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -4,6 +4,9 @@
#include "net/http/http_network_transaction.h"
+#include <set>
+#include <vector>
+
#include "base/compiler_specific.h"
#include "base/field_trial.h"
#include "base/format_macros.h"
@@ -11,11 +14,12 @@
#include "base/scoped_ptr.h"
#include "base/stats_counters.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "build/build_config.h"
#include "googleurl/src/gurl.h"
-#include "net/base/connection_type_histograms.h"
-#include "net/base/host_mapping_rules.h"
+#include "net/base/auth.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -34,8 +38,10 @@
#include "net/http/http_proxy_client_socket_pool.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_request_info.h"
+#include "net/http/http_response_body_drainer.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
+#include "net/http/http_stream_request.h"
#include "net/http/http_util.h"
#include "net/http/url_security_manager.h"
#include "net/socket/client_socket_factory.h"
@@ -53,14 +59,6 @@ namespace net {
namespace {
-const HostMappingRules* g_host_mapping_rules = NULL;
-const std::string* g_next_protos = NULL;
-bool g_use_alternate_protocols = false;
-
-// A set of host:port strings. These are servers which we have needed to back
-// off to SSLv3 for.
-std::set<std::string>* g_tls_intolerant_servers = NULL;
-
void BuildRequestHeaders(const HttpRequestInfo* request_info,
const HttpRequestHeaders& authorization_headers,
const UploadDataStream* upload_data_stream,
@@ -70,7 +68,7 @@ void BuildRequestHeaders(const HttpRequestInfo* request_info,
const std::string path = using_proxy ?
HttpUtil::SpecForRequest(request_info->url) :
HttpUtil::PathForRequest(request_info->url);
- *request_line = StringPrintf(
+ *request_line = base::StringPrintf(
"%s %s HTTP/1.1\r\n", request_info->method.c_str(), path.c_str());
request_headers->SetHeader(HttpRequestHeaders::kHost,
GetHostAndOptionalPort(request_info->url));
@@ -94,7 +92,7 @@ void BuildRequestHeaders(const HttpRequestInfo* request_info,
if (upload_data_stream) {
request_headers->SetHeader(
HttpRequestHeaders::kContentLength,
- Uint64ToString(upload_data_stream->size()));
+ base::Uint64ToString(upload_data_stream->size()));
} else if (request_info->method == "POST" || request_info->method == "PUT" ||
request_info->method == "HEAD") {
// An empty POST/PUT request still needs a content length. As for HEAD,
@@ -130,67 +128,27 @@ void BuildRequestHeaders(const HttpRequestInfo* request_info,
request_headers->MergeFrom(stripped_extra_headers);
}
-void ProcessAlternateProtocol(const HttpResponseHeaders& headers,
- const HostPortPair& http_host_port_pair,
- HttpAlternateProtocols* alternate_protocols) {
-
+void ProcessAlternateProtocol(HttpStreamFactory* factory,
+ HttpAlternateProtocols* alternate_protocols,
+ const HttpResponseHeaders& headers,
+ const HostPortPair& http_host_port_pair) {
std::string alternate_protocol_str;
+
if (!headers.EnumerateHeader(NULL, HttpAlternateProtocols::kHeader,
&alternate_protocol_str)) {
// Header is not present.
return;
}
- std::vector<std::string> port_protocol_vector;
- SplitString(alternate_protocol_str, ':', &port_protocol_vector);
- if (port_protocol_vector.size() != 2) {
- DLOG(WARNING) << HttpAlternateProtocols::kHeader
- << " header has too many tokens: "
- << alternate_protocol_str;
- return;
- }
-
- int port;
- if (!StringToInt(port_protocol_vector[0], &port) ||
- port <= 0 || port >= 1 << 16) {
- DLOG(WARNING) << HttpAlternateProtocols::kHeader
- << " header has unrecognizable port: "
- << port_protocol_vector[0];
- return;
- }
-
- if (port_protocol_vector[1] !=
- HttpAlternateProtocols::kProtocolStrings[
- HttpAlternateProtocols::NPN_SPDY_1]) {
- // Currently, we only recognize the npn-spdy protocol.
- DLOG(WARNING) << HttpAlternateProtocols::kHeader
- << " header has unrecognized protocol: "
- << port_protocol_vector[1];
- return;
- }
-
- HostPortPair host_port(http_host_port_pair);
- if (g_host_mapping_rules)
- g_host_mapping_rules->RewriteHost(&host_port);
-
- if (alternate_protocols->HasAlternateProtocolFor(host_port)) {
- const HttpAlternateProtocols::PortProtocolPair existing_alternate =
- alternate_protocols->GetAlternateProtocolFor(host_port);
- // If we think the alternate protocol is broken, don't change it.
- if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
- return;
- }
-
- alternate_protocols->SetAlternateProtocolFor(
- host_port, port, HttpAlternateProtocols::NPN_SPDY_1);
+ factory->ProcessAlternateProtocol(alternate_protocols,
+ alternate_protocol_str,
+ http_host_port_pair);
}
} // namespace
//-----------------------------------------------------------------------------
-bool HttpNetworkTransaction::g_ignore_certificate_errors = false;
-
HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
: pending_auth_target_(HttpAuth::AUTH_NONE),
ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -198,49 +156,52 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session)
user_callback_(NULL),
session_(session),
request_(NULL),
- pac_request_(NULL),
- connection_(new ClientSocketHandle),
- reused_socket_(false),
headers_valid_(false),
logged_response_time_(false),
- using_ssl_(false),
- using_spdy_(false),
- spdy_certificate_error_(OK),
- alternate_protocol_mode_(
- g_use_alternate_protocols ? kUnspecified :
- kDoNotUseAlternateProtocol),
read_buf_len_(0),
next_state_(STATE_NONE),
establishing_tunnel_(false) {
session->ssl_config_service()->GetSSLConfig(&ssl_config_);
- if (g_next_protos)
- ssl_config_.next_protos = *g_next_protos;
- if (!g_tls_intolerant_servers)
- g_tls_intolerant_servers = new std::set<std::string>;
-}
+ if (session->http_stream_factory()->next_protos())
+ ssl_config_.next_protos = *session->http_stream_factory()->next_protos();
-// static
-void HttpNetworkTransaction::SetHostMappingRules(const std::string& rules) {
- HostMappingRules* host_mapping_rules = new HostMappingRules();
- host_mapping_rules->SetRulesFromString(rules);
- delete g_host_mapping_rules;
- g_host_mapping_rules = host_mapping_rules;
}
-// static
-void HttpNetworkTransaction::SetUseAlternateProtocols(bool value) {
- g_use_alternate_protocols = value;
-}
-
-// static
-void HttpNetworkTransaction::SetNextProtos(const std::string& next_protos) {
- delete g_next_protos;
- g_next_protos = new std::string(next_protos);
-}
+HttpNetworkTransaction::~HttpNetworkTransaction() {
+ if (stream_.get()) {
+ HttpResponseHeaders* headers = GetResponseHeaders();
+ // TODO(mbelshe): The stream_ should be able to compute whether or not the
+ // stream should be kept alive. No reason to compute here
+ // and pass it in.
+ bool try_to_keep_alive =
+ next_state_ == STATE_NONE &&
+ stream_->CanFindEndOfResponse() &&
+ (!headers || headers->IsKeepAlive());
+ if (!try_to_keep_alive) {
+ stream_->Close(true /* not reusable */);
+ } else {
+ if (stream_->IsResponseBodyComplete()) {
+ // If the response body is complete, we can just reuse the socket.
+ stream_->Close(false /* reusable */);
+ } else {
+ // Otherwise, we try to drain the response body.
+ // TODO(willchan): Consider moving this response body draining to the
+ // stream implementation. For SPDY, there's clearly no point. For
+ // HTTP, it can vary depending on whether or not we're pipelining. It's
+ // stream dependent, so the different subtypes should be implementing
+ // their solutions.
+ HttpResponseBodyDrainer* drainer =
+ new HttpResponseBodyDrainer(stream_.release());
+ drainer->Start(session_);
+ // |drainer| will delete itself.
+ }
+ }
+ }
-// static
-void HttpNetworkTransaction::IgnoreCertificateErrors(bool enabled) {
- g_ignore_certificate_errors = enabled;
+ if (stream_request_.get()) {
+ stream_request_->Cancel();
+ stream_request_ = NULL;
+ }
}
int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
@@ -252,7 +213,7 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
request_ = request_info;
start_time_ = base::Time::Now();
- next_state_ = STATE_RESOLVE_PROXY;
+ next_state_ = STATE_CREATE_STREAM;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
@@ -261,21 +222,12 @@ int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
int HttpNetworkTransaction::RestartIgnoringLastError(
CompletionCallback* callback) {
- if (connection_->socket() && connection_->socket()->IsConnectedAndIdle()) {
- // TODO(wtc): Should we update any of the connection histograms that we
- // update in DoSSLConnectComplete if |result| is OK?
- if (using_spdy_) {
- // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620
- next_state_ = STATE_SPDY_GET_STREAM;
- } else {
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- }
- } else {
- if (connection_->socket())
- connection_->socket()->Disconnect();
- connection_->Reset();
- next_state_ = STATE_INIT_CONNECTION;
- }
+ DCHECK(!stream_.get());
+ DCHECK(!stream_request_.get());
+ DCHECK_EQ(STATE_NONE, next_state_);
+
+ next_state_ = STATE_CREATE_STREAM;
+
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
@@ -285,16 +237,22 @@ int HttpNetworkTransaction::RestartIgnoringLastError(
int HttpNetworkTransaction::RestartWithCertificate(
X509Certificate* client_cert,
CompletionCallback* callback) {
+ // In HandleCertificateRequest(), we always tear down existing stream
+ // requests to force a new connection. So we shouldn't have one here.
+ DCHECK(!stream_request_.get());
+ DCHECK(!stream_.get());
+ DCHECK_EQ(STATE_NONE, next_state_);
+
ssl_config_.client_cert = client_cert;
if (client_cert) {
session_->ssl_client_auth_cache()->Add(GetHostAndPort(request_->url),
client_cert);
}
ssl_config_.send_client_cert = true;
- next_state_ = STATE_INIT_CONNECTION;
// Reset the other member variables.
// Note: this is necessary only with SSL renegotiation.
ResetStateForRestart();
+ next_state_ = STATE_CREATE_STREAM;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
@@ -302,8 +260,8 @@ int HttpNetworkTransaction::RestartWithCertificate(
}
int HttpNetworkTransaction::RestartWithAuth(
- const std::wstring& username,
- const std::wstring& password,
+ const string16& username,
+ const string16& password,
CompletionCallback* callback) {
HttpAuth::Target target = pending_auth_target_;
if (target == HttpAuth::AUTH_NONE) {
@@ -314,33 +272,42 @@ int HttpNetworkTransaction::RestartWithAuth(
auth_controllers_[target]->ResetAuth(username, password);
- if (target == HttpAuth::AUTH_PROXY && using_ssl_ && proxy_info_.is_http()) {
- DCHECK(establishing_tunnel_);
- next_state_ = STATE_INIT_CONNECTION;
+ DCHECK(user_callback_ == NULL);
+
+ int rv = OK;
+ if (target == HttpAuth::AUTH_PROXY && establishing_tunnel_) {
+ // In this case, we've gathered credentials for use with proxy
+ // authentication of a tunnel.
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
+ DCHECK(stream_request_ != NULL);
+ auth_controllers_[target] = NULL;
ResetStateForRestart();
+ rv = stream_request_->RestartTunnelWithProxyAuth(username, password);
} else {
+ // In this case, we've gathered credentials for the server or the proxy
+ // but it is not during the tunneling phase.
+ DCHECK(stream_request_ == NULL);
PrepareForAuthRestart(target);
+ rv = DoLoop(OK);
}
- DCHECK(user_callback_ == NULL);
- int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
-
return rv;
}
void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
DCHECK(HaveAuth(target));
- DCHECK(!establishing_tunnel_);
+ DCHECK(!stream_request_.get());
+
bool keep_alive = false;
// Even if the server says the connection is keep-alive, we have to be
// able to find the end of each response in order to reuse the connection.
if (GetResponseHeaders()->IsKeepAlive() &&
- http_stream_->CanFindEndOfResponse()) {
+ stream_->CanFindEndOfResponse()) {
// If the response body hasn't been completely read, we need to drain
// it first.
- if (!http_stream_->IsResponseBodyComplete()) {
+ if (!stream_->IsResponseBodyComplete()) {
next_state_ = STATE_DRAIN_BODY_FOR_AUTH_RESTART;
read_buf_ = new IOBuffer(kDrainBodyBufferSize); // A bit bucket.
read_buf_len_ = kDrainBodyBufferSize;
@@ -355,23 +322,27 @@ void HttpNetworkTransaction::PrepareForAuthRestart(HttpAuth::Target target) {
}
void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) {
- DCHECK(!establishing_tunnel_);
- if (keep_alive && connection_->socket()->IsConnectedAndIdle()) {
- // We should call connection_->set_idle_time(), but this doesn't occur
- // often enough to be worth the trouble.
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- connection_->set_is_reused(true);
- reused_socket_ = true;
- } else {
- next_state_ = STATE_INIT_CONNECTION;
- connection_->socket()->Disconnect();
- connection_->Reset();
+ DCHECK(!stream_request_.get());
+
+ if (stream_.get()) {
+ if (keep_alive) {
+ // We should call connection_->set_idle_time(), but this doesn't occur
+ // often enough to be worth the trouble.
+ stream_->SetConnectionReused();
+ }
+ stream_->Close(!keep_alive);
+ next_state_ = STATE_CREATE_STREAM;
}
// Reset the other member variables.
ResetStateForRestart();
}
+bool HttpNetworkTransaction::IsReadyToRestartForAuth() {
+ return pending_auth_target_ != HttpAuth::AUTH_NONE &&
+ HaveAuth(pending_auth_target_);
+}
+
int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(buf);
@@ -380,7 +351,7 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
State next_state = STATE_NONE;
scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
- if (headers_valid_ && headers.get() && establishing_tunnel_) {
+ 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
// bytes when establishing a tunnel because they might be controlled by
@@ -388,7 +359,7 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
// because an active network attacker can already control HTTP sessions.
// We reach this case when the user cancels a 407 proxy auth prompt.
// See http://crbug.com/8473.
- DCHECK(proxy_info_.is_http());
+ DCHECK(proxy_info_.is_http() || proxy_info_.is_https());
DCHECK_EQ(headers->response_code(), 407);
LOG(WARNING) << "Blocked proxy response with status "
<< headers->response_code() << " to CONNECT request for "
@@ -397,17 +368,8 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
}
// Are we using SPDY or HTTP?
- if (using_spdy_) {
- DCHECK(!http_stream_.get());
- DCHECK(spdy_http_stream_->GetResponseInfo()->headers);
- next_state = STATE_SPDY_READ_BODY;
- } else {
- DCHECK(!spdy_http_stream_.get());
- next_state = STATE_READ_BODY;
-
- if (!connection_->is_initialized())
- return 0; // |*connection_| has been reset. Treat like EOF.
- }
+ next_state = STATE_READ_BODY;
+ DCHECK(stream_->GetResponseInfo()->headers);
read_buf_ = buf;
read_buf_len_ = buf_len;
@@ -428,21 +390,15 @@ LoadState HttpNetworkTransaction::GetLoadState() const {
// TODO(wtc): Define a new LoadState value for the
// STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
switch (next_state_) {
- case STATE_RESOLVE_PROXY_COMPLETE:
- return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
- case STATE_INIT_CONNECTION_COMPLETE:
- return connection_->GetLoadState();
+ case STATE_CREATE_STREAM_COMPLETE:
+ return stream_request_->GetLoadState();
case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE:
case STATE_SEND_REQUEST_COMPLETE:
- case STATE_SPDY_GET_STREAM:
- case STATE_SPDY_SEND_REQUEST_COMPLETE:
return LOAD_STATE_SENDING_REQUEST;
case STATE_READ_HEADERS_COMPLETE:
- case STATE_SPDY_READ_HEADERS_COMPLETE:
return LOAD_STATE_WAITING_FOR_RESPONSE;
case STATE_READ_BODY_COMPLETE:
- case STATE_SPDY_READ_BODY_COMPLETE:
return LOAD_STATE_READING_RESPONSE;
default:
return LOAD_STATE_IDLE;
@@ -450,37 +406,84 @@ LoadState HttpNetworkTransaction::GetLoadState() const {
}
uint64 HttpNetworkTransaction::GetUploadProgress() const {
- if (!http_stream_.get())
+ if (!stream_.get())
return 0;
- return http_stream_->GetUploadProgress();
+ return stream_->GetUploadProgress();
}
-HttpNetworkTransaction::~HttpNetworkTransaction() {
- // If we still have an open socket, then make sure to disconnect it so it
- // won't call us back and we don't try to reuse it later on. However,
- // don't close the socket if we should keep the connection alive.
- if (connection_.get() && connection_->is_initialized()) {
- // The STATE_NONE check guarantees there are no pending socket IOs that
- // could try to call this object back after it is deleted.
- bool keep_alive = next_state_ == STATE_NONE &&
- http_stream_.get() &&
- http_stream_->IsResponseBodyComplete() &&
- http_stream_->CanFindEndOfResponse() &&
- GetResponseHeaders()->IsKeepAlive();
- if (!keep_alive)
- connection_->socket()->Disconnect();
- }
+void HttpNetworkTransaction::OnStreamReady(HttpStream* stream) {
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
+ DCHECK(stream_request_.get());
+
+ stream_.reset(stream);
+ response_.was_alternate_protocol_available =
+ stream_request_->was_alternate_protocol_available();
+ response_.was_npn_negotiated = stream_request_->was_npn_negotiated();
+ response_.was_fetched_via_spdy = stream_request_->using_spdy();
+ response_.was_fetched_via_proxy = !proxy_info_.is_direct();
+
+ OnIOComplete(OK);
+}
+
+void HttpNetworkTransaction::OnStreamFailed(int result) {
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
+ DCHECK_NE(OK, result);
+ DCHECK(stream_request_.get());
+ DCHECK(!stream_.get());
+
+ OnIOComplete(result);
+}
+
+void HttpNetworkTransaction::OnCertificateError(int result,
+ const SSLInfo& ssl_info) {
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
+ DCHECK_NE(OK, result);
+ DCHECK(stream_request_.get());
+ DCHECK(!stream_.get());
+
+ response_.ssl_info = ssl_info;
+
+ // TODO(mbelshe): For now, we're going to pass the error through, and that
+ // will close the stream_request in all cases. This means that we're always
+ // going to restart an entire STATE_CREATE_STREAM, even if the connection is
+ // good and the user chooses to ignore the error. This is not ideal, but not
+ // the end of the world either.
+
+ OnIOComplete(result);
+}
+
+void HttpNetworkTransaction::OnNeedsProxyAuth(
+ const HttpResponseInfo& proxy_response,
+ HttpAuthController* auth_controller) {
+ DCHECK(stream_request_.get());
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
+
+ establishing_tunnel_ = true;
+ response_.headers = proxy_response.headers;
+ response_.auth_challenge = proxy_response.auth_challenge;
+ headers_valid_ = true;
- if (pac_request_)
- session_->proxy_service()->CancelPacRequest(pac_request_);
+ auth_controllers_[HttpAuth::AUTH_PROXY] = auth_controller;
+ pending_auth_target_ = HttpAuth::AUTH_PROXY;
- if (spdy_http_stream_.get())
- spdy_http_stream_->Cancel();
+ DoCallback(OK);
+}
+
+void HttpNetworkTransaction::OnNeedsClientAuth(
+ SSLCertRequestInfo* cert_info) {
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
+
+ response_.cert_request_info = cert_info;
+ OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+}
+
+bool HttpNetworkTransaction::is_https_request() const {
+ return request_->url.SchemeIs("https");
}
void HttpNetworkTransaction::DoCallback(int rv) {
- DCHECK(rv != ERR_IO_PENDING);
+ DCHECK_NE(rv, ERR_IO_PENDING);
DCHECK(user_callback_);
// Since Run may result in Read being called, clear user_callback_ up front.
@@ -503,19 +506,19 @@ int HttpNetworkTransaction::DoLoop(int result) {
State state = next_state_;
next_state_ = STATE_NONE;
switch (state) {
- case STATE_RESOLVE_PROXY:
+ case STATE_CREATE_STREAM:
DCHECK_EQ(OK, rv);
- rv = DoResolveProxy();
+ rv = DoCreateStream();
break;
- case STATE_RESOLVE_PROXY_COMPLETE:
- rv = DoResolveProxyComplete(rv);
+ case STATE_CREATE_STREAM_COMPLETE:
+ rv = DoCreateStreamComplete(rv);
break;
- case STATE_INIT_CONNECTION:
+ case STATE_INIT_STREAM:
DCHECK_EQ(OK, rv);
- rv = DoInitConnection();
+ rv = DoInitStream();
break;
- case STATE_INIT_CONNECTION_COMPLETE:
- rv = DoInitConnectionComplete(rv);
+ case STATE_INIT_STREAM_COMPLETE:
+ rv = DoInitStreamComplete(rv);
break;
case STATE_GENERATE_PROXY_AUTH_TOKEN:
DCHECK_EQ(OK, rv);
@@ -569,40 +572,6 @@ int HttpNetworkTransaction::DoLoop(int result) {
net_log_.EndEvent(
NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, NULL);
break;
- case STATE_SPDY_GET_STREAM:
- DCHECK_EQ(OK, rv);
- rv = DoSpdyGetStream();
- break;
- case STATE_SPDY_GET_STREAM_COMPLETE:
- rv = DoSpdyGetStreamComplete(rv);
- break;
- case STATE_SPDY_SEND_REQUEST:
- DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
- rv = DoSpdySendRequest();
- break;
- case STATE_SPDY_SEND_REQUEST_COMPLETE:
- rv = DoSpdySendRequestComplete(rv);
- net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
- break;
- case STATE_SPDY_READ_HEADERS:
- DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
- rv = DoSpdyReadHeaders();
- break;
- case STATE_SPDY_READ_HEADERS_COMPLETE:
- rv = DoSpdyReadHeadersComplete(rv);
- net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
- break;
- case STATE_SPDY_READ_BODY:
- DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
- rv = DoSpdyReadBody();
- break;
- case STATE_SPDY_READ_BODY_COMPLETE:
- rv = DoSpdyReadBodyComplete(rv);
- net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
- break;
default:
NOTREACHED() << "bad state";
rv = ERR_FAILED;
@@ -613,347 +582,70 @@ int HttpNetworkTransaction::DoLoop(int result) {
return rv;
}
-int HttpNetworkTransaction::DoResolveProxy() {
- DCHECK(!pac_request_);
-
- next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
-
- // |endpoint_| indicates the final destination endpoint.
- endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
- request_->url.EffectiveIntPort());
-
- // Extra URL we might be attempting to resolve to.
- GURL alternate_endpoint_url;
-
- // Tracks whether we are using |request_->url| or |alternate_endpoint_url|.
- const GURL *curr_endpoint_url = &request_->url;
-
- if (g_host_mapping_rules && g_host_mapping_rules->RewriteHost(&endpoint_)) {
- url_canon::Replacements<char> replacements;
- const std::string port_str = IntToString(endpoint_.port);
- replacements.SetPort(port_str.c_str(),
- url_parse::Component(0, port_str.size()));
- replacements.SetHost(endpoint_.host.c_str(),
- url_parse::Component(0, endpoint_.host.size()));
- alternate_endpoint_url = curr_endpoint_url->ReplaceComponents(replacements);
- curr_endpoint_url = &alternate_endpoint_url;
- }
-
- const HttpAlternateProtocols& alternate_protocols =
- session_->alternate_protocols();
- if (alternate_protocols.HasAlternateProtocolFor(endpoint_)) {
- response_.was_alternate_protocol_available = true;
- if (alternate_protocol_mode_ == kUnspecified) {
- HttpAlternateProtocols::PortProtocolPair alternate =
- alternate_protocols.GetAlternateProtocolFor(endpoint_);
- if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
- DCHECK_EQ(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
- endpoint_.port = alternate.port;
- alternate_protocol_ = HttpAlternateProtocols::NPN_SPDY_1;
- alternate_protocol_mode_ = kUsingAlternateProtocol;
-
- url_canon::Replacements<char> replacements;
- replacements.SetScheme("https",
- url_parse::Component(0, strlen("https")));
- const std::string port_str = IntToString(endpoint_.port);
- replacements.SetPort(port_str.c_str(),
- url_parse::Component(0, port_str.size()));
- alternate_endpoint_url =
- curr_endpoint_url->ReplaceComponents(replacements);
- curr_endpoint_url = &alternate_endpoint_url;
- }
- }
- }
+int HttpNetworkTransaction::DoCreateStream() {
+ next_state_ = STATE_CREATE_STREAM_COMPLETE;
- if (request_->load_flags & LOAD_BYPASS_PROXY) {
- proxy_info_.UseDirect();
- return OK;
- }
-
- return session_->proxy_service()->ResolveProxy(
- *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_, net_log_);
+ session_->http_stream_factory()->RequestStream(request_,
+ &ssl_config_,
+ &proxy_info_,
+ this,
+ net_log_,
+ session_,
+ &stream_request_);
+ return ERR_IO_PENDING;
}
-int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
- pac_request_ = NULL;
-
- if (result != OK)
- return result;
-
- // Remove unsupported proxies from the list.
- proxy_info_.RemoveProxiesWithoutScheme(
- ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP |
- ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
-
- if (proxy_info_.is_empty()) {
- // No proxies/direct to choose from. This happens when we don't support any
- // of the proxies in the returned list.
- return ERR_NO_SUPPORTED_PROXIES;
+int HttpNetworkTransaction::DoCreateStreamComplete(int result) {
+ if (result == OK) {
+ next_state_ = STATE_INIT_STREAM;
+ DCHECK(stream_.get());
}
- next_state_ = STATE_INIT_CONNECTION;
- return OK;
+ // At this point we are done with the stream_request_.
+ stream_request_ = NULL;
+ return result;
}
-int HttpNetworkTransaction::DoInitConnection() {
- DCHECK(!connection_->is_initialized());
- DCHECK(proxy_info_.proxy_server().is_valid());
- next_state_ = STATE_INIT_CONNECTION_COMPLETE;
-
- // Now that the proxy server has been resolved, create the auth_controllers_.
- for (int i = 0; i < HttpAuth::AUTH_NUM_TARGETS; i++) {
- HttpAuth::Target target = static_cast<HttpAuth::Target>(i);
- if (!auth_controllers_[target].get())
- auth_controllers_[target] = new HttpAuthController(target,
- AuthURL(target),
- session_);
- }
-
- bool want_spdy = alternate_protocol_mode_ == kUsingAlternateProtocol
- && alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_1;
- using_ssl_ = request_->url.SchemeIs("https") || want_spdy;
- using_spdy_ = false;
- response_.was_fetched_via_proxy = !proxy_info_.is_direct();
-
- // Use the fixed testing ports if they've been provided.
- if (using_ssl_) {
- if (session_->fixed_https_port() != 0)
- endpoint_.port = session_->fixed_https_port();
- } else if (session_->fixed_http_port() != 0) {
- endpoint_.port = session_->fixed_http_port();
- }
-
- // Check first if we have a spdy session for this group. If so, then go
- // straight to using that.
- if (session_->spdy_session_pool()->HasSession(endpoint_)) {
- using_spdy_ = true;
- reused_socket_ = true;
- next_state_ = STATE_SPDY_GET_STREAM;
- return OK;
- }
-
- // Build the string used to uniquely identify connections of this type.
- // Determine the host and port to connect to.
- std::string connection_group = endpoint_.ToString();
- DCHECK(!connection_group.empty());
-
- if (using_ssl_)
- connection_group = StringPrintf("ssl/%s", connection_group.c_str());
-
- // If the user is refreshing the page, bypass the host cache.
- bool disable_resolver_cache = request_->load_flags & LOAD_BYPASS_CACHE ||
- request_->load_flags & LOAD_VALIDATE_CACHE ||
- request_->load_flags & LOAD_DISABLE_CACHE;
-
- // Build up the connection parameters.
- scoped_refptr<TCPSocketParams> tcp_params;
- scoped_refptr<HttpProxySocketParams> http_proxy_params;
- scoped_refptr<SOCKSSocketParams> socks_params;
- scoped_ptr<HostPortPair> proxy_host_port;
-
- if (proxy_info_.is_direct()) {
- tcp_params = new TCPSocketParams(endpoint_, request_->priority,
- request_->referrer,
- disable_resolver_cache);
- } else {
- ProxyServer proxy_server = proxy_info_.proxy_server();
- proxy_host_port.reset(new HostPortPair(proxy_server.HostNoBrackets(),
- proxy_server.port()));
- scoped_refptr<TCPSocketParams> proxy_tcp_params =
- new TCPSocketParams(*proxy_host_port, request_->priority,
- request_->referrer, disable_resolver_cache);
-
- if (proxy_info_.is_http()) {
- scoped_refptr<HttpAuthController> http_proxy_auth;
- if (using_ssl_) {
- http_proxy_auth = auth_controllers_[HttpAuth::AUTH_PROXY];
- establishing_tunnel_ = true;
- }
- http_proxy_params = new HttpProxySocketParams(proxy_tcp_params,
- request_->url, endpoint_,
- http_proxy_auth,
- using_ssl_);
- } else {
- DCHECK(proxy_info_.is_socks());
- char socks_version;
- if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5)
- socks_version = '5';
- else
- socks_version = '4';
- connection_group =
- StringPrintf("socks%c/%s", socks_version, connection_group.c_str());
-
- socks_params = new SOCKSSocketParams(proxy_tcp_params,
- socks_version == '5',
- endpoint_,
- request_->priority,
- request_->referrer);
- }
- }
-
- // Deal with SSL - which layers on top of any given proxy.
- if (using_ssl_) {
- if (ContainsKey(*g_tls_intolerant_servers, GetHostAndPort(request_->url))) {
- LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
- << GetHostAndPort(request_->url);
- ssl_config_.ssl3_fallback = true;
- ssl_config_.tls1_enabled = false;
- }
-
- UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback",
- (int) ssl_config_.ssl3_fallback, 2);
-
- int load_flags = request_->load_flags;
- if (g_ignore_certificate_errors)
- load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
- if (request_->load_flags & LOAD_VERIFY_EV_CERT)
- ssl_config_.verify_ev_cert = true;
-
- scoped_refptr<SSLSocketParams> ssl_params =
- new SSLSocketParams(tcp_params, http_proxy_params, socks_params,
- proxy_info_.proxy_server().scheme(),
- request_->url.HostNoBrackets(), ssl_config_,
- load_flags, want_spdy);
-
- scoped_refptr<SSLClientSocketPool> ssl_pool;
- if (proxy_info_.is_direct())
- ssl_pool = session_->ssl_socket_pool();
- else
- ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port);
-
- return connection_->Init(connection_group, ssl_params, request_->priority,
- &io_callback_, ssl_pool, net_log_);
- }
-
- // Finally, get the connection started.
- if (proxy_info_.is_http()) {
- return connection_->Init(
- connection_group, http_proxy_params, request_->priority, &io_callback_,
- session_->GetSocketPoolForHTTPProxy(*proxy_host_port), net_log_);
- }
-
- if (proxy_info_.is_socks()) {
- return connection_->Init(
- connection_group, socks_params, request_->priority, &io_callback_,
- session_->GetSocketPoolForSOCKSProxy(*proxy_host_port), net_log_);
- }
-
- DCHECK(proxy_info_.is_direct());
- return connection_->Init(connection_group, tcp_params, request_->priority,
- &io_callback_, session_->tcp_socket_pool(),
- net_log_);
+int HttpNetworkTransaction::DoInitStream() {
+ DCHECK(stream_.get());
+ next_state_ = STATE_INIT_STREAM_COMPLETE;
+ return stream_->InitializeStream(request_, net_log_, &io_callback_);
}
-int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
- // |result| may be the result of any of the stacked pools. The following
- // logic is used when determining how to interpret an error.
- // If |result| < 0:
- // and connection_->socket() != NULL, then the SSL handshake ran and it
- // is a potentially recoverable error.
- // and connection_->socket == NULL and connection_->is_ssl_error() is true,
- // then the SSL handshake ran with an unrecoverable error.
- // otherwise, the error came from one of the other pools.
- bool ssl_started = using_ssl_ && (result == OK || connection_->socket() ||
- connection_->is_ssl_error());
-
- if (ssl_started && (result == OK || IsCertificateError(result))) {
- SSLClientSocket* ssl_socket =
- static_cast<SSLClientSocket*>(connection_->socket());
- if (ssl_socket->wasNpnNegotiated()) {
- response_.was_npn_negotiated = true;
- std::string proto;
- ssl_socket->GetNextProto(&proto);
- if (SSLClientSocket::NextProtoFromString(proto) ==
- SSLClientSocket::kProtoSPDY1)
- using_spdy_ = true;
- }
- }
-
- if (result == ERR_PROXY_AUTH_REQUESTED) {
- DCHECK(!ssl_started);
- const HttpResponseInfo& tunnel_auth_response =
- connection_->ssl_error_response_info();
-
- response_.headers = tunnel_auth_response.headers;
- response_.auth_challenge = tunnel_auth_response.auth_challenge;
- headers_valid_ = true;
- pending_auth_target_ = HttpAuth::AUTH_PROXY;
- return OK;
- }
-
- if ((!ssl_started && result < 0 &&
- alternate_protocol_mode_ == kUsingAlternateProtocol) ||
- result == ERR_NPN_NEGOTIATION_FAILED) {
- // Mark the alternate protocol as broken and fallback.
- MarkBrokenAlternateProtocolAndFallback();
- return OK;
- }
-
- if (result < 0 && !ssl_started)
- return ReconsiderProxyAfterError(result);
- establishing_tunnel_ = false;
-
- if (connection_->socket()) {
- LogHttpConnectedMetrics(*connection_);
-
- // Set the reused_socket_ flag to indicate that we are using a keep-alive
- // connection. This flag is used to handle errors that occur while we are
- // trying to reuse a keep-alive connection.
- reused_socket_ = connection_->is_reused();
- // TODO(vandebo) should we exclude SPDY in the following if?
- if (!reused_socket_)
- UpdateConnectionTypeHistograms(CONNECTION_HTTP);
+int HttpNetworkTransaction::DoInitStreamComplete(int result) {
+ if (result == OK) {
+ next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- if (!using_ssl_) {
- DCHECK_EQ(OK, result);
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- return result;
- }
- }
+ if (is_https_request())
+ stream_->GetSSLInfo(&response_.ssl_info);
+ } else {
+ if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
+ result = HandleCertificateRequest(result);
- // Handle SSL errors below.
- DCHECK(using_ssl_);
- DCHECK(ssl_started);
- if (IsCertificateError(result)) {
- if (using_spdy_ && request_->url.SchemeIs("http")) {
- // We ignore certificate errors for http over spdy.
- spdy_certificate_error_ = result;
- result = OK;
- } else {
- result = HandleCertificateError(result);
- if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
- connection_->socket()->Disconnect();
- connection_->Reset();
- next_state_ = STATE_INIT_CONNECTION;
- return result;
- }
- }
- }
+ if (result < 0)
+ result = HandleIOError(result);
- if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
- response_.cert_request_info =
- connection_->ssl_error_response_info().cert_request_info;
- return HandleCertificateRequest(result);
+ // The stream initialization failed, so this stream will never be useful.
+ stream_.reset();
}
- if (result < 0)
- return HandleSSLHandshakeError(result);
- if (using_spdy_) {
- UpdateConnectionTypeHistograms(CONNECTION_SPDY);
- // TODO(cbentzel): Add auth support to spdy. See http://crbug.com/46620
- next_state_ = STATE_SPDY_GET_STREAM;
- } else {
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- }
- return OK;
+ return result;
}
int HttpNetworkTransaction::DoGenerateProxyAuthToken() {
next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
if (!ShouldApplyProxyAuth())
return OK;
- return auth_controllers_[HttpAuth::AUTH_PROXY]->MaybeGenerateAuthToken(
- request_, &io_callback_, net_log_);
+ HttpAuth::Target target = HttpAuth::AUTH_PROXY;
+ if (!auth_controllers_[target].get())
+ auth_controllers_[target] =
+ new HttpAuthController(target,
+ AuthURL(target),
+ session_->auth_cache(),
+ session_->http_auth_handler_factory());
+ return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
+ &io_callback_,
+ net_log_);
}
int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) {
@@ -965,10 +657,18 @@ int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) {
int HttpNetworkTransaction::DoGenerateServerAuthToken() {
next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE;
+ HttpAuth::Target target = HttpAuth::AUTH_SERVER;
+ if (!auth_controllers_[target].get())
+ auth_controllers_[target] =
+ new HttpAuthController(target,
+ AuthURL(target),
+ session_->auth_cache(),
+ session_->http_auth_handler_factory());
if (!ShouldApplyServerAuth())
return OK;
- return auth_controllers_[HttpAuth::AUTH_SERVER]->MaybeGenerateAuthToken(
- request_, &io_callback_, net_log_);
+ return auth_controllers_[target]->MaybeGenerateAuthToken(request_,
+ &io_callback_,
+ net_log_);
}
int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) {
@@ -991,7 +691,7 @@ int HttpNetworkTransaction::DoSendRequest() {
// This is constructed lazily (instead of within our Start method), so that
// we have proxy info available.
- if (request_headers_.empty()) {
+ if (request_headers_.empty() && !response_.was_fetched_via_spdy) {
// Figure out if we can/should add Proxy-Authentication & Authentication
// headers.
HttpRequestHeaders authorization_headers;
@@ -1007,27 +707,34 @@ int HttpNetworkTransaction::DoSendRequest() {
&authorization_headers);
std::string request_line;
HttpRequestHeaders request_headers;
+
BuildRequestHeaders(request_, authorization_headers, request_body,
- !using_ssl_ && proxy_info_.is_http(), &request_line,
- &request_headers);
+ !is_https_request() && (proxy_info_.is_http() ||
+ proxy_info_.is_https()),
+ &request_line, &request_headers);
if (session_->network_delegate())
session_->network_delegate()->OnSendHttpRequest(&request_headers);
- if (net_log_.HasListener()) {
+ if (net_log_.IsLoggingAll()) {
net_log_.AddEvent(
NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
new NetLogHttpRequestParameter(request_line, request_headers));
}
request_headers_ = request_line + request_headers.ToString();
+ } else {
+ if (net_log_.IsLoggingAll()) {
+ net_log_.AddEvent(
+ NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
+ new NetLogHttpRequestParameter(request_->url.spec(),
+ request_->extra_headers));
+ }
}
headers_valid_ = false;
- http_stream_.reset(new HttpBasicStream(connection_.get(), net_log_));
-
- return http_stream_->SendRequest(request_, request_headers_,
- request_body, &response_, &io_callback_);
+ return stream_->SendRequest(request_headers_, request_body, &response_,
+ &io_callback_);
}
int HttpNetworkTransaction::DoSendRequestComplete(int result) {
@@ -1039,11 +746,11 @@ int HttpNetworkTransaction::DoSendRequestComplete(int result) {
int HttpNetworkTransaction::DoReadHeaders() {
next_state_ = STATE_READ_HEADERS_COMPLETE;
- return http_stream_->ReadResponseHeaders(&io_callback_);
+ return stream_->ReadResponseHeaders(&io_callback_);
}
int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
- if (!response_.headers) {
+ if (!response_.headers && !stream_->IsConnectionReused()) {
// The connection was closed before any data was sent. Likely an error
// rather than empty HTTP/0.9 response.
return ERR_EMPTY_RESPONSE;
@@ -1055,40 +762,39 @@ int HttpNetworkTransaction::HandleConnectionClosedBeforeEndOfHeaders() {
int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
// We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here
// due to SSL renegotiation.
- if (using_ssl_) {
- if (IsCertificateError(result)) {
- // We don't handle a certificate error during SSL renegotiation, so we
- // have to return an error that's not in the certificate error range
- // (-2xx).
- LOG(ERROR) << "Got a server certificate with error " << result
- << " during SSL renegotiation";
- result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
- } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
- response_.cert_request_info = new SSLCertRequestInfo;
- SSLClientSocket* ssl_socket =
- static_cast<SSLClientSocket*>(connection_->socket());
- ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info);
- 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.
- g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
- ResetConnectionAndRequestForResend();
- return OK;
- }
+ if (IsCertificateError(result)) {
+ // We don't handle a certificate error during SSL renegotiation, so we
+ // have to return an error that's not in the certificate error range
+ // (-2xx).
+ LOG(ERROR) << "Got a server certificate with error " << result
+ << " during SSL renegotiation";
+ result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION;
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+ // TODO(wtc): Need a test case for this code path!
+ DCHECK(stream_.get());
+ DCHECK(is_https_request());
+ response_.cert_request_info = new SSLCertRequestInfo;
+ stream_->GetSSLCertRequestInfo(response_.cert_request_info);
+ 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)
@@ -1102,7 +808,8 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
// After we call RestartWithAuth a new response_time will be recorded, and
// we need to be cautious about incorrectly logging the duration across the
// authentication activity.
- LogTransactionConnectedMetrics();
+ if (result == OK)
+ LogTransactionConnectedMetrics();
if (result == ERR_CONNECTION_CLOSED) {
// For now, if we get at least some data, we do the best we can to make
@@ -1112,7 +819,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
return rv;
}
- if (net_log_.HasListener()) {
+ if (net_log_.IsLoggingAll()) {
net_log_.AddEvent(
NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
new NetLogHttpResponseParameter(response_.headers));
@@ -1137,20 +844,17 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
return OK;
}
- ProcessAlternateProtocol(*response_.headers,
- endpoint_,
- session_->mutable_alternate_protocols());
+ HostPortPair endpoint = HostPortPair(request_->url.HostNoBrackets(),
+ request_->url.EffectiveIntPort());
+ ProcessAlternateProtocol(session_->http_stream_factory(),
+ session_->mutable_alternate_protocols(),
+ *response_.headers,
+ endpoint);
int rv = HandleAuthChallenge();
if (rv != OK)
return rv;
- if (using_ssl_) {
- SSLClientSocket* ssl_socket =
- static_cast<SSLClientSocket*>(connection_->socket());
- ssl_socket->GetSSLInfo(&response_.ssl_info);
- }
-
headers_valid_ = true;
return OK;
}
@@ -1158,31 +862,43 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
int HttpNetworkTransaction::DoReadBody() {
DCHECK(read_buf_);
DCHECK_GT(read_buf_len_, 0);
- DCHECK(connection_->is_initialized());
+ DCHECK(stream_ != NULL);
next_state_ = STATE_READ_BODY_COMPLETE;
- return http_stream_->ReadResponseBody(read_buf_, read_buf_len_,
- &io_callback_);
+ return stream_->ReadResponseBody(read_buf_, read_buf_len_, &io_callback_);
}
int HttpNetworkTransaction::DoReadBodyComplete(int result) {
// We are done with the Read call.
- bool done = false, keep_alive = false;
- if (result <= 0)
+ bool done = false;
+ if (result <= 0) {
+ DCHECK_NE(ERR_IO_PENDING, result);
done = true;
+ }
- if (http_stream_->IsResponseBodyComplete()) {
- done = true;
- if (http_stream_->CanFindEndOfResponse())
+ bool keep_alive = false;
+ if (stream_->IsResponseBodyComplete()) {
+ // Note: Just because IsResponseBodyComplete is true, we're not
+ // necessarily "done". We're only "done" when it is the last
+ // read on this HttpNetworkTransaction, which will be signified
+ // by a zero-length read.
+ // TODO(mbelshe): The keepalive property is really a property of
+ // the stream. No need to compute it here just to pass back
+ // to the stream's Close function.
+ if (stream_->CanFindEndOfResponse())
keep_alive = GetResponseHeaders()->IsKeepAlive();
}
- // Clean up connection_->if we are done.
+ // Clean up connection if we are done.
if (done) {
LogTransactionMetrics();
- if (!keep_alive)
- connection_->socket()->Disconnect();
- connection_->Reset();
+ stream_->Close(!keep_alive);
+ // Note: we don't reset the stream here. We've closed it, but we still
+ // need it around so that callers can call methods such as
+ // GetUploadProgress() and have them be meaningful.
+ // TODO(mbelshe): This means we closed the stream here, and we close it
+ // again in ~HttpNetworkTransaction. Clean that up.
+
// The next Read call will return 0 (EOF).
}
@@ -1213,7 +929,7 @@ int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
// Error or closed connection while reading the socket.
done = true;
keep_alive = false;
- } else if (http_stream_->IsResponseBodyComplete()) {
+ } else if (stream_->IsResponseBodyComplete()) {
done = true;
}
@@ -1227,166 +943,6 @@ int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) {
return OK;
}
-int HttpNetworkTransaction::DoSpdyGetStream() {
- next_state_ = STATE_SPDY_GET_STREAM_COMPLETE;
- CHECK(!spdy_http_stream_.get());
-
- // First we get a SPDY session. Theoretically, we've just negotiated one, but
- // if one already exists, then screw it, use the existing one! Otherwise,
- // use the existing TCP socket.
-
- const scoped_refptr<SpdySessionPool> spdy_pool =
- session_->spdy_session_pool();
- scoped_refptr<SpdySession> spdy_session;
-
- if (spdy_pool->HasSession(endpoint_)) {
- spdy_session = spdy_pool->Get(endpoint_, session_, net_log_);
- } else {
- // SPDY is negotiated using the TLS next protocol negotiation (NPN)
- // extension, so |connection_| must contain an SSLClientSocket.
- DCHECK(using_ssl_);
- CHECK(connection_->socket());
- int error = spdy_pool->GetSpdySessionFromSSLSocket(
- endpoint_, session_, connection_.release(), net_log_,
- spdy_certificate_error_, &spdy_session);
- if (error != OK)
- return error;
- }
-
- CHECK(spdy_session.get());
- if(spdy_session->IsClosed())
- return ERR_CONNECTION_CLOSED;
-
- headers_valid_ = false;
-
- spdy_http_stream_.reset(new SpdyHttpStream());
- return spdy_http_stream_->InitializeStream(spdy_session, *request_,
- net_log_, &io_callback_);
-}
-
-int HttpNetworkTransaction::DoSpdyGetStreamComplete(int result) {
- if (result < 0)
- return result;
-
- next_state_ = STATE_SPDY_SEND_REQUEST;
- return OK;
-}
-
-int HttpNetworkTransaction::DoSpdySendRequest() {
- next_state_ = STATE_SPDY_SEND_REQUEST_COMPLETE;
-
- UploadDataStream* upload_data_stream = NULL;
- if (request_->upload_data) {
- int error_code = OK;
- upload_data_stream = UploadDataStream::Create(request_->upload_data,
- &error_code);
- if (!upload_data_stream)
- return error_code;
- }
- spdy_http_stream_->InitializeRequest(base::Time::Now(), upload_data_stream);
-
- return spdy_http_stream_->SendRequest(&response_, &io_callback_);
-}
-
-int HttpNetworkTransaction::DoSpdySendRequestComplete(int result) {
- if (result < 0)
- return result;
-
- next_state_ = STATE_SPDY_READ_HEADERS;
- return OK;
-}
-
-int HttpNetworkTransaction::DoSpdyReadHeaders() {
- next_state_ = STATE_SPDY_READ_HEADERS_COMPLETE;
- return spdy_http_stream_->ReadResponseHeaders(&io_callback_);
-}
-
-int HttpNetworkTransaction::DoSpdyReadHeadersComplete(int result) {
- // TODO(willchan): Flesh out the support for HTTP authentication here.
- if (result == OK)
- headers_valid_ = true;
-
- LogTransactionConnectedMetrics();
-
- return result;
-}
-
-int HttpNetworkTransaction::DoSpdyReadBody() {
- next_state_ = STATE_SPDY_READ_BODY_COMPLETE;
-
- return spdy_http_stream_->ReadResponseBody(
- read_buf_, read_buf_len_, &io_callback_);
-}
-
-int HttpNetworkTransaction::DoSpdyReadBodyComplete(int result) {
- read_buf_ = NULL;
- read_buf_len_ = 0;
-
- if (result <= 0)
- spdy_http_stream_.reset();
-
- return result;
-}
-
-void HttpNetworkTransaction::LogHttpConnectedMetrics(
- const ClientSocketHandle& handle) {
- UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
- ClientSocketHandle::NUM_TYPES);
-
- switch (handle.reuse_type()) {
- case ClientSocketHandle::UNUSED:
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
- handle.setup_time(),
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10),
- 100);
- break;
- case ClientSocketHandle::UNUSED_IDLE:
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
- handle.idle_time(),
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(6),
- 100);
- break;
- case ClientSocketHandle::REUSED_IDLE:
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
- handle.idle_time(),
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(6),
- 100);
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-void HttpNetworkTransaction::LogIOErrorMetrics(
- const ClientSocketHandle& handle) {
- UMA_HISTOGRAM_ENUMERATION("Net.IOError_SocketReuseType",
- handle.reuse_type(), ClientSocketHandle::NUM_TYPES);
-
- switch (handle.reuse_type()) {
- case ClientSocketHandle::UNUSED:
- break;
- case ClientSocketHandle::UNUSED_IDLE:
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.SocketIdleTimeOnIOError2_UnusedSocket",
- handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(6), 100);
- break;
- case ClientSocketHandle::REUSED_IDLE:
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.SocketIdleTimeOnIOError2_ReusedSocket",
- handle.idle_time(), base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(6), 100);
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
if (logged_response_time_)
return;
@@ -1401,7 +957,8 @@ void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
100);
- if (!reused_socket_) {
+ bool reused_socket = stream_->IsConnectionReused();
+ if (!reused_socket) {
UMA_HISTOGRAM_CLIPPED_TIMES(
"Net.Transaction_Connected_New",
total_duration,
@@ -1429,7 +986,7 @@ void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
total_duration, base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMinutes(10), 100);
- if (!reused_socket_) {
+ if (!reused_socket) {
UMA_HISTOGRAM_CLIPPED_TIMES(
FieldTrial::MakeName("Net.Transaction_Connected_New", "SpdyImpact"),
total_duration, base::TimeDelta::FromMilliseconds(1),
@@ -1472,7 +1029,7 @@ void HttpNetworkTransaction::LogTransactionMetrics() const {
total_duration,
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMinutes(10), 100);
- if (!reused_socket_) {
+ if (!stream_->IsConnectionReused()) {
UMA_HISTOGRAM_CLIPPED_TIMES(
"Net.Transaction_Latency_Total_New_Connection_Under_10",
total_duration, base::TimeDelta::FromMilliseconds(1),
@@ -1480,37 +1037,33 @@ void HttpNetworkTransaction::LogTransactionMetrics() const {
}
}
-int HttpNetworkTransaction::HandleCertificateError(int error) {
- DCHECK(using_ssl_);
- DCHECK(IsCertificateError(error));
-
- SSLClientSocket* ssl_socket =
- static_cast<SSLClientSocket*>(connection_->socket());
- ssl_socket->GetSSLInfo(&response_.ssl_info);
-
- // Add the bad certificate to the set of allowed certificates in the
- // SSL info object. This data structure will be consulted after calling
- // RestartIgnoringLastError(). And the user will be asked interactively
- // before RestartIgnoringLastError() is ever called.
- SSLConfig::CertAndStatus bad_cert;
- bad_cert.cert = response_.ssl_info.cert;
- bad_cert.cert_status = response_.ssl_info.cert_status;
- ssl_config_.allowed_bad_certs.push_back(bad_cert);
-
- int load_flags = request_->load_flags;
- if (g_ignore_certificate_errors)
- load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
- if (ssl_socket->IgnoreCertError(error, load_flags))
- return OK;
- return error;
-}
-
int HttpNetworkTransaction::HandleCertificateRequest(int error) {
- // Close the connection while the user is selecting a certificate to send
- // to the server.
- if (connection_->socket())
- connection_->socket()->Disconnect();
- connection_->Reset();
+ // There are two paths through which the server can request a certificate
+ // from us. The first is during the initial handshake, the second is
+ // during SSL renegotiation.
+ //
+ // In both cases, we want to close the connection before proceeding.
+ // We do this for two reasons:
+ // First, we don't want to keep the connection to the server hung for a
+ // long time while the user selects a certificate.
+ // Second, even if we did keep the connection open, NSS has a bug where
+ // restarting the handshake for ClientAuth is currently broken.
+ DCHECK_EQ(error, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+
+ if (stream_.get()) {
+ // Since we already have a stream, we're being called as part of SSL
+ // renegotiation.
+ DCHECK(!stream_request_.get());
+ stream_->Close(true);
+ stream_.reset();
+ }
+
+ if (stream_request_.get()) {
+ // The server is asking for a client certificate during the initial
+ // handshake.
+ stream_request_->Cancel();
+ stream_request_ = NULL;
+ }
// If the user selected one of the certificate in client_certs for this
// server before, use it automatically.
@@ -1521,9 +1074,12 @@ int HttpNetworkTransaction::HandleCertificateRequest(int error) {
response_.cert_request_info->client_certs;
for (size_t i = 0; i < client_certs.size(); ++i) {
if (client_cert->fingerprint().Equals(client_certs[i]->fingerprint())) {
+ // TODO(davidben): Add a unit test which covers this path; we need to be
+ // able to send a legitimate certificate and also bypass/clear the
+ // SSL session cache.
ssl_config_.client_cert = client_cert;
ssl_config_.send_client_cert = true;
- next_state_ = STATE_INIT_CONNECTION;
+ next_state_ = STATE_CREATE_STREAM;
// Reset the other member variables.
// Note: this is necessary only with SSL renegotiation.
ResetStateForRestart();
@@ -1534,32 +1090,6 @@ int HttpNetworkTransaction::HandleCertificateRequest(int error) {
return error;
}
-int HttpNetworkTransaction::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_->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.
- g_tls_intolerant_servers->insert(GetHostAndPort(request_->url));
- 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
@@ -1573,7 +1103,6 @@ int HttpNetworkTransaction::HandleIOError(int error) {
case ERR_CONNECTION_RESET:
case ERR_CONNECTION_CLOSED:
case ERR_CONNECTION_ABORTED:
- LogIOErrorMetrics(*connection_);
if (ShouldResendRequest(error)) {
ResetConnectionAndRequestForResend();
error = OK;
@@ -1587,10 +1116,11 @@ void HttpNetworkTransaction::ResetStateForRestart() {
pending_auth_target_ = HttpAuth::AUTH_NONE;
read_buf_ = NULL;
read_buf_len_ = 0;
- http_stream_.reset();
+ stream_.reset();
headers_valid_ = false;
request_headers_.clear();
response_ = HttpResponseInfo();
+ establishing_tunnel_ = false;
}
HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
@@ -1598,25 +1128,28 @@ HttpResponseHeaders* HttpNetworkTransaction::GetResponseHeaders() const {
}
bool HttpNetworkTransaction::ShouldResendRequest(int error) const {
+ bool connection_is_proven = stream_->IsConnectionReused();
+ bool has_received_headers = GetResponseHeaders() != NULL;
+
// NOTE: we resend a request only if we reused a keep-alive connection.
// This automatically prevents an infinite resend loop because we'll run
// out of the cached keep-alive connections eventually.
- if (!connection_->ShouldResendFailedRequest(error) ||
- GetResponseHeaders()) { // We have received some response headers.
- return false;
- }
- return true;
+ if (connection_is_proven && !has_received_headers)
+ return true;
+ return false;
}
void HttpNetworkTransaction::ResetConnectionAndRequestForResend() {
- if (connection_->socket())
- connection_->socket()->Disconnect();
- connection_->Reset();
+ if (stream_.get()) {
+ stream_->Close(true);
+ stream_.reset();
+ }
+
// We need to clear request_headers_ because it contains the real request
// headers, but we may need to resend the CONNECT request first to recreate
// the SSL tunnel.
-
request_headers_.clear();
+<<<<<<< HEAD
next_state_ = STATE_INIT_CONNECTION; // Resend the request.
}
@@ -1683,10 +1216,14 @@ int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) {
}
return rv;
+=======
+ next_state_ = STATE_CREATE_STREAM; // Resend the request.
+>>>>>>> Chromium at release 7.0.540.0
}
bool HttpNetworkTransaction::ShouldApplyProxyAuth() const {
- return !using_ssl_ && proxy_info_.is_http();
+ return !is_https_request() &&
+ (proxy_info_.is_https() || proxy_info_.is_http());
}
bool HttpNetworkTransaction::ShouldApplyServerAuth() const {
@@ -1719,14 +1256,23 @@ int HttpNetworkTransaction::HandleAuthChallenge() {
return rv;
}
+bool HttpNetworkTransaction::HaveAuth(HttpAuth::Target target) const {
+ return auth_controllers_[target].get() &&
+ auth_controllers_[target]->HaveAuth();
+}
+
+
GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
switch (target) {
- case HttpAuth::AUTH_PROXY:
+ case HttpAuth::AUTH_PROXY: {
if (!proxy_info_.proxy_server().is_valid() ||
proxy_info_.proxy_server().is_direct()) {
return GURL(); // There is no proxy server.
}
- return GURL("http://" + proxy_info_.proxy_server().host_and_port());
+ const char* scheme = proxy_info_.is_https() ? "https://" : "http://";
+ return GURL(scheme +
+ proxy_info_.proxy_server().host_port_pair().ToString());
+ }
case HttpAuth::AUTH_SERVER:
return request_->url;
default:
@@ -1734,42 +1280,16 @@ GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const {
}
}
-void HttpNetworkTransaction::MarkBrokenAlternateProtocolAndFallback() {
- // We have to:
- // * Reset the endpoint to be the unmodified URL specified destination.
- // * Mark the endpoint as broken so we don't try again.
- // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we
- // ignore future Alternate-Protocol headers from the HostPortPair.
- // * Reset the connection and go back to STATE_INIT_CONNECTION.
-
- endpoint_ = HostPortPair(request_->url.HostNoBrackets(),
- request_->url.EffectiveIntPort());
-
- session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
- endpoint_);
-
- alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
- if (connection_->socket())
- connection_->socket()->Disconnect();
- connection_->Reset();
- next_state_ = STATE_INIT_CONNECTION;
-}
-
-#define STATE_CASE(s) case s: \
- description = StringPrintf("%s (0x%08X)", #s, s); \
- break
+#define STATE_CASE(s) \
+ case s: \
+ description = base::StringPrintf("%s (0x%08X)", #s, s); \
+ break
std::string HttpNetworkTransaction::DescribeState(State state) {
std::string description;
switch (state) {
- STATE_CASE(STATE_RESOLVE_PROXY);
- STATE_CASE(STATE_RESOLVE_PROXY_COMPLETE);
- STATE_CASE(STATE_INIT_CONNECTION);
- STATE_CASE(STATE_INIT_CONNECTION_COMPLETE);
- STATE_CASE(STATE_GENERATE_PROXY_AUTH_TOKEN);
- STATE_CASE(STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE);
- STATE_CASE(STATE_GENERATE_SERVER_AUTH_TOKEN);
- STATE_CASE(STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE);
+ STATE_CASE(STATE_CREATE_STREAM);
+ STATE_CASE(STATE_CREATE_STREAM_COMPLETE);
STATE_CASE(STATE_SEND_REQUEST);
STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
STATE_CASE(STATE_READ_HEADERS);
@@ -1778,22 +1298,31 @@ std::string HttpNetworkTransaction::DescribeState(State state) {
STATE_CASE(STATE_READ_BODY_COMPLETE);
STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART);
STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE);
- STATE_CASE(STATE_SPDY_GET_STREAM);
- STATE_CASE(STATE_SPDY_GET_STREAM_COMPLETE);
- STATE_CASE(STATE_SPDY_SEND_REQUEST);
- STATE_CASE(STATE_SPDY_SEND_REQUEST_COMPLETE);
- STATE_CASE(STATE_SPDY_READ_HEADERS);
- STATE_CASE(STATE_SPDY_READ_HEADERS_COMPLETE);
- STATE_CASE(STATE_SPDY_READ_BODY);
- STATE_CASE(STATE_SPDY_READ_BODY_COMPLETE);
STATE_CASE(STATE_NONE);
default:
- description = StringPrintf("Unknown state 0x%08X (%u)", state, state);
+ description = base::StringPrintf("Unknown state 0x%08X (%u)", state,
+ state);
break;
}
return description;
}
+// TODO(gavinp): re-adjust this once SPDY v3 has three priority bits,
+// eliminating the need for this folding.
+int ConvertRequestPriorityToSpdyPriority(const RequestPriority priority) {
+ DCHECK(HIGHEST <= priority && priority < NUM_PRIORITIES);
+ switch (priority) {
+ case LOWEST:
+ return SPDY_PRIORITY_LOWEST-1;
+ case IDLE:
+ return SPDY_PRIORITY_LOWEST;
+ default:
+ return priority;
+ }
+}
+
+
+
#undef STATE_CASE
} // namespace net
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 7c32bd3..f0080e2 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -4,56 +4,40 @@
#ifndef NET_HTTP_HTTP_NETWORK_TRANSACTION_H_
#define NET_HTTP_HTTP_NETWORK_TRANSACTION_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
-#include "net/base/address_list.h"
-#include "net/base/io_buffer.h"
-#include "net/base/load_flags.h"
-#include "net/base/load_states.h"
#include "net/base/net_log.h"
+#include "net/base/request_priority.h"
#include "net/base/ssl_config_service.h"
-#include "net/http/http_alternate_protocols.h"
#include "net/http/http_auth.h"
-#include "net/http/http_auth_controller.h"
-#include "net/http/http_auth_handler.h"
#include "net/http/http_response_info.h"
#include "net/http/http_transaction.h"
+#include "net/http/stream_factory.h"
#include "net/proxy/proxy_service.h"
-#include "net/socket/client_socket_pool.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
namespace net {
-class ClientSocketFactory;
-class ClientSocketHandle;
+class HttpAuthController;
class HttpNetworkSession;
-class HttpRequestHeaders;
class HttpStream;
-class SpdyHttpStream;
+class HttpStreamRequest;
+class IOBuffer;
+struct HttpRequestInfo;
-class HttpNetworkTransaction : public HttpTransaction {
+class HttpNetworkTransaction : public HttpTransaction,
+ public StreamFactory::StreamRequestDelegate {
public:
explicit HttpNetworkTransaction(HttpNetworkSession* session);
virtual ~HttpNetworkTransaction();
- static void SetHostMappingRules(const std::string& rules);
-
- // Controls whether or not we use the Alternate-Protocol header.
- static void SetUseAlternateProtocols(bool value);
-
- // Sets the next protocol negotiation value used during the SSL handshake.
- static void SetNextProtos(const std::string& next_protos);
-
- // Sets the HttpNetworkTransaction into a mode where it can ignore
- // certificate errors. This is for testing.
- static void IgnoreCertificateErrors(bool enabled);
-
// HttpTransaction methods:
virtual int Start(const HttpRequestInfo* request_info,
CompletionCallback* callback,
@@ -61,13 +45,10 @@ class HttpNetworkTransaction : public HttpTransaction {
virtual int RestartIgnoringLastError(CompletionCallback* callback);
virtual int RestartWithCertificate(X509Certificate* client_cert,
CompletionCallback* callback);
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
+ virtual int RestartWithAuth(const string16& username,
+ const string16& password,
CompletionCallback* callback);
- virtual bool IsReadyToRestartForAuth() {
- return pending_auth_target_ != HttpAuth::AUTH_NONE &&
- HaveAuth(pending_auth_target_);
- }
+ virtual bool IsReadyToRestartForAuth();
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
virtual void StopCaching() {}
@@ -75,14 +56,27 @@ class HttpNetworkTransaction : public HttpTransaction {
virtual LoadState GetLoadState() const;
virtual uint64 GetUploadProgress() const;
+ // StreamRequestDelegate methods:
+ virtual void OnStreamReady(HttpStream* stream);
+ virtual void OnStreamFailed(int status);
+ virtual void OnCertificateError(int status, const SSLInfo& ssl_info);
+ virtual void OnNeedsProxyAuth(
+ const HttpResponseInfo& response_info,
+ HttpAuthController* auth_controller);
+ virtual void OnNeedsClientAuth(SSLCertRequestInfo* cert_info);
+
private:
- FRIEND_TEST(HttpNetworkTransactionTest, ResetStateForRestart);
+ FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest, ResetStateForRestart);
+ FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, WindowUpdateReceived);
+ FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, WindowUpdateSent);
+ FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, WindowUpdateOverflow);
+ FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, FlowControlStallResume);
enum State {
- STATE_RESOLVE_PROXY,
- STATE_RESOLVE_PROXY_COMPLETE,
- STATE_INIT_CONNECTION,
- STATE_INIT_CONNECTION_COMPLETE,
+ STATE_CREATE_STREAM,
+ STATE_CREATE_STREAM_COMPLETE,
+ STATE_INIT_STREAM,
+ STATE_INIT_STREAM_COMPLETE,
STATE_GENERATE_PROXY_AUTH_TOKEN,
STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE,
STATE_GENERATE_SERVER_AUTH_TOKEN,
@@ -95,22 +89,10 @@ class HttpNetworkTransaction : public HttpTransaction {
STATE_READ_BODY_COMPLETE,
STATE_DRAIN_BODY_FOR_AUTH_RESTART,
STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE,
- STATE_SPDY_GET_STREAM,
- STATE_SPDY_GET_STREAM_COMPLETE,
- STATE_SPDY_SEND_REQUEST,
- STATE_SPDY_SEND_REQUEST_COMPLETE,
- STATE_SPDY_READ_HEADERS,
- STATE_SPDY_READ_HEADERS_COMPLETE,
- STATE_SPDY_READ_BODY,
- STATE_SPDY_READ_BODY_COMPLETE,
STATE_NONE
};
- enum AlternateProtocolMode {
- kUnspecified, // Unspecified, check HttpAlternateProtocols
- kUsingAlternateProtocol, // Using an alternate protocol
- kDoNotUseAlternateProtocol, // Failed to connect once, do not try again.
- };
+ bool is_https_request() const;
void DoCallback(int result);
void OnIOComplete(int result);
@@ -122,10 +104,10 @@ class HttpNetworkTransaction : public HttpTransaction {
// argument receive the result from the previous state. If a method returns
// ERR_IO_PENDING, then the result from OnIOComplete will be passed to the
// next state method as the result arg.
- int DoResolveProxy();
- int DoResolveProxyComplete(int result);
- int DoInitConnection();
- int DoInitConnectionComplete(int result);
+ int DoCreateStream();
+ int DoCreateStreamComplete(int result);
+ int DoInitStream();
+ int DoInitStreamComplete(int result);
int DoGenerateProxyAuthToken();
int DoGenerateProxyAuthTokenComplete(int result);
int DoGenerateServerAuthToken();
@@ -138,17 +120,6 @@ class HttpNetworkTransaction : public HttpTransaction {
int DoReadBodyComplete(int result);
int DoDrainBodyForAuthRestart();
int DoDrainBodyForAuthRestartComplete(int result);
- int DoSpdyGetStream();
- int DoSpdyGetStreamComplete(int result);
- int DoSpdySendRequest();
- int DoSpdySendRequestComplete(int result);
- int DoSpdyReadHeaders();
- int DoSpdyReadHeadersComplete(int result);
- int DoSpdyReadBody();
- int DoSpdyReadBodyComplete(int result);
-
- // Record histograms of latency until Connect() completes.
- static void LogHttpConnectedMetrics(const ClientSocketHandle& handle);
// Record histogram of time until first byte of header is received.
void LogTransactionConnectedMetrics();
@@ -160,21 +131,9 @@ class HttpNetworkTransaction : public HttpTransaction {
// response to a CONNECT request.
void LogBlockedTunnelResponse(int response_code) const;
- static void LogIOErrorMetrics(const ClientSocketHandle& handle);
-
- // Called to handle a certificate error. Returns OK if the error should be
- // ignored. Otherwise, stores the certificate in response_.ssl_info and
- // returns the same error code.
- int HandleCertificateError(int error);
-
// 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.
@@ -191,14 +150,6 @@ class HttpNetworkTransaction : public HttpTransaction {
// ShouldResendRequest() is true.
void ResetConnectionAndRequestForResend();
- // Called when we encounter a network error that could be resolved by trying
- // a new proxy configuration. If there is another proxy configuration to try
- // then this method sets next_state_ appropriately and returns either OK or
- // ERR_IO_PENDING depending on whether or not the new proxy configuration is
- // available synchronously or asynchronously. Otherwise, the given error
- // code is simply returned.
- int ReconsiderProxyAfterError(int error);
-
// Decides the policy when the connection is closed before the end of headers
// has been read. This only applies to reading responses, and not writing
// requests.
@@ -226,21 +177,15 @@ class HttpNetworkTransaction : public HttpTransaction {
// May update |pending_auth_target_| or |response_.auth_challenge|.
int HandleAuthChallenge();
- bool HaveAuth(HttpAuth::Target target) const {
- return auth_controllers_[target].get() &&
- auth_controllers_[target]->HaveAuth();
- }
+ // Returns true if we have auth credentials for the given target.
+ bool HaveAuth(HttpAuth::Target target) const;
// Get the {scheme, host, path, port} for the authentication target
GURL AuthURL(HttpAuth::Target target) const;
- void MarkBrokenAlternateProtocolAndFallback();
-
// Debug helper.
static std::string DescribeState(State state);
- static bool g_ignore_certificate_errors;
-
scoped_refptr<HttpAuthController>
auth_controllers_[HttpAuth::AUTH_NUM_TARGETS];
@@ -258,13 +203,10 @@ class HttpNetworkTransaction : public HttpTransaction {
const HttpRequestInfo* request_;
HttpResponseInfo response_;
- ProxyService::PacRequest* pac_request_;
ProxyInfo proxy_info_;
- scoped_ptr<ClientSocketHandle> connection_;
- scoped_ptr<HttpStream> http_stream_;
- scoped_ptr<SpdyHttpStream> spdy_http_stream_;
- bool reused_socket_;
+ scoped_refptr<StreamFactory::StreamRequestJob> stream_request_;
+ scoped_ptr<HttpStream> stream_;
// True if we've validated the headers that the stream parser has returned.
bool headers_valid_;
@@ -274,19 +216,6 @@ class HttpNetworkTransaction : public HttpTransaction {
// responses.
bool logged_response_time_;
- bool using_ssl_; // True if handling a HTTPS request
-
- // True if this network transaction is using SPDY instead of HTTP.
- bool using_spdy_;
-
- // The certificate error while using SPDY over SSL for insecure URLs.
- int spdy_certificate_error_;
-
- AlternateProtocolMode alternate_protocol_mode_;
-
- // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol.
- HttpAlternateProtocols::Protocol alternate_protocol_;
-
SSLConfig ssl_config_;
std::string request_headers_;
@@ -294,7 +223,7 @@ class HttpNetworkTransaction : public HttpTransaction {
// The size in bytes of the buffer we use to drain the response body that
// we want to throw away. The response body is typically a small error
// page just a few hundred bytes long.
- enum { kDrainBodyBufferSize = 1024 };
+ static const int kDrainBodyBufferSize = 1024;
// User buffer and length passed to the Read method.
scoped_refptr<IOBuffer> read_buf_;
@@ -306,10 +235,6 @@ class HttpNetworkTransaction : public HttpTransaction {
// The next state in the state machine.
State next_state_;
- // 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.
- HostPortPair endpoint_;
-
// True when the tunnel is in the process of being established - we can't
// read from the socket until the tunnel is done.
bool establishing_tunnel_;
@@ -317,6 +242,8 @@ class HttpNetworkTransaction : public HttpTransaction {
DISALLOW_COPY_AND_ASSIGN(HttpNetworkTransaction);
};
+int ConvertRequestPriorityToSpdyPriority(RequestPriority priority);
+
} // namespace net
#endif // NET_HTTP_HTTP_NETWORK_TRANSACTION_H_
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 03e4b31..68e4038 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -12,6 +12,8 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/auth.h"
#include "net/base/capturing_net_log.h"
#include "net/base/completion_callback.h"
#include "net/base/mock_host_resolver.h"
@@ -28,6 +30,7 @@
#include "net/http/http_basic_stream.h"
#include "net/http/http_network_session.h"
#include "net/http/http_stream.h"
+#include "net/http/http_stream_factory.h"
#include "net/http/http_transaction_unittest.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_resolver.h"
@@ -44,6 +47,23 @@
//-----------------------------------------------------------------------------
+namespace {
+
+const string16 kBar(ASCIIToUTF16("bar"));
+const string16 kBar2(ASCIIToUTF16("bar2"));
+const string16 kBar3(ASCIIToUTF16("bar3"));
+const string16 kBaz(ASCIIToUTF16("baz"));
+const string16 kFirst(ASCIIToUTF16("first"));
+const string16 kFoo(ASCIIToUTF16("foo"));
+const string16 kFoo2(ASCIIToUTF16("foo2"));
+const string16 kFoo3(ASCIIToUTF16("foo3"));
+const string16 kFou(ASCIIToUTF16("fou"));
+const string16 kSecond(ASCIIToUTF16("second"));
+const string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm"));
+const string16 kWrongPassword(ASCIIToUTF16("wrongpassword"));
+
+} // namespace
+
namespace net {
class HttpNetworkSessionPeer {
@@ -52,30 +72,48 @@ class HttpNetworkSessionPeer {
const scoped_refptr<HttpNetworkSession>& session)
: session_(session) {}
- void SetTCPSocketPool(const scoped_refptr<TCPClientSocketPool>& pool) {
- session_->tcp_socket_pool_ = pool;
+ void SetTCPSocketPool(TCPClientSocketPool* pool) {
+ session_->socket_pool_manager_.tcp_socket_pool_.reset(pool);
}
void SetSocketPoolForSOCKSProxy(
const HostPortPair& socks_proxy,
- const scoped_refptr<SOCKSClientSocketPool>& pool) {
- session_->socks_socket_pools_[socks_proxy] = pool;
+ SOCKSClientSocketPool* pool) {
+ ClientSocketPoolManager* socket_pool_manager =
+ &session_->socket_pool_manager_;
+
+ // Call through the public interface to force initialization of the
+ // wrapped socket pools.
+ delete socket_pool_manager->GetSocketPoolForSOCKSProxy(socks_proxy);
+ socket_pool_manager->socks_socket_pools_[socks_proxy] = pool;
}
void SetSocketPoolForHTTPProxy(
const HostPortPair& http_proxy,
- const scoped_refptr<HttpProxyClientSocketPool>& pool) {
- session_->http_proxy_socket_pools_[http_proxy] = pool;
+ HttpProxyClientSocketPool* pool) {
+ ClientSocketPoolManager* socket_pool_manager =
+ &session_->socket_pool_manager_;
+
+ // Call through the public interface to force initialization of the
+ // wrapped socket pools.
+ delete socket_pool_manager->GetSocketPoolForHTTPProxy(http_proxy);
+ socket_pool_manager->http_proxy_socket_pools_[http_proxy] = pool;
}
- void SetSSLSocketPool(const scoped_refptr<SSLClientSocketPool>& pool) {
- session_->ssl_socket_pool_ = pool;
+ void SetSSLSocketPool(SSLClientSocketPool* pool) {
+ session_->socket_pool_manager_.ssl_socket_pool_.reset(pool);
}
void SetSocketPoolForSSLWithProxy(
const HostPortPair& proxy_host,
- const scoped_refptr<SSLClientSocketPool>& pool) {
- session_->ssl_socket_pools_for_proxies_[proxy_host] = pool;
+ SSLClientSocketPool* pool) {
+ ClientSocketPoolManager* socket_pool_manager =
+ &session_->socket_pool_manager_;
+
+ // Call through the public interface to force initialization of the
+ // wrapped socket pools.
+ delete socket_pool_manager->GetSocketPoolForSSLWithProxy(proxy_host);
+ socket_pool_manager->ssl_socket_pools_for_proxies_[proxy_host] = pool;
}
private:
@@ -90,10 +128,11 @@ struct SessionDependencies {
// Default set of dependencies -- "null" proxy service.
SessionDependencies()
: host_resolver(new MockHostResolver),
- proxy_service(ProxyService::CreateNull()),
+ proxy_service(ProxyService::CreateDirect()),
ssl_config_service(new SSLConfigServiceDefaults),
- http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()),
- spdy_session_pool(new SpdySessionPool()),
+ http_auth_handler_factory(
+ HttpAuthHandlerFactory::CreateDefault(host_resolver)),
+ spdy_session_pool(new SpdySessionPool(NULL)),
net_log(NULL) {}
// Custom proxy service dependency.
@@ -101,8 +140,9 @@ struct SessionDependencies {
: host_resolver(new MockHostResolver),
proxy_service(proxy_service),
ssl_config_service(new SSLConfigServiceDefaults),
- http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()),
- spdy_session_pool(new SpdySessionPool()),
+ http_auth_handler_factory(
+ HttpAuthHandlerFactory::CreateDefault(host_resolver)),
+ spdy_session_pool(new SpdySessionPool(NULL)),
net_log(NULL) {}
scoped_refptr<MockHostResolverBase> host_resolver;
@@ -134,14 +174,20 @@ HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
class HttpNetworkTransactionTest : public PlatformTest {
public:
virtual void SetUp() {
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ MessageLoop::current()->RunAllPending();
spdy::SpdyFramer::set_enable_compression_default(false);
}
virtual void TearDown() {
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ MessageLoop::current()->RunAllPending();
spdy::SpdyFramer::set_enable_compression_default(true);
// Empty the current queue.
MessageLoop::current()->RunAllPending();
PlatformTest::TearDown();
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ MessageLoop::current()->RunAllPending();
}
protected:
@@ -307,13 +353,27 @@ CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool(
: ParentPool(0, 0, NULL, session->host_resolver(), NULL, NULL) {}
template<>
+CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool(
+ HttpNetworkSession* session)
+ : HttpProxyClientSocketPool(0, 0, NULL, session->host_resolver(), NULL,
+ NULL, NULL) {}
+
+template<>
CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
HttpNetworkSession* session)
: SSLClientSocketPool(0, 0, NULL, session->host_resolver(), NULL, NULL,
- NULL, NULL, NULL) {}
+ NULL, NULL, NULL, NULL) {}
//-----------------------------------------------------------------------------
+// This is the expected list of advertised protocols from the browser's NPN
+// list.
+static const char kExpectedNPNString[] = "\x08http/1.1\x06spdy/2";
+
+// This is the expected return from a current server advertising SPDY.
+static const char kAlternateProtocolHttpHeader[] =
+ "Alternate-Protocol: 443:npn-spdy/2\r\n\r\n";
+
TEST_F(HttpNetworkTransactionTest, Basic) {
SessionDependencies session_deps;
scoped_ptr<HttpTransaction> trans(
@@ -450,6 +510,41 @@ TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) {
EXPECT_EQ("Hello world", out.response_data);
}
+// Next tests deal with http://crbug.com/56344.
+
+TEST_F(HttpNetworkTransactionTest,
+ MultipleContentLengthHeadersNoTransferEncoding) {
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Length: 10\r\n"),
+ MockRead("Content-Length: 5\r\n\r\n"),
+ };
+ SimpleGetHelperResult out = SimpleGetHelper(data_reads,
+ arraysize(data_reads));
+ EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv);
+}
+
+TEST_F(HttpNetworkTransactionTest,
+ MultipleContentLengthHeadersTransferEncoding) {
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Length: 666\r\n"),
+ MockRead("Content-Length: 1337\r\n"),
+ MockRead("Transfer-Encoding: chunked\r\n\r\n"),
+ MockRead("5\r\nHello\r\n"),
+ MockRead("1\r\n"),
+ MockRead(" \r\n"),
+ MockRead("5\r\nworld\r\n"),
+ MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"),
+ MockRead(false, OK),
+ };
+ SimpleGetHelperResult out = SimpleGetHelper(data_reads,
+ arraysize(data_reads));
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("Hello world", out.response_data);
+}
+
// Do a request using the HEAD method. Verify that we don't try to read the
// message body (since HEAD has none).
TEST_F(HttpNetworkTransactionTest, Head) {
@@ -526,7 +621,7 @@ TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
session_deps.socket_factory.AddSocketDataProvider(&data);
- const char* kExpectedResponseData[] = {
+ const char* const kExpectedResponseData[] = {
"hello", "world"
};
@@ -816,8 +911,9 @@ TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv);
}
-// Test that we correctly reuse a keep-alive connection after receiving a 304.
-TEST_F(HttpNetworkTransactionTest, KeepAliveAfter304) {
+// Test that we correctly reuse a keep-alive connection after not explicitly
+// reading the body.
+TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
SessionDependencies session_deps;
scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
@@ -826,8 +922,23 @@ TEST_F(HttpNetworkTransactionTest, KeepAliveAfter304) {
request.url = GURL("http://www.foo.com/");
request.load_flags = 0;
+ // Note that because all these reads happen in the same
+ // StaticSocketDataProvider, it shows that the same socket is being reused for
+ // all transactions.
MockRead data1_reads[] = {
+ MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
+ MockRead("HTTP/1.1 205 Reset Content\r\n\r\n"),
MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"),
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Content-Length: 0\r\n\r\n"),
+ MockRead("HTTP/1.1 302 Found\r\n"
+ "Content-Length: 5\r\n\r\n"
+ "hello"),
+ MockRead("HTTP/1.1 301 Moved Permanently\r\n"
+ "Content-Length: 0\r\n\r\n"),
+ MockRead("HTTP/1.1 301 Moved Permanently\r\n"
+ "Content-Length: 5\r\n\r\n"
+ "hello"),
MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
MockRead("hello"),
};
@@ -840,7 +951,10 @@ TEST_F(HttpNetworkTransactionTest, KeepAliveAfter304) {
StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0);
session_deps.socket_factory.AddSocketDataProvider(&data2);
- for (int i = 0; i < 2; ++i) {
+ const int kNumUnreadBodies = arraysize(data1_reads) - 2;
+ std::string response_lines[kNumUnreadBodies];
+
+ for (size_t i = 0; i < arraysize(data1_reads) - 2; ++i) {
TestCompletionCallback callback;
scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
@@ -852,22 +966,44 @@ TEST_F(HttpNetworkTransactionTest, KeepAliveAfter304) {
EXPECT_EQ(OK, rv);
const HttpResponseInfo* response = trans->GetResponseInfo();
- EXPECT_TRUE(response != NULL);
+ ASSERT_TRUE(response != NULL);
- EXPECT_TRUE(response->headers != NULL);
- if (i == 0) {
- EXPECT_EQ("HTTP/1.1 304 Not Modified",
- response->headers->GetStatusLine());
- // We intentionally don't read the response in this case, to reflect how
- // HttpCache::Transaction uses HttpNetworkTransaction.
- } else {
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
- EXPECT_EQ("hello", response_data);
- }
+ ASSERT_TRUE(response->headers != NULL);
+ response_lines[i] = response->headers->GetStatusLine();
+
+ // We intentionally don't read the response bodies.
}
+
+ const char* const kStatusLines[] = {
+ "HTTP/1.1 204 No Content",
+ "HTTP/1.1 205 Reset Content",
+ "HTTP/1.1 304 Not Modified",
+ "HTTP/1.1 302 Found",
+ "HTTP/1.1 302 Found",
+ "HTTP/1.1 301 Moved Permanently",
+ "HTTP/1.1 301 Moved Permanently",
+ };
+
+ COMPILE_ASSERT(kNumUnreadBodies == arraysize(kStatusLines),
+ forgot_to_update_kStatusLines);
+
+ for (int i = 0; i < kNumUnreadBodies; ++i)
+ EXPECT_EQ(kStatusLines[i], response_lines[i]);
+
+ TestCompletionCallback callback;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+ 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_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ std::string response_data;
+ rv = ReadTransaction(trans.get(), &response_data);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("hello", response_data);
}
// Test the request-challenge-retry sequence for basic auth.
@@ -945,7 +1081,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuth) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -1002,8 +1138,7 @@ TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) {
// connection.
TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
HttpRequestInfo request;
request.method = "GET";
@@ -1033,8 +1168,8 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
// Lastly, the server responds with the actual content.
MockRead("HTTP/1.1 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(false, OK),
+ MockRead("Content-Length: 5\r\n\r\n"),
+ MockRead("Hello"),
};
StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
@@ -1043,6 +1178,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
int rv = trans->Start(&request, &callback1, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1061,7 +1197,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -1070,15 +1206,14 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
response = trans->GetResponseInfo();
EXPECT_FALSE(response == NULL);
EXPECT_TRUE(response->auth_challenge.get() == NULL);
- EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_EQ(5, response->headers->GetContentLength());
}
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// connection and with no response body to drain.
TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
HttpRequestInfo request;
request.method = "GET";
@@ -1106,8 +1241,8 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
// Lastly, the server responds with the actual content.
MockRead("HTTP/1.1 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(false, OK),
+ MockRead("Content-Length: 5\r\n\r\n"),
+ MockRead("hello"),
};
StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
@@ -1116,6 +1251,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
int rv = trans->Start(&request, &callback1, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1134,7 +1270,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -1143,15 +1279,14 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
response = trans->GetResponseInfo();
EXPECT_FALSE(response == NULL);
EXPECT_TRUE(response->auth_challenge.get() == NULL);
- EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_EQ(5, response->headers->GetContentLength());
}
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// connection and with a large response body to drain.
TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
HttpRequestInfo request;
request.method = "GET";
@@ -1187,8 +1322,8 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
// Lastly, the server responds with the actual content.
MockRead("HTTP/1.1 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(false, OK),
+ MockRead("Content-Length: 5\r\n\r\n"),
+ MockRead("hello"),
};
StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
@@ -1197,6 +1332,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
int rv = trans->Start(&request, &callback1, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1215,7 +1351,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -1224,15 +1360,14 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
response = trans->GetResponseInfo();
EXPECT_FALSE(response == NULL);
EXPECT_TRUE(response->auth_challenge.get() == NULL);
- EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_EQ(5, response->headers->GetContentLength());
}
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// connection, but the server gets impatient and closes the connection.
TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
HttpRequestInfo request;
request.method = "GET";
@@ -1275,8 +1410,8 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
MockRead data_reads2[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(false, OK),
+ MockRead("Content-Length: 5\r\n\r\n"),
+ MockRead("hello"),
};
StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
@@ -1288,6 +1423,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
int rv = trans->Start(&request, &callback1, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1306,7 +1442,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -1315,7 +1451,115 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
response = trans->GetResponseInfo();
ASSERT_FALSE(response == NULL);
EXPECT_TRUE(response->auth_challenge.get() == NULL);
- EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_EQ(5, response->headers->GetContentLength());
+}
+
+// Test the request-challenge-retry sequence for basic auth, over a connection
+// that requires a restart when setting up an SSL tunnel.
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) {
+ // Configure against proxy server "myproxy:70".
+ SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ // when the no authentication data flag is set.
+ request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
+
+ // Since we have proxy, should try to establish tunnel.
+ MockWrite data_writes1[] = {
+ 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"),
+
+ // After calling trans->RestartWithAuth(), this is the request we should
+ // be issuing -- the final header line contains the credentials.
+ MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ // The proxy responds to the connect with a 407, using a persistent
+ // connection.
+ MockRead data_reads1[] = {
+ // No credentials.
+ MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
+ MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
+ MockRead("Proxy-Connection: close\r\n\r\n"),
+
+ MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
+
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
+ MockRead("Content-Length: 5\r\n\r\n"),
+ MockRead(false, "hello"),
+ };
+
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
+ data_writes1, arraysize(data_writes1));
+ session_deps.socket_factory.AddSocketDataProvider(&data1);
+ SSLSocketDataProvider ssl(true, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ TestCompletionCallback callback1;
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ size_t pos = ExpectLogContainsSomewhere(
+ log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLog::PHASE_NONE);
+ ExpectLogContainsSomewhere(
+ log.entries(), pos,
+ NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLog::PHASE_NONE);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_EQ(407, response->headers->response_code());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+
+ // The password prompt info should have been set in response->auth_challenge.
+ ASSERT_FALSE(response->auth_challenge.get() == NULL);
+
+ EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port);
+ EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
+ EXPECT_EQ(L"basic", response->auth_challenge->scheme);
+
+ TestCompletionCallback callback2;
+
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback2.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_TRUE(response->headers->IsKeepAlive());
+ EXPECT_EQ(200, response->headers->response_code());
+ EXPECT_EQ(5, response->headers->GetContentLength());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+
+ // The password prompt info should not be set.
+ EXPECT_TRUE(response->auth_challenge.get() == NULL);
+
+ trans.reset();
+ session->FlushSocketPools();
}
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
@@ -1404,7 +1648,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
TestCompletionCallback callback2;
// Wrong password (should be "bar").
- rv = trans->RestartWithAuth(L"foo", L"baz", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBaz, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -1528,6 +1772,212 @@ TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv);
}
+
+// Test a simple get through an HTTPS Proxy.
+TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) {
+ // Configure against https proxy server "proxy:70".
+ SessionDependencies session_deps(CreateFixedProxyService("https://proxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+
+ // Since we have proxy, should use full url
+ MockWrite data_writes1[] = {
+ MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads1[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
+ MockRead("Content-Length: 100\r\n\r\n"),
+ MockRead(false, OK),
+ };
+
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
+ data_writes1, arraysize(data_writes1));
+ session_deps.socket_factory.AddSocketDataProvider(&data1);
+ SSLSocketDataProvider ssl(true, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ TestCompletionCallback callback1;
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_TRUE(response->headers->IsKeepAlive());
+ EXPECT_EQ(200, response->headers->response_code());
+ EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+
+ // The password prompt info should not be set.
+ EXPECT_TRUE(response->auth_challenge.get() == NULL);
+}
+
+// Test a SPDY get through an HTTPS Proxy.
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
+ // Configure against https proxy server "proxy:70".
+ SessionDependencies session_deps(CreateFixedProxyService("https://proxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ // fetch http://www.google.com/ via SPDY
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST,
+ false));
+ MockWrite spdy_writes[] = { CreateMockWrite(*req) };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
+ MockRead spdy_reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*data),
+ MockRead(true, 0, 0),
+ };
+
+ scoped_refptr<DelayedSocketData> spdy_data(
+ new DelayedSocketData(
+ 1, // wait for one write to finish before reading.
+ spdy_reads, arraysize(spdy_reads),
+ spdy_writes, arraysize(spdy_writes)));
+ session_deps.socket_factory.AddSocketDataProvider(spdy_data);
+
+ SSLSocketDataProvider ssl(true, OK);
+ ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ ssl.next_proto = "spdy/2";
+ ssl.was_npn_negotiated = true;
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ TestCompletionCallback callback1;
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_EQ(net::kUploadData, response_data);
+}
+
+// Test the challenge-response-retry sequence through an HTTPS Proxy
+TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
+ // Configure against https proxy server "proxy:70".
+ SessionDependencies session_deps(CreateFixedProxyService("https://proxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ // when the no authentication data flag is set.
+ request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA;
+
+ // Since we have proxy, should use full url
+ MockWrite data_writes1[] = {
+ MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
+
+ // After calling trans->RestartWithAuth(), this is the request we should
+ // be issuing -- the final header line contains the credentials.
+ MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+ };
+
+ // The proxy responds to the GET with a 407, using a persistent
+ // connection.
+ MockRead data_reads1[] = {
+ // No credentials.
+ MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
+ MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
+ MockRead("Proxy-Connection: keep-alive\r\n"),
+ MockRead("Content-Length: 0\r\n\r\n"),
+
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
+ MockRead("Content-Length: 100\r\n\r\n"),
+ MockRead(false, OK),
+ };
+
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
+ data_writes1, arraysize(data_writes1));
+ session_deps.socket_factory.AddSocketDataProvider(&data1);
+ SSLSocketDataProvider ssl(true, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ TestCompletionCallback callback1;
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_EQ(407, response->headers->response_code());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+
+ // The password prompt info should have been set in response->auth_challenge.
+ ASSERT_FALSE(response->auth_challenge.get() == NULL);
+
+ EXPECT_EQ(L"proxy:70", response->auth_challenge->host_and_port);
+ EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm);
+ EXPECT_EQ(L"basic", response->auth_challenge->scheme);
+
+ TestCompletionCallback callback2;
+
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback2.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_TRUE(response->headers->IsKeepAlive());
+ EXPECT_EQ(200, response->headers->response_code());
+ EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+
+ // The password prompt info should not be set.
+ EXPECT_TRUE(response->auth_challenge.get() == NULL);
+}
+
void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus(
const MockRead& status, int expected_status) {
// Configure against proxy server "myproxy:70".
@@ -1535,8 +1985,6 @@ void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus(
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
- scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
-
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.google.com/");
@@ -1562,6 +2010,8 @@ void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus(
TestCompletionCallback callback;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
int rv = trans->Start(&request, &callback, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1842,7 +2292,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -1858,7 +2308,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3);
+ rv = trans->RestartWithAuth(kFoo2, kBar2, &callback3);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback3.WaitForResult();
@@ -1882,8 +2332,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1,
MockGetHostName);
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
HttpRequestInfo request;
request.method = "GET";
@@ -1964,6 +2413,8 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
int rv = trans->Start(&request, &callback1, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1972,7 +2423,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
EXPECT_TRUE(trans->IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -1991,7 +2442,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback3);
+ rv = trans->RestartWithAuth(kTestingNTLM, kTestingNTLM, &callback3);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback3.WaitForResult();
@@ -2009,8 +2460,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2,
MockGetHostName);
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
HttpRequestInfo request;
request.method = "GET";
@@ -2142,6 +2592,8 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
int rv = trans->Start(&request, &callback1, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -2150,7 +2602,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
EXPECT_TRUE(trans->IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -2169,7 +2621,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
TestCompletionCallback callback3;
// Enter the wrong password.
- rv = trans->RestartWithAuth(L"testing-ntlm", L"wrongpassword", &callback3);
+ rv = trans->RestartWithAuth(kTestingNTLM, kWrongPassword, &callback3);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback3.WaitForResult();
@@ -2177,7 +2629,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
EXPECT_TRUE(trans->IsReadyToRestartForAuth());
TestCompletionCallback callback4;
- rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback4);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback4);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback4.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -2196,7 +2648,7 @@ TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
TestCompletionCallback callback5;
// Now enter the right password.
- rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback5);
+ rv = trans->RestartWithAuth(kTestingNTLM, kTestingNTLM, &callback5);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback5.WaitForResult();
@@ -2361,6 +2813,160 @@ TEST_F(HttpNetworkTransactionTest, RecycleSocket) {
EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount());
}
+// Make sure that we recycle a SSL socket after reading all of the response
+// body.
+TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) {
+ SessionDependencies session_deps;
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ MockWrite data_writes[] = {
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Length: 11\r\n\r\n"),
+ MockRead("hello world"),
+ MockRead(false, OK),
+ };
+
+ SSLSocketDataProvider ssl(true, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+
+ TestCompletionCallback callback;
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount());
+
+ std::string response_data;
+ rv = ReadTransaction(trans.get(), &response_data);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("hello world", response_data);
+
+ // Empty the current queue. This is necessary because idle sockets are
+ // added to the connection pool asynchronously with a PostTask.
+ MessageLoop::current()->RunAllPending();
+
+ // We now check to make sure the socket was added back to the pool.
+ EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount());
+}
+
+// Grab a SSL socket, use it, and put it back into the pool. Then, reuse it
+// from the pool and make sure that we recover okay.
+TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
+ SessionDependencies session_deps;
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ MockWrite data_writes[] = {
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Length: 11\r\n\r\n"),
+ MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead("hello world"),
+ MockRead(true, 0, 0) // EOF
+ };
+
+ SSLSocketDataProvider ssl(true, OK);
+ SSLSocketDataProvider ssl2(true, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2);
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ StaticSocketDataProvider data2(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+ session_deps.socket_factory.AddSocketDataProvider(&data2);
+
+ TestCompletionCallback callback;
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount());
+
+ std::string response_data;
+ rv = ReadTransaction(trans.get(), &response_data);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("hello world", response_data);
+
+ // Empty the current queue. This is necessary because idle sockets are
+ // added to the connection pool asynchronously with a PostTask.
+ MessageLoop::current()->RunAllPending();
+
+ // We now check to make sure the socket was added back to the pool.
+ EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount());
+
+ // Now start the second transaction, which should reuse the previous socket.
+
+ trans.reset(new HttpNetworkTransaction(session));
+
+ rv = trans->Start(&request, &callback, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount());
+
+ rv = ReadTransaction(trans.get(), &response_data);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("hello world", response_data);
+
+ // Empty the current queue. This is necessary because idle sockets are
+ // added to the connection pool asynchronously with a PostTask.
+ MessageLoop::current()->RunAllPending();
+
+ // We now check to make sure the socket was added back to the pool.
+ EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount());
+}
+
// Make sure that we recycle a socket after a zero-length response.
// http://crbug.com/9880
TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
@@ -2569,7 +3175,7 @@ TEST_F(HttpNetworkTransactionTest, AuthIdentityInURL) {
EXPECT_TRUE(trans->IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -2667,7 +3273,7 @@ TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
EXPECT_TRUE(trans->IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -2683,7 +3289,7 @@ TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
EXPECT_EQ(L"basic", response->auth_challenge->scheme);
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback3);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback3);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback3.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -2771,7 +3377,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -2856,7 +3462,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2);
+ rv = trans->RestartWithAuth(kFoo2, kBar2, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -2972,7 +3578,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
EXPECT_TRUE(trans->IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -3061,7 +3667,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
EXPECT_TRUE(trans->IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -3080,7 +3686,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback3);
+ rv = trans->RestartWithAuth(kFoo3, kBar3, &callback3);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback3.WaitForResult();
@@ -3167,7 +3773,7 @@ TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -3404,6 +4010,143 @@ TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
}
}
+
+// Test HTTPS connections to a site, going through an HTTPS proxy
+TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) {
+ SessionDependencies session_deps(CreateFixedProxyService("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"),
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
+ MockRead("Content-Length: 100\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
+ SSLSocketDataProvider tunnel_ssl(true, OK); // SSL through the tunnel
+
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&tunnel_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_TRUE(response->headers->IsKeepAlive());
+ EXPECT_EQ(200, response->headers->response_code());
+ EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+}
+
+// Test HTTPS connections to a site with a bad certificate, going through an
+// HTTPS proxy
+TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) {
+ SessionDependencies session_deps(CreateFixedProxyService("https://proxy:70"));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ // Attempt to fetch the URL from a server with a bad cert
+ MockWrite bad_cert_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 bad_cert_reads[] = {
+ MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
+ MockRead(false, OK)
+ };
+
+ // Attempt to fetch the URL with a good cert
+ MockWrite good_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"),
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead good_cert_reads[] = {
+ MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
+ MockRead("HTTP/1.0 200 OK\r\n"),
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
+ MockRead("Content-Length: 100\r\n\r\n"),
+ MockRead(false, OK),
+ };
+
+ StaticSocketDataProvider ssl_bad_certificate(
+ bad_cert_reads, arraysize(bad_cert_reads),
+ bad_cert_writes, arraysize(bad_cert_writes));
+ StaticSocketDataProvider data(good_cert_reads, arraysize(good_cert_reads),
+ good_data_writes, arraysize(good_data_writes));
+ SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID);
+ SSLSocketDataProvider ssl(true, OK);
+
+ // SSL to the proxy, then CONNECT request, then SSL with bad certificate
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+ session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad);
+
+ // SSL to the proxy, then CONNECT request, then valid SSL certificate
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&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(ERR_CERT_AUTHORITY_INVALID, rv);
+
+ rv = trans->RestartIgnoringLastError(&callback);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+
+ EXPECT_FALSE(response == NULL);
+ EXPECT_EQ(100, response->headers->GetContentLength());
+}
+
TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
SessionDependencies session_deps;
scoped_ptr<HttpTransaction> trans(
@@ -3443,6 +4186,44 @@ TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
EXPECT_EQ(OK, rv);
}
+TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) {
+ SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(CreateSession(&session_deps)));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
+ "Chromium Ultra Awesome X Edition");
+
+ 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"
+ "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"),
+ };
+ MockRead data_reads[] = {
+ // Return an error, so the transaction stops here (this test isn't
+ // interested in the rest).
+ MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
+ MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
+ MockRead("Proxy-Connection: close\r\n\r\n"),
+ };
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+
+ TestCompletionCallback callback;
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+}
+
TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) {
SessionDependencies session_deps;
scoped_ptr<HttpTransaction> trans(
@@ -4010,7 +4791,7 @@ scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests(
session->mutable_alternate_protocols();
alternate_protocols->SetAlternateProtocolFor(
HostPortPair("host.with.alternate", 80), 443,
- HttpAlternateProtocols::NPN_SPDY_1);
+ HttpAlternateProtocols::NPN_SPDY_2);
return session;
}
@@ -4067,18 +4848,18 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
},
};
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
+ HttpStreamFactory::set_use_alternate_protocols(true);
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
scoped_refptr<HttpNetworkSession> session(
SetupSessionForGroupNameTests(tests[i].proxy_server));
HttpNetworkSessionPeer peer(session);
- scoped_refptr<CaptureGroupNameTCPSocketPool> tcp_conn_pool(
- new CaptureGroupNameTCPSocketPool(session.get()));
+ CaptureGroupNameTCPSocketPool* tcp_conn_pool =
+ new CaptureGroupNameTCPSocketPool(session);
peer.SetTCPSocketPool(tcp_conn_pool);
- scoped_refptr<CaptureGroupNameSSLSocketPool> ssl_conn_pool(
- new CaptureGroupNameSSLSocketPool(session.get()));
+ CaptureGroupNameSSLSocketPool* ssl_conn_pool =
+ new CaptureGroupNameSSLSocketPool(session.get());
peer.SetSSLSocketPool(ssl_conn_pool);
EXPECT_EQ(ERR_IO_PENDING,
@@ -4091,7 +4872,7 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
tcp_conn_pool->last_group_name_received());
}
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
@@ -4119,7 +4900,7 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
},
};
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
+ HttpStreamFactory::set_use_alternate_protocols(true);
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
scoped_refptr<HttpNetworkSession> session(
@@ -4128,11 +4909,11 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
HttpNetworkSessionPeer peer(session);
HostPortPair proxy_host("http_proxy", 80);
- scoped_refptr<CaptureGroupNameHttpProxySocketPool> http_proxy_pool(
- new CaptureGroupNameHttpProxySocketPool(session.get()));
+ CaptureGroupNameHttpProxySocketPool* http_proxy_pool =
+ new CaptureGroupNameHttpProxySocketPool(session);
peer.SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
- scoped_refptr<CaptureGroupNameSSLSocketPool> ssl_conn_pool(
- new CaptureGroupNameSSLSocketPool(session.get()));
+ CaptureGroupNameSSLSocketPool* ssl_conn_pool =
+ new CaptureGroupNameSSLSocketPool(session);
peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
EXPECT_EQ(ERR_IO_PENDING,
@@ -4145,7 +4926,7 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
http_proxy_pool->last_group_name_received());
}
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
@@ -4185,7 +4966,7 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
},
};
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
+ HttpStreamFactory::set_use_alternate_protocols(true);
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
scoped_refptr<HttpNetworkSession> session(
@@ -4193,11 +4974,11 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
HttpNetworkSessionPeer peer(session);
HostPortPair proxy_host("socks_proxy", 1080);
- scoped_refptr<CaptureGroupNameSOCKSSocketPool> socks_conn_pool(
- new CaptureGroupNameSOCKSSocketPool(session.get()));
+ CaptureGroupNameSOCKSSocketPool* socks_conn_pool =
+ new CaptureGroupNameSOCKSSocketPool(session);
peer.SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool);
- scoped_refptr<CaptureGroupNameSSLSocketPool> ssl_conn_pool(
- new CaptureGroupNameSSLSocketPool(session.get()));
+ CaptureGroupNameSSLSocketPool* ssl_conn_pool =
+ new CaptureGroupNameSSLSocketPool(session);
peer.SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
@@ -4212,7 +4993,7 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
socks_conn_pool->last_group_name_received());
}
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
@@ -4236,7 +5017,7 @@ TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+ EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
}
// Host resolution observer used by
@@ -4332,7 +5113,7 @@ void BypassHostCacheOnRefreshHelper(int load_flags) {
// a synchronous lookup.)
AddressList addrlist;
int rv = session_deps.host_resolver->Resolve(
- HostResolver::RequestInfo("www.google.com", 80), &addrlist,
+ HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist,
NULL, NULL, BoundNetLog());
EXPECT_EQ(OK, rv);
@@ -4340,7 +5121,7 @@ void BypassHostCacheOnRefreshHelper(int load_flags) {
// and confirming it completes synchronously.
TestCompletionCallback resolve_callback;
rv = session_deps.host_resolver->Resolve(
- HostResolver::RequestInfo("www.google.com", 80), &addrlist,
+ HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist,
&resolve_callback, NULL, BoundNetLog());
ASSERT_EQ(OK, rv);
@@ -4460,8 +5241,7 @@ TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
// restart does the right thing.
TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
HttpRequestInfo request;
request.method = "GET";
@@ -4510,6 +5290,8 @@ TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
int rv = trans->Start(&request, &callback1, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -4528,7 +5310,7 @@ TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -4630,7 +5412,7 @@ TEST_F(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
element.SetToFilePath(temp_file_path);
element.SetContentLength(kFakeSize);
elements.push_back(element);
- request.upload_data->set_elements(elements);
+ request.upload_data->SetElements(elements);
EXPECT_EQ(kFakeSize, request.upload_data->GetContentLength());
MockRead data_reads[] = {
@@ -4687,7 +5469,7 @@ TEST_F(HttpNetworkTransactionTest, UploadUnreadableFile) {
UploadData::Element element;
element.SetToFilePath(temp_file);
elements.push_back(element);
- request.upload_data->set_elements(elements);
+ request.upload_data->SetElements(elements);
MockRead data_reads[] = {
MockRead("HTTP/1.0 200 OK\r\n\r\n"),
@@ -4742,7 +5524,7 @@ TEST_F(HttpNetworkTransactionTest, UnreadableUploadFileAfterAuthRestart) {
UploadData::Element element;
element.SetToFilePath(temp_file);
elements.push_back(element);
- request.upload_data->set_elements(elements);
+ request.upload_data->SetElements(elements);
MockRead data_reads[] = {
MockRead("HTTP/1.1 401 Unauthorized\r\n"),
@@ -4796,7 +5578,7 @@ TEST_F(HttpNetworkTransactionTest, UnreadableUploadFileAfterAuthRestart) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback2);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
@@ -4814,8 +5596,6 @@ TEST_F(HttpNetworkTransactionTest, UnreadableUploadFileAfterAuthRestart) {
// Tests that changes to Auth realms are treated like auth rejections.
TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
SessionDependencies session_deps;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
HttpRequestInfo request;
request.method = "GET";
@@ -4878,8 +5658,9 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
MockRead data_reads4[] = {
MockRead("HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 100\r\n"
- "\r\n"),
+ "Content-Length: 5\r\n"
+ "\r\n"
+ "hello"),
};
StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
@@ -4897,6 +5678,9 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
TestCompletionCallback callback1;
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(CreateSession(&session_deps)));
+
// Issue the first request with Authorize headers. There should be a
// password prompt for first_realm waiting to be filled in after the
// transaction completes.
@@ -4915,7 +5699,7 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
// password prompt for second_realm waiting to be filled in after the
// transaction completes.
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(L"first", L"baz", &callback2);
+ rv = trans->RestartWithAuth(kFirst, kBaz, &callback2);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -4931,7 +5715,7 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
// prompt is not present, it indicates that the HttpAuthCacheEntry for
// first_realm was not correctly removed.
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(L"second", L"fou", &callback3);
+ rv = trans->RestartWithAuth(kSecond, kFou, &callback3);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback3.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -4944,7 +5728,7 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
// Issue the fourth request with the correct password and username.
TestCompletionCallback callback4;
- rv = trans->RestartWithAuth(L"first", L"bar", &callback4);
+ rv = trans->RestartWithAuth(kFirst, kBar, &callback4);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback4.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -4954,14 +5738,14 @@ TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
}
TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
- HttpNetworkTransaction::SetNextProtos("needs_to_be_set_for_this_test");
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
+ HttpStreamFactory::set_next_protos("needs_to_be_set_for_this_test");
+ HttpStreamFactory::set_use_alternate_protocols(true);
SessionDependencies session_deps;
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alternate-Protocol: 443:npn-spdy/1\r\n\r\n"),
+ MockRead(kAlternateProtocolHttpHeader),
MockRead("hello world"),
MockRead(false, OK),
};
@@ -4983,9 +5767,7 @@ TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
int rv = trans->Start(&request, &callback, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- HostPortPair http_host_port_pair;
- http_host_port_pair.host = "www.google.com";
- http_host_port_pair.port = 80;
+ HostPortPair http_host_port_pair("www.google.com", 80);
const HttpAlternateProtocols& alternate_protocols =
session->alternate_protocols();
EXPECT_FALSE(
@@ -5010,15 +5792,15 @@ TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
alternate_protocols.GetAlternateProtocolFor(http_host_port_pair);
HttpAlternateProtocols::PortProtocolPair expected_alternate;
expected_alternate.port = 443;
- expected_alternate.protocol = HttpAlternateProtocols::NPN_SPDY_1;
+ expected_alternate.protocol = HttpAlternateProtocols::NPN_SPDY_2;
EXPECT_TRUE(expected_alternate.Equals(alternate));
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
- HttpNetworkTransaction::SetNextProtos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
+ HttpStreamFactory::set_next_protos("");
}
TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) {
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
+ HttpStreamFactory::set_use_alternate_protocols(true);
SessionDependencies session_deps;
HttpRequestInfo request;
@@ -5049,14 +5831,12 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) {
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
- HostPortPair http_host_port_pair;
- http_host_port_pair.host = "www.google.com";
- http_host_port_pair.port = 80;
+ HostPortPair http_host_port_pair("www.google.com", 80);
HttpAlternateProtocols* alternate_protocols =
session->mutable_alternate_protocols();
alternate_protocols->SetAlternateProtocolFor(
http_host_port_pair, 1234 /* port is ignored by MockConnect anyway */,
- HttpAlternateProtocols::NPN_SPDY_1);
+ HttpAlternateProtocols::NPN_SPDY_2);
scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
@@ -5078,7 +5858,7 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) {
const HttpAlternateProtocols::PortProtocolPair alternate =
alternate_protocols->GetAlternateProtocolFor(http_host_port_pair);
EXPECT_EQ(HttpAlternateProtocols::BROKEN, alternate.protocol);
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
// TODO(willchan): Redo this test to use TLS/NPN=>SPDY. Currently, the code
@@ -5135,9 +5915,8 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) {
// }
TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) {
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
- HttpNetworkTransaction::SetNextProtos(
- "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy");
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
SessionDependencies session_deps;
HttpRequestInfo request;
@@ -5164,14 +5943,12 @@ TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) {
scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
- HostPortPair http_host_port_pair;
- http_host_port_pair.host = "www.google.com";
- http_host_port_pair.port = 80;
+ HostPortPair http_host_port_pair("www.google.com", 80);
HttpAlternateProtocols* alternate_protocols =
session->mutable_alternate_protocols();
alternate_protocols->SetAlternateProtocolFor(
http_host_port_pair, 1234 /* port is ignored */,
- HttpAlternateProtocols::NPN_SPDY_1);
+ HttpAlternateProtocols::NPN_SPDY_2);
scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
@@ -5187,14 +5964,13 @@ TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) {
std::string response_data;
ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
EXPECT_EQ("hello world", response_data);
- HttpNetworkTransaction::SetNextProtos("");
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
- HttpNetworkTransaction::SetNextProtos(
- "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy");
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
SessionDependencies session_deps;
HttpRequestInfo request;
@@ -5204,7 +5980,7 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alternate-Protocol: 443:npn-spdy/1\r\n\r\n"),
+ MockRead(kAlternateProtocolHttpHeader),
MockRead("hello world"),
MockRead(true, OK),
};
@@ -5215,7 +5991,7 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
SSLSocketDataProvider ssl(true, OK);
ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- ssl.next_proto = "spdy/1";
+ ssl.next_proto = "spdy/2";
ssl.was_npn_negotiated = true;
session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
@@ -5272,8 +6048,8 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
EXPECT_EQ("hello!", response_data);
- HttpNetworkTransaction::SetNextProtos("");
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
class CapturingProxyResolver : public ProxyResolver {
@@ -5286,8 +6062,8 @@ class CapturingProxyResolver : public ProxyResolver {
CompletionCallback* callback,
RequestHandle* request,
const BoundNetLog& net_log) {
- ProxyServer proxy_server(
- ProxyServer::SCHEME_HTTP, "myproxy", 80);
+ ProxyServer proxy_server(ProxyServer::SCHEME_HTTP,
+ HostPortPair("myproxy", 80));
results->UseProxyServer(proxy_server);
resolved_.push_back(url);
return OK;
@@ -5311,9 +6087,8 @@ class CapturingProxyResolver : public ProxyResolver {
};
TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) {
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
- HttpNetworkTransaction::SetNextProtos(
- "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy");
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
ProxyConfig proxy_config;
proxy_config.set_auto_detect(true);
@@ -5332,7 +6107,7 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alternate-Protocol: 443:npn-spdy/1\r\n\r\n"),
+ MockRead(kAlternateProtocolHttpHeader),
MockRead("hello world"),
MockRead(true, OK),
};
@@ -5343,7 +6118,7 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) {
SSLSocketDataProvider ssl(true, OK);
ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- ssl.next_proto = "spdy/1";
+ ssl.next_proto = "spdy/2";
ssl.was_npn_negotiated = true;
session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
@@ -5413,15 +6188,14 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) {
EXPECT_EQ("https://www.google.com/",
capturing_proxy_resolver->resolved()[1].spec());
- HttpNetworkTransaction::SetNextProtos("");
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
TEST_F(HttpNetworkTransactionTest,
UseAlternateProtocolForNpnSpdyWithExistingSpdySession) {
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
- HttpNetworkTransaction::SetNextProtos(
- "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy");
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
SessionDependencies session_deps;
HttpRequestInfo request;
@@ -5431,7 +6205,7 @@ TEST_F(HttpNetworkTransactionTest,
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alternate-Protocol: 443:npn-spdy/1\r\n\r\n"),
+ MockRead(kAlternateProtocolHttpHeader),
MockRead("hello world"),
MockRead(true, OK),
};
@@ -5442,7 +6216,7 @@ TEST_F(HttpNetworkTransactionTest,
SSLSocketDataProvider ssl(true, OK);
ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- ssl.next_proto = "spdy/1";
+ ssl.next_proto = "spdy/2";
ssl.was_npn_negotiated = true;
session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
// Make sure we use ssl for spdy here.
@@ -5486,12 +6260,33 @@ TEST_F(HttpNetworkTransactionTest,
EXPECT_EQ("hello world", response_data);
// Set up an initial SpdySession in the pool to reuse.
+ HostPortPair host_port_pair("www.google.com", 443);
+ HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
scoped_refptr<SpdySession> spdy_session =
- session->spdy_session_pool()->Get(HostPortPair("www.google.com", 443),
- session, BoundNetLog());
+ session->spdy_session_pool()->Get(pair, session->mutable_spdy_settings(),
+ BoundNetLog());
scoped_refptr<TCPSocketParams> tcp_params =
new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false);
- spdy_session->Connect("www.google.com:443", tcp_params, MEDIUM);
+
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+ EXPECT_EQ(ERR_IO_PENDING,
+ connection->Init(host_port_pair.ToString(),tcp_params, LOWEST,
+ &callback, session->tcp_socket_pool(),
+ BoundNetLog()));
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ SSLConfig ssl_config;
+ session->ssl_config_service()->GetSSLConfig(&ssl_config);
+ ClientSocket* socket = connection->release_socket();
+ socket = session->socket_factory()->CreateSSLClientSocket(socket, "" ,
+ ssl_config);
+ connection->set_socket(socket);
+ EXPECT_EQ(ERR_IO_PENDING, socket->Connect(&callback));
+ EXPECT_EQ(OK, callback.WaitForResult());
+
+ EXPECT_EQ(OK, spdy_session->InitializeWithSocket(connection.release(),
+ true, OK));
+
trans.reset(new HttpNetworkTransaction(session));
rv = trans->Start(&request, &callback, BoundNetLog());
@@ -5509,8 +6304,8 @@ TEST_F(HttpNetworkTransactionTest,
ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
EXPECT_EQ("hello!", response_data);
- HttpNetworkTransaction::SetNextProtos("");
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
// GenerateAuthToken is a mighty big test.
@@ -5530,9 +6325,9 @@ TEST_F(HttpNetworkTransactionTest,
// specifies both the configuration for the test as well as the expectations
// for the results.
TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
- const char* kServer = "http://www.example.com";
- const char* kSecureServer = "https://www.example.com";
- const char* kProxy = "myproxy:70";
+ static const char kServer[] = "http://www.example.com";
+ static const char kSecureServer[] = "https://www.example.com";
+ static const char kProxy[] = "myproxy:70";
const int kAuthErr = ERR_INVALID_AUTH_CREDENTIALS;
enum AuthTiming {
@@ -5817,7 +6612,6 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
};
SessionDependencies session_deps;
- scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
HttpAuthHandlerMock::Factory* auth_factory(
new HttpAuthHandlerMock::Factory());
session_deps.http_auth_handler_factory.reset(auth_factory);
@@ -5856,7 +6650,7 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
session_deps.proxy_service =
CreateFixedProxyService(test_config.proxy_url);
} else {
- session_deps.proxy_service = ProxyService::CreateNull();
+ session_deps.proxy_service = ProxyService::CreateDirect();
}
HttpRequestInfo request;
@@ -5864,8 +6658,8 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
request.url = GURL(test_config.server_url);
request.load_flags = 0;
- scoped_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(CreateSession(&session_deps)));
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+ HttpNetworkTransaction trans(CreateSession(&session_deps));
for (int round = 0; round < test_config.num_auth_rounds; ++round) {
const TestRound& read_write_round = test_config.rounds[round];
@@ -5900,16 +6694,16 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
TestCompletionCallback callback;
int rv;
if (round == 0) {
- rv = trans->Start(&request, &callback, BoundNetLog());
+ rv = trans.Start(&request, &callback, BoundNetLog());
} else {
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback);
+ rv = trans.RestartWithAuth(kFoo, kBar, &callback);
}
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
// Compare results with expected data.
EXPECT_EQ(read_write_round.expected_rv, rv);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
if (read_write_round.expected_rv == OK) {
EXPECT_FALSE(response == NULL);
} else {
@@ -5924,9 +6718,6 @@ TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
}
}
}
-
- // Flush the idle socket before the HttpNetworkTransaction goes out of scope.
- session->FlushSocketPools();
}
TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
@@ -5935,7 +6726,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
HttpAuthHandlerMock::Factory* auth_factory(
new HttpAuthHandlerMock::Factory());
session_deps.http_auth_handler_factory.reset(auth_factory);
- session_deps.proxy_service = ProxyService::CreateNull();
+ session_deps.proxy_service = ProxyService::CreateDirect();
session_deps.host_resolver->rules()->AddRule("www.example.com", "10.0.0.1");
session_deps.host_resolver->set_synchronous_mode(true);
@@ -5989,6 +6780,8 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
kGetAuth,
// Third round
kGetAuth,
+ // Fourth round
+ kGetAuth
};
MockRead reads[] = {
// First round
@@ -5996,6 +6789,8 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
// Second round
kServerChallenge,
// Third round
+ kServerChallenge,
+ // Fourth round
kSuccess,
};
StaticSocketDataProvider data_provider(reads, arraysize(reads),
@@ -6014,7 +6809,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
// Second round
auth_handler->SetGenerateExpectation(false, OK);
- rv = trans->RestartWithAuth(L"foo", L"bar", &callback);
+ rv = trans->RestartWithAuth(kFoo, kBar, &callback);
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -6024,7 +6819,17 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
// Third round
auth_handler->SetGenerateExpectation(false, OK);
- rv = trans->RestartWithAuth(L"", L"", &callback);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback);
+ if (rv == ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+ EXPECT_TRUE(response->auth_challenge.get() == NULL);
+
+ // Fourth round
+ auth_handler->SetGenerateExpectation(false, OK);
+ rv = trans->RestartWithAuth(string16(), string16(), &callback);
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -6149,8 +6954,8 @@ TEST_F(HttpNetworkTransactionTest,
// This tests the case that a request is issued via http instead of spdy after
// npn is negotiated.
TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
- HttpNetworkTransaction::SetNextProtos("\x08http/1.1\x07http1.1");
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos("\x08http/1.1\x07http1.1");
SessionDependencies session_deps;
HttpRequestInfo request;
request.method = "GET";
@@ -6165,7 +6970,7 @@ TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alternate-Protocol: 443:npn-spdy/1\r\n\r\n"),
+ MockRead(kAlternateProtocolHttpHeader),
MockRead("hello world"),
MockRead(false, OK),
};
@@ -6203,17 +7008,16 @@ TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
EXPECT_TRUE(response->was_npn_negotiated);
EXPECT_FALSE(response->was_alternate_protocol_available);
- HttpNetworkTransaction::SetNextProtos("");
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
}
TEST_F(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) {
// Simulate the SSL handshake completing with an NPN negotiation
// followed by an immediate server closing of the socket.
// Fix crash: http://crbug.com/46369
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
- HttpNetworkTransaction::SetNextProtos(
- "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy");
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
SessionDependencies session_deps;
HttpRequestInfo request;
@@ -6223,7 +7027,7 @@ TEST_F(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) {
SSLSocketDataProvider ssl(true, OK);
ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- ssl.next_proto = "spdy/1";
+ ssl.next_proto = "spdy/2";
ssl.was_npn_negotiated = true;
session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
@@ -6250,8 +7054,418 @@ TEST_F(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) {
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
- HttpNetworkTransaction::SetNextProtos("");
- HttpNetworkTransaction::SetUseAlternateProtocols(false);
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
+}
+
+TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) {
+ // This test ensures that the URL passed into the proxy is upgraded
+ // to https when doing an Alternate Protocol upgrade.
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(
+ "\x08http/1.1\x07http1.1\x06spdy/2\x04spdy");
+
+ SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
+ HttpAuthHandlerMock::Factory* auth_factory =
+ new HttpAuthHandlerMock::Factory();
+ HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock();
+ auth_factory->set_mock_handler(auth_handler, HttpAuth::AUTH_PROXY);
+ auth_factory->set_do_init_from_challenge(true);
+ session_deps.http_auth_handler_factory.reset(auth_factory);
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com");
+ request.load_flags = 0;
+
+ // First round goes unauthenticated through the proxy.
+ MockWrite data_writes_1[] = {
+ MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "\r\n"),
+ };
+ MockRead data_reads_1[] = {
+ MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Alternate-Protocol: 443:npn-spdy/2\r\n"
+ "Proxy-Connection: close\r\n"
+ "\r\n"),
+ };
+ StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1),
+ data_writes_1, arraysize(data_writes_1));
+
+ // Second round tries to tunnel to www.google.com due to the
+ // Alternate-Protocol announcement in the first round. It fails due
+ // to a proxy authentication challenge.
+ // After the failure, a tunnel is established to www.google.com using
+ // Proxy-Authorization headers. There is then a SPDY request round.
+ //
+ // NOTE: Despite the "Proxy-Connection: Close", these are done on the
+ // same MockTCPClientSocket since the underlying HttpNetworkClientSocket
+ // does a Disconnect and Connect on the same socket, rather than trying
+ // to obtain a new one.
+ //
+ // NOTE: Originally, the proxy response to the second CONNECT request
+ // simply returned another 407 so the unit test could skip the SSL connection
+ // establishment and SPDY framing issues. Alas, the
+ // retry-http-when-alternate-protocol fails logic kicks in, which was more
+ // complicated to set up expectations for than the SPDY session.
+
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
+
+ MockWrite data_writes_2[] = {
+ // First connection attempt without Proxy-Authorization.
+ 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"),
+
+ // Second connection attempt with Proxy-Authorization.
+ MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authorization: auth_token\r\n"
+ "\r\n"),
+
+ // SPDY request
+ CreateMockWrite(*req),
+ };
+ const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n"
+ "Proxy-Authenticate: Mock\r\n"
+ "Proxy-Connection: close\r\n"
+ "\r\n");
+ const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n";
+ MockRead data_reads_2[] = {
+ // First connection attempt fails
+ MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1),
+ MockRead(true, kRejectConnectResponse,
+ arraysize(kRejectConnectResponse) - 1, 1),
+
+ // Second connection attempt passes
+ MockRead(true, kAcceptConnectResponse,
+ arraysize(kAcceptConnectResponse) -1, 4),
+
+ // SPDY response
+ CreateMockRead(*resp.get(), 6),
+ CreateMockRead(*data.get(), 6),
+ MockRead(true, 0, 0, 6),
+ };
+ scoped_refptr<OrderedSocketData> data_2(
+ new OrderedSocketData(data_reads_2, arraysize(data_reads_2),
+ data_writes_2, arraysize(data_writes_2)));
+
+ SSLSocketDataProvider ssl(true, OK);
+ ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ ssl.next_proto = "spdy/2";
+ ssl.was_npn_negotiated = true;
+
+ session_deps.socket_factory.AddSocketDataProvider(&data_1);
+ session_deps.socket_factory.AddSocketDataProvider(data_2.get());
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // First round should work and provide the Alternate-Protocol state.
+ TestCompletionCallback callback_1;
+ scoped_ptr<HttpTransaction> trans_1(new HttpNetworkTransaction(session));
+ int rv = trans_1->Start(&request, &callback_1, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback_1.WaitForResult());
+
+ // Second round should attempt a tunnel connect and get an auth challenge.
+ TestCompletionCallback callback_2;
+ scoped_ptr<HttpTransaction> trans_2(new HttpNetworkTransaction(session));
+ rv = trans_2->Start(&request, &callback_2, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback_2.WaitForResult());
+ const HttpResponseInfo* response = trans_2->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+ ASSERT_FALSE(response->auth_challenge.get() == NULL);
+
+ // Restart with auth. Tunnel should work and response received.
+ TestCompletionCallback callback_3;
+ rv = trans_2->RestartWithAuth(kFoo, kBar, &callback_3);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback_3.WaitForResult());
+
+ // After all that work, these two lines (or actually, just the scheme) are
+ // what this test is all about. Make sure it happens correctly.
+ const GURL& request_url = auth_handler->request_url();
+ EXPECT_EQ("https", request_url.scheme());
+ EXPECT_EQ("www.google.com", request_url.host());
+
+ HttpStreamFactory::set_next_protos("");
+ HttpStreamFactory::set_use_alternate_protocols(false);
+}
+
+// Test that if we cancel the transaction as the connection is completing, that
+// everything tears down correctly.
+TEST_F(HttpNetworkTransactionTest, SimpleCancel) {
+ // Setup everything about the connection to complete synchronously, so that
+ // after calling HttpNetworkTransaction::Start, the only thing we're waiting
+ // for is the callback from the HttpStreamRequest.
+ // Then cancel the transaction.
+ // Verify that we don't crash.
+ MockConnect mock_connect(false, OK);
+ MockRead data_reads[] = {
+ MockRead(false, "HTTP/1.0 200 OK\r\n\r\n"),
+ MockRead(false, "hello world"),
+ MockRead(false, OK),
+ };
+
+ SessionDependencies session_deps;
+ session_deps.host_resolver->set_synchronous_mode(true);
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(CreateSession(&session_deps)));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.load_flags = 0;
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
+ data.set_connect_data(mock_connect);
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+
+ TestCompletionCallback callback;
+
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ int rv = trans->Start(&request, &callback, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ trans.reset(); // Cancel the transaction here.
+
+ MessageLoop::current()->RunAllPending();
+}
+
+// Test a basic GET request through a proxy.
+TEST_F(HttpNetworkTransactionTest, ProxyGet) {
+ SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+
+ MockWrite data_writes1[] = {
+ MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads1[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
+ MockRead("Content-Length: 100\r\n\r\n"),
+ MockRead(false, OK),
+ };
+
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
+ data_writes1, arraysize(data_writes1));
+ session_deps.socket_factory.AddSocketDataProvider(&data1);
+
+ TestCompletionCallback callback1;
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_TRUE(response->headers->IsKeepAlive());
+ EXPECT_EQ(200, response->headers->response_code());
+ EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_TRUE(response->was_fetched_via_proxy);
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+}
+
+// Test a basic HTTPS GET request through a proxy.
+TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) {
+ SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+
+ // Since we have proxy, should try to establish tunnel.
+ MockWrite data_writes1[] = {
+ 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"),
+
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads1[] = {
+ MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
+
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
+ MockRead("Content-Length: 100\r\n\r\n"),
+ MockRead(false, OK),
+ };
+
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
+ data_writes1, arraysize(data_writes1));
+ session_deps.socket_factory.AddSocketDataProvider(&data1);
+ SSLSocketDataProvider ssl(true, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ TestCompletionCallback callback1;
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ size_t pos = ExpectLogContainsSomewhere(
+ log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLog::PHASE_NONE);
+ ExpectLogContainsSomewhere(
+ log.entries(), pos,
+ NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLog::PHASE_NONE);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_TRUE(response->headers->IsKeepAlive());
+ EXPECT_EQ(200, response->headers->response_code());
+ EXPECT_EQ(100, response->headers->GetContentLength());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+ EXPECT_TRUE(response->was_fetched_via_proxy);
+}
+
+// Test a basic HTTPS GET request through a proxy, but the server hangs up
+// while establishing the tunnel.
+TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) {
+ SessionDependencies session_deps(CreateFixedProxyService("myproxy:70"));
+ CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
+ session_deps.net_log = log.bound().net_log();
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+
+ // Since we have proxy, should try to establish tunnel.
+ MockWrite data_writes1[] = {
+ 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"),
+
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads1[] = {
+ MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
+ MockRead(true, 0, 0), // EOF
+ };
+
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
+ data_writes1, arraysize(data_writes1));
+ session_deps.socket_factory.AddSocketDataProvider(&data1);
+ SSLSocketDataProvider ssl(true, OK);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ TestCompletionCallback callback1;
+
+ scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback1, log.bound());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback1.WaitForResult();
+ EXPECT_EQ(ERR_EMPTY_RESPONSE, rv);
+ size_t pos = ExpectLogContainsSomewhere(
+ log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLog::PHASE_NONE);
+ ExpectLogContainsSomewhere(
+ log.entries(), pos,
+ NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLog::PHASE_NONE);
+}
+
+// Test for crbug.com/55424.
+TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
+ SessionDependencies session_deps;
+
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(
+ "https://www.google.com", false, 1, LOWEST));
+ MockWrite spdy_writes[] = { CreateMockWrite(*req) };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true));
+ MockRead spdy_reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*data),
+ MockRead(true, 0, 0),
+ };
+
+ scoped_refptr<DelayedSocketData> spdy_data(
+ new DelayedSocketData(
+ 1, // wait for one write to finish before reading.
+ spdy_reads, arraysize(spdy_reads),
+ spdy_writes, arraysize(spdy_writes)));
+ session_deps.socket_factory.AddSocketDataProvider(spdy_data);
+
+ SSLSocketDataProvider ssl(true, OK);
+ ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ ssl.next_proto = "spdy/2";
+ ssl.was_npn_negotiated = true;
+ session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+
+ // Set up an initial SpdySession in the pool to reuse.
+ HostPortPair host_port_pair("www.google.com", 443);
+ HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
+ scoped_refptr<SpdySession> spdy_session =
+ session->spdy_session_pool()->Get(pair, session->mutable_spdy_settings(),
+ BoundNetLog());
+ scoped_refptr<TCPSocketParams> tcp_params =
+ new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false);
+ TestCompletionCallback callback;
+
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+ EXPECT_EQ(ERR_IO_PENDING,
+ connection->Init(host_port_pair.ToString(), tcp_params, LOWEST,
+ &callback, session->tcp_socket_pool(),
+ BoundNetLog()));
+ EXPECT_EQ(OK, callback.WaitForResult());
+ spdy_session->InitializeWithSocket(connection.release(), false, OK);
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ // This is the important line that marks this as a preconnect.
+ request.motivation = HttpRequestInfo::PRECONNECT_MOTIVATED;
+
+ scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
}
} // namespace net
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index ec4b753..ccc5d5d 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -5,15 +5,17 @@
#include "net/http/http_proxy_client_socket.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "googleurl/src/gurl.h"
+#include "net/base/auth.h"
#include "net/base/host_port_pair.h"
#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_request_info.h"
+#include "net/http/http_stream_parser.h"
#include "net/socket/client_socket_handle.h"
namespace net {
@@ -31,7 +33,7 @@ void BuildTunnelRequest(const HttpRequestInfo* request_info,
// RFC 2616 Section 9 says the Host request-header field MUST accompany all
// HTTP/1.1 requests. Add "Proxy-Connection: keep-alive" for compat with
// HTTP/1.0 proxies such as Squid (required for NTLM authentication).
- *request_line = StringPrintf(
+ *request_line = base::StringPrintf(
"CONNECT %s HTTP/1.1\r\n", endpoint.ToString().c_str());
request_headers->SetHeader(HttpRequestHeaders::kHost,
GetHostAndOptionalPort(request_info->url));
@@ -49,22 +51,36 @@ void BuildTunnelRequest(const HttpRequestInfo* request_info,
} // namespace
HttpProxyClientSocket::HttpProxyClientSocket(
- ClientSocketHandle* transport_socket, const GURL& request_url,
- const HostPortPair& endpoint, const scoped_refptr<HttpAuthController>& auth,
- bool tunnel)
+ ClientSocketHandle* transport_socket,
+ const GURL& request_url,
+ const std::string& user_agent,
+ const HostPortPair& endpoint,
+ const HostPortPair& proxy_server,
+ HttpAuthCache* http_auth_cache,
+ HttpAuthHandlerFactory* http_auth_handler_factory,
+ bool tunnel,
+ bool using_spdy)
: ALLOW_THIS_IN_INITIALIZER_LIST(
io_callback_(this, &HttpProxyClientSocket::OnIOComplete)),
next_state_(STATE_NONE),
user_callback_(NULL),
transport_(transport_socket),
endpoint_(endpoint),
- auth_(auth),
+ auth_(tunnel ?
+ new HttpAuthController(HttpAuth::AUTH_PROXY,
+ GURL("http://" + proxy_server.ToString()),
+ http_auth_cache,
+ http_auth_handler_factory)
+ : NULL),
tunnel_(tunnel),
+ using_spdy_(using_spdy),
net_log_(transport_socket->socket()->NetLog()) {
- DCHECK_EQ(tunnel, auth != NULL);
// Synthesize the bits of a request that we actually use.
request_.url = request_url;
request_.method = "GET";
+ if (!user_agent.empty())
+ request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
+ user_agent);
}
HttpProxyClientSocket::~HttpProxyClientSocket() {
@@ -74,10 +90,14 @@ HttpProxyClientSocket::~HttpProxyClientSocket() {
int HttpProxyClientSocket::Connect(CompletionCallback* callback) {
DCHECK(transport_.get());
DCHECK(transport_->socket());
- DCHECK(transport_->socket()->IsConnected());
DCHECK(!user_callback_);
- if (!tunnel_)
+ // TODO(rch): figure out the right way to set up a tunnel with SPDY.
+ // This approach sends the complete HTTPS request to the proxy
+ // which allows the proxy to see "private" data. Instead, we should
+ // create an SSL tunnel to the origin server using the CONNECT method
+ // inside a single SPDY stream.
+ if (using_spdy_ || !tunnel_)
next_state_ = STATE_DONE;
if (next_state_ == STATE_DONE)
return OK;
@@ -111,8 +131,8 @@ int HttpProxyClientSocket::PrepareForAuthRestart() {
bool keep_alive = false;
if (response_.headers->IsKeepAlive() &&
- http_stream_->CanFindEndOfResponse()) {
- if (!http_stream_->IsResponseBodyComplete()) {
+ http_stream_parser_->CanFindEndOfResponse()) {
+ if (!http_stream_parser_->IsResponseBodyComplete()) {
next_state_ = STATE_DRAIN_BODY;
drain_buf_ = new IOBuffer(kDrainBodyBufferSize);
return OK;
@@ -126,21 +146,23 @@ int HttpProxyClientSocket::PrepareForAuthRestart() {
}
int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) {
- int rc = OK;
if (keep_alive && transport_->socket()->IsConnectedAndIdle()) {
next_state_ = STATE_GENERATE_AUTH_TOKEN;
transport_->set_is_reused(true);
} else {
+ // This assumes that the underlying transport socket is a TCP socket,
+ // since only TCP sockets are restartable.
+ next_state_ = STATE_TCP_RESTART;
transport_->socket()->Disconnect();
- rc = ERR_RETRY_CONNECTION;
}
// Reset the other member variables.
drain_buf_ = NULL;
- http_stream_.reset();
+ parser_buf_ = NULL;
+ http_stream_parser_.reset();
request_headers_.clear();
response_ = HttpResponseInfo();
- return rc;
+ return OK;
}
void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const {
@@ -159,19 +181,40 @@ void HttpProxyClientSocket::Disconnect() {
}
bool HttpProxyClientSocket::IsConnected() const {
- return transport_->socket()->IsConnected();
+ return next_state_ == STATE_DONE && transport_->socket()->IsConnected();
}
bool HttpProxyClientSocket::IsConnectedAndIdle() const {
- return transport_->socket()->IsConnectedAndIdle();
+ return next_state_ == STATE_DONE &&
+ transport_->socket()->IsConnectedAndIdle();
}
-bool HttpProxyClientSocket::NeedsRestartWithAuth() const {
- return next_state_ != STATE_DONE;
+void HttpProxyClientSocket::SetSubresourceSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetSubresourceSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void HttpProxyClientSocket::SetOmniboxSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetOmniboxSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+bool HttpProxyClientSocket::WasEverUsed() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->WasEverUsed();
+ }
+ NOTREACHED();
+ return false;
}
int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
- CompletionCallback* callback) {
+ CompletionCallback* callback) {
DCHECK(!user_callback_);
if (next_state_ != STATE_DONE) {
// We're trying to read the body of the response but we're still trying
@@ -273,6 +316,13 @@ int HttpProxyClientSocket::DoLoop(int last_io_result) {
case STATE_DRAIN_BODY_COMPLETE:
rv = DoDrainBodyComplete(rv);
break;
+ case STATE_TCP_RESTART:
+ DCHECK_EQ(OK, rv);
+ rv = DoTCPRestart();
+ break;
+ case STATE_TCP_RESTART_COMPLETE:
+ rv = DoTCPRestartComplete(rv);
+ break;
case STATE_DONE:
break;
default:
@@ -280,8 +330,8 @@ int HttpProxyClientSocket::DoLoop(int last_io_result) {
rv = ERR_UNEXPECTED;
break;
}
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE
- && next_state_ != STATE_DONE);
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE &&
+ next_state_ != STATE_DONE);
return rv;
}
@@ -310,7 +360,7 @@ int HttpProxyClientSocket::DoSendRequest() {
HttpRequestHeaders request_headers;
BuildTunnelRequest(&request_, authorization_headers, endpoint_,
&request_line, &request_headers);
- if (net_log_.HasListener()) {
+ if (net_log_.IsLoggingAll()) {
net_log_.AddEvent(
NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
new NetLogHttpRequestParameter(
@@ -319,10 +369,12 @@ int HttpProxyClientSocket::DoSendRequest() {
request_headers_ = request_line + request_headers.ToString();
}
- http_stream_.reset(new HttpBasicStream(transport_.get(), net_log_));
- return http_stream_->SendRequest(&request_, request_headers_, NULL,
- &response_, &io_callback_);
+ parser_buf_ = new GrowableIOBuffer();
+ http_stream_parser_.reset(
+ new HttpStreamParser(transport_.get(), &request_, parser_buf_, net_log_));
+ return http_stream_parser_->SendRequest(request_headers_, NULL,
+ &response_, &io_callback_);
}
int HttpProxyClientSocket::DoSendRequestComplete(int result) {
@@ -335,7 +387,7 @@ int HttpProxyClientSocket::DoSendRequestComplete(int result) {
int HttpProxyClientSocket::DoReadHeaders() {
next_state_ = STATE_READ_HEADERS_COMPLETE;
- return http_stream_->ReadResponseHeaders(&io_callback_);
+ return http_stream_parser_->ReadResponseHeaders(&io_callback_);
}
int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
@@ -346,7 +398,7 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
if (response_.headers->GetParsedHttpVersion() < HttpVersion(1, 0))
return ERR_TUNNEL_CONNECTION_FAILED;
- if (net_log_.HasListener()) {
+ if (net_log_.IsLoggingAll()) {
net_log_.AddEvent(
NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
new NetLogHttpResponseParameter(response_.headers));
@@ -354,7 +406,7 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
switch (response_.headers->response_code()) {
case 200: // OK
- if (http_stream_->IsMoreDataBuffered())
+ if (http_stream_parser_->IsMoreDataBuffered())
// The proxy sent extraneous data after the headers.
return ERR_TUNNEL_CONNECTION_FAILED;
@@ -390,15 +442,15 @@ int HttpProxyClientSocket::DoDrainBody() {
DCHECK(drain_buf_);
DCHECK(transport_->is_initialized());
next_state_ = STATE_DRAIN_BODY_COMPLETE;
- return http_stream_->ReadResponseBody(drain_buf_, kDrainBodyBufferSize,
- &io_callback_);
+ return http_stream_parser_->ReadResponseBody(drain_buf_, kDrainBodyBufferSize,
+ &io_callback_);
}
int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
if (result < 0)
return result;
- if (http_stream_->IsResponseBodyComplete())
+ if (http_stream_parser_->IsResponseBodyComplete())
return DidDrainBodyForAuthRestart(true);
// Keep draining.
@@ -406,6 +458,19 @@ int HttpProxyClientSocket::DoDrainBodyComplete(int result) {
return OK;
}
+int HttpProxyClientSocket::DoTCPRestart() {
+ next_state_ = STATE_TCP_RESTART_COMPLETE;
+ return transport_->socket()->Connect(&io_callback_);
+}
+
+int HttpProxyClientSocket::DoTCPRestartComplete(int result) {
+ if (result != OK)
+ return result;
+
+ next_state_ = STATE_GENERATE_AUTH_TOKEN;
+ return result;
+}
+
int HttpProxyClientSocket::HandleAuthChallenge() {
DCHECK(response_.headers);
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h
index 61e8158..6530285 100644
--- a/net/http/http_proxy_client_socket.h
+++ b/net/http/http_proxy_client_socket.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_PROXY_CLIENT_SOCKET_H_
#define NET_HTTP_HTTP_PROXY_CLIENT_SOCKET_H_
+#pragma once
#include <string>
@@ -24,8 +25,12 @@ namespace net {
class AddressList;
class ClientSocketHandle;
+class GrowableIOBuffer;
+class HttpAuthCache;
+class HttpAuthHandleFactory;
class HttpStream;
-class IOBuffer;;
+class HttpStreamParser;
+class IOBuffer;
class HttpProxyClientSocket : public ClientSocket {
public:
@@ -33,9 +38,14 @@ class HttpProxyClientSocket : public ClientSocket {
// by the time Connect() is called. If tunnel is true then on Connect()
// this socket will establish an Http tunnel.
HttpProxyClientSocket(ClientSocketHandle* transport_socket,
- const GURL& request_url, const HostPortPair& endpoint,
- const scoped_refptr<HttpAuthController>& auth,
- bool tunnel);
+ const GURL& request_url,
+ const std::string& user_agent,
+ const HostPortPair& endpoint,
+ const HostPortPair& proxy_server,
+ HttpAuthCache* http_auth_cache,
+ HttpAuthHandlerFactory* http_auth_handler_factory,
+ bool tunnel,
+ bool using_spdy);
// On destruction Disconnect() is called.
virtual ~HttpProxyClientSocket();
@@ -45,12 +55,16 @@ class HttpProxyClientSocket : public ClientSocket {
// RestartWithAuth.
int RestartWithAuth(CompletionCallback* callback);
- // Indicates if RestartWithAuth needs to be called. i.e. if Connect
- // returned PROXY_AUTH_REQUESTED. Only valid after Connect has been called.
- bool NeedsRestartWithAuth() const;
-
const HttpResponseInfo* GetResponseInfo() const {
- return response_.headers ? &response_ : NULL;
+ return response_.headers ? &response_ : NULL;
+ }
+
+ const scoped_refptr<HttpAuthController>& auth_controller() {
+ return auth_;
+ }
+
+ bool using_spdy() {
+ return using_spdy_;
}
// ClientSocket methods:
@@ -61,6 +75,9 @@ class HttpProxyClientSocket : public ClientSocket {
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
@@ -80,17 +97,17 @@ class HttpProxyClientSocket : public ClientSocket {
STATE_SEND_REQUEST_COMPLETE,
STATE_READ_HEADERS,
STATE_READ_HEADERS_COMPLETE,
- STATE_RESOLVE_CANONICAL_NAME,
- STATE_RESOLVE_CANONICAL_NAME_COMPLETE,
STATE_DRAIN_BODY,
STATE_DRAIN_BODY_COMPLETE,
+ STATE_TCP_RESTART,
+ STATE_TCP_RESTART_COMPLETE,
STATE_DONE,
};
// The size in bytes of the buffer we use to drain the response body that
// we want to throw away. The response body is typically a small error
// page just a few hundred bytes long.
- enum { kDrainBodyBufferSize = 1024 };
+ static const int kDrainBodyBufferSize = 1024;
int PrepareForAuthRestart();
int DidDrainBodyForAuthRestart(bool keep_alive);
@@ -111,6 +128,8 @@ class HttpProxyClientSocket : public ClientSocket {
int DoReadHeadersComplete(int result);
int DoDrainBody();
int DoDrainBodyComplete(int result);
+ int DoTCPRestart();
+ int DoTCPRestartComplete(int result);
CompletionCallbackImpl<HttpProxyClientSocket> io_callback_;
State next_state_;
@@ -121,7 +140,8 @@ class HttpProxyClientSocket : public ClientSocket {
HttpRequestInfo request_;
HttpResponseInfo response_;
- scoped_ptr<HttpStream> http_stream_;
+ scoped_refptr<GrowableIOBuffer> parser_buf_;
+ scoped_ptr<HttpStreamParser> http_stream_parser_;
scoped_refptr<IOBuffer> drain_buf_;
// Stores the underlying socket.
@@ -132,6 +152,8 @@ class HttpProxyClientSocket : public ClientSocket {
const HostPortPair endpoint_;
scoped_refptr<HttpAuthController> auth_;
const bool tunnel_;
+ // If true, then the connection to the proxy is a SPDY connection.
+ const bool using_spdy_;
std::string request_headers_;
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc
index a142576..fa49944 100644
--- a/net/http/http_proxy_client_socket_pool.cc
+++ b/net/http/http_proxy_client_socket_pool.cc
@@ -4,27 +4,50 @@
#include "net/http/http_proxy_client_socket_pool.h"
+#include <algorithm>
+
#include "base/time.h"
+#include "base/values.h"
#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
+#include "net/http/http_network_session.h"
#include "net/http/http_proxy_client_socket.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_base.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/tcp_client_socket_pool.h"
namespace net {
HttpProxySocketParams::HttpProxySocketParams(
- const scoped_refptr<TCPSocketParams>& proxy_server,
+ const scoped_refptr<TCPSocketParams>& tcp_params,
+ const scoped_refptr<SSLSocketParams>& ssl_params,
const GURL& request_url,
+ const std::string& user_agent,
HostPortPair endpoint,
- scoped_refptr<HttpAuthController> auth_controller,
+ HttpAuthCache* http_auth_cache,
+ HttpAuthHandlerFactory* http_auth_handler_factory,
bool tunnel)
- : tcp_params_(proxy_server),
+ : tcp_params_(tcp_params),
+ ssl_params_(ssl_params),
request_url_(request_url),
+ user_agent_(user_agent),
endpoint_(endpoint),
- auth_controller_(auth_controller),
+ http_auth_cache_(tunnel ? http_auth_cache : NULL),
+ http_auth_handler_factory_(tunnel ? http_auth_handler_factory : NULL),
tunnel_(tunnel) {
+ DCHECK((tcp_params == NULL && ssl_params != NULL) ||
+ (tcp_params != NULL && ssl_params == NULL));
+}
+
+const HostResolver::RequestInfo& HttpProxySocketParams::destination() const {
+ if (tcp_params_ == NULL)
+ return ssl_params_->tcp_params()->destination();
+ else
+ return tcp_params_->destination();
}
HttpProxySocketParams::~HttpProxySocketParams() {}
@@ -37,7 +60,8 @@ HttpProxyConnectJob::HttpProxyConnectJob(
const std::string& group_name,
const scoped_refptr<HttpProxySocketParams>& params,
const base::TimeDelta& timeout_duration,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
+ SSLClientSocketPool* ssl_pool,
const scoped_refptr<HostResolver>& host_resolver,
Delegate* delegate,
NetLog* net_log)
@@ -45,20 +69,24 @@ HttpProxyConnectJob::HttpProxyConnectJob(
BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
params_(params),
tcp_pool_(tcp_pool),
+ ssl_pool_(ssl_pool),
resolver_(host_resolver),
ALLOW_THIS_IN_INITIALIZER_LIST(
- callback_(this, &HttpProxyConnectJob::OnIOComplete)) {
+ callback_(this, &HttpProxyConnectJob::OnIOComplete)),
+ using_spdy_(false) {
}
HttpProxyConnectJob::~HttpProxyConnectJob() {}
LoadState HttpProxyConnectJob::GetLoadState() const {
switch (next_state_) {
- case kStateTCPConnect:
- case kStateTCPConnectComplete:
- return tcp_socket_handle_->GetLoadState();
- case kStateHttpProxyConnect:
- case kStateHttpProxyConnectComplete:
+ case STATE_TCP_CONNECT:
+ case STATE_TCP_CONNECT_COMPLETE:
+ case STATE_SSL_CONNECT:
+ case STATE_SSL_CONNECT_COMPLETE:
+ return transport_socket_handle_->GetLoadState();
+ case STATE_HTTP_PROXY_CONNECT:
+ case STATE_HTTP_PROXY_CONNECT_COMPLETE:
return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL;
default:
NOTREACHED();
@@ -67,7 +95,10 @@ LoadState HttpProxyConnectJob::GetLoadState() const {
}
int HttpProxyConnectJob::ConnectInternal() {
- next_state_ = kStateTCPConnect;
+ if (params_->tcp_params())
+ next_state_ = STATE_TCP_CONNECT;
+ else
+ next_state_ = STATE_SSL_CONNECT;
return DoLoop(OK);
}
@@ -78,25 +109,32 @@ void HttpProxyConnectJob::OnIOComplete(int result) {
}
int HttpProxyConnectJob::DoLoop(int result) {
- DCHECK_NE(next_state_, kStateNone);
+ DCHECK_NE(next_state_, STATE_NONE);
int rv = result;
do {
State state = next_state_;
- next_state_ = kStateNone;
+ next_state_ = STATE_NONE;
switch (state) {
- case kStateTCPConnect:
+ case STATE_TCP_CONNECT:
DCHECK_EQ(OK, rv);
rv = DoTCPConnect();
break;
- case kStateTCPConnectComplete:
+ case STATE_TCP_CONNECT_COMPLETE:
rv = DoTCPConnectComplete(rv);
break;
- case kStateHttpProxyConnect:
+ case STATE_SSL_CONNECT:
+ DCHECK_EQ(OK, rv);
+ rv = DoSSLConnect();
+ break;
+ case STATE_SSL_CONNECT_COMPLETE:
+ rv = DoSSLConnectComplete(rv);
+ break;
+ case STATE_HTTP_PROXY_CONNECT:
DCHECK_EQ(OK, rv);
rv = DoHttpProxyConnect();
break;
- case kStateHttpProxyConnectComplete:
+ case STATE_HTTP_PROXY_CONNECT_COMPLETE:
rv = DoHttpProxyConnectComplete(rv);
break;
default:
@@ -104,15 +142,15 @@ int HttpProxyConnectJob::DoLoop(int result) {
rv = ERR_FAILED;
break;
}
- } while (rv != ERR_IO_PENDING && next_state_ != kStateNone);
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
return rv;
}
int HttpProxyConnectJob::DoTCPConnect() {
- next_state_ = kStateTCPConnectComplete;
- tcp_socket_handle_.reset(new ClientSocketHandle());
- return tcp_socket_handle_->Init(
+ next_state_ = STATE_TCP_CONNECT_COMPLETE;
+ transport_socket_handle_.reset(new ClientSocketHandle());
+ return transport_socket_handle_->Init(
group_name(), params_->tcp_params(),
params_->tcp_params()->destination().priority(), &callback_, tcp_pool_,
net_log());
@@ -120,67 +158,131 @@ int HttpProxyConnectJob::DoTCPConnect() {
int HttpProxyConnectJob::DoTCPConnectComplete(int result) {
if (result != OK)
- return result;
+ return ERR_PROXY_CONNECTION_FAILED;
// Reset the timer to just the length of time allowed for HttpProxy handshake
// so that a fast TCP connection plus a slow HttpProxy failure doesn't take
// longer to timeout than it should.
ResetTimer(base::TimeDelta::FromSeconds(
kHttpProxyConnectJobTimeoutInSeconds));
- next_state_ = kStateHttpProxyConnect;
+ next_state_ = STATE_HTTP_PROXY_CONNECT;
+ return result;
+}
+
+int HttpProxyConnectJob::DoSSLConnect() {
+ next_state_ = STATE_SSL_CONNECT_COMPLETE;
+ transport_socket_handle_.reset(new ClientSocketHandle());
+ return transport_socket_handle_->Init(
+ group_name(), params_->ssl_params(),
+ params_->ssl_params()->tcp_params()->destination().priority(),
+ &callback_, ssl_pool_, net_log());
+}
+
+int HttpProxyConnectJob::DoSSLConnectComplete(int result) {
+ if (IsCertificateError(result) &&
+ params_->ssl_params()->load_flags() & LOAD_IGNORE_ALL_CERT_ERRORS)
+ result = OK;
+ if (result < 0) {
+ // TODO(eroman): return ERR_PROXY_CONNECTION_FAILED if failed with the
+ // TCP connection.
+ if (transport_socket_handle_->socket())
+ transport_socket_handle_->socket()->Disconnect();
+ return result;
+ }
+
+ SSLClientSocket* ssl =
+ static_cast<SSLClientSocket*>(transport_socket_handle_->socket());
+ using_spdy_ = ssl->was_spdy_negotiated();
+
+ // Reset the timer to just the length of time allowed for HttpProxy handshake
+ // so that a fast SSL connection plus a slow HttpProxy failure doesn't take
+ // longer to timeout than it should.
+ ResetTimer(base::TimeDelta::FromSeconds(
+ kHttpProxyConnectJobTimeoutInSeconds));
+ next_state_ = STATE_HTTP_PROXY_CONNECT;
return result;
}
int HttpProxyConnectJob::DoHttpProxyConnect() {
- next_state_ = kStateHttpProxyConnectComplete;
+ next_state_ = STATE_HTTP_PROXY_CONNECT_COMPLETE;
+ const HostResolver::RequestInfo& tcp_destination = params_->destination();
+ const HostPortPair& proxy_server = tcp_destination.host_port_pair();
// Add a HttpProxy connection on top of the tcp socket.
- socket_.reset(new HttpProxyClientSocket(tcp_socket_handle_.release(),
- params_->request_url(),
- params_->endpoint(),
- params_->auth_controller(),
- params_->tunnel()));
- return socket_->Connect(&callback_);
+ transport_socket_.reset(
+ new HttpProxyClientSocket(transport_socket_handle_.release(),
+ params_->request_url(),
+ params_->user_agent(),
+ params_->endpoint(),
+ proxy_server,
+ params_->http_auth_cache(),
+ params_->http_auth_handler_factory(),
+ params_->tunnel(),
+ using_spdy_));
+ int result = transport_socket_->Connect(&callback_);
+
+ // Clear the circular reference to HttpNetworkSession (|params_| reference
+ // HttpNetworkSession, which reference HttpProxyClientSocketPool, which
+ // references |this|) here because it is safe to do so now but not at other
+ // points. This may cancel this ConnectJob.
+ params_ = NULL;
+ return result;
}
int HttpProxyConnectJob::DoHttpProxyConnectComplete(int result) {
- DCHECK_NE(result, ERR_RETRY_CONNECTION);
-
if (result == OK || result == ERR_PROXY_AUTH_REQUESTED)
- set_socket(socket_.release());
+ set_socket(transport_socket_.release());
return result;
}
+HttpProxyClientSocketPool::
+HttpProxyConnectJobFactory::HttpProxyConnectJobFactory(
+ TCPClientSocketPool* tcp_pool,
+ SSLClientSocketPool* ssl_pool,
+ HostResolver* host_resolver,
+ NetLog* net_log)
+ : tcp_pool_(tcp_pool),
+ ssl_pool_(ssl_pool),
+ host_resolver_(host_resolver),
+ net_log_(net_log) {
+ base::TimeDelta max_pool_timeout = base::TimeDelta();
+ if (tcp_pool_)
+ max_pool_timeout = tcp_pool_->ConnectionTimeout();
+ if (ssl_pool_)
+ max_pool_timeout = std::max(max_pool_timeout,
+ ssl_pool_->ConnectionTimeout());
+ timeout_ = max_pool_timeout +
+ base::TimeDelta::FromSeconds(kHttpProxyConnectJobTimeoutInSeconds);
+}
+
+
ConnectJob*
HttpProxyClientSocketPool::HttpProxyConnectJobFactory::NewConnectJob(
const std::string& group_name,
const PoolBase::Request& request,
ConnectJob::Delegate* delegate) const {
return new HttpProxyConnectJob(group_name, request.params(),
- ConnectionTimeout(), tcp_pool_, host_resolver_,
- delegate, net_log_);
-}
-
-base::TimeDelta
-HttpProxyClientSocketPool::HttpProxyConnectJobFactory::ConnectionTimeout()
-const {
- return tcp_pool_->ConnectionTimeout() +
- base::TimeDelta::FromSeconds(kHttpProxyConnectJobTimeoutInSeconds);
+ ConnectionTimeout(), tcp_pool_, ssl_pool_,
+ host_resolver_, delegate, net_log_);
}
HttpProxyClientSocketPool::HttpProxyClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
const scoped_refptr<HostResolver>& host_resolver,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
+ SSLClientSocketPool* ssl_pool,
NetLog* net_log)
- : base_(max_sockets, max_sockets_per_group, histograms,
+ : tcp_pool_(tcp_pool),
+ ssl_pool_(ssl_pool),
+ base_(max_sockets, max_sockets_per_group, histograms,
base::TimeDelta::FromSeconds(
ClientSocketPool::unused_idle_socket_timeout()),
base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
- new HttpProxyConnectJobFactory(tcp_pool, host_resolver, net_log)) {}
+ new HttpProxyConnectJobFactory(tcp_pool, ssl_pool, host_resolver,
+ net_log)) {}
HttpProxyClientSocketPool::~HttpProxyClientSocketPool() {}
@@ -226,4 +328,26 @@ LoadState HttpProxyClientSocketPool::GetLoadState(
return base_.GetLoadState(group_name, handle);
}
+DictionaryValue* HttpProxyClientSocketPool::GetInfoAsValue(
+ const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const {
+ DictionaryValue* dict = base_.GetInfoAsValue(name, type);
+ if (include_nested_pools) {
+ ListValue* list = new ListValue();
+ if (tcp_pool_) {
+ list->Append(tcp_pool_->GetInfoAsValue("tcp_socket_pool",
+ "tcp_socket_pool",
+ true));
+ }
+ if (ssl_pool_) {
+ list->Append(ssl_pool_->GetInfoAsValue("ssl_socket_pool",
+ "ssl_socket_pool",
+ true));
+ }
+ dict->Set("nested_pools", list);
+ }
+ return dict;
+}
+
} // namespace net
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h
index afe7d19..ea3c51f 100644
--- a/net/http/http_proxy_client_socket_pool.h
+++ b/net/http/http_proxy_client_socket_pool.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_PROXY_CLIENT_SOCKET_POOL_H_
#define NET_HTTP_HTTP_PROXY_CLIENT_SOCKET_POOL_H_
+#pragma once
#include <string>
@@ -12,35 +13,50 @@
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "net/base/host_port_pair.h"
-#include "net/base/host_resolver.h"
#include "net/http/http_auth.h"
-#include "net/proxy/proxy_server.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/client_socket_pool_histograms.h"
#include "net/socket/client_socket_pool.h"
-#include "net/socket/tcp_client_socket_pool.h"
namespace net {
-class ClientSocketFactory;
-class ConnectJobFactory;
-class HttpAuthController;
-
+class HostResolver;
+class HttpAuthCache;
+class HttpAuthHandlerFactory;
+class SSLClientSocketPool;
+class SSLSocketParams;
+class TCPClientSocketPool;
+class TCPSocketParams;
+
+// HttpProxySocketParams only needs the socket params for one of the proxy
+// types. The other param must be NULL. When using an HTTP Proxy,
+// |tcp_params| must be set. When using an HTTPS Proxy, |ssl_params|
+// must be set.
class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> {
public:
- HttpProxySocketParams(const scoped_refptr<TCPSocketParams>& proxy_server,
- const GURL& request_url, HostPortPair endpoint,
- scoped_refptr<HttpAuthController> auth_controller,
+ HttpProxySocketParams(const scoped_refptr<TCPSocketParams>& tcp_params,
+ const scoped_refptr<SSLSocketParams>& ssl_params,
+ const GURL& request_url,
+ const std::string& user_agent,
+ HostPortPair endpoint,
+ HttpAuthCache* http_auth_cache,
+ HttpAuthHandlerFactory* http_auth_handler_factory,
bool tunnel);
const scoped_refptr<TCPSocketParams>& tcp_params() const {
return tcp_params_;
}
+ const scoped_refptr<SSLSocketParams>& ssl_params() const {
+ return ssl_params_;
+ }
const GURL& request_url() const { return request_url_; }
+ const std::string& user_agent() const { return user_agent_; }
const HostPortPair& endpoint() const { return endpoint_; }
- const scoped_refptr<HttpAuthController>& auth_controller() {
- return auth_controller_;
+ HttpAuthCache* http_auth_cache() const { return http_auth_cache_; }
+ HttpAuthHandlerFactory* http_auth_handler_factory() const {
+ return http_auth_handler_factory_;
}
+ const HostResolver::RequestInfo& destination() const;
bool tunnel() const { return tunnel_; }
private:
@@ -48,9 +64,12 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> {
~HttpProxySocketParams();
const scoped_refptr<TCPSocketParams> tcp_params_;
+ const scoped_refptr<SSLSocketParams> ssl_params_;
const GURL request_url_;
+ const std::string user_agent_;
const HostPortPair endpoint_;
- const scoped_refptr<HttpAuthController> auth_controller_;
+ HttpAuthCache* const http_auth_cache_;
+ HttpAuthHandlerFactory* const http_auth_handler_factory_;
const bool tunnel_;
DISALLOW_COPY_AND_ASSIGN(HttpProxySocketParams);
@@ -63,7 +82,8 @@ class HttpProxyConnectJob : public ConnectJob {
HttpProxyConnectJob(const std::string& group_name,
const scoped_refptr<HttpProxySocketParams>& params,
const base::TimeDelta& timeout_duration,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
+ SSLClientSocketPool* ssl_pool,
const scoped_refptr<HostResolver> &host_resolver,
Delegate* delegate,
NetLog* net_log);
@@ -74,11 +94,13 @@ class HttpProxyConnectJob : public ConnectJob {
private:
enum State {
- kStateTCPConnect,
- kStateTCPConnectComplete,
- kStateHttpProxyConnect,
- kStateHttpProxyConnectComplete,
- kStateNone,
+ STATE_TCP_CONNECT,
+ STATE_TCP_CONNECT_COMPLETE,
+ STATE_SSL_CONNECT,
+ STATE_SSL_CONNECT_COMPLETE,
+ STATE_HTTP_PROXY_CONNECT,
+ STATE_HTTP_PROXY_CONNECT_COMPLETE,
+ STATE_NONE,
};
// Begins the tcp connection and the optional Http proxy tunnel. If the
@@ -95,19 +117,26 @@ class HttpProxyConnectJob : public ConnectJob {
// Runs the state transition loop.
int DoLoop(int result);
+ // Connecting to HTTP Proxy
int DoTCPConnect();
int DoTCPConnectComplete(int result);
+ // Connecting to HTTPS Proxy
+ int DoSSLConnect();
+ int DoSSLConnectComplete(int result);
+
int DoHttpProxyConnect();
int DoHttpProxyConnectComplete(int result);
scoped_refptr<HttpProxySocketParams> params_;
- const scoped_refptr<TCPClientSocketPool> tcp_pool_;
+ TCPClientSocketPool* const tcp_pool_;
+ SSLClientSocketPool* const ssl_pool_;
const scoped_refptr<HostResolver> resolver_;
State next_state_;
CompletionCallbackImpl<HttpProxyConnectJob> callback_;
- scoped_ptr<ClientSocketHandle> tcp_socket_handle_;
- scoped_ptr<ClientSocket> socket_;
+ scoped_ptr<ClientSocketHandle> transport_socket_handle_;
+ scoped_ptr<ClientSocket> transport_socket_;
+ bool using_spdy_;
DISALLOW_COPY_AND_ASSIGN(HttpProxyConnectJob);
};
@@ -117,11 +146,14 @@ class HttpProxyClientSocketPool : public ClientSocketPool {
HttpProxyClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
const scoped_refptr<HostResolver>& host_resolver,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
+ SSLClientSocketPool* ssl_pool,
NetLog* net_log);
+ virtual ~HttpProxyClientSocketPool();
+
// ClientSocketPool methods:
virtual int RequestSocket(const std::string& group_name,
const void* connect_params,
@@ -150,47 +182,48 @@ class HttpProxyClientSocketPool : public ClientSocketPool {
virtual LoadState GetLoadState(const std::string& group_name,
const ClientSocketHandle* handle) const;
+ virtual DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const;
+
virtual base::TimeDelta ConnectionTimeout() const {
return base_.ConnectionTimeout();
}
- virtual scoped_refptr<ClientSocketPoolHistograms> histograms() const {
+ virtual ClientSocketPoolHistograms* histograms() const {
return base_.histograms();
};
- protected:
- virtual ~HttpProxyClientSocketPool();
-
private:
typedef ClientSocketPoolBase<HttpProxySocketParams> PoolBase;
class HttpProxyConnectJobFactory : public PoolBase::ConnectJobFactory {
public:
HttpProxyConnectJobFactory(
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
+ SSLClientSocketPool* ssl_pool,
HostResolver* host_resolver,
- NetLog* net_log)
- : tcp_pool_(tcp_pool),
- host_resolver_(host_resolver),
- net_log_(net_log) {}
-
- virtual ~HttpProxyConnectJobFactory() {}
+ NetLog* net_log);
// ClientSocketPoolBase::ConnectJobFactory methods.
virtual ConnectJob* NewConnectJob(const std::string& group_name,
const PoolBase::Request& request,
ConnectJob::Delegate* delegate) const;
- virtual base::TimeDelta ConnectionTimeout() const;
+ virtual base::TimeDelta ConnectionTimeout() const { return timeout_; }
private:
- const scoped_refptr<TCPClientSocketPool> tcp_pool_;
+ TCPClientSocketPool* const tcp_pool_;
+ SSLClientSocketPool* const ssl_pool_;
const scoped_refptr<HostResolver> host_resolver_;
NetLog* net_log_;
+ base::TimeDelta timeout_;
DISALLOW_COPY_AND_ASSIGN(HttpProxyConnectJobFactory);
};
+ TCPClientSocketPool* const tcp_pool_;
+ SSLClientSocketPool* const ssl_pool_;
PoolBase base_;
DISALLOW_COPY_AND_ASSIGN(HttpProxyClientSocketPool);
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 9400dd8..4a68d9b 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -6,12 +6,20 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
+#include "net/base/ssl_config_service_defaults.h"
#include "net/base/test_completion_callback.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_network_session.h"
#include "net/http/http_proxy_client_socket.h"
+#include "net/proxy/proxy_service.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_histograms.h"
#include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_session_pool.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -21,61 +29,139 @@ namespace {
const int kMaxSockets = 32;
const int kMaxSocketsPerGroup = 6;
-class HttpProxyClientSocketPoolTest : public ClientSocketPoolTest {
+enum HttpProxyType {
+ HTTP,
+ HTTPS
+};
+
+typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
+
+class HttpProxyClientSocketPoolTest : public TestWithHttpParam {
protected:
HttpProxyClientSocketPoolTest()
- : ignored_tcp_socket_params_(new TCPSocketParams(
+ : ssl_config_(),
+ ignored_tcp_socket_params_(new TCPSocketParams(
HostPortPair("proxy", 80), MEDIUM, GURL(), false)),
- tcp_histograms_(new ClientSocketPoolHistograms("MockTCP")),
- tcp_socket_pool_(new MockTCPClientSocketPool(kMaxSockets,
- kMaxSocketsPerGroup, tcp_histograms_, &tcp_client_socket_factory_)),
- notunnel_socket_params_(new HttpProxySocketParams(
- ignored_tcp_socket_params_, GURL("http://host"),
- HostPortPair("host", 80), NULL, false)),
- auth_controller_(new MockHttpAuthController),
- tunnel_socket_params_(new HttpProxySocketParams(
- ignored_tcp_socket_params_, GURL("http://host"),
- HostPortPair("host", 80), auth_controller_, true)),
- http_proxy_histograms_(
- new ClientSocketPoolHistograms("HttpProxyUnitTest")),
- pool_(new HttpProxyClientSocketPool(kMaxSockets, kMaxSocketsPerGroup,
- http_proxy_histograms_, NULL, tcp_socket_pool_, NULL)) {
+ ignored_ssl_socket_params_(new SSLSocketParams(
+ ignored_tcp_socket_params_, NULL, NULL, ProxyServer::SCHEME_DIRECT,
+ "host", ssl_config_, 0, false, false)),
+ tcp_histograms_("MockTCP"),
+ tcp_socket_pool_(
+ kMaxSockets, kMaxSocketsPerGroup,
+ &tcp_histograms_,
+ &tcp_client_socket_factory_),
+ ssl_histograms_("MockSSL"),
+ ssl_socket_pool_(kMaxSockets, kMaxSocketsPerGroup,
+ &ssl_histograms_,
+ &tcp_client_socket_factory_,
+ &tcp_socket_pool_),
+ host_resolver_(new MockHostResolver),
+ http_auth_handler_factory_(
+ HttpAuthHandlerFactory::CreateDefault(host_resolver_)),
+ session_(new HttpNetworkSession(host_resolver_,
+ ProxyService::CreateDirect(),
+ &socket_factory_,
+ new SSLConfigServiceDefaults,
+ new SpdySessionPool(NULL),
+ http_auth_handler_factory_.get(),
+ NULL,
+ NULL)),
+ http_proxy_histograms_("HttpProxyUnitTest"),
+ pool_(kMaxSockets, kMaxSocketsPerGroup,
+ &http_proxy_histograms_,
+ NULL,
+ &tcp_socket_pool_,
+ &ssl_socket_pool_,
+ NULL) {
+ }
+
+ virtual ~HttpProxyClientSocketPoolTest() {
+ }
+
+ void AddAuthToCache() {
+ const string16 kFoo(ASCIIToUTF16("foo"));
+ const string16 kBar(ASCIIToUTF16("bar"));
+ session_->auth_cache()->Add(GURL("http://proxy/"), "MyRealm1", "Basic",
+ "Basic realm=MyRealm1", kFoo, kBar, "/");
+ }
+
+ scoped_refptr<TCPSocketParams> GetTcpParams() {
+ if (GetParam() == HTTPS)
+ return scoped_refptr<TCPSocketParams>();
+ return ignored_tcp_socket_params_;
+ }
+
+ scoped_refptr<SSLSocketParams> GetSslParams() {
+ if (GetParam() == HTTP)
+ return scoped_refptr<SSLSocketParams>();
+ return ignored_ssl_socket_params_;
+ }
+
+ // Returns the a correctly constructed HttpProxyParms
+ // for the HTTP or HTTPS proxy.
+ scoped_refptr<HttpProxySocketParams> GetParams(bool tunnel) {
+ return scoped_refptr<HttpProxySocketParams>(
+ new HttpProxySocketParams(
+ GetTcpParams(),
+ GetSslParams(),
+ GURL("http://host/"),
+ "",
+ HostPortPair("host", 80),
+ session_->auth_cache(),
+ session_->http_auth_handler_factory(),
+ tunnel));
}
- int StartRequest(const std::string& group_name, RequestPriority priority) {
- return StartRequestUsingPool(
- pool_, group_name, priority, tunnel_socket_params_);
+ scoped_refptr<HttpProxySocketParams> GetTunnelParams() {
+ return GetParams(true);
}
+ scoped_refptr<HttpProxySocketParams> GetNoTunnelParams() {
+ return GetParams(false);
+ }
+
+ SSLConfig ssl_config_;
+
scoped_refptr<TCPSocketParams> ignored_tcp_socket_params_;
- scoped_refptr<ClientSocketPoolHistograms> tcp_histograms_;
+ scoped_refptr<SSLSocketParams> ignored_ssl_socket_params_;
+ ClientSocketPoolHistograms tcp_histograms_;
MockClientSocketFactory tcp_client_socket_factory_;
- scoped_refptr<MockTCPClientSocketPool> tcp_socket_pool_;
-
- scoped_refptr<HttpProxySocketParams> notunnel_socket_params_;
- scoped_refptr<MockHttpAuthController> auth_controller_;
- scoped_refptr<HttpProxySocketParams> tunnel_socket_params_;
- scoped_refptr<ClientSocketPoolHistograms> http_proxy_histograms_;
- scoped_refptr<HttpProxyClientSocketPool> pool_;
+ MockTCPClientSocketPool tcp_socket_pool_;
+ ClientSocketPoolHistograms ssl_histograms_;
+ MockSSLClientSocketPool ssl_socket_pool_;
+
+ MockClientSocketFactory socket_factory_;
+ scoped_refptr<HostResolver> host_resolver_;
+ scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_;
+ scoped_refptr<HttpNetworkSession> session_;
+ ClientSocketPoolHistograms http_proxy_histograms_;
+ HttpProxyClientSocketPool pool_;
};
-TEST_F(HttpProxyClientSocketPoolTest, NoTunnel) {
+//-----------------------------------------------------------------------------
+// All tests are run with three different connection types: SPDY after NPN
+// negotiation, SPDY without SSL, and SPDY with SSL.
+INSTANTIATE_TEST_CASE_P(HttpProxyClientSocketPoolTests,
+ HttpProxyClientSocketPoolTest,
+ ::testing::Values(HTTP, HTTPS));
+
+TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(false, 0));
tcp_client_socket_factory_.AddSocketDataProvider(&data);
ClientSocketHandle handle;
- int rv = handle.Init("a", notunnel_socket_params_, LOW, NULL, pool_,
+ int rv = handle.Init("a", GetNoTunnelParams(), LOW, NULL, &pool_,
BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
HttpProxyClientSocket* tunnel_socket =
static_cast<HttpProxyClientSocket*>(handle.socket());
- EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth());
+ EXPECT_TRUE(tunnel_socket->IsConnected());
}
-TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) {
+TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
MockWrite writes[] = {
MockWrite("CONNECT host:80 HTTP/1.1\r\n"
"Host: host\r\n"
@@ -92,14 +178,10 @@ TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) {
arraysize(writes));
tcp_client_socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData(""),
- };
- auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data));
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", tunnel_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
@@ -110,16 +192,16 @@ TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) {
EXPECT_TRUE(handle.socket());
HttpProxyClientSocket* tunnel_socket =
static_cast<HttpProxyClientSocket*>(handle.socket());
- EXPECT_TRUE(tunnel_socket->NeedsRestartWithAuth());
+ EXPECT_FALSE(tunnel_socket->IsConnected());
}
-TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) {
+TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
MockWrite writes[] = {
MockWrite(false,
"CONNECT host:80 HTTP/1.1\r\n"
"Host: host\r\n"
"Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
MockRead reads[] = {
MockRead(false, "HTTP/1.1 200 Connection Established\r\n\r\n"),
@@ -129,29 +211,26 @@ TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) {
data.set_connect_data(MockConnect(false, 0));
tcp_client_socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
- auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data));
+ AddAuthToCache();
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", tunnel_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
HttpProxyClientSocket* tunnel_socket =
static_cast<HttpProxyClientSocket*>(handle.socket());
- EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth());
+ EXPECT_TRUE(tunnel_socket->IsConnected());
}
-TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
+TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
MockWrite writes[] = {
MockWrite("CONNECT host:80 HTTP/1.1\r\n"
"Host: host\r\n"
"Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
MockRead reads[] = {
MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
@@ -160,14 +239,11 @@ TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
arraysize(writes));
tcp_client_socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
- auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data));
+ AddAuthToCache();
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", tunnel_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
@@ -178,10 +254,10 @@ TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
EXPECT_TRUE(handle.socket());
HttpProxyClientSocket* tunnel_socket =
static_cast<HttpProxyClientSocket*>(handle.socket());
- EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth());
+ EXPECT_TRUE(tunnel_socket->IsConnected());
}
-TEST_F(HttpProxyClientSocketPoolTest, TCPError) {
+TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(true, ERR_CONNECTION_CLOSED));
@@ -189,23 +265,27 @@ TEST_F(HttpProxyClientSocketPoolTest, TCPError) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", tunnel_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
+ if (GetParam() == HTTP)
+ EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult());
+ else
+ EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
+
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
}
-TEST_F(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
+TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
MockWrite writes[] = {
MockWrite("CONNECT host:80 HTTP/1.1\r\n"
"Host: host\r\n"
"Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
MockRead reads[] = {
MockRead("HTTP/1.1 200 Conn"),
@@ -215,14 +295,11 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
arraysize(writes));
tcp_client_socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
- auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data));
+ AddAuthToCache();
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", tunnel_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
@@ -233,12 +310,12 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
EXPECT_FALSE(handle.socket());
}
-TEST_F(HttpProxyClientSocketPoolTest, TunnelSetupError) {
+TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
MockWrite writes[] = {
MockWrite("CONNECT host:80 HTTP/1.1\r\n"
"Host: host\r\n"
"Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
MockRead reads[] = {
MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"),
@@ -247,14 +324,11 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelSetupError) {
arraysize(writes));
tcp_client_socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
- auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data));
+ AddAuthToCache();
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", tunnel_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", GetTunnelParams(), LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
diff --git a/net/http/http_request_headers.cc b/net/http/http_request_headers.cc
index 29379c1..9f2eb90 100644
--- a/net/http/http_request_headers.cc
+++ b/net/http/http_request_headers.cc
@@ -5,6 +5,7 @@
#include "net/http/http_request_headers.h"
#include "base/logging.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "net/http/http_util.h"
@@ -30,6 +31,15 @@ const char HttpRequestHeaders::kRange[] = "Range";
const char HttpRequestHeaders::kReferer[] = "Referer";
const char HttpRequestHeaders::kUserAgent[] = "User-Agent";
+HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair() {
+}
+
+HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair(
+ const base::StringPiece& key, const base::StringPiece& value)
+ : key(key.data(), key.size()), value(value.data(), value.size()) {
+}
+
+
HttpRequestHeaders::Iterator::Iterator(const HttpRequestHeaders& headers)
: started_(false),
curr_(headers.headers_.begin()),
@@ -130,7 +140,8 @@ void HttpRequestHeaders::AddHeadersFromString(
// TODO(willchan): Consider adding more StringPiece support in string_util.h
// to eliminate copies.
std::vector<std::string> header_line_vector;
- SplitStringUsingSubstr(headers.as_string(), "\r\n", &header_line_vector);
+ base::SplitStringUsingSubstr(headers.as_string(), "\r\n",
+ &header_line_vector);
for (std::vector<std::string>::const_iterator it = header_line_vector.begin();
it != header_line_vector.end(); ++it) {
if (!it->empty())
diff --git a/net/http/http_request_headers.h b/net/http/http_request_headers.h
index c1f98b6..734194a 100644
--- a/net/http/http_request_headers.h
+++ b/net/http/http_request_headers.h
@@ -9,6 +9,7 @@
#ifndef NET_HTTP_HTTP_REQUEST_HEADERS_H_
#define NET_HTTP_HTTP_REQUEST_HEADERS_H_
+#pragma once
#include <string>
#include <vector>
@@ -20,10 +21,9 @@ namespace net {
class HttpRequestHeaders {
public:
struct HeaderKeyValuePair {
- HeaderKeyValuePair() {}
+ HeaderKeyValuePair();
HeaderKeyValuePair(const base::StringPiece& key,
- const base::StringPiece& value)
- : key(key.data(), key.size()), value(value.data(), value.size()) {}
+ const base::StringPiece& value);
std::string key;
std::string value;
diff --git a/net/http/http_request_info.h b/net/http/http_request_info.h
index c36e21a..3c072c0 100644
--- a/net/http/http_request_info.h
+++ b/net/http/http_request_info.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_REQUEST_INFO_H__
#define NET_HTTP_HTTP_REQUEST_INFO_H__
+#pragma once
#include <string>
#include "base/ref_counted.h"
@@ -16,7 +17,17 @@ namespace net {
struct HttpRequestInfo {
public:
- HttpRequestInfo() : load_flags(0), priority(LOWEST) {
+ enum RequestMotivation{
+ // TODO(mbelshe): move these into Client Socket.
+ PRECONNECT_MOTIVATED, // This request was motivated by a prefetch.
+ OMNIBOX_MOTIVATED, // This request was motivated by the omnibox.
+ NORMAL_MOTIVATION // No special motivation associated with the request.
+ };
+
+ HttpRequestInfo()
+ : load_flags(0),
+ priority(LOWEST),
+ motivation(NORMAL_MOTIVATION) {
}
// The requested URL.
@@ -39,6 +50,9 @@ struct HttpRequestInfo {
// The priority level for this request.
RequestPriority priority;
+
+ // The motivation behind this request.
+ RequestMotivation motivation;
};
} // namespace net
diff --git a/net/http/http_response_body_drainer.cc b/net/http/http_response_body_drainer.cc
new file mode 100644
index 0000000..cf32aaa
--- /dev/null
+++ b/net/http/http_response_body_drainer.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2010 The Chromium Authors. 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_response_body_drainer.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_stream.h"
+
+namespace net {
+
+HttpResponseBodyDrainer::HttpResponseBodyDrainer(HttpStream* stream)
+ : stream_(stream),
+ next_state_(STATE_NONE),
+ total_read_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ io_callback_(this, &HttpResponseBodyDrainer::OnIOComplete)),
+ user_callback_(NULL),
+ session_(NULL) {}
+
+HttpResponseBodyDrainer::~HttpResponseBodyDrainer() {}
+
+void HttpResponseBodyDrainer::Start(HttpNetworkSession* session) {
+ read_buf_ = new IOBuffer(kDrainBodyBufferSize);
+ next_state_ = STATE_DRAIN_RESPONSE_BODY;
+ int rv = DoLoop(OK);
+
+ if (rv == ERR_IO_PENDING) {
+ timer_.Start(base::TimeDelta::FromSeconds(kTimeoutInSeconds),
+ this,
+ &HttpResponseBodyDrainer::OnTimerFired);
+ session_ = session;
+ session->AddResponseDrainer(this);
+ return;
+ }
+
+ Finish(rv);
+}
+
+int HttpResponseBodyDrainer::DoLoop(int result) {
+ DCHECK_NE(next_state_, STATE_NONE);
+
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_DRAIN_RESPONSE_BODY:
+ DCHECK_EQ(OK, rv);
+ rv = DoDrainResponseBody();
+ break;
+ case STATE_DRAIN_RESPONSE_BODY_COMPLETE:
+ rv = DoDrainResponseBodyComplete(rv);
+ break;
+ default:
+ NOTREACHED() << "bad state";
+ rv = ERR_UNEXPECTED;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+
+ return rv;
+}
+
+int HttpResponseBodyDrainer::DoDrainResponseBody() {
+ next_state_ = STATE_DRAIN_RESPONSE_BODY_COMPLETE;
+
+ return stream_->ReadResponseBody(
+ read_buf_, kDrainBodyBufferSize - total_read_,
+ &io_callback_);
+}
+
+int HttpResponseBodyDrainer::DoDrainResponseBodyComplete(int result) {
+ DCHECK_NE(ERR_IO_PENDING, result);
+
+ if (result < 0)
+ return result;
+
+ if (result == 0)
+ return ERR_CONNECTION_CLOSED;
+
+ total_read_ += result;
+ if (stream_->IsResponseBodyComplete())
+ return OK;
+
+ DCHECK_LE(total_read_, kDrainBodyBufferSize);
+ if (total_read_ >= kDrainBodyBufferSize)
+ return ERR_RESPONSE_BODY_TOO_BIG_TO_DRAIN;
+
+ next_state_ = STATE_DRAIN_RESPONSE_BODY;
+ return OK;
+}
+
+void HttpResponseBodyDrainer::OnIOComplete(int result) {
+ int rv = DoLoop(result);
+ if (rv != ERR_IO_PENDING) {
+ timer_.Stop();
+ Finish(rv);
+ }
+}
+
+void HttpResponseBodyDrainer::OnTimerFired() {
+ Finish(ERR_TIMED_OUT);
+}
+
+void HttpResponseBodyDrainer::Finish(int result) {
+ DCHECK_NE(ERR_IO_PENDING, result);
+
+ if (session_)
+ session_->RemoveResponseDrainer(this);
+
+ if (result < 0) {
+ stream_->Close(true /* no keep-alive */);
+ } else {
+ DCHECK_EQ(OK, result);
+ stream_->Close(false /* keep-alive */);
+ }
+
+ delete this;
+}
+
+} // namespace net
diff --git a/net/http/http_response_body_drainer.h b/net/http/http_response_body_drainer.h
new file mode 100644
index 0000000..1aa4e93
--- /dev/null
+++ b/net/http/http_response_body_drainer.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 NET_HTTP_HTTP_RESPONSE_BODY_DRAINER_H_
+#define NET_HTTP_HTTP_RESPONSE_BODY_DRAINER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/timer.h"
+#include "net/base/completion_callback.h"
+#include "net/http/http_network_session.h"
+
+namespace net {
+
+class HttpStream;
+class IOBuffer;
+
+class HttpResponseBodyDrainer {
+ public:
+ // The size in bytes of the buffer we use to drain the response body that
+ // we want to throw away. The response body is typically a small page just a
+ // few hundred bytes long. We set a limit to prevent it from taking too long,
+ // since we may as well just create a new socket then.
+ static const int kDrainBodyBufferSize = 16384;
+ static const int kTimeoutInSeconds = 5;
+
+ explicit HttpResponseBodyDrainer(HttpStream* stream);
+ ~HttpResponseBodyDrainer();
+
+ // Starts reading the body until completion, or we hit the buffer limit, or we
+ // timeout. After Start(), |this| will eventually delete itself. If it
+ // doesn't complete immediately, it will add itself to |session|.
+ void Start(HttpNetworkSession* session);
+
+ private:
+ enum State {
+ STATE_DRAIN_RESPONSE_BODY,
+ STATE_DRAIN_RESPONSE_BODY_COMPLETE,
+ STATE_NONE,
+ };
+
+ int DoLoop(int result);
+
+ int DoDrainResponseBody();
+ int DoDrainResponseBodyComplete(int result);
+
+ void OnIOComplete(int result);
+ void OnTimerFired();
+ void Finish(int result);
+
+ scoped_refptr<IOBuffer> read_buf_;
+ const scoped_ptr<HttpStream> stream_;
+ State next_state_;
+ int total_read_;
+ CompletionCallbackImpl<HttpResponseBodyDrainer> io_callback_;
+ CompletionCallback* user_callback_;
+ base::OneShotTimer<HttpResponseBodyDrainer> timer_;
+ HttpNetworkSession* session_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpResponseBodyDrainer);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_RESPONSE_BODY_DRAINER_H_
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
new file mode 100644
index 0000000..6226b98
--- /dev/null
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -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.
+
+#include "net/http/http_response_body_drainer.h"
+
+#include <cstring>
+
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/ssl_config_service_defaults.h"
+#include "net/base/test_completion_callback.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_stream.h"
+#include "net/proxy/proxy_service.h"
+#include "net/spdy/spdy_session_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+const int kMagicChunkSize = 1024;
+COMPILE_ASSERT(
+ (HttpResponseBodyDrainer::kDrainBodyBufferSize % kMagicChunkSize) == 0,
+ chunk_size_needs_to_divide_evenly_into_buffer_size);
+
+class CloseResultWaiter {
+ public:
+ CloseResultWaiter()
+ : result_(false),
+ have_result_(false),
+ waiting_for_result_(false) {}
+
+ int WaitForResult() {
+ DCHECK(!waiting_for_result_);
+ while (!have_result_) {
+ waiting_for_result_ = true;
+ MessageLoop::current()->Run();
+ waiting_for_result_ = false;
+ }
+ return result_;
+ }
+
+ void set_result(bool result) {
+ result_ = result;
+ have_result_ = true;
+ if (waiting_for_result_)
+ MessageLoop::current()->Quit();
+ }
+
+ private:
+ int result_;
+ bool have_result_;
+ bool waiting_for_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseResultWaiter);
+};
+
+class MockHttpStream : public HttpStream {
+ public:
+ MockHttpStream(CloseResultWaiter* result_waiter)
+ : result_waiter_(result_waiter),
+ user_callback_(NULL),
+ closed_(false),
+ stall_reads_forever_(false),
+ num_chunks_(0),
+ is_complete_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
+ virtual ~MockHttpStream() {}
+
+ // HttpStream implementation:
+ virtual int InitializeStream(const HttpRequestInfo* request_info,
+ const BoundNetLog& net_log,
+ CompletionCallback* callback) {
+ return ERR_UNEXPECTED;
+ }
+ virtual int SendRequest(const std::string& request_headers,
+ UploadDataStream* request_body,
+ HttpResponseInfo* response,
+ CompletionCallback* callback) {
+ return ERR_UNEXPECTED;
+ }
+ virtual uint64 GetUploadProgress() const { return 0; }
+ virtual int ReadResponseHeaders(CompletionCallback* callback) {
+ return ERR_UNEXPECTED;
+ }
+ virtual const HttpResponseInfo* GetResponseInfo() const { return NULL; }
+
+ virtual bool CanFindEndOfResponse() const { return true; }
+ virtual bool IsMoreDataBuffered() const { return false; }
+ virtual bool IsConnectionReused() const { return false; }
+ virtual void SetConnectionReused() {}
+ virtual void GetSSLInfo(SSLInfo* ssl_info) {}
+ virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) {}
+
+ // Mocked API
+ virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback);
+ virtual void Close(bool not_reusable) {
+ DCHECK(!closed_);
+ closed_ = true;
+ result_waiter_->set_result(not_reusable);
+ }
+ virtual bool IsResponseBodyComplete() const { return is_complete_; }
+
+ // Methods to tweak/observer mock behavior:
+ void StallReadsForever() { stall_reads_forever_ = true; }
+
+ void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; }
+
+ private:
+ void CompleteRead();
+
+ bool closed() const { return closed_; }
+
+ CloseResultWaiter* const result_waiter_;
+ scoped_refptr<IOBuffer> user_buf_;
+ CompletionCallback* user_callback_;
+ bool closed_;
+ bool stall_reads_forever_;
+ int num_chunks_;
+ bool is_complete_;
+ ScopedRunnableMethodFactory<MockHttpStream> method_factory_;
+};
+
+int MockHttpStream::ReadResponseBody(
+ IOBuffer* buf, int buf_len, CompletionCallback* callback) {
+ DCHECK(callback);
+ DCHECK(!user_callback_);
+ DCHECK(buf);
+
+ if (stall_reads_forever_)
+ return ERR_IO_PENDING;
+
+ if (num_chunks_ == 0)
+ return ERR_UNEXPECTED;
+
+ if (buf_len > kMagicChunkSize && num_chunks_ > 1) {
+ user_buf_ = buf;
+ user_callback_ = callback;
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(&MockHttpStream::CompleteRead));
+ return ERR_IO_PENDING;
+ }
+
+ num_chunks_--;
+ if (!num_chunks_)
+ is_complete_ = true;
+
+ return buf_len;
+}
+
+void MockHttpStream::CompleteRead() {
+ CompletionCallback* callback = user_callback_;
+ std::memset(user_buf_->data(), 1, kMagicChunkSize);
+ user_buf_ = NULL;
+ user_callback_ = NULL;
+ num_chunks_--;
+ if (!num_chunks_)
+ is_complete_ = true;
+ callback->Run(kMagicChunkSize);
+}
+
+class HttpResponseBodyDrainerTest : public testing::Test {
+ protected:
+ HttpResponseBodyDrainerTest()
+ : session_(new HttpNetworkSession(
+ NULL,
+ ProxyService::CreateDirect(),
+ NULL,
+ new SSLConfigServiceDefaults,
+ new SpdySessionPool(NULL),
+ NULL,
+ NULL,
+ NULL)),
+ mock_stream_(new MockHttpStream(&result_waiter_)),
+ drainer_(new HttpResponseBodyDrainer(mock_stream_)) {}
+ ~HttpResponseBodyDrainerTest() {}
+
+ const scoped_refptr<HttpNetworkSession> session_;
+ CloseResultWaiter result_waiter_;
+ MockHttpStream* const mock_stream_; // Owned by |drainer_|.
+ HttpResponseBodyDrainer* const drainer_; // Deletes itself.
+};
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) {
+ mock_stream_->set_num_chunks(1);
+ drainer_->Start(session_);
+ EXPECT_FALSE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) {
+ mock_stream_->set_num_chunks(3);
+ drainer_->Start(session_);
+ EXPECT_FALSE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) {
+ mock_stream_->set_num_chunks(
+ HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize);
+ drainer_->Start(session_);
+ EXPECT_FALSE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) {
+ mock_stream_->set_num_chunks(2);
+ mock_stream_->StallReadsForever();
+ drainer_->Start(session_);
+ EXPECT_TRUE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, CancelledBySession) {
+ mock_stream_->set_num_chunks(2);
+ mock_stream_->StallReadsForever();
+ drainer_->Start(session_);
+ // HttpNetworkSession should delete |drainer_|.
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodyTooLarge) {
+ TestCompletionCallback callback;
+ int too_many_chunks =
+ HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize;
+ too_many_chunks += 1; // Now it's too large.
+
+ mock_stream_->set_num_chunks(too_many_chunks);
+ drainer_->Start(session_);
+ EXPECT_TRUE(result_waiter_.WaitForResult());
+}
+
+} // namespace
+
+} // namespace net
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index 08f397d..631b3a1 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.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.
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/pickle.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
#include "net/base/escape.h"
@@ -493,6 +494,12 @@ bool HttpResponseHeaders::HasHeader(const std::string& name) const {
return FindHeader(0, name) != std::string::npos;
}
+HttpResponseHeaders::HttpResponseHeaders() {
+}
+
+HttpResponseHeaders::~HttpResponseHeaders() {
+}
+
// Note: this implementation implicitly assumes that line_end points at a valid
// sentinel character (such as '\0').
// static
@@ -591,7 +598,7 @@ void HttpResponseHeaders::ParseStatusLine(
raw_headers_.push_back(' ');
raw_headers_.append(code, p);
raw_headers_.push_back(' ');
- response_code_ = static_cast<int>(StringToInt64(std::string(code, p)));
+ base::StringToInt(std::string(code, p), &response_code_);
// Skip whitespace.
while (*p == ' ')
@@ -965,8 +972,9 @@ bool HttpResponseHeaders::GetMaxAgeValue(TimeDelta* result) const {
if (LowerCaseEqualsASCII(value.begin(),
value.begin() + kMaxAgePrefixLen,
kMaxAgePrefix)) {
- *result = TimeDelta::FromSeconds(
- StringToInt64(value.substr(kMaxAgePrefixLen)));
+ int64 seconds;
+ base::StringToInt64(value.substr(kMaxAgePrefixLen), &seconds);
+ *result = TimeDelta::FromSeconds(seconds);
return true;
}
}
@@ -980,7 +988,9 @@ bool HttpResponseHeaders::GetAgeValue(TimeDelta* result) const {
if (!EnumerateHeader(NULL, "Age", &value))
return false;
- *result = TimeDelta::FromSeconds(StringToInt64(value));
+ int64 seconds;
+ base::StringToInt64(value, &seconds);
+ *result = TimeDelta::FromSeconds(seconds);
return true;
}
@@ -1071,7 +1081,7 @@ int64 HttpResponseHeaders::GetContentLength() const {
return -1;
int64 result;
- bool ok = StringToInt64(content_length_val, &result);
+ bool ok = base::StringToInt64(content_length_val, &result);
if (!ok || result < 0)
return -1;
@@ -1138,7 +1148,7 @@ bool HttpResponseHeaders::GetContentRange(int64* first_byte_position,
byte_range_resp_spec.begin() + minus_position;
HttpUtil::TrimLWS(&first_byte_pos_begin, &first_byte_pos_end);
- bool ok = StringToInt64(
+ bool ok = base::StringToInt64(
std::string(first_byte_pos_begin, first_byte_pos_end),
first_byte_position);
@@ -1149,7 +1159,7 @@ bool HttpResponseHeaders::GetContentRange(int64* first_byte_position,
byte_range_resp_spec.end();
HttpUtil::TrimLWS(&last_byte_pos_begin, &last_byte_pos_end);
- ok &= StringToInt64(
+ ok &= base::StringToInt64(
std::string(last_byte_pos_begin, last_byte_pos_end),
last_byte_position);
if (!ok) {
@@ -1174,7 +1184,7 @@ bool HttpResponseHeaders::GetContentRange(int64* first_byte_position,
if (LowerCaseEqualsASCII(instance_length_begin, instance_length_end, "*")) {
return false;
- } else if (!StringToInt64(
+ } else if (!base::StringToInt64(
std::string(instance_length_begin, instance_length_end),
instance_length)) {
*instance_length = -1;
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index 30e43ea..aacd35a 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_RESPONSE_HEADERS_H_
#define NET_HTTP_HTTP_RESPONSE_HEADERS_H_
+#pragma once
#include <string>
#include <vector>
@@ -137,9 +138,10 @@ class HttpResponseHeaders
// method returns the un-coalesced response header lines, so if a response
// header appears on multiple lines, then it will appear multiple times in
// this enumeration (in the order the header lines were received from the
- // server). Initialize a 'void*' variable to NULL and pass it by address to
- // EnumerateHeaderLines. Call EnumerateHeaderLines repeatedly until it
- // returns false. The out-params 'name' and 'value' are set upon success.
+ // server). Also, a given header might have an empty value. Initialize a
+ // 'void*' variable to NULL and pass it by address to EnumerateHeaderLines.
+ // Call EnumerateHeaderLines repeatedly until it returns false. The
+ // out-params 'name' and 'value' are set upon success.
bool EnumerateHeaderLines(void** iter,
std::string* name,
std::string* value) const;
@@ -148,7 +150,8 @@ class HttpResponseHeaders
// in the first header, then you can pass NULL for the 'iter' parameter.
// Otherwise, to iterate across all values for the specified header,
// initialize a 'void*' variable to NULL and pass it by address to
- // EnumerateHeader. Call EnumerateHeader repeatedly until it returns false.
+ // EnumerateHeader. Note that a header might have an empty value. Call
+ // EnumerateHeader repeatedly until it returns false.
bool EnumerateHeader(void** iter,
const std::string& name,
std::string* value) const;
@@ -250,8 +253,8 @@ class HttpResponseHeaders
typedef base::hash_set<std::string> HeaderSet;
- HttpResponseHeaders() {}
- ~HttpResponseHeaders() {}
+ HttpResponseHeaders();
+ ~HttpResponseHeaders();
// Initializes from the given raw headers.
void Parse(const std::string& raw_input);
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 0159caf..dc90d1f 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -7,6 +7,11 @@
#include "base/logging.h"
#include "base/pickle.h"
#include "base/time.h"
+#include "net/base/auth.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/ssl_cert_request_info.h"
+#include "net/base/x509_certificate.h"
#include "net/http/http_response_headers.h"
using base::Time;
@@ -63,9 +68,42 @@ HttpResponseInfo::HttpResponseInfo()
was_fetched_via_proxy(false) {
}
+HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
+ : was_cached(rhs.was_cached),
+ was_fetched_via_spdy(rhs.was_fetched_via_spdy),
+ was_npn_negotiated(rhs.was_npn_negotiated),
+ was_alternate_protocol_available(rhs.was_alternate_protocol_available),
+ was_fetched_via_proxy(rhs.was_fetched_via_proxy),
+ request_time(rhs.request_time),
+ response_time(rhs.response_time),
+ auth_challenge(rhs.auth_challenge),
+ cert_request_info(rhs.cert_request_info),
+ ssl_info(rhs.ssl_info),
+ headers(rhs.headers),
+ vary_data(rhs.vary_data),
+ metadata(rhs.metadata) {
+}
+
HttpResponseInfo::~HttpResponseInfo() {
}
+HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
+ was_cached = rhs.was_cached;
+ was_fetched_via_spdy = rhs.was_fetched_via_spdy;
+ was_npn_negotiated = rhs.was_npn_negotiated;
+ was_alternate_protocol_available = rhs.was_alternate_protocol_available;
+ was_fetched_via_proxy = rhs.was_fetched_via_proxy;
+ request_time = rhs.request_time;
+ response_time = rhs.response_time;
+ auth_challenge = rhs.auth_challenge;
+ cert_request_info = rhs.cert_request_info;
+ ssl_info = rhs.ssl_info;
+ headers = rhs.headers;
+ vary_data = rhs.vary_data;
+ metadata = rhs.metadata;
+ return *this;
+}
+
bool HttpResponseInfo::InitFromPickle(const Pickle& pickle,
bool* response_truncated) {
void* iter = NULL;
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index 52c3a0e..cd66982 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -4,24 +4,29 @@
#ifndef NET_HTTP_HTTP_RESPONSE_INFO_H_
#define NET_HTTP_HTTP_RESPONSE_INFO_H_
+#pragma once
#include "base/time.h"
-#include "net/base/auth.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_info.h"
-#include "net/http/http_response_headers.h"
#include "net/http/http_vary_data.h"
class Pickle;
namespace net {
+class AuthChallengeInfo;
+class HttpResponseHeaders;
+class IOBufferWithSize;
+class SSLCertRequestInfo;
+
class HttpResponseInfo {
public:
HttpResponseInfo();
+ HttpResponseInfo(const HttpResponseInfo& rhs);
~HttpResponseInfo();
- // Default copy-constructor and assignment operator are OK!
+ HttpResponseInfo& operator=(const HttpResponseInfo& rhs);
+ // Even though we could get away with the copy ctor and default operator=,
+ // that would prevent us from doing a bunch of forward declaration.
// The following is only defined if the request_time member is set.
// If this response was resurrected from cache, then this bool is set, and
diff --git a/net/http/http_stream.h b/net/http/http_stream.h
index de2a8d7..211267d 100644
--- a/net/http/http_stream.h
+++ b/net/http/http_stream.h
@@ -5,10 +5,14 @@
// HttpStream is an interface for reading and writing data to an HttpStream that
// keeps the client agnostic of the actual underlying transport layer. This
// provides an abstraction for both a basic http stream as well as http
-// pipelining implementations.
+// pipelining implementations. The HttpStream subtype is expected to manage the
+// underlying transport appropriately. For example, a non-pipelined HttpStream
+// would return the transport socket to the pool for reuse. SPDY streams on the
+// other hand leave the transport socket management to the SpdySession.
#ifndef NET_HTTP_HTTP_STREAM_H_
#define NET_HTTP_HTTP_STREAM_H_
+#pragma once
#include <string>
@@ -17,23 +21,31 @@
namespace net {
-struct HttpRequestInfo;
+class BoundNetLog;
class HttpResponseInfo;
class IOBuffer;
+class SSLCertRequestInfo;
+class SSLInfo;
class UploadDataStream;
+struct HttpRequestInfo;
class HttpStream {
public:
HttpStream() {}
virtual ~HttpStream() {}
+ // Initialize stream. Must be called before calling SendRequest().
+ // Returns a net error code, possibly ERR_IO_PENDING.
+ virtual int InitializeStream(const HttpRequestInfo* request_info,
+ const BoundNetLog& net_log,
+ CompletionCallback* callback) = 0;
+
// Writes the headers and uploads body data to the underlying socket.
// ERR_IO_PENDING is returned if the operation could not be completed
// synchronously, in which case the result will be passed to the callback
// when available. Returns OK on success. The HttpStream takes ownership
// of the request_body.
- virtual int SendRequest(const HttpRequestInfo* request,
- const std::string& request_headers,
+ virtual int SendRequest(const std::string& request_headers,
UploadDataStream* request_body,
HttpResponseInfo* response,
CompletionCallback* callback) = 0;
@@ -49,7 +61,7 @@ class HttpStream {
virtual int ReadResponseHeaders(CompletionCallback* callback) = 0;
// Provides access to HttpResponseInfo (owned by HttpStream).
- virtual HttpResponseInfo* GetResponseInfo() const = 0;
+ virtual const HttpResponseInfo* GetResponseInfo() const = 0;
// Reads response body data, up to |buf_len| bytes. |buf_len| should be a
// reasonable size (<2MB). The number of bytes read is returned, or an
@@ -64,6 +76,17 @@ class HttpStream {
virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
CompletionCallback* callback) = 0;
+ // Closes the stream.
+ // |not_reusable| indicates if the stream can be used for further requests.
+ // In the case of HTTP, where we re-use the byte-stream (e.g. the connection)
+ // this means we need to close the connection; in the case of SPDY, where the
+ // underlying stream is never reused, it has no effect.
+ // TODO(mbelshe): We should figure out how to fold the not_reusable flag
+ // into the stream implementation itself so that the caller
+ // does not need to pass it at all. We might also be able to
+ // eliminate the SetConnectionReused() below.
+ virtual void Close(bool not_reusable) = 0;
+
// Indicates if the response body has been completely read.
virtual bool IsResponseBodyComplete() const = 0;
@@ -78,6 +101,23 @@ class HttpStream {
// as part of the next pipelined response) has been read from the socket.
virtual bool IsMoreDataBuffered() const = 0;
+ // A stream exists on top of a connection. If the connection has been used
+ // to successfully exchange data in the past, error handling for the
+ // stream is done differently. This method returns true if the underlying
+ // connection is reused or has been connected and idle for some time.
+ virtual bool IsConnectionReused() const = 0;
+ virtual void SetConnectionReused() = 0;
+
+ // Get the SSLInfo associated with this stream's connection. This should
+ // only be called for streams over SSL sockets, otherwise the behavior is
+ // undefined.
+ virtual void GetSSLInfo(SSLInfo* ssl_info) = 0;
+
+ // Get the SSLCertRequestInfo associated with this stream's connection.
+ // This should only be called for streams over SSL sockets, otherwise the
+ // behavior is undefined.
+ virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(HttpStream);
};
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc
new file mode 100644
index 0000000..03237ab
--- /dev/null
+++ b/net/http/http_stream_factory.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 "net/http/http_stream_factory.h"
+
+#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "net/base/net_log.h"
+#include "net/base/net_util.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_stream_request.h"
+
+namespace net {
+
+// static
+const HostMappingRules* HttpStreamFactory::host_mapping_rules_ = NULL;
+// static
+const std::string* HttpStreamFactory::next_protos_ = NULL;
+// static
+bool HttpStreamFactory::use_alternate_protocols_ = false;
+// static
+bool HttpStreamFactory::force_spdy_over_ssl_ = true;
+// static
+bool HttpStreamFactory::force_spdy_always_ = false;
+// static
+bool HttpStreamFactory::ignore_certificate_errors_ = false;
+
+// static
+void HttpStreamFactory::SetHostMappingRules(const std::string& rules) {
+ HostMappingRules* host_mapping_rules = new HostMappingRules();
+ host_mapping_rules->SetRulesFromString(rules);
+ delete host_mapping_rules_;
+ host_mapping_rules_ = host_mapping_rules;
+}
+
+HttpStreamFactory::HttpStreamFactory() {
+}
+
+HttpStreamFactory::~HttpStreamFactory() {
+}
+
+void HttpStreamFactory::RequestStream(
+ const HttpRequestInfo* request_info,
+ SSLConfig* ssl_config,
+ ProxyInfo* proxy_info,
+ StreamFactory::StreamRequestDelegate* delegate,
+ const BoundNetLog& net_log,
+ const scoped_refptr<HttpNetworkSession>& session,
+ scoped_refptr<StreamRequestJob>* stream) {
+ DCHECK(stream != NULL);
+ *stream = new HttpStreamRequest(this, session);
+ (*stream)->Start(request_info, ssl_config, proxy_info, delegate, net_log);
+}
+
+void HttpStreamFactory::AddTLSIntolerantServer(const GURL& url) {
+ tls_intolerant_servers_.insert(GetHostAndPort(url));
+}
+
+bool HttpStreamFactory::IsTLSIntolerantServer(const GURL& url) {
+ return ContainsKey(tls_intolerant_servers_, GetHostAndPort(url));
+}
+
+void HttpStreamFactory::ProcessAlternateProtocol(
+ HttpAlternateProtocols* alternate_protocols,
+ const std::string& alternate_protocol_str,
+ const HostPortPair& http_host_port_pair) {
+ std::vector<std::string> port_protocol_vector;
+ SplitString(alternate_protocol_str, ':', &port_protocol_vector);
+ if (port_protocol_vector.size() != 2) {
+ DLOG(WARNING) << HttpAlternateProtocols::kHeader
+ << " header has too many tokens: "
+ << alternate_protocol_str;
+ return;
+ }
+
+ int port;
+ if (!base::StringToInt(port_protocol_vector[0], &port) ||
+ port <= 0 || port >= 1 << 16) {
+ DLOG(WARNING) << HttpAlternateProtocols::kHeader
+ << " header has unrecognizable port: "
+ << port_protocol_vector[0];
+ return;
+ }
+
+ HttpAlternateProtocols::Protocol protocol = HttpAlternateProtocols::BROKEN;
+ // We skip NPN_SPDY_1 here, because we've rolled the protocol version to 2.
+ for (int i = HttpAlternateProtocols::NPN_SPDY_2;
+ i < HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS; ++i) {
+ if (port_protocol_vector[1] == HttpAlternateProtocols::kProtocolStrings[i])
+ protocol = static_cast<HttpAlternateProtocols::Protocol>(i);
+ }
+
+ if (protocol == HttpAlternateProtocols::BROKEN) {
+ // Currently, we only recognize the npn-spdy protocol.
+ DLOG(WARNING) << HttpAlternateProtocols::kHeader
+ << " header has unrecognized protocol: "
+ << port_protocol_vector[1];
+ return;
+ }
+
+ HostPortPair host_port(http_host_port_pair);
+ if (host_mapping_rules_)
+ host_mapping_rules_->RewriteHost(&host_port);
+
+ if (alternate_protocols->HasAlternateProtocolFor(host_port)) {
+ const HttpAlternateProtocols::PortProtocolPair existing_alternate =
+ alternate_protocols->GetAlternateProtocolFor(host_port);
+ // If we think the alternate protocol is broken, don't change it.
+ if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN)
+ return;
+ }
+
+ alternate_protocols->SetAlternateProtocolFor(host_port, port, protocol);
+}
+
+GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url,
+ HostPortPair* endpoint) {
+ if (host_mapping_rules_ && host_mapping_rules_->RewriteHost(endpoint)) {
+ url_canon::Replacements<char> replacements;
+ const std::string port_str = base::IntToString(endpoint->port());
+ replacements.SetPort(port_str.c_str(),
+ url_parse::Component(0, port_str.size()));
+ replacements.SetHost(endpoint->host().c_str(),
+ url_parse::Component(0, endpoint->host().size()));
+ return url.ReplaceComponents(replacements);
+ }
+ return url;
+}
+
+} // namespace net
+
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
new file mode 100644
index 0000000..5c6f179
--- /dev/null
+++ b/net/http/http_stream_factory.h
@@ -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.
+
+#ifndef NET_HTTP_HTTP_STREAM_FACTORY_H_
+#define NET_HTTP_HTTP_STREAM_FACTORY_H_
+
+#include <set>
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/host_mapping_rules.h"
+#include "net/base/ssl_config_service.h"
+#include "net/http/http_auth.h"
+#include "net/http/http_auth_controller.h"
+#include "net/http/stream_factory.h"
+#include "net/proxy/proxy_service.h"
+#include "net/socket/client_socket_handle.h"
+
+namespace net {
+
+class HttpNetworkSession;
+struct HttpRequestInfo;
+
+class HttpStreamFactory : public StreamFactory,
+ public base::RefCounted<HttpStreamFactory> {
+ public:
+ HttpStreamFactory();
+ virtual ~HttpStreamFactory();
+
+ // StreamFactory Interface
+ virtual void RequestStream(const HttpRequestInfo* info,
+ SSLConfig* ssl_config,
+ ProxyInfo* proxy_info,
+ StreamRequestDelegate* delegate,
+ const BoundNetLog& net_log,
+ const scoped_refptr<HttpNetworkSession>& session,
+ scoped_refptr<StreamRequestJob>* stream);
+
+ // TLS Intolerant Server API
+ void AddTLSIntolerantServer(const GURL& url);
+ bool IsTLSIntolerantServer(const GURL& url);
+
+ // Alternate Protocol API
+ void ProcessAlternateProtocol(HttpAlternateProtocols* alternate_protocols,
+ const std::string& alternate_protocol_str,
+ const HostPortPair& http_host_port_pair);
+
+ // Host Mapping Rules API
+ GURL ApplyHostMappingRules(const GURL& url, HostPortPair* endpoint);
+
+ // Static settings
+
+ // Controls whether or not we use the Alternate-Protocol header.
+ static void set_use_alternate_protocols(bool value) {
+ use_alternate_protocols_ = value;
+ }
+ static bool use_alternate_protocols() { return use_alternate_protocols_; }
+
+ // Controls whether or not we use ssl when in spdy mode.
+ static void set_force_spdy_over_ssl(bool value) {
+ force_spdy_over_ssl_ = value;
+ }
+ static bool force_spdy_over_ssl() {
+ return force_spdy_over_ssl_;
+ }
+
+ // Controls whether or not we use spdy without npn.
+ static void set_force_spdy_always(bool value) {
+ force_spdy_always_ = value;
+ }
+ static bool force_spdy_always() { return force_spdy_always_; }
+
+ // Sets the next protocol negotiation value used during the SSL handshake.
+ static void set_next_protos(const std::string& value) {
+ delete next_protos_;
+ next_protos_ = new std::string(value);
+ }
+ static const std::string* next_protos() { return next_protos_; }
+
+ // Sets the HttpStreamFactory into a mode where it can ignore certificate
+ // errors. This is for testing.
+ static void set_ignore_certificate_errors(bool value) {
+ ignore_certificate_errors_ = value;
+ }
+ static bool ignore_certificate_errors() {
+ return ignore_certificate_errors_;
+ }
+
+ static void SetHostMappingRules(const std::string& rules);
+
+ private:
+ std::set<std::string> tls_intolerant_servers_;
+
+ static const HostMappingRules* host_mapping_rules_;
+ static const std::string* next_protos_;
+ static bool use_alternate_protocols_;
+ static bool force_spdy_over_ssl_;
+ static bool force_spdy_always_;
+ static bool ignore_certificate_errors_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpStreamFactory);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_STREAM_FACTORY_H_
+
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index 1426957..ce115b3 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -6,18 +6,23 @@
#include "base/compiler_specific.h"
#include "base/histogram.h"
+#include "net/base/auth.h"
#include "net/base/io_buffer.h"
+#include "net/base/ssl_cert_request_info.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/client_socket_handle.h"
namespace net {
HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection,
+ const HttpRequestInfo* request,
GrowableIOBuffer* read_buffer,
const BoundNetLog& net_log)
: io_state_(STATE_NONE),
- request_(NULL),
+ request_(request),
request_headers_(NULL),
request_body_(NULL),
read_buf_(read_buffer),
@@ -38,8 +43,7 @@ HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection,
HttpStreamParser::~HttpStreamParser() {}
-int HttpStreamParser::SendRequest(const HttpRequestInfo* request,
- const std::string& headers,
+int HttpStreamParser::SendRequest(const std::string& headers,
UploadDataStream* request_body,
HttpResponseInfo* response,
CompletionCallback* callback) {
@@ -48,7 +52,6 @@ int HttpStreamParser::SendRequest(const HttpRequestInfo* request,
DCHECK(callback);
DCHECK(response);
- request_ = request;
response_ = response;
scoped_refptr<StringIOBuffer> headers_io_buf = new StringIOBuffer(headers);
request_headers_ = new DrainableIOBuffer(headers_io_buf,
@@ -91,6 +94,12 @@ int HttpStreamParser::ReadResponseHeaders(CompletionCallback* callback) {
return result > 0 ? OK : result;
}
+void HttpStreamParser::Close(bool not_reusable) {
+ if (not_reusable && connection_->socket())
+ connection_->socket()->Disconnect();
+ connection_->Reset();
+}
+
int HttpStreamParser::ReadResponseBody(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(io_state_ == STATE_BODY_PENDING || io_state_ == STATE_DONE);
@@ -264,8 +273,10 @@ int HttpStreamParser::DoReadHeadersComplete(int result) {
io_state_ = STATE_DONE;
return result;
}
+ // If we've used the connection before, then we know it is not a HTTP/0.9
+ // response and return ERR_CONNECTION_CLOSED.
if (result == ERR_CONNECTION_CLOSED && read_buf_->offset() == 0 &&
- connection_->ShouldResendFailedRequest(result)) {
+ connection_->is_reused()) {
io_state_ = STATE_DONE;
return result;
}
@@ -292,16 +303,24 @@ int HttpStreamParser::DoReadHeadersComplete(int result) {
io_state_ = STATE_BODY_PENDING;
end_offset = 0;
}
- DoParseResponseHeaders(end_offset);
+ int rv = DoParseResponseHeaders(end_offset);
+ if (rv < 0)
+ return rv;
return result;
}
}
read_buf_->set_offset(read_buf_->offset() + result);
DCHECK_LE(read_buf_->offset(), read_buf_->capacity());
- DCHECK(result >= 0);
+ DCHECK_GE(result, 0);
int end_of_header_offset = ParseResponseHeaders();
+
+ // Note: -1 is special, it indicates we haven't found the end of headers.
+ // Anything less than -1 is a net::Error, so we bail out.
+ if (end_of_header_offset < -1)
+ return end_of_header_offset;
+
if (end_of_header_offset == -1) {
io_state_ = STATE_READ_HEADERS;
// Prevent growing the headers buffer indefinitely.
@@ -470,11 +489,13 @@ int HttpStreamParser::ParseResponseHeaders() {
if (end_offset == -1)
return -1;
- DoParseResponseHeaders(end_offset);
+ int rv = DoParseResponseHeaders(end_offset);
+ if (rv < 0)
+ return rv;
return end_offset + read_buf_unused_offset_;
}
-void HttpStreamParser::DoParseResponseHeaders(int end_offset) {
+int HttpStreamParser::DoParseResponseHeaders(int end_offset) {
scoped_refptr<HttpResponseHeaders> headers;
if (response_header_start_offset_ >= 0) {
headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(
@@ -484,8 +505,23 @@ void HttpStreamParser::DoParseResponseHeaders(int end_offset) {
headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
}
+ // Check for multiple Content-Length headers with a Transfer-Encoding header.
+ // If they exist, it's a potential response smuggling attack.
+
+ void* it = NULL;
+ const std::string content_length_header("Content-Length");
+ std::string ignored_header_value;
+ if (!headers->HasHeader("Transfer-Encoding") &&
+ headers->EnumerateHeader(
+ &it, content_length_header, &ignored_header_value) &&
+ headers->EnumerateHeader(
+ &it, content_length_header, &ignored_header_value)) {
+ return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH;
+ }
+
response_->headers = headers;
response_->vary_data.Init(*request_, *response_->headers);
+ return OK;
}
void HttpStreamParser::CalculateResponseBodySize() {
@@ -556,4 +592,35 @@ bool HttpStreamParser::IsMoreDataBuffered() const {
return read_buf_->offset() > read_buf_unused_offset_;
}
+bool HttpStreamParser::IsConnectionReused() const {
+ ClientSocketHandle::SocketReuseType reuse_type = connection_->reuse_type();
+ return connection_->is_reused() ||
+ reuse_type == ClientSocketHandle::UNUSED_IDLE;
+}
+
+void HttpStreamParser::SetConnectionReused() {
+ connection_->set_is_reused(true);
+}
+
+void HttpStreamParser::GetSSLInfo(SSLInfo* ssl_info) {
+ if (request_->url.SchemeIs("https")) {
+ if (!connection_->socket() || !connection_->socket()->IsConnected())
+ return;
+ SSLClientSocket* ssl_socket =
+ static_cast<SSLClientSocket*>(connection_->socket());
+ ssl_socket->GetSSLInfo(ssl_info);
+ }
+}
+
+void HttpStreamParser::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ if (request_->url.SchemeIs("https")) {
+ if (!connection_->socket() || !connection_->socket()->IsConnected())
+ return;
+ SSLClientSocket* ssl_socket =
+ static_cast<SSLClientSocket*>(connection_->socket());
+ ssl_socket->GetSSLCertRequestInfo(cert_request_info);
+ }
+}
+
} // namespace net
diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h
index 44cc9e8..a1dda07 100644
--- a/net/http/http_stream_parser.h
+++ b/net/http/http_stream_parser.h
@@ -4,21 +4,26 @@
#ifndef NET_HTTP_HTTP_STREAM_PARSER_H_
#define NET_HTTP_HTTP_STREAM_PARSER_H_
+#pragma once
#include <string>
#include "base/basictypes.h"
-#include "net/base/io_buffer.h"
+#include "net/base/completion_callback.h"
#include "net/base/net_log.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_chunked_decoder.h"
-#include "net/http/http_response_info.h"
-#include "net/socket/client_socket_handle.h"
namespace net {
class ClientSocketHandle;
+class DrainableIOBuffer;
+class GrowableIOBuffer;
struct HttpRequestInfo;
+class HttpResponseInfo;
+class IOBuffer;
+class SSLCertRequestInfo;
+class SSLInfo;
class HttpStreamParser {
public:
@@ -28,21 +33,23 @@ class HttpStreamParser {
// buffer's offset will be set to the first free byte. |read_buffer| may
// have its capacity changed.
HttpStreamParser(ClientSocketHandle* connection,
+ const HttpRequestInfo* request,
GrowableIOBuffer* read_buffer,
const BoundNetLog& net_log);
~HttpStreamParser();
// These functions implement the interface described in HttpStream with
// some additional functionality
- int SendRequest(const HttpRequestInfo* request, const std::string& headers,
- UploadDataStream* request_body, HttpResponseInfo* response,
- CompletionCallback* callback);
+ int SendRequest(const std::string& headers, UploadDataStream* request_body,
+ HttpResponseInfo* response, CompletionCallback* callback);
int ReadResponseHeaders(CompletionCallback* callback);
int ReadResponseBody(IOBuffer* buf, int buf_len,
CompletionCallback* callback);
+ void Close(bool not_reusable);
+
uint64 GetUploadProgress() const;
HttpResponseInfo* GetResponseInfo();
@@ -53,6 +60,14 @@ class HttpStreamParser {
bool IsMoreDataBuffered() const;
+ bool IsConnectionReused() const;
+
+ void SetConnectionReused();
+
+ void GetSSLInfo(SSLInfo* ssl_info);
+
+ void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
+
private:
// FOO_COMPLETE states implement the second half of potentially asynchronous
// operations and don't necessarily mean that FOO is complete.
@@ -96,14 +111,15 @@ class HttpStreamParser {
int DoReadBody();
int DoReadBodyComplete(int result);
- // Examines |read_buf_| to find the start and end of the headers. Return
- // the offset for the end of the headers, or -1 if the complete headers
- // were not found. If they are are found, parse them with
- // DoParseResponseHeaders().
+ // Examines |read_buf_| to find the start and end of the headers. If they are
+ // found, parse them with DoParseResponseHeaders(). Return the offset for
+ // the end of the headers, or -1 if the complete headers were not found, or
+ // with a net::Error if we encountered an error during parsing.
int ParseResponseHeaders();
- // Parse the headers into response_.
- void DoParseResponseHeaders(int end_of_header_offset);
+ // Parse the headers into response_. Returns OK on success or a net::Error on
+ // failure.
+ int DoParseResponseHeaders(int end_of_header_offset);
// Examine the parsed headers to try to determine the response body size.
void CalculateResponseBodySize();
diff --git a/net/http/http_stream_request.cc b/net/http/http_stream_request.cc
new file mode 100644
index 0000000..67aefb0
--- /dev/null
+++ b/net/http/http_stream_request.cc
@@ -0,0 +1,994 @@
+// Copyright (c) 2010 The Chromium Authors. 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_stream_request.h"
+
+#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "net/base/connection_type_histograms.h"
+#include "net/base/net_log.h"
+#include "net/base/net_util.h"
+#include "net/base/ssl_cert_request_info.h"
+#include "net/http/http_basic_stream.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_proxy_client_socket.h"
+#include "net/http/http_proxy_client_socket_pool.h"
+#include "net/http/http_request_info.h"
+#include "net/socket/client_socket_handle.h"
+#include "net/socket/client_socket_handle.h"
+#include "net/socket/socks_client_socket_pool.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/tcp_client_socket_pool.h"
+#include "net/spdy/spdy_http_stream.h"
+#include "net/spdy/spdy_session.h"
+#include "net/spdy/spdy_session_pool.h"
+
+namespace net {
+
+namespace {
+
+GURL UpgradeUrlToHttps(const GURL& original_url) {
+ GURL::Replacements replacements;
+ // new_sheme and new_port need to be in scope here because GURL::Replacements
+ // references the memory contained by them directly.
+ const std::string new_scheme = "https";
+ const std::string new_port = base::IntToString(443);
+ replacements.SetSchemeStr(new_scheme);
+ replacements.SetPortStr(new_port);
+ return original_url.ReplaceComponents(replacements);
+}
+
+} // namespace
+
+HttpStreamRequest::HttpStreamRequest(
+ HttpStreamFactory* factory,
+ const scoped_refptr<HttpNetworkSession>& session)
+ : request_info_(NULL),
+ proxy_info_(NULL),
+ ssl_config_(NULL),
+ session_(session),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ io_callback_(this, &HttpStreamRequest::OnIOComplete)),
+ connection_(new ClientSocketHandle),
+ factory_(factory),
+ delegate_(NULL),
+ next_state_(STATE_NONE),
+ pac_request_(NULL),
+ using_ssl_(false),
+ using_spdy_(false),
+ force_spdy_always_(factory->force_spdy_always()),
+ force_spdy_over_ssl_(factory->force_spdy_over_ssl()),
+ spdy_certificate_error_(OK),
+ establishing_tunnel_(false),
+ was_alternate_protocol_available_(false),
+ was_npn_negotiated_(false),
+ cancelled_(false) {
+ if (factory->use_alternate_protocols())
+ alternate_protocol_mode_ = kUnspecified;
+ else
+ alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
+}
+
+HttpStreamRequest::~HttpStreamRequest() {
+ // When we're in a partially constructed state, waiting for the user to
+ // provide certificate handling information or authentication, we can't reuse
+ // this stream at all.
+ if (next_state_ == STATE_WAITING_USER_ACTION) {
+ connection_->socket()->Disconnect();
+ connection_->Reset();
+ connection_.reset();
+ }
+
+ if (pac_request_)
+ session_->proxy_service()->CancelPacRequest(pac_request_);
+}
+
+void HttpStreamRequest::Start(const HttpRequestInfo* request_info,
+ SSLConfig* ssl_config,
+ ProxyInfo* proxy_info,
+ StreamFactory::StreamRequestDelegate* delegate,
+ const BoundNetLog& net_log) {
+ CHECK_EQ(STATE_NONE, next_state_);
+ CHECK(!cancelled_);
+
+ request_info_ = request_info;
+ ssl_config_ = ssl_config;
+ proxy_info_ = proxy_info;
+ delegate_ = delegate;
+ net_log_ = net_log;
+ next_state_ = STATE_RESOLVE_PROXY;
+ int rv = RunLoop(OK);
+ DCHECK_EQ(ERR_IO_PENDING, rv);
+}
+
+void HttpStreamRequest::Cancel() {
+ cancelled_ = true;
+
+ // If we were waiting for the user to take action, then the connection
+ // is in a partially connected state. All we can do is close it at this
+ // point.
+ if (next_state_ == STATE_WAITING_USER_ACTION) {
+ connection_->socket()->Disconnect();
+ connection_->Reset();
+ connection_.reset();
+ }
+
+ // The stream could be in a partial state. It is not reusable.
+ if (stream_.get()) {
+ stream_->Close(true);
+ stream_.reset();
+ }
+
+ delegate_ = NULL;
+
+ next_state_ = STATE_NONE;
+}
+
+int HttpStreamRequest::RestartWithCertificate(X509Certificate* client_cert) {
+ ssl_config()->client_cert = client_cert;
+ ssl_config()->send_client_cert = true;
+ next_state_ = STATE_INIT_CONNECTION;
+ // Reset the other member variables.
+ // Note: this is necessary only with SSL renegotiation.
+ stream_.reset();
+ return RunLoop(OK);
+}
+
+int HttpStreamRequest::RestartTunnelWithProxyAuth(const string16& username,
+ const string16& password) {
+ DCHECK(establishing_tunnel_);
+ next_state_ = STATE_RESTART_TUNNEL_AUTH;
+ stream_.reset();
+ return RunLoop(OK);
+}
+
+LoadState HttpStreamRequest::GetLoadState() const {
+ switch (next_state_) {
+ case STATE_RESOLVE_PROXY_COMPLETE:
+ return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
+ case STATE_CREATE_STREAM_COMPLETE:
+ return connection_->GetLoadState();
+ case STATE_INIT_CONNECTION_COMPLETE:
+ return LOAD_STATE_SENDING_REQUEST;
+ default:
+ return LOAD_STATE_IDLE;
+ }
+}
+
+void HttpStreamRequest::GetSSLInfo() {
+ DCHECK(using_ssl_);
+ DCHECK(!establishing_tunnel_);
+ DCHECK(connection_.get() && connection_->socket());
+ SSLClientSocket* ssl_socket =
+ static_cast<SSLClientSocket*>(connection_->socket());
+ ssl_socket->GetSSLInfo(&ssl_info_);
+}
+
+const HttpRequestInfo& HttpStreamRequest::request_info() const {
+ DCHECK(!cancelled_); // Can't access this after cancellation.
+ return *request_info_;
+}
+
+ProxyInfo* HttpStreamRequest::proxy_info() const {
+ DCHECK(!cancelled_); // Can't access this after cancellation.
+ return proxy_info_;
+}
+
+SSLConfig* HttpStreamRequest::ssl_config() const {
+ DCHECK(!cancelled_); // Can't access this after cancellation.
+ return ssl_config_;
+}
+
+void HttpStreamRequest::OnStreamReadyCallback(HttpStream* stream) {
+ if (cancelled_) {
+ // The delegate is gone. We need to cleanup the stream.
+ delete stream;
+ return;
+ }
+ delegate_->OnStreamReady(stream);
+}
+
+void HttpStreamRequest::OnStreamFailedCallback(int result) {
+ if (cancelled_)
+ return;
+ delegate_->OnStreamFailed(result);
+}
+
+void HttpStreamRequest::OnCertificateErrorCallback(int result,
+ const SSLInfo& ssl_info) {
+ if (cancelled_)
+ return;
+ delegate_->OnCertificateError(result, ssl_info);
+}
+
+void HttpStreamRequest::OnNeedsProxyAuthCallback(
+ const HttpResponseInfo& response,
+ HttpAuthController* auth_controller) {
+ if (cancelled_)
+ return;
+ delegate_->OnNeedsProxyAuth(response, auth_controller);
+}
+
+void HttpStreamRequest::OnNeedsClientAuthCallback(
+ SSLCertRequestInfo* cert_info) {
+ if (cancelled_)
+ return;
+ delegate_->OnNeedsClientAuth(cert_info);
+}
+
+void HttpStreamRequest::OnIOComplete(int result) {
+ RunLoop(result);
+}
+
+int HttpStreamRequest::RunLoop(int result) {
+ if (cancelled_)
+ return ERR_ABORTED;
+
+ result = DoLoop(result);
+
+ DCHECK(delegate_);
+
+ if (IsCertificateError(result)) {
+ // Retrieve SSL information from the socket.
+ GetSSLInfo();
+
+ next_state_ = STATE_WAITING_USER_ACTION;
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &HttpStreamRequest::OnCertificateErrorCallback,
+ result, ssl_info_));
+ return ERR_IO_PENDING;
+ }
+
+ switch (result) {
+ case ERR_PROXY_AUTH_REQUESTED:
+ {
+ DCHECK(connection_.get());
+ DCHECK(connection_->socket());
+ DCHECK(establishing_tunnel_);
+
+ HttpProxyClientSocket* http_proxy_socket =
+ static_cast<HttpProxyClientSocket*>(connection_->socket());
+ const HttpResponseInfo* tunnel_auth_response =
+ http_proxy_socket->GetResponseInfo();
+
+ next_state_ = STATE_WAITING_USER_ACTION;
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &HttpStreamRequest::OnNeedsProxyAuthCallback,
+ *tunnel_auth_response,
+ http_proxy_socket->auth_controller()));
+ }
+ return ERR_IO_PENDING;
+
+ case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &HttpStreamRequest::OnNeedsClientAuthCallback,
+ connection_->ssl_error_response_info().cert_request_info));
+ return ERR_IO_PENDING;
+
+ case ERR_IO_PENDING:
+ break;
+
+ case OK:
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &HttpStreamRequest::OnStreamReadyCallback,
+ stream_.release()));
+ return ERR_IO_PENDING;
+
+ default:
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &HttpStreamRequest::OnStreamFailedCallback,
+ result));
+ return ERR_IO_PENDING;
+ }
+ return result;
+}
+
+int HttpStreamRequest::DoLoop(int result) {
+ DCHECK(next_state_ != STATE_NONE);
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_RESOLVE_PROXY:
+ DCHECK_EQ(OK, rv);
+ rv = DoResolveProxy();
+ break;
+ case STATE_RESOLVE_PROXY_COMPLETE:
+ rv = DoResolveProxyComplete(rv);
+ break;
+ case STATE_INIT_CONNECTION:
+ DCHECK_EQ(OK, rv);
+ rv = DoInitConnection();
+ break;
+ case STATE_INIT_CONNECTION_COMPLETE:
+ rv = DoInitConnectionComplete(rv);
+ break;
+ case STATE_WAITING_USER_ACTION:
+ rv = DoWaitingUserAction(rv);
+ break;
+ case STATE_RESTART_TUNNEL_AUTH:
+ DCHECK_EQ(OK, rv);
+ rv = DoRestartTunnelAuth();
+ break;
+ case STATE_RESTART_TUNNEL_AUTH_COMPLETE:
+ rv = DoRestartTunnelAuthComplete(rv);
+ break;
+ case STATE_CREATE_STREAM:
+ DCHECK_EQ(OK, rv);
+ rv = DoCreateStream();
+ break;
+ case STATE_CREATE_STREAM_COMPLETE:
+ rv = DoCreateStreamComplete(rv);
+ break;
+ default:
+ NOTREACHED() << "bad state";
+ rv = ERR_FAILED;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+ return rv;
+}
+
+int HttpStreamRequest::DoResolveProxy() {
+ DCHECK(!pac_request_);
+
+ next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
+
+ // |endpoint_| indicates the final destination endpoint.
+ endpoint_ = HostPortPair(request_info().url.HostNoBrackets(),
+ request_info().url.EffectiveIntPort());
+
+ // Extra URL we might be attempting to resolve to.
+ GURL alternate_endpoint_url = request_info().url;
+
+ // Tracks whether we are using |request_.url| or |alternate_endpoint_url|.
+ const GURL *curr_endpoint_url = &request_info().url;
+
+ alternate_endpoint_url =
+ factory_->ApplyHostMappingRules(alternate_endpoint_url, &endpoint_);
+
+ const HttpAlternateProtocols& alternate_protocols =
+ session_->alternate_protocols();
+ if (alternate_protocols.HasAlternateProtocolFor(endpoint_)) {
+ was_alternate_protocol_available_ = true;
+ if (alternate_protocol_mode_ == kUnspecified) {
+ HttpAlternateProtocols::PortProtocolPair alternate =
+ alternate_protocols.GetAlternateProtocolFor(endpoint_);
+ if (alternate.protocol != HttpAlternateProtocols::BROKEN) {
+ DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
+ DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS,
+ alternate.protocol);
+ endpoint_.set_port(alternate.port);
+ alternate_protocol_ = alternate.protocol;
+ alternate_protocol_mode_ = kUsingAlternateProtocol;
+ alternate_endpoint_url = UpgradeUrlToHttps(*curr_endpoint_url);
+ curr_endpoint_url = &alternate_endpoint_url;
+ }
+ }
+ }
+
+ if (request_info().load_flags & LOAD_BYPASS_PROXY) {
+ proxy_info()->UseDirect();
+ return OK;
+ }
+
+ return session_->proxy_service()->ResolveProxy(
+ *curr_endpoint_url, proxy_info(), &io_callback_, &pac_request_,
+ net_log_);
+}
+
+int HttpStreamRequest::DoResolveProxyComplete(int result) {
+ pac_request_ = NULL;
+
+ if (result != OK)
+ return result;
+
+ // TODO(mbelshe): consider retrying ResolveProxy if we came here via use of
+ // AlternateProtocol.
+
+ // Remove unsupported proxies from the list.
+ proxy_info()->RemoveProxiesWithoutScheme(
+ ProxyServer::SCHEME_DIRECT |
+ ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS |
+ ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5);
+
+ if (proxy_info()->is_empty()) {
+ // No proxies/direct to choose from. This happens when we don't support any
+ // of the proxies in the returned list.
+ return ERR_NO_SUPPORTED_PROXIES;
+ }
+
+ next_state_ = STATE_INIT_CONNECTION;
+ return OK;
+}
+
+int HttpStreamRequest::DoInitConnection() {
+ DCHECK(!connection_->is_initialized());
+ DCHECK(proxy_info()->proxy_server().is_valid());
+ next_state_ = STATE_INIT_CONNECTION_COMPLETE;
+
+ bool want_spdy_over_npn =
+ alternate_protocol_mode_ == kUsingAlternateProtocol &&
+ alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2;
+ using_ssl_ = request_info().url.SchemeIs("https") ||
+ (force_spdy_always_ && force_spdy_over_ssl_) ||
+ want_spdy_over_npn;
+ using_spdy_ = false;
+
+ // Check first if we have a spdy session for this group. If so, then go
+ // straight to using that.
+ HostPortProxyPair pair(endpoint_, proxy_info()->proxy_server());
+ if (session_->spdy_session_pool()->HasSession(pair)) {
+ using_spdy_ = true;
+ next_state_ = STATE_CREATE_STREAM;
+ return OK;
+ }
+ // Check next if we have a spdy session for this proxy. If so, then go
+ // straight to using that.
+ if (proxy_info()->is_https()) {
+ HostPortProxyPair proxy(proxy_info()->proxy_server().host_port_pair(),
+ proxy_info()->proxy_server());
+ if (session_->spdy_session_pool()->HasSession(proxy)) {
+ using_spdy_ = true;
+ next_state_ = STATE_CREATE_STREAM;
+ return OK;
+ }
+ }
+
+ // Build the string used to uniquely identify connections of this type.
+ // Determine the host and port to connect to.
+ std::string connection_group = endpoint_.ToString();
+ DCHECK(!connection_group.empty());
+
+ if (using_ssl_)
+ connection_group = base::StringPrintf("ssl/%s", connection_group.c_str());
+
+ // If the user is refreshing the page, bypass the host cache.
+ bool disable_resolver_cache =
+ request_info().load_flags & LOAD_BYPASS_CACHE ||
+ request_info().load_flags & LOAD_VALIDATE_CACHE ||
+ request_info().load_flags & LOAD_DISABLE_CACHE;
+
+ // Build up the connection parameters.
+ scoped_refptr<TCPSocketParams> tcp_params;
+ scoped_refptr<HttpProxySocketParams> http_proxy_params;
+ scoped_refptr<SOCKSSocketParams> socks_params;
+ scoped_ptr<HostPortPair> proxy_host_port;
+
+ if (proxy_info()->is_direct()) {
+ tcp_params = new TCPSocketParams(endpoint_, request_info().priority,
+ request_info().referrer,
+ disable_resolver_cache);
+ } else {
+ ProxyServer proxy_server = proxy_info()->proxy_server();
+ proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair()));
+ scoped_refptr<TCPSocketParams> proxy_tcp_params =
+ new TCPSocketParams(*proxy_host_port, request_info().priority,
+ request_info().referrer, disable_resolver_cache);
+
+ if (proxy_info()->is_http() || proxy_info()->is_https()) {
+ GURL authentication_url = request_info().url;
+ if (using_ssl_ && !authentication_url.SchemeIs("https")) {
+ // If a proxy tunnel connection needs to be established due to
+ // an Alternate-Protocol, the URL needs to be changed to indicate
+ // https or digest authentication attempts will fail.
+ // For example, suppose the initial request was for
+ // "http://www.example.com/index.html". If this is an SSL
+ // upgrade due to alternate protocol, the digest authorization
+ // should have a uri="www.example.com:443" field rather than a
+ // "/index.html" entry, even though the original request URL has not
+ // changed.
+ authentication_url = UpgradeUrlToHttps(authentication_url);
+ }
+ establishing_tunnel_ = using_ssl_;
+ std::string user_agent;
+ request_info().extra_headers.GetHeader(HttpRequestHeaders::kUserAgent,
+ &user_agent);
+ scoped_refptr<SSLSocketParams> ssl_params;
+ if (proxy_info()->is_https()) {
+ // Set ssl_params, and unset proxy_tcp_params
+ ssl_params = GenerateSslParams(proxy_tcp_params, NULL, NULL,
+ ProxyServer::SCHEME_DIRECT,
+ want_spdy_over_npn);
+ proxy_tcp_params = NULL;
+ }
+
+ http_proxy_params =
+ new HttpProxySocketParams(proxy_tcp_params,
+ ssl_params,
+ authentication_url,
+ user_agent,
+ endpoint_,
+ session_->auth_cache(),
+ session_->http_auth_handler_factory(),
+ using_ssl_);
+ } else {
+ DCHECK(proxy_info()->is_socks());
+ char socks_version;
+ if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5)
+ socks_version = '5';
+ else
+ socks_version = '4';
+ connection_group = base::StringPrintf(
+ "socks%c/%s", socks_version, connection_group.c_str());
+
+ socks_params = new SOCKSSocketParams(proxy_tcp_params,
+ socks_version == '5',
+ endpoint_,
+ request_info().priority,
+ request_info().referrer);
+ }
+ }
+
+ // Deal with SSL - which layers on top of any given proxy.
+ if (using_ssl_) {
+ scoped_refptr<SSLSocketParams> ssl_params =
+ GenerateSslParams(tcp_params, http_proxy_params, socks_params,
+ proxy_info()->proxy_server().scheme(),
+ want_spdy_over_npn);
+ SSLClientSocketPool* ssl_pool = NULL;
+ if (proxy_info()->is_direct())
+ ssl_pool = session_->ssl_socket_pool();
+ else
+ ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port);
+
+ return connection_->Init(connection_group, ssl_params,
+ request_info().priority, &io_callback_, ssl_pool,
+ net_log_);
+ }
+
+ // Finally, get the connection started.
+ if (proxy_info()->is_http() || proxy_info()->is_https()) {
+ return connection_->Init(
+ connection_group, http_proxy_params, request_info().priority,
+ &io_callback_, session_->GetSocketPoolForHTTPProxy(*proxy_host_port),
+ net_log_);
+ }
+
+ if (proxy_info()->is_socks()) {
+ return connection_->Init(
+ connection_group, socks_params, request_info().priority, &io_callback_,
+ session_->GetSocketPoolForSOCKSProxy(*proxy_host_port), net_log_);
+ }
+
+ DCHECK(proxy_info()->is_direct());
+ return connection_->Init(connection_group, tcp_params,
+ request_info().priority, &io_callback_,
+ session_->tcp_socket_pool(), net_log_);
+}
+
+int HttpStreamRequest::DoInitConnectionComplete(int result) {
+ // |result| may be the result of any of the stacked pools. The following
+ // logic is used when determining how to interpret an error.
+ // If |result| < 0:
+ // and connection_->socket() != NULL, then the SSL handshake ran and it
+ // is a potentially recoverable error.
+ // and connection_->socket == NULL and connection_->is_ssl_error() is true,
+ // then the SSL handshake ran with an unrecoverable error.
+ // otherwise, the error came from one of the other pools.
+ bool ssl_started = using_ssl_ && (result == OK || connection_->socket() ||
+ connection_->is_ssl_error());
+
+ if (ssl_started && (result == OK || IsCertificateError(result))) {
+ SSLClientSocket* ssl_socket =
+ static_cast<SSLClientSocket*>(connection_->socket());
+ if (ssl_socket->was_npn_negotiated()) {
+ was_npn_negotiated_ = true;
+ if (ssl_socket->was_spdy_negotiated())
+ using_spdy_ = true;
+ }
+ if (force_spdy_over_ssl_ && force_spdy_always_)
+ using_spdy_ = true;
+ } else if (proxy_info()->is_https() && connection_->socket() &&
+ result == OK) {
+ HttpProxyClientSocket* proxy_socket =
+ static_cast<HttpProxyClientSocket*>(connection_->socket());
+ if (proxy_socket->using_spdy()) {
+ was_npn_negotiated_ = true;
+ using_spdy_ = true;
+ }
+ }
+
+ // We may be using spdy without SSL
+ if (!force_spdy_over_ssl_ && force_spdy_always_)
+ using_spdy_ = true;
+
+ if (result == ERR_PROXY_AUTH_REQUESTED) {
+ 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.
+ connection_.reset(connection_->release_pending_http_proxy_connection());
+ return result;
+ }
+
+ if ((!ssl_started && result < 0 &&
+ alternate_protocol_mode_ == kUsingAlternateProtocol) ||
+ result == ERR_NPN_NEGOTIATION_FAILED) {
+ // Mark the alternate protocol as broken and fallback.
+ MarkBrokenAlternateProtocolAndFallback();
+ return OK;
+ }
+
+ if (result < 0 && !ssl_started)
+ return ReconsiderProxyAfterError(result);
+ establishing_tunnel_ = false;
+
+ if (connection_->socket()) {
+ LogHttpConnectedMetrics(*connection_);
+
+ // We officially have a new connection. Record the type.
+ if (!connection_->is_reused()) {
+ ConnectionType type = using_spdy_ ? CONNECTION_SPDY : CONNECTION_HTTP;
+ UpdateConnectionTypeHistograms(type);
+ }
+ }
+
+ // Handle SSL errors below.
+ if (using_ssl_) {
+ DCHECK(ssl_started);
+ if (IsCertificateError(result)) {
+ if (using_spdy_ && request_info().url.SchemeIs("http")) {
+ // We ignore certificate errors for http over spdy.
+ spdy_certificate_error_ = result;
+ result = OK;
+ } else {
+ result = HandleCertificateError(result);
+ if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
+ connection_->socket()->Disconnect();
+ connection_->Reset();
+ next_state_ = STATE_INIT_CONNECTION;
+ return result;
+ }
+ }
+ }
+ if (result < 0)
+ return HandleSSLHandshakeError(result);
+ }
+
+ next_state_ = STATE_CREATE_STREAM;
+ return OK;
+}
+
+int HttpStreamRequest::DoWaitingUserAction(int result) {
+ // This state indicates that the stream request is in a partially
+ // completed state, and we've called back to the delegate for more
+ // information.
+
+ // We're always waiting here for the delegate to call us back.
+ return ERR_IO_PENDING;
+}
+
+int HttpStreamRequest::DoCreateStream() {
+ next_state_ = STATE_CREATE_STREAM_COMPLETE;
+
+ // We only set the socket motivation if we're the first to use
+ // this socket. Is there a race for two SPDY requests? We really
+ // need to plumb this through to the connect level.
+ if (connection_->socket() && !connection_->is_reused())
+ SetSocketMotivation();
+
+ if (!using_spdy_) {
+ stream_.reset(new HttpBasicStream(connection_.release()));
+ return OK;
+ }
+
+ CHECK(!stream_.get());
+
+ bool direct = true;
+ const scoped_refptr<SpdySessionPool> spdy_pool =
+ session_->spdy_session_pool();
+ scoped_refptr<SpdySession> spdy_session;
+
+ const ProxyServer& proxy_server = proxy_info()->proxy_server();
+ HostPortProxyPair pair(endpoint_, proxy_server);
+ if (spdy_pool->HasSession(pair)) {
+ // We have a SPDY session to the origin server. This might be a direct
+ // connection, or it might be a SPDY session through an HTTP or HTTPS proxy.
+ spdy_session =
+ spdy_pool->Get(pair, session_->mutable_spdy_settings(), net_log_);
+ } else if (proxy_info()->is_https()) {
+ // If we don't have a direct SPDY session, and we're using an HTTPS
+ // proxy, then we might have a SPDY session to the proxy
+ pair = HostPortProxyPair(proxy_server.host_port_pair(), proxy_server);
+ if (spdy_pool->HasSession(pair)) {
+ spdy_session =
+ spdy_pool->Get(pair, session_->mutable_spdy_settings(), net_log_);
+ }
+ direct = false;
+ }
+
+ if (!spdy_session.get()) {
+ // SPDY can be negotiated using the TLS next protocol negotiation (NPN)
+ // extension, or just directly using SSL. Either way, |connection_| must
+ // contain an SSLClientSocket.
+ CHECK(connection_->socket());
+ int error = spdy_pool->GetSpdySessionFromSocket(
+ pair, session_->mutable_spdy_settings(), connection_.release(),
+ net_log_, spdy_certificate_error_, &spdy_session, using_ssl_);
+ if (error != OK)
+ return error;
+ }
+
+ if (spdy_session->IsClosed())
+ return ERR_CONNECTION_CLOSED;
+
+ stream_.reset(new SpdyHttpStream(spdy_session, direct));
+ return OK;
+}
+
+int HttpStreamRequest::DoCreateStreamComplete(int result) {
+ if (result < 0)
+ return result;
+
+ next_state_ = STATE_NONE;
+ return OK;
+}
+
+int HttpStreamRequest::DoRestartTunnelAuth() {
+ next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE;
+ HttpProxyClientSocket* http_proxy_socket =
+ static_cast<HttpProxyClientSocket*>(connection_->socket());
+ return http_proxy_socket->RestartWithAuth(&io_callback_);
+}
+
+int HttpStreamRequest::DoRestartTunnelAuthComplete(int result) {
+ if (result == ERR_PROXY_AUTH_REQUESTED)
+ return result;
+
+ if (result == OK) {
+ // Now that we've got the HttpProxyClientSocket connected. We have
+ // to release it as an idle socket into the pool and start the connection
+ // process from the beginning. Trying to pass it in with the
+ // SSLSocketParams might cause a deadlock since params are dispatched
+ // interchangeably. This request won't necessarily get this http proxy
+ // socket, but there will be forward progress.
+ connection_->Reset();
+ establishing_tunnel_ = false;
+ next_state_ = STATE_INIT_CONNECTION;
+ return OK;
+ }
+
+ return ReconsiderProxyAfterError(result);
+}
+
+void HttpStreamRequest::SetSocketMotivation() {
+ if (request_info_->motivation == HttpRequestInfo::PRECONNECT_MOTIVATED)
+ connection_->socket()->SetSubresourceSpeculation();
+ else if (request_info_->motivation == HttpRequestInfo::OMNIBOX_MOTIVATED)
+ connection_->socket()->SetOmniboxSpeculation();
+ // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED).
+}
+
+// Returns a newly create SSLSocketParams, and sets several
+// fields of ssl_config_.
+scoped_refptr<SSLSocketParams> HttpStreamRequest::GenerateSslParams(
+ scoped_refptr<TCPSocketParams> tcp_params,
+ scoped_refptr<HttpProxySocketParams> http_proxy_params,
+ scoped_refptr<SOCKSSocketParams> socks_params,
+ ProxyServer::Scheme proxy_scheme,
+ bool want_spdy_over_npn) {
+
+ if (factory_->IsTLSIntolerantServer(request_info().url)) {
+ LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
+ << GetHostAndPort(request_info().url);
+ ssl_config()->ssl3_fallback = true;
+ ssl_config()->tls1_enabled = false;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback",
+ static_cast<int>(ssl_config()->ssl3_fallback), 2);
+
+ int load_flags = request_info().load_flags;
+ if (factory_->ignore_certificate_errors())
+ load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
+ if (request_info().load_flags & LOAD_VERIFY_EV_CERT)
+ ssl_config()->verify_ev_cert = true;
+
+ if (proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTP ||
+ proxy_info()->proxy_server().scheme() == ProxyServer::SCHEME_HTTPS) {
+ ssl_config()->mitm_proxies_allowed = true;
+ }
+
+ scoped_refptr<SSLSocketParams> ssl_params =
+ new SSLSocketParams(tcp_params, socks_params, http_proxy_params,
+ proxy_scheme, request_info().url.HostNoBrackets(),
+ *ssl_config(), load_flags,
+ force_spdy_always_ && force_spdy_over_ssl_,
+ want_spdy_over_npn);
+
+ return ssl_params;
+}
+
+
+void HttpStreamRequest::MarkBrokenAlternateProtocolAndFallback() {
+ // We have to:
+ // * Reset the endpoint to be the unmodified URL specified destination.
+ // * Mark the endpoint as broken so we don't try again.
+ // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we
+ // ignore future Alternate-Protocol headers from the HostPortPair.
+ // * Reset the connection and go back to STATE_INIT_CONNECTION.
+
+ endpoint_ = HostPortPair(request_info().url.HostNoBrackets(),
+ request_info().url.EffectiveIntPort());
+
+ session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor(
+ endpoint_);
+
+ alternate_protocol_mode_ = kDoNotUseAlternateProtocol;
+ if (connection_->socket())
+ connection_->socket()->Disconnect();
+ connection_->Reset();
+ next_state_ = STATE_INIT_CONNECTION;
+}
+
+int HttpStreamRequest::ReconsiderProxyAfterError(int error) {
+ DCHECK(!pac_request_);
+
+ // A failure to resolve the hostname or any error related to establishing a
+ // TCP connection could be grounds for trying a new proxy configuration.
+ //
+ // Why do this when a hostname cannot be resolved? Some URLs only make sense
+ // to proxy servers. The hostname in those URLs might fail to resolve if we
+ // are still using a non-proxy config. We need to check if a proxy config
+ // now exists that corresponds to a proxy server that could load the URL.
+ //
+ switch (error) {
+ case ERR_PROXY_CONNECTION_FAILED:
+ case ERR_NAME_NOT_RESOLVED:
+ case ERR_INTERNET_DISCONNECTED:
+ case ERR_ADDRESS_UNREACHABLE:
+ case ERR_CONNECTION_CLOSED:
+ case ERR_CONNECTION_RESET:
+ case ERR_CONNECTION_REFUSED:
+ case ERR_CONNECTION_ABORTED:
+ case ERR_TIMED_OUT:
+ case ERR_TUNNEL_CONNECTION_FAILED:
+ case ERR_SOCKS_CONNECTION_FAILED:
+ break;
+ case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
+ // Remap the SOCKS-specific "host unreachable" error to a more
+ // generic error code (this way consumers like the link doctor
+ // know to substitute their error page).
+ //
+ // Note that if the host resolving was done by the SOCSK5 proxy, we can't
+ // differentiate between a proxy-side "host not found" versus a proxy-side
+ // "address unreachable" error, and will report both of these failures as
+ // ERR_ADDRESS_UNREACHABLE.
+ return ERR_ADDRESS_UNREACHABLE;
+ default:
+ return error;
+ }
+
+ if (request_info().load_flags & LOAD_BYPASS_PROXY) {
+ return error;
+ }
+
+ int rv = session_->proxy_service()->ReconsiderProxyAfterError(
+ request_info().url, proxy_info(), &io_callback_, &pac_request_,
+ net_log_);
+ if (rv == OK || rv == ERR_IO_PENDING) {
+ // If the error was during connection setup, there is no socket to
+ // disconnect.
+ if (connection_->socket())
+ connection_->socket()->Disconnect();
+ connection_->Reset();
+ next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
+ } else {
+ // If ReconsiderProxyAfterError() failed synchronously, it means
+ // there was nothing left to fall-back to, so fail the transaction
+ // with the last connection error we got.
+ // TODO(eroman): This is a confusing contract, make it more obvious.
+ rv = error;
+ }
+
+ return rv;
+}
+
+int HttpStreamRequest::HandleCertificateError(int error) {
+ DCHECK(using_ssl_);
+ DCHECK(IsCertificateError(error));
+
+ SSLClientSocket* ssl_socket =
+ static_cast<SSLClientSocket*>(connection_->socket());
+ ssl_socket->GetSSLInfo(&ssl_info_);
+
+ // Add the bad certificate to the set of allowed certificates in the
+ // SSL info object. This data structure will be consulted after calling
+ // RestartIgnoringLastError(). And the user will be asked interactively
+ // before RestartIgnoringLastError() is ever called.
+ SSLConfig::CertAndStatus bad_cert;
+ bad_cert.cert = ssl_info_.cert;
+ bad_cert.cert_status = ssl_info_.cert_status;
+ ssl_config()->allowed_bad_certs.push_back(bad_cert);
+
+ int load_flags = request_info().load_flags;
+ if (factory_->ignore_certificate_errors())
+ load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS;
+ if (ssl_socket->IgnoreCertError(error, load_flags))
+ return OK;
+ 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;
+}
+
+// static
+void HttpStreamRequest::LogHttpConnectedMetrics(
+ const ClientSocketHandle& handle) {
+ UMA_HISTOGRAM_ENUMERATION("Net.HttpSocketType", handle.reuse_type(),
+ ClientSocketHandle::NUM_TYPES);
+
+ switch (handle.reuse_type()) {
+ case ClientSocketHandle::UNUSED:
+ UMA_HISTOGRAM_CUSTOM_TIMES("Net.HttpConnectionLatency",
+ handle.setup_time(),
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(10),
+ 100);
+ break;
+ case ClientSocketHandle::UNUSED_IDLE:
+ UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_UnusedSocket",
+ handle.idle_time(),
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(6),
+ 100);
+ break;
+ case ClientSocketHandle::REUSED_IDLE:
+ UMA_HISTOGRAM_CUSTOM_TIMES("Net.SocketIdleTimeBeforeNextUse_ReusedSocket",
+ handle.idle_time(),
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(6),
+ 100);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+} // namespace net
diff --git a/net/http/http_stream_request.h b/net/http/http_stream_request.h
new file mode 100644
index 0000000..a60c96d
--- /dev/null
+++ b/net/http/http_stream_request.h
@@ -0,0 +1,218 @@
+// Copyright (c) 2010 The Chromium Authors. 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_HTTP_STREAM_REQUEST_H_
+#define NET_HTTP_HTTP_STREAM_REQUEST_H_
+
+#include "base/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/host_mapping_rules.h"
+#include "net/base/ssl_config_service.h"
+#include "net/http/http_auth.h"
+#include "net/http/http_auth_controller.h"
+#include "net/http/http_alternate_protocols.h"
+#include "net/http/http_stream_factory.h"
+#include "net/http/stream_factory.h"
+#include "net/proxy/proxy_service.h"
+#include "net/socket/client_socket_handle.h"
+
+namespace net {
+
+class ClientSocketHandle;
+class HttpAuthController;
+class HttpNetworkSession;
+class HttpProxySocketParams;
+class HttpStreamFactory;
+class SOCKSSocketParams;
+class SSLSocketParams;
+class StreamRequestDelegate;
+class TCPSocketParams;
+struct HttpRequestInfo;
+
+// An HttpStreamRequest exists for each stream which is in progress of being
+// created for the StreamFactory.
+class HttpStreamRequest : public StreamFactory::StreamRequestJob {
+ public:
+ HttpStreamRequest(HttpStreamFactory* factory,
+ const scoped_refptr<HttpNetworkSession>& session);
+ virtual ~HttpStreamRequest();
+
+ // StreamRequest interface
+ virtual void Start(const HttpRequestInfo* request_info,
+ SSLConfig* ssl_config,
+ ProxyInfo* proxy_info,
+ StreamFactory::StreamRequestDelegate* delegate,
+ const BoundNetLog& net_log);
+ virtual void Cancel();
+ virtual int RestartWithCertificate(X509Certificate* client_cert);
+ virtual int RestartTunnelWithProxyAuth(const string16& username,
+ 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_; }
+
+ private:
+ enum AlternateProtocolMode {
+ kUnspecified, // Unspecified, check HttpAlternateProtocols
+ kUsingAlternateProtocol, // Using an alternate protocol
+ kDoNotUseAlternateProtocol, // Failed to connect once, do not try again.
+ };
+
+ enum State {
+ STATE_RESOLVE_PROXY,
+ STATE_RESOLVE_PROXY_COMPLETE,
+ STATE_INIT_CONNECTION,
+ STATE_INIT_CONNECTION_COMPLETE,
+ STATE_WAITING_USER_ACTION,
+ STATE_RESTART_TUNNEL_AUTH,
+ STATE_RESTART_TUNNEL_AUTH_COMPLETE,
+ STATE_CREATE_STREAM,
+ STATE_CREATE_STREAM_COMPLETE,
+ STATE_DRAIN_BODY_FOR_AUTH_RESTART,
+ STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE,
+ STATE_NONE
+ };
+
+ const HttpRequestInfo& request_info() const;
+ ProxyInfo* proxy_info() const;
+ SSLConfig* ssl_config() const;
+
+ // Callbacks to the delegate.
+ void OnStreamReadyCallback(HttpStream* stream);
+ void OnStreamFailedCallback(int result);
+ void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info);
+ void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info,
+ HttpAuthController* auth_controller);
+ void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info);
+
+ void OnIOComplete(int result);
+ int RunLoop(int result);
+ int DoLoop(int result);
+
+ // Each of these methods corresponds to a State value. Those with an input
+ // argument receive the result from the previous state. If a method returns
+ // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the
+ // next state method as the result arg.
+ int DoResolveProxy();
+ int DoResolveProxyComplete(int result);
+ int DoInitConnection();
+ int DoInitConnectionComplete(int result);
+ int DoWaitingUserAction(int result);
+ int DoCreateStream();
+ int DoCreateStreamComplete(int result);
+ int DoRestartTunnelAuth();
+ int DoRestartTunnelAuthComplete(int result);
+
+ // Set the motivation for this request onto the underlying socket.
+ void SetSocketMotivation();
+
+ // Returns a newly create SSLSocketParams, and sets several
+ // fields of ssl_config_.
+ scoped_refptr<SSLSocketParams> GenerateSslParams(
+ scoped_refptr<TCPSocketParams> tcp_params,
+ scoped_refptr<HttpProxySocketParams> http_proxy_params,
+ scoped_refptr<SOCKSSocketParams> socks_params,
+ ProxyServer::Scheme proxy_scheme,
+ bool want_spdy_over_npn);
+
+ // AlternateProtocol API
+ void MarkBrokenAlternateProtocolAndFallback();
+
+ // Retrieve SSLInfo from our SSL Socket.
+ // This must only be called when we are using an SSLSocket.
+ // After calling, the caller can use ssl_info_.
+ void GetSSLInfo();
+
+ // Called when we encounter a network error that could be resolved by trying
+ // a new proxy configuration. If there is another proxy configuration to try
+ // then this method sets next_state_ appropriately and returns either OK or
+ // ERR_IO_PENDING depending on whether or not the new proxy configuration is
+ // available synchronously or asynchronously. Otherwise, the given error
+ // code is simply returned.
+ int ReconsiderProxyAfterError(int error);
+
+ // Called to handle a certificate error. Stores the certificate in the
+ // allowed_bad_certs list, and checks if the error can be ignored. Returns
+ // OK if it can be ignored, or the error code otherwise.
+ int HandleCertificateError(int error);
+
+ // 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);
+
+ // Record histograms of latency until Connect() completes.
+ static void LogHttpConnectedMetrics(const ClientSocketHandle& handle);
+
+ const HttpRequestInfo* request_info_; // Use request_info().
+ ProxyInfo* proxy_info_; // Use proxy_info().
+ SSLConfig* ssl_config_; // Use ssl_config().
+
+ scoped_refptr<HttpNetworkSession> session_;
+ CompletionCallbackImpl<HttpStreamRequest> io_callback_;
+ scoped_ptr<ClientSocketHandle> connection_;
+ scoped_refptr<HttpStreamFactory> factory_;
+ StreamFactory::StreamRequestDelegate* delegate_;
+ BoundNetLog net_log_;
+ State next_state_;
+ ProxyService::PacRequest* pac_request_;
+ SSLInfo ssl_info_;
+ // 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.
+ HostPortPair endpoint_;
+
+ // True if handling a HTTPS request, or using SPDY with SSL
+ bool using_ssl_;
+
+ // True if this network transaction is using SPDY instead of HTTP.
+ bool using_spdy_;
+
+ // Force spdy for all connections.
+ bool force_spdy_always_;
+
+ // Force spdy only for SSL connections.
+ bool force_spdy_over_ssl_;
+
+ // The certificate error while using SPDY over SSL for insecure URLs.
+ int spdy_certificate_error_;
+
+ scoped_refptr<HttpAuthController>
+ auth_controllers_[HttpAuth::AUTH_NUM_TARGETS];
+
+ AlternateProtocolMode alternate_protocol_mode_;
+
+ // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol.
+ HttpAlternateProtocols::Protocol alternate_protocol_;
+
+ // True when the tunnel is in the process of being established - we can't
+ // read from the socket until the tunnel is done.
+ bool establishing_tunnel_;
+
+ scoped_ptr<HttpStream> stream_;
+
+ // True if finding the connection for this request found an alternate
+ // protocol was available.
+ bool was_alternate_protocol_available_;
+
+ // True if we negotiated NPN.
+ bool was_npn_negotiated_;
+
+ // Indicates that this StreamRequest has been cancelled. Note that once
+ // this has been cancelled, input parameters passed into the StreamRequest
+ // can no longer be touched (as they belong to the requestor).
+ bool cancelled_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpStreamRequest);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_STREAM_REQUEST_H_
diff --git a/net/http/http_transaction.h b/net/http/http_transaction.h
index 103f8f6..690d521 100644
--- a/net/http/http_transaction.h
+++ b/net/http/http_transaction.h
@@ -1,12 +1,12 @@
-// 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.
#ifndef NET_HTTP_HTTP_TRANSACTION_H_
#define NET_HTTP_HTTP_TRANSACTION_H_
+#pragma once
-#include <string>
-
+#include "base/string16.h"
#include "net/base/completion_callback.h"
#include "net/base/load_states.h"
@@ -61,8 +61,8 @@ class HttpTransaction {
CompletionCallback* callback) = 0;
// Restarts the HTTP transaction with authentication credentials.
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
+ virtual int RestartWithAuth(const string16& username,
+ const string16& password,
CompletionCallback* callback) = 0;
// Returns true if auth is ready to be continued. Callers should check
diff --git a/net/http/http_transaction_factory.h b/net/http/http_transaction_factory.h
index 3d37ffe..0d0f642 100644
--- a/net/http/http_transaction_factory.h
+++ b/net/http/http_transaction_factory.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_TRANSACTION_FACTORY_H__
#define NET_HTTP_HTTP_TRANSACTION_FACTORY_H__
+#pragma once
#include "base/scoped_ptr.h"
diff --git a/net/http/http_transaction_unittest.h b/net/http/http_transaction_unittest.h
index e550903..3149534 100644
--- a/net/http/http_transaction_unittest.h
+++ b/net/http/http_transaction_unittest.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_
#define NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_
+#pragma once
#include "net/http/http_transaction.h"
@@ -13,10 +14,12 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/message_loop.h"
+#include "base/string16.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
@@ -224,8 +227,8 @@ class MockNetworkTransaction : public net::HttpTransaction {
if (t->handler)
(t->handler)(request, &resp_status, &resp_headers, &resp_data);
- std::string header_data =
- StringPrintf("%s\n%s\n", resp_status.c_str(), resp_headers.c_str());
+ std::string header_data = base::StringPrintf(
+ "%s\n%s\n", resp_status.c_str(), resp_headers.c_str());
std::replace(header_data.begin(), header_data.end(), '\n', '\0');
response_.request_time = base::Time::Now();
@@ -259,8 +262,8 @@ class MockNetworkTransaction : public net::HttpTransaction {
return net::ERR_FAILED;
}
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
+ virtual int RestartWithAuth(const string16& username,
+ const string16& password,
net::CompletionCallback* callback) {
return net::ERR_FAILED;
}
diff --git a/net/http/http_util.cc b/net/http/http_util.cc
index 8168102..1098a06 100644
--- a/net/http/http_util.cc
+++ b/net/http/http_util.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,7 +9,9 @@
#include <algorithm>
+#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "net/base/net_util.h"
@@ -244,7 +246,7 @@ bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier,
// Try to obtain first-byte-pos.
if (!first_byte_pos.empty()) {
int64 first_byte_position = -1;
- if (!StringToInt64(first_byte_pos, &first_byte_position))
+ if (!base::StringToInt64(first_byte_pos, &first_byte_position))
return false;
range.set_first_byte_position(first_byte_position);
}
@@ -259,7 +261,7 @@ bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier,
// We have last-byte-pos or suffix-byte-range-spec in this case.
if (!last_byte_pos.empty()) {
int64 last_byte_position;
- if (!StringToInt64(last_byte_pos, &last_byte_position))
+ if (!base::StringToInt64(last_byte_pos, &last_byte_position))
return false;
if (range.HasFirstBytePosition())
range.set_last_byte_position(last_byte_position);
@@ -629,6 +631,9 @@ HttpUtil::HeadersIterator::HeadersIterator(string::const_iterator headers_begin,
: lines_(headers_begin, headers_end, line_delimiter) {
}
+HttpUtil::HeadersIterator::~HeadersIterator() {
+}
+
bool HttpUtil::HeadersIterator::GetNext() {
while (lines_.GetNext()) {
name_begin_ = lines_.token_begin();
@@ -681,6 +686,9 @@ HttpUtil::ValuesIterator::ValuesIterator(
values_.set_quote_chars("\'\"");
}
+HttpUtil::ValuesIterator::~ValuesIterator() {
+}
+
bool HttpUtil::ValuesIterator::GetNext() {
while (values_.GetNext()) {
value_begin_ = values_.token_begin();
diff --git a/net/http/http_util.h b/net/http/http_util.h
index 447e490..776b876 100644
--- a/net/http/http_util.h
+++ b/net/http/http_util.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_UTIL_H_
#define NET_HTTP_HTTP_UTIL_H_
+#pragma once
#include <vector>
@@ -17,6 +18,8 @@
namespace net {
+class HttpStream;
+
class HttpUtil {
public:
// Returns the absolute path of the URL, to be used for the http request.
@@ -164,6 +167,7 @@ class HttpUtil {
HeadersIterator(std::string::const_iterator headers_begin,
std::string::const_iterator headers_end,
const std::string& line_delimiter);
+ ~HeadersIterator();
// Advances the iterator to the next header, if any. Returns true if there
// is a next header. Use name* and values* methods to access the resultant
@@ -226,6 +230,7 @@ class HttpUtil {
ValuesIterator(std::string::const_iterator values_begin,
std::string::const_iterator values_end,
char delimiter);
+ ~ValuesIterator();
// Advances the iterator to the next value, if any. Returns true if there
// is a next value. Use value* methods to access the resultant value.
diff --git a/net/http/http_vary_data.h b/net/http/http_vary_data.h
index 98b94fa..7e5cbb9 100644
--- a/net/http/http_vary_data.h
+++ b/net/http/http_vary_data.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_VARY_DATA_H__
#define NET_HTTP_HTTP_VARY_DATA_H__
+#pragma once
#include "base/md5.h"
diff --git a/net/http/http_version.h b/net/http/http_version.h
index 127e711..554de21 100644
--- a/net/http/http_version.h
+++ b/net/http/http_version.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_HTTP_VERSION_H_
#define NET_HTTP_HTTP_VERSION_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/net/http/md4.h b/net/http/md4.h
index b416e26..887f15f 100644
--- a/net/http/md4.h
+++ b/net/http/md4.h
@@ -43,6 +43,7 @@
#ifndef NET_HTTP_MD4_H_
#define NET_HTTP_MD4_H_
+#pragma once
#include "base/basictypes.h"
diff --git a/net/http/mock_gssapi_library_posix.cc b/net/http/mock_gssapi_library_posix.cc
index fed2ccd..d0a46b1 100644
--- a/net/http/mock_gssapi_library_posix.cc
+++ b/net/http/mock_gssapi_library_posix.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/third_party/gssapi/gssapi.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -312,9 +313,9 @@ OM_uint32 MockGSSAPILibrary::display_status(
gss_buffer_t status_string) {
if (minor_status)
*minor_status = 0;
- std::string msg = StringPrintf("Value: %u, Type %u",
- status_value,
- status_type);
+ std::string msg = base::StringPrintf("Value: %u, Type %u",
+ status_value,
+ status_type);
if (message_context)
*message_context = 0;
BufferFromString(msg, status_string);
diff --git a/net/http/mock_gssapi_library_posix.h b/net/http/mock_gssapi_library_posix.h
index a78fb00..15e14f2 100644
--- a/net/http/mock_gssapi_library_posix.h
+++ b/net/http/mock_gssapi_library_posix.h
@@ -4,9 +4,9 @@
#ifndef NET_HTTP_MOCK_GSSAPI_LIBRARY_POSIX_H_
#define NET_HTTP_MOCK_GSSAPI_LIBRARY_POSIX_H_
+#pragma once
#include <list>
-#include <set>
#include <string>
#include "base/gtest_prod_util.h"
diff --git a/net/http/mock_sspi_library_win.cc b/net/http/mock_sspi_library_win.cc
index d0dae51..c3d875c 100644
--- a/net/http/mock_sspi_library_win.cc
+++ b/net/http/mock_sspi_library_win.cc
@@ -50,6 +50,10 @@ SECURITY_STATUS MockSSPILibrary::InitializeSecurityContext(
uint8* buf = reinterpret_cast<uint8 *>(out_buffer->pvBuffer);
buf[0] = 0xAB;
buf[1] = 0xBA;
+
+ // Fill in phNewContext with arbitrary value if it's invalid.
+ if (phNewContext != phContext)
+ phNewContext->dwLower = phNewContext->dwUpper = ((ULONG_PTR) ((INT_PTR)0));
return SEC_E_OK;
}
@@ -75,8 +79,10 @@ SECURITY_STATUS MockSSPILibrary::FreeCredentialsHandle(
}
SECURITY_STATUS MockSSPILibrary::DeleteSecurityContext(PCtxtHandle phContext) {
- ADD_FAILURE();
- return ERROR_CALL_NOT_IMPLEMENTED;
+ EXPECT_TRUE(phContext->dwLower == ((ULONG_PTR) ((INT_PTR) 0)));
+ EXPECT_TRUE(phContext->dwLower == ((ULONG_PTR) ((INT_PTR) 0)));
+ SecInvalidateHandle(phContext);
+ return SEC_E_OK;
}
SECURITY_STATUS MockSSPILibrary::FreeContextBuffer(PVOID pvContextBuffer) {
diff --git a/net/http/mock_sspi_library_win.h b/net/http/mock_sspi_library_win.h
index eca3eb5..9d673b4 100644
--- a/net/http/mock_sspi_library_win.h
+++ b/net/http/mock_sspi_library_win.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_MOCK_SSPI_LIBRARY_WIN_H_
#define NET_HTTP_MOCK_SSPI_LIBRARY_WIN_H_
+#pragma once
#include <list>
#include <set>
diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc
index 49d68d2..54900b3 100644
--- a/net/http/partial_data.cc
+++ b/net/http/partial_data.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-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.
@@ -6,7 +6,9 @@
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_response_headers.h"
@@ -25,13 +27,13 @@ void AddRangeHeader(int64 start, int64 end, HttpRequestHeaders* headers) {
DCHECK(start >= 0 || end >= 0);
std::string my_start, my_end;
if (start >= 0)
- my_start = Int64ToString(start);
+ my_start = base::Int64ToString(start);
if (end >= 0)
- my_end = Int64ToString(end);
+ my_end = base::Int64ToString(end);
headers->SetHeader(
HttpRequestHeaders::kRange,
- StringPrintf("bytes=%s-%s", my_start.c_str(), my_end.c_str()));
+ base::StringPrintf("bytes=%s-%s", my_start.c_str(), my_end.c_str()));
}
} // namespace
@@ -348,11 +350,11 @@ void PartialData::FixResponseHeaders(HttpResponseHeaders* headers) {
DCHECK(byte_range_.HasFirstBytePosition());
DCHECK(byte_range_.HasLastBytePosition());
headers->AddHeader(
- StringPrintf("%s: bytes %" PRId64 "-%" PRId64 "/%" PRId64,
- kRangeHeader,
- byte_range_.first_byte_position(),
- byte_range_.last_byte_position(),
- resource_size_));
+ base::StringPrintf("%s: bytes %" PRId64 "-%" PRId64 "/%" PRId64,
+ kRangeHeader,
+ byte_range_.first_byte_position(),
+ byte_range_.last_byte_position(),
+ resource_size_));
range_len = byte_range_.last_byte_position() -
byte_range_.first_byte_position() + 1;
} else {
@@ -362,13 +364,14 @@ void PartialData::FixResponseHeaders(HttpResponseHeaders* headers) {
range_len = resource_size_;
}
- headers->AddHeader(StringPrintf("%s: %" PRId64, kLengthHeader, range_len));
+ headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader,
+ range_len));
}
void PartialData::FixContentLength(HttpResponseHeaders* headers) {
headers->RemoveHeader(kLengthHeader);
- headers->AddHeader(StringPrintf("%s: %" PRId64, kLengthHeader,
- resource_size_));
+ headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader,
+ resource_size_));
}
int PartialData::CacheRead(disk_cache::Entry* entry, IOBuffer* data,
diff --git a/net/http/partial_data.h b/net/http/partial_data.h
index b720e6e..22e0c8b 100644
--- a/net/http/partial_data.h
+++ b/net/http/partial_data.h
@@ -1,11 +1,10 @@
-// Copyright (c) 2009-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.
#ifndef NET_HTTP_PARTIAL_DATA_H_
#define NET_HTTP_PARTIAL_DATA_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "net/base/completion_callback.h"
diff --git a/net/http/stream_factory.h b/net/http/stream_factory.h
new file mode 100644
index 0000000..9ec85f1
--- /dev/null
+++ b/net/http/stream_factory.h
@@ -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.
+
+#ifndef NET_HTTP_STREAM_FACTORY_H_
+#define NET_HTTP_STREAM_FACTORY_H_
+
+#include <string>
+
+#include "base/ref_counted.h"
+#include "net/base/load_states.h"
+
+namespace net {
+
+class BoundNetLog;
+class HostPortPair;
+class HttpAlternateProtocols;
+class HttpAuthController;
+class HttpNetworkSession;
+class HttpResponseInfo;
+class HttpStream;
+class ProxyInfo;
+class SSLCertRequestInfo;
+class SSLInfo;
+class X509Certificate;
+struct HttpRequestInfo;
+struct SSLConfig;
+
+// The StreamFactory defines an interface for creating usable HttpStreams.
+class StreamFactory {
+ public:
+ // The StreamRequestDelegate is a set of callback methods for a
+ // StreamRequestJob. Generally, only one of these methods will be
+ // called as a result of a stream request.
+ class StreamRequestDelegate {
+ public:
+ virtual ~StreamRequestDelegate() {}
+
+ // This is the success case.
+ // |stream| is now owned by the delegate.
+ virtual void OnStreamReady(HttpStream* stream) = 0;
+
+ // This is the failure to create a stream case.
+ virtual void OnStreamFailed(int status) = 0;
+
+ // Called when we have a certificate error for the request.
+ virtual void OnCertificateError(int status, const SSLInfo& ssl_info) = 0;
+
+ // This is the failure case where we need proxy authentication during
+ // proxy tunnel establishment. For the tunnel case, we were unable to
+ // create the HttpStream, so the caller provides the auth and then resumes
+ // the StreamRequest. For the non-tunnel case, the caller will handle
+ // the authentication failure and restart the StreamRequest entirely.
+ // Ownership of |auth_controller| and |proxy_response| are owned
+ // by the StreamRequest. |proxy_response| is not guaranteed to be usable
+ // after the lifetime of this callback. The delegate may take a reference
+ // to |auth_controller| if it is needed beyond the lifetime of this
+ // callback.
+ virtual void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response,
+ HttpAuthController* auth_controller) = 0;
+
+ // This is the failure for SSL Client Auth
+ // Ownership of |cert_info| is retained by the StreamRequest. The delegate
+ // may take a reference if it needs the cert_info beyond the lifetime of
+ // this callback.
+ virtual void OnNeedsClientAuth(SSLCertRequestInfo* cert_info) = 0;
+ };
+
+ // The StreamRequestJob is the worker object which handles the creation
+ // of an HttpStream. While the HttpStream is being created, this job
+ // is the creator's handle for interacting with the HttpStream creation
+ // process.
+ class StreamRequestJob : public base::RefCounted<StreamRequestJob> {
+ public:
+ virtual ~StreamRequestJob() {}
+
+ // Start initiates the process of creating a new HttpStream.
+ // 3 parameters are passed in by reference. The caller asserts that the
+ // lifecycle of these parameters will remain valid until the stream is
+ // created, failed, or until the caller calls Cancel() on the stream
+ // request. In all cases, the delegate will be called to notify
+ // completion of the request.
+ virtual void Start(const HttpRequestInfo* request_info,
+ SSLConfig* ssl_config,
+ ProxyInfo* proxy_info,
+ StreamRequestDelegate* delegate,
+ const BoundNetLog& net_log) = 0;
+
+ // Cancel can be used to abort the HttpStream creation. Once cancelled,
+ // the delegates associated with the request will not be invoked.
+ virtual void Cancel() = 0;
+
+ // When a HttpStream creation process requires a SSL Certificate,
+ // the delegate OnNeedsClientAuth handler will have been called.
+ // It now becomes the delegate's responsibility to collect the certificate
+ // (probably from the user), and then call this method to resume
+ // the HttpStream creation process.
+ // Ownership of |client_cert| remains with the StreamRequest. The
+ // delegate can take a reference if needed beyond the lifetime of this
+ // call.
+ virtual int RestartWithCertificate(X509Certificate* client_cert) = 0;
+
+ // When a HttpStream creation process is stalled due to necessity
+ // of Proxy authentication credentials, the delegate OnNeedsProxyAuth
+ // will have been called. It now becomes the delegate's responsibility
+ // to collect the necessary credentials, and then call this method to
+ // resume the HttpStream creation process.
+ virtual int RestartTunnelWithProxyAuth(const string16& username,
+ const string16& password) = 0;
+
+ // Returns the LoadState for the request.
+ virtual LoadState GetLoadState() const = 0;
+
+ // Returns true if an AlternateProtocol for this request was available.
+ virtual bool was_alternate_protocol_available() const = 0;
+
+ // Returns true if TLS/NPN was negotiated for this stream.
+ virtual bool was_npn_negotiated() const = 0;
+
+ // Returns true if this stream is being fetched over SPDY.
+ virtual bool using_spdy() const = 0;
+ };
+
+ virtual ~StreamFactory() {}
+
+ // Request a stream.
+ // Will callback to the StreamRequestDelegate upon completion.
+ virtual void RequestStream(const HttpRequestInfo* info,
+ SSLConfig* ssl_config,
+ ProxyInfo* proxy_info,
+ StreamRequestDelegate* delegate,
+ const BoundNetLog& net_log,
+ const scoped_refptr<HttpNetworkSession>& session,
+ scoped_refptr<StreamRequestJob>* stream) = 0;
+
+ // TLS Intolerant Server API
+ virtual void AddTLSIntolerantServer(const GURL& url) = 0;
+ virtual bool IsTLSIntolerantServer(const GURL& url) = 0;
+
+ // Alternate Protocol API
+ virtual void ProcessAlternateProtocol(
+ HttpAlternateProtocols* alternate_protocols,
+ const std::string& alternate_protocol_str,
+ const HostPortPair& http_host_port_pair) = 0;
+};
+
+} // namespace net
+
+#endif // NET_HTTP_STREAM_FACTORY_H_
diff --git a/net/http/url_security_manager.cc b/net/http/url_security_manager.cc
index d3bc42e..d848644 100644
--- a/net/http/url_security_manager.cc
+++ b/net/http/url_security_manager.cc
@@ -9,13 +9,22 @@
namespace net {
URLSecurityManagerWhitelist::URLSecurityManagerWhitelist(
- HttpAuthFilter* whitelist) : whitelist_(whitelist) {
+ const HttpAuthFilter* whitelist_default,
+ const HttpAuthFilter* whitelist_delegate)
+ : whitelist_default_(whitelist_default),
+ whitelist_delegate_(whitelist_delegate) {
}
bool URLSecurityManagerWhitelist::CanUseDefaultCredentials(
- const GURL& auth_origin) {
- if (whitelist_.get())
- return whitelist_->IsValid(auth_origin, HttpAuth::AUTH_SERVER);
+ const GURL& auth_origin) const {
+ if (whitelist_default_.get())
+ return whitelist_default_->IsValid(auth_origin, HttpAuth::AUTH_SERVER);
+ return false;
+}
+
+bool URLSecurityManagerWhitelist::CanDelegate(const GURL& auth_origin) const {
+ if (whitelist_delegate_.get())
+ return whitelist_delegate_->IsValid(auth_origin, HttpAuth::AUTH_SERVER);
return false;
}
diff --git a/net/http/url_security_manager.h b/net/http/url_security_manager.h
index cd80a7d..5e148b4 100644
--- a/net/http/url_security_manager.h
+++ b/net/http/url_security_manager.h
@@ -4,6 +4,7 @@
#ifndef NET_HTTP_URL_SECURITY_MANAGER_H_
#define NET_HTTP_URL_SECURITY_MANAGER_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "base/basictypes.h"
@@ -22,12 +23,34 @@ class URLSecurityManager {
virtual ~URLSecurityManager() {}
// Creates a platform-dependent instance of URLSecurityManager.
- // The URLSecurityManager takes ownership of the HttpAuthFilter.
- static URLSecurityManager* Create(HttpAuthFilter* whitelist);
+ //
+ // |whitelist_default| is the whitelist of servers that default credentials
+ // can be used with during NTLM or Negotiate authentication. If
+ // |whitelist_default| is NULL and the platform is Windows, it indicates
+ // that security zone mapping should be used to determine whether default
+ // credentials sxhould be used. If |whitelist_default| is NULL and the
+ // platform is non-Windows, it indicates that no servers should be
+ // whitelisted.
+ //
+ // |whitelist_delegate| is the whitelist of servers that are allowed
+ // to have Delegated Kerberos tickets. If |whitelist_delegate| is NULL,
+ // no servers can have delegated Kerberos tickets.
+ //
+ // Both |whitelist_default| and |whitelist_delegate| will be owned by
+ // the created URLSecurityManager.
+ //
+ // TODO(cbentzel): Perhaps it's better to make a non-abstract HttpAuthFilter
+ // and just copy into the URLSecurityManager?
+ static URLSecurityManager* Create(const HttpAuthFilter* whitelist_default,
+ const HttpAuthFilter* whitelist_delegate);
// Returns true if we can send the default credentials to the server at
// |auth_origin| for HTTP NTLM or Negotiate authentication.
- virtual bool CanUseDefaultCredentials(const GURL& auth_origin) = 0;
+ virtual bool CanUseDefaultCredentials(const GURL& auth_origin) const = 0;
+
+ // Returns true if Kerberos delegation is allowed for the server at
+ // |auth_origin| for HTTP Negotiate authentication.
+ virtual bool CanDelegate(const GURL& auth_origin) const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(URLSecurityManager);
@@ -35,26 +58,32 @@ class URLSecurityManager {
class URLSecurityManagerWhitelist : public URLSecurityManager {
public:
- // The URLSecurityManagerWhitelist takes ownership of the HttpAuthFilter.
- explicit URLSecurityManagerWhitelist(HttpAuthFilter* whitelist);
+ // The URLSecurityManagerWhitelist takes ownership of the whitelists.
+ URLSecurityManagerWhitelist(const HttpAuthFilter* whitelist_default,
+ const HttpAuthFilter* whitelist_delegation);
// URLSecurityManager methods.
- virtual bool CanUseDefaultCredentials(const GURL& auth_origin);
+ virtual bool CanUseDefaultCredentials(const GURL& auth_origin) const;
+ virtual bool CanDelegate(const GURL& auth_origin) const;
private:
- scoped_ptr<HttpAuthFilter> whitelist_;
+ scoped_ptr<const HttpAuthFilter> whitelist_default_;
+ scoped_ptr<const HttpAuthFilter> whitelist_delegate_;
DISALLOW_COPY_AND_ASSIGN(URLSecurityManagerWhitelist);
};
#if defined(UNIT_TEST)
-// An URLSecurityManager which always allows default credentials.
+// An URLSecurityManager which is very permissive.
class URLSecurityManagerAllow : public URLSecurityManager {
public:
URLSecurityManagerAllow() {}
virtual ~URLSecurityManagerAllow() {}
- virtual bool CanUseDefaultCredentials(const GURL& auth_origin) {
+ virtual bool CanUseDefaultCredentials(const GURL& auth_origin) const {
+ return true;
+ }
+ virtual bool CanDelegate(const GURL& auth_origin) const {
return true;
}
diff --git a/net/http/url_security_manager_posix.cc b/net/http/url_security_manager_posix.cc
index 931d9cc..d3b42fb 100644
--- a/net/http/url_security_manager_posix.cc
+++ b/net/http/url_security_manager_posix.cc
@@ -10,8 +10,9 @@ namespace net {
// static
URLSecurityManager* URLSecurityManager::Create(
- HttpAuthFilter* whitelist) {
- return new URLSecurityManagerWhitelist(whitelist);
+ const HttpAuthFilter* whitelist_default,
+ const HttpAuthFilter* whitelist_delegate) {
+ return new URLSecurityManagerWhitelist(whitelist_default, whitelist_delegate);
}
} // namespace net
diff --git a/net/http/url_security_manager_unittest.cc b/net/http/url_security_manager_unittest.cc
index b08a7b2..45d93c9 100644
--- a/net/http/url_security_manager_unittest.cc
+++ b/net/http/url_security_manager_unittest.cc
@@ -43,11 +43,13 @@ const TestData kTestDataList[] = {
} // namespace
-// For Windows, This relies on the contents of the registry, so in theory it
-// might fail.
-TEST(URLSecurityManager, FLAKY_CreateNoWhitelist) {
+TEST(URLSecurityManager, UseDefaultCredentials) {
+ HttpAuthFilterWhitelist* auth_filter = new HttpAuthFilterWhitelist(
+ kTestAuthWhitelist);
+ ASSERT_TRUE(auth_filter);
+ // The URL security manager takes ownership of |auth_filter|.
scoped_ptr<URLSecurityManager> url_security_manager(
- URLSecurityManager::Create(NULL));
+ URLSecurityManager::Create(auth_filter, NULL));
ASSERT_TRUE(url_security_manager.get());
for (size_t i = 0; i < arraysize(kTestDataList); ++i) {
@@ -55,34 +57,40 @@ TEST(URLSecurityManager, FLAKY_CreateNoWhitelist) {
bool can_use_default =
url_security_manager->CanUseDefaultCredentials(gurl);
-#if defined(OS_WIN)
- EXPECT_EQ(kTestDataList[i].succeds_in_windows_default, can_use_default)
- << " Run: " << i << " URL: '" << gurl << "'";
-#else
- // No whitelist means nothing can use the default.
- EXPECT_FALSE(can_use_default)
+ EXPECT_EQ(kTestDataList[i].succeeds_in_whitelist, can_use_default)
<< " Run: " << i << " URL: '" << gurl << "'";
-#endif // OS_WIN
}
}
-TEST(URLSecurityManager, CreateWhitelist) {
- HttpAuthFilterWhitelist* auth_filter = new HttpAuthFilterWhitelist();
+TEST(URLSecurityManager, CanDelegate) {
+ HttpAuthFilterWhitelist* auth_filter = new HttpAuthFilterWhitelist(
+ kTestAuthWhitelist);
ASSERT_TRUE(auth_filter);
- auth_filter->SetWhitelist(kTestAuthWhitelist);
// The URL security manager takes ownership of |auth_filter|.
scoped_ptr<URLSecurityManager> url_security_manager(
- URLSecurityManager::Create(auth_filter));
+ URLSecurityManager::Create(NULL, auth_filter));
ASSERT_TRUE(url_security_manager.get());
for (size_t i = 0; i < arraysize(kTestDataList); ++i) {
GURL gurl(kTestDataList[i].url);
- bool can_use_default =
- url_security_manager->CanUseDefaultCredentials(gurl);
-
- EXPECT_EQ(kTestDataList[i].succeeds_in_whitelist, can_use_default)
+ bool can_delegate = url_security_manager->CanDelegate(gurl);
+ EXPECT_EQ(kTestDataList[i].succeeds_in_whitelist, can_delegate)
<< " Run: " << i << " URL: '" << gurl << "'";
}
}
+TEST(URLSecurityManager, CanDelegate_NoWhitelist) {
+ // Nothing can delegate in this case.
+ scoped_ptr<URLSecurityManager> url_security_manager(
+ URLSecurityManager::Create(NULL, NULL));
+ ASSERT_TRUE(url_security_manager.get());
+
+ for (size_t i = 0; i < arraysize(kTestDataList); ++i) {
+ GURL gurl(kTestDataList[i].url);
+ bool can_delegate = url_security_manager->CanDelegate(gurl);
+ EXPECT_EQ(false, can_delegate);
+ }
+}
+
+
} // namespace net
diff --git a/net/http/url_security_manager_win.cc b/net/http/url_security_manager_win.cc
index 4eaef78..1770a19 100644
--- a/net/http/url_security_manager_win.cc
+++ b/net/http/url_security_manager_win.cc
@@ -9,7 +9,9 @@
#include "base/scoped_comptr_win.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
+#include "net/http/http_auth_filter.h"
// The Windows implementation of URLSecurityManager uses WinINet/IE's
// URL security zone manager. See the MSDN page "URL Security Zones" at
@@ -26,32 +28,30 @@ namespace net {
class URLSecurityManagerWin : public URLSecurityManager {
public:
- URLSecurityManagerWin();
+ explicit URLSecurityManagerWin(const HttpAuthFilter* whitelist_delegate);
// URLSecurityManager methods:
- virtual bool CanUseDefaultCredentials(const GURL& auth_origin);
+ virtual bool CanUseDefaultCredentials(const GURL& auth_origin) const;
+ virtual bool CanDelegate(const GURL& auth_origin) const;
private:
+ bool EnsureSystemSecurityManager();
+
ScopedComPtr<IInternetSecurityManager> security_manager_;
+ scoped_ptr<const HttpAuthFilter> whitelist_delegate_;
DISALLOW_COPY_AND_ASSIGN(URLSecurityManagerWin);
};
-URLSecurityManagerWin::URLSecurityManagerWin() {
+URLSecurityManagerWin::URLSecurityManagerWin(
+ const HttpAuthFilter* whitelist_delegate)
+ : whitelist_delegate_(whitelist_delegate) {
}
-
bool URLSecurityManagerWin::CanUseDefaultCredentials(
- const GURL& auth_origin) {
- if (!security_manager_) {
- HRESULT hr = CoInternetCreateSecurityManager(NULL,
- security_manager_.Receive(),
- NULL);
- if (FAILED(hr) || !security_manager_) {
- LOG(ERROR) << "Unable to create the Windows Security Manager instance";
- return false;
- }
- }
+ const GURL& auth_origin) const {
+ if (!const_cast<URLSecurityManagerWin*>(this)->EnsureSystemSecurityManager())
+ return false;
std::wstring url_w = ASCIIToWide(auth_origin.spec());
DWORD policy = 0;
@@ -102,13 +102,36 @@ bool URLSecurityManagerWin::CanUseDefaultCredentials(
}
}
+bool URLSecurityManagerWin::CanDelegate(const GURL& auth_origin) const {
+ // TODO(cbentzel): Could this just use the security zone as well? Apparently
+ // this is what IE does as well.
+ if (whitelist_delegate_.get())
+ return whitelist_delegate_->IsValid(auth_origin, HttpAuth::AUTH_SERVER);
+ return false;
+}
+
+bool URLSecurityManagerWin::EnsureSystemSecurityManager() {
+ if (!security_manager_) {
+ HRESULT hr = CoInternetCreateSecurityManager(NULL,
+ security_manager_.Receive(),
+ NULL);
+ if (FAILED(hr) || !security_manager_) {
+ LOG(ERROR) << "Unable to create the Windows Security Manager instance";
+ return false;
+ }
+ }
+ return true;
+}
+
// static
URLSecurityManager* URLSecurityManager::Create(
- HttpAuthFilter* whitelist) {
+ const HttpAuthFilter* whitelist_default,
+ const HttpAuthFilter* whitelist_delegate) {
// If we have a whitelist, just use that.
- if (whitelist)
- return new URLSecurityManagerWhitelist(whitelist);
- return new URLSecurityManagerWin();
+ if (whitelist_default)
+ return new URLSecurityManagerWhitelist(whitelist_default,
+ whitelist_delegate);
+ return new URLSecurityManagerWin(whitelist_delegate);
}
} // namespace net
diff --git a/net/http_listen_socket.target.mk b/net/http_listen_socket.target.mk
index 9a98489..d19087f 100644
--- a/net/http_listen_socket.target.mk
+++ b/net/http_listen_socket.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -70,6 +71,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -128,11 +130,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/net/net.Makefile b/net/net.Makefile
index 3ac1873..5df3938 100644
--- a/net/net.Makefile
+++ b/net/net.Makefile
@@ -3,4 +3,4 @@
export builddir_name ?= /usr/local/google/src/chromium-merge/src/net/out
.PHONY: all
all:
- $(MAKE) -C .. net_resources net_base tld_cleanup net hresolv net_test_support fetch_client http_listen_socket fetch_server run_testserver net_perftests crash_cache net_unittests stress_cache
+ $(MAKE) -C .. ssl_false_start_blacklist_process net_resources tld_cleanup net_base hresolv dnssec_chain_verify net net_test_support http_listen_socket fetch_server fetch_client net_unittests net_perftests run_testserver stress_cache crash_cache
diff --git a/net/net.gyp b/net/net.gyp
index 1dcaf25..5bc0bd8 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -19,6 +19,7 @@
'../third_party/icu/icu.gyp:icuuc',
'../third_party/zlib/zlib.gyp:zlib',
'net_resources',
+ 'ssl_false_start_blacklist_process#host',
],
'sources': [
'base/address_family.h',
@@ -26,10 +27,12 @@
'base/address_list.h',
'base/address_list_net_log_param.cc',
'base/address_list_net_log_param.h',
+ 'base/auth.cc',
'base/auth.h',
'base/cache_type.h',
'base/capturing_net_log.cc',
'base/capturing_net_log.h',
+ 'base/cert_database.cc',
'base/cert_database.h',
'base/cert_database_mac.cc',
'base/cert_database_nss.cc',
@@ -51,8 +54,17 @@
'base/data_url.h',
'base/directory_lister.cc',
'base/directory_lister.h',
+ 'base/dns_reload_timer.cc',
+ 'base/dns_reload_timer.h',
+ 'base/dnssec_chain_verifier.cc',
+ 'base/dnssec_chain_verifier.h',
+ 'base/dnssec_keyset.cc',
+ 'base/dnssec_keyset.h',
+ 'base/dnssec_proto.h',
'base/dns_util.cc',
'base/dns_util.h',
+ 'base/dnsrr_resolver.cc',
+ 'base/dnsrr_resolver.h',
'base/escape.cc',
'base/escape.h',
'base/ev_root_ca_metadata.cc',
@@ -123,8 +135,12 @@
'base/network_change_notifier_netlink_linux.h',
'base/network_change_notifier_win.cc',
'base/network_change_notifier_win.h',
+ 'base/network_config_watcher_mac.cc',
+ 'base/network_config_watcher_mac.h',
'base/nss_memio.c',
'base/nss_memio.h',
+ 'base/pem_tokenizer.cc',
+ 'base/pem_tokenizer.h',
'base/platform_mime_util.h',
# TODO(tc): gnome-vfs? xdgmime? /etc/mime.types?
'base/platform_mime_util_linux.cc',
@@ -137,6 +153,7 @@
'base/sdch_filter.h',
'base/sdch_manager.cc',
'base/sdch_manager.h',
+ 'base/ssl_cert_request_info.cc',
'base/ssl_cert_request_info.h',
'base/ssl_cipher_suite_names.cc',
'base/ssl_cipher_suite_names.h',
@@ -144,19 +161,20 @@
'base/ssl_client_auth_cache.h',
'base/ssl_config_service.cc',
'base/ssl_config_service.h',
+ 'base/ssl_config_service_defaults.cc',
'base/ssl_config_service_defaults.h',
'base/ssl_config_service_mac.cc',
'base/ssl_config_service_mac.h',
'base/ssl_config_service_win.cc',
'base/ssl_config_service_win.h',
+ 'base/ssl_false_start_blacklist.cc',
+ 'base/ssl_info.cc',
'base/ssl_info.h',
'base/static_cookie_policy.cc',
'base/static_cookie_policy.h',
'base/transport_security_state.cc',
'base/transport_security_state.h',
'base/sys_addrinfo.h',
- 'base/telnet_server.cc',
- 'base/telnet_server.h',
'base/test_completion_callback.h',
'base/upload_data.cc',
'base/upload_data.h',
@@ -174,16 +192,42 @@
'base/x509_cert_types_mac.cc',
'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
'third_party/mozilla_security_manager/nsKeygenHandler.h',
+ 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp',
+ 'third_party/mozilla_security_manager/nsNSSCertificateDB.h',
+ 'third_party/mozilla_security_manager/nsNSSCertTrust.cpp',
+ 'third_party/mozilla_security_manager/nsNSSCertTrust.h',
+ 'third_party/mozilla_security_manager/nsPKCS12Blob.cpp',
+ 'third_party/mozilla_security_manager/nsPKCS12Blob.h',
],
'export_dependent_settings': [
'../base/base.gyp:base',
],
+ 'actions': [
+ {
+ 'action_name': 'ssl_false_start_blacklist',
+ 'inputs': [
+ '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)ssl_false_start_blacklist_process<(EXECUTABLE_SUFFIX)',
+ 'base/ssl_false_start_blacklist.txt',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/net/base/ssl_false_start_blacklist_data.cc',
+ ],
+ 'action':
+ ['<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)ssl_false_start_blacklist_process<(EXECUTABLE_SUFFIX)',
+ 'base/ssl_false_start_blacklist.txt',
+ '<(SHARED_INTERMEDIATE_DIR)/net/base/ssl_false_start_blacklist_data.cc',
+ ],
+ 'message': 'Generating SSL False Start blacklist',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
'conditions': [
[ 'OS == "linux" or OS == "freebsd" or OS == "openbsd"', {
'dependencies': [
'../build/linux/system.gyp:gconf',
'../build/linux/system.gyp:gdk',
'../build/linux/system.gyp:nss',
+ '../build/linux/system.gyp:libresolv',
],
},
{ # else: OS is not in the above list
@@ -193,13 +237,18 @@
'base/x509_certificate_nss.cc',
'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
'third_party/mozilla_security_manager/nsKeygenHandler.h',
+ 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp',
+ 'third_party/mozilla_security_manager/nsNSSCertificateDB.h',
+ 'third_party/mozilla_security_manager/nsNSSCertTrust.cpp',
+ 'third_party/mozilla_security_manager/nsNSSCertTrust.h',
+ 'third_party/mozilla_security_manager/nsPKCS12Blob.cpp',
+ 'third_party/mozilla_security_manager/nsPKCS12Blob.h',
],
},
],
[ 'OS == "win"', {
'dependencies': [
- # For nss_memio.{c,h}, which require only NSPR.
- '../third_party/nss/nss.gyp:nspr',
+ '../third_party/nss/nss.gyp:nss',
'tld_cleanup',
],
},
@@ -214,13 +263,13 @@
],
[ 'OS == "mac"', {
'dependencies': [
- # For nss_memio.{c,h}, which require only NSPR.
- '../third_party/nss/nss.gyp:nspr',
+ '../third_party/nss/nss.gyp:nss',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Security.framework',
'$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
+ '$(SDKROOT)/usr/lib/libresolv.dylib',
]
},
},
@@ -260,6 +309,7 @@
'disk_cache/errors.h',
'disk_cache/eviction.cc',
'disk_cache/eviction.h',
+ 'disk_cache/experiments.h',
'disk_cache/file.h',
'disk_cache/file_block.h',
'disk_cache/file_lock.cc',
@@ -327,6 +377,8 @@
'ftp/ftp_util.h',
'http/des.cc',
'http/des.h',
+ 'http/disk_cache_based_ssl_host_info.cc',
+ 'http/disk_cache_based_ssl_host_info.h',
'http/http_alternate_protocols.cc',
'http/http_alternate_protocols.h',
'http/http_atom_list.h',
@@ -378,13 +430,19 @@
'http/http_request_headers.cc',
'http/http_request_headers.h',
'http/http_request_info.h',
+ 'http/http_response_body_drainer.cc',
+ 'http/http_response_body_drainer.h',
'http/http_response_headers.cc',
'http/http_response_headers.h',
'http/http_response_info.cc',
'http/http_response_info.h',
'http/http_stream.h',
+ 'http/http_stream_factory.cc',
+ 'http/http_stream_factory.h',
'http/http_stream_parser.cc',
'http/http_stream_parser.h',
+ 'http/http_stream_request.cc',
+ 'http/http_stream_request.h',
'http/http_transaction.h',
'http/http_transaction_factory.h',
'http/url_security_manager.h',
@@ -405,12 +463,15 @@
'http/md4.h',
'http/partial_data.cc',
'http/partial_data.h',
+ 'http/stream_factory.h',
'ocsp/nss_ocsp.cc',
'ocsp/nss_ocsp.h',
'proxy/init_proxy_resolver.cc',
'proxy/init_proxy_resolver.h',
'proxy/multi_threaded_proxy_resolver.cc',
'proxy/multi_threaded_proxy_resolver.h',
+ 'proxy/polling_proxy_config_service.cc',
+ 'proxy/polling_proxy_config_service.h',
'proxy/proxy_bypass_rules.cc',
'proxy/proxy_bypass_rules.h',
'proxy/proxy_config.cc',
@@ -450,6 +511,7 @@
'proxy/proxy_service.h',
'proxy/sync_host_resolver_bridge.cc',
'proxy/sync_host_resolver_bridge.h',
+ 'socket/client_socket.cc',
'socket/client_socket.h',
'socket/client_socket_factory.cc',
'socket/client_socket_factory.h',
@@ -461,6 +523,8 @@
'socket/client_socket_pool_base.h',
'socket/client_socket_pool_histograms.cc',
'socket/client_socket_pool_histograms.h',
+ 'socket/client_socket_pool_manager.cc',
+ 'socket/client_socket_pool_manager.h',
'socket/socket.h',
'socket/socks5_client_socket.cc',
'socket/socks5_client_socket.h',
@@ -477,6 +541,8 @@
'socket/ssl_client_socket_nss.h',
'socket/ssl_client_socket_nss_factory.cc',
'socket/ssl_client_socket_nss_factory.h',
+ 'socket/ssl_client_socket_openssl.cc',
+ 'socket/ssl_client_socket_openssl.h',
'socket/ssl_client_socket_pool.cc',
'socket/ssl_client_socket_pool.h',
'socket/ssl_client_socket_win.cc',
@@ -488,7 +554,6 @@
'socket/tcp_client_socket_pool.h',
'socket/tcp_client_socket_win.cc',
'socket/tcp_client_socket_win.h',
- 'socket/tcp_pinger.h',
'socket_stream/socket_stream.cc',
'socket_stream/socket_stream.h',
'socket_stream/socket_stream_job.cc',
@@ -504,10 +569,10 @@
'spdy/spdy_framer.h',
'spdy/spdy_http_stream.cc',
'spdy/spdy_http_stream.h',
+ 'spdy/spdy_http_utils.cc',
+ 'spdy/spdy_http_utils.h',
'spdy/spdy_io_buffer.cc',
'spdy/spdy_io_buffer.h',
- 'spdy/spdy_network_transaction.cc',
- 'spdy/spdy_network_transaction.h',
'spdy/spdy_protocol.h',
'spdy/spdy_session.cc',
'spdy/spdy_session.h',
@@ -517,13 +582,13 @@
'spdy/spdy_settings_storage.h',
'spdy/spdy_stream.cc',
'spdy/spdy_stream.h',
- 'spdy/spdy_transaction_factory.h',
'url_request/https_prober.h',
'url_request/https_prober.cc',
'url_request/url_request.cc',
'url_request/url_request.h',
'url_request/url_request_about_job.cc',
'url_request/url_request_about_job.h',
+ 'url_request/url_request_context.cc',
'url_request/url_request_context.h',
'url_request/url_request_data_job.cc',
'url_request/url_request_data_job.h',
@@ -570,6 +635,7 @@
'websockets/websocket_handshake_handler.h',
'websockets/websocket_job.cc',
'websockets/websocket_job.h',
+ 'websockets/websocket_net_log_params.h',
'websockets/websocket_throttle.cc',
'websockets/websocket_throttle.h',
],
@@ -582,6 +648,24 @@
'../v8/tools/gyp/v8.gyp:v8',
],
}],
+ ['chromeos==1', {
+ 'sources!': [
+ 'proxy/proxy_config_service_linux.cc',
+ 'proxy/proxy_config_service_linux.h',
+ ],
+ }],
+ ['use_openssl==1 and OS == "linux"', {
+ 'dependencies': [
+ '../build/linux/system.gyp:openssl',
+ ]
+ },
+ { # else !use_openssl: remove the unneeded files
+ 'sources!': [
+ 'socket/ssl_client_socket_openssl.cc',
+ 'socket/ssl_client_socket_openssl.h',
+ ],
+ },
+ ],
[ 'OS == "linux" or OS == "freebsd" or OS == "openbsd"', {
'dependencies': [
'../build/linux/system.gyp:gconf',
@@ -647,6 +731,7 @@
'net_test_support',
'../base/base.gyp:base',
'../base/base.gyp:base_i18n',
+ '../base/base.gyp:test_support_base',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'../third_party/zlib/zlib.gyp:zlib',
@@ -654,10 +739,13 @@
'msvs_guid': 'E99DA267-BE90-4F45-88A1-6919DB2C7567',
'sources': [
'base/address_list_unittest.cc',
+ 'base/cert_database_nss_unittest.cc',
'base/cookie_monster_unittest.cc',
'base/data_url_unittest.cc',
'base/directory_lister_unittest.cc',
+ 'base/dnssec_unittest.cc',
'base/dns_util_unittest.cc',
+ 'base/dnsrr_resolver_unittest.cc',
'base/escape_unittest.cc',
'base/file_stream_unittest.cc',
'base/filter_unittest.cc',
@@ -675,19 +763,20 @@
'base/mime_sniffer_unittest.cc',
'base/mime_util_unittest.cc',
'base/net_log_unittest.h',
- 'base/net_test_constants.h',
'base/net_test_suite.h',
'base/net_util_unittest.cc',
+ 'base/pem_tokenizer_unittest.cc',
'base/registry_controlled_domain_unittest.cc',
'base/run_all_unittests.cc',
'base/sdch_filter_unittest.cc',
'base/ssl_cipher_suite_names_unittest.cc',
'base/ssl_client_auth_cache_unittest.cc',
'base/ssl_config_service_mac_unittest.cc',
+ 'base/ssl_config_service_unittest.cc',
'base/ssl_config_service_win_unittest.cc',
+ 'base/ssl_false_start_blacklist_unittest.cc',
'base/static_cookie_policy_unittest.cc',
'base/transport_security_state_unittest.cc',
- 'base/telnet_server_unittest.cc',
'base/test_certificate_data.h',
'base/test_completion_callback_unittest.cc',
'base/upload_data_stream_unittest.cc',
@@ -733,6 +822,7 @@
'http/http_network_transaction_unittest.cc',
'http/http_proxy_client_socket_pool_unittest.cc',
'http/http_request_headers_unittest.cc',
+ 'http/http_response_body_drainer_unittest.cc',
'http/http_response_headers_unittest.cc',
'http/http_transaction_unittest.cc',
'http/http_transaction_unittest.h',
@@ -765,7 +855,6 @@
'socket/ssl_client_socket_pool_unittest.cc',
'socket/tcp_client_socket_pool_unittest.cc',
'socket/tcp_client_socket_unittest.cc',
- 'socket/tcp_pinger_unittest.cc',
'socket_stream/socket_stream_metrics_unittest.cc',
'socket_stream/socket_stream_unittest.cc',
'spdy/spdy_framer_test.cc',
@@ -776,9 +865,13 @@
'spdy/spdy_stream_unittest.cc',
'spdy/spdy_test_util.cc',
'spdy/spdy_test_util.h',
+ 'test/python_utils_unittest.cc',
'tools/dump_cache/url_to_filename_encoder.cc',
'tools/dump_cache/url_to_filename_encoder.h',
'tools/dump_cache/url_to_filename_encoder_unittest.cc',
+ 'tools/dump_cache/url_utilities.h',
+ 'tools/dump_cache/url_utilities.cc',
+ 'tools/dump_cache/url_utilities_unittest.cc',
'url_request/url_request_job_tracker_unittest.cc',
'url_request/url_request_unittest.cc',
'url_request/url_request_unittest.h',
@@ -792,6 +885,11 @@
'websockets/websocket_unittest.cc',
],
'conditions': [
+ ['chromeos==1', {
+ 'sources!': [
+ 'proxy/proxy_config_service_linux_unittest.cc',
+ ],
+ }],
[ 'OS == "linux" or OS == "freebsd" or OS == "openbsd"', {
'dependencies': [
'../build/linux/system.gyp:gtk',
@@ -801,6 +899,11 @@
'base/sdch_filter_unittest.cc',
],
},
+ { # else: OS is not in the above list
+ 'sources!': [
+ 'base/cert_database_nss_unittest.cc',
+ ],
+ }
],
['OS == "linux"', {
'conditions': [
@@ -922,7 +1025,11 @@
'proxy/proxy_config_service_common_unittest.h',
'socket/socket_test_util.cc',
'socket/socket_test_util.h',
+ 'test/python_utils.cc',
+ 'test/python_utils.h',
'test/test_server.cc',
+ 'test/test_server_posix.cc',
+ 'test/test_server_win.cc',
'test/test_server.h',
],
'conditions': [
@@ -1051,6 +1158,27 @@
'tools/hresolv/hresolv.cc',
],
},
+ {
+ 'target_name': 'dnssec_chain_verify',
+ 'type': 'executable',
+ 'dependencies': [
+ 'net_base',
+ ],
+ 'sources': [
+ 'tools/dnssec_chain_verify/dnssec_chain_verify.cc',
+ ]
+ },
+ {
+ 'target_name': 'ssl_false_start_blacklist_process',
+ 'type': 'executable',
+ 'toolsets': ['host'],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'base/ssl_false_start_blacklist_process.cc',
+ ],
+ },
],
'conditions': [
# ['OS=="linux"', {
@@ -1121,7 +1249,8 @@
'tools/dump_cache/upgrade.cc',
'tools/dump_cache/url_to_filename_encoder.cc',
'tools/dump_cache/url_to_filename_encoder.h',
- 'tools/dump_cache/url_utilties.h',
+ 'tools/dump_cache/url_utilities.h',
+ 'tools/dump_cache/url_utilities.cc',
],
},
],
diff --git a/net/net.target.mk b/net/net.target.mk
index 0d01fba..a735c5f 100644
--- a/net/net.target.mk
+++ b/net/net.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -100,6 +101,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -196,6 +198,7 @@ OBJS := $(obj).target/$(TARGET)/net/disk_cache/addr.o \
$(obj).target/$(TARGET)/net/ftp/ftp_server_type_histograms.o \
$(obj).target/$(TARGET)/net/ftp/ftp_util.o \
$(obj).target/$(TARGET)/net/http/des.o \
+ $(obj).target/$(TARGET)/net/http/disk_cache_based_ssl_host_info.o \
$(obj).target/$(TARGET)/net/http/http_alternate_protocols.o \
$(obj).target/$(TARGET)/net/http/http_auth.o \
$(obj).target/$(TARGET)/net/http/http_auth_cache.o \
@@ -218,9 +221,12 @@ OBJS := $(obj).target/$(TARGET)/net/disk_cache/addr.o \
$(obj).target/$(TARGET)/net/http/http_network_session.o \
$(obj).target/$(TARGET)/net/http/http_network_transaction.o \
$(obj).target/$(TARGET)/net/http/http_request_headers.o \
+ $(obj).target/$(TARGET)/net/http/http_response_body_drainer.o \
$(obj).target/$(TARGET)/net/http/http_response_headers.o \
$(obj).target/$(TARGET)/net/http/http_response_info.o \
+ $(obj).target/$(TARGET)/net/http/http_stream_factory.o \
$(obj).target/$(TARGET)/net/http/http_stream_parser.o \
+ $(obj).target/$(TARGET)/net/http/http_stream_request.o \
$(obj).target/$(TARGET)/net/http/url_security_manager.o \
$(obj).target/$(TARGET)/net/http/url_security_manager_posix.o \
$(obj).target/$(TARGET)/net/http/http_proxy_client_socket.o \
@@ -233,6 +239,7 @@ OBJS := $(obj).target/$(TARGET)/net/disk_cache/addr.o \
$(obj).target/$(TARGET)/net/ocsp/nss_ocsp.o \
$(obj).target/$(TARGET)/net/proxy/init_proxy_resolver.o \
$(obj).target/$(TARGET)/net/proxy/multi_threaded_proxy_resolver.o \
+ $(obj).target/$(TARGET)/net/proxy/polling_proxy_config_service.o \
$(obj).target/$(TARGET)/net/proxy/proxy_bypass_rules.o \
$(obj).target/$(TARGET)/net/proxy/proxy_config.o \
$(obj).target/$(TARGET)/net/proxy/proxy_config_service_linux.o \
@@ -245,11 +252,13 @@ OBJS := $(obj).target/$(TARGET)/net/disk_cache/addr.o \
$(obj).target/$(TARGET)/net/proxy/proxy_server.o \
$(obj).target/$(TARGET)/net/proxy/proxy_service.o \
$(obj).target/$(TARGET)/net/proxy/sync_host_resolver_bridge.o \
+ $(obj).target/$(TARGET)/net/socket/client_socket.o \
$(obj).target/$(TARGET)/net/socket/client_socket_factory.o \
$(obj).target/$(TARGET)/net/socket/client_socket_handle.o \
$(obj).target/$(TARGET)/net/socket/client_socket_pool.o \
$(obj).target/$(TARGET)/net/socket/client_socket_pool_base.o \
$(obj).target/$(TARGET)/net/socket/client_socket_pool_histograms.o \
+ $(obj).target/$(TARGET)/net/socket/client_socket_pool_manager.o \
$(obj).target/$(TARGET)/net/socket/socks5_client_socket.o \
$(obj).target/$(TARGET)/net/socket/socks_client_socket.o \
$(obj).target/$(TARGET)/net/socket/socks_client_socket_pool.o \
@@ -264,8 +273,8 @@ OBJS := $(obj).target/$(TARGET)/net/disk_cache/addr.o \
$(obj).target/$(TARGET)/net/spdy/spdy_frame_builder.o \
$(obj).target/$(TARGET)/net/spdy/spdy_framer.o \
$(obj).target/$(TARGET)/net/spdy/spdy_http_stream.o \
+ $(obj).target/$(TARGET)/net/spdy/spdy_http_utils.o \
$(obj).target/$(TARGET)/net/spdy/spdy_io_buffer.o \
- $(obj).target/$(TARGET)/net/spdy/spdy_network_transaction.o \
$(obj).target/$(TARGET)/net/spdy/spdy_session.o \
$(obj).target/$(TARGET)/net/spdy/spdy_session_pool.o \
$(obj).target/$(TARGET)/net/spdy/spdy_settings_storage.o \
@@ -273,6 +282,7 @@ OBJS := $(obj).target/$(TARGET)/net/disk_cache/addr.o \
$(obj).target/$(TARGET)/net/url_request/https_prober.o \
$(obj).target/$(TARGET)/net/url_request/url_request.o \
$(obj).target/$(TARGET)/net/url_request/url_request_about_job.o \
+ $(obj).target/$(TARGET)/net/url_request/url_request_context.o \
$(obj).target/$(TARGET)/net/url_request/url_request_data_job.o \
$(obj).target/$(TARGET)/net/url_request/url_request_error_job.o \
$(obj).target/$(TARGET)/net/url_request/url_request_file_dir_job.o \
@@ -325,11 +335,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/net/net_base.target.mk b/net/net_base.target.mk
index a3c4d6d..b892526 100644
--- a/net/net_base.target.mk
+++ b/net/net_base.target.mk
@@ -2,6 +2,22 @@
TOOLSET := target
TARGET := net_base
+### Rules for action "ssl_false_start_blacklist":
+quiet_cmd_net_base_ssl_false_start_blacklist = ACTION Generating SSL False Start blacklist $@
+cmd_net_base_ssl_false_start_blacklist = export LD_LIBRARY_PATH=$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; cd net; mkdir -p $(obj)/gen/net/base; "$(builddir)/ssl_false_start_blacklist_process" base/ssl_false_start_blacklist.txt "$(obj)/gen/net/base/ssl_false_start_blacklist_data.cc"
+
+$(obj)/gen/net/base/ssl_false_start_blacklist_data.cc: obj := $(abs_obj)
+
+$(obj)/gen/net/base/ssl_false_start_blacklist_data.cc: builddir := $(abs_builddir)
+
+$(obj)/gen/net/base/ssl_false_start_blacklist_data.cc: TOOLSET := $(TOOLSET)
+$(obj)/gen/net/base/ssl_false_start_blacklist_data.cc: $(builddir)/ssl_false_start_blacklist_process net/base/ssl_false_start_blacklist.txt FORCE_DO_CMD
+ $(call do_cmd,net_base_ssl_false_start_blacklist)
+
+all_deps += $(obj)/gen/net/base/ssl_false_start_blacklist_data.cc
+action_net_base_ssl_false_start_blacklist_outputs := $(obj)/gen/net/base/ssl_false_start_blacklist_data.cc
+
+
DEFS_Debug := '-DNO_HEAPCHECKER' \
'-DCHROMIUM_BUILD' \
'-DENABLE_REMOTING=1' \
@@ -21,6 +37,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -99,6 +116,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -161,7 +179,9 @@ INCS_Release := -Ithird_party/icu/public/common \
OBJS := $(obj).target/$(TARGET)/net/base/address_list.o \
$(obj).target/$(TARGET)/net/base/address_list_net_log_param.o \
+ $(obj).target/$(TARGET)/net/base/auth.o \
$(obj).target/$(TARGET)/net/base/capturing_net_log.o \
+ $(obj).target/$(TARGET)/net/base/cert_database.o \
$(obj).target/$(TARGET)/net/base/cert_database_nss.o \
$(obj).target/$(TARGET)/net/base/cert_status_flags.o \
$(obj).target/$(TARGET)/net/base/cert_verifier.o \
@@ -169,7 +189,11 @@ OBJS := $(obj).target/$(TARGET)/net/base/address_list.o \
$(obj).target/$(TARGET)/net/base/cookie_monster.o \
$(obj).target/$(TARGET)/net/base/data_url.o \
$(obj).target/$(TARGET)/net/base/directory_lister.o \
+ $(obj).target/$(TARGET)/net/base/dns_reload_timer.o \
+ $(obj).target/$(TARGET)/net/base/dnssec_chain_verifier.o \
+ $(obj).target/$(TARGET)/net/base/dnssec_keyset.o \
$(obj).target/$(TARGET)/net/base/dns_util.o \
+ $(obj).target/$(TARGET)/net/base/dnsrr_resolver.o \
$(obj).target/$(TARGET)/net/base/escape.o \
$(obj).target/$(TARGET)/net/base/ev_root_ca_metadata.o \
$(obj).target/$(TARGET)/net/base/file_stream_posix.o \
@@ -199,28 +223,39 @@ OBJS := $(obj).target/$(TARGET)/net/base/address_list.o \
$(obj).target/$(TARGET)/net/base/network_change_notifier_linux.o \
$(obj).target/$(TARGET)/net/base/network_change_notifier_netlink_linux.o \
$(obj).target/$(TARGET)/net/base/nss_memio.o \
+ $(obj).target/$(TARGET)/net/base/pem_tokenizer.o \
$(obj).target/$(TARGET)/net/base/platform_mime_util_linux.o \
$(obj).target/$(TARGET)/net/base/registry_controlled_domain.o \
$(obj).target/$(TARGET)/net/base/sdch_filter.o \
$(obj).target/$(TARGET)/net/base/sdch_manager.o \
+ $(obj).target/$(TARGET)/net/base/ssl_cert_request_info.o \
$(obj).target/$(TARGET)/net/base/ssl_cipher_suite_names.o \
$(obj).target/$(TARGET)/net/base/ssl_client_auth_cache.o \
$(obj).target/$(TARGET)/net/base/ssl_config_service.o \
+ $(obj).target/$(TARGET)/net/base/ssl_config_service_defaults.o \
+ $(obj).target/$(TARGET)/net/base/ssl_false_start_blacklist.o \
+ $(obj).target/$(TARGET)/net/base/ssl_info.o \
$(obj).target/$(TARGET)/net/base/static_cookie_policy.o \
$(obj).target/$(TARGET)/net/base/transport_security_state.o \
- $(obj).target/$(TARGET)/net/base/telnet_server.o \
$(obj).target/$(TARGET)/net/base/upload_data.o \
$(obj).target/$(TARGET)/net/base/upload_data_stream.o \
$(obj).target/$(TARGET)/net/base/x509_certificate.o \
$(obj).target/$(TARGET)/net/base/x509_certificate_nss.o \
$(obj).target/$(TARGET)/net/base/x509_cert_types.o \
- $(obj).target/$(TARGET)/net/third_party/mozilla_security_manager/nsKeygenHandler.o
+ $(obj).target/$(TARGET)/net/third_party/mozilla_security_manager/nsKeygenHandler.o \
+ $(obj).target/$(TARGET)/net/third_party/mozilla_security_manager/nsNSSCertificateDB.o \
+ $(obj).target/$(TARGET)/net/third_party/mozilla_security_manager/nsNSSCertTrust.o \
+ $(obj).target/$(TARGET)/net/third_party/mozilla_security_manager/nsPKCS12Blob.o \
+ $(obj).target/$(TARGET)/gen/net/base/ssl_false_start_blacklist_data.o
# Add to the list of files we specially track dependencies for.
all_deps += $(OBJS)
# Make sure our dependencies are built before any of us.
-$(OBJS): | $(obj).target/net/net_resources.stamp
+$(OBJS): | $(obj).target/net/net_resources.stamp ssl_false_start_blacklist_process
+
+# Make sure our actions/rules run before any of us.
+$(OBJS): | $(action_net_base_ssl_false_start_blacklist_outputs)
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
@@ -261,12 +296,19 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
+# Build our special outputs first.
+$(obj).target/net/libnet_base.a: | $(action_net_base_ssl_false_start_blacklist_outputs)
+
+# Preserve order dependency of special output on deps.
+$(action_net_base_ssl_false_start_blacklist_outputs): | $(obj).target/net/net_resources.stamp ssl_false_start_blacklist_process
+
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/net/net_perftests.target.mk b/net/net_perftests.target.mk
index 65afebf..7f63c42 100644
--- a/net/net_perftests.target.mk
+++ b/net/net_perftests.target.mk
@@ -22,6 +22,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -72,6 +73,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -111,7 +113,7 @@ OBJS := $(obj).target/$(TARGET)/net/base/cookie_monster_perftest.o \
all_deps += $(OBJS)
# Make sure our dependencies are built before any of us.
-$(OBJS): | $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/base/libtest_support_perf.a $(obj).target/testing/libgtest.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a
+$(OBJS): | $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/base/libtest_support_perf.a $(obj).target/testing/libgtest.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a $(obj).target/testing/libgmock.a
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
@@ -138,14 +140,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -174,12 +177,13 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/net_perftests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/net_perftests: LIBS := $(LIBS)
$(builddir)/net_perftests: TOOLSET := $(TOOLSET)
-$(builddir)/net_perftests: $(OBJS) $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/base/libtest_support_perf.a $(obj).target/testing/libgtest.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a FORCE_DO_CMD
+$(builddir)/net_perftests: $(OBJS) $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/base/libtest_support_perf.a $(obj).target/testing/libgtest.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/libxdg_mime.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a $(obj).target/testing/libgmock.a FORCE_DO_CMD
$(call do_cmd,link)
all_deps += $(builddir)/net_perftests
diff --git a/net/net_resources.target.mk b/net/net_resources.target.mk
index 6b8fe7a..ca44ac2 100644
--- a/net/net_resources.target.mk
+++ b/net/net_resources.target.mk
@@ -8,7 +8,11 @@ $(obj)/gen/net/grit/net_resources.h: obj := $(abs_obj)
$(obj)/gen/net/grit/net_resources.h: builddir := $(abs_builddir)
$(obj)/gen/net/grit/net_resources.h: TOOLSET := $(TOOLSET)
+<<<<<<< HEAD
$(obj)/gen/net/grit/net_resources.h: net/base/net_resources.grd net/base/dir_header.html net/base/net_resources.grd tools/grit/grit.py tools/grit/grit_info.py tools/grit/resource_ids tools/grit/grit/exception.py tools/grit/grit/tclib.py tools/grit/grit/pseudo_unittest.py tools/grit/grit/grd_reader_unittest.py tools/grit/grit/grd_reader.py tools/grit/grit/scons.py tools/grit/grit/clique_unittest.py tools/grit/grit/constants.py tools/grit/grit/grit_runner.py tools/grit/grit/clique.py tools/grit/grit/grit_runner_unittest.py tools/grit/grit/shortcuts.py tools/grit/grit/util_unittest.py tools/grit/grit/__init__.py tools/grit/grit/tclib_unittest.py tools/grit/grit/xtb_reader_unittest.py tools/grit/grit/xtb_reader.py tools/grit/grit/pseudo.py tools/grit/grit/test_suite_all.py tools/grit/grit/util.py tools/grit/grit/shortcuts_unittests.py tools/grit/grit/extern/tclib.py tools/grit/grit/extern/FP.py tools/grit/grit/extern/__init__.py tools/grit/grit/node/structure.py tools/grit/grit/node/io_unittest.py tools/grit/grit/node/message.py tools/grit/grit/node/structure_unittest.py tools/grit/grit/node/base.py tools/grit/grit/node/empty.py tools/grit/grit/node/misc.py tools/grit/grit/node/__init__.py tools/grit/grit/node/include.py tools/grit/grit/node/mapping.py tools/grit/grit/node/message_unittest.py tools/grit/grit/node/io.py tools/grit/grit/node/variant.py tools/grit/grit/node/base_unittest.py tools/grit/grit/node/misc_unittest.py tools/grit/grit/node/custom/filename_unittest.py tools/grit/grit/node/custom/filename.py tools/grit/grit/node/custom/__init__.py tools/grit/grit/tool/newgrd.py tools/grit/grit/tool/transl2tc.py tools/grit/grit/tool/postprocess_interface.py tools/grit/grit/tool/preprocess_unittest.py tools/grit/grit/tool/test.py tools/grit/grit/tool/count.py tools/grit/grit/tool/toolbar_preprocess.py tools/grit/grit/tool/toolbar_postprocess.py tools/grit/grit/tool/resize.py tools/grit/grit/tool/unit.py tools/grit/grit/tool/preprocess_interface.py tools/grit/grit/tool/menu_from_parts.py tools/grit/grit/tool/__init__.py tools/grit/grit/tool/rc2grd_unittest.py tools/grit/grit/tool/interface.py tools/grit/grit/tool/postprocess_unittest.py tools/grit/grit/tool/diff_structures.py tools/grit/grit/tool/transl2tc_unittest.py tools/grit/grit/tool/rc2grd.py tools/grit/grit/tool/build.py tools/grit/grit/gather/admin_template.py tools/grit/grit/gather/muppet_strings_unittest.py tools/grit/grit/gather/rc_unittest.py tools/grit/grit/gather/tr_html.py tools/grit/grit/gather/regexp.py tools/grit/grit/gather/__init__.py tools/grit/grit/gather/admin_template_unittest.py tools/grit/grit/gather/interface.py tools/grit/grit/gather/muppet_strings.py tools/grit/grit/gather/rc.py tools/grit/grit/gather/txt_unittest.py tools/grit/grit/gather/tr_html_unittest.py tools/grit/grit/gather/txt.py tools/grit/grit/format/rc_header_unittest.py tools/grit/grit/format/data_pack.py tools/grit/grit/format/data_pack_unittest.py tools/grit/grit/format/rc_unittest.py tools/grit/grit/format/js_map_format.py tools/grit/grit/format/resource_map.py tools/grit/grit/format/rc_header.py tools/grit/grit/format/__init__.py tools/grit/grit/format/html_inline.py tools/grit/grit/format/interface.py tools/grit/grit/format/rc.py tools/grit/grit/format/js_map_format_unittest.py FORCE_DO_CMD
+=======
+$(obj)/gen/net/grit/net_resources.h: net/base/net_resources.grd net/base/dir_header.html net/base/net_resources.grd tools/grit/grit_info.py tools/grit/resource_ids tools/grit/grit.py tools/grit/grit/exception.py tools/grit/grit/shortcuts_unittests.py tools/grit/grit/test_suite_all.py tools/grit/grit/tclib.py tools/grit/grit/util_unittest.py tools/grit/grit/pseudo_unittest.py tools/grit/grit/grd_reader.py tools/grit/grit/clique.py tools/grit/grit/xtb_reader_unittest.py tools/grit/grit/grit_runner.py tools/grit/grit/tclib_unittest.py tools/grit/grit/util.py tools/grit/grit/pseudo.py tools/grit/grit/shortcuts.py tools/grit/grit/clique_unittest.py tools/grit/grit/xtb_reader.py tools/grit/grit/__init__.py tools/grit/grit/scons.py tools/grit/grit/constants.py tools/grit/grit/grd_reader_unittest.py tools/grit/grit/grit_runner_unittest.py tools/grit/grit/format/html_inline.py tools/grit/grit/format/rc_unittest.py tools/grit/grit/format/rc_header.py tools/grit/grit/format/interface.py tools/grit/grit/format/data_pack_unittest.py tools/grit/grit/format/__init__.py tools/grit/grit/format/rc_header_unittest.py tools/grit/grit/format/js_map_format.py tools/grit/grit/format/data_pack.py tools/grit/grit/format/rc.py tools/grit/grit/format/resource_map.py tools/grit/grit/format/js_map_format_unittest.py tools/grit/grit/format/policy_templates/policy_template_generator.py tools/grit/grit/format/policy_templates/template_formatter.py tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py tools/grit/grit/format/policy_templates/writer_configuration.py tools/grit/grit/format/policy_templates/__init__.py tools/grit/grit/format/policy_templates/writers/adm_writer.py tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py tools/grit/grit/format/policy_templates/writers/plist_writer.py tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py tools/grit/grit/format/policy_templates/writers/doc_writer.py tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py tools/grit/grit/format/policy_templates/writers/__init__.py tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py tools/grit/grit/format/policy_templates/writers/adml_writer.py tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py tools/grit/grit/format/policy_templates/writers/mock_writer.py tools/grit/grit/format/policy_templates/writers/template_writer.py tools/grit/grit/format/policy_templates/writers/admx_writer.py tools/grit/grit/gather/tr_html.py tools/grit/grit/gather/rc_unittest.py tools/grit/grit/gather/tr_html_unittest.py tools/grit/grit/gather/txt_unittest.py tools/grit/grit/gather/muppet_strings_unittest.py tools/grit/grit/gather/regexp.py tools/grit/grit/gather/interface.py tools/grit/grit/gather/muppet_strings.py tools/grit/grit/gather/__init__.py tools/grit/grit/gather/json_loader.py tools/grit/grit/gather/admin_template.py tools/grit/grit/gather/txt.py tools/grit/grit/gather/rc.py tools/grit/grit/gather/admin_template_unittest.py tools/grit/grit/tool/diff_structures.py tools/grit/grit/tool/toolbar_preprocess.py tools/grit/grit/tool/rc2grd.py tools/grit/grit/tool/rc2grd_unittest.py tools/grit/grit/tool/test.py tools/grit/grit/tool/postprocess_interface.py tools/grit/grit/tool/unit.py tools/grit/grit/tool/transl2tc.py tools/grit/grit/tool/resize.py tools/grit/grit/tool/interface.py tools/grit/grit/tool/preprocess_unittest.py tools/grit/grit/tool/__init__.py tools/grit/grit/tool/newgrd.py tools/grit/grit/tool/build.py tools/grit/grit/tool/preprocess_interface.py tools/grit/grit/tool/count.py tools/grit/grit/tool/postprocess_unittest.py tools/grit/grit/tool/menu_from_parts.py tools/grit/grit/tool/toolbar_postprocess.py tools/grit/grit/tool/transl2tc_unittest.py tools/grit/grit/extern/tclib.py tools/grit/grit/extern/__init__.py tools/grit/grit/extern/FP.py tools/grit/grit/node/structure.py tools/grit/grit/node/variant.py tools/grit/grit/node/include.py tools/grit/grit/node/io_unittest.py tools/grit/grit/node/base.py tools/grit/grit/node/misc_unittest.py tools/grit/grit/node/base_unittest.py tools/grit/grit/node/message.py tools/grit/grit/node/__init__.py tools/grit/grit/node/mapping.py tools/grit/grit/node/io.py tools/grit/grit/node/message_unittest.py tools/grit/grit/node/structure_unittest.py tools/grit/grit/node/misc.py tools/grit/grit/node/empty.py tools/grit/grit/node/custom/filename.py tools/grit/grit/node/custom/filename_unittest.py tools/grit/grit/node/custom/__init__.py FORCE_DO_CMD
+>>>>>>> Chromium at release 7.0.540.0
$(call do_cmd,net_resources_grit_0)
$(obj)/gen/net/net_resources.pak $(obj)/gen/net/net_resources.rc: $(obj)/gen/net/grit/net_resources.h
$(obj)/gen/net/net_resources.pak $(obj)/gen/net/net_resources.rc: ;
@@ -42,6 +46,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -74,6 +79,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
diff --git a/net/net_test_support.target.mk b/net/net_test_support.target.mk
index 8e2077e..8d387d2 100644
--- a/net/net_test_support.target.mk
+++ b/net/net_test_support.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -75,6 +76,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -115,7 +117,9 @@ OBJS := $(obj).target/$(TARGET)/net/base/cert_test_util.o \
$(obj).target/$(TARGET)/net/disk_cache/disk_cache_test_util.o \
$(obj).target/$(TARGET)/net/proxy/proxy_config_service_common_unittest.o \
$(obj).target/$(TARGET)/net/socket/socket_test_util.o \
- $(obj).target/$(TARGET)/net/test/test_server.o
+ $(obj).target/$(TARGET)/net/test/python_utils.o \
+ $(obj).target/$(TARGET)/net/test/test_server.o \
+ $(obj).target/$(TARGET)/net/test/test_server_posix.o
# Add to the list of files we specially track dependencies for.
all_deps += $(OBJS)
@@ -145,11 +149,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/net/net_unittests.target.mk b/net/net_unittests.target.mk
index 4b45d03..9cbef17 100644
--- a/net/net_unittests.target.mk
+++ b/net/net_unittests.target.mk
@@ -22,6 +22,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -78,6 +79,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -116,10 +118,13 @@ INCS_Release := -I. \
-Itesting/gtest/include
OBJS := $(obj).target/$(TARGET)/net/base/address_list_unittest.o \
+ $(obj).target/$(TARGET)/net/base/cert_database_nss_unittest.o \
$(obj).target/$(TARGET)/net/base/cookie_monster_unittest.o \
$(obj).target/$(TARGET)/net/base/data_url_unittest.o \
$(obj).target/$(TARGET)/net/base/directory_lister_unittest.o \
+ $(obj).target/$(TARGET)/net/base/dnssec_unittest.o \
$(obj).target/$(TARGET)/net/base/dns_util_unittest.o \
+ $(obj).target/$(TARGET)/net/base/dnsrr_resolver_unittest.o \
$(obj).target/$(TARGET)/net/base/escape_unittest.o \
$(obj).target/$(TARGET)/net/base/file_stream_unittest.o \
$(obj).target/$(TARGET)/net/base/filter_unittest.o \
@@ -134,13 +139,15 @@ OBJS := $(obj).target/$(TARGET)/net/base/address_list_unittest.o \
$(obj).target/$(TARGET)/net/base/mime_sniffer_unittest.o \
$(obj).target/$(TARGET)/net/base/mime_util_unittest.o \
$(obj).target/$(TARGET)/net/base/net_util_unittest.o \
+ $(obj).target/$(TARGET)/net/base/pem_tokenizer_unittest.o \
$(obj).target/$(TARGET)/net/base/registry_controlled_domain_unittest.o \
$(obj).target/$(TARGET)/net/base/run_all_unittests.o \
$(obj).target/$(TARGET)/net/base/ssl_cipher_suite_names_unittest.o \
$(obj).target/$(TARGET)/net/base/ssl_client_auth_cache_unittest.o \
+ $(obj).target/$(TARGET)/net/base/ssl_config_service_unittest.o \
+ $(obj).target/$(TARGET)/net/base/ssl_false_start_blacklist_unittest.o \
$(obj).target/$(TARGET)/net/base/static_cookie_policy_unittest.o \
$(obj).target/$(TARGET)/net/base/transport_security_state_unittest.o \
- $(obj).target/$(TARGET)/net/base/telnet_server_unittest.o \
$(obj).target/$(TARGET)/net/base/test_completion_callback_unittest.o \
$(obj).target/$(TARGET)/net/base/upload_data_stream_unittest.o \
$(obj).target/$(TARGET)/net/base/x509_certificate_unittest.o \
@@ -182,6 +189,7 @@ OBJS := $(obj).target/$(TARGET)/net/base/address_list_unittest.o \
$(obj).target/$(TARGET)/net/http/http_network_transaction_unittest.o \
$(obj).target/$(TARGET)/net/http/http_proxy_client_socket_pool_unittest.o \
$(obj).target/$(TARGET)/net/http/http_request_headers_unittest.o \
+ $(obj).target/$(TARGET)/net/http/http_response_body_drainer_unittest.o \
$(obj).target/$(TARGET)/net/http/http_response_headers_unittest.o \
$(obj).target/$(TARGET)/net/http/http_transaction_unittest.o \
$(obj).target/$(TARGET)/net/http/http_util_unittest.o \
@@ -208,7 +216,6 @@ OBJS := $(obj).target/$(TARGET)/net/base/address_list_unittest.o \
$(obj).target/$(TARGET)/net/socket/ssl_client_socket_pool_unittest.o \
$(obj).target/$(TARGET)/net/socket/tcp_client_socket_pool_unittest.o \
$(obj).target/$(TARGET)/net/socket/tcp_client_socket_unittest.o \
- $(obj).target/$(TARGET)/net/socket/tcp_pinger_unittest.o \
$(obj).target/$(TARGET)/net/socket_stream/socket_stream_metrics_unittest.o \
$(obj).target/$(TARGET)/net/socket_stream/socket_stream_unittest.o \
$(obj).target/$(TARGET)/net/spdy/spdy_framer_test.o \
@@ -218,8 +225,11 @@ OBJS := $(obj).target/$(TARGET)/net/base/address_list_unittest.o \
$(obj).target/$(TARGET)/net/spdy/spdy_session_unittest.o \
$(obj).target/$(TARGET)/net/spdy/spdy_stream_unittest.o \
$(obj).target/$(TARGET)/net/spdy/spdy_test_util.o \
+ $(obj).target/$(TARGET)/net/test/python_utils_unittest.o \
$(obj).target/$(TARGET)/net/tools/dump_cache/url_to_filename_encoder.o \
$(obj).target/$(TARGET)/net/tools/dump_cache/url_to_filename_encoder_unittest.o \
+ $(obj).target/$(TARGET)/net/tools/dump_cache/url_utilities.o \
+ $(obj).target/$(TARGET)/net/tools/dump_cache/url_utilities_unittest.o \
$(obj).target/$(TARGET)/net/url_request/url_request_job_tracker_unittest.o \
$(obj).target/$(TARGET)/net/url_request/url_request_unittest.o \
$(obj).target/$(TARGET)/net/url_request/view_cache_helper_unittest.o \
@@ -235,7 +245,7 @@ OBJS := $(obj).target/$(TARGET)/net/base/address_list_unittest.o \
all_deps += $(OBJS)
# Make sure our dependencies are built before any of us.
-$(OBJS): | $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/base/libxdg_mime.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a
+$(OBJS): | $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/base/libxdg_mime.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
@@ -262,14 +272,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -298,12 +309,13 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/net_unittests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/net_unittests: LIBS := $(LIBS)
$(builddir)/net_unittests: TOOLSET := $(TOOLSET)
-$(builddir)/net_unittests: $(OBJS) $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/base/libxdg_mime.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a FORCE_DO_CMD
+$(builddir)/net_unittests: $(OBJS) $(obj).target/net/libnet.a $(obj).target/net/libnet_test_support.a $(obj).target/base/libbase.a $(obj).target/base/libbase_i18n.a $(obj).target/base/libtest_support_base.a $(obj).target/testing/libgmock.a $(obj).target/testing/libgtest.a $(obj).target/third_party/zlib/libzlib.a $(obj).target/base/allocator/liballocator.a $(obj).target/third_party/modp_b64/libmodp_b64.a $(obj).target/base/third_party/dynamic_annotations/libdynamic_annotations.a $(obj).target/base/libsymbolize.a $(obj).target/net/third_party/nss/libssl.a $(obj).target/base/libxdg_mime.a $(obj).target/third_party/libevent/libevent.a $(obj).target/third_party/icu/libicui18n.a $(obj).target/third_party/icu/libicuuc.a $(obj).target/third_party/icu/libicudata.a $(obj).target/build/temp_gyp/libgoogleurl.a $(obj).target/sdch/libsdch.a $(obj).target/net/libnet_base.a $(obj).target/v8/tools/gyp/libv8_snapshot.a $(obj).target/v8/tools/gyp/libv8_base.a FORCE_DO_CMD
$(call do_cmd,link)
all_deps += $(builddir)/net_unittests
diff --git a/net/ocsp/nss_ocsp.cc b/net/ocsp/nss_ocsp.cc
index 702baa6..2368df0 100644
--- a/net/ocsp/nss_ocsp.cc
+++ b/net/ocsp/nss_ocsp.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.
@@ -19,6 +19,8 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/singleton.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/thread.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
@@ -447,11 +449,11 @@ class OCSPServerSession {
// TODO(ukai): If |host| is an IPv6 literal, we need to quote it with
// square brackets [].
- std::string url_string(StringPrintf("%s://%s:%d%s",
- http_protocol_variant,
- host_.c_str(),
- port_,
- path_and_query_string));
+ std::string url_string(base::StringPrintf("%s://%s:%d%s",
+ http_protocol_variant,
+ host_.c_str(),
+ port_,
+ path_and_query_string));
LOG(INFO) << "URL [" << url_string << "]";
GURL url(url_string);
return new OCSPRequestSession(
diff --git a/net/ocsp/nss_ocsp.h b/net/ocsp/nss_ocsp.h
index 1bacd76..a31d025 100644
--- a/net/ocsp/nss_ocsp.h
+++ b/net/ocsp/nss_ocsp.h
@@ -4,6 +4,7 @@
#ifndef NET_OCSP_NSS_OCSP_H_
#define NET_OCSP_NSS_OCSP_H_
+#pragma once
class URLRequestContext;
diff --git a/net/proxy/init_proxy_resolver.cc b/net/proxy/init_proxy_resolver.cc
index 04f828b..368fcf0 100644
--- a/net/proxy/init_proxy_resolver.cc
+++ b/net/proxy/init_proxy_resolver.cc
@@ -16,6 +16,10 @@
namespace net {
+// This is the hard-coded location used by the DNS portion of web proxy
+// auto-discovery.
+static const char kWpadUrl[] = "http://wpad/wpad.dat";
+
InitProxyResolver::InitProxyResolver(ProxyResolver* resolver,
ProxyScriptFetcher* proxy_script_fetcher,
NetLog* net_log)
@@ -27,7 +31,8 @@ InitProxyResolver::InitProxyResolver(ProxyResolver* resolver,
current_pac_url_index_(0u),
next_state_(STATE_NONE),
net_log_(BoundNetLog::Make(
- net_log, NetLog::SOURCE_INIT_PROXY_RESOLVER)) {
+ net_log, NetLog::SOURCE_INIT_PROXY_RESOLVER)),
+ effective_config_(NULL) {
}
InitProxyResolver::~InitProxyResolver() {
@@ -36,17 +41,26 @@ InitProxyResolver::~InitProxyResolver() {
}
int InitProxyResolver::Init(const ProxyConfig& config,
+ const base::TimeDelta wait_delay,
+ ProxyConfig* effective_config,
CompletionCallback* callback) {
DCHECK_EQ(STATE_NONE, next_state_);
DCHECK(callback);
- DCHECK(config.MayRequirePACResolver());
+ DCHECK(config.HasAutomaticSettings());
net_log_.BeginEvent(NetLog::TYPE_INIT_PROXY_RESOLVER, NULL);
+ // Save the |wait_delay| as a non-negative value.
+ wait_delay_ = wait_delay;
+ if (wait_delay_ < base::TimeDelta())
+ wait_delay_ = base::TimeDelta();
+
+ effective_config_ = effective_config;
+
pac_urls_ = BuildPacUrlsFallbackList(config);
DCHECK(!pac_urls_.empty());
- next_state_ = GetStartState();
+ next_state_ = STATE_WAIT;
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
@@ -86,6 +100,13 @@ int InitProxyResolver::DoLoop(int result) {
State state = next_state_;
next_state_ = STATE_NONE;
switch (state) {
+ case STATE_WAIT:
+ DCHECK_EQ(OK, rv);
+ rv = DoWait();
+ break;
+ case STATE_WAIT_COMPLETE:
+ rv = DoWaitComplete(rv);
+ break;
case STATE_FETCH_PAC_SCRIPT:
DCHECK_EQ(OK, rv);
rv = DoFetchPacScript();
@@ -115,6 +136,27 @@ void InitProxyResolver::DoCallback(int result) {
user_callback_->Run(result);
}
+int InitProxyResolver::DoWait() {
+ next_state_ = STATE_WAIT_COMPLETE;
+
+ // If no waiting is required, continue on to the next state.
+ if (wait_delay_.ToInternalValue() == 0)
+ return OK;
+
+ // Otherwise wait the specified amount of time.
+ wait_timer_.Start(wait_delay_, this, &InitProxyResolver::OnWaitTimerFired);
+ net_log_.BeginEvent(NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT, NULL);
+ return ERR_IO_PENDING;
+}
+
+int InitProxyResolver::DoWaitComplete(int result) {
+ DCHECK_EQ(OK, result);
+ if (wait_delay_.ToInternalValue() != 0)
+ net_log_.EndEvent(NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT, NULL);
+ next_state_ = GetStartState();
+ return OK;
+}
+
int InitProxyResolver::DoFetchPacScript() {
DCHECK(resolver_->expects_pac_bytes());
@@ -123,7 +165,7 @@ int InitProxyResolver::DoFetchPacScript() {
const PacURL& pac_url = current_pac_url();
const GURL effective_pac_url =
- pac_url.auto_detect ? GURL("http://wpad/wpad.dat") : pac_url.url;
+ pac_url.auto_detect ? GURL(kWpadUrl) : pac_url.url;
net_log_.BeginEvent(
NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT,
@@ -184,6 +226,20 @@ int InitProxyResolver::DoSetPacScriptComplete(int result) {
return TryToFallbackPacUrl(result);
}
+ // Let the caller know which automatic setting we ended up initializing the
+ // resolver for (there may have been multiple fallbacks to choose from.)
+ if (effective_config_) {
+ if (current_pac_url().auto_detect && resolver_->expects_pac_bytes()) {
+ *effective_config_ =
+ ProxyConfig::CreateFromCustomPacURL(GURL(kWpadUrl));
+ } else if (current_pac_url().auto_detect) {
+ *effective_config_ = ProxyConfig::CreateAutoDetect();
+ } else {
+ *effective_config_ =
+ ProxyConfig::CreateFromCustomPacURL(current_pac_url().url);
+ }
+ }
+
net_log_.EndEvent(NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT, NULL);
return result;
}
@@ -217,6 +273,10 @@ const InitProxyResolver::PacURL& InitProxyResolver::current_pac_url() const {
return pac_urls_[current_pac_url_index_];
}
+void InitProxyResolver::OnWaitTimerFired() {
+ OnIOCompletion(OK);
+}
+
void InitProxyResolver::DidCompleteInit() {
net_log_.EndEvent(NetLog::TYPE_INIT_PROXY_RESOLVER, NULL);
}
@@ -227,6 +287,9 @@ void InitProxyResolver::Cancel() {
net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
switch (next_state_) {
+ case STATE_WAIT_COMPLETE:
+ wait_timer_.Stop();
+ break;
case STATE_FETCH_PAC_SCRIPT_COMPLETE:
proxy_script_fetcher_->Cancel();
break;
diff --git a/net/proxy/init_proxy_resolver.h b/net/proxy/init_proxy_resolver.h
index 814e932..2691be5 100644
--- a/net/proxy/init_proxy_resolver.h
+++ b/net/proxy/init_proxy_resolver.h
@@ -1,13 +1,16 @@
-// 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.
#ifndef NET_PROXY_INIT_PROXY_RESOLVER_H_
#define NET_PROXY_INIT_PROXY_RESOLVER_H_
+#pragma once
-#include <string>
#include <vector>
+#include "base/string16.h"
+#include "base/time.h"
+#include "base/timer.h"
#include "googleurl/src/gurl.h"
#include "net/base/completion_callback.h"
#include "net/base/net_log.h"
@@ -45,13 +48,25 @@ class InitProxyResolver {
// Aborts any in-progress request.
~InitProxyResolver();
- // Apply the PAC settings of |config| to |resolver_|.
+ // Applies the PAC settings of |config| to |resolver_|.
+ // If |wait_delay| is positive, the initialization will pause for this
+ // amount of time before getting started.
+ // If |effective_config| is non-NULL, then on successful initialization of
+ // |resolver_| the "effective" proxy settings we ended up using will be
+ // written out to |*effective_config|. Note that this may differ from
+ // |config| since we will have stripped any manual settings, and decided
+ // whether to use auto-detect or the custom PAC URL. Finally, if auto-detect
+ // was used we may now have resolved that to a specific script URL.
int Init(const ProxyConfig& config,
+ const base::TimeDelta wait_delay,
+ ProxyConfig* effective_config,
CompletionCallback* callback);
private:
enum State {
STATE_NONE,
+ STATE_WAIT,
+ STATE_WAIT_COMPLETE,
STATE_FETCH_PAC_SCRIPT,
STATE_FETCH_PAC_SCRIPT_COMPLETE,
STATE_SET_PAC_SCRIPT,
@@ -74,6 +89,9 @@ class InitProxyResolver {
int DoLoop(int result);
void DoCallback(int result);
+ int DoWait();
+ int DoWaitComplete(int result);
+
int DoFetchPacScript();
int DoFetchPacScriptComplete(int result);
@@ -93,6 +111,7 @@ class InitProxyResolver {
// Returns the current PAC URL we are fetching/testing.
const PacURL& current_pac_url() const;
+ void OnWaitTimerFired();
void DidCompleteInit();
void Cancel();
@@ -112,6 +131,11 @@ class InitProxyResolver {
BoundNetLog net_log_;
+ base::TimeDelta wait_delay_;
+ base::OneShotTimer<InitProxyResolver> wait_timer_;
+
+ ProxyConfig* effective_config_;
+
DISALLOW_COPY_AND_ASSIGN(InitProxyResolver);
};
diff --git a/net/proxy/init_proxy_resolver_unittest.cc b/net/proxy/init_proxy_resolver_unittest.cc
index 458cc53..0c7e8a1 100644
--- a/net/proxy/init_proxy_resolver_unittest.cc
+++ b/net/proxy/init_proxy_resolver_unittest.cc
@@ -177,7 +177,7 @@ TEST(InitProxyResolverTest, CustomPacSucceeds) {
TestCompletionCallback callback;
CapturingNetLog log(CapturingNetLog::kUnbounded);
InitProxyResolver init(&resolver, &fetcher, &log);
- EXPECT_EQ(OK, init.Init(config, &callback));
+ EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(rule.text(), resolver.script_data()->utf16());
// Check the NetLog was filled correctly.
@@ -210,7 +210,8 @@ TEST(InitProxyResolverTest, CustomPacFails1) {
TestCompletionCallback callback;
CapturingNetLog log(CapturingNetLog::kUnbounded);
InitProxyResolver init(&resolver, &fetcher, &log);
- EXPECT_EQ(kFailedDownloading, init.Init(config, &callback));
+ EXPECT_EQ(kFailedDownloading,
+ init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(NULL, resolver.script_data());
// Check the NetLog was filled correctly.
@@ -238,7 +239,8 @@ TEST(InitProxyResolverTest, CustomPacFails2) {
TestCompletionCallback callback;
InitProxyResolver init(&resolver, &fetcher, NULL);
- EXPECT_EQ(kFailedParsing, init.Init(config, &callback));
+ EXPECT_EQ(kFailedParsing,
+ init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(NULL, resolver.script_data());
}
@@ -252,7 +254,8 @@ TEST(InitProxyResolverTest, HasNullProxyScriptFetcher) {
TestCompletionCallback callback;
InitProxyResolver init(&resolver, NULL, NULL);
- EXPECT_EQ(ERR_UNEXPECTED, init.Init(config, &callback));
+ EXPECT_EQ(ERR_UNEXPECTED,
+ init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(NULL, resolver.script_data());
}
@@ -269,7 +272,7 @@ TEST(InitProxyResolverTest, AutodetectSuccess) {
TestCompletionCallback callback;
InitProxyResolver init(&resolver, &fetcher, NULL);
- EXPECT_EQ(OK, init.Init(config, &callback));
+ EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(rule.text(), resolver.script_data()->utf16());
}
@@ -288,7 +291,7 @@ TEST(InitProxyResolverTest, AutodetectFailCustomSuccess1) {
TestCompletionCallback callback;
InitProxyResolver init(&resolver, &fetcher, NULL);
- EXPECT_EQ(OK, init.Init(config, &callback));
+ EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(rule.text(), resolver.script_data()->utf16());
}
@@ -301,16 +304,25 @@ TEST(InitProxyResolverTest, AutodetectFailCustomSuccess2) {
ProxyConfig config;
config.set_auto_detect(true);
config.set_pac_url(GURL("http://custom/proxy.pac"));
+ config.proxy_rules().ParseFromString("unused-manual-proxy:99");
rules.AddFailParsingRule("http://wpad/wpad.dat");
Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac");
TestCompletionCallback callback;
CapturingNetLog log(CapturingNetLog::kUnbounded);
+
+ ProxyConfig effective_config;
InitProxyResolver init(&resolver, &fetcher, &log);
- EXPECT_EQ(OK, init.Init(config, &callback));
+ EXPECT_EQ(OK, init.Init(config, base::TimeDelta(),
+ &effective_config, &callback));
EXPECT_EQ(rule.text(), resolver.script_data()->utf16());
+ // Verify that the effective configuration no longer contains auto detect or
+ // any of the manual settings.
+ EXPECT_TRUE(effective_config.Equals(
+ ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac"))));
+
// Check the NetLog was filled correctly.
// (Note that the Fetch and Set states are repeated since both WPAD and custom
// PAC scripts are tried).
@@ -356,7 +368,8 @@ TEST(InitProxyResolverTest, AutodetectFailCustomFails1) {
TestCompletionCallback callback;
InitProxyResolver init(&resolver, &fetcher, NULL);
- EXPECT_EQ(kFailedDownloading, init.Init(config, &callback));
+ EXPECT_EQ(kFailedDownloading,
+ init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(NULL, resolver.script_data());
}
@@ -375,7 +388,8 @@ TEST(InitProxyResolverTest, AutodetectFailCustomFails2) {
TestCompletionCallback callback;
InitProxyResolver init(&resolver, &fetcher, NULL);
- EXPECT_EQ(kFailedParsing, init.Init(config, &callback));
+ EXPECT_EQ(kFailedParsing,
+ init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(NULL, resolver.script_data());
}
@@ -396,9 +410,81 @@ TEST(InitProxyResolverTest, AutodetectFailCustomSuccess2_NoFetch) {
TestCompletionCallback callback;
InitProxyResolver init(&resolver, &fetcher, NULL);
- EXPECT_EQ(OK, init.Init(config, &callback));
+ EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback));
EXPECT_EQ(rule.url, resolver.script_data()->url());
}
+// This is a copy-paste of CustomPacFails1, with the exception that we give it
+// a 1 millisecond delay. This means it will now complete asynchronously.
+// Moreover, we test the NetLog to make sure it logged the pause.
+TEST(InitProxyResolverTest, CustomPacFails1_WithPositiveDelay) {
+ Rules rules;
+ RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/);
+ RuleBasedProxyScriptFetcher fetcher(&rules);
+
+ ProxyConfig config;
+ config.set_pac_url(GURL("http://custom/proxy.pac"));
+
+ rules.AddFailDownloadRule("http://custom/proxy.pac");
+
+ TestCompletionCallback callback;
+ CapturingNetLog log(CapturingNetLog::kUnbounded);
+ InitProxyResolver init(&resolver, &fetcher, &log);
+ EXPECT_EQ(ERR_IO_PENDING,
+ init.Init(config, base::TimeDelta::FromMilliseconds(1),
+ NULL, &callback));
+
+ EXPECT_EQ(kFailedDownloading, callback.WaitForResult());
+ EXPECT_EQ(NULL, resolver.script_data());
+
+ // Check the NetLog was filled correctly.
+ EXPECT_EQ(6u, log.entries().size());
+ EXPECT_TRUE(LogContainsBeginEvent(
+ log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ EXPECT_TRUE(LogContainsBeginEvent(
+ log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT));
+ EXPECT_TRUE(LogContainsEndEvent(
+ log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT));
+ EXPECT_TRUE(LogContainsBeginEvent(
+ log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(LogContainsEndEvent(
+ log.entries(), 4, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(LogContainsEndEvent(
+ log.entries(), 5, NetLog::TYPE_INIT_PROXY_RESOLVER));
+}
+
+// This is a copy-paste of CustomPacFails1, with the exception that we give it
+// a -5 second delay instead of a 0 ms delay. This change should have no effect
+// so the rest of the test is unchanged.
+TEST(InitProxyResolverTest, CustomPacFails1_WithNegativeDelay) {
+ Rules rules;
+ RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/);
+ RuleBasedProxyScriptFetcher fetcher(&rules);
+
+ ProxyConfig config;
+ config.set_pac_url(GURL("http://custom/proxy.pac"));
+
+ rules.AddFailDownloadRule("http://custom/proxy.pac");
+
+ TestCompletionCallback callback;
+ CapturingNetLog log(CapturingNetLog::kUnbounded);
+ InitProxyResolver init(&resolver, &fetcher, &log);
+ EXPECT_EQ(kFailedDownloading,
+ init.Init(config, base::TimeDelta::FromSeconds(-5),
+ NULL, &callback));
+ EXPECT_EQ(NULL, resolver.script_data());
+
+ // Check the NetLog was filled correctly.
+ EXPECT_EQ(4u, log.entries().size());
+ EXPECT_TRUE(LogContainsBeginEvent(
+ log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ EXPECT_TRUE(LogContainsBeginEvent(
+ log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(LogContainsEndEvent(
+ log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(LogContainsEndEvent(
+ log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER));
+}
+
} // namespace
} // namespace net
diff --git a/net/proxy/mock_proxy_resolver.h b/net/proxy/mock_proxy_resolver.h
index 9babb66..880612b 100644
--- a/net/proxy/mock_proxy_resolver.h
+++ b/net/proxy/mock_proxy_resolver.h
@@ -4,10 +4,12 @@
#ifndef NET_PROXY_MOCK_PROXY_RESOLVER_H_
#define NET_PROXY_MOCK_PROXY_RESOLVER_H_
+#pragma once
#include <vector>
#include "base/logging.h"
+#include "base/scoped_ptr.h"
#include "base/message_loop.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
diff --git a/net/proxy/multi_threaded_proxy_resolver.cc b/net/proxy/multi_threaded_proxy_resolver.cc
index 69e9ef7..95071b1 100644
--- a/net/proxy/multi_threaded_proxy_resolver.cc
+++ b/net/proxy/multi_threaded_proxy_resolver.cc
@@ -6,6 +6,7 @@
#include "base/message_loop.h"
#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"
@@ -315,7 +316,7 @@ MultiThreadedProxyResolver::Executor::Executor(
// Note that it is safe to pass a temporary C-String to Thread(), as it will
// make a copy.
std::string thread_name =
- StringPrintf("PAC thread #%d", thread_number);
+ base::StringPrintf("PAC thread #%d", thread_number);
thread_.reset(new base::Thread(thread_name.c_str()));
thread_->Start();
}
diff --git a/net/proxy/multi_threaded_proxy_resolver.h b/net/proxy/multi_threaded_proxy_resolver.h
index a69699a..1ad28f7 100644
--- a/net/proxy/multi_threaded_proxy_resolver.h
+++ b/net/proxy/multi_threaded_proxy_resolver.h
@@ -4,9 +4,9 @@
#ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
#define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
+#pragma once
#include <deque>
-#include <string>
#include <vector>
#include "base/basictypes.h"
diff --git a/net/proxy/multi_threaded_proxy_resolver_unittest.cc b/net/proxy/multi_threaded_proxy_resolver_unittest.cc
index 1a76d21..7027161 100644
--- a/net/proxy/multi_threaded_proxy_resolver_unittest.cc
+++ b/net/proxy/multi_threaded_proxy_resolver_unittest.cc
@@ -6,11 +6,13 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "base/waitable_event.h"
#include "googleurl/src/gurl.h"
+#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
-#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/proxy/proxy_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -618,8 +620,8 @@ TEST(MultiThreadedProxyResolverTest, ThreeThreads_Basic) {
for (int i = 1; i < kNumRequests; ++i) {
rv = resolver.GetProxyForURL(
- GURL(StringPrintf("http://request%d", i)), &results[i], &callback[i],
- &request[i], BoundNetLog());
+ GURL(base::StringPrintf("http://request%d", i)), &results[i],
+ &callback[i], &request[i], BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
}
@@ -724,7 +726,7 @@ TEST(MultiThreadedProxyResolverTest, OneThreadBlocked) {
for (int i = 1; i < kNumRequests; ++i) {
rv = resolver.GetProxyForURL(
- GURL(StringPrintf("http://request%d", i)),
+ GURL(base::StringPrintf("http://request%d", i)),
&results[i], &callback[i], &request[i], BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
}
diff --git a/net/proxy/proxy_bypass_rules.cc b/net/proxy/proxy_bypass_rules.cc
index e273d67..757d817 100644
--- a/net/proxy/proxy_bypass_rules.cc
+++ b/net/proxy/proxy_bypass_rules.cc
@@ -4,7 +4,7 @@
#include "net/proxy/proxy_bypass_rules.h"
-#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "net/base/net_util.h"
@@ -32,8 +32,7 @@ class HostnamePatternRule : public ProxyBypassRules::Rule {
// Note it is necessary to lower-case the host, since GURL uses capital
// letters for percent-escaped characters.
- return MatchPatternASCII(StringToLowerASCII(url.host()),
- hostname_pattern_);
+ return MatchPattern(StringToLowerASCII(url.host()), hostname_pattern_);
}
virtual std::string ToString() const {
@@ -123,9 +122,21 @@ bool IsIPAddress(const std::string& domain) {
} // namespace
+ProxyBypassRules::ProxyBypassRules() {
+}
+
+ProxyBypassRules::ProxyBypassRules(const ProxyBypassRules& rhs)
+ : rules_(rhs.rules_) {
+}
+
ProxyBypassRules::~ProxyBypassRules() {
}
+ProxyBypassRules& ProxyBypassRules::operator=(const ProxyBypassRules& rhs) {
+ rules_ = rhs.rules_;
+ return *this;
+}
+
bool ProxyBypassRules::Matches(const GURL& url) const {
for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); ++it) {
if ((*it)->Matches(url))
@@ -253,7 +264,7 @@ bool ProxyBypassRules::AddRuleFromStringInternal(
host = raw;
port = -1;
if (pos_colon != std::string::npos) {
- if (!StringToInt(raw.substr(pos_colon + 1), &port) ||
+ if (!base::StringToInt(raw.substr(pos_colon + 1), &port) ||
(port < 0 || port > 0xFFFF)) {
return false; // Port was invalid.
}
diff --git a/net/proxy/proxy_bypass_rules.h b/net/proxy/proxy_bypass_rules.h
index 267fdc9..9873154 100644
--- a/net/proxy/proxy_bypass_rules.h
+++ b/net/proxy/proxy_bypass_rules.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_PROXY_BYPASS_RULES_H_
#define NET_PROXY_PROXY_BYPASS_RULES_H_
+#pragma once
#include <string>
#include <vector>
@@ -42,8 +43,10 @@ class ProxyBypassRules {
typedef std::vector<scoped_refptr<Rule> > RuleList;
// Note: This class supports copy constructor and assignment.
-
+ ProxyBypassRules();
+ ProxyBypassRules(const ProxyBypassRules& rhs);
~ProxyBypassRules();
+ ProxyBypassRules& operator=(const ProxyBypassRules& rhs);
// Returns the current list of rules.
const RuleList& rules() const { return rules_; }
diff --git a/net/proxy/proxy_bypass_rules_unittest.cc b/net/proxy/proxy_bypass_rules_unittest.cc
index 208f9cd..5b6ce04 100644
--- a/net/proxy/proxy_bypass_rules_unittest.cc
+++ b/net/proxy/proxy_bypass_rules_unittest.cc
@@ -5,6 +5,7 @@
#include "net/proxy/proxy_bypass_rules.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/proxy/proxy_config_service_common_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -275,7 +276,7 @@ TEST(ProxyBypassRulesTest, BypassLocalNames) {
rules.ParseFromString("<local>");
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf(
+ SCOPED_TRACE(base::StringPrintf(
"Test[%d]: %s", static_cast<int>(i), tests[i].url));
EXPECT_EQ(tests[i].expected_is_local, rules.Matches(GURL(tests[i].url)));
}
diff --git a/net/proxy/proxy_config.cc b/net/proxy/proxy_config.cc
index 6e73101..ce14358 100644
--- a/net/proxy/proxy_config.cc
+++ b/net/proxy/proxy_config.cc
@@ -1,22 +1,44 @@
-// 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 "net/proxy/proxy_config.h"
+#include "base/logging.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
+#include "base/values.h"
#include "net/proxy/proxy_info.h"
namespace net {
+namespace {
+
+// If |proxy| is valid, sets it in |dict| under the key |name|.
+void AddProxyToValue(const char* name,
+ const ProxyServer& proxy,
+ DictionaryValue* dict) {
+ if (proxy.is_valid())
+ dict->SetString(name, proxy.ToURI());
+}
+
+} // namespace
+
+ProxyConfig::ProxyRules::ProxyRules()
+ : reverse_bypass(false),
+ type(TYPE_NO_RULES) {
+}
+
+ProxyConfig::ProxyRules::~ProxyRules() {
+}
+
bool ProxyConfig::ProxyRules::Equals(const ProxyRules& other) const {
return type == other.type &&
single_proxy == other.single_proxy &&
proxy_for_http == other.proxy_for_http &&
proxy_for_https == other.proxy_for_https &&
proxy_for_ftp == other.proxy_for_ftp &&
- socks_proxy == other.socks_proxy &&
+ fallback_proxy == other.fallback_proxy &&
bypass_rules.Equals(other.bypass_rules) &&
reverse_bypass == other.reverse_bypass;
}
@@ -66,7 +88,7 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
proxy_for_http = ProxyServer();
proxy_for_https = ProxyServer();
proxy_for_ftp = ProxyServer();
- socks_proxy = ProxyServer();
+ fallback_proxy = ProxyServer();
StringTokenizer proxy_server_list(proxy_rules, ";");
while (proxy_server_list.GetNext()) {
@@ -93,11 +115,21 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
// Add it to the per-scheme mappings (if supported scheme).
type = TYPE_PROXY_PER_SCHEME;
- if (ProxyServer* entry = MapSchemeToProxy(url_scheme)) {
- std::string proxy_server_token = proxy_server_for_scheme.token();
- ProxyServer::Scheme scheme = (entry == &socks_proxy) ?
- ProxyServer::SCHEME_SOCKS4 : ProxyServer::SCHEME_HTTP;
- *entry = ProxyServer::FromURI(proxy_server_token, scheme);
+ ProxyServer* entry = MapUrlSchemeToProxyNoFallback(url_scheme);
+ ProxyServer::Scheme default_scheme = ProxyServer::SCHEME_HTTP;
+
+ // socks=XXX is inconsistent with the other formats, since "socks"
+ // is not a URL scheme. Rather this means "for everything else, send
+ // it to the SOCKS proxy server XXX".
+ if (url_scheme == "socks") {
+ DCHECK(!entry);
+ entry = &fallback_proxy;
+ default_scheme = ProxyServer::SCHEME_SOCKS4;
+ }
+
+ if (entry) {
+ *entry = ProxyServer::FromURI(proxy_server_for_scheme.token(),
+ default_scheme);
}
}
}
@@ -106,31 +138,47 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
const ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxy(
const std::string& url_scheme) const {
const ProxyServer* proxy_server =
- const_cast<ProxyRules*>(this)->MapSchemeToProxy(url_scheme);
+ const_cast<ProxyRules*>(this)->MapUrlSchemeToProxyNoFallback(url_scheme);
if (proxy_server && proxy_server->is_valid())
return proxy_server;
- if (socks_proxy.is_valid())
- return &socks_proxy;
+ if (fallback_proxy.is_valid())
+ return &fallback_proxy;
return NULL; // No mapping for this scheme. Use direct.
}
-ProxyServer* ProxyConfig::ProxyRules::MapSchemeToProxy(
+ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxyNoFallback(
const std::string& scheme) {
- DCHECK(type == TYPE_PROXY_PER_SCHEME);
+ DCHECK_EQ(TYPE_PROXY_PER_SCHEME, type);
if (scheme == "http")
return &proxy_for_http;
if (scheme == "https")
return &proxy_for_https;
if (scheme == "ftp")
return &proxy_for_ftp;
- if (scheme == "socks")
- return &socks_proxy;
return NULL; // No mapping for this scheme.
}
ProxyConfig::ProxyConfig() : auto_detect_(false), id_(INVALID_ID) {
}
+ProxyConfig::ProxyConfig(const ProxyConfig& config)
+ : auto_detect_(config.auto_detect_),
+ pac_url_(config.pac_url_),
+ proxy_rules_(config.proxy_rules_),
+ id_(config.id_) {
+}
+
+ProxyConfig::~ProxyConfig() {
+}
+
+ProxyConfig& ProxyConfig::operator=(const ProxyConfig& config) {
+ auto_detect_ = config.auto_detect_;
+ pac_url_ = config.pac_url_;
+ proxy_rules_ = config.proxy_rules_;
+ id_ = config.id_;
+ return *this;
+}
+
bool ProxyConfig::Equals(const ProxyConfig& other) const {
// The two configs can have different IDs. We are just interested in if they
// have the same settings.
@@ -139,107 +187,63 @@ bool ProxyConfig::Equals(const ProxyConfig& other) const {
proxy_rules_.Equals(other.proxy_rules());
}
-bool ProxyConfig::MayRequirePACResolver() const {
+bool ProxyConfig::HasAutomaticSettings() const {
return auto_detect_ || has_pac_url();
}
-} // namespace net
-
-namespace {
-
-// Helper to stringize a ProxyServer.
-std::ostream& operator<<(std::ostream& out,
- const net::ProxyServer& proxy_server) {
- if (proxy_server.is_valid())
- out << proxy_server.ToURI();
- return out;
+void ProxyConfig::ClearAutomaticSettings() {
+ auto_detect_ = false;
+ pac_url_ = GURL();
}
-const char* BoolToYesNoString(bool b) {
- return b ? "Yes" : "No";
-}
+Value* ProxyConfig::ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+
+ // Output the automatic settings.
+ if (auto_detect_)
+ dict->SetBoolean("auto_detect", auto_detect_);
+ if (has_pac_url())
+ dict->SetString("pac_url", pac_url_.possibly_invalid_spec());
+
+ // Output the manual settings.
+ if (proxy_rules_.type != ProxyRules::TYPE_NO_RULES) {
+ switch (proxy_rules_.type) {
+ case ProxyRules::TYPE_SINGLE_PROXY:
+ AddProxyToValue("single_proxy", proxy_rules_.single_proxy, dict);
+ break;
+ case ProxyRules::TYPE_PROXY_PER_SCHEME: {
+ DictionaryValue* dict2 = new DictionaryValue();
+ AddProxyToValue("http", proxy_rules_.proxy_for_http, dict2);
+ AddProxyToValue("https", proxy_rules_.proxy_for_https, dict2);
+ AddProxyToValue("ftp", proxy_rules_.proxy_for_ftp, dict2);
+ AddProxyToValue("fallback", proxy_rules_.fallback_proxy, dict2);
+ dict->Set("proxy_per_scheme", dict2);
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
-} // namespace
+ // Output the bypass rules.
+ const ProxyBypassRules& bypass = proxy_rules_.bypass_rules;
+ if (!bypass.rules().empty()) {
+ if (proxy_rules_.reverse_bypass)
+ dict->SetBoolean("reverse_bypass", true);
-std::ostream& operator<<(std::ostream& out,
- const net::ProxyConfig::ProxyRules& rules) {
- // Stringize the type enum.
- std::string type;
- switch (rules.type) {
- case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
- type = "TYPE_NO_RULES";
- break;
- case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
- type = "TYPE_PROXY_PER_SCHEME";
- break;
- case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
- type = "TYPE_SINGLE_PROXY";
- break;
- default:
- type = IntToString(rules.type);
- break;
- }
- return out << " {\n"
- << " type: " << type << "\n"
- << " single_proxy: " << rules.single_proxy << "\n"
- << " proxy_for_http: " << rules.proxy_for_http << "\n"
- << " proxy_for_https: " << rules.proxy_for_https << "\n"
- << " proxy_for_ftp: " << rules.proxy_for_ftp << "\n"
- << " socks_proxy: " << rules.socks_proxy << "\n"
- << " }";
-}
-
-std::ostream& operator<<(std::ostream& out, const net::ProxyConfig& config) {
- // "Automatic" settings.
- out << "Automatic settings:\n";
- out << " Auto-detect: " << BoolToYesNoString(config.auto_detect()) << "\n";
- out << " Custom PAC script: ";
- if (config.has_pac_url())
- out << config.pac_url();
- else
- out << "[None]";
- out << "\n";
-
- // "Manual" settings.
- out << "Manual settings:\n";
- out << " Proxy server: ";
-
- switch (config.proxy_rules().type) {
- case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
- out << "[None]\n";
- break;
- case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
- out << config.proxy_rules().single_proxy;
- out << "\n";
- break;
- case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
- out << "\n";
- if (config.proxy_rules().proxy_for_http.is_valid())
- out << " HTTP: " << config.proxy_rules().proxy_for_http << "\n";
- if (config.proxy_rules().proxy_for_https.is_valid())
- out << " HTTPS: " << config.proxy_rules().proxy_for_https << "\n";
- if (config.proxy_rules().proxy_for_ftp.is_valid())
- out << " FTP: " << config.proxy_rules().proxy_for_ftp << "\n";
- if (config.proxy_rules().socks_proxy.is_valid())
- out << " SOCKS: " << config.proxy_rules().socks_proxy << "\n";
- break;
- }
+ ListValue* list = new ListValue();
+
+ for (ProxyBypassRules::RuleList::const_iterator it =
+ bypass.rules().begin();
+ it != bypass.rules().end(); ++it) {
+ list->Append(Value::CreateStringValue((*it)->ToString()));
+ }
- if (config.proxy_rules().reverse_bypass)
- out << " Only use proxy for: ";
- else
- out << " Bypass list: ";
- if (config.proxy_rules().bypass_rules.rules().empty()) {
- out << "[None]";
- } else {
- const net::ProxyBypassRules& bypass_rules =
- config.proxy_rules().bypass_rules;
- net::ProxyBypassRules::RuleList::const_iterator it;
- for (it = bypass_rules.rules().begin();
- it != bypass_rules.rules().end(); ++it) {
- out << "\n " << (*it)->ToString();
+ dict->Set("bypass_list", list);
}
}
- return out;
+ return dict;
}
+
+} // namespace net
+
diff --git a/net/proxy/proxy_config.h b/net/proxy/proxy_config.h
index a247e38..9012a31 100644
--- a/net/proxy/proxy_config.h
+++ b/net/proxy/proxy_config.h
@@ -1,18 +1,19 @@
-// 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.
#ifndef NET_PROXY_PROXY_CONFIG_H_
#define NET_PROXY_PROXY_CONFIG_H_
+#pragma once
-#include <ostream>
#include <string>
-#include <vector>
#include "googleurl/src/gurl.h"
#include "net/proxy/proxy_bypass_rules.h"
#include "net/proxy/proxy_server.h"
+class Value;
+
namespace net {
class ProxyInfo;
@@ -41,7 +42,8 @@ class ProxyConfig {
// Note that the default of TYPE_NO_RULES results in direct connections
// being made when using this ProxyConfig.
- ProxyRules() : reverse_bypass(false), type(TYPE_NO_RULES) {}
+ ProxyRules();
+ ~ProxyRules();
bool empty() const {
return type == TYPE_NO_RULES;
@@ -69,9 +71,7 @@ class ProxyConfig {
void ParseFromString(const std::string& proxy_rules);
// Returns one of {&proxy_for_http, &proxy_for_https, &proxy_for_ftp,
- // &socks_proxy}, or NULL if it is a scheme that we don't have a mapping
- // for. If the scheme mapping is not present and socks_proxy is defined,
- // we fall back to using socks_proxy.
+ // &fallback_proxy}, or NULL if there is no proxy to use.
// Should only call this if the type is TYPE_PROXY_PER_SCHEME.
const ProxyServer* MapUrlSchemeToProxy(const std::string& url_scheme) const;
@@ -94,14 +94,14 @@ class ProxyConfig {
ProxyServer proxy_for_https;
ProxyServer proxy_for_ftp;
- // Set if the configuration has a SOCKS proxy fallback.
- ProxyServer socks_proxy;
+ // Used when there isn't a more specific per-scheme proxy server.
+ ProxyServer fallback_proxy;
private:
- // Returns one of {&proxy_for_http, &proxy_for_https, &proxy_for_ftp,
- // &socks_proxy}, or NULL if it is a scheme that we don't have a mapping
+ // Returns one of {&proxy_for_http, &proxy_for_https, &proxy_for_ftp}
+ // or NULL if it is a scheme that we don't have a mapping
// for. Should only call this if the type is TYPE_PROXY_PER_SCHEME.
- ProxyServer* MapSchemeToProxy(const std::string& scheme);
+ ProxyServer* MapUrlSchemeToProxyNoFallback(const std::string& scheme);
};
typedef int ID;
@@ -110,18 +110,27 @@ class ProxyConfig {
enum { INVALID_ID = 0 };
ProxyConfig();
+ ProxyConfig(const ProxyConfig& config);
+ ~ProxyConfig();
+ ProxyConfig& operator=(const ProxyConfig& config);
// Used to numerically identify this configuration.
ID id() const { return id_; }
void set_id(int id) { id_ = id; }
- bool is_valid() { return id_ != INVALID_ID; }
+ bool is_valid() const { return id_ != INVALID_ID; }
// Returns true if the given config is equivalent to this config.
bool Equals(const ProxyConfig& other) const;
- // Returns true if this config could possibly require the proxy service to
- // use a PAC resolver.
- bool MayRequirePACResolver() const;
+ // Returns true if this config contains any "automatic" settings. See the
+ // class description for what that means.
+ bool HasAutomaticSettings() const;
+
+ void ClearAutomaticSettings();
+
+ // Creates a Value dump of this configuration. The caller is responsible for
+ // deleting the returned value.
+ Value* ToValue() const;
ProxyRules& proxy_rules() {
return proxy_rules_;
@@ -184,13 +193,6 @@ class ProxyConfig {
} // namespace net
-// Dumps a human-readable string representation of the configuration to |out|;
-// used when logging the configuration changes.
-std::ostream& operator<<(std::ostream& out, const net::ProxyConfig& config);
-// Dumps a human-readable string representation of the |rules| to |out|;
-// used for logging and for better unittest failure output.
-std::ostream& operator<<(std::ostream& out,
- const net::ProxyConfig::ProxyRules& rules);
#endif // NET_PROXY_PROXY_CONFIG_H_
diff --git a/net/proxy/proxy_config_service.h b/net/proxy/proxy_config_service.h
index 9f6bb50..da67cd6 100644
--- a/net/proxy/proxy_config_service.h
+++ b/net/proxy/proxy_config_service.h
@@ -1,24 +1,48 @@
-// 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.
#ifndef NET_PROXY_PROXY_CONFIG_SERVICE_H_
#define NET_PROXY_PROXY_CONFIG_SERVICE_H_
+#pragma once
namespace net {
class ProxyConfig;
-// Synchronously fetch the system's proxy configuration settings. Called on
-// the IO Thread.
+// Service for watching when the proxy settings have changed.
class ProxyConfigService {
public:
+ // Observer for being notified when the proxy settings have changed.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+ virtual void OnProxyConfigChanged(const ProxyConfig& config) = 0;
+ };
+
virtual ~ProxyConfigService() {}
- // Get the proxy configuration. Returns OK if successful or an error code if
- // otherwise. |config| should be in its initial state when this method is
- // called.
- virtual int GetProxyConfig(ProxyConfig* config) = 0;
+ // Adds/Removes an observer that will be called whenever the proxy
+ // configuration has changed.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Gets the most recent value of the proxy configuration. Returns false if
+ // it is not available yet. In the case where we returned false, it is
+ // guaranteed that subscribed observers will be notified of a change at
+ // some point in the future once the configuration is available.
+ // Note that to avoid re-entrancy problems, implementations should not
+ // dispatch any change notifications from within this function.
+ virtual bool GetLatestProxyConfig(ProxyConfig* config) = 0;
+
+ // ProxyService will call this periodically during periods of activity.
+ // It can be used as a signal for polling-based implementations.
+ //
+ // Note that this is purely used as an optimization -- polling
+ // implementations could simply set a global timer that goes off every
+ // X seconds at which point they check for changes. However that has
+ // the disadvantage of doing continuous work even during idle periods.
+ virtual void OnLazyPoll() {}
};
} // namespace net
diff --git a/net/proxy/proxy_config_service_common_unittest.cc b/net/proxy/proxy_config_service_common_unittest.cc
index 9e5fd76..b233bb6 100644
--- a/net/proxy/proxy_config_service_common_unittest.cc
+++ b/net/proxy/proxy_config_service_common_unittest.cc
@@ -66,8 +66,8 @@ std::string FlattenProxyBypass(const ProxyBypassRules& bypass_rules) {
rules.proxy_for_http, &failure_details, &failed);
MatchesProxyServerHelper("Bad proxy_for_https", proxy_for_https,
rules.proxy_for_https, &failure_details, &failed);
- MatchesProxyServerHelper("Bad proxy_for_socks", socks_proxy,
- rules.socks_proxy, &failure_details, &failed);
+ MatchesProxyServerHelper("Bad fallback_proxy", fallback_proxy,
+ rules.fallback_proxy, &failure_details, &failed);
std::string actual_flattened_bypass = FlattenProxyBypass(rules.bypass_rules);
if (std::string(flattened_bypass_rules) != actual_flattened_bypass) {
diff --git a/net/proxy/proxy_config_service_common_unittest.h b/net/proxy/proxy_config_service_common_unittest.h
index 3b70ef0..b64cd6b 100644
--- a/net/proxy/proxy_config_service_common_unittest.h
+++ b/net/proxy/proxy_config_service_common_unittest.h
@@ -1,12 +1,10 @@
-// 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.
#ifndef NET_PROXY_PROXY_CONFIG_SERVICE_COMMON_UNITTEST_H_
#define NET_PROXY_PROXY_CONFIG_SERVICE_COMMON_UNITTEST_H_
-
-#include <string>
-#include <vector>
+#pragma once
#include "net/proxy/proxy_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -16,8 +14,6 @@
namespace net {
-class ProxyBypassRules;
-
// This structure contains our expectations on what values the ProxyRules
// should have.
struct ProxyRulesExpectation {
@@ -26,7 +22,7 @@ struct ProxyRulesExpectation {
const char* proxy_for_http,
const char* proxy_for_https,
const char* proxy_for_ftp,
- const char* socks_proxy,
+ const char* fallback_proxy,
const char* flattened_bypass_rules,
bool reverse_bypass)
: type(type),
@@ -34,7 +30,7 @@ struct ProxyRulesExpectation {
proxy_for_http(proxy_for_http),
proxy_for_https(proxy_for_https),
proxy_for_ftp(proxy_for_ftp),
- socks_proxy(socks_proxy),
+ fallback_proxy(fallback_proxy),
flattened_bypass_rules(flattened_bypass_rules),
reverse_bypass(reverse_bypass) {
}
@@ -70,7 +66,7 @@ struct ProxyRulesExpectation {
const char* proxy_http,
const char* proxy_https,
const char* proxy_ftp,
- const char* socks_proxy,
+ const char* fallback_proxy,
const char* flattened_bypass_rules);
// Same as PerScheme, but with the bypass rules reversed
@@ -85,7 +81,7 @@ struct ProxyRulesExpectation {
const char* proxy_for_http;
const char* proxy_for_https;
const char* proxy_for_ftp;
- const char* socks_proxy;
+ const char* fallback_proxy;
const char* flattened_bypass_rules;
bool reverse_bypass;
};
diff --git a/net/proxy/proxy_config_service_fixed.h b/net/proxy/proxy_config_service_fixed.h
index b677eb4..e9eac8e 100644
--- a/net/proxy/proxy_config_service_fixed.h
+++ b/net/proxy/proxy_config_service_fixed.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_PROXY_CONFIG_SERVICE_FIXED_H_
#define NET_PROXY_PROXY_CONFIG_SERVICE_FIXED_H_
+#pragma once
#include "net/base/net_errors.h"
#include "net/proxy/proxy_config.h"
@@ -17,9 +18,11 @@ class ProxyConfigServiceFixed : public ProxyConfigService {
explicit ProxyConfigServiceFixed(const ProxyConfig& pc) : pc_(pc) {}
// ProxyConfigService methods:
- virtual int GetProxyConfig(ProxyConfig* config) {
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual bool GetLatestProxyConfig(ProxyConfig* config) {
*config = pc_;
- return OK;
+ return true;
}
private:
diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc
index bd863bd..b61167f 100644
--- a/net/proxy/proxy_config_service_linux.cc
+++ b/net/proxy/proxy_config_service_linux.cc
@@ -15,11 +15,12 @@
#include <map>
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/task.h"
@@ -42,11 +43,11 @@ namespace {
// TODO(arindam): Remove URI string manipulation by using MapUrlSchemeToProxy.
std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
std::string host) {
- if (scheme == ProxyServer::SCHEME_SOCKS4 &&
- StartsWithASCII(host, "socks5://", false)) {
- // We default to socks 4, but if the user specifically set it to
- // socks5://, then use that.
- scheme = ProxyServer::SCHEME_SOCKS5;
+ if (scheme == ProxyServer::SCHEME_SOCKS5 &&
+ StartsWithASCII(host, "socks4://", false)) {
+ // We default to socks 5, but if the user specifically set it to
+ // socks4://, then use that.
+ scheme = ProxyServer::SCHEME_SOCKS4;
}
// Strip the scheme if any.
std::string::size_type colon = host.find("://");
@@ -78,11 +79,14 @@ std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
} // namespace
+ProxyConfigServiceLinux::Delegate::~Delegate() {
+}
+
bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVarForScheme(
const char* variable, ProxyServer::Scheme scheme,
ProxyServer* result_server) {
std::string env_value;
- if (env_var_getter_->GetEnv(variable, &env_value)) {
+ if (env_var_getter_->GetVar(variable, &env_value)) {
if (!env_value.empty()) {
env_value = FixupProxyHostScheme(scheme, env_value);
ProxyServer proxy_server =
@@ -110,7 +114,7 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) {
// extension has ever used this, but it still sounds like a good
// idea.
std::string auto_proxy;
- if (env_var_getter_->GetEnv("auto_proxy", &auto_proxy)) {
+ if (env_var_getter_->GetVar("auto_proxy", &auto_proxy)) {
if (auto_proxy.empty()) {
// Defined and empty => autodetect
config->set_auto_detect(true);
@@ -148,11 +152,13 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) {
}
if (config->proxy_rules().empty()) {
// If the above were not defined, try for socks.
- ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS4;
+ // For environment variables, we default to version 5, per the gnome
+ // documentation: http://library.gnome.org/devel/gnet/stable/gnet-socks.html
+ ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS5;
std::string env_version;
- if (env_var_getter_->GetEnv("SOCKS_VERSION", &env_version)
- && env_version == "5")
- scheme = ProxyServer::SCHEME_SOCKS5;
+ if (env_var_getter_->GetVar("SOCKS_VERSION", &env_version)
+ && env_version == "4")
+ scheme = ProxyServer::SCHEME_SOCKS4;
if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) {
config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
config->proxy_rules().single_proxy = proxy_server;
@@ -160,7 +166,7 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) {
}
// Look for the proxy bypass list.
std::string no_proxy;
- env_var_getter_->GetEnv("no_proxy", &no_proxy);
+ env_var_getter_->GetVar("no_proxy", &no_proxy);
if (config->proxy_rules().empty()) {
// Having only "no_proxy" set, presumably to "*", makes it
// explicit that env vars do specify a configuration: having no
@@ -421,19 +427,19 @@ class GConfSettingGetterImplKDE
: public ProxyConfigServiceLinux::GConfSettingGetter,
public base::MessagePumpLibevent::Watcher {
public:
- explicit GConfSettingGetterImplKDE(base::EnvVarGetter* env_var_getter)
+ explicit GConfSettingGetterImplKDE(base::Environment* env_var_getter)
: inotify_fd_(-1), notify_delegate_(NULL), indirect_manual_(false),
auto_no_pac_(false), reversed_bypass_list_(false),
env_var_getter_(env_var_getter), file_loop_(NULL) {
// Derive the location of the kde config dir from the environment.
std::string home;
- if (env_var_getter->GetEnv("KDEHOME", &home) && !home.empty()) {
+ if (env_var_getter->GetVar("KDEHOME", &home) && !home.empty()) {
// $KDEHOME is set. Use it unconditionally.
kde_config_dir_ = KDEHomeToConfigPath(FilePath(home));
} else {
// $KDEHOME is unset. Try to figure out what to use. This seems to be
// the common case on most distributions.
- if (!env_var_getter->GetEnv(base::env_vars::kHome, &home))
+ if (!env_var_getter->GetVar(base::env_vars::kHome, &home))
// User has no $HOME? Give up. Later we'll report the failure.
return;
if (base::GetDesktopEnvironment(env_var_getter) ==
@@ -458,8 +464,8 @@ class GConfSettingGetterImplKDE
FilePath kde4_config = KDEHomeToConfigPath(kde4_path);
bool use_kde4 = false;
if (file_util::DirectoryExists(kde4_path)) {
- file_util::FileInfo kde3_info;
- file_util::FileInfo kde4_info;
+ base::PlatformFileInfo kde3_info;
+ base::PlatformFileInfo kde4_info;
if (file_util::GetFileInfo(kde4_config, &kde4_info)) {
if (file_util::GetFileInfo(kde3_config, &kde3_info)) {
use_kde4 = kde4_info.last_modified >= kde3_info.last_modified;
@@ -632,7 +638,9 @@ class GConfSettingGetterImplKDE
const char* mode = "none";
indirect_manual_ = false;
auto_no_pac_ = false;
- switch (StringToInt(value)) {
+ int int_value;
+ base::StringToInt(value, &int_value);
+ switch (int_value) {
case 0: // No proxy, or maybe kioslaverc syntax error.
break;
case 1: // Manual configuration.
@@ -663,12 +671,15 @@ class GConfSettingGetterImplKDE
// We count "true" or any nonzero number as true, otherwise false.
// Note that if the value is not actually numeric StringToInt()
// will return 0, which we count as false.
- reversed_bypass_list_ = (value == "true" || StringToInt(value));
+ int int_value;
+ base::StringToInt(value, &int_value);
+ reversed_bypass_list_ = (value == "true" || int_value);
} else if (key == "NoProxyFor") {
AddHostList("/system/http_proxy/ignore_hosts", value);
} else if (key == "AuthMode") {
// Check for authentication, just so we can warn.
- int mode = StringToInt(value);
+ int mode;
+ base::StringToInt(value, &mode);
if (mode) {
// ProxyConfig does not support authentication parameters, but
// Chrome will prompt for the password later. So we ignore this.
@@ -682,7 +693,7 @@ class GConfSettingGetterImplKDE
string_map_type::iterator it = string_table_.find(key);
if (it != string_table_.end()) {
std::string value;
- if (env_var_getter_->GetEnv(it->second.c_str(), &value))
+ if (env_var_getter_->GetVar(it->second.c_str(), &value))
it->second = value;
else
string_table_.erase(it);
@@ -694,7 +705,7 @@ class GConfSettingGetterImplKDE
if (it != strings_table_.end()) {
std::string value;
if (!it->second.empty() &&
- env_var_getter_->GetEnv(it->second[0].c_str(), &value))
+ env_var_getter_->GetVar(it->second[0].c_str(), &value))
AddHostList(key, value);
else
strings_table_.erase(it);
@@ -873,7 +884,7 @@ class GConfSettingGetterImplKDE
// We don't own |env_var_getter_|. It's safe to hold a pointer to it, since
// both it and us are owned by ProxyConfigServiceLinux::Delegate, and have the
// same lifetime.
- base::EnvVarGetter* env_var_getter_;
+ base::Environment* env_var_getter_;
// We cache these settings whenever we re-read the kioslaverc file.
string_map_type string_table_;
@@ -903,10 +914,10 @@ bool ProxyConfigServiceLinux::Delegate::GetProxyFromGConf(
gconf_getter_->GetInt((key + "port").c_str(), &port);
if (port != 0) {
// If a port is set and non-zero:
- host += ":" + IntToString(port);
+ host += ":" + base::IntToString(port);
}
host = FixupProxyHostScheme(
- is_socks ? ProxyServer::SCHEME_SOCKS4 : ProxyServer::SCHEME_HTTP,
+ is_socks ? ProxyServer::SCHEME_SOCKS5 : ProxyServer::SCHEME_HTTP,
host);
ProxyServer proxy_server = ProxyServer::FromURI(host,
ProxyServer::SCHEME_HTTP);
@@ -973,7 +984,9 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromGConf(
// Try socks.
if (GetProxyFromGConf("/system/proxy/socks_", true, &proxy_server)) {
// gconf settings do not appear to distinguish between socks
- // version. We default to version 4.
+ // version. We default to version 5. For more information on this policy
+ // decisions, see:
+ // http://code.google.com/p/chromium/issues/detail?id=55912#c2
config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
config->proxy_rules().single_proxy = proxy_server;
}
@@ -1045,7 +1058,7 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromGConf(
return true;
}
-ProxyConfigServiceLinux::Delegate::Delegate(base::EnvVarGetter* env_var_getter)
+ProxyConfigServiceLinux::Delegate::Delegate(base::Environment* env_var_getter)
: env_var_getter_(env_var_getter),
glib_default_loop_(NULL), io_loop_(NULL) {
// Figure out which GConfSettingGetterImpl to use, if any.
@@ -1063,7 +1076,7 @@ ProxyConfigServiceLinux::Delegate::Delegate(base::EnvVarGetter* env_var_getter)
}
}
-ProxyConfigServiceLinux::Delegate::Delegate(base::EnvVarGetter* env_var_getter,
+ProxyConfigServiceLinux::Delegate::Delegate(base::Environment* env_var_getter,
GConfSettingGetter* gconf_getter)
: env_var_getter_(env_var_getter), gconf_getter_(gconf_getter),
glib_default_loop_(NULL), io_loop_(NULL) {
@@ -1085,7 +1098,7 @@ void ProxyConfigServiceLinux::Delegate::SetupAndFetchInitialConfig(
LOG(INFO) << "Monitoring of proxy setting changes is disabled";
// Fetch and cache the current proxy config. The config is left in
- // cached_config_, where GetProxyConfig() running on the IO thread
+ // cached_config_, where GetLatestProxyConfig() running on the IO thread
// will expect to find it. This is safe to do because we return
// before this ProxyConfigServiceLinux is passed on to
// the ProxyService.
@@ -1133,14 +1146,30 @@ void ProxyConfigServiceLinux::Delegate::SetupAndFetchInitialConfig(
}
}
-int ProxyConfigServiceLinux::Delegate::GetProxyConfig(ProxyConfig* config) {
+void ProxyConfigServiceLinux::Delegate::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ProxyConfigServiceLinux::Delegate::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool ProxyConfigServiceLinux::Delegate::GetLatestProxyConfig(
+ ProxyConfig* config) {
// This is called from the IO thread.
DCHECK(!io_loop_ || MessageLoop::current() == io_loop_);
// Simply return the last proxy configuration that glib_default_loop
// notified us of.
- *config = cached_config_;
- return cached_config_.is_valid() ? OK : ERR_FAILED;
+ *config = cached_config_.is_valid() ?
+ cached_config_ : ProxyConfig::CreateDirect();
+
+ // We return true to indicate that *config was filled in. It is always
+ // going to be available since we initialized eagerly on the UI thread.
+ // TODO(eroman): do lazy initialization instead, so we no longer need
+ // to construct ProxyConfigServiceLinux on the UI thread.
+ // In which case, we may return false here.
+ return true;
}
// Depending on the GConfSettingGetter in use, this method will be called
@@ -1153,7 +1182,7 @@ void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() {
if (valid)
new_config.set_id(1); // mark it as valid
- // See if it is different than what we had before.
+ // See if it is different from what we had before.
if (new_config.is_valid() != reference_config_.is_valid() ||
!new_config.Equals(reference_config_)) {
// Post a task to |io_loop| with the new configuration, so it can
@@ -1174,6 +1203,7 @@ void ProxyConfigServiceLinux::Delegate::SetNewProxyConfig(
DCHECK(MessageLoop::current() == io_loop_);
LOG(INFO) << "Proxy configuration changed";
cached_config_ = new_config;
+ FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(new_config));
}
void ProxyConfigServiceLinux::Delegate::PostDestroyTask() {
@@ -1201,16 +1231,20 @@ void ProxyConfigServiceLinux::Delegate::OnDestroy() {
}
ProxyConfigServiceLinux::ProxyConfigServiceLinux()
- : delegate_(new Delegate(base::EnvVarGetter::Create())) {
+ : delegate_(new Delegate(base::Environment::Create())) {
+}
+
+ProxyConfigServiceLinux::~ProxyConfigServiceLinux() {
+ delegate_->PostDestroyTask();
}
ProxyConfigServiceLinux::ProxyConfigServiceLinux(
- base::EnvVarGetter* env_var_getter)
+ base::Environment* env_var_getter)
: delegate_(new Delegate(env_var_getter)) {
}
ProxyConfigServiceLinux::ProxyConfigServiceLinux(
- base::EnvVarGetter* env_var_getter,
+ base::Environment* env_var_getter,
GConfSettingGetter* gconf_getter)
: delegate_(new Delegate(env_var_getter, gconf_getter)) {
}
diff --git a/net/proxy/proxy_config_service_linux.h b/net/proxy/proxy_config_service_linux.h
index 44ea4de..cd70ea7 100644
--- a/net/proxy/proxy_config_service_linux.h
+++ b/net/proxy/proxy_config_service_linux.h
@@ -4,13 +4,15 @@
#ifndef NET_PROXY_PROXY_CONFIG_SERVICE_LINUX_H_
#define NET_PROXY_PROXY_CONFIG_SERVICE_LINUX_H_
+#pragma once
#include <string>
#include <vector>
#include "base/basictypes.h"
-#include "base/env_var.h"
+#include "base/environment.h"
#include "base/message_loop.h"
+#include "base/observer_list.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "net/proxy/proxy_config.h"
@@ -90,16 +92,18 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// ProxyConfigServiceLinux is created on the UI thread, and
// SetupAndFetchInitialConfig() is immediately called to
- // synchronously fetch the original configuration and setup gconf
+ // synchronously fetch the original configuration and set up gconf
// notifications on the UI thread.
//
- // Passed that point, it is accessed periodically through
- // GetProxyConfig() from the IO thread.
+ // Past that point, it is accessed periodically through the
+ // ProxyConfigService interface (GetLatestProxyConfig, AddObserver,
+ // RemoveObserver) from the IO thread.
//
// gconf change notification callbacks can occur at any time and are
// run on the UI thread. The new gconf settings are fetched on the
// UI thread, and the new resulting proxy config is posted to the IO
- // thread through Delegate::SetNewProxyConfig().
+ // thread through Delegate::SetNewProxyConfig(). We then notify
+ // observers on the IO thread of the configuration change.
//
// ProxyConfigServiceLinux is deleted from the IO thread.
//
@@ -113,10 +117,10 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
public:
// Constructor receives env var getter implementation to use, and
// takes ownership of it. This is the normal constructor.
- explicit Delegate(base::EnvVarGetter* env_var_getter);
+ explicit Delegate(base::Environment* env_var_getter);
// Constructor receives gconf and env var getter implementations
// to use, and takes ownership of them. Used for testing.
- Delegate(base::EnvVarGetter* env_var_getter,
+ Delegate(base::Environment* env_var_getter,
GConfSettingGetter* gconf_getter);
// Synchronously obtains the proxy configuration. If gconf is
// used, also enables gconf notification for setting
@@ -138,7 +142,9 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
void OnCheckProxyConfigSettings();
// Called from IO thread.
- int GetProxyConfig(ProxyConfig* config);
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+ bool GetLatestProxyConfig(ProxyConfig* config);
// Posts a call to OnDestroy() to the UI thread. Called from
// ProxyConfigServiceLinux's destructor.
@@ -149,7 +155,7 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
private:
friend class base::RefCountedThreadSafe<Delegate>;
- ~Delegate() {}
+ ~Delegate();
// Obtains an environment variable's value. Parses a proxy server
// specification from it and puts it in result. Returns true if the
@@ -176,11 +182,11 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// carry the new config information.
void SetNewProxyConfig(const ProxyConfig& new_config);
- scoped_ptr<base::EnvVarGetter> env_var_getter_;
+ scoped_ptr<base::Environment> env_var_getter_;
scoped_ptr<GConfSettingGetter> gconf_getter_;
// Cached proxy configuration, to be returned by
- // GetProxyConfig. Initially populated from the UI thread, but
+ // GetLatestProxyConfig. Initially populated from the UI thread, but
// afterwards only accessed from the IO thread.
ProxyConfig cached_config_;
@@ -199,10 +205,12 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// this thread. Since gconf is not thread safe, any use of gconf
// must be done on the thread running this loop.
MessageLoop* glib_default_loop_;
- // MessageLoop for the IO thread. GetProxyConfig() is called from
+ // MessageLoop for the IO thread. GetLatestProxyConfig() is called from
// the thread running this loop.
MessageLoop* io_loop_;
+ ObserverList<Observer> observers_;
+
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
@@ -211,13 +219,11 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// Usual constructor
ProxyConfigServiceLinux();
// For testing: take alternate gconf and env var getter implementations.
- explicit ProxyConfigServiceLinux(base::EnvVarGetter* env_var_getter);
- ProxyConfigServiceLinux(base::EnvVarGetter* env_var_getter,
+ explicit ProxyConfigServiceLinux(base::Environment* env_var_getter);
+ ProxyConfigServiceLinux(base::Environment* env_var_getter,
GConfSettingGetter* gconf_getter);
- virtual ~ProxyConfigServiceLinux() {
- delegate_->PostDestroyTask();
- }
+ virtual ~ProxyConfigServiceLinux();
void SetupAndFetchInitialConfig(MessageLoop* glib_default_loop,
MessageLoop* io_loop,
@@ -233,8 +239,17 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// ProxyConfigService methods:
// Called from IO thread.
- virtual int GetProxyConfig(ProxyConfig* config) {
- return delegate_->GetProxyConfig(config);
+
+ 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);
}
private:
diff --git a/net/proxy/proxy_config_service_linux_unittest.cc b/net/proxy/proxy_config_service_linux_unittest.cc
index 0a84548..2cb1259 100644
--- a/net/proxy/proxy_config_service_linux_unittest.cc
+++ b/net/proxy/proxy_config_service_linux_unittest.cc
@@ -13,6 +13,7 @@
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/task.h"
#include "base/thread.h"
#include "base/waitable_event.h"
@@ -78,9 +79,9 @@ struct SettingsTable {
map_type settings;
};
-class MockEnvVarGetter : public base::EnvVarGetter {
+class MockEnvironment : public base::Environment {
public:
- MockEnvVarGetter() {
+ MockEnvironment() {
#define ENTRY(x) table.settings[#x] = &values.x
ENTRY(DESKTOP_SESSION);
ENTRY(HOME);
@@ -104,7 +105,8 @@ class MockEnvVarGetter : public base::EnvVarGetter {
values = zero_values;
}
- virtual bool GetEnv(const char* variable_name, std::string* result) {
+ // Begin base::Environment implementation.
+ virtual bool GetVar(const char* variable_name, std::string* result) {
const char* env_value = table.Get(variable_name);
if (env_value) {
// Note that the variable may be defined but empty.
@@ -114,11 +116,17 @@ class MockEnvVarGetter : public base::EnvVarGetter {
return false;
}
- virtual bool SetEnv(const char* variable_name, const std::string& new_value) {
- NOTIMPLEMENTED();
+ virtual bool SetVar(const char* variable_name, const std::string& new_value) {
+ ADD_FAILURE();
return false;
}
+ virtual bool UnSetVar(const char* variable_name) {
+ ADD_FAILURE();
+ return false;
+ }
+ // End base::Environment implementation.
+
// Intentionally public, for convenience when setting up a test.
EnvVarValues values;
@@ -239,7 +247,7 @@ class MockGConfSettingGetter
} // namespace
} // namespace net
-// This helper class runs ProxyConfigServiceLinux::GetProxyConfig() on
+// This helper class runs ProxyConfigServiceLinux::GetLatestProxyConfig() on
// the IO thread and synchronously waits for the result.
// Some code duplicated from proxy_script_fetcher_unittest.cc.
class SynchConfigGetter {
@@ -282,12 +290,12 @@ class SynchConfigGetter {
static_cast<MessageLoopForIO*>(file_loop));
}
// Synchronously gets the proxy config.
- int SyncGetProxyConfig(net::ProxyConfig* config) {
+ bool SyncGetLatestProxyConfig(net::ProxyConfig* config) {
io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SynchConfigGetter::GetConfigOnIOThread));
+ this, &SynchConfigGetter::GetLatestConfigOnIOThread));
Wait();
*config = proxy_config_;
- return get_config_result_;
+ return get_latest_config_result_;
}
private:
@@ -296,10 +304,11 @@ class SynchConfigGetter {
event_.Signal();
}
- // Calls GetProxyConfig, running on |io_thread_|] Signals |event_|
+ // Calls GetLatestProxyConfig, running on |io_thread_| Signals |event_|
// on completion.
- void GetConfigOnIOThread() {
- get_config_result_ = config_service_->GetProxyConfig(&proxy_config_);
+ void GetLatestConfigOnIOThread() {
+ get_latest_config_result_ =
+ config_service_->GetLatestProxyConfig(&proxy_config_);
event_.Signal();
}
@@ -322,7 +331,7 @@ class SynchConfigGetter {
// The config obtained by |io_thread_| and read back by the main
// thread.
net::ProxyConfig proxy_config_;
- int get_config_result_; // Return value from GetProxyConfig().
+ bool get_latest_config_result_; // Return value from GetLatestProxyConfig().
};
DISABLE_RUNNABLE_METHOD_REFCOUNT(SynchConfigGetter);
@@ -368,7 +377,7 @@ class ProxyConfigServiceLinuxTest : public PlatformTest {
};
// Builds an identifier for each test in an array.
-#define TEST_DESC(desc) StringPrintf("at line %d <%s>", __LINE__, desc)
+#define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) {
std::vector<std::string> empty_ignores;
@@ -573,7 +582,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) {
false, // auto_detect
GURL(), // pac_url
ProxyRulesExpectation::Single(
- "socks4://socks.com:99", // single proxy
+ "socks5://socks.com:99", // single proxy
"") // bypass rules
},
@@ -597,16 +606,16 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
- tests[i].description.c_str()));
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
+ tests[i].description.c_str()));
+ MockEnvironment* env = new MockEnvironment;
MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter;
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter, gconf_getter));
+ new ProxyConfigServiceLinux(env, gconf_getter));
ProxyConfig config;
gconf_getter->values = tests[i].values;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
EXPECT_EQ(tests[i].pac_url, config.pac_url());
@@ -816,12 +825,12 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
false, // auto_detect
GURL(), // pac_url
ProxyRulesExpectation::Single(
- "socks4://socks.com:888", // single proxy
+ "socks5://socks.com:888", // single proxy
""), // bypass rules
},
{
- TEST_DESC("socks5"),
+ TEST_DESC("socks4"),
{ // Input.
NULL, // DESKTOP_SESSION
NULL, // HOME
@@ -830,7 +839,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
NULL, // auto_proxy
"", // all_proxy
NULL, NULL, NULL, // per-proto proxies
- "socks.com:888", "5", // SOCKS
+ "socks.com:888", "4", // SOCKS
NULL, // no_proxy
},
@@ -838,7 +847,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
false, // auto_detect
GURL(), // pac_url
ProxyRulesExpectation::Single(
- "socks5://socks.com:888", // single proxy
+ "socks4://socks.com:888", // single proxy
""), // bypass rules
},
@@ -860,7 +869,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
false, // auto_detect
GURL(), // pac_url
ProxyRulesExpectation::Single(
- "socks4://socks.com:1080", // single proxy
+ "socks5://socks.com:1080", // single proxy
""), // bypass rules
},
@@ -887,16 +896,16 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
- tests[i].description.c_str()));
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
+ tests[i].description.c_str()));
+ MockEnvironment* env = new MockEnvironment;
MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter;
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter, gconf_getter));
+ new ProxyConfigServiceLinux(env, gconf_getter));
ProxyConfig config;
- env_getter->values = tests[i].values;
+ env->values = tests[i].values;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
EXPECT_EQ(tests[i].pac_url, config.pac_url());
@@ -905,24 +914,24 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) {
}
TEST_F(ProxyConfigServiceLinuxTest, GconfNotification) {
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
+ MockEnvironment* env = new MockEnvironment;
MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter;
ProxyConfigServiceLinux* service =
- new ProxyConfigServiceLinux(env_getter, gconf_getter);
+ new ProxyConfigServiceLinux(env, gconf_getter);
SynchConfigGetter sync_config_getter(service);
ProxyConfig config;
// Start with no proxy.
gconf_getter->values.mode = "none";
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_FALSE(config.auto_detect());
// Now set to auto-detect.
gconf_getter->values.mode = "auto";
// Simulate gconf notification callback.
service->OnCheckProxyConfigSettings();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
}
@@ -1284,21 +1293,21 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
- tests[i].description.c_str()));
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
- env_getter->values = tests[i].env_values;
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
+ tests[i].description.c_str()));
+ MockEnvironment* env = new MockEnvironment;
+ env->values = tests[i].env_values;
// Force the KDE getter to be used and tell it where the test is.
- env_getter->values.DESKTOP_SESSION = "kde4";
- env_getter->values.KDEHOME = kde_home_.value().c_str();
+ env->values.DESKTOP_SESSION = "kde4";
+ env->values.KDEHOME = kde_home_.value().c_str();
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter));
+ new ProxyConfigServiceLinux(env));
ProxyConfig config;
// Overwrite the kioslaverc file.
file_util::WriteFile(kioslaverc_, tests[i].kioslaverc.c_str(),
tests[i].kioslaverc.length());
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
EXPECT_EQ(tests[i].pac_url, config.pac_url());
@@ -1322,14 +1331,14 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
CHECK(!file_util::DirectoryExists(kde4_home_));
{ SCOPED_TRACE("KDE4, no .kde4 directory, verify fallback");
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
- env_getter->values.DESKTOP_SESSION = "kde4";
- env_getter->values.HOME = user_home_.value().c_str();
+ MockEnvironment* env = new MockEnvironment;
+ env->values.DESKTOP_SESSION = "kde4";
+ env->values.HOME = user_home_.value().c_str();
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter));
+ new ProxyConfigServiceLinux(env));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
@@ -1341,41 +1350,41 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
CHECK(file_util::PathExists(kioslaverc4_));
{ SCOPED_TRACE("KDE4, .kde4 directory present, use it");
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
- env_getter->values.DESKTOP_SESSION = "kde4";
- env_getter->values.HOME = user_home_.value().c_str();
+ MockEnvironment* env = new MockEnvironment;
+ env->values.DESKTOP_SESSION = "kde4";
+ env->values.HOME = user_home_.value().c_str();
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter));
+ new ProxyConfigServiceLinux(env));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_FALSE(config.auto_detect());
EXPECT_EQ(slaverc4_pac_url, config.pac_url());
}
{ SCOPED_TRACE("KDE3, .kde4 directory present, ignore it");
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
- env_getter->values.DESKTOP_SESSION = "kde";
- env_getter->values.HOME = user_home_.value().c_str();
+ MockEnvironment* env = new MockEnvironment;
+ env->values.DESKTOP_SESSION = "kde";
+ env->values.HOME = user_home_.value().c_str();
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter));
+ new ProxyConfigServiceLinux(env));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
{ SCOPED_TRACE("KDE4, .kde4 directory present, KDEHOME set to .kde");
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
- env_getter->values.DESKTOP_SESSION = "kde4";
- env_getter->values.HOME = user_home_.value().c_str();
- env_getter->values.KDEHOME = kde_home_.value().c_str();
+ MockEnvironment* env = new MockEnvironment;
+ env->values.DESKTOP_SESSION = "kde4";
+ env->values.HOME = user_home_.value().c_str();
+ env->values.KDEHOME = kde_home_.value().c_str();
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter));
+ new ProxyConfigServiceLinux(env));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
@@ -1385,14 +1394,14 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEHomePicker) {
file_util::SetLastModifiedTime(kde4_config_, base::Time());
{ SCOPED_TRACE("KDE4, very old .kde4 directory present, use .kde");
- MockEnvVarGetter* env_getter = new MockEnvVarGetter;
- env_getter->values.DESKTOP_SESSION = "kde4";
- env_getter->values.HOME = user_home_.value().c_str();
+ MockEnvironment* env = new MockEnvironment;
+ env->values.DESKTOP_SESSION = "kde4";
+ env->values.HOME = user_home_.value().c_str();
SynchConfigGetter sync_config_getter(
- new ProxyConfigServiceLinux(env_getter));
+ new ProxyConfigServiceLinux(env));
ProxyConfig config;
sync_config_getter.SetupAndInitialFetch();
- sync_config_getter.SyncGetProxyConfig(&config);
+ sync_config_getter.SyncGetLatestProxyConfig(&config);
EXPECT_TRUE(config.auto_detect());
EXPECT_EQ(GURL(), config.pac_url());
}
diff --git a/net/proxy/proxy_config_service_mac.cc b/net/proxy/proxy_config_service_mac.cc
index 1e04ff0..a197313 100644
--- a/net/proxy/proxy_config_service_mac.cc
+++ b/net/proxy/proxy_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.
@@ -16,8 +16,12 @@
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_server.h"
+namespace net {
+
namespace {
+const int kPollIntervalSec = 5;
+
// Utility function to pull out a boolean value from a dictionary and return it,
// returning a default value if the key is not present.
bool GetBoolFromDictionary(CFDictionaryRef dict,
@@ -35,11 +39,7 @@ bool GetBoolFromDictionary(CFDictionaryRef dict,
return default_value;
}
-} // namespace
-
-namespace net {
-
-int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
+void GetCurrentProxyConfig(ProxyConfig* config) {
scoped_cftyperef<CFDictionaryRef> config_dict(
SCDynamicStoreCopyProxies(NULL));
DCHECK(config_dict);
@@ -122,7 +122,7 @@ int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
if (proxy_server.is_valid()) {
config->proxy_rules().type =
ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
- config->proxy_rules().socks_proxy = proxy_server;
+ config->proxy_rules().fallback_proxy = proxy_server;
}
}
@@ -157,8 +157,112 @@ int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
false)) {
config->proxy_rules().bypass_rules.AddRuleToBypassLocal();
}
+}
+
+} // namespace
+
+// Reference-counted helper for posting a task to
+// ProxyConfigServiceMac::OnProxyConfigChanged between the notifier and IO
+// thread. This helper object may outlive the ProxyConfigServiceMac.
+class ProxyConfigServiceMac::Helper
+ : public base::RefCountedThreadSafe<ProxyConfigServiceMac::Helper> {
+ public:
+ explicit Helper(ProxyConfigServiceMac* parent) : parent_(parent) {
+ DCHECK(parent);
+ }
+
+ // Called when the parent is destroyed.
+ void Orphan() {
+ parent_ = NULL;
+ }
+
+ void OnProxyConfigChanged(const ProxyConfig& new_config) {
+ if (parent_)
+ parent_->OnProxyConfigChanged(new_config);
+ }
+
+ private:
+ ProxyConfigServiceMac* parent_;
+};
+
+ProxyConfigServiceMac::ProxyConfigServiceMac(MessageLoop* io_loop)
+ : forwarder_(this),
+ config_watcher_(&forwarder_),
+ has_fetched_config_(false),
+ helper_(new Helper(this)),
+ io_loop_(io_loop) {
+ DCHECK(io_loop);
+}
+
+ProxyConfigServiceMac::~ProxyConfigServiceMac() {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+ helper_->Orphan();
+ io_loop_ = NULL;
+}
+
+void ProxyConfigServiceMac::AddObserver(Observer* observer) {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+ observers_.AddObserver(observer);
+}
+
+void ProxyConfigServiceMac::RemoveObserver(Observer* observer) {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+ observers_.RemoveObserver(observer);
+}
+
+bool ProxyConfigServiceMac::GetLatestProxyConfig(ProxyConfig* config) {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+
+ // Lazy-initialize by fetching the proxy setting from this thread.
+ if (!has_fetched_config_) {
+ GetCurrentProxyConfig(&last_config_fetched_);
+ has_fetched_config_ = true;
+ }
+
+ *config = last_config_fetched_;
+ return has_fetched_config_;
+}
+
+void ProxyConfigServiceMac::SetDynamicStoreNotificationKeys(
+ SCDynamicStoreRef store) {
+ // Called on notifier thread.
+
+ CFStringRef proxies_key = SCDynamicStoreKeyCreateProxies(NULL);
+ CFArrayRef key_array = CFArrayCreate(
+ NULL, (const void **)(&proxies_key), 1, &kCFTypeArrayCallBacks);
+
+ bool ret = SCDynamicStoreSetNotificationKeys(store, key_array, NULL);
+ // TODO(willchan): Figure out a proper way to handle this rather than crash.
+ CHECK(ret);
+
+ CFRelease(key_array);
+ CFRelease(proxies_key);
+}
+
+void ProxyConfigServiceMac::OnNetworkConfigChange(CFArrayRef changed_keys) {
+ // Called on notifier thread.
+
+ // Fetch the new system proxy configuration.
+ ProxyConfig new_config;
+ GetCurrentProxyConfig(&new_config);
+
+ // Call OnProxyConfigChanged() on the IO thread to notify our observers.
+ io_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ helper_.get(), &Helper::OnProxyConfigChanged, new_config));
+}
+
+void ProxyConfigServiceMac::OnProxyConfigChanged(
+ const ProxyConfig& new_config) {
+ DCHECK_EQ(io_loop_, MessageLoop::current());
+
+ // Keep track of the last value we have seen.
+ has_fetched_config_ = true;
+ last_config_fetched_ = new_config;
- return OK;
+ // Notify all the observers.
+ FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(new_config));
}
} // namespace net
diff --git a/net/proxy/proxy_config_service_mac.h b/net/proxy/proxy_config_service_mac.h
index 6a93228..68a7d22 100644
--- a/net/proxy/proxy_config_service_mac.h
+++ b/net/proxy/proxy_config_service_mac.h
@@ -4,15 +4,76 @@
#ifndef NET_PROXY_PROXY_CONFIG_SERVICE_MAC_H_
#define NET_PROXY_PROXY_CONFIG_SERVICE_MAC_H_
+#pragma once
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "base/ref_counted.h"
+#include "net/base/network_config_watcher_mac.h"
+#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service.h"
namespace net {
class ProxyConfigServiceMac : public ProxyConfigService {
public:
- // ProxyConfigService methods:
- virtual int GetProxyConfig(ProxyConfig* config);
+ // Constructs a ProxyConfigService that watches the Mac OS system settings.
+ // This instance is expected to be operated and deleted on |io_loop|
+ // (however it may be constructed from a different thread).
+ explicit ProxyConfigServiceMac(MessageLoop* io_loop);
+ virtual ~ProxyConfigServiceMac();
+
+ public:
+ // ProxyConfigService implementation:
+ virtual void AddObserver(Observer* observer);
+ virtual void RemoveObserver(Observer* observer);
+ virtual bool GetLatestProxyConfig(ProxyConfig* config);
+
+ private:
+ class Helper;
+
+ // Forwarder just exists to keep the NetworkConfigWatcherMac API out of
+ // ProxyConfigServiceMac's public API.
+ class Forwarder : public NetworkConfigWatcherMac::Delegate {
+ public:
+ explicit Forwarder(ProxyConfigServiceMac* net_config_watcher)
+ : net_config_watcher_(net_config_watcher) {}
+
+ // NetworkConfigWatcherMac::Delegate implementation:
+ virtual void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store) {
+ net_config_watcher_->SetDynamicStoreNotificationKeys(store);
+ }
+ virtual void OnNetworkConfigChange(CFArrayRef changed_keys) {
+ net_config_watcher_->OnNetworkConfigChange(changed_keys);
+ }
+
+ private:
+ ProxyConfigServiceMac* const net_config_watcher_;
+ DISALLOW_COPY_AND_ASSIGN(Forwarder);
+ };
+
+ // NetworkConfigWatcherMac::Delegate implementation:
+ void SetDynamicStoreNotificationKeys(SCDynamicStoreRef store);
+ void OnNetworkConfigChange(CFArrayRef changed_keys);
+
+ // Called when the proxy configuration has changed, to notify the observers.
+ void OnProxyConfigChanged(const ProxyConfig& new_config);
+
+ Forwarder forwarder_;
+ const NetworkConfigWatcherMac config_watcher_;
+
+ ObserverList<Observer> observers_;
+
+ // Holds the last system proxy settings that we fetched.
+ bool has_fetched_config_;
+ ProxyConfig last_config_fetched_;
+
+ scoped_refptr<Helper> helper_;
+
+ // The thread that we expect to be operated on.
+ MessageLoop* io_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceMac);
};
} // namespace net
diff --git a/net/proxy/proxy_config_service_win.cc b/net/proxy/proxy_config_service_win.cc
index 38819de..1cd8a8c 100644
--- a/net/proxy/proxy_config_service_win.cc
+++ b/net/proxy/proxy_config_service_win.cc
@@ -8,8 +8,11 @@
#include <winhttp.h>
#include "base/logging.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
+#include "base/stl_util-inl.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_config.h"
@@ -17,7 +20,11 @@
namespace net {
-static void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
+namespace {
+
+const int kPollIntervalSec = 10;
+
+void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
if (ie_config->lpszAutoConfigUrl)
GlobalFree(ie_config->lpszAutoConfigUrl);
if (ie_config->lpszProxy)
@@ -26,16 +33,128 @@ static void FreeIEConfig(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_config) {
GlobalFree(ie_config->lpszProxyBypass);
}
-int ProxyConfigServiceWin::GetProxyConfig(ProxyConfig* config) {
+} // namespace
+
+// RegKey and ObjectWatcher pair.
+class ProxyConfigServiceWin::KeyEntry {
+ public:
+ bool StartWatching(base::ObjectWatcher::Delegate* delegate) {
+ // Try to create a watch event for the registry key (which watches the
+ // sibling tree as well).
+ if (!key_.StartWatching())
+ return false;
+
+ // Now setup an ObjectWatcher for this event, so we get OnObjectSignaled()
+ // invoked on this message loop once it is signalled.
+ if (!watcher_.StartWatching(key_.watch_event(), delegate))
+ return false;
+
+ return true;
+ }
+
+ bool CreateRegKey(HKEY rootkey, const wchar_t* subkey) {
+ return key_.Create(rootkey, subkey, KEY_NOTIFY);
+ }
+
+ HANDLE watch_event() const {
+ return key_.watch_event();
+ }
+
+ private:
+ RegKey key_;
+ base::ObjectWatcher watcher_;
+};
+
+ProxyConfigServiceWin::ProxyConfigServiceWin()
+ : PollingProxyConfigService(
+ base::TimeDelta::FromSeconds(kPollIntervalSec),
+ &ProxyConfigServiceWin::GetCurrentProxyConfig) {
+}
+
+ProxyConfigServiceWin::~ProxyConfigServiceWin() {
+ STLDeleteElements(&keys_to_watch_);
+}
+
+void ProxyConfigServiceWin::AddObserver(Observer* observer) {
+ // Lazily-initialize our registry watcher.
+ StartWatchingRegistryForChanges();
+
+ // Let the super-class do its work now.
+ PollingProxyConfigService::AddObserver(observer);
+}
+
+void ProxyConfigServiceWin::StartWatchingRegistryForChanges() {
+ if (!keys_to_watch_.empty())
+ return; // Already initialized.
+
+ // There are a number of different places where proxy settings can live
+ // in the registry. In some cases it appears in a binary value, in other
+ // cases string values. Furthermore winhttp and wininet appear to have
+ // separate stores, and proxy settings can be configured per-machine
+ // or per-user.
+ //
+ // This function is probably not exhaustive in the registry locations it
+ // watches for changes, however it should catch the majority of the
+ // cases. In case we have missed some less common triggers (likely), we
+ // will catch them during the periodic (10 second) polling, so things
+ // will recover.
+
+ AddKeyToWatchList(
+ HKEY_CURRENT_USER,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+
+ AddKeyToWatchList(
+ HKEY_LOCAL_MACHINE,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+
+ AddKeyToWatchList(
+ HKEY_LOCAL_MACHINE,
+ L"SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\"
+ L"Internet Settings");
+}
+
+bool ProxyConfigServiceWin::AddKeyToWatchList(HKEY rootkey,
+ const wchar_t* subkey) {
+ scoped_ptr<KeyEntry> entry(new KeyEntry);
+ if (!entry->CreateRegKey(rootkey, subkey))
+ return false;
+
+ if (!entry->StartWatching(this))
+ return false;
+
+ keys_to_watch_.push_back(entry.release());
+ return true;
+}
+
+void ProxyConfigServiceWin::OnObjectSignaled(HANDLE object) {
+ // Figure out which registry key signalled this change.
+ KeyEntryList::iterator it;
+ for (it = keys_to_watch_.begin(); it != keys_to_watch_.end(); ++it) {
+ if ((*it)->watch_event() == object)
+ break;
+ }
+
+ DCHECK(it != keys_to_watch_.end());
+
+ // Keep watching the registry key.
+ if (!(*it)->StartWatching(this))
+ keys_to_watch_.erase(it);
+
+ // Have the PollingProxyConfigService test for changes.
+ CheckForChangesNow();
+}
+
+// static
+void ProxyConfigServiceWin::GetCurrentProxyConfig(ProxyConfig* config) {
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_config = {0};
if (!WinHttpGetIEProxyConfigForCurrentUser(&ie_config)) {
LOG(ERROR) << "WinHttpGetIEProxyConfigForCurrentUser failed: " <<
GetLastError();
- return ERR_FAILED; // TODO(darin): Bug 1189288: translate error code.
+ *config = ProxyConfig::CreateDirect();
+ return;
}
SetFromIEConfig(config, ie_config);
FreeIEConfig(&ie_config);
- return OK;
}
// static
diff --git a/net/proxy/proxy_config_service_win.h b/net/proxy/proxy_config_service_win.h
index 6217a9e..e10e9a0 100644
--- a/net/proxy/proxy_config_service_win.h
+++ b/net/proxy/proxy_config_service_win.h
@@ -1,32 +1,77 @@
-// 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.
#ifndef NET_PROXY_PROXY_CONFIG_SERVICE_WIN_H_
#define NET_PROXY_PROXY_CONFIG_SERVICE_WIN_H_
+#pragma once
#include <windows.h>
#include <winhttp.h>
-#include "net/proxy/proxy_config_service.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/object_watcher.h"
+#include "net/proxy/polling_proxy_config_service.h"
namespace net {
// Implementation of ProxyConfigService that retrieves the system proxy
// settings.
-class ProxyConfigServiceWin : public ProxyConfigService {
+//
+// It works by calling WinHttpGetIEProxyConfigForCurrentUser() to fetch the
+// Internet Explorer proxy settings.
+//
+// We use two different strategies to notice when the configuration has
+// changed:
+//
+// (1) Watch the internet explorer settings registry keys for changes. When
+// one of the registry keys pertaining to proxy settings has changed, we
+// call WinHttpGetIEProxyConfigForCurrentUser() again to read the
+// configuration's new value.
+//
+// (2) Do regular polling every 10 seconds during network activity to see if
+// WinHttpGetIEProxyConfigForCurrentUser() returns something different.
+//
+// Ideally strategy (1) should be sufficient to pick up all of the changes.
+// However we still do the regular polling as a precaution in case the
+// implementation details of WinHttpGetIEProxyConfigForCurrentUser() ever
+// change, or in case we got it wrong (and are not checking all possible
+// registry dependencies).
+class ProxyConfigServiceWin : public PollingProxyConfigService,
+ public base::ObjectWatcher::Delegate {
public:
- // ProxyConfigService methods:
- virtual int GetProxyConfig(ProxyConfig* config);
+ ProxyConfigServiceWin();
+ virtual ~ProxyConfigServiceWin();
+
+ // Overrides a function from PollingProxyConfigService.
+ virtual void AddObserver(Observer* observer);
private:
- FRIEND_TEST(ProxyConfigServiceWinTest, SetFromIEConfig);
+ FRIEND_TEST_ALL_PREFIXES(ProxyConfigServiceWinTest, SetFromIEConfig);
+ class KeyEntry;
+ typedef std::vector<KeyEntry*> KeyEntryList;
+
+ // Registers change observers on the registry keys relating to proxy settings.
+ void StartWatchingRegistryForChanges();
+
+ // Creates a new KeyEntry and appends it to |keys_to_watch_|. If the key
+ // fails to be created, it is not appended to the list and we return false.
+ bool AddKeyToWatchList(HKEY rootkey, const wchar_t* subkey);
+
+ // ObjectWatcher::Delegate methods:
+ // This is called whenever one of the registry keys we are watching change.
+ virtual void OnObjectSignaled(HANDLE object);
+
+ static void GetCurrentProxyConfig(ProxyConfig* config);
// Set |config| using the proxy configuration values of |ie_config|.
static void SetFromIEConfig(
ProxyConfig* config,
const WINHTTP_CURRENT_USER_IE_PROXY_CONFIG& ie_config);
+
+ KeyEntryList keys_to_watch_;
};
} // namespace net
diff --git a/net/proxy/proxy_config_service_win_unittest.cc b/net/proxy/proxy_config_service_win_unittest.cc
index 1d4f45d..72b49cf 100644
--- a/net/proxy/proxy_config_service_win_unittest.cc
+++ b/net/proxy/proxy_config_service_win_unittest.cc
@@ -103,7 +103,7 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) {
""), // bypass rules
},
- // SOCKS proxy configuration
+ // SOCKS proxy configuration.
{
{ // Input.
FALSE, // fAutoDetect
@@ -114,6 +114,10 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) {
},
// Expected result.
+ // Note that "socks" is interprted as meaning "socks4", since that is how
+ // Internet Explorer applies the settings. For more details on this
+ // policy, see:
+ // http://code.google.com/p/chromium/issues/detail?id=55912#c2
false, // auto_detect
GURL(), // pac_url
ProxyRulesExpectation::PerSchemeWithSocks(
diff --git a/net/proxy/proxy_config_unittest.cc b/net/proxy/proxy_config_unittest.cc
index 5806f30..1947ce4 100644
--- a/net/proxy/proxy_config_unittest.cc
+++ b/net/proxy/proxy_config_unittest.cc
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <ostream>
-
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service_common_unittest.h"
#include "net/proxy/proxy_info.h"
@@ -106,7 +104,7 @@ TEST(ProxyConfigTest, ParseProxyRules) {
const char* proxy_for_http;
const char* proxy_for_https;
const char* proxy_for_ftp;
- const char* socks_proxy;
+ const char* fallback_proxy;
} tests[] = {
// One HTTP proxy for all schemes.
{
@@ -248,188 +246,8 @@ TEST(ProxyConfigTest, ParseProxyRules) {
config.proxy_rules().proxy_for_https);
ExpectProxyServerEquals(tests[i].proxy_for_ftp,
config.proxy_rules().proxy_for_ftp);
- ExpectProxyServerEquals(tests[i].socks_proxy,
- config.proxy_rules().socks_proxy);
- }
-}
-
-std::string ProxyConfigToString(const ProxyConfig& config) {
- std::ostringstream stream;
- stream << config;
- return stream.str();
-}
-
-TEST(ProxyConfigTest, ToString) {
- // Manual proxy.
- {
- ProxyConfig config;
- config.set_auto_detect(false);
- config.proxy_rules().ParseFromString("http://single-proxy:81");
-
- EXPECT_EQ("Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: [None]\n"
- "Manual settings:\n"
- " Proxy server: single-proxy:81\n"
- " Bypass list: [None]",
- ProxyConfigToString(config));
- }
-
- // Autodetect + custom PAC + manual proxy.
- {
- ProxyConfig config;
- config.set_auto_detect(true);
- config.set_pac_url(GURL("http://custom/pac.js"));
- config.proxy_rules().ParseFromString("http://single-proxy:81");
-
- EXPECT_EQ("Automatic settings:\n"
- " Auto-detect: Yes\n"
- " Custom PAC script: http://custom/pac.js\n"
- "Manual settings:\n"
- " Proxy server: single-proxy:81\n"
- " Bypass list: [None]",
- ProxyConfigToString(config));
- }
-
- // Manual proxy with bypass list + bypass local.
- {
- ProxyConfig config;
- config.set_auto_detect(false);
- config.proxy_rules().ParseFromString("http://single-proxy:81");
- config.proxy_rules().bypass_rules.AddRuleFromString("google.com");
- config.proxy_rules().bypass_rules.AddRuleFromString("bypass2.net:1730");
- config.proxy_rules().bypass_rules.AddRuleToBypassLocal();
-
- EXPECT_EQ("Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: [None]\n"
- "Manual settings:\n"
- " Proxy server: single-proxy:81\n"
- " Bypass list: \n"
- " google.com\n"
- " bypass2.net:1730\n"
- " <local>",
- ProxyConfigToString(config));
- }
-
- // Proxy-per scheme (HTTP and HTTPS)
- {
- ProxyConfig config;
- config.set_auto_detect(false);
- config.proxy_rules().ParseFromString(
- "http=proxy-for-http:1801; https=proxy-for-https:1802");
-
- EXPECT_EQ("Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: [None]\n"
- "Manual settings:\n"
- " Proxy server: \n"
- " HTTP: proxy-for-http:1801\n"
- " HTTPS: proxy-for-https:1802\n"
- " Bypass list: [None]",
- ProxyConfigToString(config));
- }
-
- // Proxy-per scheme (HTTP and SOCKS)
- {
- ProxyConfig config;
- config.set_auto_detect(false);
- config.proxy_rules().ParseFromString(
- "http=http://proxy-for-http:1801; socks=socks-server:6083");
-
- EXPECT_EQ("Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: [None]\n"
- "Manual settings:\n"
- " Proxy server: \n"
- " HTTP: proxy-for-http:1801\n"
- " SOCKS: socks4://socks-server:6083\n"
- " Bypass list: [None]",
- ProxyConfigToString(config));
- }
-
- // No proxy.
- {
- ProxyConfig config;
- config.set_auto_detect(false);
-
- EXPECT_EQ("Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: [None]\n"
- "Manual settings:\n"
- " Proxy server: [None]\n"
- " Bypass list: [None]",
- ProxyConfigToString(config));
- }
-
- // Manual proxy with bypass list + bypass local, list reversed.
- {
- ProxyConfig config;
- config.set_auto_detect(false);
- config.proxy_rules().ParseFromString("http://single-proxy:81");
- config.proxy_rules().bypass_rules.AddRuleFromString("google.com");
- config.proxy_rules().bypass_rules.AddRuleFromString("bypass2.net:1730");
- config.proxy_rules().bypass_rules.AddRuleToBypassLocal();
- config.proxy_rules().reverse_bypass = true;
-
- EXPECT_EQ("Automatic settings:\n"
- " Auto-detect: No\n"
- " Custom PAC script: [None]\n"
- "Manual settings:\n"
- " Proxy server: single-proxy:81\n"
- " Only use proxy for: \n"
- " google.com\n"
- " bypass2.net:1730\n"
- " <local>",
- ProxyConfigToString(config));
- }
-}
-
-TEST(ProxyConfigTest, MayRequirePACResolver) {
- {
- ProxyConfig config;
- EXPECT_FALSE(config.MayRequirePACResolver());
- }
- {
- ProxyConfig config;
- config.set_auto_detect(true);
- EXPECT_TRUE(config.MayRequirePACResolver());
- }
- {
- ProxyConfig config;
- config.set_pac_url(GURL("http://custom/pac.js"));
- EXPECT_TRUE(config.MayRequirePACResolver());
- }
- {
- ProxyConfig config;
- config.set_pac_url(GURL("notvalid"));
- EXPECT_FALSE(config.MayRequirePACResolver());
- }
-}
-
-TEST(ProxyConfigTest, ReversedBypassList) {
- {
- ProxyConfig config;
- config.set_auto_detect(false);
- config.proxy_rules().ParseFromString("http://single-proxy:81");
- config.proxy_rules().bypass_rules.AddRuleFromString("google.com");
- config.proxy_rules().bypass_rules.AddRuleFromString("bypass2.net:1730");
- config.proxy_rules().bypass_rules.AddRuleToBypassLocal();
- config.proxy_rules().reverse_bypass = true;
-
- ProxyInfo info[3];
- GURL url0("http://google.com");
- GURL url1("http://www.webkit.com");
- GURL url2("http://bypass2.net:1730");
-
- config.proxy_rules().Apply(url0, &info[0]);
- EXPECT_EQ("single-proxy:81", info[0].proxy_server().ToURI());
-
- config.proxy_rules().Apply(url1, &info[1]);
- EXPECT_TRUE(info[1].is_direct());
-
- config.proxy_rules().Apply(url2, &info[2]);
- EXPECT_EQ("single-proxy:81", info[2].proxy_server().ToURI());
+ ExpectProxyServerEquals(tests[i].fallback_proxy,
+ config.proxy_rules().fallback_proxy);
}
}
diff --git a/net/proxy/proxy_info.cc b/net/proxy/proxy_info.cc
index 796d341..ebefa84 100644
--- a/net/proxy/proxy_info.cc
+++ b/net/proxy/proxy_info.cc
@@ -4,11 +4,16 @@
#include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_retry_info.h"
+
namespace net {
ProxyInfo::ProxyInfo() : config_id_(ProxyConfig::INVALID_ID) {
}
+ProxyInfo::~ProxyInfo() {
+}
+
void ProxyInfo::Use(const ProxyInfo& other) {
proxy_list_ = other.proxy_list_;
}
@@ -29,4 +34,17 @@ std::string ProxyInfo::ToPacString() const {
return proxy_list_.ToPacString();
}
+bool ProxyInfo::Fallback(ProxyRetryInfoMap* proxy_retry_info) {
+ return proxy_list_.Fallback(proxy_retry_info);
+}
+
+void ProxyInfo::DeprioritizeBadProxies(
+ const ProxyRetryInfoMap& proxy_retry_info) {
+ proxy_list_.DeprioritizeBadProxies(proxy_retry_info);
+}
+
+void ProxyInfo::RemoveProxiesWithoutScheme(int scheme_bit_field) {
+ proxy_list_.RemoveProxiesWithoutScheme(scheme_bit_field);
+}
+
} // namespace net
diff --git a/net/proxy/proxy_info.h b/net/proxy/proxy_info.h
index 2531c6d..1194752 100644
--- a/net/proxy/proxy_info.h
+++ b/net/proxy/proxy_info.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_PROXY_PROXY_INFO_H_
#define NET_PROXY_PROXY_INFO_H_
+#pragma once
#include <string>
@@ -12,14 +13,13 @@
#include "net/proxy/proxy_retry_info.h"
#include "net/proxy/proxy_server.h"
-class GURL;
-
namespace net {
// This object holds proxy information returned by ResolveProxy.
class ProxyInfo {
public:
ProxyInfo();
+ ~ProxyInfo();
// Default copy-constructor and assignment operator are OK!
// Uses the same proxy server as the given |proxy_info|.
@@ -78,27 +78,21 @@ class ProxyInfo {
// Returns the first valid proxy server. is_empty() must be false to be able
// to call this function.
- ProxyServer proxy_server() const { return proxy_list_.Get(); }
+ const ProxyServer& proxy_server() const { return proxy_list_.Get(); }
// See description in ProxyList::ToPacString().
std::string ToPacString() const;
// Marks the current proxy as bad. Returns true if there is another proxy
// available to try in proxy list_.
- bool Fallback(ProxyRetryInfoMap* proxy_retry_info) {
- return proxy_list_.Fallback(proxy_retry_info);
- }
+ bool Fallback(ProxyRetryInfoMap* proxy_retry_info);
// De-prioritizes the proxies that we have cached as not working, by moving
// them to the end of the proxy list.
- void DeprioritizeBadProxies(const ProxyRetryInfoMap& proxy_retry_info) {
- proxy_list_.DeprioritizeBadProxies(proxy_retry_info);
- }
+ void DeprioritizeBadProxies(const ProxyRetryInfoMap& proxy_retry_info);
// Deletes any entry which doesn't have one of the specified proxy schemes.
- void RemoveProxiesWithoutScheme(int scheme_bit_field) {
- proxy_list_.RemoveProxiesWithoutScheme(scheme_bit_field);
- }
+ void RemoveProxiesWithoutScheme(int scheme_bit_field);
private:
friend class ProxyService;
diff --git a/net/proxy/proxy_list.h b/net/proxy/proxy_list.h
index 5df1e0a..26265d0 100644
--- a/net/proxy/proxy_list.h
+++ b/net/proxy/proxy_list.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_PROXY_LIST_H_
#define NET_PROXY_PROXY_LIST_H_
+#pragma once
#include <string>
#include <vector>
diff --git a/net/proxy/proxy_resolver.h b/net/proxy/proxy_resolver.h
index 003fa84..9220f5e 100644
--- a/net/proxy/proxy_resolver.h
+++ b/net/proxy/proxy_resolver.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_PROXY_RESOLVER_H_
#define NET_PROXY_PROXY_RESOLVER_H_
+#pragma once
#include "base/logging.h"
#include "base/ref_counted.h"
diff --git a/net/proxy/proxy_resolver_js_bindings.cc b/net/proxy/proxy_resolver_js_bindings.cc
index 56604cd..5f9307e 100644
--- a/net/proxy/proxy_resolver_js_bindings.cc
+++ b/net/proxy/proxy_resolver_js_bindings.cc
@@ -31,8 +31,8 @@ class ErrorNetlogParams : public NetLog::EventParameters {
virtual Value* ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- dict->SetInteger(L"line_number", line_number_);
- dict->SetStringFromUTF16(L"message", message_);
+ dict->SetInteger("line_number", line_number_);
+ dict->SetString("message", message_);
return dict;
}
@@ -51,7 +51,7 @@ class AlertNetlogParams : public NetLog::EventParameters {
virtual Value* ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- dict->SetStringFromUTF16(L"message", message_);
+ dict->SetString("message", message_);
return dict;
}
@@ -173,13 +173,13 @@ class DefaultJSBindings : public ProxyResolverJSBindings {
bool DnsResolveImpl(const std::string& host,
std::string* first_ip_address) {
- // Do a sync resolve of the hostname.
+ // Do a sync resolve of the hostname (port doesn't matter).
// Disable IPv6 results. We do this because the PAC specification isn't
// really IPv6 friendly, and Internet Explorer also restricts to IPv4.
// Consequently a lot of existing PAC scripts assume they will only get
// IPv4 results, and will misbehave if they get an IPv6 result.
// See http://crbug.com/24641 for more details.
- HostResolver::RequestInfo info(host, 80); // Port doesn't matter.
+ HostResolver::RequestInfo info(HostPortPair(host, 80));
info.set_address_family(ADDRESS_FAMILY_IPV4);
AddressList address_list;
@@ -198,8 +198,8 @@ class DefaultJSBindings : public ProxyResolverJSBindings {
bool DnsResolveExImpl(const std::string& host,
std::string* ip_address_list) {
- // Do a sync resolve of the hostname.
- HostResolver::RequestInfo info(host, 80); // Port doesn't matter.
+ // Do a sync resolve of the hostname (port doesn't matter).
+ HostResolver::RequestInfo info(HostPortPair(host, 80));
AddressList address_list;
int result = DnsResolveHelper(info, &address_list);
diff --git a/net/proxy/proxy_resolver_js_bindings.h b/net/proxy/proxy_resolver_js_bindings.h
index ae13584..cbfdb75 100644
--- a/net/proxy/proxy_resolver_js_bindings.h
+++ b/net/proxy/proxy_resolver_js_bindings.h
@@ -4,13 +4,12 @@
#ifndef NET_PROXY_PROXY_RESOLVER_JS_BINDINGS_H_
#define NET_PROXY_PROXY_RESOLVER_JS_BINDINGS_H_
+#pragma once
#include <string>
#include "base/string16.h"
-class MessageLoop;
-
namespace net {
class HostResolver;
@@ -35,7 +34,8 @@ class ProxyResolverJSBindings {
// |*ip_address_list| with the result.
//
// This is a Microsoft extension to PAC for IPv6, see:
- // http://blogs.msdn.com/wndp/articles/IPV6_PAC_Extensions_v0_9.aspx
+ // http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx
+
virtual bool MyIpAddressEx(std::string* ip_address_list) = 0;
// Handler for "dnsResolve(host)". Returns true on success and fills
@@ -47,7 +47,7 @@ class ProxyResolverJSBindings {
// |*ip_address_list| with the result.
//
// This is a Microsoft extension to PAC for IPv6, see:
- // http://blogs.msdn.com/wndp/articles/IPV6_PAC_Extensions_v0_9.aspx
+ // http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx
virtual bool DnsResolveEx(const std::string& host,
std::string* ip_address_list) = 0;
diff --git a/net/proxy/proxy_resolver_js_bindings_unittest.cc b/net/proxy/proxy_resolver_js_bindings_unittest.cc
index 0124469..3b10631 100644
--- a/net/proxy/proxy_resolver_js_bindings_unittest.cc
+++ b/net/proxy/proxy_resolver_js_bindings_unittest.cc
@@ -183,7 +183,7 @@ TEST(ProxyResolverJSBindingsTest, RestrictAddressFamily) {
// Verify that our mock setups works as expected, and we get different results
// depending if the address family was IPV4_ONLY or not.
- HostResolver::RequestInfo info("foo", 80);
+ HostResolver::RequestInfo info(HostPortPair("foo", 80));
AddressList address_list;
EXPECT_EQ(OK, host_resolver->Resolve(info, &address_list, NULL, NULL,
BoundNetLog()));
diff --git a/net/proxy/proxy_resolver_mac.h b/net/proxy/proxy_resolver_mac.h
index cacf6c8..950b11f 100644
--- a/net/proxy/proxy_resolver_mac.h
+++ b/net/proxy/proxy_resolver_mac.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef NET_PROXY_PROXY_RESOLVER_MAC_H_
#define NET_PROXY_PROXY_RESOLVER_MAC_H_
-
-#include <string>
+#pragma once
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
@@ -33,7 +32,7 @@ class ProxyResolverMac : public ProxyResolver {
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* /*callback*/) {
- script_data_ = script_data_;
+ script_data_ = script_data;
return OK;
}
diff --git a/net/proxy/proxy_resolver_perftest.cc b/net/proxy/proxy_resolver_perftest.cc
index 0c57955..dda9587 100644
--- a/net/proxy/proxy_resolver_perftest.cc
+++ b/net/proxy/proxy_resolver_perftest.cc
@@ -2,12 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
#include "base/perftimer.h"
#include "base/string_util.h"
#include "net/base/mock_host_resolver.h"
+#include "net/base/net_errors.h"
+#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver_js_bindings.h"
#include "net/proxy/proxy_resolver_v8.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
@@ -78,10 +83,14 @@ class PacPerfSuiteRunner {
// |resolver_name| is the label used when logging the results.
PacPerfSuiteRunner(net::ProxyResolver* resolver,
const std::string& resolver_name)
- : resolver_(resolver), resolver_name_(resolver_name) {
+ : resolver_(resolver),
+ resolver_name_(resolver_name),
+ test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("net/data/proxy_resolver_perftest"))) {
}
void RunAllTests() {
+ ASSERT_TRUE(test_server_.Start());
for (size_t i = 0; i < arraysize(kPerfTests); ++i) {
const PacPerfTest& test_data = kPerfTests[i];
RunTest(test_data.pac_name,
@@ -95,9 +104,8 @@ class PacPerfSuiteRunner {
const PacQuery* queries,
int queries_len) {
if (!resolver_->expects_pac_bytes()) {
- InitHttpServer();
GURL pac_url =
- server_->TestServerPage(std::string("files/") + script_name);
+ test_server_.GetURL(std::string("files/") + script_name);
int rv = resolver_->SetPacScript(
net::ProxyResolverScriptData::FromURL(pac_url), NULL);
EXPECT_EQ(net::OK, rv);
@@ -140,16 +148,6 @@ class PacPerfSuiteRunner {
timer.Done();
}
- // Lazily startup an HTTP server (to serve the PAC script).
- void InitHttpServer() {
- DCHECK(!resolver_->expects_pac_bytes());
- if (!server_) {
- server_ = HTTPTestServer::CreateServer(
- L"net/data/proxy_resolver_perftest", NULL);
- }
- ASSERT_TRUE(server_.get() != NULL);
- }
-
// Read the PAC script from disk and initialize the proxy resolver with it.
void LoadPacScriptIntoResolver(const std::string& script_name) {
FilePath path;
@@ -175,7 +173,7 @@ class PacPerfSuiteRunner {
net::ProxyResolver* resolver_;
std::string resolver_name_;
- scoped_refptr<HTTPTestServer> server_;
+ net::TestServer test_server_;
};
#if defined(OS_WIN)
diff --git a/net/proxy/proxy_resolver_request_context.h b/net/proxy/proxy_resolver_request_context.h
index fdcced1..4d1b372 100644
--- a/net/proxy/proxy_resolver_request_context.h
+++ b/net/proxy/proxy_resolver_request_context.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_PROXY_RESOLVER_REQUEST_CONTEXT_H_
#define NET_PROXY_PROXY_RESOLVER_REQUEST_CONTEXT_H_
+#pragma once
namespace net {
diff --git a/net/proxy/proxy_resolver_script.h b/net/proxy/proxy_resolver_script.h
index a872cba..fa80798 100644
--- a/net/proxy/proxy_resolver_script.h
+++ b/net/proxy/proxy_resolver_script.h
@@ -39,6 +39,7 @@
#ifndef NET_PROXY_PROXY_RESOLVER_SCRIPT_H_
#define NET_PROXY_PROXY_RESOLVER_SCRIPT_H_
+#pragma once
// The following code was formatted from:
// 'mozilla/netwerk/base/src/nsProxyAutoConfig.js' (1.55)
@@ -266,7 +267,7 @@
"}\n"
// This is a Microsoft extension to PAC for IPv6, see:
-// http://blogs.msdn.com/wndp/articles/IPV6_PAC_Extensions_v0_9.aspx
+// http://blogs.msdn.com/b/wndp/archive/2006/07/13/ipv6-pac-extensions-v0-9.aspx
#define PROXY_RESOLVER_SCRIPT_EX \
"function isResolvableEx(host) {\n" \
" var ipList = dnsResolveEx(host);\n" \
diff --git a/net/proxy/proxy_resolver_script_data.h b/net/proxy/proxy_resolver_script_data.h
index f0bb2ee..72092e1 100644
--- a/net/proxy/proxy_resolver_script_data.h
+++ b/net/proxy/proxy_resolver_script_data.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_PROXY_RESOLVER_SCRIPT_DATA_H_
#define NET_PROXY_PROXY_RESOLVER_SCRIPT_DATA_H_
+#pragma once
#include "base/ref_counted.h"
#include "base/string16.h"
diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc
index 495bbe9..2bf3b6d 100644
--- a/net/proxy/proxy_resolver_v8.cc
+++ b/net/proxy/proxy_resolver_v8.cc
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
+#include <cstdio>
+
#include "net/proxy/proxy_resolver_v8.h"
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
@@ -13,6 +17,7 @@
#include "net/base/host_cache.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
+#include "net/base/net_util.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver_js_bindings.h"
#include "net/proxy/proxy_resolver_request_context.h"
@@ -26,25 +31,27 @@
// pulls in.
//
// In addition, we implement a subset of Microsoft's extensions to PAC.
-// TODO(eroman): Implement the rest.
-//
-// - myIpAddressEx()
-// - dnsResolveEx()
-// - isResolvableEx()
+// - myIpAddressEx()
+// - dnsResolveEx()
+// - isResolvableEx()
+// - isInNetEx()
+// - sortIpAddressList()
//
// It is worth noting that the original PAC specification does not describe
// the return values on failure. Consequently, there are compatibility
// differences between browsers on what to return on failure, which are
// illustrated below:
//
-// ----------------+-------------+-------------------+--------------
-// | Firefox3 | InternetExplorer8 | --> Us <---
-// ----------------+-------------+-------------------+--------------
-// myIpAddress() | "127.0.0.1" | ??? | "127.0.0.1"
-// dnsResolve() | null | false | null
-// myIpAddressEx() | N/A | "" | ""
-// dnsResolveEx() | N/A | "" | ""
-// ----------------+-------------+-------------------+--------------
+// --------------------+-------------+-------------------+--------------
+// | Firefox3 | InternetExplorer8 | --> Us <---
+// --------------------+-------------+-------------------+--------------
+// myIpAddress() | "127.0.0.1" | ??? | "127.0.0.1"
+// dnsResolve() | null | false | null
+// myIpAddressEx() | N/A | "" | ""
+// sortIpAddressList() | N/A | false | false
+// dnsResolveEx() | N/A | "" | ""
+// isInNetEx() | N/A | false | false
+// --------------------+-------------+-------------------+--------------
//
// TODO(eroman): The cell above reading ??? means I didn't test it.
//
@@ -53,15 +60,17 @@
// include both IPv4 and IPv6. The following table illustrates the
// differences:
//
-// -----------------+-------------+-------------------+--------------
-// | Firefox3 | InternetExplorer8 | --> Us <---
-// -----------------+-------------+-------------------+--------------
-// myIpAddress() | IPv4/IPv6 | IPv4 | IPv4
-// dnsResolve() | IPv4/IPv6 | IPv4 | IPv4
-// isResolvable() | IPv4/IPv6 | IPv4 | IPv4
-// myIpAddressEx() | N/A | IPv4/IPv6 | IPv4/IPv6
-// dnsResolveEx() | N/A | IPv4/IPv6 | IPv4/IPv6
-// isResolvableEx() | N/A | IPv4/IPv6 | IPv4/IPv6
+// --------------------+-------------+-------------------+--------------
+// | Firefox3 | InternetExplorer8 | --> Us <---
+// --------------------+-------------+-------------------+--------------
+// myIpAddress() | IPv4/IPv6 | IPv4 | IPv4
+// dnsResolve() | IPv4/IPv6 | IPv4 | IPv4
+// isResolvable() | IPv4/IPv6 | IPv4 | IPv4
+// myIpAddressEx() | N/A | IPv4/IPv6 | IPv4/IPv6
+// dnsResolveEx() | N/A | IPv4/IPv6 | IPv4/IPv6
+// sortIpAddressList() | N/A | IPv4/IPv6 | IPv4/IPv6
+// isResolvableEx() | N/A | IPv4/IPv6 | IPv4/IPv6
+// isInNetEx() | N/A | IPv4/IPv6 | IPv4/IPv6
// -----------------+-------------+-------------------+--------------
namespace net {
@@ -126,6 +135,13 @@ class V8ExternalASCIILiteral : public v8::String::ExternalAsciiStringResource {
// the cutoff length for when to start wrapping rather than creating copies.
const size_t kMaxStringBytesForCopy = 256;
+// Converts a V8 String to a UTF8 std::string.
+std::string V8StringToUTF8(v8::Handle<v8::String> s) {
+ std::string result;
+ s->WriteUtf8(WriteInto(&result, s->Length() + 1));
+ return result;
+}
+
// Converts a V8 String to a UTF16 string16.
string16 V8StringToUTF16(v8::Handle<v8::String> s) {
int len = s->Length();
@@ -213,6 +229,101 @@ bool GetHostnameArgument(const v8::Arguments& args, std::string* hostname) {
return success;
}
+// Wrapper for passing around IP address strings and IPAddressNumber objects.
+struct IPAddress {
+ IPAddress(const std::string& ip_string, const IPAddressNumber& ip_number)
+ : string_value(ip_string),
+ ip_address_number(ip_number) {
+ }
+
+ // Used for sorting IP addresses in ascending order in SortIpAddressList().
+ // IP6 addresses are placed ahead of IPv4 addresses.
+ bool operator<(const IPAddress& rhs) const {
+ const IPAddressNumber& ip1 = this->ip_address_number;
+ const IPAddressNumber& ip2 = rhs.ip_address_number;
+ if (ip1.size() != ip2.size())
+ return ip1.size() > ip2.size(); // IPv6 before IPv4.
+ DCHECK(ip1.size() == ip2.size());
+ return memcmp(&ip1[0], &ip2[0], ip1.size()) < 0; // Ascending order.
+ }
+
+ std::string string_value;
+ IPAddressNumber ip_address_number;
+};
+
+// Handler for "sortIpAddressList(IpAddressList)". |ip_address_list| is a
+// semi-colon delimited string containing IP addresses.
+// |sorted_ip_address_list| is the resulting list of sorted semi-colon delimited
+// IP addresses or an empty string if unable to sort the IP address list.
+// Returns 'true' if the sorting was successful, and 'false' if the input was an
+// empty string, a string of separators (";" in this case), or if any of the IP
+// addresses in the input list failed to parse.
+bool SortIpAddressList(const std::string& ip_address_list,
+ std::string* sorted_ip_address_list) {
+ sorted_ip_address_list->clear();
+
+ // Strip all whitespace (mimics IE behavior).
+ std::string cleaned_ip_address_list;
+ RemoveChars(ip_address_list, " \t", &cleaned_ip_address_list);
+ if (cleaned_ip_address_list.empty())
+ return false;
+
+ // Split-up IP addresses and store them in a vector.
+ std::vector<IPAddress> ip_vector;
+ IPAddressNumber ip_num;
+ StringTokenizer str_tok(cleaned_ip_address_list, ";");
+ while (str_tok.GetNext()) {
+ if (!ParseIPLiteralToNumber(str_tok.token(), &ip_num))
+ return false;
+ ip_vector.push_back(IPAddress(str_tok.token(), ip_num));
+ }
+
+ if (ip_vector.empty()) // Can happen if we have something like
+ return false; // sortIpAddressList(";") or sortIpAddressList("; ;")
+
+ DCHECK(!ip_vector.empty());
+
+ // Sort lists according to ascending numeric value.
+ if (ip_vector.size() > 1)
+ std::stable_sort(ip_vector.begin(), ip_vector.end());
+
+ // Return a semi-colon delimited list of sorted addresses (IPv6 followed by
+ // IPv4).
+ for (size_t i = 0; i < ip_vector.size(); ++i) {
+ if (i > 0)
+ *sorted_ip_address_list += ";";
+ *sorted_ip_address_list += ip_vector[i].string_value;
+ }
+ return true;
+}
+
+// Handler for "isInNetEx(ip_address, ip_prefix)". |ip_address| is a string
+// containing an IPv4/IPv6 address, and |ip_prefix| is a string containg a
+// slash-delimited IP prefix with the top 'n' bits specified in the bit
+// field. This returns 'true' if the address is in the same subnet, and
+// 'false' otherwise. Also returns 'false' if the prefix is in an incorrect
+// format, or if an address and prefix of different types are used (e.g. IPv6
+// address and IPv4 prefix).
+bool IsInNetEx(const std::string& ip_address, const std::string& ip_prefix) {
+ IPAddressNumber address;
+ if (!ParseIPLiteralToNumber(ip_address, &address))
+ return false;
+
+ IPAddressNumber prefix;
+ size_t prefix_length_in_bits;
+ if (!ParseCIDRBlock(ip_prefix, &prefix, &prefix_length_in_bits))
+ return false;
+
+ // Both |address| and |prefix| must be of the same type (IPv4 or IPv6).
+ if (address.size() != prefix.size())
+ return false;
+
+ DCHECK((address.size() == 4 && prefix.size() == 4) ||
+ (address.size() == 16 && prefix.size() == 16));
+
+ return IPNumberMatchesPrefix(address, prefix, prefix_length_in_bits);
+}
+
} // namespace
// ProxyResolverV8::Context ---------------------------------------------------
@@ -310,7 +421,7 @@ class ProxyResolverV8::Context {
global_template->Set(ASCIILiteralToV8String("dnsResolve"),
dns_resolve_template);
- // Microsoft's PAC extensions (incomplete):
+ // Microsoft's PAC extensions:
v8::Local<v8::FunctionTemplate> dns_resolve_ex_template =
v8::FunctionTemplate::New(&DnsResolveExCallback, v8_this_);
@@ -322,6 +433,16 @@ class ProxyResolverV8::Context {
global_template->Set(ASCIILiteralToV8String("myIpAddressEx"),
my_ip_address_ex_template);
+ v8::Local<v8::FunctionTemplate> sort_ip_address_list_template =
+ v8::FunctionTemplate::New(&SortIpAddressListCallback, v8_this_);
+ global_template->Set(ASCIILiteralToV8String("sortIpAddressList"),
+ sort_ip_address_list_template);
+
+ v8::Local<v8::FunctionTemplate> is_in_net_ex_template =
+ v8::FunctionTemplate::New(&IsInNetExCallback, v8_this_);
+ global_template->Set(ASCIILiteralToV8String("isInNetEx"),
+ is_in_net_ex_template);
+
v8_context_ = v8::Context::New(NULL, global_template);
v8::Context::Scope ctx(v8_context_);
@@ -507,8 +628,7 @@ class ProxyResolverV8::Context {
{
v8::Unlocker unlocker;
- success = context->js_bindings_->DnsResolveEx(hostname,
- &ip_address_list);
+ success = context->js_bindings_->DnsResolveEx(hostname, &ip_address_list);
}
if (!success)
@@ -517,6 +637,39 @@ class ProxyResolverV8::Context {
return ASCIIStringToV8String(ip_address_list);
}
+ // V8 callback for when "sortIpAddressList()" is invoked by the PAC script.
+ static v8::Handle<v8::Value> SortIpAddressListCallback(
+ const v8::Arguments& args) {
+ // We need at least one string argument.
+ if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString())
+ return v8::Null();
+
+ std::string ip_address_list = V8StringToUTF8(args[0]->ToString());
+ if (!IsStringASCII(ip_address_list))
+ return v8::Null();
+ std::string sorted_ip_address_list;
+ bool success = SortIpAddressList(ip_address_list, &sorted_ip_address_list);
+ if (!success)
+ return v8::False();
+ return ASCIIStringToV8String(sorted_ip_address_list);
+ }
+
+ // V8 callback for when "isInNetEx()" is invoked by the PAC script.
+ static v8::Handle<v8::Value> IsInNetExCallback(const v8::Arguments& args) {
+ // We need at least 2 string arguments.
+ if (args.Length() < 2 || args[0].IsEmpty() || !args[0]->IsString() ||
+ args[1].IsEmpty() || !args[1]->IsString())
+ return v8::Null();
+
+ std::string ip_address = V8StringToUTF8(args[0]->ToString());
+ if (!IsStringASCII(ip_address))
+ return v8::False();
+ std::string ip_prefix = V8StringToUTF8(args[1]->ToString());
+ if (!IsStringASCII(ip_prefix))
+ return v8::False();
+ return IsInNetEx(ip_address, ip_prefix) ? v8::True() : v8::False();
+ }
+
ProxyResolverJSBindings* js_bindings_;
v8::Persistent<v8::External> v8_this_;
v8::Persistent<v8::Context> v8_context_;
diff --git a/net/proxy/proxy_resolver_v8.h b/net/proxy/proxy_resolver_v8.h
index 8d7a231..7345f45 100644
--- a/net/proxy/proxy_resolver_v8.h
+++ b/net/proxy/proxy_resolver_v8.h
@@ -1,18 +1,16 @@
-// 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.
#ifndef NET_PROXY_PROXY_RESOLVER_V8_H_
#define NET_PROXY_PROXY_RESOLVER_V8_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "net/proxy/proxy_resolver.h"
-class MessageLoop;
-
namespace net {
-class HostResolver;
class ProxyResolverJSBindings;
// Implementation of ProxyResolver that uses V8 to evaluate PAC scripts.
diff --git a/net/proxy/proxy_resolver_v8_unittest.cc b/net/proxy/proxy_resolver_v8_unittest.cc
index f0bfa1d..9e4a5d7 100644
--- a/net/proxy/proxy_resolver_v8_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_unittest.cc
@@ -5,6 +5,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
@@ -276,7 +277,7 @@ TEST(ProxyResolverV8Test, SideEffects) {
result = resolver.GetProxyForURL(kQueryUrl, &proxy_info, NULL, NULL,
BoundNetLog());
EXPECT_EQ(OK, result);
- EXPECT_EQ(StringPrintf("sideffect_%d:80", i),
+ EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i),
proxy_info.proxy_server().ToURI());
}
@@ -290,7 +291,7 @@ TEST(ProxyResolverV8Test, SideEffects) {
result = resolver.GetProxyForURL(kQueryUrl, &proxy_info, NULL, NULL,
BoundNetLog());
EXPECT_EQ(OK, result);
- EXPECT_EQ(StringPrintf("sideffect_%d:80", i),
+ EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i),
proxy_info.proxy_server().ToURI());
}
}
diff --git a/net/proxy/proxy_resolver_winhttp.cc b/net/proxy/proxy_resolver_winhttp.cc
index d7aaae3..4307b5e 100644
--- a/net/proxy/proxy_resolver_winhttp.cc
+++ b/net/proxy/proxy_resolver_winhttp.cc
@@ -9,6 +9,7 @@
#include "base/histogram.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_info.h"
diff --git a/net/proxy/proxy_resolver_winhttp.h b/net/proxy/proxy_resolver_winhttp.h
index 7ad40dc..68d1109 100644
--- a/net/proxy/proxy_resolver_winhttp.h
+++ b/net/proxy/proxy_resolver_winhttp.h
@@ -1,11 +1,10 @@
-// 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.
#ifndef NET_PROXY_PROXY_RESOLVER_WINHTTP_H_
#define NET_PROXY_PROXY_RESOLVER_WINHTTP_H_
-
-#include <string>
+#pragma once
#include "googleurl/src/gurl.h"
#include "net/proxy/proxy_resolver.h"
diff --git a/net/proxy/proxy_retry_info.h b/net/proxy/proxy_retry_info.h
index c5ac782..2206718 100644
--- a/net/proxy/proxy_retry_info.h
+++ b/net/proxy/proxy_retry_info.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_PROXY_RETRY_INFO_H_
#define NET_PROXY_PROXY_RETRY_INFO_H_
+#pragma once
#include <map>
diff --git a/net/proxy/proxy_script_fetcher.h b/net/proxy/proxy_script_fetcher.h
index 8899cbb..f6c1795 100644
--- a/net/proxy/proxy_script_fetcher.h
+++ b/net/proxy/proxy_script_fetcher.h
@@ -8,10 +8,11 @@
#ifndef NET_PROXY_PROXY_SCRIPT_FETCHER_H_
#define NET_PROXY_PROXY_SCRIPT_FETCHER_H_
+#pragma once
+#include "base/gtest_prod_util.h"
#include "base/string16.h"
#include "net/base/completion_callback.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
class GURL;
class URLRequestContext;
@@ -55,8 +56,8 @@ class ProxyScriptFetcher {
// Testing helpers (only available to unit-tests).
// --------------------------------------------------------------------------
private:
- FRIEND_TEST(ProxyScriptFetcherTest, Hang);
- FRIEND_TEST(ProxyScriptFetcherTest, TooLarge);
+ FRIEND_TEST_ALL_PREFIXES(ProxyScriptFetcherTest, Hang);
+ FRIEND_TEST_ALL_PREFIXES(ProxyScriptFetcherTest, TooLarge);
// Sets the maximum duration for a fetch to |timeout_ms|. Returns the previous
// bound.
diff --git a/net/proxy/proxy_script_fetcher_unittest.cc b/net/proxy/proxy_script_fetcher_unittest.cc
index e0e64c9..8980c0e 100644
--- a/net/proxy/proxy_script_fetcher_unittest.cc
+++ b/net/proxy/proxy_script_fetcher_unittest.cc
@@ -7,6 +7,7 @@
#include "base/file_path.h"
#include "base/compiler_specific.h"
#include "base/path_service.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_util.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/base/test_completion_callback.h"
@@ -20,7 +21,8 @@
// - Test canceling an outstanding request.
// - Test deleting ProxyScriptFetcher while a request is in progress.
-const wchar_t kDocRoot[] = L"net/data/proxy_script_fetcher_unittest";
+const FilePath::CharType kDocRoot[] =
+ FILE_PATH_LITERAL("net/data/proxy_script_fetcher_unittest");
struct FetchResult {
int code;
@@ -33,7 +35,8 @@ class RequestContext : public URLRequestContext {
RequestContext() {
net::ProxyConfig no_proxy;
host_resolver_ =
- net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism);
+ net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
+ NULL);
proxy_service_ = net::ProxyService::CreateFixed(no_proxy);
ssl_config_service_ = new net::SSLConfigServiceDefaults;
@@ -63,7 +66,15 @@ GURL GetTestFileUrl(const std::string& relpath) {
return GURL(base_url.spec() + "/" + relpath);
}
-typedef PlatformTest ProxyScriptFetcherTest;
+class ProxyScriptFetcherTest : public PlatformTest {
+ public:
+ ProxyScriptFetcherTest()
+ : test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)) {
+ }
+
+ protected:
+ net::TestServer test_server_;
+};
TEST_F(ProxyScriptFetcherTest, FileUrl) {
scoped_refptr<URLRequestContext> context = new RequestContext;
@@ -93,15 +104,14 @@ TEST_F(ProxyScriptFetcherTest, FileUrl) {
// Note that all mime types are allowed for PAC file, to be consistent
// with other browsers.
TEST_F(ProxyScriptFetcherTest, HttpMimeType) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new RequestContext;
scoped_ptr<ProxyScriptFetcher> pac_fetcher(
ProxyScriptFetcher::Create(context));
{ // Fetch a PAC with mime type "text/plain"
- GURL url = server->TestServerPage("files/pac.txt");
+ GURL url(test_server_.GetURL("files/pac.txt"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -110,7 +120,7 @@ TEST_F(ProxyScriptFetcherTest, HttpMimeType) {
EXPECT_EQ(ASCIIToUTF16("-pac.txt-\n"), text);
}
{ // Fetch a PAC with mime type "text/html"
- GURL url = server->TestServerPage("files/pac.html");
+ GURL url(test_server_.GetURL("files/pac.html"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -119,7 +129,7 @@ TEST_F(ProxyScriptFetcherTest, HttpMimeType) {
EXPECT_EQ(ASCIIToUTF16("-pac.html-\n"), text);
}
{ // Fetch a PAC with mime type "application/x-ns-proxy-autoconfig"
- GURL url = server->TestServerPage("files/pac.nsproxy");
+ GURL url(test_server_.GetURL("files/pac.nsproxy"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -130,15 +140,14 @@ TEST_F(ProxyScriptFetcherTest, HttpMimeType) {
}
TEST_F(ProxyScriptFetcherTest, HttpStatusCode) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new RequestContext;
scoped_ptr<ProxyScriptFetcher> pac_fetcher(
ProxyScriptFetcher::Create(context));
{ // Fetch a PAC which gives a 500 -- FAIL
- GURL url = server->TestServerPage("files/500.pac");
+ GURL url(test_server_.GetURL("files/500.pac"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -147,7 +156,7 @@ TEST_F(ProxyScriptFetcherTest, HttpStatusCode) {
EXPECT_TRUE(text.empty());
}
{ // Fetch a PAC which gives a 404 -- FAIL
- GURL url = server->TestServerPage("files/404.pac");
+ GURL url(test_server_.GetURL("files/404.pac"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -158,16 +167,15 @@ TEST_F(ProxyScriptFetcherTest, HttpStatusCode) {
}
TEST_F(ProxyScriptFetcherTest, ContentDisposition) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new RequestContext;
scoped_ptr<ProxyScriptFetcher> pac_fetcher(
ProxyScriptFetcher::Create(context));
// Fetch PAC scripts via HTTP with a Content-Disposition header -- should
// have no effect.
- GURL url = server->TestServerPage("files/downloadable.pac");
+ GURL url(test_server_.GetURL("files/downloadable.pac"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -177,15 +185,14 @@ TEST_F(ProxyScriptFetcherTest, ContentDisposition) {
}
TEST_F(ProxyScriptFetcherTest, NoCache) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new RequestContext;
scoped_ptr<ProxyScriptFetcher> pac_fetcher(
ProxyScriptFetcher::Create(context));
// Fetch a PAC script whose HTTP headers make it cacheable for 1 hour.
- GURL url = server->TestServerPage("files/cacheable_1hr.pac");
+ GURL url(test_server_.GetURL("files/cacheable_1hr.pac"));
{
string16 text;
TestCompletionCallback callback;
@@ -196,8 +203,7 @@ TEST_F(ProxyScriptFetcherTest, NoCache) {
}
// Now kill the HTTP server.
- EXPECT_TRUE(server->Stop()); // Verify it shutdown synchronously.
- server = NULL;
+ ASSERT_TRUE(test_server_.Stop());
// Try to fetch the file again -- if should fail, since the server is not
// running anymore. (If it were instead being loaded from cache, we would
@@ -212,9 +218,8 @@ TEST_F(ProxyScriptFetcherTest, NoCache) {
}
TEST_F(ProxyScriptFetcherTest, TooLarge) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new RequestContext;
scoped_ptr<ProxyScriptFetcher> pac_fetcher(
ProxyScriptFetcher::Create(context));
@@ -224,7 +229,7 @@ TEST_F(ProxyScriptFetcherTest, TooLarge) {
// These two URLs are the same file, but are http:// vs file://
GURL urls[] = {
- server->TestServerPage("files/large-pac.nsproxy"),
+ test_server_.GetURL("files/large-pac.nsproxy"),
GetTestFileUrl("large-pac.nsproxy")
};
@@ -244,7 +249,7 @@ TEST_F(ProxyScriptFetcherTest, TooLarge) {
ProxyScriptFetcher::SetSizeConstraintForUnittest(prev_size);
{ // Make sure we can still fetch regular URLs.
- GURL url = server->TestServerPage("files/pac.nsproxy");
+ GURL url(test_server_.GetURL("files/pac.nsproxy"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -255,9 +260,8 @@ TEST_F(ProxyScriptFetcherTest, TooLarge) {
}
TEST_F(ProxyScriptFetcherTest, Hang) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new RequestContext;
scoped_ptr<ProxyScriptFetcher> pac_fetcher(
ProxyScriptFetcher::Create(context));
@@ -268,7 +272,7 @@ TEST_F(ProxyScriptFetcherTest, Hang) {
// Try fetching a URL which takes 1.2 seconds. We should abort the request
// after 500 ms, and fail with a timeout error.
- { GURL url = server->TestServerPage("slow/proxy.pac?1.2");
+ { GURL url(test_server_.GetURL("slow/proxy.pac?1.2"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -281,7 +285,7 @@ TEST_F(ProxyScriptFetcherTest, Hang) {
ProxyScriptFetcher::SetTimeoutConstraintForUnittest(prev_timeout);
{ // Make sure we can still fetch regular URLs.
- GURL url = server->TestServerPage("files/pac.nsproxy");
+ GURL url(test_server_.GetURL("files/pac.nsproxy"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -295,16 +299,15 @@ TEST_F(ProxyScriptFetcherTest, Hang) {
// (like gzip, bzip, etc.), and apply any charset conversions to yield
// UTF8.
TEST_F(ProxyScriptFetcherTest, Encodings) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(kDocRoot, NULL);
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new RequestContext;
scoped_ptr<ProxyScriptFetcher> pac_fetcher(
ProxyScriptFetcher::Create(context));
// Test a response that is gzip-encoded -- should get inflated.
{
- GURL url = server->TestServerPage("files/gzipped_pac");
+ GURL url(test_server_.GetURL("files/gzipped_pac"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
@@ -316,7 +319,7 @@ TEST_F(ProxyScriptFetcherTest, Encodings) {
// Test a response that was served as UTF-16 (BE). It should
// be converted to UTF8.
{
- GURL url = server->TestServerPage("files/utf16be_pac");
+ GURL url(test_server_.GetURL("files/utf16be_pac"));
string16 text;
TestCompletionCallback callback;
int result = pac_fetcher->Fetch(url, &text, &callback);
diff --git a/net/proxy/proxy_server.cc b/net/proxy/proxy_server.cc
index b78c347..0bcf89c 100644
--- a/net/proxy/proxy_server.cc
+++ b/net/proxy/proxy_server.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.
@@ -50,7 +50,7 @@ ProxyServer::Scheme GetSchemeFromURI(std::string::const_iterator begin,
if (LowerCaseEqualsASCII(begin, end, "socks4"))
return ProxyServer::SCHEME_SOCKS4;
if (LowerCaseEqualsASCII(begin, end, "socks"))
- return ProxyServer::SCHEME_SOCKS4;
+ return ProxyServer::SCHEME_SOCKS5;
if (LowerCaseEqualsASCII(begin, end, "socks5"))
return ProxyServer::SCHEME_SOCKS5;
if (LowerCaseEqualsASCII(begin, end, "direct"))
@@ -60,39 +60,32 @@ ProxyServer::Scheme GetSchemeFromURI(std::string::const_iterator begin,
return ProxyServer::SCHEME_INVALID;
}
-} // namespace
-
-std::string ProxyServer::HostNoBrackets() const {
- // Doesn't make sense to call this if the URI scheme doesn't
- // have concept of a host.
- DCHECK(is_valid() && !is_direct());
-
+std::string HostNoBrackets(const std::string& host) {
// Remove brackets from an RFC 2732-style IPv6 literal address.
- const std::string::size_type len = host_.size();
- if (len != 0 && host_[0] == '[' && host_[len - 1] == ']')
- return host_.substr(1, len - 2);
- return host_;
+ const std::string::size_type len = host.size();
+ if (len >= 2 && host[0] == '[' && host[len - 1] == ']')
+ return host.substr(1, len - 2);
+ return host;
}
-int ProxyServer::port() const {
- // Doesn't make sense to call this if the URI scheme doesn't
- // have concept of a port.
- DCHECK(is_valid() && !is_direct());
- return port_;
-}
+} // namespace
-std::string ProxyServer::host_and_port() const {
- // Doesn't make sense to call this if the URI scheme doesn't
- // have concept of a host.
- DCHECK(is_valid() && !is_direct());
- return host_ + ":" + IntToString(port_);
+ProxyServer::ProxyServer(Scheme scheme, const HostPortPair& host_port_pair)
+ : scheme_(scheme), host_port_pair_(host_port_pair) {
+ if (scheme_ == SCHEME_DIRECT || scheme_ == SCHEME_INVALID) {
+ // |host_port_pair| isn't relevant for these special schemes, so none should
+ // have been specified. It is important for this to be consistent since we
+ // do raw field comparisons in the equality and comparison functions.
+ DCHECK(host_port_pair.Equals(HostPortPair()));
+ host_port_pair_ = HostPortPair();
+ }
}
-HostPortPair ProxyServer::host_port_pair() const {
+const HostPortPair& ProxyServer::host_port_pair() const {
// Doesn't make sense to call this if the URI scheme doesn't
// have concept of a host.
DCHECK(is_valid() && !is_direct());
- return HostPortPair(host_, port_);
+ return host_port_pair_;
}
// static
@@ -131,13 +124,13 @@ std::string ProxyServer::ToURI() const {
return "direct://";
case SCHEME_HTTP:
// Leave off "http://" since it is our default scheme.
- return host_and_port();
+ return host_port_pair().ToString();
case SCHEME_SOCKS4:
- return std::string("socks4://") + host_and_port();
+ return std::string("socks4://") + host_port_pair().ToString();
case SCHEME_SOCKS5:
- return std::string("socks5://") + host_and_port();
+ return std::string("socks5://") + host_port_pair().ToString();
case SCHEME_HTTPS:
- return std::string("https://") + host_and_port();
+ return std::string("https://") + host_port_pair().ToString();
default:
// Got called with an invalid scheme.
NOTREACHED();
@@ -180,14 +173,14 @@ std::string ProxyServer::ToPacString() const {
case SCHEME_DIRECT:
return "DIRECT";
case SCHEME_HTTP:
- return std::string("PROXY ") + host_and_port();
+ return std::string("PROXY ") + host_port_pair().ToString();
case SCHEME_SOCKS4:
// For compatibility send SOCKS instead of SOCKS4.
- return std::string("SOCKS ") + host_and_port();
+ return std::string("SOCKS ") + host_port_pair().ToString();
case SCHEME_SOCKS5:
- return std::string("SOCKS5 ") + host_and_port();
+ return std::string("SOCKS5 ") + host_port_pair().ToString();
case SCHEME_HTTPS:
- return std::string("HTTPS ") + host_and_port();
+ return std::string("HTTPS ") + host_port_pair().ToString();
default:
// Got called with an invalid scheme.
NOTREACHED();
@@ -222,21 +215,24 @@ ProxyServer ProxyServer::FromSchemeHostAndPort(
if (scheme == SCHEME_DIRECT && begin != end)
return ProxyServer(); // Invalid -- DIRECT cannot have a host/port.
- std::string host;
- int port = -1;
+ HostPortPair host_port_pair;
if (scheme != SCHEME_INVALID && scheme != SCHEME_DIRECT) {
+ std::string host;
+ int port = -1;
// If the scheme has a host/port, parse it.
bool ok = net::ParseHostAndPort(begin, end, &host, &port);
if (!ok)
return ProxyServer(); // Invalid -- failed parsing <host>[":"<port>]
- }
- // Choose a default port number if none was given.
- if (port == -1)
- port = GetDefaultPortForScheme(scheme);
+ // Choose a default port number if none was given.
+ if (port == -1)
+ port = GetDefaultPortForScheme(scheme);
+
+ host_port_pair = HostPortPair(HostNoBrackets(host), port);
+ }
- return ProxyServer(scheme, host, port);
+ return ProxyServer(scheme, host_port_pair);
}
} // namespace net
diff --git a/net/proxy/proxy_server.h b/net/proxy/proxy_server.h
index 3d5593c..3786ddb 100644
--- a/net/proxy/proxy_server.h
+++ b/net/proxy/proxy_server.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_PROXY_PROXY_SERVER_H_
#define NET_PROXY_PROXY_SERVER_H_
+#pragma once
#include "build/build_config.h"
@@ -35,12 +36,9 @@ class ProxyServer {
// Default copy-constructor and assignment operator are OK!
// Constructs an invalid ProxyServer.
- ProxyServer() : scheme_(SCHEME_INVALID), port_(-1) {}
+ ProxyServer() : scheme_(SCHEME_INVALID) {}
- // If |host| is an IPv6 literal address, it must include the square
- // brackets.
- ProxyServer(Scheme scheme, const std::string& host, int port)
- : scheme_(scheme), host_(host), port_(port) {}
+ ProxyServer(Scheme scheme, const HostPortPair& host_port_pair);
bool is_valid() const { return scheme_ != SCHEME_INVALID; }
@@ -61,21 +59,7 @@ class ProxyServer {
return scheme_ == SCHEME_SOCKS4 || scheme_ == SCHEME_SOCKS5;
}
- // Gets the host portion of the proxy server. If the host portion is an
- // IPv6 literal address, the return value does not include the square
- // brackets ([]) used to separate it from the port portion.
- std::string HostNoBrackets() const;
-
- // Gets the port portion of the proxy server.
- int port() const;
-
- // Returns the <host>":"<port> string for the proxy server.
- // TODO(willchan): Remove in favor of host_port_pair().
- std::string host_and_port() const;
-
- // TODO(willchan): Change to const HostPortPair& after refactoring |host_| and
- // |port_| here.
- HostPortPair host_port_pair() const;
+ const HostPortPair& host_port_pair() const;
// Parses from an input with format:
// [<scheme>"://"]<server>[":"<port>]
@@ -88,6 +72,7 @@ class ProxyServer {
//
// Examples (for |default_scheme| = SCHEME_HTTP ):
// "foopy" {scheme=HTTP, host="foopy", port=80}
+ // "socks://foopy" {scheme=SOCKS5, host="foopy", port=1080}
// "socks4://foopy" {scheme=SOCKS4, host="foopy", port=1080}
// "socks5://foopy" {scheme=SOCKS5, host="foopy", port=1080}
// "http://foopy:17" {scheme=HTTP, host="foopy", port=17}
@@ -121,7 +106,7 @@ class ProxyServer {
// Returns a ProxyServer representing DIRECT connections.
static ProxyServer Direct() {
- return ProxyServer(SCHEME_DIRECT, std::string(), -1);
+ return ProxyServer(SCHEME_DIRECT, HostPortPair());
}
#if defined(OS_MACOSX)
@@ -145,8 +130,14 @@ class ProxyServer {
bool operator==(const ProxyServer& other) const {
return scheme_ == other.scheme_ &&
- host_ == other.host_ &&
- port_ == other.port_;
+ host_port_pair_.Equals(other.host_port_pair_);
+ }
+
+ // Comparator function so this can be placed in a std::map.
+ bool operator<(const ProxyServer& other) const {
+ if (scheme_ != other.scheme_)
+ return scheme_ < other.scheme_;
+ return host_port_pair_ < other.host_port_pair_;
}
private:
@@ -158,8 +149,7 @@ class ProxyServer {
std::string::const_iterator host_and_port_end);
Scheme scheme_;
- std::string host_;
- int port_;
+ HostPortPair host_port_pair_;
};
} // namespace net
diff --git a/net/proxy/proxy_server_mac.cc b/net/proxy/proxy_server_mac.cc
index 44c21cd..61e320f 100644
--- a/net/proxy/proxy_server_mac.cc
+++ b/net/proxy/proxy_server_mac.cc
@@ -21,7 +21,7 @@ ProxyServer ProxyServer::FromDictionary(Scheme scheme,
CFStringRef port_key) {
if (scheme == SCHEME_INVALID || scheme == SCHEME_DIRECT) {
// No hostname port to extract; we are done.
- return ProxyServer(scheme, std::string(), -1);
+ return ProxyServer(scheme, HostPortPair());
}
CFStringRef host_ref =
@@ -45,7 +45,7 @@ ProxyServer ProxyServer::FromDictionary(Scheme scheme,
port = GetDefaultPortForScheme(scheme);
}
- return ProxyServer(scheme, host, port);
+ return ProxyServer(scheme, HostPortPair(host, port));
}
} // namespace net
diff --git a/net/proxy/proxy_server_unittest.cc b/net/proxy/proxy_server_unittest.cc
index f91ad66..7646467 100644
--- a/net/proxy/proxy_server_unittest.cc
+++ b/net/proxy/proxy_server_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.
@@ -16,7 +16,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::Scheme expected_scheme;
const char* expected_host;
int expected_port;
- const char* expected_host_and_port;
const char* expected_pac_string;
} tests[] = {
// HTTP proxy URIs:
@@ -26,7 +25,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTP,
"foopy",
10,
- "foopy:10",
"PROXY foopy:10"
},
{
@@ -35,7 +33,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTP,
"foopy",
80,
- "foopy:80",
"PROXY foopy:80"
},
{
@@ -44,7 +41,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTP,
"foopy",
10,
- "foopy:10",
"PROXY foopy:10"
},
@@ -55,7 +51,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTP,
"FEDC:BA98:7654:3210:FEDC:BA98:7654:3210",
10,
- "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:10",
"PROXY [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:10"
},
{
@@ -64,7 +59,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTP,
"3ffe:2a00:100:7031::1",
80,
- "[3ffe:2a00:100:7031::1]:80",
"PROXY [3ffe:2a00:100:7031::1]:80"
},
{
@@ -73,7 +67,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTP,
"::192.9.5.5",
80,
- "[::192.9.5.5]:80",
"PROXY [::192.9.5.5]:80"
},
{
@@ -82,7 +75,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTP,
"::FFFF:129.144.52.38",
80,
- "[::FFFF:129.144.52.38]:80",
"PROXY [::FFFF:129.144.52.38]:80"
},
@@ -93,7 +85,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_SOCKS4,
"foopy",
1080,
- "foopy:1080",
"SOCKS foopy:1080"
},
{
@@ -102,7 +93,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_SOCKS4,
"foopy",
10,
- "foopy:10",
"SOCKS foopy:10"
},
@@ -113,7 +103,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_SOCKS5,
"foopy",
1080,
- "foopy:1080",
"SOCKS5 foopy:1080"
},
{
@@ -122,28 +111,25 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_SOCKS5,
"foopy",
10,
- "foopy:10",
"SOCKS5 foopy:10"
},
- // SOCKS proxy URIs (should default to SOCKS4)
+ // SOCKS proxy URIs (should default to SOCKS5)
{
"socks://foopy", // No port.
- "socks4://foopy:1080",
- net::ProxyServer::SCHEME_SOCKS4,
+ "socks5://foopy:1080",
+ net::ProxyServer::SCHEME_SOCKS5,
"foopy",
1080,
- "foopy:1080",
- "SOCKS foopy:1080"
+ "SOCKS5 foopy:1080"
},
{
"socks://foopy:10",
- "socks4://foopy:10",
- net::ProxyServer::SCHEME_SOCKS4,
+ "socks5://foopy:10",
+ net::ProxyServer::SCHEME_SOCKS5,
"foopy",
10,
- "foopy:10",
- "SOCKS foopy:10"
+ "SOCKS5 foopy:10"
},
// HTTPS proxy URIs:
@@ -153,7 +139,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTPS,
"foopy",
443,
- "foopy:443",
"HTTPS foopy:443"
},
{
@@ -162,7 +147,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTPS,
"foopy",
10,
- "foopy:10",
"HTTPS foopy:10"
},
{
@@ -171,7 +155,6 @@ TEST(ProxyServerTest, FromURI) {
net::ProxyServer::SCHEME_HTTPS,
"1.2.3.4",
10,
- "1.2.3.4:10",
"HTTPS 1.2.3.4:10"
},
};
@@ -184,9 +167,8 @@ TEST(ProxyServerTest, FromURI) {
EXPECT_FALSE(uri.is_direct());
EXPECT_EQ(tests[i].expected_uri, uri.ToURI());
EXPECT_EQ(tests[i].expected_scheme, uri.scheme());
- EXPECT_EQ(tests[i].expected_host, uri.HostNoBrackets());
- EXPECT_EQ(tests[i].expected_port, uri.port());
- EXPECT_EQ(tests[i].expected_host_and_port, uri.host_and_port());
+ EXPECT_EQ(tests[i].expected_host, uri.host_port_pair().host());
+ EXPECT_EQ(tests[i].expected_port, uri.host_port_pair().port());
EXPECT_EQ(tests[i].expected_pac_string, uri.ToPacString());
}
}
@@ -318,3 +300,69 @@ TEST(ProxyServerTest, FromPACStringInvalid) {
EXPECT_FALSE(uri.is_valid());
}
}
+
+TEST(ProxyServerTest, ComparatorAndEquality) {
+ struct {
+ // Inputs.
+ const char* server1;
+ const char* server2;
+
+ // Expectation.
+ // -1 means server1 is less than server2
+ // 0 means server1 equals server2
+ // 1 means server1 is greater than server2
+ int expected_comparison;
+ } tests[] = {
+ { // Equal.
+ "foo:11",
+ "http://foo:11",
+ 0
+ },
+ { // Port is different.
+ "foo:333",
+ "foo:444",
+ -1
+ },
+ { // Host is different.
+ "foo:33",
+ "bar:33",
+ 1
+ },
+ { // Scheme is different.
+ "socks4://foo:33",
+ "http://foo:33",
+ 1
+ },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ // Parse the expected inputs to ProxyServer instances.
+ const net::ProxyServer server1 =
+ net::ProxyServer::FromURI(
+ tests[i].server1, net::ProxyServer::SCHEME_HTTP);
+
+ const net::ProxyServer server2 =
+ net::ProxyServer::FromURI(
+ tests[i].server2, net::ProxyServer::SCHEME_HTTP);
+
+ switch (tests[i].expected_comparison) {
+ case -1:
+ EXPECT_TRUE(server1 < server2);
+ EXPECT_FALSE(server2 < server1);
+ EXPECT_FALSE(server2 == server1);
+ break;
+ case 0:
+ EXPECT_FALSE(server1 < server2);
+ EXPECT_FALSE(server2 < server1);
+ EXPECT_TRUE(server2 == server1);
+ break;
+ case 1:
+ EXPECT_FALSE(server1 < server2);
+ EXPECT_TRUE(server2 < server1);
+ EXPECT_FALSE(server2 == server1);
+ break;
+ default:
+ FAIL() << "Invalid expectation. Can be only -1, 0, 1";
+ }
+ }
+}
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index 33af9c6..67c64dd 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/values.h"
#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/string_util.h"
@@ -26,7 +27,7 @@
#elif defined(OS_MACOSX)
#include "net/proxy/proxy_config_service_mac.h"
#include "net/proxy/proxy_resolver_mac.h"
-#elif defined(OS_LINUX)
+#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include "net/proxy/proxy_config_service_linux.h"
#endif
#include "net/proxy/proxy_resolver.h"
@@ -40,15 +41,59 @@ using base::TimeTicks;
namespace net {
-static const size_t kMaxNumNetLogEntries = 100;
-static const size_t kDefaultNumPacThreads = 4;
-
-// Config getter that fails every time.
-class ProxyConfigServiceNull : public ProxyConfigService {
+namespace {
+
+const size_t kMaxNumNetLogEntries = 100;
+const size_t kDefaultNumPacThreads = 4;
+
+// When the IP address changes we don't immediately re-run proxy auto-config.
+// Instead, we wait for |kNumMillisToStallAfterNetworkChanges| before
+// attempting to re-valuate proxy auto-config.
+//
+// During this time window, any resolve requests sent to the ProxyService will
+// be queued. Once we have waited the required amount of them, the proxy
+// auto-config step will be run, and the queued requests resumed.
+//
+// The reason we play this game is that our signal for detecting network
+// changes (NetworkChangeNotifier) may fire *before* the system's networking
+// dependencies are fully configured. This is a problem since it means if
+// we were to run proxy auto-config right away, it could fail due to spurious
+// DNS failures. (see http://crbug.com/50779 for more details.)
+//
+// By adding the wait window, we give things a chance to get properly set up.
+// Now by the time we run the proxy-autoconfig there is a lower chance of
+// getting transient DNS / connect failures.
+//
+// Admitedly this is a hack. Ideally we would have NetworkChangeNotifier
+// deliver a reliable signal indicating that the network has changed AND is
+// ready for action... But until then, we can reduce the likelihood of users
+// getting wedged because of proxy detection failures on network switch.
+//
+// The obvious downside to this strategy is it introduces an additional
+// latency when switching networks. This delay shouldn't be too disruptive
+// assuming network switches are infrequent and user initiated. However if
+// NetworkChangeNotifier delivers network changes more frequently this could
+// cause jankiness. (NetworkChangeNotifier broadcasts a change event when ANY
+// interface goes up/down. So in theory if the non-primary interface were
+// hopping on and off wireless networks our constant delayed reconfiguration
+// could add noticeable jank.)
+//
+// The specific hard-coded wait time below is arbitrary.
+// Basically I ran some experiments switching between wireless networks on
+// a Linux Ubuntu (Lucid) laptop, and experimentally found this timeout fixes
+// things. It is entirely possible that the value is insuficient for other
+// setups.
+const int64 kNumMillisToStallAfterNetworkChanges = 2000;
+
+// Config getter that always returns direct settings.
+class ProxyConfigServiceDirect : public ProxyConfigService {
public:
// ProxyConfigService implementation:
- virtual int GetProxyConfig(ProxyConfig* config) {
- return ERR_NOT_IMPLEMENTED;
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
+ virtual bool GetLatestProxyConfig(ProxyConfig* config) {
+ *config = ProxyConfig::CreateDirect();
+ return true;
}
};
@@ -77,6 +122,37 @@ class ProxyResolverNull : public ProxyResolver {
}
};
+// ProxyResolver that simulates a PAC script which returns
+// |pac_string| for every single URL.
+class ProxyResolverFromPacString : public ProxyResolver {
+ public:
+ ProxyResolverFromPacString(const std::string& pac_string)
+ : ProxyResolver(false /*expects_pac_bytes*/),
+ pac_string_(pac_string) {}
+
+ virtual int GetProxyForURL(const GURL& url,
+ ProxyInfo* results,
+ CompletionCallback* callback,
+ RequestHandle* request,
+ const BoundNetLog& net_log) {
+ results->UsePacString(pac_string_);
+ return OK;
+ }
+
+ virtual void CancelRequest(RequestHandle request) {
+ NOTREACHED();
+ }
+
+ virtual int SetPacScript(
+ const scoped_refptr<ProxyResolverScriptData>& pac_script,
+ CompletionCallback* callback) {
+ return OK;
+ }
+
+ private:
+ const std::string pac_string_;
+};
+
// This factory creates V8ProxyResolvers with appropriate javascript bindings.
class ProxyResolverFactoryForV8 : public ProxyResolverFactory {
public:
@@ -136,6 +212,33 @@ class ProxyResolverFactoryForNonV8 : public ProxyResolverFactory {
}
};
+// NetLog parameter to describe a proxy configuration change.
+class ProxyConfigChangedNetLogParam : public NetLog::EventParameters {
+ public:
+ ProxyConfigChangedNetLogParam(const ProxyConfig& old_config,
+ const ProxyConfig& new_config)
+ : old_config_(old_config),
+ new_config_(new_config) {
+ }
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ // The "old_config" is optional -- the first notification will not have
+ // any "previous" configuration.
+ if (old_config_.is_valid())
+ dict->Set("old_config", old_config_.ToValue());
+ dict->Set("new_config", new_config_.ToValue());
+ return dict;
+ }
+
+ private:
+ const ProxyConfig old_config_;
+ const ProxyConfig new_config_;
+ DISALLOW_COPY_AND_ASSIGN(ProxyConfigChangedNetLogParam);
+};
+
+} // namespace
+
// ProxyService::PacRequest ---------------------------------------------------
class ProxyService::PacRequest
@@ -163,6 +266,8 @@ class ProxyService::PacRequest
DCHECK(!was_cancelled());
DCHECK(!is_started());
+ DCHECK(service_->config_.is_valid());
+
config_id_ = service_->config_.id();
return resolver()->GetProxyForURL(
@@ -262,14 +367,17 @@ class ProxyService::PacRequest
ProxyService::ProxyService(ProxyConfigService* config_service,
ProxyResolver* resolver,
NetLog* net_log)
- : config_service_(config_service),
- resolver_(resolver),
+ : resolver_(resolver),
next_config_id_(1),
- should_use_proxy_resolver_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(init_proxy_resolver_callback_(
this, &ProxyService::OnInitProxyResolverComplete)),
- net_log_(net_log) {
+ current_state_(STATE_NONE) ,
+ net_log_(net_log),
+ stall_proxy_auto_config_delay_(
+ base::TimeDelta::FromMilliseconds(
+ kNumMillisToStallAfterNetworkChanges)) {
NetworkChangeNotifier::AddObserver(this);
+ ResetConfigService(config_service);
}
// static
@@ -318,9 +426,26 @@ ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
}
// static
-ProxyService* ProxyService::CreateNull() {
- // Use a configuration fetcher and proxy resolver which always fail.
- return new ProxyService(new ProxyConfigServiceNull, new ProxyResolverNull,
+ProxyService* ProxyService::CreateDirect() {
+ // Use direct connections.
+ return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
+ NULL);
+}
+
+// static
+ProxyService* ProxyService::CreateFixedFromPacResult(
+ const std::string& pac_string) {
+
+ // We need the settings to contain an "automatic" setting, otherwise the
+ // ProxyResolver dependency we give it will never be used.
+ scoped_ptr<ProxyConfigService> proxy_config_service(
+ new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect()));
+
+ scoped_ptr<ProxyResolver> proxy_resolver(
+ new ProxyResolverFromPacString(pac_string));
+
+ return new ProxyService(proxy_config_service.release(),
+ proxy_resolver.release(),
NULL);
}
@@ -333,13 +458,16 @@ int ProxyService::ResolveProxy(const GURL& raw_url,
net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
+ config_service_->OnLazyPoll();
+ if (current_state_ == STATE_NONE)
+ ApplyProxyConfigIfAvailable();
+
// Strip away any reference fragments and the username/password, as they
// are not relevant to proxy resolution.
GURL url = SimplifyUrlForRequest(raw_url);
- // Check if the request can be completed right away. This is the case when
- // using a direct connection, or when the config is bad.
- UpdateConfigIfOld(net_log);
+ // Check if the request can be completed right away. (This is the case when
+ // using a direct connection for example).
int rv = TryToCompleteSynchronously(url, result);
if (rv != ERR_IO_PENDING)
return DidFinishResolvingProxy(result, rv, net_log);
@@ -347,9 +475,7 @@ int ProxyService::ResolveProxy(const GURL& raw_url,
scoped_refptr<PacRequest> req =
new PacRequest(this, url, result, callback, net_log);
- bool resolver_is_ready = !IsInitializingProxyResolver();
-
- if (resolver_is_ready) {
+ if (current_state_ == STATE_READY) {
// Start the resolve request.
rv = req->Start();
if (rv != ERR_IO_PENDING)
@@ -372,22 +498,25 @@ int ProxyService::ResolveProxy(const GURL& raw_url,
int ProxyService::TryToCompleteSynchronously(const GURL& url,
ProxyInfo* result) {
- result->config_id_ = config_.id();
+ DCHECK_NE(STATE_NONE, current_state_);
- DCHECK(config_.id() != ProxyConfig::INVALID_ID);
+ if (current_state_ != STATE_READY)
+ return ERR_IO_PENDING; // Still initializing.
- if (should_use_proxy_resolver_ || IsInitializingProxyResolver()) {
- // May need to go through ProxyResolver for this.
- return ERR_IO_PENDING;
- }
+ DCHECK_NE(config_.id(), ProxyConfig::INVALID_ID);
+
+ if (config_.HasAutomaticSettings())
+ return ERR_IO_PENDING; // Must submit the request to the proxy resolver.
// Use the manual proxy settings.
config_.proxy_rules().Apply(url, result);
+ result->config_id_ = config_.id();
return OK;
}
ProxyService::~ProxyService() {
NetworkChangeNotifier::RemoveObserver(this);
+ config_service_->RemoveObserver(this);
// Cancel any inprogress requests.
for (PendingRequests::iterator it = pending_requests_.begin();
@@ -395,10 +524,6 @@ ProxyService::~ProxyService() {
++it) {
(*it)->Cancel();
}
-
- // Make sure that InitProxyResolver gets destroyed BEFORE the
- // CapturingNetLog it is using is deleted.
- init_proxy_resolver_.reset();
}
void ProxyService::SuspendAllPendingRequests() {
@@ -415,8 +540,9 @@ void ProxyService::SuspendAllPendingRequests() {
}
}
-void ProxyService::ResumeAllPendingRequests() {
- DCHECK(!IsInitializingProxyResolver());
+void ProxyService::SetReady() {
+ DCHECK(!init_proxy_resolver_.get());
+ current_state_ = STATE_READY;
// Make a copy in case |this| is deleted during the synchronous completion
// of one of the requests. If |this| is deleted then all of the PacRequest
@@ -438,22 +564,47 @@ void ProxyService::ResumeAllPendingRequests() {
}
}
+void ProxyService::ApplyProxyConfigIfAvailable() {
+ DCHECK_EQ(STATE_NONE, current_state_);
+
+ config_service_->OnLazyPoll();
+
+ // If we have already fetched the configuration, start applying it.
+ if (fetched_config_.is_valid()) {
+ InitializeUsingLastFetchedConfig();
+ return;
+ }
+
+ // Otherwise we need to first fetch the configuration.
+ current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
+
+ // Retrieve the current proxy configuration from the ProxyConfigService.
+ // If a configuration is not available yet, we will get called back later
+ // by our ProxyConfigService::Observer once it changes.
+ ProxyConfig config;
+ bool has_config = config_service_->GetLatestProxyConfig(&config);
+ if (has_config)
+ OnProxyConfigChanged(config);
+}
+
void ProxyService::OnInitProxyResolverComplete(int result) {
+ DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
DCHECK(init_proxy_resolver_.get());
- DCHECK(config_.MayRequirePACResolver());
- DCHECK(!should_use_proxy_resolver_);
+ DCHECK(fetched_config_.HasAutomaticSettings());
init_proxy_resolver_.reset();
- should_use_proxy_resolver_ = result == OK;
-
if (result != OK) {
LOG(INFO) << "Failed configuring with PAC script, falling-back to manual "
"proxy servers.";
+ config_ = fetched_config_;
+ config_.ClearAutomaticSettings();
}
+ config_.set_id(fetched_config_.id());
+
// Resume any requests which we had to defer until the PAC script was
// downloaded.
- ResumeAllPendingRequests();
+ SetReady();
}
int ProxyService::ReconsiderProxyAfterError(const GURL& url,
@@ -466,13 +617,7 @@ int ProxyService::ReconsiderProxyAfterError(const GURL& url,
// direct connection failed and we never tried the current config.
bool re_resolve = result->config_id_ != config_.id();
- if (!re_resolve) {
- UpdateConfig(net_log);
- if (result->config_id_ != config_.id()) {
- // A new configuration!
- re_resolve = true;
- }
- }
+
if (re_resolve) {
// If we have a new config or the config was never tried, we delete the
// list of bad proxies and we try again.
@@ -514,7 +659,7 @@ int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
// Log the result of the proxy resolution.
if (result_code == OK) {
// When full logging is enabled, dump the proxy list.
- if (net_log.HasListener()) {
+ if (net_log.IsLoggingAll()) {
net_log.AddEvent(
NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
new NetLogStringParameter("pac_string", result->ToPacString()));
@@ -542,29 +687,44 @@ int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
void ProxyService::SetProxyScriptFetcher(
ProxyScriptFetcher* proxy_script_fetcher) {
- if (init_proxy_resolver_.get()) {
- // We need to be careful to first cancel |init_proxy_resolver_|, since it
- // holds a pointer to the old proxy script fetcher we are about to delete.
-
- DCHECK(IsInitializingProxyResolver());
- init_proxy_resolver_.reset();
- proxy_script_fetcher_.reset(proxy_script_fetcher);
-
- // Restart the initialization, using the new proxy script fetcher.
- StartInitProxyResolver();
- } else {
- proxy_script_fetcher_.reset(proxy_script_fetcher);
- }
+ State previous_state = ResetProxyConfig(false);
+ proxy_script_fetcher_.reset(proxy_script_fetcher);
+ if (previous_state != STATE_NONE)
+ ApplyProxyConfigIfAvailable();
}
ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const {
return proxy_script_fetcher_.get();
}
+ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) {
+ State previous_state = current_state_;
+
+ proxy_retry_info_.clear();
+ init_proxy_resolver_.reset();
+ SuspendAllPendingRequests();
+ config_ = ProxyConfig();
+ if (reset_fetched_config)
+ fetched_config_ = ProxyConfig();
+ current_state_ = STATE_NONE;
+
+ return previous_state;
+}
+
void ProxyService::ResetConfigService(
ProxyConfigService* new_proxy_config_service) {
+ State previous_state = ResetProxyConfig(true);
+
+ // Release the old configuration service.
+ if (config_service_.get())
+ config_service_->RemoveObserver(this);
+
+ // Set the new configuration service.
config_service_.reset(new_proxy_config_service);
- UpdateConfig(BoundNetLog());
+ config_service_->AddObserver(this);
+
+ if (previous_state != STATE_NONE)
+ ApplyProxyConfigIfAvailable();
}
void ProxyService::PurgeMemory() {
@@ -573,11 +733,8 @@ void ProxyService::PurgeMemory() {
}
void ProxyService::ForceReloadProxyConfig() {
- // Mark the current configuration as being un-initialized, then force it to
- // start updating (normally this would happen lazily during the next
- // call to ResolveProxy()).
- config_.set_id(ProxyConfig::INVALID_ID);
- UpdateConfig(BoundNetLog());
+ ResetProxyConfig(false);
+ ApplyProxyConfigIfAvailable();
}
// static
@@ -586,8 +743,17 @@ ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
#if defined(OS_WIN)
return new ProxyConfigServiceWin();
#elif defined(OS_MACOSX)
+<<<<<<< HEAD
return new ProxyConfigServiceMac();
#elif defined(OS_LINUX) && !defined(ANDROID)
+=======
+ return new ProxyConfigServiceMac(io_loop);
+#elif defined(OS_CHROMEOS)
+ NOTREACHED() << "ProxyConfigService for ChromeOS should be created in "
+ << "chrome_url_request_context.cc::CreateProxyConfigService.";
+ return NULL;
+#elif defined(OS_LINUX)
+>>>>>>> Chromium at release 7.0.540.0
ProxyConfigServiceLinux* linux_config_service
= new ProxyConfigServiceLinux();
@@ -614,104 +780,65 @@ ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
#endif
}
-void ProxyService::UpdateConfig(const BoundNetLog& net_log) {
- bool is_first_update = !config_has_been_initialized();
-
- ProxyConfig latest;
-
- // Fetch the proxy settings.
- TimeTicks start_time = TimeTicks::Now();
- net_log.BeginEvent(
- NetLog::TYPE_PROXY_SERVICE_POLL_CONFIG_SERVICE_FOR_CHANGES, NULL);
- int rv = config_service_->GetProxyConfig(&latest);
- net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE_POLL_CONFIG_SERVICE_FOR_CHANGES,
- NULL);
- TimeTicks end_time = TimeTicks::Now();
-
- // Record how long the call to config_service_->GetConfig() above took.
- // On some setups of Windows, we have reports that querying the system
- // proxy settings can take multiple seconds (http://crbug.com/12189).
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.ProxyPollConfigurationTime",
- end_time - start_time,
- TimeDelta::FromMilliseconds(1),
- TimeDelta::FromSeconds(30),
- 50);
-
- if (rv != OK) {
- if (is_first_update) {
- // Default to direct-connection if the first fetch fails.
- LOG(INFO) << "Failed initial proxy configuration fetch.";
- SetConfig(ProxyConfig());
- }
- return;
+void ProxyService::OnProxyConfigChanged(const ProxyConfig& config) {
+ // Emit the proxy settings change to the NetLog stream.
+ if (net_log_) {
+ scoped_refptr<NetLog::EventParameters> params =
+ new ProxyConfigChangedNetLogParam(fetched_config_, config);
+ net_log_->AddEntry(net::NetLog::TYPE_PROXY_CONFIG_CHANGED,
+ base::TimeTicks::Now(),
+ NetLog::Source(),
+ NetLog::PHASE_NONE,
+ params);
}
- config_last_update_time_ = TimeTicks::Now();
- if (!is_first_update && latest.Equals(config_))
- return;
+ // Set the new configuration as the most recently fetched one.
+ fetched_config_ = config;
+ fetched_config_.set_id(1); // Needed for a later DCHECK of is_valid().
- SetConfig(latest);
+ InitializeUsingLastFetchedConfig();
}
-void ProxyService::SetConfig(const ProxyConfig& config) {
- config_ = config;
+void ProxyService::InitializeUsingLastFetchedConfig() {
+ ResetProxyConfig(false);
- // Increment the ID to reflect that the config has changed.
- config_.set_id(next_config_id_++);
-
- // Reset state associated with latest config.
- proxy_retry_info_.clear();
+ DCHECK(fetched_config_.is_valid());
- // Cancel any PAC fetching / ProxyResolver::SetPacScript() which was
- // in progress for the previous configuration.
- init_proxy_resolver_.reset();
- should_use_proxy_resolver_ = false;
-
- // Start downloading + testing the PAC scripts for this new configuration.
- if (config_.MayRequirePACResolver()) {
- // Since InitProxyResolver will be playing around with the proxy resolver
- // as it tests the parsing of various PAC scripts, make sure there is
- // nothing in-flight in |resolver_|. These paused requests are resumed by
- // OnInitProxyResolverComplete().
- SuspendAllPendingRequests();
+ // Increment the ID to reflect that the config has changed.
+ fetched_config_.set_id(next_config_id_++);
- // Calls OnInitProxyResolverComplete() on completion.
- StartInitProxyResolver();
+ if (!fetched_config_.HasAutomaticSettings()) {
+ config_ = fetched_config_;
+ SetReady();
+ return;
}
-}
-void ProxyService::StartInitProxyResolver() {
- DCHECK(!init_proxy_resolver_.get());
+ // Start downloading + testing the PAC scripts for this new configuration.
+ current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
init_proxy_resolver_.reset(
new InitProxyResolver(resolver_.get(), proxy_script_fetcher_.get(),
net_log_));
+ // If we changed networks recently, we should delay running proxy auto-config.
+ base::TimeDelta wait_delay =
+ stall_proxy_autoconfig_until_ - base::TimeTicks::Now();
+
int rv = init_proxy_resolver_->Init(
- config_, &init_proxy_resolver_callback_);
+ fetched_config_, wait_delay, &config_, &init_proxy_resolver_callback_);
if (rv != ERR_IO_PENDING)
OnInitProxyResolverComplete(rv);
}
-void ProxyService::UpdateConfigIfOld(const BoundNetLog& net_log) {
- // The overhead of calling ProxyConfigService::GetProxyConfig is very low.
- const TimeDelta kProxyConfigMaxAge = TimeDelta::FromSeconds(5);
-
- // Periodically check for a new config.
- if (!config_has_been_initialized() ||
- (TimeTicks::Now() - config_last_update_time_) > kProxyConfigMaxAge)
- UpdateConfig(net_log);
-}
-
-
void ProxyService::OnIPAddressChanged() {
- // Mark the current configuration as being un-initialized.
- //
- // This will force us to re-fetch the configuration (and re-run all of
- // the initialization steps) on the next ResolveProxy() request, as part
- // of UpdateConfigIfOld().
- config_.set_id(ProxyConfig::INVALID_ID);
+ // See the comment block by |kNumMillisToStallAfterNetworkChanges| for info.
+ stall_proxy_autoconfig_until_ =
+ base::TimeTicks::Now() + stall_proxy_auto_config_delay_;
+
+ State previous_state = ResetProxyConfig(false);
+ if (previous_state != STATE_NONE)
+ ApplyProxyConfigIfAvailable();
}
SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop,
diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h
index a702b38..d8d2e6c 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -4,19 +4,20 @@
#ifndef NET_PROXY_PROXY_SERVICE_H_
#define NET_PROXY_PROXY_SERVICE_H_
+#pragma once
-#include <string>
#include <vector>
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/waitable_event.h"
#include "net/base/completion_callback.h"
#include "net/base/network_change_notifier.h"
#include "net/base/net_log.h"
+#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_info.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
class GURL;
class MessageLoop;
@@ -25,7 +26,6 @@ class URLRequestContext;
namespace net {
class InitProxyResolver;
-class ProxyConfigService;
class ProxyResolver;
class ProxyScriptFetcher;
@@ -33,7 +33,8 @@ class ProxyScriptFetcher;
// HTTP(S) URL. It uses the given ProxyResolver to handle the actual proxy
// resolution. See ProxyResolverV8 for example.
class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
- public NetworkChangeNotifier::Observer {
+ public NetworkChangeNotifier::Observer,
+ public ProxyConfigService::Observer {
public:
// The instance takes ownership of |config_service| and |resolver|.
// |net_log| is a possibly NULL destination to send log events to. It must
@@ -108,12 +109,13 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// Tells the resolver to purge any memory it does not need.
void PurgeMemory();
- // Returns true if we have called UpdateConfig() at least once.
- bool config_has_been_initialized() const {
- return config_.id() != ProxyConfig::INVALID_ID;
- }
// Returns the last configuration fetched from ProxyConfigService.
+ const ProxyConfig& fetched_config() {
+ return fetched_config_;
+ }
+
+ // Returns the current configuration being used by ProxyConfigService.
const ProxyConfig& config() {
return config_;
}
@@ -175,19 +177,31 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// specified fixed settings. |pc| must not be NULL.
static ProxyService* CreateFixed(const ProxyConfig& pc);
- // Creates a proxy service that always fails to fetch the proxy configuration,
- // so it falls back to direct connect.
- static ProxyService* CreateNull();
+ // Creates a proxy service that uses a DIRECT connection for all requests.
+ static ProxyService* CreateDirect();
+
+ // This method is used by tests to create a ProxyService that returns a
+ // hardcoded proxy fallback list (|pac_string|) for every URL.
+ //
+ // |pac_string| is a list of proxy servers, in the format that a PAC script
+ // would return it. For example, "PROXY foobar:99; SOCKS fml:2; DIRECT"
+ static ProxyService* CreateFixedFromPacResult(const std::string& pac_string);
// Creates a config service appropriate for this platform that fetches the
// system proxy settings.
static ProxyConfigService* CreateSystemProxyConfigService(
MessageLoop* io_loop, MessageLoop* file_loop);
+#if UNIT_TEST
+ void set_stall_proxy_auto_config_delay(base::TimeDelta delay) {
+ stall_proxy_auto_config_delay_ = delay;
+ }
+#endif
+
private:
friend class base::RefCountedThreadSafe<ProxyService>;
- FRIEND_TEST(ProxyServiceTest, UpdateConfigAfterFailedAutodetect);
- FRIEND_TEST(ProxyServiceTest, UpdateConfigFromPACToDirect);
+ FRIEND_TEST_ALL_PREFIXES(ProxyServiceTest, UpdateConfigAfterFailedAutodetect);
+ FRIEND_TEST_ALL_PREFIXES(ProxyServiceTest, UpdateConfigFromPACToDirect);
friend class PacRequest;
// TODO(eroman): change this to a std::set. Note that this requires updating
@@ -196,31 +210,26 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// which expects requests to finish in the order they were added.
typedef std::vector<scoped_refptr<PacRequest> > PendingRequests;
- ~ProxyService();
-
- // Identifies the proxy configuration.
- ProxyConfig::ID config_id() const { return config_.id(); }
-
- // Checks to see if the proxy configuration changed, and then updates config_
- // to reference the new configuration.
- void UpdateConfig(const BoundNetLog& net_log);
+ enum State {
+ STATE_NONE,
+ STATE_WAITING_FOR_PROXY_CONFIG,
+ STATE_WAITING_FOR_INIT_PROXY_RESOLVER,
+ STATE_READY,
+ };
- // Assign |config| as the current configuration.
- void SetConfig(const ProxyConfig& config);
-
- // Starts downloading and testing the various PAC choices.
- // Calls OnInitProxyResolverComplete() when completed.
- void StartInitProxyResolver();
+ ~ProxyService();
- // Tries to update the configuration if it hasn't been checked in a while.
- void UpdateConfigIfOld(const BoundNetLog& net_log);
+ // Resets all the variables associated with the current proxy configuration,
+ // and rewinds the current state to |STATE_NONE|. Returns the previous value
+ // of |current_state_|. If |reset_fetched_config| is true then
+ // |fetched_config_| will also be reset, otherwise it will be left as-is.
+ // Resetting it means that we will have to re-fetch the configuration from
+ // the ProxyConfigService later.
+ State ResetProxyConfig(bool reset_fetched_config);
- // Returns true if the proxy resolver is being initialized for PAC
- // (downloading PAC script(s) + testing).
- // Resolve requests will be frozen until the initialization has completed.
- bool IsInitializingProxyResolver() const {
- return init_proxy_resolver_.get() != NULL;
- }
+ // Retrieves the current proxy configuration from the ProxyConfigService, and
+ // starts initializing for it.
+ void ApplyProxyConfigIfAvailable();
// Callback for when the proxy resolver has been initialized with a
// PAC script.
@@ -235,8 +244,9 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// restarted when calling ResumeAllPendingRequests().
void SuspendAllPendingRequests();
- // Sends all the unstarted pending requests off to the resolver.
- void ResumeAllPendingRequests();
+ // Advances the current state to |STATE_READY|, and resumes any pending
+ // requests which had been stalled waiting for initialization to complete.
+ void SetReady();
// Returns true if |pending_requests_| contains |req|.
bool ContainsPendingRequest(PacRequest* req);
@@ -255,19 +265,26 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// When this is called, we re-fetch PAC scripts and re-run WPAD.
virtual void OnIPAddressChanged();
+ // ProxyConfigService::Observer
+ virtual void OnProxyConfigChanged(const ProxyConfig& config);
+
+ // Start initialization using |fetched_config_|.
+ void InitializeUsingLastFetchedConfig();
+
scoped_ptr<ProxyConfigService> config_service_;
scoped_ptr<ProxyResolver> resolver_;
- // We store the proxy config and a counter (ID) that is incremented each time
- // the config changes.
+ // We store the proxy configuration that was last fetched from the
+ // ProxyConfigService, as well as the resulting "effective" configuration.
+ // The effective configuration is what we condense the original fetched
+ // settings to after testing the various automatic settings (auto-detect
+ // and custom PAC url).
+ ProxyConfig fetched_config_;
ProxyConfig config_;
// Increasing ID to give to the next ProxyConfig that we set.
int next_config_id_;
- // Indicates whether the ProxyResolver should be sent requests.
- bool should_use_proxy_resolver_;
-
// The time when the proxy configuration was last read from the system.
base::TimeTicks config_last_update_time_;
@@ -291,10 +308,19 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// |proxy_resolver_| must outlive |init_proxy_resolver_|.
scoped_ptr<InitProxyResolver> init_proxy_resolver_;
+ State current_state_;
+
// This is the log where any events generated by |init_proxy_resolver_| are
// sent to.
NetLog* net_log_;
+ // The earliest time at which we should run any proxy auto-config. (Used to
+ // stall re-configuration following an IP address change).
+ base::TimeTicks stall_proxy_autoconfig_until_;
+
+ // The amount of time to stall requests following IP address changes.
+ base::TimeDelta stall_proxy_auto_config_delay_;
+
DISALLOW_COPY_AND_ASSIGN(ProxyService);
};
diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc
index a69b66e..1c77876 100644
--- a/net/proxy/proxy_service_unittest.cc
+++ b/net/proxy/proxy_service_unittest.cc
@@ -9,6 +9,7 @@
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
@@ -27,18 +28,41 @@ namespace {
class MockProxyConfigService: public ProxyConfigService {
public:
- MockProxyConfigService() {} // Direct connect.
- explicit MockProxyConfigService(const ProxyConfig& pc) : config(pc) {}
- explicit MockProxyConfigService(const std::string& pac_url) {
- config.set_pac_url(GURL(pac_url));
+ explicit MockProxyConfigService(const ProxyConfig& config)
+ : has_config_(true), config_(config) {
}
- virtual int GetProxyConfig(ProxyConfig* results) {
- *results = config;
- return OK;
+ explicit MockProxyConfigService(const std::string& pac_url)
+ : has_config_(true),
+ config_(ProxyConfig::CreateFromCustomPacURL(GURL(pac_url))) {
}
- ProxyConfig config;
+ virtual void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
+
+ virtual void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
+
+ virtual bool GetLatestProxyConfig(ProxyConfig* results) {
+ if (has_config_) {
+ *results = config_;
+ return true;
+ }
+ return false;
+ }
+
+ void SetConfig(const ProxyConfig& config) {
+ has_config_ = true;
+ config_ = config;
+ FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(config));
+ }
+
+ private:
+ bool has_config_;
+ ProxyConfig config_;
+ ObserverList<Observer, true> observers_;
};
} // namespace
@@ -91,7 +115,8 @@ class MockProxyScriptFetcher : public ProxyScriptFetcher {
TEST(ProxyServiceTest, Direct) {
MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
scoped_refptr<ProxyService> service(
- new ProxyService(new MockProxyConfigService, resolver, NULL));
+ new ProxyService(new MockProxyConfigService(
+ ProxyConfig::CreateDirect()), resolver, NULL));
GURL url("http://www.google.com/");
@@ -105,11 +130,14 @@ TEST(ProxyServiceTest, Direct) {
EXPECT_TRUE(info.is_direct());
// Check the NetLog was filled correctly.
- EXPECT_EQ(5u, log.entries().size());
+ EXPECT_EQ(3u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
log.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
+ EXPECT_TRUE(LogContainsEvent(
+ log.entries(), 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
+ NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_PROXY_SERVICE));
+ log.entries(), 2, NetLog::TYPE_PROXY_SERVICE));
}
TEST(ProxyServiceTest, PAC) {
@@ -146,15 +174,15 @@ TEST(ProxyServiceTest, PAC) {
EXPECT_EQ("foopy:80", info.proxy_server().ToURI());
// Check the NetLog was filled correctly.
- EXPECT_EQ(7u, log.entries().size());
+ EXPECT_EQ(5u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
log.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 3, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ log.entries(), 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ log.entries(), 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 6, NetLog::TYPE_PROXY_SERVICE));
+ log.entries(), 4, NetLog::TYPE_PROXY_SERVICE));
}
// Test that the proxy resolver does not see the URL's username/password
@@ -552,8 +580,8 @@ TEST(ProxyServiceTest, ProxyFallback_NewSettings) {
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
// Fake an error on the proxy, and also a new configuration on the proxy.
- config_service->config = ProxyConfig();
- config_service->config.set_pac_url(GURL("http://foopy-new/proxy.pac"));
+ config_service->SetConfig(
+ ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy-new/proxy.pac")));
TestCompletionCallback callback2;
rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
@@ -583,8 +611,9 @@ TEST(ProxyServiceTest, ProxyFallback_NewSettings) {
EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
// We simulate a new configuration.
- config_service->config = ProxyConfig();
- config_service->config.set_pac_url(GURL("http://foopy-new2/proxy.pac"));
+ config_service->SetConfig(
+ ProxyConfig::CreateFromCustomPacURL(
+ GURL("http://foopy-new2/proxy.pac")));
// We fake another error. It should go back to the first proxy.
TestCompletionCallback callback4;
@@ -1121,17 +1150,17 @@ TEST(ProxyServiceTest, CancelWhilePACFetching) {
EXPECT_FALSE(callback2.have_result()); // Cancelled.
// Check the NetLog for request 1 (which was cancelled) got filled properly.
- EXPECT_EQ(6u, log1.entries().size());
+ EXPECT_EQ(4u, log1.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
log1.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- log1.entries(), 3, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ log1.entries(), 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(), 4, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
+ log1.entries(), 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log1.entries(), 5, NetLog::TYPE_PROXY_SERVICE));
+ log1.entries(), 3, NetLog::TYPE_PROXY_SERVICE));
}
// Test that if auto-detect fails, we fall-back to the custom pac.
@@ -1411,8 +1440,8 @@ TEST(ProxyServiceTest, BypassDoesntApplyToPac) {
// have any memory errors (used to be that the ProxyScriptFetcher was
// being deleted prior to the InitProxyResolver).
TEST(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) {
- ProxyConfig config;
- config.set_pac_url(GURL("http://foopy/proxy.pac"));
+ ProxyConfig config =
+ ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
MockProxyConfigService* config_service = new MockProxyConfigService(config);
MockAsyncProxyResolverExpectsBytes* resolver =
@@ -1496,61 +1525,10 @@ TEST(ProxyServiceTest, ResetProxyConfigService) {
EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
}
-// Check that after we have done the auto-detect test, and the configuration
-// is updated (with no change), we don't re-try the autodetect test.
-// Regression test for http://crbug.com/18526 -- the configuration was being
-// mutated to cancel out the automatic settings, which meant UpdateConfig()
-// thought it had received a new configuration.
-TEST(ProxyServiceTest, UpdateConfigAfterFailedAutodetect) {
- ProxyConfig config;
- config.set_auto_detect(true);
-
- MockProxyConfigService* config_service = new MockProxyConfigService(config);
- MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
- scoped_refptr<ProxyService> service(
- new ProxyService(config_service, resolver, NULL));
-
- // Start 1 requests.
-
- ProxyInfo info1;
- TestCompletionCallback callback1;
- int rv = service->ResolveProxy(
- GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Check that nothing has been sent to the proxy resolver yet.
- ASSERT_EQ(0u, resolver->pending_requests().size());
-
- // Fail the setting of autodetect script.
- EXPECT_EQ(ProxyResolverScriptData::TYPE_AUTO_DETECT,
- resolver->pending_set_pac_script_request()->script_data()->type());
- resolver->pending_set_pac_script_request()->CompleteNow(ERR_FAILED);
-
- // Verify that request ran as expected -- should have fallen back to direct.
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_TRUE(info1.is_direct());
-
- // Force the ProxyService to pull down a new proxy configuration.
- // (Even though the configuration isn't old/bad).
- service->UpdateConfig(BoundNetLog());
-
- // Start another request -- the effective configuration has not
- // changed, so we shouldn't re-run the autodetect step.
- // Rather, it should complete synchronously as direct-connect.
- ProxyInfo info2;
- TestCompletionCallback callback2;
- rv = service->ResolveProxy(
- GURL("http://www.google.com"), &info2, &callback2, NULL, BoundNetLog());
- EXPECT_EQ(OK, rv);
-
- EXPECT_TRUE(info2.is_direct());
-}
-
// Test that when going from a configuration that required PAC to one
// that does NOT, we unset the variable |should_use_proxy_resolver_|.
TEST(ProxyServiceTest, UpdateConfigFromPACToDirect) {
- ProxyConfig config;
- config.set_auto_detect(true);
+ ProxyConfig config = ProxyConfig::CreateAutoDetect();
MockProxyConfigService* config_service = new MockProxyConfigService(config);
MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
@@ -1587,9 +1565,7 @@ TEST(ProxyServiceTest, UpdateConfigFromPACToDirect) {
//
// This new configuration no longer has auto_detect set, so
// requests should complete synchronously now as direct-connect.
- config.set_auto_detect(false);
- config_service->config = config;
- service->UpdateConfig(BoundNetLog());
+ config_service->SetConfig(ProxyConfig::CreateDirect());
// Start another request -- the effective configuration has changed.
ProxyInfo info2;
@@ -1608,12 +1584,18 @@ TEST(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
MockAsyncProxyResolverExpectsBytes* resolver =
new MockAsyncProxyResolverExpectsBytes;
+ CapturingNetLog log(CapturingNetLog::kUnbounded);
+
scoped_refptr<ProxyService> service(
- new ProxyService(config_service, resolver, NULL));
+ new ProxyService(config_service, resolver, &log));
MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
service->SetProxyScriptFetcher(fetcher);
+ // Disable the "wait after IP address changes" hack, so this unit-test can
+ // complete quickly.
+ service->set_stall_proxy_auto_config_delay(base::TimeDelta());
+
// Start 1 request.
ProxyInfo info1;
@@ -1692,6 +1674,16 @@ TEST(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
// Wait for completion callback, and verify that the request ran as expected.
EXPECT_EQ(OK, callback2.WaitForResult());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
+
+ // Check that the expected events were outputted to the log stream.
+ // 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,
+ 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);
}
} // namespace net
diff --git a/net/proxy/sync_host_resolver_bridge.h b/net/proxy/sync_host_resolver_bridge.h
index b02d496..d3b9bb9 100644
--- a/net/proxy/sync_host_resolver_bridge.h
+++ b/net/proxy/sync_host_resolver_bridge.h
@@ -4,6 +4,7 @@
#ifndef NET_PROXY_SYNC_HOST_RESOLVER_BRIDGE_H_
#define NET_PROXY_SYNC_HOST_RESOLVER_BRIDGE_H_
+#pragma once
#include "base/scoped_ptr.h"
#include "net/base/host_resolver.h"
diff --git a/net/proxy/sync_host_resolver_bridge_unittest.cc b/net/proxy/sync_host_resolver_bridge_unittest.cc
index 95ba446..c10c3e6 100644
--- a/net/proxy/sync_host_resolver_bridge_unittest.cc
+++ b/net/proxy/sync_host_resolver_bridge_unittest.cc
@@ -91,7 +91,7 @@ class SyncProxyResolver : public ProxyResolver {
EXPECT_FALSE(request);
// Do a synchronous host resolve.
- HostResolver::RequestInfo info(url.host(), 80);
+ HostResolver::RequestInfo info(HostPortPair::FromURL(url));
AddressList addresses;
int rv =
host_resolver_->Resolve(info, &addresses, NULL, NULL, BoundNetLog());
diff --git a/net/run_testserver.target.mk b/net/run_testserver.target.mk
index 8de959b..22c1af4 100644
--- a/net/run_testserver.target.mk
+++ b/net/run_testserver.target.mk
@@ -21,6 +21,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -70,6 +71,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -134,14 +136,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -170,7 +173,8 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/run_testserver: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/run_testserver: LIBS := $(LIBS)
diff --git a/net/server/http_listen_socket.cc b/net/server/http_listen_socket.cc
index 16c664e..b4f05d9 100644
--- a/net/server/http_listen_socket.cc
+++ b/net/server/http_listen_socket.cc
@@ -13,7 +13,9 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/md5.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/server/http_listen_socket.h"
#include "net/server/http_server_request_info.h"
@@ -37,6 +39,9 @@ void HttpListenSocket::Accept() {
} else {
scoped_refptr<HttpListenSocket> sock =
new HttpListenSocket(conn, delegate_);
+#if defined(OS_POSIX)
+ sock->WatchSocket(WAITING_READ);
+#endif
// it's up to the delegate to AddRef if it wants to keep it around
DidAccept(this, sock);
}
@@ -58,11 +63,11 @@ HttpListenSocket* HttpListenSocket::Listen(
}
std::string GetHeaderValue(
- HttpServerRequestInfo* request,
+ const HttpServerRequestInfo& request,
const std::string& header_name) {
HttpServerRequestInfo::HeadersMap::iterator it =
- request->headers.find(header_name);
- if (it != request->headers.end())
+ request.headers.find(header_name);
+ if (it != request.headers.end())
return it->second;
return "";
}
@@ -81,12 +86,12 @@ uint32 WebSocketKeyFingerprint(const std::string& str) {
if (spaces == 0)
return 0;
int64 number = 0;
- if (!StringToInt64(result, &number))
+ if (!base::StringToInt64(result, &number))
return 0;
return htonl(static_cast<uint32>(number / spaces));
}
-void HttpListenSocket::AcceptWebSocket(HttpServerRequestInfo* request) {
+void HttpListenSocket::AcceptWebSocket(const HttpServerRequestInfo& request) {
std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1");
std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
@@ -96,23 +101,23 @@ void HttpListenSocket::AcceptWebSocket(HttpServerRequestInfo* request) {
char data[16];
memcpy(data, &fp1, 4);
memcpy(data + 4, &fp2, 4);
- memcpy(data + 8, &request->data[0], 8);
+ memcpy(data + 8, &request.data[0], 8);
MD5Digest digest;
MD5Sum(data, 16, &digest);
std::string origin = GetHeaderValue(request, "Origin");
std::string host = GetHeaderValue(request, "Host");
- std::string location = "ws://" + host + request->path;
+ std::string location = "ws://" + host + request.path;
is_web_socket_ = true;
- Send(StringPrintf("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Origin: %s\r\n"
- "Sec-WebSocket-Location: %s\r\n"
- "\r\n",
- origin.c_str(),
- location.c_str()));
+ Send(base::StringPrintf("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Origin: %s\r\n"
+ "Sec-WebSocket-Location: %s\r\n"
+ "\r\n",
+ origin.c_str(),
+ location.c_str()));
Send(reinterpret_cast<char*>(digest.a), 16);
}
@@ -125,6 +130,33 @@ void HttpListenSocket::SendOverWebSocket(const std::string& data) {
Send(&message_end, 1);
}
+void HttpListenSocket::Send200(const std::string& data,
+ const std::string& content_type) {
+ Send(base::StringPrintf("HTTP/1.1 200 OK\r\n"
+ "Content-Type:%s\r\n"
+ "Content-Length:%d\r\n"
+ "\r\n",
+ content_type.c_str(),
+ static_cast<int>(data.length())));
+ Send(data);
+}
+
+void HttpListenSocket::Send404() {
+ Send("HTTP/1.1 404 Not Found\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n");
+}
+
+void HttpListenSocket::Send500(const std::string& message) {
+ Send(base::StringPrintf("HTTP/1.1 500 Internal Error\r\n"
+ "Content-Type:text/html\r\n"
+ "Content-Length:%d\r\n"
+ "\r\n"
+ "%s",
+ static_cast<int>(message.length()),
+ message.c_str()));
+}
+
//
// HTTP Request Parser
// This HTTP request parser uses a simple state machine to quickly parse
@@ -199,11 +231,10 @@ int charToInput(char ch) {
return INPUT_DEFAULT;
}
-HttpServerRequestInfo* HttpListenSocket::ParseHeaders() {
+bool HttpListenSocket::ParseHeaders(HttpServerRequestInfo* info) {
int pos = 0;
int data_len = recv_data_.length();
int state = is_web_socket_ ? ST_WS_READY : ST_METHOD;
- scoped_ptr<HttpServerRequestInfo> info(new HttpServerRequestInfo());
std::string buffer;
std::string header_name;
std::string header_value;
@@ -247,7 +278,7 @@ HttpServerRequestInfo* HttpListenSocket::ParseHeaders() {
recv_data_ = recv_data_.substr(pos);
info->data = buffer;
buffer.clear();
- return info.release();
+ return true;
break;
}
state = next_state;
@@ -266,17 +297,17 @@ HttpServerRequestInfo* HttpListenSocket::ParseHeaders() {
recv_data_ = recv_data_.substr(pos);
info->data = recv_data_;
recv_data_.clear();
- return info.release();
+ return true;
case ST_WS_CLOSE:
is_web_socket_ = false;
- return NULL;
+ return false;
case ST_ERR:
- return NULL;
+ return false;
}
}
}
// No more characters, but we haven't finished parsing yet.
- return NULL;
+ return false;
}
void HttpListenSocket::DidAccept(ListenSocket* server,
@@ -289,26 +320,26 @@ void HttpListenSocket::DidRead(ListenSocket*,
int len) {
recv_data_.append(data, len);
while (recv_data_.length()) {
- scoped_ptr<HttpServerRequestInfo> request(ParseHeaders());
- if (!request.get())
+ HttpServerRequestInfo request;
+ if (!ParseHeaders(&request))
break;
if (is_web_socket_) {
- delegate_->OnWebSocketMessage(this, request->data);
+ delegate_->OnWebSocketMessage(this, request.data);
continue;
}
- std::string connection = GetHeaderValue(request.get(), "Connection");
+ std::string connection = GetHeaderValue(request, "Connection");
if (connection == "Upgrade") {
// Is this WebSocket and if yes, upgrade the connection.
- std::string key1 = GetHeaderValue(request.get(), "Sec-WebSocket-Key1");
- std::string key2 = GetHeaderValue(request.get(), "Sec-WebSocket-Key2");
+ std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1");
+ std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
if (!key1.empty() && !key2.empty()) {
- delegate_->OnWebSocketRequest(this, request.get());
+ delegate_->OnWebSocketRequest(this, request);
continue;
}
}
- delegate_->OnHttpRequest(this, request.get());
+ delegate_->OnHttpRequest(this, request);
}
}
diff --git a/net/server/http_listen_socket.h b/net/server/http_listen_socket.h
index 5517af0..2eae47d 100644
--- a/net/server/http_listen_socket.h
+++ b/net/server/http_listen_socket.h
@@ -4,6 +4,7 @@
#ifndef NET_SERVER_HTTP_LISTEN_SOCKET_H_
#define NET_SERVER_HTTP_LISTEN_SOCKET_H_
+#pragma once
#include "net/base/listen_socket.h"
@@ -16,10 +17,10 @@ class HttpListenSocket : public ListenSocket,
class Delegate {
public:
virtual void OnHttpRequest(HttpListenSocket* socket,
- HttpServerRequestInfo* info) = 0;
+ const HttpServerRequestInfo& info) = 0;
virtual void OnWebSocketRequest(HttpListenSocket* socket,
- HttpServerRequestInfo* info) = 0;
+ const HttpServerRequestInfo& info) = 0;
virtual void OnWebSocketMessage(HttpListenSocket* socket,
const std::string& data) = 0;
@@ -29,16 +30,22 @@ class HttpListenSocket : public ListenSocket,
virtual ~Delegate() {}
};
+ virtual void Accept();
+
static HttpListenSocket* Listen(const std::string& ip,
int port,
HttpListenSocket::Delegate* delegate);
- void AcceptWebSocket(HttpServerRequestInfo* request);
+ void AcceptWebSocket(const HttpServerRequestInfo& request);
void SendOverWebSocket(const std::string& data);
+ void Send200(const std::string& data, const std::string& mime_type);
+ void Send404();
+ void Send500(const std::string& message);
+
+ void Close() { ListenSocket::Close(); }
void Listen() { ListenSocket::Listen(); }
- virtual void Accept();
// ListenSocketDelegate
virtual void DidAccept(ListenSocket* server, ListenSocket* connection);
@@ -53,7 +60,7 @@ class HttpListenSocket : public ListenSocket,
// Expects the raw data to be stored in recv_data_. If parsing is successful,
// will remove the data parsed from recv_data_, leaving only the unused
// recv data.
- HttpServerRequestInfo* ParseHeaders();
+ bool ParseHeaders(HttpServerRequestInfo* info);
HttpListenSocket::Delegate* delegate_;
bool is_web_socket_;
diff --git a/net/server/http_server_request_info.h b/net/server/http_server_request_info.h
index 84f767f..9c362e2 100644
--- a/net/server/http_server_request_info.h
+++ b/net/server/http_server_request_info.h
@@ -4,6 +4,7 @@
#ifndef NET_SERVER_HTTP_SERVER_REQUEST_INFO_H_
#define NET_SERVER_HTTP_SERVER_REQUEST_INFO_H_
+#pragma once
#include <string>
#include <map>
@@ -29,7 +30,7 @@ class HttpServerRequestInfo {
// A map of the names -> values for HTTP headers.
typedef std::map<std::string, std::string> HeadersMap;
- HeadersMap headers;
+ mutable HeadersMap headers;
};
#endif // NET_SERVER_HTTP_SERVER_REQUEST_INFO_H_
diff --git a/net/socket/client_socket.cc b/net/socket/client_socket.cc
new file mode 100644
index 0000000..0edee70
--- /dev/null
+++ b/net/socket/client_socket.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 "net/socket/client_socket.h"
+
+#include "base/field_trial.h"
+#include "base/histogram.h"
+
+namespace net {
+
+ClientSocket::UseHistory::UseHistory()
+ : was_ever_connected_(false),
+ was_used_to_convey_data_(false),
+ omnibox_speculation_(false),
+ subresource_speculation_(false) {
+}
+
+ClientSocket::UseHistory::~UseHistory() {
+ EmitPreconnectionHistograms();
+}
+
+void ClientSocket::UseHistory::EmitPreconnectionHistograms() const {
+ DCHECK(!subresource_speculation_ || !omnibox_speculation_);
+ // 0 ==> non-speculative, never connected.
+ // 1 ==> non-speculative never used (but connected).
+ // 2 ==> non-speculative and used.
+ // 3 ==> omnibox_speculative never connected.
+ // 4 ==> omnibox_speculative never used (but connected).
+ // 5 ==> omnibox_speculative and used.
+ // 6 ==> subresource_speculative never connected.
+ // 7 ==> subresource_speculative never used (but connected).
+ // 8 ==> subresource_speculative and used.
+ int result;
+ if (was_used_to_convey_data_)
+ result = 2;
+ else if (was_ever_connected_)
+ result = 1;
+ else
+ result = 0; // Never used, and not really connected.
+
+ if (omnibox_speculation_)
+ result += 3;
+ else if (subresource_speculation_)
+ result += 6;
+ UMA_HISTOGRAM_ENUMERATION("Net.PreconnectUtilization2", result, 9);
+
+ static const bool connect_backup_jobs_fieldtrial =
+ FieldTrialList::Find("ConnnectBackupJobs") &&
+ !FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty();
+ if (connect_backup_jobs_fieldtrial) {
+ UMA_HISTOGRAM_ENUMERATION(
+ FieldTrial::MakeName("Net.PreconnectUtilization2",
+ "ConnnectBackupJobs"),
+ result, 9);
+ }
+}
+
+void ClientSocket::UseHistory::set_was_ever_connected() {
+ DCHECK(!was_used_to_convey_data_);
+ was_ever_connected_ = true;
+}
+
+void ClientSocket::UseHistory::set_was_used_to_convey_data() {
+ DCHECK(was_ever_connected_);
+ was_used_to_convey_data_ = true;
+}
+
+
+void ClientSocket::UseHistory::set_subresource_speculation() {
+ DCHECK(was_ever_connected_);
+ // TODO(jar): We should transition to marking a socket (or stream) at
+ // construction time as being created for speculative reasons. This current
+ // approach of trying to track use of a socket to convey data can make
+ // mistakes when other sockets (such as ones sitting in the pool for a long
+ // time) are issued. Unused sockets can be left over when a when a set of
+ // connections to a host are made, and one is "unlucky" and takes so long to
+ // complete a connection, that another socket is used, and recycled before a
+ // second connection comes available. Similarly, re-try connections can leave
+ // an original (slow to connect socket) in the pool, and that can be issued
+ // to a speculative requester. In any cases such old sockets will fail when an
+ // attempt is made to used them!... and then it will look like a speculative
+ // socket was discarded without any user!?!?!
+ if (was_used_to_convey_data_)
+ return;
+ subresource_speculation_ = true;
+}
+
+void ClientSocket::UseHistory::set_omnibox_speculation() {
+ DCHECK(was_ever_connected_);
+ if (was_used_to_convey_data_)
+ return;
+ omnibox_speculation_ = true;
+}
+
+bool ClientSocket::UseHistory::was_used_to_convey_data() const {
+ DCHECK(!was_used_to_convey_data_ || was_ever_connected_);
+ return was_used_to_convey_data_;
+}
+
+} // namespace net
diff --git a/net/socket/client_socket.h b/net/socket/client_socket.h
index 2bc1adb..e7ba153 100644
--- a/net/socket/client_socket.h
+++ b/net/socket/client_socket.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_CLIENT_SOCKET_H_
#define NET_SOCKET_CLIENT_SOCKET_H_
+#pragma once
#include "net/socket/socket.h"
@@ -14,6 +15,8 @@ class BoundNetLog;
class ClientSocket : public Socket {
public:
+ virtual ~ClientSocket() {}
+
// Called to establish a connection. Returns OK if the connection could be
// established synchronously. Otherwise, ERR_IO_PENDING is returned and the
// given callback will run asynchronously when the connection is established
@@ -49,10 +52,60 @@ class ClientSocket : public Socket {
virtual bool IsConnectedAndIdle() const = 0;
// Copies the peer address to |address| and returns a network error code.
+ // ERR_UNEXPECTED will be returned if the socket is not connected.
virtual int GetPeerAddress(AddressList* address) const = 0;
// Gets the NetLog for this socket.
virtual const BoundNetLog& NetLog() const = 0;
+
+ // Set the annotation to indicate this socket was created for speculative
+ // reasons. This call is generally forwarded to a basic TCPClientSocket*,
+ // where a UseHistory can be updated.
+ virtual void SetSubresourceSpeculation() = 0;
+ virtual void SetOmniboxSpeculation() = 0;
+
+ // Returns true if the underlying transport socket ever had any reads or
+ // writes. ClientSockets layered on top of transport sockets should forward
+ // this call to the transport socket.
+ virtual bool WasEverUsed() const = 0;
+
+ protected:
+ // The following class is only used to gather statistics about the history of
+ // a socket. It is only instantiated and used in basic sockets, such as
+ // TCPClientSocket* instances. Other classes that are derived from
+ // ClientSocket should forward any potential settings to their underlying
+ // transport sockets.
+ class UseHistory {
+ public:
+ UseHistory();
+ ~UseHistory();
+
+ void set_was_ever_connected();
+ void set_was_used_to_convey_data();
+
+ // The next two setters only have any impact if the socket has not yet been
+ // used to transmit data. If called later, we assume that the socket was
+ // reused from the pool, and was NOT constructed to service a speculative
+ // request.
+ void set_subresource_speculation();
+ void set_omnibox_speculation();
+
+ bool was_used_to_convey_data() const;
+
+ private:
+ // Summarize the statistics for this socket.
+ void EmitPreconnectionHistograms() const;
+ // Indicate if this was ever connected.
+ bool was_ever_connected_;
+ // Indicate if this socket was ever used to transmit or receive data.
+ bool was_used_to_convey_data_;
+
+ // Indicate if this socket was first created for speculative use, and
+ // identify the motivation.
+ bool omnibox_speculation_;
+ bool subresource_speculation_;
+ DISALLOW_COPY_AND_ASSIGN(UseHistory);
+ };
};
} // namespace net
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
index 622bccd..b45f911 100644
--- a/net/socket/client_socket_factory.cc
+++ b/net/socket/client_socket_factory.cc
@@ -9,6 +9,8 @@
#include "net/socket/client_socket_handle.h"
#if defined(OS_WIN)
#include "net/socket/ssl_client_socket_win.h"
+#elif defined(USE_OPENSSL)
+#include "net/socket/ssl_client_socket_openssl.h"
#elif defined(USE_NSS)
#include "net/socket/ssl_client_socket_nss.h"
#elif defined(USE_OPENSSL)
@@ -29,6 +31,8 @@ SSLClientSocket* DefaultSSLClientSocketFactory(
const SSLConfig& ssl_config) {
#if defined(OS_WIN)
return new SSLClientSocketWin(transport_socket, hostname, ssl_config);
+#elif defined(USE_OPENSSL)
+ return new SSLClientSocketOpenSSL(transport_socket, hostname, ssl_config);
#elif defined(USE_NSS)
return new SSLClientSocketNSS(transport_socket, hostname, ssl_config);
#elif defined(USE_OPENSSL)
@@ -37,7 +41,7 @@ SSLClientSocket* DefaultSSLClientSocketFactory(
// TODO(wtc): SSLClientSocketNSS can't do SSL client authentication using
// Mac OS X CDSA/CSSM yet (http://crbug.com/45369), so fall back on
// SSLClientSocketMac.
- if (ssl_config.client_cert)
+ if (ssl_config.send_client_cert)
return new SSLClientSocketMac(transport_socket, hostname, ssl_config);
return new SSLClientSocketNSS(transport_socket, hostname, ssl_config);
@@ -52,8 +56,10 @@ SSLClientSocketFactory g_ssl_factory = DefaultSSLClientSocketFactory;
class DefaultClientSocketFactory : public ClientSocketFactory {
public:
virtual ClientSocket* CreateTCPClientSocket(
- const AddressList& addresses, NetLog* net_log) {
- return new TCPClientSocket(addresses, net_log);
+ const AddressList& addresses,
+ NetLog* net_log,
+ const NetLog::Source& source) {
+ return new TCPClientSocket(addresses, net_log, source);
}
virtual SSLClientSocket* CreateSSLClientSocket(
diff --git a/net/socket/client_socket_factory.h b/net/socket/client_socket_factory.h
index dddf1de..97fb361 100644
--- a/net/socket/client_socket_factory.h
+++ b/net/socket/client_socket_factory.h
@@ -4,15 +4,17 @@
#ifndef NET_SOCKET_CLIENT_SOCKET_FACTORY_H_
#define NET_SOCKET_CLIENT_SOCKET_FACTORY_H_
+#pragma once
#include <string>
+#include "net/base/net_log.h"
+
namespace net {
class AddressList;
class ClientSocket;
class ClientSocketHandle;
-class NetLog;
class SSLClientSocket;
struct SSLConfig;
@@ -28,8 +30,12 @@ class ClientSocketFactory {
public:
virtual ~ClientSocketFactory() {}
+ // |source| is the NetLog::Source for the entity trying to create the socket,
+ // if it has one.
virtual ClientSocket* CreateTCPClientSocket(
- const AddressList& addresses, NetLog* net_log) = 0;
+ const AddressList& addresses,
+ NetLog* net_log,
+ const NetLog::Source& source) = 0;
virtual SSLClientSocket* CreateSSLClientSocket(
ClientSocketHandle* transport_socket,
diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc
index de2fd94..f9ab898 100644
--- a/net/socket/client_socket_handle.cc
+++ b/net/socket/client_socket_handle.cc
@@ -59,6 +59,7 @@ void ClientSocketHandle::ResetInternal(bool cancel) {
void ClientSocketHandle::ResetErrorState() {
is_ssl_error_ = false;
ssl_error_response_info_ = HttpResponseInfo();
+ pending_http_proxy_connection_.reset();
}
LoadState ClientSocketHandle::GetLoadState() const {
@@ -91,7 +92,7 @@ void ClientSocketHandle::HandleInitCompletion(int result) {
CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value.";
setup_time_ = base::TimeTicks::Now() - init_time_;
- scoped_refptr<ClientSocketPoolHistograms> histograms = pool_->histograms();
+ ClientSocketPoolHistograms* histograms = pool_->histograms();
histograms->AddSocketType(reuse_type());
switch (reuse_type()) {
case ClientSocketHandle::UNUSED:
diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h
index 7fdf784..406b9bb 100644
--- a/net/socket/client_socket_handle.h
+++ b/net/socket/client_socket_handle.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_CLIENT_SOCKET_HANDLE_H_
#define NET_SOCKET_CLIENT_SOCKET_HANDLE_H_
+#pragma once
#include <string>
@@ -73,7 +74,7 @@ class ClientSocketHandle {
const scoped_refptr<SocketParams>& socket_params,
RequestPriority priority,
CompletionCallback* callback,
- const scoped_refptr<PoolType>& pool,
+ PoolType* pool,
const BoundNetLog& net_log);
// An initialized handle can be reset, which causes it to return to the
@@ -108,6 +109,9 @@ class ClientSocketHandle {
void set_ssl_error_response_info(const HttpResponseInfo& ssl_error_state) {
ssl_error_response_info_ = ssl_error_state;
}
+ void set_pending_http_proxy_connection(ClientSocketHandle* connection) {
+ pending_http_proxy_connection_.reset(connection);
+ }
// Only valid if there is no |socket_|.
bool is_ssl_error() const {
@@ -120,6 +124,9 @@ class ClientSocketHandle {
const HttpResponseInfo& ssl_error_response_info() const {
return ssl_error_response_info_;
}
+ ClientSocketHandle* release_pending_http_proxy_connection() {
+ return pending_http_proxy_connection_.release();
+ }
// These may only be used if is_initialized() is true.
const std::string& group_name() const { return group_name_; }
@@ -137,19 +144,6 @@ class ClientSocketHandle {
return UNUSED_IDLE;
}
}
- bool ShouldResendFailedRequest(int error) const {
- // NOTE: we resend a request only if we reused a keep-alive connection.
- // This automatically prevents an infinite resend loop because we'll run
- // out of the cached keep-alive connections eventually.
- if ( // We used a socket that was never idle.
- reuse_type() == ClientSocketHandle::UNUSED ||
- // We used an unused, idle socket and got a error that wasn't a TCP RST.
- (reuse_type() == ClientSocketHandle::UNUSED_IDLE &&
- (error != OK && error != ERR_CONNECTION_RESET))) {
- return false;
- }
- return true;
- }
private:
// Called on asynchronous completion of an Init() request.
@@ -168,7 +162,7 @@ class ClientSocketHandle {
void ResetErrorState();
bool is_initialized_;
- scoped_refptr<ClientSocketPool> pool_;
+ ClientSocketPool* pool_;
scoped_ptr<ClientSocket> socket_;
std::string group_name_;
bool is_reused_;
@@ -178,6 +172,7 @@ class ClientSocketHandle {
int pool_id_; // See ClientSocketPool::ReleaseSocket() for an explanation.
bool is_ssl_error_;
HttpResponseInfo ssl_error_response_info_;
+ scoped_ptr<ClientSocketHandle> pending_http_proxy_connection_;
base::TimeTicks init_time_;
base::TimeDelta setup_time_;
@@ -192,7 +187,7 @@ int ClientSocketHandle::Init(const std::string& group_name,
const scoped_refptr<SocketParams>& socket_params,
RequestPriority priority,
CompletionCallback* callback,
- const scoped_refptr<PoolType>& pool,
+ PoolType* pool,
const BoundNetLog& net_log) {
requesting_source_ = net_log.source();
diff --git a/net/socket/client_socket_pool.h b/net/socket/client_socket_pool.h
index 646b5ed..c727345 100644
--- a/net/socket/client_socket_pool.h
+++ b/net/socket/client_socket_pool.h
@@ -4,9 +4,9 @@
#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_H_
#define NET_SOCKET_CLIENT_SOCKET_POOL_H_
+#pragma once
#include <deque>
-#include <map>
#include <string>
#include "base/basictypes.h"
@@ -18,6 +18,8 @@
#include "net/base/load_states.h"
#include "net/base/request_priority.h"
+class DictionaryValue;
+
namespace net {
class ClientSocket;
@@ -27,7 +29,7 @@ class ClientSocketPoolHistograms;
// A ClientSocketPool is used to restrict the number of sockets open at a time.
// It also maintains a list of idle persistent sockets.
//
-class ClientSocketPool : public base::RefCounted<ClientSocketPool> {
+class ClientSocketPool {
public:
// Requests a connected socket for a group_name.
//
@@ -87,7 +89,7 @@ class ClientSocketPool : public base::RefCounted<ClientSocketPool> {
// This flushes all state from the ClientSocketPool. This means that all
// idle and connecting sockets are discarded. Active sockets being
// held by ClientSocketPool clients will be discarded when released back to
- // the pool.
+ // the pool. Does not flush any pools wrapped by |this|.
virtual void Flush() = 0;
// Called to close any idle connections held by the connection manager.
@@ -103,12 +105,20 @@ class ClientSocketPool : public base::RefCounted<ClientSocketPool> {
virtual LoadState GetLoadState(const std::string& group_name,
const ClientSocketHandle* handle) const = 0;
+ // Retrieves information on the current state of the pool as a
+ // DictionaryValue. Caller takes possession of the returned value.
+ // If |include_nested_pools| is true, the states of any nested
+ // ClientSocketPools will be included.
+ virtual DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const = 0;
+
// Returns the maximum amount of time to wait before retrying a connect.
static const int kMaxConnectRetryIntervalMs = 250;
// The set of histograms specific to this pool. We can't use the standard
// UMA_HISTOGRAM_* macros because they are callsite static.
- virtual scoped_refptr<ClientSocketPoolHistograms> histograms() const = 0;
+ virtual ClientSocketPoolHistograms* histograms() const = 0;
static int unused_idle_socket_timeout();
static void set_unused_idle_socket_timeout(int timeout);
@@ -121,8 +131,6 @@ class ClientSocketPool : public base::RefCounted<ClientSocketPool> {
virtual base::TimeDelta ConnectionTimeout() const = 0;
private:
- friend class base::RefCounted<ClientSocketPool>;
-
DISALLOW_COPY_AND_ASSIGN(ClientSocketPool);
};
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index e4a611b..be197f5 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -11,6 +11,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/values.h"
#include "net/base/net_log.h"
#include "net/base/net_errors.h"
#include "net/socket/client_socket_handle.h"
@@ -27,6 +28,10 @@ namespace {
// some conditions. See http://crbug.com/4606.
const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
+// Indicate whether or not we should establish a new TCP connection after a
+// certain timeout has passed without receiving an ACK.
+bool g_connect_backup_jobs_enabled = true;
+
} // namespace
namespace net {
@@ -118,7 +123,9 @@ ClientSocketPoolBaseHelper::Request::Request(
CompletionCallback* callback,
RequestPriority priority,
const BoundNetLog& net_log)
- : handle_(handle), callback_(callback), priority_(priority),
+ : handle_(handle),
+ callback_(callback),
+ priority_(priority),
net_log_(net_log) {}
ClientSocketPoolBaseHelper::Request::~Request() {}
@@ -137,9 +144,9 @@ ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
unused_idle_socket_timeout_(unused_idle_socket_timeout),
used_idle_socket_timeout_(used_idle_socket_timeout),
connect_job_factory_(connect_job_factory),
- backup_jobs_enabled_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
- pool_generation_number_(0) {
+ connect_backup_jobs_enabled_(false),
+ pool_generation_number_(0),
+ method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
DCHECK_LE(0, max_sockets_per_group);
DCHECK_LE(max_sockets_per_group, max_sockets);
@@ -147,13 +154,11 @@ ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
}
ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
- CancelAllConnectJobs();
-
- // Clean up any idle sockets. Assert that we have no remaining active
- // sockets or pending requests. They should have all been cleaned up prior
- // to the manager being destroyed.
- CloseIdleSockets();
- CHECK(group_map_.empty());
+ // Clean up any idle sockets and pending connect jobs. Assert that we have no
+ // remaining active sockets or pending requests. They should have all been
+ // cleaned up prior to |this| being destroyed.
+ Flush();
+ DCHECK(group_map_.empty());
DCHECK(pending_callback_map_.empty());
DCHECK_EQ(0, connecting_socket_count_);
@@ -176,9 +181,12 @@ void ClientSocketPoolBaseHelper::InsertRequestIntoQueue(
// static
const ClientSocketPoolBaseHelper::Request*
ClientSocketPoolBaseHelper::RemoveRequestFromQueue(
- RequestQueue::iterator it, RequestQueue* pending_requests) {
+ RequestQueue::iterator it, Group* group) {
const Request* req = *it;
- pending_requests->erase(it);
+ group->mutable_pending_requests()->erase(it);
+ // If there are no more requests, we kill the backup timer.
+ if (group->pending_requests().empty())
+ group->CleanupBackupJob();
return req;
}
@@ -186,7 +194,7 @@ int ClientSocketPoolBaseHelper::RequestSocket(
const std::string& group_name,
const Request* request) {
request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
- Group& group = group_map_[group_name];
+ Group* group = GetOrCreateGroup(group_name);
int rv = RequestSocketInternal(group_name, request);
if (rv != ERR_IO_PENDING) {
@@ -194,7 +202,7 @@ int ClientSocketPoolBaseHelper::RequestSocket(
CHECK(!request->handle()->is_initialized());
delete request;
} else {
- InsertRequestIntoQueue(request, &group.pending_requests);
+ InsertRequestIntoQueue(request, group->mutable_pending_requests());
}
return rv;
}
@@ -207,14 +215,14 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
CHECK(callback);
ClientSocketHandle* const handle = request->handle();
CHECK(handle);
- Group& group = group_map_[group_name];
+ Group* group = GetOrCreateGroup(group_name);
// Try to reuse a socket.
- if (AssignIdleSocketToGroup(&group, request))
+ if (AssignIdleSocketToGroup(request, group))
return OK;
// Can we make another active socket now?
- if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) {
+ if (!group->HasAvailableSocketSlot(max_sockets_per_group_)) {
request->net_log().AddEvent(
NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL);
return ERR_IO_PENDING;
@@ -240,31 +248,27 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
if (rv == OK) {
LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
- handle, base::TimeDelta(), &group, request->net_log());
+ handle, base::TimeDelta(), group, request->net_log());
} else if (rv == ERR_IO_PENDING) {
// If we don't have any sockets in this group, set a timer for potentially
// creating a new one. If the SYN is lost, this backup socket may complete
// before the slow socket, improving end user latency.
- if (group.IsEmpty() && !group.backup_job && backup_jobs_enabled_) {
- group.backup_job = connect_job_factory_->NewConnectJob(group_name,
- *request,
- this);
- StartBackupSocketTimer(group_name);
- }
+ if (group->IsEmpty() && !group->HasBackupJob() &&
+ connect_backup_jobs_enabled_)
+ group->StartBackupSocketTimer(group_name, this);
connecting_socket_count_++;
- ConnectJob* job = connect_job.release();
- group.jobs.insert(job);
+ group->AddJob(connect_job.release());
} else {
LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
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());
- } else if (group.IsEmpty()) {
- group_map_.erase(group_name);
+ base::TimeDelta(), group, request->net_log());
+ } else if (group->IsEmpty()) {
+ RemoveGroup(group_name);
}
}
@@ -272,20 +276,20 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
}
bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
- Group* group, const Request* request) {
+ const Request* request, Group* group) {
// Iterate through the list of idle sockets until we find one or exhaust
// the list.
- while (!group->idle_sockets.empty()) {
- IdleSocket idle_socket = group->idle_sockets.back();
- group->idle_sockets.pop_back();
+ while (!group->idle_sockets().empty()) {
+ IdleSocket idle_socket = group->idle_sockets().back();
+ group->mutable_idle_sockets()->pop_back();
DecrementIdleCount();
if (idle_socket.socket->IsConnectedAndIdle()) {
// We found one we can reuse!
base::TimeDelta idle_time =
base::TimeTicks::Now() - idle_socket.start_time;
HandOutSocket(
- idle_socket.socket, idle_socket.used, request->handle(), idle_time,
- group, request->net_log());
+ idle_socket.socket, idle_socket.socket->WasEverUsed(),
+ request->handle(), idle_time, group, request->net_log());
return true;
}
delete idle_socket.socket;
@@ -301,60 +305,6 @@ void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
new NetLogSourceParameter("source_dependency", connect_job_source));
}
-void ClientSocketPoolBaseHelper::StartBackupSocketTimer(
- const std::string& group_name) {
- CHECK(ContainsKey(group_map_, group_name));
- Group& group = group_map_[group_name];
-
- // Only allow one timer pending to create a backup socket.
- if (group.backup_task)
- return;
-
- group.backup_task = method_factory_.NewRunnableMethod(
- &ClientSocketPoolBaseHelper::OnBackupSocketTimerFired, group_name);
- MessageLoop::current()->PostDelayedTask(FROM_HERE, group.backup_task,
- ConnectRetryIntervalMs());
-}
-
-void ClientSocketPoolBaseHelper::OnBackupSocketTimerFired(
- const std::string& group_name) {
- CHECK(ContainsKey(group_map_, group_name));
-
- Group& group = group_map_[group_name];
-
- CHECK(group.backup_task);
- group.backup_task = NULL;
-
- CHECK(group.backup_job);
-
- // If there are no more jobs pending, there is no work to do.
- // If we've done our cleanups correctly, this should not happen.
- if (group.jobs.empty()) {
- NOTREACHED();
- return;
- }
-
- // If our backup job is waiting on DNS, or if we can't create any sockets
- // right now due to limits, just reset the timer.
- if (ReachedMaxSocketsLimit() ||
- !group.HasAvailableSocketSlot(max_sockets_per_group_) ||
- (*group.jobs.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
- StartBackupSocketTimer(group_name);
- return;
- }
-
- group.backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED,
- NULL);
- SIMPLE_STATS_COUNTER("socket.backup_created");
- int rv = group.backup_job->Connect();
- connecting_socket_count_++;
- group.jobs.insert(group.backup_job);
- ConnectJob* job = group.backup_job;
- group.backup_job = NULL;
- if (rv != ERR_IO_PENDING)
- OnConnectJobComplete(rv, job);
-}
-
void ClientSocketPoolBaseHelper::CancelRequest(
const std::string& group_name, ClientSocketHandle* handle) {
PendingCallbackMap::iterator callback_it = pending_callback_map_.find(handle);
@@ -372,20 +322,20 @@ void ClientSocketPoolBaseHelper::CancelRequest(
CHECK(ContainsKey(group_map_, group_name));
- Group& group = group_map_[group_name];
+ Group* group = GetOrCreateGroup(group_name);
// Search pending_requests for matching handle.
- RequestQueue::iterator it = group.pending_requests.begin();
- for (; it != group.pending_requests.end(); ++it) {
+ RequestQueue::iterator it = group->mutable_pending_requests()->begin();
+ for (; it != group->pending_requests().end(); ++it) {
if ((*it)->handle() == handle) {
- const Request* req = RemoveRequestFromQueue(it, &group.pending_requests);
+ const Request* req = RemoveRequestFromQueue(it, group);
req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL);
req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
delete req;
// We let the job run, unless we're at the socket limit.
- if (group.jobs.size() && ReachedMaxSocketsLimit()) {
- RemoveConnectJob(*group.jobs.begin(), &group);
+ if (group->jobs().size() && ReachedMaxSocketsLimit()) {
+ RemoveConnectJob(*group->jobs().begin(), group);
CheckForStalledSocketGroups();
}
break;
@@ -393,8 +343,13 @@ void ClientSocketPoolBaseHelper::CancelRequest(
}
}
+bool ClientSocketPoolBaseHelper::HasGroup(const std::string& group_name) const {
+ return ContainsKey(group_map_, group_name);
+}
+
void ClientSocketPoolBaseHelper::CloseIdleSockets() {
CleanupIdleSockets(true);
+ DCHECK_EQ(0, idle_socket_count_);
}
int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
@@ -402,7 +357,7 @@ int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
GroupMap::const_iterator i = group_map_.find(group_name);
CHECK(i != group_map_.end());
- return i->second.idle_sockets.size();
+ return i->second->idle_sockets().size();
}
LoadState ClientSocketPoolBaseHelper::GetLoadState(
@@ -418,16 +373,16 @@ LoadState ClientSocketPoolBaseHelper::GetLoadState(
}
// Can't use operator[] since it is non-const.
- const Group& group = group_map_.find(group_name)->second;
+ const Group& group = *group_map_.find(group_name)->second;
// Search pending_requests for matching handle.
- RequestQueue::const_iterator it = group.pending_requests.begin();
- for (size_t i = 0; it != group.pending_requests.end(); ++it, ++i) {
+ RequestQueue::const_iterator it = group.pending_requests().begin();
+ for (size_t i = 0; it != group.pending_requests().end(); ++it, ++i) {
if ((*it)->handle() == handle) {
- if (i < group.jobs.size()) {
+ if (i < group.jobs().size()) {
LoadState max_state = LOAD_STATE_IDLE;
- for (ConnectJobSet::const_iterator job_it = group.jobs.begin();
- job_it != group.jobs.end(); ++job_it) {
+ for (ConnectJobSet::const_iterator job_it = group.jobs().begin();
+ job_it != group.jobs().end(); ++job_it) {
max_state = std::max(max_state, (*job_it)->GetLoadState());
}
return max_state;
@@ -443,12 +398,57 @@ LoadState ClientSocketPoolBaseHelper::GetLoadState(
return LOAD_STATE_IDLE;
}
+DictionaryValue* ClientSocketPoolBaseHelper::GetInfoAsValue(
+ const std::string& name, const std::string& type) const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("name", name);
+ dict->SetString("type", type);
+ dict->SetInteger("handed_out_socket_count", handed_out_socket_count_);
+ dict->SetInteger("connecting_socket_count", connecting_socket_count_);
+ dict->SetInteger("idle_socket_count", idle_socket_count_);
+ dict->SetInteger("max_socket_count", max_sockets_);
+ dict->SetInteger("max_sockets_per_group", max_sockets_per_group_);
+ dict->SetInteger("pool_generation_number", pool_generation_number_);
+
+ if (group_map_.empty())
+ return dict;
+
+ DictionaryValue* all_groups_dict = new DictionaryValue();
+ for (GroupMap::const_iterator it = group_map_.begin();
+ it != group_map_.end(); it++) {
+ const Group* group = it->second;
+ DictionaryValue* group_dict = new DictionaryValue();
+
+ group_dict->SetInteger("pending_request_count",
+ group->pending_requests().size());
+ if (!group->pending_requests().empty()) {
+ group_dict->SetInteger("top_pending_priority",
+ group->TopPendingPriority());
+ }
+
+ group_dict->SetInteger("active_socket_count", group->active_socket_count());
+ group_dict->SetInteger("idle_socket_count", group->idle_sockets().size());
+ group_dict->SetInteger("connect_job_count", group->jobs().size());
+
+ group_dict->SetBoolean("is_stalled",
+ group->IsStalled(max_sockets_per_group_));
+ group_dict->SetBoolean("has_backup_job", group->HasBackupJob());
+
+ all_groups_dict->SetWithoutPathExpansion(it->first, group_dict);
+ }
+ dict->Set("groups", all_groups_dict);
+ return dict;
+}
+
bool ClientSocketPoolBaseHelper::IdleSocket::ShouldCleanup(
base::TimeTicks now,
base::TimeDelta timeout) const {
bool timed_out = (now - start_time) >= timeout;
- return timed_out ||
- !(used ? socket->IsConnectedAndIdle() : socket->IsConnected());
+ if (timed_out)
+ return true;
+ if (socket->WasEverUsed())
+ return !socket->IsConnectedAndIdle();
+ return !socket->IsConnected();
}
void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
@@ -461,15 +461,16 @@ void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
GroupMap::iterator i = group_map_.begin();
while (i != group_map_.end()) {
- Group& group = i->second;
+ Group* group = i->second;
- std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
- while (j != group.idle_sockets.end()) {
+ std::deque<IdleSocket>::iterator j = group->mutable_idle_sockets()->begin();
+ while (j != group->idle_sockets().end()) {
base::TimeDelta timeout =
- j->used ? used_idle_socket_timeout_ : unused_idle_socket_timeout_;
+ j->socket->WasEverUsed() ?
+ used_idle_socket_timeout_ : unused_idle_socket_timeout_;
if (force || j->ShouldCleanup(now, timeout)) {
delete j->socket;
- j = group.idle_sockets.erase(j);
+ j = group->mutable_idle_sockets()->erase(j);
DecrementIdleCount();
} else {
++j;
@@ -477,14 +478,45 @@ void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
}
// Delete group if no longer needed.
- if (group.IsEmpty()) {
- group_map_.erase(i++);
+ if (group->IsEmpty()) {
+ RemoveGroup(i++);
} else {
++i;
}
}
}
+ClientSocketPoolBaseHelper::Group* ClientSocketPoolBaseHelper::GetOrCreateGroup(
+ const std::string& group_name) {
+ GroupMap::iterator it = group_map_.find(group_name);
+ if (it != group_map_.end())
+ return it->second;
+ Group* group = new Group;
+ group_map_[group_name] = group;
+ return group;
+}
+
+void ClientSocketPoolBaseHelper::RemoveGroup(const std::string& group_name) {
+ GroupMap::iterator it = group_map_.find(group_name);
+ CHECK(it != group_map_.end());
+
+ RemoveGroup(it);
+}
+
+void ClientSocketPoolBaseHelper::RemoveGroup(GroupMap::iterator it) {
+ delete it->second;
+ group_map_.erase(it);
+}
+
+// static
+void ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(bool enabled) {
+ g_connect_backup_jobs_enabled = enabled;
+}
+
+void ClientSocketPoolBaseHelper::EnableConnectBackupJobs() {
+ connect_backup_jobs_enabled_ = g_connect_backup_jobs_enabled;
+}
+
void ClientSocketPoolBaseHelper::IncrementIdleCount() {
if (++idle_socket_count_ == 1)
timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
@@ -502,20 +534,20 @@ void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
GroupMap::iterator i = group_map_.find(group_name);
CHECK(i != group_map_.end());
- Group& group = i->second;
+ Group* group = i->second;
CHECK_GT(handed_out_socket_count_, 0);
handed_out_socket_count_--;
- CHECK_GT(group.active_socket_count, 0);
- group.active_socket_count--;
+ CHECK_GT(group->active_socket_count(), 0);
+ group->DecrementActiveSocketCount();
const bool can_reuse = socket->IsConnectedAndIdle() &&
id == pool_generation_number_;
if (can_reuse) {
// Add it to the idle list.
- AddIdleSocket(socket, true /* used socket */, &group);
- OnAvailableSocketSlot(group_name, &group);
+ AddIdleSocket(socket, group);
+ OnAvailableSocketSlot(group_name, group);
} else {
delete socket;
}
@@ -558,16 +590,16 @@ bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group,
bool has_stalled_group = false;
for (GroupMap::iterator i = group_map_.begin();
i != group_map_.end(); ++i) {
- Group& group = i->second;
- const RequestQueue& queue = group.pending_requests;
+ Group* curr_group = i->second;
+ const RequestQueue& queue = curr_group->pending_requests();
if (queue.empty())
continue;
- if (group.IsStalled(max_sockets_per_group_)) {
+ if (curr_group->IsStalled(max_sockets_per_group_)) {
has_stalled_group = true;
bool has_higher_priority = !top_group ||
- group.TopPendingPriority() < top_group->TopPendingPriority();
+ curr_group->TopPendingPriority() < top_group->TopPendingPriority();
if (has_higher_priority) {
- top_group = &group;
+ top_group = curr_group;
top_group_name = &i->first;
}
}
@@ -586,7 +618,7 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
const std::string group_name = job->group_name();
GroupMap::iterator group_it = group_map_.find(group_name);
CHECK(group_it != group_map_.end());
- Group& group = group_it->second;
+ Group* group = group_it->second;
scoped_ptr<ClientSocket> socket(job->ReleaseSocket());
@@ -594,44 +626,44 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
if (result == OK) {
DCHECK(socket.get());
- RemoveConnectJob(job, &group);
- if (!group.pending_requests.empty()) {
+ RemoveConnectJob(job, group);
+ if (!group->pending_requests().empty()) {
scoped_ptr<const Request> r(RemoveRequestFromQueue(
- group.pending_requests.begin(), &group.pending_requests));
+ group->mutable_pending_requests()->begin(), group));
LogBoundConnectJobToRequest(job_log.source(), r.get());
HandOutSocket(
socket.release(), false /* unused socket */, r->handle(),
- base::TimeDelta(), &group, r->net_log());
+ base::TimeDelta(), group, r->net_log());
r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
InvokeUserCallbackLater(r->handle(), r->callback(), result);
} else {
- AddIdleSocket(socket.release(), false /* unused socket */, &group);
- OnAvailableSocketSlot(group_name, &group);
+ AddIdleSocket(socket.release(), group);
+ OnAvailableSocketSlot(group_name, group);
CheckForStalledSocketGroups();
}
} else {
// If we got a socket, it must contain error information so pass that
// up so that the caller can retrieve it.
bool handed_out_socket = false;
- if (!group.pending_requests.empty()) {
+ if (!group->pending_requests().empty()) {
scoped_ptr<const Request> r(RemoveRequestFromQueue(
- group.pending_requests.begin(), &group.pending_requests));
+ group->mutable_pending_requests()->begin(), group));
LogBoundConnectJobToRequest(job_log.source(), r.get());
job->GetAdditionalErrorState(r->handle());
- RemoveConnectJob(job, &group);
+ RemoveConnectJob(job, group);
if (socket.get()) {
handed_out_socket = true;
HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
- base::TimeDelta(), &group, r->net_log());
+ base::TimeDelta(), group, r->net_log());
}
r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL,
new NetLogIntegerParameter("net_error", result));
InvokeUserCallbackLater(r->handle(), r->callback(), result);
} else {
- RemoveConnectJob(job, &group);
+ RemoveConnectJob(job, group);
}
if (!handed_out_socket) {
- OnAvailableSocketSlot(group_name, &group);
+ OnAvailableSocketSlot(group_name, group);
CheckForStalledSocketGroups();
}
}
@@ -645,6 +677,7 @@ void ClientSocketPoolBaseHelper::Flush() {
pool_generation_number_++;
CancelAllConnectJobs();
CloseIdleSockets();
+ AbortAllRequests();
}
void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
@@ -653,12 +686,12 @@ void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
connecting_socket_count_--;
DCHECK(group);
- DCHECK(ContainsKey(group->jobs, job));
- group->jobs.erase(job);
+ DCHECK(ContainsKey(group->jobs(), job));
+ group->RemoveJob(job);
// If we've got no more jobs for this group, then we no longer need a
// backup job either.
- if (group->jobs.empty())
+ if (group->jobs().empty())
group->CleanupBackupJob();
DCHECK(job);
@@ -667,20 +700,22 @@ void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
const std::string& group_name, Group* group) {
- if (!group->pending_requests.empty())
- ProcessPendingRequest(group_name, group);
-
+ DCHECK(ContainsKey(group_map_, group_name));
if (group->IsEmpty())
- group_map_.erase(group_name);
+ RemoveGroup(group_name);
+ else if (!group->pending_requests().empty())
+ ProcessPendingRequest(group_name, group);
}
void ClientSocketPoolBaseHelper::ProcessPendingRequest(
const std::string& group_name, Group* group) {
int rv = RequestSocketInternal(group_name,
- *group->pending_requests.begin());
+ *group->pending_requests().begin());
if (rv != ERR_IO_PENDING) {
scoped_ptr<const Request> request(RemoveRequestFromQueue(
- group->pending_requests.begin(), &group->pending_requests));
+ group->mutable_pending_requests()->begin(), group));
+ if (group->IsEmpty())
+ RemoveGroup(group_name);
scoped_refptr<NetLog::EventParameters> params;
if (rv != OK)
@@ -716,35 +751,59 @@ void ClientSocketPoolBaseHelper::HandOutSocket(
"source_dependency", socket->NetLog().source()));
handed_out_socket_count_++;
- group->active_socket_count++;
+ group->IncrementActiveSocketCount();
}
void ClientSocketPoolBaseHelper::AddIdleSocket(
- ClientSocket* socket, bool used, Group* group) {
+ ClientSocket* socket, Group* group) {
DCHECK(socket);
IdleSocket idle_socket;
idle_socket.socket = socket;
idle_socket.start_time = base::TimeTicks::Now();
- idle_socket.used = used;
- group->idle_sockets.push_back(idle_socket);
+ group->mutable_idle_sockets()->push_back(idle_socket);
IncrementIdleCount();
}
void ClientSocketPoolBaseHelper::CancelAllConnectJobs() {
for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
- Group& group = i->second;
- connecting_socket_count_ -= group.jobs.size();
- STLDeleteElements(&group.jobs);
+ Group* group = i->second;
+ connecting_socket_count_ -= group->jobs().size();
+ group->RemoveAllJobs();
- if (group.backup_task) {
- group.backup_task->Cancel();
- group.backup_task = NULL;
+ // Delete group if no longer needed.
+ if (group->IsEmpty()) {
+ // RemoveGroup() will call .erase() which will invalidate the iterator,
+ // but i will already have been incremented to a valid iterator before
+ // RemoveGroup() is called.
+ RemoveGroup(i++);
+ } else {
+ ++i;
+ }
+ }
+ DCHECK_EQ(0, connecting_socket_count_);
+}
+
+void ClientSocketPoolBaseHelper::AbortAllRequests() {
+ for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
+ Group* group = i->second;
+
+ RequestQueue pending_requests;
+ pending_requests.swap(*group->mutable_pending_requests());
+ for (RequestQueue::iterator it2 = pending_requests.begin();
+ it2 != pending_requests.end(); ++it2) {
+ const Request* request = *it2;
+ InvokeUserCallbackLater(
+ request->handle(), request->callback(), ERR_ABORTED);
+ delete request;
}
// Delete group if no longer needed.
- if (group.IsEmpty()) {
- group_map_.erase(i++);
+ if (group->IsEmpty()) {
+ // RemoveGroup() will call .erase() which will invalidate the iterator,
+ // but i will already have been incremented to a valid iterator before
+ // RemoveGroup() is called.
+ RemoveGroup(i++);
} else {
++i;
}
@@ -766,15 +825,16 @@ void ClientSocketPoolBaseHelper::CloseOneIdleSocket() {
CHECK_GT(idle_socket_count(), 0);
for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
- Group& group = i->second;
+ Group* group = i->second;
- if (!group.idle_sockets.empty()) {
- std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
+ if (!group->idle_sockets().empty()) {
+ std::deque<IdleSocket>::iterator j =
+ group->mutable_idle_sockets()->begin();
delete j->socket;
- group.idle_sockets.erase(j);
+ group->mutable_idle_sockets()->erase(j);
DecrementIdleCount();
- if (group.IsEmpty())
- group_map_.erase(i);
+ if (group->IsEmpty())
+ RemoveGroup(i);
return;
}
@@ -789,8 +849,7 @@ void ClientSocketPoolBaseHelper::InvokeUserCallbackLater(
pending_callback_map_[handle] = CallbackResultPair(callback, rv);
MessageLoop::current()->PostTask(
FROM_HERE,
- NewRunnableMethod(
- this,
+ method_factory_.NewRunnableMethod(
&ClientSocketPoolBaseHelper::InvokeUserCallback,
handle));
}
@@ -810,6 +869,71 @@ void ClientSocketPoolBaseHelper::InvokeUserCallback(
callback->Run(result);
}
+ClientSocketPoolBaseHelper::Group::Group()
+ : active_socket_count_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
+
+ClientSocketPoolBaseHelper::Group::~Group() {
+ CleanupBackupJob();
+}
+
+void ClientSocketPoolBaseHelper::Group::StartBackupSocketTimer(
+ const std::string& group_name,
+ ClientSocketPoolBaseHelper* pool) {
+ // Only allow one timer pending to create a backup socket.
+ if (!method_factory_.empty())
+ return;
+
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &Group::OnBackupSocketTimerFired, group_name, pool),
+ pool->ConnectRetryIntervalMs());
+}
+
+void ClientSocketPoolBaseHelper::Group::OnBackupSocketTimerFired(
+ std::string group_name,
+ ClientSocketPoolBaseHelper* pool) {
+ // If there are no more jobs pending, there is no work to do.
+ // If we've done our cleanups correctly, this should not happen.
+ if (jobs_.empty()) {
+ NOTREACHED();
+ return;
+ }
+
+ // If our backup job is waiting on DNS, or if we can't create any sockets
+ // right now due to limits, just reset the timer.
+ if (pool->ReachedMaxSocketsLimit() ||
+ !HasAvailableSocketSlot(pool->max_sockets_per_group_) ||
+ (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
+ StartBackupSocketTimer(group_name, pool);
+ return;
+ }
+
+ if (pending_requests_.empty()) {
+ LOG(DFATAL) << "No pending request for backup job.";
+ return;
+ }
+
+ ConnectJob* backup_job = pool->connect_job_factory_->NewConnectJob(
+ group_name, **pending_requests_.begin(), pool);
+ backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, NULL);
+ SIMPLE_STATS_COUNTER("socket.backup_created");
+ int rv = backup_job->Connect();
+ pool->connecting_socket_count_++;
+ AddJob(backup_job);
+ if (rv != ERR_IO_PENDING)
+ pool->OnConnectJobComplete(rv, backup_job);
+}
+
+void ClientSocketPoolBaseHelper::Group::RemoveAllJobs() {
+ // Delete active jobs.
+ STLDeleteElements(&jobs_);
+
+ // Cancel pending backup job.
+ method_factory_.RevokeAll();
+}
+
} // namespace internal
} // namespace net
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index ef4b115..ba49e9b 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -21,6 +21,7 @@
//
#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
#define NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
+#pragma once
#include <deque>
#include <map>
@@ -28,7 +29,6 @@
#include <string>
#include "base/basictypes.h"
-#include "base/compiler_specific.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
@@ -131,8 +131,7 @@ namespace internal {
// ClientSocketPoolBaseHelper. This class is not for external use, please use
// ClientSocketPoolBase instead.
class ClientSocketPoolBaseHelper
- : public base::RefCounted<ClientSocketPoolBaseHelper>,
- public ConnectJob::Delegate,
+ : public ConnectJob::Delegate,
public NetworkChangeNotifier::Observer {
public:
class Request {
@@ -181,6 +180,8 @@ class ClientSocketPoolBaseHelper
base::TimeDelta used_idle_socket_timeout,
ConnectJobFactory* connect_job_factory);
+ ~ClientSocketPoolBaseHelper();
+
// See ClientSocketPool::RequestSocket for documentation on this function.
// ClientSocketPoolBaseHelper takes ownership of |request|, which must be
// heap allocated.
@@ -227,28 +228,34 @@ class ClientSocketPoolBaseHelper
virtual void OnIPAddressChanged();
int NumConnectJobsInGroup(const std::string& group_name) const {
- return group_map_.find(group_name)->second.jobs.size();
+ return group_map_.find(group_name)->second->jobs().size();
}
+ bool HasGroup(const std::string& group_name) const;
+
// Closes all idle sockets if |force| is true. Else, only closes idle
// sockets that timed out or can't be reused. Made public for testing.
void CleanupIdleSockets(bool force);
+ // See ClientSocketPool::GetInfoAsValue for documentation on this function.
+ DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type) const;
+
base::TimeDelta ConnectionTimeout() const {
return connect_job_factory_->ConnectionTimeout();
}
- void EnableBackupJobs() { backup_jobs_enabled_ = true; }
+ static void set_connect_backup_jobs_enabled(bool enabled);
+ void EnableConnectBackupJobs();
private:
friend class base::RefCounted<ClientSocketPoolBaseHelper>;
// Entry for a persistent socket which became idle at time |start_time|.
struct IdleSocket {
- IdleSocket() : socket(NULL), used(false) {}
+ IdleSocket() : socket(NULL) {}
ClientSocket* socket;
base::TimeTicks start_time;
- bool used; // Indicates whether or not the socket has been used yet.
// An idle socket should be removed if it can't be reused, or has been idle
// for too long. |now| is the current time value (TimeTicks::Now()).
@@ -267,57 +274,69 @@ class ClientSocketPoolBaseHelper
// A Group is allocated per group_name when there are idle sockets or pending
// requests. Otherwise, the Group object is removed from the map.
// |active_socket_count| tracks the number of sockets held by clients.
- struct Group {
- Group()
- : active_socket_count(0),
- backup_job(NULL),
- backup_task(NULL) {
- }
-
- ~Group() {
- CleanupBackupJob();
- }
+ class Group {
+ public:
+ Group();
+ ~Group();
bool IsEmpty() const {
- return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() &&
- pending_requests.empty();
+ return active_socket_count_ == 0 && idle_sockets_.empty() &&
+ jobs_.empty() && pending_requests_.empty();
}
bool HasAvailableSocketSlot(int max_sockets_per_group) const {
- return active_socket_count + static_cast<int>(jobs.size()) <
+ return active_socket_count_ + static_cast<int>(jobs_.size()) <
max_sockets_per_group;
}
bool IsStalled(int max_sockets_per_group) const {
return HasAvailableSocketSlot(max_sockets_per_group) &&
- pending_requests.size() > jobs.size();
+ pending_requests_.size() > jobs_.size();
}
RequestPriority TopPendingPriority() const {
- return pending_requests.front()->priority();
+ return pending_requests_.front()->priority();
}
+ bool HasBackupJob() const { return !method_factory_.empty(); }
+
void CleanupBackupJob() {
- if (backup_job) {
- delete backup_job;
- backup_job = NULL;
- }
- if (backup_task) {
- backup_task->Cancel();
- backup_task = NULL;
- }
+ method_factory_.RevokeAll();
}
- std::deque<IdleSocket> idle_sockets;
- std::set<const ConnectJob*> jobs;
- RequestQueue pending_requests;
- int active_socket_count; // number of active sockets used by clients
- // A backup job in case the connect for this group takes too long.
- ConnectJob* backup_job;
- CancelableTask* backup_task;
+ // Set a timer to create a backup socket if it takes too long to create one.
+ void StartBackupSocketTimer(const std::string& group_name,
+ ClientSocketPoolBaseHelper* pool);
+
+ // Called when the backup socket timer fires.
+ void OnBackupSocketTimerFired(
+ std::string group_name,
+ ClientSocketPoolBaseHelper* pool);
+
+ void AddJob(const ConnectJob* job) { jobs_.insert(job); }
+ void RemoveJob(const ConnectJob* job) { jobs_.erase(job); }
+ void RemoveAllJobs();
+
+ void IncrementActiveSocketCount() { active_socket_count_++; }
+ void DecrementActiveSocketCount() { active_socket_count_--; }
+
+ const std::set<const ConnectJob*>& jobs() const { return jobs_; }
+ const std::deque<IdleSocket>& idle_sockets() const { return idle_sockets_; }
+ const RequestQueue& pending_requests() const { return pending_requests_; }
+ int active_socket_count() const { return active_socket_count_; }
+ RequestQueue* mutable_pending_requests() { return &pending_requests_; }
+ std::deque<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; }
+
+ private:
+ std::deque<IdleSocket> idle_sockets_;
+ std::set<const ConnectJob*> jobs_;
+ RequestQueue pending_requests_;
+ int active_socket_count_; // number of active sockets used by clients
+ // A factory to pin the backup_job tasks.
+ ScopedRunnableMethodFactory<Group> method_factory_;
};
- typedef std::map<std::string, Group> GroupMap;
+ typedef std::map<std::string, Group*> GroupMap;
typedef std::set<const ConnectJob*> ConnectJobSet;
@@ -333,12 +352,14 @@ class ClientSocketPoolBaseHelper
typedef std::map<const ClientSocketHandle*, CallbackResultPair>
PendingCallbackMap;
- ~ClientSocketPoolBaseHelper();
-
static void InsertRequestIntoQueue(const Request* r,
RequestQueue* pending_requests);
static const Request* RemoveRequestFromQueue(RequestQueue::iterator it,
- RequestQueue* pending_requests);
+ Group* group);
+
+ Group* GetOrCreateGroup(const std::string& group_name);
+ void RemoveGroup(const std::string& group_name);
+ void RemoveGroup(GroupMap::iterator it);
// Called when the number of idle sockets changes.
void IncrementIdleCount();
@@ -373,15 +394,17 @@ class ClientSocketPoolBaseHelper
Group* group,
const BoundNetLog& net_log);
- // Adds |socket| to the list of idle sockets for |group|. |used| indicates
- // whether or not the socket has previously been used.
- void AddIdleSocket(ClientSocket* socket, bool used, Group* group);
+ // Adds |socket| to the list of idle sockets for |group|.
+ void AddIdleSocket(ClientSocket* socket, Group* group);
- // Iterates through |connect_job_map_|, canceling all ConnectJobs.
- // Afterwards, it iterates through all groups and deletes them if they are no
- // longer needed.
+ // Iterates through |group_map_|, canceling all ConnectJobs and deleting
+ // groups if they are no longer needed.
void CancelAllConnectJobs();
+ // Iterates through |group_map_|, posting ERR_ABORTED callbacks for all
+ // requests, and then deleting groups if they are no longer needed.
+ void AbortAllRequests();
+
// Returns true if we can't create any more sockets due to the total limit.
bool ReachedMaxSocketsLimit() const;
@@ -393,17 +416,11 @@ class ClientSocketPoolBaseHelper
// Assigns an idle socket for the group to the request.
// Returns |true| if an idle socket is available, false otherwise.
- bool AssignIdleSocketToGroup(Group* group, const Request* request);
+ bool AssignIdleSocketToGroup(const Request* request, Group* group);
static void LogBoundConnectJobToRequest(
const NetLog::Source& connect_job_source, const Request* request);
- // Set a timer to create a backup socket if it takes too long to create one.
- void StartBackupSocketTimer(const std::string& group_name);
-
- // Called when the backup socket timer fires.
- void OnBackupSocketTimerFired(const std::string& group_name);
-
// Closes one idle socket. Picks the first one encountered.
// TODO(willchan): Consider a better algorithm for doing this. Perhaps we
// should keep an ordered list of idle sockets, and close them in order.
@@ -460,15 +477,16 @@ class ClientSocketPoolBaseHelper
const scoped_ptr<ConnectJobFactory> connect_job_factory_;
// TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool
- bool backup_jobs_enabled_;
-
- // A factory to pin the backup_job tasks.
- ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_;
+ bool connect_backup_jobs_enabled_;
// A unique id for the pool. It gets incremented every time we Flush() the
// pool. This is so that when sockets get released back to the pool, we can
// make sure that they are discarded rather than reused.
int pool_generation_number_;
+
+ ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBaseHelper);
};
} // namespace internal
@@ -487,7 +505,7 @@ class ClientSocketPoolBase {
const scoped_refptr<SocketParams>& params,
const BoundNetLog& net_log)
: internal::ClientSocketPoolBaseHelper::Request(
- handle, callback, priority, net_log),
+ handle, callback, priority, net_log),
params_(params) {}
const scoped_refptr<SocketParams>& params() const { return params_; }
@@ -521,15 +539,14 @@ class ClientSocketPoolBase {
ClientSocketPoolBase(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
base::TimeDelta unused_idle_socket_timeout,
base::TimeDelta used_idle_socket_timeout,
ConnectJobFactory* connect_job_factory)
: histograms_(histograms),
- helper_(new internal::ClientSocketPoolBaseHelper(
- max_sockets, max_sockets_per_group,
- unused_idle_socket_timeout, used_idle_socket_timeout,
- new ConnectJobFactoryAdaptor(connect_job_factory))) {}
+ helper_(max_sockets, max_sockets_per_group,
+ unused_idle_socket_timeout, used_idle_socket_timeout,
+ new ConnectJobFactoryAdaptor(connect_job_factory)) {}
virtual ~ClientSocketPoolBase() {}
@@ -545,55 +562,64 @@ class ClientSocketPoolBase {
CompletionCallback* callback,
const BoundNetLog& net_log) {
Request* request = new Request(handle, callback, priority, params, net_log);
- return helper_->RequestSocket(group_name, request);
+ return helper_.RequestSocket(group_name, request);
}
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) {
- return helper_->CancelRequest(group_name, handle);
+ return helper_.CancelRequest(group_name, handle);
}
void ReleaseSocket(const std::string& group_name, ClientSocket* socket,
int id) {
- return helper_->ReleaseSocket(group_name, socket, id);
+ return helper_.ReleaseSocket(group_name, socket, id);
}
- void CloseIdleSockets() { return helper_->CloseIdleSockets(); }
+ void CloseIdleSockets() { return helper_.CloseIdleSockets(); }
- int idle_socket_count() const { return helper_->idle_socket_count(); }
+ int idle_socket_count() const { return helper_.idle_socket_count(); }
int IdleSocketCountInGroup(const std::string& group_name) const {
- return helper_->IdleSocketCountInGroup(group_name);
+ return helper_.IdleSocketCountInGroup(group_name);
}
LoadState GetLoadState(const std::string& group_name,
const ClientSocketHandle* handle) const {
- return helper_->GetLoadState(group_name, handle);
+ return helper_.GetLoadState(group_name, handle);
}
virtual void OnConnectJobComplete(int result, ConnectJob* job) {
- return helper_->OnConnectJobComplete(result, job);
+ return helper_.OnConnectJobComplete(result, job);
}
int NumConnectJobsInGroup(const std::string& group_name) const {
- return helper_->NumConnectJobsInGroup(group_name);
+ return helper_.NumConnectJobsInGroup(group_name);
+ }
+
+ bool HasGroup(const std::string& group_name) const {
+ return helper_.HasGroup(group_name);
}
void CleanupIdleSockets(bool force) {
- return helper_->CleanupIdleSockets(force);
+ return helper_.CleanupIdleSockets(force);
+ }
+
+ DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type) const {
+ return helper_.GetInfoAsValue(name, type);
}
base::TimeDelta ConnectionTimeout() const {
- return helper_->ConnectionTimeout();
+ return helper_.ConnectionTimeout();
}
- scoped_refptr<ClientSocketPoolHistograms> histograms() const {
+ ClientSocketPoolHistograms* histograms() const {
return histograms_;
}
- void EnableBackupJobs() { helper_->EnableBackupJobs(); }
+ void EnableConnectBackupJobs() { helper_.EnableConnectBackupJobs(); }
- void Flush() { helper_->Flush(); }
+ void Flush() { helper_.Flush(); }
private:
// This adaptor class exists to bridge the
@@ -607,8 +633,7 @@ class ClientSocketPoolBase {
typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
ConnectJobFactory;
- explicit ConnectJobFactoryAdaptor(
- ConnectJobFactory* connect_job_factory)
+ explicit ConnectJobFactoryAdaptor(ConnectJobFactory* connect_job_factory)
: connect_job_factory_(connect_job_factory) {}
virtual ~ConnectJobFactoryAdaptor() {}
@@ -629,13 +654,8 @@ class ClientSocketPoolBase {
};
// Histograms for the pool
- const scoped_refptr<ClientSocketPoolHistograms> histograms_;
-
- // The reason for reference counting here is because the operations on
- // the ClientSocketPoolBaseHelper which release sockets can cause the
- // ClientSocketPoolBase<T> reference to drop to zero. While we're deep
- // in cleanup code, we'll often hold a reference to |self|.
- scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_;
+ ClientSocketPoolHistograms* const histograms_;
+ internal::ClientSocketPoolBaseHelper helper_;
DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
};
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 55f1949..1624a46 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -10,12 +10,14 @@
#include "base/platform_thread.h"
#include "base/ref_counted.h"
#include "base/scoped_vector.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
-#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/base/test_completion_callback.h"
+#include "net/http/http_response_headers.h"
#include "net/socket/client_socket.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_handle.h"
@@ -40,7 +42,7 @@ typedef ClientSocketPoolBase<TestSocketParams> TestClientSocketPoolBase;
class MockClientSocket : public ClientSocket {
public:
- MockClientSocket() : connected_(false) {}
+ MockClientSocket() : connected_(false), was_used_to_convey_data_(false) {}
// Socket methods:
virtual int Read(
@@ -49,8 +51,9 @@ class MockClientSocket : public ClientSocket {
}
virtual int Write(
- IOBuffer* /* buf */, int /* len */, CompletionCallback* /* callback */) {
- return ERR_UNEXPECTED;
+ IOBuffer* /* buf */, int len, CompletionCallback* /* callback */) {
+ was_used_to_convey_data_ = true;
+ return len;
}
virtual bool SetReceiveBufferSize(int32 size) { return true; }
virtual bool SetSendBufferSize(int32 size) { return true; }
@@ -74,9 +77,14 @@ class MockClientSocket : public ClientSocket {
return net_log_;
}
+ virtual void SetSubresourceSpeculation() {}
+ virtual void SetOmniboxSpeculation() {}
+ virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
+
private:
bool connected_;
BoundNetLog net_log_;
+ bool was_used_to_convey_data_;
DISALLOW_COPY_AND_ASSIGN(MockClientSocket);
};
@@ -87,8 +95,10 @@ class MockClientSocketFactory : public ClientSocketFactory {
public:
MockClientSocketFactory() : allocation_count_(0) {}
- virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses,
- NetLog* /* net_log */) {
+ virtual ClientSocket* CreateTCPClientSocket(
+ const AddressList& addresses,
+ NetLog* /* net_log */,
+ const NetLog::Source& /*source*/) {
allocation_count_++;
return NULL;
}
@@ -166,7 +176,8 @@ class TestConnectJob : public ConnectJob {
virtual int ConnectInternal() {
AddressList ignored;
- client_socket_factory_->CreateTCPClientSocket(ignored, NULL);
+ client_socket_factory_->CreateTCPClientSocket(
+ ignored, NULL, net::NetLog::Source());
set_socket(new MockClientSocket());
switch (job_type_) {
case kMockJob:
@@ -348,7 +359,7 @@ class TestClientSocketPool : public ClientSocketPool {
TestClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
base::TimeDelta unused_idle_socket_timeout,
base::TimeDelta used_idle_socket_timeout,
TestClientSocketPoolBase::ConnectJobFactory* connect_job_factory)
@@ -356,6 +367,8 @@ class TestClientSocketPool : public ClientSocketPool {
unused_idle_socket_timeout, used_idle_socket_timeout,
connect_job_factory) {}
+ virtual ~TestClientSocketPool() {}
+
virtual int RequestSocket(
const std::string& group_name,
const void* params,
@@ -401,11 +414,17 @@ class TestClientSocketPool : public ClientSocketPool {
return base_.GetLoadState(group_name, handle);
}
+ virtual DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const {
+ return base_.GetInfoAsValue(name, type);
+ }
+
virtual base::TimeDelta ConnectionTimeout() const {
return base_.ConnectionTimeout();
}
- virtual scoped_refptr<ClientSocketPoolHistograms> histograms() const {
+ virtual ClientSocketPoolHistograms* histograms() const {
return base_.histograms();
}
@@ -415,13 +434,15 @@ class TestClientSocketPool : public ClientSocketPool {
return base_.NumConnectJobsInGroup(group_name);
}
+ bool HasGroup(const std::string& group_name) const {
+ return base_.HasGroup(group_name);
+ }
+
void CleanupTimedOutIdleSockets() { base_.CleanupIdleSockets(false); }
- void EnableBackupJobs() { base_.EnableBackupJobs(); }
+ void EnableConnectBackupJobs() { base_.EnableConnectBackupJobs(); }
private:
- ~TestClientSocketPool() {}
-
TestClientSocketPoolBase base_;
DISALLOW_COPY_AND_ASSIGN(TestClientSocketPool);
@@ -475,11 +496,13 @@ class TestConnectJobDelegate : public ConnectJob::Delegate {
int result_;
};
-class ClientSocketPoolBaseTest : public ClientSocketPoolTest {
+class ClientSocketPoolBaseTest : public testing::Test {
protected:
ClientSocketPoolBaseTest()
: params_(new TestSocketParams()),
- histograms_(new ClientSocketPoolHistograms("ClientSocketPoolTest")) {}
+ histograms_("ClientSocketPoolTest") {}
+
+ virtual ~ClientSocketPoolBaseTest() {}
void CreatePool(int max_sockets, int max_sockets_per_group) {
CreatePoolWithIdleTimeouts(
@@ -496,45 +519,44 @@ class ClientSocketPoolBaseTest : public ClientSocketPoolTest {
base::TimeDelta used_idle_socket_timeout) {
DCHECK(!pool_.get());
connect_job_factory_ = new TestConnectJobFactory(&client_socket_factory_);
- pool_ = new TestClientSocketPool(max_sockets,
- max_sockets_per_group,
- histograms_,
- unused_idle_socket_timeout,
- used_idle_socket_timeout,
- connect_job_factory_);
+ pool_.reset(new TestClientSocketPool(max_sockets,
+ max_sockets_per_group,
+ &histograms_,
+ unused_idle_socket_timeout,
+ used_idle_socket_timeout,
+ connect_job_factory_));
}
int StartRequest(const std::string& group_name,
net::RequestPriority priority) {
- return StartRequestUsingPool<TestClientSocketPool, TestSocketParams>(
- pool_, group_name, priority, params_);
+ return test_base_.StartRequestUsingPool<
+ TestClientSocketPool, TestSocketParams>(
+ pool_.get(), group_name, priority, params_);
+ }
+
+ int GetOrderOfRequest(size_t index) const {
+ return test_base_.GetOrderOfRequest(index);
+ }
+
+ bool ReleaseOneConnection(ClientSocketPoolTest::KeepAlive keep_alive) {
+ return test_base_.ReleaseOneConnection(keep_alive);
}
- virtual void TearDown() {
- // We post all of our delayed tasks with a 2ms delay. I.e. they don't
- // actually become pending until 2ms after they have been created. In order
- // to flush all tasks, we need to wait so that we know there are no
- // soon-to-be-pending tasks waiting.
- PlatformThread::Sleep(10);
- MessageLoop::current()->RunAllPending();
-
- // Need to delete |pool_| before we turn late binding back off. We also need
- // to delete |requests_| because the pool is reference counted and requests
- // keep reference to it.
- // TODO(willchan): Remove this part when late binding becomes the default.
- TestClientSocketPool* pool = pool_.get();
- pool_ = NULL;
- requests_.reset();
- pool = NULL;
-
- ClientSocketPoolTest::TearDown();
+ void ReleaseAllConnections(ClientSocketPoolTest::KeepAlive keep_alive) {
+ test_base_.ReleaseAllConnections(keep_alive);
}
+ TestSocketRequest* request(int i) { return test_base_.request(i); }
+ size_t requests_size() const { return test_base_.requests_size(); }
+ ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
+ size_t completion_count() const { return test_base_.completion_count(); }
+
MockClientSocketFactory client_socket_factory_;
TestConnectJobFactory* connect_job_factory_;
scoped_refptr<TestSocketParams> params_;
- scoped_refptr<TestClientSocketPool> pool_;
- scoped_refptr<ClientSocketPoolHistograms> histograms_;
+ ClientSocketPoolHistograms histograms_;
+ scoped_ptr<TestClientSocketPool> pool_;
+ ClientSocketPoolTest test_base_;
};
// Even though a timeout is specified, it doesn't time out on a synchronous
@@ -599,8 +621,13 @@ TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
ClientSocketHandle handle;
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
- EXPECT_EQ(OK, handle.Init("a", params_, kDefaultPriority, &callback, pool_,
- log.bound()));
+ EXPECT_EQ(OK,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ log.bound()));
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
handle.Reset();
@@ -624,18 +651,23 @@ TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
- TestSocketRequest req(&request_order_, &completion_count_);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
// Set the additional error state members to ensure that they get cleared.
- req.handle()->set_is_ssl_error(true);
+ handle.set_is_ssl_error(true);
HttpResponseInfo info;
info.headers = new HttpResponseHeaders("");
- req.handle()->set_ssl_error_response_info(info);
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.handle()->Init("a", params_,
- kDefaultPriority, &req,
- pool_, log.bound()));
- EXPECT_FALSE(req.handle()->socket());
- EXPECT_FALSE(req.handle()->is_ssl_error());
- EXPECT_TRUE(req.handle()->ssl_error_response_info().headers.get() == NULL);
+ handle.set_ssl_error_response_info(info);
+ EXPECT_EQ(ERR_CONNECTION_FAILED,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ log.bound()));
+ EXPECT_FALSE(handle.socket());
+ EXPECT_FALSE(handle.is_ssl_error());
+ EXPECT_TRUE(handle.ssl_error_response_info().headers.get() == NULL);
EXPECT_EQ(3u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
@@ -657,19 +689,19 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimit) {
EXPECT_EQ(OK, StartRequest("c", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("d", kDefaultPriority));
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSockets, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", kDefaultPriority));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("f", kDefaultPriority));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("g", kDefaultPriority));
- ReleaseAllConnections(NO_KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSockets, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
@@ -680,7 +712,7 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimit) {
EXPECT_EQ(7, GetOrderOfRequest(7));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(8));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(8));
}
TEST_F(ClientSocketPoolBaseTest, TotalLimitReachedNewGroup) {
@@ -694,18 +726,18 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitReachedNewGroup) {
EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSockets, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
// Now create a new group and verify that we don't starve it.
EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kDefaultPriority));
- ReleaseAllConnections(NO_KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSockets, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
@@ -714,7 +746,7 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitReachedNewGroup) {
EXPECT_EQ(5, GetOrderOfRequest(5));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(6));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(6));
}
TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsPriority) {
@@ -725,16 +757,16 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsPriority) {
EXPECT_EQ(OK, StartRequest("b", HIGHEST));
EXPECT_EQ(OK, StartRequest("a", LOWEST));
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", LOWEST));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", HIGHEST));
- ReleaseAllConnections(NO_KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
- EXPECT_EQ(requests_.size() - kDefaultMaxSockets, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
// First 4 requests don't have to wait, and finish in order.
EXPECT_EQ(1, GetOrderOfRequest(1));
@@ -749,7 +781,7 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsPriority) {
EXPECT_EQ(5, GetOrderOfRequest(7));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(8));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(9));
}
TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsGroupLimit) {
@@ -760,18 +792,18 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsGroupLimit) {
EXPECT_EQ(OK, StartRequest("b", HIGHEST));
EXPECT_EQ(OK, StartRequest("b", MEDIUM));
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", MEDIUM));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", HIGHEST));
- ReleaseAllConnections(NO_KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSockets, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
// First 4 requests don't have to wait, and finish in order.
EXPECT_EQ(1, GetOrderOfRequest(1));
@@ -788,7 +820,7 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsGroupLimit) {
EXPECT_EQ(7, GetOrderOfRequest(7));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(8));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(8));
}
// Make sure that we count connecting sockets against the total limit.
@@ -814,9 +846,9 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitCountsConnectingSockets) {
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", kDefaultPriority));
- ReleaseAllConnections(NO_KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
@@ -826,7 +858,7 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitCountsConnectingSockets) {
EXPECT_EQ(5, GetOrderOfRequest(5));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(6));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(6));
}
TEST_F(ClientSocketPoolBaseTest, CorrectlyCountStalledGroups) {
@@ -847,12 +879,12 @@ TEST_F(ClientSocketPoolBaseTest, CorrectlyCountStalledGroups) {
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
- EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
EXPECT_EQ(kDefaultMaxSockets + 1, client_socket_factory_.allocation_count());
- EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
EXPECT_EQ(kDefaultMaxSockets + 2, client_socket_factory_.allocation_count());
- EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
- EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
EXPECT_EQ(kDefaultMaxSockets + 2, client_socket_factory_.allocation_count());
}
@@ -862,14 +894,24 @@ TEST_F(ClientSocketPoolBaseTest, StallAndThenCancelAndTriggerAvailableSocket) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
ClientSocketHandle handles[4];
for (size_t i = 0; i < arraysize(handles); ++i) {
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handles[i].Init("b", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handles[i].Init("b",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
}
// One will be stalled, cancel all the handles now.
@@ -887,16 +929,23 @@ TEST_F(ClientSocketPoolBaseTest, CancelStalledSocketAtSocketLimit) {
ClientSocketHandle handles[kDefaultMaxSockets];
TestCompletionCallback callbacks[kDefaultMaxSockets];
for (int i = 0; i < kDefaultMaxSockets; ++i) {
- EXPECT_EQ(OK, handles[i].Init(IntToString(i), params_, kDefaultPriority,
- &callbacks[i], pool_, BoundNetLog()));
+ EXPECT_EQ(OK, handles[i].Init(base::IntToString(i),
+ params_,
+ kDefaultPriority,
+ &callbacks[i],
+ pool_.get(),
+ BoundNetLog()));
}
// Force a stalled group.
ClientSocketHandle stalled_handle;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo", params_,
- kDefaultPriority, &callback,
- pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
// Cancel the stalled request.
stalled_handle.Reset();
@@ -919,18 +968,24 @@ TEST_F(ClientSocketPoolBaseTest, CancelPendingSocketAtSocketLimit) {
ClientSocketHandle handles[kDefaultMaxSockets];
for (int i = 0; i < kDefaultMaxSockets; ++i) {
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handles[i].Init(IntToString(i), params_,
- kDefaultPriority, &callback,
- pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handles[i].Init(base::IntToString(i),
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
}
// Force a stalled group.
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle stalled_handle;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo", params_,
- kDefaultPriority, &callback,
- pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
// Since it is stalled, it should have no connect jobs.
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("foo"));
@@ -965,8 +1020,11 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) {
ClientSocketHandle handles[kDefaultMaxSockets];
for (int i = 0; i < kDefaultMaxSockets; ++i) {
TestCompletionCallback callback;
- EXPECT_EQ(OK, handles[i].Init(StringPrintf("Take 2: %d", i), params_,
- kDefaultPriority, &callback, pool_,
+ EXPECT_EQ(OK, handles[i].Init(base::StringPrintf("Take 2: %d", i),
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
BoundNetLog()));
}
@@ -974,9 +1032,12 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) {
EXPECT_EQ(0, pool_->IdleSocketCount());
// Now we will hit the socket limit.
- EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo", params_,
- kDefaultPriority, &callback,
- pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
// Dropping out of scope will close all handles and return them to idle.
}
@@ -992,14 +1053,18 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) {
// Regression test for http://crbug.com/40952.
TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- pool_->EnableBackupJobs();
+ pool_->EnableConnectBackupJobs();
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
for (int i = 0; i < kDefaultMaxSockets; ++i) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init(IntToString(i), params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(OK, handle.Init(base::IntToString(i),
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
}
// Flush all the DoReleaseSocket tasks.
@@ -1014,7 +1079,11 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) {
// "0" is special here, since it should be the first entry in the sorted map,
// which is the one which we would close an idle socket for. We shouldn't
// close an idle socket though, since we should reuse the idle socket.
- EXPECT_EQ(OK, handle.Init("0", params_, kDefaultPriority, &callback, pool_,
+ EXPECT_EQ(OK, handle.Init("0",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
BoundNetLog()));
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
@@ -1026,28 +1095,31 @@ TEST_F(ClientSocketPoolBaseTest, PendingRequests) {
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", IDLE));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- ReleaseAllConnections(KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
EXPECT_EQ(kDefaultMaxSocketsPerGroup,
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSocketsPerGroup, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup,
+ completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(6, GetOrderOfRequest(3));
- EXPECT_EQ(4, GetOrderOfRequest(4));
- EXPECT_EQ(3, GetOrderOfRequest(5));
- EXPECT_EQ(5, GetOrderOfRequest(6));
- EXPECT_EQ(7, GetOrderOfRequest(7));
+ EXPECT_EQ(8, GetOrderOfRequest(3));
+ EXPECT_EQ(6, GetOrderOfRequest(4));
+ EXPECT_EQ(4, GetOrderOfRequest(5));
+ EXPECT_EQ(3, GetOrderOfRequest(6));
+ EXPECT_EQ(5, GetOrderOfRequest(7));
+ EXPECT_EQ(7, GetOrderOfRequest(8));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(8));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(9));
}
TEST_F(ClientSocketPoolBaseTest, PendingRequests_NoKeepAlive) {
@@ -1061,14 +1133,15 @@ TEST_F(ClientSocketPoolBaseTest, PendingRequests_NoKeepAlive) {
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- ReleaseAllConnections(NO_KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
- for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_.size(); ++i)
- EXPECT_EQ(OK, requests_[i]->WaitForResult());
+ for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_size(); ++i)
+ EXPECT_EQ(OK, request(i)->WaitForResult());
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSocketsPerGroup, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup,
+ completion_count());
}
// This test will start up a RequestSocket() and then immediately Cancel() it.
@@ -1078,10 +1151,15 @@ TEST_F(ClientSocketPoolBaseTest, CancelRequestClearGroup) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
- req.handle()->Reset();
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
+ handle.Reset();
}
TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
@@ -1090,16 +1168,24 @@ TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle;
TestCompletionCallback callback;
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
handle.Reset();
TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback2, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog()));
EXPECT_EQ(OK, callback2.WaitForResult());
EXPECT_FALSE(callback.have_result());
@@ -1120,26 +1206,27 @@ TEST_F(ClientSocketPoolBaseTest, CancelRequest) {
// Cancel a request.
size_t index_to_cancel = kDefaultMaxSocketsPerGroup + 2;
- EXPECT_FALSE(requests_[index_to_cancel]->handle()->is_initialized());
- requests_[index_to_cancel]->handle()->Reset();
+ EXPECT_FALSE((*requests())[index_to_cancel]->handle()->is_initialized());
+ (*requests())[index_to_cancel]->handle()->Reset();
- ReleaseAllConnections(KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
EXPECT_EQ(kDefaultMaxSocketsPerGroup,
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kDefaultMaxSocketsPerGroup - 1,
- completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup - 1,
+ completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
EXPECT_EQ(5, GetOrderOfRequest(3));
EXPECT_EQ(3, GetOrderOfRequest(4));
- EXPECT_EQ(kRequestNotFound, GetOrderOfRequest(5)); // Canceled request.
+ EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound,
+ GetOrderOfRequest(5)); // Canceled request.
EXPECT_EQ(4, GetOrderOfRequest(6));
EXPECT_EQ(6, GetOrderOfRequest(7));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(8));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(8));
}
class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
@@ -1173,8 +1260,12 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
within_callback_ = true;
TestCompletionCallback next_job_callback;
scoped_refptr<TestSocketParams> params = new TestSocketParams();
- int rv = handle_->Init("a", params, kDefaultPriority, &next_job_callback,
- pool_, BoundNetLog());
+ int rv = handle_->Init("a",
+ params,
+ kDefaultPriority,
+ &next_job_callback,
+ pool_,
+ BoundNetLog());
switch (next_job_type_) {
case TestConnectJob::kMockJob:
EXPECT_EQ(OK, rv);
@@ -1208,7 +1299,7 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
private:
ClientSocketHandle* const handle_;
- const scoped_refptr<TestClientSocketPool> pool_;
+ TestClientSocketPool* const pool_;
bool within_callback_;
TestConnectJobFactory* const test_connect_job_factory_;
TestConnectJob::JobType next_job_type_;
@@ -1223,7 +1314,11 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobTwice) {
RequestSocketCallback callback(
&handle, pool_.get(), connect_job_factory_,
TestConnectJob::kMockPendingJob);
- int rv = handle.Init("a", params_, kDefaultPriority, &callback, pool_,
+ int rv = handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, rv);
@@ -1237,7 +1332,11 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobThenSynchronous) {
ClientSocketHandle handle;
RequestSocketCallback callback(
&handle, pool_.get(), connect_job_factory_, TestConnectJob::kMockJob);
- int rv = handle.Init("a", params_, kDefaultPriority, &callback, pool_,
+ int rv = handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, rv);
@@ -1262,17 +1361,18 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestWithPendingRequests) {
// Now, kDefaultMaxSocketsPerGroup requests should be active.
// Let's cancel them.
for (int i = 0; i < kDefaultMaxSocketsPerGroup; ++i) {
- ASSERT_FALSE(requests_[i]->handle()->is_initialized());
- requests_[i]->handle()->Reset();
+ ASSERT_FALSE(request(i)->handle()->is_initialized());
+ request(i)->handle()->Reset();
}
// Let's wait for the rest to complete now.
- for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_.size(); ++i) {
- EXPECT_EQ(OK, requests_[i]->WaitForResult());
- requests_[i]->handle()->Reset();
+ for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_size(); ++i) {
+ EXPECT_EQ(OK, request(i)->WaitForResult());
+ request(i)->handle()->Reset();
}
- EXPECT_EQ(requests_.size() - kDefaultMaxSocketsPerGroup, completion_count_);
+ EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup,
+ completion_count());
}
// Make sure that pending requests get serviced after active requests fail.
@@ -1290,7 +1390,7 @@ TEST_F(ClientSocketPoolBaseTest, FailingActiveRequestWithPendingRequests) {
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
for (size_t i = 0; i < kNumberOfRequests; ++i)
- EXPECT_EQ(ERR_CONNECTION_FAILED, requests_[i]->WaitForResult());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, request(i)->WaitForResult());
}
TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) {
@@ -1298,21 +1398,29 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) {
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- TestSocketRequest req(&request_order_, &completion_count_);
- int rv = req.handle()->Init("a", params_, kDefaultPriority, &req, pool_,
- BoundNetLog());
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ int rv = handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
// Cancel the active request.
- req.handle()->Reset();
+ handle.Reset();
- rv = req.handle()->Init("a", params_, kDefaultPriority, &req, pool_,
- BoundNetLog());
+ rv = handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, req.WaitForResult());
+ EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_FALSE(req.handle()->is_reused());
- EXPECT_EQ(1U, completion_count_);
+ EXPECT_FALSE(handle.is_reused());
EXPECT_EQ(2, client_socket_factory_.allocation_count());
}
@@ -1341,8 +1449,8 @@ TEST_F(ClientSocketPoolBaseTest, GroupWithPendingRequestsIsNotEmpty) {
// the first release will unblock the pending request for "a". The
// second release will unblock a request for "c", becaue it is the next
// high priority socket.
- EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
- EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
// Closing idle sockets should not get us into trouble, but in the bug
// we were hitting a CHECK here.
@@ -1356,15 +1464,21 @@ TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- TestSocketRequest req(&request_order_, &completion_count_);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
- int rv = req.handle()->Init("a", params_, LOWEST, &req, pool_, log.bound());
+ int rv = handle.Init("a",
+ params_,
+ LOWEST,
+ &callback,
+ pool_.get(),
+ log.bound());
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
- EXPECT_EQ(OK, req.WaitForResult());
- EXPECT_TRUE(req.handle()->is_initialized());
- EXPECT_TRUE(req.handle()->socket());
- req.handle()->Reset();
+ EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_TRUE(handle.is_initialized());
+ EXPECT_TRUE(handle.socket());
+ handle.Reset();
EXPECT_EQ(4u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
@@ -1384,19 +1498,24 @@ TEST_F(ClientSocketPoolBaseTest,
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
- TestSocketRequest req(&request_order_, &completion_count_);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
// Set the additional error state members to ensure that they get cleared.
- req.handle()->set_is_ssl_error(true);
+ handle.set_is_ssl_error(true);
HttpResponseInfo info;
info.headers = new HttpResponseHeaders("");
- req.handle()->set_ssl_error_response_info(info);
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, log.bound()));
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
- EXPECT_FALSE(req.handle()->is_ssl_error());
- EXPECT_TRUE(req.handle()->ssl_error_response_info().headers.get() == NULL);
+ handle.set_ssl_error_response_info(info);
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ log.bound()));
+ EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
+ EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_FALSE(handle.is_ssl_error());
+ EXPECT_TRUE(handle.ssl_error_response_info().headers.get() == NULL);
EXPECT_EQ(3u, log.entries().size());
EXPECT_TRUE(LogContainsBeginEvent(
@@ -1414,22 +1533,34 @@ TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- TestSocketRequest req(&request_order_, &completion_count_);
- TestSocketRequest req2(&request_order_, &completion_count_);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
CapturingBoundNetLog log2(CapturingNetLog::kUnbounded);
- EXPECT_EQ(ERR_IO_PENDING, req2.handle()->Init("a", params_, kDefaultPriority,
- &req2, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog()));
- req.handle()->Reset();
+ handle.Reset();
// At this point, request 2 is just waiting for the connect job to finish.
- EXPECT_EQ(OK, req2.WaitForResult());
- req2.handle()->Reset();
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ handle2.Reset();
// Now request 2 has actually finished.
// TODO(eroman): Add back log expectations.
@@ -1446,14 +1577,14 @@ TEST_F(ClientSocketPoolBaseTest, CancelRequestLimitsJobs) {
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
- requests_[2]->handle()->Reset();
- requests_[3]->handle()->Reset();
+ (*requests())[2]->handle()->Reset();
+ (*requests())[3]->handle()->Reset();
EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
- requests_[1]->handle()->Reset();
+ (*requests())[1]->handle()->Reset();
EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
- requests_[0]->handle()->Reset();
+ (*requests())[0]->handle()->Reset();
EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
}
@@ -1465,8 +1596,13 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
// Start job 1 (async OK)
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- TestSocketRequest req1(&request_order_, &completion_count_);
- int rv = req1.handle()->Init("a", params_, kDefaultPriority, &req1, pool_,
+ std::vector<TestSocketRequest*> request_order;
+ size_t completion_count; // unused
+ TestSocketRequest req1(&request_order, &completion_count);
+ int rv = req1.handle()->Init("a",
+ params_,
+ kDefaultPriority,
+ &req1, pool_.get(),
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(OK, req1.WaitForResult());
@@ -1475,12 +1611,20 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
// without a job.
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- TestSocketRequest req2(&request_order_, &completion_count_);
- rv = req2.handle()->Init("a", params_, kDefaultPriority, &req2, pool_,
+ TestSocketRequest req2(&request_order, &completion_count);
+ rv = req2.handle()->Init("a",
+ params_,
+ kDefaultPriority,
+ &req2,
+ pool_.get(),
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- TestSocketRequest req3(&request_order_, &completion_count_);
- rv = req3.handle()->Init("a", params_, kDefaultPriority, &req3, pool_,
+ TestSocketRequest req3(&request_order, &completion_count);
+ rv = req3.handle()->Init("a",
+ params_,
+ kDefaultPriority,
+ &req3,
+ pool_.get(),
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1497,10 +1641,10 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
client_socket_factory_.SignalJobs();
EXPECT_EQ(OK, req3.WaitForResult());
- ASSERT_EQ(3U, request_order_.size());
- EXPECT_EQ(&req1, request_order_[0]);
- EXPECT_EQ(&req2, request_order_[1]);
- EXPECT_EQ(&req3, request_order_[2]);
+ ASSERT_EQ(3U, request_order.size());
+ EXPECT_EQ(&req1, request_order[0]);
+ EXPECT_EQ(&req2, request_order[1]);
+ EXPECT_EQ(&req3, request_order[2]);
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
}
@@ -1511,21 +1655,35 @@ TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) {
// First two jobs are async.
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
- TestSocketRequest req1(&request_order_, &completion_count_);
- int rv = req1.handle()->Init("a", params_, kDefaultPriority, &req1, pool_,
+ std::vector<TestSocketRequest*> request_order;
+ size_t completion_count; // unused
+ TestSocketRequest req1(&request_order, &completion_count);
+ int rv = req1.handle()->Init("a",
+ params_,
+ kDefaultPriority,
+ &req1,
+ pool_.get(),
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- TestSocketRequest req2(&request_order_, &completion_count_);
- rv = req2.handle()->Init("a", params_, kDefaultPriority, &req2, pool_,
+ TestSocketRequest req2(&request_order, &completion_count);
+ rv = req2.handle()->Init("a",
+ params_,
+ kDefaultPriority,
+ &req2,
+ pool_.get(),
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
// The pending job is sync.
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- TestSocketRequest req3(&request_order_, &completion_count_);
- rv = req3.handle()->Init("a", params_, kDefaultPriority, &req3, pool_,
+ TestSocketRequest req3(&request_order, &completion_count);
+ rv = req3.handle()->Init("a",
+ params_,
+ kDefaultPriority,
+ &req3,
+ pool_.get(),
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1533,10 +1691,10 @@ TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) {
EXPECT_EQ(OK, req2.WaitForResult());
EXPECT_EQ(ERR_CONNECTION_FAILED, req3.WaitForResult());
- ASSERT_EQ(3U, request_order_.size());
- EXPECT_EQ(&req1, request_order_[0]);
- EXPECT_EQ(&req2, request_order_[1]);
- EXPECT_EQ(&req3, request_order_[2]);
+ ASSERT_EQ(3U, request_order.size());
+ EXPECT_EQ(&req1, request_order[0]);
+ EXPECT_EQ(&req2, request_order[1]);
+ EXPECT_EQ(&req3, request_order[2]);
}
TEST_F(ClientSocketPoolBaseTest, LoadState) {
@@ -1544,34 +1702,44 @@ TEST_F(ClientSocketPoolBaseTest, LoadState) {
connect_job_factory_->set_job_type(
TestConnectJob::kMockAdvancingLoadStateJob);
- TestSocketRequest req1(&request_order_, &completion_count_);
- int rv = req1.handle()->Init("a", params_, kDefaultPriority, &req1, pool_,
- BoundNetLog());
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ int rv = handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_IDLE, req1.handle()->GetLoadState());
+ EXPECT_EQ(LOAD_STATE_IDLE, handle.GetLoadState());
MessageLoop::current()->RunAllPending();
- TestSocketRequest req2(&request_order_, &completion_count_);
- rv = req2.handle()->Init("a", params_, kDefaultPriority, &req2, pool_,
- BoundNetLog());
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ rv = handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2, pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_NE(LOAD_STATE_IDLE, req1.handle()->GetLoadState());
- EXPECT_NE(LOAD_STATE_IDLE, req2.handle()->GetLoadState());
+ EXPECT_NE(LOAD_STATE_IDLE, handle.GetLoadState());
+ EXPECT_NE(LOAD_STATE_IDLE, handle2.GetLoadState());
}
TEST_F(ClientSocketPoolBaseTest, Recoverable) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockRecoverableJob);
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, req.handle()->Init("a", params_,
- kDefaultPriority,
- &req, pool_,
- BoundNetLog()));
- EXPECT_TRUE(req.handle()->is_initialized());
- EXPECT_TRUE(req.handle()->socket());
- req.handle()->Reset();
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback, pool_.get(),
+ BoundNetLog()));
+ EXPECT_TRUE(handle.is_initialized());
+ EXPECT_TRUE(handle.socket());
}
TEST_F(ClientSocketPoolBaseTest, AsyncRecoverable) {
@@ -1579,14 +1747,19 @@ TEST_F(ClientSocketPoolBaseTest, AsyncRecoverable) {
connect_job_factory_->set_job_type(
TestConnectJob::kMockPendingRecoverableJob);
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, req.WaitForResult());
- EXPECT_TRUE(req.handle()->is_initialized());
- EXPECT_TRUE(req.handle()->socket());
- req.handle()->Reset();
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
+ EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
+ EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult());
+ EXPECT_TRUE(handle.is_initialized());
+ EXPECT_TRUE(handle.socket());
}
TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateSynchronous) {
@@ -1594,15 +1767,19 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateSynchronous) {
connect_job_factory_->set_job_type(
TestConnectJob::kMockAdditionalErrorStateJob);
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.handle()->Init("a", params_,
- kDefaultPriority, &req,
- pool_, BoundNetLog()));
- EXPECT_FALSE(req.handle()->is_initialized());
- EXPECT_FALSE(req.handle()->socket());
- EXPECT_TRUE(req.handle()->is_ssl_error());
- EXPECT_FALSE(req.handle()->ssl_error_response_info().headers.get() == NULL);
- req.handle()->Reset();
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_CONNECTION_FAILED,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
+ EXPECT_FALSE(handle.is_initialized());
+ EXPECT_FALSE(handle.socket());
+ EXPECT_TRUE(handle.is_ssl_error());
+ EXPECT_FALSE(handle.ssl_error_response_info().headers.get() == NULL);
}
TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateAsynchronous) {
@@ -1610,16 +1787,21 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateAsynchronous) {
connect_job_factory_->set_job_type(
TestConnectJob::kMockPendingAdditionalErrorStateJob);
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
- EXPECT_FALSE(req.handle()->is_initialized());
- EXPECT_FALSE(req.handle()->socket());
- EXPECT_TRUE(req.handle()->is_ssl_error());
- EXPECT_FALSE(req.handle()->ssl_error_response_info().headers.get() == NULL);
- req.handle()->Reset();
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
+ EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
+ EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_FALSE(handle.is_initialized());
+ EXPECT_FALSE(handle.socket());
+ EXPECT_TRUE(handle.is_ssl_error());
+ EXPECT_FALSE(handle.ssl_error_response_info().headers.get() == NULL);
}
TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSockets) {
@@ -1632,24 +1814,38 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSockets) {
// Startup two mock pending connect jobs, which will sit in the MessageLoop.
- TestSocketRequest req(&request_order_, &completion_count_);
- int rv = req.handle()->Init("a", params_, LOWEST, &req, pool_, BoundNetLog());
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ int rv = handle.Init("a",
+ params_,
+ LOWEST,
+ &callback,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
+ EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- TestSocketRequest req2(&request_order_, &completion_count_);
- rv = req2.handle()->Init("a", params_, LOWEST, &req2, pool_, BoundNetLog());
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ rv = handle2.Init("a",
+ params_,
+ LOWEST,
+ &callback2,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req2.handle()));
+ EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle2));
// Cancel one of the requests. Wait for the other, which will get the first
// job. Release the socket. Run the loop again to make sure the second
// socket is sitting idle and the first one is released (since ReleaseSocket()
// just posts a DoReleaseSocket() task).
- req.handle()->Reset();
- EXPECT_EQ(OK, req2.WaitForResult());
- req2.handle()->Reset();
+ handle.Reset();
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ // Use the socket.
+ EXPECT_EQ(1, handle2.socket()->Write(NULL, 1, NULL));
+ handle2.Reset();
// We post all of our delayed tasks with a 2ms delay. I.e. they don't
// actually become pending until 2ms after they have been created. In order
@@ -1665,9 +1861,14 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSockets) {
pool_->CleanupTimedOutIdleSockets();
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
- rv = req.handle()->Init("a", params_, LOWEST, &req, pool_, log.bound());
+ rv = handle.Init("a",
+ params_,
+ LOWEST,
+ &callback,
+ pool_.get(),
+ log.bound());
EXPECT_EQ(OK, rv);
- EXPECT_TRUE(req.handle()->is_reused());
+ EXPECT_TRUE(handle.is_reused());
EXPECT_TRUE(LogContainsEntryWithType(
log.entries(), 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
}
@@ -1684,33 +1885,57 @@ TEST_F(ClientSocketPoolBaseTest, MultipleReleasingDisconnectedSockets) {
// Startup 4 connect jobs. Two of them will be pending.
- TestSocketRequest req(&request_order_, &completion_count_);
- int rv = req.handle()->Init("a", params_, LOWEST, &req, pool_, BoundNetLog());
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ int rv = handle.Init("a",
+ params_,
+ LOWEST,
+ &callback,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(OK, rv);
- TestSocketRequest req2(&request_order_, &completion_count_);
- rv = req2.handle()->Init("a", params_, LOWEST, &req2, pool_, BoundNetLog());
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ rv = handle2.Init("a",
+ params_,
+ LOWEST,
+ &callback2,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(OK, rv);
- TestSocketRequest req3(&request_order_, &completion_count_);
- rv = req3.handle()->Init("a", params_, LOWEST, &req3, pool_, BoundNetLog());
+ ClientSocketHandle handle3;
+ TestCompletionCallback callback3;
+ rv = handle3.Init("a",
+ params_,
+ LOWEST,
+ &callback3,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
- TestSocketRequest req4(&request_order_, &completion_count_);
- rv = req4.handle()->Init("a", params_, LOWEST, &req4, pool_, BoundNetLog());
+ ClientSocketHandle handle4;
+ TestCompletionCallback callback4;
+ rv = handle4.Init("a",
+ params_,
+ LOWEST,
+ &callback4,
+ pool_.get(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
// Release two disconnected sockets.
- req.handle()->socket()->Disconnect();
- req.handle()->Reset();
- req2.handle()->socket()->Disconnect();
- req2.handle()->Reset();
+ handle.socket()->Disconnect();
+ handle.Reset();
+ handle2.socket()->Disconnect();
+ handle2.Reset();
- EXPECT_EQ(OK, req3.WaitForResult());
- EXPECT_FALSE(req3.handle()->is_reused());
- EXPECT_EQ(OK, req4.WaitForResult());
- EXPECT_FALSE(req4.handle()->is_reused());
+ EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_FALSE(handle3.is_reused());
+ EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_FALSE(handle4.is_reused());
}
// Regression test for http://crbug.com/42267.
@@ -1726,29 +1951,43 @@ TEST_F(ClientSocketPoolBaseTest, SocketLimitReleasingSockets) {
// Max out the socket limit with 2 per group.
- scoped_ptr<TestSocketRequest> req_a[4];
- scoped_ptr<TestSocketRequest> req_b[4];
+ ClientSocketHandle handle_a[4];
+ TestCompletionCallback callback_a[4];
+ ClientSocketHandle handle_b[4];
+ TestCompletionCallback callback_b[4];
for (int i = 0; i < 2; ++i) {
- req_a[i].reset(new TestSocketRequest(&request_order_, &completion_count_));
- req_b[i].reset(new TestSocketRequest(&request_order_, &completion_count_));
- EXPECT_EQ(OK, req_a[i]->handle()->Init("a", params_, LOWEST, req_a[i].get(),
- pool_, BoundNetLog()));
- EXPECT_EQ(OK, req_b[i]->handle()->Init("b", params_, LOWEST, req_b[i].get(),
- pool_, BoundNetLog()));
+ EXPECT_EQ(OK, handle_a[i].Init("a",
+ params_,
+ LOWEST,
+ &callback_a[i],
+ pool_.get(),
+ BoundNetLog()));
+ EXPECT_EQ(OK, handle_b[i].Init("b",
+ params_,
+ LOWEST,
+ &callback_b[i],
+ pool_.get(),
+ BoundNetLog()));
}
// Make 4 pending requests, 2 per group.
for (int i = 2; i < 4; ++i) {
- req_a[i].reset(new TestSocketRequest(&request_order_, &completion_count_));
- req_b[i].reset(new TestSocketRequest(&request_order_, &completion_count_));
- EXPECT_EQ(ERR_IO_PENDING, req_a[i]->handle()->Init("a", params_, LOWEST,
- req_a[i].get(), pool_,
- BoundNetLog()));
- EXPECT_EQ(ERR_IO_PENDING, req_b[i]->handle()->Init("b", params_, LOWEST,
- req_b[i].get(), pool_,
- BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle_a[i].Init("a",
+ params_,
+ LOWEST,
+ &callback_a[i],
+ pool_.get(),
+ BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle_b[i].Init("b",
+ params_,
+ LOWEST,
+ &callback_b[i],
+ pool_.get(),
+ BoundNetLog()));
}
// Release b's socket first. The order is important, because in
@@ -1756,22 +1995,22 @@ TEST_F(ClientSocketPoolBaseTest, SocketLimitReleasingSockets) {
// a are stalled, but 'a' is lower lexicographically, we'll process group 'a'
// first, which has a releasing socket, so it refuses to start up another
// ConnectJob. So, we used to infinite loop on this.
- req_b[0]->handle()->socket()->Disconnect();
- req_b[0]->handle()->Reset();
- req_a[0]->handle()->socket()->Disconnect();
- req_a[0]->handle()->Reset();
+ handle_b[0].socket()->Disconnect();
+ handle_b[0].Reset();
+ handle_a[0].socket()->Disconnect();
+ handle_a[0].Reset();
// Used to get stuck here.
MessageLoop::current()->RunAllPending();
- req_b[1]->handle()->socket()->Disconnect();
- req_b[1]->handle()->Reset();
- req_a[1]->handle()->socket()->Disconnect();
- req_a[1]->handle()->Reset();
+ handle_b[1].socket()->Disconnect();
+ handle_b[1].Reset();
+ handle_a[1].socket()->Disconnect();
+ handle_a[1].Reset();
for (int i = 2; i < 4; ++i) {
- EXPECT_EQ(OK, req_b[i]->WaitForResult());
- EXPECT_EQ(OK, req_a[i]->WaitForResult());
+ EXPECT_EQ(OK, callback_b[i].WaitForResult());
+ EXPECT_EQ(OK, callback_a[i].WaitForResult());
}
}
@@ -1786,17 +2025,17 @@ TEST_F(ClientSocketPoolBaseTest,
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
- EXPECT_EQ(OK, requests_[1]->WaitForResult());
- EXPECT_EQ(2u, completion_count_);
+ EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[1]->WaitForResult());
+ EXPECT_EQ(2u, completion_count());
// Releases one connection.
- EXPECT_TRUE(ReleaseOneConnection(NO_KEEP_ALIVE));
- EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE));
+ EXPECT_EQ(OK, (*requests())[2]->WaitForResult());
- EXPECT_TRUE(ReleaseOneConnection(NO_KEEP_ALIVE));
- EXPECT_EQ(OK, requests_[3]->WaitForResult());
- EXPECT_EQ(4u, completion_count_);
+ EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE));
+ EXPECT_EQ(OK, (*requests())[3]->WaitForResult());
+ EXPECT_EQ(4u, completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
@@ -1804,12 +2043,13 @@ TEST_F(ClientSocketPoolBaseTest,
EXPECT_EQ(4, GetOrderOfRequest(4));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(5));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(5));
}
class TestReleasingSocketRequest : public CallbackRunner< Tuple1<int> > {
public:
- TestReleasingSocketRequest(TestClientSocketPool* pool, int expected_result,
+ TestReleasingSocketRequest(TestClientSocketPool* pool,
+ int expected_result,
bool reset_releasing_handle)
: pool_(pool),
expected_result_(expected_result),
@@ -1826,13 +2066,16 @@ class TestReleasingSocketRequest : public CallbackRunner< Tuple1<int> > {
if (reset_releasing_handle_)
handle_.Reset();
scoped_refptr<TestSocketParams> con_params = new TestSocketParams();
- EXPECT_EQ(expected_result_, handle2_.Init("a", con_params, kDefaultPriority,
- &callback2_, pool_,
+ EXPECT_EQ(expected_result_, handle2_.Init("a",
+ con_params,
+ kDefaultPriority,
+ &callback2_,
+ pool_,
BoundNetLog()));
}
private:
- scoped_refptr<TestClientSocketPool> pool_;
+ TestClientSocketPool* const pool_;
int expected_result_;
bool reset_releasing_handle_;
ClientSocketHandle handle_;
@@ -1849,14 +2092,19 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorSocketsDontUseSlot) {
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
connect_job_factory_->set_job_type(
TestConnectJob::kMockPendingAdditionalErrorStateJob);
TestReleasingSocketRequest req(pool_.get(), OK, false);
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ req.handle()->Init("a",
+ params_,
+ kDefaultPriority,
+ &req,
+ pool_.get(),
+ BoundNetLog()));
// The next job should complete synchronously
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
@@ -1881,11 +2129,14 @@ TEST_F(ClientSocketPoolBaseTest, CallbackThatReleasesPool) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
- // Simulate flushing the pool.
- pool_ = NULL;
+ pool_->Flush();
// We'll call back into this now.
callback.WaitForResult();
@@ -1897,8 +2148,12 @@ TEST_F(ClientSocketPoolBaseTest, DoNotReuseSocketAfterFlush) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
EXPECT_EQ(OK, callback.WaitForResult());
EXPECT_EQ(ClientSocketHandle::UNUSED, handle.reuse_type());
@@ -1907,34 +2162,107 @@ TEST_F(ClientSocketPoolBaseTest, DoNotReuseSocketAfterFlush) {
handle.Reset();
MessageLoop::current()->RunAllPending();
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
EXPECT_EQ(OK, callback.WaitForResult());
EXPECT_EQ(ClientSocketHandle::UNUSED, handle.reuse_type());
}
+class ConnectWithinCallback : public CallbackRunner< Tuple1<int> > {
+ public:
+ ConnectWithinCallback(
+ const std::string& group_name,
+ const scoped_refptr<TestSocketParams>& params,
+ TestClientSocketPool* pool)
+ : group_name_(group_name), params_(params), pool_(pool) {}
+
+ ~ConnectWithinCallback() {}
+
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ callback_.RunWithParams(params);
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle_.Init(group_name_,
+ params_,
+ kDefaultPriority,
+ &nested_callback_,
+ pool_,
+ BoundNetLog()));
+ }
+
+ int WaitForResult() {
+ return callback_.WaitForResult();
+ }
+
+ int WaitForNestedResult() {
+ return nested_callback_.WaitForResult();
+ }
+
+ private:
+ const std::string group_name_;
+ const scoped_refptr<TestSocketParams> params_;
+ TestClientSocketPool* const pool_;
+ ClientSocketHandle handle_;
+ TestCompletionCallback callback_;
+ TestCompletionCallback nested_callback_;
+};
+
+TEST_F(ClientSocketPoolBaseTest, AbortAllRequestsOnFlush) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+
+ // First job will be waiting until it gets aborted.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
+
+ ClientSocketHandle handle;
+ ConnectWithinCallback callback("a", params_, pool_.get());
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
+
+ // Second job will be started during the first callback, and will
+ // asynchronously complete with OK.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+ pool_->Flush();
+ EXPECT_EQ(ERR_ABORTED, callback.WaitForResult());
+ EXPECT_EQ(OK, callback.WaitForNestedResult());
+}
+
// Cancel a pending socket request while we're at max sockets,
// and verify that the backup socket firing doesn't cause a crash.
TEST_F(ClientSocketPoolBaseTest, BackupSocketCancelAtMaxSockets) {
// Max 4 sockets globally, max 4 sockets per group.
CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- pool_->EnableBackupJobs();
+ pool_->EnableConnectBackupJobs();
- // Create the first socket and set to ERR_IO_PENDING. This creates a
- // backup job.
+ // Create the first socket and set to ERR_IO_PENDING. This starts the backup
+ // timer.
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
// Start (MaxSockets - 1) connected sockets to reach max sockets.
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
ClientSocketHandle handles[kDefaultMaxSockets];
for (int i = 1; i < kDefaultMaxSockets; ++i) {
TestCompletionCallback callback;
- EXPECT_EQ(OK, handles[i].Init("bar", params_, kDefaultPriority, &callback,
- pool_, BoundNetLog()));
+ EXPECT_EQ(OK, handles[i].Init("bar",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
}
MessageLoop::current()->RunAllPending();
@@ -1949,6 +2277,70 @@ TEST_F(ClientSocketPoolBaseTest, BackupSocketCancelAtMaxSockets) {
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
}
+TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterCancelingAllRequests) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
+ pool_->EnableConnectBackupJobs();
+
+ // Create the first socket and set to ERR_IO_PENDING. This starts the backup
+ // timer.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
+ ASSERT_TRUE(pool_->HasGroup("bar"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("bar"));
+
+ // Cancel the socket request. This should cancel the backup timer. Wait for
+ // the backup time to see if it indeed got canceled.
+ handle.Reset();
+ // Wait for the backup timer to fire (add some slop to ensure it fires)
+ PlatformThread::Sleep(ClientSocketPool::kMaxConnectRetryIntervalMs / 2 * 3);
+ MessageLoop::current()->RunAllPending();
+ ASSERT_TRUE(pool_->HasGroup("bar"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("bar"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterFinishingAllRequests) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
+ pool_->EnableConnectBackupJobs();
+
+ // Create the first socket and set to ERR_IO_PENDING. This starts the backup
+ // timer.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ EXPECT_EQ(ERR_IO_PENDING, handle2.Init("bar",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog()));
+ ASSERT_TRUE(pool_->HasGroup("bar"));
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("bar"));
+
+ // Cancel request 1 and then complete request 2. With the requests finished,
+ // the backup timer should be cancelled.
+ handle.Reset();
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ // Wait for the backup timer to fire (add some slop to ensure it fires)
+ PlatformThread::Sleep(ClientSocketPool::kMaxConnectRetryIntervalMs / 2 * 3);
+ MessageLoop::current()->RunAllPending();
+}
+
// Test delayed socket binding for the case where we have two connects,
// and while one is waiting on a connect, the other frees up.
// The socket waiting on a connect should switch immediately to the freed
@@ -1959,8 +2351,13 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) {
ClientSocketHandle handle1;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
EXPECT_EQ(OK, callback.WaitForResult());
// No idle sockets, no pending jobs.
@@ -1970,8 +2367,13 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) {
// Create a second socket to the same host, but this one will wait.
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
ClientSocketHandle handle2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
// No idle sockets, and one connecting job.
EXPECT_EQ(0, pool_->IdleSocketCount());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2007,8 +2409,13 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
ClientSocketHandle handle1;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
EXPECT_EQ(OK, callback.WaitForResult());
// No idle sockets, no pending jobs.
@@ -2018,8 +2425,13 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
// Create a second socket to the same host, but this one will wait.
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
ClientSocketHandle handle2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
// No idle sockets, and one connecting job.
EXPECT_EQ(0, pool_->IdleSocketCount());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2049,7 +2461,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
// Test out the case where we have one socket connected, one
// connecting, when the first socket finishes and goes idle.
-// Although the second connection is pending, th second request
+// Although the second connection is pending, the second request
// should complete, by taking the first socket's idle socket.
TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
@@ -2057,8 +2469,13 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
ClientSocketHandle handle1;
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
EXPECT_EQ(OK, callback.WaitForResult());
// No idle sockets, no pending jobs.
@@ -2068,8 +2485,13 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
// Create a second socket to the same host, but this one will wait.
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
ClientSocketHandle handle2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback,
+ pool_.get(),
+ BoundNetLog()));
// No idle sockets, and one connecting job.
EXPECT_EQ(0, pool_->IdleSocketCount());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2097,6 +2519,50 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
MessageLoop::current()->RunAllPending();
}
+// Cover the case where on an available socket slot, we have one pending
+// request that completes synchronously, thereby making the Group empty.
+TEST_F(ClientSocketPoolBaseTest, SynchronouslyProcessOnePendingRequest) {
+ const int kUnlimitedSockets = 100;
+ const int kOneSocketPerGroup = 1;
+ CreatePool(kUnlimitedSockets, kOneSocketPerGroup);
+
+ // Make the first request asynchronous fail.
+ // This will free up a socket slot later.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+
+ // Make the second request synchronously fail. This should make the Group
+ // empty.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ // It'll be ERR_IO_PENDING now, but the TestConnectJob will synchronously fail
+ // when created.
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog()));
+
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+
+ EXPECT_EQ(ERR_CONNECTION_FAILED, callback1.WaitForResult());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, callback2.WaitForResult());
+ EXPECT_FALSE(pool_->HasGroup("a"));
+}
+
} // namespace
} // namespace net
diff --git a/net/socket/client_socket_pool_histograms.cc b/net/socket/client_socket_pool_histograms.cc
index e86543d..873bd5b 100644
--- a/net/socket/client_socket_pool_histograms.cc
+++ b/net/socket/client_socket_pool_histograms.cc
@@ -6,13 +6,16 @@
#include <string>
+#include "base/field_trial.h"
#include "base/histogram.h"
#include "net/socket/client_socket_handle.h"
namespace net {
ClientSocketPoolHistograms::ClientSocketPoolHistograms(
- const std::string& pool_name) {
+ const std::string& pool_name)
+ : is_http_proxy_connection_(false),
+ is_socks_connection_(false) {
// UMA_HISTOGRAM_ENUMERATION
socket_type_ = LinearHistogram::FactoryGet("Net.SocketType_" + pool_name, 1,
ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1,
@@ -35,6 +38,14 @@ ClientSocketPoolHistograms::ClientSocketPoolHistograms(
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMinutes(6),
100, Histogram::kUmaTargetedHistogramFlag);
+
+ if (pool_name == "HTTPProxy")
+ is_http_proxy_connection_ = true;
+ else if (pool_name == "SOCK")
+ is_socks_connection_ = true;
+}
+
+ClientSocketPoolHistograms::~ClientSocketPoolHistograms() {
}
void ClientSocketPoolHistograms::AddSocketType(int type) const {
@@ -43,6 +54,26 @@ void ClientSocketPoolHistograms::AddSocketType(int type) const {
void ClientSocketPoolHistograms::AddRequestTime(base::TimeDelta time) const {
request_time_->AddTime(time);
+
+ static bool proxy_connection_impact_trial_exists(
+ FieldTrialList::Find("ProxyConnectionImpact") &&
+ !FieldTrialList::Find("ProxyConnectionImpact")->group_name().empty());
+ if (proxy_connection_impact_trial_exists && is_http_proxy_connection_) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ FieldTrial::MakeName("Net.HttpProxySocketRequestTime",
+ "ProxyConnectionImpact"),
+ time,
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
+ 100);
+ }
+ if (proxy_connection_impact_trial_exists && is_socks_connection_) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ FieldTrial::MakeName("Net.SocksSocketRequestTime",
+ "ProxyConnectionImpact"),
+ time,
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
+ 100);
+ }
}
void ClientSocketPoolHistograms::AddUnusedIdleTime(base::TimeDelta time) const {
diff --git a/net/socket/client_socket_pool_histograms.h b/net/socket/client_socket_pool_histograms.h
index 1aea112..74be341 100644
--- a/net/socket/client_socket_pool_histograms.h
+++ b/net/socket/client_socket_pool_histograms.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_HISTOGRAMS_H_
#define NET_SOCKET_CLIENT_SOCKET_POOL_HISTOGRAMS_H_
+#pragma once
#include <string>
@@ -12,10 +13,10 @@
namespace net {
-class ClientSocketPoolHistograms
- : public base::RefCounted<ClientSocketPoolHistograms> {
+class ClientSocketPoolHistograms {
public:
ClientSocketPoolHistograms(const std::string& pool_name);
+ ~ClientSocketPoolHistograms();
void AddSocketType(int socket_reuse_type) const;
void AddRequestTime(base::TimeDelta time) const;
@@ -23,13 +24,15 @@ class ClientSocketPoolHistograms
void AddReusedIdleTime(base::TimeDelta time) const;
private:
- friend class base::RefCounted<ClientSocketPoolHistograms>;
- ~ClientSocketPoolHistograms() {}
-
scoped_refptr<Histogram> socket_type_;
scoped_refptr<Histogram> request_time_;
scoped_refptr<Histogram> unused_idle_time_;
scoped_refptr<Histogram> reused_idle_time_;
+
+ bool is_http_proxy_connection_;
+ bool is_socks_connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolHistograms);
};
} // namespace net
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
new file mode 100644
index 0000000..423f8b2
--- /dev/null
+++ b/net/socket/client_socket_pool_manager.cc
@@ -0,0 +1,327 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ClientSocketPoolManager manages access to all ClientSocketPools. It's a
+// simple container for all of them. Most importantly, it handles the lifetime
+// and destruction order properly.
+
+#include "net/socket/client_socket_pool_manager.h"
+
+#include "base/logging.h"
+#include "base/values.h"
+#include "net/base/ssl_config_service.h"
+#include "net/http/http_proxy_client_socket_pool.h"
+#include "net/socket/client_socket_pool_histograms.h"
+#include "net/proxy/proxy_service.h"
+#include "net/socket/socks_client_socket_pool.h"
+#include "net/socket/ssl_client_socket_pool.h"
+#include "net/socket/tcp_client_socket_pool.h"
+
+namespace net {
+
+namespace {
+
+// Total limit of sockets.
+int g_max_sockets = 256;
+
+// Default to allow up to 6 connections per host. Experiment and tuning may
+// try other values (greater than 0). Too large may cause many problems, such
+// as home routers blocking the connections!?!? See http://crbug.com/12066.
+int g_max_sockets_per_group = 6;
+
+// The max number of sockets to allow per proxy server. This applies both to
+// http and SOCKS proxies. See http://crbug.com/12066 and
+// http://crbug.com/44501 for details about proxy server connection limits.
+int g_max_sockets_per_proxy_server = 32;
+
+// Appends information about all |socket_pools| to the end of |list|.
+template <class MapType>
+static void AddSocketPoolsToList(ListValue* list,
+ const MapType& socket_pools,
+ const std::string& type,
+ bool include_nested_pools) {
+ typename MapType::const_iterator socket_pool_it = socket_pools.begin();
+ for (typename MapType::const_iterator it = socket_pools.begin();
+ it != socket_pools.end(); it++) {
+ list->Append(it->second->GetInfoAsValue(it->first.ToString(),
+ type,
+ include_nested_pools));
+ }
+}
+
+} // namespace
+
+ClientSocketPoolManager::ClientSocketPoolManager(
+ NetLog* net_log,
+ ClientSocketFactory* socket_factory,
+ HostResolver* host_resolver,
+ ProxyService* proxy_service,
+ SSLConfigService* ssl_config_service)
+ : net_log_(net_log),
+ socket_factory_(socket_factory),
+ host_resolver_(host_resolver),
+ proxy_service_(proxy_service),
+ ssl_config_service_(ssl_config_service),
+ tcp_pool_histograms_("TCP"),
+ tcp_socket_pool_(new TCPClientSocketPool(
+ g_max_sockets, g_max_sockets_per_group,
+ &tcp_pool_histograms_,
+ host_resolver,
+ socket_factory_,
+ net_log)),
+ ssl_pool_histograms_("SSL2"),
+ ssl_socket_pool_(new SSLClientSocketPool(
+ g_max_sockets, g_max_sockets_per_group,
+ &ssl_pool_histograms_,
+ host_resolver,
+ socket_factory,
+ tcp_socket_pool_.get(),
+ NULL /* no socks proxy */,
+ NULL /* no http proxy */,
+ ssl_config_service,
+ net_log)),
+ tcp_for_socks_pool_histograms_("TCPforSOCKS"),
+ socks_pool_histograms_("SOCK"),
+ tcp_for_http_proxy_pool_histograms_("TCPforHTTPProxy"),
+ tcp_for_https_proxy_pool_histograms_("TCPforHTTPSProxy"),
+ ssl_for_https_proxy_pool_histograms_("SSLforHTTPSProxy"),
+ http_proxy_pool_histograms_("HTTPProxy"),
+ ssl_socket_pool_for_proxies_histograms_("SSLForProxies") {}
+
+ClientSocketPoolManager::~ClientSocketPoolManager() {}
+
+void ClientSocketPoolManager::FlushSocketPools() {
+ // Flush the highest level pools first, since higher level pools may release
+ // stuff to the lower level pools.
+
+ for (SSLSocketPoolMap::const_iterator it =
+ ssl_socket_pools_for_proxies_.begin();
+ it != ssl_socket_pools_for_proxies_.end();
+ ++it)
+ it->second->Flush();
+
+ for (HTTPProxySocketPoolMap::const_iterator it =
+ http_proxy_socket_pools_.begin();
+ it != http_proxy_socket_pools_.end();
+ ++it)
+ it->second->Flush();
+
+ for (SSLSocketPoolMap::const_iterator it =
+ ssl_socket_pools_for_https_proxies_.begin();
+ it != ssl_socket_pools_for_https_proxies_.end();
+ ++it)
+ it->second->Flush();
+
+ for (TCPSocketPoolMap::const_iterator it =
+ tcp_socket_pools_for_https_proxies_.begin();
+ it != tcp_socket_pools_for_https_proxies_.end();
+ ++it)
+ it->second->Flush();
+
+ for (TCPSocketPoolMap::const_iterator it =
+ tcp_socket_pools_for_http_proxies_.begin();
+ it != tcp_socket_pools_for_http_proxies_.end();
+ ++it)
+ it->second->Flush();
+
+ for (SOCKSSocketPoolMap::const_iterator it =
+ socks_socket_pools_.begin();
+ it != socks_socket_pools_.end();
+ ++it)
+ it->second->Flush();
+
+ for (TCPSocketPoolMap::const_iterator it =
+ tcp_socket_pools_for_socks_proxies_.begin();
+ it != tcp_socket_pools_for_socks_proxies_.end();
+ ++it)
+ it->second->Flush();
+
+ ssl_socket_pool_->Flush();
+ tcp_socket_pool_->Flush();
+}
+
+SOCKSClientSocketPool* ClientSocketPoolManager::GetSocketPoolForSOCKSProxy(
+ const HostPortPair& socks_proxy) {
+ SOCKSSocketPoolMap::const_iterator it = socks_socket_pools_.find(socks_proxy);
+ if (it != socks_socket_pools_.end()) {
+ DCHECK(ContainsKey(tcp_socket_pools_for_socks_proxies_, socks_proxy));
+ return it->second;
+ }
+
+ DCHECK(!ContainsKey(tcp_socket_pools_for_socks_proxies_, socks_proxy));
+
+ std::pair<TCPSocketPoolMap::iterator, bool> tcp_ret =
+ tcp_socket_pools_for_socks_proxies_.insert(
+ std::make_pair(
+ socks_proxy,
+ new TCPClientSocketPool(
+ g_max_sockets_per_proxy_server, g_max_sockets_per_group,
+ &tcp_for_socks_pool_histograms_,
+ host_resolver_,
+ socket_factory_,
+ net_log_)));
+ DCHECK(tcp_ret.second);
+
+ std::pair<SOCKSSocketPoolMap::iterator, bool> ret =
+ socks_socket_pools_.insert(
+ std::make_pair(socks_proxy, new SOCKSClientSocketPool(
+ g_max_sockets_per_proxy_server, g_max_sockets_per_group,
+ &socks_pool_histograms_,
+ host_resolver_,
+ tcp_ret.first->second,
+ net_log_)));
+
+ return ret.first->second;
+}
+
+HttpProxyClientSocketPool* ClientSocketPoolManager::GetSocketPoolForHTTPProxy(
+ const HostPortPair& http_proxy) {
+ HTTPProxySocketPoolMap::const_iterator it =
+ http_proxy_socket_pools_.find(http_proxy);
+ if (it != http_proxy_socket_pools_.end()) {
+ DCHECK(ContainsKey(tcp_socket_pools_for_http_proxies_, http_proxy));
+ DCHECK(ContainsKey(tcp_socket_pools_for_https_proxies_, http_proxy));
+ DCHECK(ContainsKey(ssl_socket_pools_for_https_proxies_, http_proxy));
+ return it->second;
+ }
+
+ DCHECK(!ContainsKey(tcp_socket_pools_for_http_proxies_, http_proxy));
+ DCHECK(!ContainsKey(tcp_socket_pools_for_https_proxies_, http_proxy));
+ DCHECK(!ContainsKey(ssl_socket_pools_for_https_proxies_, http_proxy));
+
+ std::pair<TCPSocketPoolMap::iterator, bool> tcp_http_ret =
+ tcp_socket_pools_for_http_proxies_.insert(
+ std::make_pair(
+ http_proxy,
+ new TCPClientSocketPool(
+ g_max_sockets_per_proxy_server, g_max_sockets_per_group,
+ &tcp_for_http_proxy_pool_histograms_,
+ host_resolver_,
+ socket_factory_,
+ net_log_)));
+ DCHECK(tcp_http_ret.second);
+
+ std::pair<TCPSocketPoolMap::iterator, bool> tcp_https_ret =
+ tcp_socket_pools_for_https_proxies_.insert(
+ std::make_pair(
+ http_proxy,
+ new TCPClientSocketPool(
+ g_max_sockets_per_proxy_server, g_max_sockets_per_group,
+ &tcp_for_https_proxy_pool_histograms_,
+ host_resolver_,
+ socket_factory_,
+ net_log_)));
+ DCHECK(tcp_https_ret.second);
+
+ std::pair<SSLSocketPoolMap::iterator, bool> ssl_https_ret =
+ ssl_socket_pools_for_https_proxies_.insert(
+ std::make_pair(
+ http_proxy,
+ new SSLClientSocketPool(
+ g_max_sockets_per_proxy_server, g_max_sockets_per_group,
+ &ssl_for_https_proxy_pool_histograms_,
+ host_resolver_,
+ socket_factory_,
+ tcp_https_ret.first->second /* https proxy */,
+ NULL /* no socks proxy */,
+ NULL /* no http proxy */,
+ ssl_config_service_, net_log_)));
+ DCHECK(tcp_https_ret.second);
+
+ std::pair<HTTPProxySocketPoolMap::iterator, bool> ret =
+ http_proxy_socket_pools_.insert(
+ std::make_pair(
+ http_proxy,
+ new HttpProxyClientSocketPool(
+ g_max_sockets_per_proxy_server, g_max_sockets_per_group,
+ &http_proxy_pool_histograms_,
+ host_resolver_,
+ tcp_http_ret.first->second,
+ ssl_https_ret.first->second,
+ net_log_)));
+
+ return ret.first->second;
+}
+
+SSLClientSocketPool* ClientSocketPoolManager::GetSocketPoolForSSLWithProxy(
+ const HostPortPair& proxy_server) {
+ SSLSocketPoolMap::const_iterator it =
+ ssl_socket_pools_for_proxies_.find(proxy_server);
+ if (it != ssl_socket_pools_for_proxies_.end())
+ return it->second;
+
+ SSLClientSocketPool* new_pool = new SSLClientSocketPool(
+ g_max_sockets_per_proxy_server, g_max_sockets_per_group,
+ &ssl_pool_histograms_,
+ host_resolver_,
+ socket_factory_,
+ NULL, /* no tcp pool, we always go through a proxy */
+ GetSocketPoolForSOCKSProxy(proxy_server),
+ GetSocketPoolForHTTPProxy(proxy_server),
+ ssl_config_service_,
+ net_log_);
+
+ std::pair<SSLSocketPoolMap::iterator, bool> ret =
+ ssl_socket_pools_for_proxies_.insert(std::make_pair(proxy_server,
+ new_pool));
+
+ return ret.first->second;
+}
+
+// static
+int ClientSocketPoolManager::max_sockets_per_group() {
+ return g_max_sockets_per_group;
+}
+
+// static
+void ClientSocketPoolManager::set_max_sockets_per_group(int socket_count) {
+ DCHECK_LT(0, socket_count);
+ // The following is a sanity check... but we should NEVER be near this value.
+ DCHECK_GT(100, socket_count);
+ g_max_sockets_per_group = socket_count;
+
+ DCHECK_GE(g_max_sockets, g_max_sockets_per_group);
+ DCHECK_GE(g_max_sockets_per_proxy_server, g_max_sockets_per_group);
+}
+
+// static
+void ClientSocketPoolManager::set_max_sockets_per_proxy_server(
+ int socket_count) {
+ DCHECK_LT(0, socket_count);
+ DCHECK_GT(100, socket_count); // Sanity check.
+ // Assert this case early on. The max number of sockets per group cannot
+ // exceed the max number of sockets per proxy server.
+ DCHECK_LE(g_max_sockets_per_group, socket_count);
+ g_max_sockets_per_proxy_server = socket_count;
+}
+
+Value* ClientSocketPoolManager::SocketPoolInfoToValue() const {
+ ListValue* list = new ListValue();
+ list->Append(tcp_socket_pool_->GetInfoAsValue("tcp_socket_pool",
+ "tcp_socket_pool",
+ false));
+ // Third parameter is false because |ssl_socket_pool_| uses |tcp_socket_pool_|
+ // internally, and do not want to add it a second time.
+ list->Append(ssl_socket_pool_->GetInfoAsValue("ssl_socket_pool",
+ "ssl_socket_pool",
+ false));
+ AddSocketPoolsToList(list,
+ http_proxy_socket_pools_,
+ "http_proxy_socket_pool",
+ true);
+ AddSocketPoolsToList(list,
+ socks_socket_pools_,
+ "socks_socket_pool",
+ true);
+
+ // Third parameter is false because |ssl_socket_pools_for_proxies_| use
+ // socket pools in |http_proxy_socket_pools_| and |socks_socket_pools_|.
+ AddSocketPoolsToList(list,
+ ssl_socket_pools_for_proxies_,
+ "ssl_socket_pool_for_proxies",
+ false);
+ return list;
+}
+
+} // namespace net
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h
new file mode 100644
index 0000000..40f831f
--- /dev/null
+++ b/net/socket/client_socket_pool_manager.h
@@ -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.
+//
+// ClientSocketPoolManager manages access to all ClientSocketPools. It's a
+// 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_
+#pragma once
+
+#include <map>
+#include "base/basictypes.h"
+#include "base/non_thread_safe.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/template_util.h"
+#include "base/stl_util-inl.h"
+#include "net/socket/client_socket_pool_histograms.h"
+
+class Value;
+
+namespace net {
+
+class ClientSocketFactory;
+class ClientSocketPoolHistograms;
+class HostPortPair;
+class HttpProxyClientSocketPool;
+class HostResolver;
+class NetLog;
+class ProxyService;
+class SOCKSClientSocketPool;
+class SSLClientSocketPool;
+class SSLConfigService;
+class TCPClientSocketPool;
+
+namespace internal {
+
+// A helper class for auto-deleting Values in the destructor.
+template <typename Key, typename Value>
+class OwnedPoolMap : public std::map<Key, Value> {
+ public:
+ OwnedPoolMap() {
+ COMPILE_ASSERT(base::is_pointer<Value>::value,
+ value_must_be_a_pointer);
+ }
+
+ ~OwnedPoolMap() {
+ STLDeleteValues(this);
+ }
+};
+
+} // internal
+
+class ClientSocketPoolManager : public NonThreadSafe {
+ public:
+ ClientSocketPoolManager(NetLog* net_log,
+ ClientSocketFactory* socket_factory,
+ HostResolver* host_resolver,
+ ProxyService* proxy_service,
+ SSLConfigService* ssl_config_service);
+ ~ClientSocketPoolManager();
+
+ void FlushSocketPools();
+
+ TCPClientSocketPool* tcp_socket_pool() { return tcp_socket_pool_.get(); }
+
+ SSLClientSocketPool* ssl_socket_pool() { return ssl_socket_pool_.get(); }
+
+ SOCKSClientSocketPool* GetSocketPoolForSOCKSProxy(
+ const HostPortPair& socks_proxy);
+
+ HttpProxyClientSocketPool* GetSocketPoolForHTTPProxy(
+ const HostPortPair& http_proxy);
+
+ SSLClientSocketPool* GetSocketPoolForSSLWithProxy(
+ const HostPortPair& proxy_server);
+
+ static int max_sockets_per_group();
+ static void set_max_sockets_per_group(int socket_count);
+ static void set_max_sockets_per_proxy_server(int socket_count);
+
+ // Creates a Value summary of the state of the socket pools. The caller is
+ // responsible for deleting the returned value.
+ Value* SocketPoolInfoToValue() const;
+
+ private:
+ friend class HttpNetworkSessionPeer;
+
+ typedef internal::OwnedPoolMap<HostPortPair, TCPClientSocketPool*>
+ TCPSocketPoolMap;
+ typedef internal::OwnedPoolMap<HostPortPair, SOCKSClientSocketPool*>
+ SOCKSSocketPoolMap;
+ typedef internal::OwnedPoolMap<HostPortPair, HttpProxyClientSocketPool*>
+ HTTPProxySocketPoolMap;
+ typedef internal::OwnedPoolMap<HostPortPair, SSLClientSocketPool*>
+ SSLSocketPoolMap;
+
+ NetLog* const net_log_;
+ ClientSocketFactory* const socket_factory_;
+ const scoped_refptr<HostResolver> host_resolver_;
+ const scoped_refptr<ProxyService> proxy_service_;
+ const scoped_refptr<SSLConfigService> ssl_config_service_;
+
+ // Note: this ordering is important.
+
+ ClientSocketPoolHistograms tcp_pool_histograms_;
+ scoped_ptr<TCPClientSocketPool> tcp_socket_pool_;
+
+ ClientSocketPoolHistograms ssl_pool_histograms_;
+ scoped_ptr<SSLClientSocketPool> ssl_socket_pool_;
+
+ ClientSocketPoolHistograms tcp_for_socks_pool_histograms_;
+ TCPSocketPoolMap tcp_socket_pools_for_socks_proxies_;
+
+ ClientSocketPoolHistograms socks_pool_histograms_;
+ SOCKSSocketPoolMap socks_socket_pools_;
+
+ ClientSocketPoolHistograms tcp_for_http_proxy_pool_histograms_;
+ TCPSocketPoolMap tcp_socket_pools_for_http_proxies_;
+
+ ClientSocketPoolHistograms tcp_for_https_proxy_pool_histograms_;
+ TCPSocketPoolMap tcp_socket_pools_for_https_proxies_;
+
+ ClientSocketPoolHistograms ssl_for_https_proxy_pool_histograms_;
+ SSLSocketPoolMap ssl_socket_pools_for_https_proxies_;
+
+ ClientSocketPoolHistograms http_proxy_pool_histograms_;
+ HTTPProxySocketPoolMap http_proxy_socket_pools_;
+
+ ClientSocketPoolHistograms ssl_socket_pool_for_proxies_histograms_;
+ SSLSocketPoolMap ssl_socket_pools_for_proxies_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolManager);
+};
+
+} // namespace net
+
+#endif // NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_
diff --git a/net/socket/socket.h b/net/socket/socket.h
index a0834bf..8addca7 100644
--- a/net/socket/socket.h
+++ b/net/socket/socket.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SOCKET_H_
#define NET_SOCKET_SOCKET_H_
+#pragma once
#include "net/base/completion_callback.h"
@@ -16,25 +17,29 @@ class Socket {
public:
virtual ~Socket() {}
- // Reads data, up to buf_len bytes, from the socket. The number of bytes
- // read is returned, or an error is returned upon failure. Zero is returned
- // to indicate end-of-file. ERR_IO_PENDING is returned if the operation
- // could not be completed synchronously, in which case the result will be
- // passed to the callback when available. If the operation is not completed
- // immediately, the socket acquires a reference to the provided buffer until
- // the callback is invoked or the socket is destroyed.
+ // Reads data, up to buf_len bytes, from the socket. The number of bytes read
+ // is returned, or an error is returned upon failure. Zero is returned once
+ // to indicate end-of-file; subsequent calls return ERR_CONNECTION_CLOSED.
+ // ERR_IO_PENDING is returned if the operation could not be completed
+ // synchronously, in which case the result will be passed to the callback when
+ // available. If the operation is not completed immediately, the socket
+ // acquires a reference to the provided buffer until the callback is invoked
+ // or the socket is destroyed. If the socket is closed before the read
+ // completes, the callback will not be invoked.
virtual int Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) = 0;
// Writes data, up to buf_len bytes, to the socket. Note: only part of the
// data may be written! The number of bytes written is returned, or an error
- // is returned upon failure. ERR_IO_PENDING is returned if the operation
- // could not be completed synchronously, in which case the result will be
- // passed to the callback when available. If the operation is not completed
- // immediately, the socket acquires a reference to the provided buffer until
- // the callback is invoked or the socket is destroyed.
+ // is returned upon failure. ERR_CONNECTION_CLOSED is returned if the
+ // operation is attempted on a closed socket. ERR_IO_PENDING is returned if
+ // the operation could not be completed synchronously, in which case the
+ // result will be passed to the callback when available. If the operation is
+ // not completed immediately, the socket acquires a reference to the provided
+ // buffer until the callback is invoked or the socket is destroyed.
// Implementations of this method should not modify the contents of the actual
- // buffer that is written to the socket.
+ // buffer that is written to the socket. If the socket is closed before the
+ // write completes, the callback will not be invoked.
virtual int Write(IOBuffer* buf, int buf_len,
CompletionCallback* callback) = 0;
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 0d75516..0c181b6 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -178,7 +178,8 @@ MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses,
peer_closed_connection_(false),
pending_buf_(NULL),
pending_buf_len_(0),
- pending_callback_(NULL) {
+ pending_callback_(NULL),
+ was_used_to_convey_data_(false) {
DCHECK(data_);
data_->Reset();
}
@@ -187,6 +188,7 @@ int MockTCPClientSocket::Connect(net::CompletionCallback* callback) {
if (connected_)
return net::OK;
connected_ = true;
+ peer_closed_connection_ = false;
if (data_->connect_data().async) {
RunCallbackAsync(callback, data_->connect_data().result);
return net::ERR_IO_PENDING;
@@ -247,10 +249,13 @@ int MockTCPClientSocket::Write(net::IOBuffer* buf, int buf_len,
std::string data(buf->data(), buf_len);
net::MockWriteResult write_result = data_->OnWrite(data);
+ was_used_to_convey_data_ = true;
+
if (write_result.async) {
RunCallbackAsync(callback, write_result.result);
return net::ERR_IO_PENDING;
}
+
return write_result.result;
}
@@ -278,6 +283,8 @@ int MockTCPClientSocket::CompleteRead() {
DCHECK(pending_buf_);
DCHECK(pending_buf_len_ > 0);
+ was_used_to_convey_data_ = true;
+
// Save the pending async IO data and reset our |pending_| state.
net::IOBuffer* buf = pending_buf_;
int buf_len = pending_buf_len_;
@@ -311,8 +318,129 @@ int MockTCPClientSocket::CompleteRead() {
return result;
}
-class MockSSLClientSocket::ConnectCallback :
- public net::CompletionCallbackImpl<MockSSLClientSocket::ConnectCallback> {
+DeterministicMockTCPClientSocket::DeterministicMockTCPClientSocket(
+ net::NetLog* net_log, net::DeterministicSocketData* data)
+ : MockClientSocket(net_log),
+ write_pending_(false),
+ write_callback_(NULL),
+ write_result_(0),
+ read_data_(),
+ read_buf_(NULL),
+ read_buf_len_(0),
+ read_pending_(false),
+ read_callback_(NULL),
+ data_(data),
+ was_used_to_convey_data_(false) {}
+
+void DeterministicMockTCPClientSocket::OnReadComplete(const MockRead& data) {}
+
+// TODO(erikchen): Support connect sequencing.
+int DeterministicMockTCPClientSocket::Connect(
+ net::CompletionCallback* callback) {
+ if (connected_)
+ return net::OK;
+ connected_ = true;
+ if (data_->connect_data().async) {
+ RunCallbackAsync(callback, data_->connect_data().result);
+ return net::ERR_IO_PENDING;
+ }
+ return data_->connect_data().result;
+}
+
+void DeterministicMockTCPClientSocket::Disconnect() {
+ MockClientSocket::Disconnect();
+}
+
+bool DeterministicMockTCPClientSocket::IsConnected() const {
+ return connected_;
+}
+
+int DeterministicMockTCPClientSocket::Write(
+ net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) {
+ DCHECK(buf);
+ DCHECK_GT(buf_len, 0);
+
+ if (!connected_)
+ return net::ERR_UNEXPECTED;
+
+ std::string data(buf->data(), buf_len);
+ net::MockWriteResult write_result = data_->OnWrite(data);
+
+ if (write_result.async) {
+ write_callback_ = callback;
+ write_result_ = write_result.result;
+ DCHECK(write_callback_ != NULL);
+ write_pending_ = true;
+ return net::ERR_IO_PENDING;
+ }
+
+ was_used_to_convey_data_ = true;
+ write_pending_ = false;
+ return write_result.result;
+}
+
+int DeterministicMockTCPClientSocket::Read(
+ net::IOBuffer* buf, int buf_len, net::CompletionCallback* callback) {
+ if (!connected_)
+ return net::ERR_UNEXPECTED;
+
+ read_data_ = data_->GetNextRead();
+ // The buffer should always be big enough to contain all the MockRead data. To
+ // use small buffers, split the data into multiple MockReads.
+ DCHECK_LE(read_data_.data_len, buf_len);
+
+ read_buf_ = buf;
+ read_buf_len_ = buf_len;
+ read_callback_ = callback;
+
+ if (read_data_.async || (read_data_.result == ERR_IO_PENDING)) {
+ read_pending_ = true;
+ DCHECK(read_callback_);
+ return ERR_IO_PENDING;
+ }
+
+ was_used_to_convey_data_ = true;
+ return CompleteRead();
+}
+
+void DeterministicMockTCPClientSocket::CompleteWrite(){
+ was_used_to_convey_data_ = true;
+ write_pending_ = false;
+ write_callback_->Run(write_result_);
+}
+
+int DeterministicMockTCPClientSocket::CompleteRead() {
+ DCHECK_GT(read_buf_len_, 0);
+ DCHECK_LE(read_data_.data_len, read_buf_len_);
+ DCHECK(read_buf_);
+
+ was_used_to_convey_data_ = true;
+
+ if (read_data_.result == ERR_IO_PENDING)
+ read_data_ = data_->GetNextRead();
+ DCHECK_NE(ERR_IO_PENDING, read_data_.result);
+ // If read_data_.async is true, we do not need to wait, since this is already
+ // the callback. Therefore we don't even bother to check it.
+ int result = read_data_.result;
+
+ if (read_data_.data_len > 0) {
+ DCHECK(read_data_.data);
+ result = std::min(read_buf_len_, read_data_.data_len);
+ memcpy(read_buf_->data(), read_data_.data, result);
+ } else {
+ result = 0;
+ }
+
+ if (read_pending_) {
+ read_pending_ = false;
+ read_callback_->Run(result);
+ }
+
+ return result;
+}
+
+class MockSSLClientSocket::ConnectCallback
+ : public net::CompletionCallbackImpl<MockSSLClientSocket::ConnectCallback> {
public:
ConnectCallback(MockSSLClientSocket *ssl_client_socket,
net::CompletionCallback* user_callback,
@@ -346,7 +474,8 @@ MockSSLClientSocket::MockSSLClientSocket(
: MockClientSocket(transport_socket->socket()->NetLog().net_log()),
transport_(transport_socket),
data_(data),
- is_npn_state_set_(false) {
+ is_npn_state_set_(false),
+ new_npn_value_(false) {
DCHECK(data_);
}
@@ -360,12 +489,12 @@ int MockSSLClientSocket::Connect(net::CompletionCallback* callback) {
int rv = transport_->socket()->Connect(connect_callback);
if (rv == net::OK) {
delete connect_callback;
+ if (data_->connect.result == net::OK)
+ connected_ = true;
if (data_->connect.async) {
RunCallbackAsync(callback, data_->connect.result);
return net::ERR_IO_PENDING;
}
- if (data_->connect.result == net::OK)
- connected_ = true;
return data_->connect.result;
}
return rv;
@@ -377,6 +506,14 @@ void MockSSLClientSocket::Disconnect() {
transport_->socket()->Disconnect();
}
+bool MockSSLClientSocket::IsConnected() const {
+ return transport_->socket()->IsConnected();
+}
+
+bool MockSSLClientSocket::WasEverUsed() const {
+ return transport_->socket()->WasEverUsed();
+}
+
int MockSSLClientSocket::Read(net::IOBuffer* buf, int buf_len,
net::CompletionCallback* callback) {
return transport_->socket()->Read(buf, buf_len, callback);
@@ -397,13 +534,13 @@ SSLClientSocket::NextProtoStatus MockSSLClientSocket::GetNextProto(
return data_->next_proto_status;
}
-bool MockSSLClientSocket::wasNpnNegotiated() const {
+bool MockSSLClientSocket::was_npn_negotiated() const {
if (is_npn_state_set_)
return new_npn_value_;
return data_->was_npn_negotiated;
}
-bool MockSSLClientSocket::setWasNpnNegotiated(bool negotiated) {
+bool MockSSLClientSocket::set_was_npn_negotiated(bool negotiated) {
is_npn_state_set_ = true;
return new_npn_value_ = negotiated;
}
@@ -521,8 +658,11 @@ DelayedSocketData::DelayedSocketData(
set_connect_data(connect);
}
+DelayedSocketData::~DelayedSocketData() {
+}
+
MockRead DelayedSocketData::GetNextRead() {
- if (write_delay_)
+ if (write_delay_ > 0)
return MockRead(true, ERR_IO_PENDING);
return StaticSocketDataProvider::GetNextRead();
}
@@ -547,6 +687,11 @@ void DelayedSocketData::CompleteRead() {
socket()->OnReadComplete(GetNextRead());
}
+void DelayedSocketData::ForceNextRead() {
+ write_delay_ = 0;
+ CompleteRead();
+}
+
OrderedSocketData::OrderedSocketData(
MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count)
: StaticSocketDataProvider(reads, reads_count, writes, writes_count),
@@ -643,6 +788,113 @@ void OrderedSocketData::CompleteRead() {
}
}
+DeterministicSocketData::DeterministicSocketData(MockRead* reads,
+ size_t reads_count, MockWrite* writes, size_t writes_count)
+ : StaticSocketDataProvider(reads, reads_count, writes, writes_count),
+ sequence_number_(0),
+ current_read_(),
+ current_write_(),
+ next_read_seq_(0),
+ stopping_sequence_number_(1<<31),
+ stopped_(false),
+ print_debug_(false) {}
+
+MockRead DeterministicSocketData::GetNextRead() {
+ const MockRead& next_read = StaticSocketDataProvider::PeekRead();
+ EXPECT_LE(sequence_number_, next_read.sequence_number);
+ current_read_ = next_read;
+ next_read_seq_ = current_read_.sequence_number;
+ if (sequence_number_ >= stopping_sequence_number_) {
+ SetStopped(true);
+ NET_TRACE(INFO, " *** ") << "Force Stop. I/O Pending on read. Stage "
+ << sequence_number_;
+ MockRead result = MockRead(false, ERR_IO_PENDING);
+ if (print_debug_)
+ DumpMockRead(result);
+ return result;
+ }
+ if (sequence_number_ < next_read.sequence_number) {
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
+ << ": I/O Pending";
+ MockRead result = MockRead(false, ERR_IO_PENDING);
+ if (print_debug_)
+ DumpMockRead(result);
+ return result;
+ }
+
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
+ << ": Read " << read_index();
+ if (print_debug_)
+ DumpMockRead(next_read);
+ sequence_number_++;
+ StaticSocketDataProvider::GetNextRead();
+ if (current_read_.result == ERR_IO_PENDING)
+ current_read_ = StaticSocketDataProvider::GetNextRead();
+
+ if (!at_read_eof())
+ next_read_seq_ = PeekRead().sequence_number;
+
+ return next_read;
+}
+
+MockWriteResult DeterministicSocketData::OnWrite(const std::string& data) {
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
+ << ": Write " << write_index();
+ const MockWrite& next_write = StaticSocketDataProvider::PeekWrite();
+ DCHECK_LE(next_write.sequence_number, sequence_number_);
+ if (print_debug_)
+ DumpMockRead(next_write);
+ ++sequence_number_;
+ current_write_ = next_write;
+ return StaticSocketDataProvider::OnWrite(data);
+}
+
+void DeterministicSocketData::Reset(){
+ NET_TRACE(INFO, " *** ") << "Stage "
+ << sequence_number_ << ": Reset()";
+ sequence_number_ = 0;
+ StaticSocketDataProvider::Reset();
+ NOTREACHED();
+}
+
+void DeterministicSocketData::Run(){
+ int counter = 0;
+ // Continue to consume data until all data has run out, or the stopped_ flag
+ // has been set. Consuming data requires two separate operations -- running
+ // the tasks in the message loop, and explicitly invoking the read/write
+ // callbacks (simulating network I/O). We check our conditions between each,
+ // since they can change in either.
+ while ((!at_write_eof() || !at_read_eof()) &&
+ !stopped()) {
+ if (counter % 2 == 0)
+ MessageLoop::current()->RunAllPending();
+ if (counter % 2 == 1)
+ InvokeCallbacks();
+ counter++;
+ }
+ // We're done consuming new data, but it is possible there are still some
+ // pending callbacks which we expect to complete before returning.
+ while (socket_ && (socket_->write_pending() || socket_->read_pending()) &&
+ !stopped()) {
+ InvokeCallbacks();
+ MessageLoop::current()->RunAllPending();
+ }
+ SetStopped(false);
+}
+
+void DeterministicSocketData::InvokeCallbacks(){
+ if (socket_ && socket_->write_pending() &&
+ (current_write().sequence_number == sequence_number())) {
+ socket_->CompleteWrite();
+ return;
+ }
+ if (socket_ && socket_->read_pending() &&
+ (next_read_seq() == sequence_number())) {
+ socket_->CompleteRead();
+ return;
+ }
+}
+
void MockClientSocketFactory::AddSocketDataProvider(
SocketDataProvider* data) {
mock_data_.Add(data);
@@ -671,7 +923,9 @@ MockSSLClientSocket* MockClientSocketFactory::GetMockSSLClientSocket(
}
ClientSocket* MockClientSocketFactory::CreateTCPClientSocket(
- const AddressList& addresses, net::NetLog* net_log) {
+ const AddressList& addresses,
+ net::NetLog* net_log,
+ const NetLog::Source& source) {
SocketDataProvider* data_provider = mock_data_.GetNext();
MockTCPClientSocket* socket =
new MockTCPClientSocket(addresses, net_log, data_provider);
@@ -691,6 +945,50 @@ SSLClientSocket* MockClientSocketFactory::CreateSSLClientSocket(
return socket;
}
+void DeterministicMockClientSocketFactory::AddSocketDataProvider(
+ DeterministicSocketData* data) {
+ mock_data_.Add(data);
+}
+
+void DeterministicMockClientSocketFactory::AddSSLSocketDataProvider(
+ SSLSocketDataProvider* data) {
+ mock_ssl_data_.Add(data);
+}
+
+void DeterministicMockClientSocketFactory::ResetNextMockIndexes() {
+ mock_data_.ResetNextIndex();
+ mock_ssl_data_.ResetNextIndex();
+}
+
+MockSSLClientSocket* DeterministicMockClientSocketFactory::
+ GetMockSSLClientSocket(size_t index) const {
+ DCHECK_LT(index, ssl_client_sockets_.size());
+ return ssl_client_sockets_[index];
+}
+
+ClientSocket* DeterministicMockClientSocketFactory::CreateTCPClientSocket(
+ const AddressList& addresses,
+ net::NetLog* net_log,
+ const net::NetLog::Source& source) {
+ DeterministicSocketData* data_provider = mock_data().GetNext();
+ DeterministicMockTCPClientSocket* socket =
+ new DeterministicMockTCPClientSocket(net_log, data_provider);
+ data_provider->set_socket(socket->AsWeakPtr());
+ tcp_client_sockets().push_back(socket);
+ return socket;
+}
+
+SSLClientSocket* DeterministicMockClientSocketFactory::CreateSSLClientSocket(
+ ClientSocketHandle* transport_socket,
+ const std::string& hostname,
+ const SSLConfig& ssl_config) {
+ MockSSLClientSocket* socket =
+ new MockSSLClientSocket(transport_socket, hostname, ssl_config,
+ mock_ssl_data_.GetNext());
+ ssl_client_sockets_.push_back(socket);
+ return socket;
+}
+
int TestSocketRequest::WaitForResult() {
return callback_.WaitForResult();
}
@@ -707,26 +1005,10 @@ const int ClientSocketPoolTest::kIndexOutOfBounds = -1;
// static
const int ClientSocketPoolTest::kRequestNotFound = -2;
-void ClientSocketPoolTest::SetUp() {
- completion_count_ = 0;
-}
+ClientSocketPoolTest::ClientSocketPoolTest() : completion_count_(0) {}
+ClientSocketPoolTest::~ClientSocketPoolTest() {}
-void ClientSocketPoolTest::TearDown() {
- // The tests often call Reset() on handles at the end which may post
- // DoReleaseSocket() tasks.
- // Pending tasks created by client_socket_pool_base_unittest.cc are
- // posted two milliseconds into the future and thus won't become
- // scheduled until that time.
- // We wait a few milliseconds to make sure that all such future tasks
- // are ready to run, before calling RunAllPending(). This will work
- // correctly even if Sleep() finishes late (and it should never finish
- // early), as all we have to ensure is that actual wall-time has progressed
- // past the scheduled starting time of the pending task.
- PlatformThread::Sleep(10);
- MessageLoop::current()->RunAllPending();
-}
-
-int ClientSocketPoolTest::GetOrderOfRequest(size_t index) {
+int ClientSocketPoolTest::GetOrderOfRequest(size_t index) const {
index--;
if (index >= requests_.size())
return kIndexOutOfBounds;
@@ -810,7 +1092,7 @@ void MockTCPClientSocketPool::MockConnectJob::OnConnect(int rv) {
MockTCPClientSocketPool::MockTCPClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
ClientSocketFactory* socket_factory)
: TCPClientSocketPool(max_sockets, max_sockets_per_group, histograms,
NULL, NULL, NULL),
@@ -826,7 +1108,7 @@ int MockTCPClientSocketPool::RequestSocket(const std::string& group_name,
CompletionCallback* callback,
const BoundNetLog& net_log) {
ClientSocket* socket = client_socket_factory_->CreateTCPClientSocket(
- AddressList(), net_log.net_log());
+ AddressList(), net_log.net_log(), net::NetLog::Source());
MockConnectJob* job = new MockConnectJob(socket, handle, callback);
job_list_.push_back(job);
handle->set_pool_id(1);
@@ -856,8 +1138,8 @@ MockTCPClientSocketPool::~MockTCPClientSocketPool() {}
MockSOCKSClientSocketPool::MockSOCKSClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool)
+ ClientSocketPoolHistograms* histograms,
+ TCPClientSocketPool* tcp_pool)
: SOCKSClientSocketPool(max_sockets, max_sockets_per_group, histograms,
NULL, tcp_pool, NULL),
tcp_pool_(tcp_pool) {
@@ -886,65 +1168,114 @@ void MockSOCKSClientSocketPool::ReleaseSocket(const std::string& group_name,
MockSOCKSClientSocketPool::~MockSOCKSClientSocketPool() {}
-MockHttpAuthController::MockHttpAuthController()
- : HttpAuthController(HttpAuth::AUTH_PROXY, GURL(),
- scoped_refptr<HttpNetworkSession>(NULL)),
- data_(NULL),
- data_index_(0),
- data_count_(0) {
-}
+const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
+const int kSOCKS5GreetRequestLength = arraysize(kSOCKS5GreetRequest);
-void MockHttpAuthController::SetMockAuthControllerData(
- struct MockHttpAuthControllerData* data, size_t count) {
- data_ = data;
- data_count_ = count;
-}
+const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
+const int kSOCKS5GreetResponseLength = arraysize(kSOCKS5GreetResponse);
-int MockHttpAuthController::MaybeGenerateAuthToken(
- const HttpRequestInfo* request,
- CompletionCallback* callback,
- const BoundNetLog& net_log) {
- return OK;
-}
+const char kSOCKS5OkRequest[] =
+ { 0x05, 0x01, 0x00, 0x03, 0x04, 'h', 'o', 's', 't', 0x00, 0x50 };
+const int kSOCKS5OkRequestLength = arraysize(kSOCKS5OkRequest);
-void MockHttpAuthController::AddAuthorizationHeader(
- HttpRequestHeaders* authorization_headers) {
- authorization_headers->AddHeadersFromString(CurrentData().auth_header);
+const char kSOCKS5OkResponse[] =
+ { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 };
+const int kSOCKS5OkResponseLength = arraysize(kSOCKS5OkResponse);
+
+MockSSLClientSocketPool::MockSSLClientSocketPool(
+ int max_sockets,
+ int max_sockets_per_group,
+ ClientSocketPoolHistograms* histograms,
+ ClientSocketFactory* socket_factory,
+ TCPClientSocketPool* tcp_pool)
+ : SSLClientSocketPool(max_sockets, max_sockets_per_group, histograms,
+ NULL, socket_factory,
+ tcp_pool,
+ NULL, NULL, NULL, NULL),
+ client_socket_factory_(socket_factory),
+ release_count_(0),
+ cancel_count_(0) {
}
-int MockHttpAuthController::HandleAuthChallenge(
- scoped_refptr<HttpResponseHeaders> headers,
- bool do_not_send_server_auth,
- bool establishing_tunnel,
- const BoundNetLog& net_log) {
- return OK;
+int MockSSLClientSocketPool::RequestSocket(const std::string& group_name,
+ const void* socket_params,
+ RequestPriority priority,
+ ClientSocketHandle* handle,
+ CompletionCallback* callback,
+ const BoundNetLog& net_log) {
+ ClientSocket* socket = client_socket_factory_->CreateTCPClientSocket(
+ AddressList(), net_log.net_log(), net::NetLog::Source());
+ MockConnectJob* job = new MockConnectJob(socket, handle, callback);
+ job_list_.push_back(job);
+ handle->set_pool_id(1);
+ return job->Connect();
}
-void MockHttpAuthController::ResetAuth(const std::wstring& username,
- const std::wstring& password) {
- data_index_++;
+void MockSSLClientSocketPool::CancelRequest(const std::string& group_name,
+ ClientSocketHandle* handle) {
+ std::vector<MockConnectJob*>::iterator i;
+ for (i = job_list_.begin(); i != job_list_.end(); ++i) {
+ if ((*i)->CancelHandle(handle)) {
+ cancel_count_++;
+ break;
+ }
+ }
}
-bool MockHttpAuthController::HaveAuth() const {
- return CurrentData().auth_header.size() != 0;
+void MockSSLClientSocketPool::ReleaseSocket(const std::string& group_name,
+ ClientSocket* socket, int id) {
+ EXPECT_EQ(1, id);
+ release_count_++;
+ delete socket;
}
-bool MockHttpAuthController::HaveAuthHandler() const {
- return HaveAuth();
+MockSSLClientSocketPool::~MockSSLClientSocketPool() {}
+
+MockSSLClientSocketPool::MockConnectJob::MockConnectJob(
+ ClientSocket* socket,
+ ClientSocketHandle* handle,
+ CompletionCallback* callback)
+ : socket_(socket),
+ handle_(handle),
+ user_callback_(callback),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ connect_callback_(this, &MockConnectJob::OnConnect)) {
}
-const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
-const int kSOCKS5GreetRequestLength = arraysize(kSOCKS5GreetRequest);
+int MockSSLClientSocketPool::MockConnectJob::Connect() {
+ int rv = socket_->Connect(&connect_callback_);
+ if (rv == OK) {
+ user_callback_ = NULL;
+ OnConnect(OK);
+ }
+ return rv;
+}
-const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
-const int kSOCKS5GreetResponseLength = arraysize(kSOCKS5GreetResponse);
+bool MockSSLClientSocketPool::MockConnectJob::CancelHandle(
+ const ClientSocketHandle* handle) {
+ if (handle != handle_)
+ return false;
+ socket_.reset();
+ handle_ = NULL;
+ user_callback_ = NULL;
+ return true;
+}
-const char kSOCKS5OkRequest[] =
- { 0x05, 0x01, 0x00, 0x03, 0x04, 'h', 'o', 's', 't', 0x00, 0x50 };
-const int kSOCKS5OkRequestLength = arraysize(kSOCKS5OkRequest);
+void MockSSLClientSocketPool::MockConnectJob::OnConnect(int rv) {
+ if (!socket_.get())
+ return;
+ if (rv == OK) {
+ handle_->set_socket(socket_.release());
+ } else {
+ socket_.reset();
+ }
-const char kSOCKS5OkResponse[] =
- { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 };
-const int kSOCKS5OkResponseLength = arraysize(kSOCKS5OkResponse);
+ handle_ = NULL;
+ if (user_callback_) {
+ CompletionCallback* callback = user_callback_;
+ user_callback_ = NULL;
+ callback->Run(rv);
+ }
+}
} // namespace net
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 2bd0d23..7f83a70 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SOCKET_TEST_UTIL_H_
#define NET_SOCKET_SOCKET_TEST_UTIL_H_
+#pragma once
#include <cstring>
#include <deque>
@@ -15,6 +16,8 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/scoped_vector.h"
+#include "base/string16.h"
+#include "base/weak_ptr.h"
#include "net/base/address_list.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -27,6 +30,7 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/socks_client_socket_pool.h"
#include "net/socket/ssl_client_socket.h"
+#include "net/socket/ssl_client_socket_pool.h"
#include "net/socket/tcp_client_socket_pool.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -42,8 +46,6 @@ enum {
};
class ClientSocket;
-class HttpRequestHeaders;
-class HttpResponseHeaders;
class MockClientSocket;
class SSLClientSocket;
@@ -166,6 +168,7 @@ class StaticSocketDataProvider : public SocketDataProvider {
write_index_(0),
write_count_(writes_count) {
}
+ virtual ~StaticSocketDataProvider() {}
// SocketDataProvider methods:
virtual MockRead GetNextRead();
@@ -277,11 +280,13 @@ class DelayedSocketData : public StaticSocketDataProvider,
DelayedSocketData(const MockConnect& connect, int write_delay,
MockRead* reads, size_t reads_count,
MockWrite* writes, size_t writes_count);
+ ~DelayedSocketData();
virtual MockRead GetNextRead();
virtual MockWriteResult OnWrite(const std::string& data);
virtual void Reset();
void CompleteRead();
+ void ForceNextRead();
private:
int write_delay_;
@@ -340,6 +345,89 @@ class OrderedSocketData : public StaticSocketDataProvider,
ScopedRunnableMethodFactory<OrderedSocketData> factory_;
};
+class DeterministicMockTCPClientSocket;
+
+// This class gives the user full control over the mock socket reads and writes,
+// including the timing of the callbacks. By default, synchronous reads and
+// writes will force the callback for that read or write to complete before
+// allowing another read or write to finish.
+//
+// Sequence numbers are preserved across both reads and writes. There should be
+// no gaps in sequence numbers, and no repeated sequence numbers. i.e.
+// MockWrite writes[] = {
+// MockWrite(true, "first write", length, 0),
+// MockWrite(false, "second write", length, 3),
+// };
+//
+// MockRead reads[] = {
+// MockRead(false, "first read", length, 1)
+// MockRead(false, "second read", length, 2)
+// };
+// Example control flow:
+// The first write completes. A call to read() returns ERR_IO_PENDING, since the
+// first write's callback has not happened yet. The first write's callback is
+// called. Now the first read's callback will be called. A call to write() will
+// succeed, because the write() API requires this, but the callback will not be
+// called until the second read has completed and its callback called.
+class DeterministicSocketData : public StaticSocketDataProvider,
+ public base::RefCounted<DeterministicSocketData> {
+ public:
+ // |reads| the list of MockRead completions.
+ // |writes| the list of MockWrite completions.
+ DeterministicSocketData(MockRead* reads, size_t reads_count,
+ MockWrite* writes, size_t writes_count);
+
+ // |connect| the result for the connect phase.
+ // |reads| the list of MockRead completions.
+ // |writes| the list of MockWrite completions.
+ DeterministicSocketData(const MockConnect& connect,
+ MockRead* reads, size_t reads_count,
+ MockWrite* writes, size_t writes_count);
+
+ // When the socket calls Read(), that calls GetNextRead(), and expects either
+ // ERR_IO_PENDING or data.
+ virtual MockRead GetNextRead();
+
+ // When the socket calls Write(), it always completes synchronously. OnWrite()
+ // checks to make sure the written data matches the expected data. The
+ // callback will not be invoked until its sequence number is reached.
+ virtual MockWriteResult OnWrite(const std::string& data);
+
+ virtual void Reset();
+
+ // Consume all the data up to the give stop point (via SetStop()).
+ void Run();
+
+ // Stop when Read() is about to consume a MockRead with sequence_number >=
+ // seq. Instead feed ERR_IO_PENDING to Read().
+ virtual void SetStop(int seq) { stopping_sequence_number_ = seq; }
+
+ void CompleteRead();
+ bool stopped() const { return stopped_; }
+ void SetStopped(bool val) { stopped_ = val; }
+ MockRead& current_read() { return current_read_; }
+ MockRead& current_write() { return current_write_; }
+ int next_read_seq() const { return next_read_seq_; }
+ int sequence_number() const { return sequence_number_; }
+ void set_socket(base::WeakPtr<DeterministicMockTCPClientSocket> socket) {
+ socket_ = socket;
+ }
+
+ private:
+ // Invoke the read and write callbacks, if the timing is appropriate.
+ void InvokeCallbacks();
+
+ int sequence_number_;
+ MockRead current_read_;
+ MockWrite current_write_;
+ int next_read_seq_;
+ int stopping_sequence_number_;
+ bool stopped_;
+ base::WeakPtr<DeterministicMockTCPClientSocket> socket_;
+ bool print_debug_;
+};
+
+
// Holds an array of SocketDataProvider elements. As Mock{TCP,SSL}ClientSocket
// objects get instantiated, they take their data from the i'th element of this
// array.
@@ -395,12 +483,20 @@ class MockClientSocketFactory : public ClientSocketFactory {
MockSSLClientSocket* GetMockSSLClientSocket(size_t index) const;
// ClientSocketFactory
- virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses,
- NetLog* net_log);
+ virtual ClientSocket* CreateTCPClientSocket(
+ const AddressList& addresses,
+ NetLog* net_log,
+ const NetLog::Source& source);
virtual SSLClientSocket* CreateSSLClientSocket(
ClientSocketHandle* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config);
+ SocketDataProviderArray<SocketDataProvider>& mock_data() {
+ return mock_data_;
+ }
+ std::vector<MockTCPClientSocket*>& tcp_client_sockets() {
+ return tcp_client_sockets_;
+ }
private:
SocketDataProviderArray<SocketDataProvider> mock_data_;
@@ -414,7 +510,6 @@ class MockClientSocketFactory : public ClientSocketFactory {
class MockClientSocket : public net::SSLClientSocket {
public:
explicit MockClientSocket(net::NetLog* net_log);
-
// ClientSocket methods:
virtual int Connect(net::CompletionCallback* callback) = 0;
virtual void Disconnect();
@@ -422,6 +517,8 @@ class MockClientSocket : public net::SSLClientSocket {
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
virtual const BoundNetLog& NetLog() const { return net_log_;}
+ virtual void SetSubresourceSpeculation() {}
+ virtual void SetOmniboxSpeculation() {}
// SSLClientSocket methods:
virtual void GetSSLInfo(net::SSLInfo* ssl_info);
@@ -445,6 +542,7 @@ class MockClientSocket : public net::SSLClientSocket {
virtual void OnReadComplete(const MockRead& data) = 0;
protected:
+ virtual ~MockClientSocket() {}
void RunCallbackAsync(net::CompletionCallback* callback, int result);
void RunCallback(net::CompletionCallback*, int result);
@@ -466,6 +564,7 @@ class MockTCPClientSocket : public MockClientSocket {
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const { return IsConnected(); }
+ virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
// Socket methods:
virtual int Read(net::IOBuffer* buf, int buf_len,
@@ -496,6 +595,48 @@ class MockTCPClientSocket : public MockClientSocket {
net::IOBuffer* pending_buf_;
int pending_buf_len_;
net::CompletionCallback* pending_callback_;
+ bool was_used_to_convey_data_;
+};
+
+class DeterministicMockTCPClientSocket : public MockClientSocket,
+ public base::SupportsWeakPtr<DeterministicMockTCPClientSocket> {
+ public:
+ DeterministicMockTCPClientSocket(net::NetLog* net_log,
+ net::DeterministicSocketData* data);
+
+ // ClientSocket methods:
+ virtual int Connect(net::CompletionCallback* callback);
+ virtual void Disconnect();
+ virtual bool IsConnected() const;
+ virtual bool IsConnectedAndIdle() const { return IsConnected(); }
+ virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
+
+ // Socket methods:
+ virtual int Write(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback);
+ virtual int Read(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback);
+
+ bool write_pending() const { return write_pending_; }
+ bool read_pending() const { return read_pending_; }
+
+ void CompleteWrite();
+ int CompleteRead();
+ void OnReadComplete(const MockRead& data);
+
+ private:
+ bool write_pending_;
+ net::CompletionCallback* write_callback_;
+ int write_result_;
+
+ net::MockRead read_data_;
+
+ net::IOBuffer* read_buf_;
+ int read_buf_len_;
+ bool read_pending_;
+ net::CompletionCallback* read_callback_;
+ net::DeterministicSocketData* data_;
+ bool was_used_to_convey_data_;
};
class MockSSLClientSocket : public MockClientSocket {
@@ -510,6 +651,8 @@ class MockSSLClientSocket : public MockClientSocket {
// ClientSocket methods:
virtual int Connect(net::CompletionCallback* callback);
virtual void Disconnect();
+ virtual bool IsConnected() const;
+ virtual bool WasEverUsed() const;
// Socket methods:
virtual int Read(net::IOBuffer* buf, int buf_len,
@@ -520,8 +663,8 @@ class MockSSLClientSocket : public MockClientSocket {
// SSLClientSocket methods:
virtual void GetSSLInfo(net::SSLInfo* ssl_info);
virtual NextProtoStatus GetNextProto(std::string* proto);
- virtual bool wasNpnNegotiated() const;
- virtual bool setWasNpnNegotiated(bool negotiated);
+ virtual bool was_npn_negotiated() const;
+ virtual bool set_was_npn_negotiated(bool negotiated);
// This MockSocket does not implement the manual async IO feature.
virtual void OnReadComplete(const MockRead& data) { NOTIMPLEMENTED(); }
@@ -533,6 +676,7 @@ class MockSSLClientSocket : public MockClientSocket {
net::SSLSocketDataProvider* data_;
bool is_npn_state_set_;
bool new_npn_value_;
+ bool was_used_to_convey_data_;
};
class TestSocketRequest : public CallbackRunner< Tuple1<int> > {
@@ -558,8 +702,8 @@ class TestSocketRequest : public CallbackRunner< Tuple1<int> > {
TestCompletionCallback callback_;
};
-class ClientSocketPoolTest : public testing::Test {
- protected:
+class ClientSocketPoolTest {
+ public:
enum KeepAlive {
KEEP_ALIVE,
@@ -570,15 +714,15 @@ class ClientSocketPoolTest : public testing::Test {
static const int kIndexOutOfBounds;
static const int kRequestNotFound;
- virtual void SetUp();
- virtual void TearDown();
+ ClientSocketPoolTest();
+ ~ClientSocketPoolTest();
template <typename PoolType, typename SocketParams>
- int StartRequestUsingPool(const scoped_refptr<PoolType>& socket_pool,
+ int StartRequestUsingPool(PoolType* socket_pool,
const std::string& group_name,
RequestPriority priority,
const scoped_refptr<SocketParams>& socket_params) {
- DCHECK(socket_pool.get());
+ DCHECK(socket_pool);
TestSocketRequest* request = new TestSocketRequest(&request_order_,
&completion_count_);
requests_.push_back(request);
@@ -594,7 +738,7 @@ class ClientSocketPoolTest : public testing::Test {
// and returns order in which that request completed, in range 1..n,
// or kIndexOutOfBounds if |index| is out of bounds, or kRequestNotFound
// if that request did not complete (for example was canceled).
- int GetOrderOfRequest(size_t index);
+ int GetOrderOfRequest(size_t index) const;
// Resets first initialized socket handle from |requests_|. If found such
// a handle, returns true.
@@ -603,6 +747,12 @@ class ClientSocketPoolTest : public testing::Test {
// Releases connections until there is nothing to release.
void ReleaseAllConnections(KeepAlive keep_alive);
+ TestSocketRequest* request(int i) { return requests_[i]; }
+ size_t requests_size() const { return requests_.size(); }
+ ScopedVector<TestSocketRequest>* requests() { return &requests_; }
+ size_t completion_count() const { return completion_count_; }
+
+ private:
ScopedVector<TestSocketRequest> requests_;
std::vector<TestSocketRequest*> request_order_;
size_t completion_count_;
@@ -632,11 +782,13 @@ class MockTCPClientSocketPool : public TCPClientSocketPool {
MockTCPClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
ClientSocketFactory* socket_factory);
- int release_count() const { return release_count_; };
- int cancel_count() const { return cancel_count_; };
+ virtual ~MockTCPClientSocketPool();
+
+ int release_count() const { return release_count_; }
+ int cancel_count() const { return cancel_count_; }
// TCPClientSocketPool methods.
virtual int RequestSocket(const std::string& group_name,
@@ -651,25 +803,59 @@ class MockTCPClientSocketPool : public TCPClientSocketPool {
virtual void ReleaseSocket(const std::string& group_name,
ClientSocket* socket, int id);
- protected:
- virtual ~MockTCPClientSocketPool();
-
private:
ClientSocketFactory* client_socket_factory_;
+ ScopedVector<MockConnectJob> job_list_;
int release_count_;
int cancel_count_;
- ScopedVector<MockConnectJob> job_list_;
DISALLOW_COPY_AND_ASSIGN(MockTCPClientSocketPool);
};
+class DeterministicMockClientSocketFactory : public ClientSocketFactory {
+ public:
+ void AddSocketDataProvider(DeterministicSocketData* socket);
+ void AddSSLSocketDataProvider(SSLSocketDataProvider* socket);
+ void ResetNextMockIndexes();
+
+ // Return |index|-th MockSSLClientSocket (starting from 0) that the factory
+ // created.
+ MockSSLClientSocket* GetMockSSLClientSocket(size_t index) const;
+
+ // ClientSocketFactory
+ virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses,
+ NetLog* net_log,
+ const NetLog::Source& source);
+ virtual SSLClientSocket* CreateSSLClientSocket(
+ ClientSocketHandle* transport_socket,
+ const std::string& hostname,
+ const SSLConfig& ssl_config);
+
+ SocketDataProviderArray<DeterministicSocketData>& mock_data() {
+ return mock_data_;
+ }
+ std::vector<DeterministicMockTCPClientSocket*>& tcp_client_sockets() {
+ return tcp_client_sockets_;
+ }
+
+ private:
+ SocketDataProviderArray<DeterministicSocketData> mock_data_;
+ SocketDataProviderArray<SSLSocketDataProvider> mock_ssl_data_;
+
+ // Store pointers to handed out sockets in case the test wants to get them.
+ std::vector<DeterministicMockTCPClientSocket*> tcp_client_sockets_;
+ std::vector<MockSSLClientSocket*> ssl_client_sockets_;
+};
+
class MockSOCKSClientSocketPool : public SOCKSClientSocketPool {
public:
MockSOCKSClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool);
+ ClientSocketPoolHistograms* histograms,
+ TCPClientSocketPool* tcp_pool);
+
+ virtual ~MockSOCKSClientSocketPool();
// SOCKSClientSocketPool methods.
virtual int RequestSocket(const std::string& group_name,
@@ -684,54 +870,12 @@ class MockSOCKSClientSocketPool : public SOCKSClientSocketPool {
virtual void ReleaseSocket(const std::string& group_name,
ClientSocket* socket, int id);
- protected:
- virtual ~MockSOCKSClientSocketPool();
-
private:
- const scoped_refptr<TCPClientSocketPool> tcp_pool_;
+ TCPClientSocketPool* const tcp_pool_;
DISALLOW_COPY_AND_ASSIGN(MockSOCKSClientSocketPool);
};
-struct MockHttpAuthControllerData {
- MockHttpAuthControllerData(std::string header) : auth_header(header) {}
-
- std::string auth_header;
-};
-
-class MockHttpAuthController : public HttpAuthController {
- public:
- MockHttpAuthController();
- void SetMockAuthControllerData(struct MockHttpAuthControllerData* data,
- size_t data_length);
-
- // HttpAuthController methods.
- virtual int MaybeGenerateAuthToken(const HttpRequestInfo* request,
- CompletionCallback* callback,
- const BoundNetLog& net_log);
- virtual void AddAuthorizationHeader(
- HttpRequestHeaders* authorization_headers);
- virtual int HandleAuthChallenge(scoped_refptr<HttpResponseHeaders> headers,
- bool do_not_send_server_auth,
- bool establishing_tunnel,
- const BoundNetLog& net_log);
- virtual void ResetAuth(const std::wstring& username,
- const std::wstring& password);
- virtual bool HaveAuthHandler() const;
- virtual bool HaveAuth() const;
-
- private:
- virtual ~MockHttpAuthController() {}
- const struct MockHttpAuthControllerData& CurrentData() const {
- DCHECK(data_index_ < data_count_);
- return data_[data_index_];
- }
-
- MockHttpAuthControllerData* data_;
- size_t data_index_;
- size_t data_count_;
-};
-
// Constants for a successful SOCKS v5 handshake.
extern const char kSOCKS5GreetRequest[];
extern const int kSOCKS5GreetRequestLength;
@@ -745,6 +889,62 @@ extern const int kSOCKS5OkRequestLength;
extern const char kSOCKS5OkResponse[];
extern const int kSOCKS5OkResponseLength;
+class MockSSLClientSocketPool : public SSLClientSocketPool {
+ public:
+ class MockConnectJob {
+ public:
+ MockConnectJob(ClientSocket* socket, ClientSocketHandle* handle,
+ CompletionCallback* callback);
+
+ int Connect();
+ bool CancelHandle(const ClientSocketHandle* handle);
+
+ private:
+ void OnConnect(int rv);
+
+ scoped_ptr<ClientSocket> socket_;
+ ClientSocketHandle* handle_;
+ CompletionCallback* user_callback_;
+ CompletionCallbackImpl<MockConnectJob> connect_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockConnectJob);
+ };
+
+ MockSSLClientSocketPool(
+ int max_sockets,
+ int max_sockets_per_group,
+ ClientSocketPoolHistograms* histograms,
+ ClientSocketFactory* socket_factory,
+ TCPClientSocketPool* tcp_pool);
+
+ virtual ~MockSSLClientSocketPool();
+
+ int release_count() const { return release_count_; }
+ int cancel_count() const { return cancel_count_; }
+
+ // SSLClientSocketPool methods.
+ virtual int RequestSocket(const std::string& group_name,
+ const void* socket_params,
+ RequestPriority priority,
+ ClientSocketHandle* handle,
+ CompletionCallback* callback,
+ const BoundNetLog& net_log);
+
+ virtual void CancelRequest(const std::string& group_name,
+ ClientSocketHandle* handle);
+ virtual void ReleaseSocket(const std::string& group_name,
+ ClientSocket* socket, int id);
+
+ private:
+ ClientSocketFactory* client_socket_factory_;
+ int release_count_;
+ int cancel_count_;
+ ScopedVector<MockConnectJob> job_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSSLClientSocketPool);
+};
+
+
} // namespace net
#endif // NET_SOCKET_SOCKET_TEST_UTIL_H_
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index 392483d..501a3a7 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -69,7 +69,6 @@ SOCKS5ClientSocket::~SOCKS5ClientSocket() {
int SOCKS5ClientSocket::Connect(CompletionCallback* callback) {
DCHECK(transport_.get());
DCHECK(transport_->socket());
- DCHECK(transport_->socket()->IsConnected());
DCHECK_EQ(STATE_NONE, next_state_);
DCHECK(!user_callback_);
@@ -109,6 +108,30 @@ bool SOCKS5ClientSocket::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
}
+void SOCKS5ClientSocket::SetSubresourceSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetSubresourceSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void SOCKS5ClientSocket::SetOmniboxSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetOmniboxSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+bool SOCKS5ClientSocket::WasEverUsed() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->WasEverUsed();
+ }
+ NOTREACHED();
+ return false;
+}
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len,
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index e6150f3..72e27db 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -4,10 +4,11 @@
#ifndef NET_SOCKET_SOCKS5_CLIENT_SOCKET_H_
#define NET_SOCKET_SOCKS5_CLIENT_SOCKET_H_
+#pragma once
#include <string>
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "googleurl/src/gurl.h"
@@ -55,6 +56,9 @@ class SOCKS5ClientSocket : public ClientSocket {
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc
index 736a725..9ceffd0 100644
--- a/net/socket/socks5_client_socket_unittest.cc
+++ b/net/socket/socks5_client_socket_unittest.cc
@@ -66,7 +66,7 @@ void SOCKS5ClientSocketTest::SetUp() {
PlatformTest::SetUp();
// Resolve the "localhost" AddressList used by the TCP connection to connect.
- HostResolver::RequestInfo info("www.socks-proxy.com", 1080);
+ HostResolver::RequestInfo info(HostPortPair("www.socks-proxy.com", 1080));
int rv = host_resolver_->Resolve(info, &address_list_, NULL, NULL,
BoundNetLog());
ASSERT_EQ(OK, rv);
@@ -92,7 +92,7 @@ SOCKS5ClientSocket* SOCKS5ClientSocketTest::BuildMockSocket(
EXPECT_TRUE(tcp_sock_->IsConnected());
return new SOCKS5ClientSocket(tcp_sock_,
- HostResolver::RequestInfo(hostname, port));
+ HostResolver::RequestInfo(HostPortPair(hostname, port)));
}
// Tests a complete SOCKS5 handshake and the disconnection.
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index 0af80b4..9069c01 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -104,7 +104,6 @@ SOCKSClientSocket::~SOCKSClientSocket() {
int SOCKSClientSocket::Connect(CompletionCallback* callback) {
DCHECK(transport_.get());
DCHECK(transport_->socket());
- DCHECK(transport_->socket()->IsConnected());
DCHECK_EQ(STATE_NONE, next_state_);
DCHECK(!user_callback_);
@@ -144,6 +143,30 @@ bool SOCKSClientSocket::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
}
+void SOCKSClientSocket::SetSubresourceSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetSubresourceSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void SOCKSClientSocket::SetOmniboxSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetOmniboxSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+bool SOCKSClientSocket::WasEverUsed() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->WasEverUsed();
+ }
+ NOTREACHED();
+ return false;
+}
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
int SOCKSClientSocket::Read(IOBuffer* buf, int buf_len,
diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h
index f99bff0..e9e9695 100644
--- a/net/socket/socks_client_socket.h
+++ b/net/socket/socks_client_socket.h
@@ -4,10 +4,12 @@
#ifndef NET_SOCKET_SOCKS_CLIENT_SOCKET_H_
#define NET_SOCKET_SOCKS_CLIENT_SOCKET_H_
+#pragma once
#include <string>
-#include "base/logging.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "googleurl/src/gurl.h"
@@ -17,7 +19,6 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/socket/client_socket.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
namespace net {
@@ -52,6 +53,9 @@ class SOCKSClientSocket : public ClientSocket {
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
@@ -63,9 +67,9 @@ class SOCKSClientSocket : public ClientSocket {
virtual int GetPeerAddress(AddressList* address) const;
private:
- FRIEND_TEST(SOCKSClientSocketTest, CompleteHandshake);
- FRIEND_TEST(SOCKSClientSocketTest, SOCKS4AFailedDNS);
- FRIEND_TEST(SOCKSClientSocketTest, SOCKS4AIfDomainInIPv6);
+ FRIEND_TEST_ALL_PREFIXES(SOCKSClientSocketTest, CompleteHandshake);
+ FRIEND_TEST_ALL_PREFIXES(SOCKSClientSocketTest, SOCKS4AFailedDNS);
+ FRIEND_TEST_ALL_PREFIXES(SOCKSClientSocketTest, SOCKS4AIfDomainInIPv6);
enum State {
STATE_RESOLVE_HOST,
diff --git a/net/socket/socks_client_socket_pool.cc b/net/socket/socks_client_socket_pool.cc
index d1c75b6..129c075 100644
--- a/net/socket/socks_client_socket_pool.cc
+++ b/net/socket/socks_client_socket_pool.cc
@@ -5,6 +5,7 @@
#include "net/socket/socks_client_socket_pool.h"
#include "base/time.h"
+#include "base/values.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
#include "net/socket/client_socket_factory.h"
@@ -12,6 +13,7 @@
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/socks5_client_socket.h"
#include "net/socket/socks_client_socket.h"
+#include "net/socket/tcp_client_socket_pool.h"
namespace net {
@@ -22,7 +24,7 @@ SOCKSSocketParams::SOCKSSocketParams(
RequestPriority priority,
const GURL& referrer)
: tcp_params_(proxy_server),
- destination_(host_port_pair.host, host_port_pair.port),
+ destination_(host_port_pair),
socks_v5_(socks_v5) {
// 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
@@ -41,7 +43,7 @@ SOCKSConnectJob::SOCKSConnectJob(
const std::string& group_name,
const scoped_refptr<SOCKSSocketParams>& socks_params,
const base::TimeDelta& timeout_duration,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
const scoped_refptr<HostResolver>& host_resolver,
Delegate* delegate,
NetLog* net_log)
@@ -61,11 +63,11 @@ SOCKSConnectJob::~SOCKSConnectJob() {
LoadState SOCKSConnectJob::GetLoadState() const {
switch (next_state_) {
- case kStateTCPConnect:
- case kStateTCPConnectComplete:
+ case STATE_TCP_CONNECT:
+ case STATE_TCP_CONNECT_COMPLETE:
return tcp_socket_handle_->GetLoadState();
- case kStateSOCKSConnect:
- case kStateSOCKSConnectComplete:
+ case STATE_SOCKS_CONNECT:
+ case STATE_SOCKS_CONNECT_COMPLETE:
return LOAD_STATE_CONNECTING;
default:
NOTREACHED();
@@ -74,7 +76,7 @@ LoadState SOCKSConnectJob::GetLoadState() const {
}
int SOCKSConnectJob::ConnectInternal() {
- next_state_ = kStateTCPConnect;
+ next_state_ = STATE_TCP_CONNECT;
return DoLoop(OK);
}
@@ -85,25 +87,25 @@ void SOCKSConnectJob::OnIOComplete(int result) {
}
int SOCKSConnectJob::DoLoop(int result) {
- DCHECK_NE(next_state_, kStateNone);
+ DCHECK_NE(next_state_, STATE_NONE);
int rv = result;
do {
State state = next_state_;
- next_state_ = kStateNone;
+ next_state_ = STATE_NONE;
switch (state) {
- case kStateTCPConnect:
+ case STATE_TCP_CONNECT:
DCHECK_EQ(OK, rv);
rv = DoTCPConnect();
break;
- case kStateTCPConnectComplete:
+ case STATE_TCP_CONNECT_COMPLETE:
rv = DoTCPConnectComplete(rv);
break;
- case kStateSOCKSConnect:
+ case STATE_SOCKS_CONNECT:
DCHECK_EQ(OK, rv);
rv = DoSOCKSConnect();
break;
- case kStateSOCKSConnectComplete:
+ case STATE_SOCKS_CONNECT_COMPLETE:
rv = DoSOCKSConnectComplete(rv);
break;
default:
@@ -111,13 +113,13 @@ int SOCKSConnectJob::DoLoop(int result) {
rv = ERR_FAILED;
break;
}
- } while (rv != ERR_IO_PENDING && next_state_ != kStateNone);
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
return rv;
}
int SOCKSConnectJob::DoTCPConnect() {
- next_state_ = kStateTCPConnectComplete;
+ next_state_ = STATE_TCP_CONNECT_COMPLETE;
tcp_socket_handle_.reset(new ClientSocketHandle());
return tcp_socket_handle_->Init(group_name(), socks_params_->tcp_params(),
socks_params_->destination().priority(),
@@ -126,18 +128,18 @@ int SOCKSConnectJob::DoTCPConnect() {
int SOCKSConnectJob::DoTCPConnectComplete(int result) {
if (result != OK)
- return result;
+ return ERR_PROXY_CONNECTION_FAILED;
// Reset the timer to just the length of time allowed for SOCKS handshake
// so that a fast TCP connection plus a slow SOCKS failure doesn't take
// longer to timeout than it should.
ResetTimer(base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds));
- next_state_ = kStateSOCKSConnect;
+ next_state_ = STATE_SOCKS_CONNECT;
return result;
}
int SOCKSConnectJob::DoSOCKSConnect() {
- next_state_ = kStateSOCKSConnectComplete;
+ next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
// Add a SOCKS connection on top of the tcp socket.
if (socks_params_->is_socks_v5()) {
@@ -178,11 +180,12 @@ SOCKSClientSocketPool::SOCKSConnectJobFactory::ConnectionTimeout() const {
SOCKSClientSocketPool::SOCKSClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
const scoped_refptr<HostResolver>& host_resolver,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
NetLog* net_log)
- : base_(max_sockets, max_sockets_per_group, histograms,
+ : tcp_pool_(tcp_pool),
+ base_(max_sockets, max_sockets_per_group, histograms,
base::TimeDelta::FromSeconds(
ClientSocketPool::unused_idle_socket_timeout()),
base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
@@ -232,4 +235,19 @@ LoadState SOCKSClientSocketPool::GetLoadState(
return base_.GetLoadState(group_name, handle);
}
+DictionaryValue* SOCKSClientSocketPool::GetInfoAsValue(
+ const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const {
+ DictionaryValue* dict = base_.GetInfoAsValue(name, type);
+ if (include_nested_pools) {
+ ListValue* list = new ListValue();
+ list->Append(tcp_pool_->GetInfoAsValue("tcp_socket_pool",
+ "tcp_socket_pool",
+ false));
+ dict->Set("nested_pools", list);
+ }
+ return dict;
+}
+
} // namespace net
diff --git a/net/socket/socks_client_socket_pool.h b/net/socket/socks_client_socket_pool.h
index 4387aa7..383de63 100644
--- a/net/socket/socks_client_socket_pool.h
+++ b/net/socket/socks_client_socket_pool.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SOCKS_CLIENT_SOCKET_POOL_H_
#define NET_SOCKET_SOCKS_CLIENT_SOCKET_POOL_H_
+#pragma once
#include <string>
@@ -14,16 +15,15 @@
#include "base/time.h"
#include "net/base/host_port_pair.h"
#include "net/base/host_resolver.h"
-#include "net/proxy/proxy_server.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/client_socket_pool_histograms.h"
#include "net/socket/client_socket_pool.h"
-#include "net/socket/tcp_client_socket_pool.h"
namespace net {
-class ClientSocketFactory;
class ConnectJobFactory;
+class TCPClientSocketPool;
+class TCPSocketParams;
class SOCKSSocketParams : public base::RefCounted<SOCKSSocketParams> {
public:
@@ -57,7 +57,7 @@ class SOCKSConnectJob : public ConnectJob {
SOCKSConnectJob(const std::string& group_name,
const scoped_refptr<SOCKSSocketParams>& params,
const base::TimeDelta& timeout_duration,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
const scoped_refptr<HostResolver> &host_resolver,
Delegate* delegate,
NetLog* net_log);
@@ -68,11 +68,11 @@ class SOCKSConnectJob : public ConnectJob {
private:
enum State {
- kStateTCPConnect,
- kStateTCPConnectComplete,
- kStateSOCKSConnect,
- kStateSOCKSConnectComplete,
- kStateNone,
+ STATE_TCP_CONNECT,
+ STATE_TCP_CONNECT_COMPLETE,
+ STATE_SOCKS_CONNECT,
+ STATE_SOCKS_CONNECT_COMPLETE,
+ STATE_NONE,
};
// Begins the tcp connection and the SOCKS handshake. Returns OK on success
@@ -91,7 +91,7 @@ class SOCKSConnectJob : public ConnectJob {
int DoSOCKSConnectComplete(int result);
scoped_refptr<SOCKSSocketParams> socks_params_;
- const scoped_refptr<TCPClientSocketPool> tcp_pool_;
+ TCPClientSocketPool* const tcp_pool_;
const scoped_refptr<HostResolver> resolver_;
State next_state_;
@@ -107,11 +107,13 @@ class SOCKSClientSocketPool : public ClientSocketPool {
SOCKSClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
const scoped_refptr<HostResolver>& host_resolver,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ TCPClientSocketPool* tcp_pool,
NetLog* net_log);
+ virtual ~SOCKSClientSocketPool();
+
// ClientSocketPool methods:
virtual int RequestSocket(const std::string& group_name,
const void* connect_params,
@@ -140,23 +142,24 @@ class SOCKSClientSocketPool : public ClientSocketPool {
virtual LoadState GetLoadState(const std::string& group_name,
const ClientSocketHandle* handle) const;
+ virtual DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const;
+
virtual base::TimeDelta ConnectionTimeout() const {
return base_.ConnectionTimeout();
}
- virtual scoped_refptr<ClientSocketPoolHistograms> histograms() const {
+ virtual ClientSocketPoolHistograms* histograms() const {
return base_.histograms();
};
- protected:
- virtual ~SOCKSClientSocketPool();
-
private:
typedef ClientSocketPoolBase<SOCKSSocketParams> PoolBase;
class SOCKSConnectJobFactory : public PoolBase::ConnectJobFactory {
public:
- SOCKSConnectJobFactory(const scoped_refptr<TCPClientSocketPool>& tcp_pool,
+ SOCKSConnectJobFactory(TCPClientSocketPool* tcp_pool,
HostResolver* host_resolver,
NetLog* net_log)
: tcp_pool_(tcp_pool),
@@ -174,13 +177,14 @@ class SOCKSClientSocketPool : public ClientSocketPool {
virtual base::TimeDelta ConnectionTimeout() const;
private:
- const scoped_refptr<TCPClientSocketPool> tcp_pool_;
+ TCPClientSocketPool* const tcp_pool_;
const scoped_refptr<HostResolver> host_resolver_;
NetLog* net_log_;
DISALLOW_COPY_AND_ASSIGN(SOCKSConnectJobFactory);
};
+ TCPClientSocketPool* const tcp_pool_;
PoolBase base_;
DISALLOW_COPY_AND_ASSIGN(SOCKSClientSocketPool);
diff --git a/net/socket/socks_client_socket_pool_unittest.cc b/net/socket/socks_client_socket_pool_unittest.cc
index 14e2bee..9627f1a 100644
--- a/net/socket/socks_client_socket_pool_unittest.cc
+++ b/net/socket/socks_client_socket_pool_unittest.cc
@@ -23,7 +23,7 @@ namespace {
const int kMaxSockets = 32;
const int kMaxSocketsPerGroup = 6;
-class SOCKSClientSocketPoolTest : public ClientSocketPoolTest {
+class SOCKSClientSocketPoolTest : public testing::Test {
protected:
class SOCKS5MockData {
public:
@@ -55,30 +55,44 @@ class SOCKSClientSocketPoolTest : public ClientSocketPoolTest {
SOCKSClientSocketPoolTest()
: ignored_tcp_socket_params_(new TCPSocketParams(
HostPortPair("proxy", 80), MEDIUM, GURL(), false)),
- tcp_histograms_(new ClientSocketPoolHistograms("MockTCP")),
- tcp_socket_pool_(new MockTCPClientSocketPool(kMaxSockets,
- kMaxSocketsPerGroup, tcp_histograms_, &tcp_client_socket_factory_)),
+ tcp_histograms_("MockTCP"),
+ tcp_socket_pool_(
+ kMaxSockets, kMaxSocketsPerGroup,
+ &tcp_histograms_,
+ &tcp_client_socket_factory_),
ignored_socket_params_(new SOCKSSocketParams(
ignored_tcp_socket_params_, true, HostPortPair("host", 80), MEDIUM,
GURL())),
- socks_histograms_(new ClientSocketPoolHistograms("SOCKSUnitTest")),
- pool_(new SOCKSClientSocketPool(kMaxSockets, kMaxSocketsPerGroup,
- socks_histograms_, NULL, tcp_socket_pool_, NULL)) {
+ socks_histograms_("SOCKSUnitTest"),
+ pool_(kMaxSockets, kMaxSocketsPerGroup,
+ &socks_histograms_,
+ NULL,
+ &tcp_socket_pool_,
+ NULL) {
}
+ virtual ~SOCKSClientSocketPoolTest() {}
+
int StartRequest(const std::string& group_name, RequestPriority priority) {
- return StartRequestUsingPool(
- pool_, group_name, priority, ignored_socket_params_);
+ return test_base_.StartRequestUsingPool(
+ &pool_, group_name, priority, ignored_socket_params_);
+ }
+
+ int GetOrderOfRequest(size_t index) const {
+ return test_base_.GetOrderOfRequest(index);
}
+ ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
+
scoped_refptr<TCPSocketParams> ignored_tcp_socket_params_;
- scoped_refptr<ClientSocketPoolHistograms> tcp_histograms_;
+ ClientSocketPoolHistograms tcp_histograms_;
MockClientSocketFactory tcp_client_socket_factory_;
- scoped_refptr<MockTCPClientSocketPool> tcp_socket_pool_;
+ MockTCPClientSocketPool tcp_socket_pool_;
scoped_refptr<SOCKSSocketParams> ignored_socket_params_;
- scoped_refptr<ClientSocketPoolHistograms> socks_histograms_;
- scoped_refptr<SOCKSClientSocketPool> pool_;
+ ClientSocketPoolHistograms socks_histograms_;
+ SOCKSClientSocketPool pool_;
+ ClientSocketPoolTest test_base_;
};
TEST_F(SOCKSClientSocketPoolTest, Simple) {
@@ -87,7 +101,7 @@ TEST_F(SOCKSClientSocketPoolTest, Simple) {
tcp_client_socket_factory_.AddSocketDataProvider(data.data_provider());
ClientSocketHandle handle;
- int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, pool_,
+ int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_TRUE(handle.is_initialized());
@@ -100,7 +114,7 @@ TEST_F(SOCKSClientSocketPoolTest, Async) {
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
@@ -117,9 +131,9 @@ TEST_F(SOCKSClientSocketPoolTest, TCPConnectError) {
tcp_client_socket_factory_.AddSocketDataProvider(socket_data.get());
ClientSocketHandle handle;
- int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, pool_,
+ int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
BoundNetLog());
- EXPECT_EQ(ERR_CONNECTION_REFUSED, rv);
+ EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
}
@@ -131,13 +145,13 @@ TEST_F(SOCKSClientSocketPoolTest, AsyncTCPConnectError) {
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, pool_,
+ int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.WaitForResult());
+ EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult());
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
}
@@ -152,13 +166,13 @@ TEST_F(SOCKSClientSocketPoolTest, SOCKSConnectError) {
tcp_client_socket_factory_.AddSocketDataProvider(socket_data.get());
ClientSocketHandle handle;
- EXPECT_EQ(0, tcp_socket_pool_->release_count());
- int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, pool_,
+ EXPECT_EQ(0, tcp_socket_pool_.release_count());
+ int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(1, tcp_socket_pool_->release_count());
+ EXPECT_EQ(1, tcp_socket_pool_.release_count());
}
TEST_F(SOCKSClientSocketPoolTest, AsyncSOCKSConnectError) {
@@ -172,8 +186,8 @@ TEST_F(SOCKSClientSocketPoolTest, AsyncSOCKSConnectError) {
TestCompletionCallback callback;
ClientSocketHandle handle;
- EXPECT_EQ(0, tcp_socket_pool_->release_count());
- int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, pool_,
+ EXPECT_EQ(0, tcp_socket_pool_.release_count());
+ int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
@@ -182,7 +196,7 @@ TEST_F(SOCKSClientSocketPoolTest, AsyncSOCKSConnectError) {
EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, callback.WaitForResult());
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(1, tcp_socket_pool_->release_count());
+ EXPECT_EQ(1, tcp_socket_pool_.release_count());
}
TEST_F(SOCKSClientSocketPoolTest, CancelDuringTCPConnect) {
@@ -193,28 +207,28 @@ TEST_F(SOCKSClientSocketPoolTest, CancelDuringTCPConnect) {
SOCKS5MockData data2(false);
tcp_client_socket_factory_.AddSocketDataProvider(data2.data_provider());
- EXPECT_EQ(0, tcp_socket_pool_->cancel_count());
+ EXPECT_EQ(0, tcp_socket_pool_.cancel_count());
int rv = StartRequest("a", LOW);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = StartRequest("a", LOW);
EXPECT_EQ(ERR_IO_PENDING, rv);
- pool_->CancelRequest("a", requests_[0]->handle());
- pool_->CancelRequest("a", requests_[1]->handle());
+ pool_.CancelRequest("a", (*requests())[0]->handle());
+ pool_.CancelRequest("a", (*requests())[1]->handle());
// Requests in the connect phase don't actually get cancelled.
- EXPECT_EQ(0, tcp_socket_pool_->cancel_count());
+ EXPECT_EQ(0, tcp_socket_pool_.cancel_count());
// Now wait for the TCP sockets to connect.
MessageLoop::current()->RunAllPending();
- EXPECT_EQ(kRequestNotFound, GetOrderOfRequest(1));
- EXPECT_EQ(kRequestNotFound, GetOrderOfRequest(2));
- EXPECT_EQ(0, tcp_socket_pool_->cancel_count());
- EXPECT_EQ(2, pool_->IdleSocketCount());
+ EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(1));
+ EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(2));
+ EXPECT_EQ(0, tcp_socket_pool_.cancel_count());
+ EXPECT_EQ(2, pool_.IdleSocketCount());
- requests_[0]->handle()->Reset();
- requests_[1]->handle()->Reset();
+ (*requests())[0]->handle()->Reset();
+ (*requests())[1]->handle()->Reset();
}
TEST_F(SOCKSClientSocketPoolTest, CancelDuringSOCKSConnect) {
@@ -227,31 +241,31 @@ TEST_F(SOCKSClientSocketPoolTest, CancelDuringSOCKSConnect) {
data2.data_provider()->set_connect_data(MockConnect(false, 0));
tcp_client_socket_factory_.AddSocketDataProvider(data2.data_provider());
- EXPECT_EQ(0, tcp_socket_pool_->cancel_count());
- EXPECT_EQ(0, tcp_socket_pool_->release_count());
+ EXPECT_EQ(0, tcp_socket_pool_.cancel_count());
+ EXPECT_EQ(0, tcp_socket_pool_.release_count());
int rv = StartRequest("a", LOW);
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = StartRequest("a", LOW);
EXPECT_EQ(ERR_IO_PENDING, rv);
- pool_->CancelRequest("a", requests_[0]->handle());
- pool_->CancelRequest("a", requests_[1]->handle());
- EXPECT_EQ(0, tcp_socket_pool_->cancel_count());
+ pool_.CancelRequest("a", (*requests())[0]->handle());
+ pool_.CancelRequest("a", (*requests())[1]->handle());
+ EXPECT_EQ(0, tcp_socket_pool_.cancel_count());
// Requests in the connect phase don't actually get cancelled.
- EXPECT_EQ(0, tcp_socket_pool_->release_count());
+ EXPECT_EQ(0, tcp_socket_pool_.release_count());
// Now wait for the async data to reach the SOCKS connect jobs.
MessageLoop::current()->RunAllPending();
- EXPECT_EQ(kRequestNotFound, GetOrderOfRequest(1));
- EXPECT_EQ(kRequestNotFound, GetOrderOfRequest(2));
- EXPECT_EQ(0, tcp_socket_pool_->cancel_count());
- EXPECT_EQ(0, tcp_socket_pool_->release_count());
- EXPECT_EQ(2, pool_->IdleSocketCount());
+ EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(1));
+ EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(2));
+ EXPECT_EQ(0, tcp_socket_pool_.cancel_count());
+ EXPECT_EQ(0, tcp_socket_pool_.release_count());
+ EXPECT_EQ(2, pool_.IdleSocketCount());
- requests_[0]->handle()->Reset();
- requests_[1]->handle()->Reset();
+ (*requests())[0]->handle()->Reset();
+ (*requests())[1]->handle()->Reset();
}
// It would be nice to also test the timeouts in SOCKSClientSocketPool.
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc
index aaabc4b..8ed82b9 100644
--- a/net/socket/socks_client_socket_unittest.cc
+++ b/net/socket/socks_client_socket_unittest.cc
@@ -79,7 +79,7 @@ SOCKSClientSocket* SOCKSClientSocketTest::BuildMockSocket(
EXPECT_TRUE(tcp_sock_->IsConnected());
return new SOCKSClientSocket(tcp_sock_,
- HostResolver::RequestInfo(hostname, port),
+ HostResolver::RequestInfo(HostPortPair(hostname, port)),
host_resolver);
}
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index 9c34282..064dd26 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -4,9 +4,11 @@
#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_H_
+#pragma once
#include <string>
+#include "net/base/completion_callback.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/socket/client_socket.h"
@@ -15,6 +17,20 @@ namespace net {
class SSLCertRequestInfo;
class SSLInfo;
+struct RRResponse;
+
+// DNSSECProvider is an interface to an object that can return DNSSEC data.
+class DNSSECProvider {
+ public:
+ // GetDNSSECRecords will either:
+ // 1) set |*out| to NULL and return OK.
+ // 2) set |*out| to a pointer, which is owned by this object, and return OK.
+ // 3) return IO_PENDING and call |callback| on the current MessageLoop at
+ // some point in the future. Once the callback has been made, this
+ // function will return OK if called again.
+ virtual int GetDNSSECRecords(RRResponse** out,
+ CompletionCallback* callback) = 0;
+};
// A client socket that uses SSL as the transport layer.
//
@@ -24,7 +40,7 @@ class SSLInfo;
//
class SSLClientSocket : public ClientSocket {
public:
- SSLClientSocket() : was_npn_negotiated_(false) {
+ SSLClientSocket() : was_npn_negotiated_(false), was_spdy_negotiated_(false) {
}
// Next Protocol Negotiation (NPN) allows a TLS client and server to come to
// an agreement about the application level protocol to speak over a
@@ -44,6 +60,7 @@ class SSLClientSocket : public ClientSocket {
kProtoUnknown = 0,
kProtoHTTP11 = 1,
kProtoSPDY1 = 2,
+ kProtoSPDY2 = 3,
};
// Gets the SSL connection information of the socket.
@@ -66,8 +83,10 @@ class SSLClientSocket : public ClientSocket {
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" || proto_string == "spdy/1") {
+ } else if (proto_string == "spdy/1") {
return kProtoSPDY1;
+ } else if (proto_string == "spdy/2") {
+ return kProtoSPDY2;
} else {
return kProtoUnknown;
}
@@ -90,17 +109,29 @@ class SSLClientSocket : public ClientSocket {
return false;
}
- virtual bool wasNpnNegotiated() const {
+ virtual bool was_npn_negotiated() const {
return was_npn_negotiated_;
}
- virtual bool setWasNpnNegotiated(bool negotiated) {
+ virtual bool set_was_npn_negotiated(bool negotiated) {
return was_npn_negotiated_ = negotiated;
}
+ virtual void UseDNSSEC(DNSSECProvider*) { }
+
+ virtual bool was_spdy_negotiated() const {
+ return was_spdy_negotiated_;
+ }
+
+ virtual bool set_was_spdy_negotiated(bool negotiated) {
+ return was_spdy_negotiated_ = negotiated;
+ }
+
private:
// True if NPN was responded to, independent of selecting SPDY or HTTP.
bool was_npn_negotiated_;
+ // True if NPN successfully negotiated SPDY.
+ bool was_spdy_negotiated_;
};
} // namespace net
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index c3c7d7a..284937a 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -591,6 +591,30 @@ int SSLClientSocketMac::GetPeerAddress(AddressList* address) const {
return transport_->socket()->GetPeerAddress(address);
}
+void SSLClientSocketMac::SetSubresourceSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetSubresourceSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void SSLClientSocketMac::SetOmniboxSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetOmniboxSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+bool SSLClientSocketMac::WasEverUsed() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->WasEverUsed();
+ }
+ NOTREACHED();
+ return false;
+}
+
int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake_);
@@ -653,8 +677,12 @@ void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) {
// security info
SSLCipherSuite suite;
OSStatus status = SSLGetNegotiatedCipher(ssl_context_, &suite);
- if (!status)
+ if (!status) {
ssl_info->security_bits = KeySizeOfCipherSuite(suite);
+ ssl_info->connection_status |=
+ (suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
+ SSL_CONNECTION_CIPHERSUITE_SHIFT;
+ }
if (ssl_config_.ssl3_fallback)
ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK;
@@ -782,17 +810,21 @@ int SSLClientSocketMac::InitializeSSLContext() {
if (status)
return NetErrorFromOSStatus(status);
+ // It is tricky to handle client cert request over renegotiation due to bugs
+ // in Secure Transport. From Ken McLeod on apple-cdsa:
+ // http://lists.apple.com/archives/apple-cdsa/2010/Feb/msg00058.html
+ // A possible workaround would be to set the
+ // kSSLSessionOptionBreakOnCertRequested option initially, then if you get
+ // that status, ask for a client cert, abort the connection yourself and
+ // retry it (this time calling SSLSetCertificate before the handshake
+ // starts, and *not* setting the kSSLSessionOptionBreakOnCertRequested
+ // option.)
if (ssl_config_.send_client_cert) {
- // Provide the client cert up-front if we have one, even though we'll get
- // notified later when the server requests it, and set it again; this is
- // seemingly redundant but works around a problem with SecureTransport
- // and provides correct behavior on both 10.5 and 10.6:
- // http://lists.apple.com/archives/apple-cdsa/2010/Feb/msg00058.html
- // http://code.google.com/p/chromium/issues/detail?id=38905
SSL_LOG << "Setting client cert in advance because send_client_cert is set";
status = SetClientCert();
if (status)
return NetErrorFromOSStatus(status);
+ return OK;
}
status = EnableBreakOnAuth(true);
@@ -1089,11 +1121,8 @@ int SSLClientSocketMac::DoHandshakeFinish() {
break;
case errSSLClientCertRequested:
SSL_LOG << "Server requested client cert (DoHandshakeFinish)";
- if (!ssl_config_.send_client_cert)
- return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
- // (We already called SetClientCert during InitializeSSLContext.)
- status = noErr;
- next_handshake_state_ = STATE_HANDSHAKE_FINISH;
+ DCHECK(!ssl_config_.send_client_cert);
+ return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
break;
case errSSLClosedGraceful:
return ERR_SSL_PROTOCOL_ERROR;
@@ -1128,16 +1157,7 @@ int SSLClientSocketMac::DoHandshakeFinish() {
}
void SSLClientSocketMac::HandshakeFinished() {
- // After the handshake's finished, disable breaking on server or client
- // auth. Otherwise it might be triggered during a subsequent renegotiation,
- // and SecureTransport doesn't handle that very well (there's usually no way
- // to proceed without aborting the connection, at least not on 10.5.)
SSL_LOG << "HandshakeFinished()";
- OSStatus status = EnableBreakOnAuth(false);
- if (status != noErr)
- SSL_LOG << "EnableBreakOnAuth failed: " << status;
- // Note- this will actually always return an error, up through OS 10.6.3,
- // because the option can't be changed after the context opens.
}
int SSLClientSocketMac::DoPayloadRead() {
@@ -1167,14 +1187,7 @@ int SSLClientSocketMac::DoPayloadRead() {
case errSSLClientCertRequested:
// Server wants to renegotiate, probably to ask for a client cert,
// but SecureTransport doesn't support renegotiation so we have to close.
- if (ssl_config_.send_client_cert) {
- // We already gave SecureTransport a client cert. At this point there's
- // nothing we can do; the renegotiation will fail regardless, due to
- // bugs in Apple's SecureTransport library.
- SSL_LOG << "Server renegotiating (status=" << status
- << "), but I've already set a client cert. Fatal error.";
- return ERR_SSL_PROTOCOL_ERROR;
- }
+ DCHECK(!ssl_config_.send_client_cert);
// Tell my caller the server wants a client cert so it can reconnect.
SSL_LOG << "Server renegotiating; assuming it wants a client cert...";
return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h
index dc2ed65..05b9735 100644
--- a/net/socket/ssl_client_socket_mac.h
+++ b/net/socket/ssl_client_socket_mac.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_MAC_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_MAC_H_
+#pragma once
#include <Security/Security.h>
@@ -25,7 +26,7 @@ class ClientSocketHandle;
// An SSL client socket implemented with Secure Transport.
class SSLClientSocketMac : public SSLClientSocket {
public:
- // Takes ownership of the transport_socket, which may already be connected.
+ // Takes ownership of the |transport_socket|, which must already be connected.
// The given hostname will be compared with the name(s) in the server's
// certificate during the SSL handshake. ssl_config specifies the SSL
// settings.
@@ -46,6 +47,9 @@ class SSLClientSocketMac : public SSLClientSocket {
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_mac_factory.h b/net/socket/ssl_client_socket_mac_factory.h
index dafc40f..2c793c2 100644
--- a/net/socket/ssl_client_socket_mac_factory.h
+++ b/net/socket/ssl_client_socket_mac_factory.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_MAC_FACTORY_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_MAC_FACTORY_H_
+#pragma once
#include "net/socket/client_socket_factory.h"
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 0a81a48..fb5668a 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -51,25 +51,33 @@
#include <dlfcn.h>
#endif
#include <certdb.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 <pk11pub.h>
#include "base/compiler_specific.h"
#include "base/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"
#include "net/base/address_list.h"
+#include "net/base/cert_status_flags.h"
#include "net/base/cert_verifier.h"
+#include "net/base/dns_util.h"
+#include "net/base/dnsrr_resolver.h"
+#include "net/base/dnssec_chain_verifier.h"
#include "net/base/io_buffer.h"
-#include "net/base/net_log.h"
#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_connection_status_flags.h"
#include "net/base/ssl_info.h"
@@ -182,6 +190,11 @@ int MapNSPRError(PRErrorCode err) {
return ERR_ADDRESS_UNREACHABLE;
case PR_ADDRESS_NOT_AVAILABLE_ERROR:
return ERR_ADDRESS_INVALID;
+ case PR_INVALID_ARGUMENT_ERROR:
+ return ERR_INVALID_ARGUMENT;
+
+ case SEC_ERROR_INVALID_ARGS:
+ return ERR_INVALID_ARGUMENT;
case SSL_ERROR_SSL_DISABLED:
return ERR_NO_SSL_VERSIONS_ENABLED;
@@ -198,6 +211,8 @@ int MapNSPRError(PRErrorCode err) {
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)) {
@@ -271,6 +286,40 @@ bool IsProblematicComodoEVCACert(const CERTCertificate& cert) {
cert.serialNumber.len) == 0;
}
+// This callback is intended to be used with CertFindChainInStore. In addition
+// to filtering by extended/enhanced key usage, we do not show expired
+// certificates and require digital signature usage in the key usage
+// extension.
+//
+// This matches our behavior on Mac OS X and that of NSS. It also matches the
+// default behavior of IE8. See http://support.microsoft.com/kb/890326 and
+// http://blogs.msdn.com/b/askie/archive/2009/06/09/my-expired-client-certificates-no-longer-display-when-connecting-to-my-web-server-using-ie8.aspx
+BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context,
+ void* find_arg) {
+ LOG(INFO) << "Calling ClientCertFindCallback from _nss";
+ // Verify the certificate's KU is good.
+ BYTE key_usage;
+ if (CertGetIntendedKeyUsage(X509_ASN_ENCODING, cert_context->pCertInfo,
+ &key_usage, 1)) {
+ if (!(key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE))
+ return FALSE;
+ } else {
+ DWORD err = GetLastError();
+ // If |err| is non-zero, it's an actual error. Otherwise the extension
+ // just isn't present, and we treat it as if everything was allowed.
+ if (err) {
+ DLOG(ERROR) << "CertGetIntendedKeyUsage failed: " << err;
+ return FALSE;
+ }
+ }
+
+ // Verify the current time is within the certificate's validity period.
+ if (CertVerifyTimeValidity(NULL, cert_context->pCertInfo) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
#endif
} // namespace
@@ -289,6 +338,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
this, &SSLClientSocketNSS::BufferRecvComplete)),
transport_send_busy_(false),
transport_recv_busy_(false),
+ corked_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_(
this, &SSLClientSocketNSS::OnHandshakeIOComplete)),
transport_(transport_socket),
@@ -303,6 +353,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
client_auth_cert_needed_(false),
handshake_callback_called_(false),
completed_handshake_(false),
+ dnssec_provider_(NULL),
next_handshake_state_(STATE_NONE),
nss_fd_(NULL),
nss_bufs_(NULL),
@@ -407,7 +458,7 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
/* Push SSL onto our fake I/O socket */
nss_fd_ = SSL_ImportFD(NULL, nss_fd_);
if (nss_fd_ == NULL) {
- return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR/NSS error code.
+ return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR/NSS error code.
}
// TODO(port): set more ssl options! Check errors!
@@ -415,11 +466,11 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE);
if (rv != SECSuccess)
- return ERR_UNEXPECTED;
+ return ERR_UNEXPECTED;
rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, ssl_config_.ssl2_enabled);
if (rv != SECSuccess)
- return ERR_UNEXPECTED;
+ return ERR_UNEXPECTED;
// SNI is enabled automatically if TLS is enabled -- as long as
// SSL_V2_COMPATIBLE_HELLO isn't.
@@ -459,13 +510,19 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
#endif
#ifdef SSL_ENABLE_FALSE_START
- rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_FALSE_START, PR_TRUE);
+ rv = SSL_OptionSet(
+ nss_fd_, SSL_ENABLE_FALSE_START,
+ ssl_config_.false_start_enabled &&
+ !SSLConfigService::IsKnownFalseStartIncompatibleServer(hostname_));
if (rv != SECSuccess)
- LOG(INFO) << "SSL_ENABLE_FALSE_START failed. Old system nss?";
+ LOG(INFO) << "SSL_ENABLE_FALSE_START failed. Old system nss?";
#endif
#ifdef SSL_ENABLE_RENEGOTIATION
- if (SSLConfigService::IsKnownStrictTLSServer(hostname_)) {
+ // Deliberately disable this check for now: http://crbug.com/55410
+ if (false &&
+ SSLConfigService::IsKnownStrictTLSServer(hostname_) &&
+ !ssl_config_.mitm_proxies_allowed) {
rv = SSL_OptionSet(nss_fd_, SSL_REQUIRE_SAFE_NEGOTIATION, PR_TRUE);
if (rv != SECSuccess)
LOG(INFO) << "SSL_REQUIRE_SAFE_NEGOTIATION failed.";
@@ -478,7 +535,7 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
// http://extendedsubset.com/?p=8
rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_RENEGOTIATION,
- SSL_RENEGOTIATE_UNRESTRICTED);
+ SSL_RENEGOTIATE_TRANSITIONAL);
}
if (rv != SECSuccess)
LOG(INFO) << "SSL_ENABLE_RENEGOTIATION failed.";
@@ -519,8 +576,8 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
// rather than the destination server's address in that case.
// TODO(wtc): port in |peer_address| is not the server's port when a proxy is
// used.
- std::string peer_id = StringPrintf("%s:%d", hostname_.c_str(),
- peer_address.GetPort());
+ std::string peer_id = base::StringPrintf("%s:%d", hostname_.c_str(),
+ peer_address.GetPort());
rv = SSL_SetSockPeerID(nss_fd_, const_cast<char*>(peer_id.c_str()));
if (rv != SECSuccess)
LOG(INFO) << "SSL_SetSockPeerID failed: peer_id=" << peer_id;
@@ -609,6 +666,30 @@ int SSLClientSocketNSS::GetPeerAddress(AddressList* address) const {
return transport_->socket()->GetPeerAddress(address);
}
+void SSLClientSocketNSS::SetSubresourceSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetSubresourceSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void SSLClientSocketNSS::SetOmniboxSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetOmniboxSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+bool SSLClientSocketNSS::WasEverUsed() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->WasEverUsed();
+ }
+ NOTREACHED();
+ return false;
+}
+
int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
EnterFunction(buf_len);
@@ -647,6 +728,7 @@ int SSLClientSocketNSS::Write(IOBuffer* buf, int buf_len,
user_write_buf_ = buf;
user_write_buf_len_ = buf_len;
+ corked_ = false;
int rv = DoWriteLoop(OK);
if (rv == ERR_IO_PENDING) {
@@ -862,6 +944,10 @@ SSLClientSocketNSS::GetNextProto(std::string* proto) {
#endif
}
+void SSLClientSocketNSS::UseDNSSEC(DNSSECProvider* provider) {
+ dnssec_provider_ = provider;
+}
+
void SSLClientSocketNSS::DoReadCallback(int rv) {
EnterFunction(rv);
DCHECK(rv != ERR_IO_PENDING);
@@ -1029,38 +1115,35 @@ bool SSLClientSocketNSS::DoTransportIO() {
// > 0 for bytes transferred immediately,
// < 0 for error (or the non-error ERR_IO_PENDING).
int SSLClientSocketNSS::BufferSend(void) {
- if (transport_send_busy_) return ERR_IO_PENDING;
+ if (transport_send_busy_)
+ return ERR_IO_PENDING;
- int nsent = 0;
EnterFunction("");
- // nss_bufs_ is a circular buffer. It may have two contiguous parts
- // (before and after the wrap). So this for loop needs two iterations.
- for (int i = 0; i < 2; ++i) {
- const char* buf;
- int nb = memio_GetWriteParams(nss_bufs_, &buf);
- if (!nb)
- break;
-
- scoped_refptr<IOBuffer> send_buffer = new IOBuffer(nb);
- memcpy(send_buffer->data(), buf, nb);
- int rv = transport_->socket()->Write(send_buffer, nb,
- &buffer_send_callback_);
+ const char* buf1;
+ const char* buf2;
+ unsigned int len1, len2;
+ memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2);
+ const unsigned int len = len1 + len2;
+
+ if (corked_ && len < kRecvBufferSize / 2)
+ return 0;
+
+ 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;
- break;
} else {
memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv));
- if (rv < 0) {
- // Return the error even if the previous Write succeeded.
- nsent = rv;
- break;
- }
- nsent += rv;
}
}
- LeaveFunction(nsent);
- return nsent;
+ LeaveFunction(rv);
+ return rv;
}
void SSLClientSocketNSS::BufferSendComplete(int result) {
@@ -1131,6 +1214,12 @@ int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) {
case STATE_HANDSHAKE:
rv = DoHandshake();
break;
+ case STATE_VERIFY_DNSSEC:
+ rv = DoVerifyDNSSEC(rv);
+ break;
+ case STATE_VERIFY_DNSSEC_COMPLETE:
+ rv = DoVerifyDNSSECComplete(rv);
+ break;
case STATE_VERIFY_CERT:
DCHECK(rv == OK);
rv = DoVerifyCert(rv);
@@ -1140,7 +1229,7 @@ int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) {
break;
default:
rv = ERR_UNEXPECTED;
- NOTREACHED() << "unexpected state";
+ LOG(DFATAL) << "unexpected state " << state;
break;
}
@@ -1160,8 +1249,10 @@ int SSLClientSocketNSS::DoReadLoop(int result) {
if (result < 0)
return result;
- if (!nss_bufs_)
+ if (!nss_bufs_) {
+ LOG(DFATAL) << "!nss_bufs_";
return ERR_UNEXPECTED;
+ }
bool network_moved;
int rv;
@@ -1182,8 +1273,10 @@ int SSLClientSocketNSS::DoWriteLoop(int result) {
if (result < 0)
return result;
- if (!nss_bufs_)
+ if (!nss_bufs_) {
+ LOG(DFATAL) << "!nss_bufs_";
return ERR_UNEXPECTED;
+ }
bool network_moved;
int rv;
@@ -1206,6 +1299,23 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
PRFileDesc* socket,
PRBool checksig,
PRBool is_server) {
+#ifdef SSL_ENABLE_FALSE_START
+ // In the event that we are False Starting this connection, we wish to send
+ // out the Finished message and first application data record in the same
+ // packet. This prevents non-determinism when talking to False Start
+ // intolerant servers which, otherwise, might see the two messages in
+ // different reads or not, depending on network conditions.
+ PRBool false_start = 0;
+ SECStatus rv = SSL_OptionGet(socket, SSL_ENABLE_FALSE_START, &false_start);
+ if (rv != SECSuccess)
+ NOTREACHED();
+ if (false_start) {
+ SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
+ if (!that->handshake_callback_called_)
+ that->corked_ = true;
+ }
+#endif
+
// Tell NSS to not verify the certificate.
return SECSuccess;
}
@@ -1255,6 +1365,7 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
find_by_issuer_para.cIssuer = ca_names->nnames;
find_by_issuer_para.rgIssuer = ca_names->nnames ? &issuer_list[0] : NULL;
+ find_by_issuer_para.pfnFindCallback = ClientCertFindCallback;
PCCERT_CHAIN_CONTEXT chain_context = NULL;
@@ -1335,16 +1446,14 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
// handshake by returning ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
return SECWouldBlock;
#else
- CERTCertificate* cert = NULL;
- SECKEYPrivateKey* privkey = NULL;
void* wincx = SSL_RevealPinArg(socket);
// Second pass: a client certificate should have been selected.
if (that->ssl_config_.send_client_cert) {
if (that->ssl_config_.client_cert) {
- cert = CERT_DupCertificate(
+ CERTCertificate* cert = CERT_DupCertificate(
that->ssl_config_.client_cert->os_cert_handle());
- privkey = PK11_FindKeyByAnyCert(cert, wincx);
+ SECKEYPrivateKey* privkey = PK11_FindKeyByAnyCert(cert, wincx);
if (privkey) {
// TODO(jsorianopastor): We should wait for server certificate
// verification before sending our credentials. See
@@ -1359,33 +1468,32 @@ SECStatus SSLClientSocketNSS::ClientAuthHandler(
return SECFailure;
}
- CERTCertNicknames* names = CERT_GetCertNicknames(
- CERT_GetDefaultCertDB(), SEC_CERT_NICKNAMES_USER, wincx);
- if (names) {
- for (int i = 0; i < names->numnicknames; ++i) {
- cert = CERT_FindUserCertByUsage(
- CERT_GetDefaultCertDB(), names->nicknames[i],
- certUsageSSLClient, PR_FALSE, wincx);
- if (!cert)
+ // Iterate over all client certificates.
+ CERTCertList* client_certs = CERT_FindUserCertsByUsage(
+ CERT_GetDefaultCertDB(), certUsageSSLClient,
+ PR_FALSE, PR_FALSE, wincx);
+ if (client_certs) {
+ for (CERTCertListNode* node = CERT_LIST_HEAD(client_certs);
+ !CERT_LIST_END(node, client_certs);
+ node = CERT_LIST_NEXT(node)) {
+ // Only offer unexpired certificates.
+ if (CERT_CheckCertValidTimes(node->cert, PR_Now(), PR_TRUE) !=
+ secCertTimeValid)
continue;
- // Only check unexpired certs.
- if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) ==
- secCertTimeValid && (!ca_names->nnames ||
- NSS_CmpCertChainWCANames(cert, ca_names) == SECSuccess)) {
- privkey = PK11_FindKeyByAnyCert(cert, wincx);
- if (privkey) {
- X509Certificate* x509_cert = X509Certificate::CreateFromHandle(
- cert, X509Certificate::SOURCE_LONE_CERT_IMPORT,
- net::X509Certificate::OSCertHandles());
- that->client_certs_.push_back(x509_cert);
- CERT_DestroyCertificate(cert);
- SECKEY_DestroyPrivateKey(privkey);
- continue;
- }
- }
- CERT_DestroyCertificate(cert);
+ // Filter by issuer.
+ //
+ // TODO(davidben): This does a binary comparison of the DER-encoded
+ // issuers. We should match according to RFC 5280 sec. 7.1. We should find
+ // an appropriate NSS function or add one if needbe.
+ if (ca_names->nnames &&
+ NSS_CmpCertChainWCANames(node->cert, ca_names) != SECSuccess)
+ continue;
+ X509Certificate* x509_cert = X509Certificate::CreateFromHandle(
+ node->cert, X509Certificate::SOURCE_LONE_CERT_IMPORT,
+ net::X509Certificate::OSCertHandles());
+ that->client_certs_.push_back(x509_cert);
}
- CERT_FreeNicknames(names);
+ CERT_DestroyCertList(client_certs);
}
// Tell NSS to suspend the client authentication. We will then abort the
@@ -1427,7 +1535,7 @@ int SSLClientSocketNSS::DoHandshake() {
} else if (rv == SECSuccess) {
if (handshake_callback_called_) {
// SSL handshake is completed. Let's verify the certificate.
- GotoState(STATE_VERIFY_CERT);
+ GotoState(STATE_VERIFY_DNSSEC);
// Done!
} else {
// SSL_ForceHandshake returned SECSuccess prematurely.
@@ -1451,25 +1559,229 @@ int SSLClientSocketNSS::DoHandshake() {
return net_error;
}
+// DNSValidationResult enumerates the possible outcomes from processing a
+// set of DNS records.
+enum DNSValidationResult {
+ DNSVR_SUCCESS, // the cert is immediately acceptable.
+ DNSVR_FAILURE, // the cert is unconditionally rejected.
+ DNSVR_CONTINUE, // perform CA validation as usual.
+};
+
+// VerifyTXTRecords processes the RRDATA for a number of DNS TXT records and
+// checks them against the given certificate.
+// dnssec: if true then the TXT records are DNSSEC validated. In this case,
+// DNSVR_SUCCESS may be returned.
+// server_cert_nss: the certificate to validate
+// rrdatas: the TXT records for the current domain.
+static DNSValidationResult VerifyTXTRecords(
+ bool dnssec,
+ CERTCertificate* server_cert_nss,
+ const std::vector<base::StringPiece>& rrdatas) {
+ bool found_well_formed_record = false;
+ bool matched_record = false;
+
+ for (std::vector<base::StringPiece>::const_iterator
+ i = rrdatas.begin(); i != rrdatas.end(); ++i) {
+ std::map<std::string, std::string> m(
+ DNSSECChainVerifier::ParseTLSTXTRecord(*i));
+ if (m.empty())
+ continue;
+
+ std::map<std::string, std::string>::const_iterator j;
+ j = m.find("v");
+ if (j == m.end() || j->second != "tls1")
+ continue;
+
+ j = m.find("ha");
+
+ HASH_HashType hash_algorithm;
+ unsigned hash_length;
+ if (j == m.end() || j->second == "sha1") {
+ hash_algorithm = HASH_AlgSHA1;
+ hash_length = SHA1_LENGTH;
+ } else if (j->second == "sha256") {
+ hash_algorithm = HASH_AlgSHA256;
+ hash_length = SHA256_LENGTH;
+ } else {
+ continue;
+ }
+
+ j = m.find("h");
+ if (j == m.end())
+ continue;
+
+ std::vector<uint8> given_hash;
+ if (!base::HexStringToBytes(j->second, &given_hash))
+ continue;
+
+ if (given_hash.size() != hash_length)
+ continue;
+
+ uint8 calculated_hash[SHA256_LENGTH]; // SHA256 is the largest.
+ SECStatus rv;
+
+ j = m.find("hr");
+ if (j == m.end() || j->second == "pubkey") {
+ rv = HASH_HashBuf(hash_algorithm, calculated_hash,
+ server_cert_nss->derPublicKey.data,
+ server_cert_nss->derPublicKey.len);
+ } else if (j->second == "cert") {
+ rv = HASH_HashBuf(hash_algorithm, calculated_hash,
+ server_cert_nss->derCert.data,
+ server_cert_nss->derCert.len);
+ } else {
+ continue;
+ }
+
+ if (rv != SECSuccess)
+ NOTREACHED();
+
+ found_well_formed_record = true;
+
+ if (memcmp(calculated_hash, &given_hash[0], hash_length) == 0) {
+ matched_record = true;
+ if (dnssec)
+ return DNSVR_SUCCESS;
+ }
+ }
+
+ if (found_well_formed_record && !matched_record)
+ return DNSVR_FAILURE;
+
+ return DNSVR_CONTINUE;
+}
+
+
+// CheckDNSSECChain tries to validate a DNSSEC chain embedded in
+// |server_cert_nss_|. It returns true iff a chain is found that proves the
+// value of a TXT record that contains a valid public key fingerprint.
+static DNSValidationResult CheckDNSSECChain(
+ const std::string& hostname,
+ CERTCertificate* server_cert_nss) {
+ if (!server_cert_nss)
+ return DNSVR_CONTINUE;
+
+ // CERT_FindCertExtensionByOID isn't exported so we have to install an OID,
+ // get a tag for it and find the extension by using that tag.
+ static SECOidTag dnssec_chain_tag;
+ static bool dnssec_chain_tag_valid;
+ if (!dnssec_chain_tag_valid) {
+ // It's harmless if multiple threads enter this block concurrently.
+ static const uint8 kDNSSECChainOID[] =
+ // 1.3.6.1.4.1.11129.13172
+ // (iso.org.dod.internet.private.enterprises.google.13172)
+ {0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0xe6, 0x74};
+ SECOidData oid_data;
+ memset(&oid_data, 0, sizeof(oid_data));
+ oid_data.oid.data = const_cast<uint8*>(kDNSSECChainOID);
+ oid_data.oid.len = sizeof(kDNSSECChainOID);
+ oid_data.desc = "DNSSEC chain";
+ oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION;
+ dnssec_chain_tag = SECOID_AddEntry(&oid_data);
+ DCHECK_NE(SEC_OID_UNKNOWN, dnssec_chain_tag);
+ dnssec_chain_tag_valid = true;
+ }
+
+ SECItem dnssec_embedded_chain;
+ SECStatus rv = CERT_FindCertExtension(server_cert_nss,
+ dnssec_chain_tag, &dnssec_embedded_chain);
+ if (rv != SECSuccess)
+ return DNSVR_CONTINUE;
+
+ base::StringPiece chain(
+ reinterpret_cast<char*>(dnssec_embedded_chain.data),
+ dnssec_embedded_chain.len);
+ std::string dns_hostname;
+ if (!DNSDomainFromDot(hostname, &dns_hostname))
+ return DNSVR_CONTINUE;
+ DNSSECChainVerifier verifier(dns_hostname, chain);
+ DNSSECChainVerifier::Error err = verifier.Verify();
+ if (err != DNSSECChainVerifier::OK) {
+ LOG(ERROR) << "DNSSEC chain verification failed: " << err;
+ return DNSVR_CONTINUE;
+ }
+
+ if (verifier.rrtype() != kDNS_TXT)
+ return DNSVR_CONTINUE;
+
+ DNSValidationResult r = VerifyTXTRecords(
+ true /* DNSSEC verified */, server_cert_nss, verifier.rrdatas());
+ SECITEM_FreeItem(&dnssec_embedded_chain, PR_FALSE);
+ return r;
+}
+
+int SSLClientSocketNSS::DoVerifyDNSSEC(int result) {
+ if (ssl_config_.dnssec_enabled) {
+ DNSValidationResult r = CheckDNSSECChain(hostname_, server_cert_nss_);
+ if (r == DNSVR_SUCCESS) {
+ server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+ GotoState(STATE_VERIFY_CERT_COMPLETE);
+ return OK;
+ }
+ }
+
+ if (dnssec_provider_ == NULL) {
+ GotoState(STATE_VERIFY_CERT);
+ return OK;
+ }
+
+ GotoState(STATE_VERIFY_DNSSEC_COMPLETE);
+ RRResponse* response;
+ dnssec_wait_start_time_ = base::Time::Now();
+ return dnssec_provider_->GetDNSSECRecords(&response, &handshake_io_callback_);
+}
+
+int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) {
+ RRResponse* response;
+ int err = dnssec_provider_->GetDNSSECRecords(&response, NULL);
+ DCHECK_EQ(err, OK);
+
+ const base::TimeDelta elapsed = base::Time::Now() - dnssec_wait_start_time_;
+ HISTOGRAM_TIMES("Net.DNSSECWaitTime", elapsed);
+
+ GotoState(STATE_VERIFY_CERT);
+ if (!response || response->rrdatas.empty())
+ return OK;
+
+ std::vector<base::StringPiece> records;
+ records.resize(response->rrdatas.size());
+ for (unsigned i = 0; i < response->rrdatas.size(); i++)
+ records[i] = base::StringPiece(response->rrdatas[i]);
+ DNSValidationResult r =
+ VerifyTXTRecords(response->dnssec, server_cert_nss_, records);
+
+ if (!ssl_config_.dnssec_enabled) {
+ // If DNSSEC is not enabled we don't take any action based on the result,
+ // except to record the latency, above.
+ return OK;
+ }
+
+ switch (r) {
+ case DNSVR_FAILURE:
+ GotoState(STATE_VERIFY_CERT_COMPLETE);
+ server_cert_verify_result_.cert_status |= CERT_STATUS_NOT_IN_DNS;
+ return ERR_CERT_NOT_IN_DNS;
+ case DNSVR_CONTINUE:
+ GotoState(STATE_VERIFY_CERT);
+ break;
+ case DNSVR_SUCCESS:
+ server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+ GotoState(STATE_VERIFY_CERT_COMPLETE);
+ break;
+ default:
+ NOTREACHED();
+ GotoState(STATE_VERIFY_CERT);
+ }
+
+ return OK;
+}
+
int SSLClientSocketNSS::DoVerifyCert(int result) {
DCHECK(server_cert_);
GotoState(STATE_VERIFY_CERT_COMPLETE);
int flags = 0;
- /* Disable revocation checking for SPDY. This is a hack, but we ignore
- * certificate errors for SPDY anyway so it's no loss in security. This lets
- * us benchmark as if we had OCSP stapling.
- *
- * http://crbug.com/32020
- */
- unsigned char buf[255];
- int state;
- unsigned int len;
- SECStatus rv = SSL_GetNextProto(nss_fd_, &state, buf, &len, sizeof(buf));
- bool spdy = (rv == SECSuccess && state == SSL_NEXT_PROTO_NEGOTIATED &&
- len == 4 && memcmp(buf, "spdy", 4) == 0);
-
- if (ssl_config_.rev_checking_enabled && !spdy)
+ if (ssl_config_.rev_checking_enabled)
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
if (ssl_config_.verify_ev_cert)
flags |= X509Certificate::VERIFY_EV_CERT;
@@ -1482,7 +1794,6 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
// Derived from AuthCertificateCallback() in
// mozilla/source/security/manager/ssl/src/nsNSSCallbacks.cpp.
int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
- DCHECK(verifier_.get());
verifier_.reset();
if (result == OK) {
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 60544ea..3796826 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_
+#pragma once
#include <certt.h>
#include <keyt.h>
@@ -14,6 +15,7 @@
#include <vector>
#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/net_log.h"
@@ -32,7 +34,7 @@ class X509Certificate;
// An SSL client socket implemented with Mozilla NSS.
class SSLClientSocketNSS : public SSLClientSocket {
public:
- // Takes ownership of the transport_socket, which may already be connected.
+ // Takes ownership of the |transport_socket|, which must already be connected.
// The given hostname will be compared with the name(s) in the server's
// certificate during the SSL handshake. ssl_config specifies the SSL
// settings.
@@ -45,6 +47,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual void GetSSLInfo(SSLInfo* ssl_info);
virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
virtual NextProtoStatus GetNextProto(std::string* proto);
+ virtual void UseDNSSEC(DNSSECProvider*);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -53,6 +56,9 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
@@ -85,6 +91,9 @@ class SSLClientSocketNSS : public SSLClientSocket {
int DoWriteLoop(int result);
int DoHandshake();
+
+ int DoVerifyDNSSEC(int result);
+ int DoVerifyDNSSECComplete(int result);
int DoVerifyCert(int result);
int DoVerifyCertComplete(int result);
int DoPayloadRead();
@@ -115,6 +124,9 @@ class SSLClientSocketNSS : public SSLClientSocket {
CompletionCallbackImpl<SSLClientSocketNSS> buffer_recv_callback_;
bool transport_send_busy_;
bool transport_recv_busy_;
+ // corked_ is true if we are currently suspending writes to the network. This
+ // is named after the similar kernel flag, TCP_CORK.
+ bool corked_;
scoped_refptr<IOBuffer> recv_buffer_;
CompletionCallbackImpl<SSLClientSocketNSS> handshake_io_callback_;
@@ -154,9 +166,16 @@ class SSLClientSocketNSS : public SSLClientSocket {
// True if the SSL handshake has been completed.
bool completed_handshake_;
+ // This pointer is owned by the caller of UseDNSSEC.
+ DNSSECProvider* dnssec_provider_;
+ // The time when we started waiting for DNSSEC records.
+ base::Time dnssec_wait_start_time_;
+
enum State {
STATE_NONE,
STATE_HANDSHAKE,
+ STATE_VERIFY_DNSSEC,
+ STATE_VERIFY_DNSSEC_COMPLETE,
STATE_VERIFY_CERT,
STATE_VERIFY_CERT_COMPLETE,
};
diff --git a/net/socket/ssl_client_socket_nss_factory.cc b/net/socket/ssl_client_socket_nss_factory.cc
index 99fb632..30de930 100644
--- a/net/socket/ssl_client_socket_nss_factory.cc
+++ b/net/socket/ssl_client_socket_nss_factory.cc
@@ -25,7 +25,7 @@ SSLClientSocket* SSLClientSocketNSSFactory(
// CryptoAPI yet (http://crbug.com/37560), so we fall back on
// SSLClientSocketWin.
#if defined(OS_WIN)
- if (ssl_config.client_cert)
+ if (ssl_config.send_client_cert)
return new SSLClientSocketWin(transport_socket, hostname, ssl_config);
#endif
diff --git a/net/socket/ssl_client_socket_nss_factory.h b/net/socket/ssl_client_socket_nss_factory.h
index b3b99b9..f977109 100644
--- a/net/socket/ssl_client_socket_nss_factory.h
+++ b/net/socket/ssl_client_socket_nss_factory.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_NSS_FACTORY_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_NSS_FACTORY_H_
+#pragma once
#include "net/socket/client_socket_factory.h"
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 3fd960c..ea9d04b 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -4,21 +4,31 @@
#include "net/socket/ssl_client_socket_pool.h"
+#include "base/values.h"
+#include "net/base/dnsrr_resolver.h"
+#include "net/base/dns_util.h"
#include "net/base/net_errors.h"
+#include "net/base/ssl_cert_request_info.h"
+#include "net/http/http_proxy_client_socket.h"
+#include "net/http/http_proxy_client_socket_pool.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_handle.h"
+#include "net/socket/socks_client_socket_pool.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/tcp_client_socket_pool.h"
namespace net {
SSLSocketParams::SSLSocketParams(
const scoped_refptr<TCPSocketParams>& tcp_params,
- const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
const scoped_refptr<SOCKSSocketParams>& socks_params,
+ const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
ProxyServer::Scheme proxy,
const std::string& hostname,
const SSLConfig& ssl_config,
int load_flags,
- bool want_spdy)
+ bool force_spdy_over_ssl,
+ bool want_spdy_over_npn)
: tcp_params_(tcp_params),
http_proxy_params_(http_proxy_params),
socks_params_(socks_params),
@@ -26,7 +36,11 @@ SSLSocketParams::SSLSocketParams(
hostname_(hostname),
ssl_config_(ssl_config),
load_flags_(load_flags),
- want_spdy_(want_spdy) {
+ force_spdy_over_ssl_(force_spdy_over_ssl),
+ want_spdy_over_npn_(want_spdy_over_npn),
+ dnssec_resolution_attempted_(false),
+ dnssec_resolution_complete_(false),
+ dnssec_resolution_callback_(NULL) {
switch (proxy_) {
case ProxyServer::SCHEME_DIRECT:
DCHECK(tcp_params_.get() != NULL);
@@ -34,6 +48,7 @@ SSLSocketParams::SSLSocketParams(
DCHECK(socks_params_.get() == NULL);
break;
case ProxyServer::SCHEME_HTTP:
+ case ProxyServer::SCHEME_HTTPS:
DCHECK(tcp_params_.get() == NULL);
DCHECK(http_proxy_params_.get() != NULL);
DCHECK(socks_params_.get() == NULL);
@@ -52,6 +67,61 @@ SSLSocketParams::SSLSocketParams(
SSLSocketParams::~SSLSocketParams() {}
+void SSLSocketParams::StartDNSSECResolution() {
+ dnssec_response_.reset(new RRResponse);
+ // We keep a reference to ourselves while the DNS resolution is underway.
+ // When it completes (in DNSSECResolutionComplete), we balance it out.
+ AddRef();
+
+ dnssec_resolution_attempted_ = true;
+ bool r = DnsRRResolver::Resolve(
+ hostname(), kDNS_TXT, DnsRRResolver::FLAG_WANT_DNSSEC,
+ NewCallback(this, &SSLSocketParams::DNSSECResolutionComplete),
+ dnssec_response_.get());
+ if (!r) {
+ dnssec_response_.reset();
+ dnssec_resolution_attempted_ = false;
+ }
+}
+
+void SSLSocketParams::DNSSECResolutionComplete(int rv) {
+ CompletionCallback* callback = NULL;
+ {
+ DCHECK(dnssec_resolution_attempted_);
+ DCHECK(!dnssec_resolution_complete_);
+
+ if (rv != OK)
+ dnssec_response_.reset();
+
+ dnssec_resolution_complete_ = true;
+ if (dnssec_resolution_callback_)
+ callback = dnssec_resolution_callback_;
+ }
+
+ if (callback)
+ callback->Run(OK);
+
+ Release();
+}
+
+int SSLSocketParams::GetDNSSECRecords(RRResponse** out,
+ CompletionCallback* callback) {
+ if (!dnssec_resolution_attempted_) {
+ *out = NULL;
+ return OK;
+ }
+
+ if (dnssec_resolution_complete_) {
+ *out = dnssec_response_.get();
+ return OK;
+ }
+
+ DCHECK(dnssec_resolution_callback_ == NULL);
+
+ dnssec_resolution_callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
// Timeout for the SSL handshake portion of the connect.
static const int kSSLHandshakeTimeoutInSeconds = 30;
@@ -59,9 +129,9 @@ SSLConnectJob::SSLConnectJob(
const std::string& group_name,
const scoped_refptr<SSLSocketParams>& params,
const base::TimeDelta& timeout_duration,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
- const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
- const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
+ TCPClientSocketPool* tcp_pool,
+ SOCKSClientSocketPool* socks_pool,
+ HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
const scoped_refptr<HostResolver>& host_resolver,
Delegate* delegate,
@@ -70,8 +140,8 @@ SSLConnectJob::SSLConnectJob(
BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
params_(params),
tcp_pool_(tcp_pool),
- http_proxy_pool_(http_proxy_pool),
socks_pool_(socks_pool),
+ http_proxy_pool_(http_proxy_pool),
client_socket_factory_(client_socket_factory),
resolver_(host_resolver),
ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -101,16 +171,12 @@ LoadState SSLConnectJob::GetLoadState() const {
}
int SSLConnectJob::ConnectInternal() {
- DetermineFirstState();
- return DoLoop(OK);
-}
-
-void SSLConnectJob::DetermineFirstState() {
switch (params_->proxy()) {
case ProxyServer::SCHEME_DIRECT:
next_state_ = STATE_TCP_CONNECT;
break;
case ProxyServer::SCHEME_HTTP:
+ case ProxyServer::SCHEME_HTTPS:
next_state_ = STATE_TUNNEL_CONNECT;
break;
case ProxyServer::SCHEME_SOCKS4:
@@ -121,6 +187,7 @@ void SSLConnectJob::DetermineFirstState() {
NOTREACHED() << "unknown proxy type";
break;
}
+ return DoLoop(OK);
}
void SSLConnectJob::OnIOComplete(int result) {
@@ -176,7 +243,11 @@ int SSLConnectJob::DoLoop(int result) {
}
int SSLConnectJob::DoTCPConnect() {
- DCHECK(tcp_pool_.get());
+ DCHECK(tcp_pool_);
+
+ if (SSLConfigService::dnssec_enabled())
+ params_->StartDNSSECResolution();
+
next_state_ = STATE_TCP_CONNECT_COMPLETE;
transport_socket_handle_.reset(new ClientSocketHandle());
scoped_refptr<TCPSocketParams> tcp_params = params_->tcp_params();
@@ -193,7 +264,7 @@ int SSLConnectJob::DoTCPConnectComplete(int result) {
}
int SSLConnectJob::DoSOCKSConnect() {
- DCHECK(socks_pool_.get());
+ DCHECK(socks_pool_);
next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
transport_socket_handle_.reset(new ClientSocketHandle());
scoped_refptr<SOCKSSocketParams> socks_params = params_->socks_params();
@@ -210,14 +281,15 @@ int SSLConnectJob::DoSOCKSConnectComplete(int result) {
}
int SSLConnectJob::DoTunnelConnect() {
- DCHECK(http_proxy_pool_.get());
+ DCHECK(http_proxy_pool_);
next_state_ = STATE_TUNNEL_CONNECT_COMPLETE;
+
transport_socket_handle_.reset(new ClientSocketHandle());
scoped_refptr<HttpProxySocketParams> http_proxy_params =
params_->http_proxy_params();
return transport_socket_handle_->Init(
group_name(), http_proxy_params,
- http_proxy_params->tcp_params()->destination().priority(), &callback_,
+ http_proxy_params->destination().priority(), &callback_,
http_proxy_pool_, net_log());
}
@@ -226,12 +298,6 @@ int SSLConnectJob::DoTunnelConnectComplete(int result) {
HttpProxyClientSocket* tunnel_socket =
static_cast<HttpProxyClientSocket*>(socket);
- if (result == ERR_RETRY_CONNECTION) {
- DetermineFirstState();
- transport_socket_handle_->socket()->Disconnect();
- return OK;
- }
-
// Extract the information needed to prompt for the proxy authentication.
// so that when ClientSocketPoolBaseHelper calls |GetAdditionalErrorState|,
// we can easily set the state.
@@ -241,19 +307,17 @@ int SSLConnectJob::DoTunnelConnectComplete(int result) {
if (result < 0)
return result;
- if (tunnel_socket->NeedsRestartWithAuth()) {
- // We must have gotten an 'idle' tunnel socket that is waiting for auth.
- // The HttpAuthController should have new credentials, we just need
- // to retry.
- next_state_ = STATE_TUNNEL_CONNECT_COMPLETE;
- return tunnel_socket->RestartWithAuth(&callback_);
- }
-
next_state_ = STATE_SSL_CONNECT;
return result;
}
void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle * handle) {
+ // Headers in |error_response_info_| indicate a proxy tunnel setup
+ // problem. See DoTunnelConnectComplete.
+ if (error_response_info_.headers) {
+ handle->set_pending_http_proxy_connection(
+ transport_socket_handle_.release());
+ }
handle->set_ssl_error_response_info(error_response_info_);
if (!ssl_connect_start_time_.is_null())
handle->set_is_ssl_error(true);
@@ -268,6 +332,8 @@ int SSLConnectJob::DoSSLConnect() {
ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket(
transport_socket_handle_.release(), params_->hostname(),
params_->ssl_config()));
+ if (SSLConfigService::dnssec_enabled())
+ ssl_socket_->UseDNSSEC(params_.get());
return ssl_socket_->Connect(&callback_);
}
@@ -281,17 +347,26 @@ int SSLConnectJob::DoSSLConnectComplete(int result) {
if (result == OK || IsCertificateError(result))
status = ssl_socket_->GetNextProto(&proto);
- bool using_spdy = false;
+ // If we want spdy over npn, make sure it succeeded.
if (status == SSLClientSocket::kNextProtoNegotiated) {
- ssl_socket_->setWasNpnNegotiated(true);
- if (SSLClientSocket::NextProtoFromString(proto) ==
- SSLClientSocket::kProtoSPDY1) {
- using_spdy = true;
+ ssl_socket_->set_was_npn_negotiated(true);
+ SSLClientSocket::NextProto next_protocol =
+ SSLClientSocket::NextProtoFromString(proto);
+ // If we negotiated either version of SPDY, we must have
+ // advertised it, so allow it.
+ // TODO(mbelshe): verify it was a protocol we advertised?
+ if (next_protocol == SSLClientSocket::kProtoSPDY1 ||
+ next_protocol == SSLClientSocket::kProtoSPDY2) {
+ ssl_socket_->set_was_spdy_negotiated(true);
}
}
- if (params_->want_spdy() && !using_spdy)
+ if (params_->want_spdy_over_npn() && !ssl_socket_->was_spdy_negotiated())
return ERR_NPN_NEGOTIATION_FAILED;
+ // Spdy might be turned on by default, or it might be over npn.
+ bool using_spdy = params_->force_spdy_over_ssl() ||
+ params_->want_spdy_over_npn();
+
if (result == OK ||
ssl_socket_->IgnoreCertError(result, params_->load_flags())) {
DCHECK(ssl_connect_start_time_ != base::TimeTicks());
@@ -326,21 +401,21 @@ ConnectJob* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob(
const PoolBase::Request& request,
ConnectJob::Delegate* delegate) const {
return new SSLConnectJob(group_name, request.params(), ConnectionTimeout(),
- tcp_pool_, http_proxy_pool_, socks_pool_,
+ tcp_pool_, socks_pool_, http_proxy_pool_,
client_socket_factory_, host_resolver_, delegate,
net_log_);
}
SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
- const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
- const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
+ TCPClientSocketPool* tcp_pool,
+ SOCKSClientSocketPool* socks_pool,
+ HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
HostResolver* host_resolver,
NetLog* net_log)
: tcp_pool_(tcp_pool),
- http_proxy_pool_(http_proxy_pool),
socks_pool_(socks_pool),
+ http_proxy_pool_(http_proxy_pool),
client_socket_factory_(client_socket_factory),
host_resolver_(host_resolver),
net_log_(net_log) {
@@ -365,22 +440,33 @@ SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
SSLClientSocketPool::SSLClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
const scoped_refptr<HostResolver>& host_resolver,
ClientSocketFactory* client_socket_factory,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
- const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
- const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
+ TCPClientSocketPool* tcp_pool,
+ SOCKSClientSocketPool* socks_pool,
+ HttpProxyClientSocketPool* http_proxy_pool,
+ SSLConfigService* ssl_config_service,
NetLog* net_log)
- : base_(max_sockets, max_sockets_per_group, histograms,
+ : tcp_pool_(tcp_pool),
+ socks_pool_(socks_pool),
+ http_proxy_pool_(http_proxy_pool),
+ base_(max_sockets, max_sockets_per_group, histograms,
base::TimeDelta::FromSeconds(
ClientSocketPool::unused_idle_socket_timeout()),
base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
- new SSLConnectJobFactory(tcp_pool, http_proxy_pool, socks_pool,
+ new SSLConnectJobFactory(tcp_pool, socks_pool, http_proxy_pool,
client_socket_factory, host_resolver,
- net_log)) {}
+ net_log)),
+ ssl_config_service_(ssl_config_service) {
+ if (ssl_config_service_)
+ ssl_config_service_->AddObserver(this);
+}
-SSLClientSocketPool::~SSLClientSocketPool() {}
+SSLClientSocketPool::~SSLClientSocketPool() {
+ if (ssl_config_service_)
+ ssl_config_service_->RemoveObserver(this);
+}
int SSLClientSocketPool::RequestSocket(const std::string& group_name,
const void* socket_params,
@@ -423,4 +509,35 @@ LoadState SSLClientSocketPool::GetLoadState(
return base_.GetLoadState(group_name, handle);
}
+void SSLClientSocketPool::OnSSLConfigChanged() {
+ Flush();
+}
+
+DictionaryValue* SSLClientSocketPool::GetInfoAsValue(
+ const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const {
+ DictionaryValue* dict = base_.GetInfoAsValue(name, type);
+ if (include_nested_pools) {
+ ListValue* list = new ListValue();
+ if (tcp_pool_) {
+ list->Append(tcp_pool_->GetInfoAsValue("tcp_socket_pool",
+ "tcp_socket_pool",
+ false));
+ }
+ if (socks_pool_) {
+ list->Append(socks_pool_->GetInfoAsValue("socks_pool",
+ "socks_pool",
+ true));
+ }
+ if (http_proxy_pool_) {
+ list->Append(http_proxy_pool_->GetInfoAsValue("http_proxy_pool",
+ "http_proxy_pool",
+ true));
+ }
+ dict->Set("nested_pools", list);
+ }
+ return dict;
+}
+
} // namespace net
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index fd5bbb3..d84d147 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_POOL_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_POOL_H_
+#pragma once
#include <string>
@@ -12,37 +13,43 @@
#include "base/time.h"
#include "net/base/host_resolver.h"
#include "net/base/ssl_config_service.h"
-#include "net/http/http_proxy_client_socket.h"
-#include "net/http/http_proxy_client_socket_pool.h"
+#include "net/http/http_response_info.h"
#include "net/proxy/proxy_server.h"
-#include "net/socket/client_socket_factory.h"
+#include "net/socket/ssl_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"
-#include "net/socket/socks_client_socket_pool.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/socket/tcp_client_socket_pool.h"
namespace net {
class ClientSocketFactory;
class ConnectJobFactory;
+class HttpProxyClientSocketPool;
+class HttpProxySocketParams;
+class SOCKSClientSocketPool;
+class SOCKSSocketParams;
+class SSLClientSocket;
+class TCPClientSocketPool;
+class TCPSocketParams;
+struct RRResponse;
// SSLSocketParams only needs the socket params for the transport socket
// that will be used (denoted by |proxy|).
-class SSLSocketParams : public base::RefCounted<SSLSocketParams> {
+class SSLSocketParams : public base::RefCounted<SSLSocketParams>,
+ public DNSSECProvider {
public:
SSLSocketParams(const scoped_refptr<TCPSocketParams>& tcp_params,
- const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
const scoped_refptr<SOCKSSocketParams>& socks_params,
+ const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
ProxyServer::Scheme proxy,
const std::string& hostname,
const SSLConfig& ssl_config,
int load_flags,
- bool want_spdy);
+ bool force_spdy_over_ssl,
+ bool want_spdy_over_npn);
const scoped_refptr<TCPSocketParams>& tcp_params() { return tcp_params_; }
- const scoped_refptr<HttpProxySocketParams>& http_proxy_params () {
+ const scoped_refptr<HttpProxySocketParams>& http_proxy_params() {
return http_proxy_params_;
}
const scoped_refptr<SOCKSSocketParams>& socks_params() {
@@ -52,11 +59,18 @@ class SSLSocketParams : public base::RefCounted<SSLSocketParams> {
const std::string& hostname() const { return hostname_; }
const SSLConfig& ssl_config() const { return ssl_config_; }
int load_flags() const { return load_flags_; }
- bool want_spdy() const { return want_spdy_; }
+ bool force_spdy_over_ssl() const { return force_spdy_over_ssl_; }
+ bool want_spdy_over_npn() const { return want_spdy_over_npn_; }
+ // Start to resolve DNSSEC records for the given hostname.
+ void StartDNSSECResolution();
+
+ // DNSSECProvider implementation.
+ virtual int GetDNSSECRecords(RRResponse** out, CompletionCallback* callback);
private:
friend class base::RefCounted<SSLSocketParams>;
~SSLSocketParams();
+ void DNSSECResolutionComplete(int rv);
const scoped_refptr<TCPSocketParams> tcp_params_;
const scoped_refptr<HttpProxySocketParams> http_proxy_params_;
@@ -65,7 +79,15 @@ class SSLSocketParams : public base::RefCounted<SSLSocketParams> {
const std::string hostname_;
const SSLConfig ssl_config_;
const int load_flags_;
- const bool want_spdy_;
+ const bool force_spdy_over_ssl_;
+ const bool want_spdy_over_npn_;
+
+ // This is true if we have started a DNSSEC resolution.
+ bool dnssec_resolution_attempted_;
+ // This is true if |dnssec_response_| is valid.
+ bool dnssec_resolution_complete_;
+ scoped_ptr<RRResponse> dnssec_response_;
+ CompletionCallback* dnssec_resolution_callback_;
DISALLOW_COPY_AND_ASSIGN(SSLSocketParams);
};
@@ -78,9 +100,9 @@ class SSLConnectJob : public ConnectJob {
const std::string& group_name,
const scoped_refptr<SSLSocketParams>& params,
const base::TimeDelta& timeout_duration,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
- const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
- const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
+ TCPClientSocketPool* tcp_pool,
+ SOCKSClientSocketPool* socks_pool,
+ HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
const scoped_refptr<HostResolver>& host_resolver,
Delegate* delegate,
@@ -110,8 +132,6 @@ class SSLConnectJob : public ConnectJob {
// Otherwise, it returns a net error code.
virtual int ConnectInternal();
- void DetermineFirstState();
-
void OnIOComplete(int result);
// Runs the state transition loop.
@@ -127,9 +147,9 @@ class SSLConnectJob : public ConnectJob {
int DoSSLConnectComplete(int result);
scoped_refptr<SSLSocketParams> params_;
- const scoped_refptr<TCPClientSocketPool> tcp_pool_;
- const scoped_refptr<HttpProxyClientSocketPool> http_proxy_pool_;
- const scoped_refptr<SOCKSClientSocketPool> socks_pool_;
+ TCPClientSocketPool* const tcp_pool_;
+ SOCKSClientSocketPool* const socks_pool_;
+ HttpProxyClientSocketPool* const http_proxy_pool_;
ClientSocketFactory* const client_socket_factory_;
const scoped_refptr<HostResolver> resolver_;
@@ -146,21 +166,25 @@ class SSLConnectJob : public ConnectJob {
DISALLOW_COPY_AND_ASSIGN(SSLConnectJob);
};
-class SSLClientSocketPool : public ClientSocketPool {
+class SSLClientSocketPool : public ClientSocketPool,
+ public SSLConfigService::Observer {
public:
// Only the pools that will be used are required. i.e. if you never
// try to create an SSL over SOCKS socket, |socks_pool| may be NULL.
SSLClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
const scoped_refptr<HostResolver>& host_resolver,
ClientSocketFactory* client_socket_factory,
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
- const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
- const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
+ TCPClientSocketPool* tcp_pool,
+ SOCKSClientSocketPool* socks_pool,
+ HttpProxyClientSocketPool* http_proxy_pool,
+ SSLConfigService* ssl_config_service,
NetLog* net_log);
+ virtual ~SSLClientSocketPool();
+
// ClientSocketPool methods:
virtual int RequestSocket(const std::string& group_name,
const void* connect_params,
@@ -189,26 +213,33 @@ class SSLClientSocketPool : public ClientSocketPool {
virtual LoadState GetLoadState(const std::string& group_name,
const ClientSocketHandle* handle) const;
+ virtual DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const;
+
virtual base::TimeDelta ConnectionTimeout() const {
return base_.ConnectionTimeout();
}
- virtual scoped_refptr<ClientSocketPoolHistograms> histograms() const {
+ virtual ClientSocketPoolHistograms* histograms() const {
return base_.histograms();
};
- protected:
- virtual ~SSLClientSocketPool();
-
private:
+ // SSLConfigService::Observer methods:
+
+ // When the user changes the SSL config, we flush all idle sockets so they
+ // won't get re-used.
+ virtual void OnSSLConfigChanged();
+
typedef ClientSocketPoolBase<SSLSocketParams> PoolBase;
class SSLConnectJobFactory : public PoolBase::ConnectJobFactory {
public:
SSLConnectJobFactory(
- const scoped_refptr<TCPClientSocketPool>& tcp_pool,
- const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
- const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
+ TCPClientSocketPool* tcp_pool,
+ SOCKSClientSocketPool* socks_pool,
+ HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
HostResolver* host_resolver,
NetLog* net_log);
@@ -224,9 +255,9 @@ class SSLClientSocketPool : public ClientSocketPool {
virtual base::TimeDelta ConnectionTimeout() const { return timeout_; }
private:
- const scoped_refptr<TCPClientSocketPool> tcp_pool_;
- const scoped_refptr<HttpProxyClientSocketPool> http_proxy_pool_;
- const scoped_refptr<SOCKSClientSocketPool> socks_pool_;
+ TCPClientSocketPool* const tcp_pool_;
+ SOCKSClientSocketPool* const socks_pool_;
+ HttpProxyClientSocketPool* const http_proxy_pool_;
ClientSocketFactory* const client_socket_factory_;
const scoped_refptr<HostResolver> host_resolver_;
base::TimeDelta timeout_;
@@ -235,7 +266,11 @@ class SSLClientSocketPool : public ClientSocketPool {
DISALLOW_COPY_AND_ASSIGN(SSLConnectJobFactory);
};
+ TCPClientSocketPool* const tcp_pool_;
+ SOCKSClientSocketPool* const socks_pool_;
+ HttpProxyClientSocketPool* const http_proxy_pool_;
PoolBase base_;
+ const scoped_refptr<SSLConfigService> ssl_config_service_;
DISALLOW_COPY_AND_ASSIGN(SSLClientSocketPool);
};
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 972f7d8..feac473 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -6,13 +6,15 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "net/base/auth.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/base/ssl_config_service_defaults.h"
-#include "net/http/http_auth_controller.h"
+#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
@@ -20,6 +22,7 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_histograms.h"
#include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_session_pool.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -29,91 +32,117 @@ namespace {
const int kMaxSockets = 32;
const int kMaxSocketsPerGroup = 6;
-class SSLClientSocketPoolTest : public ClientSocketPoolTest {
+class SSLClientSocketPoolTest : public testing::Test {
protected:
SSLClientSocketPoolTest()
- : direct_tcp_socket_params_(new TCPSocketParams(
+ : host_resolver_(new MockHostResolver),
+ http_auth_handler_factory_(HttpAuthHandlerFactory::CreateDefault(
+ host_resolver_)),
+ session_(new HttpNetworkSession(host_resolver_,
+ ProxyService::CreateDirect(),
+ &socket_factory_,
+ new SSLConfigServiceDefaults,
+ new SpdySessionPool(NULL),
+ http_auth_handler_factory_.get(),
+ NULL,
+ NULL)),
+ direct_tcp_socket_params_(new TCPSocketParams(
HostPortPair("host", 443), MEDIUM, GURL(), false)),
- tcp_socket_pool_(new MockTCPClientSocketPool(
+ tcp_histograms_("MockTCP"),
+ tcp_socket_pool_(
kMaxSockets,
kMaxSocketsPerGroup,
- make_scoped_refptr(new ClientSocketPoolHistograms("MockTCP")),
- &socket_factory_)),
+ &tcp_histograms_,
+ &socket_factory_),
proxy_tcp_socket_params_(new TCPSocketParams(
HostPortPair("proxy", 443), MEDIUM, GURL(), false)),
- http_proxy_socket_pool_(new HttpProxyClientSocketPool(
- kMaxSockets,
- kMaxSocketsPerGroup,
- make_scoped_refptr(new ClientSocketPoolHistograms("MockHttpProxy")),
- new MockHostResolver,
- tcp_socket_pool_,
- NULL)),
socks_socket_params_(new SOCKSSocketParams(
proxy_tcp_socket_params_, true, HostPortPair("sockshost", 443),
MEDIUM, GURL())),
- socks_socket_pool_(new MockSOCKSClientSocketPool(
+ socks_histograms_("MockSOCKS"),
+ socks_socket_pool_(
+ kMaxSockets,
+ kMaxSocketsPerGroup,
+ &socks_histograms_,
+ &tcp_socket_pool_),
+ http_proxy_socket_params_(new HttpProxySocketParams(
+ proxy_tcp_socket_params_, NULL, GURL("http://host"), "",
+ HostPortPair("host", 80),
+ session_->auth_cache(),
+ session_->http_auth_handler_factory(),
+ true)),
+ http_proxy_histograms_("MockHttpProxy"),
+ http_proxy_socket_pool_(
kMaxSockets,
kMaxSocketsPerGroup,
- make_scoped_refptr(new ClientSocketPoolHistograms("MockSOCKS")),
- tcp_socket_pool_)) {
+ &http_proxy_histograms_,
+ new MockHostResolver,
+ &tcp_socket_pool_,
+ NULL,
+ NULL) {
scoped_refptr<SSLConfigService> ssl_config_service(
new SSLConfigServiceDefaults);
ssl_config_service->GetSSLConfig(&ssl_config_);
}
void CreatePool(bool tcp_pool, bool http_proxy_pool, bool socks_pool) {
- pool_ = new SSLClientSocketPool(
+ ssl_histograms_.reset(new ClientSocketPoolHistograms("SSLUnitTest"));
+ pool_.reset(new SSLClientSocketPool(
kMaxSockets,
kMaxSocketsPerGroup,
- make_scoped_refptr(new ClientSocketPoolHistograms("SSLUnitTest")),
+ ssl_histograms_.get(),
NULL,
&socket_factory_,
- tcp_pool ? tcp_socket_pool_ : NULL,
- http_proxy_pool ? http_proxy_socket_pool_ : NULL,
- socks_pool ? socks_socket_pool_ : NULL,
- NULL);
+ tcp_pool ? &tcp_socket_pool_ : NULL,
+ socks_pool ? &socks_socket_pool_ : NULL,
+ http_proxy_pool ? &http_proxy_socket_pool_ : NULL,
+ NULL,
+ NULL));
}
- scoped_refptr<SSLSocketParams> SSLParams(
- ProxyServer::Scheme proxy, struct MockHttpAuthControllerData* auth_data,
- size_t auth_data_len, bool want_spdy) {
-
- scoped_refptr<HttpProxySocketParams> http_proxy_params;
- if (proxy == ProxyServer::SCHEME_HTTP) {
- scoped_refptr<MockHttpAuthController> auth_controller =
- new MockHttpAuthController();
- auth_controller->SetMockAuthControllerData(auth_data, auth_data_len);
- http_proxy_params = new HttpProxySocketParams(proxy_tcp_socket_params_,
- GURL("http://host"),
- HostPortPair("host", 80),
- auth_controller, true);
- }
-
+ scoped_refptr<SSLSocketParams> SSLParams(ProxyServer::Scheme proxy,
+ bool want_spdy_over_npn) {
return make_scoped_refptr(new SSLSocketParams(
proxy == ProxyServer::SCHEME_DIRECT ? direct_tcp_socket_params_ : NULL,
- http_proxy_params,
proxy == ProxyServer::SCHEME_SOCKS5 ? socks_socket_params_ : NULL,
+ proxy == ProxyServer::SCHEME_HTTP ? http_proxy_socket_params_ : NULL,
proxy,
"host",
ssl_config_,
0,
- want_spdy));
+ false,
+ want_spdy_over_npn));
+ }
+
+ void AddAuthToCache() {
+ const string16 kFoo(ASCIIToUTF16("foo"));
+ const string16 kBar(ASCIIToUTF16("bar"));
+ session_->auth_cache()->Add(GURL("http://proxy:443/"), "MyRealm1", "Basic",
+ "Basic realm=MyRealm1", kFoo, kBar, "/");
}
MockClientSocketFactory socket_factory_;
+ scoped_refptr<HostResolver> host_resolver_;
+ scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_;
+ scoped_refptr<HttpNetworkSession> session_;
scoped_refptr<TCPSocketParams> direct_tcp_socket_params_;
- scoped_refptr<MockTCPClientSocketPool> tcp_socket_pool_;
+ ClientSocketPoolHistograms tcp_histograms_;
+ MockTCPClientSocketPool tcp_socket_pool_;
scoped_refptr<TCPSocketParams> proxy_tcp_socket_params_;
- scoped_refptr<HttpProxySocketParams> http_proxy_socket_params_;
- scoped_refptr<HttpProxyClientSocketPool> http_proxy_socket_pool_;
scoped_refptr<SOCKSSocketParams> socks_socket_params_;
- scoped_refptr<MockSOCKSClientSocketPool> socks_socket_pool_;
+ ClientSocketPoolHistograms socks_histograms_;
+ MockSOCKSClientSocketPool socks_socket_pool_;
+
+ scoped_refptr<HttpProxySocketParams> http_proxy_socket_params_;
+ ClientSocketPoolHistograms http_proxy_histograms_;
+ HttpProxyClientSocketPool http_proxy_socket_pool_;
SSLConfig ssl_config_;
- scoped_refptr<SSLClientSocketPool> pool_;
+ scoped_ptr<ClientSocketPoolHistograms> ssl_histograms_;
+ scoped_ptr<SSLClientSocketPool> pool_;
};
TEST_F(SSLClientSocketPoolTest, TCPFail) {
@@ -123,10 +152,10 @@ TEST_F(SSLClientSocketPoolTest, TCPFail) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
- int rv = handle.Init("a", params, MEDIUM, NULL, pool_, BoundNetLog());
+ int rv = handle.Init("a", params, MEDIUM, NULL, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_CONNECTION_FAILED, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -140,11 +169,12 @@ TEST_F(SSLClientSocketPoolTest, TCPFailAsync) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -164,11 +194,12 @@ TEST_F(SSLClientSocketPoolTest, BasicDirect) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
@@ -182,11 +213,12 @@ TEST_F(SSLClientSocketPoolTest, BasicDirectAsync) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -204,11 +236,12 @@ TEST_F(SSLClientSocketPoolTest, DirectCertError) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -226,11 +259,12 @@ TEST_F(SSLClientSocketPoolTest, DirectSSLError) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -251,11 +285,12 @@ TEST_F(SSLClientSocketPoolTest, DirectWithNPN) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -264,7 +299,7 @@ TEST_F(SSLClientSocketPoolTest, DirectWithNPN) {
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(handle.socket());
- EXPECT_TRUE(ssl_socket->wasNpnNegotiated());
+ EXPECT_TRUE(ssl_socket->was_npn_negotiated());
}
TEST_F(SSLClientSocketPoolTest, DirectNoSPDY) {
@@ -277,11 +312,12 @@ TEST_F(SSLClientSocketPoolTest, DirectNoSPDY) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, true);
+ true);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -297,16 +333,17 @@ TEST_F(SSLClientSocketPoolTest, DirectGotSPDY) {
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(true, OK);
ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- ssl.next_proto = "spdy/1";
+ ssl.next_proto = "spdy/2";
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, true);
+ true);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -316,11 +353,11 @@ TEST_F(SSLClientSocketPoolTest, DirectGotSPDY) {
EXPECT_TRUE(handle.socket());
SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(handle.socket());
- EXPECT_TRUE(ssl_socket->wasNpnNegotiated());
+ EXPECT_TRUE(ssl_socket->was_npn_negotiated());
std::string proto;
ssl_socket->GetNextProto(&proto);
EXPECT_EQ(SSLClientSocket::NextProtoFromString(proto),
- SSLClientSocket::kProtoSPDY1);
+ SSLClientSocket::kProtoSPDY2);
}
TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) {
@@ -328,16 +365,17 @@ TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) {
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(true, OK);
ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- ssl.next_proto = "spdy/1";
+ ssl.next_proto = "spdy/2";
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT,
- NULL, 0, false);
+ true);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -347,11 +385,11 @@ TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) {
EXPECT_TRUE(handle.socket());
SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(handle.socket());
- EXPECT_TRUE(ssl_socket->wasNpnNegotiated());
+ EXPECT_TRUE(ssl_socket->was_npn_negotiated());
std::string proto;
ssl_socket->GetNextProto(&proto);
EXPECT_EQ(SSLClientSocket::NextProtoFromString(proto),
- SSLClientSocket::kProtoSPDY1);
+ SSLClientSocket::kProtoSPDY2);
}
TEST_F(SSLClientSocketPoolTest, SOCKSFail) {
@@ -361,11 +399,12 @@ TEST_F(SSLClientSocketPoolTest, SOCKSFail) {
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_CONNECTION_FAILED, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -379,11 +418,12 @@ TEST_F(SSLClientSocketPoolTest, SOCKSFailAsync) {
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -403,11 +443,12 @@ TEST_F(SSLClientSocketPoolTest, SOCKSBasic) {
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
@@ -421,11 +462,12 @@ TEST_F(SSLClientSocketPoolTest, SOCKSBasicAsync) {
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -442,12 +484,13 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyFail) {
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
- EXPECT_EQ(ERR_CONNECTION_FAILED, rv);
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
+ EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
@@ -460,16 +503,17 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyFailAsync) {
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP,
- NULL, 0, false);
+ false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult());
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
@@ -481,7 +525,7 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasic) {
"CONNECT host:80 HTTP/1.1\r\n"
"Host: host\r\n"
"Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
MockRead reads[] = {
MockRead(false, "HTTP/1.1 200 Connection Established\r\n\r\n"),
@@ -490,21 +534,18 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasic) {
arraysize(writes));
data.set_connect_data(MockConnect(false, OK));
socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
+ AddAuthToCache();
SSLSocketDataProvider ssl(false, OK);
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP,
- auth_data,
- arraysize(auth_data),
false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(OK, rv);
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
@@ -515,7 +556,7 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasicAsync) {
MockWrite("CONNECT host:80 HTTP/1.1\r\n"
"Host: host\r\n"
"Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
MockRead reads[] = {
MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
@@ -523,21 +564,18 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasicAsync) {
StaticSocketDataProvider data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
+ AddAuthToCache();
SSLSocketDataProvider ssl(true, OK);
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP,
- auth_data,
- arraysize(auth_data),
false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -562,69 +600,17 @@ TEST_F(SSLClientSocketPoolTest, NeedProxyAuth) {
StaticSocketDataProvider data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData(""),
- };
- SSLSocketDataProvider ssl(true, OK);
- socket_factory_.AddSSLSocketDataProvider(&ssl);
-
- CreatePool(false, true /* http proxy pool */, true /* socks pool */);
- scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP,
- auth_data,
- arraysize(auth_data),
- false);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
-
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult());
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
- EXPECT_FALSE(handle.is_ssl_error());
- const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info();
- EXPECT_EQ(tunnel_info.headers->response_code(), 407);
-}
-
-TEST_F(SSLClientSocketPoolTest, DoProxyAuth) {
- MockWrite writes[] = {
- MockWrite("CONNECT host:80 HTTP/1.1\r\n"
- "Host: host\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("CONNECT host:80 HTTP/1.1\r\n"
- "Host: host\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
- };
- MockRead reads[] = {
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead("0123456789"),
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- };
- StaticSocketDataProvider data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&data);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData(""),
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
SSLSocketDataProvider ssl(true, OK);
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(false, true /* http proxy pool */, true /* socks pool */);
scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP,
- auth_data,
- arraysize(auth_data),
false);
ClientSocketHandle handle;
TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
+ int rv = handle.Init(
+ "a", params, MEDIUM, &callback, pool_.get(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -635,85 +621,10 @@ TEST_F(SSLClientSocketPoolTest, DoProxyAuth) {
EXPECT_FALSE(handle.is_ssl_error());
const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info();
EXPECT_EQ(tunnel_info.headers->response_code(), 407);
-
- params->http_proxy_params()->auth_controller()->ResetAuth(std::wstring(),
- std::wstring());
- rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
-
- // Test that http://crbug.com/49325 doesn't regress.
- EXPECT_EQ(handle.GetLoadState(), LOAD_STATE_ESTABLISHING_PROXY_TUNNEL);
-
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_TRUE(handle.is_initialized());
- EXPECT_TRUE(handle.socket());
-}
-
-TEST_F(SSLClientSocketPoolTest, DoProxyAuthNoKeepAlive) {
- MockWrite writes1[] = {
- MockWrite("CONNECT host:80 HTTP/1.1\r\n"
- "Host: host\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockWrite writes2[] = {
- MockWrite("CONNECT host:80 HTTP/1.1\r\n"
- "Host: host\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
- };
- MockRead reads1[] = {
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"),
- MockRead("Content0123456789"),
- };
- MockRead reads2[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- };
- StaticSocketDataProvider data1(reads1, arraysize(reads1), writes1,
- arraysize(writes1));
- socket_factory_.AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(reads2, arraysize(reads2), writes2,
- arraysize(writes2));
- socket_factory_.AddSocketDataProvider(&data2);
- MockHttpAuthControllerData auth_data[] = {
- MockHttpAuthControllerData(""),
- MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="),
- };
- SSLSocketDataProvider ssl(true, OK);
- socket_factory_.AddSSLSocketDataProvider(&ssl);
-
- CreatePool(false, true /* http proxy pool */, true /* socks pool */);
- scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP,
- auth_data,
- arraysize(auth_data),
- false);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
-
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult());
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
- EXPECT_FALSE(handle.is_ssl_error());
- const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info();
- EXPECT_EQ(tunnel_info.headers->response_code(), 407);
-
- params->http_proxy_params()->auth_controller()->ResetAuth(std::wstring(),
- std::wstring());
- rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
-
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_TRUE(handle.is_initialized());
- EXPECT_TRUE(handle.socket());
+ scoped_ptr<ClientSocketHandle> tunnel_handle(
+ handle.release_pending_http_proxy_connection());
+ EXPECT_TRUE(tunnel_handle->socket());
+ EXPECT_FALSE(tunnel_handle->socket()->IsConnected());
}
// It would be nice to also test the timeouts in SSLClientSocketPool.
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index a62927e..70540f9 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -27,59 +27,37 @@ class SSLClientSocketTest : public PlatformTest {
public:
SSLClientSocketTest()
: resolver_(net::CreateSystemHostResolver(
- net::HostResolver::kDefaultParallelism)),
+ net::HostResolver::kDefaultParallelism,
+ NULL)),
socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) {
}
- void StartOKServer() {
- bool success = server_.Start(net::TestServerLauncher::ProtoHTTP,
- server_.kHostName, server_.kOKHTTPSPort,
- FilePath(), server_.GetOKCertPath(), std::wstring());
- ASSERT_TRUE(success);
- }
-
- void StartMismatchedServer() {
- bool success = server_.Start(net::TestServerLauncher::ProtoHTTP,
- server_.kMismatchedHostName, server_.kOKHTTPSPort,
- FilePath(), server_.GetOKCertPath(), std::wstring());
- ASSERT_TRUE(success);
- }
-
- void StartExpiredServer() {
- bool success = server_.Start(net::TestServerLauncher::ProtoHTTP,
- server_.kHostName, server_.kBadHTTPSPort,
- FilePath(), server_.GetExpiredCertPath(), std::wstring());
- ASSERT_TRUE(success);
- }
-
protected:
scoped_refptr<net::HostResolver> resolver_;
net::ClientSocketFactory* socket_factory_;
- net::TestServerLauncher server_;
};
//-----------------------------------------------------------------------------
TEST_F(SSLClientSocketTest, Connect) {
- StartOKServer();
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
+ ASSERT_TRUE(test_server.Start());
net::AddressList addr;
- TestCompletionCallback callback;
-
- net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver_->Resolve(info, &addr, NULL, NULL, net::BoundNetLog());
- EXPECT_EQ(net::OK, rv);
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
+ TestCompletionCallback callback;
net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
- net::ClientSocket* transport = new net::TCPClientSocket(addr, &log);
- rv = transport->Connect(&callback);
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, &log, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(transport,
- server_.kHostName, kDefaultSSLConfig));
+ test_server.host_port_pair().host(), kDefaultSSLConfig));
EXPECT_FALSE(sock->IsConnected());
@@ -105,25 +83,25 @@ TEST_F(SSLClientSocketTest, Connect) {
}
TEST_F(SSLClientSocketTest, ConnectExpired) {
- StartExpiredServer();
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE,
+ FilePath());
+ ASSERT_TRUE(test_server.Start());
net::AddressList addr;
- TestCompletionCallback callback;
-
- net::HostResolver::RequestInfo info(server_.kHostName, server_.kBadHTTPSPort);
- int rv = resolver_->Resolve(info, &addr, NULL, NULL, net::BoundNetLog());
- EXPECT_EQ(net::OK, rv);
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
+ TestCompletionCallback callback;
net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
- net::ClientSocket* transport = new net::TCPClientSocket(addr, &log);
- rv = transport->Connect(&callback);
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, &log, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(transport,
- server_.kHostName, kDefaultSSLConfig));
+ test_server.host_port_pair().host(), kDefaultSSLConfig));
EXPECT_FALSE(sock->IsConnected());
@@ -149,26 +127,25 @@ TEST_F(SSLClientSocketTest, ConnectExpired) {
}
TEST_F(SSLClientSocketTest, ConnectMismatched) {
- StartMismatchedServer();
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME,
+ FilePath());
+ ASSERT_TRUE(test_server.Start());
net::AddressList addr;
- TestCompletionCallback callback;
-
- net::HostResolver::RequestInfo info(server_.kMismatchedHostName,
- server_.kOKHTTPSPort);
- int rv = resolver_->Resolve(info, &addr, NULL, NULL, net::BoundNetLog());
- EXPECT_EQ(net::OK, rv);
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
+ TestCompletionCallback callback;
net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
- net::ClientSocket* transport = new net::TCPClientSocket(addr, &log);
- rv = transport->Connect(&callback);
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, &log, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(transport,
- server_.kMismatchedHostName, kDefaultSSLConfig));
+ test_server.host_port_pair().host(), kDefaultSSLConfig));
EXPECT_FALSE(sock->IsConnected());
@@ -194,33 +171,129 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) {
log.entries(), -1, net::NetLog::TYPE_SSL_CONNECT));
}
+// Attempt to connect to a page which requests a client certificate. It should
+// return an error code on connect.
+TEST_F(SSLClientSocketTest, FLAKY_ConnectClientAuthCertRequested) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH,
+ FilePath());
+ ASSERT_TRUE(test_server.Start());
+
+ net::AddressList addr;
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
+
+ TestCompletionCallback callback;
+ net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, &log, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
+ if (rv == net::ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_EQ(net::OK, rv);
+
+ scoped_ptr<net::SSLClientSocket> sock(
+ socket_factory_->CreateSSLClientSocket(transport,
+ test_server.host_port_pair().host(), kDefaultSSLConfig));
+
+ EXPECT_FALSE(sock->IsConnected());
+
+ rv = sock->Connect(&callback);
+ EXPECT_TRUE(net::LogContainsBeginEvent(
+ log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ if (rv != net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+ ASSERT_EQ(net::ERR_IO_PENDING, rv);
+ EXPECT_FALSE(sock->IsConnected());
+ EXPECT_FALSE(net::LogContainsEndEvent(
+ log.entries(), -1, net::NetLog::TYPE_SSL_CONNECT));
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ }
+
+ // 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(net::LogContainsEndEvent(
+ log.entries(), -1, net::NetLog::TYPE_SSL_CONNECT));
+}
+
+// Connect to a server requesting optional client authentication. Send it a
+// null certificate. It should allow the connection.
+//
+// TODO(davidben): Also test providing an actual certificate.
+TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH,
+ FilePath());
+ ASSERT_TRUE(test_server.Start());
+
+ net::AddressList addr;
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
+
+ TestCompletionCallback callback;
+ net::CapturingNetLog log(net::CapturingNetLog::kUnbounded);
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, &log, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
+ if (rv == net::ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_EQ(net::OK, rv);
+
+ net::SSLConfig ssl_config = kDefaultSSLConfig;
+ ssl_config.send_client_cert = true;
+ ssl_config.client_cert = NULL;
+
+ scoped_ptr<net::SSLClientSocket> sock(
+ socket_factory_->CreateSSLClientSocket(transport,
+ test_server.host_port_pair().host(), 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);
+ EXPECT_TRUE(net::LogContainsBeginEvent(
+ log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ if (rv != net::OK) {
+ ASSERT_EQ(net::ERR_IO_PENDING, rv);
+ EXPECT_FALSE(sock->IsConnected());
+ EXPECT_FALSE(net::LogContainsEndEvent(
+ log.entries(), -1, net::NetLog::TYPE_SSL_CONNECT));
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(net::OK, rv);
+ }
+
+ EXPECT_TRUE(sock->IsConnected());
+ EXPECT_TRUE(net::LogContainsEndEvent(
+ log.entries(), -1, net::NetLog::TYPE_SSL_CONNECT));
+
+ sock->Disconnect();
+ EXPECT_FALSE(sock->IsConnected());
+}
+
// TODO(wtc): Add unit tests for IsConnectedAndIdle:
// - Server closes an SSL connection (with a close_notify alert message).
// - Server closes the underlying TCP connection directly.
// - Server sends data unexpectedly.
TEST_F(SSLClientSocketTest, Read) {
- StartOKServer();
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
+ ASSERT_TRUE(test_server.Start());
net::AddressList addr;
- TestCompletionCallback callback;
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
- net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver_->Resolve(info, &addr, &callback, NULL, net::BoundNetLog());
- EXPECT_EQ(net::ERR_IO_PENDING, rv);
-
- rv = callback.WaitForResult();
- EXPECT_EQ(net::OK, rv);
-
- net::ClientSocket* transport = new net::TCPClientSocket(addr, NULL);
- rv = transport->Connect(&callback);
+ TestCompletionCallback callback;
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, NULL, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(transport,
- server_.kHostName,
+ test_server.host_port_pair().host(),
kDefaultSSLConfig));
rv = sock->Connect(&callback);
@@ -261,28 +334,25 @@ TEST_F(SSLClientSocketTest, Read) {
// Test the full duplex mode, with Read and Write pending at the same time.
// This test also serves as a regression test for http://crbug.com/29815.
TEST_F(SSLClientSocketTest, Read_FullDuplex) {
- StartOKServer();
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
+ ASSERT_TRUE(test_server.Start());
net::AddressList addr;
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
+
TestCompletionCallback callback; // Used for everything except Write.
TestCompletionCallback callback2; // Used for Write only.
- net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver_->Resolve(info, &addr, &callback, NULL, net::BoundNetLog());
- EXPECT_EQ(net::ERR_IO_PENDING, rv);
-
- rv = callback.WaitForResult();
- EXPECT_EQ(net::OK, rv);
-
- net::ClientSocket* transport = new net::TCPClientSocket(addr, NULL);
- rv = transport->Connect(&callback);
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, NULL, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(transport,
- server_.kHostName,
+ test_server.host_port_pair().host(),
kDefaultSSLConfig));
rv = sock->Connect(&callback);
@@ -324,24 +394,23 @@ TEST_F(SSLClientSocketTest, Read_FullDuplex) {
}
TEST_F(SSLClientSocketTest, Read_SmallChunks) {
- StartOKServer();
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
+ ASSERT_TRUE(test_server.Start());
net::AddressList addr;
- TestCompletionCallback callback;
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
- net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver_->Resolve(info, &addr, NULL, NULL, net::BoundNetLog());
- EXPECT_EQ(net::OK, rv);
-
- net::ClientSocket* transport = new net::TCPClientSocket(addr, NULL);
- rv = transport->Connect(&callback);
+ TestCompletionCallback callback;
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, NULL, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(transport,
- server_.kHostName, kDefaultSSLConfig));
+ test_server.host_port_pair().host(), kDefaultSSLConfig));
rv = sock->Connect(&callback);
if (rv != net::OK) {
@@ -378,24 +447,23 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) {
}
TEST_F(SSLClientSocketTest, Read_Interrupted) {
- StartOKServer();
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
+ ASSERT_TRUE(test_server.Start());
net::AddressList addr;
- TestCompletionCallback callback;
-
- net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver_->Resolve(info, &addr, NULL, NULL, net::BoundNetLog());
- EXPECT_EQ(net::OK, rv);
+ ASSERT_TRUE(test_server.GetAddressList(&addr));
- net::ClientSocket* transport = new net::TCPClientSocket(addr, NULL);
- rv = transport->Connect(&callback);
+ TestCompletionCallback callback;
+ net::ClientSocket* transport = new net::TCPClientSocket(
+ addr, NULL, net::NetLog::Source());
+ int rv = transport->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(transport,
- server_.kHostName, kDefaultSSLConfig));
+ test_server.host_port_pair().host(), kDefaultSSLConfig));
rv = sock->Connect(&callback);
if (rv != net::OK) {
@@ -430,6 +498,9 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) {
// Regression test for http://crbug.com/42538
TEST_F(SSLClientSocketTest, PrematureApplicationData) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
net::AddressList addr;
TestCompletionCallback callback;
@@ -465,7 +536,7 @@ TEST_F(SSLClientSocketTest, PrematureApplicationData) {
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(
- transport, server_.kHostName, kDefaultSSLConfig));
+ transport, test_server.host_port_pair().host(), kDefaultSSLConfig));
rv = sock->Connect(&callback);
EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc
index 0484ebd..1146fdf 100644
--- a/net/socket/ssl_client_socket_win.cc
+++ b/net/socket/ssl_client_socket_win.cc
@@ -5,12 +5,14 @@
#include "net/socket/ssl_client_socket_win.h"
#include <schnlsp.h>
+#include <map>
#include "base/compiler_specific.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"
#include "net/base/cert_verifier.h"
#include "net/base/connection_type_histograms.h"
#include "net/base/io_buffer.h"
@@ -61,6 +63,7 @@ static int MapSecurityError(SECURITY_STATUS err) {
return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
case SEC_E_INVALID_HANDLE:
case SEC_E_INVALID_TOKEN:
+ LOG(ERROR) << "Unexpected error " << err;
return ERR_UNEXPECTED;
case SEC_E_OK:
return OK;
@@ -253,6 +256,41 @@ static CredHandle* GetCredHandle(PCCERT_CONTEXT client_cert,
//-----------------------------------------------------------------------------
+// This callback is intended to be used with CertFindChainInStore. In addition
+// to filtering by extended/enhanced key usage, we do not show expired
+// certificates and require digital signature usage in the key usage
+// extension.
+//
+// This matches our behavior on Mac OS X and that of NSS. It also matches the
+// default behavior of IE8. See http://support.microsoft.com/kb/890326 and
+// http://blogs.msdn.com/b/askie/archive/2009/06/09/my-expired-client-certificates-no-longer-display-when-connecting-to-my-web-server-using-ie8.aspx
+static BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context,
+ void* find_arg) {
+ // Verify the certificate's KU is good.
+ BYTE key_usage;
+ if (CertGetIntendedKeyUsage(X509_ASN_ENCODING, cert_context->pCertInfo,
+ &key_usage, 1)) {
+ if (!(key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE))
+ return FALSE;
+ } else {
+ DWORD err = GetLastError();
+ // If |err| is non-zero, it's an actual error. Otherwise the extension
+ // just isn't present, and we treat it as if everything was allowed.
+ if (err) {
+ DLOG(ERROR) << "CertGetIntendedKeyUsage failed: " << err;
+ return FALSE;
+ }
+ }
+
+ // Verify the current time is within the certificate's validity period.
+ if (CertVerifyTimeValidity(NULL, cert_context->pCertInfo) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+
// A memory certificate store for client certificates. This allows us to
// close the "MY" system certificate store when we finish searching for
// client certificates.
@@ -353,6 +391,23 @@ void SSLClientSocketWin::GetSSLInfo(SSLInfo* ssl_info) {
// normalized.
ssl_info->security_bits = connection_info.dwCipherStrength;
}
+ // SecPkgContext_CipherInfo comes from CNG and is available on Vista or
+ // later only. On XP, the next QueryContextAttributes call fails with
+ // SEC_E_UNSUPPORTED_FUNCTION (0x80090302), so ssl_info->connection_status
+ // won't contain the cipher suite. If this is a problem, we can build the
+ // cipher suite from the aiCipher, aiHash, and aiExch fields of
+ // SecPkgContext_ConnectionInfo based on Appendix C of RFC 5246.
+ SecPkgContext_CipherInfo cipher_info = { SECPKGCONTEXT_CIPHERINFO_V1 };
+ status = QueryContextAttributes(
+ &ctxt_, SECPKG_ATTR_CIPHER_INFO, &cipher_info);
+ if (status == SEC_E_OK) {
+ // TODO(wtc): find out what the cipher_info.dwBaseCipherSuite field is.
+ ssl_info->connection_status |=
+ (cipher_info.dwCipherSuite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
+ SSL_CONNECTION_CIPHERSUITE_SHIFT;
+ // SChannel doesn't support TLS compression, so cipher_info doesn't have
+ // any field related to the compression method.
+ }
if (ssl_config_.ssl3_fallback)
ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK;
@@ -391,6 +446,7 @@ void SSLClientSocketWin::GetSSLCertRequestInfo(
find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
find_by_issuer_para.cIssuer = issuer_list.cIssuers;
find_by_issuer_para.rgIssuer = issuer_list.aIssuers;
+ find_by_issuer_para.pfnFindCallback = ClientCertFindCallback;
PCCERT_CHAIN_CONTEXT chain_context = NULL;
@@ -516,7 +572,7 @@ int SSLClientSocketWin::InitializeSSLContext() {
&out_flags,
&expiry);
if (status != SEC_I_CONTINUE_NEEDED) {
- DLOG(ERROR) << "InitializeSecurityContext failed: " << status;
+ LOG(ERROR) << "InitializeSecurityContext failed: " << status;
return MapSecurityError(status);
}
@@ -575,6 +631,30 @@ int SSLClientSocketWin::GetPeerAddress(AddressList* address) const {
return transport_->socket()->GetPeerAddress(address);
}
+void SSLClientSocketWin::SetSubresourceSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetSubresourceSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void SSLClientSocketWin::SetOmniboxSpeculation() {
+ if (transport_.get() && transport_->socket()) {
+ transport_->socket()->SetOmniboxSpeculation();
+ } else {
+ NOTREACHED();
+ }
+}
+
+bool SSLClientSocketWin::WasEverUsed() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->WasEverUsed();
+ }
+ NOTREACHED();
+ return false;
+}
+
int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake());
@@ -735,7 +815,7 @@ int SSLClientSocketWin::DoLoop(int last_io_result) {
return rv;
default:
rv = ERR_UNEXPECTED;
- NOTREACHED() << "unexpected state";
+ LOG(DFATAL) << "unexpected state " << state;
break;
}
} while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
@@ -751,7 +831,7 @@ int SSLClientSocketWin::DoHandshakeRead() {
int buf_len = kRecvBufferSize - bytes_received_;
if (buf_len <= 0) {
- NOTREACHED() << "Receive buffer is too small!";
+ LOG(DFATAL) << "Receive buffer is too small!";
return ERR_UNEXPECTED;
}
@@ -870,6 +950,7 @@ int SSLClientSocketWin::DidCallInitializeSecurityContext() {
}
if (FAILED(isc_status_)) {
+ LOG(ERROR) << "InitializeSecurityContext failed: " << isc_status_;
int result = MapSecurityError(isc_status_);
// We told Schannel to not verify the server certificate
// (SCH_CRED_MANUAL_CRED_VALIDATION), so any certificate error returned by
@@ -944,8 +1025,10 @@ int SSLClientSocketWin::DoHandshakeWriteComplete(int result) {
bool overflow = (bytes_sent_ > static_cast<int>(send_buffer_.cbBuffer));
FreeSendBuffer();
bytes_sent_ = 0;
- if (overflow) // Bug!
+ if (overflow) { // Bug!
+ LOG(DFATAL) << "overflow";
return ERR_UNEXPECTED;
+ }
if (writing_first_token_) {
writing_first_token_ = false;
DCHECK(bytes_received_ == 0);
@@ -1106,6 +1189,7 @@ int SSLClientSocketWin::DoPayloadDecrypt() {
if (status != SEC_E_OK && status != SEC_I_RENEGOTIATE) {
DCHECK(status != SEC_E_MESSAGE_ALTERED);
+ LOG(ERROR) << "DecryptMessage failed: " << status;
return MapSecurityError(status);
}
@@ -1233,8 +1317,10 @@ int SSLClientSocketWin::DoPayloadEncrypt() {
SECURITY_STATUS status = EncryptMessage(&ctxt_, 0, &buffer_desc, 0);
- if (FAILED(status))
+ if (FAILED(status)) {
+ LOG(ERROR) << "EncryptMessage failed: " << status;
return MapSecurityError(status);
+ }
payload_send_buffer_len_ = buffers[0].cbBuffer +
buffers[1].cbBuffer +
@@ -1279,8 +1365,10 @@ int SSLClientSocketWin::DoPayloadWriteComplete(int result) {
payload_send_buffer_.reset();
payload_send_buffer_len_ = 0;
bytes_sent_ = 0;
- if (overflow) // Bug!
+ if (overflow) { // Bug!
+ LOG(DFATAL) << "overflow";
return ERR_UNEXPECTED;
+ }
// Done
return user_write_buf_len_;
}
@@ -1302,7 +1390,7 @@ int SSLClientSocketWin::DidCompleteHandshake() {
SECURITY_STATUS status = QueryContextAttributes(
&ctxt_, SECPKG_ATTR_STREAM_SIZES, &stream_sizes_);
if (status != SEC_E_OK) {
- DLOG(ERROR) << "QueryContextAttributes (stream sizes) failed: " << status;
+ LOG(ERROR) << "QueryContextAttributes (stream sizes) failed: " << status;
return MapSecurityError(status);
}
DCHECK(!server_cert_ || renegotiating_);
@@ -1310,7 +1398,7 @@ int SSLClientSocketWin::DidCompleteHandshake() {
status = QueryContextAttributes(
&ctxt_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &server_cert_handle);
if (status != SEC_E_OK) {
- DLOG(ERROR) << "QueryContextAttributes (remote cert) failed: " << status;
+ LOG(ERROR) << "QueryContextAttributes (remote cert) failed: " << status;
return MapSecurityError(status);
}
if (renegotiating_ &&
diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h
index b4a0bad..38cdb32 100644
--- a/net/socket/ssl_client_socket_win.h
+++ b/net/socket/ssl_client_socket_win.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_SSL_CLIENT_SOCKET_WIN_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_WIN_H_
+#pragma once
#define SECURITY_WIN32 // Needs to be defined before including security.h
@@ -29,7 +30,7 @@ class BoundNetLog;
// An SSL client socket implemented with the Windows Schannel.
class SSLClientSocketWin : public SSLClientSocket {
public:
- // Takes ownership of the transport_socket, which may already be connected.
+ // Takes ownership of the |transport_socket|, which must already be connected.
// The given hostname will be compared with the name(s) in the server's
// certificate during the SSL handshake. ssl_config specifies the SSL
// settings.
@@ -50,6 +51,9 @@ class SSLClientSocketWin : public SSLClientSocket {
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h
index 194de6e..6139b5b 100644
--- a/net/socket/tcp_client_socket.h
+++ b/net/socket/tcp_client_socket.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_TCP_CLIENT_SOCKET_H_
#define NET_SOCKET_TCP_CLIENT_SOCKET_H_
+#pragma once
#include "build/build_config.h"
diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index 93593d9..6f7403b 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -69,6 +69,7 @@ int MapPosixError(int os_error) {
case ECONNREFUSED:
return ERR_CONNECTION_REFUSED;
case EHOSTUNREACH:
+ case EHOSTDOWN:
case ENETUNREACH:
return ERR_ADDRESS_UNREACHABLE;
case EADDRNOTAVAIL:
@@ -99,8 +100,10 @@ int MapConnectError(int os_error) {
//-----------------------------------------------------------------------------
-TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses,
- net::NetLog* net_log)
+TCPClientSocketLibevent::TCPClientSocketLibevent(
+ const AddressList& addresses,
+ net::NetLog* net_log,
+ const net::NetLog::Source& source)
: socket_(kInvalidSocket),
addresses_(addresses),
current_ai_(NULL),
@@ -111,7 +114,10 @@ TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses,
next_connect_state_(CONNECT_STATE_NONE),
connect_os_error_(0),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
+ scoped_refptr<NetLog::EventParameters> params;
+ if (source.is_valid())
+ params = new NetLogSourceParameter("source_dependency", source);
+ net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
}
TCPClientSocketLibevent::~TCPClientSocketLibevent() {
@@ -202,7 +208,7 @@ int TCPClientSocketLibevent::DoConnect() {
// Check if the connect() failed synchronously.
connect_os_error_ = errno;
if (connect_os_error_ != EINPROGRESS)
- return MapPosixError(connect_os_error_);
+ return MapConnectError(connect_os_error_);
// Otherwise the connect() is going to complete asynchronously, so watch
// for its completion.
@@ -228,8 +234,10 @@ int TCPClientSocketLibevent::DoConnectComplete(int result) {
write_socket_watcher_.StopWatchingFileDescriptor();
- if (result == OK)
+ if (result == OK) {
+ use_history_.set_was_ever_connected();
return OK; // Done!
+ }
// Close whatever partially connected socket we currently have.
DoDisconnect();
@@ -315,7 +323,8 @@ int TCPClientSocketLibevent::Read(IOBuffer* buf,
if (nread >= 0) {
static StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(nread);
-
+ if (nread > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
new NetLogIntegerParameter("num_bytes", nread));
return nread;
@@ -353,6 +362,8 @@ int TCPClientSocketLibevent::Write(IOBuffer* buf,
if (nwrite >= 0) {
static StatsCounter write_bytes("tcp.write_bytes");
write_bytes.Add(nwrite);
+ if (nwrite > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_SENT,
new NetLogIntegerParameter("num_bytes", nwrite));
return nwrite;
@@ -469,6 +480,10 @@ void TCPClientSocketLibevent::DidCompleteRead() {
int result;
if (bytes_transferred >= 0) {
result = bytes_transferred;
+ static StatsCounter read_bytes("tcp.read_bytes");
+ read_bytes.Add(bytes_transferred);
+ if (bytes_transferred > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
new NetLogIntegerParameter("num_bytes", result));
} else {
@@ -492,6 +507,10 @@ void TCPClientSocketLibevent::DidCompleteWrite() {
int result;
if (bytes_transferred >= 0) {
result = bytes_transferred;
+ static StatsCounter write_bytes("tcp.write_bytes");
+ write_bytes.Add(bytes_transferred);
+ if (bytes_transferred > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_SENT,
new NetLogIntegerParameter("num_bytes", result));
} else {
@@ -509,10 +528,22 @@ void TCPClientSocketLibevent::DidCompleteWrite() {
int TCPClientSocketLibevent::GetPeerAddress(AddressList* address) const {
DCHECK(CalledOnValidThread());
DCHECK(address);
- if (!current_ai_)
+ if (!IsConnected())
return ERR_UNEXPECTED;
address->Copy(current_ai_, false);
return OK;
}
+void TCPClientSocketLibevent::SetSubresourceSpeculation() {
+ use_history_.set_subresource_speculation();
+}
+
+void TCPClientSocketLibevent::SetOmniboxSpeculation() {
+ use_history_.set_omnibox_speculation();
+}
+
+bool TCPClientSocketLibevent::WasEverUsed() const {
+ return use_history_.was_used_to_convey_data();
+}
+
} // namespace net
diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h
index f0bed43..980e4cd 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_TCP_CLIENT_SOCKET_LIBEVENT_H_
#define NET_SOCKET_TCP_CLIENT_SOCKET_LIBEVENT_H_
+#pragma once
#include "base/message_loop.h"
#include "base/non_thread_safe.h"
@@ -26,8 +27,9 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe {
// The IP address(es) and port number to connect to. The TCP socket will try
// each IP address in the list until it succeeds in establishing a
// connection.
- explicit TCPClientSocketLibevent(const AddressList& addresses,
- net::NetLog* net_log);
+ TCPClientSocketLibevent(const AddressList& addresses,
+ net::NetLog* net_log,
+ const net::NetLog::Source& source);
virtual ~TCPClientSocketLibevent();
@@ -38,6 +40,9 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe {
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -160,6 +165,10 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe {
BoundNetLog net_log_;
+ // Record of connectivity and transmissions, for use in speculative connection
+ // histograms.
+ UseHistory use_history_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent);
};
diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc
index 730f40e..ce53fa5 100644
--- a/net/socket/tcp_client_socket_pool.cc
+++ b/net/socket/tcp_client_socket_pool.cc
@@ -23,7 +23,7 @@ namespace net {
TCPSocketParams::TCPSocketParams(const HostPortPair& host_port_pair,
RequestPriority priority, const GURL& referrer,
bool disable_resolver_cache)
- : destination_(host_port_pair.host, host_port_pair.port) {
+ : destination_(host_port_pair) {
Initialize(priority, referrer, disable_resolver_cache);
}
@@ -31,7 +31,7 @@ TCPSocketParams::TCPSocketParams(const HostPortPair& host_port_pair,
TCPSocketParams::TCPSocketParams(const std::string& host, int port,
RequestPriority priority, const GURL& referrer,
bool disable_resolver_cache)
- : destination_(host, port) {
+ : destination_(HostPortPair(host, port)) {
Initialize(priority, referrer, disable_resolver_cache);
}
@@ -72,11 +72,11 @@ TCPConnectJob::~TCPConnectJob() {
LoadState TCPConnectJob::GetLoadState() const {
switch (next_state_) {
- case kStateResolveHost:
- case kStateResolveHostComplete:
+ case STATE_RESOLVE_HOST:
+ case STATE_RESOLVE_HOST_COMPLETE:
return LOAD_STATE_RESOLVING_HOST;
- case kStateTCPConnect:
- case kStateTCPConnectComplete:
+ case STATE_TCP_CONNECT:
+ case STATE_TCP_CONNECT_COMPLETE:
return LOAD_STATE_CONNECTING;
default:
NOTREACHED();
@@ -85,7 +85,7 @@ LoadState TCPConnectJob::GetLoadState() const {
}
int TCPConnectJob::ConnectInternal() {
- next_state_ = kStateResolveHost;
+ next_state_ = STATE_RESOLVE_HOST;
start_time_ = base::TimeTicks::Now();
return DoLoop(OK);
}
@@ -97,25 +97,25 @@ void TCPConnectJob::OnIOComplete(int result) {
}
int TCPConnectJob::DoLoop(int result) {
- DCHECK_NE(next_state_, kStateNone);
+ DCHECK_NE(next_state_, STATE_NONE);
int rv = result;
do {
State state = next_state_;
- next_state_ = kStateNone;
+ next_state_ = STATE_NONE;
switch (state) {
- case kStateResolveHost:
+ case STATE_RESOLVE_HOST:
DCHECK_EQ(OK, rv);
rv = DoResolveHost();
break;
- case kStateResolveHostComplete:
+ case STATE_RESOLVE_HOST_COMPLETE:
rv = DoResolveHostComplete(rv);
break;
- case kStateTCPConnect:
+ case STATE_TCP_CONNECT:
DCHECK_EQ(OK, rv);
rv = DoTCPConnect();
break;
- case kStateTCPConnectComplete:
+ case STATE_TCP_CONNECT_COMPLETE:
rv = DoTCPConnectComplete(rv);
break;
default:
@@ -123,27 +123,27 @@ int TCPConnectJob::DoLoop(int result) {
rv = ERR_FAILED;
break;
}
- } while (rv != ERR_IO_PENDING && next_state_ != kStateNone);
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
return rv;
}
int TCPConnectJob::DoResolveHost() {
- next_state_ = kStateResolveHostComplete;
+ next_state_ = STATE_RESOLVE_HOST_COMPLETE;
return resolver_.Resolve(params_->destination(), &addresses_, &callback_,
net_log());
}
int TCPConnectJob::DoResolveHostComplete(int result) {
if (result == OK)
- next_state_ = kStateTCPConnect;
+ next_state_ = STATE_TCP_CONNECT;
return result;
}
int TCPConnectJob::DoTCPConnect() {
- next_state_ = kStateTCPConnectComplete;
+ next_state_ = STATE_TCP_CONNECT_COMPLETE;
set_socket(client_socket_factory_->CreateTCPClientSocket(
- addresses_, net_log().net_log()));
+ addresses_, net_log().net_log(), net_log().source()));
connect_start_time_ = base::TimeTicks::Now();
return socket()->Connect(&callback_);
}
@@ -194,7 +194,7 @@ base::TimeDelta
TCPClientSocketPool::TCPClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
HostResolver* host_resolver,
ClientSocketFactory* client_socket_factory,
NetLog* net_log)
@@ -204,7 +204,7 @@ TCPClientSocketPool::TCPClientSocketPool(
base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
new TCPConnectJobFactory(client_socket_factory,
host_resolver, net_log)) {
- base_.EnableBackupJobs();
+ base_.EnableConnectBackupJobs();
}
TCPClientSocketPool::~TCPClientSocketPool() {}
@@ -219,15 +219,13 @@ int TCPClientSocketPool::RequestSocket(
const scoped_refptr<TCPSocketParams>* casted_params =
static_cast<const scoped_refptr<TCPSocketParams>*>(params);
- if (net_log.HasListener()) {
+ if (net_log.IsLoggingAll()) {
// TODO(eroman): Split out the host and port parameters.
net_log.AddEvent(
NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET,
new NetLogStringParameter(
"host_and_port",
- StringPrintf("%s [port %d]",
- casted_params->get()->destination().hostname().c_str(),
- casted_params->get()->destination().port())));
+ casted_params->get()->destination().host_port_pair().ToString()));
}
return base_.RequestSocket(group_name, *casted_params, priority, handle,
diff --git a/net/socket/tcp_client_socket_pool.h b/net/socket/tcp_client_socket_pool.h
index 1ee50d2..1de3870 100644
--- a/net/socket/tcp_client_socket_pool.h
+++ b/net/socket/tcp_client_socket_pool.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_TCP_CLIENT_SOCKET_POOL_H_
#define NET_SOCKET_TCP_CLIENT_SOCKET_POOL_H_
+#pragma once
#include <string>
@@ -71,11 +72,11 @@ class TCPConnectJob : public ConnectJob {
private:
enum State {
- kStateResolveHost,
- kStateResolveHostComplete,
- kStateTCPConnect,
- kStateTCPConnectComplete,
- kStateNone,
+ STATE_RESOLVE_HOST,
+ STATE_RESOLVE_HOST_COMPLETE,
+ STATE_TCP_CONNECT,
+ STATE_TCP_CONNECT_COMPLETE,
+ STATE_NONE,
};
// Begins the host resolution and the TCP connect. Returns OK on success
@@ -114,11 +115,13 @@ class TCPClientSocketPool : public ClientSocketPool {
TCPClientSocketPool(
int max_sockets,
int max_sockets_per_group,
- const scoped_refptr<ClientSocketPoolHistograms>& histograms,
+ ClientSocketPoolHistograms* histograms,
HostResolver* host_resolver,
ClientSocketFactory* client_socket_factory,
NetLog* net_log);
+ virtual ~TCPClientSocketPool();
+
// ClientSocketPool methods:
virtual int RequestSocket(const std::string& group_name,
@@ -148,17 +151,20 @@ class TCPClientSocketPool : public ClientSocketPool {
virtual LoadState GetLoadState(const std::string& group_name,
const ClientSocketHandle* handle) const;
+ virtual DictionaryValue* GetInfoAsValue(const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const {
+ return base_.GetInfoAsValue(name, type);
+ }
+
virtual base::TimeDelta ConnectionTimeout() const {
return base_.ConnectionTimeout();
}
- virtual scoped_refptr<ClientSocketPoolHistograms> histograms() const {
+ virtual ClientSocketPoolHistograms* histograms() const {
return base_.histograms();
}
- protected:
- virtual ~TCPClientSocketPool();
-
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 9516f9f..1e701aa 100644
--- a/net/socket/tcp_client_socket_pool_unittest.cc
+++ b/net/socket/tcp_client_socket_pool_unittest.cc
@@ -50,6 +50,10 @@ class MockClientSocket : public ClientSocket {
return net_log_;
}
+ virtual void SetSubresourceSpeculation() {}
+ virtual void SetOmniboxSpeculation() {}
+ virtual bool WasEverUsed() const { return false; }
+
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
@@ -91,6 +95,10 @@ class MockFailingClientSocket : public ClientSocket {
return net_log_;
}
+ virtual void SetSubresourceSpeculation() {}
+ virtual void SetOmniboxSpeculation() {}
+ virtual bool WasEverUsed() const { return false; }
+
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
@@ -145,6 +153,10 @@ class MockPendingClientSocket : public ClientSocket {
return net_log_;
}
+ virtual void SetSubresourceSpeculation() {}
+ virtual void SetOmniboxSpeculation() {}
+ virtual bool WasEverUsed() const { return false; }
+
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
@@ -198,8 +210,10 @@ class MockClientSocketFactory : public ClientSocketFactory {
client_socket_types_(NULL), client_socket_index_(0),
client_socket_index_max_(0) {}
- virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses,
- NetLog* /* net_log */) {
+ virtual ClientSocket* CreateTCPClientSocket(
+ const AddressList& addresses,
+ NetLog* /* net_log */,
+ const NetLog::Source& /* source */) {
allocation_count_++;
ClientSocketType type = client_socket_type_;
@@ -259,7 +273,7 @@ class MockClientSocketFactory : public ClientSocketFactory {
int client_socket_index_max_;
};
-class TCPClientSocketPoolTest : public ClientSocketPoolTest {
+class TCPClientSocketPoolTest : public testing::Test {
protected:
TCPClientSocketPoolTest()
: params_(new TCPSocketParams(HostPortPair("www.google.com", 80),
@@ -268,32 +282,49 @@ class TCPClientSocketPoolTest : public ClientSocketPoolTest {
LOW, GURL(), false)),
histograms_(new ClientSocketPoolHistograms("TCPUnitTest")),
host_resolver_(new MockHostResolver),
- pool_(new TCPClientSocketPool(kMaxSockets,
- kMaxSocketsPerGroup,
- histograms_,
- host_resolver_,
- &client_socket_factory_,
- NULL)) {
+ pool_(kMaxSockets,
+ kMaxSocketsPerGroup,
+ histograms_.get(),
+ host_resolver_,
+ &client_socket_factory_,
+ NULL) {
}
int StartRequest(const std::string& group_name, RequestPriority priority) {
scoped_refptr<TCPSocketParams> params = new TCPSocketParams(
HostPortPair("www.google.com", 80), MEDIUM, GURL(), false);
- return StartRequestUsingPool(pool_, group_name, priority, params);
+ return test_base_.StartRequestUsingPool(
+ &pool_, group_name, priority, params);
+ }
+
+ int GetOrderOfRequest(size_t index) {
+ return test_base_.GetOrderOfRequest(index);
+ }
+
+ bool ReleaseOneConnection(ClientSocketPoolTest::KeepAlive keep_alive) {
+ return test_base_.ReleaseOneConnection(keep_alive);
}
+ void ReleaseAllConnections(ClientSocketPoolTest::KeepAlive keep_alive) {
+ test_base_.ReleaseAllConnections(keep_alive);
+ }
+
+ ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
+ size_t completion_count() const { return test_base_.completion_count(); }
+
scoped_refptr<TCPSocketParams> params_;
scoped_refptr<TCPSocketParams> low_params_;
- scoped_refptr<ClientSocketPoolHistograms> histograms_;
+ scoped_ptr<ClientSocketPoolHistograms> histograms_;
scoped_refptr<MockHostResolver> host_resolver_;
MockClientSocketFactory client_socket_factory_;
- scoped_refptr<TCPClientSocketPool> pool_;
+ TCPClientSocketPool pool_;
+ ClientSocketPoolTest test_base_;
};
TEST_F(TCPClientSocketPoolTest, Basic) {
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("a", low_params_, LOW, &callback, pool_, BoundNetLog());
+ int rv = handle.Init("a", low_params_, LOW, &callback, &pool_, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -307,34 +338,36 @@ TEST_F(TCPClientSocketPoolTest, Basic) {
TEST_F(TCPClientSocketPoolTest, InitHostResolutionFailure) {
host_resolver_->rules()->AddSimulatedFailure("unresolvable.host.name");
- TestSocketRequest req(&request_order_, &completion_count_);
+ TestCompletionCallback callback;
+ ClientSocketHandle handle;
scoped_refptr<TCPSocketParams> dest = new TCPSocketParams(
"unresolvable.host.name", 80, kDefaultPriority, GURL(), false);
EXPECT_EQ(ERR_IO_PENDING,
- req.handle()->Init("a", dest, kDefaultPriority, &req, pool_,
- BoundNetLog()));
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req.WaitForResult());
+ handle.Init("a", dest, kDefaultPriority, &callback, &pool_,
+ BoundNetLog()));
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback.WaitForResult());
}
TEST_F(TCPClientSocketPoolTest, InitConnectionFailure) {
client_socket_factory_.set_client_socket_type(
MockClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET);
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
+ TestCompletionCallback callback;
+ ClientSocketHandle handle;
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
+ &callback, &pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
// Make the host resolutions complete synchronously this time.
host_resolver_->set_synchronous_mode(true);
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.handle()->Init("a", params_,
- kDefaultPriority, &req,
- pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_CONNECTION_FAILED, handle.Init("a", params_,
+ kDefaultPriority, &callback,
+ &pool_, BoundNetLog()));
}
TEST_F(TCPClientSocketPoolTest, PendingRequests) {
// First request finishes asynchronously.
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
@@ -358,12 +391,12 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests) {
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- ReleaseAllConnections(KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count());
// One initial asynchronous request and then 10 pending requests.
- EXPECT_EQ(11U, completion_count_);
+ EXPECT_EQ(11U, completion_count());
// First part of requests, all with the same priority, finishes in FIFO order.
EXPECT_EQ(1, GetOrderOfRequest(1));
@@ -386,13 +419,13 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests) {
EXPECT_EQ(9, GetOrderOfRequest(16));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(17));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(17));
}
TEST_F(TCPClientSocketPoolTest, PendingRequests_NoKeepAlive) {
// First request finishes asynchronously.
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
@@ -411,53 +444,48 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests_NoKeepAlive) {
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- ReleaseAllConnections(NO_KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
// The pending requests should finish successfully.
- EXPECT_EQ(OK, requests_[6]->WaitForResult());
- EXPECT_EQ(OK, requests_[7]->WaitForResult());
- EXPECT_EQ(OK, requests_[8]->WaitForResult());
- EXPECT_EQ(OK, requests_[9]->WaitForResult());
- EXPECT_EQ(OK, requests_[10]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[6]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[7]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[8]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[9]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[10]->WaitForResult());
- EXPECT_EQ(static_cast<int>(requests_.size()),
+ EXPECT_EQ(static_cast<int>(requests()->size()),
client_socket_factory_.allocation_count());
// First asynchronous request, and then last 5 pending requests.
- EXPECT_EQ(6U, completion_count_);
+ EXPECT_EQ(6U, completion_count());
}
// This test will start up a RequestSocket() and then immediately Cancel() it.
// The pending host resolution will eventually complete, and destroy the
// ClientSocketPool which will crash if the group was not cleared properly.
TEST_F(TCPClientSocketPoolTest, CancelRequestClearGroup) {
- TestSocketRequest req(&request_order_, &completion_count_);
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
- req.handle()->Reset();
-
- // There is a race condition here. If the worker pool doesn't post the task
- // before we get here, then this might not run ConnectingSocket::OnIOComplete
- // and therefore leak the canceled ConnectingSocket. However, other tests
- // after this will call MessageLoop::RunAllPending() which should prevent a
- // leak, unless the worker thread takes longer than all of them.
- PlatformThread::Sleep(10);
- MessageLoop::current()->RunAllPending();
+ TestCompletionCallback callback;
+ ClientSocketHandle handle;
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
+ &callback, &pool_, BoundNetLog()));
+ handle.Reset();
}
TEST_F(TCPClientSocketPoolTest, TwoRequestsCancelOne) {
- TestSocketRequest req(&request_order_, &completion_count_);
- TestSocketRequest req2(&request_order_, &completion_count_);
+ ClientSocketHandle handle;
+ TestCompletionCallback callback;
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
- &req, pool_, BoundNetLog()));
- EXPECT_EQ(ERR_IO_PENDING, req2.handle()->Init("a", params_, kDefaultPriority,
- &req2, pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
+ &callback, &pool_, BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a", params_, kDefaultPriority,
+ &callback2, &pool_, BoundNetLog()));
- req.handle()->Reset();
+ handle.Reset();
- EXPECT_EQ(OK, req2.WaitForResult());
- req2.handle()->Reset();
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ handle2.Reset();
}
TEST_F(TCPClientSocketPoolTest, ConnectCancelConnect) {
@@ -465,16 +493,14 @@ TEST_F(TCPClientSocketPoolTest, ConnectCancelConnect) {
MockClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET);
ClientSocketHandle handle;
TestCompletionCallback callback;
- TestSocketRequest req(&request_order_, &completion_count_);
-
EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback, pool_, BoundNetLog()));
+ &callback, &pool_, BoundNetLog()));
handle.Reset();
TestCompletionCallback callback2;
EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", params_, kDefaultPriority,
- &callback2, pool_, BoundNetLog()));
+ &callback2, &pool_, BoundNetLog()));
host_resolver_->set_synchronous_mode(true);
// At this point, handle has two ConnectingSockets out for it. Due to the
@@ -495,7 +521,7 @@ TEST_F(TCPClientSocketPoolTest, ConnectCancelConnect) {
TEST_F(TCPClientSocketPoolTest, CancelRequest) {
// First request finishes asynchronously.
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
@@ -520,14 +546,14 @@ TEST_F(TCPClientSocketPoolTest, CancelRequest) {
// Cancel a request.
size_t index_to_cancel = kMaxSocketsPerGroup + 2;
- EXPECT_FALSE(requests_[index_to_cancel]->handle()->is_initialized());
- requests_[index_to_cancel]->handle()->Reset();
+ EXPECT_FALSE((*requests())[index_to_cancel]->handle()->is_initialized());
+ (*requests())[index_to_cancel]->handle()->Reset();
- ReleaseAllConnections(KEEP_ALIVE);
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
EXPECT_EQ(kMaxSocketsPerGroup,
client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_.size() - kMaxSocketsPerGroup, completion_count_);
+ EXPECT_EQ(requests()->size() - kMaxSocketsPerGroup, completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
@@ -537,7 +563,8 @@ TEST_F(TCPClientSocketPoolTest, CancelRequest) {
EXPECT_EQ(6, GetOrderOfRequest(6));
EXPECT_EQ(14, GetOrderOfRequest(7));
EXPECT_EQ(7, GetOrderOfRequest(8));
- EXPECT_EQ(kRequestNotFound, GetOrderOfRequest(9)); // Canceled request.
+ EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound,
+ GetOrderOfRequest(9)); // Canceled request.
EXPECT_EQ(9, GetOrderOfRequest(10));
EXPECT_EQ(10, GetOrderOfRequest(11));
EXPECT_EQ(11, GetOrderOfRequest(12));
@@ -547,7 +574,7 @@ TEST_F(TCPClientSocketPoolTest, CancelRequest) {
EXPECT_EQ(15, GetOrderOfRequest(16));
// Make sure we test order of all requests made.
- EXPECT_EQ(kIndexOutOfBounds, GetOrderOfRequest(17));
+ EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(17));
}
class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
@@ -574,8 +601,7 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
within_callback_ = true;
scoped_refptr<TCPSocketParams> dest = new TCPSocketParams(
HostPortPair("www.google.com", 80), LOWEST, GURL(), false);
- int rv = handle_->Init("a", dest, LOWEST, this, pool_,
- BoundNetLog());
+ int rv = handle_->Init("a", dest, LOWEST, this, pool_, BoundNetLog());
EXPECT_EQ(OK, rv);
}
}
@@ -586,17 +612,17 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
private:
ClientSocketHandle* const handle_;
- const scoped_refptr<TCPClientSocketPool> pool_;
+ TCPClientSocketPool* const pool_;
bool within_callback_;
TestCompletionCallback callback_;
};
TEST_F(TCPClientSocketPoolTest, RequestTwice) {
ClientSocketHandle handle;
- RequestSocketCallback callback(&handle, pool_.get());
+ RequestSocketCallback callback(&handle, &pool_);
scoped_refptr<TCPSocketParams> dest = new TCPSocketParams(
HostPortPair("www.google.com", 80), LOWEST, GURL(), false);
- int rv = handle.Init("a", dest, LOWEST, &callback, pool_,
+ int rv = handle.Init("a", dest, LOWEST, &callback, &pool_,
BoundNetLog());
ASSERT_EQ(ERR_IO_PENDING, rv);
@@ -627,17 +653,17 @@ TEST_F(TCPClientSocketPoolTest, CancelActiveRequestWithPendingRequests) {
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
// Now, kMaxSocketsPerGroup requests should be active. Let's cancel them.
- ASSERT_LE(kMaxSocketsPerGroup, static_cast<int>(requests_.size()));
+ ASSERT_LE(kMaxSocketsPerGroup, static_cast<int>(requests()->size()));
for (int i = 0; i < kMaxSocketsPerGroup; i++)
- requests_[i]->handle()->Reset();
+ (*requests())[i]->handle()->Reset();
// Let's wait for the rest to complete now.
- for (size_t i = kMaxSocketsPerGroup; i < requests_.size(); ++i) {
- EXPECT_EQ(OK, requests_[i]->WaitForResult());
- requests_[i]->handle()->Reset();
+ for (size_t i = kMaxSocketsPerGroup; i < requests()->size(); ++i) {
+ EXPECT_EQ(OK, (*requests())[i]->WaitForResult());
+ (*requests())[i]->handle()->Reset();
}
- EXPECT_EQ(requests_.size() - kMaxSocketsPerGroup, completion_count_);
+ EXPECT_EQ(requests()->size() - kMaxSocketsPerGroup, completion_count());
}
// Make sure that pending requests get serviced after active requests fail.
@@ -653,13 +679,13 @@ TEST_F(TCPClientSocketPoolTest, FailingActiveRequestWithPendingRequests) {
EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
for (int i = 0; i < kNumRequests; i++)
- EXPECT_EQ(ERR_CONNECTION_FAILED, requests_[i]->WaitForResult());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, (*requests())[i]->WaitForResult());
}
TEST_F(TCPClientSocketPoolTest, ResetIdleSocketsOnIPAddressChange) {
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("a", low_params_, LOW, &callback, pool_, BoundNetLog());
+ int rv = handle.Init("a", low_params_, LOW, &callback, &pool_, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -674,13 +700,13 @@ TEST_F(TCPClientSocketPoolTest, ResetIdleSocketsOnIPAddressChange) {
MessageLoop::current()->RunAllPending();
// Now we should have 1 idle socket.
- EXPECT_EQ(1, pool_->IdleSocketCount());
+ EXPECT_EQ(1, pool_.IdleSocketCount());
// After an IP address change, we should have 0 idle sockets.
NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
MessageLoop::current()->RunAllPending(); // Notification happens async.
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
}
TEST_F(TCPClientSocketPoolTest, BackupSocketConnect) {
@@ -710,11 +736,11 @@ TEST_F(TCPClientSocketPoolTest, BackupSocketConnect) {
for (size_t index = 0; index < arraysize(cases); ++index) {
client_socket_factory_.set_client_socket_types(cases[index], 2);
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("b", low_params_, LOW, &callback, pool_,
+ int rv = handle.Init("b", low_params_, LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
@@ -734,17 +760,11 @@ TEST_F(TCPClientSocketPoolTest, BackupSocketConnect) {
EXPECT_TRUE(handle.socket());
// One socket is stalled, the other is active.
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
handle.Reset();
// Close all pending connect jobs and existing sockets.
- pool_->Flush();
-
- // TODO(mbelshe): Flush has a bug. UIt doesn't clean out pending connect
- // jobs. When they complete, they become idle sockets. For now, continue
- // to replace the pool_. But we really need to fix Flush().
- pool_ = new TCPClientSocketPool(kMaxSockets, kMaxSocketsPerGroup,
- histograms_, host_resolver_, &client_socket_factory_, NULL);
+ pool_.Flush();
}
}
@@ -757,11 +777,11 @@ TEST_F(TCPClientSocketPoolTest, BackupSocketCancel) {
enum { CANCEL_BEFORE_WAIT, CANCEL_AFTER_WAIT };
for (int index = CANCEL_BEFORE_WAIT; index < CANCEL_AFTER_WAIT; ++index) {
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("c", low_params_, LOW, &callback, pool_,
+ int rv = handle.Init("c", low_params_, LOW, &callback, &pool_,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
@@ -785,7 +805,7 @@ TEST_F(TCPClientSocketPoolTest, BackupSocketCancel) {
EXPECT_FALSE(handle.socket());
// One socket is stalled, the other is active.
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
}
}
@@ -802,11 +822,11 @@ TEST_F(TCPClientSocketPoolTest, BackupSocketFailAfterStall) {
client_socket_factory_.set_client_socket_types(case_types, 2);
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("b", low_params_, LOW, &callback, pool_, BoundNetLog());
+ int rv = handle.Init("b", low_params_, LOW, &callback, &pool_, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -827,7 +847,7 @@ TEST_F(TCPClientSocketPoolTest, BackupSocketFailAfterStall) {
EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
handle.Reset();
// Reset for the next case.
@@ -847,11 +867,11 @@ TEST_F(TCPClientSocketPoolTest, BackupSocketFailAfterDelay) {
client_socket_factory_.set_client_socket_types(case_types, 2);
- EXPECT_EQ(0, pool_->IdleSocketCount());
+ EXPECT_EQ(0, pool_.IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
- int rv = handle.Init("b", low_params_, LOW, &callback, pool_, BoundNetLog());
+ int rv = handle.Init("b", low_params_, LOW, &callback, &pool_, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc
index 638e887..17ec51c 100644
--- a/net/socket/tcp_client_socket_unittest.cc
+++ b/net/socket/tcp_client_socket_unittest.cc
@@ -26,7 +26,9 @@ const char kServerReply[] = "HTTP/1.1 404 Not Found";
class TCPClientSocketTest
: public PlatformTest, public ListenSocket::ListenSocketDelegate {
public:
- TCPClientSocketTest() : net_log_(CapturingNetLog::kUnbounded) {
+ TCPClientSocketTest()
+ : listen_port_(0),
+ net_log_(CapturingNetLog::kUnbounded) {
}
// Implement ListenSocketDelegate methods
@@ -90,11 +92,12 @@ void TCPClientSocketTest::SetUp() {
AddressList addr;
scoped_refptr<HostResolver> resolver(
- CreateSystemHostResolver(HostResolver::kDefaultParallelism));
- HostResolver::RequestInfo info("localhost", listen_port_);
+ CreateSystemHostResolver(HostResolver::kDefaultParallelism,
+ NULL));
+ HostResolver::RequestInfo info(HostPortPair("localhost", listen_port_));
int rv = resolver->Resolve(info, &addr, NULL, NULL, BoundNetLog());
CHECK_EQ(rv, OK);
- sock_.reset(new TCPClientSocket(addr, &net_log_));
+ sock_.reset(new TCPClientSocket(addr, &net_log_, NetLog::Source()));
}
TEST_F(TCPClientSocketTest, Connect) {
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index 3faf41b..f6a2e81 100644
--- a/net/socket/tcp_client_socket_win.cc
+++ b/net/socket/tcp_client_socket_win.cc
@@ -23,6 +23,21 @@ namespace net {
namespace {
+// Assert that the (manual-reset) event object is not signaled.
+void AssertEventNotSignaled(WSAEVENT hEvent) {
+ DWORD wait_rv = WaitForSingleObject(hEvent, 0);
+ if (wait_rv != WAIT_TIMEOUT) {
+ DWORD err = ERROR_SUCCESS;
+ if (wait_rv == WAIT_FAILED)
+ err = GetLastError();
+ CHECK(false); // Crash.
+ // This LOG statement is unreachable since we have already crashed, but it
+ // should prevent the compiler from optimizing away the |wait_rv| and
+ // |err| variables so they appear nicely on the stack in crash dumps.
+ LOG(INFO) << "wait_rv=" << wait_rv << ", err=" << err;
+ }
+}
+
// If the (manual-reset) event object is signaled, resets it and returns true.
// Otherwise, does nothing and returns false. Called after a Winsock function
// succeeds synchronously
@@ -69,13 +84,14 @@ int MapWinsockError(int os_error) {
// connection shutdown. We should not ever see this error code for TCP
// sockets, which are byte stream oriented.
NOTREACHED();
- return ERR_CONNECTION_CLOSED;
+ return ERR_UNEXPECTED;
case WSAEHOSTUNREACH:
case WSAENETUNREACH:
return ERR_ADDRESS_UNREACHABLE;
case WSAEADDRNOTAVAIL:
return ERR_ADDRESS_INVALID;
case WSA_IO_INCOMPLETE:
+ LOG(ERROR) << "Unexpected error " << os_error;
return ERR_UNEXPECTED;
case ERROR_SUCCESS:
return OK;
@@ -256,7 +272,8 @@ void TCPClientSocketWin::Core::WriteDelegate::OnObjectSignaled(
//-----------------------------------------------------------------------------
TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses,
- net::NetLog* net_log)
+ net::NetLog* net_log,
+ const net::NetLog::Source& source)
: socket_(INVALID_SOCKET),
addresses_(addresses),
current_ai_(NULL),
@@ -267,7 +284,11 @@ TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses,
next_connect_state_(CONNECT_STATE_NONE),
connect_os_error_(0),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
+
+ scoped_refptr<NetLog::EventParameters> params;
+ if (source.is_valid())
+ params = new NetLogSourceParameter("source_dependency", source);
+ net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
EnsureWinsockInit();
}
@@ -322,7 +343,7 @@ int TCPClientSocketWin::DoConnectLoop(int result) {
rv = DoConnectComplete(rv);
break;
default:
- LOG(DFATAL) << "bad state";
+ LOG(DFATAL) << "bad state " << state;
rv = ERR_UNEXPECTED;
break;
}
@@ -394,8 +415,10 @@ int TCPClientSocketWin::DoConnectComplete(int result) {
params = new NetLogIntegerParameter("os_error", os_error);
net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params);
- if (result == OK)
+ if (result == OK) {
+ use_history_.set_was_ever_connected();
return OK; // Done!
+ }
// Close whatever partially connected socket we currently have.
DoDisconnect();
@@ -488,12 +511,24 @@ bool TCPClientSocketWin::IsConnectedAndIdle() const {
int TCPClientSocketWin::GetPeerAddress(AddressList* address) const {
DCHECK(CalledOnValidThread());
DCHECK(address);
- if (!current_ai_)
- return ERR_FAILED;
+ if (!IsConnected())
+ return ERR_UNEXPECTED;
address->Copy(current_ai_, false);
return OK;
}
+void TCPClientSocketWin::SetSubresourceSpeculation() {
+ use_history_.set_subresource_speculation();
+}
+
+void TCPClientSocketWin::SetOmniboxSpeculation() {
+ use_history_.set_omnibox_speculation();
+}
+
+bool TCPClientSocketWin::WasEverUsed() const {
+ return use_history_.was_used_to_convey_data();
+}
+
int TCPClientSocketWin::Read(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
@@ -508,9 +543,8 @@ int TCPClientSocketWin::Read(IOBuffer* buf,
core_->read_buffer_.len = buf_len;
core_->read_buffer_.buf = buf->data();
- // TODO(wtc): Remove the CHECK after enough testing.
- CHECK_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
- WaitForSingleObject(core_->read_overlapped_.hEvent, 0));
+ // TODO(wtc): Remove the assertion after enough testing.
+ AssertEventNotSignaled(core_->read_overlapped_.hEvent);
DWORD num, flags = 0;
int rv = WSARecv(socket_, &core_->read_buffer_, 1, &num, &flags,
&core_->read_overlapped_, NULL);
@@ -525,6 +559,8 @@ int TCPClientSocketWin::Read(IOBuffer* buf,
base::MemoryDebug::MarkAsInitialized(core_->read_buffer_.buf, num);
static StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(num);
+ if (num > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
new NetLogIntegerParameter("num_bytes", num));
return static_cast<int>(num);
@@ -551,16 +587,15 @@ int TCPClientSocketWin::Write(IOBuffer* buf,
DCHECK_GT(buf_len, 0);
DCHECK(!core_->write_iobuffer_);
- static StatsCounter reads("tcp.writes");
- reads.Increment();
+ static StatsCounter writes("tcp.writes");
+ writes.Increment();
core_->write_buffer_.len = buf_len;
core_->write_buffer_.buf = buf->data();
core_->write_buffer_length_ = buf_len;
- // TODO(wtc): Remove the CHECK after enough testing.
- CHECK_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
- WaitForSingleObject(core_->write_overlapped_.hEvent, 0));
+ // TODO(wtc): Remove the assertion after enough testing.
+ AssertEventNotSignaled(core_->write_overlapped_.hEvent);
DWORD num;
int rv = WSASend(socket_, &core_->write_buffer_, 1, &num, 0,
&core_->write_overlapped_, NULL);
@@ -576,6 +611,8 @@ int TCPClientSocketWin::Write(IOBuffer* buf,
}
static StatsCounter write_bytes("tcp.write_bytes");
write_bytes.Add(rv);
+ if (rv > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_SENT,
new NetLogIntegerParameter("num_bytes", rv));
return rv;
@@ -680,9 +717,6 @@ void TCPClientSocketWin::DoReadCallback(int rv) {
DCHECK_NE(rv, ERR_IO_PENDING);
DCHECK(read_callback_);
- static StatsCounter read_bytes("tcp.read_bytes");
- read_bytes.Add(rv);
-
// since Run may result in Read being called, clear read_callback_ up front.
CompletionCallback* c = read_callback_;
read_callback_ = NULL;
@@ -693,9 +727,6 @@ void TCPClientSocketWin::DoWriteCallback(int rv) {
DCHECK_NE(rv, ERR_IO_PENDING);
DCHECK(write_callback_);
- static StatsCounter write_bytes("tcp.write_bytes");
- write_bytes.Add(rv);
-
// since Run may result in Write being called, clear write_callback_ up front.
CompletionCallback* c = write_callback_;
write_callback_ = NULL;
@@ -739,6 +770,10 @@ void TCPClientSocketWin::DidCompleteRead() {
waiting_read_ = false;
core_->read_iobuffer_ = NULL;
if (ok) {
+ static StatsCounter read_bytes("tcp.read_bytes");
+ read_bytes.Add(num_bytes);
+ if (num_bytes > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
new NetLogIntegerParameter("num_bytes", num_bytes));
}
@@ -766,6 +801,10 @@ void TCPClientSocketWin::DidCompleteWrite() {
<< " bytes reported.";
rv = ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES;
} else {
+ static StatsCounter write_bytes("tcp.write_bytes");
+ write_bytes.Add(num_bytes);
+ if (num_bytes > 0)
+ use_history_.set_was_used_to_convey_data();
net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_SENT,
new NetLogIntegerParameter("num_bytes", rv));
}
diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h
index 4ac57a8..be25157 100644
--- a/net/socket/tcp_client_socket_win.h
+++ b/net/socket/tcp_client_socket_win.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_TCP_CLIENT_SOCKET_WIN_H_
#define NET_SOCKET_TCP_CLIENT_SOCKET_WIN_H_
+#pragma once
#include <winsock2.h>
@@ -23,9 +24,11 @@ class TCPClientSocketWin : public ClientSocket, NonThreadSafe {
// The IP address(es) and port number to connect to. The TCP socket will try
// each IP address in the list until it succeeds in establishing a
// connection.
- TCPClientSocketWin(const AddressList& addresses, net::NetLog* net_log);
+ TCPClientSocketWin(const AddressList& addresses,
+ net::NetLog* net_log,
+ const net::NetLog::Source& source);
- ~TCPClientSocketWin();
+ virtual ~TCPClientSocketWin();
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -34,6 +37,9 @@ class TCPClientSocketWin : public ClientSocket, NonThreadSafe {
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual void SetSubresourceSpeculation();
+ virtual void SetOmniboxSpeculation();
+ virtual bool WasEverUsed() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -111,6 +117,10 @@ class TCPClientSocketWin : public ClientSocket, NonThreadSafe {
BoundNetLog net_log_;
+ // Record of connectivity and transmissions, for use in speculative connection
+ // histograms.
+ UseHistory use_history_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocketWin);
};
diff --git a/net/socket/tcp_pinger.h b/net/socket/tcp_pinger.h
deleted file mode 100644
index 96fa4fd..0000000
--- a/net/socket/tcp_pinger.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 NET_SOCKET_TCP_PINGER_H_
-#define NET_SOCKET_TCP_PINGER_H_
-
-#include "base/compiler_specific.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/thread.h"
-#include "base/waitable_event.h"
-#include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_errors.h"
-#include "net/socket/tcp_client_socket.h"
-
-namespace base {
-class TimeDelta;
-}
-
-namespace net {
-
-// Simple class to wait until a TCP server is accepting connections.
-class TCPPinger {
- public:
- explicit TCPPinger(const net::AddressList& addr)
- : io_thread_("TCPPinger"),
- worker_(new Worker(addr)) {
- worker_->AddRef();
- // Start up a throwaway IO thread just for this.
- // TODO(dkegel): use some existing thread pool instead?
- base::Thread::Options options;
- options.message_loop_type = MessageLoop::TYPE_IO;
- io_thread_.StartWithOptions(options);
- }
-
- ~TCPPinger() {
- io_thread_.message_loop()->ReleaseSoon(FROM_HERE, worker_);
- }
-
- int Ping() {
- // Default is 10 tries, each with a timeout of 1000ms,
- // for a total max timeout of 10 seconds.
- return Ping(base::TimeDelta::FromMilliseconds(1000), 10);
- }
-
- int Ping(base::TimeDelta tryTimeout, int nTries) {
- int err = ERR_IO_PENDING;
- // Post a request to do the connect on that thread.
- for (int i = 0; i < nTries; i++) {
- io_thread_.message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(worker_,
- &net::TCPPinger::Worker::DoConnect));
- // Timeout here in case remote host offline
- err = worker_->TimedWaitForResult(tryTimeout);
- if (err == net::OK)
- break;
- PlatformThread::Sleep(static_cast<int>(tryTimeout.InMilliseconds()));
-
- // Cancel leftover activity, if any
- io_thread_.message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(worker_,
- &net::TCPPinger::Worker::DoDisconnect));
- worker_->WaitForResult();
- }
- return err;
- }
-
- private:
-
- // Inner class to handle all actual socket calls.
- // This makes the outer interface simpler,
- // and helps us obey the "all socket calls
- // must be on same thread" restriction.
- class Worker : public base::RefCountedThreadSafe<Worker> {
- public:
- explicit Worker(const net::AddressList& addr)
- : event_(false, false),
- net_error_(ERR_IO_PENDING),
- addr_(addr),
- ALLOW_THIS_IN_INITIALIZER_LIST(connect_callback_(this,
- &net::TCPPinger::Worker::ConnectDone)) {
- }
-
- void DoConnect() {
- sock_.reset(new TCPClientSocket(addr_, NULL));
- int rv = sock_->Connect(&connect_callback_);
- // Regardless of success or failure, if we're done now,
- // signal the customer.
- if (rv != ERR_IO_PENDING)
- ConnectDone(rv);
- }
-
- void DoDisconnect() {
- sock_.reset();
- event_.Signal();
- }
-
- void ConnectDone(int rv) {
- sock_.reset();
- net_error_ = rv;
- event_.Signal();
- }
-
- int TimedWaitForResult(base::TimeDelta tryTimeout) {
- event_.TimedWait(tryTimeout);
- // In case of timeout, the value of net_error_ should be ERR_IO_PENDING.
- // However, a harmless data race can happen if TimedWait times out right
- // before event_.Signal() is called in ConnectDone().
- return ANNOTATE_UNPROTECTED_READ(net_error_);
- }
-
- int WaitForResult() {
- event_.Wait();
- return net_error_;
- }
-
- private:
- friend class base::RefCountedThreadSafe<Worker>;
-
- ~Worker() {}
-
- base::WaitableEvent event_;
- int net_error_;
- net::AddressList addr_;
- scoped_ptr<TCPClientSocket> sock_;
- net::CompletionCallbackImpl<Worker> connect_callback_;
- };
-
- base::Thread io_thread_;
- Worker* worker_;
- DISALLOW_COPY_AND_ASSIGN(TCPPinger);
-};
-
-} // namespace net
-
-#endif // NET_SOCKET_TCP_PINGER_H_
diff --git a/net/socket/tcp_pinger_unittest.cc b/net/socket/tcp_pinger_unittest.cc
deleted file mode 100644
index c415ac3..0000000
--- a/net/socket/tcp_pinger_unittest.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 "base/ref_counted.h"
-#include "base/trace_event.h"
-#include "net/base/address_list.h"
-#include "net/base/host_resolver.h"
-#include "net/base/listen_socket.h"
-#include "net/base/net_errors.h"
-#include "net/base/winsock_init.h"
-#include "net/socket/tcp_client_socket.h"
-#include "net/socket/tcp_pinger.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-class TCPPingerTest
- : public PlatformTest, public ListenSocket::ListenSocketDelegate {
- public:
- TCPPingerTest() {
- }
-
- // Implement ListenSocketDelegate methods
- virtual void DidAccept(ListenSocket* server, ListenSocket* connection) {
- // This callback doesn't seem to happen
- // right away, so this handler may not be called at all
- // during connect-only tests.
- LOG(INFO) << "TCPPinger accepted connection";
- connected_sock_ = connection;
- }
- virtual void DidRead(ListenSocket*, const char* str, int len) {
- // Not really needed yet, as TCPPinger doesn't support Read
- connected_sock_->Send(std::string("HTTP/1.1 404 Not Found"), true);
- connected_sock_ = NULL;
- }
- virtual void DidClose(ListenSocket* sock) {}
-
- // Testcase hooks
- virtual void SetUp();
-
- protected:
- int listen_port_;
- scoped_refptr<ListenSocket> listen_sock_;
-
- private:
- scoped_refptr<ListenSocket> connected_sock_;
-};
-
-void TCPPingerTest::SetUp() {
- PlatformTest::SetUp();
-
- // Find a free port to listen on
- // Range of ports to listen on. Shouldn't need to try many.
- static const int kMinPort = 10100;
- static const int kMaxPort = 10200;
-#if defined(OS_WIN)
- net::EnsureWinsockInit();
-#endif
- for (listen_port_ = kMinPort; listen_port_ < kMaxPort; listen_port_++) {
- listen_sock_ = ListenSocket::Listen("127.0.0.1", listen_port_, this);
- if (listen_sock_.get()) break;
- }
- ASSERT_TRUE(listen_sock_.get() != NULL);
-}
-
-TEST_F(TCPPingerTest, Ping) {
- net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(
- net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism));
-
- net::HostResolver::RequestInfo info("localhost", listen_port_);
- int rv = resolver->Resolve(info, &addr, NULL, NULL, net::BoundNetLog());
- EXPECT_EQ(rv, net::OK);
-
- net::TCPPinger pinger(addr);
- rv = pinger.Ping();
- EXPECT_EQ(rv, net::OK);
-}
-
-TEST_F(TCPPingerTest, PingFail) {
- net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(
- net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism));
-
- // "Kill" "server"
- listen_sock_ = NULL;
-
- net::HostResolver::RequestInfo info("localhost", listen_port_);
- int rv = resolver->Resolve(info, &addr, NULL, NULL, net::BoundNetLog());
- EXPECT_EQ(rv, net::OK);
-
- net::TCPPinger pinger(addr);
- rv = pinger.Ping(base::TimeDelta::FromMilliseconds(100), 1);
- EXPECT_NE(rv, net::OK);
-}
diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc
index d1ead09..7abf2be 100644
--- a/net/socket_stream/socket_stream.cc
+++ b/net/socket_stream/socket_stream.cc
@@ -7,12 +7,15 @@
#include "net/socket_stream/socket_stream.h"
+#include <set>
#include <string>
#include "base/compiler_specific.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 "net/base/auth.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
@@ -23,9 +26,9 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/socket/client_socket_factory.h"
-#include "net/socket/ssl_client_socket.h"
#include "net/socket/socks5_client_socket.h"
#include "net/socket/socks_client_socket.h"
+#include "net/socket/ssl_client_socket.h"
#include "net/socket/tcp_client_socket.h"
#include "net/socket_stream/socket_stream_metrics.h"
#include "net/url_request/url_request.h"
@@ -64,6 +67,7 @@ SocketStream::SocketStream(const GURL& url, Delegate* delegate)
write_buf_offset_(0),
write_buf_size_(0),
closing_(false),
+ server_closed_(false),
metrics_(new SocketStreamMetrics(url)) {
DCHECK(MessageLoop::current()) <<
"The current MessageLoop must exist";
@@ -186,16 +190,33 @@ void SocketStream::Close() {
// of AddRef() and Release() in Connect() and Finish(), respectively.
if (next_state_ == STATE_NONE)
return;
- closing_ = true;
- // Close asynchronously, so that delegate won't be called
- // back before returning Close().
MessageLoop::current()->PostTask(
FROM_HERE,
- NewRunnableMethod(this, &SocketStream::DoLoop, OK));
+ NewRunnableMethod(this, &SocketStream::DoClose));
+}
+
+void SocketStream::DoClose() {
+ closing_ = true;
+ // If next_state_ is STATE_TCP_CONNECT, it's waiting other socket establishing
+ // connection. If next_state_ is STATE_AUTH_REQUIRED, it's waiting for
+ // restarting. In these states, we'll close the SocketStream now.
+ if (next_state_ == STATE_TCP_CONNECT || next_state_ == STATE_AUTH_REQUIRED) {
+ DoLoop(ERR_ABORTED);
+ return;
+ }
+ // If next_state_ is STATE_READ_WRITE, we'll run DoLoop and close
+ // the SocketStream.
+ // If it's writing now, we should defer the closing after the current
+ // writing is completed.
+ if (next_state_ == STATE_READ_WRITE && !current_write_buf_)
+ DoLoop(ERR_ABORTED);
+
+ // In other next_state_, we'll wait for callback of other APIs, such as
+ // ResolveProxy().
}
void SocketStream::RestartWithAuth(
- const std::wstring& username, const std::wstring& password) {
+ const string16& username, const string16& password) {
DCHECK(MessageLoop::current()) <<
"The current MessageLoop must exist";
DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
@@ -328,7 +349,8 @@ void SocketStream::OnIOCompleted(int result) {
void SocketStream::OnReadCompleted(int result) {
if (result == 0) {
// 0 indicates end-of-file, so socket was closed.
- next_state_ = STATE_CLOSE;
+ // Don't close the socket if it's still writing.
+ server_closed_ = true;
} else if (result > 0 && read_buf_) {
result = DidReceiveData(result);
}
@@ -369,8 +391,7 @@ void SocketStream::DoLoop(int result) {
result = DoResolveHostComplete(result);
break;
case STATE_TCP_CONNECT:
- DCHECK_EQ(OK, result);
- result = DoTcpConnect();
+ result = DoTcpConnect(result);
break;
case STATE_TCP_CONNECT_COMPLETE:
result = DoTcpConnectComplete(result);
@@ -406,12 +427,17 @@ void SocketStream::DoLoop(int result) {
case STATE_READ_WRITE:
result = DoReadWrite(result);
break;
+ case STATE_AUTH_REQUIRED:
+ // It might be called when DoClose is called while waiting in
+ // STATE_AUTH_REQUIRED.
+ Finish(result);
+ return;
case STATE_CLOSE:
DCHECK_LE(result, OK);
Finish(result);
return;
default:
- NOTREACHED() << "bad state";
+ NOTREACHED() << "bad state " << state;
Finish(result);
return;
}
@@ -484,18 +510,14 @@ int SocketStream::DoResolveHost() {
proxy_mode_ = kTunnelProxy;
// Determine the host and port to connect to.
- std::string host;
- int port;
+ HostPortPair host_port_pair;
if (proxy_mode_ != kDirectConnection) {
- ProxyServer proxy_server = proxy_info_.proxy_server();
- host = proxy_server.HostNoBrackets();
- port = proxy_server.port();
+ host_port_pair = proxy_info_.proxy_server().host_port_pair();
} else {
- host = url_.HostNoBrackets();
- port = url_.EffectiveIntPort();
+ host_port_pair = HostPortPair::FromURL(url_);
}
- HostResolver::RequestInfo resolve_info(host, port);
+ HostResolver::RequestInfo resolve_info(host_port_pair);
DCHECK(host_resolver_.get());
resolver_.reset(new SingleRequestHostResolver(host_resolver_.get()));
@@ -504,7 +526,7 @@ int SocketStream::DoResolveHost() {
}
int SocketStream::DoResolveHostComplete(int result) {
- if (result == OK) {
+ if (result == OK && delegate_) {
next_state_ = STATE_TCP_CONNECT;
result = delegate_->OnStartOpenConnection(this, &io_callback_);
if (result == net::ERR_IO_PENDING)
@@ -516,11 +538,16 @@ int SocketStream::DoResolveHostComplete(int result) {
return result;
}
-int SocketStream::DoTcpConnect() {
+int SocketStream::DoTcpConnect(int result) {
+ if (result != OK) {
+ next_state_ = STATE_CLOSE;
+ return result;
+ }
next_state_ = STATE_TCP_CONNECT_COMPLETE;
DCHECK(factory_);
socket_.reset(factory_->CreateTCPClientSocket(addresses_,
- net_log_.net_log()));
+ net_log_.net_log(),
+ net_log_.source()));
metrics_->OnStartConnection();
return socket_->Connect(&io_callback_);
}
@@ -599,7 +626,7 @@ int SocketStream::DoWriteTunnelHeaders() {
": " + auth_token + "\r\n");
}
- tunnel_request_headers_->headers_ = StringPrintf(
+ tunnel_request_headers_->headers_ = base::StringPrintf(
"CONNECT %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Proxy-Connection: keep-alive\r\n",
@@ -715,7 +742,7 @@ int SocketStream::DoReadTunnelHeadersComplete(int result) {
auth_info_ = new AuthChallengeInfo;
auth_info_->is_proxy = true;
auth_info_->host_and_port =
- ASCIIToWide(proxy_info_.proxy_server().host_and_port());
+ ASCIIToWide(proxy_info_.proxy_server().host_port_pair().ToString());
auth_info_->scheme = ASCIIToWide(auth_handler_->scheme());
auth_info_->realm = ASCIIToWide(auth_handler_->realm());
// Wait until RestartWithAuth or Close is called.
@@ -738,8 +765,7 @@ int SocketStream::DoSOCKSConnect() {
next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
ClientSocket* s = socket_.release();
- HostResolver::RequestInfo req_info(url_.HostNoBrackets(),
- url_.EffectiveIntPort());
+ HostResolver::RequestInfo req_info(HostPortPair::FromURL(url_));
DCHECK(!proxy_info_.is_empty());
if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5)
@@ -839,26 +865,32 @@ int SocketStream::DoReadWrite(int result) {
next_state_ = STATE_READ_WRITE;
- if (!read_buf_) {
- // No read pending.
- read_buf_ = new IOBuffer(kReadBufferSize);
- result = socket_->Read(read_buf_, kReadBufferSize, &read_callback_);
- if (result > 0) {
- return DidReceiveData(result);
- } else if (result == 0) {
- // 0 indicates end-of-file, so socket was closed.
- next_state_ = STATE_CLOSE;
- return ERR_CONNECTION_CLOSED;
- }
- // If read is pending, try write as well.
- // Otherwise, return the result and do next loop (to close the connection).
- if (result != ERR_IO_PENDING) {
- next_state_ = STATE_CLOSE;
- return result;
+ // If server already closed the socket, we don't try to read.
+ if (!server_closed_) {
+ if (!read_buf_) {
+ // No read pending and server didn't close the socket.
+ read_buf_ = new IOBuffer(kReadBufferSize);
+ result = socket_->Read(read_buf_, kReadBufferSize, &read_callback_);
+ if (result > 0) {
+ return DidReceiveData(result);
+ } else if (result == 0) {
+ // 0 indicates end-of-file, so socket was closed.
+ next_state_ = STATE_CLOSE;
+ server_closed_ = true;
+ return ERR_CONNECTION_CLOSED;
+ }
+ // If read is pending, try write as well.
+ // Otherwise, return the result and do next loop (to close the
+ // connection).
+ if (result != ERR_IO_PENDING) {
+ next_state_ = STATE_CLOSE;
+ server_closed_ = true;
+ return result;
+ }
}
+ // Read is pending.
+ DCHECK(read_buf_);
}
- // Read is pending.
- DCHECK(read_buf_);
if (write_buf_ && !current_write_buf_) {
// No write pending.
@@ -885,7 +917,8 @@ int SocketStream::DoReadWrite(int result) {
GURL SocketStream::ProxyAuthOrigin() const {
DCHECK(!proxy_info_.is_empty());
- return GURL("http://" + proxy_info_.proxy_server().host_and_port());
+ return GURL("http://" +
+ proxy_info_.proxy_server().host_port_pair().ToString());
}
int SocketStream::HandleAuthChallenge(const HttpResponseHeaders* headers) {
@@ -893,10 +926,11 @@ int SocketStream::HandleAuthChallenge(const HttpResponseHeaders* headers) {
LOG(INFO) << "The proxy " << auth_origin << " requested auth";
- // The auth we tried just failed, hence it can't be valid.
- // Remove it from the cache so it won't be used again.
- if (auth_handler_.get() && !auth_identity_.invalid &&
- auth_handler_->IsFinalRound()) {
+ // TODO(cbentzel): Since SocketStream only suppports basic authentication
+ // right now, another challenge is always treated as a rejection.
+ // Ultimately this should be converted to use HttpAuthController like the
+ // HttpNetworkTransaction has.
+ if (auth_handler_.get() && !auth_identity_.invalid) {
if (auth_identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP)
auth_cache_.Remove(auth_origin,
auth_handler_->realm(),
@@ -990,4 +1024,3 @@ ProxyService* SocketStream::proxy_service() const {
}
} // namespace net
-
diff --git a/net/socket_stream/socket_stream.h b/net/socket_stream/socket_stream.h
index d0e8b2e..aaf48de 100644
--- a/net/socket_stream/socket_stream.h
+++ b/net/socket_stream/socket_stream.h
@@ -4,21 +4,23 @@
#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_H_
#define NET_SOCKET_STREAM_SOCKET_STREAM_H_
+#pragma once
#include <deque>
#include <map>
#include <string>
-#include <vector>
#include "base/linked_ptr.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/task.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_log.h"
#include "net/base/net_errors.h"
+#include "net/base/ssl_config_service.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_cache.h"
#include "net/http/http_auth_handler.h"
@@ -132,8 +134,8 @@ class SocketStream : public base::RefCountedThreadSafe<SocketStream> {
// Restarts with authentication info.
// Should be used for response of OnAuthRequired.
virtual void RestartWithAuth(
- const std::wstring& username,
- const std::wstring& password);
+ const string16& username,
+ const string16& password);
// Detach delegate. Call before delegate is deleted.
// Once delegate is detached, close the socket stream and never call delegate
@@ -218,6 +220,8 @@ class SocketStream : public base::RefCountedThreadSafe<SocketStream> {
// Used for WebSocketThrottleTest.
void CopyAddrInfo(struct addrinfo* head);
+ void DoClose();
+
// Finishes the job.
// Calls OnError and OnClose of delegate, and no more
// notifications will be sent to delegate.
@@ -237,7 +241,7 @@ class SocketStream : public base::RefCountedThreadSafe<SocketStream> {
int DoResolveProxyComplete(int result);
int DoResolveHost();
int DoResolveHostComplete(int result);
- int DoTcpConnect();
+ int DoTcpConnect(int result);
int DoTcpConnectComplete(int result);
int DoWriteTunnelHeaders();
int DoWriteTunnelHeadersComplete(int result);
@@ -319,6 +323,7 @@ class SocketStream : public base::RefCountedThreadSafe<SocketStream> {
PendingDataQueue pending_write_bufs_;
bool closing_;
+ bool server_closed_;
scoped_ptr<SocketStreamMetrics> metrics_;
diff --git a/net/socket_stream/socket_stream_job.h b/net/socket_stream/socket_stream_job.h
index 618620c..89e0c36 100644
--- a/net/socket_stream/socket_stream_job.h
+++ b/net/socket_stream/socket_stream_job.h
@@ -4,10 +4,12 @@
#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
+#pragma once
#include <string>
#include "base/ref_counted.h"
+#include "base/string16.h"
#include "net/socket_stream/socket_stream.h"
class GURL;
@@ -64,8 +66,8 @@ class SocketStreamJob : public base::RefCountedThreadSafe<SocketStreamJob> {
}
virtual void RestartWithAuth(
- const std::wstring& username,
- const std::wstring& password) {
+ const string16& username,
+ const string16& password) {
socket_->RestartWithAuth(username, password);
}
diff --git a/net/socket_stream/socket_stream_job_manager.h b/net/socket_stream/socket_stream_job_manager.h
index 17ff833..1150058 100644
--- a/net/socket_stream/socket_stream_job_manager.h
+++ b/net/socket_stream/socket_stream_job_manager.h
@@ -4,6 +4,7 @@
#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
+#pragma once
#include <map>
#include <string>
diff --git a/net/socket_stream/socket_stream_metrics.h b/net/socket_stream/socket_stream_metrics.h
index 44cbc7b..946a065 100644
--- a/net/socket_stream/socket_stream_metrics.h
+++ b/net/socket_stream/socket_stream_metrics.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.
//
@@ -7,8 +7,7 @@
#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
#define NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
-
-#include <string>
+#pragma once
#include "base/basictypes.h"
#include "base/time.h"
diff --git a/net/socket_stream/socket_stream_unittest.cc b/net/socket_stream/socket_stream_unittest.cc
index d32654a..d8e2093 100644
--- a/net/socket_stream/socket_stream_unittest.cc
+++ b/net/socket_stream/socket_stream_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.
@@ -6,6 +6,8 @@
#include <vector>
#include "base/callback.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/auth.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
@@ -119,8 +121,8 @@ class SocketStreamEventRecorder : public net::SocketStream::Delegate {
<< " password=" << password_;
event->socket->RestartWithAuth(username_, password_);
}
- void SetAuthInfo(const std::wstring& username,
- const std::wstring& password) {
+ void SetAuthInfo(const string16& username,
+ const string16& password) {
username_ = username;
password_ = password;
}
@@ -138,8 +140,8 @@ class SocketStreamEventRecorder : public net::SocketStream::Delegate {
Callback1<SocketStreamEvent*>::Type* on_auth_required_;
net::CompletionCallback* callback_;
- std::wstring username_;
- std::wstring password_;
+ string16 username_;
+ string16 password_;
DISALLOW_COPY_AND_ASSIGN(SocketStreamEventRecorder);
};
@@ -307,6 +309,10 @@ TEST_F(SocketStreamTest, BasicAuthProxy) {
MockRead("HTTP/1.1 200 Connection Established\r\n"),
MockRead("Proxy-agent: Apache/2.2.8\r\n"),
MockRead("\r\n"),
+ // SocketStream::DoClose is run asynchronously. Socket can be read after
+ // "\r\n". We have to give ERR_IO_PENDING to SocketStream then to indicate
+ // server doesn't close the connection.
+ MockRead(true, ERR_IO_PENDING)
};
StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
data_writes2, arraysize(data_writes2));
@@ -318,9 +324,7 @@ TEST_F(SocketStreamTest, BasicAuthProxy) {
new SocketStreamEventRecorder(&callback));
delegate->SetOnConnected(NewCallback(delegate.get(),
&SocketStreamEventRecorder::DoClose));
- const std::wstring kUsername = L"foo";
- const std::wstring kPassword = L"bar";
- delegate->SetAuthInfo(kUsername, kPassword);
+ delegate->SetAuthInfo(ASCIIToUTF16("foo"), ASCIIToUTF16("bar"));
delegate->SetOnAuthRequired(
NewCallback(delegate.get(),
&SocketStreamEventRecorder::DoRestartWithAuth));
diff --git a/net/spdy/spdy_bitmasks.h b/net/spdy/spdy_bitmasks.h
index 03752e3..eb34ce6 100644
--- a/net/spdy/spdy_bitmasks.h
+++ b/net/spdy/spdy_bitmasks.h
@@ -4,6 +4,7 @@
#ifndef NET_SPDY_SPDY_BITMASKS_H_
#define NET_SPDY_SPDY_BITMASKS_H_
+#pragma once
namespace spdy {
diff --git a/net/spdy/spdy_frame_builder.cc b/net/spdy/spdy_frame_builder.cc
index 7d21b82..eed6eb2 100644
--- a/net/spdy/spdy_frame_builder.cc
+++ b/net/spdy/spdy_frame_builder.cc
@@ -104,7 +104,6 @@ bool SpdyFrameBuilder::ReadData(void** iter, const char** data,
}
char* SpdyFrameBuilder::BeginWrite(size_t length) {
- size_t offset = length_;
size_t needed_size = length_ + length;
if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
return NULL;
@@ -113,7 +112,7 @@ char* SpdyFrameBuilder::BeginWrite(size_t length) {
DCHECK_LE(length, std::numeric_limits<uint32>::max());
#endif
- return buffer_ + offset;
+ return buffer_ + length_;
}
void SpdyFrameBuilder::EndWrite(char* dest, int length) {
@@ -163,16 +162,16 @@ char* SpdyFrameBuilder::BeginWriteData(uint16 length) {
}
bool SpdyFrameBuilder::Resize(size_t new_capacity) {
- if (new_capacity < capacity_)
+ if (new_capacity <= capacity_)
return true;
char* p = new char[new_capacity];
+ if (!p)
+ return false;
if (buffer_) {
memcpy(p, buffer_, capacity_);
delete[] buffer_;
}
- if (!p && new_capacity > 0)
- return false;
buffer_ = p;
capacity_ = new_capacity;
return true;
diff --git a/net/spdy/spdy_frame_builder.h b/net/spdy/spdy_frame_builder.h
index 5b70437..548cfda 100644
--- a/net/spdy/spdy_frame_builder.h
+++ b/net/spdy/spdy_frame_builder.h
@@ -1,9 +1,10 @@
-// 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.
-#ifndef NET_SPDY_FRAME_BUILDER_H_
-#define NET_SPDY_FRAME_BUILDER_H_
+#ifndef NET_SPDY_SPDY_FRAME_BUILDER_H_
+#define NET_SPDY_SPDY_FRAME_BUILDER_H_
+#pragma once
#ifdef WIN32
#include <winsock2.h> // for htonl() functions
@@ -13,7 +14,7 @@
#include <string>
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "net/spdy/spdy_protocol.h"
namespace spdy {
@@ -159,5 +160,4 @@ class SpdyFrameBuilder {
} // namespace spdy
-#endif // NET_SPDY_FRAME_BUILDER_H_
-
+#endif // NET_SPDY_SPDY_FRAME_BUILDER_H_
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index cd622b8..50682a8 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -27,6 +27,7 @@ static const size_t kControlFrameBufferMaxSize = 64 * 1024;
// By default is compression on or off.
bool SpdyFramer::compression_default_ = true;
+int SpdyFramer::spdy_version_ = kSpdyProtocolVersion;
#ifdef DEBUG_SPDY_STATE_CHANGES
#define CHANGE_STATE(newstate) \
@@ -169,7 +170,7 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
continue;
case SPDY_READING_COMMON_HEADER: {
- int bytes_read = ProcessCommonHeader(data, len);
+ size_t bytes_read = ProcessCommonHeader(data, len);
len -= bytes_read;
data += bytes_read;
continue;
@@ -183,7 +184,7 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
continue;
case SPDY_CONTROL_FRAME_PAYLOAD: {
- int bytes_read = ProcessControlFramePayload(data, len);
+ size_t bytes_read = ProcessControlFramePayload(data, len);
len -= bytes_read;
data += bytes_read;
}
@@ -192,7 +193,7 @@ size_t SpdyFramer::ProcessInput(const char* data, size_t len) {
// control frame has too-large payload
// intentional fallthrough
case SPDY_FORWARD_STREAM_FRAME: {
- int bytes_read = ProcessDataFramePayload(data, len);
+ size_t bytes_read = ProcessDataFramePayload(data, len);
len -= bytes_read;
data += bytes_read;
continue;
@@ -210,7 +211,7 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
// state.
DCHECK_EQ(state_, SPDY_READING_COMMON_HEADER);
- int original_len = len;
+ size_t original_len = len;
SpdyFrame current_frame(current_frame_buffer_, false);
do {
@@ -259,7 +260,7 @@ void SpdyFramer::ProcessControlFrameHeader() {
// We check version before we check validity: version can never be 'invalid',
// it can only be unsupported.
- if (current_control_frame.version() != kSpdyProtocolVersion) {
+ if (current_control_frame.version() != spdy_version_) {
set_error(SPDY_UNSUPPORTED_VERSION);
return;
}
@@ -421,11 +422,10 @@ size_t SpdyFramer::ProcessDataFramePayload(const char* data, size_t len) {
}
void SpdyFramer::ExpandControlFrameBuffer(size_t size) {
- DCHECK_LT(size, kControlFrameBufferMaxSize);
- if (size < current_frame_capacity_)
+ size_t alloc_size = size + SpdyFrame::size();
+ DCHECK_LT(alloc_size, kControlFrameBufferMaxSize);
+ if (alloc_size <= current_frame_capacity_)
return;
-
- int alloc_size = size + SpdyFrame::size();
char* new_buffer = new char[alloc_size];
memcpy(new_buffer, current_frame_buffer_, current_frame_len_);
delete [] current_frame_buffer_;
@@ -520,7 +520,7 @@ SpdySynStreamControlFrame* SpdyFramer::CreateSynStream(
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
DCHECK_EQ(0u, associated_stream_id & ~kStreamIdMask);
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(SYN_STREAM);
frame.WriteUInt32(0); // Placeholder for the length and flags
frame.WriteUInt32(stream_id);
@@ -562,7 +562,7 @@ SpdyRstStreamControlFrame* SpdyFramer::CreateRstStream(SpdyStreamId stream_id,
DCHECK_LT(status, NUM_STATUS_CODES);
SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(RST_STREAM);
frame.WriteUInt32(8);
frame.WriteUInt32(stream_id);
@@ -576,7 +576,7 @@ SpdyGoAwayControlFrame* SpdyFramer::CreateGoAway(
DCHECK_EQ(0u, last_accepted_stream_id & ~kStreamIdMask);
SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(GOAWAY);
size_t go_away_size = SpdyGoAwayControlFrame::size() - SpdyFrame::size();
frame.WriteUInt32(go_away_size);
@@ -594,7 +594,7 @@ SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
DCHECK_LT(delta_window_size, 0x80000000u); // 2^31
SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(WINDOW_UPDATE);
size_t window_update_size = SpdyWindowUpdateControlFrame::size() -
SpdyFrame::size();
@@ -608,7 +608,7 @@ SpdyWindowUpdateControlFrame* SpdyFramer::CreateWindowUpdate(
SpdySettingsControlFrame* SpdyFramer::CreateSettings(
const SpdySettings& values) {
SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(SETTINGS);
size_t settings_size = SpdySettingsControlFrame::size() - SpdyFrame::size() +
8 * values.size();
@@ -630,7 +630,7 @@ SpdySynReplyControlFrame* SpdyFramer::CreateSynReply(SpdyStreamId stream_id,
SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(SYN_REPLY);
frame.WriteUInt32(0); // Placeholder for the length and flags.
frame.WriteUInt32(stream_id);
@@ -697,7 +697,7 @@ SpdyDataFrame* SpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
/* static */
SpdyControlFrame* SpdyFramer::CreateNopFrame() {
SpdyFrameBuilder frame;
- frame.WriteUInt16(kControlFlagMask | kSpdyProtocolVersion);
+ frame.WriteUInt16(kControlFlagMask | spdy_version_);
frame.WriteUInt16(NOOP);
frame.WriteUInt32(0);
return reinterpret_cast<SpdyControlFrame*>(frame.take());
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index f188373..e6d0e15 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -4,6 +4,7 @@
#ifndef NET_SPDY_SPDY_FRAMER_H_
#define NET_SPDY_SPDY_FRAMER_H_
+#pragma once
#ifdef _WIN32
#include <winsock2.h>
@@ -16,10 +17,9 @@
#include <utility>
#include "base/basictypes.h"
-#include "base/logging.h"
+#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "net/spdy/spdy_protocol.h"
-#include "testing/gtest/include/gtest/gtest_prod.h"
typedef struct z_stream_s z_stream; // Forward declaration for zlib.
@@ -238,14 +238,16 @@ class SpdyFramer {
// For debugging.
static const char* StateToString(int state);
static const char* ErrorCodeToString(int error_code);
+ static void set_protocol_version(int version) { spdy_version_= version; }
+ static int protocol_version() { return spdy_version_; }
// Export the compression dictionary
static const char kDictionary[];
static const int kDictionarySize;
protected:
- FRIEND_TEST(SpdyFramerTest, DataCompression);
- FRIEND_TEST(SpdyFramerTest, UnclosedStreamDataCompressors);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, DataCompression);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, UnclosedStreamDataCompressors);
friend class net::SpdyNetworkTransactionTest;
friend class net::HttpNetworkTransactionTest;
friend class net::HttpNetworkLayer; // This is temporary for the server.
@@ -327,6 +329,7 @@ class SpdyFramer {
SpdyFramerVisitorInterface* visitor_;
static bool compression_default_;
+ static int spdy_version_;
};
} // namespace spdy
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 4e976ab..d238062 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -438,7 +438,7 @@ TEST_F(SpdyFramerTest, DecompressUncompressedFrame) {
TEST_F(SpdyFramerTest, Basic) {
const unsigned char input[] = {
- 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
+ 0x80, 0x02, 0x00, 0x01, // SYN Stream #1
0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
@@ -452,7 +452,7 @@ TEST_F(SpdyFramerTest, Basic) {
0xde, 0xad, 0xbe, 0xef,
0xde, 0xad, 0xbe, 0xef,
- 0x80, 0x01, 0x00, 0x01, // SYN Stream #3
+ 0x80, 0x02, 0x00, 0x01, // SYN Stream #3
0x00, 0x00, 0x00, 0x0c,
0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x00,
@@ -467,7 +467,7 @@ TEST_F(SpdyFramerTest, Basic) {
0x00, 0x00, 0x00, 0x04,
0xde, 0xad, 0xbe, 0xef,
- 0x80, 0x01, 0x00, 0x03, // RST_STREAM on Stream #1
+ 0x80, 0x02, 0x00, 0x03, // RST_STREAM on Stream #1
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
@@ -475,7 +475,7 @@ TEST_F(SpdyFramerTest, Basic) {
0x00, 0x00, 0x00, 0x03, // DATA on Stream #3
0x00, 0x00, 0x00, 0x00,
- 0x80, 0x01, 0x00, 0x03, // RST_STREAM on Stream #3
+ 0x80, 0x02, 0x00, 0x03, // RST_STREAM on Stream #3
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x00,
@@ -496,7 +496,7 @@ TEST_F(SpdyFramerTest, Basic) {
// Test that the FIN flag on a data frame signifies EOF.
TEST_F(SpdyFramerTest, FinOnDataFrame) {
const unsigned char input[] = {
- 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
+ 0x80, 0x02, 0x00, 0x01, // SYN Stream #1
0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
@@ -504,7 +504,7 @@ TEST_F(SpdyFramerTest, FinOnDataFrame) {
0x00, 0x02, 'h', 'h',
0x00, 0x02, 'v', 'v',
- 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1
+ 0x80, 0x02, 0x00, 0x02, // SYN REPLY Stream #1
0x00, 0x00, 0x00, 0x10,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
@@ -537,7 +537,7 @@ TEST_F(SpdyFramerTest, FinOnDataFrame) {
// Test that the FIN flag on a SYN reply frame signifies EOF.
TEST_F(SpdyFramerTest, FinOnSynReplyFrame) {
const unsigned char input[] = {
- 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
+ 0x80, 0x02, 0x00, 0x01, // SYN Stream #1
0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
@@ -545,7 +545,7 @@ TEST_F(SpdyFramerTest, FinOnSynReplyFrame) {
0x00, 0x02, 'h', 'h',
0x00, 0x02, 'v', 'v',
- 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1
+ 0x80, 0x02, 0x00, 0x02, // SYN REPLY Stream #1
0x01, 0x00, 0x00, 0x10,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
@@ -788,7 +788,7 @@ TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) {
headers["foo"] = "bar";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x01,
+ 0x80, 0x02, 0x00, 0x01,
0x00, 0x00, 0x00, 0x20,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
@@ -815,7 +815,7 @@ TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) {
headers["foo"] = "bar";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x01,
+ 0x80, 0x02, 0x00, 0x01,
0x01, 0x00, 0x00, 0x1D,
0x7f, 0xff, 0xff, 0xff,
0x7f, 0xff, 0xff, 0xff,
@@ -842,7 +842,7 @@ TEST_F(SpdyFramerTest, CreateSynStreamUncompressed) {
headers["foo"] = "";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x01,
+ 0x80, 0x02, 0x00, 0x01,
0x01, 0x00, 0x00, 0x1D,
0x7f, 0xff, 0xff, 0xff,
0x7f, 0xff, 0xff, 0xff,
@@ -873,7 +873,7 @@ TEST_F(SpdyFramerTest, CreateSynStreamCompressed) {
headers["foo"] = "bar";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x01,
+ 0x80, 0x02, 0x00, 0x01,
0x00, 0x00, 0x00, 0x25,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
@@ -905,7 +905,7 @@ TEST_F(SpdyFramerTest, CreateSynReplyUncompressed) {
headers["foo"] = "bar";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x02,
+ 0x80, 0x02, 0x00, 0x02,
0x00, 0x00, 0x00, 0x1C,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x02,
@@ -929,7 +929,7 @@ TEST_F(SpdyFramerTest, CreateSynReplyUncompressed) {
headers["foo"] = "bar";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x02,
+ 0x80, 0x02, 0x00, 0x02,
0x01, 0x00, 0x00, 0x19,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x02,
@@ -953,7 +953,7 @@ TEST_F(SpdyFramerTest, CreateSynReplyUncompressed) {
headers["foo"] = "";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x02,
+ 0x80, 0x02, 0x00, 0x02,
0x01, 0x00, 0x00, 0x19,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x02,
@@ -981,7 +981,7 @@ TEST_F(SpdyFramerTest, CreateSynReplyCompressed) {
headers["foo"] = "bar";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x02,
+ 0x80, 0x02, 0x00, 0x02,
0x00, 0x00, 0x00, 0x21,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x38, 0xea,
@@ -1005,7 +1005,7 @@ TEST_F(SpdyFramerTest, CreateRstStream) {
{
const char kDescription[] = "RST_STREAM frame";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x03,
+ 0x80, 0x02, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
@@ -1017,7 +1017,7 @@ TEST_F(SpdyFramerTest, CreateRstStream) {
{
const char kDescription[] = "RST_STREAM frame with max stream ID";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x03,
+ 0x80, 0x02, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01,
@@ -1030,7 +1030,7 @@ TEST_F(SpdyFramerTest, CreateRstStream) {
{
const char kDescription[] = "RST_STREAM frame with max status code";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x03,
+ 0x80, 0x02, 0x00, 0x03,
0x00, 0x00, 0x00, 0x08,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x06,
@@ -1061,7 +1061,7 @@ TEST_F(SpdyFramerTest, CreateSettings) {
settings.push_back(SpdySetting(0x01000004, 0xffffffff));
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x04,
+ 0x80, 0x02, 0x00, 0x04,
0x00, 0x00, 0x00, 0x44,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00,
@@ -1091,7 +1091,7 @@ TEST_F(SpdyFramerTest, CreateSettings) {
SpdySettings settings;
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x04,
+ 0x80, 0x02, 0x00, 0x04,
0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00,
};
@@ -1106,7 +1106,7 @@ TEST_F(SpdyFramerTest, CreateNopFrame) {
{
const char kDescription[] = "NOOP frame";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x05,
+ 0x80, 0x02, 0x00, 0x05,
0x00, 0x00, 0x00, 0x00,
};
scoped_ptr<SpdyFrame> frame(framer.CreateNopFrame());
@@ -1120,7 +1120,7 @@ TEST_F(SpdyFramerTest, CreateGoAway) {
{
const char kDescription[] = "GOAWAY frame";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x07,
+ 0x80, 0x02, 0x00, 0x07,
0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00,
};
@@ -1131,7 +1131,7 @@ TEST_F(SpdyFramerTest, CreateGoAway) {
{
const char kDescription[] = "GOAWAY frame with max stream ID";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x07,
+ 0x80, 0x02, 0x00, 0x07,
0x00, 0x00, 0x00, 0x04,
0x7f, 0xff, 0xff, 0xff,
};
@@ -1146,7 +1146,7 @@ TEST_F(SpdyFramerTest, CreateWindowUpdate) {
{
const char kDescription[] = "WINDOW_UPDATE frame";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x09,
+ 0x80, 0x02, 0x00, 0x09,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
@@ -1158,7 +1158,7 @@ TEST_F(SpdyFramerTest, CreateWindowUpdate) {
{
const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x09,
+ 0x80, 0x02, 0x00, 0x09,
0x00, 0x00, 0x00, 0x08,
0x7f, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x01,
@@ -1170,7 +1170,7 @@ TEST_F(SpdyFramerTest, CreateWindowUpdate) {
{
const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
const unsigned char kFrameData[] = {
- 0x80, 0x01, 0x00, 0x09,
+ 0x80, 0x02, 0x00, 0x09,
0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x01,
0x7f, 0xff, 0xff, 0xff,
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 581cb27..0e3962e 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -10,149 +10,42 @@
#include "base/logging.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
#include "net/base/load_flags.h"
+#include "net/base/net_util.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
+#include "net/http/http_util.h"
+#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session.h"
-namespace {
-
-// 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.
-bool SpdyHeadersToHttpResponse(const spdy::SpdyHeaderBlock& headers,
- net::HttpResponseInfo* response) {
- std::string version;
- std::string status;
-
- // The "status" and "version" headers are required.
- spdy::SpdyHeaderBlock::const_iterator it;
- it = headers.find("status");
- if (it == headers.end()) {
- LOG(ERROR) << "SpdyHeaderBlock without status header.";
- return false;
- }
- status = it->second;
-
- // Grab the version. If not provided by the server,
- it = headers.find("version");
- if (it == headers.end()) {
- LOG(ERROR) << "SpdyHeaderBlock without version header.";
- return false;
- }
- version = it->second;
-
- response->response_time = base::Time::Now();
-
- std::string raw_headers(version);
- raw_headers.push_back(' ');
- raw_headers.append(status);
- raw_headers.push_back('\0');
- for (it = headers.begin(); it != headers.end(); ++it) {
- // For each value, if the server sends a NUL-separated
- // list of values, we separate that back out into
- // individual headers for each value in the list.
- // e.g.
- // Set-Cookie "foo\0bar"
- // becomes
- // Set-Cookie: foo\0
- // Set-Cookie: bar\0
- std::string value = it->second;
- size_t start = 0;
- size_t end = 0;
- do {
- end = value.find('\0', start);
- std::string tval;
- if (end != value.npos)
- tval = value.substr(start, (end - start));
- else
- tval = value.substr(start);
- raw_headers.append(it->first);
- raw_headers.push_back(':');
- raw_headers.append(tval);
- raw_headers.push_back('\0');
- start = end + 1;
- } while (end != value.npos);
- }
-
- response->headers = new net::HttpResponseHeaders(raw_headers);
- response->was_fetched_via_spdy = true;
- return true;
-}
-
-// Create a SpdyHeaderBlock for a Spdy SYN_STREAM Frame from
-// a HttpRequestInfo block.
-void CreateSpdyHeadersFromHttpRequest(
- const net::HttpRequestInfo& info, spdy::SpdyHeaderBlock* headers) {
- // TODO(willchan): It's not really necessary to convert from
- // HttpRequestHeaders to spdy::SpdyHeaderBlock.
-
- static const char kHttpProtocolVersion[] = "HTTP/1.1";
-
- net::HttpRequestHeaders::Iterator it(info.extra_headers);
-
- while (it.GetNext()) {
- std::string name = StringToLowerASCII(it.name());
- if (headers->find(name) == headers->end()) {
- (*headers)[name] = it.value();
- } else {
- std::string new_value = (*headers)[name];
- new_value.append(1, '\0'); // +=() doesn't append 0's
- new_value += it.value();
- (*headers)[name] = new_value;
- }
- }
-
- // TODO(mbelshe): Add Proxy headers here. (See http_network_transaction.cc)
- // TODO(mbelshe): Add authentication headers here.
-
- (*headers)["method"] = info.method;
- (*headers)["url"] = info.url.spec();
- (*headers)["version"] = kHttpProtocolVersion;
- if (!info.referrer.is_empty())
- (*headers)["referer"] = info.referrer.spec();
-
- // Honor load flags that impact proxy caches.
- if (info.load_flags & net::LOAD_BYPASS_CACHE) {
- (*headers)["pragma"] = "no-cache";
- (*headers)["cache-control"] = "no-cache";
- } else if (info.load_flags & net::LOAD_VALIDATE_CACHE) {
- (*headers)["cache-control"] = "max-age=0";
- }
-}
-
-} // anonymous namespace
-
namespace net {
-SpdyHttpStream::SpdyHttpStream()
+SpdyHttpStream::SpdyHttpStream(SpdySession* spdy_session, bool direct)
: ALLOW_THIS_IN_INITIALIZER_LIST(read_callback_factory_(this)),
stream_(NULL),
- spdy_session_(NULL),
+ spdy_session_(spdy_session),
response_info_(NULL),
download_finished_(false),
user_callback_(NULL),
user_buffer_len_(0),
buffered_read_callback_pending_(false),
- more_read_data_pending_(false) { }
+ more_read_data_pending_(false),
+ direct_(direct) { }
SpdyHttpStream::~SpdyHttpStream() {
if (stream_)
stream_->DetachDelegate();
}
-int SpdyHttpStream::InitializeStream(
- SpdySession* spdy_session,
- const HttpRequestInfo& request_info,
- const BoundNetLog& stream_net_log,
- CompletionCallback* callback) {
- spdy_session_ = spdy_session;
+int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
+ const BoundNetLog& stream_net_log,
+ CompletionCallback* callback) {
+ if (spdy_session_->IsClosed())
+ return ERR_CONNECTION_CLOSED;
+
request_info_ = request_info;
- if (request_info_.method == "GET") {
- int error = spdy_session_->GetPushStream(request_info.url, &stream_,
+ if (request_info_->method == "GET") {
+ int error = spdy_session_->GetPushStream(request_info_->url, &stream_,
stream_net_log);
if (error != OK)
return error;
@@ -160,35 +53,10 @@ int SpdyHttpStream::InitializeStream(
if (stream_.get())
return OK;
- else
- return spdy_session_->CreateStream(request_info_.url,
- request_info_.priority, &stream_,
- stream_net_log, callback);
-}
-
-void SpdyHttpStream::InitializeRequest(
- base::Time request_time,
- UploadDataStream* upload_data) {
- CHECK(stream_.get());
- stream_->SetDelegate(this);
- linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
- CreateSpdyHeadersFromHttpRequest(request_info_, headers.get());
- stream_->set_spdy_headers(headers);
-
- stream_->SetRequestTime(request_time);
- // This should only get called in the case of a request occuring
- // during server push that has already begun but hasn't finished,
- // so we set the response's request time to be the actual one
- if (response_info_)
- response_info_->request_time = request_time;
- CHECK(!request_body_stream_.get());
- if (upload_data) {
- if (upload_data->size())
- request_body_stream_.reset(upload_data);
- else
- delete upload_data;
- }
+ return spdy_session_->CreateStream(request_info_->url,
+ request_info_->priority, &stream_,
+ stream_net_log, callback);
}
const HttpResponseInfo* SpdyHttpStream::GetResponseInfo() const {
@@ -203,28 +71,30 @@ uint64 SpdyHttpStream::GetUploadProgress() const {
}
int SpdyHttpStream::ReadResponseHeaders(CompletionCallback* callback) {
- DCHECK(stream_->is_idle());
- // Note: The SpdyStream may have already received the response headers, so
- // this call may complete synchronously.
CHECK(callback);
+ CHECK(!stream_->cancelled());
- if (stream_->response_complete())
+ if (stream_->closed())
return stream_->response_status();
- int result = stream_->DoReadResponseHeaders();
- if (result == ERR_IO_PENDING) {
- CHECK(!user_callback_);
- user_callback_ = callback;
+ // Check if we already have the response headers. If so, return synchronously.
+ if(stream_->response_received()) {
+ CHECK(stream_->is_idle());
+ return OK;
}
- return result;
+
+ // Still waiting for the response, return IO_PENDING.
+ CHECK(!user_callback_);
+ user_callback_ = callback;
+ return ERR_IO_PENDING;
}
int SpdyHttpStream::ReadResponseBody(
IOBuffer* buf, int buf_len, CompletionCallback* callback) {
+ CHECK(stream_->is_idle());
CHECK(buf);
CHECK(buf_len);
CHECK(callback);
- DCHECK(stream_->is_idle());
// If we have data buffered, complete the IO immediately.
if (!response_body_.empty()) {
@@ -246,8 +116,10 @@ int SpdyHttpStream::ReadResponseBody(
}
bytes_read += bytes_to_copy;
}
+ if (spdy_session_->flow_control())
+ stream_->IncreaseRecvWindowSize(bytes_read);
return bytes_read;
- } else if (stream_->response_complete()) {
+ } else if (stream_->closed()) {
return stream_->response_status();
}
@@ -261,13 +133,45 @@ int SpdyHttpStream::ReadResponseBody(
return ERR_IO_PENDING;
}
-int SpdyHttpStream::SendRequest(HttpResponseInfo* response,
+void SpdyHttpStream::Close(bool not_reusable) {
+ // Note: the not_reusable flag has no meaning for SPDY streams.
+
+ Cancel();
+}
+
+int SpdyHttpStream::SendRequest(const std::string& /*headers_string*/,
+ UploadDataStream* request_body,
+ HttpResponseInfo* response,
CompletionCallback* callback) {
+ base::Time request_time = base::Time::Now();
+ CHECK(stream_.get());
+
+ stream_->SetDelegate(this);
+
+ linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
+ CreateSpdyHeadersFromHttpRequest(*request_info_, headers.get(), direct_);
+ stream_->set_spdy_headers(headers);
+
+ stream_->SetRequestTime(request_time);
+ // This should only get called in the case of a request occurring
+ // during server push that has already begun but hasn't finished,
+ // so we set the response's request time to be the actual one
+ if (response_info_)
+ response_info_->request_time = request_time;
+
+ CHECK(!request_body_stream_.get());
+ if (request_body) {
+ if (request_body->size())
+ request_body_stream_.reset(request_body);
+ else
+ delete request_body;
+ }
+
CHECK(callback);
CHECK(!stream_->cancelled());
CHECK(response);
- if (stream_->response_complete()) {
+ if (!stream_->pushed() && stream_->closed()) {
if (stream_->response_status() == OK)
return ERR_FAILED;
else
@@ -279,20 +183,18 @@ int SpdyHttpStream::SendRequest(HttpResponseInfo* response,
// a) A client initiated request. In this case, |response_info_| should be
// NULL to start with.
// b) A client request which matches a response that the server has already
- // pushed. In this case, the value of |*push_response_info_| is copied
- // over to the new response object |*response|. |push_response_info_| is
- // deleted, and |response_info_| is reset |response|.
+ // pushed.
if (push_response_info_.get()) {
- *response = *push_response_info_;
+ *response = *(push_response_info_.get());
push_response_info_.reset();
- response_info_ = NULL;
}
+ else
+ DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_);
- DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_);
response_info_ = response;
bool has_upload_data = request_body_stream_.get() != NULL;
- int result = stream_->DoSendRequest(has_upload_data);
+ int result = stream_->SendRequest(has_upload_data);
if (result == ERR_IO_PENDING) {
CHECK(!user_callback_);
user_callback_ = callback;
@@ -309,6 +211,8 @@ void SpdyHttpStream::Cancel() {
}
bool SpdyHttpStream::OnSendHeadersComplete(int status) {
+ if (user_callback_)
+ DoCallback(status);
return request_body_stream_.get() == NULL;
}
@@ -336,13 +240,18 @@ int SpdyHttpStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response,
response_info_ = push_response_info_.get();
}
+ // TODO(mbelshe): This is the time of all headers received, not just time
+ // to first byte.
+ DCHECK(response_info_->response_time.is_null());
+ response_info_->response_time = base::Time::Now();
+
if (!SpdyHeadersToHttpResponse(response, response_info_)) {
status = ERR_INVALID_RESPONSE;
} else {
stream_->GetSSLInfo(&response_info_->ssl_info,
&response_info_->was_npn_negotiated);
response_info_->request_time = stream_->GetRequestTime();
- response_info_->vary_data.Init(request_info_, *response_info_->headers);
+ response_info_->vary_data.Init(*request_info_, *response_info_->headers);
// TODO(ahendrickson): This is recorded after the entire SYN_STREAM control
// frame has been received and processed. Move to framer?
response_info_->response_time = response_time;
@@ -357,7 +266,8 @@ void SpdyHttpStream::OnDataReceived(const char* data, int length) {
// Note that data may be received for a SpdyStream prior to the user calling
// ReadResponseBody(), therefore user_buffer_ may be NULL. This may often
// happen for server initiated streams.
- if (length > 0 && !stream_->response_complete()) {
+ DCHECK(!stream_->closed() || stream_->pushed());
+ if (length > 0) {
// Save the received data.
IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
memcpy(io_buffer->data(), data, length);
@@ -407,7 +317,7 @@ void SpdyHttpStream::ScheduleBufferedReadCallback() {
// the caller. Returns true if we should wait, false otherwise.
bool SpdyHttpStream::ShouldWaitForMoreBufferedData() const {
// If the response is complete, there is no point in waiting.
- if (stream_->response_complete())
+ if (stream_->closed())
return false;
int bytes_buffered = 0;
@@ -459,4 +369,16 @@ void SpdyHttpStream::DoCallback(int rv) {
c->Run(rv);
}
+void SpdyHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
+ DCHECK(stream_);
+ bool using_npn;
+ stream_->GetSSLInfo(ssl_info, &using_npn);
+}
+
+void SpdyHttpStream::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ DCHECK(stream_);
+ stream_->GetSSLCertRequestInfo(cert_request_info);
+}
+
} // namespace net
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h
index 3926501..eab605c 100644
--- a/net/spdy/spdy_http_stream.h
+++ b/net/spdy/spdy_http_stream.h
@@ -4,8 +4,10 @@
#ifndef NET_SPDY_SPDY_HTTP_STREAM_H_
#define NET_SPDY_SPDY_HTTP_STREAM_H_
+#pragma once
#include <list>
+#include <string>
#include "base/basictypes.h"
#include "base/ref_counted.h"
@@ -13,7 +15,9 @@
#include "net/base/completion_callback.h"
#include "net/base/net_log.h"
#include "net/http/http_request_info.h"
+#include "net/http/http_stream.h"
#include "net/spdy/spdy_protocol.h"
+#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_stream.h"
namespace net {
@@ -25,53 +29,77 @@ class UploadData;
class UploadDataStream;
// The SpdyHttpStream is a HTTP-specific type of stream known to a SpdySession.
-class SpdyHttpStream : public SpdyStream::Delegate {
+class SpdyHttpStream : public SpdyStream::Delegate, public HttpStream {
public:
// SpdyHttpStream constructor
- SpdyHttpStream();
+ SpdyHttpStream(SpdySession* spdy_session, bool direct);
virtual ~SpdyHttpStream();
SpdyStream* stream() { return stream_.get(); }
- // Initialize stream. Must be called before calling InitializeRequest().
- int InitializeStream(SpdySession* spdy_session,
- const HttpRequestInfo& request_info,
- const BoundNetLog& stream_net_log,
- CompletionCallback* callback);
-
- // Initialize request. Must be called before calling SendRequest().
- // SpdyHttpStream takes ownership of |upload_data|. |upload_data| may be NULL.
- void InitializeRequest(base::Time request_time,
- UploadDataStream* upload_data);
-
- const HttpResponseInfo* GetResponseInfo() const;
-
// ===================================================
- // Interface for [Http|Spdy]NetworkTransaction to use.
+ // HttpStream methods:
+
+ // Initialize stream. Must be called before calling SendRequest().
+ virtual int InitializeStream(const HttpRequestInfo* request_info,
+ const BoundNetLog& net_log,
+ CompletionCallback* callback);
// Sends the request.
// |callback| is used when this completes asynchronously.
+ // SpdyHttpStream takes ownership of |upload_data|. |upload_data| may be NULL.
// The actual SYN_STREAM packet will be sent if the stream is non-pushed.
- int SendRequest(HttpResponseInfo* response,
- CompletionCallback* callback);
+ virtual int SendRequest(const std::string& headers,
+ UploadDataStream* request_body,
+ HttpResponseInfo* response,
+ CompletionCallback* callback);
+
+ // Returns the number of bytes uploaded.
+ virtual uint64 GetUploadProgress() const;
// Reads the response headers. Returns a net error code.
- int ReadResponseHeaders(CompletionCallback* callback);
+ virtual int ReadResponseHeaders(CompletionCallback* callback);
+
+ virtual const HttpResponseInfo* GetResponseInfo() const;
// Reads the response body. Returns a net error code or the number of bytes
// read.
- int ReadResponseBody(
+ virtual int ReadResponseBody(
IOBuffer* buf, int buf_len, CompletionCallback* callback);
- // Cancels any callbacks from being invoked and deletes the stream.
- void Cancel();
+ // Closes the stream.
+ virtual void Close(bool not_reusable);
- // Returns the number of bytes uploaded.
- uint64 GetUploadProgress() const;
+ // Indicates if the response body has been completely read.
+ virtual bool IsResponseBodyComplete() const {
+ if (!stream_)
+ return false;
+ return stream_->closed();
+ }
+
+ // With SPDY the end of response is always detectable.
+ virtual bool CanFindEndOfResponse() const { return true; }
+
+ // A SPDY stream never has more data after the FIN.
+ 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 void GetSSLInfo(SSLInfo* ssl_info);
+ virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
// ===================================================
// SpdyStream::Delegate.
+ // Cancels any callbacks from being invoked and deletes the stream.
+ void Cancel();
+
virtual bool OnSendHeadersComplete(int status);
virtual int OnSendBody();
virtual bool OnSendBodyComplete(int status);
@@ -103,6 +131,8 @@ class SpdyHttpStream : public SpdyStream::Delegate {
virtual void OnClose(int status);
private:
+ FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, FlowControlStallResume);
+
// Call the user callback.
void DoCallback(int rv);
@@ -117,7 +147,7 @@ class SpdyHttpStream : public SpdyStream::Delegate {
scoped_refptr<SpdySession> spdy_session_;
// The request to send.
- HttpRequestInfo request_info_;
+ const HttpRequestInfo* request_info_;
scoped_ptr<UploadDataStream> request_body_stream_;
@@ -146,6 +176,9 @@ class SpdyHttpStream : public SpdyStream::Delegate {
// scheduled read callback.
bool more_read_data_pending_;
+ // Is this spdy stream direct to the origin server (or to a proxy).
+ bool direct_;
+
DISALLOW_COPY_AND_ASSIGN(SpdyHttpStream);
};
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 65a8068..ee1a34e 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -10,8 +10,10 @@
namespace net {
class SpdyHttpStreamTest : public testing::Test {
+ public:
+ OrderedSocketData* data() { return data_; }
protected:
- SpdyHttpStreamTest(){}
+ SpdyHttpStreamTest() {}
void EnableCompression(bool enabled) {
spdy::SpdyFramer::set_enable_compression_default(enabled);
@@ -20,54 +22,137 @@ class SpdyHttpStreamTest : public testing::Test {
virtual void TearDown() {
MessageLoop::current()->RunAllPending();
}
+ int InitSession(MockRead* reads, size_t reads_count,
+ MockWrite* writes, size_t writes_count,
+ HostPortPair& host_port_pair) {
+ HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
+ data_ = new OrderedSocketData(reads, reads_count, writes, writes_count);
+ session_deps_.socket_factory->AddSocketDataProvider(data_.get());
+ http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
+ session_ = http_session_->spdy_session_pool()->
+ Get(pair, http_session_->mutable_spdy_settings(), BoundNetLog());
+ tcp_params_ = new TCPSocketParams(host_port_pair.host(),
+ host_port_pair.port(),
+ MEDIUM, GURL(), false);
+ TestCompletionCallback callback;
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+ EXPECT_EQ(ERR_IO_PENDING,
+ connection->Init(host_port_pair.ToString(), tcp_params_, MEDIUM,
+ &callback, http_session_->tcp_socket_pool(),
+ BoundNetLog()));
+ EXPECT_EQ(OK, callback.WaitForResult());
+ return session_->InitializeWithSocket(connection.release(), false, OK);
+ }
+ SpdySessionDependencies session_deps_;
+ scoped_refptr<OrderedSocketData> data_;
+ scoped_refptr<HttpNetworkSession> http_session_;
+ scoped_refptr<SpdySession> session_;
+ scoped_refptr<TCPSocketParams> tcp_params_;
};
TEST_F(SpdyHttpStreamTest, SendRequest) {
EnableCompression(false);
SpdySession::SetSSLMode(false);
- SpdySessionDependencies session_deps;
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = {
CreateMockWrite(*req.get(), 1),
};
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
- MockRead(false, 0, 2) // EOF
+ CreateMockRead(*resp, 2),
+ MockRead(false, 0, 3) // EOF
};
- scoped_refptr<OrderedSocketData> data(
- new OrderedSocketData(reads, arraysize(reads),
- writes, arraysize(writes)));
- session_deps.socket_factory.AddSocketDataProvider(data.get());
-
- scoped_refptr<HttpNetworkSession> http_session(
- SpdySessionDependencies::SpdyCreateSession(&session_deps));
- scoped_refptr<SpdySessionPool> spdy_session_pool(
- http_session->spdy_session_pool());
+
HostPortPair host_port_pair("www.google.com", 80);
- scoped_refptr<SpdySession> session =
- spdy_session_pool->Get(
- host_port_pair, http_session.get(), BoundNetLog());
- scoped_refptr<TCPSocketParams> tcp_params =
- new TCPSocketParams(host_port_pair.host, host_port_pair.port,
- MEDIUM, GURL(), false);
- int rv = session->Connect(host_port_pair.host, tcp_params, MEDIUM);
- ASSERT_EQ(OK, rv);
+ HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
+ EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
+ host_port_pair));
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.google.com/");
TestCompletionCallback callback;
HttpResponseInfo response;
- scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream());
+ BoundNetLog net_log;
+ scoped_ptr<SpdyHttpStream> http_stream(
+ new SpdyHttpStream(session_.get(), true));
ASSERT_EQ(
OK,
- http_stream->InitializeStream(session, request, BoundNetLog(), NULL));
- http_stream->InitializeRequest(base::Time::Now(), NULL);
+ http_stream->InitializeStream(&request, net_log, NULL));
+
EXPECT_EQ(ERR_IO_PENDING,
- http_stream->SendRequest(&response, &callback));
- MessageLoop::current()->RunAllPending();
- EXPECT_TRUE(spdy_session_pool->HasSession(host_port_pair));
- spdy_session_pool->Remove(session);
+ http_stream->SendRequest("", NULL, &response, &callback));
+ EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
+
+ // This triggers the MockWrite and read 2
+ callback.WaitForResult();
+
+ // This triggers read 3. The empty read causes the session to shut down.
+ data()->CompleteRead();
+
+ // Because we abandoned the stream, we don't expect to find a session in the
+ // pool anymore.
+ EXPECT_TRUE(!http_session_->spdy_session_pool()->HasSession(pair));
+ EXPECT_TRUE(data()->at_read_eof());
+ EXPECT_TRUE(data()->at_write_eof());
+}
+
+// Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
+TEST_F(SpdyHttpStreamTest, SpdyURLTest) {
+ EnableCompression(false);
+ SpdySession::SetSSLMode(false);
+
+ const char * const full_url = "http://www.google.com/foo?query=what#anchor";
+ const char * const base_url = "http://www.google.com/foo?query=what";
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(base_url, false, 1, LOWEST));
+ MockWrite writes[] = {
+ CreateMockWrite(*req.get(), 1),
+ };
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ MockRead reads[] = {
+ CreateMockRead(*resp, 2),
+ MockRead(false, 0, 3) // EOF
+ };
+
+ HostPortPair host_port_pair("www.google.com", 80);
+ HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
+ EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
+ host_port_pair));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL(full_url);
+ TestCompletionCallback callback;
+ HttpResponseInfo response;
+ BoundNetLog net_log;
+ scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
+ ASSERT_EQ(
+ OK,
+ http_stream->InitializeStream(&request, net_log, NULL));
+
+ EXPECT_EQ(ERR_IO_PENDING,
+ http_stream->SendRequest("", NULL, &response, &callback));
+
+ spdy::SpdyHeaderBlock* spdy_header =
+ http_stream->stream()->spdy_headers().get();
+ EXPECT_TRUE(spdy_header != NULL);
+ if (spdy_header->find("url") != spdy_header->end())
+ EXPECT_EQ("/foo?query=what", spdy_header->find("url")->second);
+ else
+ FAIL() << "No url is set in spdy_header!";
+
+ // This triggers the MockWrite and read 2
+ callback.WaitForResult();
+
+ // This triggers read 3. The empty read causes the session to shut down.
+ data()->CompleteRead();
+
+ // Because we abandoned the stream, we don't expect to find a session in the
+ // pool anymore.
+ EXPECT_TRUE(!http_session_->spdy_session_pool()->HasSession(pair));
+ EXPECT_TRUE(data()->at_read_eof());
+ EXPECT_TRUE(data()->at_write_eof());
}
// TODO(willchan): Write a longer test for SpdyStream that exercises all
diff --git a/net/spdy/spdy_http_utils.cc b/net/spdy/spdy_http_utils.cc
new file mode 100644
index 0000000..d2fdd8f
--- /dev/null
+++ b/net/spdy/spdy_http_utils.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2010 The Chromium Authors. 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/spdy/spdy_http_utils.h"
+
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_util.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_request_info.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
+#include "net/http/http_util.h"
+
+namespace net {
+
+bool SpdyHeadersToHttpResponse(const spdy::SpdyHeaderBlock& headers,
+ HttpResponseInfo* response) {
+ std::string version;
+ std::string status;
+
+ // The "status" and "version" headers are required.
+ spdy::SpdyHeaderBlock::const_iterator it;
+ it = headers.find("status");
+ if (it == headers.end()) {
+ LOG(ERROR) << "SpdyHeaderBlock without status header.";
+ return false;
+ }
+ status = it->second;
+
+ // Grab the version. If not provided by the server,
+ it = headers.find("version");
+ if (it == headers.end()) {
+ LOG(ERROR) << "SpdyHeaderBlock without version header.";
+ return false;
+ }
+ version = it->second;
+
+ response->response_time = base::Time::Now();
+
+ std::string raw_headers(version);
+ raw_headers.push_back(' ');
+ raw_headers.append(status);
+ raw_headers.push_back('\0');
+ for (it = headers.begin(); it != headers.end(); ++it) {
+ // For each value, if the server sends a NUL-separated
+ // list of values, we separate that back out into
+ // individual headers for each value in the list.
+ // e.g.
+ // Set-Cookie "foo\0bar"
+ // becomes
+ // Set-Cookie: foo\0
+ // Set-Cookie: bar\0
+ std::string value = it->second;
+ size_t start = 0;
+ size_t end = 0;
+ do {
+ end = value.find('\0', start);
+ std::string tval;
+ if (end != value.npos)
+ tval = value.substr(start, (end - start));
+ else
+ tval = value.substr(start);
+ raw_headers.append(it->first);
+ raw_headers.push_back(':');
+ raw_headers.append(tval);
+ raw_headers.push_back('\0');
+ start = end + 1;
+ } while (end != value.npos);
+ }
+
+ response->headers = new HttpResponseHeaders(raw_headers);
+ response->was_fetched_via_spdy = true;
+ return true;
+}
+
+void CreateSpdyHeadersFromHttpRequest(
+ const HttpRequestInfo& info, spdy::SpdyHeaderBlock* headers,
+ bool direct) {
+ // TODO(willchan): It's not really necessary to convert from
+ // HttpRequestHeaders to spdy::SpdyHeaderBlock.
+
+ static const char kHttpProtocolVersion[] = "HTTP/1.1";
+
+ HttpRequestHeaders::Iterator it(info.extra_headers);
+
+ while (it.GetNext()) {
+ std::string name = StringToLowerASCII(it.name());
+ if (headers->find(name) == headers->end()) {
+ (*headers)[name] = it.value();
+ } else {
+ std::string new_value = (*headers)[name];
+ new_value.append(1, '\0'); // +=() doesn't append 0's
+ new_value += it.value();
+ (*headers)[name] = new_value;
+ }
+ }
+
+ // TODO(rch): Add Proxy headers here. (See http_network_transaction.cc)
+ // TODO(rch): Add authentication headers here.
+
+ (*headers)["method"] = info.method;
+
+ // Handle content-length. This is the same as BuildRequestHeader in
+ // http_network_transaction.cc.
+ // TODO(lzheng): reduce the code duplication between spdy and http here.
+ if (info.upload_data) {
+ (*headers)["content-length"] =
+ base::Int64ToString(info.upload_data->GetContentLength());
+ } else if (info.method == "POST" || info.method == "PUT" ||
+ info.method == "HEAD") {
+ // An empty POST/PUT request still needs a content length. As for HEAD,
+ // IE and Safari also add a content length header. Presumably it is to
+ // support sending a HEAD request to an URL that only expects to be sent a
+ // POST or some other method that normally would have a message body.
+ (*headers)["content-length"] = "0";
+ }
+
+ if (direct)
+ (*headers)["url"] = HttpUtil::PathForRequest(info.url);
+ else
+ (*headers)["url"] = HttpUtil::SpecForRequest(info.url);
+ (*headers)["host"] = GetHostAndOptionalPort(info.url);
+ (*headers)["scheme"] = info.url.scheme();
+ (*headers)["version"] = kHttpProtocolVersion;
+ if (!info.referrer.is_empty())
+ (*headers)["referer"] = info.referrer.spec();
+
+ // Honor load flags that impact proxy caches.
+ if (info.load_flags & LOAD_BYPASS_CACHE) {
+ (*headers)["pragma"] = "no-cache";
+ (*headers)["cache-control"] = "no-cache";
+ } else if (info.load_flags & LOAD_VALIDATE_CACHE) {
+ (*headers)["cache-control"] = "max-age=0";
+ }
+}
+
+} // namespace net
diff --git a/net/spdy/spdy_http_utils.h b/net/spdy/spdy_http_utils.h
new file mode 100644
index 0000000..7ec29a5
--- /dev/null
+++ b/net/spdy/spdy_http_utils.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 NET_SPDY_SPDY_HTTP_UTILS_H_
+#define NET_SPDY_SPDY_HTTP_UTILS_H_
+#pragma once
+
+#include "net/spdy/spdy_framer.h"
+
+namespace net {
+
+class HttpResponseInfo;
+struct HttpRequestInfo;
+
+// 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.
+bool SpdyHeadersToHttpResponse(const spdy::SpdyHeaderBlock& headers,
+ HttpResponseInfo* response);
+
+// Create a SpdyHeaderBlock for a Spdy SYN_STREAM Frame from
+// a HttpRequestInfo block.
+void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
+ spdy::SpdyHeaderBlock* headers,
+ bool direct);
+
+} // namespace net
+
+#endif // NET_SPDY_SPDY_HTTP_UTILS_H_
diff --git a/net/spdy/spdy_io_buffer.h b/net/spdy/spdy_io_buffer.h
index e34c7fe..23d6465 100644
--- a/net/spdy/spdy_io_buffer.h
+++ b/net/spdy/spdy_io_buffer.h
@@ -4,6 +4,7 @@
#ifndef NET_SPDY_SPDY_IO_BUFFER_H_
#define NET_SPDY_SPDY_IO_BUFFER_H_
+#pragma once
#include "base/ref_counted.h"
#include "net/base/io_buffer.h"
diff --git a/net/spdy/spdy_network_transaction.cc b/net/spdy/spdy_network_transaction.cc
deleted file mode 100644
index 7814553..0000000
--- a/net/spdy/spdy_network_transaction.cc
+++ /dev/null
@@ -1,335 +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/spdy/spdy_network_transaction.h"
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "base/stats_counters.h"
-#include "net/base/host_resolver.h"
-#include "net/base/io_buffer.h"
-#include "net/base/load_flags.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/base/net_util.h"
-#include "net/base/upload_data_stream.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_response_info.h"
-#include "net/socket/tcp_client_socket_pool.h"
-#include "net/spdy/spdy_http_stream.h"
-
-using base::Time;
-
-namespace net {
-
-//-----------------------------------------------------------------------------
-
-SpdyNetworkTransaction::SpdyNetworkTransaction(HttpNetworkSession* session)
- : ALLOW_THIS_IN_INITIALIZER_LIST(
- io_callback_(this, &SpdyNetworkTransaction::OnIOComplete)),
- user_callback_(NULL),
- user_buffer_len_(0),
- session_(session),
- request_(NULL),
- next_state_(STATE_NONE),
- stream_(NULL) {
-}
-
-SpdyNetworkTransaction::~SpdyNetworkTransaction() {
- LOG(INFO) << "SpdyNetworkTransaction dead. " << this;
- if (stream_.get())
- stream_->Cancel();
-}
-
-int SpdyNetworkTransaction::Start(const HttpRequestInfo* request_info,
- CompletionCallback* callback,
- const BoundNetLog& net_log) {
- CHECK(request_info);
- CHECK(callback);
-
- SIMPLE_STATS_COUNTER("SpdyNetworkTransaction.Count");
-
- net_log_ = net_log;
- request_ = request_info;
- start_time_ = base::TimeTicks::Now();
-
- next_state_ = STATE_INIT_CONNECTION;
- int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
- user_callback_ = callback;
- return rv;
-}
-
-int SpdyNetworkTransaction::RestartIgnoringLastError(
- CompletionCallback* callback) {
- // TODO(mbelshe): implement me.
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
-}
-
-int SpdyNetworkTransaction::RestartWithCertificate(
- X509Certificate* client_cert, CompletionCallback* callback) {
- // TODO(mbelshe): implement me.
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
-}
-
-int SpdyNetworkTransaction::RestartWithAuth(
- const std::wstring& username,
- const std::wstring& password,
- CompletionCallback* callback) {
- // TODO(mbelshe): implement me.
- NOTIMPLEMENTED();
- return 0;
-}
-
-int SpdyNetworkTransaction::Read(IOBuffer* buf, int buf_len,
- CompletionCallback* callback) {
- DCHECK(buf);
- DCHECK_GT(buf_len, 0);
- DCHECK(callback);
-
- user_buffer_ = buf;
- user_buffer_len_ = buf_len;
-
- next_state_ = STATE_READ_BODY;
- int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
- user_callback_ = callback;
- return rv;
-}
-
-const HttpResponseInfo* SpdyNetworkTransaction::GetResponseInfo() const {
- return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
-}
-
-LoadState SpdyNetworkTransaction::GetLoadState() const {
- switch (next_state_) {
- case STATE_INIT_CONNECTION_COMPLETE:
- if (spdy_.get())
- return spdy_->GetLoadState();
- return LOAD_STATE_CONNECTING;
- case STATE_GET_STREAM_COMPLETE:
- case STATE_SEND_REQUEST_COMPLETE:
- return LOAD_STATE_SENDING_REQUEST;
- case STATE_READ_HEADERS_COMPLETE:
- return LOAD_STATE_WAITING_FOR_RESPONSE;
- case STATE_READ_BODY_COMPLETE:
- return LOAD_STATE_READING_RESPONSE;
- default:
- return LOAD_STATE_IDLE;
- }
-}
-
-uint64 SpdyNetworkTransaction::GetUploadProgress() const {
- if (!stream_.get())
- return 0;
-
- return stream_->GetUploadProgress();
-}
-
-void SpdyNetworkTransaction::DoCallback(int rv) {
- CHECK_NE(rv, ERR_IO_PENDING);
- CHECK(user_callback_);
-
- // Since Run may result in Read being called, clear user_callback_ up front.
- CompletionCallback* c = user_callback_;
- user_callback_ = NULL;
- c->Run(rv);
-}
-
-void SpdyNetworkTransaction::OnIOComplete(int result) {
- int rv = DoLoop(result);
- if (rv != ERR_IO_PENDING)
- DoCallback(rv);
-}
-
-int SpdyNetworkTransaction::DoLoop(int result) {
- DCHECK(next_state_ != STATE_NONE);
- DCHECK(request_);
-
- if (!request_)
- return 0;
-
- int rv = result;
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_INIT_CONNECTION:
- DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_INIT_CONNECTION,
- NULL);
- rv = DoInitConnection();
- break;
- case STATE_INIT_CONNECTION_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_INIT_CONNECTION, NULL);
- rv = DoInitConnectionComplete(rv);
- break;
- case STATE_GET_STREAM:
- DCHECK_EQ(OK, rv);
- rv = DoGetStream();
- break;
- case STATE_GET_STREAM_COMPLETE:
- rv = DoGetStreamComplete(rv);
- case STATE_SEND_REQUEST:
- DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
- rv = DoSendRequest();
- break;
- case STATE_SEND_REQUEST_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST, NULL);
- rv = DoSendRequestComplete(rv);
- break;
- case STATE_READ_HEADERS:
- DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
- rv = DoReadHeaders();
- break;
- case STATE_READ_HEADERS_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS, NULL);
- rv = DoReadHeadersComplete(rv);
- break;
- case STATE_READ_BODY:
- DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
- rv = DoReadBody();
- break;
- case STATE_READ_BODY_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_TRANSACTION_READ_BODY, NULL);
- rv = DoReadBodyComplete(rv);
- break;
- case STATE_NONE:
- rv = ERR_FAILED;
- break;
- default:
- NOTREACHED() << "bad state";
- rv = ERR_FAILED;
- break;
- }
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
-
- return rv;
-}
-
-int SpdyNetworkTransaction::DoInitConnection() {
- next_state_ = STATE_INIT_CONNECTION_COMPLETE;
-
- std::string host = request_->url.HostNoBrackets();
- int port = request_->url.EffectiveIntPort();
-
- // Use the fixed testing ports if they've been provided. This is useful for
- // debugging.
- if (SpdySession::SSLMode()) {
- if (session_->fixed_https_port() != 0)
- port = session_->fixed_https_port();
- } else if (session_->fixed_http_port() != 0) {
- port = session_->fixed_http_port();
- }
-
- std::string connection_group = "spdy.";
- connection_group.append(host);
-
- HostPortPair host_port_pair(host, port);
- scoped_refptr<TCPSocketParams> tcp_params =
- new TCPSocketParams(host_port_pair, request_->priority,
- request_->referrer, false);
-
- spdy_ = session_->spdy_session_pool()->Get(
- host_port_pair, session_, net_log_);
- DCHECK(spdy_);
-
- return spdy_->Connect(
- connection_group, tcp_params, request_->priority);
-}
-
-int SpdyNetworkTransaction::DoInitConnectionComplete(int result) {
- if (result < 0)
- return result;
-
- next_state_ = STATE_GET_STREAM;
- return OK;
-}
-
-int SpdyNetworkTransaction::DoGetStream() {
- next_state_ = STATE_GET_STREAM_COMPLETE;
-
- // It is possible that the spdy session was shut down while it was
- // asynchronously waiting to connect.
- if (spdy_->IsClosed())
- return ERR_CONNECTION_CLOSED;
-
- CHECK(!stream_.get());
-
- stream_.reset(new SpdyHttpStream());
- return stream_->InitializeStream(spdy_, *request_,
- net_log_, &io_callback_);
-}
-
-int SpdyNetworkTransaction::DoGetStreamComplete(int result) {
- if (result < 0) {
- return result;
- }
-
- next_state_ = STATE_SEND_REQUEST;
- return OK;
-}
-
-int SpdyNetworkTransaction::DoSendRequest() {
- next_state_ = STATE_SEND_REQUEST_COMPLETE;
-
- UploadDataStream* upload_data_stream = NULL;
- if (request_->upload_data) {
- int error_code;
- upload_data_stream = UploadDataStream::Create(request_->upload_data,
- &error_code);
- if (!upload_data_stream)
- return error_code;
- }
- stream_->InitializeRequest(base::Time::Now(), upload_data_stream);
- spdy_ = NULL;
-
- return stream_->SendRequest(&response_, &io_callback_);
-}
-
-int SpdyNetworkTransaction::DoSendRequestComplete(int result) {
- if (result < 0) {
- stream_.reset();
- return result;
- }
-
- next_state_ = STATE_READ_HEADERS;
- return OK;
-}
-
-int SpdyNetworkTransaction::DoReadHeaders() {
- next_state_ = STATE_READ_HEADERS_COMPLETE;
- return stream_->ReadResponseHeaders(&io_callback_);
-}
-
-int SpdyNetworkTransaction::DoReadHeadersComplete(int result) {
- // TODO(willchan): Flesh out the support for HTTP authentication here.
- return result;
-}
-
-int SpdyNetworkTransaction::DoReadBody() {
- next_state_ = STATE_READ_BODY_COMPLETE;
-
- return stream_->ReadResponseBody(
- user_buffer_, user_buffer_len_, &io_callback_);
-}
-
-int SpdyNetworkTransaction::DoReadBodyComplete(int result) {
- user_buffer_ = NULL;
- user_buffer_len_ = 0;
-
- if (result <= 0)
- stream_.reset();
-
- return result;
-}
-
-} // namespace net
diff --git a/net/spdy/spdy_network_transaction.h b/net/spdy/spdy_network_transaction.h
deleted file mode 100644
index 4611cda..0000000
--- a/net/spdy/spdy_network_transaction.h
+++ /dev/null
@@ -1,123 +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 NET_SPDY_NETWORK_TRANSACTION_H_
-#define NET_SPDY_NETWORK_TRANSACTION_H_
-
-#include <string>
-#include <deque>
-
-#include "base/basictypes.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/time.h"
-#include "net/base/completion_callback.h"
-#include "net/base/load_states.h"
-#include "net/base/net_log.h"
-#include "net/http/http_response_info.h"
-#include "net/http/http_transaction.h"
-#include "net/spdy/spdy_session.h"
-
-namespace net {
-
-class SpdySession;
-class SpdyHttpStream;
-class HttpNetworkSession;
-class HttpResponseInfo;
-class IOBuffer;
-class UploadDataStream;
-
-// A SpdyNetworkTransaction can be used to fetch HTTP conent.
-// The SpdyDelegate is the consumer of events from the SpdySession.
-class SpdyNetworkTransaction : public HttpTransaction {
- public:
- explicit SpdyNetworkTransaction(HttpNetworkSession* session);
- virtual ~SpdyNetworkTransaction();
-
- // HttpTransaction methods:
- virtual int Start(const HttpRequestInfo* request_info,
- CompletionCallback* callback,
- const BoundNetLog& net_log);
- virtual int RestartIgnoringLastError(CompletionCallback* callback);
- virtual int RestartWithCertificate(X509Certificate* client_cert,
- CompletionCallback* callback);
- virtual int RestartWithAuth(const std::wstring& username,
- const std::wstring& password,
- CompletionCallback* callback);
- virtual bool IsReadyToRestartForAuth() { return false; }
- virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
- virtual void StopCaching() {}
- virtual const HttpResponseInfo* GetResponseInfo() const;
- virtual LoadState GetLoadState() const;
- virtual uint64 GetUploadProgress() const;
-
- private:
- FRIEND_TEST(SpdyNetworkTransactionTest, WindowUpdate);
- FRIEND_TEST(SpdyNetworkTransactionTest, WindowUpdateOverflow);
-
- enum State {
- STATE_INIT_CONNECTION,
- STATE_INIT_CONNECTION_COMPLETE,
- STATE_GET_STREAM,
- STATE_GET_STREAM_COMPLETE,
- STATE_SEND_REQUEST,
- STATE_SEND_REQUEST_COMPLETE,
- STATE_READ_HEADERS,
- STATE_READ_HEADERS_COMPLETE,
- STATE_READ_BODY,
- STATE_READ_BODY_COMPLETE,
- STATE_NONE
- };
-
- void DoCallback(int result);
- void OnIOComplete(int result);
-
- // Runs the state transition loop.
- int DoLoop(int result);
-
- // Each of these methods corresponds to a State value. Those with an input
- // argument receive the result from the previous state. If a method returns
- // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the
- // next state method as the result arg.
- int DoInitConnection();
- int DoInitConnectionComplete(int result);
- int DoGetStream();
- int DoGetStreamComplete(int result);
- int DoSendRequest();
- int DoSendRequestComplete(int result);
- int DoReadHeaders();
- int DoReadHeadersComplete(int result);
- int DoReadBody();
- int DoReadBodyComplete(int result);
-
- BoundNetLog net_log_;
-
- scoped_refptr<SpdySession> spdy_;
-
- CompletionCallbackImpl<SpdyNetworkTransaction> io_callback_;
- CompletionCallback* user_callback_;
-
- // Used to pass onto the SpdyStream
- scoped_refptr<IOBuffer> user_buffer_;
- int user_buffer_len_;
-
- scoped_refptr<HttpNetworkSession> session_;
-
- const HttpRequestInfo* request_;
- HttpResponseInfo response_;
-
- // The time the Start method was called.
- base::TimeTicks start_time_;
-
- // The next state in the state machine.
- State next_state_;
-
- scoped_ptr<SpdyHttpStream> stream_;
-
- DISALLOW_COPY_AND_ASSIGN(SpdyNetworkTransaction);
-};
-
-} // namespace net
-
-#endif // NET_SPDY_NETWORK_TRANSACTION_H_
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 7dbc12c..5ddbd40 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -2,36 +2,46 @@
// 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 "net/base/net_log_unittest.h"
#include "net/http/http_transaction_unittest.h"
#include "net/spdy/spdy_http_stream.h"
-#include "net/spdy/spdy_network_transaction.h"
+#include "net/spdy/spdy_session.h"
+#include "net/spdy/spdy_session_pool.h"
#include "net/spdy/spdy_test_util.h"
+#include "net/url_request/url_request_unittest.h"
#include "testing/platform_test.h"
//-----------------------------------------------------------------------------
namespace net {
-class SpdyNetworkTransactionTest : public PlatformTest {
+// This is the expected list of advertised protocols from the browser's NPN
+// list.
+static const char kExpectedNPNString[] = "\x08http/1.1\x06spdy/2";
+
+enum SpdyNetworkTransactionTestTypes {
+ SPDYNPN,
+ SPDYNOSSL,
+ SPDYSSL
+};
+class SpdyNetworkTransactionTest
+ : public ::testing::TestWithParam<SpdyNetworkTransactionTestTypes> {
protected:
virtual void SetUp() {
// By default, all tests turn off compression.
EnableCompression(false);
google_get_request_initialized_ = false;
- HttpNetworkTransaction::SetUseAlternateProtocols(true);
- HttpNetworkTransaction::SetNextProtos(
- "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy");
+ google_post_request_initialized_ = false;
}
virtual void TearDown() {
// Empty the current queue.
MessageLoop::current()->RunAllPending();
- PlatformTest::TearDown();
}
- void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
-
struct TransactionHelperResult {
int rv;
std::string status_line;
@@ -50,56 +60,75 @@ class SpdyNetworkTransactionTest : public PlatformTest {
class NormalSpdyTransactionHelper {
public:
NormalSpdyTransactionHelper(const HttpRequestInfo& request,
- const BoundNetLog& log)
+ const BoundNetLog& log,
+ SpdyNetworkTransactionTestTypes test_type)
: request_(request),
- session_(SpdySessionDependencies::SpdyCreateSession(&session_deps_)),
- log_(log), add_data_allowed_(true) {}
+ session_deps_(new SpdySessionDependencies()),
+ session_(SpdySessionDependencies::SpdyCreateSession(
+ session_deps_.get())),
+ log_(log),
+ test_type_(test_type),
+ deterministic_(false) {
+ switch (test_type_) {
+ case SPDYNOSSL:
+ case SPDYSSL:
+ port_ = 80;
+ break;
+ case SPDYNPN:
+ port_ = 443;
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ ~NormalSpdyTransactionHelper() {
+ // Any test which doesn't close the socket by sending it an EOF will
+ // have a valid session left open, which leaks the entire session pool.
+ // This is just fine - in fact, some of our tests intentionally do this
+ // so that we can check consistency of the SpdySessionPool as the test
+ // finishes. If we had put an EOF on the socket, the SpdySession would
+ // have closed and we wouldn't be able to check the consistency.
+
+ // Forcefully close existing sessions here.
+ session()->spdy_session_pool()->CloseAllSessions();
+ }
- void RunPreTestSetup() {
- // Disallow future calls to AddData
- add_data_allowed_ = false;
-
- // Set up http data.
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alternate-Protocol: 443:npn-spdy/1\r\n\r\n"),
- MockRead("hello world"),
- MockRead(true, OK),
- };
- first_transaction_.reset(
- new StaticSocketDataProvider(data_reads, arraysize(data_reads),
- NULL, 0));
- session_deps_.socket_factory.AddSocketDataProvider(
- first_transaction_.get());
+ void SetDeterministic() {
+ session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
+ session_deps_.get());
+ deterministic_ = true;
+ }
- // Set up actual test data. Also add one SSLSocketDataProvider per
- // DataProvider.
- for(DataVector::iterator it = data_vector_.begin();
- it != data_vector_.end(); ++it) {
- linked_ptr<SSLSocketDataProvider> ssl_(
- new SSLSocketDataProvider(true, OK));
- ssl_->next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- ssl_->next_proto = "spdy/1";
- ssl_->was_npn_negotiated = true;
- ssl_vector_.push_back(ssl_);
- session_deps_.socket_factory.AddSSLSocketDataProvider(ssl_.get());
- session_deps_.socket_factory.AddSocketDataProvider(*it);
+ void RunPreTestSetup() {
+ if (!session_deps_.get())
+ session_deps_.reset(new SpdySessionDependencies());
+ if (!session_.get())
+ session_ = SpdySessionDependencies::SpdyCreateSession(
+ session_deps_.get());
+ HttpStreamFactory::set_use_alternate_protocols(false);
+ HttpStreamFactory::set_force_spdy_over_ssl(false);
+ HttpStreamFactory::set_force_spdy_always(false);
+ switch (test_type_) {
+ case SPDYNPN:
+ session_->mutable_alternate_protocols()->SetAlternateProtocolFor(
+ HostPortPair("www.google.com", 80), 443,
+ HttpAlternateProtocols::NPN_SPDY_2);
+ HttpStreamFactory::set_use_alternate_protocols(true);
+ HttpStreamFactory::set_next_protos(kExpectedNPNString);
+ break;
+ case SPDYNOSSL:
+ HttpStreamFactory::set_force_spdy_over_ssl(false);
+ HttpStreamFactory::set_force_spdy_always(true);
+ break;
+ case SPDYSSL:
+ HttpStreamFactory::set_force_spdy_over_ssl(true);
+ HttpStreamFactory::set_force_spdy_always(true);
+ break;
+ default:
+ NOTREACHED();
}
- // We first send an http request. The Alternate-Protocol header switches
- // the HttpNetworkTransaction into SSL/SPDY mode.
- trans_http_.reset(new HttpNetworkTransaction(session_));
- int rv = trans_http_->Start(&request_, &callback, log_);
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
- const HttpResponseInfo* response = trans_http_->GetResponseInfo();
- EXPECT_TRUE(response != NULL);
- EXPECT_TRUE(response->headers != NULL);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- EXPECT_EQ(OK, ReadTransaction(trans_http_.get(), &response_data));
- EXPECT_EQ("hello world", response_data);
-
// We're now ready to use SSL-npn SPDY.
trans_.reset(new HttpNetworkTransaction(session_));
}
@@ -115,7 +144,7 @@ class SpdyNetworkTransactionTest : public PlatformTest {
output_.rv = callback.WaitForResult();
if (output_.rv != OK) {
- session_->spdy_session_pool()->ClearSessions();
+ session_->spdy_session_pool()->CloseCurrentSessions();
return;
}
@@ -125,8 +154,13 @@ class SpdyNetworkTransactionTest : public PlatformTest {
ASSERT_TRUE(response->headers != NULL);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_TRUE(response->was_alternate_protocol_available);
+ if (test_type_ == SPDYNPN) {
+ EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alternate_protocol_available);
+ } else {
+ EXPECT_TRUE(!response->was_npn_negotiated);
+ EXPECT_TRUE(!response->was_alternate_protocol_available);
+ }
output_.status_line = response->headers->GetStatusLine();
output_.response_info = *response; // Make a copy so we can verify.
output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
@@ -138,7 +172,7 @@ class SpdyNetworkTransactionTest : public PlatformTest {
// should end with an empty read, and that read needs to be processed to
// ensure proper deletion of the spdy_session_pool.
void VerifyDataConsumed() {
- for(DataVector::iterator it = data_vector_.begin();
+ for (DataVector::iterator it = data_vector_.begin();
it != data_vector_.end(); ++it) {
EXPECT_TRUE((*it)->at_read_eof()) << "Read count: "
<< (*it)->read_count()
@@ -155,7 +189,7 @@ class SpdyNetworkTransactionTest : public PlatformTest {
// processed. In that case we want to explicitly ensure that the reads were
// not processed.
void VerifyDataNotConsumed() {
- for(DataVector::iterator it = data_vector_.begin();
+ for (DataVector::iterator it = data_vector_.begin();
it != data_vector_.end(); ++it) {
EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: "
<< (*it)->read_count()
@@ -165,45 +199,81 @@ class SpdyNetworkTransactionTest : public PlatformTest {
<< (*it)->write_count()
<< " Write index: "
<< (*it)->write_index();
-
}
}
void RunToCompletion(StaticSocketDataProvider* data) {
- AddData(data);
RunPreTestSetup();
+ AddData(data);
RunDefaultTest();
VerifyDataConsumed();
}
- // Only call AddData before calling RunPreTestSetup!! When RunPreTestSetup
- // is run, it will add this Data Provider, and a corresponding SSL data
- // provider.
void AddData(StaticSocketDataProvider* data) {
- EXPECT_TRUE(add_data_allowed_);
+ DCHECK(!deterministic_);
+ data_vector_.push_back(data);
+ linked_ptr<SSLSocketDataProvider> ssl_(
+ new SSLSocketDataProvider(true, OK));
+ if (test_type_ == SPDYNPN) {
+ ssl_->next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ ssl_->next_proto = "spdy/2";
+ ssl_->was_npn_negotiated = true;
+ }
+ ssl_vector_.push_back(ssl_);
+ if(test_type_ == SPDYNPN || test_type_ == SPDYSSL)
+ session_deps_->socket_factory->AddSSLSocketDataProvider(ssl_.get());
+ session_deps_->socket_factory->AddSocketDataProvider(data);
+ }
+
+ void AddDeterministicData(DeterministicSocketData* data) {
+ DCHECK(deterministic_);
data_vector_.push_back(data);
+ linked_ptr<SSLSocketDataProvider> ssl_(
+ new SSLSocketDataProvider(true, OK));
+ if (test_type_ == SPDYNPN) {
+ ssl_->next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ ssl_->next_proto = "spdy/2";
+ ssl_->was_npn_negotiated = true;
+ }
+ ssl_vector_.push_back(ssl_);
+ if(test_type_ == SPDYNPN || test_type_ == SPDYSSL)
+ session_deps_->deterministic_socket_factory->
+ AddSSLSocketDataProvider(ssl_.get());
+ session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
}
// This can only be called after RunPreTestSetup. It adds a Data Provider,
// but not a corresponding SSL data provider
void AddDataNoSSL(StaticSocketDataProvider* data) {
- session_deps_.socket_factory.AddSocketDataProvider(data);
+ DCHECK(!deterministic_);
+ session_deps_->socket_factory->AddSocketDataProvider(data);
+ }
+ void AddDataNoSSL(DeterministicSocketData* data) {
+ DCHECK(deterministic_);
+ session_deps_->deterministic_socket_factory->AddSocketDataProvider(data);
}
- void SetSession(scoped_refptr<HttpNetworkSession>& session) {
+ void SetSession(const scoped_refptr<HttpNetworkSession>& session) {
session_ = session;
}
HttpNetworkTransaction* trans() { return trans_.get(); }
void ResetTrans() { trans_.reset(); }
TransactionHelperResult& output() { return output_; }
- HttpRequestInfo& request() { return request_; }
- scoped_refptr<HttpNetworkSession>& session() { return session_; }
+ const HttpRequestInfo& request() const { return request_; }
+ const scoped_refptr<HttpNetworkSession>& session() const {
+ return session_;
+ }
+ scoped_ptr<SpdySessionDependencies>& session_deps() {
+ return session_deps_;
+ }
+ int port() const { return port_; }
+ SpdyNetworkTransactionTestTypes test_type() const { return test_type_; }
private:
typedef std::vector<StaticSocketDataProvider*> DataVector;
typedef std::vector<linked_ptr<SSLSocketDataProvider> > SSLVector;
HttpRequestInfo request_;
- SpdySessionDependencies session_deps_;
+ scoped_ptr<SpdySessionDependencies> session_deps_;
scoped_refptr<HttpNetworkSession> session_;
TransactionHelperResult output_;
scoped_ptr<StaticSocketDataProvider> first_transaction_;
@@ -213,7 +283,9 @@ class SpdyNetworkTransactionTest : public PlatformTest {
scoped_ptr<HttpNetworkTransaction> trans_http_;
DataVector data_vector_;
const BoundNetLog& log_;
- bool add_data_allowed_;
+ SpdyNetworkTransactionTestTypes test_type_;
+ int port_;
+ bool deterministic_;
};
void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
@@ -221,32 +293,167 @@ class SpdyNetworkTransactionTest : public PlatformTest {
void ConnectStatusHelper(const MockRead& status);
+ const HttpRequestInfo& CreateGetPushRequest() {
+ google_get_push_request_.method = "GET";
+ google_get_push_request_.url = GURL("http://www.google.com/foo.dat");
+ google_get_push_request_.load_flags = 0;
+ return google_get_push_request_;
+ }
+
const HttpRequestInfo& CreateGetRequest() {
if (!google_get_request_initialized_) {
google_get_request_.method = "GET";
- google_get_request_.url = GURL("http://www.google.com/");
+ google_get_request_.url = GURL(kDefaultURL);
google_get_request_.load_flags = 0;
google_get_request_initialized_ = true;
}
return google_get_request_;
}
+ const HttpRequestInfo& CreatePostRequest() {
+ if (!google_post_request_initialized_) {
+ google_post_request_.method = "POST";
+ google_post_request_.url = GURL(kDefaultURL);
+ google_post_request_.upload_data = new UploadData();
+ google_post_request_.upload_data->AppendBytes(kUploadData,
+ kUploadDataSize);
+ google_post_request_initialized_ = true;
+ }
+ return google_post_request_;
+ }
+
+ // Read the result of a particular transaction, knowing that we've got
+ // multiple transactions in the read pipeline; so as we read, we may have
+ // to skip over data destined for other transactions while we consume
+ // the data for |trans|.
+ int ReadResult(HttpNetworkTransaction* trans,
+ OrderedSocketData* data,
+ std::string* result) {
+ const int kSize = 3000;
+
+ int bytes_read = 0;
+ scoped_refptr<net::IOBufferWithSize> buf = new net::IOBufferWithSize(kSize);
+ TestCompletionCallback callback;
+ while (true) {
+ int rv = trans->Read(buf, kSize, &callback);
+ if (rv == ERR_IO_PENDING) {
+ // Multiple transactions may be in the data set. Keep pulling off
+ // reads until we complete our callback.
+ while (!callback.have_result()) {
+ data->CompleteRead();
+ MessageLoop::current()->RunAllPending();
+ }
+ rv = callback.WaitForResult();
+ } else if (rv <= 0) {
+ break;
+ }
+ result->append(buf->data(), rv);
+ bytes_read += rv;
+ }
+ return bytes_read;
+ }
+
+ void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
+ // This lengthy block is reaching into the pool to dig out the active
+ // session. Once we have the session, we verify that the streams are
+ // all closed and not leaked at this point.
+ const GURL& url = helper.request().url;
+ int port = helper.test_type() == SPDYNPN ? 443 : 80;
+ HostPortPair host_port_pair(url.host(), port);
+ HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
+ BoundNetLog log;
+ const scoped_refptr<HttpNetworkSession>& session = helper.session();
+ scoped_refptr<SpdySessionPool> pool(session->spdy_session_pool());
+ EXPECT_TRUE(pool->HasSession(pair));
+ scoped_refptr<SpdySession> spdy_session(
+ pool->Get(pair, session->mutable_spdy_settings(), log));
+ ASSERT_TRUE(spdy_session.get() != NULL);
+ EXPECT_EQ(0u, spdy_session->num_active_streams());
+ EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams());
+ }
+
+ void RunServerPushTest(MockWrite writes[], int writes_length,
+ MockRead reads[], int reads_length,
+ HttpResponseInfo* response,
+ HttpResponseInfo* response2,
+ std::string& expected) {
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, reads_length,
+ writes, writes_length));
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+
+ HttpNetworkTransaction* trans = helper.trans();
+
+ // Start the transaction with basic parameters.
+ TestCompletionCallback callback;
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback.WaitForResult();
+
+ // Request the pushed path.
+ scoped_ptr<HttpNetworkTransaction> trans2(
+ new HttpNetworkTransaction(helper.session()));
+ rv = trans2->Start(&CreateGetPushRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ MessageLoop::current()->RunAllPending();
+
+ // The data for the pushed path may be coming in more than 1 packet. Compile
+ // the results into a single string.
+
+ // Read the server push body.
+ std::string result2;
+ ReadResult(trans2.get(), data, &result2);
+ // Read the response body.
+ std::string result;
+ ReadResult(trans, data, &result);
+
+ // Verify that we consumed all test data.
+ EXPECT_TRUE(data->at_read_eof());
+ EXPECT_TRUE(data->at_write_eof());
+
+ // Verify that the received push data is same as the expected push data.
+ EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
+ << result2
+ << "||||| Expected data: "
+ << expected;
+
+ // Verify the SYN_REPLY.
+ // Copy the response info, because trans goes away.
+ *response = *trans->GetResponseInfo();
+ *response2 = *trans2->GetResponseInfo();
+
+ VerifyStreamsClosed(helper);
+ }
+
private:
bool google_get_request_initialized_;
+ bool google_post_request_initialized_;
HttpRequestInfo google_get_request_;
+ HttpRequestInfo google_post_request_;
+ HttpRequestInfo google_get_push_request_;
};
//-----------------------------------------------------------------------------
+// All tests are run with three different connection types: SPDY after NPN
+// negotiation, SPDY without SSL, and SPDY with SSL.
+INSTANTIATE_TEST_CASE_P(Spdy,
+ SpdyNetworkTransactionTest,
+ ::testing::Values(SPDYNOSSL, SPDYSSL, SPDYNPN));
+
// Verify HttpNetworkTransaction constructor.
-TEST_F(SpdyNetworkTransactionTest, Constructor) {
+TEST_P(SpdyNetworkTransactionTest, Constructor) {
SpdySessionDependencies session_deps;
scoped_refptr<HttpNetworkSession> session =
SpdySessionDependencies::SpdyCreateSession(&session_deps);
scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
}
-TEST_F(SpdyNetworkTransactionTest, Get) {
+TEST_P(SpdyNetworkTransactionTest, Get) {
// Construct the request.
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = { CreateMockWrite(*req) };
@@ -263,7 +470,7 @@ TEST_F(SpdyNetworkTransactionTest, Get) {
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(OK, out.rv);
@@ -271,6 +478,59 @@ TEST_F(SpdyNetworkTransactionTest, Get) {
EXPECT_EQ("hello!", out.response_data);
}
+TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
+ for (RequestPriority p = HIGHEST; p < NUM_PRIORITIES;
+ p = RequestPriority(p+1)) {
+ // Construct the request.
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, p));
+ MockWrite writes[] = { CreateMockWrite(*req) };
+
+ const int spdy_prio = reinterpret_cast<spdy::SpdySynStreamControlFrame*>(
+ req.get())->priority();
+ // this repeats the RequestPriority-->SpdyPriority mapping from
+ // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
+ // sure it's being done right.
+ switch(p) {
+ case HIGHEST:
+ EXPECT_EQ(0, spdy_prio);
+ break;
+ case MEDIUM:
+ EXPECT_EQ(1, spdy_prio);
+ break;
+ case LOW:
+ case LOWEST:
+ EXPECT_EQ(2, spdy_prio);
+ break;
+ case IDLE:
+ EXPECT_EQ(3, spdy_prio);
+ break;
+ default:
+ FAIL();
+ }
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ MockRead reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*body),
+ MockRead(true, 0, 0) // EOF
+ };
+
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(1, reads, arraysize(reads),
+ writes, arraysize(writes)));
+ HttpRequestInfo http_req = CreateGetRequest();
+ http_req.priority = p;
+
+ NormalSpdyTransactionHelper helper(http_req, BoundNetLog(), GetParam());
+ helper.RunToCompletion(data.get());
+ TransactionHelperResult out = helper.output();
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!", out.response_data);
+ }
+}
+
// Start three gets simultaniously; making sure that multiplexed
// streams work properly.
@@ -281,7 +541,7 @@ TEST_F(SpdyNetworkTransactionTest, Get) {
// TODO(gavinp): create a working generalized TransactionHelper that
// can allow multiple streams in flight.
-TEST_F(SpdyNetworkTransactionTest, ThreeGets) {
+TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false));
@@ -315,74 +575,72 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGets) {
MockRead(true, 0, 0), // EOF
};
-
scoped_refptr<OrderedSocketData> data(
new OrderedSocketData(reads, arraysize(reads),
writes, arraysize(writes)));
+ scoped_refptr<OrderedSocketData> data_placeholder(
+ new OrderedSocketData(NULL, 0, NULL, 0));
BoundNetLog log;
TransactionHelperResult out;
- {
- SpdySessionDependencies session_deps;
- HttpNetworkSession* session =
- SpdySessionDependencies::SpdyCreateSession(&session_deps);
- SpdySession::SetSSLMode(false);
- scoped_ptr<SpdyNetworkTransaction> trans1(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans2(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans3(
- new SpdyNetworkTransaction(session));
-
- session_deps.socket_factory.AddSocketDataProvider(data);
-
- TestCompletionCallback callback1;
- TestCompletionCallback callback2;
- TestCompletionCallback callback3;
-
- HttpRequestInfo httpreq1 = CreateGetRequest();
- HttpRequestInfo httpreq2 = CreateGetRequest();
- HttpRequestInfo httpreq3 = CreateGetRequest();
-
- out.rv = trans1->Start(&httpreq1, &callback1, log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans2->Start(&httpreq2, &callback2, log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans3->Start(&httpreq3, &callback3, log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
-
- out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
- out.rv = callback3.WaitForResult();
- ASSERT_EQ(OK, out.rv);
-
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- EXPECT_TRUE(response1->headers != NULL);
- EXPECT_TRUE(response1->was_fetched_via_spdy);
- out.status_line = response1->headers->GetStatusLine();
- out.response_info = *response1;
-
- trans2->GetResponseInfo();
-
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
- }
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+ // We require placeholder data because three get requests are sent out, so
+ // there needs to be three sets of SSL connection data.
+ helper.AddData(data_placeholder.get());
+ helper.AddData(data_placeholder.get());
+ scoped_ptr<HttpNetworkTransaction> trans1(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans2(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans3(
+ new HttpNetworkTransaction(helper.session()));
+
+ TestCompletionCallback callback1;
+ TestCompletionCallback callback2;
+ TestCompletionCallback callback3;
+
+ HttpRequestInfo httpreq1 = CreateGetRequest();
+ HttpRequestInfo httpreq2 = CreateGetRequest();
+ HttpRequestInfo httpreq3 = CreateGetRequest();
+
+ out.rv = trans1->Start(&httpreq1, &callback1, log);
+ ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans2->Start(&httpreq2, &callback2, log);
+ ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans3->Start(&httpreq3, &callback3, log);
+ ASSERT_EQ(ERR_IO_PENDING, out.rv);
+
+ out.rv = callback1.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+ out.rv = callback3.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+
+ const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ EXPECT_TRUE(response1->headers != NULL);
+ EXPECT_TRUE(response1->was_fetched_via_spdy);
+ out.status_line = response1->headers->GetStatusLine();
+ out.response_info = *response1;
+
+ trans2->GetResponseInfo();
+
+ out.rv = ReadTransaction(trans1.get(), &out.response_data);
+ helper.VerifyDataConsumed();
EXPECT_EQ(OK, out.rv);
- EXPECT_TRUE(data->at_read_eof());
- EXPECT_TRUE(data->at_write_eof());
-
EXPECT_EQ(OK, out.rv);
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
}
-
// Similar to ThreeGets above, however this test adds a SETTINGS
// frame. The SETTINGS frame is read during the IO loop waiting on
// the first transaction completion, and sets a maximum concurrent
// stream limit of 1. This means that our IO loop exists after the
// second transaction completes, so we can assert on read_index().
-TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
+TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
// Construct the request.
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -412,14 +670,14 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
CreateMockWrite(*req3),
};
MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
+ CreateMockRead(*settings_frame, 1),
CreateMockRead(*resp),
CreateMockRead(*body),
CreateMockRead(*fbody),
- CreateMockRead(*resp2, 6),
+ CreateMockRead(*resp2, 7),
CreateMockRead(*body2),
CreateMockRead(*fbody2),
- CreateMockRead(*resp3, 11),
+ CreateMockRead(*resp3, 12),
CreateMockRead(*body3),
CreateMockRead(*fbody3),
@@ -429,22 +687,26 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
scoped_refptr<OrderedSocketData> data(
new OrderedSocketData(reads, arraysize(reads),
writes, arraysize(writes)));
+ scoped_refptr<OrderedSocketData> data_placeholder(
+ new OrderedSocketData(NULL, 0, NULL, 0));
BoundNetLog log;
TransactionHelperResult out;
{
- SpdySessionDependencies session_deps;
- HttpNetworkSession* session =
- SpdySessionDependencies::SpdyCreateSession(&session_deps);
- SpdySession::SetSSLMode(false);
- scoped_ptr<SpdyNetworkTransaction> trans1(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans2(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans3(
- new SpdyNetworkTransaction(session));
-
- session_deps.socket_factory.AddSocketDataProvider(data);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+ // We require placeholder data because three get requests are sent out, so
+ // there needs to be three sets of SSL connection data.
+ helper.AddData(data_placeholder.get());
+ helper.AddData(data_placeholder.get());
+ scoped_ptr<HttpNetworkTransaction> trans1(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans2(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans3(
+ new HttpNetworkTransaction(helper.session()));
TestCompletionCallback callback1;
TestCompletionCallback callback2;
@@ -459,6 +721,7 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
// run transaction 1 through quickly to force a read of our SETTINGS
// frame
out.rv = callback1.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
out.rv = trans2->Start(&httpreq2, &callback2, log);
ASSERT_EQ(out.rv, ERR_IO_PENDING);
@@ -472,6 +735,7 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
ASSERT_EQ(OK, out.rv);
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ ASSERT_TRUE(response1 != NULL);
EXPECT_TRUE(response1->headers != NULL);
EXPECT_TRUE(response1->was_fetched_via_spdy);
out.status_line = response1->headers->GetStatusLine();
@@ -496,11 +760,10 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
EXPECT_EQ(OK, out.rv);
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
+
+ helper.VerifyDataConsumed();
}
EXPECT_EQ(OK, out.rv);
-
- EXPECT_TRUE(data->at_read_eof());
- EXPECT_TRUE(data->at_write_eof());
}
// Similar to ThreeGetsWithMaxConcurrent above, however this test adds
@@ -508,7 +771,7 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
// different data ("hello!" vs "hello!hello!") and because of the
// user specified priority, we expect to see them inverted in
// the response from the server.
-TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
+TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
// Construct the request.
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -540,21 +803,21 @@ TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
MockWrite writes[] = { CreateMockWrite(*req),
- CreateMockWrite(*req2),
- CreateMockWrite(*req4),
- CreateMockWrite(*req3),
+ CreateMockWrite(*req2),
+ CreateMockWrite(*req4),
+ CreateMockWrite(*req3),
};
MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
+ CreateMockRead(*settings_frame, 1),
CreateMockRead(*resp),
CreateMockRead(*body),
CreateMockRead(*fbody),
- CreateMockRead(*resp2, 6),
+ CreateMockRead(*resp2, 7),
CreateMockRead(*body2),
CreateMockRead(*fbody2),
- CreateMockRead(*resp4, 12),
+ CreateMockRead(*resp4, 13),
CreateMockRead(*fbody4),
- CreateMockRead(*resp3, 15),
+ CreateMockRead(*resp3, 16),
CreateMockRead(*body3),
CreateMockRead(*fbody3),
@@ -563,107 +826,108 @@ TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
scoped_refptr<OrderedSocketData> data(
new OrderedSocketData(reads, arraysize(reads),
- writes, arraysize(writes)));
+ writes, arraysize(writes)));
+ scoped_refptr<OrderedSocketData> data_placeholder(
+ new OrderedSocketData(NULL, 0, NULL, 0));
BoundNetLog log;
TransactionHelperResult out;
- {
- SpdySessionDependencies session_deps;
- HttpNetworkSession* session =
- SpdySessionDependencies::SpdyCreateSession(&session_deps);
- SpdySession::SetSSLMode(false);
- scoped_ptr<SpdyNetworkTransaction> trans1(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans2(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans3(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans4(
- new SpdyNetworkTransaction(session));
-
- session_deps.socket_factory.AddSocketDataProvider(data);
-
- TestCompletionCallback callback1;
- TestCompletionCallback callback2;
- TestCompletionCallback callback3;
- TestCompletionCallback callback4;
-
- HttpRequestInfo httpreq1 = CreateGetRequest();
- HttpRequestInfo httpreq2 = CreateGetRequest();
- HttpRequestInfo httpreq3 = CreateGetRequest();
- HttpRequestInfo httpreq4 = CreateGetRequest();
- httpreq4.priority = HIGHEST;
-
- out.rv = trans1->Start(&httpreq1, &callback1, log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- // run transaction 1 through quickly to force a read of our SETTINGS
- // frame
- out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
-
- out.rv = trans2->Start(&httpreq2, &callback2, log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans3->Start(&httpreq3, &callback3, log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans4->Start(&httpreq4, &callback4, log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
-
- out.rv = callback2.WaitForResult();
- ASSERT_EQ(OK, out.rv);
- EXPECT_EQ(data->read_index(), 7U); // i.e. the third & fourth trans queued
-
- out.rv = callback3.WaitForResult();
- ASSERT_EQ(OK, out.rv);
-
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- EXPECT_TRUE(response1->headers != NULL);
- EXPECT_TRUE(response1->was_fetched_via_spdy);
- out.status_line = response1->headers->GetStatusLine();
- out.response_info = *response1;
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("hello!hello!", out.response_data);
-
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
- out.status_line = response2->headers->GetStatusLine();
- out.response_info = *response2;
- out.rv = ReadTransaction(trans2.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("hello!hello!", out.response_data);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+ // We require placeholder data because four get requests are sent out, so
+ // there needs to be four sets of SSL connection data.
+ helper.AddData(data_placeholder.get());
+ helper.AddData(data_placeholder.get());
+ helper.AddData(data_placeholder.get());
+ scoped_ptr<HttpNetworkTransaction> trans1(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans2(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans3(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans4(
+ new HttpNetworkTransaction(helper.session()));
+
+ TestCompletionCallback callback1;
+ TestCompletionCallback callback2;
+ TestCompletionCallback callback3;
+ TestCompletionCallback callback4;
+
+ HttpRequestInfo httpreq1 = CreateGetRequest();
+ HttpRequestInfo httpreq2 = CreateGetRequest();
+ HttpRequestInfo httpreq3 = CreateGetRequest();
+ HttpRequestInfo httpreq4 = CreateGetRequest();
+ httpreq4.priority = HIGHEST;
+
+ out.rv = trans1->Start(&httpreq1, &callback1, log);
+ ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ // run transaction 1 through quickly to force a read of our SETTINGS
+ // frame
+ out.rv = callback1.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+
+ out.rv = trans2->Start(&httpreq2, &callback2, log);
+ ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans3->Start(&httpreq3, &callback3, log);
+ ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans4->Start(&httpreq4, &callback4, log);
+ ASSERT_EQ(ERR_IO_PENDING, out.rv);
+
+ out.rv = callback2.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+ EXPECT_EQ(data->read_index(), 7U); // i.e. the third & fourth trans queued
+
+ out.rv = callback3.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+
+ const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ EXPECT_TRUE(response1->headers != NULL);
+ EXPECT_TRUE(response1->was_fetched_via_spdy);
+ out.status_line = response1->headers->GetStatusLine();
+ out.response_info = *response1;
+ out.rv = ReadTransaction(trans1.get(), &out.response_data);
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!hello!", out.response_data);
- // notice: response3 gets two hellos, response4 gets one
- // hello, so we know dequeuing priority was respected.
- const HttpResponseInfo* response3 = trans3->GetResponseInfo();
- out.status_line = response3->headers->GetStatusLine();
- out.response_info = *response3;
- out.rv = ReadTransaction(trans3.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("hello!hello!", out.response_data);
+ const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+ out.status_line = response2->headers->GetStatusLine();
+ out.response_info = *response2;
+ out.rv = ReadTransaction(trans2.get(), &out.response_data);
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!hello!", out.response_data);
- out.rv = callback4.WaitForResult();
- EXPECT_EQ(OK, out.rv);
- const HttpResponseInfo* response4 = trans4->GetResponseInfo();
- out.status_line = response4->headers->GetStatusLine();
- out.response_info = *response4;
- out.rv = ReadTransaction(trans4.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("hello!", out.response_data);
- }
+ // notice: response3 gets two hellos, response4 gets one
+ // hello, so we know dequeuing priority was respected.
+ const HttpResponseInfo* response3 = trans3->GetResponseInfo();
+ out.status_line = response3->headers->GetStatusLine();
+ out.response_info = *response3;
+ out.rv = ReadTransaction(trans3.get(), &out.response_data);
EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!hello!", out.response_data);
- EXPECT_TRUE(data->at_read_eof());
- EXPECT_TRUE(data->at_write_eof());
+ out.rv = callback4.WaitForResult();
+ EXPECT_EQ(OK, out.rv);
+ const HttpResponseInfo* response4 = trans4->GetResponseInfo();
+ out.status_line = response4->headers->GetStatusLine();
+ out.response_info = *response4;
+ out.rv = ReadTransaction(trans4.get(), &out.response_data);
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!", out.response_data);
+ helper.VerifyDataConsumed();
+ EXPECT_EQ(OK, out.rv);
}
// Similar to ThreeGetsMaxConcurrrent above, however, this test
// deletes a session in the middle of the transaction to insure
// that we properly remove pendingcreatestream objects from
// the spdy_session
-TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
+TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
// Construct the request.
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -675,11 +939,6 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false));
scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true));
- scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST));
- scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5));
- scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(5, false));
- scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true));
-
spdy::SpdySettings settings;
spdy::SettingsFlagsAndId id(0);
id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS);
@@ -689,14 +948,14 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
MockWrite writes[] = { CreateMockWrite(*req),
- CreateMockWrite(*req2),
+ CreateMockWrite(*req2),
};
MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
+ CreateMockRead(*settings_frame, 1),
CreateMockRead(*resp),
CreateMockRead(*body),
CreateMockRead(*fbody),
- CreateMockRead(*resp2, 6),
+ CreateMockRead(*resp2, 7),
CreateMockRead(*body2),
CreateMockRead(*fbody2),
MockRead(true, 0, 0), // EOF
@@ -704,83 +963,333 @@ TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
scoped_refptr<OrderedSocketData> data(
new OrderedSocketData(reads, arraysize(reads),
- writes, arraysize(writes)));
+ writes, arraysize(writes)));
+ scoped_refptr<OrderedSocketData> data_placeholder(
+ new OrderedSocketData(NULL, 0, NULL, 0));
BoundNetLog log;
TransactionHelperResult out;
- {
- SpdySessionDependencies session_deps;
- HttpNetworkSession* session =
- SpdySessionDependencies::SpdyCreateSession(&session_deps);
- SpdySession::SetSSLMode(false);
- scoped_ptr<SpdyNetworkTransaction> trans1(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans2(
- new SpdyNetworkTransaction(session));
- scoped_ptr<SpdyNetworkTransaction> trans3(
- new SpdyNetworkTransaction(session));
-
- session_deps.socket_factory.AddSocketDataProvider(data);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+ // We require placeholder data because three get requests are sent out, so
+ // there needs to be three sets of SSL connection data.
+ helper.AddData(data_placeholder.get());
+ helper.AddData(data_placeholder.get());
+ scoped_ptr<HttpNetworkTransaction> trans1(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans2(
+ new HttpNetworkTransaction(helper.session()));
+ scoped_ptr<HttpNetworkTransaction> trans3(
+ new HttpNetworkTransaction(helper.session()));
+
+ TestCompletionCallback callback1;
+ TestCompletionCallback callback2;
+ TestCompletionCallback callback3;
+
+ HttpRequestInfo httpreq1 = CreateGetRequest();
+ HttpRequestInfo httpreq2 = CreateGetRequest();
+ HttpRequestInfo httpreq3 = CreateGetRequest();
+
+ out.rv = trans1->Start(&httpreq1, &callback1, log);
+ ASSERT_EQ(out.rv, ERR_IO_PENDING);
+ // run transaction 1 through quickly to force a read of our SETTINGS
+ // frame
+ out.rv = callback1.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+
+ out.rv = trans2->Start(&httpreq2, &callback2, log);
+ ASSERT_EQ(out.rv, ERR_IO_PENDING);
+ out.rv = trans3->Start(&httpreq3, &callback3, log);
+ delete trans3.release();
+ ASSERT_EQ(out.rv, ERR_IO_PENDING);
+ out.rv = callback2.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+
+ EXPECT_EQ(8U, data->read_index());
+
+ const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ ASSERT_TRUE(response1 != NULL);
+ EXPECT_TRUE(response1->headers != NULL);
+ EXPECT_TRUE(response1->was_fetched_via_spdy);
+ out.status_line = response1->headers->GetStatusLine();
+ out.response_info = *response1;
+ out.rv = ReadTransaction(trans1.get(), &out.response_data);
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!hello!", out.response_data);
- TestCompletionCallback callback1;
- TestCompletionCallback callback2;
- TestCompletionCallback callback3;
+ const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+ ASSERT_TRUE(response2 != NULL);
+ out.status_line = response2->headers->GetStatusLine();
+ out.response_info = *response2;
+ out.rv = ReadTransaction(trans2.get(), &out.response_data);
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!hello!", out.response_data);
+ helper.VerifyDataConsumed();
+ EXPECT_EQ(OK, out.rv);
+}
- HttpRequestInfo httpreq1 = CreateGetRequest();
- HttpRequestInfo httpreq2 = CreateGetRequest();
- HttpRequestInfo httpreq3 = CreateGetRequest();
+// The KillerCallback will delete the transaction on error as part of the
+// callback.
+class KillerCallback : public TestCompletionCallback {
+ public:
+ explicit KillerCallback(HttpNetworkTransaction* transaction)
+ : transaction_(transaction) {}
- out.rv = trans1->Start(&httpreq1, &callback1, log);
- ASSERT_EQ(out.rv, ERR_IO_PENDING);
- // run transaction 1 through quickly to force a read of our SETTINGS
- // frame
- out.rv = callback1.WaitForResult();
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ if (params.a < 0)
+ delete transaction_;
+ TestCompletionCallback::RunWithParams(params);
+ }
- out.rv = trans2->Start(&httpreq2, &callback2, log);
- ASSERT_EQ(out.rv, ERR_IO_PENDING);
- out.rv = trans3->Start(&httpreq3, &callback3, log);
- delete trans3.release();
- ASSERT_EQ(out.rv, ERR_IO_PENDING);
- out.rv = callback2.WaitForResult();
+ private:
+ HttpNetworkTransaction* transaction_;
+};
- EXPECT_EQ(8U, data->read_index());
+// Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
+// closes the socket while we have a pending transaction waiting for
+// a pending stream creation. http://crbug.com/52901
+TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
+ // Construct the request.
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false));
+ scoped_ptr<spdy::SpdyFrame> fin_body(ConstructSpdyBodyFrame(1, true));
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- EXPECT_TRUE(response1->headers != NULL);
- EXPECT_TRUE(response1->was_fetched_via_spdy);
- out.status_line = response1->headers->GetStatusLine();
- out.response_info = *response1;
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("hello!hello!", out.response_data);
+ scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
- out.status_line = response2->headers->GetStatusLine();
- out.response_info = *response2;
- out.rv = ReadTransaction(trans2.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("hello!hello!", out.response_data);
- }
+ spdy::SpdySettings settings;
+ spdy::SettingsFlagsAndId id(0);
+ id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS);
+ const size_t max_concurrent_streams = 1;
+
+ settings.push_back(spdy::SpdySetting(id, max_concurrent_streams));
+ scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
+
+ MockWrite writes[] = { CreateMockWrite(*req),
+ CreateMockWrite(*req2),
+ };
+ MockRead reads[] = {
+ CreateMockRead(*settings_frame, 1),
+ CreateMockRead(*resp),
+ CreateMockRead(*body),
+ CreateMockRead(*fin_body),
+ CreateMockRead(*resp2, 7),
+ MockRead(true, ERR_CONNECTION_RESET, 0), // Abort!
+ };
+
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ scoped_refptr<OrderedSocketData> data_placeholder(
+ new OrderedSocketData(NULL, 0, NULL, 0));
+
+ BoundNetLog log;
+ TransactionHelperResult out;
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+ // We require placeholder data because three get requests are sent out, so
+ // there needs to be three sets of SSL connection data.
+ helper.AddData(data_placeholder.get());
+ helper.AddData(data_placeholder.get());
+ HttpNetworkTransaction trans1(helper.session());
+ HttpNetworkTransaction trans2(helper.session());
+ HttpNetworkTransaction* trans3(new HttpNetworkTransaction(helper.session()));
+
+ TestCompletionCallback callback1;
+ TestCompletionCallback callback2;
+ KillerCallback callback3(trans3);
+
+ HttpRequestInfo httpreq1 = CreateGetRequest();
+ HttpRequestInfo httpreq2 = CreateGetRequest();
+ HttpRequestInfo httpreq3 = CreateGetRequest();
+
+ out.rv = trans1.Start(&httpreq1, &callback1, log);
+ ASSERT_EQ(out.rv, ERR_IO_PENDING);
+ // run transaction 1 through quickly to force a read of our SETTINGS
+ // frame
+ out.rv = callback1.WaitForResult();
+ ASSERT_EQ(OK, out.rv);
+
+ out.rv = trans2.Start(&httpreq2, &callback2, log);
+ ASSERT_EQ(out.rv, ERR_IO_PENDING);
+ out.rv = trans3->Start(&httpreq3, &callback3, log);
+ ASSERT_EQ(out.rv, ERR_IO_PENDING);
+ out.rv = callback3.WaitForResult();
+ ASSERT_EQ(ERR_ABORTED, out.rv);
+
+ EXPECT_EQ(6U, data->read_index());
+
+ const HttpResponseInfo* response1 = trans1.GetResponseInfo();
+ ASSERT_TRUE(response1 != NULL);
+ EXPECT_TRUE(response1->headers != NULL);
+ EXPECT_TRUE(response1->was_fetched_via_spdy);
+ out.status_line = response1->headers->GetStatusLine();
+ out.response_info = *response1;
+ out.rv = ReadTransaction(&trans1, &out.response_data);
EXPECT_EQ(OK, out.rv);
- EXPECT_TRUE(data->at_read_eof());
- EXPECT_TRUE(data->at_write_eof());
+ const HttpResponseInfo* response2 = trans2.GetResponseInfo();
+ ASSERT_TRUE(response2 != NULL);
+ out.status_line = response2->headers->GetStatusLine();
+ out.response_info = *response2;
+ out.rv = ReadTransaction(&trans2, &out.response_data);
+ EXPECT_EQ(ERR_CONNECTION_RESET, out.rv);
+
+ helper.VerifyDataConsumed();
}
-// Test that a simple POST works.
-TEST_F(SpdyNetworkTransactionTest, Post) {
- static const char upload[] = { "hello!" };
+// Test that a simple PUT request works.
+TEST_P(SpdyNetworkTransactionTest, Put) {
+ // Setup the request
+ HttpRequestInfo request;
+ request.method = "PUT";
+ request.url = GURL("http://www.google.com/");
+
+ const SpdyHeaderInfo kSynStartHeader = {
+ spdy::SYN_STREAM, // Kind = Syn
+ 1, // Stream ID
+ 0, // Associated stream ID
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
+ spdy::CONTROL_FLAG_FIN, // Control Flags
+ false, // Compressed
+ spdy::INVALID, // Status
+ NULL, // Data
+ 0, // Length
+ spdy::DATA_FLAG_NONE // Data Flags
+ };
+ const char* const kPutHeaders[] = {
+ "method", "PUT",
+ "url", "/",
+ "host", "www.google.com",
+ "scheme", "http",
+ "version", "HTTP/1.1",
+ "content-length", "0"
+ };
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0,
+ kPutHeaders, arraysize(kPutHeaders)/2));
+ MockWrite writes[] = {
+ CreateMockWrite(*req)
+ };
+
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ const SpdyHeaderInfo kSynReplyHeader = {
+ spdy::SYN_REPLY, // Kind = SynReply
+ 1, // Stream ID
+ 0, // Associated stream ID
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
+ spdy::CONTROL_FLAG_NONE, // Control Flags
+ false, // Compressed
+ spdy::INVALID, // Status
+ NULL, // Data
+ 0, // Length
+ spdy::DATA_FLAG_NONE // Data Flags
+ };
+ static const char* const kStandardGetHeaders[] = {
+ "status", "200",
+ "version", "HTTP/1.1"
+ "content-length", "1234"
+ };
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader,
+ NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
+ MockRead reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*body),
+ MockRead(true, 0, 0) // EOF
+ };
+
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(1, reads, arraysize(reads),
+ writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(request,
+ BoundNetLog(), GetParam());
+ helper.RunToCompletion(data.get());
+ TransactionHelperResult out = helper.output();
+
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+}
+// Test that a simple HEAD request works.
+TEST_P(SpdyNetworkTransactionTest, Head) {
// Setup the request
HttpRequestInfo request;
- request.method = "POST";
+ request.method = "HEAD";
request.url = GURL("http://www.google.com/");
- request.upload_data = new UploadData();
- request.upload_data->AppendBytes(upload, strlen(upload));
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(NULL, 0));
+ const SpdyHeaderInfo kSynStartHeader = {
+ spdy::SYN_STREAM, // Kind = Syn
+ 1, // Stream ID
+ 0, // Associated stream ID
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
+ spdy::CONTROL_FLAG_FIN, // Control Flags
+ false, // Compressed
+ spdy::INVALID, // Status
+ NULL, // Data
+ 0, // Length
+ spdy::DATA_FLAG_NONE // Data Flags
+ };
+ const char* const kHeadHeaders[] = {
+ "method", "HEAD",
+ "url", "/",
+ "host", "www.google.com",
+ "scheme", "http",
+ "version", "HTTP/1.1",
+ "content-length", "0"
+ };
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0,
+ kHeadHeaders, arraysize(kHeadHeaders)/2));
+ MockWrite writes[] = {
+ CreateMockWrite(*req)
+ };
+
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ const SpdyHeaderInfo kSynReplyHeader = {
+ spdy::SYN_REPLY, // Kind = SynReply
+ 1, // Stream ID
+ 0, // Associated stream ID
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority
+ spdy::CONTROL_FLAG_NONE, // Control Flags
+ false, // Compressed
+ spdy::INVALID, // Status
+ NULL, // Data
+ 0, // Length
+ spdy::DATA_FLAG_NONE // Data Flags
+ };
+ static const char* const kStandardGetHeaders[] = {
+ "status", "200",
+ "version", "HTTP/1.1"
+ "content-length", "1234"
+ };
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader,
+ NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
+ MockRead reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*body),
+ MockRead(true, 0, 0) // EOF
+ };
+
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(1, reads, arraysize(reads),
+ writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(request,
+ BoundNetLog(), GetParam());
+ helper.RunToCompletion(data.get());
+ TransactionHelperResult out = helper.output();
+
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+}
+
+// Test that a simple POST works.
+TEST_P(SpdyNetworkTransactionTest, Post) {
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(kUploadDataSize, NULL, 0));
scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
MockWrite writes[] = {
CreateMockWrite(*req),
@@ -797,8 +1306,47 @@ TEST_F(SpdyNetworkTransactionTest, Post) {
scoped_refptr<DelayedSocketData> data(
new DelayedSocketData(2, reads, arraysize(reads),
writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(CreatePostRequest(),
+ BoundNetLog(), GetParam());
+ helper.RunToCompletion(data.get());
+ TransactionHelperResult out = helper.output();
+ EXPECT_EQ(OK, out.rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!", out.response_data);
+}
+
+// Test that a POST without any post data works.
+TEST_P(SpdyNetworkTransactionTest, NullPost) {
+ // Setup the request
+ HttpRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ // Create an empty UploadData.
+ request.upload_data = NULL;
+
+ // When request.upload_data is NULL for post, content-length is
+ // expected to be 0.
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(0, NULL, 0));
+ // Set the FIN bit since there will be no body.
+ req->set_flags(spdy::CONTROL_FLAG_FIN);
+ MockWrite writes[] = {
+ CreateMockWrite(*req),
+ };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ MockRead reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*body),
+ MockRead(true, 0, 0) // EOF
+ };
+
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(1, reads, arraysize(reads),
+ writes, arraysize(writes)));
+
NormalSpdyTransactionHelper helper(request,
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(OK, out.rv);
@@ -807,7 +1355,7 @@ TEST_F(SpdyNetworkTransactionTest, Post) {
}
// Test that a simple POST works.
-TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
+TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
// Setup the request
HttpRequestInfo request;
request.method = "POST";
@@ -815,7 +1363,14 @@ TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
// Create an empty UploadData.
request.upload_data = new UploadData();
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(NULL, 0));
+ // Http POST Content-Length is using UploadDataStream::size().
+ // It is the same as request.upload_data->GetContentLength().
+ scoped_ptr<UploadDataStream> stream(UploadDataStream::Create(
+ request.upload_data, NULL));
+ ASSERT_EQ(request.upload_data->GetContentLength(), stream->size());
+
+ scoped_ptr<spdy::SpdyFrame>
+ req(ConstructSpdyPost(request.upload_data->GetContentLength(), NULL, 0));
// Set the FIN bit since there will be no body.
req->set_flags(spdy::CONTROL_FLAG_FIN);
MockWrite writes[] = {
@@ -835,7 +1390,7 @@ TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(request,
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(OK, out.rv);
@@ -844,7 +1399,7 @@ TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
}
// While we're doing a post, the server sends back a SYN_REPLY.
-TEST_F(SpdyNetworkTransactionTest, PostWithEarlySynReply) {
+TEST_P(SpdyNetworkTransactionTest, PostWithEarlySynReply) {
static const char upload[] = { "hello!" };
// Setup the request
@@ -854,35 +1409,76 @@ TEST_F(SpdyNetworkTransactionTest, PostWithEarlySynReply) {
request.upload_data = new UploadData();
request.upload_data->AppendBytes(upload, sizeof(upload));
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(NULL, 0));
- scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
- MockWrite writes[] = {
- CreateMockWrite(*req.get(), 2),
- CreateMockWrite(*body.get(), 3), // POST upload frame
- };
-
- scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
+ // Http POST Content-Length is using UploadDataStream::size().
+ // It is the same as request.upload_data->GetContentLength().
+ scoped_ptr<UploadDataStream> stream(UploadDataStream::Create(
+ request.upload_data, NULL));
+ ASSERT_EQ(request.upload_data->GetContentLength(), stream->size());
+ scoped_ptr<spdy::SpdyFrame> stream_reply(ConstructSpdyPostSynReply(NULL, 0));
+ scoped_ptr<spdy::SpdyFrame> stream_body(ConstructSpdyBodyFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp.get(), 2),
- CreateMockRead(*body.get(), 3),
+ CreateMockRead(*stream_reply, 2),
+ CreateMockRead(*stream_body, 3),
MockRead(false, 0, 0) // EOF
};
scoped_refptr<DelayedSocketData> data(
- new DelayedSocketData(0, reads, arraysize(reads),
- writes, arraysize(writes)));
+ new DelayedSocketData(0, reads, arraysize(reads), NULL, 0));
NormalSpdyTransactionHelper helper(request,
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
helper.RunDefaultTest();
- helper.VerifyDataNotConsumed();
+ helper.VerifyDataConsumed();
+
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
+}
+
+// The client upon cancellation tries to send a RST_STREAM frame. The mock
+// socket causes the TCP write to return zero. This test checks that the client
+// tries to queue up the RST_STREAM frame again.
+TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> rst(
+ ConstructSpdyRstStream(1, spdy::CANCEL));
+ MockWrite writes[] = {
+ CreateMockWrite(*req.get(), 0, false),
+ MockWrite(false, 0, 0, 2),
+ CreateMockWrite(*rst.get(), 3, false),
+ };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ MockRead reads[] = {
+ CreateMockRead(*resp.get(), 1, false),
+ MockRead(false, 0, 0, 4) // EOF
+ };
+
+ scoped_refptr<DeterministicSocketData> data(
+ new DeterministicSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.SetDeterministic();
+ helper.RunPreTestSetup();
+ helper.AddDeterministicData(data.get());
+ HttpNetworkTransaction* trans = helper.trans();
+
+ TestCompletionCallback callback;
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ data->SetStop(2);
+ data->Run();
+ helper.ResetTrans();
+ data->SetStop(20);
+ data->Run();
+
+ helper.VerifyDataConsumed();
}
// Test that the transaction doesn't crash when we don't have a reply.
-TEST_F(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
+TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
MockRead reads[] = {
CreateMockRead(*body),
@@ -892,7 +1488,7 @@ TEST_F(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
scoped_refptr<DelayedSocketData> data(
new DelayedSocketData(1, reads, arraysize(reads), NULL, 0));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
@@ -900,7 +1496,7 @@ TEST_F(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
// Test that the transaction doesn't crash when we get two replies on the same
// stream ID. See http://crbug.com/45639.
-TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
+TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = { CreateMockWrite(*req) };
@@ -918,9 +1514,9 @@ TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
@@ -931,6 +1527,7 @@ TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
EXPECT_EQ(OK, rv);
const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
EXPECT_TRUE(response->headers != NULL);
EXPECT_TRUE(response->was_fetched_via_spdy);
std::string response_data;
@@ -940,136 +1537,372 @@ TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
helper.VerifyDataConsumed();
}
-// Test that WINDOW_UPDATE frames change window_size correctly.
-TEST_F(SpdyNetworkTransactionTest, WindowUpdate) {
- SpdySessionDependencies session_deps;
- scoped_refptr<HttpNetworkSession> session =
- SpdySessionDependencies::SpdyCreateSession(&session_deps);
-
- // We disable SSL for this test.
- SpdySession::SetSSLMode(false);
+// Test that sent data frames and received WINDOW_UPDATE frames change
+// the send_window_size_ correctly.
+
+// WINDOW_UPDATE is different than most other frames in that it can arrive
+// while the client is still sending the request body. In order to enforce
+// this scenario, we feed a couple of dummy frames and give a delay of 0 to
+// socket data provider, so that initial read that is done as soon as the
+// stream is created, succeeds and schedules another read. This way reads
+// and writes are interleaved; after doing a full frame write, SpdyStream
+// will break out of DoLoop and will read and process a WINDOW_UPDATE.
+// Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
+// since request has not been completely written, therefore we feed
+// enough number of WINDOW_UPDATEs to finish the first read and cause a
+// write, leading to a complete write of request body; after that we send
+// a reply with a body, to cause a graceful shutdown.
+
+// TODO(agayev): develop a socket data provider where both, reads and
+// writes are ordered so that writing tests like these are easy and rewrite
+// all these tests using it. Right now we are working around the
+// limitations as described above and it's not deterministic, tests may
+// fail under specific circumstances.
+TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
+ SpdySession::set_flow_control(true);
+
+ static int kFrameCount = 2;
+ scoped_ptr<std::string> content(
+ new std::string(kMaxSpdyFrameChunkSize, 'a'));
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
+ kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0));
+ scoped_ptr<spdy::SpdyFrame> body(
+ ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
+ scoped_ptr<spdy::SpdyFrame> body_end(
+ ConstructSpdyBodyFrame(1, content->c_str(), content->size(), true));
- // Setup the request
- static const char upload[] = { "hello!" };
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.upload_data = new UploadData();
- request.upload_data->AppendBytes(upload, strlen(upload));
-
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(NULL, 0));
- scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
MockWrite writes[] = {
CreateMockWrite(*req),
CreateMockWrite(*body),
+ CreateMockWrite(*body_end),
};
- // Response frames, send WINDOW_UPDATE first
static const int kDeltaWindowSize = 0xff;
+ static const int kDeltaCount = 4;
scoped_ptr<spdy::SpdyFrame> window_update(
ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
- scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0));
+ scoped_ptr<spdy::SpdyFrame> window_update_dummy(
+ ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
MockRead reads[] = {
+ CreateMockRead(*window_update_dummy),
+ CreateMockRead(*window_update_dummy),
+ CreateMockRead(*window_update_dummy),
+ CreateMockRead(*window_update), // Four updates, therefore window
+ CreateMockRead(*window_update), // size should increase by
+ CreateMockRead(*window_update), // kDeltaWindowSize * 4
CreateMockRead(*window_update),
- CreateMockRead(*reply),
- CreateMockRead(*body),
+ CreateMockRead(*resp),
+ CreateMockRead(*body_end),
MockRead(true, 0, 0) // EOF
};
scoped_refptr<DelayedSocketData> data(
- new DelayedSocketData(2, reads, arraysize(reads),
+ new DelayedSocketData(0, reads, arraysize(reads),
writes, arraysize(writes)));
- session_deps.socket_factory.AddSocketDataProvider(data.get());
- scoped_ptr<SpdyNetworkTransaction> trans(
- new SpdyNetworkTransaction(session));
+ // Setup the request
+ HttpRequestInfo request;
+ request.method = "POST";
+ request.url = GURL(kDefaultURL);
+ request.upload_data = new UploadData();
+ for (int i = 0; i < kFrameCount; ++i)
+ request.upload_data->AppendBytes(content->c_str(), content->size());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, &callback, BoundNetLog());
+ NormalSpdyTransactionHelper helper(request, BoundNetLog(), GetParam());
+ helper.AddData(data.get());
+ helper.RunPreTestSetup();
- ASSERT_TRUE(trans->stream_ != NULL);
- ASSERT_TRUE(trans->stream_->stream() != NULL);
- EXPECT_EQ(spdy::kInitialWindowSize, trans->stream_->stream()->window_size());
+ HttpNetworkTransaction* trans = helper.trans();
+
+ TestCompletionCallback callback;
+ int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
- ASSERT_TRUE(trans->stream_ != NULL);
- ASSERT_TRUE(trans->stream_->stream() != NULL);
- EXPECT_EQ(spdy::kInitialWindowSize + kDeltaWindowSize,
- trans->stream_->stream()->window_size());
- EXPECT_TRUE(data->at_read_eof());
- EXPECT_TRUE(data->at_write_eof());
+ SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
+ ASSERT_TRUE(stream != NULL);
+ ASSERT_TRUE(stream->stream() != NULL);
+ EXPECT_EQ(spdy::kInitialWindowSize +
+ kDeltaWindowSize * kDeltaCount -
+ kMaxSpdyFrameChunkSize * kFrameCount,
+ stream->stream()->send_window_size());
+ helper.VerifyDataConsumed();
+ SpdySession::set_flow_control(false);
}
-// Test that WINDOW_UPDATE frame causing overflow is handled correctly.
-TEST_F(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
- SpdySessionDependencies session_deps;
- scoped_refptr<HttpNetworkSession> session =
- SpdySessionDependencies::SpdyCreateSession(&session_deps);
+// Test that received data frames and sent WINDOW_UPDATE frames change
+// the recv_window_size_ correctly.
+TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
+ SpdySession::set_flow_control(true);
- // We disable SSL for this test.
- SpdySession::SetSSLMode(false);
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> window_update(
+ ConstructSpdyWindowUpdate(1, kUploadDataSize));
- // Setup the request
- static const char upload[] = { "hello!" };
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.upload_data = new UploadData();
- request.upload_data->AppendBytes(upload, strlen(upload));
+ MockWrite writes[] = {
+ CreateMockWrite(*req),
+ CreateMockWrite(*window_update),
+ };
- scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(NULL, 0));
- scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ scoped_ptr<spdy::SpdyFrame> resp(
+ ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body_no_fin(
+ ConstructSpdyBodyFrame(1, false));
+ scoped_ptr<spdy::SpdyFrame> body_fin(
+ ConstructSpdyBodyFrame(1, NULL, 0, true));
+ MockRead reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*body_no_fin),
+ MockRead(true, ERR_IO_PENDING, 0), // Force a pause
+ CreateMockRead(*body_fin),
+ MockRead(true, ERR_IO_PENDING, 0), // Force a pause
+ MockRead(true, 0, 0) // EOF
+ };
+
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(1, reads, arraysize(reads),
+ writes, arraysize(writes)));
+
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.AddData(data.get());
+ helper.RunPreTestSetup();
+ HttpNetworkTransaction* trans = helper.trans();
+
+ TestCompletionCallback callback;
+ int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ SpdyHttpStream* stream =
+ static_cast<SpdyHttpStream*>(trans->stream_.get());
+ ASSERT_TRUE(stream != NULL);
+ ASSERT_TRUE(stream->stream() != NULL);
+
+ EXPECT_EQ(spdy::kInitialWindowSize - kUploadDataSize,
+ stream->stream()->recv_window_size());
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ ASSERT_TRUE(response->headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+
+ // Issue a read which will cause a WINDOW_UPDATE to be sent and window
+ // size increased to default.
+ scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kUploadDataSize);
+ rv = trans->Read(buf, kUploadDataSize, NULL);
+ EXPECT_EQ(kUploadDataSize, rv);
+ std::string content(buf->data(), buf->data()+kUploadDataSize);
+ EXPECT_STREQ(kUploadData, content.c_str());
+
+ // Schedule the reading of empty data frame with FIN
+ data->CompleteRead();
+
+ // Force write of WINDOW_UPDATE which was scheduled during the above
+ // read.
+ MessageLoop::current()->RunAllPending();
+
+ // Read EOF.
+ data->CompleteRead();
+
+ helper.VerifyDataConsumed();
+ SpdySession::set_flow_control(false);
+}
+
+// Test that WINDOW_UPDATE frame causing overflow is handled correctly. We
+// use the same trick as in the above test to enforce our scenario.
+TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
+ SpdySession::set_flow_control(true);
+
+ // number of full frames we hope to write (but will not, used to
+ // set content-length header correctly)
+ static int kFrameCount = 3;
+
+ scoped_ptr<std::string> content(
+ new std::string(kMaxSpdyFrameChunkSize, 'a'));
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
+ kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0));
+ scoped_ptr<spdy::SpdyFrame> body(
+ ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
scoped_ptr<spdy::SpdyFrame> rst(
ConstructSpdyRstStream(1, spdy::FLOW_CONTROL_ERROR));
+
+ // We're not going to write a data frame with FIN, we'll receive a bad
+ // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
MockWrite writes[] = {
CreateMockWrite(*req),
CreateMockWrite(*body),
CreateMockWrite(*rst),
};
- // Response frames, send WINDOW_UPDATE first
- static const int kDeltaWindowSize = 0x7fffffff; // cause an overflow
+ static const int kDeltaWindowSize = 0x7fffffff; // cause an overflow
scoped_ptr<spdy::SpdyFrame> window_update(
ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
+ scoped_ptr<spdy::SpdyFrame> window_update2(
+ ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0));
+
MockRead reads[] = {
+ CreateMockRead(*window_update2),
+ CreateMockRead(*window_update2),
CreateMockRead(*window_update),
- CreateMockRead(*reply),
- CreateMockRead(*body),
+ CreateMockRead(*window_update),
+ CreateMockRead(*window_update),
+ MockRead(true, ERR_IO_PENDING, 0), // Wait for the RST to be written.
MockRead(true, 0, 0) // EOF
};
scoped_refptr<DelayedSocketData> data(
- new DelayedSocketData(2, reads, arraysize(reads),
+ new DelayedSocketData(0, reads, arraysize(reads),
writes, arraysize(writes)));
- session_deps.socket_factory.AddSocketDataProvider(data.get());
- scoped_ptr<SpdyNetworkTransaction> trans(
- new SpdyNetworkTransaction(session));
+ // Setup the request
+ HttpRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.upload_data = new UploadData();
+ for (int i = 0; i < kFrameCount; ++i)
+ request.upload_data->AppendBytes(content->c_str(), content->size());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, &callback, BoundNetLog());
+ NormalSpdyTransactionHelper helper(request,
+ BoundNetLog(), GetParam());
+ helper.AddData(data.get());
+ helper.RunPreTestSetup();
+
+ HttpNetworkTransaction* trans = helper.trans();
- ASSERT_TRUE(trans->stream_ != NULL);
- ASSERT_TRUE(trans->stream_->stream() != NULL);
- EXPECT_EQ(spdy::kInitialWindowSize, trans->stream_->stream()->window_size());
+ TestCompletionCallback callback;
+ int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
- ASSERT_TRUE(session != NULL);
- ASSERT_TRUE(session->spdy_session_pool() != NULL);
- session->spdy_session_pool()->ClearSessions();
+ data->CompleteRead();
+
+ ASSERT_TRUE(helper.session() != NULL);
+ ASSERT_TRUE(helper.session()->spdy_session_pool() != NULL);
+ helper.session()->spdy_session_pool()->CloseAllSessions();
+ helper.VerifyDataConsumed();
- EXPECT_FALSE(data->at_read_eof());
- EXPECT_TRUE(data->at_write_eof());
+ SpdySession::set_flow_control(false);
+}
+
+// Test that after hitting a send window size of 0, the write process
+// stalls and upon receiving WINDOW_UPDATE frame write resumes.
+
+// This test constructs a POST request followed by enough data frames
+// containing 'a' that would make the window size 0, followed by another
+// data frame containing default content (which is "hello!") and this frame
+// also contains a FIN flag. DelayedSocketData is used to enforce all
+// writes go through before a read could happen. However, the last frame
+// ("hello!") is not supposed to go through since by the time its turn
+// arrives, window size is 0. At this point MessageLoop::Run() called via
+// callback would block. Therefore we call MessageLoop::RunAllPending()
+// which returns after performing all possible writes. We use DCHECKS to
+// ensure that last data frame is still there and stream has stalled.
+// After that, next read is artifically enforced, which causes a
+// WINDOW_UPDATE to be read and I/O process resumes.
+TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
+ SpdySession::set_flow_control(true);
+
+ // Number of frames we need to send to zero out the window size: data
+ // frames plus SYN_STREAM plus the last data frame; also we need another
+ // data frame that we will send once the WINDOW_UPDATE is received,
+ // therefore +3.
+ size_t nwrites = spdy::kInitialWindowSize / kMaxSpdyFrameChunkSize + 3;
+
+ // Calculate last frame's size; 0 size data frame is legal.
+ size_t last_frame_size = spdy::kInitialWindowSize % kMaxSpdyFrameChunkSize;
+
+ // Construct content for a data frame of maximum size.
+ scoped_ptr<std::string> content(
+ new std::string(kMaxSpdyFrameChunkSize, 'a'));
+
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(
+ spdy::kInitialWindowSize + kUploadDataSize, NULL, 0));
+
+ // Full frames.
+ scoped_ptr<spdy::SpdyFrame> body1(
+ ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false));
+
+ // Last frame to zero out the window size.
+ scoped_ptr<spdy::SpdyFrame> body2(
+ ConstructSpdyBodyFrame(1, content->c_str(), last_frame_size, false));
+
+ // Data frame to be sent once WINDOW_UPDATE frame is received.
+ scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(1, true));
+
+ // Fill in mock writes.
+ scoped_array<MockWrite> writes(new MockWrite[nwrites]);
+ size_t i = 0;
+ writes[i] = CreateMockWrite(*req);
+ for (i = 1; i < nwrites-2; i++)
+ writes[i] = CreateMockWrite(*body1);
+ writes[i++] = CreateMockWrite(*body2);
+ writes[i] = CreateMockWrite(*body3);
+
+ // Construct read frame, give enough space to upload the rest of the
+ // data.
+ scoped_ptr<spdy::SpdyFrame> window_update(
+ ConstructSpdyWindowUpdate(1, kUploadDataSize));
+ scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0));
+ MockRead reads[] = {
+ CreateMockRead(*window_update),
+ CreateMockRead(*window_update),
+ CreateMockRead(*reply),
+ CreateMockRead(*body2),
+ CreateMockRead(*body3),
+ MockRead(true, 0, 0) // EOF
+ };
+
+ // Force all writes to happen before any read, last write will not
+ // actually queue a frame, due to window size being 0.
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(nwrites, reads, arraysize(reads),
+ writes.get(), nwrites));
+
+ HttpRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.upload_data = new UploadData();
+ scoped_ptr<std::string> upload_data(
+ new std::string(spdy::kInitialWindowSize, 'a'));
+ upload_data->append(kUploadData, kUploadDataSize);
+ request.upload_data->AppendBytes(upload_data->c_str(), upload_data->size());
+ NormalSpdyTransactionHelper helper(request,
+ BoundNetLog(), GetParam());
+ helper.AddData(data.get());
+ helper.RunPreTestSetup();
+
+ HttpNetworkTransaction* trans = helper.trans();
+
+ TestCompletionCallback callback;
+ int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ MessageLoop::current()->RunAllPending(); // Write as much as we can.
+
+ SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
+ ASSERT_TRUE(stream != NULL);
+ ASSERT_TRUE(stream->stream() != NULL);
+ EXPECT_EQ(0, stream->stream()->send_window_size());
+ EXPECT_FALSE(stream->request_body_stream_->eof());
+
+ data->ForceNextRead(); // Read in WINDOW_UPDATE frame.
+ rv = callback.WaitForResult();
+ helper.VerifyDataConsumed();
+
+ SpdySession::set_flow_control(false);
}
-TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
+TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
// Construct the request.
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = {
@@ -1090,9 +1923,9 @@ TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(&data);
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
@@ -1106,11 +1939,53 @@ TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
helper.VerifyDataNotConsumed();
}
+// Verify that the client sends a Rst Frame upon cancelling the stream.
+TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> rst(
+ ConstructSpdyRstStream(1, spdy::CANCEL));
+ MockWrite writes[] = {
+ CreateMockWrite(*req, 0, false),
+ CreateMockWrite(*rst, 2, false),
+ };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ MockRead reads[] = {
+ CreateMockRead(*resp, 1, false),
+ MockRead(false, 0, 0, 3) // EOF
+ };
+
+ scoped_refptr<DeterministicSocketData> data(
+ new DeterministicSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(),
+ GetParam());
+ helper.SetDeterministic();
+ helper.RunPreTestSetup();
+ helper.AddDeterministicData(data.get());
+ HttpNetworkTransaction* trans = helper.trans();
+
+ TestCompletionCallback callback;
+
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ data->SetStop(2);
+ data->Run();
+ helper.ResetTrans();
+ data->SetStop(20);
+ data->Run();
+
+ helper.VerifyDataConsumed();
+}
+
class SpdyNetworkTransactionTest::StartTransactionCallback
: public CallbackRunner< Tuple1<int> > {
public:
explicit StartTransactionCallback(
- scoped_refptr<HttpNetworkSession>& session,
+ const scoped_refptr<HttpNetworkSession>& session,
NormalSpdyTransactionHelper& helper)
: session_(session), helper_(helper) {}
@@ -1129,14 +2004,14 @@ class SpdyNetworkTransactionTest::StartTransactionCallback
}
private:
- scoped_refptr<HttpNetworkSession>& session_;
+ const scoped_refptr<HttpNetworkSession>& session_;
NormalSpdyTransactionHelper& helper_;
};
// Verify that the client can correctly deal with the user callback attempting
// to start another transaction on a session that is closing down. See
// http://crbug.com/47455
-TEST_F(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
+TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = { CreateMockWrite(*req) };
MockWrite writes2[] = { CreateMockWrite(*req) };
@@ -1168,14 +2043,14 @@ TEST_F(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
new OrderedSocketData(reads, arraysize(reads),
writes, arraysize(writes)));
scoped_refptr<DelayedSocketData> data2(
- new DelayedSocketData(0, reads2, arraysize(reads2),
+ new DelayedSocketData(1, reads2, arraysize(reads2),
writes2, arraysize(writes2)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
helper.AddData(data.get());
helper.AddData(data2.get());
- helper.RunPreTestSetup();
HttpNetworkTransaction* trans = helper.trans();
// Start the transaction with basic parameters.
@@ -1213,7 +2088,7 @@ class SpdyNetworkTransactionTest::DeleteSessionCallback
// Verify that the client can correctly deal with the user callback deleting the
// transaction. Failures will usually be valgrind errors. See
// http://crbug.com/46925
-TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
+TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = { CreateMockWrite(*req) };
@@ -1231,9 +2106,9 @@ TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
// Start the transaction with basic parameters.
@@ -1256,9 +2131,714 @@ TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
helper.VerifyDataConsumed();
}
+// 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.
+ const char* const kExtraHeaders[] = {
+ "accept-charset",
+ "",
+ "accept-encoding",
+ "gzip,deflate",
+ "accept-language",
+ "",
+ };
+ const SpdyHeaderInfo kSynStartHeader = make_spdy_header(spdy::SYN_STREAM);
+ const char* const kStandardGetHeaders[] = {
+ "host",
+ "www.google.com",
+ "method",
+ "GET",
+ "scheme",
+ "http",
+ "url",
+ "/",
+ "user-agent",
+ "",
+ "version",
+ "HTTP/1.1"
+ };
+ const char* const kStandardGetHeaders2[] = {
+ "host",
+ "www.foo.com",
+ "method",
+ "GET",
+ "scheme",
+ "http",
+ "url",
+ "/index.php",
+ "user-agent",
+ "",
+ "version",
+ "HTTP/1.1"
+ };
+
+ // Setup writes/reads to www.google.com
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(
+ kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
+ kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
+ scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyPacket(
+ kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
+ kStandardGetHeaders2, arraysize(kStandardGetHeaders2)/2));
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReplyRedirect(1));
+ MockWrite writes[] = {
+ CreateMockWrite(*req, 1),
+ };
+ MockRead reads[] = {
+ CreateMockRead(*resp, 2),
+ MockRead(true, 0, 0, 3) // EOF
+ };
+
+ // Setup writes/reads to www.foo.com
+ scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true));
+ MockWrite writes2[] = {
+ CreateMockWrite(*req2, 1),
+ };
+ MockRead reads2[] = {
+ CreateMockRead(*resp2, 2),
+ CreateMockRead(*body2, 3),
+ MockRead(true, 0, 0, 4) // EOF
+ };
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ scoped_refptr<OrderedSocketData> data2(
+ new OrderedSocketData(reads2, arraysize(reads2),
+ writes2, arraysize(writes2)));
+
+ // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
+ HttpStreamFactory::set_force_spdy_over_ssl(false);
+ HttpStreamFactory::set_force_spdy_always(true);
+ TestDelegate d;
+ {
+ URLRequest r(GURL("http://www.google.com/"), &d);
+ SpdyURLRequestContext* spdy_url_request_context =
+ new SpdyURLRequestContext();
+ r.set_context(spdy_url_request_context);
+ spdy_url_request_context->socket_factory().
+ AddSocketDataProvider(data.get());
+ spdy_url_request_context->socket_factory().
+ AddSocketDataProvider(data2.get());
+
+ d.set_quit_on_redirect(true);
+ r.Start();
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(1, d.received_redirect_count());
+
+ r.FollowDeferredRedirect();
+ MessageLoop::current()->Run();
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_FALSE(d.received_data_before_response());
+ EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+ std::string contents("hello!");
+ EXPECT_EQ(contents, d.data_received());
+ }
+ EXPECT_TRUE(data->at_read_eof());
+ EXPECT_TRUE(data->at_write_eof());
+ EXPECT_TRUE(data2->at_read_eof());
+ EXPECT_TRUE(data2->at_write_eof());
+}
+
+// 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.
+ const char* const kExtraHeaders[] = {
+ "accept-charset",
+ "",
+ "accept-encoding",
+ "gzip,deflate",
+ "accept-language",
+ "",
+ };
+ const SpdyHeaderInfo kSynStartHeader = make_spdy_header(spdy::SYN_STREAM);
+ const char* const kStandardGetHeaders[] = {
+ "host",
+ "www.google.com",
+ "method",
+ "GET",
+ "scheme",
+ "http",
+ "url",
+ "/",
+ "user-agent",
+ "",
+ "version",
+ "HTTP/1.1"
+ };
+ const char* const kStandardGetHeaders2[] = {
+ "host",
+ "www.foo.com",
+ "method",
+ "GET",
+ "scheme",
+ "http",
+ "url",
+ "/index.php",
+ "user-agent",
+ "",
+ "version",
+ "HTTP/1.1"
+ };
+
+ // Setup writes/reads to www.google.com
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(
+ kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
+ kStandardGetHeaders, arraysize(kStandardGetHeaders)/2));
+ scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyPacket(
+ kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders)/2,
+ kStandardGetHeaders2, arraysize(kStandardGetHeaders2)/2));
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> rep(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat",
+ "301 Moved Permanently", "http://www.foo.com/index.php",
+ "http://www.foo.com/index.php"));
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ MockWrite writes[] = {
+ CreateMockWrite(*req, 1),
+ };
+ MockRead reads[] = {
+ CreateMockRead(*resp, 2),
+ CreateMockRead(*rep, 3),
+ CreateMockRead(*body, 4),
+ MockRead(true, ERR_IO_PENDING, 5), // Force a pause
+ MockRead(true, 0, 0, 6) // EOF
+ };
+
+ // Setup writes/reads to www.foo.com
+ scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true));
+ MockWrite writes2[] = {
+ CreateMockWrite(*req2, 1),
+ };
+ MockRead reads2[] = {
+ CreateMockRead(*resp2, 2),
+ CreateMockRead(*body2, 3),
+ MockRead(true, 0, 0, 5) // EOF
+ };
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ scoped_refptr<OrderedSocketData> data2(
+ new OrderedSocketData(reads2, arraysize(reads2),
+ writes2, arraysize(writes2)));
+
+ // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
+ HttpStreamFactory::set_force_spdy_over_ssl(false);
+ HttpStreamFactory::set_force_spdy_always(true);
+ TestDelegate d;
+ TestDelegate d2;
+ scoped_refptr<SpdyURLRequestContext> spdy_url_request_context(
+ new SpdyURLRequestContext());
+ {
+ URLRequest r(GURL("http://www.google.com/"), &d);
+ r.set_context(spdy_url_request_context);
+ spdy_url_request_context->socket_factory().
+ AddSocketDataProvider(data.get());
+
+ r.Start();
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(0, d.received_redirect_count());
+ std::string contents("hello!");
+ EXPECT_EQ(contents, d.data_received());
+
+ 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());
+
+ d2.set_quit_on_redirect(true);
+ r2.Start();
+ MessageLoop::current()->Run();
+ EXPECT_EQ(1, d2.received_redirect_count());
+
+ r2.FollowDeferredRedirect();
+ MessageLoop::current()->Run();
+ EXPECT_EQ(1, d2.response_started_count());
+ EXPECT_FALSE(d2.received_data_before_response());
+ EXPECT_EQ(URLRequestStatus::SUCCESS, r2.status().status());
+ std::string contents2("hello!");
+ EXPECT_EQ(contents2, d2.data_received());
+ }
+ data->CompleteRead();
+ data2->CompleteRead();
+ EXPECT_TRUE(data->at_read_eof());
+ EXPECT_TRUE(data->at_write_eof());
+ EXPECT_TRUE(data2->at_read_eof());
+ EXPECT_TRUE(data2->at_write_eof());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
+ static const unsigned char kPushBodyFrame[] = {
+ 0x00, 0x00, 0x00, 0x02, // header, ID
+ 0x01, 0x00, 0x00, 0x06, // FIN, length
+ 'p', 'u', 's', 'h', 'e', 'd' // "pushed"
+ };
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ CreateMockRead(*stream1_body, 4, false),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame),
+ arraysize(kPushBodyFrame), 5),
+ MockRead(true, ERR_IO_PENDING, 6), // Force a pause
+ };
+
+ HttpResponseInfo response;
+ HttpResponseInfo response2;
+ std::string expected_push_result("pushed");
+ RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
+ &response, &response2, expected_push_result);
+
+ // Verify the SYN_REPLY.
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+
+ // Verify the pushed stream.
+ EXPECT_TRUE(response2.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
+ static const unsigned char kPushBodyFrame[] = {
+ 0x00, 0x00, 0x00, 0x02, // header, ID
+ 0x01, 0x00, 0x00, 0x06, // FIN, length
+ 'p', 'u', 's', 'h', 'e', 'd' // "pushed"
+ };
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame),
+ arraysize(kPushBodyFrame), 5),
+ CreateMockRead(*stream1_body, 4, false),
+ MockRead(true, ERR_IO_PENDING, 6), // Force a pause
+ };
+
+ HttpResponseInfo response;
+ HttpResponseInfo response2;
+ std::string expected_push_result("pushed");
+ RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
+ &response, &response2, expected_push_result);
+
+ // Verify the SYN_REPLY.
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+
+ // Verify the pushed stream.
+ EXPECT_TRUE(response2.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_rst(ConstructSpdyRstStream(2, spdy::PROTOCOL_ERROR));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ CreateMockRead(*stream2_rst, 4),
+ CreateMockRead(*stream1_body, 5, false),
+ MockRead(true, ERR_IO_PENDING, 6), // Force a pause
+ };
+
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+
+ HttpNetworkTransaction* trans = helper.trans();
+
+ // Start the transaction with basic parameters.
+ TestCompletionCallback callback;
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ // Verify that we consumed all test data.
+ EXPECT_TRUE(data->at_read_eof()) << "Read count: "
+ << data->read_count()
+ << " Read index: "
+ << data->read_index();
+ EXPECT_TRUE(data->at_write_eof()) << "Write count: "
+ << data->write_count()
+ << " Write index: "
+ << data->write_index();
+
+ // Verify the SYN_REPLY.
+ HttpResponseInfo response = *trans->GetResponseInfo();
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) {
+ // Verify that we don't leak streams and that we properly send a reset
+ // if the server pushes the same stream twice.
+ static const unsigned char kPushBodyFrame[] = {
+ 0x00, 0x00, 0x00, 0x02, // header, ID
+ 0x01, 0x00, 0x00, 0x06, // FIN, length
+ 'p', 'u', 's', 'h', 'e', 'd' // "pushed"
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ scoped_ptr<spdy::SpdyFrame>
+ stream3_rst(ConstructSpdyRstStream(4, spdy::PROTOCOL_ERROR));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ CreateMockWrite(*stream3_rst, 5),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
+ scoped_ptr<spdy::SpdyFrame>
+ stream3_syn(ConstructSpdyPush(NULL, 0, 4, 1, "/foo.dat"));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ CreateMockRead(*stream3_syn, 4),
+ CreateMockRead(*stream1_body, 6, false),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame),
+ arraysize(kPushBodyFrame), 7),
+ MockRead(true, ERR_IO_PENDING, 8), // Force a pause
+ };
+
+ HttpResponseInfo response;
+ HttpResponseInfo response2;
+ std::string expected_push_result("pushed");
+ RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
+ &response, &response2, expected_push_result);
+
+ // Verify the SYN_REPLY.
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+
+ // Verify the pushed stream.
+ EXPECT_TRUE(response2.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
+ static const unsigned char kPushBodyFrame1[] = {
+ 0x00, 0x00, 0x00, 0x02, // header, ID
+ 0x01, 0x00, 0x00, 0x1F, // FIN, length
+ 'p', 'u', 's', 'h', 'e', 'd' // "pushed"
+ };
+ static const char kPushBodyFrame2[] = " my darling";
+ static const char kPushBodyFrame3[] = " hello";
+ static const char kPushBodyFrame4[] = " my baby";
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame1),
+ arraysize(kPushBodyFrame1), 4),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame2),
+ arraysize(kPushBodyFrame2) - 1, 5),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame3),
+ arraysize(kPushBodyFrame3) - 1, 6),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame4),
+ arraysize(kPushBodyFrame4) - 1, 7),
+ CreateMockRead(*stream1_body, 8, false),
+ MockRead(true, ERR_IO_PENDING, 9), // Force a pause
+ };
+
+ HttpResponseInfo response;
+ HttpResponseInfo response2;
+ std::string expected_push_result("pushed my darling hello my baby");
+ RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
+ &response, &response2, expected_push_result);
+
+ // Verify the SYN_REPLY.
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+
+ // Verify the pushed stream.
+ EXPECT_TRUE(response2.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
+ static const unsigned char kPushBodyFrame1[] = {
+ 0x00, 0x00, 0x00, 0x02, // header, ID
+ 0x01, 0x00, 0x00, 0x1F, // FIN, length
+ 'p', 'u', 's', 'h', 'e', 'd' // "pushed"
+ };
+ static const char kPushBodyFrame2[] = " my darling";
+ static const char kPushBodyFrame3[] = " hello";
+ static const char kPushBodyFrame4[] = " my baby";
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1, "/foo.dat"));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame1),
+ arraysize(kPushBodyFrame1), 4),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame2),
+ arraysize(kPushBodyFrame2) - 1, 5),
+ MockRead(true, ERR_IO_PENDING, 6), // Force a pause
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame3),
+ arraysize(kPushBodyFrame3) - 1, 7),
+ MockRead(true, reinterpret_cast<const char*>(kPushBodyFrame4),
+ arraysize(kPushBodyFrame4) - 1, 8),
+ CreateMockRead(*stream1_body.get(), 9, false),
+ MockRead(true, ERR_IO_PENDING, 10) // Force a pause.
+ };
+
+ HttpResponseInfo response;
+ HttpResponseInfo response2;
+ std::string expected_push_result("pushed my darling hello my baby");
+ RunServerPushTest(writes, arraysize(writes), reads, arraysize(reads),
+ &response, &response2, expected_push_result);
+
+ // Verify the SYN_REPLY.
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+
+ // Verify the pushed stream.
+ EXPECT_TRUE(response2.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_rst(ConstructSpdyRstStream(2, spdy::INVALID_STREAM));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ CreateMockWrite(*stream2_rst, 4),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 0, "/foo.dat"));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ CreateMockRead(*stream1_body, 4),
+ MockRead(true, ERR_IO_PENDING, 5) // Force a pause
+ };
+
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+
+ HttpNetworkTransaction* trans = helper.trans();
+
+ // Start the transaction with basic parameters.
+ TestCompletionCallback callback;
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ // Verify that we consumed all test data.
+ EXPECT_TRUE(data->at_read_eof()) << "Read count: "
+ << data->read_count()
+ << " Read index: "
+ << data->read_index();
+ EXPECT_TRUE(data->at_write_eof()) << "Write count: "
+ << data->write_count()
+ << " Write index: "
+ << data->write_index();
+
+ // Verify the SYN_REPLY.
+ HttpResponseInfo response = *trans->GetResponseInfo();
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_rst(ConstructSpdyRstStream(2, spdy::INVALID_ASSOCIATED_STREAM));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ CreateMockWrite(*stream2_rst, 4),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 9, "/foo.dat"));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ CreateMockRead(*stream1_body, 4),
+ MockRead(true, ERR_IO_PENDING, 5), // Force a pause
+ };
+
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+
+ HttpNetworkTransaction* trans = helper.trans();
+
+ // Start the transaction with basic parameters.
+ TestCompletionCallback callback;
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ // Verify that we consumed all test data.
+ EXPECT_TRUE(data->at_read_eof()) << "Read count: "
+ << data->read_count()
+ << " Read index: "
+ << data->read_index();
+ EXPECT_TRUE(data->at_write_eof()) << "Write count: "
+ << data->write_count()
+ << " Write index: "
+ << data->write_index();
+
+ // Verify the SYN_REPLY.
+ HttpResponseInfo response = *trans->GetResponseInfo();
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+}
+
+TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_body(ConstructSpdyBodyFrame(1, true));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_rst(ConstructSpdyRstStream(2, spdy::PROTOCOL_ERROR));
+ MockWrite writes[] = {
+ CreateMockWrite(*stream1_syn, 1),
+ CreateMockWrite(*stream2_rst, 4),
+ };
+
+ scoped_ptr<spdy::SpdyFrame>
+ stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame>
+ stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1));
+ MockRead reads[] = {
+ CreateMockRead(*stream1_reply, 2),
+ CreateMockRead(*stream2_syn, 3),
+ CreateMockRead(*stream1_body, 4),
+ MockRead(true, ERR_IO_PENDING, 5) // Force a pause
+ };
+
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+
+ helper.RunPreTestSetup();
+ helper.AddData(data.get());
+
+ HttpNetworkTransaction* trans = helper.trans();
+
+ // Start the transaction with basic parameters.
+ TestCompletionCallback callback;
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ // Verify that we consumed all test data.
+ EXPECT_TRUE(data->at_read_eof()) << "Read count: "
+ << data->read_count()
+ << " Read index: "
+ << data->read_index();
+ EXPECT_TRUE(data->at_write_eof()) << "Write count: "
+ << data->write_count()
+ << " Write index: "
+ << data->write_index();
+
+ // Verify the SYN_REPLY.
+ HttpResponseInfo response = *trans->GetResponseInfo();
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+}
+
// Verify that various SynReply headers parse correctly through the
// HTTP layer.
-TEST_F(SpdyNetworkTransactionTest, SynReplyHeaders) {
+TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
struct SynReplyHeadersTests {
int num_headers;
const char* extra_headers[5];
@@ -1318,7 +2898,7 @@ TEST_F(SpdyNetworkTransactionTest, SynReplyHeaders) {
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
@@ -1342,12 +2922,13 @@ TEST_F(SpdyNetworkTransactionTest, SynReplyHeaders) {
// Verify that various SynReply headers parse vary fields correctly
// through the HTTP layer, and the response matches the request.
-TEST_F(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
+TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
static const SpdyHeaderInfo syn_reply_info = {
spdy::SYN_REPLY, // Syn Reply
1, // Stream ID
0, // Associated Stream ID
- SPDY_PRIORITY_LOWEST, // Priority
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST),
+ // Priority
spdy::CONTROL_FLAG_NONE, // Control Flags
false, // Compressed
spdy::INVALID, // Status
@@ -1466,7 +3047,7 @@ TEST_F(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(request,
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
@@ -1510,12 +3091,13 @@ TEST_F(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
}
// Verify that we don't crash on invalid SynReply responses.
-TEST_F(SpdyNetworkTransactionTest, InvalidSynReply) {
+TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
const SpdyHeaderInfo kSynStartHeader = {
spdy::SYN_REPLY, // Kind = SynReply
1, // Stream ID
0, // Associated stream ID
- SPDY_PRIORITY_LOWEST, // Priority
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST),
+ // Priority
spdy::CONTROL_FLAG_NONE, // Control Flags
false, // Compressed
spdy::INVALID, // Status
@@ -1571,7 +3153,7 @@ TEST_F(SpdyNetworkTransactionTest, InvalidSynReply) {
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(ERR_INVALID_RESPONSE, out.rv);
@@ -1580,7 +3162,7 @@ TEST_F(SpdyNetworkTransactionTest, InvalidSynReply) {
// Verify that we don't crash on some corrupt frames.
// TODO(eroman): Renable this test, see http://crbug.com/48588
-TEST_F(SpdyNetworkTransactionTest, DISABLED_CorruptFrameSessionError) {
+TEST_P(SpdyNetworkTransactionTest, DISABLED_CorruptFrameSessionError) {
// This is the length field with a big number
scoped_ptr<spdy::SpdyFrame> syn_reply_massive_length(
ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -1611,7 +3193,7 @@ TEST_F(SpdyNetworkTransactionTest, DISABLED_CorruptFrameSessionError) {
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
@@ -1619,7 +3201,7 @@ TEST_F(SpdyNetworkTransactionTest, DISABLED_CorruptFrameSessionError) {
}
// Test that we shutdown correctly on write errors.
-TEST_F(SpdyNetworkTransactionTest, WriteError) {
+TEST_P(SpdyNetworkTransactionTest, WriteError) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = {
// We'll write 10 bytes successfully
@@ -1632,7 +3214,7 @@ TEST_F(SpdyNetworkTransactionTest, WriteError) {
new DelayedSocketData(2, NULL, 0,
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(ERR_FAILED, out.rv);
@@ -1640,7 +3222,7 @@ TEST_F(SpdyNetworkTransactionTest, WriteError) {
}
// Test that partial writes work.
-TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
+TEST_P(SpdyNetworkTransactionTest, PartialWrite) {
// Chop the SYN_STREAM frame into 5 chunks.
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
const int kChunks = 5;
@@ -1658,7 +3240,7 @@ TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
new DelayedSocketData(kChunks, reads, arraysize(reads),
writes.get(), kChunks));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(OK, out.rv);
@@ -1668,14 +3250,17 @@ TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
// In this test, we enable compression, but get a uncompressed SynReply from
// the server. Verify that teardown is all clean.
-TEST_F(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
+TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
// For this test, we turn on the normal compression.
EnableCompression(true);
scoped_ptr<spdy::SpdyFrame> compressed(
ConstructSpdyGet(NULL, 0, true, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> rst(
+ ConstructSpdyRstStream(1, spdy::PROTOCOL_ERROR));
MockWrite writes[] = {
CreateMockWrite(*compressed),
+ CreateMockWrite(*rst),
};
scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -1683,24 +3268,24 @@ TEST_F(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
MockRead reads[] = {
CreateMockRead(*resp),
CreateMockRead(*body),
- MockRead(true, 0, 0) // EOF
+ MockRead(true, 0, 0)
};
scoped_refptr<DelayedSocketData> data(
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
+ EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
data->Reset();
EnableCompression(false);
}
// Test that the NetLog contains good data for a simple GET request.
-TEST_F(SpdyNetworkTransactionTest, NetLog) {
+TEST_P(SpdyNetworkTransactionTest, NetLog) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = { CreateMockWrite(*req) };
@@ -1718,7 +3303,7 @@ TEST_F(SpdyNetworkTransactionTest, NetLog) {
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- log.bound());
+ log.bound(), GetParam());
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
EXPECT_EQ(OK, out.rv);
@@ -1732,22 +3317,22 @@ TEST_F(SpdyNetworkTransactionTest, NetLog) {
EXPECT_LT(0u, log.entries().size());
int pos = 0;
pos = net::ExpectLogContainsSomewhere(log.entries(), 0,
- net::NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST,
+ net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
net::NetLog::PHASE_BEGIN);
pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
- net::NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST,
+ net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
net::NetLog::PHASE_END);
pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
- net::NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS,
+ net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
net::NetLog::PHASE_BEGIN);
pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
- net::NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS,
+ net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
net::NetLog::PHASE_END);
pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
- net::NetLog::TYPE_SPDY_TRANSACTION_READ_BODY,
+ net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
net::NetLog::PHASE_BEGIN);
pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
- net::NetLog::TYPE_SPDY_TRANSACTION_READ_BODY,
+ net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
net::NetLog::PHASE_END);
}
@@ -1755,7 +3340,7 @@ TEST_F(SpdyNetworkTransactionTest, NetLog) {
// that when we read out the maximum amount of data (e.g. we received 50 bytes
// on the network, but issued a Read for only 5 of those bytes) that the data
// flow still works correctly.
-TEST_F(SpdyNetworkTransactionTest, BufferFull) {
+TEST_P(SpdyNetworkTransactionTest, BufferFull) {
spdy::SpdyFramer framer;
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
@@ -1795,9 +3380,9 @@ TEST_F(SpdyNetworkTransactionTest, BufferFull) {
TestCompletionCallback callback;
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -1846,7 +3431,7 @@ TEST_F(SpdyNetworkTransactionTest, BufferFull) {
EXPECT_EQ("goodbye world", out.response_data);
}
-TEST_F(SpdyNetworkTransactionTest, ConnectFailureFallbackToHttp) {
+TEST_P(SpdyNetworkTransactionTest, ConnectFailureFallbackToHttp) {
MockConnect connects[] = {
MockConnect(true, ERR_NAME_NOT_RESOLVED),
MockConnect(false, ERR_NAME_NOT_RESOLVED),
@@ -1874,9 +3459,9 @@ TEST_F(SpdyNetworkTransactionTest, ConnectFailureFallbackToHttp) {
new DelayedSocketData(connects[index], 1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
// Set up http fallback data.
MockRead http_fallback_data[] = {
@@ -1897,6 +3482,12 @@ TEST_F(SpdyNetworkTransactionTest, ConnectFailureFallbackToHttp) {
EXPECT_EQ(rv, ERR_IO_PENDING);
rv = callback.WaitForResult();
const HttpResponseInfo* response = trans->GetResponseInfo();
+ if (GetParam() == SPDYNOSSL || GetParam() == SPDYSSL) {
+ ASSERT_TRUE(response == NULL);
+ return;
+ }
+ if (GetParam() != SPDYNPN)
+ NOTREACHED();
ASSERT_TRUE(response != NULL);
ASSERT_TRUE(response->headers != NULL);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
@@ -1917,7 +3508,7 @@ TEST_F(SpdyNetworkTransactionTest, ConnectFailureFallbackToHttp) {
// Verify that basic buffering works; when multiple data frames arrive
// at the same time, ensure that we don't notify a read completion for
// each data frame individually.
-TEST_F(SpdyNetworkTransactionTest, Buffering) {
+TEST_P(SpdyNetworkTransactionTest, Buffering) {
spdy::SpdyFramer framer;
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
@@ -1952,9 +3543,9 @@ TEST_F(SpdyNetworkTransactionTest, Buffering) {
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
@@ -2011,7 +3602,7 @@ TEST_F(SpdyNetworkTransactionTest, Buffering) {
}
// Verify the case where we buffer data but read it after it has been buffered.
-TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
+TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
spdy::SpdyFramer framer;
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
@@ -2047,9 +3638,9 @@ TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
@@ -2102,7 +3693,7 @@ TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
}
// Verify the case where we buffer data and close the connection.
-TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
+TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
spdy::SpdyFramer framer;
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
@@ -2135,9 +3726,9 @@ TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
@@ -2192,7 +3783,7 @@ TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
}
// Verify the case where we buffer data and cancel the transaction.
-TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
+TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
spdy::SpdyFramer framer;
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
@@ -2215,9 +3806,9 @@ TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
- helper.AddData(data.get());
+ BoundNetLog(), GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
@@ -2263,12 +3854,13 @@ TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
// Test that if the server requests persistence of settings, that we save
// the settings in the SpdySettingsStorage.
-TEST_F(SpdyNetworkTransactionTest, SettingsSaved) {
+TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
static const SpdyHeaderInfo kSynReplyInfo = {
spdy::SYN_REPLY, // Syn Reply
1, // Stream ID
0, // Associated Stream ID
- SPDY_PRIORITY_LOWEST, // Priority
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST),
+ // Priority
spdy::CONTROL_FLAG_NONE, // Control Flags
false, // Compressed
spdy::INVALID, // Status
@@ -2282,10 +3874,11 @@ TEST_F(SpdyNetworkTransactionTest, SettingsSaved) {
};
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
// Verify that no settings exist initially.
- HostPortPair host_port_pair("www.google.com", 443);
+ HostPortPair host_port_pair("www.google.com", helper.port());
EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty());
// Construct the request.
@@ -2337,7 +3930,9 @@ TEST_F(SpdyNetworkTransactionTest, SettingsSaved) {
scoped_refptr<DelayedSocketData> data(
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
- helper.RunToCompletion(data.get());
+ helper.AddData(data.get());
+ helper.RunDefaultTest();
+ helper.VerifyDataConsumed();
TransactionHelperResult out = helper.output();
EXPECT_EQ(OK, out.rv);
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
@@ -2367,12 +3962,13 @@ TEST_F(SpdyNetworkTransactionTest, SettingsSaved) {
// Test that when there are settings saved that they are sent back to the
// server upon session establishment.
-TEST_F(SpdyNetworkTransactionTest, SettingsPlayback) {
+TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
static const SpdyHeaderInfo kSynReplyInfo = {
spdy::SYN_REPLY, // Syn Reply
1, // Stream ID
0, // Associated Stream ID
- SPDY_PRIORITY_LOWEST, // Priority
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST),
+ // Priority
spdy::CONTROL_FLAG_NONE, // Control Flags
false, // Compressed
spdy::INVALID, // Status
@@ -2386,10 +3982,11 @@ TEST_F(SpdyNetworkTransactionTest, SettingsPlayback) {
};
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
+ helper.RunPreTestSetup();
// Verify that no settings exist initially.
- HostPortPair host_port_pair("www.google.com", 443);
+ HostPortPair host_port_pair("www.google.com", helper.port());
EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty());
unsigned int kSampleId1 = 0x1;
@@ -2445,7 +4042,9 @@ TEST_F(SpdyNetworkTransactionTest, SettingsPlayback) {
scoped_refptr<DelayedSocketData> data(
new DelayedSocketData(2, reads, arraysize(reads),
writes, arraysize(writes)));
- helper.RunToCompletion(data.get());
+ helper.AddData(data.get());
+ helper.RunDefaultTest();
+ helper.VerifyDataConsumed();
TransactionHelperResult out = helper.output();
EXPECT_EQ(OK, out.rv);
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
@@ -2473,27 +4072,28 @@ TEST_F(SpdyNetworkTransactionTest, SettingsPlayback) {
}
}
-TEST_F(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
+TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = { CreateMockWrite(*req) };
scoped_ptr<spdy::SpdyFrame> go_away(ConstructSpdyGoAway());
MockRead reads[] = {
CreateMockRead(*go_away),
- MockRead(true, 0, 0) // EOF
+ MockRead(true, 0, 0), // EOF
};
scoped_refptr<DelayedSocketData> data(
new DelayedSocketData(1, reads, arraysize(reads),
writes, arraysize(writes)));
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- BoundNetLog());
+ BoundNetLog(), GetParam());
+ helper.AddData(data);
helper.RunToCompletion(data.get());
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
+ EXPECT_EQ(ERR_ABORTED, out.rv);
}
-TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
+TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = { CreateMockWrite(*req) };
@@ -2508,9 +4108,9 @@ TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
writes, arraysize(writes)));
BoundNetLog log;
NormalSpdyTransactionHelper helper(CreateGetRequest(),
- log);
- helper.AddData(data.get());
+ log, GetParam());
helper.RunPreTestSetup();
+ helper.AddData(data.get());
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
@@ -2531,4 +4131,356 @@ TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
helper.VerifyDataConsumed();
}
+// Test to make sure we can correctly connect through a proxy.
+TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.session_deps().reset(new SpdySessionDependencies(
+ ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
+ helper.SetSession(SpdySessionDependencies::SpdyCreateSession(
+ helper.session_deps().get()));
+ helper.RunPreTestSetup();
+ HttpNetworkTransaction* trans = helper.trans();
+
+ const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"};
+ const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"};
+ const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+
+ MockWrite writes_SPDYNPN[] = {
+ MockWrite(false, kConnect443, arraysize(kConnect443) - 1, 0),
+ CreateMockWrite(*req, 2),
+ };
+ MockRead reads_SPDYNPN[] = {
+ MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
+ CreateMockRead(*resp, 3),
+ CreateMockRead(*body.get(), 4),
+ MockRead(true, 0, 0, 5),
+ };
+
+ MockWrite writes_SPDYSSL[] = {
+ MockWrite(false, kConnect80, arraysize(kConnect80) - 1, 0),
+ CreateMockWrite(*req, 2),
+ };
+ MockRead reads_SPDYSSL[] = {
+ MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
+ CreateMockRead(*resp, 3),
+ CreateMockRead(*body.get(), 4),
+ MockRead(true, 0, 0, 5),
+ };
+
+ MockWrite writes_SPDYNOSSL[] = {
+ CreateMockWrite(*req, 0),
+ };
+
+ MockRead reads_SPDYNOSSL[] = {
+ CreateMockRead(*resp, 1),
+ CreateMockRead(*body.get(), 2),
+ MockRead(true, 0, 0, 3),
+ };
+
+ scoped_refptr<OrderedSocketData> data;
+ switch(GetParam()) {
+ case SPDYNOSSL:
+ data = new OrderedSocketData(reads_SPDYNOSSL,
+ arraysize(reads_SPDYNOSSL),
+ writes_SPDYNOSSL,
+ arraysize(writes_SPDYNOSSL));
+ break;
+ case SPDYSSL:
+ data = new OrderedSocketData(reads_SPDYSSL, arraysize(reads_SPDYSSL),
+ writes_SPDYSSL, arraysize(writes_SPDYSSL));
+ break;
+ case SPDYNPN:
+ data = new OrderedSocketData(reads_SPDYNPN, arraysize(reads_SPDYNPN),
+ writes_SPDYNPN, arraysize(writes_SPDYNPN));
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ helper.AddData(data.get());
+ TestCompletionCallback callback;
+
+ int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(0, rv);
+
+ // Verify the SYN_REPLY.
+ HttpResponseInfo response = *trans->GetResponseInfo();
+ EXPECT_TRUE(response.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine());
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(trans, &response_data));
+ EXPECT_EQ("hello!", response_data);
+ helper.VerifyDataConsumed();
+}
+
+// Test to make sure we can correctly connect through a proxy to www.google.com,
+// if there already exists a direct spdy connection to www.google.com. See
+// http://crbug.com/49874
+TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
+ // When setting up the first transaction, we store the SpdySessionPool so that
+ // we can use the same pool in the second transaction.
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+
+ // Use a proxy service which returns a proxy fallback list from DIRECT to
+ // myproxy:70. For this test there will be no fallback, so it is equivalent
+ // to simply DIRECT. The reason for appending the second proxy is to verify
+ // that the session pool key used does is just "DIRECT".
+ helper.session_deps().reset(new SpdySessionDependencies(
+ ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70")));
+ helper.SetSession(SpdySessionDependencies::SpdyCreateSession(
+ helper.session_deps().get()));
+
+ scoped_refptr<SpdySessionPool> spdy_session_pool =
+ helper.session_deps()->spdy_session_pool;
+ helper.RunPreTestSetup();
+
+ // Construct and send a simple GET request.
+ scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
+ MockWrite writes[] = {
+ CreateMockWrite(*req, 1),
+ };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ MockRead reads[] = {
+ CreateMockRead(*resp, 2),
+ CreateMockRead(*body, 3),
+ MockRead(true, ERR_IO_PENDING, 4), // Force a pause
+ MockRead(true, 0, 5) // EOF
+ };
+ scoped_refptr<OrderedSocketData> data(
+ new OrderedSocketData(reads, arraysize(reads),
+ writes, arraysize(writes)));
+ helper.AddData(data.get());
+ HttpNetworkTransaction* trans = helper.trans();
+
+ TestCompletionCallback callback;
+ TransactionHelperResult out;
+ out.rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+
+ EXPECT_EQ(out.rv, ERR_IO_PENDING);
+ out.rv = callback.WaitForResult();
+ EXPECT_EQ(out.rv, OK);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ EXPECT_TRUE(response->headers != NULL);
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ out.rv = ReadTransaction(trans, &out.response_data);
+ EXPECT_EQ(OK, out.rv);
+ out.status_line = response->headers->GetStatusLine();
+ EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+ EXPECT_EQ("hello!", out.response_data);
+
+ // Check that the SpdySession is still in the SpdySessionPool.
+ HostPortPair host_port_pair("www.google.com", helper.port());
+ HostPortProxyPair session_pool_key_direct(
+ host_port_pair, ProxyServer::Direct());
+ EXPECT_TRUE(spdy_session_pool->HasSession(session_pool_key_direct));
+ HostPortProxyPair session_pool_key_proxy(
+ host_port_pair,
+ ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP));
+ EXPECT_FALSE(spdy_session_pool->HasSession(session_pool_key_proxy));
+
+ // Set up data for the proxy connection.
+ const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"};
+ const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"};
+ const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
+ scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(
+ "http://www.google.com/foo.dat", false, 1, LOWEST));
+ scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true));
+
+ MockWrite writes_SPDYNPN[] = {
+ MockWrite(false, kConnect443, arraysize(kConnect443) - 1, 0),
+ CreateMockWrite(*req2, 2),
+ };
+ MockRead reads_SPDYNPN[] = {
+ MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
+ CreateMockRead(*resp2, 3),
+ CreateMockRead(*body2, 4),
+ MockRead(true, 0, 5) // EOF
+ };
+
+ MockWrite writes_SPDYNOSSL[] = {
+ CreateMockWrite(*req2, 0),
+ };
+ MockRead reads_SPDYNOSSL[] = {
+ CreateMockRead(*resp2, 1),
+ CreateMockRead(*body2, 2),
+ MockRead(true, 0, 3) // EOF
+ };
+
+ MockWrite writes_SPDYSSL[] = {
+ MockWrite(false, kConnect80, arraysize(kConnect80) - 1, 0),
+ CreateMockWrite(*req2, 2),
+ };
+ MockRead reads_SPDYSSL[] = {
+ MockRead(false, kHTTP200, arraysize(kHTTP200) - 1, 1),
+ CreateMockRead(*resp2, 3),
+ CreateMockRead(*body2, 4),
+ MockRead(true, 0, 0, 5),
+ };
+
+ scoped_refptr<OrderedSocketData> data_proxy;
+ switch(GetParam()) {
+ case SPDYNPN:
+ data_proxy = new OrderedSocketData(reads_SPDYNPN,
+ arraysize(reads_SPDYNPN),
+ writes_SPDYNPN,
+ arraysize(writes_SPDYNPN));
+ break;
+ case SPDYNOSSL:
+ data_proxy = new OrderedSocketData(reads_SPDYNOSSL,
+ arraysize(reads_SPDYNOSSL),
+ writes_SPDYNOSSL,
+ arraysize(writes_SPDYNOSSL));
+ break;
+ case SPDYSSL:
+ data_proxy = new OrderedSocketData(reads_SPDYSSL,
+ arraysize(reads_SPDYSSL),
+ writes_SPDYSSL,
+ arraysize(writes_SPDYSSL));
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // Create another request to www.google.com, but this time through a proxy.
+ HttpRequestInfo request_proxy;
+ request_proxy.method = "GET";
+ request_proxy.url = GURL("http://www.google.com/foo.dat");
+ request_proxy.load_flags = 0;
+ scoped_ptr<SpdySessionDependencies> ssd_proxy(
+ new SpdySessionDependencies(
+ ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")));
+ // Ensure that this transaction uses the same SpdySessionPool.
+ ssd_proxy->spdy_session_pool = spdy_session_pool;
+ scoped_refptr<HttpNetworkSession> session_proxy =
+ SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get());
+ NormalSpdyTransactionHelper helper_proxy(request_proxy,
+ BoundNetLog(), GetParam());
+ helper_proxy.session_deps().swap(ssd_proxy);
+ helper_proxy.SetSession(session_proxy);
+ helper_proxy.RunPreTestSetup();
+ helper_proxy.AddData(data_proxy.get());
+
+ HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
+ TestCompletionCallback callback_proxy;
+ int rv = trans_proxy->Start(&request_proxy, &callback_proxy, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback_proxy.WaitForResult();
+ EXPECT_EQ(0, rv);
+
+ HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
+ EXPECT_TRUE(response_proxy.headers != NULL);
+ EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine());
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data));
+ EXPECT_EQ("hello!", response_data);
+
+ data->CompleteRead();
+ helper_proxy.VerifyDataConsumed();
+}
+
+// When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
+// on a new connection, if the connection was previously known to be good.
+// This can happen when a server reboots without saying goodbye, or when
+// we're behind a NAT that masked the RST.
+TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true));
+ MockRead reads[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*body),
+ MockRead(true, ERR_IO_PENDING),
+ MockRead(true, ERR_CONNECTION_RESET),
+ };
+
+ MockRead reads2[] = {
+ CreateMockRead(*resp),
+ CreateMockRead(*body),
+ MockRead(true, 0, 0) // EOF
+ };
+
+ // This test has a couple of variants.
+ enum {
+ // Induce the RST while waiting for our transaction to send.
+ VARIANT_RST_DURING_SEND_COMPLETION,
+ // Induce the RST while waiting for our transaction to read.
+ // In this case, the send completed - everything copied into the SNDBUF.
+ VARIANT_RST_DURING_READ_COMPLETION
+ };
+
+ for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
+ variant <= VARIANT_RST_DURING_READ_COMPLETION;
+ ++variant) {
+ scoped_refptr<DelayedSocketData> data1(
+ new DelayedSocketData(1, reads, arraysize(reads),
+ NULL, 0));
+
+ scoped_refptr<DelayedSocketData> data2(
+ new DelayedSocketData(1, reads2, arraysize(reads2),
+ NULL, 0));
+
+ NormalSpdyTransactionHelper helper(CreateGetRequest(),
+ BoundNetLog(), GetParam());
+ helper.AddData(data1.get());
+ helper.AddData(data2.get());
+ helper.RunPreTestSetup();
+
+ for (int i = 0; i < 2; ++i) {
+ scoped_ptr<HttpNetworkTransaction> trans(
+ new HttpNetworkTransaction(helper.session()));
+
+ TestCompletionCallback callback;
+ int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ // On the second transaction, we trigger the RST.
+ if (i == 1) {
+ if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
+ // Writes to the socket complete asynchronously on SPDY by running
+ // through the message loop. Complete the write here.
+ MessageLoop::current()->RunAllPending();
+ }
+
+ // Now schedule the ERR_CONNECTION_RESET.
+ EXPECT_EQ(3u, data1->read_index());
+ data1->CompleteRead();
+ EXPECT_EQ(4u, data1->read_index());
+ }
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != NULL);
+ EXPECT_TRUE(response->headers != NULL);
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ std::string response_data;
+ rv = ReadTransaction(trans.get(), &response_data);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_EQ("hello!", response_data);
+ }
+
+ helper.VerifyDataConsumed();
+ }
+}
} // namespace net
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index 810d5b3..ce074c4 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -6,6 +6,7 @@
#ifndef NET_SPDY_SPDY_PROTOCOL_H_
#define NET_SPDY_SPDY_PROTOCOL_H_
+#pragma once
#ifdef WIN32
#include <winsock2.h>
@@ -118,8 +119,8 @@
namespace spdy {
-// This implementation of Spdy is version 1.
-const int kSpdyProtocolVersion = 1;
+// The SPDY version of this implementation.
+const int kSpdyProtocolVersion = 2;
// Default initial window size.
const int kInitialWindowSize = 64 * 1024;
@@ -188,7 +189,8 @@ enum SpdyStatusCodes {
CANCEL = 5,
INTERNAL_ERROR = 6,
FLOW_CONTROL_ERROR = 7,
- NUM_STATUS_CODES = 8
+ INVALID_ASSOCIATED_STREAM = 8,
+ NUM_STATUS_CODES = 9
};
// A SPDY stream id is a 31 bit entity.
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 06ba7d5..ed3d346 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -8,59 +8,29 @@
#include "base/linked_ptr.h"
#include "base/logging.h"
#include "base/message_loop.h"
-#include "base/rand_util.h"
#include "base/stats_counters.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "net/base/connection_type_histograms.h"
-#include "net/base/load_flags.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
#include "net/http/http_network_session.h"
-#include "net/socket/client_socket.h"
-#include "net/socket/client_socket_factory.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_frame_builder.h"
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/spdy_settings_storage.h"
#include "net/spdy/spdy_stream.h"
-namespace {
-
-// Diagnostics function to dump the headers of a request.
-// TODO(mbelshe): Remove this function.
-void DumpSpdyHeaders(const spdy::SpdyHeaderBlock& headers) {
- // Because this function gets called on every request,
- // take extra care to optimize it away if logging is turned off.
- if (logging::LOG_INFO < logging::GetMinLogLevel())
- return;
-
- spdy::SpdyHeaderBlock::const_iterator it = headers.begin();
- while (it != headers.end()) {
- std::string val = (*it).second;
- std::string::size_type pos = 0;
- while ((pos = val.find('\0', pos)) != val.npos)
- val[pos] = '\n';
- LOG(INFO) << (*it).first << "==" << val;
- ++it;
- }
-}
-
-} // namespace
-
namespace net {
namespace {
-#ifdef WIN32
-// We use an artificially small buffer size on windows because the async IO
-// system will artifiially delay IO completions when we use large buffers.
-const int kReadBufferSize = 2 * 1024;
-#else
const int kReadBufferSize = 8 * 1024;
-#endif
void AdjustSocketBufferSizes(ClientSocket* socket) {
// Adjust socket buffer sizes.
@@ -73,6 +43,21 @@ void AdjustSocketBufferSizes(ClientSocket* socket) {
socket->SetSendBufferSize(kSocketBufferSize);
}
+class NetLogSpdySessionParameter : public NetLog::EventParameters {
+ public:
+ NetLogSpdySessionParameter(const HostPortProxyPair& host_pair)
+ : host_pair_(host_pair) {}
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->Set("host", new StringValue(host_pair_.first.ToString()));
+ dict->Set("proxy", new StringValue(host_pair_.second.ToPacString()));
+ return dict;
+ }
+ private:
+ const HostPortProxyPair host_pair_;
+ DISALLOW_COPY_AND_ASSIGN(NetLogSpdySessionParameter);
+};
+
class NetLogSpdySynParameter : public NetLog::EventParameters {
public:
NetLogSpdySynParameter(const linked_ptr<spdy::SpdyHeaderBlock>& headers,
@@ -82,14 +67,15 @@ class NetLogSpdySynParameter : public NetLog::EventParameters {
Value* ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- DictionaryValue* headers_dict = new DictionaryValue();
+ ListValue* headers_list = new ListValue();
for (spdy::SpdyHeaderBlock::const_iterator it = headers_->begin();
it != headers_->end(); ++it) {
- headers_dict->SetString(ASCIIToWide(it->first), it->second);
+ headers_list->Append(new StringValue(base::StringPrintf(
+ "%s: %s", it->first.c_str(), it->second.c_str())));
}
- dict->SetInteger(L"flags", flags_);
- dict->Set(L"headers", headers_dict);
- dict->SetInteger(L"id", id_);
+ dict->SetInteger("flags", flags_);
+ dict->Set("headers", headers_list);
+ dict->SetInteger("id", id_);
return dict;
}
@@ -97,8 +83,8 @@ class NetLogSpdySynParameter : public NetLog::EventParameters {
~NetLogSpdySynParameter() {}
const linked_ptr<spdy::SpdyHeaderBlock> headers_;
- spdy::SpdyControlFlags flags_;
- spdy::SpdyStreamId id_;
+ const spdy::SpdyControlFlags flags_;
+ const spdy::SpdyStreamId id_;
DISALLOW_COPY_AND_ASSIGN(NetLogSpdySynParameter);
};
@@ -114,38 +100,134 @@ class NetLogSpdySettingsParameter : public NetLog::EventParameters {
for (spdy::SpdySettings::const_iterator it = settings_.begin();
it != settings_.end(); ++it) {
settings->Append(new StringValue(
- StringPrintf("[%u:%u]", it->first.id(), it->second)));
+ base::StringPrintf("[%u:%u]", it->first.id(), it->second)));
}
- dict->Set(L"settings", settings);
+ dict->Set("settings", settings);
return dict;
}
private:
~NetLogSpdySettingsParameter() {}
-
const spdy::SpdySettings settings_;
DISALLOW_COPY_AND_ASSIGN(NetLogSpdySettingsParameter);
};
+class NetLogSpdyWindowUpdateParameter : public NetLog::EventParameters {
+ public:
+ NetLogSpdyWindowUpdateParameter(spdy::SpdyStreamId stream_id,
+ int delta,
+ int window_size)
+ : stream_id_(stream_id), delta_(delta), window_size_(window_size) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("stream_id", static_cast<int>(stream_id_));
+ dict->SetInteger("delta", delta_);
+ dict->SetInteger("window_size", window_size_);
+ return dict;
+ }
+
+ private:
+ ~NetLogSpdyWindowUpdateParameter() {}
+ const spdy::SpdyStreamId stream_id_;
+ const int delta_;
+ const int window_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetLogSpdyWindowUpdateParameter);
+};
+
+class NetLogSpdyDataParameter : public NetLog::EventParameters {
+ public:
+ NetLogSpdyDataParameter(spdy::SpdyStreamId stream_id,
+ int size,
+ spdy::SpdyDataFlags flags)
+ : stream_id_(stream_id), size_(size), flags_(flags) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("stream_id", static_cast<int>(stream_id_));
+ dict->SetInteger("size", size_);
+ dict->SetInteger("flags", static_cast<int>(flags_));
+ return dict;
+ }
+
+ private:
+ ~NetLogSpdyDataParameter() {}
+ const spdy::SpdyStreamId stream_id_;
+ const int size_;
+ const spdy::SpdyDataFlags flags_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetLogSpdyDataParameter);
+};
+
+class NetLogSpdyRstParameter : public NetLog::EventParameters {
+ public:
+ NetLogSpdyRstParameter(spdy::SpdyStreamId stream_id, int status)
+ : stream_id_(stream_id), status_(status) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("stream_id", static_cast<int>(stream_id_));
+ dict->SetInteger("status", status_);
+ return dict;
+ }
+
+ private:
+ ~NetLogSpdyRstParameter() {}
+ const spdy::SpdyStreamId stream_id_;
+ const int status_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetLogSpdyRstParameter);
+};
+
+class NetLogSpdyGoAwayParameter : public NetLog::EventParameters {
+ public:
+ NetLogSpdyGoAwayParameter(spdy::SpdyStreamId last_stream_id,
+ int active_streams,
+ int unclaimed_streams)
+ : last_stream_id_(last_stream_id),
+ active_streams_(active_streams),
+ unclaimed_streams_(unclaimed_streams) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("last_accepted_stream_id",
+ static_cast<int>(last_stream_id_));
+ dict->SetInteger("active_streams", active_streams_);
+ dict->SetInteger("unclaimed_streams", unclaimed_streams_);
+ return dict;
+ }
+
+ private:
+ ~NetLogSpdyGoAwayParameter() {}
+ const spdy::SpdyStreamId last_stream_id_;
+ const int active_streams_;
+ const int unclaimed_streams_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetLogSpdyGoAwayParameter);
+};
+
} // namespace
// static
bool SpdySession::use_ssl_ = true;
-SpdySession::SpdySession(const HostPortPair& host_port_pair,
- HttpNetworkSession* session,
+// static
+bool SpdySession::use_flow_control_ = false;
+
+SpdySession::SpdySession(const HostPortProxyPair& host_port_proxy_pair,
+ SpdySessionPool* spdy_session_pool,
+ SpdySettingsStorage* spdy_settings,
NetLog* net_log)
: ALLOW_THIS_IN_INITIALIZER_LIST(
- connect_callback_(this, &SpdySession::OnTCPConnect)),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- ssl_connect_callback_(this, &SpdySession::OnSSLConnect)),
- ALLOW_THIS_IN_INITIALIZER_LIST(
read_callback_(this, &SpdySession::OnReadComplete)),
ALLOW_THIS_IN_INITIALIZER_LIST(
write_callback_(this, &SpdySession::OnWriteComplete)),
- host_port_pair_(host_port_pair),
- session_(session),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
+ host_port_proxy_pair_(host_port_proxy_pair),
+ spdy_session_pool_(spdy_session_pool),
+ spdy_settings_(spdy_settings),
connection_(new ClientSocketHandle),
read_buffer_(new IOBuffer(kReadBufferSize)),
read_pending_(false),
@@ -161,21 +243,21 @@ SpdySession::SpdySession(const HostPortPair& host_port_pair,
streams_pushed_count_(0),
streams_pushed_and_claimed_count_(0),
streams_abandoned_count_(0),
+ frames_received_(0),
sent_settings_(false),
received_settings_(false),
in_session_pool_(true),
- initial_window_size_(spdy::kInitialWindowSize),
+ initial_send_window_size_(spdy::kInitialWindowSize),
+ initial_recv_window_size_(spdy::kInitialWindowSize),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) {
net_log_.BeginEvent(
NetLog::TYPE_SPDY_SESSION,
- new NetLogStringParameter("host_port", host_port_pair_.ToString()));
+ new NetLogSpdySessionParameter(host_port_proxy_pair_));
// TODO(mbelshe): consider randomization of the stream_hi_water_mark.
spdy_framer_.set_visitor(this);
- session_->ssl_config_service()->GetSSLConfig(&ssl_config_);
-
SendSettings();
}
@@ -190,13 +272,18 @@ SpdySession::~SpdySession() {
connection_->socket()->Disconnect();
}
+ // Streams should all be gone now.
+ DCHECK_EQ(0u, num_active_streams());
+ DCHECK_EQ(0u, num_unclaimed_pushed_streams());
+
RecordHistograms();
net_log_.EndEvent(NetLog::TYPE_SPDY_SESSION, NULL);
}
-net::Error SpdySession::InitializeWithSSLSocket(
+net::Error SpdySession::InitializeWithSocket(
ClientSocketHandle* connection,
+ bool is_secure,
int certificate_error_code) {
static StatsCounter spdy_sessions("spdy.sessions");
spdy_sessions.Increment();
@@ -205,7 +292,7 @@ net::Error SpdySession::InitializeWithSSLSocket(
state_ = CONNECTED;
connection_.reset(connection);
- is_secure_ = true; // |connection| contains an SSLClientSocket.
+ is_secure_ = is_secure;
certificate_error_code_ = certificate_error_code;
// This is a newly initialized session that no client should have a handle to
@@ -217,34 +304,6 @@ net::Error SpdySession::InitializeWithSSLSocket(
return error;
}
-net::Error SpdySession::Connect(
- const std::string& group_name,
- const scoped_refptr<TCPSocketParams>& destination,
- RequestPriority priority) {
- DCHECK(priority >= SPDY_PRIORITY_HIGHEST && priority <= SPDY_PRIORITY_LOWEST);
-
- // If the connect process is started, let the caller continue.
- if (state_ > IDLE)
- return net::OK;
-
- state_ = CONNECTING;
-
- static StatsCounter spdy_sessions("spdy.sessions");
- spdy_sessions.Increment();
-
- int rv = connection_->Init(group_name, destination, priority,
- &connect_callback_, session_->tcp_socket_pool(),
- net_log_);
- DCHECK(rv <= 0);
-
- // If the connect is pending, we still return ok. The APIs enqueue
- // work until after the connect completes asynchronously later.
- if (rv == net::ERR_IO_PENDING)
- return net::OK;
- OnTCPConnect(rv);
- return static_cast<net::Error>(rv);
-}
-
int SpdySession::GetPushStream(
const GURL& url,
scoped_refptr<SpdyStream>* stream,
@@ -270,24 +329,7 @@ int SpdySession::GetPushStream(
streams_pushed_and_claimed_count_++;
return OK;
}
-
- // Check if we have a pending push stream for this url.
- // Note that we shouldn't have a pushed stream for non-GET method.
- PendingStreamMap::iterator it;
- it = pending_streams_.find(path);
- if (it != pending_streams_.end()) {
- // Server has advertised a stream, but not yet sent it.
- DCHECK(!it->second);
- // Server will assign a stream id when the push stream arrives. Use 0 for
- // now.
- net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM, NULL);
- *stream = new SpdyStream(this, 0, true);
- (*stream)->set_path(path);
- (*stream)->set_net_log(stream_net_log);
- it->second = *stream;
- return OK;
- }
- return OK;
+ return 0;
}
int SpdySession::CreateStream(
@@ -301,6 +343,7 @@ int SpdySession::CreateStream(
return CreateStreamImpl(url, priority, spdy_stream, stream_net_log);
}
+ net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_MAX_STREAMS, NULL);
create_stream_queues_[priority].push(
PendingCreateStream(url, priority, spdy_stream,
stream_net_log, callback));
@@ -313,14 +356,14 @@ void SpdySession::ProcessPendingCreateStreams() {
bool no_pending_create_streams = true;
for (int i = 0;i < NUM_PRIORITIES;++i) {
if (!create_stream_queues_[i].empty()) {
- PendingCreateStream& pending_create = create_stream_queues_[i].front();
+ PendingCreateStream pending_create = create_stream_queues_[i].front();
+ create_stream_queues_[i].pop();
no_pending_create_streams = false;
int error = CreateStreamImpl(*pending_create.url,
pending_create.priority,
pending_create.spdy_stream,
*pending_create.stream_net_log);
pending_create.callback->Run(error);
- create_stream_queues_[i].pop();
break;
}
}
@@ -335,10 +378,10 @@ void SpdySession::CancelPendingCreateStreams(
PendingCreateStreamQueue tmp;
// Make a copy removing this trans
while (!create_stream_queues_[i].empty()) {
- PendingCreateStream& pending_create = create_stream_queues_[i].front();
+ PendingCreateStream pending_create = create_stream_queues_[i].front();
+ create_stream_queues_[i].pop();
if (pending_create.spdy_stream != spdy_stream)
tmp.push(pending_create);
- create_stream_queues_[i].pop();
}
// Now copy it back
while (!tmp.empty()) {
@@ -366,22 +409,23 @@ int SpdySession::CreateStreamImpl(
const spdy::SpdyStreamId stream_id = GetNewStreamId();
- *spdy_stream = new SpdyStream(this, stream_id, false);
+ *spdy_stream = new SpdyStream(this,
+ stream_id,
+ false,
+ stream_net_log);
const scoped_refptr<SpdyStream>& stream = *spdy_stream;
stream->set_priority(priority);
stream->set_path(path);
- stream->set_net_log(stream_net_log);
- stream->set_window_size(initial_window_size_);
+ stream->set_send_window_size(initial_send_window_size_);
+ stream->set_recv_window_size(initial_recv_window_size_);
ActivateStream(stream);
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyPriorityCount",
static_cast<int>(priority), 0, 10, 11);
- LOG(INFO) << "SpdyStream: Creating stream " << stream_id << " for " << url;
// TODO(mbelshe): Optimize memory allocations
- DCHECK(priority >= SPDY_PRIORITY_HIGHEST &&
- priority <= SPDY_PRIORITY_LOWEST);
+ DCHECK(priority >= net::HIGHEST && priority < net::NUM_PRIORITIES);
DCHECK_EQ(active_streams_[stream_id].get(), stream.get());
return OK;
@@ -399,21 +443,19 @@ int SpdySession::WriteSynStream(
CHECK_EQ(stream->stream_id(), stream_id);
scoped_ptr<spdy::SpdySynStreamControlFrame> syn_frame(
- spdy_framer_.CreateSynStream(stream_id, 0, priority, flags, false,
- headers.get()));
+ spdy_framer_.CreateSynStream(
+ stream_id, 0,
+ ConvertRequestPriorityToSpdyPriority(priority),
+ flags, false, headers.get()));
QueueFrame(syn_frame.get(), priority, stream);
static StatsCounter spdy_requests("spdy.requests");
spdy_requests.Increment();
streams_initiated_count_++;
- LOG(INFO) << "SPDY SYN_STREAM HEADERS ----------------------------------";
- DumpSpdyHeaders(*headers);
-
- const BoundNetLog& log = stream->net_log();
- if (log.HasListener()) {
- log.AddEvent(
- NetLog::TYPE_SPDY_STREAM_SYN_STREAM,
+ if (net_log().IsLoggingAll()) {
+ net_log().AddEvent(
+ NetLog::TYPE_SPDY_SESSION_SYN_STREAM,
new NetLogSpdySynParameter(headers, flags, stream_id));
}
@@ -423,15 +465,6 @@ int SpdySession::WriteSynStream(
int SpdySession::WriteStreamData(spdy::SpdyStreamId stream_id,
net::IOBuffer* data, int len,
spdy::SpdyDataFlags flags) {
- LOG(INFO) << "Writing Stream Data for stream " << stream_id << " (" << len
- << " bytes)";
- const int kMss = 1430; // This is somewhat arbitrary and not really fixed,
- // but it will always work reasonably with ethernet.
- // Chop the world into 2-packet chunks. This is somewhat arbitrary, but
- // is reasonably small and ensures that we elicit ACKs quickly from TCP
- // (because TCP tries to only ACK every other packet).
- const int kMaxSpdyFrameChunkSize = (2 * kMss) - spdy::SpdyFrame::size();
-
// Find our stream
DCHECK(IsStreamActive(stream_id));
scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
@@ -441,9 +474,35 @@ int SpdySession::WriteStreamData(spdy::SpdyStreamId stream_id,
if (len > kMaxSpdyFrameChunkSize) {
len = kMaxSpdyFrameChunkSize;
- flags = spdy::DATA_FLAG_NONE;
+ flags = static_cast<spdy::SpdyDataFlags>(flags & ~spdy::DATA_FLAG_FIN);
+ }
+
+ // Obey send window size of the stream if flow control is enabled.
+ if (use_flow_control_) {
+ if (stream->send_window_size() <= 0) {
+ // Because we queue frames onto the session, it is possible that
+ // a stream was not flow controlled at the time it attempted the
+ // write, but when we go to fulfill the write, it is now flow
+ // controlled. This is why we need the session to mark the stream
+ // as stalled - because only the session knows for sure when the
+ // stall occurs.
+ stream->set_stalled_by_flow_control(true);
+ net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_ON_SEND_WINDOW,
+ new NetLogIntegerParameter("stream_id", stream_id));
+ return ERR_IO_PENDING;
+ }
+ int new_len = std::min(len, stream->send_window_size());
+ if (new_len < len) {
+ len = new_len;
+ flags = static_cast<spdy::SpdyDataFlags>(flags & ~spdy::DATA_FLAG_FIN);
+ }
+ stream->DecreaseSendWindowSize(len);
}
+ if (net_log().IsLoggingAll())
+ net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_SEND_DATA,
+ new NetLogSpdyDataParameter(stream_id, len, flags));
+
// TODO(mbelshe): reduce memory copies here.
scoped_ptr<spdy::SpdyDataFrame> frame(
spdy_framer_.CreateDataFrame(stream_id, data->data(), len, flags));
@@ -452,7 +511,6 @@ int SpdySession::WriteStreamData(spdy::SpdyStreamId stream_id,
}
void SpdySession::CloseStream(spdy::SpdyStreamId stream_id, int status) {
- LOG(INFO) << "Closing stream " << stream_id << " with status " << status;
// TODO(mbelshe): We should send a RST_STREAM control frame here
// so that the server can cancel a large send.
@@ -461,16 +519,21 @@ void SpdySession::CloseStream(spdy::SpdyStreamId stream_id, int status) {
void SpdySession::ResetStream(
spdy::SpdyStreamId stream_id, spdy::SpdyStatusCodes status) {
- DCHECK(IsStreamActive(stream_id));
- scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
- CHECK_EQ(stream->stream_id(), stream_id);
- LOG(INFO) << "Sending a RST_STREAM frame for stream " << stream_id
- << " with status " << status;
+ net_log().AddEvent(
+ NetLog::TYPE_SPDY_SESSION_SEND_RST_STREAM,
+ new NetLogSpdyRstParameter(stream_id, status));
scoped_ptr<spdy::SpdyRstStreamControlFrame> rst_frame(
spdy_framer_.CreateRstStream(stream_id, status));
- QueueFrame(rst_frame.get(), stream->priority(), stream);
+
+ // Default to lowest priority unless we know otherwise.
+ int priority = 3;
+ if(IsStreamActive(stream_id)) {
+ scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
+ priority = stream->priority();
+ }
+ QueueFrame(rst_frame.get(), priority, NULL);
DeleteStream(stream_id, ERR_SPDY_PROTOCOL_ERROR);
}
@@ -494,85 +557,19 @@ LoadState SpdySession::GetLoadState() const {
return LOAD_STATE_IDLE;
}
-void SpdySession::OnTCPConnect(int result) {
- LOG(INFO) << "Spdy socket connected (result=" << result << ")";
-
- // We shouldn't be coming through this path if we didn't just open a fresh
- // socket (or have an error trying to do so).
- DCHECK(!connection_->socket() || !connection_->is_reused());
-
- if (result != net::OK) {
- DCHECK_LT(result, 0);
- CloseSessionOnError(static_cast<net::Error>(result));
- return;
- } else {
- UpdateConnectionTypeHistograms(CONNECTION_SPDY);
- }
-
- AdjustSocketBufferSizes(connection_->socket());
-
- if (use_ssl_) {
- // Add a SSL socket on top of our existing transport socket.
- ClientSocket* socket = connection_->release_socket();
- // TODO(mbelshe): Fix the hostname. This is BROKEN without having
- // a real hostname.
- socket = session_->socket_factory()->CreateSSLClientSocket(
- socket, "" /* request_->url.HostNoBrackets() */ , ssl_config_);
- connection_->set_socket(socket);
- is_secure_ = true;
- int status = connection_->socket()->Connect(&ssl_connect_callback_);
- if (status != ERR_IO_PENDING)
- OnSSLConnect(status);
- } else {
- DCHECK_EQ(state_, CONNECTING);
- state_ = CONNECTED;
-
- // Make sure we get any pending data sent.
- WriteSocketLater();
- // Start reading
- ReadSocket();
- }
-}
-
-void SpdySession::OnSSLConnect(int result) {
- // TODO(mbelshe): We need to replicate the functionality of
- // HttpNetworkTransaction::DoSSLConnectComplete here, where it calls
- // HandleCertificateError() and such.
- if (IsCertificateError(result))
- result = OK; // TODO(mbelshe): pretend we're happy anyway.
-
- if (result == OK) {
- DCHECK_EQ(state_, CONNECTING);
- state_ = CONNECTED;
-
- // After we've connected, send any data to the server, and then issue
- // our read.
- WriteSocketLater();
- ReadSocket();
- } else {
- DCHECK_LT(result, 0); // It should be an error, not a byte count.
- CloseSessionOnError(static_cast<net::Error>(result));
- }
-}
-
void SpdySession::OnReadComplete(int bytes_read) {
// Parse a frame. For now this code requires that the frame fit into our
// buffer (32KB).
// TODO(mbelshe): support arbitrarily large frames!
- LOG(INFO) << "Spdy socket read: " << bytes_read << " bytes";
-
read_pending_ = false;
if (bytes_read <= 0) {
// Session is tearing down.
net::Error error = static_cast<net::Error>(bytes_read);
- if (bytes_read == 0) {
- LOG(INFO) << "Spdy socket closed by server[" <<
- host_port_pair().ToString() << "].";
+ if (bytes_read == 0)
error = ERR_CONNECTION_CLOSED;
- }
- CloseSessionOnError(error);
+ CloseSessionOnError(error, true);
return;
}
@@ -599,16 +596,11 @@ void SpdySession::OnReadComplete(int bytes_read) {
void SpdySession::OnWriteComplete(int result) {
DCHECK(write_pending_);
DCHECK(in_flight_write_.size());
- DCHECK_NE(result, 0); // This shouldn't happen for write.
write_pending_ = false;
scoped_refptr<SpdyStream> stream = in_flight_write_.stream();
- LOG(INFO) << "Spdy write complete (result=" << result << ")"
- << (stream ? std::string(" for stream ") +
- IntToString(stream->stream_id()) : "");
-
if (result >= 0) {
// It should not be possible to have written more bytes than our
// in_flight_write_.
@@ -647,7 +639,7 @@ void SpdySession::OnWriteComplete(int result) {
in_flight_write_.release();
// The stream is now errored. Close it down.
- CloseSessionOnError(static_cast<net::Error>(result));
+ CloseSessionOnError(static_cast<net::Error>(result), true);
}
}
@@ -668,7 +660,7 @@ net::Error SpdySession::ReadSocket() {
switch (bytes_read) {
case 0:
// Socket is closed!
- CloseSessionOnError(ERR_CONNECTION_CLOSED);
+ CloseSessionOnError(ERR_CONNECTION_CLOSED, true);
return ERR_CONNECTION_CLOSED;
case net::ERR_IO_PENDING:
// Waiting for data. Nothing to do now.
@@ -679,8 +671,10 @@ net::Error SpdySession::ReadSocket() {
// Schedule the work through the message loop to avoid recursive
// callbacks.
read_pending_ = true;
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SpdySession::OnReadComplete, bytes_read));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SpdySession::OnReadComplete, bytes_read));
break;
}
return OK;
@@ -694,8 +688,9 @@ void SpdySession::WriteSocketLater() {
return;
delayed_write_pending_ = true;
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SpdySession::WriteSocket));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(&SpdySession::WriteSocket));
}
void SpdySession::WriteSocket() {
@@ -729,7 +724,7 @@ void SpdySession::WriteSocket() {
spdy_framer_.CompressFrame(uncompressed_frame));
if (!compressed_frame.get()) {
LOG(ERROR) << "SPDY Compression failure";
- CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR);
+ CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, true);
return;
}
@@ -768,23 +763,22 @@ void SpdySession::WriteSocket() {
}
void SpdySession::CloseAllStreams(net::Error status) {
- LOG(INFO) << "Closing all SPDY Streams for " << host_port_pair().ToString();
-
static StatsCounter abandoned_streams("spdy.abandoned_streams");
static StatsCounter abandoned_push_streams("spdy.abandoned_push_streams");
if (!active_streams_.empty())
abandoned_streams.Add(active_streams_.size());
- if (!pushed_streams_.empty()) {
- streams_abandoned_count_ += pushed_streams_.size();
- abandoned_push_streams.Add(pushed_streams_.size());
+ if (!unclaimed_pushed_streams_.empty()) {
+ streams_abandoned_count_ += unclaimed_pushed_streams_.size();
+ abandoned_push_streams.Add(unclaimed_pushed_streams_.size());
+ unclaimed_pushed_streams_.clear();
}
for (int i = 0;i < NUM_PRIORITIES;++i) {
while (!create_stream_queues_[i].empty()) {
- PendingCreateStream& pending_create = create_stream_queues_[i].front();
- pending_create.callback->Run(ERR_ABORTED);
+ PendingCreateStream pending_create = create_stream_queues_[i].front();
create_stream_queues_[i].pop();
+ pending_create.callback->Run(ERR_ABORTED);
}
}
@@ -792,21 +786,11 @@ void SpdySession::CloseAllStreams(net::Error status) {
ActiveStreamMap::iterator it = active_streams_.begin();
const scoped_refptr<SpdyStream>& stream = it->second;
DCHECK(stream);
- LOG(ERROR) << "ABANDONED (stream_id=" << stream->stream_id()
- << "): " << stream->path();
+ LOG(WARNING) << "ABANDONED (stream_id=" << stream->stream_id()
+ << "): " << stream->path();
DeleteStream(stream->stream_id(), status);
}
- // TODO(erikchen): ideally stream->OnClose() is only ever called by
- // DeleteStream, but pending streams fall into their own category for now.
- PendingStreamMap::iterator it;
- for (it = pending_streams_.begin(); it != pending_streams_.end(); ++it) {
- const scoped_refptr<SpdyStream>& stream = it->second;
- if (stream)
- stream->OnClose(ERR_ABORTED);
- }
- pending_streams_.clear();
-
// We also need to drain the queue.
while (queue_.size())
queue_.pop();
@@ -831,14 +815,14 @@ void SpdySession::QueueFrame(spdy::SpdyFrame* frame,
WriteSocketLater();
}
-void SpdySession::CloseSessionOnError(net::Error err) {
+void SpdySession::CloseSessionOnError(net::Error err, bool remove_from_pool) {
// Closing all streams can have a side-effect of dropping the last reference
// to |this|. Hold a reference through this function.
scoped_refptr<SpdySession> self(this);
DCHECK_LT(err, OK);
- LOG(INFO) << "spdy::CloseSessionOnError(" << err << ") for " <<
- host_port_pair().ToString();
+ net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_CLOSE,
+ new NetLogIntegerParameter("status", err));
// Don't close twice. This can occur because we can have both
// a read and a write outstanding, and each can complete with
@@ -846,7 +830,8 @@ void SpdySession::CloseSessionOnError(net::Error err) {
if (state_ != CLOSED) {
state_ = CLOSED;
error_ = err;
- RemoveFromPool();
+ if (remove_from_pool)
+ RemoveFromPool();
CloseAllStreams(err);
}
}
@@ -859,13 +844,18 @@ void SpdySession::ActivateStream(SpdyStream* stream) {
}
void SpdySession::DeleteStream(spdy::SpdyStreamId id, int status) {
- // Remove the stream from pushed_streams_ and active_streams_.
- ActivePushedStreamList::iterator it;
- for (it = pushed_streams_.begin(); it != pushed_streams_.end(); ++it) {
- scoped_refptr<SpdyStream> curr = *it;
- if (id == curr->stream_id()) {
- pushed_streams_.erase(it);
- break;
+ // For push streams, if they are being deleted normally, we leave
+ // the stream in the unclaimed_pushed_streams_ list. However, if
+ // the stream is errored out, clean it up entirely.
+ if (status != OK) {
+ PushedStreamMap::iterator it;
+ for (it = unclaimed_pushed_streams_.begin();
+ it != unclaimed_pushed_streams_.end(); ++it) {
+ scoped_refptr<SpdyStream> curr = it->second;
+ if (id == curr->stream_id()) {
+ unclaimed_pushed_streams_.erase(it);
+ break;
+ }
}
}
@@ -884,7 +874,7 @@ void SpdySession::DeleteStream(spdy::SpdyStreamId id, int status) {
void SpdySession::RemoveFromPool() {
if (in_session_pool_) {
- session_->spdy_session_pool()->Remove(this);
+ spdy_session_pool_->Remove(this);
in_session_pool_ = false;
}
}
@@ -893,24 +883,17 @@ scoped_refptr<SpdyStream> SpdySession::GetActivePushStream(
const std::string& path) {
static StatsCounter used_push_streams("spdy.claimed_push_streams");
- LOG(INFO) << "Looking for push stream: " << path;
-
- scoped_refptr<SpdyStream> stream;
-
- // We just walk a linear list here.
- ActivePushedStreamList::iterator it;
- for (it = pushed_streams_.begin(); it != pushed_streams_.end(); ++it) {
- stream = *it;
- if (path == stream->path()) {
- CHECK(stream->pushed());
- pushed_streams_.erase(it);
- used_push_streams.Increment();
- LOG(INFO) << "Push Stream Claim for: " << path;
- return stream;
- }
+ PushedStreamMap::iterator it = unclaimed_pushed_streams_.find(path);
+ if (it != unclaimed_pushed_streams_.end()) {
+ net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM, NULL);
+ scoped_refptr<SpdyStream> stream = it->second;
+ unclaimed_pushed_streams_.erase(it);
+ used_push_streams.Increment();
+ return stream;
+ }
+ else {
+ return NULL;
}
-
- return NULL;
}
bool SpdySession::GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated) {
@@ -918,21 +901,33 @@ bool SpdySession::GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated) {
SSLClientSocket* ssl_socket =
reinterpret_cast<SSLClientSocket*>(connection_->socket());
ssl_socket->GetSSLInfo(ssl_info);
- *was_npn_negotiated = ssl_socket->wasNpnNegotiated();
+ *was_npn_negotiated = ssl_socket->was_npn_negotiated();
+ return true;
+ }
+ return false;
+}
+
+bool SpdySession::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ if (is_secure_) {
+ SSLClientSocket* ssl_socket =
+ reinterpret_cast<SSLClientSocket*>(connection_->socket());
+ ssl_socket->GetSSLCertRequestInfo(cert_request_info);
return true;
}
return false;
}
void SpdySession::OnError(spdy::SpdyFramer* framer) {
- LOG(ERROR) << "SpdySession error: " << framer->error_code();
- CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR);
+ CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, true);
}
void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id,
const char* data,
size_t len) {
- LOG(INFO) << "Spdy data for stream " << stream_id << ", " << len << " bytes";
+ if (net_log().IsLoggingAll())
+ net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_RECV_DATA,
+ new NetLogSpdyDataParameter(stream_id, len, spdy::SpdyDataFlags()));
if (!IsStreamActive(stream_id)) {
// NOTE: it may just be that the stream was cancelled.
@@ -961,8 +956,15 @@ bool SpdySession::Respond(const spdy::SpdyHeaderBlock& headers,
void SpdySession::OnSyn(const spdy::SpdySynStreamControlFrame& frame,
const linked_ptr<spdy::SpdyHeaderBlock>& headers) {
spdy::SpdyStreamId stream_id = frame.stream_id();
+ spdy::SpdyStreamId associated_stream_id = frame.associated_stream_id();
- LOG(INFO) << "Spdy SynStream for stream " << stream_id;
+ if (net_log_.IsLoggingAll()) {
+ net_log_.AddEvent(
+ NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM,
+ new NetLogSpdySynParameter(
+ headers, static_cast<spdy::SpdyControlFlags>(frame.flags()),
+ stream_id));
+ }
// Server-initiated streams should have even sequence numbers.
if ((stream_id & 0x1) != 0) {
@@ -975,12 +977,15 @@ void SpdySession::OnSyn(const spdy::SpdySynStreamControlFrame& frame,
return;
}
- streams_pushed_count_++;
-
- LOG(INFO) << "SpdySession: Syn received for stream: " << stream_id;
+ if (associated_stream_id == 0) {
+ LOG(ERROR) << "Received invalid OnSyn associated stream id "
+ << associated_stream_id
+ << " for stream " << stream_id;
+ ResetStream(stream_id, spdy::INVALID_STREAM);
+ return;
+ }
- LOG(INFO) << "SPDY SYN RESPONSE HEADERS -----------------------";
- DumpSpdyHeaders(*headers);
+ streams_pushed_count_++;
// TODO(mbelshe): DCHECK that this is a GET method?
@@ -988,59 +993,43 @@ void SpdySession::OnSyn(const spdy::SpdySynStreamControlFrame& frame,
headers->find("path")->second : "";
// Verify that the response had a URL for us.
- DCHECK(!path.empty());
if (path.empty()) {
+ ResetStream(stream_id, spdy::PROTOCOL_ERROR);
LOG(WARNING) << "Pushed stream did not contain a path.";
return;
}
- // Only HTTP push a stream.
- scoped_refptr<SpdyStream> stream;
-
- // Check if we already have a delegate awaiting this stream.
- PendingStreamMap::iterator it;
- it = pending_streams_.find(path);
- if (it != pending_streams_.end()) {
- stream = it->second;
- pending_streams_.erase(it);
+ if (!IsStreamActive(associated_stream_id)) {
+ LOG(ERROR) << "Received OnSyn with inactive associated stream "
+ << associated_stream_id;
+ ResetStream(stream_id, spdy::INVALID_ASSOCIATED_STREAM);
+ return;
}
- if (stream) {
- CHECK(stream->pushed());
- CHECK_EQ(0u, stream->stream_id());
- stream->set_stream_id(stream_id);
- const BoundNetLog& log = stream->net_log();
- if (log.HasListener()) {
- log.AddEvent(
- NetLog::TYPE_SPDY_STREAM_PUSHED_SYN_STREAM,
- new NetLogSpdySynParameter(
- headers, static_cast<spdy::SpdyControlFlags>(frame.flags()),
- stream_id));
- }
- } else {
- stream = new SpdyStream(this, stream_id, true);
-
- if (net_log_.HasListener()) {
- net_log_.AddEvent(
- NetLog::TYPE_SPDY_SESSION_PUSHED_SYN_STREAM,
- new NetLogSpdySynParameter(
- headers, static_cast<spdy::SpdyControlFlags>(frame.flags()),
- stream_id));
- }
- }
+ // TODO(erikchen): Actually do something with the associated id.
- pushed_streams_.push_back(stream);
+ // There should not be an existing pushed stream with the same path.
+ PushedStreamMap::iterator it = unclaimed_pushed_streams_.find(path);
+ if (it != unclaimed_pushed_streams_.end()) {
+ LOG(ERROR) << "Received duplicate pushed stream with path: " << path;
+ ResetStream(stream_id, spdy::PROTOCOL_ERROR);
+ return;
+ }
- // Activate a stream and parse the headers.
- ActivateStream(stream);
+ scoped_refptr<SpdyStream> stream =
+ new SpdyStream(this, stream_id, true, net_log_);
stream->set_path(path);
+ unclaimed_pushed_streams_[path] = stream;
+
+ ActivateStream(stream);
+ stream->set_response_received();
+
+ // Parse the headers.
if (!Respond(*headers, stream))
return;
- LOG(INFO) << "Got pushed stream for " << stream->path();
-
static StatsCounter push_requests("spdy.pushed_streams");
push_requests.Increment();
}
@@ -1048,7 +1037,6 @@ void SpdySession::OnSyn(const spdy::SpdySynStreamControlFrame& frame,
void SpdySession::OnSynReply(const spdy::SpdySynReplyControlFrame& frame,
const linked_ptr<spdy::SpdyHeaderBlock>& headers) {
spdy::SpdyStreamId stream_id = frame.stream_id();
- LOG(INFO) << "Spdy SynReply for stream " << stream_id;
bool valid_stream = IsStreamActive(stream_id);
if (!valid_stream) {
@@ -1057,52 +1045,20 @@ void SpdySession::OnSynReply(const spdy::SpdySynReplyControlFrame& frame,
return;
}
- LOG(INFO) << "SPDY SYN_REPLY RESPONSE HEADERS for stream: " << stream_id;
- DumpSpdyHeaders(*headers);
-
scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
CHECK_EQ(stream->stream_id(), stream_id);
CHECK(!stream->cancelled());
- if (stream->syn_reply_received()) {
+ if (stream->response_received()) {
LOG(WARNING) << "Received duplicate SYN_REPLY for stream " << stream_id;
CloseStream(stream->stream_id(), ERR_SPDY_PROTOCOL_ERROR);
return;
}
- stream->set_syn_reply_received();
-
- // We record content declared as being pushed so that we don't
- // request a duplicate stream which is already scheduled to be
- // sent to us.
- spdy::SpdyHeaderBlock::const_iterator it;
- it = headers->find("x-associated-content");
- if (it != headers->end()) {
- const std::string& content = it->second;
- std::string::size_type start = 0;
- std::string::size_type end = 0;
- do {
- end = content.find("||", start);
- if (end == std::string::npos)
- end = content.length();
- std::string url = content.substr(start, end - start);
- std::string::size_type pos = url.find("??");
- if (pos == std::string::npos)
- break;
- url = url.substr(pos + 2);
- GURL gurl(url);
- std::string path = gurl.PathForRequest();
- if (path.length())
- pending_streams_[path] = NULL;
- else
- LOG(INFO) << "Invalid X-Associated-Content path: " << url;
- start = end + 2;
- } while (start < content.length());
- }
+ stream->set_response_received();
- const BoundNetLog& log = stream->net_log();
- if (log.HasListener()) {
- log.AddEvent(
- NetLog::TYPE_SPDY_STREAM_SYN_REPLY,
+ if (net_log().IsLoggingAll()) {
+ net_log().AddEvent(
+ NetLog::TYPE_SPDY_SESSION_SYN_REPLY,
new NetLogSpdySynParameter(
headers, static_cast<spdy::SpdyControlFlags>(frame.flags()),
stream_id));
@@ -1116,12 +1072,22 @@ void SpdySession::OnControl(const spdy::SpdyControlFrame* frame) {
uint32 type = frame->type();
if (type == spdy::SYN_STREAM || type == spdy::SYN_REPLY) {
if (!spdy_framer_.ParseHeaderBlock(frame, headers.get())) {
- LOG(WARNING) << "Could not parse Spdy Control Frame Header";
- // TODO(mbelshe): Error the session?
+ LOG(WARNING) << "Could not parse Spdy Control Frame Header.";
+ int stream_id = 0;
+ if (type == spdy::SYN_STREAM)
+ stream_id = (reinterpret_cast<const spdy::SpdySynStreamControlFrame*>
+ (frame))->stream_id();
+ if (type == spdy::SYN_REPLY)
+ stream_id = (reinterpret_cast<const spdy::SpdySynReplyControlFrame*>
+ (frame))->stream_id();
+ if(IsStreamActive(stream_id))
+ ResetStream(stream_id, spdy::PROTOCOL_ERROR);
return;
}
}
+ frames_received_++;
+
switch (type) {
case spdy::GOAWAY:
OnGoAway(*reinterpret_cast<const spdy::SpdyGoAwayControlFrame*>(frame));
@@ -1131,7 +1097,7 @@ void SpdySession::OnControl(const spdy::SpdyControlFrame* frame) {
*reinterpret_cast<const spdy::SpdySettingsControlFrame*>(frame));
break;
case spdy::RST_STREAM:
- OnFin(*reinterpret_cast<const spdy::SpdyRstStreamControlFrame*>(frame));
+ OnRst(*reinterpret_cast<const spdy::SpdyRstStreamControlFrame*>(frame));
break;
case spdy::SYN_STREAM:
OnSyn(*reinterpret_cast<const spdy::SpdySynStreamControlFrame*>(frame),
@@ -1151,25 +1117,23 @@ void SpdySession::OnControl(const spdy::SpdyControlFrame* frame) {
}
}
-void SpdySession::OnFin(const spdy::SpdyRstStreamControlFrame& frame) {
+void SpdySession::OnRst(const spdy::SpdyRstStreamControlFrame& frame) {
spdy::SpdyStreamId stream_id = frame.stream_id();
- LOG(INFO) << "Spdy Fin for stream " << stream_id;
+
+ net_log().AddEvent(
+ NetLog::TYPE_SPDY_SESSION_RST_STREAM,
+ new NetLogSpdyRstParameter(stream_id, frame.status()));
bool valid_stream = IsStreamActive(stream_id);
if (!valid_stream) {
// NOTE: it may just be that the stream was cancelled.
- LOG(WARNING) << "Received FIN for invalid stream" << stream_id;
+ LOG(WARNING) << "Received RST for invalid stream" << stream_id;
return;
}
scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
CHECK_EQ(stream->stream_id(), stream_id);
CHECK(!stream->cancelled());
- const BoundNetLog& log = stream->net_log();
- log.AddEvent(
- NetLog::TYPE_SPDY_STREAM_RST_STREAM,
- new NetLogIntegerParameter("status", frame.status()));
-
if (frame.status() == 0) {
stream->OnDataReceived(NULL, 0);
} else {
@@ -1181,16 +1145,13 @@ void SpdySession::OnFin(const spdy::SpdyRstStreamControlFrame& frame) {
}
void SpdySession::OnGoAway(const spdy::SpdyGoAwayControlFrame& frame) {
- LOG(INFO) << "Spdy GOAWAY for session[" << this << "] for " <<
- host_port_pair().ToString();
-
net_log_.AddEvent(
NetLog::TYPE_SPDY_SESSION_GOAWAY,
- new NetLogIntegerParameter(
- "last_accepted_stream_id",
- frame.last_accepted_stream_id()));
-
+ new NetLogSpdyGoAwayParameter(frame.last_accepted_stream_id(),
+ active_streams_.size(),
+ unclaimed_pushed_streams_.size()));
RemoveFromPool();
+ CloseAllStreams(net::ERR_ABORTED);
// TODO(willchan): Cancel any streams that are past the GoAway frame's
// |last_accepted_stream_id|.
@@ -1204,12 +1165,9 @@ void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) {
spdy::SpdySettings settings;
if (spdy_framer_.ParseSettings(&frame, &settings)) {
HandleSettings(settings);
- SpdySettingsStorage* settings_storage = session_->mutable_spdy_settings();
- settings_storage->Set(host_port_pair_, settings);
+ spdy_settings_->Set(host_port_pair(), settings);
}
- // TODO(agayev): Implement initial and per stream window size update.
-
received_settings_ = true;
net_log_.AddEvent(
@@ -1220,8 +1178,6 @@ void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) {
void SpdySession::OnWindowUpdate(
const spdy::SpdyWindowUpdateControlFrame& frame) {
spdy::SpdyStreamId stream_id = frame.stream_id();
- LOG(INFO) << "Spdy WINDOW_UPDATE for stream " << stream_id;
-
if (!IsStreamActive(stream_id)) {
LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id;
return;
@@ -1239,12 +1195,35 @@ void SpdySession::OnWindowUpdate(
CHECK_EQ(stream->stream_id(), stream_id);
CHECK(!stream->cancelled());
- stream->UpdateWindowSize(delta_window_size);
+ if (use_flow_control_)
+ stream->IncreaseSendWindowSize(delta_window_size);
+
+ net_log_.AddEvent(
+ NetLog::TYPE_SPDY_SESSION_SEND_WINDOW_UPDATE,
+ new NetLogSpdyWindowUpdateParameter(stream_id,
+ delta_window_size,
+ stream->send_window_size()));
+}
+
+void SpdySession::SendWindowUpdate(spdy::SpdyStreamId stream_id,
+ int delta_window_size) {
+ DCHECK(IsStreamActive(stream_id));
+ scoped_refptr<SpdyStream> stream = active_streams_[stream_id];
+ CHECK_EQ(stream->stream_id(), stream_id);
+
+ net_log_.AddEvent(
+ NetLog::TYPE_SPDY_SESSION_RECV_WINDOW_UPDATE,
+ new NetLogSpdyWindowUpdateParameter(stream_id,
+ delta_window_size,
+ stream->recv_window_size()));
+
+ scoped_ptr<spdy::SpdyWindowUpdateControlFrame> window_update_frame(
+ spdy_framer_.CreateWindowUpdate(stream_id, delta_window_size));
+ QueueFrame(window_update_frame.get(), stream->priority(), stream);
}
void SpdySession::SendSettings() {
- const SpdySettingsStorage& settings_storage = session_->spdy_settings();
- const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_);
+ const spdy::SpdySettings& settings = spdy_settings_->Get(host_port_pair());
if (settings.empty())
return;
HandleSettings(settings);
@@ -1294,8 +1273,7 @@ void SpdySession::RecordHistograms() {
if (received_settings_) {
// Enumerate the saved settings, and set histograms for it.
- const SpdySettingsStorage& settings_storage = session_->spdy_settings();
- const spdy::SpdySettings& settings = settings_storage.Get(host_port_pair_);
+ const spdy::SpdySettings& settings = spdy_settings_->Get(host_port_pair());
spdy::SpdySettings::const_iterator it;
for (it = settings.begin(); it != settings.end(); ++it) {
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 3add9b0..313440c 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -4,6 +4,7 @@
#ifndef NET_SPDY_SPDY_SESSION_H_
#define NET_SPDY_SPDY_SESSION_H_
+#pragma once
#include <deque>
#include <list>
@@ -11,8 +12,10 @@
#include <queue>
#include <string>
+#include "base/gtest_prod_util.h"
#include "base/linked_ptr.h"
#include "base/ref_counted.h"
+#include "base/task.h"
#include "net/base/io_buffer.h"
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
@@ -27,34 +30,40 @@
#include "net/spdy/spdy_io_buffer.h"
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/spdy_session_pool.h"
-#include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST
namespace net {
-class SpdyStream;
-class HttpNetworkSession;
+// This is somewhat arbitrary and not really fixed, but it will always work
+// reasonably with ethernet. Chop the world into 2-packet chunks. This is
+// somewhat arbitrary, but is reasonably small and ensures that we elicit
+// ACKs quickly from TCP (because TCP tries to only ACK every other packet).
+const int kMss = 1430;
+const int kMaxSpdyFrameChunkSize = (2 * kMss) - spdy::SpdyFrame::size();
+
class BoundNetLog;
+class SpdySettingsStorage;
+class SpdyStream;
class SSLInfo;
class SpdySession : public base::RefCounted<SpdySession>,
public spdy::SpdyFramerVisitorInterface {
public:
// Create a new SpdySession.
- // |host_port_pair| is the host/port that this session connects to.
+ // |host_port_proxy_pair| is the host/port that this session connects to, and
+ // the proxy configuration settings that it's using.
// |session| is the HttpNetworkSession. |net_log| is the NetLog that we log
// network events to.
- SpdySession(const HostPortPair& host_port_pair, HttpNetworkSession* session,
+ SpdySession(const HostPortProxyPair& host_port_proxy_pair,
+ SpdySessionPool* spdy_session_pool,
+ SpdySettingsStorage* spdy_settings,
NetLog* net_log);
- const HostPortPair& host_port_pair() const { return host_port_pair_; }
-
- // Connect the Spdy Socket.
- // Returns net::Error::OK on success.
- // Note that this call does not wait for the connect to complete. Callers can
- // immediately start using the SpdySession while it connects.
- net::Error Connect(const std::string& group_name,
- const scoped_refptr<TCPSocketParams>& destination,
- RequestPriority priority);
+ const HostPortPair& host_port_pair() const {
+ return host_port_proxy_pair_.first;
+ }
+ const HostPortProxyPair& host_port_proxy_pair() const {
+ return host_port_proxy_pair_;
+ }
// Get a pushed stream for a given |url|.
// If the server initiates a stream, it might already exist for a given path.
@@ -78,10 +87,13 @@ class SpdySession : public base::RefCounted<SpdySession>,
// Remove PendingCreateStream objects on transaction deletion
void CancelPendingCreateStreams(const scoped_refptr<SpdyStream>* spdy_stream);
- // Used by SpdySessionPool to initialize with a pre-existing SSL socket.
+ // Used by SpdySessionPool to initialize with a pre-existing SSL socket. For
+ // testing, setting is_secure to false allows initialization with a
+ // pre-existing TCP socket.
// Returns OK on success, or an error on failure.
- net::Error InitializeWithSSLSocket(ClientSocketHandle* connection,
- int certificate_error_code);
+ net::Error InitializeWithSocket(ClientSocketHandle* connection,
+ bool is_secure,
+ int certificate_error_code);
// Send the SYN frame for |stream_id|.
int WriteSynStream(
@@ -114,10 +126,22 @@ class SpdySession : public base::RefCounted<SpdySession>,
// Fills SSL info in |ssl_info| and returns true when SSL is in use.
bool GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated);
+ // Fills SSL Certificate Request info |cert_request_info| and returns
+ // true when SSL is in use.
+ bool GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
+
// Enable or disable SSL.
static void SetSSLMode(bool enable) { use_ssl_ = enable; }
static bool SSLMode() { return use_ssl_; }
+ // Enable or disable flow control.
+ static void set_flow_control(bool enable) { use_flow_control_ = enable; }
+ static bool flow_control() { return use_flow_control_; }
+
+ // Send WINDOW_UPDATE frame, called by a stream whenever receive window
+ // size is increased.
+ void SendWindowUpdate(spdy::SpdyStreamId stream_id, int delta_window_size);
+
// If session is closed, no new streams/transactions should be created.
bool IsClosed() const { return state_ == CLOSED; }
@@ -125,11 +149,30 @@ class SpdySession : public base::RefCounted<SpdySession>,
// the session as permanently closed.
// |err| should not be OK; this function is intended to be called on
// error.
- void CloseSessionOnError(net::Error err);
+ // |remove_from_pool| indicates whether to also remove the session from the
+ // session pool.
+ void CloseSessionOnError(net::Error err, bool remove_from_pool);
+
+ // Indicates whether the session is being reused after having successfully
+ // used to send/receive data in the past.
+ bool IsReused() const {
+ return frames_received_ > 0;
+ }
+
+ void set_in_session_pool(bool val) { in_session_pool_ = val; }
+
+ // Access to the number of active and pending streams. These are primarily
+ // available for testing and diagnostics.
+ size_t num_active_streams() const { return active_streams_.size(); }
+ size_t num_unclaimed_pushed_streams() const {
+ return unclaimed_pushed_streams_.size();
+ }
+
+ const BoundNetLog& net_log() const { return net_log_; }
private:
friend class base::RefCounted<SpdySession>;
- FRIEND_TEST(SpdySessionTest, GetActivePushStream);
+ FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, GetActivePushStream);
enum State {
IDLE,
@@ -158,8 +201,7 @@ class SpdySession : public base::RefCounted<SpdySession>,
PendingCreateStreamQueue;
typedef std::map<int, scoped_refptr<SpdyStream> > ActiveStreamMap;
// Only HTTP push a stream.
- typedef std::list<scoped_refptr<SpdyStream> > ActivePushedStreamList;
- typedef std::map<std::string, scoped_refptr<SpdyStream> > PendingStreamMap;
+ typedef std::map<std::string, scoped_refptr<SpdyStream> > PushedStreamMap;
typedef std::priority_queue<SpdyIOBuffer> OutputQueue;
virtual ~SpdySession();
@@ -183,14 +225,12 @@ class SpdySession : public base::RefCounted<SpdySession>,
const linked_ptr<spdy::SpdyHeaderBlock>& headers);
void OnSynReply(const spdy::SpdySynReplyControlFrame& frame,
const linked_ptr<spdy::SpdyHeaderBlock>& headers);
- void OnFin(const spdy::SpdyRstStreamControlFrame& frame);
+ void OnRst(const spdy::SpdyRstStreamControlFrame& frame);
void OnGoAway(const spdy::SpdyGoAwayControlFrame& frame);
void OnSettings(const spdy::SpdySettingsControlFrame& frame);
void OnWindowUpdate(const spdy::SpdyWindowUpdateControlFrame& frame);
// IO Callbacks
- void OnTCPConnect(int result);
- void OnSSLConnect(int result);
void OnReadComplete(int result);
void OnWriteComplete(int result);
@@ -242,17 +282,20 @@ class SpdySession : public base::RefCounted<SpdySession>,
void CloseAllStreams(net::Error status);
// Callbacks for the Spdy session.
- CompletionCallbackImpl<SpdySession> connect_callback_;
- CompletionCallbackImpl<SpdySession> ssl_connect_callback_;
CompletionCallbackImpl<SpdySession> read_callback_;
CompletionCallbackImpl<SpdySession> write_callback_;
- // The domain this session is connected to.
- const HostPortPair host_port_pair_;
+ // Used for posting asynchronous IO tasks. We use this even though
+ // SpdySession is refcounted because we don't need to keep the SpdySession
+ // alive if the last reference is within a RunnableMethod. Just revoke the
+ // method.
+ ScopedRunnableMethodFactory<SpdySession> method_factory_;
- SSLConfig ssl_config_;
+ // The domain this session is connected to.
+ const HostPortProxyPair host_port_proxy_pair_;
- scoped_refptr<HttpNetworkSession> session_;
+ scoped_refptr<SpdySessionPool> spdy_session_pool_;
+ SpdySettingsStorage* spdy_settings_;
// The socket handle for this session.
scoped_ptr<ClientSocketHandle> connection_;
@@ -267,10 +310,6 @@ class SpdySession : public base::RefCounted<SpdySession>,
// yet been satisfied
PendingCreateStreamQueue create_stream_queues_[NUM_PRIORITIES];
- // TODO(mbelshe): We need to track these stream lists better.
- // I suspect it is possible to remove a stream from
- // one list, but not the other.
-
// Map from stream id to all active streams. Streams are active in the sense
// that they have a consumer (typically SpdyNetworkTransaction and regardless
// of whether or not there is currently any ongoing IO [might be waiting for
@@ -280,13 +319,9 @@ class SpdySession : public base::RefCounted<SpdySession>,
// them into a separate ActiveStreamMap, and not deliver network events to
// them?
ActiveStreamMap active_streams_;
- // List of all the streams that have already started to be pushed by the
+ // Map of all the streams that have already started to be pushed by the
// server, but do not have consumers yet.
- ActivePushedStreamList pushed_streams_;
- // List of streams declared in X-Associated-Content headers, but do not have
- // consumers yet.
- // The key is a string representing the path of the URI being pushed.
- PendingStreamMap pending_streams_;
+ PushedStreamMap unclaimed_pushed_streams_;
// As we gather data to be sent, we put it into the output queue.
OutputQueue queue_;
@@ -321,20 +356,28 @@ class SpdySession : public base::RefCounted<SpdySession>,
int streams_pushed_count_;
int streams_pushed_and_claimed_count_;
int streams_abandoned_count_;
+ int frames_received_;
bool sent_settings_; // Did this session send settings when it started.
bool received_settings_; // Did this session receive at least one settings
// frame.
bool in_session_pool_; // True if the session is currently in the pool.
- int initial_window_size_; // Initial window size for the session; can be
- // changed by an arriving SETTINGS frame; newly
- // created streams use this value for the initial
- // window size.
+ // Initial send window size for the session; can be changed by an
+ // arriving SETTINGS frame; newly created streams use this value for the
+ // initial send window size.
+ int initial_send_window_size_;
+
+ // Initial receive window size for the session; there are plans to add a
+ // command line switch that would cause a SETTINGS frame with window size
+ // announcement to be sent on startup; newly created streams will use
+ // this value for the initial receive window size.
+ int initial_recv_window_size_;
BoundNetLog net_log_;
static bool use_ssl_;
+ static bool use_flow_control_;
};
} // namespace net
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index 8caa040..6c4ad52 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -5,6 +5,7 @@
#include "net/spdy/spdy_session_pool.h"
#include "base/logging.h"
+#include "net/http/http_network_session.h"
#include "net/spdy/spdy_session.h"
namespace net {
@@ -14,33 +15,47 @@ static const size_t kMaxSessionsPerDomain = 1;
int SpdySessionPool::g_max_sessions_per_domain = kMaxSessionsPerDomain;
-SpdySessionPool::SpdySessionPool() {
+SpdySessionPool::SpdySessionPool(SSLConfigService* ssl_config_service)
+ : ssl_config_service_(ssl_config_service) {
NetworkChangeNotifier::AddObserver(this);
+ if (ssl_config_service_)
+ ssl_config_service_->AddObserver(this);
}
SpdySessionPool::~SpdySessionPool() {
CloseAllSessions();
+ if (ssl_config_service_)
+ ssl_config_service_->RemoveObserver(this);
NetworkChangeNotifier::RemoveObserver(this);
}
scoped_refptr<SpdySession> SpdySessionPool::Get(
- const HostPortPair& host_port_pair, HttpNetworkSession* session,
+ const HostPortProxyPair& host_port_proxy_pair,
+ SpdySettingsStorage* spdy_settings,
const BoundNetLog& net_log) {
scoped_refptr<SpdySession> spdy_session;
- SpdySessionList* list = GetSessionList(host_port_pair);
+ SpdySessionList* list = GetSessionList(host_port_proxy_pair);
if (list) {
if (list->size() >= static_cast<unsigned int>(g_max_sessions_per_domain)) {
spdy_session = list->front();
list->pop_front();
+ net_log.AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_FOUND_EXISTING_SESSION,
+ new NetLogSourceParameter("session",
+ spdy_session->net_log().source()));
}
} else {
- list = AddSessionList(host_port_pair);
+ list = AddSessionList(host_port_proxy_pair);
}
DCHECK(list);
- if (!spdy_session)
- spdy_session = new SpdySession(host_port_pair, session, net_log.net_log());
+ if (!spdy_session) {
+ spdy_session = new SpdySession(host_port_proxy_pair, this, spdy_settings,
+ net_log.net_log());
+ net_log.AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_CREATED_NEW_SESSION,
+ new NetLogSourceParameter("session",
+ spdy_session->net_log().source()));
+ }
DCHECK(spdy_session);
list->push_back(spdy_session);
@@ -48,99 +63,133 @@ scoped_refptr<SpdySession> SpdySessionPool::Get(
return spdy_session;
}
-net::Error SpdySessionPool::GetSpdySessionFromSSLSocket(
- const HostPortPair& host_port_pair,
- HttpNetworkSession* session,
+net::Error SpdySessionPool::GetSpdySessionFromSocket(
+ const HostPortProxyPair& host_port_proxy_pair,
+ SpdySettingsStorage* spdy_settings,
ClientSocketHandle* connection,
const BoundNetLog& net_log,
int certificate_error_code,
- scoped_refptr<SpdySession>* spdy_session) {
+ scoped_refptr<SpdySession>* spdy_session,
+ bool is_secure) {
// Create the SPDY session and add it to the pool.
- *spdy_session = new SpdySession(host_port_pair, session, net_log.net_log());
- SpdySessionList* list = GetSessionList(host_port_pair);
+ *spdy_session = new SpdySession(host_port_proxy_pair, this, spdy_settings,
+ net_log.net_log());
+ SpdySessionList* list = GetSessionList(host_port_proxy_pair);
if (!list)
- list = AddSessionList(host_port_pair);
+ list = AddSessionList(host_port_proxy_pair);
DCHECK(list->empty());
list->push_back(*spdy_session);
+ net_log.AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET,
+ new NetLogSourceParameter("session",
+ (*spdy_session)->net_log().source()));
+
// Now we can initialize the session with the SSL socket.
- return (*spdy_session)->InitializeWithSSLSocket(connection,
- certificate_error_code);
+ return (*spdy_session)->InitializeWithSocket(connection, is_secure,
+ certificate_error_code);
}
-bool SpdySessionPool::HasSession(const HostPortPair& host_port_pair) const {
- if (GetSessionList(host_port_pair))
+bool SpdySessionPool::HasSession(
+ const HostPortProxyPair& host_port_proxy_pair) const {
+ if (GetSessionList(host_port_proxy_pair))
return true;
return false;
}
void SpdySessionPool::Remove(const scoped_refptr<SpdySession>& session) {
- SpdySessionList* list = GetSessionList(session->host_port_pair());
+ SpdySessionList* list = GetSessionList(session->host_port_proxy_pair());
DCHECK(list); // We really shouldn't remove if we've already been removed.
if (!list)
return;
list->remove(session);
+ session->net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_POOL_REMOVE_SESSION,
+ new NetLogSourceParameter("session",
+ session->net_log().source()));
if (list->empty())
- RemoveSessionList(session->host_port_pair());
+ RemoveSessionList(session->host_port_proxy_pair());
}
void SpdySessionPool::OnIPAddressChanged() {
- ClearSessions();
+ CloseCurrentSessions();
+}
+
+void SpdySessionPool::OnSSLConfigChanged() {
+ CloseCurrentSessions();
}
SpdySessionPool::SpdySessionList*
- SpdySessionPool::AddSessionList(const HostPortPair& host_port_pair) {
- DCHECK(sessions_.find(host_port_pair) == sessions_.end());
+ SpdySessionPool::AddSessionList(
+ const HostPortProxyPair& host_port_proxy_pair) {
+ DCHECK(sessions_.find(host_port_proxy_pair) == sessions_.end());
SpdySessionPool::SpdySessionList* list = new SpdySessionList();
- sessions_[host_port_pair] = list;
+ sessions_[host_port_proxy_pair] = list;
return list;
}
SpdySessionPool::SpdySessionList*
- SpdySessionPool::GetSessionList(const HostPortPair& host_port_pair) {
- SpdySessionsMap::iterator it = sessions_.find(host_port_pair);
+ SpdySessionPool::GetSessionList(
+ const HostPortProxyPair& host_port_proxy_pair) {
+ SpdySessionsMap::iterator it = sessions_.find(host_port_proxy_pair);
if (it == sessions_.end())
return NULL;
return it->second;
}
const SpdySessionPool::SpdySessionList*
- SpdySessionPool::GetSessionList(const HostPortPair& host_port_pair) const {
- SpdySessionsMap::const_iterator it = sessions_.find(host_port_pair);
+ SpdySessionPool::GetSessionList(
+ const HostPortProxyPair& host_port_proxy_pair) const {
+ SpdySessionsMap::const_iterator it = sessions_.find(host_port_proxy_pair);
if (it == sessions_.end())
return NULL;
return it->second;
}
-void SpdySessionPool::RemoveSessionList(const HostPortPair& host_port_pair) {
- SpdySessionList* list = GetSessionList(host_port_pair);
+void SpdySessionPool::RemoveSessionList(
+ const HostPortProxyPair& host_port_proxy_pair) {
+ SpdySessionList* list = GetSessionList(host_port_proxy_pair);
if (list) {
delete list;
- sessions_.erase(host_port_pair);
+ sessions_.erase(host_port_proxy_pair);
} else {
DCHECK(false) << "removing orphaned session list";
}
}
-void SpdySessionPool::ClearSessions() {
+void SpdySessionPool::CloseAllSessions() {
while (!sessions_.empty()) {
SpdySessionList* list = sessions_.begin()->second;
- DCHECK(list);
- sessions_.erase(sessions_.begin()->first);
- while (list->size()) {
- list->pop_front();
- }
- delete list;
+ CHECK(list);
+ const scoped_refptr<SpdySession>& session = list->front();
+ CHECK(session);
+ // This call takes care of removing the session from the pool, as well as
+ // removing the session list if the list is empty.
+ session->CloseSessionOnError(net::ERR_ABORTED, true);
}
}
-void SpdySessionPool::CloseAllSessions() {
- while (!sessions_.empty()) {
- SpdySessionList* list = sessions_.begin()->second;
- DCHECK(list);
+void SpdySessionPool::CloseCurrentSessions() {
+ SpdySessionsMap old_map;
+ old_map.swap(sessions_);
+ for (SpdySessionsMap::const_iterator it = old_map.begin();
+ it != old_map.end(); ++it) {
+ SpdySessionList* list = it->second;
+ CHECK(list);
const scoped_refptr<SpdySession>& session = list->front();
- DCHECK(session);
- session->CloseSessionOnError(net::ERR_ABORTED);
+ CHECK(session);
+ session->set_in_session_pool(false);
+ }
+
+ while (!old_map.empty()) {
+ SpdySessionList* list = old_map.begin()->second;
+ CHECK(list);
+ const scoped_refptr<SpdySession>& session = list->front();
+ CHECK(session);
+ session->CloseSessionOnError(net::ERR_ABORTED, false);
+ list->pop_front();
+ if (list->empty()) {
+ delete list;
+ old_map.erase(old_map.begin()->first);
+ }
}
}
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 1004169..7dc5f27 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -4,38 +4,48 @@
#ifndef NET_SPDY_SPDY_SESSION_POOL_H_
#define NET_SPDY_SPDY_SESSION_POOL_H_
+#pragma once
#include <map>
#include <list>
#include <string>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/base/network_change_notifier.h"
-#include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST
+#include "net/base/ssl_config_service.h"
+#include "net/proxy/proxy_config.h"
+#include "net/proxy/proxy_server.h"
namespace net {
+// Sessions are uniquely identified by their HostPortPair and the proxy server
+// that will be used to connect to it (may be DIRECT).
+typedef std::pair<HostPortPair, ProxyServer> HostPortProxyPair;
class BoundNetLog;
class ClientSocketHandle;
class HttpNetworkSession;
class SpdySession;
+class SpdySettingsStorage;
// This is a very simple pool for open SpdySessions.
// TODO(mbelshe): Make this production ready.
class SpdySessionPool
: public base::RefCounted<SpdySessionPool>,
- public NetworkChangeNotifier::Observer {
+ public NetworkChangeNotifier::Observer,
+ public SSLConfigService::Observer {
public:
- SpdySessionPool();
+ explicit SpdySessionPool(SSLConfigService* ssl_config_service);
// Either returns an existing SpdySession or creates a new SpdySession for
// use.
scoped_refptr<SpdySession> Get(
- const HostPortPair& host_port_pair, HttpNetworkSession* session,
+ const HostPortProxyPair& host_port_proxy_pair,
+ SpdySettingsStorage* spdy_settings,
const BoundNetLog& net_log);
// Set the maximum concurrent sessions per domain.
@@ -50,24 +60,32 @@ class SpdySessionPool
// transferred from the caller to the SpdySession.
// |certificate_error_code| is used to indicate the certificate error
// encountered when connecting the SSL socket. OK means there was no error.
+ // For testing, setting is_secure to false allows Spdy to connect with a
+ // pre-existing TCP socket.
// Returns OK on success, and the |spdy_session| will be provided.
// Returns an error on failure, and |spdy_session| will be NULL.
- net::Error GetSpdySessionFromSSLSocket(
- const HostPortPair& host_port_pair,
- HttpNetworkSession* session,
+ net::Error GetSpdySessionFromSocket(
+ const HostPortProxyPair& host_port_proxy_pair,
+ SpdySettingsStorage* spdy_settings,
ClientSocketHandle* connection,
const BoundNetLog& net_log,
int certificate_error_code,
- scoped_refptr<SpdySession>* spdy_session);
+ scoped_refptr<SpdySession>* spdy_session,
+ bool is_secure);
// TODO(willchan): Consider renaming to HasReusableSession, since perhaps we
// should be creating a new session.
- bool HasSession(const HostPortPair& host_port_pair)const;
+ bool HasSession(const HostPortProxyPair& host_port_proxy_pair) const;
- // Close all Spdy Sessions; used for debugging.
+ // Close all SpdySessions, including any new ones created in the process of
+ // closing the current ones.
void CloseAllSessions();
+ // Close only the currently existing SpdySessions. Let any new ones created
+ // continue to live.
+ void CloseCurrentSessions();
- // Removes a SpdySession from the SpdySessionPool.
+ // Removes a SpdySession from the SpdySessionPool. This should only be called
+ // by SpdySession, because otherwise session->state_ is not set to CLOSED.
void Remove(const scoped_refptr<SpdySession>& session);
// NetworkChangeNotifier::Observer methods:
@@ -77,34 +95,38 @@ class SpdySessionPool
// or error out due to the IP address change.
virtual void OnIPAddressChanged();
+ // SSLConfigService::Observer methods:
+
+ // We perform the same flushing as described above when SSL settings change.
+ virtual void OnSSLConfigChanged();
+
private:
friend class base::RefCounted<SpdySessionPool>;
friend class SpdySessionPoolPeer; // For testing.
friend class SpdyNetworkTransactionTest; // For testing.
- FRIEND_TEST(SpdyNetworkTransactionTest, WindowUpdateOverflow);
+ FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest, WindowUpdateOverflow);
typedef std::list<scoped_refptr<SpdySession> > SpdySessionList;
- typedef std::map<HostPortPair, SpdySessionList*> SpdySessionsMap;
+ typedef std::map<HostPortProxyPair, SpdySessionList*> SpdySessionsMap;
virtual ~SpdySessionPool();
// Helper functions for manipulating the lists.
- SpdySessionList* AddSessionList(const HostPortPair& host_port_pair);
- SpdySessionList* GetSessionList(const HostPortPair& host_port_pair);
+ SpdySessionList* AddSessionList(
+ const HostPortProxyPair& host_port_proxy_pair);
+ SpdySessionList* GetSessionList(
+ const HostPortProxyPair& host_port_proxy_pair);
const SpdySessionList* GetSessionList(
- const HostPortPair& host_port_pair) const;
- void RemoveSessionList(const HostPortPair& host_port_pair);
- // Releases the SpdySessionPool reference to all sessions. Will result in all
- // idle sessions being deleted, and the active sessions from being reused, so
- // they will be deleted once all active streams belonging to that session go
- // away.
- void ClearSessions();
+ const HostPortProxyPair& host_port_proxy_pair) const;
+ void RemoveSessionList(const HostPortProxyPair& host_port_proxy_pair);
// This is our weak session pool - one session per domain.
SpdySessionsMap sessions_;
static int g_max_sessions_per_domain;
+ const scoped_refptr<SSLConfigService> ssl_config_service_;
+
DISALLOW_COPY_AND_ASSIGN(SpdySessionPool);
};
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index c012347..d39a09e 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -69,41 +69,44 @@ TEST_F(SpdySessionTest, GoAway) {
};
StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
data.set_connect_data(connect_data);
- session_deps.socket_factory.AddSocketDataProvider(&data);
+ session_deps.socket_factory->AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(false, OK);
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
+ session_deps.socket_factory->AddSSLSocketDataProvider(&ssl);
scoped_refptr<HttpNetworkSession> http_session(
SpdySessionDependencies::SpdyCreateSession(&session_deps));
const std::string kTestHost("www.foo.com");
const int kTestPort = 80;
- HostPortPair test_host_port_pair;
- test_host_port_pair.host = kTestHost;
- test_host_port_pair.port = kTestPort;
+ HostPortPair test_host_port_pair(kTestHost, kTestPort);
+ HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct());
scoped_refptr<SpdySessionPool> spdy_session_pool(
http_session->spdy_session_pool());
- EXPECT_FALSE(spdy_session_pool->HasSession(test_host_port_pair));
+ EXPECT_FALSE(spdy_session_pool->HasSession(pair));
scoped_refptr<SpdySession> session =
- spdy_session_pool->Get(
- test_host_port_pair, http_session.get(), BoundNetLog());
- EXPECT_TRUE(spdy_session_pool->HasSession(test_host_port_pair));
+ spdy_session_pool->Get(pair, http_session->mutable_spdy_settings(),
+ BoundNetLog());
+ EXPECT_TRUE(spdy_session_pool->HasSession(pair));
scoped_refptr<TCPSocketParams> tcp_params =
new TCPSocketParams(kTestHost, kTestPort, MEDIUM, GURL(), false);
- int rv = session->Connect(kTestHost, tcp_params, MEDIUM);
- ASSERT_EQ(OK, rv);
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+ EXPECT_EQ(OK,
+ connection->Init(test_host_port_pair.ToString(), tcp_params, MEDIUM,
+ NULL, http_session->tcp_socket_pool(),
+ BoundNetLog()));
+ EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK));
// Flush the SpdySession::OnReadComplete() task.
MessageLoop::current()->RunAllPending();
- EXPECT_FALSE(spdy_session_pool->HasSession(test_host_port_pair));
+ EXPECT_FALSE(spdy_session_pool->HasSession(pair));
scoped_refptr<SpdySession> session2 =
- spdy_session_pool->Get(
- test_host_port_pair, http_session.get(), BoundNetLog());
+ spdy_session_pool->Get(pair, http_session->mutable_spdy_settings(),
+ BoundNetLog());
// Delete the first session.
session = NULL;
@@ -114,84 +117,4 @@ TEST_F(SpdySessionTest, GoAway) {
}
} // namespace
-
-TEST_F(SpdySessionTest, GetActivePushStream) {
- spdy::SpdyFramer framer;
- SpdySessionTest::TurnOffCompression();
-
- SpdySessionDependencies session_deps;
- session_deps.host_resolver->set_synchronous_mode(true);
-
- MockConnect connect_data(false, OK);
- spdy::SpdyHeaderBlock headers;
- headers["path"] = "/foo.js";
- headers["status"] = "200";
- headers["version"] = "HTTP/1.1";
- scoped_ptr<spdy::SpdyFrame> push_syn(framer.CreateSynStream(
- 2, 1, 0, spdy::CONTROL_FLAG_NONE, false, &headers));
- MockRead reads[] = {
- CreateMockRead(*push_syn),
- MockRead(true, ERR_IO_PENDING, 0) // EOF
- };
- StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
- data.set_connect_data(connect_data);
- session_deps.socket_factory.AddSocketDataProvider(&data);
-
- SSLSocketDataProvider ssl(false, OK);
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl);
-
- scoped_refptr<HttpNetworkSession> http_session(
- SpdySessionDependencies::SpdyCreateSession(&session_deps));
-
- const std::string kTestHost("www.foo.com");
- const int kTestPort = 80;
- HostPortPair test_host_port_pair;
- test_host_port_pair.host = kTestHost;
- test_host_port_pair.port = kTestPort;
-
- scoped_refptr<SpdySessionPool> spdy_session_pool(
- http_session->spdy_session_pool());
- EXPECT_FALSE(spdy_session_pool->HasSession(test_host_port_pair));
- scoped_refptr<SpdySession> session =
- spdy_session_pool->Get(
- test_host_port_pair, http_session.get(), BoundNetLog());
- EXPECT_TRUE(spdy_session_pool->HasSession(test_host_port_pair));
-
- // No push streams should exist in the beginning.
- std::string test_push_path = "/foo.js";
- scoped_refptr<SpdyStream> first_stream = session->GetActivePushStream(
- test_push_path);
- EXPECT_EQ(static_cast<SpdyStream*>(NULL), first_stream.get());
-
- // Read in the data which contains a server-issued SYN_STREAM.
- scoped_refptr<TCPSocketParams> tcp_params =
- new TCPSocketParams(test_host_port_pair, MEDIUM, GURL(), false);
- int rv = session->Connect(kTestHost, tcp_params, MEDIUM);
- ASSERT_EQ(OK, rv);
- MessageLoop::current()->RunAllPending();
-
- // An unpushed path should not work.
- scoped_refptr<SpdyStream> unpushed_stream = session->GetActivePushStream(
- "/unpushed_path");
- EXPECT_EQ(static_cast<SpdyStream*>(NULL), unpushed_stream.get());
-
- // The pushed path should be found.
- scoped_refptr<SpdyStream> second_stream = session->GetActivePushStream(
- test_push_path);
- ASSERT_NE(static_cast<SpdyStream*>(NULL), second_stream.get());
- EXPECT_EQ(test_push_path, second_stream->path());
- EXPECT_EQ(2U, second_stream->stream_id());
- EXPECT_EQ(0, second_stream->priority());
-
- // Clean up
- second_stream = NULL;
- session = NULL;
- spdy_session_pool->CloseAllSessions();
-
- // RunAllPending needs to be called here because the
- // ClientSocketPoolBase posts a task to clean up and destroy the
- // underlying socket.
- MessageLoop::current()->RunAllPending();
-}
-
} // namespace net
diff --git a/net/spdy/spdy_settings_storage.cc b/net/spdy/spdy_settings_storage.cc
index 32069b7..dc9bdcd 100644
--- a/net/spdy/spdy_settings_storage.cc
+++ b/net/spdy/spdy_settings_storage.cc
@@ -11,6 +11,9 @@ namespace net {
SpdySettingsStorage::SpdySettingsStorage() {
}
+SpdySettingsStorage::~SpdySettingsStorage() {
+}
+
const spdy::SpdySettings& SpdySettingsStorage::Get(
const HostPortPair& host_port_pair) const {
SettingsMap::const_iterator it = settings_map_.find(host_port_pair);
diff --git a/net/spdy/spdy_settings_storage.h b/net/spdy/spdy_settings_storage.h
index 93b44dc..999f016 100644
--- a/net/spdy/spdy_settings_storage.h
+++ b/net/spdy/spdy_settings_storage.h
@@ -4,6 +4,7 @@
#ifndef NET_SPDY_SPDY_SETTING_STORAGE_H_
#define NET_SPDY_SPDY_SETTING_STORAGE_H_
+#pragma once
#include <map>
#include "base/basictypes.h"
@@ -17,6 +18,7 @@ namespace net {
class SpdySettingsStorage {
public:
SpdySettingsStorage();
+ ~SpdySettingsStorage();
// Get a copy of the SpdySettings stored for a host.
// If no settings are stored, returns an empty set of settings.
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index a5f9d1f..88b009d 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -7,58 +7,110 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/singleton.h"
+#include "base/values.h"
#include "net/spdy/spdy_session.h"
namespace net {
-SpdyStream::SpdyStream(
- SpdySession* session, spdy::SpdyStreamId stream_id, bool pushed)
- : stream_id_(stream_id),
+namespace {
+
+class NetLogSpdyStreamWindowUpdateParameter : public NetLog::EventParameters {
+ public:
+ NetLogSpdyStreamWindowUpdateParameter(spdy::SpdyStreamId stream_id,
+ int delta,
+ int window_size)
+ : stream_id_(stream_id), delta_(delta), window_size_(window_size) {}
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("id", static_cast<int>(stream_id_));
+ dict->SetInteger("delta", delta_);
+ dict->SetInteger("window_size", window_size_);
+ return dict;
+ }
+ private:
+ const spdy::SpdyStreamId stream_id_;
+ const int delta_;
+ const int window_size_;
+ DISALLOW_COPY_AND_ASSIGN(NetLogSpdyStreamWindowUpdateParameter);
+};
+
+}
+
+SpdyStream::SpdyStream(SpdySession* session,
+ spdy::SpdyStreamId stream_id,
+ bool pushed,
+ const BoundNetLog& net_log)
+ : continue_buffering_data_(true),
+ stream_id_(stream_id),
priority_(0),
+ stalled_by_flow_control_(false),
+ send_window_size_(spdy::kInitialWindowSize),
+ recv_window_size_(spdy::kInitialWindowSize),
pushed_(pushed),
metrics_(Singleton<BandwidthMetrics>::get()),
- syn_reply_received_(false),
+ response_received_(false),
session_(session),
delegate_(NULL),
request_time_(base::Time::Now()),
response_(new spdy::SpdyHeaderBlock),
- response_complete_(false),
io_state_(STATE_NONE),
response_status_(OK),
cancelled_(false),
+ has_upload_data_(false),
+ net_log_(net_log),
send_bytes_(0),
- recv_bytes_(0),
- histograms_recorded_(false) {}
+ recv_bytes_(0) {
+ net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM,
+ new NetLogIntegerParameter("stream_id", stream_id_));
+}
SpdyStream::~SpdyStream() {
- DLOG(INFO) << "Deleting SpdyStream for stream " << stream_id_;
-
- // When the stream_id_ is 0, we expect that it is because
- // we've cancelled or closed the stream and set the stream_id to 0.
- if (!stream_id_)
- DCHECK(response_complete_);
+ UpdateHistograms();
+ net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM, NULL);
}
void SpdyStream::SetDelegate(Delegate* delegate) {
CHECK(delegate);
delegate_ = delegate;
- if (!response_->empty()) {
- // The stream already got response.
- delegate_->OnResponseReceived(*response_, response_time_, OK);
+ if (pushed_) {
+ CHECK(response_received());
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this,
+ &SpdyStream::PushedStreamReplayData));
+ } else {
+ continue_buffering_data_ = false;
}
+}
+
+void SpdyStream::PushedStreamReplayData() {
+ if (cancelled_ || !delegate_)
+ return;
+
+ delegate_->OnResponseReceived(*response_, response_time_, OK);
+ continue_buffering_data_ = false;
std::vector<scoped_refptr<IOBufferWithSize> > buffers;
buffers.swap(pending_buffers_);
for (size_t i = 0; i < buffers.size(); ++i) {
- if (delegate_)
+ // It is always possible that a callback to the delegate results in
+ // the delegate no longer being available.
+ if (!delegate_)
+ break;
+ if (buffers[i]) {
delegate_->OnDataReceived(buffers[i]->data(), buffers[i]->size());
+ } else {
+ delegate_->OnDataReceived(NULL, 0);
+ session_->CloseStream(stream_id_, net::OK);
+ // Note: |this| may be deleted after calling CloseStream.
+ DCHECK_EQ(buffers.size() - 1, i);
+ }
}
}
void SpdyStream::DetachDelegate() {
delegate_ = NULL;
- if (!cancelled())
+ if (!closed())
Cancel();
}
@@ -71,25 +123,89 @@ void SpdyStream::set_spdy_headers(
request_ = headers;
}
-void SpdyStream::UpdateWindowSize(int delta_window_size) {
+void SpdyStream::IncreaseSendWindowSize(int delta_window_size) {
DCHECK_GE(delta_window_size, 1);
- int new_window_size = window_size_ + delta_window_size;
-
- // it's valid for window_size_ to become negative (via an incoming
- // SETTINGS frame which is handled in SpdySession::OnSettings), in which
- // case incoming WINDOW_UPDATEs will eventually make it positive;
- // however, if window_size_ is positive and incoming WINDOW_UPDATE makes
- // it negative, we have an overflow.
- if (window_size_ > 0 && new_window_size < 0) {
+ int new_window_size = send_window_size_ + delta_window_size;
+
+ // We should ignore WINDOW_UPDATEs received before or after this state,
+ // since before means we've not written SYN_STREAM yet (i.e. it's too
+ // early) and after means we've written a DATA frame with FIN bit.
+ if (io_state_ != STATE_SEND_BODY_COMPLETE)
+ return;
+
+ // it's valid for send_window_size_ to become negative (via an incoming
+ // SETTINGS), in which case incoming WINDOW_UPDATEs will eventually make
+ // it positive; however, if send_window_size_ is positive and incoming
+ // WINDOW_UPDATE makes it negative, we have an overflow.
+ if (send_window_size_ > 0 && new_window_size < 0) {
LOG(WARNING) << "Received WINDOW_UPDATE [delta:" << delta_window_size
<< "] for stream " << stream_id_
- << " overflows window size [current:" << window_size_ << "]";
+ << " overflows send_window_size_ [current:"
+ << send_window_size_ << "]";
session_->ResetStream(stream_id_, spdy::FLOW_CONTROL_ERROR);
return;
}
- window_size_ = new_window_size;
+
+ send_window_size_ = new_window_size;
+
+ net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE,
+ new NetLogSpdyStreamWindowUpdateParameter(stream_id_,
+ delta_window_size, send_window_size_));
+ if (stalled_by_flow_control_) {
+ stalled_by_flow_control_ = false;
+ io_state_ = STATE_SEND_BODY;
+ DoLoop(OK);
+ }
+}
+
+void SpdyStream::DecreaseSendWindowSize(int delta_window_size) {
+ // we only call this method when sending a frame, therefore
+ // |delta_window_size| should be within the valid frame size range.
+ DCHECK_GE(delta_window_size, 1);
+ DCHECK_LE(delta_window_size, kMaxSpdyFrameChunkSize);
+
+ // |send_window_size_| should have been at least |delta_window_size| for
+ // this call to happen.
+ DCHECK_GE(send_window_size_, delta_window_size);
+
+ send_window_size_ -= delta_window_size;
+
+ net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE,
+ new NetLogSpdyStreamWindowUpdateParameter(stream_id_,
+ -delta_window_size, send_window_size_));
+}
+
+void SpdyStream::IncreaseRecvWindowSize(int delta_window_size) {
+ DCHECK_GE(delta_window_size, 1);
+ // By the time a read is isued, stream may become inactive.
+ if (!session_->IsStreamActive(stream_id_))
+ return;
+ int new_window_size = recv_window_size_ + delta_window_size;
+ if (recv_window_size_ > 0)
+ DCHECK(new_window_size > 0);
+
+ recv_window_size_ = new_window_size;
+ net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE,
+ new NetLogSpdyStreamWindowUpdateParameter(stream_id_,
+ delta_window_size, recv_window_size_));
+ session_->SendWindowUpdate(stream_id_, delta_window_size);
}
+void SpdyStream::DecreaseRecvWindowSize(int delta_window_size) {
+ DCHECK_GE(delta_window_size, 1);
+
+ recv_window_size_ -= delta_window_size;
+ net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE,
+ new NetLogSpdyStreamWindowUpdateParameter(stream_id_,
+ -delta_window_size, recv_window_size_));
+
+ // Since we never decrease the initial window size, we should never hit
+ // a negative |recv_window_size_|, if we do, it's a flow-control violation.
+ if (recv_window_size_ < 0)
+ session_->ResetStream(stream_id_, spdy::FLOW_CONTROL_ERROR);
+}
+
+
base::Time SpdyStream::GetRequestTime() const {
return request_time_;
}
@@ -100,8 +216,6 @@ void SpdyStream::SetRequestTime(base::Time t) {
int SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) {
int rv = OK;
- LOG(INFO) << "OnResponseReceived";
- DCHECK_NE(io_state_, STATE_OPEN);
metrics_.StartStream();
@@ -111,42 +225,47 @@ int SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) {
recv_first_byte_time_ = base::TimeTicks::Now();
response_time_ = base::Time::Now();
- if (io_state_ == STATE_NONE) {
- CHECK(pushed_);
- io_state_ = STATE_READ_HEADERS;
- } else if (io_state_ == STATE_READ_HEADERS_COMPLETE) {
- // This SpdyStream could be in this state in both true and false pushed_
- // conditions.
- // The false pushed_ condition (client request) will always go through
- // this state.
- // The true pushed_condition (server push) can be in this state when the
- // client requests an X-Associated-Content piece of content prior
- // to when the server push happens.
- } else {
- // We're not expecting a response while in this state. Error!
- rv = ERR_SPDY_PROTOCOL_ERROR;
- }
+ // If we receive a response before we are in STATE_WAITING_FOR_RESPONSE, then
+ // the server has sent the SYN_REPLY too early.
+ if (!pushed_ && io_state_ != STATE_WAITING_FOR_RESPONSE)
+ return ERR_SPDY_PROTOCOL_ERROR;
+ if (pushed_)
+ CHECK(io_state_ == STATE_NONE);
+ io_state_ = STATE_OPEN;
- rv = DoLoop(rv);
if (delegate_)
rv = delegate_->OnResponseReceived(*response_, response_time_, rv);
- // if delegate_ is not yet attached, we'll return response when delegate
- // gets attached to the stream.
+ // If delegate_ is not yet attached, we'll call OnResponseReceived after the
+ // delegate gets attached to the stream.
return rv;
}
void SpdyStream::OnDataReceived(const char* data, int length) {
DCHECK_GE(length, 0);
- LOG(INFO) << "SpdyStream: Data (" << length << " bytes) received for "
- << stream_id_;
- CHECK(!response_complete_);
+ if (!delegate_ || continue_buffering_data_) {
+ // It should be valid for this to happen in the server push case.
+ // We'll return received data when delegate gets attached to the stream.
+ if (length > 0) {
+ IOBufferWithSize* buf = new IOBufferWithSize(length);
+ memcpy(buf->data(), data, length);
+ pending_buffers_.push_back(buf);
+ } else {
+ pending_buffers_.push_back(NULL);
+ metrics_.StopStream();
+ // Note: we leave the stream open in the session until the stream
+ // is claimed.
+ }
+ return;
+ }
+
+ CHECK(!closed());
// If we don't have a response, then the SYN_REPLY did not come through.
// We cannot pass data up to the caller unless the reply headers have been
// received.
- if (response_->empty()) {
+ if (!response_received()) {
session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED);
return;
}
@@ -154,12 +273,14 @@ void SpdyStream::OnDataReceived(const char* data, int length) {
// A zero-length read means that the stream is being closed.
if (!length) {
metrics_.StopStream();
- scoped_refptr<SpdyStream> self(this);
session_->CloseStream(stream_id_, net::OK);
- UpdateHistograms();
+ // Note: |this| may be deleted after calling CloseStream.
return;
}
+ if (session_->flow_control())
+ DecreaseRecvWindowSize(length);
+
// Track our bandwidth.
metrics_.RecordBytes(length);
recv_bytes_ += length;
@@ -177,24 +298,18 @@ void SpdyStream::OnDataReceived(const char* data, int length) {
delegate_->OnDataReceived(data, length);
}
-void SpdyStream::OnWriteComplete(int status) {
- // TODO(mbelshe): Check for cancellation here. If we're cancelled, we
- // should discontinue the DoLoop.
-
- // It is possible that this stream was closed while we had a write pending.
- if (response_complete_)
+// This function is only called when an entire frame is written.
+void SpdyStream::OnWriteComplete(int bytes) {
+ DCHECK_LE(0, bytes);
+ send_bytes_ += bytes;
+ if (cancelled() || closed())
return;
-
- if (status > 0)
- send_bytes_ += status;
-
- DoLoop(status);
+ DoLoop(bytes);
}
void SpdyStream::OnClose(int status) {
- response_complete_ = true;
+ io_state_ = STATE_DONE;
response_status_ = status;
- stream_id_ = 0;
Delegate* delegate = delegate_;
delegate_ = NULL;
if (delegate)
@@ -202,62 +317,28 @@ void SpdyStream::OnClose(int status) {
}
void SpdyStream::Cancel() {
- cancelled_ = true;
- session_->CloseStream(stream_id_, ERR_ABORTED);
-}
-
-int SpdyStream::DoSendRequest(bool has_upload_data) {
- CHECK(!cancelled_);
-
- if (!pushed_) {
- spdy::SpdyControlFlags flags = spdy::CONTROL_FLAG_NONE;
- if (!has_upload_data)
- flags = spdy::CONTROL_FLAG_FIN;
-
- CHECK(request_.get());
- int result = session_->WriteSynStream(
- stream_id_, static_cast<RequestPriority>(priority_), flags,
- request_);
- if (result != ERR_IO_PENDING)
- return result;
- }
-
- send_time_ = base::TimeTicks::Now();
+ if (cancelled())
+ return;
- int result = OK;
- if (!pushed_) {
- DCHECK_EQ(io_state_, STATE_NONE);
- io_state_ = STATE_SEND_HEADERS;
- } else {
- DCHECK(!has_upload_data);
- if (!response_->empty()) {
- // We already have response headers, so we don't need to read the header.
- // Pushed stream should not have upload data.
- // We don't need to call DoLoop() in this state.
- DCHECK_EQ(io_state_, STATE_OPEN);
- return OK;
- } else {
- io_state_ = STATE_READ_HEADERS;
- }
- }
- return DoLoop(result);
+ cancelled_ = true;
+ if (session_->IsStreamActive(stream_id_))
+ session_->ResetStream(stream_id_, spdy::CANCEL);
}
-int SpdyStream::DoReadResponseHeaders() {
- CHECK(!cancelled_);
-
- // The SYN_REPLY has already been received.
- if (!response_->empty()) {
- CHECK_EQ(STATE_OPEN, io_state_);
- return OK;
- } else {
- CHECK_EQ(STATE_NONE, io_state_);
+int SpdyStream::SendRequest(bool has_upload_data) {
+ // Pushed streams do not send any data, and should always be in STATE_OPEN or
+ // STATE_DONE. However, we still want to return IO_PENDING to mimic non-push
+ // behavior.
+ has_upload_data_ = has_upload_data;
+ if (pushed_) {
+ send_time_ = base::TimeTicks::Now();
+ DCHECK(!has_upload_data_);
+ DCHECK(response_received());
+ return ERR_IO_PENDING;
}
-
-
- io_state_ = STATE_READ_HEADERS;
- // Q: do we need to run DoLoop here?
- return ERR_IO_PENDING;
+ CHECK_EQ(STATE_NONE, io_state_);
+ io_state_ = STATE_SEND_HEADERS;
+ return DoLoop(OK);
}
int SpdyStream::WriteStreamData(IOBuffer* data, int length,
@@ -269,40 +350,36 @@ bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated) {
return session_->GetSSLInfo(ssl_info, was_npn_negotiated);
}
+bool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) {
+ return session_->GetSSLCertRequestInfo(cert_request_info);
+}
+
int SpdyStream::DoLoop(int result) {
do {
State state = io_state_;
io_state_ = STATE_NONE;
switch (state) {
- // State machine 1: Send headers and wait for response headers.
+ // State machine 1: Send headers and body.
case STATE_SEND_HEADERS:
CHECK_EQ(OK, result);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_SEND_HEADERS, NULL);
result = DoSendHeaders();
break;
case STATE_SEND_HEADERS_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_SEND_HEADERS, NULL);
result = DoSendHeadersComplete(result);
break;
case STATE_SEND_BODY:
CHECK_EQ(OK, result);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_SEND_BODY, NULL);
result = DoSendBody();
break;
case STATE_SEND_BODY_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_SEND_BODY, NULL);
result = DoSendBodyComplete(result);
break;
- case STATE_READ_HEADERS:
- CHECK_EQ(OK, result);
- net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_READ_HEADERS, NULL);
- result = DoReadHeaders();
- break;
- case STATE_READ_HEADERS_COMPLETE:
- net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_READ_HEADERS, NULL);
- result = DoReadHeadersComplete(result);
+ // This is an intermediary waiting state. This state is reached when all
+ // data has been sent, but no data has been received.
+ case STATE_WAITING_FOR_RESPONSE:
+ io_state_ = STATE_WAITING_FOR_RESPONSE;
+ result = ERR_IO_PENDING;
break;
-
// State machine 2: connection is established.
// In STATE_OPEN, OnResponseReceived has already been called.
// OnDataReceived, OnClose and OnWriteCompelte can be called.
@@ -335,12 +412,20 @@ int SpdyStream::DoLoop(int result) {
}
int SpdyStream::DoSendHeaders() {
- // The SpdySession will always call us back when the send is complete.
- // TODO(willchan): This code makes the assumption that for the non-push stream
- // case, the client code calls SendRequest() after creating the stream and
- // before yielding back to the MessageLoop. This is true in the current code,
- // but is not obvious from the headers. We should make the code handle
- // SendRequest() being called after the SYN_REPLY has been received.
+ CHECK(!cancelled_);
+
+ spdy::SpdyControlFlags flags = spdy::CONTROL_FLAG_NONE;
+ if (!has_upload_data_)
+ flags = spdy::CONTROL_FLAG_FIN;
+
+ CHECK(request_.get());
+ int result = session_->WriteSynStream(
+ stream_id_, static_cast<RequestPriority>(priority_), flags,
+ request_);
+ if (result != ERR_IO_PENDING)
+ return result;
+
+ send_time_ = base::TimeTicks::Now();
io_state_ = STATE_SEND_HEADERS_COMPLETE;
return ERR_IO_PENDING;
}
@@ -356,7 +441,7 @@ int SpdyStream::DoSendHeadersComplete(int result) {
// There is no body, skip that state.
if (delegate_->OnSendHeadersComplete(result)) {
- io_state_ = STATE_READ_HEADERS;
+ io_state_ = STATE_WAITING_FOR_RESPONSE;
return OK;
}
@@ -390,21 +475,11 @@ int SpdyStream::DoSendBodyComplete(int result) {
if (!delegate_->OnSendBodyComplete(result))
io_state_ = STATE_SEND_BODY;
else
- io_state_ = STATE_READ_HEADERS;
+ io_state_ = STATE_WAITING_FOR_RESPONSE;
return OK;
}
-int SpdyStream::DoReadHeaders() {
- io_state_ = STATE_READ_HEADERS_COMPLETE;
- return !response_->empty() ? OK : ERR_IO_PENDING;
-}
-
-int SpdyStream::DoReadHeadersComplete(int result) {
- io_state_ = STATE_OPEN;
- return result;
-}
-
int SpdyStream::DoOpen(int result) {
if (delegate_)
delegate_->OnDataSent(result);
@@ -413,11 +488,6 @@ int SpdyStream::DoOpen(int result) {
}
void SpdyStream::UpdateHistograms() {
- if (histograms_recorded_)
- return;
-
- histograms_recorded_ = true;
-
// We need all timers to be filled in, otherwise metrics can be bogus.
if (send_time_.is_null() || recv_first_byte_time_.is_null() ||
recv_last_byte_time_.is_null())
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h
index 13a6644..1730af5 100644
--- a/net/spdy/spdy_stream.h
+++ b/net/spdy/spdy_stream.h
@@ -4,6 +4,7 @@
#ifndef NET_SPDY_SPDY_STREAM_H_
#define NET_SPDY_SPDY_STREAM_H_
+#pragma once
#include <string>
#include <vector>
@@ -21,6 +22,7 @@
namespace net {
class SpdySession;
+class SSLCertRequestInfo;
class SSLInfo;
// The SpdyStream is used by the SpdySession to represent each stream known
@@ -50,8 +52,8 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
// Returns true if no more data to be sent.
virtual bool OnSendBodyComplete(int status) = 0;
- // Called when SYN_REPLY received. |status| indicates network error.
- // Returns network error code.
+ // Called when SYN_STREAM or SYN_REPLY received. |status| indicates network
+ // error. Returns network error code.
virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response,
base::Time response_time,
int status) = 0;
@@ -74,7 +76,10 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
};
// SpdyStream constructor
- SpdyStream(SpdySession* session, spdy::SpdyStreamId stream_id, bool pushed);
+ SpdyStream(SpdySession* session,
+ spdy::SpdyStreamId stream_id,
+ bool pushed,
+ const BoundNetLog& net_log);
// Set new |delegate|. |delegate| must not be NULL.
// If it already received SYN_REPLY or data, OnResponseReceived() or
@@ -92,8 +97,8 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
spdy::SpdyStreamId stream_id() const { return stream_id_; }
void set_stream_id(spdy::SpdyStreamId stream_id) { stream_id_ = stream_id; }
- bool syn_reply_received() const { return syn_reply_received_; }
- void set_syn_reply_received() { syn_reply_received_ = true; }
+ bool response_received() const { return response_received_; }
+ void set_response_received() { response_received_ = true; }
// For pushed streams, we track a path to identify them.
const std::string& path() const { return path_; }
@@ -102,26 +107,47 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
int priority() const { return priority_; }
void set_priority(int priority) { priority_ = priority; }
- int window_size() const { return window_size_; }
- void set_window_size(int window_size) { window_size_ = window_size; }
+ int send_window_size() const { return send_window_size_; }
+ void set_send_window_size(int window_size) {
+ send_window_size_ = window_size;
+ }
+
+ int recv_window_size() const { return recv_window_size_; }
+ void set_recv_window_size(int window_size) {
+ recv_window_size_ = window_size;
+ }
+
+ void set_stalled_by_flow_control(bool stalled) {
+ stalled_by_flow_control_ = stalled;
+ }
- // Updates |window_size_| with delta extracted from a WINDOW_UPDATE
- // frame; sends a RST_STREAM if delta overflows |window_size_| and
+ // Increases |send_window_size_| with delta extracted from a WINDOW_UPDATE
+ // frame; sends a RST_STREAM if delta overflows |send_window_size_| and
// removes the stream from the session.
- void UpdateWindowSize(int delta_window_size);
+ void IncreaseSendWindowSize(int delta_window_size);
+
+ // Decreases |send_window_size_| by the given number of bytes.
+ void DecreaseSendWindowSize(int delta_window_size);
+
+ // Increases |recv_window_size_| by the given number of bytes, also sends
+ // a WINDOW_UPDATE frame.
+ void IncreaseRecvWindowSize(int delta_window_size);
+
+ // Decreases |recv_window_size_| by the given number of bytes, called
+ // whenever data is read. May also send a RST_STREAM and remove the
+ // stream from the session if the resultant |recv_window_size_| is
+ // negative, since that would be a flow control violation.
+ void DecreaseRecvWindowSize(int delta_window_size);
const BoundNetLog& net_log() const { return net_log_; }
- void set_net_log(const BoundNetLog& log) { net_log_ = log; }
const linked_ptr<spdy::SpdyHeaderBlock>& spdy_headers() const;
void set_spdy_headers(const linked_ptr<spdy::SpdyHeaderBlock>& headers);
base::Time GetRequestTime() const;
void SetRequestTime(base::Time t);
- // Called by the SpdySession when a response (e.g. a SYN_REPLY) has been
- // received for this stream. |path| is the path of the URL for a server
- // initiated stream, otherwise is empty.
- // Returns a status code.
+ // Called by the SpdySession when a response (e.g. a SYN_STREAM or SYN_REPLY)
+ // has been received for this stream. Returns a status code.
int OnResponseReceived(const spdy::SpdyHeaderBlock& response);
// Called by the SpdySession when response data has been received for this
@@ -137,7 +163,7 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
// will be called multiple times for each write which completes. Writes
// include the SYN_STREAM write and also DATA frame writes.
// |result| is the number of bytes written or a net error code.
- void OnWriteComplete(int status);
+ void OnWriteComplete(int bytes);
// Called by the SpdySession when the request is finished. This callback
// will always be called at the end of the request and signals to the
@@ -148,29 +174,29 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
void Cancel();
bool cancelled() const { return cancelled_; }
+ bool closed() const { return io_state_ == STATE_DONE; }
// Interface for Spdy[Http|WebSocket]Stream to use.
// Sends the request.
// For non push stream, it will send SYN_STREAM frame.
- int DoSendRequest(bool has_upload_data);
-
- // Reads response headers. If the SpdyStream have already received
- // the response headers, return OK and response headers filled in
- // |response| given in SendRequest.
- // Otherwise, return ERR_IO_PENDING and OnResponseReceived() will be called.
- int DoReadResponseHeaders();
+ int SendRequest(bool has_upload_data);
// Sends DATA frame.
int WriteStreamData(IOBuffer* data, int length,
spdy::SpdyDataFlags flags);
+ // Fills SSL info in |ssl_info| and returns true when SSL is in use.
bool GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated);
+ // Fills SSL Certificate Request info |cert_request_info| and returns
+ // true when SSL is in use.
+ bool GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
+
bool is_idle() const {
- return io_state_ == STATE_NONE || io_state_ == STATE_OPEN;
+ return io_state_ == STATE_OPEN || io_state_ == STATE_DONE;
}
- bool response_complete() const { return response_complete_; }
+
int response_status() const { return response_status_; }
private:
@@ -180,8 +206,7 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
STATE_SEND_HEADERS_COMPLETE,
STATE_SEND_BODY,
STATE_SEND_BODY_COMPLETE,
- STATE_READ_HEADERS,
- STATE_READ_HEADERS_COMPLETE,
+ STATE_WAITING_FOR_RESPONSE,
STATE_OPEN,
STATE_DONE
};
@@ -205,13 +230,27 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
// be called after the stream has completed.
void UpdateHistograms();
+ // When a server pushed stream is first created, this function is posted on
+ // the MessageLoop to replay all the data that the server has already sent.
+ void PushedStreamReplayData();
+
+ // There is a small period of time between when a server pushed stream is
+ // first created, and the pushed data is replayed. Any data received during
+ // this time should continue to be buffered.
+ bool continue_buffering_data_;
+
spdy::SpdyStreamId stream_id_;
std::string path_;
int priority_;
- int window_size_;
+
+ // Flow control variables.
+ bool stalled_by_flow_control_;
+ int send_window_size_;
+ int recv_window_size_;
+
const bool pushed_;
ScopedBandwidthMetrics metrics_;
- bool syn_reply_received_;
+ bool response_received_;
scoped_refptr<SpdySession> session_;
@@ -228,14 +267,14 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
linked_ptr<spdy::SpdyHeaderBlock> response_;
base::Time response_time_;
- bool response_complete_; // TODO(mbelshe): fold this into the io_state.
State io_state_;
// Since we buffer the response, we also buffer the response status.
- // Not valid until response_complete_ is true.
+ // Not valid until the stream is closed.
int response_status_;
bool cancelled_;
+ bool has_upload_data_;
BoundNetLog net_log_;
@@ -244,7 +283,6 @@ class SpdyStream : public base::RefCounted<SpdyStream> {
base::TimeTicks recv_last_byte_time_;
int send_bytes_;
int recv_bytes_;
- bool histograms_recorded_;
// Data received before delegate is attached.
std::vector<scoped_refptr<IOBufferWithSize> > pending_buffers_;
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
index 4daad96..84d21d3 100644
--- a/net/spdy/spdy_stream_unittest.cc
+++ b/net/spdy/spdy_stream_unittest.cc
@@ -28,11 +28,6 @@ class SpdySessionPoolPeer {
namespace {
-// Create a proxy service which fails on all requests (falls back to direct).
-ProxyService* CreateNullProxyService() {
- return ProxyService::CreateNull();
-}
-
class TestSpdyStreamDelegate : public SpdyStream::Delegate {
public:
TestSpdyStreamDelegate(SpdyStream* stream,
@@ -59,6 +54,7 @@ class TestSpdyStreamDelegate : public SpdyStream::Delegate {
ADD_FAILURE() << "OnSendBodyComplete should not be called";
return true;
}
+
virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response,
base::Time response_time,
int status) {
@@ -118,9 +114,11 @@ class SpdyStreamTest : public testing::Test {
scoped_refptr<SpdySession> CreateSpdySession() {
spdy::SpdyFramer::set_enable_compression_default(false);
HostPortPair host_port_pair("www.google.com", 80);
+ HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
scoped_refptr<SpdySession> session(
- session_->spdy_session_pool()->Get(
- host_port_pair, session_, BoundNetLog()));
+ session_->spdy_session_pool()->Get(pair,
+ session_->mutable_spdy_settings(),
+ BoundNetLog()));
return session;
}
@@ -141,7 +139,7 @@ TEST_F(SpdyStreamTest, SendDataAfterOpen) {
spdy::SYN_STREAM,
1,
0,
- SPDY_PRIORITY_LOWEST,
+ net::ConvertRequestPriorityToSpdyPriority(LOWEST),
spdy::CONTROL_FLAG_NONE,
false,
spdy::INVALID,
@@ -187,7 +185,7 @@ TEST_F(SpdyStreamTest, SendDataAfterOpen) {
MockConnect connect_data(false, OK);
data->set_connect_data(connect_data);
- session_deps.socket_factory.AddSocketDataProvider(data.get());
+ session_deps.socket_factory->AddSocketDataProvider(data.get());
SpdySession::SetSSLMode(false);
scoped_refptr<SpdySession> session(CreateSpdySession());
@@ -196,8 +194,12 @@ TEST_F(SpdyStreamTest, SendDataAfterOpen) {
HostPortPair host_port_pair("www.google.com", 80);
scoped_refptr<TCPSocketParams> tcp_params =
new TCPSocketParams(host_port_pair, LOWEST, GURL(), false);
- EXPECT_EQ(OK, session->Connect("spdy.www.google.com", tcp_params,
- LOWEST));
+
+ scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+ EXPECT_EQ(OK,
+ connection->Init(host_port_pair.ToString(), tcp_params, LOWEST,
+ NULL, session_->tcp_socket_pool(), BoundNetLog()));
+ session->InitializeWithSocket(connection.release(), false, OK);
scoped_refptr<SpdyStream> stream;
ASSERT_EQ(
@@ -217,7 +219,7 @@ TEST_F(SpdyStreamTest, SendDataAfterOpen) {
(*headers)["version"] = "HTTP/1.1";
stream->set_spdy_headers(headers);
- EXPECT_EQ(ERR_IO_PENDING, stream->DoSendRequest(true));
+ EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
EXPECT_EQ(OK, callback.WaitForResult());
diff --git a/net/spdy/spdy_test_util.cc b/net/spdy/spdy_test_util.cc
index 99af4f8..1727717 100644
--- a/net/spdy/spdy_test_util.cc
+++ b/net/spdy/spdy_test_util.cc
@@ -7,7 +7,10 @@
#include <string>
#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "net/http/http_network_transaction.h"
+#include "net/spdy/spdy_framer.h"
namespace net {
@@ -248,12 +251,63 @@ int ConstructSpdyHeader(const char* const extra_headers[],
return n;
}
-// Constructs a standard SPDY GET SYN packet, optionally compressed.
+spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ spdy::SpdyControlType type,
+ spdy::SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize) {
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ compressed,
+ stream_id,
+ request_priority,
+ type,
+ flags,
+ kHeaders,
+ kHeadersSize,
+ 0);
+}
+
+spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ spdy::SpdyControlType type,
+ spdy::SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize,
+ int associated_stream_id) {
+ const SpdyHeaderInfo kSynStartHeader = {
+ type, // Kind = Syn
+ stream_id, // Stream ID
+ associated_stream_id, // Associated stream ID
+ net::ConvertRequestPriorityToSpdyPriority(request_priority),
+ // Priority
+ flags, // Control Flags
+ compressed, // Compressed
+ spdy::INVALID, // Status
+ NULL, // Data
+ 0, // Length
+ spdy::DATA_FLAG_NONE // Data Flags
+ };
+ return ConstructSpdyPacket(kSynStartHeader,
+ extra_headers,
+ extra_header_count,
+ kHeaders,
+ kHeadersSize / 2);
+}
+
+// Constructs a standard SPDY GET SYN packet, optionally compressed
+// for the url |url|.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
-spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
- int extra_header_count,
+spdy::SpdyFrame* ConstructSpdyGet(const char* const url,
bool compressed,
int stream_id,
RequestPriority request_priority) {
@@ -261,7 +315,8 @@ spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
spdy::SYN_STREAM, // Kind = Syn
stream_id, // Stream ID
0, // Associated stream ID
- request_priority, // Priority
+ net::ConvertRequestPriorityToSpdyPriority(request_priority),
+ // Priority
spdy::CONTROL_FLAG_FIN, // Control Flags
compressed, // Compressed
spdy::INVALID, // Status
@@ -269,20 +324,204 @@ spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
0, // Length
spdy::DATA_FLAG_NONE // Data Flags
};
- static const char* const kStandardGetHeaders[] = {
+
+ GURL gurl(url);
+
+ // This is so ugly. Why are we using char* in here again?
+ std::string str_path = gurl.PathForRequest();
+ std::string str_scheme = gurl.scheme();
+ std::string str_host = gurl.host(); // TODO(mbelshe): should have a port.
+ scoped_array<char> req(new char[str_path.size() + 1]);
+ scoped_array<char> scheme(new char[str_scheme.size() + 1]);
+ scoped_array<char> host(new char[str_host.size() + 1]);
+ memcpy(req.get(), str_path.c_str(), str_path.size());
+ memcpy(scheme.get(), str_scheme.c_str(), str_scheme.size());
+ memcpy(host.get(), str_host.c_str(), str_host.size());
+ req.get()[str_path.size()] = '\0';
+ scheme.get()[str_scheme.size()] = '\0';
+ host.get()[str_host.size()] = '\0';
+
+ const char* const headers[] = {
"method",
"GET",
"url",
- "http://www.google.com/",
+ req.get(),
+ "host",
+ host.get(),
+ "scheme",
+ scheme.get(),
"version",
"HTTP/1.1"
};
return ConstructSpdyPacket(
kSynStartHeader,
- extra_headers,
- extra_header_count,
- kStandardGetHeaders,
- arraysize(kStandardGetHeaders) / 2);
+ NULL,
+ 0,
+ headers,
+ arraysize(headers) / 2);
+}
+
+// Constructs a standard SPDY GET SYN packet, optionally compressed.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority) {
+ return ConstructSpdyGet(extra_headers, extra_header_count, compressed,
+ stream_id, request_priority, true);
+}
+
+// Constructs a standard SPDY GET SYN packet, optionally compressed.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ bool direct) {
+ const char* const kStandardGetHeaders[] = {
+ "method",
+ "GET",
+ "url",
+ (direct ? "/" : "http://www.google.com/"),
+ "host",
+ "www.google.com",
+ "scheme",
+ "http",
+ "version",
+ "HTTP/1.1"
+ };
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ compressed,
+ stream_id,
+ request_priority,
+ spdy::SYN_STREAM,
+ spdy::CONTROL_FLAG_FIN,
+ kStandardGetHeaders,
+ arraysize(kStandardGetHeaders));
+}
+
+// Constructs a standard SPDY push SYN packet.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id) {
+ const char* const kStandardGetHeaders[] = {
+ "hello",
+ "bye",
+ "status",
+ "200",
+ "version",
+ "HTTP/1.1"
+ };
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ false,
+ stream_id,
+ LOWEST,
+ spdy::SYN_STREAM,
+ spdy::CONTROL_FLAG_NONE,
+ kStandardGetHeaders,
+ arraysize(kStandardGetHeaders),
+ associated_stream_id);
+}
+
+spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* path) {
+ const char* const kStandardGetHeaders[] = {
+ "hello",
+ "bye",
+ "path",
+ path,
+ "status",
+ "200 OK",
+ "url",
+ path,
+ "version",
+ "HTTP/1.1"
+ };
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ false,
+ stream_id,
+ LOWEST,
+ spdy::SYN_STREAM,
+ spdy::CONTROL_FLAG_NONE,
+ kStandardGetHeaders,
+ arraysize(kStandardGetHeaders),
+ associated_stream_id);
+
+}
+spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* path,
+ const char* status,
+ const char* location,
+ const char* url) {
+ const char* const kStandardGetHeaders[] = {
+ "hello",
+ "bye",
+ "path",
+ path,
+ "status",
+ status,
+ "location",
+ location,
+ "url",
+ url,
+ "version",
+ "HTTP/1.1"
+ };
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ false,
+ stream_id,
+ LOWEST,
+ spdy::SYN_STREAM,
+ spdy::CONTROL_FLAG_NONE,
+ kStandardGetHeaders,
+ arraysize(kStandardGetHeaders),
+ associated_stream_id);
+}
+
+// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id) {
+ static const char* const kStandardGetHeaders[] = {
+ "hello",
+ "bye",
+ "status",
+ "301 Moved Permanently",
+ "location",
+ "http://www.foo.com/index.php",
+ "version",
+ "HTTP/1.1"
+ };
+ return ConstructSpdyControlFrame(NULL,
+ 0,
+ false,
+ stream_id,
+ LOWEST,
+ spdy::SYN_REPLY,
+ spdy::CONTROL_FLAG_NONE,
+ kStandardGetHeaders,
+ arraysize(kStandardGetHeaders));
}
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
@@ -292,18 +531,6 @@ spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
spdy::SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
int extra_header_count,
int stream_id) {
- const SpdyHeaderInfo kSynStartHeader = {
- spdy::SYN_REPLY, // Kind = SynReply
- stream_id, // Stream ID
- 0, // Associated stream ID
- SPDY_PRIORITY_LOWEST, // Priority
- spdy::CONTROL_FLAG_NONE, // Control Flags
- false, // Compressed
- spdy::INVALID, // Status
- NULL, // Data
- 0, // Length
- spdy::DATA_FLAG_NONE // Data Flags
- };
static const char* const kStandardGetHeaders[] = {
"hello",
"bye",
@@ -314,46 +541,49 @@ spdy::SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
"version",
"HTTP/1.1"
};
- return ConstructSpdyPacket(
- kSynStartHeader,
- extra_headers,
- extra_header_count,
- kStandardGetHeaders,
- arraysize(kStandardGetHeaders) / 2);
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ false,
+ stream_id,
+ LOWEST,
+ spdy::SYN_REPLY,
+ spdy::CONTROL_FLAG_NONE,
+ kStandardGetHeaders,
+ arraysize(kStandardGetHeaders));
}
// Constructs a standard SPDY POST SYN packet.
+// |content_length| is the size of post data.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
-spdy::SpdyFrame* ConstructSpdyPost(const char* const extra_headers[],
+spdy::SpdyFrame* ConstructSpdyPost(int64 content_length,
+ const char* const extra_headers[],
int extra_header_count) {
- const SpdyHeaderInfo kSynStartHeader = {
- spdy::SYN_STREAM, // Kind = Syn
- 1, // Stream ID
- 0, // Associated stream ID
- SPDY_PRIORITY_LOWEST, // Priority
- spdy::CONTROL_FLAG_NONE, // Control Flags
- false, // Compressed
- spdy::INVALID, // Status
- NULL, // Data
- 0, // Length
- spdy::DATA_FLAG_NONE // Data Flags
- };
- static const char* const kStandardGetHeaders[] = {
+ std::string length_str = base::Int64ToString(content_length);
+ const char* post_headers[] = {
"method",
"POST",
"url",
- "http://www.google.com/",
+ "/",
+ "host",
+ "www.google.com",
+ "scheme",
+ "http",
"version",
- "HTTP/1.1"
+ "HTTP/1.1",
+ "content-length",
+ length_str.c_str()
};
- return ConstructSpdyPacket(
- kSynStartHeader,
- extra_headers,
- extra_header_count,
- kStandardGetHeaders,
- arraysize(kStandardGetHeaders) / 2);
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ false,
+ 1,
+ LOWEST,
+ spdy::SYN_STREAM,
+ spdy::CONTROL_FLAG_NONE,
+ post_headers,
+ arraysize(post_headers));
}
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY POST.
@@ -362,18 +592,6 @@ spdy::SpdyFrame* ConstructSpdyPost(const char* const extra_headers[],
// Returns a SpdyFrame.
spdy::SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
int extra_header_count) {
- const SpdyHeaderInfo kSynStartHeader = {
- spdy::SYN_REPLY, // Kind = SynReply
- 1, // Stream ID
- 0, // Associated stream ID
- SPDY_PRIORITY_LOWEST, // Priority
- spdy::CONTROL_FLAG_NONE, // Control Flags
- false, // Compressed
- spdy::INVALID, // Status
- NULL, // Data
- 0, // Length
- spdy::DATA_FLAG_NONE // Data Flags
- };
static const char* const kStandardGetHeaders[] = {
"hello",
"bye",
@@ -384,20 +602,31 @@ spdy::SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
"version",
"HTTP/1.1"
};
- return ConstructSpdyPacket(
- kSynStartHeader,
- extra_headers,
- extra_header_count,
- kStandardGetHeaders,
- arraysize(kStandardGetHeaders) / 2);
+ return ConstructSpdyControlFrame(extra_headers,
+ extra_header_count,
+ false,
+ 1,
+ LOWEST,
+ spdy::SYN_REPLY,
+ spdy::CONTROL_FLAG_NONE,
+ kStandardGetHeaders,
+ arraysize(kStandardGetHeaders));
}
-// Constructs a single SPDY data frame with the contents "hello!"
+// Constructs a single SPDY data frame with the default contents.
spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, bool fin) {
spdy::SpdyFramer framer;
- return
- framer.CreateDataFrame(stream_id, "hello!", 6,
- fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE);
+ return framer.CreateDataFrame(
+ stream_id, kUploadData, kUploadDataSize,
+ fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE);
+}
+
+// Constructs a single SPDY data frame with the given content.
+spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
+ uint32 len, bool fin) {
+ spdy::SpdyFramer framer;
+ return framer.CreateDataFrame(
+ stream_id, data, len, fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE);
}
// Construct an expected SPDY reply string.
@@ -486,8 +715,13 @@ MockWrite CreateMockWrite(const spdy::SpdyFrame& req) {
// Create a MockWrite from the given SpdyFrame and sequence number.
MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq) {
+ return CreateMockWrite(req, seq, true);
+}
+
+// Create a MockWrite from the given SpdyFrame and sequence number.
+MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq, bool async) {
return MockWrite(
- true, req.data(), req.length() + spdy::SpdyFrame::size(), seq);
+ async, req.data(), req.length() + spdy::SpdyFrame::size(), seq);
}
// Create a MockRead from the given SpdyFrame.
@@ -498,8 +732,13 @@ MockRead CreateMockRead(const spdy::SpdyFrame& resp) {
// Create a MockRead from the given SpdyFrame and sequence number.
MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq) {
+ return CreateMockRead(resp, seq, true);
+}
+
+// Create a MockRead from the given SpdyFrame and sequence number.
+MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq, bool async) {
return MockRead(
- true, resp.data(), resp.length() + spdy::SpdyFrame::size(), seq);
+ async, resp.data(), resp.length() + spdy::SpdyFrame::size(), seq);
}
// Combines the given SpdyFrames into the given char array and returns
@@ -520,4 +759,19 @@ int CombineFrames(const spdy::SpdyFrame** frames, int num_frames,
return total_len;
}
+const SpdyHeaderInfo make_spdy_header(spdy::SpdyControlType type) {
+ const SpdyHeaderInfo kHeader = {
+ type, // Kind = Syn
+ 1, // Stream ID
+ 0, // Associated stream ID
+ 2, // Priority
+ spdy::CONTROL_FLAG_FIN, // Control Flags
+ false, // Compressed
+ spdy::INVALID, // Status
+ NULL, // Data
+ 0, // Length
+ spdy::DATA_FLAG_NONE // Data Flags
+ };
+ return kHeader;
+}
} // namespace net
diff --git a/net/spdy/spdy_test_util.h b/net/spdy/spdy_test_util.h
index 6e7a8d0..be2f7d0 100644
--- a/net/spdy/spdy_test_util.h
+++ b/net/spdy/spdy_test_util.h
@@ -4,20 +4,31 @@
#ifndef NET_SPDY_SPDY_TEST_UTIL_H_
#define NET_SPDY_SPDY_TEST_UTIL_H_
+#pragma once
#include "base/basictypes.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/request_priority.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_transaction_factory.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_session_pool.h"
+#include "net/url_request/url_request_context.h"
namespace net {
+// Default upload data used by both, mock objects and framer when creating
+// data frames.
+const char kDefaultURL[] = "http://www.google.com";
+const char kUploadData[] = "hello!";
+const int kUploadDataSize = arraysize(kUploadData)-1;
+
// NOTE: In GCC, on a Mac, this can't be in an anonymous namespace!
// This struct holds information used to construct spdy control and data frames.
struct SpdyHeaderInfo {
@@ -108,6 +119,27 @@ spdy::SpdyFrame* ConstructSpdyPacket(const SpdyHeaderInfo& header_info,
const char* const tail[],
int tail_header_count);
+// Construct a generic SpdyControlFrame.
+spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ spdy::SpdyControlType type,
+ spdy::SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize);
+spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ spdy::SpdyControlType type,
+ spdy::SpdyControlFlags flags,
+ const char* const* kHeaders,
+ int kHeadersSize,
+ int associated_stream_id);
+
// Construct an expected SPDY reply string.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
@@ -148,6 +180,16 @@ int ConstructSpdyHeader(const char* const extra_headers[],
int buffer_length,
int index);
+// Constructs a standard SPDY GET SYN packet, optionally compressed
+// for the url |url|.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyGet(const char* const url,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority);
+
// Constructs a standard SPDY GET SYN packet, optionally compressed.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
@@ -158,6 +200,40 @@ spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
int stream_id,
RequestPriority request_priority);
+// Constructs a standard SPDY GET SYN packet, optionally compressed.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls. If |direct| is false, the
+// the full url will be used instead of simply the path.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
+ int extra_header_count,
+ bool compressed,
+ int stream_id,
+ RequestPriority request_priority,
+ bool direct);
+
+// Constructs a standard SPDY push SYN packet.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id);
+spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* path);
+spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* path,
+ const char* status,
+ const char* location,
+ const char* url);
+
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
@@ -166,11 +242,18 @@ spdy::SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
int extra_header_count,
int stream_id);
+// Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
+// |extra_headers| are the extra header-value pairs, which typically
+// will vary the most between calls.
+// Returns a SpdyFrame.
+spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id);
+
// Constructs a standard SPDY POST SYN packet.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
-spdy::SpdyFrame* ConstructSpdyPost(const char* const extra_headers[],
+spdy::SpdyFrame* ConstructSpdyPost(int64 content_length,
+ const char* const extra_headers[],
int extra_header_count);
// Constructs a standard SPDY SYN_REPLY packet to match the SPDY POST.
@@ -184,18 +267,26 @@ spdy::SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id,
bool fin);
+// Constructs a single SPDY data frame with the given content.
+spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
+ uint32 len, bool fin);
+
// Create an async MockWrite from the given SpdyFrame.
MockWrite CreateMockWrite(const spdy::SpdyFrame& req);
// Create an async MockWrite from the given SpdyFrame and sequence number.
MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq);
+MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq, bool async);
+
// Create a MockRead from the given SpdyFrame.
MockRead CreateMockRead(const spdy::SpdyFrame& resp);
// Create a MockRead from the given SpdyFrame and sequence number.
MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq);
+MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq, bool async);
+
// Combines the given SpdyFrames into the given char array and returns
// the total length.
int CombineFrames(const spdy::SpdyFrame** frames, int num_frames,
@@ -208,10 +299,13 @@ class SpdySessionDependencies {
// Default set of dependencies -- "null" proxy service.
SpdySessionDependencies()
: host_resolver(new MockHostResolver),
- proxy_service(ProxyService::CreateNull()),
+ proxy_service(ProxyService::CreateDirect()),
ssl_config_service(new SSLConfigServiceDefaults),
- http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()),
- spdy_session_pool(new SpdySessionPool()) {
+ socket_factory(new MockClientSocketFactory),
+ deterministic_socket_factory(new DeterministicMockClientSocketFactory),
+ http_auth_handler_factory(
+ HttpAuthHandlerFactory::CreateDefault(host_resolver)),
+ spdy_session_pool(new SpdySessionPool(NULL)) {
// Note: The CancelledTransaction test does cleanup by running all
// tasks in the message loop (RunAllPending). Unfortunately, that
// doesn't clean up tasks on the host resolver thread; and
@@ -226,13 +320,18 @@ class SpdySessionDependencies {
: host_resolver(new MockHostResolver),
proxy_service(proxy_service),
ssl_config_service(new SSLConfigServiceDefaults),
- http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()),
- spdy_session_pool(new SpdySessionPool()) {}
+ socket_factory(new MockClientSocketFactory),
+ deterministic_socket_factory(new DeterministicMockClientSocketFactory),
+ http_auth_handler_factory(
+ HttpAuthHandlerFactory::CreateDefault(host_resolver)),
+ spdy_session_pool(new SpdySessionPool(NULL)) {}
+ // NOTE: host_resolver must be ordered before http_auth_handler_factory.
scoped_refptr<MockHostResolverBase> host_resolver;
scoped_refptr<ProxyService> proxy_service;
scoped_refptr<SSLConfigService> ssl_config_service;
- MockClientSocketFactory socket_factory;
+ scoped_ptr<MockClientSocketFactory> socket_factory;
+ scoped_ptr<DeterministicMockClientSocketFactory> deterministic_socket_factory;
scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
scoped_refptr<SpdySessionPool> spdy_session_pool;
@@ -240,16 +339,62 @@ class SpdySessionDependencies {
SpdySessionDependencies* session_deps) {
return new HttpNetworkSession(session_deps->host_resolver,
session_deps->proxy_service,
- &session_deps->socket_factory,
+ session_deps->socket_factory.get(),
session_deps->ssl_config_service,
session_deps->spdy_session_pool,
session_deps->http_auth_handler_factory.get(),
NULL,
NULL);
-}
+ }
+ static HttpNetworkSession* SpdyCreateSessionDeterministic(
+ SpdySessionDependencies* session_deps) {
+ return new HttpNetworkSession(session_deps->host_resolver,
+ session_deps->proxy_service,
+ session_deps->
+ deterministic_socket_factory.get(),
+ session_deps->ssl_config_service,
+ session_deps->spdy_session_pool,
+ session_deps->http_auth_handler_factory.get(),
+ NULL,
+ NULL);
+ }
};
+class SpdyURLRequestContext : public URLRequestContext {
+ public:
+ SpdyURLRequestContext() {
+ host_resolver_ = new MockHostResolver;
+ proxy_service_ = ProxyService::CreateDirect();
+ spdy_session_pool_ = new SpdySessionPool(NULL);
+ ssl_config_service_ = new SSLConfigServiceDefaults;
+ http_auth_handler_factory_ = HttpAuthHandlerFactory::CreateDefault(
+ host_resolver_);
+ http_transaction_factory_ = new net::HttpCache(
+ new HttpNetworkLayer(&socket_factory_,
+ host_resolver_,
+ proxy_service_,
+ ssl_config_service_,
+ spdy_session_pool_.get(),
+ http_auth_handler_factory_,
+ network_delegate_,
+ NULL),
+ net::HttpCache::DefaultBackend::InMemory(0));
+ }
+
+ MockClientSocketFactory& socket_factory() { return socket_factory_; }
+
+ protected:
+ virtual ~SpdyURLRequestContext() {
+ delete http_transaction_factory_;
+ delete http_auth_handler_factory_;
+ }
+
+ private:
+ MockClientSocketFactory socket_factory_;
+ scoped_refptr<SpdySessionPool> spdy_session_pool_;
+};
+const SpdyHeaderInfo make_spdy_header(spdy::SpdyControlType type);
} // namespace net
#endif // NET_SPDY_SPDY_TEST_UTIL_H_
diff --git a/net/spdy/spdy_transaction_factory.h b/net/spdy/spdy_transaction_factory.h
deleted file mode 100644
index bb626f9..0000000
--- a/net/spdy/spdy_transaction_factory.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 NET_SPDY_SPDY_TRANSACTION_FACTORY_H__
-#define NET_SPDY_SPDY_TRANSACTION_FACTORY_H__
-
-#include "net/http/http_transaction_factory.h"
-#include "net/spdy/spdy_network_transaction.h"
-
-namespace net {
-
-class SpdyTransactionFactory : public HttpTransactionFactory {
- public:
- explicit SpdyTransactionFactory(HttpNetworkSession* session)
- : session_(session) {
- }
- virtual ~SpdyTransactionFactory() {}
-
- // HttpTransactionFactory Interface.
- virtual HttpTransaction* CreateTransaction() {
- return new SpdyNetworkTransaction(session_);
- }
- virtual HttpCache* GetCache() {
- return NULL;
- }
- virtual void Suspend(bool suspend) {
- }
-
- private:
- scoped_refptr<HttpNetworkSession> session_;
-};
-
-} // namespace net
-
-#endif // NET_SPDY_SPDY_TRANSACTION_FACTORY_H__
diff --git a/net/stress_cache.target.mk b/net/stress_cache.target.mk
index 1bd44eb..7252539 100644
--- a/net/stress_cache.target.mk
+++ b/net/stress_cache.target.mk
@@ -19,6 +19,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -65,6 +66,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -128,14 +130,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
@@ -164,7 +167,8 @@ LIBS := -lrt \
-lnspr4 \
-lpthread \
-lz \
- -lgconf-2
+ -lgconf-2 \
+ -lresolv
$(builddir)/stress_cache: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/stress_cache: LIBS := $(LIBS)
diff --git a/net/test/test_server.cc b/net/test/test_server.cc
index 4abed54..f4eb64f 100644
--- a/net/test/test_server.cc
+++ b/net/test/test_server.cc
@@ -10,29 +10,84 @@
#include "build/build_config.h"
-#if defined(OS_WIN)
-#include <windows.h>
-#include <wincrypt.h>
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX)
#include "net/base/x509_certificate.h"
#endif
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/leak_annotations.h"
#include "base/logging.h"
#include "base/path_service.h"
+#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.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/net_test_constants.h"
#include "net/base/test_completion_callback.h"
#include "net/socket/tcp_client_socket.h"
-#include "net/socket/tcp_pinger.h"
+#include "net/test/python_utils.h"
#include "testing/platform_test.h"
-#if defined(OS_WIN)
-#pragma comment(lib, "crypt32.lib")
-#endif
+namespace {
+
+// Number of connection attempts for tests.
+const int kServerConnectionAttempts = 10;
+
+// Connection timeout in milliseconds for tests.
+const int kServerConnectionTimeoutMs = 1000;
+
+const char kTestServerShardFlag[] = "test-server-shard";
+
+int GetPortBase(net::TestServer::Type type) {
+ switch (type) {
+ case net::TestServer::TYPE_FTP:
+ return 3117;
+ case net::TestServer::TYPE_HTTP:
+ return 1337;
+ case net::TestServer::TYPE_HTTPS:
+ return 9443;
+ case net::TestServer::TYPE_HTTPS_CLIENT_AUTH:
+ return 9543;
+ case net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE:
+ // TODO(phajdan.jr): Some tests rely on this hardcoded value.
+ // Some uses of this are actually in .html/.js files.
+ return 9666;
+ case net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME:
+ return 9643;
+ default:
+ NOTREACHED();
+ }
+ return -1;
+}
+
+int GetPort(net::TestServer::Type type) {
+ int port = GetPortBase(type);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(kTestServerShardFlag)) {
+ std::string shard_str(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ kTestServerShardFlag));
+ int shard = -1;
+ if (base::StringToInt(shard_str, &shard)) {
+ port += shard;
+ } else {
+ LOG(FATAL) << "Got invalid " << kTestServerShardFlag << " flag value. "
+ << "An integer is expected.";
+ }
+ }
+ return port;
+}
+
+std::string GetHostname(net::TestServer::Type type) {
+ if (type == net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME) {
+ // Return a different hostname string that resolves to the same hostname.
+ return "localhost";
+ }
+
+ return "127.0.0.1";
+}
+
+} // namespace
namespace net {
@@ -40,269 +95,175 @@ namespace net {
void SetMacTestCertificate(X509Certificate* cert);
#endif
-// static
-const char TestServerLauncher::kHostName[] = "127.0.0.1";
-const char TestServerLauncher::kMismatchedHostName[] = "localhost";
-const int TestServerLauncher::kOKHTTPSPort = 9443;
-const int TestServerLauncher::kBadHTTPSPort = 9666;
-
-// The issuer name of the cert that should be trusted for the test to work.
-const wchar_t TestServerLauncher::kCertIssuerName[] = L"Test CA";
-
-TestServerLauncher::TestServerLauncher() : process_handle_(
- base::kNullProcessHandle),
- forking_(false),
- connection_attempts_(kDefaultTestConnectionAttempts),
- connection_timeout_(kDefaultTestConnectionTimeout)
-{
- InitCertPath();
-}
+TestServer::TestServer(Type type, const FilePath& document_root)
+ : host_port_pair_(GetHostname(type), GetPort(type)),
+ process_handle_(base::kNullProcessHandle),
+ type_(type) {
+ FilePath src_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
-TestServerLauncher::TestServerLauncher(int connection_attempts,
- int connection_timeout)
- : process_handle_(base::kNullProcessHandle),
- forking_(false),
- connection_attempts_(connection_attempts),
- connection_timeout_(connection_timeout)
-{
- InitCertPath();
-}
+ document_root_ = src_dir.Append(document_root);
-void TestServerLauncher::InitCertPath() {
- PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_);
- cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("net"))
+ certificates_dir_ = src_dir.Append(FILE_PATH_LITERAL("net"))
.Append(FILE_PATH_LITERAL("data"))
.Append(FILE_PATH_LITERAL("ssl"))
.Append(FILE_PATH_LITERAL("certificates"));
}
-namespace {
-
-void AppendToPythonPath(const FilePath& dir) {
- // Do nothing if dir already on path.
-
-#if defined(OS_WIN)
- const wchar_t kPythonPath[] = L"PYTHONPATH";
- // TODO(dkegel): handle longer PYTHONPATH variables
- wchar_t oldpath[4096];
- if (GetEnvironmentVariable(kPythonPath, oldpath, arraysize(oldpath)) == 0) {
- SetEnvironmentVariableW(kPythonPath, dir.value().c_str());
- } else if (!wcsstr(oldpath, dir.value().c_str())) {
- std::wstring newpath(oldpath);
- newpath.append(L";");
- newpath.append(dir.value());
- SetEnvironmentVariableW(kPythonPath, newpath.c_str());
- }
-#elif defined(OS_POSIX)
- const char kPythonPath[] = "PYTHONPATH";
- const char* oldpath = getenv(kPythonPath);
- // setenv() leaks memory intentionally on Mac
- if (!oldpath) {
- setenv(kPythonPath, dir.value().c_str(), 1);
- } else if (!strstr(oldpath, dir.value().c_str())) {
- std::string newpath(oldpath);
- newpath.append(":");
- newpath.append(dir.value());
- setenv(kPythonPath, newpath.c_str(), 1);
- }
+TestServer::~TestServer() {
+#if defined(OS_MACOSX)
+ SetMacTestCertificate(NULL);
#endif
+ Stop();
}
-} // end namespace
-
-void TestServerLauncher::SetPythonPath() {
- FilePath third_party_dir;
- CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir));
- third_party_dir = third_party_dir.Append(FILE_PATH_LITERAL("third_party"));
-
- AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("tlslite")));
- AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("pyftpdlib")));
-
- // Locate the Python code generated by the protocol buffers compiler.
- FilePath generated_code_dir;
- CHECK(PathService::Get(base::DIR_EXE, &generated_code_dir));
- generated_code_dir = generated_code_dir.Append(FILE_PATH_LITERAL("pyproto"));
- AppendToPythonPath(generated_code_dir);
- AppendToPythonPath(generated_code_dir.Append(FILE_PATH_LITERAL("sync_pb")));
-}
-
-bool TestServerLauncher::Start(Protocol protocol,
- const std::string& host_name, int port,
- const FilePath& document_root,
- const FilePath& cert_path,
- const std::wstring& file_root_url) {
- if (!cert_path.value().empty()) {
+bool TestServer::Start() {
+ if (GetScheme() == "https") {
if (!LoadTestRootCert())
return false;
if (!CheckCATrusted())
return false;
}
- std::string port_str = IntToString(port);
-
// Get path to python server script
FilePath testserver_path;
- if (!PathService::Get(base::DIR_SOURCE_ROOT, &testserver_path))
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &testserver_path)) {
+ LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
return false;
+ }
testserver_path = testserver_path
.Append(FILE_PATH_LITERAL("net"))
.Append(FILE_PATH_LITERAL("tools"))
.Append(FILE_PATH_LITERAL("testserver"))
.Append(FILE_PATH_LITERAL("testserver.py"));
- PathService::Get(base::DIR_SOURCE_ROOT, &document_root_dir_);
- document_root_dir_ = document_root_dir_.Append(document_root);
-
- SetPythonPath();
-
-#if defined(OS_WIN)
- // Get path to python interpreter
- if (!PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime_))
+ if (!SetPythonPath())
return false;
- python_runtime_ = python_runtime_
- .Append(FILE_PATH_LITERAL("third_party"))
- .Append(FILE_PATH_LITERAL("python_24"))
- .Append(FILE_PATH_LITERAL("python.exe"));
-
- std::wstring command_line =
- L"\"" + python_runtime_.ToWStringHack() + L"\" " +
- L"\"" + testserver_path.ToWStringHack() +
- L"\" --port=" + UTF8ToWide(port_str) +
- L" --data-dir=\"" + document_root_dir_.ToWStringHack() + L"\"";
- if (protocol == ProtoFTP)
- command_line.append(L" -f");
- if (!cert_path.value().empty()) {
- command_line.append(L" --https=\"");
- command_line.append(cert_path.ToWStringHack());
- command_line.append(L"\"");
- }
- if (!file_root_url.empty()) {
- command_line.append(L" --file-root-url=\"");
- command_line.append(file_root_url);
- command_line.append(L"\"");
- }
- // Deliberately do not pass the --forking flag. It breaks the tests
- // on Windows.
-
- if (!LaunchTestServerAsJob(command_line,
- true,
- &process_handle_,
- &job_handle_)) {
- LOG(ERROR) << "Failed to launch " << command_line;
- return false;
- }
-#elif defined(OS_POSIX)
- std::vector<std::string> command_line;
- command_line.push_back("python");
- command_line.push_back(testserver_path.value());
- command_line.push_back("--port=" + port_str);
- command_line.push_back("--data-dir=" + document_root_dir_.value());
- if (protocol == ProtoFTP)
- command_line.push_back("-f");
- if (!cert_path.value().empty())
- command_line.push_back("--https=" + cert_path.value());
- if (forking_)
- command_line.push_back("--forking");
-
- base::file_handle_mapping_vector no_mappings;
- LOG(INFO) << "Trying to launch " << command_line[0] << " ...";
- if (!base::LaunchApp(command_line, no_mappings, false, &process_handle_)) {
- LOG(ERROR) << "Failed to launch " << command_line[0] << " ...";
+
+ if (!LaunchPython(testserver_path))
return false;
- }
-#endif
- // Let the server start, then verify that it's up.
- // Our server is Python, and takes about 500ms to start
- // up the first time, and about 200ms after that.
- if (!WaitToStart(host_name, port)) {
- LOG(ERROR) << "Failed to connect to server";
+ if (!WaitToStart()) {
Stop();
return false;
}
- LOG(INFO) << "Started on port " << port_str;
return true;
}
-bool TestServerLauncher::WaitToStart(const std::string& host_name, int port) {
- // Verify that the webserver is actually started.
- // Otherwise tests can fail if they run faster than Python can start.
- net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(
- net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism));
- net::HostResolver::RequestInfo info(host_name, port);
- int rv = resolver->Resolve(info, &addr, NULL, NULL, BoundNetLog());
- if (rv != net::OK)
- return false;
-
- net::TCPPinger pinger(addr);
- rv = pinger.Ping(base::TimeDelta::FromMilliseconds(connection_timeout_),
- connection_attempts_);
- return rv == net::OK;
-}
-
-bool TestServerLauncher::WaitToFinish(int timeout_ms) {
+bool TestServer::Stop() {
if (!process_handle_)
return true;
- bool ret = base::WaitForSingleProcess(process_handle_, timeout_ms);
+ // First check if the process has already terminated.
+ bool ret = base::WaitForSingleProcess(process_handle_, 0);
+ if (!ret)
+ ret = base::KillProcess(process_handle_, 1, true);
+
if (ret) {
base::CloseProcessHandle(process_handle_);
process_handle_ = base::kNullProcessHandle;
- LOG(INFO) << "Finished.";
} else {
- LOG(INFO) << "Timed out.";
+ LOG(INFO) << "Kill failed?";
}
+
return ret;
}
-bool TestServerLauncher::Stop() {
+bool TestServer::WaitToFinish(int timeout_ms) {
if (!process_handle_)
return true;
- // First check if the process has already terminated.
- bool ret = base::WaitForSingleProcess(process_handle_, 0);
- if (!ret)
- ret = base::KillProcess(process_handle_, 1, true);
-
+ bool ret = base::WaitForSingleProcess(process_handle_, timeout_ms);
if (ret) {
base::CloseProcessHandle(process_handle_);
process_handle_ = base::kNullProcessHandle;
- LOG(INFO) << "Stopped.";
} else {
- LOG(INFO) << "Kill failed?";
+ LOG(ERROR) << "Timed out.";
}
-
return ret;
}
-TestServerLauncher::~TestServerLauncher() {
-#if defined(OS_MACOSX)
- SetMacTestCertificate(NULL);
-#endif
- Stop();
+std::string TestServer::GetScheme() const {
+ switch (type_) {
+ case TYPE_FTP:
+ return "ftp";
+ case TYPE_HTTP:
+ return "http";
+ case TYPE_HTTPS:
+ case TYPE_HTTPS_CLIENT_AUTH:
+ case TYPE_HTTPS_MISMATCHED_HOSTNAME:
+ case TYPE_HTTPS_EXPIRED_CERTIFICATE:
+ return "https";
+ default:
+ NOTREACHED();
+ }
+ return std::string();
}
-FilePath TestServerLauncher::GetRootCertPath() {
- FilePath path(cert_dir_);
- path = path.AppendASCII("root_ca_cert.crt");
- return path;
+bool TestServer::GetAddressList(AddressList* address_list) const {
+ DCHECK(address_list);
+
+ scoped_refptr<HostResolver> resolver(
+ CreateSystemHostResolver(HostResolver::kDefaultParallelism, NULL));
+ HostResolver::RequestInfo info(host_port_pair_);
+ int rv = resolver->Resolve(info, address_list, NULL, NULL, BoundNetLog());
+ if (rv != net::OK) {
+ LOG(ERROR) << "Failed to resolve hostname: " << host_port_pair_.host();
+ return false;
+ }
+ return true;
+}
+
+GURL TestServer::GetURL(const std::string& path) {
+ return GURL(GetScheme() + "://" + host_port_pair_.ToString() +
+ "/" + path);
+}
+
+GURL TestServer::GetURLWithUser(const std::string& path,
+ const std::string& user) {
+ return GURL(GetScheme() + "://" + user + "@" +
+ host_port_pair_.ToString() +
+ "/" + path);
+}
+
+GURL TestServer::GetURLWithUserAndPassword(const std::string& path,
+ const std::string& user,
+ const std::string& password) {
+ return GURL(GetScheme() + "://" + user + ":" + password +
+ "@" + host_port_pair_.ToString() +
+ "/" + path);
}
-FilePath TestServerLauncher::GetOKCertPath() {
- FilePath path(cert_dir_);
- path = path.AppendASCII("ok_cert.pem");
- return path;
+bool TestServer::SetPythonPath() {
+ FilePath third_party_dir;
+ if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) {
+ LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
+ return false;
+ }
+ third_party_dir = third_party_dir.Append(FILE_PATH_LITERAL("third_party"));
+
+ AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("tlslite")));
+ AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("pyftpdlib")));
+
+ // Locate the Python code generated by the protocol buffers compiler.
+ FilePath generated_code_dir;
+ if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
+ LOG(ERROR) << "Failed to get DIR_EXE";
+ return false;
+ }
+ generated_code_dir = generated_code_dir.Append(FILE_PATH_LITERAL("pyproto"));
+ AppendToPythonPath(generated_code_dir);
+ AppendToPythonPath(generated_code_dir.Append(FILE_PATH_LITERAL("sync_pb")));
+
+ return true;
}
-FilePath TestServerLauncher::GetExpiredCertPath() {
- FilePath path(cert_dir_);
- path = path.AppendASCII("expired_cert.pem");
- return path;
+FilePath TestServer::GetRootCertificatePath() {
+ return certificates_dir_.AppendASCII("root_ca_cert.crt");
}
-bool TestServerLauncher::LoadTestRootCert() {
+bool TestServer::LoadTestRootCert() {
#if defined(USE_NSS)
if (cert_)
return true;
@@ -313,11 +274,10 @@ bool TestServerLauncher::LoadTestRootCert() {
// 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(GetRootCertPath());
- DCHECK(cert_);
+ cert_ = LoadTemporaryRootCert(GetRootCertificatePath());
return (cert_ != NULL);
#elif defined(OS_MACOSX)
- X509Certificate* cert = LoadTemporaryRootCert(GetRootCertPath());
+ X509Certificate* cert = LoadTemporaryRootCert(GetRootCertificatePath());
if (!cert)
return false;
SetMacTestCertificate(cert);
@@ -327,88 +287,21 @@ bool TestServerLauncher::LoadTestRootCert() {
#endif
}
-bool TestServerLauncher::CheckCATrusted() {
-#if defined(OS_WIN)
- 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,
- kCertIssuerName,
- 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;
+FilePath TestServer::GetCertificatePath() {
+ switch (type_) {
+ case TYPE_FTP:
+ case TYPE_HTTP:
+ return FilePath();
+ case TYPE_HTTPS:
+ case TYPE_HTTPS_CLIENT_AUTH:
+ case TYPE_HTTPS_MISMATCHED_HOSTNAME:
+ return certificates_dir_.AppendASCII("ok_cert.pem");
+ case TYPE_HTTPS_EXPIRED_CERTIFICATE:
+ return certificates_dir_.AppendASCII("expired_cert.pem");
+ default:
+ NOTREACHED();
}
-#endif
- return true;
+ return FilePath();
}
-#if defined(OS_WIN)
-bool LaunchTestServerAsJob(const std::wstring& cmdline,
- bool start_hidden,
- base::ProcessHandle* process_handle,
- ScopedHandle* job_handle) {
- // Launch test server process.
- STARTUPINFO startup_info = {0};
- startup_info.cb = sizeof(startup_info);
- startup_info.dwFlags = STARTF_USESHOWWINDOW;
- startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW;
- PROCESS_INFORMATION process_info;
-
- // If this code is run under a debugger, the test server process is
- // automatically associated with a job object created by the debugger.
- // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
- if (!CreateProcess(NULL,
- const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
- FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL,
- &startup_info, &process_info)) {
- LOG(ERROR) << "Could not create process.";
- return false;
- }
- CloseHandle(process_info.hThread);
-
- // If the caller wants the process handle, we won't close it.
- if (process_handle) {
- *process_handle = process_info.hProcess;
- } else {
- CloseHandle(process_info.hProcess);
- }
-
- // Create a JobObject and associate the test server process with it.
- job_handle->Set(CreateJobObject(NULL, NULL));
- if (!job_handle->IsValid()) {
- LOG(ERROR) << "Could not create JobObject.";
- return false;
- } else {
- JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0};
- limit_info.BasicLimitInformation.LimitFlags =
- JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
- if (0 == SetInformationJobObject(job_handle->Get(),
- JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info))) {
- LOG(ERROR) << "Could not SetInformationJobObject.";
- return false;
- }
- if (0 == AssignProcessToJobObject(job_handle->Get(),
- process_info.hProcess)) {
- LOG(ERROR) << "Could not AssignProcessToObject.";
- return false;
- }
- }
- return true;
-}
-#endif
-
} // namespace net
diff --git a/net/test/test_server.h b/net/test/test_server.h
index 25f2c8b..6baaaec 100644
--- a/net/test/test_server.h
+++ b/net/test/test_server.h
@@ -4,13 +4,17 @@
#ifndef NET_TEST_TEST_SERVER_H_
#define NET_TEST_TEST_SERVER_H_
+#pragma once
#include "build/build_config.h"
#include <string>
+#include "base/compiler_specific.h"
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/process_util.h"
+#include "net/base/host_port_pair.h"
#if defined(OS_WIN)
#include "base/scoped_handle_win.h"
@@ -21,44 +25,29 @@
#include "net/base/x509_certificate.h"
#endif
+class GURL;
+
namespace net {
-// This object bounds the lifetime of an external python-based HTTP/HTTPS/FTP
-// server that can provide various responses useful for testing.
-// A few basic convenience methods are provided, but no
-// URL handling methods (those belong at a higher layer, e.g. in
-// url_request_unittest.h).
+class AddressList;
-class TestServerLauncher {
+// This object bounds the lifetime of an external python-based HTTP/FTP server
+// that can provide various responses useful for testing.
+class TestServer {
public:
- TestServerLauncher();
- TestServerLauncher(int connection_attempts, int connection_timeout);
-
- virtual ~TestServerLauncher();
-
- enum Protocol {
- ProtoHTTP, ProtoFTP
+ enum Type {
+ TYPE_FTP,
+ TYPE_HTTP,
+ TYPE_HTTPS,
+ TYPE_HTTPS_CLIENT_AUTH,
+ TYPE_HTTPS_MISMATCHED_HOSTNAME,
+ TYPE_HTTPS_EXPIRED_CERTIFICATE,
};
- // Load the test root cert, if it hasn't been loaded yet.
- bool LoadTestRootCert();
-
- // Tells the server to enable/disable servicing each request
- // in a separate process. Takes effect only if called before Start.
- void set_forking(bool forking) { forking_ = forking; }
-
- // Start src/net/tools/testserver/testserver.py and
- // ask it to serve the given protocol.
- // If protocol is HTTP, and cert_path is not empty, serves HTTPS.
- // file_root_url specifies the root url on the server that documents will be
- // served out of. This is /files/ by default.
- // Returns true on success, false if files not found or root cert
- // not trusted.
- bool Start(net::TestServerLauncher::Protocol protocol,
- const std::string& host_name, int port,
- const FilePath& document_root,
- const FilePath& cert_path,
- const std::wstring& file_root_url);
+ TestServer(Type type, const FilePath& document_root);
+ ~TestServer();
+
+ bool Start() WARN_UNUSED_RESULT;
// Stop the server started by Start().
bool Stop();
@@ -67,82 +56,79 @@ class TestServerLauncher {
// without a call to Stop().
// WaitToFinish is handy in that case.
// It returns true if the server exited cleanly.
- bool WaitToFinish(int milliseconds);
+ bool WaitToFinish(int milliseconds) WARN_UNUSED_RESULT;
- // Paths to a good, an expired, and an invalid server certificate
- // (use as arguments to Start()).
- FilePath GetOKCertPath();
- FilePath GetExpiredCertPath();
+ const FilePath& document_root() const { return document_root_; }
+ const HostPortPair& host_port_pair() const { return host_port_pair_; }
+ std::string GetScheme() const;
+ bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT;
- FilePath GetDocumentRootPath() { return document_root_dir_; }
+ GURL GetURL(const std::string& path);
- // Issuer name of the root cert that should be trusted for the test to work.
- static const wchar_t kCertIssuerName[];
+ GURL GetURLWithUser(const std::string& path,
+ const std::string& user);
- // Hostname to use for test server
- static const char kHostName[];
-
- // Different hostname to use for test server (that still resolves to same IP)
- static const char kMismatchedHostName[];
-
- // Port to use for test server
- static const int kOKHTTPSPort;
-
- // Port to use for bad test server
- static const int kBadHTTPSPort;
+ GURL GetURLWithUserAndPassword(const std::string& path,
+ const std::string& user,
+ const std::string& password);
private:
- // Wait a while for the server to start, return whether
- // we were able to make a connection to it.
- bool WaitToStart(const std::string& host_name, int port);
+ // Modify PYTHONPATH to contain libraries we need.
+ bool SetPythonPath() WARN_UNUSED_RESULT;
+
+ // Launches the Python test server. Returns true on success.
+ bool LaunchPython(const FilePath& testserver_path) WARN_UNUSED_RESULT;
- // Append to PYTHONPATH so Python can find pyftpdlib and tlslite.
- void SetPythonPath();
+ // Waits for the server to start. Returns true on success.
+ bool WaitToStart() WARN_UNUSED_RESULT;
- // Path to our test root certificate.
- FilePath GetRootCertPath();
+ // Returns path to the root certificate.
+ FilePath GetRootCertificatePath();
// Returns false if our test root certificate is not trusted.
- bool CheckCATrusted();
+ bool CheckCATrusted() WARN_UNUSED_RESULT;
- // Initilize the certificate path.
- void InitCertPath();
+ // Load the test root cert, if it hasn't been loaded yet.
+ bool LoadTestRootCert() WARN_UNUSED_RESULT;
+
+ // Returns path to the SSL certificate we should use, or empty path
+ // if not applicable.
+ FilePath GetCertificatePath();
- FilePath document_root_dir_;
+ // Document root of the test server.
+ FilePath document_root_;
- FilePath cert_dir_;
+ // Directory that contains the SSL certificates.
+ FilePath certificates_dir_;
- FilePath python_runtime_;
+ // Address the test server listens on.
+ HostPortPair host_port_pair_;
+ // Handle of the Python process running the test server.
base::ProcessHandle process_handle_;
#if defined(OS_WIN)
// JobObject used to clean up orphaned child processes.
ScopedHandle job_handle_;
-#endif
- // True if the server should handle each request in a separate process.
- bool forking_;
+ // The file handle the child writes to when it starts.
+ ScopedHandle child_fd_;
+#endif
- // Number of tries and timeout for each try used for WaitToStart.
- int connection_attempts_;
- int connection_timeout_;
+#if defined(OS_POSIX)
+ // The file descriptor the child writes to when it starts.
+ int child_fd_;
+ file_util::ScopedFD child_fd_closer_;
+#endif
#if defined(USE_NSS)
scoped_refptr<X509Certificate> cert_;
#endif
- DISALLOW_COPY_AND_ASSIGN(TestServerLauncher);
-};
+ Type type_;
-#if defined(OS_WIN)
-// Launch test server as a job so that it is not orphaned if the test case is
-// abnormally terminated.
-bool LaunchTestServerAsJob(const std::wstring& cmdline,
- bool start_hidden,
- base::ProcessHandle* process_handle,
- ScopedHandle* job_handle);
-#endif
+ DISALLOW_COPY_AND_ASSIGN(TestServer);
+};
} // namespace net
diff --git a/net/third_party/mozilla_security_manager/nsKeygenHandler.cpp b/net/third_party/mozilla_security_manager/nsKeygenHandler.cpp
index ffef66d..99d5206 100644
--- a/net/third_party/mozilla_security_manager/nsKeygenHandler.cpp
+++ b/net/third_party/mozilla_security_manager/nsKeygenHandler.cpp
@@ -48,9 +48,11 @@
#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
#include "base/base64.h"
+#include "base/logging.h"
#include "base/nss_util_internal.h"
#include "base/nss_util.h"
-#include "base/logging.h"
+#include "base/string_util.h"
+#include "googleurl/src/gurl.h"
namespace {
@@ -94,6 +96,7 @@ namespace mozilla_security_manager {
// in mozilla/security/manager/ssl/src/nsKeygenHandler.cpp.
std::string GenKeyAndSignChallenge(int key_size_in_bits,
const std::string& challenge,
+ const GURL& url,
bool stores_key) {
// Key pair generation mechanism - only RSA is supported at present.
PRUint32 keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // from nss/pkcs11t.h
@@ -171,6 +174,18 @@ std::string GenKeyAndSignChallenge(int key_size_in_bits,
goto failure;
}
+ // Set friendly names for the keys.
+ if (url.has_host()) {
+ // TODO(davidben): Use something like "Key generated for
+ // example.com", but localize it.
+ const std::string& label = url.host();
+ {
+ base::AutoNSSWriteLock lock;
+ PK11_SetPublicKeyNickname(publicKey, label.c_str());
+ PK11_SetPrivateKeyNickname(privateKey, label.c_str());
+ }
+ }
+
// The CA expects the signed public key in a specific format
// Let's create that now.
diff --git a/net/third_party/mozilla_security_manager/nsKeygenHandler.h b/net/third_party/mozilla_security_manager/nsKeygenHandler.h
index 75703bb..ae1f5a3 100644
--- a/net/third_party/mozilla_security_manager/nsKeygenHandler.h
+++ b/net/third_party/mozilla_security_manager/nsKeygenHandler.h
@@ -42,6 +42,8 @@
#include <string>
+class GURL;
+
namespace mozilla_security_manager {
#define DEFAULT_RSA_KEYGEN_PE 65537L
@@ -52,9 +54,11 @@ namespace mozilla_security_manager {
// Parameters:
// key_size_in_bits: key size in bits (usually 2048)
// challenge: challenge string sent by server
+// url: the URL which requested the SPKAC
// stores_key: should the generated key pair be stored persistently?
std::string GenKeyAndSignChallenge(int key_size_in_bits,
const std::string& challenge,
+ const GURL& url,
bool stores_key);
} // namespace mozilla_security_manager
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium
index b1141fe..ce137bd 100644
--- a/net/third_party/nss/README.chromium
+++ b/net/third_party/nss/README.chromium
@@ -4,7 +4,7 @@ URL: http://www.mozilla.org/projects/security/pki/nss/
This directory includes a copy of NSS's libssl from the CVS repo at:
:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
-The snapshot was updated to the CVS tag: NSS_3_12_6_RC0
+The snapshot was updated to the CVS tag: NSS_3_12_7_RTM
Patches:
@@ -14,6 +14,8 @@ Patches:
* False start support
patches/falsestart.patch
+ patches/falsestart2.patch
+ https://bugzilla.mozilla.org/show_bug.cgi?id=525092
* Commenting out a couple of functions because they need NSS symbols
which may not exist in the system NSS library.
@@ -28,5 +30,11 @@ Patches:
they're available when we resume a session.
patches/cachecerts.patch
+ * Add the SSL_ERROR_WEAK_SERVER_KEY error code for a weak server key in
+ the Server Key Exchange handshake message.
+ patches/weakserverkey.patch
+ http://crbug.com/51694
+ https://bugzilla.mozilla.org/show_bug.cgi?id=587234
+
The ssl/bodge directory contains files taken from the NSS repo that we required
for building libssl outside of its usual build environment.
diff --git a/net/third_party/nss/patches/falsestart.patch b/net/third_party/nss/patches/falsestart.patch
index 6a71159..a1975c6 100644
--- a/net/third_party/nss/patches/falsestart.patch
+++ b/net/third_party/nss/patches/falsestart.patch
@@ -1,10 +1,10 @@
Index: mozilla/security/nss/cmd/strsclnt/strsclnt.c
===================================================================
RCS file: /cvsroot/mozilla/security/nss/cmd/strsclnt/strsclnt.c,v
-retrieving revision 1.66
-diff -u -p -r1.66 strsclnt.c
---- mozilla/security/nss/cmd/strsclnt/strsclnt.c 10 Feb 2010 18:07:20 -0000 1.66
-+++ mozilla/security/nss/cmd/strsclnt/strsclnt.c 16 Mar 2010 01:25:41 -0000
+retrieving revision 1.67
+diff -u -p -r1.67 strsclnt.c
+--- mozilla/security/nss/cmd/strsclnt/strsclnt.c 3 Apr 2010 18:27:28 -0000 1.67
++++ mozilla/security/nss/cmd/strsclnt/strsclnt.c 29 Jul 2010 01:49:04 -0000
@@ -162,6 +162,7 @@ static PRBool disableLocking = PR_FALSE
static PRBool ignoreErrors = PR_FALSE;
static PRBool enableSessionTickets = PR_FALSE;
@@ -60,7 +60,7 @@ RCS file: /cvsroot/mozilla/security/nss/cmd/tstclnt/tstclnt.c,v
retrieving revision 1.62
diff -u -p -r1.62 tstclnt.c
--- mozilla/security/nss/cmd/tstclnt/tstclnt.c 10 Feb 2010 18:07:21 -0000 1.62
-+++ mozilla/security/nss/cmd/tstclnt/tstclnt.c 16 Mar 2010 01:25:41 -0000
++++ mozilla/security/nss/cmd/tstclnt/tstclnt.c 29 Jul 2010 01:49:04 -0000
@@ -225,6 +225,7 @@ static void Usage(const char *progName)
fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N");
fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
@@ -117,14 +117,14 @@ RCS file: /cvsroot/mozilla/security/nss/lib/ssl/ssl.h,v
retrieving revision 1.38
diff -u -p -r1.38 ssl.h
--- mozilla/security/nss/lib/ssl/ssl.h 17 Feb 2010 02:29:07 -0000 1.38
-+++ mozilla/security/nss/lib/ssl/ssl.h 16 Mar 2010 01:25:41 -0000
++++ mozilla/security/nss/lib/ssl/ssl.h 29 Jul 2010 01:49:04 -0000
@@ -128,6 +128,17 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFi
/* Renegotiation Info (RI) */
/* extension in ALL handshakes. */
/* default: off */
-+#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */
-+ /* default, applies only to */
-+ /* clients). False start is a */
++#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */
++ /* default, applies only to */
++ /* clients). False start is a */
+/* mode where an SSL client will start sending application data before */
+/* verifying the server's Finished message. This means that we could end up */
+/* sending data to an imposter. However, the data will be encrypted and */
@@ -139,11 +139,11 @@ diff -u -p -r1.38 ssl.h
Index: mozilla/security/nss/lib/ssl/ssl3con.c
===================================================================
RCS file: /cvsroot/mozilla/security/nss/lib/ssl/ssl3con.c,v
-retrieving revision 1.136
-diff -u -p -r1.136 ssl3con.c
---- mozilla/security/nss/lib/ssl/ssl3con.c 17 Feb 2010 02:29:07 -0000 1.136
-+++ mozilla/security/nss/lib/ssl/ssl3con.c 16 Mar 2010 01:25:41 -0000
-@@ -5656,7 +5656,17 @@ ssl3_RestartHandshakeAfterCertReq(sslSoc
+retrieving revision 1.142
+diff -u -p -r1.142 ssl3con.c
+--- mozilla/security/nss/lib/ssl/ssl3con.c 24 Jun 2010 19:53:20 -0000 1.142
++++ mozilla/security/nss/lib/ssl/ssl3con.c 29 Jul 2010 01:49:04 -0000
+@@ -5665,7 +5665,17 @@ ssl3_RestartHandshakeAfterCertReq(sslSoc
return rv;
}
@@ -162,12 +162,12 @@ diff -u -p -r1.136 ssl3con.c
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 Server Hello Done message.
-@@ -5728,6 +5738,12 @@ ssl3_HandleServerHelloDone(sslSocket *ss
+@@ -5737,6 +5747,12 @@ ssl3_HandleServerHelloDone(sslSocket *ss
ss->ssl3.hs.ws = wait_new_session_ticket;
else
ss->ssl3.hs.ws = wait_change_cipher;
+
-+ /* Do the handshake callback for sslv3 here. */
++ /* Do the handshake callback for sslv3 here, if we can false start. */
+ if (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) {
+ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+ }
@@ -175,11 +175,13 @@ diff -u -p -r1.136 ssl3con.c
return SECSuccess;
loser:
-@@ -8468,7 +8484,7 @@ xmit_loser:
+@@ -8476,8 +8492,8 @@ xmit_loser:
+ }
ss->ssl3.hs.ws = idle_handshake;
- /* Do the handshake callback for sslv3 here. */
+- /* Do the handshake callback for sslv3 here. */
- if (ss->handshakeCallback != NULL) {
++ /* Do the handshake callback for sslv3 here, if we cannot false start. */
+ if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) {
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}
@@ -190,7 +192,7 @@ RCS file: /cvsroot/mozilla/security/nss/lib/ssl/ssl3gthr.c,v
retrieving revision 1.9
diff -u -p -r1.9 ssl3gthr.c
--- mozilla/security/nss/lib/ssl/ssl3gthr.c 20 Nov 2008 07:37:25 -0000 1.9
-+++ mozilla/security/nss/lib/ssl/ssl3gthr.c 16 Mar 2010 01:25:41 -0000
++++ mozilla/security/nss/lib/ssl/ssl3gthr.c 29 Jul 2010 01:49:04 -0000
@@ -188,6 +188,7 @@ ssl3_GatherCompleteHandshake(sslSocket *
{
SSL3Ciphertext cText;
@@ -227,7 +229,7 @@ RCS file: /cvsroot/mozilla/security/nss/lib/ssl/sslimpl.h,v
retrieving revision 1.77
diff -u -p -r1.77 sslimpl.h
--- mozilla/security/nss/lib/ssl/sslimpl.h 10 Feb 2010 00:33:50 -0000 1.77
-+++ mozilla/security/nss/lib/ssl/sslimpl.h 16 Mar 2010 01:25:41 -0000
++++ mozilla/security/nss/lib/ssl/sslimpl.h 29 Jul 2010 01:49:04 -0000
@@ -333,6 +333,7 @@ typedef struct sslOptionsStr {
unsigned int enableDeflate : 1; /* 19 */
unsigned int enableRenegotiation : 2; /* 20-21 */
@@ -251,7 +253,7 @@ RCS file: /cvsroot/mozilla/security/nss/lib/ssl/sslsecur.c,v
retrieving revision 1.43
diff -u -p -r1.43 sslsecur.c
--- mozilla/security/nss/lib/ssl/sslsecur.c 14 Jan 2010 22:15:25 -0000 1.43
-+++ mozilla/security/nss/lib/ssl/sslsecur.c 16 Mar 2010 01:25:41 -0000
++++ mozilla/security/nss/lib/ssl/sslsecur.c 29 Jul 2010 01:49:04 -0000
@@ -1199,8 +1199,17 @@ ssl_SecureSend(sslSocket *ss, const unsi
ss->writerThread = PR_GetCurrentThread();
/* If any of these is non-zero, the initial handshake is not done. */
@@ -274,10 +276,10 @@ diff -u -p -r1.43 sslsecur.c
Index: mozilla/security/nss/lib/ssl/sslsock.c
===================================================================
RCS file: /cvsroot/mozilla/security/nss/lib/ssl/sslsock.c,v
-retrieving revision 1.66
-diff -u -p -r1.66 sslsock.c
---- mozilla/security/nss/lib/ssl/sslsock.c 26 Feb 2010 20:44:54 -0000 1.66
-+++ mozilla/security/nss/lib/ssl/sslsock.c 16 Mar 2010 01:25:41 -0000
+retrieving revision 1.67
+diff -u -p -r1.67 sslsock.c
+--- mozilla/security/nss/lib/ssl/sslsock.c 25 Apr 2010 23:37:38 -0000 1.67
++++ mozilla/security/nss/lib/ssl/sslsock.c 29 Jul 2010 01:49:04 -0000
@@ -183,6 +183,7 @@ static sslOptions ssl_defaults = {
PR_FALSE, /* enableDeflate */
2, /* enableRenegotiation (default: requires extension) */
@@ -330,16 +332,16 @@ RCS file: /cvsroot/mozilla/security/nss/tests/ssl/sslstress.txt,v
retrieving revision 1.18
diff -u -p -r1.18 sslstress.txt
--- mozilla/security/nss/tests/ssl/sslstress.txt 3 Feb 2010 02:25:36 -0000 1.18
-+++ mozilla/security/nss/tests/ssl/sslstress.txt 16 Mar 2010 01:25:41 -0000
++++ mozilla/security/nss/tests/ssl/sslstress.txt 29 Jul 2010 01:49:04 -0000
@@ -42,9 +42,11 @@
noECC 0 _ -c_1000_-C_A Stress SSL2 RC4 128 with MD5
noECC 0 _ -c_1000_-C_c_-T Stress SSL3 RC4 128 with MD5
noECC 0 _ -c_1000_-C_c Stress TLS RC4 128 with MD5
-+ noECC 0 _ -c_1000_-C_c_-h Stress TLS RC4 128 with MD5 (false start)
++ noECC 0 _ -c_1000_-C_c_-g Stress TLS RC4 128 with MD5 (false start)
noECC 0 -u -2_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket)
noECC 0 -z -2_-c_1000_-C_c_-z Stress TLS RC4 128 with MD5 (compression)
noECC 0 -u_-z -2_-c_1000_-C_c_-u_-z Stress TLS RC4 128 with MD5 (session ticket, compression)
-+ noECC 0 -u_-z -2_-c_1000_-C_c_-u_-z_-h Stress TLS RC4 128 with MD5 (session ticket, compression, false start)
++ noECC 0 -u_-z -2_-c_1000_-C_c_-u_-z_-g Stress TLS RC4 128 with MD5 (session ticket, compression, false start)
SNI 0 -u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI)
#
@@ -347,9 +349,9 @@ diff -u -p -r1.18 sslstress.txt
noECC 0 -r_-r -c_100_-C_c_-N_-n_TestUser Stress TLS RC4 128 with MD5 (no reuse, client auth)
noECC 0 -r_-r_-u -2_-c_100_-C_c_-n_TestUser_-u Stress TLS RC4 128 with MD5 (session ticket, client auth)
noECC 0 -r_-r_-z -2_-c_100_-C_c_-n_TestUser_-z Stress TLS RC4 128 with MD5 (compression, client auth)
-+ noECC 0 -r_-r_-z -2_-c_100_-C_c_-n_TestUser_-z_-h Stress TLS RC4 128 with MD5 (compression, client auth, false start)
++ noECC 0 -r_-r_-z -2_-c_100_-C_c_-n_TestUser_-z_-g Stress TLS RC4 128 with MD5 (compression, client auth, false start)
noECC 0 -r_-r_-u_-z -2_-c_100_-C_c_-n_TestUser_-u_-z Stress TLS RC4 128 with MD5 (session ticket, compression, client auth)
-+ noECC 0 -r_-r_-u_-z -2_-c_100_-C_c_-n_TestUser_-u_-z_-h Stress TLS RC4 128 with MD5 (session ticket, compression, client auth, false start)
++ noECC 0 -r_-r_-u_-z -2_-c_100_-C_c_-n_TestUser_-u_-z_-g Stress TLS RC4 128 with MD5 (session ticket, compression, client auth, false start)
SNI 0 -r_-r_-u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI, client auth, default virt host)
SNI 0 -r_-r_-u_-a_Host-sni.Dom_-k_Host-sni.Dom -2_-3_-c_1000_-C_c_-u_-a_Host-sni.Dom Stress TLS RC4 128 with MD5 (session ticket, SNI, client auth, change virt host)
diff --git a/net/third_party/nss/ssl.gyp b/net/third_party/nss/ssl.gyp
index 3166be8..a804e92 100644
--- a/net/third_party/nss/ssl.gyp
+++ b/net/third_party/nss/ssl.gyp
@@ -28,11 +28,13 @@
'ssl/authcert.c',
'ssl/cmpcert.c',
'ssl/derive.c',
+ 'ssl/fnv1a64.c',
'ssl/nsskea.c',
'ssl/os2_err.c',
'ssl/os2_err.h',
'ssl/preenc.h',
'ssl/prelib.c',
+ 'ssl/snapstart.c',
'ssl/ssl.h',
'ssl/ssl3con.c',
'ssl/ssl3ecc.c',
diff --git a/net/third_party/nss/ssl.target.mk b/net/third_party/nss/ssl.target.mk
index 235d092..663da33 100644
--- a/net/third_party/nss/ssl.target.mk
+++ b/net/third_party/nss/ssl.target.mk
@@ -24,6 +24,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-I/usr/include/nss \
-I/usr/include/nspr \
@@ -62,6 +63,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-I/usr/include/nss \
-I/usr/include/nspr \
@@ -83,8 +85,10 @@ INCS_Release := -Inet/third_party/nss/ssl/bodge
OBJS := $(obj).target/$(TARGET)/net/third_party/nss/ssl/authcert.o \
$(obj).target/$(TARGET)/net/third_party/nss/ssl/cmpcert.o \
$(obj).target/$(TARGET)/net/third_party/nss/ssl/derive.o \
+ $(obj).target/$(TARGET)/net/third_party/nss/ssl/fnv1a64.o \
$(obj).target/$(TARGET)/net/third_party/nss/ssl/nsskea.o \
$(obj).target/$(TARGET)/net/third_party/nss/ssl/prelib.o \
+ $(obj).target/$(TARGET)/net/third_party/nss/ssl/snapstart.o \
$(obj).target/$(TARGET)/net/third_party/nss/ssl/ssl3con.o \
$(obj).target/$(TARGET)/net/third_party/nss/ssl/ssl3ecc.o \
$(obj).target/$(TARGET)/net/third_party/nss/ssl/ssl3ext.o \
@@ -133,11 +137,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lnss3 \
diff --git a/net/third_party/nss/ssl/Makefile b/net/third_party/nss/ssl/Makefile
index 3949fb4..a777569 100644
--- a/net/third_party/nss/ssl/Makefile
+++ b/net/third_party/nss/ssl/Makefile
@@ -71,11 +71,6 @@ CSRCS += unix_err.c
endif
endif
-ifdef USE_SYSTEM_ZLIB
-DEFINES += -DNSS_ENABLE_ZLIB
-EXTRA_LIBS += $(ZLIB_LIBS)
-endif
-
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
diff --git a/net/third_party/nss/ssl/ssl.def b/net/third_party/nss/ssl/ssl.def
index a1f4b51..effc35d 100644
--- a/net/third_party/nss/ssl/ssl.def
+++ b/net/third_party/nss/ssl/ssl.def
@@ -159,3 +159,13 @@ SSL_SetNextProtoNego;
;+ local:
;+*;
;+};
+;+NSS_3.13 { # NSS 3.13 release
+;+ global:
+SSL_GetPredictedServerHelloData;
+SSL_GetSnapStartResult;
+SSL_SetPredictedPeerCertificates;
+SSL_SetPredictedServerHelloData;
+SSL_SetSnapStartApplicationData;
+;+ local:
+;+*;
+;+};
diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
index 0bc02f8..8217d2e 100644
--- a/net/third_party/nss/ssl/ssl.h
+++ b/net/third_party/nss/ssl/ssl.h
@@ -36,7 +36,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: ssl.h,v 1.36 2010/02/10 18:07:21 wtc%google.com Exp $ */
+/* $Id: ssl.h,v 1.38 2010/02/17 02:29:07 wtc%google.com Exp $ */
#ifndef __ssl_h_
#define __ssl_h_
@@ -123,14 +123,14 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
#define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */
/* DEFLATE (off by default) */
#define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */
-#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signalling */
+#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signaling */
/* Cipher Suite Value (SCSV) or */
/* Renegotiation Info (RI) */
/* extension in ALL handshakes. */
/* default: off */
-#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */
- /* default, applies only to */
- /* clients). False start is a */
+#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */
+ /* default, applies only to */
+ /* clients). False start is a */
/* mode where an SSL client will start sending application data before */
/* verifying the server's Finished message. This means that we could end up */
/* sending data to an imposter. However, the data will be encrypted and */
@@ -139,6 +139,15 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
/* occur on RSA or DH ciphersuites where the cipher's key length is >= 80 */
/* bits. The advantage of False Start is that it saves a round trip for */
/* client-speaks-first protocols when performing a full handshake. */
+#define SSL_ENABLE_SNAP_START 23 /* Enable SSL snap start (off by */
+ /* default, applies only to */
+ /* clients). Snap start is a way */
+/* of performing TLS handshakes with no round trips. The client's entire */
+/* handshake is included in the first handshake message, along with */
+/* optional application data. In order to do this, information from a */
+/* previous connection to the same server is required. See */
+/* SSL_GetPredictedServerHelloData, SSL_SetPredictedPeerCertificates and */
+/* SSL_SetSnapStartApplicationData. */
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
@@ -207,9 +216,11 @@ SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy);
/* Only renegotiate if the peer's hello bears the TLS renegotiation_info */
/* extension. This is safe renegotiation. */
#define SSL_RENEGOTIATE_REQUIRES_XTN ((PRBool)2)
-/* Disallow all renegotiation in server sockets only, but allow clients */
+/* Disallow unsafe renegotiation in server sockets only, but allow clients */
/* to continue to renegotiate with vulnerable servers. */
-#define SSL_RENEGOTIATE_CLIENT_ONLY ((PRBool)3)
+/* This value should only be used during the transition period when few */
+/* servers have been upgraded. */
+#define SSL_RENEGOTIATE_TRANSITIONAL ((PRBool)3)
/*
** Reset the handshake state for fd. This will make the complete SSL
@@ -374,6 +385,49 @@ SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f,
void *arg);
/*
+** Set the predicted chain of certificates for the peer. This is used for the
+** TLS Snap Start extension. Note that the SSL_ENABLE_SNAP_START option must
+** be set for this to occur.
+**
+** This function takes a reference to each of the given certificates.
+*/
+SSL_IMPORT SECStatus SSL_SetPredictedPeerCertificates(
+ PRFileDesc *fd, CERTCertificate **certs,
+ unsigned int numCerts);
+
+/*
+** Get the data needed to predict the server's hello message in the future. On
+** return, |*data| will either be NULL (in which case no data is available and
+** |*data_len| will be zero) or it will point to a buffer within the internal
+** data of |fd| and |*data_len| will contain the number of bytes available. If
+** non-NULL, |*data| will persist at least until the next handshake on |fd|.
+*/
+SSL_IMPORT SECStatus SSL_GetPredictedServerHelloData(
+ PRFileDesc *fd, const unsigned char **data,
+ unsigned int *data_len);
+
+/*
+** Set the predicted server hello data. This is used for the TLS Snap Start
+** extension. Note that the SSL_ENABLE_SNAP_START option must be set for this
+** to occur.
+*/
+SSL_IMPORT SECStatus SSL_SetPredictedServerHelloData(
+ PRFileDesc *fd, const unsigned char *data, unsigned int data_len);
+
+/* Set the application data which will be transmitted in a Snap Start
+** handshake. If the Snap Start handshake fails, this data will be
+* retransmitted automatically. */
+SSL_IMPORT SECStatus SSL_SetSnapStartApplicationData(
+ PRFileDesc *fd, const unsigned char *data, unsigned int data_len);
+
+/* Get the result of a Snap Start handshake. It's valid to call then even if
+** SSL_ENABLE_SNAP_START hasn't been set, although the result will always be
+** SSL_SNAP_START_NONE.
+*/
+SSL_IMPORT SECStatus SSL_GetSnapStartResult(PRFileDesc* socket,
+ SSLSnapStartResult* result);
+
+/*
** Configure SSL socket for running a secure server. Needs the
** certificate for the server and the servers private key. The arguments
** are copied.
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index 9b671e7..9ab2a1c 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -39,7 +39,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: ssl3con.c,v 1.134 2010/02/03 03:44:29 wtc%google.com Exp $ */
+/* $Id: ssl3con.c,v 1.142 2010/06/24 19:53:20 wtc%google.com Exp $ */
#include "cert.h"
#include "ssl.h"
@@ -72,7 +72,8 @@
#endif
static void ssl3_CleanupPeerCerts(sslSocket *ss);
-static void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid);
+static void ssl3_CopyPeerCertsToSID(ssl3CertNode *certs,
+ sslSessionID *sid);
static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
PK11SlotInfo * serverKeySlot);
static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms);
@@ -82,14 +83,10 @@ static SECStatus ssl3_InitState( sslSocket *ss);
static SECStatus ssl3_SendCertificate( sslSocket *ss);
static SECStatus ssl3_SendEmptyCertificate( sslSocket *ss);
static SECStatus ssl3_SendCertificateRequest(sslSocket *ss);
-static SECStatus ssl3_SendNextProto( sslSocket *ss);
-static SECStatus ssl3_SendFinished( sslSocket *ss, PRInt32 flags);
static SECStatus ssl3_SendServerHello( sslSocket *ss);
static SECStatus ssl3_SendServerHelloDone( sslSocket *ss);
static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss);
static SECStatus ssl3_NewHandshakeHashes( sslSocket *ss);
-static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss, unsigned char *b,
- unsigned int l);
static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
int maxOutputLen, const unsigned char *input,
@@ -573,17 +570,17 @@ typedef struct tooLongStr {
void SSL_AtomicIncrementLong(long * x)
{
if ((sizeof *x) == sizeof(PRInt32)) {
- PR_AtomicIncrement((PRInt32 *)x);
+ PR_ATOMIC_INCREMENT((PRInt32 *)x);
} else {
tooLong * tl = (tooLong *)x;
- if (PR_AtomicIncrement(&tl->low) == 0)
- PR_AtomicIncrement(&tl->high);
+ if (PR_ATOMIC_INCREMENT(&tl->low) == 0)
+ PR_ATOMIC_INCREMENT(&tl->high);
}
}
/* return pointer to ssl3CipherSuiteDef for suite, or NULL */
/* XXX This does a linear search. A binary search would be better. */
-static const ssl3CipherSuiteDef *
+const ssl3CipherSuiteDef *
ssl_LookupCipherSuiteDef(ssl3CipherSuite suite)
{
int cipher_suite_def_len =
@@ -1169,7 +1166,7 @@ ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat)
** ssl3_DestroySSL3Info
** Caller must hold SpecWriteLock.
*/
-static void
+void
ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
{
PRBool freeit = (PRBool)(!spec->bypassCiphers);
@@ -1211,7 +1208,7 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
** Caller must hold the ssl3 handshake lock.
** Acquires & releases SpecWriteLock.
*/
-static SECStatus
+SECStatus
ssl3_SetupPendingCipherSpec(sslSocket *ss)
{
ssl3CipherSpec * pwSpec;
@@ -2039,7 +2036,7 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) {
return isPresent;
}
-static SECStatus
+SECStatus
ssl3_CompressMACEncryptRecord(sslSocket * ss,
SSL3ContentType type,
const SSL3Opaque * pIn,
@@ -2617,7 +2614,8 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
case unexpected_message: error = SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT;
break;
case bad_record_mac: error = SSL_ERROR_BAD_MAC_ALERT; break;
- case decryption_failed: error = SSL_ERROR_DECRYPTION_FAILED_ALERT;
+ case decryption_failed_RESERVED:
+ error = SSL_ERROR_DECRYPTION_FAILED_ALERT;
break;
case record_overflow: error = SSL_ERROR_RECORD_OVERFLOW_ALERT; break;
case decompression_failure: error = SSL_ERROR_DECOMPRESSION_FAILURE_ALERT;
@@ -3096,7 +3094,7 @@ loser:
return SECFailure;
}
-static SECStatus
+SECStatus
ssl3_RestartHandshakeHashes(sslSocket *ss)
{
SECStatus rv = SECSuccess;
@@ -3174,7 +3172,7 @@ loser:
** ssl3_HandleHandshakeMessage()
** Caller must hold the ssl3Handshake lock.
*/
-static SECStatus
+SECStatus
ssl3_UpdateHandshakeHashes(sslSocket *ss, unsigned char *b, unsigned int l)
{
SECStatus rv = SECSuccess;
@@ -3433,7 +3431,7 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes,
* Caller must hold a read or write lock on the Spec R/W lock.
* (There is presently no way to assert on a Read lock.)
*/
-static SECStatus
+SECStatus
ssl3_ComputeHandshakeHashes(sslSocket * ss,
ssl3CipherSpec *spec, /* uses ->master_secret */
SSL3Hashes * hashes, /* output goes here. */
@@ -3957,7 +3955,7 @@ ssl3_SendClientHello(sslSocket *ss)
if (ss->ssl3.hs.sendingSCSV) {
/* Add the actual SCSV */
- rv = ssl3_AppendHandshakeNumber(ss, TLS_RENEGO_PROTECTION_REQUEST,
+ rv = ssl3_AppendHandshakeNumber(ss, TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
sizeof(ssl3CipherSuite));
if (rv != SECSuccess) {
return rv; /* err set by ssl3_AppendHandshake* */
@@ -4031,7 +4029,18 @@ ssl3_SendClientHello(sslSocket *ss)
return rv; /* error code set by ssl3_FlushHandshake */
}
- ss->ssl3.hs.ws = wait_server_hello;
+ switch (ss->ssl3.hs.snapStartType) {
+ case snap_start_full:
+ ss->ssl3.hs.ws = wait_new_session_ticket;
+ break;
+ case snap_start_resume:
+ ss->ssl3.hs.ws = wait_change_cipher;
+ break;
+ default:
+ ss->ssl3.hs.ws = wait_server_hello;
+ break;
+ }
+
return rv;
}
@@ -4722,7 +4731,7 @@ loser:
/* Called from ssl3_HandleServerHelloDone(). */
-static SECStatus
+SECStatus
ssl3_SendClientKeyExchange(sslSocket *ss)
{
SECKEYPublicKey * serverKey = NULL;
@@ -4861,6 +4870,94 @@ done:
return rv;
}
+/* Called from ssl3_HandleServerHello to set up the master secret in
+ * ss->ssl3.pwSpec and the auth algorithm and kea type in ss->sec in the case
+ * of a successful session resumption. */
+SECStatus ssl3_SetupMasterSecretFromSessionID(sslSocket* ss) {
+ sslSessionID *sid = ss->sec.ci.sid;
+ ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+ SECItem wrappedMS; /* wrapped master secret. */
+
+ ss->sec.authAlgorithm = sid->authAlgorithm;
+ ss->sec.authKeyBits = sid->authKeyBits;
+ ss->sec.keaType = sid->keaType;
+ ss->sec.keaKeyBits = sid->keaKeyBits;
+
+ /* 3 cases here:
+ * a) key is wrapped (implies using PKCS11)
+ * b) key is unwrapped, but we're still using PKCS11
+ * c) key is unwrapped, and we're bypassing PKCS11.
+ */
+ if (sid->u.ssl3.keys.msIsWrapped) {
+ PK11SlotInfo *slot;
+ PK11SymKey * wrapKey; /* wrapping key */
+ CK_FLAGS keyFlags = 0;
+
+ if (ss->opt.bypassPKCS11) {
+ /* we cannot restart a non-bypass session in a
+ ** bypass socket.
+ */
+ return SECFailure;
+ }
+ /* unwrap master secret with PKCS11 */
+ slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
+ sid->u.ssl3.masterSlotID);
+ if (slot == NULL) {
+ return SECFailure;
+ }
+ if (!PK11_IsPresent(slot)) {
+ PK11_FreeSlot(slot);
+ return SECFailure;
+ }
+ wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex,
+ sid->u.ssl3.masterWrapMech,
+ sid->u.ssl3.masterWrapSeries,
+ ss->pkcs11PinArg);
+ PK11_FreeSlot(slot);
+ if (wrapKey == NULL) {
+ return SECFailure;
+ }
+
+ if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
+ keyFlags = CKF_SIGN | CKF_VERIFY;
+ }
+
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ pwSpec->master_secret =
+ PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
+ NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+ CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags);
+ PK11_FreeSymKey(wrapKey);
+ if (pwSpec->master_secret == NULL) {
+ return SECFailure;
+ }
+ } else if (ss->opt.bypassPKCS11) {
+ /* MS is not wrapped */
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len);
+ pwSpec->msItem.data = pwSpec->raw_master_secret;
+ pwSpec->msItem.len = wrappedMS.len;
+ } else {
+ /* We CAN restart a bypass session in a non-bypass socket. */
+ /* need to import the raw master secret to session object */
+ PK11SlotInfo *slot = PK11_GetInternalSlot();
+ wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+ wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
+ pwSpec->master_secret =
+ PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE,
+ PK11_OriginUnwrap, CKA_ENCRYPT,
+ &wrappedMS, NULL);
+ PK11_FreeSlot(slot);
+ if (pwSpec->master_secret == NULL) {
+ return SECFailure;
+ }
+ }
+
+ return SECSuccess;
+}
+
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 ServerHello message.
* Caller must hold Handshake and RecvBuf locks.
@@ -4885,6 +4982,14 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ if (ss->ssl3.hs.snapStartType == snap_start_full ||
+ ss->ssl3.hs.snapStartType == snap_start_resume) {
+ /* Snap Start handshake was rejected. */
+ rv = ssl3_ResetForSnapStartRecovery(ss, b, length);
+ if (rv != SECSuccess)
+ return rv;
+ }
+
rv = ssl3_InitState(ss);
if (rv != SECSuccess) {
errCode = PORT_GetError(); /* ssl3_InitState has set the error code. */
@@ -4896,6 +5001,21 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
goto alert_loser;
}
+ if (!ss->ssl3.serverHelloPredictionData.data) {
+ /* If this allocation fails it will only stop the application from
+ * recording the ServerHello information and performing future Snap
+ * Starts. */
+ if (SECITEM_AllocItem(NULL, &ss->ssl3.serverHelloPredictionData,
+ length))
+ memcpy(ss->ssl3.serverHelloPredictionData.data, b, length);
+ /* ss->ssl3.serverHelloPredictionDataValid is still false at this
+ * point. We have to record the contents of the ServerHello here
+ * because we don't have a pointer to the whole message when handling
+ * the extensions. However, we wait until the Snap Start extenion
+ * handler to recognise that the server supports Snap Start and to set
+ * serverHelloPredictionDataValid. */
+ }
+
temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
if (temp < 0) {
goto loser; /* alert has been sent */
@@ -5036,118 +5156,40 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
if (sid_match &&
sid->version == ss->version &&
- sid->u.ssl3.cipherSuite == ss->ssl3.hs.cipher_suite) do {
- ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+ sid->u.ssl3.cipherSuite == ss->ssl3.hs.cipher_suite) {
+ rv = ssl3_SetupMasterSecretFromSessionID(ss);
+ /* Failure of ssl3_SetupMasterSecretFromSessionID not considered an
+ * error. Continue with a full handshake. */
+ if (rv == SECSuccess) {
+ /* Got a Match */
+ SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_hits );
- SECItem wrappedMS; /* wrapped master secret. */
+ /* If we sent a session ticket, then this is a stateless resume. */
+ if (sid->version > SSL_LIBRARY_VERSION_3_0 &&
+ sid->u.ssl3.sessionTicket.ticket.data != NULL)
+ SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_stateless_resumes );
- ss->sec.authAlgorithm = sid->authAlgorithm;
- ss->sec.authKeyBits = sid->authKeyBits;
- ss->sec.keaType = sid->keaType;
- ss->sec.keaKeyBits = sid->keaKeyBits;
+ if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
+ ss->ssl3.hs.ws = wait_new_session_ticket;
+ else
+ ss->ssl3.hs.ws = wait_change_cipher;
- /* 3 cases here:
- * a) key is wrapped (implies using PKCS11)
- * b) key is unwrapped, but we're still using PKCS11
- * c) key is unwrapped, and we're bypassing PKCS11.
- */
- if (sid->u.ssl3.keys.msIsWrapped) {
- PK11SlotInfo *slot;
- PK11SymKey * wrapKey; /* wrapping key */
- CK_FLAGS keyFlags = 0;
+ ss->ssl3.hs.isResuming = PR_TRUE;
- if (ss->opt.bypassPKCS11) {
- /* we cannot restart a non-bypass session in a
- ** bypass socket.
- */
- break;
- }
- /* unwrap master secret with PKCS11 */
- slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
- sid->u.ssl3.masterSlotID);
- if (slot == NULL) {
- break; /* not considered an error. */
- }
- if (!PK11_IsPresent(slot)) {
- PK11_FreeSlot(slot);
- break; /* not considered an error. */
- }
- wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex,
- sid->u.ssl3.masterWrapMech,
- sid->u.ssl3.masterWrapSeries,
- ss->pkcs11PinArg);
- PK11_FreeSlot(slot);
- if (wrapKey == NULL) {
- break; /* not considered an error. */
+ /* copy the peer cert from the SID */
+ if (sid->peerCert != NULL) {
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ ssl3_CopyPeerCertsFromSID(ss, sid);
}
- if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
- keyFlags = CKF_SIGN | CKF_VERIFY;
- }
-
- wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
- wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
- pwSpec->master_secret =
- PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
- NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
- CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags);
- errCode = PORT_GetError();
- PK11_FreeSymKey(wrapKey);
- if (pwSpec->master_secret == NULL) {
- break; /* errorCode set just after call to UnwrapSymKey. */
- }
- } else if (ss->opt.bypassPKCS11) {
- /* MS is not wrapped */
- wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
- wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
- memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len);
- pwSpec->msItem.data = pwSpec->raw_master_secret;
- pwSpec->msItem.len = wrappedMS.len;
- } else {
- /* We CAN restart a bypass session in a non-bypass socket. */
- /* need to import the raw master secret to session object */
- PK11SlotInfo *slot = PK11_GetInternalSlot();
- wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
- wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
- pwSpec->master_secret =
- PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE,
- PK11_OriginUnwrap, CKA_ENCRYPT,
- &wrappedMS, NULL);
- PK11_FreeSlot(slot);
- if (pwSpec->master_secret == NULL) {
- break;
+ /* NULL value for PMS signifies re-use of the old MS */
+ rv = ssl3_InitPendingCipherSpec(ss, NULL);
+ if (rv != SECSuccess) {
+ goto alert_loser;
}
+ return SECSuccess;
}
-
- /* Got a Match */
- SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_hits );
-
- /* If we sent a session ticket, then this is a stateless resume. */
- if (sid->version > SSL_LIBRARY_VERSION_3_0 &&
- sid->u.ssl3.sessionTicket.ticket.data != NULL)
- SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_stateless_resumes );
-
- if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
- ss->ssl3.hs.ws = wait_new_session_ticket;
- else
- ss->ssl3.hs.ws = wait_change_cipher;
-
- ss->ssl3.hs.isResuming = PR_TRUE;
-
- /* copy the peer cert from the SID */
- if (sid->peerCert != NULL) {
- ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
- ssl3_CopyPeerCertsFromSID(ss, sid);
- }
-
-
- /* NULL value for PMS signifies re-use of the old MS */
- rv = ssl3_InitPendingCipherSpec(ss, NULL);
- if (rv != SECSuccess) {
- goto alert_loser; /* err code was set */
- }
- return SECSuccess;
- } while (0);
+ }
if (sid_match)
SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_not_ok );
@@ -5304,14 +5346,24 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
if (rv != SECSuccess) {
goto loser; /* malformed. */
}
+ if (dh_p.len < 512/8) {
+ errCode = SSL_ERROR_WEAK_SERVER_KEY;
+ goto alert_loser;
+ }
rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
}
+ if (dh_g.len == 0 || dh_g.len > dh_p.len + 1 ||
+ (dh_g.len == 1 && dh_g.data[0] == 0))
+ goto alert_loser;
rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
}
+ if (dh_Ys.len == 0 || dh_Ys.len > dh_p.len + 1 ||
+ (dh_Ys.len == 1 && dh_Ys.data[0] == 0))
+ goto alert_loser;
rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
@@ -5748,7 +5800,7 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
else
ss->ssl3.hs.ws = wait_change_cipher;
- /* Do the handshake callback for sslv3 here. */
+ /* Do the handshake callback for sslv3 here, if we can false start. */
if (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) {
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}
@@ -5998,8 +6050,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
goto alert_loser;
}
if (ss->ssl3.hs.ws == idle_handshake &&
- (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER ||
- ss->opt.enableRenegotiation == SSL_RENEGOTIATE_CLIENT_ONLY)) {
+ ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
desc = no_renegotiation;
level = alert_warning;
errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
@@ -6075,7 +6126,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
*/
for (i = 0; i + 1 < suites.len; i += 2) {
PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1];
- if (suite_i == TLS_RENEGO_PROTECTION_REQUEST) {
+ if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext;
PRUint32 L2 = sizeof emptyRIext;
(void)ssl3_HandleHelloExtensions(ss, &b2, &L2);
@@ -6084,7 +6135,8 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
}
}
if (ss->firstHsDone &&
- ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN &&
+ (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN ||
+ ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) &&
!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
desc = no_renegotiation;
level = alert_warning;
@@ -6105,7 +6157,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
* ticket extension, but sent an empty ticket.
*/
if (!ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) ||
- ss->xtnData.emptySessionTicket) {
+ ss->xtnData.serverReceivedEmptySessionTicket) {
if (sidBytes.len > 0 && !ss->opt.noCache) {
SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x",
SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0],
@@ -6790,7 +6842,7 @@ suite_found:
*/
for (i = 0; i+2 < suite_length; i += 3) {
PRUint32 suite_i = (suites[i] << 16) | (suites[i+1] << 8) | suites[i+2];
- if (suite_i == TLS_RENEGO_PROTECTION_REQUEST) {
+ if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
SSL3Opaque * b2 = (SSL3Opaque *)emptyRIext;
PRUint32 L2 = sizeof emptyRIext;
(void)ssl3_HandleHelloExtensions(ss, &b2, &L2);
@@ -7558,6 +7610,12 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
return SECFailure; /* malformed */
}
+ if (ss->sec.ci.sid->peerCert == NULL) {
+ ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
+ ssl3_CopyPeerCertsToSID((ssl3CertNode *)ss->ssl3.peerCertChain,
+ ss->sec.ci.sid);
+ }
+
rv = ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &session_ticket);
if (rv != SECSuccess) {
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
@@ -7591,7 +7649,7 @@ get_fake_cert(SECItem *pCertItem, int *pIndex)
}
*pIndex = (NULL != strstr(testdir, "root"));
extension = (strstr(testdir, "simple") ? "" : ".der");
- fileNum = PR_AtomicIncrement(&connNum) - 1;
+ fileNum = PR_ATOMIC_INCREMENT(&connNum) - 1;
if ((startat = PR_GetEnv("START_AT")) != NULL) {
fileNum += atoi(startat);
}
@@ -7749,7 +7807,7 @@ ssl3_CleanupPeerCerts(sslSocket *ss)
ss->ssl3.peerCertChain = NULL;
}
-static void
+void
ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid)
{
PRArenaPool *arena;
@@ -8152,7 +8210,7 @@ ssl3_RestartHandshakeAfterServerCert(sslSocket *ss)
return rv;
}
-static SECStatus
+SECStatus
ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
PRBool isServer,
const SSL3Finished * hashes,
@@ -8200,7 +8258,7 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
/* called from ssl3_HandleServerHelloDone
*/
-static SECStatus
+SECStatus
ssl3_SendNextProto(sslSocket *ss)
{
SECStatus rv;
@@ -8236,7 +8294,7 @@ ssl3_SendNextProto(sslSocket *ss)
* ssl3_HandleClientHello
* ssl3_HandleFinished
*/
-static SECStatus
+SECStatus
ssl3_SendFinished(sslSocket *ss, PRInt32 flags)
{
ssl3CipherSpec *cwSpec;
@@ -8289,10 +8347,27 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags)
if (rv != SECSuccess)
goto fail; /* err set by AppendHandshake. */
}
- rv = ssl3_FlushHandshake(ss, flags);
- if (rv != SECSuccess) {
- goto fail; /* error code set by ssl3_FlushHandshake */
+ if ((flags & ssl_SEND_FLAG_NO_FLUSH) == 0) {
+ rv = ssl3_FlushHandshake(ss, flags);
+ if (rv != SECSuccess) {
+ goto fail; /* error code set by ssl3_FlushHandshake */
+ }
+ }
+
+ if ((ss->ssl3.hs.snapStartType == snap_start_recovery ||
+ ss->ssl3.hs.snapStartType == snap_start_resume_recovery) &&
+ ss->ssl3.snapStartApplicationData.data) {
+ /* In the event that the server ignored the application data in our
+ * snap start extension, we need to retransmit it now. */
+ PRInt32 sent = ssl3_SendRecord(ss, content_application_data,
+ ss->ssl3.snapStartApplicationData.data,
+ ss->ssl3.snapStartApplicationData.len,
+ flags);
+ SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE);
+ if (sent < 0)
+ return (SECStatus)sent; /* error code set by ssl3_SendRecord */
}
+
return SECSuccess;
fail:
@@ -8409,6 +8484,16 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
return SECFailure;
}
+ if (ss->ssl3.hs.snapStartType == snap_start_full ||
+ ss->ssl3.hs.snapStartType == snap_start_resume) {
+ /* Snap Start handshake was successful. Switch the cipher spec. */
+ ssl_GetSpecWriteLock(ss);
+ ssl3_DestroyCipherSpec(ss->ssl3.cwSpec, PR_TRUE/*freeSrvName*/);
+ ss->ssl3.cwSpec = ss->ssl3.pwSpec;
+ ss->ssl3.pwSpec = NULL;
+ ssl_ReleaseSpecWriteLock(ss);
+ }
+
isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0);
if (isTLS) {
TLSFinished tlsFinished;
@@ -8418,12 +8503,21 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
return SECFailure;
}
- rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer,
- hashes, &tlsFinished);
- if (!isServer)
- ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
- else
- ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
+
+ if (ss->ssl3.hs.snapStartType == snap_start_resume) {
+ /* In this case we have already advanced the Finished hash past the
+ * server's verify_data because we needed to predict the server's
+ * Finished message in order to compute our own (which includes
+ * it). When we did this, we stored a copy in tFinished[1]. */
+ tlsFinished = ss->ssl3.hs.finishedMsgs.tFinished[1];
+ } else {
+ rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer,
+ hashes, &tlsFinished);
+ if (!isServer)
+ ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
+ else
+ ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
+ }
ss->ssl3.hs.finishedBytes = sizeof tlsFinished;
if (rv != SECSuccess ||
0 != NSS_SecureMemcmp(&tlsFinished, b, length)) {
@@ -8454,8 +8548,9 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
ssl_GetXmitBufLock(ss); /*************************************/
- if ((isServer && !ss->ssl3.hs.isResuming) ||
- (!isServer && ss->ssl3.hs.isResuming)) {
+ if (ss->ssl3.hs.snapStartType != snap_start_resume &&
+ ((isServer && !ss->ssl3.hs.isResuming) ||
+ (!isServer && ss->ssl3.hs.isResuming))) {
PRInt32 flags = 0;
/* Send a NewSessionTicket message if the client sent us
@@ -8570,8 +8665,11 @@ xmit_loser:
}
ss->ssl3.hs.ws = idle_handshake;
- /* Do the handshake callback for sslv3 here. */
- if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) {
+ /* Do the handshake callback for sslv3 here, if we cannot false start. */
+ if (ss->handshakeCallback != NULL &&
+ (!ssl3_CanFalseStart(ss) ||
+ ss->ssl3.hs.snapStartType == snap_start_full ||
+ ss->ssl3.hs.snapStartType == snap_start_resume)) {
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}
@@ -8632,8 +8730,13 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
return rv;
}
}
- /* We should not include hello_request messages in the handshake hashes */
- if (ss->ssl3.hs.msg_type != hello_request) {
+ /* We should not include hello_request messages in the handshake hashes.
+ * Likewise, for Finished messages from the server during a Snap Start
+ * resume, we have already predicted and included the message in our
+ * Finished hash. */
+ if (ss->ssl3.hs.msg_type != hello_request &&
+ !(ss->ssl3.hs.msg_type == finished &&
+ ss->ssl3.hs.snapStartType == snap_start_resume)) {
rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) hdr, 4);
if (rv != SECSuccess) return rv; /* err code already set. */
rv = ssl3_UpdateHandshakeHashes(ss, b, length);
@@ -8973,27 +9076,29 @@ const ssl3BulkCipherDef *cipher_def;
PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
if (rv != SECSuccess) {
- int err = ssl_MapLowLevelError(SSL_ERROR_DECRYPTION_FAILURE);
- ssl_ReleaseSpecReadLock(ss);
- SSL3_SendAlert(ss, alert_fatal,
- isTLS ? decryption_failed : bad_record_mac);
- PORT_SetError(err);
- return SECFailure;
+ /* All decryption failures must be treated like a bad record
+ * MAC; see RFC 5246 (TLS 1.2).
+ */
+ padIsBad = PR_TRUE;
}
/* If it's a block cipher, check and strip the padding. */
- if (cipher_def->type == type_block) {
- padding_length = *(plaintext->buf + plaintext->len - 1);
+ if (cipher_def->type == type_block && !padIsBad) {
+ PRUint8 * pPaddingLen = plaintext->buf + plaintext->len - 1;
+ padding_length = *pPaddingLen;
/* TLS permits padding to exceed the block size, up to 255 bytes. */
if (padding_length + 1 + crSpec->mac_size > plaintext->len)
padIsBad = PR_TRUE;
- /* if TLS, check value of first padding byte. */
- else if (padding_length && isTLS &&
- padding_length != *(plaintext->buf +
- plaintext->len - (padding_length + 1)))
- padIsBad = PR_TRUE;
- else
- plaintext->len -= padding_length + 1;
+ else {
+ plaintext->len -= padding_length + 1;
+ /* In TLS all padding bytes must be equal to the padding length. */
+ if (isTLS) {
+ PRUint8 *p;
+ for (p = pPaddingLen - padding_length; p < pPaddingLen; ++p) {
+ padIsBad |= *p ^ padding_length;
+ }
+ }
+ }
}
/* Remove the MAC. */
@@ -9008,11 +9113,7 @@ const ssl3BulkCipherDef *cipher_def;
rType, cText->version, crSpec->read_seq_num,
plaintext->buf, plaintext->len, hash, &hashBytes);
if (rv != SECSuccess) {
- int err = ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
- ssl_ReleaseSpecReadLock(ss);
- SSL3_SendAlert(ss, alert_fatal, bad_record_mac);
- PORT_SetError(err);
- return rv;
+ padIsBad = PR_TRUE; /* really macIsBad */
}
/* Check the MAC */
@@ -9111,7 +9212,11 @@ const ssl3BulkCipherDef *cipher_def;
** function, not by this function.
*/
if (rType == content_application_data) {
- return SECSuccess;
+ if (ss->firstHsDone)
+ return SECSuccess;
+ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
+ return SECFailure;
}
/* It's a record that must be handled by ssl itself, not the application.
@@ -9270,14 +9375,14 @@ ssl3_NewKeyPair( SECKEYPrivateKey * privKey, SECKEYPublicKey * pubKey)
ssl3KeyPair *
ssl3_GetKeyPairRef(ssl3KeyPair * keyPair)
{
- PR_AtomicIncrement(&keyPair->refCount);
+ PR_ATOMIC_INCREMENT(&keyPair->refCount);
return keyPair;
}
void
ssl3_FreeKeyPair(ssl3KeyPair * keyPair)
{
- PRInt32 newCount = PR_AtomicDecrement(&keyPair->refCount);
+ PRInt32 newCount = PR_ATOMIC_DECREMENT(&keyPair->refCount);
if (!newCount) {
if (keyPair->privKey)
SECKEY_DestroyPrivateKey(keyPair->privKey);
@@ -9493,9 +9598,7 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache)
PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
return SECFailure;
}
- if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER ||
- (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_CLIENT_ONLY &&
- ss->sec.isServer)) {
+ if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
return SECFailure;
}
@@ -9534,6 +9637,15 @@ ssl3_DestroySSL3Info(sslSocket *ss)
ss->ssl3.clientCertChain = NULL;
}
+ if (ss->ssl3.predictedCertChain != NULL)
+ ssl3_CleanupPredictedPeerCertificates(ss);
+
+ if (ss->ssl3.serverHelloPredictionData.data)
+ SECITEM_FreeItem(&ss->ssl3.serverHelloPredictionData, PR_FALSE);
+
+ if (ss->ssl3.snapStartApplicationData.data)
+ SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE);
+
/* clean up handshake */
if (ss->opt.bypassPKCS11) {
SHA1_DestroyContext((SHA1Context *)ss->ssl3.hs.sha_cx, PR_FALSE);
@@ -9551,6 +9663,9 @@ ssl3_DestroySSL3Info(sslSocket *ss)
ss->ssl3.hs.messages.len = 0;
ss->ssl3.hs.messages.space = 0;
}
+ if (ss->ssl3.hs.origClientHello.data) {
+ SECITEM_FreeItem(&ss->ssl3.hs.origClientHello, PR_FALSE);
+ }
/* free the SSL3Buffer (msg_body) */
PORT_Free(ss->ssl3.hs.msg_body.buf);
diff --git a/net/third_party/nss/ssl/ssl3ecc.c b/net/third_party/nss/ssl/ssl3ecc.c
index 42720e5..778c7ab 100644
--- a/net/third_party/nss/ssl/ssl3ecc.c
+++ b/net/third_party/nss/ssl/ssl3ecc.c
@@ -40,7 +40,7 @@
* ***** END LICENSE BLOCK ***** */
/* ECC code moved here from ssl3con.c */
-/* $Id: ssl3ecc.c,v 1.23 2010/01/28 16:14:25 kaie%kuix.de Exp $ */
+/* $Id: ssl3ecc.c,v 1.24 2010/03/15 08:03:14 nelson%bolyard.com Exp $ */
#include "nss.h"
#include "cert.h"
@@ -288,7 +288,7 @@ ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint,
PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH));
PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH));
- if (hashBuf != buf && hashBuf != NULL)
+ if (hashBuf != buf)
PORT_Free(hashBuf);
return rv;
}
diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c
index ead0cfd..a7ae062 100644
--- a/net/third_party/nss/ssl/ssl3ext.c
+++ b/net/third_party/nss/ssl/ssl3ext.c
@@ -41,7 +41,7 @@
* ***** END LICENSE BLOCK ***** */
/* TLS extension code moved here from ssl3ecc.c */
-/* $Id: ssl3ext.c,v 1.11 2010/02/03 02:38:20 wtc%google.com Exp $ */
+/* $Id: ssl3ext.c,v 1.14 2010/04/03 19:19:07 nelson%bolyard.com Exp $ */
#include "nssrenam.h"
#include "nss.h"
@@ -247,6 +247,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
{ ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn },
{ ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
{ ssl_next_proto_neg_xtn, &ssl3_ClientHandleNextProtoNegoXtn },
+ { ssl_snap_start_xtn, &ssl3_ClientHandleSnapStartXtn },
{ -1, NULL }
};
@@ -270,7 +271,9 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
{ ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
#endif
{ ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
- { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn }
+ { ssl_next_proto_neg_xtn, &ssl3_ClientSendNextProtoNegoXtn },
+ { ssl_snap_start_xtn, &ssl3_SendSnapStartXtn }
+ /* NOTE: The Snap Start sender MUST be the last extension in the list. */
/* any extra entries will appear as { 0, NULL } */
};
@@ -298,7 +301,7 @@ ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type) {
xtnData->numNegotiated, ex_type);
}
-static PRBool
+PRBool
ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) {
TLSExtensionData *xtnData = &ss->xtnData;
return arrayContainsExtension(xtnData->advertised,
@@ -314,12 +317,14 @@ ssl3_SendServerNameXtn(sslSocket * ss, PRBool append,
PRUint32 maxBytes)
{
SECStatus rv;
+ if (!ss)
+ return 0;
if (!ss->sec.isServer) {
PRUint32 len;
PRNetAddr netAddr;
/* must have a hostname */
- if (!ss || !ss->url || !ss->url[0])
+ if (!ss->url || !ss->url[0])
return 0;
/* must not be an IPv4 or IPv6 address */
if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) {
@@ -513,6 +518,8 @@ ssl3_SendSessionTicketXtn(
rv = ssl3_AppendHandshakeVariable(ss, session_ticket->ticket.data,
session_ticket->ticket.len, 2);
ss->xtnData.ticketTimestampVerified = PR_FALSE;
+ if (!ss->sec.isServer)
+ ss->xtnData.clientSentNonEmptySessionTicket = PR_TRUE;
} else {
rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
}
@@ -571,7 +578,7 @@ ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned short length)
SECStatus
ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
- SECItem *data)
+ SECItem *data)
{
unsigned int i, j;
SECStatus rv;
@@ -1019,7 +1026,7 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
* instead of terminating the current connection.
*/
if (data->len == 0) {
- ss->xtnData.emptySessionTicket = PR_TRUE;
+ ss->xtnData.serverReceivedEmptySessionTicket = PR_TRUE;
} else {
int i;
SECItem extension_data;
@@ -1621,8 +1628,8 @@ ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
data->data[0] != len || (len &&
NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data,
data->data + 1, len))) {
- /* Can we do this here? Or, must we arrange for the caller to do it? */
- (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+ /* Can we do this here? Or, must we arrange for the caller to do it? */
+ (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
return SECFailure;
}
diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h
index c82c891..f3c950e 100644
--- a/net/third_party/nss/ssl/ssl3prot.h
+++ b/net/third_party/nss/ssl/ssl3prot.h
@@ -38,7 +38,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: ssl3prot.h,v 1.18 2010/02/03 02:25:35 alexei.volkov.bugs%sun.com Exp $ */
+/* $Id: ssl3prot.h,v 1.19 2010/06/24 09:24:18 nelson%bolyard.com Exp $ */
#ifndef __ssl3proto_h_
#define __ssl3proto_h_
@@ -108,7 +108,7 @@ typedef enum {
close_notify = 0,
unexpected_message = 10,
bad_record_mac = 20,
- decryption_failed = 21, /* TLS only */
+ decryption_failed_RESERVED = 21, /* do not send; see RFC 5246 */
record_overflow = 22, /* TLS only */
decompression_failure = 30,
handshake_failure = 40,
diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c
index 742765c..39c630d 100644
--- a/net/third_party/nss/ssl/sslauth.c
+++ b/net/third_party/nss/ssl/sslauth.c
@@ -92,6 +92,7 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
sslSocket *ss;
const char *cipherName;
PRBool isDes = PR_FALSE;
+ PRBool enoughFirstHsDone = PR_FALSE;
ss = ssl_FindSocket(fd);
if (!ss) {
@@ -109,8 +110,14 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
*op = SSL_SECURITY_STATUS_OFF;
}
- if (ss->opt.useSecurity && ss->firstHsDone) {
+ if (ss->firstHsDone) {
+ enoughFirstHsDone = PR_TRUE;
+ } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+ ssl3_CanFalseStart(ss)) {
+ enoughFirstHsDone = PR_TRUE;
+ }
+ if (ss->opt.useSecurity && enoughFirstHsDone) {
if (ss->version < SSL_LIBRARY_VERSION_3_0) {
cipherName = ssl_cipherName[ss->sec.cipherType];
} else {
diff --git a/net/third_party/nss/ssl/sslcon.c b/net/third_party/nss/ssl/sslcon.c
index c02b315..4e34554 100644
--- a/net/third_party/nss/ssl/sslcon.c
+++ b/net/third_party/nss/ssl/sslcon.c
@@ -37,7 +37,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: sslcon.c,v 1.39 2010/02/04 03:08:44 wtc%google.com Exp $ */
+/* $Id: sslcon.c,v 1.40 2010/04/25 23:37:38 nelson%bolyard.com Exp $ */
#include "nssrenam.h"
#include "cert.h"
@@ -1861,7 +1861,7 @@ ssl2_ChooseSessionCypher(sslSocket *ss,
}
preferred = ss->preferredCipher ? ss->preferredCipher : noneSuch;
/*
- ** Scan list of ciphers recieved from peer and look for a match in
+ ** Scan list of ciphers received from peer and look for a match in
** our list.
* Note: Our list may contain SSL v3 ciphers.
* We MUST NOT match on any of those.
diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h
index 61b721c..bd72f97 100644
--- a/net/third_party/nss/ssl/sslerr.h
+++ b/net/third_party/nss/ssl/sslerr.h
@@ -36,7 +36,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: sslerr.h,v 1.10 2010/02/03 03:44:29 wtc%google.com Exp $ */
+/* $Id: sslerr.h,v 1.11 2010/06/24 09:24:18 nelson%bolyard.com Exp $ */
#ifndef __SSL_ERR_H_
#define __SSL_ERR_H_
@@ -149,7 +149,7 @@ SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 68),
SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE = (SSL_ERROR_BASE + 69),
SSL_ERROR_ENCRYPTION_FAILURE = (SSL_ERROR_BASE + 70),
-SSL_ERROR_DECRYPTION_FAILURE = (SSL_ERROR_BASE + 71),
+SSL_ERROR_DECRYPTION_FAILURE = (SSL_ERROR_BASE + 71), /* don't use */
SSL_ERROR_SOCKET_WRITE_FAILURE = (SSL_ERROR_BASE + 72),
SSL_ERROR_MD5_DIGEST_FAILURE = (SSL_ERROR_BASE + 73),
@@ -201,6 +201,8 @@ SSL_ERROR_UNSAFE_NEGOTIATION = (SSL_ERROR_BASE + 113),
SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD = (SSL_ERROR_BASE + 114),
+SSL_ERROR_WEAK_SERVER_KEY = (SSL_ERROR_BASE + 115),
+
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/net/third_party/nss/ssl/sslgathr.c b/net/third_party/nss/ssl/sslgathr.c
index 23f52a2..92c0e8a 100644
--- a/net/third_party/nss/ssl/sslgathr.c
+++ b/net/third_party/nss/ssl/sslgathr.c
@@ -36,7 +36,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: sslgathr.c,v 1.10 2009/10/16 17:45:35 wtc%google.com Exp $ */
+/* $Id: sslgathr.c,v 1.12 2010/04/25 23:37:38 nelson%bolyard.com Exp $ */
#include "cert.h"
#include "ssl.h"
#include "sslimpl.h"
@@ -272,7 +272,7 @@ ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags)
goto spec_locked_done;
}
- /* Decrypt the portion of data that we just recieved.
+ /* Decrypt the portion of data that we just received.
** Decrypt it in place.
*/
rv = (*ss->sec.dec)(ss->sec.readcx, pBuf, &nout, gs->offset,
@@ -303,25 +303,25 @@ ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags)
gs->offset - macLen);
(*ss->sec.hash->update)(ss->sec.hashcx, seq, 4);
(*ss->sec.hash->end)(ss->sec.hashcx, mac, &macLen, macLen);
- }
- PORT_Assert(macLen == ss->sec.hash->length);
+ PORT_Assert(macLen == ss->sec.hash->length);
- ssl_ReleaseSpecReadLock(ss); /******************************/
+ ssl_ReleaseSpecReadLock(ss); /******************************/
- if (NSS_SecureMemcmp(mac, pBuf, macLen) != 0) {
- /* MAC's didn't match... */
- SSL_DBG(("%d: SSL[%d]: mac check failed, seq=%d",
- SSL_GETPID(), ss->fd, ss->sec.rcvSequence));
- PRINT_BUF(1, (ss, "computed mac:", mac, macLen));
- PRINT_BUF(1, (ss, "received mac:", pBuf, macLen));
- PORT_SetError(SSL_ERROR_BAD_MAC_READ);
- rv = SECFailure;
- goto cleanup;
+ if (NSS_SecureMemcmp(mac, pBuf, macLen) != 0) {
+ /* MAC's didn't match... */
+ SSL_DBG(("%d: SSL[%d]: mac check failed, seq=%d",
+ SSL_GETPID(), ss->fd, ss->sec.rcvSequence));
+ PRINT_BUF(1, (ss, "computed mac:", mac, macLen));
+ PRINT_BUF(1, (ss, "received mac:", pBuf, macLen));
+ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+ rv = SECFailure;
+ goto cleanup;
+ }
+ } else {
+ ssl_ReleaseSpecReadLock(ss); /******************************/
}
-
- PORT_Assert(gs->recordPadding + macLen <= gs->offset);
if (gs->recordPadding + macLen <= gs->offset) {
gs->recordOffset = macLen;
gs->readOffset = macLen;
diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h
index fe7ac7a..f708696 100644
--- a/net/third_party/nss/ssl/sslimpl.h
+++ b/net/third_party/nss/ssl/sslimpl.h
@@ -278,6 +278,7 @@ struct sslSocketOpsStr {
/* Flags interpreted by ssl send functions. */
#define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000
#define ssl_SEND_FLAG_NO_BUFFER 0x20000000
+#define ssl_SEND_FLAG_NO_FLUSH 0x10000000
#define ssl_SEND_FLAG_MASK 0x7f000000
/*
@@ -339,6 +340,7 @@ typedef struct sslOptionsStr {
unsigned int enableRenegotiation : 2; /* 20-21 */
unsigned int requireSafeNegotiation : 1; /* 22 */
unsigned int enableFalseStart : 1; /* 23 */
+ unsigned int enableSnapStart : 1; /* 24 */
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -743,7 +745,8 @@ struct TLSExtensionDataStr {
/* SessionTicket Extension related data. */
PRBool ticketTimestampVerified;
- PRBool emptySessionTicket;
+ PRBool serverReceivedEmptySessionTicket;
+ PRBool clientSentNonEmptySessionTicket;
/* SNI Extension related data
* Names data is not coppied from the input buffer. It can not be
@@ -753,6 +756,14 @@ struct TLSExtensionDataStr {
PRUint32 sniNameArrSize;
};
+typedef enum {
+ snap_start_none = 0,
+ snap_start_full,
+ snap_start_recovery,
+ snap_start_resume,
+ snap_start_resume_recovery
+} TLSSnapStartType;
+
/*
** This is the "hs" member of the "ssl3" struct.
** This entire struct is protected by ssl3HandshakeLock
@@ -791,6 +802,14 @@ const ssl3CipherSuiteDef *suite_def;
SSL3Hashes sFinished[2];
SSL3Opaque data[72];
} finishedMsgs;
+
+ TLSSnapStartType snapStartType;
+ /* When we perform a Snap Start handshake, we hash our ClientHello as if
+ * the Snap Start extension wasn't included. However, if the server rejects
+ * our Snap Start attempt, then it will hash the whole ClientHello. Thus we
+ * store the original ClientHello that we sent in case we need to reset our
+ * Finished hash to cover it. */
+ SECItem origClientHello;
#ifdef NSS_ENABLE_ECC
PRUint32 negotiatedECCurves; /* bit mask */
#endif /* NSS_ENABLE_ECC */
@@ -823,6 +842,17 @@ struct ssl3StateStr {
CERTCertificateList *clientCertChain; /* used by client */
PRBool sendEmptyCert; /* used by client */
+ /* TLS Snap Start: */
+ CERTCertificate ** predictedCertChain;
+ /* An array terminated with a NULL. */
+ SECItem serverHelloPredictionData;
+ PRBool serverHelloPredictionDataValid;
+ /* data needed to predict the ServerHello from
+ * this server. */
+ SECItem snapStartApplicationData;
+ /* the application data to include in the Snap
+ * Start extension. */
+
int policy;
/* This says what cipher suites we can do, and should
* be either SSL_ALLOWED or SSL_RESTRICTED
@@ -1258,10 +1288,13 @@ extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
const char *peerID, const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
+extern void ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid);
extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
int len, int flags);
+extern SECStatus ssl3_RestartHandshakeHashes(sslSocket *ss);
+
extern PRBool ssl_FdIsBlocking(PRFileDesc *fd);
extern PRBool ssl_SocketIsBlocking(sslSocket *ss);
@@ -1434,6 +1467,9 @@ ECName ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
#endif /* NSS_ENABLE_ECC */
+extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket* ss, unsigned char *b,
+ unsigned int l);
+
extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on);
extern SECStatus ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
@@ -1454,6 +1490,7 @@ extern void ssl3_InitSocketPolicy(sslSocket *ss);
extern SECStatus ssl3_ConstructV2CipherSpecsHack(sslSocket *ss,
unsigned char *cs, int *size);
+extern void ssl3_DestroyCipherSpec(ssl3CipherSpec* spec, PRBool freeSrvName);
extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache);
@@ -1503,6 +1540,31 @@ extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash,
extern SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss,
sslSessionID *sid, ssl3CipherSpec *spec,
SSL3KEAType effectiveExchKeyType);
+extern void ssl3_CleanupPredictedPeerCertificates(sslSocket *ss);
+extern const ssl3CipherSuiteDef* ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
+extern SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss);
+extern SECStatus ssl3_SendClientKeyExchange(sslSocket *ss);
+extern SECStatus ssl3_SendNextProto(sslSocket *ss);
+extern SECStatus ssl3_SendFinished(sslSocket *ss, PRInt32 flags);
+extern SECStatus ssl3_CompressMACEncryptRecord
+ (sslSocket * ss,
+ SSL3ContentType type,
+ const SSL3Opaque * pIn,
+ PRUint32 contentLen);
+extern PRBool ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type);
+extern SECStatus ssl3_SetupMasterSecretFromSessionID(sslSocket* ss);
+extern SECStatus ssl3_ComputeHandshakeHashes(
+ sslSocket * ss,
+ ssl3CipherSpec *spec, /* uses ->master_secret */
+ SSL3Hashes * hashes, /* output goes here. */
+ PRUint32 sender);
+extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket* ss, unsigned char *b,
+ unsigned int l);
+extern SECStatus ssl3_ComputeTLSFinished(
+ ssl3CipherSpec *spec,
+ PRBool isServer,
+ const SSL3Finished * hashes,
+ TLSFinished * tlsFinished);
/* Functions that handle ClientHello and ServerHello extensions. */
extern SECStatus ssl3_HandleServerNameXtn(sslSocket * ss,
@@ -1532,6 +1594,13 @@ extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
*/
extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
PRUint32 maxBytes);
+extern PRInt32 ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append,
+ PRUint32 maxBytes);
+extern SECStatus ssl3_ClientHandleSnapStartXtn(sslSocket *ss, PRUint16 ex_type,
+ SECItem *data);
+
+extern SECStatus ssl3_ResetForSnapStartRecovery(sslSocket *ss,
+ SSL3Opaque *b, PRUint32 length);
/* Assigns new cert, cert chain and keys to ss->serverCerts
* struct. If certChain is NULL, tries to find one. Aborts if
@@ -1635,6 +1704,12 @@ SECStatus SSL_DisableDefaultExportCipherSuites(void);
SECStatus SSL_DisableExportCipherSuites(PRFileDesc * fd);
PRBool SSL_IsExportCipherSuite(PRUint16 cipherSuite);
+/********************** FNV hash *********************/
+
+void FNV1A64_Init(PRUint64 *digest);
+void FNV1A64_Update(PRUint64 *digest, const unsigned char *data,
+ unsigned int length);
+void FNV1A64_Final(PRUint64 *digest);
#ifdef TRACE
#define SSL_TRACE(msg) ssl_Trace msg
diff --git a/net/third_party/nss/ssl/sslinfo.c b/net/third_party/nss/ssl/sslinfo.c
index e4ee35f..c1c3fd7 100644
--- a/net/third_party/nss/ssl/sslinfo.c
+++ b/net/third_party/nss/ssl/sslinfo.c
@@ -60,6 +60,7 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
sslSocket * ss;
SSLChannelInfo inf;
sslSessionID * sid;
+ PRBool enoughFirstHsDone = PR_FALSE;
if (!info || len < sizeof inf.length) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -76,7 +77,14 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
memset(&inf, 0, sizeof inf);
inf.length = PR_MIN(sizeof inf, len);
- if (ss->opt.useSecurity && ss->firstHsDone) {
+ if (ss->firstHsDone) {
+ enoughFirstHsDone = PR_TRUE;
+ } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+ ssl3_CanFalseStart(ss)) {
+ enoughFirstHsDone = PR_TRUE;
+ }
+
+ if (ss->opt.useSecurity && enoughFirstHsDone) {
sid = ss->sec.ci.sid;
inf.protocolVersion = ss->version;
inf.authKeyBits = ss->sec.authKeyBits;
diff --git a/net/third_party/nss/ssl/sslmutex.c b/net/third_party/nss/ssl/sslmutex.c
index 6b5dbd1..8403365 100644
--- a/net/third_party/nss/ssl/sslmutex.c
+++ b/net/third_party/nss/ssl/sslmutex.c
@@ -33,7 +33,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: sslmutex.c,v 1.24 2009/06/05 02:34:14 nelson%bolyard.com Exp $ */
+/* $Id: sslmutex.c,v 1.25 2010/04/03 18:27:33 nelson%bolyard.com Exp $ */
#include "seccomon.h"
/* This ifdef should match the one in sslsnce.c */
@@ -211,7 +211,7 @@ sslMutex_Unlock(sslMutex *pMutex)
return SECFailure;
}
/* Do Memory Barrier here. */
- newValue = PR_AtomicDecrement(&pMutex->u.pipeStr.nWaiters);
+ newValue = PR_ATOMIC_DECREMENT(&pMutex->u.pipeStr.nWaiters);
if (newValue > 0) {
int cc;
char c = 1;
@@ -241,7 +241,7 @@ sslMutex_Lock(sslMutex *pMutex)
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
return SECFailure;
}
- newValue = PR_AtomicIncrement(&pMutex->u.pipeStr.nWaiters);
+ newValue = PR_ATOMIC_INCREMENT(&pMutex->u.pipeStr.nWaiters);
/* Do Memory Barrier here. */
if (newValue > 1) {
int cc;
diff --git a/net/third_party/nss/ssl/sslproto.h b/net/third_party/nss/ssl/sslproto.h
index bf7b71b..b534d0b 100644
--- a/net/third_party/nss/ssl/sslproto.h
+++ b/net/third_party/nss/ssl/sslproto.h
@@ -39,7 +39,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: sslproto.h,v 1.14 2010/01/28 06:19:12 nelson%bolyard.com Exp $ */
+/* $Id: sslproto.h,v 1.15 2010/02/16 18:56:48 wtc%google.com Exp $ */
#ifndef __sslproto_h_
#define __sslproto_h_
@@ -181,11 +181,11 @@
#define TLS_RSA_WITH_SEED_CBC_SHA 0x0096
-/* TLS "Signalling Cipher Suite Value" (SCSV). May be requested by client.
+/* TLS "Signaling Cipher Suite Value" (SCSV). May be requested by client.
* Must NEVER be chosen by server. SSL 3.0 server acknowledges by sending
* back an empty Renegotiation Info (RI) server hello extension.
*/
-#define TLS_RENEGO_PROTECTION_REQUEST 0x00FF
+#define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF
/* Cipher Suite Values starting with 0xC000 are defined in informational
* RFCs.
diff --git a/net/third_party/nss/ssl/sslreveal.c b/net/third_party/nss/ssl/sslreveal.c
index 74f8814..8941ff2 100644
--- a/net/third_party/nss/ssl/sslreveal.c
+++ b/net/third_party/nss/ssl/sslreveal.c
@@ -111,14 +111,26 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
/* some decisions derived from SSL_GetChannelInfo */
sslSocket * sslsocket = NULL;
SECStatus rv = SECFailure;
+ PRBool enoughFirstHsDone = PR_FALSE;
if (!pYes)
return rv;
sslsocket = ssl_FindSocket(socket);
+ if (!sslsocket) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeNegotiatedExtension",
+ SSL_GETPID(), socket));
+ return rv;
+ }
+
+ if (sslsocket->firstHsDone) {
+ enoughFirstHsDone = PR_TRUE;
+ } else if (sslsocket->ssl3.initialized && ssl3_CanFalseStart(sslsocket)) {
+ enoughFirstHsDone = PR_TRUE;
+ }
/* according to public API SSL_GetChannelInfo, this doesn't need a lock */
- if (sslsocket && sslsocket->opt.useSecurity && sslsocket->firstHsDone) {
+ if (sslsocket->opt.useSecurity && enoughFirstHsDone) {
if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */
/* now we know this socket went through ssl3_InitState() and
* ss->xtnData got initialized, which is the only member accessed by
diff --git a/net/third_party/nss/ssl/sslsnce.c b/net/third_party/nss/ssl/sslsnce.c
index 5658dc2..6c73f25 100644
--- a/net/third_party/nss/ssl/sslsnce.c
+++ b/net/third_party/nss/ssl/sslsnce.c
@@ -36,7 +36,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: sslsnce.c,v 1.52 2010/01/14 22:15:25 alexei.volkov.bugs%sun.com Exp $ */
+/* $Id: sslsnce.c,v 1.54 2010/07/05 19:31:56 alexei.volkov.bugs%sun.com Exp $ */
/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
* cache sids!
@@ -820,7 +820,7 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
pcce = 0;
}
}
- if ((cndx = psce->u.ssl3.srvNameIndex) != -1) {
+ if (psce && ((cndx = psce->u.ssl3.srvNameIndex) != -1)) {
PRUint32 gotLock = LockSidCacheLock(cache->srvNameCacheLock,
now);
if (gotLock) {
@@ -1104,8 +1104,8 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
cache->numCertCacheEntries = (maxCertCacheEntries > 0) ?
maxCertCacheEntries : 0;
- cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries > 0) ?
- maxSrvNameCacheEntries : 0;
+ cache->numSrvNameCacheEntries = (maxSrvNameCacheEntries >= 0) ?
+ maxSrvNameCacheEntries : DEF_NAME_CACHE_ENTRIES;
/* compute size of shared memory, and offsets of all pointers */
ptr = 0;
@@ -1168,9 +1168,6 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->srvNameCacheData = (srvNameCacheEntry *)ptr;
- if (cache->numSrvNameCacheEntries < 0) {
- cache->numSrvNameCacheEntries = DEF_NAME_CACHE_ENTRIES;
- }
cache->srvNameCacheSize =
cache->numSrvNameCacheEntries * sizeof(srvNameCacheEntry);
ptr = (ptrdiff_t)(cache->srvNameCacheData + cache->numSrvNameCacheEntries);
diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c
index c4611a0..2898b88 100644
--- a/net/third_party/nss/ssl/sslsock.c
+++ b/net/third_party/nss/ssl/sslsock.c
@@ -40,7 +40,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
-/* $Id: sslsock.c,v 1.64 2010/01/28 06:19:13 nelson%bolyard.com Exp $ */
+/* $Id: sslsock.c,v 1.67 2010/04/25 23:37:38 nelson%bolyard.com Exp $ */
#include "seccomon.h"
#include "cert.h"
#include "keyhi.h"
@@ -329,7 +329,7 @@ ssl_DupSocket(sslSocket *os)
ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL :
ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair);
/*
- * XXX the preceeding CERT_ and SECKEY_ functions can fail and return NULL.
+ * XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL.
* XXX We should detect this, and not just march on with NULL pointers.
*/
ss->authCertificate = os->authCertificate;
@@ -738,6 +738,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
ss->opt.enableFalseStart = on;
break;
+ case SSL_ENABLE_SNAP_START:
+ ss->opt.enableSnapStart = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -802,6 +806,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
case SSL_REQUIRE_SAFE_NEGOTIATION:
on = ss->opt.requireSafeNegotiation; break;
case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break;
+ case SSL_ENABLE_SNAP_START: on = ss->opt.enableSnapStart; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -853,6 +858,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
on = ssl_defaults.requireSafeNegotiation;
break;
case SSL_ENABLE_FALSE_START: on = ssl_defaults.enableFalseStart; break;
+ case SSL_ENABLE_SNAP_START: on = ssl_defaults.enableSnapStart; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1000,6 +1006,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
ssl_defaults.enableFalseStart = on;
break;
+ case SSL_ENABLE_SNAP_START:
+ ssl_defaults.enableSnapStart = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -2390,10 +2400,10 @@ ssl_NewSocket(PRBool makeLocks)
ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_UNRESTRICTED;
else if (ev[0] == '0' || LOWER(ev[0]) == 'n')
ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER;
- else if (ev[0] == '3' || LOWER(ev[0]) == 'c')
- ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_CLIENT_ONLY;
- else
- ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN;
+ else if (ev[0] == '2' || LOWER(ev[0]) == 'r')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN;
+ else if (ev[0] == '3' || LOWER(ev[0]) == 't')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_TRANSITIONAL;
SSL_TRACE(("SSL: enableRenegotiation set to %d",
ssl_defaults.enableRenegotiation));
}
diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h
index f6e0b62..68cbf87 100644
--- a/net/third_party/nss/ssl/sslt.h
+++ b/net/third_party/nss/ssl/sslt.h
@@ -204,9 +204,23 @@ typedef enum {
#endif
ssl_session_ticket_xtn = 35,
ssl_next_proto_neg_xtn = 13172,
+ ssl_snap_start_xtn = 13174,
ssl_renegotiation_info_xtn = 0xff01 /* experimental number */
} SSLExtensionType;
-#define SSL_MAX_EXTENSIONS 6
+#define SSL_MAX_EXTENSIONS 7
+
+typedef enum {
+ /* No Snap Start handshake was attempted. */
+ SSL_SNAP_START_NONE = 0,
+ /* A Snap Start full handshake was completed. */
+ SSL_SNAP_START_FULL = 1,
+ /* A Snap Start full handshake was attempted, but failed. */
+ SSL_SNAP_START_RECOVERY = 2,
+ /* A Snap Start resume handshake was completed. */
+ SSL_SNAP_START_RESUME = 3,
+ /* A Snap Start resume handshake was attempted, but failed. */
+ SSL_SNAP_START_RESUME_RECOVERY = 4
+} SSLSnapStartResult;
#endif /* __sslt_h_ */
diff --git a/net/tld_cleanup.target.mk b/net/tld_cleanup.target.mk
index 982ef8a..aa2b2c0 100644
--- a/net/tld_cleanup.target.mk
+++ b/net/tld_cleanup.target.mk
@@ -19,6 +19,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -65,6 +66,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -128,14 +130,15 @@ LDFLAGS_Debug := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
- -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
- -rdynamic
+ -Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
-Wl,-uIsHeapProfilerRunning,-uProfilerStart \
-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi \
-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS := -lrt \
diff --git a/net/tools/crash_cache/crash_cache.cc b/net/tools/crash_cache/crash_cache.cc
index 1d11013..88d7d87 100644
--- a/net/tools/crash_cache/crash_cache.cc
+++ b/net/tools/crash_cache/crash_cache.cc
@@ -16,8 +16,10 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/disk_cache/backend_impl.h"
@@ -43,7 +45,7 @@ int RunSlave(RankCrashes action) {
PathService::Get(base::FILE_EXE, &exe);
CommandLine cmdline(exe);
- cmdline.AppendLooseValue(ASCIIToWide(IntToString(action)));
+ cmdline.AppendArg(base::IntToString(action));
base::ProcessHandle handle;
if (!base::LaunchApp(cmdline, false, false, &handle)) {
diff --git a/net/tools/dump_cache/cache_dumper.cc b/net/tools/dump_cache/cache_dumper.cc
index f573b2a..9eee058 100644
--- a/net/tools/dump_cache/cache_dumper.cc
+++ b/net/tools/dump_cache/cache_dumper.cc
@@ -4,6 +4,7 @@
#include "net/tools/dump_cache/cache_dumper.h"
+#include "base/utf_string_conversions.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/entry_impl.h"
diff --git a/net/tools/dump_cache/cache_dumper.h b/net/tools/dump_cache/cache_dumper.h
index d2e6034..03c7ac9 100644
--- a/net/tools/dump_cache/cache_dumper.h
+++ b/net/tools/dump_cache/cache_dumper.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_DUMP_CACHE_CACHE_DUMPER_H_
#define NET_TOOLS_DUMP_CACHE_CACHE_DUMPER_H_
+#pragma once
#include <string>
#include "base/file_path.h"
diff --git a/net/tools/dump_cache/dump_cache.cc b/net/tools/dump_cache/dump_cache.cc
index 29caefd..9644aae 100644
--- a/net/tools/dump_cache/dump_cache.cc
+++ b/net/tools/dump_cache/dump_cache.cc
@@ -1,4 +1,4 @@
-// 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.
@@ -13,6 +13,7 @@
#include "base/process_util.h"
#include "base/scoped_handle.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/disk_cache/disk_format.h"
@@ -41,8 +42,8 @@ const char kUpgradeHelp[] =
"executable should be compiled with version 5.2 being the current one.";
// Folders to read and write cache files.
-const wchar_t kInputPath[] = L"input";
-const wchar_t kOutputPath[] = L"output";
+const char kInputPath[] = "input";
+const char kOutputPath[] = "output";
// Dumps the file headers to stdout.
const wchar_t kDumpHeaders[] = L"dump-headers";
@@ -84,9 +85,9 @@ int LaunchSlave(const CommandLine& command_line,
std::wstring new_program;
if (do_upgrade)
- new_program = StringPrintf(L"%ls%d", L"dump_cache_", version);
+ new_program = base::StringPrintf(L"%ls%d", L"dump_cache_", version);
else
- new_program = StringPrintf(L"dump_cache");
+ new_program = base::StringPrintf(L"dump_cache");
hacked_command_line.insert(to_remove, new_program);
@@ -95,7 +96,8 @@ int LaunchSlave(const CommandLine& command_line,
if (do_upgrade || do_convert_to_text)
new_command_line.AppendSwitch(kSlave);
- new_command_line.AppendSwitchWithValue(kPipe, pipe_number);
+ // TODO(evanm): remove needless usage of wstring from here and elsewhere.
+ new_command_line.AppendSwitchASCII(kPipe, WideToASCII(pipe_number));
if (!base::LaunchApp(new_command_line, false, false, NULL)) {
printf("Unable to launch the needed version of this tool: %ls\n",
new_program.c_str());
@@ -114,14 +116,19 @@ int main(int argc, const char* argv[]) {
CommandLine::Init(argc, argv);
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- std::wstring input_path = command_line.GetSwitchValue(kInputPath);
+ std::wstring input_path = command_line.GetSwitchValueNative(kInputPath);
if (input_path.empty())
return Help();
bool upgrade = false;
bool slave_required = false;
bool copy_to_text = false;
- std::wstring output_path = command_line.GetSwitchValue(kOutputPath);
+ // TODO(evanm): port to FilePath.
+ std::wstring output_path = command_line.GetSwitchValueNative(kOutputPath);
+ // Make sure that output directory ends with a slash.
+ if (output_path.size() >= 1 && output_path[output_path.size() - 1] != '\\')
+ output_path.push_back('\\');
+
if (command_line.HasSwitch(kUpgrade))
upgrade = true;
if (command_line.HasSwitch(kDumpToFiles))
@@ -145,7 +152,7 @@ int main(int argc, const char* argv[]) {
slave_required = true;
}
- std::wstring pipe_number = command_line.GetSwitchValue(kPipe);
+ std::wstring pipe_number = command_line.GetSwitchValueNative(kPipe);
if (command_line.HasSwitch(kSlave) && slave_required)
return RunSlave(input_path, pipe_number);
diff --git a/net/tools/dump_cache/dump_files.cc b/net/tools/dump_cache/dump_files.cc
index 8a9abca..7a2585f 100644
--- a/net/tools/dump_cache/dump_files.cc
+++ b/net/tools/dump_cache/dump_files.cc
@@ -1,4 +1,4 @@
-// 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.
@@ -108,7 +108,10 @@ class CacheDumper {
explicit CacheDumper(const std::wstring& path)
: path_(path),
block_files_(FilePath::FromWStringHack(path)),
- index_(NULL) {}
+ index_(NULL),
+ current_hash_(0),
+ next_addr_(0) {
+ }
bool Init();
@@ -147,8 +150,6 @@ bool CacheDumper::Init() {
return false;
}
- current_hash_ = 0;
- next_addr_ = 0;
return true;
}
diff --git a/net/tools/dump_cache/upgrade.cc b/net/tools/dump_cache/upgrade.cc
index 60099b2..0d6d5e4 100644
--- a/net/tools/dump_cache/upgrade.cc
+++ b/net/tools/dump_cache/upgrade.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "googleurl/src/gurl.h"
@@ -883,7 +884,7 @@ void SlaveSM::Fail() {
HANDLE CreateServer(std::wstring* pipe_number) {
std::wstring pipe_name(kPipePrefix);
srand(static_cast<int>(base::Time::Now().ToInternalValue()));
- *pipe_number = IntToWString(rand());
+ *pipe_number = base::IntToString16(rand());
pipe_name.append(*pipe_number);
DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE |
diff --git a/net/tools/dump_cache/url_to_filename_encoder.cc b/net/tools/dump_cache/url_to_filename_encoder.cc
index 89a1ca4..84d79c7 100644
--- a/net/tools/dump_cache/url_to_filename_encoder.cc
+++ b/net/tools/dump_cache/url_to_filename_encoder.cc
@@ -11,18 +11,14 @@ using std::string;
namespace {
-inline bool IsHexDigit(unsigned char c) {
- return (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') ||
- ('a' <= c && c <= 'f'));
-}
-
// Returns 1 if buf is prefixed by "num_digits" of hex digits
// Teturns 0 otherwise.
// The function checks for '\0' for string termination.
int HexDigitsPrefix(const char* buf, int num_digits) {
- for (int i = 0; i < num_digits; i++)
+ for (int i = 0; i < num_digits; i++) {
if (!IsHexDigit(buf[i]))
return 0; // This also detects end of string as '\0' is not xdigit.
+ }
return 1;
}
@@ -44,16 +40,16 @@ uint64 ParseLeadingHex64Value(const char *str, uint64 deflt) {
namespace net {
// The escape character choice is made here -- all code and tests in this
-// directory are based off of this constant. However, our test ata
+// directory are based off of this constant. However, our testdata
// has tons of dependencies on this, so it cannot be changed without
// re-running those tests and fixing them.
-const char kTruncationChar = '-';
-const char kEscapeChar = ',';
-const size_t kMaximumSubdirectoryLength = 128;
+const char UrlToFilenameEncoder::kEscapeChar = ',';
+const char UrlToFilenameEncoder::kTruncationChar = '-';
+const size_t UrlToFilenameEncoder::kMaximumSubdirectoryLength = 128;
-void UrlToFilenameEncoder::AppendSegment(
- char dir_separator, string* segment, string* dest) {
- if (segment->empty() || (*segment == ".") || (*segment == "..")) {
+void UrlToFilenameEncoder::AppendSegment(string* segment, string* dest) {
+ CHECK(!segment->empty());
+ if ((*segment == ".") || (*segment == "..")) {
dest->append(1, kEscapeChar);
dest->append(*segment);
segment->clear();
@@ -87,9 +83,11 @@ void UrlToFilenameEncoder::AppendSegment(
}
void UrlToFilenameEncoder::EncodeSegment(const string& filename_prefix,
- const string& filename_ending,
+ const string& escaped_ending,
char dir_separator,
string* encoded_filename) {
+ string filename_ending = UrlUtilities::Unescape(escaped_ending);
+
char encoded[3];
int encoded_len;
string segment;
@@ -117,22 +115,17 @@ void UrlToFilenameEncoder::EncodeSegment(const string& filename_prefix,
for (; index < filename_ending.length(); ++index) {
unsigned char ch = static_cast<unsigned char>(filename_ending[index]);
- if (ch == dir_separator) {
- AppendSegment(dir_separator, &segment, encoded_filename);
+ // Note: instead of outputing an empty segment, we let the second slash
+ // be escaped below.
+ if ((ch == dir_separator) && !segment.empty()) {
+ AppendSegment(&segment, encoded_filename);
encoded_filename->append(1, dir_separator);
segment.clear();
} else {
- // & is common in URLs and is legal filename syntax, but is also
- // a special Unix shell character, so let's avoid making
- // filenames with &, as well as ?. It's probably better to
- // blow up query-params than it is to make it hard to work with
- // the files in shell-scripts.
- if ((ch == 0x5F) || (ch == 0x2E) || // underscore period
- (ch == 0x25) || (ch == 0x3D) || // percent equals
- (ch == 0x2B) || (ch == 0x2D) || // plus dash
- ((0x30 <= ch) && (ch <= 0x39)) || // Digits [0-9]
- ((0x41 <= ch) && (ch <= 0x5A)) || // Uppercase [A-Z]
- ((0x61 <= ch) && (ch <= 0x7A))) { // Lowercase [a-z]
+ // After removing unsafe chars the only safe ones are _.=+- and alphanums.
+ if ((ch == '_') || (ch == '.') || (ch == '=') || (ch == '+') ||
+ (ch == '-') || (('0' <= ch) && (ch <= '9')) ||
+ (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z'))) {
encoded[0] = ch;
encoded_len = 1;
} else {
@@ -145,13 +138,9 @@ void UrlToFilenameEncoder::EncodeSegment(const string& filename_prefix,
}
segment.append(encoded, encoded_len);
- // Note: We chop paths into medium sized 'chunks'.
- // This is due to filename limits on Windows and Unix.
- // The Windows limit appears to be 128 characters, and
- // Unix is larger, but not as large as URLs with large
- // numbers of query params.
+ // If segment is too big, we must chop it into chunks.
if (segment.size() > kMaximumSubdirectoryLength) {
- AppendSegment(dir_separator, &segment, encoded_filename);
+ AppendSegment(&segment, encoded_filename);
encoded_filename->append(1, dir_separator);
}
}
@@ -163,7 +152,7 @@ void UrlToFilenameEncoder::EncodeSegment(const string& filename_prefix,
// us over the 128 char limit, then we will need to append "/" and the
// remaining chars.
segment += kEscapeChar;
- AppendSegment(dir_separator, &segment, encoded_filename);
+ AppendSegment(&segment, encoded_filename);
if (!segment.empty()) {
// The last overflow segment is special, because we appended in
// kEscapeChar above. We won't need to check it again for size
@@ -195,6 +184,8 @@ bool UrlToFilenameEncoder::Decode(const string& encoded_filename,
case kStart:
if (ch == kEscapeChar) {
state = kEscape;
+ } else if (ch == dir_separator) {
+ decoded_url->append(1, '/'); // URLs only use '/' not '\\'
} else {
decoded_url->append(1, ch);
}
@@ -209,9 +200,9 @@ bool UrlToFilenameEncoder::Decode(const string& encoded_filename,
decoded_url->append(1, '.');
state = kEscapeDot; // Look for at most one more dot.
} else if (ch == dir_separator) {
- // Consider url "//x". This will get encoded to "/,/x,".
+ // Consider url "//x". This was once encoded to "/,/x,".
// This code is what skips the first Escape.
- decoded_url->append(1, ch);
+ decoded_url->append(1, '/'); // URLs only use '/' not '\\'
state = kStart;
} else {
return false;
@@ -248,7 +239,7 @@ bool UrlToFilenameEncoder::Decode(const string& encoded_filename,
return (state == kEscape);
}
-// Escapes the given input |path| and chop any individual components
+// Escape the given input |path| and chop any individual components
// of the path which are greater than kMaximumSubdirectoryLength characters
// into two chunks.
//
@@ -299,4 +290,3 @@ string UrlToFilenameEncoder::LegacyEscape(const string& path) {
}
} // namespace net
-
diff --git a/net/tools/dump_cache/url_to_filename_encoder.h b/net/tools/dump_cache/url_to_filename_encoder.h
index b5cac37..29ae8b8 100644
--- a/net/tools/dump_cache/url_to_filename_encoder.h
+++ b/net/tools/dump_cache/url_to_filename_encoder.h
@@ -14,71 +14,74 @@
// with Facebook Connect.
//
// We need an escape-character for representing characters that are legal
-// in URL paths, but not in filenames, such as '?'. Illegal characters
-// in Windows are <>:"/\|?*. For reference, see
-// http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
+// in URL paths, but not in filenames, such as '?'.
//
// We can pick any legal character as an escape, as long as we escape it too.
// But as we have a goal of having filenames that humans can correlate with
// URLs, we should pick one that doesn't show up frequently in URLs. Candidates
// are ~`!@#$%^&()-=_+{}[],. but we would prefer to avoid characters that are
-// shell escapes, and characters that occur frequently in URLs.
+// shell escapes or that various build tools use.
//
// .#&%-=_+ occur frequently in URLs.
-// ~`!$^&(){}[] are special to Unix shells
+// <>:"/\|?* are illegal in Windows
+// See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
+// ~`!$^&(){}[]'; are special to Unix shells
+// In addition, build tools do not like ^@#%
//
-// @ might seem like a reasonble option, but some build tools don't appreciate
-// filenames with @ in testdata. Perforce does not appreciate # in a filename.
+// Josh took a quick look at the frequency of some special characters in
+// Sadeesh's slurped directory from Fall 09 and found the following occurances:
//
-// Though a web-site http://www.vias.org/linux-knowhow/lnag_05_05_09.html
-// identifies ^ as a special shell character, it did not appear to be an
-// issue to use it unquoted as a filename in bash or tcsh.
-//
-// Here are some frequencies of some special characters in a data set from Fall
-// '09. We find only 3 occurences of "x5E" (^ is ascii 0x53):
-// ^ 3 build tools don't like ^ in testdata filenames
-// @ 10 build tools don't like @ in testdata filenames
+// ^ 3 build tool doesn't like ^ in testdata filenames
+// @ 10 build tool doesn't like @ in testdata filenames
// . 1676 too frequent in URLs
// , 76 THE WINNER
-// # 0 build tools doesn't like it
+// # 0 build tool doesn't like it
// & 487 Prefer to avoid shell escapes
// % 374 g4 doesn't like it
// = 579 very frequent in URLs -- leave unmodified
// - 464 very frequent in URLs -- leave unmodified
// _ 798 very frequent in URLs -- leave unmodified
//
-// It is interesting that there were no slurped URLs with #, but I suspect this
-// might be due to the slurping methdology. So let's stick with the relatively
-// rare ','.
//
-// Here's the escaping methodology:
+// The escaping algorithm is:
+// 1) Escape all unfriendly symbols as ,XX where XX is the hex code.
+// 2) Add a ',' at the end (We do not allow ',' at end of any directory name,
+// so this assures that e.g. /a and /a/b can coexist in the filesystem).
+// 3) Go through the path segment by segment (where a segment is one directory
+// or leaf in the path) and
+// 3a) If the segment is empty, escape the second slash. i.e. if it was
+// www.foo.com//a then we escape the second / like www.foo.com/,2Fa,
+// 3a) If it is "." or ".." prepend with ',' (so that we have a non-
+// empty and non-reserved filename).
+// 3b) If it is over 128 characters, break it up into smaller segments by
+// inserting ,-/ (Windows limits paths to 128 chars, other OSes also
+// have limits that would restrict us)
//
+// For example:
// URL File
// / /,
+// /index.html /index.html,
// /. /.,
-// // /,/,
+// /a/b /a/b,
+// /a/b/ /a/b/,
+// /a/b/c /a/b/c, Note: no prefix problem
+// /u?foo=bar /u,3Ffoo=bar,
+// // /,2F,
// /./ /,./,
// /../ /,../,
// /, /,2C,
-// /,/ /,2C/,
-// /a/b /a/b, (, at the end of a name indicates a leaf).
-// /a/b/ /a/b/,
-//
-// path segments greater than 128 characters (after escape expansion) are
-// suffixed with ,- so we can know that the next "/" is not part of the URL:
-//
-// /verylongname/ /verylong,-/name
+// /,./ /,2C./,
+// /very...longname/ /very...long,-/name If very...long is about 126 long.
// NOTE: we avoid using some classes here (like FilePath and GURL) because we
// share this code with other projects externally.
-#ifndef NET_TOOLS_DUMP_CACHE_URL_TO_FILE_ENCODER_H_
-#define NET_TOOLS_DUMP_CACHE_URL_TO_FILE_ENCODER_H_
+#ifndef NET_TOOLS_DUMP_CACHE_URL_TO_FILENAME_ENCODER_H_
+#define NET_TOOLS_DUMP_CACHE_URL_TO_FILENAME_ENCODER_H_
+#pragma once
#include <string>
-#include "base/file_path.h"
-#include "base/file_util.h"
#include "base/string_util.h"
#include "net/tools/dump_cache/url_utilities.h"
@@ -87,48 +90,56 @@ namespace net {
// Helper class for converting a URL into a filename.
class UrlToFilenameEncoder {
public:
- // Given a |url| and a |base_path|, returns a string which represents this
- // |url|.
+ // Given a |url| and a |base_path|, returns a filename which represents this
+ // |url|. |url| may include URL escaping such as %21 for !
// |legacy_escape| indicates that this function should use the old-style
// of encoding.
// TODO(mbelshe): delete the legacy_escape code.
static std::string Encode(const std::string& url, std::string base_path,
bool legacy_escape) {
- std::string clean_url(url);
- if (clean_url.length() && clean_url[clean_url.length()-1] == '/')
- clean_url.append("index.html");
-
- std::string host = UrlUtilities::GetUrlHost(clean_url);
- std::string filename(base_path);
- filename.append("\\");
- filename = filename.append(host);
- filename.append("\\");
+ std::string filename;
+ if (!legacy_escape) {
+ std::string url_no_scheme = UrlUtilities::GetUrlHostPath(url);
+ EncodeSegment(base_path, url_no_scheme, '/', &filename);
+#ifdef WIN32
+ ReplaceAll(&filename, "/", "\\");
+#endif
+ } else {
+ std::string clean_url(url);
+ if (clean_url.length() && clean_url[clean_url.length()-1] == '/')
+ clean_url.append("index.html");
+
+ std::string host = UrlUtilities::GetUrlHost(clean_url);
+ filename.append(base_path);
+ filename.append(host);
+#ifdef WIN32
+ filename.append("\\");
+#else
+ filename.append("/");
+#endif
- std::string url_filename = UrlUtilities::GetUrlPath(clean_url);
- // Strip the leading '/'
- if (url_filename[0] == '/')
- url_filename = url_filename.substr(1);
+ std::string url_filename = UrlUtilities::GetUrlPath(clean_url);
+ // Strip the leading '/'.
+ if (url_filename[0] == '/')
+ url_filename = url_filename.substr(1);
- // replace '/' with '\'
- ConvertToSlashes(&url_filename);
+ // Replace '/' with '\'.
+ ConvertToSlashes(&url_filename);
- // strip double slashes ("\\")
- StripDoubleSlashes(&url_filename);
+ // Strip double back-slashes ("\\\\").
+ StripDoubleSlashes(&url_filename);
- // Save path as filesystem-safe characters
- if (legacy_escape) {
+ // Save path as filesystem-safe characters.
url_filename = LegacyEscape(url_filename);
- } else {
- url_filename = Escape(url_filename);
- }
- filename = filename.append(url_filename);
+ filename.append(url_filename);
#ifndef WIN32
- // Last step - convert to native slashes!
- const std::string slash("/");
- const std::string backslash("\\");
- ReplaceAll(&filename, backslash, slash);
+ // Last step - convert to native slashes.
+ const std::string slash("/");
+ const std::string backslash("\\");
+ ReplaceAll(&filename, backslash, slash);
#endif
+ }
return filename;
}
@@ -136,12 +147,13 @@ class UrlToFilenameEncoder {
// Rewrite HTML in a form that the SPDY in-memory server
// can read.
// |filename_prefix| is prepended without escaping.
- // |filename_ending| is the URL to be encoded into a filename.
+ // |escaped_ending| is the URL to be encoded into a filename. It may have URL
+ // escaped characters (like %21 for !).
// |dir_separator| is "/" on Unix, "\" on Windows.
// |encoded_filename| is the resultant filename.
static void EncodeSegment(
const std::string& filename_prefix,
- const std::string& filename_ending,
+ const std::string& escaped_ending,
char dir_separator,
std::string* encoded_filename);
@@ -151,34 +163,28 @@ class UrlToFilenameEncoder {
char dir_separator,
std::string* decoded_url);
+ static const char kEscapeChar;
+ static const char kTruncationChar;
+ static const size_t kMaximumSubdirectoryLength;
+
+ friend class UrlToFilenameEncoderTest;
+
private:
- // Appends a segment of the path, special-casing ".", "..", and "", and
+ // Appends a segment of the path, special-casing "." and "..", and
// ensuring that the segment does not exceed the path length. If it does,
// it chops the end off the segment, writes the segment with a separator of
// ",-/", and then rewrites segment to contain just the truncated piece so
// it can be used in the next iteration.
- // |dir_separator| is "/" on Unix, "\" on Windows.
// |segment| is a read/write parameter containing segment to write
- static void AppendSegment(
- char dir_separator,
- std::string* segment,
- std::string* dest);
-
- // Escapes the given input |path| and chop any individual components
- // of the path which are greater than kMaximumSubdirectoryLength characters
- // into two chunks.
- static std::string Escape(const std::string& path) {
- std::string output;
- EncodeSegment("", path, '\\', &output);
- return output;
- }
+ // Note: this should not be called with empty segment.
+ static void AppendSegment(std::string* segment, std::string* dest);
// Allow reading of old slurped files.
static std::string LegacyEscape(const std::string& path);
// Replace all instances of |from| within |str| as |to|.
static void ReplaceAll(std::string* str, const std::string& from,
- const std::string& to) {
+ const std::string& to) {
std::string::size_type pos(0);
while ((pos = str->find(from, pos)) != std::string::npos) {
str->replace(pos, from.size(), to);
@@ -203,5 +209,4 @@ class UrlToFilenameEncoder {
} // namespace net
-#endif // NET_TOOLS_DUMP_CACHE_URL_TO_FILE_ENCODER_H_
-
+#endif // NET_TOOLS_DUMP_CACHE_URL_TO_FILENAME_ENCODER_H_
diff --git a/net/tools/dump_cache/url_to_filename_encoder_unittest.cc b/net/tools/dump_cache/url_to_filename_encoder_unittest.cc
index 32cef99..2e09e0b 100644
--- a/net/tools/dump_cache/url_to_filename_encoder_unittest.cc
+++ b/net/tools/dump_cache/url_to_filename_encoder_unittest.cc
@@ -6,8 +6,10 @@
#include <string>
#include <vector>
+
#include "base/string_piece.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
@@ -15,37 +17,39 @@ using std::string;
namespace net {
-// The escape character choice is made here -- all code and tests in this
-// directory are based off of this constant. However, our test ata
-// has tons of dependencies on this, so it cannot be changed without
-// re-running those tests and fixing them.
-const char kTruncationChar = '-';
-const char kEscapeChar = ',';
-const size_t kMaximumSubdirectoryLength = 128;
+#ifdef WIN32
+char kDirSeparator = '\\';
+char kOtherDirSeparator = '/';
+#else
+char kDirSeparator = '/';
+char kOtherDirSeparator = '\\';
+#endif
class UrlToFilenameEncoderTest : public ::testing::Test {
protected:
- UrlToFilenameEncoderTest() : escape_(1, kEscapeChar) {}
+ UrlToFilenameEncoderTest() : escape_(1, UrlToFilenameEncoder::kEscapeChar),
+ dir_sep_(1, kDirSeparator) {
+ }
void CheckSegmentLength(const StringPiece& escaped_word) {
std::vector<StringPiece> components;
Tokenize(escaped_word, StringPiece("/"), &components);
for (size_t i = 0; i < components.size(); ++i) {
- EXPECT_GE(kMaximumSubdirectoryLength,
+ EXPECT_GE(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
components[i].size());
}
}
- void CheckValidChars(const StringPiece& escaped_word) {
- // These characters are invalid in Windows. We will
- // ignore / for this test, but add in ', as that's pretty
+ void CheckValidChars(const StringPiece& escaped_word, char invalid_slash) {
+ // These characters are invalid in Windows. We add in ', as that's pretty
// inconvenient in a Unix filename.
//
// See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
- static const char kInvalidChars[] = "<>:\"\\|?*'";
+ const string kInvalidChars = "<>:\"|?*'";
for (size_t i = 0; i < escaped_word.size(); ++i) {
char c = escaped_word[i];
- EXPECT_EQ(NULL, strchr(kInvalidChars, c));
+ EXPECT_EQ(string::npos, kInvalidChars.find(c));
+ EXPECT_NE(invalid_slash, c);
EXPECT_NE('\0', c); // only invalid character in Posix
EXPECT_GT(0x7E, c); // only English printable characters
}
@@ -56,7 +60,7 @@ class UrlToFilenameEncoderTest : public ::testing::Test {
UrlToFilenameEncoder::EncodeSegment("", in_word, '/', &escaped_word);
EXPECT_EQ(gold_word, escaped_word);
CheckSegmentLength(escaped_word);
- CheckValidChars(escaped_word);
+ CheckValidChars(escaped_word, '\\');
UrlToFilenameEncoder::Decode(escaped_word, '/', &url);
EXPECT_EQ(in_word, url);
}
@@ -65,7 +69,7 @@ class UrlToFilenameEncoderTest : public ::testing::Test {
string escaped_word, url;
UrlToFilenameEncoder::EncodeSegment("", in_word, '/', &escaped_word);
CheckSegmentLength(escaped_word);
- CheckValidChars(escaped_word);
+ CheckValidChars(escaped_word, '\\');
UrlToFilenameEncoder::Decode(escaped_word, '/', &url);
EXPECT_EQ(in_word, url);
}
@@ -78,12 +82,42 @@ class UrlToFilenameEncoderTest : public ::testing::Test {
void ValidateEscaped(unsigned char ch) {
// We always suffix the leaf with kEscapeChar, unless the leaf is empty.
char escaped[100];
- const char escape = kEscapeChar;
+ const char escape = UrlToFilenameEncoder::kEscapeChar;
base::snprintf(escaped, sizeof(escaped), "%c%02X%c", escape, ch, escape);
Validate(string(1, ch), escaped);
}
+ void ValidateUrl(const string& url, const string& base_path,
+ bool legacy_escape, const string& gold_filename) {
+ string encoded_filename = UrlToFilenameEncoder::Encode(
+ url, base_path, legacy_escape);
+ EXPECT_EQ(gold_filename, encoded_filename);
+ if (!legacy_escape) {
+ CheckSegmentLength(encoded_filename);
+ CheckValidChars(encoded_filename, kOtherDirSeparator);
+ string decoded_url;
+ UrlToFilenameEncoder::Decode(encoded_filename, kDirSeparator,
+ &decoded_url);
+ if (url != decoded_url) {
+ EXPECT_EQ(url, "http://" + decoded_url);
+ }
+ }
+ }
+
+ void ValidateUrlOldNew(const string& url, const string& gold_old_filename,
+ const string& gold_new_filename) {
+ ValidateUrl(url, "", true, gold_old_filename);
+ ValidateUrl(url, "", false, gold_new_filename);
+ }
+
+ void ValidateEncodeSame(const string& url1, const string& url2) {
+ string filename1 = UrlToFilenameEncoder::Encode(url1, "", false);
+ string filename2 = UrlToFilenameEncoder::Encode(url2, "", false);
+ EXPECT_EQ(filename1, filename2);
+ }
+
string escape_;
+ string dir_sep_;
};
TEST_F(UrlToFilenameEncoderTest, DoesNotEscape) {
@@ -93,49 +127,31 @@ TEST_F(UrlToFilenameEncoderTest, DoesNotEscape) {
ValidateNoChange("ZYXWVUT");
ValidateNoChange("ZYXWVUTSRQPONMLKJIHGFEDCBA");
ValidateNoChange("01234567689");
- ValidateNoChange("/-_");
+ ValidateNoChange("_.=+-");
ValidateNoChange("abcdefghijklmnopqrstuvwxyzZYXWVUTSRQPONMLKJIHGFEDCBA"
- "01234567689/-_");
+ "01234567689_.=+-");
ValidateNoChange("index.html");
ValidateNoChange("/");
ValidateNoChange("/.");
ValidateNoChange(".");
ValidateNoChange("..");
- ValidateNoChange("%");
- ValidateNoChange("=");
- ValidateNoChange("+");
- ValidateNoChange("_");
}
TEST_F(UrlToFilenameEncoderTest, Escapes) {
- ValidateEscaped('!');
- ValidateEscaped('"');
- ValidateEscaped('#');
- ValidateEscaped('$');
- ValidateEscaped('&');
- ValidateEscaped('(');
- ValidateEscaped(')');
- ValidateEscaped('*');
- ValidateEscaped(',');
- ValidateEscaped(':');
- ValidateEscaped(';');
- ValidateEscaped('<');
- ValidateEscaped('>');
- ValidateEscaped('@');
- ValidateEscaped('[');
- ValidateEscaped('\'');
- ValidateEscaped('\\');
- ValidateEscaped(']');
- ValidateEscaped('^');
- ValidateEscaped('`');
- ValidateEscaped('{');
- ValidateEscaped('|');
- ValidateEscaped('}');
- ValidateEscaped('~');
-
- // check non-printable characters
+ const string bad_chars =
+ "<>:\"\\|?*" // Illegal on Windows
+ "~`!$^&(){}[]';" // Bad for Unix shells
+ "^@" // Build tool doesn't like
+ "#%" // Tool doesn't like
+ ","; // The escape char has to be escaped
+
+ for (size_t i = 0; i < bad_chars.size(); ++i) {
+ ValidateEscaped(bad_chars[i]);
+ }
+
+ // Check non-printable characters.
ValidateEscaped('\0');
- for (int i = 127; i < 256; ++i) {
+ for (size_t i = 127; i < 256; ++i) {
ValidateEscaped(static_cast<char>(i));
}
}
@@ -144,10 +160,10 @@ TEST_F(UrlToFilenameEncoderTest, DoesEscapeCorrectly) {
Validate("mysite.com&x", "mysite.com" + escape_ + "26x" + escape_);
Validate("/./", "/" + escape_ + "./" + escape_);
Validate("/../", "/" + escape_ + "../" + escape_);
- Validate("//", "/" + escape_ + "/" + escape_);
+ Validate("//", "/" + escape_ + "2F" + escape_);
Validate("/./leaf", "/" + escape_ + "./leaf" + escape_);
Validate("/../leaf", "/" + escape_ + "../leaf" + escape_);
- Validate("//leaf", "/" + escape_ + "/leaf" + escape_);
+ Validate("//leaf", "/" + escape_ + "2Fleaf" + escape_);
Validate("mysite/u?param1=x&param2=y",
"mysite/u" + escape_ + "3Fparam1=x" + escape_ + "26param2=y" +
escape_);
@@ -159,6 +175,63 @@ TEST_F(UrlToFilenameEncoderTest, DoesEscapeCorrectly) {
"3Fid=138" + escape_ + "26content=true" + escape_);
}
+TEST_F(UrlToFilenameEncoderTest, EncodeUrlCorrectly) {
+ ValidateUrlOldNew("http://www.google.com/index.html",
+ "www.google.com" + dir_sep_ + "indexx2Ehtml",
+ "www.google.com" + dir_sep_ + "index.html" + escape_);
+ ValidateUrlOldNew("http://www.google.com/x/search?hl=en&q=dogs&oq=",
+ "www.google.com" + dir_sep_ + "x" + dir_sep_ +
+ "searchx3Fhlx3Denx26qx3Ddogsx26oqx3D",
+
+ "www.google.com" + dir_sep_ + "x" + dir_sep_ + "search" +
+ escape_ + "3Fhl=en" + escape_ + "26q=dogs" + escape_ +
+ "26oq=" + escape_);
+ ValidateUrlOldNew("http://www.foo.com/a//",
+ "www.foo.com" + dir_sep_ + "ax255Cx255Cindexx2Ehtml",
+ "www.foo.com" + dir_sep_ + "a" + dir_sep_ + escape_ + "2F" +
+ escape_);
+
+ // From bug: Double slash preserved.
+ ValidateUrl("http://www.foo.com/u?site=http://www.google.com/index.html",
+ "", false,
+ "www.foo.com" + dir_sep_ + "u" + escape_ + "3Fsite=http" +
+ escape_ + "3A" + dir_sep_ + escape_ + "2Fwww.google.com" +
+ dir_sep_ + "index.html" + escape_);
+ ValidateUrlOldNew(
+ "http://blogutils.net/olct/online.php?"
+ "site=http://thelwordfanfics.blogspot.&interval=600",
+
+ "blogutils.net" + dir_sep_ + "olct" + dir_sep_ + "onlinex2Ephpx3F"
+ "sitex3Dhttpx3Ax255Cx255Cthelwordfanficsx2Eblogspotx2Ex26intervalx3D600",
+
+ "blogutils.net" + dir_sep_ + "olct" + dir_sep_ + "online.php" + escape_ +
+ "3Fsite=http" + escape_ + "3A" + dir_sep_ + escape_ +
+ "2Fthelwordfanfics.blogspot." + escape_ + "26interval=600" + escape_);
+}
+
+// From bug: Escapes treated the same as normal char.
+TEST_F(UrlToFilenameEncoderTest, UnescapeUrlsBeforeEncode) {
+ for (int i = 0; i < 128; ++i) {
+ string unescaped(1, static_cast<char>(i));
+ string escaped = base::StringPrintf("%%%02X", i);
+ ValidateEncodeSame(unescaped, escaped);
+ }
+
+ ValidateEncodeSame(
+ "http://www.blogger.com/navbar.g?bName=God!&Mode=FOO&searchRoot"
+ "=http%3A%2F%2Fsurvivorscanthrive.blogspot.com%2Fsearch",
+
+ "http://www.blogger.com/navbar.g?bName=God%21&Mode=FOO&searchRoot"
+ "=http%3A%2F%2Fsurvivorscanthrive.blogspot.com%2Fsearch");
+}
+
+// From bug: Filename encoding is not prefix-free.
+TEST_F(UrlToFilenameEncoderTest, EscapeSecondSlash) {
+ Validate("/", "/" + escape_);
+ Validate("//", "/" + escape_ + "2F" + escape_);
+ Validate("///", "/" + escape_ + "2F" + "/" + escape_);
+}
+
TEST_F(UrlToFilenameEncoderTest, LongTail) {
static char long_word[] =
"~joebob/briggs/12345678901234567890123456789012345678901234567890"
@@ -182,7 +255,7 @@ TEST_F(UrlToFilenameEncoderTest, LongTail) {
"78901234567890123456789012345678901234567890123456789012345678" +
escape_ + "-/"
"9012345678901234567890" + escape_;
- EXPECT_LT(kMaximumSubdirectoryLength,
+ EXPECT_LT(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
sizeof(long_word));
Validate(long_word, gold_long_word);
}
@@ -216,7 +289,7 @@ TEST_F(UrlToFilenameEncoderTest, LongTailQuestion) {
+ pattern + "1234567" +
escape_ + "-/" +
escape_ + "3F" + pattern + pattern + escape_;
- EXPECT_LT(kMaximumSubdirectoryLength,
+ EXPECT_LT(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
sizeof(long_word));
Validate(long_word, gold_long_word);
}
@@ -225,7 +298,7 @@ TEST_F(UrlToFilenameEncoderTest, CornerCasesNearMaxLenNoEscape) {
// hit corner cases, +/- 4 characters from kMaxLen
for (int i = -4; i <= 4; ++i) {
string input;
- input.append(i + kMaximumSubdirectoryLength, 'x');
+ input.append(i + UrlToFilenameEncoder::kMaximumSubdirectoryLength, 'x');
ValidateAllSegmentsSmall(input);
}
}
@@ -236,7 +309,7 @@ TEST_F(UrlToFilenameEncoderTest, CornerCasesNearMaxLenWithEscape) {
// are truncating with '/' *after* the expansion.
for (int i = -4; i <= 4; ++i) {
string input;
- input.append(i + kMaximumSubdirectoryLength - 1, 'x');
+ input.append(i + UrlToFilenameEncoder::kMaximumSubdirectoryLength - 1, 'x');
input.append(1, '.'); // this will expand to 3 characters.
ValidateAllSegmentsSmall(input);
}
@@ -252,17 +325,17 @@ TEST_F(UrlToFilenameEncoderTest, LeafBranchAlias) {
TEST_F(UrlToFilenameEncoderTest, BackslashSeparator) {
string long_word;
string escaped_word;
- long_word.append(kMaximumSubdirectoryLength + 1, 'x');
+ long_word.append(UrlToFilenameEncoder::kMaximumSubdirectoryLength + 1, 'x');
UrlToFilenameEncoder::EncodeSegment("", long_word, '\\', &escaped_word);
// check that one backslash, plus the escape ",-", and the ending , got added.
EXPECT_EQ(long_word.size() + 4, escaped_word.size());
- ASSERT_LT(kMaximumSubdirectoryLength,
+ ASSERT_LT(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
escaped_word.size());
// Check that the backslash got inserted at the correct spot.
EXPECT_EQ('\\', escaped_word[
- kMaximumSubdirectoryLength]);
+ UrlToFilenameEncoder::kMaximumSubdirectoryLength]);
}
-} // namespace
+} // namespace net
diff --git a/net/tools/dump_cache/url_utilities.h b/net/tools/dump_cache/url_utilities.h
index 4de95dc..7b926f1 100644
--- a/net/tools/dump_cache/url_utilities.h
+++ b/net/tools/dump_cache/url_utilities.h
@@ -4,61 +4,33 @@
#ifndef NET_TOOLS_DUMP_CACHE_URL_UTILITIES_H_
#define NET_TOOLS_DUMP_CACHE_URL_UTILITIES_H_
+#pragma once
#include <string>
namespace net {
-namespace UrlUtilities {
+struct UrlUtilities {
+ // Gets the host from an url, strips the port number as well if the url
+ // has one.
+ // For example: calling GetUrlHost(www.foo.com:8080/boo) returns www.foo.com
+ static std::string GetUrlHost(const std::string& url);
-// Gets the host from an url, strips the port number as well if the url
-// has one.
-// For example: calling GetUrlHost(www.foo.com:8080/boo) returns www.foo.com
-static std::string GetUrlHost(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- size_t next_slash = url.find_first_of('/', b);
- size_t next_colon = url.find_first_of(':', b);
- if (next_slash != std::string::npos
- && next_colon != std::string::npos
- && next_colon < next_slash) {
- return std::string(url, b, next_colon - b);
- }
- if (next_slash == std::string::npos) {
- if (next_colon != std::string::npos) {
- return std::string(url, next_colon - b);
- } else {
- next_slash = url.size();
- }
- }
- return std::string(url, b, next_slash - b);
-}
+ // Get the host + path portion of an url
+ // e.g http://www.foo.com/path
+ // returns www.foo.com/path
+ static std::string GetUrlHostPath(const std::string& url);
-// Gets the path portion of an url.
-// e.g http://www.foo.com/path
-// returns /path
-static std::string GetUrlPath(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- b = url.find("/", b);
- if (b == std::string::npos)
- return "/";
+ // Gets the path portion of an url.
+ // e.g http://www.foo.com/path
+ // returns /path
+ static std::string GetUrlPath(const std::string& url);
- size_t e = url.find("#", b+1);
- if (e != std::string::npos)
- return std::string(url, b, (e - b));
- return std::string(url, b);
-}
-
-} // namespace UrlUtilities
+ // Unescape a url, converting all %XX to the the actual char 0xXX.
+ // For example, this will convert "foo%21bar" to "foo!bar".
+ static std::string Unescape(const std::string& escaped_url);
+};
} // namespace net
#endif // NET_TOOLS_DUMP_CACHE_URL_UTILITIES_H_
-
diff --git a/net/tools/fetch/fetch_client.cc b/net/tools/fetch/fetch_client.cc
index 8863dd7..435dc93 100644
--- a/net/tools/fetch/fetch_client.cc
+++ b/net/tools/fetch/fetch_client.cc
@@ -9,6 +9,7 @@
#include "base/message_loop.h"
#include "base/singleton.h"
#include "base/stats_counters.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "net/base/completion_callback.h"
#include "net/base/host_resolver.h"
@@ -125,23 +126,26 @@ int main(int argc, char**argv) {
if (!url.length())
usage(argv[0]);
int client_limit = 1;
- if (parsed_command_line.HasSwitch("n"))
- StringToInt(parsed_command_line.GetSwitchValueASCII("n"), &client_limit);
+ if (parsed_command_line.HasSwitch("n")) {
+ base::StringToInt(parsed_command_line.GetSwitchValueASCII("n"),
+ &client_limit);
+ }
bool use_cache = parsed_command_line.HasSwitch("use-cache");
// Do work here.
MessageLoop loop(MessageLoop::TYPE_IO);
scoped_refptr<net::HostResolver> host_resolver(
- net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism));
+ net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
+ NULL));
scoped_refptr<net::ProxyService> proxy_service(
- net::ProxyService::CreateNull());
+ net::ProxyService::CreateDirect());
scoped_refptr<net::SSLConfigService> ssl_config_service(
net::SSLConfigService::CreateSystemSSLConfigService());
net::HttpTransactionFactory* factory = NULL;
scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory(
- net::HttpAuthHandlerFactory::CreateDefault());
+ net::HttpAuthHandlerFactory::CreateDefault(host_resolver));
if (use_cache) {
factory = new net::HttpCache(host_resolver, proxy_service,
ssl_config_service, http_auth_handler_factory.get(), NULL, NULL,
diff --git a/net/tools/fetch/http_listen_socket.cc b/net/tools/fetch/http_listen_socket.cc
index d0d6b97..fd788c8 100644
--- a/net/tools/fetch/http_listen_socket.cc
+++ b/net/tools/fetch/http_listen_socket.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,7 +9,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
#include "net/tools/fetch/http_server_request_info.h"
#include "net/tools/fetch/http_server_response_info.h"
@@ -37,8 +37,10 @@ void HttpListenSocket::Accept() {
}
}
-HttpListenSocket* HttpListenSocket::Listen(const std::string& ip, int port,
- HttpListenSocket::Delegate* delegate) {
+HttpListenSocket* HttpListenSocket::Listen(
+ const std::string& ip,
+ int port,
+ HttpListenSocket::Delegate* delegate) {
SOCKET s = ListenSocket::Listen(ip, port);
if (s == ListenSocket::kInvalidSocket) {
// TODO (ibrar): error handling
@@ -227,7 +229,7 @@ void HttpListenSocket::Respond(HttpServerResponseInfo* info,
response += "Content-type: " + info->content_type + "\r\n";
if (info->content_length > 0)
- response += "Content-length: " + IntToString(info->content_length) +
+ response += "Content-length: " + base::IntToString(info->content_length) +
"\r\n";
if (info->connection_close)
diff --git a/net/tools/fetch/http_listen_socket.h b/net/tools/fetch/http_listen_socket.h
index a1b77c5..781ac32 100644
--- a/net/tools/fetch/http_listen_socket.h
+++ b/net/tools/fetch/http_listen_socket.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_
#define NET_BASE_TOOLS_HTTP_LISTEN_SOCKET_H_
+#pragma once
#include "base/message_loop.h"
#include "net/base/listen_socket.h"
diff --git a/net/tools/fetch/http_server.h b/net/tools/fetch/http_server.h
index 1a3d402..fc37728 100644
--- a/net/tools/fetch/http_server.h
+++ b/net/tools/fetch/http_server.h
@@ -4,8 +4,10 @@
#ifndef NET_BASE_TOOLS_HTTP_SERVER_H_
#define NET_BASE_TOOLS_HTTP_SERVER_H_
+#pragma once
#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
#include "net/tools/fetch/http_session.h"
// Implements a simple, single-threaded HttpServer.
diff --git a/net/tools/fetch/http_server_request_info.h b/net/tools/fetch/http_server_request_info.h
index fb45bdb..2b7cfb5 100644
--- a/net/tools/fetch/http_server_request_info.h
+++ b/net/tools/fetch/http_server_request_info.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_
#define NET_BASE_TOOLS_HTTP_SERVER_REQUEST_INFO_H_
+#pragma once
#include <map>
#include <string>
diff --git a/net/tools/fetch/http_server_response_info.h b/net/tools/fetch/http_server_response_info.h
index 03015c8..7a8bb1f 100644
--- a/net/tools/fetch/http_server_response_info.h
+++ b/net/tools/fetch/http_server_response_info.h
@@ -1,40 +1,41 @@
-// 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.
-#ifndef NET_HTTP_HTTP_RESPONSE_INFO_H__
-#define NET_HTTP_HTTP_RESPONSE_INFO_H__
+#ifndef NET_HTTP_HTTP_RESPONSE_INFO_H_
+#define NET_HTTP_HTTP_RESPONSE_INFO_H_
+#pragma once
-#include <string>
#include <map>
+#include <string>
// Meta information about a server response.
class HttpServerResponseInfo {
public:
- HttpServerResponseInfo()
+ HttpServerResponseInfo()
: status(200), content_length(0), connection_close(false) {
}
- // The response protocol
+ // The response protocol.
std::string protocol;
- // The status code
+ // The status code.
int status;
- // The server identifier
+ // The server identifier.
std::string server_name;
- // The content type
+ // The content type.
std::string content_type;
- // The content length
+ // The content length.
int content_length;
- // Should we close the connection
+ // Should we close the connection.
bool connection_close;
- // Additional response headers
+ // Additional response headers.
std::map<std::string, std::string> headers;
};
-#endif // NET_HTTP_HTTP_RESPONSE_INFO_H__
+#endif // NET_HTTP_HTTP_RESPONSE_INFO_H_
diff --git a/net/tools/fetch/http_session.h b/net/tools/fetch/http_session.h
index a1d57bf..b4b582c 100644
--- a/net/tools/fetch/http_session.h
+++ b/net/tools/fetch/http_session.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_TOOLS_HTTP_SESSION_H_
#define NET_BASE_TOOLS_HTTP_SESSION_H_
+#pragma once
#include "base/basictypes.h"
#include "net/http/http_request_info.h"
diff --git a/net/tools/flip_server/balsa_enums.h b/net/tools/flip_server/balsa_enums.h
index 4273ee4..6a68532 100644
--- a/net/tools/flip_server/balsa_enums.h
+++ b/net/tools/flip_server/balsa_enums.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_BALSA_ENUMS_H_
#define NET_TOOLS_FLIP_SERVER_BALSA_ENUMS_H_
+#pragma once
namespace net {
diff --git a/net/tools/flip_server/balsa_frame.h b/net/tools/flip_server/balsa_frame.h
index 37bf5be..6c0b1d0 100644
--- a/net/tools/flip_server/balsa_frame.h
+++ b/net/tools/flip_server/balsa_frame.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_
#define NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_
+#pragma once
#include <strings.h>
diff --git a/net/tools/flip_server/balsa_headers.h b/net/tools/flip_server/balsa_headers.h
index 24e7940..d89c7f9 100644
--- a/net/tools/flip_server/balsa_headers.h
+++ b/net/tools/flip_server/balsa_headers.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_H_
#define NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_H_
+#pragma once
#include <algorithm>
#include <iosfwd>
diff --git a/net/tools/flip_server/balsa_headers_token_utils.h b/net/tools/flip_server/balsa_headers_token_utils.h
index c2c5a68..80c6b0c 100644
--- a/net/tools/flip_server/balsa_headers_token_utils.h
+++ b/net/tools/flip_server/balsa_headers_token_utils.h
@@ -7,6 +7,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_TOKEN_UTILS_H_
#define NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_TOKEN_UTILS_H_
+#pragma once
#include "net/tools/flip_server/balsa_headers.h"
#include "base/string_piece.h"
diff --git a/net/tools/flip_server/balsa_visitor_interface.h b/net/tools/flip_server/balsa_visitor_interface.h
index c932ff8..393d4f7 100644
--- a/net/tools/flip_server/balsa_visitor_interface.h
+++ b/net/tools/flip_server/balsa_visitor_interface.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_BALSA_VISITOR_INTERFACE_H_
#define NET_TOOLS_FLIP_SERVER_BALSA_VISITOR_INTERFACE_H_
+#pragma once
#include <cstddef>
diff --git a/net/tools/flip_server/buffer_interface.h b/net/tools/flip_server/buffer_interface.h
index ec061c9..67e1729 100644
--- a/net/tools/flip_server/buffer_interface.h
+++ b/net/tools/flip_server/buffer_interface.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_BUFFER_INTERFACE_H__
#define NET_TOOLS_FLIP_SERVER_BUFFER_INTERFACE_H__
+#pragma once
namespace net {
diff --git a/net/tools/flip_server/create_listener.h b/net/tools/flip_server/create_listener.h
index 32758ee..4c0a277 100644
--- a/net/tools/flip_server/create_listener.h
+++ b/net/tools/flip_server/create_listener.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_CREATE_LISTENER_H__
#define NET_TOOLS_FLIP_SERVER_CREATE_LISTENER_H__
+#pragma once
#include <iosfwd>
#include <string>
diff --git a/net/tools/flip_server/epoll_server.h b/net/tools/flip_server/epoll_server.h
index 262dd8a..bbcb188 100644
--- a/net/tools/flip_server/epoll_server.h
+++ b/net/tools/flip_server/epoll_server.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_TOOLS_FLIP_SERVER_EPOLL_SERVER_H_
#define NET_TOOLS_FLIP_SERVER_EPOLL_SERVER_H_
+#pragma once
#include <fcntl.h>
#include <sys/queue.h>
@@ -43,7 +44,6 @@ namespace net {
class EpollServer;
class EpollAlarmCallbackInterface;
class ReadPipeCallback;
-class WatchDogToken;
struct EpollEvent {
EpollEvent(int events, bool is_epoll_wait)
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 974994d..6a1da08 100644
--- a/net/tools/flip_server/flip_in_mem_edsm_server.cc
+++ b/net/tools/flip_server/flip_in_mem_edsm_server.cc
@@ -23,6 +23,8 @@
#include "net/spdy/spdy_frame_builder.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_protocol.h"
+#include "net/tools/dump_cache/url_to_filename_encoder.h"
+#include "net/tools/dump_cache/url_utilities.h"
#include "net/tools/flip_server/balsa_enums.h"
#include "net/tools/flip_server/balsa_frame.h"
#include "net/tools/flip_server/balsa_headers.h"
@@ -34,8 +36,6 @@
#include "net/tools/flip_server/ring_buffer.h"
#include "net/tools/flip_server/simple_buffer.h"
#include "net/tools/flip_server/split.h"
-#include "net/tools/flip_server/url_to_filename_encoder.h"
-#include "net/tools/flip_server/url_utilities.h"
////////////////////////////////////////////////////////////////////////////////
@@ -2290,4 +2290,3 @@ int main(int argc, char**argv) {
}
return 0;
}
-
diff --git a/net/tools/flip_server/http_message_constants.h b/net/tools/flip_server/http_message_constants.h
index de700cc..f34d783 100644
--- a/net/tools/flip_server/http_message_constants.h
+++ b/net/tools/flip_server/http_message_constants.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_HTTP_MESSAGE_CONSTANTS_H__
#define NET_TOOLS_FLIP_SERVER_HTTP_MESSAGE_CONSTANTS_H__
+#pragma once
namespace net {
diff --git a/net/tools/flip_server/loadtime_measurement.h b/net/tools/flip_server/loadtime_measurement.h
index b46217e..fa069d4 100644
--- a/net/tools/flip_server/loadtime_measurement.h
+++ b/net/tools/flip_server/loadtime_measurement.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H__
#define NET_TOOLS_FLIP_SERVER_LOADTIME_MEASUREMENT_H__
+#pragma once
#include <errno.h>
#include <fcntl.h>
diff --git a/net/tools/flip_server/other_defines.h b/net/tools/flip_server/other_defines.h
index ed824e4..dda2151 100644
--- a/net/tools/flip_server/other_defines.h
+++ b/net/tools/flip_server/other_defines.h
@@ -1,5 +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.
+
#ifndef NET_TOOLS_FLIP_SERVER_OTHER_DEFINES
#define NET_TOOLS_FLIP_SERVER_OTHER_DEFINES
+#pragma once
class NullStream {
public:
diff --git a/net/tools/flip_server/ring_buffer.h b/net/tools/flip_server/ring_buffer.h
index a1a5491..ee6f360 100644
--- a/net/tools/flip_server/ring_buffer.h
+++ b/net/tools/flip_server/ring_buffer.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_RING_BUFFER_H__
#define NET_TOOLS_FLIP_SERVER_RING_BUFFER_H__
+#pragma once
#include "base/scoped_ptr.h"
#include "net/tools/flip_server/buffer_interface.h"
diff --git a/net/tools/flip_server/simple_buffer.h b/net/tools/flip_server/simple_buffer.h
index c10558a..71fafc9 100644
--- a/net/tools/flip_server/simple_buffer.h
+++ b/net/tools/flip_server/simple_buffer.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_SIMPLE_BUFFER_H__
#define NET_TOOLS_FLIP_SERVER_SIMPLE_BUFFER_H__
+#pragma once
#include <string>
diff --git a/net/tools/flip_server/split.h b/net/tools/flip_server/split.h
index 247fef8..16ab74d 100644
--- a/net/tools/flip_server/split.h
+++ b/net/tools/flip_server/split.h
@@ -4,6 +4,7 @@
#ifndef NET_TOOLS_FLIP_SERVER_SPLIT_H_
#define NET_TOOLS_FLIP_SERVER_SPLIT_H_
+#pragma once
#include <vector>
#include "base/string_piece.h"
diff --git a/net/tools/flip_server/string_piece_utils.h b/net/tools/flip_server/string_piece_utils.h
index 3f3a251..5a4336f 100644
--- a/net/tools/flip_server/string_piece_utils.h
+++ b/net/tools/flip_server/string_piece_utils.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_TOOLS_FLIP_SERVER_STRING_PIECE_UTILS_H_
#define NET_TOOLS_FLIP_SERVER_STRING_PIECE_UTILS_H_
+#pragma once
#include <ctype.h>
diff --git a/net/tools/flip_server/url_to_filename_encoder.h b/net/tools/flip_server/url_to_filename_encoder.h
deleted file mode 100644
index 568c1ee..0000000
--- a/net/tools/flip_server/url_to_filename_encoder.h
+++ /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.
-
-#ifndef NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__
-#define NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__
-
-#include <string>
-#include "net/tools/flip_server/url_utilities.h"
-
-namespace net {
-
-// Helper class for converting a URL into a filename.
-class UrlToFilenameEncoder {
- public:
- // Given a |url| and a |base_path|, returns a string which represents this
- // |url|.
- static std::string Encode(const std::string& url, std::string base_path) {
- std::string clean_url(url);
- if (clean_url.length() && clean_url[clean_url.length()-1] == '/')
- clean_url.append("index.html");
-
- std::string host = UrlUtilities::GetUrlHost(clean_url);
- std::string filename(base_path);
- filename = filename.append(host + "/");
-
- std::string url_filename = UrlUtilities::GetUrlPath(clean_url);
- // Strip the leading '/'
- if (url_filename[0] == '/')
- url_filename = url_filename.substr(1);
-
- // replace '/' with '\'
- ConvertToSlashes(url_filename);
-
- // strip double slashes ("\\")
- StripDoubleSlashes(url_filename);
-
- // Save path as filesystem-safe characters
- url_filename = Escape(url_filename);
- filename = filename.append(url_filename);
-
-#ifndef WIN32
- // Last step - convert to native slashes!
- const std::string slash("/");
- const std::string backslash("\\");
- ReplaceAll(filename, backslash, slash);
-#endif
-
- return filename;
- }
-
- private:
- static const unsigned int kMaximumSubdirectoryLength = 128;
-
-
- // Escape the given input |path| and chop any individual components
- // of the path which are greater than kMaximumSubdirectoryLength characters
- // into two chunks.
- static std::string Escape(const std::string& path) {
- std::string output;
-
- // Note: We also chop paths into medium sized 'chunks'.
- // This is due to the incompetence of the windows
- // filesystem, which still hasn't figured out how
- // to deal with long filenames.
- unsigned int last_slash = 0;
- for (size_t index = 0; index < path.length(); index++) {
- char ch = path[index];
- if (ch == 0x5C)
- last_slash = index;
- if ((ch == 0x2D) || // hyphen
- (ch == 0x5C) || (ch == 0x5F) || // backslash, underscore
- ((0x30 <= ch) && (ch <= 0x39)) || // Digits [0-9]
- ((0x41 <= ch) && (ch <= 0x5A)) || // Uppercase [A-Z]
- ((0x61 <= ch) && (ch <= 0x7A))) { // Lowercase [a-z]
- output.append(&path[index],1);
- } else {
- char encoded[3];
- encoded[0] = 'x';
- encoded[1] = ch / 16;
- encoded[1] += (encoded[1] >= 10) ? 'A' - 10 : '0';
- encoded[2] = ch % 16;
- encoded[2] += (encoded[2] >= 10) ? 'A' - 10 : '0';
- output.append(encoded, 3);
- }
- if (index - last_slash > kMaximumSubdirectoryLength) {
-#ifdef WIN32
- char slash = '\\';
-#else
- char slash = '/';
-#endif
- output.append(&slash, 1);
- last_slash = index;
- }
- }
- return output;
- }
-
- // Replace all instances of |from| within |str| as |to|.
- static void ReplaceAll(std::string& str, const std::string& from,
- const std::string& to) {
- std::string::size_type pos(0);
- while ((pos = str.find(from, pos)) != std::string::npos) {
- str.replace(pos, from.size(), to);
- pos += from.size();
- }
- }
-
- // Replace all instances of "/" with "\" in |path|.
- static void ConvertToSlashes(std::string& path) {
- const std::string slash("/");
- const std::string backslash("\\");
- ReplaceAll(path, slash, backslash);
- }
-
- // Replace all instances of "\\" with "%5C%5C" in |path|.
- static void StripDoubleSlashes(std::string& path) {
- const std::string doubleslash("\\\\");
- const std::string escaped_doubleslash("%5C%5C");
- ReplaceAll(path, doubleslash, escaped_doubleslash);
- }
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__
-
diff --git a/net/tools/flip_server/url_utilities.h b/net/tools/flip_server/url_utilities.h
deleted file mode 100644
index 52a768a..0000000
--- a/net/tools/flip_server/url_utilities.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 NET_TOOLS_FLIP_SERVER_URL_UTILITIES_H__
-#define NET_TOOLS_FLIP_SERVER_URL_UTILITIES_H__
-
-#include <string>
-
-namespace net {
-
-struct UrlUtilities {
- // Get the host from an url
- static std::string GetUrlHost(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- size_t next_slash = url.find_first_of('/', b);
- size_t next_colon = url.find_first_of(':', b);
- if (next_slash != std::string::npos
- && next_colon != std::string::npos
- && next_colon < next_slash) {
- return std::string(url, b, next_colon - b);
- }
- if (next_slash == std::string::npos) {
- if (next_colon != std::string::npos) {
- return std::string(url, next_colon - b);
- } else {
- next_slash = url.size();
- }
- }
- return std::string(url, b, next_slash - b);
- }
-
- // Get the host + path portion of an url
- // e.g http://www.foo.com/path
- // returns www.foo.com/path
- static std::string GetUrlHostPath(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- return std::string(url, b);
- }
-
- // Get the path portion of an url
- // e.g http://www.foo.com/path
- // returns /path
- static std::string GetUrlPath(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- b = url.find("/", b+1);
- if (b == std::string::npos)
- return "/";
-
- return std::string(url, b);
- }
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_URL_UTILITIES_H__
-
diff --git a/net/tools/hresolv/hresolv.cc b/net/tools/hresolv/hresolv.cc
index d524bd7..250a6b2 100644
--- a/net/tools/hresolv/hresolv.cc
+++ b/net/tools/hresolv/hresolv.cc
@@ -28,10 +28,11 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
-#include "base/waitable_event.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/host_resolver_impl.h"
@@ -133,28 +134,28 @@ std::string FormatAddrinfoDetails(const struct addrinfo& ai,
std::string ai_addr = net::NetAddressToString(&ai);
std::string ai_canonname;
if (ai.ai_canonname) {
- ai_canonname = StringPrintf("%s ai_canonname: %s\n",
- indent,
- ai.ai_canonname);
+ ai_canonname = base::StringPrintf("%s ai_canonname: %s\n",
+ indent,
+ ai.ai_canonname);
}
- return StringPrintf("%saddrinfo {\n"
- "%s ai_flags: %s\n"
- "%s ai_family: %s\n"
- "%s ai_socktype: %s\n"
- "%s ai_protocol: %s\n"
- "%s ai_addrlen: %d\n"
- "%s ai_addr: %s\n"
- "%s"
- "%s}\n",
- indent,
- indent, ai_flags.c_str(),
- indent, ai_family,
- indent, ai_socktype,
- indent, ai_protocol,
- indent, ai.ai_addrlen,
- indent, ai_addr.c_str(),
- ai_canonname.c_str(),
- indent);
+ return base::StringPrintf("%saddrinfo {\n"
+ "%s ai_flags: %s\n"
+ "%s ai_family: %s\n"
+ "%s ai_socktype: %s\n"
+ "%s ai_protocol: %s\n"
+ "%s ai_addrlen: %d\n"
+ "%s ai_addr: %s\n"
+ "%s"
+ "%s}\n",
+ indent,
+ indent, ai_flags.c_str(),
+ indent, ai_family,
+ indent, ai_socktype,
+ indent, ai_protocol,
+ indent, ai.ai_addrlen,
+ indent, ai_addr.c_str(),
+ ai_canonname.c_str(),
+ indent);
}
std::string FormatAddressList(const net::AddressList& address_list,
@@ -190,7 +191,7 @@ class DelayedResolve : public base::RefCounted<DelayedResolve> {
void Start() {
net::CompletionCallback* callback = (is_async_) ? &io_callback_ : NULL;
- net::HostResolver::RequestInfo request_info(host_, 80);
+ net::HostResolver::RequestInfo request_info(net::HostPortPair(host_, 80));
int rv = resolver_->Resolve(request_info,
&address_list_,
callback,
@@ -324,7 +325,7 @@ bool ParseCommandLine(CommandLine* command_line, CommandLineOptions* options) {
options->async = command_line->HasSwitch(kAsync);
if (command_line->HasSwitch(kCacheSize)) {
std::string cache_size = command_line->GetSwitchValueASCII(kCacheSize);
- bool valid_size = StringToInt(cache_size, &options->cache_size);
+ bool valid_size = base::StringToInt(cache_size, &options->cache_size);
if (valid_size) {
valid_size = options->cache_size >= 0;
}
@@ -336,7 +337,7 @@ bool ParseCommandLine(CommandLine* command_line, CommandLineOptions* options) {
if (command_line->HasSwitch(kCacheTtl)) {
std::string cache_ttl = command_line->GetSwitchValueASCII(kCacheTtl);
- bool valid_ttl = StringToInt(cache_ttl, &options->cache_ttl);
+ bool valid_ttl = base::StringToInt(cache_ttl, &options->cache_ttl);
if (valid_ttl) {
valid_ttl = options->cache_ttl >= 0;
}
@@ -400,7 +401,7 @@ bool ReadHostsAndTimesFromFile(const FilePath& path,
}
case 2: {
int timestamp;
- if (!StringToInt(tokens[1], &timestamp)) {
+ if (!base::StringToInt(tokens[1], &timestamp)) {
// Unexpected value - keep going.
}
if (timestamp < previous_timestamp) {
@@ -451,7 +452,7 @@ int main(int argc, char** argv) {
base::TimeDelta::FromSeconds(0));
scoped_refptr<net::HostResolver> host_resolver(
- new net::HostResolverImpl(NULL, cache, 100u));
+ new net::HostResolverImpl(NULL, cache, 100u, NULL));
ResolverInvoker invoker(host_resolver.get());
invoker.ResolveAll(hosts_and_times, options.async);
diff --git a/net/tools/spdyshark/packet-spdy.h b/net/tools/spdyshark/packet-spdy.h
index 02b586b..b370a55 100644
--- a/net/tools/spdyshark/packet-spdy.h
+++ b/net/tools/spdyshark/packet-spdy.h
@@ -26,6 +26,7 @@
#ifndef __PACKET_SPDY_H__
#define __PACKET_SPDY_H__
+#pragma once
#include <epan/packet.h>
#ifdef HAVE_LIBZ
diff --git a/net/tools/testserver/chromiumsync.py b/net/tools/testserver/chromiumsync.py
index a15d265..843761a 100755
--- a/net/tools/testserver/chromiumsync.py
+++ b/net/tools/testserver/chromiumsync.py
@@ -9,19 +9,24 @@ The details of the protocol are described mostly by comments in the protocol
buffer definition at chrome/browser/sync/protocol/sync.proto.
"""
+import cgi
+import copy
import operator
import random
+import sys
import threading
+import app_specifics_pb2
import autofill_specifics_pb2
import bookmark_specifics_pb2
import extension_specifics_pb2
import nigori_specifics_pb2
import password_specifics_pb2
import preference_specifics_pb2
+import session_specifics_pb2
+import sync_pb2
import theme_specifics_pb2
import typed_url_specifics_pb2
-import sync_pb2
# An enumeration of the various kinds of data that can be synced.
# Over the wire, this enumeration is not used: a sync object's type is
@@ -29,26 +34,31 @@ import sync_pb2
# of a program, it is useful to have an enumeration.
ALL_TYPES = (
TOP_LEVEL, # The type of the 'Google Chrome' folder.
+ APPS,
AUTOFILL,
BOOKMARK,
EXTENSIONS,
NIGORI,
PASSWORD,
PREFERENCE,
- # SESSION,
+ SESSION,
THEME,
- TYPED_URL) = range(9)
+ TYPED_URL) = range(11)
+
+# Well-known server tag of the top level "Google Chrome" folder.
+TOP_LEVEL_FOLDER_TAG = 'google_chrome'
# Given a sync type from ALL_TYPES, find the extension token corresponding
# to that datatype. Note that TOP_LEVEL has no such token.
SYNC_TYPE_TO_EXTENSION = {
+ APPS: app_specifics_pb2.app,
AUTOFILL: autofill_specifics_pb2.autofill,
BOOKMARK: bookmark_specifics_pb2.bookmark,
EXTENSIONS: extension_specifics_pb2.extension,
NIGORI: nigori_specifics_pb2.nigori,
PASSWORD: password_specifics_pb2.password,
PREFERENCE: preference_specifics_pb2.preference,
- # SESSION: session_specifics_pb2.session, # Disabled
+ SESSION: session_specifics_pb2.session,
THEME: theme_specifics_pb2.theme,
TYPED_URL: typed_url_specifics_pb2.typed_url,
}
@@ -56,6 +66,15 @@ SYNC_TYPE_TO_EXTENSION = {
# The parent ID used to indicate a top-level node.
ROOT_ID = '0'
+
+class Error(Exception):
+ """Error class for this module."""
+
+
+class ProtobufExtensionNotUnique(Error):
+ """An entry should not have more than one protobuf extension present."""
+
+
def GetEntryType(entry):
"""Extract the sync type from a SyncEntry.
@@ -64,19 +83,22 @@ def GetEntryType(entry):
Returns:
A value from ALL_TYPES if the entry's type can be determined, or None
if the type cannot be determined.
+ Raises:
+ ProtobufExtensionNotUnique: More than one type was indicated by the entry.
"""
- if entry.server_defined_unique_tag == 'google_chrome':
+ if entry.server_defined_unique_tag == TOP_LEVEL_FOLDER_TAG:
return TOP_LEVEL
entry_types = GetEntryTypesFromSpecifics(entry.specifics)
if not entry_types:
return None
- # It is presupposed that the entry has at most one specifics extension
- # present. If there is more than one, either there's a bug, or else
- # the caller should use GetEntryTypes.
+
+ # If there is more than one, either there's a bug, or else the caller
+ # should use GetEntryTypes.
if len(entry_types) > 1:
- raise 'GetEntryType called with multiple extensions present.'
+ raise ProtobufExtensionNotUnique
return entry_types[0]
+
def GetEntryTypesFromSpecifics(specifics):
"""Determine the sync types indicated by an EntitySpecifics's extension(s).
@@ -92,11 +114,10 @@ def GetEntryTypesFromSpecifics(specifics):
A list of the sync types (values from ALL_TYPES) assocated with each
recognized extension of the specifics message.
"""
- entry_types = []
- for data_type, extension in SYNC_TYPE_TO_EXTENSION.iteritems():
- if specifics.HasExtension(extension):
- entry_types.append(data_type)
- return entry_types
+ return [data_type for data_type, extension
+ in SYNC_TYPE_TO_EXTENSION.iteritems()
+ if specifics.HasExtension(extension)]
+
def GetRequestedTypes(get_updates_message):
"""Determine the sync types requested by a client GetUpdates operation."""
@@ -106,9 +127,9 @@ def GetRequestedTypes(get_updates_message):
types.append(TOP_LEVEL)
return types
+
def GetDefaultEntitySpecifics(data_type):
- """Get an EntitySpecifics having a sync type's default extension value.
- """
+ """Get an EntitySpecifics having a sync type's default extension value."""
specifics = sync_pb2.EntitySpecifics()
if data_type in SYNC_TYPE_TO_EXTENSION:
extension_handle = SYNC_TYPE_TO_EXTENSION[data_type]
@@ -143,9 +164,9 @@ class PermanentItem(object):
self.parent_tag = parent_tag
self.sync_type = sync_type
+
class SyncDataModel(object):
- """Models the account state of one sync user.
- """
+ """Models the account state of one sync user."""
_BATCH_SIZE = 100
# Specify all the permanent items that a model might need.
@@ -166,22 +187,25 @@ class SyncDataModel(object):
parent_tag='google_chrome', sync_type=EXTENSIONS),
PermanentItem('google_chrome_passwords', name='Passwords',
parent_tag='google_chrome', sync_type=PASSWORD),
- # TODO(rsimha): Disabled since the protocol does not support it yet.
- # PermanentItem('google_chrome_sessions', name='Sessions',
- # parent_tag='google_chrome', SESSION),
+ PermanentItem('google_chrome_sessions', name='Sessions',
+ parent_tag='google_chrome', sync_type=SESSION),
PermanentItem('google_chrome_themes', name='Themes',
parent_tag='google_chrome', sync_type=THEME),
PermanentItem('google_chrome_typed_urls', name='Typed URLs',
parent_tag='google_chrome', sync_type=TYPED_URL),
PermanentItem('google_chrome_nigori', name='Nigori',
parent_tag='google_chrome', sync_type=NIGORI),
+ PermanentItem('google_chrome_apps', name='Apps',
+ parent_tag='google_chrome', sync_type=APPS),
]
def __init__(self):
- self._version = 0
-
# Monotonically increasing version number. The next object change will
# take on this value + 1.
+ self._version = 0
+
+ # The definitive copy of this client's items: a map from ID string to a
+ # SyncEntity protocol buffer.
self._entries = {}
# TODO(nick): uuid.uuid1() is better, but python 2.5 only.
@@ -196,7 +220,10 @@ class SyncDataModel(object):
Args:
entry: The entry to be added or updated.
"""
- self._version = self._version + 1
+ self._version += 1
+ # Maintain a global (rather than per-item) sequence number and use it
+ # both as the per-entry version as well as the update-progress timestamp.
+ # This simulates the behavior of the original server implementation.
entry.version = self._version
entry.sync_timestamp = self._version
@@ -217,6 +244,8 @@ class SyncDataModel(object):
Args:
tag: The unique, known-to-the-client tag of a server-generated item.
+ Returns:
+ The string value of the computed server ID.
"""
if tag and tag != ROOT_ID:
return '<server tag>%s' % tag
@@ -231,6 +260,8 @@ class SyncDataModel(object):
Args:
tag: The unique, opaque-to-the-server tag of a client-tagged item.
+ Returns:
+ The string value of the computed server ID.
"""
return '<client tag>%s' % tag
@@ -245,6 +276,8 @@ class SyncDataModel(object):
created this item.
client_item_id: An ID that uniquely identifies this item on the client
which created it.
+ Returns:
+ The string value of the computed server ID.
"""
# Using the client ID info is not required here (we could instead generate
# a random ID), but it's useful for debugging.
@@ -270,13 +303,14 @@ class SyncDataModel(object):
ordering. Otherwise, the entry will be given a position_in_parent
value placing it just after (to the right of) the new predecessor.
"""
- PREFERRED_GAP = 2 ** 20
- # Compute values at the beginning or end.
+ preferred_gap = 2 ** 20
+
def ExtendRange(current_limit_entry, sign_multiplier):
+ """Compute values at the beginning or end."""
if current_limit_entry.id_string == entry.id_string:
step = 0
else:
- step = sign_multiplier * PREFERRED_GAP
+ step = sign_multiplier * preferred_gap
return current_limit_entry.position_in_parent + step
siblings = [x for x in self._entries.values()
@@ -287,21 +321,22 @@ class SyncDataModel(object):
if not siblings:
# First item in this container; start in the middle.
entry.position_in_parent = 0
- elif prev_id == '':
+ elif not prev_id:
# A special value in the protocol. Insert at first position.
entry.position_in_parent = ExtendRange(siblings[0], -1)
else:
- # Consider items along with their successors.
- for a, b in zip(siblings, siblings[1:]):
- if a.id_string != prev_id:
+ # Handle mid-insertion; consider items along with their successors.
+ for item, successor in zip(siblings, siblings[1:]):
+ if item.id_string != prev_id:
continue
- elif b.id_string == entry.id_string:
+ elif successor.id_string == entry.id_string:
# We're already in place; don't change anything.
- entry.position_in_parent = b.position_in_parent
+ entry.position_in_parent = successor.position_in_parent
else:
- # Interpolate new position between two others.
- entry.position_in_parent = (
- a.position_in_parent * 7 + b.position_in_parent) / 8
+ # Interpolate new position between the previous item and its
+ # existing successor.
+ entry.position_in_parent = (item.position_in_parent * 7 +
+ successor.position_in_parent) / 8
break
else:
# Insert at end. Includes the case where prev_id is None.
@@ -362,9 +397,11 @@ class SyncDataModel(object):
more recently than this value will be retrieved; older items will
be filtered out.
Returns:
- A tuple of (version, entries). Version is a new timestamp value, which
- should be used as the starting point for the next query. Entries is the
- batch of entries meeting the current timestamp query.
+ A tuple of (version, entries, changes_remaining). Version is a new
+ timestamp value, which should be used as the starting point for the
+ next query. Entries is the batch of entries meeting the current
+ timestamp query. Changes_remaining indicates the number of changes
+ left on the server after this batch.
"""
if timestamp == 0:
self._CreatePermanentItems(requested_types)
@@ -376,17 +413,16 @@ class SyncDataModel(object):
batch = new_changes[:self._BATCH_SIZE]
if not batch:
# Client is up to date.
- return (timestamp, [])
+ return (timestamp, [], 0)
# Restrict batch to requested types. Tombstones are untyped
# and will always get included.
- filtered = []
- for x in batch:
- if (GetEntryType(x) in requested_types) or x.deleted:
- filtered.append(DeepCopyOfProto(x))
+ filtered = [DeepCopyOfProto(item) for item in batch
+ if item.deleted or (GetEntryType(item) in requested_types)]
+
# The new client timestamp is the timestamp of the last item in the
# batch, even if that item was filtered out.
- return (batch[-1].version, filtered)
+ return (batch[-1].version, filtered, len(new_changes) - len(batch))
def _CheckVersionForCommit(self, entry):
"""Perform an optimistic concurrency check on the version number.
@@ -402,15 +438,12 @@ class SyncDataModel(object):
newest server version for the given entry.
"""
if entry.id_string in self._entries:
- if (self._entries[entry.id_string].version != entry.version and
- not self._entries[entry.id_string].deleted):
- # Version mismatch that is not a tombstone recreation.
- return False
+ # Allow edits/deletes if the version matches, and any undeletion.
+ return (self._entries[entry.id_string].version == entry.version or
+ self._entries[entry.id_string].deleted)
else:
- if entry.version != 0:
- # Edit to an item that does not exist.
- return False
- return True
+ # Allow unknown ID only if the client thinks it's new too.
+ return entry.version == 0
def _CheckParentIdForCommit(self, entry):
"""Check that the parent ID referenced in a SyncEntity actually exists.
@@ -509,15 +542,48 @@ class SyncDataModel(object):
# tombstone. A sync server must track deleted IDs forever, since it does
# not keep track of client knowledge (there's no deletion ACK event).
if entry.deleted:
- # Only the ID, version and deletion state are preserved on a tombstone.
- # TODO(nick): Does the production server not preserve the type? Not
- # doing so means that tombstones cannot be filtered based on
- # requested_types at GetUpdates time.
- tombstone = sync_pb2.SyncEntity()
- tombstone.id_string = entry.id_string
- tombstone.deleted = True
- tombstone.name = ''
- entry = tombstone
+ def MakeTombstone(id_string):
+ """Make a tombstone entry that will replace the entry being deleted.
+
+ Args:
+ id_string: Index of the SyncEntity to be deleted.
+ Returns:
+ A new SyncEntity reflecting the fact that the entry is deleted.
+ """
+ # Only the ID, version and deletion state are preserved on a tombstone.
+ # TODO(nick): Does the production server not preserve the type? Not
+ # doing so means that tombstones cannot be filtered based on
+ # requested_types at GetUpdates time.
+ tombstone = sync_pb2.SyncEntity()
+ tombstone.id_string = id_string
+ tombstone.deleted = True
+ tombstone.name = ''
+ return tombstone
+
+ def IsChild(child_id):
+ """Check if a SyncEntity is a child of entry, or any of its children.
+
+ Args:
+ child_id: Index of the SyncEntity that is a possible child of entry.
+ Returns:
+ True if it is a child; false otherwise.
+ """
+ if child_id not in self._entries:
+ return False
+ if self._entries[child_id].parent_id_string == entry.id_string:
+ return True
+ return IsChild(self._entries[child_id].parent_id_string)
+
+ # Identify any children entry might have.
+ child_ids = [child.id_string for child in self._entries.itervalues()
+ if IsChild(child.id_string)]
+
+ # Mark all children that were identified as deleted.
+ for child_id in child_ids:
+ self._SaveEntry(MakeTombstone(child_id))
+
+ # Delete entry itself.
+ entry = MakeTombstone(entry.id_string)
else:
# Comments in sync.proto detail how the representation of positional
# ordering works: the 'insert_after_item_id' field specifies a
@@ -537,15 +603,15 @@ class SyncDataModel(object):
# Preserve the originator info, which the client is not required to send
# when updating.
base_entry = self._entries.get(entry.id_string)
- if base_entry and not entry.HasField("originator_cache_guid"):
+ if base_entry and not entry.HasField('originator_cache_guid'):
entry.originator_cache_guid = base_entry.originator_cache_guid
entry.originator_client_item_id = base_entry.originator_client_item_id
# Commit the change. This also updates the version number.
self._SaveEntry(entry)
- # TODO(nick): Handle recursive deletion.
return entry
+
class TestServer(object):
"""An object to handle requests for one (and only one) Chrome Sync account.
@@ -558,8 +624,23 @@ class TestServer(object):
# The implementation supports exactly one account; its state is here.
self.account = SyncDataModel()
self.account_lock = threading.Lock()
-
- def HandleCommand(self, raw_request):
+ # Clients that have talked to us: a map from the full client ID
+ # to its nickname.
+ self.clients = {}
+ self.client_name_generator = ('+' * times + chr(c)
+ for times in xrange(0, sys.maxint) for c in xrange(ord('A'),ord('Z')))
+
+ def GetShortClientName(self, query):
+ parsed = cgi.parse_qs(query[query.find('?')+1:])
+ client_id = parsed.get('client_id')
+ if not client_id:
+ return '?'
+ client_id = client_id[0]
+ if client_id not in self.clients:
+ self.clients[client_id] = self.client_name_generator.next()
+ return self.clients[client_id]
+
+ def HandleCommand(self, query, raw_request):
"""Decode and handle a sync command from a raw input of bytes.
This is the main entry point for this class. It is safe to call this
@@ -582,19 +663,21 @@ class TestServer(object):
response = sync_pb2.ClientToServerResponse()
response.error_code = sync_pb2.ClientToServerResponse.SUCCESS
response.store_birthday = self.account.store_birthday
+ log_context = "[Client %s -> %s.py]" % (self.GetShortClientName(query),
+ __name__)
if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE:
- print 'Authenticate'
+ print '%s Authenticate' % log_context
# We accept any authentication token, and support only one account.
# TODO(nick): Mock out the GAIA authentication as well; hook up here.
response.authenticate.user.email = 'syncjuser@chromium'
response.authenticate.user.display_name = 'Sync J User'
elif contents == sync_pb2.ClientToServerMessage.COMMIT:
- print 'Commit'
+ print '%s Commit' % log_context
self.HandleCommit(request.commit, response.commit)
elif contents == sync_pb2.ClientToServerMessage.GET_UPDATES:
- print ('GetUpdates from timestamp %d' %
- request.get_updates.from_timestamp)
+ print ('%s GetUpdates from timestamp %d' %
+ (log_context, request.get_updates.from_timestamp))
self.HandleGetUpdates(request.get_updates, response.get_updates)
return (200, response.SerializeToString())
finally:
@@ -655,13 +738,14 @@ class TestServer(object):
"""
update_response.SetInParent()
requested_types = GetRequestedTypes(update_request)
- new_timestamp, entries = self.account.GetChangesFromTimestamp(
+ new_timestamp, entries, remaining = self.account.GetChangesFromTimestamp(
requested_types, update_request.from_timestamp)
+ update_response.changes_remaining = remaining
# If the client is up to date, we are careful not to set the
# new_timestamp field.
if new_timestamp != update_request.from_timestamp:
update_response.new_timestamp = new_timestamp
- for e in entries:
+ for entry in entries:
reply = update_response.entries.add()
- reply.CopyFrom(e)
+ reply.CopyFrom(entry)
diff --git a/net/tools/testserver/chromiumsync_test.py b/net/tools/testserver/chromiumsync_test.py
index bb73d05..f753c3b 100755
--- a/net/tools/testserver/chromiumsync_test.py
+++ b/net/tools/testserver/chromiumsync_test.py
@@ -7,8 +7,6 @@
import unittest
-from google.protobuf import text_format
-
import chromiumsync
import sync_pb2
@@ -20,21 +18,23 @@ class SyncDataModelTest(unittest.TestCase):
self.model._entries[proto.id_string] = proto
def testPermanentItemSpecs(self):
- SPECS = chromiumsync.SyncDataModel._PERMANENT_ITEM_SPECS
- # parent_tags must be declared before use.
+ specs = chromiumsync.SyncDataModel._PERMANENT_ITEM_SPECS
+
declared_specs = set(['0'])
- for spec in SPECS:
- self.assertTrue(spec.parent_tag in declared_specs)
+ for spec in specs:
+ self.assertTrue(spec.parent_tag in declared_specs, 'parent tags must '
+ 'be declared before use')
declared_specs.add(spec.tag)
- # Every sync datatype should have a permanent folder associated with it.
- unique_datatypes = set([x.sync_type for x in SPECS])
- self.assertEqual(unique_datatypes,
- set(chromiumsync.ALL_TYPES))
+
+ unique_datatypes = set([x.sync_type for x in specs])
+ self.assertEqual(unique_datatypes, set(chromiumsync.ALL_TYPES),
+ 'Every sync datatype should have a permanent folder '
+ 'associated with it')
def testSaveEntry(self):
proto = sync_pb2.SyncEntity()
- proto.id_string = 'abcd';
- proto.version = 0;
+ proto.id_string = 'abcd'
+ proto.version = 0
self.assertFalse(self.model._ItemExists(proto.id_string))
self.model._SaveEntry(proto)
self.assertEqual(1, proto.version)
@@ -116,7 +116,8 @@ class SyncDataModelTest(unittest.TestCase):
self.model = chromiumsync.SyncDataModel()
request_types = [sync_type, chromiumsync.TOP_LEVEL]
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
expected_count = self.ExpectedPermanentItemCount(sync_type)
self.assertEqual(expected_count, version)
@@ -128,19 +129,24 @@ class SyncDataModelTest(unittest.TestCase):
self.assertTrue(change.version <= version)
# Test idempotence: another GetUpdates from ts=0 shouldn't recreate.
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(expected_count, version)
self.assertEqual(expected_count, len(changes))
+ self.assertEqual(0, remaining)
# Doing a wider GetUpdates from timestamp zero shouldn't recreate either.
- new_version, changes = self.model.GetChangesFromTimestamp(
- chromiumsync.ALL_TYPES, 0)
+ new_version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(chromiumsync.ALL_TYPES, 0))
self.assertEqual(len(chromiumsync.SyncDataModel._PERMANENT_ITEM_SPECS),
- new_version)
+ new_version)
self.assertEqual(new_version, len(changes))
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ self.assertEqual(0, remaining)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(new_version, version)
self.assertEqual(expected_count, len(changes))
+ self.assertEqual(0, remaining)
def testBatchSize(self):
for sync_type in chromiumsync.ALL_TYPES[1:]:
@@ -153,19 +159,23 @@ class SyncDataModelTest(unittest.TestCase):
entry.id_string = 'batch test %d' % i
entry.specifics.CopyFrom(specifics)
self.model._SaveEntry(entry)
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ last_bit = self.ExpectedPermanentItemCount(sync_type)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(self.model._BATCH_SIZE, version)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE*2 + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE*2, version)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE*3, version)
- expected_dingleberry = self.ExpectedPermanentItemCount(sync_type)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
- self.assertEqual(self.model._BATCH_SIZE*3 + expected_dingleberry,
- version)
+ self.assertEqual(last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
+ self.assertEqual(self.model._BATCH_SIZE*3 + last_bit, version)
+ self.assertEqual(0, changes_remaining)
# Now delete a third of the items.
for i in xrange(self.model._BATCH_SIZE*3 - 1, 0, -3):
@@ -175,19 +185,23 @@ class SyncDataModelTest(unittest.TestCase):
self.model._SaveEntry(entry)
# The batch counts shouldn't change.
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(self.model._BATCH_SIZE, len(changes))
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE*2 + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE, len(changes))
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE, len(changes))
- expected_dingleberry = self.ExpectedPermanentItemCount(sync_type)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
- self.assertEqual(expected_dingleberry, len(changes))
- self.assertEqual(self.model._BATCH_SIZE*4 + expected_dingleberry, version)
+ self.assertEqual(last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
+ self.assertEqual(last_bit, len(changes))
+ self.assertEqual(self.model._BATCH_SIZE*4 + last_bit, version)
+ self.assertEqual(0, changes_remaining)
def testCommitEachDataType(self):
for sync_type in chromiumsync.ALL_TYPES[1:]:
@@ -198,10 +212,11 @@ class SyncDataModelTest(unittest.TestCase):
commit_session = {}
# Start with a GetUpdates from timestamp 0, to populate permanent items.
- original_version, original_changes = (
+ original_version, original_changes, changes_remaining = (
self.model.GetChangesFromTimestamp([sync_type], 0))
- def DoCommit(original=None, id='', name=None, parent=None, prev=None):
+ def DoCommit(original=None, id_string='', name=None, parent=None,
+ prev=None):
proto = sync_pb2.SyncEntity()
if original is not None:
proto.version = original.version
@@ -209,7 +224,7 @@ class SyncDataModelTest(unittest.TestCase):
proto.parent_id_string = original.parent_id_string
proto.name = original.name
else:
- proto.id_string = id
+ proto.id_string = id_string
proto.version = 0
proto.specifics.CopyFrom(specifics)
if name is not None:
@@ -227,14 +242,14 @@ class SyncDataModelTest(unittest.TestCase):
return (proto, result)
# Commit a new item.
- proto1, result1 = DoCommit(name='namae', id='Foo',
+ proto1, result1 = DoCommit(name='namae', id_string='Foo',
parent=original_changes[-1])
# Commit an item whose parent is another item (referenced via the
# pre-commit ID).
- proto2, result2 = DoCommit(name='Secondo', id='Bar',
+ proto2, result2 = DoCommit(name='Secondo', id_string='Bar',
parent=proto1)
# Commit a sibling of the second item.
- proto3, result3 = DoCommit(name='Third!', id='Baz',
+ proto3, result3 = DoCommit(name='Third!', id_string='Baz',
parent=proto1, prev=proto2)
self.assertEqual(3, len(commit_session))
@@ -243,21 +258,22 @@ class SyncDataModelTest(unittest.TestCase):
self.assertEqual(r.originator_client_item_id, p.id_string)
self.assertEqual(r.originator_cache_guid, my_cache_guid)
self.assertTrue(r is not self.model._entries[r.id_string],
- "Commit result didn't make a defensive copy.")
+ "Commit result didn't make a defensive copy.")
self.assertTrue(p is not self.model._entries[r.id_string],
- "Commit result didn't make a defensive copy.")
+ "Commit result didn't make a defensive copy.")
self.assertEqual(commit_session.get(p.id_string), r.id_string)
self.assertTrue(r.version > original_version)
self.assertEqual(result1.parent_id_string, proto1.parent_id_string)
self.assertEqual(result2.parent_id_string, result1.id_string)
- version, changes = self.model.GetChangesFromTimestamp([sync_type],
- original_version)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp([sync_type], original_version))
self.assertEqual(3, len(changes))
+ self.assertEqual(0, remaining)
self.assertEqual(original_version + 3, version)
self.assertEqual([result1, result2, result3], changes)
for c in changes:
self.assertTrue(c is not self.model._entries[c.id_string],
- "GetChanges didn't make a defensive copy.")
+ "GetChanges didn't make a defensive copy.")
self.assertTrue(result2.position_in_parent < result3.position_in_parent)
self.assertEqual(0, result2.position_in_parent)
@@ -270,15 +286,15 @@ class SyncDataModelTest(unittest.TestCase):
my_cache_guid = 'A different GUID'
proto2b, result2b = DoCommit(original=result2,
parent=original_changes[-1])
- proto4, result4 = DoCommit(id='ID4', name='Four',
+ proto4, result4 = DoCommit(id_string='ID4', name='Four',
parent=result2, prev=None)
proto1b, result1b = DoCommit(original=result1,
parent=result2, prev=proto4)
- proto5, result5 = DoCommit(id='ID5', name='Five', parent=result2,
+ proto5, result5 = DoCommit(id_string='ID5', name='Five', parent=result2,
prev=result1)
- self.assertEqual(2, len(commit_session),
- 'Only new items in second batch should be in the session')
+ self.assertEqual(2, len(commit_session), 'Only new items in second '
+ 'batch should be in the session')
for p, r, original in [(proto2b, result2b, proto2),
(proto4, result4, proto4),
(proto1b, result1b, proto1),
@@ -286,25 +302,26 @@ class SyncDataModelTest(unittest.TestCase):
self.assertEqual(r.originator_client_item_id, original.id_string)
if original is not p:
self.assertEqual(r.id_string, p.id_string,
- 'Ids should be stable after first commit')
+ 'Ids should be stable after first commit')
self.assertEqual(r.originator_cache_guid, old_cache_guid)
else:
self.assertNotEqual(r.id_string, p.id_string)
self.assertEqual(r.originator_cache_guid, my_cache_guid)
self.assertEqual(commit_session.get(p.id_string), r.id_string)
self.assertTrue(r is not self.model._entries[r.id_string],
- "Commit result didn't make a defensive copy.")
+ "Commit result didn't make a defensive copy.")
self.assertTrue(p is not self.model._entries[r.id_string],
- "Commit didn't make a defensive copy.")
+ "Commit didn't make a defensive copy.")
self.assertTrue(r.version > p.version)
- version, changes = self.model.GetChangesFromTimestamp([sync_type],
- original_version)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp([sync_type], original_version))
self.assertEqual(5, len(changes))
+ self.assertEqual(0, remaining)
self.assertEqual(original_version + 7, version)
self.assertEqual([result3, result2b, result4, result1b, result5], changes)
for c in changes:
self.assertTrue(c is not self.model._entries[c.id_string],
- "GetChanges didn't make a defensive copy.")
+ "GetChanges didn't make a defensive copy.")
self.assertTrue(result4.parent_id_string ==
result1b.parent_id_string ==
result5.parent_id_string ==
@@ -313,5 +330,6 @@ class SyncDataModelTest(unittest.TestCase):
result1b.position_in_parent <
result5.position_in_parent)
+
if __name__ == '__main__':
- unittest.main() \ No newline at end of file
+ unittest.main()
diff --git a/net/tools/testserver/run_testserver.cc b/net/tools/testserver/run_testserver.cc
index 716e320..157ce3e 100644
--- a/net/tools/testserver/run_testserver.cc
+++ b/net/tools/testserver/run_testserver.cc
@@ -8,7 +8,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
-#include "net/url_request/url_request_unittest.h"
+#include "net/test/test_server.h"
static void PrintUsage() {
printf("run_testserver --doc-root=relpath [--http|--https|--ftp]\n");
@@ -29,41 +29,28 @@ int main(int argc, const char* argv[]) {
return -1;
}
- std::string protocol;
- int port;
- if (command_line->HasSwitch("https")) {
- protocol = "https";
- port = net::TestServerLauncher::kOKHTTPSPort;
- } else if (command_line->HasSwitch("ftp")) {
- protocol = "ftp";
- port = kFTPDefaultPort;
- } else {
- protocol = "http";
- port = kHTTPDefaultPort;
- }
- std::wstring doc_root = command_line->GetSwitchValue("doc-root");
+ FilePath doc_root = command_line->GetSwitchValuePath("doc-root");
if (doc_root.empty()) {
printf("Error: --doc-root must be specified\n");
PrintUsage();
return -1;
}
- // Launch testserver
- scoped_refptr<BaseTestServer> test_server;
- if (protocol == "https") {
- test_server = HTTPSTestServer::CreateGoodServer(doc_root);
- } else if (protocol == "ftp") {
- test_server = FTPTestServer::CreateServer(doc_root);
- } else if (protocol == "http") {
- test_server = HTTPTestServer::CreateServer(doc_root, NULL);
- } else {
- NOTREACHED();
+ net::TestServer::Type server_type(net::TestServer::TYPE_HTTP);
+ if (command_line->HasSwitch("https")) {
+ server_type = net::TestServer::TYPE_HTTPS;
+ } else if (command_line->HasSwitch("ftp")) {
+ server_type = net::TestServer::TYPE_FTP;
+ }
+
+ net::TestServer test_server(server_type, doc_root);
+ if (!test_server.Start()) {
+ printf("Error: failed to start test server. Exiting.\n");
+ return -1;
}
- printf("testserver running at %s://%s:%d (type ctrl+c to exit)\n",
- protocol.c_str(),
- net::TestServerLauncher::kHostName,
- port);
+ printf("testserver running at %s (type ctrl+c to exit)\n",
+ test_server.host_port_pair().ToString().c_str());
message_loop.Run();
return 0;
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 8e3df5e..9f99d71 100644
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -23,13 +23,15 @@ import SocketServer
import sys
import time
import urllib2
+import warnings
+
+# Ignore deprecation warnings, they make our output more cluttered.
+warnings.filterwarnings("ignore", category=DeprecationWarning)
import pyftpdlib.ftpserver
import tlslite
import tlslite.api
-import chromiumsync
-
try:
import hashlib
_new_md5 = hashlib.md5
@@ -37,6 +39,9 @@ except ImportError:
import md5
_new_md5 = md5.new
+if sys.platform == 'win32':
+ import msvcrt
+
SERVER_HTTP = 0
SERVER_FTP = 1
@@ -59,13 +64,21 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer):
"""This is a specialization of StoppableHTTPerver that add https support."""
- def __init__(self, server_address, request_hander_class, cert_path):
+ def __init__(self, server_address, request_hander_class, cert_path,
+ ssl_client_auth, ssl_client_cas):
s = open(cert_path).read()
x509 = tlslite.api.X509()
x509.parse(s)
self.cert_chain = tlslite.api.X509CertChain([x509])
s = open(cert_path).read()
self.private_key = tlslite.api.parsePEMKey(s, private=True)
+ self.ssl_client_auth = ssl_client_auth
+ self.ssl_client_cas = []
+ for ca_file in ssl_client_cas:
+ s = open(ca_file).read()
+ x509 = tlslite.api.X509()
+ x509.parse(s)
+ self.ssl_client_cas.append(x509.subject)
self.session_cache = tlslite.api.SessionCache()
StoppableHTTPServer.__init__(self, server_address, request_hander_class)
@@ -75,23 +88,18 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer):
try:
tlsConnection.handshakeServer(certChain=self.cert_chain,
privateKey=self.private_key,
- sessionCache=self.session_cache)
+ sessionCache=self.session_cache,
+ reqCert=self.ssl_client_auth,
+ reqCAs=self.ssl_client_cas)
tlsConnection.ignoreAbruptClose = True
return True
+ except tlslite.api.TLSAbruptCloseError:
+ # Ignore abrupt close.
+ return True
except tlslite.api.TLSError, error:
print "Handshake failure:", str(error)
return False
-class ForkingHTTPServer(SocketServer.ForkingMixIn, StoppableHTTPServer):
- """This is a specialization of of StoppableHTTPServer which serves each
- request in a separate process"""
- pass
-
-class ForkingHTTPSServer(SocketServer.ForkingMixIn, HTTPSServer):
- """This is a specialization of of HTTPSServer which serves each
- request in a separate process"""
- pass
-
class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def __init__(self, request, client_address, socket_server):
@@ -133,18 +141,17 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.MultipartHandler,
self.DefaultResponseHandler]
self._post_handlers = [
- self.WriteFile,
self.EchoTitleHandler,
self.EchoAllHandler,
self.ChromiumSyncCommandHandler,
self.EchoHandler] + self._get_handlers
self._put_handlers = [
- self.WriteFile,
self.EchoTitleHandler,
self.EchoAllHandler,
self.EchoHandler] + self._get_handlers
self._mime_types = {
+ 'crx' : 'application/x-chrome-extension',
'gif': 'image/gif',
'jpeg' : 'image/jpeg',
'jpg' : 'image/jpeg',
@@ -155,8 +162,10 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, request,
client_address,
socket_server)
- # Class variable; shared across requests.
- _sync_handler = chromiumsync.TestServer()
+
+ def log_request(self, *args, **kwargs):
+ # Disable request logging to declutter test log output.
+ pass
def _ShouldHandleRequest(self, handler_name):
"""Determines if the path can be handled by the handler.
@@ -172,7 +181,7 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Returns the mime type for the specified file_name. So far it only looks
at the file extension."""
- (shortname, extension) = os.path.splitext(file_name)
+ (shortname, extension) = os.path.splitext(file_name.split("?")[0])
if len(extension) == 0:
# no extension.
return self._default_mime_type
@@ -478,32 +487,6 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.wfile.write(request)
return True
- def WriteFile(self):
- """This is handler dumps the content of POST/PUT request to a disk file
- into the data_dir/dump. Sub-directories are not supported."""
-
- prefix='/writefile/'
- if not self.path.startswith(prefix):
- return False
-
- file_name = self.path[len(prefix):]
-
- # do not allow fancy chars in file name
- re.sub('[^a-zA-Z0-9_.-]+', '', file_name)
- if len(file_name) and file_name[0] != '.':
- path = os.path.join(self.server.data_dir, 'dump', file_name);
- length = int(self.headers.getheader('content-length'))
- request = self.rfile.read(length)
- f = open(path, "wb")
- f.write(request);
- f.close()
-
- self.send_response(200)
- self.send_header('Content-type', 'text/html')
- self.end_headers()
- self.wfile.write('<html>%s</html>' % file_name)
- return True
-
def EchoTitleHandler(self):
"""This handler is like Echo, but sets the page title to the request."""
@@ -1031,7 +1014,11 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
length = int(self.headers.getheader('content-length'))
raw_request = self.rfile.read(length)
- http_response, raw_reply = self._sync_handler.HandleCommand(raw_request)
+ if not self.server._sync_handler:
+ import chromiumsync
+ self.server._sync_handler = chromiumsync.TestServer()
+ http_response, raw_reply = self.server._sync_handler.HandleCommand(
+ self.path, raw_request)
self.send_response(http_response)
self.end_headers()
self.wfile.write(raw_reply)
@@ -1147,15 +1134,6 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
self.wfile.write('Use <pre>%s?http://dest...</pre>' % redirect_name)
self.wfile.write('</body></html>')
-def MakeDumpDir(data_dir):
- """Create directory named 'dump' where uploaded data via HTTP POST/PUT
- requests will be stored. If the directory already exists all files and
- subdirectories will be deleted."""
- dump_dir = os.path.join(data_dir, 'dump');
- if os.path.isdir(dump_dir):
- shutil.rmtree(dump_dir)
- os.mkdir(dump_dir)
-
def MakeDataDir():
if options.data_dir:
if not os.path.isdir(options.data_dir):
@@ -1173,50 +1151,54 @@ def MakeDataDir():
return my_data_dir
-def TryKillingOldServer(port):
- # Note that an HTTP /kill request to the FTP server has the effect of
- # killing it.
- for protocol in ["http", "https"]:
- try:
- urllib2.urlopen("%s://localhost:%d/kill" % (protocol, port)).read()
- print "Killed old server instance on port %d (via %s)" % (port, protocol)
- except urllib2.URLError:
- # Common case, indicates no server running.
- pass
+class FileMultiplexer:
+ def __init__(self, fd1, fd2) :
+ self.__fd1 = fd1
+ self.__fd2 = fd2
+
+ def __del__(self) :
+ if self.__fd1 != sys.stdout and self.__fd1 != sys.stderr:
+ self.__fd1.close()
+ if self.__fd2 != sys.stdout and self.__fd2 != sys.stderr:
+ self.__fd2.close()
+
+ def write(self, text) :
+ self.__fd1.write(text)
+ self.__fd2.write(text)
+
+ def flush(self) :
+ self.__fd1.flush()
+ self.__fd2.flush()
def main(options, args):
- # redirect output to a log file so it doesn't spam the unit test output
logfile = open('testserver.log', 'w')
- sys.stderr = sys.stdout = logfile
+ sys.stdout = FileMultiplexer(sys.stdout, logfile)
+ sys.stderr = FileMultiplexer(sys.stderr, logfile)
port = options.port
- # Try to free up the port if there's an orphaned old instance.
- TryKillingOldServer(port)
-
if options.server_type == SERVER_HTTP:
if options.cert:
# let's make sure the cert file exists.
if not os.path.isfile(options.cert):
- print 'specified cert file not found: ' + options.cert + ' exiting...'
+ print 'specified server cert file not found: ' + options.cert + \
+ ' exiting...'
return
- if options.forking:
- server_class = ForkingHTTPSServer
- else:
- server_class = HTTPSServer
- server = server_class(('127.0.0.1', port), TestPageHandler, options.cert)
+ for ca_cert in options.ssl_client_ca:
+ if not os.path.isfile(ca_cert):
+ print 'specified trusted client CA file not found: ' + ca_cert + \
+ ' exiting...'
+ return
+ server = HTTPSServer(('127.0.0.1', port), TestPageHandler, options.cert,
+ options.ssl_client_auth, options.ssl_client_ca)
print 'HTTPS server started on port %d...' % port
else:
- if options.forking:
- server_class = ForkingHTTPServer
- else:
- server_class = StoppableHTTPServer
- server = server_class(('127.0.0.1', port), TestPageHandler)
+ server = StoppableHTTPServer(('127.0.0.1', port), TestPageHandler)
print 'HTTP server started on port %d...' % port
server.data_dir = MakeDataDir()
server.file_root_url = options.file_root_url
- MakeDumpDir(server.data_dir)
+ server._sync_handler = None
# means FTP Server
else:
@@ -1251,6 +1233,17 @@ def main(options, args):
server = pyftpdlib.ftpserver.FTPServer(address, ftp_handler)
print 'FTP server started on port %d...' % port
+ # Notify the parent that we've started. (BaseServer subclasses
+ # bind their sockets on construction.)
+ if options.startup_pipe is not None:
+ if sys.platform == 'win32':
+ fd = msvcrt.open_osfhandle(options.startup_pipe, 0)
+ else:
+ fd = options.startup_pipe
+ startup_pipe = os.fdopen(fd, "w")
+ startup_pipe.write("READY")
+ startup_pipe.close()
+
try:
server.serve_forever()
except KeyboardInterrupt:
@@ -1263,9 +1256,6 @@ if __name__ == '__main__':
const=SERVER_FTP, default=SERVER_HTTP,
dest='server_type',
help='FTP or HTTP server: default is HTTP.')
- option_parser.add_option('--forking', action='store_true', default=False,
- dest='forking',
- help='Serve each request in a separate process.')
option_parser.add_option('', '--port', default='8888', type='int',
help='Port used by the server.')
option_parser.add_option('', '--data-dir', dest='data_dir',
@@ -1274,6 +1264,12 @@ if __name__ == '__main__':
help='Specify that https should be used, specify '
'the path to the cert containing the private key '
'the server should use.')
+ option_parser.add_option('', '--ssl-client-auth', action='store_true',
+ help='Require SSL client auth on every connection.')
+ option_parser.add_option('', '--ssl-client-ca', action='append', default=[],
+ help='Specify that the client certificate request '
+ 'should indicate that it supports the CA contained '
+ 'in the specified certificate file')
option_parser.add_option('', '--file-root-url', default='/files/',
help='Specify a root URL for files served.')
option_parser.add_option('', '--never-die', default=False,
@@ -1281,6 +1277,9 @@ if __name__ == '__main__':
help='Prevent the server from dying when visiting '
'a /kill URL. Useful for manually running some '
'tests.')
+ option_parser.add_option('', '--startup-pipe', type='int',
+ dest='startup_pipe',
+ help='File handle of pipe to parent process')
options, args = option_parser.parse_args()
sys.exit(main(options, args))
diff --git a/net/tools/tld_cleanup/tld_cleanup.cc b/net/tools/tld_cleanup/tld_cleanup.cc
index e98b95d..e055577 100644
--- a/net/tools/tld_cleanup/tld_cleanup.cc
+++ b/net/tools/tld_cleanup/tld_cleanup.cc
@@ -27,6 +27,7 @@
#include <string>
#include "base/at_exit.h"
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/i18n/icu_util.h"
#include "base/logging.h"
diff --git a/net/url_request/https_prober.cc b/net/url_request/https_prober.cc
index a7163ba..d69eaf3 100644
--- a/net/url_request/https_prober.cc
+++ b/net/url_request/https_prober.cc
@@ -9,6 +9,12 @@
namespace net {
+HTTPSProber::HTTPSProber() {
+}
+
+HTTPSProber::~HTTPSProber() {
+}
+
bool HTTPSProber::HaveProbed(const std::string& host) const {
return probed_.find(host) != probed_.end();
}
diff --git a/net/url_request/https_prober.h b/net/url_request/https_prober.h
index c1c9941..28182c4 100644
--- a/net/url_request/https_prober.h
+++ b/net/url_request/https_prober.h
@@ -4,6 +4,7 @@
#ifndef NET_BASE_HTTPS_PROBER_H_
#define NET_BASE_HTTPS_PROBER_H_
+#pragma once
#include <map>
#include <set>
@@ -32,7 +33,8 @@ class HTTPSProberDelegate {
// transparently upgrading from HTTP to HTTPS (for example, for SPDY).
class HTTPSProber : public URLRequest::Delegate {
public:
- HTTPSProber() {}
+ HTTPSProber();
+ ~HTTPSProber();
// HaveProbed returns true if the given host is known to have been probed
// since the browser was last started.
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 9f226c2..b4f9d51 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 20010 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.
@@ -23,7 +23,6 @@
using base::Time;
using net::UploadData;
using std::string;
-using std::wstring;
namespace {
@@ -46,6 +45,54 @@ void StripPostSpecificHeaders(net::HttpRequestHeaders* headers) {
} // namespace
///////////////////////////////////////////////////////////////////////////////
+// URLRequest::Interceptor
+
+URLRequestJob* URLRequest::Interceptor::MaybeInterceptRedirect(
+ URLRequest* request,
+ const GURL& location) {
+ return NULL;
+}
+
+URLRequestJob* URLRequest::Interceptor::MaybeInterceptResponse(
+ URLRequest* request) {
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// URLRequest::Delegate
+
+void URLRequest::Delegate::OnReceivedRedirect(URLRequest* request,
+ const GURL& new_url,
+ bool* defer_redirect) {
+}
+
+void URLRequest::Delegate::OnAuthRequired(URLRequest* request,
+ net::AuthChallengeInfo* auth_info) {
+ request->CancelAuth();
+}
+
+void URLRequest::Delegate::OnCertificateRequested(
+ URLRequest* request,
+ net::SSLCertRequestInfo* cert_request_info) {
+ request->ContinueWithCertificate(NULL);
+}
+
+void URLRequest::Delegate::OnSSLCertificateError(URLRequest* request,
+ int cert_error,
+ net::X509Certificate* cert) {
+ request->Cancel();
+}
+
+void URLRequest::Delegate::OnGetCookies(URLRequest* request,
+ bool blocked_by_policy) {
+}
+
+void URLRequest::Delegate::OnSetCookie(URLRequest* request,
+ const std::string& cookie_line,
+ bool blocked_by_policy) {
+}
+
+///////////////////////////////////////////////////////////////////////////////
// URLRequest
URLRequest::URLRequest(const GURL& url, Delegate* delegate)
@@ -395,7 +442,7 @@ void URLRequest::FollowDeferredRedirect() {
job_->FollowDeferredRedirect();
}
-void URLRequest::SetAuth(const wstring& username, const wstring& password) {
+void URLRequest::SetAuth(const string16& username, const string16& password) {
DCHECK(job_);
DCHECK(job_->NeedsAuth());
@@ -443,7 +490,7 @@ void URLRequest::OrphanJob() {
}
int URLRequest::Redirect(const GURL& location, int http_status_code) {
- if (net_log_.HasListener()) {
+ if (net_log_.IsLoggingAll()) {
net_log_.AddEvent(
net::NetLog::TYPE_URL_REQUEST_REDIRECTED,
new net::NetLogStringParameter(
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index b238356..7282edc 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -1,9 +1,10 @@
-// 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.
#ifndef NET_URL_REQUEST_URL_REQUEST_H_
#define NET_URL_REQUEST_URL_REQUEST_H_
+#pragma once
#include <map>
#include <string>
@@ -14,6 +15,7 @@
#include "base/logging.h"
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
+#include "base/string16.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_states.h"
#include "net/base/net_log.h"
@@ -88,9 +90,7 @@ class URLRequest : public NonThreadSafe {
// the delegate never sees the original redirect response, instead the
// response produced by the intercept job will be returned.
virtual URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
- const GURL& location) {
- return NULL;
- }
+ const GURL& location);
// Called after having received a final response, but prior to the
// the request delegate being informed of the response. This is also
@@ -100,9 +100,7 @@ class URLRequest : public NonThreadSafe {
// continue. If a new job is provided, the delegate never sees the original
// response, instead the response produced by the intercept job will be
// returned.
- virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request) {
- return NULL;
- }
+ virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request);
};
// The delegate's methods are called from the message loop of the thread
@@ -150,8 +148,7 @@ class URLRequest : public NonThreadSafe {
// deferring redirect.
virtual void OnReceivedRedirect(URLRequest* request,
const GURL& new_url,
- bool* defer_redirect) {
- }
+ bool* defer_redirect);
// Called when we receive an authentication failure. The delegate should
// call request->SetAuth() with the user's credentials once it obtains them,
@@ -159,9 +156,7 @@ class URLRequest : public NonThreadSafe {
// When it does so, the request will be reissued, restarting the sequence
// of On* callbacks.
virtual void OnAuthRequired(URLRequest* request,
- net::AuthChallengeInfo* auth_info) {
- request->CancelAuth();
- }
+ net::AuthChallengeInfo* auth_info);
// Called when we receive an SSL CertificateRequest message for client
// authentication. The delegate should call
@@ -170,9 +165,7 @@ class URLRequest : public NonThreadSafe {
// handshake without a client certificate.
virtual void OnCertificateRequested(
URLRequest* request,
- net::SSLCertRequestInfo* cert_request_info) {
- request->ContinueWithCertificate(NULL);
- }
+ net::SSLCertRequestInfo* cert_request_info);
// Called when using SSL and the server responds with a certificate with
// an error, for example, whose common name does not match the common name
@@ -182,23 +175,19 @@ class URLRequest : public NonThreadSafe {
// indicating what's wrong with the certificate.
virtual void OnSSLCertificateError(URLRequest* request,
int cert_error,
- net::X509Certificate* cert) {
- request->Cancel();
- }
+ net::X509Certificate* cert);
// Called when reading cookies. |blocked_by_policy| is true if access to
// cookies was denied due to content settings. This method will never be
// invoked when LOAD_DO_NOT_SEND_COOKIES is specified.
- virtual void OnGetCookies(URLRequest* request, bool blocked_by_policy) {
- }
+ virtual void OnGetCookies(URLRequest* request, bool blocked_by_policy);
// Called when a cookie is set. |blocked_by_policy| is true if the cookie
// was rejected due to content settings. This method will never be invoked
// when LOAD_DO_NOT_SAVE_COOKIES is specified.
virtual void OnSetCookie(URLRequest* request,
const std::string& cookie_line,
- bool blocked_by_policy) {
- }
+ bool blocked_by_policy);
// After calling Start(), the delegate will receive an OnResponseStarted
// callback when the request has completed. If an error occurred, the
@@ -377,7 +366,7 @@ class URLRequest : public NonThreadSafe {
bool was_cached() const { return response_info_.was_cached; }
// True if response could use alternate protocol. However, browser will
- // ingore the alternate protocol if spdy is not enabled.
+ // ignore the alternate protocol if spdy is not enabled.
bool was_fetched_via_spdy() const {
return response_info_.was_fetched_via_spdy;
}
@@ -388,7 +377,7 @@ class URLRequest : public NonThreadSafe {
return response_info_.was_npn_negotiated;
}
- // Returns true if the URLRequest was delivered when the alertnate protocol
+ // Returns true if the URLRequest was delivered when the alternate protocol
// is available.
bool was_alternate_protocol_available() const {
return response_info_.was_alternate_protocol_available;
@@ -503,7 +492,7 @@ class URLRequest : public NonThreadSafe {
// OnAuthRequired() callback (and only then).
// SetAuth will reissue the request with the given credentials.
// CancelAuth will give up and display the error page.
- void SetAuth(const std::wstring& username, const std::wstring& password);
+ void SetAuth(const string16& username, const string16& password);
void CancelAuth();
// This method can be called after the user selects a client certificate to
@@ -542,8 +531,13 @@ class URLRequest : public NonThreadSafe {
// Returns the priority level for this request.
net::RequestPriority priority() const { return priority_; }
void set_priority(net::RequestPriority priority) {
+<<<<<<< HEAD
//DCHECK_GE(priority, net::HIGHEST);
//DCHECK_LE(priority, net::LOWEST);
+=======
+ DCHECK_GE(priority, net::HIGHEST);
+ DCHECK_LT(priority, net::NUM_PRIORITIES);
+>>>>>>> Chromium at release 7.0.540.0
priority_ = priority;
}
@@ -570,7 +564,7 @@ class URLRequest : public NonThreadSafe {
void ResponseStarted();
// Allow an interceptor's URLRequestJob to restart this request.
- // Should only be called if the original job has not started a resposne.
+ // Should only be called if the original job has not started a response.
void Restart();
private:
@@ -594,7 +588,7 @@ class URLRequest : public NonThreadSafe {
// Contextual information used for this request (can be NULL). This contains
// most of the dependencies which are shared between requests (disk cache,
- // cookie store, socket poool, etc.)
+ // cookie store, socket pool, etc.)
scoped_refptr<URLRequestContext> context_;
// Tracks the time spent in various load states throughout this request.
diff --git a/net/url_request/url_request_about_job.cc b/net/url_request/url_request_about_job.cc
index 917abf9..ac6aa01 100644
--- a/net/url_request/url_request_about_job.cc
+++ b/net/url_request/url_request_about_job.cc
@@ -32,6 +32,9 @@ bool URLRequestAboutJob::GetMimeType(std::string* mime_type) const {
return true;
}
+URLRequestAboutJob::~URLRequestAboutJob() {
+}
+
void URLRequestAboutJob::StartAsync() {
NotifyHeadersComplete();
}
diff --git a/net/url_request/url_request_about_job.h b/net/url_request/url_request_about_job.h
index 70822d2..52a659e 100644
--- a/net/url_request/url_request_about_job.h
+++ b/net/url_request/url_request_about_job.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_ABOUT_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_ABOUT_JOB_H_
+#pragma once
#include <string>
@@ -20,7 +21,7 @@ class URLRequestAboutJob : public URLRequestJob {
static URLRequest::ProtocolFactory Factory;
private:
- ~URLRequestAboutJob() {}
+ ~URLRequestAboutJob();
void StartAsync();
};
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc
new file mode 100644
index 0000000..0ea8477
--- /dev/null
+++ b/net/url_request/url_request_context.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 "net/url_request/url_request_context.h"
+
+#include "base/string_util.h"
+#include "net/base/cookie_store.h"
+#include "net/base/host_resolver.h"
+
+URLRequestContext::URLRequestContext()
+ : net_log_(NULL),
+ http_transaction_factory_(NULL),
+ ftp_transaction_factory_(NULL),
+ http_auth_handler_factory_(NULL),
+ network_delegate_(NULL),
+ cookie_policy_(NULL),
+ transport_security_state_(NULL) {
+}
+
+const std::string& URLRequestContext::GetUserAgent(const GURL& url) const {
+ return EmptyString();
+}
+
+URLRequestContext::~URLRequestContext() {
+}
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h
index 2d2d646..99ea2d9 100644
--- a/net/url_request/url_request_context.h
+++ b/net/url_request/url_request_context.h
@@ -9,12 +9,10 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_
#define NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_
+#pragma once
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
-#include "base/string_util.h"
-#include "net/base/cookie_store.h"
-#include "net/base/host_resolver.h"
#include "net/base/net_log.h"
#include "net/base/ssl_config_service.h"
#include "net/base/transport_security_state.h"
@@ -23,11 +21,13 @@
namespace net {
class CookiePolicy;
+class CookieStore;
class FtpTransactionFactory;
+class HostResolver;
class HttpAuthHandlerFactory;
class HttpNetworkDelegate;
class HttpTransactionFactory;
-class SocketStream;
+class SSLConfigService;
}
class URLRequest;
@@ -36,15 +36,7 @@ class URLRequestContext
: public base::RefCountedThreadSafe<URLRequestContext>,
public NonThreadSafe {
public:
- URLRequestContext()
- : net_log_(NULL),
- http_transaction_factory_(NULL),
- ftp_transaction_factory_(NULL),
- http_auth_handler_factory_(NULL),
- network_delegate_(NULL),
- cookie_policy_(NULL),
- transport_security_state_(NULL) {
- }
+ URLRequestContext();
net::NetLog* net_log() const {
return net_log_;
@@ -108,9 +100,7 @@ class URLRequestContext
// Gets the UA string to use for the given URL. Pass an invalid URL (such as
// GURL()) to get the default UA string. Subclasses should override this
// method to provide a UA string.
- virtual const std::string& GetUserAgent(const GURL& url) const {
- return EmptyString();
- }
+ virtual const std::string& GetUserAgent(const GURL& url) const;
// In general, referrer_charset is not known when URLRequestContext is
// constructed. So, we need a setter.
@@ -122,7 +112,7 @@ class URLRequestContext
protected:
friend class base::RefCountedThreadSafe<URLRequestContext>;
- virtual ~URLRequestContext() {}
+ virtual ~URLRequestContext();
// The following members are expected to be initialized and owned by
// subclasses.
diff --git a/net/url_request/url_request_data_job.cc b/net/url_request/url_request_data_job.cc
index ff52bb3..737f169 100644
--- a/net/url_request/url_request_data_job.cc
+++ b/net/url_request/url_request_data_job.cc
@@ -19,7 +19,6 @@ URLRequestDataJob::URLRequestDataJob(URLRequest* request)
: URLRequestSimpleJob(request) {
}
-
bool URLRequestDataJob::GetData(std::string* mime_type,
std::string* charset,
std::string* data) const {
@@ -31,3 +30,5 @@ bool URLRequestDataJob::GetData(std::string* mime_type,
return net::DataURL::Parse(url, mime_type, charset, data);
}
+URLRequestDataJob::~URLRequestDataJob() {
+}
diff --git a/net/url_request/url_request_data_job.h b/net/url_request/url_request_data_job.h
index 1c1dbaa..1bb868a 100644
--- a/net/url_request/url_request_data_job.h
+++ b/net/url_request/url_request_data_job.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_DATA_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_DATA_JOB_H_
+#pragma once
#include <string>
@@ -23,7 +24,7 @@ class URLRequestDataJob : public URLRequestSimpleJob {
static URLRequest::ProtocolFactory Factory;
private:
- ~URLRequestDataJob() {}
+ ~URLRequestDataJob();
DISALLOW_COPY_AND_ASSIGN(URLRequestDataJob);
};
diff --git a/net/url_request/url_request_error_job.h b/net/url_request/url_request_error_job.h
index 396c38d..efaea0c 100644
--- a/net/url_request/url_request_error_job.h
+++ b/net/url_request/url_request_error_job.h
@@ -7,6 +7,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_ERROR_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_ERROR_JOB_H_
+#pragma once
#include "net/url_request/url_request_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 19a1aaf..23ff6ff 100644
--- a/net/url_request/url_request_file_dir_job.cc
+++ b/net/url_request/url_request_file_dir_job.cc
@@ -102,7 +102,7 @@ bool URLRequestFileDirJob::GetCharset(string* charset) {
}
void URLRequestFileDirJob::OnListFile(
- const file_util::FileEnumerator::FindInfo& data) {
+ const net::DirectoryLister::DirectoryListerData& data) {
// We wait to write out the header until we get the first file, so that we
// can catch errors from DirectoryLister and show an error page.
if (!wrote_header_) {
@@ -122,26 +122,26 @@ void URLRequestFileDirJob::OnListFile(
}
#if defined(OS_WIN)
- int64 size = (static_cast<unsigned __int64>(data.nFileSizeHigh) << 32) |
- data.nFileSizeLow;
+ int64 size = (static_cast<unsigned __int64>(data.info.nFileSizeHigh) << 32) |
+ data.info.nFileSizeLow;
// Note that we should not convert ftLastWriteTime to the local time because
// ICU's datetime formatting APIs expect time in UTC and take into account
// the timezone before formatting.
data_.append(net::GetDirectoryListingEntry(
- data.cFileName, std::string(),
- (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false,
+ data.info.cFileName, std::string(),
+ (data.info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false,
size,
- base::Time::FromFileTime(data.ftLastWriteTime)));
+ base::Time::FromFileTime(data.info.ftLastWriteTime)));
#elif defined(OS_POSIX)
// TOOD(jungshik): The same issue as for the directory name.
data_.append(net::GetDirectoryListingEntry(
- WideToUTF16(base::SysNativeMBToWide(data.filename)),
- data.filename,
- S_ISDIR(data.stat.st_mode),
- data.stat.st_size,
- base::Time::FromTimeT(data.stat.st_mtime)));
+ WideToUTF16(base::SysNativeMBToWide(data.info.filename)),
+ data.info.filename,
+ S_ISDIR(data.info.stat.st_mode),
+ data.info.stat.st_size,
+ base::Time::FromTimeT(data.info.stat.st_mtime)));
#endif
// TODO(darin): coalesce more?
diff --git a/net/url_request/url_request_file_dir_job.h b/net/url_request/url_request_file_dir_job.h
index 0322f10..c78de97 100644
--- a/net/url_request/url_request_file_dir_job.h
+++ b/net/url_request/url_request_file_dir_job.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_FILE_DIR_JOB_H__
#define NET_URL_REQUEST_URL_REQUEST_FILE_DIR_JOB_H__
+#pragma once
#include <string>
@@ -27,7 +28,8 @@ class URLRequestFileDirJob
virtual bool GetCharset(std::string* charset);
// DirectoryLister::DirectoryListerDelegate methods:
- virtual void OnListFile(const file_util::FileEnumerator::FindInfo& data);
+ virtual void OnListFile(
+ const net::DirectoryLister::DirectoryListerData& data);
virtual void OnListDone(int error);
bool list_complete() const { return list_complete_; }
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 003a29d..8c282ff 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -23,7 +23,7 @@
#include "base/message_loop.h"
#include "base/platform_file.h"
#include "base/string_util.h"
-#include "base/worker_pool.h"
+#include "build/build_config.h"
#include "googleurl/src/gurl.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
@@ -35,6 +35,10 @@
#include "net/url_request/url_request_file_dir_job.h"
#if defined(OS_WIN)
+#include "base/worker_pool.h"
+#endif
+
+#if defined(OS_WIN)
class URLRequestFileJob::AsyncResolver :
public base::RefCountedThreadSafe<URLRequestFileJob::AsyncResolver> {
public:
@@ -43,7 +47,7 @@ class URLRequestFileJob::AsyncResolver :
}
void Resolve(const FilePath& file_path) {
- file_util::FileInfo file_info;
+ base::PlatformFileInfo file_info;
bool exists = file_util::GetFileInfo(file_path, &file_info);
AutoLock locked(lock_);
if (owner_loop_) {
@@ -64,7 +68,7 @@ class URLRequestFileJob::AsyncResolver :
~AsyncResolver() {}
- void ReturnResults(bool exists, const file_util::FileInfo& file_info) {
+ void ReturnResults(bool exists, const base::PlatformFileInfo& file_info) {
if (owner_)
owner_->DidResolve(exists, file_info);
}
@@ -124,7 +128,7 @@ void URLRequestFileJob::Start() {
return;
}
#endif
- file_util::FileInfo file_info;
+ base::PlatformFileInfo file_info;
bool exists = file_util::GetFileInfo(file_path_, &file_info);
// Continue asynchronously.
@@ -217,7 +221,7 @@ void URLRequestFileJob::SetExtraRequestHeaders(
}
void URLRequestFileJob::DidResolve(
- bool exists, const file_util::FileInfo& file_info) {
+ bool exists, const base::PlatformFileInfo& file_info) {
#if defined(OS_WIN)
async_resolver_ = NULL;
#endif
diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h
index aed6859..adf9d24 100644
--- a/net/url_request/url_request_file_job.h
+++ b/net/url_request/url_request_file_job.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_FILE_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_FILE_JOB_H_
+#pragma once
#include <string>
@@ -41,7 +42,7 @@ class URLRequestFileJob : public URLRequestJob {
FilePath file_path_;
private:
- void DidResolve(bool exists, const file_util::FileInfo& file_info);
+ void DidResolve(bool exists, const base::PlatformFileInfo& file_info);
void DidRead(int result);
net::CompletionCallbackImpl<URLRequestFileJob> io_callback_;
diff --git a/net/url_request/url_request_filter.h b/net/url_request/url_request_filter.h
index d81e68c..58f9886 100644
--- a/net/url_request/url_request_filter.h
+++ b/net/url_request/url_request_filter.h
@@ -18,6 +18,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_FILTER_H_
#define NET_URL_REQUEST_URL_REQUEST_FILTER_H_
+#pragma once
#include <map>
#include <string>
diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc
index f8746fc..37d6ab0 100644
--- a/net/url_request/url_request_ftp_job.cc
+++ b/net/url_request/url_request_ftp_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.
@@ -6,6 +6,7 @@
#include "base/compiler_specific.h"
#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
#include "net/base/auth.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -90,8 +91,8 @@ void URLRequestFtpJob::GetAuthChallengeInfo(
result->swap(auth_info);
}
-void URLRequestFtpJob::SetAuth(const std::wstring& username,
- const std::wstring& password) {
+void URLRequestFtpJob::SetAuth(const string16& username,
+ const string16& password) {
DCHECK(NeedsAuth());
server_auth_->state = net::AUTH_STATE_HAVE_AUTH;
server_auth_->username = username;
diff --git a/net/url_request/url_request_ftp_job.h b/net/url_request/url_request_ftp_job.h
index 453543f..48f963d 100644
--- a/net/url_request/url_request_ftp_job.h
+++ b/net/url_request/url_request_ftp_job.h
@@ -1,12 +1,14 @@
-// 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.
#ifndef NET_URL_REQUEST_URL_REQUEST_FTP_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_FTP_JOB_H_
+#pragma once
#include <string>
+#include "base/string16.h"
#include "net/base/auth.h"
#include "net/base/completion_callback.h"
#include "net/ftp/ftp_request_info.h"
@@ -15,10 +17,6 @@
class URLRequestContext;
-namespace net {
-struct list_state;
-}
-
// A URLRequestJob subclass that is built on top of FtpTransaction. It
// provides an implementation for FTP.
class URLRequestFtpJob : public URLRequestJob {
@@ -41,8 +39,8 @@ class URLRequestFtpJob : public URLRequestJob {
virtual bool NeedsAuth();
virtual void GetAuthChallengeInfo(
scoped_refptr<net::AuthChallengeInfo>* auth_info);
- virtual void SetAuth(const std::wstring& username,
- const std::wstring& password);
+ virtual void SetAuth(const string16& username,
+ const string16& password);
virtual void CancelAuth();
// TODO(ibrar): Yet to give another look at this function.
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 6b938fa..025415b 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -14,6 +14,7 @@
#include "base/string_util.h"
#include "net/base/cert_status_flags.h"
#include "net/base/cookie_policy.h"
+#include "net/base/cookie_store.h"
#include "net/base/filter.h"
#include "net/base/transport_security_state.h"
#include "net/base/load_flags.h"
@@ -310,8 +311,8 @@ void URLRequestHttpJob::GetAuthChallengeInfo(
*result = response_info_->auth_challenge;
}
-void URLRequestHttpJob::SetAuth(const std::wstring& username,
- const std::wstring& password) {
+void URLRequestHttpJob::SetAuth(const string16& username,
+ const string16& password) {
DCHECK(transaction_.get());
// Proxy gets set first, then WWW.
@@ -326,8 +327,8 @@ void URLRequestHttpJob::SetAuth(const std::wstring& username,
}
void URLRequestHttpJob::RestartTransactionWithAuth(
- const std::wstring& username,
- const std::wstring& password) {
+ const string16& username,
+ const string16& password) {
username_ = username;
password_ = password;
@@ -596,7 +597,7 @@ void URLRequestHttpJob::NotifyHeadersComplete() {
// notified of the headers completion so that we can update the cookie store.
if (transaction_->IsReadyToRestartForAuth()) {
DCHECK(!response_info_->auth_challenge.get());
- RestartTransactionWithAuth(std::wstring(), std::wstring());
+ RestartTransactionWithAuth(string16(), string16());
return;
}
@@ -796,8 +797,10 @@ void URLRequestHttpJob::FetchResponseCookies(
std::string value;
void* iter = NULL;
- while (response_info->headers->EnumerateHeader(&iter, name, &value))
- cookies->push_back(value);
+ while (response_info->headers->EnumerateHeader(&iter, name, &value)) {
+ if (!value.empty())
+ cookies->push_back(value);
+ }
}
class HTTPSProberDelegate : public net::HTTPSProberDelegate {
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index 279cdd4..431756a 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -1,15 +1,16 @@
-// 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.
#ifndef NET_URL_REQUEST_URL_REQUEST_HTTP_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_HTTP_JOB_H_
+#pragma once
-#include <set>
#include <string>
#include <vector>
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "net/base/auth.h"
#include "net/base/completion_callback.h"
#include "net/http/http_request_info.h"
@@ -49,8 +50,8 @@ class URLRequestHttpJob : public URLRequestJob {
virtual bool IsSafeRedirect(const GURL& location);
virtual bool NeedsAuth();
virtual void GetAuthChallengeInfo(scoped_refptr<net::AuthChallengeInfo>*);
- virtual void SetAuth(const std::wstring& username,
- const std::wstring& password);
+ virtual void SetAuth(const string16& username,
+ const string16& password);
virtual void CancelAuth();
virtual void ContinueWithCertificate(net::X509Certificate* client_cert);
virtual void ContinueDespiteLastError();
@@ -79,8 +80,8 @@ class URLRequestHttpJob : public URLRequestJob {
bool ShouldTreatAsCertificateError(int result);
- void RestartTransactionWithAuth(const std::wstring& username,
- const std::wstring& password);
+ void RestartTransactionWithAuth(const string16& username,
+ const string16& password);
// Keep a reference to the url request context to be sure it's not deleted
// before us.
@@ -96,8 +97,8 @@ class URLRequestHttpJob : public URLRequestJob {
net::AuthState proxy_auth_state_;
net::AuthState server_auth_state_;
- std::wstring username_;
- std::wstring password_;
+ string16 username_;
+ string16 password_;
net::CompletionCallbackImpl<URLRequestHttpJob> can_get_cookies_callback_;
net::CompletionCallbackImpl<URLRequestHttpJob> can_set_cookie_callback_;
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index a31df82..f7c3e4a 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -6,6 +6,7 @@
#include "base/histogram.h"
#include "base/message_loop.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "net/base/auth.h"
#include "net/base/io_buffer.h"
@@ -110,8 +111,8 @@ void URLRequestJob::GetAuthChallengeInfo(
NOTREACHED();
}
-void URLRequestJob::SetAuth(const std::wstring& username,
- const std::wstring& password) {
+void URLRequestJob::SetAuth(const string16& username,
+ const string16& password) {
// This will only be called if NeedsAuth() returns true, in which
// case the derived class should implement this!
NOTREACHED();
@@ -515,7 +516,7 @@ void URLRequestJob::NotifyHeadersComplete() {
std::string content_length;
request_->GetResponseHeaderByName("content-length", &content_length);
if (!content_length.empty())
- expected_content_size_ = StringToInt64(content_length);
+ base::StringToInt64(content_length, &expected_content_size_);
} else {
// Chrome today only sends "Accept-Encoding" for compression schemes.
// So, if there is a filter on the response, we know that the content
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index da6fc16..ca69940 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -4,12 +4,14 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_JOB_H_
+#pragma once
#include <string>
#include <vector>
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/string16.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "net/base/filter.h"
@@ -170,8 +172,8 @@ class URLRequestJob : public base::RefCountedThreadSafe<URLRequestJob>,
scoped_refptr<net::AuthChallengeInfo>* auth_info);
// Resend the request with authentication credentials.
- virtual void SetAuth(const std::wstring& username,
- const std::wstring& password);
+ virtual void SetAuth(const string16& username,
+ const string16& password);
// Display the error page without asking for credentials again.
virtual void CancelAuth();
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h
index d8934e6..51de77a 100644
--- a/net/url_request/url_request_job_manager.h
+++ b/net/url_request/url_request_job_manager.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H__
#define NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H__
+#pragma once
#include <map>
#include <vector>
diff --git a/net/url_request/url_request_job_metrics.h b/net/url_request/url_request_job_metrics.h
index 11ee288..2f52c7f 100644
--- a/net/url_request/url_request_job_metrics.h
+++ b/net/url_request/url_request_job_metrics.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.
@@ -7,6 +7,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_METRICS_H_
#define NET_URL_REQUEST_URL_REQUEST_JOB_METRICS_H_
+#pragma once
#include <string>
@@ -17,7 +18,10 @@
class URLRequestJobMetrics {
public:
- URLRequestJobMetrics() : total_bytes_read_(0), number_of_read_IO_(0) { }
+ URLRequestJobMetrics()
+ : total_bytes_read_(0),
+ number_of_read_IO_(0),
+ success_(false) { }
~URLRequestJobMetrics() { }
// The original url the job has been created for.
diff --git a/net/url_request/url_request_job_tracker.h b/net/url_request/url_request_job_tracker.h
index e03b71f..8b554b9 100644
--- a/net/url_request/url_request_job_tracker.h
+++ b/net/url_request/url_request_job_tracker.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_TRACKER_H_
#define NET_URL_REQUEST_URL_REQUEST_JOB_TRACKER_H_
+#pragma once
#include <vector>
diff --git a/net/url_request/url_request_netlog_params.cc b/net/url_request/url_request_netlog_params.cc
index 3693ee9..56414b1 100644
--- a/net/url_request/url_request_netlog_params.cc
+++ b/net/url_request/url_request_netlog_params.cc
@@ -19,9 +19,9 @@ URLRequestStartEventParameters::URLRequestStartEventParameters(
Value* URLRequestStartEventParameters::ToValue() const {
DictionaryValue* dict = new DictionaryValue();
- dict->SetString(L"url", url_.possibly_invalid_spec());
- dict->SetString(L"method", method_);
- dict->SetInteger(L"load_flags", load_flags_);
- dict->SetInteger(L"priority", static_cast<int>(priority_));
+ dict->SetString("url", url_.possibly_invalid_spec());
+ dict->SetString("method", method_);
+ dict->SetInteger("load_flags", load_flags_);
+ dict->SetInteger("priority", static_cast<int>(priority_));
return dict;
}
diff --git a/net/url_request/url_request_netlog_params.h b/net/url_request/url_request_netlog_params.h
index d84052a..12bd1f1 100644
--- a/net/url_request/url_request_netlog_params.h
+++ b/net/url_request/url_request_netlog_params.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_NETLOG_PARAMS_H_
#define NET_URL_REQUEST_URL_REQUEST_NETLOG_PARAMS_H_
+#pragma once
#include <string>
diff --git a/net/url_request/url_request_redirect_job.h b/net/url_request/url_request_redirect_job.h
index 8a13204..55c34a7 100644
--- a/net/url_request/url_request_redirect_job.h
+++ b/net/url_request/url_request_redirect_job.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_REDIRECT_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_REDIRECT_JOB_H_
+#pragma once
#include "net/url_request/url_request_job.h"
diff --git a/net/url_request/url_request_simple_job.h b/net/url_request/url_request_simple_job.h
index 4ea856c..bcc4047 100644
--- a/net/url_request/url_request_simple_job.h
+++ b/net/url_request/url_request_simple_job.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_SIMPLE_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_SIMPLE_JOB_H_
+#pragma once
#include <string>
diff --git a/net/url_request/url_request_status.h b/net/url_request/url_request_status.h
index f82bb83..ca376fb 100644
--- a/net/url_request/url_request_status.h
+++ b/net/url_request/url_request_status.h
@@ -7,8 +7,9 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_STATUS_H_
#define NET_URL_REQUEST_URL_REQUEST_STATUS_H_
+#pragma once
-// Respresents the result of a URL request. It encodes errors and various
+// Represents the result of a URL request. It encodes errors and various
// types of success.
class URLRequestStatus {
public:
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h
index f618c07..7cb4777 100644
--- a/net/url_request/url_request_test_job.h
+++ b/net/url_request/url_request_test_job.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_TEST_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_TEST_JOB_H_
+#pragma once
#include <string>
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index bd4e56a..9070ef1 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.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.
@@ -7,8 +7,8 @@
#include "build/build_config.h"
#if defined(OS_WIN)
-#include <windows.h>
#include <shlobj.h>
+#include <windows.h>
#elif defined(USE_NSS)
#include "base/nss_util.h"
#endif
@@ -21,16 +21,19 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
+#include "base/string_number_conversions.h"
#include "base/string_piece.h"
-#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
#include "net/base/cookie_monster.h"
#include "net/base/cookie_policy.h"
#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
-#include "net/base/net_errors.h"
#include "net/base/net_module.h"
#include "net/base/net_util.h"
+#include "net/base/ssl_connection_status_flags.h"
#include "net/base/upload_data.h"
#include "net/disk_cache/disk_cache.h"
#include "net/ftp/ftp_network_layer.h"
@@ -51,6 +54,10 @@ using base::Time;
namespace {
+const string16 kChrome(ASCIIToUTF16("chrome"));
+const string16 kSecret(ASCIIToUTF16("secret"));
+const string16 kUser(ASCIIToUTF16("user"));
+
base::StringPiece TestNetResourceProvider(int key) {
return "header";
}
@@ -87,6 +94,21 @@ scoped_refptr<net::UploadData> CreateSimpleUploadData(const char* data) {
return upload;
}
+// Verify that the SSLInfo of a successful SSL connection has valid values.
+void CheckSSLInfo(const net::SSLInfo& ssl_info) {
+ // Allow ChromeFrame fake certificates to get through.
+ if (ssl_info.cert.get() &&
+ ssl_info.cert.get()->issuer().GetDisplayName() == "Chrome Internal")
+ return;
+ // -1 means unknown. 0 means no encryption.
+ EXPECT_GT(ssl_info.security_bits, 0);
+
+ // The cipher suite TLS_NULL_WITH_NULL_NULL (0) must not be negotiated.
+ int cipher_suite = net::SSLConnectionStatusToCipherSuite(
+ ssl_info.connection_status);
+ EXPECT_NE(0, cipher_suite);
+}
+
} // namespace
// Inherit PlatformTest since we require the autorelease pool on Mac OS X.f
@@ -94,18 +116,15 @@ class URLRequestTest : public PlatformTest {
};
class URLRequestTestHTTP : public URLRequestTest {
- protected:
- static void SetUpTestCase() {
- server_ = HTTPTestServer::CreateForkingServer(
- L"net/data/url_request_unittest/");
- }
-
- static void TearDownTestCase() {
- server_ = NULL;
+ public:
+ URLRequestTestHTTP()
+ : test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL(
+ "net/data/url_request_unittest"))) {
}
+ protected:
void HTTPUploadDataOperationTest(const std::string& method) {
- ASSERT_TRUE(NULL != server_.get());
const int kMsgSize = 20000; // multiple of 10
const int kIterations = 50;
char *uploadBytes = new char[kMsgSize+1];
@@ -127,7 +146,7 @@ class URLRequestTestHTTP : public URLRequestTest {
for (int i = 0; i < kIterations; ++i) {
TestDelegate d;
- URLRequest r(server_->TestServerPage("echo"), &d);
+ URLRequest r(test_server_.GetURL("echo"), &d);
r.set_context(context);
r.set_method(method.c_str());
@@ -149,24 +168,21 @@ class URLRequestTestHTTP : public URLRequestTest {
delete[] uploadBytes;
}
- static scoped_refptr<HTTPTestServer> server_;
+ net::TestServer test_server_;
};
-// static
-scoped_refptr<HTTPTestServer> URLRequestTestHTTP::server_;
-
+// In this unit test, we're using the HTTPTestServer as a proxy server and
+// issuing a CONNECT request with the magic host name "www.redirect.com".
+// The HTTPTestServer will return a 302 response, which we should not
+// follow.
TEST_F(URLRequestTestHTTP, ProxyTunnelRedirectTest) {
- // In this unit test, we're using the HTTPTestServer as a proxy server and
- // issuing a CONNECT request with the magic host name "www.redirect.com".
- // The HTTPTestServer will return a 302 response, which we should not
- // follow.
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
URLRequest r(GURL("https://www.redirect.com/"), &d);
- std::string proxy("localhost:");
- proxy.append(IntToString(kHTTPDefaultPort));
- r.set_context(new TestURLRequestContext(proxy));
+ r.set_context(
+ new TestURLRequestContext(test_server_.host_port_pair().ToString()));
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -181,17 +197,17 @@ TEST_F(URLRequestTestHTTP, ProxyTunnelRedirectTest) {
}
}
+// In this unit test, we're using the HTTPTestServer as a proxy server and
+// issuing a CONNECT request with the magic host name "www.server-auth.com".
+// The HTTPTestServer will return a 401 response, which we should balk at.
TEST_F(URLRequestTestHTTP, UnexpectedServerAuthTest) {
- // In this unit test, we're using the HTTPTestServer as a proxy server and
- // issuing a CONNECT request with the magic host name "www.server-auth.com".
- // The HTTPTestServer will return a 401 response, which we should balk at.
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
URLRequest r(GURL("https://www.server-auth.com/"), &d);
- std::string proxy("localhost:");
- proxy.append(IntToString(kHTTPDefaultPort));
- r.set_context(new TestURLRequestContext(proxy));
+ r.set_context(
+ new TestURLRequestContext(test_server_.host_port_pair().ToString()));
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -204,10 +220,11 @@ TEST_F(URLRequestTestHTTP, UnexpectedServerAuthTest) {
}
TEST_F(URLRequestTestHTTP, GetTest_NoCache) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage(""), &d);
+ TestURLRequest r(test_server_.GetURL(""), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -223,10 +240,11 @@ TEST_F(URLRequestTestHTTP, GetTest_NoCache) {
}
TEST_F(URLRequestTestHTTP, GetTest) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage(""), &d);
+ TestURLRequest r(test_server_.GetURL(""), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -240,17 +258,18 @@ TEST_F(URLRequestTestHTTP, GetTest) {
}
TEST_F(URLRequestTestHTTP, HTTPSToHTTPRedirectNoRefererTest) {
- scoped_refptr<HTTPSTestServer> https_server =
- HTTPSTestServer::CreateGoodServer(L"net/data/ssl/");
- ASSERT_TRUE(NULL != https_server.get());
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
+ net::TestServer https_test_server(
+ net::TestServer::TYPE_HTTPS, FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+ ASSERT_TRUE(https_test_server.Start());
// An https server is sent a request with an https referer,
// and responds with a redirect to an http url. The http
// server should not be sent the referer.
- GURL http_destination = server_->TestServerPage("");
+ GURL http_destination = test_server_.GetURL("");
TestDelegate d;
- TestURLRequest req(https_server->TestServerPage(
+ TestURLRequest req(https_test_server.GetURL(
"server-redirect?" + http_destination.spec()), &d);
req.set_referrer("https://www.referrer.com/");
req.Start();
@@ -262,32 +281,96 @@ TEST_F(URLRequestTestHTTP, HTTPSToHTTPRedirectNoRefererTest) {
EXPECT_EQ(std::string(), req.referrer());
}
+namespace {
+
+// Used by MakeGETRequest to implement sync load behavior.
+class SyncTestDelegate : public TestDelegate {
+ public:
+ SyncTestDelegate() : event_(false, false), success_(false) {
+ }
+ virtual void OnResponseCompleted(URLRequest* request) {
+ MessageLoop::current()->DeleteSoon(FROM_HERE, request);
+ success_ = request->status().is_success();
+ event_.Signal();
+ }
+ bool Wait(int64 secs) {
+ return event_.TimedWait(TimeDelta::FromSeconds(secs));
+ }
+ bool did_succeed() const { return success_; }
+ private:
+ base::WaitableEvent event_;
+ bool success_;
+ DISALLOW_COPY_AND_ASSIGN(SyncTestDelegate);
+};
+
+void StartGETRequest(const GURL& url, URLRequest::Delegate* delegate) {
+ URLRequest* request = new URLRequest(url, delegate);
+ request->set_context(new TestURLRequestContext());
+ request->set_method("GET");
+ request->Start();
+ EXPECT_TRUE(request->is_pending());
+}
+
+bool MakeGETRequest(const GURL& url) {
+ // Spin up a background thread for this request so that we have access to
+ // an IO message loop, and in cases where this thread already has an IO
+ // message loop, we also want to avoid spinning a nested message loop.
+ SyncTestDelegate d;
+ {
+ base::Thread io_thread("MakeGETRequest");
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ io_thread.StartWithOptions(options);
+ io_thread.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
+ &StartGETRequest, url, &d));
+
+ const int kWaitSeconds = 30;
+ if (!d.Wait(kWaitSeconds))
+ return false;
+ }
+ return d.did_succeed();
+}
+
+} // namespace
+
+// Some tests use browser javascript to fetch a 'kill' url that causes
+// the server to exit by itself (rather than letting TestServerLauncher's
+// destructor kill it). We now unit test this mechanism.
TEST_F(URLRequestTest, QuitTest) {
- // Don't use shared server here because we order it to quit.
- // It would impact other tests.
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
- server->SendQuit();
- EXPECT_TRUE(server->WaitToFinish(20000));
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
+ // Append the time to avoid problems where the kill page
+ // is being cached rather than being executed on the server
+ std::string page_name = base::StringPrintf("kill?%u",
+ static_cast<int>(base::Time::Now().ToInternalValue()));
+ int retry_count = 5;
+ while (retry_count > 0) {
+ bool r = MakeGETRequest(test_server.GetURL(page_name));
+ // BUG #1048625 causes the kill GET to fail. For now we just retry.
+ // Once the bug is fixed, we should remove the while loop and put back
+ // the following DCHECK.
+ // DCHECK(r);
+ if (r)
+ break;
+ retry_count--;
+ }
+ // Make sure we were successful in stopping the testserver.
+ EXPECT_LT(0, retry_count);
+ EXPECT_TRUE(test_server.WaitToFinish(20000));
}
class HTTPSRequestTest : public testing::Test {
};
-
TEST_F(HTTPSRequestTest, HTTPSGetTest) {
- // Note: tools/testserver/testserver.py does not need
- // a working document root to server the pages / and /hello.html,
- // so this test doesn't really need to specify a document root.
- // But if it did, a good one would be net/data/ssl.
- scoped_refptr<HTTPSTestServer> server =
- HTTPSTestServer::CreateGoodServer(L"net/data/ssl");
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS,
+ FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+ ASSERT_TRUE(test_server.Start());
TestDelegate d;
{
- TestURLRequest r(server->TestServerPage(""), &d);
+ TestURLRequest r(test_server.GetURL(""), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -297,20 +380,21 @@ TEST_F(HTTPSRequestTest, HTTPSGetTest) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_NE(0, d.bytes_received());
+ CheckSSLInfo(r.ssl_info());
}
}
TEST_F(HTTPSRequestTest, HTTPSMismatchedTest) {
- scoped_refptr<HTTPSTestServer> server =
- HTTPSTestServer::CreateMismatchedServer(L"net/data/ssl");
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_MISMATCHED_HOSTNAME,
+ FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+ ASSERT_TRUE(test_server.Start());
bool err_allowed = true;
for (int i = 0; i < 2 ; i++, err_allowed = !err_allowed) {
TestDelegate d;
{
d.set_allow_certificate_errors(err_allowed);
- TestURLRequest r(server->TestServerPage(""), &d);
+ TestURLRequest r(test_server.GetURL(""), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -320,18 +404,20 @@ TEST_F(HTTPSRequestTest, HTTPSMismatchedTest) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_TRUE(d.have_certificate_errors());
- if (err_allowed)
+ if (err_allowed) {
EXPECT_NE(0, d.bytes_received());
- else
+ CheckSSLInfo(r.ssl_info());
+ } else {
EXPECT_EQ(0, d.bytes_received());
+ }
}
}
}
TEST_F(HTTPSRequestTest, HTTPSExpiredTest) {
- scoped_refptr<HTTPSTestServer> server =
- HTTPSTestServer::CreateExpiredServer(L"net/data/ssl");
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_EXPIRED_CERTIFICATE,
+ FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+ ASSERT_TRUE(test_server.Start());
// Iterate from false to true, just so that we do the opposite of the
// previous test in order to increase test coverage.
@@ -340,7 +426,7 @@ TEST_F(HTTPSRequestTest, HTTPSExpiredTest) {
TestDelegate d;
{
d.set_allow_certificate_errors(err_allowed);
- TestURLRequest r(server->TestServerPage(""), &d);
+ TestURLRequest r(test_server.GetURL(""), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -350,14 +436,73 @@ TEST_F(HTTPSRequestTest, HTTPSExpiredTest) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_TRUE(d.have_certificate_errors());
- if (err_allowed)
+ if (err_allowed) {
EXPECT_NE(0, d.bytes_received());
- else
+ CheckSSLInfo(r.ssl_info());
+ } else {
EXPECT_EQ(0, d.bytes_received());
+ }
}
}
}
+namespace {
+
+class SSLClientAuthTestDelegate : public TestDelegate {
+ public:
+ SSLClientAuthTestDelegate() : on_certificate_requested_count_(0) {
+ }
+ virtual void OnCertificateRequested(
+ URLRequest* request,
+ net::SSLCertRequestInfo* cert_request_info) {
+ on_certificate_requested_count_++;
+ MessageLoop::current()->Quit();
+ }
+ int on_certificate_requested_count() {
+ return on_certificate_requested_count_;
+ }
+ private:
+ int on_certificate_requested_count_;
+};
+
+} // namespace
+
+// TODO(davidben): Test the rest of the code. Specifically,
+// - Filtering which certificates to select.
+// - Sending a certificate back.
+// - Getting a certificate request in an SSL renegotiation sending the
+// HTTP request.
+TEST_F(HTTPSRequestTest, ClientAuthTest) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTPS_CLIENT_AUTH,
+ FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+ ASSERT_TRUE(test_server.Start());
+
+ SSLClientAuthTestDelegate d;
+ {
+ TestURLRequest r(test_server.GetURL(""), &d);
+
+ r.Start();
+ EXPECT_TRUE(r.is_pending());
+
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(1, d.on_certificate_requested_count());
+ EXPECT_FALSE(d.received_data_before_response());
+ EXPECT_EQ(0, d.bytes_received());
+
+ // Send no certificate.
+ // TODO(davidben): Get temporary client cert import (with keys) working on
+ // all platforms so we can test sending a cert as well.
+ r.ContinueWithCertificate(NULL);
+
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_FALSE(d.received_data_before_response());
+ EXPECT_NE(0, d.bytes_received());
+ }
+}
+
TEST_F(URLRequestTestHTTP, CancelTest) {
TestDelegate d;
{
@@ -379,14 +524,11 @@ TEST_F(URLRequestTestHTTP, CancelTest) {
}
TEST_F(URLRequestTestHTTP, CancelTest2) {
- ASSERT_TRUE(NULL != server_.get());
-
- // error C2446: '!=' : no conversion from 'HTTPTestServer *const '
- // to 'const int'
+ ASSERT_TRUE(test_server_.Start());
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage(""), &d);
+ TestURLRequest r(test_server_.GetURL(""), &d);
d.set_cancel_in_response_started(true);
@@ -403,10 +545,11 @@ TEST_F(URLRequestTestHTTP, CancelTest2) {
}
TEST_F(URLRequestTestHTTP, CancelTest3) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage(""), &d);
+ TestURLRequest r(test_server_.GetURL(""), &d);
d.set_cancel_in_received_data(true);
@@ -426,10 +569,11 @@ TEST_F(URLRequestTestHTTP, CancelTest3) {
}
TEST_F(URLRequestTestHTTP, CancelTest4) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage(""), &d);
+ TestURLRequest r(test_server_.GetURL(""), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -450,13 +594,14 @@ TEST_F(URLRequestTestHTTP, CancelTest4) {
}
TEST_F(URLRequestTestHTTP, CancelTest5) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new TestURLRequestContext();
// populate cache
{
TestDelegate d;
- URLRequest r(server_->TestServerPage("cachetime"), &d);
+ URLRequest r(test_server_.GetURL("cachetime"), &d);
r.set_context(context);
r.Start();
MessageLoop::current()->Run();
@@ -466,7 +611,7 @@ TEST_F(URLRequestTestHTTP, CancelTest5) {
// cancel read from cache (see bug 990242)
{
TestDelegate d;
- URLRequest r(server_->TestServerPage("cachetime"), &d);
+ URLRequest r(test_server_.GetURL("cachetime"), &d);
r.set_context(context);
r.Start();
r.Cancel();
@@ -480,18 +625,21 @@ TEST_F(URLRequestTestHTTP, CancelTest5) {
}
TEST_F(URLRequestTestHTTP, PostTest) {
+ ASSERT_TRUE(test_server_.Start());
HTTPUploadDataOperationTest("POST");
}
TEST_F(URLRequestTestHTTP, PutTest) {
+ ASSERT_TRUE(test_server_.Start());
HTTPUploadDataOperationTest("PUT");
}
TEST_F(URLRequestTestHTTP, PostEmptyTest) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage("echo"), &d);
+ TestURLRequest r(test_server_.GetURL("echo"), &d);
r.set_method("POST");
r.Start();
@@ -508,10 +656,11 @@ TEST_F(URLRequestTestHTTP, PostEmptyTest) {
}
TEST_F(URLRequestTestHTTP, PostFileTest) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage("echo"), &d);
+ TestURLRequest r(test_server_.GetURL("echo"), &d);
r.set_method("POST");
FilePath dir;
@@ -656,8 +805,9 @@ TEST_F(URLRequestTest, FileTestFullSpecifiedRange) {
net::HttpRequestHeaders headers;
headers.SetHeader(net::HttpRequestHeaders::kRange,
- StringPrintf("bytes=%" PRIuS "-%" PRIuS,
- first_byte_position, last_byte_position));
+ base::StringPrintf(
+ "bytes=%" PRIuS "-%" PRIuS,
+ first_byte_position, last_byte_position));
r.SetExtraRequestHeaders(headers);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -699,8 +849,8 @@ TEST_F(URLRequestTest, FileTestHalfSpecifiedRange) {
net::HttpRequestHeaders headers;
headers.SetHeader(net::HttpRequestHeaders::kRange,
- StringPrintf("bytes=%" PRIuS "-",
- first_byte_position));
+ base::StringPrintf("bytes=%" PRIuS "-",
+ first_byte_position));
r.SetExtraRequestHeaders(headers);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -762,9 +912,10 @@ TEST_F(URLRequestTest, InvalidUrlTest) {
}
TEST_F(URLRequestTestHTTP, ResponseHeadersTest) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
- TestURLRequest req(server_->TestServerPage("files/with-headers.html"), &d);
+ TestURLRequest req(test_server_.GetURL("files/with-headers.html"), &d);
req.Start();
MessageLoop::current()->Run();
@@ -859,10 +1010,10 @@ TEST_F(URLRequestTest, ResolveShortcutTest) {
#endif // defined(OS_WIN)
TEST_F(URLRequestTestHTTP, ContentTypeNormalizationTest) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
TestDelegate d;
- TestURLRequest req(server_->TestServerPage(
+ TestURLRequest req(test_server_.GetURL(
"files/content-type-normalization.html"), &d);
req.Start();
MessageLoop::current()->Run();
@@ -937,10 +1088,10 @@ TEST_F(URLRequestTest, FileDirRedirectSingleSlash) {
#endif
TEST_F(URLRequestTestHTTP, RestrictRedirects) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
TestDelegate d;
- TestURLRequest req(server_->TestServerPage(
+ TestURLRequest req(test_server_.GetURL(
"files/redirect-to-file.html"), &d);
req.Start();
MessageLoop::current()->Run();
@@ -950,10 +1101,10 @@ TEST_F(URLRequestTestHTTP, RestrictRedirects) {
}
TEST_F(URLRequestTestHTTP, RedirectToInvalidURL) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
TestDelegate d;
- TestURLRequest req(server_->TestServerPage(
+ TestURLRequest req(test_server_.GetURL(
"files/redirect-to-invalid-url.html"), &d);
req.Start();
MessageLoop::current()->Run();
@@ -963,9 +1114,10 @@ TEST_F(URLRequestTestHTTP, RedirectToInvalidURL) {
}
TEST_F(URLRequestTestHTTP, NoUserPassInReferrer) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
- TestURLRequest req(server_->TestServerPage(
+ TestURLRequest req(test_server_.GetURL(
"echoheader?Referer"), &d);
req.set_referrer("http://user:pass@foo.com/");
req.Start();
@@ -975,11 +1127,12 @@ TEST_F(URLRequestTestHTTP, NoUserPassInReferrer) {
}
TEST_F(URLRequestTestHTTP, CancelRedirect) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
d.set_cancel_in_received_redirect(true);
- TestURLRequest req(server_->TestServerPage(
+ TestURLRequest req(test_server_.GetURL(
"files/redirect-test.html"), &d);
req.Start();
MessageLoop::current()->Run();
@@ -992,11 +1145,12 @@ TEST_F(URLRequestTestHTTP, CancelRedirect) {
}
TEST_F(URLRequestTestHTTP, DeferredRedirect) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
d.set_quit_on_redirect(true);
- TestURLRequest req(server_->TestServerPage(
+ TestURLRequest req(test_server_.GetURL(
"files/redirect-test.html"), &d);
req.Start();
MessageLoop::current()->Run();
@@ -1024,11 +1178,12 @@ TEST_F(URLRequestTestHTTP, DeferredRedirect) {
}
TEST_F(URLRequestTestHTTP, CancelDeferredRedirect) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
d.set_quit_on_redirect(true);
- TestURLRequest req(server_->TestServerPage(
+ TestURLRequest req(test_server_.GetURL(
"files/redirect-test.html"), &d);
req.Start();
MessageLoop::current()->Run();
@@ -1046,14 +1201,14 @@ TEST_F(URLRequestTestHTTP, CancelDeferredRedirect) {
}
TEST_F(URLRequestTestHTTP, VaryHeader) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
scoped_refptr<URLRequestContext> context = new TestURLRequestContext();
// populate the cache
{
TestDelegate d;
- URLRequest req(server_->TestServerPage("echoheader?foo"), &d);
+ URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
req.set_context(context);
net::HttpRequestHeaders headers;
headers.SetHeader("foo", "1");
@@ -1065,7 +1220,7 @@ TEST_F(URLRequestTestHTTP, VaryHeader) {
// expect a cache hit
{
TestDelegate d;
- URLRequest req(server_->TestServerPage("echoheader?foo"), &d);
+ URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
req.set_context(context);
net::HttpRequestHeaders headers;
headers.SetHeader("foo", "1");
@@ -1079,7 +1234,7 @@ TEST_F(URLRequestTestHTTP, VaryHeader) {
// expect a cache miss
{
TestDelegate d;
- URLRequest req(server_->TestServerPage("echoheader?foo"), &d);
+ URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
req.set_context(context);
net::HttpRequestHeaders headers;
headers.SetHeader("foo", "2");
@@ -1092,16 +1247,17 @@ TEST_F(URLRequestTestHTTP, VaryHeader) {
}
TEST_F(URLRequestTestHTTP, BasicAuth) {
+ ASSERT_TRUE(test_server_.Start());
+
scoped_refptr<URLRequestContext> context = new TestURLRequestContext();
- ASSERT_TRUE(NULL != server_.get());
// populate the cache
{
TestDelegate d;
- d.set_username(L"user");
- d.set_password(L"secret");
+ d.set_username(kUser);
+ d.set_password(kSecret);
- URLRequest r(server_->TestServerPage("auth-basic"), &d);
+ URLRequest r(test_server_.GetURL("auth-basic"), &d);
r.set_context(context);
r.Start();
@@ -1115,10 +1271,10 @@ TEST_F(URLRequestTestHTTP, BasicAuth) {
// response should be fetched from the cache.
{
TestDelegate d;
- d.set_username(L"user");
- d.set_password(L"secret");
+ d.set_username(kUser);
+ d.set_password(kSecret);
- URLRequest r(server_->TestServerPage("auth-basic"), &d);
+ URLRequest r(test_server_.GetURL("auth-basic"), &d);
r.set_context(context);
r.set_load_flags(net::LOAD_VALIDATE_CACHE);
r.Start();
@@ -1135,18 +1291,18 @@ TEST_F(URLRequestTestHTTP, BasicAuth) {
// Check that Set-Cookie headers in 401 responses are respected.
// http://crbug.com/6450
TEST_F(URLRequestTestHTTP, BasicAuthWithCookies) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
GURL url_requiring_auth =
- server_->TestServerPage("auth-basic?set-cookie-if-challenged");
+ test_server_.GetURL("auth-basic?set-cookie-if-challenged");
// Request a page that will give a 401 containing a Set-Cookie header.
// Verify that when the transaction is restarted, it includes the new cookie.
{
scoped_refptr<URLRequestContext> context = new TestURLRequestContext();
TestDelegate d;
- d.set_username(L"user");
- d.set_password(L"secret");
+ d.set_username(kUser);
+ d.set_password(kSecret);
URLRequest r(url_requiring_auth, &d);
r.set_context(context);
@@ -1189,15 +1345,15 @@ TEST_F(URLRequestTestHTTP, BasicAuthWithCookies) {
}
TEST_F(URLRequestTest, DoNotSendCookies) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<URLRequestContext> context = new TestURLRequestContext();
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage("set-cookie?CookieToNotSend=1"), &d);
+ URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1208,7 +1364,7 @@ TEST_F(URLRequestTest, DoNotSendCookies) {
// Verify that the cookie is set.
{
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1222,7 +1378,7 @@ TEST_F(URLRequestTest, DoNotSendCookies) {
// Verify that the cookie isn't sent when LOAD_DO_NOT_SEND_COOKIES is set.
{
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES);
req.set_context(context);
req.Start();
@@ -1238,15 +1394,15 @@ TEST_F(URLRequestTest, DoNotSendCookies) {
}
TEST_F(URLRequestTest, DoNotSaveCookies) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<URLRequestContext> context = new TestURLRequestContext();
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage("set-cookie?CookieToNotUpdate=2"),
+ URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
&d);
req.set_context(context);
req.Start();
@@ -1260,7 +1416,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies) {
// Try to set-up another cookie and update the previous cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage(
+ 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);
@@ -1277,7 +1433,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies) {
// Verify the cookies weren't saved or updated.
{
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1294,15 +1450,15 @@ TEST_F(URLRequestTest, DoNotSaveCookies) {
}
TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage("set-cookie?CookieToNotSend=1"), &d);
+ URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1314,7 +1470,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) {
// Verify that the cookie is set.
{
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1332,7 +1488,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) {
context->set_cookie_policy(&cookie_policy);
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1348,15 +1504,15 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) {
}
TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage("set-cookie?CookieToNotUpdate=2"),
+ URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
&d);
req.set_context(context);
req.Start();
@@ -1372,7 +1528,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) {
context->set_cookie_policy(&cookie_policy);
TestDelegate d;
- URLRequest req(server->TestServerPage(
+ URLRequest req(test_server.GetURL(
"set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), &d);
req.set_context(context);
req.Start();
@@ -1389,7 +1545,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) {
// Verify the cookies weren't saved or updated.
{
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1404,16 +1560,36 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) {
}
}
+TEST_F(URLRequestTest, DoNotSaveEmptyCookies) {
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
+ scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
+
+ // Set up an empty cookie.
+ {
+ TestDelegate d;
+ URLRequest req(test_server.GetURL("set-cookie"), &d);
+ req.set_context(context);
+ req.Start();
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(0, d.blocked_get_cookies_count());
+ EXPECT_EQ(0, d.blocked_set_cookie_count());
+ EXPECT_EQ(0, d.set_cookie_count());
+ }
+}
+
TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage("set-cookie?CookieToNotSend=1"), &d);
+ URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1425,7 +1601,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) {
// Verify that the cookie is set.
{
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1444,7 +1620,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) {
context->set_cookie_policy(&cookie_policy);
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1460,15 +1636,15 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) {
}
TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage("set-cookie?CookieToNotUpdate=2"),
+ URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
&d);
req.set_context(context);
req.Start();
@@ -1485,7 +1661,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) {
context->set_cookie_policy(&cookie_policy);
TestDelegate d;
- URLRequest req(server->TestServerPage(
+ URLRequest req(test_server.GetURL(
"set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), &d);
req.set_context(context);
req.Start();
@@ -1501,7 +1677,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) {
// Verify the cookies weren't saved or updated.
{
TestDelegate d;
- TestURLRequest req(server->TestServerPage("echoheader?Cookie"), &d);
+ TestURLRequest req(test_server.GetURL("echoheader?Cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1517,9 +1693,9 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) {
}
TEST_F(URLRequestTest, CancelTest_During_CookiePolicy) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
TestCookiePolicy cookie_policy(TestCookiePolicy::ASYNC);
@@ -1528,7 +1704,7 @@ TEST_F(URLRequestTest, CancelTest_During_CookiePolicy) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage("set-cookie?A=1&B=2&C=3"),
+ 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.
@@ -1548,9 +1724,9 @@ TEST_F(URLRequestTest, CancelTest_During_CookiePolicy) {
}
TEST_F(URLRequestTest, CancelTest_During_OnGetCookies) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
TestCookiePolicy cookie_policy(TestCookiePolicy::NO_GET_COOKIES);
@@ -1560,7 +1736,7 @@ TEST_F(URLRequestTest, CancelTest_During_OnGetCookies) {
{
TestDelegate d;
d.set_cancel_in_get_cookies_blocked(true);
- URLRequest req(server->TestServerPage("set-cookie?A=1&B=2&C=3"),
+ 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.
@@ -1577,9 +1753,9 @@ TEST_F(URLRequestTest, CancelTest_During_OnGetCookies) {
}
TEST_F(URLRequestTest, CancelTest_During_OnSetCookie) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
TestCookiePolicy cookie_policy(TestCookiePolicy::NO_SET_COOKIE);
@@ -1589,7 +1765,7 @@ TEST_F(URLRequestTest, CancelTest_During_OnSetCookie) {
{
TestDelegate d;
d.set_cancel_in_set_cookie_blocked(true);
- URLRequest req(server->TestServerPage("set-cookie?A=1&B=2&C=3"),
+ 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.
@@ -1611,9 +1787,9 @@ TEST_F(URLRequestTest, CancelTest_During_OnSetCookie) {
}
TEST_F(URLRequestTest, CookiePolicy_ForceSession) {
- scoped_refptr<HTTPTestServer> server =
- HTTPTestServer::CreateServer(L"", NULL);
- ASSERT_TRUE(NULL != server.get());
+ net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath());
+ ASSERT_TRUE(test_server.Start());
+
scoped_refptr<TestURLRequestContext> context = new TestURLRequestContext();
TestCookiePolicy cookie_policy(TestCookiePolicy::FORCE_SESSION);
@@ -1622,7 +1798,7 @@ TEST_F(URLRequestTest, CookiePolicy_ForceSession) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(server->TestServerPage(
+ 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.
@@ -1647,10 +1823,12 @@ TEST_F(URLRequestTest, CookiePolicy_ForceSession) {
// Content-Type header.
// http://code.google.com/p/chromium/issues/detail?id=843
TEST_F(URLRequestTestHTTP, Post302RedirectGet) {
+ ASSERT_TRUE(test_server_.Start());
+
const char kData[] = "hello world";
- ASSERT_TRUE(NULL != server_.get());
+
TestDelegate d;
- TestURLRequest req(server_->TestServerPage("files/redirect-to-echoall"), &d);
+ TestURLRequest req(test_server_.GetURL("files/redirect-to-echoall"), &d);
req.set_method("POST");
req.set_upload(CreateSimpleUploadData(kData));
@@ -1687,16 +1865,18 @@ TEST_F(URLRequestTestHTTP, Post302RedirectGet) {
}
TEST_F(URLRequestTestHTTP, Post307RedirectPost) {
+ ASSERT_TRUE(test_server_.Start());
+
const char kData[] = "hello world";
- ASSERT_TRUE(NULL != server_.get());
+
TestDelegate d;
- TestURLRequest req(server_->TestServerPage("files/redirect307-to-echo"),
+ TestURLRequest req(test_server_.GetURL("files/redirect307-to-echo"),
&d);
req.set_method("POST");
req.set_upload(CreateSimpleUploadData(kData).get());
net::HttpRequestHeaders headers;
headers.SetHeader(net::HttpRequestHeaders::kContentLength,
- UintToString(arraysize(kData) - 1));
+ base::UintToString(arraysize(kData) - 1));
req.SetExtraRequestHeaders(headers);
req.Start();
MessageLoop::current()->Run();
@@ -1714,7 +1894,7 @@ class RestartTestJob : public URLRequestTestJob {
this->NotifyRestartRequired();
}
private:
- ~RestartTestJob() {}
+ ~RestartTestJob() {}
};
class CancelTestJob : public URLRequestTestJob {
@@ -2163,27 +2343,21 @@ TEST_F(URLRequestTest, InterceptRespectsCancelInRestart) {
}
class URLRequestTestFTP : public URLRequestTest {
- protected:
- static void SetUpTestCase() {
- server_ = FTPTestServer::CreateServer(L"");
- }
-
- static void TearDownTestCase() {
- server_ = NULL;
+ public:
+ URLRequestTestFTP() : test_server_(net::TestServer::TYPE_FTP, FilePath()) {
}
- static scoped_refptr<FTPTestServer> server_;
+ protected:
+ net::TestServer test_server_;
};
-// static
-scoped_refptr<FTPTestServer> URLRequestTestFTP::server_;
-
// Flaky, see http://crbug.com/25045.
TEST_F(URLRequestTestFTP, FLAKY_FTPDirectoryListing) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage("/"), &d);
+ TestURLRequest r(test_server_.GetURL("/"), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2198,13 +2372,14 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPDirectoryListing) {
// Flaky, see http://crbug.com/25045.
TEST_F(URLRequestTestFTP, FLAKY_FTPGetTestAnonymous) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage("/LICENSE"), &d);
+ TestURLRequest r(test_server_.GetURL("/LICENSE"), &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2222,14 +2397,16 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPGetTestAnonymous) {
// Flaky, see http://crbug.com/25045.
TEST_F(URLRequestTestFTP, FLAKY_FTPGetTest) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage("/LICENSE", "chrome", "chrome"),
- &d);
+ TestURLRequest r(
+ test_server_.GetURLWithUserAndPassword("/LICENSE", "chrome", "chrome"),
+ &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2245,15 +2422,20 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPGetTest) {
}
}
-TEST_F(URLRequestTestFTP, FTPCheckWrongPassword) {
- ASSERT_TRUE(NULL != server_.get());
+// Flaky, see http://crbug.com/25045.
+TEST_F(URLRequestTestFTP, FLAKY_FTPCheckWrongPassword) {
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage("/LICENSE",
- "chrome", "wrong_password"), &d);
+ TestURLRequest r(
+ test_server_.GetURLWithUserAndPassword("/LICENSE",
+ "chrome",
+ "wrong_password"),
+ &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2271,18 +2453,22 @@ TEST_F(URLRequestTestFTP, FTPCheckWrongPassword) {
// Flaky, see http://crbug.com/25045.
TEST_F(URLRequestTestFTP, FLAKY_FTPCheckWrongPasswordRestart) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
TestDelegate d;
// Set correct login credentials. The delegate will be asked for them when
// the initial login with wrong credentials will fail.
- d.set_username(L"chrome");
- d.set_password(L"chrome");
+ d.set_username(kChrome);
+ d.set_password(kChrome);
{
- TestURLRequest r(server_->TestServerPage("/LICENSE",
- "chrome", "wrong_password"), &d);
+ TestURLRequest r(
+ test_server_.GetURLWithUserAndPassword("/LICENSE",
+ "chrome",
+ "wrong_password"),
+ &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2298,15 +2484,20 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCheckWrongPasswordRestart) {
}
}
-TEST_F(URLRequestTestFTP, FTPCheckWrongUser) {
- ASSERT_TRUE(NULL != server_.get());
+// Flaky, see http://crbug.com/25045.
+TEST_F(URLRequestTestFTP, FLAKY_FTPCheckWrongUser) {
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
TestDelegate d;
{
- TestURLRequest r(server_->TestServerPage("/LICENSE",
- "wrong_user", "chrome"), &d);
+ TestURLRequest r(
+ test_server_.GetURLWithUserAndPassword("/LICENSE",
+ "wrong_user",
+ "chrome"),
+ &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2324,18 +2515,22 @@ TEST_F(URLRequestTestFTP, FTPCheckWrongUser) {
// Flaky, see http://crbug.com/25045.
TEST_F(URLRequestTestFTP, FLAKY_FTPCheckWrongUserRestart) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
TestDelegate d;
// Set correct login credentials. The delegate will be asked for them when
// the initial login with wrong credentials will fail.
- d.set_username(L"chrome");
- d.set_password(L"chrome");
+ d.set_username(kChrome);
+ d.set_password(kChrome);
{
- TestURLRequest r(server_->TestServerPage("/LICENSE",
- "wrong_user", "chrome"), &d);
+ TestURLRequest r(
+ test_server_.GetURLWithUserAndPassword("/LICENSE",
+ "wrong_user",
+ "chrome"),
+ &d);
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2353,7 +2548,8 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCheckWrongUserRestart) {
// Flaky, see http://crbug.com/25045.
TEST_F(URLRequestTestFTP, FLAKY_FTPCacheURLCredentials) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
@@ -2361,9 +2557,11 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCacheURLCredentials) {
scoped_ptr<TestDelegate> d(new TestDelegate);
{
// Pass correct login identity in the URL.
- TestURLRequest r(server_->TestServerPage("/LICENSE",
- "chrome", "chrome"),
- d.get());
+ TestURLRequest r(
+ test_server_.GetURLWithUserAndPassword("/LICENSE",
+ "chrome",
+ "chrome"),
+ d.get());
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2381,7 +2579,7 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCacheURLCredentials) {
d.reset(new TestDelegate);
{
// This request should use cached identity from previous request.
- TestURLRequest r(server_->TestServerPage("/LICENSE"), d.get());
+ TestURLRequest r(test_server_.GetURL("/LICENSE"), d.get());
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2399,7 +2597,8 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCacheURLCredentials) {
// Flaky, see http://crbug.com/25045.
TEST_F(URLRequestTestFTP, FLAKY_FTPCacheLoginBoxCredentials) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
FilePath app_path;
PathService::Get(base::DIR_SOURCE_ROOT, &app_path);
app_path = app_path.AppendASCII("LICENSE");
@@ -2407,12 +2606,14 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCacheLoginBoxCredentials) {
scoped_ptr<TestDelegate> d(new TestDelegate);
// Set correct login credentials. The delegate will be asked for them when
// the initial login with wrong credentials will fail.
- d->set_username(L"chrome");
- d->set_password(L"chrome");
- {
- TestURLRequest r(server_->TestServerPage("/LICENSE",
- "chrome", "wrong_password"),
- d.get());
+ d->set_username(kChrome);
+ d->set_password(kChrome);
+ {
+ TestURLRequest r(
+ test_server_.GetURLWithUserAndPassword("/LICENSE",
+ "chrome",
+ "wrong_password"),
+ d.get());
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2433,7 +2634,7 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCacheLoginBoxCredentials) {
{
// Don't pass wrong credentials in the URL, they would override valid cached
// ones.
- TestURLRequest r(server_->TestServerPage("/LICENSE"), d.get());
+ TestURLRequest r(test_server_.GetURL("/LICENSE"), d.get());
r.Start();
EXPECT_TRUE(r.is_pending());
@@ -2451,9 +2652,10 @@ TEST_F(URLRequestTestFTP, FLAKY_FTPCacheLoginBoxCredentials) {
// Check that default A-L header is sent.
TEST_F(URLRequestTestHTTP, DefaultAcceptLanguage) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
- TestURLRequest req(server_->TestServerPage("echoheader?Accept-Language"), &d);
+ TestURLRequest req(test_server_.GetURL("echoheader?Accept-Language"), &d);
req.set_context(new TestURLRequestContext());
req.Start();
MessageLoop::current()->Run();
@@ -2463,10 +2665,11 @@ TEST_F(URLRequestTestHTTP, DefaultAcceptLanguage) {
// Check that if request overrides the A-L header, the default is not appended.
// See http://crbug.com/20894
TEST_F(URLRequestTestHTTP, OverrideAcceptLanguage) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
TestURLRequest
- req(server_->TestServerPage("echoheaderoverride?Accept-Language"), &d);
+ req(test_server_.GetURL("echoheaderoverride?Accept-Language"), &d);
req.set_context(new TestURLRequestContext());
net::HttpRequestHeaders headers;
headers.SetHeader(net::HttpRequestHeaders::kAcceptLanguage, "ru");
@@ -2478,9 +2681,10 @@ TEST_F(URLRequestTestHTTP, OverrideAcceptLanguage) {
// Check that default A-C header is sent.
TEST_F(URLRequestTestHTTP, DefaultAcceptCharset) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
- TestURLRequest req(server_->TestServerPage("echoheader?Accept-Charset"), &d);
+ TestURLRequest req(test_server_.GetURL("echoheader?Accept-Charset"), &d);
req.set_context(new TestURLRequestContext());
req.Start();
MessageLoop::current()->Run();
@@ -2490,10 +2694,11 @@ TEST_F(URLRequestTestHTTP, DefaultAcceptCharset) {
// Check that if request overrides the A-C header, the default is not appended.
// See http://crbug.com/20894
TEST_F(URLRequestTestHTTP, OverrideAcceptCharset) {
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
+
TestDelegate d;
TestURLRequest
- req(server_->TestServerPage("echoheaderoverride?Accept-Charset"), &d);
+ req(test_server_.GetURL("echoheaderoverride?Accept-Charset"), &d);
req.set_context(new TestURLRequestContext());
net::HttpRequestHeaders headers;
headers.SetHeader(net::HttpRequestHeaders::kAcceptCharset, "koi-8r");
diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h
index 8f090ef..5900d61 100644
--- a/net/url_request/url_request_unittest.h
+++ b/net/url_request/url_request_unittest.h
@@ -4,29 +4,27 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
#define NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
+#pragma once
#include <stdlib.h>
#include <sstream>
#include <string>
-#include <vector>
-#include "base/file_path.h"
-#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/string_util.h"
+#include "base/string16.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
-#include "base/waitable_event.h"
#include "net/base/cookie_monster.h"
#include "net/base/cookie_policy.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
-#include "net/base/net_test_constants.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/disk_cache/disk_cache.h"
#include "net/ftp/ftp_network_layer.h"
@@ -40,11 +38,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "googleurl/src/url_util.h"
-const int kHTTPDefaultPort = 1337;
-const int kFTPDefaultPort = 1338;
-
-const std::string kDefaultHostName("localhost");
-
using base::TimeDelta;
//-----------------------------------------------------------------------------
@@ -132,14 +125,16 @@ class TestURLRequestContext : public URLRequestContext {
public:
TestURLRequestContext() {
host_resolver_ =
- net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism);
- proxy_service_ = net::ProxyService::CreateNull();
+ net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
+ NULL);
+ proxy_service_ = net::ProxyService::CreateDirect();
Init();
}
explicit TestURLRequestContext(const std::string& proxy) {
host_resolver_ =
- net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism);
+ net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
+ NULL);
net::ProxyConfig proxy_config;
proxy_config.proxy_rules().ParseFromString(proxy);
proxy_service_ = net::ProxyService::CreateFixed(proxy_config);
@@ -161,7 +156,8 @@ class TestURLRequestContext : public URLRequestContext {
void Init() {
ftp_transaction_factory_ = new net::FtpNetworkLayer(host_resolver_);
ssl_config_service_ = new net::SSLConfigServiceDefaults;
- http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault();
+ http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault(
+ host_resolver_);
http_transaction_factory_ = new net::HttpCache(
net::HttpNetworkLayer::CreateFactory(host_resolver_,
proxy_service_,
@@ -346,8 +342,8 @@ class TestDelegate : public URLRequest::Delegate {
void set_allow_certificate_errors(bool val) {
allow_certificate_errors_ = val;
}
- void set_username(const std::wstring& u) { username_ = u; }
- void set_password(const std::wstring& p) { password_ = p; }
+ void set_username(const string16& u) { username_ = u; }
+ void set_password(const string16& p) { password_ = p; }
// query state
const std::string& data_received() const { return data_received_; }
@@ -376,8 +372,8 @@ class TestDelegate : public URLRequest::Delegate {
bool quit_on_redirect_;
bool allow_certificate_errors_;
- std::wstring username_;
- std::wstring password_;
+ string16 username_;
+ string16 password_;
// tracks status of callbacks
int response_started_count_;
@@ -395,379 +391,4 @@ class TestDelegate : public URLRequest::Delegate {
scoped_refptr<net::IOBuffer> buf_;
};
-//-----------------------------------------------------------------------------
-
-// This object bounds the lifetime of an external python-based HTTP/FTP server
-// that can provide various responses useful for testing.
-class BaseTestServer : public base::RefCounted<BaseTestServer> {
- protected:
- BaseTestServer() {}
- BaseTestServer(int connection_attempts, int connection_timeout)
- : launcher_(connection_attempts, connection_timeout) {}
-
- public:
- void set_forking(bool forking) {
- launcher_.set_forking(forking);
- }
-
- // Used with e.g. HTTPTestServer::SendQuit()
- bool WaitToFinish(int milliseconds) {
- return launcher_.WaitToFinish(milliseconds);
- }
-
- bool Stop() {
- return launcher_.Stop();
- }
-
- GURL TestServerPage(const std::string& base_address,
- const std::string& path) {
- return GURL(base_address + path);
- }
-
- GURL TestServerPage(const std::string& path) {
- // TODO(phajdan.jr): Check for problems with IPv6.
- return GURL(scheme_ + "://" + host_name_ + ":" + port_str_ + "/" + path);
- }
-
- GURL TestServerPage(const std::string& path,
- const std::string& user,
- const std::string& password) {
- // TODO(phajdan.jr): Check for problems with IPv6.
-
- if (password.empty())
- return GURL(scheme_ + "://" + user + "@" +
- host_name_ + ":" + port_str_ + "/" + path);
-
- return GURL(scheme_ + "://" + user + ":" + password +
- "@" + host_name_ + ":" + port_str_ + "/" + path);
- }
-
- virtual bool MakeGETRequest(const std::string& page_name) = 0;
-
- FilePath GetDataDirectory() {
- return launcher_.GetDocumentRootPath();
- }
-
- protected:
- friend class base::RefCounted<BaseTestServer>;
- virtual ~BaseTestServer() { }
-
- bool Start(net::TestServerLauncher::Protocol protocol,
- const std::string& host_name, int port,
- const FilePath& document_root,
- const FilePath& cert_path,
- const std::wstring& file_root_url) {
- if (!launcher_.Start(protocol,
- host_name, port, document_root, cert_path, file_root_url))
- return false;
-
- if (protocol == net::TestServerLauncher::ProtoFTP)
- scheme_ = "ftp";
- else
- scheme_ = "http";
- if (!cert_path.empty())
- scheme_.push_back('s');
-
- host_name_ = host_name;
- port_str_ = IntToString(port);
- return true;
- }
-
- // Used by MakeGETRequest to implement sync load behavior.
- class SyncTestDelegate : public TestDelegate {
- public:
- SyncTestDelegate() : event_(false, false), success_(false) {
- }
- virtual void OnResponseCompleted(URLRequest* request) {
- MessageLoop::current()->DeleteSoon(FROM_HERE, request);
- success_ = request->status().is_success();
- event_.Signal();
- }
- bool Wait(int64 secs) {
- TimeDelta td = TimeDelta::FromSeconds(secs);
- if (event_.TimedWait(td))
- return true;
- return false;
- }
- bool did_succeed() const { return success_; }
- private:
- base::WaitableEvent event_;
- bool success_;
- DISALLOW_COPY_AND_ASSIGN(SyncTestDelegate);
- };
-
- net::TestServerLauncher launcher_;
- std::string scheme_;
- std::string host_name_;
- std::string port_str_;
-};
-
-//-----------------------------------------------------------------------------
-
-// HTTP
-class HTTPTestServer : public BaseTestServer {
- protected:
- explicit HTTPTestServer() : loop_(NULL) {
- }
-
- explicit HTTPTestServer(int connection_attempts, int connection_timeout)
- : BaseTestServer(connection_attempts, connection_timeout), loop_(NULL) {
- }
-
- virtual ~HTTPTestServer() {}
-
- public:
- // Creates and returns a new HTTPTestServer. If |loop| is non-null, requests
- // are serviced on it, otherwise a new thread and message loop are created.
- static scoped_refptr<HTTPTestServer> CreateServer(
- const std::wstring& document_root,
- MessageLoop* loop) {
- return CreateServerWithFileRootURL(document_root, std::wstring(), loop);
- }
-
- static scoped_refptr<HTTPTestServer> CreateServer(
- const std::wstring& document_root,
- MessageLoop* loop,
- int connection_attempts,
- int connection_timeout) {
- return CreateServerWithFileRootURL(document_root, std::wstring(), loop,
- connection_attempts,
- connection_timeout);
- }
-
- static scoped_refptr<HTTPTestServer> CreateServerWithFileRootURL(
- const std::wstring& document_root,
- const std::wstring& file_root_url,
- MessageLoop* loop) {
- return CreateServerWithFileRootURL(document_root, file_root_url, loop,
- net::kDefaultTestConnectionAttempts,
- net::kDefaultTestConnectionTimeout);
- }
-
- static scoped_refptr<HTTPTestServer> CreateForkingServer(
- const std::wstring& document_root) {
- scoped_refptr<HTTPTestServer> test_server =
- new HTTPTestServer(net::kDefaultTestConnectionAttempts,
- net::kDefaultTestConnectionTimeout);
- test_server->set_forking(true);
- FilePath no_cert;
- FilePath docroot = FilePath::FromWStringHack(document_root);
- if (!StartTestServer(test_server.get(), docroot, no_cert, std::wstring()))
- return NULL;
- return test_server;
- }
-
- static scoped_refptr<HTTPTestServer> CreateServerWithFileRootURL(
- const std::wstring& document_root,
- const std::wstring& file_root_url,
- MessageLoop* loop,
- int connection_attempts,
- int connection_timeout) {
- scoped_refptr<HTTPTestServer> test_server =
- new HTTPTestServer(connection_attempts, connection_timeout);
- test_server->loop_ = loop;
- FilePath no_cert;
- FilePath docroot = FilePath::FromWStringHack(document_root);
- if (!StartTestServer(test_server.get(), docroot, no_cert, file_root_url))
- return NULL;
- return test_server;
- }
-
- static bool StartTestServer(HTTPTestServer* server,
- const FilePath& document_root,
- const FilePath& cert_path,
- const std::wstring& file_root_url) {
- return server->Start(net::TestServerLauncher::ProtoHTTP, kDefaultHostName,
- kHTTPDefaultPort, document_root, cert_path,
- file_root_url);
- }
-
- // A subclass may wish to send the request in a different manner
- virtual bool MakeGETRequest(const std::string& page_name) {
- const GURL& url = TestServerPage(page_name);
-
- // Spin up a background thread for this request so that we have access to
- // an IO message loop, and in cases where this thread already has an IO
- // message loop, we also want to avoid spinning a nested message loop.
- SyncTestDelegate d;
- {
- MessageLoop* loop = loop_;
- scoped_ptr<base::Thread> io_thread;
-
- if (!loop) {
- io_thread.reset(new base::Thread("MakeGETRequest"));
- base::Thread::Options options;
- options.message_loop_type = MessageLoop::TYPE_IO;
- io_thread->StartWithOptions(options);
- loop = io_thread->message_loop();
- }
- loop->PostTask(FROM_HERE, NewRunnableFunction(
- &HTTPTestServer::StartGETRequest, url, &d));
-
- // Build bot wait for only 300 seconds we should ensure wait do not take
- // more than 300 seconds
- if (!d.Wait(250))
- return false;
- }
- return d.did_succeed();
- }
-
- static void StartGETRequest(const GURL& url, URLRequest::Delegate* delegate) {
- URLRequest* request = new URLRequest(url, delegate);
- request->set_context(new TestURLRequestContext());
- request->set_method("GET");
- request->Start();
- EXPECT_TRUE(request->is_pending());
- }
-
- // Some tests use browser javascript to fetch a 'kill' url that causes
- // the server to exit by itself (rather than letting TestServerLauncher's
- // destructor kill it).
- // This method does the same thing so we can unit test that mechanism.
- // You can then use WaitToFinish() to sleep until the server terminates.
- void SendQuit() {
- // Append the time to avoid problems where the kill page
- // is being cached rather than being executed on the server
- std::string page_name = StringPrintf("kill?%u",
- static_cast<int>(base::Time::Now().ToInternalValue()));
- int retry_count = 5;
- while (retry_count > 0) {
- bool r = MakeGETRequest(page_name);
- // BUG #1048625 causes the kill GET to fail. For now we just retry.
- // Once the bug is fixed, we should remove the while loop and put back
- // the following DCHECK.
- // DCHECK(r);
- if (r)
- break;
- retry_count--;
- }
- // Make sure we were successful in stopping the testserver.
- DCHECK_GT(retry_count, 0);
- }
-
- virtual std::string scheme() { return "http"; }
-
- private:
- // If non-null a background thread isn't created and instead this message loop
- // is used.
- MessageLoop* loop_;
-};
-
-//-----------------------------------------------------------------------------
-
-class HTTPSTestServer : public HTTPTestServer {
- protected:
- explicit HTTPSTestServer() {
- }
-
- public:
- // Create a server with a valid certificate
- // TODO(dkegel): HTTPSTestServer should not require an instance to specify
- // stock test certificates
- static scoped_refptr<HTTPSTestServer> CreateGoodServer(
- const std::wstring& document_root) {
- scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
- FilePath docroot = FilePath::FromWStringHack(document_root);
- FilePath certpath = test_server->launcher_.GetOKCertPath();
- if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
- net::TestServerLauncher::kHostName,
- net::TestServerLauncher::kOKHTTPSPort,
- docroot, certpath, std::wstring())) {
- return NULL;
- }
- return test_server;
- }
-
- // Create a server with an up to date certificate for the wrong hostname
- // for this host
- static scoped_refptr<HTTPSTestServer> CreateMismatchedServer(
- const std::wstring& document_root) {
- scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
- FilePath docroot = FilePath::FromWStringHack(document_root);
- FilePath certpath = test_server->launcher_.GetOKCertPath();
- if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
- net::TestServerLauncher::kMismatchedHostName,
- net::TestServerLauncher::kOKHTTPSPort,
- docroot, certpath, std::wstring())) {
- return NULL;
- }
- return test_server;
- }
-
- // Create a server with an expired certificate
- static scoped_refptr<HTTPSTestServer> CreateExpiredServer(
- const std::wstring& document_root) {
- scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
- FilePath docroot = FilePath::FromWStringHack(document_root);
- FilePath certpath = test_server->launcher_.GetExpiredCertPath();
- if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
- net::TestServerLauncher::kHostName,
- net::TestServerLauncher::kBadHTTPSPort,
- docroot, certpath, std::wstring())) {
- return NULL;
- }
- return test_server;
- }
-
- // Create a server with an arbitrary certificate
- static scoped_refptr<HTTPSTestServer> CreateServer(
- const std::string& host_name, int port,
- const std::wstring& document_root,
- const std::wstring& cert_path) {
- scoped_refptr<HTTPSTestServer> test_server = new HTTPSTestServer();
- FilePath docroot = FilePath::FromWStringHack(document_root);
- FilePath certpath = FilePath::FromWStringHack(cert_path);
- if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
- host_name, port, docroot, certpath, std::wstring())) {
- return NULL;
- }
- return test_server;
- }
-
- protected:
- std::wstring cert_path_;
-
- private:
- virtual ~HTTPSTestServer() {}
-};
-
-//-----------------------------------------------------------------------------
-
-class FTPTestServer : public BaseTestServer {
- public:
- FTPTestServer() {
- }
-
- static scoped_refptr<FTPTestServer> CreateServer(
- const std::wstring& document_root) {
- scoped_refptr<FTPTestServer> test_server = new FTPTestServer();
- FilePath docroot = FilePath::FromWStringHack(document_root);
- FilePath no_cert;
- if (!test_server->Start(net::TestServerLauncher::ProtoFTP,
- kDefaultHostName, kFTPDefaultPort, docroot, no_cert, std::wstring())) {
- return NULL;
- }
- return test_server;
- }
-
- virtual bool MakeGETRequest(const std::string& page_name) {
- const GURL& url = TestServerPage(page_name);
- TestDelegate d;
- URLRequest request(url, &d);
- request.set_context(new TestURLRequestContext());
- request.set_method("GET");
- request.Start();
- EXPECT_TRUE(request.is_pending());
-
- MessageLoop::current()->Run();
- if (request.is_pending())
- return false;
-
- return true;
- }
-
- private:
- ~FTPTestServer() {}
-};
-
#endif // NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
diff --git a/net/url_request/view_cache_helper.h b/net/url_request/view_cache_helper.h
index 777775a..dd960a9 100644
--- a/net/url_request/view_cache_helper.h
+++ b/net/url_request/view_cache_helper.h
@@ -4,6 +4,7 @@
#ifndef NET_URL_REQUEST_VIEW_CACHE_HELPER_H_
#define NET_URL_REQUEST_VIEW_CACHE_HELPER_H_
+#pragma once
#include <string>
diff --git a/net/websockets/websocket.cc b/net/websockets/websocket.cc
index fa6f180..3bf1da8 100644
--- a/net/websockets/websocket.cc
+++ b/net/websockets/websocket.cc
@@ -8,6 +8,7 @@
#include "net/websockets/websocket.h"
#include "base/message_loop.h"
+#include "net/base/host_resolver.h"
#include "net/websockets/websocket_handshake.h"
#include "net/websockets/websocket_handshake_draft75.h"
diff --git a/net/websockets/websocket.h b/net/websockets/websocket.h
index 373c5e4..19720ae 100644
--- a/net/websockets/websocket.h
+++ b/net/websockets/websocket.h
@@ -10,6 +10,7 @@
#ifndef NET_WEBSOCKETS_WEBSOCKET_H_
#define NET_WEBSOCKETS_WEBSOCKET_H_
+#pragma once
#include <deque>
#include <string>
diff --git a/net/websockets/websocket_frame_handler.h b/net/websockets/websocket_frame_handler.h
index d6c38da..ec5762d 100644
--- a/net/websockets/websocket_frame_handler.h
+++ b/net/websockets/websocket_frame_handler.h
@@ -4,6 +4,7 @@
#ifndef NET_WEBSOCKETS_WEBSOCKET_FRAME_HANDLER_H_
#define NET_WEBSOCKETS_WEBSOCKET_FRAME_HANDLER_H_
+#pragma once
#include <deque>
#include <vector>
diff --git a/net/websockets/websocket_handshake.cc b/net/websockets/websocket_handshake.cc
index 5adfa67..480e395 100644
--- a/net/websockets/websocket_handshake.cc
+++ b/net/websockets/websocket_handshake.cc
@@ -7,10 +7,13 @@
#include <algorithm>
#include <vector>
+#include "base/logging.h"
#include "base/md5.h"
#include "base/rand_util.h"
#include "base/ref_counted.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
@@ -68,7 +71,7 @@ std::string WebSocketHandshake::CreateClientHandshakeMessage() {
fields.push_back("Sec-WebSocket-Key1: " + parameter_->GetSecWebSocketKey1());
fields.push_back("Sec-WebSocket-Key2: " + parameter_->GetSecWebSocketKey2());
- std::random_shuffle(fields.begin(), fields.end());
+ std::random_shuffle(fields.begin(), fields.end(), base::RandGenerator);
for (size_t i = 0; i < fields.size(); i++) {
msg += fields[i] + "\r\n";
@@ -134,7 +137,7 @@ std::string WebSocketHandshake::GetHostFieldValue() const {
(secure &&
port != kSecureWebSocketPort && port != url_parse::PORT_UNSPECIFIED)) {
host += ":";
- host += IntToString(port);
+ host += base::IntToString(port);
}
}
return host;
@@ -278,7 +281,7 @@ void WebSocketHandshake::Parameter::GenerateSecWebSocketKey(
*number = rand_(0, max);
uint32 product = *number * space;
- std::string s = StringPrintf("%u", product);
+ std::string s = base::StringPrintf("%u", product);
int n = rand_(1, 12);
for (int i = 0; i < n; i++) {
int pos = rand_(0, s.length());
diff --git a/net/websockets/websocket_handshake.h b/net/websockets/websocket_handshake.h
index 3f64b8b..b74f9be 100644
--- a/net/websockets/websocket_handshake.h
+++ b/net/websockets/websocket_handshake.h
@@ -4,6 +4,7 @@
#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_H_
#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_H_
+#pragma once
#include <string>
diff --git a/net/websockets/websocket_handshake_draft75.h b/net/websockets/websocket_handshake_draft75.h
index 6cc0506..3caaa98 100644
--- a/net/websockets/websocket_handshake_draft75.h
+++ b/net/websockets/websocket_handshake_draft75.h
@@ -4,6 +4,7 @@
#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_DRAFT75_H_
#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_DRAFT75_H_
+#pragma once
#include <string>
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc
index 5278151..57f01e9 100644
--- a/net/websockets/websocket_handshake_handler.cc
+++ b/net/websockets/websocket_handshake_handler.cc
@@ -8,6 +8,7 @@
#include "base/string_piece.h"
#include "base/string_util.h"
#include "googleurl/src/gurl.h"
+#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
namespace {
@@ -412,6 +413,12 @@ void WebSocketHandshakeResponseHandler::RemoveHeaders(
headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len);
}
+std::string WebSocketHandshakeResponseHandler::GetRawResponse() const {
+ DCHECK(HasResponse());
+ return std::string(original_.data(),
+ original_header_length_ + kResponseKeySize);
+}
+
std::string WebSocketHandshakeResponseHandler::GetResponse() {
DCHECK(HasResponse());
DCHECK(status_line_.size() > 0);
diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h
index cf5700b..5455444 100644
--- a/net/websockets/websocket_handshake_handler.h
+++ b/net/websockets/websocket_handshake_handler.h
@@ -12,6 +12,7 @@
#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
+#pragma once
#include <string>
#include <vector>
@@ -97,6 +98,9 @@ class WebSocketHandshakeResponseHandler {
void RemoveHeaders(const char* const headers_to_remove[],
size_t headers_to_remove_len);
+ // Gets raw WebSocket handshake response received from WebSocket server.
+ std::string GetRawResponse() const;
+
// Gets WebSocket handshake response message sent to renderer process.
std::string GetResponse();
diff --git a/net/websockets/websocket_handshake_handler_unittest.cc b/net/websockets/websocket_handshake_handler_unittest.cc
index 65e0712..fafd77e 100644
--- a/net/websockets/websocket_handshake_handler_unittest.cc
+++ b/net/websockets/websocket_handshake_handler_unittest.cc
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/string_util.h"
#include "googleurl/src/gurl.h"
+#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/websockets/websocket_handshake_handler.h"
diff --git a/net/websockets/websocket_handshake_unittest.cc b/net/websockets/websocket_handshake_unittest.cc
index f688554..df3914e 100644
--- a/net/websockets/websocket_handshake_unittest.cc
+++ b/net/websockets/websocket_handshake_unittest.cc
@@ -6,10 +6,12 @@
#include <vector>
#include "base/scoped_ptr.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/websockets/websocket_handshake.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace net {
@@ -85,9 +87,9 @@ class WebSocketHandshakeTest : public testing::Test {
std::string s;
for (int i = 0; i < len; i++) {
if (isprint(buf[i]))
- s += StringPrintf("%c", buf[i]);
+ s += base::StringPrintf("%c", buf[i]);
else
- s += StringPrintf("\\x%02x", buf[i]);
+ s += base::StringPrintf("\\x%02x", buf[i]);
}
return s;
}
@@ -140,7 +142,7 @@ TEST_F(WebSocketHandshakeTest, Connect) {
"\r\n"
"\x30\x73\x74\x33\x52\x6C\x26\x71\x2D\x32\x5A\x55\x5E\x77\x65\x75";
std::vector<std::string> response_lines;
- SplitStringDontTrim(kResponse, '\n', &response_lines);
+ base::SplitStringDontTrim(kResponse, '\n', &response_lines);
EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode());
// too short
diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc
index 17dc54b..64af45b 100644
--- a/net/websockets/websocket_job.cc
+++ b/net/websockets/websocket_job.cc
@@ -9,6 +9,7 @@
#include "base/string_tokenizer.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
#include "net/base/cookie_policy.h"
#include "net/base/cookie_store.h"
#include "net/base/io_buffer.h"
@@ -16,6 +17,7 @@
#include "net/url_request/url_request_context.h"
#include "net/websockets/websocket_frame_handler.h"
#include "net/websockets/websocket_handshake_handler.h"
+#include "net/websockets/websocket_net_log_params.h"
#include "net/websockets/websocket_throttle.h"
namespace {
@@ -134,8 +136,8 @@ void WebSocketJob::Close() {
}
void WebSocketJob::RestartWithAuth(
- const std::wstring& username,
- const std::wstring& password) {
+ const string16& username,
+ const string16& password) {
state_ = CONNECTING;
socket_->RestartWithAuth(username, password);
}
@@ -309,6 +311,9 @@ void WebSocketJob::OnCanGetCookiesCompleted(int policy) {
const std::string& handshake_request = handshake_request_->GetRawRequest();
handshake_request_sent_ = 0;
+ socket_->net_log()->AddEvent(
+ NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS,
+ new NetLogWebSocketHandshakeParameter(handshake_request));
socket_->SendData(handshake_request.data(),
handshake_request.size());
}
@@ -347,6 +352,10 @@ void WebSocketJob::OnReceivedHandshakeResponse(
return;
}
// handshake message is completed.
+ socket_->net_log()->AddEvent(
+ NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS,
+ new NetLogWebSocketHandshakeParameter(
+ handshake_response_->GetRawResponse()));
if (len - response_length > 0) {
// If we received extra data, it should be frame data.
receive_frame_handler_->AppendData(data + response_length,
diff --git a/net/websockets/websocket_job.h b/net/websockets/websocket_job.h
index 833726b..f19653d 100644
--- a/net/websockets/websocket_job.h
+++ b/net/websockets/websocket_job.h
@@ -4,10 +4,12 @@
#ifndef NET_WEBSOCKETS_WEBSOCKET_JOB_H_
#define NET_WEBSOCKETS_WEBSOCKET_JOB_H_
+#pragma once
#include <string>
#include <vector>
+#include "base/string16.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/socket_stream/socket_stream_job.h"
@@ -46,8 +48,8 @@ class WebSocketJob : public SocketStreamJob, public SocketStream::Delegate {
virtual bool SendData(const char* data, int len);
virtual void Close();
virtual void RestartWithAuth(
- const std::wstring& username,
- const std::wstring& password);
+ const string16& username,
+ const string16& password);
virtual void DetachDelegate();
// SocketStream::Delegate methods.
diff --git a/net/websockets/websocket_job_unittest.cc b/net/websockets/websocket_job_unittest.cc
index 0ec760c..9fde6c9 100644
--- a/net/websockets/websocket_job_unittest.cc
+++ b/net/websockets/websocket_job_unittest.cc
@@ -6,6 +6,8 @@
#include <vector>
#include "base/ref_counted.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/cookie_policy.h"
#include "net/base/cookie_store.h"
@@ -35,7 +37,7 @@ class MockSocketStream : public SocketStream {
virtual void Close() {}
virtual void RestartWithAuth(
- const std::wstring& username, std::wstring& password) {}
+ const string16& username, const string16& password) {}
virtual void DetachDelegate() {
delegate_ = NULL;
}
diff --git a/net/websockets/websocket_throttle.cc b/net/websockets/websocket_throttle.cc
index 9e33cad..614990e 100644
--- a/net/websockets/websocket_throttle.cc
+++ b/net/websockets/websocket_throttle.cc
@@ -10,7 +10,9 @@
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/singleton.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "net/base/io_buffer.h"
#include "net/base/sys_addrinfo.h"
#include "net/socket_stream/socket_stream.h"
@@ -23,23 +25,24 @@ static std::string AddrinfoToHashkey(const struct addrinfo* addrinfo) {
case AF_INET: {
const struct sockaddr_in* const addr =
reinterpret_cast<const sockaddr_in*>(addrinfo->ai_addr);
- return StringPrintf("%d:%s",
- addrinfo->ai_family,
- HexEncode(&addr->sin_addr, 4).c_str());
+ return base::StringPrintf("%d:%s",
+ addrinfo->ai_family,
+ base::HexEncode(&addr->sin_addr, 4).c_str());
}
case AF_INET6: {
const struct sockaddr_in6* const addr6 =
reinterpret_cast<const sockaddr_in6*>(addrinfo->ai_addr);
- return StringPrintf("%d:%s",
- addrinfo->ai_family,
- HexEncode(&addr6->sin6_addr,
- sizeof(addr6->sin6_addr)).c_str());
+ return base::StringPrintf(
+ "%d:%s",
+ addrinfo->ai_family,
+ base::HexEncode(&addr6->sin6_addr,
+ sizeof(addr6->sin6_addr)).c_str());
}
default:
- return StringPrintf("%d:%s",
- addrinfo->ai_family,
- HexEncode(addrinfo->ai_addr,
- addrinfo->ai_addrlen).c_str());
+ return base::StringPrintf("%d:%s",
+ addrinfo->ai_family,
+ base::HexEncode(addrinfo->ai_addr,
+ addrinfo->ai_addrlen).c_str());
}
}
diff --git a/net/websockets/websocket_throttle.h b/net/websockets/websocket_throttle.h
index d05b246..0849834 100644
--- a/net/websockets/websocket_throttle.h
+++ b/net/websockets/websocket_throttle.h
@@ -4,6 +4,7 @@
#ifndef NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
#define NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
+#pragma once
#include <deque>
#include <string>
diff --git a/sdch/sdch.target.mk b/sdch/sdch.target.mk
index 49b5959..f945961 100644
--- a/sdch/sdch.target.mk
+++ b/sdch/sdch.target.mk
@@ -19,6 +19,7 @@ CFLAGS_Debug := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -52,6 +53,7 @@ CFLAGS_Release := -Werror \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -116,11 +118,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/testing/gmock.gyp b/testing/gmock.gyp
index 1d7d255..f879dcf 100644
--- a/testing/gmock.gyp
+++ b/testing/gmock.gyp
@@ -20,7 +20,6 @@
'gmock/include/gmock/gmock-generated-matchers.h',
'gmock/include/gmock/gmock-generated-nice-strict.h',
'gmock/include/gmock/gmock-matchers.h',
- 'gmock/include/gmock/gmock-printers.h',
'gmock/include/gmock/gmock-spec-builders.h',
'gmock/include/gmock/gmock.h',
'gmock/include/gmock/internal/gmock-generated-internal-utils.h',
@@ -30,7 +29,6 @@
'gmock/src/gmock-cardinalities.cc',
'gmock/src/gmock-internal-utils.cc',
'gmock/src/gmock-matchers.cc',
- 'gmock/src/gmock-printers.cc',
'gmock/src/gmock-spec-builders.cc',
'gmock/src/gmock.cc',
'gmock_mutant.h', # gMock helpers
diff --git a/testing/gmock.target.mk b/testing/gmock.target.mk
index bb9e855..b43fc81 100644
--- a/testing/gmock.target.mk
+++ b/testing/gmock.target.mk
@@ -18,6 +18,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -51,6 +52,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -72,7 +74,6 @@ INCS_Release := -Itesting/gmock \
OBJS := $(obj).target/$(TARGET)/testing/gmock/src/gmock-cardinalities.o \
$(obj).target/$(TARGET)/testing/gmock/src/gmock-internal-utils.o \
$(obj).target/$(TARGET)/testing/gmock/src/gmock-matchers.o \
- $(obj).target/$(TARGET)/testing/gmock/src/gmock-printers.o \
$(obj).target/$(TARGET)/testing/gmock/src/gmock-spec-builders.o \
$(obj).target/$(TARGET)/testing/gmock/src/gmock.o
@@ -101,11 +102,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/testing/gmock/Makefile.am b/testing/gmock/Makefile.am
index 30941d4..e2a4673 100644
--- a/testing/gmock/Makefile.am
+++ b/testing/gmock/Makefile.am
@@ -38,7 +38,6 @@ pkginclude_HEADERS = include/gmock/gmock.h \
include/gmock/gmock-generated-nice-strict.h \
include/gmock/gmock-matchers.h \
include/gmock/gmock-more-actions.h \
- include/gmock/gmock-printers.h \
include/gmock/gmock-spec-builders.h
pkginclude_internaldir = $(pkgincludedir)/internal
@@ -76,15 +75,26 @@ test_gmock_link_test_SOURCES = test/gmock_link_test.cc \
test/gmock_link_test.h
test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la
+# Tests that fused gmock files compile and work.
+TESTS += test/gmock_fused_test
+check_PROGRAMS += test/gmock_fused_test
+test_gmock_fused_test_SOURCES = fused-src/gmock-gtest-all.cc \
+ fused-src/gmock_main.cc \
+ fused-src/gmock/gmock.h \
+ fused-src/gtest/gtest.h \
+ test/gmock_test.cc
+test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src"
+
# Google Mock source files that we don't compile directly.
-EXTRA_DIST += \
+GMOCK_SOURCE_INGLUDES = \
src/gmock.cc \
src/gmock-cardinalities.cc \
src/gmock-internal-utils.cc \
src/gmock-matchers.cc \
- src/gmock-printers.cc \
src/gmock-spec-builders.cc
+EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES)
+
# C++ tests that we don't compile using autotools.
EXTRA_DIST += \
test/gmock_all_test.cc \
@@ -98,9 +108,7 @@ EXTRA_DIST += \
test/gmock-matchers_test.cc \
test/gmock-more-actions_test.cc \
test/gmock-nice-strict_test.cc \
- test/gmock-port_test.cc \
- test/gmock-printers_test.cc \
- test/gmock_test.cc
+ test/gmock-port_test.cc
# Python tests, which we don't run using autotools.
EXTRA_DIST += \
@@ -126,9 +134,7 @@ EXTRA_DIST += include/gmock/gmock-generated-actions.h.pump \
include/gmock/internal/gmock-generated-internal-utils.h.pump
# Script for fusing Google Mock and Google Test source files.
-EXTRA_DIST += \
- scripts/fuse_gmock_files.py \
- scripts/test/Makefile
+EXTRA_DIST += scripts/fuse_gmock_files.py
# The Google Mock Generator tool from the cppclean project.
EXTRA_DIST += \
@@ -152,3 +158,30 @@ EXTRA_DIST += \
msvc/gmock_main.vcproj \
msvc/gmock-spec-builders_test.vcproj \
msvc/gmock_test.vcproj
+
+# gmock_test.cc does not really depend on files generated by the
+# fused-gmock-internal rule. However, gmock_test.o does, and it is
+# important to include test/gmock_test.cc as part of this rule in order to
+# prevent compiling gmock_test.o until all dependent files have been
+# generated.
+$(test_gmock_fused_test_SOURCES): fused-gmock-internal
+
+# TODO(vladl@google.com): Find a way to add Google Tests's sources here.
+fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
+ $(lib_libgmock_la_SOURCES) $(GMOCK_SOURCE_INGLUDES) \
+ $(lib_libgmock_main_la_SOURCES) \
+ scripts/fuse_gmock_files.py
+ mkdir -p "$(srcdir)/fused-src"
+ chmod -R u+w "$(srcdir)/fused-src"
+ rm -f "$(srcdir)/fused-src/gtest/gtest.h"
+ rm -f "$(srcdir)/fused-src/gmock/gmock.h"
+ rm -f "$(srcdir)/fused-src/gmock-gtest-all.cc"
+ "$(srcdir)/scripts/fuse_gmock_files.py" "$(srcdir)/fused-src"
+ cp -f "$(srcdir)/src/gmock_main.cc" "$(srcdir)/fused-src"
+
+maintainer-clean-local:
+ rm -rf "$(srcdir)/fused-src"
+
+# Death tests may produce core dumps in the build directory. In case
+# this happens, clean them to keep distcleancheck happy.
+CLEANFILES = core
diff --git a/testing/gmock/README b/testing/gmock/README
index 4b3efd8..8e4150a 100644
--- a/testing/gmock/README
+++ b/testing/gmock/README
@@ -1,13 +1,16 @@
Google C++ Mocking Framework
============================
+
http://code.google.com/p/googlemock/
Overview
--------
-Google's framework for writing and using C++ mock classes on Linux,
-Mac OS X, and Windows. Inspired by jMock, EasyMock, and Hamcrest, and
-designed with C++'s specifics in mind, it can help you derive better
-designs of your system and write better tests.
+
+Google's framework for writing and using C++ mock classes on a variety
+of platforms (Linux, Mac OS X, Windows, Windows CE, Symbian, etc).
+Inspired by jMock, EasyMock, and Hamcrest, and designed with C++'s
+specifics in mind, it can help you derive better designs of your
+system and write better tests.
Google Mock:
@@ -25,22 +28,23 @@ Google Mock:
- does not use exceptions, and
- is easy to learn and use.
-Please see the project page above for more information as well as mailing lists
-for questions, discussions, and development. There is also an IRC channel on
-OFTC (irc.oftc.net) #gtest available. Please join us!
+Please see the project page above for more information as well as the
+mailing list for questions, discussions, and development. There is
+also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
+join us!
Please note that code under scripts/generator/ is from the cppclean
project (http://code.google.com/p/cppclean/) and under the Apache
License, which is different from Google Mock's license.
-Requirements
-------------
-Google Mock is not a testing framework itself. Instead, it needs a
-testing framework for writing tests. It works with Google Test
-(http://code.google.com/p/googletest/) out of the box. You can use
-either the copy of Google Test that comes with Google Mock, or a
-compatible version you already have. This version of Google Mock
-requires Google Test 1.4.0.
+Requirements for End Users
+--------------------------
+
+Google Mock is implemented on top of the Google Test C++ testing
+framework (http://code.google.com/p/googletest/), and includes the
+latter as part of the SVN repositary and distribution package. You
+must use the bundled version of Google Test when using Google Mock, or
+you may get compiler/linker errors.
You can also easily configure Google Mock to work with another testing
framework of your choice; although it will still need Google Test as
@@ -52,90 +56,186 @@ Google Mock depends on advanced C++ features and thus requires a more
modern compiler. The following are needed to use Google Mock:
### Linux Requirements ###
+
These are the base requirements to build and use Google Mock from a source
package (as described below):
+
* GNU-compatible Make or "gmake"
* POSIX-standard shell
* POSIX(-2) Regular Expressions (regex.h)
- * gcc 3.4 or newer.
-
-Furthermore, if you are building Google Mock from a VCS Checkout (also
-described below), there are further requirements:
- * Automake version 1.9 or newer
- * Autoconf version 2.59 or newer
- * Libtool / Libtoolize
- * Python version 2.3 or newer
+ * C++98-standard-compliant compiler (e.g. GCC 3.4 or newer)
### Windows Requirements ###
+
* Microsoft Visual C++ 8.0 SP1 or newer
### Mac OS X Requirements ###
+
* Mac OS X 10.4 Tiger or newer
* Developer Tools Installed
+Requirements for Contributors
+-----------------------------
+
+We welcome patches. If you plan to contribute a patch, you need to
+build Google Mock and its own tests from an SVN checkout (described
+below), which has further requirements:
+
+ * Automake version 1.9 or newer
+ * Autoconf version 2.59 or newer
+ * Libtool / Libtoolize
+ * Python version 2.3 or newer (for running some of the tests and
+ re-generating certain source files from templates)
+
Getting the Source
------------------
-There are two primary ways of getting Google Mock's source code: you can
-download a source release in your preferred archive format, or directly check
-out the source from a Version Control System (VCS, we use Google Code's
-Subversion hosting). The VCS checkout requires a few extra steps and some extra
-software packages on your system, but lets you track development, and make
-patches to contribute much more easily, so we highly encourage it.
-
-### VCS Checkout: ###
-The first step is to select whether you want to check out the main line of
-development on Google Mock, or one of the released branches. The former will be
-much more active and have the latest features, but the latter provides much
-more stability and predictability. Choose whichever fits your needs best, and
-proceed with the following Subversion commands:
- svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn
+There are two primary ways of getting Google Mock's source code: you
+can download a stable source release in your preferred archive format,
+or directly check out the source from our Subversion (SVN) repositary.
+The SVN checkout requires a few extra steps and some extra software
+packages on your system, but lets you track development and make
+patches much more easily, so we highly encourage it.
-or for a release version X.Y.*'s branch:
+### Source Package ###
- svn checkout http://googlemock.googlecode.com/svn/branches/release-X.Y/ \
- gmock-X.Y-svn
+Google Mock is released in versioned source packages which can be
+downloaded from the download page [1]. Several different archive
+formats are provided, but the only difference is the tools needed to
+extract their contents, and the size of the resulting file. Download
+whichever you are most comfortable with.
-Next you will need to prepare the GNU Autotools build system, if you
-are using Linux or Mac OS X. Enter the target directory of the
-checkout command you used ('gmock-svn' or 'gmock-X.Y-svn' above) and
-proceed with the following command:
+ [1] http://code.google.com/p/googlemock/downloads/list
+
+Once downloaded expand the archive using whichever tools you prefer
+for that type. This will always result in a new directory with the
+name "gmock-X.Y.Z" which contains all of the source code. Here are
+some examples on Linux:
+
+ tar -xvzf gmock-X.Y.Z.tar.gz
+ tar -xvjf gmock-X.Y.Z.tar.bz2
+ unzip gmock-X.Y.Z.zip
+
+### SVN Checkout ###
+
+To check out the main branch (also known as the "trunk") of Google
+Mock, run the following Subversion command:
+
+ svn checkout http://googlemock.googlecode.com/svn/trunk/ gmock-svn
+
+If you are using a *nix system and plan to use the GNU Autotools build
+system to build Google Mock (described below), you'll need to
+configure it now. Otherwise you are done with getting the source
+files.
+
+To prepare the Autotools build system, enter the target directory of
+the checkout command you used ('gmock-svn') and proceed with the
+following command:
autoreconf -fvi
-Once you have completed this step, you are ready to build the library. Note
-that you should only need to complete this step once. The subsequent `make'
-invocations will automatically re-generate the bits of the build system that
-need to be changed.
+Once you have completed this step, you are ready to build the library.
+Note that you should only need to complete this step once. The
+subsequent 'make' invocations will automatically re-generate the bits
+of the build system that need to be changed.
-If your system uses older versions of the autotools, the above command will
-fail. You may need to explicitly specify a version to use. For instance, if you
-have both GNU Automake 1.4 and 1.9 installed and `automake' would invoke the
-1.4, use instead:
+If your system uses older versions of the autotools, the above command
+will fail. You may need to explicitly specify a version to use. For
+instance, if you have both GNU Automake 1.4 and 1.9 installed and
+'automake' would invoke the 1.4, use instead:
AUTOMAKE=automake-1.9 ACLOCAL=aclocal-1.9 autoreconf -fvi
Make sure you're using the same version of automake and aclocal.
-### Source Package: ###
-Google Mock is also released in source packages which can be downloaded from
-its Google Code download page[1]. Several different archive formats are
-provided, but the only difference is the tools needed to extract their
-contents, and the size of the resulting file. Download whichever you are most
-comfortable with.
+Setting up the Build
+--------------------
- [1] Google Mock Downloads: http://code.google.com/p/googlemock/downloads/list
+To build Google Mock and your tests that use it, you need to tell your
+build system where to find its headers and source files. The exact
+way to do it depends on which build system you use, and is usually
+straightforward.
-Once downloaded expand the archive using whichever tools you prefer for that
-type. This will always result in a new directory with the name "gmock-X.Y.Z"
-which contains all of the source code. Here are some examples in Linux:
+### Generic Build Instructions ###
- tar -xvzf gmock-X.Y.Z.tar.gz
- tar -xvjf gmock-X.Y.Z.tar.bz2
- unzip gmock-X.Y.Z.zip
+This section shows how you can integrate Google Mock into your
+existing build system.
+
+Suppose you put Google Mock in directory ${GMOCK_DIR} and Google Test
+in ${GTEST_DIR} (the latter is ${GMOCK_DIR}/gtest by default). To
+build Google Mock, create a library build target (or a project as
+called by Visual Studio and Xcode) to compile
+
+ ${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc
+
+with
+
+ ${GTEST_DIR}/include, ${GTEST_DIR}, ${GMOCK_DIR}/include, and ${GMOCK_DIR}
+
+in the header search path. Assuming a Linux-like system and gcc,
+something like the following will do:
+
+ g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -I${GMOCK_DIR}/include \
+ -I${GMOCK_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
+ g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -I${GMOCK_DIR}/include \
+ -I${GMOCK_DIR} -c ${GMOCK_DIR}/src/gmock-all.cc
+ ar -rv libgmock.a gtest-all.o gmock-all.o
+
+Next, you should compile your test source file with
+${GTEST_DIR}/include and ${GMOCK_DIR}/include in the header search
+path, and link it with gmock and any other necessary libraries:
+
+ g++ -I${GTEST_DIR}/include -I${GMOCK_DIR}/include \
+ path/to/your_test.cc libgmock.a -o your_test
+
+As an example, the make/ directory contains a Makefile that you can
+use to build Google Mock on systems where GNU make is available
+(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
+Mock's own tests. Instead, it just builds the Google Mock library and
+a sample test. You can use it as a starting point for your own build
+script.
+
+If the default settings are correct for your environment, the
+following commands should succeed:
+
+ cd ${GMOCK_DIR}/make
+ make
+ ./gmock_test
+
+If you see errors, try to tweak the contents of make/Makefile to make
+them go away. There are instructions in make/Makefile on how to do
+it.
+
+### Windows ###
+
+The msvc/ directory contains VC++ 2005 projects for building Google
+Mock and selected tests.
+
+Open msvc/gmock.sln and build the library and tests. If you want to
+create your own project to use with Google Mock, you'll have to
+configure it to use the gmock_config propety sheet. For that:
+
+ * Open the Property Manager window (View | Other Windows | Property Manager)
+ * Right-click on your project and select "Add Existing Property Sheet..."
+ * Navigate to gmock_config.vsprops and select it.
+ * In Project Properties | Configuration Properties | General | Additional
+ Include Directories, type <path to Google Mock>/include.
+
+Tweaking Google Mock
+--------------------
+
+Google Mock can be used in diverse environments. The default
+configuration may not work (or may not work well) out of the box in
+some environments. However, you can easily tweak Google Mock by
+defining control macros on the compiler command line. Generally,
+these macros are named like GTEST_XYZ and you define them to either 1
+or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below. For a complete list,
+see file ${GTEST_DIR}/include/gtest/internal/gtest-port.h.
+
+### Choosing a TR1 Tuple Library ###
-Choosing a TR1 Tuple Library
-----------------------------
Google Mock uses the C++ Technical Report 1 (TR1) tuple library
heavily. Unfortunately TR1 tuple is not yet widely available with all
compilers. The good news is that Google Test 1.4.0+ implements a
@@ -146,104 +246,85 @@ provide TR1 tuple.
Usually you don't need to care about which tuple library Google Test
and Google Mock use. However, if your project already uses TR1 tuple,
you need to tell Google Test and Google Mock to use the same TR1 tuple
-library the rest of your project uses (this requirement is new in
-Google Test 1.4.0 and Google Mock 1.2.0, so you may need to take care
-of it when upgrading from an earlier version), or the two tuple
+library the rest of your project uses, or the two tuple
implementations will clash. To do that, add
-DGTEST_USE_OWN_TR1_TUPLE=0
to the compiler flags while compiling Google Test, Google Mock, and
-your tests.
+your tests. If you want to force Google Test and Google Mock to use
+their own tuple library, just add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=1
+
+to the compiler flags instead.
If you want to use Boost's TR1 tuple library with Google Mock, please
refer to the Boost website (http://www.boost.org/) for how to obtain
it and set it up.
-Building the Source
--------------------
-### Linux and Mac OS X (without Xcode) ###
-There are two primary options for building the source at this point: build it
-inside the source code tree, or in a separate directory. We recommend building
-in a separate directory as that tends to produce both more consistent results
-and be easier to clean up should anything go wrong, but both patterns are
-supported. The only hard restriction is that while the build directory can be
-a subdirectory of the source directory, the opposite is not possible and will
-result in errors. Once you have selected where you wish to build Google Mock,
-create the directory if necessary, and enter it. The following steps apply for
-either approach by simply substituting the shell variable SRCDIR with "." for
-building inside the source directory, and the relative path to the source
-directory otherwise.
-
- ${SRCDIR}/configure # Standard GNU configure script, --help for more info
-
-Once you have successfully configured Google Mock, the build steps are standard
-for GNU-style OSS packages.
-
- make # Standard makefile following GNU conventions
- make check # Builds and runs all tests - all should pass
+### Tweaking Google Test ###
-Note that when building your project against Google Mock, you are building
-against Google Test as well. There is no need to configure Google Test
-separately.
+Most of Google Test's control macros apply to Google Mock as well.
+Please see file ${GTEST_DIR}/README for how to tweak them.
-### Windows ###
-The msvc/ directory contains VC++ 2005 projects for building Google
-Mock and selected tests.
+Upgrading from an Earlier Version
+---------------------------------
-If you want to use a version of Google Test other then the one bundled with
-Google Mock, change the value of the GTestDir macro in gmock_config.vsprop
-to point to the new location.
+We strive to keep Google Mock releases backward compatible.
+Sometimes, though, we have to make some breaking changes for the
+users' long-term benefits. This section describes what you'll need to
+do if you are upgrading from an earlier version of Google Mock.
-Open msvc/gmock.sln and build the library and tests. If you want to
-create your own project to use with Google Mock, you'll have to
-configure it to use the gmock_config propety sheet. For that:
- * Open the Property Manager window (View | Other Windows | Property Manager)
- * Right-click on your project and select "Add Existing Property Sheet..."
- * Navigate to gmock_config.vsprops and select it.
- * In Project Properties | Configuration Properties | General | Additional
- Include Directories, type <path to Google Mock>/include.
+### Upgrading from 1.1.0 or Earlier ###
-TODO(wan@google.com): update the .vsprops and .vcproj files such that the
-last step is unnecessary.
+You may need to explicitly enable or disable Google Test's own TR1
+tuple library. See the instructions in section "Choosing a TR1 Tuple
+Library".
-### Using GNU Make ###
-The make/ directory contains a Makefile that you can use to build
-Google Mock on systems where GNU make is available (e.g. Linux and Mac
-OS X). It doesn't try to build Google Mock's own tests. Instead, it
-just builds the Google Mock libraries and some sample tests. You can
-use it as a starting point for your own Makefile.
+### Upgrading from 1.4.0 or Earlier ###
-If the default settings are correct for your environment, the
-following commands should succeed:
+On platforms where the pthread library is available, Google Test and
+Google Mock use it in order to be thread-safe. For this to work, you
+may need to tweak your compiler and/or linker flags. Please see the
+"Multi-threaded Tests" section in file ${GTEST_DIR}/README for what
+you may need to do.
- cd ${SRCDIR}/make
- make
- ./gmock_test
+If you have custom matchers defined using MatcherInterface or
+MakePolymorphicMatcher(), you'll need to update their definitions to
+use the new matcher API [2]. Matchers defined using MATCHER() or
+MATCHER_P*() aren't affected.
-If you see errors, try to tweak the contents of make/Makefile to make
-them go away. There are instructions in make/Makefile on how to do
-it.
+ [2] http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers,
+ http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers
-### Using Your Own Build System ###
-If none of the build solutions we provide works for you, or if you
-prefer your own build system, you just need to compile
-${GTEST_SRCDIR}/src/gtest-all.cc (where GTEST_SRCDIR is the root of
-the Google Test source tree) and src/gmock-all.cc into a library and
-link your tests with it. Assuming a Linux-like system and gcc,
-something like the following will do:
+Developing Google Mock
+----------------------
- cd ${SRCDIR}
- g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \
- -c {GTEST_SRCDIR}/src/gtest-all.cc
- g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \
- -c src/gmock-all.cc
- ar -rv libgmock.a gtest-all.o gmock-all.o
- g++ -I. -I./include -I${GTEST_SRCDIR} -I${GTEST_SRCDIR}/include \
- path/to/your_test.cc libgmock.a -o your_test
+This section discusses how to make your own changes to Google Mock.
+
+### Testing Google Mock Itself ###
+
+To make sure your changes work as intended and don't break existing
+functionality, you'll want to compile and run Google Test's own tests.
+For that you'll need Autotools. First, make sure you have followed
+the instructions in section "SVN Checkout" to configure Google Mock.
+Then, create a build output directory and enter it. Next,
+
+ ${GMOCK_DIR}/configure # Standard GNU configure script, --help for more info
+
+Once you have successfully configured Google Mock, the build steps are
+standard for GNU-style OSS packages.
+
+ make # Standard makefile following GNU conventions
+ make check # Builds and runs all tests - all should pass.
+
+Note that when building your project against Google Mock, you are building
+against Google Test as well. There is no need to configure Google Test
+separately.
+
+### Regenerating Source Files ###
-Regenerating Source Files
--------------------------
Some of Google Mock's source files are generated from templates (not
in the C++ sense) using a script. A template file is named FOO.pump,
where FOO is the name of the file it will generate. For example, the
@@ -251,12 +332,21 @@ file include/gmock/gmock-generated-actions.h.pump is used to generate
gmock-generated-actions.h in the same directory.
Normally you don't need to worry about regenerating the source files,
-unless you need to modify them (e.g. if you are working on a patch for
-Google Mock). In that case, you should modify the corresponding .pump
-files instead and run the 'pump' script (for Pump is Useful for Meta
-Programming) to regenerate them. We are still working on releasing
-the script and its documentation. If you need it now, please email
-googlemock@googlegroups.com such that we know to make it happen
-sooner.
+unless you need to modify them. In that case, you should modify the
+corresponding .pump files instead and run the 'pump' script (for Pump
+is Useful for Meta Programming) to regenerate them. You can find
+pump.py in the ${GTEST_DIR}/scripts/ directory. Read the Pump manual
+[3] for how to use it.
+
+ [3] http://code.google.com/p/googletest/wiki/PumpManual.
+
+### Contributing a Patch ###
+
+We welcome patches. Please read the Google Mock developer's guide [4]
+for how you can contribute. In particular, make sure you have signed
+the Contributor License Agreement, or we won't be able to accept the
+patch.
+
+ [4] http://code.google.com/p/googlemock/wiki/DevGuide
Happy testing!
diff --git a/testing/gmock/include/gmock/gmock-actions.h b/testing/gmock/include/gmock/gmock-actions.h
index 007ad9d..9fe1964 100644
--- a/testing/gmock/include/gmock/gmock-actions.h
+++ b/testing/gmock/include/gmock/gmock-actions.h
@@ -43,7 +43,6 @@
#include <errno.h>
#endif
-#include <gmock/gmock-printers.h>
#include <gmock/internal/gmock-internal-utils.h>
#include <gmock/internal/gmock-port.h>
@@ -477,7 +476,7 @@ class ReturnAction {
// and put the typedef both here (for use in assert statement) and
// in the Impl class. But both definitions must be the same.
typedef typename Function<F>::Result Result;
- GMOCK_COMPILE_ASSERT_(
+ GTEST_COMPILE_ASSERT_(
!internal::is_reference<Result>::value,
use_ReturnRef_instead_of_Return_to_return_a_reference);
return Action<F>(new Impl<F>(value_));
@@ -504,7 +503,7 @@ class ReturnAction {
virtual Result Perform(const ArgumentTuple&) { return value_; }
private:
- GMOCK_COMPILE_ASSERT_(!internal::is_reference<Result>::value,
+ GTEST_COMPILE_ASSERT_(!internal::is_reference<Result>::value,
Result_cannot_be_a_reference_type);
Result value_;
@@ -522,7 +521,7 @@ class ReturnNullAction {
// Allows ReturnNull() to be used in any pointer-returning function.
template <typename Result, typename ArgumentTuple>
static Result Perform(const ArgumentTuple&) {
- GMOCK_COMPILE_ASSERT_(internal::is_pointer<Result>::value,
+ GTEST_COMPILE_ASSERT_(internal::is_pointer<Result>::value,
ReturnNull_can_be_used_to_return_a_pointer_only);
return NULL;
}
@@ -555,7 +554,7 @@ class ReturnRefAction {
// Asserts that the function return type is a reference. This
// catches the user error of using ReturnRef(x) when Return(x)
// should be used, and generates some helpful error message.
- GMOCK_COMPILE_ASSERT_(internal::is_reference<Result>::value,
+ GTEST_COMPILE_ASSERT_(internal::is_reference<Result>::value,
use_Return_instead_of_ReturnRef_to_return_a_value);
return Action<F>(new Impl<F>(ref_));
}
diff --git a/testing/gmock/include/gmock/gmock-generated-function-mockers.h b/testing/gmock/include/gmock/gmock-generated-function-mockers.h
index 3b2ede1..58be7e1 100644
--- a/testing/gmock/include/gmock/gmock-generated-function-mockers.h
+++ b/testing/gmock/include/gmock/gmock-generated-function-mockers.h
@@ -344,7 +344,7 @@ using internal::FunctionMocker;
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD0_(tn, constness, ct, Method, F) \
GMOCK_RESULT_(tn, F) ct Method() constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 0, \
this_method_does_not_take_0_arguments); \
GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \
@@ -359,7 +359,7 @@ using internal::FunctionMocker;
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD1_(tn, constness, ct, Method, F) \
GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 1, \
this_method_does_not_take_1_argument); \
GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \
@@ -376,7 +376,7 @@ using internal::FunctionMocker;
#define GMOCK_METHOD2_(tn, constness, ct, Method, F) \
GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \
GMOCK_ARG_(tn, F, 2) gmock_a2) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 2, \
this_method_does_not_take_2_arguments); \
GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \
@@ -395,7 +395,7 @@ using internal::FunctionMocker;
GMOCK_RESULT_(tn, F) ct Method(GMOCK_ARG_(tn, F, 1) gmock_a1, \
GMOCK_ARG_(tn, F, 2) gmock_a2, \
GMOCK_ARG_(tn, F, 3) gmock_a3) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 3, \
this_method_does_not_take_3_arguments); \
GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \
@@ -417,7 +417,7 @@ using internal::FunctionMocker;
GMOCK_ARG_(tn, F, 2) gmock_a2, \
GMOCK_ARG_(tn, F, 3) gmock_a3, \
GMOCK_ARG_(tn, F, 4) gmock_a4) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 4, \
this_method_does_not_take_4_arguments); \
GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \
@@ -442,7 +442,7 @@ using internal::FunctionMocker;
GMOCK_ARG_(tn, F, 3) gmock_a3, \
GMOCK_ARG_(tn, F, 4) gmock_a4, \
GMOCK_ARG_(tn, F, 5) gmock_a5) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 5, \
this_method_does_not_take_5_arguments); \
GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \
@@ -469,7 +469,7 @@ using internal::FunctionMocker;
GMOCK_ARG_(tn, F, 4) gmock_a4, \
GMOCK_ARG_(tn, F, 5) gmock_a5, \
GMOCK_ARG_(tn, F, 6) gmock_a6) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 6, \
this_method_does_not_take_6_arguments); \
GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \
@@ -498,7 +498,7 @@ using internal::FunctionMocker;
GMOCK_ARG_(tn, F, 5) gmock_a5, \
GMOCK_ARG_(tn, F, 6) gmock_a6, \
GMOCK_ARG_(tn, F, 7) gmock_a7) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 7, \
this_method_does_not_take_7_arguments); \
GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \
@@ -529,7 +529,7 @@ using internal::FunctionMocker;
GMOCK_ARG_(tn, F, 6) gmock_a6, \
GMOCK_ARG_(tn, F, 7) gmock_a7, \
GMOCK_ARG_(tn, F, 8) gmock_a8) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 8, \
this_method_does_not_take_8_arguments); \
GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \
@@ -562,7 +562,7 @@ using internal::FunctionMocker;
GMOCK_ARG_(tn, F, 7) gmock_a7, \
GMOCK_ARG_(tn, F, 8) gmock_a8, \
GMOCK_ARG_(tn, F, 9) gmock_a9) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 9, \
this_method_does_not_take_9_arguments); \
GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \
@@ -598,7 +598,7 @@ using internal::FunctionMocker;
GMOCK_ARG_(tn, F, 8) gmock_a8, \
GMOCK_ARG_(tn, F, 9) gmock_a9, \
GMOCK_ARG_(tn, F, 10) gmock_a10) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == 10, \
this_method_does_not_take_10_arguments); \
GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \
diff --git a/testing/gmock/include/gmock/gmock-generated-function-mockers.h.pump b/testing/gmock/include/gmock/gmock-generated-function-mockers.h.pump
index 619debd..20a4454 100644
--- a/testing/gmock/include/gmock/gmock-generated-function-mockers.h.pump
+++ b/testing/gmock/include/gmock/gmock-generated-function-mockers.h.pump
@@ -132,7 +132,7 @@ $var matcher_as = [[$for j, \
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
#define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, F) \
GMOCK_RESULT_(tn, F) ct Method($arg_as) constness { \
- GMOCK_COMPILE_ASSERT_(::std::tr1::tuple_size< \
+ GTEST_COMPILE_ASSERT_(::std::tr1::tuple_size< \
tn ::testing::internal::Function<F>::ArgumentTuple>::value == $i, \
this_method_does_not_take_$i[[]]_argument[[$if i != 1 [[s]]]]); \
GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \
diff --git a/testing/gmock/include/gmock/gmock-generated-matchers.h b/testing/gmock/include/gmock/gmock-generated-matchers.h
index 9e5bede..2790e06 100644
--- a/testing/gmock/include/gmock/gmock-generated-matchers.h
+++ b/testing/gmock/include/gmock/gmock-generated-matchers.h
@@ -42,7 +42,6 @@
#include <string>
#include <vector>
#include <gmock/gmock-matchers.h>
-#include <gmock/gmock-printers.h>
namespace testing {
namespace internal {
@@ -222,7 +221,7 @@ template <class ArgsTuple, int k0 = -1, int k1 = -1, int k2 = -1, int k3 = -1,
class ArgsMatcherImpl : public MatcherInterface<ArgsTuple> {
public:
// ArgsTuple may have top-level const or reference modifiers.
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple;
typedef typename internal::TupleFields<RawArgsTuple, k0, k1, k2, k3, k4, k5,
k6, k7, k8, k9>::type SelectedArgs;
typedef Matcher<const SelectedArgs&> MonomorphicInnerMatcher;
@@ -315,8 +314,7 @@ class ElementsAreMatcher1 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -344,8 +342,7 @@ class ElementsAreMatcher2 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -372,8 +369,7 @@ class ElementsAreMatcher3 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -402,8 +398,7 @@ class ElementsAreMatcher4 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -434,8 +429,7 @@ class ElementsAreMatcher5 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -470,8 +464,7 @@ class ElementsAreMatcher6 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -508,8 +501,7 @@ class ElementsAreMatcher7 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -548,8 +540,7 @@ class ElementsAreMatcher8 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -591,8 +582,7 @@ class ElementsAreMatcher9 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -636,8 +626,7 @@ class ElementsAreMatcher10 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
diff --git a/testing/gmock/include/gmock/gmock-generated-matchers.h.pump b/testing/gmock/include/gmock/gmock-generated-matchers.h.pump
index 07a51a3..db498ec 100644
--- a/testing/gmock/include/gmock/gmock-generated-matchers.h.pump
+++ b/testing/gmock/include/gmock/gmock-generated-matchers.h.pump
@@ -44,7 +44,6 @@ $$ }} This line fixes auto-indentation of the following code in Emacs.
#include <string>
#include <vector>
#include <gmock/gmock-matchers.h>
-#include <gmock/gmock-printers.h>
namespace testing {
namespace internal {
@@ -108,7 +107,7 @@ template <class ArgsTuple$for i [[, int k$i = -1]]>
class ArgsMatcherImpl : public MatcherInterface<ArgsTuple> {
public:
// ArgsTuple may have top-level const or reference modifiers.
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(ArgsTuple)) RawArgsTuple;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(ArgsTuple) RawArgsTuple;
typedef typename internal::TupleFields<RawArgsTuple, $ks>::type SelectedArgs;
typedef Matcher<const SelectedArgs&> MonomorphicInnerMatcher;
@@ -201,8 +200,7 @@ class ElementsAreMatcher$i {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
diff --git a/testing/gmock/include/gmock/gmock-matchers.h b/testing/gmock/include/gmock/gmock-matchers.h
index 66efecd..2a42bf9 100644
--- a/testing/gmock/include/gmock/gmock-matchers.h
+++ b/testing/gmock/include/gmock/gmock-matchers.h
@@ -43,9 +43,9 @@
#include <ostream> // NOLINT
#include <sstream>
#include <string>
+#include <utility>
#include <vector>
-#include <gmock/gmock-printers.h>
#include <gmock/internal/gmock-internal-utils.h>
#include <gmock/internal/gmock-port.h>
#include <gtest/gtest.h>
@@ -419,20 +419,20 @@ class SafeMatcherCastImpl {
template <typename U>
static inline Matcher<T> Cast(const Matcher<U>& matcher) {
// Enforce that T can be implicitly converted to U.
- GMOCK_COMPILE_ASSERT_((internal::ImplicitlyConvertible<T, U>::value),
+ GTEST_COMPILE_ASSERT_((internal::ImplicitlyConvertible<T, U>::value),
T_must_be_implicitly_convertible_to_U);
// Enforce that we are not converting a non-reference type T to a reference
// type U.
- GMOCK_COMPILE_ASSERT_(
+ GTEST_COMPILE_ASSERT_(
internal::is_reference<T>::value || !internal::is_reference<U>::value,
cannot_convert_non_referentce_arg_to_reference);
// In case both T and U are arithmetic types, enforce that the
// conversion is not lossy.
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(T)) RawT;
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(U)) RawU;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU;
const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther;
const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther;
- GMOCK_COMPILE_ASSERT_(
+ GTEST_COMPILE_ASSERT_(
kTIsOther || kUIsOther ||
(internal::LosslessArithmeticConvertible<RawT, RawU>::value),
conversion_of_arithmetic_types_must_be_lossless);
@@ -566,7 +566,7 @@ bool TupleMatches(const MatcherTuple& matcher_tuple,
using ::std::tr1::tuple_size;
// Makes sure that matcher_tuple and value_tuple have the same
// number of fields.
- GMOCK_COMPILE_ASSERT_(tuple_size<MatcherTuple>::value ==
+ GTEST_COMPILE_ASSERT_(tuple_size<MatcherTuple>::value ==
tuple_size<ValueTuple>::value,
matcher_and_value_have_different_numbers_of_fields);
return TuplePrefix<tuple_size<ValueTuple>::value>::
@@ -703,11 +703,11 @@ class AnythingMatcher {
} \
virtual void DescribeTo(::std::ostream* os) const { \
*os << relation " "; \
- UniversalPrinter<Rhs>::Print(rhs_, os); \
+ UniversalPrint(rhs_, os); \
} \
virtual void DescribeNegationTo(::std::ostream* os) const { \
*os << negated_relation " "; \
- UniversalPrinter<Rhs>::Print(rhs_, os); \
+ UniversalPrint(rhs_, os); \
} \
private: \
Rhs rhs_; \
@@ -911,7 +911,7 @@ class StrEqualityMatcher {
if (!case_sensitive_) {
*os << "(ignoring case) ";
}
- UniversalPrinter<StringType>::Print(string_, os);
+ UniversalPrint(string_, os);
}
const StringType string_;
@@ -948,12 +948,12 @@ class HasSubstrMatcher {
// Describes what this matcher matches.
void DescribeTo(::std::ostream* os) const {
*os << "has substring ";
- UniversalPrinter<StringType>::Print(substring_, os);
+ UniversalPrint(substring_, os);
}
void DescribeNegationTo(::std::ostream* os) const {
*os << "has no substring ";
- UniversalPrinter<StringType>::Print(substring_, os);
+ UniversalPrint(substring_, os);
}
private:
@@ -989,12 +989,12 @@ class StartsWithMatcher {
void DescribeTo(::std::ostream* os) const {
*os << "starts with ";
- UniversalPrinter<StringType>::Print(prefix_, os);
+ UniversalPrint(prefix_, os);
}
void DescribeNegationTo(::std::ostream* os) const {
*os << "doesn't start with ";
- UniversalPrinter<StringType>::Print(prefix_, os);
+ UniversalPrint(prefix_, os);
}
private:
@@ -1029,12 +1029,12 @@ class EndsWithMatcher {
void DescribeTo(::std::ostream* os) const {
*os << "ends with ";
- UniversalPrinter<StringType>::Print(suffix_, os);
+ UniversalPrint(suffix_, os);
}
void DescribeNegationTo(::std::ostream* os) const {
*os << "doesn't end with ";
- UniversalPrinter<StringType>::Print(suffix_, os);
+ UniversalPrint(suffix_, os);
}
private:
@@ -1096,38 +1096,46 @@ class MatchesRegexMatcher {
//
// We define this as a macro in order to eliminate duplicated source
// code.
-#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op) \
+#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \
class name##2Matcher { \
public: \
template <typename T1, typename T2> \
+ operator Matcher< ::std::tr1::tuple<T1, T2> >() const { \
+ return MakeMatcher(new Impl< ::std::tr1::tuple<T1, T2> >); \
+ } \
+ template <typename T1, typename T2> \
operator Matcher<const ::std::tr1::tuple<T1, T2>&>() const { \
- return MakeMatcher(new Impl<T1, T2>); \
+ return MakeMatcher(new Impl<const ::std::tr1::tuple<T1, T2>&>); \
} \
private: \
- template <typename T1, typename T2> \
- class Impl : public MatcherInterface<const ::std::tr1::tuple<T1, T2>&> { \
+ template <typename Tuple> \
+ class Impl : public MatcherInterface<Tuple> { \
public: \
virtual bool MatchAndExplain( \
- const ::std::tr1::tuple<T1, T2>& args, \
+ Tuple args, \
MatchResultListener* /* listener */) const { \
return ::std::tr1::get<0>(args) op ::std::tr1::get<1>(args); \
} \
virtual void DescribeTo(::std::ostream* os) const { \
- *os << "are a pair (x, y) where x " #op " y"; \
+ *os << "are " relation; \
} \
virtual void DescribeNegationTo(::std::ostream* os) const { \
- *os << "are a pair (x, y) where x " #op " y is false"; \
+ *os << "aren't " relation; \
} \
}; \
}
// Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively.
-GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==);
-GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ge, >=);
-GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Gt, >);
-GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Le, <=);
-GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Lt, <);
-GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=);
+GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Eq, ==, "an equal pair");
+GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(
+ Ge, >=, "a pair where the first >= the second");
+GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(
+ Gt, >, "a pair where the first > the second");
+GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(
+ Le, <=, "a pair where the first <= the second");
+GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(
+ Lt, <, "a pair where the first < the second");
+GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(Ne, !=, "an unequal pair");
#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
@@ -1604,8 +1612,8 @@ class PointeeMatcher {
template <typename Pointer>
class Impl : public MatcherInterface<Pointer> {
public:
- typedef typename PointeeOf<GMOCK_REMOVE_CONST_( // NOLINT
- GMOCK_REMOVE_REFERENCE_(Pointer))>::type Pointee;
+ typedef typename PointeeOf<GTEST_REMOVE_CONST_( // NOLINT
+ GTEST_REMOVE_REFERENCE_(Pointer))>::type Pointee;
explicit Impl(const InnerMatcher& matcher)
: matcher_(MatcherCast<const Pointee&>(matcher)) {}
@@ -1663,7 +1671,7 @@ class FieldMatcher {
bool MatchAndExplain(const T& value, MatchResultListener* listener) const {
return MatchAndExplainImpl(
typename ::testing::internal::
- is_pointer<GMOCK_REMOVE_CONST_(T)>::type(),
+ is_pointer<GTEST_REMOVE_CONST_(T)>::type(),
value, listener);
}
@@ -1702,9 +1710,9 @@ class PropertyMatcher {
public:
// The property may have a reference type, so 'const PropertyType&'
// may cause double references and fail to compile. That's why we
- // need GMOCK_REFERENCE_TO_CONST, which works regardless of
+ // need GTEST_REFERENCE_TO_CONST, which works regardless of
// PropertyType being a reference or not.
- typedef GMOCK_REFERENCE_TO_CONST_(PropertyType) RefToConstProperty;
+ typedef GTEST_REFERENCE_TO_CONST_(PropertyType) RefToConstProperty;
PropertyMatcher(PropertyType (Class::*property)() const,
const Matcher<RefToConstProperty>& matcher)
@@ -1724,7 +1732,7 @@ class PropertyMatcher {
bool MatchAndExplain(const T&value, MatchResultListener* listener) const {
return MatchAndExplainImpl(
typename ::testing::internal::
- is_pointer<GMOCK_REMOVE_CONST_(T)>::type(),
+ is_pointer<GTEST_REMOVE_CONST_(T)>::type(),
value, listener);
}
@@ -1874,25 +1882,25 @@ class ContainerEqMatcher {
explicit ContainerEqMatcher(const Container& rhs) : rhs_(View::Copy(rhs)) {
// Makes sure the user doesn't instantiate this class template
// with a const or reference type.
- testing::StaticAssertTypeEq<Container,
- GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))>();
+ (void)testing::StaticAssertTypeEq<Container,
+ GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>();
}
void DescribeTo(::std::ostream* os) const {
*os << "equals ";
- UniversalPrinter<StlContainer>::Print(rhs_, os);
+ UniversalPrint(rhs_, os);
}
void DescribeNegationTo(::std::ostream* os) const {
*os << "does not equal ";
- UniversalPrinter<StlContainer>::Print(rhs_, os);
+ UniversalPrint(rhs_, os);
}
template <typename LhsContainer>
bool MatchAndExplain(const LhsContainer& lhs,
MatchResultListener* listener) const {
- // GMOCK_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug
+ // GTEST_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug
// that causes LhsContainer to be a const type sometimes.
- typedef internal::StlContainerView<GMOCK_REMOVE_CONST_(LhsContainer)>
+ typedef internal::StlContainerView<GTEST_REMOVE_CONST_(LhsContainer)>
LhsView;
typedef typename LhsView::type LhsStlContainer;
StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
@@ -1914,8 +1922,7 @@ class ContainerEqMatcher {
*os << "which has these unexpected elements: ";
printed_header = true;
}
- UniversalPrinter<typename LhsStlContainer::value_type>::
- Print(*it, os);
+ UniversalPrint(*it, os);
}
}
@@ -1933,7 +1940,7 @@ class ContainerEqMatcher {
<< " doesn't have these expected elements: ";
printed_header2 = true;
}
- UniversalPrinter<typename StlContainer::value_type>::Print(*it, os);
+ UniversalPrint(*it, os);
}
}
}
@@ -1947,55 +1954,218 @@ class ContainerEqMatcher {
GTEST_DISALLOW_ASSIGN_(ContainerEqMatcher);
};
-// Implements Contains(element_matcher) for the given argument type Container.
+// Implements Pointwise(tuple_matcher, rhs_container). tuple_matcher
+// must be able to be safely cast to Matcher<tuple<const T1&, const
+// T2&> >, where T1 and T2 are the types of elements in the LHS
+// container and the RHS container respectively.
+template <typename TupleMatcher, typename RhsContainer>
+class PointwiseMatcher {
+ public:
+ typedef internal::StlContainerView<RhsContainer> RhsView;
+ typedef typename RhsView::type RhsStlContainer;
+ typedef typename RhsStlContainer::value_type RhsValue;
+
+ // Like ContainerEq, we make a copy of rhs in case the elements in
+ // it are modified after this matcher is created.
+ PointwiseMatcher(const TupleMatcher& tuple_matcher, const RhsContainer& rhs)
+ : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) {
+ // Makes sure the user doesn't instantiate this class template
+ // with a const or reference type.
+ (void)testing::StaticAssertTypeEq<RhsContainer,
+ GTEST_REMOVE_REFERENCE_AND_CONST_(RhsContainer)>();
+ }
+
+ template <typename LhsContainer>
+ operator Matcher<LhsContainer>() const {
+ return MakeMatcher(new Impl<LhsContainer>(tuple_matcher_, rhs_));
+ }
+
+ template <typename LhsContainer>
+ class Impl : public MatcherInterface<LhsContainer> {
+ public:
+ typedef internal::StlContainerView<
+ GTEST_REMOVE_REFERENCE_AND_CONST_(LhsContainer)> LhsView;
+ typedef typename LhsView::type LhsStlContainer;
+ typedef typename LhsView::const_reference LhsStlContainerReference;
+ typedef typename LhsStlContainer::value_type LhsValue;
+ // We pass the LHS value and the RHS value to the inner matcher by
+ // reference, as they may be expensive to copy. We must use tuple
+ // instead of pair here, as a pair cannot hold references (C++ 98,
+ // 20.2.2 [lib.pairs]).
+ typedef std::tr1::tuple<const LhsValue&, const RhsValue&> InnerMatcherArg;
+
+ Impl(const TupleMatcher& tuple_matcher, const RhsStlContainer& rhs)
+ // mono_tuple_matcher_ holds a monomorphic version of the tuple matcher.
+ : mono_tuple_matcher_(SafeMatcherCast<InnerMatcherArg>(tuple_matcher)),
+ rhs_(rhs) {}
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "contains " << rhs_.size()
+ << " values, where each value and its corresponding value in ";
+ UniversalPrinter<RhsStlContainer>::Print(rhs_, os);
+ *os << " ";
+ mono_tuple_matcher_.DescribeTo(os);
+ }
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't contain exactly " << rhs_.size()
+ << " values, or contains a value x at some index i"
+ << " where x and the i-th value of ";
+ UniversalPrint(rhs_, os);
+ *os << " ";
+ mono_tuple_matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(LhsContainer lhs,
+ MatchResultListener* listener) const {
+ LhsStlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
+ const size_t actual_size = lhs_stl_container.size();
+ if (actual_size != rhs_.size()) {
+ *listener << "which contains " << actual_size << " values";
+ return false;
+ }
+
+ typename LhsStlContainer::const_iterator left = lhs_stl_container.begin();
+ typename RhsStlContainer::const_iterator right = rhs_.begin();
+ for (size_t i = 0; i != actual_size; ++i, ++left, ++right) {
+ const InnerMatcherArg value_pair(*left, *right);
+
+ if (listener->IsInterested()) {
+ StringMatchResultListener inner_listener;
+ if (!mono_tuple_matcher_.MatchAndExplain(
+ value_pair, &inner_listener)) {
+ *listener << "where the value pair (";
+ UniversalPrint(*left, listener->stream());
+ *listener << ", ";
+ UniversalPrint(*right, listener->stream());
+ *listener << ") at index #" << i << " don't match";
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+ return false;
+ }
+ } else {
+ if (!mono_tuple_matcher_.Matches(value_pair))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ const Matcher<InnerMatcherArg> mono_tuple_matcher_;
+ const RhsStlContainer rhs_;
+
+ GTEST_DISALLOW_ASSIGN_(Impl);
+ };
+
+ private:
+ const TupleMatcher tuple_matcher_;
+ const RhsStlContainer rhs_;
+
+ GTEST_DISALLOW_ASSIGN_(PointwiseMatcher);
+};
+
+// Holds the logic common to ContainsMatcherImpl and EachMatcherImpl.
template <typename Container>
-class ContainsMatcherImpl : public MatcherInterface<Container> {
+class QuantifierMatcherImpl : public MatcherInterface<Container> {
public:
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef StlContainerView<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
typedef typename StlContainer::value_type Element;
template <typename InnerMatcher>
- explicit ContainsMatcherImpl(InnerMatcher inner_matcher)
+ explicit QuantifierMatcherImpl(InnerMatcher inner_matcher)
: inner_matcher_(
- testing::SafeMatcherCast<const Element&>(inner_matcher)) {}
+ testing::SafeMatcherCast<const Element&>(inner_matcher)) {}
+
+ // Checks whether:
+ // * All elements in the container match, if all_elements_should_match.
+ // * Any element in the container matches, if !all_elements_should_match.
+ bool MatchAndExplainImpl(bool all_elements_should_match,
+ Container container,
+ MatchResultListener* listener) const {
+ StlContainerReference stl_container = View::ConstReference(container);
+ size_t i = 0;
+ for (typename StlContainer::const_iterator it = stl_container.begin();
+ it != stl_container.end(); ++it, ++i) {
+ StringMatchResultListener inner_listener;
+ const bool matches = inner_matcher_.MatchAndExplain(*it, &inner_listener);
+
+ if (matches != all_elements_should_match) {
+ *listener << "whose element #" << i
+ << (matches ? " matches" : " doesn't match");
+ PrintIfNotEmpty(inner_listener.str(), listener->stream());
+ return !all_elements_should_match;
+ }
+ }
+ return all_elements_should_match;
+ }
+
+ protected:
+ const Matcher<const Element&> inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(QuantifierMatcherImpl);
+};
+
+// Implements Contains(element_matcher) for the given argument type Container.
+// Symmetric to EachMatcherImpl.
+template <typename Container>
+class ContainsMatcherImpl : public QuantifierMatcherImpl<Container> {
+ public:
+ template <typename InnerMatcher>
+ explicit ContainsMatcherImpl(InnerMatcher inner_matcher)
+ : QuantifierMatcherImpl<Container>(inner_matcher) {}
// Describes what this matcher does.
virtual void DescribeTo(::std::ostream* os) const {
*os << "contains at least one element that ";
- inner_matcher_.DescribeTo(os);
+ this->inner_matcher_.DescribeTo(os);
}
- // Describes what the negation of this matcher does.
virtual void DescribeNegationTo(::std::ostream* os) const {
*os << "doesn't contain any element that ";
- inner_matcher_.DescribeTo(os);
+ this->inner_matcher_.DescribeTo(os);
}
virtual bool MatchAndExplain(Container container,
MatchResultListener* listener) const {
- StlContainerReference stl_container = View::ConstReference(container);
- size_t i = 0;
- for (typename StlContainer::const_iterator it = stl_container.begin();
- it != stl_container.end(); ++it, ++i) {
- StringMatchResultListener inner_listener;
- if (inner_matcher_.MatchAndExplain(*it, &inner_listener)) {
- *listener << "whose element #" << i << " matches";
- PrintIfNotEmpty(inner_listener.str(), listener->stream());
- return true;
- }
- }
- return false;
+ return this->MatchAndExplainImpl(false, container, listener);
}
private:
- const Matcher<const Element&> inner_matcher_;
-
GTEST_DISALLOW_ASSIGN_(ContainsMatcherImpl);
};
+// Implements Each(element_matcher) for the given argument type Container.
+// Symmetric to ContainsMatcherImpl.
+template <typename Container>
+class EachMatcherImpl : public QuantifierMatcherImpl<Container> {
+ public:
+ template <typename InnerMatcher>
+ explicit EachMatcherImpl(InnerMatcher inner_matcher)
+ : QuantifierMatcherImpl<Container>(inner_matcher) {}
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "only contains elements that ";
+ this->inner_matcher_.DescribeTo(os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "contains some element that ";
+ this->inner_matcher_.DescribeNegationTo(os);
+ }
+
+ virtual bool MatchAndExplain(Container container,
+ MatchResultListener* listener) const {
+ return this->MatchAndExplainImpl(true, container, listener);
+ }
+
+ private:
+ GTEST_DISALLOW_ASSIGN_(EachMatcherImpl);
+};
+
// Implements polymorphic Contains(element_matcher).
template <typename M>
class ContainsMatcher {
@@ -2013,6 +2183,23 @@ class ContainsMatcher {
GTEST_DISALLOW_ASSIGN_(ContainsMatcher);
};
+// Implements polymorphic Each(element_matcher).
+template <typename M>
+class EachMatcher {
+ public:
+ explicit EachMatcher(M m) : inner_matcher_(m) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ return MakeMatcher(new EachMatcherImpl<Container>(inner_matcher_));
+ }
+
+ private:
+ const M inner_matcher_;
+
+ GTEST_DISALLOW_ASSIGN_(EachMatcher);
+};
+
// Implements Key(inner_matcher) for the given argument pair type.
// Key(inner_matcher) matches an std::pair whose 'first' field matches
// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an
@@ -2020,7 +2207,7 @@ class ContainsMatcher {
template <typename PairType>
class KeyMatcherImpl : public MatcherInterface<PairType> {
public:
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(PairType)) RawPairType;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType;
typedef typename RawPairType::first_type KeyType;
template <typename InnerMatcher>
@@ -2082,7 +2269,7 @@ class KeyMatcher {
template <typename PairType>
class PairMatcherImpl : public MatcherInterface<PairType> {
public:
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(PairType)) RawPairType;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(PairType) RawPairType;
typedef typename RawPairType::first_type FirstType;
typedef typename RawPairType::second_type SecondType;
@@ -2189,7 +2376,7 @@ class PairMatcher {
template <typename Container>
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
public:
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef internal::StlContainerView<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
@@ -2308,8 +2495,7 @@ class ElementsAreMatcher0 {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -2327,8 +2513,7 @@ class ElementsAreArrayMatcher {
template <typename Container>
operator Matcher<Container>() const {
- typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
- RawContainer;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type::value_type
Element;
@@ -2539,7 +2724,7 @@ inline PolymorphicMatcher<
return MakePolymorphicMatcher(
internal::PropertyMatcher<Class, PropertyType>(
property,
- MatcherCast<GMOCK_REFERENCE_TO_CONST_(PropertyType)>(matcher)));
+ MatcherCast<GTEST_REFERENCE_TO_CONST_(PropertyType)>(matcher)));
// The call to MatcherCast() is required for supporting inner
// matchers of compatible types. For example, it allows
// Property(&Foo::bar, m)
@@ -2823,15 +3008,32 @@ Truly(Predicate pred) {
// values and order differences are not explained.)
template <typename Container>
inline PolymorphicMatcher<internal::ContainerEqMatcher< // NOLINT
- GMOCK_REMOVE_CONST_(Container)> >
+ GTEST_REMOVE_CONST_(Container)> >
ContainerEq(const Container& rhs) {
// This following line is for working around a bug in MSVC 8.0,
// which causes Container to be a const type sometimes.
- typedef GMOCK_REMOVE_CONST_(Container) RawContainer;
+ typedef GTEST_REMOVE_CONST_(Container) RawContainer;
return MakePolymorphicMatcher(
internal::ContainerEqMatcher<RawContainer>(rhs));
}
+// Matches an STL-style container or a native array that contains the
+// same number of elements as in rhs, where its i-th element and rhs's
+// i-th element (as a pair) satisfy the given pair matcher, for all i.
+// TupleMatcher must be able to be safely cast to Matcher<tuple<const
+// T1&, const T2&> >, where T1 and T2 are the types of elements in the
+// LHS container and the RHS container respectively.
+template <typename TupleMatcher, typename Container>
+inline internal::PointwiseMatcher<TupleMatcher,
+ GTEST_REMOVE_CONST_(Container)>
+Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) {
+ // This following line is for working around a bug in MSVC 8.0,
+ // which causes Container to be a const type sometimes.
+ typedef GTEST_REMOVE_CONST_(Container) RawContainer;
+ return internal::PointwiseMatcher<TupleMatcher, RawContainer>(
+ tuple_matcher, rhs);
+}
+
// Matches an STL-style container or a native array that contains at
// least one element matching the given value or matcher.
//
@@ -2855,6 +3057,38 @@ inline internal::ContainsMatcher<M> Contains(M matcher) {
return internal::ContainsMatcher<M>(matcher);
}
+// Matches an STL-style container or a native array that contains only
+// elements matching the given value or matcher.
+//
+// Each(m) is semantically equivalent to Not(Contains(Not(m))). Only
+// the messages are different.
+//
+// Examples:
+// ::std::set<int> page_ids;
+// // Each(m) matches an empty container, regardless of what m is.
+// EXPECT_THAT(page_ids, Each(Eq(1)));
+// EXPECT_THAT(page_ids, Each(Eq(77)));
+//
+// page_ids.insert(3);
+// EXPECT_THAT(page_ids, Each(Gt(0)));
+// EXPECT_THAT(page_ids, Not(Each(Gt(4))));
+// page_ids.insert(1);
+// EXPECT_THAT(page_ids, Not(Each(Lt(2))));
+//
+// ::std::map<int, size_t> page_lengths;
+// page_lengths[1] = 100;
+// page_lengths[2] = 200;
+// page_lengths[3] = 300;
+// EXPECT_THAT(page_lengths, Not(Each(Pair(1, 100))));
+// EXPECT_THAT(page_lengths, Each(Key(Le(3))));
+//
+// const char* user_ids[] = { "joe", "mike", "tom" };
+// EXPECT_THAT(user_ids, Not(Each(Eq(::std::string("tom")))));
+template <typename M>
+inline internal::EachMatcher<M> Each(M matcher) {
+ return internal::EachMatcher<M>(matcher);
+}
+
// Key(inner_matcher) matches an std::pair whose 'first' field matches
// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an
// std::map that contains at least one element whose key is >= 5.
diff --git a/testing/gmock/include/gmock/gmock-more-actions.h b/testing/gmock/include/gmock/gmock-more-actions.h
index 6226392..6d686cd 100644
--- a/testing/gmock/include/gmock/gmock-more-actions.h
+++ b/testing/gmock/include/gmock/gmock-more-actions.h
@@ -162,7 +162,7 @@ ACTION_TEMPLATE(SetArgReferee,
// Ensures that argument #k is a reference. If you get a compiler
// error on the next line, you are using SetArgReferee<k>(value) in
// a mock function whose k-th (0-based) argument is not a reference.
- GMOCK_COMPILE_ASSERT_(internal::is_reference<argk_type>::value,
+ GTEST_COMPILE_ASSERT_(internal::is_reference<argk_type>::value,
SetArgReferee_must_be_used_with_a_reference_argument);
::std::tr1::get<k>(args) = value;
}
@@ -198,7 +198,17 @@ ACTION_TEMPLATE(DeleteArg,
// Action Throw(exception) can be used in a mock function of any type
// to throw the given exception. Any copyable value can be thrown.
#if GTEST_HAS_EXCEPTIONS
+
+// Suppresses the 'unreachable code' warning that VC generates in opt modes.
+#ifdef _MSC_VER
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4702) // Temporarily disables warning 4702.
+#endif
ACTION_P(Throw, exception) { throw exception; }
+#ifdef _MSC_VER
+#pragma warning(pop) // Restores the warning state.
+#endif
+
#endif // GTEST_HAS_EXCEPTIONS
#ifdef _MSC_VER
diff --git a/testing/gmock/include/gmock/gmock-printers.h b/testing/gmock/include/gmock/gmock-printers.h
deleted file mode 100644
index d1cd03c..0000000
--- a/testing/gmock/include/gmock/gmock-printers.h
+++ /dev/null
@@ -1,725 +0,0 @@
-// Copyright 2007, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Google Mock - a framework for writing C++ mock classes.
-//
-// This file implements a universal value printer that can print a
-// value of any type T:
-//
-// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
-//
-// A user can teach this function how to print a class type T by
-// defining either operator<<() or PrintTo() in the namespace that
-// defines T. More specifically, the FIRST defined function in the
-// following list will be used (assuming T is defined in namespace
-// foo):
-//
-// 1. foo::PrintTo(const T&, ostream*)
-// 2. operator<<(ostream&, const T&) defined in either foo or the
-// global namespace.
-//
-// If none of the above is defined, it will print the debug string of
-// the value if it is a protocol buffer, or print the raw bytes in the
-// value otherwise.
-//
-// To aid debugging: when T is a reference type, the address of the
-// value is also printed; when T is a (const) char pointer, both the
-// pointer value and the NUL-terminated string it points to are
-// printed.
-//
-// We also provide some convenient wrappers:
-//
-// // Prints a value to a string. For a (const or not) char
-// // pointer, the NUL-terminated string (but not the pointer) is
-// // printed.
-// std::string ::testing::PrintToString(const T& value);
-//
-// // Prints a value tersely: for a reference type, the referenced
-// // value (but not the address) is printed; for a (const or not) char
-// // pointer, the NUL-terminated string (but not the pointer) is
-// // printed.
-// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
-//
-// // Prints value using the type inferred by the compiler. The difference
-// // from UniversalTersePrint() is that this function prints both the
-// // pointer and the NUL-terminated string for a (const or not) char pointer.
-// void ::testing::internal::UniversalPrint(const T& value, ostream*);
-//
-// // Prints the fields of a tuple tersely to a string vector, one
-// // element for each field.
-// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
-// const Tuple& value);
-//
-// Known limitation:
-//
-// The print primitives print the elements of an STL-style container
-// using the compiler-inferred type of *iter where iter is a
-// const_iterator of the container. When const_iterator is an input
-// iterator but not a forward iterator, this inferred type may not
-// match value_type, and the print output may be incorrect. In
-// practice, this is rarely a problem as for most containers
-// const_iterator is a forward iterator. We'll fix this if there's an
-// actual need for it. Note that this fix cannot rely on value_type
-// being defined as many user-defined container types don't have
-// value_type.
-
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_
-
-#include <ostream> // NOLINT
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <gmock/internal/gmock-internal-utils.h>
-#include <gmock/internal/gmock-port.h>
-#include <gtest/gtest.h>
-
-namespace testing {
-
-// Definitions in the 'internal' and 'internal2' name spaces are
-// subject to change without notice. DO NOT USE THEM IN USER CODE!
-namespace internal2 {
-
-// Prints the given number of bytes in the given object to the given
-// ostream.
-void PrintBytesInObjectTo(const unsigned char* obj_bytes,
- size_t count,
- ::std::ostream* os);
-
-// TypeWithoutFormatter<T, kIsProto>::PrintValue(value, os) is called
-// by the universal printer to print a value of type T when neither
-// operator<< nor PrintTo() is defined for type T. When T is
-// ProtocolMessage, proto2::Message, or a subclass of those, kIsProto
-// will be true and the short debug string of the protocol message
-// value will be printed; otherwise kIsProto will be false and the
-// bytes in the value will be printed.
-template <typename T, bool kIsProto>
-class TypeWithoutFormatter {
- public:
- static void PrintValue(const T& value, ::std::ostream* os) {
- PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
- sizeof(value), os);
- }
-};
-
-// We print a protobuf using its ShortDebugString() when the string
-// doesn't exceed this many characters; otherwise we print it using
-// DebugString() for better readability.
-const size_t kProtobufOneLinerMaxLength = 50;
-
-template <typename T>
-class TypeWithoutFormatter<T, true> {
- public:
- static void PrintValue(const T& value, ::std::ostream* os) {
- const ::testing::internal::string short_str = value.ShortDebugString();
- const ::testing::internal::string pretty_str =
- short_str.length() <= kProtobufOneLinerMaxLength ?
- short_str : ("\n" + value.DebugString());
- ::std::operator<<(*os, "<" + pretty_str + ">");
- }
-};
-
-// Prints the given value to the given ostream. If the value is a
-// protocol message, its short debug string is printed; otherwise the
-// bytes in the value are printed. This is what
-// UniversalPrinter<T>::Print() does when it knows nothing about type
-// T and T has no << operator.
-//
-// A user can override this behavior for a class type Foo by defining
-// a << operator in the namespace where Foo is defined.
-//
-// We put this operator in namespace 'internal2' instead of 'internal'
-// to simplify the implementation, as much code in 'internal' needs to
-// use << in STL, which would conflict with our own << were it defined
-// in 'internal'.
-//
-// Note that this operator<< takes a generic std::basic_ostream<Char,
-// CharTraits> type instead of the more restricted std::ostream. If
-// we define it to take an std::ostream instead, we'll get an
-// "ambiguous overloads" compiler error when trying to print a type
-// Foo that supports streaming to std::basic_ostream<Char,
-// CharTraits>, as the compiler cannot tell whether
-// operator<<(std::ostream&, const T&) or
-// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
-// specific.
-template <typename Char, typename CharTraits, typename T>
-::std::basic_ostream<Char, CharTraits>& operator<<(
- ::std::basic_ostream<Char, CharTraits>& os, const T& x) {
- TypeWithoutFormatter<T, ::testing::internal::IsAProtocolMessage<T>::value>::
- PrintValue(x, &os);
- return os;
-}
-
-} // namespace internal2
-} // namespace testing
-
-// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
-// magic needed for implementing UniversalPrinter won't work.
-namespace testing_internal {
-
-// Used to print a value that is not an STL-style container when the
-// user doesn't define PrintTo() for it.
-template <typename T>
-void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
- // With the following statement, during unqualified name lookup,
- // testing::internal2::operator<< appears as if it was declared in
- // the nearest enclosing namespace that contains both
- // ::testing_internal and ::testing::internal2, i.e. the global
- // namespace. For more details, refer to the C++ Standard section
- // 7.3.4-1 [namespace.udir]. This allows us to fall back onto
- // testing::internal2::operator<< in case T doesn't come with a <<
- // operator.
- //
- // We cannot write 'using ::testing::internal2::operator<<;', which
- // gcc 3.3 fails to compile due to a compiler bug.
- using namespace ::testing::internal2; // NOLINT
-
- // Assuming T is defined in namespace foo, in the next statement,
- // the compiler will consider all of:
- //
- // 1. foo::operator<< (thanks to Koenig look-up),
- // 2. ::operator<< (as the current namespace is enclosed in ::),
- // 3. testing::internal2::operator<< (thanks to the using statement above).
- //
- // The operator<< whose type matches T best will be picked.
- //
- // We deliberately allow #2 to be a candidate, as sometimes it's
- // impossible to define #1 (e.g. when foo is ::std, defining
- // anything in it is undefined behavior unless you are a compiler
- // vendor.).
- *os << value;
-}
-
-} // namespace testing_internal
-
-namespace testing {
-namespace internal {
-
-// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
-// value to the given ostream. The caller must ensure that
-// 'ostream_ptr' is not NULL, or the behavior is undefined.
-//
-// We define UniversalPrinter as a class template (as opposed to a
-// function template), as we need to partially specialize it for
-// reference types, which cannot be done with function templates.
-template <typename T>
-class UniversalPrinter;
-
-template <typename T>
-void UniversalPrint(const T& value, ::std::ostream* os);
-
-// Used to print an STL-style container when the user doesn't define
-// a PrintTo() for it.
-template <typename C>
-void DefaultPrintTo(IsContainer /* dummy */,
- false_type /* is not a pointer */,
- const C& container, ::std::ostream* os) {
- const size_t kMaxCount = 32; // The maximum number of elements to print.
- *os << '{';
- size_t count = 0;
- for (typename C::const_iterator it = container.begin();
- it != container.end(); ++it, ++count) {
- if (count > 0) {
- *os << ',';
- if (count == kMaxCount) { // Enough has been printed.
- *os << " ...";
- break;
- }
- }
- *os << ' ';
- // We cannot call PrintTo(*it, os) here as PrintTo() doesn't
- // handle *it being a native array.
- internal::UniversalPrint(*it, os);
- }
-
- if (count > 0) {
- *os << ' ';
- }
- *os << '}';
-}
-
-// Used to print a pointer that is neither a char pointer nor a member
-// pointer, when the user doesn't define PrintTo() for it. (A member
-// variable pointer or member function pointer doesn't really point to
-// a location in the address space. Their representation is
-// implementation-defined. Therefore they will be printed as raw
-// bytes.)
-template <typename T>
-void DefaultPrintTo(IsNotContainer /* dummy */,
- true_type /* is a pointer */,
- T* p, ::std::ostream* os) {
- if (p == NULL) {
- *os << "NULL";
- } else {
- // We want to print p as a const void*. However, we cannot cast
- // it to const void* directly, even using reinterpret_cast, as
- // earlier versions of gcc (e.g. 3.4.5) cannot compile the cast
- // when p is a function pointer. Casting to UInt64 first solves
- // the problem.
- *os << reinterpret_cast<const void*>(reinterpret_cast<internal::UInt64>(p));
- }
-}
-
-// Used to print a non-container, non-pointer value when the user
-// doesn't define PrintTo() for it.
-template <typename T>
-void DefaultPrintTo(IsNotContainer /* dummy */,
- false_type /* is not a pointer */,
- const T& value, ::std::ostream* os) {
- ::testing_internal::DefaultPrintNonContainerTo(value, os);
-}
-
-// Prints the given value using the << operator if it has one;
-// otherwise prints the bytes in it. This is what
-// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
-// or overloaded for type T.
-//
-// A user can override this behavior for a class type Foo by defining
-// an overload of PrintTo() in the namespace where Foo is defined. We
-// give the user this option as sometimes defining a << operator for
-// Foo is not desirable (e.g. the coding style may prevent doing it,
-// or there is already a << operator but it doesn't do what the user
-// wants).
-template <typename T>
-void PrintTo(const T& value, ::std::ostream* os) {
- // DefaultPrintTo() is overloaded. The type of its first two
- // arguments determine which version will be picked. If T is an
- // STL-style container, the version for container will be called; if
- // T is a pointer, the pointer version will be called; otherwise the
- // generic version will be called.
- //
- // Note that we check for container types here, prior to we check
- // for protocol message types in our operator<<. The rationale is:
- //
- // For protocol messages, we want to give people a chance to
- // override Google Mock's format by defining a PrintTo() or
- // operator<<. For STL containers, other formats can be
- // incompatible with Google Mock's format for the container
- // elements; therefore we check for container types here to ensure
- // that our format is used.
- //
- // The second argument of DefaultPrintTo() is needed to bypass a bug
- // in Symbian's C++ compiler that prevents it from picking the right
- // overload between:
- //
- // PrintTo(const T& x, ...);
- // PrintTo(T* x, ...);
- DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
-}
-
-// The following list of PrintTo() overloads tells
-// UniversalPrinter<T>::Print() how to print standard types (built-in
-// types, strings, plain arrays, and pointers).
-
-// Overloads for various char types.
-void PrintCharTo(char c, int char_code, ::std::ostream* os);
-inline void PrintTo(unsigned char c, ::std::ostream* os) {
- PrintCharTo(c, c, os);
-}
-inline void PrintTo(signed char c, ::std::ostream* os) {
- PrintCharTo(c, c, os);
-}
-inline void PrintTo(char c, ::std::ostream* os) {
- // When printing a plain char, we always treat it as unsigned. This
- // way, the output won't be affected by whether the compiler thinks
- // char is signed or not.
- PrintTo(static_cast<unsigned char>(c), os);
-}
-
-// Overloads for other simple built-in types.
-inline void PrintTo(bool x, ::std::ostream* os) {
- *os << (x ? "true" : "false");
-}
-
-// Overload for wchar_t type.
-// Prints a wchar_t as a symbol if it is printable or as its internal
-// code otherwise and also as its decimal code (except for L'\0').
-// The L'\0' char is printed as "L'\\0'". The decimal code is printed
-// as signed integer when wchar_t is implemented by the compiler
-// as a signed type and is printed as an unsigned integer when wchar_t
-// is implemented as an unsigned type.
-void PrintTo(wchar_t wc, ::std::ostream* os);
-
-// Overloads for C strings.
-void PrintTo(const char* s, ::std::ostream* os);
-inline void PrintTo(char* s, ::std::ostream* os) {
- PrintTo(implicit_cast<const char*>(s), os);
-}
-
-// MSVC can be configured to define wchar_t as a typedef of unsigned
-// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
-// type. When wchar_t is a typedef, defining an overload for const
-// wchar_t* would cause unsigned short* be printed as a wide string,
-// possibly causing invalid memory accesses.
-#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
-// Overloads for wide C strings
-void PrintTo(const wchar_t* s, ::std::ostream* os);
-inline void PrintTo(wchar_t* s, ::std::ostream* os) {
- PrintTo(implicit_cast<const wchar_t*>(s), os);
-}
-#endif
-
-// Overload for C arrays. Multi-dimensional arrays are printed
-// properly.
-
-// Prints the given number of elements in an array, without printing
-// the curly braces.
-template <typename T>
-void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
- UniversalPrinter<T>::Print(a[0], os);
- for (size_t i = 1; i != count; i++) {
- *os << ", ";
- UniversalPrinter<T>::Print(a[i], os);
- }
-}
-
-// Overloads for ::string and ::std::string.
-#if GTEST_HAS_GLOBAL_STRING
-void PrintStringTo(const ::string&s, ::std::ostream* os);
-inline void PrintTo(const ::string& s, ::std::ostream* os) {
- PrintStringTo(s, os);
-}
-#endif // GTEST_HAS_GLOBAL_STRING
-
-void PrintStringTo(const ::std::string&s, ::std::ostream* os);
-inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
- PrintStringTo(s, os);
-}
-
-// Overloads for ::wstring and ::std::wstring.
-#if GTEST_HAS_GLOBAL_WSTRING
-void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
-inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
- PrintWideStringTo(s, os);
-}
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-#if GTEST_HAS_STD_WSTRING
-void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
-inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
- PrintWideStringTo(s, os);
-}
-#endif // GTEST_HAS_STD_WSTRING
-
-// Overload for ::std::tr1::tuple. Needed for printing function
-// arguments, which are packed as tuples.
-
-// Helper function for printing a tuple. T must be instantiated with
-// a tuple type.
-template <typename T>
-void PrintTupleTo(const T& t, ::std::ostream* os);
-
-// Overloaded PrintTo() for tuples of various arities. We support
-// tuples of up-to 10 fields. The following implementation works
-// regardless of whether tr1::tuple is implemented using the
-// non-standard variadic template feature or not.
-
-inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1>
-void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2>
-void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-void PrintTo(
- const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
- ::std::ostream* os) {
- PrintTupleTo(t, os);
-}
-
-// Overload for std::pair.
-template <typename T1, typename T2>
-void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
- *os << '(';
- UniversalPrinter<T1>::Print(value.first, os);
- *os << ", ";
- UniversalPrinter<T2>::Print(value.second, os);
- *os << ')';
-}
-
-// Implements printing a non-reference type T by letting the compiler
-// pick the right overload of PrintTo() for T.
-template <typename T>
-class UniversalPrinter {
- public:
- // MSVC warns about adding const to a function type, so we want to
- // disable the warning.
-#ifdef _MSC_VER
-#pragma warning(push) // Saves the current warning state.
-#pragma warning(disable:4180) // Temporarily disables warning 4180.
-#endif // _MSC_VER
-
- // Note: we deliberately don't call this PrintTo(), as that name
- // conflicts with ::testing::internal::PrintTo in the body of the
- // function.
- static void Print(const T& value, ::std::ostream* os) {
- // By default, ::testing::internal::PrintTo() is used for printing
- // the value.
- //
- // Thanks to Koenig look-up, if T is a class and has its own
- // PrintTo() function defined in its namespace, that function will
- // be visible here. Since it is more specific than the generic ones
- // in ::testing::internal, it will be picked by the compiler in the
- // following statement - exactly what we want.
- PrintTo(value, os);
- }
-
-#ifdef _MSC_VER
-#pragma warning(pop) // Restores the warning state.
-#endif // _MSC_VER
-};
-
-// UniversalPrintArray(begin, len, os) prints an array of 'len'
-// elements, starting at address 'begin'.
-template <typename T>
-void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
- if (len == 0) {
- *os << "{}";
- } else {
- *os << "{ ";
- const size_t kThreshold = 18;
- const size_t kChunkSize = 8;
- // If the array has more than kThreshold elements, we'll have to
- // omit some details by printing only the first and the last
- // kChunkSize elements.
- // TODO(wan@google.com): let the user control the threshold using a flag.
- if (len <= kThreshold) {
- PrintRawArrayTo(begin, len, os);
- } else {
- PrintRawArrayTo(begin, kChunkSize, os);
- *os << ", ..., ";
- PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
- }
- *os << " }";
- }
-}
-// This overload prints a (const) char array compactly.
-void UniversalPrintArray(const char* begin, size_t len, ::std::ostream* os);
-
-// Implements printing an array type T[N].
-template <typename T, size_t N>
-class UniversalPrinter<T[N]> {
- public:
- // Prints the given array, omitting some elements when there are too
- // many.
- static void Print(const T (&a)[N], ::std::ostream* os) {
- UniversalPrintArray(a, N, os);
- }
-};
-
-// Implements printing a reference type T&.
-template <typename T>
-class UniversalPrinter<T&> {
- public:
- // MSVC warns about adding const to a function type, so we want to
- // disable the warning.
-#ifdef _MSC_VER
-#pragma warning(push) // Saves the current warning state.
-#pragma warning(disable:4180) // Temporarily disables warning 4180.
-#endif // _MSC_VER
-
- static void Print(const T& value, ::std::ostream* os) {
- // Prints the address of the value. We use reinterpret_cast here
- // as static_cast doesn't compile when T is a function type.
- *os << "@" << reinterpret_cast<const void*>(&value) << " ";
-
- // Then prints the value itself.
- UniversalPrinter<T>::Print(value, os);
- }
-
-#ifdef _MSC_VER
-#pragma warning(pop) // Restores the warning state.
-#endif // _MSC_VER
-};
-
-// Prints a value tersely: for a reference type, the referenced value
-// (but not the address) is printed; for a (const) char pointer, the
-// NUL-terminated string (but not the pointer) is printed.
-template <typename T>
-void UniversalTersePrint(const T& value, ::std::ostream* os) {
- UniversalPrinter<T>::Print(value, os);
-}
-inline void UniversalTersePrint(const char* str, ::std::ostream* os) {
- if (str == NULL) {
- *os << "NULL";
- } else {
- UniversalPrinter<string>::Print(string(str), os);
- }
-}
-inline void UniversalTersePrint(char* str, ::std::ostream* os) {
- UniversalTersePrint(static_cast<const char*>(str), os);
-}
-
-// Prints a value using the type inferred by the compiler. The
-// difference between this and UniversalTersePrint() is that for a
-// (const) char pointer, this prints both the pointer and the
-// NUL-terminated string.
-template <typename T>
-void UniversalPrint(const T& value, ::std::ostream* os) {
- UniversalPrinter<T>::Print(value, os);
-}
-
-typedef ::std::vector<string> Strings;
-
-// This helper template allows PrintTo() for tuples and
-// UniversalTersePrintTupleFieldsToStrings() to be defined by
-// induction on the number of tuple fields. The idea is that
-// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
-// fields in tuple t, and can be defined in terms of
-// TuplePrefixPrinter<N - 1>.
-
-// The inductive case.
-template <size_t N>
-struct TuplePrefixPrinter {
- // Prints the first N fields of a tuple.
- template <typename Tuple>
- static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
- TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
- *os << ", ";
- UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
- ::Print(::std::tr1::get<N - 1>(t), os);
- }
-
- // Tersely prints the first N fields of a tuple to a string vector,
- // one element for each field.
- template <typename Tuple>
- static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
- TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
- ::std::stringstream ss;
- UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
- strings->push_back(ss.str());
- }
-};
-
-// Base cases.
-template <>
-struct TuplePrefixPrinter<0> {
- template <typename Tuple>
- static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
-
- template <typename Tuple>
- static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
-};
-template <>
-template <typename Tuple>
-void TuplePrefixPrinter<1>::PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
- UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
- Print(::std::tr1::get<0>(t), os);
-}
-
-// Helper function for printing a tuple. T must be instantiated with
-// a tuple type.
-template <typename T>
-void PrintTupleTo(const T& t, ::std::ostream* os) {
- *os << "(";
- TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
- PrintPrefixTo(t, os);
- *os << ")";
-}
-
-// Prints the fields of a tuple tersely to a string vector, one
-// element for each field. See the comment before
-// UniversalTersePrint() for how we define "tersely".
-template <typename Tuple>
-Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
- Strings result;
- TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
- TersePrintPrefixToStrings(value, &result);
- return result;
-}
-
-} // namespace internal
-
-template <typename T>
-::std::string PrintToString(const T& value) {
- ::std::stringstream ss;
- internal::UniversalTersePrint(value, &ss);
- return ss.str();
-}
-
-} // namespace testing
-
-#endif // GMOCK_INCLUDE_GMOCK_GMOCK_PRINTERS_H_
diff --git a/testing/gmock/include/gmock/gmock-spec-builders.h b/testing/gmock/include/gmock/gmock-spec-builders.h
index 74a095d..7038c2e 100644
--- a/testing/gmock/include/gmock/gmock-spec-builders.h
+++ b/testing/gmock/include/gmock/gmock-spec-builders.h
@@ -69,7 +69,6 @@
#include <gmock/gmock-actions.h>
#include <gmock/gmock-cardinalities.h>
#include <gmock/gmock-matchers.h>
-#include <gmock/gmock-printers.h>
#include <gmock/internal/gmock-internal-utils.h>
#include <gmock/internal/gmock-port.h>
#include <gtest/gtest.h>
@@ -1269,6 +1268,7 @@ class ActionResultHolder {
// Prints the held value as an action's result to os.
void PrintAsActionResult(::std::ostream* os) const {
*os << "\n Returns: ";
+ // T may be a reference type, so we don't use UniversalPrint().
UniversalPrinter<T>::Print(value_, os);
}
@@ -1540,7 +1540,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
*os << "Uninteresting mock function call - ";
DescribeDefaultActionTo(args, os);
*os << " Function call: " << Name();
- UniversalPrinter<ArgumentTuple>::Print(args, os);
+ UniversalPrint(args, os);
}
// Critical section: We must find the matching expectation and the
@@ -1776,7 +1776,7 @@ typename Function<F>::Result FunctionMockerBase<F>::InvokeWith(
}
ss << " Function call: " << Name();
- UniversalPrinter<ArgumentTuple>::Print(args, &ss);
+ UniversalPrint(args, &ss);
// In case the action deletes a piece of the expectation, we
// generate the message beforehand.
diff --git a/testing/gmock/include/gmock/gmock.h b/testing/gmock/include/gmock/gmock.h
index daf5288..e3d5fd8 100644
--- a/testing/gmock/include/gmock/gmock.h
+++ b/testing/gmock/include/gmock/gmock.h
@@ -63,7 +63,6 @@
#include <gmock/gmock-more-actions.h>
#include <gmock/gmock-generated-nice-strict.h>
#include <gmock/gmock-matchers.h>
-#include <gmock/gmock-printers.h>
#include <gmock/internal/gmock-internal-utils.h>
namespace testing {
diff --git a/testing/gmock/include/gmock/internal/gmock-internal-utils.h b/testing/gmock/include/gmock/internal/gmock-internal-utils.h
index 0c33fdd..69a2338 100644
--- a/testing/gmock/include/gmock/internal/gmock-internal-utils.h
+++ b/testing/gmock/include/gmock/internal/gmock-internal-utils.h
@@ -57,9 +57,6 @@
#define GMOCK_ATTRIBUTE_UNUSED_
#endif // __GNUC__
-class ProtocolMessage;
-namespace proto2 { class Message; }
-
namespace testing {
namespace internal {
@@ -69,77 +66,6 @@ namespace internal {
// "foo_bar_123" are converted to "foo bar 123".
string ConvertIdentifierNameToWords(const char* id_name);
-// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
-// compiler error iff T1 and T2 are different types.
-template <typename T1, typename T2>
-struct CompileAssertTypesEqual;
-
-template <typename T>
-struct CompileAssertTypesEqual<T, T> {
-};
-
-// Removes the reference from a type if it is a reference type,
-// otherwise leaves it unchanged. This is the same as
-// tr1::remove_reference, which is not widely available yet.
-template <typename T>
-struct RemoveReference { typedef T type; }; // NOLINT
-template <typename T>
-struct RemoveReference<T&> { typedef T type; }; // NOLINT
-
-// A handy wrapper around RemoveReference that works when the argument
-// T depends on template parameters.
-#define GMOCK_REMOVE_REFERENCE_(T) \
- typename ::testing::internal::RemoveReference<T>::type
-
-// Removes const from a type if it is a const type, otherwise leaves
-// it unchanged. This is the same as tr1::remove_const, which is not
-// widely available yet.
-template <typename T>
-struct RemoveConst { typedef T type; }; // NOLINT
-template <typename T>
-struct RemoveConst<const T> { typedef T type; }; // NOLINT
-
-// MSVC 8.0 has a bug which causes the above definition to fail to
-// remove the const in 'const int[3]'. The following specialization
-// works around the bug. However, it causes trouble with gcc and thus
-// needs to be conditionally compiled.
-#ifdef _MSC_VER
-template <typename T, size_t N>
-struct RemoveConst<T[N]> {
- typedef typename RemoveConst<T>::type type[N];
-};
-#endif // _MSC_VER
-
-// A handy wrapper around RemoveConst that works when the argument
-// T depends on template parameters.
-#define GMOCK_REMOVE_CONST_(T) \
- typename ::testing::internal::RemoveConst<T>::type
-
-// Adds reference to a type if it is not a reference type,
-// otherwise leaves it unchanged. This is the same as
-// tr1::add_reference, which is not widely available yet.
-template <typename T>
-struct AddReference { typedef T& type; }; // NOLINT
-template <typename T>
-struct AddReference<T&> { typedef T& type; }; // NOLINT
-
-// A handy wrapper around AddReference that works when the argument T
-// depends on template parameters.
-#define GMOCK_ADD_REFERENCE_(T) \
- typename ::testing::internal::AddReference<T>::type
-
-// Adds a reference to const on top of T as necessary. For example,
-// it transforms
-//
-// char ==> const char&
-// const char ==> const char&
-// char& ==> const char&
-// const char& ==> const char&
-//
-// The argument T must depend on some template parameters.
-#define GMOCK_REFERENCE_TO_CONST_(T) \
- GMOCK_ADD_REFERENCE_(const GMOCK_REMOVE_REFERENCE_(T))
-
// PointeeOf<Pointer>::type is the type of a value pointed to by a
// Pointer, which can be either a smart pointer or a raw pointer. The
// following default implementation is for the case where Pointer is a
@@ -174,53 +100,6 @@ struct LinkedPtrLessThan {
}
};
-// ImplicitlyConvertible<From, To>::value is a compile-time bool
-// constant that's true iff type From can be implicitly converted to
-// type To.
-template <typename From, typename To>
-class ImplicitlyConvertible {
- private:
- // We need the following helper functions only for their types.
- // They have no implementations.
-
- // MakeFrom() is an expression whose type is From. We cannot simply
- // use From(), as the type From may not have a public default
- // constructor.
- static From MakeFrom();
-
- // These two functions are overloaded. Given an expression
- // Helper(x), the compiler will pick the first version if x can be
- // implicitly converted to type To; otherwise it will pick the
- // second version.
- //
- // The first version returns a value of size 1, and the second
- // version returns a value of size 2. Therefore, by checking the
- // size of Helper(x), which can be done at compile time, we can tell
- // which version of Helper() is used, and hence whether x can be
- // implicitly converted to type To.
- static char Helper(To);
- static char (&Helper(...))[2]; // NOLINT
-
- // We have to put the 'public' section after the 'private' section,
- // or MSVC refuses to compile the code.
- public:
- // MSVC warns about implicitly converting from double to int for
- // possible loss of data, so we need to temporarily disable the
- // warning.
-#ifdef _MSC_VER
-#pragma warning(push) // Saves the current warning state.
-#pragma warning(disable:4244) // Temporarily disables warning 4244.
- static const bool value =
- sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
-#pragma warning(pop) // Restores the warning state.
-#else
- static const bool value =
- sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
-#endif // _MSV_VER
-};
-template <typename From, typename To>
-const bool ImplicitlyConvertible<From, To>::value;
-
// Symbian compilation can be done with wchar_t being either a native
// type or a typedef. Using Google Mock with OpenC without wchar_t
// should require the definition of _STLP_NO_WCHAR_T.
@@ -385,32 +264,6 @@ struct LosslessArithmeticConvertible
: public LosslessArithmeticConvertibleImpl<
GMOCK_KIND_OF_(From), From, GMOCK_KIND_OF_(To), To> {}; // NOLINT
-// IsAProtocolMessage<T>::value is a compile-time bool constant that's
-// true iff T is type ProtocolMessage, proto2::Message, or a subclass
-// of those.
-template <typename T>
-struct IsAProtocolMessage
- : public bool_constant<
- ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
- ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
-};
-
-// When the compiler sees expression IsContainerTest<C>(0), the first
-// overload of IsContainerTest will be picked if C is an STL-style
-// container class (since C::const_iterator* is a valid type and 0 can
-// be converted to it), while the second overload will be picked
-// otherwise (since C::const_iterator will be an invalid type in this
-// case). Therefore, we can determine whether C is a container class
-// by checking the type of IsContainerTest<C>(0). The value of the
-// expression is insignificant.
-typedef int IsContainer;
-template <class C>
-IsContainer IsContainerTest(typename C::const_iterator*) { return 0; }
-
-typedef char IsNotContainer;
-template <class C>
-IsNotContainer IsContainerTest(...) { return '\0'; }
-
// This interface knows how to report a Google Mock failure (either
// non-fatal or fatal).
class FailureReporterInterface {
@@ -514,149 +367,6 @@ inline T Invalid() {
template <>
inline void Invalid<void>() {}
-// Utilities for native arrays.
-
-// ArrayEq() compares two k-dimensional native arrays using the
-// elements' operator==, where k can be any integer >= 0. When k is
-// 0, ArrayEq() degenerates into comparing a single pair of values.
-
-template <typename T, typename U>
-bool ArrayEq(const T* lhs, size_t size, const U* rhs);
-
-// This generic version is used when k is 0.
-template <typename T, typename U>
-inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
-
-// This overload is used when k >= 1.
-template <typename T, typename U, size_t N>
-inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
- return internal::ArrayEq(lhs, N, rhs);
-}
-
-// This helper reduces code bloat. If we instead put its logic inside
-// the previous ArrayEq() function, arrays with different sizes would
-// lead to different copies of the template code.
-template <typename T, typename U>
-bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
- for (size_t i = 0; i != size; i++) {
- if (!internal::ArrayEq(lhs[i], rhs[i]))
- return false;
- }
- return true;
-}
-
-// Finds the first element in the iterator range [begin, end) that
-// equals elem. Element may be a native array type itself.
-template <typename Iter, typename Element>
-Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
- for (Iter it = begin; it != end; ++it) {
- if (internal::ArrayEq(*it, elem))
- return it;
- }
- return end;
-}
-
-// CopyArray() copies a k-dimensional native array using the elements'
-// operator=, where k can be any integer >= 0. When k is 0,
-// CopyArray() degenerates into copying a single value.
-
-template <typename T, typename U>
-void CopyArray(const T* from, size_t size, U* to);
-
-// This generic version is used when k is 0.
-template <typename T, typename U>
-inline void CopyArray(const T& from, U* to) { *to = from; }
-
-// This overload is used when k >= 1.
-template <typename T, typename U, size_t N>
-inline void CopyArray(const T(&from)[N], U(*to)[N]) {
- internal::CopyArray(from, N, *to);
-}
-
-// This helper reduces code bloat. If we instead put its logic inside
-// the previous CopyArray() function, arrays with different sizes
-// would lead to different copies of the template code.
-template <typename T, typename U>
-void CopyArray(const T* from, size_t size, U* to) {
- for (size_t i = 0; i != size; i++) {
- internal::CopyArray(from[i], to + i);
- }
-}
-
-// The relation between an NativeArray object (see below) and the
-// native array it represents.
-enum RelationToSource {
- kReference, // The NativeArray references the native array.
- kCopy // The NativeArray makes a copy of the native array and
- // owns the copy.
-};
-
-// Adapts a native array to a read-only STL-style container. Instead
-// of the complete STL container concept, this adaptor only implements
-// members useful for Google Mock's container matchers. New members
-// should be added as needed. To simplify the implementation, we only
-// support Element being a raw type (i.e. having no top-level const or
-// reference modifier). It's the client's responsibility to satisfy
-// this requirement. Element can be an array type itself (hence
-// multi-dimensional arrays are supported).
-template <typename Element>
-class NativeArray {
- public:
- // STL-style container typedefs.
- typedef Element value_type;
- typedef const Element* const_iterator;
-
- // Constructs from a native array.
- NativeArray(const Element* array, size_t count, RelationToSource relation) {
- Init(array, count, relation);
- }
-
- // Copy constructor.
- NativeArray(const NativeArray& rhs) {
- Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
- }
-
- ~NativeArray() {
- // Ensures that the user doesn't instantiate NativeArray with a
- // const or reference type.
- testing::StaticAssertTypeEq<Element,
- GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Element))>();
- if (relation_to_source_ == kCopy)
- delete[] array_;
- }
-
- // STL-style container methods.
- size_t size() const { return size_; }
- const_iterator begin() const { return array_; }
- const_iterator end() const { return array_ + size_; }
- bool operator==(const NativeArray& rhs) const {
- return size() == rhs.size() &&
- ArrayEq(begin(), size(), rhs.begin());
- }
-
- private:
- // Not implemented as we don't want to support assignment.
- void operator=(const NativeArray& rhs);
-
- // Initializes this object; makes a copy of the input array if
- // 'relation' is kCopy.
- void Init(const Element* array, size_t a_size, RelationToSource relation) {
- if (relation == kReference) {
- array_ = array;
- } else {
- Element* const copy = new Element[a_size];
- CopyArray(array, a_size, copy);
- array_ = copy;
- }
- size_ = a_size;
- relation_to_source_ = relation;
- }
-
- const Element* array_;
- size_t size_;
- RelationToSource relation_to_source_;
-};
-
// Given a raw type (i.e. having no top-level reference or const
// modifier) RawContainer that's either an STL-style container or a
// native array, class StlContainerView<RawContainer> has the
@@ -682,7 +392,7 @@ class StlContainerView {
static const_reference ConstReference(const RawContainer& container) {
// Ensures that RawContainer is not a const type.
testing::StaticAssertTypeEq<RawContainer,
- GMOCK_REMOVE_CONST_(RawContainer)>();
+ GTEST_REMOVE_CONST_(RawContainer)>();
return container;
}
static type Copy(const RawContainer& container) { return container; }
@@ -692,7 +402,7 @@ class StlContainerView {
template <typename Element, size_t N>
class StlContainerView<Element[N]> {
public:
- typedef GMOCK_REMOVE_CONST_(Element) RawElement;
+ typedef GTEST_REMOVE_CONST_(Element) RawElement;
typedef internal::NativeArray<RawElement> type;
// NativeArray<T> can represent a native array either by value or by
// reference (selected by a constructor argument), so 'const type'
@@ -737,7 +447,7 @@ class StlContainerView<Element[N]> {
template <typename ElementPointer, typename Size>
class StlContainerView< ::std::tr1::tuple<ElementPointer, Size> > {
public:
- typedef GMOCK_REMOVE_CONST_(
+ typedef GTEST_REMOVE_CONST_(
typename internal::PointeeOf<ElementPointer>::type) RawElement;
typedef internal::NativeArray<RawElement> type;
typedef const type const_reference;
diff --git a/testing/gmock/include/gmock/internal/gmock-port.h b/testing/gmock/include/gmock/internal/gmock-port.h
index 30115f2..b644eb4 100644
--- a/testing/gmock/include/gmock/internal/gmock-port.h
+++ b/testing/gmock/include/gmock/internal/gmock-port.h
@@ -50,149 +50,12 @@
// tr1/tuple. gmock-port.h does this via gtest-port.h, which is
// guaranteed to pull in the tuple header.
-#if GTEST_OS_LINUX
-
-#endif // GTEST_OS_LINUX
-
-namespace testing {
-namespace internal {
-
// For MS Visual C++, check the compiler version. At least VS 2003 is
// required to compile Google Mock.
#if defined(_MSC_VER) && _MSC_VER < 1310
#error "At least Visual C++ 2003 (7.1) is required to compile Google Mock."
#endif
-// Use implicit_cast as a safe version of static_cast for upcasting in
-// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
-// const Foo*). When you use implicit_cast, the compiler checks that
-// the cast is safe. Such explicit implicit_casts are necessary in
-// surprisingly many situations where C++ demands an exact type match
-// instead of an argument type convertable to a target type.
-//
-// The syntax for using implicit_cast is the same as for static_cast:
-//
-// implicit_cast<ToType>(expr)
-//
-// implicit_cast would have been part of the C++ standard library,
-// but the proposal was submitted too late. It will probably make
-// its way into the language in the future.
-template<typename To>
-inline To implicit_cast(To x) { return x; }
-
-// When you upcast (that is, cast a pointer from type Foo to type
-// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
-// always succeed. When you downcast (that is, cast a pointer from
-// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
-// how do you know the pointer is really of type SubclassOfFoo? It
-// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
-// when you downcast, you should use this macro. In debug mode, we
-// use dynamic_cast<> to double-check the downcast is legal (we die
-// if it's not). In normal mode, we do the efficient static_cast<>
-// instead. Thus, it's important to test in debug mode to make sure
-// the cast is legal!
-// This is the only place in the code we should use dynamic_cast<>.
-// In particular, you SHOULDN'T be using dynamic_cast<> in order to
-// do RTTI (eg code like this:
-// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
-// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
-// You should design the code some other way not to need this.
-template<typename To, typename From> // use like this: down_cast<T*>(foo);
-inline To down_cast(From* f) { // so we only accept pointers
- // Ensures that To is a sub-type of From *. This test is here only
- // for compile-time type checking, and has no overhead in an
- // optimized build at run-time, as it will be optimized away
- // completely.
- if (false) {
- const To to = NULL;
- ::testing::internal::implicit_cast<From*>(to);
- }
-
-#if GTEST_HAS_RTTI
- assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
-#endif
- return static_cast<To>(f);
-}
-
-// The GMOCK_COMPILE_ASSERT_ macro can be used to verify that a compile time
-// expression is true. For example, you could use it to verify the
-// size of a static array:
-//
-// GMOCK_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
-// content_type_names_incorrect_size);
-//
-// or to make sure a struct is smaller than a certain size:
-//
-// GMOCK_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
-//
-// The second argument to the macro is the name of the variable. If
-// the expression is false, most compilers will issue a warning/error
-// containing the name of the variable.
-
-template <bool>
-struct CompileAssert {
-};
-
-#define GMOCK_COMPILE_ASSERT_(expr, msg) \
- typedef ::testing::internal::CompileAssert<(bool(expr))> \
- msg[bool(expr) ? 1 : -1]
-
-// Implementation details of GMOCK_COMPILE_ASSERT_:
-//
-// - GMOCK_COMPILE_ASSERT_ works by defining an array type that has -1
-// elements (and thus is invalid) when the expression is false.
-//
-// - The simpler definition
-//
-// #define GMOCK_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
-//
-// does not work, as gcc supports variable-length arrays whose sizes
-// are determined at run-time (this is gcc's extension and not part
-// of the C++ standard). As a result, gcc fails to reject the
-// following code with the simple definition:
-//
-// int foo;
-// GMOCK_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
-// // not a compile-time constant.
-//
-// - By using the type CompileAssert<(bool(expr))>, we ensures that
-// expr is a compile-time constant. (Template arguments must be
-// determined at compile-time.)
-//
-// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
-// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
-//
-// CompileAssert<bool(expr)>
-//
-// instead, these compilers will refuse to compile
-//
-// GMOCK_COMPILE_ASSERT_(5 > 0, some_message);
-//
-// (They seem to think the ">" in "5 > 0" marks the end of the
-// template argument list.)
-//
-// - The array size is (bool(expr) ? 1 : -1), instead of simply
-//
-// ((expr) ? 1 : -1).
-//
-// This is to avoid running into a bug in MS VC 7.1, which
-// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
-
-#if GTEST_HAS_GLOBAL_STRING
-typedef ::string string;
-#else
-typedef ::std::string string;
-#endif // GTEST_HAS_GLOBAL_STRING
-
-#if GTEST_HAS_GLOBAL_WSTRING
-typedef ::wstring wstring;
-#elif GTEST_HAS_STD_WSTRING
-typedef ::std::wstring wstring;
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-} // namespace internal
-} // namespace testing
-
// Macro for referencing flags. This is public as we want the user to
// use this syntax to reference Google Mock flags.
#define GMOCK_FLAG(name) FLAGS_gmock_##name
diff --git a/testing/gmock/make/Makefile b/testing/gmock/make/Makefile
index ee0527e..6386e5b 100644
--- a/testing/gmock/make/Makefile
+++ b/testing/gmock/make/Makefile
@@ -27,15 +27,14 @@ GMOCK_DIR = ..
USER_DIR = ../test
# Flags passed to the preprocessor.
-CPPFLAGS += -I$(GMOCK_DIR) -I$(GMOCK_DIR)/include \
- -I$(GTEST_DIR) -I$(GTEST_DIR)/include
+CPPFLAGS += -I$(GTEST_DIR)/include -I$(GMOCK_DIR)/include
# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
-TESTS = gmock_link_test gmock_test
+TESTS = gmock_test
# All Google Test headers. Usually you shouldn't change this
# definition.
@@ -73,13 +72,16 @@ GMOCK_SRCS_ = $(GMOCK_DIR)/src/*.cc $(GMOCK_HEADERS)
# Google Test compile fast and for ordinary users their source rarely
# changes.
gtest-all.o : $(GTEST_SRCS_)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest-all.cc
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \
+ -c $(GTEST_DIR)/src/gtest-all.cc
gmock-all.o : $(GMOCK_SRCS_)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_DIR)/src/gmock-all.cc
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \
+ -c $(GMOCK_DIR)/src/gmock-all.cc
gmock_main.o : $(GMOCK_SRCS_)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_DIR)/src/gmock_main.cc
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) -I$(GMOCK_DIR) $(CXXFLAGS) \
+ -c $(GMOCK_DIR)/src/gmock_main.cc
gmock.a : gmock-all.o gtest-all.o
$(AR) $(ARFLAGS) $@ $^
@@ -89,21 +91,8 @@ gmock_main.a : gmock-all.o gtest-all.o gmock_main.o
# Builds a sample test.
-gmock_link_test.o : $(USER_DIR)/gmock_link_test.cc \
- $(USER_DIR)/gmock_link_test.h $(GMOCK_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_link_test.cc
-
-gmock_link2_test.o : $(USER_DIR)/gmock_link2_test.cc \
- $(USER_DIR)/gmock_link_test.h $(GMOCK_HEADERS)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_link2_test.cc
-
-gmock_link_test : gmock_link_test.o gmock_link2_test.o gmock_main.a
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
-
-# Builds another sample test.
-
gmock_test.o : $(USER_DIR)/gmock_test.cc $(GMOCK_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/gmock_test.cc
gmock_test : gmock_test.o gmock_main.a
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
diff --git a/testing/gmock/run_tests.py b/testing/gmock/run_tests.py
index 42dc14b..5e7b308 100755
--- a/testing/gmock/run_tests.py
+++ b/testing/gmock/run_tests.py
@@ -68,7 +68,6 @@ def _Main():
options, args = run_tests_util.ParseArgs('gtest')
test_runner = run_tests_util.TestRunner(
script_dir=SCRIPT_DIR,
- build_dir_var_name='GMOCK_BUILD_DIR',
injected_build_dir_finder=GetGmockBuildDir)
tests = test_runner.GetTestsToRun(args,
options.configurations,
diff --git a/testing/gmock/scripts/gmock_doctor.py b/testing/gmock/scripts/gmock_doctor.py
index bc814ad..fad4e34 100755
--- a/testing/gmock/scripts/gmock_doctor.py
+++ b/testing/gmock/scripts/gmock_doctor.py
@@ -203,7 +203,7 @@ def _IncompleteByReferenceArgumentDiagnoser(msg):
"""Diagnoses the IBRA disease, given the error messages by gcc."""
regex = (_FILE_LINE_RE + r'instantiated from here\n'
- r'.*gmock-printers\.h.*error: invalid application of '
+ r'.*gtest-printers\.h.*error: invalid application of '
r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
diagnosis = """
In order to mock this function, Google Mock needs to see the definition
diff --git a/testing/gmock/scripts/test/Makefile b/testing/gmock/scripts/test/Makefile
deleted file mode 100644
index 8edaea0..0000000
--- a/testing/gmock/scripts/test/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-# A Makefile for fusing Google Mock and building a sample test against it.
-#
-# SYNOPSIS:
-#
-# make [all] - makes everything.
-# make TARGET - makes the given target.
-# make check - makes everything and runs the built sample test.
-# make clean - removes all files generated by make.
-
-# Points to the root of fused Google Mock, relative to where this file is.
-FUSED_GMOCK_DIR = output
-
-# Paths to the fused gmock files.
-FUSED_GTEST_H = $(FUSED_GMOCK_DIR)/gtest/gtest.h
-FUSED_GMOCK_H = $(FUSED_GMOCK_DIR)/gmock/gmock.h
-FUSED_GMOCK_GTEST_ALL_CC = $(FUSED_GMOCK_DIR)/gmock-gtest-all.cc
-
-# Where to find the gmock_test.cc.
-GMOCK_TEST_CC = ../../test/gmock_test.cc
-
-# Where to find gmock_main.cc.
-GMOCK_MAIN_CC = ../../src/gmock_main.cc
-
-# Flags passed to the preprocessor.
-CPPFLAGS += -I$(FUSED_GMOCK_DIR)
-
-# Flags passed to the C++ compiler.
-CXXFLAGS += -g
-
-all : gmock_test
-
-check : all
- ./gmock_test
-
-clean :
- rm -rf $(FUSED_GMOCK_DIR) gmock_test *.o
-
-$(FUSED_GTEST_H) :
- ../fuse_gmock_files.py $(FUSED_GMOCK_DIR)
-
-$(FUSED_GMOCK_H) :
- ../fuse_gmock_files.py $(FUSED_GMOCK_DIR)
-
-$(FUSED_GMOCK_GTEST_ALL_CC) :
- ../fuse_gmock_files.py $(FUSED_GMOCK_DIR)
-
-gmock-gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(FUSED_GMOCK_GTEST_ALL_CC)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GMOCK_GTEST_ALL_CC)
-
-gmock_main.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_MAIN_CC)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_MAIN_CC)
-
-gmock_test.o : $(FUSED_GTEST_H) $(FUSED_GMOCK_H) $(GMOCK_TEST_CC)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GMOCK_TEST_CC)
-
-gmock_test : gmock_test.o gmock-gtest-all.o gmock_main.o
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
diff --git a/testing/gmock/src/gmock-all.cc b/testing/gmock/src/gmock-all.cc
index c9223fc..76118d8 100644
--- a/testing/gmock/src/gmock-all.cc
+++ b/testing/gmock/src/gmock-all.cc
@@ -43,6 +43,5 @@
#include "src/gmock-cardinalities.cc"
#include "src/gmock-internal-utils.cc"
#include "src/gmock-matchers.cc"
-#include "src/gmock-printers.cc"
#include "src/gmock-spec-builders.cc"
#include "src/gmock.cc"
diff --git a/testing/gmock/src/gmock-printers.cc b/testing/gmock/src/gmock-printers.cc
deleted file mode 100644
index fd7d305..0000000
--- a/testing/gmock/src/gmock-printers.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2007, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Google Mock - a framework for writing C++ mock classes.
-//
-// This file implements a universal value printer that can print a
-// value of any type T:
-//
-// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
-//
-// It uses the << operator when possible, and prints the bytes in the
-// object otherwise. A user can override its behavior for a class
-// type Foo by defining either operator<<(::std::ostream&, const Foo&)
-// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
-// defines Foo.
-
-#include <gmock/gmock-printers.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <ostream> // NOLINT
-#include <string>
-#include <gmock/internal/gmock-port.h>
-
-namespace testing {
-
-namespace {
-
-using ::std::ostream;
-
-#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s.
-#define snprintf _snprintf
-#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf.
-#define snprintf _snprintf_s
-#elif _MSC_VER
-#define snprintf _snprintf
-#endif // GTEST_OS_WINDOWS_MOBILE
-
-// Prints a segment of bytes in the given object.
-void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
- size_t count, ostream* os) {
- char text[5] = "";
- for (size_t i = 0; i != count; i++) {
- const size_t j = start + i;
- if (i != 0) {
- // Organizes the bytes into groups of 2 for easy parsing by
- // human.
- if ((j % 2) == 0) {
- *os << " ";
- }
- }
- snprintf(text, sizeof(text), "%02X", obj_bytes[j]);
- *os << text;
- }
-}
-
-// Prints the bytes in the given value to the given ostream.
-void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
- ostream* os) {
- // Tells the user how big the object is.
- *os << count << "-byte object <";
-
- const size_t kThreshold = 132;
- const size_t kChunkSize = 64;
- // If the object size is bigger than kThreshold, we'll have to omit
- // some details by printing only the first and the last kChunkSize
- // bytes.
- // TODO(wan): let the user control the threshold using a flag.
- if (count < kThreshold) {
- PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
- } else {
- PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
- *os << " ... ";
- // Rounds up to 2-byte boundary.
- const size_t resume_pos = (count - kChunkSize + 1)/2*2;
- PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
- }
- *os << ">";
-}
-
-} // namespace
-
-namespace internal2 {
-
-// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
-// given object. The delegation simplifies the implementation, which
-// uses the << operator and thus is easier done outside of the
-// ::testing::internal namespace, which contains a << operator that
-// sometimes conflicts with the one in STL.
-void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
- ostream* os) {
- PrintBytesInObjectToImpl(obj_bytes, count, os);
-}
-
-} // namespace internal2
-
-namespace internal {
-
-// Prints a wide char as a char literal without the quotes, escaping it
-// when necessary.
-static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) {
- switch (c) {
- case L'\0':
- *os << "\\0";
- break;
- case L'\'':
- *os << "\\'";
- break;
- case L'\?':
- *os << "\\?";
- break;
- case L'\\':
- *os << "\\\\";
- break;
- case L'\a':
- *os << "\\a";
- break;
- case L'\b':
- *os << "\\b";
- break;
- case L'\f':
- *os << "\\f";
- break;
- case L'\n':
- *os << "\\n";
- break;
- case L'\r':
- *os << "\\r";
- break;
- case L'\t':
- *os << "\\t";
- break;
- case L'\v':
- *os << "\\v";
- break;
- default:
- // Checks whether c is printable or not. Printable characters are in
- // the range [0x20,0x7E].
- // We test the value of c directly instead of calling isprint(), as
- // isprint() is buggy on Windows mobile.
- if (0x20 <= c && c <= 0x7E) {
- *os << static_cast<char>(c);
- } else {
- // Buffer size enough for the maximum number of digits and \0.
- char text[2 * sizeof(unsigned long) + 1] = "";
- snprintf(text, sizeof(text), "%lX", static_cast<unsigned long>(c));
- *os << "\\x" << text;
- }
- }
-}
-
-// Prints a char as if it's part of a string literal, escaping it when
-// necessary.
-static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) {
- switch (c) {
- case L'\'':
- *os << "'";
- break;
- case L'"':
- *os << "\\\"";
- break;
- default:
- PrintAsWideCharLiteralTo(c, os);
- }
-}
-
-// Prints a char as a char literal without the quotes, escaping it
-// when necessary.
-static void PrintAsCharLiteralTo(char c, ostream* os) {
- PrintAsWideCharLiteralTo(static_cast<unsigned char>(c), os);
-}
-
-// Prints a char as if it's part of a string literal, escaping it when
-// necessary.
-static void PrintAsStringLiteralTo(char c, ostream* os) {
- PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os);
-}
-
-// Prints a char and its code. The '\0' char is printed as "'\\0'",
-// other unprintable characters are also properly escaped using the
-// standard C++ escape sequence.
-void PrintCharTo(char c, int char_code, ostream* os) {
- *os << "'";
- PrintAsCharLiteralTo(c, os);
- *os << "'";
- if (c != '\0')
- *os << " (" << char_code << ")";
-}
-
-// Prints a wchar_t as a symbol if it is printable or as its internal
-// code otherwise and also as its decimal code (except for L'\0').
-// The L'\0' char is printed as "L'\\0'". The decimal code is printed
-// as signed integer when wchar_t is implemented by the compiler
-// as a signed type and is printed as an unsigned integer when wchar_t
-// is implemented as an unsigned type.
-void PrintTo(wchar_t wc, ostream* os) {
- *os << "L'";
- PrintAsWideCharLiteralTo(wc, os);
- *os << "'";
- if (wc != L'\0') {
- // Type Int64 is used because it provides more storage than wchar_t thus
- // when the compiler converts signed or unsigned implementation of wchar_t
- // to Int64 it fills higher bits with either zeros or the sign bit
- // passing it to operator <<() as either signed or unsigned integer.
- *os << " (" << static_cast<Int64>(wc) << ")";
- }
-}
-
-// Prints the given array of characters to the ostream.
-// The array starts at *begin, the length is len, it may include '\0' characters
-// and may not be null-terminated.
-static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) {
- *os << "\"";
- for (size_t index = 0; index < len; ++index) {
- PrintAsStringLiteralTo(begin[index], os);
- }
- *os << "\"";
-}
-
-// Prints a (const) char array of 'len' elements, starting at address 'begin'.
-void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
- PrintCharsAsStringTo(begin, len, os);
-}
-
-// Prints the given array of wide characters to the ostream.
-// The array starts at *begin, the length is len, it may include L'\0'
-// characters and may not be null-terminated.
-static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len,
- ostream* os) {
- *os << "L\"";
- for (size_t index = 0; index < len; ++index) {
- PrintAsWideStringLiteralTo(begin[index], os);
- }
- *os << "\"";
-}
-
-// Prints the given C string to the ostream.
-void PrintTo(const char* s, ostream* os) {
- if (s == NULL) {
- *os << "NULL";
- } else {
- *os << implicit_cast<const void*>(s) << " pointing to ";
- PrintCharsAsStringTo(s, strlen(s), os);
- }
-}
-
-// MSVC compiler can be configured to define whar_t as a typedef
-// of unsigned short. Defining an overload for const wchar_t* in that case
-// would cause pointers to unsigned shorts be printed as wide strings,
-// possibly accessing more memory than intended and causing invalid
-// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
-// wchar_t is implemented as a native type.
-#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
-// Prints the given wide C string to the ostream.
-void PrintTo(const wchar_t* s, ostream* os) {
- if (s == NULL) {
- *os << "NULL";
- } else {
- *os << implicit_cast<const void*>(s) << " pointing to ";
- PrintWideCharsAsStringTo(s, wcslen(s), os);
- }
-}
-#endif // wchar_t is native
-
-// Prints a ::string object.
-#if GTEST_HAS_GLOBAL_STRING
-void PrintStringTo(const ::string& s, ostream* os) {
- PrintCharsAsStringTo(s.data(), s.size(), os);
-}
-#endif // GTEST_HAS_GLOBAL_STRING
-
-void PrintStringTo(const ::std::string& s, ostream* os) {
- PrintCharsAsStringTo(s.data(), s.size(), os);
-}
-
-// Prints a ::wstring object.
-#if GTEST_HAS_GLOBAL_WSTRING
-void PrintWideStringTo(const ::wstring& s, ostream* os) {
- PrintWideCharsAsStringTo(s.data(), s.size(), os);
-}
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-#if GTEST_HAS_STD_WSTRING
-void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
- PrintWideCharsAsStringTo(s.data(), s.size(), os);
-}
-#endif // GTEST_HAS_STD_WSTRING
-
-} // namespace internal
-
-} // namespace testing
diff --git a/testing/gmock/test/gmock-actions_test.cc b/testing/gmock/test/gmock-actions_test.cc
index a2c6fe1..8391e5f 100644
--- a/testing/gmock/test/gmock-actions_test.cc
+++ b/testing/gmock/test/gmock-actions_test.cc
@@ -74,9 +74,9 @@ using testing::SetArgumentPointee;
using testing::SetErrnoAndReturn;
#endif
-#if GMOCK_HAS_PROTOBUF_
+#if GTEST_HAS_PROTOBUF_
using testing::internal::TestMessage;
-#endif // GMOCK_HAS_PROTOBUF_
+#endif // GTEST_HAS_PROTOBUF_
// Tests that BuiltInDefaultValue<T*>::Get() returns NULL.
TEST(BuiltInDefaultValueTest, IsNullForPointerTypes) {
@@ -689,7 +689,7 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointee) {
EXPECT_EQ('a', ch);
}
-#if GMOCK_HAS_PROTOBUF_
+#if GTEST_HAS_PROTOBUF_
// Tests that SetArgumentPointee<N>(proto_buffer) sets the v1 protobuf
// variable pointed to by the N-th (0-based) argument to proto_buffer.
@@ -786,7 +786,7 @@ TEST(SetArgumentPointeeTest, SetsTheNthPointeeOfProto2BufferBaseType) {
EXPECT_EQ("hi", dest.string_field());
}
-#endif // GMOCK_HAS_PROTOBUF_
+#endif // GTEST_HAS_PROTOBUF_
// Sample functions and functors for testing Invoke() and etc.
int Nullary() { return 1; }
diff --git a/testing/gmock/test/gmock-generated-matchers_test.cc b/testing/gmock/test/gmock-generated-matchers_test.cc
index 12479af..eebca8a 100644
--- a/testing/gmock/test/gmock-generated-matchers_test.cc
+++ b/testing/gmock/test/gmock-generated-matchers_test.cc
@@ -192,7 +192,8 @@ TEST(ArgsTest, AcceptsTenTemplateArgs) {
TEST(ArgsTest, DescirbesSelfCorrectly) {
const Matcher<tuple<int, bool, char> > m = Args<2, 0>(Lt());
- EXPECT_EQ("are a tuple whose fields (#2, #0) are a pair (x, y) where x < y",
+ EXPECT_EQ("are a tuple whose fields (#2, #0) are a pair where "
+ "the first < the second",
Describe(m));
}
@@ -200,14 +201,14 @@ TEST(ArgsTest, DescirbesNestedArgsCorrectly) {
const Matcher<const tuple<int, bool, char, int>&> m =
Args<0, 2, 3>(Args<2, 0>(Lt()));
EXPECT_EQ("are a tuple whose fields (#0, #2, #3) are a tuple "
- "whose fields (#2, #0) are a pair (x, y) where x < y",
+ "whose fields (#2, #0) are a pair where the first < the second",
Describe(m));
}
TEST(ArgsTest, DescribesNegationCorrectly) {
const Matcher<tuple<int, char> > m = Args<1, 0>(Gt());
- EXPECT_EQ("are a tuple whose fields (#1, #0) are a pair (x, y) "
- "where x > y is false",
+ EXPECT_EQ("are a tuple whose fields (#1, #0) aren't a pair "
+ "where the first > the second",
DescribeNegation(m));
}
diff --git a/testing/gmock/test/gmock-internal-utils_test.cc b/testing/gmock/test/gmock-internal-utils_test.cc
index fc5d9e5..4309f7c 100644
--- a/testing/gmock/test/gmock-internal-utils_test.cc
+++ b/testing/gmock/test/gmock-internal-utils_test.cc
@@ -96,102 +96,6 @@ TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameIsMixture) {
ConvertIdentifierNameToWords("_Chapter11Section_1_"));
}
-// Tests that CompileAssertTypesEqual compiles when the type arguments are
-// equal.
-TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) {
- CompileAssertTypesEqual<void, void>();
- CompileAssertTypesEqual<int*, int*>();
-}
-
-// Tests that RemoveReference does not affect non-reference types.
-TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) {
- CompileAssertTypesEqual<int, RemoveReference<int>::type>();
- CompileAssertTypesEqual<const char, RemoveReference<const char>::type>();
-}
-
-// Tests that RemoveReference removes reference from reference types.
-TEST(RemoveReferenceTest, RemovesReference) {
- CompileAssertTypesEqual<int, RemoveReference<int&>::type>();
- CompileAssertTypesEqual<const char, RemoveReference<const char&>::type>();
-}
-
-// Tests GMOCK_REMOVE_REFERENCE_.
-
-template <typename T1, typename T2>
-void TestGMockRemoveReference() {
- CompileAssertTypesEqual<T1, GMOCK_REMOVE_REFERENCE_(T2)>();
-}
-
-TEST(RemoveReferenceTest, MacroVersion) {
- TestGMockRemoveReference<int, int>();
- TestGMockRemoveReference<const char, const char&>();
-}
-
-
-// Tests that RemoveConst does not affect non-const types.
-TEST(RemoveConstTest, DoesNotAffectNonConstType) {
- CompileAssertTypesEqual<int, RemoveConst<int>::type>();
- CompileAssertTypesEqual<char&, RemoveConst<char&>::type>();
-}
-
-// Tests that RemoveConst removes const from const types.
-TEST(RemoveConstTest, RemovesConst) {
- CompileAssertTypesEqual<int, RemoveConst<const int>::type>();
- CompileAssertTypesEqual<char[2], RemoveConst<const char[2]>::type>();
- CompileAssertTypesEqual<char[2][3], RemoveConst<const char[2][3]>::type>();
-}
-
-// Tests GMOCK_REMOVE_CONST_.
-
-template <typename T1, typename T2>
-void TestGMockRemoveConst() {
- CompileAssertTypesEqual<T1, GMOCK_REMOVE_CONST_(T2)>();
-}
-
-TEST(RemoveConstTest, MacroVersion) {
- TestGMockRemoveConst<int, int>();
- TestGMockRemoveConst<double&, double&>();
- TestGMockRemoveConst<char, const char>();
-}
-
-// Tests that AddReference does not affect reference types.
-TEST(AddReferenceTest, DoesNotAffectReferenceType) {
- CompileAssertTypesEqual<int&, AddReference<int&>::type>();
- CompileAssertTypesEqual<const char&, AddReference<const char&>::type>();
-}
-
-// Tests that AddReference adds reference to non-reference types.
-TEST(AddReferenceTest, AddsReference) {
- CompileAssertTypesEqual<int&, AddReference<int>::type>();
- CompileAssertTypesEqual<const char&, AddReference<const char>::type>();
-}
-
-// Tests GMOCK_ADD_REFERENCE_.
-
-template <typename T1, typename T2>
-void TestGMockAddReference() {
- CompileAssertTypesEqual<T1, GMOCK_ADD_REFERENCE_(T2)>();
-}
-
-TEST(AddReferenceTest, MacroVersion) {
- TestGMockAddReference<int&, int>();
- TestGMockAddReference<const char&, const char&>();
-}
-
-// Tests GMOCK_REFERENCE_TO_CONST_.
-
-template <typename T1, typename T2>
-void TestGMockReferenceToConst() {
- CompileAssertTypesEqual<T1, GMOCK_REFERENCE_TO_CONST_(T2)>();
-}
-
-TEST(GMockReferenceToConstTest, Works) {
- TestGMockReferenceToConst<const char&, char>();
- TestGMockReferenceToConst<const int&, const int>();
- TestGMockReferenceToConst<const double&, double>();
- TestGMockReferenceToConst<const string&, const string&>();
-}
-
TEST(PointeeOfTest, WorksForSmartPointers) {
CompileAssertTypesEqual<const char,
PointeeOf<internal::linked_ptr<const char> >::type>();
@@ -217,38 +121,11 @@ TEST(GetRawPointerTest, WorksForRawPointers) {
EXPECT_EQ(&n, GetRawPointer(&n));
}
+// Tests KindOf<T>.
+
class Base {};
class Derived : public Base {};
-// Tests that ImplicitlyConvertible<T1, T2>::value is a compile-time constant.
-TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) {
- GMOCK_COMPILE_ASSERT_((ImplicitlyConvertible<int, int>::value), const_true);
- GMOCK_COMPILE_ASSERT_((!ImplicitlyConvertible<void*, int*>::value),
- const_false);
-}
-
-// Tests that ImplicitlyConvertible<T1, T2>::value is true when T1 can
-// be implicitly converted to T2.
-TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) {
- EXPECT_TRUE((ImplicitlyConvertible<int, double>::value));
- EXPECT_TRUE((ImplicitlyConvertible<double, int>::value));
- EXPECT_TRUE((ImplicitlyConvertible<int*, void*>::value));
- EXPECT_TRUE((ImplicitlyConvertible<int*, const int*>::value));
- EXPECT_TRUE((ImplicitlyConvertible<Derived&, const Base&>::value));
- EXPECT_TRUE((ImplicitlyConvertible<const Base, Base>::value));
-}
-
-// Tests that ImplicitlyConvertible<T1, T2>::value is false when T1
-// cannot be implicitly converted to T2.
-TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) {
- EXPECT_FALSE((ImplicitlyConvertible<double, int*>::value));
- EXPECT_FALSE((ImplicitlyConvertible<void*, int*>::value));
- EXPECT_FALSE((ImplicitlyConvertible<const int*, int*>::value));
- EXPECT_FALSE((ImplicitlyConvertible<Base&, Derived&>::value));
-}
-
-// Tests KindOf<T>.
-
TEST(KindOfTest, Bool) {
EXPECT_EQ(kBool, GMOCK_KIND_OF_(bool)); // NOLINT
}
@@ -382,46 +259,6 @@ TEST(LosslessArithmeticConvertibleTest, FloatingPointToFloatingPoint) {
}
}
-// Tests that IsAProtocolMessage<T>::value is a compile-time constant.
-TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) {
- GMOCK_COMPILE_ASSERT_(IsAProtocolMessage<ProtocolMessage>::value, const_true);
- GMOCK_COMPILE_ASSERT_(!IsAProtocolMessage<int>::value, const_false);
-}
-
-// Tests that IsAProtocolMessage<T>::value is true when T is
-// ProtocolMessage or a sub-class of it.
-TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) {
- EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value);
- EXPECT_TRUE(IsAProtocolMessage<ProtocolMessage>::value);
-#if GMOCK_HAS_PROTOBUF_
- EXPECT_TRUE(IsAProtocolMessage<const TestMessage>::value);
-#endif // GMOCK_HAS_PROTOBUF_
-}
-
-// Tests that IsAProtocolMessage<T>::value is false when T is neither
-// ProtocolMessage nor a sub-class of it.
-TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) {
- EXPECT_FALSE(IsAProtocolMessage<int>::value);
- EXPECT_FALSE(IsAProtocolMessage<const Base>::value);
-}
-
-// Tests IsContainerTest.
-
-class NonContainer {};
-
-TEST(IsContainerTestTest, WorksForNonContainer) {
- EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<int>(0)));
- EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<char[5]>(0)));
- EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<NonContainer>(0)));
-}
-
-TEST(IsContainerTestTest, WorksForContainer) {
- EXPECT_EQ(sizeof(IsContainer),
- sizeof(IsContainerTest<std::vector<bool> >(0)));
- EXPECT_EQ(sizeof(IsContainer),
- sizeof(IsContainerTest<std::map<int, double> >(0)));
-}
-
// Tests the TupleMatches() template function.
TEST(TupleMatchesTest, WorksForSize0) {
@@ -565,10 +402,12 @@ void TestLogWithSeverity(const string& verbosity, LogSeverity severity,
// Tests that when the stack_frames_to_skip parameter is negative,
// Log() doesn't include the stack trace in the output.
TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) {
+ const string saved_flag = GMOCK_FLAG(verbose);
GMOCK_FLAG(verbose) = kInfoVerbosity;
CaptureStdout();
Log(INFO, "Test log.\n", -1);
EXPECT_STREQ("\nTest log.\n", GetCapturedStdout().c_str());
+ GMOCK_FLAG(verbose) = saved_flag;
}
// Tests that in opt mode, a positive stack_frames_to_skip argument is
@@ -735,148 +574,6 @@ TEST(OnCallTest, LogsAnythingArgument) {
#endif // GTEST_HAS_STREAM_REDIRECTION_
-// Tests ArrayEq().
-
-TEST(ArrayEqTest, WorksForDegeneratedArrays) {
- EXPECT_TRUE(ArrayEq(5, 5L));
- EXPECT_FALSE(ArrayEq('a', 0));
-}
-
-TEST(ArrayEqTest, WorksForOneDimensionalArrays) {
- const int a[] = { 0, 1 };
- long b[] = { 0, 1 };
- EXPECT_TRUE(ArrayEq(a, b));
- EXPECT_TRUE(ArrayEq(a, 2, b));
-
- b[0] = 2;
- EXPECT_FALSE(ArrayEq(a, b));
- EXPECT_FALSE(ArrayEq(a, 1, b));
-}
-
-TEST(ArrayEqTest, WorksForTwoDimensionalArrays) {
- const char a[][3] = { "hi", "lo" };
- const char b[][3] = { "hi", "lo" };
- const char c[][3] = { "hi", "li" };
-
- EXPECT_TRUE(ArrayEq(a, b));
- EXPECT_TRUE(ArrayEq(a, 2, b));
-
- EXPECT_FALSE(ArrayEq(a, c));
- EXPECT_FALSE(ArrayEq(a, 2, c));
-}
-
-// Tests ArrayAwareFind().
-
-TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) {
- const char a[] = "hello";
- EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o'));
- EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x'));
-}
-
-TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) {
- int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
- const int b[2] = { 2, 3 };
- EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b));
-
- const int c[2] = { 6, 7 };
- EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c));
-}
-
-// Tests CopyArray().
-
-TEST(CopyArrayTest, WorksForDegeneratedArrays) {
- int n = 0;
- CopyArray('a', &n);
- EXPECT_EQ('a', n);
-}
-
-TEST(CopyArrayTest, WorksForOneDimensionalArrays) {
- const char a[3] = "hi";
- int b[3];
- CopyArray(a, &b);
- EXPECT_TRUE(ArrayEq(a, b));
-
- int c[3];
- CopyArray(a, 3, c);
- EXPECT_TRUE(ArrayEq(a, c));
-}
-
-TEST(CopyArrayTest, WorksForTwoDimensionalArrays) {
- const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } };
- int b[2][3];
- CopyArray(a, &b);
- EXPECT_TRUE(ArrayEq(a, b));
-
- int c[2][3];
- CopyArray(a, 2, c);
- EXPECT_TRUE(ArrayEq(a, c));
-}
-
-// Tests NativeArray.
-
-TEST(NativeArrayTest, ConstructorFromArrayWorks) {
- const int a[3] = { 0, 1, 2 };
- NativeArray<int> na(a, 3, kReference);
- EXPECT_EQ(3U, na.size());
- EXPECT_EQ(a, na.begin());
-}
-
-TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) {
- typedef int Array[2];
- Array* a = new Array[1];
- (*a)[0] = 0;
- (*a)[1] = 1;
- NativeArray<int> na(*a, 2, kCopy);
- EXPECT_NE(*a, na.begin());
- delete[] a;
- EXPECT_EQ(0, na.begin()[0]);
- EXPECT_EQ(1, na.begin()[1]);
-
- // We rely on the heap checker to verify that na deletes the copy of
- // array.
-}
-
-TEST(NativeArrayTest, TypeMembersAreCorrect) {
- StaticAssertTypeEq<char, NativeArray<char>::value_type>();
- StaticAssertTypeEq<int[2], NativeArray<int[2]>::value_type>();
-
- StaticAssertTypeEq<const char*, NativeArray<char>::const_iterator>();
- StaticAssertTypeEq<const bool(*)[2], NativeArray<bool[2]>::const_iterator>();
-}
-
-TEST(NativeArrayTest, MethodsWork) {
- const int a[3] = { 0, 1, 2 };
- NativeArray<int> na(a, 3, kCopy);
- ASSERT_EQ(3U, na.size());
- EXPECT_EQ(3, na.end() - na.begin());
-
- NativeArray<int>::const_iterator it = na.begin();
- EXPECT_EQ(0, *it);
- ++it;
- EXPECT_EQ(1, *it);
- it++;
- EXPECT_EQ(2, *it);
- ++it;
- EXPECT_EQ(na.end(), it);
-
- EXPECT_THAT(na, Eq(na));
-
- NativeArray<int> na2(a, 3, kReference);
- EXPECT_THAT(na, Eq(na2));
-
- const int b1[3] = { 0, 1, 1 };
- const int b2[4] = { 0, 1, 2, 3 };
- EXPECT_THAT(na, Not(Eq(NativeArray<int>(b1, 3, kReference))));
- EXPECT_THAT(na, Not(Eq(NativeArray<int>(b2, 4, kCopy))));
-}
-
-TEST(NativeArrayTest, WorksForTwoDimensionalArray) {
- const char a[2][3] = { "hi", "lo" };
- NativeArray<char[3]> na(a, 2, kReference);
- ASSERT_EQ(2U, na.size());
- EXPECT_EQ(a, na.begin());
-}
-
// Tests StlContainerView.
TEST(StlContainerViewTest, WorksForStlContainer) {
diff --git a/testing/gmock/test/gmock-matchers_test.cc b/testing/gmock/test/gmock-matchers_test.cc
index 6d784f1..3b151db 100644
--- a/testing/gmock/test/gmock-matchers_test.cc
+++ b/testing/gmock/test/gmock-matchers_test.cc
@@ -61,12 +61,19 @@ bool SkipPrefix(const char* prefix, const char** pstr);
namespace gmock_matchers_test {
+using std::list;
using std::make_pair;
using std::map;
using std::multimap;
+using std::multiset;
+using std::ostream;
using std::pair;
+using std::set;
using std::stringstream;
+using std::tr1::get;
using std::tr1::make_tuple;
+using std::tr1::tuple;
+using std::vector;
using testing::A;
using testing::AllArgs;
using testing::AllOf;
@@ -102,6 +109,7 @@ using testing::Not;
using testing::NotNull;
using testing::Pair;
using testing::Pointee;
+using testing::Pointwise;
using testing::PolymorphicMatcher;
using testing::Property;
using testing::Ref;
@@ -142,7 +150,7 @@ class GreaterThanMatcher : public MatcherInterface<int> {
public:
explicit GreaterThanMatcher(int rhs) : rhs_(rhs) {}
- virtual void DescribeTo(::std::ostream* os) const {
+ virtual void DescribeTo(ostream* os) const {
*os << "is > " << rhs_;
}
@@ -187,9 +195,9 @@ string DescribeNegation(const Matcher<T>& m) {
// Returns the reason why x matches, or doesn't match, m.
template <typename MatcherType, typename Value>
string Explain(const MatcherType& m, const Value& x) {
- stringstream ss;
- m.ExplainMatchResultTo(x, &ss);
- return ss.str();
+ StringMatchResultListener listener;
+ ExplainMatchResult(m, x, &listener);
+ return listener.str();
}
TEST(MatchResultListenerTest, StreamingWorks) {
@@ -226,7 +234,7 @@ class EvenMatcherImpl : public MatcherInterface<int> {
return x % 2 == 0;
}
- virtual void DescribeTo(::std::ostream* os) const {
+ virtual void DescribeTo(ostream* os) const {
*os << "is an even number";
}
@@ -256,7 +264,7 @@ class NewEvenMatcherImpl : public MatcherInterface<int> {
return match;
}
- virtual void DescribeTo(::std::ostream* os) const {
+ virtual void DescribeTo(ostream* os) const {
*os << "is an even number";
}
};
@@ -363,20 +371,20 @@ TEST(MakeMatcherTest, ConstructsMatcherFromMatcherInterface) {
// Tests that MakePolymorphicMatcher() can construct a polymorphic
// matcher from its implementation using the old API.
-const int bar = 1;
+const int g_bar = 1;
class ReferencesBarOrIsZeroImpl {
public:
template <typename T>
bool MatchAndExplain(const T& x,
MatchResultListener* /* listener */) const {
const void* p = &x;
- return p == &bar || x == 0;
+ return p == &g_bar || x == 0;
}
- void DescribeTo(::std::ostream* os) const { *os << "bar or zero"; }
+ void DescribeTo(ostream* os) const { *os << "g_bar or zero"; }
- void DescribeNegationTo(::std::ostream* os) const {
- *os << "doesn't reference bar and is not zero";
+ void DescribeNegationTo(ostream* os) const {
+ *os << "doesn't reference g_bar and is not zero";
}
};
@@ -391,24 +399,24 @@ TEST(MakePolymorphicMatcherTest, ConstructsMatcherUsingOldAPI) {
Matcher<const int&> m1 = ReferencesBarOrIsZero();
EXPECT_TRUE(m1.Matches(0));
// Verifies that the identity of a by-reference argument is preserved.
- EXPECT_TRUE(m1.Matches(bar));
+ EXPECT_TRUE(m1.Matches(g_bar));
EXPECT_FALSE(m1.Matches(1));
- EXPECT_EQ("bar or zero", Describe(m1));
+ EXPECT_EQ("g_bar or zero", Describe(m1));
// Using a polymorphic matcher to match a value type.
Matcher<double> m2 = ReferencesBarOrIsZero();
EXPECT_TRUE(m2.Matches(0.0));
EXPECT_FALSE(m2.Matches(0.1));
- EXPECT_EQ("bar or zero", Describe(m2));
+ EXPECT_EQ("g_bar or zero", Describe(m2));
}
// Tests implementing a polymorphic matcher using MatchAndExplain().
class PolymorphicIsEvenImpl {
public:
- void DescribeTo(::std::ostream* os) const { *os << "is even"; }
+ void DescribeTo(ostream* os) const { *os << "is even"; }
- void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(ostream* os) const {
*os << "is odd";
}
@@ -1148,7 +1156,7 @@ TEST(KeyTest, SafelyCastsInnerMatcher) {
}
TEST(KeyTest, InsideContainsUsingMap) {
- std::map<int, char> container;
+ map<int, char> container;
container.insert(make_pair(1, 'a'));
container.insert(make_pair(2, 'b'));
container.insert(make_pair(4, 'c'));
@@ -1157,7 +1165,7 @@ TEST(KeyTest, InsideContainsUsingMap) {
}
TEST(KeyTest, InsideContainsUsingMultimap) {
- std::multimap<int, char> container;
+ multimap<int, char> container;
container.insert(make_pair(1, 'a'));
container.insert(make_pair(2, 'b'));
container.insert(make_pair(4, 'c'));
@@ -1266,7 +1274,7 @@ TEST(PairTest, SafelyCastsInnerMatchers) {
}
TEST(PairTest, InsideContainsUsingMap) {
- std::map<int, char> container;
+ map<int, char> container;
container.insert(make_pair(1, 'a'));
container.insert(make_pair(2, 'b'));
container.insert(make_pair(4, 'c'));
@@ -1759,7 +1767,7 @@ TEST(Eq2Test, MatchesEqualArguments) {
// Tests that Eq() describes itself properly.
TEST(Eq2Test, CanDescribeSelf) {
Matcher<const Tuple2&> m = Eq();
- EXPECT_EQ("are a pair (x, y) where x == y", Describe(m));
+ EXPECT_EQ("are an equal pair", Describe(m));
}
// Tests that Ge() matches a 2-tuple where the first field >= the
@@ -1774,7 +1782,7 @@ TEST(Ge2Test, MatchesGreaterThanOrEqualArguments) {
// Tests that Ge() describes itself properly.
TEST(Ge2Test, CanDescribeSelf) {
Matcher<const Tuple2&> m = Ge();
- EXPECT_EQ("are a pair (x, y) where x >= y", Describe(m));
+ EXPECT_EQ("are a pair where the first >= the second", Describe(m));
}
// Tests that Gt() matches a 2-tuple where the first field > the
@@ -1789,7 +1797,7 @@ TEST(Gt2Test, MatchesGreaterThanArguments) {
// Tests that Gt() describes itself properly.
TEST(Gt2Test, CanDescribeSelf) {
Matcher<const Tuple2&> m = Gt();
- EXPECT_EQ("are a pair (x, y) where x > y", Describe(m));
+ EXPECT_EQ("are a pair where the first > the second", Describe(m));
}
// Tests that Le() matches a 2-tuple where the first field <= the
@@ -1804,7 +1812,7 @@ TEST(Le2Test, MatchesLessThanOrEqualArguments) {
// Tests that Le() describes itself properly.
TEST(Le2Test, CanDescribeSelf) {
Matcher<const Tuple2&> m = Le();
- EXPECT_EQ("are a pair (x, y) where x <= y", Describe(m));
+ EXPECT_EQ("are a pair where the first <= the second", Describe(m));
}
// Tests that Lt() matches a 2-tuple where the first field < the
@@ -1819,7 +1827,7 @@ TEST(Lt2Test, MatchesLessThanArguments) {
// Tests that Lt() describes itself properly.
TEST(Lt2Test, CanDescribeSelf) {
Matcher<const Tuple2&> m = Lt();
- EXPECT_EQ("are a pair (x, y) where x < y", Describe(m));
+ EXPECT_EQ("are a pair where the first < the second", Describe(m));
}
// Tests that Ne() matches a 2-tuple where the first field != the
@@ -1834,7 +1842,7 @@ TEST(Ne2Test, MatchesUnequalArguments) {
// Tests that Ne() describes itself properly.
TEST(Ne2Test, CanDescribeSelf) {
Matcher<const Tuple2&> m = Ne();
- EXPECT_EQ("are a pair (x, y) where x != y", Describe(m));
+ EXPECT_EQ("are an unequal pair", Describe(m));
}
// Tests that Not(m) matches any value that doesn't match m.
@@ -3336,11 +3344,11 @@ class DivisibleByImpl {
return (n % divider_) == 0;
}
- void DescribeTo(::std::ostream* os) const {
+ void DescribeTo(ostream* os) const {
*os << "is divisible by " << divider_;
}
- void DescribeNegationTo(::std::ostream* os) const {
+ void DescribeNegationTo(ostream* os) const {
*os << "is not divisible by " << divider_;
}
@@ -3442,10 +3450,10 @@ template <typename T>
class ContainerEqTest : public testing::Test {};
typedef testing::Types<
- std::set<int>,
- std::vector<size_t>,
- std::multiset<size_t>,
- std::list<int> >
+ set<int>,
+ vector<size_t>,
+ multiset<size_t>,
+ list<int> >
ContainerEqTestTypes;
TYPED_TEST_CASE(ContainerEqTest, ContainerEqTestTypes);
@@ -3513,9 +3521,9 @@ TYPED_TEST(ContainerEqTest, DuplicateDifference) {
TEST(ContainerEqExtraTest, MultipleValuesMissing) {
static const int vals[] = {1, 1, 2, 3, 5, 8};
static const int test_vals[] = {2, 1, 5};
- std::vector<int> my_set(vals, vals + 6);
- std::vector<int> test_set(test_vals, test_vals + 3);
- const Matcher<std::vector<int> > m = ContainerEq(my_set);
+ vector<int> my_set(vals, vals + 6);
+ vector<int> test_set(test_vals, test_vals + 3);
+ const Matcher<vector<int> > m = ContainerEq(my_set);
EXPECT_FALSE(m.Matches(test_set));
EXPECT_EQ("which doesn't have these expected elements: 3, 8",
Explain(m, test_set));
@@ -3526,9 +3534,9 @@ TEST(ContainerEqExtraTest, MultipleValuesMissing) {
TEST(ContainerEqExtraTest, MultipleValuesAdded) {
static const int vals[] = {1, 1, 2, 3, 5, 8};
static const int test_vals[] = {1, 2, 92, 3, 5, 8, 46};
- std::list<size_t> my_set(vals, vals + 6);
- std::list<size_t> test_set(test_vals, test_vals + 7);
- const Matcher<const std::list<size_t>&> m = ContainerEq(my_set);
+ list<size_t> my_set(vals, vals + 6);
+ list<size_t> test_set(test_vals, test_vals + 7);
+ const Matcher<const list<size_t>&> m = ContainerEq(my_set);
EXPECT_FALSE(m.Matches(test_set));
EXPECT_EQ("which has these unexpected elements: 92, 46",
Explain(m, test_set));
@@ -3538,9 +3546,9 @@ TEST(ContainerEqExtraTest, MultipleValuesAdded) {
TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) {
static const int vals[] = {1, 1, 2, 3, 5, 8};
static const int test_vals[] = {1, 2, 3, 92, 46};
- std::list<size_t> my_set(vals, vals + 6);
- std::list<size_t> test_set(test_vals, test_vals + 5);
- const Matcher<const std::list<size_t> > m = ContainerEq(my_set);
+ list<size_t> my_set(vals, vals + 6);
+ list<size_t> test_set(test_vals, test_vals + 5);
+ const Matcher<const list<size_t> > m = ContainerEq(my_set);
EXPECT_FALSE(m.Matches(test_set));
EXPECT_EQ("which has these unexpected elements: 92, 46,\n"
"and doesn't have these expected elements: 5, 8",
@@ -3552,9 +3560,9 @@ TEST(ContainerEqExtraTest, MultipleValuesAddedAndRemoved) {
TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) {
static const int vals[] = {1, 1, 2, 3, 5, 8};
static const int test_vals[] = {1, 2, 3, 5, 8};
- std::vector<int> my_set(vals, vals + 6);
- std::vector<int> test_set(test_vals, test_vals + 5);
- const Matcher<std::vector<int> > m = ContainerEq(my_set);
+ vector<int> my_set(vals, vals + 6);
+ vector<int> test_set(test_vals, test_vals + 5);
+ const Matcher<vector<int> > m = ContainerEq(my_set);
EXPECT_TRUE(m.Matches(my_set));
EXPECT_FALSE(m.Matches(test_set));
// There is nothing to report when both sets contain all the same values.
@@ -3564,15 +3572,15 @@ TEST(ContainerEqExtraTest, MultiSetOfIntDuplicateDifference) {
// Tests that ContainerEq works for non-trivial associative containers,
// like maps.
TEST(ContainerEqExtraTest, WorksForMaps) {
- std::map<int, std::string> my_map;
+ map<int, std::string> my_map;
my_map[0] = "a";
my_map[1] = "b";
- std::map<int, std::string> test_map;
+ map<int, std::string> test_map;
test_map[0] = "aa";
test_map[1] = "b";
- const Matcher<const std::map<int, std::string>&> m = ContainerEq(my_map);
+ const Matcher<const map<int, std::string>&> m = ContainerEq(my_map);
EXPECT_TRUE(m.Matches(my_map));
EXPECT_FALSE(m.Matches(test_map));
@@ -3984,5 +3992,209 @@ TEST(MatcherTupleTest, ExplainsMatchFailure) {
// explanation.
}
+// Tests Each().
+
+TEST(EachTest, ExplainsMatchResultCorrectly) {
+ set<int> a; // empty
+
+ Matcher<set<int> > m = Each(2);
+ EXPECT_EQ("", Explain(m, a));
+
+ Matcher<const int(&)[1]> n = Each(1);
+
+ const int b[1] = { 1 };
+ EXPECT_EQ("", Explain(n, b));
+
+ n = Each(3);
+ EXPECT_EQ("whose element #0 doesn't match", Explain(n, b));
+
+ a.insert(1);
+ a.insert(2);
+ a.insert(3);
+ m = Each(GreaterThan(0));
+ EXPECT_EQ("", Explain(m, a));
+
+ m = Each(GreaterThan(10));
+ EXPECT_EQ("whose element #0 doesn't match, which is 9 less than 10",
+ Explain(m, a));
+}
+
+TEST(EachTest, DescribesItselfCorrectly) {
+ Matcher<vector<int> > m = Each(1);
+ EXPECT_EQ("only contains elements that is equal to 1", Describe(m));
+
+ Matcher<vector<int> > m2 = Not(m);
+ EXPECT_EQ("contains some element that isn't equal to 1", Describe(m2));
+}
+
+TEST(EachTest, MatchesVectorWhenAllElementsMatch) {
+ vector<int> some_vector;
+ EXPECT_THAT(some_vector, Each(1));
+ some_vector.push_back(3);
+ EXPECT_THAT(some_vector, Not(Each(1)));
+ EXPECT_THAT(some_vector, Each(3));
+ some_vector.push_back(1);
+ some_vector.push_back(2);
+ EXPECT_THAT(some_vector, Not(Each(3)));
+ EXPECT_THAT(some_vector, Each(Lt(3.5)));
+
+ vector<string> another_vector;
+ another_vector.push_back("fee");
+ EXPECT_THAT(another_vector, Each(string("fee")));
+ another_vector.push_back("fie");
+ another_vector.push_back("foe");
+ another_vector.push_back("fum");
+ EXPECT_THAT(another_vector, Not(Each(string("fee"))));
+}
+
+TEST(EachTest, MatchesMapWhenAllElementsMatch) {
+ map<const char*, int> my_map;
+ const char* bar = "a string";
+ my_map[bar] = 2;
+ EXPECT_THAT(my_map, Each(make_pair(bar, 2)));
+
+ map<string, int> another_map;
+ EXPECT_THAT(another_map, Each(make_pair(string("fee"), 1)));
+ another_map["fee"] = 1;
+ EXPECT_THAT(another_map, Each(make_pair(string("fee"), 1)));
+ another_map["fie"] = 2;
+ another_map["foe"] = 3;
+ another_map["fum"] = 4;
+ EXPECT_THAT(another_map, Not(Each(make_pair(string("fee"), 1))));
+ EXPECT_THAT(another_map, Not(Each(make_pair(string("fum"), 1))));
+ EXPECT_THAT(another_map, Each(Pair(_, Gt(0))));
+}
+
+TEST(EachTest, AcceptsMatcher) {
+ const int a[] = { 1, 2, 3 };
+ EXPECT_THAT(a, Each(Gt(0)));
+ EXPECT_THAT(a, Not(Each(Gt(1))));
+}
+
+TEST(EachTest, WorksForNativeArrayAsTuple) {
+ const int a[] = { 1, 2 };
+ const int* const pointer = a;
+ EXPECT_THAT(make_tuple(pointer, 2), Each(Gt(0)));
+ EXPECT_THAT(make_tuple(pointer, 2), Not(Each(Gt(1))));
+}
+
+// For testing Pointwise().
+class IsHalfOfMatcher {
+ public:
+ template <typename T1, typename T2>
+ bool MatchAndExplain(const tuple<T1, T2>& a_pair,
+ MatchResultListener* listener) const {
+ if (get<0>(a_pair) == get<1>(a_pair)/2) {
+ *listener << "where the second is " << get<1>(a_pair);
+ return true;
+ } else {
+ *listener << "where the second/2 is " << get<1>(a_pair)/2;
+ return false;
+ }
+ }
+
+ void DescribeTo(ostream* os) const {
+ *os << "are a pair where the first is half of the second";
+ }
+
+ void DescribeNegationTo(ostream* os) const {
+ *os << "are a pair where the first isn't half of the second";
+ }
+};
+
+PolymorphicMatcher<IsHalfOfMatcher> IsHalfOf() {
+ return MakePolymorphicMatcher(IsHalfOfMatcher());
+}
+
+TEST(PointwiseTest, DescribesSelf) {
+ vector<int> rhs;
+ rhs.push_back(1);
+ rhs.push_back(2);
+ rhs.push_back(3);
+ const Matcher<const vector<int>&> m = Pointwise(IsHalfOf(), rhs);
+ EXPECT_EQ("contains 3 values, where each value and its corresponding value "
+ "in { 1, 2, 3 } are a pair where the first is half of the second",
+ Describe(m));
+ EXPECT_EQ("doesn't contain exactly 3 values, or contains a value x at some "
+ "index i where x and the i-th value of { 1, 2, 3 } are a pair "
+ "where the first isn't half of the second",
+ DescribeNegation(m));
+}
+
+TEST(PointwiseTest, MakesCopyOfRhs) {
+ list<signed char> rhs;
+ rhs.push_back(2);
+ rhs.push_back(4);
+
+ int lhs[] = { 1, 2 };
+ const Matcher<const int (&)[2]> m = Pointwise(IsHalfOf(), rhs);
+ EXPECT_THAT(lhs, m);
+
+ // Changing rhs now shouldn't affect m, which made a copy of rhs.
+ rhs.push_back(6);
+ EXPECT_THAT(lhs, m);
+}
+
+TEST(PointwiseTest, WorksForLhsNativeArray) {
+ const int lhs[] = { 1, 2, 3 };
+ vector<int> rhs;
+ rhs.push_back(2);
+ rhs.push_back(4);
+ rhs.push_back(6);
+ EXPECT_THAT(lhs, Pointwise(Lt(), rhs));
+ EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs)));
+}
+
+TEST(PointwiseTest, WorksForRhsNativeArray) {
+ const int rhs[] = { 1, 2, 3 };
+ vector<int> lhs;
+ lhs.push_back(2);
+ lhs.push_back(4);
+ lhs.push_back(6);
+ EXPECT_THAT(lhs, Pointwise(Gt(), rhs));
+ EXPECT_THAT(lhs, Not(Pointwise(Lt(), rhs)));
+}
+
+TEST(PointwiseTest, RejectsWrongSize) {
+ const double lhs[2] = { 1, 2 };
+ const int rhs[1] = { 0 };
+ EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs)));
+ EXPECT_EQ("which contains 2 values",
+ Explain(Pointwise(Gt(), rhs), lhs));
+
+ const int rhs2[3] = { 0, 1, 2 };
+ EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs2)));
+}
+
+TEST(PointwiseTest, RejectsWrongContent) {
+ const double lhs[3] = { 1, 2, 3 };
+ const int rhs[3] = { 2, 6, 4 };
+ EXPECT_THAT(lhs, Not(Pointwise(IsHalfOf(), rhs)));
+ EXPECT_EQ("where the value pair (2, 6) at index #1 don't match, "
+ "where the second/2 is 3",
+ Explain(Pointwise(IsHalfOf(), rhs), lhs));
+}
+
+TEST(PointwiseTest, AcceptsCorrectContent) {
+ const double lhs[3] = { 1, 2, 3 };
+ const int rhs[3] = { 2, 4, 6 };
+ EXPECT_THAT(lhs, Pointwise(IsHalfOf(), rhs));
+ EXPECT_EQ("", Explain(Pointwise(IsHalfOf(), rhs), lhs));
+}
+
+TEST(PointwiseTest, AllowsMonomorphicInnerMatcher) {
+ const double lhs[3] = { 1, 2, 3 };
+ const int rhs[3] = { 2, 4, 6 };
+ const Matcher<tuple<const double&, const int&> > m1 = IsHalfOf();
+ EXPECT_THAT(lhs, Pointwise(m1, rhs));
+ EXPECT_EQ("", Explain(Pointwise(m1, rhs), lhs));
+
+ // This type works as a tuple<const double&, const int&> can be
+ // implicitly cast to tuple<double, int>.
+ const Matcher<tuple<double, int> > m2 = IsHalfOf();
+ EXPECT_THAT(lhs, Pointwise(m2, rhs));
+ EXPECT_EQ("", Explain(Pointwise(m2, rhs), lhs));
+}
+
} // namespace gmock_matchers_test
} // namespace testing
diff --git a/testing/gmock/test/gmock-nice-strict_test.cc b/testing/gmock/test/gmock-nice-strict_test.cc
index f6f278e..0e52450 100644
--- a/testing/gmock/test/gmock-nice-strict_test.cc
+++ b/testing/gmock/test/gmock-nice-strict_test.cc
@@ -137,6 +137,7 @@ TEST(NiceMockTest, NoWarningForUninterestingCallAfterDeath) {
TEST(NiceMockTest, InfoForUninterestingCall) {
NiceMock<MockFoo> nice_foo;
+ const string saved_flag = GMOCK_FLAG(verbose);
GMOCK_FLAG(verbose) = "info";
CaptureStdout();
nice_foo.DoThis();
@@ -147,6 +148,7 @@ TEST(NiceMockTest, InfoForUninterestingCall) {
nice_foo.DoThat(true);
EXPECT_THAT(GetCapturedStdout(),
HasSubstr("Uninteresting mock function call"));
+ GMOCK_FLAG(verbose) = saved_flag;
}
#endif // GTEST_HAS_STREAM_REDIRECTION_
diff --git a/testing/gmock/test/gmock-port_test.cc b/testing/gmock/test/gmock-port_test.cc
index 054313b..a84eb9e 100644
--- a/testing/gmock/test/gmock-port_test.cc
+++ b/testing/gmock/test/gmock-port_test.cc
@@ -39,126 +39,5 @@
// NOTE: if this file is left without tests for some reason, put a dummy
// test here to make references to symbols in the gtest library and avoid
// 'undefined symbol' linker errors in gmock_main:
-//
-// TEST(DummyTest, Dummy) {}
-
-namespace testing {
-namespace internal {
-// Needed to avoid name collisions in gmock_all_test.cc.
-namespace gmock_port_test {
-
-class Base {
- public:
- // Copy constructor and assignment operator do exactly what we need, so we
- // use them.
- Base() : member_(0) {}
- explicit Base(int n) : member_(n) {}
- virtual ~Base() {}
- int member() { return member_; }
-
- private:
- int member_;
-};
-
-class Derived : public Base {
- public:
- explicit Derived(int n) : Base(n) {}
-};
-
-TEST(ImplicitCastTest, ConvertsPointers) {
- Derived derived(0);
- EXPECT_TRUE(&derived == ::testing::internal::implicit_cast<Base*>(&derived));
-}
-
-TEST(ImplicitCastTest, CanUseInheritance) {
- Derived derived(1);
- Base base = ::testing::internal::implicit_cast<Base>(derived);
- EXPECT_EQ(derived.member(), base.member());
-}
-
-class Castable {
- public:
- Castable(bool* converted) : converted_(converted) {}
- operator Base() {
- *converted_ = true;
- return Base();
- }
-
- private:
- bool* converted_;
-};
-
-TEST(ImplicitCastTest, CanUseNonConstCastOperator) {
- bool converted = false;
- Castable castable(&converted);
- Base base = ::testing::internal::implicit_cast<Base>(castable);
- EXPECT_TRUE(converted);
-}
-
-class ConstCastable {
- public:
- ConstCastable(bool* converted) : converted_(converted) {}
- operator Base() const {
- *converted_ = true;
- return Base();
- }
-
- private:
- bool* converted_;
-};
-
-TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) {
- bool converted = false;
- const ConstCastable const_castable(&converted);
- Base base = ::testing::internal::implicit_cast<Base>(const_castable);
- EXPECT_TRUE(converted);
-}
-
-class ConstAndNonConstCastable {
- public:
- ConstAndNonConstCastable(bool* converted, bool* const_converted)
- : converted_(converted), const_converted_(const_converted) {}
- operator Base() {
- *converted_ = true;
- return Base();
- }
- operator Base() const {
- *const_converted_ = true;
- return Base();
- }
-
- private:
- bool* converted_;
- bool* const_converted_;
-};
-
-TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) {
- bool converted = false;
- bool const_converted = false;
- ConstAndNonConstCastable castable(&converted, &const_converted);
- Base base = ::testing::internal::implicit_cast<Base>(castable);
- EXPECT_TRUE(converted);
- EXPECT_FALSE(const_converted);
-
- converted = false;
- const_converted = false;
- const ConstAndNonConstCastable const_castable(&converted, &const_converted);
- base = ::testing::internal::implicit_cast<Base>(const_castable);
- EXPECT_FALSE(converted);
- EXPECT_TRUE(const_converted);
-}
-
-class To {
- public:
- To(bool* converted) { *converted = true; } // NOLINT
-};
-
-TEST(ImplicitCastTest, CanUseImplicitConstructor) {
- bool converted = false;
- To to = ::testing::internal::implicit_cast<To>(&converted);
- EXPECT_TRUE(converted);
-}
-} // namespace gmock_port_test
-} // namespace internal
-} // namespace testing
+TEST(DummyTest, Dummy) {}
diff --git a/testing/gmock/test/gmock-printers_test.cc b/testing/gmock/test/gmock-printers_test.cc
deleted file mode 100644
index 92c8413..0000000
--- a/testing/gmock/test/gmock-printers_test.cc
+++ /dev/null
@@ -1,1118 +0,0 @@
-// Copyright 2007, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Google Mock - a framework for writing C++ mock classes.
-//
-// This file tests the universal value printer.
-
-#include <gmock/gmock-printers.h>
-
-#include <ctype.h>
-#include <limits.h>
-#include <string.h>
-#include <algorithm>
-#include <deque>
-#include <list>
-#include <map>
-#include <set>
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-#include <gmock/gmock-generated-matchers.h>
-#include <gmock/gmock-matchers.h>
-#include <gmock/internal/gmock-port.h>
-#include <gtest/gtest.h>
-
-// hash_map and hash_set are available on Windows.
-#if GTEST_OS_WINDOWS
-#define GMOCK_HAS_HASH_MAP_ 1 // Indicates that hash_map is available.
-#include <hash_map> // NOLINT
-#define GMOCK_HAS_HASH_SET_ 1 // Indicates that hash_set is available.
-#include <hash_set> // NOLINT
-#endif // GTEST_OS_WINDOWS
-
-// Some user-defined types for testing the universal value printer.
-
-// A user-defined unprintable class template in the global namespace.
-template <typename T>
-class UnprintableTemplateInGlobal {
- public:
- UnprintableTemplateInGlobal() : value_() {}
- private:
- T value_;
-};
-
-// A user-defined streamable type in the global namespace.
-class StreamableInGlobal {
- public:
- virtual ~StreamableInGlobal() {}
-};
-
-inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) {
- os << "StreamableInGlobal";
-}
-
-namespace foo {
-
-// A user-defined unprintable type in a user namespace.
-class UnprintableInFoo {
- public:
- UnprintableInFoo() : x_(0x12EF), y_(0xAB34), z_(0) {}
- private:
- testing::internal::Int32 x_;
- testing::internal::Int32 y_;
- double z_;
-};
-
-// A user-defined printable type in a user-chosen namespace.
-struct PrintableViaPrintTo {
- PrintableViaPrintTo() : value() {}
- int value;
-};
-
-void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) {
- *os << "PrintableViaPrintTo: " << x.value;
-}
-
-// A user-defined printable class template in a user-chosen namespace.
-template <typename T>
-class PrintableViaPrintToTemplate {
- public:
- explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {}
-
- const T& value() const { return value_; }
- private:
- T value_;
-};
-
-template <typename T>
-void PrintTo(const PrintableViaPrintToTemplate<T>& x, ::std::ostream* os) {
- *os << "PrintableViaPrintToTemplate: " << x.value();
-}
-
-// A user-defined streamable class template in a user namespace.
-template <typename T>
-class StreamableTemplateInFoo {
- public:
- StreamableTemplateInFoo() : value_() {}
-
- const T& value() const { return value_; }
- private:
- T value_;
-};
-
-template <typename T>
-inline ::std::ostream& operator<<(::std::ostream& os,
- const StreamableTemplateInFoo<T>& x) {
- return os << "StreamableTemplateInFoo: " << x.value();
-}
-
-} // namespace foo
-
-namespace testing {
-namespace gmock_printers_test {
-
-using ::std::deque;
-using ::std::list;
-using ::std::make_pair;
-using ::std::map;
-using ::std::multimap;
-using ::std::multiset;
-using ::std::pair;
-using ::std::set;
-using ::std::tr1::make_tuple;
-using ::std::tr1::tuple;
-using ::std::vector;
-using ::testing::ElementsAre;
-using ::testing::PrintToString;
-using ::testing::StartsWith;
-using ::testing::internal::NativeArray;
-using ::testing::internal::Strings;
-using ::testing::internal::UniversalTersePrint;
-using ::testing::internal::UniversalPrint;
-using ::testing::internal::UniversalTersePrintTupleFieldsToStrings;
-using ::testing::internal::UniversalPrinter;
-using ::testing::internal::kReference;
-using ::testing::internal::string;
-
-#if GTEST_OS_WINDOWS
-// MSVC defines the following classes in the ::stdext namespace while
-// gcc defines them in the :: namespace. Note that they are not part
-// of the C++ standard.
-
-using ::stdext::hash_map;
-using ::stdext::hash_set;
-using ::stdext::hash_multimap;
-using ::stdext::hash_multiset;
-
-#endif // GTEST_OS_WINDOWS
-
-// Prints a value to a string using the universal value printer. This
-// is a helper for testing UniversalPrinter<T>::Print() for various types.
-template <typename T>
-string Print(const T& value) {
- ::std::stringstream ss;
- UniversalPrinter<T>::Print(value, &ss);
- return ss.str();
-}
-
-// Prints a value passed by reference to a string, using the universal
-// value printer. This is a helper for testing
-// UniversalPrinter<T&>::Print() for various types.
-template <typename T>
-string PrintByRef(const T& value) {
- ::std::stringstream ss;
- UniversalPrinter<T&>::Print(value, &ss);
- return ss.str();
-}
-
-// Tests printing various char types.
-
-// char.
-TEST(PrintCharTest, PlainChar) {
- EXPECT_EQ("'\\0'", Print('\0'));
- EXPECT_EQ("'\\'' (39)", Print('\''));
- EXPECT_EQ("'\"' (34)", Print('"'));
- EXPECT_EQ("'\\?' (63)", Print('\?'));
- EXPECT_EQ("'\\\\' (92)", Print('\\'));
- EXPECT_EQ("'\\a' (7)", Print('\a'));
- EXPECT_EQ("'\\b' (8)", Print('\b'));
- EXPECT_EQ("'\\f' (12)", Print('\f'));
- EXPECT_EQ("'\\n' (10)", Print('\n'));
- EXPECT_EQ("'\\r' (13)", Print('\r'));
- EXPECT_EQ("'\\t' (9)", Print('\t'));
- EXPECT_EQ("'\\v' (11)", Print('\v'));
- EXPECT_EQ("'\\x7F' (127)", Print('\x7F'));
- EXPECT_EQ("'\\xFF' (255)", Print('\xFF'));
- EXPECT_EQ("' ' (32)", Print(' '));
- EXPECT_EQ("'a' (97)", Print('a'));
-}
-
-// signed char.
-TEST(PrintCharTest, SignedChar) {
- EXPECT_EQ("'\\0'", Print(static_cast<signed char>('\0')));
- EXPECT_EQ("'\\xCE' (-50)",
- Print(static_cast<signed char>(-50)));
-}
-
-// unsigned char.
-TEST(PrintCharTest, UnsignedChar) {
- EXPECT_EQ("'\\0'", Print(static_cast<unsigned char>('\0')));
- EXPECT_EQ("'b' (98)",
- Print(static_cast<unsigned char>('b')));
-}
-
-// Tests printing other simple, built-in types.
-
-// bool.
-TEST(PrintBuiltInTypeTest, Bool) {
- EXPECT_EQ("false", Print(false));
- EXPECT_EQ("true", Print(true));
-}
-
-// wchar_t.
-TEST(PrintBuiltInTypeTest, Wchar_t) {
- EXPECT_EQ("L'\\0'", Print(L'\0'));
- EXPECT_EQ("L'\\'' (39)", Print(L'\''));
- EXPECT_EQ("L'\"' (34)", Print(L'"'));
- EXPECT_EQ("L'\\?' (63)", Print(L'\?'));
- EXPECT_EQ("L'\\\\' (92)", Print(L'\\'));
- EXPECT_EQ("L'\\a' (7)", Print(L'\a'));
- EXPECT_EQ("L'\\b' (8)", Print(L'\b'));
- EXPECT_EQ("L'\\f' (12)", Print(L'\f'));
- EXPECT_EQ("L'\\n' (10)", Print(L'\n'));
- EXPECT_EQ("L'\\r' (13)", Print(L'\r'));
- EXPECT_EQ("L'\\t' (9)", Print(L'\t'));
- EXPECT_EQ("L'\\v' (11)", Print(L'\v'));
- EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F'));
- EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF'));
- EXPECT_EQ("L' ' (32)", Print(L' '));
- EXPECT_EQ("L'a' (97)", Print(L'a'));
- EXPECT_EQ("L'\\x576' (1398)", Print(L'\x576'));
- EXPECT_EQ("L'\\xC74D' (51021)", Print(L'\xC74D'));
-}
-
-// Test that Int64 provides more storage than wchar_t.
-TEST(PrintTypeSizeTest, Wchar_t) {
- EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64));
-}
-
-// Various integer types.
-TEST(PrintBuiltInTypeTest, Integer) {
- EXPECT_EQ("'\\xFF' (255)", Print(static_cast<unsigned char>(255))); // uint8
- EXPECT_EQ("'\\x80' (-128)", Print(static_cast<signed char>(-128))); // int8
- EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16
- EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16
- EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32
- EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32
- EXPECT_EQ("18446744073709551615",
- Print(static_cast<testing::internal::UInt64>(-1))); // uint64
- EXPECT_EQ("-9223372036854775808",
- Print(static_cast<testing::internal::Int64>(1) << 63)); // int64
-}
-
-// Size types.
-TEST(PrintBuiltInTypeTest, Size_t) {
- EXPECT_EQ("1", Print(sizeof('a'))); // size_t.
-#if !GTEST_OS_WINDOWS
- // Windows has no ssize_t type.
- EXPECT_EQ("-2", Print(static_cast<ssize_t>(-2))); // ssize_t.
-#endif // !GTEST_OS_WINDOWS
-}
-
-// Floating-points.
-TEST(PrintBuiltInTypeTest, FloatingPoints) {
- EXPECT_EQ("1.5", Print(1.5f)); // float
- EXPECT_EQ("-2.5", Print(-2.5)); // double
-}
-
-// Since ::std::stringstream::operator<<(const void *) formats the pointer
-// output differently with different compilers, we have to create the expected
-// output first and use it as our expectation.
-static string PrintPointer(const void *p) {
- ::std::stringstream expected_result_stream;
- expected_result_stream << p;
- return expected_result_stream.str();
-}
-
-// Tests printing C strings.
-
-// const char*.
-TEST(PrintCStringTest, Const) {
- const char* p = "World";
- EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p));
-}
-
-// char*.
-TEST(PrintCStringTest, NonConst) {
- char p[] = "Hi";
- EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"",
- Print(static_cast<char*>(p)));
-}
-
-// NULL C string.
-TEST(PrintCStringTest, Null) {
- const char* p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// Tests that C strings are escaped properly.
-TEST(PrintCStringTest, EscapesProperly) {
- const char* p = "'\"\?\\\a\b\f\n\r\t\v\x7F\xFF a";
- EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"\\?\\\\\\a\\b\\f"
- "\\n\\r\\t\\v\\x7F\\xFF a\"",
- Print(p));
-}
-
-
-
-// MSVC compiler can be configured to define whar_t as a typedef
-// of unsigned short. Defining an overload for const wchar_t* in that case
-// would cause pointers to unsigned shorts be printed as wide strings,
-// possibly accessing more memory than intended and causing invalid
-// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
-// wchar_t is implemented as a native type.
-#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
-
-// const wchar_t*.
-TEST(PrintWideCStringTest, Const) {
- const wchar_t* p = L"World";
- EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p));
-}
-
-// wchar_t*.
-TEST(PrintWideCStringTest, NonConst) {
- wchar_t p[] = L"Hi";
- EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"",
- Print(static_cast<wchar_t*>(p)));
-}
-
-// NULL wide C string.
-TEST(PrintWideCStringTest, Null) {
- const wchar_t* p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// Tests that wide C strings are escaped properly.
-TEST(PrintWideCStringTest, EscapesProperly) {
- const wchar_t* p = L"'\"\?\\\a\b\f\n\r\t\v\xD3\x576\x8D3\xC74D a";
- EXPECT_EQ(PrintPointer(p) + " pointing to L\"'\\\"\\?\\\\\\a\\b\\f"
- "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"",
- Print(p));
-}
-#endif // native wchar_t
-
-// Tests printing pointers to other char types.
-
-// signed char*.
-TEST(PrintCharPointerTest, SignedChar) {
- signed char* p = reinterpret_cast<signed char*>(0x1234);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// const signed char*.
-TEST(PrintCharPointerTest, ConstSignedChar) {
- signed char* p = reinterpret_cast<signed char*>(0x1234);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// unsigned char*.
-TEST(PrintCharPointerTest, UnsignedChar) {
- unsigned char* p = reinterpret_cast<unsigned char*>(0x1234);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// const unsigned char*.
-TEST(PrintCharPointerTest, ConstUnsignedChar) {
- const unsigned char* p = reinterpret_cast<const unsigned char*>(0x1234);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// Tests printing pointers to simple, built-in types.
-
-// bool*.
-TEST(PrintPointerToBuiltInTypeTest, Bool) {
- bool* p = reinterpret_cast<bool*>(0xABCD);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// void*.
-TEST(PrintPointerToBuiltInTypeTest, Void) {
- void* p = reinterpret_cast<void*>(0xABCD);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// const void*.
-TEST(PrintPointerToBuiltInTypeTest, ConstVoid) {
- const void* p = reinterpret_cast<const void*>(0xABCD);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// Tests printing pointers to pointers.
-TEST(PrintPointerToPointerTest, IntPointerPointer) {
- int** p = reinterpret_cast<int**>(0xABCD);
- EXPECT_EQ(PrintPointer(p), Print(p));
- p = NULL;
- EXPECT_EQ("NULL", Print(p));
-}
-
-// Tests printing (non-member) function pointers.
-
-void MyFunction(int /* n */) {}
-
-TEST(PrintPointerTest, NonMemberFunctionPointer) {
- // We cannot directly cast &MyFunction to const void* because the
- // standard disallows casting between pointers to functions and
- // pointers to objects, and some compilers (e.g. GCC 3.4) enforce
- // this limitation.
- EXPECT_EQ(
- PrintPointer(reinterpret_cast<const void*>(
- reinterpret_cast<internal::BiggestInt>(&MyFunction))),
- Print(&MyFunction));
- int (*p)(bool) = NULL; // NOLINT
- EXPECT_EQ("NULL", Print(p));
-}
-
-// Tests printing member variable pointers. Although they are called
-// pointers, they don't point to a location in the address space.
-// Their representation is implementation-defined. Thus they will be
-// printed as raw bytes.
-
-struct Foo {
- public:
- virtual ~Foo() {}
- int MyMethod(char x) { return x + 1; }
- virtual char MyVirtualMethod(int /* n */) { return 'a'; }
-
- int value;
-};
-
-TEST(PrintPointerTest, MemberVariablePointer) {
- EXPECT_THAT(Print(&Foo::value),
- StartsWith(Print(sizeof(&Foo::value)) + "-byte object "));
- int (Foo::*p) = NULL; // NOLINT
- EXPECT_THAT(Print(p),
- StartsWith(Print(sizeof(p)) + "-byte object "));
-}
-
-// Tests printing member function pointers. Although they are called
-// pointers, they don't point to a location in the address space.
-// Their representation is implementation-defined. Thus they will be
-// printed as raw bytes.
-TEST(PrintPointerTest, MemberFunctionPointer) {
- EXPECT_THAT(Print(&Foo::MyMethod),
- StartsWith(Print(sizeof(&Foo::MyMethod)) + "-byte object "));
- EXPECT_THAT(Print(&Foo::MyVirtualMethod),
- StartsWith(Print(sizeof((&Foo::MyVirtualMethod)))
- + "-byte object "));
- int (Foo::*p)(char) = NULL; // NOLINT
- EXPECT_THAT(Print(p),
- StartsWith(Print(sizeof(p)) + "-byte object "));
-}
-
-// Tests printing C arrays.
-
-// The difference between this and Print() is that it ensures that the
-// argument is a reference to an array.
-template <typename T, size_t N>
-string PrintArrayHelper(T (&a)[N]) {
- return Print(a);
-}
-
-// One-dimensional array.
-TEST(PrintArrayTest, OneDimensionalArray) {
- int a[5] = { 1, 2, 3, 4, 5 };
- EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a));
-}
-
-// Two-dimensional array.
-TEST(PrintArrayTest, TwoDimensionalArray) {
- int a[2][5] = {
- { 1, 2, 3, 4, 5 },
- { 6, 7, 8, 9, 0 }
- };
- EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a));
-}
-
-// Array of const elements.
-TEST(PrintArrayTest, ConstArray) {
- const bool a[1] = { false };
- EXPECT_EQ("{ false }", PrintArrayHelper(a));
-}
-
-// Char array.
-TEST(PrintArrayTest, CharArray) {
- // Array a contains '\0' in the middle and doesn't end with '\0'.
- char a[3] = { 'H', '\0', 'i' };
- EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a));
-}
-
-// Const char array.
-TEST(PrintArrayTest, ConstCharArray) {
- const char a[4] = "\0Hi";
- EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a));
-}
-
-// Array of objects.
-TEST(PrintArrayTest, ObjectArray) {
- string a[3] = { "Hi", "Hello", "Ni hao" };
- EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a));
-}
-
-// Array with many elements.
-TEST(PrintArrayTest, BigArray) {
- int a[100] = { 1, 2, 3 };
- EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }",
- PrintArrayHelper(a));
-}
-
-// Tests printing ::string and ::std::string.
-
-#if GTEST_HAS_GLOBAL_STRING
-// ::string.
-TEST(PrintStringTest, StringInGlobalNamespace) {
- const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a";
- const ::string str(s, sizeof(s));
- EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"",
- Print(str));
-}
-#endif // GTEST_HAS_GLOBAL_STRING
-
-// ::std::string.
-TEST(PrintStringTest, StringInStdNamespace) {
- const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a";
- const ::std::string str(s, sizeof(s));
- EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"",
- Print(str));
-}
-
-// Tests printing ::wstring and ::std::wstring.
-
-#if GTEST_HAS_GLOBAL_WSTRING
-// ::wstring.
-TEST(PrintWideStringTest, StringInGlobalNamespace) {
- const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a";
- const ::wstring str(s, sizeof(s)/sizeof(wchar_t));
- EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v"
- "\\xD3\\x576\\x8D3\\xC74D a\\0\"",
- Print(str));
-}
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-#if GTEST_HAS_STD_WSTRING
-// ::std::wstring.
-TEST(PrintWideStringTest, StringInStdNamespace) {
- const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a";
- const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t));
- EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v"
- "\\xD3\\x576\\x8D3\\xC74D a\\0\"",
- Print(str));
-}
-#endif // GTEST_HAS_STD_WSTRING
-
-// Tests printing types that support generic streaming (i.e. streaming
-// to std::basic_ostream<Char, CharTraits> for any valid Char and
-// CharTraits types).
-
-// Tests printing a non-template type that supports generic streaming.
-
-class AllowsGenericStreaming {};
-
-template <typename Char, typename CharTraits>
-std::basic_ostream<Char, CharTraits>& operator<<(
- std::basic_ostream<Char, CharTraits>& os,
- const AllowsGenericStreaming& /* a */) {
- return os << "AllowsGenericStreaming";
-}
-
-TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) {
- AllowsGenericStreaming a;
- EXPECT_EQ("AllowsGenericStreaming", Print(a));
-}
-
-// Tests printing a template type that supports generic streaming.
-
-template <typename T>
-class AllowsGenericStreamingTemplate {};
-
-template <typename Char, typename CharTraits, typename T>
-std::basic_ostream<Char, CharTraits>& operator<<(
- std::basic_ostream<Char, CharTraits>& os,
- const AllowsGenericStreamingTemplate<T>& /* a */) {
- return os << "AllowsGenericStreamingTemplate";
-}
-
-TEST(PrintTypeWithGenericStreamingTest, TemplateType) {
- AllowsGenericStreamingTemplate<int> a;
- EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a));
-}
-
-// Tests printing a type that supports generic streaming and can be
-// implicitly converted to another printable type.
-
-template <typename T>
-class AllowsGenericStreamingAndImplicitConversionTemplate {
- public:
- operator bool() const { return false; }
-};
-
-template <typename Char, typename CharTraits, typename T>
-std::basic_ostream<Char, CharTraits>& operator<<(
- std::basic_ostream<Char, CharTraits>& os,
- const AllowsGenericStreamingAndImplicitConversionTemplate<T>& /* a */) {
- return os << "AllowsGenericStreamingAndImplicitConversionTemplate";
-}
-
-TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) {
- AllowsGenericStreamingAndImplicitConversionTemplate<int> a;
- EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a));
-}
-
-// Tests printing STL containers.
-
-TEST(PrintStlContainerTest, EmptyDeque) {
- deque<char> empty;
- EXPECT_EQ("{}", Print(empty));
-}
-
-TEST(PrintStlContainerTest, NonEmptyDeque) {
- deque<int> non_empty;
- non_empty.push_back(1);
- non_empty.push_back(3);
- EXPECT_EQ("{ 1, 3 }", Print(non_empty));
-}
-
-#if GMOCK_HAS_HASH_MAP_
-
-TEST(PrintStlContainerTest, OneElementHashMap) {
- hash_map<int, char> map1;
- map1[1] = 'a';
- EXPECT_EQ("{ (1, 'a' (97)) }", Print(map1));
-}
-
-TEST(PrintStlContainerTest, HashMultiMap) {
- hash_multimap<int, bool> map1;
- map1.insert(make_pair(5, true));
- map1.insert(make_pair(5, false));
-
- // Elements of hash_multimap can be printed in any order.
- const string result = Print(map1);
- EXPECT_TRUE(result == "{ (5, true), (5, false) }" ||
- result == "{ (5, false), (5, true) }")
- << " where Print(map1) returns \"" << result << "\".";
-}
-
-#endif // GMOCK_HAS_HASH_MAP_
-
-#if GMOCK_HAS_HASH_SET_
-
-TEST(PrintStlContainerTest, HashSet) {
- hash_set<string> set1;
- set1.insert("hello");
- EXPECT_EQ("{ \"hello\" }", Print(set1));
-}
-
-TEST(PrintStlContainerTest, HashMultiSet) {
- const int kSize = 5;
- int a[kSize] = { 1, 1, 2, 5, 1 };
- hash_multiset<int> set1(a, a + kSize);
-
- // Elements of hash_multiset can be printed in any order.
- const string result = Print(set1);
- const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit.
-
- // Verifies the result matches the expected pattern; also extracts
- // the numbers in the result.
- ASSERT_EQ(expected_pattern.length(), result.length());
- std::vector<int> numbers;
- for (size_t i = 0; i != result.length(); i++) {
- if (expected_pattern[i] == 'd') {
- ASSERT_TRUE(isdigit(result[i]) != 0);
- numbers.push_back(result[i] - '0');
- } else {
- EXPECT_EQ(expected_pattern[i], result[i]) << " where result is "
- << result;
- }
- }
-
- // Makes sure the result contains the right numbers.
- std::sort(numbers.begin(), numbers.end());
- std::sort(a, a + kSize);
- EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin()));
-}
-
-#endif // GMOCK_HAS_HASH_SET_
-
-TEST(PrintStlContainerTest, List) {
- const char* a[] = {
- "hello",
- "world"
- };
- const list<string> strings(a, a + 2);
- EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings));
-}
-
-TEST(PrintStlContainerTest, Map) {
- map<int, bool> map1;
- map1[1] = true;
- map1[5] = false;
- map1[3] = true;
- EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1));
-}
-
-TEST(PrintStlContainerTest, MultiMap) {
- multimap<bool, int> map1;
- map1.insert(make_pair(true, 0));
- map1.insert(make_pair(true, 1));
- map1.insert(make_pair(false, 2));
- EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1));
-}
-
-TEST(PrintStlContainerTest, Set) {
- const unsigned int a[] = { 3, 0, 5 };
- set<unsigned int> set1(a, a + 3);
- EXPECT_EQ("{ 0, 3, 5 }", Print(set1));
-}
-
-TEST(PrintStlContainerTest, MultiSet) {
- const int a[] = { 1, 1, 2, 5, 1 };
- multiset<int> set1(a, a + 5);
- EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1));
-}
-
-TEST(PrintStlContainerTest, Pair) {
- pair<const bool, int> p(true, 5);
- EXPECT_EQ("(true, 5)", Print(p));
-}
-
-TEST(PrintStlContainerTest, Vector) {
- vector<int> v;
- v.push_back(1);
- v.push_back(2);
- EXPECT_EQ("{ 1, 2 }", Print(v));
-}
-
-TEST(PrintStlContainerTest, LongSequence) {
- const int a[100] = { 1, 2, 3 };
- const vector<int> v(a, a + 100);
- EXPECT_EQ("{ 1, 2, 3, 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, ... }", Print(v));
-}
-
-TEST(PrintStlContainerTest, NestedContainer) {
- const int a1[] = { 1, 2 };
- const int a2[] = { 3, 4, 5 };
- const list<int> l1(a1, a1 + 2);
- const list<int> l2(a2, a2 + 3);
-
- vector<list<int> > v;
- v.push_back(l1);
- v.push_back(l2);
- EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v));
-}
-
-TEST(PrintStlContainerTest, OneDimensionalNativeArray) {
- const int a[3] = { 1, 2, 3 };
- NativeArray<int> b(a, 3, kReference);
- EXPECT_EQ("{ 1, 2, 3 }", Print(b));
-}
-
-TEST(PrintStlContainerTest, TwoDimensionalNativeArray) {
- const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
- NativeArray<int[3]> b(a, 2, kReference);
- EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b));
-}
-
-// Tests printing tuples.
-
-// Tuples of various arities.
-TEST(PrintTupleTest, VariousSizes) {
- tuple<> t0;
- EXPECT_EQ("()", Print(t0));
-
- tuple<int> t1(5);
- EXPECT_EQ("(5)", Print(t1));
-
- tuple<char, bool> t2('a', true);
- EXPECT_EQ("('a' (97), true)", Print(t2));
-
- tuple<bool, int, int> t3(false, 2, 3);
- EXPECT_EQ("(false, 2, 3)", Print(t3));
-
- tuple<bool, int, int, int> t4(false, 2, 3, 4);
- EXPECT_EQ("(false, 2, 3, 4)", Print(t4));
-
- tuple<bool, int, int, int, bool> t5(false, 2, 3, 4, true);
- EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5));
-
- tuple<bool, int, int, int, bool, int> t6(false, 2, 3, 4, true, 6);
- EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6));
-
- tuple<bool, int, int, int, bool, int, int> t7(false, 2, 3, 4, true, 6, 7);
- EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7));
-
- tuple<bool, int, int, int, bool, int, int, bool> t8(
- false, 2, 3, 4, true, 6, 7, true);
- EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8));
-
- tuple<bool, int, int, int, bool, int, int, bool, int> t9(
- false, 2, 3, 4, true, 6, 7, true, 9);
- EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9));
-
- const char* const str = "8";
- tuple<bool, char, short, testing::internal::Int32, // NOLINT
- testing::internal::Int64, float, double, const char*, void*, string>
- t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, NULL, "10");
- EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) +
- " pointing to \"8\", NULL, \"10\")",
- Print(t10));
-}
-
-// Nested tuples.
-TEST(PrintTupleTest, NestedTuple) {
- tuple<tuple<int, bool>, char> nested(make_tuple(5, true), 'a');
- EXPECT_EQ("((5, true), 'a' (97))", Print(nested));
-}
-
-// Tests printing user-defined unprintable types.
-
-// Unprintable types in the global namespace.
-TEST(PrintUnprintableTypeTest, InGlobalNamespace) {
- EXPECT_EQ("1-byte object <00>",
- Print(UnprintableTemplateInGlobal<bool>()));
-}
-
-// Unprintable types in a user namespace.
-TEST(PrintUnprintableTypeTest, InUserNamespace) {
- EXPECT_EQ("16-byte object <EF12 0000 34AB 0000 0000 0000 0000 0000>",
- Print(::foo::UnprintableInFoo()));
-}
-
-// Unprintable types are that too big to be printed completely.
-
-struct Big {
- Big() { memset(array, 0, sizeof(array)); }
- char array[257];
-};
-
-TEST(PrintUnpritableTypeTest, BigObject) {
- EXPECT_EQ("257-byte object <0000 0000 0000 0000 0000 0000 "
- "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
- "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
- "0000 0000 0000 0000 0000 0000 ... 0000 0000 0000 "
- "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
- "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
- "0000 0000 0000 0000 0000 0000 0000 0000 00>",
- Print(Big()));
-}
-
-// Tests printing user-defined streamable types.
-
-// Streamable types in the global namespace.
-TEST(PrintStreamableTypeTest, InGlobalNamespace) {
- EXPECT_EQ("StreamableInGlobal",
- Print(StreamableInGlobal()));
-}
-
-// Printable template types in a user namespace.
-TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) {
- EXPECT_EQ("StreamableTemplateInFoo: 0",
- Print(::foo::StreamableTemplateInFoo<int>()));
-}
-
-// Tests printing user-defined types that have a PrintTo() function.
-TEST(PrintPrintableTypeTest, InUserNamespace) {
- EXPECT_EQ("PrintableViaPrintTo: 0",
- Print(::foo::PrintableViaPrintTo()));
-}
-
-// Tests printing user-defined class template that have a PrintTo() function.
-TEST(PrintPrintableTypeTest, TemplateInUserNamespace) {
- EXPECT_EQ("PrintableViaPrintToTemplate: 5",
- Print(::foo::PrintableViaPrintToTemplate<int>(5)));
-}
-
-#if GMOCK_HAS_PROTOBUF_
-
-// Tests printing a protocol message.
-TEST(PrintProtocolMessageTest, PrintsShortDebugString) {
- testing::internal::TestMessage msg;
- msg.set_member("yes");
- EXPECT_EQ("<member:\"yes\">", Print(msg));
-}
-
-// Tests printing a short proto2 message.
-TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort) {
- testing::internal::FooMessage msg;
- msg.set_int_field(2);
- msg.set_string_field("hello");
- EXPECT_PRED2(RE::FullMatch, Print(msg),
- "<int_field:\\s*2\\s+string_field:\\s*\"hello\">");
-}
-
-// Tests printing a long proto2 message.
-TEST(PrintProto2MessageTest, PrintsDebugStringWhenItIsLong) {
- testing::internal::FooMessage msg;
- msg.set_int_field(2);
- msg.set_string_field("hello");
- msg.add_names("peter");
- msg.add_names("paul");
- msg.add_names("mary");
- EXPECT_PRED2(RE::FullMatch, Print(msg),
- "<\n"
- "int_field:\\s*2\n"
- "string_field:\\s*\"hello\"\n"
- "names:\\s*\"peter\"\n"
- "names:\\s*\"paul\"\n"
- "names:\\s*\"mary\"\n"
- ">");
-}
-
-#endif // GMOCK_HAS_PROTOBUF_
-
-// Tests that the universal printer prints both the address and the
-// value of a reference.
-TEST(PrintReferenceTest, PrintsAddressAndValue) {
- int n = 5;
- EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n));
-
- int a[2][3] = {
- { 0, 1, 2 },
- { 3, 4, 5 }
- };
- EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }",
- PrintByRef(a));
-
- const ::foo::UnprintableInFoo x;
- EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object "
- "<EF12 0000 34AB 0000 0000 0000 0000 0000>",
- PrintByRef(x));
-}
-
-// Tests that the universal printer prints a function pointer passed by
-// reference.
-TEST(PrintReferenceTest, HandlesFunctionPointer) {
- void (*fp)(int n) = &MyFunction;
- const string fp_pointer_string =
- PrintPointer(reinterpret_cast<const void*>(&fp));
- // We cannot directly cast &MyFunction to const void* because the
- // standard disallows casting between pointers to functions and
- // pointers to objects, and some compilers (e.g. GCC 3.4) enforce
- // this limitation.
- const string fp_string = PrintPointer(reinterpret_cast<const void*>(
- reinterpret_cast<internal::BiggestInt>(fp)));
- EXPECT_EQ("@" + fp_pointer_string + " " + fp_string,
- PrintByRef(fp));
-}
-
-// Tests that the universal printer prints a member function pointer
-// passed by reference.
-TEST(PrintReferenceTest, HandlesMemberFunctionPointer) {
- int (Foo::*p)(char ch) = &Foo::MyMethod;
- EXPECT_THAT(PrintByRef(p),
- StartsWith("@" + PrintPointer(reinterpret_cast<const void*>(&p))
- + " " + Print(sizeof(p)) + "-byte object "));
-
- char (Foo::*p2)(int n) = &Foo::MyVirtualMethod;
- EXPECT_THAT(PrintByRef(p2),
- StartsWith("@" + PrintPointer(reinterpret_cast<const void*>(&p2))
- + " " + Print(sizeof(p2)) + "-byte object "));
-}
-
-// Tests that the universal printer prints a member variable pointer
-// passed by reference.
-TEST(PrintReferenceTest, HandlesMemberVariablePointer) {
- int (Foo::*p) = &Foo::value; // NOLINT
- EXPECT_THAT(PrintByRef(p),
- StartsWith("@" + PrintPointer(&p)
- + " " + Print(sizeof(p)) + "-byte object "));
-}
-
-TEST(PrintToStringTest, WorksForScalar) {
- EXPECT_EQ("123", PrintToString(123));
-}
-
-TEST(PrintToStringTest, WorksForPointerToConstChar) {
- const char* p = "hello";
- EXPECT_EQ("\"hello\"", PrintToString(p));
-}
-
-TEST(PrintToStringTest, WorksForPointerToNonConstChar) {
- char s[] = "hello";
- char* p = s;
- EXPECT_EQ("\"hello\"", PrintToString(p));
-}
-
-TEST(PrintToStringTest, WorksForArray) {
- int n[3] = { 1, 2, 3 };
- EXPECT_EQ("{ 1, 2, 3 }", PrintToString(n));
-}
-
-TEST(UniversalTersePrintTest, WorksForNonReference) {
- ::std::stringstream ss;
- UniversalTersePrint(123, &ss);
- EXPECT_EQ("123", ss.str());
-}
-
-TEST(UniversalTersePrintTest, WorksForReference) {
- const int& n = 123;
- ::std::stringstream ss;
- UniversalTersePrint(n, &ss);
- EXPECT_EQ("123", ss.str());
-}
-
-TEST(UniversalTersePrintTest, WorksForCString) {
- const char* s1 = "abc";
- ::std::stringstream ss1;
- UniversalTersePrint(s1, &ss1);
- EXPECT_EQ("\"abc\"", ss1.str());
-
- char* s2 = const_cast<char*>(s1);
- ::std::stringstream ss2;
- UniversalTersePrint(s2, &ss2);
- EXPECT_EQ("\"abc\"", ss2.str());
-
- const char* s3 = NULL;
- ::std::stringstream ss3;
- UniversalTersePrint(s3, &ss3);
- EXPECT_EQ("NULL", ss3.str());
-}
-
-TEST(UniversalPrintTest, WorksForNonReference) {
- ::std::stringstream ss;
- UniversalPrint(123, &ss);
- EXPECT_EQ("123", ss.str());
-}
-
-TEST(UniversalPrintTest, WorksForReference) {
- const int& n = 123;
- ::std::stringstream ss;
- UniversalPrint(n, &ss);
- EXPECT_EQ("123", ss.str());
-}
-
-TEST(UniversalPrintTest, WorksForCString) {
- const char* s1 = "abc";
- ::std::stringstream ss1;
- UniversalPrint(s1, &ss1);
- EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str()));
-
- char* s2 = const_cast<char*>(s1);
- ::std::stringstream ss2;
- UniversalPrint(s2, &ss2);
- EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str()));
-
- const char* s3 = NULL;
- ::std::stringstream ss3;
- UniversalPrint(s3, &ss3);
- EXPECT_EQ("NULL", ss3.str());
-}
-
-
-TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple) {
- EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple()),
- ElementsAre());
-}
-
-TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsOneTuple) {
- EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple(1)),
- ElementsAre("1"));
-}
-
-TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTwoTuple) {
- EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(make_tuple(1, 'a')),
- ElementsAre("1", "'a' (97)"));
-}
-
-TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTersely) {
- const int n = 1;
- EXPECT_THAT(UniversalTersePrintTupleFieldsToStrings(
- tuple<const int&, const char*>(n, "a")),
- ElementsAre("1", "\"a\""));
-}
-
-} // namespace gmock_printers_test
-} // namespace testing
diff --git a/testing/gmock/test/gmock-spec-builders_test.cc b/testing/gmock/test/gmock-spec-builders_test.cc
index e5fc2ec..ff30f02 100644
--- a/testing/gmock/test/gmock-spec-builders_test.cc
+++ b/testing/gmock/test/gmock-spec-builders_test.cc
@@ -1783,6 +1783,25 @@ class MockC {
GTEST_DISALLOW_COPY_AND_ASSIGN_(MockC);
};
+class VerboseFlagPreservingFixture : public testing::Test {
+ protected:
+ // The code needs to work when both ::string and ::std::string are defined
+ // and the flag is implemented as a testing::internal::String. In this
+ // case, without the call to c_str(), the compiler will complain that it
+ // cannot figure out what overload of string constructor to use.
+ // TODO(vladl@google.com): Use internal::string instead of String for
+ // string flags in Google Test.
+ VerboseFlagPreservingFixture()
+ : saved_verbose_flag_(GMOCK_FLAG(verbose).c_str()) {}
+
+ ~VerboseFlagPreservingFixture() { GMOCK_FLAG(verbose) = saved_verbose_flag_; }
+
+ private:
+ const string saved_verbose_flag_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(VerboseFlagPreservingFixture);
+};
+
#if GTEST_HAS_STREAM_REDIRECTION_
// Tests that an uninteresting mock function call generates a warning
@@ -1842,7 +1861,7 @@ TEST(FunctionCallMessageTest, UninterestingCallPrintsArgumentsAndReturnValue) {
// Tests how the --gmock_verbose flag affects Google Mock's output.
-class GMockVerboseFlagTest : public testing::Test {
+class GMockVerboseFlagTest : public VerboseFlagPreservingFixture {
public:
// Verifies that the given Google Mock output is correct. (When
// should_print is true, the output should match the given regex and
@@ -1982,22 +2001,9 @@ class LogTestHelper {
GTEST_DISALLOW_COPY_AND_ASSIGN_(LogTestHelper);
};
-class GMockLogTest : public ::testing::Test {
+class GMockLogTest : public VerboseFlagPreservingFixture {
protected:
- virtual void SetUp() {
- // The code needs to work when both ::string and ::std::string are
- // defined and the flag is implemented as a
- // testing::internal::String. In this case, without the call to
- // c_str(), the compiler will complain that it cannot figure out
- // whether the String flag should be converted to a ::string or an
- // ::std::string before being assigned to original_verbose_.
- original_verbose_ = GMOCK_FLAG(verbose).c_str();
- }
-
- virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; }
-
LogTestHelper helper_;
- string original_verbose_;
};
TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsWarning) {
@@ -2358,9 +2364,23 @@ TEST(VerifyAndClearTest, DoesNotAffectOtherMockObjects) {
// action or as a default action without causing a dead lock. It
// verifies that the action is not performed inside the critical
// section.
+TEST(SynchronizationTest, CanCallMockMethodInAction) {
+ MockA a;
+ MockC c;
+ ON_CALL(a, DoA(_))
+ .WillByDefault(IgnoreResult(InvokeWithoutArgs(&c,
+ &MockC::NonVoidMethod)));
+ EXPECT_CALL(a, DoA(1));
+ EXPECT_CALL(a, DoA(1))
+ .WillOnce(Invoke(&a, &MockA::DoA))
+ .RetiresOnSaturation();
+ EXPECT_CALL(c, NonVoidMethod());
-void Helper(MockC* c) {
- c->NonVoidMethod();
+ a.DoA(1);
+ // This will match the second EXPECT_CALL() and trigger another a.DoA(1),
+ // which will in turn match the first EXPECT_CALL() and trigger a call to
+ // c.NonVoidMethod() that was specified by the ON_CALL() since the first
+ // EXPECT_CALL() did not specify an action.
}
} // namespace
diff --git a/testing/gmock/test/gmock_all_test.cc b/testing/gmock/test/gmock_all_test.cc
index 7361259..691aac8 100644
--- a/testing/gmock/test/gmock_all_test.cc
+++ b/testing/gmock/test/gmock_all_test.cc
@@ -44,6 +44,5 @@
#include "test/gmock-more-actions_test.cc"
#include "test/gmock-nice-strict_test.cc"
#include "test/gmock-port_test.cc"
-#include "test/gmock-printers_test.cc"
#include "test/gmock-spec-builders_test.cc"
#include "test/gmock_test.cc"
diff --git a/testing/gmock/test/gmock_output_test.py b/testing/gmock/test/gmock_output_test.py
index 614a58f..eced8a8 100755
--- a/testing/gmock/test/gmock_output_test.py
+++ b/testing/gmock/test/gmock_output_test.py
@@ -32,7 +32,7 @@
"""Tests the text output of Google C++ Mocking Framework.
SYNOPSIS
- gmock_output_test.py --gmock_build_dir=BUILD/DIR --gengolden
+ gmock_output_test.py --build_dir=BUILD/DIR --gengolden
# where BUILD/DIR contains the built gmock_output_test_ file.
gmock_output_test.py --gengolden
gmock_output_test.py
diff --git a/testing/gmock/test/gmock_output_test_golden.txt b/testing/gmock/test/gmock_output_test_golden.txt
index 382dc8c..a7ff563 100644
--- a/testing/gmock/test/gmock_output_test_golden.txt
+++ b/testing/gmock/test/gmock_output_test_golden.txt
@@ -151,7 +151,7 @@ FILE:#: pre-requisite #1
[ RUN ] GMockOutputTest.UnsatisfiedWith
FILE:#: Failure
Actual function call count doesn't match EXPECT_CALL(foo_, Bar2(_, _))...
- Expected args: are a pair (x, y) where x >= y
+ Expected args: are a pair where the first >= the second
Expected: to be called once
Actual: never called - unsatisfied and active
[ FAILED ] GMockOutputTest.UnsatisfiedWith
@@ -190,7 +190,7 @@ Unexpected mock function call - returning default value.
Google Mock tried the following 1 expectation, but it didn't match:
FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))...
- Expected args: are a pair (x, y) where x >= y
+ Expected args: are a pair where the first >= the second
Actual: don't match
Expected: to be called once
Actual: never called - unsatisfied and active
@@ -206,7 +206,7 @@ Google Mock tried the following 1 expectation, but it didn't match:
FILE:#: EXPECT_CALL(foo_, Bar2(Ge(2), Ge(1)))...
Expected arg #0: is >= 2
Actual: 1
- Expected args: are a pair (x, y) where x >= y
+ Expected args: are a pair where the first >= the second
Actual: don't match
Expected: to be called once
Actual: never called - unsatisfied and active
diff --git a/testing/gmock/test/gmock_test_utils.py b/testing/gmock/test/gmock_test_utils.py
index fa896a4..ac3d67a 100755
--- a/testing/gmock/test/gmock_test_utils.py
+++ b/testing/gmock/test/gmock_test_utils.py
@@ -51,62 +51,10 @@ sys.path.append(GTEST_TESTS_UTIL_DIR)
import gtest_test_utils # pylint: disable-msg=C6204
-# Initially maps a flag to its default value. After
-# _ParseAndStripGMockFlags() is called, maps a flag to its actual
-# value.
-_flag_map = {'gmock_source_dir': os.path.dirname(sys.argv[0]),
- 'gmock_build_dir': os.path.dirname(sys.argv[0])}
-_gmock_flags_are_parsed = False
-
-
-def _ParseAndStripGMockFlags(argv):
- """Parses and strips Google Test flags from argv. This is idempotent."""
-
- global _gmock_flags_are_parsed
- if _gmock_flags_are_parsed:
- return
-
- _gmock_flags_are_parsed = True
- for flag in _flag_map:
- # The environment variable overrides the default value.
- if flag.upper() in os.environ:
- _flag_map[flag] = os.environ[flag.upper()]
-
- # The command line flag overrides the environment variable.
- i = 1 # Skips the program name.
- while i < len(argv):
- prefix = '--' + flag + '='
- if argv[i].startswith(prefix):
- _flag_map[flag] = argv[i][len(prefix):]
- del argv[i]
- break
- else:
- # We don't increment i in case we just found a --gmock_* flag
- # and removed it from argv.
- i += 1
-
-
-def GetFlag(flag):
- """Returns the value of the given flag."""
-
- # In case GetFlag() is called before Main(), we always call
- # _ParseAndStripGMockFlags() here to make sure the --gmock_* flags
- # are parsed.
- _ParseAndStripGMockFlags(sys.argv)
-
- return _flag_map[flag]
-
-
def GetSourceDir():
"""Returns the absolute path of the directory where the .py files are."""
- return os.path.abspath(GetFlag('gmock_source_dir'))
-
-
-def GetBuildDir():
- """Returns the absolute path of the directory where the test binaries are."""
-
- return os.path.abspath(GetFlag('gmock_build_dir'))
+ return gtest_test_utils.GetSourceDir()
def GetTestExecutablePath(executable_name):
@@ -122,7 +70,7 @@ def GetTestExecutablePath(executable_name):
The absolute path of the test binary.
"""
- return gtest_test_utils.GetTestExecutablePath(executable_name, GetBuildDir())
+ return gtest_test_utils.GetTestExecutablePath(executable_name)
def GetExitStatus(exit_code):
@@ -160,8 +108,4 @@ TestCase = gtest_test_utils.TestCase
def Main():
"""Runs the unit test."""
- # We must call _ParseAndStripGMockFlags() before calling
- # gtest_test_utils.Main(). Otherwise unittest.main it calls will be
- # confused by the --gmock_* flags.
- _ParseAndStripGMockFlags(sys.argv)
gtest_test_utils.Main()
diff --git a/testing/gmockmain.target.mk b/testing/gmockmain.target.mk
index b406484..229e244 100644
--- a/testing/gmockmain.target.mk
+++ b/testing/gmockmain.target.mk
@@ -18,6 +18,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -50,6 +51,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -94,11 +96,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/testing/gtest.gyp b/testing/gtest.gyp
index c8f64e5..da95f42 100644
--- a/testing/gtest.gyp
+++ b/testing/gtest.gyp
@@ -9,10 +9,10 @@
'type': '<(library)',
'msvs_guid': 'BFE8E2A7-3B3B-43B0-A994-3058B852DB8B',
'sources': [
- # Sources based on files in r267 of gmock.
'gtest/include/gtest/gtest-death-test.h',
'gtest/include/gtest/gtest-message.h',
'gtest/include/gtest/gtest-param-test.h',
+ 'gtest/include/gtest/gtest-printers.h',
'gtest/include/gtest/gtest-spi.h',
'gtest/include/gtest/gtest-test-part.h',
'gtest/include/gtest/gtest-typed-test.h',
@@ -34,6 +34,7 @@
'gtest/src/gtest-filepath.cc',
'gtest/src/gtest-internal-inl.h',
'gtest/src/gtest-port.cc',
+ 'gtest/src/gtest-printers.cc',
'gtest/src/gtest-test-part.cc',
'gtest/src/gtest-typed-test.cc',
'gtest/src/gtest.cc',
@@ -51,6 +52,8 @@
'conditions': [
['OS == "mac"', {
'sources': [
+ 'gtest_mac.h',
+ 'gtest_mac.mm',
'platform_test_mac.mm'
],
'link_settings': {
@@ -76,6 +79,20 @@
],
},
}],
+ ['clang==1', {
+ # We want gtest features that use tr1::tuple, but clang currently
+ # doesn't support the variadic templates used by libstdc++'s
+ # implementation. gtest supports this scenario by providing its
+ # own implementation but we must opt in to it.
+ 'defines': [
+ 'GTEST_USE_OWN_TR1_TUPLE=1',
+ ],
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'GTEST_USE_OWN_TR1_TUPLE=1',
+ ],
+ },
+ }],
],
'direct_dependent_settings': {
'defines': [
diff --git a/testing/gtest.target.mk b/testing/gtest.target.mk
index 07503b6..1db9611 100644
--- a/testing/gtest.target.mk
+++ b/testing/gtest.target.mk
@@ -17,6 +17,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -48,6 +49,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -68,6 +70,7 @@ INCS_Release := -Itesting/gtest \
OBJS := $(obj).target/$(TARGET)/testing/gtest/src/gtest-death-test.o \
$(obj).target/$(TARGET)/testing/gtest/src/gtest-filepath.o \
$(obj).target/$(TARGET)/testing/gtest/src/gtest-port.o \
+ $(obj).target/$(TARGET)/testing/gtest/src/gtest-printers.o \
$(obj).target/$(TARGET)/testing/gtest/src/gtest-test-part.o \
$(obj).target/$(TARGET)/testing/gtest/src/gtest-typed-test.o \
$(obj).target/$(TARGET)/testing/gtest/src/gtest.o \
@@ -98,11 +101,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/testing/gtest/CMakeLists.txt b/testing/gtest/CMakeLists.txt
index 4c80bde..4a978a1 100644
--- a/testing/gtest/CMakeLists.txt
+++ b/testing/gtest/CMakeLists.txt
@@ -8,12 +8,25 @@
# ctest. You can select which tests to run using 'ctest -R regex'.
# For more options, run 'ctest --help'.
-# For hermetic builds, we may need to tell CMake to use compiler in a
-# specific location.
-if (gtest_compiler)
- include(CMakeForceCompiler)
- cmake_force_c_compiler("${gtest_compiler}" "")
- cmake_force_cxx_compiler("${gtest_compiler}" "")
+# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
+# make it prominent in the GUI.
+option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
+
+# When other libraries are using a shared version of runtime libraries,
+# Google Test also has to use one.
+option(
+ gtest_force_shared_crt
+ "Use shared (DLL) run-time lib even when Google Test is built as static lib."
+ OFF)
+
+option(gtest_build_tests "Build all of gtest's own tests." OFF)
+
+option(gtest_build_samples "Build gtest's sample programs." OFF)
+
+include(cmake/hermetic_build.cmake OPTIONAL)
+
+if (COMMAND pre_project_set_up_hermetic_build)
+ pre_project_set_up_hermetic_build()
endif()
########################################################################
@@ -27,122 +40,35 @@ endif()
# ${gtest_BINARY_DIR}.
# Language "C" is required for find_package(Threads).
project(gtest CXX C)
-cmake_minimum_required(VERSION 2.6.4)
-
-if (MSVC)
- # For MSVC, CMake sets certain flags to defaults we want to override.
- # This replacement code is taken from sample in the CMake Wiki at
- # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace.
- foreach (flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- # In hermetic build environments, tests may not have access to MS runtime
- # DLLs, so this replaces /MD (CRT libraries in DLLs) with /MT (static CRT
- # libraries).
- string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
- # We prefer more strict warning checking for building Google Test.
- # Replaces /W3 with /W4 in defaults.
- string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}")
- endforeach()
+cmake_minimum_required(VERSION 2.6.2)
+
+if (COMMAND set_up_hermetic_build)
+ set_up_hermetic_build()
endif()
-# Where gtest's .h files can be found.
+# Defines functions and variables used by Google Test.
+include(cmake/internal_utils.cmake)
+
+fix_default_settings() # Defined in internal_utils.cmake.
+
+# Where Google Test's .h files can be found.
include_directories(
${gtest_SOURCE_DIR}/include
${gtest_SOURCE_DIR})
-# Where the gtest libraries can be found.
-link_directories(
- ${gtest_BINARY_DIR}/src)
-
-# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
-find_package(Threads)
-
-# Defines the compiler/linker flags used to build gtest. You can
-# tweak these definitions to suit your need. A variable's value is
-# empty before it's explicitly assigned to.
-
-if (MSVC)
- # Newlines inside flags variables break CMake's NMake generator.
- set(cxx_base_flags "-GS -W4 -WX -wd4275 -nologo -J -Zi")
- set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
- set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
- set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
- set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0")
- set(cxx_no_rtti_flags "-GR-")
-elseif (CMAKE_COMPILER_IS_GNUCXX)
- set(cxx_base_flags "-Wall -Wshadow")
- set(cxx_exception_flags "-fexceptions")
- set(cxx_no_exception_flags "-fno-exceptions")
- # Until version 4.3.2, GCC doesn't define a macro to indicate
- # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
- # explicitly.
- set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
- set(cxx_strict_flags "-Wextra")
-elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "SunPro")
- set(cxx_exception_flags "-features=except")
- # Sun Pro doesn't provide macros to indicate whether exceptions and
- # RTTI are enabled, so we define GTEST_HAS_* explicitly.
- set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0")
- set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0")
-elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "VisualAge")
- set(cxx_exception_flags "-qeh")
- set(cxx_no_exception_flags "-qnoeh")
- # Until version 9.0, Visual Age doesn't define a macro to indicate
- # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
- # explicitly.
- set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0")
-endif()
-
-if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available.
- set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1")
-endif()
-
-# For building gtest's own tests and samples.
-set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}")
-set(cxx_no_exception
- "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
-set(cxx_default "${cxx_exception}")
-set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
-set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1")
-
-# For building the gtest libraries.
-set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
+# Where Google Test's libraries can be found.
+link_directories(${gtest_BINARY_DIR}/src)
########################################################################
#
# Defines the gtest & gtest_main libraries. User tests should link
# with one of them.
-function(cxx_library_with_type name type cxx_flags)
- # type can be either STATIC or SHARED to denote a static or shared library.
- # ARGN refers to additional arguments after 'cxx_flags'.
- add_library(${name} ${type} ${ARGN})
- set_target_properties(${name}
- PROPERTIES
- COMPILE_FLAGS "${cxx_flags}")
- if (CMAKE_USE_PTHREADS_INIT)
- target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT})
- endif()
-endfunction()
-
-function(cxx_static_library name cxx_flags)
- cxx_library_with_type(${name} STATIC "${cxx_flags}" ${ARGN})
-endfunction()
-
-function(cxx_shared_library name cxx_flags)
- cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN})
-endfunction()
-
-function(cxx_library name cxx_flags)
- # TODO(vladl@google.com): Make static/shared a user option.
- cxx_static_library(${name} "${cxx_flags}" ${ARGN})
-endfunction()
-
-# Static versions of Google Test libraries. We build them using more
-# strict warnings than what are used for other targets, to ensure that
-# gtest can be compiled by a user aggressive about warnings.
-cxx_static_library(gtest "${cxx_strict}" src/gtest-all.cc)
-cxx_static_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
+
+# Google Test libraries. We build them using more strict warnings than what
+# are used for other targets, to ensure that gtest can be compiled by a user
+# aggressive about warnings.
+cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
+cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
target_link_libraries(gtest_main gtest)
########################################################################
@@ -150,36 +76,10 @@ target_link_libraries(gtest_main gtest)
# Samples on how to link user tests with gtest or gtest_main.
#
# They are not built by default. To build them, set the
-# build_gtest_samples option to ON. You can do it by running ccmake
+# gtest_build_samples option to ON. You can do it by running ccmake
# or specifying the -Dbuild_gtest_samples=ON flag when running cmake.
-option(build_gtest_samples "Build gtest's sample programs." OFF)
-
-# cxx_executable_with_flags(name cxx_flags lib srcs...)
-#
-# creates a named C++ executable that depends on the given library and
-# is built from the given source files with the given compiler flags.
-function(cxx_executable_with_flags name cxx_flags lib)
- add_executable(${name} ${ARGN})
- if (cxx_flags)
- set_target_properties(${name}
- PROPERTIES
- COMPILE_FLAGS "${cxx_flags}")
- endif()
- target_link_libraries(${name} ${lib})
-endfunction()
-
-# cxx_executable(name dir lib srcs...)
-#
-# creates a named target that depends on the given lib and is built
-# from the given source files. dir/name.cc is implicitly included in
-# the source file list.
-function(cxx_executable name dir lib)
- cxx_executable_with_flags(
- ${name} "${cxx_default}" ${lib} "${dir}/${name}.cc" ${ARGN})
-endfunction()
-
-if (build_gtest_samples)
+if (gtest_build_samples)
cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc)
cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc)
cxx_executable(sample3_unittest samples gtest_main)
@@ -199,52 +99,18 @@ endif()
# You can skip this section if you aren't interested in testing
# Google Test itself.
#
-# Most of the tests are not built by default. To build them, set the
-# build_all_gtest_tests option to ON. You can do it by running ccmake
-# or specifying the -Dbuild_all_gtest_tests=ON flag when running cmake.
-
-option(build_all_gtest_tests "Build all of gtest's own tests." OFF)
-
-# This must be set in the root directory for the tests to be run by
-# 'make test' or ctest.
-enable_testing()
+# The tests are not built by default. To build them, set the
+# gtest_build_tests option to ON. You can do it by running ccmake
+# or specifying the -Dgtest_build_tests=ON flag when running cmake.
-# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE.
-find_package(PythonInterp)
+if (gtest_build_tests)
+ # This must be set in the root directory for the tests to be run by
+ # 'make test' or ctest.
+ enable_testing()
-############################################################
-# C++ tests built with standard compiler flags.
+ ############################################################
+ # C++ tests built with standard compiler flags.
-# cxx_test_with_flags(name cxx_flags libs srcs...)
-#
-# creates a named C++ test that depends on the given libs and is built
-# from the given source files with the given compiler flags.
-function(cxx_test_with_flags name cxx_flags libs)
- add_executable(${name} ${ARGN})
- set_target_properties(${name}
- PROPERTIES
- COMPILE_FLAGS "${cxx_flags}")
- # To support mixing linking in static and dynamic libraries, link each
- # library in with an extra call to target_link_libraries.
- foreach (lib "${libs}")
- target_link_libraries(${name} ${lib})
- endforeach()
- add_test(${name} ${name})
-endfunction()
-
-# cxx_test(name libs srcs...)
-#
-# creates a named test target that depends on the given libs and is
-# built from the given source files. Unlike cxx_test_with_flags,
-# test/name.cc is already implicitly included in the source file list.
-function(cxx_test name libs)
- cxx_test_with_flags("${name}" "${cxx_default}" "${libs}"
- "test/${name}.cc" ${ARGN})
-endfunction()
-
-cxx_test(gtest_unittest gtest_main)
-
-if (build_all_gtest_tests)
cxx_test(gtest-death-test_test gtest_main)
cxx_test(gtest_environment_test gtest)
cxx_test(gtest-filepath_test gtest_main)
@@ -258,6 +124,7 @@ if (build_all_gtest_tests)
test/gtest-param-test2_test.cc)
cxx_test(gtest-port_test gtest_main)
cxx_test(gtest_pred_impl_unittest gtest_main)
+ cxx_test(gtest-printers_test gtest_main)
cxx_test(gtest_prod_test gtest_main
test/production.cc)
cxx_test(gtest_repeat_test gtest)
@@ -267,13 +134,12 @@ if (build_all_gtest_tests)
cxx_test(gtest_throw_on_failure_ex_test gtest)
cxx_test(gtest-typed-test_test gtest_main
test/gtest-typed-test2_test.cc)
+ cxx_test(gtest_unittest gtest_main)
cxx_test(gtest-unittest-api_test gtest)
-endif()
-############################################################
-# C++ tests built with non-standard compiler flags.
+ ############################################################
+ # C++ tests built with non-standard compiler flags.
-if (build_all_gtest_tests)
cxx_library(gtest_no_exception "${cxx_no_exception}"
src/gtest-all.cc)
cxx_library(gtest_main_no_rtti "${cxx_no_rtti}"
@@ -282,26 +148,16 @@ if (build_all_gtest_tests)
cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
gtest_main_no_rtti test/gtest_unittest.cc)
- set(cxx_use_shared_gtest "${cxx_default} -DGTEST_LINKED_AS_SHARED_LIBRARY=1")
- set(cxx_build_shared_gtest "${cxx_default} -DGTEST_CREATE_SHARED_LIBRARY=1")
- if (MSVC)
- # Disables the "class 'X' needs to have dll-interface to be used
- # by clients of class 'Y'" warning. This particularly concerns generic
- # classes like vector that MS doesn't mark as exported.
- set(cxx_use_shared_gtest "${cxx_use_shared_gtest} -wd4251")
- set(cxx_build_shared_gtest "${cxx_build_shared_gtest} -wd4251")
- endif()
-
- cxx_shared_library(gtest_dll "${cxx_build_shared_gtest}"
- src/gtest-all.cc)
+ cxx_shared_library(gtest_dll "${cxx_default}"
+ src/gtest-all.cc src/gtest_main.cc)
- # TODO(vladl): This and the next tests may not run in the hermetic
- # environment on Windows. Re-evaluate and possibly make them
- # platform-conditional after implementing hermetic builds.
- cxx_executable_with_flags(gtest_dll_test_ "${cxx_use_shared_gtest}"
+ cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}"
gtest_dll test/gtest_all_test.cc)
+ set_target_properties(gtest_dll_test_
+ PROPERTIES
+ COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
- if (NOT(MSVC AND (MSVC_VERSION EQUAL 1600)))
+ if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600)
# The C++ Standard specifies tuple_element<int, class>.
# Yet MSVC 10's <utility> declares tuple_element<size_t, class>.
# That declaration conflicts with our own standard-conforming
@@ -318,28 +174,9 @@ if (build_all_gtest_tests)
test/gtest-param-test_test.cc test/gtest-param-test2_test.cc)
endif()
-endif()
-
-############################################################
-# Python tests.
-
-# py_test(name)
-#
-# creates a Python test with the given name whose main module is in
-# test/name.py. It does nothing if Python is not installed.
-function(py_test name)
- if (PYTHONINTERP_FOUND)
- # ${gtest_BINARY_DIR} is known at configuration time, so we can
- # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known
- # only at ctest runtime (by calling ctest -c <Configuration>), so
- # we have to escape $ to delay variable substitution here.
- add_test(${name}
- ${PYTHON_EXECUTABLE} ${gtest_SOURCE_DIR}/test/${name}.py
- --gtest_build_dir=${gtest_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE})
- endif()
-endfunction()
+ ############################################################
+ # Python tests.
-if (build_all_gtest_tests)
cxx_executable(gtest_break_on_failure_unittest_ test gtest)
py_test(gtest_break_on_failure_unittest)
diff --git a/testing/gtest/Makefile.am b/testing/gtest/Makefile.am
index 2ac14ca..c661db0 100644
--- a/testing/gtest/Makefile.am
+++ b/testing/gtest/Makefile.am
@@ -1,6 +1,6 @@
# Automake file
-# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump.
+ACLOCAL_AMFLAGS = -I m4
# Nonstandard package files for distribution
EXTRA_DIST = \
@@ -16,16 +16,20 @@ EXTRA_DIST = \
scripts/pump.py \
scripts/test/Makefile
-# gtest source files that we don't compile directly.
-EXTRA_DIST += \
+# gtest source files that we don't compile directly. They are
+# #included by gtest-all.cc.
+GTEST_SRC = \
src/gtest.cc \
src/gtest-death-test.cc \
src/gtest-filepath.cc \
src/gtest-internal-inl.h \
src/gtest-port.cc \
+ src/gtest-printers.cc \
src/gtest-test-part.cc \
src/gtest-typed-test.cc
+EXTRA_DIST += $(GTEST_SRC)
+
# Sample files that we don't compile.
EXTRA_DIST += \
samples/prime_tables.h \
@@ -51,6 +55,7 @@ EXTRA_DIST += \
test/gtest-param-test2_test.cc \
test/gtest-param-test_test.h \
test/gtest-port_test.cc \
+ test/gtest-printers_test.cc \
test/gtest_pred_impl_unittest.cc \
test/gtest_prod_test.cc \
test/production.cc \
@@ -154,11 +159,6 @@ EXTRA_DIST += \
codegear/gtest_unittest.cbproj \
codegear/gtest.groupproj
-# TODO(wan@google.com): integrate scripts/gen_gtest_pred_impl.py into
-# the build system such that a user can specify the maximum predicate
-# arity here and have the script automatically generate the
-# corresponding .h and .cc files.
-
# Scripts and utilities
bin_SCRIPTS = scripts/gtest-config
CLEANFILES = $(bin_SCRIPTS)
@@ -190,6 +190,7 @@ pkginclude_HEADERS = include/gtest/gtest.h \
include/gtest/gtest-message.h \
include/gtest/gtest-param-test.h \
include/gtest/gtest_pred_impl.h \
+ include/gtest/gtest-printers.h \
include/gtest/gtest_prod.h \
include/gtest/gtest-spi.h \
include/gtest/gtest-test-part.h \
@@ -254,35 +255,35 @@ test_gtest_all_test_SOURCES = test/gtest_all_test.cc
test_gtest_all_test_LDADD = lib/libgtest_main.la
# Tests that fused gtest files compile and work.
-TESTS += test/gtest_fused_test
-check_PROGRAMS += test/gtest_fused_test
-test_gtest_fused_test_SOURCES = fused-src/gtest/gtest-all.cc \
- fused-src/gtest/gtest_main.cc \
- fused-src/gtest/gtest.h \
+FUSED_GTEST_SRC = \
+ fused-src/gtest/gtest-all.cc \
+ fused-src/gtest/gtest_main.cc \
+ fused-src/gtest/gtest.h
+
+TESTS += test/fused_gtest_test
+check_PROGRAMS += test/fused_gtest_test
+test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \
samples/sample1.cc samples/sample1_unittest.cc
-test_gtest_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src"
+test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src"
# Build rules for putting fused Google Test files into the distribution
# package. The user can also create those files by manually running
# scripts/fuse_gtest_files.py.
-$(srcdir)/fused-src/gtest/gtest-all.cc: fused-gtest-internal
-
-$(srcdir)/fused-src/gtest/gtest.h: fused-gtest-internal
+$(test_fused_gtest_test_SOURCES): fused-gtest
-fused-gtest-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
- $(lib_libgtest_la_SOURCES) \
- scripts/fuse_gtest_files.py
- mkdir -p "$(srcdir)/fused-src/gtest"
+fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
+ $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \
+ scripts/fuse_gtest_files.py
+ mkdir -p "$(srcdir)/fused-src"
chmod -R u+w "$(srcdir)/fused-src"
rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc"
rm -f "$(srcdir)/fused-src/gtest/gtest.h"
"$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src"
-
-$(srcdir)/fused-src/gtest/gtest_main.cc: src/gtest_main.cc
- mkdir -p "$(srcdir)/fused-src/gtest"
- chmod -R u+w "$(srcdir)/fused-src"
- cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest"
+ cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/"
maintainer-clean-local:
- chmod -R u+w "$(srcdir)/fused-src"
- rm -rf "$(srcdir)/fused-src/gtest"
+ rm -rf "$(srcdir)/fused-src"
+
+# Death tests may produce core dumps in the build directory. In case
+# this happens, clean them to keep distcleancheck happy.
+CLEANFILES += core
diff --git a/testing/gtest/README b/testing/gtest/README
index 5205303..792abf3 100644
--- a/testing/gtest/README
+++ b/testing/gtest/README
@@ -1,273 +1,395 @@
Google C++ Testing Framework
============================
+
http://code.google.com/p/googletest/
Overview
--------
-Google's framework for writing C++ tests on a variety of platforms (Linux, Mac
-OS X, Windows, Windows CE, Symbian, and etc). Based on the xUnit architecture.
-Supports automatic test discovery, a rich set of assertions, user-defined
-assertions, death tests, fatal and non-fatal failures, various options for
-running the tests, and XML test report generation.
-
-Please see the project page above for more information as well as mailing lists
-for questions, discussions, and development. There is also an IRC channel on
-OFTC (irc.oftc.net) #gtest available. Please join us!
-
-Requirements
-------------
+
+Google's framework for writing C++ tests on a variety of platforms
+(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the
+xUnit architecture. Supports automatic test discovery, a rich set of
+assertions, user-defined assertions, death tests, fatal and non-fatal
+failures, various options for running the tests, and XML test report
+generation.
+
+Please see the project page above for more information as well as the
+mailing list for questions, discussions, and development. There is
+also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
+join us!
+
+Requirements for End Users
+--------------------------
+
Google Test is designed to have fairly minimal requirements to build
-and use with your projects, but there are some. Currently, we support
-building Google Test on Linux, Windows, Mac OS X, and Cygwin. We will
-also make our best effort to support other platforms (e.g. Solaris and
-IBM z/OS). However, since core members of the Google Test project
-have no access to them, Google Test may have outstanding issues on
-these platforms. If you notice any problems on your platform, please
-notify googletestframework@googlegroups.com (patches for fixing them
-are even more welcome!).
+and use with your projects, but there are some. Currently, we support
+Linux, Windows, Mac OS X, and Cygwin. We will also make our best
+effort to support other platforms (e.g. Solaris, AIX, and z/OS).
+However, since core members of the Google Test project have no access
+to these platforms, Google Test may have outstanding issues there. If
+you notice any problems on your platform, please notify
+googletestframework@googlegroups.com. Patches for fixing them are
+even more welcome!
### Linux Requirements ###
+
These are the base requirements to build and use Google Test from a source
package (as described below):
- * GNU-compatible Make or "gmake"
+ * GNU-compatible Make or gmake
* POSIX-standard shell
* POSIX(-2) Regular Expressions (regex.h)
- * A C++98 standards compliant compiler
-
-Furthermore, if you are building Google Test from a VCS Checkout (also
-described below), there are further requirements:
- * Automake version 1.9 or newer
- * Autoconf version 2.59 or newer
- * Libtool / Libtoolize
- * Python version 2.4 or newer
+ * A C++98-standard-compliant compiler
### Windows Requirements ###
- * Microsoft Visual Studio 7.1 or newer
+
+ * Microsoft Visual C++ 7.1 or newer
### Cygwin Requirements ###
+
* Cygwin 1.5.25-14 or newer
### Mac OS X Requirements ###
+
* Mac OS X 10.4 Tiger or newer
* Developer Tools Installed
- * Optional: Xcode 2.5 or later for univeral-binary framework; see note below.
+
+Also, you'll need CMake 2.6.4 or higher if you want to build the
+samples using the provided CMake script, regardless of the platform.
+
+Requirements for Contributors
+-----------------------------
+
+We welcome patches. If you plan to contribute a patch, you need to
+build Google Test and its own tests from an SVN checkout (described
+below), which has further requirements:
+
+ * Python version 2.3 or newer (for running some of the tests and
+ re-generating certain source files from templates)
+ * CMake 2.6.4 or newer
Getting the Source
------------------
-There are two primary ways of getting Google Test's source code: you can
-download a source release in your preferred archive format, or directly check
-out the source from a Version Control System (VCS, we use Google Code's
-Subversion hosting). The VCS checkout requires a few extra steps and some extra
-software packages on your system, but lets you track development, and make
-patches to contribute much more easily, so we highly encourage it.
-
-### VCS Checkout: ###
-The first step is to select whether you want to check out the main line of
-development on Google Test, or one of the released branches. The former will be
-much more active and have the latest features, but the latter provides much
-more stability and predictability. Choose whichever fits your needs best, and
-proceed with the following Subversion commands:
+
+There are two primary ways of getting Google Test's source code: you
+can download a stable source release in your preferred archive format,
+or directly check out the source from our Subversion (SVN) repositary.
+The SVN checkout requires a few extra steps and some extra software
+packages on your system, but lets you track the latest development and
+make patches much more easily, so we highly encourage it.
+
+### Source Package ###
+
+Google Test is released in versioned source packages which can be
+downloaded from the download page [1]. Several different archive
+formats are provided, but the only difference is the tools used to
+manipulate them, and the size of the resulting file. Download
+whichever you are most comfortable with.
+
+ [1] http://code.google.com/p/googletest/downloads/list
+
+Once the package is downloaded, expand it using whichever tools you
+prefer for that type. This will result in a new directory with the
+name "gtest-X.Y.Z" which contains all of the source code. Here are
+some examples on Linux:
+
+ tar -xvzf gtest-X.Y.Z.tar.gz
+ tar -xvjf gtest-X.Y.Z.tar.bz2
+ unzip gtest-X.Y.Z.zip
+
+### SVN Checkout ###
+
+To check out the main branch (also known as the "trunk") of Google
+Test, run the following Subversion command:
svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
-or for a release version X.Y.*'s branch:
+Setting up the Build
+--------------------
- svn checkout http://googletest.googlecode.com/svn/branches/release-X.Y/ \
- gtest-X.Y-svn
+To build Google Test and your tests that use it, you need to tell your
+build system where to find its headers and source files. The exact
+way to do it depends on which build system you use, and is usually
+straightforward.
-Next you will need to prepare the GNU Autotools build system, if you
-are using Linux, Mac OS X, or Cygwin. Enter the target directory of
-the checkout command you used ('gtest-svn' or 'gtest-X.Y-svn' above)
-and proceed with the following command:
+### Generic Build Instructions ###
- autoreconf -fvi
+Suppose you put Google Test in directory ${GTEST_DIR}. To build it,
+create a library build target (or a project as called by Visual Studio
+and Xcode) to compile
-Once you have completed this step, you are ready to build the library. Note
-that you should only need to complete this step once. The subsequent `make'
-invocations will automatically re-generate the bits of the build system that
-need to be changed.
+ ${GTEST_DIR}/src/gtest-all.cc
-If your system uses older versions of the autotools, the above command will
-fail. You may need to explicitly specify a version to use. For instance, if you
-have both GNU Automake 1.4 and 1.9 installed and `automake' would invoke the
-1.4, use instead:
+with
- AUTOMAKE=automake-1.9 ACLOCAL=aclocal-1.9 autoreconf -fvi
+ ${GTEST_DIR}/include and ${GTEST_DIR}
-Make sure you're using the same version of automake and aclocal.
+in the header search path. Assuming a Linux-like system and gcc,
+something like the following will do:
-### Source Package: ###
-Google Test is also released in source packages which can be downloaded from
-its Google Code download page[1]. Several different archive formats are
-provided, but the only difference is the tools used to manipulate them, and the
-size of the resulting file. Download whichever you are most comfortable with.
+ g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
+ ar -rv libgtest.a gtest-all.o
- [1] Google Test Downloads: http://code.google.com/p/googletest/downloads/list
+Next, you should compile your test source file with
+${GTEST_DIR}/include in the header search path, and link it with gtest
+and any other necessary libraries:
-Once downloaded expand the archive using whichever tools you prefer for that
-type. This will always result in a new directory with the name "gtest-X.Y.Z"
-which contains all of the source code. Here are some examples in Linux:
+ g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test
- tar -xvzf gtest-X.Y.Z.tar.gz
- tar -xvjf gtest-X.Y.Z.tar.bz2
- unzip gtest-X.Y.Z.zip
+As an example, the make/ directory contains a Makefile that you can
+use to build Google Test on systems where GNU make is available
+(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
+Test's own tests. Instead, it just builds the Google Test library and
+a sample test. You can use it as a starting point for your own build
+script.
+
+If the default settings are correct for your environment, the
+following commands should succeed:
+
+ cd ${GTEST_DIR}/make
+ make
+ ./sample1_unittest
+
+If you see errors, try to tweak the contents of make/Makefile to make
+them go away. There are instructions in make/Makefile on how to do
+it.
+
+### Using CMake ###
+
+Google Test comes with a CMake build script (CMakeLists.txt) that can
+be used on a wide range of platforms ("C" stands for cross-platofrm.).
+If you don't have CMake installed already, you can download it for
+free from http://www.cmake.org/.
+
+CMake works by generating native makefiles or build projects that can
+be used in the compiler environment of your choice. The typical
+workflow starts with:
+
+ mkdir mybuild # Create a directory to hold the build output.
+ cd mybuild
+ cmake ${GTEST_DIR} # Generate native build scripts.
+
+If you want to build Google Test's samples, you should replace the
+last command with
+
+ cmake -Dgtest_build_samples=ON ${GTEST_DIR}
+
+If you are on a *nix system, you should now see a Makefile in the
+current directory. Just type 'make' to build gtest.
+
+If you use Windows and have Vistual Studio installed, a gtest.sln file
+and several .vcproj files will be created. You can then build them
+using Visual Studio.
+
+On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
+
+### Legacy Build Scripts ###
+
+Before settling on CMake, we have been providing hand-maintained build
+projects/scripts for Visual Studio, Xcode, and Autotools. While we
+continue to provide them for convenience, they are not actively
+maintained any more. We highly recommend that you follow the
+instructions in the previous two sections to integrate Google Test
+with your existing build system.
+
+If you still need to use the legacy build scripts, here's how:
+
+The msvc\ folder contains two solutions with Visual C++ projects.
+Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
+are ready to build Google Test the same way you build any Visual
+Studio project. Files that have names ending with -md use DLL
+versions of Microsoft runtime libraries (the /MD or the /MDd compiler
+option). Files without that suffix use static versions of the runtime
+libraries (the /MT or the /MTd option). Please note that one must use
+the same option to compile both gtest and the test code. If you use
+Visual Studio 2005 or above, we recommend the -md version as /MD is
+the default for new projects in these versions of Visual Studio.
+
+On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
+Xcode. Build the "gtest" target. The universal binary framework will
+end up in your selected build directory (selected in the Xcode
+"Preferences..." -> "Building" pane and defaults to xcode/build).
+Alternatively, at the command line, enter:
+
+ xcodebuild
+
+This will build the "Release" configuration of gtest.framework in your
+default build location. See the "xcodebuild" man page for more
+information about building different configurations and building in
+different locations.
+
+Tweaking Google Test
+--------------------
+
+Google Test can be used in diverse environments. The default
+configuration may not work (or may not work well) out of the box in
+some environments. However, you can easily tweak Google Test by
+defining control macros on the compiler command line. Generally,
+these macros are named like GTEST_XYZ and you define them to either 1
+or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below. For a complete list,
+see file include/gtest/internal/gtest-port.h.
+
+### Choosing a TR1 Tuple Library ###
-Choosing a TR1 Tuple Library
-----------------------------
Some Google Test features require the C++ Technical Report 1 (TR1)
-tuple library, which is not yet widely available with all compilers.
-The good news is that Google Test implements a subset of TR1 tuple
-that's enough for its own need, and will automatically use this when
-the compiler doesn't provide TR1 tuple.
+tuple library, which is not yet available with all compilers. The
+good news is that Google Test implements a subset of TR1 tuple that's
+enough for its own need, and will automatically use this when the
+compiler doesn't provide TR1 tuple.
Usually you don't need to care about which tuple library Google Test
uses. However, if your project already uses TR1 tuple, you need to
tell Google Test to use the same TR1 tuple library the rest of your
-project uses (this requirement is new in Google Test 1.4.0, so you may
-need to take care of it when upgrading from an earlier version), or
-the two tuple implementations will clash. To do that, add
+project uses, or the two tuple implementations will clash. To do
+that, add
-DGTEST_USE_OWN_TR1_TUPLE=0
-to the compiler flags while compiling Google Test and your tests.
+to the compiler flags while compiling Google Test and your tests. If
+you want to force Google Test to use its own tuple library, just add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=1
+
+to the compiler flags instead.
If you don't want Google Test to use tuple at all, add
-DGTEST_HAS_TR1_TUPLE=0
-to the compiler flags. All features using tuple will be disabled in
-this mode.
-
-Building the Source
--------------------
-### Linux, Mac OS X (without Xcode), and Cygwin ###
-There are two primary options for building the source at this point: build it
-inside the source code tree, or in a separate directory. We recommend building
-in a separate directory as that tends to produce both more consistent results
-and be easier to clean up should anything go wrong, but both patterns are
-supported. The only hard restriction is that while the build directory can be
-a subdirectory of the source directory, the opposite is not possible and will
-result in errors. Once you have selected where you wish to build Google Test,
-create the directory if necessary, and enter it. The following steps apply for
-either approach by simply substituting the shell variable SRCDIR with "." for
-building inside the source directory, and the relative path to the source
-directory otherwise.
-
- ${SRCDIR}/configure # Standard GNU configure script, --help for more info
- make # Standard makefile following GNU conventions
- make check # Builds and runs all tests - all should pass
-
-### Windows ###
-The msvc\ folder contains two solutions with Visual C++ projects. Open the
-gtest.sln or gtest-md.sln file using Visual Studio, and you are ready to
-build Google Test the same way you build any Visual Studio project. Files
-that have names ending with -md use DLL versions of Microsoft runtime
-libraries (the /MD or the /MDd compiler option). Files without that suffix
-use static versions of the runtime libraries (the /MT or the /MTd option).
-Please note that one must use the same option to compile both gtest and his
-test code. If you use Visual Studio 2005 or above, we recommend the -md
-version as /MD is the default for new projects in these versions of Visual
-Studio.
-
-### Mac OS X (universal-binary framework) ###
-Open the gtest.xcodeproj in the xcode/ folder using Xcode. Build the "gtest"
-target. The universal binary framework will end up in your selected build
-directory (selected in the Xcode "Preferences..." -> "Building" pane and
-defaults to xcode/build). Alternatively, at the command line, enter:
+and all features using tuple will be disabled.
- xcodebuild
+### Multi-threaded Tests ###
-This will build the "Release" configuration of gtest.framework in your
-default build location. See the "xcodebuild" man page for more information about
-building different configurations and building in different locations.
+Google Test is thread-safe where the pthread library is available.
+After #include <gtest/gtest.h>, you can check the GTEST_IS_THREADSAFE
+macro to see whether this is the case (yes if the macro is #defined to
+1, no if it's undefined.).
-To test the gtest.framework in Xcode, change the active target to "Check" and
-then build. This target builds all of the tests and then runs them. Don't worry
-if you see some errors. Xcode reports all test failures (even the intentional
-ones) as errors. However, you should see a "Build succeeded" message at the end
-of the build log. To run all of the tests from the command line, enter:
+If Google Test doesn't correctly detect whether pthread is available
+in your environment, you can force it with
- xcodebuild -target Check
+ -DGTEST_HAS_PTHREAD=1
-Installation with xcodebuild requires specifying an installation desitination
-directory, known as the DSTROOT. Three items will be installed when using
-xcodebuild:
+or
- $DSTROOT/Library/Frameworks/gtest.framework
- $DSTROOT/usr/local/lib/libgtest.a
- $DSTROOT/usr/local/lib/libgtest_main.a
+ -DGTEST_HAS_PTHREAD=0
-You specify the installation directory on the command line with the other
-xcodebuild options. Here's how you would install in a user-visible location:
+When Google Test uses pthread, you may need to add flags to your
+compiler and/or linker to select the pthread library, or you'll get
+link errors. If you use the CMake script or the deprecated Autotools
+script, this is taken care of for you. If you use your own build
+script, you'll need to read your compiler and linker's manual to
+figure out what flags to add.
- xcodebuild install DSTROOT=~
+### As a Shared Library (DLL) ###
-To perform a system-wide inistall, escalate to an administrator and specify
-the file system root as the DSTROOT:
+Google Test is compact, so most users can build and link it as a
+static library for the simplicity. You can choose to use Google Test
+as a shared library (known as a DLL on Windows) if you prefer.
- sudo xcodebuild install DSTROOT=/
+To compile gtest as a shared library, add
-To uninstall gtest.framework via the command line, you need to delete the three
-items listed above. Remember to escalate to an administrator if deleting these
-from the system-wide location using the commands listed below:
+ -DGTEST_CREATE_SHARED_LIBRARY=1
- sudo rm -r /Library/Frameworks/gtest.framework
- sudo rm /usr/local/lib/libgtest.a
- sudo rm /usr/local/lib/libgtest_main.a
+to the compiler flags. You'll also need to tell the linker to produce
+a shared library instead - consult your linker's manual for how to do
+it.
-It is also possible to build and execute individual tests within Xcode. Each
-test has its own Xcode "Target" and Xcode "Executable". To build any of the
-tests, change the active target and the active executable to the test of
-interest and then build and run.
+To compile your tests that use the gtest shared library, add
-Individual tests can be built from the command line using:
+ -DGTEST_LINKED_AS_SHARED_LIBRARY=1
- xcodebuild -target <test_name>
+to the compiler flags.
-These tests can be executed from the command line by moving to the build
-directory and then (in bash)
+### Avoiding Macro Name Clashes ###
- export DYLD_FRAMEWORK_PATH=`pwd`
- ./<test_name> # (e.g. ./gtest_unittest)
+In C++, macros don't obey namespaces. Therefore two libraries that
+both define a macro of the same name will clash if you #include both
+definitions. In case a Google Test macro clashes with another
+library, you can force Google Test to rename its macro to avoid the
+conflict.
-To use gtest.framework for your own tests, first, install the framework using
-the steps described above. Then add it to your Xcode project by selecting
-Project->Add to Project... from the main menu. Next, add libgtest_main.a from
-gtest.framework/Resources directory using the same menu command. Finally,
-create a new executable target and add gtest.framework and libgtest_main.a to
-the "Link Binary With Libraries" build phase.
+Specifically, if both Google Test and some other code define macro
+FOO, you can add
-### Using GNU Make ###
-The make/ directory contains a Makefile that you can use to build
-Google Test on systems where GNU make is available (e.g. Linux, Mac OS
-X, and Cygwin). It doesn't try to build Google Test's own tests.
-Instead, it just builds the Google Test library and a sample test.
-You can use it as a starting point for your own Makefile.
+ -DGTEST_DONT_DEFINE_FOO=1
-If the default settings are correct for your environment, the
-following commands should succeed:
+to the compiler flags to tell Google Test to change the macro's name
+from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST.
+For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
- cd ${SRCDIR}/make
- make
- ./sample1_unittest
+ GTEST_TEST(SomeTest, DoesThis) { ... }
-If you see errors, try to tweak the contents of make/Makefile to make
-them go away. There are instructions in make/Makefile on how to do
-it.
+instead of
-### Using Your Own Build System ###
-If none of the build solutions we provide works for you, or if you
-prefer your own build system, you just need to compile
-src/gtest-all.cc into a library and link your tests with it. Assuming
-a Linux-like system and gcc, something like the following will do:
+ TEST(SomeTest, DoesThis) { ... }
- cd ${SRCDIR}
- g++ -I. -I./include -c src/gtest-all.cc
- ar -rv libgtest.a gtest-all.o
- g++ -I. -I./include path/to/your_test.cc libgtest.a -o your_test
+in order to define a test.
+
+Upgrating from an Earlier Version
+---------------------------------
+
+We strive to keep Google Test releases backward compatible.
+Sometimes, though, we have to make some breaking changes for the
+users' long-term benefits. This section describes what you'll need to
+do if you are upgrading from an earlier version of Google Test.
+
+### Upgrading from 1.3.0 or Earlier ###
+
+You may need to explicitly enable or disable Google Test's own TR1
+tuple library. See the instructions in section "Choosing a TR1 Tuple
+Library".
+
+### Upgrading from 1.4.0 or Earlier ###
+
+The Autotools build script (configure + make) is no longer officially
+supportted. You are encouraged to migrate to your own build system or
+use CMake. If you still need to use Autotools, you can find
+instructions in the README file from Google Test 1.4.0.
+
+On platforms where the pthread library is available, Google Test uses
+it in order to be thread-safe. See the "Multi-threaded Tests" section
+for what this means to your build script.
+
+If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
+Test will no longer compile. This should affect very few people, as a
+large portion of STL (including <string>) doesn't compile in this mode
+anyway. We decided to stop supporting it in order to greatly simplify
+Google Test's implementation.
+
+Developing Google Test
+----------------------
+
+This section discusses how to make your own changes to Google Test.
+
+### Testing Google Test Itself ###
+
+To make sure your changes work as intended and don't break existing
+functionality, you'll want to compile and run Google Test's own tests.
+For that you can use CMake:
+
+ mkdir mybuild
+ cd mybuild
+ cmake -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Make sure you have Python installed, as some of Google Test's tests
+are written in Python. If the cmake command complains about not being
+able to find Python ("Could NOT find PythonInterp (missing:
+PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
+executable can be found:
+
+ cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Next, you can build Google Test and all of its own tests. On *nix,
+this is usually done by 'make'. To run the tests, do
+
+ make test
+
+All tests should pass.
+
+### Regenerating Source Files ###
-Regenerating Source Files
--------------------------
Some of Google Test's source files are generated from templates (not
in the C++ sense) using a script. A template file is named FOO.pump,
where FOO is the name of the file it will generate. For example, the
@@ -275,12 +397,20 @@ file include/gtest/internal/gtest-type-util.h.pump is used to generate
gtest-type-util.h in the same directory.
Normally you don't need to worry about regenerating the source files,
-unless you need to modify them (e.g. if you are working on a patch for
-Google Test). In that case, you should modify the corresponding .pump
-files instead and run the 'pump' script (for Pump is Useful for Meta
-Programming) to regenerate them. We are still working on releasing
-the script and its documentation. If you need it now, please email
-googletestframework@googlegroups.com such that we know to make it
-happen sooner.
+unless you need to modify them. In that case, you should modify the
+corresponding .pump files instead and run the pump.py Python script to
+regenerate them. You can find pump.py in the scripts/ directory.
+Read the Pump manual [2] for how to use it.
+
+ [2] http://code.google.com/p/googletest/wiki/PumpManual
+
+### Contributing a Patch ###
+
+We welcome patches. Please read the Google Test developer's guide [3]
+for how you can contribute. In particular, make sure you have signed
+the Contributor License Agreement, or we won't be able to accept the
+patch.
+
+ [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
Happy testing!
diff --git a/testing/gtest/codegear/gtest.groupproj b/testing/gtest/codegear/gtest.groupproj
index 8b650f8..faf31ca 100644
--- a/testing/gtest/codegear/gtest.groupproj
+++ b/testing/gtest/codegear/gtest.groupproj
@@ -23,15 +23,6 @@
<Target Name="gtest:Make">
<MSBuild Projects="gtest.cbproj" Targets="Make" />
</Target>
- <Target Name="gtest_unittest">
- <MSBuild Projects="gtest_unittest.cbproj" Targets="" />
- </Target>
- <Target Name="gtest_unittest:Clean">
- <MSBuild Projects="gtest_unittest.cbproj" Targets="Clean" />
- </Target>
- <Target Name="gtest_unittest:Make">
- <MSBuild Projects="gtest_unittest.cbproj" Targets="Make" />
- </Target>
<Target Name="gtest_main">
<MSBuild Projects="gtest_main.cbproj" Targets="" />
</Target>
@@ -41,14 +32,23 @@
<Target Name="gtest_main:Make">
<MSBuild Projects="gtest_main.cbproj" Targets="Make" />
</Target>
+ <Target Name="gtest_unittest">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="" />
+ </Target>
+ <Target Name="gtest_unittest:Clean">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="Clean" />
+ </Target>
+ <Target Name="gtest_unittest:Make">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="Make" />
+ </Target>
<Target Name="Build">
- <CallTarget Targets="gtest;gtest_unittest;gtest_main" />
+ <CallTarget Targets="gtest;gtest_main;gtest_unittest" />
</Target>
<Target Name="Clean">
- <CallTarget Targets="gtest:Clean;gtest_unittest:Clean;gtest_main:Clean" />
+ <CallTarget Targets="gtest:Clean;gtest_main:Clean;gtest_unittest:Clean" />
</Target>
<Target Name="Make">
- <CallTarget Targets="gtest:Make;gtest_unittest:Make;gtest_main:Make" />
+ <CallTarget Targets="gtest:Make;gtest_main:Make;gtest_unittest:Make" />
</Target>
<Import Condition="Exists('$(MSBuildBinPath)\Borland.Group.Targets')" Project="$(MSBuildBinPath)\Borland.Group.Targets" />
</Project> \ No newline at end of file
diff --git a/testing/gtest/codegear/gtest_unittest.cbproj b/testing/gtest/codegear/gtest_unittest.cbproj
index d3823c9..dc5db8e 100644
--- a/testing/gtest/codegear/gtest_unittest.cbproj
+++ b/testing/gtest/codegear/gtest_unittest.cbproj
@@ -18,27 +18,27 @@
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
- <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<OutputExt>exe</OutputExt>
- <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+ <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<Defines>NO_STRICT</Defines>
+ <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
<DynamicRTL>true</DynamicRTL>
- <UsePackages>true</UsePackages>
<ILINK_ObjectSearchPath>..\test</ILINK_ObjectSearchPath>
- <NoVCL>true</NoVCL>
+ <UsePackages>true</UsePackages>
<ProjectType>CppConsoleApplication</ProjectType>
+ <NoVCL>true</NoVCL>
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
- <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi</PackageImports>
+ <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi</PackageImports>
<BCC_wpar>false</BCC_wpar>
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</IncludePath>
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</ILINK_LibraryPath>
<Multithreaded>true</Multithreaded>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
- <DCC_Optimize>false</DCC_Optimize>
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
- <Defines>_DEBUG;$(Defines)</Defines>
+ <DCC_Optimize>false</DCC_Optimize>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+ <Defines>_DEBUG;$(Defines)</Defines>
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
@@ -48,8 +48,8 @@
<IntermediateOutputDir>Debug</IntermediateOutputDir>
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
<BCC_StackFrames>true</BCC_StackFrames>
- <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+ <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>Full</TASM_Debugging>
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
</PropertyGroup>
diff --git a/testing/gtest/configure.ac b/testing/gtest/configure.ac
index 1b91237..de2d1e7 100644
--- a/testing/gtest/configure.ac
+++ b/testing/gtest/configure.ac
@@ -12,6 +12,7 @@ AC_INIT([Google C++ Testing Framework],
# Provide various options to initialize the Autoconf and configure processes.
AC_PREREQ([2.59])
AC_CONFIG_SRCDIR([./COPYING])
+AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([build-aux/config.h])
AC_CONFIG_FILES([Makefile])
diff --git a/testing/gtest/include/gtest/gtest.h b/testing/gtest/include/gtest/gtest.h
index ee7a8d5..937f476 100644
--- a/testing/gtest/include/gtest/gtest.h
+++ b/testing/gtest/include/gtest/gtest.h
@@ -59,6 +59,7 @@
#include <gtest/gtest-death-test.h>
#include <gtest/gtest-message.h>
#include <gtest/gtest-param-test.h>
+#include <gtest/gtest-printers.h>
#include <gtest/gtest_prod.h>
#include <gtest/gtest-test-part.h>
#include <gtest/gtest-typed-test.h>
@@ -1651,10 +1652,22 @@ const T* TestWithParam<T>::parameter_ = NULL;
#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
// Generates a fatal failure with a generic message.
-#define FAIL() GTEST_FATAL_FAILURE_("Failed")
+#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Define this macro to 1 to omit the definition of FAIL(), which is a
+// generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_FAIL
+#define FAIL() GTEST_FAIL()
+#endif
// Generates a success with a generic message.
-#define SUCCEED() GTEST_SUCCESS_("Succeeded")
+#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Define this macro to 1 to omit the definition of SUCCEED(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_SUCCEED
+#define SUCCEED() GTEST_SUCCEED()
+#endif
// Macros for testing exceptions.
//
@@ -1914,17 +1927,6 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
__FILE__, __LINE__, ::testing::Message() << (message))
-namespace internal {
-
-// This template is declared, but intentionally undefined.
-template <typename T1, typename T2>
-struct StaticAssertTypeEqHelper;
-
-template <typename T>
-struct StaticAssertTypeEqHelper<T, T> {};
-
-} // namespace internal
-
// Compile-time assertion for type equality.
// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
// the same type. The value it returns is not interesting.
@@ -1957,7 +1959,7 @@ struct StaticAssertTypeEqHelper<T, T> {};
// to cause a compiler error.
template <typename T1, typename T2>
bool StaticAssertTypeEq() {
- internal::StaticAssertTypeEqHelper<T1, T2>();
+ (void)internal::StaticAssertTypeEqHelper<T1, T2>();
return true;
}
@@ -1986,10 +1988,15 @@ bool StaticAssertTypeEq() {
// code. GetTestTypeId() is guaranteed to always return the same
// value, as it always calls GetTypeId<>() from the Google Test
// framework.
-#define TEST(test_case_name, test_name)\
+#define GTEST_TEST(test_case_name, test_name)\
GTEST_TEST_(test_case_name, test_name, \
::testing::Test, ::testing::internal::GetTestTypeId())
+// Define this macro to 1 to omit the definition of TEST(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_TEST
+#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
+#endif
// Defines a test that uses a test fixture.
//
diff --git a/testing/gtest/include/gtest/internal/gtest-internal.h b/testing/gtest/include/gtest/internal/gtest-internal.h
index 31a66e9..bf8412b 100644
--- a/testing/gtest/include/gtest/internal/gtest-internal.h
+++ b/testing/gtest/include/gtest/internal/gtest-internal.h
@@ -97,6 +97,9 @@ inline void GTestStreamToHelper(std::ostream* os, const T& val) {
*os << val;
}
+class ProtocolMessage;
+namespace proto2 { class Message; }
+
namespace testing {
// Forward declaration of classes.
@@ -762,6 +765,15 @@ GTEST_API_ bool AlwaysTrue();
// Always returns false.
inline bool AlwaysFalse() { return !AlwaysTrue(); }
+// Helper for suppressing false warning from Clang on a const char*
+// variable declared in a conditional expression always being NULL in
+// the else branch.
+struct GTEST_API_ ConstCharPtr {
+ ConstCharPtr(const char* str) : value(str) {}
+ operator bool() const { return true; }
+ const char* value;
+};
+
// A simple Linear Congruential Generator for generating random
// numbers with a uniform distribution. Unlike rand() and srand(), it
// doesn't use global state (and therefore can't interfere with user
@@ -784,6 +796,296 @@ class GTEST_API_ Random {
GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
};
+// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
+// compiler error iff T1 and T2 are different types.
+template <typename T1, typename T2>
+struct CompileAssertTypesEqual;
+
+template <typename T>
+struct CompileAssertTypesEqual<T, T> {
+};
+
+// Removes the reference from a type if it is a reference type,
+// otherwise leaves it unchanged. This is the same as
+// tr1::remove_reference, which is not widely available yet.
+template <typename T>
+struct RemoveReference { typedef T type; }; // NOLINT
+template <typename T>
+struct RemoveReference<T&> { typedef T type; }; // NOLINT
+
+// A handy wrapper around RemoveReference that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_REFERENCE_(T) \
+ typename ::testing::internal::RemoveReference<T>::type
+
+// Removes const from a type if it is a const type, otherwise leaves
+// it unchanged. This is the same as tr1::remove_const, which is not
+// widely available yet.
+template <typename T>
+struct RemoveConst { typedef T type; }; // NOLINT
+template <typename T>
+struct RemoveConst<const T> { typedef T type; }; // NOLINT
+
+// MSVC 8.0 has a bug which causes the above definition to fail to
+// remove the const in 'const int[3]'. The following specialization
+// works around the bug. However, it causes trouble with gcc and thus
+// needs to be conditionally compiled.
+#ifdef _MSC_VER
+template <typename T, size_t N>
+struct RemoveConst<T[N]> {
+ typedef typename RemoveConst<T>::type type[N];
+};
+#endif // _MSC_VER
+
+// A handy wrapper around RemoveConst that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_CONST_(T) \
+ typename ::testing::internal::RemoveConst<T>::type
+
+// Turns const U&, U&, const U, and U all into U.
+#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
+ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))
+
+// Adds reference to a type if it is not a reference type,
+// otherwise leaves it unchanged. This is the same as
+// tr1::add_reference, which is not widely available yet.
+template <typename T>
+struct AddReference { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddReference<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper around AddReference that works when the argument T
+// depends on template parameters.
+#define GTEST_ADD_REFERENCE_(T) \
+ typename ::testing::internal::AddReference<T>::type
+
+// Adds a reference to const on top of T as necessary. For example,
+// it transforms
+//
+// char ==> const char&
+// const char ==> const char&
+// char& ==> const char&
+// const char& ==> const char&
+//
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T))
+
+// ImplicitlyConvertible<From, To>::value is a compile-time bool
+// constant that's true iff type From can be implicitly converted to
+// type To.
+template <typename From, typename To>
+class ImplicitlyConvertible {
+ private:
+ // We need the following helper functions only for their types.
+ // They have no implementations.
+
+ // MakeFrom() is an expression whose type is From. We cannot simply
+ // use From(), as the type From may not have a public default
+ // constructor.
+ static From MakeFrom();
+
+ // These two functions are overloaded. Given an expression
+ // Helper(x), the compiler will pick the first version if x can be
+ // implicitly converted to type To; otherwise it will pick the
+ // second version.
+ //
+ // The first version returns a value of size 1, and the second
+ // version returns a value of size 2. Therefore, by checking the
+ // size of Helper(x), which can be done at compile time, we can tell
+ // which version of Helper() is used, and hence whether x can be
+ // implicitly converted to type To.
+ static char Helper(To);
+ static char (&Helper(...))[2]; // NOLINT
+
+ // We have to put the 'public' section after the 'private' section,
+ // or MSVC refuses to compile the code.
+ public:
+ // MSVC warns about implicitly converting from double to int for
+ // possible loss of data, so we need to temporarily disable the
+ // warning.
+#ifdef _MSC_VER
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4244) // Temporarily disables warning 4244.
+ static const bool value =
+ sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+#pragma warning(pop) // Restores the warning state.
+#else
+ static const bool value =
+ sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+#endif // _MSV_VER
+};
+template <typename From, typename To>
+const bool ImplicitlyConvertible<From, To>::value;
+
+// IsAProtocolMessage<T>::value is a compile-time bool constant that's
+// true iff T is type ProtocolMessage, proto2::Message, or a subclass
+// of those.
+template <typename T>
+struct IsAProtocolMessage
+ : public bool_constant<
+ ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
+ ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
+};
+
+// When the compiler sees expression IsContainerTest<C>(0), the first
+// overload of IsContainerTest will be picked if C is an STL-style
+// container class (since C::const_iterator* is a valid type and 0 can
+// be converted to it), while the second overload will be picked
+// otherwise (since C::const_iterator will be an invalid type in this
+// case). Therefore, we can determine whether C is a container class
+// by checking the type of IsContainerTest<C>(0). The value of the
+// expression is insignificant.
+typedef int IsContainer;
+template <class C>
+IsContainer IsContainerTest(typename C::const_iterator*) { return 0; }
+
+typedef char IsNotContainer;
+template <class C>
+IsNotContainer IsContainerTest(...) { return '\0'; }
+
+// Utilities for native arrays.
+
+// ArrayEq() compares two k-dimensional native arrays using the
+// elements' operator==, where k can be any integer >= 0. When k is
+// 0, ArrayEq() degenerates into comparing a single pair of values.
+
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
+ return internal::ArrayEq(lhs, N, rhs);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous ArrayEq() function, arrays with different sizes would
+// lead to different copies of the template code.
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
+ for (size_t i = 0; i != size; i++) {
+ if (!internal::ArrayEq(lhs[i], rhs[i]))
+ return false;
+ }
+ return true;
+}
+
+// Finds the first element in the iterator range [begin, end) that
+// equals elem. Element may be a native array type itself.
+template <typename Iter, typename Element>
+Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
+ for (Iter it = begin; it != end; ++it) {
+ if (internal::ArrayEq(*it, elem))
+ return it;
+ }
+ return end;
+}
+
+// CopyArray() copies a k-dimensional native array using the elements'
+// operator=, where k can be any integer >= 0. When k is 0,
+// CopyArray() degenerates into copying a single value.
+
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline void CopyArray(const T& from, U* to) { *to = from; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline void CopyArray(const T(&from)[N], U(*to)[N]) {
+ internal::CopyArray(from, N, *to);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous CopyArray() function, arrays with different sizes
+// would lead to different copies of the template code.
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to) {
+ for (size_t i = 0; i != size; i++) {
+ internal::CopyArray(from[i], to + i);
+ }
+}
+
+// The relation between an NativeArray object (see below) and the
+// native array it represents.
+enum RelationToSource {
+ kReference, // The NativeArray references the native array.
+ kCopy // The NativeArray makes a copy of the native array and
+ // owns the copy.
+};
+
+// Adapts a native array to a read-only STL-style container. Instead
+// of the complete STL container concept, this adaptor only implements
+// members useful for Google Mock's container matchers. New members
+// should be added as needed. To simplify the implementation, we only
+// support Element being a raw type (i.e. having no top-level const or
+// reference modifier). It's the client's responsibility to satisfy
+// this requirement. Element can be an array type itself (hence
+// multi-dimensional arrays are supported).
+template <typename Element>
+class NativeArray {
+ public:
+ // STL-style container typedefs.
+ typedef Element value_type;
+ typedef const Element* const_iterator;
+
+ // Constructs from a native array.
+ NativeArray(const Element* array, size_t count, RelationToSource relation) {
+ Init(array, count, relation);
+ }
+
+ // Copy constructor.
+ NativeArray(const NativeArray& rhs) {
+ Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
+ }
+
+ ~NativeArray() {
+ // Ensures that the user doesn't instantiate NativeArray with a
+ // const or reference type.
+ static_cast<void>(StaticAssertTypeEqHelper<Element,
+ GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
+ if (relation_to_source_ == kCopy)
+ delete[] array_;
+ }
+
+ // STL-style container methods.
+ size_t size() const { return size_; }
+ const_iterator begin() const { return array_; }
+ const_iterator end() const { return array_ + size_; }
+ bool operator==(const NativeArray& rhs) const {
+ return size() == rhs.size() &&
+ ArrayEq(begin(), size(), rhs.begin());
+ }
+
+ private:
+ // Initializes this object; makes a copy of the input array if
+ // 'relation' is kCopy.
+ void Init(const Element* array, size_t a_size, RelationToSource relation) {
+ if (relation == kReference) {
+ array_ = array;
+ } else {
+ Element* const copy = new Element[a_size];
+ CopyArray(array, a_size, copy);
+ array_ = copy;
+ }
+ size_ = a_size;
+ relation_to_source_ = relation;
+ }
+
+ const Element* array_;
+ size_t size_;
+ RelationToSource relation_to_source_;
+
+ GTEST_DISALLOW_ASSIGN_(NativeArray);
+};
+
} // namespace internal
} // namespace testing
@@ -808,7 +1110,7 @@ class GTEST_API_ Random {
#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
+ if (::testing::internal::ConstCharPtr gtest_msg = "") { \
bool gtest_caught_expected = false; \
try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
@@ -817,38 +1119,38 @@ class GTEST_API_ Random {
gtest_caught_expected = true; \
} \
catch (...) { \
- gtest_msg = "Expected: " #statement " throws an exception of type " \
- #expected_exception ".\n Actual: it throws a different " \
- "type."; \
+ gtest_msg.value = \
+ "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws a different type."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
if (!gtest_caught_expected) { \
- gtest_msg = "Expected: " #statement " throws an exception of type " \
- #expected_exception ".\n Actual: it throws nothing."; \
+ gtest_msg.value = \
+ "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws nothing."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
- fail(gtest_msg)
+ fail(gtest_msg.value)
#define GTEST_TEST_NO_THROW_(statement, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
+ if (::testing::internal::AlwaysTrue()) { \
try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
} \
catch (...) { \
- gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \
- " Actual: it throws."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
- fail(gtest_msg)
+ fail("Expected: " #statement " doesn't throw an exception.\n" \
+ " Actual: it throws.")
#define GTEST_TEST_ANY_THROW_(statement, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
+ if (::testing::internal::AlwaysTrue()) { \
bool gtest_caught_any = false; \
try { \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
@@ -857,13 +1159,12 @@ class GTEST_API_ Random {
gtest_caught_any = true; \
} \
if (!gtest_caught_any) { \
- gtest_msg = "Expected: " #statement " throws an exception.\n" \
- " Actual: it doesn't."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
- fail(gtest_msg)
+ fail("Expected: " #statement " throws an exception.\n" \
+ " Actual: it doesn't.")
// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
@@ -880,18 +1181,17 @@ class GTEST_API_ Random {
#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
+ if (::testing::internal::AlwaysTrue()) { \
::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
- gtest_msg = "Expected: " #statement " doesn't generate new fatal " \
- "failures in the current thread.\n" \
- " Actual: it does."; \
goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
} \
} else \
GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
- fail(gtest_msg)
+ fail("Expected: " #statement " doesn't generate new fatal " \
+ "failures in the current thread.\n" \
+ " Actual: it does.")
// Expands to the name of the class that implements the given test.
#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
diff --git a/testing/gtest/include/gtest/internal/gtest-param-util.h b/testing/gtest/include/gtest/internal/gtest-param-util.h
index 0cbb58c..98bcca7 100644
--- a/testing/gtest/include/gtest/internal/gtest-param-util.h
+++ b/testing/gtest/include/gtest/internal/gtest-param-util.h
@@ -44,6 +44,7 @@
#include <gtest/internal/gtest-internal.h>
#include <gtest/internal/gtest-linked_ptr.h>
#include <gtest/internal/gtest-port.h>
+#include <gtest/gtest-printers.h>
#if GTEST_HAS_PARAM_TEST
@@ -171,7 +172,7 @@ class ParamGenerator {
iterator end() const { return iterator(impl_->End()); }
private:
- ::testing::internal::linked_ptr<const ParamGeneratorInterface<T> > impl_;
+ linked_ptr<const ParamGeneratorInterface<T> > impl_;
};
// Generates values from a range of two comparable values. Can be used to
@@ -285,7 +286,7 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
public:
Iterator(const ParamGeneratorInterface<T>* base,
typename ContainerType::const_iterator iterator)
- : base_(base), iterator_(iterator) {}
+ : base_(base), iterator_(iterator) {}
virtual ~Iterator() {}
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
@@ -504,12 +505,12 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
param_it != generator.end(); ++param_it, ++i) {
Message test_name_stream;
test_name_stream << test_info->test_base_name.c_str() << "/" << i;
- ::testing::internal::MakeAndRegisterTestInfo(
+ std::string comment = "GetParam() = " + PrintToString(*param_it);
+ MakeAndRegisterTestInfo(
test_case_name_stream.GetString().c_str(),
test_name_stream.GetString().c_str(),
"", // test_case_comment
- "", // comment; TODO(vladl@google.com): provide parameter value
- // representation.
+ comment.c_str(),
GetTestCaseTypeId(),
TestCase::SetUpTestCase,
TestCase::TearDownTestCase,
diff --git a/testing/gtest/include/gtest/internal/gtest-port.h b/testing/gtest/include/gtest/internal/gtest-port.h
index a2a62be..f2c80f3 100644
--- a/testing/gtest/include/gtest/internal/gtest-port.h
+++ b/testing/gtest/include/gtest/internal/gtest-port.h
@@ -609,6 +609,91 @@ namespace internal {
class String;
+// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+// content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define GTEST_COMPILE_ASSERT_(expr, msg) \
+ typedef ::testing::internal::CompileAssert<(bool(expr))> \
+ msg[bool(expr) ? 1 : -1]
+
+// Implementation details of GTEST_COMPILE_ASSERT_:
+//
+// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
+// elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+// does not work, as gcc supports variable-length arrays whose sizes
+// are determined at run-time (this is gcc's extension and not part
+// of the C++ standard). As a result, gcc fails to reject the
+// following code with the simple definition:
+//
+// int foo;
+// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
+// // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// expr is a compile-time constant. (Template arguments must be
+// determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
+//
+// CompileAssert<bool(expr)>
+//
+// instead, these compilers will refuse to compile
+//
+// GTEST_COMPILE_ASSERT_(5 > 0, some_message);
+//
+// (They seem to think the ">" in "5 > 0" marks the end of the
+// template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+// ((expr) ? 1 : -1).
+//
+// This is to avoid running into a bug in MS VC 7.1, which
+// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
+//
+// This template is declared, but intentionally undefined.
+template <typename T1, typename T2>
+struct StaticAssertTypeEqHelper;
+
+template <typename T>
+struct StaticAssertTypeEqHelper<T, T> {};
+
+#if GTEST_HAS_GLOBAL_STRING
+typedef ::string string;
+#else
+typedef ::std::string string;
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+typedef ::wstring wstring;
+#elif GTEST_HAS_STD_WSTRING
+typedef ::std::wstring wstring;
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
typedef ::std::stringstream StrStream;
// A helper for suppressing warnings on constant condition. It just
@@ -790,6 +875,58 @@ inline void FlushInfoLog() { fflush(NULL); }
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
//
+// Use implicit_cast as a safe version of static_cast for upcasting in
+// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
+// const Foo*). When you use implicit_cast, the compiler checks that
+// the cast is safe. Such explicit implicit_casts are necessary in
+// surprisingly many situations where C++ demands an exact type match
+// instead of an argument type convertable to a target type.
+//
+// The syntax for using implicit_cast is the same as for static_cast:
+//
+// implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late. It will probably make
+// its way into the language in the future.
+template<typename To>
+inline To implicit_cast(To x) { return x; }
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
+// always succeed. When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo? It
+// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
+// when you downcast, you should use this macro. In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not). In normal mode, we do the efficient static_cast<>
+// instead. Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+// This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+template<typename To, typename From> // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) { // so we only accept pointers
+ // Ensures that To is a sub-type of From *. This test is here only
+ // for compile-time type checking, and has no overhead in an
+ // optimized build at run-time, as it will be optimized away
+ // completely.
+ if (false) {
+ const To to = NULL;
+ ::testing::internal::implicit_cast<From*>(to);
+ }
+
+#if GTEST_HAS_RTTI
+ // RTTI: debug mode only!
+ GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL);
+#endif
+ return static_cast<To>(f);
+}
+
// Downcasts the pointer of type Base to Derived.
// Derived must be a subclass of Base. The parameter MUST
// point to a class of type Derived, not any subclass of it.
diff --git a/testing/gtest/include/gtest/internal/gtest-string.h b/testing/gtest/include/gtest/internal/gtest-string.h
index d1d0297..aff093d 100644
--- a/testing/gtest/include/gtest/internal/gtest-string.h
+++ b/testing/gtest/include/gtest/internal/gtest-string.h
@@ -41,6 +41,11 @@
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+#include <mem.h>
+#endif
+
#include <string.h>
#include <gtest/internal/gtest-port.h>
diff --git a/testing/gtest/make/Makefile b/testing/gtest/make/Makefile
index 2d8806e..5b27b6a 100644
--- a/testing/gtest/make/Makefile
+++ b/testing/gtest/make/Makefile
@@ -20,7 +20,7 @@ GTEST_DIR = ..
USER_DIR = ../samples
# Flags passed to the preprocessor.
-CPPFLAGS += -I$(GTEST_DIR) -I$(GTEST_DIR)/include
+CPPFLAGS += -I$(GTEST_DIR)/include
# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra
@@ -52,10 +52,12 @@ GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
gtest-all.o : $(GTEST_SRCS_)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest-all.cc
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_DIR)/src/gtest_main.cc
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest_main.cc
gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $@ $^
@@ -75,4 +77,4 @@ sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc
sample1_unittest : sample1.o sample1_unittest.o gtest_main.a
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
diff --git a/testing/gtest/src/gtest-all.cc b/testing/gtest/src/gtest-all.cc
index fe34765..f3e22dd 100644
--- a/testing/gtest/src/gtest-all.cc
+++ b/testing/gtest/src/gtest-all.cc
@@ -43,5 +43,6 @@
#include "src/gtest-death-test.cc"
#include "src/gtest-filepath.cc"
#include "src/gtest-port.cc"
+#include "src/gtest-printers.cc"
#include "src/gtest-test-part.cc"
#include "src/gtest-typed-test.cc"
diff --git a/testing/gtest/src/gtest-death-test.cc b/testing/gtest/src/gtest-death-test.cc
index 3b73b01..66bf189 100644
--- a/testing/gtest/src/gtest-death-test.cc
+++ b/testing/gtest/src/gtest-death-test.cc
@@ -418,7 +418,14 @@ void DeathTestImpl::Abort(AbortReason reason) {
const char status_ch =
reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
- GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd()));
+ // We are leaking the descriptor here because on some platforms (i.e.,
+ // when built as Windows DLL), destructors of global objects will still
+ // run after calling _exit(). On such systems, write_fd_ will be
+ // indirectly closed from the destructor of UnitTestImpl, causing double
+ // close if it is also closed here. On debug configurations, double close
+ // may assert. As there are no in-process buffers to flush here, we are
+ // relying on the OS to close the descriptor after the process terminates
+ // when the destructors are not run.
_exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
}
diff --git a/testing/gtest/src/gtest-internal-inl.h b/testing/gtest/src/gtest-internal-inl.h
index 855b215..9e63aed 100644
--- a/testing/gtest/src/gtest-internal-inl.h
+++ b/testing/gtest/src/gtest-internal-inl.h
@@ -739,11 +739,11 @@ class GTEST_API_ UnitTestImpl {
}
// Registers all parameterized tests defined using TEST_P and
- // INSTANTIATE_TEST_P, creating regular tests for each test/parameter
- // combination. This method can be called more then once; it has
- // guards protecting from registering the tests more then once.
- // If value-parameterized tests are disabled, RegisterParameterizedTests
- // is present but does nothing.
+ // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter
+ // combination. This method can be called more then once; it has guards
+ // protecting from registering the tests more then once. If
+ // value-parameterized tests are disabled, RegisterParameterizedTests is
+ // present but does nothing.
void RegisterParameterizedTests();
// Runs all tests in this UnitTest object, prints the result, and
@@ -977,7 +977,7 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
// Returns the message describing the last system error, regardless of the
// platform.
-String GetLastErrnoDescription();
+GTEST_API_ String GetLastErrnoDescription();
#if GTEST_OS_WINDOWS
// Provides leak-safe Windows kernel handle ownership.
diff --git a/testing/gtest/src/gtest.cc b/testing/gtest/src/gtest.cc
index 342d458..e136a18 100644
--- a/testing/gtest/src/gtest.cc
+++ b/testing/gtest/src/gtest.cc
@@ -2592,6 +2592,7 @@ bool ShouldUseColor(bool stdout_is_tty) {
String::CStringEquals(term, "xterm") ||
String::CStringEquals(term, "xterm-color") ||
String::CStringEquals(term, "xterm-256color") ||
+ String::CStringEquals(term, "screen") ||
String::CStringEquals(term, "linux") ||
String::CStringEquals(term, "cygwin");
return stdout_is_tty && term_supports_color;
@@ -2657,6 +2658,19 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) {
va_end(args);
}
+void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
+ const char* const comment = test_info.comment();
+ const char* const test_case_comment = test_info.test_case_comment();
+
+ if (test_case_comment[0] != '\0' || comment[0] != '\0') {
+ printf(", where %s", test_case_comment);
+ if (test_case_comment[0] != '\0' && comment[0] != '\0') {
+ printf(" and ");
+ }
+ printf("%s", comment);
+ }
+}
+
// This class implements the TestEventListener interface.
//
// Class PrettyUnitTestResultPrinter is copyable.
@@ -2747,11 +2761,7 @@ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
PrintTestName(test_case_name_.c_str(), test_info.name());
- if (test_info.comment()[0] == '\0') {
- printf("\n");
- } else {
- printf(", where %s\n", test_info.comment());
- }
+ printf("\n");
fflush(stdout);
}
@@ -2774,6 +2784,9 @@ void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
ColoredPrintf(COLOR_RED, "[ FAILED ] ");
}
PrintTestName(test_case_name_.c_str(), test_info.name());
+ if (test_info.result()->Failed())
+ PrintFullTestCommentIfPresent(test_info);
+
if (GTEST_FLAG(print_time)) {
printf(" (%s ms)\n", internal::StreamableToString(
test_info.result()->elapsed_time()).c_str());
@@ -2822,15 +2835,8 @@ void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
}
ColoredPrintf(COLOR_RED, "[ FAILED ] ");
printf("%s.%s", test_case.name(), test_info.name());
- if (test_case.comment()[0] != '\0' ||
- test_info.comment()[0] != '\0') {
- printf(", where %s", test_case.comment());
- if (test_case.comment()[0] != '\0' &&
- test_info.comment()[0] != '\0') {
- printf(" and ");
- }
- }
- printf("%s\n", test_info.comment());
+ PrintFullTestCommentIfPresent(test_info);
+ printf("\n");
}
}
}
diff --git a/testing/gtest/src/gtest_main.cc b/testing/gtest/src/gtest_main.cc
index d20c02f..6d4d22d 100644
--- a/testing/gtest/src/gtest_main.cc
+++ b/testing/gtest/src/gtest_main.cc
@@ -31,7 +31,7 @@
#include <gtest/gtest.h>
-int main(int argc, char **argv) {
+GTEST_API_ int main(int argc, char **argv) {
std::cout << "Running main() from gtest_main.cc\n";
testing::InitGoogleTest(&argc, argv);
diff --git a/testing/gtest/test/gtest-param-test_test.cc b/testing/gtest/test/gtest-param-test_test.cc
index d0a0e73..26acce4 100644
--- a/testing/gtest/test/gtest-param-test_test.cc
+++ b/testing/gtest/test/gtest-param-test_test.cc
@@ -792,19 +792,50 @@ INSTANTIATE_TEST_CASE_P(FourElemSequence, SeparateInstanceTest, Range(1, 4));
// sequence element used to instantiate the test.
class NamingTest : public TestWithParam<int> {};
-TEST_P(NamingTest, TestsAreNamedAppropriately) {
+TEST_P(NamingTest, TestsAreNamedAndCommentedCorrectly) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_case_name());
- Message msg;
- msg << "TestsAreNamedAppropriately/" << GetParam();
- EXPECT_STREQ(msg.GetString().c_str(), test_info->name());
+ Message index_stream;
+ index_stream << "TestsAreNamedAndCommentedCorrectly/" << GetParam();
+ EXPECT_STREQ(index_stream.GetString().c_str(), test_info->name());
+
+ const ::std::string comment =
+ "GetParam() = " + ::testing::PrintToString(GetParam());
+ EXPECT_EQ(comment, test_info->comment());
}
INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5));
+// Class that cannot be streamed into an ostream. It needs to be copyable
+// (and, in case of MSVC, also assignable) in order to be a test parameter
+// type. Its default copy constructor and assignment operator do exactly
+// what we need.
+class Unstreamable {
+ public:
+ explicit Unstreamable(int value) : value_(value) {}
+
+ private:
+ int value_;
+};
+
+class CommentTest : public TestWithParam<Unstreamable> {};
+
+TEST_P(CommentTest, TestsWithUnstreamableParamsCommentedCorrectly) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ const ::std::string comment =
+ "GetParam() = " + ::testing::PrintToString(GetParam());
+ EXPECT_EQ(comment, test_info->comment());
+}
+
+INSTANTIATE_TEST_CASE_P(InstantiationWithComments,
+ CommentTest,
+ Values(Unstreamable(1)));
+
#endif // GTEST_HAS_PARAM_TEST
TEST(CompileTest, CombineIsDefinedOnlyWhenGtestHasParamTestIsDefined) {
diff --git a/testing/gtest/test/gtest-port_test.cc b/testing/gtest/test/gtest-port_test.cc
index 3725860..6f1512c 100644
--- a/testing/gtest/test/gtest-port_test.cc
+++ b/testing/gtest/test/gtest-port_test.cc
@@ -59,6 +59,118 @@ using std::pair;
namespace testing {
namespace internal {
+class Base {
+ public:
+ // Copy constructor and assignment operator do exactly what we need, so we
+ // use them.
+ Base() : member_(0) {}
+ explicit Base(int n) : member_(n) {}
+ virtual ~Base() {}
+ int member() { return member_; }
+
+ private:
+ int member_;
+};
+
+class Derived : public Base {
+ public:
+ explicit Derived(int n) : Base(n) {}
+};
+
+TEST(ImplicitCastTest, ConvertsPointers) {
+ Derived derived(0);
+ EXPECT_TRUE(&derived == ::testing::internal::implicit_cast<Base*>(&derived));
+}
+
+TEST(ImplicitCastTest, CanUseInheritance) {
+ Derived derived(1);
+ Base base = ::testing::internal::implicit_cast<Base>(derived);
+ EXPECT_EQ(derived.member(), base.member());
+}
+
+class Castable {
+ public:
+ Castable(bool* converted) : converted_(converted) {}
+ operator Base() {
+ *converted_ = true;
+ return Base();
+ }
+
+ private:
+ bool* converted_;
+};
+
+TEST(ImplicitCastTest, CanUseNonConstCastOperator) {
+ bool converted = false;
+ Castable castable(&converted);
+ Base base = ::testing::internal::implicit_cast<Base>(castable);
+ EXPECT_TRUE(converted);
+}
+
+class ConstCastable {
+ public:
+ ConstCastable(bool* converted) : converted_(converted) {}
+ operator Base() const {
+ *converted_ = true;
+ return Base();
+ }
+
+ private:
+ bool* converted_;
+};
+
+TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) {
+ bool converted = false;
+ const ConstCastable const_castable(&converted);
+ Base base = ::testing::internal::implicit_cast<Base>(const_castable);
+ EXPECT_TRUE(converted);
+}
+
+class ConstAndNonConstCastable {
+ public:
+ ConstAndNonConstCastable(bool* converted, bool* const_converted)
+ : converted_(converted), const_converted_(const_converted) {}
+ operator Base() {
+ *converted_ = true;
+ return Base();
+ }
+ operator Base() const {
+ *const_converted_ = true;
+ return Base();
+ }
+
+ private:
+ bool* converted_;
+ bool* const_converted_;
+};
+
+TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) {
+ bool converted = false;
+ bool const_converted = false;
+ ConstAndNonConstCastable castable(&converted, &const_converted);
+ Base base = ::testing::internal::implicit_cast<Base>(castable);
+ EXPECT_TRUE(converted);
+ EXPECT_FALSE(const_converted);
+
+ converted = false;
+ const_converted = false;
+ const ConstAndNonConstCastable const_castable(&converted, &const_converted);
+ base = ::testing::internal::implicit_cast<Base>(const_castable);
+ EXPECT_FALSE(converted);
+ EXPECT_TRUE(const_converted);
+}
+
+class To {
+ public:
+ To(bool* converted) { *converted = true; } // NOLINT
+};
+
+TEST(ImplicitCastTest, CanUseImplicitConstructor) {
+ bool converted = false;
+ To to = ::testing::internal::implicit_cast<To>(&converted);
+ EXPECT_TRUE(converted);
+}
+
// Tests that the element_type typedef is available in scoped_ptr and refers
// to the parameter type.
TEST(ScopedPtrTest, DefinesElementType) {
@@ -149,8 +261,10 @@ TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) {
const char regex[] =
#ifdef _MSC_VER
"gtest-port_test\\.cc\\(\\d+\\):"
-#else
+#elif GTEST_USES_POSIX_RE
"gtest-port_test\\.cc:[0-9]+"
+#else
+ "gtest-port_test\\.cc:\\d+"
#endif // _MSC_VER
".*a_false_condition.*Extra info.*";
diff --git a/testing/gtest/test/gtest_all_test.cc b/testing/gtest/test/gtest_all_test.cc
index e1edb08..955aa62 100644
--- a/testing/gtest/test/gtest_all_test.cc
+++ b/testing/gtest/test/gtest_all_test.cc
@@ -45,4 +45,3 @@
#include "test/gtest-typed-test2_test.cc"
#include "test/gtest_unittest.cc"
#include "test/production.cc"
-#include "src/gtest_main.cc"
diff --git a/testing/gtest/test/gtest_filter_unittest.py b/testing/gtest/test/gtest_filter_unittest.py
index 89171e0..0d1a770 100755
--- a/testing/gtest/test/gtest_filter_unittest.py
+++ b/testing/gtest/test/gtest_filter_unittest.py
@@ -108,6 +108,14 @@ TEST_CASE_REGEX = re.compile(r'^\[\-+\] \d+ tests? from (\w+(/\w+)?)')
# Regex for parsing test names from Google Test's output.
TEST_REGEX = re.compile(r'^\[\s*RUN\s*\].*\.(\w+(/\w+)?)')
+# The command line flag to tell Google Test to output the list of tests it
+# will run.
+LIST_TESTS_FLAG = '--gtest_list_tests'
+
+# Indicates whether Google Test supports death tests.
+SUPPORTS_DEATH_TESTS = 'HasDeathTest' in gtest_test_utils.Subprocess(
+ [COMMAND, LIST_TESTS_FLAG]).output
+
# Full names of all tests in gtest_filter_unittests_.
PARAM_TESTS = [
'SeqP/ParamTest.TestX/0',
@@ -129,6 +137,14 @@ DISABLED_TESTS = [
'DISABLED_FoobarbazTest.TestA',
]
+if SUPPORTS_DEATH_TESTS:
+ DEATH_TESTS = [
+ 'HasDeathTest.Test1',
+ 'HasDeathTest.Test2',
+ ]
+else:
+ DEATH_TESTS = []
+
# All the non-disabled tests.
ACTIVE_TESTS = [
'FooTest.Abc',
@@ -141,10 +157,7 @@ ACTIVE_TESTS = [
'BazTest.TestOne',
'BazTest.TestA',
'BazTest.TestB',
-
- 'HasDeathTest.Test1',
- 'HasDeathTest.Test2',
- ] + PARAM_TESTS
+ ] + DEATH_TESTS + PARAM_TESTS
param_tests_present = None
@@ -210,7 +223,7 @@ def RunWithSharding(total_shards, shard_index, command):
class GTestFilterUnitTest(gtest_test_utils.TestCase):
- """Tests GTEST_FILTER env variable or --gtest_filter flag to filter tests."""
+ """Tests the env variable or the command line flag to filter tests."""
# Utilities.
@@ -242,17 +255,17 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
return tests_to_run
def RunAndVerify(self, gtest_filter, tests_to_run):
- """Checks that the binary runs correct set of tests for the given filter."""
+ """Checks that the binary runs correct set of tests for a given filter."""
tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
- # First, tests using GTEST_FILTER.
+ # First, tests using the environment variable.
# Windows removes empty variables from the environment when passing it
- # to a new process. This means it is impossible to pass an empty filter
- # into a process using the GTEST_FILTER environment variable. However,
- # we can still test the case when the variable is not supplied (i.e.,
- # gtest_filter is None).
+ # to a new process. This means it is impossible to pass an empty filter
+ # into a process using the environment variable. However, we can still
+ # test the case when the variable is not supplied (i.e., gtest_filter is
+ # None).
# pylint: disable-msg=C6403
if CAN_TEST_EMPTY_FILTER or gtest_filter != '':
SetEnvVar(FILTER_ENV_VAR, gtest_filter)
@@ -261,7 +274,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
self.AssertSetEqual(tests_run, tests_to_run)
# pylint: enable-msg=C6403
- # Next, tests using --gtest_filter.
+ # Next, tests using the command line flag.
if gtest_filter is None:
args = []
@@ -291,10 +304,10 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
# Windows removes empty variables from the environment when passing it
- # to a new process. This means it is impossible to pass an empty filter
- # into a process using the GTEST_FILTER environment variable. However,
- # we can still test the case when the variable is not supplied (i.e.,
- # gtest_filter is None).
+ # to a new process. This means it is impossible to pass an empty filter
+ # into a process using the environment variable. However, we can still
+ # test the case when the variable is not supplied (i.e., gtest_filter is
+ # None).
# pylint: disable-msg=C6403
if CAN_TEST_EMPTY_FILTER or gtest_filter != '':
SetEnvVar(FILTER_ENV_VAR, gtest_filter)
@@ -435,10 +448,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
'BazTest.TestOne',
'BazTest.TestA',
- 'BazTest.TestB',
-
- 'HasDeathTest.Test1',
- 'HasDeathTest.Test2', ] + PARAM_TESTS)
+ 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS)
def testWildcardInTestName(self):
"""Tests using wildcard in the test name."""
@@ -499,7 +509,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
])
def testNegativeFilters(self):
- self.RunAndVerify('*-HasDeathTest.Test1', [
+ self.RunAndVerify('*-BazTest.TestOne', [
'FooTest.Abc',
'FooTest.Xyz',
@@ -507,24 +517,17 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
'BarTest.TestTwo',
'BarTest.TestThree',
- 'BazTest.TestOne',
'BazTest.TestA',
'BazTest.TestB',
+ ] + DEATH_TESTS + PARAM_TESTS)
- 'HasDeathTest.Test2',
- ] + PARAM_TESTS)
-
- self.RunAndVerify('*-FooTest.Abc:HasDeathTest.*', [
+ self.RunAndVerify('*-FooTest.Abc:BazTest.*', [
'FooTest.Xyz',
'BarTest.TestOne',
'BarTest.TestTwo',
'BarTest.TestThree',
-
- 'BazTest.TestOne',
- 'BazTest.TestA',
- 'BazTest.TestB',
- ] + PARAM_TESTS)
+ ] + DEATH_TESTS + PARAM_TESTS)
self.RunAndVerify('BarTest.*-BarTest.TestOne', [
'BarTest.TestTwo',
@@ -532,15 +535,11 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
])
# Tests without leading '*'.
- self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:HasDeathTest.*', [
+ self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:BazTest.*', [
'BarTest.TestOne',
'BarTest.TestTwo',
'BarTest.TestThree',
-
- 'BazTest.TestOne',
- 'BazTest.TestA',
- 'BazTest.TestB',
- ] + PARAM_TESTS)
+ ] + DEATH_TESTS + PARAM_TESTS)
# Value parameterized tests.
self.RunAndVerify('*/*', PARAM_TESTS)
@@ -586,7 +585,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
os.remove(shard_status_file)
def testShardStatusFileIsCreatedWithListTests(self):
- """Tests that the shard file is created with --gtest_list_tests."""
+ """Tests that the shard file is created with the "list_tests" flag."""
shard_status_file = os.path.join(gtest_test_utils.GetTempDir(),
'shard_status_file2')
@@ -594,32 +593,41 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file}
try:
- InvokeWithModifiedEnv(extra_env,
- RunAndReturnOutput,
- ['--gtest_list_tests'])
+ output = InvokeWithModifiedEnv(extra_env,
+ RunAndReturnOutput,
+ [LIST_TESTS_FLAG])
finally:
+ # This assertion ensures that Google Test enumerated the tests as
+ # opposed to running them.
+ self.assert_('[==========]' not in output,
+ 'Unexpected output during test enumeration.\n'
+ 'Please ensure that LIST_TESTS_FLAG is assigned the\n'
+ 'correct flag value for listing Google Test tests.')
+
self.assert_(os.path.exists(shard_status_file))
os.remove(shard_status_file)
- def testShardingWorksWithDeathTests(self):
- """Tests integration with death tests and sharding."""
- gtest_filter = 'HasDeathTest.*:SeqP/*'
- expected_tests = [
- 'HasDeathTest.Test1',
- 'HasDeathTest.Test2',
-
- 'SeqP/ParamTest.TestX/0',
- 'SeqP/ParamTest.TestX/1',
- 'SeqP/ParamTest.TestY/0',
- 'SeqP/ParamTest.TestY/1',
- ]
-
- for flag in ['--gtest_death_test_style=threadsafe',
- '--gtest_death_test_style=fast']:
- self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests,
- check_exit_0=True, args=[flag])
- self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests,
- check_exit_0=True, args=[flag])
+ if SUPPORTS_DEATH_TESTS:
+ def testShardingWorksWithDeathTests(self):
+ """Tests integration with death tests and sharding."""
+
+ gtest_filter = 'HasDeathTest.*:SeqP/*'
+ expected_tests = [
+ 'HasDeathTest.Test1',
+ 'HasDeathTest.Test2',
+
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestX/1',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqP/ParamTest.TestY/1',
+ ]
+
+ for flag in ['--gtest_death_test_style=threadsafe',
+ '--gtest_death_test_style=fast']:
+ self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests,
+ check_exit_0=True, args=[flag])
+ self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests,
+ check_exit_0=True, args=[flag])
if __name__ == '__main__':
gtest_test_utils.Main()
diff --git a/testing/gtest/test/gtest_help_test.py b/testing/gtest/test/gtest_help_test.py
index 7883c1c..dc67ed3 100755
--- a/testing/gtest/test/gtest_help_test.py
+++ b/testing/gtest/test/gtest_help_test.py
@@ -32,7 +32,7 @@
"""Tests the --help flag of Google C++ Testing Framework.
SYNOPSIS
- gtest_help_test.py --gtest_build_dir=BUILD/DIR
+ gtest_help_test.py --build_dir=BUILD/DIR
# where BUILD/DIR contains the built gtest_help_test_ file.
gtest_help_test.py
"""
@@ -51,11 +51,15 @@ FLAG_PREFIX = '--gtest_'
CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions'
DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style'
UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing'
-INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', DEATH_TEST_STYLE_FLAG),
- re.sub('^--', '/', DEATH_TEST_STYLE_FLAG),
- re.sub('_', '-', DEATH_TEST_STYLE_FLAG)]
+LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests'
+INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG),
+ re.sub('^--', '/', LIST_TESTS_FLAG),
+ re.sub('_', '-', LIST_TESTS_FLAG)]
INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing'
+SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess(
+ [PROGRAM_PATH, LIST_TESTS_FLAG]).output
+
# The help message must match this regex.
HELP_REGEX = re.compile(
FLAG_PREFIX + r'list_tests.*' +
@@ -107,10 +111,13 @@ class GTestHelpTest(gtest_test_utils.TestCase):
self.assert_(HELP_REGEX.search(output), output)
if IS_WINDOWS:
self.assert_(CATCH_EXCEPTIONS_FLAG in output, output)
- self.assert_(DEATH_TEST_STYLE_FLAG not in output, output)
else:
self.assert_(CATCH_EXCEPTIONS_FLAG not in output, output)
+
+ if SUPPORTS_DEATH_TESTS and not IS_WINDOWS:
self.assert_(DEATH_TEST_STYLE_FLAG in output, output)
+ else:
+ self.assert_(DEATH_TEST_STYLE_FLAG not in output, output)
def TestNonHelpFlag(self, flag):
"""Verifies correct behavior when no help flag is specified.
diff --git a/testing/gtest/test/gtest_help_test_.cc b/testing/gtest/test/gtest_help_test_.cc
index 0282bc8..aad0d72 100644
--- a/testing/gtest/test/gtest_help_test_.cc
+++ b/testing/gtest/test/gtest_help_test_.cc
@@ -40,3 +40,7 @@
TEST(HelpFlagTest, ShouldNotBeRun) {
ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified.";
}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {}
+#endif
diff --git a/testing/gtest/test/gtest_output_test.py b/testing/gtest/test/gtest_output_test.py
index 192030a..425d9da 100755
--- a/testing/gtest/test/gtest_output_test.py
+++ b/testing/gtest/test/gtest_output_test.py
@@ -32,7 +32,7 @@
"""Tests the text output of Google C++ Testing Framework.
SYNOPSIS
- gtest_output_test.py --gtest_build_dir=BUILD/DIR --gengolden
+ gtest_output_test.py --build_dir=BUILD/DIR --gengolden
# where BUILD/DIR contains the built gtest_output_test_ file.
gtest_output_test.py --gengolden
gtest_output_test.py
@@ -240,7 +240,7 @@ SUPPORTS_STACK_TRACES = False
CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and
SUPPORTS_TYPED_TESTS and
- SUPPORTS_THREADS)
+ (SUPPORTS_THREADS or IS_WINDOWS))
class GTestOutputTest(gtest_test_utils.TestCase):
diff --git a/testing/gtest/test/gtest_output_test_.cc b/testing/gtest/test/gtest_output_test_.cc
index 273e8e9..1ac439c 100644
--- a/testing/gtest/test/gtest_output_test_.cc
+++ b/testing/gtest/test/gtest_output_test_.cc
@@ -87,6 +87,20 @@ TEST(PassingTest, PassingTest1) {
TEST(PassingTest, PassingTest2) {
}
+// Tests that parameters of failing parameterized tests are printed in the
+// failing test summary.
+class FailingParamTest : public testing::TestWithParam<int> {};
+
+TEST_P(FailingParamTest, Fails) {
+ EXPECT_EQ(1, GetParam());
+}
+
+// This generates a test which will fail. Google Test is expected to print
+// its parameter when it outputs the list of all failed tests.
+INSTANTIATE_TEST_CASE_P(PrintingFailingParams,
+ FailingParamTest,
+ testing::Values(2));
+
// Tests catching a fatal failure in a subroutine.
TEST(FatalFailureTest, FatalFailureInSubroutine) {
printf("(expecting a failure that x should be 1)\n");
@@ -1085,9 +1099,7 @@ class BarEnvironment : public testing::Environment {
}
};
-GTEST_DEFINE_bool_(internal_skip_environment_and_ad_hoc_tests, false,
- "This flag causes the program to skip test environment "
- "tests and ad hoc tests.");
+bool GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = false;
// The main function.
//
diff --git a/testing/gtest/test/gtest_output_test_golden_lin.txt b/testing/gtest/test/gtest_output_test_golden_lin.txt
index ec60437..2f3994a 100644
--- a/testing/gtest/test/gtest_output_test_golden_lin.txt
+++ b/testing/gtest/test/gtest_output_test_golden_lin.txt
@@ -7,7 +7,7 @@ Expected: true
gtest_output_test_.cc:#: Failure
Value of: 3
Expected: 2
-[==========] Running 60 tests from 25 test cases.
+[==========] Running 61 tests from 26 test cases.
[----------] Global test environment set-up.
FooEnvironment::SetUp() called.
BarEnvironment::SetUp() called.
@@ -411,7 +411,7 @@ Value of: TypeParam()
Actual: 0
Expected: 1
Expected failure
-[ FAILED ] TypedTest/0.Failure
+[ FAILED ] TypedTest/0.Failure, where TypeParam = int
[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char
[ RUN ] Unsigned/TypedTestP/0.Success
[ OK ] Unsigned/TypedTestP/0.Success
@@ -422,7 +422,7 @@ Value of: TypeParam()
Expected: 1U
Which is: 1
Expected failure
-[ FAILED ] Unsigned/TypedTestP/0.Failure
+[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char
[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int
[ RUN ] Unsigned/TypedTestP/1.Success
[ OK ] Unsigned/TypedTestP/1.Success
@@ -433,7 +433,7 @@ Value of: TypeParam()
Expected: 1U
Which is: 1
Expected failure
-[ FAILED ] Unsigned/TypedTestP/1.Failure
+[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int
[----------] 4 tests from ExpectFailureTest
[ RUN ] ExpectFailureTest.ExpectFatalFailure
(expecting 1 failure)
@@ -564,6 +564,13 @@ gtest_output_test_.cc:#: Failure
Failed
Expected non-fatal failure.
[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+[----------] 1 test from PrintingFailingParams/FailingParamTest
+[ RUN ] PrintingFailingParams/FailingParamTest.Fails/0
+gtest_output_test_.cc:#: Failure
+Value of: GetParam()
+ Actual: 2
+Expected: 1
+[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
[----------] Global test environment tear-down
BarEnvironment::TearDown() called.
gtest_output_test_.cc:#: Failure
@@ -573,9 +580,9 @@ FooEnvironment::TearDown() called.
gtest_output_test_.cc:#: Failure
Failed
Expected fatal failure.
-[==========] 60 tests from 25 test cases ran.
+[==========] 61 tests from 26 test cases ran.
[ PASSED ] 21 tests.
-[ FAILED ] 39 tests, listed below:
+[ FAILED ] 40 tests, listed below:
[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
@@ -615,8 +622,9 @@ Expected fatal failure.
[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure
[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure
[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
-39 FAILED TESTS
+40 FAILED TESTS
 YOU HAVE 1 DISABLED TEST
Note: Google Test filter = FatalFailureTest.*:LoggingTest.*
diff --git a/testing/gtest/test/gtest_output_test_golden_win.txt b/testing/gtest/test/gtest_output_test_golden_win.txt
index 313c3aa..fb69710 100644
--- a/testing/gtest/test/gtest_output_test_golden_win.txt
+++ b/testing/gtest/test/gtest_output_test_golden_win.txt
@@ -5,7 +5,7 @@ gtest_output_test_.cc:#: error: Value of: false
Expected: true
gtest_output_test_.cc:#: error: Value of: 3
Expected: 2
-[==========] Running 61 tests from 27 test cases.
+[==========] Running 62 tests from 28 test cases.
[----------] Global test environment set-up.
FooEnvironment::SetUp() called.
BarEnvironment::SetUp() called.
@@ -369,7 +369,7 @@ gtest_output_test_.cc:#: error: Value of: TypeParam()
Actual: 0
Expected: 1
Expected failure
-[ FAILED ] TypedTest/0.Failure
+[ FAILED ] TypedTest/0.Failure, where TypeParam = int
[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char
[ RUN ] Unsigned/TypedTestP/0.Success
[ OK ] Unsigned/TypedTestP/0.Success
@@ -379,7 +379,7 @@ gtest_output_test_.cc:#: error: Value of: TypeParam()
Expected: 1U
Which is: 1
Expected failure
-[ FAILED ] Unsigned/TypedTestP/0.Failure
+[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char
[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int
[ RUN ] Unsigned/TypedTestP/1.Success
[ OK ] Unsigned/TypedTestP/1.Success
@@ -389,7 +389,7 @@ gtest_output_test_.cc:#: error: Value of: TypeParam()
Expected: 1U
Which is: 1
Expected failure
-[ FAILED ] Unsigned/TypedTestP/1.Failure
+[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int
[----------] 4 tests from ExpectFailureTest
[ RUN ] ExpectFailureTest.ExpectFatalFailure
(expecting 1 failure)
@@ -479,6 +479,12 @@ Failed
Expected non-fatal failure.
[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+[----------] 1 test from PrintingFailingParams/FailingParamTest
+[ RUN ] PrintingFailingParams/FailingParamTest.Fails/0
+gtest_output_test_.cc:#: error: Value of: GetParam()
+ Actual: 2
+Expected: 1
+[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
[----------] Global test environment tear-down
BarEnvironment::TearDown() called.
gtest_output_test_.cc:#: error: Failed
@@ -486,9 +492,9 @@ Expected non-fatal failure.
FooEnvironment::TearDown() called.
gtest_output_test_.cc:#: error: Failed
Expected fatal failure.
-[==========] 61 tests from 27 test cases ran.
+[==========] 62 tests from 28 test cases ran.
[ PASSED ] 21 tests.
-[ FAILED ] 40 tests, listed below:
+[ FAILED ] 41 tests, listed below:
[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
@@ -529,8 +535,9 @@ Expected fatal failure.
[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure
[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads
[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+[ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
-40 FAILED TESTS
+41 FAILED TESTS
YOU HAVE 1 DISABLED TEST
Note: Google Test filter = FatalFailureTest.*:LoggingTest.*
diff --git a/testing/gtest/test/gtest_test_utils.py b/testing/gtest/test/gtest_test_utils.py
index e0f5973..e7ee9d9 100755
--- a/testing/gtest/test/gtest_test_utils.py
+++ b/testing/gtest/test/gtest_test_utils.py
@@ -63,8 +63,8 @@ TestCase = _test_module.TestCase # pylint: disable-msg=C6409
# Initially maps a flag to its default value. After
# _ParseAndStripGTestFlags() is called, maps a flag to its actual value.
-_flag_map = {'gtest_source_dir': os.path.dirname(sys.argv[0]),
- 'gtest_build_dir': os.path.dirname(sys.argv[0])}
+_flag_map = {'source_dir': os.path.dirname(sys.argv[0]),
+ 'build_dir': os.path.dirname(sys.argv[0])}
_gtest_flags_are_parsed = False
@@ -111,13 +111,13 @@ def GetFlag(flag):
def GetSourceDir():
"""Returns the absolute path of the directory where the .py files are."""
- return os.path.abspath(GetFlag('gtest_source_dir'))
+ return os.path.abspath(GetFlag('source_dir'))
def GetBuildDir():
"""Returns the absolute path of the directory where the test binaries are."""
- return os.path.abspath(GetFlag('gtest_build_dir'))
+ return os.path.abspath(GetFlag('build_dir'))
_temp_dir = None
@@ -161,7 +161,7 @@ def GetTestExecutablePath(executable_name, build_dir=None):
if not os.path.exists(path):
message = (
'Unable to find the test binary. Please make sure to provide path\n'
- 'to the binary via the --gtest_build_dir flag or the GTEST_BUILD_DIR\n'
+ 'to the binary via the --build_dir flag or the BUILD_DIR\n'
'environment variable. For convenient use, invoke this script via\n'
'mk_test.py.\n'
# TODO(vladl@google.com): change mk_test.py to test.py after renaming
diff --git a/testing/gtest/test/gtest_unittest.cc b/testing/gtest/test/gtest_unittest.cc
index 199b254..40049ae 100644
--- a/testing/gtest/test/gtest_unittest.cc
+++ b/testing/gtest/test/gtest_unittest.cc
@@ -132,23 +132,28 @@ using testing::Message;
using testing::ScopedFakeTestPartResultReporter;
using testing::StaticAssertTypeEq;
using testing::Test;
-using testing::TestEventListeners;
using testing::TestCase;
+using testing::TestEventListeners;
using testing::TestPartResult;
using testing::TestPartResultArray;
using testing::TestProperty;
using testing::TestResult;
using testing::UnitTest;
using testing::kMaxStackTraceDepth;
+using testing::internal::AddReference;
using testing::internal::AlwaysFalse;
using testing::internal::AlwaysTrue;
using testing::internal::AppendUserMessage;
+using testing::internal::ArrayAwareFind;
+using testing::internal::ArrayEq;
using testing::internal::CodePointToUtf8;
+using testing::internal::CompileAssertTypesEqual;
+using testing::internal::CopyArray;
using testing::internal::CountIf;
using testing::internal::EqFailure;
using testing::internal::FloatingPoint;
-using testing::internal::FormatTimeInMillisAsSeconds;
using testing::internal::ForEach;
+using testing::internal::FormatTimeInMillisAsSeconds;
using testing::internal::GTestFlagSaver;
using testing::internal::GetCurrentOsStackTraceExceptTop;
using testing::internal::GetElementOr;
@@ -157,9 +162,17 @@ using testing::internal::GetRandomSeedFromFlag;
using testing::internal::GetTestTypeId;
using testing::internal::GetTypeId;
using testing::internal::GetUnitTestImpl;
+using testing::internal::ImplicitlyConvertible;
using testing::internal::Int32;
using testing::internal::Int32FromEnvOrDie;
+using testing::internal::IsAProtocolMessage;
+using testing::internal::IsContainer;
+using testing::internal::IsContainerTest;
+using testing::internal::IsNotContainer;
+using testing::internal::NativeArray;
using testing::internal::ParseInt32Flag;
+using testing::internal::RemoveConst;
+using testing::internal::RemoveReference;
using testing::internal::ShouldRunTestOnShard;
using testing::internal::ShouldShard;
using testing::internal::ShouldUseColor;
@@ -171,7 +184,9 @@ using testing::internal::TestEventListenersAccessor;
using testing::internal::TestResultAccessor;
using testing::internal::UInt32;
using testing::internal::WideStringToUtf8;
+using testing::internal::kCopy;
using testing::internal::kMaxRandomSeed;
+using testing::internal::kReference;
using testing::internal::kTestTypeIdInGoogleTest;
using testing::internal::scoped_ptr;
@@ -184,6 +199,10 @@ using testing::internal::GetCapturedStdout;
using testing::internal::ThreadWithParam;
#endif
+#if GTEST_HAS_PROTOBUF_
+using ::testing::internal::TestMessage;
+#endif // GTEST_HAS_PROTOBUF_
+
class TestingVector : public std::vector<int> {
};
@@ -323,7 +342,7 @@ TEST(NullLiteralTest, IsFalseForNonNullLiterals) {
}
#ifdef __BORLANDC__
-// Restores warnings after previous "#pragma option push" supressed them
+// Restores warnings after previous "#pragma option push" suppressed them.
#pragma option pop
#endif
@@ -1353,7 +1372,7 @@ void DoesNotAbortHelper(bool* aborted) {
}
#ifdef __BORLANDC__
-// Restores warnings after previous "#pragma option push" supressed them
+// Restores warnings after previous "#pragma option push" suppressed them.
#pragma option pop
#endif
@@ -1371,7 +1390,7 @@ static int global_var = 0;
#define GTEST_USE_UNPROTECTED_COMMA_ global_var++, global_var++
TEST_F(ExpectFatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) {
-#ifndef __BORLANDC__
+#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600
// ICE's in C++Builder 2007.
EXPECT_FATAL_FAILURE({
GTEST_USE_UNPROTECTED_COMMA_;
@@ -3490,10 +3509,13 @@ TEST(AssertionTest, ASSERT_TRUE) {
// Tests ASSERT_TRUE(predicate) for predicates returning AssertionResult.
TEST(AssertionTest, AssertTrueWithAssertionResult) {
ASSERT_TRUE(ResultIsEven(2));
+#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600
+ // ICE's in C++Builder 2007.
EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEven(3)),
"Value of: ResultIsEven(3)\n"
" Actual: false (3 is odd)\n"
"Expected: true");
+#endif
ASSERT_TRUE(ResultIsEvenNoExplanation(2));
EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEvenNoExplanation(3)),
"Value of: ResultIsEvenNoExplanation(3)\n"
@@ -3513,10 +3535,13 @@ TEST(AssertionTest, ASSERT_FALSE) {
// Tests ASSERT_FALSE(predicate) for predicates returning AssertionResult.
TEST(AssertionTest, AssertFalseWithAssertionResult) {
ASSERT_FALSE(ResultIsEven(3));
+#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600
+ // ICE's in C++Builder 2007.
EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEven(2)),
"Value of: ResultIsEven(2)\n"
" Actual: true (2 is even)\n"
"Expected: false");
+#endif
ASSERT_FALSE(ResultIsEvenNoExplanation(3));
EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEvenNoExplanation(2)),
"Value of: ResultIsEvenNoExplanation(2)\n"
@@ -3628,13 +3653,15 @@ void ThrowNothing() {}
// Tests ASSERT_THROW.
TEST(AssertionTest, ASSERT_THROW) {
ASSERT_THROW(ThrowAnInteger(), int);
-#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600 || defined(_DEBUG)
- // ICE's in C++Builder 2007 (Release build).
+
+#ifndef __BORLANDC__
+ // ICE's in C++Builder 2007 and 2009.
EXPECT_FATAL_FAILURE(
ASSERT_THROW(ThrowAnInteger(), bool),
"Expected: ThrowAnInteger() throws an exception of type bool.\n"
" Actual: it throws a different type.");
#endif
+
EXPECT_FATAL_FAILURE(
ASSERT_THROW(ThrowNothing(), bool),
"Expected: ThrowNothing() throws an exception of type bool.\n"
@@ -6256,8 +6283,17 @@ TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) {
SetEnv("TERM", "xterm-color"); // TERM supports colors.
EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+ SetEnv("TERM", "xterm-256color"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "screen"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
SetEnv("TERM", "linux"); // TERM supports colors.
EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "cygwin"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
#endif // GTEST_OS_WINDOWS
}
@@ -6695,3 +6731,347 @@ TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks) {
EXPECT_FALSE(is_destroyed);
delete listener;
}
+
+// Sanity tests to ensure that the alternative, verbose spellings of
+// some of the macros work. We don't test them thoroughly as that
+// would be quite involved. Since their implementations are
+// straightforward, and they are rarely used, we'll just rely on the
+// users to tell us when they are broken.
+GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST.
+ GTEST_SUCCEED() << "OK"; // GTEST_SUCCEED is the same as SUCCEED.
+
+ // GTEST_FAIL is the same as FAIL.
+ EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure",
+ "An expected failure");
+}
+
+// Tests for internal utilities necessary for implementation of the universal
+// printing.
+// TODO(vladl@google.com): Find a better home for them.
+
+class ConversionHelperBase {};
+class ConversionHelperDerived : public ConversionHelperBase {};
+
+// Tests that IsAProtocolMessage<T>::value is a compile-time constant.
+TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) {
+ GTEST_COMPILE_ASSERT_(IsAProtocolMessage<ProtocolMessage>::value,
+ const_true);
+ GTEST_COMPILE_ASSERT_(!IsAProtocolMessage<int>::value, const_false);
+}
+
+// Tests that IsAProtocolMessage<T>::value is true when T is
+// ProtocolMessage or a sub-class of it.
+TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) {
+ EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value);
+ EXPECT_TRUE(IsAProtocolMessage<ProtocolMessage>::value);
+#if GTEST_HAS_PROTOBUF_
+ EXPECT_TRUE(IsAProtocolMessage<const TestMessage>::value);
+#endif // GTEST_HAS_PROTOBUF_
+}
+
+// Tests that IsAProtocolMessage<T>::value is false when T is neither
+// ProtocolMessage nor a sub-class of it.
+TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) {
+ EXPECT_FALSE(IsAProtocolMessage<int>::value);
+ EXPECT_FALSE(IsAProtocolMessage<const ConversionHelperBase>::value);
+}
+
+// Tests that CompileAssertTypesEqual compiles when the type arguments are
+// equal.
+TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) {
+ CompileAssertTypesEqual<void, void>();
+ CompileAssertTypesEqual<int*, int*>();
+}
+
+// Tests that RemoveReference does not affect non-reference types.
+TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) {
+ CompileAssertTypesEqual<int, RemoveReference<int>::type>();
+ CompileAssertTypesEqual<const char, RemoveReference<const char>::type>();
+}
+
+// Tests that RemoveReference removes reference from reference types.
+TEST(RemoveReferenceTest, RemovesReference) {
+ CompileAssertTypesEqual<int, RemoveReference<int&>::type>();
+ CompileAssertTypesEqual<const char, RemoveReference<const char&>::type>();
+}
+
+// Tests GTEST_REMOVE_REFERENCE_.
+
+template <typename T1, typename T2>
+void TestGTestRemoveReference() {
+ CompileAssertTypesEqual<T1, GTEST_REMOVE_REFERENCE_(T2)>();
+}
+
+TEST(RemoveReferenceTest, MacroVersion) {
+ TestGTestRemoveReference<int, int>();
+ TestGTestRemoveReference<const char, const char&>();
+}
+
+
+// Tests that RemoveConst does not affect non-const types.
+TEST(RemoveConstTest, DoesNotAffectNonConstType) {
+ CompileAssertTypesEqual<int, RemoveConst<int>::type>();
+ CompileAssertTypesEqual<char&, RemoveConst<char&>::type>();
+}
+
+// Tests that RemoveConst removes const from const types.
+TEST(RemoveConstTest, RemovesConst) {
+ CompileAssertTypesEqual<int, RemoveConst<const int>::type>();
+ CompileAssertTypesEqual<char[2], RemoveConst<const char[2]>::type>();
+ CompileAssertTypesEqual<char[2][3], RemoveConst<const char[2][3]>::type>();
+}
+
+// Tests GTEST_REMOVE_CONST_.
+
+template <typename T1, typename T2>
+void TestGTestRemoveConst() {
+ CompileAssertTypesEqual<T1, GTEST_REMOVE_CONST_(T2)>();
+}
+
+TEST(RemoveConstTest, MacroVersion) {
+ TestGTestRemoveConst<int, int>();
+ TestGTestRemoveConst<double&, double&>();
+ TestGTestRemoveConst<char, const char>();
+}
+
+// Tests GTEST_REMOVE_REFERENCE_AND_CONST_.
+
+template <typename T1, typename T2>
+void TestGTestRemoveReferenceAndConst() {
+ CompileAssertTypesEqual<T1, GTEST_REMOVE_REFERENCE_AND_CONST_(T2)>();
+}
+
+TEST(RemoveReferenceToConstTest, Works) {
+ TestGTestRemoveReferenceAndConst<int, int>();
+ TestGTestRemoveReferenceAndConst<double, double&>();
+ TestGTestRemoveReferenceAndConst<char, const char>();
+ TestGTestRemoveReferenceAndConst<char, const char&>();
+ TestGTestRemoveReferenceAndConst<const char*, const char*>();
+}
+
+// Tests that AddReference does not affect reference types.
+TEST(AddReferenceTest, DoesNotAffectReferenceType) {
+ CompileAssertTypesEqual<int&, AddReference<int&>::type>();
+ CompileAssertTypesEqual<const char&, AddReference<const char&>::type>();
+}
+
+// Tests that AddReference adds reference to non-reference types.
+TEST(AddReferenceTest, AddsReference) {
+ CompileAssertTypesEqual<int&, AddReference<int>::type>();
+ CompileAssertTypesEqual<const char&, AddReference<const char>::type>();
+}
+
+// Tests GTEST_ADD_REFERENCE_.
+
+template <typename T1, typename T2>
+void TestGTestAddReference() {
+ CompileAssertTypesEqual<T1, GTEST_ADD_REFERENCE_(T2)>();
+}
+
+TEST(AddReferenceTest, MacroVersion) {
+ TestGTestAddReference<int&, int>();
+ TestGTestAddReference<const char&, const char&>();
+}
+
+// Tests GTEST_REFERENCE_TO_CONST_.
+
+template <typename T1, typename T2>
+void TestGTestReferenceToConst() {
+ CompileAssertTypesEqual<T1, GTEST_REFERENCE_TO_CONST_(T2)>();
+}
+
+TEST(GTestReferenceToConstTest, Works) {
+ TestGTestReferenceToConst<const char&, char>();
+ TestGTestReferenceToConst<const int&, const int>();
+ TestGTestReferenceToConst<const double&, double>();
+ TestGTestReferenceToConst<const String&, const String&>();
+}
+
+// Tests that ImplicitlyConvertible<T1, T2>::value is a compile-time constant.
+TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) {
+ GTEST_COMPILE_ASSERT_((ImplicitlyConvertible<int, int>::value), const_true);
+ GTEST_COMPILE_ASSERT_((!ImplicitlyConvertible<void*, int*>::value),
+ const_false);
+}
+
+// Tests that ImplicitlyConvertible<T1, T2>::value is true when T1 can
+// be implicitly converted to T2.
+TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) {
+ EXPECT_TRUE((ImplicitlyConvertible<int, double>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<double, int>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<int*, void*>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<int*, const int*>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<ConversionHelperDerived&,
+ const ConversionHelperBase&>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<const ConversionHelperBase,
+ ConversionHelperBase>::value));
+}
+
+// Tests that ImplicitlyConvertible<T1, T2>::value is false when T1
+// cannot be implicitly converted to T2.
+TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) {
+ EXPECT_FALSE((ImplicitlyConvertible<double, int*>::value));
+ EXPECT_FALSE((ImplicitlyConvertible<void*, int*>::value));
+ EXPECT_FALSE((ImplicitlyConvertible<const int*, int*>::value));
+ EXPECT_FALSE((ImplicitlyConvertible<ConversionHelperBase&,
+ ConversionHelperDerived&>::value));
+}
+
+// Tests IsContainerTest.
+
+class NonContainer {};
+
+TEST(IsContainerTestTest, WorksForNonContainer) {
+ EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<int>(0)));
+ EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<char[5]>(0)));
+ EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<NonContainer>(0)));
+}
+
+TEST(IsContainerTestTest, WorksForContainer) {
+ EXPECT_EQ(sizeof(IsContainer),
+ sizeof(IsContainerTest<std::vector<bool> >(0)));
+ EXPECT_EQ(sizeof(IsContainer),
+ sizeof(IsContainerTest<std::map<int, double> >(0)));
+}
+
+// Tests ArrayEq().
+
+TEST(ArrayEqTest, WorksForDegeneratedArrays) {
+ EXPECT_TRUE(ArrayEq(5, 5L));
+ EXPECT_FALSE(ArrayEq('a', 0));
+}
+
+TEST(ArrayEqTest, WorksForOneDimensionalArrays) {
+ const int a[] = { 0, 1 };
+ long b[] = { 0, 1 };
+ EXPECT_TRUE(ArrayEq(a, b));
+ EXPECT_TRUE(ArrayEq(a, 2, b));
+
+ b[0] = 2;
+ EXPECT_FALSE(ArrayEq(a, b));
+ EXPECT_FALSE(ArrayEq(a, 1, b));
+}
+
+TEST(ArrayEqTest, WorksForTwoDimensionalArrays) {
+ const char a[][3] = { "hi", "lo" };
+ const char b[][3] = { "hi", "lo" };
+ const char c[][3] = { "hi", "li" };
+
+ EXPECT_TRUE(ArrayEq(a, b));
+ EXPECT_TRUE(ArrayEq(a, 2, b));
+
+ EXPECT_FALSE(ArrayEq(a, c));
+ EXPECT_FALSE(ArrayEq(a, 2, c));
+}
+
+// Tests ArrayAwareFind().
+
+TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) {
+ const char a[] = "hello";
+ EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o'));
+ EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x'));
+}
+
+TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) {
+ int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
+ const int b[2] = { 2, 3 };
+ EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b));
+
+ const int c[2] = { 6, 7 };
+ EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c));
+}
+
+// Tests CopyArray().
+
+TEST(CopyArrayTest, WorksForDegeneratedArrays) {
+ int n = 0;
+ CopyArray('a', &n);
+ EXPECT_EQ('a', n);
+}
+
+TEST(CopyArrayTest, WorksForOneDimensionalArrays) {
+ const char a[3] = "hi";
+ int b[3];
+ CopyArray(a, &b);
+ EXPECT_TRUE(ArrayEq(a, b));
+
+ int c[3];
+ CopyArray(a, 3, c);
+ EXPECT_TRUE(ArrayEq(a, c));
+}
+
+TEST(CopyArrayTest, WorksForTwoDimensionalArrays) {
+ const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } };
+ int b[2][3];
+ CopyArray(a, &b);
+ EXPECT_TRUE(ArrayEq(a, b));
+
+ int c[2][3];
+ CopyArray(a, 2, c);
+ EXPECT_TRUE(ArrayEq(a, c));
+}
+
+// Tests NativeArray.
+
+TEST(NativeArrayTest, ConstructorFromArrayWorks) {
+ const int a[3] = { 0, 1, 2 };
+ NativeArray<int> na(a, 3, kReference);
+ EXPECT_EQ(3U, na.size());
+ EXPECT_EQ(a, na.begin());
+}
+
+TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) {
+ typedef int Array[2];
+ Array* a = new Array[1];
+ (*a)[0] = 0;
+ (*a)[1] = 1;
+ NativeArray<int> na(*a, 2, kCopy);
+ EXPECT_NE(*a, na.begin());
+ delete[] a;
+ EXPECT_EQ(0, na.begin()[0]);
+ EXPECT_EQ(1, na.begin()[1]);
+
+ // We rely on the heap checker to verify that na deletes the copy of
+ // array.
+}
+
+TEST(NativeArrayTest, TypeMembersAreCorrect) {
+ StaticAssertTypeEq<char, NativeArray<char>::value_type>();
+ StaticAssertTypeEq<int[2], NativeArray<int[2]>::value_type>();
+
+ StaticAssertTypeEq<const char*, NativeArray<char>::const_iterator>();
+ StaticAssertTypeEq<const bool(*)[2], NativeArray<bool[2]>::const_iterator>();
+}
+
+TEST(NativeArrayTest, MethodsWork) {
+ const int a[3] = { 0, 1, 2 };
+ NativeArray<int> na(a, 3, kCopy);
+ ASSERT_EQ(3U, na.size());
+ EXPECT_EQ(3, na.end() - na.begin());
+
+ NativeArray<int>::const_iterator it = na.begin();
+ EXPECT_EQ(0, *it);
+ ++it;
+ EXPECT_EQ(1, *it);
+ it++;
+ EXPECT_EQ(2, *it);
+ ++it;
+ EXPECT_EQ(na.end(), it);
+
+ EXPECT_TRUE(na == na);
+
+ NativeArray<int> na2(a, 3, kReference);
+ EXPECT_TRUE(na == na2);
+
+ const int b1[3] = { 0, 1, 1 };
+ const int b2[4] = { 0, 1, 2, 3 };
+ EXPECT_FALSE(na == NativeArray<int>(b1, 3, kReference));
+ EXPECT_FALSE(na == NativeArray<int>(b2, 4, kCopy));
+}
+
+TEST(NativeArrayTest, WorksForTwoDimensionalArray) {
+ const char a[2][3] = { "hi", "lo" };
+ NativeArray<char[3]> na(a, 2, kReference);
+ ASSERT_EQ(2U, na.size());
+ EXPECT_EQ(a, na.begin());
+}
diff --git a/testing/gtest/test/run_tests_util.py b/testing/gtest/test/run_tests_util.py
index 9e57931..a123569 100755
--- a/testing/gtest/test/run_tests_util.py
+++ b/testing/gtest/test/run_tests_util.py
@@ -171,7 +171,7 @@ class TestRunner(object):
def __init__(self,
script_dir,
- build_dir_var_name='GTEST_BUILD_DIR',
+ build_dir_var_name='BUILD_DIR',
injected_os=os,
injected_subprocess=subprocess,
injected_build_dir_finder=_GetGtestBuildDir):
diff --git a/testing/gtestmain.target.mk b/testing/gtestmain.target.mk
index 86208d7..e1db871 100644
--- a/testing/gtestmain.target.mk
+++ b/testing/gtestmain.target.mk
@@ -18,6 +18,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -49,6 +50,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -92,11 +94,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/third_party/libevent/libevent.target.mk b/third_party/libevent/libevent.target.mk
index 1f06b0e..a06862c 100644
--- a/third_party/libevent/libevent.target.mk
+++ b/third_party/libevent/libevent.target.mk
@@ -17,6 +17,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -48,6 +49,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -106,11 +108,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp
index ff191b4..0c68ec6 100644
--- a/third_party/libjingle/libjingle.gyp
+++ b/third_party/libjingle/libjingle.gyp
@@ -152,11 +152,13 @@
'source/talk/base/DiskCacheStd.h',
'source/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h',
+ 'source/talk/base/asyncfile.cc',
'source/talk/base/asyncfile.h',
'source/talk/base/asynchttprequest.cc',
'source/talk/base/asynchttprequest.h',
'source/talk/base/asyncpacketsocket.cc',
'source/talk/base/asyncpacketsocket.h',
+ 'source/talk/base/asyncsocket.cc',
'source/talk/base/asyncsocket.h',
'source/talk/base/asynctcpsocket.cc',
'source/talk/base/asynctcpsocket.h',
@@ -234,10 +236,13 @@
'source/talk/base/socketadapters.h',
'source/talk/base/socketaddress.cc',
'source/talk/base/socketaddress.h',
+ 'source/talk/base/socketaddresspair.cc',
+ 'source/talk/base/socketaddresspair.h',
'source/talk/base/socketfactory.h',
'source/talk/base/socketpool.cc',
'source/talk/base/socketpool.h',
'source/talk/base/socketserver.h',
+ 'source/talk/base/socketstream.cc',
'source/talk/base/socketstream.h',
'source/talk/base/ssladapter.cc',
'source/talk/base/ssladapter.h',
@@ -377,6 +382,7 @@
'source/talk/p2p/base/session.cc',
'source/talk/p2p/base/session.h',
'source/talk/p2p/base/sessionclient.h',
+ 'source/talk/p2p/base/sessiondescription.cc',
'source/talk/p2p/base/sessiondescription.h',
'source/talk/p2p/base/sessionid.h',
'source/talk/p2p/base/sessionmanager.cc',
diff --git a/third_party/libjingle/libjingle.target.mk b/third_party/libjingle/libjingle.target.mk
index 2b399d3..13d0672 100644
--- a/third_party/libjingle/libjingle.target.mk
+++ b/third_party/libjingle/libjingle.target.mk
@@ -23,6 +23,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -76,6 +77,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -110,8 +112,10 @@ INCS_Release := -Ithird_party/libjingle/overrides \
-I.
OBJS := $(obj).target/$(TARGET)/third_party/libjingle/overrides/talk/xmllite/qname.o \
+ $(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/asyncfile.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/asynchttprequest.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/asyncpacketsocket.o \
+ $(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/asyncsocket.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/asynctcpsocket.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/asyncudpsocket.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/autodetectproxy.o \
@@ -143,7 +147,9 @@ OBJS := $(obj).target/$(TARGET)/third_party/libjingle/overrides/talk/xmllite/qna
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/signalthread.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/socketadapters.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/socketaddress.o \
+ $(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/socketaddresspair.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/socketpool.o \
+ $(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/socketstream.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/ssladapter.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/sslsocketfactory.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/base/stream.o \
@@ -210,11 +216,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/third_party/libjingle/libjingle_p2p.target.mk b/third_party/libjingle/libjingle_p2p.target.mk
index a32e0f2..734bd2d 100644
--- a/third_party/libjingle/libjingle_p2p.target.mk
+++ b/third_party/libjingle/libjingle_p2p.target.mk
@@ -23,6 +23,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -76,6 +77,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-pthread \
-D_REENTRANT \
@@ -118,6 +120,7 @@ OBJS := $(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/const
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/relayport.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/session.o \
+ $(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/sessiondescription.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/sessionmanager.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/sessionmessages.o \
$(obj).target/$(TARGET)/third_party/libjingle/source/talk/p2p/base/parsing.o \
@@ -160,11 +163,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/third_party/libjingle/overrides/talk/base/scoped_ptr.h b/third_party/libjingle/overrides/talk/base/scoped_ptr.h
index bfe5f14..cc4fec9 100644
--- a/third_party/libjingle/overrides/talk/base/scoped_ptr.h
+++ b/third_party/libjingle/overrides/talk/base/scoped_ptr.h
@@ -5,10 +5,11 @@
// This file overrides the inclusion of talk/base/scoped_ptr.h. We use
// a version of scoped_ptr from Chromium base, to avoid multiple definitions.
-#ifndef OVERRIDES_TALK_BASE_SCOPED_PTR_H__
-#define OVERRIDES_TALK_BASE_SCOPED_PTR_H__
+#ifndef OVERRIDES_TALK_BASE_SCOPED_PTR_H_
+#define OVERRIDES_TALK_BASE_SCOPED_PTR_H_
#include "base/scoped_ptr.h"
+#include "talk/base/common.h"
namespace talk_base {
@@ -17,4 +18,4 @@ using ::scoped_array;
} // namespace talk_base
-#endif // OVERRIDES_TALK_BASE_SCOPED_PTR_H__
+#endif // OVERRIDES_TALK_BASE_SCOPED_PTR_H_
diff --git a/third_party/libjingle/source/README b/third_party/libjingle/source/README
index 2c4d73d..bdccd20 100644
--- a/third_party/libjingle/source/README
+++ b/third_party/libjingle/source/README
@@ -1,57 +1,74 @@
-Libjingle
-
-Libjingle is a set of components provided by Google to interoperate with Google
-Talk's peer-to-peer and voice capabilities. This package will create several
-static libraries you may link to your project as needed.
-
--talk - No source files in talk/, just these subdirectories
-|-base - Contains basic low-level portable utility functions for
-| things like threads and sockets
-|-p2p - The P2P stack
- |-base - Base p2p functionality
- |-client - Hooks to tie it into XMPP
-|-session - Signaling
- |-phone - Signaling code specific to making phone calls
-|-third_party - Components that aren't ours
- |-mediastreamer - Media components for dealing with sound hardware and
- | voice codecs
-|-xmllite - XML parser
-|-xmpp - XMPP engine
-
-In addition, this package contains two examples in talk/examples which
-illustrate the basic concepts of how the provided classes work.
-
-The xmllite component of libjingle depends on expat. You can download expat
-from http://expat.sourceforge.net/.
-
-mediastreamer, the media components used by the example applications depend on
-the oRTP and iLBC components from linphone, which can be found at
-http://www.linphone.org. Linphone, in turn depends on GLib, which can be found
-at http://www.gtk.org. This GLib dependency should be removed in future
-releases.
-
-Building Libjingle
-
-Once the dependencies are installed, run ./configure. ./configure will return
-an error if it failed to locate the proper dependencies. If ./configure
-succeeds, run 'make' to build the components and examples.
-
-When the build is complete, you can run the call example from
-talk/examples/call and the pcp example from talk/examples/pcp.
-
-Relay Server
-
-Libjingle will also build a relay server that may be used to relay traffic
-when a direct peer-to-peer connection could not be established. The relay
-server will build in talk/p2p/base/relayserver and will listen on UDP
-ports 5000 and 5001. See the Libjingle Developer Guide at
-http://code.google.com/apis/talk/index.html for information about configuring
-a client to use this relay server.
-
-STUN Server
-
-Lastly, Libjingle builds a STUN server which implements the STUN protocol for
-Simple Traversal of UDP over NAT. The STUN server is built as
-talk/p2p/base/stunserver and listens on UDP port 7000. See the Libjingle
-Developer Guide at http://code.google.com/apis/talk/index.html for information
-about configuring a client to use this STUN server.
+Libjingle
+
+1. Introduction
+
+Libjingle is a set of components provided by Google to implement Jingle
+protocols XEP-166 (http://xmpp.org/extensions/xep-0166.html) and XEP-167
+(http://xmpp.org/extensions/xep-0167.html). Libjingle is also backward
+compatible with Google Talk Call Signaling
+(http://code.google.com/apis/talk/call_signaling.html). This package will
+create several static libraries you may link to your projects as needed.
+
+-talk - No source files in talk/, just these subdirectories
+|-base - Contains basic low-level portable utility functions for
+| things like threads and sockets
+|-p2p - The P2P stack
+ |-base - Base p2p functionality
+ |-client - Hooks to tie it into XMPP
+|-session - Signaling
+ |-phone - Signaling code specific to making phone calls
+ |-tunnel - Tunnel session and channel
+|-xmllite - XML parser
+|-xmpp - XMPP engine
+
+In addition, this package contains two examples in talk/examples which
+illustrate the basic concepts of how the provided classes work.
+
+2. How to Build
+
+Libjingle is built with swtoolkit (http://code.google.com/p/swtoolkit/), which
+is a set of extensions to the open-source SCons build tool (www.scons.org).
+ * First, install Python 2.4 or later from http://www.python.org/.
+
+ * Second, install the stand alone scons-local package 2.0.0 or later from
+ http://www.scons.org/download.php and set an environment variable,
+ SCONS_DIR, to point to the directory containing SCons, for example,
+ /src/libjingle/scons-local/scons-local-2.0.0.final.0/.
+
+ * Third, install swtoolkit from http://code.google.com/p/swtoolkit/.
+
+ * Finally, Libjingle depends on two open-source projects, expat and srtp.
+ Download expat from http://sourceforge.net/projects/expat/ to
+ talk/third_party/expat-2.0.1/. Follow the instructions at
+ http://sourceforge.net/projects/srtp/develop to download latest srtp to
+ talk/third_party/srtp. Note that srtp-1.4.4 does not work since it misses
+ the extensions used by Libjingle.
+ If you put expat or srtp in a different directory, you need to edit
+ talk/libjingle.scons correspondingly.
+
+2.1 Build Libjingle under Linux or OS X
+ * First, make sure the SCONS_DIR environment variable is set correctly.
+ * Second, run talk/third_party/expat-2.0.1/configure and
+ talk/third_party/srtp/configure.
+ * Third, go to the talk/ directory and run $path_to_swtoolkit/hammer.sh. Run
+ $path_to_swtoolkit/hammer.sh --help for information on how to build for
+ different modes.
+
+2.2 Build Libjingle under Windows
+ * First, make sure the SCONS_DIR environment variable is set correctly and
+ Microsoft Visual Studio is installed.
+ * Second, copy talk/third_party/srtp/config.hw to
+ talk/third_party/srtp/crypto/include/config.h.
+ * Third, go to the talk/ directory and run $path_to_swtoolkit/hammer.bat. Run
+ $path_to_swtoolkit/hammer.sh --help for information on how to build for
+ different modes. You can run the last step under Visual Studio Command
+ Prompt if Visual Studio tools are not under the path environment variable.
+
+The built binaries are under talk/build/dbg/staging or talk/build/opt/staging,
+depending on the build mode. When the build is complete, you can run the
+examples, login or call. Libjingle also builds two server tools, a relay server
+and a STUN server. The relay server may be used to relay traffic when a direct
+peer-to-peer connection could not be established. The STUN Server implements the
+STUN protocol for Simple Traversal of UDP over NAT. See the Libjingle Developer
+Guide at http://code.google.com/apis/talk/index.html for information about
+configuring a client to use this relay server and this STUN server. \ No newline at end of file
diff --git a/third_party/libjingle/source/talk/base/asyncfile.h b/third_party/libjingle/source/talk/base/asyncfile.h
index 1437979..8af52be 100644
--- a/third_party/libjingle/source/talk/base/asyncfile.h
+++ b/third_party/libjingle/source/talk/base/asyncfile.h
@@ -1,27 +1,27 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -35,8 +35,9 @@ namespace talk_base {
// Provides the ability to perform file I/O asynchronously.
// TODO: Create a common base class with AsyncSocket.
class AsyncFile {
-public:
- virtual ~AsyncFile() {}
+ public:
+ AsyncFile();
+ virtual ~AsyncFile();
// Determines whether the file will receive read events.
virtual bool readable() = 0;
@@ -48,9 +49,9 @@ public:
sigslot::signal1<AsyncFile*> SignalReadEvent;
sigslot::signal1<AsyncFile*> SignalWriteEvent;
- sigslot::signal2<AsyncFile*,int> SignalCloseEvent;
+ sigslot::signal2<AsyncFile*, int> SignalCloseEvent;
};
-} // namespace talk_base
+} // namespace talk_base
-#endif // TALK_BASE_ASYNCFILE_H__
+#endif // TALK_BASE_ASYNCFILE_H__
diff --git a/third_party/libjingle/source/talk/base/asynchttprequest.cc b/third_party/libjingle/source/talk/base/asynchttprequest.cc
index 394cc6b..1e05d82 100644
--- a/third_party/libjingle/source/talk/base/asynchttprequest.cc
+++ b/third_party/libjingle/source/talk/base/asynchttprequest.cc
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2009, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -45,6 +45,9 @@ AsyncHttpRequest::AsyncHttpRequest(const std::string &user_agent)
&AsyncHttpRequest::OnComplete);
}
+AsyncHttpRequest::~AsyncHttpRequest() {
+}
+
void AsyncHttpRequest::OnWorkStart() {
factory_.SetProxy(proxy_);
if (secure_)
diff --git a/third_party/libjingle/source/talk/base/asynchttprequest.h b/third_party/libjingle/source/talk/base/asynchttprequest.h
index 3ab5d04..f5d7f46 100644
--- a/third_party/libjingle/source/talk/base/asynchttprequest.h
+++ b/third_party/libjingle/source/talk/base/asynchttprequest.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2009, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -48,6 +48,7 @@ class FirewallManager;
class AsyncHttpRequest : public SignalThread {
public:
explicit AsyncHttpRequest(const std::string &user_agent);
+ ~AsyncHttpRequest();
void set_proxy(const ProxyInfo& proxy) {
proxy_ = proxy;
diff --git a/third_party/libjingle/source/talk/base/asyncsocket.h b/third_party/libjingle/source/talk/base/asyncsocket.h
index 5cf1ada..1541894 100644
--- a/third_party/libjingle/source/talk/base/asyncsocket.h
+++ b/third_party/libjingle/source/talk/base/asyncsocket.h
@@ -1,27 +1,27 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -39,6 +39,9 @@ namespace talk_base {
// Provides the ability to perform socket I/O asynchronously.
class AsyncSocket : public Socket {
public:
+ AsyncSocket();
+ virtual ~AsyncSocket();
+
virtual AsyncSocket* Accept(SocketAddress* paddr) = 0;
sigslot::signal1<AsyncSocket*> SignalReadEvent; // ready to read
@@ -53,26 +56,9 @@ class AsyncSocketAdapter : public AsyncSocket, public sigslot::has_slots<> {
// However, subclasses which support detached mode must override any methods
// that will be called during the detached period (usually GetState()), to
// avoid dereferencing a null pointer.
- explicit AsyncSocketAdapter(AsyncSocket* socket) : socket_(NULL) {
- Attach(socket);
- }
- virtual ~AsyncSocketAdapter() {
- delete socket_;
- }
- void Attach(AsyncSocket* socket) {
- ASSERT(!socket_);
- socket_ = socket;
- if (socket_) {
- socket_->SignalConnectEvent.connect(this,
- &AsyncSocketAdapter::OnConnectEvent);
- socket_->SignalReadEvent.connect(this,
- &AsyncSocketAdapter::OnReadEvent);
- socket_->SignalWriteEvent.connect(this,
- &AsyncSocketAdapter::OnWriteEvent);
- socket_->SignalCloseEvent.connect(this,
- &AsyncSocketAdapter::OnCloseEvent);
- }
- }
+ explicit AsyncSocketAdapter(AsyncSocket* socket);
+ virtual ~AsyncSocketAdapter();
+ void Attach(AsyncSocket* socket);
virtual SocketAddress GetLocalAddress() const {
return socket_->GetLocalAddress();
}
diff --git a/third_party/libjingle/source/talk/base/asynctcpsocket.cc b/third_party/libjingle/source/talk/base/asynctcpsocket.cc
index 43cef73..37c7a6c 100644
--- a/third_party/libjingle/source/talk/base/asynctcpsocket.cc
+++ b/third_party/libjingle/source/talk/base/asynctcpsocket.cc
@@ -1,34 +1,30 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#if defined(_MSC_VER) && _MSC_VER < 1300
-#pragma warning(disable:4786)
-#endif
-
#include "talk/base/asynctcpsocket.h"
#include <cstring>
@@ -37,15 +33,9 @@
#include "talk/base/common.h"
#include "talk/base/logging.h"
-#if defined(_MSC_VER) && _MSC_VER < 1300
-namespace std {
- using ::strerror;
-}
-#endif
-
#ifdef POSIX
#include <errno.h>
-#endif // POSIX
+#endif // POSIX
namespace talk_base {
@@ -56,7 +46,17 @@ const size_t PKT_LEN_SIZE = sizeof(PacketLength);
const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
-AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket), insize_(BUF_SIZE), inpos_(0), outsize_(BUF_SIZE), outpos_(0) {
+AsyncTCPSocket* AsyncTCPSocket::Create(SocketFactory* factory) {
+ AsyncSocket* sock = factory->CreateAsyncSocket(SOCK_STREAM);
+ return (sock) ? new AsyncTCPSocket(sock) : NULL;
+}
+
+AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket)
+ : AsyncPacketSocket(socket),
+ insize_(BUF_SIZE),
+ inpos_(0),
+ outsize_(BUF_SIZE),
+ outpos_(0) {
inbuf_ = new char[insize_];
outbuf_ = new char[outsize_];
@@ -90,7 +90,7 @@ int AsyncTCPSocket::Send(const void *pv, size_t cb) {
int res = Flush();
if (res <= 0) {
// drop packet if we made no progress
- outpos_ = 0;
+ outpos_ = 0;
return res;
}
@@ -98,7 +98,8 @@ int AsyncTCPSocket::Send(const void *pv, size_t cb) {
return static_cast<int>(cb);
}
-int AsyncTCPSocket::SendTo(const void *pv, size_t cb, const SocketAddress& addr) {
+int AsyncTCPSocket::SendTo(const void *pv, size_t cb,
+ const SocketAddress& addr) {
if (addr == GetRemoteAddress())
return Send(pv, cb);
@@ -198,4 +199,4 @@ void AsyncTCPSocket::OnCloseEvent(AsyncSocket* socket, int error) {
SignalClose(this, error);
}
-} // namespace talk_base
+} // namespace talk_base
diff --git a/third_party/libjingle/source/talk/base/asynctcpsocket.h b/third_party/libjingle/source/talk/base/asynctcpsocket.h
index 82e02f1..8f24861 100644
--- a/third_party/libjingle/source/talk/base/asynctcpsocket.h
+++ b/third_party/libjingle/source/talk/base/asynctcpsocket.h
@@ -1,27 +1,27 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -38,10 +38,7 @@ namespace talk_base {
// buffer them in user space.
class AsyncTCPSocket : public AsyncPacketSocket {
public:
- static AsyncTCPSocket* Create(SocketFactory* factory) {
- AsyncSocket* sock = factory->CreateAsyncSocket(SOCK_STREAM);
- return (sock) ? new AsyncTCPSocket(sock) : NULL;
- }
+ static AsyncTCPSocket* Create(SocketFactory* factory);
explicit AsyncTCPSocket(AsyncSocket* socket);
virtual ~AsyncTCPSocket();
diff --git a/third_party/libjingle/source/talk/base/basictypes.h b/third_party/libjingle/source/talk/base/basictypes.h
index e98898d..71b75c6 100644
--- a/third_party/libjingle/source/talk/base/basictypes.h
+++ b/third_party/libjingle/source/talk/base/basictypes.h
@@ -2,32 +2,36 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TALK_BASE_BASICTYPES_H__
#define TALK_BASE_BASICTYPES_H__
+#ifndef WIN32
+#include <stdint.h> // for uintptr_t
+#endif
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -82,6 +86,9 @@ namespace talk_base {
#define alignof(t) __alignof__(t)
#endif // !WIN32
#define IS_ALIGNED(p, t) (0==(reinterpret_cast<uintptr_t>(p) & (alignof(t)-1)))
+#define ALIGNP(p, t) \
+ (reinterpret_cast<uint8*>(((reinterpret_cast<uintptr_t>(p) + \
+ ((t)-1)) & ~((t)-1))))
#ifndef UNUSED
#define UNUSED(x) Unused(static_cast<const void *>(&x))
diff --git a/third_party/libjingle/source/talk/base/bytebuffer.cc b/third_party/libjingle/source/talk/base/bytebuffer.cc
index 1eb260d..9aef159 100644
--- a/third_party/libjingle/source/talk/base/bytebuffer.cc
+++ b/third_party/libjingle/source/talk/base/bytebuffer.cc
@@ -34,12 +34,6 @@
#include "talk/base/basictypes.h"
#include "talk/base/byteorder.h"
-#if defined(_MSC_VER) && _MSC_VER < 1300
-namespace std {
- using ::memcpy;
-}
-#endif
-
namespace talk_base {
static const int DEFAULT_SIZE = 4096;
@@ -71,45 +65,67 @@ ByteBuffer::~ByteBuffer() {
delete[] bytes_;
}
-bool ByteBuffer::ReadUInt8(uint8& val) {
- return ReadBytes(reinterpret_cast<char*>(&val), 1);
+bool ByteBuffer::ReadUInt8(uint8* val) {
+ if (!val) return false;
+
+ return ReadBytes(reinterpret_cast<char*>(val), 1);
}
-bool ByteBuffer::ReadUInt16(uint16& val) {
+bool ByteBuffer::ReadUInt16(uint16* val) {
+ if (!val) return false;
+
uint16 v;
if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
return false;
} else {
- val = NetworkToHost16(v);
+ *val = NetworkToHost16(v);
return true;
}
}
-bool ByteBuffer::ReadUInt24(uint32& val) {
+bool ByteBuffer::ReadUInt24(uint32* val) {
+ if (!val) return false;
+
uint32 v = 0;
if (!ReadBytes(reinterpret_cast<char*>(&v) + 1, 3)) {
return false;
} else {
- val = NetworkToHost32(v);
+ *val = NetworkToHost32(v);
return true;
}
}
-bool ByteBuffer::ReadUInt32(uint32& val) {
+bool ByteBuffer::ReadUInt32(uint32* val) {
+ if (!val) return false;
+
uint32 v;
if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
return false;
} else {
- val = NetworkToHost32(v);
+ *val = NetworkToHost32(v);
+ return true;
+ }
+}
+
+bool ByteBuffer::ReadUInt64(uint64* val) {
+ if (!val) return false;
+
+ uint64 v;
+ if (!ReadBytes(reinterpret_cast<char*>(&v), 8)) {
+ return false;
+ } else {
+ *val = NetworkToHost64(v);
return true;
}
}
-bool ByteBuffer::ReadString(std::string& val, size_t len) {
+bool ByteBuffer::ReadString(std::string* val, size_t len) {
+ if (!val) return false;
+
if (len > Length()) {
return false;
} else {
- val.append(bytes_ + start_, len);
+ val->append(bytes_ + start_, len);
start_ += len;
return true;
}
@@ -144,6 +160,11 @@ void ByteBuffer::WriteUInt32(uint32 val) {
WriteBytes(reinterpret_cast<const char*>(&v), 4);
}
+void ByteBuffer::WriteUInt64(uint64 val) {
+ uint64 v = HostToNetwork64(val);
+ WriteBytes(reinterpret_cast<const char*>(&v), 8);
+}
+
void ByteBuffer::WriteString(const std::string& val) {
WriteBytes(val.c_str(), val.size());
}
@@ -187,4 +208,4 @@ void ByteBuffer::Shift(size_t size) {
start_ = 0;
}
-} // namespace talk_base
+} // namespace talk_base
diff --git a/third_party/libjingle/source/talk/base/bytebuffer.h b/third_party/libjingle/source/talk/base/bytebuffer.h
index d5cfb00..bb162ec 100644
--- a/third_party/libjingle/source/talk/base/bytebuffer.h
+++ b/third_party/libjingle/source/talk/base/bytebuffer.h
@@ -46,17 +46,19 @@ class ByteBuffer {
size_t Length() const { return end_ - start_; }
size_t Capacity() const { return size_ - start_; }
- bool ReadUInt8(uint8& val);
- bool ReadUInt16(uint16& val);
- bool ReadUInt24(uint32& val);
- bool ReadUInt32(uint32& val);
- bool ReadString(std::string& val, size_t len); // append to val
+ bool ReadUInt8(uint8* val);
+ bool ReadUInt16(uint16* val);
+ bool ReadUInt24(uint32* val);
+ bool ReadUInt32(uint32* val);
+ bool ReadUInt64(uint64* val);
+ bool ReadString(std::string* val, size_t len); // append to val
bool ReadBytes(char* val, size_t len);
void WriteUInt8(uint8 val);
void WriteUInt16(uint16 val);
void WriteUInt24(uint32 val);
void WriteUInt32(uint32 val);
+ void WriteUInt64(uint64 val);
void WriteString(const std::string& val);
void WriteBytes(const char* val, size_t len);
diff --git a/third_party/libjingle/source/talk/base/byteorder.h b/third_party/libjingle/source/talk/base/byteorder.h
index 4153f5d..08094b8 100644
--- a/third_party/libjingle/source/talk/base/byteorder.h
+++ b/third_party/libjingle/source/talk/base/byteorder.h
@@ -40,22 +40,6 @@
namespace talk_base {
-inline uint16 HostToNetwork16(uint16 n) {
- return htons(n);
-}
-
-inline uint32 HostToNetwork32(uint32 n) {
- return htonl(n);
-}
-
-inline uint16 NetworkToHost16(uint16 n) {
- return ntohs(n);
-}
-
-inline uint32 NetworkToHost32(uint32 n) {
- return ntohl(n);
-}
-
// Reading and writing of little and big-endian numbers from memory
// TODO: Add HostEndian #defines (HE)
// TODO: Consider NetworkEndian as synonym for BigEndian, for clarity in use.
@@ -151,6 +135,38 @@ inline uint64 GetLE64(const void* memory) {
| (static_cast<uint64>(Get8(memory, 0)) << 0);
}
-} // namespace talk_base
+// Check if the current host is big endian.
+inline bool IsHostBigEndian() {
+ static const int number = 1;
+ return (0 == *reinterpret_cast<const char*>(&number));
+}
+
+inline uint16 HostToNetwork16(uint16 n) {
+ return htons(n);
+}
+
+inline uint32 HostToNetwork32(uint32 n) {
+ return htonl(n);
+}
+
+inline uint64 HostToNetwork64(uint64 n) {
+ // If the host is little endian, GetBE64 converts n to big network endian.
+ return IsHostBigEndian() ? n : GetBE64(&n);
+}
+
+inline uint16 NetworkToHost16(uint16 n) {
+ return ntohs(n);
+}
+
+inline uint32 NetworkToHost32(uint32 n) {
+ return ntohl(n);
+}
+
+inline uint64 NetworkToHost64(uint64 n) {
+ // If the host is little endian, GetBE64 converts n to little endian.
+ return IsHostBigEndian() ? n : GetBE64(&n);
+}
+
+} // namespace talk_base
-#endif // TALK_BASE_BYTEORDER_H__
+#endif // TALK_BASE_BYTEORDER_H__
diff --git a/third_party/libjingle/source/talk/base/common.h b/third_party/libjingle/source/talk/base/common.h
index e8dae87..1dfd5ba 100644
--- a/third_party/libjingle/source/talk/base/common.h
+++ b/third_party/libjingle/source/talk/base/common.h
@@ -25,8 +25,8 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TALK_BASE_COMMON_H__
-#define TALK_BASE_COMMON_H__
+#ifndef TALK_BASE_COMMON_H_
+#define TALK_BASE_COMMON_H_
#include "talk/base/constructormagic.h"
@@ -128,4 +128,11 @@ inline bool ImplicitCastToBool(bool result) { return result; }
#define CTA_MAKE_NAME(line) MAKE_NAME2(line)
#define CTA_MAKE_NAME2(line) constraint_ ## line
-#endif // TALK_BASE_COMMON_H__
+#ifdef __GNUC__
+// Forces compiler to inline, even against its better judgement. Use wisely.
+#define FORCE_INLINE __attribute__((always_inline))
+#else
+#define FORCE_INLINE
+#endif
+
+#endif // TALK_BASE_COMMON_H_
diff --git a/third_party/libjingle/source/talk/base/fileutils.h b/third_party/libjingle/source/talk/base/fileutils.h
index b87a224..8ad631f 100644
--- a/third_party/libjingle/source/talk/base/fileutils.h
+++ b/third_party/libjingle/source/talk/base/fileutils.h
@@ -121,6 +121,15 @@ class FilesystemInterface {
virtual FileStream *OpenFile(const Pathname &filename,
const std::string &mode) = 0;
+ // Atomically creates an empty file accessible only to the current user if one
+ // does not already exist at the given path, otherwise fails. This is the only
+ // secure way to create a file in a shared temp directory (e.g., C:\Temp on
+ // Windows or /tmp on Linux).
+ // Note that if it is essential that a file be successfully created then the
+ // app must generate random names and retry on failure, or else it will be
+ // vulnerable to a trivial DoS.
+ virtual bool CreatePrivateFile(const Pathname &filename) = 0;
+
// This will attempt to delete the path located at filename.
// It ASSERTS and returns false if the path points to a folder or a
// non-existent file.
@@ -302,6 +311,10 @@ class Filesystem {
return EnsureDefaultFilesystem()->OpenFile(filename, mode);
}
+ static bool CreatePrivateFile(const Pathname &filename) {
+ return EnsureDefaultFilesystem()->CreatePrivateFile(filename);
+ }
+
static bool DeleteFile(const Pathname &filename) {
return EnsureDefaultFilesystem()->DeleteFile(filename);
}
diff --git a/third_party/libjingle/source/talk/base/httpbase.cc b/third_party/libjingle/source/talk/base/httpbase.cc
index ac90a30..7015145 100644
--- a/third_party/libjingle/source/talk/base/httpbase.cc
+++ b/third_party/libjingle/source/talk/base/httpbase.cc
@@ -126,7 +126,7 @@ HttpParser::Process(const char* buffer, size_t len, size_t* processed,
ProcessResult result = ProcessData(buffer + *processed, available, read,
error);
LOG(LS_VERBOSE) << "Processed data, result: " << result << " read: "
- << read << " error: " << error;
+ << read << " err: " << error;
if (PR_CONTINUE != result) {
return result;
@@ -144,7 +144,7 @@ HttpParser::Process(const char* buffer, size_t len, size_t* processed,
HttpParser::ProcessResult
HttpParser::ProcessLine(const char* line, size_t len, HttpError* error) {
LOG_F(LS_VERBOSE) << " state: " << state_ << " line: "
- << std::string(line, len) << " len: " << len << " error: "
+ << std::string(line, len) << " len: " << len << " err: "
<< error;
switch (state_) {
@@ -285,12 +285,12 @@ public:
// When the method returns, we restore the old document. Ideally, we would
// pass our StreamInterface* to DoReceiveLoop, but due to the callbacks
// of HttpParser, we would still need to store the pointer temporarily.
-
- BlockingMemoryStream stream(reinterpret_cast<char*>(buffer), buffer_len);
+ scoped_ptr<StreamInterface>
+ stream(new BlockingMemoryStream(reinterpret_cast<char*>(buffer),
+ buffer_len));
// Replace the existing document with our wrapped buffer.
- StreamInterface* prior_stream = base_->data_->document.release();
- base_->data_->document.reset(&stream);
+ base_->data_->document.swap(stream);
// Pump the I/O loop. DoReceiveLoop is guaranteed not to attempt to
// complete the I/O process, which means that our wrapper is not in danger
@@ -301,8 +301,7 @@ public:
bool complete = base_->DoReceiveLoop(&http_error);
// Reinstall the original output document.
- base_->data_->document.release();
- base_->data_->document.reset(prior_stream);
+ base_->data_->document.swap(stream);
// If we reach the end of the receive stream, we disconnect our stream
// adapter from the HttpBase, and further calls to read will either return
@@ -318,7 +317,7 @@ public:
// Even if we are complete, if some data was read we must return SUCCESS.
// Future Reads will return EOS or ERROR based on the error_ variable.
size_t position;
- stream.GetPosition(&position);
+ stream->GetPosition(&position);
if (position > 0) {
if (read) *read = position;
result = SR_SUCCESS;
diff --git a/third_party/libjingle/source/talk/base/httpcommon.cc b/third_party/libjingle/source/talk/base/httpcommon.cc
index 24c09e4..d83255f 100644
--- a/third_party/libjingle/source/talk/base/httpcommon.cc
+++ b/third_party/libjingle/source/talk/base/httpcommon.cc
@@ -840,7 +840,7 @@ HttpAuthResult HttpAuthenticate(
std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);
#if TEST_DIGEST
- assert(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0);
+ ASSERT(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0);
#endif
std::stringstream ss;
@@ -1019,7 +1019,7 @@ HttpAuthResult HttpAuthenticate(
return HAR_IGNORE;
}
- assert(!context);
+ ASSERT(!context);
context = neg = new NegotiateAuthContext(auth_method, cred, ctx);
neg->specified_credentials = specify_credentials;
neg->steps = steps;
diff --git a/third_party/libjingle/source/talk/base/httpcommon.h b/third_party/libjingle/source/talk/base/httpcommon.h
index cd630ec..f3be3cd 100644
--- a/third_party/libjingle/source/talk/base/httpcommon.h
+++ b/third_party/libjingle/source/talk/base/httpcommon.h
@@ -180,7 +180,7 @@ bool HttpHasNthAttribute(HttpAttributeList& attributes,
// Convert RFC1123 date (DoW, DD Mon YYYY HH:MM:SS TZ) to unix timestamp
bool HttpDateToSeconds(const std::string& date, unsigned long* seconds);
-inline const uint16 HttpDefaultPort(bool secure) {
+inline uint16 HttpDefaultPort(bool secure) {
return secure ? HTTP_SECURE_PORT : HTTP_DEFAULT_PORT;
}
diff --git a/third_party/libjingle/source/talk/base/logging.h b/third_party/libjingle/source/talk/base/logging.h
index ccfd883..ac69b7b 100644
--- a/third_party/libjingle/source/talk/base/logging.h
+++ b/third_party/libjingle/source/talk/base/logging.h
@@ -28,7 +28,7 @@
// LOG(...) an ostream target that can be used to send formatted
// output to a variety of logging targets, such as debugger console, stderr,
// file, or any StreamInterface.
-// The severity level passed as the first argument to the the LOGging
+// The severity level passed as the first argument to the LOGging
// functions is used as a filter, to limit the verbosity of the logging.
// Static members of LogMessage documented below are used to control the
// verbosity and target of the output.
diff --git a/third_party/libjingle/source/talk/base/messagequeue.cc b/third_party/libjingle/source/talk/base/messagequeue.cc
index fc8cd42..8c3a8ce 100644
--- a/third_party/libjingle/source/talk/base/messagequeue.cc
+++ b/third_party/libjingle/source/talk/base/messagequeue.cc
@@ -73,12 +73,25 @@ void MessageQueueManager::Add(MessageQueue *message_queue) {
void MessageQueueManager::Remove(MessageQueue *message_queue) {
ASSERT(!crit_.CurrentThreadIsOwner()); // See note above.
- CritScope cs(&crit_);
- std::vector<MessageQueue *>::iterator iter;
- iter = std::find(message_queues_.begin(), message_queues_.end(),
- message_queue);
- if (iter != message_queues_.end())
- message_queues_.erase(iter);
+ // If this is the last MessageQueue, destroy the manager as well so that
+ // we don't leak this object at program shutdown. As mentioned above, this is
+ // not thread-safe, but this should only happen at program termination (when
+ // the ThreadManager is destroyed, and threads are no longer active).
+ bool destroy = false;
+ {
+ CritScope cs(&crit_);
+ std::vector<MessageQueue *>::iterator iter;
+ iter = std::find(message_queues_.begin(), message_queues_.end(),
+ message_queue);
+ if (iter != message_queues_.end()) {
+ message_queues_.erase(iter);
+ }
+ destroy = message_queues_.empty();
+ }
+ if (destroy) {
+ instance_ = NULL;
+ delete this;
+ }
}
void MessageQueueManager::Clear(MessageHandler *handler) {
diff --git a/third_party/libjingle/source/talk/base/openssladapter.cc b/third_party/libjingle/source/talk/base/openssladapter.cc
index 97a5770..5f0bfae 100644
--- a/third_party/libjingle/source/talk/base/openssladapter.cc
+++ b/third_party/libjingle/source/talk/base/openssladapter.cc
@@ -7,6 +7,7 @@
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
+#include <openssl/opensslv.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
@@ -653,7 +654,11 @@ bool OpenSSLAdapter::VerifyServerName(SSL* ssl, const char* host,
int extension_nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
if (extension_nid == NID_subject_alt_name) {
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ const X509V3_EXT_METHOD* meth = X509V3_EXT_get(extension);
+#else
X509V3_EXT_METHOD* meth = X509V3_EXT_get(extension);
+#endif
if (!meth)
break;
diff --git a/third_party/libjingle/source/talk/base/proxydetect.cc b/third_party/libjingle/source/talk/base/proxydetect.cc
index 5c498f5..79ec3ac 100644
--- a/third_party/libjingle/source/talk/base/proxydetect.cc
+++ b/third_party/libjingle/source/talk/base/proxydetect.cc
@@ -457,16 +457,22 @@ bool GetDefaultFirefoxProfile(Pathname* profile_path) {
if (line.at(0) == '[') {
relative = true;
candidate.clear();
- } else if (line.find("IsRelative=") == 0) {
+ } else if (line.find("IsRelative=") == 0 &&
+ line.length() >= 12) {
+ // TODO(tschmelcher): The initial Linux public launch revealed a fairly
+ // high number of machines where IsRelative= did not have anything after
+ // it. Perhaps that is legal profiles.ini syntax?
relative = (line.at(11) != '0');
- } else if (line.find("Path=") == 0) {
+ } else if (line.find("Path=") == 0 &&
+ line.length() >= 6) {
if (relative) {
candidate = path;
} else {
candidate.clear();
}
candidate.AppendFolder(line.substr(5));
- } else if (line.find("Default=") == 0) {
+ } else if (line.find("Default=") == 0 &&
+ line.length() >= 9) {
if ((line.at(8) != '0') && !candidate.empty()) {
break;
}
diff --git a/third_party/libjingle/source/talk/base/scoped_ptr.h b/third_party/libjingle/source/talk/base/scoped_ptr.h
index 5927990..fd753ec 100644
--- a/third_party/libjingle/source/talk/base/scoped_ptr.h
+++ b/third_party/libjingle/source/talk/base/scoped_ptr.h
@@ -25,9 +25,10 @@
#ifndef TALK_BASE_SCOPED_PTR_H__
#define TALK_BASE_SCOPED_PTR_H__
-#include <cstddef> // for std::ptrdiff_t
-#include <assert.h> // for assert
-#include <stdlib.h> // for free() decl
+#include <cstddef> // for std::ptrdiff_t
+#include <stdlib.h> // for free() decl
+
+#include "talk/base/common.h" // for ASSERT
#ifdef _WIN32
namespace std { using ::ptrdiff_t; };
@@ -67,12 +68,12 @@ class scoped_ptr {
}
T& operator*() const {
- assert(ptr != NULL);
+ ASSERT(ptr != NULL);
return *ptr;
}
T* operator->() const {
- assert(ptr != NULL);
+ ASSERT(ptr != NULL);
return ptr;
}
@@ -149,8 +150,8 @@ class scoped_array {
}
T& operator[](std::ptrdiff_t i) const {
- assert(ptr != NULL);
- assert(i >= 0);
+ ASSERT(ptr != NULL);
+ ASSERT(i >= 0);
return ptr[i];
}
@@ -213,12 +214,12 @@ template<typename T, void (*FF)(void*) = free> class scoped_ptr_malloc {
}
T& operator*() const {
- assert(ptr != 0);
+ ASSERT(ptr != 0);
return *ptr;
}
T* operator->() const {
- assert(ptr != 0);
+ ASSERT(ptr != 0);
return ptr;
}
diff --git a/third_party/libjingle/source/talk/base/signalthread.cc b/third_party/libjingle/source/talk/base/signalthread.cc
index ad7c09e..d6a86c0 100644
--- a/third_party/libjingle/source/talk/base/signalthread.cc
+++ b/third_party/libjingle/source/talk/base/signalthread.cc
@@ -40,17 +40,25 @@ SignalThread::SignalThread() : main_(Thread::Current()), state_(kInit) {
&SignalThread::OnMainThreadDestroyed);
refcount_ = 1;
worker_.parent_ = this;
+ worker_.SetName("SignalThread", this);
}
SignalThread::~SignalThread() {
ASSERT(refcount_ == 0);
}
-void SignalThread::SetPriority(ThreadPriority priority) {
+bool SignalThread::SetName(const std::string& name, const void* obj) {
EnterExit ee(this);
ASSERT(main_->IsCurrent());
ASSERT(kInit == state_);
- worker_.SetPriority(priority);
+ return worker_.SetName(name, obj);
+}
+
+bool SignalThread::SetPriority(ThreadPriority priority) {
+ EnterExit ee(this);
+ ASSERT(main_->IsCurrent());
+ ASSERT(kInit == state_);
+ return worker_.SetPriority(priority);
}
void SignalThread::Start() {
diff --git a/third_party/libjingle/source/talk/base/signalthread.h b/third_party/libjingle/source/talk/base/signalthread.h
index 9ac1899..99a6e69 100644
--- a/third_party/libjingle/source/talk/base/signalthread.h
+++ b/third_party/libjingle/source/talk/base/signalthread.h
@@ -28,6 +28,8 @@
#ifndef TALK_BASE_SIGNALTHREAD_H_
#define TALK_BASE_SIGNALTHREAD_H_
+#include <string>
+
#include "talk/base/thread.h"
#include "talk/base/sigslot.h"
@@ -54,8 +56,11 @@ class SignalThread : public sigslot::has_slots<>, protected MessageHandler {
public:
SignalThread();
+ // Context: Main Thread. Call before Start to change the worker's name.
+ bool SetName(const std::string& name, const void* obj);
+
// Context: Main Thread. Call before Start to change the worker's priority.
- void SetPriority(ThreadPriority priority);
+ bool SetPriority(ThreadPriority priority);
// Context: Main Thread. Call to begin the worker thread.
void Start();
diff --git a/third_party/libjingle/source/talk/base/socketadapters.cc b/third_party/libjingle/source/talk/base/socketadapters.cc
index f9947b5..b82c3fe 100644
--- a/third_party/libjingle/source/talk/base/socketadapters.cc
+++ b/third_party/libjingle/source/talk/base/socketadapters.cc
@@ -563,8 +563,8 @@ void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
if (state_ == SS_HELLO) {
uint8 ver, method;
- if (!response.ReadUInt8(ver) ||
- !response.ReadUInt8(method))
+ if (!response.ReadUInt8(&ver) ||
+ !response.ReadUInt8(&method))
return;
if (ver != 5) {
@@ -582,8 +582,8 @@ void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
}
} else if (state_ == SS_AUTH) {
uint8 ver, status;
- if (!response.ReadUInt8(ver) ||
- !response.ReadUInt8(status))
+ if (!response.ReadUInt8(&ver) ||
+ !response.ReadUInt8(&status))
return;
if ((ver != 1) || (status != 0)) {
@@ -594,10 +594,10 @@ void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
SendConnect();
} else if (state_ == SS_CONNECT) {
uint8 ver, rep, rsv, atyp;
- if (!response.ReadUInt8(ver) ||
- !response.ReadUInt8(rep) ||
- !response.ReadUInt8(rsv) ||
- !response.ReadUInt8(atyp))
+ if (!response.ReadUInt8(&ver) ||
+ !response.ReadUInt8(&rep) ||
+ !response.ReadUInt8(&rsv) ||
+ !response.ReadUInt8(&atyp))
return;
if ((ver != 5) || (rep != 0)) {
@@ -608,22 +608,22 @@ void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
uint16 port;
if (atyp == 1) {
uint32 addr;
- if (!response.ReadUInt32(addr) ||
- !response.ReadUInt16(port))
+ if (!response.ReadUInt32(&addr) ||
+ !response.ReadUInt16(&port))
return;
LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
} else if (atyp == 3) {
uint8 len;
std::string addr;
- if (!response.ReadUInt8(len) ||
- !response.ReadString(addr, len) ||
- !response.ReadUInt16(port))
+ if (!response.ReadUInt8(&len) ||
+ !response.ReadString(&addr, len) ||
+ !response.ReadUInt16(&port))
return;
LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
} else if (atyp == 4) {
std::string addr;
- if (!response.ReadString(addr, 16) ||
- !response.ReadUInt16(port))
+ if (!response.ReadString(&addr, 16) ||
+ !response.ReadUInt16(&port))
return;
LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
} else {
@@ -737,8 +737,8 @@ void AsyncSocksProxyServerSocket::DirectSend(const ByteBuffer& buf) {
void AsyncSocksProxyServerSocket::HandleHello(ByteBuffer* request) {
uint8 ver, num_methods;
- if (!request->ReadUInt8(ver) ||
- !request->ReadUInt8(num_methods)) {
+ if (!request->ReadUInt8(&ver) ||
+ !request->ReadUInt8(&num_methods)) {
Error(0);
return;
}
@@ -750,7 +750,7 @@ void AsyncSocksProxyServerSocket::HandleHello(ByteBuffer* request) {
// Handle either no-auth (0) or user/pass auth (2)
uint8 method = 0xFF;
- if (num_methods > 0 && !request->ReadUInt8(method)) {
+ if (num_methods > 0 && !request->ReadUInt8(&method)) {
Error(0);
return;
}
@@ -776,11 +776,11 @@ void AsyncSocksProxyServerSocket::SendHelloReply(int method) {
void AsyncSocksProxyServerSocket::HandleAuth(ByteBuffer* request) {
uint8 ver, user_len, pass_len;
std::string user, pass;
- if (!request->ReadUInt8(ver) ||
- !request->ReadUInt8(user_len) ||
- !request->ReadString(user, user_len) ||
- !request->ReadUInt8(pass_len) ||
- !request->ReadString(pass, pass_len)) {
+ if (!request->ReadUInt8(&ver) ||
+ !request->ReadUInt8(&user_len) ||
+ !request->ReadString(&user, user_len) ||
+ !request->ReadUInt8(&pass_len) ||
+ !request->ReadString(&pass, pass_len)) {
Error(0);
return;
}
@@ -801,12 +801,12 @@ void AsyncSocksProxyServerSocket::HandleConnect(ByteBuffer* request) {
uint8 ver, command, reserved, addr_type;
uint32 ip;
uint16 port;
- if (!request->ReadUInt8(ver) ||
- !request->ReadUInt8(command) ||
- !request->ReadUInt8(reserved) ||
- !request->ReadUInt8(addr_type) ||
- !request->ReadUInt32(ip) ||
- !request->ReadUInt16(port)) {
+ if (!request->ReadUInt8(&ver) ||
+ !request->ReadUInt8(&command) ||
+ !request->ReadUInt8(&reserved) ||
+ !request->ReadUInt8(&addr_type) ||
+ !request->ReadUInt32(&ip) ||
+ !request->ReadUInt16(&port)) {
Error(0);
return;
}
diff --git a/third_party/libjingle/source/talk/base/socketaddress.cc b/third_party/libjingle/source/talk/base/socketaddress.cc
index 66dd303..cbb0805 100644
--- a/third_party/libjingle/source/talk/base/socketaddress.cc
+++ b/third_party/libjingle/source/talk/base/socketaddress.cc
@@ -215,7 +215,7 @@ bool SocketAddress::ResolveIP(bool force, int* error) {
<< IPToString(ip_);
FreeHostEnt(pHost);
} else {
- LOG_F(LS_ERROR) << "(" << hostname_ << ") error: " << errcode;
+ LOG_F(LS_ERROR) << "(" << hostname_ << ") err: " << errcode;
}
if (error) {
*error = errcode;
@@ -351,7 +351,7 @@ bool SocketAddress::GetLocalIPs(std::vector<uint32>& ips) {
FreeHostEnt(pHost);
return !ips.empty();
}
- LOG(LS_ERROR) << "gethostbyname error: " << errcode;
+ LOG(LS_ERROR) << "gethostbyname err: " << errcode;
return false;
}
diff --git a/third_party/libjingle/source/talk/base/socketstream.h b/third_party/libjingle/source/talk/base/socketstream.h
index f0711cd..591dc4c 100644
--- a/third_party/libjingle/source/talk/base/socketstream.h
+++ b/third_party/libjingle/source/talk/base/socketstream.h
@@ -1,32 +1,32 @@
/*
* libjingle
- * Copyright 2005, Google Inc.
+ * Copyright 2005--2010, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TALK_BASE_SOCKET_STREAM_H__
-#define TALK_BASE_SOCKET_STREAM_H__
+#ifndef TALK_BASE_SOCKETSTREAM_H_
+#define TALK_BASE_SOCKETSTREAM_H_
#include "talk/base/asyncsocket.h"
#include "talk/base/common.h"
@@ -38,105 +38,30 @@ namespace talk_base {
class SocketStream : public StreamInterface, public sigslot::has_slots<> {
public:
- SocketStream(AsyncSocket* socket) : socket_(NULL) {
- Attach(socket);
- }
- virtual ~SocketStream() { delete socket_; }
-
- void Attach(AsyncSocket* socket) {
- if (socket_)
- delete socket_;
- socket_ = socket;
- if (socket_) {
- socket_->SignalConnectEvent.connect(this, &SocketStream::OnConnectEvent);
- socket_->SignalReadEvent.connect(this, &SocketStream::OnReadEvent);
- socket_->SignalWriteEvent.connect(this, &SocketStream::OnWriteEvent);
- socket_->SignalCloseEvent.connect(this, &SocketStream::OnCloseEvent);
- }
- }
-
- AsyncSocket* Detach() {
- AsyncSocket* socket = socket_;
- if (socket_) {
- socket_->SignalConnectEvent.disconnect(this);
- socket_->SignalReadEvent.disconnect(this);
- socket_->SignalWriteEvent.disconnect(this);
- socket_->SignalCloseEvent.disconnect(this);
- socket_ = NULL;
- }
- return socket;
- }
+ explicit SocketStream(AsyncSocket* socket);
+ virtual ~SocketStream();
+
+ void Attach(AsyncSocket* socket);
+ AsyncSocket* Detach();
AsyncSocket* GetSocket() { return socket_; }
- virtual StreamState GetState() const {
- ASSERT(socket_ != NULL);
- switch (socket_->GetState()) {
- case Socket::CS_CONNECTED:
- return SS_OPEN;
- case Socket::CS_CONNECTING:
- return SS_OPENING;
- case Socket::CS_CLOSED:
- default:
- return SS_CLOSED;
- }
- }
+ virtual StreamState GetState() const;
virtual StreamResult Read(void* buffer, size_t buffer_len,
- size_t* read, int* error) {
- ASSERT(socket_ != NULL);
- int result = socket_->Recv(buffer, buffer_len);
- if (result < 0) {
- if (socket_->IsBlocking())
- return SR_BLOCK;
- if (error)
- *error = socket_->GetError();
- return SR_ERROR;
- }
- if ((result > 0) || (buffer_len == 0)) {
- if (read)
- *read = result;
- return SR_SUCCESS;
- }
- return SR_EOS;
- }
+ size_t* read, int* error);
virtual StreamResult Write(const void* data, size_t data_len,
- size_t* written, int* error) {
- ASSERT(socket_ != NULL);
- int result = socket_->Send(data, data_len);
- if (result < 0) {
- if (socket_->IsBlocking())
- return SR_BLOCK;
- if (error)
- *error = socket_->GetError();
- return SR_ERROR;
- }
- if (written)
- *written = result;
- return SR_SUCCESS;
- }
-
- virtual void Close() { ASSERT(socket_ != NULL); socket_->Close(); }
+ size_t* written, int* error);
+
+ virtual void Close();
private:
- void OnConnectEvent(AsyncSocket* socket) {
- ASSERT(socket == socket_);
- SignalEvent(this, SE_OPEN | SE_READ | SE_WRITE, 0);
- }
- void OnReadEvent(AsyncSocket* socket) {
- ASSERT(socket == socket_);
- SignalEvent(this, SE_READ, 0);
- }
- void OnWriteEvent(AsyncSocket* socket) {
- ASSERT(socket == socket_);
- SignalEvent(this, SE_WRITE, 0);
- }
- void OnCloseEvent(AsyncSocket* socket, int err) {
- ASSERT(socket == socket_);
- SignalEvent(this, SE_CLOSE, err);
- }
-
+ void OnConnectEvent(AsyncSocket* socket);
+ void OnReadEvent(AsyncSocket* socket);
+ void OnWriteEvent(AsyncSocket* socket);
+ void OnCloseEvent(AsyncSocket* socket, int err);
+
AsyncSocket* socket_;
DISALLOW_EVIL_CONSTRUCTORS(SocketStream);
@@ -146,4 +71,4 @@ class SocketStream : public StreamInterface, public sigslot::has_slots<> {
} // namespace talk_base
-#endif // TALK_BASE_SOCKET_STREAM_H__
+#endif // TALK_BASE_SOCKETSTREAM_H_
diff --git a/third_party/libjingle/source/talk/base/stream.cc b/third_party/libjingle/source/talk/base/stream.cc
index 16eaf70..45ba7ad 100644
--- a/third_party/libjingle/source/talk/base/stream.cc
+++ b/third_party/libjingle/source/talk/base/stream.cc
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -55,6 +55,9 @@ enum {
MSG_POST_EVENT = 0xF1F1
};
+StreamInterface::~StreamInterface() {
+}
+
struct PostEventData : public MessageData {
int events, error;
PostEventData(int ev, int er) : events(ev), error(er) { }
@@ -120,6 +123,9 @@ void StreamInterface::PostEvent(int events, int err) {
PostEvent(Thread::Current(), events, err);
}
+StreamInterface::StreamInterface() {
+}
+
void StreamInterface::OnMessage(Message* msg) {
if (MSG_POST_EVENT == msg->message_id) {
PostEventData* pe = static_cast<PostEventData*>(msg->pdata);
@@ -129,6 +135,41 @@ void StreamInterface::OnMessage(Message* msg) {
}
///////////////////////////////////////////////////////////////////////////////
+// StreamAdapterInterface
+///////////////////////////////////////////////////////////////////////////////
+
+StreamAdapterInterface::StreamAdapterInterface(StreamInterface* stream,
+ bool owned)
+ : stream_(stream), owned_(owned) {
+ if (NULL != stream_)
+ stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
+}
+
+void StreamAdapterInterface::Attach(StreamInterface* stream, bool owned) {
+ if (NULL != stream_)
+ stream_->SignalEvent.disconnect(this);
+ if (owned_)
+ delete stream_;
+ stream_ = stream;
+ owned_ = owned;
+ if (NULL != stream_)
+ stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
+}
+
+StreamInterface* StreamAdapterInterface::Detach() {
+ if (NULL != stream_)
+ stream_->SignalEvent.disconnect(this);
+ StreamInterface* stream = stream_;
+ stream_ = NULL;
+ return stream;
+}
+
+StreamAdapterInterface::~StreamAdapterInterface() {
+ if (owned_)
+ delete stream_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// StreamTap
///////////////////////////////////////////////////////////////////////////////
@@ -655,6 +696,9 @@ ExternalMemoryStream::ExternalMemoryStream(void* data, size_t length) {
SetData(data, length);
}
+ExternalMemoryStream::~ExternalMemoryStream() {
+}
+
void ExternalMemoryStream::SetData(void* data, size_t length) {
data_length_ = buffer_length_ = length;
buffer_ = static_cast<char*>(data);
@@ -953,6 +997,31 @@ bool StringStream::ReserveSize(size_t size) {
}
///////////////////////////////////////////////////////////////////////////////
+// StreamReference
+///////////////////////////////////////////////////////////////////////////////
+
+StreamReference::StreamReference(StreamInterface* stream)
+ : StreamAdapterInterface(stream, false) {
+ // owner set to false so the destructor does not free the stream.
+ stream_ref_count_ = new StreamRefCount(stream);
+}
+
+StreamInterface* StreamReference::NewReference() {
+ stream_ref_count_->AddReference();
+ return new StreamReference(stream_ref_count_, stream());
+}
+
+StreamReference::~StreamReference() {
+ stream_ref_count_->Release();
+}
+
+StreamReference::StreamReference(StreamRefCount* stream_ref_count,
+ StreamInterface* stream)
+ : StreamAdapterInterface(stream, false),
+ stream_ref_count_(stream_ref_count) {
+}
+
+///////////////////////////////////////////////////////////////////////////////
StreamResult Flow(StreamInterface* source,
char* buffer, size_t buffer_len,
diff --git a/third_party/libjingle/source/talk/base/stream.h b/third_party/libjingle/source/talk/base/stream.h
index 84ebe75..ea91eac 100644
--- a/third_party/libjingle/source/talk/base/stream.h
+++ b/third_party/libjingle/source/talk/base/stream.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2005, Google Inc.
+ * Copyright 2004--2010, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -67,7 +67,7 @@ class Thread;
class StreamInterface : public MessageHandler {
public:
- virtual ~StreamInterface() { }
+ virtual ~StreamInterface();
virtual StreamState GetState() const = 0;
@@ -223,7 +223,7 @@ class StreamInterface : public MessageHandler {
StreamResult ReadLine(std::string *line);
protected:
- StreamInterface() { }
+ StreamInterface();
// MessageHandler Interface
virtual void OnMessage(Message* msg);
@@ -243,11 +243,7 @@ class StreamInterface : public MessageHandler {
class StreamAdapterInterface : public StreamInterface,
public sigslot::has_slots<> {
public:
- explicit StreamAdapterInterface(StreamInterface* stream, bool owned = true)
- : stream_(stream), owned_(owned) {
- if (NULL != stream_)
- stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
- }
+ explicit StreamAdapterInterface(StreamInterface* stream, bool owned = true);
// Core Stream Interface
virtual StreamState GetState() const {
@@ -311,29 +307,12 @@ class StreamAdapterInterface : public StreamInterface,
return stream_->ReserveSize(size);
}
- void Attach(StreamInterface* stream, bool owned = true) {
- if (NULL != stream_)
- stream_->SignalEvent.disconnect(this);
- if (owned_)
- delete stream_;
- stream_ = stream;
- owned_ = owned;
- if (NULL != stream_)
- stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
- }
- StreamInterface* Detach() {
- if (NULL != stream_)
- stream_->SignalEvent.disconnect(this);
- StreamInterface* stream = stream_;
- stream_ = NULL;
- return stream;
- }
+ void Attach(StreamInterface* stream, bool owned = true);
+ StreamInterface* Detach();
protected:
- virtual ~StreamAdapterInterface() {
- if (owned_)
- delete stream_;
- }
+ virtual ~StreamAdapterInterface();
+
// Note that the adapter presents itself as the origin of the stream events,
// since users of the adapter may not recognize the adapted object.
virtual void OnEvent(StreamInterface* stream, int events, int err) {
@@ -543,8 +522,8 @@ class MemoryStreamBase : public StreamInterface {
class MemoryStream : public MemoryStreamBase {
public:
MemoryStream();
- MemoryStream(const char* data); // Calls SetData(data, strlen(data))
- MemoryStream(const void* data, size_t length); // Calls SetData(data, length)
+ explicit MemoryStream(const char* data); // Calls SetData(data, strlen(data))
+ MemoryStream(const void* data, size_t length); // Calls SetData(data, length)
virtual ~MemoryStream();
void SetData(const void* data, size_t length);
@@ -560,6 +539,7 @@ class ExternalMemoryStream : public MemoryStreamBase {
public:
ExternalMemoryStream();
ExternalMemoryStream(void* data, size_t length);
+ virtual ~ExternalMemoryStream();
void SetData(void* data, size_t length);
};
@@ -604,7 +584,7 @@ class FifoBuffer : public StreamInterface {
///////////////////////////////////////////////////////////////////////////////
class LoggingAdapter : public StreamAdapterInterface {
-public:
+ public:
LoggingAdapter(StreamInterface* stream, LoggingSeverity level,
const std::string& label, bool hex_mode = false);
@@ -633,9 +613,9 @@ public:
///////////////////////////////////////////////////////////////////////////////
class StringStream : public StreamInterface {
-public:
- StringStream(std::string& str);
- StringStream(const std::string& str);
+ public:
+ explicit StringStream(std::string& str);
+ explicit StringStream(const std::string& str);
virtual StreamState GetState() const;
virtual StreamResult Read(void* buffer, size_t buffer_len,
@@ -649,7 +629,7 @@ public:
virtual bool GetAvailable(size_t* size) const;
virtual bool ReserveSize(size_t size);
-private:
+ private:
std::string& str_;
size_t read_pos_;
bool read_only_;
@@ -674,19 +654,10 @@ class StreamReference : public StreamAdapterInterface {
// Constructor for the first reference to a stream
// Note: get more references through NewReference(). Use this
// constructor only once on a given stream.
- explicit StreamReference(StreamInterface* stream)
- : StreamAdapterInterface(stream, false) {
- // owner set to false so the destructor does not free the stream.
- stream_ref_count_ = new StreamRefCount(stream);
- }
+ explicit StreamReference(StreamInterface* stream);
StreamInterface* GetStream() { return stream(); }
- StreamInterface* NewReference() {
- stream_ref_count_->AddReference();
- return new StreamReference(stream_ref_count_, stream());
- }
- virtual ~StreamReference() {
- stream_ref_count_->Release();
- }
+ StreamInterface* NewReference();
+ virtual ~StreamReference();
private:
class StreamRefCount {
@@ -718,10 +689,8 @@ class StreamReference : public StreamAdapterInterface {
// Constructor for adding references
explicit StreamReference(StreamRefCount* stream_ref_count,
- StreamInterface* stream)
- : StreamAdapterInterface(stream, false),
- stream_ref_count_(stream_ref_count) {
- }
+ StreamInterface* stream);
+
StreamRefCount* stream_ref_count_;
DISALLOW_EVIL_CONSTRUCTORS(StreamReference);
};
@@ -743,6 +712,6 @@ StreamResult Flow(StreamInterface* source,
///////////////////////////////////////////////////////////////////////////////
-} // namespace talk_base
+} // namespace talk_base
#endif // TALK_BASE_STREAM_H__
diff --git a/third_party/libjingle/source/talk/base/task.cc b/third_party/libjingle/source/talk/base/task.cc
index dfd29f7..ad17438 100644
--- a/third_party/libjingle/source/talk/base/task.cc
+++ b/third_party/libjingle/source/talk/base/task.cc
@@ -48,7 +48,7 @@ Task::Task(TaskParent *parent)
unique_id_ = unique_id_seed_++;
// sanity check that we didn't roll-over our id seed
- assert(unique_id_ < unique_id_seed_);
+ ASSERT(unique_id_ < unique_id_seed_);
}
Task::~Task() {
@@ -89,7 +89,7 @@ void Task::Step() {
// we do not know how !blocked_ happens when done_ - should be impossible.
// But it causes problems, so in retail build, we force blocked_, and
// under debug we assert.
- assert(blocked_);
+ ASSERT(blocked_);
#else
blocked_ = true;
#endif
@@ -107,7 +107,7 @@ void Task::Step() {
Stop();
#ifdef _DEBUG
// verify that stop removed this from its parent
- assert(!parent()->IsChildTask(this));
+ ASSERT(!parent()->IsChildTask(this));
#endif
return;
}
@@ -144,7 +144,7 @@ void Task::Step() {
Stop();
#if _DEBUG
// verify that stop removed this from its parent
- assert(!parent()->IsChildTask(this));
+ ASSERT(!parent()->IsChildTask(this));
#endif
blocked_ = true;
}
@@ -169,7 +169,7 @@ void Task::Abort(bool nowake) {
Stop();
#ifdef _DEBUG
// verify that stop removed this from its parent
- assert(!parent()->IsChildTask(this));
+ ASSERT(!parent()->IsChildTask(this));
#endif
if (!nowake) {
// WakeTasks to self-delete.
diff --git a/third_party/libjingle/source/talk/base/taskparent.cc b/third_party/libjingle/source/talk/base/taskparent.cc
index 0d8f5de..f05ee82 100644
--- a/third_party/libjingle/source/talk/base/taskparent.cc
+++ b/third_party/libjingle/source/talk/base/taskparent.cc
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2006, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -36,17 +36,17 @@ namespace talk_base {
TaskParent::TaskParent(Task* derived_instance, TaskParent *parent)
: parent_(parent) {
- assert(derived_instance);
- assert(parent);
+ ASSERT(derived_instance != NULL);
+ ASSERT(parent != NULL);
runner_ = parent->GetRunner();
parent_->AddChild(derived_instance);
Initialize();
}
-TaskParent::TaskParent(TaskRunner *derived_instance)
+TaskParent::TaskParent(TaskRunner *derived_instance)
: parent_(NULL),
runner_(derived_instance) {
- assert(derived_instance);
+ ASSERT(derived_instance != NULL);
Initialize();
}
@@ -62,7 +62,7 @@ void TaskParent::AddChild(Task *child) {
#ifdef _DEBUG
bool TaskParent::IsChildTask(Task *task) {
- assert(task);
+ ASSERT(task != NULL);
return task->parent_ == this && children_->find(task) != children_->end();
}
#endif
@@ -86,7 +86,7 @@ void TaskParent::AbortAllChildren() {
#ifdef _DEBUG
runner_->IncrementAbortCount();
#endif
-
+
ChildSet copy = *children_;
for (ChildSet::iterator it = copy.begin(); it != copy.end(); ++it) {
(*it)->Abort(true); // Note we do not wake
diff --git a/third_party/libjingle/source/talk/base/thread.cc b/third_party/libjingle/source/talk/base/thread.cc
index c4bebdc..af640a0 100644
--- a/third_party/libjingle/source/talk/base/thread.cc
+++ b/third_party/libjingle/source/talk/base/thread.cc
@@ -25,16 +25,20 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef POSIX
+#include "talk/base/thread.h"
+
+#if defined(WIN32)
+#include <comdef.h>
+#elif defined(POSIX)
#include <time.h>
#endif
#include "talk/base/common.h"
#include "talk/base/logging.h"
-#include "talk/base/thread.h"
+#include "talk/base/stringutils.h"
#include "talk/base/time.h"
-#if defined(OSX_USE_COCOA)
+#ifdef OSX_USE_COCOA
#ifndef OSX
#error OSX_USE_COCOA is defined but not OSX
#endif
@@ -42,8 +46,6 @@
#include "talk/base/scoped_autorelease_pool.h"
#endif
-#define MSDEV_SET_THREAD_NAME 0x406D1388
-
namespace talk_base {
ThreadManager g_thmgr;
@@ -69,11 +71,10 @@ ThreadManager::~ThreadManager() {
UnwrapCurrentThread();
// Unwrap deletes main_thread_ automatically.
pthread_key_delete(key_);
-
}
Thread *ThreadManager::CurrentThread() {
- return (Thread *)pthread_getspecific(key_);
+ return static_cast<Thread *>(pthread_getspecific(key_));
}
void ThreadManager::SetCurrent(Thread *thread) {
@@ -95,7 +96,7 @@ ThreadManager::~ThreadManager() {
}
Thread *ThreadManager::CurrentThread() {
- return (Thread *)TlsGetValue(key_);
+ return static_cast<Thread *>(TlsGetValue(key_));
}
void ThreadManager::SetCurrent(Thread *thread) {
@@ -148,13 +149,14 @@ void ThreadManager::Add(Thread *thread) {
void ThreadManager::Remove(Thread *thread) {
CritScope cs(&crit_);
- threads_.erase(std::remove(threads_.begin(), threads_.end(), thread), threads_.end());
+ threads_.erase(std::remove(threads_.begin(), threads_.end(), thread),
+ threads_.end());
}
void ThreadManager::StopAllThreads_() {
// TODO: In order to properly implement, Threads need to be ref-counted.
CritScope cs(&g_thmgr.crit_);
- for (size_t i=0; i<g_thmgr.threads_.size(); ++i) {
+ for (size_t i = 0; i < g_thmgr.threads_.size(); ++i) {
g_thmgr.threads_[i]->Stop();
}
}
@@ -174,6 +176,7 @@ Thread::Thread(SocketServer* ss)
#endif
owned_(true) {
g_thmgr.Add(this);
+ SetName("Thread", this); // default name
}
Thread::~Thread() {
@@ -202,10 +205,27 @@ bool Thread::SleepMs(int milliseconds) {
#endif
}
+bool Thread::SetName(const std::string& name, const void* obj) {
+ if (started_) return false;
+ name_ = name;
+ if (obj) {
+ char buf[16];
+ sprintfn(buf, sizeof(buf), " 0x%p", obj);
+ name_ += buf;
+ }
+ return true;
+}
+
+bool Thread::SetPriority(ThreadPriority priority) {
+ if (started_) return false;
+ priority_ = priority;
+ return true;
+}
+
bool Thread::Start(Runnable* runnable) {
- assert(owned_);
+ ASSERT(owned_);
if (!owned_) return false;
- assert(!started_);
+ ASSERT(!started_);
if (started_) return false;
ThreadInit* init = new ThreadInit;
@@ -288,40 +308,39 @@ void Thread::Join() {
}
#ifdef WIN32
-typedef struct tagTHREADNAME_INFO
-{
+// As seen on MSDN.
+// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx
+#define MSDEV_SET_THREAD_NAME 0x406D1388
+typedef struct tagTHREADNAME_INFO {
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
} THREADNAME_INFO;
-void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
-{
+void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) {
THREADNAME_INFO info;
- {
- info.dwType = 0x1000;
- info.szName = szThreadName;
- info.dwThreadID = dwThreadID;
- info.dwFlags = 0;
- }
- __try
- {
- RaiseException(MSDEV_SET_THREAD_NAME, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
+ info.dwType = 0x1000;
+ info.szName = szThreadName;
+ info.dwThreadID = dwThreadID;
+ info.dwFlags = 0;
+
+ __try {
+ RaiseException(MSDEV_SET_THREAD_NAME, 0, sizeof(info) / sizeof(DWORD),
+ reinterpret_cast<DWORD*>(&info));
}
- __except(EXCEPTION_CONTINUE_EXECUTION)
- {
+ __except(EXCEPTION_CONTINUE_EXECUTION) {
}
}
-#endif // WIN32
+#endif // WIN32
void* Thread::PreRun(void* pv) {
ThreadInit* init = static_cast<ThreadInit*>(pv);
ThreadManager::SetCurrent(init->thread);
-#if defined(WIN32) && defined(_DEBUG)
- char buf[256];
- _snprintf(buf, sizeof(buf), "Thread 0x%.8x", init->thread);
- SetThreadName(GetCurrentThreadId(), buf);
+#if defined(WIN32)
+ SetThreadName(GetCurrentThreadId(), init->thread->name_.c_str());
+#elif defined(POSIX)
+ // TODO(juberti): See if naming exists for pthreads.
#endif
#ifdef OSX_USE_COCOA
// Make sure the new thread has an autoreleasepool
@@ -492,4 +511,17 @@ AutoThread::~AutoThread() {
}
}
-} // namespace talk_base
+#ifdef WIN32
+void ComThread::Run() {
+ HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ ASSERT(SUCCEEDED(hr));
+ if (SUCCEEDED(hr)) {
+ Thread::Run();
+ CoUninitialize();
+ } else {
+ LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
+ }
+}
+#endif
+
+} // namespace talk_base
diff --git a/third_party/libjingle/source/talk/base/thread.h b/third_party/libjingle/source/talk/base/thread.h
index ff6f15b..36b9e76 100644
--- a/third_party/libjingle/source/talk/base/thread.h
+++ b/third_party/libjingle/source/talk/base/thread.h
@@ -30,6 +30,7 @@
#include <algorithm>
#include <list>
+#include <string>
#include <vector>
#ifdef POSIX
@@ -119,23 +120,29 @@ public:
return ThreadManager::CurrentThread();
}
+ bool IsCurrent() const {
+ return (ThreadManager::CurrentThread() == this);
+ }
+
// Sleeps the calling thread for the specified number of milliseconds, during
// which time no processing is performed. Returns false if sleeping was
// interrupted by a signal (POSIX only).
static bool SleepMs(int millis);
- inline bool IsCurrent() const {
- return (ThreadManager::CurrentThread() == this);
- }
+ // Sets the thread's name, for debugging. Must be called before Start().
+ // If |obj| is non-NULL, its value is appended to |name|.
+ const std::string& name() const { return name_; }
+ bool SetName(const std::string& name, const void* obj);
- void SetPriority(ThreadPriority priority) {
- priority_ = priority;
- }
+ // Sets the thread's priority. Must be called before Start().
+ ThreadPriority priority() const { return priority_; }
+ bool SetPriority(ThreadPriority priority);
+ // Starts the execution of the thread.
bool started() const { return started_; }
-
bool Start(Runnable* runnable = NULL);
+ // Tells the thread to stop and waits until it is joined.
// Never call Stop on the current thread. Instead use the inherited Quit
// function which will exit the base MessageQueue without terminating the
// underlying OS thread.
@@ -183,6 +190,7 @@ private:
void Join();
std::list<_SendMessage> sendlist_;
+ std::string name_;
ThreadPriority priority_;
bool started_;
bool has_sends_;
@@ -210,6 +218,14 @@ public:
virtual ~AutoThread();
};
+// Win32 extension for threads that need to use COM
+#ifdef WIN32
+class ComThread : public Thread {
+ protected:
+ virtual void Run();
+};
+#endif
+
// Provides an easy way to install/uninstall a socketserver on a thread.
class SocketServerScope {
public:
diff --git a/third_party/libjingle/source/talk/base/unixfilesystem.cc b/third_party/libjingle/source/talk/base/unixfilesystem.cc
index dc29a35..842f560 100644
--- a/third_party/libjingle/source/talk/base/unixfilesystem.cc
+++ b/third_party/libjingle/source/talk/base/unixfilesystem.cc
@@ -28,6 +28,7 @@
#include "talk/base/unixfilesystem.h"
#include <errno.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
@@ -130,6 +131,22 @@ FileStream *UnixFilesystem::OpenFile(const Pathname &filename,
return fs;
}
+bool UnixFilesystem::CreatePrivateFile(const Pathname &filename) {
+ int fd = open(filename.pathname().c_str(),
+ O_RDWR | O_CREAT | O_EXCL,
+ S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ LOG_ERR(LS_ERROR) << "open() failed.";
+ return false;
+ }
+ // Don't need to keep the file descriptor.
+ if (close(fd) < 0) {
+ LOG_ERR(LS_ERROR) << "close() failed.";
+ // Continue.
+ }
+ return true;
+}
+
bool UnixFilesystem::DeleteFile(const Pathname &filename) {
LOG(LS_INFO) << "Deleting file:" << filename.pathname();
diff --git a/third_party/libjingle/source/talk/base/unixfilesystem.h b/third_party/libjingle/source/talk/base/unixfilesystem.h
index 1b686be..71960ac 100644
--- a/third_party/libjingle/source/talk/base/unixfilesystem.h
+++ b/third_party/libjingle/source/talk/base/unixfilesystem.h
@@ -38,7 +38,11 @@ class UnixFilesystem : public FilesystemInterface {
// Opens a file. Returns an open StreamInterface if function succeeds. Otherwise,
// returns NULL.
virtual FileStream *OpenFile(const Pathname &filename,
- const std::string &mode);
+ const std::string &mode);
+
+ // Atomically creates an empty file accessible only to the current user if one
+ // does not already exist at the given path, otherwise fails.
+ virtual bool CreatePrivateFile(const Pathname &filename);
// This will attempt to delete the file located at filename.
// It will fail with VERIY if you pass it a non-existant file, or a directory.
@@ -100,6 +104,7 @@ class UnixFilesystem : public FilesystemInterface {
// Returns the absolute path of the current directory.
virtual Pathname GetCurrentDirectory();
+
private:
static std::string app_temp_path_;
};
diff --git a/third_party/libjingle/source/talk/base/win32filesystem.cc b/third_party/libjingle/source/talk/base/win32filesystem.cc
index aeebc86..41e2e9a 100644
--- a/third_party/libjingle/source/talk/base/win32filesystem.cc
+++ b/third_party/libjingle/source/talk/base/win32filesystem.cc
@@ -87,6 +87,114 @@ FileStream *Win32Filesystem::OpenFile(const Pathname &filename,
return fs;
}
+bool Win32Filesystem::CreatePrivateFile(const Pathname &filename) {
+ // To make the file private to the current user, we first must construct a
+ // SECURITY_DESCRIPTOR specifying an ACL. This code is mostly based upon
+ // http://msdn.microsoft.com/en-us/library/ms707085%28VS.85%29.aspx
+
+ // Get the current process token.
+ HANDLE process_token = INVALID_HANDLE_VALUE;
+ if (!::OpenProcessToken(GetCurrentProcess(),
+ TOKEN_QUERY,
+ &process_token)) {
+ LOG_ERR(LS_ERROR) << "OpenProcessToken() failed";
+ return false;
+ }
+
+ // Get the size of its TOKEN_USER structure. Return value is not checked
+ // because we expect it to fail.
+ DWORD token_user_size = 0;
+ (void)::GetTokenInformation(process_token,
+ TokenUser,
+ NULL,
+ 0,
+ &token_user_size);
+
+ // Get the TOKEN_USER structure.
+ scoped_array<char> token_user_bytes(new char[token_user_size]);
+ PTOKEN_USER token_user = reinterpret_cast<PTOKEN_USER>(
+ token_user_bytes.get());
+ memset(token_user, 0, token_user_size);
+ BOOL success = ::GetTokenInformation(process_token,
+ TokenUser,
+ token_user,
+ token_user_size,
+ &token_user_size);
+ // We're now done with this.
+ ::CloseHandle(process_token);
+ if (!success) {
+ LOG_ERR(LS_ERROR) << "GetTokenInformation() failed";
+ return false;
+ }
+
+ if (!IsValidSid(token_user->User.Sid)) {
+ LOG_ERR(LS_ERROR) << "Current process has invalid user SID";
+ return false;
+ }
+
+ // Compute size needed for an ACL that allows access to just this user.
+ int acl_size = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) +
+ GetLengthSid(token_user->User.Sid);
+
+ // Allocate it.
+ scoped_array<char> acl_bytes(new char[acl_size]);
+ PACL acl = reinterpret_cast<PACL>(acl_bytes.get());
+ memset(acl, 0, acl_size);
+ if (!::InitializeAcl(acl, acl_size, ACL_REVISION)) {
+ LOG_ERR(LS_ERROR) << "InitializeAcl() failed";
+ return false;
+ }
+
+ // Allow access to only the current user.
+ if (!::AddAccessAllowedAce(acl,
+ ACL_REVISION,
+ GENERIC_READ | GENERIC_WRITE | STANDARD_RIGHTS_ALL,
+ token_user->User.Sid)) {
+ LOG_ERR(LS_ERROR) << "AddAccessAllowedAce() failed";
+ return false;
+ }
+
+ // Now make the security descriptor.
+ SECURITY_DESCRIPTOR security_descriptor;
+ if (!::InitializeSecurityDescriptor(&security_descriptor,
+ SECURITY_DESCRIPTOR_REVISION)) {
+ LOG_ERR(LS_ERROR) << "InitializeSecurityDescriptor() failed";
+ return false;
+ }
+
+ // Put the ACL in it.
+ if (!::SetSecurityDescriptorDacl(&security_descriptor,
+ TRUE,
+ acl,
+ FALSE)) {
+ LOG_ERR(LS_ERROR) << "SetSecurityDescriptorDacl() failed";
+ return false;
+ }
+
+ // Finally create the file.
+ SECURITY_ATTRIBUTES security_attributes;
+ security_attributes.nLength = sizeof(security_attributes);
+ security_attributes.lpSecurityDescriptor = &security_descriptor;
+ security_attributes.bInheritHandle = FALSE;
+ HANDLE handle = ::CreateFile(
+ ToUtf16(filename.pathname()).c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &security_attributes,
+ CREATE_NEW,
+ 0,
+ NULL);
+ if (INVALID_HANDLE_VALUE == handle) {
+ LOG_ERR(LS_ERROR) << "CreateFile() failed";
+ return false;
+ }
+ if (!::CloseHandle(handle)) {
+ LOG_ERR(LS_ERROR) << "CloseFile() failed";
+ // Continue.
+ }
+ return true;
+}
+
bool Win32Filesystem::DeleteFile(const Pathname &filename) {
LOG(LS_INFO) << "Deleting file " << filename.pathname();
if (!IsFile(filename)) {
diff --git a/third_party/libjingle/source/talk/base/win32filesystem.h b/third_party/libjingle/source/talk/base/win32filesystem.h
index ef1b28f..c17bdd9 100644
--- a/third_party/libjingle/source/talk/base/win32filesystem.h
+++ b/third_party/libjingle/source/talk/base/win32filesystem.h
@@ -37,7 +37,11 @@ class Win32Filesystem : public FilesystemInterface {
// Opens a file. Returns an open StreamInterface if function succeeds. Otherwise,
// returns NULL.
virtual FileStream *OpenFile(const Pathname &filename,
- const std::string &mode);
+ const std::string &mode);
+
+ // Atomically creates an empty file accessible only to the current user if one
+ // does not already exist at the given path, otherwise fails.
+ virtual bool CreatePrivateFile(const Pathname &filename);
// This will attempt to delete the path located at filename.
// If the path points to a folder, it will fail with VERIFY
diff --git a/third_party/libjingle/source/talk/examples/call/callclient.cc b/third_party/libjingle/source/talk/examples/call/callclient.cc
index 5eeb9cb..73ede99 100644
--- a/third_party/libjingle/source/talk/examples/call/callclient.cc
+++ b/third_party/libjingle/source/talk/examples/call/callclient.cc
@@ -130,8 +130,8 @@ void CallClient::ParseLine(const std::string& line) {
state = 1;
}
} else {
- assert(state == 1);
- assert(start >= 0);
+ ASSERT(state == 1);
+ ASSERT(start >= 0);
if (isspace(line[index])) {
std::string word(line, start, index - start);
words.push_back(word);
@@ -163,9 +163,6 @@ void CallClient::ParseLine(const std::string& line) {
call_->Mute(true);
} else if ((words.size() == 1) && (words[0] == "unmute")) {
call_->Mute(false);
- } else if ((words.size() == 2) && (words[0] == "dtmf")) {
- int ev = std::string("0123456789*#").find(words[1][0]);
- call_->PressDTMF(ev);
} else {
console_->Print(CALL_COMMANDS);
}
@@ -584,8 +581,8 @@ void CallClient::RemoveStream(uint32 audio_src_id, uint32 video_src_id) {
}
void CallClient::Accept() {
- assert(call_ && incoming_call_);
- assert(call_->sessions().size() == 1);
+ ASSERT(call_ && incoming_call_);
+ ASSERT(call_->sessions().size() == 1);
call_->AcceptSession(call_->sessions()[0]);
media_client_->SetFocus(call_);
if (call_->video()) {
@@ -598,7 +595,7 @@ void CallClient::Accept() {
}
void CallClient::Reject() {
- assert(call_ && incoming_call_);
+ ASSERT(call_ && incoming_call_);
call_->RejectSession(call_->sessions()[0]);
incoming_call_ = false;
}
diff --git a/third_party/libjingle/source/talk/examples/login/xmppthread.cc b/third_party/libjingle/source/talk/examples/login/xmppthread.cc
index bb5d8cd..c030391 100644
--- a/third_party/libjingle/source/talk/examples/login/xmppthread.cc
+++ b/third_party/libjingle/source/talk/examples/login/xmppthread.cc
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -68,13 +68,13 @@ void XmppThread::OnStateChange(buzz::XmppEngine::State state) {
void XmppThread::OnMessage(talk_base::Message* pmsg) {
if (pmsg->message_id == MSG_LOGIN) {
- assert(pmsg->pdata);
+ ASSERT(pmsg->pdata != NULL);
LoginData* data = reinterpret_cast<LoginData*>(pmsg->pdata);
pump_->DoLogin(data->xcs, new XmppSocket(false), new XmppAuth());
delete data;
} else if (pmsg->message_id == MSG_DISCONNECT) {
pump_->DoDisconnect();
} else {
- assert(false);
+ ASSERT(false);
}
}
diff --git a/third_party/libjingle/source/talk/libjingle.scons b/third_party/libjingle/source/talk/libjingle.scons
index a6e1d62..ea5ed1a 100644
--- a/third_party/libjingle/source/talk/libjingle.scons
+++ b/third_party/libjingle/source/talk/libjingle.scons
@@ -2,37 +2,86 @@ import talk
Import("env")
talk.Library(env, name = "expat",
- srcs = [
- "third_party/expat/v2_0_1/Source/lib/xmlparse.c",
- "third_party/expat/v2_0_1/Source/lib/xmlrole.c",
- "third_party/expat/v2_0_1/Source/lib/xmltok.c",
- "third_party/expat/v2_0_1/Source/lib/xmltok_impl.c",
- "third_party/expat/v2_0_1/Source/lib/xmltok_ns.c",
+ CPPPATH = [
+ "third_party/expat-2.0.1/",
],
CPPDEFINES = [
- "HAVE_BCOPY",
+ "XML_STATIC",
+ ],
+ srcs = [
+ "third_party/expat-2.0.1/lib/xmlparse.c",
+ "third_party/expat-2.0.1/lib/xmlrole.c",
+ "third_party/expat-2.0.1/lib/xmltok.c",
+ ],
+ win_cppdefines = [
+ "COMPILED_FROM_DSP",
+ ],
+ posix_cppdefines = [
+ "HAVE_EXPAT_CONFIG_H",
+ ],
+)
+talk.Library(env, name = "libsrtp",
+ srcs = [
+ "third_party/srtp/crypto/cipher/aes.c",
+ "third_party/srtp/crypto/cipher/aes_cbc.c",
+ "third_party/srtp/crypto/cipher/aes_icm.c",
+ "third_party/srtp/crypto/cipher/cipher.c",
+ "third_party/srtp/crypto/cipher/null_cipher.c",
+ "third_party/srtp/crypto/hash/auth.c",
+ "third_party/srtp/crypto/hash/hmac.c",
+ "third_party/srtp/crypto/hash/null_auth.c",
+ "third_party/srtp/crypto/hash/sha1.c",
+ "third_party/srtp/crypto/replay/rdb.c",
+ "third_party/srtp/crypto/replay/rdbx.c",
+ "third_party/srtp/crypto/replay/ut_sim.c",
+ "third_party/srtp/crypto/math/datatypes.c",
+ "third_party/srtp/crypto/math/stat.c",
+ "third_party/srtp/crypto/kernel/alloc.c",
+ "third_party/srtp/crypto/kernel/crypto_kernel.c",
+ "third_party/srtp/crypto/kernel/err.c",
+ "third_party/srtp/crypto/kernel/key.c",
+ "third_party/srtp/crypto/rng/ctr_prng.c",
+ "third_party/srtp/crypto/rng/rand_source.c",
+ "third_party/srtp/srtp/ekt.c",
+ "third_party/srtp/srtp/srtp.c",
+ ],
+ win_ccflags = [
+ "/wd4701",
+ "/wd4702",
+ ],
+ CPPPATH = [
+ "third_party/srtp/include",
+ "third_party/srtp/crypto/include",
],
)
talk.Library(env, name = "libjingle",
lin_srcs = [
"base/linux.cc",
+ "session/phone/v4llookup.cc",
],
mac_srcs = [
"base/macconversion.cc",
"base/macutils.cc",
+ "session/phone/devicemanager_mac.mm",
],
posix_srcs = [
"base/unixfilesystem.cc",
+ "base/opensslidentity.cc",
+ "base/opensslstreamadapter.cc",
+ "base/sslidentity.cc",
+ "base/sslstreamadapter.cc",
],
CPPDEFINES = [
"FEATURE_ENABLE_VOICEMAIL",
- "FEATURE_ENABLE_SSL",
- "SSL_USE_OPENSSL",
- "HAVE_OPENSSL_SSL_H=1",
+ "EXPAT_RELATIVE_PATH",
+ "SRTP_RELATIVE_PATH",
+ "XML_STATIC",
],
srcs = [
+ "base/asyncfile.cc",
"base/asynchttprequest.cc",
"base/asyncpacketsocket.cc",
+ "base/asyncsocket.cc",
"base/asynctcpsocket.cc",
"base/asyncudpsocket.cc",
"base/autodetectproxy.cc",
@@ -58,8 +107,6 @@ talk.Library(env, name = "libjingle",
"base/nethelpers.cc",
"base/network.cc",
"base/openssladapter.cc",
- "base/opensslidentity.cc",
- "base/opensslstreamadapter.cc",
"base/pathutils.cc",
"base/physicalsocketserver.cc",
"base/proxydetect.cc",
@@ -67,11 +114,11 @@ talk.Library(env, name = "libjingle",
"base/signalthread.cc",
"base/socketadapters.cc",
"base/socketaddress.cc",
+ "base/socketaddresspair.cc",
"base/socketpool.cc",
+ "base/socketstream.cc",
"base/ssladapter.cc",
- "base/sslidentity.cc",
"base/sslsocketfactory.cc",
- "base/sslstreamadapter.cc",
"base/stream.cc",
"base/stringdigest.cc",
"base/stringencode.cc",
@@ -89,14 +136,17 @@ talk.Library(env, name = "libjingle",
"p2p/base/port.cc",
"p2p/base/pseudotcp.cc",
"p2p/base/relayport.cc",
+ "p2p/base/relayserver.cc",
"p2p/base/rawtransport.cc",
"p2p/base/rawtransportchannel.cc",
"p2p/base/session.cc",
+ "p2p/base/sessiondescription.cc",
"p2p/base/sessionmanager.cc",
"p2p/base/sessionmessages.cc",
"p2p/base/stun.cc",
"p2p/base/stunport.cc",
"p2p/base/stunrequest.cc",
+ "p2p/base/stunserver.cc",
"p2p/base/tcpport.cc",
"p2p/base/transport.cc",
"p2p/base/transportchannel.cc",
@@ -119,7 +169,6 @@ talk.Library(env, name = "libjingle",
"session/phone/mediasessionclient.cc",
"session/phone/soundclip.cc",
"session/phone/srtpfilter.cc",
- "session/phone/v4llookup.cc",
"xmllite/qname.cc",
"xmllite/xmlbuilder.cc",
"xmllite/xmlconstants.cc",
@@ -149,6 +198,11 @@ talk.Library(env, name = "libjingle",
"base/winfirewall.cc",
"base/winping.cc",
],
+ CPPPATH = [
+ "third_party/expat-2.0.1/",
+ "third_party/srtp/include",
+ "third_party/srtp/crypto/include",
+ ],
)
talk.App(env, name = "login",
libs = [
@@ -160,6 +214,10 @@ talk.App(env, name = "login",
"examples/login/xmppthread.cc",
"examples/login/login_main.cc",
],
+ mac_libs = [
+ "crypto",
+ "ssl",
+ ],
lin_libs = [
"libpthread",
":libssl.so.0.9.8",
@@ -176,10 +234,34 @@ talk.Library(env, name = "libxmpphelp",
],
)
talk.App(env, name = "call",
- libs = [
- "libjingle",
- "expat",
- "libxmpphelp",
+ mac_FRAMEWORKS = [
+ "AudioToolbox",
+ "AudioUnit",
+ "Cocoa",
+ "CoreAudio",
+ "CoreFoundation",
+ "IOKit",
+ "QTKit",
+ "QuickTime",
+ ],
+ win_libs = [
+ "d3d9.lib",
+ "gdi32.lib",
+ "powrprof.lib",
+ "strmiids.lib",
+ "winmm.lib",
+ ],
+ mac_libs = [
+ "crypto",
+ "ssl",
+ ],
+ CPPDEFINES = [
+ "FEATURE_ENABLE_VOICEMAIL",
+ ],
+ lin_libs = [
+ "libasound",
+ "libpthread",
+ ":libssl.so.0.9.8",
],
srcs = [
"examples/call/call_main.cc",
@@ -193,12 +275,32 @@ talk.App(env, name = "call",
"examples/call/presencepushtask.cc",
"examples/call/voicemailjidrequester.cc",
],
- CPPDEFINES = [
- "FEATURE_ENABLE_VOICEMAIL",
+ libs = [
+ "libjingle",
+ "expat",
+ "libsrtp",
+ "libxmpphelp",
+ ],
+)
+talk.App(env, name = "relayserver",
+ libs = [
+ "libjingle",
+ ],
+ srcs = [
+ "p2p/base/relayserver_main.cc",
+ ],
+ lin_libs = [
+ "libpthread",
+ ],
+)
+talk.App(env, name = "stunserver",
+ libs = [
+ "libjingle",
+ ],
+ srcs = [
+ "p2p/base/stunserver_main.cc",
],
lin_libs = [
- "libasound",
"libpthread",
- ":libssl.so.0.9.8",
],
)
diff --git a/third_party/libjingle/source/talk/main.scons b/third_party/libjingle/source/talk/main.scons
index b14d978..34895c6 100644
--- a/third_party/libjingle/source/talk/main.scons
+++ b/third_party/libjingle/source/talk/main.scons
@@ -62,6 +62,7 @@ root_env = Environment(
'FEATURE_ENABLE_PSTN',
'HAVE_GIPS',
'HAVE_LMI',
+ 'HAVE_SRTP',
]
)
@@ -71,6 +72,7 @@ root_env = Environment(
win_env = root_env.Clone(
tools = [
'atlmfc_vc80',
+ 'code_signing',
'component_targets_msvs',
'directx_9_0_c',
#'grid_builder',
@@ -80,16 +82,18 @@ win_env = root_env.Clone(
# Don't use default vc80 midl.exe. It doesn't understand vista_sdk idl files.
MIDL = '$PLATFORM_SDK_VISTA_6_0_DIR/Bin/midl.exe ',
WIX_DIR = '$GOOGLECLIENT/third_party/wix/v3_0_2925/files',
+ # Flags for debug and optimization are added to CCFLAGS instead
+ CCPDBFLAGS = '',
+ CCFLAGS_DEBUG = '',
+ CCFLAGS_OPTIMIZED = '',
)
win_env.Append(
COMPONENT_LIBRARY_PUBLISH = True, # Put dlls in output dir too
CCFLAGS = [
- '/nologo',
- '/W3', # level 3 warnings
+ '/Fd${TARGET}.pdb', # pdb per object allows --jobs=
'/WX', # warnings are errors
'/Zc:forScope', # handle 'for (int i = 0 ...)' right
- '/GS', # enable stack smash protection
'/EHs-c-', # disable C++ EH
'/GR-', # disable RTTI
'/wd4996', # ignore POSIX deprecated warnings
@@ -154,20 +158,51 @@ win_env.Append(
# of OS_WINDOWS symbol.
win_env.FilterOut(CPPDEFINES = ['OS_WINDOWS=OS_WINDOWS'])
+# Set up digital signing
+DeclareBit('test_signing', 'Sign binaries with the test certificate')
+win_env.SetBitFromOption('test_signing', False)
+if win_env.Bit('test_signing'):
+ win_env.Replace(
+ CERTIFICATE_PATH = win_env.File(
+ '$GOOGLECLIENT/tools/test_key/testkey.pfx').abspath,
+ CERTIFICATE_PASSWORD = 'test',
+ )
+AddTargetGroup('signed_binaries', 'digitally signed binaries can be built')
+
win_dbg_env = win_env.Clone(
BUILD_TYPE = 'dbg',
BUILD_TYPE_DESCRIPTION = 'Windows debug build',
BUILD_GROUPS = ['default', 'all'],
- tools = ['target_debug']
+ tools = ['target_debug'],
+)
+
+win_dbg_env.Prepend(
+ CCFLAGS=[
+ '/ZI', # enable debugging
+ '/Od', # disable optimizations
+ '/MTd', # link with LIBCMTD.LIB debug lib
+ '/RTC1', # enable runtime checks
+ ],
)
+
envs.append(win_dbg_env)
win_opt_env = win_env.Clone(
BUILD_TYPE = 'opt',
BUILD_TYPE_DESCRIPTION = 'Windows opt build',
BUILD_GROUPS = ['all'],
- tools = ['target_optimized']
+ tools = ['target_optimized'],
)
+
+win_opt_env.Prepend(
+ CCFLAGS=[
+ '/Zi', # enable debugging
+ '/O1', # optimize for size
+ '/MT', # link with LIBCMT.LIB (multi-threaded, static linked crt)
+ '/GS', # enable security checks
+ ],
+)
+
envs.append(win_opt_env)
@@ -214,11 +249,10 @@ mac_env.Append(
CPPDEFINES = [
'OSX',
'MAC_OS_X_VERSION_MIN_REQUIRED=1040',
- 'HAVE_SRTP',
],
CCFLAGS = [
'-arch', 'i386',
- '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk',
+ '-isysroot', '/Developer/SDKs/MacOSX10.5.sdk',
'-fasm-blocks',
],
LINKFLAGS = [
@@ -235,6 +269,7 @@ mac_env.Append(
'Carbon',
'Security',
'SystemConfiguration',
+ 'OpenGL',
]
)
@@ -283,7 +318,6 @@ linux_env.Append(
'LINUX',
'HAVE_GLIB',
# TODO() Enable once we figure out multiple defines with gips lib
- #'HAVE_SRTP',
# Also consider other linux flags: 64bit, no-strict-aliasing, wrap, etc
],
LINKFLAGS = [
@@ -326,6 +360,14 @@ linux_chromeos_env = linux_env.Clone(
)
linux_chromeos_env.Append(
+ CPPDEFINES = [
+ 'CHROMEOS',
+ '__MMX__',
+ '__SSE__',
+ '__SSE2__',
+ 'USE_TALK_SOUND',
+ ],
+
CPPPATH = [
os.environ.get("CPPPATH"),
],
@@ -336,6 +378,12 @@ linux_chromeos_env.Append(
CCFLAGS = [
os.environ.get("CCFLAGS"),
+ # ChromeOS devices for sure has MMX, SSE, and SSE2.
+ # So turning on -mmmx, -msse, and -msse2 without CPU detection should be
+ # safe.
+ '-mmmx',
+ '-msse',
+ '-msse2',
],
CXXFLAGS = [
diff --git a/third_party/libjingle/source/talk/p2p/base/candidate.h b/third_party/libjingle/source/talk/p2p/base/candidate.h
index f8b78ff..e347ec5 100644
--- a/third_party/libjingle/source/talk/p2p/base/candidate.h
+++ b/third_party/libjingle/source/talk/p2p/base/candidate.h
@@ -59,7 +59,7 @@ class Candidate {
address_ = address;
}
- const float preference() const { return preference_; }
+ float preference() const { return preference_; }
void set_preference(const float preference) { preference_ = preference; }
const std::string preference_str() const {
std::ostringstream ost;
diff --git a/third_party/libjingle/source/talk/p2p/base/constants.cc b/third_party/libjingle/source/talk/p2p/base/constants.cc
index b1545e7..44ac86f 100644
--- a/third_party/libjingle/source/talk/p2p/base/constants.cc
+++ b/third_party/libjingle/source/talk/p2p/base/constants.cc
@@ -45,6 +45,7 @@ const std::string JINGLE_ACTION_SESSION_INFO("session-info");
const std::string JINGLE_ACTION_SESSION_ACCEPT("session-accept");
const std::string JINGLE_ACTION_SESSION_TERMINATE("session-terminate");
const std::string JINGLE_ACTION_TRANSPORT_INFO("transport-info");
+const std::string JINGLE_ACTION_TRANSPORT_ACCEPT("transport-accept");
const buzz::QName QN_GINGLE_SESSION(true, NS_GINGLE, "session");
const std::string GINGLE_ACTION_INITIATE("initiate");
@@ -54,8 +55,8 @@ const std::string GINGLE_ACTION_REJECT("reject");
const std::string GINGLE_ACTION_TERMINATE("terminate");
const std::string GINGLE_ACTION_CANDIDATES("candidates");
-// SessionApps (aka Gingle <session><description>
-// or Jingle <content><description>)
+// Session Contents (aka Gingle <session><description>
+// or Jingle <content><description>)
const std::string LN_DESCRIPTION("description");
const std::string LN_PAYLOADTYPE("payload-type");
const buzz::QName QN_ID(true, NS_EMPTY, "id");
@@ -76,26 +77,29 @@ const std::string PAYLOADTYPE_PARAMETER_HEIGHT("height");
const std::string PAYLOADTYPE_PARAMETER_WIDTH("width");
const std::string PAYLOADTYPE_PARAMETER_FRAMERATE("framerate");
+const std::string CN_AUDIO("audio");
+const std::string CN_VIDEO("video");
+const std::string CN_OTHER("main");
const std::string NS_JINGLE_AUDIO("urn:xmpp:jingle:apps:rtp:audio");
-const buzz::QName QN_JINGLE_AUDIO_FORMAT(
+const buzz::QName QN_JINGLE_AUDIO_CONTENT(
true, NS_JINGLE_AUDIO, LN_DESCRIPTION);
const buzz::QName QN_JINGLE_AUDIO_PAYLOADTYPE(
true, NS_JINGLE_AUDIO, LN_PAYLOADTYPE);
const std::string NS_JINGLE_VIDEO("urn:xmpp:jingle:apps:rtp:video");
-const buzz::QName QN_JINGLE_VIDEO_FORMAT(
+const buzz::QName QN_JINGLE_VIDEO_CONTENT(
true, NS_JINGLE_VIDEO, LN_DESCRIPTION);
const buzz::QName QN_JINGLE_VIDEO_PAYLOADTYPE(
true, NS_JINGLE_VIDEO, LN_PAYLOADTYPE);
const std::string NS_GINGLE_AUDIO("http://www.google.com/session/phone");
-const buzz::QName QN_GINGLE_AUDIO_FORMAT(
+const buzz::QName QN_GINGLE_AUDIO_CONTENT(
true, NS_GINGLE_AUDIO, LN_DESCRIPTION);
const buzz::QName QN_GINGLE_AUDIO_PAYLOADTYPE(
true, NS_GINGLE_AUDIO, LN_PAYLOADTYPE);
const buzz::QName QN_GINGLE_AUDIO_SRCID(true, NS_GINGLE_AUDIO, "src-id");
const std::string NS_GINGLE_VIDEO("http://www.google.com/session/video");
-const buzz::QName QN_GINGLE_VIDEO_FORMAT(
+const buzz::QName QN_GINGLE_VIDEO_CONTENT(
true, NS_GINGLE_VIDEO, LN_DESCRIPTION);
const buzz::QName QN_GINGLE_VIDEO_PAYLOADTYPE(
true, NS_GINGLE_VIDEO, LN_PAYLOADTYPE);
diff --git a/third_party/libjingle/source/talk/p2p/base/constants.h b/third_party/libjingle/source/talk/p2p/base/constants.h
index b144d1d..edf200e 100644
--- a/third_party/libjingle/source/talk/p2p/base/constants.h
+++ b/third_party/libjingle/source/talk/p2p/base/constants.h
@@ -73,6 +73,7 @@ extern const std::string JINGLE_ACTION_SESSION_INFO;
extern const std::string JINGLE_ACTION_SESSION_ACCEPT;
extern const std::string JINGLE_ACTION_SESSION_TERMINATE;
extern const std::string JINGLE_ACTION_TRANSPORT_INFO;
+extern const std::string JINGLE_ACTION_TRANSPORT_ACCEPT;
extern const buzz::QName QN_GINGLE_SESSION;
extern const std::string GINGLE_ACTION_INITIATE;
@@ -83,10 +84,8 @@ extern const std::string GINGLE_ACTION_TERMINATE;
extern const std::string GINGLE_ACTION_CANDIDATES;
-// SessionFormats (aka Gingle <session><description>
-// or Jingle <content><description>)
-// For now, FormatDescription == SessionDescription
-// Long term, everything will be FormatDescription
+// Session Contents (aka Gingle <session><description>
+// or Jingle <content><description>)
extern const std::string LN_DESCRIPTION;
extern const std::string LN_PAYLOADTYPE;
extern const buzz::QName QN_ID;
@@ -107,19 +106,28 @@ extern const std::string PAYLOADTYPE_PARAMETER_HEIGHT;
extern const std::string PAYLOADTYPE_PARAMETER_WIDTH;
extern const std::string PAYLOADTYPE_PARAMETER_FRAMERATE;
+// CN_ == "content name". When we initiate a session, we choose the
+// name, and when we receive a Gingle session, we provide default
+// names (since Gingle has no content names). But when we receive a
+// Jingle call, the content name can be anything, so don't rely on
+// these values being the same as the ones received.
+extern const std::string CN_AUDIO;
+extern const std::string CN_VIDEO;
+extern const std::string CN_OTHER;
+
extern const std::string NS_JINGLE_AUDIO;
-extern const buzz::QName QN_JINGLE_AUDIO_FORMAT;
+extern const buzz::QName QN_JINGLE_AUDIO_CONTENT;
extern const buzz::QName QN_JINGLE_AUDIO_PAYLOADTYPE;
extern const std::string NS_JINGLE_VIDEO;
-extern const buzz::QName QN_JINGLE_VIDEO_FORMAT;
+extern const buzz::QName QN_JINGLE_VIDEO_CONTENT;
extern const buzz::QName QN_JINGLE_VIDEO_PAYLOADTYPE;
extern const std::string NS_GINGLE_AUDIO;
-extern const buzz::QName QN_GINGLE_AUDIO_FORMAT;
+extern const buzz::QName QN_GINGLE_AUDIO_CONTENT;
extern const buzz::QName QN_GINGLE_AUDIO_PAYLOADTYPE;
extern const buzz::QName QN_GINGLE_AUDIO_SRCID;
extern const std::string NS_GINGLE_VIDEO;
-extern const buzz::QName QN_GINGLE_VIDEO_FORMAT;
+extern const buzz::QName QN_GINGLE_VIDEO_CONTENT;
extern const buzz::QName QN_GINGLE_VIDEO_PAYLOADTYPE;
extern const buzz::QName QN_GINGLE_VIDEO_SRCID;
extern const buzz::QName QN_GINGLE_VIDEO_BANDWIDTH;
diff --git a/third_party/libjingle/source/talk/p2p/base/p2ptransport.cc b/third_party/libjingle/source/talk/p2p/base/p2ptransport.cc
index c47db4d..b360246 100644
--- a/third_party/libjingle/source/talk/p2p/base/p2ptransport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/p2ptransport.cc
@@ -151,22 +151,26 @@ const buzz::QName& GetCandidateQName(SignalingProtocol protocol) {
}
}
-void P2PTransport::WriteCandidates(const Candidates& candidates,
+bool P2PTransport::WriteCandidates(const Candidates& candidates,
SignalingProtocol protocol,
- XmlElements* candidate_elems) {
+ XmlElements* candidate_elems,
+ WriteError* error) {
for (std::vector<Candidate>::const_iterator
iter = candidates.begin();
iter != candidates.end();
++iter) {
buzz::XmlElement* cand_elem =
new buzz::XmlElement(GetCandidateQName(protocol));
- WriteCandidate(*iter, cand_elem);
+ if (!WriteCandidate(*iter, cand_elem, error))
+ return false;
candidate_elems->push_back(cand_elem);
}
+ return true;
}
-void P2PTransport::WriteCandidate(const Candidate& candidate,
- buzz::XmlElement* elem) {
+bool P2PTransport::WriteCandidate(const Candidate& candidate,
+ buzz::XmlElement* elem,
+ WriteError* error) {
elem->SetAttr(buzz::QN_NAME, candidate.name());
elem->SetAttr(QN_ADDRESS, candidate.address().IPAsString());
elem->SetAttr(QN_PORT, candidate.address().PortAsString());
@@ -180,11 +184,12 @@ void P2PTransport::WriteCandidate(const Candidate& candidate,
elem->SetAttr(buzz::QN_TYPE, candidate.type());
if (candidate.network_name().size() > 0)
elem->SetAttr(QN_NETWORK, candidate.network_name());
+ return true;
}
TransportChannelImpl* P2PTransport::CreateTransportChannel(
- const std::string& name, const std::string& session_type) {
- return new P2PTransportChannel(name, session_type, this, port_allocator());
+ const std::string& name, const std::string& content_type) {
+ return new P2PTransportChannel(name, content_type, this, port_allocator());
}
void P2PTransport::DestroyTransportChannel(TransportChannelImpl* channel) {
diff --git a/third_party/libjingle/source/talk/p2p/base/p2ptransport.h b/third_party/libjingle/source/talk/p2p/base/p2ptransport.h
index bd88c48..aaf154d 100644
--- a/third_party/libjingle/source/talk/p2p/base/p2ptransport.h
+++ b/third_party/libjingle/source/talk/p2p/base/p2ptransport.h
@@ -42,24 +42,26 @@ class P2PTransport: public Transport {
virtual bool ParseCandidates(const buzz::XmlElement* elem,
Candidates* candidates,
ParseError* error);
- virtual void WriteCandidates(const Candidates& candidates,
+ virtual bool WriteCandidates(const Candidates& candidates,
SignalingProtocol protocol,
- XmlElements* candidate_elems);
+ XmlElements* candidate_elems,
+ WriteError* error);
virtual void OnTransportError(const buzz::XmlElement* error);
protected:
// Creates and destroys P2PTransportChannel.
virtual TransportChannelImpl* CreateTransportChannel(
- const std::string& name, const std::string& session_type);
+ const std::string& name, const std::string& content_type);
virtual void DestroyTransportChannel(TransportChannelImpl* channel);
private:
bool ParseCandidate(const buzz::XmlElement* elem,
Candidate* candidate,
ParseError* error);
- void WriteCandidate(const Candidate& candidate,
- buzz::XmlElement* elem);
+ bool WriteCandidate(const Candidate& candidate,
+ buzz::XmlElement* elem,
+ WriteError* error);
bool VerifyUsernameFormat(const std::string& username,
ParseError* error);
diff --git a/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc b/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
index 47b1e91..0cd9b71 100644
--- a/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
+++ b/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
@@ -160,10 +160,10 @@ bool ShouldSwitch(cricket::Connection* a_conn, cricket::Connection* b_conn) {
namespace cricket {
P2PTransportChannel::P2PTransportChannel(const std::string &name,
- const std::string &session_type,
+ const std::string &content_type,
P2PTransport* transport,
PortAllocator *allocator) :
- TransportChannelImpl(name, session_type),
+ TransportChannelImpl(name, content_type),
transport_(transport),
allocator_(allocator),
worker_thread_(talk_base::Thread::Current()),
@@ -909,7 +909,7 @@ int P2PTransportChannel::SetOption(talk_base::Socket::Option opt, int value) {
void P2PTransportChannel::OnSignalingReady() {
if (waiting_for_signaling_) {
waiting_for_signaling_ = false;
- AddAllocatorSession(allocator_->CreateSession(name(), session_type()));
+ AddAllocatorSession(allocator_->CreateSession(name(), content_type()));
thread()->PostDelayed(kAllocatePeriod, this, MSG_ALLOCATE);
}
}
diff --git a/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h b/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h
index 9068619..805e159 100644
--- a/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h
+++ b/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h
@@ -68,7 +68,7 @@ class P2PTransportChannel : public TransportChannelImpl,
public talk_base::MessageHandler {
public:
P2PTransportChannel(const std::string &name,
- const std::string &session_type,
+ const std::string &content_type,
P2PTransport* transport,
PortAllocator *allocator);
virtual ~P2PTransportChannel();
diff --git a/third_party/libjingle/source/talk/p2p/base/parsing.cc b/third_party/libjingle/source/talk/p2p/base/parsing.cc
index 3ea2849..1ece5d0 100644
--- a/third_party/libjingle/source/talk/p2p/base/parsing.cc
+++ b/third_party/libjingle/source/talk/p2p/base/parsing.cc
@@ -33,7 +33,16 @@
namespace cricket {
bool BadParse(const std::string& text, ParseError* err) {
- err->text = text;
+ if (err != NULL) {
+ err->text = text;
+ }
+ return false;
+}
+
+bool BadWrite(const std::string& text, WriteError* err) {
+ if (err != NULL) {
+ err->text = text;
+ }
return false;
}
@@ -113,8 +122,8 @@ void AddXmlChildren(buzz::XmlElement* parent,
}
}
-void CopyXmlChildren(buzz::XmlElement* source, buzz::XmlElement* dest) {
- for (buzz::XmlElement* child = source->FirstElement();
+void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest) {
+ for (const buzz::XmlElement* child = source->FirstElement();
child != NULL;
child = child->NextElement()) {
dest->AddElement(new buzz::XmlElement(*child));
diff --git a/third_party/libjingle/source/talk/p2p/base/parsing.h b/third_party/libjingle/source/talk/p2p/base/parsing.h
index 3397eb6..a932d9d 100644
--- a/third_party/libjingle/source/talk/p2p/base/parsing.h
+++ b/third_party/libjingle/source/talk/p2p/base/parsing.h
@@ -38,11 +38,8 @@ namespace cricket {
// We decided "bool Parse(in, out*, error*)" is generally the best
// parse signature. "out Parse(in)" doesn't allow for errors.
// "error* Parse(in, out*)" doesn't allow flexible memory management.
-// If a function can't return an error (common for unparsing), "void
-// Parse(in, out*)" is acceptable.
-// The common error class for parsing and unparsing actions,
-// transports, and payloads.
+// The error type for parsing.
struct ParseError {
public:
// explains the error
@@ -61,8 +58,17 @@ struct ParseError {
}
};
+// The error type for writing.
+struct WriteError {
+ std::string text;
+};
+
+// Convenience method for returning a message when parsing fails.
bool BadParse(const std::string& text, ParseError* err);
+// Convenience method for returning a message when writing fails.
+bool BadWrite(const std::string& text, WriteError* error);
+
// helper XML functions
std::string GetXmlAttr(const buzz::XmlElement* elem,
const buzz::QName& name,
@@ -84,7 +90,7 @@ bool RequireXmlAttr(const buzz::XmlElement* elem,
ParseError* error);
void AddXmlChildren(buzz::XmlElement* parent,
const std::vector<buzz::XmlElement*>& children);
-void CopyXmlChildren(buzz::XmlElement* source, buzz::XmlElement* dest);
+void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest);
std::vector<buzz::XmlElement*> CopyOfXmlChildren(const buzz::XmlElement* elem);
} // namespace cricket
diff --git a/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc b/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
index bcc62f9..c342dbc 100644
--- a/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
+++ b/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -38,7 +38,7 @@
#include "talk/base/stringutils.h"
#include "talk/base/time.h"
-// The following logging is for detailed (packet-level) pseudotcp analysis only.
+// The following logging is for detailed (packet-level) analysis only.
#define _DBG_NONE 0
#define _DBG_NORMAL 1
#define _DBG_VERBOSE 2
@@ -87,8 +87,8 @@ const uint32 JINGLE_HEADER_SIZE = 64; // when relay framing is in use
// Global Constants and Functions
//////////////////////////////////////////////////////////////////////
//
-// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 0 | Conversation Number |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -196,7 +196,7 @@ inline void Incr(Stat s) { ++g_stats[s]; }
void ReportStats() {
char buffer[256];
size_t len = 0;
- for (int i=0; i<S_NUM_STATS; ++i) {
+ for (int i = 0; i < S_NUM_STATS; ++i) {
len += talk_base::sprintfn(buffer, ARRAY_SIZE(buffer), "%s%s:%d",
(i == 0) ? "" : ",", STAT_NAMES[i], g_stats[i]);
g_stats[i] = 0;
@@ -218,7 +218,7 @@ uint32 PseudoTcp::Now() {
#endif
}
-PseudoTcp::PseudoTcp(IPseudoTcpNotify * notify, uint32 conv)
+PseudoTcp::PseudoTcp(IPseudoTcpNotify* notify, uint32 conv)
: m_notify(notify), m_shutdown(SD_NONE), m_error(0) {
// Sanity check on buffer sizes (needed for OnTcpWriteable notification logic)
@@ -261,8 +261,7 @@ PseudoTcp::PseudoTcp(IPseudoTcpNotify * notify, uint32 conv)
PseudoTcp::~PseudoTcp() {
}
-int
-PseudoTcp::Connect() {
+int PseudoTcp::Connect() {
if (m_state != TCP_LISTEN) {
m_error = EINVAL;
return -1;
@@ -279,16 +278,14 @@ PseudoTcp::Connect() {
return 0;
}
-void
-PseudoTcp::NotifyMTU(uint16 mtu) {
+void PseudoTcp::NotifyMTU(uint16 mtu) {
m_mtu_advise = mtu;
if (m_state == TCP_ESTABLISHED) {
adjustMTU();
}
}
-void
-PseudoTcp::NotifyClock(uint32 now) {
+void PseudoTcp::NotifyClock(uint32 now) {
if (m_state == TCP_CLOSED)
return;
@@ -322,9 +319,9 @@ PseudoTcp::NotifyClock(uint32 now) {
m_rto_base = now;
}
}
-
+
// Check if it's time to probe closed windows
- if ((m_snd_wnd == 0)
+ if ((m_snd_wnd == 0)
&& (talk_base::TimeDiff(m_lastsend + m_rx_rto, now) <= 0)) {
if (talk_base::TimeDiff(now, m_lastrecv) >= 15000) {
closedown(ECONNABORTED);
@@ -358,8 +355,7 @@ PseudoTcp::NotifyClock(uint32 now) {
#endif // PSEUDO_KEEPALIVE
}
-bool
-PseudoTcp::NotifyPacket(const char * buffer, size_t len) {
+bool PseudoTcp::NotifyPacket(const char* buffer, size_t len) {
if (len > MAX_PACKET) {
LOG_F(WARNING) << "packet too large";
return false;
@@ -367,17 +363,15 @@ PseudoTcp::NotifyPacket(const char * buffer, size_t len) {
return parse(reinterpret_cast<const uint8 *>(buffer), uint32(len));
}
-bool
-PseudoTcp::GetNextClock(uint32 now, long& timeout) {
+bool PseudoTcp::GetNextClock(uint32 now, long& timeout) {
return clock_check(now, timeout);
}
-//
+//
// IPStream Implementation
//
-int
-PseudoTcp::Recv(char * buffer, size_t len) {
+int PseudoTcp::Recv(char* buffer, size_t len) {
if (m_state != TCP_ESTABLISHED) {
m_error = ENOTCONN;
return SOCKET_ERROR;
@@ -396,7 +390,7 @@ PseudoTcp::Recv(char * buffer, size_t len) {
// !?! until we create a circular buffer, we need to move all of the rest of the buffer up!
memmove(m_rbuf, m_rbuf + read, sizeof(m_rbuf) - read/*m_rlen*/);
- if ((sizeof(m_rbuf) - m_rlen - m_rcv_wnd)
+ if ((sizeof(m_rbuf) - m_rlen - m_rcv_wnd)
>= talk_base::_min<uint32>(sizeof(m_rbuf) / 2, m_mss)) {
bool bWasClosed = (m_rcv_wnd == 0); // !?! Not sure about this was closed business
@@ -410,8 +404,7 @@ PseudoTcp::Recv(char * buffer, size_t len) {
return read;
}
-int
-PseudoTcp::Send(const char * buffer, size_t len) {
+int PseudoTcp::Send(const char* buffer, size_t len) {
if (m_state != TCP_ESTABLISHED) {
m_error = ENOTCONN;
return SOCKET_ERROR;
@@ -428,8 +421,7 @@ PseudoTcp::Send(const char * buffer, size_t len) {
return written;
}
-void
-PseudoTcp::Close(bool force) {
+void PseudoTcp::Close(bool force) {
LOG_F(LS_VERBOSE) << "(" << (force ? "true" : "false") << ")";
m_shutdown = force ? SD_FORCEFUL : SD_GRACEFUL;
}
@@ -442,8 +434,7 @@ int PseudoTcp::GetError() {
// Internal Implementation
//
-uint32
-PseudoTcp::queue(const char * data, uint32 len, bool bCtrl) {
+uint32 PseudoTcp::queue(const char* data, uint32 len, bool bCtrl) {
if (len > sizeof(m_sbuf) - m_slen) {
ASSERT(!bCtrl);
len = sizeof(m_sbuf) - m_slen;
@@ -464,8 +455,8 @@ PseudoTcp::queue(const char * data, uint32 len, bool bCtrl) {
return len;
}
-IPseudoTcpNotify::WriteResult
-PseudoTcp::packet(uint32 seq, uint8 flags, const char * data, uint32 len) {
+IPseudoTcpNotify::WriteResult PseudoTcp::packet(uint32 seq, uint8 flags,
+ const char* data, uint32 len) {
ASSERT(HEADER_SIZE + len <= MAX_PACKET);
uint32 now = Now();
@@ -513,8 +504,7 @@ PseudoTcp::packet(uint32 seq, uint8 flags, const char * data, uint32 len) {
return IPseudoTcpNotify::WR_SUCCESS;
}
-bool
-PseudoTcp::parse(const uint8 * buffer, uint32 size) {
+bool PseudoTcp::parse(const uint8* buffer, uint32 size) {
if (size < 12)
return false;
@@ -524,7 +514,7 @@ PseudoTcp::parse(const uint8 * buffer, uint32 size) {
seg.ack = bytes_to_long(buffer + 8);
seg.flags = buffer[13];
seg.wnd = bytes_to_short(buffer + 14);
-
+
seg.tsval = bytes_to_long(buffer + 16);
seg.tsecr = bytes_to_long(buffer + 20);
@@ -545,8 +535,7 @@ PseudoTcp::parse(const uint8 * buffer, uint32 size) {
return process(seg);
}
-bool
-PseudoTcp::clock_check(uint32 now, long& nTimeout) {
+bool PseudoTcp::clock_check(uint32 now, long& nTimeout) {
if (m_shutdown == SD_FORCEFUL)
return false;
@@ -583,8 +572,7 @@ PseudoTcp::clock_check(uint32 now, long& nTimeout) {
return true;
}
-bool
-PseudoTcp::process(Segment& seg) {
+bool PseudoTcp::process(Segment& seg) {
// If this is the wrong conversation, send a reset!?! (with the correct conversation?)
if (seg.conv != m_conv) {
//if ((seg.flags & FLAG_RST) == 0) {
@@ -698,7 +686,7 @@ PseudoTcp::process(Segment& seg) {
if (m_dup_acks >= 3) {
if (m_snd_una >= m_recover) { // NewReno
uint32 nInFlight = m_snd_nxt - m_snd_una;
- m_cwnd = talk_base::_min(m_ssthresh, nInFlight + m_mss); // (Fast Retransmit)
+ m_cwnd = talk_base::_min(m_ssthresh, nInFlight + m_mss); // (Fast Retransmit)
#if _DEBUGMSG >= _DBG_NORMAL
LOG(LS_INFO) << "exit recovery";
#endif // _DEBUGMSG
@@ -733,7 +721,7 @@ PseudoTcp::process(Segment& seg) {
}
//notify(evOpen);
}
-
+
// If we make room in the send queue, notify the user
// The goal it to make sure we always have at least enough data to fill the
// window. We'd like to notify the app when we are halfway to that point.
@@ -834,7 +822,7 @@ PseudoTcp::process(Segment& seg) {
m_rcv_nxt += seg.len;
m_rcv_wnd -= seg.len;
bNewData = true;
-
+
RList::iterator it = m_rlist.begin();
while ((it != m_rlist.end()) && (it->seq <= m_rcv_nxt)) {
if (it->seq + it->len > m_rcv_nxt) {
@@ -879,8 +867,7 @@ PseudoTcp::process(Segment& seg) {
return true;
}
-bool
-PseudoTcp::transmit(const SList::iterator& seg, uint32 now) {
+bool PseudoTcp::transmit(const SList::iterator& seg, uint32 now) {
if (seg->xmit >= ((m_state == TCP_ESTABLISHED) ? 15 : 30)) {
LOG_F(LS_VERBOSE) << "too many retransmits";
return false;
@@ -891,7 +878,7 @@ PseudoTcp::transmit(const SList::iterator& seg, uint32 now) {
while (true) {
uint32 seq = seg->seq;
uint8 flags = (seg->bCtrl ? FLAG_CTL : 0);
- const char * buffer = m_sbuf + (seg->seq - m_snd_una);
+ const char* buffer = m_sbuf + (seg->seq - m_snd_una);
IPseudoTcpNotify::WriteResult wres = this->packet(seq, flags, buffer, nTransmit);
if (wres == IPseudoTcpNotify::WR_SUCCESS)
@@ -947,8 +934,7 @@ PseudoTcp::transmit(const SList::iterator& seg, uint32 now) {
return true;
}
-void
-PseudoTcp::attemptSend(SendFlags sflags) {
+void PseudoTcp::attemptSend(SendFlags sflags) {
uint32 now = Now();
if (talk_base::TimeDiff(now, m_lastsend) > static_cast<long>(m_rx_rto)) {
@@ -1003,9 +989,9 @@ PseudoTcp::attemptSend(SendFlags sflags) {
} else {
m_t_ack = Now();
}
- return;
+ return;
}
-
+
// Nagle algorithm
if ((m_snd_nxt > m_snd_una) && (nAvailable < m_mss)) {
return;
@@ -1066,4 +1052,4 @@ PseudoTcp::adjustMTU() {
m_cwnd = talk_base::_max(m_cwnd, m_mss);
}
-} // namespace cricket
+} // namespace cricket
diff --git a/third_party/libjingle/source/talk/p2p/base/pseudotcp.h b/third_party/libjingle/source/talk/p2p/base/pseudotcp.h
index 7b0e01f..1446201 100644
--- a/third_party/libjingle/source/talk/p2p/base/pseudotcp.h
+++ b/third_party/libjingle/source/talk/p2p/base/pseudotcp.h
@@ -25,10 +25,11 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __PSEUDOTCP_H__
-#define __PSEUDOTCP_H__
+#ifndef TALK_P2P_BASE_PSEUDOTCP_H_
+#define TALK_P2P_BASE_PSEUDOTCP_H_
#include <list>
+
#include "talk/base/basictypes.h"
namespace cricket {
@@ -40,17 +41,18 @@ namespace cricket {
class PseudoTcp;
class IPseudoTcpNotify {
-public:
+ public:
virtual ~IPseudoTcpNotify() {}
// Notification of tcp events
- virtual void OnTcpOpen(PseudoTcp * tcp) = 0;
- virtual void OnTcpReadable(PseudoTcp * tcp) = 0;
- virtual void OnTcpWriteable(PseudoTcp * tcp) = 0;
- virtual void OnTcpClosed(PseudoTcp * tcp, uint32 nError) = 0;
+ virtual void OnTcpOpen(PseudoTcp* tcp) = 0;
+ virtual void OnTcpReadable(PseudoTcp* tcp) = 0;
+ virtual void OnTcpWriteable(PseudoTcp* tcp) = 0;
+ virtual void OnTcpClosed(PseudoTcp* tcp, uint32 error) = 0;
// Write the packet onto the network
enum WriteResult { WR_SUCCESS, WR_TOO_LARGE, WR_FAIL };
- virtual WriteResult TcpWritePacket(PseudoTcp * tcp, const char * buffer, size_t len) = 0;
+ virtual WriteResult TcpWritePacket(PseudoTcp* tcp,
+ const char* buffer, size_t len) = 0;
};
//////////////////////////////////////////////////////////////////////
@@ -58,19 +60,21 @@ public:
//////////////////////////////////////////////////////////////////////
class PseudoTcp {
-public:
+ public:
static uint32 Now();
- PseudoTcp(IPseudoTcpNotify * notify, uint32 conv);
+ PseudoTcp(IPseudoTcpNotify* notify, uint32 conv);
virtual ~PseudoTcp();
int Connect();
- int Recv(char * buffer, size_t len);
- int Send(const char * buffer, size_t len);
+ int Recv(char* buffer, size_t len);
+ int Send(const char* buffer, size_t len);
void Close(bool force);
int GetError();
- enum TcpState { TCP_LISTEN, TCP_SYN_SENT, TCP_SYN_RECEIVED, TCP_ESTABLISHED, TCP_CLOSED };
+ enum TcpState {
+ TCP_LISTEN, TCP_SYN_SENT, TCP_SYN_RECEIVED, TCP_ESTABLISHED, TCP_CLOSED
+ };
TcpState State() const { return m_state; }
// Call this when the PMTU changes.
@@ -88,7 +92,7 @@ public:
// Returns false if the socket is ready to be destroyed.
bool GetNextClock(uint32 now, long& timeout);
-protected:
+ protected:
enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck };
enum {
// Note: can't go as high as 1024 * 64, because of uint16 precision
@@ -96,7 +100,7 @@ protected:
// Note: send buffer should be larger to make sure we can always fill the
// receiver window
kSndBufSize = 1024 * 90
- };
+ };
struct Segment {
uint32 conv, seq, ack;
@@ -108,12 +112,13 @@ protected:
};
struct SSegment {
+ SSegment(uint32 s, uint32 l, bool c)
+ : seq(s), len(l), /*tstamp(0),*/ xmit(0), bCtrl(c) {
+ }
uint32 seq, len;
//uint32 tstamp;
uint8 xmit;
bool bCtrl;
-
- SSegment(uint32 s, uint32 l, bool c) : seq(s), len(l), /*tstamp(0),*/ xmit(0), bCtrl(c) { }
};
typedef std::list<SSegment> SList;
@@ -121,10 +126,11 @@ protected:
uint32 seq, len;
};
- uint32 queue(const char * data, uint32 len, bool bCtrl);
+ uint32 queue(const char* data, uint32 len, bool bCtrl);
- IPseudoTcpNotify::WriteResult packet(uint32 seq, uint8 flags, const char * data, uint32 len);
- bool parse(const uint8 * buffer, uint32 size);
+ IPseudoTcpNotify::WriteResult packet(uint32 seq, uint8 flags,
+ const char* data, uint32 len);
+ bool parse(const uint8* buffer, uint32 size);
void attemptSend(SendFlags sflags = sfNone);
@@ -137,8 +143,8 @@ protected:
void adjustMTU();
-private:
- IPseudoTcpNotify * m_notify;
+ private:
+ IPseudoTcpNotify* m_notify;
enum Shutdown { SD_NONE, SD_GRACEFUL, SD_FORCEFUL } m_shutdown;
int m_error;
@@ -176,8 +182,6 @@ private:
uint32 m_t_ack;
};
-//////////////////////////////////////////////////////////////////////
-
-} // namespace cricket
+} // namespace cricket
-#endif // __PSEUDOTCP_H__
+#endif // TALK_P2P_BASE_PSEUDOTCP_H_
diff --git a/third_party/libjingle/source/talk/p2p/base/rawtransport.cc b/third_party/libjingle/source/talk/p2p/base/rawtransport.cc
index da7c69e..0bcdd6a 100644
--- a/third_party/libjingle/source/talk/p2p/base/rawtransport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/rawtransport.cc
@@ -70,9 +70,10 @@ bool RawTransport::ParseCandidates(const buzz::XmlElement* elem,
return true;
}
-void RawTransport::WriteCandidates(const Candidates& candidates,
+bool RawTransport::WriteCandidates(const Candidates& candidates,
SignalingProtocol protocol,
- XmlElements* candidate_elems) {
+ XmlElements* candidate_elems,
+ WriteError* error) {
for (std::vector<Candidate>::const_iterator
cand = candidates.begin();
cand != candidates.end();
@@ -86,6 +87,7 @@ void RawTransport::WriteCandidates(const Candidates& candidates,
elem->SetAttr(QN_PORT, addr.PortAsString());
candidate_elems->push_back(elem);
}
+ return true;
}
bool RawTransport::ParseRawAddress(const buzz::XmlElement* elem,
@@ -110,8 +112,8 @@ bool RawTransport::ParseRawAddress(const buzz::XmlElement* elem,
}
TransportChannelImpl* RawTransport::CreateTransportChannel(
- const std::string& name, const std::string& session_type) {
- return new RawTransportChannel(name, session_type, this,
+ const std::string& name, const std::string& content_type) {
+ return new RawTransportChannel(name, content_type, this,
worker_thread(),
port_allocator());
}
diff --git a/third_party/libjingle/source/talk/p2p/base/rawtransport.h b/third_party/libjingle/source/talk/p2p/base/rawtransport.h
index b5a5054..09f715f 100644
--- a/third_party/libjingle/source/talk/p2p/base/rawtransport.h
+++ b/third_party/libjingle/source/talk/p2p/base/rawtransport.h
@@ -45,14 +45,15 @@ class RawTransport: public Transport {
virtual bool ParseCandidates(const buzz::XmlElement* elem,
Candidates* candidates,
ParseError* error);
- virtual void WriteCandidates(const Candidates& candidates,
+ virtual bool WriteCandidates(const Candidates& candidates,
SignalingProtocol protocol,
- XmlElements* candidate_elems);
+ XmlElements* candidate_elems,
+ WriteError* error);
protected:
// Creates and destroys raw channels.
virtual TransportChannelImpl* CreateTransportChannel(
- const std::string& name, const std::string &session_type);
+ const std::string& name, const std::string &content_type);
virtual void DestroyTransportChannel(TransportChannelImpl* channel);
private:
diff --git a/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc b/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc
index b3beffb..39db13c 100644
--- a/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc
+++ b/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.cc
@@ -52,11 +52,11 @@ const uint32 MSG_DESTROY_UNUSED_PORTS = 1;
namespace cricket {
RawTransportChannel::RawTransportChannel(const std::string &name,
- const std::string &session_type,
+ const std::string &content_type,
RawTransport* transport,
talk_base::Thread *worker_thread,
PortAllocator *allocator)
- : TransportChannelImpl(name, session_type),
+ : TransportChannelImpl(name, content_type),
raw_transport_(transport),
allocator_(allocator),
allocator_session_(NULL),
@@ -95,7 +95,7 @@ int RawTransportChannel::GetError() {
void RawTransportChannel::Connect() {
// Create an allocator that only returns stun and relay ports.
- allocator_session_ = allocator_->CreateSession(name(), session_type());
+ allocator_session_ = allocator_->CreateSession(name(), content_type());
uint32 flags = PORTALLOCATOR_DISABLE_UDP | PORTALLOCATOR_DISABLE_TCP;
diff --git a/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h b/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h
index 4f7e483..f99c9c4 100644
--- a/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h
+++ b/third_party/libjingle/source/talk/p2p/base/rawtransportchannel.h
@@ -57,7 +57,7 @@ class RawTransportChannel : public TransportChannelImpl,
public talk_base::MessageHandler {
public:
RawTransportChannel(const std::string &name,
- const std::string &session_type,
+ const std::string &content_type,
RawTransport* transport,
talk_base::Thread *worker_thread,
PortAllocator *allocator);
diff --git a/third_party/libjingle/source/talk/p2p/base/relayport.cc b/third_party/libjingle/source/talk/p2p/base/relayport.cc
index c59967e..eaa5f73 100644
--- a/third_party/libjingle/source/talk/p2p/base/relayport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/relayport.cc
@@ -374,16 +374,6 @@ void RelayPort::OnReadPacket(
}
}
-void RelayPort::DisposeSocket(talk_base::AsyncPacketSocket * socket) {
- // TODO(oja): Socket should be deleted by the RelayConnection destructor.
- thread_->Dispose(socket);
-}
-
-void RelayPort::DisposeConnection(RelayConnection* connection) {
- thread_->Dispose(connection);
- DisposeSocket(connection->socket());
-}
-
RelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
talk_base::AsyncPacketSocket* socket,
talk_base::Thread* thread)
@@ -396,6 +386,7 @@ RelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
RelayConnection::~RelayConnection() {
delete request_manager_;
+ delete socket_;
}
int RelayConnection::SetSocketOption(talk_base::Socket::Option opt,
@@ -456,7 +447,7 @@ void RelayEntry::Connect() {
// Remove any previous connection.
if (current_connection_) {
- port()->DisposeConnection(current_connection_);
+ port()->thread()->Dispose(current_connection_);
current_connection_ = NULL;
}
diff --git a/third_party/libjingle/source/talk/p2p/base/relayport.h b/third_party/libjingle/source/talk/p2p/base/relayport.h
index 09d1cf5..fd0f83d 100644
--- a/third_party/libjingle/source/talk/p2p/base/relayport.h
+++ b/third_party/libjingle/source/talk/p2p/base/relayport.h
@@ -81,10 +81,6 @@ class RelayPort : public Port {
const ProtocolAddress * ServerAddress(size_t index) const;
bool IsReady() { return ready_; }
- // TODO(oja): Move these two methods to RelayEntry.
- void DisposeSocket(talk_base::AsyncPacketSocket * socket);
- void DisposeConnection(RelayConnection* connection);
-
// Used for testing.
sigslot::signal1<const ProtocolAddress*> SignalConnectFailure;
sigslot::signal1<const ProtocolAddress*> SignalSoftTimeout;
diff --git a/third_party/libjingle/source/talk/p2p/base/session.cc b/third_party/libjingle/source/talk/p2p/base/session.cc
index e669336..6dc5a4b 100644
--- a/third_party/libjingle/source/talk/p2p/base/session.cc
+++ b/third_party/libjingle/source/talk/p2p/base/session.cc
@@ -59,13 +59,13 @@ bool BadMessage(const buzz::QName type,
BaseSession::BaseSession(talk_base::Thread *signaling_thread)
: state_(STATE_INIT), error_(ERROR_NONE),
- description_(NULL), remote_description_(NULL),
+ local_description_(NULL), remote_description_(NULL),
signaling_thread_(signaling_thread) {
}
BaseSession::~BaseSession() {
delete remote_description_;
- delete description_;
+ delete local_description_;
}
void BaseSession::SetState(State state) {
@@ -121,7 +121,7 @@ void BaseSession::OnMessage(talk_base::Message *pmsg) {
Session::Session(SessionManager *session_manager, const std::string& name,
- const SessionID& id, const std::string& session_type,
+ const SessionID& id, const std::string& content_type,
SessionClient* client) :
BaseSession(session_manager->signaling_thread()) {
ASSERT(session_manager->signaling_thread()->IsCurrent());
@@ -129,7 +129,7 @@ Session::Session(SessionManager *session_manager, const std::string& name,
session_manager_ = session_manager;
name_ = name;
id_ = id;
- session_type_ = session_type;
+ content_type_ = content_type;
client_ = client;
error_ = ERROR_NONE;
state_ = STATE_INIT;
@@ -158,7 +158,7 @@ Session::~Session() {
}
bool Session::Initiate(const std::string &to,
- const SessionDescription *description) {
+ const SessionDescription* sdesc) {
ASSERT(signaling_thread_->IsCurrent());
// Only from STATE_INIT
@@ -168,9 +168,9 @@ bool Session::Initiate(const std::string &to,
// Setup for signaling.
remote_name_ = to;
initiator_ = true;
- set_local_description(description);
+ set_local_description(sdesc);
- SendInitiateMessage(description);
+ SendInitiateMessage(sdesc);
SetState(Session::STATE_SENTINITIATE);
// We speculatively start attempting connection of the P2P transports.
@@ -178,7 +178,7 @@ bool Session::Initiate(const std::string &to,
return true;
}
-bool Session::Accept(const SessionDescription *description) {
+bool Session::Accept(const SessionDescription* sdesc) {
ASSERT(signaling_thread_->IsCurrent());
// Only if just received initiate
@@ -187,13 +187,13 @@ bool Session::Accept(const SessionDescription *description) {
// Setup for signaling.
initiator_ = false;
- set_local_description(description);
+ set_local_description(sdesc);
// Wait for ChooseTransport to complete
if (!transport_negotiated_)
return true;
- SendAcceptMessage();
+ SendAcceptMessage(sdesc);
SetState(Session::STATE_SENTACCEPT);
return true;
}
@@ -266,7 +266,7 @@ void Session::ConnectDefaultTransportChannels(Transport* transport) {
iter != channels_.end();
++iter) {
ASSERT(!transport->HasChannel(iter->first));
- transport->CreateChannel(iter->first, session_type());
+ transport->CreateChannel(iter->first, content_type());
}
transport->ConnectChannels();
}
@@ -281,7 +281,7 @@ void Session::ConnectTransportChannels(Transport* transport) {
TransportChannelProxy* channel = iter->second;
TransportChannelImpl* impl = transport->GetChannel(channel->name());
if (impl == NULL)
- impl = transport->CreateChannel(channel->name(), session_type());
+ impl = transport->CreateChannel(channel->name(), content_type());
ASSERT(impl != NULL);
channel->SetImplementation(impl);
}
@@ -297,9 +297,9 @@ TransportParserMap Session::GetTransportParsers() {
return parsers;
}
-FormatParserMap Session::GetFormatParsers() {
- FormatParserMap parsers;
- parsers[session_type_] = client_;
+ContentParserMap Session::GetContentParsers() {
+ ContentParserMap parsers;
+ parsers[content_type_] = client_;
return parsers;
}
@@ -307,13 +307,20 @@ TransportChannel* Session::CreateChannel(const std::string& name) {
ASSERT(channels_.find(name) == channels_.end());
ASSERT(!transport_->HasChannel(name));
+ // We always create a proxy in case we need to change out the transport later.
TransportChannelProxy* channel =
- new TransportChannelProxy(name, session_type_);
+ new TransportChannelProxy(name, content_type_);
channels_[name] = channel;
+
+ // If we've already decided on a transport, create the transport channel and
+ // tell the proxy to use it.
if (transport_negotiated_) {
- channel->SetImplementation(transport_->CreateChannel(name, session_type_));
+ channel->SetImplementation(transport_->CreateChannel(name, content_type_));
+ // If we're in the process of initiating the session, the transport will
+ // be trying to connect its channels, so just add a new transport channel.
+ // When we decide on a transport, we'll hook it up to the new proxy.
} else if (state_ == STATE_SENTINITIATE) {
- transport_->CreateChannel(name, session_type());
+ transport_->CreateChannel(name, content_type());
}
return channel;
}
@@ -437,6 +444,9 @@ void Session::OnIncomingMessage(const SessionMessage& msg) {
case ACTION_TRANSPORT_INFO:
valid = OnTransportInfoMessage(msg, &error);
break;
+ case ACTION_TRANSPORT_ACCEPT:
+ valid = OnTransportAcceptMessage(msg, &error);
+ break;
default:
valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
"unknown session message type",
@@ -500,7 +510,7 @@ bool Session::OnInitiateMessage(const SessionMessage& msg,
return false;
SessionInitiate init;
- if (!ParseSessionInitiate(msg.action_elem, GetFormatParsers(), &init, error))
+ if (!ParseSessionInitiate(msg.action_elem, GetContentParsers(), &init, error))
return false;
if (transport_->name() != init.transport_name)
@@ -510,17 +520,17 @@ bool Session::OnInitiateMessage(const SessionMessage& msg,
initiator_ = false;
remote_name_ = msg.from;
- set_remote_description(init.AdoptFormat());
+ set_remote_description(new SessionDescription(init.AdoptContents()));
SetState(STATE_RECEIVEDINITIATE);
- // User of Session may listen to state change and call Reject().
+ // Users of Session may listen to state change and call Reject().
if (state_ != STATE_SENTREJECT && !transport_negotiated_) {
transport_negotiated_ = true;
ConnectTransportChannels(transport_);
// If the user wants to accept, allow that now
- if (description_) {
- Accept(description_);
+ if (local_description_) {
+ Accept(local_description_);
}
}
return true;
@@ -531,11 +541,19 @@ bool Session::OnAcceptMessage(const SessionMessage& msg, SessionError* error) {
return false;
SessionAccept accept;
- if (!ParseSessionAccept(msg.action_elem, GetFormatParsers(), &accept, error))
+ if (!ParseSessionAccept(msg.action_elem, GetContentParsers(), &accept, error))
return false;
- set_remote_description(accept.AdoptFormat());
+ set_remote_description(new SessionDescription(accept.AdoptContents()));
SetState(STATE_RECEIVEDACCEPT);
+
+
+ // Users of Session may listen to state change and call Reject().
+ if (state_ != STATE_SENTREJECT && !transport_negotiated_) {
+ transport_negotiated_ = true;
+ ConnectTransportChannels(transport_);
+ }
+
return true;
}
@@ -563,6 +581,8 @@ bool Session::OnTerminateMessage(const SessionMessage& msg,
if (term.debug_reason != buzz::STR_EMPTY) {
LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
}
+
+ SetState(STATE_RECEIVEDTERMINATE);
return true;
}
@@ -582,6 +602,13 @@ bool Session::OnTransportInfoMessage(const SessionMessage& msg,
return true;
}
+bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
+ SessionError* error) {
+ // TODO(pthatcher): Currently here only for compatibility with
+ // Gingle 1.1 clients (notably, Google Voice).
+ return true;
+}
+
bool Session::CheckState(State state, SessionError* error) {
ASSERT(state_ == state);
if (state_ != state) {
@@ -614,21 +641,26 @@ void Session::OnMessage(talk_base::Message *pmsg) {
}
}
-void Session::SendInitiateMessage(const SessionDescription *description) {
- SessionInitiate init(transport_->name(), session_type_, description);
+void Session::SendInitiateMessage(const SessionDescription* sdesc) {
+ SessionInitiate init(transport_->name(), sdesc->contents());
XmlElements elems;
- WriteSessionInitiate(init, GetFormatParsers(), current_protocol_, &elems);
+ // TODO(pthatcher): Handle write errors.
+ WriteError error;
+ WriteSessionInitiate(init, GetContentParsers(), current_protocol_,
+ &elems, &error);
SendMessage(ACTION_SESSION_INITIATE, elems);
}
-void Session::SendAcceptMessage() {
+void Session::SendAcceptMessage(const SessionDescription* sdesc) {
// TODO(pthatcher): When we support the Jingle standard, we need to
// include at least an empty <transport> in the accept.
std::string transport_name = "";
- SessionAccept accept(transport_name, session_type_, description_);
+ SessionAccept accept(transport_name, sdesc->contents());
XmlElements elems;
- WriteSessionAccept(accept, GetFormatParsers(), &elems);
+ // TODO(pthatcher): Handle write errors.
+ WriteError error;
+ WriteSessionAccept(accept, GetContentParsers(), &elems, &error);
SendMessage(ACTION_SESSION_ACCEPT, elems);
}
@@ -645,7 +677,10 @@ void Session::SendTerminateMessage() {
void Session::SendTransportInfoMessage(const Candidates& candidates) {
TransportInfo info(transport_->name(), candidates);
XmlElements elems;
- WriteTransportInfo(info, GetTransportParsers(), current_protocol_, &elems);
+ // TODO(pthatcher): Handle write errors.
+ WriteError error;
+ WriteTransportInfo(info, GetTransportParsers(), current_protocol_,
+ &elems, &error);
SendMessage(ACTION_TRANSPORT_INFO, elems);
}
diff --git a/third_party/libjingle/source/talk/p2p/base/session.h b/third_party/libjingle/source/talk/p2p/base/session.h
index 4d861cb..181b63b 100644
--- a/third_party/libjingle/source/talk/p2p/base/session.h
+++ b/third_party/libjingle/source/talk/p2p/base/session.h
@@ -36,7 +36,6 @@
#include "talk/p2p/base/sessionmessages.h"
#include "talk/p2p/base/sessionmanager.h"
#include "talk/base/socketaddress.h"
-#include "talk/p2p/base/sessiondescription.h"
#include "talk/p2p/base/sessionclient.h"
#include "talk/p2p/base/sessionid.h"
#include "talk/p2p/base/parsing.h"
@@ -144,33 +143,37 @@ class BaseSession : public sigslot::has_slots<>,
sigslot::signal2<Session*, const std::string&> SignalChannelGone;
// Returns the application-level description given by our client.
- // If we are the recipient, this will be null until we send an accept.
- const SessionDescription *local_description() const { return description_; }
- bool set_local_description(const SessionDescription* description) {
- if (description != description_) {
- delete description_;
- description_ = description;
+ // If we are the recipient, this will be NULL until we send an accept.
+ const SessionDescription* local_description() const {
+ return local_description_;
+ }
+ // Takes ownership of SessionDescription*
+ bool set_local_description(const SessionDescription* sdesc) {
+ if (sdesc != local_description_) {
+ delete local_description_;
+ local_description_ = sdesc;
}
return true;
}
// Returns the application-level description given by the other client.
- // If we are the initiator, this will be null until we receive an accept.
- const SessionDescription *remote_description() const {
+ // If we are the initiator, this will be NULL until we receive an accept.
+ const SessionDescription* remote_description() const {
return remote_description_;
}
- bool set_remote_description(const SessionDescription* description) {
- if (description != remote_description_) {
+ // Takes ownership of SessionDescription*
+ bool set_remote_description(const SessionDescription* sdesc) {
+ if (sdesc != remote_description_) {
delete remote_description_;
- remote_description_ = description;
+ remote_description_ = sdesc;
}
return true;
}
- // When we receive a session initiation from another client, we create a
- // session in the RECEIVEDINITIATE state. We respond by accepting,
- // rejecting, or redirecting the session somewhere else.
- virtual bool Accept(const SessionDescription *description) = 0;
+ // When we receive an initiate, we create a session in the
+ // RECEIVEDINITIATE state and respond by accepting or rejecting.
+ // Takes ownership of session description.
+ virtual bool Accept(const SessionDescription* sdesc) = 0;
virtual bool Reject() = 0;
// At any time, we may terminate an outstanding session.
@@ -185,21 +188,27 @@ class BaseSession : public sigslot::has_slots<>,
// Returns the JID of the other peer in this session.
const std::string &remote_name() const { return remote_name_; }
+ // Set the JID of the other peer in this session.
+ // Typically the remote_name_ is set when the session is initiated.
+ // However, sometimes (e.g when a proxy is used) the peer name is
+ // known after the BaseSession has been initiated and it must be updated
+ // explicitly.
+ void set_remote_name(const std::string& name) { remote_name_ = name; }
+
// Holds the ID of this session, which should be unique across the world.
const SessionID& id() const { return id_; }
protected:
State state_;
Error error_;
- // Descriptions also known as "apps". See comment in
- // constants.h about it.
- const SessionDescription *description_;
- const SessionDescription *remote_description_;
+ const SessionDescription* local_description_;
+ const SessionDescription* remote_description_;
SessionID id_;
// We don't use buzz::Jid because changing to buzz:Jid here has a
// cascading effect that requires an enormous number places to
// change to buzz::Jid as well.
std::string name_;
+
std::string remote_name_;
talk_base::Thread *signaling_thread_;
};
@@ -216,7 +225,7 @@ class Session : public BaseSession {
}
// Returns the XML namespace identifying the type of this session.
- const std::string& session_type() const { return session_type_; }
+ const std::string& content_type() const { return content_type_; }
// Returns the client that is handling the application data of this session.
SessionClient* client() const { return client_; }
@@ -231,16 +240,14 @@ class Session : public BaseSession {
// still in progress.
Transport* transport() const { return transport_; }
- // When a session was created by us, we are the initiator, and we send the
- // initiate message when this method is invoked. The extra_xml parameter is
- // a list of elements that will get inserted inside <Session> ... </Session>
+ // Takes ownership of session description.
bool Initiate(const std::string& to,
- const SessionDescription *description);
+ const SessionDescription* sdesc);
- // When we receive a session initiation from another client, we create a
- // session in the RECEIVEDINITIATE state. We respond by accepting,
- // rejecting, or redirecting the session somewhere else.
- virtual bool Accept(const SessionDescription *description);
+ // When we receive an initiate, we create a session in the
+ // RECEIVEDINITIATE state and respond by accepting or rejecting.
+ // Takes ownership of session description.
+ virtual bool Accept(const SessionDescription* sdesc);
virtual bool Reject();
// At any time, we may terminate an outstanding session.
@@ -254,7 +261,7 @@ class Session : public BaseSession {
// Maps passed to serialization functions.
TransportParserMap GetTransportParsers();
- FormatParserMap GetFormatParsers();
+ ContentParserMap GetContentParsers();
// Creates a new channel with the given name. This method may be called
// immediately after creating the session. However, the actual
@@ -275,9 +282,7 @@ class Session : public BaseSession {
SessionManager *session_manager_;
bool initiator_;
- // TODO(pthatcher): Support multiple session types and call them
- // "format names".
- std::string session_type_;
+ std::string content_type_;
SessionClient* client_;
// TODO(pthatcher): reenable redirect the Jingle way
// std::string redirect_target_;
@@ -298,7 +303,7 @@ class Session : public BaseSession {
Session(SessionManager *session_manager,
const std::string& name,
const SessionID& id,
- const std::string& session_type,
+ const std::string& content_type,
SessionClient* client);
~Session();
@@ -349,8 +354,8 @@ class Session : public BaseSession {
void OnSignalingReady();
// Send various kinds of session messages.
- void SendInitiateMessage(const SessionDescription *description);
- void SendAcceptMessage();
+ void SendInitiateMessage(const SessionDescription* sdesc);
+ void SendAcceptMessage(const SessionDescription* sdesc);
void SendRejectMessage();
void SendTerminateMessage();
void SendTransportInfoMessage(const Candidates& candidates);
@@ -389,6 +394,7 @@ class Session : public BaseSession {
bool OnInfoMessage(const SessionMessage& msg);
bool OnTerminateMessage(const SessionMessage& msg, SessionError* error);
bool OnTransportInfoMessage(const SessionMessage& msg, SessionError* error);
+ bool OnTransportAcceptMessage(const SessionMessage& msg, SessionError* error);
// Verifies that we are in the appropriate state to receive this message.
bool CheckState(State state, SessionError* error);
diff --git a/third_party/libjingle/source/talk/p2p/base/sessionclient.h b/third_party/libjingle/source/talk/p2p/base/sessionclient.h
index c340dce..38e1693 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessionclient.h
+++ b/third_party/libjingle/source/talk/p2p/base/sessionclient.h
@@ -34,39 +34,26 @@ class XmlElement;
namespace cricket {
+struct ParseError;
class Session;
class SessionDescription;
-// TODO(pthatcher): For Jingle migration, we're calling what was
-// previously "SessionDescription" now "FormatDescription", since we can
-// have multiple contents. But for backwards compatibility of the
-// code, we keep the SessionDescription name around. When we're ready
-// to break backwards compatibilty or make a nicer API for
-// SessionClients, we should remove the SessionDescription name
-// entirely.
-typedef SessionDescription FormatDescription;
-
-class FormatParser {
+class ContentParser {
public:
- // TODO(pthatcher): We decided "bool Parse(in, out*, error*)" was
- // generally the best parse signature for parsing. However, in
- // order to keep backwards compatibility with exisisting
- // SessionClients, we are keeping the signatures like "out
- // Parse(in)". Someday when we're willing to break backwards
- // compatibility, we should change this.
- virtual const FormatDescription* ParseFormat(
- const buzz::XmlElement* element) = 0;
- virtual buzz::XmlElement* WriteFormat(
- const FormatDescription* format) = 0;
-
- virtual ~FormatParser() {}
+ virtual bool ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error) = 0;
+ virtual bool WriteContent(const ContentDescription* content,
+ buzz::XmlElement** elem,
+ WriteError* error) = 0;
+ virtual ~ContentParser() {}
};
// A SessionClient exists in 1-1 relation with each session. The implementor
// of this interface is the one that understands *what* the two sides are
// trying to send to one another. The lower-level layers only know how to send
// data; they do not know what is being sent.
-class SessionClient : public FormatParser {
+class SessionClient : public ContentParser {
public:
// Notifies the client of the creation / destruction of sessions of this type.
//
@@ -78,20 +65,12 @@ class SessionClient : public FormatParser {
virtual void OnSessionCreate(Session* session, bool received_initiate) = 0;
virtual void OnSessionDestroy(Session* session) = 0;
- // For backwards compability. Old ones work with Create/Translate.
- // In the future, use Parse/Write
- virtual const SessionDescription* CreateSessionDescription(
- const buzz::XmlElement* element) {return NULL;}
- virtual buzz::XmlElement* TranslateSessionDescription(
- const SessionDescription* description) {return NULL;}
- virtual const FormatDescription* ParseFormat(
- const buzz::XmlElement* element) {
- return CreateSessionDescription(element);
- }
- virtual buzz::XmlElement* WriteFormat(
- const FormatDescription* format) {
- return TranslateSessionDescription(format);
- }
+ virtual bool ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error) = 0;
+ virtual bool WriteContent(const ContentDescription* content,
+ buzz::XmlElement** elem,
+ WriteError* error) = 0;
protected:
// The SessionClient interface explicitly does not include destructor
diff --git a/third_party/libjingle/source/talk/p2p/base/sessiondescription.h b/third_party/libjingle/source/talk/p2p/base/sessiondescription.h
index 2145b17..5fe8ed1 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessiondescription.h
+++ b/third_party/libjingle/source/talk/p2p/base/sessiondescription.h
@@ -28,26 +28,75 @@
#ifndef TALK_P2P_BASE_SESSIONDESCRIPTION_H_
#define TALK_P2P_BASE_SESSIONDESCRIPTION_H_
+#include <string>
+#include <vector>
+
namespace cricket {
-// Describes a session. Individual session types can override this as needed.
+// Describes a session content. Individual content types inherit from
+// this class. Analagous to a <jingle><content><description> or
+// <session><description>.
+class ContentDescription {
+ public:
+ virtual ~ContentDescription() {}
+};
+
+// Analagous to a <jingle><content> or <session><description>.
+// name = name of <content name="...">
+// type = xmlns of <content>
+struct ContentInfo {
+ ContentInfo() : description(NULL) {}
+ ContentInfo(const std::string& name,
+ const std::string& type,
+ const ContentDescription* description) :
+ name(name), type(type), description(description) {}
+ std::string name;
+ std::string type;
+ const ContentDescription* description;
+};
+
+// Describes a collection of contents, each with its own name and
+// type. Analgous to a <jingle> or <session> stanza. Assumes that
+// contents are unique be name, but doesn't enforce that.
class SessionDescription {
public:
- virtual ~SessionDescription() {}
+ SessionDescription() {}
+ explicit SessionDescription(const std::vector<ContentInfo>& contents) :
+ contents_(contents) {}
+ const ContentInfo* GetContentByName(const std::string& name) const;
+ const ContentInfo* FirstContentByType(const std::string& type) const;
+ // Takes ownership of ContentDescription*.
+ void AddContent(const std::string& name,
+ const std::string& type,
+ const ContentDescription* description);
+ // TODO(pthatcher): Implement RemoveContent when it's needed for
+ // content-remove Jingle messages.
+ // void RemoveContent(const std::string& name);
+ const std::vector<ContentInfo>& contents() const { return contents_; }
+
+ ~SessionDescription() {
+ for (std::vector<ContentInfo>::iterator content = contents_.begin();
+ content != contents_.end(); content++) {
+ delete content->description;
+ }
+ }
+
+ private:
+ std::vector<ContentInfo> contents_;
};
-// Indicates whether a SessionDescription was an offer or an answer, as
-// described in http://www.ietf.org/rfc/rfc3264.txt. DT_UPDATE
+// Indicates whether a ContentDescription was an offer or an answer, as
+// described in http://www.ietf.org/rfc/rfc3264.txt. CA_UPDATE
// indicates a jingle update message which contains a subset of a full
// session description
-enum DescriptionType {
- DT_OFFER, DT_ANSWER, DT_UPDATE
+enum ContentAction {
+ CA_OFFER, CA_ANSWER, CA_UPDATE
};
-// Indicates whether a SessionDescription was sent by the local client
+// Indicates whether a ContentDescription was sent by the local client
// or received from the remote client.
-enum DescriptionSource {
- DS_LOCAL, DS_REMOTE
+enum ContentSource {
+ CS_LOCAL, CS_REMOTE
};
} // namespace cricket
diff --git a/third_party/libjingle/source/talk/p2p/base/sessionmanager.cc b/third_party/libjingle/source/talk/p2p/base/sessionmanager.cc
index f7650d3..49aacc3 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessionmanager.cc
+++ b/third_party/libjingle/source/talk/p2p/base/sessionmanager.cc
@@ -57,36 +57,36 @@ SessionManager::~SessionManager() {
// TerminateAll();
}
-void SessionManager::AddClient(const std::string& session_type,
+void SessionManager::AddClient(const std::string& content_type,
SessionClient* client) {
- ASSERT(client_map_.find(session_type) == client_map_.end());
- client_map_[session_type] = client;
+ ASSERT(client_map_.find(content_type) == client_map_.end());
+ client_map_[content_type] = client;
}
-void SessionManager::RemoveClient(const std::string& session_type) {
- ClientMap::iterator iter = client_map_.find(session_type);
+void SessionManager::RemoveClient(const std::string& content_type) {
+ ClientMap::iterator iter = client_map_.find(content_type);
ASSERT(iter != client_map_.end());
client_map_.erase(iter);
}
-SessionClient* SessionManager::GetClient(const std::string& session_type) {
- ClientMap::iterator iter = client_map_.find(session_type);
+SessionClient* SessionManager::GetClient(const std::string& content_type) {
+ ClientMap::iterator iter = client_map_.find(content_type);
return (iter != client_map_.end()) ? iter->second : NULL;
}
Session *SessionManager::CreateSession(const std::string& name,
- const std::string& session_type) {
+ const std::string& content_type) {
return CreateSession(name, SessionID(name, talk_base::CreateRandomId()),
- session_type, false);
+ content_type, false);
}
Session *SessionManager::CreateSession(
const std::string &name, const SessionID& id,
- const std::string& session_type, bool received_initiate) {
- SessionClient* client = GetClient(session_type);
+ const std::string& content_type, bool received_initiate) {
+ SessionClient* client = GetClient(content_type);
ASSERT(client != NULL);
- Session *session = new Session(this, name, id, session_type, client);
+ Session *session = new Session(this, name, id, content_type, client);
session_map_[session->id()] = session;
session->SignalRequestSignaling.connect(
this, &SessionManager::OnRequestSignaling);
@@ -164,14 +164,14 @@ void SessionManager::OnIncomingMessage(const buzz::XmlElement* stanza) {
return;
}
- std::string format_name;
- if (!ParseFormatName(msg.action_elem, &format_name, &error)) {
+ std::string content_type;
+ if (!ParseFirstContentType(msg.action_elem, &content_type, &error)) {
SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
error.text, NULL);
return;
}
- if (!GetClient(format_name)) {
+ if (!GetClient(content_type)) {
SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
"unknown session description type", NULL);
return;
@@ -179,7 +179,7 @@ void SessionManager::OnIncomingMessage(const buzz::XmlElement* stanza) {
session = CreateSession(msg.to,
SessionID(msg.initiator, msg.sid),
- format_name, true);
+ content_type, true);
session->OnIncomingMessage(msg);
}
diff --git a/third_party/libjingle/source/talk/p2p/base/sessionmanager.h b/third_party/libjingle/source/talk/p2p/base/sessionmanager.h
index 4f273cd..9eebc4d 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessionmanager.h
+++ b/third_party/libjingle/source/talk/p2p/base/sessionmanager.h
@@ -67,14 +67,14 @@ class SessionManager : public sigslot::has_slots<> {
// describing a session of the given type, we will automatically create a
// Session object and notify this client. The client may then accept or
// reject the session.
- void AddClient(const std::string& session_type, SessionClient* client);
- void RemoveClient(const std::string& session_type);
- SessionClient* GetClient(const std::string& session_type);
+ void AddClient(const std::string& content_type, SessionClient* client);
+ void RemoveClient(const std::string& content_type);
+ SessionClient* GetClient(const std::string& content_type);
// Creates a new session. The given name is the JID of the client on whose
// behalf we initiate the session.
Session *CreateSession(const std::string& name,
- const std::string& session_type);
+ const std::string& content_type);
// Destroys the given session.
void DestroySession(Session *session);
@@ -140,7 +140,7 @@ class SessionManager : public sigslot::has_slots<> {
// a message attempting to initiate a session with this client.
Session *CreateSession(const std::string& name,
const SessionID& id,
- const std::string& session_type,
+ const std::string& content_type,
bool received_initiate);
// Attempts to find a registered session type whose description appears as
diff --git a/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc b/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc
index de41be2..c340629 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc
+++ b/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc
@@ -25,8 +25,9 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "talk/base/logging.h"
#include "talk/p2p/base/sessionmessages.h"
+
+#include "talk/base/logging.h"
#include "talk/xmpp/constants.h"
#include "talk/p2p/base/constants.h"
#include "talk/p2p/base/p2ptransport.h"
@@ -51,6 +52,8 @@ ActionType ToActionType(const std::string& type) {
return ACTION_TRANSPORT_INFO;
if (type == JINGLE_ACTION_TRANSPORT_INFO)
return ACTION_TRANSPORT_INFO;
+ if (type == JINGLE_ACTION_TRANSPORT_ACCEPT)
+ return ACTION_TRANSPORT_ACCEPT;
return ACTION_UNKNOWN;
}
@@ -199,105 +202,198 @@ buzz::XmlElement* NewTransportElement(const std::string& name) {
return new buzz::XmlElement(buzz::QName(true, name, LN_TRANSPORT), true);
}
-void WriteGingleTransport(const std::string& trans_name,
+bool WriteGingleTransport(const std::string& trans_name,
const Candidates& candidates,
const TransportParserMap& trans_parsers,
SignalingProtocol protocol,
- XmlElements* elems) {
+ XmlElements* elems,
+ WriteError* error) {
TransportParser* trans_parser = GetTransportParser(trans_parsers, trans_name);
if (trans_parser == NULL)
- // TODO(pthatcher): should we handle errors from writes?
- // return BadParse("unknown transport type: " + trans_name, error);
- return;
+ return BadWrite("unknown transport type: " + trans_name, error);
if (protocol == PROTOCOL_GINGLE2) {
buzz::XmlElement* trans_elem = NewTransportElement(trans_name);
XmlElements cand_elems;
- trans_parser->WriteCandidates(candidates, protocol, &cand_elems);
+ if (!trans_parser->WriteCandidates(candidates, protocol,
+ &cand_elems, error))
+ return false;
AddXmlChildren(trans_elem, cand_elems);
elems->push_back(trans_elem);
} else {
- trans_parser->WriteCandidates(candidates, protocol, elems);
+ if (!trans_parser->WriteCandidates(candidates, protocol, elems, error))
+ return false;
}
+ return true;
}
-void WriteGingleTransportWithoutCandidates(const std::string& trans_name,
+bool WriteGingleTransportWithoutCandidates(const std::string& trans_name,
SignalingProtocol protocol,
- XmlElements* elems) {
+ XmlElements* elems,
+ WriteError* error) {
if (protocol == PROTOCOL_GINGLE2) {
elems->push_back(NewTransportElement(trans_name));
}
+ return true;
}
-FormatParser* GetFormatParser(const FormatParserMap& format_parsers,
- const std::string& name) {
- FormatParserMap::const_iterator map = format_parsers.find(name);
- if (map == format_parsers.end()) {
+ContentParser* FindContentParser(const ContentParserMap& content_parsers,
+ const std::string& type) {
+ ContentParserMap::const_iterator map = content_parsers.find(type);
+ if (map == content_parsers.end()) {
return NULL;
} else {
return map->second;
}
}
-// Pass in a NULL format to disable format parsing (so you only get the name).
-bool ParseFormat(const buzz::XmlElement* format_elem,
- const FormatParserMap& format_parsers,
- std::string* format_name,
- const FormatDescription** format,
- ParseError* error) {
- *format_name = format_elem->Name().Namespace();
- if (format != NULL) {
- FormatParser* format_parser = GetFormatParser(format_parsers, *format_name);
- if (format_parser == NULL)
- return BadParse("unknown application format: " + *format_name, error);
- *format = format_parser->ParseFormat(format_elem);
+// Like FindContentParser, but does trickery for NS_GINGLE_AUDIO and
+// NS_GINGLE_VIDEO. Because clients still assume only one content
+// type, but we split up the types, we need to be able to let either
+// content type work as the other.
+ContentParser* GetContentParser(const ContentParserMap& content_parsers,
+ const std::string& type) {
+ ContentParser* parser = FindContentParser(content_parsers, type);
+ if (parser == NULL) {
+ if (type == NS_GINGLE_AUDIO) {
+ return FindContentParser(content_parsers, NS_GINGLE_VIDEO);
+ } else if (type == NS_GINGLE_VIDEO) {
+ return FindContentParser(content_parsers, NS_GINGLE_AUDIO);
+ }
}
+
+ return parser;
+}
+
+bool ParseContent(const std::string& name,
+ const std::string& type,
+ const buzz::XmlElement* elem,
+ const ContentParserMap& parsers,
+ std::vector<ContentInfo>* contents,
+ ParseError* error) {
+ ContentParser* parser = GetContentParser(parsers, type);
+ if (parser == NULL)
+ return BadParse("unknown application content: " + type, error);
+
+ const ContentDescription* desc;
+ if (!parser->ParseContent(elem, &desc, error))
+ return false;
+
+ contents->push_back(ContentInfo(name, type, desc));
return true;
}
-bool ParseGingleFormat(const buzz::XmlElement* action_elem,
- const FormatParserMap& format_parsers,
- std::string* format_name,
- const FormatDescription** format,
- ParseError* error) {
- const buzz::XmlElement* format_elem;
- if (!RequireXmlChild(action_elem, LN_DESCRIPTION, &format_elem, error))
+bool ParseGingleContentType(const buzz::XmlElement* action_elem,
+ std::string* content_type,
+ const buzz::XmlElement** content_elem,
+ ParseError* error) {
+ if (!RequireXmlChild(action_elem, LN_DESCRIPTION, content_elem, error))
return false;
- return ParseFormat(format_elem, format_parsers,
- format_name, format, error);
+ *content_type = (*content_elem)->Name().Namespace();
+ return true;
}
-void WriteFormat(const std::string& format_name,
- const FormatDescription* format,
- const FormatParserMap& format_parsers,
- XmlElements* elems) {
- FormatParser* format_parser =
- GetFormatParser(format_parsers, format_name);
- if (format_parser == NULL)
- // TODO(pthatcher): should we handle errors from writes?
- // return error->Set("unknown application format: " + init.format_name);
- return;
-
- elems->push_back(format_parser->WriteFormat(format));
+bool ParseGingleContents(const buzz::XmlElement* action_elem,
+ const ContentParserMap& content_parsers,
+ std::vector<ContentInfo>* contents,
+ ParseError* error) {
+ std::string content_type;
+ const buzz::XmlElement* content_elem;
+ if (!ParseGingleContentType(action_elem, &content_type, &content_elem, error))
+ return false;
+
+ if (content_type == NS_GINGLE_VIDEO) {
+ // A parser parsing audio or video content should look at the
+ // namespace and only parse the codecs relevant to that namespace.
+ // We use this to control which codecs get parsed: first video,
+ // then audio.
+ if (!ParseContent(CN_VIDEO, NS_GINGLE_VIDEO,
+ content_elem, content_parsers,
+ contents, error))
+ return false;
+
+ talk_base::scoped_ptr<buzz::XmlElement> audio_elem(
+ new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT));
+ CopyXmlChildren(content_elem, audio_elem.get());
+ if (!ParseContent(CN_AUDIO, NS_GINGLE_AUDIO,
+ audio_elem.get(), content_parsers,
+ contents, error))
+ return false;
+ } else {
+ if (!ParseContent(CN_OTHER, content_type,
+ content_elem, content_parsers,
+ contents, error))
+ return false;
+ }
+ return true;
}
-bool ParseFormatName(const buzz::XmlElement* action_elem,
- std::string* format_name,
- ParseError* error) {
- return ParseGingleFormat(action_elem, FormatParserMap(),
- format_name, NULL, error);
+buzz::XmlElement* WriteContent(const ContentInfo& content,
+ const ContentParserMap& parsers,
+ WriteError* error) {
+ ContentParser* parser = GetContentParser(parsers, content.type);
+ if (parser == NULL) {
+ BadWrite("unknown content type: " + content.type, error);
+ return NULL;
+ }
+
+ buzz::XmlElement* elem = NULL;
+ if (!parser->WriteContent(content.description, &elem, error))
+ return NULL;
+
+ return elem;
+}
+
+bool WriteGingleContents(const std::vector<ContentInfo>& contents,
+ const ContentParserMap& parsers,
+ XmlElements* elems,
+ WriteError* error) {
+ if (contents.size() == 1) {
+ buzz::XmlElement* elem = WriteContent(contents.front(), parsers, error);
+ if (!elem)
+ return false;
+
+ elems->push_back(elem);
+ } else if (contents.size() == 2 &&
+ contents.at(0).type == NS_GINGLE_AUDIO &&
+ contents.at(1).type == NS_GINGLE_VIDEO) {
+ // Special-case audio + video contents so that they are "merged"
+ // into one "video" content.
+ buzz::XmlElement* audio = WriteContent(contents.at(0), parsers, error);
+ if (!audio)
+ return false;
+
+ buzz::XmlElement* video = WriteContent(contents.at(1), parsers, error);
+ if (!video) {
+ delete audio;
+ return false;
+ }
+
+ CopyXmlChildren(audio, video);
+ elems->push_back(video);
+ delete audio;
+ } else {
+ return BadWrite("Gingle protocol may only have one content.", error);
+ }
+
+ return true;
+}
+
+bool ParseFirstContentType(const buzz::XmlElement* action_elem,
+ std::string* content_type,
+ ParseError* error) {
+ const buzz::XmlElement* content_elem;
+ return ParseGingleContentType(
+ action_elem, content_type, &content_elem, error);
}
bool ParseSessionInitiate(const buzz::XmlElement* action_elem,
- const FormatParserMap& format_parsers,
+ const ContentParserMap& content_parsers,
SessionInitiate* init, ParseError* error) {
- std::string format_name;
- const FormatDescription* format;
- if (!ParseGingleFormat(action_elem, format_parsers,
- &format_name, &format, error))
+ if (!ParseGingleContents(action_elem, content_parsers,
+ &init->contents, error))
return false;
- init->SetFormat(format_name, format);
if (!ParseGingleTransportName(action_elem, &(init->transport_name), error))
return false;
@@ -305,35 +401,39 @@ bool ParseSessionInitiate(const buzz::XmlElement* action_elem,
return true;
}
-void WriteSessionInitiate(const SessionInitiate& init,
- const FormatParserMap& format_parsers,
+bool WriteSessionInitiate(const SessionInitiate& init,
+ const ContentParserMap& content_parsers,
SignalingProtocol protocol,
- XmlElements* elems) {
- WriteFormat(init.format_name, init.format, format_parsers, elems);
+ XmlElements* elems,
+ WriteError* error) {
+ if (!WriteGingleContents(init.contents, content_parsers, elems, error))
+ return false;
+
// We don't have any candidates yet, so only send the transport
// name. Send candidates asynchronously later with transport-info
// or candidates messages.
- WriteGingleTransportWithoutCandidates(init.transport_name, protocol, elems);
+ if (!WriteGingleTransportWithoutCandidates(
+ init.transport_name, protocol, elems, error))
+ return false;
+
+ return true;
}
bool ParseSessionAccept(const buzz::XmlElement* action_elem,
- const FormatParserMap& format_parsers,
+ const ContentParserMap& content_parsers,
SessionAccept* accept, ParseError* error) {
- std::string format_name;
- const FormatDescription* format;
- if (!ParseGingleFormat(action_elem, format_parsers,
- &format_name, &format, error))
+ if (!ParseGingleContents(action_elem, content_parsers,
+ &accept->contents, error))
return false;
- accept->SetFormat(format_name, format);
return true;
}
-void WriteSessionAccept(const SessionAccept& accept,
- const FormatParserMap& format_parsers,
- XmlElements* elems) {
- WriteFormat(accept.format_name, accept.format, format_parsers,
- elems);
+bool WriteSessionAccept(const SessionAccept& accept,
+ const ContentParserMap& content_parsers,
+ XmlElements* elems,
+ WriteError* error) {
+ return WriteGingleContents(accept.contents, content_parsers, elems, error);
}
bool ParseSessionTerminate(const buzz::XmlElement* action_elem,
@@ -349,10 +449,12 @@ bool ParseSessionTerminate(const buzz::XmlElement* action_elem,
return true;
}
-void WriteSessionTerminate(const SessionTerminate& term,
- XmlElements* elems) {
+bool WriteSessionTerminate(const SessionTerminate& term,
+ XmlElements* elems,
+ WriteError* error) {
elems->push_back(new buzz::XmlElement(
buzz::QName(true, NS_EMPTY, term.reason)));
+ return true;
}
bool ParseTransportInfo(const buzz::XmlElement* action_elem,
@@ -363,12 +465,14 @@ bool ParseTransportInfo(const buzz::XmlElement* action_elem,
error);
}
-void WriteTransportInfo(const TransportInfo& info,
+bool WriteTransportInfo(const TransportInfo& info,
const TransportParserMap& trans_parsers,
SignalingProtocol protocol,
- XmlElements* elems) {
- WriteGingleTransport(info.transport_name, info.candidates, trans_parsers,
- protocol, elems);
+ XmlElements* elems,
+ WriteError* error) {
+ return WriteGingleTransport(info.transport_name, info.candidates,
+ trans_parsers, protocol,
+ elems, error);
}
diff --git a/third_party/libjingle/source/talk/p2p/base/sessionmessages.h b/third_party/libjingle/source/talk/p2p/base/sessionmessages.h
index 7895805..7ecf0b3 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessionmessages.h
+++ b/third_party/libjingle/source/talk/p2p/base/sessionmessages.h
@@ -34,23 +34,19 @@
#include "talk/xmllite/xmlelement.h"
#include "talk/p2p/base/constants.h"
-// Needed to delete SessionInitiate.format.
-#include "talk/p2p/base/sessiondescription.h"
+#include "talk/p2p/base/sessiondescription.h" // Needed to delete contents.
namespace cricket {
struct ParseError;
+struct WriteError;
class Candidate;
-class FormatParser;
+class ContentParser;
class TransportParser;
-// see comment in constants.h about FormatDescription and
-// SessionDescription being the same. SessionDescription is the old
-// word. FormatDescription is the new word.
-typedef SessionDescription FormatDescription;
typedef std::vector<buzz::XmlElement*> XmlElements;
typedef std::vector<Candidate> Candidates;
-typedef std::map<std::string, FormatParser*> FormatParserMap;
+typedef std::map<std::string, ContentParser*> ContentParserMap;
typedef std::map<std::string, TransportParser*> TransportParserMap;
enum ActionType {
@@ -95,53 +91,37 @@ struct SessionMessage {
const buzz::XmlElement* stanza;
};
-// These are different "action"s found in <jingle> or <session> The
-// Jingle specs allows actions to have multiple "contents", where each
-// content is a pair of format+transport. our Sessions can only
-// handle one such content. It will be a long time before we can
-// support multiple contents in the session. So, our actions only
-// supports one.
-
-// TODO(pthatcher): switch to jingle-style contents (Session has
-// multiple Contents, which each are a pairs of (format, transport)
-
struct SessionInitiate {
- SessionInitiate() : format(NULL), owns_format(false) {}
+ // Object will have ownership of contents.
+ SessionInitiate() : owns_contents(true) {}
+ // Caller retains ownership of contents.
SessionInitiate(const std::string& transport_name,
- const std::string& format_name,
- const FormatDescription* format) :
+ const std::vector<ContentInfo>& contents) :
transport_name(transport_name),
- format_name(format_name), format(format), owns_format(false) {}
+ contents(contents), owns_contents(false) {}
~SessionInitiate() {
- if (owns_format) {
- delete format;
+ if (owns_contents) {
+ for (std::vector<ContentInfo>::iterator content = contents.begin();
+ content != contents.end(); content++) {
+ delete content->description;
+ }
}
}
- // Object takes ownership of format.
- void SetFormat(const std::string& format_name,
- const FormatDescription* format) {
- this->format_name = format_name;
- this->format = format;
- this->owns_format = true;
- }
-
- // Caller takes ownership of format.
- const FormatDescription* AdoptFormat() {
- const FormatDescription* out = format;
- format = NULL;
- owns_format = false;
+ // Caller takes ownership of contents.
+ std::vector<ContentInfo> AdoptContents() {
+ std::vector<ContentInfo> out;
+ contents.swap(out);
return out;
}
std::string transport_name; // xmlns of <transport>
// TODO(pthatcher): Jingle spec allows candidates to be in the
// initiate. We should support receiving them.
- std::string format_name; // xmlns of <description>
- const FormatDescription* format;
- bool owns_format;
+ std::vector<ContentInfo> contents;
+ bool owns_contents;
};
typedef SessionInitiate SessionAccept;
@@ -169,36 +149,40 @@ bool IsSessionMessage(const buzz::XmlElement* stanza);
bool ParseSessionMessage(const buzz::XmlElement* stanza,
SessionMessage* msg,
ParseError* error);
-bool ParseFormatName(const buzz::XmlElement* action_elem,
- std::string* format_name,
- ParseError* error);
+bool ParseFirstContentType(const buzz::XmlElement* action_elem,
+ std::string* content_type,
+ ParseError* error);
void WriteSessionMessage(const SessionMessage& msg,
const XmlElements& action_elems,
buzz::XmlElement* stanza);
bool ParseSessionInitiate(const buzz::XmlElement* action_elem,
- const FormatParserMap& format_parsers,
+ const ContentParserMap& content_parsers,
SessionInitiate* init, ParseError* error);
-void WriteSessionInitiate(const SessionInitiate& init,
- const FormatParserMap& format_parsers,
+bool WriteSessionInitiate(const SessionInitiate& init,
+ const ContentParserMap& content_parsers,
SignalingProtocol protocol,
- XmlElements* elems);
+ XmlElements* elems,
+ WriteError* error);
bool ParseSessionAccept(const buzz::XmlElement* action_elem,
- const FormatParserMap& format_parsers,
+ const ContentParserMap& content_parsers,
SessionAccept* accept, ParseError* error);
-void WriteSessionAccept(const SessionAccept& accept,
- const FormatParserMap& format_parsers,
- XmlElements* elems);
+bool WriteSessionAccept(const SessionAccept& accept,
+ const ContentParserMap& content_parsers,
+ XmlElements* elems,
+ WriteError* error);
bool ParseSessionTerminate(const buzz::XmlElement* action_elem,
SessionTerminate* term, ParseError* error);
-void WriteSessionTerminate(const SessionAccept& term,
- XmlElements* elems);
+bool WriteSessionTerminate(const SessionAccept& term,
+ XmlElements* elems,
+ WriteError* error);
bool ParseTransportInfo(const buzz::XmlElement* action_elem,
const TransportParserMap& trans_parsers,
TransportInfo* info, ParseError* error);
-void WriteTransportInfo(const TransportInfo& info,
+bool WriteTransportInfo(const TransportInfo& info,
const TransportParserMap& trans_parsers,
SignalingProtocol protocol,
- XmlElements* elems);
+ XmlElements* elems,
+ WriteError* error);
} // namespace cricket
#endif // TALK_P2P_BASE_SESSIONMESSAGES_H_
diff --git a/third_party/libjingle/source/talk/p2p/base/stun.cc b/third_party/libjingle/source/talk/p2p/base/stun.cc
index c62f70e..ad8b5ce 100644
--- a/third_party/libjingle/source/talk/p2p/base/stun.cc
+++ b/third_party/libjingle/source/talk/p2p/base/stun.cc
@@ -142,7 +142,7 @@ const StunAttribute* StunMessage::GetAttribute(StunAttributeType type) const {
}
bool StunMessage::Read(ByteBuffer* buf) {
- if (!buf->ReadUInt16(type_))
+ if (!buf->ReadUInt16(&type_))
return false;
if (type_ & 0x8000) {
@@ -151,11 +151,11 @@ bool StunMessage::Read(ByteBuffer* buf) {
return false;
}
- if (!buf->ReadUInt16(length_))
+ if (!buf->ReadUInt16(&length_))
return false;
std::string transaction_id;
- if (!buf->ReadString(transaction_id, 16))
+ if (!buf->ReadString(&transaction_id, 16))
return false;
ASSERT(transaction_id.size() == 16);
transaction_id_ = transaction_id;
@@ -168,9 +168,9 @@ bool StunMessage::Read(ByteBuffer* buf) {
size_t rest = buf->Length() - length_;
while (buf->Length() > rest) {
uint16 attr_type, attr_length;
- if (!buf->ReadUInt16(attr_type))
+ if (!buf->ReadUInt16(&attr_type))
return false;
- if (!buf->ReadUInt16(attr_length))
+ if (!buf->ReadUInt16(&attr_length))
return false;
StunAttribute* attr = StunAttribute::Create(attr_type, attr_length);
@@ -325,13 +325,13 @@ StunAddressAttribute::StunAddressAttribute(uint16 type)
bool StunAddressAttribute::Read(ByteBuffer* buf) {
uint8 dummy;
- if (!buf->ReadUInt8(dummy))
+ if (!buf->ReadUInt8(&dummy))
return false;
- if (!buf->ReadUInt8(family_))
+ if (!buf->ReadUInt8(&family_))
return false;
- if (!buf->ReadUInt16(port_))
+ if (!buf->ReadUInt16(&port_))
return false;
- if (!buf->ReadUInt32(ip_))
+ if (!buf->ReadUInt32(&ip_))
return false;
return true;
}
@@ -359,7 +359,7 @@ void StunUInt32Attribute::SetBit(int index, bool value) {
}
bool StunUInt32Attribute::Read(ByteBuffer* buf) {
- if (!buf->ReadUInt32(bits_))
+ if (!buf->ReadUInt32(&bits_))
return false;
return true;
}
@@ -434,7 +434,7 @@ void StunErrorCodeAttribute::SetReason(const std::string& reason) {
bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
uint32 val;
- if (!buf->ReadUInt32(val))
+ if (!buf->ReadUInt32(&val))
return false;
if ((val >> 11) != 0)
@@ -442,7 +442,7 @@ bool StunErrorCodeAttribute::Read(ByteBuffer* buf) {
SetErrorCode(val);
- if (!buf->ReadString(reason_, length() - 4))
+ if (!buf->ReadString(&reason_, length() - 4))
return false;
return true;
@@ -482,7 +482,7 @@ void StunUInt16ListAttribute::AddType(uint16 value) {
bool StunUInt16ListAttribute::Read(ByteBuffer* buf) {
for (int i = 0; i < length() / 2; i++) {
uint16 attr;
- if (!buf->ReadUInt16(attr))
+ if (!buf->ReadUInt16(&attr))
return false;
attr_types_->push_back(attr);
}
@@ -518,7 +518,7 @@ void StunTransportPrefsAttribute::SetPreallocateAddress(
bool StunTransportPrefsAttribute::Read(ByteBuffer* buf) {
uint32 val;
- if (!buf->ReadUInt32(val))
+ if (!buf->ReadUInt32(&val))
return false;
if ((val >> 3) != 0)
diff --git a/third_party/libjingle/source/talk/p2p/base/stunrequest.cc b/third_party/libjingle/source/talk/p2p/base/stunrequest.cc
index b93408d..1ad121e 100644
--- a/third_party/libjingle/source/talk/p2p/base/stunrequest.cc
+++ b/third_party/libjingle/source/talk/p2p/base/stunrequest.cc
@@ -155,7 +155,7 @@ void StunRequest::Construct() {
}
}
-const StunMessageType StunRequest::type() {
+StunMessageType StunRequest::type() {
ASSERT(msg_ != NULL);
return msg_->type();
}
diff --git a/third_party/libjingle/source/talk/p2p/base/stunrequest.h b/third_party/libjingle/source/talk/p2p/base/stunrequest.h
index 93fd044..fea2c99 100644
--- a/third_party/libjingle/source/talk/p2p/base/stunrequest.h
+++ b/third_party/libjingle/source/talk/p2p/base/stunrequest.h
@@ -91,7 +91,7 @@ public:
const std::string& id() { return id_; }
// Returns the STUN type of the request message.
- const StunMessageType type();
+ StunMessageType type();
// Handles messages for sending and timeout.
void OnMessage(talk_base::Message* pmsg);
diff --git a/third_party/libjingle/source/talk/p2p/base/transport.cc b/third_party/libjingle/source/talk/p2p/base/transport.cc
index 6be6d6e..b42269e 100644
--- a/third_party/libjingle/source/talk/p2p/base/transport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/transport.cc
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -43,8 +43,8 @@ struct ChannelParams {
explicit ChannelParams(const std::string& name)
: name(name), channel(NULL), candidate(NULL) {}
ChannelParams(const std::string& name,
- const std::string& session_type)
- : name(name), session_type(session_type),
+ const std::string& content_type)
+ : name(name), content_type(content_type),
channel(NULL), candidate(NULL) {}
explicit ChannelParams(cricket::Candidate* candidate) :
channel(NULL), candidate(candidate) {
@@ -56,7 +56,7 @@ struct ChannelParams {
}
std::string name;
- std::string session_type;
+ std::string content_type;
cricket::TransportChannelImpl* channel;
cricket::Candidate* candidate;
};
@@ -91,18 +91,18 @@ Transport::~Transport() {
}
TransportChannelImpl* Transport::CreateChannel(
- const std::string& name, const std::string& session_type) {
- ChannelParams params(name, session_type);
+ const std::string& name, const std::string& content_type) {
+ ChannelParams params(name, content_type);
ChannelMessage msg(&params);
worker_thread()->Send(this, MSG_CREATECHANNEL, &msg);
return msg.data()->channel;
}
TransportChannelImpl* Transport::CreateChannel_w(
- const std::string& name, const std::string& session_type) {
+ const std::string& name, const std::string& content_type) {
ASSERT(worker_thread()->IsCurrent());
- TransportChannelImpl* impl = CreateTransportChannel(name, session_type);
+ TransportChannelImpl* impl = CreateTransportChannel(name, content_type);
impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
impl->SignalRequestSignaling.connect(
@@ -356,7 +356,7 @@ void Transport::OnMessage(talk_base::Message* msg) {
case MSG_CREATECHANNEL:
{
ChannelParams* params = static_cast<ChannelMessage*>(msg->pdata)->data();
- params->channel = CreateChannel_w(params->name, params->session_type);
+ params->channel = CreateChannel_w(params->name, params->content_type);
}
break;
case MSG_DESTROYCHANNEL:
@@ -379,9 +379,11 @@ void Transport::OnMessage(talk_base::Message* msg) {
break;
case MSG_ONREMOTECANDIDATE:
{
- ChannelParams* params = static_cast<ChannelMessage*>(msg->pdata)->data();
+ ChannelMessage* channel_msg = static_cast<ChannelMessage*>(msg->pdata);
+ ChannelParams* params = channel_msg->data();
OnRemoteCandidate_w(*(params->candidate));
delete params;
+ delete channel_msg;
}
break;
case MSG_CONNECTING:
diff --git a/third_party/libjingle/source/talk/p2p/base/transport.h b/third_party/libjingle/source/talk/p2p/base/transport.h
index afe84d6..09068f7 100644
--- a/third_party/libjingle/source/talk/p2p/base/transport.h
+++ b/third_party/libjingle/source/talk/p2p/base/transport.h
@@ -67,6 +67,7 @@ class XmlElement;
namespace cricket {
struct ParseError;
+struct WriteError;
class PortAllocator;
class SessionManager;
class Session;
@@ -82,14 +83,13 @@ typedef std::vector<Candidate> Candidates;
// Create/Translate.
class TransportParser {
public:
- // see comment in parsing.h about parsing and unparsing function
- // signatures
virtual bool ParseCandidates(const buzz::XmlElement* elem,
Candidates* candidates,
ParseError* error) = 0;
- virtual void WriteCandidates(const Candidates& candidates,
+ virtual bool WriteCandidates(const Candidates& candidates,
SignalingProtocol protocol,
- XmlElements* candidate_elems) = 0;
+ XmlElements* candidate_elems,
+ WriteError* error) = 0;
virtual ~TransportParser() {}
};
@@ -124,7 +124,7 @@ class Transport : public talk_base::MessageHandler, public sigslot::has_slots<>,
// Create, destroy, and lookup the channels of this type by their names.
TransportChannelImpl* CreateChannel(const std::string& name,
- const std::string& session_type);
+ const std::string& content_type);
// Note: GetChannel may lead to race conditions, since the mutex is not held
// after the pointer is returned.
TransportChannelImpl* GetChannel(const std::string& name);
@@ -184,7 +184,7 @@ class Transport : public talk_base::MessageHandler, public sigslot::has_slots<>,
// These are called by Create/DestroyChannel above in order to create or
// destroy the appropriate type of channel.
virtual TransportChannelImpl* CreateTransportChannel(
- const std::string& name, const std::string &session_type) = 0;
+ const std::string& name, const std::string &content_type) = 0;
virtual void DestroyTransportChannel(TransportChannelImpl* channel) = 0;
// Informs the subclass that we received the signaling ready message.
@@ -221,7 +221,7 @@ class Transport : public talk_base::MessageHandler, public sigslot::has_slots<>,
// particular thread (s = signaling, w = worker). The above methods post or
// send a message to invoke this version.
TransportChannelImpl* CreateChannel_w(const std::string& name,
- const std::string& session_type);
+ const std::string& content_type);
void DestroyChannel_w(const std::string& name);
void ConnectChannels_w();
void ResetChannels_w();
diff --git a/third_party/libjingle/source/talk/p2p/base/transportchannel.h b/third_party/libjingle/source/talk/p2p/base/transportchannel.h
index 8196847..a9384af 100644
--- a/third_party/libjingle/source/talk/p2p/base/transportchannel.h
+++ b/third_party/libjingle/source/talk/p2p/base/transportchannel.h
@@ -41,14 +41,14 @@ class P2PTransportChannel;
// between the two sides of a session.
class TransportChannel: public sigslot::has_slots<> {
public:
- TransportChannel(const std::string& name, const std::string &session_type)
- : name_(name), session_type_(session_type),
+ TransportChannel(const std::string& name, const std::string &content_type)
+ : name_(name), content_type_(content_type),
readable_(false), writable_(false) {}
virtual ~TransportChannel() {}
// Returns the name of this channel.
const std::string& name() const { return name_; }
- const std::string& session_type() const { return session_type_; }
+ const std::string& content_type() const { return content_type_; }
// Returns the readable and states of this channel. Each time one of these
// states changes, a signal is raised. These states are aggregated by the
@@ -98,7 +98,7 @@ class TransportChannel: public sigslot::has_slots<> {
private:
std::string name_;
- std::string session_type_;
+ std::string content_type_;
bool readable_;
bool writable_;
diff --git a/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h b/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h
index a84b4bf..39e4288 100644
--- a/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h
+++ b/third_party/libjingle/source/talk/p2p/base/transportchannelimpl.h
@@ -43,8 +43,8 @@ class Candidate;
// client.
class TransportChannelImpl : public TransportChannel {
public:
- TransportChannelImpl(const std::string& name, const std::string& session_type)
- : TransportChannel(name, session_type) {}
+ TransportChannelImpl(const std::string& name, const std::string& content_type)
+ : TransportChannel(name, content_type) {}
// Returns the transport that created this channel.
virtual Transport* GetTransport() = 0;
diff --git a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
index e2d11ed..405ed76 100644
--- a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
+++ b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
@@ -33,8 +33,8 @@
namespace cricket {
TransportChannelProxy::TransportChannelProxy(const std::string& name,
- const std::string &session_type)
- : TransportChannel(name, session_type), impl_(NULL) {
+ const std::string &content_type)
+ : TransportChannel(name, content_type), impl_(NULL) {
}
TransportChannelProxy::~TransportChannelProxy() {
diff --git a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
index 46d8a44..2184477 100644
--- a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
+++ b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
@@ -42,7 +42,7 @@ class TransportChannelImpl;
// when negotiation completes, connect the proxy to the implementaiton.
class TransportChannelProxy: public TransportChannel {
public:
- TransportChannelProxy(const std::string& name, const std::string &session_type);
+ TransportChannelProxy(const std::string& name, const std::string &content_type);
virtual ~TransportChannelProxy();
TransportChannelImpl* impl() const { return impl_; }
diff --git a/third_party/libjingle/source/talk/session/phone/call.cc b/third_party/libjingle/source/talk/session/phone/call.cc
index e2717ce..8feddc9 100644
--- a/third_party/libjingle/source/talk/session/phone/call.cc
+++ b/third_party/libjingle/source/talk/session/phone/call.cc
@@ -62,15 +62,8 @@ Session *Call::InitiateSession(const buzz::Jid &jid) {
Session *session = session_client_->CreateSession(this);
AddSession(session);
- MediaSessionDescription *session_desc =
- session_client_->CreateOfferSessionDescription(video_);
- if (mux_) {
- session_desc->voice().set_ssrc(0);
- if (video_) {
- session_desc->video().set_ssrc(0);
- }
- }
- session->Initiate(jid.Str(), session_desc);
+ const SessionDescription* offer = session_client_->CreateOffer(video_, mux_);
+ session->Initiate(jid.Str(), offer);
// After this timeout, terminate the call because the callee isn't
// answering
@@ -85,23 +78,23 @@ Session *Call::InitiateSession(const buzz::Jid &jid) {
void Call::AcceptSession(BaseSession *session) {
std::vector<Session *>::iterator it;
it = std::find(sessions_.begin(), sessions_.end(), session);
- assert(it != sessions_.end());
+ ASSERT(it != sessions_.end());
if (it != sessions_.end()) {
- session->Accept(session_client_->CreateAcceptSessionDescription(
- session->remote_description()));
+ session->Accept(
+ session_client_->CreateAnswer(session->remote_description()));
}
}
void Call::RejectSession(BaseSession *session) {
std::vector<Session *>::iterator it;
it = std::find(sessions_.begin(), sessions_.end(), session);
- assert(it != sessions_.end());
+ ASSERT(it != sessions_.end());
if (it != sessions_.end())
session->Reject();
}
void Call::TerminateSession(BaseSession *session) {
- assert(std::find(sessions_.begin(), sessions_.end(), session)
+ ASSERT(std::find(sessions_.begin(), sessions_.end(), session)
!= sessions_.end());
std::vector<Session *>::iterator it;
it = std::find(sessions_.begin(), sessions_.end(), session);
diff --git a/third_party/libjingle/source/talk/session/phone/channel.cc b/third_party/libjingle/source/talk/session/phone/channel.cc
index 2b3e043..b59c0f1 100644
--- a/third_party/libjingle/source/talk/session/phone/channel.cc
+++ b/third_party/libjingle/source/talk/session/phone/channel.cc
@@ -93,17 +93,23 @@ bool BaseChannel::RemoveStream(uint32 ssrc) {
return true;
}
-bool BaseChannel::SetLocalDescription(const MediaSessionDescription& desc,
- DescriptionType type) {
- SetDescriptionData data(desc, type);
- Send(MSG_SETLOCALDESCRIPTION, &data);
+bool BaseChannel::SetRtcpCName(const std::string& cname) {
+ SetRtcpCNameData data(cname);
+ Send(MSG_SETRTCPCNAME, &data);
return data.result;
}
-bool BaseChannel::SetRemoteDescription(const MediaSessionDescription& desc,
- DescriptionType type) {
- SetDescriptionData data(desc, type);
- Send(MSG_SETREMOTEDESCRIPTION, &data);
+bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
+ ContentAction action) {
+ SetContentData data(content, action);
+ Send(MSG_SETLOCALCONTENT, &data);
+ return data.result;
+}
+
+bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
+ ContentAction action) {
+ SetContentData data(content, action);
+ Send(MSG_SETREMOTECONTENT, &data);
return data.result;
}
@@ -270,27 +276,32 @@ void BaseChannel::OnSessionState(BaseSession* session,
BaseSession::State state) {
// TODO(juberti): tear down the call via session->SetError() if the
// SetXXXXDescription calls fail.
+ const MediaContentDescription* content = NULL;
switch (state) {
case Session::STATE_SENTINITIATE:
+ content = GetFirstContent(session->local_description());
+ if (content) {
+ SetLocalContent(content, CA_OFFER);
+ }
+ break;
case Session::STATE_SENTACCEPT:
- if (session->local_description()) {
- SetLocalDescription(*static_cast<const MediaSessionDescription*>(
- session->local_description()),
- (state == Session::STATE_SENTINITIATE) ?
- DT_OFFER : DT_ANSWER);
+ content = GetFirstContent(session->local_description());
+ if (content) {
+ SetLocalContent(content, CA_ANSWER);
}
break;
-
case Session::STATE_RECEIVEDINITIATE:
+ content = GetFirstContent(session->remote_description());
+ if (content) {
+ SetRemoteContent(content, CA_OFFER);
+ }
+ break;
case Session::STATE_RECEIVEDACCEPT:
- if (session->remote_description()) {
- SetRemoteDescription(*static_cast<const MediaSessionDescription*>(
- session->remote_description()),
- (state == Session::STATE_RECEIVEDINITIATE) ?
- DT_OFFER : DT_ANSWER);
+ content = GetFirstContent(session->remote_description());
+ if (content) {
+ SetRemoteContent(content, CA_ANSWER);
}
break;
-
default:
break;
}
@@ -363,26 +374,30 @@ bool BaseChannel::SetMaxSendBandwidth_w(int max_bandwidth) {
return media_channel()->SetMaxSendBandwidth(max_bandwidth);
}
+bool BaseChannel::SetRtcpCName_w(const std::string& cname) {
+ return media_channel()->SetRtcpCName(cname);
+}
+
bool BaseChannel::SetSrtp_w(const std::vector<CryptoParams>& cryptos,
- DescriptionType type, DescriptionSource src) {
+ ContentAction action, ContentSource src) {
bool ret;
- if (type == DT_OFFER) {
+ if (action == CA_OFFER) {
ret = srtp_filter_.SetOffer(cryptos, src);
- } else if (type == DT_ANSWER) {
+ } else if (action == CA_ANSWER) {
ret = srtp_filter_.SetAnswer(cryptos, src);
} else {
- // DT_UPDATE, no crypto params.
+ // CA_UPDATE, no crypto params.
ret = true;
}
return ret;
}
-bool BaseChannel::SetRtcpMux_w(bool enable, DescriptionType type,
- DescriptionSource src) {
+bool BaseChannel::SetRtcpMux_w(bool enable, ContentAction action,
+ ContentSource src) {
bool ret;
- if (type == DT_OFFER) {
+ if (action == CA_OFFER) {
ret = rtcp_mux_filter_.SetOffer(enable, src);
- } else if (type == DT_ANSWER) {
+ } else if (action == CA_ANSWER) {
ret = rtcp_mux_filter_.SetAnswer(enable, src);
if (ret && rtcp_mux_filter_.IsActive()) {
// We activated RTCP mux, close down the RTCP transport.
@@ -393,7 +408,7 @@ bool BaseChannel::SetRtcpMux_w(bool enable, DescriptionType type,
}
}
} else {
- // DT_UPDATE, no RTCP mux info.
+ // CA_UPDATE, no RTCP mux info.
ret = true;
}
return ret;
@@ -415,14 +430,20 @@ void BaseChannel::OnMessage(talk_base::Message *pmsg) {
UnmuteMedia_w();
break;
- case MSG_SETLOCALDESCRIPTION: {
- SetDescriptionData* data = static_cast<SetDescriptionData*>(pmsg->pdata);
- data->result = SetLocalDescription_w(data->desc, data->type);
+ case MSG_SETRTCPCNAME: {
+ SetRtcpCNameData* data = static_cast<SetRtcpCNameData*>(pmsg->pdata);
+ data->result = SetRtcpCName_w(data->cname);
+ break;
+ }
+
+ case MSG_SETLOCALCONTENT: {
+ SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
+ data->result = SetLocalContent_w(data->content, data->action);
break;
}
- case MSG_SETREMOTEDESCRIPTION: {
- SetDescriptionData* data = static_cast<SetDescriptionData*>(pmsg->pdata);
- data->result = SetRemoteDescription_w(data->desc, data->type);
+ case MSG_SETREMOTECONTENT: {
+ SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
+ data->result = SetRemoteContent_w(data->content, data->action);
break;
}
@@ -587,44 +608,61 @@ void VoiceChannel::ChangeState() {
LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
}
-bool VoiceChannel::SetLocalDescription_w(const MediaSessionDescription& desc,
- DescriptionType type) {
+const MediaContentDescription* VoiceChannel::GetFirstContent(
+ const SessionDescription* sdesc) {
+ const ContentInfo* cinfo = GetFirstAudioContent(sdesc);
+ if (cinfo == NULL)
+ return NULL;
+
+ return static_cast<const MediaContentDescription*>(cinfo->description);
+}
+
+bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
+ ContentAction action) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting local voice description";
+ const AudioContentDescription* audio =
+ static_cast<const AudioContentDescription*>(content);
+ ASSERT(audio != NULL);
+
bool ret;
// set SRTP
- ret = SetSrtp_w(desc.voice().cryptos(), type, DS_LOCAL);
+ ret = SetSrtp_w(audio->cryptos(), action, CS_LOCAL);
// set RTCP mux
if (ret) {
- ret = SetRtcpMux_w(desc.voice().rtcp_mux(), type, DS_LOCAL);
+ ret = SetRtcpMux_w(audio->rtcp_mux(), action, CS_LOCAL);
}
// set payload type and config for voice codecs
if (ret) {
- ret = media_channel()->SetRecvCodecs(desc.voice().codecs());
+ ret = media_channel()->SetRecvCodecs(audio->codecs());
}
return ret;
}
-bool VoiceChannel::SetRemoteDescription_w(const MediaSessionDescription& desc,
- DescriptionType type) {
+bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
+ ContentAction action) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting remote voice description";
+ const AudioContentDescription* audio =
+ static_cast<const AudioContentDescription*>(content);
+ ASSERT(audio != NULL);
+
bool ret;
// set the sending SSRC, if the remote side gave us one
- if (desc.voice().ssrc_set()) {
- media_channel()->SetSendSsrc(desc.voice().ssrc());
+ if (audio->ssrc_set()) {
+ media_channel()->SetSendSsrc(audio->ssrc());
}
// set SRTP
- ret = SetSrtp_w(desc.voice().cryptos(), type, DS_REMOTE);
+ ret = SetSrtp_w(audio->cryptos(), action, CS_REMOTE);
// set RTCP mux
if (ret) {
- ret = SetRtcpMux_w(desc.voice().rtcp_mux(), type, DS_REMOTE);
+ ret = SetRtcpMux_w(audio->rtcp_mux(), action, CS_REMOTE);
}
// set codecs and payload types
if (ret) {
- ret = media_channel()->SetSendCodecs(desc.voice().codecs());
+ ret = media_channel()->SetSendCodecs(audio->codecs());
}
// update state
if (ret) {
@@ -755,17 +793,6 @@ bool VideoChannel::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
return true;
}
-bool VideoChannel::AddScreencast(uint32 ssrc, talk_base::WindowId id) {
- ScreencastMessageData data(ssrc, id);
- Send(MSG_ADDSCREENCAST, &data);
- return true;
-}
-
-bool VideoChannel::RemoveScreencast(uint32 ssrc) {
- ScreencastMessageData data(ssrc, 0);
- Send(MSG_REMOVESCREENCAST, &data);
- return true;
-}
void VideoChannel::ChangeState() {
// render incoming data if we are the active call
@@ -797,47 +824,64 @@ void VideoChannel::StopMediaMonitor() {
}
}
-bool VideoChannel::SetLocalDescription_w(const MediaSessionDescription& desc,
- DescriptionType type) {
+const MediaContentDescription* VideoChannel::GetFirstContent(
+ const SessionDescription* sdesc) {
+ const ContentInfo* cinfo = GetFirstVideoContent(sdesc);
+ if (cinfo == NULL)
+ return NULL;
+
+ return static_cast<const MediaContentDescription*>(cinfo->description);
+}
+
+bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
+ ContentAction action) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting local video description";
+ const VideoContentDescription* video =
+ static_cast<const VideoContentDescription*>(content);
+ ASSERT(video != NULL);
+
bool ret;
// set SRTP
- ret = SetSrtp_w(desc.video().cryptos(), type, DS_LOCAL);
+ ret = SetSrtp_w(video->cryptos(), action, CS_LOCAL);
// set RTCP mux
if (ret) {
- ret = SetRtcpMux_w(desc.video().rtcp_mux(), type, DS_LOCAL);
+ ret = SetRtcpMux_w(video->rtcp_mux(), action, CS_LOCAL);
}
// set payload types and config for receiving video
if (ret) {
- ret = media_channel()->SetRecvCodecs(desc.video().codecs());
+ ret = media_channel()->SetRecvCodecs(video->codecs());
}
return ret;
}
-bool VideoChannel::SetRemoteDescription_w(const MediaSessionDescription& desc,
- DescriptionType type) {
+bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
+ ContentAction action) {
ASSERT(worker_thread() == talk_base::Thread::Current());
LOG(LS_INFO) << "Setting remote video description";
+ const VideoContentDescription* video =
+ static_cast<const VideoContentDescription*>(content);
+ ASSERT(video != NULL);
+
bool ret;
// set the sending SSRC, if the remote side gave us one
// TODO(juberti): remove this, since it's not needed.
- if (desc.video().ssrc_set()) {
- media_channel()->SetSendSsrc(desc.video().ssrc());
+ if (video->ssrc_set()) {
+ media_channel()->SetSendSsrc(video->ssrc());
}
// set SRTP
- ret = SetSrtp_w(desc.video().cryptos(), type, DS_REMOTE);
+ ret = SetSrtp_w(video->cryptos(), action, CS_REMOTE);
// set RTCP mux
if (ret) {
- ret = SetRtcpMux_w(desc.video().rtcp_mux(), type, DS_REMOTE);
+ ret = SetRtcpMux_w(video->rtcp_mux(), action, CS_REMOTE);
}
// TODO(juberti): Set bandwidth appropriately here.
if (ret) {
- ret = media_channel()->SetSendCodecs(desc.video().codecs());
+ ret = media_channel()->SetSendCodecs(video->codecs());
}
- media_channel()->SetRtpExtensionHeaders(!desc.video().rtp_headers_disabled());
+ media_channel()->SetRtpExtensionHeaders(!video->rtp_headers_disabled());
if (ret) {
set_has_codec(true);
ChangeState();
@@ -857,13 +901,6 @@ void VideoChannel::SetRenderer_w(uint32 ssrc, VideoRenderer* renderer) {
media_channel()->SetRenderer(ssrc, renderer);
}
-void VideoChannel::AddScreencast_w(uint32 ssrc, talk_base::WindowId id) {
- media_channel()->AddScreencast(ssrc, id);
-}
-
-void VideoChannel::RemoveScreencast_w(uint32 ssrc) {
- media_channel()->RemoveScreencast(ssrc);
-}
void VideoChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
@@ -877,18 +914,6 @@ void VideoChannel::OnMessage(talk_base::Message *pmsg) {
SetRenderer_w(data->ssrc, data->renderer);
break;
}
- case MSG_ADDSCREENCAST: {
- ScreencastMessageData* data =
- static_cast<ScreencastMessageData*>(pmsg->pdata);
- AddScreencast_w(data->ssrc, data->window_id);
- break;
- }
- case MSG_REMOVESCREENCAST: {
- ScreencastMessageData* data =
- static_cast<ScreencastMessageData*>(pmsg->pdata);
- RemoveScreencast_w(data->ssrc);
- break;
- }
default:
BaseChannel::OnMessage(pmsg);
break;
@@ -917,11 +942,11 @@ bool RtcpMuxFilter::IsActive() const {
return (state_ == ST_SENTOFFER || state_ == ST_ACTIVE);
}
-bool RtcpMuxFilter::SetOffer(bool offer_enable, DescriptionSource source) {
+bool RtcpMuxFilter::SetOffer(bool offer_enable, ContentSource source) {
bool ret = false;
if (state_ == ST_INIT) {
offer_enable_ = offer_enable;
- state_ = (source == DS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
+ state_ = (source == CS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
ret = true;
} else {
LOG(LS_ERROR) << "Invalid state for RTCP mux offer";
@@ -929,10 +954,10 @@ bool RtcpMuxFilter::SetOffer(bool offer_enable, DescriptionSource source) {
return ret;
}
-bool RtcpMuxFilter::SetAnswer(bool answer_enable, DescriptionSource source) {
+bool RtcpMuxFilter::SetAnswer(bool answer_enable, ContentSource source) {
bool ret = false;
- if ((state_ == ST_SENTOFFER && source == DS_REMOTE) ||
- (state_ == ST_RECEIVEDOFFER && source == DS_LOCAL)) {
+ if ((state_ == ST_SENTOFFER && source == CS_REMOTE) ||
+ (state_ == ST_RECEIVEDOFFER && source == CS_LOCAL)) {
if (offer_enable_) {
state_ = (answer_enable) ? ST_ACTIVE : ST_INIT;
ret = true;
diff --git a/third_party/libjingle/source/talk/session/phone/channel.h b/third_party/libjingle/source/talk/session/phone/channel.h
index 85e5074..ff059bb 100644
--- a/third_party/libjingle/source/talk/session/phone/channel.h
+++ b/third_party/libjingle/source/talk/session/phone/channel.h
@@ -28,12 +28,12 @@
#ifndef TALK_SESSION_PHONE_CHANNEL_H_
#define TALK_SESSION_PHONE_CHANNEL_H_
+#include <string>
#include <vector>
#include "talk/base/asyncudpsocket.h"
#include "talk/base/network.h"
#include "talk/base/sigslot.h"
-#include "talk/base/windowpicker.h"
#include "talk/p2p/client/socketmonitor.h"
#include "talk/p2p/base/session.h"
#include "talk/session/phone/audiomonitor.h"
@@ -44,7 +44,7 @@
namespace cricket {
-class MediaSessionDescription;
+class MediaContentDescription;
struct CryptoParams;
enum {
@@ -52,8 +52,8 @@ enum {
MSG_DISABLE = 2,
MSG_MUTE = 3,
MSG_UNMUTE = 4,
- MSG_SETREMOTEDESCRIPTION = 5,
- MSG_SETLOCALDESCRIPTION = 6,
+ MSG_SETREMOTECONTENT = 5,
+ MSG_SETLOCALCONTENT = 6,
MSG_EARLYMEDIATIMEOUT = 8,
MSG_PRESSDTMF = 9,
MSG_SETRENDERER = 10,
@@ -63,7 +63,8 @@ enum {
MSG_PLAYRINGBACKTONE = 14,
MSG_SETMAXSENDBANDWIDTH = 15,
MSG_ADDSCREENCAST = 16,
- MSG_REMOVESCREENCAST = 17
+ MSG_REMOVESCREENCAST = 17,
+ MSG_SETRTCPCNAME = 18
};
// TODO(juberti): Move to own file.
@@ -75,10 +76,10 @@ class RtcpMuxFilter {
bool IsActive() const;
// Specifies whether the offer indicates the use of RTCP mux.
- bool SetOffer(bool offer_enable, DescriptionSource src);
+ bool SetOffer(bool offer_enable, ContentSource src);
// Specifies whether the answer indicates the use of RTCP mux.
- bool SetAnswer(bool answer_enable, DescriptionSource src);
+ bool SetAnswer(bool answer_enable, ContentSource src);
// Determines whether the specified packet is RTCP.
bool DemuxRtcp(const char* data, int len);
@@ -115,10 +116,11 @@ class BaseChannel
bool secure() const { return srtp_filter_.IsActive(); }
// Channel control
- bool SetLocalDescription(const MediaSessionDescription& desc,
- DescriptionType type);
- bool SetRemoteDescription(const MediaSessionDescription& desc,
- DescriptionType type);
+ bool SetRtcpCName(const std::string& cname);
+ bool SetLocalContent(const MediaContentDescription* content,
+ ContentAction action);
+ bool SetRemoteContent(const MediaContentDescription* content,
+ ContentAction action);
bool SetMaxSendBandwidth(int max_bandwidth);
bool Enable(bool enable);
@@ -178,22 +180,35 @@ class BaseChannel
virtual void RemoveStream_w(uint32 ssrc) = 0;
virtual void ChangeState() = 0;
- struct SetDescriptionData : public talk_base::MessageData {
- SetDescriptionData(const MediaSessionDescription& desc,
- DescriptionType type)
- : desc(desc), type(type), result(false) {}
- const MediaSessionDescription& desc;
- DescriptionType type;
+
+ struct SetRtcpCNameData : public talk_base::MessageData {
+ explicit SetRtcpCNameData(const std::string& cname)
+ : cname(cname), result(false) {}
+ std::string cname;
+ bool result;
+ };
+ bool SetRtcpCName_w(const std::string& cname);
+
+ struct SetContentData : public talk_base::MessageData {
+ SetContentData(const MediaContentDescription* content,
+ ContentAction action)
+ : content(content), action(action), result(false) {}
+ const MediaContentDescription* content;
+ ContentAction action;
bool result;
};
- virtual bool SetLocalDescription_w(const MediaSessionDescription& desc,
- DescriptionType type) = 0;
- virtual bool SetRemoteDescription_w(const MediaSessionDescription& desc,
- DescriptionType type) = 0;
- bool SetSrtp_w(const std::vector<CryptoParams>& params, DescriptionType type,
- DescriptionSource src);
- bool SetRtcpMux_w(bool enable, DescriptionType type, DescriptionSource src);
+ // Gets the content appropriate to the channel (audio or video).
+ virtual const MediaContentDescription* GetFirstContent(
+ const SessionDescription* sdesc) = 0;
+ virtual bool SetLocalContent_w(const MediaContentDescription* content,
+ ContentAction action) = 0;
+ virtual bool SetRemoteContent_w(const MediaContentDescription* content,
+ ContentAction action) = 0;
+
+ bool SetSrtp_w(const std::vector<CryptoParams>& params, ContentAction action,
+ ContentSource src);
+ bool SetRtcpMux_w(bool enable, ContentAction action, ContentSource src);
struct SetBandwidthData : public talk_base::MessageData {
explicit SetBandwidthData(int value) : value(value), result(false) {}
@@ -301,10 +316,12 @@ class VoiceChannel : public BaseChannel {
virtual void OnChannelRead(TransportChannel* channel,
const char *data, size_t len);
virtual void ChangeState();
- virtual bool SetLocalDescription_w(const MediaSessionDescription& desc,
- DescriptionType type);
- virtual bool SetRemoteDescription_w(const MediaSessionDescription& desc,
- DescriptionType type);
+ virtual const MediaContentDescription* GetFirstContent(
+ const SessionDescription* sdesc);
+ virtual bool SetLocalContent_w(const MediaContentDescription* content,
+ ContentAction action);
+ virtual bool SetRemoteContent_w(const MediaContentDescription* content,
+ ContentAction action);
void AddStream_w(uint32 ssrc);
void RemoveStream_w(uint32 ssrc);
@@ -345,8 +362,6 @@ class VideoChannel : public BaseChannel {
bool SetRenderer(uint32 ssrc, VideoRenderer* renderer);
- bool AddScreencast(uint32 ssrc, talk_base::WindowId id);
- bool RemoveScreencast(uint32 ssrc);
sigslot::signal2<VideoChannel*, const std::vector<ConnectionInfo> &>
SignalConnectionMonitor;
@@ -358,10 +373,12 @@ class VideoChannel : public BaseChannel {
private:
// overrides from BaseChannel
virtual void ChangeState();
- virtual bool SetLocalDescription_w(const MediaSessionDescription& desc,
- DescriptionType type);
- virtual bool SetRemoteDescription_w(const MediaSessionDescription& desc,
- DescriptionType type);
+ virtual const MediaContentDescription* GetFirstContent(
+ const SessionDescription* sdesc);
+ virtual bool SetLocalContent_w(const MediaContentDescription* content,
+ ContentAction action);
+ virtual bool SetRemoteContent_w(const MediaContentDescription* content,
+ ContentAction action);
void AddStream_w(uint32 ssrc, uint32 voice_ssrc);
void RemoveStream_w(uint32 ssrc);
@@ -372,17 +389,9 @@ class VideoChannel : public BaseChannel {
VideoRenderer* renderer;
};
- struct ScreencastMessageData : public talk_base::MessageData {
- ScreencastMessageData(uint32 s, talk_base::WindowId id)
- : ssrc(s), window_id(id) {}
- uint32 ssrc;
- talk_base::WindowId window_id;
- };
void SetRenderer_w(uint32 ssrc, VideoRenderer* renderer);
- void AddScreencast_w(uint32 ssrc, talk_base::WindowId);
- void RemoveScreencast_w(uint32 ssrc);
virtual void OnMessage(talk_base::Message *pmsg);
virtual void OnConnectionMonitorUpdate(
diff --git a/third_party/libjingle/source/talk/session/phone/channelmanager.cc b/third_party/libjingle/source/talk/session/phone/channelmanager.cc
index 92957bf..8affab0 100644
--- a/third_party/libjingle/source/talk/session/phone/channelmanager.cc
+++ b/third_party/libjingle/source/talk/session/phone/channelmanager.cc
@@ -57,7 +57,7 @@ enum {
MSG_DESTROYVIDEOCHANNEL = 12,
MSG_SETVIDEOOPTIONS = 13,
MSG_SETLOCALRENDERER = 14,
- MSG_SETDEFAULTVIDEOCODEC = 15,
+ MSG_SETDEFAULTVIDEOENCODERCONFIG = 15,
MSG_SETVIDEOLOGGING = 16,
MSG_CREATESOUNDCLIP = 17,
MSG_DESTROYSOUNDCLIP = 18,
@@ -96,9 +96,10 @@ struct VideoOptions : public talk_base::MessageData {
bool result;
};
-struct DefaultVideoCodec : public talk_base::MessageData {
- explicit DefaultVideoCodec(const VideoCodec& c) : codec(c), result(false) {}
- VideoCodec codec;
+struct DefaultVideoEncoderConfig : public talk_base::MessageData {
+ explicit DefaultVideoEncoderConfig(const VideoEncoderConfig& c)
+ : config(c), result(false) {}
+ VideoEncoderConfig config;
bool result;
};
@@ -121,10 +122,10 @@ struct LoggingOptions : public talk_base::MessageData {
};
struct CaptureParams : public talk_base::MessageData {
- explicit CaptureParams(bool c) : capture(c), result(MediaEngine::CR_FAILURE) {
- }
+ explicit CaptureParams(bool c) : capture(c), result(CR_FAILURE) {}
+
bool capture;
- MediaEngine::CaptureResult result;
+ CaptureResult result;
};
ChannelManager::ChannelManager(talk_base::Thread* worker_thread)
@@ -142,11 +143,14 @@ ChannelManager::ChannelManager(talk_base::Thread* worker_thread)
sound_system_factory_.get()
#endif
)),
- initialized_(false), main_thread_(talk_base::Thread::Current()),
- worker_thread_(NULL), audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ initialized_(false),
+ main_thread_(talk_base::Thread::Current()),
+ worker_thread_(worker_thread),
+ audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ local_renderer_(NULL),
capturing_(false),
monitoring_(false) {
- Construct(worker_thread);
+ Construct();
}
ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* dm,
@@ -155,15 +159,19 @@ ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* dm,
#ifdef USE_TALK_SOUND
sound_system_factory_(NULL),
#endif
- media_engine_(me), device_manager_(dm),
- initialized_(false), main_thread_(talk_base::Thread::Current()),
- worker_thread_(NULL), audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ media_engine_(me),
+ device_manager_(dm),
+ initialized_(false),
+ main_thread_(talk_base::Thread::Current()),
+ worker_thread_(worker_thread),
+ audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ local_renderer_(NULL),
capturing_(false),
monitoring_(false) {
- Construct(worker_thread);
+ Construct();
}
-void ChannelManager::Construct(talk_base::Thread* worker_thread) {
+void ChannelManager::Construct() {
// Init the device manager immediately, and set up our default video device.
SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
device_manager_->Init();
@@ -173,10 +181,6 @@ void ChannelManager::Construct(talk_base::Thread* worker_thread) {
// completes to be able to forward them to the rendering manager.
media_engine_->SignalVideoCaptureResult.connect(
this, &ChannelManager::OnVideoCaptureResult);
-
- // If we're given a worker thread, init the media engine right away.
- if (worker_thread)
- Init(worker_thread);
}
ChannelManager::~ChannelManager() {
@@ -188,11 +192,13 @@ int ChannelManager::GetCapabilities() {
return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
}
-void ChannelManager::GetSupportedCodecs(std::vector<Codec>* codecs) const {
+void ChannelManager::GetSupportedAudioCodecs(
+ std::vector<AudioCodec>* codecs) const {
codecs->clear();
- for (std::vector<Codec>::const_iterator it = media_engine_->codecs().begin();
- it != media_engine_->codecs().end(); ++it) {
+ for (std::vector<AudioCodec>::const_iterator it =
+ media_engine_->audio_codecs().begin();
+ it != media_engine_->audio_codecs().end(); ++it) {
codecs->push_back(*it);
}
}
@@ -208,16 +214,15 @@ void ChannelManager::GetSupportedVideoCodecs(
}
}
-bool ChannelManager::Init(talk_base::Thread* worker_thread) {
+bool ChannelManager::Init() {
ASSERT(!initialized_);
if (initialized_) {
return false;
}
- ASSERT(worker_thread != NULL);
- if (worker_thread && worker_thread->started()) {
+ ASSERT(worker_thread_ != NULL);
+ if (worker_thread_ && worker_thread_->started()) {
if (media_engine_->Init()) {
- worker_thread_ = worker_thread;
initialized_ = true;
// Now that we're initialized, apply any stored preferences.
@@ -231,8 +236,12 @@ bool ChannelManager::Init(talk_base::Thread* worker_thread) {
camera_device_.clear();
}
// Now apply the default video codec that has been set earlier.
- if (default_video_codec_.id != 0) {
- SetDefaultVideoCodec(default_video_codec_);
+ if (default_video_encoder_config_.max_codec.id != 0) {
+ SetDefaultVideoEncoderConfig(default_video_encoder_config_);
+ }
+ // And the local renderer.
+ if (local_renderer_) {
+ SetLocalRenderer(local_renderer_);
}
}
}
@@ -258,7 +267,6 @@ void ChannelManager::Terminate() {
media_engine_->Terminate();
initialized_ = false;
- worker_thread_ = NULL;
}
VoiceChannel* ChannelManager::CreateVoiceChannel(BaseSession* session,
@@ -492,8 +500,22 @@ bool ChannelManager::SetVideoOptions(const std::string& cam_name) {
// If we're running, tell the media engine about it.
if (ret && initialized_) {
- VideoOptions options(&device);
- ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
+#ifdef OSX
+ // Defer SequenceGrabber queries until call time as they can spin up the
+ // high power GPU. Can remove once LMI moves to QTKit enumeration.
+ Device sg_device;
+ ret = device_manager_->QtKitToSgDevice(device.name, &sg_device);
+ if (ret) {
+ device = sg_device;
+ } else {
+ LOG(LS_ERROR) << "Unable to find SG Component for qtkit device "
+ << device.name;
+ }
+#endif
+ if (ret) {
+ VideoOptions options(&device);
+ ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
+ }
}
// If everything worked, retain the name of the selected camera.
@@ -511,22 +533,23 @@ bool ChannelManager::SetVideoOptions_w(const Device* cam_device) {
return media_engine_->SetVideoCaptureDevice(cam_device);
}
-bool ChannelManager::SetDefaultVideoCodec(const VideoCodec& c) {
+bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
bool ret = true;
if (initialized_) {
- DefaultVideoCodec codec(c);
- ret = Send(MSG_SETDEFAULTVIDEOCODEC, &codec) && codec.result;
+ DefaultVideoEncoderConfig config(c);
+ ret = Send(MSG_SETDEFAULTVIDEOENCODERCONFIG, &config) && config.result;
}
if (ret) {
- default_video_codec_ = c;
+ default_video_encoder_config_ = c;
}
return ret;
}
-bool ChannelManager::SetDefaultVideoCodec_w(const VideoCodec& c) {
+bool ChannelManager::SetDefaultVideoEncoderConfig_w(
+ const VideoEncoderConfig& c) {
ASSERT(worker_thread_ == talk_base::Thread::Current());
ASSERT(initialized_);
- return media_engine_->SetDefaultVideoCodec(c);
+ return media_engine_->SetDefaultVideoEncoderConfig(c);
}
bool ChannelManager::SetLocalMonitor(bool enable) {
@@ -545,11 +568,13 @@ bool ChannelManager::SetLocalMonitor_w(bool enable) {
}
bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) {
- bool ret;
- LocalRenderer capture(renderer);
- ret = (Send(MSG_SETLOCALRENDERER, &capture) && capture.result);
+ bool ret = true;
+ if (initialized_) {
+ LocalRenderer local(renderer);
+ ret = (Send(MSG_SETLOCALRENDERER, &local) && local.result);
+ }
if (ret) {
- capturing_ = (renderer != NULL);
+ local_renderer_ = renderer;
}
return ret;
}
@@ -560,18 +585,18 @@ bool ChannelManager::SetLocalRenderer_w(VideoRenderer* renderer) {
return media_engine_->SetLocalRenderer(renderer);
}
-MediaEngine::CaptureResult ChannelManager::SetVideoCapture(bool capture) {
+CaptureResult ChannelManager::SetVideoCapture(bool capture) {
bool ret;
CaptureParams capture_params(capture);
ret = (Send(MSG_SETVIDEOCAPTURE, &capture_params) &&
- (capture_params.result != MediaEngine::CR_FAILURE));
+ (capture_params.result != CR_FAILURE));
if (ret) {
capturing_ = capture;
}
return capture_params.result;
}
-MediaEngine::CaptureResult ChannelManager::SetVideoCapture_w(bool capture) {
+CaptureResult ChannelManager::SetVideoCapture_w(bool capture) {
ASSERT(worker_thread_ == talk_base::Thread::Current());
ASSERT(initialized_);
return media_engine_->SetVideoCapture(capture);
@@ -609,7 +634,7 @@ void ChannelManager::SetMediaLogging_w(bool video, int level,
}
bool ChannelManager::Send(uint32 id, talk_base::MessageData* data) {
- if (!worker_thread_) return false;
+ if (!worker_thread_ || !initialized_) return false;
worker_thread_->Send(this, id, data);
return true;
}
@@ -679,9 +704,10 @@ void ChannelManager::OnMessage(talk_base::Message* message) {
p->result = SetVideoOptions_w(p->cam_device);
break;
}
- case MSG_SETDEFAULTVIDEOCODEC: {
- DefaultVideoCodec* p = static_cast<DefaultVideoCodec*>(data);
- p->result = SetDefaultVideoCodec_w(p->codec);
+ case MSG_SETDEFAULTVIDEOENCODERCONFIG: {
+ DefaultVideoEncoderConfig* p =
+ static_cast<DefaultVideoEncoderConfig*>(data);
+ p->result = SetDefaultVideoEncoderConfig_w(p->config);
break;
}
case MSG_SETLOCALRENDERER: {
diff --git a/third_party/libjingle/source/talk/session/phone/channelmanager.h b/third_party/libjingle/source/talk/session/phone/channelmanager.h
index e0d8dec..2c17fdb 100644
--- a/third_party/libjingle/source/talk/session/phone/channelmanager.h
+++ b/third_party/libjingle/source/talk/session/phone/channelmanager.h
@@ -28,6 +28,7 @@
#ifndef TALK_SESSION_PHONE_CHANNELMANAGER_H_
#define TALK_SESSION_PHONE_CHANNELMANAGER_H_
+#include <string>
#include <vector>
#include "talk/base/criticalsection.h"
@@ -57,25 +58,34 @@ class VoiceChannel;
class ChannelManager : public talk_base::MessageHandler,
public sigslot::has_slots<> {
public:
- // Creates the channel manager, and initializes it if the thread is not NULL.
+ // Creates the channel manager, and specifies the worker thread to use.
explicit ChannelManager(talk_base::Thread* worker);
// For testing purposes. Allows the media engine and dev manager to be mocks.
// The ChannelManager takes ownership of these objects.
ChannelManager(MediaEngine* me, DeviceManager* dm, talk_base::Thread* worker);
~ChannelManager();
+ // Accessors for the worker thread, allowing it to be set after construction,
+ // but before Init. set_worker_thread will return false if called after Init.
+ talk_base::Thread* worker_thread() const { return worker_thread_; }
+ bool set_worker_thread(talk_base::Thread* thread) {
+ if (initialized_) return false;
+ worker_thread_ = thread;
+ return true;
+ }
+
// Gets capabilities. Can be called prior to starting the media engine.
int GetCapabilities();
// Retrieves the list of supported audio & video codec types.
// Can be called before starting the media engine.
- void GetSupportedCodecs(std::vector<Codec>* codecs) const;
+ void GetSupportedAudioCodecs(std::vector<AudioCodec>* codecs) const;
void GetSupportedVideoCodecs(std::vector<VideoCodec>* codecs) const;
// Determines if a specific audio or video codec is supported.
// Can be called before starting the media engine.
- bool FindCodec(const Codec& codec) const {
- return media_engine_->FindCodec(codec);
+ bool FindAudioCodec(const AudioCodec& codec) const {
+ return media_engine_->FindAudioCodec(codec);
}
bool FindVideoCodec(const VideoCodec& video_codec) const {
return media_engine_->FindVideoCodec(video_codec);
@@ -83,9 +93,12 @@ class ChannelManager : public talk_base::MessageHandler,
// Indicates whether the media engine is started.
bool initialized() const { return initialized_; }
- talk_base::Thread* worker_thread() const { return worker_thread_; }
// Starts up the media engine.
- bool Init(talk_base::Thread* worker_thread);
+ bool Init();
+ // TODO(juberti): Remove this temporary API once Flute is updated.
+ bool Init(talk_base::Thread* thread) {
+ return set_worker_thread(thread) && Init();
+ }
// Shuts down the media engine.
void Terminate();
@@ -121,7 +134,7 @@ class ChannelManager : public talk_base::MessageHandler,
bool SetOutputVolume(int level);
bool GetVideoOptions(std::string* cam_device);
bool SetVideoOptions(const std::string& cam_device);
- bool SetDefaultVideoCodec(const VideoCodec& codec);
+ bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config);
// Starts/stops the local microphone and enables polling of the input level.
bool SetLocalMonitor(bool enable);
@@ -129,7 +142,7 @@ class ChannelManager : public talk_base::MessageHandler,
// Sets the local renderer where to renderer the local camera.
bool SetLocalRenderer(VideoRenderer* renderer);
// Starts and stops the local camera and renders it to the local renderer.
- MediaEngine::CaptureResult SetVideoCapture(bool capture);
+ CaptureResult SetVideoCapture(bool capture);
bool capturing() const { return capturing_; }
// Configures the logging output of the mediaengine(s).
@@ -149,7 +162,7 @@ class ChannelManager : public talk_base::MessageHandler,
typedef std::vector<VideoChannel*> VideoChannels;
typedef std::vector<Soundclip*> Soundclips;
- void Construct(talk_base::Thread* worker_thread);
+ void Construct();
bool Send(uint32 id, talk_base::MessageData* pdata);
VoiceChannel* CreateVoiceChannel_w(BaseSession* session, bool rtcp);
void DestroyVoiceChannel_w(VoiceChannel* voice_channel);
@@ -163,9 +176,9 @@ class ChannelManager : public talk_base::MessageHandler,
bool SetOutputVolume_w(int level);
bool SetLocalMonitor_w(bool enable);
bool SetVideoOptions_w(const Device* cam_device);
- bool SetDefaultVideoCodec_w(const VideoCodec& codec);
+ bool SetDefaultVideoEncoderConfig_w(const VideoEncoderConfig& config);
bool SetLocalRenderer_w(VideoRenderer* renderer);
- MediaEngine::CaptureResult SetVideoCapture_w(bool capture);
+ CaptureResult SetVideoCapture_w(bool capture);
void SetMediaLogging(bool video, int level, const char* filter);
void SetMediaLogging_w(bool video, int level, const char* filter);
void OnVideoCaptureResult(bool result);
@@ -189,7 +202,8 @@ class ChannelManager : public talk_base::MessageHandler,
std::string audio_out_device_;
int audio_options_;
std::string camera_device_;
- VideoCodec default_video_codec_;
+ VideoEncoderConfig default_video_encoder_config_;
+ VideoRenderer* local_renderer_;
bool capturing_;
bool monitoring_;
diff --git a/third_party/libjingle/source/talk/session/phone/codec.cc b/third_party/libjingle/source/talk/session/phone/codec.cc
index 7c6f5a6..ba617da 100644
--- a/third_party/libjingle/source/talk/session/phone/codec.cc
+++ b/third_party/libjingle/source/talk/session/phone/codec.cc
@@ -32,14 +32,14 @@ namespace cricket {
static const int kMaxStaticPayloadId = 95;
-bool Codec::Matches(int payload, const std::string& nm) const {
+bool AudioCodec::Matches(int payload, const std::string& nm) const {
return (id <= kMaxStaticPayloadId && id == payload) ||
(id > kMaxStaticPayloadId && name == nm);
}
-std::string Codec::ToString() const {
+std::string AudioCodec::ToString() const {
std::ostringstream os;
- os << "Codec[" << id << ":" << name << ":" << clockrate << ":" << bitrate
+ os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate
<< ":" << channels << ":" << preference << "]";
return os.str();
}
diff --git a/third_party/libjingle/source/talk/session/phone/codec.h b/third_party/libjingle/source/talk/session/phone/codec.h
index fdebbbe..4a3105b 100644
--- a/third_party/libjingle/source/talk/session/phone/codec.h
+++ b/third_party/libjingle/source/talk/session/phone/codec.h
@@ -32,7 +32,7 @@
namespace cricket {
-struct Codec {
+struct AudioCodec {
int id;
std::string name;
int clockrate;
@@ -42,20 +42,43 @@ struct Codec {
int preference;
// Creates a codec with the given parameters.
- Codec(int pt, const std::string& nm, int cr, int br, int cs, int pr)
+ AudioCodec(int pt, const std::string& nm, int cr, int br, int cs, int pr)
: id(pt), name(nm), clockrate(cr), bitrate(br),
channels(cs), preference(pr) {}
// Creates an empty codec.
- Codec() : id(0), clockrate(0), bitrate(0), channels(0), preference(0) {}
+ AudioCodec() : id(0), clockrate(0), bitrate(0), channels(0), preference(0) {}
bool Matches(int payload, const std::string& nm) const;
- static bool Preferable(const Codec& first, const Codec& other) {
+ static bool Preferable(const AudioCodec& first, const AudioCodec& other) {
return first.preference > other.preference;
}
std::string ToString() const;
+
+ AudioCodec& operator=(const AudioCodec& c) {
+ this->id = c.id; // id is reserved in objective-c
+ name = c.name;
+ clockrate = c.clockrate;
+ bitrate = c.bitrate;
+ channels = c.channels;
+ preference = c.preference;
+ return *this;
+ }
+
+ bool operator==(const AudioCodec& c) const {
+ return this->id == c.id && // id is reserved in objective-c
+ name == c.name &&
+ clockrate == c.clockrate &&
+ bitrate == c.bitrate &&
+ channels == c.channels &&
+ preference == c.preference;
+ }
+
+ bool operator!=(const AudioCodec& c) const {
+ return !(*this == c);
+ }
};
struct VideoCodec {
@@ -82,9 +105,75 @@ struct VideoCodec {
}
std::string ToString() const;
+
+ VideoCodec& operator=(const VideoCodec& c) {
+ this->id = c.id; // id is reserved in objective-c
+ name = c.name;
+ width = c.width;
+ height = c.height;
+ framerate = c.framerate;
+ preference = c.preference;
+ return *this;
+ }
+
+ bool operator==(const VideoCodec& c) const {
+ return this->id == c.id && // id is reserved in objective-c
+ name == c.name &&
+ width == c.width &&
+ height == c.height &&
+ framerate == c.framerate &&
+ preference == c.preference;
+ }
+
+ bool operator!=(const VideoCodec& c) const {
+ return !(*this == c);
+ }
+};
+
+struct VideoEncoderConfig {
+ static const int kDefaultMaxThreads = -1;
+ static const int kDefaultCpuProfile = -1;
+
+ VideoEncoderConfig()
+ : max_codec(),
+ num_threads(kDefaultMaxThreads),
+ cpu_profile(kDefaultCpuProfile) {
+ }
+
+ VideoEncoderConfig(const VideoCodec& c)
+ : max_codec(c),
+ num_threads(kDefaultMaxThreads),
+ cpu_profile(kDefaultCpuProfile) {
+ }
+
+ VideoEncoderConfig(const VideoCodec& c, int t, int p)
+ : max_codec(c),
+ num_threads(t),
+ cpu_profile(p) {
+ }
+
+ VideoEncoderConfig& operator=(const VideoEncoderConfig& config) {
+ max_codec = config.max_codec;
+ num_threads = config.num_threads;
+ cpu_profile = config.cpu_profile;
+ return *this;
+ }
+
+ bool operator==(const VideoEncoderConfig& config) const {
+ return max_codec == config.max_codec &&
+ num_threads == config.num_threads &&
+ cpu_profile == config.cpu_profile;
+ }
+
+ bool operator!=(const VideoEncoderConfig& config) const {
+ return !(*this == config);
+ }
+
+ VideoCodec max_codec;
+ int num_threads;
+ int cpu_profile;
};
} // namespace cricket
#endif // TALK_SESSION_PHONE_CODEC_H_
-
diff --git a/third_party/libjingle/source/talk/session/phone/devicemanager.cc b/third_party/libjingle/source/talk/session/phone/devicemanager.cc
index 3e98e0a..bbff3fd 100644
--- a/third_party/libjingle/source/talk/session/phone/devicemanager.cc
+++ b/third_party/libjingle/source/talk/session/phone/devicemanager.cc
@@ -94,7 +94,9 @@ class DeviceWatcher {
#ifndef LINUX
static bool ShouldDeviceBeIgnored(const std::string& device_name);
#endif
+#ifndef OSX
static bool GetVideoDevices(std::vector<Device>* out);
+#endif
#if WIN32
static const wchar_t kFriendlyName[] = L"FriendlyName";
static const wchar_t kDevicePath[] = L"DevicePath";
@@ -103,8 +105,10 @@ static bool GetDevices(const CLSID& catid, std::vector<Device>* out);
static bool GetCoreAudioDevices(bool input, std::vector<Device>* devs);
static bool GetWaveDevices(bool input, std::vector<Device>* devs);
#elif OSX
-static const UInt32 kAudioDeviceNameLength = 64;
static const int kVideoDeviceOpenAttempts = 3;
+static const UInt32 kAudioDeviceNameLength = 64;
+// Obj-C function defined in devicemanager-mac.mm
+extern bool GetQTKitVideoDevices(std::vector<Device>* out);
static bool GetAudioDeviceIDs(bool inputs, std::vector<AudioDeviceID>* out);
static bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out);
#endif
@@ -177,10 +181,107 @@ bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) {
return GetAudioDevice(false, name, out);
}
+#ifdef OSX
+static bool FilterDevice(const Device& d) {
+ return ShouldDeviceBeIgnored(d.name);
+}
+#endif
+
bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
+ devices->clear();
+#ifdef OSX
+ if (GetQTKitVideoDevices(devices)) {
+ // Now filter out any known incompatible devices
+ devices->erase(remove_if(devices->begin(), devices->end(), FilterDevice),
+ devices->end());
+ return true;
+ }
+ return false;
+#else
return GetVideoDevices(devices);
+#endif
}
+#ifdef OSX
+bool DeviceManager::QtKitToSgDevice(const std::string& qtkit_name,
+ Device* out) {
+ out->name.clear();
+
+ ComponentDescription only_vdig;
+ memset(&only_vdig, 0, sizeof(only_vdig));
+ only_vdig.componentType = videoDigitizerComponentType;
+ only_vdig.componentSubType = kAnyComponentSubType;
+ only_vdig.componentManufacturer = kAnyComponentManufacturer;
+
+ // Enumerate components (drivers).
+ Component component = 0;
+ while ((component = FindNextComponent(component, &only_vdig)) &&
+ out->name.empty()) {
+ // Get the name of the component and see if we want to open it.
+ Handle name_handle = NewHandle(0);
+ GetComponentInfo(component, NULL, name_handle, NULL, NULL);
+ Ptr name_ptr = *name_handle;
+ std::string comp_name(name_ptr + 1, static_cast<size_t>(*name_ptr));
+ DisposeHandle(name_handle);
+
+ if (!ShouldDeviceBeIgnored(comp_name)) {
+ // Try to open the component.
+ // DV Video will fail with err=-9408 (deviceCantMeetRequest)
+ // IIDC FireWire Video and USB Video Class Video will fail with err=704
+ // if no cameras are present, or there is contention for the camera.
+ // We can't tell the scenarios apart, so we will retry a few times if
+ // we get a 704 to make sure we detect the cam if one is really there.
+ int attempts = 0;
+ ComponentInstance vdig;
+ OSErr err;
+ do {
+ err = OpenAComponent(component, &vdig);
+ ++attempts;
+ } while (!vdig && err == 704 && attempts < kVideoDeviceOpenAttempts);
+
+ if (vdig) {
+ // We were able to open the component.
+ LOG(LS_INFO) << "Opened component \"" << comp_name
+ << "\", tries=" << attempts;
+
+ // Enumerate cameras on the component.
+ // Note, that due to QT strangeness VDGetNumberOfInputs really returns
+ // the number of inputs minus one. If no inputs are available -1 is
+ // returned.
+ short num_inputs; // NOLINT
+ VideoDigitizerError err = VDGetNumberOfInputs(vdig, &num_inputs);
+ if (err == 0 && num_inputs >= 0) {
+ LOG(LS_INFO) << "Found " << num_inputs + 1 << " webcams attached.";
+ Str255 pname;
+ for (int i = 0; i <= num_inputs; ++i) {
+ err = VDGetInputName(vdig, i, pname);
+ if (err == 0) {
+ // The format for camera ids is <component>:<camera index>.
+ char id_buf[256];
+ talk_base::sprintfn(id_buf, ARRAY_SIZE(id_buf), "%s:%d",
+ comp_name.c_str(), i);
+ std::string name(reinterpret_cast<const char*>(pname + 1),
+ static_cast<size_t>(*pname)), id(id_buf);
+ LOG(LS_INFO) << " Webcam " << i << ": " << name;
+ if (name == qtkit_name) {
+ out->name = name;
+ out->id = id;
+ break;
+ }
+ }
+ }
+ }
+ CloseComponent(vdig);
+ } else {
+ LOG(LS_INFO) << "Failed to open component \"" << comp_name
+ << "\", err=" << err;
+ }
+ }
+ }
+ return !out->name.empty();
+}
+#endif
+
bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
bool ret = false;
#if WIN32
@@ -396,10 +497,26 @@ bool GetDevices(const CLSID& catid, std::vector<Device>* devices) {
return true;
}
+HRESULT GetStringProp(IPropertyStore* bag, PROPERTYKEY key, std::string* out) {
+ out->clear();
+ PROPVARIANT var;
+ PropVariantInit(&var);
+
+ HRESULT hr = bag->GetValue(key, &var);
+ if (SUCCEEDED(hr)) {
+ if (var.pwszVal)
+ *out = talk_base::ToUtf8(var.pwszVal);
+ else
+ hr = E_FAIL;
+ }
+
+ PropVariantClear(&var);
+ return hr;
+}
+
// Adapted from http://msdn.microsoft.com/en-us/library/dd370812(v=VS.85).aspx
HRESULT CricketDeviceFromImmDevice(IMMDevice* device, Device* out) {
CComPtr<IPropertyStore> props;
- PROPVARIANT name, guid;
HRESULT hr = device->OpenPropertyStore(STGM_READ, &props);
if (FAILED(hr)) {
@@ -407,19 +524,16 @@ HRESULT CricketDeviceFromImmDevice(IMMDevice* device, Device* out) {
}
// Get the endpoint's name and id.
- PropVariantInit(&name);
- hr = props->GetValue(PKEY_Device_FriendlyName, &name);
+ std::string name, guid;
+ hr = GetStringProp(props, PKEY_Device_FriendlyName, &name);
if (SUCCEEDED(hr)) {
- PropVariantInit(&guid);
- hr = props->GetValue(PKEY_AudioEndpoint_GUID, &guid);
+ hr = GetStringProp(props, PKEY_AudioEndpoint_GUID, &guid);
if (SUCCEEDED(hr)) {
- out->name = talk_base::ToUtf8(name.pwszVal);
- out->id = talk_base::ToUtf8(guid.pwszVal);
+ out->name = name;
+ out->id = guid;
}
- PropVariantClear(&guid);
}
- PropVariantClear(&name);
return hr;
}
@@ -452,7 +566,9 @@ bool GetCoreAudioDevices(bool input, std::vector<Device>* devs) {
if (SUCCEEDED(hr)) {
devs->push_back(dev);
} else {
- break;
+ LOG(LS_WARNING) << "Unable to query IMM Device, skipping. HR="
+ << hr;
+ hr = S_FALSE;
}
}
}
@@ -559,76 +675,6 @@ bool DeviceWatcher::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
return false;
}
#elif defined(OSX)
-static bool GetVideoDevices(std::vector<Device>* devices) {
- ComponentDescription only_vdig;
- memset(&only_vdig, 0, sizeof(only_vdig));
- only_vdig.componentType = videoDigitizerComponentType;
- only_vdig.componentSubType = kAnyComponentSubType;
- only_vdig.componentManufacturer = kAnyComponentManufacturer;
-
- // Enumerate components (drivers).
- Component component = 0;
- while ((component = FindNextComponent(component, &only_vdig))) {
- // Get the name of the component and see if we want to open it.
- Handle name_handle = NewHandle(0);
- GetComponentInfo(component, NULL, name_handle, NULL, NULL);
- Ptr name_ptr = *name_handle;
- std::string comp_name(name_ptr + 1, static_cast<size_t>(*name_ptr));
- DisposeHandle(name_handle);
-
- if (!ShouldDeviceBeIgnored(comp_name)) {
- // Try to open the component.
- // DV Video will fail with err=-9408 (deviceCantMeetRequest)
- // IIDC FireWire Video and USB Video Class Video will fail with err=704
- // if no cameras are present, or there is contention for the camera.
- // We can't tell the scenarios apart, so we will retry a few times if
- // we get a 704 to make sure we detect the cam if one is really there.
- int attempts = 0;
- ComponentInstance vdig;
- OSErr err;
- do {
- err = OpenAComponent(component, &vdig);
- attempts++;
- } while (!vdig && err == 704 && attempts < kVideoDeviceOpenAttempts);
-
- if (vdig) {
- // We were able to open the component.
- LOG(LS_INFO) << "Opened component \"" << comp_name
- << "\", tries=" << attempts;
-
- // Enumerate cameras on the component.
- // Note, that due to QT strangeness VDGetNumberOfInputs really returns
- // the number of inputs minus one. If no inputs are available -1 is
- // returned.
- short num_inputs; // NOLINT
- VideoDigitizerError err = VDGetNumberOfInputs(vdig, &num_inputs);
- if (err == 0 && num_inputs >= 0) {
- LOG(LS_INFO) << "Found " << num_inputs + 1 << " webcams attached.";
- Str255 pname;
- for (int i = 0; i <= num_inputs; ++i) {
- err = VDGetInputName(vdig, i, pname);
- if (err == 0) {
- // The format for camera ids is <component>:<camera index>.
- char id_buf[256];
- talk_base::sprintfn(id_buf, ARRAY_SIZE(id_buf), "%s:%d",
- comp_name.c_str(), i);
- std::string name(reinterpret_cast<const char*>(pname + 1),
- static_cast<size_t>(*pname)), id(id_buf);
- LOG(LS_INFO) << " Webcam " << i << ": " << name;
- devices->push_back(Device(name, id));
- }
- }
- }
- CloseComponent(vdig);
- } else {
- LOG(LS_INFO) << "Failed to open component \"" << comp_name
- << "\", err=" << err;
- }
- }
- }
- return true;
-}
-
static bool GetAudioDeviceIDs(bool input,
std::vector<AudioDeviceID>* out_dev_ids) {
UInt32 propsize;
@@ -856,18 +902,18 @@ static bool GetVideoDevices(std::vector<Device>* devices) {
}
#endif
-#ifndef LINUX
// TODO(tommyw): Try to get hold of a copy of Final Cut to understand why we
// crash while scanning their components on OS X.
+#ifndef LINUX
static bool ShouldDeviceBeIgnored(const std::string& device_name) {
static const char* const kFilteredDevices[] = {
"Google Camera Adapter", // Our own magiccams
#ifdef WIN32
"Asus virtual Camera", // Bad Asus desktop virtual cam
"Bluetooth Video", // Bad Sony viao bluetooth sharing driver
-#endif
-#ifdef OSX
+#elif OSX
"DVCPRO HD", // Final cut
+ "Sonix SN9C201p", // Crashes in OpenAComponent and CloseComponent
#endif
};
diff --git a/third_party/libjingle/source/talk/session/phone/devicemanager.h b/third_party/libjingle/source/talk/session/phone/devicemanager.h
index a79f7fb..594e9bd 100644
--- a/third_party/libjingle/source/talk/session/phone/devicemanager.h
+++ b/third_party/libjingle/source/talk/session/phone/devicemanager.h
@@ -83,6 +83,10 @@ class DeviceManager {
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
virtual bool GetDefaultVideoCaptureDevice(Device* device);
+#ifdef OSX
+ virtual bool QtKitToSgDevice(const std::string& qtkit_name, Device* out);
+#endif
+
sigslot::signal0<> SignalDevicesChange;
void OnDevicesChange() { SignalDevicesChange(); }
diff --git a/third_party/libjingle/source/talk/session/phone/filevideoengine.h b/third_party/libjingle/source/talk/session/phone/filevideoengine.h
index 158b775..5056ff8 100644
--- a/third_party/libjingle/source/talk/session/phone/filevideoengine.h
+++ b/third_party/libjingle/source/talk/session/phone/filevideoengine.h
@@ -85,12 +85,10 @@ class FileVideoEngine {
int GetCapabilities() { return 0; }
bool SetOptions(int opts) { return true; }
bool SetLocalRenderer(VideoRenderer* renderer) { return true; }
- MediaEngine::CaptureResult SetCapture(bool capture) {
- return MediaEngine::CR_SUCCESS;
- }
+ CaptureResult SetCapture(bool capture) { return CR_SUCCESS; }
const std::vector<VideoCodec>& codecs();
bool FindCodec(const VideoCodec& codec);
- bool SetDefaultCodec(const VideoCodec& codec);
+ bool SetDefaultEncoderConfig(const VideoEncoderConfig& config);
void SetLogging(int severity, const char* filter) {}
sigslot::signal1<bool> SignalCaptureResult;
diff --git a/third_party/libjingle/source/talk/session/phone/filevideomediachannel.h b/third_party/libjingle/source/talk/session/phone/filevideomediachannel.h
index d7f8137..5b73a8c 100644
--- a/third_party/libjingle/source/talk/session/phone/filevideomediachannel.h
+++ b/third_party/libjingle/source/talk/session/phone/filevideomediachannel.h
@@ -74,6 +74,7 @@ class FileVideoMediaChannel : public VideoMediaChannel {
virtual bool RemoveScreencast(uint32 ssrc) { return true; }
virtual bool SetSend(bool send) { return true; }
virtual void SetSendSsrc(uint32 id) {}
+ virtual bool SetRtcpCName(const std::string& cname) { return true; }
virtual bool SetMaxSendBandwidth(int max_bandwidth) { return false; }
virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc) { return false; }
virtual bool RemoveStream(uint32 ssrc) { return false; }
diff --git a/third_party/libjingle/source/talk/session/phone/mediachannel.h b/third_party/libjingle/source/talk/session/phone/mediachannel.h
index 857f1b6..962aec3 100644
--- a/third_party/libjingle/source/talk/session/phone/mediachannel.h
+++ b/third_party/libjingle/source/talk/session/phone/mediachannel.h
@@ -28,12 +28,12 @@
#ifndef TALK_SESSION_PHONE_MEDIACHANNEL_H_
#define TALK_SESSION_PHONE_MEDIACHANNEL_H_
+#include <string>
#include <vector>
#include "talk/base/basictypes.h"
#include "talk/base/sigslot.h"
#include "talk/base/socket.h"
-#include "talk/base/windowpicker.h"
#include "talk/session/phone/codec.h"
// TODO(juberti): re-evaluate this include
#include "talk/session/phone/audiomonitor.h"
@@ -81,6 +81,8 @@ class MediaChannel : public sigslot::has_slots<> {
virtual void OnRtcpReceived(const void *data, int len) = 0;
// Sets the SSRC to be used for outgoing data.
virtual void SetSendSsrc(uint32 id) = 0;
+ // Set the CNAME of RTCP
+ virtual bool SetRtcpCName(const std::string& cname) = 0;
// Mutes the channel.
virtual bool Mute(bool on) = 0;
@@ -119,9 +121,9 @@ class VoiceMediaChannel : public MediaChannel {
VoiceMediaChannel() {}
virtual ~VoiceMediaChannel() {}
// Sets the codecs/payload types to be used for incoming media.
- virtual bool SetRecvCodecs(const std::vector<Codec>& codecs) = 0;
+ virtual bool SetRecvCodecs(const std::vector<AudioCodec>& codecs) = 0;
// Sets the codecs/payload types to be used for outgoing media.
- virtual bool SetSendCodecs(const std::vector<Codec>& codecs) = 0;
+ virtual bool SetSendCodecs(const std::vector<AudioCodec>& codecs) = 0;
// Starts or stops playout of received audio.
virtual bool SetPlayout(bool playout) = 0;
// Starts or stops sending (and potentially capture) of local audio.
@@ -144,7 +146,7 @@ class VoiceMediaChannel : public MediaChannel {
virtual bool GetStats(VoiceMediaInfo* info) = 0;
};
-// Represents a (decoded) video frame, in YUV420 (a.k.a. I420) format.
+// Represents a YUV420 (a.k.a. I420) video frame.
class VideoFrame {
friend class flute::MagicCamVideoRenderer;
@@ -170,6 +172,13 @@ class VideoFrame {
virtual size_t GetPixelWidth() const = 0;
virtual size_t GetPixelHeight() const = 0;
+ // TODO(whyuan): Add a fourcc format here and probably combine VideoFrame
+ // with CapturedFrame.
+ virtual int64 GetElapsedTime() const = 0;
+ virtual int64 GetTimeStamp() const = 0;
+ virtual void SetElapsedTime(int64 elapsed_time) = 0;
+ virtual void SetTimeStamp(int64 time_stamp) = 0;
+
// Writes the frame into the given frame buffer, provided that it is of
// sufficient size. Returns the frame's actual size, regardless of whether
// it was written or not (like snprintf). If there is insufficient space,
@@ -184,34 +193,37 @@ class VideoFrame {
size_t size, size_t pitch_rgb) const = 0;
// Writes the frame into the given planes, stretched to the given width and
- // height.
- // "interpolate" controls whether to interpolate or just take the
- // nearest-point.
+ // height. The parameter "interpolate" controls whether to interpolate or just
+ // take the nearest-point. The parameter "crop" controls whether to crop this
+ // frame to the aspect ratio of the given dimensions before stretching.
virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v,
int32 pitchY, int32 pitchU, int32 pitchV,
size_t width, size_t height,
- bool interpolate) const = 0;
+ bool interpolate, bool crop) const = 0;
- // Writes the frame into the given frame buffer, stretched to the given
- // width and height, provided that it is of sufficient size. Returns the
- // frame's actual size, regardless of whether it was written or not
- // (like snprintf). If there is insufficient space, nothing is written.
+ // Writes the frame into the given frame buffer, stretched to the given width
+ // and height, provided that it is of sufficient size. Returns the frame's
+ // actual size, regardless of whether it was written or not (like snprintf).
+ // If there is insufficient space, nothing is written. The parameter
// "interpolate" controls whether to interpolate or just take the
- // nearest-point.
+ // nearest-point. The parameter "crop" controls whether to crop this frame to
+ // the aspect ratio of the given dimensions before stretching.
virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
- bool interpolate) const = 0;
+ bool interpolate, bool crop) const = 0;
// Writes the frame into the target VideoFrame, stretched to the size of that
- // frame.
- // "interpolate" controls whether to interpolate or just take the
- // nearest-point.
- virtual void StretchToFrame(VideoFrame *target, bool interpolate) const = 0;
+ // frame. The parameter "interpolate" controls whether to interpolate or just
+ // take the nearest-point. The parameter "crop" controls whether to crop this
+ // frame to the aspect ratio of the target frame before stretching.
+ virtual void StretchToFrame(VideoFrame *target, bool interpolate,
+ bool crop) const = 0;
// Stretches the frame to the given size, creating a new VideoFrame object to
- // hold it.
- // "interpolate" controls whether to interpolate or just take the
- // nearest-point.
- virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate) const = 0;
+ // hold it. The parameter "interpolate" controls whether to interpolate or
+ // just take the nearest-point. The parameter "crop" controls whether to crop
+ // this frame to the aspect ratio of the given dimensions before stretching.
+ virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate,
+ bool crop) const = 0;
// Size of an I420 image of given dimensions when stored as a frame buffer.
static size_t SizeOf(size_t w, size_t h) {
@@ -242,6 +254,10 @@ class NullVideoFrame : public VideoFrame {
virtual size_t GetPixelWidth() const { return 1; }
virtual size_t GetPixelHeight() const { return 1; }
+ virtual int64 GetElapsedTime() const { return 0; }
+ virtual int64 GetTimeStamp() const { return 0; }
+ virtual void SetElapsedTime(int64 elapsed_time) {}
+ virtual void SetTimeStamp(int64 time_stamp) {}
virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const {
return 0;
@@ -255,22 +271,25 @@ class NullVideoFrame : public VideoFrame {
virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v,
int32 pitchY, int32 pitchU, int32 pitchV,
size_t width, size_t height,
- bool interpolate) const {
+ bool interpolate, bool crop) const {
}
virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
- bool interpolate) const {
+ bool interpolate, bool crop) const {
return 0;
}
- virtual void StretchToFrame(VideoFrame *target, bool interpolate) const {
+ virtual void StretchToFrame(VideoFrame *target, bool interpolate,
+ bool crop) const {
}
- virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate) const {
+ virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate,
+ bool crop) const {
return NULL;
}
};
+// Abstract interface for rendering VideoFrames.
class VideoRenderer {
public:
virtual ~VideoRenderer() {}
@@ -280,6 +299,17 @@ class VideoRenderer {
virtual bool RenderFrame(const VideoFrame *frame) = 0;
};
+// Simple implementation for use in tests.
+class NullVideoRenderer : public VideoRenderer {
+ virtual bool SetSize(int width, int height, int reserved) {
+ return true;
+ }
+ // Called when a new frame is available for display.
+ virtual bool RenderFrame(const VideoFrame *frame) {
+ return true;
+ }
+};
+
class VideoMediaChannel : public MediaChannel {
public:
VideoMediaChannel() { renderer_ = NULL; }
@@ -299,8 +329,6 @@ class VideoMediaChannel : public MediaChannel {
// Sets the renderer object to be used for the specified stream.
// If SSRC is 0, the renderer is used for the 'default' stream.
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) = 0;
- virtual bool AddScreencast(uint32 ssrc, talk_base::WindowId id) = 0;
- virtual bool RemoveScreencast(uint32 ssrc) = 0;
// Gets quality stats for the channel.
virtual bool GetStats(VideoMediaInfo* info) = 0;
protected:
diff --git a/third_party/libjingle/source/talk/session/phone/mediaengine.h b/third_party/libjingle/source/talk/session/phone/mediaengine.h
index 2633e05..eade188 100644
--- a/third_party/libjingle/source/talk/session/phone/mediaengine.h
+++ b/third_party/libjingle/source/talk/session/phone/mediaengine.h
@@ -42,6 +42,7 @@
#ifdef USE_TALK_SOUND
#include "talk/sound/soundsystemfactory.h"
#endif
+#include "talk/session/phone/videocommon.h"
namespace cricket {
@@ -86,13 +87,6 @@ class MediaEngine {
enum VideoOptions {
};
- enum CaptureResult {
- CR_SUCCESS,
- CR_PENDING,
- CR_FAILURE,
- CR_NO_DEVICE,
- };
-
virtual ~MediaEngine() {}
static MediaEngine* Create(
#ifdef USE_TALK_SOUND
@@ -124,8 +118,10 @@ class MediaEngine {
virtual bool SetAudioOptions(int options) = 0;
// Sets global video options. "options" are from VideoOptions, above.
virtual bool SetVideoOptions(int options) = 0;
- // Sets the default (maximum) codec/resolution to capture and encode video.
- virtual bool SetDefaultVideoCodec(const VideoCodec& codec) = 0;
+ // Sets the default (maximum) codec/resolution and encoder option to capture
+ // and encode video.
+ virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config)
+ = 0;
// Device selection
// TODO(tschmelcher): Add method for selecting the soundclip device.
@@ -149,10 +145,9 @@ class MediaEngine {
// Starts/stops local camera.
virtual CaptureResult SetVideoCapture(bool capture) = 0;
- // Codecs
- virtual const std::vector<Codec>& codecs() = 0;
+ virtual const std::vector<AudioCodec>& audio_codecs() = 0;
virtual const std::vector<VideoCodec>& video_codecs() = 0;
- virtual bool FindCodec(const Codec &codec) = 0;
+ virtual bool FindAudioCodec(const AudioCodec &codec) = 0;
virtual bool FindVideoCodec(const VideoCodec &codec) = 0;
// Logging control
@@ -168,7 +163,9 @@ template<class VOICE, class VIDEO>
class CompositeMediaEngine : public MediaEngine {
public:
#ifdef USE_TALK_SOUND
- CompositeMediaEngine(SoundSystemFactory *factory) : voice_(factory) {}
+ explicit CompositeMediaEngine(SoundSystemFactory *factory)
+ : voice_(factory) {
+ }
#endif
CompositeMediaEngine() {}
virtual bool Init() {
@@ -205,8 +202,8 @@ class CompositeMediaEngine : public MediaEngine {
virtual bool SetVideoOptions(int o) {
return video_.SetOptions(o);
}
- virtual bool SetDefaultVideoCodec(const VideoCodec& codec) {
- return video_.SetDefaultCodec(codec);
+ virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) {
+ return video_.SetDefaultEncoderConfig(config);
}
virtual bool SetSoundDevices(const Device* in_device,
@@ -230,18 +227,18 @@ class CompositeMediaEngine : public MediaEngine {
virtual bool SetLocalRenderer(VideoRenderer* renderer) {
return video_.SetLocalRenderer(renderer);
}
- virtual MediaEngine::CaptureResult SetVideoCapture(bool capture) {
+ virtual CaptureResult SetVideoCapture(bool capture) {
return video_.SetCapture(capture);
}
- virtual const std::vector<Codec>& codecs() {
+ virtual const std::vector<AudioCodec>& audio_codecs() {
return voice_.codecs();
}
virtual const std::vector<VideoCodec>& video_codecs() {
return video_.codecs();
}
- virtual bool FindCodec(const Codec &codec) {
+ virtual bool FindAudioCodec(const AudioCodec &codec) {
return voice_.FindCodec(codec);
}
virtual bool FindVideoCodec(const VideoCodec &codec) {
@@ -280,11 +277,11 @@ class NullVoiceEngine {
bool SetOutputVolume(int level) { return true; }
int GetInputLevel() { return 0; }
bool SetLocalMonitor(bool enable) { return true; }
- const std::vector<Codec>& codecs() { return codecs_; }
- bool FindCodec(const Codec&) { return false; }
+ const std::vector<AudioCodec>& codecs() { return codecs_; }
+ bool FindCodec(const AudioCodec&) { return false; }
void SetLogging(int min_sev, const char* filter) {}
private:
- std::vector<Codec> codecs_;
+ std::vector<AudioCodec> codecs_;
};
// NullVideoEngine can be used with CompositeMediaEngine in the case where only
@@ -298,12 +295,12 @@ class NullVideoEngine {
return NULL;
}
bool SetOptions(int opts) { return true; }
- bool SetDefaultCodec(const VideoCodec& codec) { return true; }
+ bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) {
+ return true;
+ }
bool SetCaptureDevice(const Device* cam_device) { return true; }
bool SetLocalRenderer(VideoRenderer* renderer) { return true; }
- MediaEngine::CaptureResult SetCapture(bool capture) {
- return MediaEngine::CR_SUCCESS;
- }
+ CaptureResult SetCapture(bool capture) { return CR_SUCCESS; }
const std::vector<VideoCodec>& codecs() { return codecs_; }
bool FindCodec(const VideoCodec&) { return false; }
void SetLogging(int min_sev, const char* filter) {}
diff --git a/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc b/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc
index 7d0e476..fa07ccc 100644
--- a/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc
+++ b/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc
@@ -61,6 +61,10 @@ void MediaSessionClient::Construct() {
session_manager_->AddClient(NS_GINGLE_VIDEO, this);
// Forward device notifications.
SignalDevicesChange.repeat(channel_manager_->SignalDevicesChange);
+ // Bring up the channel manager.
+ // In previous versions of ChannelManager, this was done automatically
+ // in the constructor.
+ channel_manager_->Init();
}
MediaSessionClient::~MediaSessionClient() {
@@ -79,57 +83,93 @@ MediaSessionClient::~MediaSessionClient() {
session_manager_->RemoveClient(NS_GINGLE_AUDIO);
}
-MediaSessionDescription* MediaSessionClient::CreateOfferSessionDescription(
- bool video) {
- MediaSessionDescription* session_desc = new MediaSessionDescription();
+SessionDescription* MediaSessionClient::CreateOffer(bool video, bool set_ssrc) {
+ SessionDescription* offer = new SessionDescription();
+ AudioContentDescription* audio = new AudioContentDescription();
- // add audio codecs
- std::vector<Codec> codecs;
- channel_manager_->GetSupportedCodecs(&codecs);
- for (std::vector<Codec>::const_iterator i = codecs.begin();
- i != codecs.end(); ++i)
- session_desc->voice().AddCodec(*i);
+ AudioCodecs audio_codecs;
+ channel_manager_->GetSupportedAudioCodecs(&audio_codecs);
+ for (AudioCodecs::const_iterator codec = audio_codecs.begin();
+ codec != audio_codecs.end(); codec++) {
+ audio->AddCodec(*codec);
+ }
+ if (set_ssrc) {
+ audio->set_ssrc(0);
+ }
+ audio->SortCodecs();
+ offer->AddContent(CN_AUDIO, NS_GINGLE_AUDIO, audio);
// add video codecs, if this is a video call
if (video) {
- std::vector<VideoCodec> video_codecs;
+ VideoContentDescription* video = new VideoContentDescription();
+ VideoCodecs video_codecs;
channel_manager_->GetSupportedVideoCodecs(&video_codecs);
- for (std::vector<VideoCodec>::const_iterator i = video_codecs.begin();
- i != video_codecs.end(); i++)
- session_desc->video().AddCodec(*i);
+ for (VideoCodecs::const_iterator codec = video_codecs.begin();
+ codec != video_codecs.end(); codec++) {
+ video->AddCodec(*codec);
+ }
+ if (set_ssrc) {
+ video->set_ssrc(0);
+ }
+ video->SortCodecs();
+ offer->AddContent(CN_VIDEO, NS_GINGLE_VIDEO, video);
}
- session_desc->Sort();
- return session_desc;
+ return offer;
+}
+
+const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
+ const std::string& content_type) {
+ if (sdesc == NULL)
+ return NULL;
+
+ return sdesc->FirstContentByType(content_type);
}
-MediaSessionDescription* MediaSessionClient::CreateAcceptSessionDescription(
- const SessionDescription* offer) {
- const MediaSessionDescription* offer_desc =
- static_cast<const MediaSessionDescription*>(offer);
- MediaSessionDescription* accept_desc = new MediaSessionDescription();
-
- // add audio codecs
- std::vector<Codec> codecs;
- channel_manager_->GetSupportedCodecs(&codecs);
- for (unsigned int i = 0; i < offer_desc->voice().codecs().size(); ++i) {
- if (channel_manager_->FindCodec(offer_desc->voice().codecs()[i]))
- accept_desc->voice().AddCodec(offer_desc->voice().codecs()[i]);
+const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
+ return GetFirstMediaContent(sdesc, NS_GINGLE_AUDIO);
+}
+
+const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
+ return GetFirstMediaContent(sdesc, NS_GINGLE_VIDEO);
+}
+
+SessionDescription* MediaSessionClient::CreateAnswer(
+ const SessionDescription* offer) {
+ SessionDescription* accept = new SessionDescription();
+
+ const ContentInfo* audio_content = GetFirstAudioContent(offer);
+ if (audio_content) {
+ const AudioContentDescription* audio_offer =
+ static_cast<const AudioContentDescription*>(audio_content->description);
+ AudioContentDescription* audio_accept = new AudioContentDescription();
+ for (AudioCodecs::const_iterator codec = audio_offer->codecs().begin();
+ codec != audio_offer->codecs().end(); codec++) {
+ if (channel_manager_->FindAudioCodec(*codec)) {
+ audio_accept->AddCodec(*codec);
+ }
+ }
+ audio_accept->SortCodecs();
+ accept->AddContent(audio_content->name, audio_content->type, audio_accept);
}
- // add video codecs, if the incoming session description has them
- if (!offer_desc->video().codecs().empty()) {
- std::vector<VideoCodec> video_codecs;
- channel_manager_->GetSupportedVideoCodecs(&video_codecs);
- for (unsigned int i = 0; i < offer_desc->video().codecs().size(); ++i) {
- if (channel_manager_->FindVideoCodec(offer_desc->video().codecs()[i]))
- accept_desc->video().AddCodec(offer_desc->video().codecs()[i]);
+ const ContentInfo* video_content = GetFirstVideoContent(offer);
+ if (video_content) {
+ const VideoContentDescription* video_offer =
+ static_cast<const VideoContentDescription*>(video_content->description);
+ VideoContentDescription* video_accept = new VideoContentDescription();
+ for (VideoCodecs::const_iterator codec = video_offer->codecs().begin();
+ codec != video_offer->codecs().end(); codec++) {
+ if (channel_manager_->FindVideoCodec(*codec)) {
+ video_accept->AddCodec(*codec);
+ }
}
+ video_accept->SortCodecs();
+ accept->AddContent(video_content->name, video_content->type, video_accept);
}
- accept_desc->Sort();
- return accept_desc;
+ return accept;
}
Call *MediaSessionClient::CreateCall(bool video, bool mux) {
@@ -144,7 +184,7 @@ void MediaSessionClient::OnSessionCreate(Session *session,
if (received_initiate) {
session->SignalState.connect(this, &MediaSessionClient::OnSessionState);
- Call *call = CreateCall(session->session_type() == NS_GINGLE_VIDEO);
+ Call *call = CreateCall(session->content_type() == NS_GINGLE_VIDEO);
session_map_[session->id()] = call;
call->AddSession(session);
}
@@ -154,13 +194,16 @@ void MediaSessionClient::OnSessionState(BaseSession *session,
BaseSession::State state) {
if (state == Session::STATE_RECEIVEDINITIATE) {
// If our accept would have no codecs, then we must reject this call.
- MediaSessionDescription* accept_desc =
- CreateAcceptSessionDescription(session->remote_description());
- if (accept_desc->voice().codecs().size() == 0) {
+ SessionDescription* accept = CreateAnswer(session->remote_description());
+ const ContentInfo* audio_content = GetFirstAudioContent(accept);
+ const AudioContentDescription* audio_accept = (!audio_content) ? NULL :
+ static_cast<const AudioContentDescription*>(audio_content->description);
+
+ if (!audio_accept || audio_accept->codecs().size() == 0) {
// TODO(?): include an error description with the rejection.
session->Reject();
}
- delete accept_desc;
+ delete accept;
}
}
@@ -184,7 +227,7 @@ void MediaSessionClient::OnSessionDestroy(Session *session) {
// Find the call this session is in, remove it
std::map<SessionID, Call *>::iterator it = session_map_.find(session->id());
- assert(it != session_map_.end());
+ ASSERT(it != session_map_.end());
if (it != session_map_.end()) {
Call *call = (*it).second;
session_map_.erase(it);
@@ -226,7 +269,7 @@ Session *MediaSessionClient::CreateSession(Call *call) {
}
bool MediaSessionClient::ParseAudioCodec(const buzz::XmlElement* element,
- Codec* out) {
+ AudioCodec* out) {
int id = GetXmlAttr(element, QN_ID, -1);
if (id < 0)
return false;
@@ -235,7 +278,7 @@ bool MediaSessionClient::ParseAudioCodec(const buzz::XmlElement* element,
int clockrate = GetXmlAttr(element, QN_CLOCKRATE, 0);
int bitrate = GetXmlAttr(element, QN_BITRATE, 0);
int channels = GetXmlAttr(element, QN_CHANNELS, 1);
- *out = Codec(id, name, clockrate, bitrate, channels, 0);
+ *out = AudioCodec(id, name, clockrate, bitrate, channels, 0);
return true;
}
@@ -253,58 +296,63 @@ bool MediaSessionClient::ParseVideoCodec(const buzz::XmlElement* element,
return true;
}
-const FormatDescription* MediaSessionClient::ParseFormat(
- const buzz::XmlElement* element) {
- MediaSessionDescription* media = new MediaSessionDescription();
- // Includes payloads of unknown type (xmlns). We need to know they
- // are there so that we don't auto-add old codecs unless there are
- // really no payload types, even of unknown type.
- bool has_payload_types = false;
- for (const buzz::XmlElement* payload_type = element->FirstElement();
- payload_type != NULL;
- payload_type = payload_type->NextElement()) {
- has_payload_types = true;
- const std::string& name = payload_type->Name().LocalPart();
- if (name == QN_GINGLE_AUDIO_PAYLOADTYPE.LocalPart() ||
- name == QN_GINGLE_VIDEO_PAYLOADTYPE.LocalPart()) {
- if (payload_type->Name() == QN_GINGLE_AUDIO_PAYLOADTYPE) {
- Codec acodec;
- if (ParseAudioCodec(payload_type, &acodec)) {
- media->voice().AddCodec(acodec);
- }
- } else if (payload_type->Name() == QN_GINGLE_VIDEO_PAYLOADTYPE) {
- VideoCodec vcodec;
- if (ParseVideoCodec(payload_type, &vcodec)) {
- media->video().AddCodec(vcodec);
+bool MediaSessionClient::ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error) {
+ const std::string& content_type = elem->Name().Namespace();
+ if (NS_GINGLE_AUDIO == content_type) {
+ AudioContentDescription* audio = new AudioContentDescription();
+
+ if (elem->FirstElement()) {
+ for (const buzz::XmlElement* codec_elem =
+ elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE);
+ codec_elem != NULL;
+ codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) {
+ AudioCodec audio_codec;
+ if (ParseAudioCodec(codec_elem, &audio_codec)) {
+ audio->AddCodec(audio_codec);
}
}
+ } else {
+ // For backward compatibility, we can assume the other client is
+ // an old version of Talk if it has no audio payload types at all.
+ audio->AddCodec(AudioCodec(103, "ISAC", 16000, -1, 1, 1));
+ audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0));
}
- }
- if (!has_payload_types) {
- // For backward compatibility, we can assume the other client is
- // an old version of Talk if it has no audio payload types at all.
- media->voice().AddCodec(Codec(103, "ISAC", 16000, -1, 1, 1));
- media->voice().AddCodec(Codec(0, "PCMU", 8000, 64000, 1, 0));
- }
+ const buzz::XmlElement* src_id = elem->FirstNamed(QN_GINGLE_AUDIO_SRCID);
+ if (src_id) {
+ audio->set_ssrc(strtoul(src_id->BodyText().c_str(), NULL, 10));
+ }
- // get ssrcs, if present
- const buzz::XmlElement* src_id;
- src_id = element->FirstNamed(QN_GINGLE_AUDIO_SRCID);
- if (src_id) {
- media->voice().set_ssrc(strtoul(src_id->BodyText().c_str(),
- NULL, 10));
- }
- src_id = element->FirstNamed(QN_GINGLE_VIDEO_SRCID);
- if (src_id) {
- media->video().set_ssrc(strtoul(src_id->BodyText().c_str(),
- NULL, 10));
+ *content = audio;
+ } else if (NS_GINGLE_VIDEO == content_type) {
+ VideoContentDescription* video = new VideoContentDescription();
+
+ for (const buzz::XmlElement* codec_elem =
+ elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE);
+ codec_elem != NULL;
+ codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) {
+ VideoCodec video_codec;
+ if (ParseVideoCodec(codec_elem, &video_codec)) {
+ video->AddCodec(video_codec);
+ }
+ }
+
+ const buzz::XmlElement* src_id = elem->FirstNamed(QN_GINGLE_VIDEO_SRCID);
+ if (src_id) {
+ video->set_ssrc(strtoul(src_id->BodyText().c_str(), NULL, 10));
+ }
+
+ *content = video;
+ } else {
+ return BadParse("unknown media content type: " + content_type, error);
}
- return media;
+ return true;
}
-buzz::XmlElement* WriteAudioCodec(const Codec& codec) {
+buzz::XmlElement* WriteAudioCodec(const AudioCodec& codec) {
buzz::XmlElement* payload_type =
new buzz::XmlElement(QN_GINGLE_AUDIO_PAYLOADTYPE, true);
AddXmlAttr(payload_type, QN_ID, codec.id);
@@ -329,43 +377,54 @@ buzz::XmlElement* WriteVideoCodec(const VideoCodec& codec) {
return payload_type;
}
-buzz::XmlElement* MediaSessionClient::WriteFormat(
- const FormatDescription* untyped_format) {
- const MediaSessionDescription* media =
- static_cast<const MediaSessionDescription*>(untyped_format);
+bool MediaSessionClient::WriteContent(const ContentDescription* untyped_content,
+ buzz::XmlElement** elem,
+ WriteError* error) {
+ const MediaContentDescription* media =
+ static_cast<const MediaContentDescription*>(untyped_content);
+
+ buzz::XmlElement* content_elem;
+ if (media->type() == MEDIA_TYPE_AUDIO) {
+ const AudioContentDescription* audio =
+ static_cast<const AudioContentDescription*>(untyped_content);
+ content_elem = new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT, true);
+
+ for (AudioCodecs::const_iterator codec = audio->codecs().begin();
+ codec != audio->codecs().end(); codec++) {
+ content_elem->AddElement(WriteAudioCodec(*codec));
+ }
+ if (audio->ssrc_set()) {
+ buzz::XmlElement* src_id =
+ new buzz::XmlElement(QN_GINGLE_AUDIO_SRCID, true);
+ if (audio->ssrc()) {
+ SetXmlBody(src_id, audio->ssrc());
+ }
+ content_elem->AddElement(src_id);
+ }
- bool has_video_codecs = !media->video().codecs().empty();
- buzz::XmlElement* format_elem = new buzz::XmlElement(
- has_video_codecs ? QN_GINGLE_VIDEO_FORMAT
- : QN_GINGLE_AUDIO_FORMAT, true);
- for (size_t i = 0; i < media->voice().codecs().size(); ++i) {
- format_elem->AddElement(WriteAudioCodec(media->voice().codecs()[i]));
- }
- for (size_t i = 0; i < media->video().codecs().size(); ++i) {
- format_elem->AddElement(WriteVideoCodec(media->video().codecs()[i]));
- }
+ *elem = content_elem;
+ } else if (media->type() == MEDIA_TYPE_VIDEO) {
+ const VideoContentDescription* video =
+ static_cast<const VideoContentDescription*>(untyped_content);
+ content_elem = new buzz::XmlElement(QN_GINGLE_VIDEO_CONTENT, true);
- // Add ssrcs, if set.
- if (media->voice().ssrc_set()) {
- buzz::XmlElement* src_id =
- new buzz::XmlElement(QN_GINGLE_AUDIO_SRCID, true);
- if (media->voice().ssrc()) {
- SetXmlBody(src_id, media->voice().ssrc());
+ for (VideoCodecs::const_iterator codec = video->codecs().begin();
+ codec != video->codecs().end(); codec++) {
+ content_elem->AddElement(WriteVideoCodec(*codec));
}
- format_elem->AddElement(src_id);
- }
- if (has_video_codecs && media->video().ssrc_set()) {
- buzz::XmlElement* src_id =
- new buzz::XmlElement(QN_GINGLE_VIDEO_SRCID, true);
- if (media->video().ssrc()) {
- SetXmlBody(src_id, media->video().ssrc());
+ if (video->ssrc_set()) {
+ buzz::XmlElement* src_id =
+ new buzz::XmlElement(QN_GINGLE_VIDEO_SRCID, true);
+ if (video->ssrc()) {
+ SetXmlBody(src_id, video->ssrc());
+ }
+ content_elem->AddElement(src_id);
}
- format_elem->AddElement(src_id);
- }
-
- return format_elem;
+ *elem = content_elem;
+ }
+ return true;
}
} // namespace cricket
diff --git a/third_party/libjingle/source/talk/session/phone/mediasessionclient.h b/third_party/libjingle/source/talk/session/phone/mediasessionclient.h
index d55b3b0..246e58e 100644
--- a/third_party/libjingle/source/talk/session/phone/mediasessionclient.h
+++ b/third_party/libjingle/source/talk/session/phone/mediasessionclient.h
@@ -47,7 +47,9 @@
namespace cricket {
class Call;
-class MediaSessionDescription;
+class SessionDescription;
+typedef std::vector<AudioCodec> AudioCodecs;
+typedef std::vector<VideoCodec> VideoCodecs;
class MediaSessionClient: public SessionClient, public sigslot::has_slots<> {
public:
@@ -98,19 +100,22 @@ class MediaSessionClient: public SessionClient, public sigslot::has_slots<> {
sigslot::signal1<Call *> SignalCallDestroy;
sigslot::repeater0<> SignalDevicesChange;
- MediaSessionDescription* CreateOfferSessionDescription(bool video = false);
- MediaSessionDescription* CreateAcceptSessionDescription(
- const SessionDescription* offer);
+ SessionDescription* CreateOffer(bool video = false, bool set_ssrc = false);
+ SessionDescription* CreateAnswer(const SessionDescription* offer);
private:
void Construct();
void OnSessionCreate(Session *session, bool received_initiate);
void OnSessionState(BaseSession *session, BaseSession::State state);
void OnSessionDestroy(Session *session);
- virtual const FormatDescription* ParseFormat(const buzz::XmlElement* element);
- virtual buzz::XmlElement* WriteFormat(const FormatDescription* format);
+ virtual bool ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error);
+ virtual bool WriteContent(const ContentDescription* content,
+ buzz::XmlElement** elem,
+ WriteError* error);
Session *CreateSession(Call *call);
- static bool ParseAudioCodec(const buzz::XmlElement* element, Codec* out);
+ static bool ParseAudioCodec(const buzz::XmlElement* element, AudioCodec* out);
static bool ParseVideoCodec(const buzz::XmlElement* element, VideoCodec* out);
@@ -125,88 +130,87 @@ class MediaSessionClient: public SessionClient, public sigslot::has_slots<> {
friend class Call;
};
-// Parameters for a voice and/or video session.
-class MediaSessionDescription : public SessionDescription {
+enum MediaType {
+ MEDIA_TYPE_AUDIO,
+ MEDIA_TYPE_VIDEO
+};
+
+class MediaContentDescription : public ContentDescription {
public:
- // Base class with common options.
- struct Content {
- Content() : ssrc_(0), ssrc_set_(false), rtcp_mux_(false),
- rtp_headers_disabled_(false) {}
-
- uint32 ssrc() const { return ssrc_; }
- bool ssrc_set() const { return ssrc_set_; }
- void set_ssrc(uint32 ssrc) {
- ssrc_ = ssrc;
- ssrc_set_ = true;
- }
-
- bool rtcp_mux() const { return rtcp_mux_; }
- void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; }
-
- bool rtp_headers_disabled() const {
- return rtp_headers_disabled_;
- }
- void set_rtp_headers_disabled(bool disable) {
- rtp_headers_disabled_ = disable;
- }
-
- const std::vector<CryptoParams>& cryptos() const { return cryptos_; }
- void AddCrypto(const CryptoParams& params) {
- cryptos_.push_back(params);
- }
-
- template <class T> struct PreferenceSort {
- bool operator()(T a, T b) { return a.preference > b.preference; }
- };
-
- uint32 ssrc_;
- bool ssrc_set_;
- bool rtcp_mux_;
- bool rtp_headers_disabled_;
- std::vector<CryptoParams> cryptos_;
- };
- // Voice-specific options.
- struct VoiceContent : public Content {
- const std::vector<Codec>& codecs() const { return codecs_; }
- void AddCodec(const Codec& codec) {
- codecs_.push_back(codec);
- }
- void SortCodecs() {
- std::sort(codecs_.begin(), codecs_.end(), PreferenceSort<Codec>());
- }
- std::vector<Codec> codecs_;
- };
- // Video-specific options.
- struct VideoContent : public Content {
- const std::vector<VideoCodec>& codecs() const { return codecs_; }
- void AddCodec(const VideoCodec& codec) {
- codecs_.push_back(codec);
- }
- void SortCodecs() {
- std::sort(codecs_.begin(), codecs_.end(), PreferenceSort<VideoCodec>());
- }
- std::vector<VideoCodec> codecs_;
- };
+ MediaContentDescription() : ssrc_(0), ssrc_set_(false), rtcp_mux_(false),
+ rtp_headers_disabled_(false) {}
- const VoiceContent& voice() const { return voice_; }
- VoiceContent& voice() { return voice_; }
- const VideoContent& video() const { return video_; }
- VideoContent& video() { return video_; }
+ virtual MediaType type() const = 0;
- void Sort() {
- voice_.SortCodecs();
- video_.SortCodecs();
+ uint32 ssrc() const { return ssrc_; }
+ bool ssrc_set() const { return ssrc_set_; }
+ void set_ssrc(uint32 ssrc) {
+ ssrc_ = ssrc;
+ ssrc_set_ = true;
}
+ bool rtcp_mux() const { return rtcp_mux_; }
+ void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; }
+
+ bool rtp_headers_disabled() const {
+ return rtp_headers_disabled_;
+ }
+ void set_rtp_headers_disabled(bool disable) {
+ rtp_headers_disabled_ = disable;
+ }
+
+ const std::vector<CryptoParams>& cryptos() const { return cryptos_; }
+ void AddCrypto(const CryptoParams& params) {
+ cryptos_.push_back(params);
+ }
+
+ uint32 ssrc_;
+ bool ssrc_set_;
+ bool rtcp_mux_;
+ bool rtp_headers_disabled_;
+ std::vector<CryptoParams> cryptos_;
+};
+
+template <class C>
+class MediaContentDescriptionImpl : public MediaContentDescription {
+ public:
+ struct PreferenceSort {
+ bool operator()(C a, C b) { return a.preference > b.preference; }
+ };
+
+ const std::vector<C>& codecs() const { return codecs_; }
+ void AddCodec(const C& codec) {
+ codecs_.push_back(codec);
+ }
+ void SortCodecs() {
+ std::sort(codecs_.begin(), codecs_.end(), PreferenceSort());
+ }
+
+ private:
+ std::vector<C> codecs_;
+};
+
+class AudioContentDescription : public MediaContentDescriptionImpl<AudioCodec> {
+ public:
+ virtual MediaType type() const { return MEDIA_TYPE_AUDIO; }
+
const std::string &lang() const { return lang_; }
void set_lang(const std::string &lang) { lang_ = lang; }
private:
- VoiceContent voice_;
- VideoContent video_;
std::string lang_;
};
+class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> {
+ public:
+ virtual MediaType type() const { return MEDIA_TYPE_VIDEO; }
+};
+
+// Convenience functions.
+const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc);
+const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc);
+
+
} // namespace cricket
#endif // TALK_SESSION_PHONE_MEDIASESSIONCLIENT_H_
diff --git a/third_party/libjingle/source/talk/session/phone/srtpfilter.cc b/third_party/libjingle/source/talk/session/phone/srtpfilter.cc
index cbe5c17..2770281 100644
--- a/third_party/libjingle/source/talk/session/phone/srtpfilter.cc
+++ b/third_party/libjingle/source/talk/session/phone/srtpfilter.cc
@@ -35,7 +35,7 @@
#include "talk/base/base64.h"
#include "talk/base/logging.h"
-// TODO(juberti):For the XCode build, we force SRTP (b/2500074)
+// TODO(juberti): For the XCode build, we force SRTP (b/2500074)
#if defined(OSX) && !defined(HAVE_SRTP)
#define HAVE_SRTP 1
#endif
@@ -44,7 +44,11 @@
// #define SRTP_DEBUG
#ifdef HAVE_SRTP
+#ifdef SRTP_RELATIVE_PATH
+#include "srtp.h" // NOLINT
+#else
#include "third_party/libsrtp/include/srtp.h"
+#endif // SRTP_RELATIVE_PATH
#ifdef _DEBUG
extern "C" debug_module_t mod_srtp;
#endif
@@ -70,7 +74,7 @@ bool SrtpFilter::IsActive() const {
}
bool SrtpFilter::SetOffer(const std::vector<CryptoParams>& offer_params,
- DescriptionSource source) {
+ ContentSource source) {
bool ret = false;
if (state_ == ST_INIT) {
ret = StoreParams(offer_params, source);
@@ -81,10 +85,10 @@ bool SrtpFilter::SetOffer(const std::vector<CryptoParams>& offer_params,
}
bool SrtpFilter::SetAnswer(const std::vector<CryptoParams>& answer_params,
- DescriptionSource source) {
+ ContentSource source) {
bool ret = false;
- if ((state_ == ST_SENTOFFER && source == DS_REMOTE) ||
- (state_ == ST_RECEIVEDOFFER && source == DS_LOCAL)) {
+ if ((state_ == ST_SENTOFFER && source == CS_REMOTE) ||
+ (state_ == ST_RECEIVEDOFFER && source == CS_LOCAL)) {
// If the answer requests crypto, finalize the parameters and apply them.
// Otherwise, complete the negotiation of a unencrypted session.
if (!answer_params.empty()) {
@@ -136,9 +140,9 @@ bool SrtpFilter::UnprotectRtcp(void* p, int in_len, int* out_len) {
bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params,
- DescriptionSource source) {
+ ContentSource source) {
offer_params_ = params;
- state_ = (source == DS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
+ state_ = (source == CS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
return true;
}
@@ -408,11 +412,13 @@ bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
return SrtpNotAvailable(__FUNCTION__);
}
-bool SrtpSession::ProtectRtp(void* data, int in_len, int max_len, int* out_len) {
+bool SrtpSession::ProtectRtp(void* data, int in_len, int max_len,
+ int* out_len) {
return SrtpNotAvailable(__FUNCTION__);
}
-bool SrtpSession::ProtectRtcp(void* data, int in_len, int max_len, int* out_len) {
+bool SrtpSession::ProtectRtcp(void* data, int in_len, int max_len,
+ int* out_len) {
return SrtpNotAvailable(__FUNCTION__);
}
diff --git a/third_party/libjingle/source/talk/session/phone/srtpfilter.h b/third_party/libjingle/source/talk/session/phone/srtpfilter.h
index 292ccb6..032c112 100644
--- a/third_party/libjingle/source/talk/session/phone/srtpfilter.h
+++ b/third_party/libjingle/source/talk/session/phone/srtpfilter.h
@@ -104,14 +104,14 @@ class SrtpFilter {
// offer_params should contain a list of available parameters to use, or none,
// if crypto is not desired. This must be called before SetAnswer.
bool SetOffer(const std::vector<CryptoParams>& offer_params,
- DescriptionSource source);
+ ContentSource source);
// Indicates which crypto algorithms and keys were contained in the answer.
// answer_params should contain the negotiated parameters, which may be none,
// if crypto was not desired or could not be negotiated (and not required).
// This must be called after SetOffer. If crypto negotiation completes
// successfully, this will advance the filter to the active state.
bool SetAnswer(const std::vector<CryptoParams>& answer_params,
- DescriptionSource source);
+ ContentSource source);
// Encrypts/signs an individual RTP/RTCP packet, in-place.
// If an HMAC is used, this will increase the packet size.
@@ -124,7 +124,7 @@ class SrtpFilter {
protected:
bool StoreParams(const std::vector<CryptoParams>& offer_params,
- DescriptionSource source);
+ ContentSource source);
bool NegotiateParams(const std::vector<CryptoParams>& answer_params,
CryptoParams* selected_params);
bool ApplyParams(const CryptoParams& send_params,
diff --git a/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc b/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc
index 0e4f0c1..2ac23f0 100644
--- a/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc
+++ b/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.cc
@@ -42,8 +42,7 @@
namespace cricket {
-// XML elements and namespaces for XMPP stanzas used in session
-// description exchanges.
+// XML elements and namespaces for XMPP stanzas used in content exchanges.
const std::string NS_SECURE_TUNNEL("http://www.google.com/talk/securetunnel");
const buzz::QName QN_SECURE_TUNNEL_DESCRIPTION(NS_SECURE_TUNNEL,
@@ -53,18 +52,19 @@ const buzz::QName QN_SECURE_TUNNEL_CLIENT_CERT(NS_SECURE_TUNNEL,
"client-cert");
const buzz::QName QN_SECURE_TUNNEL_SERVER_CERT(NS_SECURE_TUNNEL,
"server-cert");
+const std::string CN_SECURE_TUNNEL("securetunnel");
-// SecureTunnelSessionDescription
+// SecureTunnelContentDescription
-// TunnelSessionDescription is extended to hold string forms of the
+// TunnelContentDescription is extended to hold string forms of the
// client and server certificate, PEM encoded.
-struct SecureTunnelSessionDescription : public SessionDescription {
+struct SecureTunnelContentDescription : public ContentDescription {
std::string description;
std::string client_pem_certificate;
std::string server_pem_certificate;
- SecureTunnelSessionDescription(const std::string& desc,
+ SecureTunnelContentDescription(const std::string& desc,
const std::string& client_pem_cert,
const std::string& server_pem_cert)
: description(desc),
@@ -129,14 +129,25 @@ TunnelSession* SecureTunnelSessionClient::MakeTunnelSession(
return new SecureTunnelSession(this, session, stream_thread, role);
}
+const SecureTunnelContentDescription* FindSecureTunnelContent(
+ const cricket::SessionDescription* sdesc) {
+ const ContentInfo* cinfo = sdesc->FirstContentByType(NS_SECURE_TUNNEL);
+ if (cinfo == NULL)
+ return NULL;
+
+ return static_cast<const SecureTunnelContentDescription*>(
+ cinfo->description);
+}
+
void SecureTunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
Session *session) {
- const SecureTunnelSessionDescription *desc =
- static_cast<const SecureTunnelSessionDescription*>(
- session->remote_description());
+ const SecureTunnelContentDescription* content =
+ FindSecureTunnelContent(session->remote_description());
+ ASSERT(content != NULL);
+
// Validate the certificate
talk_base::scoped_ptr<talk_base::SSLCertificate> peer_cert(
- ParseCertificate(desc->client_pem_certificate));
+ ParseCertificate(content->client_pem_certificate));
if (peer_cert.get() == NULL) {
LOG(LS_ERROR)
<< "Rejecting incoming secure tunnel with invalid cetificate";
@@ -146,11 +157,11 @@ void SecureTunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
// If there were a convenient place we could have cached the
// peer_cert so as not to have to parse it a second time when
// configuring the tunnel.
- SignalIncomingTunnel(this, jid, desc->description, session);
+ SignalIncomingTunnel(this, jid, content->description, session);
}
// The XML representation of a session initiation request (XMPP IQ),
-// containing the initiator's SecureTunnelSessionDescription,
+// containing the initiator's SecureTunnelContentDescription,
// looks something like this:
// <iq from="INITIATOR@gmail.com/pcpE101B7F4"
// to="RECIPIENT@gmail.com/pcp8B87F0A3"
@@ -194,84 +205,91 @@ void SecureTunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
// </session>
// </iq>
-// The below methods deal with the <description> component.
-const SessionDescription* SecureTunnelSessionClient::CreateSessionDescription(
- const buzz::XmlElement* element) {
- // Parse the XML representation of a SecureSessionDescription. See
- // example above.
- const buzz::XmlElement* type_elem =
- element->FirstNamed(QN_SECURE_TUNNEL_TYPE);
+bool SecureTunnelSessionClient::ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error) {
+ const buzz::XmlElement* type_elem = elem->FirstNamed(QN_SECURE_TUNNEL_TYPE);
+
if (type_elem == NULL)
// Missing mandatory XML element.
- return NULL;
+ return false;
+
// Here we consider the certificate components to be optional. In
// practice the client certificate is always present, and the server
// certificate is initially missing from the session description
// sent during session initiation. OnAccept() will enforce that we
// have a certificate for our peer.
const buzz::XmlElement* client_cert_elem =
- element->FirstNamed(QN_SECURE_TUNNEL_CLIENT_CERT);
+ elem->FirstNamed(QN_SECURE_TUNNEL_CLIENT_CERT);
const buzz::XmlElement* server_cert_elem =
- element->FirstNamed(QN_SECURE_TUNNEL_SERVER_CERT);
- return new SecureTunnelSessionDescription(
+ elem->FirstNamed(QN_SECURE_TUNNEL_SERVER_CERT);
+ *content = new SecureTunnelContentDescription(
type_elem->BodyText(),
client_cert_elem ? client_cert_elem->BodyText() : "",
server_cert_elem ? server_cert_elem->BodyText() : "");
+ return true;
}
-buzz::XmlElement* SecureTunnelSessionClient::TranslateSessionDescription(
- const SessionDescription* description) {
- // Generate an XML representation of a SecureSessionDescription. See
- // example above.
- const SecureTunnelSessionDescription* desc =
- static_cast<const SecureTunnelSessionDescription*>(description);
+bool SecureTunnelSessionClient::WriteContent(
+ const ContentDescription* untyped_content,
+ buzz::XmlElement** elem, WriteError* error) {
+ const SecureTunnelContentDescription* content =
+ static_cast<const SecureTunnelContentDescription*>(untyped_content);
+
buzz::XmlElement* root =
new buzz::XmlElement(QN_SECURE_TUNNEL_DESCRIPTION, true);
buzz::XmlElement* type_elem = new buzz::XmlElement(QN_SECURE_TUNNEL_TYPE);
- type_elem->SetBodyText(desc->description);
+ type_elem->SetBodyText(content->description);
root->AddElement(type_elem);
- if (!desc->client_pem_certificate.empty()) {
+ if (!content->client_pem_certificate.empty()) {
buzz::XmlElement* client_cert_elem =
new buzz::XmlElement(QN_SECURE_TUNNEL_CLIENT_CERT);
- client_cert_elem->SetBodyText(desc->client_pem_certificate);
+ client_cert_elem->SetBodyText(content->client_pem_certificate);
root->AddElement(client_cert_elem);
}
- if (!desc->server_pem_certificate.empty()) {
+ if (!content->server_pem_certificate.empty()) {
buzz::XmlElement* server_cert_elem =
new buzz::XmlElement(QN_SECURE_TUNNEL_SERVER_CERT);
- server_cert_elem->SetBodyText(desc->server_pem_certificate);
+ server_cert_elem->SetBodyText(content->server_pem_certificate);
root->AddElement(server_cert_elem);
}
- return root;
+ *elem = root;
+ return true;
+}
+
+SessionDescription* NewSecureTunnelSessionDescription(
+ const ContentDescription* content) {
+ SessionDescription* sdesc = new SessionDescription();
+ sdesc->AddContent(CN_SECURE_TUNNEL, NS_SECURE_TUNNEL, content);
+ return sdesc;
}
-// Makes up a secure session description to be sent out when
-// initiating a session.
-SessionDescription*
-SecureTunnelSessionClient::CreateOutgoingSessionDescription(
+SessionDescription* SecureTunnelSessionClient::CreateOffer(
const buzz::Jid &jid, const std::string &description) {
// We are the initiator so we are the client. Put our cert into the
// description.
std::string pem_cert = GetIdentity().certificate().ToPEMString();
- return new SecureTunnelSessionDescription(description, pem_cert, "");
+ return NewSecureTunnelSessionDescription(
+ new SecureTunnelContentDescription(description, pem_cert, ""));
}
-// Makes up a secure session description to be sent out when accepting
-// a session request.
-SessionDescription*
-SecureTunnelSessionClient::CreateOutgoingSessionDescription(Session *session) {
- const SecureTunnelSessionDescription* in_desc =
- static_cast<const SecureTunnelSessionDescription*>(
- session->remote_description());
+SessionDescription* SecureTunnelSessionClient::CreateAnswer(
+ const SessionDescription* offer) {
+ const SecureTunnelContentDescription* offer_tunnel =
+ FindSecureTunnelContent(offer);
+ if (offer_tunnel == NULL)
+ return NULL;
+
// We are accepting a session request. We need to add our cert, the
// server cert, into the description. The client cert was validated
// in OnIncomingTunnel().
- ASSERT(!in_desc->client_pem_certificate.empty());
- return new SecureTunnelSessionDescription(
- in_desc->description,
- in_desc->client_pem_certificate,
- GetIdentity().certificate().ToPEMString());
+ ASSERT(!offer_tunnel->client_pem_certificate.empty());
+ return NewSecureTunnelSessionDescription(
+ new SecureTunnelContentDescription(
+ offer_tunnel->description,
+ offer_tunnel->client_pem_certificate,
+ GetIdentity().certificate().ToPEMString()));
}
// SecureTunnelSession
@@ -318,12 +336,13 @@ void SecureTunnelSession::OnAccept() {
// connect the tunnel. First we must set the peer certificate.
ASSERT(channel_ != NULL);
ASSERT(session_ != NULL);
- const SecureTunnelSessionDescription* remote_desc =
- static_cast<const SecureTunnelSessionDescription*>
- (session_->remote_description());
+ const SecureTunnelContentDescription* remote_tunnel =
+ FindSecureTunnelContent(session_->remote_description());
+ ASSERT(remote_tunnel != NULL);
+
const std::string& cert_pem =
- role_ == INITIATOR ? remote_desc->server_pem_certificate :
- remote_desc->client_pem_certificate;
+ role_ == INITIATOR ? remote_tunnel->server_pem_certificate :
+ remote_tunnel->client_pem_certificate;
talk_base::SSLCertificate* peer_cert =
ParseCertificate(cert_pem);
if (peer_cert == NULL) {
diff --git a/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.h b/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.h
index 234e4bb..6b0abd7 100644
--- a/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.h
+++ b/third_party/libjingle/source/talk/session/tunnel/securetunnelsessionclient.h
@@ -50,7 +50,7 @@ class SecureTunnelSession; // below
// SSL/TLS. The PseudoTcpChannel stream is wrapped with an
// SSLStreamAdapter. An SSLIdentity must be set or generated.
//
-// The TunnelSessionDescription is extended to include the client and
+// The TunnelContentDescription is extended to include the client and
// server certificates. The initiator acts as the client. The session
// initiate stanza carries a description that contains the client's
// certificate, and the session accept response's description has the
@@ -81,14 +81,16 @@ class SecureTunnelSessionClient : public TunnelSessionClient {
// Inherited methods
virtual void OnIncomingTunnel(const buzz::Jid& jid, Session *session);
- virtual const SessionDescription* CreateSessionDescription(
- const buzz::XmlElement* element);
- virtual buzz::XmlElement* TranslateSessionDescription(
- const SessionDescription* description);
- virtual SessionDescription *CreateOutgoingSessionDescription(
+ virtual bool ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error);
+ virtual bool WriteContent(const ContentDescription* content,
+ buzz::XmlElement** elem,
+ WriteError* error);
+ virtual SessionDescription* CreateOffer(
const buzz::Jid &jid, const std::string &description);
- virtual SessionDescription *CreateOutgoingSessionDescription(
- Session *incoming);
+ virtual SessionDescription* CreateAnswer(
+ const SessionDescription* offer);
protected:
virtual TunnelSession* MakeTunnelSession(
@@ -140,7 +142,7 @@ class SecureTunnelSession : public TunnelSession {
// Our role in requesting the tunnel: INITIATOR or
// RESPONDER. Translates to our role in SSL negotiation:
// respectively client or server. Also indicates which slot of the
- // SecureTunnelSessionDescription our cert goes into: client-cert or
+ // SecureTunnelContentDescription our cert goes into: client-cert or
// server-cert respectively.
TunnelSessionRole role_;
diff --git a/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.cc b/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.cc
index 2dc9705..facb08b 100644
--- a/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.cc
+++ b/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.cc
@@ -41,6 +41,7 @@ namespace cricket {
const std::string NS_TUNNEL("http://www.google.com/talk/tunnel");
const buzz::QName QN_TUNNEL_DESCRIPTION(NS_TUNNEL, "description");
const buzz::QName QN_TUNNEL_TYPE(NS_TUNNEL, "type");
+const std::string CN_TUNNEL("tunnel");
enum {
MSG_CLOCK = 1,
@@ -83,13 +84,13 @@ const talk_base::ConstantLabel SESSION_STATES[] = {
};
///////////////////////////////////////////////////////////////////////////////
-// TunnelSessionDescription
+// TunnelContentDescription
///////////////////////////////////////////////////////////////////////////////
-struct TunnelSessionDescription : public SessionDescription {
+struct TunnelContentDescription : public ContentDescription {
std::string description;
- TunnelSessionDescription(const std::string& desc) : description(desc) { }
+ TunnelContentDescription(const std::string& desc) : description(desc) { }
};
///////////////////////////////////////////////////////////////////////////////
@@ -163,7 +164,11 @@ talk_base::StreamInterface* TunnelSessionClientBase::AcceptTunnel(
}
ASSERT(tunnel != NULL);
- session->Accept(CreateOutgoingSessionDescription(session));
+ SessionDescription* answer = CreateAnswer(session->remote_description());
+ if (answer == NULL)
+ return NULL;
+
+ session->Accept(answer);
return tunnel->GetStream();
}
@@ -180,9 +185,8 @@ void TunnelSessionClientBase::OnMessage(talk_base::Message* pmsg) {
TunnelSession* tunnel = MakeTunnelSession(session, data->thread,
INITIATOR);
sessions_.push_back(tunnel);
- SessionDescription *desc =
- CreateOutgoingSessionDescription(data->jid, data->description);
- session->Initiate(data->jid.Str(), desc);
+ SessionDescription* offer = CreateOffer(data->jid, data->description);
+ session->Initiate(data->jid.Str(), offer);
data->stream = tunnel->GetStream();
}
}
@@ -211,49 +215,71 @@ TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid,
TunnelSessionClient::~TunnelSessionClient() {
}
-const SessionDescription* TunnelSessionClient::CreateSessionDescription(
- const buzz::XmlElement* element) {
- if (const buzz::XmlElement* type_elem = element->FirstNamed(QN_TUNNEL_TYPE)) {
- return new TunnelSessionDescription(type_elem->BodyText());
+
+bool TunnelSessionClient::ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error) {
+ if (const buzz::XmlElement* type_elem = elem->FirstNamed(QN_TUNNEL_TYPE)) {
+ *content = new TunnelContentDescription(type_elem->BodyText());
+ return true;
}
- ASSERT(false);
- return 0;
+ return false;
}
-buzz::XmlElement* TunnelSessionClient::TranslateSessionDescription(
- const SessionDescription* description) {
- const TunnelSessionDescription* desc =
- static_cast<const TunnelSessionDescription*>(description);
+bool TunnelSessionClient::WriteContent(
+ const ContentDescription* untyped_content,
+ buzz::XmlElement** elem, WriteError* error) {
+ const TunnelContentDescription* content =
+ static_cast<const TunnelContentDescription*>(untyped_content);
buzz::XmlElement* root = new buzz::XmlElement(QN_TUNNEL_DESCRIPTION, true);
buzz::XmlElement* type_elem = new buzz::XmlElement(QN_TUNNEL_TYPE);
- type_elem->SetBodyText(desc->description);
+ type_elem->SetBodyText(content->description);
root->AddElement(type_elem);
- return root;
+ *elem = root;
+ return true;
}
-void TunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
+SessionDescription* NewTunnelSessionDescription(
+ const ContentDescription* content) {
+ SessionDescription* sdesc = new SessionDescription();
+ sdesc->AddContent(CN_TUNNEL, NS_TUNNEL, content);
+ return sdesc;
+}
+
+const TunnelContentDescription* FindTunnelContent(
+ const cricket::SessionDescription* sdesc) {
+ const ContentInfo* cinfo = sdesc->FirstContentByType(NS_TUNNEL);
+ if (cinfo == NULL)
+ return NULL;
+
+ return static_cast<const TunnelContentDescription*>(
+ cinfo->description);
+}
+
+void TunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid,
Session *session) {
- const TunnelSessionDescription *desc =
- static_cast<const TunnelSessionDescription*>(session->remote_description());
+ const TunnelContentDescription* content = FindTunnelContent(
+ session->remote_description());
+ ASSERT(content != NULL);
- SignalIncomingTunnel(this, jid, desc->description, session);
+ SignalIncomingTunnel(this, jid, content->description, session);
}
-SessionDescription *TunnelSessionClient::CreateOutgoingSessionDescription(
+SessionDescription* TunnelSessionClient::CreateOffer(
const buzz::Jid &jid, const std::string &description) {
- return new TunnelSessionDescription(description);
+ return NewTunnelSessionDescription(
+ new TunnelContentDescription(description));
}
-SessionDescription *TunnelSessionClient::CreateOutgoingSessionDescription(
- Session *session) {
- const TunnelSessionDescription* in_desc =
- static_cast<const TunnelSessionDescription*>(
- session->remote_description());
- TunnelSessionDescription* out_desc = new TunnelSessionDescription(
- in_desc->description);
+SessionDescription* TunnelSessionClient::CreateAnswer(
+ const SessionDescription* offer) {
+ const TunnelContentDescription* offer_tunnel = FindTunnelContent(offer);
+ if (offer_tunnel == NULL)
+ return NULL;
- return out_desc;
+ return NewTunnelSessionDescription(
+ new TunnelContentDescription(offer_tunnel->description));
}
///////////////////////////////////////////////////////////////////////////////
// TunnelSession
diff --git a/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h b/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h
index 2671458..6746ced 100644
--- a/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h
+++ b/third_party/libjingle/source/talk/session/tunnel/tunnelsessionclient.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2008, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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. The name of the author may not be used to endorse or promote products
+ * 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * 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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -54,7 +54,7 @@ enum TunnelSessionRole { INITIATOR, RESPONDER };
class TunnelSessionClientBase
: public SessionClient, public talk_base::MessageHandler {
public:
- TunnelSessionClientBase(const buzz::Jid& jid, SessionManager* manager,
+ TunnelSessionClientBase(const buzz::Jid& jid, SessionManager* manager,
const std::string &ns);
virtual ~TunnelSessionClientBase();
@@ -77,12 +77,12 @@ public:
virtual void OnIncomingTunnel(const buzz::Jid &jid, Session *session) = 0;
// Invoked on an outgoing session request
- virtual SessionDescription *CreateOutgoingSessionDescription(
- const buzz::Jid &jid, const std::string &description) = 0;
- // Invoked on a session request accept to create
+ virtual SessionDescription* CreateOffer(
+ const buzz::Jid &jid, const std::string &description) = 0;
+ // Invoked on a session request accept to create
// the local-side session description
- virtual SessionDescription *CreateOutgoingSessionDescription(
- Session *incoming) = 0;
+ virtual SessionDescription* CreateAnswer(
+ const SessionDescription* offer) = 0;
protected:
@@ -102,7 +102,7 @@ protected:
bool shutdown_;
};
-class TunnelSessionClient
+class TunnelSessionClient
: public TunnelSessionClientBase, public sigslot::has_slots<> {
public:
TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager);
@@ -110,21 +110,23 @@ public:
const std::string &ns);
virtual ~TunnelSessionClient();
- virtual const SessionDescription* CreateSessionDescription(
- const buzz::XmlElement* element);
- virtual buzz::XmlElement* TranslateSessionDescription(
- const SessionDescription* description);
+ virtual bool ParseContent(const buzz::XmlElement* elem,
+ const ContentDescription** content,
+ ParseError* error);
+ virtual bool WriteContent(const ContentDescription* content,
+ buzz::XmlElement** elem,
+ WriteError* error);
// Signal arguments are this, initiator, description, session
sigslot::signal4<TunnelSessionClient*, buzz::Jid, std::string, Session*>
SignalIncomingTunnel;
- virtual void OnIncomingTunnel(const buzz::Jid &jid,
+ virtual void OnIncomingTunnel(const buzz::Jid &jid,
Session *session);
- virtual SessionDescription *CreateOutgoingSessionDescription(
- const buzz::Jid &jid, const std::string &description);
- virtual SessionDescription *CreateOutgoingSessionDescription(
- Session *incoming);
+ virtual SessionDescription* CreateOffer(
+ const buzz::Jid &jid, const std::string &description);
+ virtual SessionDescription* CreateAnswer(
+ const SessionDescription* offer);
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/libjingle/source/talk/site_scons/talk.py b/third_party/libjingle/source/talk/site_scons/talk.py
index b984415..50cff66 100644
--- a/third_party/libjingle/source/talk/site_scons/talk.py
+++ b/third_party/libjingle/source/talk/site_scons/talk.py
@@ -105,6 +105,16 @@ def App(env, **kwargs):
params = kwargs
return ExtendComponent(env, env.ComponentProgram, **params)
+def WiX(env, **kwargs):
+ """ Extends the WiX builder
+ Args:
+ env: The current environment.
+ kwargs: The keyword arguments.
+
+ Returns:
+ The node produced by the environment's wix builder
+ """
+ return ExtendComponent(env, env.WiX, **kwargs)
def Repository(env, at, path):
"""Maps a directory external to $MAIN_DIR to the given path so that sources
@@ -217,6 +227,7 @@ def AddMediaLibs(env, **kwargs):
'LmiSignaling',
'LmiStun',
'LmiTransport',
+ 'LmiUi',
'LmiUtils',
'LmiVideoCommon',
'LmiXml',
@@ -232,11 +243,13 @@ def AddMediaLibs(env, **kwargs):
if env.Bit('windows'):
AddToDict(kwargs, 'libs', [
+ 'dsound',
+ 'd3d9',
+ 'gdi32',
'ippcorel',
'ippscmerged',
'ippscemerged',
'strmiids',
- 'dsound',
])
else:
AddToDict(kwargs, 'libs', [
@@ -356,9 +369,36 @@ def MergeAndFilterByPlatform(env, params):
def ExtendComponent(env, component, **kwargs):
+ """A wrapper around a scons builder function that preprocesses and post-
+ processes its inputs and outputs. For example, it merges and filters
+ fields based on platform and build mode, factors out common includes,
+ and can make a digitally signed copy of the output.
+
+ Why do we build everything up in to the params dict and pass explicitly
+ to component? We've just always done it that way? It's probably more
+ conventional to clone env, append or prepend in to env's existing
+ construction variables, then call component(srcs, target) without any extra
+ paremters. Both methods ensure settings from one target don't leak back in
+ to the original env polluting later targets.
+
+ Args:
+ env: The hammer environment with which to build the target
+ component: The environment's builder function, e.g. ComponentProgram
+ kwargs: keyword arguments that are either merged, translated, and passed on
+ to the call to component, or which control execution.
+ TODO(): Document the fields, such as cppdefines->CPPDEFINES,
+ prepend_includedirs, include_talk_media_libs, etc.
+ Returns:
+ The output node returned by the call to component, or a subsequent signed
+ dependant node.
+ """
+
# get our target identifier
name = GetEntry(kwargs, 'name')
- log_env = GetEntry(kwargs, 'dump')
+
+ signed = env.Bit('windows') and kwargs.has_key('signed') and kwargs['signed']
+ if signed:
+ name = 'unsigned_' + name
if (kwargs.has_key('include_talk_media_libs') and
kwargs['include_talk_media_libs']):
@@ -394,7 +434,21 @@ def ExtendComponent(env, component, **kwargs):
return None
# invoke the builder function
- return component(name, srcs, **params)
+ node = component(name, srcs, **params)
+
+ if signed:
+ # Get the name of the built binary, then get the name of the final signed
+ # version from it. We need the output path since we don't know the file
+ # extension beforehand.
+ target = node[0].path.split('_', 1)[1]
+ signed_node = env.SignedBinary(
+ source = node,
+ target = '$STAGING_DIR/' + target,
+ )
+ env.Alias('signed_binaries', signed_node)
+ return signed
+ else:
+ return node
def AddToDict(dictionary, key, values, append=True):
diff --git a/third_party/libjingle/source/talk/third_party/gipslite/Interface/GipsVoiceEngineLite.h b/third_party/libjingle/source/talk/third_party/gipslite/Interface/GipsVoiceEngineLite.h
deleted file mode 100644
index 29b6a7a..0000000
--- a/third_party/libjingle/source/talk/third_party/gipslite/Interface/GipsVoiceEngineLite.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// GipsVoiceEngineLib.h
-//
-//////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////
-//
-// Created by: Fredrik Galschiödt
-// Date : 011202
-//
-// $Change$
-//
-// Public API for GIPS Voice Engine on a PC platform.
-//
-// Copyright (c) 2001
-// Global IP Sound AB, Organization number: 5565739017
-// Rosenlundsgatan 54, SE-118 63 Stockholm, Sweden
-// All rights reserved.
-//
-//////////////////////////////////////////////////////////////////////
-
-#ifndef PUBLIC_GIPS_VOICE_ENGINE_LITE_H
-#define PUBLIC_GIPS_VOICE_ENGINE_LITE_H
-
-#include "GIPS_common_types.h"
-
-#ifdef GIPS_EXPORT
-#define VOICEENGINE_DLLEXPORT _declspec(dllexport)
-#elif GIPS_DLL
-#define VOICEENGINE_DLLEXPORT _declspec(dllimport)
-#else
-#define VOICEENGINE_DLLEXPORT
-#endif
-
-
-//////////////////////////////////////////////////////////////////////
-// GipsVoiceEngineLib
-//
-// Public interface to the GIPS Voice Engine for PC platforms
-//////////////////////////////////////////////////////////////////////
-
-#ifndef NULL
-#define NULL 0L
-#endif
-
-class VOICEENGINE_DLLEXPORT GipsVoiceEngineLite
-{
-public:
- virtual int GIPSVE_Init(bool recordAEC =false, bool multiCore = false,int month = 0,int day = 0,int year = 0 ) = 0;
- virtual int GIPSVE_SetNetworkStatus(int networktype) = 0;
- virtual int GIPSVE_GetNetworkStatus() = 0;
- virtual int GIPSVE_CreateChannel() = 0;
- virtual int GIPSVE_DeleteChannel(int channel) = 0;
- virtual int GIPSVE_GetCodec(short listnr, GIPS_CodecInst *codec_inst) = 0;
- virtual int GIPSVE_GetNofCodecs() = 0;
- virtual int GIPSVE_SetSendCodec(int channel, GIPS_CodecInst *codec_inst) = 0;
- virtual int GIPSVE_GetCurrentSendCodec(short channel, GIPS_CodecInst *gipsve_inst) = 0;
- virtual int GIPSVE_GetRecCodec(int channel, GIPS_CodecInst *recCodec) = 0;
- virtual int GIPSVE_SetRecPort(int channel, int portnr, char * multiCastAddr = NULL, char * ip = NULL) = 0;
- virtual int GIPSVE_GetRecPort(int channel) = 0;
- virtual int GIPSVE_SetSendPort(int channel, int portnr) = 0;
- virtual int GIPSVE_SetSrcPort(int channel, int portnr) = 0;
- virtual int GIPSVE_GetSendPort(int channel) = 0;
- virtual int GIPSVE_SetSendIP(int channel, char *ipadr) = 0;
- virtual int GIPSVE_GetSendIP(int channel, char *ipadr, int bufsize) = 0;
- virtual int GIPSVE_StartListen(int channel) = 0;
- virtual int GIPSVE_StartPlayout(int channel) = 0;
- virtual int GIPSVE_StartSend(int channel) = 0;
- virtual int GIPSVE_StopListen(int channel) = 0;
- virtual int GIPSVE_StopPlayout(int channel) = 0;
- virtual int GIPSVE_StopSend(int channel) = 0;
- virtual int GIPSVE_GetLastError() = 0;
- virtual int GIPSVE_SetSpeakerVolume(unsigned int level) = 0;
- virtual int GIPSVE_GetSpeakerVolume() = 0;
- virtual int GIPSVE_SetMicVolume(unsigned int level) = 0;
- virtual int GIPSVE_GetMicVolume() = 0;
- virtual int GIPSVE_SetAGCStatus(int mode) = 0;
- virtual int GIPSVE_GetAGCStatus() = 0;
- virtual int GIPSVE_GetVersion(char *version, int buflen) = 0;
- virtual int GIPSVE_Terminate() = 0;
- virtual int GIPSVE_SetDTMFPayloadType(int channel, int payloadType) = 0;
- virtual int GIPSVE_SendDTMF(int channel, int eventnr, int inBand) = 0;
- virtual int GIPSVE_PlayDTMFTone(int eventnr) = 0;
- virtual unsigned short GIPSVE_GetFromPort(int channel)=0;
- virtual int GIPSVE_SetFilterPort(int channel,unsigned short filter) = 0;
- virtual int GIPSVE_SetFilterIP(int channel,char *IPaddress) = 0;
- virtual unsigned short GIPSVE_GetFilterPort(int channel) = 0;
- virtual int GIPSVE_SetRecPayloadType(short channel, GIPS_CodecInst *codec_inst)=0;
- virtual int GIPSVE_RTCPStat(int channel, unsigned short *fraction_lost, unsigned long *cum_lost, unsigned long *ext_max, unsigned long *jitter, int *RTT)=0;
- virtual int GIPSVE_SetSoundDevices(unsigned int WaveInDevice, unsigned int WaveOutDevice, bool disableMicBoost = false)= 0;
- virtual int GIPSVE_SetDTMFFeedbackStatus(int mode) = 0;
- virtual int GIPSVE_GetDTMFFeedbackStatus() = 0;
-
- virtual int GIPSVE_GetNoOfChannels() = 0;
- virtual int GIPSVE_GetInputLevel() = 0;
- virtual int GIPSVE_GetOutputLevel(int channel = -1) = 0;
- virtual int GIPSVE_MuteMic(int channel,int Mute) = 0;
- virtual int GIPSVE_PutOnHold(int channel,bool enable) = 0;
- virtual int GIPSVE_AddToConference(int channel,bool enable, bool includeCSRCs = false, bool includeVoiceLevel = false) = 0;
-
- virtual int GIPSVE_CheckIfAudioIsAvailable(int checkPlay, int checkRec) = 0;
-
- // RTCP calls
- virtual int GIPSVE_EnableRTCP(int channel, int enable) = 0;
- virtual int GIPSVE_SetRTCPCNAME(int channel, char * str) = 0;
- virtual int GIPSVE_getRemoteRTCPCNAME(int channel, char * str) = 0;
-
- virtual int GIPSVE_SetPacketTimeout(int channel, bool enable, int time_sec) = 0;
-
- // Send extra packet over RTP / RTCP channel (no RTP headers added)
- virtual int sendExtraPacket_RTP(int channel, unsigned char* data, int nbytes) = 0;
- virtual int sendExtraPacket_RTCP(int channel, unsigned char* data, int nbytes) = 0;
-
- // Voice Activity
- virtual int GIPSVE_GetVoiceActivityIndicator(int channel) = 0;
-
- // Use these function calls ONLY when a customer specific transport protocol is going to be used
- virtual int GIPSVE_SetSendTransport(int channel, GIPS_transport &transport) = 0;
- virtual int GIPSVE_ReceivedRTPPacket(int channel, const void *data, int len) = 0;
- virtual int GIPSVE_ReceivedRTCPPacket(int channel, const void *data, int len) = 0;
-
- virtual ~GipsVoiceEngineLite();
-};
-
-//////////////////////////////////////////////////////////////////////
-// Factory method
-//////////////////////////////////////////////////////////////////////
-
-VOICEENGINE_DLLEXPORT GipsVoiceEngineLite &GetGipsVoiceEngineLite();
-
-
-
-#endif // PUBLIC_GIPS_VOICE_ENGINE_LIB_H
diff --git a/third_party/libjingle/source/talk/third_party/gipslite/Interface/expiration.h b/third_party/libjingle/source/talk/third_party/gipslite/Interface/expiration.h
deleted file mode 100644
index 622c3ea..0000000
--- a/third_party/libjingle/source/talk/third_party/gipslite/Interface/expiration.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#define GIPS_EXPIRATION_MONTH 5
-
-#define GIPS_EXPIRATION_DAY 5
-
-#define GIPS_EXPIRATION_YEAR 2010
-
diff --git a/third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.dll b/third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.dll
deleted file mode 100644
index e3a9cc9..0000000
--- a/third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.dll
+++ /dev/null
Binary files differ
diff --git a/third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.lib b/third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.lib
deleted file mode 100644
index 6abed76..0000000
--- a/third_party/libjingle/source/talk/third_party/gipslite/Libraries/GipsVoiceEngineLite.lib
+++ /dev/null
Binary files differ
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/Makefile.am b/third_party/libjingle/source/talk/third_party/mediastreamer/Makefile.am
deleted file mode 100644
index 9dcf686..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/Makefile.am
+++ /dev/null
@@ -1,91 +0,0 @@
-noinst_LTLIBRARIES = libmediastreamer.la
-libmediastreamer_la_SOURCES=msfilter.c msfilter.h msutils.h waveheader.h\
- mscodec.c mscodec.h \
- mssoundread.c mssoundread.h \
- mssoundwrite.c mssoundwrite.h \
- msbuffer.c msbuffer.h \
- msqueue.c msqueue.h \
- msfifo.c msfifo.h \
- ms.c ms.h\
- mssync.c mssync.h \
- msnosync.c msnosync.h \
- msread.c msread.h \
- mswrite.c mswrite.h \
- mscopy.c mscopy.h \
- msosswrite.c msosswrite.h \
- msossread.c msossread.h \
- msringplayer.c msringplayer.h \
- msrtprecv.c msrtprecv.h \
- msrtpsend.c msrtpsend.h \
- msAlawenc.c msAlawenc.h g711common.h \
- msAlawdec.c msAlawdec.h g711common.h \
- msMUlawenc.c msMUlawenc.h g711common.h \
- msMUlawdec.c msMUlawdec.h g711common.h \
- mstimer.c mstimer.h \
- msqdispatcher.c msqdispatcher.h \
- msfdispatcher.c msfdispatcher.h \
- sndcard.c sndcard.h \
- osscard.c osscard.h\
- hpuxsndcard.c \
- alsacard.c alsacard.h \
- jackcard.c jackcard.h \
- audiostream.c mediastream.h \
- msspeexenc.c msspeexenc.h msspeexdec.c msspeexdec.h \
- msilbcdec.c msilbcdec.h msilbcenc.c msilbcenc.h
-
-noinst_HEADERS = affine.h \
- msAlawenc.h \
- msfdispatcher.h \
- msilbcdec.h \
- msnosync.h \
- msringplayer.h \
- msspeexdec.h \
- msutils.h \
- waveheader.h \
- alsacard.h \
- msavdecoder.h \
- msfifo.h \
- msilbcenc.h \
- msossread.h \
- msrtprecv.h \
- msspeexenc.h \
- msv4l.h \
- g711common.h \
- msavencoder.h \
- msfilter.h \
- msLPC10decoder.h \
- msosswrite.h \
- msrtpsend.h \
- mssync.h \
- msvideosource.h \
- jackcard.h \
- msbuffer.h \
- msGSMdecoder.h \
- msLPC10encoder.h \
- msqdispatcher.h \
- mssdlout.h \
- mstimer.h \
- mswrite.h \
- mediastream.h \
- mscodec.h \
- msGSMencoder.h \
- msMUlawdec.h \
- msqueue.h \
- mssoundread.h \
- mstruespeechdecoder.h \
- osscard.h \
- msAlawdec.h \
- mscopy.h \
- ms.h \
- msMUlawenc.h \
- msread.h \
- mssoundwrite.h \
- mstruespeechencoder.h \
- sndcard.h
-
-
-libmediastreamer_la_LIBADD= $(GLIB_LIBS) $(ORTP_LIBS)
-
-AM_CFLAGS=$(GLIB_CFLAGS) -D__ALSA_ENABLED__ -DHAVE_ALSA_ASOUNDLIB_H -DG_LOG_DOMAIN=\"MediaStreamer\" $(ORTP_CFLAGS) $(IPV6_CFLAGS) $(ILBC_CFLAGS) $(SPEEX_CFLAGS)
-
-INCLUDES= -I$(top_srcdir) $(ORTP_CFLAGS)
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/affine.c b/third_party/libjingle/source/talk/third_party/mediastreamer/affine.c
deleted file mode 100644
index 99f33d7..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/affine.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * affine.c -- Affine Transforms for 2d objects
- * Copyright (C) 2002 Charles Yates <charles.yates@pandora.be>
- * Portions Copyright (C) 2003 Dan Dennedy <dan@dennedy.org>
- * ported from C++ to C
- * wrote affine_scale()
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include "affine.h"
-
-static inline void Multiply( affine_transform_t *this, affine_transform_t *that )
-{
- double output[2][2];
- register int i, j;
-
- for ( i = 0; i < 2; i ++ )
- for ( j = 0; j < 2; j ++ )
- output[ i ][ j ] = this->matrix[ i ][ 0 ] * that->matrix[ j ][ 0 ] +
- this->matrix[ i ][ 1 ] * that->matrix[ j ][ 1 ];
-
- this->matrix[ 0 ][ 0 ] = output[ 0 ][ 0 ];
- this->matrix[ 0 ][ 1 ] = output[ 0 ][ 1 ];
- this->matrix[ 1 ][ 0 ] = output[ 1 ][ 0 ];
- this->matrix[ 1 ][ 1 ] = output[ 1 ][ 1 ];
-}
-
-void affine_transform_init( affine_transform_t *this )
-{
- this->matrix[ 0 ][ 0 ] = 1;
- this->matrix[ 0 ][ 1 ] = 0;
- this->matrix[ 1 ][ 0 ] = 0;
- this->matrix[ 1 ][ 1 ] = 1;
-}
-
-// Rotate by a given angle
-void affine_transform_rotate( affine_transform_t *this, double angle )
-{
- affine_transform_t affine;
- affine.matrix[ 0 ][ 0 ] = cos( angle * M_PI / 180 );
- affine.matrix[ 0 ][ 1 ] = 0 - sin( angle * M_PI / 180 );
- affine.matrix[ 1 ][ 0 ] = sin( angle * M_PI / 180 );
- affine.matrix[ 1 ][ 1 ] = cos( angle * M_PI / 180 );
- Multiply( this, &affine );
-}
-
-// Shear by a given value
-void affine_transform_shear( affine_transform_t *this, double shear )
-{
- affine_transform_t affine;
- affine.matrix[ 0 ][ 0 ] = 1;
- affine.matrix[ 0 ][ 1 ] = shear;
- affine.matrix[ 1 ][ 0 ] = 0;
- affine.matrix[ 1 ][ 1 ] = 1;
- Multiply( this, &affine );
-}
-
-void affine_transform_scale( affine_transform_t *this, double sx, double sy )
-{
- affine_transform_t affine;
- affine.matrix[ 0 ][ 0 ] = sx;
- affine.matrix[ 0 ][ 1 ] = 0;
- affine.matrix[ 1 ][ 0 ] = 0;
- affine.matrix[ 1 ][ 1 ] = sy;
- Multiply( this, &affine );
-}
-
-// Obtain the mapped x coordinate of the input
-double affine_transform_mapx( affine_transform_t *this, int x, int y )
-{
- return this->matrix[0][0] * x + this->matrix[0][1] * y;
-}
-
-// Obtain the mapped y coordinate of the input
-double affine_transform_mapy( affine_transform_t *this, int x, int y )
-{
- return this->matrix[1][0] * x + this->matrix[1][1] * y;
-}
-
-#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
-
-void affine_scale( const unsigned char *src, unsigned char *dest, int src_width, int src_height, int dest_width, int dest_height, int bpp )
-{
- affine_transform_t affine;
- double scale_x = (double) dest_width / (double) src_width;
- double scale_y = (double) dest_height / (double) src_height;
- register unsigned char *d = dest;
- register const unsigned char *s = src;
- register int i, j, k, x, y;
-
- affine_transform_init( &affine );
-
- if ( scale_x <= 1.0 && scale_y <= 1.0 )
- {
- affine_transform_scale( &affine, scale_x, scale_y );
-
- for( j = 0; j < src_height; j++ )
- for( i = 0; i < src_width; i++ )
- {
- x = (int) ( affine_transform_mapx( &affine, i - src_width/2, j - src_height/2 ) );
- y = (int) ( affine_transform_mapy( &affine, i - src_width/2, j - src_height/2 ) );
- x += dest_width/2;
- x = CLAMP( x, 0, dest_width);
- y += dest_height/2;
- y = CLAMP( y, 0, dest_height);
- s = src + (j*src_width*bpp) + i*bpp; // + (bpp-1);
- d = dest + y*dest_width*bpp + x*bpp;
- for ( k = 0; k < bpp; k++ )
- *d++ = *s++;
- }
- }
- else if ( scale_x > 1.0 && scale_y > 1.0 )
- {
- affine_transform_scale( &affine, 1.0/scale_x, 1.0/scale_y );
-
- for( y = 0; y < dest_height; y++ )
- for( x = 0; x < dest_width; x++ )
- {
- i = (int) ( affine_transform_mapx( &affine, x - dest_width/2, y - dest_height/2 ) );
- j = (int) ( affine_transform_mapy( &affine, x - dest_width/2, y - dest_height/2 ) );
- i += src_width/2;
- i = CLAMP( i, 0, dest_width);
- j += src_height/2;
- j = CLAMP( j, 0, dest_height);
- s = src + (j*src_width*bpp) + i*bpp; // + (bpp-1);
- d = dest + y*dest_width*bpp + x*bpp;
- for ( k = 0; k < bpp; k++ )
- *d++ = *s++;
- }
- }
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/affine.h b/third_party/libjingle/source/talk/third_party/mediastreamer/affine.h
deleted file mode 100644
index 620fdc9..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/affine.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * affine.h -- Affine Transforms for 2d objects
- * Copyright (C) 2002 Charles Yates <charles.yates@pandora.be>
- * Portions Copyright (C) 2003 Dan Dennedy <dan@dennedy.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _AFFINE_H
-#define _AFFINE_H
-
-#include <math.h>
-
-/** Affine transforms for 2d image manipulation. Current provides shearing and
- rotating support.
-*/
-
-typedef struct {
- double matrix[2][2];
-} affine_transform_t;
-
-void affine_transform_init( affine_transform_t *this );
-void affine_transform_rotate( affine_transform_t *this, double angle );
-void affine_transform_shear( affine_transform_t *this, double shear );
-void affine_transform_scale( affine_transform_t *this, double sx, double sy );
-double affine_transform_mapx( affine_transform_t *this, int x, int y );
-double affine_transform_mapy( affine_transform_t *this, int x, int y );
-void affine_scale( const unsigned char *src, unsigned char *dest, int src_width, int src_height, int dest_width, int dest_height, int bpp );
-
-#endif
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.c b/third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.c
deleted file mode 100644
index ebf2909..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.c
+++ /dev/null
@@ -1,640 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "alsacard.h"
-
-#ifdef HAVE_ALSA_ASOUNDLIB_H
-
-static gchar *over_pcmdev=NULL;
-
-#include "msossread.h"
-#include "msosswrite.h"
-
-#include <signal.h>
-
-int __alsa_card_write(AlsaCard *obj,char *buf,int size);
-
-int alsa_set_params(AlsaCard *obj, int rw, int bits, int stereo, int rate)
-{
- snd_pcm_hw_params_t *hwparams=NULL;
- snd_pcm_sw_params_t *swparams=NULL;
- snd_pcm_t *pcm_handle;
- gint dir,exact_value;
- gint channels;
- gint fsize=0;
- gint periods=8;
- gint periodsize=256;
- gint err;
- int format;
-
- if (rw) {
- pcm_handle=obj->write_handle;
- }
- else pcm_handle=obj->read_handle;
-
- /* Allocate the snd_pcm_hw_params_t structure on the stack. */
- snd_pcm_hw_params_alloca(&hwparams);
-
- /* Init hwparams with full configuration space */
- if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
- g_warning("alsa_set_params: Cannot configure this PCM device.\n");
- return(-1);
- }
-
- if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
- g_warning("alsa_set_params: Error setting access.\n");
- return(-1);
- }
- /* Set sample format */
-#ifdef WORDS_BIGENDIAN
- format=SND_PCM_FORMAT_S16_BE;
-#else
- format=SND_PCM_FORMAT_S16_LE;
-#endif
- if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {
- g_warning("alsa_set_params: Error setting format.\n");
- return(-1);
- }
- /* Set number of channels */
- if (stereo) channels=2;
- else channels=1;
- if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {
- g_warning("alsa_set_params: Error setting channels.\n");
- return(-1);
- }
- /* Set sample rate. If the exact rate is not supported */
- /* by the hardware, use nearest possible rate. */
- exact_value=rate;
- dir=0;
- if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_value, &dir))<0){
- g_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err));
- return -1;
- }
- if (dir != 0) {
- g_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n "
- "==> Using %d Hz instead.\n", rate, exact_value);
- }
- /* choose greater period size when rate is high */
- periodsize=periodsize*(rate/8000);
-
- /* Set buffer size (in frames). The resulting latency is given by */
- /* latency = periodsize * periods / (rate * bytes_per_frame) */
- /*
- fsize=periodsize * periods;
- exact_value=fsize;
- if ((err=snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,&exact_value)) < 0) {
- g_warning("alsa_set_params: Error setting buffer size:%s",snd_strerror(err));
- return(-1);
- }
- if (fsize!= exact_value) {
- g_warning("alsa_set_params: The buffer size %d is not supported by your hardware.\n "
- "==> Using %d instead.\n", fsize, exact_value);
- }
- */
- /* set period size */
- exact_value=periodsize;
- dir=0;
- if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
- g_warning("alsa_set_params: Error setting period size.\n");
- return(-1);
- }
- if (dir != 0) {
- g_warning("alsa_set_params: The period size %d is not supported by your hardware.\n "
- "==> Using %d instead.\n", periodsize, exact_value);
- }
- periodsize=exact_value;
- /* Set number of periods. Periods used to be called fragments. */
- exact_value=periods;
- dir=0;
- if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
- g_warning("alsa_set_params: Error setting periods.\n");
- return(-1);
- }
- if (dir != 0) {
- g_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n "
- "==> Using %d instead.\n", periods, exact_value);
- }
- /* Apply HW parameter settings to */
- /* PCM device and prepare device */
- if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
- g_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err));
- return(-1);
- }
- /*prepare sw params */
- if (rw){
- snd_pcm_sw_params_alloca(&swparams);
- snd_pcm_sw_params_current(pcm_handle, swparams);
- if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){
- g_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err));
- return -1;
- }
- if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){
- g_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err));
- return(-1);
- }
- }
- obj->frame_size=channels*(bits/8);
- SND_CARD(obj)->bsize=periodsize*obj->frame_size;
- //SND_CARD(obj)->bsize=4096;
- obj->frames=periodsize;
- g_message("alsa_set_params: blocksize=%i.",SND_CARD(obj)->bsize);
- return SND_CARD(obj)->bsize;
-}
-
-int alsa_card_open_r(AlsaCard *obj,int bits,int stereo,int rate)
-{
- int bsize;
- int err;
- snd_pcm_t *pcm_handle;
- gchar *pcmdev;
- if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
- else pcmdev=obj->pcmdev;
-
- if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) {
- g_warning("alsa_card_open_r: Error opening PCM device %s\n",obj->pcmdev );
- return -1;
- }
- g_return_val_if_fail(pcm_handle!=NULL,-1);
- obj->read_handle=pcm_handle;
- if ((bsize=alsa_set_params(obj,0,bits,stereo,rate))<0){
- snd_pcm_close(pcm_handle);
- obj->read_handle=NULL;
- return -1;
- }
- obj->readbuf=g_malloc0(bsize);
-
- err=snd_pcm_start(obj->read_handle);
- if (err<0){
- g_warning("Cannot start read pcm: %s", snd_strerror(err));
- }
- obj->readpos=0;
- SND_CARD(obj)->bsize=bsize;
- SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
- return 0;
-}
-
-int alsa_card_open_w(AlsaCard *obj,int bits,int stereo,int rate)
-{
- int err,bsize;
- snd_pcm_t *pcm_handle;
- gchar *pcmdev;
- if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
- else pcmdev=obj->pcmdev;
-
- if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {
- g_warning("alsa_card_open_w: Error opening PCM device %s\n", obj->pcmdev);
- return -1;
- }
- obj->write_handle=pcm_handle;
- if ((bsize=alsa_set_params(obj,1,bits,stereo,rate))<0){
- snd_pcm_close(pcm_handle);
- obj->write_handle=NULL;
- return -1;
- }
- obj->writebuf=g_malloc0(bsize);
-
- obj->writepos=0;
- SND_CARD(obj)->bsize=bsize;
- SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
- return 0;
-}
-
-
-void alsa_card_set_blocking_mode(AlsaCard *obj, gboolean yesno){
- if (obj->read_handle!=NULL) snd_pcm_nonblock(obj->read_handle,!yesno);
- if (obj->write_handle!=NULL) snd_pcm_nonblock(obj->write_handle,!yesno);
-}
-
-void alsa_card_close_r(AlsaCard *obj)
-{
- if (obj->read_handle!=NULL){
- snd_pcm_close(obj->read_handle);
- obj->read_handle=NULL;
- g_free(obj->readbuf);
- obj->readbuf=NULL;
- }
-}
-
-void alsa_card_close_w(AlsaCard *obj)
-{
- if (obj->write_handle!=NULL){
- snd_pcm_close(obj->write_handle);
- obj->write_handle=NULL;
- g_free(obj->writebuf);
- obj->writebuf=NULL;
- }
-}
-
-int alsa_card_probe(AlsaCard *obj,int bits,int stereo,int rate)
-{
- int ret;
- ret=alsa_card_open_w(obj,bits,stereo,rate);
- if (ret<0) return -1;
- ret=SND_CARD(obj)->bsize;
- alsa_card_close_w(obj);
- return ret;
-}
-
-
-void alsa_card_destroy(AlsaCard *obj)
-{
- snd_card_uninit(SND_CARD(obj));
- g_free(obj->pcmdev);
- if (obj->readbuf!=0) g_free(obj->readbuf);
- if (obj->writebuf!=0) g_free(obj->writebuf);
-}
-
-gboolean alsa_card_can_read(AlsaCard *obj)
-{
- int frames;
- g_return_val_if_fail(obj->read_handle!=NULL,0);
- if (obj->readpos!=0) return TRUE;
- if ( frames=snd_pcm_avail_update(obj->read_handle)>=obj->frames) return 1;
- //g_message("frames=%i",frames);
- return 0;
-}
-
-
-
-int __alsa_card_read(AlsaCard *obj,char *buf,int bsize)
-{
- int err;
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set,SIGALRM);
- sigprocmask(SIG_BLOCK,&set,NULL);
- err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
- if (err<0) {
- if (err!=-EPIPE){
- g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
- }
- snd_pcm_prepare(obj->read_handle);
- err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
- if (err<0) g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
- }
- sigprocmask(SIG_UNBLOCK,&set,NULL);
- return err*obj->frame_size;
-}
-
-int alsa_card_read(AlsaCard *obj,char *buf,int size)
-{
- int err;
- gint bsize=SND_CARD(obj)->bsize;
- g_return_val_if_fail(obj->read_handle!=NULL,-1);
- if (size<bsize){
- gint canread=MIN(bsize-obj->readpos,size);
-
- if (obj->readpos==0){
- err=__alsa_card_read(obj,obj->readbuf,bsize);
- }
-
- memcpy(buf,&obj->readbuf[obj->readpos],canread);
- obj->readpos+=canread;
- if (obj->readpos>=bsize) obj->readpos=0;
- return canread;
- }else{
- err=__alsa_card_read(obj,buf,size);
- return err;
- }
-
-}
-
-int __alsa_card_write(AlsaCard *obj,char *buf,int size)
-{
- int err;
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set,SIGALRM);
- sigprocmask(SIG_BLOCK,&set,NULL);
- if ((err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size))<0){
- if (err!=-EPIPE){
- g_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err));
- }
- snd_pcm_prepare(obj->write_handle);
- err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size);
- if (err<0) g_warning("alsa_card_write: Error writing sound buffer (size=%i):%s",size,snd_strerror(err));
-
- }
- sigprocmask(SIG_UNBLOCK,&set,NULL);
- return err;
-}
-
-int alsa_card_write(AlsaCard *obj,char *buf,int size)
-{
- int err;
- gint bsize=SND_CARD(obj)->bsize;
- g_return_val_if_fail(obj->write_handle!=NULL,-1);
- if (size<bsize){
- gint canwrite;
-
- canwrite=MIN(bsize-obj->writepos,size);
- memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
- obj->writepos+=canwrite;
- if (obj->writepos>=bsize){
- err=__alsa_card_write(obj,obj->writebuf,bsize);
- obj->writepos=0;
- }
- return canwrite;
- }else{
- return __alsa_card_write(obj,buf,bsize);
- }
-}
-
-snd_mixer_t *alsa_mixer_open(AlsaCard *obj){
- snd_mixer_t *mixer=NULL;
- int err;
- err=snd_mixer_open(&mixer,0);
- if (err<0){
- g_warning("Could not open alsa mixer: %s",snd_strerror(err));
- return NULL;
- }
- if ((err = snd_mixer_attach (mixer, obj->mixdev)) < 0){
- g_warning("Could not attach mixer to card: %s",snd_strerror(err));
- snd_mixer_close(mixer);
- return NULL;
- }
- if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){
- g_warning("snd_mixer_selem_register: %s",snd_strerror(err));
- snd_mixer_close(mixer);
- return NULL;
- }
- if ((err = snd_mixer_load (mixer)) < 0){
- g_warning("snd_mixer_load: %s",snd_strerror(err));
- snd_mixer_close(mixer);
- return NULL;
- }
- obj->mixer=mixer;
- return mixer;
-}
-
-void alsa_mixer_close(AlsaCard *obj){
- snd_mixer_close(obj->mixer);
- obj->mixer=NULL;
-}
-
-typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction;
-
-static gint get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){
- long value=0;
- const char *elemname;
- snd_mixer_elem_t *elem;
- int err;
- long sndMixerPMin;
- long sndMixerPMax;
- long newvol;
- elem=snd_mixer_first_elem(mixer);
- while (elem!=NULL){
- elemname=snd_mixer_selem_get_name(elem);
- //g_message("Found alsa mixer element %s.",elemname);
- if (strcmp(elemname,name)==0){
- switch (action){
- case CAPTURE:
- if (snd_mixer_selem_has_capture_volume(elem)){
- snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
- err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol);
- newvol-=sndMixerPMin;
- value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
- if (err<0) g_warning("Could not get capture volume for %s:%s",name,snd_strerror(err));
- //else g_message("Succesfully get capture level for %s.",elemname);
- break;
- }
- break;
- case PLAYBACK:
- if (snd_mixer_selem_has_playback_volume(elem)){
- snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
- err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol);
- newvol-=sndMixerPMin;
- value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
- if (err<0) g_warning("Could not get playback volume for %s:%s",name,snd_strerror(err));
- //else g_message("Succesfully get playback level for %s.",elemname);
- break;
- }
- break;
- case CAPTURE_SWITCH:
-
- break;
- }
- }
- elem=snd_mixer_elem_next(elem);
- }
-
- return value;
-}
-
-
-static void set_mixer_element(snd_mixer_t *mixer,const char *name, gint level,MixerAction action){
- const char *elemname;
- snd_mixer_elem_t *elem;
- int tmp;
- long sndMixerPMin;
- long sndMixerPMax;
- long newvol;
-
- elem=snd_mixer_first_elem(mixer);
-
- while (elem!=NULL){
- elemname=snd_mixer_selem_get_name(elem);
- //g_message("Found alsa mixer element %s.",elemname);
- if (strcmp(elemname,name)==0){
- switch(action){
- case CAPTURE:
- if (snd_mixer_selem_has_capture_volume(elem)){
- snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
- newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
- snd_mixer_selem_set_capture_volume_all(elem,newvol);
- //g_message("Succesfully set capture level for %s.",elemname);
- return;
- }
- break;
- case PLAYBACK:
- if (snd_mixer_selem_has_playback_volume(elem)){
- snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
- newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
- snd_mixer_selem_set_playback_volume_all(elem,newvol);
- //g_message("Succesfully set playback level for %s.",elemname);
- return;
- }
- break;
- case CAPTURE_SWITCH:
- if (snd_mixer_selem_has_capture_switch(elem)){
- snd_mixer_selem_set_capture_switch_all(elem,level);
- //g_message("Succesfully set capture switch for %s.",elemname);
- }
- break;
- case PLAYBACK_SWITCH:
- if (snd_mixer_selem_has_playback_switch(elem)){
- snd_mixer_selem_set_playback_switch_all(elem,level);
- //g_message("Succesfully set capture switch for %s.",elemname);
- }
- break;
-
- }
- }
- elem=snd_mixer_elem_next(elem);
- }
-
- return ;
-}
-
-
-void alsa_card_set_level(AlsaCard *obj,gint way,gint a)
-{
- snd_mixer_t *mixer;
- mixer=alsa_mixer_open(obj);
- if (mixer==NULL) return ;
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- set_mixer_element(mixer,"Master",a,PLAYBACK);
- break;
- case SND_CARD_LEVEL_INPUT:
- set_mixer_element(mixer,"Capture",a,CAPTURE);
- break;
- case SND_CARD_LEVEL_OUTPUT:
- set_mixer_element(mixer,"PCM",a,PLAYBACK);
- break;
- default:
- g_warning("oss_card_set_level: unsupported command.");
- }
- alsa_mixer_close(obj);
-}
-
-gint alsa_card_get_level(AlsaCard *obj,gint way)
-{
- snd_mixer_t *mixer;
- gint value;
- mixer=alsa_mixer_open(obj);
- if (mixer==NULL) return 0;
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- value=get_mixer_element(mixer,"Master",PLAYBACK);
- break;
- case SND_CARD_LEVEL_INPUT:
- value=get_mixer_element(mixer,"Capture",CAPTURE);
- break;
- case SND_CARD_LEVEL_OUTPUT:
- value=get_mixer_element(mixer,"PCM",PLAYBACK);
- break;
- default:
- g_warning("oss_card_set_level: unsupported command.");
- }
- alsa_mixer_close(obj);
- return value;
-}
-
-void alsa_card_set_source(AlsaCard *obj,int source)
-{
- snd_mixer_t *mixer;
- mixer=alsa_mixer_open(obj);
- if (mixer==NULL) return;
- switch (source){
- case 'm':
- set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH);
- set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
- break;
- case 'l':
- set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH);
- set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
- break;
- }
-}
-
-MSFilter *alsa_card_create_read_filter(AlsaCard *card)
-{
- MSFilter *f=ms_oss_read_new();
- ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
- return f;
-}
-
-MSFilter *alsa_card_create_write_filter(AlsaCard *card)
-{
- MSFilter *f=ms_oss_write_new();
- ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
- return f;
-}
-
-
-SndCard * alsa_card_new(gint devid)
-{
- AlsaCard * obj;
- SndCard *base;
- int err;
- gchar *name=NULL;
-
- /* carefull: this is an alsalib call despite its name! */
- err=snd_card_get_name(devid,&name);
- if (err<0) {
- return NULL;
- }
- obj= g_new0(AlsaCard,1);
- base= SND_CARD(obj);
- snd_card_init(base);
-
- base->card_name=g_strdup_printf("%s (Advanced Linux Sound Architecture)",name);
- base->_probe=(SndCardOpenFunc)alsa_card_probe;
- base->_open_r=(SndCardOpenFunc)alsa_card_open_r;
- base->_open_w=(SndCardOpenFunc)alsa_card_open_w;
- base->_can_read=(SndCardPollFunc)alsa_card_can_read;
- base->_set_blocking_mode=(SndCardSetBlockingModeFunc)alsa_card_set_blocking_mode;
- base->_read=(SndCardIOFunc)alsa_card_read;
- base->_write=(SndCardIOFunc)alsa_card_write;
- base->_close_r=(SndCardCloseFunc)alsa_card_close_r;
- base->_close_w=(SndCardCloseFunc)alsa_card_close_w;
- base->_set_rec_source=(SndCardMixerSetRecSourceFunc)alsa_card_set_source;
- base->_set_level=(SndCardMixerSetLevelFunc)alsa_card_set_level;
- base->_get_level=(SndCardMixerGetLevelFunc)alsa_card_get_level;
- base->_destroy=(SndCardDestroyFunc)alsa_card_destroy;
- base->_create_read_filter=(SndCardCreateFilterFunc)alsa_card_create_read_filter;
- base->_create_write_filter=(SndCardCreateFilterFunc)alsa_card_create_write_filter;
-
-
- obj->pcmdev=g_strdup_printf("plughw:%i,0",devid);
- obj->mixdev=g_strdup_printf("hw:%i",devid);
- obj->readbuf=NULL;
- obj->writebuf=NULL;
- return base;
-}
-
-
-gint alsa_card_manager_init(SndCardManager *m, gint index)
-{
- gint devindex;
- gint i;
- gint found=0;
- gchar *name=NULL;
- for(devindex=0;index<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
- if (snd_card_get_name(devindex,&name)==0){
- g_message("Found ALSA device: %s",name);
- m->cards[index]=alsa_card_new(devindex);
- m->cards[index]->index=index;
- found++;
- index++;
- }
- }
- return found;
-}
-
-void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev){
- if (over_pcmdev!=NULL){
- g_free(over_pcmdev);
- }
- over_pcmdev=g_strdup(pcmdev);
-}
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.h b/third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.h
deleted file mode 100644
index df3372f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/alsacard.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <config.h>
-
-#ifdef HAVE_ALSA_ASOUNDLIB_H
-
-#include "sndcard.h"
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#include <alsa/asoundlib.h>
-struct _AlsaCard
-{
- SndCard parent;
- gchar *pcmdev;
- gchar *mixdev;
- snd_pcm_t *read_handle;
- snd_pcm_t *write_handle;
- gint frame_size;
- gint frames;
- gchar *readbuf;
- gint readpos;
- gchar *writebuf;
- gint writepos;
- snd_mixer_t *mixer;
-};
-
-typedef struct _AlsaCard AlsaCard;
-
-SndCard *alsa_card_new(gint dev_id);
-gint alsa_card_manager_init(SndCardManager *m, gint index);
-void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/audiostream.c b/third_party/libjingle/source/talk/third_party/mediastreamer/audiostream.c
deleted file mode 100644
index 67a4485..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/audiostream.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "mediastream.h"
-#ifdef INET6
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netdb.h>
-#endif
-
-
-#define MAX_RTP_SIZE 1500
-
-/* this code is not part of the library itself, it is part of the mediastream program */
-void audio_stream_free(AudioStream *stream)
-{
- RtpSession *s;
- RtpSession *destroyed=NULL;
- if (stream->rtprecv!=NULL) {
- s=ms_rtp_recv_get_session(MS_RTP_RECV(stream->rtprecv));
- if (s!=NULL){
- destroyed=s;
- rtp_session_destroy(s);
- }
- ms_filter_destroy(stream->rtprecv);
- }
- if (stream->rtpsend!=NULL) {
- s=ms_rtp_send_get_session(MS_RTP_SEND(stream->rtpsend));
- if (s!=NULL){
- if (s!=destroyed)
- rtp_session_destroy(s);
- }
- ms_filter_destroy(stream->rtpsend);
- }
- if (stream->soundread!=NULL) ms_filter_destroy(stream->soundread);
- if (stream->soundwrite!=NULL) ms_filter_destroy(stream->soundwrite);
- if (stream->encoder!=NULL) ms_filter_destroy(stream->encoder);
- if (stream->decoder!=NULL) ms_filter_destroy(stream->decoder);
- if (stream->timer!=NULL) ms_sync_destroy(stream->timer);
- g_free(stream);
-}
-
-static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
-
-static void on_dtmf_received(RtpSession *s,gint dtmf,gpointer user_data)
-{
- AudioStream *stream=(AudioStream*)user_data;
- if (dtmf>15){
- g_warning("Unsupported telephone-event type.");
- return;
- }
- g_message("Receiving dtmf %c.",dtmf_tab[dtmf]);
- if (stream!=NULL){
- if (strcmp(stream->soundwrite->klass->name,"OssWrite")==0)
- ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf_tab[dtmf]);
- }
-}
-
-static void on_timestamp_jump(RtpSession *s,guint32* ts, gpointer user_data)
-{
- g_warning("The remote sip-phone has send data with a future timestamp: %u,"
- "resynchronising session.",*ts);
- rtp_session_reset(s);
-}
-
-static const char *ip4local="0.0.0.0";
-static const char *ip6local="::";
-
-const char *get_local_addr_for(const char *remote)
-{
- const char *ret;
-#ifdef INET6
- char num[8];
- struct addrinfo hints, *res0;
- int err;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM;
- err = getaddrinfo(remote,"8000", &hints, &res0);
- if (err!=0) {
- g_warning ("get_local_addr_for: %s", gai_strerror(err));
- return ip4local;
- }
- ret=(res0->ai_addr->sa_family==AF_INET6) ? ip6local : ip4local;
- freeaddrinfo(res0);
-#else
- ret=ip4local;
-#endif
- return ret;
-}
-
-void create_duplex_rtpsession(RtpProfile *profile, int locport,char *remip,int remport,
- int payload,int jitt_comp,
- RtpSession **recvsend){
- RtpSession *rtpr;
- rtpr=rtp_session_new(RTP_SESSION_SENDRECV);
- rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
- rtp_session_set_profile(rtpr,profile);
- rtp_session_set_local_addr(rtpr,get_local_addr_for(remip),locport);
- if (remport>0) rtp_session_set_remote_addr(rtpr,remip,remport);
- rtp_session_set_scheduling_mode(rtpr,0);
- rtp_session_set_blocking_mode(rtpr,0);
- rtp_session_set_payload_type(rtpr,payload);
- rtp_session_set_jitter_compensation(rtpr,jitt_comp);
- rtp_session_enable_adaptive_jitter_compensation(rtpr,TRUE);
- /*rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);*/
- *recvsend=rtpr;
-}
-
-void create_rtp_sessions(RtpProfile *profile, int locport,char *remip,int remport,
- int payload,int jitt_comp,
- RtpSession **recv, RtpSession **send){
- RtpSession *rtps,*rtpr;
- PayloadType *pt;
- /* creates two rtp filters to recv send streams (remote part)*/
-
- rtps=rtp_session_new(RTP_SESSION_SENDONLY);
- rtp_session_max_buf_size_set(rtps,MAX_RTP_SIZE);
- rtp_session_set_profile(rtps,profile);
-#ifdef INET6
- rtp_session_set_local_addr(rtps,"::",locport+2);
-#else
- rtp_session_set_local_addr(rtps,"0.0.0.0",locport+2);
-#endif
- rtp_session_set_remote_addr(rtps,remip,remport);
- rtp_session_set_scheduling_mode(rtps,0);
- rtp_session_set_blocking_mode(rtps,0);
- rtp_session_set_payload_type(rtps,payload);
- rtp_session_set_jitter_compensation(rtps,jitt_comp);
-
- rtpr=rtp_session_new(RTP_SESSION_RECVONLY);
- rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
- rtp_session_set_profile(rtpr,profile);
-#ifdef INET6
- rtp_session_set_local_addr(rtpr,"::",locport);
-#else
- rtp_session_set_local_addr(rtpr,"0.0.0.0",locport);
-#endif
- rtp_session_set_scheduling_mode(rtpr,0);
- rtp_session_set_blocking_mode(rtpr,0);
- rtp_session_set_payload_type(rtpr,payload);
- rtp_session_set_jitter_compensation(rtpr,jitt_comp);
- rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,NULL);
- rtp_session_signal_connect(rtpr,"timestamp_jump",(RtpCallback)on_timestamp_jump,NULL);
- *recv=rtpr;
- *send=rtps;
-
-}
-
-
-AudioStream * audio_stream_start_full(RtpProfile *profile, int locport,char *remip,int remport,
- int payload,int jitt_comp, gchar *infile, gchar *outfile, SndCard *playcard, SndCard *captcard)
-{
- AudioStream *stream=g_new0(AudioStream,1);
- RtpSession *rtps,*rtpr;
- PayloadType *pt;
-
- //create_rtp_sessions(profile,locport,remip,remport,payload,jitt_comp,&rtpr,&rtps);
-
- create_duplex_rtpsession(profile,locport,remip,remport,payload,jitt_comp,&rtpr);
- rtp_session_signal_connect(rtpr,"telephone-event",(RtpCallback)on_dtmf_received,(gpointer)stream);
- rtps=rtpr;
-
- stream->recv_session = rtpr;
- stream->send_session = rtps;
- stream->rtpsend=ms_rtp_send_new();
- ms_rtp_send_set_session(MS_RTP_SEND(stream->rtpsend),rtps);
- stream->rtprecv=ms_rtp_recv_new();
- ms_rtp_recv_set_session(MS_RTP_RECV(stream->rtprecv),rtpr);
-
-
- /* creates the local part */
- if (infile==NULL) stream->soundread=snd_card_create_read_filter(captcard);
- else stream->soundread=ms_read_new(infile);
- if (outfile==NULL) stream->soundwrite=snd_card_create_write_filter(playcard);
- else stream->soundwrite=ms_write_new(outfile);
-
- /* creates the couple of encoder/decoder */
- pt=rtp_profile_get_payload(profile,payload);
- if (pt==NULL){
- g_error("audiostream.c: undefined payload type.");
- return NULL;
- }
- stream->encoder=ms_encoder_new_with_string_id(pt->mime_type);
- stream->decoder=ms_decoder_new_with_string_id(pt->mime_type);
- if ((stream->encoder==NULL) || (stream->decoder==NULL)){
- /* big problem: we have not a registered codec for this payload...*/
- audio_stream_free(stream);
- g_error("mediastream.c: No decoder available for payload %i.",payload);
- return NULL;
- }
- /* give the sound filters some properties */
- ms_filter_set_property(stream->soundread,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
- ms_filter_set_property(stream->soundwrite,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
-
- /* give the encoder/decoder some parameters*/
- ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
- ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate);
- ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FREQ,&pt->clock_rate);
- ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_BITRATE,&pt->normal_bitrate);
-
- ms_filter_set_property(stream->encoder,MS_FILTER_PROPERTY_FMTP, (void*)pt->fmtp);
- ms_filter_set_property(stream->decoder,MS_FILTER_PROPERTY_FMTP,(void*)pt->fmtp);
- /* create the synchronisation source */
- stream->timer=ms_timer_new();
-
- /* and then connect all */
- ms_filter_add_link(stream->soundread,stream->encoder);
- ms_filter_add_link(stream->encoder,stream->rtpsend);
- ms_filter_add_link(stream->rtprecv,stream->decoder);
- ms_filter_add_link(stream->decoder,stream->soundwrite);
-
- ms_sync_attach(stream->timer,stream->soundread);
- ms_sync_attach(stream->timer,stream->rtprecv);
-
- /* and start */
- ms_start(stream->timer);
-
- return stream;
-}
-
-static int defcard=0;
-
-void audio_stream_set_default_card(int cardindex){
- defcard=cardindex;
-}
-
-AudioStream * audio_stream_start_with_files(RtpProfile *prof,int locport,char *remip,
- int remport,int profile,int jitt_comp,gchar *infile, gchar*outfile)
-{
- return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,infile,outfile,NULL,NULL);
-}
-
-AudioStream * audio_stream_start(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp)
-{
- SndCard *sndcard;
- sndcard=snd_card_manager_get_card(snd_card_manager,defcard);
- return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,sndcard,sndcard);
-}
-
-AudioStream *audio_stream_start_with_sndcards(RtpProfile *prof,int locport,char *remip,int remport,int profile,int jitt_comp,SndCard *playcard, SndCard *captcard)
-{
- g_return_val_if_fail(playcard!=NULL,NULL);
- g_return_val_if_fail(captcard!=NULL,NULL);
- return audio_stream_start_full(prof,locport,remip,remport,profile,jitt_comp,NULL,NULL,playcard,captcard);
-}
-
-void audio_stream_set_rtcp_information(AudioStream *st, const char *cname){
- if (st->send_session!=NULL){
- rtp_session_set_source_description(st->send_session,cname,NULL,NULL,NULL, NULL,"linphone",
- "This is free software (GPL) !");
- }
-}
-
-void audio_stream_stop(AudioStream * stream)
-{
-
- ms_stop(stream->timer);
- ortp_global_stats_display();
- ms_sync_detach(stream->timer,stream->soundread);
- ms_sync_detach(stream->timer,stream->rtprecv);
-
- ms_filter_remove_links(stream->soundread,stream->encoder);
- ms_filter_remove_links(stream->encoder,stream->rtpsend);
- ms_filter_remove_links(stream->rtprecv,stream->decoder);
- ms_filter_remove_links(stream->decoder,stream->soundwrite);
-
- audio_stream_free(stream);
-}
-
-RingStream * ring_start(gchar *file,gint interval,SndCard *sndcard)
-{
- return ring_start_with_cb(file,interval,sndcard,NULL,NULL);
-}
-
-RingStream * ring_start_with_cb(gchar *file,gint interval,SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data)
-{
- RingStream *stream;
- int tmp;
- g_return_val_if_fail(sndcard!=NULL,NULL);
- stream=g_new0(RingStream,1);
- stream->source=ms_ring_player_new(file,interval);
- if (stream->source==NULL) {
- g_warning("Could not create ring player. Probably the ring file (%s) does not exist.",file);
- return NULL;
- }
- if (func!=NULL) ms_filter_set_notify_func(MS_FILTER(stream->source),func,user_data);
- stream->sndwrite=snd_card_create_write_filter(sndcard);
- ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_FREQ,&tmp);
- ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_FREQ,&tmp);
- ms_filter_get_property(stream->source,MS_FILTER_PROPERTY_CHANNELS,&tmp);
- ms_filter_set_property(stream->sndwrite,MS_FILTER_PROPERTY_CHANNELS,&tmp);
- stream->timer=ms_timer_new();
- ms_filter_add_link(stream->source,stream->sndwrite);
- ms_sync_attach(stream->timer,stream->source);
- ms_start(stream->timer);
- return stream;
-}
-
-void ring_stop(RingStream *stream)
-{
- ms_stop(stream->timer);
- ms_sync_detach(stream->timer,stream->source);
- ms_sync_destroy(stream->timer);
- ms_filter_remove_links(stream->source,stream->sndwrite);
- ms_filter_destroy(stream->source);
- ms_filter_destroy(stream->sndwrite);
- g_free(stream);
-}
-
-/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */
-gint test_audio_dev(int dev_id)
-{
- gint err;
- SndCard *sndcard=snd_card_manager_get_card(snd_card_manager,dev_id);
- if (sndcard==NULL) return -1;
- err=snd_card_probe(sndcard,16,0,8000);
- return err; /* return latency in number of sample */
-}
-
-gint audio_stream_send_dtmf(AudioStream *stream, gchar dtmf)
-{
- ms_rtp_send_dtmf(MS_RTP_SEND(stream->rtpsend), dtmf);
- ms_oss_write_play_dtmf(MS_OSS_WRITE(stream->soundwrite),dtmf);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/g711common.h b/third_party/libjingle/source/talk/third_party/mediastreamer/g711common.h
deleted file mode 100644
index 3f5ad16..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/g711common.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * PCM - A-Law conversion
- * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
- *
- * Wrapper for linphone Codec class by Simon Morlat <simon.morlat@free.fr>
- */
-
-static inline int val_seg(int val)
-{
- int r = 0;
- val >>= 7;
- if (val & 0xf0) {
- val >>= 4;
- r += 4;
- }
- if (val & 0x0c) {
- val >>= 2;
- r += 2;
- }
- if (val & 0x02)
- r += 1;
- return r;
-}
-
-/*
- * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
- *
- * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
- *
- * Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 0000000wxyza 000wxyz
- * 0000001wxyza 001wxyz
- * 000001wxyzab 010wxyz
- * 00001wxyzabc 011wxyz
- * 0001wxyzabcd 100wxyz
- * 001wxyzabcde 101wxyz
- * 01wxyzabcdef 110wxyz
- * 1wxyzabcdefg 111wxyz
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-
-static inline unsigned char s16_to_alaw(int pcm_val)
-{
- int mask;
- int seg;
- unsigned char aval;
-
- if (pcm_val >= 0) {
- mask = 0xD5;
- } else {
- mask = 0x55;
- pcm_val = -pcm_val;
- if (pcm_val > 0x7fff)
- pcm_val = 0x7fff;
- }
-
- if (pcm_val < 256)
- aval = pcm_val >> 4;
- else {
- /* Convert the scaled magnitude to segment number. */
- seg = val_seg(pcm_val);
- aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
- }
- return aval ^ mask;
-}
-
-/*
- * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
- *
- */
-static inline int alaw_to_s16(unsigned char a_val)
-{
- int t;
- int seg;
-
- a_val ^= 0x55;
- t = a_val & 0x7f;
- if (t < 16)
- t = (t << 4) + 8;
- else {
- seg = (t >> 4) & 0x07;
- t = ((t & 0x0f) << 4) + 0x108;
- t <<= seg -1;
- }
- return ((a_val & 0x80) ? t : -t);
-}
-/*
- * s16_to_ulaw() - Convert a linear PCM value to u-law
- *
- * In order to simplify the encoding process, the original linear magnitude
- * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
- * (33 - 8191). The result can be seen in the following encoding table:
- *
- * Biased Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 00000001wxyza 000wxyz
- * 0000001wxyzab 001wxyz
- * 000001wxyzabc 010wxyz
- * 00001wxyzabcd 011wxyz
- * 0001wxyzabcde 100wxyz
- * 001wxyzabcdef 101wxyz
- * 01wxyzabcdefg 110wxyz
- * 1wxyzabcdefgh 111wxyz
- *
- * Each biased linear code has a leading 1 which identifies the segment
- * number. The value of the segment number is equal to 7 minus the number
- * of leading 0's. The quantization interval is directly available as the
- * four bits wxyz. * The trailing bits (a - h) are ignored.
- *
- * Ordinarily the complement of the resulting code word is used for
- * transmission, and so the code word is complemented before it is returned.
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-
-static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */
-{
- int mask;
- int seg;
- unsigned char uval;
-
- if (pcm_val < 0) {
- pcm_val = 0x84 - pcm_val;
- mask = 0x7f;
- } else {
- pcm_val += 0x84;
- mask = 0xff;
- }
- if (pcm_val > 0x7fff)
- pcm_val = 0x7fff;
-
- /* Convert the scaled magnitude to segment number. */
- seg = val_seg(pcm_val);
-
- /*
- * Combine the sign, segment, quantization bits;
- * and complement the code word.
- */
- uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
- return uval ^ mask;
-}
-
-/*
- * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
- *
- * First, a biased linear code is derived from the code word. An unbiased
- * output can then be obtained by subtracting 33 from the biased code.
- *
- * Note that this function expects to be passed the complement of the
- * original code word. This is in keeping with ISDN conventions.
- */
-static inline int ulaw_to_s16(unsigned char u_val)
-{
- int t;
-
- /* Complement to obtain normal u-law value. */
- u_val = ~u_val;
-
- /*
- * Extract and bias the quantization bits. Then
- * shift up by the segment number and subtract out the bias.
- */
- t = ((u_val & 0x0f) << 3) + 0x84;
- t <<= (u_val & 0x70) >> 4;
-
- return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/hpuxsndcard.c b/third_party/libjingle/source/talk/third_party/mediastreamer/hpuxsndcard.c
deleted file mode 100644
index 8210e29..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/hpuxsndcard.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "sndcard.h"
-#include "osscard.h"
-
-#ifdef HAVE_SYS_AUDIO_H
-#include <sys/audio.h>
-
-
-#include "msossread.h"
-#include "msosswrite.h"
-
-#include <errno.h>
-#include <fcntl.h>
-
-
-int hpuxsnd_open(HpuxSndCard *obj, int bits,int stereo, int rate)
-{
- int fd;
- int p=0,cond=0;
- int i=0;
- int min_size=0,blocksize=512;
- /* do a quick non blocking open to be sure that we are not going to be blocked here
- for the eternity */
- fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
- if (fd<0) return -EWOULDBLOCK;
- close(fd);
- /* open the device */
- fd=open(obj->dev_name,O_RDWR);
-
- g_return_val_if_fail(fd>0,-errno);
-
- ioctl(fd,AUDIO_RESET,0);
- ioctl(fd,AUDIO_SET_SAMPLE_RATE,rate);
- ioctl(fd,AUDIO_SET_CHANNELS,stereo);
- p=AUDIO_FORMAT_LINEAR16BIT;
- ioctl(fd,AUDIO_SET_DATA_FORMAT,p);
- /* ioctl(fd,AUDIO_GET_RXBUFSIZE,&min_size); does not work ? */
- min_size=2048;
-
- g_message("dsp blocksize is %i.",min_size);
- obj->fd=fd;
- obj->readpos=0;
- obj->writepos=0;
- SND_CARD(obj)->bits=bits;
- SND_CARD(obj)->stereo=stereo;
- SND_CARD(obj)->rate=rate;
- SND_CARD(obj)->bsize=min_size;
- return fd;
-}
-
-int hpux_snd_card_probe(HpuxSndCard *obj,int bits,int stereo,int rate)
-{
- return 2048;
-}
-
-
-int hpux_snd_card_open(HpuxSndCard *obj,int bits,int stereo,int rate)
-{
- int fd;
- obj->ref++;
- if (obj->fd==0){
- fd=hpuxsnd_open(obj,bits,stereo,rate);
- if (fd<0) {
- obj->fd=0;
- obj->ref--;
- return -1;
- }
- }
- SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
- return 0;
-}
-
-void hpux_snd_card_close(HpuxSndCard *obj)
-{
- int i;
- obj->ref--;
- if (obj->ref==0) {
- close(obj->fd);
- obj->fd=0;
- SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED;
-
- }
-}
-
-void hpux_snd_card_destroy(HpuxSndCard *obj)
-{
- snd_card_uninit(SND_CARD(obj));
- g_free(obj->dev_name);
- g_free(obj->mixdev_name);
-}
-
-gboolean hpux_snd_card_can_read(HpuxSndCard *obj)
-{
- struct timeval tout={0,0};
- int err;
- fd_set fdset;
- FD_ZERO(&fdset);
- FD_SET(obj->fd,&fdset);
- err=select(obj->fd+1,&fdset,NULL,NULL,&tout);
- if (err>0) return TRUE;
- else return FALSE;
-}
-
-int hpux_snd_card_read(HpuxSndCard *obj,char *buf,int size)
-{
- int err;
- gint bsize=SND_CARD(obj)->bsize;
- if (size<bsize){
- gint canread=MIN(bsize-obj->readpos,size);
- if (obj->readbuf==NULL) obj->readbuf=g_malloc0(bsize);
- if (obj->readpos==0){
- err=read(obj->fd,obj->readbuf,bsize);
- if (err<0) {
- g_warning("hpux_snd_card_read: read() failed:%s.",strerror(errno));
- return -1;
- }
- }
-
- memcpy(buf,&obj->readbuf[obj->readpos],canread);
- obj->readpos+=canread;
- if (obj->readpos>=bsize) obj->readpos=0;
- return canread;
- }else{
- err=read(obj->fd,buf,size);
- if (err<0) {
- g_warning("hpux_snd_card_read: read-2() failed:%s.",strerror(errno));
- }
- return err;
- }
-
-}
-
-int hpux_snd_card_write(HpuxSndCard *obj,char *buf,int size)
-{
- int err;
- gint bsize=SND_CARD(obj)->bsize;
- if (size<bsize){
- gint canwrite=MIN(bsize-obj->writepos,size);
- if (obj->writebuf==NULL) obj->writebuf=g_malloc0(bsize);
-
- memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
- obj->writepos+=canwrite;
- if (obj->writepos>=bsize){
- err=write(obj->fd,obj->writebuf,bsize);
- }
- return canwrite;
- }else{
- return write(obj->fd,buf,bsize);
- }
-}
-
-#define SND_CARD_LEVEL_TO_HPUX_LEVEL(a) (((a)*2) - 100)
-#define HPUX_LEVEL_TO_SND_CARD_LEVEL(a) (((a)+200)/2)
-void hpux_snd_card_set_level(HpuxSndCard *obj,gint way,gint a)
-{
- struct audio_gain gain;
- int error,mix_fd;
-
- g_return_if_fail(obj->mixdev_name!=NULL);
- memset(&gain,0,sizeof(struct audio_gain));
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- gain.cgain[0].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
- gain.cgain[1].monitor_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
- break;
- case SND_CARD_LEVEL_INPUT:
- gain.cgain[0].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
- gain.cgain[1].receive_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
- break;
- case SND_CARD_LEVEL_OUTPUT:
- gain.cgain[0].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
- gain.cgain[1].transmit_gain=SND_CARD_LEVEL_TO_HPUX_LEVEL(a);
- break;
- default:
- g_warning("hpux_snd_card_set_level: unsupported command.");
- return;
- }
- gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT;
- mix_fd = open(obj->mixdev_name, O_WRONLY);
- g_return_if_fail(mix_fd>0);
- error=ioctl(mix_fd,AUDIO_SET_GAINS,&gain);
- if (error<0){
- g_warning("hpux_snd_card_set_level: Could not set gains: %s",strerror(errno));
- }
- close(mix_fd);
-}
-
-gint hpux_snd_card_get_level(HpuxSndCard *obj,gint way)
-{
- struct audio_gain gain;
- int p=0,mix_fd,error;
- g_return_if_fail(obj->mixdev_name!=NULL);
-
- gain.channel_mask=AUDIO_CHANNEL_RIGHT|AUDIO_CHANNEL_LEFT;
- mix_fd = open(obj->mixdev_name, O_RDONLY);
- g_return_if_fail(mix_fd>0);
- error=ioctl(mix_fd,AUDIO_GET_GAINS,&gain);
- if (error<0){
- g_warning("hpux_snd_card_set_level: Could not get gains: %s",strerror(errno));
- }
- close(mix_fd);
-
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- p=gain.cgain[0].monitor_gain;
- break;
- case SND_CARD_LEVEL_INPUT:
- p=gain.cgain[0].receive_gain;
- break;
- case SND_CARD_LEVEL_OUTPUT:
- p=gain.cgain[0].transmit_gain;
- break;
- default:
- g_warning("hpux_snd_card_get_level: unsupported command.");
- return -1;
- }
- return HPUX_LEVEL_TO_SND_CARD_LEVEL(p);
-}
-
-void hpux_snd_card_set_source(HpuxSndCard *obj,int source)
-{
- gint p=0;
- gint mix_fd;
- gint error=0;
- g_return_if_fail(obj->mixdev_name!=NULL);
-
- mix_fd=open("/dev/audio",O_WRONLY);
- g_return_if_fail(mix_fd>0);
- switch(source){
- case 'm':
- error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_MIKE);
- break;
- case 'l':
- error=ioctl(mix_fd,AUDIO_SET_INPUT,AUDIO_IN_LINE);
- break;
- default:
- g_warning("hpux_snd_card_set_source: unsupported source.");
- }
- close(mix_fd);
-}
-
-MSFilter *hpux_snd_card_create_read_filter(HpuxSndCard *card)
-{
- MSFilter *f=ms_oss_read_new();
- ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
- return f;
-}
-
-MSFilter *hpux_snd_card_create_write_filter(HpuxSndCard *card)
-{
- MSFilter *f=ms_oss_write_new();
- ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
- return f;
-}
-
-
-SndCard * hpux_snd_card_new(char *devname, char *mixdev_name)
-{
- HpuxSndCard * obj= g_new0(HpuxSndCard,1);
- SndCard *base= SND_CARD(obj);
- snd_card_init(base);
- obj->dev_name=g_strdup(devname);
- obj->mixdev_name=g_strdup( mixdev_name);
- base->card_name=g_strdup(devname);
- base->_probe=(SndCardOpenFunc)hpux_snd_card_probe;
- base->_open_r=(SndCardOpenFunc)hpux_snd_card_open;
- base->_open_w=(SndCardOpenFunc)hpux_snd_card_open;
- base->_can_read=(SndCardPollFunc)hpux_snd_card_can_read;
- base->_read=(SndCardIOFunc)hpux_snd_card_read;
- base->_write=(SndCardIOFunc)hpux_snd_card_write;
- base->_close_r=(SndCardCloseFunc)hpux_snd_card_close;
- base->_close_w=(SndCardCloseFunc)hpux_snd_card_close;
- base->_set_rec_source=(SndCardMixerSetRecSourceFunc)hpux_snd_card_set_source;
- base->_set_level=(SndCardMixerSetLevelFunc)hpux_snd_card_set_level;
- base->_get_level=(SndCardMixerGetLevelFunc)hpux_snd_card_get_level;
- base->_destroy=(SndCardDestroyFunc)hpux_snd_card_destroy;
- base->_create_read_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_read_filter;
- base->_create_write_filter=(SndCardCreateFilterFunc)hpux_snd_card_create_write_filter;
- return base;
-}
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.c b/third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.c
deleted file mode 100644
index b929cce..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.c
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- JACK support
- Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk
-*/
-
-#include "jackcard.h"
-
-#ifdef __JACK_ENABLED__
-
-#include "msossread.h"
-#include "msosswrite.h"
-
-#include <signal.h>
-
-#define READBUFFERSIZE 524288
-#define WRITEBUFFERSIZE 524288
-#define BSIZE 512
-
-/**
- * jack_shutdown:
- * @arg:
- *
- * This is the shutdown callback for this JACK application.
- * It is called by JACK if the server ever shuts down or
- * decides to disconnect the client.
- *
- */
-void
-jack_shutdown (void *arg)
-{
- JackCard* obj = (JackCard*) arg;
-
- obj->jack_running = FALSE;
- obj->jack_active = FALSE;
- obj->read.port = NULL;
- if (obj->read.open)
- obj->read.init = TRUE;
- obj->write.port = NULL;
- if (obj->write.open)
- obj->write.init = TRUE;
-}
-
-int samplerate(jack_nframes_t rate, void *arg)
-{
- JackCard* obj = (JackCard*) arg;
- int error;
-
- obj->rate = rate;
- if (obj->read.open) {
- obj->read.data.src_ratio = (double)obj->read.rate / (double)obj->rate;
- obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
- g_free(obj->read.data.data_in);
- obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
- if (obj->read.src_state)
- if ((error = src_set_ratio(obj->read.src_state, obj->read.data.src_ratio)) != 0)
- g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
- }
- if (obj->write.open) {
- obj->write.data.src_ratio = (double)obj->rate / (double)obj->write.rate;
- obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
- g_free(obj->write.data.data_out);
- obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
- if (obj->write.src_state)
- if ((error = src_set_ratio(obj->write.src_state, obj->write.data.src_ratio)) != 0)
- g_warning("Error while resetting the write samplerate: %s", src_strerror(error));
- }
- return 0;
-}
-
-/*
- * The process callback for this JACK application.
- * It is called by JACK at the appropriate times.
- * @nframes :
- * @arg :
- */
-int
-process (jack_nframes_t nframes, void *arg)
-{
- JackCard* obj = (JackCard*) arg;
- sample_t *out;
- sample_t *in;
-
- if (obj->clear && !obj->write.can_process) {
- out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
- memset (out, 0, nframes * sizeof(sample_t));
- obj->clear = FALSE;
- }
-
- if (!obj->can_process)
- return 0;
-
- if(obj->read.can_process) {
- in = (sample_t *) jack_port_get_buffer (obj->read.port, nframes);
- jack_ringbuffer_write (obj->read.buffer, (void *) in, sizeof(sample_t) * nframes);
- }
-
- if (obj->write.can_process) {
- out = (sample_t *) jack_port_get_buffer (obj->write.port, nframes);
- memset (out, 0, nframes * sizeof(sample_t));
- if (obj->clear && jack_ringbuffer_read_space(obj->write.buffer) == 0) {
- obj->write.can_process = FALSE;
- if (!obj->read.open)
- obj->can_process = FALSE;
- obj->clear = FALSE;
- return 0;
- }
- jack_ringbuffer_read (obj->write.buffer, (void *) out, sizeof(sample_t) * nframes);
- }
- return 0;
-}
-
-int jack_init(JackCard* obj)
-{
- char* client_name;
- int error;
-
- if (!obj->jack_running) {
- obj->client = NULL;
- client_name = g_strdup_printf("linphone-%u", g_random_int());
- if ((obj->client = jack_client_new (client_name)) == NULL) {
- g_warning("cannot create jack client");
- g_free(client_name);
- return -1;
- }
- g_message("Found Jack Daemon");
- g_free(client_name);
-
- /* tell the JACK server to call `process()' whenever
- there is work to be done.
- */
- jack_set_process_callback (obj->client, process, obj);
-
- /* tell the JACK server to call `jack_shutdown()' if
- it ever shuts down, either entirely, or if it
- just decides to stop calling us.
- */
- jack_on_shutdown (obj->client, jack_shutdown, obj);
- jack_set_sample_rate_callback (obj->client, samplerate, obj);
- obj->rate = jack_get_sample_rate (obj->client);
- if (obj->rate == 0) {
- g_warning ("rate is 0???");
- if (jack_client_close(obj->client) != 0)
- g_warning("could not close client");
- return -1;
- }
- obj->buffer_size = jack_get_buffer_size(obj->client);
- obj->jack_running = TRUE;
- }
-
- if (!obj->jack_active) {
- if (jack_activate (obj->client)) {
- g_warning("cannot activate jack client");
- return -1;
- } else obj->jack_active = TRUE;
- }
-
- if (obj->read.init) {
- if (!obj->read.port && (obj->read.port = jack_port_register (obj->client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))==NULL) {
- g_warning("error while trying to register input port");
- return -1;
- }
- if (!obj->read.phys_ports && (obj->read.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) {
- g_warning("Cannot find any physical capture ports\n");
- jack_port_unregister(obj->client, obj->read.port);
- obj->read.port = NULL;
- return -1;
- }
- if (!jack_port_connected(obj->read.port))
- if ((error = jack_connect (obj->client, obj->read.phys_ports[0], jack_port_name (obj->read.port))) != 0) {
- g_warning("cannot connect input ports: %s -> %s\n", jack_port_name (obj->read.port), obj->read.phys_ports[0]);
- if (error == EEXIST) g_warning("connection already made");
- else {
- jack_port_unregister(obj->client, obj->read.port);
- obj->read.port = NULL;
- return -1;
- }
- }
- obj->read.init = FALSE;
- }
-
- if (obj->write.init) {
- if (!obj->write.port && (obj->write.port = jack_port_register (obj->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0))==NULL) {
- g_warning("error while trying to register output port");
- return -1;
- }
- if (!obj->write.phys_ports && (obj->write.phys_ports = jack_get_ports (obj->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
- g_warning("Cannot find any physical playback ports\n");
- jack_port_unregister(obj->client, obj->write.port);
- obj->write.port = NULL;
- return -1;
- }
- if (!jack_port_connected(obj->write.port)) {
- if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[0])) != 0) {
- g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[0]);
- if (error == EEXIST) g_warning("connection already made");
- else {
- jack_port_unregister(obj->client, obj->write.port);
- obj->write.port = NULL;
- return -1;
- }
- }
- if ((error = jack_connect (obj->client, jack_port_name (obj->write.port), obj->write.phys_ports[1])) != 0) {
- g_warning("cannot connect output ports: %s -> %s\n", jack_port_name (obj->write.port), obj->write.phys_ports[1]);
- if (error == EEXIST) g_warning("connection already made");
- else {
- jack_port_unregister(obj->client, obj->write.port);
- obj->write.port = NULL;
- return -1;
- }
- }
- }
- obj->write.init = FALSE;
- }
- return 0;
-}
-
-int jack_card_open_r(JackCard *obj,int bits,int stereo,int rate)
-{
- int channels = stereo + 1, bsize, error;
- obj->read.init = TRUE;
- if (jack_init(obj) != 0) return -1;
-
- obj->read.rate = rate;
- obj->sample_size = bits / 8;
- obj->frame_size = channels * obj->sample_size;
- bsize = BSIZE;
- obj->read.frames = bsize / 2;
- SND_CARD(obj)->bsize = bsize;
- SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
- obj->read.channels = channels;
- if ((obj->read.src_state = src_new (SRC_SINC_FASTEST, channels, &error)) == NULL)
- g_warning("Error while initializing the samplerate converter: %s", src_strerror(error));
- obj->read.data.src_ratio = (double)rate / (double)obj->rate;
- obj->read.data.input_frames = (long)((double)obj->read.frames/obj->read.data.src_ratio);
- obj->read.data.data_in = malloc(obj->read.data.input_frames*sizeof(float));
- obj->read.data.data_out = malloc(obj->read.frames*sizeof(float));
- obj->read.data.end_of_input = 0;
- if (!obj->read.buffer)
- obj->read.buffer = jack_ringbuffer_create(READBUFFERSIZE);
- obj->read.can_process = TRUE;
- obj->can_process = TRUE;
- obj->read.open = TRUE;
- obj->read.init = FALSE;
- return 0;
-}
-
-int jack_card_open_w(JackCard *obj,int bits,int stereo,int rate)
-{
- int channels = stereo + 1, bsize, err;
- obj->write.init = TRUE;
- if (jack_init(obj) != 0) return -1;
-
- obj->write.rate = rate;
- obj->sample_size = bits / 8;
- obj->frame_size = channels * obj->sample_size;
- bsize = BSIZE;
- obj->write.frames = bsize / 2;
- SND_CARD(obj)->bsize = bsize;
- SND_CARD(obj)->flags |= SND_CARD_FLAGS_OPENED;
- obj->write.channels = channels;
- if ((obj->write.src_state = src_new (SRC_SINC_FASTEST, channels, &err)) == NULL)
- g_warning("Error while initializing the samplerate converter: %s", src_strerror(err));
- obj->write.data.src_ratio = (double)obj->rate / (double)rate;
- obj->write.data.data_in = malloc(obj->write.frames*sizeof(float));
- obj->write.data.end_of_input = 0;
- obj->write.data.output_frames = (long)((double)obj->write.frames*obj->write.data.src_ratio);
- obj->write.data.data_out = malloc(obj->write.data.output_frames*sizeof(float));
- if (!obj->write.buffer)
- obj->write.buffer = jack_ringbuffer_create(WRITEBUFFERSIZE);
- obj->write.can_process = TRUE;
- obj->can_process = TRUE;
- obj->write.open = TRUE;
- obj->write.init = FALSE;
- return 0;
-}
-
-void jack_card_set_blocking_mode(JackCard *obj, gboolean yesno)
-{
-}
-
-void jack_card_close_r(JackCard *obj)
-{
- obj->read.open = FALSE;
- obj->read.init = FALSE;
- obj->read.can_process = FALSE;
- if (!obj->write.open)
- obj->can_process = FALSE;
- if (obj->read.src_state)
- obj->read.src_state = src_delete (obj->read.src_state);
- g_free(obj->read.data.data_in);
- g_free(obj->read.data.data_out);
-}
-
-void jack_card_close_w(JackCard *obj)
-{
- obj->write.open = FALSE;
- obj->write.init = FALSE;
- obj->clear = TRUE;
- if (!obj->jack_running) {
- obj->write.can_process = FALSE;
- obj->can_process = FALSE;
- }
- if (obj->write.src_state)
- obj->write.src_state = src_delete (obj->write.src_state);
- g_free(obj->write.data.data_in);
- g_free(obj->write.data.data_out);
-}
-
-int jack_card_probe(JackCard *obj,int bits,int stereo,int rate)
-{
- if (obj->jack_running) return BSIZE;
- else if (jack_init(obj) == 0) return BSIZE;
- else return -1;
-}
-
-void jack_card_destroy(JackCard *obj)
-{
- if (obj->jack_running) jack_client_close (obj->client);
- snd_card_uninit(SND_CARD(obj));
- if (obj->read.buffer) {
- jack_ringbuffer_free(obj->read.buffer);
- obj->read.buffer = NULL;
- }
- if (obj->write.buffer) {
- jack_ringbuffer_free(obj->write.buffer);
- obj->write.buffer = NULL;
- }
- if (obj->read.phys_ports) {
- g_free(obj->read.phys_ports);
- obj->read.phys_ports = NULL;
- }
- if (obj->write.phys_ports) {
- g_free(obj->write.phys_ports);
- obj->write.phys_ports = NULL;
- }
-}
-
-gboolean jack_card_can_read(JackCard *obj)
-{
- g_return_val_if_fail(obj->read.buffer!=NULL,0);
- if (jack_ringbuffer_read_space(obj->read.buffer)>=(long)((double)obj->read.frames/obj->read.data.src_ratio)*sizeof(sample_t)) return TRUE;
- else return FALSE;
-}
-
-int jack_card_read(JackCard *obj,char *buf,int size)
-{
- size_t bytes, can_read, i;
- int error;
- float norm, value;
-
- g_return_val_if_fail((obj->read.buffer!=NULL)&&(obj->read.src_state!=NULL),-1);
- if (jack_init(obj) != 0) return -1;
- size /= 2;
- can_read = MIN(size, obj->read.frames);
- // can_read = MIN(((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t), jack_ringbuffer_read_space(obj->read.buffer));
- can_read = ((long)((double)can_read / obj->read.data.src_ratio))*sizeof(sample_t);
- obj->read.can_process = FALSE;
- bytes = jack_ringbuffer_read (obj->read.buffer, (void *)obj->read.data.data_in, can_read);
- obj->read.can_process = TRUE;
- obj->read.data.input_frames = bytes / sizeof(sample_t);
- can_read = MIN(size, obj->read.frames);
- obj->read.data.output_frames = can_read;
- if ((error = src_process(obj->read.src_state, &(obj->read.data))) != 0)
- g_warning("error while samplerate conversion. error: %s", src_strerror(error));
- norm = obj->read.level*obj->level*(float)0x8000;
- for (i=0; i < obj->read.data.output_frames_gen; i++) {
- value = obj->read.data.data_out[i]*norm;
- if (value >= 32767.0)
- ((short*)buf)[i] = 32767;
- else if (value <= -32768.0)
- ((short*)buf)[i] = -32768;
- else
- ((short*)buf)[i] = (short)value;
- }
- bytes = obj->read.data.output_frames_gen * 2;
- return bytes;
-}
-
-int jack_card_write(JackCard *obj,char *buf,int size)
-{
- size_t bytes, can_write, i;
- int error;
- float norm;
-
- g_return_val_if_fail((obj->write.buffer!=NULL)&&(obj->write.src_state!=NULL),-1);
- if (jack_init(obj) != 0) return -1;
- size /= 2;
- can_write = MIN(size, obj->write.frames);
- norm = obj->write.level*obj->level/(float)0x8000;
- for (i=0; i<can_write; i++) {
- obj->write.data.data_in[i] = (float)((short*)buf)[i]*norm;
- }
- obj->write.data.input_frames = can_write;
- if ((error = src_process(obj->write.src_state, &(obj->write.data))) != 0)
- g_warning("error while samplerate conversion. error: %s", src_strerror(error));
- obj->write.can_process = FALSE;
- bytes = jack_ringbuffer_write (obj->write.buffer, (void *) obj->write.data.data_out, sizeof(sample_t)*obj->write.data.output_frames_gen);
- obj->write.can_process = TRUE;
- return bytes;
-}
-
-void jack_card_set_level(JackCard *obj,gint way,gint a)
-{
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- obj->level = (float)a / 100.0;
- break;
- case SND_CARD_LEVEL_INPUT:
- obj->read.level = (float)a / 100.0;
- break;
- case SND_CARD_LEVEL_OUTPUT:
- obj->write.level = (float)a / 100.0;
- break;
- default:
- g_warning("jack_card_set_level: unsupported command.");
- }
-}
-
-gint jack_card_get_level(JackCard *obj,gint way)
-{
- gint value = 0;
-
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- value = (gint)(obj->level*100.0);
- break;
- case SND_CARD_LEVEL_INPUT:
- value = (gint)(obj->read.level*100.0);
- break;
- case SND_CARD_LEVEL_OUTPUT:
- value = (gint)(obj->write.level*100.0);
- break;
- default:
- g_warning("jack_card_get_level: unsupported command.");
- }
- return value;
-}
-
-void jack_card_set_source(JackCard *obj,int source)
-{
-}
-
-MSFilter *jack_card_create_read_filter(JackCard *card)
-{
- MSFilter *f=ms_oss_read_new();
- ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
- return f;
-}
-
-MSFilter *jack_card_create_write_filter(JackCard *card)
-{
- MSFilter *f=ms_oss_write_new();
- ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
- return f;
-}
-SndCard * jack_card_new(jack_client_t *client)
-{
- JackCard * obj;
- SndCard *base;
-
- obj= g_new0(JackCard,1);
-
- if (!client) return NULL;
- obj->client = client;
- obj->jack_running = TRUE;
- obj->jack_active = FALSE;
- obj->can_process = FALSE;
- obj->clear = TRUE;
- obj->write.can_process = FALSE;
- obj->write.open = FALSE;
- obj->write.init = TRUE;
- obj->write.port = NULL;
- obj->write.phys_ports = NULL;
- obj->write.buffer = NULL;
- obj->read.can_process = FALSE;
- obj->read.open = FALSE;
- obj->read.init = TRUE;
- obj->read.port = NULL;
- obj->read.phys_ports = NULL;
- obj->read.buffer = NULL;
-
- /* tell the JACK server to call `process()' whenever
- there is work to be done.
- */
- jack_set_process_callback (client, process, obj);
-
- /* tell the JACK server to call `jack_shutdown()' if
- it ever shuts down, either entirely, or if it
- just decides to stop calling us.
- */
- jack_on_shutdown (client, jack_shutdown, obj);
-
- jack_set_sample_rate_callback (client, samplerate, obj);
-
- obj->rate = jack_get_sample_rate (client);
- obj->buffer_size = jack_get_buffer_size(obj->client);
-
- jack_init(obj);
-
- base= SND_CARD(obj);
- snd_card_init(base);
-
-#ifdef HAVE_GLIB
- base->card_name=g_strdup_printf("JACK client");
-#else
- base->card_name=malloc(100);
- snprintf(base->card_name, 100, "JACK client");
-#endif
-
- base->_probe=(SndCardOpenFunc)jack_card_probe;
- base->_open_r=(SndCardOpenFunc)jack_card_open_r;
- base->_open_w=(SndCardOpenFunc)jack_card_open_w;
- base->_can_read=(SndCardPollFunc)jack_card_can_read;
- base->_set_blocking_mode=(SndCardSetBlockingModeFunc)jack_card_set_blocking_mode;
- base->_read=(SndCardIOFunc)jack_card_read;
- base->_write=(SndCardIOFunc)jack_card_write;
- base->_close_r=(SndCardCloseFunc)jack_card_close_r;
- base->_close_w=(SndCardCloseFunc)jack_card_close_w;
- base->_set_rec_source=(SndCardMixerSetRecSourceFunc)jack_card_set_source;
- base->_set_level=(SndCardMixerSetLevelFunc)jack_card_set_level;
- base->_get_level=(SndCardMixerGetLevelFunc)jack_card_get_level;
- base->_destroy=(SndCardDestroyFunc)jack_card_destroy;
- base->_create_read_filter=(SndCardCreateFilterFunc)jack_card_create_read_filter;
- base->_create_write_filter=(SndCardCreateFilterFunc)jack_card_create_write_filter;
-
- obj->read.buffer=NULL;
- obj->write.buffer=NULL;
- obj->buffer_size = 0;
- obj->level = 1.0;
- obj->write.level = 1.0;
- obj->read.level = 1.0;
-
- return base;
-}
-
-
-gint jack_card_manager_init(SndCardManager *m, gint index)
-{
- jack_client_t *client = NULL;
- char* client_name;
-
- client_name=g_strdup_printf("linphone-%u", g_random_int());
- if ((client = jack_client_new (client_name))!= NULL)
- {
- g_message("Found Jack Daemon");
- g_free(client_name);
- m->cards[index]=jack_card_new(client);
- m->cards[index]->index=index;
- return 1;
- } else {
- g_free(client_name);
- return 0;
- }
-}
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.h b/third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.h
deleted file mode 100644
index 33ec46d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/jackcard.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- JACK support
- Copyright (C) 2004 Tobias Gehrig tobias@gehrig.tk
-*/
-
-#ifndef JACK_CARD_H
-#define JACK_CARD_H
-
-#include <config.h>
-
-#ifdef __JACK_ENABLED__
-
-#include "sndcard.h"
-
-#include <jack/jack.h>
-#include <jack/ringbuffer.h>
-
-#include <samplerate.h>
-
-typedef jack_default_audio_sample_t sample_t;
-
-typedef struct {
- jack_port_t *port;
- const char **phys_ports;
- float level;
- jack_ringbuffer_t *buffer;
- gint channels;
- gint rate;
- SRC_STATE* src_state;
- SRC_DATA data;
- size_t frames;
- gboolean can_process;
- gboolean open;
- gboolean init;
-} jackcard_mode_t;
-
-struct _JackCard
-{
- SndCard parent;
-
- jack_client_t *client;
- gboolean jack_running;
- gboolean jack_active;
- float level;
- jack_nframes_t buffer_size;
- gint sample_size;
- gint frame_size;
- gint rate;
- gboolean can_process;
- gboolean clear;
-
- jackcard_mode_t read, write;
-};
-
-typedef struct _JackCard JackCard;
-
-SndCard * jack_card_new(jack_client_t *client);
-
-gint jack_card_manager_init(SndCardManager *m, gint index);
-
-#endif
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.c
deleted file mode 100644
index e4ea789..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "mediastream.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond--;
- if (cond<0) exit(-1);
-}
-
-void parse_addr(gchar *addr, char **ip, int *port)
-{
- char *semicolon;
- gint iplen;
-
- *ip=NULL;
- *port=0;
- semicolon=strchr(addr,':');
- if (semicolon==NULL) return;
- iplen=semicolon-addr;
- *ip=g_malloc(iplen+1);
- strncpy(*ip,addr,iplen);
- (*ip)[iplen]='\0';
- *port=atoi(semicolon+1);
-}
-
-char *usage="mediastream --local <port> --remote <ip:port> --payload <payload type>\n";
-void run_media_streams(gint localport, gchar *remote_ip, gint remoteport, gint payload);
-
-int main(int argc, char * argv[])
-{
- gint i;
- gint localport=0,remoteport=0,payload=0;
- gchar *ip;
- gchar *tmp;
-
- /*create the rtp session */
- ortp_init();
- ortp_set_debug_file("oRTP",NULL);
- rtp_profile_set_payload(&av_profile,115,&lpc1015);
- rtp_profile_set_payload(&av_profile,110,&speex_nb);
- rtp_profile_set_payload(&av_profile,8,&pcma8000);
-
-
- if (argc<4) {
- printf(usage);
- return -1;
- }
- for (i=1;i<argc;i++){
- if (strcmp(argv[i],"--local")==0){
- i++;
- localport=atoi(argv[i]);
- }else if (strcmp(argv[i],"--remote")==0){
- i++;
- parse_addr(argv[i],&ip,&remoteport);
- if (ip==NULL) {
- printf(usage);
- return -1;
- }
- printf("Remote addr: ip=%s port=%i\n",ip,remoteport);
- }else if (strcmp(argv[i],"--payload")==0){
- i++;
- payload=atoi(argv[i]);
- }
- }
- tmp=getenv("defcard");
- if (tmp!=NULL) audio_stream_set_default_card(atoi(tmp));
- run_media_streams(localport,ip,remoteport,payload);
- return 0;
-}
-
-void run_media_streams(gint localport, gchar *remote_ip, gint remoteport, gint payload)
-{
- AudioStream *audio;
- ms_init();
- ms_speex_codec_init();
- ms_ilbc_codec_init();
- signal(SIGINT,stop_handler);
-
- audio=audio_stream_start(&av_profile,localport,remote_ip,remoteport,payload,250);
- while(cond)
- {
- /* sleep until we receive SIGINT */
- sleep(1);
- }
-
- printf("stoping all...\n");
-
- audio_stream_stop(audio);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.h
deleted file mode 100644
index 3ccbab6..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mediastream.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MEDIASTREAM_H
-#define MEDIASTREAM_H
-
-#include "msrtprecv.h"
-#include "msrtpsend.h"
-#include "ms.h"
-#include "msosswrite.h"
-#include "msossread.h"
-#include "msread.h"
-#include "mswrite.h"
-#include "mstimer.h"
-#include "mscodec.h"
-#ifdef HAVE_SPEEX
-#include "msspeexdec.h"
-#endif
-#include "msringplayer.h"
-
-
-struct _AudioStream
-{
- MSSync *timer;
- RtpSession *send_session;
- RtpSession *recv_session;
- MSFilter *soundread;
- MSFilter *soundwrite;
- MSFilter *encoder;
- MSFilter *decoder;
- MSFilter *rtprecv;
- MSFilter *rtpsend;
-};
-
-
-typedef struct _AudioStream AudioStream;
-
-struct _RingStream
-{
- MSSync *timer;
- MSFilter *source;
- MSFilter *sndwrite;
-};
-
-typedef struct _RingStream RingStream;
-
-/* start a thread that does sampling->encoding->rtp_sending|rtp_receiving->decoding->playing */
-AudioStream *audio_stream_start (RtpProfile * prof, int locport, char *remip,
- int remport, int profile, int jitt_comp);
-
-AudioStream *audio_stream_start_with_sndcards(RtpProfile * prof, int locport, char *remip4,
- int remport, int profile, int jitt_comp, SndCard *playcard, SndCard *captcard);
-
-AudioStream *audio_stream_start_with_files (RtpProfile * prof, int locport,
- char *remip4, int remport,
- int profile, int jitt_comp,
- gchar * infile, gchar * outfile);
-void audio_stream_set_rtcp_information(AudioStream *st, const char *cname);
-
-
-/* stop the above process*/
-void audio_stream_stop (AudioStream * stream);
-
-RingStream *ring_start (gchar * file, gint interval, SndCard *sndcard);
-RingStream *ring_start_with_cb(gchar * file, gint interval, SndCard *sndcard, MSFilterNotifyFunc func,gpointer user_data);
-void ring_stop (RingStream * stream);
-
-/* returns the latency in samples if the audio device with id dev_id is openable in full duplex mode, else 0 */
-gint test_audio_dev (int dev_id);
-
-/* send a dtmf */
-gint audio_stream_send_dtmf (AudioStream * stream, gchar dtmf);
-
-void audio_stream_set_default_card(int cardindex);
-
-
-#ifdef VIDEO_ENABLED
-
-/*****************
- Video Support
- *****************/
-
-
-
-struct _VideoStream
-{
- MSSync *timer;
- RtpSession *send_session;
- RtpSession *recv_session;
- MSFilter *source;
- MSFilter *output;
- MSFilter *encoder;
- MSFilter *decoder;
- MSFilter *rtprecv;
- MSFilter *rtpsend;
- gboolean show_local;
-};
-
-
-typedef struct _VideoStream VideoStream;
-
-VideoStream *video_stream_start(RtpProfile *profile, int locport, char *remip4, int remport,
- int payload, int jitt_comp, gboolean show_local, const gchar *source, const gchar *device);
-void video_stream_set_rtcp_information(VideoStream *st, const char *cname);
-void video_stream_stop (VideoStream * stream);
-
-VideoStream * video_preview_start(const gchar *source, const gchar *device);
-void video_preview_stop(VideoStream *stream);
-
-#endif
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/ms.c b/third_party/libjingle/source/talk/third_party/mediastreamer/ms.c
deleted file mode 100644
index a4a57f8..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/ms.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "ms.h"
-#include "sndcard.h"
-#include "mscodec.h"
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef VIDEO_ENABLED
-extern void ms_video_source_register_all();
-#endif
-#ifdef HAVE_ILBC
-extern void ms_ilbc_codec_init();
-#endif
-
-/**
- * ms_init:
- *
- *
- * Initialize the mediastreamer. This must be the first function called in a program
- * using the mediastreamer library.
- *
- *
- */
-void ms_init()
-{
- if (!g_thread_supported()) g_thread_init (NULL);
-#ifdef HAVE_GLIB
- if (!g_module_supported()){
- g_error("GModule is not supported.");
- }
-#endif
- /* initialize the oss subsystem */
- snd_card_manager_init(snd_card_manager);
- /* register the statically linked codecs */
- ms_codec_register_all();
-#ifdef VIDEO_ENABLED
- ms_video_source_register_all();
-#endif
-#ifdef HAVE_ILBC
- ms_ilbc_codec_init();
-#endif
-}
-
-
-static gint compare(gconstpointer a, gconstpointer b)
-{
- MSFilter *f1=(MSFilter*)a,*f2=(MSFilter*)b;
- if (f1->klass<f2->klass) return -1;
- if (f1->klass==f2->klass) return 0;
- /* if f1->klass>f2->klass ....*/
- return 1;
-}
-
-static GList *g_list_append_if_new(GList *l,gpointer data)
-{
- GList *res=l;
- if (g_list_find(res,data)==NULL)
- res=g_list_append(res,data);
- return(res);
-}
-
-static GList *get_nexts(MSFilter *f,GList *l)
-{
- int i;
- MSFifo *fifo;
- MSQueue *q;
- GList *res=l;
-
- /* check fifos*/
- for (i=0;i <f->klass->max_foutputs;i++)
- {
- fifo=f->outfifos[i];
- if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data);
- }
- /* check queues*/
- for (i=0;i <f->klass->max_qoutputs;i++)
- {
- q=f->outqueues[i];
- if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data);
- }
- return(res);
-}
-
-/* compile graphs attached to a sync source*/
-int ms_compile(MSSync *sync)
-{
- int i;
- GList *list1=NULL,*list2=NULL,*elem;
- GList *proc_chain=NULL;
- MSFilter *f;
-
- /* first free the old list if we are just updating*/
- if (sync->execution_list!=NULL) g_list_free(sync->execution_list);
- /* get the list of filters attached to this sync*/
- for (i=0;i<sync->filters;i++)
- {
- //printf("found filter !\n");
- list1=g_list_append(list1,sync->attached_filters[i]);
- }
- /* find the processing chain */
- while (list1!=NULL)
- {
- list2=NULL;
- /* sort the list by types of filter*/
- list1=g_list_sort(list1,compare);
- /* save into the processing chain list*/
- //printf("list1 :%i elements\n",g_list_length(list1));
- proc_chain=g_list_concat(proc_chain,list1);
- /* get all following filters. They are appended to list2*/
- elem=list1;
- while (elem!=NULL)
- {
- f=(MSFilter*)(elem->data);
- /* check if filter 's status */
- if (f->klass->attributes & FILTER_CAN_SYNC)
- {
- sync->samples_per_tick=0;
- }
- list2=get_nexts(f,list2);
- elem=g_list_next(elem);
- }
- list1=list2;
- }
- sync->execution_list=proc_chain;
- sync->flags&=~MS_SYNC_NEED_UPDATE;
- ms_trace("%i filters successfully compiled in a processing chain.",g_list_length(sync->execution_list));
- return 0;
-}
-
-/*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/
-void *ms_thread_run(void *sync_ptr)
-{
- MSSync *sync=(MSSync*) sync_ptr;
- GList *filter;
- MSFilter *f;
-
-
- ms_sync_lock(sync);
- while(sync->run)
- {
- //g_message("sync->run=%i",sync->run);
- if (sync->samples_per_tick==0) ms_sync_suspend(sync);
- if (sync->flags & MS_SYNC_NEED_UPDATE){
- ms_compile(sync);
- ms_sync_setup(sync);
- }
- filter=sync->execution_list;
- ms_sync_unlock(sync);
- //ms_trace("Calling synchronisation");
- ms_sync_synchronize(sync);
- while(filter!=NULL)
- {
- f=(MSFilter*)filter->data;
- if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE)
- {
- /* execute it once */
- ms_trace("Running source filter %s.",f->klass->name);
- ms_filter_process(f);
- }
- else
- {
- /* make the filter process its input data until it has no more */
- while ( ms_filter_fifos_have_data(f) || ms_filter_queues_have_data(f) )
- {
- ms_trace("Running filter %s.",f->klass->name);
- ms_filter_process(f);
- }
- }
- filter=g_list_next(filter);
- }
- ms_sync_lock(sync);
- }
- g_cond_signal(sync->stop_cond); /* signal that the sync thread has finished */
- ms_sync_unlock(sync);
- g_message("Mediastreamer processing thread is exiting.");
- return NULL;
-}
-
-/* stop the processing chain attached to a sync source.*/
-void ms_thread_stop(MSSync *sync)
-{
- if (sync->thread!=NULL)
- {
- if (sync->samples_per_tick==0)
- {
- /* to wakeup the thread */
- //g_cond_signal(sync->thread_cond);
- }
- g_mutex_lock(sync->lock);
- sync->run=0;
- sync->thread=NULL;
- g_cond_wait(sync->stop_cond,sync->lock);
- g_mutex_unlock(sync->lock);
- }
- //g_message("ms_thread_stop() finished.");
-}
-
-/**
- * ms_start:
- * @sync: A synchronisation source to be started.
- *
- * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync.
- *
- *
- */
-void ms_start(MSSync *sync)
-{
- if (sync->run==1) return; /*already running*/
- ms_compile(sync);
- ms_sync_setup(sync);
- /* this is to avoid race conditions, for example:
- ms_start(sync);
- ms_oss_write_start(ossw);
- here tge ossw filter need to be compiled to run ms_oss_write_start()
- */
- ms_trace("ms_start: creating new thread.");
- sync->run=1;
- sync->thread=g_thread_create((GThreadFunc)ms_thread_run,(gpointer)sync,TRUE,NULL);
- if (sync->thread==NULL){
- g_warning("Could not create thread !");
- }
-}
-
-/**
- * ms_stop:
- * @sync: A synchronisation source to be stopped.
- *
- * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync.
- * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start().
- *
- *
- */
-void ms_stop(MSSync *sync)
-{
- ms_thread_stop(sync);
- ms_sync_unsetup(sync);
-}
-
-
-gint ms_load_plugin(gchar *path)
-{
-#ifdef HAVE_GLIB
- g_module_open(path,0);
-#endif
- return 0;
-}
-
-gchar * ms_proc_get_param(gchar *parameter)
-{
- gchar *file;
- int fd;
- int err,len;
- gchar *p,*begin,*end;
- gchar *ret;
- fd=open("/proc/cpuinfo",O_RDONLY);
- if (fd<0){
- g_warning("Could not open /proc/cpuinfo.");
- return NULL;
- }
- file=g_malloc(1024);
- err=read(fd,file,1024);
- file[err-1]='\0';
- /* find the parameter */
- p=strstr(file,parameter);
- if (p==NULL){
- /* parameter not found */
- g_free(file);
- return NULL;
- }
- /* find the following ':' */
- p=strchr(p,':');
- if (p==NULL){
- g_free(file);
- return NULL;
- }
- /* find the value*/
- begin=p+2;
- end=strchr(begin,'\n');
- if (end==NULL) end=strchr(begin,'\0');
- len=end-begin+1;
- ret=g_malloc(len+1);
- snprintf(ret,len,"%s",begin);
- //printf("%s=%s\n",parameter,ret);
- g_free(file);
- return ret;
-}
-
-gint ms_proc_get_type()
-{
- static int proc_type=0;
- gchar *value;
- if (proc_type==0){
- value=ms_proc_get_param("cpu family");
- if (value!=NULL) {
- proc_type=atoi(value);
- g_free(value);
- }else return -1;
- }
- return proc_type;
-}
-
-gint ms_proc_get_speed()
-{
- char *value;
- static int proc_speed=0;
- if (proc_speed==0){
- value=ms_proc_get_param("cpu MHz");
- if (value!=NULL){
- proc_speed=atoi(value);
- g_free(value);
- }else return -1;
- }
- //printf("proc_speed=%i\n",proc_speed);
- return proc_speed;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/ms.h b/third_party/libjingle/source/talk/third_party/mediastreamer/ms.h
deleted file mode 100644
index 51c69b9..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/ms.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-
-#ifndef MS_H
-#define MS_H
-#include "msfilter.h"
-#include "mssync.h"
-
-
-void ms_init();
-
-/* compile graphs attached to a sync source*/
-int ms_compile(MSSync *source);
-
-
-/* stop the processing chain attached to a sync source.*/
-void ms_thread_stop(MSSync *sync);
-
-
-/**
- * function_name:ms_thread_run
- * @sync: The synchronization source for all the set of graphs to run.
- *
- * Execute the processing chain attached to a sync source. This function loops indefinitely.
- * The media streamer programmer can choose to execute this function directly, or to call ms_start(),
- * that will start a thread for the synchronisation source.
- *
- * Returns: no return value.
- */
-void *ms_thread_run(void *sync);
-
-
-/**
- * function_name:ms_start
- * @sync: A synchronisation source to be started.
- *
- * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync.
- *
- * Returns: no return value.
- */
-void ms_start(MSSync *sync);
-
-
-/**
- * function_name:ms_stop
- * @sync: A synchronisation source to be stopped.
- *
- * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync.
- * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start().
- *
- * Returns: no return value.
- */
-void ms_stop(MSSync *sync);
-
-
-gchar * ms_proc_get_param(gchar *parameter);
-gint ms_proc_get_type();
-gint ms_proc_get_speed();
-
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.c
deleted file mode 100644
index 70cc906..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.c
+++ /dev/null
@@ -1,132 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include <msAlawdec.h>
-#include <g711common.h>
-
-extern MSFilter * ms_ALAWencoder_new(void);
-
-MSCodecInfo ALAWinfo={
- {
- "ALAW codec",
- 0,
- MS_FILTER_AUDIO_CODEC,
- ms_ALAWencoder_new,
- "This is the classic A-law codec. Good quality, but only usable with high speed network connections."
- },
- ms_ALAWencoder_new,
- ms_ALAWdecoder_new,
- 320,
- 160,
- 64000,
- 8000,
- 8,
- "PCMA",
- 1,
- 1,
-};
-
-static MSALAWDecoderClass *ms_ALAWdecoder_class=NULL;
-
-MSFilter * ms_ALAWdecoder_new(void)
-{
- MSALAWDecoder *r;
-
- r=g_new(MSALAWDecoder,1);
- ms_ALAWdecoder_init(r);
- if (ms_ALAWdecoder_class==NULL)
- {
- ms_ALAWdecoder_class=g_new(MSALAWDecoderClass,1);
- ms_ALAWdecoder_class_init(ms_ALAWdecoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ALAWdecoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_ALAWdecoder_init(MSALAWDecoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=ALAW_DECODER_RMAXGRAN;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWDECODER_MAX_INPUTS);
-
-}
-
-void ms_ALAWdecoder_class_init(MSALAWDecoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWDecoder");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo;
- MS_FILTER_CLASS(klass)->max_finputs=MSALAWDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSALAWDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=ALAW_DECODER_RMAXGRAN;
- MS_FILTER_CLASS(klass)->w_maxgran=ALAW_DECODER_WMAXGRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWdecoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWdecoder_process;
-}
-
-void ms_ALAWdecoder_process(MSALAWDecoder *r)
-{
- MSFifo *fi,*fo;
- int inlen,outlen;
- gchar *s,*d;
- int i;
- /* process output fifos, but there is only one for this class of filter*/
-
- /* this is the simplest process function design:
- the filter declares a r_mingran of ALAW_DECODER_RMAXGRAN, so the mediastreamer's
- scheduler will call the process function each time there is ALAW_DECODER_RMAXGRAN
- bytes to read in the input fifo. If there is more, then it will call it several
- time in order to the fifo to be completetly processed.
- This is very simple, but not very efficient because of the multiple call function
- of MSFilterProcessFunc that may happen.
- The MSAlawEncoder implements another design; see it.
- */
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
- g_return_if_fail(fi!=NULL);
- g_return_if_fail(fo!=NULL);
-
- inlen=ms_fifo_get_read_ptr(fi,ALAW_DECODER_RMAXGRAN,(void**)&s);
- if (s==NULL) return;
- outlen=ms_fifo_get_write_ptr(fo,ALAW_DECODER_WMAXGRAN,(void**)&d);
- if (d!=NULL)
- {
- for(i=0;i<ALAW_DECODER_RMAXGRAN;i++)
- {
- ((gint16*)d)[i]=alaw_to_s16( (unsigned char) s[i]);
- }
- }
- else g_warning("MSALAWDecoder: Discarding samples !!");
-
-}
-
-
-
-void ms_ALAWdecoder_destroy( MSALAWDecoder *obj)
-{
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.h
deleted file mode 100644
index 7db4c75..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawdec.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSALAWDECODER_H
-#define MSALAWDECODER_H
-
-#include <msfilter.h>
-#include <mscodec.h>
-
-/*this is the class that implements a ALAWdecoder filter*/
-
-#define MSALAWDECODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSALAWDecoder
-{
- /* the MSALAWDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSALAWDecoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSALAWDECODER_MAX_INPUTS];
- MSFifo *f_outputs[MSALAWDECODER_MAX_INPUTS];
-} MSALAWDecoder;
-
-typedef struct _MSALAWDecoderClass
-{
- /* the MSALAWDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSALAWDecoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSALAWDecoderClass;
-
-/* PUBLIC */
-#define MS_ALAWDECODER(filter) ((MSALAWDecoder*)(filter))
-#define MS_ALAWDECODER_CLASS(klass) ((MSALAWDecoderClass*)(klass))
-MSFilter * ms_ALAWdecoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_ALAWdecoder_init(MSALAWDecoder *r);
-void ms_ALAWdecoder_class_init(MSALAWDecoderClass *klass);
-void ms_ALAWdecoder_destroy( MSALAWDecoder *obj);
-void ms_ALAWdecoder_process(MSALAWDecoder *r);
-
-/* tuning parameters :*/
-#define ALAW_DECODER_WMAXGRAN 320
-#define ALAW_DECODER_RMAXGRAN 160
-
-extern MSCodecInfo ALAWinfo;
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.c
deleted file mode 100644
index fd1f9ab..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.c
+++ /dev/null
@@ -1,124 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msAlawenc.h"
-#include "g711common.h"
-
-extern MSCodecInfo ALAWinfo;
-
-static MSALAWEncoderClass *ms_ALAWencoder_class=NULL;
-
-MSFilter * ms_ALAWencoder_new(void)
-{
- MSALAWEncoder *r;
-
- r=g_new(MSALAWEncoder,1);
- ms_ALAWencoder_init(r);
- if (ms_ALAWencoder_class==NULL)
- {
- ms_ALAWencoder_class=g_new(MSALAWEncoderClass,1);
- ms_ALAWencoder_class_init(ms_ALAWencoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ALAWencoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_ALAWencoder_init(MSALAWEncoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=ALAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is
- something to process */
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSALAWENCODER_MAX_INPUTS);
-
-}
-
-void ms_ALAWencoder_class_init(MSALAWEncoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ALAWEncoder");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ALAWinfo;
- MS_FILTER_CLASS(klass)->max_finputs=MSALAWENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSALAWENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=ALAW_ENCODER_RMAXGRAN;
- MS_FILTER_CLASS(klass)->w_maxgran=ALAW_ENCODER_WMAXGRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ALAWencoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ALAWencoder_process;
-}
-
-void ms_ALAWencoder_process(MSALAWEncoder *r)
-{
- MSFifo *fi,*fo;
- int inlen,outlen;
- gchar *s,*d;
- int i;
- /* process output fifos, but there is only one for this class of filter*/
-
- /* this is the sophisticated design of the process function:
- Here the filter declares that it can be called as soon as there is something
- to read on the input fifo by setting r_mingran=0.
- Then it ask for the fifo to get as many data as possible by calling:
- inlen=ms_fifo_get_read_ptr(fi,0,(void**)&s);
- This avoid multiple call to the process function to process all data available
- on the input fifo... but the writing of the process function is a bit
- more difficult, because althoug ms_fifo_get_read_ptr() returns N bytes,
- we cannot ask ms_fifo_get_write_ptr to return N bytes if
- N>MS_FILTER_CLASS(klass)->w_maxgran. This is forbidden by the MSFifo
- mechanism.
- This is an open issue.
- For the moment what is done here is that ms_fifo_get_write_ptr() is called
- several time with its maximum granularity in order to try to write the output.
- ...
- One solution:
- -create a new function ms_fifo_get_rw_ptr(fifo1,p1, fifo2,p2) to
- return the number of bytes able to being processed according to the input
- and output fifo, and their respective data pointers
- */
-
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
-
- inlen=ms_fifo_get_read_ptr(fi,ALAW_ENCODER_RMAXGRAN,(void**)&s);
- if (s==NULL) return;
- outlen=ms_fifo_get_write_ptr(fo,ALAW_ENCODER_WMAXGRAN,(void**)&d);
- if (d!=NULL)
- {
- for(i=0;i<ALAW_ENCODER_WMAXGRAN;i++)
- {
- d[i]=s16_to_alaw( *((gint16*)s) );
- s+=2;
- }
- }
- else g_warning("MSALAWDecoder: Discarding samples !!");
-
-}
-
-
-
-void ms_ALAWencoder_destroy( MSALAWEncoder *obj)
-{
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.h
deleted file mode 100644
index 608a988..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msAlawenc.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSALAWENCODER_H
-#define MSALAWENCODER_H
-
-#include "mscodec.h"
-
-
-/*this is the class that implements a ALAWencoder filter*/
-
-#define MSALAWENCODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSALAWEncoder
-{
- /* the MSALAWEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSALAWEncoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSALAWENCODER_MAX_INPUTS];
- MSFifo *f_outputs[MSALAWENCODER_MAX_INPUTS];
-} MSALAWEncoder;
-
-typedef struct _MSALAWEncoderClass
-{
- /* the MSALAWEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSALAWEncoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSALAWEncoderClass;
-
-/* PUBLIC */
-#define MS_ALAWENCODER(filter) ((MSALAWEncoder*)(filter))
-#define MS_ALAWENCODER_CLASS(klass) ((MSALAWEncoderClass*)(klass))
-MSFilter * ms_ALAWencoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_ALAWencoder_init(MSALAWEncoder *r);
-void ms_ALAWencoder_class_init(MSALAWEncoderClass *klass);
-void ms_ALAWencoder_destroy( MSALAWEncoder *obj);
-void ms_ALAWencoder_process(MSALAWEncoder *r);
-
-/* tuning parameters :*/
-#define ALAW_ENCODER_WMAXGRAN 160
-#define ALAW_ENCODER_RMAXGRAN 320
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.c
deleted file mode 100644
index 1c18517..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msGSMdecoder.h"
-
-extern MSFilter * ms_GSMencoder_new(void);
-
-MSCodecInfo GSMinfo={
- {
- "GSM codec",
- 0,
- MS_FILTER_AUDIO_CODEC,
- ms_GSMencoder_new,
- "This is the codec widely used in european mobile phones. This implementation was done by "
- "Jutta Degener and Carsten Bormann."
- },
- ms_GSMencoder_new,
- ms_GSMdecoder_new,
- 320,
- 33,
- 13800,
- 8000,
- 3,
- "GSM",
- 1,
- 1,
-};
-
-static MSGSMDecoderClass *ms_GSMdecoder_class=NULL;
-
-MSFilter * ms_GSMdecoder_new(void)
-{
- MSGSMDecoder *r;
-
- r=g_new(MSGSMDecoder,1);
- ms_GSMdecoder_init(r);
- if (ms_GSMdecoder_class==NULL)
- {
- ms_GSMdecoder_class=g_new(MSGSMDecoderClass,1);
- ms_GSMdecoder_class_init(ms_GSMdecoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_GSMdecoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_GSMdecoder_init(MSGSMDecoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=33;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSGSMDECODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSGSMDECODER_MAX_INPUTS);
- r->gsm_handle=gsm_create();
-}
-
-void ms_GSMdecoder_class_init(MSGSMDecoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"GSMDecoder");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&GSMinfo;
- MS_FILTER_CLASS(klass)->max_finputs=MSGSMDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSGSMDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=33;
- MS_FILTER_CLASS(klass)->w_maxgran=2*160;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_GSMdecoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_GSMdecoder_process;
-}
-
-void ms_GSMdecoder_process(MSGSMDecoder *r)
-{
- MSFifo *fi,*fo;
- int err1;
- void *s,*d;
-
- /* process output fifos, but there is only one for this class of filter*/
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
- if (fi!=NULL)
- {
- err1=ms_fifo_get_read_ptr(fi,33,&s);
- if (err1>0)
- {
- err1=ms_fifo_get_write_ptr(fo,160*2,&d);
- if (d!=NULL) gsm_decode(r->gsm_handle,s,(gsm_signal*)d);
- }
-
- }
-}
-
-void ms_GSMdecoder_uninit(MSGSMDecoder *obj)
-{
- gsm_destroy(obj->gsm_handle);
-}
-
-void ms_GSMdecoder_destroy( MSGSMDecoder *obj)
-{
- ms_GSMdecoder_uninit(obj);
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.h
deleted file mode 100644
index e73fb33..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMdecoder.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSGSMDECODER_H
-#define MSGSMDECODER_H
-
-#include <msfilter.h>
-#include <mscodec.h>
-#include <gsm.h>
-
-/*this is the class that implements a GSMdecoder filter*/
-
-#define MSGSMDECODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSGSMDecoder
-{
- /* the MSGSMDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMDecoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSGSMDECODER_MAX_INPUTS];
- MSFifo *f_outputs[MSGSMDECODER_MAX_INPUTS];
- gsm gsm_handle;
-} MSGSMDecoder;
-
-typedef struct _MSGSMDecoderClass
-{
- /* the MSGSMDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMDecoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSGSMDecoderClass;
-
-/* PUBLIC */
-#define MS_GSMDECODER(filter) ((MSGSMDecoder*)(filter))
-#define MS_GSMDECODER_CLASS(klass) ((MSGSMDecoderClass*)(klass))
-MSFilter * ms_GSMdecoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_GSMdecoder_init(MSGSMDecoder *r);
-void ms_GSMdecoder_class_init(MSGSMDecoderClass *klass);
-void ms_GSMdecoder_destroy( MSGSMDecoder *obj);
-void ms_GSMdecoder_process(MSGSMDecoder *r);
-
-extern MSCodecInfo GSMinfo;
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.c
deleted file mode 100644
index 44570d7..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msGSMencoder.h"
-#include "mscodec.h"
-
-extern MSCodecInfo GSMinfo;
-
-static MSGSMEncoderClass *ms_GSMencoder_class=NULL;
-
-MSFilter * ms_GSMencoder_new(void)
-{
- MSGSMEncoder *r;
-
- r=g_new(MSGSMEncoder,1);
- ms_GSMencoder_init(r);
- if (ms_GSMencoder_class==NULL)
- {
- ms_GSMencoder_class=g_new(MSGSMEncoderClass,1);
- ms_GSMencoder_class_init(ms_GSMencoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_GSMencoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_GSMencoder_init(MSGSMEncoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=2*160;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSGSMENCODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSGSMENCODER_MAX_INPUTS);
- r->gsm_handle=gsm_create();
-}
-
-void ms_GSMencoder_class_init(MSGSMEncoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"GSMEncoder");
- MS_FILTER_CLASS(klass)->max_finputs=MSGSMENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSGSMENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=2*160;
- MS_FILTER_CLASS(klass)->w_maxgran=33;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_GSMencoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_GSMencoder_process;
- MS_FILTER_CLASS(klass)->info=MS_FILTER_INFO(&GSMinfo);
-}
-
-void ms_GSMencoder_process(MSGSMEncoder *r)
-{
- MSFifo *fi,*fo;
- int err1;
- void *s,*d;
-
- /* process output fifos, but there is only one for this class of filter*/
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
- if (fi!=NULL)
- {
- err1=ms_fifo_get_read_ptr(fi,160*2,&s);
- if (err1>0)
- {
- err1=ms_fifo_get_write_ptr(fo,33,&d);
- if (d!=NULL) gsm_encode(r->gsm_handle,(gsm_signal*)s,(gsm_byte*)d);
- }
-
- }
-}
-
-void ms_GSMencoder_uninit(MSGSMEncoder *obj)
-{
- gsm_destroy(obj->gsm_handle);
-}
-
-void ms_GSMencoder_destroy( MSGSMEncoder *obj)
-{
- ms_GSMencoder_uninit(obj);
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.h
deleted file mode 100644
index 2deae38..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msGSMencoder.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSGSMENCODER_H
-#define MSGSMENCODER_H
-
-#include "msfilter.h"
-#include <gsm.h>
-
-/*this is the class that implements a GSMencoder filter*/
-
-#define MSGSMENCODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSGSMEncoder
-{
- /* the MSGSMEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSGSMEncoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSGSMENCODER_MAX_INPUTS];
- MSFifo *f_outputs[MSGSMENCODER_MAX_INPUTS];
- gsm gsm_handle;
-} MSGSMEncoder;
-
-typedef struct _MSGSMEncoderClass
-{
- /* the MSGSMEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSGSMEncoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSGSMEncoderClass;
-
-/* PUBLIC */
-#define MS_GSMENCODER(filter) ((MSGSMEncoder*)(filter))
-#define MS_GSMENCODER_CLASS(klass) ((MSGSMEncoderClass*)(klass))
-MSFilter * ms_GSMencoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_GSMencoder_init(MSGSMEncoder *r);
-void ms_GSMencoder_class_init(MSGSMEncoderClass *klass);
-void ms_GSMencoder_destroy( MSGSMEncoder *obj);
-void ms_GSMencoder_process(MSGSMEncoder *r);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.c
deleted file mode 100644
index 1d398be..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msLPC10decoder.h"
-#include "msLPC10encoder.h"
-#include <stdlib.h>
-#include <lpc10.h>
-
-extern MSFilter * ms_LPC10encoder_new(void);
-
-MSCodecInfo LPC10info={
- {
- "LPC10-15 codec",
- 0,
- MS_FILTER_AUDIO_CODEC,
- ms_LPC10encoder_new,
- "A low quality but very low bit rate codec from the U.S. Department of Defense."
- },
- ms_LPC10encoder_new,
- ms_LPC10decoder_new,
- 360,
- 7,
- 2400,
- 8000,
- 115,
- "1015",
- 1,
- 1,
-};
-
-static MSLPC10DecoderClass *ms_LPC10decoder_class=NULL;
-
-MSFilter * ms_LPC10decoder_new(void)
-{
- MSLPC10Decoder *r;
-
- r=g_new(MSLPC10Decoder,1);
- ms_LPC10decoder_init(r);
- if (ms_LPC10decoder_class==NULL)
- {
- ms_LPC10decoder_class=g_new(MSLPC10DecoderClass,1);
- ms_LPC10decoder_class_init(ms_LPC10decoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_LPC10decoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_LPC10decoder_init(MSLPC10Decoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=7;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSLPC10DECODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSLPC10DECODER_MAX_INPUTS);
- r->lpc10_dec=create_lpc10_decoder_state();
-}
-
-void ms_LPC10decoder_class_init(MSLPC10DecoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"LPC10Dec");
- MS_FILTER_CLASS(klass)->max_finputs=MSLPC10DECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSLPC10DECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=7;
- MS_FILTER_CLASS(klass)->w_maxgran=LPC10_SAMPLES_PER_FRAME*2;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_LPC10decoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_LPC10decoder_process;
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&LPC10info;
-}
-
-void ms_LPC10decoder_process(MSLPC10Decoder *r)
-{
- MSFifo *fi,*fo;
- int err1;
- void *s,*d;
- float speech[LPC10_SAMPLES_PER_FRAME];
- INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
-
- /* process output fifos, but there is only one for this class of filter*/
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
- if (fi!=NULL)
- {
- err1=ms_fifo_get_read_ptr(fi,7,&s);
- if (err1>0)
- {
- err1=ms_fifo_get_write_ptr(fo,LPC10_SAMPLES_PER_FRAME*2,&d);
- if (d!=NULL)
- {
- read_bits(s, bits, LPC10_BITS_IN_COMPRESSED_FRAME);
- lpc10_decode(bits,speech, r->lpc10_dec);
- write_16bit_samples((INT16*)d, speech, LPC10_SAMPLES_PER_FRAME);
- }
- }
- }
-}
-
-void ms_LPC10decoder_uninit(MSLPC10Decoder *obj)
-{
- free(obj->lpc10_dec);
-}
-
-void ms_LPC10decoder_destroy( MSLPC10Decoder *obj)
-{
- ms_LPC10decoder_uninit(obj);
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.h
deleted file mode 100644
index 59d9dec..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10decoder.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSLPC10DECODER_H
-#define MSLPC10DECODER_H
-
-#include <msfilter.h>
-#include <mscodec.h>
-#include <lpc10.h>
-
-/*this is the class that implements a LPC10decoder filter*/
-
-#define MSLPC10DECODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSLPC10Decoder
-{
- /* the MSLPC10Decoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Decoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSLPC10DECODER_MAX_INPUTS];
- MSFifo *f_outputs[MSLPC10DECODER_MAX_INPUTS];
- struct lpc10_decoder_state *lpc10_dec;
-} MSLPC10Decoder;
-
-typedef struct _MSLPC10DecoderClass
-{
- /* the MSLPC10Decoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Decoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSLPC10DecoderClass;
-
-/* PUBLIC */
-#define MS_LPC10DECODER(filter) ((MSLPC10Decoder*)(filter))
-#define MS_LPC10DECODER_CLASS(klass) ((MSLPC10DecoderClass*)(klass))
-MSFilter * ms_LPC10decoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_LPC10decoder_init(MSLPC10Decoder *r);
-void ms_LPC10decoder_class_init(MSLPC10DecoderClass *klass);
-void ms_LPC10decoder_destroy( MSLPC10Decoder *obj);
-void ms_LPC10decoder_process(MSLPC10Decoder *r);
-
-extern MSCodecInfo LPC10info;
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.c
deleted file mode 100644
index 2c083f3..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <stdlib.h>
-#include "msLPC10encoder.h"
-#include <lpc10.h>
-
-
-extern MSCodecInfo LPC10info;
-
-/* The return value of each of these calls is the same as that
- returned by fread/fwrite, which should be the number of samples
- successfully read/written, not the number of bytes. */
-
-int
-read_16bit_samples(INT16 int16samples[], float speech[], int n)
-{
- int i;
-
- /* Convert 16 bit integer samples to floating point values in the
- range [-1,+1]. */
-
- for (i = 0; i < n; i++) {
- speech[i] = ((float) int16samples[i]) / 32768.0;
- }
-
- return (n);
-}
-
-
-
-int
-write_16bit_samples(INT16 int16samples[], float speech[], int n)
-{
- int i;
- float real_sample;
-
- /* Convert floating point samples in range [-1,+1] to 16 bit
- integers. */
- for (i = 0; i < n; i++) {
- real_sample = 32768.0 * speech[i];
- if (real_sample < -32768.0) {
- int16samples[i] = -32768;
- } else if (real_sample > 32767.0) {
- int16samples[i] = 32767;
- } else {
- int16samples[i] = real_sample;
- }
- }
- return (n);
-}
-
-/*
-
-Write the bits in bits[0] through bits[len-1] to file f, in "packed"
-format.
-
-bits is expected to be an array of len integer values, where each
-integer is 0 to represent a 0 bit, and any other value represents a 1
-bit. This bit string is written to the file f in the form of several
-8 bit characters. If len is not a multiple of 8, then the last
-character is padded with 0 bits -- the padding is in the least
-significant bits of the last byte. The 8 bit characters are "filled"
-in order from most significant bit to least significant.
-
-*/
-
-void
-write_bits(unsigned char *data, INT32 *bits, int len)
-{
- int i; /* generic loop variable */
- unsigned char mask; /* The next bit position within the
- variable "data" to place the next
- bit. */
-
-
- /* Fill in the array bits.
- * The first compressed output bit will be the most significant
- * bit of the byte, so initialize mask to 0x80. The next byte of
- * compressed data is initially 0, and the desired bits will be
- * turned on below.
- */
- mask = 0x80;
- *data = 0;
-
- for (i = 0; i < len; i++) {
- /* Turn on the next bit of output data, if necessary. */
- if (bits[i]) {
- (*data) |= mask;
- }
- /*
- * If the byte data is full, determined by mask becoming 0,
- * then write the byte to the output file, and reinitialize
- * data and mask for the next output byte. Also add the byte
- * if (i == len-1), because if len is not a multiple of 8,
- * then mask won't yet be 0. */
- mask >>= 1;
- if ((mask == 0) || (i == len-1)) {
- data++;
- *data = 0;
- mask = 0x80;
- }
- }
-}
-
-
-
-/*
-
-Read bits from file f into bits[0] through bits[len-1], in "packed"
-format.
-
-Read ceiling(len/8) characters from file f, if that many are available
-to read, otherwise read to the end of the file. The first character's
-8 bits, in order from MSB to LSB, are used to fill bits[0] through
-bits[7]. The second character's bits are used to fill bits[8] through
-bits[15], and so on. If ceiling(len/8) characters are available to
-read, and len is not a multiple of 8, then some of the least
-significant bits of the last character read are completely ignored.
-Every entry of bits[] that is modified is changed to either a 0 or a
-1.
-
-The number of bits successfully read is returned, and is always in the
-range 0 to len, inclusive. If it is less than len, it will always be
-a multiple of 8.
-
-*/
-
-int
-read_bits(unsigned char *data, INT32 *bits, int len)
-{
- int i,ind=0; /* generic loop variable */
- int c=0;
-
- /* Unpack the array bits into coded_frame. */
- for (i = 0; i < len; i++) {
- if ((i % 8) == 0) {
- c = (int)(data[ind]);
- ind++;
- }
- if (c & (0x80 >> (i & 7))) {
- bits[i] = 1;
- } else {
- bits[i] = 0;
- }
- }
- return (len);
-}
-
-
-
-
-static MSLPC10EncoderClass *ms_LPC10encoder_class=NULL;
-
-MSFilter * ms_LPC10encoder_new(void)
-{
- MSLPC10Encoder *r;
-
- r=g_new(MSLPC10Encoder,1);
- ms_LPC10encoder_init(r);
- if (ms_LPC10encoder_class==NULL)
- {
- ms_LPC10encoder_class=g_new(MSLPC10EncoderClass,1);
- ms_LPC10encoder_class_init(ms_LPC10encoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_LPC10encoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_LPC10encoder_init(MSLPC10Encoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=LPC10_SAMPLES_PER_FRAME*2;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSLPC10ENCODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSLPC10ENCODER_MAX_INPUTS);
- r->lpc10_enc=create_lpc10_encoder_state();
-}
-
-void ms_LPC10encoder_class_init(MSLPC10EncoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"LPC10Enc");
- MS_FILTER_CLASS(klass)->max_finputs=MSLPC10ENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSLPC10ENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=LPC10_SAMPLES_PER_FRAME*2;
- MS_FILTER_CLASS(klass)->w_maxgran=7;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_LPC10encoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_LPC10encoder_process;
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&LPC10info;
-}
-
-void ms_LPC10encoder_process(MSLPC10Encoder *r)
-{
- MSFifo *fi,*fo;
- int err1;
- void *s,*d;
- float speech[LPC10_SAMPLES_PER_FRAME];
- INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
-
- /* process output fifos, but there is only one for this class of filter*/
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
- if (fi!=NULL)
- {
- err1=ms_fifo_get_read_ptr(fi,LPC10_SAMPLES_PER_FRAME*2,&s);
- if (err1>0)
- {
- err1=ms_fifo_get_write_ptr(fo,7,&d);
- if (d!=NULL)
- {
- read_16bit_samples((INT16*)s, speech, LPC10_SAMPLES_PER_FRAME);
- lpc10_encode(speech, bits, r->lpc10_enc);
- write_bits(d, bits, LPC10_BITS_IN_COMPRESSED_FRAME);
- }
- }
-
- }
-}
-
-void ms_LPC10encoder_uninit(MSLPC10Encoder *obj)
-{
- free(obj->lpc10_enc);
-}
-
-void ms_LPC10encoder_destroy( MSLPC10Encoder *obj)
-{
- ms_LPC10encoder_uninit(obj);
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.h
deleted file mode 100644
index 4db1643..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msLPC10encoder.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSLPC10ENCODER_H
-#define MSLPC10ENCODER_H
-
-#include "mscodec.h"
-
-
-int
-read_16bit_samples(gint16 int16samples[], float speech[], int n);
-
-int
-write_16bit_samples(gint16 int16samples[], float speech[], int n);
-
-void
-write_bits(unsigned char *data, gint32 *bits, int len);
-
-int
-read_bits(unsigned char *data, gint32 *bits, int len);
-
-
-/*this is the class that implements a LPC10encoder filter*/
-
-#define MSLPC10ENCODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSLPC10Encoder
-{
- /* the MSLPC10Encoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSLPC10Encoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSLPC10ENCODER_MAX_INPUTS];
- MSFifo *f_outputs[MSLPC10ENCODER_MAX_INPUTS];
- struct lpc10_encoder_state *lpc10_enc;
-} MSLPC10Encoder;
-
-typedef struct _MSLPC10EncoderClass
-{
- /* the MSLPC10Encoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSLPC10Encoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSLPC10EncoderClass;
-
-/* PUBLIC */
-#define MS_LPC10ENCODER(filter) ((MSLPC10Encoder*)(filter))
-#define MS_LPC10ENCODER_CLASS(klass) ((MSLPC10EncoderClass*)(klass))
-MSFilter * ms_LPC10encoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_LPC10encoder_init(MSLPC10Encoder *r);
-void ms_LPC10encoder_class_init(MSLPC10EncoderClass *klass);
-void ms_LPC10encoder_destroy( MSLPC10Encoder *obj);
-void ms_LPC10encoder_process(MSLPC10Encoder *r);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.c
deleted file mode 100644
index 500f238..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.c
+++ /dev/null
@@ -1,130 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include <msMUlawdec.h>
-#include <g711common.h>
-
-extern MSFilter * ms_MULAWencoder_new(void);
-
-MSCodecInfo MULAWinfo={
- {
- "MULAW codec",
- 0,
- MS_FILTER_AUDIO_CODEC,
- ms_MULAWencoder_new,
- "This is the classic Mu-law codec. Good quality, but only usable with high speed network connections."
- },
- ms_MULAWencoder_new,
- ms_MULAWdecoder_new,
- 320,
- 160,
- 64000,
- 8000,
- 0,
- "PCMU",
- 1,
- 1
-};
-
-static MSMULAWDecoderClass *ms_MULAWdecoder_class=NULL;
-
-MSFilter * ms_MULAWdecoder_new(void)
-{
- MSMULAWDecoder *r;
-
- r=g_new(MSMULAWDecoder,1);
- ms_MULAWdecoder_init(r);
- if (ms_MULAWdecoder_class==NULL)
- {
- ms_MULAWdecoder_class=g_new(MSMULAWDecoderClass,1);
- ms_MULAWdecoder_class_init(ms_MULAWdecoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_MULAWdecoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_MULAWdecoder_init(MSMULAWDecoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=MULAW_DECODER_RMAXGRAN;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWDECODER_MAX_INPUTS);
-
-}
-
-void ms_MULAWdecoder_class_init(MSMULAWDecoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWDecoder");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo;
- MS_FILTER_CLASS(klass)->max_finputs=MSMULAWDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=MULAW_DECODER_RMAXGRAN;
- MS_FILTER_CLASS(klass)->w_maxgran=MULAW_DECODER_WMAXGRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWdecoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWdecoder_process;
-}
-
-void ms_MULAWdecoder_process(MSMULAWDecoder *r)
-{
- MSFifo *fi,*fo;
- int inlen,outlen;
- gchar *s,*d;
- int i;
- /* process output fifos, but there is only one for this class of filter*/
-
- /* this is the simplest process function design:
- the filter declares a r_mingran of MULAW_DECODER_RMAXGRAN, so the mediastreamer's
- scheduler will call the process function each time there is MULAW_DECODER_RMAXGRAN
- bytes to read in the input fifo. If there is more, then it will call it several
- time in order to the fifo to be completetly processed.
- This is very simple, but not very efficient because of the multiple call function
- of MSFilterProcessFunc that may happen.
- The MSAlawEncoder implements another design; see it.
- */
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
-
- inlen=ms_fifo_get_read_ptr(fi,MULAW_DECODER_RMAXGRAN,(void**)&s);
- if (s==NULL) g_error("ms_MULAWdecoder_process: internal error.");
- outlen=ms_fifo_get_write_ptr(fo,MULAW_DECODER_WMAXGRAN,(void**)&d);
- if (d!=NULL)
- {
- for(i=0;i<MULAW_DECODER_RMAXGRAN;i++)
- {
- *((gint16*)d)=ulaw_to_s16( (unsigned char) s[i]);
- d+=2;
- }
- }
- else g_warning("MSMULAWDecoder: Discarding samples !!");
-}
-
-
-
-void ms_MULAWdecoder_destroy( MSMULAWDecoder *obj)
-{
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.h
deleted file mode 100644
index c135d21..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawdec.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSMULAWDECODER_H
-#define MSMULAWDECODER_H
-
-#include <msfilter.h>
-#include <mscodec.h>
-
-/*this is the class that implements a MULAWdecoder filter*/
-
-#define MSMULAWDECODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSMULAWDecoder
-{
- /* the MSMULAWDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSMULAWDecoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSMULAWDECODER_MAX_INPUTS];
- MSFifo *f_outputs[MSMULAWDECODER_MAX_INPUTS];
-} MSMULAWDecoder;
-
-typedef struct _MSMULAWDecoderClass
-{
- /* the MSMULAWDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSMULAWDecoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSMULAWDecoderClass;
-
-/* PUBLIC */
-#define MS_MULAWDECODER(filter) ((MSMULAWDecoder*)(filter))
-#define MS_MULAWDECODER_CLASS(klass) ((MSMULAWDecoderClass*)(klass))
-MSFilter * ms_MULAWdecoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_MULAWdecoder_init(MSMULAWDecoder *r);
-void ms_MULAWdecoder_class_init(MSMULAWDecoderClass *klass);
-void ms_MULAWdecoder_destroy( MSMULAWDecoder *obj);
-void ms_MULAWdecoder_process(MSMULAWDecoder *r);
-
-/* tuning parameters :*/
-#define MULAW_DECODER_WMAXGRAN 320
-#define MULAW_DECODER_RMAXGRAN 160
-
-extern MSCodecInfo MULAWinfo;
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.c
deleted file mode 100644
index 2f740d8..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.c
+++ /dev/null
@@ -1,99 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msMUlawenc.h"
-#include "g711common.h"
-
-extern MSCodecInfo MULAWinfo;
-
-static MSMULAWEncoderClass *ms_MULAWencoder_class=NULL;
-
-MSFilter * ms_MULAWencoder_new(void)
-{
- MSMULAWEncoder *r;
-
- r=g_new(MSMULAWEncoder,1);
- ms_MULAWencoder_init(r);
- if (ms_MULAWencoder_class==NULL)
- {
- ms_MULAWencoder_class=g_new(MSMULAWEncoderClass,1);
- ms_MULAWencoder_class_init(ms_MULAWencoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_MULAWencoder_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_MULAWencoder_init(MSMULAWEncoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=MULAW_ENCODER_RMAXGRAN; /* the filter can be called as soon as there is
- something to process */
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSMULAWENCODER_MAX_INPUTS);
-
-}
-
-void ms_MULAWencoder_class_init(MSMULAWEncoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"MULAWEncoder");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&MULAWinfo;
- MS_FILTER_CLASS(klass)->max_finputs=MSMULAWENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSMULAWENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=MULAW_ENCODER_RMAXGRAN;
- MS_FILTER_CLASS(klass)->w_maxgran=MULAW_ENCODER_WMAXGRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_MULAWencoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_MULAWencoder_process;
-}
-
-void ms_MULAWencoder_process(MSMULAWEncoder *r)
-{
- MSFifo *fi,*fo;
- int inlen,outlen;
- gchar *s,*d;
- int i;
- /* process output fifos, but there is only one for this class of filter*/
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
- inlen=ms_fifo_get_read_ptr(fi,MULAW_ENCODER_RMAXGRAN,(void**)&s);
- outlen=ms_fifo_get_write_ptr(fo,MULAW_ENCODER_WMAXGRAN,(void**)&d);
- if (d!=NULL)
- {
- for(i=0;i<MULAW_ENCODER_WMAXGRAN;i++)
- {
- d[i]=s16_to_ulaw( *((gint16*)s) );
- s+=2;
- }
- }
- else g_warning("MSMULAWDecoder: Discarding samples !!");
-}
-
-
-
-void ms_MULAWencoder_destroy( MSMULAWEncoder *obj)
-{
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.h
deleted file mode 100644
index 52f7666..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msMUlawenc.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSMULAWENCODER_H
-#define MSMULAWENCODER_H
-
-#include "mscodec.h"
-
-
-/*this is the class that implements a MULAWencoder filter*/
-
-#define MSMULAWENCODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSMULAWEncoder
-{
- /* the MSMULAWEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSMULAWEncoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSMULAWENCODER_MAX_INPUTS];
- MSFifo *f_outputs[MSMULAWENCODER_MAX_INPUTS];
-} MSMULAWEncoder;
-
-typedef struct _MSMULAWEncoderClass
-{
- /* the MSMULAWEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSMULAWEncoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSMULAWEncoderClass;
-
-/* PUBLIC */
-#define MS_MULAWENCODER(filter) ((MSMULAWEncoder*)(filter))
-#define MS_MULAWENCODER_CLASS(klass) ((MSMULAWEncoderClass*)(klass))
-MSFilter * ms_MULAWencoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_MULAWencoder_init(MSMULAWEncoder *r);
-void ms_MULAWencoder_class_init(MSMULAWEncoderClass *klass);
-void ms_MULAWencoder_destroy( MSMULAWEncoder *obj);
-void ms_MULAWencoder_process(MSMULAWEncoder *r);
-
-/* tuning parameters :*/
-#define MULAW_ENCODER_WMAXGRAN 160
-#define MULAW_ENCODER_RMAXGRAN 320
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.c
deleted file mode 100644
index bff2778..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msavdecoder.h"
-#include "mscodec.h"
-extern MSFilter *ms_mpeg_encoder_new();
-extern MSFilter *ms_mpeg4_encoder_new();
-extern MSFilter *ms_h263_encoder_new();
-
-
-MSCodecInfo MPEGinfo={
- {
- "MPEG1 codec",
- 0,
- MS_FILTER_VIDEO_CODEC,
- ms_mpeg_encoder_new,
- "This is a MPEG1 codec taken from the ffmpeg project."
- },
- ms_mpeg_encoder_new,
- ms_mpeg_decoder_new,
- 0,
- 0,
- 0, /*bitrate */
- 0, /*sample freq */
- 0,
- "MPV",
- 1,
- 1
-};
-
-MSCodecInfo h263info={
- {
- "H263 codec",
- 0,
- MS_FILTER_VIDEO_CODEC,
- ms_h263_encoder_new,
- "This is a H263 codec taken from the ffmpeg project."
- },
- ms_h263_encoder_new,
- ms_h263_decoder_new,
- 0,
- 0,
- 0, /*bitrate */
- 0, /*sample freq */
- 0,
- "H263",
- 1,
- 1
-};
-
-MSCodecInfo MPEG4info={
- {
- "MPEG4 codec",
- 0,
- MS_FILTER_VIDEO_CODEC,
- ms_mpeg4_encoder_new,
- "This is a MPEG4 codec taken from the ffmpeg project."
- },
- ms_mpeg4_encoder_new,
- ms_mpeg4_decoder_new,
- 0,
- 0,
- 0, /*bitrate */
- 0, /*sample freq */
- 0,
- "MP4V-ES",
- 1,
- 1
-};
-
-
-void ms_AVCodec_init()
-{
- avcodec_init();
- avcodec_register_all();
- ms_filter_register((MSFilterInfo*)&h263info);
- //ms_filter_register((MSFilterInfo*)&MPEG4info);
-}
-
-
-static MSAVDecoderClass *ms_avdecoder_class=NULL;
-
-MSFilter *ms_h263decoder_new()
-{
- return ms_AVdecoder_new_with_codec(CODEC_ID_H263);
-}
-
-MSFilter *ms_mpeg_decoder_new()
-{
- return ms_AVdecoder_new_with_codec(CODEC_ID_MPEG1VIDEO);
-}
-
-MSFilter *ms_mpeg4_decoder_new()
-{
- return ms_AVdecoder_new_with_codec(CODEC_ID_MPEG4);
-}
-
-MSFilter *ms_h263_decoder_new(){
- return ms_AVdecoder_new_with_codec(CODEC_ID_H263);
-}
-
-MSFilter * ms_AVdecoder_new_with_codec(enum CodecID codec_id)
-{
- MSAVDecoder *enc;
-
- enc=g_malloc0(sizeof(MSAVDecoder));
- if (ms_avdecoder_class==NULL)
- {
- ms_avdecoder_class=g_malloc0(sizeof(MSAVDecoderClass));
- ms_AVdecoder_class_init(ms_avdecoder_class);
- }
- MS_FILTER(enc)->klass=(MSFilterClass*)ms_avdecoder_class;
- ms_AVdecoder_init(enc,avcodec_find_decoder(codec_id));
- return MS_FILTER(enc);
-}
-
-
-void ms_AVdecoder_init(MSAVDecoder *dec, AVCodec *codec)
-{
- gint error;
-
- ms_filter_init(MS_FILTER(dec));
- MS_FILTER(dec)->inqueues=dec->q_inputs;
- MS_FILTER(dec)->outqueues=dec->q_outputs;
- avcodec_get_context_defaults(&dec->av_context);
- dec->av_codec=codec;
- dec->av_opened=0;
- dec->skip_gob=1;
- dec->obufwrap=NULL;
-}
-
-void ms_AVdecoder_class_init(MSAVDecoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name( MS_FILTER_CLASS(klass),"AVdecoder");
- MS_FILTER_CLASS(klass)->max_qinputs=MSAVDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_qoutputs=MSAVDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=0;
- MS_FILTER_CLASS(klass)->w_maxgran=0;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_AVdecoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_AVdecoder_process;
-}
-
-void ms_AVdecoder_uninit(MSAVDecoder *dec)
-{
- if (dec->obufwrap!=NULL) ms_buffer_destroy(dec->obufwrap);
- if (dec->av_opened) avcodec_close(&dec->av_context);
-}
-void ms_AVdecoder_destroy( MSAVDecoder *obj)
-{
- ms_AVdecoder_uninit(obj);
- g_free(obj);
-}
-
-gint ms_AVdecoder_set_format(MSAVDecoder *dec, gchar *fmt)
-{
- gint format;
- if (strcmp(fmt,"YUV420P")==0) format=PIX_FMT_YUV420P;
- else if (strcmp(fmt,"YUV422")==0) format=PIX_FMT_YUV422;
- else if (strcmp(fmt,"RGB24")==0) format=PIX_FMT_RGB24;
- else if (strcmp(fmt,"BGR24")==0) format=PIX_FMT_BGR24;
- else if (strcmp(fmt,"YUV422P")==0) format=PIX_FMT_YUV422P;
- else if (strcmp(fmt,"YUV444P")==0) format=PIX_FMT_YUV444P;
- else {
- g_warning("ms_AVdecoder_set_format: unsupported format %s.",fmt);
- return -1;
- }
- dec->output_pix_fmt=format;
- return 0;
-}
-
-void ms_AVdecoder_process(MSAVDecoder *r)
-{
- AVFrame orig;
- AVFrame transformed;
- MSQueue *inq,*outq;
- MSMessage *inm,*outm;
- gint error;
- gint got_picture;
- gint len;
- unsigned char *data;
- AVCodecContext *ctx=&r->av_context;
- gint gob_num;
-
- inq=r->q_inputs[0];
- outq=r->q_outputs[0];
-
- /* get a picture from the input queue */
- inm=ms_queue_get(inq);
- g_return_if_fail(inm!=NULL);
- if (inm->size > 0)
- {
- guint32 *p = inm->data;
-
- if (!r->av_opened){
- error=avcodec_open(&r->av_context, r->av_codec);
- if (error!=0) g_warning("avcodec_open() failed: %i",error);
- else r->av_opened=1;
- }
-
- gob_num = (ntohl(*p) >> 10) & 0x1f;
- ms_trace("gob %i, size %i", gob_num, inm->size);
- ms_trace("ms_AVdecoder_process: received %08x %08x", ntohl(p[0]), ntohl(p[1]));
-
- /* remove H.263 Payload Header */
- p[0] = htonl( ntohl(p[0]) & 0x0000ffff );
-
- if (gob_num == 0){
- if (r->skip_gob == 0)
- {
- unsigned char *data = r->buf_compressed;
- ms_trace("ms_AVdecoder_process: decoding %08x %08x %08x", ntohl(((unsigned int *)data)[0]), ntohl(((unsigned int *)data)[1]), ntohl(((unsigned int *)data)[2]));
- while (r->buf_size > 0) {
- len=avcodec_decode_video(&r->av_context,&orig,&got_picture,data,r->buf_size /*inm->size*/);
- if (len<0) {
- ms_warning("ms_AVdecoder_process: error %i.",len);
- break;
- }
- if (got_picture) {
- ms_trace("ms_AVdecoder_process: got_picture: width=%i height=%i fmt=%i",
- ctx->width,ctx->height,ctx->pix_fmt);
- /* set the image in the wanted format */
- outm=ms_message_alloc();
- if (r->obufwrap==NULL){
- r->obufwrap=ms_buffer_new(avpicture_get_size(r->output_pix_fmt,ctx->width,ctx->height));
- r->obufwrap->ref_count++;
- }
- ms_message_set_buf(outm,r->obufwrap);
- avpicture_fill(&transformed,outm->data,r->output_pix_fmt,ctx->width,ctx->height);
- img_convert(&transformed, r->output_pix_fmt,
- &orig,ctx->pix_fmt,ctx->width,ctx->height);
- ms_queue_put(outq,outm);
- }
- r->buf_size -= len;
- data += len;
- }
- }
- else {
- r->skip_gob = 0;
- }
- memcpy(r->buf_compressed, inm->data, inm->size);
- r->buf_size = inm->size;
- }
- else {
- memcpy(r->buf_compressed + r->buf_size, inm->data, inm->size);
- r->buf_size += inm->size;
- }
- }
- ms_message_destroy(inm);
-}
-
-
-void ms_AVdecoder_set_width(MSAVDecoder *av,gint w)
-{
- av->av_context.width=av->width=w;
-}
-
-void ms_AVdecoder_set_height(MSAVDecoder *av,gint h)
-{
- av->av_context.height=av->height=h;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.h
deleted file mode 100644
index e7c880b..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msavdecoder.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSAVDECODER_H
-#define MSAVDECODER_H
-
-#include "msfilter.h"
-
-
-#include <avcodec.h>
-
-/*this is the class that implements a AVdecoder filter*/
-
-#define MSAVDECODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-struct _MSAVDecoder
-{
- /* the MSAVDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVDecoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSQueue *q_inputs[MSAVDECODER_MAX_INPUTS];
- MSQueue *q_outputs[MSAVDECODER_MAX_INPUTS];
- AVCodec *av_codec; /*the AVCodec from which this MSFilter is related */
- AVCodecContext av_context; /* the context of the AVCodec */
- gint av_opened;
- int output_pix_fmt;
- int width;
- int height;
- int skip_gob;
- unsigned char buf_compressed[100000];
- int buf_size;
- MSBuffer *obufwrap; /* alternate buffer, when format change is needed*/
-};
-
-typedef struct _MSAVDecoder MSAVDecoder;
-
-struct _MSAVDecoderClass
-{
- /* the MSAVDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVDecoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-};
-
-typedef struct _MSAVDecoderClass MSAVDecoderClass;
-
-/* PUBLIC */
-#define MS_AVDECODER(filter) ((MSAVDecoder*)(filter))
-#define MS_AVDECODER_CLASS(klass) ((MSAVDecoderClass*)(klass))
-
-MSFilter *ms_h263_decoder_new();
-MSFilter *ms_mpeg_decoder_new();
-MSFilter *ms_mpeg4_decoder_new();
-MSFilter * ms_AVdecoder_new_with_codec(enum CodecID codec_id);
-
-gint ms_AVdecoder_set_format(MSAVDecoder *dec, gchar *fmt);
-void ms_AVdecoder_set_width(MSAVDecoder *av,gint w);
-void ms_AVdecoder_set_height(MSAVDecoder *av,gint h);
-
-/* FOR INTERNAL USE*/
-void ms_AVdecoder_init(MSAVDecoder *r, AVCodec *codec);
-void ms_AVdecoder_uninit(MSAVDecoder *enc);
-void ms_AVdecoder_class_init(MSAVDecoderClass *klass);
-void ms_AVdecoder_destroy( MSAVDecoder *obj);
-void ms_AVdecoder_process(MSAVDecoder *r);
-
-void ms_AVCodec_init();
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.c
deleted file mode 100644
index ae65c37..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msavencoder.h"
-#include "msutils.h"
-
-extern MSCodecInfo MPEG4info;
-extern MSCodecInfo MPEGinfo;
-extern MSCodecInfo h263info;
-
-static MSAVEncoderClass *ms_avencoder_class=NULL;
-static void ms_AVencoder_rtp_callback (AVCodecContext *ctx,void *data, int size, int packet_number);
-
-MSFilter *ms_h263_encoder_new()
-{
- return ms_AVencoder_new_with_codec(CODEC_ID_H263,&h263info);
-}
-
-MSFilter *ms_mpeg_encoder_new()
-{
- return ms_AVencoder_new_with_codec(CODEC_ID_MPEG1VIDEO, &MPEGinfo);
-}
-
-MSFilter *ms_mpeg4_encoder_new()
-{
- return ms_AVencoder_new_with_codec(CODEC_ID_MPEG4,&MPEG4info);
-}
-
-MSFilter * ms_AVencoder_new_with_codec(enum CodecID codec_id, MSCodecInfo *info)
-{
- MSAVEncoder *enc;
- AVCodec *avc;
- enc=g_malloc0(sizeof(MSAVEncoder));
- if (ms_avencoder_class==NULL)
- {
- ms_avencoder_class=g_malloc0(sizeof(MSAVEncoderClass));
- ms_AVencoder_class_init(ms_avencoder_class);
- }
- MS_FILTER(enc)->klass=(MSFilterClass*)ms_avencoder_class;
- avc=avcodec_find_encoder(codec_id);
- if (avc==NULL) g_error("unknown av codec.");
- ms_AVencoder_init(enc,avc);
- return MS_FILTER(enc);
-}
-
-
-void ms_AVencoder_init(MSAVEncoder *enc, AVCodec *codec)
-{
- gint error;
- AVCodecContext *c=&enc->av_context;
-
- ms_filter_init(MS_FILTER(enc));
- MS_FILTER(enc)->inqueues=enc->q_inputs;
- MS_FILTER(enc)->outqueues=enc->q_outputs;
- /* put default values */
- memset(c, 0, sizeof(AVCodecContext));
- avcodec_get_context_defaults(c);
-
- /* put sample parameters */
- c->bit_rate = 400000;
- /* resolution must be a multiple of two */
- c->width = VIDEO_SIZE_CIF_W;
- c->height = VIDEO_SIZE_CIF_H;
- /* frames per second */
- c->frame_rate = 15;
- c->frame_rate_base = 1;
- c->gop_size = 10; /* emit one intra frame every x frames */
- c->rtp_mode = 1;
- c->rtp_payload_size = 1488;
- c->opaque = (void *) enc;
- c->rtp_callback = ms_AVencoder_rtp_callback;
- c->pix_fmt=PIX_FMT_YUV420P;
-
- enc->av_opened=0;
- enc->av_codec=codec;
- enc->yuv_buf=NULL;
- enc->comp_buf=NULL;
- /*set default input format */
- ms_AVencoder_set_format(enc,"RGB24");
-}
-
-void ms_AVencoder_class_init(MSAVEncoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- MS_FILTER_CLASS(klass)->info=0;
- MS_FILTER_CLASS(klass)->max_qinputs=MSAVENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_qoutputs=MSAVENCODER_MAX_OUTPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=0;
- MS_FILTER_CLASS(klass)->w_maxgran=0;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_AVencoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_AVencoder_process;
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"AVEncoder");
-
-}
-
-void ms_AVencoder_uninit(MSAVEncoder *enc)
-{
- if (enc->av_opened)
- avcodec_close(&enc->av_context);
- if (enc->comp_buf!=NULL) {
- ms_buffer_destroy(enc->comp_buf);
- enc->comp_buf=NULL;
- }
- if (enc->yuv_buf!=NULL) {
- ms_buffer_destroy(enc->yuv_buf);
- enc->yuv_buf=NULL;
- }
-
-}
-void ms_AVencoder_destroy( MSAVEncoder *obj)
-{
- ms_AVencoder_uninit(obj);
- g_free(obj);
-}
-
-
-void ms_AVencoder_set_frame_rate(MSAVEncoder *obj, gint frame_rate, gint frame_rate_base)
-{
- obj->av_context.frame_rate = frame_rate;
- obj->av_context.frame_rate_base = frame_rate_base;
-}
-
-static void ms_AVencoder_rtp_callback (AVCodecContext *ctx, void *data, int size, int packet_number)
-{
- MSAVEncoder *r = MS_AVENCODER(ctx->opaque);
- MSQueue *outq = r->q_outputs[0];
- MSMessage *outm;
- guint32 *p = (guint32 *) data;
- gint gob_num = (ntohl(*p) >> 10) & 0x1f;
-
- /*g_message("ms_AVencoder_rtp_callback: packet %i, size %i, GOB number %i", packet_number, size, gob_num);*/
- ms_trace("ms_AVencoder_rtp_callback: received %08x %08x", ntohl(p[0]), ntohl(p[1]));
- /* set the H.263 Payload Header (RFC 2429) */
- p[0] = ntohl( (0x04000000) | (ntohl(p[0]) & 0x0000ffff) ); /* P=1, V=0, PLEN=0 */
- ms_trace("ms_AVencoder_rtp_callback: sending %08x %08x", ntohl(p[0]), ntohl(p[1]));
- outm = ms_message_new(size);
- memcpy(outm->data,data,size);
- ms_queue_put(outq, outm);
-}
-
-void ms_AVencoder_process(MSAVEncoder *r)
-{
- AVFrame orig;
- AVFrame pict;
- AVCodecContext *c=&r->av_context;
- MSQueue *inq,*outq;
- MSMessage *inm,*outm;
- gint error;
-
- inq=r->q_inputs[0];
- outq=r->q_outputs[0];
-
- /* get a picture from the input queue */
- inm=ms_queue_get(inq);
- g_return_if_fail(inm!=NULL);
-
- /* allocate a new image */
- if (r->yuv_buf==NULL){
- gint bsize = avpicture_get_size(c->pix_fmt,c->width,c->height);
- r->yuv_buf=ms_buffer_new(bsize);
- r->yuv_buf->ref_count++;
-
- r->comp_buf=ms_buffer_new(bsize/2);
- r->comp_buf->ref_count++;
- }
- if (!r->av_opened || r->av_context.codec == NULL){
- error=avcodec_open(c, r->av_codec);
- ms_trace("image format is %i.",c->pix_fmt);
- if (error!=0) {
- g_warning("avcodec_open() failed: %i",error);
- return;
- }else r->av_opened=1;
- }
- outm=ms_message_alloc();
- /* convert image if necessary */
- if (r->input_pix_fmt!=c->pix_fmt){
- ms_trace("Changing picture format.");
- avpicture_fill((AVPicture*)&orig,inm->data,r->input_pix_fmt,c->width,c->height);
- avpicture_fill((AVPicture*)&pict,r->yuv_buf->buffer,c->pix_fmt,c->width,c->height);
- if (img_convert((AVPicture*)&pict,c->pix_fmt,(AVPicture*)&orig,r->input_pix_fmt,c->width,c->height) < 0) {
- g_warning("img_convert failed");
- return;
- }
- //if (pict.data[0]==NULL) g_error("img_convert failed.");
- ms_message_set_buf(outm,r->yuv_buf);
- }
- else
- {
- avpicture_fill((AVPicture*)&pict,inm->data,c->pix_fmt,c->width,c->height);
- ms_message_set_buf(outm,inm->buffer);
- }
- /* timestamp used by ffmpeg, unset here */
- pict.pts=AV_NOPTS_VALUE;
- error=avcodec_encode_video(c, r->comp_buf->buffer, r->comp_buf->size, &pict);
- if (error<=0) ms_warning("ms_AVencoder_process: error %i.",error);
- else ms_trace("ms_AVencoder_process: video encoding done");
- if (r->q_outputs[1]!=NULL) ms_queue_put(r->q_outputs[1],outm);
- else ms_message_destroy(outm);
- ms_message_destroy(inm);
-}
-
-gint ms_AVencoder_set_format(MSAVEncoder *enc, gchar *fmt)
-{
- gint format;
- if (strcmp(fmt,"YUV420P")==0) format=PIX_FMT_YUV420P;
- else if (strcmp(fmt,"YUV422")==0) format=PIX_FMT_YUV422;
- else if (strcmp(fmt,"RGB24")==0) format=PIX_FMT_RGB24;
- else if (strcmp(fmt,"BGR24")==0) format=PIX_FMT_BGR24;
- else if (strcmp(fmt,"YUV422P")==0) format=PIX_FMT_YUV422P;
- else if (strcmp(fmt,"YUV444P")==0) format=PIX_FMT_YUV444P;
- else {
- g_warning("ms_AVdecoder_set_format: unsupported format %s.",fmt);
- return -1;
- }
- enc->input_pix_fmt=format;
-
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.h
deleted file mode 100644
index 6fe5cad..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msavencoder.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSAVENCODER_H
-#define MSAVENCODER_H
-
-#include "msfilter.h"
-#include "mscodec.h"
-#include <avcodec.h>
-
-/*this is the class that implements a AVencoder filter*/
-
-#define MSAVENCODER_MAX_INPUTS 1 /* max output per filter*/
-#define MSAVENCODER_MAX_OUTPUTS 2
-
-struct _MSAVEncoder
-{
- /* the MSAVEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSAVEncoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSQueue *q_inputs[MSAVENCODER_MAX_INPUTS];
- MSQueue *q_outputs[MSAVENCODER_MAX_OUTPUTS];
- AVCodec *av_codec; /*the AVCodec from which this MSFilter is related */
- AVCodecContext av_context; /* the context of the AVCodec */
- gint input_pix_fmt;
- gint av_opened;
- MSBuffer *comp_buf;
- MSBuffer *yuv_buf;
-};
-
-typedef struct _MSAVEncoder MSAVEncoder;
-/* MSAVEncoder always outputs planar YUV and accept any incoming format you should setup using
- ms_AVencoder_set_format()
-q_outputs[0] is the compressed video stream output
-q_outputs[1] is a YUV planar buffer of the image it receives in input.
-*/
-
-
-struct _MSAVEncoderClass
-{
- /* the MSAVEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSAVEncoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-};
-
-typedef struct _MSAVEncoderClass MSAVEncoderClass;
-
-/* PUBLIC */
-#define MS_AVENCODER(filter) ((MSAVEncoder*)(filter))
-#define MS_AVENCODER_CLASS(klass) ((MSAVEncoderClass*)(klass))
-
-MSFilter *ms_h263_encoder_new();
-MSFilter *ms_mpeg_encoder_new();
-MSFilter *ms_mpeg4_encoder_new();
-MSFilter * ms_AVencoder_new_with_codec(enum CodecID codec_id, MSCodecInfo *info);
-
-gint ms_AVencoder_set_format(MSAVEncoder *enc, gchar *fmt);
-
-#define ms_AVencoder_set_width(av,w) (av)->av_context.width=(w)
-#define ms_AVencoder_set_height(av,h) (av)->av_context.height=(h)
-#define ms_AVencoder_set_bit_rate(av,r) (av)->av_context.bit_rate=(r)
-
-void ms_AVencoder_set_frame_rate(MSAVEncoder *enc, gint frame_rate, gint frame_rate_base);
-
-/* FOR INTERNAL USE*/
-void ms_AVencoder_init(MSAVEncoder *r, AVCodec *codec);
-void ms_AVencoder_uninit(MSAVEncoder *enc);
-void ms_AVencoder_class_init(MSAVEncoderClass *klass);
-void ms_AVencoder_destroy( MSAVEncoder *obj);
-void ms_AVencoder_process(MSAVEncoder *r);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.c
deleted file mode 100644
index 4ca3c92..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msbuffer.h"
-#include "msutils.h"
-#include <string.h>
-
-
-
-MSBuffer * ms_buffer_new(guint32 size)
-{
- MSBuffer *buf;
- buf=(MSBuffer*)g_malloc(sizeof(MSBuffer)+size);
- buf->ref_count=0;
- buf->size=size;
- ms_trace("ms_buffer_new: Allocating buffer of %i bytes.",size);
- /* allocate the data buffer: there is a lot of optmisation that can be done by using a pool of cached buffers*/
- buf->buffer=((char*)(buf))+sizeof(MSBuffer); /* to avoid to do two allocations,
- buffer info and buffer are contigous.*/
- buf->flags=MS_BUFFER_CONTIGUOUS;
- return(buf);
-}
-
-MSBuffer *ms_buffer_alloc(gint flags)
-{
- MSBuffer *buf;
- buf=(MSBuffer*)g_malloc(sizeof(MSBuffer));
- buf->ref_count=0;
- buf->size=0;
- buf->buffer=NULL;
- buf->flags=0;
- return(buf);
-}
-
-
-void ms_buffer_destroy(MSBuffer *buf)
-{
- if (buf->flags & MS_BUFFER_CONTIGUOUS){
- g_free(buf);
- }
- else {
- g_free(buf->buffer);
- g_free(buf);
- }
-}
-
-MSMessage *ms_message_alloc()
-{
- MSMessage *m=g_malloc(sizeof(MSMessage));
- memset(m,0,sizeof(MSMessage));
- return m;
-}
-
-MSMessage *ms_message_new(gint size)
-{
- MSMessage *m=ms_message_alloc();
- MSBuffer *buf=ms_buffer_new(size);
- ms_message_set_buf(m,buf);
- return m;
-}
-
-void ms_message_destroy(MSMessage *m)
-{
- /* the buffer is freed if its ref_count goes to zero */
- if (m->buffer!=NULL){
- m->buffer->ref_count--;
- if (m->buffer->ref_count==0) ms_buffer_destroy(m->buffer);
- }
- g_free(m);
-}
-
-MSMessage * ms_message_dup(MSMessage *m)
-{
- MSMessage *msg=ms_message_alloc();
- ms_message_set_buf(msg,m->buffer);
- return msg;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.h
deleted file mode 100644
index f96b35a..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msbuffer.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSBUFFER_H
-#define MSBUFFER_H
-#include <config.h>
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#else
-#include <uglib.h>
-#endif
-
-
-#define MS_BUFFER_LARGE 4092
-
-
-typedef struct _MSBuffer
-{
- gchar *buffer;
- guint32 size;
- guint16 ref_count;
- guint16 flags;
-#define MS_BUFFER_CONTIGUOUS (1)
-}MSBuffer;
-
-MSBuffer * ms_buffer_new(guint32 size);
-void ms_buffer_destroy(MSBuffer *buf);
-
-struct _MSMessage
-{
- MSBuffer *buffer; /* points to a MSBuffer */
- void *data; /*points to buffer->buffer */
- guint32 size; /* the size of the buffer to read in data. It may not be the
- physical size (I mean buffer->buffer->size */
- struct _MSMessage *next;
- struct _MSMessage *prev; /* MSMessage are queued into MSQueues */
-};
-
-typedef struct _MSMessage MSMessage;
-
-
-MSBuffer *ms_buffer_alloc(gint flags);
-MSMessage *ms_message_new(gint size);
-
-#define ms_message_set_buf(m,b) do { (b)->ref_count++; (m)->buffer=(b); (m)->data=(b)->buffer; (m)->size=(b)->size; }while(0)
-#define ms_message_unset_buf(m) do { (m)->buffer->ref_count--; (m)->buffer=NULL; (m)->size=0; (m)->data=NULL; } while(0)
-
-#define ms_message_size(m) (m)->size
-void ms_message_destroy(MSMessage *m);
-
-MSMessage * ms_message_dup(MSMessage *m);
-
-/* allocate a single message without buffer */
-MSMessage *ms_message_alloc();
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.c
deleted file mode 100644
index 7677dbe..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "mscodec.h"
-#include "msMUlawdec.h"
-
-#ifdef TRUESPEECH
-extern MSCodecInfo TrueSpeechinfo;
-#endif
-
-#ifdef VIDEO_ENABLED
-extern void ms_AVCodec_init();
-#endif
-
-#define UDP_HDR_SZ 8
-#define RTP_HDR_SZ 12
-#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/
-
-
-
-
-/* register all statically linked codecs */
-void ms_codec_register_all()
-{
-// ms_filter_register(MS_FILTER_INFO(&GSMinfo));
-// ms_filter_register(MS_FILTER_INFO(&LPC10info));
- ms_filter_register(MS_FILTER_INFO(&MULAWinfo));
-#ifdef TRUESPEECH
- ms_filter_register(MS_FILTER_INFO(&TrueSpeechinfo));
-#endif
-#ifdef VIDEO_ENABLED
- ms_AVCodec_init();
-#endif
-
-}
-
-/* returns a list of MSCodecInfo */
-GList * ms_codec_get_all_audio()
-{
- GList *audio_codecs=NULL;
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if (info->type==MS_FILTER_AUDIO_CODEC){
- audio_codecs=g_list_append(audio_codecs,info);
- }
- elem=g_list_next(elem);
- }
- return audio_codecs;
-}
-
-
-MSCodecInfo * ms_audio_codec_info_get(gchar *name)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ( (info->type==MS_FILTER_AUDIO_CODEC) ){
- MSCodecInfo *codinfo=(MSCodecInfo *)info;
- if (strcmp(codinfo->description,name)==0){
- return MS_CODEC_INFO(info);
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-
-MSCodecInfo * ms_video_codec_info_get(gchar *name)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ( (info->type==MS_FILTER_VIDEO_CODEC) ){
- MSCodecInfo *codinfo=(MSCodecInfo *)info;
- if (strcmp(codinfo->description,name)==0){
- return MS_CODEC_INFO(info);
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-
-/* returns a list of MSCodecInfo */
-GList * ms_codec_get_all_video()
-{
- GList *video_codecs=NULL;
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if (info->type==MS_FILTER_VIDEO_CODEC){
- video_codecs=g_list_append(video_codecs,info);
- }
- elem=g_list_next(elem);
- }
- return video_codecs;
-}
-
-MSFilter * ms_encoder_new(gchar *name)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
- MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
- if (strcmp(info->name,name)==0){
- return codinfo->encoder();
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-
-MSFilter * ms_decoder_new(gchar *name)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
- MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
- if (strcmp(info->name,name)==0){
- return codinfo->decoder();
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-
-MSFilter * ms_encoder_new_with_pt(gint pt)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
- MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
- if (codinfo->pt==pt){
- return codinfo->encoder();
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-
-MSFilter * ms_decoder_new_with_pt(gint pt)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
- MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
- if (codinfo->pt==pt){
- return codinfo->decoder();
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-
-MSFilter * ms_decoder_new_with_string_id(gchar *id)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
- MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
- if (strcasecmp(codinfo->description,id)==0){
- return codinfo->decoder();
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-
-MSFilter * ms_encoder_new_with_string_id(gchar *id)
-{
- GList *elem=filter_list;
- MSFilterInfo *info;
- while (elem!=NULL)
- {
- info=(MSFilterInfo *)elem->data;
- if ((info->type==MS_FILTER_AUDIO_CODEC) || (info->type==MS_FILTER_VIDEO_CODEC)){
- MSCodecInfo *codinfo=(MSCodecInfo *)elem->data;
- if (strcasecmp(codinfo->description,id)==0){
- return codinfo->encoder();
- }
- }
- elem=g_list_next(elem);
- }
- return NULL;
-}
-/* return 0 if codec can be used with bandwidth, -1 else*/
-int ms_codec_is_usable(MSCodecInfo *codec,double bandwidth)
-{
- double codec_band;
- double npacket;
- double packet_size;
-
- if (((MSFilterInfo*)codec)->type==MS_FILTER_AUDIO_CODEC)
- {
- /* calculate the total bandwdith needed by codec (including headers for rtp, udp, ip)*/
- /* number of packet per second*/
- npacket=2.0*(double)(codec->rate)/(double)(codec->fr_size);
- packet_size=(double)(codec->dt_size)+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
- codec_band=packet_size*8.0*npacket;
- }
- else return -1;
- return(codec_band<bandwidth);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.h
deleted file mode 100644
index 6c6847d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mscodec.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSCODEC_H
-#define MSCODEC_H
-
-#include "msfilter.h"
-
-struct _MSCodecInfo
-{
- MSFilterInfo info;
- MSFilterNewFunc encoder;
- MSFilterNewFunc decoder;
- gint fr_size; /* size in char of the uncompressed frame */
- gint dt_size; /* size in char of the compressed frame */
- gint bitrate; /* the minimum bit rate in bits/second */
- gint rate; /*frequency */
- gint pt; /* the payload type number associated with this codec*/
- gchar *description; /* a rtpmap field to describe the codec */
- guint is_usable:1; /* linphone set this flag to remember if it can use this codec considering the total bandwidth*/
- guint is_selected:1; /* linphone (user) set this flag if he allows this codec to be used*/
-};
-
-typedef struct _MSCodecInfo MSCodecInfo;
-
-MSFilter * ms_encoder_new(gchar *name);
-MSFilter * ms_decoder_new(gchar *name);
-
-MSFilter * ms_encoder_new_with_pt(gint pt);
-MSFilter * ms_decoder_new_with_pt(gint pt);
-
-MSFilter * ms_encoder_new_with_string_id(gchar *id);
-MSFilter * ms_decoder_new_with_string_id(gchar *id);
-
-/* return 0 if codec can be used with bandwidth, -1 else*/
-int ms_codec_is_usable(MSCodecInfo *codec,double bandwidth);
-
-GList * ms_codec_get_all_audio();
-
-GList * ms_codec_get_all_video();
-
-MSCodecInfo * ms_audio_codec_info_get(gchar *name);
-MSCodecInfo * ms_video_codec_info_get(gchar *name);
-
-/* register all statically linked codecs */
-void ms_codec_register_all();
-
-#define MS_CODEC_INFO(codinfo) ((MSCodecInfo*)codinfo)
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.c
deleted file mode 100644
index 3040b2e..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "mscopy.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-
-static MSCopyClass *ms_copy_class=NULL;
-
-MSFilter * ms_copy_new(void)
-{
- MSCopy *r;
-
- r=g_new(MSCopy,1);
- ms_copy_init(r);
- if (ms_copy_class==NULL)
- {
- ms_copy_class=g_new(MSCopyClass,1);
- ms_copy_class_init(ms_copy_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_copy_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_copy_init(MSCopy *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->r_mingran=MSCOPY_DEF_GRAN;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSCOPY_MAX_INPUTS);
-}
-
-void ms_copy_class_init(MSCopyClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"fifocopier");
- MS_FILTER_CLASS(klass)->max_finputs=MSCOPY_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSCOPY_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=MSCOPY_DEF_GRAN;
- MS_FILTER_CLASS(klass)->w_maxgran=MSCOPY_DEF_GRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_copy_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_copy_process;
-}
-
-void ms_copy_process(MSCopy *r)
-{
- MSFifo *fi,*fo;
- int err1;
- gint gran=MS_FILTER(r)->klass->r_maxgran;
- void *s,*d;
-
- /* process output fifos, but there is only one for this class of filter*/
-
- fi=r->f_inputs[0];
- fo=r->f_outputs[0];
- if (fi!=NULL)
- {
- err1=ms_fifo_get_read_ptr(fi,gran,&s);
- if (err1>0) err1=ms_fifo_get_write_ptr(fo,gran,&d);
- if (err1>0)
- {
- memcpy(d,s,gran);
- }
- }
-}
-
-void ms_copy_destroy( MSCopy *obj)
-{
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.h
deleted file mode 100644
index 2b5749b..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mscopy.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSCOPY_H
-#define MSCOPY_H
-
-#include "msfilter.h"
-
-
-/*this is the class that implements a copy filter*/
-
-#define MSCOPY_MAX_INPUTS 1 /* max output per filter*/
-
-#define MSCOPY_DEF_GRAN 64 /* the default granularity*/
-
-typedef struct _MSCopy
-{
- /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSCOPY_MAX_INPUTS];
- MSFifo *f_outputs[MSCOPY_MAX_INPUTS];
-} MSCopy;
-
-typedef struct _MSCopyClass
-{
- /* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSCopyClass;
-
-/* PUBLIC */
-#define MS_COPY(filter) ((MSCopy*)(filter))
-#define MS_COPY_CLASS(klass) ((MSCopyClass*)(klass))
-MSFilter * ms_copy_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_copy_init(MSCopy *r);
-void ms_copy_class_init(MSCopyClass *klass);
-void ms_copy_destroy( MSCopy *obj);
-void ms_copy_process(MSCopy *r);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.c
deleted file mode 100644
index 692bbb7..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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 dispatcher of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msfdispatcher.h"
-
-static MSFdispatcherClass *ms_fdispatcher_class=NULL;
-
-MSFilter * ms_fdispatcher_new(void)
-{
- MSFdispatcher *obj;
- obj=g_malloc(sizeof(MSFdispatcher));
- if (ms_fdispatcher_class==NULL){
- ms_fdispatcher_class=g_malloc(sizeof(MSFdispatcherClass));
- ms_fdispatcher_class_init(ms_fdispatcher_class);
- }
- MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_fdispatcher_class);
- ms_fdispatcher_init(obj);
- return MS_FILTER(obj);
-}
-
-
-void ms_fdispatcher_init(MSFdispatcher *obj)
-{
- ms_filter_init(MS_FILTER(obj));
- MS_FILTER(obj)->infifos=obj->f_inputs;
- MS_FILTER(obj)->outfifos=obj->f_outputs;
- MS_FILTER(obj)->r_mingran=MS_FDISPATCHER_DEF_GRAN;
- memset(obj->f_inputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_INPUTS);
- memset(obj->f_outputs,0,sizeof(MSFifo*)*MS_FDISPATCHER_MAX_OUTPUTS);
-}
-
-
-
-void ms_fdispatcher_class_init(MSFdispatcherClass *klass)
-{
- MSFilterClass *parent_class=MS_FILTER_CLASS(klass);
- ms_filter_class_init(parent_class);
- ms_filter_class_set_name(parent_class,"fdispatcher");
- parent_class->max_finputs=MS_FDISPATCHER_MAX_INPUTS;
- parent_class->max_foutputs=MS_FDISPATCHER_MAX_OUTPUTS;
- parent_class->r_maxgran=MS_FDISPATCHER_DEF_GRAN;
- parent_class->w_maxgran=MS_FDISPATCHER_DEF_GRAN;
- parent_class->destroy=(MSFilterDestroyFunc)ms_fdispatcher_destroy;
- parent_class->process=(MSFilterProcessFunc)ms_fdispatcher_process;
-}
-
-
-void ms_fdispatcher_destroy( MSFdispatcher *obj)
-{
- g_free(obj);
-}
-
-void ms_fdispatcher_process(MSFdispatcher *obj)
-{
- gint i;
- MSFifo *inf=obj->f_inputs[0];
-
-
- if (inf!=NULL){
- void *s,*d;
- /* dispatch fifos */
- while ( ms_fifo_get_read_ptr(inf,MS_FDISPATCHER_DEF_GRAN,&s) >0 ){
- for (i=0;i<MS_FDISPATCHER_MAX_OUTPUTS;i++){
- MSFifo *outf=obj->f_outputs[i];
-
- if (outf!=NULL)
- {
- ms_fifo_get_write_ptr(outf,MS_FDISPATCHER_DEF_GRAN,&d);
- if (d!=NULL) memcpy(d,s,MS_FDISPATCHER_DEF_GRAN);
- }
- }
- }
- }
-}
-
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.h
deleted file mode 100644
index b1b457d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msfdispatcher.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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 dispatcher of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSFDISPATCHER_H
-#define MSFDISPATCHER_H
-
-#include "msfilter.h"
-
-
-/*this is the class that implements a fdispatcher filter*/
-
-#define MS_FDISPATCHER_MAX_INPUTS 1
-#define MS_FDISPATCHER_MAX_OUTPUTS 5
-#define MS_FDISPATCHER_DEF_GRAN 64 /* the default granularity*/
-
-typedef struct _MSFdispatcher
-{
- /* the MSFdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSFdispatcher object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MS_FDISPATCHER_MAX_INPUTS];
- MSFifo *f_outputs[MS_FDISPATCHER_MAX_OUTPUTS];
-} MSFdispatcher;
-
-typedef struct _MSFdispatcherClass
-{
- /* the MSFdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSFdispatcher class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSFdispatcherClass;
-
-/* PUBLIC */
-#define MS_FDISPATCHER(filter) ((MSFdispatcher*)(filter))
-#define MS_FDISPATCHER_CLASS(klass) ((MSFdispatcherClass*)(klass))
-MSFilter * ms_fdispatcher_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_fdispatcher_init(MSFdispatcher *r);
-void ms_fdispatcher_class_init(MSFdispatcherClass *klass);
-void ms_fdispatcher_destroy( MSFdispatcher *obj);
-void ms_fdispatcher_process(MSFdispatcher *r);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.c
deleted file mode 100644
index 9897e08..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <errno.h>
-#include <string.h>
-#include "msutils.h"
-#include "msfifo.h"
-
-MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset)
-{
- MSFifo *fifo;
- gint saved_offset=MAX(r_gran+r_offset,w_offset);
-
- g_return_val_if_fail(saved_offset<=(buf->size),NULL);
- fifo=g_malloc(sizeof(MSFifo));
- fifo->buffer=buf;
- fifo->r_gran=r_gran;
- fifo->w_gran=w_gran;
- fifo->begin=fifo->wr_ptr=fifo->rd_ptr=buf->buffer+saved_offset;
- fifo->readsize=0;
- fifo->size=fifo->writesize=buf->size-saved_offset;
- fifo->saved_offset= saved_offset;
- fifo->r_end=fifo->w_end=buf->buffer+buf->size;
- fifo->pre_end=fifo->w_end-saved_offset;
- buf->ref_count++;
- fifo->prev_data=NULL;
- fifo->next_data=NULL;
- ms_trace("fifo base=%x, begin=%x, end=%x, saved_offset=%i, size=%i"
- ,fifo->buffer->buffer,fifo->begin,fifo->w_end,fifo->saved_offset,fifo->size);
- return(fifo);
-}
-
-MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset,
- gint min_fifo_size)
-{
- MSFifo *fifo;
- MSBuffer *buf;
- gint saved_offset=MAX(r_gran+r_offset,w_offset);
- gint fifo_size;
- gint tmp;
- if (min_fifo_size==0) min_fifo_size=w_gran;
-
- /* we must allocate a fifo with a size multiple of min_fifo_size,
- with a saved_offset */
- if (min_fifo_size>MS_BUFFER_LARGE)
- fifo_size=(min_fifo_size) + saved_offset;
- else fifo_size=(6*min_fifo_size) + saved_offset;
- buf=ms_buffer_new(fifo_size);
- fifo=ms_fifo_new(buf,r_gran,w_gran,r_offset,w_offset);
- ms_trace("fifo_size=%i",fifo_size);
- return(fifo);
-}
-
-void ms_fifo_destroy( MSFifo *fifo)
-{
- g_free(fifo);
-}
-
-void ms_fifo_destroy_with_buffer(MSFifo *fifo)
-{
- ms_buffer_destroy(fifo->buffer);
- ms_fifo_destroy(fifo);
-}
-
-gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr)
-{
- gchar *rnext;
-
- *ret_ptr=NULL;
- //ms_trace("ms_fifo_get_read_ptr: entering.");
- g_return_val_if_fail(bsize<=fifo->r_gran,-EINVAL);
-
- if (bsize>fifo->readsize)
- {
- ms_trace("Not enough data: bsize=%i, readsize=%i",bsize,fifo->readsize);
- return (-ENODATA);
- }
-
- rnext=fifo->rd_ptr+bsize;
- if (rnext<=fifo->r_end){
-
- *ret_ptr=fifo->rd_ptr;
- fifo->rd_ptr=rnext;
- }else{
- int unread=fifo->r_end-fifo->rd_ptr;
- *ret_ptr=fifo->begin-unread;
- memcpy(fifo->buffer->buffer,fifo->r_end-fifo->saved_offset,fifo->saved_offset);
- fifo->rd_ptr=(char*)(*ret_ptr) + bsize;
- fifo->r_end=fifo->w_end; /* this is important ! */
- ms_trace("moving read ptr to %x",fifo->rd_ptr);
-
- }
- /* update write size*/
- fifo->writesize+=bsize;
- fifo->readsize-=bsize;
- return bsize;
-}
-
-
-void ms_fifo_update_write_ptr(MSFifo *fifo, gint written){
- gint reserved=fifo->wr_ptr-fifo->prev_wr_ptr;
- gint unwritten;
- g_return_if_fail(reserved>=0);
- unwritten=reserved-written;
- g_return_if_fail(unwritten>=0);
- /* fix readsize and writesize */
- fifo->readsize-=unwritten;
- fifo->writesize+=unwritten;
- fifo->wr_ptr+=written;
-}
-
-gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr)
-{
- gchar *wnext;
-
- *ret_ptr=NULL;
- //ms_trace("ms_fifo_get_write_ptr: Entering.");
- g_return_val_if_fail(bsize<=fifo->w_gran,-EINVAL);
- if (bsize>fifo->writesize)
- {
- ms_trace("Not enough space: bsize=%i, writesize=%i",bsize,fifo->writesize);
- *ret_ptr=NULL;
- return(-ENODATA);
- }
- wnext=fifo->wr_ptr+bsize;
- if (wnext<=fifo->w_end){
- *ret_ptr=fifo->wr_ptr;
- fifo->wr_ptr=wnext;
- }else{
- *ret_ptr=fifo->begin;
- fifo->r_end=fifo->wr_ptr;
- fifo->wr_ptr=fifo->begin+bsize;
- ms_trace("moving write ptr to %x",fifo->wr_ptr);
- }
- fifo->prev_wr_ptr=*ret_ptr;
- /* update readsize*/
- fifo->readsize+=bsize;
- fifo->writesize-=bsize;
- //ms_trace("ms_fifo_get_write_ptr: readsize=%i, writesize=%i",fifo->readsize,fifo->writesize);
- return bsize;
-}
-
-gint ms_fifo_get_rw_ptr(MSFifo *f1,void **p1,gint minsize1,
- MSFifo *f2,void **p2,gint minsize2)
-{
- gint rbsize,wbsize;
-
- rbsize=MIN(f1->readsize,(f1->pre_end-f1->rd_ptr));
- wbsize=MIN(f2->writesize,(f2->w_end-f2->wr_ptr));
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.h
deleted file mode 100644
index fde1bec..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msfifo.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#else
-#include "glist.h"
-#endif
-#include "msbuffer.h"
-
-typedef struct _MSFifo
-{
- gint r_gran; /*maximum granularity for reading*/
- gint w_gran; /*maximum granularity for writing*/
- gchar * rd_ptr; /* read pointer on the position where there is something to read on the MSBuffer */
- guint32 readsize;
- gchar * wr_ptr;
- gchar * prev_wr_ptr;
- guint32 writesize; /* write pointer on the position where it is possible to write on the MSBuffer */
- gchar * begin; /* rd_ptr et wr_ptr must all be >=begin*/
- guint32 size; /* the length of the fifo, but this may not be equal to buffer->size*/
- guint32 saved_offset;
- gchar * pre_end; /* the end of the buffer that is copied at the begginning when we wrap around*/
- gchar * w_end; /* when a wr ptr is expected to exceed end_offset,
- it must be wrapped around to go at the beginning of the buffer. This is the end of the buffer*/
- gchar * r_end; /* this is the last position written at the end of the fifo. If a read ptr is expected to
- exceed this pointer, it must be put at the begginning of the buffer */
- void *prev_data; /*user data, usually the writing MSFilter*/
- void *next_data; /* user data, usually the reading MSFilter */
- MSBuffer *buffer;
-} MSFifo;
-
-/* constructor*/
-/* r_gran: max granularity for reading (in number of bytes)*/
-/* w_gran: max granularity for writing (in number of bytes)*/
-/* r_offset: number of bytes that are kept available behind read pointer (for recursive filters)*/
-/* w_offset: number of bytes that are kept available behind write pointer (for recursive filters)*/
-/* buf is a MSBuffer that should be compatible with the above parameter*/
-MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset);
-
-/*does the same that ms_fifo_new(), but also allocate a compatible buffer automatically*/
-MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset, gint min_buffer_size);
-
-void ms_fifo_destroy( MSFifo *fifo);
-
-void ms_fifo_destroy_with_buffer(MSFifo *fifo);
-
-/* get data to read */
-gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr);
-
-/* get a buffer to write*/
-gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr);
-
-/* in case the buffer got by ms_fifo_get_write_ptr() could not be filled completely, you must
-tell it by using this function */
-void ms_fifo_update_write_ptr(MSFifo *fifo, gint written);
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.c
deleted file mode 100644
index c67e9f0..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.c
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include <errno.h>
-#include "msfilter.h"
-
-
-
-void ms_filter_init(MSFilter *filter)
-{
- filter->finputs=0;
- filter->foutputs=0;
- filter->qinputs=0;
- filter->qoutputs=0;
- filter->infifos=NULL;
- filter->outfifos=NULL;
- filter->inqueues=NULL;
- filter->outqueues=NULL;
- filter->lock=g_mutex_new();
- filter->min_fifo_size=0x7fff;
- filter->notify_event=NULL;
- filter->userdata=NULL;
-}
-
-void ms_filter_uninit(MSFilter *filter)
-{
- g_mutex_free(filter->lock);
-}
-
-void ms_filter_class_init(MSFilterClass *filterclass)
-{
- filterclass->name=NULL;
- filterclass->max_finputs=0;
- filterclass->max_foutputs=0;
- filterclass->max_qinputs=0;
- filterclass->max_qoutputs=0;
- filterclass->r_maxgran=0;
- filterclass->w_maxgran=0;
- filterclass->r_offset=0;
- filterclass->w_offset=0;
- filterclass->set_property=NULL;
- filterclass->get_property=NULL;
- filterclass->setup=NULL;
- filterclass->unsetup=NULL;
- filterclass->process=NULL;
- filterclass->destroy=NULL;
- filterclass->attributes=0;
- filterclass->ref_count=0;
-}
-
-/* find output queue */
-gint find_oq(MSFilter *m1,MSQueue *oq)
-{
- gint i;
-
- for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++){
- if (m1->outqueues[i]==oq) return i;
- }
-
- return -1;
-}
-
-/* find input queue */
-gint find_iq(MSFilter *m1,MSQueue *iq)
-{
- gint i;
- for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qinputs;i++){
- if (m1->inqueues[i]==iq) return i;
- }
- return -1;
-}
-
-/* find output fifo */
-gint find_of(MSFilter *m1,MSFifo *of)
-{
- gint i;
- for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++){
- if (m1->outfifos[i]==of) return i;
- }
-
- return -1;
-}
-
-/* find input fifo */
-gint find_if(MSFilter *m1,MSFifo *inf)
-{
- gint i;
-
- for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_finputs;i++){
- if (m1->infifos[i]==inf) return i;
- }
-
- return -1;
-}
-
-#define find_free_iq(_m1) find_iq(_m1,NULL)
-#define find_free_oq(_m1) find_oq(_m1,NULL)
-#define find_free_if(_m1) find_if(_m1,NULL)
-#define find_free_of(_m1) find_of(_m1,NULL)
-
-int ms_filter_add_link(MSFilter *m1, MSFilter *m2)
-{
- gint m1_q=-1;
- gint m1_f=-1;
- gint m2_q=-1;
- gint m2_f=-1;
- /* determine the type of link we can add */
- m1_q=find_free_oq(m1);
- m1_f=find_free_of(m1);
- m2_q=find_free_iq(m2);
- m2_f=find_free_if(m2);
- if ((m1_q!=-1) && (m2_q!=-1)){
- /* link with queues */
- ms_trace("m1_q=%i , m2_q=%i",m1_q,m2_q);
- return ms_filter_link(m1,m1_q,m2,m2_q,LINK_QUEUE);
- }
- if ((m1_f!=-1) && (m2_f!=-1)){
- /* link with queues */
- ms_trace("m1_f=%i , m2_f=%i",m1_f,m2_f);
- return ms_filter_link(m1,m1_f,m2,m2_f,LINK_FIFO);
- }
- g_warning("ms_filter_add_link: could not link.");
- return -1;
-}
-/**
- * ms_filter_link:
- * @m1: A #MSFilter object.
- * @pin1: The pin number on @m1.
- * @m2: A #MSFilter object.
- * @pin2: The pin number on @m2.
- * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
- *
- * This function links two MSFilter object between them. It must be used to make chains of filters.
- * All data outgoing from pin1 of m1 will go to the input pin2 of m2.
- * The way to communicate can be fifos or queues, depending of the nature of the filters. Filters can have
- * multiple queue pins and multiple fifo pins, but most of them have only one queue input/output or only one
- * fifo input/output. Fifos are usally used by filters doing audio processing, while queues are used by filters doing
- * video processing.
- *
- * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
- */
-int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, int linktype)
-{
- MSQueue *q;
- MSFifo *fifo;
-
- g_message("ms_filter_add_link: %s,%i -> %s,%i",m1->klass->name,pin1,m2->klass->name,pin2);
- switch(linktype)
- {
- case LINK_QUEUE:
- /* Are filter m1 and m2 able to accept more queues connections ?*/
- g_return_val_if_fail(m1->qoutputs<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EMLINK);
- g_return_val_if_fail(m2->qinputs<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EMLINK);
- /* Are filter m1 and m2 valid with their inputs and outputs ?*/
- g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
- g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
- /* are the requested pins exists ?*/
- g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
- g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
- /* are the requested pins free ?*/
- g_return_val_if_fail(m1->outqueues[pin1]==NULL,-EBUSY);
- g_return_val_if_fail(m2->inqueues[pin2]==NULL,-EBUSY);
-
- q=ms_queue_new();
- m1->outqueues[pin1]=m2->inqueues[pin2]=q;
- m1->qoutputs++;
- m2->qinputs++;
- q->prev_data=(void*)m1;
- q->next_data=(void*)m2;
- break;
- case LINK_FIFO:
- /* Are filter m1 and m2 able to accept more fifo connections ?*/
- g_return_val_if_fail(m1->foutputs<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EMLINK);
- g_return_val_if_fail(m2->finputs<MS_FILTER_GET_CLASS(m2)->max_finputs,-EMLINK);
- /* Are filter m1 and m2 valid with their inputs and outputs ?*/
- g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
- g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
- /* are the requested pins exists ?*/
- g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
- g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
- /* are the requested pins free ?*/
- g_return_val_if_fail(m1->outfifos[pin1]==NULL,-EBUSY);
- g_return_val_if_fail(m2->infifos[pin2]==NULL,-EBUSY);
-
- if (MS_FILTER_GET_CLASS(m1)->attributes & FILTER_IS_SOURCE)
- {
- /* configure min_fifo_size */
- fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
- MS_FILTER_GET_CLASS(m1)->w_maxgran,
- MS_FILTER_GET_CLASS(m2)->r_offset,
- MS_FILTER_GET_CLASS(m1)->w_offset,
- MS_FILTER_GET_CLASS(m1)->w_maxgran);
- m2->min_fifo_size=MS_FILTER_GET_CLASS(m1)->w_maxgran;
- }
- else
- {
- gint next_size;
- ms_trace("ms_filter_add_link: min_fifo_size=%i",m1->min_fifo_size);
- fifo=ms_fifo_new_with_buffer(MS_FILTER_GET_CLASS(m2)->r_maxgran,
- MS_FILTER_GET_CLASS(m1)->w_maxgran,
- MS_FILTER_GET_CLASS(m2)->r_offset,
- MS_FILTER_GET_CLASS(m1)->w_offset,
- m1->min_fifo_size);
- if (MS_FILTER_GET_CLASS(m2)->r_maxgran>0){
- next_size=(m1->min_fifo_size*
- (MS_FILTER_GET_CLASS(m2)->w_maxgran)) /
- (MS_FILTER_GET_CLASS(m2)->r_maxgran);
- }else next_size=m1->min_fifo_size;
- ms_trace("ms_filter_add_link: next_size=%i",next_size);
- m2->min_fifo_size=next_size;
- }
-
-
- m1->outfifos[pin1]=m2->infifos[pin2]=fifo;
- m1->foutputs++;
- m2->finputs++;
- fifo->prev_data=(void*)m1;
- fifo->next_data=(void*)m2;
- break;
- }
- return 0;
-}
-/**
- * ms_filter_unlink:
- * @m1: A #MSFilter object.
- * @pin1: The pin number on @m1.
- * @m2: A #MSFilter object.
- * @pin2: The pin number on @m2.
- * @linktype: Type of connection, it may be #LINK_QUEUE, #LINK_FIFOS.
- *
- * Unlink @pin1 of filter @m1 from @pin2 of filter @m2. @linktype specifies what type of connection is removed.
- *
- * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
- */
-int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype)
-{
- switch(linktype)
- {
- case LINK_QUEUE:
- /* Are filter m1 and m2 valid with their inputs and outputs ?*/
- g_return_val_if_fail(m1->outqueues!=NULL,-EFAULT);
- g_return_val_if_fail(m2->inqueues!=NULL,-EFAULT);
- /* are the requested pins exists ?*/
- g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_qoutputs,-EINVAL);
- g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_qinputs,-EINVAL);
- /* are the requested pins busy ?*/
- g_return_val_if_fail(m1->outqueues[pin1]!=NULL,-ENOENT);
- g_return_val_if_fail(m2->inqueues[pin2]!=NULL,-ENOENT);
- /* are the two pins connected together ?*/
- g_return_val_if_fail(m1->outqueues[pin1]==m2->inqueues[pin2],-EINVAL);
-
- ms_queue_destroy(m1->outqueues[pin1]);
- m1->outqueues[pin1]=m2->inqueues[pin2]=NULL;
- m1->qoutputs--;
- m2->qinputs--;
-
- break;
- case LINK_FIFO:
- /* Are filter m1 and m2 valid with their inputs and outputs ?*/
- g_return_val_if_fail(m1->outfifos!=NULL,-EFAULT);
- g_return_val_if_fail(m2->infifos!=NULL,-EFAULT);
- /* are the requested pins exists ?*/
- g_return_val_if_fail(pin1<MS_FILTER_GET_CLASS(m1)->max_foutputs,-EINVAL);
- g_return_val_if_fail(pin2<MS_FILTER_GET_CLASS(m2)->max_finputs,-EINVAL);
- /* are the requested pins busy ?*/
- g_return_val_if_fail(m1->outfifos[pin1]!=NULL,-ENOENT);
- g_return_val_if_fail(m2->infifos[pin2]!=NULL,-ENOENT);
- /* are the two pins connected together ?*/
- g_return_val_if_fail(m1->outfifos[pin1]==m2->infifos[pin2],-EINVAL);
- ms_fifo_destroy_with_buffer(m1->outfifos[pin1]);
- m1->outfifos[pin1]=m2->infifos[pin2]=NULL;
- m1->foutputs--;
- m2->finputs--;
- break;
- }
- return 0;
-}
-
-/**
- *ms_filter_remove_links:
- *@m1: a filter
- *@m2: another filter.
- *
- * Removes all links between m1 and m2.
- *
- *Returns: 0 if one more link have been removed, -1 if not.
-**/
-gint ms_filter_remove_links(MSFilter *m1, MSFilter *m2)
-{
- int i,j;
- int removed=-1;
- MSQueue *qo;
- MSFifo *fo;
- /* takes all outputs of m1, and removes the one that goes to m2 */
- if (m1->outqueues!=NULL){
- for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_qoutputs;i++)
- {
- qo=m1->outqueues[i];
- if (qo!=NULL){
- MSFilter *rmf;
- /* test if the queue connects to m2 */
- rmf=(MSFilter*)qo->next_data;
- if (rmf==m2){
- j=find_iq(rmf,qo);
- if (j==-1) g_error("Could not find input queue: impossible case.");
- ms_filter_unlink(m1,i,m2,j,LINK_QUEUE);
- removed=0;
- }
- }
- }
- }
- if (m1->outfifos!=NULL){
- for (i=0;i<MS_FILTER_GET_CLASS(m1)->max_foutputs;i++)
- {
- fo=m1->outfifos[i];
- if (fo!=NULL){
- MSFilter *rmf;
- /* test if the queue connects to m2 */
- rmf=(MSFilter*)fo->next_data;
- if (rmf==m2){
- j=find_if(rmf,fo);
- if (j==-1) g_error("Could not find input fifo: impossible case.");
- ms_filter_unlink(m1,i,m2,j,LINK_FIFO);
- removed=0;
- }
- }
- }
- }
- return removed;
-}
-
-/**
- * ms_filter_fifos_have_data:
- * @f: a #MSFilter object.
- *
- * Tells if the filter has enough data in its input fifos in order to be executed succesfully.
- *
- * Returns: 1 if it can be executed, 0 else.
- */
-gint ms_filter_fifos_have_data(MSFilter *f)
-{
- gint i,j;
- gint max_inputs=f->klass->max_finputs;
- gint con_inputs=f->finputs;
- MSFifo *fifo;
- /* test fifos */
- for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
- {
- fifo=f->infifos[i];
- if (fifo!=NULL)
- {
- j++;
- if (fifo->readsize==0) return 0;
- if (fifo->readsize>=f->r_mingran) return 1;
- }
- }
- return 0;
-}
-
-/**
- * ms_filter_queues_have_data:
- * @f: a #MSFilter object.
- *
- * Tells if the filter has enough data in its input queues in order to be executed succesfully.
- *
- * Returns: 1 if it can be executed, 0 else.
- */
-gint ms_filter_queues_have_data(MSFilter *f)
-{
- gint i,j;
- gint max_inputs=f->klass->max_qinputs;
- gint con_inputs=f->qinputs;
- MSQueue *q;
- /* test queues */
- for(i=0,j=0; (i<max_inputs) && (j<con_inputs);i++)
- {
- q=f->inqueues[i];
- if (q!=NULL)
- {
- j++;
- if (ms_queue_can_get(q)) return 1;
- }
- }
- return 0;
-}
-
-
-
-void ms_filter_destroy(MSFilter *f)
-{
- /* first check if the filter is disconnected from any others */
- g_return_if_fail(f->finputs==0);
- g_return_if_fail(f->foutputs==0);
- g_return_if_fail(f->qinputs==0);
- g_return_if_fail(f->qoutputs==0);
- f->klass->destroy(f);
-}
-
-GList *filter_list=NULL;
-
-void ms_filter_register(MSFilterInfo *info)
-{
- gpointer tmp;
- tmp=g_list_find(filter_list,info);
- if (tmp==NULL) filter_list=g_list_append(filter_list,(gpointer)info);
-}
-
-void ms_filter_unregister(MSFilterInfo *info)
-{
- filter_list=g_list_remove(filter_list,(gpointer)info);
-}
-
-static gint compare_names(gpointer info, gpointer name)
-{
- MSFilterInfo *i=(MSFilterInfo*) info;
- return (strcmp(i->name,name));
-}
-
-MSFilterInfo * ms_filter_get_by_name(const gchar *name)
-{
- GList *elem=g_list_find_custom(filter_list,
- (gpointer)name,(GCompareFunc)compare_names);
- if (elem!=NULL){
- return (MSFilterInfo*)elem->data;
- }
- return NULL;
-}
-
-
-
-MSFilter * ms_filter_new_with_name(const gchar *name)
-{
- MSFilterInfo *info=ms_filter_get_by_name(name);
- if (info!=NULL) return info->constructor();
- g_warning("ms_filter_new_with_name: no filter named %s found.",name);
- return NULL;
-}
-
-
-/* find the first codec in the left part of the stream */
-MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type)
-{
- MSFilter *tmp=f;
- MSFilterInfo *info;
-
- if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL)){
- tmp=(MSFilter*) tmp->infifos[0]->prev_data;
- while(1){
- info=MS_FILTER_GET_CLASS(tmp)->info;
- if (info!=NULL){
- if ( (info->type==type) ){
- return tmp;
- }
- }
- if ((tmp->infifos!=NULL) && (tmp->infifos[0]!=NULL))
- tmp=(MSFilter*) tmp->infifos[0]->prev_data;
- else break;
- }
- }
- tmp=f;
- if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL)){
- tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
- while(1){
-
- info=MS_FILTER_GET_CLASS(tmp)->info;
- if (info!=NULL){
- if ( (info->type==type)){
- return tmp;
- }
- }else g_warning("ms_filter_search_upstream_by_type: filter %s has no info."
- ,MS_FILTER_GET_CLASS(tmp)->name);
- if ((tmp->inqueues!=NULL) && (tmp->inqueues[0]!=NULL))
- tmp=(MSFilter*) tmp->inqueues[0]->prev_data;
- else break;
- }
- }
- return NULL;
-}
-
-
-int ms_filter_set_property(MSFilter *f, MSFilterProperty prop,void *value)
-{
- if (f->klass->set_property!=NULL){
- return f->klass->set_property(f,prop,value);
- }
- return 0;
-}
-
-int ms_filter_get_property(MSFilter *f, MSFilterProperty prop,void *value)
-{
- if (f->klass->get_property!=NULL){
- return f->klass->get_property(f,prop,value);
- }
- return -1;
-}
-
-void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata)
-{
- filter->notify_event=func;
- filter->userdata=userdata;
-}
-
-void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg)
-{
- if (filter->notify_event!=NULL){
- filter->notify_event(filter,event,arg,filter->userdata);
- }
-}
-
-void swap_buffer(gchar *buffer, gint len)
-{
- int i;
- gchar tmp;
- for (i=0;i<len;i+=2){
- tmp=buffer[i];
- buffer[i]=buffer[i+1];
- buffer[i+1]=tmp;
- }
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.h
deleted file mode 100644
index 71ec81a..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msfilter.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSFILTER_H
-#define MSFILTER_H
-
-#include <config.h>
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#include <gmodule.h>
-#else
-#undef VERSION
-#undef PACKAGE
-#include <uglib.h>
-#endif
-
-#include <string.h>
-#include "msutils.h"
-#include "msfifo.h"
-#include "msqueue.h"
-
-struct _MSFilter;
-/*this is the abstract object and class for all filter types*/
-typedef gint (*MSFilterNotifyFunc)(struct _MSFilter*, gint event, gpointer arg, gpointer userdata);
-
-struct _MSFilter
-{
- struct _MSFilterClass *klass;
- GMutex *lock;
- guchar finputs; /* number of connected fifo inputs*/
- guchar foutputs; /* number of connected fifo outputs*/
- guchar qinputs; /* number of connected queue inputs*/
- guchar qoutputs; /* number of connected queue outputs*/
- gint min_fifo_size; /* set when linking*/
- gint r_mingran; /* read minimum granularity (for fifos).
- It can be zero so that the filter can accept any size of reading data*/
- MSFifo **infifos; /*pointer to a table of pointer to input fifos*/
- MSFifo **outfifos; /*pointer to a table of pointer to output fifos*/
- MSQueue **inqueues; /*pointer to a table of pointer to input queues*/
- MSQueue **outqueues; /*pointer to a table of pointer to output queues*/
- MSFilterNotifyFunc notify_event;
- gpointer userdata;
-};
-
-typedef struct _MSFilter MSFilter;
-
-typedef enum{
- MS_FILTER_PROPERTY_FREQ, /* value is int */
- MS_FILTER_PROPERTY_BITRATE, /*value is int */
- MS_FILTER_PROPERTY_CHANNELS,/*value is int */
- MS_FILTER_PROPERTY_FMTP /* value is string */
-}MSFilterProperty;
-
-#define MS_FILTER_PROPERTY_STRING_MAX_SIZE 256
-
-typedef MSFilter * (*MSFilterNewFunc)(void);
-typedef void (*MSFilterProcessFunc)(MSFilter *);
-typedef void (*MSFilterDestroyFunc)(MSFilter *);
-typedef int (*MSFilterPropertyFunc)(MSFilter *,int ,void*);
-typedef void (*MSFilterSetupFunc)(MSFilter *, void *); /*2nd arg is the sync */
-
-typedef struct _MSFilterClass
-{
- struct _MSFilterInfo *info; /*pointer to a filter_info */
- gchar *name;
- guchar max_finputs; /* maximum number of fifo inputs*/
- guchar max_foutputs; /* maximum number of fifo outputs*/
- guchar max_qinputs; /* maximum number of queue inputs*/
- guchar max_qoutputs; /* maximum number of queue outputs*/
- gint r_maxgran; /* read maximum granularity (for fifos)*/
- gint w_maxgran; /* write maximum granularity (for fifos)*/
- gint r_offset; /* size of kept samples behind read pointer (for fifos)*/
- gint w_offset; /* size of kept samples behind write pointer (for fifos)*/
- MSFilterPropertyFunc set_property;
- MSFilterPropertyFunc get_property;
- MSFilterSetupFunc setup; /* called when attaching to sync */
- void (*process)(MSFilter *filter);
- MSFilterSetupFunc unsetup; /* called when detaching from sync */
- void (*destroy)(MSFilter *filter);
- guint attributes;
-#define FILTER_HAS_FIFOS (0x0001)
-#define FILTER_HAS_QUEUES (0x0001<<1)
-#define FILTER_IS_SOURCE (0x0001<<2)
-#define FILTER_IS_SINK (0x0001<<3)
-#define FILTER_CAN_SYNC (0x0001<<4)
- guint ref_count; /*number of object using the class*/
-} MSFilterClass;
-
-
-
-#define MS_FILTER(obj) ((MSFilter*)obj)
-#define MS_FILTER_CLASS(klass) ((MSFilterClass*)klass)
-#define MS_FILTER_GET_CLASS(obj) ((MSFilterClass*)((MS_FILTER(obj)->klass)))
-
-void ms_filter_class_init(MSFilterClass *filterclass);
-void ms_filter_init(MSFilter *filter);
-
-#define ms_filter_class_set_attr(filter,flag) ((filter)->attributes|=(flag))
-#define ms_filter_class_unset_attr(filter,flag) ((filter)->attributes&=~(flag))
-
-#define ms_filter_class_set_name(__klass,__name) (__klass)->name=g_strdup((__name))
-#define ms_filter_class_set_info(_klass,_info) (_klass)->info=(_info)
-/* public*/
-
-#define ms_filter_process(filter) ((filter)->klass->process((filter)))
-
-#define ms_filter_lock(filter) g_mutex_lock((filter)->lock)
-#define ms_filter_unlock(filter) g_mutex_unlock((filter)->lock)
-/* low level connect functions */
-int ms_filter_link(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2, gint linktype);
-int ms_filter_unlink(MSFilter *m1, gint pin1, MSFilter *m2,gint pin2,gint linktype);
-
-/* high level connect functions */
-int ms_filter_add_link(MSFilter *m1, MSFilter *m2);
-int ms_filter_remove_links(MSFilter *m1, MSFilter *m2);
-
-void ms_filter_set_notify_func(MSFilter* filter,MSFilterNotifyFunc func, gpointer userdata);
-void ms_filter_notify_event(MSFilter *filter,gint event, gpointer arg);
-
-int ms_filter_set_property(MSFilter *f,MSFilterProperty property, void *value);
-int ms_filter_get_property(MSFilter *f,MSFilterProperty property, void *value);
-
-
-gint ms_filter_fifos_have_data(MSFilter *f);
-gint ms_filter_queues_have_data(MSFilter *f);
-
-void ms_filter_uninit(MSFilter *obj);
-void ms_filter_destroy(MSFilter *f);
-
-#define ms_filter_get_mingran(f) ((f)->r_mingran)
-#define ms_filter_set_mingran(f,gran) ((f)->r_mingran=(gran))
-
-#define LINK_DEFAULT 0
-#define LINK_FIFO 1
-#define LINK_QUEUE 2
-
-
-#define MSFILTER_VERSION(a,b,c) (((a)<<2)|((b)<<1)|(c))
-
-enum _MSFilterType
-{
- MS_FILTER_DISK_IO,
- MS_FILTER_AUDIO_CODEC,
- MS_FILTER_VIDEO_CODEC,
- MS_FILTER_NET_IO,
- MS_FILTER_VIDEO_IO,
- MS_FILTER_AUDIO_IO,
- MS_FILTER_OTHER
-};
-
-typedef enum _MSFilterType MSFilterType;
-
-
-/* find the first codec in the left part of the stream */
-MSFilter * ms_filter_search_upstream_by_type(MSFilter *f,MSFilterType type);
-
-struct _MSFilterInfo
-{
- gchar *name;
- gint version;
- MSFilterType type;
- MSFilterNewFunc constructor;
- char *description; /*some textual information*/
-};
-
-typedef struct _MSFilterInfo MSFilterInfo;
-
-void ms_filter_register(MSFilterInfo *finfo);
-void ms_filter_unregister(MSFilterInfo *finfo);
-MSFilterInfo * ms_filter_get_by_name(const gchar *name);
-
-MSFilter * ms_filter_new_with_name(const gchar *name);
-
-
-
-extern GList *filter_list;
-#define MS_FILTER_INFO(obj) ((MSFilterInfo*)obj)
-
-void swap_buffer(gchar *buffer, gint len);
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.c
deleted file mode 100644
index b2dfff9..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <config.h>
-
-#ifdef HAVE_ILBC
-
-
-#include "msilbcdec.h"
-#include "msilbcenc.h"
-#include "mscodec.h"
-#include <stdlib.h>
-#include <stdio.h>
-
-
-
-extern MSFilter * ms_ilbc_encoder_new(void);
-
-MSCodecInfo ilbc_info={
- {
- "iLBC codec",
- 0,
- MS_FILTER_AUDIO_CODEC,
- ms_ilbc_encoder_new,
- "A speech codec suitable for robust voice communication over IP"
- },
- ms_ilbc_encoder_new,
- ms_ilbc_decoder_new,
- 0, /* not applicable, 2 modes */
- 0, /* not applicable, 2 modes */
- 15200,
- 8000,
- 97,
- "iLBC",
- 1,
- 1,
-};
-
-
-void ms_ilbc_codec_init()
-{
- ms_filter_register(MS_FILTER_INFO(&ilbc_info));
-}
-
-
-
-static MSILBCDecoderClass *ms_ilbc_decoder_class=NULL;
-
-MSFilter * ms_ilbc_decoder_new(void)
-{
- MSILBCDecoder *r;
-
- r=g_new(MSILBCDecoder,1);
- ms_ilbc_decoder_init(r);
- if (ms_ilbc_decoder_class==NULL)
- {
- ms_ilbc_decoder_class=g_new(MSILBCDecoderClass,1);
- ms_ilbc_decoder_class_init(ms_ilbc_decoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ilbc_decoder_class);
- return(MS_FILTER(r));
-}
-
-
-int ms_ilbc_decoder_set_property(MSILBCDecoder *obj, MSFilterProperty prop, char *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FMTP:
- if (value == NULL) return 0;
- if (strstr(value,"ptime=20")!=NULL) obj->ms_per_frame=20;
- else if (strstr(value,"ptime=30")!=NULL) obj->ms_per_frame=30;
- else g_warning("Unrecognized fmtp parameter for ilbc encoder!");
- break;
- }
- return 0;
-}
-int ms_ilbc_decoder_get_property(MSILBCDecoder *obj, MSFilterProperty prop, char *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FMTP:
- if (obj->ms_per_frame==20) strncpy(value,"ptime=20",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
- if (obj->ms_per_frame==30) strncpy(value,"ptime=30",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
- break;
- }
- return 0;
-}
-
-void ms_ilbc_decoder_setup(MSILBCDecoder *r)
-{
- MSFilterClass *klass = NULL;
- switch (r->ms_per_frame) {
- case 20:
- r->samples_per_frame = BLOCKL_20MS;
- r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
- break;
- case 30:
- r->samples_per_frame = BLOCKL_30MS;
- r->bytes_per_compressed_frame = NO_OF_BYTES_30MS;
- break;
- default:
- g_error("ms_ilbc_decoder_setup: Bad value for ptime (%i)",r->ms_per_frame);
- }
- g_message("Using ilbc decoder with %i ms frames mode.",r->ms_per_frame);
- initDecode(&r->ilbc_dec, r->ms_per_frame /* ms frames */, /* user enhancer */ 0);
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_ilbc_decoder_init(MSILBCDecoder *r)
-{
- /* default bitrate */
- r->bitrate = 15200;
- r->ms_per_frame = 30;
- r->samples_per_frame = BLOCKL_20MS;
- r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
-
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->inqueues=r->q_inputs;
- MS_FILTER(r)->outfifos=r->f_outputs;
- memset(r->q_inputs,0,sizeof(MSFifo*)*MSILBCDECODER_MAX_INPUTS);
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSILBCDECODER_MAX_INPUTS);
-}
-
-void ms_ilbc_decoder_class_init(MSILBCDecoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ILBCDec");
- MS_FILTER_CLASS(klass)->max_qinputs=MSILBCDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSILBCDECODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->w_maxgran= ILBC_MAX_SAMPLES_PER_FRAME*2;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ilbc_decoder_destroy;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ilbc_decoder_set_property;
- MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ilbc_decoder_get_property;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ilbc_decoder_setup;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ilbc_decoder_process;
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ilbc_info;
-}
-
-void ms_ilbc_decoder_process(MSILBCDecoder *r)
-{
- MSFifo *fo;
- MSQueue *qi;
- int err1;
- void *dst=NULL;
- float speech[ILBC_MAX_SAMPLES_PER_FRAME];
- MSMessage *m;
-
- qi=r->q_inputs[0];
- fo=r->f_outputs[0];
- m=ms_queue_get(qi);
-
- ms_fifo_get_write_ptr(fo, r->samples_per_frame*2, &dst);
- if (dst!=NULL){
- if (m->data!=NULL){
- if (m->size<r->bytes_per_compressed_frame) {
- g_warning("Invalid ilbc frame ?");
- }
- iLBC_decode(speech, m->data, &r->ilbc_dec, /* mode */1);
- }else{
- iLBC_decode(speech,NULL, &r->ilbc_dec,0);
- }
- ilbc_write_16bit_samples((gint16*)dst, speech, r->samples_per_frame);
- }
- ms_message_destroy(m);
-}
-
-void ms_ilbc_decoder_uninit(MSILBCDecoder *obj)
-{
-}
-
-void ms_ilbc_decoder_destroy( MSILBCDecoder *obj)
-{
- ms_ilbc_decoder_uninit(obj);
- g_free(obj);
-}
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.h
deleted file mode 100644
index c219aab..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcdec.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSILBCDECODER_H
-#define MSILBCDECODER_H
-
-#include <msfilter.h>
-#include <mscodec.h>
-#include <iLBC_decode.h>
-
-/*this is the class that implements a ILBCdecoder filter*/
-
-#define MSILBCDECODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSILBCDecoder
-{
- /* the MSILBCDecoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSILBCDecoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSQueue *q_inputs[MSILBCDECODER_MAX_INPUTS];
- MSFifo *f_outputs[MSILBCDECODER_MAX_INPUTS];
- iLBC_Dec_Inst_t ilbc_dec;
- int bitrate;
- int ms_per_frame;
- int samples_per_frame;
- int bytes_per_compressed_frame;
-} MSILBCDecoder;
-
-typedef struct _MSILBCDecoderClass
-{
- /* the MSILBCDecoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSILBCDecoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSILBCDecoderClass;
-
-/* PUBLIC */
-
-/* call this before if don't load the plugin dynamically */
-void ms_ilbc_codec_init();
-
-#define MS_ILBCDECODER(filter) ((MSILBCDecoder*)(filter))
-#define MS_ILBCDECODER_CLASS(klass) ((MSILBCDecoderClass*)(klass))
-MSFilter * ms_ilbc_decoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_ilbc_decoder_init(MSILBCDecoder *r);
-void ms_ilbc_decoder_class_init(MSILBCDecoderClass *klass);
-void ms_ilbc_decoder_destroy( MSILBCDecoder *obj);
-void ms_ilbc_decoder_process(MSILBCDecoder *r);
-
-extern MSCodecInfo ilbc_info;
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.c
deleted file mode 100644
index 76d8b64..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <config.h>
-
-#ifdef HAVE_ILBC
-
-#include <stdlib.h>
-#include <stdio.h>
-#include "msilbcenc.h"
-
-
-extern MSCodecInfo ilbc_info;
-
-/* The return value of each of these calls is the same as that
- returned by fread/fwrite, which should be the number of samples
- successfully read/written, not the number of bytes. */
-
-int
-ilbc_read_16bit_samples(gint16 int16samples[], float speech[], int n)
-{
- int i;
-
- /* Convert 16 bit integer samples to floating point values in the
- range [-1,+1]. */
-
- for (i = 0; i < n; i++) {
- speech[i] = int16samples[i];
- }
-
- return (n);
-}
-
-
-
-int
-ilbc_write_16bit_samples(gint16 int16samples[], float speech[], int n)
-{
- int i;
- float real_sample;
-
- /* Convert floating point samples in range [-1,+1] to 16 bit
- integers. */
- for (i = 0; i < n; i++) {
- float dtmp=speech[i];
- if (dtmp<MIN_SAMPLE)
- dtmp=MIN_SAMPLE;
- else if (dtmp>MAX_SAMPLE)
- dtmp=MAX_SAMPLE;
- int16samples[i] = (short) dtmp;
- }
- return (n);
-}
-
-/*
-
-Write the bits in bits[0] through bits[len-1] to file f, in "packed"
-format.
-
-bits is expected to be an array of len integer values, where each
-integer is 0 to represent a 0 bit, and any other value represents a 1
-bit. This bit string is written to the file f in the form of several
-8 bit characters. If len is not a multiple of 8, then the last
-character is padded with 0 bits -- the padding is in the least
-significant bits of the last byte. The 8 bit characters are "filled"
-in order from most significant bit to least significant.
-
-*/
-
-void
-ilbc_write_bits(unsigned char *data, unsigned char *bits, int nbytes)
-{
- memcpy(data, bits, nbytes);
-}
-
-
-
-/*
-
-Read bits from file f into bits[0] through bits[len-1], in "packed"
-format.
-
-*/
-
-int
-ilbc_read_bits(unsigned char *data, unsigned char *bits, int nbytes)
-{
-
- memcpy(bits, data, nbytes);
-
- return (nbytes);
-}
-
-
-
-
-static MSILBCEncoderClass *ms_ilbc_encoder_class=NULL;
-
-MSFilter * ms_ilbc_encoder_new(void)
-{
- MSILBCEncoder *r;
-
- r=g_new(MSILBCEncoder,1);
- ms_ilbc_encoder_init(r);
- if (ms_ilbc_encoder_class==NULL)
- {
- ms_ilbc_encoder_class=g_new(MSILBCEncoderClass,1);
- ms_ilbc_encoder_class_init(ms_ilbc_encoder_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ilbc_encoder_class);
- return(MS_FILTER(r));
-}
-
-
-int ms_ilbc_encoder_set_property(MSILBCEncoder *obj, MSFilterProperty prop, char *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FMTP:
- if (value == NULL) return 0;
- if (strstr(value,"ptime=20")!=NULL) obj->ms_per_frame=20;
- else if (strstr(value,"ptime=30")!=NULL) obj->ms_per_frame=30;
- else g_warning("Unrecognized fmtp parameter for ilbc encoder!");
- break;
- }
- return 0;
-}
-
-
-int ms_ilbc_encoder_get_property(MSILBCEncoder *obj, MSFilterProperty prop, char *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FMTP:
- if (obj->ms_per_frame==20) strncpy(value,"ptime=20",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
- if (obj->ms_per_frame==30) strncpy(value,"ptime=30",MS_FILTER_PROPERTY_STRING_MAX_SIZE);
- break;
- }
- return 0;
-}
-
-void ms_ilbc_encoder_setup(MSILBCEncoder *r)
-{
- MSFilterClass *klass = NULL;
- switch (r->ms_per_frame) {
- case 20:
- r->samples_per_frame = BLOCKL_20MS;
- r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
- break;
- case 30:
- r->samples_per_frame = BLOCKL_30MS;
- r->bytes_per_compressed_frame = NO_OF_BYTES_30MS;
- break;
- default:
- g_error("Bad bitrate value (%i) for ilbc encoder!", r->ms_per_frame);
- break;
- }
- MS_FILTER(r)->r_mingran= (r->samples_per_frame * 2);
- g_message("Using ilbc encoder with %i ms frames mode.",r->ms_per_frame);
- initEncode(&r->ilbc_enc, r->ms_per_frame /* ms frames */);
-}
-
-/* FOR INTERNAL USE*/
-void ms_ilbc_encoder_init(MSILBCEncoder *r)
-{
- /* default bitrate */
- r->bitrate = 15200;
- r->ms_per_frame = 20;
- r->samples_per_frame = BLOCKL_20MS;
- r->bytes_per_compressed_frame = NO_OF_BYTES_20MS;
-
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->outqueues=r->q_outputs;
- MS_FILTER(r)->r_mingran= (r->samples_per_frame * 2);
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSILBCENCODER_MAX_INPUTS);
- memset(r->q_outputs,0,sizeof(MSFifo*)*MSILBCENCODER_MAX_INPUTS);
-}
-
-void ms_ilbc_encoder_class_init(MSILBCEncoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ILBCEnc");
- MS_FILTER_CLASS(klass)->max_finputs=MSILBCENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_qoutputs=MSILBCENCODER_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=ILBC_MAX_SAMPLES_PER_FRAME*2;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ilbc_encoder_set_property;
- MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ilbc_encoder_get_property;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ilbc_encoder_setup;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ilbc_encoder_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ilbc_encoder_process;
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&ilbc_info;
-}
-
-void ms_ilbc_encoder_process(MSILBCEncoder *r)
-{
- MSFifo *fi;
- MSQueue *qo;
- MSMessage *m;
- void *src=NULL;
- float speech[ILBC_MAX_SAMPLES_PER_FRAME];
-
- /* process output fifos, but there is only one for this class of filter*/
-
- qo=r->q_outputs[0];
- fi=r->f_inputs[0];
- ms_fifo_get_read_ptr(fi,r->samples_per_frame*2,&src);
- if (src==NULL) {
- g_warning( "src=%p\n", src);
- return;
- }
- m=ms_message_new(r->bytes_per_compressed_frame);
-
- ilbc_read_16bit_samples((gint16*)src, speech, r->samples_per_frame);
- iLBC_encode((unsigned char *)m->data, speech, &r->ilbc_enc);
- ms_queue_put(qo,m);
-}
-
-void ms_ilbc_encoder_uninit(MSILBCEncoder *obj)
-{
-}
-
-void ms_ilbc_encoder_destroy( MSILBCEncoder *obj)
-{
- ms_ilbc_encoder_uninit(obj);
- g_free(obj);
-}
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.h
deleted file mode 100644
index bd8f3bf..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msilbcenc.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSILBCENCODER_H
-#define MSILBCENCODER_H
-
-#include "mscodec.h"
-#include <iLBC_encode.h>
-
-#define ILBC_BITS_IN_COMPRESSED_FRAME 400
-
-int
-ilbc_read_16bit_samples(gint16 int16samples[], float speech[], int n);
-
-int
-ilbc_write_16bit_samples(gint16 int16samples[], float speech[], int n);
-
-void
-ilbc_write_bits(unsigned char *data, unsigned char *bits, int nbytes);
-
-int
-ilbc_read_bits(unsigned char *data, unsigned char *bits, int nbytes);
-
-
-/*this is the class that implements a ILBCencoder filter*/
-
-#define MSILBCENCODER_MAX_INPUTS 1 /* max output per filter*/
-
-
-typedef struct _MSILBCEncoder
-{
- /* the MSILBCEncoder derivates from MSFilter, so the MSFilter object MUST be the first of the MSILBCEncoder object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSILBCENCODER_MAX_INPUTS];
- MSQueue *q_outputs[MSILBCENCODER_MAX_INPUTS];
- iLBC_Enc_Inst_t ilbc_enc;
- int ilbc_encoded_bytes;
- int bitrate;
- int ms_per_frame;
- int samples_per_frame;
- int bytes_per_compressed_frame;
-} MSILBCEncoder;
-
-typedef struct _MSILBCEncoderClass
-{
- /* the MSILBCEncoder derivates from MSFilter, so the MSFilter class MUST be the first of the MSILBCEncoder class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSILBCEncoderClass;
-
-/* PUBLIC */
-#define MS_ILBCENCODER(filter) ((MSILBCEncoder*)(filter))
-#define MS_ILBCENCODER_CLASS(klass) ((MSILBCEncoderClass*)(klass))
-MSFilter * ms_ilbc_encoder_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_ilbc_encoder_init(MSILBCEncoder *r);
-void ms_ilbc_encoder_class_init(MSILBCEncoderClass *klass);
-void ms_ilbc_encoder_destroy( MSILBCEncoder *obj);
-void ms_ilbc_encoder_process(MSILBCEncoder *r);
-
-#define ILBC_MAX_BYTES_PER_COMPRESSED_FRAME NO_OF_BYTES_30MS
-#define ILBC_MAX_SAMPLES_PER_FRAME BLOCKL_30MS
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.c
deleted file mode 100644
index af5141c..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msnosync.h"
-
-static MSNoSyncClass *ms_nosync_class=NULL;
-
-void ms_nosync_init(MSNoSync *sync)
-{
- ms_sync_init(MS_SYNC(sync));
- MS_SYNC(sync)->attached_filters=sync->filters;
- memset(sync->filters,0,MSNOSYNC_MAX_FILTERS*sizeof(MSFilter*));
- MS_SYNC(sync)->samples_per_tick=160;
- sync->started=0;
-}
-
-void ms_nosync_class_init(MSNoSyncClass *klass)
-{
- ms_sync_class_init(MS_SYNC_CLASS(klass));
- MS_SYNC_CLASS(klass)->max_filters=MSNOSYNC_MAX_FILTERS;
- MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_nosync_synchronize;
- MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_nosync_destroy;
- /* no need to overload these function*/
- MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic;
- MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic;
-}
-
-void ms_nosync_destroy(MSNoSync *nosync)
-{
- g_free(nosync);
-}
-
-/* the synchronization function that does nothing*/
-void ms_nosync_synchronize(MSNoSync *nosync)
-{
- gint32 time;
- if (nosync->started==0){
- gettimeofday(&nosync->start,NULL);
- nosync->started=1;
- }
- gettimeofday(&nosync->current,NULL);
- MS_SYNC(nosync)->ticks++;
- /* update the time, we are supposed to work at 8000 Hz */
- time=((nosync->current.tv_sec-nosync->start.tv_sec)*1000) +
- ((nosync->current.tv_usec-nosync->start.tv_usec)/1000);
- MS_SYNC(nosync)->time=time;
- return;
-}
-
-
-MSSync *ms_nosync_new()
-{
- MSNoSync *nosync;
-
- nosync=g_malloc(sizeof(MSNoSync));
- ms_nosync_init(nosync);
- if (ms_nosync_class==NULL)
- {
- ms_nosync_class=g_new(MSNoSyncClass,1);
- ms_nosync_class_init(ms_nosync_class);
- }
- MS_SYNC(nosync)->klass=MS_SYNC_CLASS(ms_nosync_class);
- return(MS_SYNC(nosync));
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.h
deleted file mode 100644
index eef52d4..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msnosync.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "mssync.h"
-
-#include <sys/time.h>
-#define MSNOSYNC_MAX_FILTERS 10
-
-/* MSNoSync derivates from MSSync base class*/
-
-typedef struct _MSNoSync
-{
- /* the MSSync must be the first field of the object in order to the object mechanism to work*/
- MSSync sync;
- MSFilter *filters[MSNOSYNC_MAX_FILTERS];
- int started;
- struct timeval start,current;
-} MSNoSync;
-
-
-typedef struct _MSNoSyncClass
-{
- /* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/
- MSSyncClass parent_class;
-} MSNoSyncClass;
-
-
-/*private*/
-
-void ms_nosync_init(MSNoSync *sync);
-void ms_nosync_class_init(MSNoSyncClass *sync);
-
-void ms_nosync_destroy(MSNoSync *nosync);
-void ms_nosync_synchronize(MSNoSync *nosync);
-
-/*public*/
-
-/* casts a MSSync object into a MSNoSync */
-#define MS_NOSYNC(sync) ((MSNoSync*)(sync))
-/* casts a MSSync class into a MSNoSync class */
-#define MS_NOSYNC_CLASS(klass) ((MSNoSyncClass*)(klass))
-
-MSSync *ms_nosync_new();
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msossread.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msossread.c
deleted file mode 100644
index 2e7b032..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msossread.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msossread.h"
-#include "mssync.h"
-#include <unistd.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-MSFilterInfo oss_read_info={
- "OSS read",
- 0,
- MS_FILTER_AUDIO_IO,
- ms_oss_read_new,
- NULL
-};
-
-static MSOssReadClass *msossreadclass=NULL;
-
-MSFilter * ms_oss_read_new()
-{
- MSOssRead *w;
-
- if (msossreadclass==NULL)
- {
- msossreadclass=g_new(MSOssReadClass,1);
- ms_oss_read_class_init( msossreadclass );
- }
-
- w=g_new(MSOssRead,1);
- MS_FILTER(w)->klass=MS_FILTER_CLASS(msossreadclass);
- ms_oss_read_init(w);
-
- return(MS_FILTER(w));
-}
-
-/* FOR INTERNAL USE*/
-void ms_oss_read_init(MSOssRead *w)
-{
- ms_sound_read_init(MS_SOUND_READ(w));
- MS_FILTER(w)->outfifos=w->f_outputs;
- MS_FILTER(w)->outfifos[0]=NULL;
- w->devid=0;
- w->sndcard=NULL;
- w->freq=8000;
-}
-
-gint ms_oss_read_set_property(MSOssRead *f,MSFilterProperty prop, void *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FREQ:
- f->freq=((gint*)value)[0];
- break;
- }
- return 0;
-}
-void ms_oss_read_class_init(MSOssReadClass *klass)
-{
- ms_sound_read_class_init(MS_SOUND_READ_CLASS(klass));
- MS_FILTER_CLASS(klass)->max_foutputs=1; /* one fifo output only */
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_oss_read_setup;
- MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_oss_read_stop;
- MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_read_process;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_read_set_property;
- MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_read_destroy;
- MS_FILTER_CLASS(klass)->w_maxgran=MS_OSS_READ_MAX_GRAN;
- MS_FILTER_CLASS(klass)->info=&oss_read_info;
- MS_SOUND_READ_CLASS(klass)->set_device=(gint (*)(MSSoundRead*,gint))ms_oss_read_set_device;
- MS_SOUND_READ_CLASS(klass)->start=(void (*)(MSSoundRead*))ms_oss_read_start;
- MS_SOUND_READ_CLASS(klass)->stop=(void (*)(MSSoundRead*))ms_oss_read_stop;
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssRead");
- //ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_CAN_SYNC|FILTER_IS_SOURCE);
-}
-
-void ms_oss_read_destroy( MSOssRead *obj)
-{
- g_free(obj);
-}
-
-void ms_oss_read_process(MSOssRead *f)
-{
- MSFifo *fifo;
- char *p;
- fifo=f->f_outputs[0];
-
- g_return_if_fail(f->sndcard!=NULL);
- g_return_if_fail(f->gran>0);
-
- if (snd_card_can_read(f->sndcard)){
- int got;
- ms_fifo_get_write_ptr(fifo,f->gran,(void**)&p);
- g_return_if_fail(p!=NULL);
- got=snd_card_read(f->sndcard,p,f->gran);
- if (got>=0 && got!=f->gran) ms_fifo_update_write_ptr(fifo,got);
- }
-}
-
-
-void ms_oss_read_start(MSOssRead *r)
-{
- g_return_if_fail(r->devid!=-1);
- r->sndcard=snd_card_manager_get_card(snd_card_manager,r->devid);
- g_return_if_fail(r->sndcard!=NULL);
- /* open the device for an audio telephony signal with minimum latency */
- snd_card_open_r(r->sndcard,16,0,r->freq);
- r->gran=(512*r->freq)/8000;
-
-}
-
-void ms_oss_read_stop(MSOssRead *w)
-{
- g_return_if_fail(w->devid!=-1);
- g_return_if_fail(w->sndcard!=NULL);
- snd_card_close_r(w->sndcard);
- w->sndcard=NULL;
-}
-
-
-void ms_oss_read_setup(MSOssRead *f, MSSync *sync)
-{
- f->sync=sync;
- ms_oss_read_start(f);
-}
-
-
-gint ms_oss_read_set_device(MSOssRead *r,gint devid)
-{
- r->devid=devid;
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msossread.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msossread.h
deleted file mode 100644
index 89d5a40..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msossread.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef MSOSSREAD_H
-#define MSOSSREAD_H
-
-#include "mssoundread.h"
-#include "sndcard.h"
-#include "mssync.h"
-
-
-/*this is the class that implements oss writing sink filter*/
-
-#define MS_OSS_READ_MAX_INPUTS 1 /* max output per filter*/
-
-#define MS_OSS_READ_MAX_GRAN (512*2) /* the maximum granularity*/
-
-struct _MSOssRead
-{
- /* the MSOssRead derivates from MSSoundRead so the MSSoundRead object MUST be the first of the MSOssRead object
- in order to the object mechanism to work*/
- MSSoundRead filter;
- MSFifo *f_outputs[MS_OSS_READ_MAX_INPUTS];
- MSSync *sync;
- SndCard *sndcard;
- gint freq;
- gint devid; /* the sound device id it depends on*/
- gint gran;
- gint flags;
-#define START_REQUESTED 1
-#define STOP_REQUESTED 2
-};
-
-typedef struct _MSOssRead MSOssRead;
-
-struct _MSOssReadClass
-{
- /* the MSOssRead derivates from MSSoundRead, so the MSSoundRead class MUST be the first of the MSOssRead class
- in order to the class mechanism to work*/
- MSSoundReadClass parent_class;
-};
-
-typedef struct _MSOssReadClass MSOssReadClass;
-
-/* PUBLIC */
-#define MS_OSS_READ(filter) ((MSOssRead*)(filter))
-#define MS_OSS_READ_CLASS(klass) ((MSOssReadClass*)(klass))
-MSFilter * ms_oss_read_new(void);
-gint ms_oss_read_set_device(MSOssRead *w,gint devid);
-void ms_oss_read_start(MSOssRead *w);
-void ms_oss_read_stop(MSOssRead *w);
-
-/* FOR INTERNAL USE*/
-void ms_oss_read_init(MSOssRead *r);
-void ms_oss_read_class_init(MSOssReadClass *klass);
-void ms_oss_read_destroy( MSOssRead *obj);
-void ms_oss_read_process(MSOssRead *f);
-void ms_oss_read_setup(MSOssRead *f, MSSync *sync);
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.c
deleted file mode 100644
index 13a0dfe..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msosswrite.h"
-#include "mssync.h"
-#include <unistd.h>
-#include <math.h>
-
-MSFilterInfo oss_write_info={
- "OSS write",
- 0,
- MS_FILTER_OTHER,
- ms_oss_write_new,
- NULL
-};
-
-
-static MSOssWriteClass *msosswriteclass=NULL;
-
-MSFilter * ms_oss_write_new()
-{
- MSOssWrite *w;
-
- if (msosswriteclass==NULL)
- {
- msosswriteclass=g_new(MSOssWriteClass,1);
- ms_oss_write_class_init( msosswriteclass );
- }
- w=g_new(MSOssWrite,1);
- MS_FILTER(w)->klass=MS_FILTER_CLASS(msosswriteclass);
- ms_oss_write_init(w);
- return(MS_FILTER(w));
-}
-
-/* FOR INTERNAL USE*/
-void ms_oss_write_init(MSOssWrite *w)
-{
- ms_sound_write_init(MS_SOUND_WRITE(w));
- MS_FILTER(w)->infifos=w->f_inputs;
- MS_FILTER(w)->infifos[0]=NULL;
- MS_FILTER(w)->r_mingran=512; /* very few cards can do that...*/
- w->devid=0;
- w->sndcard=NULL;
- w->freq=8000;
- w->channels=1;
- w->dtmf_time=-1;
-}
-
-gint ms_oss_write_set_property(MSOssWrite *f,MSFilterProperty prop, void *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FREQ:
- f->freq=((gint*)value)[0];
- break;
- case MS_FILTER_PROPERTY_CHANNELS:
- f->channels=((gint*)value)[0];
- break;
- }
- return 0;
-}
-
-void ms_oss_write_class_init(MSOssWriteClass *klass)
-{
- ms_sound_write_class_init(MS_SOUND_WRITE_CLASS(klass));
- MS_FILTER_CLASS(klass)->max_finputs=1; /* one fifo input only */
- MS_FILTER_CLASS(klass)->r_maxgran=MS_OSS_WRITE_DEF_GRAN;
- MS_FILTER_CLASS(klass)->process= (MSFilterProcessFunc)ms_oss_write_process;
- MS_FILTER_CLASS(klass)->destroy= (MSFilterDestroyFunc)ms_oss_write_destroy;
- MS_FILTER_CLASS(klass)->setup= (MSFilterSetupFunc)ms_oss_write_setup;
- MS_FILTER_CLASS(klass)->unsetup= (MSFilterSetupFunc)ms_oss_write_stop;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_oss_write_set_property;
- MS_FILTER_CLASS(klass)->info=&oss_write_info;
- MS_SOUND_WRITE_CLASS(klass)->set_device=(gint (*)(MSSoundWrite*,gint))ms_oss_write_set_device;
- MS_SOUND_WRITE_CLASS(klass)->start=(void (*)(MSSoundWrite*))ms_oss_write_start;
- MS_SOUND_WRITE_CLASS(klass)->stop=(void (*)(MSSoundWrite*))ms_oss_write_stop;
- MS_SOUND_WRITE_CLASS(klass)->set_level=(void (*)(MSSoundWrite*, gint))ms_oss_write_set_level;
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"OssWrite");
-}
-
-void ms_oss_write_destroy( MSOssWrite *obj)
-{
-
- g_free(obj);
-}
-
-void ms_oss_write_process(MSOssWrite *f)
-{
- MSFifo *fifo;
- void *p;
- int i;
- gint gran=ms_filter_get_mingran(MS_FILTER(f));
-
- /* always consume something */
- fifo=f->f_inputs[0];
- ms_fifo_get_read_ptr(fifo,gran,&p);
- if (p==NULL) {
- g_warning("Not enough data: gran=%i.",gran);
- return;
- }
- g_return_if_fail(f->sndcard!=NULL);
- if (f->dtmf_time!=-1){
- gint16 *buf=(gint16*)p;
- /* generate a DTMF*/
- for(i=0;i<gran/2;i++){
- buf[i]=(gint16)(10000.0*sin(2*M_PI*(double)f->dtmf_time*f->lowfreq));
- buf[i]+=(gint16)(10000.0*sin(2*M_PI*(double)f->dtmf_time*f->highfreq));
- f->dtmf_time++;
- //printf("buf[%i]=%i\n",i,buf[i]);
- }
- if (f->dtmf_time>f->dtmf_duration) f->dtmf_time=-1; /*finished*/
- }
- snd_card_write(f->sndcard,p,gran);
-}
-
-void ms_oss_write_start(MSOssWrite *w)
-{
- gint bsize;
- g_return_if_fail(w->devid!=-1);
- w->sndcard=snd_card_manager_get_card(snd_card_manager,w->devid);
- g_return_if_fail(w->sndcard!=NULL);
- /* open the device for an audio telephony signal with minimum latency */
- snd_card_open_w(w->sndcard,16,w->channels==2,w->freq);
- w->bsize=snd_card_get_bsize(w->sndcard);
- //MS_FILTER(w)->r_mingran=w->bsize;
- //ms_sync_set_samples_per_tick(MS_FILTER(w)->sync,bsize);
-}
-
-void ms_oss_write_stop(MSOssWrite *w)
-{
- g_return_if_fail(w->devid!=-1);
- g_return_if_fail(w->sndcard!=NULL);
- snd_card_close_w(w->sndcard);
- w->sndcard=NULL;
-}
-
-void ms_oss_write_set_level(MSOssWrite *w,gint a)
-{
-
-}
-
-gint ms_oss_write_set_device(MSOssWrite *w, gint devid)
-{
- w->devid=devid;
- return 0;
-}
-
-void ms_oss_write_setup(MSOssWrite *r)
-{
- //g_message("starting MSOssWrite..");
- ms_oss_write_start(r);
-}
-
-
-
-void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf){
-
- w->dtmf_duration=0.1*w->freq;
- switch(dtmf){
- case '0':
- w->lowfreq=941;
- w->highfreq=1336;
- break;
- case '1':
- w->lowfreq=697;
- w->highfreq=1209;
- break;
- case '2':
- w->lowfreq=697;
- w->highfreq=1336;
- break;
- case '3':
- w->lowfreq=697;
- w->highfreq=1477;
- break;
- case '4':
- w->lowfreq=770;
- w->highfreq=1209;
- break;
- case '5':
- w->lowfreq=770;
- w->highfreq=1336;
- break;
- case '6':
- w->lowfreq=770;
- w->highfreq=1477;
- break;
- case '7':
- w->lowfreq=852;
- w->highfreq=1209;
- break;
- case '8':
- w->lowfreq=852;
- w->highfreq=1336;
- break;
- case '9':
- w->lowfreq=852;
- w->highfreq=1477;
- break;
- case '*':
- w->lowfreq=941;
- w->highfreq=1209;
- break;
- case '#':
- w->lowfreq=941;
- w->highfreq=1477;
- break;
- case 'A':
- w->lowfreq=697;
- w->highfreq=1633;
- break;
- case 'B':
- w->lowfreq=770;
- w->highfreq=1633;
- break;
- case 'C':
- w->lowfreq=852;
- w->highfreq=1633;
- break;
- case 'D':
- w->lowfreq=941;
- w->highfreq=1633;
- break;
- default:
- g_warning("Not a dtmf key.");
- return;
- }
- w->lowfreq=w->lowfreq/w->freq;
- w->highfreq=w->highfreq/w->freq;
- w->dtmf_time=0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.h
deleted file mode 100644
index d477534..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msosswrite.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef MSOSSWRITE_H
-#define MSOSSWRITE_H
-
-#include "mssoundwrite.h"
-#include "sndcard.h"
-
-/*this is the class that implements oss writing sink filter*/
-
-#define MS_OSS_WRITE_MAX_INPUTS 1 /* max output per filter*/
-
-#define MS_OSS_WRITE_DEF_GRAN (512*2) /* the default granularity*/
-
-struct _MSOssWrite
-{
- /* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite object MUST be the first of the MSOssWrite object
- in order to the object mechanism to work*/
- MSSoundWrite filter;
- MSFifo *f_inputs[MS_OSS_WRITE_MAX_INPUTS];
- gint devid; /* the sound device id it depends on*/
- SndCard *sndcard;
- gint bsize;
- gint freq;
- gint channels;
- gdouble lowfreq;
- gdouble highfreq;
- gint dtmf_time;
- gint dtmf_duration;
-};
-
-typedef struct _MSOssWrite MSOssWrite;
-
-struct _MSOssWriteClass
-{
- /* the MSOssWrite derivates from MSSoundWrite, so the MSSoundWrite class MUST be the first of the MSOssWrite class
- in order to the class mechanism to work*/
- MSSoundWriteClass parent_class;
-};
-
-typedef struct _MSOssWriteClass MSOssWriteClass;
-
-/* PUBLIC */
-#define MS_OSS_WRITE(filter) ((MSOssWrite*)(filter))
-#define MS_OSS_WRITE_CLASS(klass) ((MSOssWriteClass*)(klass))
-MSFilter * ms_oss_write_new(void);
-gint ms_oss_write_set_device(MSOssWrite *w,gint devid);
-void ms_oss_write_start(MSOssWrite *w);
-void ms_oss_write_stop(MSOssWrite *w);
-void ms_oss_write_set_level(MSOssWrite *w, gint level);
-void ms_oss_write_play_dtmf(MSOssWrite *w, char dtmf);
-
-/* FOR INTERNAL USE*/
-void ms_oss_write_init(MSOssWrite *r);
-void ms_oss_write_setup(MSOssWrite *r);
-void ms_oss_write_class_init(MSOssWriteClass *klass);
-void ms_oss_write_destroy( MSOssWrite *obj);
-void ms_oss_write_process(MSOssWrite *f);
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.c
deleted file mode 100644
index 6bd073b..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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 dispatcher of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msqdispatcher.h"
-
-static MSQdispatcherClass *ms_qdispatcher_class=NULL;
-
-MSFilter * ms_qdispatcher_new(void)
-{
- MSQdispatcher *obj;
- obj=g_malloc(sizeof(MSQdispatcher));
- if (ms_qdispatcher_class==NULL){
- ms_qdispatcher_class=g_malloc0(sizeof(MSQdispatcherClass));
- ms_qdispatcher_class_init(ms_qdispatcher_class);
- }
- MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_qdispatcher_class);
- ms_qdispatcher_init(obj);
- return MS_FILTER(obj);
-}
-
-
-void ms_qdispatcher_init(MSQdispatcher *obj)
-{
- ms_filter_init(MS_FILTER(obj));
-
- MS_FILTER(obj)->inqueues=obj->q_inputs;
- MS_FILTER(obj)->outqueues=obj->q_outputs;
- memset(obj->q_inputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_INPUTS);
- memset(obj->q_outputs,0,sizeof(MSQueue*)*MS_QDISPATCHER_MAX_OUTPUTS);
-}
-
-
-
-void ms_qdispatcher_class_init(MSQdispatcherClass *klass)
-{
- MSFilterClass *parent_class=MS_FILTER_CLASS(klass);
- ms_filter_class_init(parent_class);
- ms_filter_class_set_name(parent_class,"qdispatcher");
- parent_class->max_qinputs=MS_QDISPATCHER_MAX_INPUTS;
- parent_class->max_qoutputs=MS_QDISPATCHER_MAX_OUTPUTS;
-
- parent_class->destroy=(MSFilterDestroyFunc)ms_qdispatcher_destroy;
- parent_class->process=(MSFilterProcessFunc)ms_qdispatcher_process;
-}
-
-
-void ms_qdispatcher_destroy( MSQdispatcher *obj)
-{
- g_free(obj);
-}
-
-void ms_qdispatcher_process(MSQdispatcher *obj)
-{
- gint i;
- MSQueue *inq=obj->q_inputs[0];
-
- if (inq!=NULL){
- MSQueue *outq;
- MSMessage *m1,*m2;
- while ( (m1=ms_queue_get(inq))!=NULL){
- /* dispatch incoming messages to output queues */
- for (i=0;i<MS_QDISPATCHER_MAX_OUTPUTS;i++){
- outq=obj->q_outputs[i];
- if (outq!=NULL){
- m2=ms_message_dup(m1);
- ms_queue_put(outq,m2);
- }
- }
- ms_message_destroy(m1);
- }
- }
-
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.h
deleted file mode 100644
index 3b0c566..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msqdispatcher.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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 dispatcher of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSQDISPATCHER_H
-#define MSQDISPATCHER_H
-
-#include "msfilter.h"
-
-
-/*this is the class that implements a qdispatcher filter*/
-
-#define MS_QDISPATCHER_MAX_INPUTS 1
-#define MS_QDISPATCHER_MAX_OUTPUTS 5
-
-typedef struct _MSQdispatcher
-{
- /* the MSQdispatcher derivates from MSFilter, so the MSFilter object MUST be the first of the MSQdispatcher object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSQueue *q_inputs[MS_QDISPATCHER_MAX_INPUTS];
- MSQueue *q_outputs[MS_QDISPATCHER_MAX_OUTPUTS];
-} MSQdispatcher;
-
-typedef struct _MSQdispatcherClass
-{
- /* the MSQdispatcher derivates from MSFilter, so the MSFilter class MUST be the first of the MSQdispatcher class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSQdispatcherClass;
-
-/* PUBLIC */
-#define MS_QDISPATCHER(filter) ((MSQdispatcher*)(filter))
-#define MS_QDISPATCHER_CLASS(klass) ((MSQdispatcherClass*)(klass))
-MSFilter * ms_qdispatcher_new(void);
-
-/* FOR INTERNAL USE*/
-void ms_qdispatcher_init(MSQdispatcher *r);
-void ms_qdispatcher_class_init(MSQdispatcherClass *klass);
-void ms_qdispatcher_destroy( MSQdispatcher *obj);
-void ms_qdispatcher_process(MSQdispatcher *r);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.c
deleted file mode 100644
index 4636895..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msqueue.h"
-#include <string.h>
-
-MSQueue * ms_queue_new()
-{
- MSQueue *q=g_malloc(sizeof(MSQueue));
- memset(q,0,sizeof(MSQueue));
- return q;
-}
-
-MSMessage *ms_queue_get(MSQueue *q)
-{
- MSMessage *b=q->last;
- if (b==NULL) return NULL;
- q->last=b->prev;
- if (b->prev==NULL) q->first=NULL; /* it was the only element of the queue*/
- q->size--;
- b->next=b->prev=NULL;
- return(b);
-}
-
-void ms_queue_put(MSQueue *q, MSMessage *m)
-{
- MSMessage *mtmp=q->first;
- g_return_if_fail(m!=NULL);
- q->first=m;
- m->next=mtmp;
- if (mtmp!=NULL)
- {
- mtmp->prev=m;
- }
- else q->last=m; /* it was the first element of the q */
- q->size++;
-}
-
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.h
deleted file mode 100644
index 73ab8d8..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msqueue.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSQUEUE_H
-#define MSQUEUE_H
-
-#include "msbuffer.h"
-
-/* for the moment these are stupid queues limited to one element*/
-
-typedef struct _MSQueue
-{
- MSMessage *first;
- MSMessage *last;
- gint size;
- void *prev_data; /*user data, usually the writting filter*/
- void *next_data; /* user data, usually the reading filter*/
-}MSQueue;
-
-
-MSQueue * ms_queue_new();
-
-MSMessage *ms_queue_get(MSQueue *q);
-
-void ms_queue_put(MSQueue *q, MSMessage *m);
-
-#define ms_queue_can_get(q) ( (q)->size!=0 )
-
-#define ms_queue_destroy(q) g_free(q)
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msread.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msread.c
deleted file mode 100644
index 6f0ec99..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msread.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msread.h"
-#include "mssync.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-
-static MSReadClass *ms_read_class=NULL;
-
-MSFilter * ms_read_new(char *name)
-{
- MSRead *r;
- int fd=-1;
-
- r=g_new(MSRead,1);
- ms_read_init(r);
- if (ms_read_class==NULL)
- {
- ms_read_class=g_new(MSReadClass,1);
- ms_read_class_init(ms_read_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_read_class);
- r->fd=-1;
- if (name!=NULL) ms_read_open(r,name);
- return(MS_FILTER(r));
-}
-
-
-
-gint ms_read_open(MSRead *r, gchar *name)
-{
- gint fd;
- fd=open(name,O_RDONLY);
- if (fd<0) {
- r->fd=-1;
- g_warning("ms_read_new: cannot open %s : %s",name,strerror(errno));
- return -1;
- }
- r->fd=fd;
- if (strstr(name,".wav")!=NULL){
- /* skip the header */
- lseek(fd,20,SEEK_SET);
-#ifdef WORDS_BIGENDIAN
- r->need_swap=1;
-#else
- r->need_swap=0;
-#endif
- }
- r->state=MS_READ_STATE_STARTED;
- return 0;
-}
-
-/* FOR INTERNAL USE*/
-void ms_read_init(MSRead *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->outfifos=r->foutputs;
- MS_FILTER(r)->outqueues=r->qoutputs;
- memset(r->foutputs,0,sizeof(MSFifo*)*MSREAD_MAX_OUTPUTS);
- memset(r->qoutputs,0,sizeof(MSQueue*)*MSREAD_MAX_OUTPUTS);
- r->fd=-1;
- r->gran=320;
- r->state=MS_READ_STATE_STOPPED;
- r->need_swap=0;
- r->rate=8000;
-}
-
-gint ms_read_set_property(MSRead *f,MSFilterProperty prop, void *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FREQ:
- f->rate=((gint*)value)[0];
- break;
- }
- return 0;
-}
-
-void ms_read_class_init(MSReadClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskreader");
- ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
- MS_FILTER_CLASS(klass)->max_foutputs=MSREAD_MAX_OUTPUTS;
- MS_FILTER_CLASS(klass)->max_qoutputs=MSREAD_MAX_OUTPUTS;
- MS_FILTER_CLASS(klass)->w_maxgran=MSREAD_DEF_GRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_read_destroy;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_read_setup;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_read_process;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_read_set_property;
-}
-
-void ms_read_process(MSRead *r)
-{
- MSFifo *f;
- MSQueue *q;
- MSMessage *msg=NULL;
- int err;
- gint gran=r->gran;
- void *p;
-
- f=r->foutputs[0];
- if ((f!=NULL) && (r->state==MS_READ_STATE_STARTED))
- {
- ms_fifo_get_write_ptr(f,gran,&p);
- if (p!=NULL)
- {
- err=read(r->fd,p,gran);
- if (err<0)
- {
- /* temp: */
- g_warning("ms_read_process: failed to read: %s.\n",strerror(errno));
- }
- else if (err<gran){
- ms_trace("ms_read_process: end of file.");
- ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL);
- r->state=MS_READ_STATE_STOPPED;
- close(r->fd);
- r->fd=-1;
- }
- if (r->need_swap) swap_buffer(p,gran);
- }
- }
- /* process output queues*/
- q=r->qoutputs[0];
- if ((q!=NULL) && (r->fd>0))
- {
- msg=ms_message_new(r->gran);
- err=read(r->fd,msg->data,r->gran);
- if (err>0){
- msg->size=err;
- ms_queue_put(q,msg);
- if (r->need_swap) swap_buffer(msg->data,r->gran);
- }else{
- ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL);
- ms_trace("End of file reached.");
- r->state=MS_READ_STATE_STOPPED;
- }
- }
-}
-
-void ms_read_destroy( MSRead *obj)
-{
- if (obj->fd!=0) close(obj->fd);
- g_free(obj);
-}
-
-gint ms_read_close(MSRead *obj)
-{
- if (obj->fd!=0) {
- close(obj->fd);
- obj->fd=-1;
- obj->state=MS_READ_STATE_STOPPED;
- }
-}
-
-
-void ms_read_setup(MSRead *r, MSSync *sync)
-{
- r->sync=sync;
- r->gran=(r->rate*sync->interval/1000)*2;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msread.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msread.h
deleted file mode 100644
index 93177f3..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msread.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSREAD_H
-#define MSREAD_H
-
-#include "msfilter.h"
-#include "mssync.h"
-
-/*this is the class that implements file reading source filter*/
-
-#define MSREAD_MAX_OUTPUTS 1 /* max output per filter*/
-
-#define MSREAD_DEF_GRAN 640 /* the default granularity*/
-
-typedef enum{
- MS_READ_STATE_STARTED,
- MS_READ_STATE_STOPPED,
- MS_READ_STATE_EOF
-}MSReadState;
-
-typedef struct _MSRead
-{
- /* the MSRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSRead object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *foutputs[MSREAD_MAX_OUTPUTS];
- MSQueue *qoutputs[MSREAD_MAX_OUTPUTS];
- MSSync *sync;
- gint rate;
- gint fd; /* the file descriptor of the file being read*/
- gint gran; /*granularity*/ /* for use with queues */
- gint need_swap;
- gint state;
-} MSRead;
-
-typedef struct _MSReadClass
-{
- /* the MSRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSRead class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSReadClass;
-
-/* PUBLIC */
-#define MS_READ(filter) ((MSRead*)(filter))
-#define MS_READ_CLASS(klass) ((MSReadClass*)(klass))
-MSFilter * ms_read_new(char *name);
-/* set the granularity for reading file on disk */
-#define ms_read_set_bufsize(filter,sz) (filter)->gran=(sz)
-
-/* FOR INTERNAL USE*/
-void ms_read_init(MSRead *r);
-void ms_read_class_init(MSReadClass *klass);
-void ms_read_destroy( MSRead *obj);
-void ms_read_process(MSRead *r);
-void ms_read_setup(MSRead *r, MSSync *sync);
-
-typedef enum{
- MS_READ_EVENT_EOF /* end of file */
-} MSReadEvent;
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.c
deleted file mode 100644
index fb2006e..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msringplayer.h"
-#include "mssync.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-
-#include "waveheader.h"
-
-#define WAVE_HEADER_OFFSET sizeof(wave_header_t)
-
-enum { PLAY_RING, PLAY_SILENCE};
-
-static int supported_freq[6]={8000,11025,16000,22050,32000,44100};
-
-gint freq_is_supported(gint freq){
- int i;
- for (i=0;i<6;i++){
- if (abs(supported_freq[i]-freq)<50) return supported_freq[i];
- }
- return 0;
-}
-
-static MSRingPlayerClass *ms_ring_player_class=NULL;
-
-/**
- * ms_ring_player_new:
- * @name: The path to the 16-bit 8khz raw file to be played as a ring.
- * @seconds: The number of seconds that separates two rings.
- *
- * Allocates a new MSRingPlayer object.
- *
- *
- * Returns: a pointer the the object, NULL if name could not be open.
- */
-MSFilter * ms_ring_player_new(char *name, gint seconds)
-{
- MSRingPlayer *r;
- int fd=-1;
-
- if ((name!=NULL) && (strlen(name)!=0))
- {
- fd=open(name,O_RDONLY);
- if (fd<0)
- {
- g_warning("ms_ring_player_new: failed to open %s.\n",name);
- return NULL;
- }
-
- }else {
- g_warning("ms_ring_player_new: Bad file name");
- return NULL;
- }
-
- r=g_new(MSRingPlayer,1);
- ms_ring_player_init(r);
- if (ms_ring_player_class==NULL)
- {
- ms_ring_player_class=g_new(MSRingPlayerClass,1);
- ms_ring_player_class_init(ms_ring_player_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_ring_player_class);
-
- r->fd=fd;
- r->silence=seconds;
- r->freq=8000;
- if (strstr(name,".wav")!=NULL){
- wave_header_t header;
- int freq,freq2;
- /* read the header */
- read(fd,&header,sizeof(wave_header_t));
- freq=wave_header_get_rate(&header);
- if ((freq2=freq_is_supported(freq))>0){
- r->freq=freq2;
- }else {
- g_warning("Unsupported sampling rate %i",freq);
- r->freq=8000;
- }
- r->channel=wave_header_get_channel(&header);
- lseek(fd,WAVE_HEADER_OFFSET,SEEK_SET);
-#ifdef WORDS_BIGENDIAN
- r->need_swap=1;
-#else
- r->need_swap=0;
-#endif
- }
- ms_ring_player_set_property(r, MS_FILTER_PROPERTY_FREQ,&r->freq);
- r->state=PLAY_RING;
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_ring_player_init(MSRingPlayer *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->outfifos=r->foutputs;
- MS_FILTER(r)->outqueues=r->qoutputs;
- memset(r->foutputs,0,sizeof(MSFifo*)*MS_RING_PLAYER_MAX_OUTPUTS);
- memset(r->qoutputs,0,sizeof(MSQueue*)*MS_RING_PLAYER_MAX_OUTPUTS);
- r->fd=-1;
- r->current_pos=0;
- r->need_swap=0;
- r->sync=NULL;
-}
-
-gint ms_ring_player_set_property(MSRingPlayer *f,MSFilterProperty prop, void *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FREQ:
- f->rate=((gint*)value)[0]*2;
- f->silence_bytes=f->silence*f->rate;
- if (f->sync!=NULL)
- f->gran=(f->rate*f->sync->interval/1000)*2;
- break;
- }
- return 0;
-}
-
-gint ms_ring_player_get_property(MSRingPlayer *f,MSFilterProperty prop, void *value)
-{
- switch(prop){
- case MS_FILTER_PROPERTY_FREQ:
- ((gint*)value)[0]=f->freq;
-
- break;
- case MS_FILTER_PROPERTY_CHANNELS:
- ((gint*)value)[0]=f->channel;
- break;
- }
- return 0;
-}
-
-gint ms_ring_player_get_sample_freq(MSRingPlayer *obj){
- return obj->freq;
-}
-
-
-void ms_ring_player_class_init(MSRingPlayerClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"ringplay");
- ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
- MS_FILTER_CLASS(klass)->max_foutputs=MS_RING_PLAYER_MAX_OUTPUTS;
- MS_FILTER_CLASS(klass)->max_qoutputs=MS_RING_PLAYER_MAX_OUTPUTS;
- MS_FILTER_CLASS(klass)->w_maxgran=MS_RING_PLAYER_DEF_GRAN;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_ring_player_setup;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_ring_player_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_ring_player_process;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_ring_player_set_property;
- MS_FILTER_CLASS(klass)->get_property=(MSFilterPropertyFunc)ms_ring_player_get_property;
-}
-
-void ms_ring_player_process(MSRingPlayer *r)
-{
- MSFifo *f;
- gint err;
- gint processed=0;
- gint gran=r->gran;
- char *p;
-
- g_return_if_fail(gran>0);
- /* process output fifos*/
-
- f=r->foutputs[0];
- ms_fifo_get_write_ptr(f,gran,(void**)&p);
- g_return_if_fail(p!=NULL);
- for (processed=0;processed<gran;){
- switch(r->state){
- case PLAY_RING:
- err=read(r->fd,&p[processed],gran-processed);
- if (err<0)
- {
- memset(&p[processed],0,gran-processed);
- processed=gran;
- g_warning("ms_ring_player_process: failed to read: %s.\n",strerror(errno));
- return;
- }
- else if (err<gran)
- {/* end of file */
-
- r->current_pos=r->silence_bytes;
- lseek(r->fd,WAVE_HEADER_OFFSET,SEEK_SET);
- r->state=PLAY_SILENCE;
- ms_filter_notify_event(MS_FILTER(r),MS_RING_PLAYER_END_OF_RING_EVENT,NULL);
- }
- if (r->need_swap) swap_buffer(&p[processed],err);
- processed+=err;
- break;
- case PLAY_SILENCE:
- err=gran-processed;
- if (r->current_pos>err){
- memset(&p[processed],0,err);
- r->current_pos-=gran;
- processed=gran;
- }else{
- memset(&p[processed],0,r->current_pos);
- processed+=r->current_pos;
- r->state=PLAY_RING;
- }
- break;
- }
- }
-}
-
-/**
- * ms_ring_player_destroy:
- * @obj: A valid MSRingPlayer object.
- *
- * Destroy a MSRingPlayer object.
- *
- *
- */
-
-void ms_ring_player_destroy( MSRingPlayer *obj)
-{
- if (obj->fd!=0) close(obj->fd);
- g_free(obj);
-}
-
-void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync)
-{
- r->sync=sync;
- r->gran=(r->rate*r->sync->interval/1000)*r->channel;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.h
deleted file mode 100644
index 1f5e67d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msringplayer.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSRINGPLAYER_H
-#define MSRINGPLAYER_H
-
-#include "msfilter.h"
-#include "mssync.h"
-
-
-/*this is the class that implements file reading source filter*/
-
-#define MS_RING_PLAYER_MAX_OUTPUTS 1 /* max output per filter*/
-
-#define MS_RING_PLAYER_DEF_GRAN 8192 /* the default granularity*/
-
-#define MS_RING_PLAYER_END_OF_RING_EVENT 1
-
-struct _MSRingPlayer
-{
- /* the MSRingPlayer derivates from MSFilter, so the MSFilter object MUST be the first of the MSRingPlayer object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *foutputs[MS_RING_PLAYER_MAX_OUTPUTS];
- MSQueue *qoutputs[MS_RING_PLAYER_MAX_OUTPUTS];\
- MSSync *sync;
- gint gran;
- gint freq;
- gint rate;
- gint channel; /* number of interleaved channels */
- gint silence; /* silence time between each ring, in seconds */
- gint state;
- gint fd; /* the file descriptor of the file being read*/
- gint silence_bytes; /*silence in number of bytes between each ring */
- gint current_pos;
- gint need_swap;
-};
-
-typedef struct _MSRingPlayer MSRingPlayer;
-
-struct _MSRingPlayerClass
-{
- /* the MSRingPlayer derivates from MSFilter, so the MSFilter class MUST be the first of the MSRingPlayer class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-};
-
-typedef struct _MSRingPlayerClass MSRingPlayerClass;
-
-/* PUBLIC */
-#define MS_RING_PLAYER(filter) ((MSRingPlayer*)(filter))
-#define MS_RING_PLAYER_CLASS(klass) ((MSRingPlayerClass*)(klass))
-MSFilter * ms_ring_player_new(char *name, gint seconds);
-gint ms_ring_player_get_sample_freq(MSRingPlayer *obj);
-
-
-/* FOR INTERNAL USE*/
-void ms_ring_player_init(MSRingPlayer *r);
-void ms_ring_player_class_init(MSRingPlayerClass *klass);
-void ms_ring_player_destroy( MSRingPlayer *obj);
-void ms_ring_player_process(MSRingPlayer *r);
-#define ms_ring_player_set_bufsize(filter,sz) (filter)->gran=(sz)
-void ms_ring_player_setup(MSRingPlayer *r,MSSync *sync);
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.c
deleted file mode 100644
index 9b82e93..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msrtprecv.h"
-
-
-/* some utilities to convert mblk_t to MSMessage and vice-versa */
-MSMessage *msgb_2_ms_message(mblk_t* mp){
- MSMessage *msg;
- MSBuffer *msbuf;
- if (mp->b_datap->ref_count!=1) return NULL; /* cannot handle properly non-unique buffers*/
- /* create a MSBuffer using the mblk_t buffer */
- msg=ms_message_alloc();
- msbuf=ms_buffer_alloc(0);
- msbuf->buffer=mp->b_datap->db_base;
- msbuf->size=(char*)mp->b_datap->db_lim-(char*)mp->b_datap->db_base;
- ms_message_set_buf(msg,msbuf);
- msg->size=mp->b_wptr-mp->b_rptr;
- msg->data=mp->b_rptr;
- /* free the mblk_t */
- g_free(mp->b_datap);
- g_free(mp);
- return msg;
-}
-
-
-static MSRtpRecvClass *ms_rtp_recv_class=NULL;
-
-MSFilter * ms_rtp_recv_new(void)
-{
- MSRtpRecv *r;
-
- r=g_new(MSRtpRecv,1);
- ms_rtp_recv_init(r);
- if (ms_rtp_recv_class==NULL)
- {
- ms_rtp_recv_class=g_new0(MSRtpRecvClass,1);
- ms_rtp_recv_class_init(ms_rtp_recv_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_recv_class);
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_rtp_recv_init(MSRtpRecv *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->outfifos=r->f_outputs;
- MS_FILTER(r)->outqueues=r->q_outputs;
- memset(r->f_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS);
- memset(r->q_outputs,0,sizeof(MSFifo*)*MSRTPRECV_MAX_OUTPUTS);
- r->rtpsession=NULL;
- r->stream_started=0;
-}
-
-void ms_rtp_recv_class_init(MSRtpRecvClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPRecv");
- MS_FILTER_CLASS(klass)->max_qoutputs=MSRTPRECV_MAX_OUTPUTS;
- MS_FILTER_CLASS(klass)->max_foutputs=MSRTPRECV_MAX_OUTPUTS;
- MS_FILTER_CLASS(klass)->w_maxgran=MSRTPRECV_DEF_GRAN;
- ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_recv_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_recv_process;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_recv_setup;
-}
-
-void ms_rtp_recv_process(MSRtpRecv *r)
-{
- MSFifo *fo;
- MSQueue *qo;
- MSSync *sync= r->sync;
- void *d;
- mblk_t *mp;
- gint len;
- gint gran=ms_sync_get_samples_per_tick(MS_SYNC(sync));
-
- if (r->rtpsession==NULL) return;
- /* process output fifo and output queue*/
- fo=r->f_outputs[0];
- if (fo!=NULL)
- {
- while( (mp=rtp_session_recvm_with_ts(r->rtpsession,r->prev_ts))!=NULL) {
- /* try to get rtp packets and paste them to the output fifo */
- r->stream_started=1;
- len=mp->b_cont->b_wptr-mp->b_cont->b_rptr;
- ms_fifo_get_write_ptr(fo,len,&d);
- if (d!=NULL){
- memcpy(d,mp->b_cont->b_rptr,len);
- }else ms_warning("ms_rtp_recv_process: no space on output fifo !");
- freemsg(mp);
- }
- r->prev_ts+=gran;
-
- }
- qo=r->q_outputs[0];
- if (qo!=NULL)
- {
- guint32 clock;
- gint got=0;
- /* we are connected with queues (surely for video)*/
- /* use the sync system time to compute a timestamp */
- PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
- if (pt==NULL) {
- ms_warning("ms_rtp_recv_process(): NULL RtpPayload- skipping.");
- return;
- }
- clock=(guint32)(((double)sync->time*(double)pt->clock_rate)/1000.0);
- /*g_message("Querying packet with timestamp %u",clock);*/
- /* get rtp packet, and send them through the output queue */
- while ( (mp=rtp_session_recvm_with_ts(r->rtpsession,clock))!=NULL ){
- MSMessage *msg;
- mblk_t *mdata;
- /*g_message("Got packet with timestamp %u",clock);*/
- got++;
- r->stream_started=1;
- mdata=mp->b_cont;
- freeb(mp);
- msg=msgb_2_ms_message(mdata);
- ms_queue_put(qo,msg);
- }
- }
-}
-
-void ms_rtp_recv_destroy( MSRtpRecv *obj)
-{
- g_free(obj);
-}
-
-RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session)
-{
- RtpSession *old=obj->rtpsession;
- obj->rtpsession=session;
- obj->prev_ts=0;
- return old;
-}
-
-
-void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync)
-{
- r->sync=sync;
- r->stream_started=0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.h
deleted file mode 100644
index 8c2c2ed..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtprecv.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSRTPRECV_H
-#define MSRTPRECV_H
-
-#include "msfilter.h"
-#include "mssync.h"
-
-/* because of a conflict between config.h from oRTP and config.h from linphone:*/
-#undef PACKAGE
-#undef VERSION
-#include <ortp/ortp.h>
-
-/*this is the class that implements a copy filter*/
-
-#define MSRTPRECV_MAX_OUTPUTS 1 /* max output per filter*/
-
-#define MSRTPRECV_DEF_GRAN 4096 /* the default granularity*/
-
-struct _MSRtpRecv
-{
- /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_outputs[MSRTPRECV_MAX_OUTPUTS];
- MSQueue *q_outputs[MSRTPRECV_MAX_OUTPUTS];
- MSSync *sync;
- RtpSession *rtpsession;
- guint32 prev_ts;
- gint stream_started;
-};
-
-typedef struct _MSRtpRecv MSRtpRecv;
-
-struct _MSRtpRecvClass
-{
- /* the MSCopy derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-};
-
-typedef struct _MSRtpRecvClass MSRtpRecvClass;
-
-/* PUBLIC */
-#define MS_RTP_RECV(filter) ((MSRtpRecv*)(filter))
-#define MS_RTP_RECV_CLASS(klass) ((MSRtpRecvClass*)(klass))
-MSFilter * ms_rtp_recv_new(void);
-RtpSession * ms_rtp_recv_set_session(MSRtpRecv *obj,RtpSession *session);
-#define ms_rtp_recv_unset_session(obj) (ms_rtp_recv_set_session((obj),NULL))
-#define ms_rtp_recv_get_session(obj) ((obj)->rtpsession)
-
-
-
-/* FOR INTERNAL USE*/
-void ms_rtp_recv_init(MSRtpRecv *r);
-void ms_rtp_recv_class_init(MSRtpRecvClass *klass);
-void ms_rtp_recv_destroy( MSRtpRecv *obj);
-void ms_rtp_recv_process(MSRtpRecv *r);
-void ms_rtp_recv_setup(MSRtpRecv *r,MSSync *sync);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.c
deleted file mode 100644
index 5e781ff..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msrtpsend.h"
-#include <ortp/telephonyevents.h>
-#include "mssync.h"
-#include "mscodec.h"
-
-
-
-static MSRtpSendClass *ms_rtp_send_class=NULL;
-
-MSFilter * ms_rtp_send_new(void)
-{
- MSRtpSend *r;
-
- r=g_new(MSRtpSend,1);
-
- if (ms_rtp_send_class==NULL)
- {
- ms_rtp_send_class=g_new(MSRtpSendClass,1);
- ms_rtp_send_class_init(ms_rtp_send_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_send_class);
- ms_rtp_send_init(r);
- return(MS_FILTER(r));
-}
-
-
-void ms_rtp_send_init(MSRtpSend *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->inqueues=r->q_inputs;
- MS_FILTER(r)->r_mingran=MSRTPSEND_DEF_GRAN;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
- memset(r->q_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
- r->rtpsession=NULL;
- r->ts=0;
- r->ts_inc=0;
- r->flags=0;
- r->delay=0;
-}
-
-void ms_rtp_send_class_init(MSRtpSendClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPSend");
- MS_FILTER_CLASS(klass)->max_qinputs=MSRTPSEND_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_finputs=MSRTPSEND_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=MSRTPSEND_DEF_GRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_send_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_send_process;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_send_setup;
-}
-
-void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size)
-{
- r->ts_inc=ts_inc;
- r->packet_size=payload_size;
- if (r->ts_inc!=0) r->flags|=RTPSEND_CONFIGURED;
- else r->flags&=~RTPSEND_CONFIGURED;
- MS_FILTER(r)->r_mingran=payload_size;
- /*g_message("ms_rtp_send_set_timing: ts_inc=%i",ts_inc);*/
-}
-
-guint32 get_new_timestamp(MSRtpSend *r,guint32 synctime)
-{
- guint32 clockts;
- /* use the sync system time to compute a timestamp */
- PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
- g_return_val_if_fail(pt!=NULL,0);
- clockts=(guint32)(((double)synctime * (double)pt->clock_rate)/1000.0);
- ms_trace("ms_rtp_send_process: sync->time=%i clock=%i",synctime,clockts);
- if (r->flags & RTPSEND_CONFIGURED){
- if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(clockts,r->ts+(2*r->ts_inc) )){
- r->ts=clockts;
- }
- else r->ts+=r->ts_inc;
- }else{
- r->ts=clockts;
- }
- return r->ts;
-}
-
-
-void ms_rtp_send_process(MSRtpSend *r)
-{
- MSFifo *fi;
- MSQueue *qi;
- MSSync *sync= r->sync;
- int gran=ms_sync_get_samples_per_tick(sync);
- guint32 ts;
- void *s;
- guint skip;
- guint32 synctime=sync->time;
-
- g_return_if_fail(gran>0);
- if (r->rtpsession==NULL) return;
-
- ms_filter_lock(MS_FILTER(r));
- skip=r->delay!=0;
- if (skip) r->delay--;
- /* process output fifo and output queue*/
- fi=r->f_inputs[0];
- if (fi!=NULL)
- {
- ts=get_new_timestamp(r,synctime);
- /* try to read r->packet_size bytes and send them in a rtp packet*/
- ms_fifo_get_read_ptr(fi,r->packet_size,&s);
- if (!skip){
- rtp_session_send_with_ts(r->rtpsession,s,r->packet_size,ts);
- ms_trace("len=%i, ts=%i ",r->packet_size,ts);
- }
- }
- qi=r->q_inputs[0];
- if (qi!=NULL)
- {
- MSMessage *msg;
- /* read a MSMessage and send it through the network*/
- while ( (msg=ms_queue_get(qi))!=NULL){
- ts=get_new_timestamp(r,synctime);
- if (!skip) {
- /*g_message("Sending packet with ts=%u",ts);*/
- rtp_session_send_with_ts(r->rtpsession,msg->data,msg->size,ts);
-
- }
- ms_message_destroy(msg);
- }
- }
- ms_filter_unlock(MS_FILTER(r));
-}
-
-void ms_rtp_send_destroy( MSRtpSend *obj)
-{
- g_free(obj);
-}
-
-RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session)
-{
- RtpSession *old=obj->rtpsession;
- obj->rtpsession=session;
- obj->ts=0;
- obj->ts_inc=0;
- return old;
-}
-
-void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync)
-{
- MSFilter *codec;
- MSCodecInfo *info;
- r->sync=sync;
- codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_AUDIO_CODEC);
- if (codec==NULL) codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_VIDEO_CODEC);
- if (codec==NULL){
- g_warning("ms_rtp_send_setup: could not find upstream codec.");
- return;
- }
- info=MS_CODEC_INFO(codec->klass->info);
- if (info->info.type==MS_FILTER_AUDIO_CODEC){
- int ts_inc=info->fr_size/2;
- int psize=info->dt_size;
- if (ts_inc==0){
- /* dont'use the normal frame size: this is a variable frame size codec */
- /* use the MS_FILTER(codec)->r_mingran */
- ts_inc=MS_FILTER(codec)->r_mingran/2;
- psize=0;
- }
- ms_rtp_send_set_timing(r,ts_inc,psize);
- }
-}
-
-gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf)
-{
- gint res;
-
- if (r->rtpsession==NULL) return -1;
- if (rtp_session_telephone_events_supported(r->rtpsession)==-1){
- g_warning("ERROR : telephone events not supported.\n");
- return -1;
- }
-
- ms_filter_lock(MS_FILTER(r));
- g_message("Sending DTMF.");
- res=rtp_session_send_dtmf(r->rtpsession, dtmf, r->ts);
- if (res==0){
- //r->ts+=r->ts_inc;
- r->delay+=2;
- }else g_warning("Could not send dtmf.");
-
- ms_filter_unlock(MS_FILTER(r));
-
- return res;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.h
deleted file mode 100644
index b70f4e5..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msrtpsend.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSRTPSEND_H
-#define MSRTPSEND_H
-
-#include "msfilter.h"
-#include "mssync.h"
-
-#undef PACKAGE
-#undef VERSION
-#include <ortp/ortp.h>
-
-
-/*this is the class that implements a sending through rtp filter*/
-
-#define MSRTPSEND_MAX_INPUTS 1 /* max input per filter*/
-
-#define MSRTPSEND_DEF_GRAN 4096/* the default granularity*/
-
-struct _MSRtpSend
-{
- /* the MSCopy derivates from MSFilter, so the MSFilter object MUST be the first of the MSCopy object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSRTPSEND_MAX_INPUTS];
- MSQueue *q_inputs[MSRTPSEND_MAX_INPUTS];
- MSSync *sync;
- RtpSession *rtpsession;
- guint32 ts;
- guint32 ts_inc; /* the timestamp increment */
- gint packet_size;
- guint flags;
- guint delay; /* number of _proccess call which must be skipped */
-#define RTPSEND_CONFIGURED (1)
-};
-
-typedef struct _MSRtpSend MSRtpSend;
-
-struct _MSRtpSendClass
-{
- /* the MSRtpSend derivates from MSFilter, so the MSFilter class MUST be the first of the MSCopy class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-};
-
-typedef struct _MSRtpSendClass MSRtpSendClass;
-
-/* PUBLIC */
-#define MS_RTP_SEND(filter) ((MSRtpSend*)(filter))
-#define MS_RTP_SEND_CLASS(klass) ((MSRtpSendClass*)(klass))
-MSFilter * ms_rtp_send_new(void);
-RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session);
-#define ms_rtp_send_unset_session(obj) (ms_rtp_send_set_session((obj),NULL))
-#define ms_rtp_send_get_session(obj) ((obj)->rtpsession)
-void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size);
-gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf);
-
-
-/* FOR INTERNAL USE*/
-void ms_rtp_send_init(MSRtpSend *r);
-void ms_rtp_send_class_init(MSRtpSendClass *klass);
-void ms_rtp_send_destroy( MSRtpSend *obj);
-void ms_rtp_send_process(MSRtpSend *r);
-void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.c
deleted file mode 100644
index 8e49cd3..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/***************************************************************************
- * mssdlout.c
- *
- * Mon Jul 11 16:17:59 2005
- * Copyright 2005 Simon Morlat
- * Email simon dot morlat at linphone dot org
- ****************************************************************************/
-
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "mssdlout.h"
-
-MSSdlOutClass *ms_sdl_out_class=NULL;
-
-void ms_sdl_out_init(MSSdlOut *obj){
- ms_filter_init(MS_FILTER(obj));
- obj->width=VIDEO_SIZE_CIF_W;
- obj->height=VIDEO_SIZE_CIF_H;
- obj->format="RGB24";
- obj->use_yuv=FALSE;
- obj->oldinm1=NULL;
- MS_FILTER(obj)->inqueues=obj->input;
-}
-
-void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt){
- obj->format=fmt;
- if (strcmp(fmt,"YUV420P")==0) obj->use_yuv=TRUE;
- else obj->use_yuv=FALSE;
-}
-
-void ms_sdl_uninit_sdl(MSSdlOut *obj){
- if (obj->overlay!=NULL){
- SDL_FreeYUVOverlay(obj->overlay);
- obj->overlay=NULL;
- }
- if (obj->screen!=NULL){
- SDL_FreeSurface(obj->screen);
- obj->screen=NULL;
- }
-
-}
-
-void ms_sdl_out_uninit(MSSdlOut *obj){
- ms_sdl_uninit_sdl(obj);
-}
-
-void ms_sdl_out_destroy(MSSdlOut *obj){
- ms_sdl_out_uninit(obj);
- if (obj->oldinm1!=NULL) ms_message_destroy(obj->oldinm1);
- g_free(obj);
-}
-
-void ms_sdl_init_sdl(MSSdlOut *obj){
- if (strcmp(obj->format,"RGB24")==0){
- }else{
- obj->use_yuv=TRUE;
- }
- obj->screen = SDL_SetVideoMode(obj->width, obj->height, 0,SDL_HWSURFACE|SDL_ANYFORMAT);
- if ( obj->screen == NULL ) {
- g_warning("Couldn't set video mode: %s\n",
- SDL_GetError());
- return ;
- }
- if (obj->screen->flags & SDL_HWSURFACE) g_message("SDL surface created in hardware");
- SDL_WM_SetCaption("Linphone Video", NULL);
-
- if (obj->use_yuv){
- g_message("Using yuv overlay.");
- obj->overlay=SDL_CreateYUVOverlay(obj->width,obj->height,SDL_IYUV_OVERLAY,obj->screen);
- if (obj->overlay==NULL){
- g_warning("Couldn't create yuv overlay: %s\n",
- SDL_GetError());
- }else{
- if (obj->overlay->hw_overlay) g_message("YUV overlay using hardware acceleration.");
- }
- }
-
-}
-
-static void resize_yuv_small(char *pict, int w, int h, int scale){
- int i,j,id,jd;
- int nh,nw;
- char *smallpict;
- int ysize,usize,ydsize,udsize;
- int smallpict_sz;
- char *dptr,*sptr;
- nw=w/scale;
- nh=h/scale;
- ysize=w*h;
- usize=ysize/4;
- ydsize=nw*nh;
- udsize=ydsize/4;
- smallpict_sz=(ydsize*3)/2;
- smallpict=(char*)alloca(smallpict_sz);
- memset(smallpict,0,smallpict_sz);
-
-
- dptr=smallpict;
- sptr=pict;
- for (j=0,jd=0;j<nh;j++,jd+=scale){
- for (i=0,id=0;i<nw;i++,id+=scale){
- dptr[(j*nw) + i]=sptr[(jd*w)+id];
- }
- }
-
- nh=nh/2;
- nw=nw/2;
- w=w/2;
- h=h/2;
- dptr+=ydsize;
- sptr+=ysize;
- for (j=0,jd=0;j<nh;j++,jd+=scale){
- for (i=0,id=0;i<nw;i++,id+=scale){
- dptr[(j*nw) + i]=sptr[(jd*w)+id];
- }
- }
- dptr+=udsize;
- sptr+=usize;
- for (j=0,jd=0;j<nh;j++,jd+=scale){
- for (i=0,id=0;i<nw;i++,id+=scale){
- dptr[(j*nw) + i]=sptr[(jd*w)+id];
- }
- }
-
- memcpy(pict,smallpict,smallpict_sz);
-}
-
-static void fill_overlay_at_pos(SDL_Overlay *lay, MSMessage *m, int x, int y, int w, int h){
- char *data=(char*)m->data;
- int i,j;
- int jlim,ilim;
- int off;
- char *dptr;
-
- ilim=MIN(x+w,lay->w);
- jlim=MIN(y+h,lay->h);
- SDL_LockYUVOverlay(lay);
- /* set Y */
- dptr=lay->pixels[0];
- for (j=y;j<jlim;j++){
- off=j*lay->w;
- for (i=x;i<ilim;i++){
- dptr[off + i]=*data;
- data++;
- }
- }
- /*set U and V*/
- ilim=ilim/2;
- jlim=jlim/2;
- dptr=lay->pixels[1];
- for (j=y/2;j<jlim;j++){
- off=j*(lay->w/2);
- for (i=x/2;i<ilim;i++){
- dptr[off + i]=*data;
- data++;
- }
- }
- dptr=lay->pixels[2];
- for (j=y/2;j<jlim;j++){
- off=j*(lay->w/2);
- for (i=x/2;i<ilim;i++){
- dptr[off + i]=*data;
- data++;
- }
- }
- SDL_UnlockYUVOverlay(lay);
-}
-
-static void fill_overlay(SDL_Overlay *lay, MSMessage *m){
-
- int w2,h2;
- char *data=(char*)m->data;
- int ysize=lay->w*lay->h;
- int usize;
- w2=lay->w/2;
- h2=lay->h/2;
- usize=w2*h2;
- SDL_LockYUVOverlay(lay);
- memcpy(lay->pixels[0],data,ysize);
- memcpy(lay->pixels[1],data+ysize,usize);
- memcpy(lay->pixels[2],data+ysize+usize,usize);
- SDL_UnlockYUVOverlay(lay);
-}
-
-#define SCALE_FACTOR 6
-
-void ms_sdl_out_process(MSSdlOut *obj){
- MSQueue *q0=obj->input[0];
- MSQueue *q1=obj->input[1];
- MSMessage *inm0=NULL;
- MSMessage *inm1=NULL;
- int err;
- SDL_Rect smallrect;
- SDL_Rect rect;
- rect.w=obj->width;
- rect.h=obj->height;
- rect.x=0;
- rect.y=0;
- smallrect.w=obj->width/SCALE_FACTOR;
- smallrect.h=obj->height/SCALE_FACTOR;
- smallrect.x=obj->width - smallrect.w ;
- smallrect.y=obj->height -smallrect.h;
-
- if (obj->screen==NULL){
- ms_sdl_init_sdl(obj);
- }
-
- if (q0!=NULL)
- inm0=ms_queue_get(q0);
- if (q1!=NULL)
- inm1=ms_queue_get(q1);
-
- if (inm0!=NULL){
- SDL_Surface *surf;
- if (obj->use_yuv){
-
- fill_overlay(obj->overlay,inm0);
-
- }else {
- surf=SDL_CreateRGBSurfaceFrom(inm0->data,obj->width,obj->height,24,obj->width*3,0,0,0,0);
-
- err=SDL_BlitSurface(surf,NULL,obj->screen,NULL);
- if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError());
- SDL_FreeSurface(surf);
- }
- ms_message_destroy(inm0);
- }
- if (inm1!=NULL){
- /* this message is blitted on the right,bottom corner of the screen */
- SDL_Surface *surf;
-
- if (obj->use_yuv){
- resize_yuv_small(inm1->data,rect.w,rect.h,SCALE_FACTOR);
- fill_overlay_at_pos(obj->overlay,inm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h);
- }else {
- surf=SDL_CreateRGBSurfaceFrom(inm1->data,obj->width,obj->height,24,obj->width*3,0,0,0,0);
-
- err=SDL_BlitSurface(surf,NULL,obj->screen,&smallrect);
- if (err<0) g_warning("Fail to blit surface: %s",SDL_GetError());
- SDL_FreeSurface(surf);
- }
- if (obj->oldinm1!=NULL) {
- ms_message_destroy(obj->oldinm1);
- }
- obj->oldinm1=inm1;
-
- }else{
- /* this is the case were we have only inm0, we have to redisplay inm1 */
- if (obj->use_yuv){
- if (obj->oldinm1!=NULL){
- fill_overlay_at_pos(obj->overlay,obj->oldinm1,smallrect.x, smallrect.y, smallrect.w, smallrect.h);
- }
- }
- }
-
- if (obj->use_yuv) SDL_DisplayYUVOverlay(obj->overlay,&rect);
- SDL_UpdateRect(obj->screen,0,0,obj->width,obj->height);
-
-}
-
-void ms_sdl_out_class_init(MSSdlOutClass *klass){
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_sdl_out_process;
- MS_FILTER_CLASS(klass)->max_qinputs=2;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_sdl_out_destroy;
- MS_FILTER_CLASS(klass)->name="MSSdlOut";
- /* Initialize the SDL library */
- if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
- fprintf(stderr,
- "Couldn't initialize SDL: %s\n", SDL_GetError());
- return;
- }
- /* Clean up on exit */
- atexit(SDL_Quit);
-}
-
-MSFilter * ms_sdl_out_new(void){
- MSSdlOut *obj=g_new0(MSSdlOut,1);
- if (ms_sdl_out_class==NULL){
- ms_sdl_out_class=g_new0(MSSdlOutClass,1);
- ms_sdl_out_class_init(ms_sdl_out_class);
- }
- MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_sdl_out_class);
- ms_sdl_out_init(obj);
- return MS_FILTER(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.h
deleted file mode 100644
index fd6ec54..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssdlout.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/***************************************************************************
- * mssdlout.h
- *
- * Mon Jul 11 16:18:55 2005
- * Copyright 2005 Simon Morlat
- * Email simon dot morlat at linphone dot org
- ****************************************************************************/
-
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef mssdlout_h
-#define mssdlout_h
-
-#include "msfilter.h"
-
-#include <SDL/SDL.h>
-#include <SDL/SDL_video.h>
-
-struct _MSSdlOut
-{
- MSFilter parent;
- MSQueue *input[2];
- gint width,height;
- const gchar *format;
- SDL_Surface *screen;
- SDL_Overlay *overlay;
- MSMessage *oldinm1;
- gboolean use_yuv;
-};
-
-
-typedef struct _MSSdlOut MSSdlOut;
-
-struct _MSSdlOutClass
-{
- MSFilterClass parent_class;
-};
-
-typedef struct _MSSdlOutClass MSSdlOutClass;
-
-MSFilter * ms_sdl_out_new(void);
-void ms_sdl_out_set_format(MSSdlOut *obj, const char *fmt);
-
-#define MS_SDL_OUT(obj) ((MSSdlOut*)obj)
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.c
deleted file mode 100644
index 3803b01..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation
-
- */
-
-#include "mssoundread.h"
-
-
-void ms_sound_read_init(MSSoundRead *w)
-{
- ms_filter_init(MS_FILTER(w));
-
-}
-
-void ms_sound_read_class_init(MSSoundReadClass *klass)
-{
- int i;
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- MS_FILTER_CLASS(klass)->max_foutputs=1; /* one fifo output only */
-
- ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SOURCE);
-}
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.h
deleted file mode 100644
index 7f2cab9..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundread.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef MSSOUNDREAD_H
-#define MSSOUNDREAD_H
-
-#include "msfilter.h"
-#include "mssync.h"
-
-
-
-struct _MSSoundRead
-{
- /* the MSOssRead derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssRead object
- in order to the object mechanism to work*/
- MSFilter filter;
-};
-
-typedef struct _MSSoundRead MSSoundRead;
-
-struct _MSSoundReadClass
-{
- /* the MSOssRead derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssRead class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
- gint (*set_device)(MSSoundRead *, gint devid);
- void (*start)(MSSoundRead *);
- void (*stop)(MSSoundRead*);
- void (*set_level)(MSSoundRead *, gint a);
-};
-
-typedef struct _MSSoundReadClass MSSoundReadClass;
-
-/* PUBLIC */
-#define MS_SOUND_READ(filter) ((MSSoundRead*)(filter))
-#define MS_SOUND_READ_CLASS(klass) ((MSSoundReadClass*)(klass))
-
-static inline int ms_sound_read_set_device(MSSoundRead *r,gint devid)
-{
- return MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->set_device(r,devid);
-}
-
-static inline void ms_sound_read_start(MSSoundRead *r)
-{
- MS_SOUND_READ_CLASS( MS_FILTER(r)->klass )->start(r);
-}
-
-static inline void ms_sound_read_stop(MSSoundRead *w)
-{
- MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->stop(w);
-}
-
-static inline void ms_sound_read_set_level(MSSoundRead *w,gint a)
-{
- MS_SOUND_READ_CLASS( MS_FILTER(w)->klass )->set_level(w,a);
-}
-
-/* FOR INTERNAL USE*/
-void ms_sound_read_init(MSSoundRead *r);
-void ms_sound_read_class_init(MSSoundReadClass *klass);
-
-
-#endif
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.c
deleted file mode 100644
index 9c5879f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation
-
- */
-
-#include "mssoundwrite.h"
-
-
-void ms_sound_write_init(MSSoundWrite *w)
-{
- ms_filter_init(MS_FILTER(w));
-
-}
-
-void ms_sound_write_class_init(MSSoundWriteClass *klass)
-{
- int i;
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- MS_FILTER_CLASS(klass)->max_finputs=1; /* one fifo output only */
-
- ms_filter_class_set_attr( MS_FILTER_CLASS(klass),FILTER_IS_SINK);
-}
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.h
deleted file mode 100644
index e6d7987..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssoundwrite.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef MSSOUNDWRITE_H
-#define MSSOUNDWRITE_H
-
-#include "msfilter.h"
-#include "mssync.h"
-
-
-
-struct _MSSoundWrite
-{
- /* the MSOssWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSOssWrite object
- in order to the object mechanism to work*/
- MSFilter filter;
-};
-
-typedef struct _MSSoundWrite MSSoundWrite;
-
-struct _MSSoundWriteClass
-{
- /* the MSOssWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSOssWrite class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
- gint (*set_device)(MSSoundWrite *, gint devid);
- void (*start)(MSSoundWrite *);
- void (*stop)(MSSoundWrite*);
- void (*set_level)(MSSoundWrite *, gint a);
-};
-
-typedef struct _MSSoundWriteClass MSSoundWriteClass;
-
-/* PUBLIC */
-#define MS_SOUND_WRITE(filter) ((MSSoundWrite*)(filter))
-#define MS_SOUND_WRITE_CLASS(klass) ((MSSoundWriteClass*)(klass))
-
-static inline int ms_sound_write_set_device(MSSoundWrite *r,gint devid)
-{
- return MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->set_device(r,devid);
-}
-
-static inline void ms_sound_write_start(MSSoundWrite *r)
-{
- MS_SOUND_WRITE_CLASS( MS_FILTER(r)->klass )->start(r);
-}
-
-static inline void ms_sound_write_stop(MSSoundWrite *w)
-{
- MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->stop(w);
-}
-
-static inline void ms_sound_write_set_level(MSSoundWrite *w,gint a)
-{
- MS_SOUND_WRITE_CLASS( MS_FILTER(w)->klass )->set_level(w,a);
-}
-
-/* FOR INTERNAL USE*/
-void ms_sound_write_init(MSSoundWrite *r);
-void ms_sound_write_class_init(MSSoundWriteClass *klass);
-
-
-#endif
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.c
deleted file mode 100644
index f3fd4d2..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <config.h>
-
-#ifdef HAVE_SPEEX
-
-#include "msspeexdec.h"
-
-#ifdef HAVE_GLIB
-#include <gmodule.h>
-#endif
-
-extern MSFilter * ms_speex_enc_new();
-
-MSCodecInfo speex_info=
-{
- {
- "Speex codec",
- 0,
- MS_FILTER_AUDIO_CODEC,
- ms_speex_dec_new,
- "A high quality variable bit-rate codec from Jean Marc Valin and David Rowe."
- },
- ms_speex_enc_new,
- ms_speex_dec_new,
- 0, /*frame size */
- 0,
- 8000, /*minimal bitrate */
- -1, /* sampling frequency */
- 110, /* payload type */
- "speex",
- 1,
- 1
-};
-
-
-
-void ms_speex_codec_init()
-{
-
- ms_filter_register(MS_FILTER_INFO(&speex_info));
- //ms_filter_register(MS_FILTER_INFO(&speex_lbr_info));
-}
-
-#ifdef HAVE_GLIB
-gchar * g_module_check_init(GModule *module)
-{
- ms_speex_codec_init();
-
- return NULL;
-}
-#else
-gchar * g_module_check_init()
-{
- ms_speex_codec_init();
-
- return NULL;
-}
-#endif
-
-static MSSpeexDecClass * ms_speex_dec_class=NULL;
-//static MSSpeexDecClass * ms_speexnb_dec_class=NULL;
-
-MSFilter * ms_speex_dec_new()
-{
- MSSpeexDec *obj=g_new(MSSpeexDec,1);
-
- if (ms_speex_dec_class==NULL){
- ms_speex_dec_class=g_new(MSSpeexDecClass,1);
- ms_speex_dec_class_init(ms_speex_dec_class);
- }
- MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_dec_class);
-
- ms_speex_dec_init(obj);
- return MS_FILTER(obj);
-}
-
-void ms_speex_dec_init(MSSpeexDec *obj)
-{
- ms_filter_init(MS_FILTER(obj));
- obj->initialized=0;
- MS_FILTER(obj)->outfifos=obj->outf;
- MS_FILTER(obj)->inqueues=obj->inq;
- obj->outf[0]=NULL;
- obj->inq[0]=NULL;
- obj->frequency=8000; /*default value */
-
-}
-
-void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode)
-{
- int pf=1;
-
- obj->speex_state=speex_decoder_init(mode);
- speex_bits_init(&obj->bits);
- /* enable the perceptual post filter */
- speex_decoder_ctl(obj->speex_state,SPEEX_SET_PF, &pf);
-
- speex_mode_query(mode, SPEEX_MODE_FRAME_SIZE, &obj->frame_size);
-
- obj->initialized=1;
-}
-
-int ms_speex_dec_set_property(MSSpeexDec *obj, MSFilterProperty prop, int *value)
-{
- if (obj->initialized){
- /* we are called when speex is running !! forbid that! */
- ms_warning("ms_speex_dec_set_property: cannot call this function when running!");
- return -1;
- }
- switch(prop){
- case MS_FILTER_PROPERTY_FREQ:
- obj->frequency=value[0];
- break;
- }
- return 0;
-}
-
-void ms_speex_dec_setup(MSSpeexDec *obj)
-{
- const SpeexMode *mode;
- g_message("Speex decoder setup: freq=%i",obj->frequency);
- if ( obj->frequency< 16000) mode=&speex_nb_mode;
- else mode=&speex_wb_mode;
- ms_speex_dec_init_core(obj,mode);
-}
-
-void ms_speex_dec_unsetup(MSSpeexDec *obj)
-{
- ms_speex_dec_uninit_core(obj);
-}
-
-void ms_speex_dec_class_init(MSSpeexDecClass *klass)
-{
- gint frame_size=0;
-
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- /* use the largest frame size to configure fifos */
- speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_dec_process;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_dec_setup;
- MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_dec_unsetup;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_dec_destroy;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_dec_set_property;
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexDecoder");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info;
- MS_FILTER_CLASS(klass)->max_foutputs=1;
- MS_FILTER_CLASS(klass)->max_qinputs=1;
- MS_FILTER_CLASS(klass)->w_maxgran=frame_size*2;
- ms_trace("ms_speex_dec_class_init: w_maxgran is %i.",MS_FILTER_CLASS(klass)->w_maxgran);
-}
-
-void ms_speex_dec_uninit_core(MSSpeexDec *obj)
-{
- speex_decoder_destroy(obj->speex_state);
- obj->initialized=0;
-}
-
-void ms_speex_dec_uninit(MSSpeexDec *obj)
-{
-
-}
-
-void ms_speex_dec_destroy(MSSpeexDec *obj)
-{
- ms_speex_dec_uninit(obj);
- g_free(obj);
-}
-
-void ms_speex_dec_process(MSSpeexDec *obj)
-{
- MSFifo *outf=obj->outf[0];
- MSQueue *inq=obj->inq[0];
- gint16 *output;
- gint gran=obj->frame_size*2;
- gint i;
- MSMessage *m;
-
- g_return_if_fail(inq!=NULL);
- g_return_if_fail(outf!=NULL);
-
- m=ms_queue_get(inq);
- g_return_if_fail(m!=NULL);
- speex_bits_reset(&obj->bits);
- ms_fifo_get_write_ptr(outf,gran,(void**)&output);
- g_return_if_fail(output!=NULL);
- if (m->data!=NULL){
-
- speex_bits_read_from(&obj->bits,m->data,m->size);
- /* decode */
- speex_decode_int(obj->speex_state,&obj->bits,(short*)output);
- }else{
- /* we have a missing packet */
- speex_decode_int(obj->speex_state,NULL,(short*)output);
- }
- ms_message_destroy(m);
-
-}
-
-#endif /* HAVE_SPEEX */
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.h
deleted file mode 100644
index d4e745f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexdec.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSSPEEXDEC_H
-#define MSSPEEXDEC_H
-
-#include <mscodec.h>
-#include <speex.h>
-
-struct _MSSpeexDec
-{
- MSFilter parent;
- MSQueue *inq[1]; /* speex has an input q because it can be variable bit rate */
- MSFifo *outf[1];
- void *speex_state;
- SpeexBits bits;
- int frequency;
- int frame_size;
- int initialized;
-};
-
-typedef struct _MSSpeexDec MSSpeexDec;
-
-
-struct _MSSpeexDecClass
-{
- MSFilterClass parent;
-};
-
-typedef struct _MSSpeexDecClass MSSpeexDecClass;
-
-
-#define MS_SPEEX_DEC(o) ((MSSpeexDec*)(o))
-#define MS_SPEEX_DEC_CLASS(o) ((MSSpeexDecClass*)(o))
-
-/* call this before if don't load the plugin dynamically */
-void ms_speex_codec_init();
-
-/* mediastreamer compliant constructor */
-MSFilter * ms_speex_dec_new();
-
-void ms_speex_dec_init(MSSpeexDec *obj);
-void ms_speex_dec_init_core(MSSpeexDec *obj,const SpeexMode *mode);
-void ms_speex_dec_class_init(MSSpeexDecClass *klass);
-void ms_speex_dec_uninit(MSSpeexDec *obj);
-void ms_speex_dec_uninit_core(MSSpeexDec *obj);
-
-void ms_speex_dec_process(MSSpeexDec *obj);
-void ms_speex_dec_destroy(MSSpeexDec *obj);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.c
deleted file mode 100644
index abf976e..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <config.h>
-
-#ifdef HAVE_SPEEX
-
-#include "msspeexenc.h"
-#include "ms.h"
-extern MSCodecInfo speex_info;
-
-static MSSpeexEncClass * ms_speex_enc_class=NULL;
-
-MSFilter * ms_speex_enc_new()
-{
- MSSpeexEnc *obj=g_new(MSSpeexEnc,1);
-
- if (ms_speex_enc_class==NULL){
- ms_speex_enc_class=g_new(MSSpeexEncClass,1);
- ms_speex_enc_class_init(ms_speex_enc_class);
- }
- MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_speex_enc_class);
- ms_speex_enc_init(MS_SPEEX_ENC(obj));
- return MS_FILTER(obj);
-}
-
-void ms_speex_enc_init(MSSpeexEnc *obj)
-{
- ms_filter_init(MS_FILTER(obj));
- MS_FILTER(obj)->infifos=obj->inf;
- MS_FILTER(obj)->outqueues=obj->outq;
- obj->inf[0]=NULL;
- obj->outq[0]=NULL;
- obj->frequency=8000;
- obj->bitrate=30000;
- obj->initialized=0;
-}
-
-void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint bitrate)
-{
- int proc_type, proc_speed;
- gchar *proc_vendor;
- int tmp;
- int frame_size;
-
- obj->speex_state=speex_encoder_init(mode);
- speex_bits_init(&obj->bits);
-
- if (bitrate>0) {
- bitrate++;
- speex_encoder_ctl(obj->speex_state, SPEEX_SET_BITRATE, &bitrate);
- g_message("Setting speex output bitrate less or equal than %i",bitrate-1);
- }
-
- proc_speed=ms_proc_get_speed();
- proc_vendor=ms_proc_get_param("vendor_id");
- if (proc_speed<0 || proc_vendor==NULL){
- g_warning("Can't guess processor features: setting speex encoder to its lowest complexity.");
- tmp=1;
- speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
- }else if ((proc_speed!=-1) && (proc_speed<200)){
- g_warning("A cpu speed less than 200 Mhz is not enough: let's reduce the complexity of the speex codec.");
- tmp=1;
- speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
- }else if (proc_vendor!=NULL) {
- if (strncmp(proc_vendor,"GenuineIntel",strlen("GenuineIntel"))==0){
- proc_type=ms_proc_get_type();
- if (proc_type==5){
- g_warning("A pentium I is not enough fast for speex codec in normal mode: let's reduce its complexity.");
- tmp=1;
- speex_encoder_ctl(obj->speex_state,SPEEX_SET_COMPLEXITY,&tmp);
- }
- }
- g_free(proc_vendor);
- }
- /* guess the used input frame size */
- speex_mode_query(mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
- MS_FILTER(obj)->r_mingran=frame_size*2;
- ms_trace("ms_speex_init: using frame size of %i.",MS_FILTER(obj)->r_mingran);
-
- obj->initialized=1;
-}
-
-/* must be called before the encoder is running*/
-int ms_speex_enc_set_property(MSSpeexEnc *obj,int property,int *value)
-{
- if (obj->initialized){
- /* we are called when speex is running !! forbid that! */
- ms_warning("ms_speex_enc_set_property: cannot call this function when running!");
- return -1;
- }
- switch(property){
- case MS_FILTER_PROPERTY_FREQ:
- obj->frequency=value[0];
- break;
- case MS_FILTER_PROPERTY_BITRATE: /* to specify max bitrate */
- obj->bitrate=value[0];
- break;
- }
- return 0;
-}
-
-void ms_speex_enc_setup(MSSpeexEnc *obj)
-{
- const SpeexMode *mode;
- int quality;
- g_message("Speex encoder setup: freq=%i",obj->frequency);
- if ( obj->frequency< 16000) mode=&speex_nb_mode;
- else mode=&speex_wb_mode;
- ms_speex_enc_init_core(obj,mode,obj->bitrate);
-
-}
-
-void ms_speex_enc_unsetup(MSSpeexEnc *obj)
-{
- ms_speex_enc_uninit_core(obj);
-}
-
-void ms_speex_enc_class_init(MSSpeexEncClass *klass)
-{
- gint frame_size=0;
-
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- /* we take the larger (wb) frame size */
- speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size);
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_enc_process;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_enc_destroy;
- MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_enc_setup;
- MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_enc_unsetup;
- MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_enc_set_property;
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexEncoder");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info;
- MS_FILTER_CLASS(klass)->max_finputs=1;
- MS_FILTER_CLASS(klass)->max_qoutputs=1;
- MS_FILTER_CLASS(klass)->r_maxgran=frame_size*2;
- ms_trace("ms_speex_enc_class_init: r_maxgran is %i.",MS_FILTER_CLASS(klass)->r_maxgran);
-}
-
-void ms_speex_enc_uninit_core(MSSpeexEnc *obj)
-{
- if (obj->initialized){
- speex_encoder_destroy(obj->speex_state);
- obj->initialized=0;
- }
-}
-
-void ms_speex_enc_destroy(MSSpeexEnc *obj)
-{
- ms_speex_enc_uninit_core(obj);
- g_free(obj);
-}
-
-void ms_speex_enc_process(MSSpeexEnc *obj)
-{
- MSFifo *inf=obj->inf[0];
- MSQueue *outq=obj->outq[0];
- gint16 *input;
- gint gran=MS_FILTER(obj)->r_mingran;
- gint i;
- MSMessage *m;
-
- g_return_if_fail(inf!=NULL);
- g_return_if_fail(outq!=NULL);
-
- ms_fifo_get_read_ptr(inf,gran,(void**)&input);
- g_return_if_fail(input!=NULL);
- /* encode */
- speex_bits_reset(&obj->bits);
- speex_encode_int(obj->speex_state,(short*)input,&obj->bits);
- m=ms_message_new(speex_bits_nbytes(&obj->bits));
- m->size=speex_bits_write(&obj->bits,m->data,m->size);
- ms_queue_put(outq,m);
-}
-
-#endif /* HAVE_SPEEX */
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.h
deleted file mode 100644
index 41655b9..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msspeexenc.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSSPEEXENC_H
-#define MSSPEEXENC_H
-
-#include <mscodec.h>
-#include <speex.h>
-
-struct _MSSpeexEnc
-{
- MSFilter parent;
- MSFifo *inf[1];
- MSQueue *outq[1]; /* speex has an output q because it can be variable bit rate */
- void *speex_state;
- SpeexBits bits;
- int frequency;
- int bitrate;
- int initialized;
-};
-
-typedef struct _MSSpeexEnc MSSpeexEnc;
-
-
-struct _MSSpeexEncClass
-{
- MSFilterClass parent;
-};
-
-typedef struct _MSSpeexEncClass MSSpeexEncClass;
-
-
-#define MS_SPEEX_ENC(o) ((MSSpeexEnc*)(o))
-#define MS_SPEEX_ENC_CLASS(o) ((MSSpeexEncClass*)(o))
-
-/* generic constructor */
-MSFilter * ms_speex_enc_new();
-
-void ms_speex_enc_init_core(MSSpeexEnc *obj,const SpeexMode *mode, gint quality);
-void ms_speex_enc_uninit_core(MSSpeexEnc *obj);
-void ms_speex_enc_init(MSSpeexEnc *obj);
-void ms_speex_enc_class_init(MSSpeexEncClass *klass);
-
-
-void ms_speex_enc_process(MSSpeexEnc *obj);
-void ms_speex_enc_destroy(MSSpeexEnc *obj);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssync.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mssync.c
deleted file mode 100644
index 9e32a8a..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssync.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "mssync.h"
-#include <errno.h>
-
-/* TODO:
- -define an uninit function that free the mutex
-*/
-
-/**
- * function_name:ms_sync_get_bytes_per_tick
- * @sync: A #MSSync object.
- *
- * Returns the number of bytes per tick. This is a usefull information for sources, so
- * that they can know how much data they must deliver each time they are called.
- *
- */
-
-/* private */
-void ms_sync_init(MSSync *sync)
-{
- sync->klass=NULL;
- sync->lock=g_mutex_new();
- sync->thread_cond=g_cond_new();
- sync->stop_cond=g_cond_new();
- sync->attached_filters=NULL;
- sync->execution_list=NULL;
- sync->filters=0;
- sync->run=0;
- sync->flags=0;
- sync->samples_per_tick=0;
- sync->ticks=0;
- sync->time=0;
- sync->thread=NULL;
-}
-
-void ms_sync_class_init(MSSyncClass *klass)
-{
- klass->max_filters=0;
- klass->synchronize=NULL;
- klass->attach=ms_sync_attach_generic;
- klass->detach=ms_sync_detach_generic;
- klass->destroy=NULL;
-}
-
-/* public*/
-
-
-/**
- * ms_sync_attach:
- * @sync: A #MSSync object.
- * @f: A #MSFilter object.
- *
- * Attach a chain of filters to a synchronisation source @sync. Filter @f must be the first filter of the processing chain.
- * In order to be run, each chain of filter must be attached to a synchronisation source, that will be responsible for scheduling
- * the processing. Multiple chains can be attached to a single synchronisation.
- *
- * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
- */
-int ms_sync_attach(MSSync *sync,MSFilter *f)
-{
- gint err;
- ms_sync_lock(sync);
- err=sync->klass->attach(sync,f);
- ms_sync_update(sync);
- ms_sync_unlock(sync);
- return(err);
-}
-
-int ms_sync_attach_generic(MSSync *sync,MSFilter *f)
-{
- int i;
- //printf("attr: %i\n",f->klass->attributes);
- g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL);
- g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT);
-
-
- /* find a free place to attach*/
- for (i=0;i<sync->klass->max_filters;i++)
- {
- if (sync->attached_filters[i]==NULL)
- {
- sync->attached_filters[i]=f;
- sync->filters++;
- ms_trace("Filter succesfully attached to sync.");
- return 0;
- }
- }
- g_warning("No more link on sync !");
- return(-EMLINK);
-}
-
-/**
- * ms_sync_detach:
- * @sync: A #MSSync object.
- * @f: A #MSFilter object.
- *
- * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
- * The processing chain will no more be executed.
- *
- * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
- */
-int ms_sync_detach(MSSync *sync,MSFilter *f)
-{
- gint err;
- ms_sync_lock(sync);
- err=sync->klass->detach(sync,f);
- ms_sync_update(sync);
- ms_sync_unlock(sync);
- return(err);
-}
-
-int ms_sync_detach_generic(MSSync *sync,MSFilter *f)
-{
- int i;
- g_return_val_if_fail(f->klass->attributes & FILTER_IS_SOURCE,-EINVAL);
- g_return_val_if_fail(sync->attached_filters!=NULL,-EFAULT);
- for (i=0;i<sync->filters;i++)
- {
- if (sync->attached_filters[i]==f)
- {
- sync->attached_filters[i]=NULL;
- sync->filters--;
- return 0;
- }
- }
- return(-EMLINK);
-}
-
-void ms_sync_set_samples_per_tick(MSSync *sync,gint size)
-{
- if (sync->samples_per_tick==0)
- {
- sync->samples_per_tick=size;
- g_cond_signal(sync->thread_cond);
- }
- else sync->samples_per_tick=size;
-}
-
-/* call the setup func of each filter attached to the graph */
-void ms_sync_setup(MSSync *sync)
-{
- GList *elem=sync->execution_list;
- MSFilter *f;
- while(elem!=NULL){
- f=(MSFilter*)elem->data;
- if (f->klass->setup!=NULL){
- f->klass->setup(f,sync);
- }
- elem=g_list_next(elem);
- }
-}
-
-/* call the unsetup func of each filter attached to the graph */
-void ms_sync_unsetup(MSSync *sync)
-{
- GList *elem=sync->execution_list;
- MSFilter *f;
- while(elem!=NULL){
- f=(MSFilter*)elem->data;
- if (f->klass->unsetup!=NULL){
- f->klass->unsetup(f,sync);
- }
- elem=g_list_next(elem);
- }
-}
-
-
-int ms_sync_uninit(MSSync *sync)
-{
- g_mutex_free(sync->lock);
- g_cond_free(sync->thread_cond);
- g_cond_free(sync->stop_cond);
-}
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mssync.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mssync.h
deleted file mode 100644
index 012c068..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mssync.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MS_SYNC_H
-#define MS_SYNC_H
-
-
-#include "msfilter.h"
-
-struct _MSSync
-{
- struct _MSSyncClass *klass;
- GMutex *lock;
- MSFilter **attached_filters; /* pointer to a table of pointer of filters*/
- GList *execution_list; /* the list of filters to be executed. This is filled with compilation */
- gint filters; /*number of filters attached to the sync */
- gint run; /* flag to indicate whether the sync must be run or not */
- GThread * thread; /* the thread ressource if this sync is run by a thread*/
- GCond *thread_cond;
- GCond *stop_cond;
- guint32 flags;
- gint interval; /* in miliseconds*/
-#define MS_SYNC_NEED_UPDATE (0x0001) /* a modification has occured in the processing chains
- attached to this sync; so the execution list has to be updated */
- guint samples_per_tick; /* number of bytes produced by sources of the processing chains*/
- guint32 ticks;
- guint32 time; /* a time since the start of the sync expressed in milisec*/
-};
-
-typedef struct _MSSync MSSync;
-
-typedef void (*MSSyncDestroyFunc)(MSSync*);
-typedef void (*MSSyncSyncFunc)(MSSync*);
-typedef int (*MSSyncAttachFunc)(MSSync*,MSFilter*);
-typedef int (*MSSyncDetachFunc)(MSSync*,MSFilter*);
-
-typedef struct _MSSyncClass
-{
- gint max_filters; /* the maximum number of filters that can be attached to this sync*/
- MSSyncSyncFunc synchronize;
- MSSyncDestroyFunc destroy;
- MSSyncAttachFunc attach;
- MSSyncDetachFunc detach;
-} MSSyncClass;
-
-/* private */
-void ms_sync_init(MSSync *sync);
-void ms_sync_class_init(MSSyncClass *klass);
-
-int ms_sync_attach_generic(MSSync *sync,MSFilter *f);
-int ms_sync_detach_generic(MSSync *sync,MSFilter *f);
-
-/* public*/
-
-#define MS_SYNC(sync) ((MSSync*)(sync))
-#define MS_SYNC_CLASS(klass) ((MSSyncClass*)(klass))
-
-#define ms_sync_synchronize(_sync) \
-do \
-{ \
- MSSync *__sync=_sync; \
- __sync->ticks++; \
- ((__sync)->klass->synchronize((__sync))); \
-}while(0)
-
-void ms_sync_setup(MSSync *sync);
-
-void ms_sync_unsetup(MSSync *sync);
-
-#define ms_sync_update(sync) (sync)->flags|=MS_SYNC_NEED_UPDATE
-
-#define ms_sync_get_samples_per_tick(sync) ((sync)->samples_per_tick)
-
-void ms_sync_set_samples_per_tick(MSSync *sync,gint size);
-
-#define ms_sync_get_tick_count(sync) ((sync)->ticks)
-
-#define ms_sync_suspend(sync) g_cond_wait((sync)->thread_cond,(sync)->lock)
-
-#define ms_sync_lock(sync) g_mutex_lock((sync)->lock)
-
-#define ms_sync_unlock(sync) g_mutex_unlock((sync)->lock)
-
-#define ms_sync_trylock(sync) g_mutex_trylock((sync)->lock)
-
-/**
- * function_name:ms_sync_attach
- * @sync: A #MSSync object.
- * @f: A #MSFilter object.
- *
- * Attach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
- *
- * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
- */
-int ms_sync_attach(MSSync *sync,MSFilter *f);
-
-/**
- * ms_sync_detach:
- * @sync: A #MSSync object.
- * @f: A #MSFilter object.
- *
- * Dettach a chain of filters to a synchronisation source. Filter @f must be the first filter of the processing chain.
- * The processing chain will no more be executed.
- *
- * Returns: 0 if successfull, a negative value reprensenting the errno.h error.
- */
-int ms_sync_detach(MSSync *sync,MSFilter *f);
-
-int ms_sync_uninit(MSSync *sync);
-
-#define ms_sync_start(sync) ms_start((sync))
-#define ms_sync_stop(sync) ms_stop((sync))
-
-
-/*destroy*/
-#define ms_sync_destroy(sync) (sync)->klass->destroy((sync))
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.c
deleted file mode 100644
index 1955ef2..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.c
+++ /dev/null
@@ -1,114 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "mstimer.h"
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <signal.h>
-
-static MSTimerClass *ms_timer_class=NULL;
-
-
-void ms_timer_init(MSTimer *sync)
-{
- ms_sync_init(MS_SYNC(sync));
- MS_SYNC(sync)->attached_filters=sync->filters;
- memset(sync->filters,0,MSTIMER_MAX_FILTERS*sizeof(MSFilter*));
- MS_SYNC(sync)->samples_per_tick=160;
- ms_timer_set_interval(sync,20);
- sync->state=MS_TIMER_STOPPED;
-}
-
-void ms_timer_class_init(MSTimerClass *klass)
-{
- ms_sync_class_init(MS_SYNC_CLASS(klass));
- MS_SYNC_CLASS(klass)->max_filters=MSTIMER_MAX_FILTERS;
- MS_SYNC_CLASS(klass)->synchronize=(MSSyncSyncFunc)ms_timer_synchronize;
- MS_SYNC_CLASS(klass)->destroy=(MSSyncDestroyFunc)ms_timer_destroy;
- /* no need to overload these function*/
- MS_SYNC_CLASS(klass)->attach=ms_sync_attach_generic;
- MS_SYNC_CLASS(klass)->detach=ms_sync_detach_generic;
-}
-
-void ms_timer_destroy(MSTimer *timer)
-{
- g_free(timer);
-}
-
-
-void ms_timer_synchronize(MSTimer *timer)
-{
- //printf("ticks=%i \n",MS_SYNC(timer)->ticks);
- if (timer->state==MS_TIMER_STOPPED){
- timer->state=MS_TIMER_RUNNING;
- gettimeofday(&timer->orig,NULL);
- timer->sync.time=0;
- }
- else {
- gint32 diff,time;
- struct timeval tv,cur;
-
- gettimeofday(&cur,NULL);
- time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 );
- if ( (diff=time-timer->sync.time)>50){
- g_warning("Must catchup %i miliseconds.",diff);
- }
- while((diff = timer->sync.time-time) > 0)
- {
- tv.tv_sec = diff/1000;
- tv.tv_usec = (diff%1000)*1000;
- select(0,NULL,NULL,NULL,&tv);
- gettimeofday(&cur,NULL);
- time=((cur.tv_usec-timer->orig.tv_usec)/1000 ) + ((cur.tv_sec-timer->orig.tv_sec)*1000 );
- }
- }
- timer->sync.time+=timer->milisec;
- return;
-}
-
-
-MSSync *ms_timer_new()
-{
- MSTimer *timer;
-
- timer=g_malloc(sizeof(MSTimer));
- ms_timer_init(timer);
- if (ms_timer_class==NULL)
- {
- ms_timer_class=g_new(MSTimerClass,1);
- ms_timer_class_init(ms_timer_class);
- }
- MS_SYNC(timer)->klass=MS_SYNC_CLASS(ms_timer_class);
- return(MS_SYNC(timer));
-}
-
-void ms_timer_set_interval(MSTimer *timer, int milisec)
-{
-
- MS_SYNC(timer)->ticks=0;
- MS_SYNC(timer)->interval=milisec;
- timer->interval.tv_sec=milisec/1000;
- timer->interval.tv_usec=(milisec % 1000)*1000;
- timer->milisec=milisec;
-
-
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.h
deleted file mode 100644
index 5c7e8ed..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mstimer.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef MSTIMER_H
-#define MSTIMER_H
-
-#include "mssync.h"
-#include <sys/time.h>
-
-#define MSTIMER_MAX_FILTERS 10
-
-/* MSTimer derivates from MSSync base class*/
-
-typedef struct _MSTimer
-{
- /* the MSSync must be the first field of the object in order to the object mechanism to work*/
- MSSync sync;
- MSFilter *filters[MSTIMER_MAX_FILTERS];
- gint milisec; /* the interval */
- struct timeval interval;
- struct timeval orig;
- gint state;
-} MSTimer;
-
-
-typedef struct _MSTimerClass
-{
- /* the MSSyncClass must be the first field of the class in order to the class mechanism to work*/
- MSSyncClass parent_class;
-} MSTimerClass;
-
-
-/*private*/
-#define MS_TIMER_RUNNING 1
-#define MS_TIMER_STOPPED 0
-void ms_timer_init(MSTimer *sync);
-void ms_timer_class_init(MSTimerClass *sync);
-
-void ms_timer_destroy(MSTimer *timer);
-void ms_timer_synchronize(MSTimer *timer);
-
-/*public*/
-void ms_timer_set_interval(MSTimer *timer, gint milisec);
-
-/* casts a MSSync object into a MSTimer */
-#define MS_TIMER(sync) ((MSTimer*)(sync))
-/* casts a MSSync class into a MSTimer class */
-#define MS_TIMER_CLASS(klass) ((MSTimerClass*)(klass))
-
-MSSync *ms_timer_new();
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.c
deleted file mode 100644
index aba6e06..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- Copyright 2003 Robert W. Brewer <rbrewer at op.net>
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "mstruespeechdecoder.h"
-#include "mscodec.h"
-
-MSCodecInfo TrueSpeechinfo =
-{
- {
- "TrueSpeech codec",
- 0,
- MS_FILTER_AUDIO_CODEC,
- ms_truespeechencoder_new,
- "This is a proprietary codec by the DSP Group that is used in some "
- "Windows applications. It has a good quality and bitrate. "
- "It requires the Windows DLLs tssoft32.acm and "
- "tsd32.dll to be available."
- },
- ms_truespeechencoder_new,
- ms_truespeechdecoder_new,
- 480,
- 32,
- 8536,
- 8000,
- 116,
- "TSP0",
- 1,
- 1,
-};
-
-
-static MSTrueSpeechDecoderClass *ms_truespeechdecoder_class = 0;
-
-/* FOR INTERNAL USE*/
-void ms_truespeechdecoder_init(MSTrueSpeechDecoder *r);
-void ms_truespeechdecoder_class_init(MSTrueSpeechDecoderClass *klass);
-void ms_truespeechdecoder_destroy(MSTrueSpeechDecoder *obj);
-void ms_truespeechdecoder_process(MSTrueSpeechDecoder *r);
-
-MSFilter * ms_truespeechdecoder_new(void)
-{
- MSTrueSpeechDecoder *r = 0;
-
- if (!ms_truespeechdecoder_class)
- {
- ms_truespeechdecoder_class = g_new(MSTrueSpeechDecoderClass, 1);
- ms_truespeechdecoder_class_init(ms_truespeechdecoder_class);
- }
-
- r = g_new(MSTrueSpeechDecoder, 1);
- MS_FILTER(r)->klass = MS_FILTER_CLASS(ms_truespeechdecoder_class);
- ms_truespeechdecoder_init(r);
- return MS_FILTER(r);
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_truespeechdecoder_init(MSTrueSpeechDecoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos = r->f_inputs;
- MS_FILTER(r)->outfifos = r->f_outputs;
-
- WAVEFORMATEX* wf = ms_truespeechencoder_wf_create();
-
- r->codec = win32codec_create(wf, 0);
- free(wf);
-
- MS_FILTER(r)->r_mingran = r->codec->min_insize;
-
- MS_FILTER_CLASS(ms_truespeechdecoder_class)->r_maxgran =
- r->codec->min_insize;
- MS_FILTER_CLASS(ms_truespeechdecoder_class)->w_maxgran =
- r->codec->min_outsize;
-
- memset(r->f_inputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT);
- memset(r->f_outputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT);
-}
-
-void ms_truespeechdecoder_class_init(MSTrueSpeechDecoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass), "TrueSpeechDecoder");
- MS_FILTER_CLASS(klass)->max_finputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT;
- MS_FILTER_CLASS(klass)->max_foutputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT;
- MS_FILTER_CLASS(klass)->r_maxgran = 0; /* filled in by first instance */
- MS_FILTER_CLASS(klass)->w_maxgran = 0; /* filled in by first instance */
- MS_FILTER_CLASS(klass)->destroy = (MSFilterDestroyFunc)ms_truespeechdecoder_destroy;
- MS_FILTER_CLASS(klass)->process = (MSFilterProcessFunc)ms_truespeechdecoder_process;
- MS_FILTER_CLASS(klass)->info = MS_FILTER_INFO(&TrueSpeechinfo);
- klass->driver = win32codec_create_driver(TRUESPEECH_DLL,
- TRUESPEECH_FORMAT_TAG, 0);
-}
-
-void ms_truespeechdecoder_process(MSTrueSpeechDecoder *r)
-{
- MSFifo *fi,*fo;
- gint err1;
- void *s,*d;
-
- /* process output fifos, but there is only one for this class of filter*/
-
- fi = r->f_inputs[0];
- fo = r->f_outputs[0];
- if (fi)
- {
- err1 = ms_fifo_get_read_ptr(fi, r->codec->min_insize, &s);
- if (err1 > 0)
- {
- err1 = ms_fifo_get_write_ptr(fo, r->codec->min_outsize, &d);
- if (d)
- {
- signed long n;
- n = win32codec_convert(r->codec,
- s, r->codec->min_insize,
- d, r->codec->min_outsize);
- }
- }
-
- }
-}
-
-
-
-void ms_truespeechdecoder_uninit(MSTrueSpeechDecoder *obj)
-{
- win32codec_destroy(obj->codec);
-}
-
-void ms_truespeechdecoder_destroy(MSTrueSpeechDecoder *obj)
-{
- ms_truespeechdecoder_uninit(obj);
- g_free(obj);
-}
-
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.h
deleted file mode 100644
index 6247743..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechdecoder.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- Copyright (C) 2003 Robert W. Brewer <rbrewer at op.net>
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSTRUESPEECHDECODER_H
-#define MSTRUESPEECHDECODER_H
-
-#include "msfilter.h"
-#include "mstruespeechencoder.h"
-
-
-
-typedef struct _MSTrueSpeechDecoder
-{
- /* the MSTrueSpeechDecoder derives from MSFilter, so the MSFilter
- object MUST be the first of the MSTrueSpeechDecoder object
- in order for the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
- MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
- Win32Codec* codec;
-} MSTrueSpeechDecoder;
-
-typedef struct _MSTrueSpeechDecoderClass
-{
- /* the MSTrueSpeechDecoder derives from MSFilter,
- so the MSFilter class MUST be the first of the MSTrueSpechDecoder
- class
- in order for the class mechanism to work*/
- MSFilterClass parent_class;
- Win32CodecDriver* driver;
-} MSTrueSpeechDecoderClass;
-
-/* PUBLIC */
-#define MS_TRUESPEECHDECODER(filter) ((MSTrueSpechMDecoder*)(filter))
-#define MS_TRUESPEECHDECODER_CLASS(klass) ((MSTrueSpeechDecoderClass*)(klass))
-MSFilter * ms_truespeechdecoder_new(void);
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.c
deleted file mode 100644
index 0b00c0c..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- Copyright 2003 Robert W. Brewer <rbrewer at op.net>
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "mstruespeechencoder.h"
-#include "mscodec.h"
-
-#define TRUESPEECH_CBSIZE 32
-
-extern MSCodecInfo TrueSpeechinfo;
-
-static MSTrueSpeechEncoderClass *ms_truespeechencoder_class = 0;
-
-/* FOR INTERNAL USE*/
-void ms_truespeechencoder_init(MSTrueSpeechEncoder *r);
-void ms_truespeechencoder_class_init(MSTrueSpeechEncoderClass *klass);
-void ms_truespeechencoder_destroy(MSTrueSpeechEncoder *obj);
-void ms_truespeechencoder_process(MSTrueSpeechEncoder *r);
-
-MSFilter * ms_truespeechencoder_new(void)
-{
- MSTrueSpeechEncoder *r = 0;
-
- if (!ms_truespeechencoder_class)
- {
- ms_truespeechencoder_class = g_new(MSTrueSpeechEncoderClass, 1);
- ms_truespeechencoder_class_init(ms_truespeechencoder_class);
- }
-
- r = g_new(MSTrueSpeechEncoder, 1);
- MS_FILTER(r)->klass = MS_FILTER_CLASS(ms_truespeechencoder_class);
- ms_truespeechencoder_init(r);
- return MS_FILTER(r);
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_truespeechencoder_init(MSTrueSpeechEncoder *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos = r->f_inputs;
- MS_FILTER(r)->outfifos = r->f_outputs;
-
- WAVEFORMATEX* wf = ms_truespeechencoder_wf_create();
-
- r->codec = win32codec_create(wf, 1);
- free(wf);
-
- MS_FILTER(r)->r_mingran = r->codec->min_insize;
-
- MS_FILTER_CLASS(ms_truespeechencoder_class)->r_maxgran =
- r->codec->min_insize;
- MS_FILTER_CLASS(ms_truespeechencoder_class)->w_maxgran =
- r->codec->min_outsize;
-
- memset(r->f_inputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT);
- memset(r->f_outputs, 0, sizeof(MSFifo*) * MS_TRUESPEECH_CODEC_MAX_IN_OUT);
-}
-
-void ms_truespeechencoder_class_init(MSTrueSpeechEncoderClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass), "TrueSpeechEncoder");
- MS_FILTER_CLASS(klass)->max_finputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT;
- MS_FILTER_CLASS(klass)->max_foutputs = MS_TRUESPEECH_CODEC_MAX_IN_OUT;
- MS_FILTER_CLASS(klass)->r_maxgran = 0; /* filled in by first instance */
- MS_FILTER_CLASS(klass)->w_maxgran = 0; /* filled in by first instance */
- MS_FILTER_CLASS(klass)->destroy = (MSFilterDestroyFunc)ms_truespeechencoder_destroy;
- MS_FILTER_CLASS(klass)->process = (MSFilterProcessFunc)ms_truespeechencoder_process;
- MS_FILTER_CLASS(klass)->info = MS_FILTER_INFO(&TrueSpeechinfo);
- klass->driver = win32codec_create_driver(TRUESPEECH_DLL,
- TRUESPEECH_FORMAT_TAG, 1);
-}
-
-void ms_truespeechencoder_process(MSTrueSpeechEncoder *r)
-{
- MSFifo *fi,*fo;
- int err1;
- void *s,*d;
-
- /* process output fifos, but there is only one for this class of filter*/
-
- fi = r->f_inputs[0];
- fo = r->f_outputs[0];
- if (fi)
- {
- err1 = ms_fifo_get_read_ptr(fi, r->codec->min_insize, &s);
- if (err1 > 0)
- {
- err1 = ms_fifo_get_write_ptr(fo, r->codec->min_outsize, &d);
- if (d)
- {
- signed long n;
-
- n = win32codec_convert(r->codec,
- s, r->codec->min_insize,
- d, r->codec->min_outsize);
- }
- }
-
- }
-}
-
-
-
-void ms_truespeechencoder_uninit(MSTrueSpeechEncoder *obj)
-{
- win32codec_destroy(obj->codec);
-}
-
-void ms_truespeechencoder_destroy(MSTrueSpeechEncoder *obj)
-{
- ms_truespeechencoder_uninit(obj);
- g_free(obj);
-}
-
-
-WAVEFORMATEX* ms_truespeechencoder_wf_create()
-{
- WAVEFORMATEX* ts_wf = 0;
- long* iptr = 0;
-
- ts_wf = malloc(sizeof(WAVEFORMATEX) + TRUESPEECH_CBSIZE);
- if (!ts_wf)
- {
- return 0;
- }
-
- memset(ts_wf, 0, sizeof(*ts_wf) + TRUESPEECH_CBSIZE);
-
- ts_wf->wFormatTag = TRUESPEECH_FORMAT_TAG;
- ts_wf->nChannels = 1;
- ts_wf->nSamplesPerSec = 8000;
- ts_wf->wBitsPerSample = 1;
- ts_wf->nBlockAlign = 32;
- ts_wf->nAvgBytesPerSec = 1067;
- ts_wf->cbSize = TRUESPEECH_CBSIZE;
-
- /* write extra data needed by TrueSpeech codec found
- from examining a TrueSpeech .wav file header
- */
- iptr = (long*)(ts_wf + 1);
- *iptr = 0x00f00001;
-
- return ts_wf;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.h
deleted file mode 100644
index 04e40bb..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mstruespeechencoder.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- Copyright (C) 2003 Robert W. Brewer <rbrewer at op.net>
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#ifndef MSTRUESPEECHENCODER_H
-#define MSTRUESPEECHENCODER_H
-
-#include "msfilter.h"
-#include <win32codec.h>
-
-
-#define MS_TRUESPEECH_CODEC_MAX_IN_OUT 1 /* max inputs/outputs per filter*/
-
-#define TRUESPEECH_FORMAT_TAG 0x22
-#define TRUESPEECH_DLL "tssoft32.acm"
-
-typedef struct _MSTrueSpeechEncoder
-{
- /* the MSTrueSpeechEncoder derives from MSFilter, so the MSFilter
- object MUST be the first of the MSTrueSpeechEncoder object
- in order for the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
- MSFifo *f_outputs[MS_TRUESPEECH_CODEC_MAX_IN_OUT];
- Win32Codec* codec;
-} MSTrueSpeechEncoder;
-
-typedef struct _MSTrueSpeechEncoderClass
-{
- /* the MSTrueSpeechEncoder derives from MSFilter,
- so the MSFilter class MUST be the first of the MSTrueSpechEncoder
- class
- in order for the class mechanism to work*/
- MSFilterClass parent_class;
- Win32CodecDriver* driver;
-} MSTrueSpeechEncoderClass;
-
-/* PUBLIC */
-#define MS_TRUESPEECHENCODER(filter) ((MSTrueSpechMEncoder*)(filter))
-#define MS_TRUESPEECHENCODER_CLASS(klass) ((MSTrueSpeechEncoderClass*)(klass))
-MSFilter * ms_truespeechencoder_new(void);
-
-/* for internal use only */
-WAVEFORMATEX* ms_truespeechencoder_wf_create();
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msutils.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msutils.h
deleted file mode 100644
index 012b87d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msutils.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#ifndef MSUTILS_H
-#define MSUTILS_H
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#else
-#include <uglib.h>
-#endif
-#include <errno.h>
-
-#ifndef ENODATA
-/* this is for freeBSD .*/
-#define ENODATA EWOULDBLOCK
-#endif
-
-#ifdef MS_DEBUG
-
-#define ms_trace g_message
-
-#else
-
-#define ms_trace(...)
-#endif
-
-#define ms_warning g_warning
-#define ms_error g_error
-
-#define VIDEO_SIZE_CIF_W 352
-#define VIDEO_SIZE_CIF_H 288
-#define VIDEO_SIZE_QCIF_W 176
-#define VIDEO_SIZE_QCIF_H 144
-#define VIDEO_SIZE_4CIF_W 704
-#define VIDEO_SIZE_4CIF_H 576
-#define VIDEO_SIZE_MAX_W VIDEO_SIZE_4CIF_W
-#define VIDEO_SIZE_MAX_H VIDEO_SIZE_4CIF_H
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.c
deleted file mode 100644
index 4534d1f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msv4l.h"
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/mman.h>
-
-char *v4l_palette_string[17]={
- "none",
- "GREY", /* Linear greyscale */
- "HI240", /* High 240 cube (BT848) */
- "RGB565", /* 565 16 bit RGB */
- "RGB24", /* 24bit RGB */
- "RGB32", /* 32bit RGB */
- "RGB555", /* 555 15bit RGB */
- "YUV422", /* YUV422 capture */
- "YUYV",
- "UYVY", /* The great thing about standards is ... */
- "YUV420",
- "YUV411", /* YUV411 capture */
- "RAW", /* RAW capture (BT848) */
- "YUV422P", /* YUV 4:2:2 Planar */
- "YUV411P", /* YUV 4:1:1 Planar */
- "YUV420P", /* YUV 4:2:0 Planar */
- "YUV410P", /* YUV 4:1:0 Planar */
-};
-
-#define V4L_PALETTE_TO_STRING(pal) v4l_palette_string[(pal)]
-
-MSFilterInfo v4l_info=
-{
- "Video4Linux",
- 0,
- MS_FILTER_VIDEO_IO,
- ms_v4l_new,
- NULL
-};
-
-
-static MSV4lClass *ms_v4l_class=NULL;
-
-MSFilter * ms_v4l_new()
-{
- MSV4l *obj;
- obj=g_malloc0(sizeof(MSV4l));
- if (ms_v4l_class==NULL)
- {
- ms_v4l_class=g_malloc0(sizeof(MSV4lClass));
- ms_v4l_class_init(ms_v4l_class);
- }
- MS_FILTER(obj)->klass=MS_FILTER_CLASS(ms_v4l_class);
- ms_v4l_init(obj);
- return MS_FILTER(obj);
-}
-
-void ms_v4l_init(MSV4l *obj)
-{
- ms_video_source_init(MS_VIDEO_SOURCE(obj));
- /* initialize the static buffer */
- obj->use_mmap=0;
- obj->fd=-1;
- obj->device = g_strdup("/dev/video0");
- obj->count=0;
- obj->allocdbuf=NULL;
- obj->grab_image=FALSE;
- obj->image_grabbed=NULL;
- obj->cond=g_cond_new();
- obj->stopcond=g_cond_new();
- obj->v4lthread=NULL;
- obj->thread_exited=FALSE;
- obj->frame=0;
- MS_VIDEO_SOURCE(obj)->format="RGB24"; /*default value */
- MS_VIDEO_SOURCE(obj)->width = VIDEO_SIZE_CIF_W; /*default value */
- MS_VIDEO_SOURCE(obj)->height = VIDEO_SIZE_CIF_H; /*default value */
-}
-
-void ms_v4l_class_init(MSV4lClass *klass)
-{
- ms_video_source_class_init(MS_VIDEO_SOURCE_CLASS(klass));
- MS_VIDEO_SOURCE_CLASS(klass)->start=(void (*)(MSVideoSource *))ms_v4l_start;
- MS_VIDEO_SOURCE_CLASS(klass)->stop=(void (*)(MSVideoSource *))ms_v4l_stop;
- MS_VIDEO_SOURCE_CLASS(klass)->set_device=(int (*)(MSVideoSource*,const gchar*))ms_v4l_set_device;
- MS_FILTER_CLASS(klass)->process=(void (*)(MSFilter *))v4l_process;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_v4l_destroy;
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"msv4l");
- MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&v4l_info;
-}
-
-void *v4l_thread(MSV4l *obj);
-
-void ms_v4l_start(MSV4l *obj)
-{
- int err;
- ms_filter_lock(MS_FILTER(obj));
- obj->fd=open(obj->device,O_RDONLY);
- if (obj->fd<0)
- {
- g_warning("MSV4l: cannot open video device: %s.",strerror(errno));
- }else{
- err=v4l_configure(obj);
- if (err<0)
- {
- g_warning("MSV4l: could not get configuration of video device");
- }
- }
- obj->thread_exited=FALSE;
- obj->v4lthread=g_thread_create((GThreadFunc)v4l_thread,(gpointer)obj,FALSE,NULL);
- while(!obj->thread_run) g_cond_wait(obj->cond,MS_FILTER(obj)->lock);
- ms_filter_unlock(MS_FILTER(obj));
-}
-
-void ms_v4l_stop(MSV4l *obj)
-{
- ms_filter_lock(MS_FILTER(obj));
- obj->thread_run=FALSE;
- obj->grab_image=FALSE;
- g_cond_signal(obj->cond);
- if (obj->fd>0)
- {
- close(obj->fd);
- obj->fd=-1;
- if (!obj->use_mmap){
- if (obj->allocdbuf!=NULL) ms_buffer_destroy(obj->allocdbuf);
- else obj->allocdbuf=NULL;
- }else
- {
- munmap(obj->mmapdbuf,obj->vmbuf.size);
- obj->mmapdbuf=NULL;
- }
- obj->image_grabbed=NULL;
- }
- while(!obj->thread_exited) g_cond_wait(obj->stopcond,MS_FILTER(obj)->lock);
- obj->v4lthread=NULL;
- ms_filter_unlock(MS_FILTER(obj));
-}
-
-gint ms_v4l_get_width(MSV4l *v4l)
-{
- return v4l->win.width;
-}
-
-gint ms_v4l_get_height(MSV4l *v4l)
-{
- return v4l->win.height;
-}
-
-int ms_v4l_set_device(MSV4l *obj, const gchar *device)
-{
- if (obj->device!=NULL) g_free(obj->device);
- obj->device=g_strdup(device);
- return 0;
-}
-
-void ms_v4l_set_size(MSV4l *obj, gint width, gint height)
-{
- gint err;
- gboolean restart = FALSE;
-
- if (obj->fd == -1)
- {
- obj->fd = open(obj->device, O_RDONLY);
- if (obj->fd < 0)
- {
- g_warning("MSV4l: cannot open video device: %s.",strerror(errno));
- return;
- }
- } else
- restart = TRUE;
-
- ms_filter_lock(MS_FILTER(obj));
- err = ioctl(obj->fd, VIDIOCGCAP, &obj->cap);
- if (err != 0)
- {
- g_warning("MSV4l: cannot get device capabilities: %s.",strerror(errno));
- return;
- }
- if (width <= obj->cap.maxwidth && width >= obj->cap.minwidth &&
- height <= obj->cap.maxheight && height >= obj->cap.minheight)
- {
- MS_VIDEO_SOURCE(obj)->width = width;
- MS_VIDEO_SOURCE(obj)->height = height;
- }
- ms_filter_unlock(MS_FILTER(obj));
-
- if (restart)
- {
- ms_v4l_stop(obj);
- ms_v4l_start(obj);
- }
-
-}
-
-int v4l_configure(MSV4l *f)
-{
- gint err;
- gint i;
- struct video_channel *chan=&f->channel;
- struct video_window *win=&f->win;
- struct video_picture *pict=&f->pict;
- struct video_mmap *vmap=&f->vmap;
- struct video_mbuf *vmbuf=&f->vmbuf;
- struct video_capture *vcap=&f->vcap;
- int found=0;
-
- err=ioctl(f->fd,VIDIOCGCAP,&f->cap);
- if (err!=0)
- {
- g_warning("MSV4l: cannot get device capabilities: %s.",strerror(errno));
- return -1;
- }
- MS_VIDEO_SOURCE(f)->dev_name=f->cap.name;
-
- for (i=0;i<f->cap.channels;i++)
- {
- chan->channel=i;
- err=ioctl(f->fd,VIDIOCGCHAN,chan);
- if (err==0)
- {
- g_message("Getting video channel %s",chan->name);
- switch(chan->type){
- case VIDEO_TYPE_TV:
- g_message("Channel is a TV.");
- break;
- case VIDEO_TYPE_CAMERA:
- g_message("Channel is a camera");
- break;
- default:
- g_warning("unknown video channel type.");
- }
- found=1;
- break; /* find the first channel */
- }
- }
- if (found) g_message("A valid video channel was found.");
- /* select this channel */
- ioctl(f->fd,VIDIOCSCHAN,chan);
-
- /* set/get the resolution */
- err = -1;
- /*
- if (f->cap.type & VID_TYPE_SUBCAPTURE) {
- vcap->x = vcap->y = 0;
- vcap->width = MS_VIDEO_SOURCE(f)->width;
- vcap->height = MS_VIDEO_SOURCE(f)->height;
- err = ioctl(f->fd, VIDIOCSCAPTURE, vcap);
- if (err > -1) {
- f->width = MS_VIDEO_SOURCE(f)->width;
- f->height = MS_VIDEO_SOURCE(f)->height;
- }
- }
- */
- if (err < 0) {
- win->x = win->y = 0;
- win->width = MS_VIDEO_SOURCE(f)->width;
- win->height = MS_VIDEO_SOURCE(f)->height;
- win->clipcount = win->flags = 0;
- win->clips = NULL;
- err=ioctl(f->fd,VIDIOCSWIN,win);
- if (err < 0) {
- g_warning("Could not set video window properties: %s",strerror(errno));
-
- err=ioctl(f->fd,VIDIOCGWIN,win);
- if (err < 0) {
- g_warning("Could not set video window properties: %s",strerror(errno));
- return -1;
- }
- f->width = win->width;
- f->height = win->height;
- }
- else {
- f->width = MS_VIDEO_SOURCE(f)->width;
- f->height = MS_VIDEO_SOURCE(f)->height;
- }
- }
-
- /* get picture properties */
- err=ioctl(f->fd,VIDIOCGPICT,pict);
- if (err<0){
- g_warning("Could not get picture properties: %s",strerror(errno));
- return -1;
- }
- g_message("Picture properties: depth=%i, palette=%i.",pict->depth, pict->palette);
- f->bsize=(pict->depth/8) * f->height * f->width;
-
- /* try to get mmap properties */
- err=ioctl(f->fd,VIDIOCGMBUF,vmbuf);
- if (err<0){
- g_warning("Could not get mmap properties: %s",strerror(errno));
- f->use_mmap=0;
- }else
- {
- if (vmbuf->size>0){
- f->use_mmap=1;
- /* do the mmap */
- f->mmapdbuf=mmap((void*)f,vmbuf->size,PROT_READ,MAP_PRIVATE,f->fd,0);
- if (f->mmapdbuf==(void*)-1) {
- g_warning("Could not mmap. Using read instead.");
- f->use_mmap=0;
- f->mmapdbuf=NULL;
- }else {
- /* initialize the mediastreamer buffers */
- gint i;
- g_message("Using %i-frames mmap'd buffer.",vmbuf->frames);
- for(i=0;i<vmbuf->frames;i++){
- f->img[i].buffer=f->mmapdbuf+vmbuf->offsets[i];
- f->img[i].size=f->bsize;
- f->img[i].ref_count=1;
- }
- f->frame=0;
- }
- } else g_warning("This device cannot support mmap.");
- }
-
- /* initialize the video map structure */
- vmap->width=win->width;
- vmap->height=win->height;
- vmap->format=pict->palette;
- vmap->frame=0;
-
- MS_VIDEO_SOURCE(f)->format=V4L_PALETTE_TO_STRING(pict->palette);
- return 0;
-}
-
-#define BPP 3
-static inline
-void crop( guchar *src, gint s_width, gint s_height, guchar *dest, gint d_width, gint d_height)
-{
- register int i;
- register int stride = d_width*BPP;
- register guchar *s = src, *d = dest;
- s += ((s_height - d_height)/2 * s_width * BPP) + ((s_width - d_width)/2 * BPP);
- for (i = 0; i < d_height; i++, d += stride, s += s_width * BPP)
- memcpy( d, s, stride);
-}
-
-MSBuffer * v4l_grab_image_mmap(MSV4l *obj){
- struct video_mmap *vmap=&obj->vmap;
- struct video_mbuf *vmbuf=&obj->vmbuf;
- int err;
- int syncframe;
- int jitter=vmbuf->frames-1;
- obj->query_frame=(obj->frame) % vmbuf->frames;
- ms_trace("v4l_mmap_process: query_frame=%i",
- obj->query_frame);
- vmap->frame=obj->query_frame;
- err=ioctl(obj->fd,VIDIOCMCAPTURE,vmap);
- if (err<0) {
- g_warning("v4l_mmap_process: error in VIDIOCMCAPTURE: %s.",strerror(errno));
- return NULL;
- }
- syncframe=(obj->frame-jitter);
- obj->frame++;
- if (syncframe>=0){
- syncframe=syncframe%vmbuf->frames;
- err=ioctl(obj->fd,VIDIOCSYNC,&syncframe);
- if (err<0) {
- g_warning("v4l_mmap_process: error in VIDIOCSYNC: %s.",strerror(errno));
- return NULL;
- }
- }else {
- return NULL;
- }
- /* not particularly efficient - hope for a capture source that
- provides subcapture or setting window */
-
- if (obj->width != MS_VIDEO_SOURCE(obj)->width || obj->height != MS_VIDEO_SOURCE(obj)->height){
- guchar tmp[obj->bsize];
- crop((guchar*) obj->img[syncframe].buffer, obj->width, obj->height, tmp,
- MS_VIDEO_SOURCE(obj)->width, MS_VIDEO_SOURCE(obj)->height);
- memcpy(obj->img[syncframe].buffer, tmp, MS_VIDEO_SOURCE(obj)->width *
- MS_VIDEO_SOURCE(obj)->height * obj->pict.depth/8);
- }
- return &obj->img[syncframe];
-}
-
-MSBuffer *v4l_grab_image_read(MSV4l *obj){
- int err;
- if (obj->allocdbuf==NULL){
- obj->allocdbuf=ms_buffer_new(obj->bsize);
- obj->allocdbuf->ref_count++;
- }
- if (obj->width != MS_VIDEO_SOURCE(obj)->width || obj->height != MS_VIDEO_SOURCE(obj)->height)
- {
- guchar tmp[obj->bsize];
- err=read(obj->fd,tmp,obj->bsize);
- if (err>0)
- crop(tmp, obj->width, obj->height, obj->allocdbuf->buffer, MS_VIDEO_SOURCE(obj)->width, MS_VIDEO_SOURCE(obj)->height);
- else {
- g_warning("MSV4l: Fail to read(): %s",strerror(errno));
- return NULL;
- }
- }
- else
- {
- err=read(obj->fd,obj->allocdbuf->buffer,obj->bsize);
- if (err<0){
- g_warning("MSV4l: Fail to read(): %s",strerror(errno));
- return NULL;
- }
- }
- return obj->allocdbuf;
-}
-
-
-MSBuffer * v4l_make_mire(MSV4l *obj){
- gchar *data;
- int i,j,line,pos;
- int patternw=obj->parent.width/6;
- int patternh=obj->parent.height/6;
- int red,green=0,blue=0;
- if (obj->allocdbuf==NULL){
- obj->allocdbuf=ms_buffer_new(obj->parent.width*obj->parent.height*3);
- obj->allocdbuf->ref_count++;
- }
- data=obj->allocdbuf->buffer;
- for (i=0;i<obj->parent.height;++i){
- line=i*obj->parent.width*3;
- if ( ((i+obj->count)/patternh) & 0x1) red=255;
- else red= 0;
- for (j=0;j<obj->parent.width;++j){
- int tmp;
- pos=line+(j*3);
-
- if ( ((j+obj->count)/patternw) & 0x1) blue=255;
- else blue= 0;
-
- data[pos]=red;
- data[pos+1]=green;
- data[pos+2]=blue;
- }
- }
- obj->count++;
- usleep(60000);
- return obj->allocdbuf;
-}
-
-
-void *v4l_thread(MSV4l *obj){
- GMutex *mutex=MS_FILTER(obj)->lock;
- g_mutex_lock(mutex);
- obj->thread_run=TRUE;
- g_cond_signal(obj->cond);
- while(obj->thread_run){
- g_cond_wait(obj->cond,mutex);
- if (obj->grab_image){
- MSBuffer *grabbed;
- g_mutex_unlock(mutex);
- if (obj->fd>0){
- if (obj->use_mmap){
- grabbed=v4l_grab_image_mmap(obj);
- }else{
- grabbed=v4l_grab_image_read(obj);
- }
- }else grabbed=v4l_make_mire(obj);
- g_mutex_lock(mutex);
- if (grabbed){
- obj->image_grabbed=grabbed;
- obj->grab_image=FALSE;
- }
- }
- }
- g_cond_signal(obj->stopcond);
- obj->thread_exited=TRUE;
- g_mutex_unlock(mutex);
- return NULL;
-}
-
-
-
-
-void v4l_process(MSV4l * obj)
-{
- GMutex *mutex=MS_FILTER(obj)->lock;
- g_mutex_lock(mutex);
- if (obj->image_grabbed!=NULL){
- MSMessage *m=ms_message_alloc();
- ms_message_set_buf(m,obj->image_grabbed);
- ms_queue_put(MS_FILTER(obj)->outqueues[0],m);
- obj->image_grabbed=NULL;
- }else{
- obj->grab_image=TRUE;
- g_cond_signal(obj->cond);
- }
- g_mutex_unlock(mutex);
-}
-
-void ms_v4l_uninit(MSV4l *obj)
-{
- if (obj->device!=NULL) {
- g_free(obj->device);
- obj->device=NULL;
- }
- if (obj->v4lthread!=NULL) ms_v4l_stop(obj);
- if (obj->allocdbuf!=NULL) {
- ms_buffer_destroy(obj->allocdbuf);
- obj->allocdbuf=NULL;
- }
- g_cond_free(obj->cond);
- g_cond_free(obj->stopcond);
- ms_filter_uninit(MS_FILTER(obj));
-}
-
-void ms_v4l_destroy(MSV4l *obj)
-{
- ms_v4l_uninit(obj);
- g_free(obj);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.h
deleted file mode 100644
index e19ac9e..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msv4l.h
+++ /dev/null
@@ -1,96 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSV4L_H
-#define MSV4L_H
-
-#include <msvideosource.h>
-#include <sys/types.h>
-#include <linux/videodev.h>
-
-struct _MSV4l
-{
- MSVideoSource parent;
- int fd;
- char *device;
- struct video_capability cap;
- struct video_channel channel;
- struct video_window win;
- struct video_picture pict;
- struct video_mmap vmap;
- struct video_mbuf vmbuf;
- struct video_capture vcap;
- gint bsize;
- gint use_mmap;
- gint frame;
- guint query_frame;
- gchar *mmapdbuf; /* the mmap'd buffer */
- MSBuffer img[VIDEO_MAX_FRAME]; /* the buffer wrappers used for mmaps */
- gint width; /* the capture image size - can be cropped to output size */
- gint height;
- MSBuffer *allocdbuf; /* the buffer allocated for read() and mire */
- gint count;
- MSBuffer *image_grabbed;
- GCond *cond;
- GCond *stopcond;
- GThread *v4lthread;
- gboolean grab_image;
- gboolean thread_run;
- gboolean thread_exited;
-};
-
-typedef struct _MSV4l MSV4l;
-
-
-struct _MSV4lClass
-{
- MSVideoSourceClass parent_class;
-
-};
-
-typedef struct _MSV4lClass MSV4lClass;
-
-
-/* PUBLIC API */
-#define MS_V4L(v) ((MSV4l*)(v))
-#define MS_V4L_CLASS(k) ((MSV4lClass*)(k))
-MSFilter * ms_v4l_new();
-
-void ms_v4l_start(MSV4l *obj);
-void ms_v4l_stop(MSV4l *obj);
-int ms_v4l_set_device(MSV4l *f, const gchar *device);
-gint ms_v4l_get_width(MSV4l *v4l);
-gint ms_v4l_get_height(MSV4l *v4l);
-void ms_v4l_set_size(MSV4l *v4l, gint w, gint h);
-
-/* PRIVATE API */
-void ms_v4l_init(MSV4l *obj);
-void ms_v4l_class_init(MSV4lClass *klass);
-int v4l_configure(MSV4l *f);
-
-void v4l_process(MSV4l *obj);
-
-void ms_v4l_uninit(MSV4l *obj);
-
-void ms_v4l_destroy(MSV4l *obj);
-
-extern MSFilterInfo v4l_info;
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.c b/third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.c
deleted file mode 100644
index b3a9f12..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "msvideosource.h"
-#include "mediastream.h"
-#include "msv4l.h"
-#ifdef HAVE_LIBDC1394
-#include "msdc1394.h"
-#endif
-
-/* register all statically linked codecs */
-void ms_video_source_register_all()
-{
- ms_filter_register(&v4l_info);
-#ifdef HAVE_LIBDC1394
- ms_filter_register(MS_FILTER_INFO(&dc1394_info));
-#endif
-}
-
-void ms_video_source_class_init(MSVideoSourceClass *klass)
-{
- /* init base class first*/
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- /* then init videosource specific things*/
- MS_FILTER_CLASS(klass)->max_qoutputs=MSVIDEOSOURCE_MAX_OUTPUTS;
- ms_filter_class_set_attr(MS_FILTER_CLASS(klass),FILTER_IS_SOURCE|FILTER_HAS_QUEUES);
-}
-
-void ms_video_source_init(MSVideoSource *obj)
-{
- ms_filter_init(MS_FILTER(obj));
- MS_FILTER(obj)->outqueues=obj->outputs;
- obj->width = VIDEO_SIZE_CIF_W;
- obj->height = VIDEO_SIZE_CIF_H;
-}
-
-void ms_video_source_start(MSVideoSource *f)
-{
- MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->start(f);
-}
-
-void ms_video_source_stop(MSVideoSource *f)
-{
- MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->stop(f);
-}
-
-int ms_video_source_set_device(MSVideoSource *f, const gchar *device)
-{
- return MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_device(f,device);
-}
-
-gchar* ms_video_source_get_device_name(MSVideoSource *f)
-{
- return f->dev_name;
-}
-
-void ms_video_source_set_size(MSVideoSource *f, gint width, gint height)
-{
- if (MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_size)
- MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_size(f, width, height);
-}
-
-void ms_video_source_set_frame_rate(MSVideoSource *f, gint frame_rate, gint frame_rate_base)
-{
- if (MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_frame_rate)
- MS_VIDEO_SOURCE_CLASS(MS_FILTER(f)->klass)->set_frame_rate(f, frame_rate, frame_rate_base);
- else{
- f->frame_rate=frame_rate;
- f->frame_rate_base=frame_rate_base;
- }
-}
-
-gchar* ms_video_source_get_format(MSVideoSource *f)
-{
- return f->format;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.h b/third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.h
deleted file mode 100644
index 9a27f83..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/msvideosource.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSVIDEOSOURCE_H
-#define MSVIDEOSOURCE_H
-
-
-#include "msfilter.h"
-
-/* this is the video input abstract class */
-
-#define MSVIDEOSOURCE_MAX_OUTPUTS 1 /* max output per filter*/
-
-typedef struct _MSVideoSource
-{
- /* the MSVideoSource derivates from MSFilter, so the MSFilter object MUST be the first of the MSVideoSource object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSQueue *outputs[MSVIDEOSOURCE_MAX_OUTPUTS];
- gchar *dev_name;
- gint width, height;
- gchar *format;
- gint frame_rate;
- gint frame_rate_base;
-} MSVideoSource;
-
-typedef struct _MSVideoSourceClass
-{
- /* the MSVideoSource derivates from MSFilter, so the MSFilter class MUST be the first of the MSVideoSource class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
- gint (*set_device)(MSVideoSource *s, const gchar *name);
- void (*start)(MSVideoSource *s);
- void (*stop)(MSVideoSource *s);
- void (*set_size)(MSVideoSource *s, gint width, gint height);
- void (*set_frame_rate)(MSVideoSource *s, gint frame_rate, gint frame_rate_base);
-} MSVideoSourceClass;
-
-/* PUBLIC */
-void ms_video_source_register_all();
-int ms_video_source_set_device(MSVideoSource *f, const gchar *device);
-gchar* ms_video_source_get_device_name(MSVideoSource *f);
-void ms_video_source_start(MSVideoSource *f);
-void ms_video_source_stop(MSVideoSource *f);
-void ms_video_source_set_size(MSVideoSource *f, gint width, gint height);
-void ms_video_source_set_frame_rate(MSVideoSource *f, gint frame_rate, gint frame_rate_base);
-gchar* ms_video_source_get_format(MSVideoSource *f);
-
-#define MS_VIDEO_SOURCE(obj) ((MSVideoSource*)(obj))
-#define MS_VIDEO_SOURCE_CLASS(klass) ((MSVideoSourceClass*)(klass))
-
-
-/* FOR INTERNAL USE*/
-void ms_video_source_init(MSVideoSource *f);
-void ms_video_source_class_init(MSVideoSourceClass *klass);
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.c b/third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.c
deleted file mode 100644
index 178e294..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "mswrite.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-
-static MSWriteClass *ms_write_class=NULL;
-
-MSFilter * ms_write_new(char *name)
-{
- MSWrite *r;
- int fd=-1;
-
- r=g_new(MSWrite,1);
- ms_write_init(r);
- if (ms_write_class==NULL)
- {
- ms_write_class=g_new(MSWriteClass,1);
- ms_write_class_init(ms_write_class);
- }
- MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_write_class);
- if ((name!=NULL) && (strlen(name)!=0))
- {
- fd=open(name,O_WRONLY | O_CREAT | O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
- if (fd<0) g_error("ms_write_new: failed to open %s.\n",name);
- }
- r->fd=fd;
- return(MS_FILTER(r));
-}
-
-
-/* FOR INTERNAL USE*/
-void ms_write_init(MSWrite *r)
-{
- ms_filter_init(MS_FILTER(r));
- MS_FILTER(r)->infifos=r->f_inputs;
- MS_FILTER(r)->inqueues=r->q_inputs;
- MS_FILTER(r)->r_mingran=MSWRITE_MIN_GRAN;
- memset(r->f_inputs,0,sizeof(MSFifo*)*MSWRITE_MAX_INPUTS);
- memset(r->q_inputs,0,sizeof(MSQueue*)*MSWRITE_MAX_INPUTS);
- r->fd=-1;
-}
-
-void ms_write_class_init(MSWriteClass *klass)
-{
- ms_filter_class_init(MS_FILTER_CLASS(klass));
- ms_filter_class_set_name(MS_FILTER_CLASS(klass),"dskwriter");
- MS_FILTER_CLASS(klass)->max_finputs=MSWRITE_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->max_qinputs=MSWRITE_MAX_INPUTS;
- MS_FILTER_CLASS(klass)->r_maxgran=MSWRITE_DEF_GRAN;
- MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_write_destroy;
- MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_write_process;
-}
-
-void ms_write_process(MSWrite *r)
-{
- MSFifo *f;
- MSQueue *q;
- MSMessage *buf=NULL;
- int i,j,err1,err2;
- gint gran=ms_filter_get_mingran(MS_FILTER(r));
- void *p;
-
- /* process output fifos*/
- for (i=0,j=0;(i<MS_FILTER(r)->klass->max_finputs)&&(j<MS_FILTER(r)->finputs);i++)
- {
- f=r->f_inputs[i];
- if (f!=NULL)
- {
- if ( (err1=ms_fifo_get_read_ptr(f,gran,&p))>0 )
- {
-
- err2=write(r->fd,p,gran);
- if (err2<0) g_warning("ms_write_process: failed to write: %s.\n",strerror(errno));
- }
- j++;
- }
- }
- /* process output queues*/
- for (i=0,j=0;(i<MS_FILTER(r)->klass->max_qinputs)&&(j<MS_FILTER(r)->qinputs);i++)
- {
- q=r->q_inputs[i];
- if (q!=NULL)
- {
- while ( (buf=ms_queue_get(q))!=NULL ){
- write(r->fd,buf->data,buf->size);
- j++;
- ms_message_destroy(buf);
- }
- }
- }
-}
-
-void ms_write_destroy( MSWrite *obj)
-{
- if (obj->fd!=0) close(obj->fd);
- g_free(obj);
-}
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.h b/third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.h
deleted file mode 100644
index cd766d1..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/mswrite.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef MSWRITE_H
-#define MSWRITE_H
-
-#include "msfilter.h"
-
-
-/*this is the class that implements writing reading sink filter*/
-
-#define MSWRITE_MAX_INPUTS 1 /* max output per filter*/
-
-#define MSWRITE_DEF_GRAN 512 /* the default granularity*/
-#define MSWRITE_MIN_GRAN 64
-
-typedef struct _MSWrite
-{
- /* the MSWrite derivates from MSFilter, so the MSFilter object MUST be the first of the MSWrite object
- in order to the object mechanism to work*/
- MSFilter filter;
- MSFifo *f_inputs[MSWRITE_MAX_INPUTS];
- MSQueue *q_inputs[MSWRITE_MAX_INPUTS];
- gint fd; /* the file descriptor of the file being written*/
-} MSWrite;
-
-typedef struct _MSWriteClass
-{
- /* the MSWrite derivates from MSFilter, so the MSFilter class MUST be the first of the MSWrite class
- in order to the class mechanism to work*/
- MSFilterClass parent_class;
-} MSWriteClass;
-
-/* PUBLIC */
-#define MS_WRITE(filter) ((MSWrite*)(filter))
-#define MS_WRITE_CLASS(klass) ((MSWriteClass*)(klass))
-MSFilter * ms_write_new(char *name);
-
-/* FOR INTERNAL USE*/
-void ms_write_init(MSWrite *r);
-void ms_write_class_init(MSWriteClass *klass);
-void ms_write_destroy( MSWrite *obj);
-void ms_write_process(MSWrite *r);
-
-#endif
-
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/osscard.c b/third_party/libjingle/source/talk/third_party/mediastreamer/osscard.c
deleted file mode 100644
index 636c579..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/osscard.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "osscard.h"
-
-#include "msossread.h"
-#include "msosswrite.h"
-
-#ifdef HAVE_SYS_SOUNDCARD_H
-#include <sys/soundcard.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/time.h>
-
-#if 0
-void * oss_thread(OssCard *obj)
-{
- gint i;
- gint err;
- g_message("oss_thread: starting **********");
- while(1){
- for(i=0;i<OSS_CARD_BUFFERS;i++){
- g_mutex_lock(obj->lock);
- if (obj->ref==0){
- g_cond_signal(obj->cond);
- g_mutex_unlock(obj->lock);
- g_thread_exit(NULL);
- }
- g_mutex_unlock(obj->lock);
- obj->readindex=i;
-
- err=read(obj->fd,obj->readbuf[i],SND_CARD(obj)->bsize);
- if (err<0) g_warning("oss_thread: read() error:%s.",strerror(errno));
- obj->writeindex=i;
- write(obj->fd,obj->writebuf[i],SND_CARD(obj)->bsize);
- memset(obj->writebuf[i],0,SND_CARD(obj)->bsize);
- }
- }
-}
-#endif
-int oss_open(OssCard *obj, int bits,int stereo, int rate)
-{
- int fd;
- int p=0,cond=0;
- int i=0;
- int min_size=0,blocksize=512;
- int err;
-
- //g_message("opening sound device");
- fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
- if (fd<0) return -EWOULDBLOCK;
- /* unset nonblocking mode */
- /* We wanted non blocking open but now put it back to normal ; thanks Xine !*/
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)&~O_NONBLOCK);
-
- /* reset is maybe not needed but takes time*/
- /*ioctl(fd, SNDCTL_DSP_RESET, 0); */
-
-
-#ifdef WORDS_BIGENDIAN
- p=AFMT_U16_BE;
-#else
- p=AFMT_U16_LE;
-#endif
-
- err=ioctl(fd,SNDCTL_DSP_SETFMT,&p);
- if (err<0){
- g_warning("oss_open: can't set sample format:%s.",strerror(errno));
- }
-
-
- p = bits; /* 16 bits */
- err=ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p);
- if (err<0){
- g_warning("oss_open: can't set sample size to %i:%s.",bits,strerror(errno));
- }
-
- p = rate; /* rate in khz*/
- err=ioctl(fd, SNDCTL_DSP_SPEED, &p);
- if (err<0){
- g_warning("oss_open: can't set sample rate to %i:%s.",rate,strerror(errno));
- }
-
- p = stereo; /* stereo or not */
- err=ioctl(fd, SNDCTL_DSP_STEREO, &p);
- if (err<0){
- g_warning("oss_open: can't set mono/stereo mode:%s.",strerror(errno));
- }
-
- if (rate==16000) blocksize=4096; /* oss emulation is not very good at 16khz */
- else blocksize=blocksize*(rate/8000);
- ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
-
- /* try to subdivide BLKSIZE to reach blocksize if necessary */
- if (min_size>blocksize)
- {
- cond=1;
- p=min_size/blocksize;
- while(cond)
- {
- i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p);
- //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno);
- if ((i==0) || (p==1)) cond=0;
- else p=p/2;
- }
- }
- ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
- if (min_size>blocksize)
- {
- g_warning("dsp block size set to %i.",min_size);
- }else{
- /* no need to access the card with less latency than needed*/
- min_size=blocksize;
- }
-
- g_message("dsp blocksize is %i.",min_size);
-
- /* start recording !!! Alex */
- {
- int fl,res;
-
- fl=PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT;
- res=ioctl(fd, SNDCTL_DSP_SETTRIGGER, &fl);
- if (res<0) g_warning("OSS_TRIGGER: %s",strerror(errno));
- }
-
- obj->fd=fd;
- obj->readpos=0;
- obj->writepos=0;
- SND_CARD(obj)->bits=bits;
- SND_CARD(obj)->stereo=stereo;
- SND_CARD(obj)->rate=rate;
- SND_CARD(obj)->bsize=min_size;
- return fd;
-}
-
-int oss_card_probe(OssCard *obj,int bits,int stereo,int rate)
-{
-
- int fd;
- int p=0,cond=0;
- int i=0;
- int min_size=0,blocksize=512;
-
- if (obj->fd>0) return SND_CARD(obj)->bsize;
- fd=open(obj->dev_name,O_RDWR|O_NONBLOCK);
- if (fd<0) {
- g_warning("oss_card_probe: can't open %s: %s.",obj->dev_name,strerror(errno));
- return -1;
- }
- ioctl(fd, SNDCTL_DSP_RESET, 0);
-
- p = bits; /* 16 bits */
- ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &p);
-
- p = stereo; /* number of channels */
- ioctl(fd, SNDCTL_DSP_CHANNELS, &p);
-
- p = rate; /* rate in khz*/
- ioctl(fd, SNDCTL_DSP_SPEED, &p);
-
- ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
-
- /* try to subdivide BLKSIZE to reach blocksize if necessary */
- if (min_size>blocksize)
- {
- cond=1;
- p=min_size/blocksize;
- while(cond)
- {
- i=ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &p);
- //printf("SUB_DIVIDE said error=%i,errno=%i\n",i,errno);
- if ((i==0) || (p==1)) cond=0;
- else p=p/2;
- }
- }
- ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &min_size);
- if (min_size>blocksize)
- {
- g_warning("dsp block size set to %i.",min_size);
- }else{
- /* no need to access the card with less latency than needed*/
- min_size=blocksize;
- }
- close(fd);
- return min_size;
-}
-
-
-int oss_card_open(OssCard *obj,int bits,int stereo,int rate)
-{
- int fd;
- obj->ref++;
- if (obj->fd==0){
- fd=oss_open(obj,bits,stereo,rate);
- if (fd<0) {
- obj->fd=0;
- obj->ref--;
- return -1;
- }
- }
-
- obj->readbuf=g_malloc0(SND_CARD(obj)->bsize);
- obj->writebuf=g_malloc0(SND_CARD(obj)->bsize);
-
- SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
- return 0;
-}
-
-void oss_card_close(OssCard *obj)
-{
- int i;
- obj->ref--;
- if (obj->ref==0) {
- close(obj->fd);
- obj->fd=0;
- SND_CARD(obj)->flags&=~SND_CARD_FLAGS_OPENED;
- g_free(obj->readbuf);
- obj->readbuf=NULL;
- g_free(obj->writebuf);
- obj->writebuf=NULL;
-
- }
-}
-
-void oss_card_destroy(OssCard *obj)
-{
- snd_card_uninit(SND_CARD(obj));
- g_free(obj->dev_name);
- g_free(obj->mixdev_name);
- if (obj->readbuf!=NULL) g_free(obj->readbuf);
- if (obj->writebuf!=NULL) g_free(obj->writebuf);
-}
-
-gboolean oss_card_can_read(OssCard *obj)
-{
- struct timeval tout={0,0};
- int err;
- fd_set fdset;
- if (obj->readpos!=0) return TRUE;
- FD_ZERO(&fdset);
- FD_SET(obj->fd,&fdset);
- err=select(obj->fd+1,&fdset,NULL,NULL,&tout);
- if (err>0) return TRUE;
- else return FALSE;
-}
-
-int oss_card_read(OssCard *obj,char *buf,int size)
-{
- int err;
- gint bsize=SND_CARD(obj)->bsize;
- if (size<bsize){
- gint canread=MIN(bsize-obj->readpos,size);
- if (obj->readpos==0){
- err=read(obj->fd,obj->readbuf,bsize);
- if (err<0) {
- g_warning("oss_card_read: read() failed:%s.",strerror(errno));
- return -1;
- }
- }
-
- memcpy(buf,&obj->readbuf[obj->readpos],canread);
- obj->readpos+=canread;
- if (obj->readpos>=bsize) obj->readpos=0;
- return canread;
- }else{
- err=read(obj->fd,buf,size);
- if (err<0) {
- g_warning("oss_card_read: read-2() failed:%s.",strerror(errno));
- }
- return err;
- }
-
-}
-
-int oss_card_write(OssCard *obj,char *buf,int size)
-{
- int err;
- gint bsize=SND_CARD(obj)->bsize;
-
- if (size<bsize){
- gint canwrite;
- canwrite=MIN(bsize-obj->writepos,size);
- memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
- obj->writepos+=canwrite;
- if (obj->writepos>=bsize){
- err=write(obj->fd,obj->writebuf,bsize);
- obj->writepos=0;
- }
- return canwrite;
- }else{
- return write(obj->fd,buf,bsize);
- }
-}
-
-void oss_card_set_level(OssCard *obj,gint way,gint a)
-{
- int p,mix_fd;
- int osscmd;
- g_return_if_fail(obj->mixdev_name!=NULL);
-#ifdef HAVE_SYS_SOUNDCARD_H
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- osscmd=SOUND_MIXER_VOLUME;
- break;
- case SND_CARD_LEVEL_INPUT:
- osscmd=SOUND_MIXER_IGAIN;
- break;
- case SND_CARD_LEVEL_OUTPUT:
- osscmd=SOUND_MIXER_PCM;
- break;
- default:
- g_warning("oss_card_set_level: unsupported command.");
- return;
- }
- p=(((int)a)<<8 | (int)a);
- mix_fd = open(obj->mixdev_name, O_WRONLY);
- ioctl(mix_fd,MIXER_WRITE(osscmd), &p);
- close(mix_fd);
-#endif
-}
-
-gint oss_card_get_level(OssCard *obj,gint way)
-{
- int p=0,mix_fd;
- int osscmd;
- g_return_if_fail(obj->mixdev_name!=NULL);
-#ifdef HAVE_SYS_SOUNDCARD_H
- switch(way){
- case SND_CARD_LEVEL_GENERAL:
- osscmd=SOUND_MIXER_VOLUME;
- break;
- case SND_CARD_LEVEL_INPUT:
- osscmd=SOUND_MIXER_IGAIN;
- break;
- case SND_CARD_LEVEL_OUTPUT:
- osscmd=SOUND_MIXER_PCM;
- break;
- default:
- g_warning("oss_card_get_level: unsupported command.");
- return -1;
- }
- mix_fd = open(obj->mixdev_name, O_RDONLY);
- ioctl(mix_fd,MIXER_READ(SOUND_MIXER_VOLUME), &p);
- close(mix_fd);
-#endif
- return p>>8;
-}
-
-void oss_card_set_source(OssCard *obj,int source)
-{
- gint p=0;
- gint mix_fd;
- g_return_if_fail(obj->mixdev_name!=NULL);
-#ifdef HAVE_SYS_SOUNDCARD_H
- if (source == 'c')
- p = 1 << SOUND_MIXER_CD;
- if (source == 'l')
- p = 1 << SOUND_MIXER_LINE;
- if (source == 'm')
- p = 1 << SOUND_MIXER_MIC;
-
-
- mix_fd = open(obj->mixdev_name, O_WRONLY);
- ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &p);
- close(mix_fd);
-#endif
-}
-
-MSFilter *oss_card_create_read_filter(OssCard *card)
-{
- MSFilter *f=ms_oss_read_new();
- ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
- return f;
-}
-
-MSFilter *oss_card_create_write_filter(OssCard *card)
-{
- MSFilter *f=ms_oss_write_new();
- ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
- return f;
-}
-
-
-SndCard * oss_card_new(char *devname, char *mixdev_name)
-{
- OssCard * obj= g_new0(OssCard,1);
- SndCard *base= SND_CARD(obj);
- snd_card_init(base);
- obj->dev_name=g_strdup(devname);
- obj->mixdev_name=g_strdup( mixdev_name);
-#ifdef HAVE_GLIB
- base->card_name=g_strdup_printf("%s (Open Sound System)",devname);
-#else
- base->card_name=malloc(100);
- snprintf(base->card_name, 100, "%s (Open Sound System)",devname);
-#endif
- base->_probe=(SndCardOpenFunc)oss_card_probe;
- base->_open_r=(SndCardOpenFunc)oss_card_open;
- base->_open_w=(SndCardOpenFunc)oss_card_open;
- base->_can_read=(SndCardPollFunc)oss_card_can_read;
- base->_read=(SndCardIOFunc)oss_card_read;
- base->_write=(SndCardIOFunc)oss_card_write;
- base->_close_r=(SndCardCloseFunc)oss_card_close;
- base->_close_w=(SndCardCloseFunc)oss_card_close;
- base->_set_rec_source=(SndCardMixerSetRecSourceFunc)oss_card_set_source;
- base->_set_level=(SndCardMixerSetLevelFunc)oss_card_set_level;
- base->_get_level=(SndCardMixerGetLevelFunc)oss_card_get_level;
- base->_destroy=(SndCardDestroyFunc)oss_card_destroy;
- base->_create_read_filter=(SndCardCreateFilterFunc)oss_card_create_read_filter;
- base->_create_write_filter=(SndCardCreateFilterFunc)oss_card_create_write_filter;
- return base;
-}
-
-#define DSP_NAME "/dev/dsp"
-#define MIXER_NAME "/dev/mixer"
-
-gint oss_card_manager_init(SndCardManager *manager, gint tabindex)
-{
- gchar *devname;
- gchar *mixername;
- gint devindex=0;
- gint found=0;
-
- /* search for /dev/dsp and /dev/mixer */
-#ifdef HAVE_GLIB
- if (g_file_test(DSP_NAME,G_FILE_TEST_EXISTS)){
- tabindex++;
- devindex++;
- manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME);
- manager->cards[0]->index=0;
- found++;
- g_message("Found /dev/dsp.");
- }
- for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
- devname=g_strdup_printf("%s%i",DSP_NAME,devindex);
- mixername=g_strdup_printf("%s%i",MIXER_NAME,devindex);
- if (g_file_test(devname,G_FILE_TEST_EXISTS)){
- manager->cards[tabindex]=oss_card_new(devname,mixername);
- manager->cards[tabindex]->index=tabindex;
- tabindex++;
- found++;
- }
- g_free(devname);
- g_free(mixername);
- }
-#else
- if (access(DSP_NAME,F_OK)==0){
- tabindex++;
- devindex++;
- manager->cards[0]=oss_card_new(DSP_NAME,MIXER_NAME);
- manager->cards[0]->index=0;
- found++;
- g_message("Found /dev/dsp.");
- }
- for (;tabindex<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
- devname=malloc(100);
- snprintf(devname, 100, "%s%i",DSP_NAME,devindex);
- mixername=malloc(100);
- snprintf(mixername, 100, "%s%i",MIXER_NAME,devindex);
-
- if (access(devname,F_OK)==0){
- manager->cards[tabindex]=oss_card_new(devname,mixername);
- manager->cards[tabindex]->index=tabindex;
- tabindex++;
- found++;
- }
- g_free(devname);
- g_free(mixername);
- }
-#endif
- if (tabindex==0) g_warning("No sound cards found !");
- return found;
-}
-
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/osscard.h b/third_party/libjingle/source/talk/third_party/mediastreamer/osscard.h
deleted file mode 100644
index 30b96c2..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/osscard.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-/* An implementation of SndCard : the OssCard */
-
-#ifndef OSS_CARD_H
-#define OSS_CARD_H
-
-#include "sndcard.h"
-
-#define OSS_CARD_BUFFERS 3
-struct _OssCard
-{
- SndCard parent;
- gchar *dev_name; /* /dev/dsp0 for example */
- gchar *mixdev_name; /* /dev/mixer0 for example */
- gint fd; /* the file descriptor of the open soundcard, 0 if not open*/
- gint ref;
- gchar *readbuf;
- gint readpos;
- gchar *writebuf;
- gint writepos;
-};
-
-typedef struct _OssCard OssCard;
-
-SndCard * oss_card_new(char *devname, char *mixdev_name);
-
-typedef OssCard HpuxSndCard;
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/recvrtp.c b/third_party/libjingle/source/talk/third_party/mediastreamer/recvrtp.c
deleted file mode 100644
index eaad77f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/recvrtp.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "msrtprecv.h"
-#include "ms.h"
-#include "mswrite.h"
-#include "msosswrite.h"
-#include "msMUlawdec.h"
-#include "mstimer.h"
-#include "msfdispatcher.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void usage(){
- printf(
- "\nUsage: \ntest_rtprecv <output_file> <address> <port>\n"
- "<output_file> is a file to log the flow\n"
- "<address> is a local ip address to listen\n"
- "<port> is a local udp port to listen\n"
- );
-
-}
-
-void stop_handler(int signum){
- cond=0;
-}
-
-int main(int argc, char *argv[]){
- MSFilter *play,*dec,*rec;
- MSSync *timer;
- RtpSession *rtps;
- int port;
-
- if (argc < 4){
- usage();
- exit(0);
- }
- port = atoi(argv[3]);
-
- printf("#################################\n"
- "Test Program\n"
- "Receiving RTP flow with oRTP\n"
- "#################################\n"
- );
- /*create the rtp session */
- ortp_init();
- ortp_set_debug_file("oRTP",NULL);
- rtps=rtp_session_new(RTP_SESSION_RECVONLY);
- rtp_session_set_local_addr(rtps,argv[2],port);
- rtp_session_set_scheduling_mode(rtps,0);
- rtp_session_set_blocking_mode(rtps,0);
-
- printf(
- "##########################################################################\n"
- "Inicialized to listen to the %s (local address) in the port %d\n"
- "##########################################################################\n", argv[2], port);
- ms_init();
- signal(SIGINT,stop_handler);
-
- play=ms_rtp_recv_new();
- rec=ms_oss_write_new();
- ms_sound_write_set_device(MS_SOUND_WRITE(rec),0);
- dec=ms_MULAWdecoder_new();
- timer=ms_timer_new();
-
- ms_rtp_recv_set_session(MS_RTP_RECV(play),rtps);
-
- ms_filter_add_link(play,dec);
- ms_filter_add_link(dec,rec);
- ms_sync_attach(timer,play);
- printf(
- "############\n"
- "gran=%i\n"
- "############\n",MS_SYNC(timer)->samples_per_tick);
-
- ms_start(timer);
- ms_sound_write_start(MS_SOUND_WRITE(rec));
- while(cond)
- {
- sleep(1);
- }
-
- printf(
- "#################################\n"
- "stoping sync...\n"
- "#################################\n");
- ms_stop(timer);
- ms_sound_write_stop(MS_SOUND_WRITE(rec));
- printf(
- "#################################\n"
- "unlinking filters...\n"
- "#################################\n");
- ms_filter_remove_links(play,dec);
- ms_filter_remove_links(dec,rec);
- printf( "#################################\n"
- "destroying filters...\n"
- "#################################\n");
- ms_filter_destroy(play);
- ms_filter_destroy(dec);
- ms_filter_destroy(rec);
-
- rtp_session_destroy(rtps);
- ms_sync_destroy(timer);
- ortp_global_stats_display();
-
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/ring_test.c b/third_party/libjingle/source/talk/third_party/mediastreamer/ring_test.c
deleted file mode 100644
index 46afcfb..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/ring_test.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "ms.h"
-
-#include "msringplayer.h"
-#include "msosswrite.h"
-#include "msossread.h"
-#include "mscopy.h"
-#include "mstimer.h"
-#include <unistd.h>
-
-
-#define READFILE "../share/ring.wav"
-#define WRITEFILE "/tmp/mediaout"
-
-int main()
-{
- MSFilter *play,*copy,*rec;
- MSSync *timer;
- int i=0;
- SndCard *card;
- ms_init();
-
- card=snd_card_manager_get_card(snd_card_manager,1);
- play=ms_ring_player_new(READFILE,2);
- //play=ms_oss_read_new(0);
- rec=snd_card_create_write_filter(card);
- copy=ms_copy_new();
- timer=ms_timer_new();
-
- ms_filter_add_link(play,copy);
- ms_filter_add_link(copy,rec);
- ms_sync_attach(timer,play);
-
- ms_start(timer);
-
- while(1)
- {
- ms_sound_write_set_level(MS_SOUND_WRITE(rec),i);
- i+=10;
- sleep(2);
- if (i>100) i=0;
- }
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/rtpspeex.c b/third_party/libjingle/source/talk/third_party/mediastreamer/rtpspeex.c
deleted file mode 100644
index 4ae057d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/rtpspeex.c
+++ /dev/null
@@ -1,38 +0,0 @@
-
-#include "mediastream.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond--;
- if (cond<0) exit(-1);
-}
-
-int main(int argc, char * argv[])
-{
- AudioStream *audio;
-
- ortp_init();
- rtp_profile_set_payload(&av_profile, 110, &speex_wb);
- rtp_profile_set_payload(&av_profile,102,&payload_type_ilbc);
-
- ms_init();
- ms_speex_codec_init();
- ms_ilbc_codec_init();
-
- signal(SIGINT, stop_handler);
-
- audio = audio_stream_start(&av_profile, 2000, "127.0.0.1", 2000, 110, 250);
-
- for (;;) sleep(1);
-
- audio_stream_stop(audio);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/sendrtp.c b/third_party/libjingle/source/talk/third_party/mediastreamer/sendrtp.c
deleted file mode 100644
index 924b549..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/sendrtp.c
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "msrtpsend.h"
-#include "ms.h"
-#include "msread.h"
-#include "msossread.h"
-#include "msMUlawenc.h"
-#include "mstimer.h"
-#include "msfdispatcher.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void usage(){
- printf(
- "\nUsage: \ntest_rtpsend <output_file> <address> <port>\n"
- "<output_file> is a file to log the flow\n"
- "<address> is a remote ip address to listen\n"
- "<port> is a remote udp port to listen\n"
- );
-
-}
-
-void stop_handler(int signum){
- cond=0;
-}
-
-int main(int argc, char *argv[]){
- MSFilter *sender,*enc,*mic;
- MSSync *timer;
- RtpSession *rtps;
- int port;
-
- if (argc < 4){
- usage();
- exit(0);
- }
- port = atoi(argv[3]);
-
- printf("#################################\n"
- "Test Program\n"
- "Sending RTP flow with oRTP\n"
- "#################################\n"
- );
- /*create the rtp session */
- ortp_init();
- ortp_set_debug_file("oRTP",NULL);
- rtps=rtp_session_new(RTP_SESSION_SENDONLY);
- rtp_session_set_remote_addr(rtps,argv[2],port);
- rtp_session_set_scheduling_mode(rtps,0);
- rtp_session_set_blocking_mode(rtps,0);
-
- printf(
- "##########################################################################\n"
- "Inicialized to write on the %s (remote address) in the port %d\n"
- "##########################################################################\n", argv[2], port);
- ms_init();
- signal(SIGINT,stop_handler);
-
- sender=(MSFilter*)ms_rtp_send_new();
- mic=(MSFilter*)ms_oss_read_new();
- ms_sound_read_set_device(MS_SOUND_READ(mic),0);
- enc=(MSFilter*)ms_MULAWencoder_new();
-
- timer=ms_timer_new();
-
- ms_rtp_send_set_session(MS_RTP_SEND(sender),rtps);
-
- ms_filter_add_link(mic,enc);
- ms_filter_add_link(enc,sender);
- ms_sync_attach(timer,mic);
- printf(
- "############\n"
- "gran=%i\n"
- "############\n",MS_SYNC(timer)->samples_per_tick);
-
- ms_start(timer);
- ms_sound_read_start(MS_SOUND_READ(mic));
- while(cond)
- {
- sleep(1);
- }
-
- printf(
- "#################################\n"
- "stoping sync...\n"
- "#################################\n");
- ms_stop(timer);
- ms_sound_read_stop(MS_SOUND_READ(mic));
- printf(
- "#################################\n"
- "unlinking filters...\n"
- "#################################\n");
- ms_filter_remove_links(enc,sender);
- ms_filter_remove_links(mic,enc);
- printf( "#################################\n"
- "destroying filters...\n"
- "#################################\n");
- ms_filter_destroy(sender);
- ms_filter_destroy(enc);
- ms_filter_destroy(mic);
-
- rtp_session_destroy(rtps);
- ms_sync_destroy(timer);
- ortp_global_stats_display();
-
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.c b/third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.c
deleted file mode 100644
index ada3e6d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "sndcard.h"
-#include "msfilter.h"
-
-void snd_card_init(SndCard *obj)
-{
- memset(obj,0,sizeof(SndCard));
-}
-
-void snd_card_uninit(SndCard *obj)
-{
- if (obj->card_name!=NULL) g_free(obj->card_name);
-}
-
-const gchar *snd_card_get_identifier(SndCard *obj)
-{
- return obj->card_name;
-}
-
-int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate)
-{
- g_return_val_if_fail(obj->_open_r!=NULL,-1);
- g_message("Opening sound card [%s] in capture mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits);
- return obj->_open_r(obj,bits,stereo,rate);
-}
-int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate)
-{
- g_return_val_if_fail(obj->_open_w!=NULL,-1);
- g_message("Opening sound card [%s] in playback mode with stereo=%i,rate=%i,bits=%i",obj->card_name,stereo,rate,bits);
- return obj->_open_w(obj,bits,stereo,rate);
-}
-
-gboolean snd_card_can_read(SndCard *obj){
- g_return_val_if_fail(obj->_can_read!=NULL,-1);
- return obj->_can_read(obj);
-}
-
-void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno){
- g_return_if_fail(obj->_set_blocking_mode!=NULL);
- obj->_set_blocking_mode(obj,yesno);
-}
-
-int snd_card_read(SndCard *obj,char *buffer,int size)
-{
- g_return_val_if_fail(obj->_read!=NULL,-1);
- return obj->_read(obj,buffer,size);
-}
-int snd_card_write(SndCard *obj,char *buffer,int size)
-{
- g_return_val_if_fail(obj->_write!=NULL,-1);
- return obj->_write(obj,buffer,size);
-}
-
-int snd_card_get_bsize(SndCard *obj)
-{
- if (obj->flags & SND_CARD_FLAGS_OPENED){
- return obj->bsize;
- }
- return -1;
-}
-
-void snd_card_close_r(SndCard *obj)
-{
- g_return_if_fail(obj->_close_r!=NULL);
- g_message("Closing reading channel of soundcard.");
- obj->_close_r(obj);
-}
-
-void snd_card_close_w(SndCard *obj)
-{
- g_return_if_fail(obj->_close_w!=NULL);
- g_message("Closing writing channel of soundcard.");
- obj->_close_w(obj);
-}
-
-gint snd_card_probe(SndCard *obj,int bits, int stereo, int rate)
-{
- g_return_val_if_fail(obj->_probe!=NULL,-1);
- return obj->_probe(obj,bits,stereo,rate);
-}
-
-void snd_card_set_rec_source(SndCard *obj, int source)
-{
- g_return_if_fail(obj->_set_rec_source!=NULL);
- obj->_set_rec_source(obj,source);
-}
-
-void snd_card_set_level(SndCard *obj, int way, int level)
-{
- g_return_if_fail(obj->_set_level!=NULL);
- obj->_set_level(obj,way,level);
-}
-
-gint snd_card_get_level(SndCard *obj,int way)
-{
- g_return_val_if_fail(obj->_get_level!=NULL,-1);
- return obj->_get_level(obj,way);
-}
-
-
-MSFilter * snd_card_create_read_filter(SndCard *obj)
-{
- g_return_val_if_fail(obj->_create_read_filter!=NULL,NULL);
- return obj->_create_read_filter(obj);
-}
-MSFilter * snd_card_create_write_filter(SndCard *obj)
-{
- g_return_val_if_fail(obj->_create_write_filter!=NULL,NULL);
- return obj->_create_write_filter(obj);
-}
-
-
-#ifdef HAVE_SYS_AUDIO_H
-gint sys_audio_manager_init(SndCardManager *manager, gint index)
-{
- /* this is a quick shortcut, as multiple soundcards on HPUX does not happen
- very often... */
- manager->cards[index]=hpux_snd_card_new("/dev/audio","/dev/audio");
- return 1;
-}
-
-#endif
-
-#include "osscard.h"
-#include "alsacard.h"
-#include "jackcard.h"
-
-void snd_card_manager_init(SndCardManager *manager)
-{
- gint index=0;
- gint tmp=0;
- memset(manager,0,sizeof(SndCardManager));
- #ifdef HAVE_SYS_SOUNDCARD_H
- tmp=oss_card_manager_init(manager,index);
- index+=tmp;
- if (index>=MAX_SND_CARDS) return;
- #endif
- #ifdef __ALSA_ENABLED__
- tmp=alsa_card_manager_init(manager,index);
- index+=tmp;
- if (index>=MAX_SND_CARDS) return;
- #endif
- #ifdef __JACK_ENABLED__
- tmp=jack_card_manager_init(manager,index);
- index+=tmp;
- if (index>=MAX_SND_CARDS) return;
- #endif
- #ifdef HAVE_SYS_AUDIO_H
- tmp=sys_audio_manager_init(manager,index);
- index+=tmp;
- #endif
-}
-
-
-
-
-
-SndCard * snd_card_manager_get_card(SndCardManager *manager,int index)
-{
- g_return_val_if_fail(index>=0,NULL);
- g_return_val_if_fail(index<MAX_SND_CARDS,NULL);
- if (index>MAX_SND_CARDS) return NULL;
- return manager->cards[index];
-}
-
-SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index)
-{
- int i;
- for (i=0;i<MAX_SND_CARDS;i++){
- gchar *card_name;
- if (manager->cards[i]==NULL) continue;
- card_name=manager->cards[i]->card_name;
- if (card_name==NULL) continue;
- if (strcmp(card_name,cardname)==0){
- *index=i;
- return manager->cards[i];
- }
- }
- g_warning("No card %s found.",cardname);
- return NULL;
-}
-
-SndCardManager _snd_card_manager;
-SndCardManager *snd_card_manager=&_snd_card_manager;
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.h b/third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.h
deleted file mode 100644
index d84757f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/sndcard.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-
-#ifndef SNDCARD_H
-#define SNDCARD_H
-
-#undef PACKAGE
-#undef VERSION
-#include <config.h>
-#undef PACKAGE
-#undef VERSION
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#else
-#include <uglib.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* the base class for all soundcards: SndCard */
-struct _SndCard;
-
-typedef int (*SndCardOpenFunc)(struct _SndCard*,int, int, int);
-typedef void (*SndCardSetBlockingModeFunc)(struct _SndCard*, gboolean );
-typedef void (*SndCardCloseFunc)(struct _SndCard*);
-typedef gint (*SndCardIOFunc)(struct _SndCard*,char *,int);
-typedef void (*SndCardDestroyFunc)(struct _SndCard*);
-typedef gboolean (*SndCardPollFunc)(struct _SndCard*);
-typedef gint (*SndCardMixerGetLevelFunc)(struct _SndCard*,gint);
-typedef void (*SndCardMixerSetRecSourceFunc)(struct _SndCard*,gint);
-typedef void (*SndCardMixerSetLevelFunc)(struct _SndCard*,gint ,gint);
-typedef struct _MSFilter * (*SndCardCreateFilterFunc)(struct _SndCard *);
-
-struct _SndCard
-{
- gchar *card_name; /* SB16 PCI for example */
- gint index;
- gint bsize;
- gint rate;
- gint stereo;
- gint bits;
- gint flags;
-#define SND_CARD_FLAGS_OPENED 1
- SndCardOpenFunc _probe;
- SndCardOpenFunc _open_r;
- SndCardOpenFunc _open_w;
- SndCardSetBlockingModeFunc _set_blocking_mode;
- SndCardPollFunc _can_read;
- SndCardIOFunc _read;
- SndCardIOFunc _write;
- SndCardCloseFunc _close_r;
- SndCardCloseFunc _close_w;
- SndCardMixerGetLevelFunc _get_level;
- SndCardMixerSetLevelFunc _set_level;
- SndCardMixerSetRecSourceFunc _set_rec_source;
- SndCardCreateFilterFunc _create_read_filter;
- SndCardCreateFilterFunc _create_write_filter;
- SndCardDestroyFunc _destroy;
-};
-
-
-typedef struct _SndCard SndCard;
-
-void snd_card_init(SndCard *obj);
-void snd_card_uninit(SndCard *obj);
-gint snd_card_probe(SndCard *obj, int bits, int stereo, int rate);
-int snd_card_open_r(SndCard *obj, int bits, int stereo, int rate);
-int snd_card_open_w(SndCard *obj, int bits, int stereo, int rate);
-int snd_card_get_bsize(SndCard *obj);
-gboolean snd_card_can_read(SndCard *obj);
-int snd_card_read(SndCard *obj,char *buffer,int size);
-int snd_card_write(SndCard *obj,char *buffer,int size);
-void snd_card_set_blocking_mode(SndCard *obj,gboolean yesno);
-void snd_card_close_r(SndCard *obj);
-void snd_card_close_w(SndCard *obj);
-
-void snd_card_set_rec_source(SndCard *obj, int source); /* source='l' or 'm'*/
-void snd_card_set_level(SndCard *obj, int way, int level);
-gint snd_card_get_level(SndCard *obj,int way);
-
-const gchar *snd_card_get_identifier(SndCard *obj);
-
-struct _MSFilter * snd_card_create_read_filter(SndCard *sndcard);
-struct _MSFilter * snd_card_create_write_filter(SndCard *sndcard);
-
-
-#define SND_CARD_LEVEL_GENERAL 1
-#define SND_CARD_LEVEL_INPUT 2
-#define SND_CARD_LEVEL_OUTPUT 3
-
-
-int snd_card_destroy(SndCard *obj);
-
-#define SND_CARD(obj) ((SndCard*)(obj))
-
-
-
-
-/* SndCardManager */
-
-#define MAX_SND_CARDS 20
-
-
-struct _SndCardManager
-{
- SndCard *cards[MAX_SND_CARDS];
-};
-
-typedef struct _SndCardManager SndCardManager;
-
-void snd_card_manager_init(SndCardManager *manager);
-SndCard * snd_card_manager_get_card(SndCardManager *manager,int index);
-SndCard * snd_card_manager_get_card_with_string(SndCardManager *manager,const char *cardname,int *index);
-
-extern SndCardManager *snd_card_manager;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test.c
deleted file mode 100644
index a24c3f4..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "ms.h"
-
-#include "msringplayer.h"
-#include "msosswrite.h"
-#include "msossread.h"
-#include "mscopy.h"
-#include "mstimer.h"
-#include <unistd.h>
-#include <signal.h>
-
-#define READFILE "../share/rings/orig.wav"
-#define WRITEFILE "/tmp/mediaout"
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond=0;
-}
-
-
-int main(int argc, char *argv[])
-{
- MSFilter *play,*copy,*rec;
- MSSync *timer;
- int i=0;
- int tmp;
- char *ring;
-
- ms_init();
-
- if (argc>1){
- ring=argv[1];
- }else ring= READFILE;
-
- play=ms_ring_player_new(ring,2);
- //play=ms_oss_read_new(0);
- rec=snd_card_create_write_filter(snd_card_manager_get_card(snd_card_manager,1));
- copy=ms_copy_new();
-
- ms_filter_get_property(play,MS_FILTER_PROPERTY_FREQ,&tmp);
- g_message("Playing at rate %i.",tmp);
- ms_filter_set_property(rec,MS_FILTER_PROPERTY_FREQ,&tmp);
- ms_filter_get_property(play,MS_FILTER_PROPERTY_CHANNELS,&tmp);
- g_message("Playing with %i channels",tmp);
- ms_filter_set_property(rec,MS_FILTER_PROPERTY_CHANNELS,&tmp);
-
- timer=ms_timer_new();
- ms_sync_start(timer);
-
- ms_filter_add_link(play,copy);
- ms_filter_add_link(copy,rec);
- ms_sync_attach(timer,play);
-
-
- while(cond)
- {
- sleep(1);
- }
- ms_sync_detach(timer,play);
- ms_sync_stop(timer);
- ms_sync_destroy(timer);
-
- ms_filter_remove_links(play,copy);
- ms_filter_remove_links(copy,rec);
- ms_filter_destroy(play);
- ms_filter_destroy(copy);
- ms_filter_destroy(rec);
-
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_alaw.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_alaw.c
deleted file mode 100644
index 243ceca..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_alaw.c
+++ /dev/null
@@ -1,90 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "ms.h"
-
-#include "msosswrite.h"
-#include "msossread.h"
-#include "mscopy.h"
-#include "mstimer.h"
-#include "msAlawdec.h"
-#include "msAlawenc.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond=0;
-}
-
-int main()
-{
- MSFilter *play,*enc,*dec,*rec;
- MSSync *timer;
-
- ms_init();
- signal(SIGINT,stop_handler);
-
- play=ms_oss_read_new();
- rec=ms_oss_write_new();
-
- ms_sound_read_set_device(MS_SOUND_READ(play),0);
- ms_sound_write_set_device(MS_SOUND_WRITE(rec),0);
-
- enc=ms_ALAWencoder_new();
- dec=ms_ALAWdecoder_new();
- timer=ms_timer_new();
-
- ms_filter_add_link(play,enc);
- ms_filter_add_link(enc,dec);
- ms_filter_add_link(dec,rec);
- ms_sync_attach(timer,play);
-
- ms_start(timer);
-
- ms_sound_read_start(MS_SOUND_READ(play));
- ms_sound_write_start(MS_SOUND_WRITE(rec));
- while(cond)
- {
- sleep(1);
- }
-
- ms_sound_read_stop(MS_SOUND_READ(play));
- ms_sound_write_stop(MS_SOUND_WRITE(rec));
-
- printf("stoping sync...\n");
- ms_stop(timer);
- printf("unlinking filters...\n");
- ms_filter_remove_links(play,enc);
- ms_filter_remove_links(enc,dec);
- ms_filter_remove_links(dec,rec);
- printf("destroying filters...\n");
- ms_filter_destroy(play);
- ms_filter_destroy(enc);
- ms_filter_destroy(dec);
- ms_filter_destroy(rec);
- ms_sync_destroy(timer);
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_gsm.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_gsm.c
deleted file mode 100644
index 924b549..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_gsm.c
+++ /dev/null
@@ -1,110 +0,0 @@
-#include "msrtpsend.h"
-#include "ms.h"
-#include "msread.h"
-#include "msossread.h"
-#include "msMUlawenc.h"
-#include "mstimer.h"
-#include "msfdispatcher.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void usage(){
- printf(
- "\nUsage: \ntest_rtpsend <output_file> <address> <port>\n"
- "<output_file> is a file to log the flow\n"
- "<address> is a remote ip address to listen\n"
- "<port> is a remote udp port to listen\n"
- );
-
-}
-
-void stop_handler(int signum){
- cond=0;
-}
-
-int main(int argc, char *argv[]){
- MSFilter *sender,*enc,*mic;
- MSSync *timer;
- RtpSession *rtps;
- int port;
-
- if (argc < 4){
- usage();
- exit(0);
- }
- port = atoi(argv[3]);
-
- printf("#################################\n"
- "Test Program\n"
- "Sending RTP flow with oRTP\n"
- "#################################\n"
- );
- /*create the rtp session */
- ortp_init();
- ortp_set_debug_file("oRTP",NULL);
- rtps=rtp_session_new(RTP_SESSION_SENDONLY);
- rtp_session_set_remote_addr(rtps,argv[2],port);
- rtp_session_set_scheduling_mode(rtps,0);
- rtp_session_set_blocking_mode(rtps,0);
-
- printf(
- "##########################################################################\n"
- "Inicialized to write on the %s (remote address) in the port %d\n"
- "##########################################################################\n", argv[2], port);
- ms_init();
- signal(SIGINT,stop_handler);
-
- sender=(MSFilter*)ms_rtp_send_new();
- mic=(MSFilter*)ms_oss_read_new();
- ms_sound_read_set_device(MS_SOUND_READ(mic),0);
- enc=(MSFilter*)ms_MULAWencoder_new();
-
- timer=ms_timer_new();
-
- ms_rtp_send_set_session(MS_RTP_SEND(sender),rtps);
-
- ms_filter_add_link(mic,enc);
- ms_filter_add_link(enc,sender);
- ms_sync_attach(timer,mic);
- printf(
- "############\n"
- "gran=%i\n"
- "############\n",MS_SYNC(timer)->samples_per_tick);
-
- ms_start(timer);
- ms_sound_read_start(MS_SOUND_READ(mic));
- while(cond)
- {
- sleep(1);
- }
-
- printf(
- "#################################\n"
- "stoping sync...\n"
- "#################################\n");
- ms_stop(timer);
- ms_sound_read_stop(MS_SOUND_READ(mic));
- printf(
- "#################################\n"
- "unlinking filters...\n"
- "#################################\n");
- ms_filter_remove_links(enc,sender);
- ms_filter_remove_links(mic,enc);
- printf( "#################################\n"
- "destroying filters...\n"
- "#################################\n");
- ms_filter_destroy(sender);
- ms_filter_destroy(enc);
- ms_filter_destroy(mic);
-
- rtp_session_destroy(rtps);
- ms_sync_destroy(timer);
- ortp_global_stats_display();
-
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_lpc10.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_lpc10.c
deleted file mode 100644
index eaad77f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_lpc10.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "msrtprecv.h"
-#include "ms.h"
-#include "mswrite.h"
-#include "msosswrite.h"
-#include "msMUlawdec.h"
-#include "mstimer.h"
-#include "msfdispatcher.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void usage(){
- printf(
- "\nUsage: \ntest_rtprecv <output_file> <address> <port>\n"
- "<output_file> is a file to log the flow\n"
- "<address> is a local ip address to listen\n"
- "<port> is a local udp port to listen\n"
- );
-
-}
-
-void stop_handler(int signum){
- cond=0;
-}
-
-int main(int argc, char *argv[]){
- MSFilter *play,*dec,*rec;
- MSSync *timer;
- RtpSession *rtps;
- int port;
-
- if (argc < 4){
- usage();
- exit(0);
- }
- port = atoi(argv[3]);
-
- printf("#################################\n"
- "Test Program\n"
- "Receiving RTP flow with oRTP\n"
- "#################################\n"
- );
- /*create the rtp session */
- ortp_init();
- ortp_set_debug_file("oRTP",NULL);
- rtps=rtp_session_new(RTP_SESSION_RECVONLY);
- rtp_session_set_local_addr(rtps,argv[2],port);
- rtp_session_set_scheduling_mode(rtps,0);
- rtp_session_set_blocking_mode(rtps,0);
-
- printf(
- "##########################################################################\n"
- "Inicialized to listen to the %s (local address) in the port %d\n"
- "##########################################################################\n", argv[2], port);
- ms_init();
- signal(SIGINT,stop_handler);
-
- play=ms_rtp_recv_new();
- rec=ms_oss_write_new();
- ms_sound_write_set_device(MS_SOUND_WRITE(rec),0);
- dec=ms_MULAWdecoder_new();
- timer=ms_timer_new();
-
- ms_rtp_recv_set_session(MS_RTP_RECV(play),rtps);
-
- ms_filter_add_link(play,dec);
- ms_filter_add_link(dec,rec);
- ms_sync_attach(timer,play);
- printf(
- "############\n"
- "gran=%i\n"
- "############\n",MS_SYNC(timer)->samples_per_tick);
-
- ms_start(timer);
- ms_sound_write_start(MS_SOUND_WRITE(rec));
- while(cond)
- {
- sleep(1);
- }
-
- printf(
- "#################################\n"
- "stoping sync...\n"
- "#################################\n");
- ms_stop(timer);
- ms_sound_write_stop(MS_SOUND_WRITE(rec));
- printf(
- "#################################\n"
- "unlinking filters...\n"
- "#################################\n");
- ms_filter_remove_links(play,dec);
- ms_filter_remove_links(dec,rec);
- printf( "#################################\n"
- "destroying filters...\n"
- "#################################\n");
- ms_filter_destroy(play);
- ms_filter_destroy(dec);
- ms_filter_destroy(rec);
-
- rtp_session_destroy(rtps);
- ms_sync_destroy(timer);
- ortp_global_stats_display();
-
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_mulaw.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_mulaw.c
deleted file mode 100644
index 9962e86..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_mulaw.c
+++ /dev/null
@@ -1,87 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "ms.h"
-
-#include "msosswrite.h"
-#include "msossread.h"
-#include "mscopy.h"
-#include "msnosync.h"
-#include "mstimer.h"
-#include "msMUlawdec.h"
-#include "msMUlawenc.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond=0;
-}
-
-int main()
-{
- MSFilter *play,*enc,*dec,*rec;
- MSSync *timer;
-
- ms_init();
- signal(SIGINT,stop_handler);
-
- play=ms_oss_read_new();
- rec=ms_oss_write_new();
- ms_sound_read_set_device(MS_SOUND_READ(play),0);
- ms_sound_write_set_device(MS_SOUND_WRITE(rec),0);
-
- enc=ms_MULAWencoder_new();
- dec=ms_MULAWdecoder_new();
- timer=ms_timer_new();
-
- ms_filter_add_link(play,enc);
- ms_filter_add_link(enc,dec);
- ms_filter_add_link(dec,rec);
- ms_sync_attach(timer,play);
-
- ms_start(timer);
- ms_sound_read_start(MS_SOUND_READ(play));
- ms_sound_write_start(MS_SOUND_WRITE(rec));
- while(cond)
- {
- sleep(1);
- }
- ms_sound_read_stop(MS_SOUND_READ(play));
- ms_sound_write_stop(MS_SOUND_WRITE(rec));
- printf("stoping sync...\n");
- ms_stop(timer);
- printf("unlinking filters...\n");
- ms_filter_remove_links(play,enc);
- ms_filter_remove_links(enc,dec);
- ms_filter_remove_links(dec,rec);
- printf("destroying filters...\n");
- ms_filter_destroy(play);
- ms_filter_destroy(enc);
- ms_filter_destroy(dec);
- ms_filter_destroy(rec);
- ms_sync_destroy(timer);
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_rtprecv.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_rtprecv.c
deleted file mode 100644
index b8d6796..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_rtprecv.c
+++ /dev/null
@@ -1,100 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "msrtprecv.h"
-#include "ms.h"
-#include "mswrite.h"
-#include "msosswrite.h"
-#include "msMUlawdec.h"
-#include "mstimer.h"
-#include "msfdispatcher.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond=0;
-}
-
-int main()
-{
- MSFilter *play,*dec,*rec,*filerec,*dis;
- MSSync *timer;
- RtpSession *rtps;
-
- /*create the rtp session */
- ortp_init();
- ortp_set_debug_file("oRTP",NULL);
- rtps=rtp_session_new(RTP_SESSION_RECVONLY);
- rtp_session_set_local_addr(rtps,"0.0.0.0",8000);
- rtp_session_set_scheduling_mode(rtps,0);
- rtp_session_set_blocking_mode(rtps,0);
-
- ms_init();
- signal(SIGINT,stop_handler);
-
- play=ms_rtp_recv_new();
- rec=ms_oss_write_new();
- ms_sound_write_set_device(MS_SOUND_WRITE(rec),0);
- dec=ms_MULAWdecoder_new();
- filerec=ms_write_new("/tmp/rtpstream");
- dis=ms_fdispatcher_new();
- timer=ms_timer_new();
-
- ms_rtp_recv_set_session(MS_RTP_RECV(play),rtps);
-
- ms_filter_add_link(play,dec);
- ms_filter_add_link(dec,dis);
- ms_filter_add_link(dis,rec);
- ms_filter_add_link(dis,filerec);
- ms_sync_attach(timer,play);
- printf("gran=%i\n",MS_SYNC(timer)->samples_per_tick);
-
- ms_start(timer);
- ms_sound_write_start(MS_SOUND_WRITE(rec));
- while(cond)
- {
- sleep(1);
- }
-
- printf("stoping sync...\n");
- ms_stop(timer);
- ms_sound_write_stop(MS_SOUND_WRITE(rec));
- printf("unlinking filters...\n");
- ms_filter_remove_links(play,dec);
- ms_filter_remove_links(dec,rec);
- printf("destroying filters...\n");
- ms_filter_destroy(play);
- ms_filter_destroy(dec);
- ms_filter_destroy(rec);
- ms_filter_destroy(dis);
- ms_filter_destroy(filerec);
-
- rtp_session_destroy(rtps);
- ms_sync_destroy(timer);
- ortp_global_stats_display();
-
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_speex.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_speex.c
deleted file mode 100644
index 4ae057d..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_speex.c
+++ /dev/null
@@ -1,38 +0,0 @@
-
-#include "mediastream.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond--;
- if (cond<0) exit(-1);
-}
-
-int main(int argc, char * argv[])
-{
- AudioStream *audio;
-
- ortp_init();
- rtp_profile_set_payload(&av_profile, 110, &speex_wb);
- rtp_profile_set_payload(&av_profile,102,&payload_type_ilbc);
-
- ms_init();
- ms_speex_codec_init();
- ms_ilbc_codec_init();
-
- signal(SIGINT, stop_handler);
-
- audio = audio_stream_start(&av_profile, 2000, "127.0.0.1", 2000, 110, 250);
-
- for (;;) sleep(1);
-
- audio_stream_stop(audio);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_truespeech.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_truespeech.c
deleted file mode 100644
index 4e734fa..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_truespeech.c
+++ /dev/null
@@ -1,91 +0,0 @@
- /*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "ms.h"
-
-#include "msosswrite.h"
-#include "msossread.h"
-#include "mscopy.h"
-#include "mstimer.h"
-#include "mstruespeechdecoder.h"
-#include "mstruespeechencoder.h"
-
-#include <signal.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-
-static int cond=1;
-
-void stop_handler(int signum)
-{
- cond=0;
-}
-
-
-int main()
-{
- MSFilter *play,*enc,*dec,*rec;
- MSSync *timer;
-
- ms_init();
- signal(SIGINT,stop_handler);
-
- play=ms_oss_read_new();
- rec=ms_oss_write_new();
-
- ms_sound_read_set_device(MS_SOUND_READ(play),0);
- ms_sound_write_set_device(MS_SOUND_WRITE(rec),0);
-
- enc=ms_truespeechencoder_new();
- dec=ms_truespeechdecoder_new();
- timer=ms_timer_new();
-
- ms_filter_add_link(play,enc);
- ms_filter_add_link(enc,dec);
- ms_filter_add_link(dec,rec);
- ms_sync_attach(timer,play);
-
- ms_start(timer);
-
- ms_sound_read_start(MS_SOUND_READ(play));
- ms_sound_write_start(MS_SOUND_WRITE(rec));
- while(cond)
- {
- sleep(1);
- }
-
- ms_sound_read_stop(MS_SOUND_READ(play));
- ms_sound_write_stop(MS_SOUND_WRITE(rec));
-
- printf("stoping sync...\n");
- ms_stop(timer);
- printf("unlinking filters...\n");
- ms_filter_remove_links(play,enc);
- ms_filter_remove_links(enc,dec);
- ms_filter_remove_links(dec,rec);
- printf("destroying filters...\n");
- ms_filter_destroy(play);
- ms_filter_destroy(dec);
- ms_filter_destroy(enc);
- ms_filter_destroy(rec);
- ms_sync_destroy(timer);
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_v4l.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_v4l.c
deleted file mode 100644
index ffb72d3..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_v4l.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "mediastream.h"
-
-
-int main()
-{
- VideoStream *v;
- ms_init();
- v=video_preview_start("Video4Linux","/dev/video0");
- sleep(5);
- video_preview_stop(v);
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/test_videostream.c b/third_party/libjingle/source/talk/third_party/mediastreamer/test_videostream.c
deleted file mode 100644
index 0e68900..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/test_videostream.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "mediastream.h"
-#include <signal.h>
-
-static gboolean cond=TRUE;
-
-static void stop_handler(int signum){
- cond=FALSE;
-}
-
-int main()
-{
- VideoStream *v;
- ortp_init();
- ms_init();
- signal(SIGINT,stop_handler);
- v=video_stream_start(&av_profile,6000,"127.0.0.1",6000, 34, 60, TRUE, "Video4Linux","/dev/video0");
- while(cond) {
- ortp_global_stats_display();
- sleep(1);
- }
- video_stream_stop(v);
- ortp_exit();
- return 0;
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/videostream.c b/third_party/libjingle/source/talk/third_party/mediastreamer/videostream.c
deleted file mode 100644
index 44d2495..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/videostream.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- The mediastreamer library aims at providing modular media processing and I/O
- for linphone, but also for any telephony application.
- Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
-
- 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 2.1 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-
-#include "mediastream.h"
-#include "msvideosource.h"
-#include "msavdecoder.h"
-#include "msavencoder.h"
-#include "msnosync.h"
-#include "mssdlout.h"
-
-#define USE_SDL
-
-extern void create_duplex_rtpsession(RtpProfile *profile, int locport,char *remip,int remport,
- int payload,int jitt_comp,
- RtpSession **recvsend);
-
-#define MAX_RTP_SIZE 5000
-
-/* this code is not part of the library itself, it is part of the mediastream program */
-void
-video_stream_free (VideoStream * stream)
-{
- RtpSession *recvs, *sends;
- if (stream->rtprecv != NULL)
- {
- recvs = ms_rtp_recv_get_session (MS_RTP_RECV (stream->rtprecv));
- if (recvs != NULL)
- {
- rtp_session_destroy (recvs);
- }
- ms_filter_destroy (stream->rtprecv);
- }
- if (stream->rtpsend != NULL)
- {
- sends = ms_rtp_send_get_session (MS_RTP_SEND (stream->rtpsend));
- if (sends != NULL && sends!=recvs)
- {
- rtp_session_destroy (sends);
- }
- ms_filter_destroy (stream->rtpsend);
- }
- if (stream->source != NULL)
- ms_filter_destroy (stream->source);
- if (stream->output != NULL)
- ms_filter_destroy (stream->output);
- if (stream->decoder != NULL)
- ms_filter_destroy (stream->decoder);
- if (stream->encoder != NULL)
- ms_filter_destroy (stream->encoder);
- if (stream->timer != NULL)
- ms_sync_destroy (stream->timer);
- g_free (stream);
-}
-
-
-VideoStream *
-video_stream_start (RtpProfile *profile, int locport, char *remip, int remport,
- int payload, int jitt_comp, gboolean show_local,
- const gchar *source, const gchar *device)
-{
- VideoStream *stream = g_new0 (VideoStream, 1);
- RtpSession *rtps, *rtpr;
- PayloadType *pt;
- gchar *format;
- gint width = VIDEO_SIZE_CIF_W;
- gint height = VIDEO_SIZE_CIF_H;
- gfloat fps;
-
- create_duplex_rtpsession(profile,locport,remip,remport,payload,jitt_comp,&rtpr);
- rtp_session_enable_adaptive_jitter_compensation(rtpr,FALSE);
- rtps=rtpr;
- ms_trace("sending video to %s:%i", remip4, remport);
-
- /* creates two rtp filters to recv send streams (remote part) */
- rtp_session_max_buf_size_set(rtpr,MAX_RTP_SIZE);
- stream->rtpsend = ms_rtp_send_new ();
- if (remport>0) ms_rtp_send_set_session (MS_RTP_SEND (stream->rtpsend), rtps);
-
-
- stream->rtprecv = ms_rtp_recv_new ();
- ms_rtp_recv_set_session (MS_RTP_RECV (stream->rtprecv), rtpr);
-
- pt=rtp_profile_get_payload(profile,payload);
- if (pt==NULL){
- g_error("videostream.c: undefined payload type.");
- return NULL;
- }
- ms_trace("videostream.c: getting codecs for %s", pt->mime_type);
-
- /* creates the filters */
- stream->source = ms_filter_new_with_name(source);
- if (stream->source == NULL){
- g_error("videostream.c: failed to create video source %s.", source);
- return NULL;
- }
-
-#ifdef USE_SDL
- stream->output=ms_sdl_out_new();
-#else
- stream->output = MS_FILTER(ms_video_output_new ());
-#endif
- stream->encoder=ms_encoder_new_with_string_id(pt->mime_type);
- g_message("Video encoder created: %x",stream->encoder);
- stream->decoder=ms_decoder_new_with_string_id(pt->mime_type);
- if ((stream->encoder==NULL) || (stream->decoder==NULL)){
- /* big problem: we have not a registered codec for this payload...*/
- video_stream_free(stream);
- g_error("videostream.c: No codecs available for payload %i.",payload);
- return NULL;
- }
-
- /* configure the filters */
- ms_video_source_set_device(MS_VIDEO_SOURCE(stream->source), device);
- ms_video_source_set_size(MS_VIDEO_SOURCE(stream->source), width, height);
- ms_video_source_set_frame_rate(MS_VIDEO_SOURCE(stream->source), 8, 1);
- fps = MS_VIDEO_SOURCE(stream->source)->frame_rate / MS_VIDEO_SOURCE(stream->source)->frame_rate_base;
- format = ms_video_source_get_format(MS_VIDEO_SOURCE(stream->source));
-
- ms_AVencoder_set_format (MS_AVENCODER (stream->encoder), format);
- ms_AVencoder_set_width(MS_AVENCODER(stream->encoder), width);
- ms_AVencoder_set_height(MS_AVENCODER(stream->encoder), height);
- /* bitrate is based upon 30fps? adjust by our possibly lower framerate */
- ms_AVencoder_set_bit_rate(MS_AVENCODER(stream->encoder), pt->normal_bitrate * 30 / fps );
- ms_AVdecoder_set_format (MS_AVDECODER (stream->decoder), "YUV420P");
- ms_AVdecoder_set_width(MS_AVDECODER(stream->decoder), width);
- ms_AVdecoder_set_height(MS_AVDECODER(stream->decoder), height);
-#ifdef USE_SDL
- /* we suppose our decoder and pin1 of encoder always outputs YUV420P */
- ms_sdl_out_set_format(MS_SDL_OUT(stream->output),"YUV420P");
-#else
- ms_video_output_set_size (MS_VIDEO_OUTPUT (stream->output), width, height);
-#endif
-
- /* and then connect all */
- ms_filter_add_link (stream->source, stream->encoder);
- ms_filter_add_link (stream->encoder, stream->rtpsend);
-
- ms_filter_add_link (stream->rtprecv, stream->decoder);
- ms_filter_add_link (stream->decoder, stream->output);
- if (show_local)
- ms_filter_add_link(stream->encoder,stream->output);
-
- /* create the synchronisation source */
- stream->timer = ms_timer_new();
- ms_sync_attach (stream->timer, stream->source);
- ms_sync_attach (stream->timer, stream->rtprecv);
-
- /* and start */
- ms_video_source_start(MS_VIDEO_SOURCE(stream->source));
- ms_start (stream->timer);
- stream->show_local=show_local;
- return stream;
-}
-
-
-
-void
-video_stream_stop (VideoStream * stream)
-{
-
- ms_stop (stream->timer);
- ms_video_source_stop (MS_VIDEO_SOURCE(stream->source));
- ms_sync_detach (stream->timer, stream->source);
- ms_sync_detach (stream->timer, stream->rtprecv);
-
- ms_filter_remove_links(stream->source,stream->encoder);
- ms_filter_remove_links (stream->encoder,
- stream->rtpsend);
-
- ms_filter_remove_links (stream->rtprecv,
- stream->decoder);
- ms_filter_remove_links (stream->decoder,
- stream->output);
- if (stream->show_local) {
- ms_filter_remove_links (stream->encoder,
- stream->output);
- }
- video_stream_free (stream);
-}
-
-
-void video_stream_set_rtcp_information(VideoStream *st, const char *cname){
- if (st->send_session!=NULL){
- rtp_session_set_source_description(st->send_session,cname,NULL,NULL,NULL,NULL,"linphone-" LINPHONE_VERSION,
- "This is free software (GPL) !");
- }
-}
-
-
-
-VideoStream * video_preview_start(const gchar *source, const gchar *device){
- VideoStream *stream = g_new0 (VideoStream, 1);
- gchar *format;
- gint width = VIDEO_SIZE_CIF_W;
- gint height = VIDEO_SIZE_CIF_H;
-
- /* creates the filters */
- stream->source = ms_filter_new_with_name(source);
- if (stream->source == NULL){
- g_error("videostream.c: failed to create video source %s.", source);
- return NULL;
- }
-#ifdef USE_SDL
- stream->output=ms_sdl_out_new();
-#else
- stream->output = ms_video_output_new ();
-#endif
- /* configure the filters */
- ms_video_source_set_device(MS_VIDEO_SOURCE(stream->source), device);
- ms_video_source_set_size(MS_VIDEO_SOURCE(stream->source), width, height);
- ms_video_source_set_frame_rate(MS_VIDEO_SOURCE(stream->source), 8, 1);
- format = ms_video_source_get_format(MS_VIDEO_SOURCE(stream->source));
-
-#ifdef USE_SDL
- ms_sdl_out_set_format(MS_SDL_OUT(stream->output),format);
-#else
- ms_video_output_set_format(MS_VIDEO_OUTPUT(stream->output),format);
- ms_video_output_set_size (MS_VIDEO_OUTPUT (stream->output), width, height);
- ms_video_output_set_title(MS_VIDEO_OUTPUT(stream->output),"Linphone Video");
-#endif
- /* and then connect all */
- ms_filter_add_link (stream->source, stream->output);
- /* create the synchronisation source */
- stream->timer = ms_timer_new();
- ms_sync_attach (stream->timer, stream->source);
-
- /* and start */
- ms_video_source_start(MS_VIDEO_SOURCE(stream->source));
- ms_start (stream->timer);
-
- return stream;
-}
-
-void video_preview_stop(VideoStream *stream){
- ms_stop (stream->timer);
- ms_video_source_stop (MS_VIDEO_SOURCE(stream->source));
- ms_sync_detach (stream->timer, stream->source);
- ms_filter_remove_links(stream->source,stream->output);
- video_stream_free(stream);
-}
diff --git a/third_party/libjingle/source/talk/third_party/mediastreamer/waveheader.h b/third_party/libjingle/source/talk/third_party/mediastreamer/waveheader.h
deleted file mode 100644
index 6768d8f..0000000
--- a/third_party/libjingle/source/talk/third_party/mediastreamer/waveheader.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-linphone
-Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr)
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program 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 General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-/* the following code was taken from a free software utility that I don't remember the name. */
-/* sorry */
-
-
-
-#include <ms.h>
-#ifndef waveheader_h
-#define waveheader_h
-
-typedef struct uint16scheme
-{
- unsigned char lo_byte;
- unsigned char hi_byte;
-} uint16scheme_t;
-
-typedef struct uint32scheme
-{
- guint16 lo_int;
- guint16 hi_int;
-} uint32scheme_t;
-
-
-/* all integer in wav header must be read in least endian order */
-inline guint16 _readuint16(guint16 a)
-{
- guint16 res;
- uint16scheme_t *tmp1=(uint16scheme_t*)&a;
-
- ((uint16scheme_t *)(&res))->lo_byte=tmp1->hi_byte;
- ((uint16scheme_t *)(&res))->hi_byte=tmp1->lo_byte;
- return res;
-}
-
-inline guint32 _readuint32(guint32 a)
-{
- guint32 res;
- uint32scheme_t *tmp1=(uint32scheme_t*)&a;
-
- ((uint32scheme_t *)(&res))->lo_int=_readuint16(tmp1->hi_int);
- ((uint32scheme_t *)(&res))->hi_int=_readuint16(tmp1->lo_int);
- return res;
-}
-
-#ifdef WORDS_BIGENDIAN
-#define le_uint32(a) (_readuint32((a)))
-#define le_uint16(a) (_readuint16((a)))
-#define le_int16(a) ( (gint16) _readuint16((guint16)((a))) )
-#else
-#define le_uint32(a) (a)
-#define le_uint16(a) (a)
-#define le_int16(a) (a)
-#endif
-
-typedef struct _riff_t {
- char riff[4] ; /* "RIFF" (ASCII characters) */
- guint32 len ; /* Length of package (binary, little endian) */
- char wave[4] ; /* "WAVE" (ASCII characters) */
-} riff_t;
-
-/* The FORMAT chunk */
-
-typedef struct _format_t {
- char fmt[4] ; /* "fmt_" (ASCII characters) */
- guint32 len ; /* length of FORMAT chunk (always 0x10) */
- guint16 que ; /* Always 0x01 */
- guint16 channel ; /* Channel numbers (0x01 = mono, 0x02 = stereo) */
- guint32 rate ; /* Sample rate (binary, in Hz) */
- guint32 bps ; /* Bytes Per Second */
- guint16 bpsmpl ; /* bytes per sample: 1 = 8 bit Mono,
- 2 = 8 bit Stereo/16 bit Mono,
- 4 = 16 bit Stereo */
- guint16 bitpspl ; /* bits per sample */
-} format_t;
-
-/* The DATA chunk */
-
-typedef struct _data_t {
- char data[4] ; /* "data" (ASCII characters) */
- int len ; /* length of data */
-} data_t;
-
-typedef struct _wave_header_t
-{
- riff_t riff_chunk;
- format_t format_chunk;
- data_t data_chunk;
-} wave_header_t;
-
-#define wave_header_get_rate(header) le_uint32((header)->format_chunk.rate)
-#define wave_header_get_channel(header) le_uint16((header)->format_chunk.channel)
-
-#endif
diff --git a/third_party/modp_b64/README.chromium b/third_party/modp_b64/README.chromium
index 4b22d61..fc30450 100644
--- a/third_party/modp_b64/README.chromium
+++ b/third_party/modp_b64/README.chromium
@@ -8,7 +8,9 @@ and to fix compilation errors that occur under VC8. The file was renamed
modp_b64.cc to force it to be compiled as C++ so that the inclusion of
basictypes.h could be possible.
-The file modp_b64_data.h was generated by modp_b64_gen.c (under Linux), which
-is not included in this directory. The resulting header was modified to remove
-the "#include <stdint.h>" since that header file does not exist under VC8. The
-required typedefs for uint8_t and uint32_t were defined in its place.
+The file modp_b64_data.h was generated by modp_b64_gen.c (under Linux),
+which is not included in this directory. The resulting header was
+modified to not include <stdint.h> when COMPILER_MSVC is defined (since
+that header file does not exist under VC8), but instead in that case to
+include "base/basictypes.h" and provide the required typedefs for
+uint8_t and uint32_t using uint8 and uint32.
diff --git a/third_party/modp_b64/modp_b64.target.mk b/third_party/modp_b64/modp_b64.target.mk
index e5e180a..5d51384 100644
--- a/third_party/modp_b64/modp_b64.target.mk
+++ b/third_party/modp_b64/modp_b64.target.mk
@@ -16,6 +16,7 @@ CFLAGS_Debug := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O0 \
-g
@@ -45,6 +46,7 @@ CFLAGS_Release := -pthread \
-Wno-missing-field-initializers \
-D_FILE_OFFSET_BITS=64 \
-fvisibility=hidden \
+ -pipe \
-fno-strict-aliasing \
-O2 \
-fno-ident \
@@ -88,11 +90,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := -pthread \
- -Wl,-z,noexecstack \
- -rdynamic
+ -Wl,-z,noexecstack
LDFLAGS_Release := -pthread \
-Wl,-z,noexecstack \
+ -Wl,-O1 \
+ -Wl,--as-needed \
-Wl,--gc-sections
LIBS :=
diff --git a/third_party/modp_b64/modp_b64_data.h b/third_party/modp_b64/modp_b64_data.h
index a2dc7dd..aca6f0f 100644
--- a/third_party/modp_b64/modp_b64_data.h
+++ b/third_party/modp_b64/modp_b64_data.h
@@ -1,6 +1,14 @@
+#include "build/build_config.h"
+#if !defined(COMPILER_MSVC)
+#include <stdint.h>
+#else
+// VC8 doesn't have stdint.h. On the other hand, some compilers don't like
+// the below code, because basictypes.h itself includes stdint.h and the
+// typedefs below can cause conflicts.
#include "base/basictypes.h"
typedef uint8 uint8_t;
typedef uint32 uint32_t;
+#endif
#define CHAR62 '+'
#define CHAR63 '/'
diff --git a/webkit/glue/DEPS b/webkit/glue/DEPS
index e59afec..0a36ef7 100644
--- a/webkit/glue/DEPS
+++ b/webkit/glue/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+app",
+ "+gpu",
"+media",
"+skia/ext",
"+skia/include",
diff --git a/webkit/glue/context_menu.cc b/webkit/glue/context_menu.cc
new file mode 100644
index 0000000..390d740
--- /dev/null
+++ b/webkit/glue/context_menu.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 "webkit/glue/context_menu.h"
+
+ContextMenuParams::ContextMenuParams() {
+}
+
+ContextMenuParams::ContextMenuParams(const WebKit::WebContextMenuData& data)
+ : media_type(data.mediaType),
+ x(data.mousePosition.x),
+ y(data.mousePosition.y),
+ link_url(data.linkURL),
+ unfiltered_link_url(data.linkURL),
+ src_url(data.srcURL),
+ is_image_blocked(data.isImageBlocked),
+ page_url(data.pageURL),
+ frame_url(data.frameURL),
+ media_flags(data.mediaFlags),
+ selection_text(UTF16ToWideHack(data.selectedText)),
+ misspelled_word(data.misspelledWord),
+ spellcheck_enabled(data.isSpellCheckingEnabled),
+ is_editable(data.isEditable),
+#if defined(OS_MACOSX)
+ writing_direction_default(data.writingDirectionDefault),
+ writing_direction_left_to_right(data.writingDirectionLeftToRight),
+ writing_direction_right_to_left(data.writingDirectionRightToLeft),
+#endif // OS_MACOSX
+ edit_flags(data.editFlags),
+ security_info(data.securityInfo),
+ frame_charset(data.frameEncoding.utf8()) {
+ for (size_t i = 0; i < data.customItems.size(); ++i)
+ custom_items.push_back(WebMenuItem(data.customItems[i]));
+}
+
+ContextMenuParams::~ContextMenuParams() {
+}
diff --git a/webkit/glue/context_menu.h b/webkit/glue/context_menu.h
index 764fb9d..b681a38 100644
--- a/webkit/glue/context_menu.h
+++ b/webkit/glue/context_menu.h
@@ -96,34 +96,9 @@ struct ContextMenuParams {
std::vector<WebMenuItem> custom_items;
- ContextMenuParams() {}
-
- ContextMenuParams(const WebKit::WebContextMenuData& data)
- : media_type(data.mediaType),
- x(data.mousePosition.x),
- y(data.mousePosition.y),
- link_url(data.linkURL),
- unfiltered_link_url(data.linkURL),
- src_url(data.srcURL),
- is_image_blocked(data.isImageBlocked),
- page_url(data.pageURL),
- frame_url(data.frameURL),
- media_flags(data.mediaFlags),
- selection_text(UTF16ToWideHack(data.selectedText)),
- misspelled_word(data.misspelledWord),
- spellcheck_enabled(data.isSpellCheckingEnabled),
- is_editable(data.isEditable),
-#if defined(OS_MACOSX)
- writing_direction_default(data.writingDirectionDefault),
- writing_direction_left_to_right(data.writingDirectionLeftToRight),
- writing_direction_right_to_left(data.writingDirectionRightToLeft),
-#endif // OS_MACOSX
- edit_flags(data.editFlags),
- security_info(data.securityInfo),
- frame_charset(data.frameEncoding.utf8()) {
- for (size_t i = 0; i < data.customItems.size(); ++i)
- custom_items.push_back(WebMenuItem(data.customItems[i]));
- }
+ ContextMenuParams();
+ ContextMenuParams(const WebKit::WebContextMenuData& data);
+ ~ContextMenuParams();
};
#endif // WEBKIT_GLUE_CONTEXT_MENU_H_
diff --git a/webkit/glue/cpp_bound_class.cc b/webkit/glue/cpp_bound_class.cc
index 09c3f40..d58fc4e 100644
--- a/webkit/glue/cpp_bound_class.cc
+++ b/webkit/glue/cpp_bound_class.cc
@@ -173,6 +173,10 @@ NPClass CppNPObject::np_class_ = {
return obj->bound_class->SetProperty(ident, value);
}
+CppBoundClass::CppBoundClass()
+ : bound_to_frame_(false) {
+}
+
CppBoundClass::~CppBoundClass() {
for (MethodList::iterator i = methods_.begin(); i != methods_.end(); ++i)
delete i->second;
diff --git a/webkit/glue/cpp_bound_class.h b/webkit/glue/cpp_bound_class.h
index dcd5c3e..a446386 100644
--- a/webkit/glue/cpp_bound_class.h
+++ b/webkit/glue/cpp_bound_class.h
@@ -51,7 +51,7 @@ class CppBoundClass {
// The constructor should call BindMethod, BindProperty, and
// SetFallbackMethod as needed to set up the methods, properties, and
// fallback method.
- CppBoundClass() : bound_to_frame_(false) { }
+ CppBoundClass();
virtual ~CppBoundClass();
// Return a CppVariant representing this class, for use with BindProperty().
diff --git a/webkit/glue/cpp_variant.cc b/webkit/glue/cpp_variant.cc
index a254669..8545bc1 100644
--- a/webkit/glue/cpp_variant.cc
+++ b/webkit/glue/cpp_variant.cc
@@ -9,6 +9,7 @@
#include "webkit/glue/cpp_variant.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
using WebKit::WebBindings;
@@ -228,11 +229,11 @@ std::vector<std::wstring> CppVariant::ToStringVector() const {
length = NPVARIANT_TO_INT32(length_value);
WebBindings::releaseVariantValue(&length_value);
- // For sanity, only allow 100 items.
- length = std::min(100, length);
+ // For sanity, only allow 60000 items.
+ length = std::min(60000, length);
for (int i = 0; i < length; ++i) {
// Get each of the items.
- std::string index = StringPrintf("%d", i);
+ std::string index = base::StringPrintf("%d", i);
NPIdentifier index_id = WebBindings::getStringIdentifier(index.c_str());
if (WebBindings::hasProperty(NULL, np_value, index_id)) {
NPVariant index_value;
diff --git a/webkit/glue/devtools_message_data.cc b/webkit/glue/devtools_message_data.cc
deleted file mode 100644
index a9af3c5..0000000
--- a/webkit/glue/devtools_message_data.cc
+++ /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 "webkit/glue/devtools_message_data.h"
-
-#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDevToolsMessageData.h"
-
-using WebKit::WebDevToolsMessageData;
-using WebKit::WebString;
-using WebKit::WebVector;
-
-DevToolsMessageData::DevToolsMessageData(const WebDevToolsMessageData& data)
- : class_name(data.className.utf8()),
- method_name(data.methodName.utf8()) {
- for (size_t i = 0; i < data.arguments.size(); i++)
- arguments.push_back(data.arguments[i].utf8());
-}
-
-WebDevToolsMessageData DevToolsMessageData::ToWebDevToolsMessageData() const {
- WebDevToolsMessageData result;
- result.className = WebString::fromUTF8(class_name);
- result.methodName = WebString::fromUTF8(method_name);
- WebVector<WebString> web_args(arguments.size());
- for (size_t i = 0; i < arguments.size(); i++)
- web_args[i] = WebString::fromUTF8(arguments[i]);
- result.arguments.swap(web_args);
- return result;
-}
diff --git a/webkit/glue/devtools_message_data.h b/webkit/glue/devtools_message_data.h
deleted file mode 100644
index 31daa14..0000000
--- a/webkit/glue/devtools_message_data.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 WEBKIT_GLUE_DEVTOOLS_MESSAGE_DATA_H_
-#define WEBKIT_GLUE_DEVTOOLS_MESSAGE_DATA_H_
-
-#include <string>
-#include <vector>
-
-namespace WebKit {
-struct WebDevToolsMessageData;
-}
-
-struct DevToolsMessageData {
- DevToolsMessageData() {}
- explicit DevToolsMessageData(const WebKit::WebDevToolsMessageData&);
- WebKit::WebDevToolsMessageData ToWebDevToolsMessageData() const;
-
- std::string class_name;
- std::string method_name;
- std::vector<std::string> arguments;
-};
-
-#endif // WEBKIT_GLUE_DEVTOOLS_DEVTOOLS_MESSAGE_DATA_H_
diff --git a/webkit/glue/devtools_strings.grd b/webkit/glue/devtools_strings.grd
index a21baf5..36f14ca 100644
--- a/webkit/glue/devtools_strings.grd
+++ b/webkit/glue/devtools_strings.grd
@@ -19,6 +19,7 @@ Google Chrome Developer Tools. -->
<output filename="devtoolsStrings_es.js" type="js_map_format" lang="es" />
<output filename="devtoolsStrings_es-419.js" type="js_map_format" lang="es-419" />
<output filename="devtoolsStrings_et.js" type="js_map_format" lang="et" />
+ <output filename="devtoolsStrings_fa.js" type="js_map_format" lang="fa" />
<output filename="devtoolsStrings_fi.js" type="js_map_format" lang="fi" />
<output filename="devtoolsStrings_fil.js" type="js_map_format" lang="fil" />
<output filename="devtoolsStrings_fr.js" type="js_map_format" lang="fr" />
diff --git a/webkit/glue/dom_operations.cc b/webkit/glue/dom_operations.cc
index 82e5e3a..22e0e75 100644
--- a/webkit/glue/dom_operations.cc
+++ b/webkit/glue/dom_operations.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "webkit/glue/dom_operations.h"
+
#include <set>
#include "base/compiler_specific.h"
-#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "third_party/WebKit/WebKit/chromium/public/WebAnimationController.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/WebKit/chromium/public/WebElement.h"
@@ -17,7 +20,6 @@
#include "third_party/WebKit/WebKit/chromium/public/WebNodeList.h"
#include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
-#include "webkit/glue/dom_operations.h"
#include "webkit/glue/form_data.h"
#include "webkit/glue/password_form_dom_manager.h"
#include "webkit/glue/webpasswordautocompletelistener_impl.h"
@@ -184,7 +186,7 @@ static bool FillFormImpl(FormElements* fe, const FormData& data) {
WebKit::WebInputElement& element = it->second;
if (!element.value().isEmpty()) // Don't overwrite pre-filled values.
continue;
- if (element.inputType() == WebInputElement::Password &&
+ if (element.isPasswordField() &&
(!element.isEnabledFormControl() || element.hasAttribute("readonly"))) {
continue; // Don't fill uneditable password fields.
}
@@ -312,7 +314,7 @@ WebString GetSubResourceLinkFromElement(const WebElement& element) {
attribute_name = "src";
} else if (element.hasTagName("input")) {
const WebInputElement input = element.toConst<WebInputElement>();
- if (input.inputType() == WebInputElement::Image) {
+ if (input.isImageButton()) {
attribute_name = "src";
}
} else if (element.hasTagName("body") ||
@@ -405,7 +407,7 @@ static int ParseSingleIconSize(const string16& text) {
return 0;
}
int output;
- if (!StringToInt(text, &output))
+ if (!base::StringToInt(text, &output))
return 0;
return output;
}
@@ -415,7 +417,7 @@ static int ParseSingleIconSize(const string16& text) {
// If the input couldn't be parsed, a size with a width/height < 0 is returned.
static gfx::Size ParseIconSize(const string16& text) {
std::vector<string16> sizes;
- SplitStringDontTrim(text, L'x', &sizes);
+ base::SplitStringDontTrim(text, L'x', &sizes);
if (sizes.size() != 2)
return gfx::Size();
@@ -591,9 +593,10 @@ int NumberOfActiveAnimations(WebView* view) {
return controller->numberOfActiveAnimations();
}
-void GetMetaElementsWithName(WebDocument* document,
- const string16& name,
- std::vector<WebElement>* meta_elements) {
+void GetMetaElementsWithAttribute(WebDocument* document,
+ const string16& attribute_name,
+ const string16& attribute_value,
+ std::vector<WebElement>* meta_elements) {
DCHECK(document);
DCHECK(meta_elements);
meta_elements->clear();
@@ -609,8 +612,8 @@ void GetMetaElementsWithName(WebDocument* document,
WebElement element = node.to<WebElement>();
if (!element.hasTagName("meta"))
continue;
- WebString meta_name = element.getAttribute("name");
- if (meta_name.isNull() || meta_name != name)
+ WebString value = element.getAttribute(attribute_name);
+ if (value.isNull() || value != attribute_value)
continue;
meta_elements->push_back(element);
}
diff --git a/webkit/glue/dom_operations.h b/webkit/glue/dom_operations.h
index 664add0..20084f7 100644
--- a/webkit/glue/dom_operations.h
+++ b/webkit/glue/dom_operations.h
@@ -6,7 +6,6 @@
#define WEBKIT_GLUE_DOM_OPERATIONS_H__
#include <string>
-#include <map>
#include <vector>
#include "gfx/size.h"
@@ -133,11 +132,12 @@ int NumberOfActiveAnimations(WebKit::WebView* view);
WebKit::WebString GetSubResourceLinkFromElement(
const WebKit::WebElement& element);
-// Puts the meta-elements of |document| that have the specified |name| in
-// |meta_elements|.
-void GetMetaElementsWithName(WebKit::WebDocument* document,
- const string16& name,
- std::vector<WebKit::WebElement>* meta_elements);
+// Puts the meta-elements of |document| that have the attribute |attribute_name|
+// with a value of |attribute_value| in |meta_elements|.
+void GetMetaElementsWithAttribute(WebKit::WebDocument* document,
+ const string16& attribute_name,
+ const string16& atribute_value,
+ std::vector<WebKit::WebElement>* meta_elements);
} // namespace webkit_glue
diff --git a/webkit/glue/dom_operations_unittest.cc b/webkit/glue/dom_operations_unittest.cc
index e9f590c..c57e943 100644
--- a/webkit/glue/dom_operations_unittest.cc
+++ b/webkit/glue/dom_operations_unittest.cc
@@ -5,6 +5,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_context.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
diff --git a/webkit/glue/dom_serializer_unittest.cc b/webkit/glue/dom_serializer_unittest.cc
index a1846f3..62b5a3d 100644
--- a/webkit/glue/dom_serializer_unittest.cc
+++ b/webkit/glue/dom_serializer_unittest.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,6 +6,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/hash_tables.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_context.h"
@@ -582,6 +583,7 @@ TEST_F(DomSerializerTests, SerializeHTMLDOMWithEntitiesInText) {
// Test situation of html entities in attribute value when serializing
// HTML DOM.
+// This test started to fail at WebKit r65388. See http://crbug.com/52279.
TEST_F(DomSerializerTests, SerializeHTMLDOMWithEntitiesInAttributeValue) {
FilePath page_file_path = data_dir_;
page_file_path = page_file_path.AppendASCII(
@@ -631,6 +633,7 @@ TEST_F(DomSerializerTests, SerializeHTMLDOMWithEntitiesInAttributeValue) {
}
// Test situation of non-standard HTML entities when serializing HTML DOM.
+// This test started to fail at WebKit r65351. See http://crbug.com/52279.
TEST_F(DomSerializerTests, SerializeHTMLDOMWithNonStandardEntities) {
// Make a test file URL and load it.
FilePath page_file_path = data_dir_;
@@ -644,7 +647,7 @@ TEST_F(DomSerializerTests, SerializeHTMLDOMWithNonStandardEntities) {
WebDocument doc = web_frame->document();
ASSERT_TRUE(doc.isHTMLDocument());
WebElement body_element = doc.body();
- // Unescaped string for "&percnt;&nsup;&supl;&apos;".
+ // Unescaped string for "&percnt;&nsup;&sup1;&apos;".
static const wchar_t parsed_value[] = {
'%', 0x2285, 0x00b9, '\'', 0
};
@@ -661,7 +664,7 @@ TEST_F(DomSerializerTests, SerializeHTMLDOMWithNonStandardEntities) {
// Confirm that the serialized string has no non-standard HTML entities.
ASSERT_EQ(std::string::npos, serialized_contents.find("&percnt;"));
ASSERT_EQ(std::string::npos, serialized_contents.find("&nsup;"));
- ASSERT_EQ(std::string::npos, serialized_contents.find("&supl;"));
+ ASSERT_EQ(std::string::npos, serialized_contents.find("&sup1;"));
ASSERT_EQ(std::string::npos, serialized_contents.find("&apos;"));
}
diff --git a/webkit/glue/form_data.cc b/webkit/glue/form_data.cc
new file mode 100644
index 0000000..4e1a6ea
--- /dev/null
+++ b/webkit/glue/form_data.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 "webkit/glue/form_data.h"
+
+namespace webkit_glue {
+
+FormData::FormData()
+ : user_submitted(false) {
+}
+
+FormData::FormData(const FormData& data)
+ : name(data.name),
+ method(data.method),
+ origin(data.origin),
+ action(data.action),
+ user_submitted(data.user_submitted),
+ fields(data.fields) {
+}
+
+FormData::~FormData() {
+}
+
+bool FormData::operator==(const FormData& form) const {
+ return (name == form.name &&
+ StringToLowerASCII(method) == StringToLowerASCII(form.method) &&
+ origin == form.origin &&
+ action == form.action &&
+ user_submitted == form.user_submitted &&
+ fields == form.fields);
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/form_data.h b/webkit/glue/form_data.h
index 2bb7115..063b021 100644
--- a/webkit/glue/form_data.h
+++ b/webkit/glue/form_data.h
@@ -27,17 +27,17 @@ struct FormData {
GURL origin;
// The action target of the form.
GURL action;
+ // true if this form was submitted by a user gesture and not javascript.
+ bool user_submitted;
// A vector of all the input fields in the form.
std::vector<FormField> fields;
+ FormData();
+ FormData(const FormData& data);
+ ~FormData();
+
// Used by FormStructureTest.
- inline bool operator==(const FormData& form) const {
- return (name == form.name &&
- StringToLowerASCII(method) == StringToLowerASCII(form.method) &&
- origin == form.origin &&
- action == form.action &&
- fields == form.fields);
- }
+ bool operator==(const FormData& form) const;
};
} // namespace webkit_glue
diff --git a/webkit/glue/form_field.cc b/webkit/glue/form_field.cc
index a0fbdef..30d22ad 100644
--- a/webkit/glue/form_field.cc
+++ b/webkit/glue/form_field.cc
@@ -66,6 +66,9 @@ FormField::FormField(const string16& label,
size_(size) {
}
+FormField::~FormField() {
+}
+
bool FormField::operator==(const FormField& field) const {
// A FormField stores a value, but the value is not part of the identity of
// the field, so we don't want to compare the values.
diff --git a/webkit/glue/form_field.h b/webkit/glue/form_field.h
index 2a1ffcf..56d8969 100644
--- a/webkit/glue/form_field.h
+++ b/webkit/glue/form_field.h
@@ -22,6 +22,7 @@ class FormField {
const string16& value,
const string16& form_control_type,
int size);
+ ~FormField();
const string16& label() const { return label_; }
const string16& name() const { return name_; }
diff --git a/webkit/glue/ftp_directory_listing_response_delegate.h b/webkit/glue/ftp_directory_listing_response_delegate.h
index 1218da9..e259c1e 100644
--- a/webkit/glue/ftp_directory_listing_response_delegate.h
+++ b/webkit/glue/ftp_directory_listing_response_delegate.h
@@ -61,6 +61,8 @@ class FtpDirectoryListingResponseDelegate {
// True if we got an error when parsing the response.
bool had_parsing_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingResponseDelegate);
};
} // namespace webkit_glue
diff --git a/webkit/glue/glue_serialize.cc b/webkit/glue/glue_serialize.cc
index caf37b4..835ae78 100644
--- a/webkit/glue/glue_serialize.cc
+++ b/webkit/glue/glue_serialize.cc
@@ -15,11 +15,11 @@
#include "third_party/WebKit/WebKit/chromium/public/WebPoint.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSerializedScriptValue.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/WebVector.h"
#include "webkit/glue/webkit_glue.h"
using WebKit::WebData;
-using WebKit::WebFileInfo;
using WebKit::WebHistoryItem;
using WebKit::WebHTTPBody;
using WebKit::WebPoint;
@@ -56,12 +56,13 @@ struct SerializeObject {
// 7: Adds support for stateObject
// 8: Adds support for file range and modification time
// 9: Adds support for itemSequenceNumbers
+// 10: Adds support for blob
// Should be const, but unit tests may modify it.
//
// NOTE: If the version is -1, then the pickle contains only a URL string.
// See CreateHistoryStateForURL.
//
-int kVersion = 9;
+int kVersion = 10;
// A bunch of convenience functions to read/write to SerializeObjects.
// The serializers assume the input data is in the correct format and so does
@@ -191,7 +192,9 @@ inline WebString ReadString(const SerializeObject* obj) {
// In version 2, the length field was the length in WebUChars.
// In version 1 and 3 it is the length in bytes.
- int bytes = ((obj->version == 2) ? length * sizeof(WebUChar) : length);
+ int bytes = length;
+ if (obj->version == 2)
+ bytes *= sizeof(WebUChar);
const void* data;
if (!ReadBytes(obj, &data, bytes))
@@ -232,11 +235,13 @@ static void WriteFormData(const WebHTTPBody& http_body, SerializeObject* obj) {
if (element.type == WebHTTPBody::Element::TypeData) {
WriteData(element.data.data(), static_cast<int>(element.data.size()),
obj);
- } else {
+ } else if (element.type == WebHTTPBody::Element::TypeFile) {
WriteString(element.filePath, obj);
WriteInteger64(element.fileStart, obj);
WriteInteger64(element.fileLength, obj);
- WriteReal(element.fileInfo.modificationTime, obj);
+ WriteReal(element.modificationTime, obj);
+ } else {
+ WriteGURL(element.blobURL, obj);
}
}
WriteInteger64(http_body.identifier(), obj);
@@ -263,17 +268,21 @@ static WebHTTPBody ReadFormData(const SerializeObject* obj) {
ReadData(obj, &data, &length);
if (length >= 0)
http_body.appendData(WebData(static_cast<const char*>(data), length));
- } else {
+ } else if (type == WebHTTPBody::Element::TypeFile) {
WebString file_path = ReadString(obj);
long long file_start = 0;
long long file_length = -1;
- WebFileInfo file_info;
+ double modification_time = 0.0;
if (obj->version >= 8) {
file_start = ReadInteger64(obj);
file_length = ReadInteger64(obj);
- file_info.modificationTime = ReadReal(obj);
+ modification_time = ReadReal(obj);
}
- http_body.appendFileRange(file_path, file_start, file_length, file_info);
+ http_body.appendFileRange(file_path, file_start, file_length,
+ modification_time);
+ } else if (obj->version >= 10) {
+ GURL blob_url = ReadGURL(obj);
+ http_body.appendBlob(blob_url);
}
}
if (obj->version >= 4)
diff --git a/webkit/glue/idb_bindings.cc b/webkit/glue/idb_bindings.cc
new file mode 100644
index 0000000..fd26130
--- /dev/null
+++ b/webkit/glue/idb_bindings.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 "webkit/glue/idb_bindings.h"
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBKey.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebIDBKeyPath.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSerializedScriptValue.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
+#include "v8/include/v8.h"
+
+namespace webkit_glue {
+
+using WebKit::WebIDBKey;
+using WebKit::WebIDBKeyPath;
+using WebKit::WebSerializedScriptValue;
+
+namespace {
+
+class LocalContext {
+ public:
+ LocalContext()
+ : context_(v8::Context::New()) {
+ context_->Enter();
+ }
+
+ virtual ~LocalContext() {
+ context_->Exit();
+ context_.Dispose();
+ }
+
+ private:
+ v8::Locker lock_;
+ v8::HandleScope scope_;
+ v8::Persistent<v8::Context> context_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalContext);
+};
+
+} // namespace
+
+bool IDBKeysFromValuesAndKeyPath(
+ const std::vector<WebSerializedScriptValue>& serialized_script_values,
+ const string16& idb_key_path,
+ std::vector<WebIDBKey>* values) {
+ LocalContext env;
+ WebIDBKeyPath web_idb_key_path = WebIDBKeyPath::create(idb_key_path);
+ bool error = web_idb_key_path.parseError() != 0;
+ // TODO(bulach): what to do when we have a parse error? For now, setting
+ // all values back as invalid and returning a boolean.
+ for (std::vector<WebSerializedScriptValue>::const_iterator i =
+ serialized_script_values.begin();
+ i != serialized_script_values.end(); ++i) {
+ if (error) {
+ values->push_back(WebIDBKey::createInvalid());
+ } else {
+ values->push_back(
+ WebIDBKey::createFromValueAndKeyPath(*i, web_idb_key_path));
+ }
+ }
+ return error;
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/idb_bindings.h b/webkit/glue/idb_bindings.h
new file mode 100644
index 0000000..074595d
--- /dev/null
+++ b/webkit/glue/idb_bindings.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.
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+namespace WebKit {
+class WebIDBKey;
+class WebSerializedScriptValue;
+}
+
+namespace webkit_glue {
+
+// Warning: this method holds a V8 lock, it should only be called within a
+// sandbox.
+bool IDBKeysFromValuesAndKeyPath(
+ const std::vector<WebKit::WebSerializedScriptValue>&
+ serialized_script_values,
+ const string16& idb_key_path,
+ std::vector<WebKit::WebIDBKey>* values);
+
+} // namespace webkit_glue
diff --git a/webkit/glue/inspector_strings.grd b/webkit/glue/inspector_strings.grd
index 9d634b7..22f147d 100644
--- a/webkit/glue/inspector_strings.grd
+++ b/webkit/glue/inspector_strings.grd
@@ -55,6 +55,7 @@ so we include the original license below:
<output filename="inspectorStrings_es.js" type="js_map_format" lang="es" />
<output filename="inspectorStrings_es-419.js" type="js_map_format" lang="es-419" />
<output filename="inspectorStrings_et.js" type="js_map_format" lang="et" />
+ <output filename="inspectorStrings_fa.js" type="js_map_format" lang="fa" />
<output filename="inspectorStrings_fi.js" type="js_map_format" lang="fi" />
<output filename="inspectorStrings_fil.js" type="js_map_format" lang="fil" />
<output filename="inspectorStrings_fr.js" type="js_map_format" lang="fr" />
diff --git a/webkit/glue/media/buffered_data_source.cc b/webkit/glue/media/buffered_data_source.cc
index dfac588..f4aad57 100644
--- a/webkit/glue/media/buffered_data_source.cc
+++ b/webkit/glue/media/buffered_data_source.cc
@@ -350,7 +350,9 @@ void BufferedResourceLoader::OnReceivedData(const char* data, int len) {
}
void BufferedResourceLoader::OnCompletedRequest(
- const URLRequestStatus& status, const std::string& security_info) {
+ const URLRequestStatus& status,
+ const std::string& security_info,
+ const base::Time& completion_time) {
DCHECK(bridge_.get());
// Saves the information that the request has completed.
diff --git a/webkit/glue/media/buffered_data_source.h b/webkit/glue/media/buffered_data_source.h
index 0dc2115..b520418 100644
--- a/webkit/glue/media/buffered_data_source.h
+++ b/webkit/glue/media/buffered_data_source.h
@@ -5,9 +5,7 @@
#ifndef WEBKIT_GLUE_MEDIA_BUFFERED_DATA_SOURCE_H_
#define WEBKIT_GLUE_MEDIA_BUFFERED_DATA_SOURCE_H_
-#include <algorithm>
#include <string>
-#include <vector>
#include "base/callback.h"
#include "base/lock.h"
@@ -118,9 +116,12 @@ class BufferedResourceLoader :
virtual void OnReceivedResponse(
const webkit_glue::ResourceLoaderBridge::ResponseInfo& 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);
+ virtual void OnCompletedRequest(
+ const URLRequestStatus& status,
+ const std::string& security_info,
+ const base::Time& completion_time);
GURL GetURLForDebugging() const { return url_; }
protected:
diff --git a/webkit/glue/media/buffered_data_source_unittest.cc b/webkit/glue/media/buffered_data_source_unittest.cc
index ce42437..7254c92 100644
--- a/webkit/glue/media/buffered_data_source_unittest.cc
+++ b/webkit/glue/media/buffered_data_source_unittest.cc
@@ -6,7 +6,9 @@
#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 "media/base/mock_filter_host.h"
#include "media/base/mock_filters.h"
@@ -51,7 +53,7 @@ ACTION_P(RequestCanceled, loader) {
URLRequestStatus status;
status.set_status(URLRequestStatus::CANCELED);
status.set_os_error(net::ERR_ABORTED);
- loader->OnCompletedRequest(status, "");
+ loader->OnCompletedRequest(status, "", base::Time());
}
class BufferedResourceLoaderTest : public testing::Test {
@@ -98,9 +100,9 @@ class BufferedResourceLoaderTest : public testing::Test {
void FullResponse(int64 instance_size) {
EXPECT_CALL(*this, StartCallback(net::OK));
ResourceLoaderBridge::ResponseInfo info;
- std::string header = StringPrintf("HTTP/1.1 200 OK\n"
- "Content-Length: %" PRId64,
- instance_size);
+ 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;
@@ -115,12 +117,12 @@ class BufferedResourceLoaderTest : public testing::Test {
EXPECT_CALL(*this, StartCallback(net::OK));
int64 content_length = last_position - first_position + 1;
ResourceLoaderBridge::ResponseInfo info;
- std::string header = StringPrintf("HTTP/1.1 206 Partial Content\n"
- "Content-Range: bytes "
- "%" PRId64 "-%" PRId64 "/%" PRId64,
- first_position,
- last_position,
- instance_size);
+ 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;
@@ -267,9 +269,9 @@ TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) {
.WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
ResourceLoaderBridge::ResponseInfo info;
- std::string header = StringPrintf("HTTP/1.1 206 Partial Content\n"
- "Content-Range: bytes %d-%d/%d",
- 1, 10, 1024);
+ 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;
@@ -315,7 +317,7 @@ TEST_F(BufferedResourceLoaderTest, BufferAndRead) {
.WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
URLRequestStatus status;
status.set_status(URLRequestStatus::SUCCESS);
- loader_->OnCompletedRequest(status, "");
+ loader_->OnCompletedRequest(status, "", base::Time());
// Try to read 10 from position 25 will just return with 5 bytes.
EXPECT_CALL(*this, ReadCallback(5));
@@ -361,7 +363,7 @@ TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) {
.WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
URLRequestStatus status;
status.set_status(URLRequestStatus::SUCCESS);
- loader_->OnCompletedRequest(status, "");
+ loader_->OnCompletedRequest(status, "", base::Time());
}
TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) {
@@ -379,7 +381,7 @@ TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) {
.WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
URLRequestStatus status;
status.set_status(URLRequestStatus::FAILED);
- loader_->OnCompletedRequest(status, "");
+ loader_->OnCompletedRequest(status, "", base::Time());
}
// Tests the logic of caching data to disk when media is paused.
diff --git a/webkit/glue/media/media_resource_loader_bridge_factory.cc b/webkit/glue/media/media_resource_loader_bridge_factory.cc
index 1961bcc..9d8d547 100644
--- a/webkit/glue/media/media_resource_loader_bridge_factory.cc
+++ b/webkit/glue/media/media_resource_loader_bridge_factory.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.
@@ -6,6 +6,7 @@
#include "base/format_macros.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
namespace {
@@ -61,12 +62,13 @@ const std::string MediaResourceLoaderBridgeFactory::GenerateHeaders (
if (first_byte_position > kPositionNotSpecified &&
last_byte_position > kPositionNotSpecified) {
if (first_byte_position <= last_byte_position) {
- header = StringPrintf("Range: bytes=%" PRId64 "-%" PRId64,
- 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 = StringPrintf("Range: bytes=%" PRId64 "-", first_byte_position);
+ header = base::StringPrintf("Range: bytes=%" PRId64 "-",
+ first_byte_position);
} else if (last_byte_position > kPositionNotSpecified) {
NOTIMPLEMENTED() << "Suffix range not implemented";
}
diff --git a/webkit/glue/media/media_resource_loader_bridge_factory.h b/webkit/glue/media/media_resource_loader_bridge_factory.h
index 6408949..5f09235 100644
--- a/webkit/glue/media/media_resource_loader_bridge_factory.h
+++ b/webkit/glue/media/media_resource_loader_bridge_factory.h
@@ -5,7 +5,7 @@
#ifndef WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
#define WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
-#include "testing/gtest/include/gtest/gtest_prod.h"
+#include "base/gtest_prod_util.h"
#include "webkit/glue/resource_loader_bridge.h"
namespace webkit_glue {
@@ -44,7 +44,8 @@ class MediaResourceLoaderBridgeFactory {
}
private:
- FRIEND_TEST(MediaResourceLoaderBridgeFactoryTest, GenerateHeaders);
+ FRIEND_TEST_ALL_PREFIXES(MediaResourceLoaderBridgeFactoryTest,
+ GenerateHeaders);
// Returns a range request header using parameters |first_byte_position| and
// |last_byte_position|.
diff --git a/webkit/glue/media/mock_media_resource_loader_bridge_factory.h b/webkit/glue/media/mock_media_resource_loader_bridge_factory.h
index 7bb27fe..3c0a3ae 100644
--- a/webkit/glue/media/mock_media_resource_loader_bridge_factory.h
+++ b/webkit/glue/media/mock_media_resource_loader_bridge_factory.h
@@ -1,9 +1,9 @@
-// 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.
-#ifndef WEBKIT_GLUE_MOCK_RESOURCE_LOADER_BRIDGE_H_
-#define WEBKIT_GLUE_MOCK_RESOURCE_LOADER_BRIDGE_H_
+#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"
@@ -33,4 +33,4 @@ class MockMediaResourceLoaderBridgeFactory
} // namespace webkit_glue
-#endif // WEBKIT_GLUE_MEDIA_MOCK_RESOURCE_LOADER_BRIDGE_H_
+#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 20bf0af..56deaeb 100644
--- a/webkit/glue/media/simple_data_source.cc
+++ b/webkit/glue/media/simple_data_source.cc
@@ -120,10 +120,6 @@ bool SimpleDataSource::IsStreaming() {
return false;
}
-void SimpleDataSource::OnDownloadProgress(uint64 position, uint64 size) {}
-
-void SimpleDataSource::OnUploadProgress(uint64 position, uint64 size) {}
-
bool SimpleDataSource::OnReceivedRedirect(
const GURL& new_url,
const webkit_glue::ResourceLoaderBridge::ResponseInfo& info,
@@ -146,7 +142,8 @@ void SimpleDataSource::OnReceivedData(const char* data, int len) {
}
void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info) {
+ const std::string& security_info,
+ const base::Time& completion_time) {
AutoLock auto_lock(lock_);
// It's possible this gets called after Stop(), in which case |host_| is no
// longer valid.
diff --git a/webkit/glue/media/simple_data_source.h b/webkit/glue/media/simple_data_source.h
index 577d973..d238f61 100644
--- a/webkit/glue/media/simple_data_source.h
+++ b/webkit/glue/media/simple_data_source.h
@@ -51,8 +51,7 @@ class SimpleDataSource : public media::DataSource,
virtual bool IsStreaming();
// webkit_glue::ResourceLoaderBridge::Peer implementation.
- virtual void OnDownloadProgress(uint64 position, uint64 size);
- virtual void OnUploadProgress(uint64 position, uint64 size);
+ virtual void OnUploadProgress(uint64 position, uint64 size) {}
virtual bool OnReceivedRedirect(
const GURL& new_url,
const webkit_glue::ResourceLoaderBridge::ResponseInfo& info,
@@ -61,9 +60,11 @@ class SimpleDataSource : public media::DataSource,
virtual void OnReceivedResponse(
const webkit_glue::ResourceLoaderBridge::ResponseInfo& 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 std::string& security_info,
+ const base::Time& completion_time);
virtual GURL GetURLForDebugging() const;
private:
diff --git a/webkit/glue/media/simple_data_source_unittest.cc b/webkit/glue/media/simple_data_source_unittest.cc
index e6acba9..d05bb72 100644
--- a/webkit/glue/media/simple_data_source_unittest.cc
+++ b/webkit/glue/media/simple_data_source_unittest.cc
@@ -105,7 +105,7 @@ class SimpleDataSourceTest : public testing::Test {
URLRequestStatus status;
status.set_status(URLRequestStatus::SUCCESS);
status.set_os_error(0);
- data_source_->OnCompletedRequest(status, "");
+ data_source_->OnCompletedRequest(status, "", base::Time());
// Let the tasks to be executed.
MessageLoop::current()->RunAllPending();
@@ -122,7 +122,7 @@ class SimpleDataSourceTest : public testing::Test {
URLRequestStatus status;
status.set_status(URLRequestStatus::FAILED);
status.set_os_error(100);
- data_source_->OnCompletedRequest(status, "");
+ data_source_->OnCompletedRequest(status, "", base::Time());
// Let the tasks to be executed.
MessageLoop::current()->RunAllPending();
diff --git a/webkit/glue/media/video_renderer_impl.cc b/webkit/glue/media/video_renderer_impl.cc
index 796d07f..6d7323d 100644
--- a/webkit/glue/media/video_renderer_impl.cc
+++ b/webkit/glue/media/video_renderer_impl.cc
@@ -95,6 +95,16 @@ void VideoRendererImpl::Paint(skia::PlatformCanvas* canvas,
PutCurrentFrame(video_frame);
}
+void VideoRendererImpl::GetCurrentFrame(
+ scoped_refptr<media::VideoFrame>* frame_out) {
+ VideoRendererBase::GetCurrentFrame(frame_out);
+}
+
+void VideoRendererImpl::PutCurrentFrame(
+ scoped_refptr<media::VideoFrame> frame) {
+ VideoRendererBase::PutCurrentFrame(frame);
+}
+
// CanFastPaint is a helper method to determine the conditions for fast
// painting. The conditions are:
// 1. No skew in canvas matrix.
diff --git a/webkit/glue/media/video_renderer_impl.h b/webkit/glue/media/video_renderer_impl.h
index 30f2e38..39ce1b2 100644
--- a/webkit/glue/media/video_renderer_impl.h
+++ b/webkit/glue/media/video_renderer_impl.h
@@ -27,6 +27,8 @@ class VideoRendererImpl : public WebVideoRenderer {
// WebVideoRenderer implementation.
virtual void SetRect(const gfx::Rect& rect);
virtual void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect);
+ virtual void GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out);
+ virtual void PutCurrentFrame(scoped_refptr<media::VideoFrame> frame);
// Static method for creating factory for this object.
static media::FilterFactory* CreateFactory(WebMediaPlayerImpl::Proxy* proxy,
diff --git a/webkit/glue/media/web_video_renderer.h b/webkit/glue/media/web_video_renderer.h
index 8bafb1a..d8b47ad 100644
--- a/webkit/glue/media/web_video_renderer.h
+++ b/webkit/glue/media/web_video_renderer.h
@@ -1,10 +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.
+// Copyright (c) 2010 The Chromium Authors. 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_WEB_VIDEO_RENDERER_H_
#define WEBKIT_GLUE_MEDIA_WEB_VIDEO_RENDERER_H_
+#include "media/base/video_frame.h"
#include "media/filters/video_renderer_base.h"
namespace webkit_glue {
@@ -30,6 +31,15 @@ class WebVideoRenderer : public media::VideoRendererBase {
virtual void Paint(skia::PlatformCanvas* canvas,
const gfx::Rect& dest_rect) = 0;
+ // Clients of this class (painter/compositor) should use GetCurrentFrame()
+ // obtain ownership of VideoFrame, it should always relinquish the ownership
+ // by use PutCurrentFrame(). Current frame is not guaranteed to be non-NULL.
+ // It expects clients to use color-fill the background if current frame
+ // is NULL. This could happen when before pipeline is pre-rolled or during
+ // pause/flush/seek.
+ virtual void GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out) {}
+ virtual void PutCurrentFrame(scoped_refptr<media::VideoFrame> frame) {}
+
private:
DISALLOW_COPY_AND_ASSIGN(WebVideoRenderer);
};
diff --git a/webkit/glue/mimetype_unittest.cc b/webkit/glue/mimetype_unittest.cc
index 152d20d..1c2e5f4 100644
--- a/webkit/glue/mimetype_unittest.cc
+++ b/webkit/glue/mimetype_unittest.cc
@@ -25,18 +25,17 @@ class MimeTypeTests : public TestShellTest {
void CheckMimeType(const char* mimetype, const std::wstring& expected) {
std::string path("contenttype?");
- GURL url = server_->TestServerPage(path + mimetype);
+ GURL url(test_server_.GetURL(path + mimetype));
LoadURL(url);
WebFrame* frame = test_shell_->webView()->mainFrame();
EXPECT_EQ(expected, webkit_glue::DumpDocumentText(frame));
}
- scoped_refptr<UnittestTestServer> server_;
+ UnittestTestServer test_server_;
};
TEST_F(MimeTypeTests, MimeTypeTests) {
- server_ = UnittestTestServer::CreateServer();
- ASSERT_TRUE(NULL != server_.get());
+ ASSERT_TRUE(test_server_.Start());
std::wstring expected_src(L"<html>\n<body>\n"
L"<p>HTML text</p>\n</body>\n</html>\n");
diff --git a/webkit/glue/mock_resource_loader_bridge.h b/webkit/glue/mock_resource_loader_bridge.h
index 7176e04..49c41ed 100644
--- a/webkit/glue/mock_resource_loader_bridge.h
+++ b/webkit/glue/mock_resource_loader_bridge.h
@@ -1,14 +1,15 @@
-// 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.
-#ifndef WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
-#define WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
+#ifndef WEBKIT_GLUE_MOCK_RESOURCE_LOADER_BRIDGE_H_
+#define WEBKIT_GLUE_MOCK_RESOURCE_LOADER_BRIDGE_H_
-#include "base/file_path.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 {
@@ -21,11 +22,12 @@ class MockResourceLoaderBridge : public webkit_glue::ResourceLoaderBridge {
}
MOCK_METHOD2(AppendDataToUpload, void(const char* data, int data_len));
- MOCK_METHOD4(AppendFileRangeToUpload,
+ 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());
@@ -39,4 +41,4 @@ class MockResourceLoaderBridge : public webkit_glue::ResourceLoaderBridge {
} // namespace webkit_glue
-#endif // WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
+#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 0b37050..4839a91 100644
--- a/webkit/glue/multipart_response_delegate.cc
+++ b/webkit/glue/multipart_response_delegate.cc
@@ -5,6 +5,7 @@
#include "webkit/glue/multipart_response_delegate.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "net/base/net_util.h"
#include "net/http/http_util.h"
@@ -125,13 +126,13 @@ void MultipartResponseDelegate::OnReceivedData(const char* data,
size_t boundary_pos;
while ((boundary_pos = FindBoundary()) != std::string::npos) {
- if (boundary_pos > 0 && client_) {
+ if (client_) {
// Strip out trailing \n\r characters in the buffer preceding the
// boundary on the same lines as Firefox.
size_t data_length = boundary_pos;
- if (data_[boundary_pos - 1] == '\n') {
+ if (boundary_pos > 0 && data_[boundary_pos - 1] == '\n') {
data_length--;
- if (data_[boundary_pos - 2] == '\r') {
+ if (boundary_pos > 1 && data_[boundary_pos - 2] == '\r') {
data_length--;
}
}
@@ -363,9 +364,9 @@ bool MultipartResponseDelegate::ReadContentRanges(
content_range.substr(byte_range_upper_bound_start_offset,
byte_range_upper_bound_characters);
- if (!StringToInt(byte_range_lower_bound, content_range_lower_bound))
+ if (!base::StringToInt(byte_range_lower_bound, content_range_lower_bound))
return false;
- if (!StringToInt(byte_range_upper_bound, content_range_upper_bound))
+ if (!base::StringToInt(byte_range_upper_bound, content_range_upper_bound))
return false;
return true;
}
diff --git a/webkit/glue/multipart_response_delegate_unittest.cc b/webkit/glue/multipart_response_delegate_unittest.cc
index 0433b52..ffacfb3 100644
--- a/webkit/glue/multipart_response_delegate_unittest.cc
+++ b/webkit/glue/multipart_response_delegate_unittest.cc
@@ -72,7 +72,7 @@ class MockWebURLLoaderClient : public WebURLLoaderClient {
data_.append(data, data_length);
}
- virtual void didFinishLoading(WebURLLoader*) {}
+ virtual void didFinishLoading(WebURLLoader*, double finishTime) {}
virtual void didFail(WebURLLoader*, const WebURLError&) {}
void Reset() {
@@ -97,11 +97,9 @@ TEST(MultipartResponseTest, Functions) {
WebURLResponse response;
response.initialize();
- response.setMIMEType(WebString::fromUTF8("multipart/x-mixed-replace"));
- response.setHTTPHeaderField(WebString::fromUTF8("Foo"),
- WebString::fromUTF8("Bar"));
- response.setHTTPHeaderField(WebString::fromUTF8("Content-type"),
- WebString::fromUTF8("text/plain"));
+ response.setMIMEType("multipart/x-mixed-replace");
+ response.setHTTPHeaderField("Foo", "Bar");
+ response.setHTTPHeaderField("Content-type", "text/plain");
MockWebURLLoaderClient client;
MultipartResponseDelegate delegate(&client, NULL, response, "bound");
MultipartResponseDelegateTester delegate_tester(&delegate);
@@ -203,11 +201,9 @@ TEST(MultipartResponseTest, Functions) {
TEST(MultipartResponseTest, MissingBoundaries) {
WebURLResponse response;
response.initialize();
- response.setMIMEType(WebString::fromUTF8("multipart/x-mixed-replace"));
- response.setHTTPHeaderField(WebString::fromUTF8("Foo"),
- WebString::fromUTF8("Bar"));
- response.setHTTPHeaderField(WebString::fromUTF8("Content-type"),
- WebString::fromUTF8("text/plain"));
+ response.setMIMEType("multipart/x-mixed-replace");
+ response.setHTTPHeaderField("Foo", "Bar");
+ response.setHTTPHeaderField("Content-type", "text/plain");
MockWebURLLoaderClient client;
MultipartResponseDelegate delegate(&client, NULL, response, "bound");
@@ -270,11 +266,9 @@ TEST(MultipartResponseTest, MalformedBoundary) {
WebURLResponse response;
response.initialize();
- response.setMIMEType(WebString::fromUTF8("multipart/x-mixed-replace"));
- response.setHTTPHeaderField(WebString::fromUTF8("Foo"),
- WebString::fromUTF8("Bar"));
- response.setHTTPHeaderField(WebString::fromUTF8("Content-type"),
- WebString::fromUTF8("text/plain"));
+ response.setMIMEType("multipart/x-mixed-replace");
+ response.setHTTPHeaderField("Foo", "Bar");
+ response.setHTTPHeaderField("Content-type", "text/plain");
MockWebURLLoaderClient client;
MultipartResponseDelegate delegate(&client, NULL, response, "--bound");
@@ -318,7 +312,7 @@ void VariousChunkSizesTest(const TestChunk chunks[], int chunks_size,
WebURLResponse response;
response.initialize();
- response.setMIMEType(WebString::fromUTF8("multipart/x-mixed-replace"));
+ response.setMIMEType("multipart/x-mixed-replace");
MockWebURLLoaderClient client;
MultipartResponseDelegate delegate(&client, NULL, response, "bound");
@@ -428,11 +422,37 @@ TEST(MultipartResponseTest, BreakInData) {
2, 2, "foof");
}
+TEST(MultipartResponseTest, SmallChunk) {
+ WebURLResponse response;
+ response.initialize();
+ response.setMIMEType("multipart/x-mixed-replace");
+ response.setHTTPHeaderField("Content-type", "text/plain");
+ MockWebURLLoaderClient client;
+ MultipartResponseDelegate delegate(&client, NULL, response, "bound");
+
+ // Test chunks of size 1, 2, and 0.
+ string data(
+ "--boundContent-type: text/plain\n\n"
+ "\n--boundContent-type: text/plain\n\n"
+ "\n\n--boundContent-type: text/plain\n\n"
+ "--boundContent-type: text/plain\n\n"
+ "end--bound--");
+ delegate.OnReceivedData(data.c_str(),
+ static_cast<int>(data.length()));
+ EXPECT_EQ(4, client.received_response_);
+ EXPECT_EQ(2, client.received_data_);
+ EXPECT_EQ(string("end"), client.data_);
+
+ delegate.OnCompletedRequest();
+ EXPECT_EQ(4, client.received_response_);
+ EXPECT_EQ(2, client.received_data_);
+}
+
TEST(MultipartResponseTest, MultipleBoundaries) {
// Test multiple boundaries back to back
WebURLResponse response;
response.initialize();
- response.setMIMEType(WebString::fromUTF8("multipart/x-mixed-replace"));
+ response.setMIMEType("multipart/x-mixed-replace");
MockWebURLLoaderClient client;
MultipartResponseDelegate delegate(&client, NULL, response, "bound");
@@ -450,12 +470,10 @@ TEST(MultipartResponseTest, MultipartByteRangeParsingTest) {
// Test multipart/byteranges based boundary parsing.
WebURLResponse response1;
response1.initialize();
- response1.setMIMEType(WebString::fromUTF8("multipart/x-mixed-replace"));
- response1.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
- WebString::fromUTF8("200"));
- response1.setHTTPHeaderField(
- WebString::fromUTF8("Content-type"),
- WebString::fromUTF8("multipart/byteranges; boundary=--bound--"));
+ response1.setMIMEType("multipart/x-mixed-replace");
+ response1.setHTTPHeaderField("Content-Length", "200");
+ response1.setHTTPHeaderField("Content-type",
+ "multipart/byteranges; boundary=--bound--");
std::string multipart_boundary;
bool result = MultipartResponseDelegate::ReadMultipartBoundary(
@@ -466,16 +484,12 @@ TEST(MultipartResponseTest, MultipartByteRangeParsingTest) {
WebURLResponse response2;
response2.initialize();
- response2.setMIMEType(WebString::fromUTF8("image/png"));
+ response2.setMIMEType("image/png");
- response2.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
- WebString::fromUTF8("300"));
- response2.setHTTPHeaderField(
- WebString::fromUTF8("Last-Modified"),
- WebString::fromUTF8("Mon, 04 Apr 2005 20:36:01 GMT"));
- response2.setHTTPHeaderField(
- WebString::fromUTF8("Date"),
- WebString::fromUTF8("Thu, 11 Sep 2008 18:21:42 GMT"));
+ response2.setHTTPHeaderField("Content-Length", "300");
+ response2.setHTTPHeaderField("Last-Modified",
+ "Mon, 04 Apr 2005 20:36:01 GMT");
+ response2.setHTTPHeaderField("Date", "Thu, 11 Sep 2008 18:21:42 GMT");
multipart_boundary.clear();
result = MultipartResponseDelegate::ReadMultipartBoundary(
@@ -484,19 +498,13 @@ TEST(MultipartResponseTest, MultipartByteRangeParsingTest) {
WebURLResponse response3;
response3.initialize();
- response3.setMIMEType(WebString::fromUTF8("multipart/byteranges"));
-
- response3.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
- WebString::fromUTF8("300"));
- response3.setHTTPHeaderField(
- WebString::fromUTF8("Last-Modified"),
- WebString::fromUTF8("Mon, 04 Apr 2005 20:36:01 GMT"));
- response3.setHTTPHeaderField(
- WebString::fromUTF8("Date"),
- WebString::fromUTF8("Thu, 11 Sep 2008 18:21:42 GMT"));
- response3.setHTTPHeaderField(
- WebString::fromUTF8("Content-type"),
- WebString::fromUTF8("multipart/byteranges"));
+ response3.setMIMEType("multipart/byteranges");
+
+ response3.setHTTPHeaderField("Content-Length", "300");
+ response3.setHTTPHeaderField("Last-Modified",
+ "Mon, 04 Apr 2005 20:36:01 GMT");
+ response3.setHTTPHeaderField("Date", "Thu, 11 Sep 2008 18:21:42 GMT");
+ response3.setHTTPHeaderField("Content-type", "multipart/byteranges");
multipart_boundary.clear();
result = MultipartResponseDelegate::ReadMultipartBoundary(
@@ -506,13 +514,10 @@ TEST(MultipartResponseTest, MultipartByteRangeParsingTest) {
WebURLResponse response4;
response4.initialize();
- response4.setMIMEType(WebString::fromUTF8("multipart/byteranges"));
- response4.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
- WebString::fromUTF8("200"));
- response4.setHTTPHeaderField(
- WebString::fromUTF8("Content-type"),
- WebString::fromUTF8(
- "multipart/byteranges; boundary=--bound--; charSet=utf8"));
+ response4.setMIMEType("multipart/byteranges");
+ response4.setHTTPHeaderField("Content-Length", "200");
+ response4.setHTTPHeaderField("Content-type",
+ "multipart/byteranges; boundary=--bound--; charSet=utf8");
multipart_boundary.clear();
@@ -523,13 +528,10 @@ TEST(MultipartResponseTest, MultipartByteRangeParsingTest) {
WebURLResponse response5;
response5.initialize();
- response5.setMIMEType(WebString::fromUTF8("multipart/byteranges"));
- response5.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
- WebString::fromUTF8("200"));
- response5.setHTTPHeaderField(
- WebString::fromUTF8("Content-type"),
- WebString::fromUTF8(
- "multipart/byteranges; boundary=\"--bound--\"; charSet=utf8"));
+ response5.setMIMEType("multipart/byteranges");
+ response5.setHTTPHeaderField("Content-Length", "200");
+ response5.setHTTPHeaderField("Content-type",
+ "multipart/byteranges; boundary=\"--bound--\"; charSet=utf8");
multipart_boundary.clear();
@@ -607,7 +609,7 @@ TEST(MultipartResponseTest, MultipartContentRangesTest) {
TEST(MultipartResponseTest, MultipartPayloadSet) {
WebURLResponse response;
response.initialize();
- response.setMIMEType(WebString::fromUTF8("multipart/x-mixed-replace"));
+ response.setMIMEType("multipart/x-mixed-replace");
MockWebURLLoaderClient client;
MultipartResponseDelegate delegate(&client, NULL, response, "bound");
diff --git a/webkit/glue/password_form.cc b/webkit/glue/password_form.cc
new file mode 100644
index 0000000..97777dc
--- /dev/null
+++ b/webkit/glue/password_form.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 "webkit/glue/password_form.h"
+
+namespace webkit_glue {
+
+PasswordForm::PasswordForm()
+ : scheme(SCHEME_HTML),
+ ssl_valid(false),
+ preferred(false),
+ blacklisted_by_user(false) {
+}
+
+PasswordForm::PasswordForm(const WebKit::WebPasswordFormData& web_password_form)
+ : scheme(SCHEME_HTML),
+ signon_realm(web_password_form.signonRealm.utf8()),
+ origin(web_password_form.origin),
+ action(web_password_form.action),
+ submit_element(web_password_form.submitElement),
+ username_element(web_password_form.userNameElement),
+ username_value(web_password_form.userNameValue),
+ password_element(web_password_form.passwordElement),
+ password_value(web_password_form.passwordValue),
+ old_password_element(web_password_form.oldPasswordElement),
+ old_password_value(web_password_form.oldPasswordValue),
+ ssl_valid(false),
+ preferred(false),
+ blacklisted_by_user(false) {
+}
+
+PasswordForm::~PasswordForm() {
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/password_form.h b/webkit/glue/password_form.h
index 57a54c1..c2967a4 100644
--- a/webkit/glue/password_form.h
+++ b/webkit/glue/password_form.h
@@ -32,9 +32,9 @@ namespace webkit_glue {
// about a particular "saved password entry" to our PasswordForm
// representation.
//
-// The field descriptions in the struct specification below are
-// intended to describe which fields are not strictly required when adding a saved
-// password entry to the database and how they can affect the matching process.
+// The field descriptions in the struct specification below are intended to
+// describe which fields are not strictly required when adding a saved password
+// entry to the database and how they can affect the matching process.
struct PasswordForm {
// Enum to differentiate between HTML form based authentication, and dialogs
@@ -135,29 +135,9 @@ struct PasswordForm {
// When parsing an HTML form, this is not used.
bool blacklisted_by_user;
- PasswordForm()
- : scheme(SCHEME_HTML),
- ssl_valid(false),
- preferred(false),
- blacklisted_by_user(false) {
- }
-
- PasswordForm(const WebKit::WebPasswordFormData& web_password_form)
- : scheme(SCHEME_HTML),
- signon_realm(web_password_form.signonRealm.utf8()),
- origin(web_password_form.origin),
- action(web_password_form.action),
- submit_element(web_password_form.submitElement),
- username_element(web_password_form.userNameElement),
- username_value(web_password_form.userNameValue),
- password_element(web_password_form.passwordElement),
- password_value(web_password_form.passwordValue),
- old_password_element(web_password_form.oldPasswordElement),
- old_password_value(web_password_form.oldPasswordValue),
- ssl_valid(false),
- preferred(false),
- blacklisted_by_user(false) {
- }
+ PasswordForm();
+ PasswordForm(const WebKit::WebPasswordFormData& web_password_form);
+ ~PasswordForm();
};
// Map username to PasswordForm* for convenience. See password_form_manager.h.
diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.cc b/webkit/glue/plugins/gtk_plugin_container_manager.cc
index 9d9ee4b..f26b44c 100644
--- a/webkit/glue/plugins/gtk_plugin_container_manager.cc
+++ b/webkit/glue/plugins/gtk_plugin_container_manager.cc
@@ -65,17 +65,21 @@ void GtkPluginContainerManager::MovePluginContainer(
return;
}
- DCHECK(GTK_WIDGET_REALIZED(widget));
gtk_widget_show(widget);
if (!move.rects_valid)
return;
- 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);
+ // 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.
diff --git a/webkit/glue/plugins/pepper_buffer.cc b/webkit/glue/plugins/pepper_buffer.cc
index 1c0bdd8..c3acef8 100644
--- a/webkit/glue/plugins/pepper_buffer.cc
+++ b/webkit/glue/plugins/pepper_buffer.cc
@@ -8,10 +8,10 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
+#include "third_party/ppapi/c/dev/ppb_buffer_dev.h"
#include "third_party/ppapi/c/pp_instance.h"
#include "third_party/ppapi/c/pp_module.h"
#include "third_party/ppapi/c/pp_resource.h"
-#include "third_party/ppapi/c/ppb_buffer.h"
#include "webkit/glue/plugins/pepper_plugin_instance.h"
#include "webkit/glue/plugins/pepper_plugin_module.h"
@@ -22,11 +22,11 @@ namespace {
PP_Resource Create(PP_Module module_id, int32_t size) {
PluginModule* module = PluginModule::FromPPModule(module_id);
if (!module)
- return NULL;
+ return 0;
scoped_refptr<Buffer> buffer(new Buffer(module));
if (!buffer->Init(size))
- return NULL;
+ return 0;
return buffer->GetReference();
}
@@ -57,7 +57,7 @@ void Unmap(PP_Resource resource) {
return buffer->Unmap();
}
-const PPB_Buffer ppb_buffer = {
+const PPB_Buffer_Dev ppb_buffer = {
&Create,
&IsBuffer,
&Describe,
@@ -76,7 +76,7 @@ Buffer::~Buffer() {
}
// static
-const PPB_Buffer* Buffer::GetInterface() {
+const PPB_Buffer_Dev* Buffer::GetInterface() {
return &ppb_buffer;
}
diff --git a/webkit/glue/plugins/pepper_buffer.h b/webkit/glue/plugins/pepper_buffer.h
index 5d750ec..2f20e55 100644
--- a/webkit/glue/plugins/pepper_buffer.h
+++ b/webkit/glue/plugins/pepper_buffer.h
@@ -7,9 +7,10 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "third_party/ppapi/c/ppb_buffer.h"
#include "webkit/glue/plugins/pepper_resource.h"
+struct PPB_Buffer_Dev;
+
namespace pepper {
class PluginInstance;
@@ -28,7 +29,7 @@ class Buffer : public Resource {
// Returns a pointer to the interface implementing PPB_Buffer that is
// exposed to the plugin.
- static const PPB_Buffer* GetInterface();
+ static const PPB_Buffer_Dev* GetInterface();
// Resource overrides.
Buffer* AsBuffer() { return this; }
diff --git a/webkit/glue/plugins/pepper_device_context_2d.cc b/webkit/glue/plugins/pepper_device_context_2d.cc
deleted file mode 100644
index 45ed9ee..0000000
--- a/webkit/glue/plugins/pepper_device_context_2d.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_device_context_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 "third_party/ppapi/c/pp_errors.h"
-#include "third_party/ppapi/c/pp_module.h"
-#include "third_party/ppapi/c/pp_rect.h"
-#include "third_party/ppapi/c/pp_resource.h"
-#include "third_party/ppapi/c/ppb_device_context_2d.h"
-#include "third_party/skia/include/core/SkBitmap.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/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;
-}
-
-PP_Resource Create(PP_Module module_id,
- const PP_Size* size,
- bool is_always_opaque) {
- PluginModule* module = PluginModule::FromPPModule(module_id);
- if (!module)
- return NULL;
-
- scoped_refptr<DeviceContext2D> context(new DeviceContext2D(module));
- if (!context->Init(size->width, size->height, is_always_opaque))
- return NULL;
- return context->GetReference();
-}
-
-bool IsDeviceContext2D(PP_Resource resource) {
- return !!Resource::GetAs<DeviceContext2D>(resource);
-}
-
-bool Describe(PP_Resource device_context,
- PP_Size* size,
- bool* is_always_opaque) {
- scoped_refptr<DeviceContext2D> context(
- Resource::GetAs<DeviceContext2D>(device_context));
- if (!context)
- return false;
- return context->Describe(size, is_always_opaque);
-}
-
-bool PaintImageData(PP_Resource device_context,
- PP_Resource image,
- const PP_Point* top_left,
- const PP_Rect* src_rect) {
- scoped_refptr<DeviceContext2D> context(
- Resource::GetAs<DeviceContext2D>(device_context));
- if (!context)
- return false;
- return context->PaintImageData(image, top_left, src_rect);
-}
-
-bool Scroll(PP_Resource device_context,
- const PP_Rect* clip_rect,
- const PP_Point* amount) {
- scoped_refptr<DeviceContext2D> context(
- Resource::GetAs<DeviceContext2D>(device_context));
- if (!context)
- return false;
- return context->Scroll(clip_rect, amount);
-}
-
-bool ReplaceContents(PP_Resource device_context, PP_Resource image) {
- scoped_refptr<DeviceContext2D> context(
- Resource::GetAs<DeviceContext2D>(device_context));
- if (!context)
- return false;
- return context->ReplaceContents(image);
-}
-
-int32_t Flush(PP_Resource device_context,
- PP_CompletionCallback callback) {
- scoped_refptr<DeviceContext2D> context(
- Resource::GetAs<DeviceContext2D>(device_context));
- if (!context)
- return PP_ERROR_BADRESOURCE;
- return context->Flush(callback);
-}
-
-const PPB_DeviceContext2D ppb_devicecontext2d = {
- &Create,
- &IsDeviceContext2D,
- &Describe,
- &PaintImageData,
- &Scroll,
- &ReplaceContents,
- &Flush
-};
-
-} // namespace
-
-struct DeviceContext2D::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;
-};
-
-DeviceContext2D::DeviceContext2D(PluginModule* module)
- : Resource(module),
- bound_instance_(NULL),
- flushed_any_data_(false),
- offscreen_flush_pending_(false) {
-}
-
-DeviceContext2D::~DeviceContext2D() {
-}
-
-// static
-const PPB_DeviceContext2D* DeviceContext2D::GetInterface() {
- return &ppb_devicecontext2d;
-}
-
-bool DeviceContext2D::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(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width, height, true) ||
- !image_data_->Map()) {
- image_data_ = NULL;
- return false;
- }
-
- return true;
-}
-
-bool DeviceContext2D::Describe(PP_Size* size, bool* is_always_opaque) {
- size->width = image_data_->width();
- size->height = image_data_->height();
- *is_always_opaque = false; // TODO(brettw) implement this.
- return true;
-}
-
-bool DeviceContext2D::PaintImageData(PP_Resource image,
- const PP_Point* top_left,
- const PP_Rect* src_rect) {
- if (!top_left)
- return false;
-
- scoped_refptr<ImageData> image_resource(Resource::GetAs<ImageData>(image));
- if (!image_resource)
- return false;
-
- QueuedOperation operation(QueuedOperation::PAINT);
- operation.paint_image = image_resource;
- if (!ValidateAndConvertRect(src_rect, image_resource->width(),
- image_resource->height(),
- &operation.paint_src_rect))
- return false;
-
- // 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 false;
- if (y64 + static_cast<int64>(operation.paint_src_rect.y()) < 0 ||
- y64 + static_cast<int64>(operation.paint_src_rect.bottom()) >
- image_data_->height())
- return false;
- operation.paint_x = top_left->x;
- operation.paint_y = top_left->y;
-
- queued_operations_.push_back(operation);
- return true;
-}
-
-bool DeviceContext2D::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 false;
-
- // 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() ||
- dx <= -image_data_->height() || dy >= image_data_->height())
- return true;
-
- operation.scroll_dx = dx;
- operation.scroll_dy = dy;
-
- queued_operations_.push_back(operation);
- return false;
-}
-
-bool DeviceContext2D::ReplaceContents(PP_Resource image) {
- scoped_refptr<ImageData> image_resource(Resource::GetAs<ImageData>(image));
- if (!image_resource)
- return false;
- if (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL)
- return false;
-
- if (image_resource->width() != image_data_->width() ||
- image_resource->height() != image_data_->height())
- return false;
-
- QueuedOperation operation(QueuedOperation::REPLACE);
- operation.replace_image = image_resource;
- queued_operations_.push_back(operation);
-
- return true;
-}
-
-int32_t DeviceContext2D::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;
-
- gfx::Rect changed_rect;
- 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;
- }
- changed_rect = changed_rect.Union(op_rect);
- }
- queued_operations_.clear();
- flushed_any_data_ = true;
-
- // 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_ && !changed_rect.IsEmpty())
- visible_changed_rect = bound_instance_->clip().Intersect(changed_rect);
-
- if (bound_instance_ && !visible_changed_rect.IsEmpty()) {
- unpainted_flush_callback_.Set(callback);
- bound_instance_->InvalidateRect(visible_changed_rect);
- } else {
- // There's nothing visible to invalidate so just schedule the callback to
- // execute in the next round of the message loop.
- ScheduleOffscreenCallback(FlushCallbackData(callback));
- }
- return PP_ERROR_WOULDBLOCK;
-}
-
-bool DeviceContext2D::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 (image_resource->format() != PP_IMAGEDATAFORMAT_BGRA_PREMUL)
- 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;
- skia::PlatformCanvas* dest_canvas = image_resource->mapped_canvas();
-
- 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()) };
-
- // 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 DeviceContext2D::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 DeviceContext2D::Paint(WebKit::WebCanvas* canvas,
- const gfx::Rect& plugin_rect,
- const gfx::Rect& paint_rect) {
- // We're guaranteed to have a mapped canvas since we mapped it in Init().
- const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap();
-
-#if defined(OS_MACOSX)
- SkAutoLockPixels lock(backing_bitmap);
-
- scoped_cftyperef<CGDataProviderRef> data_provider(
- CGDataProviderCreateWithData(
- NULL, backing_bitmap.getAddr32(0, 0),
- backing_bitmap.rowBytes() * backing_bitmap.height(), NULL));
- scoped_cftyperef<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();
-
- CGContextDrawImage(canvas, bounds, image);
- CGContextRestoreGState(canvas);
-#else
- 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()));
-#endif
-}
-
-void DeviceContext2D::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 DeviceContext2D::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 DeviceContext2D::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()) };
-
- // 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 DeviceContext2D::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 DeviceContext2D::ExecuteReplaceContents(ImageData* image,
- gfx::Rect* invalidated_rect) {
- image_data_->Swap(image);
- *invalidated_rect = gfx::Rect(0, 0,
- image_data_->width(), image_data_->height());
-}
-
-void DeviceContext2D::ScheduleOffscreenCallback(
- const FlushCallbackData& callback) {
- DCHECK(!HasPendingFlush());
- offscreen_flush_pending_ = true;
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &DeviceContext2D::ExecuteOffscreenCallback,
- callback));
-}
-
-void DeviceContext2D::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 DeviceContext2D::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_device_context_2d.h b/webkit/glue/plugins/pepper_device_context_2d.h
deleted file mode 100644
index 603bd52..0000000
--- a/webkit/glue/plugins/pepper_device_context_2d.h
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. 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_2D_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_2D_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "third_party/ppapi/c/pp_completion_callback.h"
-#include "third_party/ppapi/c/ppb_device_context_2d.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-typedef struct _ppb_DeviceContext2D PPB_DeviceContext2D;
-
-namespace gfx {
-class Rect;
-}
-
-namespace pepper {
-
-class ImageData;
-class PluginInstance;
-class PluginModule;
-
-class DeviceContext2D : public Resource {
- public:
- DeviceContext2D(PluginModule* module);
- virtual ~DeviceContext2D();
-
- // Returns a pointer to the interface implementing PPB_ImageData that is
- // exposed to the plugin.
- static const PPB_DeviceContext2D* GetInterface();
-
- bool Init(int width, int height, bool is_always_opaque);
-
- // Resource override.
- virtual DeviceContext2D* AsDeviceContext2D() { return this; }
-
- // PPB_DeviceContext2D functions.
- bool Describe(PP_Size* size, bool* is_always_opaque);
- bool PaintImageData(PP_Resource image,
- const PP_Point* top_left,
- const PP_Rect* src_rect);
- bool Scroll(const PP_Rect* clip_rect, const PP_Point* amount);
- bool ReplaceContents(PP_Resource image);
- 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 device context is currently
- // bound to, if any. If the device 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_;
-
- DISALLOW_COPY_AND_ASSIGN(DeviceContext2D);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_2D_H_
diff --git a/webkit/glue/plugins/pepper_directory_reader.cc b/webkit/glue/plugins/pepper_directory_reader.cc
index 93f19ee..bcf2533 100644
--- a/webkit/glue/plugins/pepper_directory_reader.cc
+++ b/webkit/glue/plugins/pepper_directory_reader.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "third_party/ppapi/c/pp_completion_callback.h"
+#include "third_party/ppapi/c/dev/ppb_directory_reader_dev.h"
#include "third_party/ppapi/c/pp_errors.h"
#include "webkit/glue/plugins/pepper_file_ref.h"
#include "webkit/glue/plugins/pepper_resource_tracker.h"
@@ -29,7 +30,7 @@ bool IsDirectoryReader(PP_Resource resource) {
}
int32_t GetNextEntry(PP_Resource reader_id,
- PP_DirectoryEntry* entry,
+ PP_DirectoryEntry_Dev* entry,
PP_CompletionCallback callback) {
scoped_refptr<DirectoryReader> reader(
Resource::GetAs<DirectoryReader>(reader_id));
@@ -39,7 +40,7 @@ int32_t GetNextEntry(PP_Resource reader_id,
return reader->GetNextEntry(entry, callback);
}
-const PPB_DirectoryReader ppb_directoryreader = {
+const PPB_DirectoryReader_Dev ppb_directoryreader = {
&Create,
&IsDirectoryReader,
&GetNextEntry
@@ -55,11 +56,11 @@ DirectoryReader::DirectoryReader(FileRef* directory_ref)
DirectoryReader::~DirectoryReader() {
}
-const PPB_DirectoryReader* DirectoryReader::GetInterface() {
+const PPB_DirectoryReader_Dev* DirectoryReader::GetInterface() {
return &ppb_directoryreader;
}
-int32_t DirectoryReader::GetNextEntry(PP_DirectoryEntry* entry,
+int32_t DirectoryReader::GetNextEntry(PP_DirectoryEntry_Dev* entry,
PP_CompletionCallback callback) {
NOTIMPLEMENTED(); // TODO(darin): Implement me!
return PP_ERROR_FAILED;
diff --git a/webkit/glue/plugins/pepper_directory_reader.h b/webkit/glue/plugins/pepper_directory_reader.h
index c477a3e..a56d546 100644
--- a/webkit/glue/plugins/pepper_directory_reader.h
+++ b/webkit/glue/plugins/pepper_directory_reader.h
@@ -5,9 +5,12 @@
#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_DIRECTORY_READER_H_
#define WEBKIT_GLUE_PLUGINS_PEPPER_DIRECTORY_READER_H_
-#include "third_party/ppapi/c/ppb_directory_reader.h"
#include "webkit/glue/plugins/pepper_resource.h"
+struct PP_CompletionCallback;
+struct PP_DirectoryEntry_Dev;
+struct PPB_DirectoryReader_Dev;
+
namespace pepper {
class FileRef;
@@ -19,13 +22,13 @@ class DirectoryReader : public Resource {
// Returns a pointer to the interface implementing PPB_DirectoryReader that
// is exposed to the plugin.
- static const PPB_DirectoryReader* GetInterface();
+ static const PPB_DirectoryReader_Dev* GetInterface();
// Resource overrides.
DirectoryReader* AsDirectoryReader() { return this; }
// PPB_DirectoryReader implementation.
- int32_t GetNextEntry(PP_DirectoryEntry* entry,
+ int32_t GetNextEntry(PP_DirectoryEntry_Dev* entry,
PP_CompletionCallback callback);
private:
diff --git a/webkit/glue/plugins/pepper_event_conversion.cc b/webkit/glue/plugins/pepper_event_conversion.cc
index 033ac93..b88041e 100644
--- a/webkit/glue/plugins/pepper_event_conversion.cc
+++ b/webkit/glue/plugins/pepper_event_conversion.cc
@@ -4,9 +4,13 @@
#include "webkit/glue/plugins/pepper_event_conversion.h"
+#include "base/i18n/char_iterator.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
-#include "third_party/ppapi/c/pp_event.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/utf_string_conversion_utils.h"
+#include "third_party/ppapi/c/pp_input_event.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
using WebKit::WebInputEvent;
@@ -15,153 +19,216 @@ using WebKit::WebMouseEvent;
using WebKit::WebMouseWheelEvent;
namespace {
-// Anonymous namespace for functions converting WebInputEvent to PP_Event and
-// back.
-PP_Event_Type ConvertEventTypes(WebInputEvent::Type wetype) {
+
+PP_InputEvent_Type ConvertEventTypes(WebInputEvent::Type wetype) {
switch (wetype) {
case WebInputEvent::MouseDown:
- return PP_EVENT_TYPE_MOUSEDOWN;
+ return PP_INPUTEVENT_TYPE_MOUSEDOWN;
case WebInputEvent::MouseUp:
- return PP_EVENT_TYPE_MOUSEUP;
+ return PP_INPUTEVENT_TYPE_MOUSEUP;
case WebInputEvent::MouseMove:
- return PP_EVENT_TYPE_MOUSEMOVE;
+ return PP_INPUTEVENT_TYPE_MOUSEMOVE;
case WebInputEvent::MouseEnter:
- return PP_EVENT_TYPE_MOUSEENTER;
+ return PP_INPUTEVENT_TYPE_MOUSEENTER;
case WebInputEvent::MouseLeave:
- return PP_EVENT_TYPE_MOUSELEAVE;
+ return PP_INPUTEVENT_TYPE_MOUSELEAVE;
case WebInputEvent::MouseWheel:
- return PP_EVENT_TYPE_MOUSEWHEEL;
+ return PP_INPUTEVENT_TYPE_MOUSEWHEEL;
case WebInputEvent::RawKeyDown:
- return PP_EVENT_TYPE_RAWKEYDOWN;
+ return PP_INPUTEVENT_TYPE_RAWKEYDOWN;
case WebInputEvent::KeyDown:
- return PP_EVENT_TYPE_KEYDOWN;
+ return PP_INPUTEVENT_TYPE_KEYDOWN;
case WebInputEvent::KeyUp:
- return PP_EVENT_TYPE_KEYUP;
+ return PP_INPUTEVENT_TYPE_KEYUP;
case WebInputEvent::Char:
- return PP_EVENT_TYPE_CHAR;
+ return PP_INPUTEVENT_TYPE_CHAR;
case WebInputEvent::Undefined:
default:
- return PP_EVENT_TYPE_UNDEFINED;
+ return PP_INPUTEVENT_TYPE_UNDEFINED;
}
}
-void BuildKeyEvent(const WebInputEvent* event, PP_Event* pp_event) {
- const WebKeyboardEvent* key_event =
- reinterpret_cast<const WebKeyboardEvent*>(event);
- pp_event->u.key.modifier = key_event->modifiers;
- pp_event->u.key.normalizedKeyCode = key_event->windowsKeyCode;
+// 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);
+ result.time_stamp_seconds = 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 BuildCharEvent(const WebInputEvent* event, PP_Event* pp_event) {
- const WebKeyboardEvent* key_event =
- reinterpret_cast<const WebKeyboardEvent*>(event);
- pp_event->u.character.modifier = key_event->modifiers;
- // For consistency, check that the sizes of the texts agree.
- DCHECK(sizeof(pp_event->u.character.text) == sizeof(key_event->text));
- DCHECK(sizeof(pp_event->u.character.unmodifiedText) ==
- sizeof(key_event->unmodifiedText));
- for (size_t i = 0; i < WebKeyboardEvent::textLengthCap; ++i) {
- pp_event->u.character.text[i] = key_event->text[i];
- pp_event->u.character.unmodifiedText[i] = key_event->unmodifiedText[i];
+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 BuildMouseEvent(const WebInputEvent* event, PP_Event* pp_event) {
- const WebMouseEvent* mouse_event =
- reinterpret_cast<const WebMouseEvent*>(event);
- pp_event->u.mouse.modifier = mouse_event->modifiers;
- pp_event->u.mouse.button = mouse_event->button;
- pp_event->u.mouse.x = mouse_event->x;
- pp_event->u.mouse.y = mouse_event->y;
- pp_event->u.mouse.clickCount = mouse_event->clickCount;
+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 BuildMouseWheelEvent(const WebInputEvent* event, PP_Event* pp_event) {
- const WebMouseWheelEvent* mouse_wheel_event =
- reinterpret_cast<const WebMouseWheelEvent*>(event);
- pp_event->u.wheel.modifier = mouse_wheel_event->modifiers;
- pp_event->u.wheel.deltaX = mouse_wheel_event->deltaX;
- pp_event->u.wheel.deltaY = mouse_wheel_event->deltaY;
- pp_event->u.wheel.wheelTicksX = mouse_wheel_event->wheelTicksX;
- pp_event->u.wheel.wheelTicksY = mouse_wheel_event->wheelTicksY;
- pp_event->u.wheel.scrollByPage = mouse_wheel_event->scrollByPage;
+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 = !!mouse_wheel_event.scrollByPage;
+ pp_events->push_back(result);
}
-WebKeyboardEvent* BuildKeyEvent(const PP_Event& event) {
+WebKeyboardEvent* BuildKeyEvent(const PP_InputEvent& event) {
WebKeyboardEvent* key_event = new WebKeyboardEvent();
switch (event.type) {
- case PP_EVENT_TYPE_RAWKEYDOWN:
+ case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
key_event->type = WebInputEvent::RawKeyDown;
break;
- case PP_EVENT_TYPE_KEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
key_event->type = WebInputEvent::KeyDown;
break;
- case PP_EVENT_TYPE_KEYUP:
+ case PP_INPUTEVENT_TYPE_KEYUP:
key_event->type = WebInputEvent::KeyUp;
break;
+ default:
+ NOTREACHED();
}
key_event->timeStampSeconds = event.time_stamp_seconds;
key_event->modifiers = event.u.key.modifier;
- key_event->windowsKeyCode = event.u.key.normalizedKeyCode;
+ key_event->windowsKeyCode = event.u.key.key_code;
return key_event;
}
-WebKeyboardEvent* BuildCharEvent(const PP_Event& event) {
+WebKeyboardEvent* BuildCharEvent(const PP_InputEvent& event) {
WebKeyboardEvent* key_event = new WebKeyboardEvent();
key_event->type = WebInputEvent::Char;
key_event->timeStampSeconds = event.time_stamp_seconds;
key_event->modifiers = event.u.character.modifier;
- // For consistency, check that the sizes of the texts agree.
- DCHECK(sizeof(event.u.character.text) == sizeof(key_event->text));
- DCHECK(sizeof(event.u.character.unmodifiedText) ==
- sizeof(key_event->unmodifiedText));
- for (size_t i = 0; i < WebKeyboardEvent::textLengthCap; ++i) {
- key_event->text[i] = event.u.character.text[i];
- key_event->unmodifiedText[i] = event.u.character.unmodifiedText[i];
- }
+
+ // 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_Event& event) {
+WebMouseEvent* BuildMouseEvent(const PP_InputEvent& event) {
WebMouseEvent* mouse_event = new WebMouseEvent();
switch (event.type) {
- case PP_EVENT_TYPE_MOUSEDOWN:
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN:
mouse_event->type = WebInputEvent::MouseDown;
break;
- case PP_EVENT_TYPE_MOUSEUP:
+ case PP_INPUTEVENT_TYPE_MOUSEUP:
mouse_event->type = WebInputEvent::MouseUp;
break;
- case PP_EVENT_TYPE_MOUSEMOVE:
+ case PP_INPUTEVENT_TYPE_MOUSEMOVE:
mouse_event->type = WebInputEvent::MouseMove;
break;
- case PP_EVENT_TYPE_MOUSEENTER:
+ case PP_INPUTEVENT_TYPE_MOUSEENTER:
mouse_event->type = WebInputEvent::MouseEnter;
break;
- case PP_EVENT_TYPE_MOUSELEAVE:
+ case PP_INPUTEVENT_TYPE_MOUSELEAVE:
mouse_event->type = WebInputEvent::MouseLeave;
break;
+ default:
+ NOTREACHED();
}
mouse_event->timeStampSeconds = event.time_stamp_seconds;
mouse_event->modifiers = event.u.mouse.modifier;
mouse_event->button =
static_cast<WebMouseEvent::Button>(event.u.mouse.button);
- mouse_event->x = event.u.mouse.x;
- mouse_event->y = event.u.mouse.y;
- mouse_event->clickCount = event.u.mouse.clickCount;
+ 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_Event& 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_seconds;
mouse_wheel_event->modifiers = event.u.wheel.modifier;
- mouse_wheel_event->deltaX = event.u.wheel.deltaX;
- mouse_wheel_event->deltaY = event.u.wheel.deltaY;
- mouse_wheel_event->wheelTicksX = event.u.wheel.wheelTicksX;
- mouse_wheel_event->wheelTicksY = event.u.wheel.wheelTicksY;
- mouse_wheel_event->scrollByPage = event.u.wheel.scrollByPage;
+ 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;
}
@@ -169,64 +236,58 @@ WebMouseWheelEvent* BuildMouseWheelEvent(const PP_Event& event) {
namespace pepper {
-PP_Event* CreatePP_Event(const WebInputEvent& event) {
- scoped_ptr<PP_Event> pp_event(new PP_Event);
+void CreatePPEvent(const WebInputEvent& event,
+ std::vector<PP_InputEvent>* pp_events) {
+ pp_events->clear();
- pp_event->type = ConvertEventTypes(event.type);
- pp_event->size = sizeof(pp_event);
- pp_event->time_stamp_seconds = event.timeStampSeconds;
- switch (pp_event->type) {
- case PP_EVENT_TYPE_UNDEFINED:
- return NULL;
- case PP_EVENT_TYPE_MOUSEDOWN:
- case PP_EVENT_TYPE_MOUSEUP:
- case PP_EVENT_TYPE_MOUSEMOVE:
- case PP_EVENT_TYPE_MOUSEENTER:
- case PP_EVENT_TYPE_MOUSELEAVE:
- BuildMouseEvent(&event, pp_event.get());
+ switch (event.type) {
+ case WebInputEvent::MouseDown:
+ case WebInputEvent::MouseUp:
+ case WebInputEvent::MouseMove:
+ case WebInputEvent::MouseEnter:
+ case WebInputEvent::MouseLeave:
+ AppendMouseEvent(event, pp_events);
break;
- case PP_EVENT_TYPE_MOUSEWHEEL:
- BuildMouseWheelEvent(&event, pp_event.get());
+ case WebInputEvent::MouseWheel:
+ AppendMouseWheelEvent(event, pp_events);
break;
- case PP_EVENT_TYPE_RAWKEYDOWN:
- case PP_EVENT_TYPE_KEYDOWN:
- case PP_EVENT_TYPE_KEYUP:
- BuildKeyEvent(&event, pp_event.get());
+ case WebInputEvent::RawKeyDown:
+ case WebInputEvent::KeyDown:
+ case WebInputEvent::KeyUp:
+ AppendKeyEvent(event, pp_events);
break;
- case PP_EVENT_TYPE_CHAR:
- BuildCharEvent(&event, pp_event.get());
+ case WebInputEvent::Char:
+ AppendCharEvent(event, pp_events);
+ break;
+ case WebInputEvent::Undefined:
+ default:
break;
}
-
- return pp_event.release();
}
-WebInputEvent* CreateWebInputEvent(const PP_Event& event) {
+WebInputEvent* CreateWebInputEvent(const PP_InputEvent& event) {
scoped_ptr<WebInputEvent> web_input_event;
switch (event.type) {
- case PP_EVENT_TYPE_UNDEFINED:
+ case PP_INPUTEVENT_TYPE_UNDEFINED:
return NULL;
- case PP_EVENT_TYPE_MOUSEDOWN:
- case PP_EVENT_TYPE_MOUSEUP:
- case PP_EVENT_TYPE_MOUSEMOVE:
- case PP_EVENT_TYPE_MOUSEENTER:
- case PP_EVENT_TYPE_MOUSELEAVE:
+ 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_EVENT_TYPE_MOUSEWHEEL:
+ case PP_INPUTEVENT_TYPE_MOUSEWHEEL:
web_input_event.reset(BuildMouseWheelEvent(event));
break;
- case PP_EVENT_TYPE_RAWKEYDOWN:
- case PP_EVENT_TYPE_KEYDOWN:
- case PP_EVENT_TYPE_KEYUP:
+ case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYDOWN:
+ case PP_INPUTEVENT_TYPE_KEYUP:
web_input_event.reset(BuildKeyEvent(event));
break;
- case PP_EVENT_TYPE_CHAR:
+ case PP_INPUTEVENT_TYPE_CHAR:
web_input_event.reset(BuildCharEvent(event));
break;
- case PP_EVENT_TYPE_FOCUS:
- // NOTIMPLEMENTED();
- return NULL;
}
return web_input_event.release();
diff --git a/webkit/glue/plugins/pepper_event_conversion.h b/webkit/glue/plugins/pepper_event_conversion.h
index 2d699cd..9eab3e4 100644
--- a/webkit/glue/plugins/pepper_event_conversion.h
+++ b/webkit/glue/plugins/pepper_event_conversion.h
@@ -5,7 +5,9 @@
#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_EVENT_H_
#define WEBKIT_GLUE_PLUGINS_PEPPER_EVENT_H_
-typedef struct _pp_Event PP_Event;
+#include <vector>
+
+struct PP_InputEvent;
namespace WebKit {
class WebInputEvent;
@@ -13,13 +15,15 @@ class WebInputEvent;
namespace pepper {
-// Creates a PP_Event from the given WebInputEvent. If it fails, returns NULL.
-// The caller owns the created object on success.
-PP_Event* CreatePP_Event(const WebKit::WebInputEvent& event);
+// 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_Event. If it fails, returns NULL.
-// The caller owns the created object on success.
-WebKit::WebInputEvent* CreateWebInputEvent(const PP_Event& event);
+// 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
diff --git a/webkit/glue/plugins/pepper_file_chooser.cc b/webkit/glue/plugins/pepper_file_chooser.cc
index 5e45600..138efd7 100644
--- a/webkit/glue/plugins/pepper_file_chooser.cc
+++ b/webkit/glue/plugins/pepper_file_chooser.cc
@@ -4,19 +4,35 @@
#include "webkit/glue/plugins/pepper_file_chooser.h"
+#include <string>
+#include <vector>
+
#include "base/logging.h"
#include "third_party/ppapi/c/pp_completion_callback.h"
#include "third_party/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_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* options) {
+ const PP_FileChooserOptions_Dev* options) {
PluginInstance* instance = PluginInstance::FromPPInstance(instance_id);
if (!instance)
return 0;
@@ -51,38 +67,89 @@ PP_Resource GetNextChosenFile(PP_Resource chooser_id) {
return file_ref->GetReference();
}
-const PPB_FileChooser ppb_filechooser = {
+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* options)
+ const PP_FileChooserOptions_Dev* options)
: Resource(instance->module()),
+ delegate_(instance->delegate()),
mode_(options->mode),
- accept_mime_types_(options->accept_mime_types) {
+ accept_mime_types_(options->accept_mime_types),
+ completion_callback_() {
}
FileChooser::~FileChooser() {
}
// static
-const PPB_FileChooser* FileChooser::GetInterface() {
+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(
+ new FileRef(module(), PP_FILESYSTEMTYPE_LOCALPERSISTENT, *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) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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() {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return NULL;
+ 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
index 8474188..eafdd0e 100644
--- a/webkit/glue/plugins/pepper_file_chooser.h
+++ b/webkit/glue/plugins/pepper_file_chooser.h
@@ -6,33 +6,45 @@
#define WEBKIT_GLUE_PLUGINS_PEPPER_FILE_CHOOSER_H_
#include <string>
+#include <vector>
-#include "third_party/ppapi/c/ppb_file_chooser.h"
+#include "base/scoped_ptr.h"
+#include "third_party/ppapi/c/dev/ppb_file_chooser_dev.h"
+#include "third_party/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* options);
+ 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* GetInterface();
+ 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:
- PP_FileChooserMode mode_;
+ 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
diff --git a/webkit/glue/plugins/pepper_file_io.cc b/webkit/glue/plugins/pepper_file_io.cc
index 46f7276..9090f88 100644
--- a/webkit/glue/plugins/pepper_file_io.cc
+++ b/webkit/glue/plugins/pepper_file_io.cc
@@ -4,12 +4,19 @@
#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 "third_party/ppapi/c/dev/ppb_file_io_dev.h"
+#include "third_party/ppapi/c/dev/ppb_file_io_trusted_dev.h"
#include "third_party/ppapi/c/pp_completion_callback.h"
#include "third_party/ppapi/c/pp_errors.h"
-#include "third_party/ppapi/c/ppb_file_io.h"
-#include "third_party/ppapi/c/ppb_file_io_trusted.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"
@@ -46,12 +53,11 @@ int32_t Open(PP_Resource file_io_id,
}
int32_t Query(PP_Resource file_io_id,
- PP_FileInfo* info,
+ 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);
}
@@ -62,7 +68,6 @@ int32_t Touch(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->Touch(last_access_time, last_modified_time, callback);
}
@@ -74,7 +79,6 @@ int32_t Read(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->Read(offset, buffer, bytes_to_read, callback);
}
@@ -86,7 +90,6 @@ int32_t Write(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->Write(offset, buffer, bytes_to_write, callback);
}
@@ -96,7 +99,6 @@ int32_t SetLength(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->SetLength(length, callback);
}
@@ -105,7 +107,6 @@ int32_t Flush(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->Flush(callback);
}
@@ -113,11 +114,10 @@ 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 ppb_fileio = {
+const PPB_FileIO_Dev ppb_fileio = {
&Create,
&IsFileIO,
&Open,
@@ -134,7 +134,6 @@ 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();
}
@@ -145,7 +144,6 @@ int32_t WillWrite(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->WillWrite(offset, bytes_to_write, callback);
}
@@ -155,101 +153,281 @@ int32_t WillSetLength(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->WillSetLength(length, callback);
}
-const PPB_FileIOTrusted ppb_fileiotrusted = {
+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) {
+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* FileIO::GetInterface() {
+const PPB_FileIO_Dev* FileIO::GetInterface() {
return &ppb_fileio;
}
// static
-const PPB_FileIOTrusted* FileIO::GetTrustedInterface() {
+const PPB_FileIOTrusted_Dev* FileIO::GetTrustedInterface() {
return &ppb_fileiotrusted;
}
int32_t FileIO::Open(FileRef* file_ref,
int32_t open_flags,
PP_CompletionCallback callback) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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(flags & PP_FILEOPENFLAG_WRITE);
+ flags |= base::PLATFORM_FILE_TRUNCATE;
+ }
+
+ 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->file_system_type();
+ if (!delegate_->AsyncOpenFile(
+ file_ref->system_path(), flags,
+ callback_factory_.NewCallback(&FileIO::AsyncOpenFileCallback)))
+ return PP_ERROR_FAILED;
+
+ return PP_ERROR_WOULDBLOCK;
}
-int32_t FileIO::Query(PP_FileInfo* info,
+int32_t FileIO::Query(PP_FileInfo_Dev* info,
PP_CompletionCallback callback) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ 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() {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
+ if (file_ != base::kInvalidPlatformFileValue)
+ base::FileUtilProxy::Close(
+ delegate_->GetFileThreadMessageLoopProxy(), file_, NULL);
}
int32_t FileIO::GetOSFileDescriptor() {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+#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) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ // TODO(dumi): implement me
+ return PP_OK;
}
int32_t FileIO::WillSetLength(int64_t length,
PP_CompletionCallback callback) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return PP_ERROR_FAILED;
+ // 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
index 4af6f2b..bda8ed6 100644
--- a/webkit/glue/plugins/pepper_file_io.h
+++ b/webkit/glue/plugins/pepper_file_io.h
@@ -5,13 +5,20 @@
#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 "third_party/ppapi/c/dev/pp_file_info_dev.h"
+#include "third_party/ppapi/c/pp_completion_callback.h"
#include "third_party/ppapi/c/pp_time.h"
+#include "webkit/glue/plugins/pepper_plugin_delegate.h"
#include "webkit/glue/plugins/pepper_resource.h"
-typedef struct _pp_CompletionCallback PP_CompletionCallback;
-typedef struct _pp_FileInfo PP_FileInfo;
-typedef struct _ppb_FileIO PPB_FileIO;
-typedef struct _ppb_FileIOTrusted PPB_FileIOTrusted;
+struct PP_CompletionCallback;
+struct PP_FileInfo_Dev;
+struct PPB_FileIO_Dev;
+struct PPB_FileIOTrusted_Dev;
namespace pepper {
@@ -24,11 +31,11 @@ class FileIO : public Resource {
// Returns a pointer to the interface implementing PPB_FileIO that is exposed
// to the plugin.
- static const PPB_FileIO* GetInterface();
+ 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* GetTrustedInterface();
+ static const PPB_FileIOTrusted_Dev* GetTrustedInterface();
// Resource overrides.
FileIO* AsFileIO() { return this; }
@@ -37,7 +44,7 @@ class FileIO : public Resource {
int32_t Open(FileRef* file_ref,
int32_t open_flags,
PP_CompletionCallback callback);
- int32_t Query(PP_FileInfo* info,
+ int32_t Query(PP_FileInfo_Dev* info,
PP_CompletionCallback callback);
int32_t Touch(PP_Time last_access_time,
PP_Time last_modified_time,
@@ -62,6 +69,25 @@ class FileIO : public Resource {
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
diff --git a/webkit/glue/plugins/pepper_file_ref.cc b/webkit/glue/plugins/pepper_file_ref.cc
index 9b42cff..7cb65a4 100644
--- a/webkit/glue/plugins/pepper_file_ref.cc
+++ b/webkit/glue/plugins/pepper_file_ref.cc
@@ -4,6 +4,8 @@
#include "webkit/glue/plugins/pepper_file_ref.h"
+#include "base/base_paths.h"
+#include "base/path_service.h"
#include "base/string_util.h"
#include "webkit/glue/plugins/pepper_plugin_instance.h"
#include "webkit/glue/plugins/pepper_var.h"
@@ -33,7 +35,7 @@ void TrimTrailingSlash(std::string* path) {
}
PP_Resource CreateFileRef(PP_Instance instance_id,
- PP_FileSystemType fs_type,
+ PP_FileSystemType_Dev fs_type,
const char* path) {
PluginInstance* instance = PluginInstance::FromPPInstance(instance_id);
if (!instance)
@@ -65,11 +67,10 @@ bool IsFileRef(PP_Resource resource) {
return !!Resource::GetAs<FileRef>(resource);
}
-PP_FileSystemType GetFileSystemType(PP_Resource file_ref_id) {
+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->file_system_type();
}
@@ -77,8 +78,7 @@ PP_Var GetName(PP_Resource file_ref_id) {
scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
if (!file_ref)
return PP_MakeVoid();
-
- return StringToPPVar(file_ref->GetName());
+ return StringVar::StringToPPVar(file_ref->module(), file_ref->GetName());
}
PP_Var GetPath(PP_Resource file_ref_id) {
@@ -89,7 +89,7 @@ PP_Var GetPath(PP_Resource file_ref_id) {
if (file_ref->file_system_type() == PP_FILESYSTEMTYPE_EXTERNAL)
return PP_MakeVoid();
- return StringToPPVar(file_ref->path());
+ return StringVar::StringToPPVar(file_ref->module(), file_ref->path());
}
PP_Resource GetParent(PP_Resource file_ref_id) {
@@ -107,7 +107,7 @@ PP_Resource GetParent(PP_Resource file_ref_id) {
return parent_ref->GetReference();
}
-const PPB_FileRef ppb_fileref = {
+const PPB_FileRef_Dev ppb_fileref = {
&CreatePersistentFileRef,
&CreateTemporaryFileRef,
&IsFileRef,
@@ -120,7 +120,7 @@ const PPB_FileRef ppb_fileref = {
} // namespace
FileRef::FileRef(PluginModule* module,
- PP_FileSystemType file_system_type,
+ PP_FileSystemType_Dev file_system_type,
const std::string& validated_path,
const std::string& origin)
: Resource(module),
@@ -130,11 +130,18 @@ FileRef::FileRef(PluginModule* module,
// TODO(darin): Need to initialize system_path_.
}
+FileRef::FileRef(PluginModule* module,
+ const FilePath& external_file_path)
+ : Resource(module),
+ system_path_(external_file_path),
+ fs_type_(PP_FILESYSTEMTYPE_EXTERNAL) {
+}
+
FileRef::~FileRef() {
}
// static
-const PPB_FileRef* FileRef::GetInterface() {
+const PPB_FileRef_Dev* FileRef::GetInterface() {
return &ppb_fileref;
}
@@ -166,4 +173,21 @@ scoped_refptr<FileRef> FileRef::GetParent() {
return parent_ref;
}
+// static
+FileRef* FileRef::GetInaccessibleFileRef(PluginModule* module) {
+ FilePath inaccessible_path;
+ if (!PathService::Get(base::FILE_MODULE, &inaccessible_path))
+ return NULL;
+ return new FileRef(module, inaccessible_path);
+}
+
+// static
+FileRef* FileRef::GetNonexistentFileRef(PluginModule* module) {
+ FilePath dir_module_path;
+ if (!PathService::Get(base::DIR_MODULE, &dir_module_path))
+ return NULL;
+ return new FileRef(module, dir_module_path.Append(
+ FILE_PATH_LITERAL("nonexistent_file")));
+}
+
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_file_ref.h b/webkit/glue/plugins/pepper_file_ref.h
index 34e4c3e..0ab0e65 100644
--- a/webkit/glue/plugins/pepper_file_ref.h
+++ b/webkit/glue/plugins/pepper_file_ref.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/file_path.h"
-#include "third_party/ppapi/c/ppb_file_ref.h"
+#include "third_party/ppapi/c/dev/ppb_file_ref_dev.h"
#include "webkit/glue/plugins/pepper_resource.h"
namespace pepper {
@@ -18,14 +18,16 @@ class PluginModule;
class FileRef : public Resource {
public:
FileRef(PluginModule* module,
- PP_FileSystemType file_system_type,
+ PP_FileSystemType_Dev file_system_type,
const std::string& validated_path,
const std::string& origin);
+ 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* GetInterface();
+ static const PPB_FileRef_Dev* GetInterface();
// Resource overrides.
FileRef* AsFileRef() { return this; }
@@ -34,7 +36,7 @@ class FileRef : public Resource {
std::string GetName() const;
scoped_refptr<FileRef> GetParent();
- PP_FileSystemType file_system_type() const { return fs_type_; }
+ PP_FileSystemType_Dev file_system_type() const { return fs_type_; }
// Returns the virtual path (i.e., the path that the pepper plugin sees)
// corresponding to this file.
@@ -43,9 +45,17 @@ class FileRef : public Resource {
// Returns the system path corresponding to this file.
const FilePath& system_path() const { return system_path_; }
+ // Returns a FileRef instance pointing to a file that should not be
+ // accessible by the plugin. Should be used for testing only.
+ static FileRef* GetInaccessibleFileRef(PluginModule* module);
+
+ // Returns a FileRef instance pointing to a nonexistent file.
+ // Should be used for testing only.
+ static FileRef* GetNonexistentFileRef(PluginModule* module);
+
private:
FilePath system_path_;
- PP_FileSystemType fs_type_;
+ PP_FileSystemType_Dev fs_type_;
std::string path_; // UTF-8 encoded.
std::string origin_;
};
diff --git a/webkit/glue/plugins/pepper_file_system.cc b/webkit/glue/plugins/pepper_file_system.cc
index 678399e..82a2fc8 100644
--- a/webkit/glue/plugins/pepper_file_system.cc
+++ b/webkit/glue/plugins/pepper_file_system.cc
@@ -4,45 +4,235 @@
#include "webkit/glue/plugins/pepper_file_system.h"
+#include "base/logging.h"
+#include "base/ref_counted.h"
+#include "base/weak_ptr.h"
+#include "third_party/ppapi/c/dev/ppb_file_system_dev.h"
#include "third_party/ppapi/c/pp_completion_callback.h"
-#include "third_party/ppapi/c/pp_errors.h"
-#include "third_party/ppapi/c/ppb_file_system.h"
+#include "third_party/ppapi/c/pp_time.h"
+#include "webkit/fileapi/file_system_callback_dispatcher.h"
+#include "webkit/glue/plugins/pepper_resource.h"
+#include "webkit/glue/plugins/pepper_error_util.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_plugin_module.h"
+#include "webkit/glue/plugins/pepper_resource.h"
namespace pepper {
namespace {
-int32_t MakeDirectory(PP_Resource directory_ref,
+// Instances of this class are deleted when RunCallback() is called.
+class StatusCallback : public fileapi::FileSystemCallbackDispatcher {
+ public:
+ StatusCallback(base::WeakPtr<pepper::PluginModule> module,
+ PP_CompletionCallback callback)
+ : module_(module),
+ callback_(callback) {
+ }
+
+ // FileSystemCallbackDispatcher implementation.
+ virtual void DidSucceed() {
+ RunCallback(base::PLATFORM_FILE_OK);
+ }
+
+ virtual void DidReadMetadata(const base::PlatformFileInfo&) {
+ NOTREACHED();
+ }
+
+ virtual void DidReadDirectory(
+ const std::vector<base::file_util_proxy::Entry>&, bool) {
+ NOTREACHED();
+ }
+
+ virtual void DidOpenFileSystem(const std::string&, const FilePath&) {
+ NOTREACHED();
+ }
+
+ virtual void DidFail(base::PlatformFileError error_code) {
+ RunCallback(error_code);
+ }
+
+ private:
+ void RunCallback(base::PlatformFileError error_code) {
+ if (!module_.get() || !callback_.func)
+ return;
+
+ PP_RunCompletionCallback(
+ &callback_, pepper::PlatformFileErrorToPepperError(error_code));
+
+ delete this;
+ }
+
+ base::WeakPtr<pepper::PluginModule> module_;
+ PP_CompletionCallback callback_;
+};
+
+// Instances of this class are deleted when RunCallback() is called.
+class QueryInfoCallback : public fileapi::FileSystemCallbackDispatcher {
+ public:
+ QueryInfoCallback(base::WeakPtr<pepper::PluginModule> module,
+ PP_CompletionCallback callback,
+ PP_FileInfo_Dev* info,
+ PP_FileSystemType_Dev file_system_type)
+ : module_(module),
+ callback_(callback),
+ info_(info),
+ file_system_type_(file_system_type) {
+ DCHECK(info_);
+ }
+
+ // FileSystemCallbackDispatcher implementation.
+ virtual void DidSucceed() {
+ NOTREACHED();
+ }
+
+ virtual void DidReadMetadata(const base::PlatformFileInfo& file_info) {
+ RunCallback(base::PLATFORM_FILE_OK, file_info);
+ }
+
+ virtual void DidReadDirectory(
+ const std::vector<base::file_util_proxy::Entry>&, bool) {
+ NOTREACHED();
+ }
+
+ virtual void DidOpenFileSystem(const std::string&, const FilePath&) {
+ NOTREACHED();
+ }
+
+ virtual void DidFail(base::PlatformFileError error_code) {
+ RunCallback(error_code, base::PlatformFileInfo());
+ }
+
+ private:
+ void RunCallback(base::PlatformFileError error_code,
+ const base::PlatformFileInfo& file_info) {
+ if (!module_.get() || !callback_.func)
+ return;
+
+ 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;
+ }
+ PP_RunCompletionCallback(
+ &callback_, pepper::PlatformFileErrorToPepperError(error_code));
+
+ delete this;
+ }
+
+ base::WeakPtr<pepper::PluginModule> module_;
+ PP_CompletionCallback callback_;
+ PP_FileInfo_Dev* info_;
+ PP_FileSystemType_Dev file_system_type_;
+};
+
+int32_t MakeDirectory(PP_Resource directory_ref_id,
bool make_ancestors,
PP_CompletionCallback callback) {
- return PP_ERROR_FAILED; // TODO(darin): Implement me!
+ scoped_refptr<FileRef> directory_ref(
+ Resource::GetAs<FileRef>(directory_ref_id));
+ if (!directory_ref)
+ return PP_ERROR_BADRESOURCE;
+
+ if (directory_ref->file_system_type() == PP_FILESYSTEMTYPE_EXTERNAL)
+ return PP_ERROR_FAILED;
+
+ PluginModule* module = directory_ref->module();
+ if (!module->GetSomeInstance()->delegate()->MakeDirectory(
+ directory_ref->system_path(), make_ancestors,
+ new StatusCallback(module->AsWeakPtr(), callback)))
+ return PP_ERROR_FAILED;
+
+ return PP_ERROR_WOULDBLOCK;
}
-int32_t Query(PP_Resource file_ref,
- PP_FileInfo* info,
+int32_t Query(PP_Resource file_ref_id,
+ PP_FileInfo_Dev* info,
PP_CompletionCallback callback) {
- return PP_ERROR_FAILED; // TODO(darin): Implement me!
+ scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
+ if (!file_ref)
+ return PP_ERROR_BADRESOURCE;
+
+ PluginModule* module = file_ref->module();
+ if (!module->GetSomeInstance()->delegate()->Query(
+ file_ref->system_path(),
+ new QueryInfoCallback(module->AsWeakPtr(), callback,
+ info, file_ref->file_system_type())))
+ return PP_ERROR_FAILED;
+
+ return PP_ERROR_WOULDBLOCK;
}
-int32_t Touch(PP_Resource file_ref,
+int32_t Touch(PP_Resource file_ref_id,
PP_Time last_access_time,
PP_Time last_modified_time,
PP_CompletionCallback callback) {
- return PP_ERROR_FAILED; // TODO(darin): Implement me!
+ scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
+ if (!file_ref)
+ return PP_ERROR_BADRESOURCE;
+
+ PluginModule* module = file_ref->module();
+ if (!module->GetSomeInstance()->delegate()->Touch(
+ file_ref->system_path(), base::Time::FromDoubleT(last_access_time),
+ base::Time::FromDoubleT(last_modified_time),
+ new StatusCallback(module->AsWeakPtr(), callback)))
+ return PP_ERROR_FAILED;
+
+ return PP_ERROR_WOULDBLOCK;
}
-int32_t Delete(PP_Resource file_ref,
+int32_t Delete(PP_Resource file_ref_id,
PP_CompletionCallback callback) {
- return PP_ERROR_FAILED; // TODO(darin): Implement me!
+ scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
+ if (!file_ref)
+ return PP_ERROR_BADRESOURCE;
+
+ if (file_ref->file_system_type() == PP_FILESYSTEMTYPE_EXTERNAL)
+ return PP_ERROR_FAILED;
+
+ PluginModule* module = file_ref->module();
+ if (!module->GetSomeInstance()->delegate()->Delete(
+ file_ref->system_path(),
+ new StatusCallback(module->AsWeakPtr(), callback)))
+ return PP_ERROR_FAILED;
+
+ return PP_ERROR_WOULDBLOCK;
}
-int32_t Rename(PP_Resource file_ref,
- PP_Resource new_file_ref,
+int32_t Rename(PP_Resource file_ref_id,
+ PP_Resource new_file_ref_id,
PP_CompletionCallback callback) {
- return PP_ERROR_FAILED; // TODO(darin): Implement me!
+ 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;
+
+ if ((file_ref->file_system_type() == PP_FILESYSTEMTYPE_EXTERNAL) ||
+ (file_ref->file_system_type() != new_file_ref->file_system_type()))
+ return PP_ERROR_FAILED;
+
+ PluginModule* module = file_ref->module();
+ if (!module->GetSomeInstance()->delegate()->Rename(
+ file_ref->system_path(), new_file_ref->system_path(),
+ new StatusCallback(module->AsWeakPtr(), callback)))
+ return PP_ERROR_FAILED;
+
+ return PP_ERROR_WOULDBLOCK;
}
-const PPB_FileSystem ppb_filesystem = {
+const PPB_FileSystem_Dev ppb_filesystem = {
&MakeDirectory,
&Query,
&Touch,
@@ -52,7 +242,7 @@ const PPB_FileSystem ppb_filesystem = {
} // namespace
-const PPB_FileSystem* FileSystem::GetInterface() {
+const PPB_FileSystem_Dev* FileSystem::GetInterface() {
return &ppb_filesystem;
}
diff --git a/webkit/glue/plugins/pepper_file_system.h b/webkit/glue/plugins/pepper_file_system.h
index b8ad01a..1abfc52 100644
--- a/webkit/glue/plugins/pepper_file_system.h
+++ b/webkit/glue/plugins/pepper_file_system.h
@@ -5,7 +5,9 @@
#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FILE_SYSTEM_H_
#define WEBKIT_GLUE_PLUGINS_PEPPER_FILE_SYSTEM_H_
-typedef struct _ppb_FileSystem PPB_FileSystem;
+#include "base/basictypes.h"
+
+struct PPB_FileSystem_Dev;
namespace pepper {
@@ -13,7 +15,10 @@ class FileSystem {
public:
// Returns a pointer to the interface implementing PPB_FileSystem that is
// exposed to the plugin.
- static const PPB_FileSystem* GetInterface();
+ static const PPB_FileSystem_Dev* GetInterface();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystem);
};
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_font.cc b/webkit/glue/plugins/pepper_font.cc
index af4cb81..82bf369 100644
--- a/webkit/glue/plugins/pepper_font.cc
+++ b/webkit/glue/plugins/pepper_font.cc
@@ -2,98 +2,290 @@
// 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_font.h"
-#if defined(OS_LINUX)
-#include <unistd.h>
-#endif
-
#include "base/logging.h"
-#include "third_party/ppapi/c/ppb_font.h"
+#include "base/utf_string_conversions.h"
+#include "third_party/ppapi/c/dev/ppb_font_dev.h"
+#include "third_party/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_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 {
-PP_Resource MatchFontWithFallback(PP_Module module_id,
- const PP_FontDescription* description) {
-#if defined(OS_LINUX)
+bool IsPPFontDescriptionValid(const PP_FontDescription_Dev& desc) {
+ // Check validity of UTF-8.
+ if (desc.face.type != PP_VARTYPE_STRING && desc.face.type != PP_VARTYPE_VOID)
+ 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 = font.italic;
+ result.smallCaps = 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()),
+ run->rtl, run->override_direction);
+ return true;
+}
+
+PP_Resource Create(PP_Module module_id,
+ const PP_FontDescription_Dev* description) {
PluginModule* module = PluginModule::FromPPModule(module_id);
if (!module)
- return NULL;
+ return 0;
- int fd = webkit_glue::MatchFontWithFallback(description->face,
- description->weight >= 700,
- description->italic,
- description->charset);
- if (fd == -1)
- return NULL;
-
- scoped_refptr<Font> font(new Font(module, fd));
+ if (!IsPPFontDescriptionValid(*description))
+ return 0;
+ scoped_refptr<Font> font(new Font(module, *description));
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 false;
-#endif
}
bool IsFont(PP_Resource resource) {
- return !!Resource::GetAs<Font>(resource);
+ return !!Resource::GetAs<Font>(resource).get();
}
-bool GetFontTable(PP_Resource font_id,
- uint32_t table,
- void* output,
- uint32_t* output_length) {
+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 false;
+ return font->Describe(description, metrics);
+}
- return font->GetFontTable(table, output, output_length);
+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,
+ bool image_data_is_opaque) {
+ scoped_refptr<Font> font(Resource::GetAs<Font>(font_id));
+ if (!font.get())
+ return false;
+ return font->DrawTextAt(image_data, text, position, color, clip,
+ image_data_is_opaque);
}
-const PPB_Font ppb_font = {
- &MatchFontWithFallback,
+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,
- &GetFontTable,
+ &Describe,
+ &DrawTextAt,
+ &MeasureText,
+ &CharacterOffsetForPixel,
+ &PixelOffsetForCharacter
};
} // namespace
-Font::Font(PluginModule* module, int fd)
- : Resource(module),
- fd_(fd) {
+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() {
-#if defined (OS_LINUX)
- close(fd_);
-#endif
}
// static
-const PPB_Font* Font::GetInterface() {
+const PPB_Font_Dev* Font::GetInterface() {
return &ppb_font;
}
-bool Font::GetFontTable(uint32_t table,
- void* output,
- uint32_t* output_length) {
-#if defined(OS_LINUX)
- 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;
-#else
- return false;
-#endif
+bool Font::Describe(PP_FontDescription_Dev* description,
+ PP_FontMetrics_Dev* metrics) {
+ if (description->face.type != PP_VARTYPE_VOID)
+ 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 = web_desc.italic;
+ description->small_caps = 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
index ad1abba..34fe521 100644
--- a/webkit/glue/plugins/pepper_font.h
+++ b/webkit/glue/plugins/pepper_font.h
@@ -5,9 +5,13 @@
#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FONT_H_
#define WEBKIT_GLUE_PLUGINS_PEPPER_FONT_H_
+#include "base/scoped_ptr.h"
+#include "third_party/ppapi/c/dev/ppb_font_dev.h"
#include "webkit/glue/plugins/pepper_resource.h"
-typedef struct _ppb_Font PPB_Font;
+namespace WebKit {
+class WebFont;
+}
namespace pepper {
@@ -15,23 +19,33 @@ class PluginInstance;
class Font : public Resource {
public:
- Font(PluginModule* module, int fd);
+ 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* GetInterface();
+ static const PPB_Font_Dev* GetInterface();
// Resource overrides.
Font* AsFont() { return this; }
// PPB_Font implementation.
- bool GetFontTable(uint32_t table,
- void* output,
- uint32_t* output_length);
+ 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:
- int fd_;
+ scoped_ptr<WebKit::WebFont> font_;
};
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_image_data.cc b/webkit/glue/plugins/pepper_image_data.cc
index 8288fe2..aeb2c88 100644
--- a/webkit/glue/plugins/pepper_image_data.cc
+++ b/webkit/glue/plugins/pepper_image_data.cc
@@ -14,6 +14,7 @@
#include "third_party/ppapi/c/pp_module.h"
#include "third_party/ppapi/c/pp_resource.h"
#include "third_party/ppapi/c/ppb_image_data.h"
+#include "third_party/ppapi/c/trusted/ppb_image_data_trusted.h"
#include "webkit/glue/plugins/pepper_plugin_instance.h"
#include "webkit/glue/plugins/pepper_plugin_module.h"
@@ -31,11 +32,11 @@ PP_Resource Create(PP_Module module_id,
bool init_to_zero) {
PluginModule* module = PluginModule::FromPPModule(module_id);
if (!module)
- return NULL;
+ return 0;
scoped_refptr<ImageData> data(new ImageData(module));
if (!data->Init(format, size->width, size->height, init_to_zero))
- return NULL;
+ return 0;
return data->GetReference();
}
@@ -68,6 +69,13 @@ void Unmap(PP_Resource resource) {
image_data->Unmap();
}
+uint64_t GetNativeMemoryHandle2(PP_Resource resource) {
+ scoped_refptr<ImageData> image_data(Resource::GetAs<ImageData>(resource));
+ if (image_data)
+ return image_data->GetNativeMemoryHandle();
+ return 0;
+}
+
const PPB_ImageData ppb_imagedata = {
&GetNativeImageDataFormat,
&Create,
@@ -77,6 +85,10 @@ const PPB_ImageData ppb_imagedata = {
&Unmap,
};
+const PPB_ImageDataTrusted ppb_imagedata_trusted = {
+ &GetNativeMemoryHandle2,
+};
+
} // namespace
ImageData::ImageData(PluginModule* module)
@@ -93,6 +105,11 @@ const PPB_ImageData* ImageData::GetInterface() {
return &ppb_imagedata;
}
+// static
+const PPB_ImageDataTrusted* ImageData::GetTrustedInterface() {
+ return &ppb_imagedata_trusted;
+}
+
bool ImageData::Init(PP_ImageDataFormat format,
int width, int height,
bool init_to_zero) {
@@ -143,6 +160,10 @@ void ImageData::Unmap() {
// in the future to save some memory.
}
+uint64 ImageData::GetNativeMemoryHandle() const {
+ return platform_image_->GetSharedMemoryHandle();
+}
+
const SkBitmap* ImageData::GetMappedBitmap() const {
if (!mapped_canvas_.get())
return NULL;
diff --git a/webkit/glue/plugins/pepper_image_data.h b/webkit/glue/plugins/pepper_image_data.h
index 7652b80..f2a110b 100644
--- a/webkit/glue/plugins/pepper_image_data.h
+++ b/webkit/glue/plugins/pepper_image_data.h
@@ -15,6 +15,7 @@ namespace skia {
class PlatformCanvas;
}
+struct PPB_ImageDataTrusted;
class SkBitmap;
namespace pepper {
@@ -37,12 +38,17 @@ class ImageData : public Resource {
// 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();
// Resource overrides.
- ImageData* AsImageData() { return this; }
+ virtual ImageData* AsImageData() { return this; }
// PPB_ImageData implementation.
bool Init(PP_ImageDataFormat format,
@@ -52,6 +58,9 @@ class ImageData : public Resource {
void* Map();
void Unmap();
+ // PPB_ImageDataTrusted implementation.
+ uint64 GetNativeMemoryHandle() 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;
diff --git a/webkit/glue/plugins/pepper_plugin_delegate.h b/webkit/glue/plugins/pepper_plugin_delegate.h
index ffc9d52..1bb4bed 100644
--- a/webkit/glue/plugins/pepper_plugin_delegate.h
+++ b/webkit/glue/plugins/pepper_plugin_delegate.h
@@ -5,15 +5,57 @@
#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 "base/task.h"
+#include "third_party/ppapi/c/pp_completion_callback.h"
+#include "third_party/ppapi/c/pp_errors.h"
#include "third_party/ppapi/c/pp_stdint.h"
+class AudioMessageFilter;
+
+namespace base {
+class MessageLoopProxy;
+class Time;
+}
+
+namespace fileapi {
+class FileSystemCallbackDispatcher;
+}
+
+namespace gfx {
+class Rect;
+}
+
+namespace gpu {
+class CommandBuffer;
+}
+
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.
@@ -32,6 +74,62 @@ class PluginDelegate {
// this image. This is used by NativeClient to send the image to the
// out-of-process plugin. Returns 0 on failure.
virtual intptr_t GetSharedMemoryHandle() const = 0;
+
+ virtual TransportDIB* GetTransportDIB() const = 0;
+ };
+
+ class PlatformContext3D {
+ public:
+ virtual ~PlatformContext3D() {}
+
+ // Initialize the context.
+ virtual bool Init(const gfx::Rect& position, const gfx::Rect& clip) = 0;
+
+ // This call will return the address of the command buffer object that is
+ // constructed in Initialize() and is valid until this context is destroyed.
+ virtual gpu::CommandBuffer* GetCommandBuffer() = 0;
+
+ // Sets the function to be called on repaint.
+ virtual void SetNotifyRepaintTask(Task* task) = 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;
+ };
+
+ virtual ~PlatformAudio() {}
+
+ // 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;
+ };
+
+ 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.
@@ -45,13 +143,65 @@ class PluginDelegate {
// 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 DidChangeNumberOfFindResults(int identifier,
- int total,
- bool final_result) = 0;
+ int total,
+ bool final_result) = 0;
// Notifies that the index of the currently selected item has been updated.
virtual void DidChangeSelectedFindResult(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 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;
+
+ // 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;
};
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_plugin_instance.cc b/webkit/glue/plugins/pepper_plugin_instance.cc
index 6a7bf54..b4ccd89 100644
--- a/webkit/glue/plugins/pepper_plugin_instance.cc
+++ b/webkit/glue/plugins/pepper_plugin_instance.cc
@@ -22,17 +22,19 @@
#include "printing/units.h"
#include "skia/ext/vector_platform_device.h"
#include "skia/ext/platform_canvas.h"
+#include "third_party/ppapi/c/dev/ppb_find_dev.h"
+#include "third_party/ppapi/c/dev/ppb_fullscreen_dev.h"
+#include "third_party/ppapi/c/dev/ppp_find_dev.h"
+#include "third_party/ppapi/c/dev/ppp_zoom_dev.h"
+#include "third_party/ppapi/c/pp_input_event.h"
#include "third_party/ppapi/c/pp_instance.h"
-#include "third_party/ppapi/c/pp_event.h"
#include "third_party/ppapi/c/pp_rect.h"
#include "third_party/ppapi/c/pp_resource.h"
#include "third_party/ppapi/c/pp_var.h"
#include "third_party/ppapi/c/ppb_core.h"
-#include "third_party/ppapi/c/ppb_find.h"
#include "third_party/ppapi/c/ppb_instance.h"
-#include "third_party/ppapi/c/ppp_find.h"
#include "third_party/ppapi/c/ppp_instance.h"
-#include "third_party/ppapi/c/ppp_zoom.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"
@@ -41,8 +43,9 @@
#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h"
#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
#include "webkit/glue/plugins/pepper_buffer.h"
-#include "webkit/glue/plugins/pepper_device_context_2d.h"
+#include "webkit/glue/plugins/pepper_graphics_2d.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"
@@ -50,6 +53,7 @@
#include "webkit/glue/plugins/pepper_url_loader.h"
#include "webkit/glue/plugins/pepper_var.h"
+using WebKit::WebBindings;
using WebKit::WebCanvas;
using WebKit::WebCursorInfo;
using WebKit::WebFrame;
@@ -146,11 +150,11 @@ PP_Var GetOwnerElementObject(PP_Instance instance_id) {
return instance->GetOwnerElementObject();
}
-bool BindGraphicsDeviceContext(PP_Instance instance_id, PP_Resource device_id) {
+bool BindGraphics(PP_Instance instance_id, PP_Resource device_id) {
PluginInstance* instance = PluginInstance::FromPPInstance(instance_id);
if (!instance)
return false;
- return instance->BindGraphicsDeviceContext(device_id);
+ return instance->BindGraphics(device_id);
}
bool IsFullFrame(PP_Instance instance_id) {
@@ -160,31 +164,21 @@ bool IsFullFrame(PP_Instance instance_id) {
return instance->full_frame();
}
-bool SetCursor(PP_Instance instance_id,
- PP_CursorType type,
- PP_Resource custom_image_id,
- const PP_Point* hot_spot) {
+PP_Var ExecuteScript(PP_Instance instance_id,
+ PP_Var script,
+ PP_Var* exception) {
PluginInstance* instance = PluginInstance::FromPPInstance(instance_id);
if (!instance)
- return false;
-
- scoped_refptr<ImageData> custom_image(
- Resource::GetAs<ImageData>(custom_image_id));
- if (custom_image.get()) {
- // TODO: implement custom cursors.
- NOTIMPLEMENTED();
- return false;
- }
-
- return instance->SetCursor(type);
+ return PP_MakeVoid();
+ return instance->ExecuteScript(script, exception);
}
const PPB_Instance ppb_instance = {
&GetWindowObject,
&GetOwnerElementObject,
- &BindGraphicsDeviceContext,
+ &BindGraphics,
&IsFullFrame,
- &SetCursor,
+ &ExecuteScript,
};
void NumberOfFindResultsChanged(PP_Instance instance_id,
@@ -210,11 +204,30 @@ void SelectedFindResultChanged(PP_Instance instance_id,
instance->find_identifier(), index);
}
-const PPB_Find ppb_find = {
+const PPB_Find_Dev ppb_find = {
&NumberOfFindResultsChanged,
&SelectedFindResultChanged,
};
+bool IsFullscreen(PP_Instance instance_id) {
+ PluginInstance* instance = PluginInstance::FromPPInstance(instance_id);
+ if (!instance)
+ return false;
+ return instance->IsFullscreen();
+}
+
+bool SetFullscreen(PP_Instance instance_id, bool fullscreen) {
+ PluginInstance* instance = PluginInstance::FromPPInstance(instance_id);
+ if (!instance)
+ return false;
+ return instance->SetFullscreen(fullscreen);
+}
+
+const PPB_Fullscreen_Dev ppb_fullscreen = {
+ &IsFullscreen,
+ &SetFullscreen,
+};
+
} // namespace
PluginInstance::PluginInstance(PluginDelegate* delegate,
@@ -225,6 +238,8 @@ PluginInstance::PluginInstance(PluginDelegate* delegate,
instance_interface_(instance_interface),
container_(NULL),
full_frame_(false),
+ has_webkit_focus_(false),
+ has_content_area_focus_(false),
find_identifier_(-1),
plugin_find_interface_(NULL),
plugin_zoom_interface_(NULL),
@@ -232,7 +247,10 @@ PluginInstance::PluginInstance(PluginDelegate* delegate,
num_pages_(0),
pdf_output_done_(false),
#endif // defined (OS_LINUX)
- plugin_print_interface_(NULL) {
+ plugin_print_interface_(NULL),
+ plugin_graphics_3d_interface_(NULL),
+ always_on_top_(false),
+ fullscreen_container_(NULL) {
memset(&current_print_settings_, 0, sizeof(current_print_settings_));
DCHECK(delegate);
module_->InstanceCreated(this);
@@ -255,10 +273,15 @@ PluginInstance* PluginInstance::FromPPInstance(PP_Instance instance) {
}
// static
-const PPB_Find* PluginInstance::GetFindInterface() {
+const PPB_Find_Dev* PluginInstance::GetFindInterface() {
return &ppb_find;
}
+// static
+const PPB_Fullscreen_Dev* PluginInstance::GetFullscreenInterface() {
+ return &ppb_fullscreen;
+}
+
PP_Instance PluginInstance::GetPPInstance() {
return reinterpret_cast<intptr_t>(this);
}
@@ -266,17 +289,24 @@ PP_Instance PluginInstance::GetPPInstance() {
void PluginInstance::Paint(WebCanvas* canvas,
const gfx::Rect& plugin_rect,
const gfx::Rect& paint_rect) {
- if (device_context_2d_)
- device_context_2d_->Paint(canvas, plugin_rect, paint_rect);
+ if (bound_graphics_2d_)
+ bound_graphics_2d_->Paint(canvas, plugin_rect, paint_rect);
}
void PluginInstance::InvalidateRect(const gfx::Rect& rect) {
- if (!container_ || position_.IsEmpty())
- return; // Nothing to do.
- if (rect.IsEmpty())
- container_->invalidate();
- else
- container_->invalidateRect(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);
+ }
}
PP_Var PluginInstance::GetWindowObject() {
@@ -287,29 +317,28 @@ PP_Var PluginInstance::GetWindowObject() {
if (!frame)
return PP_MakeVoid();
- return NPObjectToPPVar(frame->windowObject());
+ return ObjectVar::NPObjectToPPVar(module(), frame->windowObject());
}
PP_Var PluginInstance::GetOwnerElementObject() {
if (!container_)
return PP_MakeVoid();
-
- return NPObjectToPPVar(container_->scriptableObjectForElement());
+ return ObjectVar::NPObjectToPPVar(module(),
+ container_->scriptableObjectForElement());
}
-bool PluginInstance::BindGraphicsDeviceContext(PP_Resource device_id) {
+bool PluginInstance::BindGraphics(PP_Resource device_id) {
if (!device_id) {
// Special-case clearing the current device.
- if (device_context_2d_) {
- device_context_2d_->BindToInstance(NULL);
- device_context_2d_ = NULL;
+ if (bound_graphics_2d_) {
+ bound_graphics_2d_->BindToInstance(NULL);
+ bound_graphics_2d_ = NULL;
InvalidateRect(gfx::Rect());
}
return true;
}
- scoped_refptr<DeviceContext2D> device_2d =
- Resource::GetAs<DeviceContext2D>(device_id);
+ scoped_refptr<Graphics2D> device_2d = Resource::GetAs<Graphics2D>(device_id);
if (device_2d) {
if (!device_2d->BindToInstance(this))
@@ -317,11 +346,11 @@ bool PluginInstance::BindGraphicsDeviceContext(PP_Resource device_id) {
// See http://crbug.com/49403: this can be further optimized by keeping the
// old device around and painting from it.
- if (device_context_2d_.get()) {
+ if (bound_graphics_2d_.get()) {
// Start the new image with the content of the old image until the plugin
// repaints.
const SkBitmap* old_backing_bitmap =
- device_context_2d_->image_data()->GetMappedBitmap();
+ 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())));
@@ -334,21 +363,63 @@ bool PluginInstance::BindGraphicsDeviceContext(PP_Resource device_id) {
canvas.drawARGB(255, 255, 255, 255);
}
- device_context_2d_ = device_2d;
+ bound_graphics_2d_ = device_2d;
// BindToInstance will have invalidated the plugin if necessary.
}
return true;
}
-bool PluginInstance::SetCursor(PP_CursorType type) {
+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_MakeVoid();
+
+ // 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_MakeVoid();
+ }
+ 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_MakeVoid();
+ }
+
+ 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_MakeVoid();
+ }
+
+ PP_Var ret = Var::NPVariantToPPVar(module_, &result);
+ WebBindings::releaseVariantValue(&result);
+ return ret;
+}
+
void PluginInstance::Delete() {
instance_interface_->Delete(GetPPInstance());
+ if (fullscreen_container_) {
+ fullscreen_container_->Destroy();
+ fullscreen_container_ = NULL;
+ }
container_ = NULL;
}
@@ -382,11 +453,14 @@ bool PluginInstance::HandleDocumentLoad(URLLoader* loader) {
bool PluginInstance::HandleInputEvent(const WebKit::WebInputEvent& event,
WebCursorInfo* cursor_info) {
- scoped_ptr<PP_Event> pp_event(CreatePP_Event(event));
- if (!pp_event.get())
- return false;
+ 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 |= instance_interface_->HandleInputEvent(GetPPInstance(), &pp_events[i]);
- bool rv = instance_interface_->HandleEvent(GetPPInstance(), pp_event.get());
if (cursor_.get())
*cursor_info = *cursor_;
return rv;
@@ -415,19 +489,67 @@ void PluginInstance::ViewChanged(const gfx::Rect& position,
instance_interface_->ViewChanged(GetPPInstance(), &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_->FocusChanged(GetPPInstance(), 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_->FocusChanged(GetPPInstance(), PluginHasFocus());
+}
+
void PluginInstance::ViewInitiatedPaint() {
- if (device_context_2d_)
- device_context_2d_->ViewInitiatedPaint();
+ if (bound_graphics_2d_)
+ bound_graphics_2d_->ViewInitiatedPaint();
}
void PluginInstance::ViewFlushedPaint() {
- if (device_context_2d_)
- device_context_2d_->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 plugin_paint_rect = plugin_backing_store_rect.Intersect(clip_);
+ if (!plugin_paint_rect.Contains(paint_bounds))
+ return false;
+
+ *dib = image_data->platform_image()->GetTransportDIB();
+ *location = plugin_backing_store_rect;
+ *clip = clip_;
+ return true;
}
string16 PluginInstance::GetSelectedText(bool html) {
PP_Var rv = instance_interface_->GetSelectedText(GetPPInstance(), html);
- String* string = GetString(rv);
+ 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());
@@ -466,8 +588,8 @@ void PluginInstance::StopFind() {
bool PluginInstance::LoadFindInterface() {
if (!plugin_find_interface_) {
plugin_find_interface_ =
- reinterpret_cast<const PPP_Find*>(module_->GetPluginInterface(
- PPP_FIND_INTERFACE));
+ reinterpret_cast<const PPP_Find_Dev*>(module_->GetPluginInterface(
+ PPP_FIND_DEV_INTERFACE));
}
return !!plugin_find_interface_;
@@ -476,24 +598,28 @@ bool PluginInstance::LoadFindInterface() {
bool PluginInstance::LoadZoomInterface() {
if (!plugin_zoom_interface_) {
plugin_zoom_interface_ =
- reinterpret_cast<const PPP_Zoom*>(module_->GetPluginInterface(
- PPP_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* format) {
+ PP_PrintOutputFormat_Dev* format) {
if (!plugin_print_interface_) {
plugin_print_interface_ =
- reinterpret_cast<const PPP_Printing*>(module_->GetPluginInterface(
- PPP_PRINTING_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* supported_formats =
+ PP_PrintOutputFormat_Dev* supported_formats =
plugin_print_interface_->QuerySupportedFormats(GetPPInstance(),
&format_count);
if (!supported_formats)
@@ -517,13 +643,13 @@ bool PluginInstance::GetPreferredPrintOutputFormat(
}
bool PluginInstance::SupportsPrintInterface() {
- PP_PrintOutputFormat format;
+ PP_PrintOutputFormat_Dev format;
return GetPreferredPrintOutputFormat(&format);
}
int PluginInstance::PrintBegin(const gfx::Rect& printable_area,
int printer_dpi) {
- PP_PrintOutputFormat format;
+ PP_PrintOutputFormat_Dev format;
if (!GetPreferredPrintOutputFormat(&format)) {
// PrintBegin should not have been called since SupportsPrintInterface
// would have returned false;
@@ -531,7 +657,7 @@ int PluginInstance::PrintBegin(const gfx::Rect& printable_area,
return 0;
}
- PP_PrintSettings print_settings;
+ PP_PrintSettings_Dev print_settings;
RectToPPRect(printable_area, &print_settings.printable_area);
print_settings.dpi = printer_dpi;
print_settings.orientation = PP_PRINTORIENTATION_NORMAL;
@@ -551,7 +677,7 @@ int PluginInstance::PrintBegin(const gfx::Rect& printable_area,
bool PluginInstance::PrintPage(int page_number, WebKit::WebCanvas* canvas) {
DCHECK(plugin_print_interface_);
- PP_PrintPageNumberRange page_range;
+ 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
@@ -592,13 +718,48 @@ void PluginInstance::PrintEnd() {
plugin_print_interface_->End(GetPPInstance());
memset(&current_print_settings_, 0, sizeof(current_print_settings_));
#if defined(OS_MACOSX)
- last_printed_page_ = SkBitmap();
+ last_printed_page_ = NULL;
#elif defined(OS_LINUX)
num_pages_ = 0;
pdf_output_done_ = false;
#endif // defined(OS_LINUX)
}
+void PluginInstance::Graphics3DContextLost() {
+ if (!plugin_graphics_3d_interface_) {
+ plugin_graphics_3d_interface_ =
+ reinterpret_cast<const PPP_Graphics3D_Dev*>(module_->GetPluginInterface(
+ PPP_GRAPHICS_3D_DEV_INTERFACE));
+ }
+ if (plugin_graphics_3d_interface_)
+ plugin_graphics_3d_interface_->Graphics3DContextLost(GetPPInstance());
+}
+
+bool PluginInstance::IsFullscreen() {
+ return fullscreen_container_ != NULL;
+}
+
+bool PluginInstance::SetFullscreen(bool fullscreen) {
+ bool is_fullscreen = (fullscreen_container_ != NULL);
+ if (fullscreen == is_fullscreen)
+ return true;
+ LOG(INFO) << "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::PrintPDFOutput(PP_Resource print_output,
WebKit::WebCanvas* canvas) {
scoped_refptr<Buffer> buffer(Resource::GetAs<Buffer>(print_output));
@@ -730,7 +891,7 @@ bool PluginInstance::PrintRasterOutput(PP_Resource print_output,
DrawSkBitmapToCanvas(*bitmap, canvas, dest_rect_gfx,
current_print_settings_.printable_area.size.height);
// See comments in the header file.
- last_printed_page_ = *bitmap;
+ last_printed_page_ = image;
#else // defined(OS_MACOSX)
if (draw_to_canvas)
canvas->drawBitmapRect(*bitmap, &src_rect, dest_rect);
diff --git a/webkit/glue/plugins/pepper_plugin_instance.h b/webkit/glue/plugins/pepper_plugin_instance.h
index 4528a99..4eb956f 100644
--- a/webkit/glue/plugins/pepper_plugin_instance.h
+++ b/webkit/glue/plugins/pepper_plugin_instance.h
@@ -13,21 +13,24 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "gfx/rect.h"
-#include "third_party/ppapi/c/pp_cursor_type.h"
+#include "third_party/ppapi/c/dev/pp_cursor_type_dev.h"
+#include "third_party/ppapi/c/dev/ppp_graphics_3d_dev.h"
+#include "third_party/ppapi/c/dev/ppp_printing_dev.h"
#include "third_party/ppapi/c/pp_instance.h"
#include "third_party/ppapi/c/pp_resource.h"
-#include "third_party/ppapi/c/ppp_printing.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h"
-typedef struct _pp_Var PP_Var;
-typedef struct _ppb_Instance PPB_Instance;
-typedef struct _ppb_Find PPB_Find;
-typedef struct _ppp_Find PPP_Find;
-typedef struct _ppp_Instance PPP_Instance;
-typedef struct _ppp_Zoom PPP_Zoom;
+struct PP_Var;
+struct PPB_Instance;
+struct PPB_Find_Dev;
+struct PPB_Fullscreen_Dev;
+struct PPP_Find_Dev;
+struct PPP_Instance;
+struct PPP_Zoom_Dev;
class SkBitmap;
+class TransportDIB;
namespace gfx {
class Rect;
@@ -41,10 +44,12 @@ class WebPluginContainer;
namespace pepper {
-class DeviceContext2D;
+class Graphics2D;
+class ImageData;
class PluginDelegate;
class PluginModule;
class URLLoader;
+class FullscreenContainer;
class PluginInstance : public base::RefCounted<PluginInstance> {
public:
@@ -60,7 +65,8 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// Returns a pointer to the interface implementing PPB_Find that is
// exposed to the plugin.
- static const PPB_Find* GetFindInterface();
+ static const PPB_Find_Dev* GetFindInterface();
+ static const PPB_Fullscreen_Dev* GetFullscreenInterface();
PluginDelegate* delegate() const { return delegate_; }
PluginModule* module() const { return module_.get(); }
@@ -72,6 +78,8 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
int find_identifier() const { return find_identifier_; }
+ void set_always_on_top(bool on_top) { always_on_top_ = on_top; }
+
PP_Instance GetPPInstance();
// Paints the current backing store to the web page.
@@ -88,9 +96,10 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// PPB_Instance implementation.
PP_Var GetWindowObject();
PP_Var GetOwnerElementObject();
- bool BindGraphicsDeviceContext(PP_Resource device_id);
+ bool BindGraphics(PP_Resource device_id);
bool full_frame() const { return full_frame_; }
- bool SetCursor(PP_CursorType type);
+ bool SetCursor(PP_CursorType_Dev type);
+ PP_Var ExecuteScript(PP_Var script, PP_Var* exception);
// PPP_Instance pass-through.
void Delete();
@@ -104,12 +113,26 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
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);
void Zoom(float factor, bool text_only);
bool StartFind(const string16& search_text,
@@ -123,14 +146,24 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
bool PrintPage(int page_number, WebKit::WebCanvas* canvas);
void PrintEnd();
+ void Graphics3DContextLost();
+
+ // Implementation of PPB_Fullscreen_Dev.
+ bool IsFullscreen();
+ bool SetFullscreen(bool fullscreen);
+
private:
bool LoadFindInterface();
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* format);
+ 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)
@@ -165,24 +198,31 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// be (0, 0, w, h) regardless of scroll position.
gfx::Rect clip_;
+ // 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 current device context for painting in 2D.
- scoped_refptr<DeviceContext2D> device_context_2d_;
+ scoped_refptr<Graphics2D> bound_graphics_2d_;
// The id of the current find operation, or -1 if none is in process.
int find_identifier_;
// The plugin find and zoom interfaces.
- const PPP_Find* plugin_find_interface_;
- const PPP_Zoom* plugin_zoom_interface_;
+ const PPP_Find_Dev* plugin_find_interface_;
+ const PPP_Zoom_Dev* plugin_zoom_interface_;
// This is only valid between a successful PrintBegin call and a PrintEnd
// call.
- PP_PrintSettings current_print_settings_;
+ 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.
- SkBitmap last_printed_page_;
+ 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
@@ -197,11 +237,21 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
#endif // defined(OS_LINUX)
// The plugin print interface.
- const PPP_Printing* 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_;
+
DISALLOW_COPY_AND_ASSIGN(PluginInstance);
};
diff --git a/webkit/glue/plugins/pepper_plugin_module.cc b/webkit/glue/plugins/pepper_plugin_module.cc
index 8ffd78b..251023f 100644
--- a/webkit/glue/plugins/pepper_plugin_module.cc
+++ b/webkit/glue/plugins/pepper_plugin_module.cc
@@ -12,46 +12,71 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
-#include "third_party/ppapi/c/ppb_buffer.h"
+#include "third_party/ppapi/c/dev/ppb_buffer_dev.h"
+#include "third_party/ppapi/c/dev/ppb_char_set_dev.h"
+#include "third_party/ppapi/c/dev/ppb_cursor_control_dev.h"
+#include "third_party/ppapi/c/dev/ppb_directory_reader_dev.h"
+#include "third_party/ppapi/c/dev/ppb_file_io_dev.h"
+#include "third_party/ppapi/c/dev/ppb_file_io_trusted_dev.h"
+#include "third_party/ppapi/c/dev/ppb_file_system_dev.h"
+#include "third_party/ppapi/c/dev/ppb_find_dev.h"
+#include "third_party/ppapi/c/dev/ppb_font_dev.h"
+#include "third_party/ppapi/c/dev/ppb_fullscreen_dev.h"
+#include "third_party/ppapi/c/dev/ppb_graphics_3d_dev.h"
+#include "third_party/ppapi/c/dev/ppb_opengles_dev.h"
+#include "third_party/ppapi/c/dev/ppb_scrollbar_dev.h"
+#include "third_party/ppapi/c/dev/ppb_testing_dev.h"
+#include "third_party/ppapi/c/dev/ppb_transport_dev.h"
+#include "third_party/ppapi/c/dev/ppb_url_loader_dev.h"
+#include "third_party/ppapi/c/dev/ppb_url_loader_trusted_dev.h"
+#include "third_party/ppapi/c/dev/ppb_url_request_info_dev.h"
+#include "third_party/ppapi/c/dev/ppb_url_response_info_dev.h"
+#include "third_party/ppapi/c/dev/ppb_url_util_dev.h"
+#include "third_party/ppapi/c/dev/ppb_video_decoder_dev.h"
+#include "third_party/ppapi/c/dev/ppb_widget_dev.h"
+#include "third_party/ppapi/c/trusted/ppb_image_data_trusted.h"
+#include "third_party/ppapi/c/pp_module.h"
+#include "third_party/ppapi/c/pp_resource.h"
+#include "third_party/ppapi/c/pp_var.h"
#include "third_party/ppapi/c/ppb_core.h"
-#include "third_party/ppapi/c/ppb_device_context_2d.h"
-#include "third_party/ppapi/c/ppb_file_io.h"
-#include "third_party/ppapi/c/ppb_file_io_trusted.h"
-#include "third_party/ppapi/c/ppb_file_system.h"
+#include "third_party/ppapi/c/ppb_graphics_2d.h"
#include "third_party/ppapi/c/ppb_image_data.h"
#include "third_party/ppapi/c/ppb_instance.h"
-#include "third_party/ppapi/c/ppb_find.h"
-#include "third_party/ppapi/c/ppb_font.h"
-#include "third_party/ppapi/c/ppb_scrollbar.h"
-#include "third_party/ppapi/c/ppb_testing.h"
-#include "third_party/ppapi/c/ppb_url_loader.h"
-#include "third_party/ppapi/c/ppb_url_request_info.h"
-#include "third_party/ppapi/c/ppb_url_response_info.h"
#include "third_party/ppapi/c/ppb_var.h"
-#include "third_party/ppapi/c/ppb_widget.h"
#include "third_party/ppapi/c/ppp.h"
#include "third_party/ppapi/c/ppp_instance.h"
-#include "third_party/ppapi/c/pp_module.h"
-#include "third_party/ppapi/c/pp_resource.h"
-#include "third_party/ppapi/c/pp_var.h"
+#include "webkit/glue/plugins/pepper_audio.h"
#include "webkit/glue/plugins/pepper_buffer.h"
-#include "webkit/glue/plugins/pepper_device_context_2d.h"
+#include "webkit/glue/plugins/pepper_char_set.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
namespace pepper {
@@ -107,13 +132,18 @@ void CallOnMainThread(int delay_in_msec,
delay_in_msec);
}
+bool IsMainThread() {
+ return GetMainThreadMessageLoop()->BelongsToCurrentThread();
+}
+
const PPB_Core core_interface = {
&AddRefResource,
&ReleaseResource,
&MemAlloc,
&MemFree,
&GetTime,
- &CallOnMainThread
+ &CallOnMainThread,
+ &IsMainThread
};
// PPB_Testing -----------------------------------------------------------------
@@ -121,8 +151,8 @@ const PPB_Core core_interface = {
bool ReadImageData(PP_Resource device_context_2d,
PP_Resource image,
const PP_Point* top_left) {
- scoped_refptr<DeviceContext2D> context(
- Resource::GetAs<DeviceContext2D>(device_context_2d));
+ scoped_refptr<Graphics2D> context(
+ Resource::GetAs<Graphics2D>(device_context_2d));
if (!context.get())
return false;
return context->ReadImageData(image, top_left);
@@ -136,13 +166,37 @@ void RunMessageLoop() {
}
void QuitMessageLoop() {
- MessageLoop::current()->Quit();
+ MessageLoop::current()->QuitNow();
+}
+
+uint32_t GetLiveObjectCount(PP_Module module_id) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return static_cast<uint32_t>(-1);
+ return ResourceTracker::Get()->GetLiveObjectsForModule(module);
+}
+
+PP_Resource GetInaccessibleFileRef(PP_Module module_id) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return static_cast<uint32_t>(-1);
+ return FileRef::GetInaccessibleFileRef(module)->GetReference();
+}
+
+PP_Resource GetNonexistentFileRef(PP_Module module_id) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return static_cast<uint32_t>(-1);
+ return FileRef::GetNonexistentFileRef(module)->GetReference();
}
-const PPB_Testing testing_interface = {
+const PPB_Testing_Dev testing_interface = {
&ReadImageData,
&RunMessageLoop,
&QuitMessageLoop,
+ &GetLiveObjectCount,
+ &GetInaccessibleFileRef,
+ &GetNonexistentFileRef
};
// GetInterface ----------------------------------------------------------------
@@ -151,46 +205,78 @@ const void* GetInterface(const char* name) {
if (strcmp(name, PPB_CORE_INTERFACE) == 0)
return &core_interface;
if (strcmp(name, PPB_VAR_INTERFACE) == 0)
- return GetVarInterface();
+ 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_DEVICECONTEXT2D_INTERFACE) == 0)
- return DeviceContext2D::GetInterface();
- if (strcmp(name, PPB_URLLOADER_INTERFACE) == 0)
+ 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_DEV_INTERFACE) == 0)
return URLLoader::GetInterface();
- if (strcmp(name, PPB_URLREQUESTINFO_INTERFACE) == 0)
+ if (strcmp(name, PPB_URLLOADERTRUSTED_DEV_INTERFACE) == 0)
+ return URLLoader::GetTrustedInterface();
+ if (strcmp(name, PPB_URLREQUESTINFO_DEV_INTERFACE) == 0)
return URLRequestInfo::GetInterface();
- if (strcmp(name, PPB_URLRESPONSEINFO_INTERFACE) == 0)
+ if (strcmp(name, PPB_URLRESPONSEINFO_DEV_INTERFACE) == 0)
return URLResponseInfo::GetInterface();
- if (strcmp(name, PPB_BUFFER_INTERFACE) == 0)
+ if (strcmp(name, PPB_BUFFER_DEV_INTERFACE) == 0)
return Buffer::GetInterface();
- if (strcmp(name, PPB_FILEREF_INTERFACE) == 0)
+ if (strcmp(name, PPB_FILEREF_DEV_INTERFACE) == 0)
return FileRef::GetInterface();
- if (strcmp(name, PPB_FILEIO_INTERFACE) == 0)
+ if (strcmp(name, PPB_FILEIO_DEV_INTERFACE) == 0)
return FileIO::GetInterface();
- if (strcmp(name, PPB_FILEIOTRUSTED_INTERFACE) == 0)
+ if (strcmp(name, PPB_FILEIOTRUSTED_DEV_INTERFACE) == 0)
return FileIO::GetTrustedInterface();
- if (strcmp(name, PPB_FILESYSTEM_INTERFACE) == 0)
+ if (strcmp(name, PPB_FILESYSTEM_DEV_INTERFACE) == 0)
return FileSystem::GetInterface();
- if (strcmp(name, PPB_DIRECTORYREADER_INTERFACE) == 0)
+ if (strcmp(name, PPB_DIRECTORYREADER_DEV_INTERFACE) == 0)
return DirectoryReader::GetInterface();
- if (strcmp(name, PPB_WIDGET_INTERFACE) == 0)
+ if (strcmp(name, PPB_WIDGET_DEV_INTERFACE) == 0)
return Widget::GetInterface();
- if (strcmp(name, PPB_SCROLLBAR_INTERFACE) == 0)
+ if (strcmp(name, PPB_SCROLLBAR_DEV_INTERFACE) == 0)
return Scrollbar::GetInterface();
- if (strcmp(name, PPB_FONT_INTERFACE) == 0)
+ if (strcmp(name, PPB_FONT_DEV_INTERFACE) == 0)
return Font::GetInterface();
- if (strcmp(name, PPB_FIND_INTERFACE) == 0)
+ 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();
// 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_INTERFACE) == 0) {
+ if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0) {
if (CommandLine::ForCurrentProcess()->HasSwitch("enable-pepper-testing"))
return &testing_interface;
}
@@ -207,6 +293,17 @@ PluginModule::PluginModule()
}
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());
@@ -359,4 +456,44 @@ void PluginModule::InstanceDeleted(PluginInstance* 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
index 6bfeccf..a560c56 100644
--- a/webkit/glue/plugins/pepper_plugin_module.h
+++ b/webkit/glue/plugins/pepper_plugin_module.h
@@ -5,23 +5,30 @@
#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/file_path.h"
#include "base/native_library.h"
#include "base/ref_counted.h"
+#include "base/weak_ptr.h"
#include "third_party/ppapi/c/pp_module.h"
#include "third_party/ppapi/c/ppb.h"
-typedef struct _ppb_Core PPB_Core;
+class FilePath;
+typedef struct NPObject NPObject;
+struct PPB_Core;
+typedef void* NPIdentifier;
namespace pepper {
+class ObjectVar;
class PluginDelegate;
class PluginInstance;
+class PluginObject;
-class PluginModule : public base::RefCounted<PluginModule> {
+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);
@@ -69,6 +76,22 @@ class PluginModule : public base::RefCounted<PluginModule> {
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();
@@ -94,6 +117,14 @@ class PluginModule : public base::RefCounted<PluginModule> {
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);
};
diff --git a/webkit/glue/plugins/pepper_private.cc b/webkit/glue/plugins/pepper_private.cc
index 8d5182f..e35006b 100644
--- a/webkit/glue/plugins/pepper_private.cc
+++ b/webkit/glue/plugins/pepper_private.cc
@@ -6,26 +6,167 @@
#include "webkit/glue/plugins/pepper_private.h"
+#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
+#include "grit/webkit_resources.h"
#include "grit/webkit_strings.h"
+#include "skia/ext/platform_canvas.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_module.h"
#include "webkit/glue/plugins/pepper_var.h"
#include "webkit/glue/plugins/ppb_private.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 {
-PP_Var GetLocalizedString(PP_ResourceString string_id) {
+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 = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return PP_MakeVoid();
+
std::string rv;
if (string_id == PP_RESOURCESTRING_PDFGETPASSWORD)
rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_NEED_PASSWORD));
- return StringToPPVar(rv);
+ 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 = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return 0;
+ scoped_refptr<pepper::ImageData> image_data(new pepper::ImageData(module));
+ if (!image_data->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL,
+ 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_PrivateFontFileDescription* description) {
+#if defined(OS_LINUX)
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return 0;
+
+ int fd = webkit_glue::MatchFontWithFallback(description->face,
+ description->weight >= 700,
+ description->italic,
+ description->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
}
const PPB_Private ppb_private = {
&GetLocalizedString,
+ &GetResourceImage,
+ &GetFontFileWithFallback,
+ &GetFontTableForPrivateFontFile,
};
} // namespace
@@ -35,4 +176,16 @@ 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
index fda75a7..06016f0 100644
--- a/webkit/glue/plugins/pepper_private.h
+++ b/webkit/glue/plugins/pepper_private.h
@@ -7,7 +7,7 @@
#include "webkit/glue/plugins/pepper_resource.h"
-typedef struct _ppb_Private PPB_Private;
+struct PPB_Private;
namespace pepper {
diff --git a/webkit/glue/plugins/pepper_resource.cc b/webkit/glue/plugins/pepper_resource.cc
index c568183..cf7a7fe 100644
--- a/webkit/glue/plugins/pepper_resource.cc
+++ b/webkit/glue/plugins/pepper_resource.cc
@@ -4,10 +4,18 @@
#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_)
@@ -16,4 +24,10 @@ PP_Resource Resource::GetReference() {
resource_id_ = tracker->AddResource(this);
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
index 417a06b..cab6f32 100644
--- a/webkit/glue/plugins/pepper_resource.h
+++ b/webkit/glue/plugins/pepper_resource.h
@@ -5,7 +5,6 @@
#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_H_
#define WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_H_
-#include "base/logging.h"
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "third_party/ppapi/c/pp_resource.h"
@@ -14,24 +13,33 @@
namespace pepper {
class Buffer;
-class DeviceContext2D;
+class Audio;
+class AudioConfig;
class DirectoryReader;
class FileChooser;
class FileIO;
class FileRef;
class Font;
+class Graphics2D;
+class Graphics3D;
class ImageData;
+class ObjectVar;
class PluginModule;
+class PrivateFontFile;
class Scrollbar;
+class StringVar;
+class Transport;
class URLLoader;
class URLRequestInfo;
class URLResponseInfo;
+class Var;
+class VideoDecoder;
class Widget;
class Resource : public base::RefCountedThreadSafe<Resource> {
public:
- explicit Resource(PluginModule* module) : resource_id_(0), module_(module) {}
- virtual ~Resource() {}
+ explicit Resource(PluginModule* module);
+ virtual ~Resource();
// Returns NULL if the resource is invalid or is a different type.
template<typename T>
@@ -72,18 +80,27 @@ class Resource : public base::RefCountedThreadSafe<Resource> {
// 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.
+ virtual Audio* AsAudio() { return NULL; }
+ virtual AudioConfig* AsAudioConfig() { return NULL; }
virtual Buffer* AsBuffer() { return NULL; }
- virtual DeviceContext2D* AsDeviceContext2D() { return NULL; }
virtual DirectoryReader* AsDirectoryReader() { return NULL; }
virtual FileChooser* AsFileChooser() { return NULL; }
virtual FileIO* AsFileIO() { return NULL; }
virtual FileRef* AsFileRef() { return NULL; }
virtual Font* AsFont() { return NULL; }
+ virtual Graphics2D* AsGraphics2D() { return NULL; }
+ virtual Graphics3D* AsGraphics3D() { return NULL; }
virtual ImageData* AsImageData() { return NULL; }
+ virtual ObjectVar* AsObjectVar() { return NULL; }
+ virtual PrivateFontFile* AsPrivateFontFile() { return NULL; }
virtual Scrollbar* AsScrollbar() { return NULL; }
+ virtual StringVar* AsStringVar() { return NULL; }
+ virtual Transport* AsTransport() { return NULL; }
virtual URLLoader* AsURLLoader() { return NULL; }
virtual URLRequestInfo* AsURLRequestInfo() { return NULL; }
virtual URLResponseInfo* AsURLResponseInfo() { return NULL; }
+ virtual Var* AsVar() { return NULL; }
+ virtual VideoDecoder* AsVideoDecoder() { return NULL; }
virtual Widget* AsWidget() { return NULL; }
private:
@@ -101,10 +118,7 @@ class Resource : public base::RefCountedThreadSafe<Resource> {
// Called by the resource tracker when the last plugin reference has been
// dropped.
friend class ResourceTracker;
- void StoppedTracking() {
- DCHECK(resource_id_ != 0);
- resource_id_ = 0;
- }
+ void StoppedTracking();
DISALLOW_COPY_AND_ASSIGN(Resource);
};
@@ -115,18 +129,27 @@ class Resource : public base::RefCountedThreadSafe<Resource> {
return As##Type(); \
}
+DEFINE_RESOURCE_CAST(Audio)
+DEFINE_RESOURCE_CAST(AudioConfig)
DEFINE_RESOURCE_CAST(Buffer)
-DEFINE_RESOURCE_CAST(DeviceContext2D)
DEFINE_RESOURCE_CAST(DirectoryReader)
DEFINE_RESOURCE_CAST(FileChooser)
DEFINE_RESOURCE_CAST(FileIO)
DEFINE_RESOURCE_CAST(FileRef)
DEFINE_RESOURCE_CAST(Font)
+DEFINE_RESOURCE_CAST(Graphics2D)
+DEFINE_RESOURCE_CAST(Graphics3D)
DEFINE_RESOURCE_CAST(ImageData)
+DEFINE_RESOURCE_CAST(ObjectVar)
+DEFINE_RESOURCE_CAST(PrivateFontFile)
DEFINE_RESOURCE_CAST(Scrollbar)
+DEFINE_RESOURCE_CAST(StringVar);
+DEFINE_RESOURCE_CAST(Transport)
DEFINE_RESOURCE_CAST(URLLoader)
DEFINE_RESOURCE_CAST(URLRequestInfo)
DEFINE_RESOURCE_CAST(URLResponseInfo)
+DEFINE_RESOURCE_CAST(Var)
+DEFINE_RESOURCE_CAST(VideoDecoder)
DEFINE_RESOURCE_CAST(Widget)
#undef DEFINE_RESOURCE_CAST
diff --git a/webkit/glue/plugins/pepper_resource_tracker.cc b/webkit/glue/plugins/pepper_resource_tracker.cc
index 8aa94d2..9ee54f8 100644
--- a/webkit/glue/plugins/pepper_resource_tracker.cc
+++ b/webkit/glue/plugins/pepper_resource_tracker.cc
@@ -21,6 +21,13 @@ scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const {
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()) {
@@ -58,4 +65,18 @@ bool ResourceTracker::UnrefResource(PP_Resource res) {
}
}
+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;
+}
+
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_resource_tracker.h b/webkit/glue/plugins/pepper_resource_tracker.h
index d06c9ba..59f02d2 100644
--- a/webkit/glue/plugins/pepper_resource_tracker.h
+++ b/webkit/glue/plugins/pepper_resource_tracker.h
@@ -5,17 +5,19 @@
#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_TRACKER_H_
#define WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_TRACKER_H_
-#include <set>
+#include <utility>
-#include "base/atomic_sequence_num.h"
#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/singleton.h"
#include "third_party/ppapi/c/pp_resource.h"
+typedef struct NPObject NPObject;
+
namespace pepper {
+class PluginModule;
class Resource;
// This class maintains a global list of all live pepper resources. It allows
@@ -41,13 +43,18 @@ class ResourceTracker {
bool AddRefResource(PP_Resource res);
bool UnrefResource(PP_Resource res);
+ // Returns the number of resources associated with this module.
+ //
+ // This is slow, use only for testing.
+ uint32 GetLiveObjectsForModule(PluginModule* module) const;
+
private:
friend struct DefaultSingletonTraits<ResourceTracker>;
friend class Resource;
// Prohibit creation other then by the Singleton class.
- ResourceTracker() : last_id_(0) {}
- ~ResourceTracker() {}
+ 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
diff --git a/webkit/glue/plugins/pepper_scrollbar.cc b/webkit/glue/plugins/pepper_scrollbar.cc
index 48db8d4..a8943d2 100644
--- a/webkit/glue/plugins/pepper_scrollbar.cc
+++ b/webkit/glue/plugins/pepper_scrollbar.cc
@@ -6,7 +6,8 @@
#include "base/logging.h"
#include "base/message_loop.h"
-#include "third_party/ppapi/c/ppp_scrollbar.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/ppapi/c/dev/ppp_scrollbar_dev.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"
@@ -17,6 +18,10 @@
#include "webkit/glue/plugins/pepper_plugin_module.h"
#include "webkit/glue/webkit_glue.h"
+#if defined(OS_WIN)
+#include "base/win_util.h"
+#endif
+
using WebKit::WebInputEvent;
using WebKit::WebRect;
using WebKit::WebScrollbar;
@@ -28,7 +33,7 @@ namespace {
PP_Resource Create(PP_Instance instance_id, bool vertical) {
PluginInstance* instance = PluginInstance::FromPPInstance(instance_id);
if (!instance)
- return NULL;
+ return 0;
scoped_refptr<Scrollbar> scrollbar(new Scrollbar(instance, vertical));
return scrollbar->GetReference();
@@ -69,15 +74,13 @@ void SetTickMarks(PP_Resource resource,
scrollbar->SetTickMarks(tick_marks, count);
}
-void ScrollBy(PP_Resource resource,
- PP_ScrollBy unit,
- int32_t multiplier) {
+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 ppb_scrollbar = {
+const PPB_Scrollbar_Dev ppb_scrollbar = {
&Create,
&IsScrollbar,
&GetThickness,
@@ -101,7 +104,7 @@ Scrollbar::~Scrollbar() {
}
// static
-const PPB_Scrollbar* Scrollbar::GetInterface() {
+const PPB_Scrollbar_Dev* Scrollbar::GetInterface() {
return &ppb_scrollbar;
}
@@ -129,7 +132,7 @@ void Scrollbar::SetTickMarks(const PP_Rect* tick_marks, uint32_t count) {
Invalidate(&rect);
}
-void Scrollbar::ScrollBy(PP_ScrollBy unit, int32_t multiplier) {
+void Scrollbar::ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier) {
WebScrollbar::ScrollDirection direction = multiplier >= 0 ?
WebScrollbar::ScrollForward : WebScrollbar::ScrollBackward;
float fmultiplier = 1.0;
@@ -159,10 +162,18 @@ bool Scrollbar::Paint(const PP_Rect* rect, ImageData* image) {
if (!canvas)
return false;
scrollbar_->paint(webkit_glue::ToWebCanvas(canvas), gfx_rect);
+
+#if defined(OS_WIN)
+ if (win_util::GetWinVersion() == win_util::WINVERSION_XP) {
+ canvas->getTopPlatformDevice().makeOpaque(
+ gfx_rect.x(), gfx_rect.y(), gfx_rect.width(), gfx_rect.height());
+ }
+#endif
+
return true;
}
-bool Scrollbar::HandleEvent(const PP_Event* event) {
+bool Scrollbar::HandleEvent(const PP_InputEvent* event) {
scoped_ptr<WebInputEvent> web_input_event(CreateWebInputEvent(*event));
if (!web_input_event.get())
return false;
@@ -178,8 +189,9 @@ void Scrollbar::SetLocationInternal(const PP_Rect* location) {
}
void Scrollbar::valueChanged(WebKit::WebScrollbar* scrollbar) {
- const PPP_Scrollbar* ppp_scrollbar = static_cast<const PPP_Scrollbar*>(
- module()->GetPluginInterface(PPP_SCROLLBAR_INTERFACE));
+ 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);
diff --git a/webkit/glue/plugins/pepper_scrollbar.h b/webkit/glue/plugins/pepper_scrollbar.h
index bf25136..e8ac480 100644
--- a/webkit/glue/plugins/pepper_scrollbar.h
+++ b/webkit/glue/plugins/pepper_scrollbar.h
@@ -8,13 +8,11 @@
#include <vector>
#include "gfx/rect.h"
-#include "third_party/ppapi/c/ppb_scrollbar.h"
+#include "third_party/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"
-typedef struct _ppb_Scrollbar PPB_Scrollbar;
-
namespace pepper {
class PluginInstance;
@@ -26,7 +24,7 @@ class Scrollbar : public Widget, public WebKit::WebScrollbarClient {
// Returns a pointer to the interface implementing PPB_Scrollbar that is
// exposed to the plugin.
- static const PPB_Scrollbar* GetInterface();
+ static const PPB_Scrollbar_Dev* GetInterface();
// Resource overrides.
Scrollbar* AsScrollbar() { return this; }
@@ -36,11 +34,11 @@ class Scrollbar : public Widget, public WebKit::WebScrollbarClient {
void SetValue(uint32_t value);
void SetDocumentSize(uint32_t size);
void SetTickMarks(const PP_Rect* tick_marks, uint32_t count);
- void ScrollBy(PP_ScrollBy unit, int32_t multiplier);
+ 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_Event* event);
+ virtual bool HandleEvent(const PP_InputEvent* event);
virtual void SetLocationInternal(const PP_Rect* location);
private:
diff --git a/webkit/glue/plugins/pepper_url_loader.cc b/webkit/glue/plugins/pepper_url_loader.cc
index aa09686..4169c00 100644
--- a/webkit/glue/plugins/pepper_url_loader.cc
+++ b/webkit/glue/plugins/pepper_url_loader.cc
@@ -7,14 +7,17 @@
#include "base/logging.h"
#include "third_party/ppapi/c/pp_completion_callback.h"
#include "third_party/ppapi/c/pp_errors.h"
-#include "third_party/ppapi/c/ppb_url_loader.h"
+#include "third_party/ppapi/c/dev/ppb_url_loader_dev.h"
+#include "third_party/ppapi/c/dev/ppb_url_loader_trusted_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/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/WebURLRequest.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.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"
@@ -121,6 +124,15 @@ int32_t ReadResponseBody(PP_Resource loader_id,
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)
@@ -129,7 +141,7 @@ void Close(PP_Resource loader_id) {
loader->Close();
}
-const PPB_URLLoader ppb_urlloader = {
+const PPB_URLLoader_Dev ppb_urlloader = {
&Create,
&IsURLLoader,
&Open,
@@ -138,9 +150,22 @@ const PPB_URLLoader ppb_urlloader = {
&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();
+}
+
+const PPB_URLLoaderTrusted_Dev ppb_urlloadertrusted = {
+ &GrantUniversalAccess
+};
+
} // namespace
URLLoader::URLLoader(PluginInstance* instance)
@@ -148,22 +173,28 @@ URLLoader::URLLoader(PluginInstance* instance)
instance_(instance),
pending_callback_(),
bytes_sent_(0),
- total_bytes_to_be_sent_(0),
+ total_bytes_to_be_sent_(-1),
bytes_received_(0),
- total_bytes_to_be_received_(0),
+ total_bytes_to_be_received_(-1),
user_buffer_(NULL),
user_buffer_size_(0),
- done_(false) {
+ done_status_(PP_ERROR_WOULDBLOCK),
+ has_universal_access_(false) {
}
URLLoader::~URLLoader() {
}
// static
-const PPB_URLLoader* URLLoader::GetInterface() {
+const PPB_URLLoader_Dev* URLLoader::GetInterface() {
return &ppb_urlloader;
}
+// static
+const PPB_URLLoaderTrusted_Dev* URLLoader::GetTrustedInterface() {
+ return &ppb_urlloadertrusted;
+}
+
int32_t URLLoader::Open(URLRequestInfo* request,
PP_CompletionCallback callback) {
if (loader_.get())
@@ -177,6 +208,12 @@ int32_t URLLoader::Open(URLRequestInfo* request,
if (!frame)
return PP_ERROR_FAILED;
WebURLRequest web_request(request->ToWebURLRequest(frame));
+
+ // Check if we are allowed to access this URL.
+ if (!has_universal_access_ &&
+ !frame->securityOrigin().canRequest(web_request.url()))
+ return PP_ERROR_NOACCESS;
+
frame->dispatchWillSendRequest(web_request);
loader_.reset(WebKit::webKitClient()->createURLLoader());
@@ -199,6 +236,8 @@ int32_t URLLoader::FollowRedirect(PP_CompletionCallback callback) {
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)
@@ -214,20 +253,40 @@ int32_t URLLoader::ReadResponseBody(char* buffer, int32_t bytes_to_read,
if (!buffer_.empty())
return FillUserBuffer();
- if (done_) {
+ // We may have already reached EOF.
+ if (done_status_ != PP_ERROR_WOULDBLOCK) {
user_buffer_ = NULL;
user_buffer_size_ = 0;
- return 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() {
NOTIMPLEMENTED(); // TODO(darin): Implement me.
}
+void URLLoader::GrantUniversalAccess() {
+ has_universal_access_ = true;
+}
+
void URLLoader::willSendRequest(WebURLLoader* loader,
WebURLRequest& new_request,
const WebURLResponse& redirect_response) {
@@ -248,12 +307,22 @@ void URLLoader::didReceiveResponse(WebURLLoader* loader,
if (response_info->Initialize(response))
response_info_ = response_info;
+ // Sets -1 if the content length is unknown.
+ total_bytes_to_be_received_ = response.expectedContentLength();
+
RunCallback(PP_OK);
}
+void URLLoader::didDownloadData(WebURLLoader* loader,
+ int data_length) {
+ bytes_received_ += data_length;
+}
+
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());
@@ -262,15 +331,15 @@ void URLLoader::didReceiveData(WebURLLoader* loader,
}
}
-void URLLoader::didFinishLoading(WebURLLoader* loader) {
- done_ = true;
- RunCallback(PP_OK);
+void URLLoader::didFinishLoading(WebURLLoader* loader, double finish_time) {
+ done_status_ = PP_OK;
+ RunCallback(done_status_);
}
void URLLoader::didFail(WebURLLoader* loader, const WebURLError& error) {
- done_ = true;
// TODO(darin): Provide more detailed error information.
- RunCallback(PP_ERROR_FAILED);
+ done_status_ = PP_ERROR_FAILED;
+ RunCallback(done_status_);
}
void URLLoader::RunCallback(int32_t result) {
diff --git a/webkit/glue/plugins/pepper_url_loader.h b/webkit/glue/plugins/pepper_url_loader.h
index 088f220..4919de7 100644
--- a/webkit/glue/plugins/pepper_url_loader.h
+++ b/webkit/glue/plugins/pepper_url_loader.h
@@ -13,7 +13,8 @@
#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h"
#include "webkit/glue/plugins/pepper_resource.h"
-typedef struct _ppb_URLLoader PPB_URLLoader;
+struct PPB_URLLoader_Dev;
+struct PPB_URLLoaderTrusted_Dev;
namespace pepper {
@@ -28,7 +29,11 @@ class URLLoader : public Resource, public WebKit::WebURLLoaderClient {
// Returns a pointer to the interface implementing PPB_URLLoader that is
// exposed to the plugin.
- static const PPB_URLLoader* GetInterface();
+ static const PPB_URLLoader_Dev* GetInterface();
+
+ // Returns a pointer to the interface implementing PPB_URLLoaderTrusted that
+ // is exposed to the plugin.
+ static const PPB_URLLoaderTrusted_Dev* GetTrustedInterface();
// Resource overrides.
URLLoader* AsURLLoader() { return this; }
@@ -38,8 +43,12 @@ class URLLoader : public Resource, public WebKit::WebURLLoaderClient {
int32_t FollowRedirect(PP_CompletionCallback callback);
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();
+
// WebKit::WebURLLoaderClient implementation.
virtual void willSendRequest(WebKit::WebURLLoader* loader,
WebKit::WebURLRequest& new_request,
@@ -49,10 +58,13 @@ class URLLoader : public Resource, public WebKit::WebURLLoaderClient {
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);
+ virtual void didFinishLoading(WebKit::WebURLLoader* loader,
+ double finish_time);
virtual void didFail(WebKit::WebURLLoader* loader,
const WebKit::WebURLError& error);
@@ -81,7 +93,8 @@ class URLLoader : public Resource, public WebKit::WebURLLoaderClient {
int64_t total_bytes_to_be_received_;
char* user_buffer_;
size_t user_buffer_size_;
- bool done_;
+ int32_t done_status_;
+ bool has_universal_access_;
};
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_url_request_info.cc b/webkit/glue/plugins/pepper_url_request_info.cc
index d230f20..4edbe83 100644
--- a/webkit/glue/plugins/pepper_url_request_info.cc
+++ b/webkit/glue/plugins/pepper_url_request_info.cc
@@ -22,7 +22,6 @@
#include "webkit/glue/webkit_glue.h"
using WebKit::WebData;
-using WebKit::WebFileInfo;
using WebKit::WebHTTPBody;
using WebKit::WebString;
using WebKit::WebFrame;
@@ -62,7 +61,7 @@ bool IsURLRequestInfo(PP_Resource resource) {
}
bool SetProperty(PP_Resource request_id,
- PP_URLRequestProperty property,
+ PP_URLRequestProperty_Dev property,
PP_Var var) {
scoped_refptr<URLRequestInfo> request(
Resource::GetAs<URLRequestInfo>(request_id));
@@ -72,8 +71,11 @@ bool SetProperty(PP_Resource request_id,
if (var.type == PP_VARTYPE_BOOL)
return request->SetBooleanProperty(property, var.value.as_bool);
- if (var.type == PP_VARTYPE_STRING)
- return request->SetStringProperty(property, GetString(var)->value());
+ if (var.type == PP_VARTYPE_STRING) {
+ scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
+ if (string)
+ return request->SetStringProperty(property, string->value());
+ }
return false;
}
@@ -84,7 +86,7 @@ bool AppendDataToBody(PP_Resource request_id, PP_Var var) {
if (!request)
return false;
- String* data = GetString(var);
+ scoped_refptr<StringVar> data(StringVar::FromPPVar(var));
if (!data)
return false;
@@ -111,7 +113,7 @@ bool AppendFileToBody(PP_Resource request_id,
expected_last_modified_time);
}
-const PPB_URLRequestInfo ppb_urlrequestinfo = {
+const PPB_URLRequestInfo_Dev ppb_urlrequestinfo = {
&Create,
&IsURLRequestInfo,
&SetProperty,
@@ -122,24 +124,31 @@ const PPB_URLRequestInfo ppb_urlrequestinfo = {
} // namespace
URLRequestInfo::URLRequestInfo(PluginModule* module)
- : Resource(module) {
+ : Resource(module),
+ stream_to_file_(false) {
}
URLRequestInfo::~URLRequestInfo() {
}
// static
-const PPB_URLRequestInfo* URLRequestInfo::GetInterface() {
+const PPB_URLRequestInfo_Dev* URLRequestInfo::GetInterface() {
return &ppb_urlrequestinfo;
}
-bool URLRequestInfo::SetBooleanProperty(PP_URLRequestProperty property,
+bool URLRequestInfo::SetBooleanProperty(PP_URLRequestProperty_Dev property,
bool value) {
- NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return false;
+ switch (property) {
+ case PP_URLREQUESTPROPERTY_STREAMTOFILE:
+ stream_to_file_ = value;
+ return true;
+ default:
+ NOTIMPLEMENTED(); // TODO(darin): Implement me!
+ return false;
+ }
}
-bool URLRequestInfo::SetStringProperty(PP_URLRequestProperty property,
+bool URLRequestInfo::SetStringProperty(PP_URLRequestProperty_Dev property,
const std::string& value) {
// TODO(darin): Validate input. Perhaps at a different layer?
switch (property) {
@@ -167,6 +176,14 @@ 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,
@@ -178,6 +195,7 @@ 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_));
@@ -198,13 +216,11 @@ WebURLRequest URLRequestInfo::ToWebURLRequest(WebFrame* frame) const {
http_body.initialize();
for (size_t i = 0; i < body_.size(); ++i) {
if (body_[i].file_ref) {
- WebFileInfo file_info;
- file_info.modificationTime = body_[i].expected_last_modified_time;
http_body.appendFileRange(
webkit_glue::FilePathToWebString(body_[i].file_ref->system_path()),
body_[i].start_offset,
body_[i].number_of_bytes,
- file_info);
+ body_[i].expected_last_modified_time);
} else {
DCHECK(!body_[i].data.empty());
http_body.appendData(WebData(body_[i].data));
diff --git a/webkit/glue/plugins/pepper_url_request_info.h b/webkit/glue/plugins/pepper_url_request_info.h
index ef1452c..7220531 100644
--- a/webkit/glue/plugins/pepper_url_request_info.h
+++ b/webkit/glue/plugins/pepper_url_request_info.h
@@ -9,7 +9,7 @@
#include <vector>
#include "base/ref_counted.h"
-#include "third_party/ppapi/c/ppb_url_request_info.h"
+#include "third_party/ppapi/c/dev/ppb_url_request_info_dev.h"
#include "webkit/glue/plugins/pepper_file_ref.h"
#include "webkit/glue/plugins/pepper_resource.h"
@@ -27,14 +27,14 @@ class URLRequestInfo : public Resource {
// Returns a pointer to the interface implementing PPB_URLRequestInfo that is
// exposed to the plugin.
- static const PPB_URLRequestInfo* GetInterface();
+ static const PPB_URLRequestInfo_Dev* GetInterface();
// Resource overrides.
URLRequestInfo* AsURLRequestInfo() { return this; }
// PPB_URLRequestInfo implementation.
- bool SetBooleanProperty(PP_URLRequestProperty property, bool value);
- bool SetStringProperty(PP_URLRequestProperty property,
+ bool SetBooleanProperty(PP_URLRequestProperty_Dev property, bool value);
+ bool SetStringProperty(PP_URLRequestProperty_Dev property,
const std::string& value);
bool AppendDataToBody(const std::string& data);
bool AppendFileToBody(FileRef* file_ref,
@@ -76,6 +76,7 @@ class URLRequestInfo : public Resource {
std::string method_;
std::string headers_;
Body body_;
+ bool stream_to_file_;
};
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_url_response_info.cc b/webkit/glue/plugins/pepper_url_response_info.cc
index bff92aa..79042ba 100644
--- a/webkit/glue/plugins/pepper_url_response_info.cc
+++ b/webkit/glue/plugins/pepper_url_response_info.cc
@@ -12,6 +12,7 @@
#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.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;
@@ -42,7 +43,7 @@ bool IsURLResponseInfo(PP_Resource resource) {
}
PP_Var GetProperty(PP_Resource response_id,
- PP_URLResponseProperty property) {
+ PP_URLResponseProperty_Dev property) {
scoped_refptr<URLResponseInfo> response(
Resource::GetAs<URLResponseInfo>(response_id));
if (!response)
@@ -65,7 +66,7 @@ PP_Resource GetBody(PP_Resource response_id) {
return body->GetReference();
}
-const PPB_URLResponseInfo ppb_urlresponseinfo = {
+const PPB_URLResponseInfo_Dev ppb_urlresponseinfo = {
&IsURLResponseInfo,
&GetProperty,
&GetBody
@@ -82,18 +83,18 @@ URLResponseInfo::~URLResponseInfo() {
}
// static
-const PPB_URLResponseInfo* URLResponseInfo::GetInterface() {
+const PPB_URLResponseInfo_Dev* URLResponseInfo::GetInterface() {
return &ppb_urlresponseinfo;
}
-PP_Var URLResponseInfo::GetProperty(PP_URLResponseProperty property) {
+PP_Var URLResponseInfo::GetProperty(PP_URLResponseProperty_Dev property) {
switch (property) {
case PP_URLRESPONSEPROPERTY_URL:
- return StringToPPVar(url_);
+ return StringVar::StringToPPVar(module(), url_);
case PP_URLRESPONSEPROPERTY_STATUSCODE:
return PP_MakeInt32(status_code_);
case PP_URLRESPONSEPROPERTY_HEADERS:
- return StringToPPVar(headers_);
+ return StringVar::StringToPPVar(module(), headers_);
default:
NOTIMPLEMENTED(); // TODO(darin): Implement me!
return PP_MakeVoid();
@@ -107,6 +108,10 @@ bool URLResponseInfo::Initialize(const WebURLResponse& response) {
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;
}
diff --git a/webkit/glue/plugins/pepper_url_response_info.h b/webkit/glue/plugins/pepper_url_response_info.h
index 8874919..d8e1321 100644
--- a/webkit/glue/plugins/pepper_url_response_info.h
+++ b/webkit/glue/plugins/pepper_url_response_info.h
@@ -7,7 +7,7 @@
#include <string>
-#include "third_party/ppapi/c/ppb_url_response_info.h"
+#include "third_party/ppapi/c/dev/ppb_url_response_info_dev.h"
#include "webkit/glue/plugins/pepper_resource.h"
namespace WebKit {
@@ -23,13 +23,13 @@ class URLResponseInfo : public Resource {
// Returns a pointer to the interface implementing PPB_URLResponseInfo that
// is exposed to the plugin.
- static const PPB_URLResponseInfo* GetInterface();
+ static const PPB_URLResponseInfo_Dev* GetInterface();
// Resource overrides.
URLResponseInfo* AsURLResponseInfo() { return this; }
// PPB_URLResponseInfo implementation.
- PP_Var GetProperty(PP_URLResponseProperty property);
+ PP_Var GetProperty(PP_URLResponseProperty_Dev property);
bool Initialize(const WebKit::WebURLResponse& response);
diff --git a/webkit/glue/plugins/pepper_var.cc b/webkit/glue/plugins/pepper_var.cc
index 414df7b..b4ba014 100644
--- a/webkit/glue/plugins/pepper_var.cc
+++ b/webkit/glue/plugins/pepper_var.cc
@@ -9,9 +9,9 @@
#include "base/string_util.h"
#include "third_party/ppapi/c/pp_var.h"
#include "third_party/ppapi/c/ppb_var.h"
-#include "third_party/ppapi/c/ppp_class.h"
#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
-#include "webkit/glue/plugins/pepper_string.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;
@@ -20,43 +20,9 @@ namespace pepper {
namespace {
-void Release(PP_Var var);
-PP_Var VarFromUtf8(const char* data, uint32_t len);
-
-// ---------------------------------------------------------------------------
-// Exceptions
-
-class TryCatch {
- public:
- TryCatch(PP_Var* exception) : exception_(exception) {
- WebBindings::pushExceptionHandler(&TryCatch::Catch, this);
- }
-
- ~TryCatch() {
- WebBindings::popExceptionHandler();
- }
-
- bool HasException() const {
- return exception_ && exception_->type != PP_VARTYPE_VOID;
- }
-
- void SetException(const char* message) {
- DCHECK(!HasException());
- if (exception_)
- *exception_ = VarFromUtf8(message, strlen(message));
- }
-
- private:
- static void Catch(void* self, const NPUTF8* message) {
- static_cast<TryCatch*>(self)->SetException(message);
- }
-
- // May be null if the consumer isn't interesting in catching exceptions.
- PP_Var* exception_;
-};
-
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[] =
@@ -69,531 +35,182 @@ const char kUnableToConstructException[] = "Error: Unable to construct";
// ---------------------------------------------------------------------------
// Utilities
-String* GetStringUnchecked(PP_Var var) {
- return reinterpret_cast<String*>(var.value.as_id);
-}
-
-NPObject* GetNPObjectUnchecked(PP_Var var) {
- return reinterpret_cast<NPObject*>(var.value.as_id);
-}
-
-// 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.
-PP_Var NPVariantToPPVar(const NPVariant* variant) {
- switch (variant->type) {
- case NPVariantType_Void:
- return PP_MakeVoid();
- case NPVariantType_Null:
- return PP_MakeNull();
- case NPVariantType_Bool:
- return PP_MakeBool(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 VarFromUtf8(NPVARIANT_TO_STRING(*variant).UTF8Characters,
- NPVARIANT_TO_STRING(*variant).UTF8Length);
- case NPVariantType_Object:
- return NPObjectToPPVar(NPVARIANT_TO_OBJECT(*variant));
- }
- NOTREACHED();
- return PP_MakeVoid();
-}
-
-// Returns a NPVariant that corresponds to the given PP_Var. The contents of
-// the PP_Var will be copied unless the PP_Var corresponds to an object.
-NPVariant PPVarToNPVariant(PP_Var var) {
- NPVariant ret;
+// 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_VOID:
- VOID_TO_NPVARIANT(ret);
+ VOID_TO_NPVARIANT(*result);
break;
case PP_VARTYPE_NULL:
- NULL_TO_NPVARIANT(ret);
+ NULL_TO_NPVARIANT(*result);
break;
case PP_VARTYPE_BOOL:
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret);
+ BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
break;
case PP_VARTYPE_INT32:
- INT32_TO_NPVARIANT(var.value.as_int, ret);
+ INT32_TO_NPVARIANT(var.value.as_int, *result);
break;
case PP_VARTYPE_DOUBLE:
- DOUBLE_TO_NPVARIANT(var.value.as_double, ret);
+ DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
break;
case PP_VARTYPE_STRING: {
- const std::string& value = GetStringUnchecked(var)->value();
- STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), ret);
+ 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: {
- NPObject* object = GetNPObjectUnchecked(var);
- OBJECT_TO_NPVARIANT(WebBindings::retainObject(object), ret);
+ scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
+ if (!object) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ OBJECT_TO_NPVARIANT(object->np_object(), *result);
break;
}
- }
- return ret;
-}
-
-// Returns a NPVariant that corresponds to the given PP_Var. 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.
-NPVariant PPVarToNPVariantNoCopy(PP_Var var) {
- NPVariant ret;
- switch (var.type) {
- case PP_VARTYPE_VOID:
- VOID_TO_NPVARIANT(ret);
- break;
- case PP_VARTYPE_NULL:
- NULL_TO_NPVARIANT(ret);
- break;
- case PP_VARTYPE_BOOL:
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret);
- break;
- case PP_VARTYPE_INT32:
- INT32_TO_NPVARIANT(var.value.as_int, ret);
- break;
- case PP_VARTYPE_DOUBLE:
- DOUBLE_TO_NPVARIANT(var.value.as_double, ret);
- break;
- case PP_VARTYPE_STRING: {
- const std::string& value = GetStringUnchecked(var)->value();
- STRINGN_TO_NPVARIANT(value.c_str(), value.size(), ret);
- break;
- }
- case PP_VARTYPE_OBJECT: {
- OBJECT_TO_NPVARIANT(GetNPObjectUnchecked(var), ret);
- break;
- }
- }
- return ret;
-}
-
-// Returns a NPIdentifier that corresponds to the given PP_Var. The contents
-// of the PP_Var will be copied. Returns NULL if the given PP_Var is not a a
-// string or integer type.
-NPIdentifier PPVarToNPIdentifier(PP_Var var) {
- switch (var.type) {
- case PP_VARTYPE_STRING:
- return WebBindings::getStringIdentifier(
- GetStringUnchecked(var)->value().c_str());
- case PP_VARTYPE_INT32:
- return WebBindings::getIntIdentifier(var.value.as_int);
default:
- return NULL;
+ VOID_TO_NPVARIANT(*result);
+ return false;
}
+ return true;
}
-PP_Var NPIdentifierToPPVar(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 VarFromUtf8(string_value, strlen(string_value));
-
- return PP_MakeInt32(int_value);
-}
-
-PP_Var NPIdentifierToPPVarString(NPIdentifier id) {
- PP_Var var = NPIdentifierToPPVar(id);
- if (var.type == PP_VARTYPE_STRING)
- return var;
- DCHECK(var.type == PP_VARTYPE_INT32);
- const std::string& str = IntToString(var.value.as_int);
- return VarFromUtf8(str.data(), str.size());
-}
-
-void ThrowException(NPObject* object, PP_Var exception) {
- String* str = GetString(exception);
- if (str)
- WebBindings::setException(object, str->value().c_str());
-}
-
-// ---------------------------------------------------------------------------
-// NPObject implementation in terms of PPP_Class
-
-struct WrapperObject : NPObject {
- const PPP_Class* ppp_class;
- void* ppp_class_data;
-};
-
-static WrapperObject* ToWrapper(NPObject* object) {
- return static_cast<WrapperObject*>(object);
-}
-
-NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) {
- return new WrapperObject;
-}
-
-void WrapperClass_Deallocate(NPObject* object) {
- WrapperObject* wrapper = ToWrapper(object);
- wrapper->ppp_class->Deallocate(wrapper->ppp_class_data);
- delete object;
-}
-
-void WrapperClass_Invalidate(NPObject* object) {
- // TODO(darin): Do I need to do something here?
-}
-
-bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var method_name_var = NPIdentifierToPPVarString(method_name);
- PP_Var exception = PP_MakeVoid();
- bool rv = wrapper->ppp_class->HasMethod(wrapper->ppp_class_data,
- method_name_var,
- &exception);
- Release(method_name_var);
-
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
- }
- return rv;
-}
-
-bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name,
- const NPVariant* argv, uint32_t argc,
- NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
-
- scoped_array<PP_Var> args;
- if (argc) {
- args.reset(new PP_Var[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = NPVariantToPPVar(&argv[i]);
- }
- PP_Var method_name_var = NPIdentifierToPPVarString(method_name);
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->Call(wrapper->ppp_class_data,
- method_name_var, argc,
- args.get(), &exception);
- Release(method_name_var);
- for (uint32_t i = 0; i < argc; ++i)
- Release(args[i]);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-bool WrapperClass_InvokeDefault(NPObject* object, const NPVariant* argv,
- uint32_t argc, NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
-
- scoped_array<PP_Var> args;
- if (argc) {
- args.reset(new PP_Var[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = NPVariantToPPVar(&argv[i]);
- }
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->Call(wrapper->ppp_class_data,
- PP_MakeVoid(), argc, args.get(),
- &exception);
- for (uint32_t i = 0; i < argc; ++i)
- Release(args[i]);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var exception = PP_MakeVoid();
- bool rv = wrapper->ppp_class->HasProperty(wrapper->ppp_class_data,
- property_name_var,
- &exception);
- Release(property_name_var);
-
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
- }
- return rv;
-}
-
-bool WrapperClass_GetProperty(NPObject* object, NPIdentifier property_name,
- NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->GetProperty(wrapper->ppp_class_data,
- property_name_var,
- &exception);
- Release(property_name_var);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-bool WrapperClass_SetProperty(NPObject* object, NPIdentifier property_name,
- const NPVariant* value) {
- WrapperObject* wrapper = ToWrapper(object);
+// ObjectAccessorTryCatch ------------------------------------------------------
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var value_var = NPVariantToPPVar(value);
- PP_Var exception = PP_MakeVoid();
- wrapper->ppp_class->SetProperty(wrapper->ppp_class_data, property_name_var,
- value_var, &exception);
- Release(value_var);
- Release(property_name_var);
-
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
+// 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());
+ }
}
- return true;
-}
-bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) {
- WrapperObject* wrapper = ToWrapper(object);
+ ObjectVar* object() { return object_.get(); }
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var exception = PP_MakeVoid();
- wrapper->ppp_class->RemoveProperty(wrapper->ppp_class_data, property_name_var,
- &exception);
- Release(property_name_var);
+ protected:
+ scoped_refptr<ObjectVar> object_;
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
- }
- return true;
-}
+ DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
+};
-bool WrapperClass_Enumerate(NPObject* object, NPIdentifier** values,
- uint32_t* count) {
- WrapperObject* wrapper = ToWrapper(object);
-
- uint32_t property_count = 0;
- PP_Var* properties = NULL;
- PP_Var exception = PP_MakeVoid();
- wrapper->ppp_class->GetAllPropertyNames(wrapper->ppp_class_data,
- &property_count,
- &properties,
- &exception);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- if (property_count == 0) {
- *values = NULL;
- *count = 0;
- } else {
- *values = static_cast<NPIdentifier*>(
- malloc(sizeof(NPIdentifier) * property_count));
- *count = property_count;
- for (uint32_t i = 0; i < property_count; ++i)
- (*values)[i] = PPVarToNPIdentifier(properties[i]);
+// 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);
}
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
}
- for (uint32_t i = 0; i < property_count; ++i)
- Release(properties[i]);
- free(properties);
- return rv;
-}
+ NPIdentifier identifier() const { return identifier_; }
-bool WrapperClass_Construct(NPObject* object, const NPVariant* argv,
- uint32_t argc, NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
-
- scoped_array<PP_Var> args;
- if (argc) {
- args.reset(new PP_Var[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = NPVariantToPPVar(&argv[i]);
- }
+ private:
+ NPIdentifier identifier_;
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->Construct(wrapper->ppp_class_data,
- argc, args.get(),
- &exception);
- for (uint32_t i = 0; i < argc; ++i)
- Release(args[i]);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-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
+ DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
};
-// ---------------------------------------------------------------------------
-// PPB_Var methods
-
-void AddRef(PP_Var var) {
- if (var.type == PP_VARTYPE_STRING) {
- GetStringUnchecked(var)->AddRef();
- } else if (var.type == PP_VARTYPE_OBJECT) {
- // TODO(darin): Add thread safety check
- WebBindings::retainObject(GetNPObjectUnchecked(var));
- }
-}
-
-void Release(PP_Var var) {
- if (var.type == PP_VARTYPE_STRING) {
- GetStringUnchecked(var)->Release();
- } else if (var.type == PP_VARTYPE_OBJECT) {
- // TODO(darin): Add thread safety check
- WebBindings::releaseObject(GetNPObjectUnchecked(var));
- }
-}
+// PPB_Var methods -------------------------------------------------------------
-PP_Var VarFromUtf8(const char* data, uint32_t len) {
- String* str = new String(data, len);
- str->AddRef(); // This is for the caller, we return w/ a refcount of 1.
- PP_Var ret;
- ret.type = PP_VARTYPE_STRING;
- ret.value.as_id = reinterpret_cast<intptr_t>(str);
- return ret;
+PP_Var VarFromUtf8(PP_Module module_id, const char* data, uint32_t len) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return PP_MakeNull();
+ return StringVar::StringToPPVar(module, data, len);
}
const char* VarToUtf8(PP_Var var, uint32_t* len) {
- if (var.type != PP_VARTYPE_STRING) {
+ scoped_refptr<StringVar> str(StringVar::FromPPVar(var));
+ if (!str) {
*len = 0;
return NULL;
}
- const std::string& str = GetStringUnchecked(var)->value();
- *len = static_cast<uint32_t>(str.size());
- if (str.empty())
+ *len = static_cast<uint32_t>(str->value().size());
+ if (str->value().empty())
return ""; // Don't return NULL on success.
- return str.data();
+ return str->value().data();
}
bool HasProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return false;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return false;
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
- return false;
- }
-
- return WebBindings::hasProperty(NULL, object, identifier);
+ return WebBindings::hasProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier());
}
bool HasMethod(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return false;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return false;
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
- return false;
- }
-
- return WebBindings::hasMethod(NULL, object, identifier);
+ return WebBindings::hasMethod(NULL, accessor.object()->np_object(),
+ accessor.identifier());
}
PP_Var GetProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return PP_MakeVoid();
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return PP_MakeVoid();
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return PP_MakeVoid();
- }
NPVariant result;
- if (!WebBindings::getProperty(NULL, object, identifier, &result)) {
+ if (!WebBindings::getProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier(), &result)) {
// An exception may have been raised.
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToGetPropertyException);
+ accessor.SetException(kUnableToGetPropertyException);
return PP_MakeVoid();
}
- PP_Var ret = NPVariantToPPVar(&result);
+ PP_Var ret = Var::NPVariantToPPVar(accessor.object()->module(), &result);
WebBindings::releaseVariantValue(&result);
return ret;
}
@@ -605,21 +222,15 @@ void GetAllPropertyNames(PP_Var var,
*properties = NULL;
*property_count = 0;
- TryCatch try_catch(exception);
- if (try_catch.HasException())
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
return;
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return;
- }
-
NPIdentifier* identifiers = NULL;
uint32_t count = 0;
- if (!WebBindings::enumerate(NULL, object, &identifiers, &count)) {
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToGetAllPropertiesException);
+ if (!WebBindings::enumerate(NULL, accessor.object()->np_object(),
+ &identifiers, &count)) {
+ accessor.SetException(kUnableToGetAllPropertiesException);
return;
}
@@ -628,8 +239,10 @@ void GetAllPropertyNames(PP_Var var,
*property_count = count;
*properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count));
- for (uint32_t i = 0; i < count; ++i)
- (*properties)[i] = NPIdentifierToPPVar(identifiers[i]);
+ for (uint32_t i = 0; i < count; ++i) {
+ (*properties)[i] = Var::NPIdentifierToPPVar(accessor.object()->module(),
+ identifiers[i]);
+ }
free(identifiers);
}
@@ -637,52 +250,30 @@ void SetProperty(PP_Var var,
PP_Var name,
PP_Var value,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return;
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
+ NPVariant variant;
+ if (!PPVarToNPVariantNoCopy(value, &variant)) {
+ accessor.SetException(kInvalidValueException);
return;
}
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
- return;
- }
-
- NPVariant variant = PPVarToNPVariantNoCopy(value);
- if (!WebBindings::setProperty(NULL, object, identifier, &variant)) {
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToSetPropertyException);
- }
+ if (!WebBindings::setProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier(), &variant))
+ accessor.SetException(kUnableToSetPropertyException);
}
void RemoveProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return;
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return;
- }
- if (!WebBindings::removeProperty(NULL, object, identifier)) {
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToRemovePropertyException);
- }
+ if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier()))
+ accessor.SetException(kUnableToRemovePropertyException);
}
PP_Var Call(PP_Var var,
@@ -690,56 +281,55 @@ PP_Var Call(PP_Var var,
uint32_t argc,
PP_Var* argv,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
return PP_MakeVoid();
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return PP_MakeVoid();
- }
-
NPIdentifier identifier;
if (method_name.type == PP_VARTYPE_VOID) {
identifier = NULL;
} else if (method_name.type == PP_VARTYPE_STRING) {
// Specifically allow only string functions to be called.
- identifier = PPVarToNPIdentifier(method_name);
+ identifier = Var::PPVarToNPIdentifier(method_name);
if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ accessor.SetException(kInvalidPropertyException);
return PP_MakeVoid();
}
} else {
- try_catch.SetException(kInvalidPropertyException);
+ accessor.SetException(kInvalidPropertyException);
return PP_MakeVoid();
}
scoped_array<NPVariant> args;
if (argc) {
args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = PPVarToNPVariantNoCopy(argv[i]);
+ 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_MakeVoid();
+ }
+ }
}
bool ok;
NPVariant result;
if (identifier) {
- ok = WebBindings::invoke(NULL, object, identifier, args.get(), argc,
- &result);
+ ok = WebBindings::invoke(NULL, accessor.object()->np_object(),
+ identifier, args.get(), argc, &result);
} else {
- ok = WebBindings::invokeDefault(NULL, object, args.get(), argc, &result);
+ ok = WebBindings::invokeDefault(NULL, accessor.object()->np_object(),
+ args.get(), argc, &result);
}
if (!ok) {
// An exception may have been raised.
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToCallMethodException);
+ accessor.SetException(kUnableToCallMethodException);
return PP_MakeVoid();
}
- PP_Var ret = NPVariantToPPVar(&result);
+ PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result);
WebBindings::releaseVariantValue(&result);
return ret;
}
@@ -748,67 +338,58 @@ PP_Var Construct(PP_Var var,
uint32_t argc,
PP_Var* argv,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
return PP_MakeVoid();
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return PP_MakeVoid();
- }
-
scoped_array<NPVariant> args;
if (argc) {
args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = PPVarToNPVariantNoCopy(argv[i]);
+ 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_MakeVoid();
+ }
+ }
}
NPVariant result;
- if (!WebBindings::construct(NULL, object, args.get(), argc, &result)) {
+ if (!WebBindings::construct(NULL, accessor.object()->np_object(),
+ args.get(), argc, &result)) {
// An exception may have been raised.
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToConstructException);
+ accessor.SetException(kUnableToConstructException);
return PP_MakeVoid();
}
- PP_Var ret = NPVariantToPPVar(&result);
+ PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result);
WebBindings::releaseVariantValue(&result);
return ret;
}
-bool IsInstanceOf(PP_Var var, const PPP_Class* ppp_class,
+bool IsInstanceOf(PP_Var var,
+ const PPP_Class* ppp_class,
void** ppp_class_data) {
- NPObject* object = GetNPObject(var);
+ scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
if (!object)
- return false;
-
- if (object->_class != &wrapper_class)
- return false;
+ return false; // Not an object at all.
- WrapperObject* wrapper = ToWrapper(object);
- if (wrapper->ppp_class != ppp_class)
- return false;
-
- if (ppp_class_data)
- *ppp_class_data = wrapper->ppp_class_data;
- return true;
+ return PluginObject::IsInstanceOf(object->np_object(),
+ ppp_class, ppp_class_data);
}
-PP_Var CreateObject(const PPP_Class* ppp_class, void* ppp_class_data) {
- NPObject* object =
- WebBindings::createObject(NULL, const_cast<NPClass*>(&wrapper_class));
- static_cast<WrapperObject*>(object)->ppp_class = ppp_class;
- static_cast<WrapperObject*>(object)->ppp_class_data = ppp_class_data;
- PP_Var ret = NPObjectToPPVar(object);
- WebBindings::releaseObject(object); // Release reference from createObject
- return ret;
+PP_Var CreateObject(PP_Module module_id,
+ const PPP_Class* ppp_class,
+ void* ppp_class_data) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return PP_MakeNull();
+ return PluginObject::Create(module, ppp_class, ppp_class_data);
}
const PPB_Var var_interface = {
- &AddRef,
- &Release,
+ &Var::PluginAddRefPPVar,
+ &Var::PluginReleasePPVar,
&VarFromUtf8,
&VarToUtf8,
&HasProperty,
@@ -825,33 +406,206 @@ const PPB_Var var_interface = {
} // namespace
-const PPB_Var* GetVarInterface() {
+// 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_MakeVoid();
+ case NPVariantType_Null:
+ return PP_MakeNull();
+ case NPVariantType_Bool:
+ return PP_MakeBool(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_MakeVoid();
+}
+
+// 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* Var::GetInterface() {
return &var_interface;
}
-PP_Var NPObjectToPPVar(NPObject* object) {
+// 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_OBJECT;
- ret.value.as_id = reinterpret_cast<intptr_t>(object);
- WebBindings::retainObject(object);
+ ret.type = PP_VARTYPE_STRING;
+
+ // The caller takes ownership now.
+ ret.value.as_id = str->GetReference();
return ret;
}
-NPObject* GetNPObject(PP_Var var) {
+// 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_MakeVoid();
+
+ // 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 NULL;
- return GetNPObjectUnchecked(var);
+ return scoped_refptr<ObjectVar>(NULL);
+ return Resource::GetAs<ObjectVar>(var.value.as_id);
}
-PP_Var StringToPPVar(const std::string& str) {
- DCHECK(IsStringUTF8(str));
- return VarFromUtf8(str.data(), str.size());
+// TryCatch --------------------------------------------------------------------
+
+TryCatch::TryCatch(PluginModule* module, PP_Var* exception)
+ : module_(module),
+ has_exception_(exception && exception->type != PP_VARTYPE_VOID),
+ exception_(exception) {
+ WebBindings::pushExceptionHandler(&TryCatch::Catch, this);
}
-String* GetString(PP_Var var) {
- if (var.type != PP_VARTYPE_STRING)
- return NULL;
- return GetStringUnchecked(var);
+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
index b8c31cc..b618029 100644
--- a/webkit/glue/plugins/pepper_var.h
+++ b/webkit/glue/plugins/pepper_var.h
@@ -7,39 +7,240 @@
#include <string>
-typedef struct _pp_Var PP_Var;
-typedef struct _ppb_Var PPB_Var;
+#include "webkit/glue/plugins/pepper_resource.h"
+
+struct PP_Var;
+struct PPB_Var;
typedef struct NPObject NPObject;
typedef struct _NPVariant NPVariant;
typedef void* NPIdentifier;
namespace pepper {
-class String;
+// 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 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);
-// There's no class implementing Var since it could represent a number of
-// objects. Instead, we just expose a getter for the interface implemented in
-// the .cc file here.
-const PPB_Var* GetVarInterface();
+ // Sets the exception to be a generic message contained in a magic string
+ // not associated with any module.
+ void SetInvalidObjectException();
-// Returns a PP_Var of type object that wraps the given NPObject. Calling this
-// function multiple times given the same NPObject results in the same PP_Var.
-PP_Var NPObjectToPPVar(NPObject* object);
+ private:
+ static void Catch(void* self, const char* message);
-// Returns the NPObject corresponding to the PP_Var. This pointer has not been
-// retained, so you should not call WebBindings::releaseObject unless you first
-// call WebBindings::retainObject. Returns NULL if the PP_Var is not an object
-// type.
-NPObject* GetNPObject(PP_Var var);
+ PluginModule* module_;
-// Returns a PP_Var of type string that contains a copy of the given string.
-// The input data must be valid UTF-8 encoded text.
-PP_Var StringToPPVar(const std::string& str);
+ // 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_;
-// Returns the String corresponding to the PP_Var. This pointer has not been
-// AddRef'd, so you should not call Release! Returns NULL if the PP_Var is not
-// a string type.
-String* GetString(PP_Var var);
+ // May be null if the consumer isn't interesting in catching exceptions.
+ PP_Var* exception_;
+};
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_webplugin_impl.cc b/webkit/glue/plugins/pepper_webplugin_impl.cc
index df8aae0..32903b0 100644
--- a/webkit/glue/plugins/pepper_webplugin_impl.cc
+++ b/webkit/glue/plugins/pepper_webplugin_impl.cc
@@ -4,7 +4,6 @@
#include "webkit/glue/plugins/pepper_webplugin_impl.h"
-#include "base/file_path.h"
#include "base/message_loop.h"
#include "third_party/ppapi/c/pp_var.h"
#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h"
@@ -74,11 +73,16 @@ void WebPluginImpl::destroy() {
}
NPObject* WebPluginImpl::scriptableObject() {
- return GetNPObject(instance_->GetInstanceObject());
+ scoped_refptr<ObjectVar> object(
+ ObjectVar::FromPPVar(instance_->GetInstanceObject()));
+ if (object)
+ return object->np_object();
+ return NULL;
}
void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) {
- instance_->Paint(canvas, plugin_rect_, rect);
+ if (!instance_->IsFullscreen())
+ instance_->Paint(canvas, plugin_rect_, rect);
}
void WebPluginImpl::updateGeometry(
@@ -87,10 +91,12 @@ void WebPluginImpl::updateGeometry(
const WebVector<WebRect>& cut_outs_rects,
bool is_visible) {
plugin_rect_ = window_rect;
- instance_->ViewChanged(plugin_rect_, clip_rect);
+ if (!instance_->IsFullscreen())
+ instance_->ViewChanged(plugin_rect_, clip_rect);
}
void WebPluginImpl::updateFocus(bool focused) {
+ instance_->SetWebKitFocus(focused);
}
void WebPluginImpl::updateVisibility(bool visible) {
@@ -102,6 +108,8 @@ bool WebPluginImpl::acceptsInputEvents() {
bool WebPluginImpl::handleInputEvent(const WebKit::WebInputEvent& event,
WebKit::WebCursorInfo& cursor_info) {
+ if (instance_->IsFullscreen())
+ return false;
return instance_->HandleInputEvent(event, &cursor_info);
}
@@ -123,7 +131,7 @@ void WebPluginImpl::didReceiveData(const char* data, int data_length) {
void WebPluginImpl::didFinishLoading() {
if (document_loader_) {
- document_loader_->didFinishLoading(NULL);
+ document_loader_->didFinishLoading(NULL, 0);
document_loader_ = NULL;
}
}
diff --git a/webkit/glue/plugins/pepper_widget.cc b/webkit/glue/plugins/pepper_widget.cc
index 74b0e40..1ba5280 100644
--- a/webkit/glue/plugins/pepper_widget.cc
+++ b/webkit/glue/plugins/pepper_widget.cc
@@ -5,10 +5,10 @@
#include "webkit/glue/plugins/pepper_widget.h"
#include "base/logging.h"
+#include "third_party/ppapi/c/dev/ppb_widget_dev.h"
+#include "third_party/ppapi/c/dev/ppp_widget_dev.h"
#include "third_party/ppapi/c/pp_completion_callback.h"
#include "third_party/ppapi/c/pp_errors.h"
-#include "third_party/ppapi/c/ppb_widget.h"
-#include "third_party/ppapi/c/ppp_widget.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"
@@ -27,10 +27,13 @@ bool Paint(PP_Resource resource, const PP_Rect* rect, PP_Resource image_id) {
return false;
scoped_refptr<ImageData> image(Resource::GetAs<ImageData>(image_id));
- return widget && widget->Paint(rect, image);
+ if (!image)
+ return false;
+
+ return widget->Paint(rect, image);
}
-bool HandleEvent(PP_Resource resource, const PP_Event* event) {
+bool HandleEvent(PP_Resource resource, const PP_InputEvent* event) {
scoped_refptr<Widget> widget(Resource::GetAs<Widget>(resource));
return widget && widget->HandleEvent(event);
}
@@ -46,7 +49,7 @@ void SetLocation(PP_Resource resource, const PP_Rect* location) {
widget->SetLocation(location);
}
-const PPB_Widget ppb_widget = {
+const PPB_Widget_Dev ppb_widget = {
&IsWidget,
&Paint,
&HandleEvent,
@@ -65,7 +68,7 @@ Widget::~Widget() {
}
// static
-const PPB_Widget* Widget::GetInterface() {
+const PPB_Widget_Dev* Widget::GetInterface() {
return &ppb_widget;
}
@@ -80,8 +83,8 @@ void Widget::SetLocation(const PP_Rect* location) {
}
void Widget::Invalidate(const PP_Rect* dirty) {
- const PPP_Widget* widget = static_cast<const PPP_Widget*>(
- module()->GetPluginInterface(PPP_WIDGET_INTERFACE));
+ const PPP_Widget_Dev* widget = static_cast<const PPP_Widget_Dev*>(
+ module()->GetPluginInterface(PPP_WIDGET_DEV_INTERFACE));
if (!widget)
return;
ScopedResourceId resource(this);
diff --git a/webkit/glue/plugins/pepper_widget.h b/webkit/glue/plugins/pepper_widget.h
index 048a718..47826e3 100644
--- a/webkit/glue/plugins/pepper_widget.h
+++ b/webkit/glue/plugins/pepper_widget.h
@@ -9,8 +9,8 @@
#include "third_party/ppapi/c/pp_rect.h"
#include "webkit/glue/plugins/pepper_resource.h"
-typedef struct _ppb_Widget PPB_Widget;
-typedef struct _pp_Event PP_Event;
+struct PPB_Widget_Dev;
+struct PP_InputEvent;
namespace pepper {
@@ -24,14 +24,14 @@ class Widget : public Resource {
// Returns a pointer to the interface implementing PPB_Widget that is
// exposed to the plugin.
- static const PPB_Widget* GetInterface();
+ 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_Event* event) = 0;
+ virtual bool HandleEvent(const PP_InputEvent* event) = 0;
bool GetLocation(PP_Rect* location);
void SetLocation(const PP_Rect* location);
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
index fe1d7ef..a1a6d5f 100644
--- a/webkit/glue/plugins/plugin_host.cc
+++ b/webkit/glue/plugins/plugin_host.cc
@@ -13,6 +13,7 @@
#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/WebKit/WebKit/chromium/public/WebBindings.h"
#include "webkit/glue/webkit_glue.h"
@@ -449,7 +450,7 @@ static NPError PostURLNotify(NPP id,
base::SysNativeMBToWide(file_path_ascii));
}
- file_util::FileInfo post_file_info = {0};
+ 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;
diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc
index 8506623..f7b3bf7 100644
--- a/webkit/glue/plugins/plugin_instance.cc
+++ b/webkit/glue/plugins/plugin_instance.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/file_util.h"
#include "base/message_loop.h"
-#include "base/string_util.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"
@@ -489,13 +489,13 @@ void PluginInstance::RequestRead(NPStream* stream, NPByteRange* range_list) {
std::string range_info = "bytes=";
while (range_list) {
- range_info += IntToString(range_list->offset);
- range_info += "-";
- range_info += IntToString(range_list->offset + range_list->length - 1);
+ 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 += ",";
- }
+ if (range_list)
+ range_info.push_back(',');
}
if (plugin_data_stream_) {
diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h
index 36bf601..0dd3ee4 100644
--- a/webkit/glue/plugins/plugin_instance.h
+++ b/webkit/glue/plugins/plugin_instance.h
@@ -9,7 +9,6 @@
#define WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
#include <map>
-#include <set>
#include <stack>
#include <string>
#include <vector>
diff --git a/webkit/glue/plugins/plugin_lib.cc b/webkit/glue/plugins/plugin_lib.cc
index 877548e..9a0770e 100644
--- a/webkit/glue/plugins/plugin_lib.cc
+++ b/webkit/glue/plugins/plugin_lib.cc
@@ -98,8 +98,9 @@ NPPluginFuncs* PluginLib::functions() {
}
NPError PluginLib::NP_Initialize() {
- LOG(INFO) << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value() <<
- "): initialized=" << initialized_;
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
+ << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
+ << "): initialized=" << initialized_;
if (initialized_)
return NPERR_NO_ERROR;
@@ -123,8 +124,9 @@ NPError PluginLib::NP_Initialize() {
}
#endif // OS_MACOSX
#endif
- LOG(INFO) << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value() <<
- "): result=" << rv;
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
+ << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
+ << "): result=" << rv;
initialized_ = (rv == NPERR_NO_ERROR);
return rv;
}
@@ -165,7 +167,7 @@ bool PluginLib::Load() {
if (!internal_) {
library = base::LoadNativeLibrary(web_plugin_info_.path);
if (library == 0) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Couldn't load plugin " << web_plugin_info_.path.value();
return rv;
}
@@ -215,12 +217,12 @@ bool PluginLib::Load() {
if (!internal_) {
if (rv) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Plugin " << web_plugin_info_.path.value()
<< " loaded successfully.";
library_ = library;
} else {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Plugin " << web_plugin_info_.path.value()
<< " failed to load, unloading.";
base::UnloadNativeLibrary(library);
@@ -277,14 +279,14 @@ void PluginLib::Unload() {
FreePluginLibraryTask* free_library_task =
new FreePluginLibraryTask(skip_unload_ ? NULL : library_,
entry_points_.np_shutdown);
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ 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(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Unloading plugin " << web_plugin_info_.path.value();
base::UnloadNativeLibrary(library_);
}
diff --git a/webkit/glue/plugins/plugin_lib.h b/webkit/glue/plugins/plugin_lib.h
index 647916e..ca46e41 100644
--- a/webkit/glue/plugins/plugin_lib.h
+++ b/webkit/glue/plugins/plugin_lib.h
@@ -9,13 +9,13 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/file_path.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 {
diff --git a/webkit/glue/plugins/plugin_lib_mac.mm b/webkit/glue/plugins/plugin_lib_mac.mm
index 263b3b4..07da77c 100644
--- a/webkit/glue/plugins/plugin_lib_mac.mm
+++ b/webkit/glue/plugins/plugin_lib_mac.mm
@@ -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.
@@ -9,6 +9,7 @@
#include "base/native_library.h"
#include "base/scoped_cftyperef.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"
diff --git a/webkit/glue/plugins/plugin_lib_posix.cc b/webkit/glue/plugins/plugin_lib_posix.cc
index dbc64ed..fb813b6 100644
--- a/webkit/glue/plugins/plugin_lib_posix.cc
+++ b/webkit/glue/plugins/plugin_lib_posix.cc
@@ -17,6 +17,7 @@
#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"
@@ -118,14 +119,14 @@ void UnwrapNSPluginWrapper(void **dl, FilePath* unwrapped_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(INFO, PluginList::DebugPluginLoading())
+ 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(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Using unwrapped version " << unwrapped_path->value()
<< " of nspluginwrapper-wrapped plugin.";
base::UnloadNativeLibrary(*dl);
@@ -144,7 +145,7 @@ bool PluginLib::ReadWebPluginInfo(const FilePath& filename,
// Skip files that aren't appropriate for our architecture.
if (!ELFMatchesCurrentArchitecture(filename)) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Skipping plugin " << filename.value()
<< " because it doesn't match the current architecture.";
return false;
@@ -152,7 +153,7 @@ bool PluginLib::ReadWebPluginInfo(const FilePath& filename,
void* dl = base::LoadNativeLibrary(filename);
if (!dl) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "While reading plugin info, unable to load library "
<< filename.value() << ", skipping.";
return false;
@@ -193,12 +194,12 @@ bool PluginLib::ReadWebPluginInfo(const FilePath& filename,
if (description)
info->desc = UTF8ToUTF16(description);
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Got info for plugin " << filename.value()
<< " Name = \"" << UTF16ToUTF8(info->name)
<< "\", Description = \"" << UTF16ToUTF8(info->desc) << "\".";
} else {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Plugin " << filename.value()
<< " has no GetValue() and probably won't work.";
}
diff --git a/webkit/glue/plugins/plugin_lib_unittest.cc b/webkit/glue/plugins/plugin_lib_unittest.cc
index a52510b..5ac6bdc 100644
--- a/webkit/glue/plugins/plugin_lib_unittest.cc
+++ b/webkit/glue/plugins/plugin_lib_unittest.cc
@@ -5,6 +5,7 @@
#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"
diff --git a/webkit/glue/plugins/plugin_lib_win.cc b/webkit/glue/plugins/plugin_lib_win.cc
index 00f6243..382c2c8 100644
--- a/webkit/glue/plugins/plugin_lib_win.cc
+++ b/webkit/glue/plugins/plugin_lib_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.
@@ -6,12 +6,13 @@
#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
-{
+namespace NPAPI {
+
bool PluginLib::ReadWebPluginInfo(const FilePath &filename,
WebPluginInfo* info) {
// On windows, the way we get the mime types for the library is
@@ -21,8 +22,12 @@ bool PluginLib::ReadWebPluginInfo(const FilePath &filename,
// video/quicktime|audio/aiff|image/jpeg
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(filename.value()));
- if (!version_info.get())
+ 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());
diff --git a/webkit/glue/plugins/plugin_list.cc b/webkit/glue/plugins/plugin_list.cc
index a3412d7..b2a7634 100644
--- a/webkit/glue/plugins/plugin_list.cc
+++ b/webkit/glue/plugins/plugin_list.cc
@@ -9,9 +9,9 @@
#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/utf_string_conversions.h"
-#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "net/base/mime_util.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
@@ -45,8 +45,11 @@ void PluginList::RefreshPlugins() {
}
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) {
@@ -59,8 +62,11 @@ void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) {
}
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) {
@@ -108,8 +114,11 @@ bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi,
info->mime_types.clear();
- if (mime_types.empty())
+ 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);
@@ -168,8 +177,6 @@ void PluginList::LoadPlugins(bool refresh) {
internal_plugins = internal_plugins_;
}
- base::TimeTicks start_time = base::TimeTicks::Now();
-
std::vector<WebPluginInfo> new_plugins;
std::set<FilePath> visited_plugins;
@@ -209,10 +216,6 @@ void PluginList::LoadPlugins(bool refresh) {
if (webkit_glue::IsDefaultPluginEnabled())
LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins);
- base::TimeTicks end_time = base::TimeTicks::Now();
- base::TimeDelta elapsed = end_time - start_time;
- DLOG(INFO) << "Loaded plugin list in " << elapsed.InMilliseconds() << " ms.";
-
// Only update the data now since loading plugins can take a while.
AutoLock lock(lock_);
@@ -230,6 +233,9 @@ void PluginList::LoadPlugins(bool refresh) {
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;
diff --git a/webkit/glue/plugins/plugin_list_mac.mm b/webkit/glue/plugins/plugin_list_mac.mm
index 16bde9d..ee6c6ad 100644
--- a/webkit/glue/plugins/plugin_list_mac.mm
+++ b/webkit/glue/plugins/plugin_list_mac.mm
@@ -92,6 +92,14 @@ bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info,
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)
diff --git a/webkit/glue/plugins/plugin_list_posix.cc b/webkit/glue/plugins/plugin_list_posix.cc
index 1fbd76f..b23909b 100644
--- a/webkit/glue/plugins/plugin_list_posix.cc
+++ b/webkit/glue/plugins/plugin_list_posix.cc
@@ -7,6 +7,7 @@
#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"
@@ -121,6 +122,8 @@ void PluginList::GetPluginDirectories(std::vector<FilePath>* plugin_dirs) {
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).
@@ -156,7 +159,8 @@ void PluginList::GetPluginDirectories(std::vector<FilePath>* plugin_dirs) {
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
+#endif // defined(ARCH_CPU_64_BITS)
+#endif // !defined(OS_CHROMEOS)
}
void PluginList::LoadPluginsFromDir(const FilePath& dir_path,
@@ -183,18 +187,18 @@ void PluginList::LoadPluginsFromDir(const FilePath& dir_path,
// symlinks.
FilePath orig_path = path;
file_util::AbsolutePath(&path);
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Resolved " << orig_path.value() << " -> " << path.value();
if (visited_plugins->find(path) != visited_plugins->end()) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Skipping duplicate instance of " << path.value();
continue;
}
visited_plugins->insert(path);
if (IsBlacklistedPlugin(path)) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Skipping blacklisted plugin " << path.value();
continue;
}
@@ -209,14 +213,15 @@ void PluginList::LoadPluginsFromDir(const FilePath& dir_path,
// Go back to the old path.
path = orig_path;
} else {
- LOG(ERROR) << "Flash misbehaves when used from a directory containing "
- << kNetscapeInPath << ", so skipping " << orig_path.value();
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
+ << "Flash misbehaves when used from a directory containing "
+ << kNetscapeInPath << ", so skipping " << orig_path.value();
continue;
}
}
// Get mtime.
- file_util::FileInfo info;
+ base::PlatformFileInfo info;
if (!file_util::GetFileInfo(path, &info))
continue;
@@ -232,14 +237,13 @@ void PluginList::LoadPluginsFromDir(const FilePath& dir_path,
}
}
-
bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info,
std::vector<WebPluginInfo>* plugins) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Considering " << info.path.value() << " (" << info.name << ")";
if (IsUndesirablePlugin(info)) {
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< info.path.value() << " is undesirable.";
// See if we have a better version of this plugin.
@@ -248,7 +252,7 @@ bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info,
!IsUndesirablePlugin(plugins->at(i))) {
// Skip the current undesirable one so we can use the better one
// we just found.
- LOG_IF(INFO, PluginList::DebugPluginLoading())
+ LOG_IF(ERROR, PluginList::DebugPluginLoading())
<< "Skipping " << info.path.value() << ", preferring "
<< plugins->at(i).path.value();
return false;
diff --git a/webkit/glue/plugins/plugin_list_win.cc b/webkit/glue/plugins/plugin_list_win.cc
index 1c91916..b5ded9e 100644
--- a/webkit/glue/plugins/plugin_list_win.cc
+++ b/webkit/glue/plugins/plugin_list_win.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.
@@ -14,6 +14,8 @@
#include "base/path_service.h"
#include "base/registry.h"
#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_lib.h"
@@ -65,7 +67,7 @@ bool GetInstalledPath(const TCHAR* app, FilePath* out) {
reg_path.append(L"\\");
reg_path.append(app);
- RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str());
+ RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ);
std::wstring path;
if (key.ReadValue(kRegistryPath, &path)) {
*out = FilePath(path);
@@ -86,7 +88,7 @@ void GetPluginsInRegistryDirectory(
std::wstring reg_path = registry_folder;
reg_path.append(L"\\");
reg_path.append(iter.Name());
- RegKey key(root_key, reg_path.c_str());
+ RegKey key(root_key, reg_path.c_str(), KEY_READ);
std::wstring path;
if (key.ReadValue(kRegistryPath, &path))
@@ -313,8 +315,10 @@ bool IsNewerVersion(const std::wstring& a, const std::wstring& b) {
if (a_ver.size() != b_ver.size())
return false;
for (size_t i = 0; i < a_ver.size(); i++) {
- int cur_a = StringToInt(a_ver[i]);
- int cur_b = StringToInt(b_ver[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)
@@ -370,9 +374,9 @@ bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info,
SplitString(info.version, '.', &ver);
int major, minor, update;
if (ver.size() == 4 &&
- StringToInt(ver[0], &major) &&
- StringToInt(ver[1], &minor) &&
- StringToInt(ver[2], &update)) {
+ 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.
}
diff --git a/webkit/glue/plugins/plugin_stream.h b/webkit/glue/plugins/plugin_stream.h
index f15ea66..c17faaf 100644
--- a/webkit/glue/plugins/plugin_stream.h
+++ b/webkit/glue/plugins/plugin_stream.h
@@ -2,13 +2,17 @@
// 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_H__
-#define WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
+#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"
@@ -110,7 +114,8 @@ class PluginStream : public base::RefCounted<PluginStream> {
// 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);
+ int TryWriteToPlugin(const char *buf, const int length,
+ const int data_offset);
// The callback which calls TryWriteToPlugin.
void OnDelayDelivery();
@@ -141,6 +146,6 @@ class PluginStream : public base::RefCounted<PluginStream> {
DISALLOW_COPY_AND_ASSIGN(PluginStream);
};
-} // namespace NPAPI
+} // namespace NPAPI
-#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
+#endif // WEBKIT_GLUE_PLUGINS_PLUGIN_STREAM_H_
diff --git a/webkit/glue/plugins/ppb_private.h b/webkit/glue/plugins/ppb_private.h
index a0956f0..218f73a 100644
--- a/webkit/glue/plugins/ppb_private.h
+++ b/webkit/glue/plugins/ppb_private.h
@@ -5,17 +5,103 @@
#ifndef WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_
#define WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_
+#include "third_party/ppapi/c/pp_module.h"
#include "third_party/ppapi/c/pp_var.h"
#define PPB_PRIVATE_INTERFACE "PPB_Private;1"
-typedef enum _pp_ResourceString {
+typedef enum {
PP_RESOURCESTRING_PDFGETPASSWORD = 0,
} PP_ResourceString;
-typedef struct _ppb_Private {
+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_PRIVATEFONTPITCH_DEFAULT = 0,
+ PP_PRIVATEFONTPITCH_FIXED = 1
+} PP_PrivateFontPitch;
+
+typedef enum {
+ PP_PRIVATEFONTFAMILY_DEFAULT = 0,
+ PP_PRIVATEFONTFAMILY_ROMAN = 1,
+ PP_PRIVATEFONTFAMILY_SCRIPT = 2
+} PP_PrivateFontFamily;
+
+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;
+ PP_PrivateFontPitch pitch;
+ PP_PrivateFontFamily family;
+ PP_PrivateFontCharset charset;
+};
+
+struct PPB_Private {
// Returns a localized string.
- PP_Var (*GetLocalizedString)(PP_ResourceString string_id);
-} PPB_Private;
+ 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. Linux only.
+ PP_Resource (*GetFontFileWithFallback)(
+ PP_Module module,
+ const PP_PrivateFontFileDescription* description);
+
+ // 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);
+};
#endif // WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_
diff --git a/webkit/glue/plugins/test/npapi_test.cc b/webkit/glue/plugins/test/npapi_test.cc
index d7c4fa7..895a842 100644
--- a/webkit/glue/plugins/test/npapi_test.cc
+++ b/webkit/glue/plugins/test/npapi_test.cc
@@ -66,13 +66,55 @@ EXPORT NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
return NPAPIClient::PluginClient::GetEntryPoints(pFuncs);
}
-EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* pFuncs) {
- return NPAPIClient::PluginClient::Initialize(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 {
diff --git a/webkit/glue/plugins/test/plugin_arguments_test.cc b/webkit/glue/plugins/test/plugin_arguments_test.cc
index ee6d2c0..46ccf43 100644
--- a/webkit/glue/plugins/test/plugin_arguments_test.cc
+++ b/webkit/glue/plugins/test/plugin_arguments_test.cc
@@ -1,9 +1,10 @@
-// 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/basictypes.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "webkit/glue/plugins/test/plugin_arguments_test.h"
@@ -45,7 +46,7 @@ NPError PluginArgumentsTest::New(uint16 mode, int16 argc,
int size = atoi(size_string);
for (int index = 1; index <= max_args; index++) {
- std::string arg_name = StringPrintf("%s%d", "val", 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);
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.cc b/webkit/glue/plugins/test/plugin_geturl_test.cc
index f321b4b..aedf582 100644
--- a/webkit/glue/plugins/test/plugin_geturl_test.cc
+++ b/webkit/glue/plugins/test/plugin_geturl_test.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,6 +8,8 @@
#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.
@@ -357,7 +359,7 @@ void PluginGetURLTest::URLNotify(const char* url, NPReason reason, void* data) {
case BOGUS_URL_STREAM_ID:
if (reason != NPRES_NETWORK_ERR) {
std::string err = "BOGUS_URL received unexpected URLNotify status: ";
- err.append(IntToString(reason));
+ err.append(base::IntToString(reason));
SetError(err);
}
tests_in_progress_--;
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
index b62a764..10b3239 100644
--- a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
+++ b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
@@ -17,7 +17,8 @@ NPObjectDeletePluginInNPN_Evaluate*
NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
NPNetscapeFuncs *host_functions)
: PluginTest(id, host_functions),
- other_plugin_instance_object_(NULL) {
+ other_plugin_instance_object_(NULL),
+ timer_id_(0) {
}
NPError NPObjectLifetimeTest::SetWindow(NPWindow* pNPWindow) {
@@ -30,8 +31,8 @@ NPError NPObjectLifetimeTest::SetWindow(NPWindow* pNPWindow) {
// 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, kNPObjectLifetimeTimer, kNPObjectLifetimeTimerElapse,
- TimerProc);
+ timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
+ kNPObjectLifetimeTimerElapse, TimerProc);
}
return NPERR_NO_ERROR;
}
@@ -40,10 +41,11 @@ void CALLBACK NPObjectLifetimeTest::TimerProc(
HWND window, UINT message, UINT timer_id,
unsigned long elapsed_milli_seconds) {
- KillTimer(window, kNPObjectLifetimeTimer);
NPObjectLifetimeTest* this_instance =
reinterpret_cast<NPObjectLifetimeTest*>
(::GetProp(window, L"Plugin_Instance"));
+ KillTimer(window, this_instance->timer_id_);
+ this_instance->timer_id_ = 0;
this_instance->other_plugin_instance_object_ =
NPObjectLifetimeTestInstance2::plugin_instance_object_;
@@ -107,7 +109,7 @@ NPObjectDeletePluginInNPN_Evaluate::NPObjectDeletePluginInNPN_Evaluate(
NPP id, NPNetscapeFuncs *host_functions)
: PluginTest(id, host_functions),
plugin_instance_object_(NULL),
- npn_evaluate_timer_proc_set_(false) {
+ timer_id_(0) {
g_npn_evaluate_test_instance_ = this;
}
@@ -128,12 +130,10 @@ NPError NPObjectDeletePluginInNPN_Evaluate::SetWindow(NPWindow* np_window) {
// 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 (!npn_evaluate_timer_proc_set_) {
- npn_evaluate_timer_proc_set_ = true;
- SetTimer(window_handle, kNPObjectLifetimeTimer, kNPObjectLifetimeTimerElapse,
- TimerProc);
+ if (!timer_id_) {
+ timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
+ kNPObjectLifetimeTimerElapse, TimerProc);
}
-
return NPERR_NO_ERROR;
}
@@ -141,7 +141,8 @@ void CALLBACK NPObjectDeletePluginInNPN_Evaluate::TimerProc(
HWND window, UINT message, UINT timer_id,
unsigned long elapsed_milli_seconds) {
- KillTimer(window, kNPObjectLifetimeTimer);
+ 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,
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
index 4303d99..60d0314 100644
--- a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
+++ b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
@@ -30,6 +30,7 @@ class NPObjectLifetimeTest : public PluginTest {
#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);
};
@@ -67,10 +68,10 @@ class NPObjectDeletePluginInNPN_Evaluate : public PluginTest {
#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:
- bool npn_evaluate_timer_proc_set_;
static NPObjectDeletePluginInNPN_Evaluate* g_npn_evaluate_test_instance_;
DISALLOW_IMPLICIT_CONSTRUCTORS(NPObjectDeletePluginInNPN_Evaluate);
diff --git a/webkit/glue/plugins/test/plugin_schedule_timer_test.h b/webkit/glue/plugins/test/plugin_schedule_timer_test.h
index 9ca947f..e3e6505 100644
--- a/webkit/glue/plugins/test/plugin_schedule_timer_test.h
+++ b/webkit/glue/plugins/test/plugin_schedule_timer_test.h
@@ -1,12 +1,10 @@
-// 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.
#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
-#include <vector>
-
#include "base/at_exit.h"
#include "base/time.h"
#include "webkit/glue/plugins/test/plugin_test.h"
diff --git a/webkit/glue/plugins/test/plugin_test.h b/webkit/glue/plugins/test/plugin_test.h
index f06307e..eed6e3f 100644
--- a/webkit/glue/plugins/test/plugin_test.h
+++ b/webkit/glue/plugins/test/plugin_test.h
@@ -1,12 +1,13 @@
-// 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.
-#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
-#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+#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"
@@ -82,9 +83,9 @@ class PluginTest {
if (val1 != val2) {
std::string err;
err = "Expected Equal for '";
- err.append(IntToString(val1));
+ err.append(base::IntToString(val1));
err.append("' and '");
- err.append(IntToString(val2));
+ err.append(base::IntToString(val2));
err.append("'");
SetError(err);
}
@@ -128,4 +129,4 @@ class PluginTest {
} // namespace NPAPIClient
-#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+#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
index e2b42b3..62a3977 100644
--- a/webkit/glue/plugins/test/plugin_test_factory.cc
+++ b/webkit/glue/plugins/test/plugin_test_factory.cc
@@ -66,7 +66,8 @@ PluginTest* CreatePluginTest(const std::string& test_name,
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") {
+ } 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") {
@@ -86,7 +87,8 @@ PluginTest* CreatePluginTest(const std::string& test_name,
} 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 == "ensure_scripting_works_in_destroy" ||
+ test_name == "invoke_js_function_on_create") {
new_test = new WindowedPluginTest(instance, host_functions);
#endif
}
diff --git a/webkit/glue/plugins/test/plugin_thread_async_call_test.cc b/webkit/glue/plugins/test/plugin_thread_async_call_test.cc
index 2e9f9e9..c01a49e 100644
--- a/webkit/glue/plugins/test/plugin_thread_async_call_test.cc
+++ b/webkit/glue/plugins/test/plugin_thread_async_call_test.cc
@@ -4,6 +4,7 @@
#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"
diff --git a/webkit/glue/plugins/test/plugin_thread_async_call_test.h b/webkit/glue/plugins/test/plugin_thread_async_call_test.h
index 020e5e1..78e4e8d 100644
--- a/webkit/glue/plugins/test/plugin_thread_async_call_test.h
+++ b/webkit/glue/plugins/test/plugin_thread_async_call_test.h
@@ -1,16 +1,17 @@
-// 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.
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H
+#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
-#include <vector>
-
-#include "base/at_exit.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
@@ -35,4 +36,4 @@ class PluginThreadAsyncCallTest : public PluginTest {
} // namespace NPAPIClient
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
diff --git a/webkit/glue/plugins/test/plugin_windowed_test.cc b/webkit/glue/plugins/test/plugin_windowed_test.cc
index 5ae8e30..461fc20 100644
--- a/webkit/glue/plugins/test/plugin_windowed_test.cc
+++ b/webkit/glue/plugins/test/plugin_windowed_test.cc
@@ -36,7 +36,8 @@ NPError WindowedPluginTest::SetWindow(NPWindow* pNPWindow) {
}
if ((test_name() == "create_instance_in_paint" && test_id() == "1") ||
- test_name() == "alert_in_window_message") {
+ test_name() == "alert_in_window_message" ||
+ test_name() == "invoke_js_function_on_create") {
static ATOM window_class = 0;
if (!window_class) {
WNDCLASSEX wcex;
@@ -130,6 +131,11 @@ LRESULT CALLBACK WindowedPluginTest::WindowProc(
// 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");
}
}
diff --git a/webkit/glue/plugins/test/plugin_windowless_test.cc b/webkit/glue/plugins/test/plugin_windowless_test.cc
index c47c1d7..aa6a9d7 100644
--- a/webkit/glue/plugins/test/plugin_windowless_test.cc
+++ b/webkit/glue/plugins/test/plugin_windowless_test.cc
@@ -1,8 +1,9 @@
-// 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.
#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"
@@ -151,9 +152,9 @@ void WindowlessPluginTest::MultipleInstanceSyncCalls(NPNetscapeFuncs* browser) {
#if defined(OS_MACOSX)
std::string StringForPoint(int x, int y) {
std::string point_string("(");
- point_string.append(IntToString(x));
+ point_string.append(base::IntToString(x));
point_string.append(", ");
- point_string.append(IntToString(y));
+ point_string.append(base::IntToString(y));
point_string.append(")");
return point_string;
}
diff --git a/webkit/glue/plugins/webplugin.cc b/webkit/glue/plugins/webplugin.cc
index 6443318..18f722b 100644
--- a/webkit/glue/plugins/webplugin.cc
+++ b/webkit/glue/plugins/webplugin.cc
@@ -12,6 +12,9 @@ WebPluginGeometry::WebPluginGeometry()
visible(false) {
}
+WebPluginGeometry::~WebPluginGeometry() {
+}
+
bool WebPluginGeometry::Equals(const WebPluginGeometry& rhs) const {
return window == rhs.window &&
window_rect == rhs.window_rect &&
diff --git a/webkit/glue/plugins/webplugin.h b/webkit/glue/plugins/webplugin.h
index 1813842..19c6cb0 100644
--- a/webkit/glue/plugins/webplugin.h
+++ b/webkit/glue/plugins/webplugin.h
@@ -33,6 +33,7 @@ class WebPluginResourceClient;
// Describes the new location for a plugin window.
struct WebPluginGeometry {
WebPluginGeometry();
+ ~WebPluginGeometry();
bool Equals(const WebPluginGeometry& rhs) const;
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc
index b73b5ae..5374546 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl.cc
+++ b/webkit/glue/plugins/webplugin_delegate_impl.cc
@@ -156,6 +156,42 @@ void WebPluginDelegateImpl::UpdateGeometry(
}
}
+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();
}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
index ebf5d3e..650d398 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl.h
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H_
-#define WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H_
+#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 <set>
-#include "base/file_path.h"
#include "base/ref_counted.h"
#include "base/task.h"
#include "base/time.h"
@@ -27,9 +25,13 @@
#endif
#if defined(USE_X11)
+#include "app/x11_util.h"
+
typedef struct _GdkDrawable GdkPixmap;
#endif
+class FilePath;
+
namespace NPAPI {
class PluginInstance;
}
@@ -135,6 +137,9 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// 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.
@@ -148,16 +153,14 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
static WebPluginDelegateImpl* GetActiveDelegate();
// Informs the plugin that the window it is in has gained or lost focus.
void SetWindowHasFocus(bool has_focus);
- // Informs the plugin that the view it is in has gained or lost first
- // responder status.
- void SetContentAreaHasFocus(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(gfx::Rect window_frame, gfx::Rect view_frame);
+ void WindowFrameChanged(const gfx::Rect& window_frame,
+ const gfx::Rect& view_frame);
// Informs the delegate that the plugin set a Carbon ThemeCursor.
void SetThemeCursor(ThemeCursor cursor);
// Informs the delegate that the plugin set a Carbon Cursor.
@@ -181,6 +184,12 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
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;
@@ -246,6 +255,14 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// 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
@@ -289,9 +306,12 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// layout of this process with the one of the browser process.
HKL keyboard_layout_;
int parent_thread_id_;
-#endif // OS_WIN
+#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_;
@@ -366,10 +386,6 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// Updates everything that depends on the plugin's absolute screen location.
void PluginScreenLocationChanged();
- // Informs the plugin that it has gained or lost keyboard focus (i.e., window
- // first responder status).
- void SetPluginHasFocus(bool has_focus);
-
// Returns the apparent zoom ratio for the given event, as inferred from our
// current knowledge about about where on screen the plugin is.
// This is a temporary workaround for <http://crbug.com/9996>; once that is
@@ -424,14 +440,6 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// relative to an upper-left (0,0).
gfx::Point content_area_origin_;
- // True if the plugin thinks it has keyboard focus
- bool plugin_has_focus_;
- // True if the plugin element has focus within the page, regardless of whether
- // its containing view is currently the first responder for the window.
- bool has_webkit_focus_;
- // True if the containing view is the window's first responder.
- bool containing_view_has_focus_;
-
bool containing_window_has_focus_;
bool initial_window_focus_;
bool container_is_visible_;
@@ -484,7 +492,18 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// 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_;
+
DISALLOW_COPY_AND_ASSIGN(WebPluginDelegateImpl);
};
-#endif // WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H_
+#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
index 18b1504..3d112fa 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
+++ b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
@@ -44,6 +44,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
windowless_(false),
plugin_(NULL),
instance_(instance),
+ windowless_shm_pixmap_(None),
pixmap_(NULL),
first_event_time_(-1.0),
plug_(NULL),
@@ -51,7 +52,10 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
parent_(containing_view),
quirks_(0),
handle_event_depth_(0),
- first_set_window_call_(true) {
+ first_set_window_call_(true),
+ plugin_has_focus_(false),
+ has_webkit_focus_(false),
+ containing_view_has_focus_(true) {
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
@@ -399,47 +403,99 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_t* context,
pixmap_draw_rect.right(),
pixmap_draw_rect.bottom());
- 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);
-
// Construct the paint message, targeting the pixmap.
NPEvent np_event = {0};
XGraphicsExposeEvent &event = np_event.xgraphicsexpose;
event.type = GraphicsExpose;
- event.display = GDK_DISPLAY();
- event.drawable = GDK_PIXMAP_XID(pixmap_);
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();
- // Tell the plugin to paint into the pixmap.
- static StatsRate plugin_paint("Plugin.Paint");
- StatsScope<StatsRate> scope(plugin_paint);
- NPError err = instance()->NPP_HandleEvent(&np_event);
- DCHECK_EQ(err, NPERR_NO_ERROR);
+ 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 StatsRate plugin_paint("Plugin.Paint");
+ StatsScope<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);
+ 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 StatsRate plugin_paint("Plugin.Paint");
+ StatsScope<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);
+ // 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);
+ cairo_restore(context);
+ }
}
void WebPluginDelegateImpl::WindowlessSetWindow() {
@@ -485,7 +541,7 @@ void WebPluginDelegateImpl::WindowlessSetWindow() {
}
}
-void WebPluginDelegateImpl::SetFocus(bool focused) {
+bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
DCHECK(instance()->windowless());
NPEvent np_event = {0};
@@ -496,6 +552,7 @@ void WebPluginDelegateImpl::SetFocus(bool focused) {
event.mode = -1;
event.detail = NotifyDetailNone;
instance()->NPP_HandleEvent(&np_event);
+ return true;
}
// Converts a WebInputEvent::Modifiers bitfield into a
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
index efa6bdd..614f1d2 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
+++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
@@ -12,11 +12,11 @@
#include <set>
#include "base/file_util.h"
-#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
+#include "base/utf_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"
@@ -258,16 +258,16 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
layer_(nil),
surface_(NULL),
renderer_(nil),
- plugin_has_focus_(false),
- has_webkit_focus_(false),
- containing_view_has_focus_(false),
containing_window_has_focus_(false),
initial_window_focus_(false),
container_is_visible_(false),
have_called_set_window_(false),
external_drag_tracker_(new ExternalDragTracker()),
handle_event_depth_(0),
- first_set_window_call_(true) {
+ first_set_window_call_(true),
+ plugin_has_focus_(false),
+ has_webkit_focus_(false),
+ containing_view_has_focus_(true) {
memset(&window_, 0, sizeof(window_));
#ifndef NP_NO_CARBON
memset(&np_cg_context_, 0, sizeof(np_cg_context_));
@@ -385,12 +385,6 @@ bool WebPluginDelegateImpl::PlatformInitialize() {
break;
}
- // TODO(stuartmorgan): We need real plugin container visibility information
- // when the plugin is initialized; for now, assume it's visible.
- // None of the calls SetContainerVisibility would make are useful at this
- // point, so we just set the initial state directly.
- container_is_visible_ = true;
-
// 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).
@@ -472,15 +466,6 @@ void WebPluginDelegateImpl::Print(CGContextRef context) {
NOTIMPLEMENTED();
}
-void WebPluginDelegateImpl::SetFocus(bool focused) {
- // This is called when internal WebKit focus (the focused element on the page)
- // changes, but plugins need to know about actual first responder status, so
- // we have an extra layer of focus tracking.
- has_webkit_focus_ = focused;
- if (containing_view_has_focus_)
- SetPluginHasFocus(focused);
-}
-
bool WebPluginDelegateImpl::PlatformHandleInputEvent(
const WebInputEvent& event, WebCursorInfo* cursor_info) {
DCHECK(cursor_info != NULL);
@@ -497,12 +482,6 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent(
if (WebInputEvent::isMouseEventType(event.type) ||
event.type == WebInputEvent::MouseWheel) {
- // Ideally we would compute the content origin from the web event using the
- // code below as a safety net for missed content area location changes.
- // Because of <http://crbug.com/9996>, however, only globalX/Y are right if
- // the page has been zoomed, so for now the coordinates we get aren't
- // trustworthy enough to use for corrections.
-#if PLUGIN_SCALING_FIXED
// 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 =
@@ -517,7 +496,6 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent(
<< content_origin;
SetContentAreaOrigin(content_origin);
}
-#endif
current_windowless_cursor_.GetCursorInfo(cursor_info);
}
@@ -593,25 +571,6 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent(
}
}
-#ifndef PLUGIN_SCALING_FIXED
- // Because of <http://crbug.com/9996>, the non-global coordinates we get for
- // zoomed pages are wrong. As a temporary hack around that bug, override the
- // coordinates we are given with ones computed based on our knowledge of where
- // the plugin is on screen. We only need to do this for Cocoa, since Carbon
- // only uses the global coordinates.
- if (instance()->event_model() == NPEventModelCocoa &&
- (WebInputEvent::isMouseEventType(event.type) ||
- event.type == WebInputEvent::MouseWheel)) {
- const WebMouseEvent* mouse_event =
- static_cast<const WebMouseEvent*>(&event);
- NPCocoaEvent* cocoa_event = static_cast<NPCocoaEvent*>(plugin_event);
- cocoa_event->data.mouse.pluginX =
- mouse_event->globalX - content_area_origin_.x() - window_rect_.x();
- cocoa_event->data.mouse.pluginY =
- mouse_event->globalY - content_area_origin_.y() - window_rect_.y();
- }
-#endif
-
// Send the plugin the event.
scoped_ptr<NPAPI::ScopedCurrentPluginEvent> event_scope(NULL);
if (instance()->event_model() == NPEventModelCocoa) {
@@ -855,13 +814,9 @@ void WebPluginDelegateImpl::SetWindowHasFocus(bool has_focus) {
}
}
-void WebPluginDelegateImpl::SetPluginHasFocus(bool has_focus) {
+bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
if (!have_called_set_window_)
- return;
-
- if (has_focus == plugin_has_focus_)
- return;
- plugin_has_focus_ = has_focus;
+ return false;
ScopedActiveDelegate active_delegate(this);
@@ -869,7 +824,7 @@ void WebPluginDelegateImpl::SetPluginHasFocus(bool has_focus) {
#ifndef NP_NO_CARBON
case NPEventModelCarbon: {
NPEvent focus_event = { 0 };
- if (plugin_has_focus_)
+ if (focused)
focus_event.what = NPEventType_GetFocusEvent;
else
focus_event.what = NPEventType_LoseFocusEvent;
@@ -882,16 +837,12 @@ void WebPluginDelegateImpl::SetPluginHasFocus(bool has_focus) {
NPCocoaEvent focus_event;
memset(&focus_event, 0, sizeof(focus_event));
focus_event.type = NPCocoaEventFocusChanged;
- focus_event.data.focus.hasFocus = plugin_has_focus_;
+ focus_event.data.focus.hasFocus = focused;
instance()->NPP_HandleEvent(&focus_event);
break;
}
}
-}
-
-void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus) {
- containing_view_has_focus_ = has_focus;
- SetPluginHasFocus(containing_view_has_focus_ && has_webkit_focus_);
+ return true;
}
void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) {
@@ -925,8 +876,8 @@ void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) {
instance()->webplugin()->InvalidateRect(gfx::Rect());
}
-void WebPluginDelegateImpl::WindowFrameChanged(gfx::Rect window_frame,
- gfx::Rect view_frame) {
+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()));
}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_win.cc b/webkit/glue/plugins/webplugin_delegate_impl_win.cc
index 09184ab..9cdc7db 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_win.cc
+++ b/webkit/glue/plugins/webplugin_delegate_impl_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.
@@ -15,7 +15,10 @@
#include "base/registry.h"
#include "base/scoped_ptr.h"
#include "base/stats_counters.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/win_util.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
@@ -264,7 +267,10 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
user_gesture_msg_factory_(this),
handle_event_depth_(0),
mouse_hook_(NULL),
- first_set_window_call_(true) {
+ first_set_window_call_(true),
+ plugin_has_focus_(false),
+ has_webkit_focus_(false),
+ containing_view_has_focus_(true) {
memset(&window_, 0, sizeof(window_));
const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
@@ -285,7 +291,8 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
std::vector<std::wstring> version;
SplitString(plugin_info.version, L'.', &version);
if (version.size() > 0) {
- int major = static_cast<int>(StringToInt64(version[0]));
+ int major;
+ base::StringToInt(version[0], &major);
if (major >= 9) {
quirks_ |= PLUGIN_QUIRK_DIE_AFTER_UNLOAD;
@@ -410,7 +417,8 @@ bool WebPluginDelegateImpl::PlatformInitialize() {
if ((quirks_ & PLUGIN_QUIRK_PATCH_REGENUMKEYEXW) &&
win_util::GetWinVersion() == win_util::WINVERSION_XP &&
!RegKey().Open(HKEY_LOCAL_MACHINE,
- L"SOFTWARE\\Microsoft\\MediaPlayer\\ShimInclusionList\\chrome.exe") &&
+ 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",
@@ -1048,7 +1056,7 @@ void WebPluginDelegateImpl::WindowlessSetWindow() {
DCHECK(err == NPERR_NO_ERROR);
}
-void WebPluginDelegateImpl::SetFocus(bool focused) {
+bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
DCHECK(instance()->windowless());
NPEvent focus_event;
@@ -1057,6 +1065,7 @@ void WebPluginDelegateImpl::SetFocus(bool focused) {
focus_event.lParam = 0;
instance()->NPP_HandleEvent(&focus_event);
+ return true;
}
static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,
@@ -1187,7 +1196,7 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent(
parent_thread_id_ = GetWindowThreadProcessId(parent_, NULL);
HKL parent_layout = GetKeyboardLayout(parent_thread_id_);
if (keyboard_layout_ != parent_layout) {
- std::wstring layout_name(StringPrintf(L"%08x", parent_layout));
+ std::wstring layout_name(base::StringPrintf(L"%08x", parent_layout));
LoadKeyboardLayout(layout_name.c_str(), KLF_ACTIVATE);
keyboard_layout_ = parent_layout;
}
diff --git a/webkit/glue/plugins/webplugin_impl.cc b/webkit/glue/plugins/webplugin_impl.cc
index 1660ede..80bc197 100644
--- a/webkit/glue/plugins/webplugin_impl.cc
+++ b/webkit/glue/plugins/webplugin_impl.cc
@@ -7,6 +7,7 @@
#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"
@@ -113,7 +114,7 @@ class MultiPartResponseClient : public WebURLLoaderClient {
byte_range_lower_bound_ += data_size;
}
- virtual void didFinishLoading(WebURLLoader*) {}
+ virtual void didFinishLoading(WebURLLoader*, double finishTime) {}
virtual void didFail(WebURLLoader*, const WebURLError&) {}
void Clear() {
@@ -160,7 +161,7 @@ std::string GetAllHeaders(const WebURLResponse& response) {
return result;
// TODO(darin): Shouldn't we also report HTTP version numbers?
- result = StringPrintf("HTTP %d ", response.httpStatusCode());
+ result = base::StringPrintf("HTTP %d ", response.httpStatusCode());
result.append(status.utf8());
result.append("\n");
@@ -340,6 +341,10 @@ bool WebPluginImpl::acceptsInputEvents() {
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);
}
@@ -913,7 +918,7 @@ void WebPluginImpl::didReceiveData(WebURLLoader* loader,
}
}
-void WebPluginImpl::didFinishLoading(WebURLLoader* loader) {
+void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) {
ClientInfo* client_info = GetClientInfoFromLoader(loader);
if (client_info && client_info->client) {
MultiPartResponseHandlerMap::iterator index =
diff --git a/webkit/glue/plugins/webplugin_impl.h b/webkit/glue/plugins/webplugin_impl.h
index 9b75e6e..5fe96d2 100644
--- a/webkit/glue/plugins/webplugin_impl.h
+++ b/webkit/glue/plugins/webplugin_impl.h
@@ -204,7 +204,8 @@ class WebPluginImpl : public WebPlugin,
const WebKit::WebURLResponse& response);
virtual void didReceiveData(WebKit::WebURLLoader* loader, const char *buffer,
int length);
- virtual void didFinishLoading(WebKit::WebURLLoader* loader);
+ virtual void didFinishLoading(WebKit::WebURLLoader* loader,
+ double finishTime);
virtual void didFail(WebKit::WebURLLoader* loader,
const WebKit::WebURLError& error);
diff --git a/webkit/glue/plugins/webview_plugin.cc b/webkit/glue/plugins/webview_plugin.cc
index 413ae10..231bd37 100644
--- a/webkit/glue/plugins/webview_plugin.cc
+++ b/webkit/glue/plugins/webview_plugin.cc
@@ -4,6 +4,7 @@
#include "webkit/glue/plugins/webview_plugin.h"
+#include "base/histogram.h"
#include "base/message_loop.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
@@ -12,6 +13,7 @@
#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"
#if WEBKIT_USING_CG
@@ -27,18 +29,21 @@ 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) {
+ container_(NULL),
+ finished_loading_(false) {
web_view_ = WebView::create(this, NULL);
web_view_->initializeMainFrame(this);
}
@@ -47,6 +52,26 @@ 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_);
+ }
+}
+
bool WebViewPlugin::initialize(WebPluginContainer* container) {
container_ = container;
return true;
@@ -55,6 +80,7 @@ bool WebViewPlugin::initialize(WebPluginContainer* container) {
void WebViewPlugin::destroy() {
delegate_->WillDestroyPlugin();
delegate_ = NULL;
+ container_ = NULL;
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
@@ -104,6 +130,25 @@ bool WebViewPlugin::handleInputEvent(const WebInputEvent& event,
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::startDragging(const WebDragData&,
WebDragOperationsMask,
const WebImage&,
@@ -114,7 +159,7 @@ void WebViewPlugin::startDragging(const WebDragData&,
void WebViewPlugin::didInvalidateRect(const WebRect& rect) {
if (container_)
- container_->invalidateRect(WebRect(rect));
+ container_->invalidateRect(rect);
}
void WebViewPlugin::didChangeCursor(const WebCursorInfo& cursor) {
@@ -122,7 +167,8 @@ void WebViewPlugin::didChangeCursor(const WebCursorInfo& cursor) {
}
void WebViewPlugin::didClearWindowObject(WebFrame* frame) {
- delegate_->BindWebFrame(frame);
+ if (delegate_)
+ delegate_->BindWebFrame(frame);
}
bool WebViewPlugin::canHandleRequest(WebFrame* frame,
diff --git a/webkit/glue/plugins/webview_plugin.h b/webkit/glue/plugins/webview_plugin.h
index 2e41218..757a012 100644
--- a/webkit/glue/plugins/webview_plugin.h
+++ b/webkit/glue/plugins/webview_plugin.h
@@ -5,11 +5,14 @@
#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/WebPlugin.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/WebURLResponse.h"
#include "third_party/WebKit/WebKit/chromium/public/WebViewClient.h"
// This class implements the WebPlugin interface by forwarding drawing and
@@ -36,9 +39,14 @@ class WebViewPlugin: public WebKit::WebPlugin, public WebKit::WebViewClient,
explicit WebViewPlugin(Delegate* delegate);
- virtual WebKit::WebView* web_view() { return web_view_; }
+ WebKit::WebView* web_view() { return web_view_; }
- virtual WebKit::WebPluginContainer* container() { return container_; }
+ 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);
// WebPlugin methods:
virtual bool initialize(WebKit::WebPluginContainer*);
@@ -60,10 +68,10 @@ class WebViewPlugin: public WebKit::WebPlugin, public WebKit::WebViewClient,
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 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(
@@ -102,6 +110,11 @@ class WebViewPlugin: public WebKit::WebPlugin, public WebKit::WebViewClient,
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_;
};
#endif // WEBKIT_GLUE_PLUGINS_WEBVIEW_PLUGIN_H_
diff --git a/webkit/glue/resource_fetcher.cc b/webkit/glue/resource_fetcher.cc
index 186092b..9b00805 100644
--- a/webkit/glue/resource_fetcher.cc
+++ b/webkit/glue/resource_fetcher.cc
@@ -88,7 +88,8 @@ void ResourceFetcher::didReceiveCachedMetadata(
metadata_.assign(data, data_length);
}
-void ResourceFetcher::didFinishLoading(WebURLLoader* loader) {
+void ResourceFetcher::didFinishLoading(
+ WebURLLoader* loader, double finishTime) {
DCHECK(!completed_);
completed_ = true;
@@ -119,6 +120,9 @@ ResourceFetcherWithTimeout::ResourceFetcherWithTimeout(
&ResourceFetcherWithTimeout::TimeoutFired);
}
+ResourceFetcherWithTimeout::~ResourceFetcherWithTimeout() {
+}
+
void ResourceFetcherWithTimeout::TimeoutFired() {
if (!completed_) {
loader_->cancel();
diff --git a/webkit/glue/resource_fetcher.h b/webkit/glue/resource_fetcher.h
index 7910fc1..ff00939 100644
--- a/webkit/glue/resource_fetcher.h
+++ b/webkit/glue/resource_fetcher.h
@@ -65,7 +65,8 @@ class ResourceFetcher : public WebKit::WebURLLoaderClient {
WebKit::WebURLLoader* loader, const char* data, int data_length);
virtual void didReceiveData(
WebKit::WebURLLoader* loader, const char* data, int data_length);
- virtual void didFinishLoading(WebKit::WebURLLoader* loader);
+ virtual void didFinishLoading(
+ WebKit::WebURLLoader* loader, double finishTime);
virtual void didFail(
WebKit::WebURLLoader* loader, const WebKit::WebURLError& error);
@@ -100,7 +101,7 @@ class ResourceFetcherWithTimeout : public ResourceFetcher {
public:
ResourceFetcherWithTimeout(const GURL& url, WebKit::WebFrame* frame,
int timeout_secs, Callback* c);
- virtual ~ResourceFetcherWithTimeout() {}
+ virtual ~ResourceFetcherWithTimeout();
private:
// Callback for timer that limits how long we wait for the alternate error
diff --git a/webkit/glue/resource_fetcher_unittest.cc b/webkit/glue/resource_fetcher_unittest.cc
index 98cef0a..70c316b 100644
--- a/webkit/glue/resource_fetcher_unittest.cc
+++ b/webkit/glue/resource_fetcher_unittest.cc
@@ -5,6 +5,7 @@
#include "webkit/glue/resource_fetcher.h"
#include "base/callback.h"
+#include "base/message_loop.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
@@ -24,13 +25,8 @@ using webkit_glue::ResourceFetcherWithTimeout;
namespace {
class ResourceFetcherTests : public TestShellTest {
- public:
- void SetUp() {
- TestShellTest::SetUp();
- }
- void TearDown() {
- TestShellTest::TearDown();
- }
+ protected:
+ UnittestTestServer test_server_;
};
static const int kMaxWaitTimeMs = 5000;
@@ -154,13 +150,11 @@ FetcherDelegate* FetcherDelegate::instance_ = NULL;
// Test a fetch from the test server.
TEST_F(ResourceFetcherTests, ResourceFetcherDownload) {
- scoped_refptr<UnittestTestServer> server =
- UnittestTestServer::CreateServer();
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
WebFrame* frame = test_shell_->webView()->mainFrame();
- GURL url = server->TestServerPage("files/test_shell/index.html");
+ GURL url(test_server_.GetURL("files/test_shell/index.html"));
scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcher(
url, frame, delegate->NewCallback()));
@@ -173,7 +167,7 @@ TEST_F(ResourceFetcherTests, ResourceFetcherDownload) {
EXPECT_TRUE(text.find("What is this page?") != std::string::npos);
// Test 404 response.
- url = server->TestServerPage("files/thisfiledoesntexist.html");
+ url = test_server_.GetURL("files/thisfiledoesntexist.html");
delegate.reset(new FetcherDelegate);
fetcher.reset(new ResourceFetcher(url, frame, delegate->NewCallback()));
@@ -185,9 +179,7 @@ TEST_F(ResourceFetcherTests, ResourceFetcherDownload) {
}
TEST_F(ResourceFetcherTests, ResourceFetcherDidFail) {
- scoped_refptr<UnittestTestServer> server =
- UnittestTestServer::CreateServer();
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
WebFrame* frame = test_shell_->webView()->mainFrame();
@@ -208,15 +200,13 @@ TEST_F(ResourceFetcherTests, ResourceFetcherDidFail) {
}
TEST_F(ResourceFetcherTests, ResourceFetcherTimeout) {
- scoped_refptr<UnittestTestServer> server =
- UnittestTestServer::CreateServer();
- ASSERT_TRUE(NULL != server.get());
+ ASSERT_TRUE(test_server_.Start());
WebFrame* frame = test_shell_->webView()->mainFrame();
// Grab a page that takes at least 1 sec to respond, but set the fetcher to
// timeout in 0 sec.
- GURL url = server->TestServerPage("slow?1");
+ GURL url(test_server_.GetURL("slow?1"));
scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcherWithTimeout(
url, frame, 0, delegate->NewCallback()));
diff --git a/webkit/glue/resource_loader_bridge.cc b/webkit/glue/resource_loader_bridge.cc
index 8845256..ab19082 100644
--- a/webkit/glue/resource_loader_bridge.cc
+++ b/webkit/glue/resource_loader_bridge.cc
@@ -15,7 +15,8 @@ ResourceLoaderBridge::RequestInfo::RequestInfo()
request_type(ResourceType::MAIN_FRAME),
request_context(0),
appcache_host_id(0),
- routing_id(0) {
+ routing_id(0),
+ download_to_file(false) {
}
ResourceLoaderBridge::RequestInfo::~RequestInfo() {
diff --git a/webkit/glue/resource_loader_bridge.h b/webkit/glue/resource_loader_bridge.h
index e66181f..eae1404 100644
--- a/webkit/glue/resource_loader_bridge.h
+++ b/webkit/glue/resource_loader_bridge.h
@@ -21,6 +21,7 @@
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
#endif
+#include "base/file_path.h"
#include "base/platform_file.h"
#include "base/ref_counted.h"
#include "base/time.h"
@@ -32,8 +33,6 @@ namespace net {
class HttpResponseHeaders;
}
-class FilePath;
-
namespace webkit_glue {
class ResourceLoaderBridge {
@@ -84,6 +83,10 @@ class ResourceLoaderBridge {
// Used to associated the bridge with a frame's network context.
int routing_id;
+
+ // 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;
};
// Structure containing timing information for the request. It addresses
@@ -114,12 +117,12 @@ class ResourceLoaderBridge {
// The time that DNS lookup ended. For reused sockets this time is -1.
int32 dns_end;
- // The time that establishing connection started. For reused sockets
- // this time is -1. Connect time includes dns time.
+ // The time that establishing connection started. Connect time includes
+ // DNS, blocking, TCP, TCP retries and SSL time.
int32 connect_start;
- // The time that establishing connection ended. For reused sockets this
- // time is -1. Connect time includes dns time.
+ // The time that establishing connection ended. Connect time includes
+ // DNS, blocking, TCP, TCP retries and SSL time.
int32 connect_end;
// The time at which SSL handshake started. For non-HTTPS requests this
@@ -191,6 +194,11 @@ class ResourceLoaderBridge {
// Tools.
LoadTimingInfo load_timing;
+ // The path to a file that will contain the response body. It may only
+ // contain a portion of the response body at the time that the ResponseInfo
+ // becomes available.
+ FilePath download_file_path;
+
// True if the response was delivered using SPDY.
bool was_fetched_via_spdy;
@@ -258,6 +266,12 @@ class ResourceLoaderBridge {
virtual void OnReceivedResponse(const ResponseInfo& info,
bool content_filtered) = 0;
+ // Called when a chunk of response data is downloaded. This method may be
+ // called multiple times or not at all if an error occurs. This method is
+ // only called if RequestInfo::download_to_file was set to true, and in
+ // that case, OnReceivedData will not be called.
+ virtual void OnDownloadedData(int len) = 0;
+
// Called when a chunk of response data is available. This method may
// be called multiple times or not at all if an error occurs.
virtual void OnReceivedData(const char* data, int len) = 0;
@@ -269,7 +283,8 @@ class ResourceLoaderBridge {
// Called when the response is complete. This method signals completion of
// the resource load.ff
virtual void OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info) = 0;
+ const std::string& security_info,
+ const base::Time& completion_time) = 0;
// Returns the URL of the request, which allows us to display it in
// debugging situations.
@@ -304,6 +319,10 @@ class ResourceLoaderBridge {
uint64 length,
const base::Time& expected_modification_time) = 0;
+ // Call this method before calling Start() to append the contents of a blob
+ // to the request body. May only be used with HTTP(S) POST requests.
+ virtual void AppendBlobToUpload(const GURL& blob_url) = 0;
+
// Call this method before calling Start() to assign an upload identifier to
// this request. This is used to enable caching of POST responses. A value
// of 0 implies the unspecified identifier.
diff --git a/webkit/glue/resource_type.h b/webkit/glue/resource_type.h
index aa4a072..1de4fd2 100644
--- a/webkit/glue/resource_type.h
+++ b/webkit/glue/resource_type.h
@@ -22,6 +22,7 @@ class ResourceType {
MEDIA, // a media resource.
WORKER, // the main resource of a dedicated worker.
SHARED_WORKER, // the main resource of a shared worker.
+ PREFETCH, // an explicitly requested prefetch
LAST_TYPE // Place holder so we don't need to change ValidType
// everytime.
};
diff --git a/webkit/glue/resources/webkit_strings_am.xtb b/webkit/glue/resources/webkit_strings_am.xtb
index acba326..1a71058 100644
--- a/webkit/glue/resources/webkit_strings_am.xtb
+++ b/webkit/glue/resources/webkit_strings_am.xtb
@@ -1,43 +1,30 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="am">
-<translation id="4420062214988137980">የPlugin ጭáŠá‰µ ተሰናክáˆáˆ</translation>
<translation id="1235745349614807883">የቅርብ ጊዜ áለጋዎችን አስወáŒá‹µ</translation>
-<translation id="3825324228893189080">ተጨማሪ plugin ያስáˆáˆáŒ‹áˆ</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> plugin አáˆá‰°áŒ«áŠáˆ</translation>
<translation id="5048533449481078685">á‹áˆ­á‹áˆ­ አመáˆáŠ«á‰½</translation>
<translation id="4202807286478387388">á‹áˆˆáˆ</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">እባክዎ <ph name="PLUGIN"/> plugin ለመጫን መáˆáˆˆáŒá‹ŽáŠ• ያረጋáŒáŒ¡á¢ የሚያáˆáŠ—ቸá‹áŠ• plugins ብቻ መጫን ይኖርብዎታáˆá¢</translation>
<translation id="7658239707568436148">ሰርá‹</translation>
<translation id="795667975304826397">áˆáŠ•áˆ á‹á‹­áˆ አáˆá‰°áˆ˜áˆ¨áŒ áˆ</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> plugin ያስáˆáˆáŒ‹áˆ</translation>
-<translation id="8662565117025751661">የሚወርድ plugin…</translation>
<translation id="8141602879876242471">ይህ ሊáˆáˆˆáŒ የሚችሠመረጃ ጠቋሚ áŠá‹á¢ የáለጋ á‰áˆá ቃላት አስገባá¦</translation>
<translation id="6845533974506654842">ተጫን</translation>
<translation id="8244226242650769279">የáˆáˆµáˆ ካርታ</translation>
-<translation id="1383141426028388991">ከ<ph name="URL"/> plugin ለመጫን አáˆá‰°á‰»áˆˆáˆ</translation>
<translation id="2548326553472216322">የቅርብ ጊዜ áለጋዎች የሉáˆ</translation>
<translation id="5944544982112848342">2048(ከáተኛ ደረጃ)</translation>
<translation id="3040011195152428237">አገናáŠ</translation>
-<translation id="8281246460978372009">plugin ከተጫአበኋላᣠለማደስ እዚህ ይጫኑ</translation>
<translation id="7364796246159120393">á‹á‹­áˆ áˆáˆ¨áŒ¥</translation>
<translation id="8964020114565522021">á‹á‹­áˆ ወደዚህ ጎትት</translation>
<translation id="838869780401515933">አመáˆáŠ­á‰µ</translation>
<translation id="2846343701378493991">1024(መካከለኛ ደረጃ)</translation>
<translation id="5476505524087279545">አታመáˆáŠ­á‰µ</translation>
-<translation id="679352192834563463">ይህን ይዘት ለማሳየት áˆáŠ•áˆ plugin የለáˆ</translation>
<translation id="3789841737615482174">ጫን</translation>
<translation id="6663448176199120256">የቅርብ ጊዜ áለጋዎችን</translation>
-<translation id="3600343118165084788">plugin ለማá‹áˆ¨á‹µ እዚህ ይጫኑ</translation>
<translation id="6807599807928161586">የድር ክáˆáˆ</translation>
<translation id="5939518447894949180">ዳáŒáˆ አስጀáˆáˆ­</translation>
-<translation id="3771786644471114952">Plugin አáŒáŠ</translation>
<translation id="1842960171412779397">áˆáˆ¨áŒ¥</translation>
<translation id="6119846243427417423">አንቃ</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> á‹á‹­áˆŽá‰½</translation>
-<translation id="3926627843712816530">እባክዎ ይህን plugin ለመጫን መáˆáˆˆáŒá‹ŽáŠ• ያረጋáŒáŒ¡á¢ የሚያáˆáŠ—ቸá‹áŠ• plugins ብቻ መጫን ይኖርብዎታáˆá¢</translation>
-<translation id="4838490908464673667">የሚáˆáˆˆáŒˆá‹ plugin አáˆá‰°áŒ«áŠáˆ</translation>
<translation id="8597182159515967513">ርእስ</translation>
<translation id="2653659639078652383">አስገባ</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ar.xtb b/webkit/glue/resources/webkit_strings_ar.xtb
index a558190..6f454f7 100644
--- a/webkit/glue/resources/webkit_strings_ar.xtb
+++ b/webkit/glue/resources/webkit_strings_ar.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ar">
-<translation id="4420062214988137980">إخÙاق محاولة تثبيت المكوّن الإضاÙÙŠ</translation>
+<translation id="4519964825805946997">أخÙÙ‚ تثبيت المكون الإضاÙÙŠ من <ph name="URL"/></translation>
<translation id="1235745349614807883">محو آخر عمليات البحث</translation>
-<translation id="3825324228893189080">مطلوب مكوّن إضاÙيّ آخر.</translation>
-<translation id="2965480764085142436">المكوّن الإضاÙÙŠ <ph name="PLUGIN"/> غير متوÙّر</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="4317653869502688143">الرّجاء تأكيد طلب تثبيت المكوّن الإضاÙÙŠ <ph name="PLUGIN"/>. يجب تثبيت المكوّنات الإضاÙية الموثوق بها Ùقط.</translation>
<translation id="7658239707568436148">إلغاء</translation>
<translation id="795667975304826397">ّلم يتمّ اختيار أيّ ملÙÙ‘</translation>
-<translation id="1275511093094545429">يلزم المكوّن الإضاÙيّ <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">تحميل المكوّن الإضاÙÙŠ...</translation>
+<translation id="1416462845279468967">أخÙÙ‚ تثبيت المكون الإضاÙÙŠ</translation>
<translation id="8141602879876242471">يمكن البحث ÙÙŠ هذا الÙهرس بإدخال كلمات Ù…Ùتاحية:</translation>
+<translation id="5650795167354946011">بعد تثبيت المكون الإضاÙÙŠØŒ انقر هنا للتحديث</translation>
<translation id="6845533974506654842">اضغط</translation>
<translation id="8244226242650769279">مخطّط صورة</translation>
-<translation id="1383141426028388991">Ùشل تثبيت المكون الإضاÙÙŠ من <ph name="URL"/></translation>
<translation id="2548326553472216322">لا عمليات بحث حديثة</translation>
<translation id="5944544982112848342">2048 (درجة عالية)</translation>
<translation id="3040011195152428237">رابط</translation>
-<translation id="8281246460978372009">بعد تثبيت المكوّن الإضاÙÙŠØŒ انقر هنا لتحديث الناÙذة</translation>
+<translation id="2745343197843472802">الحصول على المكوّن الإضاÙÙŠ</translation>
+<translation id="5776402066334188252">الرجاء التأكيد على أنك تريد تثبيت المكوّن الإضاÙÙŠ هذا. يجب تثبيت المكونات الإضاÙية التي تثق Ùيها Ùقط.</translation>
+<translation id="4003986561708175844">لم يتم تثبيت المكون الإضاÙÙŠ المطلوب</translation>
+<translation id="3018094406922859308">جار٠تنزيل المكوّن الإضاÙÙŠ...</translation>
<translation id="7364796246159120393">اختيار ملÙÙ‘</translation>
<translation id="8964020114565522021">سحب الملÙÙ‘ إلى هنا</translation>
<translation id="838869780401515933">الاختيار</translation>
<translation id="2846343701378493991">1024 (درجة متوسطة)</translation>
<translation id="5476505524087279545">إزالة علامة الاختيار</translation>
-<translation id="679352192834563463">لا يتوÙر أي مكوّن إضاÙÙŠ لعرض هذا المحتوى</translation>
<translation id="3789841737615482174">تثبيت</translation>
+<translation id="5253117816378681419">الرجاء التأكيد على أنك تريد تثبيت المكوّن الإضاÙÙŠ <ph name="PLUGIN"/>. يجب تثبيت المكونات الإضاÙية التي تثق Ùيها Ùقط.</translation>
<translation id="6663448176199120256">آخر عمليات البحث</translation>
-<translation id="3600343118165084788">انقر هنا لتنزيل المكوّن الإضاÙÙŠ</translation>
+<translation id="2597378329261239068">هذا المستند محمي بكلمة المرور. الرجاء إدخال كلمة مرور.</translation>
<translation id="6807599807928161586">منطقة الويب</translation>
<translation id="5939518447894949180">إعادة</translation>
-<translation id="3771786644471114952">جلب المكوّن الإضاÙÙŠ</translation>
<translation id="1842960171412779397">الاختيار</translation>
+<translation id="7638452146404718955">انقر هنا لتنزيل المكون الإضاÙÙŠ</translation>
<translation id="6119846243427417423">تنشيط</translation>
<translation id="8444882422881193423">عدد الملÙات: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">يرجى تأكيد طلب تثبيت المكوّن الإضاÙÙŠ. يجب تثبيت المكوّنات الإضاÙية الموثوق بها Ùقط.</translation>
-<translation id="4838490908464673667">المكوّن الإضاÙيّ المطلوب غير متوÙّر</translation>
+<translation id="4470547978413275879">لم يتم تثبيت المكون الإضاÙÙŠ <ph name="PLUGIN"/></translation>
+<translation id="6765711848403622008">لا يتوÙر أي مكون إضاÙÙŠ لعرض هذا المحتوى</translation>
<translation id="8597182159515967513">العنوان</translation>
<translation id="2653659639078652383">إرسال</translation>
+<translation id="8475551193147984329">المكوّن الإضاÙÙŠ المطلوب <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_bg.xtb b/webkit/glue/resources/webkit_strings_bg.xtb
index 91d0b4b..4edbd69 100644
--- a/webkit/glue/resources/webkit_strings_bg.xtb
+++ b/webkit/glue/resources/webkit_strings_bg.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bg">
-<translation id="4420062214988137980">ИнÑталирането на приÑтавката не бе уÑпешно</translation>
+<translation id="4519964825805946997">ИнÑталирането на приÑтавката от <ph name="URL"/> не бе уÑпешно</translation>
<translation id="1235745349614807883">ИзчиÑтване на Ñкорошните Ñ‚ÑŠÑ€ÑениÑ</translation>
-<translation id="3825324228893189080">ИзиÑква Ñе допълнителна приÑтавка</translation>
-<translation id="2965480764085142436">ПриÑтавката за <ph name="PLUGIN"/> не е инÑталирана</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="4317653869502688143">МолÑ, потвърдете, че иÑкате да инÑталирате приÑтавката за <ph name="PLUGIN"/>. ИнÑталирайте Ñамо тези приÑтавки, които Ñчитате за надеждни.</translation>
<translation id="7658239707568436148">Отказ</translation>
<translation id="795667975304826397">ÐÑма избран файл</translation>
-<translation id="1275511093094545429">Ðеобходима е приÑтавка за <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">ПриÑтавката Ñе изтеглÑ...</translation>
+<translation id="1416462845279468967">ИнÑталирането на приÑтавката не бе уÑпешно</translation>
<translation id="8141602879876242471">Ð’ този Ð¸Ð½Ð´ÐµÐºÑ Ð¼Ð¾Ð¶Ðµ да Ñе Ñ‚ÑŠÑ€Ñи. Въведете ключови думи за Ñ‚ÑŠÑ€Ñене:</translation>
+<translation id="5650795167354946011">След инÑталирането на приÑтавката кликнете тук за опреÑнÑване</translation>
<translation id="6845533974506654842">натиÑкане</translation>
<translation id="8244226242650769279">карта Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ</translation>
-<translation id="1383141426028388991">ÐеуÑпешно инÑталиране на приÑтавката от <ph name="URL"/></translation>
<translation id="2548326553472216322">ÐÑма Ñкорошни Ñ‚ÑŠÑ€ÑениÑ</translation>
<translation id="5944544982112848342">2048 (виÑока Ñтепен на ÑложноÑÑ‚)</translation>
<translation id="3040011195152428237">връзка</translation>
-<translation id="8281246460978372009">След като инÑталирате приÑтавката, кликнете тук, за да опреÑните прозореца</translation>
+<translation id="2745343197843472802">Изтеглете приÑтавката</translation>
+<translation id="5776402066334188252">МолÑ, потвърдете, че иÑкате да инÑталирате тази приÑтавка. ТрÑбва да инÑталирате Ñамо приÑтавки, на които имате доверие.</translation>
+<translation id="4003986561708175844">Ðеобходимата приÑтавка не е инÑталирана</translation>
+<translation id="3018094406922859308">ПриÑтавката Ñе изтеглÑ...</translation>
<translation id="7364796246159120393">Избор на файл</translation>
<translation id="8964020114565522021">Плъзнете файла тук</translation>
<translation id="838869780401515933">отмÑтане</translation>
<translation id="2846343701378493991">1024 (Ñредна Ñтепен на ÑложноÑÑ‚)</translation>
<translation id="5476505524087279545">премахване на отметката</translation>
-<translation id="679352192834563463">ÐÑма приÑтавка, Ñ ÐºÐ¾Ñто може да Ñе покаже това Ñъдържание</translation>
<translation id="3789841737615482174">ИнÑталиране</translation>
+<translation id="5253117816378681419">МолÑ, потвърдете, че иÑкате да инÑталирате приÑтавката <ph name="PLUGIN"/>. ТрÑбва да инÑталирате Ñамо приÑтавки, на които имате доверие.</translation>
<translation id="6663448176199120256">Скорошни Ñ‚ÑŠÑ€ÑениÑ</translation>
-<translation id="3600343118165084788">Кликнете тук, за да изтеглите приÑтавката</translation>
+<translation id="2597378329261239068">Този документ е защитен Ñ Ð¿Ð°Ñ€Ð¾Ð»Ð°. МолÑ, въведете Ñ.</translation>
<translation id="6807599807928161586">уеб зона</translation>
<translation id="5939518447894949180">Повторно задаване</translation>
-<translation id="3771786644471114952">ИзтеглÑне на приÑтавката</translation>
<translation id="1842960171412779397">Избиране</translation>
+<translation id="7638452146404718955">Кликнете тук, за да изтеглите приÑтавката</translation>
<translation id="6119846243427417423">активиране</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> файла</translation>
-<translation id="3926627843712816530">МолÑ, потвърдете, че иÑкате да инÑталирате тази приÑтавка. ИнÑталирайте Ñамо тези приÑтавки, които Ñчитате за надеждни.</translation>
-<translation id="4838490908464673667">Ðеобходимата приÑтавка не е инÑталирана</translation>
+<translation id="4470547978413275879">Ðе е инÑталирана приÑтавката <ph name="PLUGIN"/></translation>
+<translation id="6765711848403622008">ÐÑма налична приÑтавка за показване на това Ñъдържание</translation>
<translation id="8597182159515967513">заглавие</translation>
<translation id="2653659639078652383">Изпращане</translation>
+<translation id="8475551193147984329">Ðеобходима е приÑтавката <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_bn.xtb b/webkit/glue/resources/webkit_strings_bn.xtb
index 098985f..1a29278 100644
--- a/webkit/glue/resources/webkit_strings_bn.xtb
+++ b/webkit/glue/resources/webkit_strings_bn.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="bn">
-<translation id="4420062214988137980">পà§à¦²à§à¦¯à¦¾à¦—ইন ইনসà§à¦Ÿà¦²à§‡à¦¶à¦¨ বà§à¦¯à¦°à§à¦¥</translation>
+<translation id="4519964825805946997"><ph name="URL"/>-à¦à¦° থেকে পà§à¦²à§à¦¯à¦¾à¦—-ইন ইনসà§à¦Ÿà¦² করতে বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
<translation id="1235745349614807883">সামà§à¦ªà§à¦°à¦¤à¦¿à¦• অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à¦—à§à¦²à¦¿ সাফ করà§à¦¨</translation>
-<translation id="3825324228893189080">অতিরিকà§à¦¤ পà§à¦²à§à¦¯à¦¾à¦—ইন পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿ</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> পà§à¦²à§à¦¯à¦¾à¦—ইন ইনসà§à¦Ÿà¦² হয় নি</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="4317653869502688143">দয়া করে নিশà§à¦šà¦¿à¦¤ করà§à¦¨, আপনি <ph name="PLUGIN"/> পà§à¦²à§à¦¯à¦¾à¦—ইন ইনসà§à¦Ÿà¦² করতে চান৷ আপনি বিশà§à¦¬à¦¾à¦¸ করেন কেবল à¦à¦®à¦¨ পà§à¦²à§à¦¯à¦¾à¦—ইনই ইনসà§à¦Ÿà¦² করা উচিত৷</translation>
<translation id="7658239707568436148">বাতিল</translation>
<translation id="795667975304826397">কোনও ফাইল চয়ন করা হয় নি</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> পà§à¦²à§à¦¯à¦¾à¦—ইন পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿ</translation>
-<translation id="8662565117025751661">পà§à¦²à§à¦¯à¦¾à¦—ইন ডাউনলোড হচà§à¦›à§‡...</translation>
+<translation id="1416462845279468967">পà§à¦²à¦¾à¦—-ইন ইনসà§à¦Ÿà¦²à§‡à¦¶à¦¾à¦¨ বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
<translation id="8141602879876242471">à¦à¦Ÿà¦¿ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à¦¯à§‹à¦—à§à¦¯ সূচি৷ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à§‡à¦° মূলশবà§à¦¦ পà§à¦°à¦¬à§‡à¦¶ করান:</translation>
+<translation id="5650795167354946011">পà§à¦²à§à¦¯à¦¾à¦—-ইন ইনসà§à¦Ÿà¦² করার পরে, রিফà§à¦°à§‡à¦¶ করার জনà§à¦¯ à¦à¦–ানে কà§à¦²à¦¿à¦• করà§à¦¨</translation>
<translation id="6845533974506654842">টিপà§à¦¨</translation>
<translation id="8244226242650769279">ছবি মানচিতà§à¦°</translation>
-<translation id="1383141426028388991"><ph name="URL"/> থেকে পà§à¦²à§à¦¯à¦¾à¦—ইন ইনসà§à¦Ÿà¦² করতে বà§à¦¯à¦°à§à¦¥ হয়েছে</translation>
<translation id="2548326553472216322">কোন সামà§à¦ªà§à¦°à¦¤à¦¿à¦• অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ নেই</translation>
<translation id="5944544982112848342">2048 (উচà§à¦š গà§à¦°à§‡à¦¡)</translation>
<translation id="3040011195152428237">লিঙà§à¦•</translation>
-<translation id="8281246460978372009">পà§à¦²à§à¦¯à¦¾à¦—ইন ইনসà§à¦Ÿà¦² করার পরে, রিফà§à¦°à§‡à¦¶ করার জনà§à¦¯ à¦à¦–ানে কà§à¦²à¦¿à¦• করà§à¦¨</translation>
+<translation id="2745343197843472802">পà§à¦²à¦¾à¦—-ইন পান</translation>
+<translation id="5776402066334188252">আপনি পà§à¦²à§à¦¯à¦¾à¦—-ইন ইনসà§à¦Ÿà¦² করতে চান কি না দয়া করে নিশà§à¦šà¦¿à¦¤ করà§à¦¨à§· আপনার কেবল সেই পà§à¦²à§à¦¯à¦¾à¦—-ইনগà§à¦²à¦¿ ইনসà§à¦Ÿà¦² করা উচিত যা আপনি বিশà§à¦¬à¦¾à¦¸ করেন৷</translation>
+<translation id="4003986561708175844">পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿ পà§à¦²à§à¦¯à¦¾à¦—-ইন ইনসà§à¦Ÿà¦² করা নেই</translation>
+<translation id="3018094406922859308">পà§à¦²à¦¾à¦—-ইন ডাউনলোড হচà§à¦›à§‡...</translation>
<translation id="7364796246159120393">ফাইল চয়ন করà§à¦¨</translation>
<translation id="8964020114565522021">ফাইল à¦à¦–ানে টেনে আনà§à¦¨</translation>
<translation id="838869780401515933">চেক করà§à¦¨</translation>
<translation id="2846343701378493991">1024 (মধà§à¦¯à¦® গà§à¦°à§‡à¦¡)</translation>
<translation id="5476505524087279545">আনচেক</translation>
-<translation id="679352192834563463">à¦à¦‡ সামগà§à¦°à§€ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করার জনà§à¦¯ কোনও পà§à¦²à§à¦¯à¦¾à¦—ইন উপলবà§à¦§ নেই</translation>
<translation id="3789841737615482174">ইনসà§à¦Ÿà¦² করà§à¦¨</translation>
+<translation id="5253117816378681419">আপনি <ph name="PLUGIN"/> পà§à¦²à§à¦¯à¦¾à¦—-ইনটি ইনসà§à¦Ÿà¦² করতে চান কি না দয়া করে নিশà§à¦šà¦¿à¦¤ করà§à¦¨à§· আপনার কেবল সেই পà§à¦²à§à¦¯à¦¾à¦—-ইনগà§à¦²à¦¿ ইনসà§à¦Ÿà¦² করার উচিত যেগà§à¦²à¦¿à¦•à§‡ আপনি বিশà§à¦¬à¦¾à¦¸ করেন৷</translation>
<translation id="6663448176199120256">সামà§à¦ªà§à¦°à¦¤à¦¿à¦• অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨à¦—à§à¦²à¦¿</translation>
-<translation id="3600343118165084788">পà§à¦²à§à¦¯à¦¾à¦— ডাউনলোড করার জনà§à¦¯ à¦à¦–ানে ডাউনলোড করà§à¦¨</translation>
+<translation id="2597378329261239068">à¦à¦‡ দসà§à¦¤à¦¾à¦¬à§‡à¦œà¦Ÿà¦¿ পাসওয়ারà§à¦¡ সà§à¦°à¦•à§à¦·à¦¿à¦¤à§· দয়া করে à¦à¦•à¦Ÿà¦¿ পাসওয়ারà§à¦¡ লিখà§à¦¨à§·</translation>
<translation id="6807599807928161586">ওয়েব à¦à¦²à¦¾à¦•à¦¾</translation>
<translation id="5939518447894949180">রিসেট করà§à¦¨</translation>
-<translation id="3771786644471114952">পà§à¦²à§à¦¯à¦¾à¦—ইন পà§à¦°à¦¾à¦ªà§à¦¤ করà§à¦¨</translation>
<translation id="1842960171412779397">নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨</translation>
+<translation id="7638452146404718955">পà§à¦²à§à¦¯à¦¾à¦—-ইন ডাউনলোড করার জনà§à¦¯ à¦à¦–ানে কà§à¦²à¦¿à¦• করà§à¦¨</translation>
<translation id="6119846243427417423">সকà§à¦°à¦¿à§Ÿ করà§à¦¨</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> টি ফাইল</translation>
-<translation id="3926627843712816530">আপনি পà§à¦²à§à¦¯à¦¾à¦—ইন ইনà§à¦¸à§à¦Ÿà¦² করতে চান তা দয়া করে নিশà§à¦šà¦¿à¦¤ করà§à¦¨à§· আপনি বিশà§à¦¬à¦¾à¦¸ করেন কেবল à¦à¦®à¦¨ পà§à¦²à§à¦¯à¦¾à¦—ইনই ইনসà§à¦Ÿà¦² করা উচিত৷</translation>
-<translation id="4838490908464673667">পà§à¦°à§Ÿà§‹à¦œà¦¨à§€à§Ÿ পà§à¦²à§à¦¯à¦¾à¦—ইন ইনসà§à¦Ÿà¦² করা নেই</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> পà§à¦²à¦¾à¦—-ইন ইনসà§à¦Ÿà¦² নেই</translation>
+<translation id="6765711848403622008">à¦à¦‡ সামগà§à¦°à§€ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করার জনà§à¦¯ কোনও পà§à¦²à§à¦¯à¦¾à¦—-ইন উপলবà§à¦§ নেই</translation>
<translation id="8597182159515967513">শিরোনামা</translation>
<translation id="2653659639078652383">জমা</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> পà§à¦²à¦¾à¦—-ইন পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ca.xtb b/webkit/glue/resources/webkit_strings_ca.xtb
index b5b1aa7..6f3dc90 100644
--- a/webkit/glue/resources/webkit_strings_ca.xtb
+++ b/webkit/glue/resources/webkit_strings_ca.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ca">
-<translation id="4420062214988137980">Error en la instal·lació del complement</translation>
+<translation id="4519964825805946997">S'ha produït un error en instal·lar el connector des de <ph name="URL"/></translation>
<translation id="1235745349614807883">Esborra les cerques recents</translation>
-<translation id="3825324228893189080">Es necessita un complement addicional</translation>
-<translation id="2965480764085142436">El complement <ph name="PLUGIN"/> no està instal·lat</translation>
<translation id="5048533449481078685">marcador de llistes</translation>
+<translation id="372362261556059955">Es necessita un connector addicional</translation>
<translation id="4202807286478387388">salta</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Confirma que vols instal·lar el complement <ph name="PLUGIN"/>. Només hauries d'instal·lar complements fiables.</translation>
<translation id="7658239707568436148">Cancel·la</translation>
<translation id="795667975304826397">No heu seleccionat cap fitxer.</translation>
-<translation id="1275511093094545429">Es necessita el complement <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">S'està baixant el complement...</translation>
+<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="6845533974506654842">prem</translation>
<translation id="8244226242650769279">mapa d'imatges</translation>
-<translation id="1383141426028388991">S'ha produït un error en instal·lar el connector des de <ph name="URL"/></translation>
<translation id="2548326553472216322">No hi ha cerques recents</translation>
<translation id="5944544982112848342">2048 (Gran)</translation>
<translation id="3040011195152428237">enllaç</translation>
-<translation id="8281246460978372009">Després d'instal·lar el complement, feu clic aquí per actualitzar.</translation>
+<translation id="2745343197843472802">Obtén el connector</translation>
+<translation id="5776402066334188252">Confirmeu que voleu instal·lar aquest connector. Us recomanem que només instal·leu connectors de la vostra confiança.</translation>
+<translation id="4003986561708175844">El connector necessari no està instal·lat</translation>
+<translation id="3018094406922859308">S'està baixant el connector...</translation>
<translation id="7364796246159120393">Selecciona el fitxer</translation>
<translation id="8964020114565522021">Arrossegueu el fitxer aquí.</translation>
<translation id="838869780401515933">marca</translation>
<translation id="2846343701378493991">1024 (Mitjà)</translation>
<translation id="5476505524087279545">desmarca</translation>
-<translation id="679352192834563463">No hi ha cap complement disponible per mostrar aquest contingut</translation>
<translation id="3789841737615482174">Instal·la</translation>
+<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="3600343118165084788">Feu clic aquí per baixar el complement</translation>
+<translation id="2597378329261239068">Aquest document està protegit mitjançant contrasenya. Introduïu una contrasenya.</translation>
<translation id="6807599807928161586">àrea web</translation>
<translation id="5939518447894949180">Restablir</translation>
-<translation id="3771786644471114952">Obtén el complement</translation>
<translation id="1842960171412779397">selecciona</translation>
+<translation id="7638452146404718955">Feu clic aquí per baixar el connector</translation>
<translation id="6119846243427417423">activa</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> fitxers</translation>
-<translation id="3926627843712816530">Confirma que vols instal·lar aquest complement. Només hauries d'instal·lar complements fiables.</translation>
-<translation id="4838490908464673667">El complement necessari no està instal·lat</translation>
+<translation id="4470547978413275879">El connector <ph name="PLUGIN"/> no està instal·lat</translation>
+<translation id="6765711848403622008">No hi ha cap connector disponible per mostrar aquest contingut</translation>
<translation id="8597182159515967513">Capçalera</translation>
<translation id="2653659639078652383">Envia</translation>
+<translation id="8475551193147984329">Es necessita el connector <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_cs.xtb b/webkit/glue/resources/webkit_strings_cs.xtb
index 33026e2..33a0d12 100644
--- a/webkit/glue/resources/webkit_strings_cs.xtb
+++ b/webkit/glue/resources/webkit_strings_cs.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="cs">
-<translation id="4420062214988137980">Nepodařilo se nainstalovat plugin</translation>
+<translation id="4519964825805946997">Instalace pluginu z adresy URL <ph name="URL"/> se nezdařila</translation>
<translation id="1235745349614807883">Smazat nedávná vyhledávání</translation>
-<translation id="3825324228893189080">Je potřeba další plugin</translation>
-<translation id="2965480764085142436">Není nainstalován plugin <ph name="PLUGIN"/></translation>
<translation id="5048533449481078685">znaÄka seznamu</translation>
+<translation id="372362261556059955">Je zapotřebí další plugin</translation>
<translation id="4202807286478387388">přejít</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">PotvrÄte prosím, že si pÅ™ejete instalovat plugin <ph name="PLUGIN"/>. MÄ›li byste instalovat pouze takové pluginy, kterým důvěřujete.</translation>
<translation id="7658239707568436148">Zrušit</translation>
<translation id="795667975304826397">Soubor nevybrán</translation>
-<translation id="1275511093094545429">Je potřeba plugin <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Stahování pluginu...</translation>
+<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="6845533974506654842">zmáÄknout</translation>
<translation id="8244226242650769279">obrázková mapa</translation>
-<translation id="1383141426028388991">Nepodařilo se nainstalovat plugin z adresy <ph name="URL"/></translation>
<translation id="2548326553472216322">Žádná nedávná vyhledávání</translation>
<translation id="5944544982112848342">2048 (vysoká kvalita)</translation>
<translation id="3040011195152428237">odkaz</translation>
-<translation id="8281246460978372009">Po instalaci pluginu klikněte sem pro obnovení</translation>
+<translation id="2745343197843472802">Získat plugin</translation>
+<translation id="5776402066334188252">PotvrÄte prosím, zda tento plugin chcete nainstalovat. Instalujte pouze pluginy, kterým důvěřujete.</translation>
+<translation id="4003986561708175844">Požadovaný plugin není nainstalován</translation>
+<translation id="3018094406922859308">Stahování pluginu...</translation>
<translation id="7364796246159120393">Vybrat soubor</translation>
<translation id="8964020114565522021">Přetáhnout soubor sem</translation>
<translation id="838869780401515933">zaškrtnout</translation>
<translation id="2846343701378493991">1024 (Střední kvalita)</translation>
<translation id="5476505524087279545">odstranit zaškrtnutí</translation>
-<translation id="679352192834563463">Není k dispozici žádný plugin pro zobrazení tohoto obsahu</translation>
<translation id="3789841737615482174">Instalovat</translation>
+<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="3600343118165084788">Pro stažení pluginu klikněte sem</translation>
+<translation id="2597378329261239068">Tento dokument je chráněn heslem. Zadejte prosím heslo.</translation>
<translation id="6807599807928161586">oblast webu</translation>
<translation id="5939518447894949180">Resetovat</translation>
-<translation id="3771786644471114952">Získat plugin</translation>
<translation id="1842960171412779397">zvolit</translation>
+<translation id="7638452146404718955">Plugin můžete stáhnout kliknutím sem</translation>
<translation id="6119846243427417423">aktivovat</translation>
<translation id="8444882422881193423">PoÄet souborů: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">PotvrÄte, prosím, že si pÅ™ejete instalovat tento plugin. MÄ›li byste instalovat pouze takové pluginy, kterým důvěřujete.</translation>
-<translation id="4838490908464673667">Požadovaný plugin není nainstalován</translation>
+<translation id="4470547978413275879">Není nainstalován plugin <ph name="PLUGIN"/></translation>
+<translation id="6765711848403622008">Není k dispozici žádný plugin k zobrazení tohoto obsahu</translation>
<translation id="8597182159515967513">záhlaví</translation>
<translation id="2653659639078652383">Odeslat</translation>
+<translation id="8475551193147984329">Je požadován plugin <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_da.xtb b/webkit/glue/resources/webkit_strings_da.xtb
index a923897..78f06ff 100644
--- a/webkit/glue/resources/webkit_strings_da.xtb
+++ b/webkit/glue/resources/webkit_strings_da.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="da">
-<translation id="4420062214988137980">Installation af plugin mislykkedes</translation>
+<translation id="4519964825805946997">Installation af plugin fra <ph name="URL"/> mislykkedes</translation>
<translation id="1235745349614807883">Slet nylige søgninger</translation>
-<translation id="3825324228893189080">Ekstra plugin påkrævet</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> plugin er ikke installeret</translation>
<translation id="5048533449481078685">listemarkering</translation>
+<translation id="372362261556059955">Ekstra plugin påkrævet</translation>
<translation id="4202807286478387388">hop</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Bekræft venligst, at du ønsker at installere plugin'et <ph name="PLUGIN"/>. Du bør udelukkende installere plugins, som du stoler på.</translation>
<translation id="7658239707568436148">Annuller</translation>
<translation id="795667975304826397">Der er ikke valgt nogen fil</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> Plugin påkrævet</translation>
-<translation id="8662565117025751661">Downloader plugin ...</translation>
+<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="6845533974506654842">tryk</translation>
<translation id="8244226242650769279">billedekort</translation>
-<translation id="1383141426028388991">Mislykket installation af plugin fra <ph name="URL"/></translation>
<translation id="2548326553472216322">Ingen nylige søgninger</translation>
<translation id="5944544982112848342">2048 (Høj klasse)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">NÃ¥r du har installeret plugin'et, skal du klikke her for at opdatere</translation>
+<translation id="2745343197843472802">Hent plugin</translation>
+<translation id="5776402066334188252">Bekræft, at du gerne vil installere dette plugin. Du skal kun installere plugins, som du har tillid til.</translation>
+<translation id="4003986561708175844">Det krævede plugin er ikke installeret</translation>
+<translation id="3018094406922859308">Downloader plugin...</translation>
<translation id="7364796246159120393">Vælg fil</translation>
<translation id="8964020114565522021">Træk filer hertil</translation>
<translation id="838869780401515933">marker</translation>
<translation id="2846343701378493991">1024 (Mellemklasse)</translation>
<translation id="5476505524087279545">fjern markering</translation>
-<translation id="679352192834563463">Intet tilgængeligt plugin kan vise dette indhold</translation>
<translation id="3789841737615482174">Installer</translation>
+<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="3600343118165084788">Klik her for at downloade plugin</translation>
+<translation id="2597378329261239068">Dette dokument er adgangskodebeskyttet. Indtast en adgangskode.</translation>
<translation id="6807599807928161586">webområde</translation>
<translation id="5939518447894949180">Nulstil</translation>
-<translation id="3771786644471114952">Hent plugin</translation>
<translation id="1842960171412779397">vælg</translation>
+<translation id="7638452146404718955">Klik her for at downloade plugin</translation>
<translation id="6119846243427417423">aktiver</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> filer</translation>
-<translation id="3926627843712816530">Bekræft venligst, at du gerne vil installere dette plugin. Du bør udelukkende installere plugins, som du stoler på.</translation>
-<translation id="4838490908464673667">Det krævede plugin er ikke installeret</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/>-plugin er ikke installeret</translation>
+<translation id="6765711848403622008">Intet tilgængeligt plugin kan vise dette indhold</translation>
<translation id="8597182159515967513">overskrift</translation>
<translation id="2653659639078652383">Indsend</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/>-plugin er påkrævet</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_de.xtb b/webkit/glue/resources/webkit_strings_de.xtb
index 76411ed..45fab1b 100644
--- a/webkit/glue/resources/webkit_strings_de.xtb
+++ b/webkit/glue/resources/webkit_strings_de.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="de">
-<translation id="4420062214988137980">Plug-in-Installation fehlgeschlagen</translation>
+<translation id="4519964825805946997">Installation des Plug-ins von <ph name="URL"/> fehlgeschlagen</translation>
<translation id="1235745349614807883">Vor kurzem durchgeführte Suchanfragen löschen</translation>
-<translation id="3825324228893189080">Zusätzliches Plug-in erforderlich</translation>
-<translation id="2965480764085142436">Plug-in <ph name="PLUGIN"/> nicht installiert</translation>
<translation id="5048533449481078685">Listenmarkierung</translation>
+<translation id="372362261556059955">Zusätzliches Plug-in erforderlich</translation>
<translation id="4202807286478387388">springen</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Bestätigen Sie, dass Sie das Plug-in <ph name="PLUGIN"/> installieren möchten. Sie sollten nur vertrauenswürdige Plug-ins installieren.</translation>
<translation id="7658239707568436148">Abbrechen</translation>
<translation id="795667975304826397">Keine Datei ausgewählt</translation>
-<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> erforderlich</translation>
-<translation id="8662565117025751661">Plug-in wird heruntergeladen...</translation>
+<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="6845533974506654842">klicken</translation>
<translation id="8244226242650769279">Imagemap</translation>
-<translation id="1383141426028388991">Installation des Plug-ins von <ph name="URL"/> fehlgeschlagen</translation>
<translation id="2548326553472216322">Keine vor kurzem durchgeführte Suchanfragen</translation>
<translation id="5944544982112848342">2048 (High Grade)</translation>
<translation id="3040011195152428237">Link</translation>
-<translation id="8281246460978372009">Klicken Sie nach der Installation des Plug-ins hier, um eine Aktualisierung durchzuführen.</translation>
+<translation id="2745343197843472802">Plug-in abrufen</translation>
+<translation id="5776402066334188252">Bitte bestätigen Sie, dass Sie dieses Plug-in installieren möchten. Installieren Sie nur Plug-ins, denen Sie vertrauen.</translation>
+<translation id="4003986561708175844">Das erforderliche Plug-in ist nicht installiert.</translation>
+<translation id="3018094406922859308">Plug-in wird heruntergeladen...</translation>
<translation id="7364796246159120393">Datei auswählen</translation>
<translation id="8964020114565522021">Datei hier ablegen</translation>
<translation id="838869780401515933">auswählen</translation>
<translation id="2846343701378493991">1024 (mittlere Stufe)</translation>
<translation id="5476505524087279545">Auswahl aufheben</translation>
-<translation id="679352192834563463">Kein Plug-in zum Anzeigen dieses Contents verfügbar</translation>
<translation id="3789841737615482174">Installieren</translation>
+<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="3600343118165084788">Klicken Sie hier, um das Plug-in herunterzuladen.</translation>
+<translation id="2597378329261239068">Dieses Dokument ist passwortgeschützt. Geben Sie ein Passwort ein.</translation>
<translation id="6807599807928161586">Webbereich</translation>
<translation id="5939518447894949180">Zurücksetzen</translation>
-<translation id="3771786644471114952">Plug-in abrufen</translation>
<translation id="1842960171412779397">auswählen</translation>
+<translation id="7638452146404718955">Hier klicken, um das Plug-in herunterzuladen</translation>
<translation id="6119846243427417423">aktivieren</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> Dateien</translation>
-<translation id="3926627843712816530">Bestätigen Sie, dass Sie dieses Plug-in installieren möchten. Sie sollten nur vertrauenswürdige Plug-ins installieren.</translation>
-<translation id="4838490908464673667">Das erforderliche Plug-in ist nicht installiert</translation>
+<translation id="4470547978413275879">Plug-in <ph name="PLUGIN"/> nicht installiert</translation>
+<translation id="6765711848403622008">Kein Plug-in zum Anzeigen dieses Contents verfügbar</translation>
<translation id="8597182159515967513">Kopfzeile</translation>
<translation id="2653659639078652383">Senden</translation>
+<translation id="8475551193147984329">Plug-in <ph name="PLUGIN"/> ist erforderlich</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_el.xtb b/webkit/glue/resources/webkit_strings_el.xtb
index dd75011..509307e 100644
--- a/webkit/glue/resources/webkit_strings_el.xtb
+++ b/webkit/glue/resources/webkit_strings_el.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="el">
-<translation id="4420062214988137980">Η εγκατάσταση της Ï€Ïοσθήκης απέτυχε</translation>
+<translation id="4519964825805946997">Η εγκατάσταση της Ï€Ïοσθήκης από τη διεÏθυνση <ph name="URL"/> απέτυχε</translation>
<translation id="1235745349614807883">ΕκκαθάÏιση Ï€Ïόσφατων αναζητήσεων</translation>
-<translation id="3825324228893189080">Απαιτείται επιπλέον Ï€Ïοσθήκη</translation>
-<translation id="2965480764085142436">Η Ï€Ïοσθήκη <ph name="PLUGIN"/> δεν έχει εγκατασταθεί</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="4317653869502688143">Επιβεβαιώστε ότι θέλετε να εγκαταστήσετε την Ï€Ïοσθήκη <ph name="PLUGIN"/>. ΠÏέπει να εγκαθιστάτε μόνο Ï€Ïοσθήκες που θεωÏείτε αξιόπιστες.</translation>
<translation id="7658239707568436148">ΑκÏÏωση</translation>
<translation id="795667975304826397">Δεν έχει επιλεγεί κανένα αÏχείο</translation>
-<translation id="1275511093094545429">ΧÏειάζεται η Ï€Ïοσθήκη <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Λήψη Ï€Ïοσθήκης...</translation>
+<translation id="1416462845279468967">Η εγκατάσταση Ï€Ïοσθήκης απέτυχε</translation>
<translation id="8141602879876242471">ΠÏόκειται για ευÏετήÏιο με δυνατότητα αναζήτησης. ΠληκτÏολογήστε λέξεις-κλειδιά αναζήτησης:</translation>
+<translation id="5650795167354946011">Μετά την εγκατάσταση της Ï€Ïοσθήκης, κάντε κλικ εδώ για ανανέωση των δεδομένων</translation>
<translation id="6845533974506654842">πατήστε</translation>
<translation id="8244226242650769279">χάÏτης εικόνας</translation>
-<translation id="1383141426028388991">Η εγκατάσταση της Ï€Ïοσθήκης από τη διεÏθυνση <ph name="URL"/> απέτυχε</translation>
<translation id="2548326553472216322">Δεν υπάÏχουν Ï€Ïόσφατες αναζητήσεις</translation>
<translation id="5944544982112848342">2048 (Υψηλός βαθμός)</translation>
<translation id="3040011195152428237">σÏνδεσμος</translation>
-<translation id="8281246460978372009">Μετά την εγκατάσταση της Ï€Ïοσθήκης, κάντε κλικ εδώ για ανανέωση</translation>
+<translation id="2745343197843472802">Λήψη Ï€Ïοσθήκης</translation>
+<translation id="5776402066334188252">Επιβεβαιώστε ότι θέλετε να εγκαταστήσετε αυτή την Ï€Ïοσθήκη. ΠÏέπει να εγκαθιστάτε μόνο Ï€Ïοσθήκες που θεωÏείτε αξιόπιστες.</translation>
+<translation id="4003986561708175844">Η απαιτοÏμενη Ï€Ïοσθήκη δεν έχει εγκατασταθεί</translation>
+<translation id="3018094406922859308">Λήψη Ï€Ïοσθήκης...</translation>
<translation id="7364796246159120393">Επιλογή αÏχείου</translation>
<translation id="8964020114565522021">ΣÏÏετε το αÏχείο εδώ</translation>
<translation id="838869780401515933">ενεÏγοποίηση</translation>
<translation id="2846343701378493991">1024 (ΜέτÏιος βαθμός)</translation>
<translation id="5476505524087279545">απενεÏγοποίηση</translation>
-<translation id="679352192834563463">Δεν υπάÏχει διαθέσιμη Ï€Ïοσθήκη για την εμφάνιση του πεÏιεχομένου</translation>
<translation id="3789841737615482174">Εγκατάσταση</translation>
+<translation id="5253117816378681419">Επιβεβαιώστε ότι θέλετε να εγκαταστήσετε την Ï€Ïοσθήκη <ph name="PLUGIN"/>. ΠÏέπει να εγκαθιστάτε μόνο Ï€Ïοσθήκες που θεωÏείτε αξιόπιστες.</translation>
<translation id="6663448176199120256">ΠÏόσφατες αναζητήσεις</translation>
-<translation id="3600343118165084788">Κάντε κλικ εδώ για να κατεβάσετε την Ï€Ïοσθήκη</translation>
+<translation id="2597378329261239068">Αυτό το έγγÏαφο Ï€ÏοστατεÏεται με κωδικό Ï€Ïόσβασης. ΠληκτÏολογήστε έναν κωδικό Ï€Ïόσβασης.</translation>
<translation id="6807599807928161586">πεÏιοχή ιστοÏ</translation>
<translation id="5939518447894949180">ΕπαναφοÏά</translation>
-<translation id="3771786644471114952">Λήψη Ï€Ïοσθήκης</translation>
<translation id="1842960171412779397">επιλογή</translation>
+<translation id="7638452146404718955">Κάντε κλικ εδώ για να κάνετε λήψη της Ï€Ïοσθήκης</translation>
<translation id="6119846243427417423">ενεÏγοποίηση</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> αÏχεία</translation>
-<translation id="3926627843712816530">Επιβεβαιώστε ότι θέλετε να εγκαταστήσετε αυτή την Ï€Ïοσθήκη. ΠÏέπει να εγκαθιστάτε μόνο Ï€Ïοσθήκες που θεωÏείτε αξιόπιστες.</translation>
-<translation id="4838490908464673667">Η απαιτοÏμενη Ï€Ïοσθήκη δεν έχει εγκατασταθεί</translation>
+<translation id="4470547978413275879">Η Ï€Ïοσθήκη <ph name="PLUGIN"/> δεν έχει εγκατασταθεί</translation>
+<translation id="6765711848403622008">Δεν υπάÏχει διαθέσιμη Ï€Ïοσθήκη για την εμφάνιση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… πεÏιεχομένου</translation>
<translation id="8597182159515967513">επικεφαλίδα</translation>
<translation id="2653659639078652383">Υποβολή</translation>
+<translation id="8475551193147984329">Απαιτείται η Ï€Ïοσθήκη <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_en-GB.xtb b/webkit/glue/resources/webkit_strings_en-GB.xtb
index ed7a1b6..14befa8 100644
--- a/webkit/glue/resources/webkit_strings_en-GB.xtb
+++ b/webkit/glue/resources/webkit_strings_en-GB.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="en-GB">
-<translation id="4420062214988137980">Plug-in installation failed</translation>
+<translation id="4519964825805946997">Failed to install plug-in from <ph name="URL"/></translation>
<translation id="1235745349614807883">Clear Recent Searches</translation>
-<translation id="3825324228893189080">Additional plug-in needed</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> plug-in is not installed</translation>
<translation id="5048533449481078685">list marker</translation>
+<translation id="372362261556059955">Additional plug-in needed</translation>
<translation id="4202807286478387388">jump</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">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="7658239707568436148">Cancel</translation>
<translation id="795667975304826397">No file chosen</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> plug-in needed</translation>
-<translation id="8662565117025751661">Downloading plug-in...</translation>
+<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="6845533974506654842">press</translation>
<translation id="8244226242650769279">image map</translation>
-<translation id="1383141426028388991">Failed to install plug-in from <ph name="URL"/></translation>
<translation id="2548326553472216322">No recent searches</translation>
<translation id="5944544982112848342">2048 (High Grade)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">After installing the plug-in, click here to refresh</translation>
+<translation id="2745343197843472802">Get Plug-in</translation>
+<translation id="5776402066334188252">Please confirm that you would like to install this plug-in. You should only install plug-ins that you trust.</translation>
+<translation id="4003986561708175844">The plug-in required is not installed</translation>
+<translation id="3018094406922859308">Downloading plug-in...</translation>
<translation id="7364796246159120393">Choose File</translation>
<translation id="8964020114565522021">Drag file here</translation>
<translation id="838869780401515933">tick</translation>
<translation id="2846343701378493991">1024 (Medium Grade)</translation>
<translation id="5476505524087279545">untick</translation>
-<translation id="679352192834563463">No plug-in available to display this content</translation>
<translation id="3789841737615482174">Install</translation>
+<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="3600343118165084788">Click here to download plug-in</translation>
+<translation id="2597378329261239068">This document is password-protected. Please enter a password.</translation>
<translation id="6807599807928161586">web area</translation>
<translation id="5939518447894949180">Reset</translation>
-<translation id="3771786644471114952">Get Plug-in</translation>
<translation id="1842960171412779397">select</translation>
+<translation id="7638452146404718955">Click here to download plug-in</translation>
<translation id="6119846243427417423">activate</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> files</translation>
-<translation id="3926627843712816530">Please confirm that you would like to install this plug-in. You should only install plug-ins that you trust.</translation>
-<translation id="4838490908464673667">The required plug-in is not installed</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> plug-in is not installed</translation>
+<translation id="6765711848403622008">No plug-in available to display this content</translation>
<translation id="8597182159515967513">heading</translation>
<translation id="2653659639078652383">Submit</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> plug-in needed</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_es-419.xtb b/webkit/glue/resources/webkit_strings_es-419.xtb
index d7e05f4..12bc57b 100644
--- a/webkit/glue/resources/webkit_strings_es-419.xtb
+++ b/webkit/glue/resources/webkit_strings_es-419.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es-419">
-<translation id="4420062214988137980">Error en la instalación del plug-in</translation>
+<translation id="4519964825805946997">Error al instalar el complemento desde <ph name="URL"/></translation>
<translation id="1235745349614807883">Eliminar búsquedas recientes</translation>
-<translation id="3825324228893189080">Se necesita un plug-in adicional</translation>
-<translation id="2965480764085142436">El plug-in <ph name="PLUGIN"/> no está instalado</translation>
<translation id="5048533449481078685">marcador de listas</translation>
+<translation id="372362261556059955">Se necesita un complemento adicional</translation>
<translation id="4202807286478387388">saltar</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Confirma que deseas instalar el plug-in <ph name="PLUGIN"/>. Solo debes instalar plug-in fiables.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="795667975304826397">No se eligió ningún archivo</translation>
-<translation id="1275511093094545429">Se requiere el plug-in <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Descargando plug-in...</translation>
+<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="6845533974506654842">hacer clic</translation>
<translation id="8244226242650769279">mapa de imágenes</translation>
-<translation id="1383141426028388991">Error al instalar el complemento desde <ph name="URL"/></translation>
<translation id="2548326553472216322">No hay búsquedas recientes</translation>
<translation id="5944544982112848342">2048 (Grado elevado)</translation>
<translation id="3040011195152428237">enlace</translation>
-<translation id="8281246460978372009">Tras instalar el complemento, haz clic aquí para actualizar.</translation>
+<translation id="2745343197843472802">Obtener complemento</translation>
+<translation id="5776402066334188252">Confirma que deseas instalar este complemento. Sólo deberías instalar los complementos confiables.</translation>
+<translation id="4003986561708175844">El complemento requerido no está instalado</translation>
+<translation id="3018094406922859308">Descargando complemento...</translation>
<translation id="7364796246159120393">Seleccionar archivo</translation>
<translation id="8964020114565522021">Arrastre el archivo hasta aquí</translation>
<translation id="838869780401515933">marcar</translation>
<translation id="2846343701378493991">1024 (Mediano)</translation>
<translation id="5476505524087279545">desmarcar</translation>
-<translation id="679352192834563463">No hay ningún plug-in disponible para mostrar este contenido</translation>
<translation id="3789841737615482174">Instalar</translation>
+<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="3600343118165084788">Haz clic aquí para descargar el plug-in.</translation>
+<translation id="2597378329261239068">Este documento está protegido por contraseña. Ingresa una contraseña.</translation>
<translation id="6807599807928161586">área web</translation>
<translation id="5939518447894949180">Restablecer</translation>
-<translation id="3771786644471114952">Obtener plug-in</translation>
<translation id="1842960171412779397">seleccionar</translation>
+<translation id="7638452146404718955">Haz clic aquí para descargar el complemento</translation>
<translation id="6119846243427417423">activar</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> archivos</translation>
-<translation id="3926627843712816530">Confirma que deseas instalar este plug-in. Solo debes instalar plug-in fiables.</translation>
-<translation id="4838490908464673667">El plug-in necesario no está instalado.</translation>
+<translation id="4470547978413275879">El complemento <ph name="PLUGIN"/> no está instalado</translation>
+<translation id="6765711848403622008">No se encuentra disponible ningún complemento para mostrar este contenido</translation>
<translation id="8597182159515967513">cabecera</translation>
<translation id="2653659639078652383">Enviar</translation>
+<translation id="8475551193147984329">Se necesita el complemento <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_es.xtb b/webkit/glue/resources/webkit_strings_es.xtb
index c95525d..5f9a245 100644
--- a/webkit/glue/resources/webkit_strings_es.xtb
+++ b/webkit/glue/resources/webkit_strings_es.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="es">
-<translation id="4420062214988137980">Error en la instalación del plug-in</translation>
+<translation id="4519964825805946997">Se ha producido un error al descargar el complemento de la página <ph name="URL"/>.</translation>
<translation id="1235745349614807883">Eliminar búsquedas recientes</translation>
-<translation id="3825324228893189080">Se necesita un plug-in adicional</translation>
-<translation id="2965480764085142436">El plug-in <ph name="PLUGIN"/> no está instalado</translation>
<translation id="5048533449481078685">marcador de listas</translation>
+<translation id="372362261556059955">Se necesita un complemento adicional</translation>
<translation id="4202807286478387388">saltar</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Confirma que deseas instalar el plug-in <ph name="PLUGIN"/>. Solo debes instalar plug-in fiables.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="795667975304826397">No se ha seleccionado ningun archivo</translation>
-<translation id="1275511093094545429">Se requiere el plug-in <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Descargando plug-in...</translation>
+<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="6845533974506654842">pulsar</translation>
<translation id="8244226242650769279">mapa de imágenes</translation>
-<translation id="1383141426028388991">Error al instalar el plugin desde <ph name="URL"/></translation>
<translation id="2548326553472216322">No hay búsquedas recientes</translation>
<translation id="5944544982112848342">2048 (Grado elevado)</translation>
<translation id="3040011195152428237">enlace</translation>
-<translation id="8281246460978372009">Tras instalar el complemento, haz clic aquí para actualizar.</translation>
+<translation id="2745343197843472802">Obtener complemento</translation>
+<translation id="5776402066334188252">Confirma que quieres instalar este complemento. Solo debes instalar complementos en los que confíes.</translation>
+<translation id="4003986561708175844">No está instalado el complemento necesario.</translation>
+<translation id="3018094406922859308">Cargando complemento...</translation>
<translation id="7364796246159120393">Seleccionar archivo</translation>
<translation id="8964020114565522021">Arrastrar archivo hasta aquí</translation>
<translation id="838869780401515933">marcar</translation>
<translation id="2846343701378493991">1024 (Mediano)</translation>
<translation id="5476505524087279545">desmarcar</translation>
-<translation id="679352192834563463">No hay ningún plug-in disponible para mostrar este contenido</translation>
<translation id="3789841737615482174">Instalar</translation>
+<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="3600343118165084788">Haz clic aquí para descargar el plug-in.</translation>
+<translation id="2597378329261239068">Este documento está protegido por contraseña. Introduce una contraseña.</translation>
<translation id="6807599807928161586">área web</translation>
<translation id="5939518447894949180">Restablecer</translation>
-<translation id="3771786644471114952">Obtener plug-in</translation>
<translation id="1842960171412779397">seleccionar</translation>
+<translation id="7638452146404718955">Haz clic aquí para descargar el complemento.</translation>
<translation id="6119846243427417423">activar</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> archivos</translation>
-<translation id="3926627843712816530">Confirma que deseas instalar este plug-in. Solo debes instalar plug-in fiables.</translation>
-<translation id="4838490908464673667">El plug-in necesario no está instalado.</translation>
+<translation id="4470547978413275879">El complemento <ph name="PLUGIN"/> no está instalado.</translation>
+<translation id="6765711848403622008">No hay ningún complemento disponible para mostrar este contenido.</translation>
<translation id="8597182159515967513">cabecera</translation>
<translation id="2653659639078652383">Enviar</translation>
+<translation id="8475551193147984329">Es necesario el complemento <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_et.xtb b/webkit/glue/resources/webkit_strings_et.xtb
index c449c06..2ac3c7a 100644
--- a/webkit/glue/resources/webkit_strings_et.xtb
+++ b/webkit/glue/resources/webkit_strings_et.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="et">
-<translation id="4420062214988137980">Lisandmooduli install ebaõnnestus</translation>
+<translation id="4519964825805946997">Pistikprogrammi installimine asukohast <ph name="URL"/> ebaõnnestus.</translation>
<translation id="1235745349614807883">Kustuta viimased otsingud</translation>
-<translation id="3825324228893189080">Vajalik täiendav lisandmoodul</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> lisandmoodul ei ole installitud</translation>
<translation id="5048533449481078685">loendilooja</translation>
+<translation id="372362261556059955">Vaja on täiendavat pistikprogrammi</translation>
<translation id="4202807286478387388">liigu</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Palun kinnitage, et soovite installida selle lisandmooduli <ph name="PLUGIN"/>. Te peaksite installima lisandmooduleid, mida usaldate.</translation>
<translation id="7658239707568436148">Loobu</translation>
<translation id="795667975304826397">Ãœhtegi faili pole valitud</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> vajalik lisandmoodul</translation>
-<translation id="8662565117025751661">Lisandmooduli allalaadimine...</translation>
+<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="6845533974506654842">vajuta</translation>
<translation id="8244226242650769279">hüperpilt</translation>
-<translation id="1383141426028388991">Lisandmooduli installimine aadressilt <ph name="URL"/> ebaõnnestus.</translation>
<translation id="2548326553472216322">Pole viimaseid otsingud</translation>
<translation id="5944544982112848342">2048 (kõrge)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">Pärast lisandmooduli installimist klõpsake värskendamiseks siia</translation>
+<translation id="2745343197843472802">Hangi pistikprogramm</translation>
+<translation id="5776402066334188252">Palun kinnitage, et soovite pistikprogrammi installida. Peaksite installima vaid usaldusväärseid pistikprogramme.</translation>
+<translation id="4003986561708175844">Nõutav pistikprogramm ei ole installitud</translation>
+<translation id="3018094406922859308">Pistikprogrammi allalaadimine...</translation>
<translation id="7364796246159120393">Vali fail</translation>
<translation id="8964020114565522021">Lohistage fail siia</translation>
<translation id="838869780401515933">mrgista</translation>
<translation id="2846343701378493991">1024 (keskmine)</translation>
<translation id="5476505524087279545">eemalda mrgistus</translation>
-<translation id="679352192834563463">Selle sisu kuvamiseks pole saadaval lisandmoodulit</translation>
<translation id="3789841737615482174">Installi</translation>
+<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="3600343118165084788">Lisandmooduli allalaadimiseks klõpsake siia.</translation>
+<translation id="2597378329261239068">Dokument on parooliga kaitstud. Sisestage parool.</translation>
<translation id="6807599807928161586">veebiala</translation>
<translation id="5939518447894949180">Lähtesta</translation>
-<translation id="3771786644471114952">Hangi lisandmoodul</translation>
<translation id="1842960171412779397">vali</translation>
+<translation id="7638452146404718955">Pistikprogrammi allalaadimiseks klõpsake siin</translation>
<translation id="6119846243427417423">aktiveeri</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> faili</translation>
-<translation id="3926627843712816530">Palun kinnitage, et soovite installida selle lisandmooduli. Te peaksite installima lisandmooduleid, mida usaldate.</translation>
-<translation id="4838490908464673667">Nõutav lisandmoodul pole installitud</translation>
+<translation id="4470547978413275879">Pistikprogramm <ph name="PLUGIN"/> ei ole installitud</translation>
+<translation id="6765711848403622008">Sisu kuvamiseks ei ole saadaval pistikprogrammi</translation>
<translation id="8597182159515967513">pealkiri</translation>
<translation id="2653659639078652383">Esita</translation>
+<translation id="8475551193147984329">Vajalik on pistikprogramm <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_fi.xtb b/webkit/glue/resources/webkit_strings_fi.xtb
index 50f3a69..4a1b6a3 100644
--- a/webkit/glue/resources/webkit_strings_fi.xtb
+++ b/webkit/glue/resources/webkit_strings_fi.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fi">
-<translation id="4420062214988137980">Laajennuksen asennus epäonnistui</translation>
+<translation id="4519964825805946997">Laajennuksen asennus osoitteesta <ph name="URL"/> epäonnistui</translation>
<translation id="1235745349614807883">Poista viimeisimmät haut</translation>
-<translation id="3825324228893189080">Lisälaajennus tarvitaan</translation>
-<translation id="2965480764085142436">Laajennusta <ph name="PLUGIN"/> ei asennettu</translation>
<translation id="5048533449481078685">luettelon merkitsijä</translation>
+<translation id="372362261556059955">Toinen laajennus vaaditaan</translation>
<translation id="4202807286478387388">siirry</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Vahvista, että haluat asentaa laajennuksen <ph name="PLUGIN"/>. Kannattaa asentaa vain luotettavia laajennuksia.</translation>
<translation id="7658239707568436148">Peruuta</translation>
<translation id="795667975304826397">Ei valittua tiedostoa</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> laajennus tarvitaan</translation>
-<translation id="8662565117025751661">Ladataan laajennusta...</translation>
+<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="6845533974506654842">paina</translation>
<translation id="8244226242650769279">kuvakartta</translation>
-<translation id="1383141426028388991">Laajennuksen asennus osoitteesta <ph name="URL"/> epäonnistui</translation>
<translation id="2548326553472216322">Ei viimeisimpiä hakuja</translation>
<translation id="5944544982112848342">2048 (korkea taso)</translation>
<translation id="3040011195152428237">linkki</translation>
-<translation id="8281246460978372009">Päivitä laajennuksen asennuksen jälkeen napsauttamalla tästä</translation>
+<translation id="2745343197843472802">Hanki laajennus</translation>
+<translation id="5776402066334188252">Vahvista, että haluat asentaa tämän laajennuksen. Suosittelemme asentamaan vain laajennuksia, joihin luotat.</translation>
+<translation id="4003986561708175844">Vaadittua laajennusta ei ole asennettu</translation>
+<translation id="3018094406922859308">Laajennusta ladataan...</translation>
<translation id="7364796246159120393">Valitse tiedosto</translation>
<translation id="8964020114565522021">Vedä tiedosto tähän</translation>
<translation id="838869780401515933">valitse</translation>
<translation id="2846343701378493991">1024 (keskitaso)</translation>
<translation id="5476505524087279545">poista valinta</translation>
-<translation id="679352192834563463">Tämän sisällön näyttämiseen ei ole saatavissa laajennusta</translation>
<translation id="3789841737615482174">Asenna</translation>
+<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="3600343118165084788">Lataa laajennus napsauttamalla tätä</translation>
+<translation id="2597378329261239068">Tämä asiakirja on suojattu salasanalla. Anna salasana.</translation>
<translation id="6807599807928161586">verkkoalue</translation>
<translation id="5939518447894949180">Tyhjennä</translation>
-<translation id="3771786644471114952">Hae laajennus</translation>
<translation id="1842960171412779397">Valitse</translation>
+<translation id="7638452146404718955">Lataa laajennus napsauttamalla tätä</translation>
<translation id="6119846243427417423">aktivoi</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> tiedostoa</translation>
-<translation id="3926627843712816530">Vahvista, että haluat asentaa tämän laajennuksen. Kannattaa asentaa vain luotettavia laajennuksia.</translation>
-<translation id="4838490908464673667">Vaadittua laajennusta ei ole asennettu</translation>
+<translation id="4470547978413275879">Laajennusta <ph name="PLUGIN"/> ei asennettu</translation>
+<translation id="6765711848403622008">Tämän sisällön näyttämiseen ei ole saatavissa laajennusta</translation>
<translation id="8597182159515967513">otsikko</translation>
<translation id="2653659639078652383">Lähetä</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/>-laajennus vaaditaan</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_fil.xtb b/webkit/glue/resources/webkit_strings_fil.xtb
index 5ed7e04..43f88c3 100644
--- a/webkit/glue/resources/webkit_strings_fil.xtb
+++ b/webkit/glue/resources/webkit_strings_fil.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fil">
-<translation id="4420062214988137980">Nabigong pag-install sa plugin</translation>
+<translation id="4519964825805946997">Nabigong ma-install ang plug-in mula sa <ph name="URL"/></translation>
<translation id="1235745349614807883">Lisiman ang Kasalukuyang Mga Paghahanap</translation>
-<translation id="3825324228893189080">Kailangan ng karagdagang plugin</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> hindi na-install ang plugin</translation>
<translation id="5048533449481078685">Ilista ang marker</translation>
+<translation id="372362261556059955">Kinakailangan ang karagdagang plug-in</translation>
<translation id="4202807286478387388">tumalon</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Mangyaring kumpirmahin na nais mong i-install ang <ph name="PLUGIN"/> plugin. Dapat mo lamang i-install ang mga plugin na pinagkakatiwalaan mo.</translation>
<translation id="7658239707568436148">Ikansela</translation>
<translation id="795667975304826397">Walang napiling file</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> kinakailangang plugin</translation>
-<translation id="8662565117025751661">Nagda-download ng plugin...</translation>
+<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="6845533974506654842">pindutin</translation>
<translation id="8244226242650769279">mapa ng imahe</translation>
-<translation id="1383141426028388991">Nabigong i-install ang plugin mula sa <ph name="URL"/></translation>
<translation id="2548326553472216322">Walang kamakailang mga paghahanap</translation>
<translation id="5944544982112848342">2048 (Pinakamataas na Marka)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">Matapos ang pag-install ng plugin, mag-click dito upang mag-refresh</translation>
+<translation id="2745343197843472802">Kumuha ng Plug-in</translation>
+<translation id="5776402066334188252">Pakikumpirma na nais mong i-install ang plug-in na ito. Dapat mong i-install lamang ang mga plug-in na iyong pinagkakatiwalaan.</translation>
+<translation id="4003986561708175844">Hindi na-install ang kinakailangang plug-in</translation>
+<translation id="3018094406922859308">Nagda-download ng plug-in...</translation>
<translation id="7364796246159120393">Pumili ng File</translation>
<translation id="8964020114565522021">Kaldkarin dito ang file</translation>
<translation id="838869780401515933">I-tsek</translation>
<translation id="2846343701378493991">1024 (Katamtamang Grado)</translation>
<translation id="5476505524087279545">i-uncheck</translation>
-<translation id="679352192834563463">Walang magagamit na plugin na ipapakita sa nilalaman nito</translation>
<translation id="3789841737615482174">Install</translation>
+<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="3600343118165084788">Mag-click dito upagn mai-download ang plugin</translation>
+<translation id="2597378329261239068">Protektado ng password ang dokumentong ito. Mangyaring magpasok ng password.</translation>
<translation id="6807599807928161586">web area</translation>
<translation id="5939518447894949180">I-reset</translation>
-<translation id="3771786644471114952">Kunin ang Plugin</translation>
<translation id="1842960171412779397">piliin</translation>
+<translation id="7638452146404718955">Mag-click dito upang ma-download ang plug-in</translation>
<translation id="6119846243427417423">isaaktibo</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> mga file</translation>
-<translation id="3926627843712816530">Mangyaring kumpirmahin na dapat gusto mong i-install sa plugin na ito. Dapat mo lamang i-install ang mga plugin na pinagkakatiwalaan mo.</translation>
-<translation id="4838490908464673667">Ang kinakailangan na plugin ay hindi na-install</translation>
+<translation id="4470547978413275879">Hindi naka-install ang <ph name="PLUGIN"/> na plug-in</translation>
+<translation id="6765711848403622008">Walang magagamit na plug-in upang maipakita ang nilalamang ito</translation>
<translation id="8597182159515967513">heading</translation>
<translation id="2653659639078652383">Isumite</translation>
+<translation id="8475551193147984329">Kinakailangan ang plug-in na <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_fr.xtb b/webkit/glue/resources/webkit_strings_fr.xtb
index 1f78547..00ab953 100644
--- a/webkit/glue/resources/webkit_strings_fr.xtb
+++ b/webkit/glue/resources/webkit_strings_fr.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="fr">
-<translation id="4420062214988137980">Échec de l'installation du plug-in</translation>
+<translation id="4519964825805946997">Échec de l'installation du plug-in depuis <ph name="URL"/></translation>
<translation id="1235745349614807883">Effacer les recherches récentes</translation>
-<translation id="3825324228893189080">Plug-in supplémentaire requis</translation>
-<translation id="2965480764085142436">Le plug-in <ph name="PLUGIN"/> n'est pas installé.</translation>
<translation id="5048533449481078685">marqueur de liste</translation>
+<translation id="372362261556059955">Plug-in supplémentaire requis</translation>
<translation id="4202807286478387388">accéder</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/> × <ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Veuillez confirmer que vous souhaitez installer le plug-in <ph name="PLUGIN"/>. Veillez à installer uniquement des plug-ins approuvés.</translation>
<translation id="7658239707568436148">Annuler</translation>
<translation id="795667975304826397">Aucun fichier choisi</translation>
-<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> requis</translation>
-<translation id="8662565117025751661">Téléchargement du plug-in...</translation>
+<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="6845533974506654842">appuyer</translation>
<translation id="8244226242650769279">image map</translation>
-<translation id="1383141426028388991">Échec de l'installation du plugin depuis <ph name="URL"/></translation>
<translation id="2548326553472216322">Aucune recherche récente</translation>
<translation id="5944544982112848342">2048 (haute sécurité)</translation>
<translation id="3040011195152428237">Lien</translation>
-<translation id="8281246460978372009">Après l'installation du plug-in, cliquez ici pour actualiser.</translation>
+<translation id="2745343197843472802">Télécharger le plug-in</translation>
+<translation id="5776402066334188252">Merci de confirmer que vous souhaitez installer ce plug-in. N'installez que les plug-ins que vous considérez fiables.</translation>
+<translation id="4003986561708175844">Le plug-in requis n'est pas installé.</translation>
+<translation id="3018094406922859308">Téléchargement du plug-in...</translation>
<translation id="7364796246159120393">Choisissez un fichier</translation>
<translation id="8964020114565522021">Placer le fichier ici</translation>
<translation id="838869780401515933">cocher</translation>
<translation id="2846343701378493991">1024 (sécurité moyenne)</translation>
<translation id="5476505524087279545">décocher</translation>
-<translation id="679352192834563463">Aucun plug-in disponible pour afficher ce contenu</translation>
<translation id="3789841737615482174">Installer</translation>
+<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="3600343118165084788">Cliquez ici pour télécharger le plug-in</translation>
+<translation id="2597378329261239068">Ce document est protégé par mot de passe. Veuillez saisir ce dernier.</translation>
<translation id="6807599807928161586">Zone Web</translation>
<translation id="5939518447894949180">Réinitialiser</translation>
-<translation id="3771786644471114952">Ajouter le plug-in</translation>
<translation id="1842960171412779397">sélectionner</translation>
+<translation id="7638452146404718955">Cliquer ici pour télécharger le plug-in</translation>
<translation id="6119846243427417423">activer</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> fichiers</translation>
-<translation id="3926627843712816530">Veuillez confirmer que vous souhaitez installer ce plug-in. Vous devez uniquement installer des plug-ins approuvés.</translation>
-<translation id="4838490908464673667">Le plug-in requis n'est pas installé.</translation>
+<translation id="4470547978413275879">Le plug-in <ph name="PLUGIN"/> n'est pas installé.</translation>
+<translation id="6765711848403622008">Aucun plug-in disponible pour afficher ce contenu</translation>
<translation id="8597182159515967513">en-tête</translation>
<translation id="2653659639078652383">Valider</translation>
+<translation id="8475551193147984329">Le plug-in <ph name="PLUGIN"/> est requis.</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_gu.xtb b/webkit/glue/resources/webkit_strings_gu.xtb
index fb40c72..e7160bb 100644
--- a/webkit/glue/resources/webkit_strings_gu.xtb
+++ b/webkit/glue/resources/webkit_strings_gu.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="gu">
-<translation id="4420062214988137980">પà«àª²àª—ઇન ઇનà«àª¸à«àªŸà«‹àª²à«‡àª¶àª¨ નિષà«àª«àª³ થયà«àª‚ છે</translation>
+<translation id="4519964825805946997"><ph name="URL"/> થી પà«àª²àª—-ઇન ઇનà«àª¸à«àªŸà«‹àª² કરવામાં નિષà«àª«àª³ રહà«àª¯àª¾àª‚</translation>
<translation id="1235745349614807883">હાલની શોધને સાફ કરો</translation>
-<translation id="3825324228893189080">વધારાના પà«àª²àª—ઇનની જરૂરિયાત</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> પà«àª²àª—ઇન ઇનà«àª¸à«àªŸà«‹àª² કરેલà«àª‚ નથી</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="4317653869502688143">કૃપા કરીને પà«àª·à«àªŸàª¿ કરો કે તમને <ph name="PLUGIN"/> પà«àª²àª—ઇન ઇનà«àª¸à«àªŸà«‹àª² કરવà«àª‚ ગમશે. તમારે ફકà«àª¤ તે જ પà«àª²àª—ઇનà«àª¸ ઇનà«àª¸à«àªŸà«‹àª² કરવા જોઈઠજેના પર તમે વિશà«àªµàª¾àª¸ કરો છો.</translation>
<translation id="7658239707568436148">રદ કરો</translation>
<translation id="795667975304826397">કોઈ ફાઇલ પસંદ કરેલી નથી</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> પà«àª²àª—ઇનની જરૂરિયાત છે</translation>
-<translation id="8662565117025751661">પà«àª²àª—ઇન ડાઉનલોડ કરી રહà«àª¯à«àª‚ છે...</translation>
+<translation id="1416462845279468967">પà«àª²àª—-ઇન ઇનà«àª¸à«àªŸà«‹àª²à«‡àª¶àª¨ નિષà«àª«àª³ ગયà«àª‚</translation>
<translation id="8141602879876242471">આ àªàª• શોધસકà«àª·àª® અનà«àª•à«àª°àª®àª£àª¿àª•àª¾ છે. શોધ કીવરà«àª¡à«àª¸ દાખલ કરો:</translation>
+<translation id="5650795167354946011">પà«àª²àª—-ઇન ઇનà«àª¸à«àªŸà«‹àª² કરà«àª¯àª¾ પછી, રીફà«àª°à«‡àª¶ કરવા અહીં કà«àª²àª¿àª• કરો</translation>
<translation id="6845533974506654842">દબાવો</translation>
<translation id="8244226242650769279">છબી નકશો</translation>
-<translation id="1383141426028388991"><ph name="URL"/> માંથી પà«àª²àª—ઇન ઇનà«àª¸à«àªŸà«‹àª² કરવામાં નિષà«àª«àª³</translation>
<translation id="2548326553472216322">હાલની શોધો નથી</translation>
<translation id="5944544982112848342">2048 (ઉચà«àªš ગà«àª°à«‡àª¡)</translation>
<translation id="3040011195152428237">લિંક</translation>
-<translation id="8281246460978372009">પà«àª²àª—ઇન ઇનà«àª¸à«àªŸà«‹àª² કરà«àª¯àª¾ પછી, રીફà«àª°à«‡àª¶ કરવા અહીં કà«àª²àª¿àª• કરો</translation>
+<translation id="2745343197843472802">પà«àª²àª—-ઇન મેળવો</translation>
+<translation id="5776402066334188252">કૃપા કરીને પà«àª·à«àªŸà«€ કરો કે તમે આ પà«àª²àª—-ઇન ઇનà«àª¸à«àªŸà«‹àª² કરવાનà«àª‚ પસંદ કરશો. તમારે ફકà«àª¤ તે જ પà«àª²àª—-ઇનà«àª¸ ઇનà«àª¸à«àªŸà«‹àª² કરવા જોઈઠજે વિશà«àªµàª¸à«àª¤ હોય.</translation>
+<translation id="4003986561708175844">જોઈતà«àª‚ પà«àª²àª—-ઇન ઇનà«àª¸à«àªŸà«‹àª² કરેલà«àª‚ નથી</translation>
+<translation id="3018094406922859308">પà«àª²àª—-ઇન ડાઉનલોડ કરી રહà«àª¯à«àª‚ છે...</translation>
<translation id="7364796246159120393">ફાઇલ પસંદ કરો</translation>
<translation id="8964020114565522021">ફાઇલને અહીં ખેંચો</translation>
<translation id="838869780401515933">તપાસો</translation>
<translation id="2846343701378493991">1024 (મધà«àª¯àª® ગà«àª°à«‡àª¡)</translation>
<translation id="5476505524087279545">અનચેક કરો</translation>
-<translation id="679352192834563463">આ સમાગà«àª°à«€ પà«àª°àª¦àª°à«àª¶àª¿àª¤ કરવા માટે કોઈ પà«àª²àª—ઇન ઉપલબà«àª§ નથી</translation>
<translation id="3789841737615482174">ઇનà«àª¸à«àªŸà«‹àª² કરો</translation>
+<translation id="5253117816378681419">કૃપા કરીને પà«àª·à«àªŸà«€ કરો કે તમે <ph name="PLUGIN"/> પà«àª²àª—-ઇન ઇનà«àª¸à«àªŸà«‹àª² કરવાનà«àª‚ પસંદ કરશો. તમારે ફકà«àª¤ તે જ પà«àª²àª—-ઇનà«àª¸ ઇનà«àª¸à«àªŸà«‹àª² કરવા જોઈઠજે વિશà«àªµàª¸à«àª¤ હોય.</translation>
<translation id="6663448176199120256">તાજેતરની શોધ</translation>
-<translation id="3600343118165084788">પà«àª²àª—ઇન ડાઉનલોડ કરવા માટે અહીં કà«àª²àª¿àª• કરો</translation>
+<translation id="2597378329261239068">આ દસà«àª¤àª¾àªµà«‡àªœ પાસવરà«àª¡ સà«àª°àª•à«àª·àª¿àª¤ છે. કૃપા કરીને પાસવરà«àª¡ દાખલ કરો.</translation>
<translation id="6807599807928161586">વેબ કà«àª·à«‡àª¤à«àª°</translation>
<translation id="5939518447894949180">રીસેટ કરો</translation>
-<translation id="3771786644471114952">પà«àª²àª—ઇન મેળવો</translation>
<translation id="1842960171412779397">પસંદ કરો</translation>
+<translation id="7638452146404718955">પà«àª²àª—-ઇન ડાઉનલોડ કરવા માટે અહીં કà«àª²àª¿àª• કરો</translation>
<translation id="6119846243427417423">સકà«àª°àª¿àª¯ કરો</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> ફાઇલો</translation>
-<translation id="3926627843712816530">કૃપા કરીને પà«àª·à«àªŸàª¿ કરો કે તમને આ પà«àª²àª—ઇન ઇનà«àª¸à«àªŸà«‹àª² કરવà«àª‚ ગમશે. તમારે ફકà«àª¤ તે જ પà«àª²àª—ઇનà«àª¸ ઇનà«àª¸à«àªŸà«‹àª² કરવા જોઈઠજેના પર તમે વિશà«àªµàª¾àª¸ કરો છો.</translation>
-<translation id="4838490908464673667">જોઈતà«àª‚ પà«àª²àª—ઇન ઇનà«àª¸à«àªŸà«‹àª² કરેલà«àª‚ નથી</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> પà«àª²àª—-ઇન ઇનà«àª¸à«àªŸà«‹àª² કરેલà«àª‚ નથી</translation>
+<translation id="6765711848403622008">આ સામગà«àª°à«€ પà«àª°àª¦àª°à«àª¶àª¿àª¤ કરવા માટે કોઈ પà«àª²àª—ઇન ઉપલબà«àª§ નથી</translation>
<translation id="8597182159515967513">મથાળà«àª‚</translation>
<translation id="2653659639078652383">સબમિટ કરો</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> પà«àª²àª—-ઇન આવશà«àª¯àª• છે </translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_hi.xtb b/webkit/glue/resources/webkit_strings_hi.xtb
index 8522437..e9bf9e7 100644
--- a/webkit/glue/resources/webkit_strings_hi.xtb
+++ b/webkit/glue/resources/webkit_strings_hi.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hi">
-<translation id="4420062214988137980">पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ असफ़ल रही</translation>
+<translation id="4519964825805946997"><ph name="URL"/> से पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने में विफल हà¥à¤†</translation>
<translation id="1235745349614807883">हाल ही की खोजें साफ़ करें</translation>
-<translation id="3825324228893189080">अतिरिकà¥à¤¤ पà¥à¤²à¤—इन आवशà¥à¤¯à¤•</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं किया गया है</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="4317653869502688143">कृपया पà¥à¤·à¥à¤Ÿà¤¿ करें कि आप <ph name="PLUGIN"/> पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करना चाहते हैं. आपके केवल वे पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने चाहिठजिनपर आप भरोसा करते हों.</translation>
<translation id="7658239707568436148">रदà¥à¤¦ करें</translation>
<translation id="795667975304826397">कोई फाइल नहीं चà¥à¤¨à¥€ गई</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> पà¥à¤²à¤—इन आवशà¥à¤¯à¤•</translation>
-<translation id="8662565117025751661">पà¥à¤²à¤—इन डाउनलोड कर रहा है ...</translation>
+<translation id="1416462845279468967">पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ विफल हà¥à¤ˆ</translation>
<translation id="8141602879876242471">यह à¤à¤• खोजने योगà¥à¤¯ इंडेकà¥à¤¸ है. खोज कà¥à¤‚जीशबà¥à¤¦ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करें :</translation>
+<translation id="5650795167354946011">पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने के बाद, रीफ़à¥à¤°à¥‡à¤¶ करने के लिठयहां कà¥à¤²à¤¿à¤• करें</translation>
<translation id="6845533974506654842">दबाà¤à¤</translation>
<translation id="8244226242650769279">चितà¥à¤° मैप</translation>
-<translation id="1383141426028388991"><ph name="URL"/> से पà¥à¤²à¤—इन इंसà¥à¤Ÿà¤¾à¤² करने में असफ़ल रहा</translation>
<translation id="2548326553472216322">हाल ही में कोई खोज नहीं</translation>
<translation id="5944544982112848342">2048 (उचà¥à¤š गà¥à¤°à¥‡à¤¡)</translation>
<translation id="3040011195152428237">लिंक</translation>
-<translation id="8281246460978372009">पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने के बाद, पà¥à¤¨: ताज़ा करने के लिठयहाठकà¥à¤²à¤¿à¤• करें</translation>
+<translation id="2745343197843472802">पà¥â€à¤²à¤—-इन पà¥à¤°à¤¾à¤ªà¥à¤¤ करें</translation>
+<translation id="5776402066334188252">कृपया पà¥à¤·à¥à¤Ÿà¤¿ करें कि आप यह पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करना चाहेंगे. आपको केवल वे पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने चाहिठजिन पर आप विशà¥à¤µà¤¾à¤¸ करते हैं.</translation>
+<translation id="4003986561708175844">आवशà¥à¤¯à¤• पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं है</translation>
+<translation id="3018094406922859308">पà¥à¤²à¤—-इन डाउनलोड किया जा रहा है...</translation>
<translation id="7364796246159120393">फ़ाइल चà¥à¤¨à¥‡à¤‚</translation>
<translation id="8964020114565522021">फाइल खींचकर यहाठलाà¤à¤‚</translation>
<translation id="838869780401515933">चेक करें</translation>
<translation id="2846343701378493991">1024 (मधà¥à¤¯à¤® गà¥à¤°à¥‡à¤¡)</translation>
<translation id="5476505524087279545">अनचेक करें</translation>
-<translation id="679352192834563463">इस सामगà¥à¤°à¥€ को पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करने के लिठकोई पà¥à¤²à¤—इन उपलबà¥à¤§ नहीं है</translation>
<translation id="3789841737615482174">सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करें</translation>
+<translation id="5253117816378681419">कृपया पà¥à¤·à¥à¤Ÿà¤¿ करें कि आप <ph name="PLUGIN"/> पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करना चाहेंगे. आपको केवल वे पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने चाहिठजिन पर आप विशà¥à¤µà¤¾à¤¸ करते हैं.</translation>
<translation id="6663448176199120256">हाल ही में की गई खोजें</translation>
-<translation id="3600343118165084788">पà¥à¤²à¤—इन डाउनलोड करने के लिठयहाठकà¥à¤²à¤¿à¤• करें</translation>
+<translation id="2597378329261239068">यह दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ पासवरà¥à¤¡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है. कृपया à¤à¤• पासवरà¥à¤¡ दरà¥à¤œ करें.</translation>
<translation id="6807599807928161586">वेब कà¥à¤·à¥‡à¤¤à¥à¤°</translation>
<translation id="5939518447894949180">पà¥à¤¨: सेट करें</translation>
-<translation id="3771786644471114952">पà¥à¤²à¤—इन पà¥à¤°à¤¾à¤ªà¥à¤¤ करें</translation>
<translation id="1842960171412779397">चà¥à¤¨à¥‡à¤‚</translation>
+<translation id="7638452146404718955">पà¥à¤²à¤—-इन डाउनलोड करने के लिठयहां कà¥à¤²à¤¿à¤• करें</translation>
<translation id="6119846243427417423">सकà¥à¤°à¤¿à¤¯ करें</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> फ़ाइलें</translation>
-<translation id="3926627843712816530">कृपया पà¥à¤·à¥à¤Ÿà¤¿ करें कि आप यह पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करना चाहते हैं. आपके केवल वे पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करने चाहिठजिनपर आप भरोसा करते हों.</translation>
-<translation id="4838490908464673667">आवशà¥à¤¯à¤• पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं है</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं है</translation>
+<translation id="6765711848403622008">इस सामगà¥à¤°à¥€ को पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करने के लिठकोई पà¥à¤²à¤—-इन उपलबà¥à¤§ नहीं है</translation>
<translation id="8597182159515967513">हेडिंग</translation>
<translation id="2653659639078652383">जमा करें</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> पà¥à¤²à¤—-इन की आवशà¥à¤¯à¤•à¤¤à¤¾ है</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_hr.xtb b/webkit/glue/resources/webkit_strings_hr.xtb
index bc93649..89458bb 100644
--- a/webkit/glue/resources/webkit_strings_hr.xtb
+++ b/webkit/glue/resources/webkit_strings_hr.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hr">
-<translation id="4420062214988137980">Nije uspjela instalacija dodatka</translation>
+<translation id="4519964825805946997">Nije uspjela instalacija dodatka s adrese <ph name="URL"/></translation>
<translation id="1235745349614807883">Obriši najnovija pretraživanja</translation>
-<translation id="3825324228893189080">Potreban je dodatak</translation>
-<translation id="2965480764085142436">Nije instaliran dodatak za <ph name="PLUGIN"/></translation>
<translation id="5048533449481078685">oznaka popisa</translation>
+<translation id="372362261556059955">Potreban je dodatni dodatak</translation>
<translation id="4202807286478387388">skoÄi</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Potvrdite da želite instalirati dodatak za <ph name="PLUGIN"/> Instalirajte samo one dodatke kojima vjerujete.</translation>
<translation id="7658239707568436148">Odustani</translation>
<translation id="795667975304826397">Nije odabrana niti jedna datoteka.</translation>
-<translation id="1275511093094545429">Potreban je dodatak za <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Preuzimanje dodatka...</translation>
+<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="6845533974506654842">pritisni</translation>
<translation id="8244226242650769279">karta slika</translation>
-<translation id="1383141426028388991">Nije uspjela instalacija dodatka s <ph name="URL"/></translation>
<translation id="2548326553472216322">Nema najnovijih pretraživanja</translation>
<translation id="5944544982112848342">2048 (visoki stupanj)</translation>
<translation id="3040011195152428237">veza</translation>
-<translation id="8281246460978372009">Nakon instalacije dodatka, kliknite ovdje za osvježenje stranice</translation>
+<translation id="2745343197843472802">Nabavi dodatak</translation>
+<translation id="5776402066334188252">Potvrdite da želite instalirati dodatak. Instalirajte samo dodatke koje smatrate pouzdanima.</translation>
+<translation id="4003986561708175844">Potreban dodatak nije instaliran</translation>
+<translation id="3018094406922859308">Preuzimanje dodatka...</translation>
<translation id="7364796246159120393">Odaberi datoteku</translation>
<translation id="8964020114565522021">Povucite datoteku ovamo</translation>
<translation id="838869780401515933">oznaÄi</translation>
<translation id="2846343701378493991">1024 (srednji)</translation>
<translation id="5476505524087279545">ukloni oznaku</translation>
-<translation id="679352192834563463">Nema dostupnog dodatka za prikaz ovog sadržaja</translation>
<translation id="3789841737615482174">Instaliraj</translation>
+<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="3600343118165084788">Kliknite ovdje za preuzimanje dodatka</translation>
+<translation id="2597378329261239068">Ovaj je dokument zaštićen zaporkom. Unesite zaporku.</translation>
<translation id="6807599807928161586">web podruÄje</translation>
<translation id="5939518447894949180">Ponovno postavi</translation>
-<translation id="3771786644471114952">Dohvati dodatak</translation>
<translation id="1842960171412779397">odaberi</translation>
+<translation id="7638452146404718955">Kliknite ovdje za preuzimanje dodatka</translation>
<translation id="6119846243427417423">aktiviraj</translation>
<translation id="8444882422881193423">Broj datoteka: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">Potvrdite da želite instalirati ovaj dodatak. Instalirajte samo one dodatke kojima vjerujete.</translation>
-<translation id="4838490908464673667">Potreban dodatak nije instaliran</translation>
+<translation id="4470547978413275879">Nije instaliran dodatak za <ph name="PLUGIN"/></translation>
+<translation id="6765711848403622008">Nema dostupnog dodatka za prikaz ovog sadržaja</translation>
<translation id="8597182159515967513">naslov</translation>
<translation id="2653659639078652383">Pošalji</translation>
+<translation id="8475551193147984329">Potreban je dodatak <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_hu.xtb b/webkit/glue/resources/webkit_strings_hu.xtb
index 7a04612..848f2df 100644
--- a/webkit/glue/resources/webkit_strings_hu.xtb
+++ b/webkit/glue/resources/webkit_strings_hu.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="hu">
-<translation id="4420062214988137980">A plugin telepítése nem sikerült</translation>
+<translation id="4519964825805946997">A plug-in telepítése nem sikerült a következő helyről: <ph name="URL"/></translation>
<translation id="1235745349614807883">Friss keresések törlése</translation>
-<translation id="3825324228893189080">További plugin szükséges</translation>
-<translation id="2965480764085142436">A(z) <ph name="PLUGIN"/> plugin nem lett telepítve</translation>
<translation id="5048533449481078685">listajelölő</translation>
+<translation id="372362261556059955">További plug-in szükséges</translation>
<translation id="4202807286478387388">Mehet</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Kérjük, erősítse meg, hogy telepíteni szeretné a(z) <ph name="PLUGIN"/> plugint. Csak azokat a plugineket telepítse, amelyekben megbízik.</translation>
<translation id="7658239707568436148">Mégse</translation>
<translation id="795667975304826397">Nem lett fájl kiválasztva</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> plugin szükséges</translation>
-<translation id="8662565117025751661">Plugin letöltése...</translation>
+<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="6845533974506654842">Gomb lenyomása</translation>
<translation id="8244226242650769279">képtérkép</translation>
-<translation id="1383141426028388991">A plugin telepítése nem sikerült a következő helyről: <ph name="URL"/></translation>
<translation id="2548326553472216322">Nincsenek friss keresések</translation>
<translation id="5944544982112848342">2048 (magasfokú)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">A plugin telepítését követően ide kattintson a frissítéshez</translation>
+<translation id="2745343197843472802">Plug-in beszerzése</translation>
+<translation id="5776402066334188252">Kérjük, igazolja, hogy ezt a plug-int szeretné telepíteni. Csak azokat a plug-ineket telepítse, amelyekben megbízik.</translation>
+<translation id="4003986561708175844">A szükséges plug-in nem lett telepítve</translation>
+<translation id="3018094406922859308">Plug-in letöltése...</translation>
<translation id="7364796246159120393">Fájl kiválasztása</translation>
<translation id="8964020114565522021">Húzza át ide a fájlt</translation>
<translation id="838869780401515933">Megjelölés</translation>
<translation id="2846343701378493991">1024 (Közepes)</translation>
<translation id="5476505524087279545">Megjelölés eltávolítása</translation>
-<translation id="679352192834563463">Nincs elérhető plugin a tartalom megjelenítéséhez</translation>
<translation id="3789841737615482174">Telepítés</translation>
+<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="3600343118165084788">Ha ide kattint, letöltheti a plugint</translation>
+<translation id="2597378329261239068">Ez a dokumentum jelszóval védett. Kérjük, adja meg a jelszót.</translation>
<translation id="6807599807928161586">internetes terület</translation>
<translation id="5939518447894949180">Visszaállítás</translation>
-<translation id="3771786644471114952">Plugin beszerzése</translation>
<translation id="1842960171412779397">Kiválasztás</translation>
+<translation id="7638452146404718955">Ide kattintva letöltheti a plug-int</translation>
<translation id="6119846243427417423">Aktiválás</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> fájl</translation>
-<translation id="3926627843712816530">Kérjük, erősítse meg, hogy telepíteni szeretné ezt a plugint. Csak azokat a plugineket telepítse, amelyekben megbízik.</translation>
-<translation id="4838490908464673667">A szükséges plugin nem lett telepítve</translation>
+<translation id="4470547978413275879">A következő plug-in nincs telepítve: <ph name="PLUGIN"/></translation>
+<translation id="6765711848403622008">Nincs elérhető plug-in a tartalom megjelenítéséhez</translation>
<translation id="8597182159515967513">fejléc</translation>
<translation id="2653659639078652383">Elküldés</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> plug-in szükséges</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_id.xtb b/webkit/glue/resources/webkit_strings_id.xtb
index d174e84..6451c08 100644
--- a/webkit/glue/resources/webkit_strings_id.xtb
+++ b/webkit/glue/resources/webkit_strings_id.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="id">
-<translation id="4420062214988137980">Penginstalan plug-in gagal</translation>
+<translation id="4519964825805946997">Gagal memasang pengaya dari <ph name="URL"/></translation>
<translation id="1235745349614807883">Hapus Penelusuran Barusan</translation>
-<translation id="3825324228893189080">Diperlukan plug-in tambahan</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> plug-in belum terinstal</translation>
<translation id="5048533449481078685">penanda daftar</translation>
+<translation id="372362261556059955">Diperlukan pengaya tambahan</translation>
<translation id="4202807286478387388">lompati</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/> - <ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Konfirmasikan bahwa Anda ingin menginstal plug-in<ph name="PLUGIN"/>. Sebaiknya hanya instal plug-in yang Anda percaya.</translation>
<translation id="7658239707568436148">Batal</translation>
<translation id="795667975304826397">Tidak ada file yang dipilih</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> diperlukan plug-in</translation>
-<translation id="8662565117025751661">Mengunduh plug-in...</translation>
+<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="6845533974506654842">tekan</translation>
<translation id="8244226242650769279">gambar peta</translation>
-<translation id="1383141426028388991">Gagal menginstal plug-in dari <ph name="URL"/></translation>
<translation id="2548326553472216322">Tidak ada penelusuran terkini</translation>
<translation id="5944544982112848342">2048 (Tingkat Tinggi)</translation>
<translation id="3040011195152428237">tautan</translation>
-<translation id="8281246460978372009">Setelah menginstal plug-in, klik di sini untuk me-refresh</translation>
+<translation id="2745343197843472802">Dapatkan Pengaya</translation>
+<translation id="5776402066334188252">Konfirmasikan bahwa Anda ingin memasang pengaya ini. Anda harus memasang pengaya yang dipercayai saja.</translation>
+<translation id="4003986561708175844">Pengaya yang diperlukan belum terpasang</translation>
+<translation id="3018094406922859308">Mengunduh pengaya...</translation>
<translation id="7364796246159120393">Pilih Berkas</translation>
<translation id="8964020114565522021">Tarik file ke sini</translation>
<translation id="838869780401515933">centangi</translation>
<translation id="2846343701378493991">1024 (Tingkat Menengah)</translation>
<translation id="5476505524087279545">batalkan centang</translation>
-<translation id="679352192834563463">Tidak tersedia plug-in untuk menampilkan konten ini</translation>
<translation id="3789841737615482174">Instal</translation>
+<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="3600343118165084788">Klik di sini untuk mengunduh plug-in</translation>
+<translation id="2597378329261239068">Dokumen ini dilindungi sandi. Masukkan sandi.</translation>
<translation id="6807599807928161586">area Web</translation>
<translation id="5939518447894949180">Atur ulang</translation>
-<translation id="3771786644471114952">Dapatkan Plug-in</translation>
<translation id="1842960171412779397">pilih</translation>
+<translation id="7638452146404718955">Klik di sini untuk mengunduh pengaya</translation>
<translation id="6119846243427417423">aktifkan</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> berkas</translation>
-<translation id="3926627843712816530">Konfirmasikan bahwa Anda ingin menginstal plug-in ini. Sebaiknya hanya instal plug-in yang Anda percaya.</translation>
-<translation id="4838490908464673667">Plug-in yang diperlukan belum terinstal</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> pengaya belum terpasang</translation>
+<translation id="6765711848403622008">Tidak tersedia pengaya untuk menampilkan konten ini</translation>
<translation id="8597182159515967513">kepala</translation>
<translation id="2653659639078652383">Kirim</translation>
+<translation id="8475551193147984329">Pengaya <ph name="PLUGIN"/> diperlukan</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_it.xtb b/webkit/glue/resources/webkit_strings_it.xtb
index f599db0..61c1e79 100644
--- a/webkit/glue/resources/webkit_strings_it.xtb
+++ b/webkit/glue/resources/webkit_strings_it.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="it">
-<translation id="4420062214988137980">Installazione plug-in non riuscita</translation>
+<translation id="4519964825805946997">Installazione del plug-in da <ph name="URL"/> non riuscita</translation>
<translation id="1235745349614807883">Cancella ricerche recenti</translation>
-<translation id="3825324228893189080">Plug-in aggiuntivo necessario</translation>
-<translation id="2965480764085142436">Plug-in <ph name="PLUGIN"/> non installato</translation>
<translation id="5048533449481078685">indicatore elenco</translation>
+<translation id="372362261556059955">È necessario un plug-in aggiuntivo</translation>
<translation id="4202807286478387388">vai</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Conferma l'installazione del plug-in <ph name="PLUGIN"/>. Ti invitiamo a installare solo i plug-in che ritieni affidabili.</translation>
<translation id="7658239707568436148">Annulla</translation>
<translation id="795667975304826397">Nessun file selezionato</translation>
-<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> necessario</translation>
-<translation id="8662565117025751661">Download del plug-in in corso...</translation>
+<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="6845533974506654842">premi</translation>
<translation id="8244226242650769279">image map</translation>
-<translation id="1383141426028388991">Installazione plug-in da <ph name="URL"/> non riuscita</translation>
<translation id="2548326553472216322">Nessuna ricerca recente</translation>
<translation id="5944544982112848342">2048 (alta qualità)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">Dopo aver installato il plug-in, fai clic qui per aggiornare</translation>
+<translation id="2745343197843472802">Scarica plug-in</translation>
+<translation id="5776402066334188252">Conferma l'installazione del plug-in. Dovresti installare soltanto plug-in attendibili.</translation>
+<translation id="4003986561708175844">Il plug-in richiesto non è installato</translation>
+<translation id="3018094406922859308">Download del plug-in in corso...</translation>
<translation id="7364796246159120393">Scegli file</translation>
<translation id="8964020114565522021">Trascina il file qui</translation>
<translation id="838869780401515933">seleziona</translation>
<translation id="2846343701378493991">1024 (Medium Grade)</translation>
<translation id="5476505524087279545">deseleziona</translation>
-<translation id="679352192834563463">Nessun plug-in disponibile per visualizzare il contenuto</translation>
<translation id="3789841737615482174">Installa</translation>
+<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="3600343118165084788">Fai clic qui per scaricare il plug-in</translation>
+<translation id="2597378329261239068">Questo documento è protetto da password. Inserisci una password.</translation>
<translation id="6807599807928161586">area web</translation>
<translation id="5939518447894949180">Ripristina</translation>
-<translation id="3771786644471114952">Aggiungi plug-in</translation>
<translation id="1842960171412779397">seleziona</translation>
+<translation id="7638452146404718955">Fai clic qui per scaricare il plug-in</translation>
<translation id="6119846243427417423">attiva</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> file</translation>
-<translation id="3926627843712816530">Conferma l'installazione del plug-in. Ti invitiamo a installare solo i plug-in che ritieni affidabili.</translation>
-<translation id="4838490908464673667">Il plug-in richiesto non è installato</translation>
+<translation id="4470547978413275879">Il plug-in <ph name="PLUGIN"/> non è installato</translation>
+<translation id="6765711848403622008">Nessun plug-in disponibile per visualizzare questo contenuto</translation>
<translation id="8597182159515967513">intestazione</translation>
<translation id="2653659639078652383">Invia</translation>
+<translation id="8475551193147984329">È necessario il plug-in <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_iw.xtb b/webkit/glue/resources/webkit_strings_iw.xtb
index 652d600..436b298 100644
--- a/webkit/glue/resources/webkit_strings_iw.xtb
+++ b/webkit/glue/resources/webkit_strings_iw.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="iw">
-<translation id="4420062214988137980">התקנת פלג×-×ין נכשלה</translation>
+<translation id="4519964825805946997">התקנת הפל×גין מתוך <ph name="URL"/> נכשלה</translation>
<translation id="1235745349614807883">הסר ×—×™×¤×•×©×™× ×חרוני×</translation>
-<translation id="3825324228893189080">דרוש תוסף נוסף</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> ×ינו מותקן</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="4317653869502688143">×שר שברצונך להתקין ×ת התוסף <ph name="PLUGIN"/>. עליך להתקין רק ×ª×•×¡×¤×™× ×תה בוטח.</translation>
<translation id="7658239707568436148">ביטול</translation>
<translation id="795667975304826397">×œ× × ×‘×—×¨ קובץ</translation>
-<translation id="1275511093094545429">נדרש plugin <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">מוריד תוסף...</translation>
+<translation id="1416462845279468967">התקנת הפל×גין נכשלה</translation>
<translation id="8141602879876242471">זהו ×ינדקס שניתן לבצע בו חיפוש. הזן מילות מפתח לחיפוש:</translation>
+<translation id="5650795167354946011">ל×חר התקנת הפל×גין, לחץ ×›×ן לרענון</translation>
<translation id="6845533974506654842">לחץ</translation>
<translation id="8244226242650769279">מפת תמונות</translation>
-<translation id="1383141426028388991">התקנת התוסף (plugin) מ-<ph name="URL"/> נכשלה</translation>
<translation id="2548326553472216322">×ין ×—×™×¤×•×©×™× ×חרוני×</translation>
<translation id="5944544982112848342">2048 (High Grade)</translation>
<translation id="3040011195152428237">קישור</translation>
-<translation id="8281246460978372009">ל×חר התקנת התוסף, לחץ ×›×ן לרענון</translation>
+<translation id="2745343197843472802">השג פל×גין</translation>
+<translation id="5776402066334188252">×שר שברצונך להתקין פל×גין ×–×”. יש להתקין רכיבי פל×גין ש×תה בוטח ×‘×”× ×‘×œ×‘×“.</translation>
+<translation id="4003986561708175844">הפל×גין הדרוש ×ינו מותקן</translation>
+<translation id="3018094406922859308">מוריד פל×גין...</translation>
<translation id="7364796246159120393">בחר קובץ</translation>
<translation id="8964020114565522021">גרור ×ת הקובץ לכ×ן</translation>
<translation id="838869780401515933">סמן</translation>
<translation id="2846343701378493991">1024 (Medium Grade)</translation>
<translation id="5476505524087279545">בטל סימון</translation>
-<translation id="679352192834563463">×ין תוסף זמין להצגת תוכן ×–×”</translation>
<translation id="3789841737615482174">התקן</translation>
+<translation id="5253117816378681419">×שר שברצונך להתקין ×ת הפל×גין <ph name="PLUGIN"/>. יש להתקין רכיבי פל×גין ש×תה בוטח ×‘×”× ×‘×œ×‘×“.</translation>
<translation id="6663448176199120256">×—×™×¤×•×©×™× ×חרוני×</translation>
-<translation id="3600343118165084788">לחץ ×›×ן להורדת התוסף</translation>
+<translation id="2597378329261239068">מסמך ×–×” מוגן ב×מצעות סיסמה. הזן סיסמה.</translation>
<translation id="6807599807928161586">×זור ×ינטרנט</translation>
<translation id="5939518447894949180">×פס</translation>
-<translation id="3771786644471114952">קבל תוסף</translation>
<translation id="1842960171412779397">בחר</translation>
+<translation id="7638452146404718955">לחץ ×›×ן להורדת פל×גין</translation>
<translation id="6119846243427417423">הפעל</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> קבצי×</translation>
-<translation id="3926627843712816530">×× × ×שר שברצונך להתקין תוסף ×–×”. עליך להתקין רק ×ª×•×¡×¤×™× ×©×‘×”× ×תה בוטח.</translation>
-<translation id="4838490908464673667">התוסף המבוקש ×ינו מותקן</translation>
+<translation id="4470547978413275879">הפל×גין <ph name="PLUGIN"/> ×ינו מותקן</translation>
+<translation id="6765711848403622008">×ין פל×גין זמין להצגת תוכן ×–×”</translation>
<translation id="8597182159515967513">כותרת</translation>
<translation id="2653659639078652383">שלח</translation>
+<translation id="8475551193147984329">הפל×גין <ph name="PLUGIN"/> דרוש</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ja.xtb b/webkit/glue/resources/webkit_strings_ja.xtb
index c16df86..2eccba2 100644
--- a/webkit/glue/resources/webkit_strings_ja.xtb
+++ b/webkit/glue/resources/webkit_strings_ja.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ja">
-<translation id="4420062214988137980">プラグインã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ãŒå¤±æ•—ã—ã¾ã—ãŸ</translation>
+<translation id="4519964825805946997"><ph name="URL"/> ã‹ã‚‰ãƒ—ラグインをインストールã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="1235745349614807883">最近ã®æ¤œç´¢å±¥æ­´ã‚’消去</translation>
-<translation id="3825324228893189080">追加ã®å¿…è¦ãªãƒ—ラグイン</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> プラグインã¯ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã›ã‚“</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="4317653869502688143"><ph name="PLUGIN"/> プラグインã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã‚’確èªã—ã¦ãã ã•ã„。信頼ã§ãるプラグインã ã‘インストールã—ã¦ãã ã•ã„。</translation>
<translation id="7658239707568436148">キャンセル</translation>
<translation id="795667975304826397">é¸æŠžã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> プラグインãŒå¿…è¦ã§ã™</translation>
-<translation id="8662565117025751661">プラグインをダウンロードã—ã¦ã„ã¾ã™...</translation>
+<translation id="1416462845279468967">プラグインをインストールã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="8141602879876242471">ã“ã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã¯æ¤œç´¢ã§ãã¾ã™ã€‚キーワードを入力ã—ã¦ãã ã•ã„:</translation>
+<translation id="5650795167354946011">プラグインをインストールã—ãŸå¾Œã¯ã€ã“ã“をクリックã—ã¦æ›´æ–°ã‚’è¡Œã£ã¦ãã ã•ã„</translation>
<translation id="6845533974506654842">押ã™</translation>
<translation id="8244226242650769279">イメージ マップ</translation>
-<translation id="1383141426028388991"><ph name="URL"/> ã‹ã‚‰ãƒ—ラグインをインストールã§ãã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="2548326553472216322">最近ã®æ¤œç´¢ã¯ã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="5944544982112848342">2048 (高)</translation>
<translation id="3040011195152428237">リンク</translation>
-<translation id="8281246460978372009">プラグインをインストールã—ãŸå¾Œã¯ã€ã“ã“をクリックã—ã¦æ›´æ–°ã—ã¦ãã ã•ã„</translation>
+<translation id="2745343197843472802">プラグインをダウンロード</translation>
+<translation id="5776402066334188252">ã“ã®ãƒ—ラグインをインストールã—ã¦ã‚‚よã„ã‹ã”確èªãã ã•ã„。信頼ã§ãるプラグインã®ã¿ã‚’インストールã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</translation>
+<translation id="4003986561708175844">å¿…è¦ãªãƒ—ラグインãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
+<translation id="3018094406922859308">プラグインをダウンロードã—ã¦ã„ã¾ã™...</translation>
<translation id="7364796246159120393">ファイルをé¸æŠž</translation>
<translation id="8964020114565522021">ファイルをã“ã“ã«ãƒ‰ãƒ©ãƒƒã‚°</translation>
<translation id="838869780401515933">ãƒã‚§ãƒƒã‚¯ã‚’付ã‘ã‚‹</translation>
<translation id="2846343701378493991">1024 (中)</translation>
<translation id="5476505524087279545">ãƒã‚§ãƒƒã‚¯ã‚’外ã™</translation>
-<translation id="679352192834563463">ã“ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®è¡¨ç¤ºã«ä½¿ç”¨ã§ãるプラグインã¯ã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="3789841737615482174">インストール</translation>
+<translation id="5253117816378681419">ã“ã® <ph name="PLUGIN"/> プラグインをインストールã—ã¦ã‚‚よã„ã‹ã”確èªãã ã•ã„。信頼ã§ãるプラグインã®ã¿ã‚’インストールã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="6663448176199120256">最近ã®æ¤œç´¢</translation>
-<translation id="3600343118165084788">ã“ã“をクリックã—ã¦ãƒ—ラグインをダウンロード</translation>
+<translation id="2597378329261239068">ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ãƒ‘スワードã§ä¿è­·ã•ã‚Œã¦ã„ã¾ã™ã€‚パスワードを入力ã—ã¦ãã ã•ã„。</translation>
<translation id="6807599807928161586">ウェブ領域</translation>
<translation id="5939518447894949180">リセット</translation>
-<translation id="3771786644471114952">プラグインã®å–å¾—</translation>
<translation id="1842960171412779397">é¸æŠž</translation>
+<translation id="7638452146404718955">ã“ã“をクリックã—ã¦ãƒ—ラグインをダウンロード</translation>
<translation id="6119846243427417423">アクティブã«ã™ã‚‹</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> ファイル</translation>
-<translation id="3926627843712816530">ã“ã®ãƒ—ラグインã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã‚’確èªã—ã¦ãã ã•ã„。信頼ã§ãるプラグインã ã‘インストールã—ã¦ãã ã•ã„。</translation>
-<translation id="4838490908464673667">å¿…è¦ãªãƒ—ラグインãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> プラグインãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
+<translation id="6765711848403622008">ã“ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®è¡¨ç¤ºã«ä½¿ç”¨ã§ãるプラグインã¯ã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="8597182159515967513">見出ã—</translation>
<translation id="2653659639078652383">é€ä¿¡</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> プラグインãŒå¿…è¦ã§ã™</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_kn.xtb b/webkit/glue/resources/webkit_strings_kn.xtb
index 1dacc42..61dbd2c 100644
--- a/webkit/glue/resources/webkit_strings_kn.xtb
+++ b/webkit/glue/resources/webkit_strings_kn.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="kn">
-<translation id="4420062214988137980">ಪà³à²²à²—à³à²‡à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³‡à²¶à²¨à³ ವಿಫಲವಾಗಿದೆ</translation>
+<translation id="4519964825805946997"><ph name="URL"/> ನಿಂದ ಪà³à²²à²—à³-ಇನೠಅನà³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à³à²µà²²à³à²²à²¿ ವಿಫಲವಾಗಿದೆ</translation>
<translation id="1235745349614807883">ಇತà³à²¤à³€à²šà²¿à²¨ ಹà³à²¡à³à²•à²¾à²Ÿà²µà²¨à³à²¨à³ ತೆರವà³à²—ೊಳಿಸಿ</translation>
-<translation id="3825324228893189080">ಹೆಚà³à²šà³à²µà²°à²¿ ಪà³à²²à²—à³à²‡à²¨à³â€Œà²—ಳ ಅವಶà³à²¯à²•à²¤à³†à²¯à²¿à²¦à³†</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> ಪà³à²²à²—à³à²‡à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಆಗಿಲà³à²²</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="4317653869502688143">ದಯವಿಟà³à²Ÿà³ <ph name="PLUGIN"/> ಪà³à²²à²—à³â€Œà²‡à²¨à³ ಅನà³à²¨à³ ನೀವೠಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಲೠಬಯಸà³à²¤à³à²¤à³€à²°à²¾ ಎಂದೠಖಚಿತಪಡಿಸಿ. ನೀವೠನಂಬಿರà³à²µ ಪà³à²²à²—à³â€Œà²‡à²¨à³à²¸à³ ಅನà³à²¨à³ ಮಾತà³à²° ನೀವೠಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಬೇಕà³.</translation>
<translation id="7658239707568436148">ರದà³à²¦à³à²®à²¾à²¡à³</translation>
<translation id="795667975304826397">ಯಾವà³à²¦à³‡ ಫೈಲೠಆಯà³à²•à³† ಮಾಡಿಲà³à²²</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> ಪà³à²²à²—à³à²‡à²¨à³ ಅವಶà³à²¯à²•à²¤à³†à²¯à²¿à²¦à³†</translation>
-<translation id="8662565117025751661">ಡೌನà³à²²à³‹à²¡à³ ಆಗà³à²¤à³à²¤à²¿à²°à³à²µ ಪà³à²²à²—ೠಇನà³...</translation>
+<translation id="1416462845279468967">ಪà³à²²à²—à³-ಇನೠಅಳವಡಿಸà³à²µà²¿à²•à³†à²¯à³ ವಿಫಲವಾಗಿದೆ</translation>
<translation id="8141602879876242471">ಇದೠಹà³à²¡à³à²•à²¾à²¡à²¬à²¹à³à²¦à²¾à²¦ ಸೂಚಿಕೆ ಹà³à²¡à³à²•à²¾à²Ÿ ಕೀವರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ನಮೂದಿಸಿ:</translation>
+<translation id="5650795167354946011">ಪà³à²²à²—à³-ಇನೠಸà³à²¥à²¾à²ªà²¨à³† ಮಾಡಿದ ನಂತರ, ರಿಫà³à²°à³†à²¶à³â€Œâ€Œ ಮಾಡಲೠಇಲà³à²²à²¿ ಕà³à²²à²¿à²•à³ ಮಾಡಿ</translation>
<translation id="6845533974506654842">ಒತà³à²¤à²¿</translation>
<translation id="8244226242650769279">ಇಮೇಜೠನಕà³à²·à³†</translation>
-<translation id="1383141426028388991"><ph name="URL"/> ನಿಂದ ಪà³à²²à²—à³à²‡à²¨à³ ಅನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಲೠವಿಫಲವಾಗಿದೆ</translation>
<translation id="2548326553472216322">ಇತà³à²¤à³€à²šà²¿à²¨ ಹà³à²¡à³à²•à²¾à²Ÿà²—ಳೠಇಲà³à²²</translation>
<translation id="5944544982112848342">2048 (ಉನà³à²¨à²¤ ಶà³à²°à³‡à²£à²¿)</translation>
<translation id="3040011195152428237">ಲಿಂಕà³</translation>
-<translation id="8281246460978372009">ಪà³à²²à²—à³à²‡à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಿದ ನಂತರ, ತಾಜಾಮಾಡಲೠಇಲà³à²²à²¿ ಕà³à²²à²¿à²•à³ ಮಾಡಿ</translation>
+<translation id="2745343197843472802">ಪà³à²²à²—à³-ಇನೠಪಡೆಯಿರಿ</translation>
+<translation id="5776402066334188252">ನೀವೠಪà³à²²à²—à³-ಇನೠಅನà³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³ ಬಯಸà³à²µà³à²¦à²¾à²¦à²²à³à²²à²¿ ದಯವಿಟà³à²Ÿà³ ಖಚಿತಪಡಿಸಿ. ನಿಮಗೆ ನಂಬಿಕೆ ಇರà³à²µ ಫà³à²²à²—à³-ಇನà³â€Œà²—ಳನà³à²¨à³ ಮಾತà³à²° ನೀವೠಸà³à²¥à²¾à²ªà²¿à²¸à²¬à³‡à²•à³.</translation>
+<translation id="4003986561708175844">ಅಗತà³à²¯à²µà²¿à²°à³à²µ ಪà³à²²à²—à³-ಇನೠಅನà³à²¨à³ ಅಳವಡಿಸಲಾಗಿಲà³à²²</translation>
+<translation id="3018094406922859308">ಪà³à²²à²—à³-ಇನೠಅನà³à²¨à³ ಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
<translation id="7364796246159120393">ಫೈಲೠಆಯà³à²•à³† ಮಾಡಿ</translation>
<translation id="8964020114565522021">ಇಲà³à²²à²¿ ಫೈಲೠಅನà³à²¨à³ ಎಳೆಯಿರಿ</translation>
<translation id="838869780401515933">ಪರಿಶೀಲಿಸà³</translation>
<translation id="2846343701378493991">1024 (ಮದà³à²¯à²® ಶà³à²°à³‡à²£à²¿)</translation>
<translation id="5476505524087279545">ಪರೀಕà³à²·à²¿à²¸à²¬à³‡à²¡à²¿</translation>
-<translation id="679352192834563463">ಈ ವಿಷಯವನà³à²¨à³ ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à²²à³ ಯಾವà³à²¦à³‡ ಪà³à²²à²—à³à²‡à²¨à³ ಲಭà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="3789841737615482174">ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³</translation>
+<translation id="5253117816378681419">ನೀವೠ<ph name="PLUGIN"/> ಪà³à²²à²—à³-ಇನೠಅನà³à²¨à³ ಅಳವಡಿಸಲೠಬಯಸà³à²µà³à²¦à²¾à²¦à²²à³à²²à²¿ ದಯವಿಟà³à²Ÿà³ ಖಚಿತಪಡಿಸಿ. ನೀವೠನಂಬà³à²µà²‚ತಹ ಫà³à²²à²—à³-ಇನà³â€Œà²—ಳನà³à²¨à³ ಮಾತà³à²° ನೀವೠಅಳವಡಿಸಬೇಕà³.</translation>
<translation id="6663448176199120256">ಇತà³à²¤à³€à²šà²¿à²¨ ಹà³à²¡à³à²•à²¾à²Ÿà²—ಳà³</translation>
-<translation id="3600343118165084788">ಪà³à²²à²—à³à²‡à²¨à³ ಅನà³à²¨à³ ಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಲೠಇಲà³à²²à²¿ ಕà³à²²à²¿à²•à³ ಮಾಡಿ</translation>
+<translation id="2597378329261239068">ಈ ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œ ಅನà³à²¨à³ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²¨à²¿à²‚ದ ರಕà³à²·à²¿à²¸à²²à²¾à²—ಿದೆ. ದಯವಿಟà³à²Ÿà³ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ನಮೂದಿಸಿ.</translation>
<translation id="6807599807928161586">ವೆಬೠಪà³à²°à²¦à³‡à²¶</translation>
<translation id="5939518447894949180">ಮರà³à²¹à³Šà²‚ದಿಸà³</translation>
-<translation id="3771786644471114952">ಪà³à²²à²—à³à²‡à²¨à³ ಪಡೆಯಿರಿ</translation>
<translation id="1842960171412779397">ಆಯà³à²•à³† ಮಾಡಿ</translation>
+<translation id="7638452146404718955">ಪà³à²²à²—à³-ಇನೠಅನà³à²¨à³ ಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಲೠಇಲà³à²²à²¿ ಕà³à²²à²¿à²•à³ ಮಾಡಿ</translation>
<translation id="6119846243427417423">ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸà³</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> ಫೈಲà³â€Œà²—ಳà³</translation>
-<translation id="3926627843712816530">ಈ ಪà³à²²à²—à³â€Œà²‡à²¨à³ ಅನà³à²¨à³ ನೀವೠಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³â€Œà²®à²¾à²¡à²²à³ ಬಯಸà³à²¤à³à²¤à³€à²°à²¾ ಎಂದೠದಯವಿಟà³à²Ÿà³ ಖಚಿತಪಡಿಸಿ. ನೀವೠನಂಬಿರà³à²µ ಪà³à²²à²—ಿನà³à²¸à³ ಅನà³à²¨à³ ಮಾತà³à²° ನೀವೠಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಬೇಕà³.</translation>
-<translation id="4838490908464673667">ಅವಶà³à²¯à²•à²µà²¾à²—ಿರà³à²µ ಪà³à²²à²—à³à²‡à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಆಗಿಲà³à²²</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> ನ ಪà³à²²à²—à³-ಇನೠಅನà³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à²¾à²—ಿಲà³à²²</translation>
+<translation id="6765711848403622008">ಈ ವಿಷಯವನà³à²¨à³ ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à²²à³ ಯಾವà³à²¦à³‡ ಪà³à²²à²—à³-ಇನೠಲಭà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="8597182159515967513">ಶೀರà³à²·à²¿à²•à³†</translation>
<translation id="2653659639078652383">ಸಲà³à²²à²¿à²¸à³</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> ಪà³à²²à²—à³-ಇನೠಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ko.xtb b/webkit/glue/resources/webkit_strings_ko.xtb
index c3b3e3e..819c8ce 100644
--- a/webkit/glue/resources/webkit_strings_ko.xtb
+++ b/webkit/glue/resources/webkit_strings_ko.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ko">
-<translation id="4420062214988137980">í”ŒëŸ¬ê·¸ì¸ ì„¤ì¹˜ 실패</translation>
+<translation id="4519964825805946997"><ph name="URL"/>ì˜ í”ŒëŸ¬ê·¸ì¸ ì„¤ì¹˜ 실패</translation>
<translation id="1235745349614807883">최근 검색 삭제</translation>
-<translation id="3825324228893189080">추가 í”ŒëŸ¬ê·¸ì¸ í•„ìš”</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> 플러그ì¸ì´ 설치ë˜ì§€ ì•ŠìŒ</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="4317653869502688143"><ph name="PLUGIN"/> 플러그ì¸ì„ 설치할 것ì¸ì§€ 확ì¸í•´ 주세요. 신뢰하는 플러그ì¸ë§Œ 설치해야 합니다.</translation>
<translation id="7658239707568436148">취소</translation>
<translation id="795667975304826397">ì„ íƒëœ íŒŒì¼ ì—†ìŒ</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> í”ŒëŸ¬ê·¸ì¸ í•„ìš”</translation>
-<translation id="8662565117025751661">í”ŒëŸ¬ê·¸ì¸ ë‹¤ìš´ë¡œë“œ 중...</translation>
+<translation id="1416462845279468967">í”ŒëŸ¬ê·¸ì¸ ì„¤ì¹˜ 실패</translation>
<translation id="8141602879876242471">ì´ê²ƒì€ 검색 색ì¸í•©ë‹ˆë‹¤. 검색 키워드 ìž…ë ¥:</translation>
+<translation id="5650795167354946011">í”ŒëŸ¬ê·¸ì¸ ì„¤ì¹˜ 후 여기를 í´ë¦­í•˜ì—¬ 새로고침</translation>
<translation id="6845533974506654842">누르기</translation>
<translation id="8244226242650769279">ì´ë¯¸ì§€ 지ë„</translation>
-<translation id="1383141426028388991"><ph name="URL"/>ì˜ í”ŒëŸ¬ê·¸ì¸ ì„¤ì¹˜ 실패</translation>
<translation id="2548326553472216322">최근 ìˆ˜í–‰ëœ ê²€ìƒ‰ ì—†ìŒ</translation>
<translation id="5944544982112848342">2048(ë†’ì€ ë“±ê¸‰)</translation>
<translation id="3040011195152428237">ë§í¬</translation>
-<translation id="8281246460978372009">í”ŒëŸ¬ê·¸ì¸ ì„¤ì¹˜ 후 여기를 í´ë¦­í•˜ì—¬ 새로고침</translation>
+<translation id="2745343197843472802">í”ŒëŸ¬ê·¸ì¸ ê°€ì ¸ì˜¤ê¸°</translation>
+<translation id="5776402066334188252">플러그ì¸ì„ 설치할지 여부를 확ì¸í•˜ì‹œê¸° ë°”ëžë‹ˆë‹¤. 신뢰할 수 있는 플러그ì¸ë§Œ 설치해야 합니다.</translation>
+<translation id="4003986561708175844">필수 플러그ì¸ì´ 설치ë˜ì§€ ì•ŠìŒ</translation>
+<translation id="3018094406922859308"> í”ŒëŸ¬ê·¸ì¸ ë‹¤ìš´ë¡œë“œ 중...</translation>
<translation id="7364796246159120393">íŒŒì¼ ì„ íƒ</translation>
<translation id="8964020114565522021">여기로 íŒŒì¼ ë“œëž˜ê·¸</translation>
<translation id="838869780401515933">ì„ íƒ</translation>
<translation id="2846343701378493991">1024(중간 등급)</translation>
<translation id="5476505524087279545">ì„ íƒì·¨ì†Œ</translation>
-<translation id="679352192834563463">ì´ ì½˜í…츠를 표시하는 ë° ì‚¬ìš©í•  í”ŒëŸ¬ê·¸ì¸ ì—†ìŒ</translation>
<translation id="3789841737615482174">설치</translation>
+<translation id="5253117816378681419"><ph name="PLUGIN"/> 플러그ì¸ì„ 설치할지 여부를 확ì¸í•˜ì‹œê¸° ë°”ëžë‹ˆë‹¤. 신뢰할 수 있는 플러그ì¸ë§Œ 설치해야 합니다.</translation>
<translation id="6663448176199120256">최근 ìˆ˜í–‰ëœ ê²€ìƒ‰</translation>
-<translation id="3600343118165084788">여기를 í´ë¦­í•˜ì—¬ 플러그ì¸ì„ 다운로드합니다.</translation>
+<translation id="2597378329261239068">문서가 비밀번호로 보호ë˜ê³  있습니다. 비밀번호를 입력하세요.</translation>
<translation id="6807599807928161586">웹 ì˜ì—­</translation>
<translation id="5939518447894949180">재설정</translation>
-<translation id="3771786644471114952">í”ŒëŸ¬ê·¸ì¸ ê°€ì ¸ì˜¤ê¸°</translation>
<translation id="1842960171412779397">ì„ íƒ</translation>
+<translation id="7638452146404718955">여기를 í´ë¦­í•˜ì—¬ í”ŒëŸ¬ê·¸ì¸ ë‹¤ìš´ë¡œë“œ</translation>
<translation id="6119846243427417423">활성화</translation>
<translation id="8444882422881193423">íŒŒì¼ <ph name="NUMBER_OF_FILES"/>ê°œ</translation>
-<translation id="3926627843712816530">해당 플러그ì¸ì„ 설치할 것ì¸ì§€ 확ì¸í•´ 주세요. 신뢰하는 플러그ì¸ë§Œ 설치해야 합니다.</translation>
-<translation id="4838490908464673667">필수 플러그ì¸ì´ 설치ë˜ì§€ ì•ŠìŒ</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> 플러그ì¸ì´ 설치ë˜ì§€ ì•ŠìŒ</translation>
+<translation id="6765711848403622008">ì´ ì½˜í…츠를 표시하는 ë° ì‚¬ìš©í•  í”ŒëŸ¬ê·¸ì¸ ì—†ìŒ</translation>
<translation id="8597182159515967513">항목</translation>
<translation id="2653659639078652383">제출</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> í”ŒëŸ¬ê·¸ì¸ í•„ìš”</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_lt.xtb b/webkit/glue/resources/webkit_strings_lt.xtb
index 9975381..8e8a7a7 100644
--- a/webkit/glue/resources/webkit_strings_lt.xtb
+++ b/webkit/glue/resources/webkit_strings_lt.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lt">
-<translation id="4420062214988137980">Papildinio įdiegti nepavyko</translation>
+<translation id="4519964825805946997">Nepavyko įdiegti papildinio iš <ph name="URL"/></translation>
<translation id="1235745349614807883">Išvalyti pastarąsias paieškas</translation>
-<translation id="3825324228893189080">Reikia papidomo papildinio</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> papildinys neįdiegtas</translation>
<translation id="5048533449481078685">sąrašo žymeklis</translation>
+<translation id="372362261556059955">Reikia papildomo papildinio</translation>
<translation id="4202807286478387388">peršokti</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Patvirtinkite, kad norite diegti <ph name="PLUGIN"/> papildinį. Diekite tik tuos papildinius, kuriais tikrai pasitikite.</translation>
<translation id="7658239707568436148">Atšaukti</translation>
<translation id="795667975304826397">Nepasirinktas joks failas</translation>
-<translation id="1275511093094545429">Reikia <ph name="PLUGIN"/> papildinio (-ių)</translation>
-<translation id="8662565117025751661">SiunÄiamas papildinys...</translation>
+<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="6845533974506654842">paspausti</translation>
<translation id="8244226242650769279">paveikslėlio žemėlapis</translation>
-<translation id="1383141426028388991">Nepavyko įdiegti papildinio iš <ph name="URL"/></translation>
<translation id="2548326553472216322">Pastaruoju metu paieškų nevykdyta</translation>
<translation id="5944544982112848342">2048 (Aukšto laipsnio)</translation>
<translation id="3040011195152428237">nuoroda</translation>
-<translation id="8281246460978372009">Ä®diegÄ™ papildinį paspauskite Äia, kad bÅ«tų perkrautas puslapis</translation>
+<translation id="2745343197843472802">Gauti papildinį</translation>
+<translation id="5776402066334188252">Patvirtinkite, kad norite įdiegti šį papildinį. Turėtumėte diegti tik tuos papildinius, kurie yra patikimi.</translation>
+<translation id="4003986561708175844">Neįdiegtas reikalingas papildinys</translation>
+<translation id="3018094406922859308">AtsisiunÄiamas papildinys...</translation>
<translation id="7364796246159120393">Pasirinkti failÄ…</translation>
<translation id="8964020114565522021">Vilkite failÄ… Äia</translation>
<translation id="838869780401515933">tikrinti</translation>
<translation id="2846343701378493991">1024 (vidutinio lygio)</translation>
<translation id="5476505524087279545">Nuimti žymėjimą</translation>
-<translation id="679352192834563463">NÄ—ra papildinio, galinÄio parodyti šį turinį</translation>
<translation id="3789841737615482174">Diegti</translation>
+<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="3600343118165084788">SpustelÄ—kite Äia, kad atsisiųstumÄ—te papildinį</translation>
+<translation id="2597378329261239068">Šis dokumentas apsaugotas slaptažodžiu. Įveskite slaptažodį.</translation>
<translation id="6807599807928161586">interneto sritis</translation>
<translation id="5939518447894949180">Nustatyti iš naujo</translation>
-<translation id="3771786644471114952">Siųsti papildinį</translation>
<translation id="1842960171412779397">pasirinkti</translation>
+<translation id="7638452146404718955">SpustelÄ—kite Äia, kad atsisiųstumÄ—te papildinį</translation>
<translation id="6119846243427417423">aktyvinti</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> failai (-ų)</translation>
-<translation id="3926627843712816530">Patvirtinkite, kad norite diegti šį papildinį. Diekite tik tuos papildinius, kuriais tikrai pasitikite.</translation>
-<translation id="4838490908464673667">Neįdiegtas reikalingas papildinys</translation>
+<translation id="4470547978413275879">„<ph name="PLUGIN"/>“ papildinys neįdiegtas</translation>
+<translation id="6765711848403622008">Nėra papildinio, kad būtų galima pateikti šį turinį</translation>
<translation id="8597182159515967513">antraštė</translation>
<translation id="2653659639078652383">Pateikti</translation>
+<translation id="8475551193147984329">Reikia „<ph name="PLUGIN"/>“ papildinio</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_lv.xtb b/webkit/glue/resources/webkit_strings_lv.xtb
index 6b7dfd5..c97eb32 100644
--- a/webkit/glue/resources/webkit_strings_lv.xtb
+++ b/webkit/glue/resources/webkit_strings_lv.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="lv">
-<translation id="4420062214988137980">Spraudņa iestatÄ«Å¡ana neizdevÄs</translation>
+<translation id="4519964825805946997">NeizdevÄs instalÄ“t spraudni no <ph name="URL"/></translation>
<translation id="1235745349614807883">Dzēst nesenos meklējumus</translation>
-<translation id="3825324228893189080">Nepieciešams papildus spraudnis</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> spraudnis nav iestatīts</translation>
<translation id="5048533449481078685">sarakstu marÄ·ieris</translation>
+<translation id="372362261556059955">Nepieciešams papildu spraudnis</translation>
<translation id="4202807286478387388">lekt</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Lūdzu, apstipriniet, ka vēlaties iestatīt <ph name="PLUGIN"/> spraudni. Jums vajadzētu iestatīt tikai tos spraudņus, kuriem uzticaties.</translation>
<translation id="7658239707568436148">Atcelt</translation>
<translation id="795667975304826397">Nav izvēlēts neviens fails</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> nepieciešams spraudnis</translation>
-<translation id="8662565117025751661">Spraudņu lejupielÄde...</translation>
+<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="6845533974506654842">nospiest</translation>
<translation id="8244226242650769279">attēlu karte</translation>
-<translation id="1383141426028388991">NeizdevÄs instalÄ“t spraudni no <ph name="URL"/></translation>
<translation id="2548326553472216322">Nav nesenu meklējumu</translation>
<translation id="5944544982112848342">2048 (Augsta Atzīme)</translation>
<translation id="3040011195152428237">saite</translation>
-<translation id="8281246460978372009">PÄ“c spraudņa iestatÄ«Å¡anas, nospiediet Å¡eit, lai atsvaidzinÄtu</translation>
+<translation id="2745343197843472802">LejupielÄdÄ“t spraudni</translation>
+<translation id="5776402066334188252">Lūdzu, apstipriniet, ka vēlaties instalēt šo spraudni. Ieteicams instalēt tikai tos spraudņus, kuriem uzticaties.</translation>
+<translation id="4003986561708175844">Nepieciešamais spraudnis nav instalēts</translation>
+<translation id="3018094406922859308">Notiek spraudņa lejupielÄde...</translation>
<translation id="7364796246159120393">Izvēlieties failu</translation>
<translation id="8964020114565522021">Ievelciet failu Å¡eit</translation>
<translation id="838869780401515933">prbaudt</translation>
<translation id="2846343701378493991">1024 (Vidēja Atzīme)</translation>
<translation id="5476505524087279545">neprbaudt</translation>
-<translation id="679352192834563463">Nav pieejamu spraudņu, lai attēlotu saturu</translation>
<translation id="3789841737615482174">Iestatīt</translation>
+<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="3600343118165084788">KlikÅ¡Ä·iniet Å¡eit, lai lejupielÄdÄ“tu spraudni</translation>
+<translation id="2597378329261239068">Å is dokuments ir aizsargÄts ar paroli. LÅ«dzu, ievadiet paroli.</translation>
<translation id="6807599807928161586">tīmekļa apgabals</translation>
<translation id="5939518447894949180">Atiestatīt</translation>
-<translation id="3771786644471114952">Iegūt spraudni</translation>
<translation id="1842960171412779397">Atlasiet</translation>
+<translation id="7638452146404718955">NoklikÅ¡Ä·iniet Å¡eit, lai lejupielÄdÄ“tu spraudni</translation>
<translation id="6119846243427417423">aktivizt</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> faili</translation>
-<translation id="3926627843712816530">Lūdzu, apstipriniet, ka vēlaties iestatīt šo spraudni. Jums vajadzētu iestatīt tikai tos spraudņus, kuriem uzticaties.</translation>
-<translation id="4838490908464673667">Nepieciešamais spraudnis nav iestatīts</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> spraudnis nav instalēts</translation>
+<translation id="6765711848403622008">Nav pieejams neviens spraudnis, kas var attēlot šo saturu</translation>
<translation id="8597182159515967513">Virsraksts</translation>
<translation id="2653659639078652383">Iesniegt</translation>
+<translation id="8475551193147984329">Nepieciešams <ph name="PLUGIN"/> spraudnis</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ml.xtb b/webkit/glue/resources/webkit_strings_ml.xtb
index d7db730..437330d 100644
--- a/webkit/glue/resources/webkit_strings_ml.xtb
+++ b/webkit/glue/resources/webkit_strings_ml.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ml">
-<translation id="4420062214988137980">à´ªàµà´²à´—à´¿à´¨àµâ€ ഇനàµâ€à´¸àµà´±àµà´±àµŠà´³àµ‡à´·à´¨àµâ€ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
+<translation id="4519964825805946997"><ph name="URL"/> à´Žà´¨àµà´¨à´¤à´¿à´²àµâ€â€Œ നിനàµà´¨àµà´³àµà´³ à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="1235745349614807883">à´…à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµ†à´¯àµà´³àµà´³ തിരയലàµà´•à´³àµâ€ മായàµà´•àµà´•àµà´•</translation>
-<translation id="3825324228893189080">കൂടàµà´¤à´²àµâ€ à´ªàµà´²à´—à´¿à´¨àµâ€ ആവശàµà´¯à´®à´¾à´£àµ</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> à´ªàµà´²à´—à´¿à´¨àµâ€ ഇനàµâ€à´¸àµà´±àµà´±àµ‹à´³àµâ€ ചെയàµà´¤à´¿à´²àµà´²</translation>
<translation id="5048533449481078685">പടàµà´Ÿà´¿à´• മാരàµâ€à´•àµà´•à´°àµâ€</translation>
+<translation id="372362261556059955">കൂടàµà´¤à´²àµâ€â€Œ à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ആവശàµà´¯à´®àµà´£àµà´Ÿàµâ€Œâ€Œ</translation>
<translation id="4202807286478387388">jump</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143"><ph name="PLUGIN"/> à´ªàµà´²à´—à´¿à´¨àµâ€ ഇനàµâ€à´¸àµà´±àµà´±à´¾à´³àµâ€ ചെയàµà´¯à´¾â€à´¨àµâ€ നിങàµà´™à´³àµâ€ താലàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµà´µàµ†à´¨àµà´¨àµ ദയവായി ഉറപàµà´ªàµà´µà´°àµà´¤àµà´¤àµà´•. നിങàµà´™à´³àµâ€à´•àµà´•àµ വിശàµà´µà´¾à´¸àµà´¯à´¤à´¯àµà´³àµà´³ à´ªàµà´²à´—à´¿à´¨àµà´•à´³àµâ€ മാâ€à´¤àµà´°à´‚ നിങàµà´™à´³àµâ€ ഇനàµâ€à´¸àµà´±àµà´±à´¾à´³àµâ€ ചെയàµà´¯àµà´•.</translation>
<translation id="7658239707568436148">റദàµà´¦à´¾à´•àµà´•àµà´•</translation>
<translation id="795667975304826397">ഒരൠഫയലàµà´‚ തിരഞàµà´žàµ†à´Ÿàµà´¤àµà´¤à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> à´ªàµà´²à´—à´¿à´¨àµâ€ ആവശàµà´¯à´®àµà´£àµà´Ÿàµ</translation>
-<translation id="8662565117025751661">à´ªàµà´²à´—ൠഇനàµâ€ ഡൌണàµâ€à´²àµ‹à´¡àµ ചെയàµà´¯àµà´•à´¯à´¾à´£àµ...</translation>
+<translation id="1416462845279468967">à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµ‡à´·à´¨àµâ€â€Œ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="8141602879876242471">ഇതൠതിരയാവàµà´¨àµà´¨ സൂചികയാണàµ. തിരയലàµâ€ കീവേഡàµà´•à´³àµâ€ നലàµâ€à´•àµà´•:</translation>
+<translation id="5650795167354946011">à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµà´šàµ†à´¯àµà´¤à´¤à´¿à´¨àµà´¶àµ‡à´·à´‚, à´ªàµà´¤àµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ ഇവിടെ à´•àµà´²à´¿à´•àµà´•àµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="6845533974506654842">അമരàµâ€à´¤àµà´¤àµà´•</translation>
<translation id="8244226242650769279">ഇമേജൠമാപàµà´ªàµ</translation>
-<translation id="1383141426028388991"><ph name="URL"/> à´²àµâ€ നിനàµà´¨àµ à´ªàµà´²à´—àµ-ഇനàµâ€ ഇനàµâ€à´¸àµà´±àµà´±àµ‹à´³àµâ€ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´²àµâ€ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="2548326553472216322">സമീപകാല തിരയലàµà´•à´³àµâ€ ഇലàµà´²</translation>
<translation id="5944544982112848342">2048 (High Grade)</translation>
<translation id="3040011195152428237">ലിങàµà´•àµ</translation>
-<translation id="8281246460978372009">à´ªàµà´²à´—à´¿à´¨àµâ€ ഇനàµâ€à´¸àµà´±àµà´±à´¾à´³àµâ€ ചെയàµà´¤à´¤à´¿à´¨àµ ശേഷം, à´ªàµà´¤àµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ ഇവിടെ à´•àµà´²à´¿à´•àµà´•àµà´šàµ†à´¯àµà´¯àµà´•</translation>
+<translation id="2745343197843472802">à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ നേടàµà´•</translation>
+<translation id="5776402066334188252">നിങàµà´™à´³àµâ€â€Œ à´ˆ à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµà´šàµ†à´¯àµà´¯à´¾à´¨àµâ€â€Œ താലàµâ€â€Œà´ªàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµà´µàµ†à´¨àµà´¨à´¤àµ ദയവായി à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´•. നിങàµà´™à´³àµâ€â€Œ വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨ à´ªàµà´²à´—àµ-ഇനàµà´•à´³àµâ€â€Œ മാതàµà´°à´®àµ‡ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµâ€â€Œ ചെയàµà´¯à´¾à´µàµ‚.</translation>
+<translation id="4003986561708175844">ആവശàµà´¯à´®à´¾à´¯ à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµà´šàµ†à´¯àµà´¤à´¿à´²àµà´²</translation>
+<translation id="3018094406922859308">à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഡൌണàµâ€â€Œà´²àµ‹à´¡àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨àµ...</translation>
<translation id="7364796246159120393">ഫയലàµâ€ തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµ‚</translation>
<translation id="8964020114565522021">ഇവിടെ ഫയലàµâ€ ഇഴയàµà´•àµà´•àµà´•</translation>
<translation id="838869780401515933">പരിശോധികàµà´•àµ‚</translation>
<translation id="2846343701378493991">1024 (മീഡിയം à´—àµà´°àµ‡à´¡àµ)</translation>
<translation id="5476505524087279545">à´…à´£àµâ€à´šàµ†à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
-<translation id="679352192834563463">à´ˆ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´°à´¦à´°àµâ€à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ ഒരൠപàµà´²à´—à´¿à´¨àµà´‚ ലഭàµà´¯à´®à´²àµà´²</translation>
<translation id="3789841737615482174">ഇനàµâ€à´¸àµà´±àµà´±àµ‹à´³àµâ€ ചെയàµà´¯àµà´•</translation>
+<translation id="5253117816378681419">നിങàµà´™à´³àµâ€â€Œ à´ˆ <ph name="PLUGIN"/> à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµà´šàµ†à´¯àµà´¯à´¾à´¨àµâ€â€Œ താലàµâ€â€Œà´ªàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµà´µàµ†à´¨àµà´¨à´¤àµ ദയവായി à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´•. നിങàµà´™à´³àµâ€â€Œ വിശàµà´µà´¸à´¿à´•àµà´•àµà´¨àµà´¨ à´ªàµà´²à´—àµ-ഇനàµà´•à´³àµâ€â€Œ മാതàµà´°à´®àµ‡ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµâ€â€Œ ചെയàµà´¯à´¾à´µàµ‚.</translation>
<translation id="6663448176199120256">സമീപകാല തിരയലàµà´•à´³àµâ€</translation>
-<translation id="3600343118165084788">à´ªàµà´²à´—àµ-ഇനàµâ€ ഡൌണàµâ€à´²àµ‹à´¡àµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´¨à´¾à´¯à´¿ ഇവിടെ à´•àµà´²à´¿à´•àµà´•àµà´šàµ†à´¯àµà´¯àµà´•</translation>
+<translation id="2597378329261239068">à´ˆ à´ªàµà´°à´®à´¾à´£à´‚ പാസàµâ€Œà´µàµ‡à´¡àµ പരിരകàµà´·à´¿à´¤à´®à´¾à´£àµ. ദയവായി ഒരൠപാസàµâ€Œà´µàµ‡à´¡àµ നലàµâ€â€Œà´•àµà´•.</translation>
<translation id="6807599807928161586">വെബൠമേഖല</translation>
<translation id="5939518447894949180">വീണàµà´Ÿàµà´‚ സജàµà´œàµ€à´•à´°à´¿à´•àµà´•àµà´•</translation>
-<translation id="3771786644471114952">à´ªàµà´²à´—à´¿à´¨àµâ€ നേടàµà´•</translation>
<translation id="1842960171412779397">തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµ‚</translation>
+<translation id="7638452146404718955">à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഡൌണàµâ€â€Œà´²àµ‹à´¡àµà´šàµ†à´¯àµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ ഇവിടെ à´•àµà´²à´¿à´•àµà´•àµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="6119846243427417423">ആകàµà´±àµà´±à´¿à´µàµ‡à´±àµà´±àµ ചെയàµà´¯àµà´•</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> ഫയലàµà´•à´³àµâ€</translation>
-<translation id="3926627843712816530">à´ªàµà´²à´—à´¿à´¨àµâ€ ഇനàµâ€à´¸àµà´±àµà´±àµ‹à´³àµâ€ ചെയàµà´¯à´¾â€à´¨àµâ€ നിങàµà´™à´³àµâ€ താലàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµà´µàµ†à´¨àµà´¨àµ ദയവായി ഉറപàµà´ªàµà´µà´°àµà´¤àµà´¤àµà´•. നിങàµà´™à´³àµâ€à´•àµà´•àµ വിശàµà´µà´¾à´¸àµà´¯à´¤à´¯àµà´³àµà´³ à´ªàµà´²à´—à´¿à´¨àµà´•à´³àµâ€ മാâ€à´¤àµà´°à´‚ നിങàµà´™à´³àµâ€ ഇനàµâ€à´¸àµà´±àµà´±àµ‹à´³àµâ€ ചെയàµà´¯àµà´•.</translation>
-<translation id="4838490908464673667">ആവശàµà´¯à´®à´¾à´¯ à´ªàµà´²à´—à´¿à´¨àµâ€ ഇനàµâ€à´¸àµà´±àµà´±à´¾à´³àµâ€ ചെയàµà´¤à´¿à´²àµà´²</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ഇനàµâ€â€Œà´¸àµà´±àµà´±à´¾à´³àµà´šàµ†à´¯àµà´¤à´¿à´²àµà´²</translation>
+<translation id="6765711848403622008">à´ˆ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´°à´¦à´°àµâ€â€Œà´¶à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´ªàµà´²à´—àµ-ഇനàµà´¨àµŠà´¨àµà´¨àµà´‚ ലഭàµà´¯à´®à´²àµà´²</translation>
<translation id="8597182159515967513">തലകàµà´•àµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="2653659639078652383">സമരàµâ€à´ªàµà´ªà´¿à´•àµà´•àµ‚</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> à´ªàµà´²à´—àµ-ഇനàµâ€â€Œ ആവശàµà´¯à´®àµà´£àµà´Ÿàµ</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_mr.xtb b/webkit/glue/resources/webkit_strings_mr.xtb
index fd6c4a4..3061c16 100644
--- a/webkit/glue/resources/webkit_strings_mr.xtb
+++ b/webkit/glue/resources/webkit_strings_mr.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="mr">
-<translation id="4420062214988137980">पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ अयशसà¥à¤µà¥€</translation>
+<translation id="4519964825805946997"><ph name="URL"/> वरून पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणे अयशसà¥à¤µà¥€</translation>
<translation id="1235745349614807883">अलीकडील शोध साफ करा</translation>
-<translation id="3825324228893189080">अतिरिकà¥à¤¤ पà¥à¤²à¤—इन आवशà¥à¤¯à¤•</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ नाही</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="4317653869502688143">कृपया आपण <ph name="PLUGIN"/> हे पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू इचà¥à¤›à¤¿à¤¤à¤¾ याची पà¥à¤·à¥à¤Ÿà¥€ करा. आपण केवळ आपलà¥à¤¯à¤¾à¤²à¤¾ विशà¥à¤µà¤¾à¤¸ असलेले पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ केले पाहिजेत.</translation>
<translation id="7658239707568436148">रदà¥à¤¦ करा</translation>
<translation id="795667975304826397">कोणतीही फाइल निवडलेली नाही</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> पà¥à¤²à¤—इन आवशà¥à¤¯à¤•</translation>
-<translation id="8662565117025751661">पà¥à¤²à¤—इन डाउनलोड करीत आहे...</translation>
+<translation id="1416462845279468967">पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ अयशसà¥à¤µà¥€</translation>
<translation id="8141602879876242471">ही शोध घेणà¥à¤¯à¤¾à¤¯à¥‹à¤—à¥à¤¯ अनà¥à¤•à¥à¤°à¤®à¤£à¤¿à¤•à¤¾ आहे. शोध कीवरà¥à¤¡ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा:</translation>
+<translation id="5650795167354946011">पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ केलà¥à¤¯à¤¾à¤¨à¤‚तर, रीफà¥à¤°à¥‡à¤¶ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ येथे कà¥à¤²à¤¿à¤• करा</translation>
<translation id="6845533974506654842">दाबा</translation>
<translation id="8244226242650769279">पà¥à¤°à¤¤à¤¿à¤®à¤¾ नकाशा</translation>
-<translation id="1383141426028388991"><ph name="URL"/> वरून पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤¤ अयशसà¥à¤µà¥€</translation>
<translation id="2548326553472216322">अलीकडील शोध नाहीत</translation>
<translation id="5944544982112848342">2048 (उचà¥à¤š गà¥à¤°à¥‡à¤¡)</translation>
<translation id="3040011195152428237">दà¥à¤µà¤¾</translation>
-<translation id="8281246460978372009">पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ केलà¥à¤¯à¤¾à¤¨à¤‚तर, रीफà¥à¤°à¥‡à¤¶ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ येथे कà¥à¤²à¤¿à¤• करा</translation>
+<translation id="2745343197843472802">पà¥à¤²à¤—-इन मिळवा</translation>
+<translation id="5776402066334188252">कृपया आपण हे पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸ इचà¥à¤›à¥à¤• असलà¥à¤¯à¤¾à¤šà¥€ पà¥à¤·à¥à¤Ÿà¥€ करा. आपण केवळ विशà¥à¤µà¤¾à¤¸à¤¾à¤°à¥à¤¹ असलेली पà¥à¤²à¤—-इनà¥à¤¸ फकà¥à¤¤ सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करावीत.</translation>
+<translation id="4003986561708175844">आवशà¥à¤¯à¤• असलेले पà¥à¤²à¤—-इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ नाही</translation>
+<translation id="3018094406922859308">पà¥à¤²à¤—-इन डाउनलोड करीत आहे...</translation>
<translation id="7364796246159120393">फाइल निवडा</translation>
<translation id="8964020114565522021">फाइल येथे डà¥à¤°à¥…ग करा</translation>
<translation id="838869780401515933">तपासा</translation>
<translation id="2846343701378493991">1024 (मधà¥à¤¯à¤® पà¥à¤°à¤¤)</translation>
<translation id="5476505524087279545">अनचेक</translation>
-<translation id="679352192834563463">ही सामगà¥à¤°à¥€ पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ कोणतेही पà¥à¤²à¤—इन उपलबà¥à¤§ नाही</translation>
<translation id="3789841737615482174">सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ करा</translation>
+<translation id="5253117816378681419">कृपया आपलà¥à¤¯à¤¾à¤²à¤¾ पà¥à¤²à¤—-इन <ph name="PLUGIN"/> सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणे आवडत असलà¥à¤¯à¤¾à¤šà¥€ पà¥à¤·à¥à¤Ÿà¥€ करा. आपण आपला विशà¥à¤µà¤¾à¤¸ असलेले पà¥à¤²à¤—-इनà¥à¤¸ फकà¥à¤¤ सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करावे. </translation>
<translation id="6663448176199120256">अलीकडील शोध</translation>
-<translation id="3600343118165084788">पà¥à¤²à¤—इन डाउनलोड करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ येथे कà¥à¤²à¤¿à¤• करा</translation>
+<translation id="2597378329261239068">हा दसà¥à¤¤à¤à¤µà¤œ संकेतशबà¥à¤¦ संरकà¥à¤·à¤¿à¤¤ आहे. कृपया संकेतशबà¥à¤¦ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ करा.</translation>
<translation id="6807599807928161586">वेब कà¥à¤·à¥‡à¤¤à¥à¤°</translation>
<translation id="5939518447894949180">रीसेट करा</translation>
-<translation id="3771786644471114952">पà¥à¤²à¤—इन मिळवा</translation>
<translation id="1842960171412779397">निवडा</translation>
+<translation id="7638452146404718955">पà¥à¤²à¤—-इन डाउनलोड करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ येथे कà¥à¤²à¤¿à¤• करा</translation>
<translation id="6119846243427417423">सकà¥à¤°à¤¿à¤¯ करा</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> फायली</translation>
-<translation id="3926627843712816530">कृपया आपण हे पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करू इचà¥à¤›à¤¿à¤¤à¤¾ याची पà¥à¤·à¥à¤Ÿà¥€ करा. आपण जà¥à¤¯à¤¾à¤‚चेवर विशà¥à¤µà¤¾à¤¸ करता केवळ असेच पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ करावेत.</translation>
-<translation id="4838490908464673667">आवशà¥à¤¯à¤• पà¥à¤²à¤—इन सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ नाही</translation>
+<translation id="4470547978413275879">पà¥à¤²à¤—-इन <ph name="PLUGIN"/> सà¥à¤¥à¤¾à¤ªà¤¿à¤¤ केले नाही</translation>
+<translation id="6765711848403622008">ही सामगà¥à¤°à¥€ पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ कोणतेही पà¥à¤²à¤—-इन उपलबà¥à¤§ नाही</translation>
<translation id="8597182159515967513">शीरà¥à¤·à¤²à¥‡à¤–</translation>
<translation id="2653659639078652383">सबमिट करा</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> पà¥à¤²à¤—-इन आवशà¥à¤¯à¤• ,,,</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_nl.xtb b/webkit/glue/resources/webkit_strings_nl.xtb
index c9cea68..df39241 100644
--- a/webkit/glue/resources/webkit_strings_nl.xtb
+++ b/webkit/glue/resources/webkit_strings_nl.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="nl">
-<translation id="4420062214988137980">Installatie van plug-in mislukt</translation>
+<translation id="4519964825805946997">Het installeren van de invoegtoepassing van <ph name="URL"/> is mislukt</translation>
<translation id="1235745349614807883">Recente zoekopdrachten wissen</translation>
-<translation id="3825324228893189080">Aanvullende plug-in vereist</translation>
-<translation id="2965480764085142436">De plug-in <ph name="PLUGIN"/> is niet geïnstalleerd</translation>
<translation id="5048533449481078685">lijstmarkering</translation>
+<translation id="372362261556059955">Aanvullende invoegtoepassing vereist</translation>
<translation id="4202807286478387388">Gaan naar</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Bevestig dat u de plugin <ph name="PLUGIN"/> wilt installeren. Installeer alleen plug-ins die u vertrouwt.</translation>
<translation id="7658239707568436148">Annuleren</translation>
<translation id="795667975304826397">Geen bestand gekozen</translation>
-<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> vereist</translation>
-<translation id="8662565117025751661">Plug-in downloaden...</translation>
+<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="6845533974506654842">Indrukken</translation>
<translation id="8244226242650769279">image map</translation>
-<translation id="1383141426028388991">Kan plug-in niet installeren van <ph name="URL"/></translation>
<translation id="2548326553472216322">Geen recente zoekopdrachten</translation>
<translation id="5944544982112848342">2048 (hoog niveau)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">Klik hier na het installeren van de plug-in om te vernieuwen</translation>
+<translation id="2745343197843472802">Invoegtoepassing downloaden</translation>
+<translation id="5776402066334188252">Bevestig dat u deze invoegtoepassing wilt installeren. U moet alleen invoegtoepassingen installeren die u vertrouwt.</translation>
+<translation id="4003986561708175844">De vereiste invoegtoepassing is niet geïnstalleerd</translation>
+<translation id="3018094406922859308">Invoegtoepassing downloaden...</translation>
<translation id="7364796246159120393">Bestand kiezen</translation>
<translation id="8964020114565522021">Sleep bestand hier naartoe</translation>
<translation id="838869780401515933">Selecteren</translation>
<translation id="2846343701378493991">1024 (gemiddeld niveau)</translation>
<translation id="5476505524087279545">Deselecteren</translation>
-<translation id="679352192834563463">Er is geen plug-in beschikbaar om deze inhoud weer te geven</translation>
<translation id="3789841737615482174">Installeren</translation>
+<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="3600343118165084788">Klik hier om de plug-in te downloaden</translation>
+<translation id="2597378329261239068">Dit document is beveiligd met een wachtwoord. Geef een wachtwoord op.</translation>
<translation id="6807599807928161586">webgedeelte</translation>
<translation id="5939518447894949180">Herstellen</translation>
-<translation id="3771786644471114952">Plug-in ophalen</translation>
<translation id="1842960171412779397">Selecteren</translation>
+<translation id="7638452146404718955">Klik hier om de invoegtoepassing te downloaden</translation>
<translation id="6119846243427417423">Activeren</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> bestanden</translation>
-<translation id="3926627843712816530">Bevestig dat u deze plug-in wilt installeren. Installeer alleen plug-ins die u vertrouwt.</translation>
-<translation id="4838490908464673667">De vereiste plug-in is niet geïnstalleerd</translation>
+<translation id="4470547978413275879">De invoegtoepassing <ph name="PLUGIN"/> is niet geïnstalleerd</translation>
+<translation id="6765711848403622008">Er is geen invoegtoepassing beschikbaar om deze inhoud weer te geven</translation>
<translation id="8597182159515967513">kop</translation>
<translation id="2653659639078652383">Verzenden</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/>-invoegtoepassing vereist</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_no.xtb b/webkit/glue/resources/webkit_strings_no.xtb
index f8f419a..c94ad8f 100644
--- a/webkit/glue/resources/webkit_strings_no.xtb
+++ b/webkit/glue/resources/webkit_strings_no.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="no">
-<translation id="4420062214988137980">Installasjon av programtillegg mislyktes</translation>
+<translation id="4519964825805946997">Kunne ikke installere programtillegget fra <ph name="URL"/></translation>
<translation id="1235745349614807883">Fjern nylige søk</translation>
-<translation id="3825324228893189080">Ytterligere programtillegg kreves</translation>
-<translation id="2965480764085142436">Programtillegget <ph name="PLUGIN"/> er ikke installert</translation>
<translation id="5048533449481078685">listemarkør</translation>
+<translation id="372362261556059955">Ekstra programtillegg kreves</translation>
<translation id="4202807286478387388">hopp</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Du må bekrefte om du vil installere programtillegget <ph name="PLUGIN"/>. Du bør bare installere programtillegg du stoler på.</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="795667975304826397">Ingen fil valgt</translation>
-<translation id="1275511093094545429">Programtillegget <ph name="PLUGIN"/> kreves</translation>
-<translation id="8662565117025751661">Laster ned programtillegg...</translation>
+<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="6845533974506654842">trykk</translation>
<translation id="8244226242650769279">bildekart</translation>
-<translation id="1383141426028388991">Kunne ikke installere programtillegget fra <ph name="URL"/></translation>
<translation id="2548326553472216322">Ingen nylige søk</translation>
<translation id="5944544982112848342">2048 (sterk)</translation>
<translation id="3040011195152428237">kobling</translation>
-<translation id="8281246460978372009">Når programtillegget er installert, klikker du her for å oppdatere</translation>
+<translation id="2745343197843472802">Finn programtillegg</translation>
+<translation id="5776402066334188252">Bekreft at du ønsker å installere programtillegget. Du bør kun installere programtillegg du stoler på.</translation>
+<translation id="4003986561708175844">Det nødvendige programmet er ikke installert</translation>
+<translation id="3018094406922859308">Laster ned programtillegg</translation>
<translation id="7364796246159120393">Velg fil</translation>
<translation id="8964020114565522021">Dra filen hit</translation>
<translation id="838869780401515933">merk av</translation>
<translation id="2846343701378493991">1024 (middels)</translation>
<translation id="5476505524087279545">fjern merke</translation>
-<translation id="679352192834563463">Intet programtillegg tilgjengelig for å vise dette innholdet</translation>
<translation id="3789841737615482174">Installer</translation>
+<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="3600343118165084788">Klikk her for å laste ned programtillegget</translation>
+<translation id="2597378329261239068">Dette dokumentet er passordbeskyttet. Skriv inn et passord.</translation>
<translation id="6807599807928161586">nettområde</translation>
<translation id="5939518447894949180">Tilbakestill</translation>
-<translation id="3771786644471114952">FÃ¥ programtillegg</translation>
<translation id="1842960171412779397">velg</translation>
+<translation id="7638452146404718955">Klikk her for å laste ned programtillegget</translation>
<translation id="6119846243427417423">aktiver</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> filer</translation>
-<translation id="3926627843712816530">Du må bekrefte om du vil installere programtillegget. Du bør bare installere programtillegg du stoler på.</translation>
-<translation id="4838490908464673667">Det nødvendige programtillegget er ikke installert</translation>
+<translation id="4470547978413275879">Programtillegget <ph name="PLUGIN"/> er ikke installert</translation>
+<translation id="6765711848403622008">Ingen programtillegg tilgjengelig for å vise dette innholdet</translation>
<translation id="8597182159515967513">overskrift</translation>
<translation id="2653659639078652383">Send</translation>
+<translation id="8475551193147984329">Programtillegg <ph name="PLUGIN"/> påkrevd</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_pl.xtb b/webkit/glue/resources/webkit_strings_pl.xtb
index c666eb9..ea4f6cf 100644
--- a/webkit/glue/resources/webkit_strings_pl.xtb
+++ b/webkit/glue/resources/webkit_strings_pl.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pl">
-<translation id="4420062214988137980">Instalacja dodatku plug-in nie powiodła się</translation>
+<translation id="4519964825805946997">Nie można zainstalować wtyczki dostępnej pod adresem <ph name="URL"/></translation>
<translation id="1235745349614807883">Wyczyść ostatnie wyszukiwania</translation>
-<translation id="3825324228893189080">Wymagany dodatkowy dodatek plug-in</translation>
-<translation id="2965480764085142436">Dodatek plug-in <ph name="PLUGIN"/> nie został zainstalowany</translation>
<translation id="5048533449481078685">znacznik listy</translation>
+<translation id="372362261556059955">Potrzebna jest dodatkowa wtyczka</translation>
<translation id="4202807286478387388">przejdź</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Potwierdź instalację dodatku plug-in <ph name="PLUGIN"/>. Należy instalować wyłącznie zaufane dodatki plug-in.</translation>
<translation id="7658239707568436148">Anuluj</translation>
<translation id="795667975304826397">Nie wybrano pliku</translation>
-<translation id="1275511093094545429">Wymagany dodatek plug-in <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Pobieranie dodatku plug-in...</translation>
+<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="6845533974506654842">naciśnij</translation>
<translation id="8244226242650769279">mapa grafiki</translation>
-<translation id="1383141426028388991">Nie można zainstalować wtyczki z adresu <ph name="URL"/></translation>
<translation id="2548326553472216322">Brak ostatnich wyszukiwań</translation>
<translation id="5944544982112848342">2048 (wysoki poziom)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">Po zainstalowaniu dodatku plug-in kliknij tutaj, aby odświeżyć</translation>
+<translation id="2745343197843472802">Pobierz wtyczkÄ™</translation>
+<translation id="5776402066334188252">Potwierdź zamiar zainstalowania tej wtyczki. Należy instalować wyłącznie zaufane wtyczki.</translation>
+<translation id="4003986561708175844">Wymagana wtyczka nie jest zainstalowana</translation>
+<translation id="3018094406922859308">Trwa pobieranie wtyczki...</translation>
<translation id="7364796246159120393">Wybierz plik</translation>
<translation id="8964020114565522021">PrzeciÄ…gnij plik tutaj</translation>
<translation id="838869780401515933">zaznacz</translation>
<translation id="2846343701378493991">1024 (średni poziom)</translation>
<translation id="5476505524087279545">odznacz</translation>
-<translation id="679352192834563463">Brak dostępnego dodatku plug-in umożliwiającego wyświetlenie tej treści</translation>
<translation id="3789841737615482174">Zainstaluj</translation>
+<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="3600343118165084788">Kliknij tutaj, aby pobrać dodatek plug-in</translation>
+<translation id="2597378329261239068">Ten dokument jest chroniony hasłem. Wprowadź hasło.</translation>
<translation id="6807599807928161586">obszar sieci</translation>
<translation id="5939518447894949180">Resetuj</translation>
-<translation id="3771786644471114952">Pobierz dodatek plug-in</translation>
<translation id="1842960171412779397">wybierz</translation>
+<translation id="7638452146404718955">Kliknij tutaj, aby pobrać wtyczkę</translation>
<translation id="6119846243427417423">aktywuj</translation>
<translation id="8444882422881193423">Liczba plików: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">Potwierdź instalację tego dodatku plug-in. Należy instalować wyłącznie zaufane dodatki plug-in.</translation>
-<translation id="4838490908464673667">Wymagany dodatek plug-in nie został zainstalowany</translation>
+<translation id="4470547978413275879">Wtyczka <ph name="PLUGIN"/> nie jest zainstalowana</translation>
+<translation id="6765711848403622008">Brak dostępnej wtyczki umożliwiającej wyświetlenie tej treści</translation>
<translation id="8597182159515967513">nagłówek</translation>
<translation id="2653659639078652383">Prześlij</translation>
+<translation id="8475551193147984329">Potrzebna jest wtyczka <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_pt-BR.xtb b/webkit/glue/resources/webkit_strings_pt-BR.xtb
index 5dfc2d3..b34c7cb 100644
--- a/webkit/glue/resources/webkit_strings_pt-BR.xtb
+++ b/webkit/glue/resources/webkit_strings_pt-BR.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-BR">
-<translation id="4420062214988137980">Falha de instalação de plug-in</translation>
+<translation id="4519964825805946997">Falha ao instalar o plug-in de <ph name="URL"/></translation>
<translation id="1235745349614807883">Limpar pesquisas recentes</translation>
-<translation id="3825324228893189080">Plug-in adicional necessário</translation>
-<translation id="2965480764085142436">O plug-in <ph name="PLUGIN"/> não está instalado</translation>
<translation id="5048533449481078685">marcador de lista</translation>
+<translation id="372362261556059955">Plug-in adicional necessário</translation>
<translation id="4202807286478387388">pular</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Confirme se deseja instalar este plug-in <ph name="PLUGIN"/>. Instale somente plug-ins confiáveis.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="795667975304826397">Nenhum arquivo selecionado</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> plug-in necessário</translation>
-<translation id="8662565117025751661">Fazendo download do plug-in...</translation>
+<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="6845533974506654842">pressione</translation>
<translation id="8244226242650769279">mapa de imagens</translation>
-<translation id="1383141426028388991">Falha ao instalar o plug-in de <ph name="URL"/></translation>
<translation id="2548326553472216322">Nenhuma pesquisa recente</translation>
<translation id="5944544982112848342">2048 (Nível alto)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">Depois de instalar o plug-in, clique aqui para atualizar</translation>
+<translation id="2745343197843472802">Obter plug-in</translation>
+<translation id="5776402066334188252">Confirme se você deseja instalar este plug-in. Você deve instalar apenas plug-ins em que confia.</translation>
+<translation id="4003986561708175844">O plug-in necessário não está instalado</translation>
+<translation id="3018094406922859308">Fazendo download do plug-in...</translation>
<translation id="7364796246159120393">Escolher arquivo</translation>
<translation id="8964020114565522021">Arraste o arquivo até aquil</translation>
<translation id="838869780401515933">marcar</translation>
<translation id="2846343701378493991">1024 (Nível médio)</translation>
<translation id="5476505524087279545">desmarcar</translation>
-<translation id="679352192834563463">Nenhum plug-in disponível para exibir este conteúdo</translation>
<translation id="3789841737615482174">Instalar</translation>
+<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="3600343118165084788">Clique aqui para fazer download do plug-in</translation>
+<translation id="2597378329261239068">Este documento está protegido por senha. Digite a senha.</translation>
<translation id="6807599807928161586">área da web</translation>
<translation id="5939518447894949180">Redefinir</translation>
-<translation id="3771786644471114952">Obter plug-in</translation>
<translation id="1842960171412779397">selecione</translation>
+<translation id="7638452146404718955">Clique aqui para fazer download do plug-in</translation>
<translation id="6119846243427417423">ativar</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> arquivos</translation>
-<translation id="3926627843712816530">Confirme se deseja instalar este plug-in. Instale somente plug-ins confiáveis.</translation>
-<translation id="4838490908464673667">O plug-in necessário não está instalado</translation>
+<translation id="4470547978413275879">O plug-in do <ph name="PLUGIN"/> não está instalado</translation>
+<translation id="6765711848403622008">Nenhum plug-in disponível para exibir este conteúdo</translation>
<translation id="8597182159515967513">cabeçalho</translation>
<translation id="2653659639078652383">Enviar</translation>
+<translation id="8475551193147984329">Plug-in do <ph name="PLUGIN"/> necessário</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_pt-PT.xtb b/webkit/glue/resources/webkit_strings_pt-PT.xtb
index 4b585e5..817cdf4 100644
--- a/webkit/glue/resources/webkit_strings_pt-PT.xtb
+++ b/webkit/glue/resources/webkit_strings_pt-PT.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="pt-PT">
-<translation id="4420062214988137980">A instalação do plug-in falhou</translation>
+<translation id="4519964825805946997">Falha ao instalar o plug-in de <ph name="URL"/></translation>
<translation id="1235745349614807883">Limpar pesquisas recentes</translation>
-<translation id="3825324228893189080">Plug-in adicional necessário</translation>
-<translation id="2965480764085142436">O plug-in <ph name="PLUGIN"/> não está instalado</translation>
<translation id="5048533449481078685">marcador de lista</translation>
+<translation id="372362261556059955">Plug-in adicional requerido</translation>
<translation id="4202807286478387388">ir para</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Confirme que pretende instalar o plug-in <ph name="PLUGIN"/>. Apenas deverá instalar plug-ins fidedignos.</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="795667975304826397">Nenhum ficheiro seleccionado</translation>
-<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> necessário</translation>
-<translation id="8662565117025751661">A transferir o plug-in…</translation>
+<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="6845533974506654842">premir</translation>
<translation id="8244226242650769279">mapa de imagem</translation>
-<translation id="1383141426028388991">Falha ao instalar plug-in de <ph name="URL"/></translation>
<translation id="2548326553472216322">Nenhuma pesquisa recente</translation>
<translation id="5944544982112848342">2048 (Tamanho grande)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">Após instalar o plug-in, clique aqui para actualizar</translation>
+<translation id="2745343197843472802">Obter plug-in</translation>
+<translation id="5776402066334188252">Confirme se pretende instalar este plug-in. Deve instalar apenas plug-ins fidedignos.</translation>
+<translation id="4003986561708175844">O plug-in necessário não está instalado</translation>
+<translation id="3018094406922859308">A transferir plug-in...</translation>
<translation id="7364796246159120393">Escolher ficheiro</translation>
<translation id="8964020114565522021">Arraste o ficheiro para aqui</translation>
<translation id="838869780401515933">verificar</translation>
<translation id="2846343701378493991">1024 (Tamanho médio)</translation>
<translation id="5476505524087279545">desmarcar</translation>
-<translation id="679352192834563463">Nenhum plug-in disponível para apresentar este conteúdo</translation>
<translation id="3789841737615482174">Instalar</translation>
+<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="3600343118165084788">Clique aqui para transferir o plug-in</translation>
+<translation id="2597378329261239068">Este documento está protegido por palavra-passe. Introduza uma palavra-passe.</translation>
<translation id="6807599807928161586">Ãrea Web</translation>
<translation id="5939518447894949180">Repor</translation>
-<translation id="3771786644471114952">Obter plug-in</translation>
<translation id="1842960171412779397">seleccionar</translation>
+<translation id="7638452146404718955">Clique aqui para transferir o plug-in</translation>
<translation id="6119846243427417423">activar</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> ficheiros</translation>
-<translation id="3926627843712816530">Confirme que pretende instalar este plug-in. Apenas deverá instalar plug-ins fidedignos.</translation>
-<translation id="4838490908464673667">O plug-in necessário não está instalado</translation>
+<translation id="4470547978413275879">O plug-in do <ph name="PLUGIN"/> não está instalado</translation>
+<translation id="6765711848403622008">Nenhum plug-in disponível para apresentar este conteúdo</translation>
<translation id="8597182159515967513">cabeçalho</translation>
<translation id="2653659639078652383">Submeter</translation>
+<translation id="8475551193147984329">Plug-in do <ph name="PLUGIN"/> necessário</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ro.xtb b/webkit/glue/resources/webkit_strings_ro.xtb
index 72c8f43..2f8ec55 100644
--- a/webkit/glue/resources/webkit_strings_ro.xtb
+++ b/webkit/glue/resources/webkit_strings_ro.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ro">
-<translation id="4420062214988137980">Instalarea plug-in-ului a eÅŸuat</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="3825324228893189080">Este necesar un plug-in suplimentar</translation>
-<translation id="2965480764085142436">Plug-in-ul <ph name="PLUGIN"/> nu este instalat</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="4317653869502688143">Confirmaţi că doriţi să instalaţi plug-in-ul <ph name="PLUGIN"/>. Ar trebui să instalaţi numai plug-in-uri în care aveţi încredere.</translation>
<translation id="7658239707568436148">Anulaţi</translation>
<translation id="795667975304826397">Nu s-au ales fiÅŸiere</translation>
-<translation id="1275511093094545429">Este necesar plug-in-ul <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Se descarcă plug-inul...</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="1383141426028388991">Instalarea plug-in-ului de la <ph name="URL"/> a eÅŸuat</translation>
<translation id="2548326553472216322">Nicio căutare recentă</translation>
<translation id="5944544982112848342">2048 (Grad înalt)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="8281246460978372009">După instalarea plug-in-ului, faceţi clic aici pentru a reactualiza</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="2846343701378493991">1024 (Grad mediu)</translation>
<translation id="5476505524087279545">Debifaţi</translation>
-<translation id="679352192834563463">Niciun plug-in disponibil pentru a afişa acest conţinut</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="3600343118165084788">Faceţi clic aici pentru a descărca plug-in-ul</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="3771786644471114952">Obţineţi plug-in-ul</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="3926627843712816530">Confirmaţi că doriţi să instalaţi acest plug-in. Ar trebui să instalaţi numai plug-in-uri în care aveţi încredere.</translation>
-<translation id="4838490908464673667">Plug-in-ul necesar nu este instalat</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="8597182159515967513">titlu</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 b9fe2f3..97e2796 100644
--- a/webkit/glue/resources/webkit_strings_ru.xtb
+++ b/webkit/glue/resources/webkit_strings_ru.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ru">
-<translation id="4420062214988137980">Ошибка при уÑтановке плагина</translation>
+<translation id="4519964825805946997">Ðе удалоÑÑŒ уÑтановить подключаемый модуль Ñ Ð°Ð´Ñ€ÐµÑа <ph name="URL"/></translation>
<translation id="1235745349614807883">ОчиÑтить недавние поиÑки</translation>
-<translation id="3825324228893189080">Ðеобходим дополнительный плагин</translation>
-<translation id="2965480764085142436">Плагин <ph name="PLUGIN"/> не уÑтановлен</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="4317653869502688143">Подтвердите, что хотите уÑтановить плагин <ph name="PLUGIN"/>. УÑтанавливать Ñледует модули только тех издателей, которым вы доверÑете.</translation>
<translation id="7658239707568436148">Отмена</translation>
<translation id="795667975304826397">Файл не выбран</translation>
-<translation id="1275511093094545429">Ðеобходим плагин <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Загрузка подключаемого модулÑ...</translation>
+<translation id="1416462845279468967">Ðе удалоÑÑŒ уÑтановить подключаемый модуль</translation>
<translation id="8141602879876242471">Это Ð¸Ð½Ð´ÐµÐºÑ Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñтью поиÑка. Введите ключевые Ñлова Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка:</translation>
+<translation id="5650795167354946011">ПоÑле уÑтановки подключаемого Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð½Ð°Ð¶Ð¼Ð¸Ñ‚Ðµ здеÑÑŒ, чтобы обновить Ñтраницу</translation>
<translation id="6845533974506654842">нажать</translation>
<translation id="8244226242650769279">графичеÑÐºÐ°Ñ ÐºÐ°Ñ€Ñ‚Ð°</translation>
-<translation id="1383141426028388991">Ðе удалоÑÑŒ уÑтановить подключаемый модуль Ñо Ñледующего адреÑа: <ph name="URL"/></translation>
<translation id="2548326553472216322">Ðет недавних поиÑков</translation>
<translation id="5944544982112848342">2048 (Крупный размер)</translation>
<translation id="3040011195152428237">ÑÑылка</translation>
-<translation id="8281246460978372009">ПоÑле уÑтановки подключаемого Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð½Ð°Ð¶Ð¼Ð¸Ñ‚Ðµ здеÑÑŒ Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ</translation>
+<translation id="2745343197843472802">Загрузить подключаемый модуль</translation>
+<translation id="5776402066334188252">Подтвердите, что вы хотите уÑтановить Ñтот подключаемый модуль. Ð’Ñ‹ доверÑете ему?</translation>
+<translation id="4003986561708175844">Ðе уÑтановлен необходимый подключаемый модуль</translation>
+<translation id="3018094406922859308">Загрузка подключаемого модулÑ...</translation>
<translation id="7364796246159120393">Выберите файл</translation>
<translation id="8964020114565522021">Перетащите файл Ñюда</translation>
<translation id="838869780401515933">поÑтавить галочку</translation>
<translation id="2846343701378493991">1024 (Средний размер)</translation>
<translation id="5476505524087279545">ÑнÑÑ‚ÑŒ галочку</translation>
-<translation id="679352192834563463">ÐедоÑтупен плагин Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñтого ÑодержаниÑ</translation>
<translation id="3789841737615482174">УÑтановить</translation>
+<translation id="5253117816378681419">Подтвердите, что вы хотите уÑтановить подключаемый модуль <ph name="PLUGIN"/>. Ð’Ñ‹ доверÑете ему?</translation>
<translation id="6663448176199120256">Ðедавние поиÑки</translation>
-<translation id="3600343118165084788">Ðажмите здеÑÑŒ, чтобы загрузить плагин</translation>
+<translation id="2597378329261239068">Документ защищен паролем. Введите пароль.</translation>
<translation id="6807599807928161586">облаÑÑ‚ÑŒ Интернетеа</translation>
<translation id="5939518447894949180">Изменить</translation>
-<translation id="3771786644471114952">Получить плагин</translation>
<translation id="1842960171412779397">выбрать</translation>
+<translation id="7638452146404718955">Ðажмите здеÑÑŒ, чтобы загрузить подключаемый модуль</translation>
<translation id="6119846243427417423">активировать</translation>
<translation id="8444882422881193423">ЧиÑло файлов: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">Подтвердите, что хотите уÑтановить Ñтот плагин. УÑтанавливать Ñледует модули только тех издателей, которым вы доверÑете.</translation>
-<translation id="4838490908464673667">Ðе уÑтановлен необходимый плагин.</translation>
+<translation id="4470547978413275879">Подключаемый модуль <ph name="PLUGIN"/> не уÑтановлен</translation>
+<translation id="6765711848403622008">ÐедоÑтупен подключаемый модуль Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñтого ÑодержаниÑ</translation>
<translation id="8597182159515967513">заголовок</translation>
<translation id="2653659639078652383">Отправить</translation>
+<translation id="8475551193147984329">Ðеобходим подключаемый модуль <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sk.xtb b/webkit/glue/resources/webkit_strings_sk.xtb
index 0804eff..71e68a9 100644
--- a/webkit/glue/resources/webkit_strings_sk.xtb
+++ b/webkit/glue/resources/webkit_strings_sk.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sk">
-<translation id="4420062214988137980">Nedal sa nainštalovať doplnkový modul</translation>
+<translation id="4519964825805946997">Inštalácia doplnku z adresy <ph name="URL"/> zlyhala</translation>
<translation id="1235745349614807883">VyÄistiÅ¥ posledné vyhľadávania</translation>
-<translation id="3825324228893189080">Vyžaduje sa Äalší doplnkový modul</translation>
-<translation id="2965480764085142436">Nie je nainštalovaný doplnkový modul <ph name="PLUGIN"/></translation>
<translation id="5048533449481078685">ukazovateľ v zozname</translation>
+<translation id="372362261556059955">Vyžaduje sa Äalší doplnok</translation>
<translation id="4202807286478387388">skok</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/> <ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">PotvrÄte, že naozaj chcete nainÅ¡talovaÅ¥ doplnkový modul <ph name="PLUGIN"/>. Mali by ste inÅ¡talovaÅ¥ len doplnkové moduly, ktorým dôverujete.</translation>
<translation id="7658239707568436148">Zrušiť</translation>
<translation id="795667975304826397">Nie je vybratý žiadny súbor</translation>
-<translation id="1275511093094545429">Vyžaduje sa doplnkový modul <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Preberá sa doplnkový modul...</translation>
+<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="6845533974506654842">stlaÄiÅ¥</translation>
<translation id="8244226242650769279">mapa obrázka</translation>
-<translation id="1383141426028388991">Nepodarilo sa nainštalovať doplnok z adresy <ph name="URL"/></translation>
<translation id="2548326553472216322">Žiadne posledné vyhľadávania</translation>
<translation id="5944544982112848342">2048 (vysoký stupeň)</translation>
<translation id="3040011195152428237">odkaz</translation>
-<translation id="8281246460978372009">Po inštalácii doplnkového modulu kliknite sem kvôli obnoveniu obsahu</translation>
+<translation id="2745343197843472802">Získať doplnok</translation>
+<translation id="5776402066334188252">PotvrÄte, že chcete nainÅ¡talovaÅ¥ tento doplnok. Mali by ste inÅ¡talovaÅ¥ len doplnky, ktorým dôverujete.</translation>
+<translation id="4003986561708175844">Vyžadovaný doplnok nie je nainštalovaný</translation>
+<translation id="3018094406922859308">Prebieha preberanie doplnku...</translation>
<translation id="7364796246159120393">Vybrať súbor</translation>
<translation id="8964020114565522021">Súbor presunúť sem</translation>
<translation id="838869780401515933">oznaÄiÅ¥</translation>
<translation id="2846343701378493991">1024 (stredný stupeň)</translation>
<translation id="5476505524087279545">zruÅ¡iÅ¥ oznaÄenie</translation>
-<translation id="679352192834563463">Na zobrazenie tohto obsahu nie je k dispozícii žiadny doplnkový modul</translation>
<translation id="3789841737615482174">Inštalovať</translation>
+<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="3600343118165084788">Kliknite sem, ak chcete prevziať doplnkový modul</translation>
+<translation id="2597378329261239068">Tento dokument je chránený heslom. Zadajte heslo.</translation>
<translation id="6807599807928161586">webová oblasť</translation>
<translation id="5939518447894949180">Vynulovať</translation>
-<translation id="3771786644471114952">Získať doplnkový modul</translation>
<translation id="1842960171412779397">vybrať</translation>
+<translation id="7638452146404718955">Kliknutím sem prevezmete doplnok</translation>
<translation id="6119846243427417423">aktivovať</translation>
<translation id="8444882422881193423">PoÄet súborov: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">PotvrÄte, že naozaj chcete nainÅ¡talovaÅ¥ tento doplnkový modul. Mali by ste inÅ¡talovaÅ¥ len doplnkové moduly, ktorým dôverujete.</translation>
-<translation id="4838490908464673667">Nie je nainštalovaný vyžadovaný doplnkový modul.</translation>
+<translation id="4470547978413275879">Nie je nainštalovaný doplnok <ph name="PLUGIN"/></translation>
+<translation id="6765711848403622008">Na zobrazenie tohto obsahu nie je k dispozícii žiadny doplnok</translation>
<translation id="8597182159515967513">nadpis</translation>
<translation id="2653659639078652383">Odoslať</translation>
+<translation id="8475551193147984329">Vyžaduje sa doplnok <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sl.xtb b/webkit/glue/resources/webkit_strings_sl.xtb
index 4108745..2ee1e5b 100644
--- a/webkit/glue/resources/webkit_strings_sl.xtb
+++ b/webkit/glue/resources/webkit_strings_sl.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sl">
-<translation id="4420062214988137980">Namestitev vtiÄnika ni bila uspeÅ¡na</translation>
+<translation id="4519964825805946997">Namestitev vtiÄnika z naslova <ph name="URL"/> ni bila uspeÅ¡na</translation>
<translation id="1235745349614807883">PoÄisti zadnja iskanja</translation>
-<translation id="3825324228893189080">Potreben je dodatni vtiÄnik</translation>
-<translation id="2965480764085142436">VtiÄnik <ph name="PLUGIN"/> ni nameÅ¡Äen</translation>
<translation id="5048533449481078685">oznaÄevalnik seznama</translation>
+<translation id="372362261556059955">Potreben je dodaten vtiÄnik</translation>
<translation id="4202807286478387388">skoÄi</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Prosimo potrdite, da želite namestiti vtiÄnik <ph name="PLUGIN"/>. PriporoÄamo vam, da namestite le vtiÄnike, ki so vredni zaupanja.</translation>
<translation id="7658239707568436148">PrekliÄi</translation>
<translation id="795667975304826397">Nobena datoteka ni izbrana</translation>
-<translation id="1275511093094545429">Potreben je vtiÄnik <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Prenos vtiÄnika ...</translation>
+<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="6845533974506654842">pritisni</translation>
<translation id="8244226242650769279">slikovni zemljevid</translation>
-<translation id="1383141426028388991">Namestitev vtiÄnika z naslova <ph name="URL"/> ni bila uspeÅ¡na</translation>
<translation id="2548326553472216322">Ni zadnjih iskanj</translation>
<translation id="5944544982112848342">2048 (visoka stopnja)</translation>
<translation id="3040011195152428237">povezava</translation>
-<translation id="8281246460978372009">Po namestitvi vtiÄnika za osvežitev kliknite tu</translation>
+<translation id="2745343197843472802">Prenesite vtiÄnik</translation>
+<translation id="5776402066334188252">Potrdite, da želite namestiti ta vtiÄnik. NameÅ¡Äajte le vtiÄnike, ki jim zaupate.</translation>
+<translation id="4003986561708175844">Zahtevani vtiÄnik ni nameÅ¡Äen</translation>
+<translation id="3018094406922859308">PrenaÅ¡anje vtiÄnika ...</translation>
<translation id="7364796246159120393">Izberi datoteko</translation>
<translation id="8964020114565522021">Datoteko povleci sem</translation>
<translation id="838869780401515933">potrdi</translation>
<translation id="2846343701378493991">1024 (srednja stopnja)</translation>
<translation id="5476505524087279545">poÄisti izbor</translation>
-<translation id="679352192834563463">Za prikaz te vsebine ni na voljo noben vtiÄnik</translation>
<translation id="3789841737615482174">Namesti</translation>
+<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="3600343118165084788">Za prenos vtiÄnika kliknite tukaj</translation>
+<translation id="2597378329261239068">Dokument je zaÅ¡Äiten z geslom. Vnesite geslo.</translation>
<translation id="6807599807928161586">spletno podroÄje</translation>
<translation id="5939518447894949180">Ponastavi</translation>
-<translation id="3771786644471114952">Dobite vtiÄnik</translation>
<translation id="1842960171412779397">izberi</translation>
+<translation id="7638452146404718955">ÄŒe želite prenesti vtiÄnik, kliknite tukaj</translation>
<translation id="6119846243427417423">aktiviraj</translation>
<translation id="8444882422881193423">Å tevilo datotek: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">Potrdite, da želite namestiti ta vtiÄnik. PriporoÄamo vam, da namestite le vtiÄnike, ki so vredni zaupanja.</translation>
-<translation id="4838490908464673667">Potrebni vtiÄnik ni nameÅ¡Äen</translation>
+<translation id="4470547978413275879">VtiÄnik <ph name="PLUGIN"/> ni nameÅ¡Äen</translation>
+<translation id="6765711848403622008">Za prikaz te vsebine ni na voljo noben vtiÄnik</translation>
<translation id="8597182159515967513">naslov</translation>
<translation id="2653659639078652383">Pošlji</translation>
+<translation id="8475551193147984329">Potreben je vtiÄnik <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sr.xtb b/webkit/glue/resources/webkit_strings_sr.xtb
index f4da790..a54c61b 100644
--- a/webkit/glue/resources/webkit_strings_sr.xtb
+++ b/webkit/glue/resources/webkit_strings_sr.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sr">
-<translation id="4420062214988137980">ИнÑталирање додатне компоненте није уÑпело</translation>
+<translation id="4519964825805946997">ИнÑталирање додатка Ñа адреÑе <ph name="URL"/> није уÑпело</translation>
<translation id="1235745349614807883">Обриши недавне претраге</translation>
-<translation id="3825324228893189080">Потребна је додатна компонента</translation>
-<translation id="2965480764085142436">Додатна компонента <ph name="PLUGIN"/> није инÑталирана</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="4317653869502688143">Потврдите да желите да инÑталирате додатну компоненту <ph name="PLUGIN"/>. Требало би да инÑталирате Ñамо додатне компоненте које Ñматрате поузданима.</translation>
<translation id="7658239707568436148">Откажи</translation>
-<translation id="795667975304826397">Ðије одабрана ниједна датотека</translation>
-<translation id="1275511093094545429">Потребна је додатна компонента <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Преузимање додатне компоненте...</translation>
+<translation id="795667975304826397">Ðије одабрана датотека</translation>
+<translation id="1416462845279468967">ИнÑталација додатка није уÑпела</translation>
<translation id="8141602879876242471">Ово је Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ñ˜Ð¸ може да Ñе претражује. УнеÑите кључне речи за претрагу:</translation>
+<translation id="5650795167354946011">Ðакон инÑталирања додатка, кликните овде да биÑте оÑвежили</translation>
<translation id="6845533974506654842">притиÑни</translation>
<translation id="8244226242650769279">мапа Ñлике</translation>
-<translation id="1383141426028388991">ÐеуÑпешно инÑталирање додатне компоненте Ñа <ph name="URL"/></translation>
<translation id="2548326553472216322">Ðема недавних претрага</translation>
<translation id="5944544982112848342">2048 (виÑоки Ñтепен)</translation>
<translation id="3040011195152428237">веза</translation>
-<translation id="8281246460978372009">Ðакон инÑталирања додатне компоненте, кликните овде да биÑте оÑвежили</translation>
-<translation id="7364796246159120393">Одаберите датотеку</translation>
+<translation id="2745343197843472802">Преузми додатак</translation>
+<translation id="5776402066334188252">Потврдите да желите да инÑталирате овај додатак. ИнÑталирајте Ñамо додатке у које имате поверења.</translation>
+<translation id="4003986561708175844">Потребан додатак није инÑталиран</translation>
+<translation id="3018094406922859308">Преузимање додатка...</translation>
+<translation id="7364796246159120393">Одабери датотеку</translation>
<translation id="8964020114565522021">Превуците датотеку овде</translation>
<translation id="838869780401515933">изабери</translation>
<translation id="2846343701378493991">1024 (Ñредњи Ñтепен)</translation>
<translation id="5476505524087279545">опозови избор</translation>
-<translation id="679352192834563463">Ðема доÑтупне додатне компоненте за приказивање овог Ñадржаја</translation>
<translation id="3789841737615482174">ИнÑталирај</translation>
+<translation id="5253117816378681419">Потврдите да желите да инÑталирате <ph name="PLUGIN"/> додатак. ИнÑталирајте Ñамо додатке у које имате поверења.</translation>
<translation id="6663448176199120256">Ðедавне претраге</translation>
-<translation id="3600343118165084788">Кликните овде да биÑте преузели додатну компоненту</translation>
+<translation id="2597378329261239068">Овај документ је заштићен лозинком. УнеÑите лозинку.</translation>
<translation id="6807599807928161586">веб облаÑÑ‚</translation>
<translation id="5939518447894949180">РеÑетуј</translation>
-<translation id="3771786644471114952">Ðабави додатну компоненту</translation>
<translation id="1842960171412779397">изабери</translation>
+<translation id="7638452146404718955">Кликните овде да биÑте преузели додатак</translation>
<translation id="6119846243427417423">активирај</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> датотеке(а)</translation>
-<translation id="3926627843712816530">Потврдите да желите да инÑталирате ову додатну компоненту. Требало би да инÑталирате Ñамо додатне компоненте које Ñматрате поузданима.</translation>
-<translation id="4838490908464673667">Потребна додатна компонента није инÑталирана</translation>
+<translation id="4470547978413275879">Додатак <ph name="PLUGIN"/> није инÑталиран</translation>
+<translation id="6765711848403622008">Ðиједан додатак није доÑтупан за приказивање овог Ñадржаја</translation>
<translation id="8597182159515967513">наÑлов</translation>
<translation id="2653659639078652383">Пошаљи</translation>
+<translation id="8475551193147984329">Потребан је <ph name="PLUGIN"/> додатак</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sv.xtb b/webkit/glue/resources/webkit_strings_sv.xtb
index 4b7323c..aa42d57 100644
--- a/webkit/glue/resources/webkit_strings_sv.xtb
+++ b/webkit/glue/resources/webkit_strings_sv.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sv">
-<translation id="4420062214988137980">Installationen av plugin-programmet misslyckades</translation>
+<translation id="4519964825805946997">Det gick inte att installera plugin-program från <ph name="URL"/></translation>
<translation id="1235745349614807883">Rensa senaste sökningar</translation>
-<translation id="3825324228893189080">Ytterligare plugin-program krävs</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/>-plugin-programmet har inte installerats</translation>
<translation id="5048533449481078685">listmarkör</translation>
+<translation id="372362261556059955">Ett ytterligare plugin-program krävs</translation>
<translation id="4202807286478387388">fortsätta</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Bekräfta att du vill installera <ph name="PLUGIN"/>-plugin-programmet. Installera bara tillförlitliga plugin-program.</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="795667975304826397">Ingen fil har valts</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/>-pluginprogram krävs</translation>
-<translation id="8662565117025751661">Laddar ned plugin-program...</translation>
+<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="6845533974506654842">tryck</translation>
<translation id="8244226242650769279">bildkarta</translation>
-<translation id="1383141426028388991">Det gick inte att installera plugin-program från <ph name="URL"/></translation>
<translation id="2548326553472216322">Inga nya sökningar</translation>
<translation id="5944544982112848342">2048 (hög)</translation>
<translation id="3040011195152428237">länk</translation>
-<translation id="8281246460978372009">Klicka här för att uppdatera när du har installerat plugin-programmet</translation>
+<translation id="2745343197843472802">Hämta plugin-program</translation>
+<translation id="5776402066334188252">Bekräfta att du vill installera detta plugin-program. Installera bara plugin-program från tillförlitliga källor.</translation>
+<translation id="4003986561708175844">Det begärda plugin-programmet har inte installerats</translation>
+<translation id="3018094406922859308">Hämtar plugin-programmet...</translation>
<translation id="7364796246159120393">Välj fil</translation>
<translation id="8964020114565522021">Dra filen hit</translation>
<translation id="838869780401515933">kryssa för</translation>
<translation id="2846343701378493991">1024 (medel)</translation>
<translation id="5476505524087279545">kryssa av</translation>
-<translation id="679352192834563463">Det finns inget plugin-program för att visa det här innehållet</translation>
<translation id="3789841737615482174">Installera</translation>
+<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="3600343118165084788">Klicka här för att ladda ned plugin-program</translation>
+<translation id="2597378329261239068">Dokumentet är lösenordsskyddat. Ange ett lösenord.</translation>
<translation id="6807599807928161586">webbområde</translation>
<translation id="5939518447894949180">Återställ</translation>
-<translation id="3771786644471114952">Hämta plugin-program</translation>
<translation id="1842960171412779397">välj</translation>
+<translation id="7638452146404718955">Klicka här för att hämta plugin-programmet</translation>
<translation id="6119846243427417423">aktivera</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> filer</translation>
-<translation id="3926627843712816530">Bekräfta att du vill installera det här plugin-programmet. Installera bara tillförlitliga plugin-program.</translation>
-<translation id="4838490908464673667">De begärda plugin-programmen har inte installerats</translation>
+<translation id="4470547978413275879">Plugin-programmet <ph name="PLUGIN"/> har inte installerats</translation>
+<translation id="6765711848403622008">Det finns inget plugin-program för att visa det här innehållet</translation>
<translation id="8597182159515967513">rubrik</translation>
<translation id="2653659639078652383">Skicka</translation>
+<translation id="8475551193147984329">Plugin-programmet <ph name="PLUGIN"/> krävs</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sw.xtb b/webkit/glue/resources/webkit_strings_sw.xtb
index 9d798d8..e507aa6 100644
--- a/webkit/glue/resources/webkit_strings_sw.xtb
+++ b/webkit/glue/resources/webkit_strings_sw.xtb
@@ -1,43 +1,30 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="sw">
-<translation id="4420062214988137980">Usanidi wa programu-jalizi haukufaulu</translation>
<translation id="1235745349614807883">Futa Utafutaji wa Hivi Karibuni</translation>
-<translation id="3825324228893189080">Programu-jalizi inahitajika</translation>
-<translation id="2965480764085142436">Programu-jalizi <ph name="PLUGIN"/> haijasanidiwa</translation>
<translation id="5048533449481078685">kialamishi orodha</translation>
<translation id="4202807286478387388">ruka</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Tafadali thibitisha kuwa ungependa kusanidi programu-jalizi <ph name="PLUGIN"/>. Unastahili kusanidi progrmau-jalizi unazoamini pekee.</translation>
<translation id="7658239707568436148">Ghairi</translation>
-<translation id="795667975304826397">Hakuna faili iliyochaguliwa</translation>
-<translation id="1275511093094545429">Programu-jalizi <ph name="PLUGIN"/> inahitajika</translation>
-<translation id="8662565117025751661">Programu-jalizi inapakuliwa</translation>
+<translation id="795667975304826397">Hakuna faili lililochaguliwa</translation>
<translation id="8141602879876242471">Hii ni fahirisi inayoweza kutafutwa. Weka maneno muhimu ya utafutaji.</translation>
<translation id="6845533974506654842">bofya</translation>
<translation id="8244226242650769279">ramani ya picha</translation>
-<translation id="1383141426028388991">Imeshindwa kusanidi programu-jalizi kutoka <ph name="URL"/></translation>
<translation id="2548326553472216322">Hakuna utafutaji wa hivi karibuni</translation>
<translation id="5944544982112848342">2048 (Gredi ya Juu)</translation>
<translation id="3040011195152428237">kiungo</translation>
-<translation id="8281246460978372009">Baada ya kusakinisha programu-jalizi, bonyeza hapa kuonyesha upya</translation>
<translation id="7364796246159120393">Chagua Faili</translation>
<translation id="8964020114565522021">Vuta faili hapa</translation>
<translation id="838869780401515933">chunguza</translation>
<translation id="2846343701378493991">1024 (Gredi Wastani)</translation>
<translation id="5476505524087279545">toa tiki</translation>
-<translation id="679352192834563463">Hakuna programu-jalizi ya kuonyesha maudhui haya</translation>
-<translation id="3789841737615482174">Sanidi</translation>
+<translation id="3789841737615482174">Sakinisha</translation>
<translation id="6663448176199120256">Utafutaji wa hivi karibuni</translation>
-<translation id="3600343118165084788">Bofya hapa kupakua programu-jalizi</translation>
<translation id="6807599807928161586">eneo wavuti</translation>
<translation id="5939518447894949180">Weka upya</translation>
-<translation id="3771786644471114952">Pata programu-jalizi</translation>
<translation id="1842960171412779397">chagua</translation>
<translation id="6119846243427417423">wezesha</translation>
<translation id="8444882422881193423">faili <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">Tafadali thibitisha kuwa ungependa kusanidi programu-jalizi hii. Unastahili kusanidi progrmau-jalizi unazoamini pekee.</translation>
-<translation id="4838490908464673667">Programu-jalizi inayohitajika haijasanidiwa</translation>
<translation id="8597182159515967513">kichwa</translation>
<translation id="2653659639078652383">Wasilisha</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ta.xtb b/webkit/glue/resources/webkit_strings_ta.xtb
index 3b19b4c..47d8547 100644
--- a/webkit/glue/resources/webkit_strings_ta.xtb
+++ b/webkit/glue/resources/webkit_strings_ta.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ta">
-<translation id="4420062214988137980">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ நிறà¯à®µà®²à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯</translation>
+<translation id="4519964825805946997"><ph name="URL"/> இலிரà¯à®¨à¯à®¤à¯ செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µà¯à®¤à®²à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯</translation>
<translation id="1235745349614807883">சமீபதà¯à®¤à®¿à®¯ தேடலà¯à®•à®³à¯ˆ சà¯à®¤à¯à®¤à®®à®¾à®•à¯à®•à¯</translation>
-<translation id="3825324228893189080">கூடà¯à®¤à®²à¯ செரà¯à®•à¯à®¨à®¿à®°à®²à¯ தேவைபà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> செரà¯à®•à¯à®¨à®¿à®°à®²à¯ நிறà¯à®µà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</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="4317653869502688143"><ph name="PLUGIN"/> செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µ விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯ எனà¯à®ªà®¤à¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•. நீஙà¯à®•à®³à¯ நமà¯à®ªà¯à®®à¯ செரà¯à®•à¯à®¨à®¿à®°à®²à¯à®•à®³à¯ˆ மடà¯à®Ÿà¯à®®à¯‡ நிறà¯à®µ வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="7658239707568436148">ரதà¯à®¤à¯à®šà¯†à®¯à¯</translation>
<translation id="795667975304826397">எநà¯à®¤ கோபà¯à®ªà¯à®®à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®ªà¯à®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> செரà¯à®•à¯à®¨à®¿à®°à®²à¯ தேவைபà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
-<translation id="8662565117025751661">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆà®ªà¯ பதிவிறகà¯à®•à¯à®•à®¿à®±à®¤à¯...</translation>
+<translation id="1416462845279468967">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µà¯à®¤à®²à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯</translation>
<translation id="8141602879876242471">இத௠தேடகà¯à®•à¯‚டிய பொரà¯à®³à®Ÿà®•à¯à®•à®®à¯. தேடல௠சொறà¯à®•à®³à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®•:</translation>
+<translation id="5650795167354946011">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µà®¿à®¯ பினà¯à®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®• இஙà¯à®•à¯ கிளிகà¯à®šà¯†à®¯à¯à®•</translation>
<translation id="6845533974506654842">à®…à®´à¯à®¤à¯à®¤à¯à®•</translation>
<translation id="8244226242650769279">பட மேபà¯</translation>
-<translation id="1383141426028388991"><ph name="URL"/> இலிரà¯à®¨à¯à®¤à¯ செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µà¯à®µà®¤à®¿à®²à¯ தோலà¯à®µà®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯</translation>
<translation id="2548326553472216322">சமீபதà¯à®¤à®¿à®¯ தேடலà¯à®•à®³à¯ எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
<translation id="5944544982112848342">2048 (உயர௠தரமà¯)</translation>
<translation id="3040011195152428237">இணைபà¯à®ªà¯</translation>
-<translation id="8281246460978372009">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µà®¿à®¯ பினà¯, பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®• இஙà¯à®•à¯ கிளிக௠செயà¯à®•</translation>
+<translation id="2745343197843472802">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆà®ªà¯ பெறà¯</translation>
+<translation id="5776402066334188252">இநà¯à®¤ செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நீஙà¯à®•à®³à¯ நிறà¯à®µ விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯ எனà¯à®ªà®¤à¯ˆ தயவà¯à®šà¯†à®¯à¯à®¤à¯ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®•. நீஙà¯à®•à®³à¯ நமà¯à®ªà¯à®®à¯ செரà¯à®•à¯à®¨à®¿à®°à®²à¯à®•à®³à¯ˆ மடà¯à®Ÿà¯à®®à¯ நீஙà¯à®•à®³à¯ நிறà¯à®µ வேணà¯à®Ÿà¯à®®à¯.</translation>
+<translation id="4003986561708175844">தேவையான செரà¯à®•à¯à®¨à®¿à®°à®²à¯ நிறà¯à®µà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
+<translation id="3018094406922859308">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆà®ªà¯ பதிவிறகà¯à®•à¯à®•à®¿à®±à®¤à¯...</translation>
<translation id="7364796246159120393">கோபà¯à®ªà¯ˆà®¤à¯ தேரà¯à®µà¯ செயà¯à®•</translation>
<translation id="8964020114565522021">கோபà¯à®ªà¯ˆ இஙà¯à®•à¯‡ இழà¯à®¤à¯à®¤à¯ வரà¯à®•</translation>
<translation id="838869780401515933">சரிபாரà¯</translation>
<translation id="2846343701378493991">1024 (இடைநிலைத௠தரமà¯)</translation>
<translation id="5476505524087279545">தேரà¯à®µà¯ நீகà¯à®•à¯</translation>
-<translation id="679352192834563463">இநà¯à®¤ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காணà¯à®ªà®¿à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®© செரà¯à®•à¯à®¨à®¿à®°à®²à¯ கிடைகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="3789841737615482174">நிறà¯à®µà¯</translation>
+<translation id="5253117816378681419"><ph name="PLUGIN"/> செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µ நீஙà¯à®•à®³à¯ விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯ எனà¯à®ªà®¤à¯ˆ தயவà¯à®šà¯†à®¯à¯à®¤à¯ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®•. நீஙà¯à®•à®³à¯ நமà¯à®ªà¯à®®à¯ செரà¯à®•à¯à®¨à®¿à®°à®²à¯à®•à®³à¯ˆ மடà¯à®Ÿà¯à®®à¯ நிறà¯à®µ வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="6663448176199120256">சமீபதà¯à®¤à®¿à®¯ தேடலà¯à®•à®³à¯</translation>
-<translation id="3600343118165084788">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆà®ªà¯ பதிவிறகà¯à®• இஙà¯à®•à¯‡ கிளிக௠செயà¯à®•</translation>
+<translation id="2597378329261239068">இநà¯à®¤ ஆவணம௠கடவà¯à®šà¯à®šà¯Šà®²à¯ பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ ஒனà¯à®±à¯. தயவà¯à®šà¯†à®¯à¯à®¤à¯ ஒர௠கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®•.</translation>
<translation id="6807599807928161586">வலைப௠பகà¯à®¤à®¿</translation>
<translation id="5939518447894949180">மீடà¯à®Ÿà®®à¯ˆ</translation>
-<translation id="3771786644471114952">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆà®ªà¯ பெறà¯à®•</translation>
<translation id="1842960171412779397">தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯</translation>
+<translation id="7638452146404718955">செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆà®ªà¯ பதிவிறகà¯à®• இஙà¯à®•à¯‡ கிளிக௠செயà¯à®•</translation>
<translation id="6119846243427417423">செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> கோபà¯à®ªà¯à®•à®³à¯</translation>
-<translation id="3926627843712816530">இநà¯à®¤ செரà¯à®•à¯à®¨à®¿à®°à®²à¯ˆ நிறà¯à®µ விரà¯à®®à¯à®ªà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯ எனà¯à®ªà®¤à¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•. நீஙà¯à®•à®³à¯ நமà¯à®ªà¯à®®à¯ செரà¯à®•à¯à®¨à®¿à®°à®²à¯à®•à®³à¯ˆ மடà¯à®Ÿà¯à®®à¯‡ நிறà¯à®µ வேணà¯à®Ÿà¯à®®à¯.</translation>
-<translation id="4838490908464673667">தேவையான செரà¯à®•à¯à®¨à®¿à®°à®²à¯ நிறà¯à®µà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> செரà¯à®•à¯à®¨à®¿à®°à®²à¯ நிறà¯à®µà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
+<translation id="6765711848403622008">இநà¯à®¤ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காணà¯à®ªà®¿à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®© செரà¯à®•à¯à®¨à®¿à®°à®²à¯ கிடைகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="8597182159515967513">தலைபà¯à®ªà¯</translation>
<translation id="2653659639078652383">சமரà¯à®ªà¯à®ªà®¿</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> செரà¯à®•à¯à®¨à®¿à®°à®²à¯ தேவை</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_te.xtb b/webkit/glue/resources/webkit_strings_te.xtb
index 37e3265..3c1e875 100644
--- a/webkit/glue/resources/webkit_strings_te.xtb
+++ b/webkit/glue/resources/webkit_strings_te.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="te">
-<translation id="4420062214988137980">à°ªà±à°²à°—ౠఇనౠఇనà±â€Œà°¸à±à°Ÿà°¾à°²à±‡à°·à°¨à± విఫలమయà±à°¯à°¿à°‚ది</translation>
+<translation id="4519964825805946997"><ph name="URL"/> à°¨à±à°‚à°¡à°¿ à°ªà±à°²à°—à±-ఇనà±â€Œà°¨à± à°µà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚చడానికి విఫలమైంది</translation>
<translation id="1235745349614807883">ఇటీవల శోధనలనౠకà±à°²à°¿à°¯à°°à± చెయà±à°¯à°¿</translation>
-<translation id="3825324228893189080">అదనపౠపà±à°²à°—à±â€Œà°‡à°¨à± అవసరం</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> à°ªà±à°²à°—à±â€Œà°‡à°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± à°…à°µà±à°µà°²à±‡à°¦à±</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="4317653869502688143">దయచేసి <ph name="PLUGIN"/> à°ªà±à°²à°—à±â€Œà°‡à°¨à±â€Œà°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చెయà±à°¯à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à°Ÿà±à°²à± నిరà±à°§à°¾à°°à°¿à°‚à°šà°‚à°¡à°¿. మీరౠనమà±à°®à±‡ à°ªà±à°²à°—à±â€Œà°‡à°¨à±â€Œà°²à°¨à± మాతà±à°°à°®à±‡ మీరౠఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చెయà±à°¯à°¾à°²à°¿.</translation>
<translation id="7658239707568436148">à°°à°¦à±à°¦à± చెయà±à°¯à°¿</translation>
<translation id="795667975304826397">ఫైలౠà°à°¦à±€ à°Žà°‚à°šà±à°•à±‹à°²à±‡à°¦à±</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> à°ªà±à°²à°—à±â€Œà°‡à°¨à± అవసరం</translation>
-<translation id="8662565117025751661">à°ªà±à°²à°—à°¿à°¨à±â€Œà°¨à± డౌనà±â€Œà°²à±‹à°¡à± చేసà±à°¤à±‹à°‚ది...</translation>
+<translation id="1416462845279468967">à°ªà±à°²à°—à±-ఇనౠవà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¨ విఫలమైంది</translation>
<translation id="8141602879876242471">ఇది à°’à°• శోధించగల సూచిక. శోధన కీవరà±à°¡à±â€Œà°²à°¨à± ఎంటరౠచెయà±à°¯à°‚à°¡à°¿:</translation>
+<translation id="5650795167354946011">à°ªà±à°²à°—à±-ఇనà±â€Œà°¨à± à°µà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚à°šà°¿à°¨ తరà±à°µà°¾à°¤, à°°à°¿à°«à±à°°à±†à°·à± చెయà±à°¯à°¡à°¾à°¨à°¿à°•à°¿ ఇకà±à°•à°¡ à°•à±à°²à°¿à°•à± చెయà±à°¯à°‚à°¡à°¿.</translation>
<translation id="6845533974506654842">నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="8244226242650769279">à°šà°¿à°¤à±à°°à°‚ మాపà±</translation>
-<translation id="1383141426028388991"><ph name="URL"/> à°¨à±à°‚à°¡à°¿ à°ªà±à°²à°—à±â€Œà°‡à°¨à±â€Œà°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చెయà±à°¯à°¡à°‚లో విఫలమైంది</translation>
<translation id="2548326553472216322">ఇటీవల శోధనలౠలేవà±</translation>
<translation id="5944544982112848342">2048 (ఉతà±à°¤à°® à°—à±à°°à±‡à°¡à±)</translation>
<translation id="3040011195152428237">లింకà±</translation>
-<translation id="8281246460978372009">à°ªà±à°²à°—à±â€Œà°‡à°¨à±â€Œâ€Œà°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేసిన తరà±à°µà°¾à°¤, à°°à°¿à°«à±à°°à±†à°·à± చెయà±à°¯à°¡à°¾à°¨à°¿à°•à°¿ ఇకà±à°•à°¡ à°•à±à°²à°¿à°•à± చెయà±à°¯à°‚à°¡à°¿.</translation>
+<translation id="2745343197843472802">à°ªà±à°²à°—à±-ఇనà±â€Œà°¨à± పొందండి</translation>
+<translation id="5776402066334188252">దయచేసి మీరౠఈ à°ªà±à°²à°—à±-ఇనà±â€Œà°¨à± à°µà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚చాలని à°…à°¨à±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°Ÿà±à°²à± నిరà±à°§à°¾à°°à°¿à°‚à°šà°‚à°¡à°¿. మీరౠనమà±à°®à±‡à°Ÿà°Ÿà±à°µà°‚à°Ÿà°¿ à°ªà±à°²à°—à±-ఇనà±â€Œà°²à°¨à± మాతà±à°°à°®à±‡ మీరౠవà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚చాలి.</translation>
+<translation id="4003986561708175844">అవసరమైన à°ªà±à°²à°—à±-ఇనౠవà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚చబడలేదà±</translation>
+<translation id="3018094406922859308">à°ªà±à°²à°—à±-ఇనà±â€Œà°¨à± డౌనà±â€Œà°²à±‹à°¡à± చేసà±à°¤à±‹à°‚ది...</translation>
<translation id="7364796246159120393">ఫైలà±â€Œà°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="8964020114565522021">ఫైలà±â€Œà°¨à± ఇకà±à°•à°¡à°•à± లాగండి</translation>
<translation id="838869780401515933">తనిఖీ చెయà±à°¯à°¿</translation>
<translation id="2846343701378493991">1024 (మధà±à°¯à°¸à±à°¥ à°—à±à°°à±‡à°¡à±)</translation>
<translation id="5476505524087279545">ఎంపిక చెయà±à°¯à°¬à°¡à°²à±‡à°¦à±</translation>
-<translation id="679352192834563463">à°ˆ కంటెంటà±â€Œà°¨à± à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚చడానికి à° à°ªà±à°²à°—à±â€Œà°‡à°¨à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±</translation>
<translation id="3789841737615482174">ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చెయà±à°¯à°¿</translation>
+<translation id="5253117816378681419">దయచేసి మీరౠ<ph name="PLUGIN"/> à°ªà±à°²à°—à±-ఇనà±â€Œà°¨à± à°µà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚చాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¨à°¿ నిరà±à°¥à°¾à°°à°¿à°‚à°šà°‚à°¡à°¿. మీరౠవిశà±à°µà°¸à°¿à°‚చే à°ªà±à°²à°—à±-ఇనà±â€Œà°²à°¨à± మాతà±à°°à°®à±‡ à°µà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚చాలి.</translation>
<translation id="6663448176199120256">ఇటీవల శోధనలà±</translation>
-<translation id="3600343118165084788">à°ªà±à°²à°—à±â€Œà°‡à°¨à±â€Œà°¨à± దిగà±à°®à°¤à°¿ చెయà±à°¯à°¡à°¾à°¨à°¿à°•à°¿ ఇకà±à°•à°¡ à°•à±à°²à°¿à°•à± చెయà±à°¯à°‚à°¡à°¿</translation>
+<translation id="2597378329261239068">à°ˆ పతà±à°°à°‚ à°…à°¨à±à°®à°¤à°¿ పదంచే à°°à°•à±à°·à°¿à°‚చబడింది. దయచేసి à°…à°¨à±à°®à°¤à°¿ పదానà±à°¨à°¿ నమోదౠచేయండి.</translation>
<translation id="6807599807928161586">వెబౠపà±à°°à°¾à°‚తం</translation>
<translation id="5939518447894949180">తిరిగి అమరà±à°šà°‚à°¡à°¿</translation>
-<translation id="3771786644471114952">à°ªà±à°²à°—à±â€Œà°‡à°¨à±â€Œà°¨à± పొందండి</translation>
<translation id="1842960171412779397">à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
+<translation id="7638452146404718955">à°ªà±à°²à°—à±-ఇనà±â€Œà°¨à± డౌనà±â€Œà°²à±‹à°¡à± చేయడానికి ఇకà±à°•à°¡ à°•à±à°²à°¿à°•à± చేయండి</translation>
<translation id="6119846243427417423">ఆకà±à°Ÿà°¿à°µà±‡à°Ÿà± చెయà±à°¯à°¿</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> ఫైళà±à°³à±</translation>
-<translation id="3926627843712816530">దయచేసి à°ˆ à°ªà±à°²à°—ౠఇనà±â€Œà°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చెయà±à°¯à°¾à°²à°¨à±à°•à±à°‚à°Ÿà±à°¨à°Ÿà±à°²à± నిరà±à°§à°¾à°°à°¿à°‚à°šà°‚à°¡à°¿. మీరౠనమà±à°®à±‡ à°ªà±à°²à°—à±â€Œà°‡à°¨à±â€Œà°²à°¨à± మాతà±à°°à°®à±‡ మీరౠఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చెయà±à°¯à°¾à°²à°¿.</translation>
-<translation id="4838490908464673667">అవసరమైన à°ªà±à°²à°—ినౠఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చెయà±à°¯à°¬à°¡à°²à±‡à°¦à±</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> à°ªà±à°²à°—à±-ఇనౠవà±à°¯à°µà°¸à±à°¥à°¾à°ªà°¿à°‚చబడలేదà±</translation>
+<translation id="6765711848403622008">à°ˆ కంటెంటà±â€Œà°¨à± à°ªà±à°°à°¦à°°à±à°¶à°¿à°‚చడానికి à° à°ªà±à°²à°—à±-ఇనౠఅందà±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±</translation>
<translation id="8597182159515967513">శీరà±à°·à°¿à°•</translation>
<translation id="2653659639078652383">సమరà±à°ªà°¿à°‚à°šà±</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> à°ªà±à°²à°—à±-ఇనౠఅవసరం</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_th.xtb b/webkit/glue/resources/webkit_strings_th.xtb
index a6c8b4b..80dd787 100644
--- a/webkit/glue/resources/webkit_strings_th.xtb
+++ b/webkit/glue/resources/webkit_strings_th.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="th">
-<translation id="4420062214988137980">à¸à¸²à¸£à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§</translation>
+<translation id="4519964825805946997">à¸à¸²à¸£à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™à¸ˆà¸²à¸ <ph name="URL"/> ล้มเหลว</translation>
<translation id="1235745349614807883">ลบà¸à¸²à¸£à¸„้นหาล่าสุด</translation>
-<translation id="3825324228893189080">ต้องà¸à¸²à¸£à¸›à¸¥à¸±à¹Šà¸à¸­à¸´à¸™à¹€à¸žà¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> ไม่ได้ติดตั้งปลั๊à¸à¸­à¸´à¸™</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="4317653869502688143">โปรดยืนยันว่าคุณต้องà¸à¸²à¸£à¸—ี่จะติดตั้ง <ph name="PLUGIN"/> ปลั๊à¸à¸­à¸´à¸™ คุณควรติดตั้งปลั๊à¸à¸­à¸´à¸™à¸—ี่คุณเชื่อถือเท่านั้น</translation>
<translation id="7658239707568436148">ยà¸à¹€à¸¥à¸´à¸</translation>
<translation id="795667975304826397">ไม่ได้เลือà¸à¹„ฟล์ใด</translation>
-<translation id="1275511093094545429">ต้องใช้ปลั๊à¸à¸­à¸´à¸™ <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">à¸à¸³à¸¥à¸±à¸‡à¸”าวน์โหลดปลั๊à¸à¸­à¸´à¸™...</translation>
+<translation id="1416462845279468967">à¸à¸²à¸£à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™à¸¥à¹‰à¸¡à¹€à¸«à¸¥à¸§</translation>
<translation id="8141602879876242471">นี่คือดัชนีที่สามารถค้นหาได้ ป้อนคำหลัà¸à¹ƒà¸™à¸à¸²à¸£à¸„้นหา:</translation>
+<translation id="5650795167354946011">หลังจาà¸à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™ ให้คลิà¸à¸—ี่นี่เพื่อรีเฟรช</translation>
<translation id="6845533974506654842">à¸à¸”</translation>
<translation id="8244226242650769279">à¹à¸œà¸™à¸—ี่รูปภาพ</translation>
-<translation id="1383141426028388991">à¸à¸²à¸£à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™à¸ˆà¸²à¸ <ph name="URL"/> ล้มเหลว</translation>
<translation id="2548326553472216322">ไม่พบà¸à¸²à¸£à¸„้นหาล่าสุด</translation>
<translation id="5944544982112848342">2048 (เà¸à¸£à¸”สูง)</translation>
<translation id="3040011195152428237">ลิงà¸à¹Œ</translation>
-<translation id="8281246460978372009">หลังจาà¸à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™ คลิà¸à¸—ี่นี่เพื่อรีเฟรซ</translation>
+<translation id="2745343197843472802">รับปลั๊à¸à¸­à¸´à¸™</translation>
+<translation id="5776402066334188252">โปรดยืนยันว่าคุณต้องà¸à¸²à¸£à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™à¸™à¸µà¹‰ คุณควรติดตั้งเฉพาะปลั๊à¸à¸­à¸´à¸™à¸—ี่คุณไว้ใจเท่านั้น </translation>
+<translation id="4003986561708175844">ไม่ได้ติดตั้งปลั๊à¸à¸­à¸´à¸™à¸—ี่จำเป็น</translation>
+<translation id="3018094406922859308">à¸à¸³à¸¥à¸±à¸‡à¸”าวน์โหลดปลั๊à¸à¸­à¸´à¸™...</translation>
<translation id="7364796246159120393">เลือà¸à¹„ฟล์</translation>
<translation id="8964020114565522021">ลาà¸à¹„ฟล์มาที่นี่</translation>
<translation id="838869780401515933">ทำเครื่องหมาย</translation>
<translation id="2846343701378493991">1024 (เà¸à¸£à¸”ปานà¸à¸¥à¸²à¸‡)</translation>
<translation id="5476505524087279545">ยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸—ำเครื่องหมาย</translation>
-<translation id="679352192834563463">ไม่มีปลั๊à¸à¸­à¸´à¸™à¸—ี่จะà¹à¸ªà¸”งเนื้อหานี้</translation>
<translation id="3789841737615482174">ติดตั้ง</translation>
+<translation id="5253117816378681419">โปรดยืนยันว่าคุณต้องà¸à¸²à¸£à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™ <ph name="PLUGIN"/> คุณควรติดตั้งเฉพาะปลั๊à¸à¸­à¸´à¸™à¸—ี่คุณไว้ใจเท่านั้น</translation>
<translation id="6663448176199120256">à¸à¸²à¸£à¸„้นหาล่าสุด</translation>
-<translation id="3600343118165084788">คลิà¸à¸—ี่นี่เพื่อดาวน์โหลดปลั๊à¸à¸­à¸´à¸™</translation>
+<translation id="2597378329261239068">เอà¸à¸ªà¸²à¸£à¸™à¸µà¹‰à¹„ด้รับà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸”้วยรหัสผ่าน โปรดป้อนรหัสผ่าน</translation>
<translation id="6807599807928161586">พื้นที่เว็บ</translation>
<translation id="5939518447894949180">ตั้งค่าใหม่</translation>
-<translation id="3771786644471114952">ติดตั้งปลั๊à¸à¸­à¸´à¸™</translation>
<translation id="1842960171412779397">เลือà¸</translation>
+<translation id="7638452146404718955">คลิà¸à¸—ี่นี่เพื่อดาวน์โหลดปลั๊à¸à¸­à¸´à¸™</translation>
<translation id="6119846243427417423">เปิดใช้งาน</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> ไฟล์</translation>
-<translation id="3926627843712816530">โปรดยืนยันว่าคุณต้องà¸à¸²à¸£à¸•à¸´à¸”ตั้งปลั๊à¸à¸­à¸´à¸™à¸™à¸µà¹‰ คุณควรติดตั้งปลั๊à¸à¸­à¸´à¸™à¸—ี่คุณเชื่อถือเท่านั้น</translation>
-<translation id="4838490908464673667">ไม่ได้ติดตั้งปลั๊à¸à¸­à¸´à¸™à¸—ี่จำเป็น</translation>
+<translation id="4470547978413275879">ไม่ได้ติดตั้งปลั๊à¸à¸­à¸´à¸™ <ph name="PLUGIN"/></translation>
+<translation id="6765711848403622008">ไม่มีปลั๊à¸à¸­à¸´à¸™à¸—ี่จะà¹à¸ªà¸”งเนื้อหานี้</translation>
<translation id="8597182159515967513">ส่วนหัว</translation>
<translation id="2653659639078652383">ส่ง</translation>
+<translation id="8475551193147984329">ต้องà¸à¸²à¸£à¸›à¸¥à¸±à¹Šà¸à¸­à¸´à¸™ <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_tr.xtb b/webkit/glue/resources/webkit_strings_tr.xtb
index 1f5571a..a4d880d 100644
--- a/webkit/glue/resources/webkit_strings_tr.xtb
+++ b/webkit/glue/resources/webkit_strings_tr.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="tr">
-<translation id="4420062214988137980">Eklenti kurulumu başarısız oldu</translation>
+<translation id="4519964825805946997">Eklenti, <ph name="URL"/> kaynağından yüklenemedi</translation>
<translation id="1235745349614807883">Son Aramaları Temizle</translation>
-<translation id="3825324228893189080">Ek eklenti gerekiyor</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> eklentisi yüklü değil</translation>
<translation id="5048533449481078685">liste işaretçisi</translation>
+<translation id="372362261556059955">BaÅŸka eklenti gerekiyor</translation>
<translation id="4202807286478387388">git</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Lütfen <ph name="PLUGIN"/> eklentisini yüklemek istediğinizi onaylayın. Yalnızca güvendiğiniz eklentileri yüklemelisiniz.</translation>
<translation id="7658239707568436148">Ä°ptal</translation>
<translation id="795667975304826397">Dosya seçilmedi</translation>
-<translation id="1275511093094545429"><ph name="PLUGIN"/> eklentisi gerekiyor</translation>
-<translation id="8662565117025751661">Eklenti indiriliyor...</translation>
+<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="6845533974506654842">bas</translation>
<translation id="8244226242650769279">resim haritası</translation>
-<translation id="1383141426028388991">Eklenti, <ph name="URL"/> kaynağından yüklenemedi</translation>
<translation id="2548326553472216322">Yeni arama yok</translation>
<translation id="5944544982112848342">2048 (Yüksek Düzey)</translation>
<translation id="3040011195152428237">bağlantı</translation>
-<translation id="8281246460978372009">Eklentiyi yükledikten sonra yenilemek için burayı tıklayın</translation>
+<translation id="2745343197843472802">Eklentiyi edinin</translation>
+<translation id="5776402066334188252">Lütfen bu eklentiyi yüklemek istediğinizi onaylayın. Yalnızca güvendiğiniz eklentileri yüklemelisiniz.</translation>
+<translation id="4003986561708175844">Gereken eklenti yüklü değil</translation>
+<translation id="3018094406922859308">Eklenti indiriliyor...</translation>
<translation id="7364796246159120393">Dosya Seç</translation>
<translation id="8964020114565522021">Dosyayı buraya sürükleyin</translation>
<translation id="838869780401515933">iÅŸaretle</translation>
<translation id="2846343701378493991">1024 (Orta Düzey)</translation>
<translation id="5476505524087279545">işareti kaldır</translation>
-<translation id="679352192834563463">Bu içeriği görüntüleyecek eklenti yok</translation>
<translation id="3789841737615482174">Yükle</translation>
+<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="3600343118165084788">Eklentiyi indirmek için burayı tıklayın</translation>
+<translation id="2597378329261239068">Doküman şifre korumalı. Lütfen şifreyi girin.</translation>
<translation id="6807599807928161586">web alanı</translation>
<translation id="5939518447894949180">Sıfırla</translation>
-<translation id="3771786644471114952">Eklenti Al</translation>
<translation id="1842960171412779397">seç</translation>
+<translation id="7638452146404718955">Eklentiyi indirmek için burayı tıklayın</translation>
<translation id="6119846243427417423">etkinleÅŸtir</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> dosya</translation>
-<translation id="3926627843712816530">Lütfen bu eklentiyi yüklemek istediğinizi onaylayın. Yalnızca güvendiğiniz eklentileri yüklemelisiniz.</translation>
-<translation id="4838490908464673667">Gereken eklenti yüklü değil</translation>
+<translation id="4470547978413275879"><ph name="PLUGIN"/> eklentisi yüklü değil</translation>
+<translation id="6765711848403622008">Bu içeriği görüntüleyecek hiçbir eklenti yok</translation>
<translation id="8597182159515967513">başlık</translation>
<translation id="2653659639078652383">Gönder</translation>
+<translation id="8475551193147984329"><ph name="PLUGIN"/> eklentisi gerekiyor</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_uk.xtb b/webkit/glue/resources/webkit_strings_uk.xtb
index ae193fe..a125fe2 100644
--- a/webkit/glue/resources/webkit_strings_uk.xtb
+++ b/webkit/glue/resources/webkit_strings_uk.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="uk">
-<translation id="4420062214988137980">Ðе вдалоÑÑŒ інÑталювати модуль</translation>
+<translation id="4519964825805946997">Ðе вдалоÑÑ Ð²Ñтановити плагін із <ph name="URL"/></translation>
<translation id="1235745349614807883">ОчиÑтити оÑтанні пошуки</translation>
-<translation id="3825324228893189080">Потрібен додатковий модуль.</translation>
-<translation id="2965480764085142436">Модуль <ph name="PLUGIN"/> не інÑтальовано</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="4317653869502688143">Підтвердьте інÑталÑцію Ð¼Ð¾Ð´ÑƒÐ»Ñ <ph name="PLUGIN"/>. Слід інÑталювати лише модулі, Ñкі вважаєте надійними.</translation>
<translation id="7658239707568436148">СкаÑувати</translation>
<translation id="795667975304826397">Файл не вибрано</translation>
-<translation id="1275511093094545429">Потрібен модуль <ph name="PLUGIN"/></translation>
-<translation id="8662565117025751661">Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ...</translation>
+<translation id="1416462845279468967">Помилка вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ð³Ñ–Ð½Ð°</translation>
<translation id="8141602879876242471">Цей доÑтупний Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ індекÑ. Введіть ключові Ñлова пошуку:</translation>
+<translation id="5650795167354946011">ПіÑÐ»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ð³Ñ–Ð½Ð° натиÑніть тут, щоб оновити</translation>
<translation id="6845533974506654842">натиÑнути</translation>
<translation id="8244226242650769279">мапа зображеннÑ</translation>
-<translation id="1383141426028388991">Ðе вдалоÑÑ Ð²Ñтановити модуль із <ph name="URL"/></translation>
<translation id="2548326553472216322">Ðемає оÑтанніх пошуків</translation>
<translation id="5944544982112848342">2048 (ВиÑокий рівень)</translation>
<translation id="3040011195152428237">поÑиланнÑ</translation>
-<translation id="8281246460978372009">ПіÑÐ»Ñ Ñ–Ð½ÑталÑції Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð½Ð°Ñ‚Ð¸Ñніть тут, щоб оновити</translation>
+<translation id="2745343197843472802">Отримати плагін</translation>
+<translation id="5776402066334188252">Підтвердьте вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ плагіна. Слід уÑтановлювати лише плагіни, Ñким ви довірÑєте.</translation>
+<translation id="4003986561708175844">Потрібний плагін не вÑтановлено</translation>
+<translation id="3018094406922859308">Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ð³Ñ–Ð½Ð°...</translation>
<translation id="7364796246159120393">Вибрати файл</translation>
<translation id="8964020114565522021">ПеретÑгніть файл Ñюди</translation>
<translation id="838869780401515933">уÑтановити прапорець</translation>
<translation id="2846343701378493991">1024 (Середній рівень)</translation>
<translation id="5476505524087279545">знÑти прапорець</translation>
-<translation id="679352192834563463">Ðемає доÑтупного Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ вміÑту</translation>
<translation id="3789841737615482174">ІнÑталювати</translation>
+<translation id="5253117816378681419">Підтвердьте вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ð³Ñ–Ð½Ð° <ph name="PLUGIN"/>. Слід уÑтановлювати лише плагіни, Ñким ви довірÑєте.</translation>
<translation id="6663448176199120256">ОÑтанні пошуки</translation>
-<translation id="3600343118165084788">ÐатиÑніть тут, щоб завантажити модуль</translation>
+<translation id="2597378329261239068">Цей документ захищено паролем. Введіть пароль.</translation>
<translation id="6807599807928161586">облаÑÑ‚ÑŒ Інтернету</translation>
<translation id="5939518447894949180">Скинути</translation>
-<translation id="3771786644471114952">Отримати модуль</translation>
<translation id="1842960171412779397">вибрати</translation>
+<translation id="7638452146404718955">ÐатиÑніть тут, щоб завантажити плагін</translation>
<translation id="6119846243427417423">активувати</translation>
<translation id="8444882422881193423">файлів: <ph name="NUMBER_OF_FILES"/></translation>
-<translation id="3926627843712816530">Підтвердьте інÑталÑцію цього модулÑ. Слід інÑталювати лише модулі, Ñкі вважаєте надійними.</translation>
-<translation id="4838490908464673667">Потрібний модуль не інÑтальовано</translation>
+<translation id="4470547978413275879">Плагін <ph name="PLUGIN"/> не вÑтановлено</translation>
+<translation id="6765711848403622008">Ðемає доÑтупного плагіна Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ вміÑту</translation>
<translation id="8597182159515967513">заголовок</translation>
<translation id="2653659639078652383">ÐадіÑлати</translation>
+<translation id="8475551193147984329">Потрібен плагін <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_vi.xtb b/webkit/glue/resources/webkit_strings_vi.xtb
index 9e3f498..84668c5 100644
--- a/webkit/glue/resources/webkit_strings_vi.xtb
+++ b/webkit/glue/resources/webkit_strings_vi.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="vi">
-<translation id="4420062214988137980">Không cài đặt plugin được</translation>
+<translation id="4519964825805946997">Cài đặt trình cắm từ <ph name="URL"/> không thành công</translation>
<translation id="1235745349614807883">Xoá Tìm kiếm Gần đây</translation>
-<translation id="3825324228893189080">Cần plugin bổ sung</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> plgin không được cài đặt</translation>
<translation id="5048533449481078685">đánh dấu danh sách</translation>
+<translation id="372362261556059955">Cần trình cắm bổ sung</translation>
<translation id="4202807286478387388">chuyển</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="4317653869502688143">Vui lòng xác nhận rằng bạn muốn cài đặt plugin <ph name="PLUGIN"/>. Bạn chỉ nên cài đặt plugin mà mình tin cậy.</translation>
<translation id="7658239707568436148">Huá»·</translation>
<translation id="795667975304826397">Không có tệp nào được chá»n</translation>
-<translation id="1275511093094545429">Cần <ph name="PLUGIN"/> plugin</translation>
-<translation id="8662565117025751661">Äang tải xuống plugin...</translation>
+<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="6845533974506654842">nhấn</translation>
<translation id="8244226242650769279">bản đồ hình ảnh</translation>
-<translation id="1383141426028388991">Không cài đặt được plugin từ <ph name="URL"/></translation>
<translation id="2548326553472216322">Không có tìm kiếm nào gần đây</translation>
<translation id="5944544982112848342">2048 (Cấp độ cao)</translation>
<translation id="3040011195152428237">liên kết</translation>
-<translation id="8281246460978372009">Sau khi cài đặt plugin, nhấp vào đây để làm mới</translation>
+<translation id="2745343197843472802">Tải Trình cắm</translation>
+<translation id="5776402066334188252">Vui lòng xác nhận rằng bạn muốn cài đặt trình cắm này. Bạn chỉ nên cài đặt trình cắm mà bạn tin tưởng.</translation>
+<translation id="4003986561708175844">Trình cắm được yêu cầu chưa được cài đặt</translation>
+<translation id="3018094406922859308">Äang tải xuống trình cắm...</translation>
<translation id="7364796246159120393">Chá»n Tệp tin</translation>
<translation id="8964020114565522021">Kéo tệp tại đây</translation>
<translation id="838869780401515933">chá»n</translation>
<translation id="2846343701378493991">1024 (Loại Trung bình)</translation>
<translation id="5476505524087279545">bá» chá»n</translation>
-<translation id="679352192834563463">Không plugin nào có sẵn để hiển thị nội dung này</translation>
<translation id="3789841737615482174">Cài đặt</translation>
+<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="3600343118165084788">Nhấp vào đây để tải plugin xuống</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="6807599807928161586">khu vá»±c web</translation>
<translation id="5939518447894949180">Äặt lại</translation>
-<translation id="3771786644471114952">Tải Plugin</translation>
<translation id="1842960171412779397">chá»n</translation>
+<translation id="7638452146404718955">Nhấp vào đây để tải xuống trình cắm</translation>
<translation id="6119846243427417423">kích hoạt</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> tệp</translation>
-<translation id="3926627843712816530">Hãy xác nhận rằng bạn muốn cài đặt plugin này. Bạn chỉ nên cài đặt plugin mà mình tin cậy.</translation>
-<translation id="4838490908464673667">Plugin yêu cầu không được cài đặt</translation>
+<translation id="4470547978413275879">Trình cắm <ph name="PLUGIN"/> chưa được cài đặt</translation>
+<translation id="6765711848403622008">Không có trình cắm nào để hiển thị nội dung này</translation>
<translation id="8597182159515967513">đầu Ä‘á»</translation>
<translation id="2653659639078652383">Gá»­i</translation>
+<translation id="8475551193147984329">Cần trình cắm <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_zh-CN.xtb b/webkit/glue/resources/webkit_strings_zh-CN.xtb
index c2d8176..f5c0644 100644
--- a/webkit/glue/resources/webkit_strings_zh-CN.xtb
+++ b/webkit/glue/resources/webkit_strings_zh-CN.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-CN">
-<translation id="4420062214988137980">安装æ’件失败</translation>
+<translation id="4519964825805946997">无法从 <ph name="URL"/> 安装æ’件</translation>
<translation id="1235745349614807883">清除最近的æœç´¢</translation>
-<translation id="3825324228893189080">需è¦ä½¿ç”¨å…¶ä»–æ’件</translation>
-<translation id="2965480764085142436">未安装 <ph name="PLUGIN"/> æ’件</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="4317653869502688143">请确认您è¦å®‰è£… <ph name="PLUGIN"/> æ’件。您åªèƒ½å®‰è£…自己信任的æ’件。</translation>
<translation id="7658239707568436148">å–消</translation>
<translation id="795667975304826397">未选择文件</translation>
-<translation id="1275511093094545429">需è¦ä½¿ç”¨ <ph name="PLUGIN"/> æ’件</translation>
-<translation id="8662565117025751661">正在下载æ’件...</translation>
+<translation id="1416462845279468967">æ’件安装失败</translation>
<translation id="8141602879876242471">这是一个å¯æœç´¢çš„索引。请输入æœç´¢å…³é”®å­—:</translation>
+<translation id="5650795167354946011">安装æ’件åŽï¼Œç‚¹å‡»æ­¤å¤„å¯åˆ·æ–°</translation>
<translation id="6845533974506654842">按</translation>
<translation id="8244226242650769279">图片映射</translation>
-<translation id="1383141426028388991">无法从 <ph name="URL"/> 安装æ’件</translation>
<translation id="2548326553472216322">最近未执行æœç´¢</translation>
<translation id="5944544982112848342">2048(高强度)</translation>
<translation id="3040011195152428237">链接</translation>
-<translation id="8281246460978372009">安装æ’件åŽï¼Œç‚¹å‡»æ­¤å¤„å¯åˆ·æ–°</translation>
+<translation id="2745343197843472802">获å–æ’件</translation>
+<translation id="5776402066334188252">请确认您è¦å®‰è£…æ­¤æ’件。您应该åªå®‰è£…自己信任的æ’件。</translation>
+<translation id="4003986561708175844">未安装所需æ’件</translation>
+<translation id="3018094406922859308">正在下载æ’件...</translation>
<translation id="7364796246159120393">选择文件</translation>
<translation id="8964020114565522021">将文件拖到此处</translation>
<translation id="838869780401515933">选中</translation>
<translation id="2846343701378493991">1024(中等强度)</translation>
<translation id="5476505524087279545">å–消选中</translation>
-<translation id="679352192834563463">没有用于显示这ç§å†…容的æ’件</translation>
<translation id="3789841737615482174">安装</translation>
+<translation id="5253117816378681419">请确认您è¦å®‰è£… <ph name="PLUGIN"/> æ’件。您应该åªå®‰è£…自己信任的æ’件。</translation>
<translation id="6663448176199120256">近期æœç´¢</translation>
-<translation id="3600343118165084788">点击此处å¯ä¸‹è½½æ’件</translation>
+<translation id="2597378329261239068">本文档设置了密ç ä¿æŠ¤ï¼Œè¯·è¾“入密ç ã€‚</translation>
<translation id="6807599807928161586">网络区域</translation>
<translation id="5939518447894949180">é‡ç½®</translation>
-<translation id="3771786644471114952">获å–æ’件</translation>
<translation id="1842960171412779397">选中</translation>
+<translation id="7638452146404718955">点击此处å¯ä¸‹è½½æ’件</translation>
<translation id="6119846243427417423">激活</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> 个文件</translation>
-<translation id="3926627843712816530">请确认您è¦å®‰è£…æ­¤æ’件。您åªèƒ½å®‰è£…自己信任的æ’件。</translation>
-<translation id="4838490908464673667">未安装所需æ’件</translation>
+<translation id="4470547978413275879">未安装 <ph name="PLUGIN"/> æ’件</translation>
+<translation id="6765711848403622008">没有用于显示此内容的æ’件</translation>
<translation id="8597182159515967513">标题</translation>
<translation id="2653659639078652383">æ交</translation>
+<translation id="8475551193147984329">éœ€è¦ <ph name="PLUGIN"/> æ’件</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_zh-TW.xtb b/webkit/glue/resources/webkit_strings_zh-TW.xtb
index 999207a..7d7eda3 100644
--- a/webkit/glue/resources/webkit_strings_zh-TW.xtb
+++ b/webkit/glue/resources/webkit_strings_zh-TW.xtb
@@ -1,43 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="zh-TW">
-<translation id="4420062214988137980">外掛程å¼å®‰è£å¤±æ•—</translation>
+<translation id="4519964825805946997">無法從 <ph name="URL"/> 安è£å¤–掛程å¼</translation>
<translation id="1235745349614807883">清除最近的æœå°‹è¨˜éŒ„</translation>
-<translation id="3825324228893189080">需è¦é¡å¤–的外掛程å¼</translation>
-<translation id="2965480764085142436"><ph name="PLUGIN"/> 外掛程å¼å°šæœªå®‰è£</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="4317653869502688143">請確定您想è¦å®‰è£ <ph name="PLUGIN"/> 外掛程å¼ã€‚建議您僅安è£å¯é çš„外掛程å¼ã€‚</translation>
<translation id="7658239707568436148">å–消</translation>
<translation id="795667975304826397">未é¸æ“‡æª”案</translation>
-<translation id="1275511093094545429">éœ€è¦ <ph name="PLUGIN"/> 外掛程å¼</translation>
-<translation id="8662565117025751661">正在下載外掛程å¼...</translation>
+<translation id="1416462845279468967">外掛程å¼å®‰è£ä¸æˆåŠŸ</translation>
<translation id="8141602879876242471">這是å¯æœå°‹çš„索引,輸入æœå°‹é—œéµå­—:</translation>
+<translation id="5650795167354946011">安è£å¤–掛程å¼å¾Œï¼Œè«‹æŒ‰ä¸€ä¸‹é€™è£¡é‡æ–°æ•´ç†</translation>
<translation id="6845533974506654842">按下</translation>
<translation id="8244226242650769279">å½±åƒåœ°åœ–</translation>
-<translation id="1383141426028388991">無法從 <ph name="URL"/> 安è£å¤–掛程å¼</translation>
<translation id="2548326553472216322">沒有近期的æœå°‹</translation>
<translation id="5944544982112848342">2048 (高級)</translation>
<translation id="3040011195152428237">連çµ</translation>
-<translation id="8281246460978372009">安è£å¤–掛程å¼å¾Œï¼Œè«‹æŒ‰ä¸€ä¸‹é€™è£¡æ›´æ–°</translation>
+<translation id="2745343197843472802">å–得外掛程å¼</translation>
+<translation id="5776402066334188252">請確èªæ‚¨è¦å®‰è£æ­¤å¤–掛程å¼ï¼Œå»ºè­°æ‚¨åƒ…安è£æ‚¨æ‰€ä¿¡ä»»çš„外掛程å¼ã€‚</translation>
+<translation id="4003986561708175844">未安è£å¿…è¦çš„外掛程å¼</translation>
+<translation id="3018094406922859308">正在下載外掛程å¼...</translation>
<translation id="7364796246159120393">é¸æ“‡æª”案</translation>
<translation id="8964020114565522021">拖曳檔案至此</translation>
<translation id="838869780401515933">é¸å–</translation>
<translation id="2846343701378493991">1024 (中等)</translation>
<translation id="5476505524087279545">å–消é¸å–</translation>
-<translation id="679352192834563463">沒有外掛程å¼å¯ä¾›é¡¯ç¤ºç›®å‰å…§å®¹</translation>
<translation id="3789841737615482174">安è£</translation>
+<translation id="5253117816378681419">請確èªæ‚¨è¦å®‰è£ <ph name="PLUGIN"/> 外掛程å¼ï¼Œå»ºè­°æ‚¨åƒ…安è£æ‚¨æ‰€ä¿¡ä»»çš„外掛程å¼ã€‚</translation>
<translation id="6663448176199120256">最近的æœå°‹</translation>
-<translation id="3600343118165084788">按一下這裡以下載掛程å¼</translation>
+<translation id="2597378329261239068">此文件å—到密碼ä¿è­·ï¼Œè«‹è¼¸å…¥å¯†ç¢¼ã€‚</translation>
<translation id="6807599807928161586">網é ç¯„åœ</translation>
<translation id="5939518447894949180">é‡è¨­</translation>
-<translation id="3771786644471114952">å–得外掛程å¼</translation>
<translation id="1842960171412779397">é¸å–</translation>
+<translation id="7638452146404718955">按一下這裡下載外掛程å¼</translation>
<translation id="6119846243427417423">å•Ÿå‹•</translation>
<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> 個檔案</translation>
-<translation id="3926627843712816530">請確定您想è¦å®‰è£æ­¤å¤–掛程å¼ã€‚建議您僅安è£å¯é çš„外掛程å¼ã€‚</translation>
-<translation id="4838490908464673667">未安è£è¦æ±‚的外掛程å¼</translation>
+<translation id="4470547978413275879">æœªå®‰è£ <ph name="PLUGIN"/> 外掛程å¼</translation>
+<translation id="6765711848403622008">沒有å¯ä»¥é¡¯ç¤ºæ­¤å…§å®¹çš„外掛程å¼</translation>
<translation id="8597182159515967513">標題</translation>
<translation id="2653659639078652383">æ交</translation>
+<translation id="8475551193147984329">éœ€è¦ <ph name="PLUGIN"/> 外掛程å¼</translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/simple_webmimeregistry_impl.cc b/webkit/glue/simple_webmimeregistry_impl.cc
index 5dd227f..d878867 100644
--- a/webkit/glue/simple_webmimeregistry_impl.cc
+++ b/webkit/glue/simple_webmimeregistry_impl.cc
@@ -6,6 +6,7 @@
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
#include "net/base/mime_util.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "webkit/glue/webkit_glue.h"
diff --git a/webkit/glue/unittest_test_server.h b/webkit/glue/unittest_test_server.h
index 0b3c7d2..575f0f9 100644
--- a/webkit/glue/unittest_test_server.h
+++ b/webkit/glue/unittest_test_server.h
@@ -5,61 +5,17 @@
#ifndef WEBKIT_GLUE_UNITTEST_TEST_SERVER_H__
#define WEBKIT_GLUE_UNITTEST_TEST_SERVER_H__
-#include "webkit/appcache/appcache_interfaces.h"
-#include "webkit/glue/resource_loader_bridge.h"
#include "net/base/load_flags.h"
-#include "net/url_request/url_request_unittest.h"
-
-using webkit_glue::ResourceLoaderBridge;
-
-// We need to use ResourceLoaderBridge to communicate with the testserver
-// instead of using URLRequest directly because URLRequests need to be run on
-// the test_shell's IO thread.
-class UnittestTestServer : public HTTPTestServer {
- protected:
- UnittestTestServer() {
- }
+#include "net/test/test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/appcache/appcache_interfaces.h"
+class UnittestTestServer : public net::TestServer {
public:
- static UnittestTestServer* CreateServer() {
- UnittestTestServer* test_server = new UnittestTestServer();
- FilePath no_cert;
- FilePath docroot(FILE_PATH_LITERAL("webkit/data"));
- if (!test_server->Start(net::TestServerLauncher::ProtoHTTP,
- "localhost", 1337, docroot, no_cert, std::wstring())) {
- delete test_server;
- return NULL;
- }
- return test_server;
+ UnittestTestServer()
+ : net::TestServer(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("webkit/data"))) {
}
-
- virtual bool MakeGETRequest(const std::string& page_name) {
- GURL url(TestServerPage(page_name));
- webkit_glue::ResourceLoaderBridge::RequestInfo request_info;
- request_info.method = "GET";
- request_info.url = url;
- request_info.first_party_for_cookies = url;
- request_info.referrer = GURL(); // No referrer.
- request_info.frame_origin = "null";
- request_info.main_frame_origin = "null";
- request_info.headers = std::string(); // No extra headers.
- request_info.load_flags = net::LOAD_NORMAL;
- request_info.requestor_pid = 0;
- request_info.request_type = ResourceType::SUB_RESOURCE;
- request_info.request_context = 0;
- request_info.appcache_host_id = appcache::kNoHostId;
- request_info.routing_id = 0;
- scoped_ptr<ResourceLoaderBridge> loader(
- ResourceLoaderBridge::Create(request_info));
- EXPECT_TRUE(loader.get());
-
- ResourceLoaderBridge::SyncLoadResponse resp;
- loader->SyncLoad(&resp);
- return resp.status.is_success();
- }
-
- private:
- virtual ~UnittestTestServer() {}
};
#endif // WEBKIT_GLUE_UNITTEST_TEST_SERVER_H__
diff --git a/webkit/glue/user_agent.cc b/webkit/glue/user_agent.cc
new file mode 100644
index 0000000..2babb49
--- /dev/null
+++ b/webkit/glue/user_agent.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2010 The Chromium Authors. 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/user_agent.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include <sys/utsname.h>
+#endif
+
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/sys_info.h"
+
+// Generated
+#include "webkit_version.h" // NOLINT
+
+namespace webkit_glue {
+
+// Forward declare GetProductVersionInfo. This is implemented in
+// renderer_glue.cc as part of the renderer lib.
+std::string GetProductVersion();
+
+std::string GetWebKitVersion() {
+ return base::StringPrintf("%d.%d", WEBKIT_VERSION_MAJOR,
+ WEBKIT_VERSION_MINOR);
+}
+
+std::string BuildOSCpuInfo() {
+ std::string os_cpu;
+
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+ int32 os_major_version = 0;
+ int32 os_minor_version = 0;
+ int32 os_bugfix_version = 0;
+ base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+ &os_minor_version,
+ &os_bugfix_version);
+#endif
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ // Should work on any Posix system.
+ struct utsname unixinfo;
+ uname(&unixinfo);
+
+ std::string cputype;
+ // special case for biarch systems
+ if (strcmp(unixinfo.machine, "x86_64") == 0 &&
+ sizeof(void*) == sizeof(int32)) { // NOLINT
+ cputype.assign("i686 (x86_64)");
+ } else {
+ cputype.assign(unixinfo.machine);
+ }
+#endif
+
+ StringAppendF(
+ &os_cpu,
+#if defined(OS_WIN)
+ "Windows NT %d.%d",
+ os_major_version,
+ os_minor_version
+#elif defined(OS_MACOSX)
+ "Intel Mac OS X %d_%d_%d",
+ os_major_version,
+ os_minor_version,
+ os_bugfix_version
+#elif defined(OS_CHROMEOS)
+ "CrOS %s %d.%d.%d",
+ cputype.c_str(), // e.g. i686
+ os_major_version,
+ os_minor_version,
+ os_bugfix_version
+#else
+ "%s %s",
+ unixinfo.sysname, // e.g. Linux
+ cputype.c_str() // e.g. i686
+#endif
+ ); // NOLINT
+
+ return os_cpu;
+}
+
+void BuildUserAgent(bool mimic_windows, std::string* result) {
+ const char kUserAgentPlatform[] =
+#if defined(OS_WIN)
+ "Windows";
+#elif defined(OS_MACOSX)
+ "Macintosh";
+#elif defined(USE_X11)
+ "X11"; // strange, but that's what Firefox uses
+#else
+ "?";
+#endif
+
+ const char kUserAgentSecurity = 'U'; // "US" strength encryption
+
+ // TODO(port): figure out correct locale
+ const char kUserAgentLocale[] = "en-US";
+
+ // Get the product name and version, and replace Safari's Version/X string
+ // with it. This is done to expose our product name in a manner that is
+ // maximally compatible with Safari, we hope!!
+ std::string product = GetProductVersion();
+
+ // Derived from Safari's UA string.
+ StringAppendF(
+ result,
+ "Mozilla/5.0 (%s; %c; %s; %s) AppleWebKit/%d.%d"
+ " (KHTML, like Gecko) %s Safari/%d.%d",
+ mimic_windows ? "Windows" : kUserAgentPlatform,
+ kUserAgentSecurity,
+ ((mimic_windows ? "Windows " : "") + BuildOSCpuInfo()).c_str(),
+ kUserAgentLocale,
+ WEBKIT_VERSION_MAJOR,
+ WEBKIT_VERSION_MINOR,
+ product.c_str(),
+ WEBKIT_VERSION_MAJOR,
+ WEBKIT_VERSION_MINOR);
+}
+
+} // namespace webkit_glue
+
diff --git a/webkit/glue/user_agent.h b/webkit/glue/user_agent.h
new file mode 100644
index 0000000..3d1f788
--- /dev/null
+++ b/webkit/glue/user_agent.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 WEBKIT_GLUE_USER_AGENT_H_
+#define WEBKIT_GLUE_USER_AGENT_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace webkit_glue {
+
+// Construct the User-Agent header, filling in |result|.
+// The other parameters are workarounds for broken websites:
+// - If mimic_windows is true, produce a fake Windows Chrome string.
+void BuildUserAgent(bool mimic_windows, std::string* result);
+
+// Builds a User-agent compatible string that describes the OS and CPU type.
+std::string BuildOSCpuInfo();
+
+// Returns the WebKit version (major.minor).
+std::string GetWebKitVersion();
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_USER_AGENT_H_
+
diff --git a/webkit/glue/webaccessibility.cc b/webkit/glue/webaccessibility.cc
index b6e0d5e..0d96685 100644
--- a/webkit/glue/webaccessibility.cc
+++ b/webkit/glue/webaccessibility.cc
@@ -4,9 +4,17 @@
#include "webkit/glue/webaccessibility.h"
+#include "base/string_util.h"
#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityCache.h"
#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityObject.h"
#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityRole.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebAttribute.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebDocumentType.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/WebNamedNodeMap.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebNode.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
using WebKit::WebAccessibilityCache;
@@ -219,19 +227,32 @@ uint32 ConvertState(const WebAccessibilityObject& o) {
if (o.isChecked())
state |= (1 << WebAccessibility::STATE_CHECKED);
+ if (o.isCollapsed())
+ state |= (1 << WebAccessibility::STATE_COLLAPSED);
+
if (o.canSetFocusAttribute())
state |= (1 << WebAccessibility::STATE_FOCUSABLE);
if (o.isFocused())
state |= (1 << WebAccessibility::STATE_FOCUSED);
+ if (o.roleValue() == WebKit::WebAccessibilityRolePopUpButton) {
+ state |= (1 << WebAccessibility::STATE_HASPOPUP);
+
+ if (!o.isCollapsed())
+ state |= (1 << WebAccessibility::STATE_EXPANDED);
+ }
+
if (o.isHovered())
state |= (1 << WebAccessibility::STATE_HOTTRACKED);
if (o.isIndeterminate())
state |= (1 << WebAccessibility::STATE_INDETERMINATE);
- if (o.isAnchor())
+ if (!o.isVisible())
+ state |= (1 << WebAccessibility::STATE_INVISIBLE);
+
+ if (o.isLinked())
state |= (1 << WebAccessibility::STATE_LINKED);
if (o.isMultiSelectable())
@@ -249,6 +270,12 @@ uint32 ConvertState(const WebAccessibilityObject& o) {
if (o.isReadOnly())
state |= (1 << WebAccessibility::STATE_READONLY);
+ if (o.canSetSelectedAttribute())
+ state |= (1 << WebAccessibility::STATE_SELECTABLE);
+
+ if (o.isSelected())
+ state |= (1 << WebAccessibility::STATE_SELECTED);
+
if (o.isVisited())
state |= (1 << WebAccessibility::STATE_TRAVERSED);
@@ -269,6 +296,9 @@ WebAccessibility::WebAccessibility(const WebKit::WebAccessibilityObject& src,
Init(src, cache);
}
+WebAccessibility::~WebAccessibility() {
+}
+
void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src,
WebKit::WebAccessibilityCache* cache) {
name = src.title();
@@ -285,15 +315,56 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src,
attributes[ATTR_HELP] = src.helpText();
if (src.keyboardShortcut().length())
attributes[ATTR_SHORTCUT] = src.keyboardShortcut();
+ if (src.hasComputedStyle())
+ attributes[ATTR_DISPLAY] = src.computedStyleDisplay();
+
+ WebKit::WebNode node = src.node();
+
+ if (!node.isNull() && node.isElementNode()) {
+ WebKit::WebElement element = node.to<WebKit::WebElement>();
+ // TODO(ctguil): The tagName in WebKit is lower cased but
+ // HTMLElement::nodeName calls localNameUpper. Consider adding
+ // a WebElement method that returns the original lower cased tagName.
+ attributes[ATTR_HTML_TAG] = StringToLowerASCII(string16(element.tagName()));
+ for (unsigned i = 0; i < element.attributes().length(); i++) {
+ html_attributes.push_back(
+ std::pair<string16, string16>(
+ element.attributes().attributeItem(i).localName(),
+ element.attributes().attributeItem(i).value()));
+ }
+ }
+
+ if (role == WebAccessibility::ROLE_DOCUMENT ||
+ role == WebAccessibility::ROLE_WEB_AREA) {
+ WebKit::WebDocument document = src.document();
+ if (name.empty())
+ name = document.title();
+ attributes[ATTR_DOC_TITLE] = document.title();
+ attributes[ATTR_DOC_URL] = document.frame()->url().spec().utf16();
+ if (document.isXHTMLDocument())
+ attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/xhtml");
+ else
+ attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/html");
+
+ WebKit::WebDocumentType doctype = document.doctype();
+ if (!doctype.isNull())
+ attributes[ATTR_DOC_DOCTYPE] = doctype.name();
+ }
// Add the source object to the cache and store its id.
id = cache->addOrGetId(src);
// Recursively create children.
int child_count = src.childCount();
- children.resize(child_count);
for (int i = 0; i < child_count; i++) {
- children[i].Init(src.childAt(i), cache);
+ WebAccessibilityObject child = src.childAt(i);
+
+ // The child may be invalid due to issues in webkit accessibility code.
+ // Don't add children are invalid thus preventing a crash.
+ // https://bugs.webkit.org/show_bug.cgi?id=44149
+ // TODO(ctguil): We may want to remove this check as webkit stabilizes.
+ if (child.isValid())
+ children.push_back(WebAccessibility(child, cache));
}
}
diff --git a/webkit/glue/webaccessibility.h b/webkit/glue/webaccessibility.h
index 305bc0c..09a9473 100644
--- a/webkit/glue/webaccessibility.h
+++ b/webkit/glue/webaccessibility.h
@@ -9,12 +9,11 @@
#include <vector>
#include "base/string16.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityObject.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityRole.h"
#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
namespace WebKit {
class WebAccessibilityCache;
+class WebAccessibilityObject;
}
namespace webkit_glue {
@@ -133,23 +132,41 @@ struct WebAccessibility {
// int mask = (1 << STATE_CHECKED) | (1 << STATE_FOCUSED);
enum State {
STATE_CHECKED,
+ STATE_COLLAPSED,
+ STATE_EXPANDED,
STATE_FOCUSABLE,
STATE_FOCUSED,
+ STATE_HASPOPUP,
STATE_HOTTRACKED,
STATE_INDETERMINATE,
+ STATE_INVISIBLE,
STATE_LINKED,
STATE_MULTISELECTABLE,
STATE_OFFSCREEN,
STATE_PRESSED,
STATE_PROTECTED,
STATE_READONLY,
+ STATE_SELECTABLE,
+ STATE_SELECTED,
STATE_TRAVERSED,
+ STATE_BUSY,
STATE_UNAVAILABLE
};
+ // Additional optional attributes that can be optionally attached to
+ // a node.
enum Attribute {
+ // Doc attributes: only make sense when applied to the top-level
+ // Document node.
+ ATTR_DOC_URL,
+ ATTR_DOC_TITLE,
+ ATTR_DOC_MIMETYPE,
+ ATTR_DOC_DOCTYPE,
+
+ // Attributes that could apply to any node.
ATTR_ACTION,
ATTR_DESCRIPTION,
+ ATTR_DISPLAY,
ATTR_HELP,
ATTR_HTML_TAG,
ATTR_LINK_TARGET,
@@ -166,6 +183,8 @@ struct WebAccessibility {
WebAccessibility(const WebKit::WebAccessibilityObject& src,
WebKit::WebAccessibilityCache* cache);
+ ~WebAccessibility();
+
// Initialize an already-created struct, same as the constructor a
void Init(const WebKit::WebAccessibilityObject& src,
WebKit::WebAccessibilityCache* cache);
@@ -180,6 +199,7 @@ struct WebAccessibility {
WebKit::WebRect location;
std::map<int32, string16> attributes;
std::vector<WebAccessibility> children;
+ std::vector<std::pair<string16, string16> > html_attributes;
};
} // namespace webkit_glue
diff --git a/webkit/glue/webclipboard_impl.cc b/webkit/glue/webclipboard_impl.cc
index 11bc96d..8e3f87b 100644
--- a/webkit/glue/webclipboard_impl.cc
+++ b/webkit/glue/webclipboard_impl.cc
@@ -58,6 +58,9 @@ std::string WebClipboardImpl::URLToImageMarkup(const WebURL& url,
return markup;
}
+WebClipboardImpl::~WebClipboardImpl() {
+}
+
bool WebClipboardImpl::isFormatAvailable(Format format, Buffer buffer) {
Clipboard::FormatType format_type;
Clipboard::Buffer buffer_type;
diff --git a/webkit/glue/webclipboard_impl.h b/webkit/glue/webclipboard_impl.h
index 92c4a5e..6a83a6d 100644
--- a/webkit/glue/webclipboard_impl.h
+++ b/webkit/glue/webclipboard_impl.h
@@ -19,7 +19,7 @@ class WebClipboardImpl : public WebKit::WebClipboard {
static std::string URLToImageMarkup(const WebKit::WebURL& url,
const WebKit::WebString& title);
- virtual ~WebClipboardImpl() {}
+ virtual ~WebClipboardImpl();
// WebClipboard methods:
virtual bool isFormatAvailable(Format, Buffer);
diff --git a/webkit/glue/webcookie.cc b/webkit/glue/webcookie.cc
new file mode 100644
index 0000000..cb255bd
--- /dev/null
+++ b/webkit/glue/webcookie.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 "webkit/glue/webcookie.h"
+
+namespace webkit_glue {
+
+WebCookie::WebCookie()
+ : expires(0),
+ http_only(false),
+ secure(false),
+ session(false) {
+}
+
+WebCookie::WebCookie(const net::CookieMonster::CanonicalCookie& c)
+ : name(c.Name()),
+ value(c.Value()),
+ domain(c.Domain()),
+ path(c.Path()),
+ expires(c.ExpiryDate().ToDoubleT() * 1000),
+ http_only(c.IsHttpOnly()),
+ secure(c.IsSecure()),
+ session(!c.IsPersistent()) {
+}
+
+WebCookie::WebCookie(const std::string& name, const std::string& value,
+ const std::string& domain, const std::string& path,
+ double expires, bool http_only, bool secure, bool session)
+ : name(name),
+ value(value),
+ domain(domain),
+ path(path),
+ expires(expires),
+ http_only(http_only),
+ secure(secure),
+ session(session) {
+}
+
+WebCookie::~WebCookie() {
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/webcookie.h b/webkit/glue/webcookie.h
index e2f11e2..11411d8 100644
--- a/webkit/glue/webcookie.h
+++ b/webkit/glue/webcookie.h
@@ -14,38 +14,12 @@
namespace webkit_glue {
struct WebCookie {
-
+ WebCookie();
+ explicit WebCookie(const net::CookieMonster::CanonicalCookie& c);
WebCookie(const std::string& name, const std::string& value,
const std::string& domain, const std::string& path, double expires,
- bool http_only, bool secure, bool session)
- : name(name),
- value(value),
- domain(domain),
- path(path),
- expires(expires),
- http_only(http_only),
- secure(secure),
- session(session) {
- }
-
- explicit WebCookie(const net::CookieMonster::CanonicalCookie& c)
- : name(c.Name()),
- value(c.Value()),
- domain(c.Domain()),
- path(c.Path()),
- expires(c.ExpiryDate().ToDoubleT() * 1000),
- http_only(c.IsHttpOnly()),
- secure(c.IsSecure()),
- session(!c.IsPersistent()) {
- }
-
- // For default constructions.
- WebCookie()
- : expires(0),
- http_only(false),
- secure(false),
- session(false) {
- }
+ bool http_only, bool secure, bool session);
+ ~WebCookie();
// Cookie name.
std::string name;
diff --git a/webkit/glue/webcursor.cc b/webkit/glue/webcursor.cc
index f09372c..8f76ef9 100644
--- a/webkit/glue/webcursor.cc
+++ b/webkit/glue/webcursor.cc
@@ -57,6 +57,7 @@ void WebCursor::InitFromCursorInfo(const WebCursorInfo& cursor_info) {
hotspot_ = cursor_info.hotSpot;
if (IsCustom())
SetCustomData(cursor_info.customImage);
+ ClampHotspot();
}
void WebCursor::GetCursorInfo(WebCursorInfo* cursor_info) const {
@@ -100,6 +101,7 @@ bool WebCursor::Deserialize(const Pickle* pickle, void** iter) {
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) {
@@ -192,3 +194,14 @@ void WebCursor::ImageFromCustomData(WebImage* image) const {
image->assign(bitmap);
}
#endif
+
+void WebCursor::ClampHotspot() {
+ if (!IsCustom())
+ return;
+
+ // Clamp the hotspot to the custom image's dimensions.
+ hotspot_.set_x(std::max(0,
+ std::min(custom_size_.width() - 1, hotspot_.x())));
+ hotspot_.set_y(std::max(0,
+ std::min(custom_size_.height() - 1, hotspot_.y())));
+}
diff --git a/webkit/glue/webcursor.h b/webkit/glue/webcursor.h
index 293bd74..35eb001 100644
--- a/webkit/glue/webcursor.h
+++ b/webkit/glue/webcursor.h
@@ -127,6 +127,9 @@ class WebCursor {
void SetCustomData(const WebKit::WebImage& image);
void ImageFromCustomData(WebKit::WebImage* image) const;
+ // Clamp the hotspot to the custom image's bounds, if this is a custom cursor.
+ void ClampHotspot();
+
// WebCore::PlatformCursor type.
int type_;
diff --git a/webkit/glue/webcursor_gtk.cc b/webkit/glue/webcursor_gtk.cc
index 70c0f46..54c8837 100644
--- a/webkit/glue/webcursor_gtk.cc
+++ b/webkit/glue/webcursor_gtk.cc
@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
#include "base/logging.h"
+#include "gfx/gtk_util.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
using WebKit::WebCursorInfo;
@@ -171,18 +172,13 @@ GdkCursor* WebCursor::GetCustomCursor() const {
return NULL;
}
- const guchar* data = reinterpret_cast<const guchar*>(&custom_data_[0]);
- GdkPixbuf* pixbuf =
- gdk_pixbuf_new_from_data(data,
- GDK_COLORSPACE_RGB,
- TRUE, // has_alpha
- 8, // bits_per_sample
- custom_size_.width(), // width
- custom_size_.height(), // height
- custom_size_.width() * 4, // row stride
- NULL, // data destroy function
- NULL); // data destroy function extra data
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+ custom_size_.width(), custom_size_.height());
+ bitmap.allocPixels();
+ memcpy(bitmap.getAddr32(0, 0), custom_data_.data(), custom_data_.size());
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
GdkCursor* cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
pixbuf,
hotspot_.x(),
diff --git a/webkit/glue/webcursor_unittest.cc b/webkit/glue/webcursor_unittest.cc
index 5c1ddfe..6e7701d 100644
--- a/webkit/glue/webcursor_unittest.cc
+++ b/webkit/glue/webcursor_unittest.cc
@@ -4,9 +4,12 @@
#include "base/pickle.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
#include "webkit/glue/webcursor.h"
#include "webkit/tools/test_shell/test_shell_test.h"
+using WebKit::WebCursorInfo;
+
TEST(WebCursorTest, CursorSerialization) {
WebCursor custom_cursor;
// This is a valid custom cursor.
@@ -80,3 +83,36 @@ TEST(WebCursorTest, CursorSerialization) {
EXPECT_FALSE(custom_cursor.Deserialize(&neg_custom_pickle, &iter));
}
+TEST(WebCursorTest, ClampHotspot) {
+ WebCursor custom_cursor;
+ // This is a valid custom cursor.
+ Pickle ok_custom_pickle;
+ // Type and hotspots.
+ ok_custom_pickle.WriteInt(WebCursorInfo::TypeCustom);
+ // Hotspot is invalid --- outside the bounds of the image.
+ ok_custom_pickle.WriteInt(5);
+ ok_custom_pickle.WriteInt(5);
+ // X & Y
+ ok_custom_pickle.WriteInt(2);
+ ok_custom_pickle.WriteInt(2);
+ // Data len including enough data for a 2x2 image.
+ ok_custom_pickle.WriteInt(4 * 4);
+ for (size_t i = 0; i < 4; i++)
+ ok_custom_pickle.WriteUInt32(0);
+ // Custom Windows message.
+ ok_custom_pickle.WriteUInt32(0);
+ void* iter = NULL;
+ ASSERT_TRUE(custom_cursor.Deserialize(&ok_custom_pickle, &iter));
+
+ // Convert to WebCursorInfo, make sure the hotspot got clamped.
+ WebCursorInfo info;
+ custom_cursor.GetCursorInfo(&info);
+ EXPECT_EQ(gfx::Point(1, 1), gfx::Point(info.hotSpot));
+
+ // Set hotspot to an invalid point again, pipe back through WebCursor,
+ // and make sure the hotspot got clamped again.
+ info.hotSpot = gfx::Point(-1, -1);
+ custom_cursor.InitFromCursorInfo(info);
+ custom_cursor.GetCursorInfo(&info);
+ EXPECT_EQ(gfx::Point(0, 0), gfx::Point(info.hotSpot));
+}
diff --git a/webkit/glue/webdropdata.cc b/webkit/glue/webdropdata.cc
index d46987a..ea9e6c6 100644
--- a/webkit/glue/webdropdata.cc
+++ b/webkit/glue/webdropdata.cc
@@ -15,6 +15,10 @@ using WebKit::WebDragData;
using WebKit::WebString;
using WebKit::WebVector;
+WebDropData::WebDropData(int32 drag_identity)
+ : identity(drag_identity) {
+}
+
WebDropData::WebDropData(const WebDragData& drag_data)
: identity(0),
url(drag_data.url()),
@@ -36,6 +40,13 @@ WebDropData::WebDropData(const WebDragData& drag_data)
file_contents.assign(contents.data(), contents.size());
}
+WebDropData::WebDropData()
+ : identity(0) {
+}
+
+WebDropData::~WebDropData() {
+}
+
WebDragData WebDropData::ToDragData() const {
WebDragData result;
result.initialize();
diff --git a/webkit/glue/webdropdata.h b/webkit/glue/webdropdata.h
index 8149d8e..d129b06 100644
--- a/webkit/glue/webdropdata.h
+++ b/webkit/glue/webdropdata.h
@@ -24,13 +24,15 @@ class WebDragData;
struct WebDropData {
// Construct with a given drag identity. Note: identity is an int32 because
// it is passed over the renderer NPAPI interface to gears.
- explicit WebDropData(int32 drag_identity) : identity(drag_identity) {}
+ explicit WebDropData(int32 drag_identity);
// Construct from a WebDragData object.
explicit WebDropData(const WebKit::WebDragData&);
// For default constructions, use drag |identity| 0.
- WebDropData() : identity(0) {}
+ WebDropData();
+
+ ~WebDropData();
int32 identity;
diff --git a/webkit/glue/webfilesystem_impl.cc b/webkit/glue/webfileutilities_impl.cc
index 585287b..a77184d 100644
--- a/webkit/glue/webfilesystem_impl.cc
+++ b/webkit/glue/webfileutilities_impl.cc
@@ -2,7 +2,7 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
-#include "webkit/glue/webfilesystem_impl.h"
+#include "webkit/glue/webfileutilities_impl.h"
#include "base/file_path.h"
#include "base/file_util.h"
@@ -17,26 +17,30 @@ using WebKit::WebString;
namespace webkit_glue {
-WebFileSystemImpl::WebFileSystemImpl()
+WebFileUtilitiesImpl::WebFileUtilitiesImpl()
: sandbox_enabled_(true) {
}
-bool WebFileSystemImpl::fileExists(const WebString& path) {
+WebFileUtilitiesImpl::~WebFileUtilitiesImpl() {
+}
+
+bool WebFileUtilitiesImpl::fileExists(const WebString& path) {
FilePath::StringType file_path = WebStringToFilePathString(path);
return file_util::PathExists(FilePath(file_path));
}
-bool WebFileSystemImpl::deleteFile(const WebString& path) {
+bool WebFileUtilitiesImpl::deleteFile(const WebString& path) {
NOTREACHED();
return false;
}
-bool WebFileSystemImpl::deleteEmptyDirectory(const WebString& path) {
+bool WebFileUtilitiesImpl::deleteEmptyDirectory(const WebString& path) {
NOTREACHED();
return false;
}
-bool WebFileSystemImpl::getFileSize(const WebString& path, long long& result) {
+bool WebFileUtilitiesImpl::getFileSize(const WebString& path,
+ long long& result) {
if (sandbox_enabled_) {
NOTREACHED();
return false;
@@ -45,25 +49,25 @@ bool WebFileSystemImpl::getFileSize(const WebString& path, long long& result) {
reinterpret_cast<int64*>(&result));
}
-bool WebFileSystemImpl::getFileModificationTime(const WebString& path,
- double& result) {
+bool WebFileUtilitiesImpl::getFileModificationTime(const WebString& path,
+ double& result) {
if (sandbox_enabled_) {
NOTREACHED();
return false;
}
- file_util::FileInfo info;
+ base::PlatformFileInfo info;
if (!file_util::GetFileInfo(WebStringToFilePath(path), &info))
return false;
result = info.last_modified.ToDoubleT();
return true;
}
-WebString WebFileSystemImpl::directoryName(const WebString& path) {
+WebString WebFileUtilitiesImpl::directoryName(const WebString& path) {
FilePath file_path(WebStringToFilePathString(path));
return FilePathToWebString(file_path.DirName());
}
-WebString WebFileSystemImpl::pathByAppendingComponent(
+WebString WebFileUtilitiesImpl::pathByAppendingComponent(
const WebString& webkit_path,
const WebString& webkit_component) {
FilePath path(WebStringToFilePathString(webkit_path));
@@ -72,29 +76,29 @@ WebString WebFileSystemImpl::pathByAppendingComponent(
return FilePathStringToWebString(combined_path.value());
}
-bool WebFileSystemImpl::makeAllDirectories(const WebString& path) {
+bool WebFileUtilitiesImpl::makeAllDirectories(const WebString& path) {
DCHECK(!sandbox_enabled_);
FilePath::StringType file_path = WebStringToFilePathString(path);
return file_util::CreateDirectory(FilePath(file_path));
}
-WebString WebFileSystemImpl::getAbsolutePath(const WebString& path) {
+WebString WebFileUtilitiesImpl::getAbsolutePath(const WebString& path) {
FilePath file_path(WebStringToFilePathString(path));
file_util::AbsolutePath(&file_path);
return FilePathStringToWebString(file_path.value());
}
-bool WebFileSystemImpl::isDirectory(const WebString& path) {
+bool WebFileUtilitiesImpl::isDirectory(const WebString& path) {
FilePath file_path(WebStringToFilePathString(path));
return file_util::DirectoryExists(file_path);
}
-WebKit::WebURL WebFileSystemImpl::filePathToURL(const WebString& path) {
+WebKit::WebURL WebFileUtilitiesImpl::filePathToURL(const WebString& path) {
return net::FilePathToFileURL(WebStringToFilePath(path));
}
-base::PlatformFile WebFileSystemImpl::openFile(const WebString& path,
- int mode) {
+base::PlatformFile WebFileUtilitiesImpl::openFile(const WebString& path,
+ int mode) {
if (sandbox_enabled_) {
NOTREACHED();
return base::kInvalidPlatformFileValue;
@@ -103,37 +107,37 @@ base::PlatformFile WebFileSystemImpl::openFile(const WebString& path,
WebStringToFilePath(path),
(mode == 0) ? (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)
: (base::PLATFORM_FILE_CREATE_ALWAYS |
- base::PLATFORM_FILE_WRITE),
- NULL);
+ base::PLATFORM_FILE_WRITE),
+ NULL, NULL);
}
-void WebFileSystemImpl::closeFile(base::PlatformFile& handle) {
+void WebFileUtilitiesImpl::closeFile(base::PlatformFile& handle) {
if (handle == base::kInvalidPlatformFileValue)
return;
if (base::ClosePlatformFile(handle))
handle = base::kInvalidPlatformFileValue;
}
-long long WebFileSystemImpl::seekFile(base::PlatformFile handle,
- long long offset,
- int origin) {
+long long WebFileUtilitiesImpl::seekFile(base::PlatformFile handle,
+ long long offset,
+ int origin) {
if (handle == base::kInvalidPlatformFileValue)
return -1;
net::FileStream file_stream(handle, 0);
return file_stream.Seek(static_cast<net::Whence>(origin), offset);
}
-bool WebFileSystemImpl::truncateFile(base::PlatformFile handle,
- long long offset) {
+bool WebFileUtilitiesImpl::truncateFile(base::PlatformFile handle,
+ long long offset) {
if (handle == base::kInvalidPlatformFileValue || offset < 0)
return false;
net::FileStream file_stream(handle, base::PLATFORM_FILE_WRITE);
return file_stream.Truncate(offset) >= 0;
}
-int WebFileSystemImpl::readFromFile(base::PlatformFile handle,
- char* data,
- int length) {
+int WebFileUtilitiesImpl::readFromFile(base::PlatformFile handle,
+ char* data,
+ int length) {
if (handle == base::kInvalidPlatformFileValue || !data || length <= 0)
return -1;
std::string buffer;
@@ -142,9 +146,9 @@ int WebFileSystemImpl::readFromFile(base::PlatformFile handle,
return file_stream.Read(data, length, NULL);
}
-int WebFileSystemImpl::writeToFile(base::PlatformFile handle,
- const char* data,
- int length) {
+int WebFileUtilitiesImpl::writeToFile(base::PlatformFile handle,
+ const char* data,
+ int length) {
if (handle == base::kInvalidPlatformFileValue || !data || length <= 0)
return -1;
net::FileStream file_stream(handle, base::PLATFORM_FILE_WRITE);
diff --git a/webkit/glue/webfilesystem_impl.h b/webkit/glue/webfileutilities_impl.h
index 875a13b..5867396 100644
--- a/webkit/glue/webfilesystem_impl.h
+++ b/webkit/glue/webfileutilities_impl.h
@@ -2,20 +2,20 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
-#ifndef WEBFILESYSTEM_IMPL_H_
-#define WEBFILESYSTEM_IMPL_H_
+#ifndef WEBFILEUTILITIES_IMPL_H_
+#define WEBFILEUTILITIES_IMPL_H_
#include "base/platform_file.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFileSystem.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFileUtilities.h"
namespace webkit_glue {
-class WebFileSystemImpl : public WebKit::WebFileSystem {
+class WebFileUtilitiesImpl : public WebKit::WebFileUtilities {
public:
- WebFileSystemImpl();
- virtual ~WebFileSystemImpl() { }
+ WebFileUtilitiesImpl();
+ virtual ~WebFileUtilitiesImpl();
- // WebFileSystem methods:
+ // WebFileUtilities methods:
virtual bool fileExists(const WebKit::WebString& path);
virtual bool deleteFile(const WebKit::WebString& path);
virtual bool deleteEmptyDirectory(const WebKit::WebString& path);
@@ -51,4 +51,4 @@ class WebFileSystemImpl : public WebKit::WebFileSystem {
} // namespace webkit_glue
-#endif // WEBFILESYSTEM_IMPL_H_
+#endif // WEBFILEUTILITIES_IMPL_H_
diff --git a/webkit/glue/webkit_glue.cc b/webkit/glue/webkit_glue.cc
index e6b0f75..661b87b 100644
--- a/webkit/glue/webkit_glue.cc
+++ b/webkit/glue/webkit_glue.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.
@@ -16,6 +16,7 @@
#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "base/sys_info.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
@@ -41,10 +42,9 @@
#include "third_party/WebKit/WebKit/chromium/public/win/WebInputEventFactory.h"
#endif
#include "webkit/glue/glue_serialize.h"
+#include "webkit/glue/user_agent.h"
#include "v8/include/v8.h"
-#include "webkit_version.h" // Generated
-
using WebKit::WebCanvas;
using WebKit::WebData;
using WebKit::WebElement;
@@ -74,11 +74,9 @@ namespace webkit_glue {
// Global variable used by the plugin quirk "die after unload".
bool g_forcefully_terminate_plugin_process = false;
-void SetJavaScriptFlags(const std::wstring& str) {
+void SetJavaScriptFlags(const std::string& str) {
#if WEBKIT_USING_V8
- std::string utf8_str = WideToUTF8(str);
- v8::V8::SetFlagsFromString(
- utf8_str.data(), static_cast<int>(utf8_str.size()));
+ v8::V8::SetFlagsFromString(str.data(), static_cast<int>(str.size()));
#endif
}
@@ -257,8 +255,9 @@ void ResetBeforeTestRun(WebView* view) {
#ifndef NDEBUG
// The log macro was having problems due to collisions with WTF, so we just
// code here what that would have inlined.
-void DumpLeakedObject(const char* file, int line, const char* object, int count) {
- std::string msg = StringPrintf("%s LEAKED %d TIMES", object, count);
+void DumpLeakedObject(const char* file, int line, const char* object,
+ int count) {
+ std::string msg = base::StringPrintf("%s LEAKED %d TIMES", object, count);
AppendToLog(file, line, msg.c_str());
}
#endif
@@ -314,8 +313,24 @@ WebString FilePathToWebString(const FilePath& file_path) {
return FilePathStringToWebString(file_path.value());
}
-std::string GetWebKitVersion() {
- return StringPrintf("%d.%d", WEBKIT_VERSION_MAJOR, WEBKIT_VERSION_MINOR);
+WebKit::WebFileError PlatformFileErrorToWebFileError(
+ base::PlatformFileError error_code) {
+ switch (error_code) {
+ case base::PLATFORM_FILE_ERROR_NOT_FOUND:
+ return WebKit::WebFileErrorNotFound;
+ case base::PLATFORM_FILE_ERROR_INVALID_OPERATION:
+ case base::PLATFORM_FILE_ERROR_EXISTS:
+ case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
+ return WebKit::WebFileErrorInvalidModification;
+ case base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
+ return WebKit::WebFileErrorNoModificationAllowed;
+ case base::PLATFORM_FILE_ERROR_FAILED:
+ return WebKit::WebFileErrorInvalidState;
+ case base::PLATFORM_FILE_ERROR_ABORT:
+ return WebKit::WebFileErrorAbort;
+ default:
+ return WebKit::WebFileErrorInvalidModification;
+ }
}
namespace {
@@ -337,101 +352,6 @@ struct UserAgentState {
Singleton<UserAgentState> g_user_agent;
-std::string BuildOSCpuInfo() {
- std::string os_cpu;
-
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
- int32 os_major_version = 0;
- int32 os_minor_version = 0;
- int32 os_bugfix_version = 0;
- base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
- &os_minor_version,
- &os_bugfix_version);
-#endif
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- // Should work on any Posix system.
- struct utsname unixinfo;
- uname(&unixinfo);
-
- std::string cputype;
- // special case for biarch systems
- if (strcmp(unixinfo.machine, "x86_64") == 0 &&
- sizeof(void*) == sizeof(int32)) {
- cputype.assign("i686 (x86_64)");
- } else {
- cputype.assign(unixinfo.machine);
- }
-#endif
-
- StringAppendF(
- &os_cpu,
-#if defined(OS_WIN)
- "Windows NT %d.%d",
- os_major_version,
- os_minor_version
-#elif defined(OS_MACOSX)
- "Intel Mac OS X %d_%d_%d",
- os_major_version,
- os_minor_version,
- os_bugfix_version
-#elif defined(OS_CHROMEOS)
- "CrOS %s %d.%d.%d",
- cputype.c_str(), // e.g. i686
- os_major_version,
- os_minor_version,
- os_bugfix_version
-#else
- "%s %s",
- unixinfo.sysname, // e.g. Linux
- cputype.c_str() // e.g. i686
-#endif
- );
-
- return os_cpu;
-}
-
-// Construct the User-Agent header, filling in |result|.
-// The other parameters are workarounds for broken websites:
-// - If mimic_windows is true, produce a fake Windows Chrome string.
-void BuildUserAgent(bool mimic_windows, std::string* result) {
- const char kUserAgentPlatform[] =
-#if defined(OS_WIN)
- "Windows";
-#elif defined(OS_MACOSX)
- "Macintosh";
-#elif defined(USE_X11)
- "X11"; // strange, but that's what Firefox uses
-#else
- "?";
-#endif
-
- const char kUserAgentSecurity = 'U'; // "US" strength encryption
-
- // TODO(port): figure out correct locale
- const char kUserAgentLocale[] = "en-US";
-
- // Get the product name and version, and replace Safari's Version/X string
- // with it. This is done to expose our product name in a manner that is
- // maximally compatible with Safari, we hope!!
- std::string product = GetProductVersion();
-
- // Derived from Safari's UA string.
- StringAppendF(
- result,
- "Mozilla/5.0 (%s; %c; %s; %s) AppleWebKit/%d.%d"
- " (KHTML, like Gecko) %s Safari/%d.%d",
- mimic_windows ? "Windows" : kUserAgentPlatform,
- kUserAgentSecurity,
- ((mimic_windows ? "Windows " : "") + BuildOSCpuInfo()).c_str(),
- kUserAgentLocale,
- WEBKIT_VERSION_MAJOR,
- WEBKIT_VERSION_MINOR,
- product.c_str(),
- WEBKIT_VERSION_MAJOR,
- WEBKIT_VERSION_MINOR
- );
-}
-
void SetUserAgentToDefault() {
BuildUserAgent(false, &g_user_agent->user_agent);
}
@@ -455,7 +375,7 @@ const std::string& GetUserAgent(const GURL& url) {
if (!g_user_agent->user_agent_is_overridden) {
// Workarounds for sites that use misguided UA sniffing.
#if defined(OS_POSIX) && !defined(OS_MACOSX)
- if (MatchPatternASCII(url.host(), "*.mail.yahoo.com")) {
+ 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.
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index 49320fc..f5d03c4 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -105,21 +105,12 @@
],
},
{
- 'target_name': 'glue',
+ 'target_name': 'webkit_user_agent',
'type': '<(library)',
- 'msvs_guid': 'C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09',
+ 'msvs_guid': 'DB162DE1-7D56-4C4A-8A9F-80D396CD7AA8',
'dependencies': [
'<(DEPTH)/app/app.gyp:app_base',
'<(DEPTH)/base/base.gyp:base_i18n',
- '<(DEPTH)/net/net.gyp:net',
- '<(DEPTH)/printing/printing.gyp:printing',
- '<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/third_party/icu/icu.gyp:icui18n',
- '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
- '<(DEPTH)/third_party/npapi/npapi.gyp:npapi',
- '<(DEPTH)/third_party/ppapi/ppapi.gyp:ppapi_c',
- 'webkit_resources',
- 'webkit_strings',
],
'actions': [
{
@@ -136,14 +127,46 @@
],
'include_dirs': [
'<(INTERMEDIATE_DIR)',
+ ],
+ 'sources': [
+ 'user_agent.cc',
+ 'user_agent.h',
+ ],
+ # Dependents may rely on files generated by this target or one of its
+ # own hard dependencies.
+ 'hard_dependency': 1,
+ 'conditions': [
+ ],
+ },
+ {
+ 'target_name': 'glue',
+ 'type': '<(library)',
+ 'msvs_guid': 'C66B126D-0ECE-4CA2-B6DC-FA780AFBBF09',
+ 'dependencies': [
+ '<(DEPTH)/app/app.gyp:app_base',
+ '<(DEPTH)/base/base.gyp:base_i18n',
+ '<(DEPTH)/gpu/gpu.gyp:gles2_implementation',
+ '<(DEPTH)/net/net.gyp:net',
+ '<(DEPTH)/printing/printing.gyp:printing',
+ '<(DEPTH)/skia/skia.gyp:skia',
+ '<(DEPTH)/third_party/icu/icu.gyp:icui18n',
+ '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
+ '<(DEPTH)/third_party/npapi/npapi.gyp:npapi',
+ '<(DEPTH)/third_party/ppapi/ppapi.gyp:ppapi_c',
+ 'webkit_resources',
+ 'webkit_strings',
+ 'webkit_user_agent',
+ ],
+ 'actions': [
+ ],
+ 'include_dirs': [
+ '<(INTERMEDIATE_DIR)',
'<(SHARED_INTERMEDIATE_DIR)/webkit',
],
'sources': [
# 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.
- 'devtools_message_data.cc',
- 'devtools_message_data.h',
'media/buffered_data_source.cc',
'media/buffered_data_source.h',
'media/media_resource_loader_bridge_factory.cc',
@@ -164,12 +187,18 @@
'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_device_context_2d.cc',
- 'plugins/pepper_device_context_2d.h',
+ 'plugins/pepper_char_set.cc',
+ 'plugins/pepper_char_set.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_chooser.cc',
@@ -182,6 +211,8 @@
'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',
@@ -189,22 +220,32 @@
'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_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_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',
@@ -258,6 +299,7 @@
'plugins/webplugininfo.h',
'alt_error_page_resource_fetcher.cc',
'alt_error_page_resource_fetcher.h',
+ 'context_menu.cc',
'context_menu.h',
'cpp_binding_example.cc',
'cpp_binding_example.h',
@@ -267,6 +309,7 @@
'cpp_variant.h',
'dom_operations.cc',
'dom_operations.h',
+ 'form_data.cc',
'form_data.h',
'form_field.cc',
'form_field.h',
@@ -274,6 +317,8 @@
'ftp_directory_listing_response_delegate.h',
'glue_serialize.cc',
'glue_serialize.h',
+ 'idb_bindings.cc',
+ 'idb_bindings.h',
'image_decoder.cc',
'image_decoder.h',
'image_resource_fetcher.cc',
@@ -282,6 +327,7 @@
'multipart_response_delegate.h',
'npruntime_util.cc',
'npruntime_util.h',
+ 'password_form.cc',
'password_form.h',
'password_form_dom_manager.cc',
'password_form_dom_manager.h',
@@ -299,6 +345,7 @@
'webaccessibility.h',
'webclipboard_impl.cc',
'webclipboard_impl.h',
+ 'webcookie.cc',
'webcookie.h',
'webcursor.cc',
'webcursor.h',
@@ -309,8 +356,8 @@
'webdropdata.cc',
'webdropdata_win.cc',
'webdropdata.h',
- 'webfilesystem_impl.cc',
- 'webfilesystem_impl.h',
+ 'webfileutilities_impl.cc',
+ 'webfileutilities_impl.h',
'webkit_glue.cc',
'webkit_glue.h',
'webkitclient_impl.cc',
@@ -331,6 +378,8 @@
'webthemeengine_impl_win.cc',
'weburlloader_impl.cc',
'weburlloader_impl.h',
+ 'webvideoframe_impl.cc',
+ 'webvideoframe_impl.h',
'window_open_disposition.h',
'window_open_disposition.cc',
@@ -344,8 +393,6 @@
'../extensions/v8/gears_extension.h',
'../extensions/v8/heap_profiler_extension.cc',
'../extensions/v8/heap_profiler_extension.h',
- '../extensions/v8/interval_extension.cc',
- '../extensions/v8/interval_extension.h',
'../extensions/v8/playback_extension.cc',
'../extensions/v8/playback_extension.h',
'../extensions/v8/profiler_extension.cc',
@@ -375,11 +422,16 @@
'sources/': [['exclude', 'plugin_(lib|list)_posix\\.cc$']],
'link_settings': {
'libraries': [
- '$(SDKROOT)/QuartzCore.framework',
+ '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
],
},
}],
['enable_gpu==1 and inside_chromium_build==1', {
+ 'sources': [
+ 'plugins/pepper_graphics_3d_gl.cc',
+ 'plugins/pepper_graphics_3d.cc',
+ 'plugins/pepper_graphics_3d.h',
+ ],
'dependencies': [
'<(DEPTH)/gpu/gpu.gyp:gpu_plugin',
],
diff --git a/webkit/glue/webkit_glue.h b/webkit/glue/webkit_glue.h
index 541836b..380bf36 100644
--- a/webkit/glue/webkit_glue.h
+++ b/webkit/glue/webkit_glue.h
@@ -16,8 +16,10 @@
#include "app/clipboard/clipboard.h"
#include "base/file_path.h"
+#include "base/platform_file.h"
#include "base/string16.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFileError.h"
class GURL;
class SkBitmap;
@@ -42,7 +44,7 @@ namespace webkit_glue {
//---- BEGIN FUNCTIONS IMPLEMENTED BY WEBKIT/GLUE -----------------------------
-void SetJavaScriptFlags(const std::wstring& flags);
+void SetJavaScriptFlags(const std::string& flags);
// Turn on the logging for notImplemented() calls from WebCore.
void EnableWebCoreNotImplementedLogging();
@@ -132,6 +134,10 @@ WebKit::WebString FilePathStringToWebString(const FilePath::StringType& str);
FilePath WebStringToFilePath(const WebKit::WebString& str);
WebKit::WebString FilePathToWebString(const FilePath& file_path);
+// File error conversion
+WebKit::WebFileError PlatformFileErrorToWebFileError(
+ base::PlatformFileError error_code);
+
// Returns a WebCanvas pointer associated with the given Skia canvas.
WebKit::WebCanvas* ToWebCanvas(skia::PlatformCanvas*);
@@ -248,7 +254,7 @@ bool FindProxyForUrl(const GURL& url, std::string* proxy_list);
// Returns the locale that this instance of webkit is running as. This is of
// the form language-country (e.g., en-US or pt-BR).
-std::wstring GetWebKitLocale();
+std::string GetWebKitLocale();
// Close current connections. Used for debugging.
void CloseCurrentConnections();
@@ -265,6 +271,9 @@ std::string GetProductVersion();
// Returns true if the embedder is running in single process mode.
bool IsSingleProcess();
+// Enables/Disables Spdy for requests afterwards. Used for benchmarking.
+void EnableSpdy(bool enable);
+
#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/webkit_resources.grd b/webkit/glue/webkit_resources.grd
index a2146fd..94d4286 100644
--- a/webkit/glue/webkit_resources.grd
+++ b/webkit/glue/webkit_resources.grd
@@ -14,6 +14,9 @@
<include name="IDC_CELL" file="resources\cell.cur" type="CURSOR" />
<include name="IDC_COLRESIZE" file="resources\col_resize.cur" type="CURSOR" />
<include name="IDC_COPYCUR" file="resources\copy.cur" type="CURSOR" />
+ <include name="IDR_INPUT_SPEECH" file="resources\input_speech.png" type="BINDATA" />
+ <include name="IDR_INPUT_SPEECH_RECORDING" file="resources\input_speech_recording.png" type="BINDATA" />
+ <include name="IDR_INPUT_SPEECH_WAITING" file="resources\input_speech_waiting.png" type="BINDATA" />
<include name="IDR_MEDIA_PAUSE_BUTTON" file="resources\media_pause.png" type="BINDATA" />
<include name="IDR_MEDIA_PLAY_BUTTON" file="resources\media_play.png" type="BINDATA" />
<include name="IDR_MEDIA_PLAY_BUTTON_DISABLED" file="resources\media_play_disabled.png" type="BINDATA" />
@@ -42,6 +45,37 @@
<include name="IDC_VERTICALTEXT" file="resources\vertical_text.cur" type="CURSOR" />
<include name="IDC_ZOOMIN" file="resources\zoom_in.cur" type="CURSOR" />
<include name="IDC_ZOOMOUT" file="resources\zoom_out.cur" type="CURSOR" />
+ <include name="IDR_AUTOFILL_CC_AMEX" file="resources\amex.png" type="BINDATA" />
+ <include name="IDR_AUTOFILL_CC_DINERS" file="resources\diners.png" type="BINDATA" />
+ <include name="IDR_AUTOFILL_CC_DISCOVER" file="resources\discover.png" type="BINDATA" />
+ <include name="IDR_AUTOFILL_CC_GENERIC" file="resources\cc-generic.png" type="BINDATA" />
+ <include name="IDR_AUTOFILL_CC_JCB" file="resources\jcb.png" type="BINDATA" />
+ <include name="IDR_AUTOFILL_CC_MASTERCARD" file="resources\mastercard.png" type="BINDATA" />
+ <include name="IDR_AUTOFILL_CC_SOLO" file="resources\solo.png" type="BINDATA" />
+ <include name="IDR_AUTOFILL_CC_VISA" file="resources\visa.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_FTH" file="resources\pdf_button_fth.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_FTH_HOVER" file="resources\pdf_button_fth_hover.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_FTH_PRESSED" file="resources\pdf_button_fth_pressed.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_FTW" file="resources\pdf_button_ftw.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_FTW_HOVER" file="resources\pdf_button_ftw_hover.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_FTW_PRESSED" file="resources\pdf_button_ftw_pressed.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_ZOOMIN" file="resources\pdf_button_zoomin.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_ZOOMIN_HOVER" file="resources\pdf_button_zoomin_hover.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_ZOOMIN_PRESSED" file="resources\pdf_button_zoomin_pressed.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_ZOOMOUT" file="resources\pdf_button_zoomout.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_ZOOMOUT_HOVER" file="resources\pdf_button_zoomout_hover.png" type="BINDATA" />
+ <include name="IDR_PDF_BUTTON_ZOOMOUT_PRESSED" file="resources\pdf_button_zoomout_pressed.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_0" file="resources\pdf_thumbnail_0.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_1" file="resources\pdf_thumbnail_1.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_2" file="resources\pdf_thumbnail_2.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_3" file="resources\pdf_thumbnail_3.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_4" file="resources\pdf_thumbnail_4.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_5" file="resources\pdf_thumbnail_5.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_6" file="resources\pdf_thumbnail_6.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_7" file="resources\pdf_thumbnail_7.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_8" file="resources\pdf_thumbnail_8.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_9" file="resources\pdf_thumbnail_9.png" type="BINDATA" />
+ <include name="IDR_PDF_THUMBNAIL_NUM_BACKGROUND" file="resources\pdf_thumbnail_num_background.png" type="BINDATA" />
<if expr="os == 'linux2' or os.find('bsd') != -1 or os == 'sunos5'">
<include name="IDR_LINUX_CHECKBOX_DISABLED_INDETERMINATE" file="resources\linux-checkbox-disabled-indeterminate.png" type="BINDATA" />
diff --git a/webkit/glue/webkit_strings.grd b/webkit/glue/webkit_strings.grd
index cbb1c7f..3cc2a98 100644
--- a/webkit/glue/webkit_strings.grd
+++ b/webkit/glue/webkit_strings.grd
@@ -59,6 +59,7 @@ below:
<output filename="webkit_strings_es.rc" type="rc_all" lang="es" />
<output filename="webkit_strings_es-419.rc" type="rc_all" lang="es-419" />
<output filename="webkit_strings_et.rc" type="rc_all" lang="et" />
+ <output filename="webkit_strings_fa.rc" type="rc_all" lang="fa" />
<output filename="webkit_strings_fi.rc" type="rc_all" lang="fi" />
<output filename="webkit_strings_fil.rc" type="rc_all" lang="fil" />
<output filename="webkit_strings_fr.rc" type="rc_all" lang="fr" />
@@ -113,6 +114,7 @@ below:
<output filename="webkit_strings_es.pak" type="data_package" lang="es" />
<output filename="webkit_strings_es-419.pak" type="data_package" lang="es-419" />
<output filename="webkit_strings_et.pak" type="data_package" lang="et" />
+ <output filename="webkit_strings_fa.pak" type="data_package" lang="fa" />
<output filename="webkit_strings_fi.pak" type="data_package" lang="fi" />
<output filename="webkit_strings_fil.pak" type="data_package" lang="fil" />
<output filename="webkit_strings_fr.pak" type="data_package" lang="fr" />
@@ -167,6 +169,7 @@ below:
<file path="resources/webkit_strings_es.xtb" lang="es" />
<file path="resources/webkit_strings_es-419.xtb" lang="es-419" />
<file path="resources/webkit_strings_et.xtb" lang="et" />
+ <file path="resources/webkit_strings_fa.xtb" lang="fa" />
<file path="resources/webkit_strings_fi.xtb" lang="fi" />
<file path="resources/webkit_strings_fil.xtb" lang="fil" />
<file path="resources/webkit_strings_fr.xtb" lang="fr" />
@@ -253,7 +256,7 @@ below:
</message>
<message name="IDS_AX_ROLE_WEB_AREA" desc="accessibility role description for web area">
- web area
+ HTML content
</message>
<message name="IDS_AX_ROLE_LINK" desc="accessibility role description for link">
link
@@ -359,6 +362,14 @@ below:
<message name="IDS_PDF_NEED_PASSWORD" desc="A message asking the user for a password to open a PDF file.">
This document is password protected. Please enter a password.
</message>
+
+ <message name="IDS_PDF_PAGE_LOADING" desc="A message displayed on the PDF page while page is loading.">
+ Loading...
+ </message>
+
+ <message name="IDS_PDF_LOADING_PROGRESS" desc="A message displayed on the PDF control to indicate loading progress.">
+ Loading document: <ph name="PAGE_NUMBER">%d<ex>3</ex></ph>/<ph name="NUMBER_OF_PAGES">%d<ex>15</ex></ph> pages...
+ </message>
</messages>
</release>
</grit>
diff --git a/webkit/glue/webkitclient_impl.cc b/webkit/glue/webkitclient_impl.cc
index b05e7d9..c65d176 100644
--- a/webkit/glue/webkitclient_impl.cc
+++ b/webkit/glue/webkitclient_impl.cc
@@ -18,6 +18,8 @@
#include "base/platform_file.h"
#include "base/singleton.h"
#include "base/stats_counters.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/trace_event.h"
@@ -165,6 +167,9 @@ WebKitClientImpl::WebKitClientImpl()
shared_timer_suspended_(0) {
}
+WebKitClientImpl::~WebKitClientImpl() {
+}
+
WebThemeEngine* WebKitClientImpl::themeEngine() {
#if defined(OS_WIN)
return &theme_engine_;
@@ -250,6 +255,17 @@ WebData WebKitClientImpl::loadResource(const char* name) {
{ "searchMagnifierResults", IDR_SEARCH_MAGNIFIER_RESULTS },
{ "textAreaResizeCorner", IDR_TEXTAREA_RESIZER },
{ "tickmarkDash", IDR_TICKMARK_DASH },
+ { "inputSpeech", IDR_INPUT_SPEECH },
+ { "inputSpeechRecording", IDR_INPUT_SPEECH_RECORDING },
+ { "inputSpeechWaiting", IDR_INPUT_SPEECH_WAITING },
+ { "americanExpressCC", IDR_AUTOFILL_CC_AMEX },
+ { "dinersCC", IDR_AUTOFILL_CC_DINERS },
+ { "discoverCC", IDR_AUTOFILL_CC_DISCOVER },
+ { "genericCC", IDR_AUTOFILL_CC_GENERIC },
+ { "jcbCC", IDR_AUTOFILL_CC_JCB },
+ { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD },
+ { "soloCC", IDR_AUTOFILL_CC_SOLO },
+ { "visaCC", IDR_AUTOFILL_CC_VISA },
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// TODO(port): rename these to "skia" instead of "Linux".
{ "linuxCheckboxDisabledIndeterminate",
@@ -275,7 +291,9 @@ WebData WebKitClientImpl::loadResource(const char* name) {
return WebData(resource.data(), resource.size());
}
}
- NOTREACHED() << "Unknown image resource " << name;
+ // TODO(jhawkins): Restore this NOTREACHED once WK stops sending in empty
+ // strings. http://crbug.com/50675.
+ //NOTREACHED() << "Unknown image resource " << name;
return WebData();
}
@@ -293,7 +311,7 @@ WebString WebKitClientImpl::queryLocalizedString(
if (message_id < 0)
return WebString();
return ReplaceStringPlaceholders(GetLocalizedString(message_id),
- IntToString16(numeric_value),
+ base::IntToString16(numeric_value),
NULL);
}
@@ -406,10 +424,11 @@ static size_t memoryUsageMBGeneric() {
}
#endif
-size_t WebKitClientImpl::memoryUsageMB() {
+static size_t getMemoryUsageMB(bool bypass_cache) {
size_t current_mem_usage = 0;
MemoryUsageCache* mem_usage_cache_singleton = MemoryUsageCache::Get();
- if (mem_usage_cache_singleton->IsCachedValueValid(&current_mem_usage))
+ if (!bypass_cache &&
+ mem_usage_cache_singleton->IsCachedValueValid(&current_mem_usage))
return current_mem_usage;
current_mem_usage =
@@ -424,6 +443,14 @@ size_t WebKitClientImpl::memoryUsageMB() {
return current_mem_usage;
}
+size_t WebKitClientImpl::memoryUsageMB() {
+ return getMemoryUsageMB(false);
+}
+
+size_t WebKitClientImpl::actualMemoryUsageMB() {
+ return getMemoryUsageMB(true);
+}
+
void WebKitClientImpl::SuspendSharedTimer() {
++shared_timer_suspended_;
}
diff --git a/webkit/glue/webkitclient_impl.h b/webkit/glue/webkitclient_impl.h
index bec7a79..607677f 100644
--- a/webkit/glue/webkitclient_impl.h
+++ b/webkit/glue/webkitclient_impl.h
@@ -19,7 +19,7 @@ namespace webkit_glue {
class WebKitClientImpl : public WebKit::WebKitClient {
public:
WebKitClientImpl();
- virtual ~WebKitClientImpl() {}
+ virtual ~WebKitClientImpl();
// WebKitClient methods (partial implementation):
virtual WebKit::WebThemeEngine* themeEngine();
@@ -35,6 +35,7 @@ class WebKitClientImpl : public WebKit::WebKitClient {
unsigned key_size_index, const WebKit::WebString& challenge,
const WebKit::WebURL& url);
virtual size_t memoryUsageMB();
+ virtual size_t actualMemoryUsageMB();
virtual WebKit::WebURLLoader* createURLLoader();
virtual WebKit::WebSocketStreamHandle* createSocketStreamHandle();
virtual WebKit::WebString userAgent(const WebKit::WebURL& url);
diff --git a/webkit/glue/webmediaplayer_impl.cc b/webkit/glue/webmediaplayer_impl.cc
index 51d67ab..d5c667d 100644
--- a/webkit/glue/webmediaplayer_impl.cc
+++ b/webkit/glue/webmediaplayer_impl.cc
@@ -4,11 +4,14 @@
#include "webkit/glue/webmediaplayer_impl.h"
+#include <limits>
+
#include "base/callback.h"
#include "base/command_line.h"
#include "media/base/limits.h"
#include "media/base/media_format.h"
#include "media/base/media_switches.h"
+#include "media/base/video_frame.h"
#include "media/filters/ffmpeg_audio_decoder.h"
#include "media/filters/ffmpeg_demuxer.h"
#include "media/filters/ffmpeg_video_decoder.h"
@@ -17,8 +20,10 @@
#include "third_party/WebKit/WebKit/chromium/public/WebRect.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/WebVideoFrame.h"
#include "webkit/glue/media/video_renderer_impl.h"
#include "webkit/glue/media/web_video_renderer.h"
+#include "webkit/glue/webvideoframe_impl.h"
using WebKit::WebCanvas;
using WebKit::WebRect;
@@ -178,6 +183,18 @@ void WebMediaPlayerImpl::Proxy::NetworkEventTask() {
}
}
+void WebMediaPlayerImpl::Proxy::GetCurrentFrame(
+ scoped_refptr<media::VideoFrame>* frame_out) {
+ if (video_renderer_)
+ video_renderer_->GetCurrentFrame(frame_out);
+}
+
+void WebMediaPlayerImpl::Proxy::PutCurrentFrame(
+ scoped_refptr<media::VideoFrame> frame) {
+ if (video_renderer_)
+ video_renderer_->PutCurrentFrame(frame);
+}
+
/////////////////////////////////////////////////////////////////////////////
// WebMediaPlayerImpl implementation
@@ -417,7 +434,10 @@ bool WebMediaPlayerImpl::seeking() const {
float WebMediaPlayerImpl::duration() const {
DCHECK(MessageLoop::current() == main_loop_);
- return static_cast<float>(pipeline_->GetMediaDuration().InSecondsF());
+ base::TimeDelta duration = pipeline_->GetMediaDuration();
+ if (duration.InMicroseconds() == media::Limits::kMaxTimeInMicroseconds)
+ return std::numeric_limits<float>::infinity();
+ return static_cast<float>(duration.InSecondsF());
}
float WebMediaPlayerImpl::currentTime() const {
@@ -562,6 +582,24 @@ WebKit::WebMediaPlayer::MovieLoadType
return WebKit::WebMediaPlayer::Unknown;
}
+WebKit::WebVideoFrame* WebMediaPlayerImpl::getCurrentFrame() {
+ scoped_refptr<media::VideoFrame> video_frame;
+ proxy_->GetCurrentFrame(&video_frame);
+ if (video_frame.get())
+ return new WebVideoFrameImpl(video_frame);
+ return NULL;
+}
+
+void WebMediaPlayerImpl::putCurrentFrame(
+ WebKit::WebVideoFrame* web_video_frame) {
+ if (web_video_frame) {
+ scoped_refptr<media::VideoFrame> video_frame =
+ WebVideoFrameImpl::toVideoFrame(web_video_frame);
+ proxy_->PutCurrentFrame(video_frame);
+ delete web_video_frame;
+ }
+}
+
void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() {
Destroy();
main_loop_ = NULL;
@@ -657,10 +695,16 @@ void WebMediaPlayerImpl::OnPipelineError() {
void WebMediaPlayerImpl::OnNetworkEvent() {
DCHECK(MessageLoop::current() == main_loop_);
if (pipeline_->GetError() == media::PIPELINE_OK) {
- if (pipeline_->IsNetworkActive())
+ if (pipeline_->IsNetworkActive()) {
SetNetworkState(WebKit::WebMediaPlayer::Loading);
- else
+ } else {
+ // If we are inactive because we just finished receiving all the data,
+ // do one final repaint to show final progress.
+ if (bytesLoaded() == totalBytes() &&
+ network_state_ != WebKit::WebMediaPlayer::Idle)
+ Repaint();
SetNetworkState(WebKit::WebMediaPlayer::Idle);
+ }
}
}
diff --git a/webkit/glue/webmediaplayer_impl.h b/webkit/glue/webmediaplayer_impl.h
index e8794dc..eefe1a9 100644
--- a/webkit/glue/webmediaplayer_impl.h
+++ b/webkit/glue/webmediaplayer_impl.h
@@ -53,8 +53,6 @@
#ifndef WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_
#define WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_
-#include <vector>
-
#include "base/lock.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
@@ -103,6 +101,8 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect);
void SetSize(const gfx::Rect& rect);
void Detach();
+ void GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out);
+ void PutCurrentFrame(scoped_refptr<media::VideoFrame> frame);
// Public methods called from the pipeline via callback issued by
// WebMediaPlayerImpl.
@@ -230,6 +230,9 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
virtual bool hasSingleSecurityOrigin() const;
virtual WebKit::WebMediaPlayer::MovieLoadType movieLoadType() const;
+ virtual WebKit::WebVideoFrame* getCurrentFrame();
+ virtual void putCurrentFrame(WebKit::WebVideoFrame* web_video_frame);
+
// As we are closing the tab or even the browser, |main_loop_| is destroyed
// even before this object gets destructed, so we need to know when
// |main_loop_| is being destroyed and we can stop posting repaint task
diff --git a/webkit/glue/webmenurunner_mac.mm b/webkit/glue/webmenurunner_mac.mm
index e4c8a4b..b7e48ba 100644
--- a/webkit/glue/webmenurunner_mac.mm
+++ b/webkit/glue/webmenurunner_mac.mm
@@ -131,11 +131,19 @@ BOOL gNewNSMenuAPI;
[button selectItemAtIndex:index];
[button setFont:[NSFont menuFontOfSize:fontSize_]];
+ // Create a dummy view to associate the popup with, since the OS will use
+ // that view for positioning the menu.
+ NSView* dummyView = [[[NSView alloc] initWithFrame:bounds] autorelease];
+ [view addSubview:dummyView];
+ NSRect dummyBounds = [dummyView convertRect:bounds fromView:view];
+
// Display the menu, and set a flag if a menu item was chosen.
- [button performClickWithFrame:bounds inView:view];
+ [button performClickWithFrame:dummyBounds inView:dummyView];
if ([self menuItemWasChosen])
index_ = [button indexOfSelectedItem];
+
+ [dummyView removeFromSuperview];
}
}
diff --git a/webkit/glue/webpasswordautocompletelistener_impl.cc b/webkit/glue/webpasswordautocompletelistener_impl.cc
index 6f6e754..fc15af0 100644
--- a/webkit/glue/webpasswordautocompletelistener_impl.cc
+++ b/webkit/glue/webpasswordautocompletelistener_impl.cc
@@ -59,15 +59,18 @@ void WebInputElementDelegate::RefreshAutofillPopup(
if (webview) {
std::vector<string16> names;
std::vector<string16> labels;
+ std::vector<string16> icons;
std::vector<int> unique_ids;
for (size_t i = 0; i < suggestions.size(); ++i) {
names.push_back(suggestions[i]);
labels.push_back(string16());
+ icons.push_back(string16());
unique_ids.push_back(0);
}
- webview->applyAutoFillSuggestions(element_, names, labels, unique_ids, -1);
+ webview->applyAutoFillSuggestions(
+ element_, names, labels, icons, unique_ids, -1);
}
}
@@ -80,6 +83,9 @@ WebPasswordAutocompleteListenerImpl::WebPasswordAutocompleteListenerImpl(
data_(data) {
}
+WebPasswordAutocompleteListenerImpl::~WebPasswordAutocompleteListenerImpl() {
+}
+
void WebPasswordAutocompleteListenerImpl::didBlurInputElement(
const WebString& user_input) {
// If this listener exists, its because the password manager had more than
diff --git a/webkit/glue/webpasswordautocompletelistener_impl.h b/webkit/glue/webpasswordautocompletelistener_impl.h
index 4fea455..8180a47 100644
--- a/webkit/glue/webpasswordautocompletelistener_impl.h
+++ b/webkit/glue/webpasswordautocompletelistener_impl.h
@@ -49,8 +49,7 @@ class WebPasswordAutocompleteListenerImpl :
WebInputElementDelegate* username_element,
WebInputElementDelegate* password_element,
const PasswordFormFillData& data);
- ~WebPasswordAutocompleteListenerImpl() {
- }
+ virtual ~WebPasswordAutocompleteListenerImpl();
// WebKit::PasswordAutocompleteListener methods:
virtual void didBlurInputElement(const WebString& user_input);
diff --git a/webkit/glue/webpasswordautocompletelistener_unittest.cc b/webkit/glue/webpasswordautocompletelistener_unittest.cc
index 5a05d46..0ce2916 100644
--- a/webkit/glue/webpasswordautocompletelistener_unittest.cc
+++ b/webkit/glue/webpasswordautocompletelistener_unittest.cc
@@ -9,6 +9,7 @@
#include <string>
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/form_field.h"
#include "webkit/glue/webpasswordautocompletelistener_impl.h"
diff --git a/webkit/glue/webpreferences.cc b/webkit/glue/webpreferences.cc
index 987cef4..ddf4ddb 100644
--- a/webkit/glue/webpreferences.cc
+++ b/webkit/glue/webpreferences.cc
@@ -59,7 +59,8 @@ void WebPreferences::Apply(WebView* web_view) const {
WebRuntimeFeatures::enableDatabase(
WebRuntimeFeatures::isDatabaseEnabled() || databases_enabled);
settings->setOfflineWebApplicationCacheEnabled(application_cache_enabled);
- settings->setHTML5ParserEnabled(enable_html5_parser);
+ settings->setCaretBrowsingEnabled(caret_browsing_enabled);
+ settings->setHyperlinkAuditingEnabled(hyperlink_auditing_enabled);
// This setting affects the behavior of links in an editable region:
// clicking the link should select it rather than navigate to it.
@@ -87,7 +88,8 @@ void WebPreferences::Apply(WebView* web_view) const {
// Enable experimental WebGL support if requested on command line
// and support is compiled in.
- settings->setExperimentalWebGLEnabled(experimental_webgl_enabled);
+ settings->setExperimentalWebGLEnabled(
+ WebRuntimeFeatures::isWebGLEnabled() || experimental_webgl_enabled);
// Display colored borders around composited render layers if requested
// on command line.
@@ -96,6 +98,9 @@ void WebPreferences::Apply(WebView* web_view) const {
// Enable gpu-accelerated compositing if requested on the command line.
settings->setAcceleratedCompositingEnabled(accelerated_compositing_enabled);
+ // Enable gpu-accelerated 2d canvas if requested on the command line.
+ settings->setAccelerated2dCanvasEnabled(accelerated_2d_canvas_enabled);
+
// Enable memory info reporting to page if requested on the command line.
settings->setMemoryInfoEnabled(memory_info_enabled);
diff --git a/webkit/glue/webpreferences.h b/webkit/glue/webpreferences.h
index 3e4f926..bc6d477 100644
--- a/webkit/glue/webpreferences.h
+++ b/webkit/glue/webpreferences.h
@@ -55,6 +55,8 @@ struct WebPreferences {
bool databases_enabled;
bool application_cache_enabled;
bool tabs_to_links;
+ bool caret_browsing_enabled;
+ bool hyperlink_auditing_enabled;
bool user_style_sheet_enabled;
GURL user_style_sheet_location;
@@ -64,7 +66,7 @@ struct WebPreferences {
bool experimental_webgl_enabled;
bool show_composited_layer_borders;
bool accelerated_compositing_enabled;
- bool enable_html5_parser;
+ bool accelerated_2d_canvas_enabled;
bool memory_info_enabled;
// We try to keep the default values the same as the default values in
@@ -103,6 +105,8 @@ struct WebPreferences {
databases_enabled(false),
application_cache_enabled(false),
tabs_to_links(true),
+ caret_browsing_enabled(false),
+ hyperlink_auditing_enabled(false),
user_style_sheet_enabled(false),
author_and_user_styles_enabled(true),
allow_universal_access_from_file_urls(false),
@@ -110,7 +114,7 @@ struct WebPreferences {
experimental_webgl_enabled(false),
show_composited_layer_borders(false),
accelerated_compositing_enabled(false),
- enable_html5_parser(true),
+ accelerated_2d_canvas_enabled(false),
memory_info_enabled(false) {
}
diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc
index f235734..aa63fc2 100644
--- a/webkit/glue/weburlloader_impl.cc
+++ b/webkit/glue/weburlloader_impl.cc
@@ -132,6 +132,8 @@ ResourceType::Type FromTargetType(WebURLRequest::TargetType type) {
return ResourceType::WORKER;
case WebURLRequest::TargetIsSharedWorker:
return ResourceType::SHARED_WORKER;
+ case WebURLRequest::TargetIsPrefetch:
+ return ResourceType::PREFETCH;
default:
NOTREACHED();
return ResourceType::SUB_RESOURCE;
@@ -182,6 +184,7 @@ void PopulateURLResponse(
response->setWasFetchedViaProxy(info.was_fetched_via_proxy);
response->setConnectionID(info.connection_id);
response->setConnectionReused(info.connection_reused);
+ response->setDownloadFilePath(FilePathToWebString(info.download_file_path));
WebURLLoadTiming timing;
timing.initialize();
@@ -213,7 +216,7 @@ void PopulateURLResponse(
// pass it to GetSuggestedFilename.
std::string value;
if (headers->EnumerateHeader(NULL, "content-disposition", &value)) {
- response->setSuggestedFileName(webkit_glue::FilePathToWebString(
+ response->setSuggestedFileName(FilePathToWebString(
net::GetSuggestedFilename(url, value, "", FilePath())));
}
@@ -260,10 +263,13 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
GURL* new_first_party_for_cookies);
virtual void OnReceivedResponse(
const ResourceLoaderBridge::ResponseInfo& info, bool content_filtered);
+ virtual void OnDownloadedData(int len);
virtual void OnReceivedData(const char* data, int len);
virtual void OnReceivedCachedMetadata(const char* data, int len);
virtual void OnCompletedRequest(
- const URLRequestStatus& status, const std::string& security_info);
+ const URLRequestStatus& status,
+ const std::string& security_info,
+ const base::Time& completion_time);
virtual GURL GetURLForDebugging() const;
private:
@@ -278,6 +284,7 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
scoped_ptr<ResourceLoaderBridge> bridge_;
scoped_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_;
scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
+ scoped_ptr<ResourceLoaderBridge> completed_bridge_;
// TODO(japhet): Storing this is a temporary hack for site isolation logging.
WebURL response_url_;
@@ -384,7 +391,7 @@ void WebURLLoaderImpl::Context::Start(
// TODO(brettw) this should take parameter encoding into account when
// creating the GURLs.
- webkit_glue::ResourceLoaderBridge::RequestInfo request_info;
+ ResourceLoaderBridge::RequestInfo request_info;
request_info.method = method;
request_info.url = url;
request_info.first_party_for_cookies = request.firstPartyForCookies();
@@ -397,6 +404,7 @@ void WebURLLoaderImpl::Context::Start(
request_info.request_type = FromTargetType(request.targetType());
request_info.appcache_host_id = request.appCacheHostID();
request_info.routing_id = request.requestorID();
+ request_info.download_to_file = request.downloadToFile();
bridge_.reset(ResourceLoaderBridge::Create(request_info));
if (!request.httpBody().isNull()) {
@@ -424,9 +432,12 @@ void WebURLLoaderImpl::Context::Start(
WebStringToFilePath(element.filePath),
static_cast<uint64>(element.fileStart),
static_cast<uint64>(element.fileLength),
- base::Time::FromDoubleT(element.fileInfo.modificationTime));
+ base::Time::FromDoubleT(element.modificationTime));
}
break;
+ case WebHTTPBody::Element::TypeBlob:
+ bridge_->AppendBlobToUpload(GURL(element.blobURL));
+ break;
default:
NOTREACHED();
}
@@ -545,6 +556,11 @@ void WebURLLoaderImpl::Context::OnReceivedResponse(
response_url_ = response.url();
}
+void WebURLLoaderImpl::Context::OnDownloadedData(int len) {
+ if (client_)
+ client_->didDownloadData(loader_, len);
+}
+
void WebURLLoaderImpl::Context::OnReceivedData(const char* data, int len) {
if (!client_)
return;
@@ -573,7 +589,8 @@ void WebURLLoaderImpl::Context::OnReceivedCachedMetadata(
void WebURLLoaderImpl::Context::OnCompletedRequest(
const URLRequestStatus& status,
- const std::string& security_info) {
+ const std::string& security_info,
+ const base::Time& completion_time) {
if (ftp_listing_delegate_.get()) {
ftp_listing_delegate_->OnCompletedRequest();
ftp_listing_delegate_.reset(NULL);
@@ -582,8 +599,10 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
multipart_delegate_.reset(NULL);
}
- // Prevent any further IPC to the browser now that we're complete.
- bridge_.reset();
+ // Prevent any further IPC to the browser now that we're complete, but
+ // don't delete it to keep any downloaded temp files alive.
+ DCHECK(!completed_bridge_.get());
+ completed_bridge_.swap(bridge_);
if (client_) {
if (status.status() != URLRequestStatus::SUCCESS) {
@@ -601,7 +620,7 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
error.unreachableURL = request_.url();
client_->didFail(loader_, error);
} else {
- client_->didFinishLoading(loader_);
+ client_->didFinishLoading(loader_, completion_time.ToDoubleT());
}
}
@@ -629,7 +648,7 @@ void WebURLLoaderImpl::Context::HandleDataURL() {
OnReceivedData(data.data(), data.size());
}
- OnCompletedRequest(status, info.security_info);
+ OnCompletedRequest(status, info.security_info, base::Time::Now());
}
// WebURLLoaderImpl -----------------------------------------------------------
diff --git a/webkit/glue/webvideoframe_impl.cc b/webkit/glue/webvideoframe_impl.cc
new file mode 100644
index 0000000..f50eded
--- /dev/null
+++ b/webkit/glue/webvideoframe_impl.cc
@@ -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.
+
+#include "webkit/glue/webvideoframe_impl.h"
+
+#include "media/base/video_frame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebVideoFrame.h"
+
+using namespace WebKit;
+
+namespace webkit_glue {
+
+media::VideoFrame* WebVideoFrameImpl::toVideoFrame(
+ WebVideoFrame* web_video_frame) {
+ WebVideoFrameImpl* wrapped_frame =
+ static_cast<WebVideoFrameImpl*>(web_video_frame);
+ if (wrapped_frame)
+ return wrapped_frame->video_frame_.get();
+ return NULL;
+}
+
+WebVideoFrameImpl::WebVideoFrameImpl(
+ scoped_refptr<media::VideoFrame> video_frame)
+ : video_frame_(video_frame) {
+}
+
+#define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, chromium_name) \
+ COMPILE_ASSERT(int(WebKit::WebVideoFrame::webkit_name) == \
+ int(media::VideoFrame::chromium_name), \
+ mismatching_enums)
+COMPILE_ASSERT_MATCHING_ENUM(FormatInvalid, INVALID);
+COMPILE_ASSERT_MATCHING_ENUM(FormatRGB555, RGB555);
+COMPILE_ASSERT_MATCHING_ENUM(FormatRGB565, RGB565);
+COMPILE_ASSERT_MATCHING_ENUM(FormatRGB24, RGB24);
+COMPILE_ASSERT_MATCHING_ENUM(FormatRGB32, RGB32);
+COMPILE_ASSERT_MATCHING_ENUM(FormatRGBA, RGBA);
+COMPILE_ASSERT_MATCHING_ENUM(FormatYV12, YV12);
+COMPILE_ASSERT_MATCHING_ENUM(FormatYV16, YV16);
+COMPILE_ASSERT_MATCHING_ENUM(FormatNV12, NV12);
+COMPILE_ASSERT_MATCHING_ENUM(FormatEmpty, EMPTY);
+COMPILE_ASSERT_MATCHING_ENUM(FormatASCII, ASCII);
+
+COMPILE_ASSERT_MATCHING_ENUM(SurfaceTypeSystemMemory, TYPE_SYSTEM_MEMORY);
+// TODO(hclam): Add checks for newly added surface types like GL texture and
+// D3D texture.
+
+WebVideoFrame::SurfaceType WebVideoFrameImpl::surfaceType() const {
+ if (video_frame_.get())
+ return static_cast<WebVideoFrame::SurfaceType>(video_frame_->type());
+ return WebVideoFrame::SurfaceTypeSystemMemory;
+}
+
+WebVideoFrame::Format WebVideoFrameImpl::format() const {
+ if (video_frame_.get())
+ return static_cast<WebVideoFrame::Format>(video_frame_->format());
+ return WebVideoFrame::FormatInvalid;
+}
+
+unsigned WebVideoFrameImpl::width() const {
+ if (video_frame_.get())
+ return video_frame_->width();
+ return 0;
+}
+
+unsigned WebVideoFrameImpl::height() const {
+ if (video_frame_.get())
+ return video_frame_->height();
+ return 0;
+}
+
+unsigned WebVideoFrameImpl::planes() const {
+ if (video_frame_.get())
+ return video_frame_->planes();
+ return 0;
+}
+
+int WebVideoFrameImpl::stride(unsigned plane) const {
+ if (video_frame_.get())
+ return static_cast<int>(video_frame_->stride(plane));
+ return 0;
+}
+
+const void* WebVideoFrameImpl::data(unsigned plane) const {
+ if (video_frame_.get())
+ return static_cast<const void*>(video_frame_->data(plane));
+ return NULL;
+}
+
+unsigned WebVideoFrameImpl::texture(unsigned plane) const {
+ if (video_frame_.get())
+ return video_frame_->gl_texture(plane);
+ return NULL;
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/webvideoframe_impl.h b/webkit/glue/webvideoframe_impl.h
new file mode 100644
index 0000000..dfaac03
--- /dev/null
+++ b/webkit/glue/webvideoframe_impl.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 WEBKIT_GLUE_WEBVIDEOFRAME_IMPL_H_
+#define WEBKIT_GLUE_WEBVIDEOFRAME_IMPL_H_
+
+#include "media/base/video_frame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebVideoFrame.h"
+
+using namespace WebKit;
+
+namespace webkit_glue {
+
+class WebVideoFrameImpl : public WebVideoFrame {
+ public:
+ // This converts a WebKit::WebVideoFrame to a media::VideoFrame.
+ static media::VideoFrame* toVideoFrame(WebVideoFrame* web_video_frame);
+
+ WebVideoFrameImpl(scoped_refptr<media::VideoFrame> video_frame);
+ virtual WebVideoFrame::SurfaceType surfaceType() const;
+ virtual WebVideoFrame::Format format() const;
+ virtual unsigned width() const;
+ virtual unsigned height() const;
+ virtual unsigned planes() const;
+ virtual int stride(unsigned plane) const;
+ virtual const void* data(unsigned plane) const;
+ virtual unsigned texture(unsigned plane) const;
+
+ private:
+ scoped_refptr<media::VideoFrame> video_frame_;
+ DISALLOW_COPY_AND_ASSIGN(WebVideoFrameImpl);
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_WEBVIDEOFRAME_IMPL_H_